Repository: JPShag/PCILEECH-DMA-FW-Guide-2.0 Branch: main Commit: 670a1871d8e6 Files: 4657 Total size: 19.5 MB Directory structure: gitextract_gv5nd5na/ ├── CN/ │ ├── README-old-2.md │ ├── README-old.md │ ├── README.md │ ├── 核对表.md │ └── 版本 4.md ├── Checklist.md ├── FW-Guide-v4.md ├── Lesson 3_ Advanced PCIe Configuration and Interrupt Handling.md ├── README-old.md ├── README-v2-old.md ├── README.md ├── RU/ │ └── README.md └── Tools/ ├── CH347/ │ └── ch347-main/ │ ├── CH347FPGATool/ │ │ ├── FPGABit/ │ │ │ ├── bscan_spi_xc3s100e.bit │ │ │ ├── bscan_spi_xc3s1200e.bit │ │ │ ├── bscan_spi_xc3s1400a.bit │ │ │ ├── bscan_spi_xc3s1400an.bit │ │ │ ├── bscan_spi_xc3s1600e.bit │ │ │ ├── bscan_spi_xc3s200a.bit │ │ │ ├── bscan_spi_xc3s200an.bit │ │ │ ├── bscan_spi_xc3s250e.bit │ │ │ ├── bscan_spi_xc3s400a.bit │ │ │ ├── bscan_spi_xc3s400an.bit │ │ │ ├── bscan_spi_xc3s500e.bit │ │ │ ├── bscan_spi_xc3s50a.bit │ │ │ ├── bscan_spi_xc3s50an.bit │ │ │ ├── bscan_spi_xc3s700a.bit │ │ │ ├── bscan_spi_xc3s700an.bit │ │ │ ├── bscan_spi_xc3sd1800a.bit │ │ │ ├── bscan_spi_xc3sd3400a.bit │ │ │ ├── bscan_spi_xc6slx100.bit │ │ │ ├── bscan_spi_xc6slx100t.bit │ │ │ ├── bscan_spi_xc6slx150.bit │ │ │ ├── bscan_spi_xc6slx150t.bit │ │ │ ├── bscan_spi_xc6slx16.bit │ │ │ ├── bscan_spi_xc6slx25.bit │ │ │ ├── bscan_spi_xc6slx25t.bit │ │ │ ├── bscan_spi_xc6slx4.bit │ │ │ ├── bscan_spi_xc6slx45.bit │ │ │ ├── bscan_spi_xc6slx45t.bit │ │ │ ├── bscan_spi_xc6slx75.bit │ │ │ ├── bscan_spi_xc6slx75t.bit │ │ │ ├── bscan_spi_xc6slx9.bit │ │ │ ├── bscan_spi_xc7a100t.bit │ │ │ ├── bscan_spi_xc7a12t.bit │ │ │ ├── bscan_spi_xc7a15t.bit │ │ │ ├── bscan_spi_xc7a200t.bit │ │ │ ├── bscan_spi_xc7a25t.bit │ │ │ ├── bscan_spi_xc7a35t.bit │ │ │ ├── bscan_spi_xc7a50t.bit │ │ │ ├── bscan_spi_xc7a75t.bit │ │ │ ├── bscan_spi_xc7k160t.bit │ │ │ ├── bscan_spi_xc7k325t-debug.bit │ │ │ ├── bscan_spi_xc7k325t.bit │ │ │ ├── bscan_spi_xc7k355t.bit │ │ │ ├── bscan_spi_xc7k410t.bit │ │ │ ├── bscan_spi_xc7k420t.bit │ │ │ ├── bscan_spi_xc7k480t.bit │ │ │ ├── bscan_spi_xc7k70t.bit │ │ │ ├── bscan_spi_xc7s25.bit │ │ │ ├── bscan_spi_xc7s50.bit │ │ │ ├── bscan_spi_xc7v2000t.bit │ │ │ ├── bscan_spi_xc7v585t.bit │ │ │ ├── bscan_spi_xc7vh580t.bit │ │ │ ├── bscan_spi_xc7vh870t.bit │ │ │ ├── bscan_spi_xc7vx1140t.bit │ │ │ ├── bscan_spi_xc7vx330t.bit │ │ │ ├── bscan_spi_xc7vx415t.bit │ │ │ ├── bscan_spi_xc7vx485t.bit │ │ │ ├── bscan_spi_xc7vx550t.bit │ │ │ ├── bscan_spi_xc7vx690t.bit │ │ │ ├── bscan_spi_xc7vx980t.bit │ │ │ └── bscan_spi_xcku040.bit │ │ ├── OpenOCD_CH347/ │ │ │ ├── bin/ │ │ │ │ └── ch347.cfg │ │ │ ├── contrib/ │ │ │ │ ├── 60-openocd.rules │ │ │ │ └── libdcc/ │ │ │ │ ├── README │ │ │ │ ├── dcc_stdio.c │ │ │ │ ├── dcc_stdio.h │ │ │ │ └── example.c │ │ │ ├── scripts/ │ │ │ │ ├── bitsbytes.tcl │ │ │ │ ├── board/ │ │ │ │ │ ├── 8devices-lima.cfg │ │ │ │ │ ├── actux3.cfg │ │ │ │ │ ├── adapteva_parallella1.cfg │ │ │ │ │ ├── adsp-sc584-ezbrd.cfg │ │ │ │ │ ├── alphascale_asm9260_ek.cfg │ │ │ │ │ ├── altera_sockit.cfg │ │ │ │ │ ├── am3517evm.cfg │ │ │ │ │ ├── ampere_emag8180.cfg │ │ │ │ │ ├── arm_evaluator7t.cfg │ │ │ │ │ ├── arm_musca_a.cfg │ │ │ │ │ ├── arty_s7.cfg │ │ │ │ │ ├── asus-rt-n16.cfg │ │ │ │ │ ├── asus-rt-n66u.cfg │ │ │ │ │ ├── at91cap7a-stk-sdram.cfg │ │ │ │ │ ├── at91eb40a.cfg │ │ │ │ │ ├── at91rm9200-dk.cfg │ │ │ │ │ ├── at91rm9200-ek.cfg │ │ │ │ │ ├── at91sam9261-ek.cfg │ │ │ │ │ ├── at91sam9263-ek.cfg │ │ │ │ │ ├── at91sam9g20-ek.cfg │ │ │ │ │ ├── atmel_at91sam7s-ek.cfg │ │ │ │ │ ├── atmel_at91sam9260-ek.cfg │ │ │ │ │ ├── atmel_at91sam9rl-ek.cfg │ │ │ │ │ ├── atmel_sam3n_ek.cfg │ │ │ │ │ ├── atmel_sam3s_ek.cfg │ │ │ │ │ ├── atmel_sam3u_ek.cfg │ │ │ │ │ ├── atmel_sam3x_ek.cfg │ │ │ │ │ ├── atmel_sam4e_ek.cfg │ │ │ │ │ ├── atmel_sam4l8_xplained_pro.cfg │ │ │ │ │ ├── atmel_sam4s_ek.cfg │ │ │ │ │ ├── atmel_sam4s_xplained_pro.cfg │ │ │ │ │ ├── atmel_samc20_xplained_pro.cfg │ │ │ │ │ ├── atmel_samc21_xplained_pro.cfg │ │ │ │ │ ├── atmel_samd10_xplained_mini.cfg │ │ │ │ │ ├── atmel_samd11_xplained_pro.cfg │ │ │ │ │ ├── atmel_samd20_xplained_pro.cfg │ │ │ │ │ ├── atmel_samd21_xplained_pro.cfg │ │ │ │ │ ├── atmel_same70_xplained.cfg │ │ │ │ │ ├── atmel_samg53_xplained_pro.cfg │ │ │ │ │ ├── atmel_samg55_xplained_pro.cfg │ │ │ │ │ ├── atmel_saml21_xplained_pro.cfg │ │ │ │ │ ├── atmel_samr21_xplained_pro.cfg │ │ │ │ │ ├── atmel_samv71_xplained_ultra.cfg │ │ │ │ │ ├── avnet_ultrazed-eg.cfg │ │ │ │ │ ├── balloon3-cpu.cfg │ │ │ │ │ ├── bcm28155_ap.cfg │ │ │ │ │ ├── bluefield.cfg │ │ │ │ │ ├── bt-homehubv1.cfg │ │ │ │ │ ├── colibri.cfg │ │ │ │ │ ├── crossbow_tech_imote2.cfg │ │ │ │ │ ├── csb337.cfg │ │ │ │ │ ├── csb732.cfg │ │ │ │ │ ├── da850evm.cfg │ │ │ │ │ ├── digi_connectcore_wi-9c.cfg │ │ │ │ │ ├── digilent_analog_discovery.cfg │ │ │ │ │ ├── digilent_atlys.cfg │ │ │ │ │ ├── digilent_nexys_video.cfg │ │ │ │ │ ├── digilent_zedboard.cfg │ │ │ │ │ ├── diolan_lpc4350-db1.cfg │ │ │ │ │ ├── diolan_lpc4357-db1.cfg │ │ │ │ │ ├── dk-tm4c129.cfg │ │ │ │ │ ├── dm355evm.cfg │ │ │ │ │ ├── dm365evm.cfg │ │ │ │ │ ├── dm6446evm.cfg │ │ │ │ │ ├── dp_busblaster_v3.cfg │ │ │ │ │ ├── dp_busblaster_v4.cfg │ │ │ │ │ ├── dptechnics_dpt-board-v1.cfg │ │ │ │ │ ├── efikamx.cfg │ │ │ │ │ ├── efm32.cfg │ │ │ │ │ ├── eir.cfg │ │ │ │ │ ├── ek-lm3s1968.cfg │ │ │ │ │ ├── ek-lm3s3748.cfg │ │ │ │ │ ├── ek-lm3s6965.cfg │ │ │ │ │ ├── ek-lm3s811-revb.cfg │ │ │ │ │ ├── ek-lm3s811.cfg │ │ │ │ │ ├── ek-lm3s8962.cfg │ │ │ │ │ ├── ek-lm3s9b9x.cfg │ │ │ │ │ ├── ek-lm3s9d92.cfg │ │ │ │ │ ├── ek-lm4f120xl.cfg │ │ │ │ │ ├── ek-lm4f232.cfg │ │ │ │ │ ├── ek-tm4c123gxl.cfg │ │ │ │ │ ├── ek-tm4c1294xl.cfg │ │ │ │ │ ├── embedded-artists_lpc2478-32.cfg │ │ │ │ │ ├── emcraft_imx8m-som-bsb.cfg │ │ │ │ │ ├── emcraft_twr-vf6-som-bsb.cfg │ │ │ │ │ ├── emcraft_vf6-som.cfg │ │ │ │ │ ├── esp32s2-kaluga-1.cfg │ │ │ │ │ ├── ethernut3.cfg │ │ │ │ │ ├── evb-lan9255.cfg │ │ │ │ │ ├── frdm-kl25z.cfg │ │ │ │ │ ├── frdm-kl46z.cfg │ │ │ │ │ ├── fsl_imx6q_sabresd.cfg │ │ │ │ │ ├── glyn_tonga2.cfg │ │ │ │ │ ├── gti/ │ │ │ │ │ │ └── espressobin.cfg │ │ │ │ │ ├── gumstix-aerocore.cfg │ │ │ │ │ ├── hammer.cfg │ │ │ │ │ ├── hilscher_nxdb500sys.cfg │ │ │ │ │ ├── hilscher_nxeb500hmi.cfg │ │ │ │ │ ├── hilscher_nxhx10.cfg │ │ │ │ │ ├── hilscher_nxhx50.cfg │ │ │ │ │ ├── hilscher_nxhx500.cfg │ │ │ │ │ ├── hilscher_nxsb100.cfg │ │ │ │ │ ├── hitex_lpc1768stick.cfg │ │ │ │ │ ├── hitex_lpc2929.cfg │ │ │ │ │ ├── hitex_stm32-performancestick.cfg │ │ │ │ │ ├── hitex_str9-comstick.cfg │ │ │ │ │ ├── iar_lpc1768.cfg │ │ │ │ │ ├── iar_str912_sk.cfg │ │ │ │ │ ├── icnova_imx53_sodimm.cfg │ │ │ │ │ ├── icnova_sam9g45_sodimm.cfg │ │ │ │ │ ├── imx27ads.cfg │ │ │ │ │ ├── imx27lnst.cfg │ │ │ │ │ ├── imx28evk.cfg │ │ │ │ │ ├── imx31pdk.cfg │ │ │ │ │ ├── imx35pdk.cfg │ │ │ │ │ ├── imx53-m53evk.cfg │ │ │ │ │ ├── imx53loco.cfg │ │ │ │ │ ├── imx8mp-evk.cfg │ │ │ │ │ ├── insignal_arndale.cfg │ │ │ │ │ ├── kasli.cfg │ │ │ │ │ ├── kc100.cfg │ │ │ │ │ ├── kc705.cfg │ │ │ │ │ ├── kcu105.cfg │ │ │ │ │ ├── keil_mcb1700.cfg │ │ │ │ │ ├── keil_mcb2140.cfg │ │ │ │ │ ├── kindle2.cfg │ │ │ │ │ ├── kontron_sl28.cfg │ │ │ │ │ ├── kwikstik.cfg │ │ │ │ │ ├── la_fonera-fon2200.cfg │ │ │ │ │ ├── lambdaconcept_ecpix-5.cfg │ │ │ │ │ ├── lemaker_hikey.cfg │ │ │ │ │ ├── linksys-wag200g.cfg │ │ │ │ │ ├── linksys-wrt54gl.cfg │ │ │ │ │ ├── linksys_nslu2.cfg │ │ │ │ │ ├── lisa-l.cfg │ │ │ │ │ ├── logicpd_imx27.cfg │ │ │ │ │ ├── lpc1850_spifi_generic.cfg │ │ │ │ │ ├── lpc4350_spifi_generic.cfg │ │ │ │ │ ├── lubbock.cfg │ │ │ │ │ ├── marsohod.cfg │ │ │ │ │ ├── marsohod2.cfg │ │ │ │ │ ├── marsohod3.cfg │ │ │ │ │ ├── mbed-lpc11u24.cfg │ │ │ │ │ ├── mbed-lpc1768.cfg │ │ │ │ │ ├── mcb1700.cfg │ │ │ │ │ ├── microchip_explorer16.cfg │ │ │ │ │ ├── microchip_sama5d27_som1_kit1.cfg │ │ │ │ │ ├── microchip_same51_curiosity_nano.cfg │ │ │ │ │ ├── microchip_same54_xplained_pro.cfg │ │ │ │ │ ├── microchip_saml11_xplained_pro.cfg │ │ │ │ │ ├── mini2440.cfg │ │ │ │ │ ├── mini6410.cfg │ │ │ │ │ ├── minispartan6.cfg │ │ │ │ │ ├── nds32_corvettef1.cfg │ │ │ │ │ ├── nds32_xc5.cfg │ │ │ │ │ ├── nds32_xc7.cfg │ │ │ │ │ ├── netgear-dg834v3.cfg │ │ │ │ │ ├── netgear-wg102.cfg │ │ │ │ │ ├── nordic_nrf51822_mkit.cfg │ │ │ │ │ ├── nordic_nrf51_dk.cfg │ │ │ │ │ ├── nordic_nrf52_dk.cfg │ │ │ │ │ ├── nordic_nrf52_ftx232.cfg │ │ │ │ │ ├── novena-internal-fpga.cfg │ │ │ │ │ ├── npcx_evb.cfg │ │ │ │ │ ├── numato_mimas_a7.cfg │ │ │ │ │ ├── numato_opsis.cfg │ │ │ │ │ ├── nxp_frdm-k64f.cfg │ │ │ │ │ ├── nxp_frdm-ls1012a.cfg │ │ │ │ │ ├── nxp_imx7sabre.cfg │ │ │ │ │ ├── nxp_lpc-link2.cfg │ │ │ │ │ ├── nxp_mcimx8m-evk.cfg │ │ │ │ │ ├── nxp_rdb-ls1046a.cfg │ │ │ │ │ ├── nxp_rdb-ls1088a.cfg │ │ │ │ │ ├── olimex_LPC2378STK.cfg │ │ │ │ │ ├── olimex_lpc_h2148.cfg │ │ │ │ │ ├── olimex_sam7_ex256.cfg │ │ │ │ │ ├── olimex_sam7_la2.cfg │ │ │ │ │ ├── olimex_sam9_l9260.cfg │ │ │ │ │ ├── olimex_stm32_h103.cfg │ │ │ │ │ ├── olimex_stm32_h107.cfg │ │ │ │ │ ├── olimex_stm32_h405.cfg │ │ │ │ │ ├── olimex_stm32_p107.cfg │ │ │ │ │ ├── omap2420_h4.cfg │ │ │ │ │ ├── openrd.cfg │ │ │ │ │ ├── or1k_generic.cfg │ │ │ │ │ ├── osk5912.cfg │ │ │ │ │ ├── phone_se_j100i.cfg │ │ │ │ │ ├── phytec_lpc3250.cfg │ │ │ │ │ ├── pic-p32mx.cfg │ │ │ │ │ ├── pico-debug.cfg │ │ │ │ │ ├── pipistrello.cfg │ │ │ │ │ ├── propox_mmnet1001.cfg │ │ │ │ │ ├── pxa255_sst.cfg │ │ │ │ │ ├── quark_d2000_refboard.cfg │ │ │ │ │ ├── quark_x10xx_board.cfg │ │ │ │ │ ├── quicklogic_quickfeather.cfg │ │ │ │ │ ├── radiona_ulx3s.cfg │ │ │ │ │ ├── redbee.cfg │ │ │ │ │ ├── reflexces_achilles_i-dev_kit_arria10.cfg │ │ │ │ │ ├── renesas_dk-s7g2.cfg │ │ │ │ │ ├── renesas_falcon.cfg │ │ │ │ │ ├── renesas_gr_peach.cfg │ │ │ │ │ ├── renesas_porter.cfg │ │ │ │ │ ├── renesas_salvator-xs.cfg │ │ │ │ │ ├── renesas_silk.cfg │ │ │ │ │ ├── renesas_stout.cfg │ │ │ │ │ ├── rigado_bmd300_ek.cfg │ │ │ │ │ ├── rpi3.cfg │ │ │ │ │ ├── rpi4b.cfg │ │ │ │ │ ├── rsc-w910.cfg │ │ │ │ │ ├── sayma_amc.cfg │ │ │ │ │ ├── sheevaplug.cfg │ │ │ │ │ ├── sifive-e31arty.cfg │ │ │ │ │ ├── sifive-e51arty.cfg │ │ │ │ │ ├── sifive-hifive1-revb.cfg │ │ │ │ │ ├── sifive-hifive1.cfg │ │ │ │ │ ├── smdk6410.cfg │ │ │ │ │ ├── snps_em_sk.cfg │ │ │ │ │ ├── snps_em_sk_v1.cfg │ │ │ │ │ ├── snps_em_sk_v2.1.cfg │ │ │ │ │ ├── snps_em_sk_v2.2.cfg │ │ │ │ │ ├── snps_hsdk.cfg │ │ │ │ │ ├── spansion_sk-fm4-176l-s6e2cc.cfg │ │ │ │ │ ├── spansion_sk-fm4-u120-9b560.cfg │ │ │ │ │ ├── spear300evb.cfg │ │ │ │ │ ├── spear300evb_mod.cfg │ │ │ │ │ ├── spear310evb20.cfg │ │ │ │ │ ├── spear310evb20_mod.cfg │ │ │ │ │ ├── spear320cpu.cfg │ │ │ │ │ ├── spear320cpu_mod.cfg │ │ │ │ │ ├── st_b-l475e-iot01a.cfg │ │ │ │ │ ├── st_nucleo_8l152r8.cfg │ │ │ │ │ ├── st_nucleo_8s208rb.cfg │ │ │ │ │ ├── st_nucleo_f0.cfg │ │ │ │ │ ├── st_nucleo_f103rb.cfg │ │ │ │ │ ├── st_nucleo_f3.cfg │ │ │ │ │ ├── st_nucleo_f4.cfg │ │ │ │ │ ├── st_nucleo_f7.cfg │ │ │ │ │ ├── st_nucleo_g0.cfg │ │ │ │ │ ├── st_nucleo_g4.cfg │ │ │ │ │ ├── st_nucleo_h743zi.cfg │ │ │ │ │ ├── st_nucleo_h745zi.cfg │ │ │ │ │ ├── st_nucleo_l073rz.cfg │ │ │ │ │ ├── st_nucleo_l1.cfg │ │ │ │ │ ├── st_nucleo_l4.cfg │ │ │ │ │ ├── st_nucleo_l5.cfg │ │ │ │ │ ├── st_nucleo_wb55.cfg │ │ │ │ │ ├── steval-idb007v1.cfg │ │ │ │ │ ├── steval-idb008v1.cfg │ │ │ │ │ ├── steval-idb011v1.cfg │ │ │ │ │ ├── steval-idb012v1.cfg │ │ │ │ │ ├── steval_pcc010.cfg │ │ │ │ │ ├── stm320518_eval.cfg │ │ │ │ │ ├── stm320518_eval_stlink.cfg │ │ │ │ │ ├── stm32100b_eval.cfg │ │ │ │ │ ├── stm3210b_eval.cfg │ │ │ │ │ ├── stm3210c_eval.cfg │ │ │ │ │ ├── stm3210e_eval.cfg │ │ │ │ │ ├── stm3220g_eval.cfg │ │ │ │ │ ├── stm3220g_eval_stlink.cfg │ │ │ │ │ ├── stm3241g_eval.cfg │ │ │ │ │ ├── stm3241g_eval_stlink.cfg │ │ │ │ │ ├── stm32429i_eval.cfg │ │ │ │ │ ├── stm32429i_eval_stlink.cfg │ │ │ │ │ ├── stm32439i_eval.cfg │ │ │ │ │ ├── stm32439i_eval_stlink.cfg │ │ │ │ │ ├── stm327x6g_eval.cfg │ │ │ │ │ ├── stm32f0discovery.cfg │ │ │ │ │ ├── stm32f103c8_blue_pill.cfg │ │ │ │ │ ├── stm32f334discovery.cfg │ │ │ │ │ ├── stm32f3discovery.cfg │ │ │ │ │ ├── stm32f412g-disco.cfg │ │ │ │ │ ├── stm32f413h-disco.cfg │ │ │ │ │ ├── stm32f429disc1.cfg │ │ │ │ │ ├── stm32f429discovery.cfg │ │ │ │ │ ├── stm32f469discovery.cfg │ │ │ │ │ ├── stm32f469i-disco.cfg │ │ │ │ │ ├── stm32f4discovery.cfg │ │ │ │ │ ├── stm32f723e-disco.cfg │ │ │ │ │ ├── stm32f746g-disco.cfg │ │ │ │ │ ├── stm32f769i-disco.cfg │ │ │ │ │ ├── stm32f7discovery.cfg │ │ │ │ │ ├── stm32h735g-disco.cfg │ │ │ │ │ ├── stm32h745i-disco.cfg │ │ │ │ │ ├── stm32h747i-disco.cfg │ │ │ │ │ ├── stm32h750b-disco.cfg │ │ │ │ │ ├── stm32h7b3i-disco.cfg │ │ │ │ │ ├── stm32h7x3i_eval.cfg │ │ │ │ │ ├── stm32h7x_dual_qspi.cfg │ │ │ │ │ ├── stm32l0discovery.cfg │ │ │ │ │ ├── stm32l476g-disco.cfg │ │ │ │ │ ├── stm32l496g-disco.cfg │ │ │ │ │ ├── stm32l4discovery.cfg │ │ │ │ │ ├── stm32l4p5g-disco.cfg │ │ │ │ │ ├── stm32l4r9i-disco.cfg │ │ │ │ │ ├── stm32ldiscovery.cfg │ │ │ │ │ ├── stm32mp13x_dk.cfg │ │ │ │ │ ├── stm32mp15x_dk2.cfg │ │ │ │ │ ├── stm32vldiscovery.cfg │ │ │ │ │ ├── str910-eval.cfg │ │ │ │ │ ├── telo.cfg │ │ │ │ │ ├── ti_am335xevm.cfg │ │ │ │ │ ├── ti_am437x_idk.cfg │ │ │ │ │ ├── ti_am43xx_evm.cfg │ │ │ │ │ ├── ti_am625evm.cfg │ │ │ │ │ ├── ti_am642evm.cfg │ │ │ │ │ ├── ti_am654evm.cfg │ │ │ │ │ ├── ti_beagleboard.cfg │ │ │ │ │ ├── ti_beagleboard_xm.cfg │ │ │ │ │ ├── ti_beaglebone-base.cfg │ │ │ │ │ ├── ti_beaglebone.cfg │ │ │ │ │ ├── ti_beaglebone_black.cfg │ │ │ │ │ ├── ti_blaze.cfg │ │ │ │ │ ├── ti_cc13x0_launchpad.cfg │ │ │ │ │ ├── ti_cc13x2_launchpad.cfg │ │ │ │ │ ├── ti_cc26x0_launchpad.cfg │ │ │ │ │ ├── ti_cc26x2_launchpad.cfg │ │ │ │ │ ├── ti_cc3200_launchxl.cfg │ │ │ │ │ ├── ti_cc3220sf_launchpad.cfg │ │ │ │ │ ├── ti_cc32xx_launchpad.cfg │ │ │ │ │ ├── ti_dk-tm4c129.cfg │ │ │ │ │ ├── ti_ek-tm4c123gxl.cfg │ │ │ │ │ ├── ti_ek-tm4c1294xl.cfg │ │ │ │ │ ├── ti_j7200evm.cfg │ │ │ │ │ ├── ti_j721evm.cfg │ │ │ │ │ ├── ti_j721s2evm.cfg │ │ │ │ │ ├── ti_msp432_launchpad.cfg │ │ │ │ │ ├── ti_pandaboard.cfg │ │ │ │ │ ├── ti_pandaboard_es.cfg │ │ │ │ │ ├── ti_tmdx570ls20susb.cfg │ │ │ │ │ ├── ti_tmdx570ls31usb.cfg │ │ │ │ │ ├── tocoding_poplar.cfg │ │ │ │ │ ├── topas910.cfg │ │ │ │ │ ├── topasa900.cfg │ │ │ │ │ ├── tp-link_tl-mr3020.cfg │ │ │ │ │ ├── tp-link_wdr4300.cfg │ │ │ │ │ ├── twr-k60f120m.cfg │ │ │ │ │ ├── twr-k60n512.cfg │ │ │ │ │ ├── twr-vf65gs10.cfg │ │ │ │ │ ├── twr-vf65gs10_cmsisdap.cfg │ │ │ │ │ ├── tx25_stk5.cfg │ │ │ │ │ ├── tx27_stk5.cfg │ │ │ │ │ ├── unknown_at91sam9260.cfg │ │ │ │ │ ├── uptech_2410.cfg │ │ │ │ │ ├── vd_a53x2_jtag.cfg │ │ │ │ │ ├── vd_m4_jtag.cfg │ │ │ │ │ ├── vd_pulpissimo_jtag.cfg │ │ │ │ │ ├── vd_swerv_jtag.cfg │ │ │ │ │ ├── verdex.cfg │ │ │ │ │ ├── voipac.cfg │ │ │ │ │ ├── voltcraft_dso-3062c.cfg │ │ │ │ │ ├── x300t.cfg │ │ │ │ │ ├── xmc-2go.cfg │ │ │ │ │ ├── xmc1100-boot-kit.cfg │ │ │ │ │ ├── xmc4200-application-kit-actuator.cfg │ │ │ │ │ ├── xmc4300-relax.cfg │ │ │ │ │ ├── xmc4500-application-kit-general.cfg │ │ │ │ │ ├── xmc4500-application-kit-sdram.cfg │ │ │ │ │ ├── xmc4500-relax.cfg │ │ │ │ │ ├── xmc4700-relax.cfg │ │ │ │ │ ├── xmc4800-relax.cfg │ │ │ │ │ └── xmos_xk-xac-xa8_arm.cfg │ │ │ │ ├── chip/ │ │ │ │ │ ├── atmel/ │ │ │ │ │ │ └── at91/ │ │ │ │ │ │ ├── aic.tcl │ │ │ │ │ │ ├── at91_pio.cfg │ │ │ │ │ │ ├── at91_pmc.cfg │ │ │ │ │ │ ├── at91_rstc.cfg │ │ │ │ │ │ ├── at91_wdt.cfg │ │ │ │ │ │ ├── at91sam7x128.tcl │ │ │ │ │ │ ├── at91sam7x256.tcl │ │ │ │ │ │ ├── at91sam9261.cfg │ │ │ │ │ │ ├── at91sam9261_matrix.cfg │ │ │ │ │ │ ├── at91sam9263.cfg │ │ │ │ │ │ ├── at91sam9263_matrix.cfg │ │ │ │ │ │ ├── at91sam9_init.cfg │ │ │ │ │ │ ├── at91sam9_sdramc.cfg │ │ │ │ │ │ ├── at91sam9_smc.cfg │ │ │ │ │ │ ├── hardware.cfg │ │ │ │ │ │ ├── pmc.tcl │ │ │ │ │ │ ├── rtt.tcl │ │ │ │ │ │ ├── sam9_smc.cfg │ │ │ │ │ │ └── usarts.tcl │ │ │ │ │ ├── st/ │ │ │ │ │ │ ├── spear/ │ │ │ │ │ │ │ ├── quirk_no_srst.tcl │ │ │ │ │ │ │ ├── spear3xx.tcl │ │ │ │ │ │ │ └── spear3xx_ddr.tcl │ │ │ │ │ │ └── stm32/ │ │ │ │ │ │ ├── stm32.tcl │ │ │ │ │ │ ├── stm32_rcc.tcl │ │ │ │ │ │ └── stm32_regs.tcl │ │ │ │ │ └── ti/ │ │ │ │ │ └── lm3s/ │ │ │ │ │ ├── lm3s.tcl │ │ │ │ │ └── lm3s_regs.tcl │ │ │ │ ├── cpld/ │ │ │ │ │ ├── altera-5m570z-cpld.cfg │ │ │ │ │ ├── altera-epm240.cfg │ │ │ │ │ ├── jtagspi.cfg │ │ │ │ │ ├── lattice-lc4032ze.cfg │ │ │ │ │ ├── xilinx-xc6s.cfg │ │ │ │ │ ├── xilinx-xc7.cfg │ │ │ │ │ ├── xilinx-xcf-p.cfg │ │ │ │ │ ├── xilinx-xcf-s.cfg │ │ │ │ │ ├── xilinx-xcr3256.cfg │ │ │ │ │ └── xilinx-xcu.cfg │ │ │ │ ├── cpu/ │ │ │ │ │ ├── arc/ │ │ │ │ │ │ ├── common.tcl │ │ │ │ │ │ ├── em.tcl │ │ │ │ │ │ ├── hs.tcl │ │ │ │ │ │ └── v2.tcl │ │ │ │ │ └── arm/ │ │ │ │ │ ├── arm7tdmi.tcl │ │ │ │ │ ├── arm920.tcl │ │ │ │ │ ├── arm946.tcl │ │ │ │ │ ├── arm966.tcl │ │ │ │ │ └── cortex_m3.tcl │ │ │ │ ├── fpga/ │ │ │ │ │ ├── altera-10m50.cfg │ │ │ │ │ ├── altera-ep3c10.cfg │ │ │ │ │ ├── altera-ep4ce10.cfg │ │ │ │ │ ├── lattice_ecp5.cfg │ │ │ │ │ ├── xilinx-dna.cfg │ │ │ │ │ └── xilinx-xadc.cfg │ │ │ │ ├── interface/ │ │ │ │ │ ├── altera-usb-blaster.cfg │ │ │ │ │ ├── altera-usb-blaster2.cfg │ │ │ │ │ ├── arm-jtag-ew.cfg │ │ │ │ │ ├── at91rm9200.cfg │ │ │ │ │ ├── beaglebone-jtag-native.cfg │ │ │ │ │ ├── beaglebone-swd-native.cfg │ │ │ │ │ ├── buspirate.cfg │ │ │ │ │ ├── calao-usb-a9260.cfg │ │ │ │ │ ├── chameleon.cfg │ │ │ │ │ ├── cmsis-dap.cfg │ │ │ │ │ ├── dln-2-gpiod.cfg │ │ │ │ │ ├── dummy.cfg │ │ │ │ │ ├── estick.cfg │ │ │ │ │ ├── flashlink.cfg │ │ │ │ │ ├── ft232r/ │ │ │ │ │ │ └── radiona_ulx3s.cfg │ │ │ │ │ ├── ft232r.cfg │ │ │ │ │ ├── ftdi/ │ │ │ │ │ │ ├── 100ask-openjtag.cfg │ │ │ │ │ │ ├── ashling-opella-ld-jtag.cfg │ │ │ │ │ │ ├── ashling-opella-ld-swd.cfg │ │ │ │ │ │ ├── axm0432.cfg │ │ │ │ │ │ ├── c232hm.cfg │ │ │ │ │ │ ├── calao-usb-a9260-c01.cfg │ │ │ │ │ │ ├── calao-usb-a9260-c02.cfg │ │ │ │ │ │ ├── cortino.cfg │ │ │ │ │ │ ├── digilent-hs1.cfg │ │ │ │ │ │ ├── digilent-hs2.cfg │ │ │ │ │ │ ├── digilent_jtag_hs3.cfg │ │ │ │ │ │ ├── digilent_jtag_smt2.cfg │ │ │ │ │ │ ├── digilent_jtag_smt2_nc.cfg │ │ │ │ │ │ ├── dlp-usb1232h.cfg │ │ │ │ │ │ ├── dp_busblaster.cfg │ │ │ │ │ │ ├── dp_busblaster_kt-link.cfg │ │ │ │ │ │ ├── esp32s2_kaluga_v1.cfg │ │ │ │ │ │ ├── flossjtag-noeeprom.cfg │ │ │ │ │ │ ├── flossjtag.cfg │ │ │ │ │ │ ├── flyswatter.cfg │ │ │ │ │ │ ├── flyswatter2.cfg │ │ │ │ │ │ ├── ft232h-module-swd.cfg │ │ │ │ │ │ ├── gw16042.cfg │ │ │ │ │ │ ├── hie-jtag.cfg │ │ │ │ │ │ ├── hilscher_nxhx10_etm.cfg │ │ │ │ │ │ ├── hilscher_nxhx500_etm.cfg │ │ │ │ │ │ ├── hilscher_nxhx500_re.cfg │ │ │ │ │ │ ├── hilscher_nxhx50_etm.cfg │ │ │ │ │ │ ├── hilscher_nxhx50_re.cfg │ │ │ │ │ │ ├── hitex_lpc1768stick.cfg │ │ │ │ │ │ ├── hitex_str9-comstick.cfg │ │ │ │ │ │ ├── icebear.cfg │ │ │ │ │ │ ├── imx8mp-evk.cfg │ │ │ │ │ │ ├── incircuit-icprog.cfg │ │ │ │ │ │ ├── iotlab-usb.cfg │ │ │ │ │ │ ├── isodebug.cfg │ │ │ │ │ │ ├── jtag-lock-pick_tiny_2.cfg │ │ │ │ │ │ ├── jtagkey.cfg │ │ │ │ │ │ ├── jtagkey2.cfg │ │ │ │ │ │ ├── jtagkey2p.cfg │ │ │ │ │ │ ├── kt-link.cfg │ │ │ │ │ │ ├── lambdaconcept_ecpix-5.cfg │ │ │ │ │ │ ├── lisa-l.cfg │ │ │ │ │ │ ├── luminary-icdi.cfg │ │ │ │ │ │ ├── luminary-lm3s811.cfg │ │ │ │ │ │ ├── luminary.cfg │ │ │ │ │ │ ├── m53evk.cfg │ │ │ │ │ │ ├── mbftdi.cfg │ │ │ │ │ │ ├── minimodule-swd.cfg │ │ │ │ │ │ ├── minimodule.cfg │ │ │ │ │ │ ├── minispartan6.cfg │ │ │ │ │ │ ├── miniwiggler.cfg │ │ │ │ │ │ ├── neodb.cfg │ │ │ │ │ │ ├── ngxtech.cfg │ │ │ │ │ │ ├── olimex-arm-jtag-swd.cfg │ │ │ │ │ │ ├── olimex-arm-usb-ocd-h.cfg │ │ │ │ │ │ ├── olimex-arm-usb-ocd.cfg │ │ │ │ │ │ ├── olimex-arm-usb-tiny-h.cfg │ │ │ │ │ │ ├── olimex-jtag-tiny.cfg │ │ │ │ │ │ ├── oocdlink.cfg │ │ │ │ │ │ ├── opendous_ftdi.cfg │ │ │ │ │ │ ├── openocd-usb-hs.cfg │ │ │ │ │ │ ├── openocd-usb.cfg │ │ │ │ │ │ ├── openrd.cfg │ │ │ │ │ │ ├── pipistrello.cfg │ │ │ │ │ │ ├── pls_spc5.cfg │ │ │ │ │ │ ├── redbee-econotag.cfg │ │ │ │ │ │ ├── redbee-usb.cfg │ │ │ │ │ │ ├── rowley-cc-arm-swd.cfg │ │ │ │ │ │ ├── sheevaplug.cfg │ │ │ │ │ │ ├── signalyzer-lite.cfg │ │ │ │ │ │ ├── signalyzer.cfg │ │ │ │ │ │ ├── snps_sdp.cfg │ │ │ │ │ │ ├── steppenprobe.cfg │ │ │ │ │ │ ├── stm32-stick.cfg │ │ │ │ │ │ ├── swd-resistor-hack.cfg │ │ │ │ │ │ ├── ti-icdi.cfg │ │ │ │ │ │ ├── tigard.cfg │ │ │ │ │ │ ├── tumpa-lite.cfg │ │ │ │ │ │ ├── tumpa.cfg │ │ │ │ │ │ ├── turtelizer2-revB.cfg │ │ │ │ │ │ ├── turtelizer2-revC.cfg │ │ │ │ │ │ ├── um232h.cfg │ │ │ │ │ │ ├── vpaclink.cfg │ │ │ │ │ │ ├── xds100v2.cfg │ │ │ │ │ │ └── xds100v3.cfg │ │ │ │ │ ├── imx-native.cfg │ │ │ │ │ ├── jlink.cfg │ │ │ │ │ ├── jtag_dpi.cfg │ │ │ │ │ ├── jtag_hat_rpi2.cfg │ │ │ │ │ ├── jtag_vpi.cfg │ │ │ │ │ ├── kitprog.cfg │ │ │ │ │ ├── nds32-aice.cfg │ │ │ │ │ ├── nulink.cfg │ │ │ │ │ ├── opendous.cfg │ │ │ │ │ ├── openjtag.cfg │ │ │ │ │ ├── osbdm.cfg │ │ │ │ │ ├── parport.cfg │ │ │ │ │ ├── parport_dlc5.cfg │ │ │ │ │ ├── raspberrypi-native.cfg │ │ │ │ │ ├── raspberrypi2-native.cfg │ │ │ │ │ ├── rlink.cfg │ │ │ │ │ ├── rshim.cfg │ │ │ │ │ ├── stlink-dap.cfg │ │ │ │ │ ├── stlink-v1.cfg │ │ │ │ │ ├── stlink-v2-1.cfg │ │ │ │ │ ├── stlink-v2.cfg │ │ │ │ │ ├── stlink.cfg │ │ │ │ │ ├── sysfsgpio-raspberrypi.cfg │ │ │ │ │ ├── ti-icdi.cfg │ │ │ │ │ ├── ulink.cfg │ │ │ │ │ ├── usb-jtag.cfg │ │ │ │ │ ├── usbprog.cfg │ │ │ │ │ ├── vdebug.cfg │ │ │ │ │ ├── vsllink.cfg │ │ │ │ │ └── xds110.cfg │ │ │ │ ├── mem_helper.tcl │ │ │ │ ├── memory.tcl │ │ │ │ ├── mmr_helpers.tcl │ │ │ │ ├── target/ │ │ │ │ │ ├── 1986ве1т.cfg │ │ │ │ │ ├── adsp-sc58x.cfg │ │ │ │ │ ├── aduc702x.cfg │ │ │ │ │ ├── aducm360.cfg │ │ │ │ │ ├── allwinner_v3s.cfg │ │ │ │ │ ├── alphascale_asm9260t.cfg │ │ │ │ │ ├── altera_fpgasoc.cfg │ │ │ │ │ ├── altera_fpgasoc_arria10.cfg │ │ │ │ │ ├── am335x.cfg │ │ │ │ │ ├── am437x.cfg │ │ │ │ │ ├── amdm37x.cfg │ │ │ │ │ ├── ampere_emag.cfg │ │ │ │ │ ├── ar71xx.cfg │ │ │ │ │ ├── arm_corelink_sse200.cfg │ │ │ │ │ ├── armada370.cfg │ │ │ │ │ ├── at32ap7000.cfg │ │ │ │ │ ├── at91r40008.cfg │ │ │ │ │ ├── at91rm9200.cfg │ │ │ │ │ ├── at91sam3XXX.cfg │ │ │ │ │ ├── at91sam3ax_4x.cfg │ │ │ │ │ ├── at91sam3ax_8x.cfg │ │ │ │ │ ├── at91sam3ax_xx.cfg │ │ │ │ │ ├── at91sam3nXX.cfg │ │ │ │ │ ├── at91sam3sXX.cfg │ │ │ │ │ ├── at91sam3u1c.cfg │ │ │ │ │ ├── at91sam3u1e.cfg │ │ │ │ │ ├── at91sam3u2c.cfg │ │ │ │ │ ├── at91sam3u2e.cfg │ │ │ │ │ ├── at91sam3u4c.cfg │ │ │ │ │ ├── at91sam3u4e.cfg │ │ │ │ │ ├── at91sam3uxx.cfg │ │ │ │ │ ├── at91sam4XXX.cfg │ │ │ │ │ ├── at91sam4c32x.cfg │ │ │ │ │ ├── at91sam4cXXX.cfg │ │ │ │ │ ├── at91sam4lXX.cfg │ │ │ │ │ ├── at91sam4sXX.cfg │ │ │ │ │ ├── at91sam4sd32x.cfg │ │ │ │ │ ├── at91sam7a2.cfg │ │ │ │ │ ├── at91sam7se512.cfg │ │ │ │ │ ├── at91sam7sx.cfg │ │ │ │ │ ├── at91sam7x256.cfg │ │ │ │ │ ├── at91sam7x512.cfg │ │ │ │ │ ├── at91sam9.cfg │ │ │ │ │ ├── at91sam9260.cfg │ │ │ │ │ ├── at91sam9260_ext_RAM_ext_flash.cfg │ │ │ │ │ ├── at91sam9261.cfg │ │ │ │ │ ├── at91sam9263.cfg │ │ │ │ │ ├── at91sam9g10.cfg │ │ │ │ │ ├── at91sam9g20.cfg │ │ │ │ │ ├── at91sam9g45.cfg │ │ │ │ │ ├── at91sam9rl.cfg │ │ │ │ │ ├── at91sama5d2.cfg │ │ │ │ │ ├── at91samdXX.cfg │ │ │ │ │ ├── at91samg5x.cfg │ │ │ │ │ ├── atheros_ar2313.cfg │ │ │ │ │ ├── atheros_ar2315.cfg │ │ │ │ │ ├── atheros_ar9331.cfg │ │ │ │ │ ├── atheros_ar9344.cfg │ │ │ │ │ ├── atmega128.cfg │ │ │ │ │ ├── atmega128rfa1.cfg │ │ │ │ │ ├── atsame5x.cfg │ │ │ │ │ ├── atsaml1x.cfg │ │ │ │ │ ├── atsamv.cfg │ │ │ │ │ ├── avr32.cfg │ │ │ │ │ ├── bcm2711.cfg │ │ │ │ │ ├── bcm281xx.cfg │ │ │ │ │ ├── bcm2835.cfg │ │ │ │ │ ├── bcm2836.cfg │ │ │ │ │ ├── bcm2837.cfg │ │ │ │ │ ├── bcm4706.cfg │ │ │ │ │ ├── bcm4718.cfg │ │ │ │ │ ├── bcm47xx.cfg │ │ │ │ │ ├── bcm5352e.cfg │ │ │ │ │ ├── bcm6348.cfg │ │ │ │ │ ├── bluefield.cfg │ │ │ │ │ ├── bluenrg-x.cfg │ │ │ │ │ ├── c100.cfg │ │ │ │ │ ├── c100config.tcl │ │ │ │ │ ├── c100helper.tcl │ │ │ │ │ ├── c100regs.tcl │ │ │ │ │ ├── cc2538.cfg │ │ │ │ │ ├── cs351x.cfg │ │ │ │ │ ├── davinci.cfg │ │ │ │ │ ├── dragonite.cfg │ │ │ │ │ ├── dsp56321.cfg │ │ │ │ │ ├── dsp568013.cfg │ │ │ │ │ ├── dsp568037.cfg │ │ │ │ │ ├── efm32.cfg │ │ │ │ │ ├── em357.cfg │ │ │ │ │ ├── em358.cfg │ │ │ │ │ ├── eos_s3.cfg │ │ │ │ │ ├── epc9301.cfg │ │ │ │ │ ├── esi32xx.cfg │ │ │ │ │ ├── esp32s2.cfg │ │ │ │ │ ├── exynos5250.cfg │ │ │ │ │ ├── faux.cfg │ │ │ │ │ ├── feroceon.cfg │ │ │ │ │ ├── fm3.cfg │ │ │ │ │ ├── fm4.cfg │ │ │ │ │ ├── fm4_mb9bf.cfg │ │ │ │ │ ├── fm4_s6e2cc.cfg │ │ │ │ │ ├── gd32e23x.cfg │ │ │ │ │ ├── gd32vf103.cfg │ │ │ │ │ ├── gp326xxxa.cfg │ │ │ │ │ ├── hi3798.cfg │ │ │ │ │ ├── hi6220.cfg │ │ │ │ │ ├── hilscher_netx10.cfg │ │ │ │ │ ├── hilscher_netx50.cfg │ │ │ │ │ ├── hilscher_netx500.cfg │ │ │ │ │ ├── icepick.cfg │ │ │ │ │ ├── imx.cfg │ │ │ │ │ ├── imx21.cfg │ │ │ │ │ ├── imx25.cfg │ │ │ │ │ ├── imx27.cfg │ │ │ │ │ ├── imx28.cfg │ │ │ │ │ ├── imx31.cfg │ │ │ │ │ ├── imx35.cfg │ │ │ │ │ ├── imx51.cfg │ │ │ │ │ ├── imx53.cfg │ │ │ │ │ ├── imx6.cfg │ │ │ │ │ ├── imx6sx.cfg │ │ │ │ │ ├── imx6ul.cfg │ │ │ │ │ ├── imx7.cfg │ │ │ │ │ ├── imx7ulp.cfg │ │ │ │ │ ├── imx8m.cfg │ │ │ │ │ ├── imx8qm.cfg │ │ │ │ │ ├── infineon/ │ │ │ │ │ │ └── tle987x.cfg │ │ │ │ │ ├── is5114.cfg │ │ │ │ │ ├── ixp42x.cfg │ │ │ │ │ ├── k1921vk01t.cfg │ │ │ │ │ ├── k40.cfg │ │ │ │ │ ├── k60.cfg │ │ │ │ │ ├── ke0x.cfg │ │ │ │ │ ├── ke1xf.cfg │ │ │ │ │ ├── ke1xz.cfg │ │ │ │ │ ├── kl25.cfg │ │ │ │ │ ├── kl46.cfg │ │ │ │ │ ├── klx.cfg │ │ │ │ │ ├── ks869x.cfg │ │ │ │ │ ├── kx.cfg │ │ │ │ │ ├── lpc11xx.cfg │ │ │ │ │ ├── lpc12xx.cfg │ │ │ │ │ ├── lpc13xx.cfg │ │ │ │ │ ├── lpc17xx.cfg │ │ │ │ │ ├── lpc1850.cfg │ │ │ │ │ ├── lpc1xxx.cfg │ │ │ │ │ ├── lpc2103.cfg │ │ │ │ │ ├── lpc2124.cfg │ │ │ │ │ ├── lpc2129.cfg │ │ │ │ │ ├── lpc2148.cfg │ │ │ │ │ ├── lpc2294.cfg │ │ │ │ │ ├── lpc2378.cfg │ │ │ │ │ ├── lpc2460.cfg │ │ │ │ │ ├── lpc2478.cfg │ │ │ │ │ ├── lpc2900.cfg │ │ │ │ │ ├── lpc2xxx.cfg │ │ │ │ │ ├── lpc3131.cfg │ │ │ │ │ ├── lpc3250.cfg │ │ │ │ │ ├── lpc40xx.cfg │ │ │ │ │ ├── lpc4350.cfg │ │ │ │ │ ├── lpc4357.cfg │ │ │ │ │ ├── lpc4370.cfg │ │ │ │ │ ├── lpc84x.cfg │ │ │ │ │ ├── lpc8nxx.cfg │ │ │ │ │ ├── lpc8xx.cfg │ │ │ │ │ ├── ls1012a.cfg │ │ │ │ │ ├── ls1028a.cfg │ │ │ │ │ ├── ls1046a.cfg │ │ │ │ │ ├── ls1088a.cfg │ │ │ │ │ ├── lsch3_common.cfg │ │ │ │ │ ├── marvell/ │ │ │ │ │ │ ├── 88f3710.cfg │ │ │ │ │ │ ├── 88f3720.cfg │ │ │ │ │ │ └── 88f37x0.cfg │ │ │ │ │ ├── max32620.cfg │ │ │ │ │ ├── max32625.cfg │ │ │ │ │ ├── max3263x.cfg │ │ │ │ │ ├── mc13224v.cfg │ │ │ │ │ ├── mdr32f9q2i.cfg │ │ │ │ │ ├── nds32v2.cfg │ │ │ │ │ ├── nds32v3.cfg │ │ │ │ │ ├── nds32v3m.cfg │ │ │ │ │ ├── nds32v5.cfg │ │ │ │ │ ├── nhs31xx.cfg │ │ │ │ │ ├── npcx.cfg │ │ │ │ │ ├── nrf51.cfg │ │ │ │ │ ├── nrf52.cfg │ │ │ │ │ ├── nuc910.cfg │ │ │ │ │ ├── numicro.cfg │ │ │ │ │ ├── omap2420.cfg │ │ │ │ │ ├── omap3530.cfg │ │ │ │ │ ├── omap4430.cfg │ │ │ │ │ ├── omap4460.cfg │ │ │ │ │ ├── omap5912.cfg │ │ │ │ │ ├── omapl138.cfg │ │ │ │ │ ├── or1k.cfg │ │ │ │ │ ├── pic32mx.cfg │ │ │ │ │ ├── psoc4.cfg │ │ │ │ │ ├── psoc5lp.cfg │ │ │ │ │ ├── psoc6.cfg │ │ │ │ │ ├── pxa255.cfg │ │ │ │ │ ├── pxa270.cfg │ │ │ │ │ ├── pxa3xx.cfg │ │ │ │ │ ├── qualcomm_qca4531.cfg │ │ │ │ │ ├── quark_d20xx.cfg │ │ │ │ │ ├── quark_x10xx.cfg │ │ │ │ │ ├── readme.txt │ │ │ │ │ ├── renesas_r7s72100.cfg │ │ │ │ │ ├── renesas_rcar_gen2.cfg │ │ │ │ │ ├── renesas_rcar_gen3.cfg │ │ │ │ │ ├── renesas_rcar_reset_common.cfg │ │ │ │ │ ├── renesas_rz_five.cfg │ │ │ │ │ ├── renesas_rz_g2.cfg │ │ │ │ │ ├── renesas_s7g2.cfg │ │ │ │ │ ├── rk3308.cfg │ │ │ │ │ ├── rk3399.cfg │ │ │ │ │ ├── rp2040-core0.cfg │ │ │ │ │ ├── samsung_s3c2410.cfg │ │ │ │ │ ├── samsung_s3c2440.cfg │ │ │ │ │ ├── samsung_s3c2450.cfg │ │ │ │ │ ├── samsung_s3c4510.cfg │ │ │ │ │ ├── samsung_s3c6410.cfg │ │ │ │ │ ├── sharp_lh79532.cfg │ │ │ │ │ ├── sim3x.cfg │ │ │ │ │ ├── smp8634.cfg │ │ │ │ │ ├── snps_em_sk_fpga.cfg │ │ │ │ │ ├── snps_hsdk.cfg │ │ │ │ │ ├── spear3xx.cfg │ │ │ │ │ ├── stellaris.cfg │ │ │ │ │ ├── stm32f0x.cfg │ │ │ │ │ ├── stm32f1x.cfg │ │ │ │ │ ├── stm32f2x.cfg │ │ │ │ │ ├── stm32f3x.cfg │ │ │ │ │ ├── stm32f4x.cfg │ │ │ │ │ ├── stm32f7x.cfg │ │ │ │ │ ├── stm32g0x.cfg │ │ │ │ │ ├── stm32g4x.cfg │ │ │ │ │ ├── stm32h7x.cfg │ │ │ │ │ ├── stm32h7x_dual_bank.cfg │ │ │ │ │ ├── stm32l0.cfg │ │ │ │ │ ├── stm32l0_dual_bank.cfg │ │ │ │ │ ├── stm32l1.cfg │ │ │ │ │ ├── stm32l1x_dual_bank.cfg │ │ │ │ │ ├── stm32l4x.cfg │ │ │ │ │ ├── stm32l5x.cfg │ │ │ │ │ ├── stm32mp13x.cfg │ │ │ │ │ ├── stm32mp15x.cfg │ │ │ │ │ ├── stm32u5x.cfg │ │ │ │ │ ├── stm32w108xx.cfg │ │ │ │ │ ├── stm32wbx.cfg │ │ │ │ │ ├── stm32wlx.cfg │ │ │ │ │ ├── stm32x5x_common.cfg │ │ │ │ │ ├── stm32xl.cfg │ │ │ │ │ ├── stm8l.cfg │ │ │ │ │ ├── stm8l152.cfg │ │ │ │ │ ├── stm8s.cfg │ │ │ │ │ ├── stm8s003.cfg │ │ │ │ │ ├── stm8s103.cfg │ │ │ │ │ ├── stm8s105.cfg │ │ │ │ │ ├── str710.cfg │ │ │ │ │ ├── str730.cfg │ │ │ │ │ ├── str750.cfg │ │ │ │ │ ├── str912.cfg │ │ │ │ │ ├── swj-dp.tcl │ │ │ │ │ ├── swm050.cfg │ │ │ │ │ ├── test_reset_syntax_error.cfg │ │ │ │ │ ├── test_syntax_error.cfg │ │ │ │ │ ├── ti-ar7.cfg │ │ │ │ │ ├── ti-cjtag.cfg │ │ │ │ │ ├── ti_calypso.cfg │ │ │ │ │ ├── ti_cc13x0.cfg │ │ │ │ │ ├── ti_cc13x2.cfg │ │ │ │ │ ├── ti_cc26x0.cfg │ │ │ │ │ ├── ti_cc26x2.cfg │ │ │ │ │ ├── ti_cc3220sf.cfg │ │ │ │ │ ├── ti_cc32xx.cfg │ │ │ │ │ ├── ti_dm355.cfg │ │ │ │ │ ├── ti_dm365.cfg │ │ │ │ │ ├── ti_dm6446.cfg │ │ │ │ │ ├── ti_k3.cfg │ │ │ │ │ ├── ti_msp432.cfg │ │ │ │ │ ├── ti_rm4x.cfg │ │ │ │ │ ├── ti_tms570.cfg │ │ │ │ │ ├── ti_tms570ls20xxx.cfg │ │ │ │ │ ├── ti_tms570ls3137.cfg │ │ │ │ │ ├── tmpa900.cfg │ │ │ │ │ ├── tmpa910.cfg │ │ │ │ │ ├── tnetc4401.cfg │ │ │ │ │ ├── u8500.cfg │ │ │ │ │ ├── vd_aarch64.cfg │ │ │ │ │ ├── vd_cortex_m.cfg │ │ │ │ │ ├── vd_riscv.cfg │ │ │ │ │ ├── vybrid_vf6xx.cfg │ │ │ │ │ ├── xilinx_zynqmp.cfg │ │ │ │ │ ├── xmc1xxx.cfg │ │ │ │ │ ├── xmc4xxx.cfg │ │ │ │ │ ├── xmos_xs1-xau8a-10_arm.cfg │ │ │ │ │ ├── zynq_7000.cfg │ │ │ │ │ └── к1879xб1я.cfg │ │ │ │ ├── test/ │ │ │ │ │ ├── selftest.cfg │ │ │ │ │ └── syntax1.cfg │ │ │ │ └── tools/ │ │ │ │ ├── firmware-recovery.tcl │ │ │ │ ├── memtest.tcl │ │ │ │ └── test_cpu_speed.tcl │ │ │ └── share/ │ │ │ ├── info/ │ │ │ │ ├── dir │ │ │ │ ├── openocd.info │ │ │ │ ├── openocd.info-1 │ │ │ │ └── openocd.info-2 │ │ │ ├── man/ │ │ │ │ └── man1/ │ │ │ │ └── openocd.1 │ │ │ └── openocd/ │ │ │ ├── contrib/ │ │ │ │ ├── 60-openocd.rules │ │ │ │ └── libdcc/ │ │ │ │ ├── README │ │ │ │ ├── dcc_stdio.c │ │ │ │ ├── dcc_stdio.h │ │ │ │ └── example.c │ │ │ └── scripts/ │ │ │ ├── bitsbytes.tcl │ │ │ ├── board/ │ │ │ │ ├── 8devices-lima.cfg │ │ │ │ ├── actux3.cfg │ │ │ │ ├── adapteva_parallella1.cfg │ │ │ │ ├── adsp-sc584-ezbrd.cfg │ │ │ │ ├── alphascale_asm9260_ek.cfg │ │ │ │ ├── altera_sockit.cfg │ │ │ │ ├── am3517evm.cfg │ │ │ │ ├── ampere_emag8180.cfg │ │ │ │ ├── arm_evaluator7t.cfg │ │ │ │ ├── arm_musca_a.cfg │ │ │ │ ├── arty_s7.cfg │ │ │ │ ├── asus-rt-n16.cfg │ │ │ │ ├── asus-rt-n66u.cfg │ │ │ │ ├── at91cap7a-stk-sdram.cfg │ │ │ │ ├── at91eb40a.cfg │ │ │ │ ├── at91rm9200-dk.cfg │ │ │ │ ├── at91rm9200-ek.cfg │ │ │ │ ├── at91sam9261-ek.cfg │ │ │ │ ├── at91sam9263-ek.cfg │ │ │ │ ├── at91sam9g20-ek.cfg │ │ │ │ ├── atmel_at91sam7s-ek.cfg │ │ │ │ ├── atmel_at91sam9260-ek.cfg │ │ │ │ ├── atmel_at91sam9rl-ek.cfg │ │ │ │ ├── atmel_sam3n_ek.cfg │ │ │ │ ├── atmel_sam3s_ek.cfg │ │ │ │ ├── atmel_sam3u_ek.cfg │ │ │ │ ├── atmel_sam3x_ek.cfg │ │ │ │ ├── atmel_sam4e_ek.cfg │ │ │ │ ├── atmel_sam4l8_xplained_pro.cfg │ │ │ │ ├── atmel_sam4s_ek.cfg │ │ │ │ ├── atmel_sam4s_xplained_pro.cfg │ │ │ │ ├── atmel_samc20_xplained_pro.cfg │ │ │ │ ├── atmel_samc21_xplained_pro.cfg │ │ │ │ ├── atmel_samd10_xplained_mini.cfg │ │ │ │ ├── atmel_samd11_xplained_pro.cfg │ │ │ │ ├── atmel_samd20_xplained_pro.cfg │ │ │ │ ├── atmel_samd21_xplained_pro.cfg │ │ │ │ ├── atmel_same70_xplained.cfg │ │ │ │ ├── atmel_samg53_xplained_pro.cfg │ │ │ │ ├── atmel_samg55_xplained_pro.cfg │ │ │ │ ├── atmel_saml21_xplained_pro.cfg │ │ │ │ ├── atmel_samr21_xplained_pro.cfg │ │ │ │ ├── atmel_samv71_xplained_ultra.cfg │ │ │ │ ├── avnet_ultrazed-eg.cfg │ │ │ │ ├── balloon3-cpu.cfg │ │ │ │ ├── bcm28155_ap.cfg │ │ │ │ ├── bluefield.cfg │ │ │ │ ├── bt-homehubv1.cfg │ │ │ │ ├── colibri.cfg │ │ │ │ ├── crossbow_tech_imote2.cfg │ │ │ │ ├── csb337.cfg │ │ │ │ ├── csb732.cfg │ │ │ │ ├── da850evm.cfg │ │ │ │ ├── digi_connectcore_wi-9c.cfg │ │ │ │ ├── digilent_analog_discovery.cfg │ │ │ │ ├── digilent_atlys.cfg │ │ │ │ ├── digilent_nexys_video.cfg │ │ │ │ ├── digilent_zedboard.cfg │ │ │ │ ├── diolan_lpc4350-db1.cfg │ │ │ │ ├── diolan_lpc4357-db1.cfg │ │ │ │ ├── dk-tm4c129.cfg │ │ │ │ ├── dm355evm.cfg │ │ │ │ ├── dm365evm.cfg │ │ │ │ ├── dm6446evm.cfg │ │ │ │ ├── dp_busblaster_v3.cfg │ │ │ │ ├── dp_busblaster_v4.cfg │ │ │ │ ├── dptechnics_dpt-board-v1.cfg │ │ │ │ ├── efikamx.cfg │ │ │ │ ├── efm32.cfg │ │ │ │ ├── eir.cfg │ │ │ │ ├── ek-lm3s1968.cfg │ │ │ │ ├── ek-lm3s3748.cfg │ │ │ │ ├── ek-lm3s6965.cfg │ │ │ │ ├── ek-lm3s811-revb.cfg │ │ │ │ ├── ek-lm3s811.cfg │ │ │ │ ├── ek-lm3s8962.cfg │ │ │ │ ├── ek-lm3s9b9x.cfg │ │ │ │ ├── ek-lm3s9d92.cfg │ │ │ │ ├── ek-lm4f120xl.cfg │ │ │ │ ├── ek-lm4f232.cfg │ │ │ │ ├── ek-tm4c123gxl.cfg │ │ │ │ ├── ek-tm4c1294xl.cfg │ │ │ │ ├── embedded-artists_lpc2478-32.cfg │ │ │ │ ├── emcraft_imx8m-som-bsb.cfg │ │ │ │ ├── emcraft_twr-vf6-som-bsb.cfg │ │ │ │ ├── emcraft_vf6-som.cfg │ │ │ │ ├── esp32s2-kaluga-1.cfg │ │ │ │ ├── ethernut3.cfg │ │ │ │ ├── evb-lan9255.cfg │ │ │ │ ├── frdm-kl25z.cfg │ │ │ │ ├── frdm-kl46z.cfg │ │ │ │ ├── fsl_imx6q_sabresd.cfg │ │ │ │ ├── glyn_tonga2.cfg │ │ │ │ ├── gti/ │ │ │ │ │ └── espressobin.cfg │ │ │ │ ├── gumstix-aerocore.cfg │ │ │ │ ├── hammer.cfg │ │ │ │ ├── hilscher_nxdb500sys.cfg │ │ │ │ ├── hilscher_nxeb500hmi.cfg │ │ │ │ ├── hilscher_nxhx10.cfg │ │ │ │ ├── hilscher_nxhx50.cfg │ │ │ │ ├── hilscher_nxhx500.cfg │ │ │ │ ├── hilscher_nxsb100.cfg │ │ │ │ ├── hitex_lpc1768stick.cfg │ │ │ │ ├── hitex_lpc2929.cfg │ │ │ │ ├── hitex_stm32-performancestick.cfg │ │ │ │ ├── hitex_str9-comstick.cfg │ │ │ │ ├── iar_lpc1768.cfg │ │ │ │ ├── iar_str912_sk.cfg │ │ │ │ ├── icnova_imx53_sodimm.cfg │ │ │ │ ├── icnova_sam9g45_sodimm.cfg │ │ │ │ ├── imx27ads.cfg │ │ │ │ ├── imx27lnst.cfg │ │ │ │ ├── imx28evk.cfg │ │ │ │ ├── imx31pdk.cfg │ │ │ │ ├── imx35pdk.cfg │ │ │ │ ├── imx53-m53evk.cfg │ │ │ │ ├── imx53loco.cfg │ │ │ │ ├── imx8mp-evk.cfg │ │ │ │ ├── insignal_arndale.cfg │ │ │ │ ├── kasli.cfg │ │ │ │ ├── kc100.cfg │ │ │ │ ├── kc705.cfg │ │ │ │ ├── kcu105.cfg │ │ │ │ ├── keil_mcb1700.cfg │ │ │ │ ├── keil_mcb2140.cfg │ │ │ │ ├── kindle2.cfg │ │ │ │ ├── kontron_sl28.cfg │ │ │ │ ├── kwikstik.cfg │ │ │ │ ├── la_fonera-fon2200.cfg │ │ │ │ ├── lambdaconcept_ecpix-5.cfg │ │ │ │ ├── lemaker_hikey.cfg │ │ │ │ ├── linksys-wag200g.cfg │ │ │ │ ├── linksys-wrt54gl.cfg │ │ │ │ ├── linksys_nslu2.cfg │ │ │ │ ├── lisa-l.cfg │ │ │ │ ├── logicpd_imx27.cfg │ │ │ │ ├── lpc1850_spifi_generic.cfg │ │ │ │ ├── lpc4350_spifi_generic.cfg │ │ │ │ ├── lubbock.cfg │ │ │ │ ├── marsohod.cfg │ │ │ │ ├── marsohod2.cfg │ │ │ │ ├── marsohod3.cfg │ │ │ │ ├── mbed-lpc11u24.cfg │ │ │ │ ├── mbed-lpc1768.cfg │ │ │ │ ├── mcb1700.cfg │ │ │ │ ├── microchip_explorer16.cfg │ │ │ │ ├── microchip_sama5d27_som1_kit1.cfg │ │ │ │ ├── microchip_same51_curiosity_nano.cfg │ │ │ │ ├── microchip_same54_xplained_pro.cfg │ │ │ │ ├── microchip_saml11_xplained_pro.cfg │ │ │ │ ├── mini2440.cfg │ │ │ │ ├── mini6410.cfg │ │ │ │ ├── minispartan6.cfg │ │ │ │ ├── nds32_corvettef1.cfg │ │ │ │ ├── nds32_xc5.cfg │ │ │ │ ├── nds32_xc7.cfg │ │ │ │ ├── netgear-dg834v3.cfg │ │ │ │ ├── netgear-wg102.cfg │ │ │ │ ├── nordic_nrf51822_mkit.cfg │ │ │ │ ├── nordic_nrf51_dk.cfg │ │ │ │ ├── nordic_nrf52_dk.cfg │ │ │ │ ├── nordic_nrf52_ftx232.cfg │ │ │ │ ├── novena-internal-fpga.cfg │ │ │ │ ├── npcx_evb.cfg │ │ │ │ ├── numato_mimas_a7.cfg │ │ │ │ ├── numato_opsis.cfg │ │ │ │ ├── nxp_frdm-k64f.cfg │ │ │ │ ├── nxp_frdm-ls1012a.cfg │ │ │ │ ├── nxp_imx7sabre.cfg │ │ │ │ ├── nxp_lpc-link2.cfg │ │ │ │ ├── nxp_mcimx8m-evk.cfg │ │ │ │ ├── nxp_rdb-ls1046a.cfg │ │ │ │ ├── nxp_rdb-ls1088a.cfg │ │ │ │ ├── olimex_LPC2378STK.cfg │ │ │ │ ├── olimex_lpc_h2148.cfg │ │ │ │ ├── olimex_sam7_ex256.cfg │ │ │ │ ├── olimex_sam7_la2.cfg │ │ │ │ ├── olimex_sam9_l9260.cfg │ │ │ │ ├── olimex_stm32_h103.cfg │ │ │ │ ├── olimex_stm32_h107.cfg │ │ │ │ ├── olimex_stm32_h405.cfg │ │ │ │ ├── olimex_stm32_p107.cfg │ │ │ │ ├── omap2420_h4.cfg │ │ │ │ ├── openrd.cfg │ │ │ │ ├── or1k_generic.cfg │ │ │ │ ├── osk5912.cfg │ │ │ │ ├── phone_se_j100i.cfg │ │ │ │ ├── phytec_lpc3250.cfg │ │ │ │ ├── pic-p32mx.cfg │ │ │ │ ├── pico-debug.cfg │ │ │ │ ├── pipistrello.cfg │ │ │ │ ├── propox_mmnet1001.cfg │ │ │ │ ├── pxa255_sst.cfg │ │ │ │ ├── quark_d2000_refboard.cfg │ │ │ │ ├── quark_x10xx_board.cfg │ │ │ │ ├── quicklogic_quickfeather.cfg │ │ │ │ ├── radiona_ulx3s.cfg │ │ │ │ ├── redbee.cfg │ │ │ │ ├── reflexces_achilles_i-dev_kit_arria10.cfg │ │ │ │ ├── renesas_dk-s7g2.cfg │ │ │ │ ├── renesas_falcon.cfg │ │ │ │ ├── renesas_gr_peach.cfg │ │ │ │ ├── renesas_porter.cfg │ │ │ │ ├── renesas_salvator-xs.cfg │ │ │ │ ├── renesas_silk.cfg │ │ │ │ ├── renesas_stout.cfg │ │ │ │ ├── rigado_bmd300_ek.cfg │ │ │ │ ├── rpi3.cfg │ │ │ │ ├── rpi4b.cfg │ │ │ │ ├── rsc-w910.cfg │ │ │ │ ├── sayma_amc.cfg │ │ │ │ ├── sheevaplug.cfg │ │ │ │ ├── sifive-e31arty.cfg │ │ │ │ ├── sifive-e51arty.cfg │ │ │ │ ├── sifive-hifive1-revb.cfg │ │ │ │ ├── sifive-hifive1.cfg │ │ │ │ ├── smdk6410.cfg │ │ │ │ ├── snps_em_sk.cfg │ │ │ │ ├── snps_em_sk_v1.cfg │ │ │ │ ├── snps_em_sk_v2.1.cfg │ │ │ │ ├── snps_em_sk_v2.2.cfg │ │ │ │ ├── snps_hsdk.cfg │ │ │ │ ├── spansion_sk-fm4-176l-s6e2cc.cfg │ │ │ │ ├── spansion_sk-fm4-u120-9b560.cfg │ │ │ │ ├── spear300evb.cfg │ │ │ │ ├── spear300evb_mod.cfg │ │ │ │ ├── spear310evb20.cfg │ │ │ │ ├── spear310evb20_mod.cfg │ │ │ │ ├── spear320cpu.cfg │ │ │ │ ├── spear320cpu_mod.cfg │ │ │ │ ├── st_b-l475e-iot01a.cfg │ │ │ │ ├── st_nucleo_8l152r8.cfg │ │ │ │ ├── st_nucleo_8s208rb.cfg │ │ │ │ ├── st_nucleo_f0.cfg │ │ │ │ ├── st_nucleo_f103rb.cfg │ │ │ │ ├── st_nucleo_f3.cfg │ │ │ │ ├── st_nucleo_f4.cfg │ │ │ │ ├── st_nucleo_f7.cfg │ │ │ │ ├── st_nucleo_g0.cfg │ │ │ │ ├── st_nucleo_g4.cfg │ │ │ │ ├── st_nucleo_h743zi.cfg │ │ │ │ ├── st_nucleo_h745zi.cfg │ │ │ │ ├── st_nucleo_l073rz.cfg │ │ │ │ ├── st_nucleo_l1.cfg │ │ │ │ ├── st_nucleo_l4.cfg │ │ │ │ ├── st_nucleo_l5.cfg │ │ │ │ ├── st_nucleo_wb55.cfg │ │ │ │ ├── steval-idb007v1.cfg │ │ │ │ ├── steval-idb008v1.cfg │ │ │ │ ├── steval-idb011v1.cfg │ │ │ │ ├── steval-idb012v1.cfg │ │ │ │ ├── steval_pcc010.cfg │ │ │ │ ├── stm320518_eval.cfg │ │ │ │ ├── stm320518_eval_stlink.cfg │ │ │ │ ├── stm32100b_eval.cfg │ │ │ │ ├── stm3210b_eval.cfg │ │ │ │ ├── stm3210c_eval.cfg │ │ │ │ ├── stm3210e_eval.cfg │ │ │ │ ├── stm3220g_eval.cfg │ │ │ │ ├── stm3220g_eval_stlink.cfg │ │ │ │ ├── stm3241g_eval.cfg │ │ │ │ ├── stm3241g_eval_stlink.cfg │ │ │ │ ├── stm32429i_eval.cfg │ │ │ │ ├── stm32429i_eval_stlink.cfg │ │ │ │ ├── stm32439i_eval.cfg │ │ │ │ ├── stm32439i_eval_stlink.cfg │ │ │ │ ├── stm327x6g_eval.cfg │ │ │ │ ├── stm32f0discovery.cfg │ │ │ │ ├── stm32f103c8_blue_pill.cfg │ │ │ │ ├── stm32f334discovery.cfg │ │ │ │ ├── stm32f3discovery.cfg │ │ │ │ ├── stm32f412g-disco.cfg │ │ │ │ ├── stm32f413h-disco.cfg │ │ │ │ ├── stm32f429disc1.cfg │ │ │ │ ├── stm32f429discovery.cfg │ │ │ │ ├── stm32f469discovery.cfg │ │ │ │ ├── stm32f469i-disco.cfg │ │ │ │ ├── stm32f4discovery.cfg │ │ │ │ ├── stm32f723e-disco.cfg │ │ │ │ ├── stm32f746g-disco.cfg │ │ │ │ ├── stm32f769i-disco.cfg │ │ │ │ ├── stm32f7discovery.cfg │ │ │ │ ├── stm32h735g-disco.cfg │ │ │ │ ├── stm32h745i-disco.cfg │ │ │ │ ├── stm32h747i-disco.cfg │ │ │ │ ├── stm32h750b-disco.cfg │ │ │ │ ├── stm32h7b3i-disco.cfg │ │ │ │ ├── stm32h7x3i_eval.cfg │ │ │ │ ├── stm32h7x_dual_qspi.cfg │ │ │ │ ├── stm32l0discovery.cfg │ │ │ │ ├── stm32l476g-disco.cfg │ │ │ │ ├── stm32l496g-disco.cfg │ │ │ │ ├── stm32l4discovery.cfg │ │ │ │ ├── stm32l4p5g-disco.cfg │ │ │ │ ├── stm32l4r9i-disco.cfg │ │ │ │ ├── stm32ldiscovery.cfg │ │ │ │ ├── stm32mp13x_dk.cfg │ │ │ │ ├── stm32mp15x_dk2.cfg │ │ │ │ ├── stm32vldiscovery.cfg │ │ │ │ ├── str910-eval.cfg │ │ │ │ ├── telo.cfg │ │ │ │ ├── ti_am335xevm.cfg │ │ │ │ ├── ti_am437x_idk.cfg │ │ │ │ ├── ti_am43xx_evm.cfg │ │ │ │ ├── ti_am625evm.cfg │ │ │ │ ├── ti_am642evm.cfg │ │ │ │ ├── ti_am654evm.cfg │ │ │ │ ├── ti_beagleboard.cfg │ │ │ │ ├── ti_beagleboard_xm.cfg │ │ │ │ ├── ti_beaglebone-base.cfg │ │ │ │ ├── ti_beaglebone.cfg │ │ │ │ ├── ti_beaglebone_black.cfg │ │ │ │ ├── ti_blaze.cfg │ │ │ │ ├── ti_cc13x0_launchpad.cfg │ │ │ │ ├── ti_cc13x2_launchpad.cfg │ │ │ │ ├── ti_cc26x0_launchpad.cfg │ │ │ │ ├── ti_cc26x2_launchpad.cfg │ │ │ │ ├── ti_cc3200_launchxl.cfg │ │ │ │ ├── ti_cc3220sf_launchpad.cfg │ │ │ │ ├── ti_cc32xx_launchpad.cfg │ │ │ │ ├── ti_dk-tm4c129.cfg │ │ │ │ ├── ti_ek-tm4c123gxl.cfg │ │ │ │ ├── ti_ek-tm4c1294xl.cfg │ │ │ │ ├── ti_j7200evm.cfg │ │ │ │ ├── ti_j721evm.cfg │ │ │ │ ├── ti_j721s2evm.cfg │ │ │ │ ├── ti_msp432_launchpad.cfg │ │ │ │ ├── ti_pandaboard.cfg │ │ │ │ ├── ti_pandaboard_es.cfg │ │ │ │ ├── ti_tmdx570ls20susb.cfg │ │ │ │ ├── ti_tmdx570ls31usb.cfg │ │ │ │ ├── tocoding_poplar.cfg │ │ │ │ ├── topas910.cfg │ │ │ │ ├── topasa900.cfg │ │ │ │ ├── tp-link_tl-mr3020.cfg │ │ │ │ ├── tp-link_wdr4300.cfg │ │ │ │ ├── twr-k60f120m.cfg │ │ │ │ ├── twr-k60n512.cfg │ │ │ │ ├── twr-vf65gs10.cfg │ │ │ │ ├── twr-vf65gs10_cmsisdap.cfg │ │ │ │ ├── tx25_stk5.cfg │ │ │ │ ├── tx27_stk5.cfg │ │ │ │ ├── unknown_at91sam9260.cfg │ │ │ │ ├── uptech_2410.cfg │ │ │ │ ├── vd_a53x2_jtag.cfg │ │ │ │ ├── vd_m4_jtag.cfg │ │ │ │ ├── vd_pulpissimo_jtag.cfg │ │ │ │ ├── vd_swerv_jtag.cfg │ │ │ │ ├── verdex.cfg │ │ │ │ ├── voipac.cfg │ │ │ │ ├── voltcraft_dso-3062c.cfg │ │ │ │ ├── x300t.cfg │ │ │ │ ├── xmc-2go.cfg │ │ │ │ ├── xmc1100-boot-kit.cfg │ │ │ │ ├── xmc4200-application-kit-actuator.cfg │ │ │ │ ├── xmc4300-relax.cfg │ │ │ │ ├── xmc4500-application-kit-general.cfg │ │ │ │ ├── xmc4500-application-kit-sdram.cfg │ │ │ │ ├── xmc4500-relax.cfg │ │ │ │ ├── xmc4700-relax.cfg │ │ │ │ ├── xmc4800-relax.cfg │ │ │ │ └── xmos_xk-xac-xa8_arm.cfg │ │ │ ├── chip/ │ │ │ │ ├── atmel/ │ │ │ │ │ └── at91/ │ │ │ │ │ ├── aic.tcl │ │ │ │ │ ├── at91_pio.cfg │ │ │ │ │ ├── at91_pmc.cfg │ │ │ │ │ ├── at91_rstc.cfg │ │ │ │ │ ├── at91_wdt.cfg │ │ │ │ │ ├── at91sam7x128.tcl │ │ │ │ │ ├── at91sam7x256.tcl │ │ │ │ │ ├── at91sam9261.cfg │ │ │ │ │ ├── at91sam9261_matrix.cfg │ │ │ │ │ ├── at91sam9263.cfg │ │ │ │ │ ├── at91sam9263_matrix.cfg │ │ │ │ │ ├── at91sam9_init.cfg │ │ │ │ │ ├── at91sam9_sdramc.cfg │ │ │ │ │ ├── at91sam9_smc.cfg │ │ │ │ │ ├── hardware.cfg │ │ │ │ │ ├── pmc.tcl │ │ │ │ │ ├── rtt.tcl │ │ │ │ │ ├── sam9_smc.cfg │ │ │ │ │ └── usarts.tcl │ │ │ │ ├── st/ │ │ │ │ │ ├── spear/ │ │ │ │ │ │ ├── quirk_no_srst.tcl │ │ │ │ │ │ ├── spear3xx.tcl │ │ │ │ │ │ └── spear3xx_ddr.tcl │ │ │ │ │ └── stm32/ │ │ │ │ │ ├── stm32.tcl │ │ │ │ │ ├── stm32_rcc.tcl │ │ │ │ │ └── stm32_regs.tcl │ │ │ │ └── ti/ │ │ │ │ └── lm3s/ │ │ │ │ ├── lm3s.tcl │ │ │ │ └── lm3s_regs.tcl │ │ │ ├── cpld/ │ │ │ │ ├── altera-5m570z-cpld.cfg │ │ │ │ ├── altera-epm240.cfg │ │ │ │ ├── jtagspi.cfg │ │ │ │ ├── lattice-lc4032ze.cfg │ │ │ │ ├── xilinx-xc6s.cfg │ │ │ │ ├── xilinx-xc7.cfg │ │ │ │ ├── xilinx-xcf-p.cfg │ │ │ │ ├── xilinx-xcf-s.cfg │ │ │ │ ├── xilinx-xcr3256.cfg │ │ │ │ └── xilinx-xcu.cfg │ │ │ ├── cpu/ │ │ │ │ ├── arc/ │ │ │ │ │ ├── common.tcl │ │ │ │ │ ├── em.tcl │ │ │ │ │ ├── hs.tcl │ │ │ │ │ └── v2.tcl │ │ │ │ └── arm/ │ │ │ │ ├── arm7tdmi.tcl │ │ │ │ ├── arm920.tcl │ │ │ │ ├── arm946.tcl │ │ │ │ ├── arm966.tcl │ │ │ │ └── cortex_m3.tcl │ │ │ ├── fpga/ │ │ │ │ ├── altera-10m50.cfg │ │ │ │ ├── altera-ep3c10.cfg │ │ │ │ ├── lattice_ecp5.cfg │ │ │ │ ├── xilinx-dna.cfg │ │ │ │ └── xilinx-xadc.cfg │ │ │ ├── interface/ │ │ │ │ ├── altera-usb-blaster.cfg │ │ │ │ ├── altera-usb-blaster2.cfg │ │ │ │ ├── arm-jtag-ew.cfg │ │ │ │ ├── at91rm9200.cfg │ │ │ │ ├── beaglebone-jtag-native.cfg │ │ │ │ ├── beaglebone-swd-native.cfg │ │ │ │ ├── buspirate.cfg │ │ │ │ ├── calao-usb-a9260.cfg │ │ │ │ ├── chameleon.cfg │ │ │ │ ├── cmsis-dap.cfg │ │ │ │ ├── dln-2-gpiod.cfg │ │ │ │ ├── dummy.cfg │ │ │ │ ├── estick.cfg │ │ │ │ ├── flashlink.cfg │ │ │ │ ├── ft232r/ │ │ │ │ │ └── radiona_ulx3s.cfg │ │ │ │ ├── ft232r.cfg │ │ │ │ ├── ftdi/ │ │ │ │ │ ├── 100ask-openjtag.cfg │ │ │ │ │ ├── ashling-opella-ld-jtag.cfg │ │ │ │ │ ├── ashling-opella-ld-swd.cfg │ │ │ │ │ ├── axm0432.cfg │ │ │ │ │ ├── c232hm.cfg │ │ │ │ │ ├── calao-usb-a9260-c01.cfg │ │ │ │ │ ├── calao-usb-a9260-c02.cfg │ │ │ │ │ ├── cortino.cfg │ │ │ │ │ ├── digilent-hs1.cfg │ │ │ │ │ ├── digilent-hs2.cfg │ │ │ │ │ ├── digilent_jtag_hs3.cfg │ │ │ │ │ ├── digilent_jtag_smt2.cfg │ │ │ │ │ ├── digilent_jtag_smt2_nc.cfg │ │ │ │ │ ├── dlp-usb1232h.cfg │ │ │ │ │ ├── dp_busblaster.cfg │ │ │ │ │ ├── dp_busblaster_kt-link.cfg │ │ │ │ │ ├── esp32s2_kaluga_v1.cfg │ │ │ │ │ ├── flossjtag-noeeprom.cfg │ │ │ │ │ ├── flossjtag.cfg │ │ │ │ │ ├── flyswatter.cfg │ │ │ │ │ ├── flyswatter2.cfg │ │ │ │ │ ├── ft232h-module-swd.cfg │ │ │ │ │ ├── gw16042.cfg │ │ │ │ │ ├── hie-jtag.cfg │ │ │ │ │ ├── hilscher_nxhx10_etm.cfg │ │ │ │ │ ├── hilscher_nxhx500_etm.cfg │ │ │ │ │ ├── hilscher_nxhx500_re.cfg │ │ │ │ │ ├── hilscher_nxhx50_etm.cfg │ │ │ │ │ ├── hilscher_nxhx50_re.cfg │ │ │ │ │ ├── hitex_lpc1768stick.cfg │ │ │ │ │ ├── hitex_str9-comstick.cfg │ │ │ │ │ ├── icebear.cfg │ │ │ │ │ ├── imx8mp-evk.cfg │ │ │ │ │ ├── incircuit-icprog.cfg │ │ │ │ │ ├── iotlab-usb.cfg │ │ │ │ │ ├── isodebug.cfg │ │ │ │ │ ├── jtag-lock-pick_tiny_2.cfg │ │ │ │ │ ├── jtagkey.cfg │ │ │ │ │ ├── jtagkey2.cfg │ │ │ │ │ ├── jtagkey2p.cfg │ │ │ │ │ ├── kt-link.cfg │ │ │ │ │ ├── lambdaconcept_ecpix-5.cfg │ │ │ │ │ ├── lisa-l.cfg │ │ │ │ │ ├── luminary-icdi.cfg │ │ │ │ │ ├── luminary-lm3s811.cfg │ │ │ │ │ ├── luminary.cfg │ │ │ │ │ ├── m53evk.cfg │ │ │ │ │ ├── mbftdi.cfg │ │ │ │ │ ├── minimodule-swd.cfg │ │ │ │ │ ├── minimodule.cfg │ │ │ │ │ ├── minispartan6.cfg │ │ │ │ │ ├── miniwiggler.cfg │ │ │ │ │ ├── neodb.cfg │ │ │ │ │ ├── ngxtech.cfg │ │ │ │ │ ├── olimex-arm-jtag-swd.cfg │ │ │ │ │ ├── olimex-arm-usb-ocd-h.cfg │ │ │ │ │ ├── olimex-arm-usb-ocd.cfg │ │ │ │ │ ├── olimex-arm-usb-tiny-h.cfg │ │ │ │ │ ├── olimex-jtag-tiny.cfg │ │ │ │ │ ├── oocdlink.cfg │ │ │ │ │ ├── opendous_ftdi.cfg │ │ │ │ │ ├── openocd-usb-hs.cfg │ │ │ │ │ ├── openocd-usb.cfg │ │ │ │ │ ├── openrd.cfg │ │ │ │ │ ├── pipistrello.cfg │ │ │ │ │ ├── pls_spc5.cfg │ │ │ │ │ ├── redbee-econotag.cfg │ │ │ │ │ ├── redbee-usb.cfg │ │ │ │ │ ├── rowley-cc-arm-swd.cfg │ │ │ │ │ ├── sheevaplug.cfg │ │ │ │ │ ├── signalyzer-lite.cfg │ │ │ │ │ ├── signalyzer.cfg │ │ │ │ │ ├── snps_sdp.cfg │ │ │ │ │ ├── steppenprobe.cfg │ │ │ │ │ ├── stm32-stick.cfg │ │ │ │ │ ├── swd-resistor-hack.cfg │ │ │ │ │ ├── ti-icdi.cfg │ │ │ │ │ ├── tigard.cfg │ │ │ │ │ ├── tumpa-lite.cfg │ │ │ │ │ ├── tumpa.cfg │ │ │ │ │ ├── turtelizer2-revB.cfg │ │ │ │ │ ├── turtelizer2-revC.cfg │ │ │ │ │ ├── um232h.cfg │ │ │ │ │ ├── vpaclink.cfg │ │ │ │ │ ├── xds100v2.cfg │ │ │ │ │ └── xds100v3.cfg │ │ │ │ ├── imx-native.cfg │ │ │ │ ├── jlink.cfg │ │ │ │ ├── jtag_dpi.cfg │ │ │ │ ├── jtag_hat_rpi2.cfg │ │ │ │ ├── jtag_vpi.cfg │ │ │ │ ├── kitprog.cfg │ │ │ │ ├── nds32-aice.cfg │ │ │ │ ├── nulink.cfg │ │ │ │ ├── opendous.cfg │ │ │ │ ├── openjtag.cfg │ │ │ │ ├── osbdm.cfg │ │ │ │ ├── parport.cfg │ │ │ │ ├── parport_dlc5.cfg │ │ │ │ ├── raspberrypi-native.cfg │ │ │ │ ├── raspberrypi2-native.cfg │ │ │ │ ├── rlink.cfg │ │ │ │ ├── rshim.cfg │ │ │ │ ├── stlink-dap.cfg │ │ │ │ ├── stlink-v1.cfg │ │ │ │ ├── stlink-v2-1.cfg │ │ │ │ ├── stlink-v2.cfg │ │ │ │ ├── stlink.cfg │ │ │ │ ├── sysfsgpio-raspberrypi.cfg │ │ │ │ ├── ti-icdi.cfg │ │ │ │ ├── ulink.cfg │ │ │ │ ├── usb-jtag.cfg │ │ │ │ ├── usbprog.cfg │ │ │ │ ├── vdebug.cfg │ │ │ │ ├── vsllink.cfg │ │ │ │ └── xds110.cfg │ │ │ ├── mem_helper.tcl │ │ │ ├── memory.tcl │ │ │ ├── mmr_helpers.tcl │ │ │ ├── target/ │ │ │ │ ├── 1986ве1т.cfg │ │ │ │ ├── adsp-sc58x.cfg │ │ │ │ ├── aduc702x.cfg │ │ │ │ ├── aducm360.cfg │ │ │ │ ├── allwinner_v3s.cfg │ │ │ │ ├── alphascale_asm9260t.cfg │ │ │ │ ├── altera_fpgasoc.cfg │ │ │ │ ├── altera_fpgasoc_arria10.cfg │ │ │ │ ├── am335x.cfg │ │ │ │ ├── am437x.cfg │ │ │ │ ├── amdm37x.cfg │ │ │ │ ├── ampere_emag.cfg │ │ │ │ ├── ar71xx.cfg │ │ │ │ ├── arm_corelink_sse200.cfg │ │ │ │ ├── armada370.cfg │ │ │ │ ├── at32ap7000.cfg │ │ │ │ ├── at91r40008.cfg │ │ │ │ ├── at91rm9200.cfg │ │ │ │ ├── at91sam3XXX.cfg │ │ │ │ ├── at91sam3ax_4x.cfg │ │ │ │ ├── at91sam3ax_8x.cfg │ │ │ │ ├── at91sam3ax_xx.cfg │ │ │ │ ├── at91sam3nXX.cfg │ │ │ │ ├── at91sam3sXX.cfg │ │ │ │ ├── at91sam3u1c.cfg │ │ │ │ ├── at91sam3u1e.cfg │ │ │ │ ├── at91sam3u2c.cfg │ │ │ │ ├── at91sam3u2e.cfg │ │ │ │ ├── at91sam3u4c.cfg │ │ │ │ ├── at91sam3u4e.cfg │ │ │ │ ├── at91sam3uxx.cfg │ │ │ │ ├── at91sam4XXX.cfg │ │ │ │ ├── at91sam4c32x.cfg │ │ │ │ ├── at91sam4cXXX.cfg │ │ │ │ ├── at91sam4lXX.cfg │ │ │ │ ├── at91sam4sXX.cfg │ │ │ │ ├── at91sam4sd32x.cfg │ │ │ │ ├── at91sam7a2.cfg │ │ │ │ ├── at91sam7se512.cfg │ │ │ │ ├── at91sam7sx.cfg │ │ │ │ ├── at91sam7x256.cfg │ │ │ │ ├── at91sam7x512.cfg │ │ │ │ ├── at91sam9.cfg │ │ │ │ ├── at91sam9260.cfg │ │ │ │ ├── at91sam9260_ext_RAM_ext_flash.cfg │ │ │ │ ├── at91sam9261.cfg │ │ │ │ ├── at91sam9263.cfg │ │ │ │ ├── at91sam9g10.cfg │ │ │ │ ├── at91sam9g20.cfg │ │ │ │ ├── at91sam9g45.cfg │ │ │ │ ├── at91sam9rl.cfg │ │ │ │ ├── at91sama5d2.cfg │ │ │ │ ├── at91samdXX.cfg │ │ │ │ ├── at91samg5x.cfg │ │ │ │ ├── atheros_ar2313.cfg │ │ │ │ ├── atheros_ar2315.cfg │ │ │ │ ├── atheros_ar9331.cfg │ │ │ │ ├── atheros_ar9344.cfg │ │ │ │ ├── atmega128.cfg │ │ │ │ ├── atmega128rfa1.cfg │ │ │ │ ├── atsame5x.cfg │ │ │ │ ├── atsaml1x.cfg │ │ │ │ ├── atsamv.cfg │ │ │ │ ├── avr32.cfg │ │ │ │ ├── bcm2711.cfg │ │ │ │ ├── bcm281xx.cfg │ │ │ │ ├── bcm2835.cfg │ │ │ │ ├── bcm2836.cfg │ │ │ │ ├── bcm2837.cfg │ │ │ │ ├── bcm4706.cfg │ │ │ │ ├── bcm4718.cfg │ │ │ │ ├── bcm47xx.cfg │ │ │ │ ├── bcm5352e.cfg │ │ │ │ ├── bcm6348.cfg │ │ │ │ ├── bluefield.cfg │ │ │ │ ├── bluenrg-x.cfg │ │ │ │ ├── c100.cfg │ │ │ │ ├── c100config.tcl │ │ │ │ ├── c100helper.tcl │ │ │ │ ├── c100regs.tcl │ │ │ │ ├── cc2538.cfg │ │ │ │ ├── cs351x.cfg │ │ │ │ ├── davinci.cfg │ │ │ │ ├── dragonite.cfg │ │ │ │ ├── dsp56321.cfg │ │ │ │ ├── dsp568013.cfg │ │ │ │ ├── dsp568037.cfg │ │ │ │ ├── efm32.cfg │ │ │ │ ├── em357.cfg │ │ │ │ ├── em358.cfg │ │ │ │ ├── eos_s3.cfg │ │ │ │ ├── epc9301.cfg │ │ │ │ ├── esi32xx.cfg │ │ │ │ ├── esp32s2.cfg │ │ │ │ ├── exynos5250.cfg │ │ │ │ ├── faux.cfg │ │ │ │ ├── feroceon.cfg │ │ │ │ ├── fm3.cfg │ │ │ │ ├── fm4.cfg │ │ │ │ ├── fm4_mb9bf.cfg │ │ │ │ ├── fm4_s6e2cc.cfg │ │ │ │ ├── gd32e23x.cfg │ │ │ │ ├── gd32vf103.cfg │ │ │ │ ├── gp326xxxa.cfg │ │ │ │ ├── hi3798.cfg │ │ │ │ ├── hi6220.cfg │ │ │ │ ├── hilscher_netx10.cfg │ │ │ │ ├── hilscher_netx50.cfg │ │ │ │ ├── hilscher_netx500.cfg │ │ │ │ ├── icepick.cfg │ │ │ │ ├── imx.cfg │ │ │ │ ├── imx21.cfg │ │ │ │ ├── imx25.cfg │ │ │ │ ├── imx27.cfg │ │ │ │ ├── imx28.cfg │ │ │ │ ├── imx31.cfg │ │ │ │ ├── imx35.cfg │ │ │ │ ├── imx51.cfg │ │ │ │ ├── imx53.cfg │ │ │ │ ├── imx6.cfg │ │ │ │ ├── imx6sx.cfg │ │ │ │ ├── imx6ul.cfg │ │ │ │ ├── imx7.cfg │ │ │ │ ├── imx7ulp.cfg │ │ │ │ ├── imx8m.cfg │ │ │ │ ├── imx8qm.cfg │ │ │ │ ├── infineon/ │ │ │ │ │ └── tle987x.cfg │ │ │ │ ├── is5114.cfg │ │ │ │ ├── ixp42x.cfg │ │ │ │ ├── k1921vk01t.cfg │ │ │ │ ├── k40.cfg │ │ │ │ ├── k60.cfg │ │ │ │ ├── ke0x.cfg │ │ │ │ ├── ke1xf.cfg │ │ │ │ ├── ke1xz.cfg │ │ │ │ ├── kl25.cfg │ │ │ │ ├── kl46.cfg │ │ │ │ ├── klx.cfg │ │ │ │ ├── ks869x.cfg │ │ │ │ ├── kx.cfg │ │ │ │ ├── lpc11xx.cfg │ │ │ │ ├── lpc12xx.cfg │ │ │ │ ├── lpc13xx.cfg │ │ │ │ ├── lpc17xx.cfg │ │ │ │ ├── lpc1850.cfg │ │ │ │ ├── lpc1xxx.cfg │ │ │ │ ├── lpc2103.cfg │ │ │ │ ├── lpc2124.cfg │ │ │ │ ├── lpc2129.cfg │ │ │ │ ├── lpc2148.cfg │ │ │ │ ├── lpc2294.cfg │ │ │ │ ├── lpc2378.cfg │ │ │ │ ├── lpc2460.cfg │ │ │ │ ├── lpc2478.cfg │ │ │ │ ├── lpc2900.cfg │ │ │ │ ├── lpc2xxx.cfg │ │ │ │ ├── lpc3131.cfg │ │ │ │ ├── lpc3250.cfg │ │ │ │ ├── lpc40xx.cfg │ │ │ │ ├── lpc4350.cfg │ │ │ │ ├── lpc4357.cfg │ │ │ │ ├── lpc4370.cfg │ │ │ │ ├── lpc84x.cfg │ │ │ │ ├── lpc8nxx.cfg │ │ │ │ ├── lpc8xx.cfg │ │ │ │ ├── ls1012a.cfg │ │ │ │ ├── ls1028a.cfg │ │ │ │ ├── ls1046a.cfg │ │ │ │ ├── ls1088a.cfg │ │ │ │ ├── lsch3_common.cfg │ │ │ │ ├── marvell/ │ │ │ │ │ ├── 88f3710.cfg │ │ │ │ │ ├── 88f3720.cfg │ │ │ │ │ └── 88f37x0.cfg │ │ │ │ ├── max32620.cfg │ │ │ │ ├── max32625.cfg │ │ │ │ ├── max3263x.cfg │ │ │ │ ├── mc13224v.cfg │ │ │ │ ├── mdr32f9q2i.cfg │ │ │ │ ├── nds32v2.cfg │ │ │ │ ├── nds32v3.cfg │ │ │ │ ├── nds32v3m.cfg │ │ │ │ ├── nds32v5.cfg │ │ │ │ ├── nhs31xx.cfg │ │ │ │ ├── npcx.cfg │ │ │ │ ├── nrf51.cfg │ │ │ │ ├── nrf52.cfg │ │ │ │ ├── nuc910.cfg │ │ │ │ ├── numicro.cfg │ │ │ │ ├── omap2420.cfg │ │ │ │ ├── omap3530.cfg │ │ │ │ ├── omap4430.cfg │ │ │ │ ├── omap4460.cfg │ │ │ │ ├── omap5912.cfg │ │ │ │ ├── omapl138.cfg │ │ │ │ ├── or1k.cfg │ │ │ │ ├── pic32mx.cfg │ │ │ │ ├── psoc4.cfg │ │ │ │ ├── psoc5lp.cfg │ │ │ │ ├── psoc6.cfg │ │ │ │ ├── pxa255.cfg │ │ │ │ ├── pxa270.cfg │ │ │ │ ├── pxa3xx.cfg │ │ │ │ ├── qualcomm_qca4531.cfg │ │ │ │ ├── quark_d20xx.cfg │ │ │ │ ├── quark_x10xx.cfg │ │ │ │ ├── readme.txt │ │ │ │ ├── renesas_r7s72100.cfg │ │ │ │ ├── renesas_rcar_gen2.cfg │ │ │ │ ├── renesas_rcar_gen3.cfg │ │ │ │ ├── renesas_rcar_reset_common.cfg │ │ │ │ ├── renesas_rz_five.cfg │ │ │ │ ├── renesas_rz_g2.cfg │ │ │ │ ├── renesas_s7g2.cfg │ │ │ │ ├── rk3308.cfg │ │ │ │ ├── rk3399.cfg │ │ │ │ ├── rp2040-core0.cfg │ │ │ │ ├── samsung_s3c2410.cfg │ │ │ │ ├── samsung_s3c2440.cfg │ │ │ │ ├── samsung_s3c2450.cfg │ │ │ │ ├── samsung_s3c4510.cfg │ │ │ │ ├── samsung_s3c6410.cfg │ │ │ │ ├── sharp_lh79532.cfg │ │ │ │ ├── sim3x.cfg │ │ │ │ ├── smp8634.cfg │ │ │ │ ├── snps_em_sk_fpga.cfg │ │ │ │ ├── snps_hsdk.cfg │ │ │ │ ├── spear3xx.cfg │ │ │ │ ├── stellaris.cfg │ │ │ │ ├── stm32f0x.cfg │ │ │ │ ├── stm32f1x.cfg │ │ │ │ ├── stm32f2x.cfg │ │ │ │ ├── stm32f3x.cfg │ │ │ │ ├── stm32f4x.cfg │ │ │ │ ├── stm32f7x.cfg │ │ │ │ ├── stm32g0x.cfg │ │ │ │ ├── stm32g4x.cfg │ │ │ │ ├── stm32h7x.cfg │ │ │ │ ├── stm32h7x_dual_bank.cfg │ │ │ │ ├── stm32l0.cfg │ │ │ │ ├── stm32l0_dual_bank.cfg │ │ │ │ ├── stm32l1.cfg │ │ │ │ ├── stm32l1x_dual_bank.cfg │ │ │ │ ├── stm32l4x.cfg │ │ │ │ ├── stm32l5x.cfg │ │ │ │ ├── stm32mp13x.cfg │ │ │ │ ├── stm32mp15x.cfg │ │ │ │ ├── stm32u5x.cfg │ │ │ │ ├── stm32w108xx.cfg │ │ │ │ ├── stm32wbx.cfg │ │ │ │ ├── stm32wlx.cfg │ │ │ │ ├── stm32x5x_common.cfg │ │ │ │ ├── stm32xl.cfg │ │ │ │ ├── stm8l.cfg │ │ │ │ ├── stm8l152.cfg │ │ │ │ ├── stm8s.cfg │ │ │ │ ├── stm8s003.cfg │ │ │ │ ├── stm8s103.cfg │ │ │ │ ├── stm8s105.cfg │ │ │ │ ├── str710.cfg │ │ │ │ ├── str730.cfg │ │ │ │ ├── str750.cfg │ │ │ │ ├── str912.cfg │ │ │ │ ├── swj-dp.tcl │ │ │ │ ├── swm050.cfg │ │ │ │ ├── test_reset_syntax_error.cfg │ │ │ │ ├── test_syntax_error.cfg │ │ │ │ ├── ti-ar7.cfg │ │ │ │ ├── ti-cjtag.cfg │ │ │ │ ├── ti_calypso.cfg │ │ │ │ ├── ti_cc13x0.cfg │ │ │ │ ├── ti_cc13x2.cfg │ │ │ │ ├── ti_cc26x0.cfg │ │ │ │ ├── ti_cc26x2.cfg │ │ │ │ ├── ti_cc3220sf.cfg │ │ │ │ ├── ti_cc32xx.cfg │ │ │ │ ├── ti_dm355.cfg │ │ │ │ ├── ti_dm365.cfg │ │ │ │ ├── ti_dm6446.cfg │ │ │ │ ├── ti_k3.cfg │ │ │ │ ├── ti_msp432.cfg │ │ │ │ ├── ti_rm4x.cfg │ │ │ │ ├── ti_tms570.cfg │ │ │ │ ├── ti_tms570ls20xxx.cfg │ │ │ │ ├── ti_tms570ls3137.cfg │ │ │ │ ├── tmpa900.cfg │ │ │ │ ├── tmpa910.cfg │ │ │ │ ├── tnetc4401.cfg │ │ │ │ ├── u8500.cfg │ │ │ │ ├── vd_aarch64.cfg │ │ │ │ ├── vd_cortex_m.cfg │ │ │ │ ├── vd_riscv.cfg │ │ │ │ ├── vybrid_vf6xx.cfg │ │ │ │ ├── xilinx_zynqmp.cfg │ │ │ │ ├── xmc1xxx.cfg │ │ │ │ ├── xmc4xxx.cfg │ │ │ │ ├── xmos_xs1-xau8a-10_arm.cfg │ │ │ │ ├── zynq_7000.cfg │ │ │ │ └── к1879xб1я.cfg │ │ │ ├── test/ │ │ │ │ ├── selftest.cfg │ │ │ │ └── syntax1.cfg │ │ │ └── tools/ │ │ │ ├── firmware-recovery.tcl │ │ │ ├── memtest.tcl │ │ │ └── test_cpu_speed.tcl │ │ ├── README.md │ │ └── translations/ │ │ ├── qt_ar.qm │ │ ├── qt_bg.qm │ │ ├── qt_ca.qm │ │ ├── qt_cs.qm │ │ ├── qt_da.qm │ │ ├── qt_de.qm │ │ ├── qt_en.qm │ │ ├── qt_es.qm │ │ ├── qt_fa.qm │ │ ├── qt_fi.qm │ │ ├── qt_fr.qm │ │ ├── qt_gd.qm │ │ ├── qt_he.qm │ │ ├── qt_hr.qm │ │ ├── qt_hu.qm │ │ ├── qt_it.qm │ │ ├── qt_ja.qm │ │ ├── qt_ko.qm │ │ ├── qt_lv.qm │ │ ├── qt_nl.qm │ │ ├── qt_nn.qm │ │ ├── qt_pl.qm │ │ ├── qt_pt_BR.qm │ │ ├── qt_ru.qm │ │ ├── qt_sk.qm │ │ ├── qt_tr.qm │ │ ├── qt_uk.qm │ │ ├── qt_zh_CN.qm │ │ └── qt_zh_TW.qm │ ├── OpenOCD_CH347/ │ │ ├── README.md │ │ ├── bin/ │ │ │ └── ch347.cfg │ │ ├── contrib/ │ │ │ ├── 60-openocd.rules │ │ │ └── libdcc/ │ │ │ ├── README │ │ │ ├── dcc_stdio.c │ │ │ ├── dcc_stdio.h │ │ │ └── example.c │ │ ├── scripts/ │ │ │ ├── bitsbytes.tcl │ │ │ ├── board/ │ │ │ │ ├── 8devices-lima.cfg │ │ │ │ ├── actux3.cfg │ │ │ │ ├── adapteva_parallella1.cfg │ │ │ │ ├── adsp-sc584-ezbrd.cfg │ │ │ │ ├── alphascale_asm9260_ek.cfg │ │ │ │ ├── altera_sockit.cfg │ │ │ │ ├── am3517evm.cfg │ │ │ │ ├── ampere_emag8180.cfg │ │ │ │ ├── arm_evaluator7t.cfg │ │ │ │ ├── arm_musca_a.cfg │ │ │ │ ├── arty_s7.cfg │ │ │ │ ├── asus-rt-n16.cfg │ │ │ │ ├── asus-rt-n66u.cfg │ │ │ │ ├── at91cap7a-stk-sdram.cfg │ │ │ │ ├── at91eb40a.cfg │ │ │ │ ├── at91rm9200-dk.cfg │ │ │ │ ├── at91rm9200-ek.cfg │ │ │ │ ├── at91sam9261-ek.cfg │ │ │ │ ├── at91sam9263-ek.cfg │ │ │ │ ├── at91sam9g20-ek.cfg │ │ │ │ ├── atmel_at91sam7s-ek.cfg │ │ │ │ ├── atmel_at91sam9260-ek.cfg │ │ │ │ ├── atmel_at91sam9rl-ek.cfg │ │ │ │ ├── atmel_sam3n_ek.cfg │ │ │ │ ├── atmel_sam3s_ek.cfg │ │ │ │ ├── atmel_sam3u_ek.cfg │ │ │ │ ├── atmel_sam3x_ek.cfg │ │ │ │ ├── atmel_sam4e_ek.cfg │ │ │ │ ├── atmel_sam4l8_xplained_pro.cfg │ │ │ │ ├── atmel_sam4s_ek.cfg │ │ │ │ ├── atmel_sam4s_xplained_pro.cfg │ │ │ │ ├── atmel_samc20_xplained_pro.cfg │ │ │ │ ├── atmel_samc21_xplained_pro.cfg │ │ │ │ ├── atmel_samd10_xplained_mini.cfg │ │ │ │ ├── atmel_samd11_xplained_pro.cfg │ │ │ │ ├── atmel_samd20_xplained_pro.cfg │ │ │ │ ├── atmel_samd21_xplained_pro.cfg │ │ │ │ ├── atmel_same70_xplained.cfg │ │ │ │ ├── atmel_samg53_xplained_pro.cfg │ │ │ │ ├── atmel_samg55_xplained_pro.cfg │ │ │ │ ├── atmel_saml21_xplained_pro.cfg │ │ │ │ ├── atmel_samr21_xplained_pro.cfg │ │ │ │ ├── atmel_samv71_xplained_ultra.cfg │ │ │ │ ├── avnet_ultrazed-eg.cfg │ │ │ │ ├── balloon3-cpu.cfg │ │ │ │ ├── bcm28155_ap.cfg │ │ │ │ ├── bluefield.cfg │ │ │ │ ├── bt-homehubv1.cfg │ │ │ │ ├── colibri.cfg │ │ │ │ ├── crossbow_tech_imote2.cfg │ │ │ │ ├── csb337.cfg │ │ │ │ ├── csb732.cfg │ │ │ │ ├── da850evm.cfg │ │ │ │ ├── digi_connectcore_wi-9c.cfg │ │ │ │ ├── digilent_analog_discovery.cfg │ │ │ │ ├── digilent_atlys.cfg │ │ │ │ ├── digilent_nexys_video.cfg │ │ │ │ ├── digilent_zedboard.cfg │ │ │ │ ├── diolan_lpc4350-db1.cfg │ │ │ │ ├── diolan_lpc4357-db1.cfg │ │ │ │ ├── dk-tm4c129.cfg │ │ │ │ ├── dm355evm.cfg │ │ │ │ ├── dm365evm.cfg │ │ │ │ ├── dm6446evm.cfg │ │ │ │ ├── dp_busblaster_v3.cfg │ │ │ │ ├── dp_busblaster_v4.cfg │ │ │ │ ├── dptechnics_dpt-board-v1.cfg │ │ │ │ ├── efikamx.cfg │ │ │ │ ├── efm32.cfg │ │ │ │ ├── eir.cfg │ │ │ │ ├── ek-lm3s1968.cfg │ │ │ │ ├── ek-lm3s3748.cfg │ │ │ │ ├── ek-lm3s6965.cfg │ │ │ │ ├── ek-lm3s811-revb.cfg │ │ │ │ ├── ek-lm3s811.cfg │ │ │ │ ├── ek-lm3s8962.cfg │ │ │ │ ├── ek-lm3s9b9x.cfg │ │ │ │ ├── ek-lm3s9d92.cfg │ │ │ │ ├── ek-lm4f120xl.cfg │ │ │ │ ├── ek-lm4f232.cfg │ │ │ │ ├── ek-tm4c123gxl.cfg │ │ │ │ ├── ek-tm4c1294xl.cfg │ │ │ │ ├── embedded-artists_lpc2478-32.cfg │ │ │ │ ├── emcraft_imx8m-som-bsb.cfg │ │ │ │ ├── emcraft_twr-vf6-som-bsb.cfg │ │ │ │ ├── emcraft_vf6-som.cfg │ │ │ │ ├── esp32s2-kaluga-1.cfg │ │ │ │ ├── ethernut3.cfg │ │ │ │ ├── evb-lan9255.cfg │ │ │ │ ├── frdm-kl25z.cfg │ │ │ │ ├── frdm-kl46z.cfg │ │ │ │ ├── fsl_imx6q_sabresd.cfg │ │ │ │ ├── glyn_tonga2.cfg │ │ │ │ ├── gti/ │ │ │ │ │ └── espressobin.cfg │ │ │ │ ├── gumstix-aerocore.cfg │ │ │ │ ├── hammer.cfg │ │ │ │ ├── hilscher_nxdb500sys.cfg │ │ │ │ ├── hilscher_nxeb500hmi.cfg │ │ │ │ ├── hilscher_nxhx10.cfg │ │ │ │ ├── hilscher_nxhx50.cfg │ │ │ │ ├── hilscher_nxhx500.cfg │ │ │ │ ├── hilscher_nxsb100.cfg │ │ │ │ ├── hitex_lpc1768stick.cfg │ │ │ │ ├── hitex_lpc2929.cfg │ │ │ │ ├── hitex_stm32-performancestick.cfg │ │ │ │ ├── hitex_str9-comstick.cfg │ │ │ │ ├── iar_lpc1768.cfg │ │ │ │ ├── iar_str912_sk.cfg │ │ │ │ ├── icnova_imx53_sodimm.cfg │ │ │ │ ├── icnova_sam9g45_sodimm.cfg │ │ │ │ ├── imx27ads.cfg │ │ │ │ ├── imx27lnst.cfg │ │ │ │ ├── imx28evk.cfg │ │ │ │ ├── imx31pdk.cfg │ │ │ │ ├── imx35pdk.cfg │ │ │ │ ├── imx53-m53evk.cfg │ │ │ │ ├── imx53loco.cfg │ │ │ │ ├── imx8mp-evk.cfg │ │ │ │ ├── insignal_arndale.cfg │ │ │ │ ├── kasli.cfg │ │ │ │ ├── kc100.cfg │ │ │ │ ├── kc705.cfg │ │ │ │ ├── kcu105.cfg │ │ │ │ ├── keil_mcb1700.cfg │ │ │ │ ├── keil_mcb2140.cfg │ │ │ │ ├── kindle2.cfg │ │ │ │ ├── kontron_sl28.cfg │ │ │ │ ├── kwikstik.cfg │ │ │ │ ├── la_fonera-fon2200.cfg │ │ │ │ ├── lambdaconcept_ecpix-5.cfg │ │ │ │ ├── lemaker_hikey.cfg │ │ │ │ ├── linksys-wag200g.cfg │ │ │ │ ├── linksys-wrt54gl.cfg │ │ │ │ ├── linksys_nslu2.cfg │ │ │ │ ├── lisa-l.cfg │ │ │ │ ├── logicpd_imx27.cfg │ │ │ │ ├── lpc1850_spifi_generic.cfg │ │ │ │ ├── lpc4350_spifi_generic.cfg │ │ │ │ ├── lubbock.cfg │ │ │ │ ├── marsohod.cfg │ │ │ │ ├── marsohod2.cfg │ │ │ │ ├── marsohod3.cfg │ │ │ │ ├── mbed-lpc11u24.cfg │ │ │ │ ├── mbed-lpc1768.cfg │ │ │ │ ├── mcb1700.cfg │ │ │ │ ├── microchip_explorer16.cfg │ │ │ │ ├── microchip_sama5d27_som1_kit1.cfg │ │ │ │ ├── microchip_same51_curiosity_nano.cfg │ │ │ │ ├── microchip_same54_xplained_pro.cfg │ │ │ │ ├── microchip_saml11_xplained_pro.cfg │ │ │ │ ├── mini2440.cfg │ │ │ │ ├── mini6410.cfg │ │ │ │ ├── minispartan6.cfg │ │ │ │ ├── nds32_corvettef1.cfg │ │ │ │ ├── nds32_xc5.cfg │ │ │ │ ├── nds32_xc7.cfg │ │ │ │ ├── netgear-dg834v3.cfg │ │ │ │ ├── netgear-wg102.cfg │ │ │ │ ├── nordic_nrf51822_mkit.cfg │ │ │ │ ├── nordic_nrf51_dk.cfg │ │ │ │ ├── nordic_nrf52_dk.cfg │ │ │ │ ├── nordic_nrf52_ftx232.cfg │ │ │ │ ├── novena-internal-fpga.cfg │ │ │ │ ├── npcx_evb.cfg │ │ │ │ ├── numato_mimas_a7.cfg │ │ │ │ ├── numato_opsis.cfg │ │ │ │ ├── nxp_frdm-k64f.cfg │ │ │ │ ├── nxp_frdm-ls1012a.cfg │ │ │ │ ├── nxp_imx7sabre.cfg │ │ │ │ ├── nxp_lpc-link2.cfg │ │ │ │ ├── nxp_mcimx8m-evk.cfg │ │ │ │ ├── nxp_rdb-ls1046a.cfg │ │ │ │ ├── nxp_rdb-ls1088a.cfg │ │ │ │ ├── olimex_LPC2378STK.cfg │ │ │ │ ├── olimex_lpc_h2148.cfg │ │ │ │ ├── olimex_sam7_ex256.cfg │ │ │ │ ├── olimex_sam7_la2.cfg │ │ │ │ ├── olimex_sam9_l9260.cfg │ │ │ │ ├── olimex_stm32_h103.cfg │ │ │ │ ├── olimex_stm32_h107.cfg │ │ │ │ ├── olimex_stm32_h405.cfg │ │ │ │ ├── olimex_stm32_p107.cfg │ │ │ │ ├── omap2420_h4.cfg │ │ │ │ ├── openrd.cfg │ │ │ │ ├── or1k_generic.cfg │ │ │ │ ├── osk5912.cfg │ │ │ │ ├── phone_se_j100i.cfg │ │ │ │ ├── phytec_lpc3250.cfg │ │ │ │ ├── pic-p32mx.cfg │ │ │ │ ├── pico-debug.cfg │ │ │ │ ├── pipistrello.cfg │ │ │ │ ├── propox_mmnet1001.cfg │ │ │ │ ├── pxa255_sst.cfg │ │ │ │ ├── quark_d2000_refboard.cfg │ │ │ │ ├── quark_x10xx_board.cfg │ │ │ │ ├── quicklogic_quickfeather.cfg │ │ │ │ ├── radiona_ulx3s.cfg │ │ │ │ ├── redbee.cfg │ │ │ │ ├── reflexces_achilles_i-dev_kit_arria10.cfg │ │ │ │ ├── renesas_dk-s7g2.cfg │ │ │ │ ├── renesas_falcon.cfg │ │ │ │ ├── renesas_gr_peach.cfg │ │ │ │ ├── renesas_porter.cfg │ │ │ │ ├── renesas_salvator-xs.cfg │ │ │ │ ├── renesas_silk.cfg │ │ │ │ ├── renesas_stout.cfg │ │ │ │ ├── rigado_bmd300_ek.cfg │ │ │ │ ├── rpi3.cfg │ │ │ │ ├── rpi4b.cfg │ │ │ │ ├── rsc-w910.cfg │ │ │ │ ├── sayma_amc.cfg │ │ │ │ ├── sheevaplug.cfg │ │ │ │ ├── sifive-e31arty.cfg │ │ │ │ ├── sifive-e51arty.cfg │ │ │ │ ├── sifive-hifive1-revb.cfg │ │ │ │ ├── sifive-hifive1.cfg │ │ │ │ ├── smdk6410.cfg │ │ │ │ ├── snps_em_sk.cfg │ │ │ │ ├── snps_em_sk_v1.cfg │ │ │ │ ├── snps_em_sk_v2.1.cfg │ │ │ │ ├── snps_em_sk_v2.2.cfg │ │ │ │ ├── snps_hsdk.cfg │ │ │ │ ├── spansion_sk-fm4-176l-s6e2cc.cfg │ │ │ │ ├── spansion_sk-fm4-u120-9b560.cfg │ │ │ │ ├── spear300evb.cfg │ │ │ │ ├── spear300evb_mod.cfg │ │ │ │ ├── spear310evb20.cfg │ │ │ │ ├── spear310evb20_mod.cfg │ │ │ │ ├── spear320cpu.cfg │ │ │ │ ├── spear320cpu_mod.cfg │ │ │ │ ├── st_b-l475e-iot01a.cfg │ │ │ │ ├── st_nucleo_8l152r8.cfg │ │ │ │ ├── st_nucleo_8s208rb.cfg │ │ │ │ ├── st_nucleo_f0.cfg │ │ │ │ ├── st_nucleo_f103rb.cfg │ │ │ │ ├── st_nucleo_f3.cfg │ │ │ │ ├── st_nucleo_f4.cfg │ │ │ │ ├── st_nucleo_f7.cfg │ │ │ │ ├── st_nucleo_g0.cfg │ │ │ │ ├── st_nucleo_g4.cfg │ │ │ │ ├── st_nucleo_h743zi.cfg │ │ │ │ ├── st_nucleo_h745zi.cfg │ │ │ │ ├── st_nucleo_l073rz.cfg │ │ │ │ ├── st_nucleo_l1.cfg │ │ │ │ ├── st_nucleo_l4.cfg │ │ │ │ ├── st_nucleo_l5.cfg │ │ │ │ ├── st_nucleo_wb55.cfg │ │ │ │ ├── steval-idb007v1.cfg │ │ │ │ ├── steval-idb008v1.cfg │ │ │ │ ├── steval-idb011v1.cfg │ │ │ │ ├── steval-idb012v1.cfg │ │ │ │ ├── steval_pcc010.cfg │ │ │ │ ├── stm320518_eval.cfg │ │ │ │ ├── stm320518_eval_stlink.cfg │ │ │ │ ├── stm32100b_eval.cfg │ │ │ │ ├── stm3210b_eval.cfg │ │ │ │ ├── stm3210c_eval.cfg │ │ │ │ ├── stm3210e_eval.cfg │ │ │ │ ├── stm3220g_eval.cfg │ │ │ │ ├── stm3220g_eval_stlink.cfg │ │ │ │ ├── stm3241g_eval.cfg │ │ │ │ ├── stm3241g_eval_stlink.cfg │ │ │ │ ├── stm32429i_eval.cfg │ │ │ │ ├── stm32429i_eval_stlink.cfg │ │ │ │ ├── stm32439i_eval.cfg │ │ │ │ ├── stm32439i_eval_stlink.cfg │ │ │ │ ├── stm327x6g_eval.cfg │ │ │ │ ├── stm32f0discovery.cfg │ │ │ │ ├── stm32f103c8_blue_pill.cfg │ │ │ │ ├── stm32f334discovery.cfg │ │ │ │ ├── stm32f3discovery.cfg │ │ │ │ ├── stm32f412g-disco.cfg │ │ │ │ ├── stm32f413h-disco.cfg │ │ │ │ ├── stm32f429disc1.cfg │ │ │ │ ├── stm32f429discovery.cfg │ │ │ │ ├── stm32f469discovery.cfg │ │ │ │ ├── stm32f469i-disco.cfg │ │ │ │ ├── stm32f4discovery.cfg │ │ │ │ ├── stm32f723e-disco.cfg │ │ │ │ ├── stm32f746g-disco.cfg │ │ │ │ ├── stm32f769i-disco.cfg │ │ │ │ ├── stm32f7discovery.cfg │ │ │ │ ├── stm32h735g-disco.cfg │ │ │ │ ├── stm32h745i-disco.cfg │ │ │ │ ├── stm32h747i-disco.cfg │ │ │ │ ├── stm32h750b-disco.cfg │ │ │ │ ├── stm32h7b3i-disco.cfg │ │ │ │ ├── stm32h7x3i_eval.cfg │ │ │ │ ├── stm32h7x_dual_qspi.cfg │ │ │ │ ├── stm32l0discovery.cfg │ │ │ │ ├── stm32l476g-disco.cfg │ │ │ │ ├── stm32l496g-disco.cfg │ │ │ │ ├── stm32l4discovery.cfg │ │ │ │ ├── stm32l4p5g-disco.cfg │ │ │ │ ├── stm32l4r9i-disco.cfg │ │ │ │ ├── stm32ldiscovery.cfg │ │ │ │ ├── stm32mp13x_dk.cfg │ │ │ │ ├── stm32mp15x_dk2.cfg │ │ │ │ ├── stm32vldiscovery.cfg │ │ │ │ ├── str910-eval.cfg │ │ │ │ ├── telo.cfg │ │ │ │ ├── ti_am335xevm.cfg │ │ │ │ ├── ti_am437x_idk.cfg │ │ │ │ ├── ti_am43xx_evm.cfg │ │ │ │ ├── ti_am625evm.cfg │ │ │ │ ├── ti_am642evm.cfg │ │ │ │ ├── ti_am654evm.cfg │ │ │ │ ├── ti_beagleboard.cfg │ │ │ │ ├── ti_beagleboard_xm.cfg │ │ │ │ ├── ti_beaglebone-base.cfg │ │ │ │ ├── ti_beaglebone.cfg │ │ │ │ ├── ti_beaglebone_black.cfg │ │ │ │ ├── ti_blaze.cfg │ │ │ │ ├── ti_cc13x0_launchpad.cfg │ │ │ │ ├── ti_cc13x2_launchpad.cfg │ │ │ │ ├── ti_cc26x0_launchpad.cfg │ │ │ │ ├── ti_cc26x2_launchpad.cfg │ │ │ │ ├── ti_cc3200_launchxl.cfg │ │ │ │ ├── ti_cc3220sf_launchpad.cfg │ │ │ │ ├── ti_cc32xx_launchpad.cfg │ │ │ │ ├── ti_dk-tm4c129.cfg │ │ │ │ ├── ti_ek-tm4c123gxl.cfg │ │ │ │ ├── ti_ek-tm4c1294xl.cfg │ │ │ │ ├── ti_j7200evm.cfg │ │ │ │ ├── ti_j721evm.cfg │ │ │ │ ├── ti_j721s2evm.cfg │ │ │ │ ├── ti_msp432_launchpad.cfg │ │ │ │ ├── ti_pandaboard.cfg │ │ │ │ ├── ti_pandaboard_es.cfg │ │ │ │ ├── ti_tmdx570ls20susb.cfg │ │ │ │ ├── ti_tmdx570ls31usb.cfg │ │ │ │ ├── tocoding_poplar.cfg │ │ │ │ ├── topas910.cfg │ │ │ │ ├── topasa900.cfg │ │ │ │ ├── tp-link_tl-mr3020.cfg │ │ │ │ ├── tp-link_wdr4300.cfg │ │ │ │ ├── twr-k60f120m.cfg │ │ │ │ ├── twr-k60n512.cfg │ │ │ │ ├── twr-vf65gs10.cfg │ │ │ │ ├── twr-vf65gs10_cmsisdap.cfg │ │ │ │ ├── tx25_stk5.cfg │ │ │ │ ├── tx27_stk5.cfg │ │ │ │ ├── unknown_at91sam9260.cfg │ │ │ │ ├── uptech_2410.cfg │ │ │ │ ├── vd_a53x2_jtag.cfg │ │ │ │ ├── vd_m4_jtag.cfg │ │ │ │ ├── vd_pulpissimo_jtag.cfg │ │ │ │ ├── vd_swerv_jtag.cfg │ │ │ │ ├── verdex.cfg │ │ │ │ ├── voipac.cfg │ │ │ │ ├── voltcraft_dso-3062c.cfg │ │ │ │ ├── x300t.cfg │ │ │ │ ├── xmc-2go.cfg │ │ │ │ ├── xmc1100-boot-kit.cfg │ │ │ │ ├── xmc4200-application-kit-actuator.cfg │ │ │ │ ├── xmc4300-relax.cfg │ │ │ │ ├── xmc4500-application-kit-general.cfg │ │ │ │ ├── xmc4500-application-kit-sdram.cfg │ │ │ │ ├── xmc4500-relax.cfg │ │ │ │ ├── xmc4700-relax.cfg │ │ │ │ ├── xmc4800-relax.cfg │ │ │ │ └── xmos_xk-xac-xa8_arm.cfg │ │ │ ├── chip/ │ │ │ │ ├── atmel/ │ │ │ │ │ └── at91/ │ │ │ │ │ ├── aic.tcl │ │ │ │ │ ├── at91_pio.cfg │ │ │ │ │ ├── at91_pmc.cfg │ │ │ │ │ ├── at91_rstc.cfg │ │ │ │ │ ├── at91_wdt.cfg │ │ │ │ │ ├── at91sam7x128.tcl │ │ │ │ │ ├── at91sam7x256.tcl │ │ │ │ │ ├── at91sam9261.cfg │ │ │ │ │ ├── at91sam9261_matrix.cfg │ │ │ │ │ ├── at91sam9263.cfg │ │ │ │ │ ├── at91sam9263_matrix.cfg │ │ │ │ │ ├── at91sam9_init.cfg │ │ │ │ │ ├── at91sam9_sdramc.cfg │ │ │ │ │ ├── at91sam9_smc.cfg │ │ │ │ │ ├── hardware.cfg │ │ │ │ │ ├── pmc.tcl │ │ │ │ │ ├── rtt.tcl │ │ │ │ │ ├── sam9_smc.cfg │ │ │ │ │ └── usarts.tcl │ │ │ │ ├── st/ │ │ │ │ │ ├── spear/ │ │ │ │ │ │ ├── quirk_no_srst.tcl │ │ │ │ │ │ ├── spear3xx.tcl │ │ │ │ │ │ └── spear3xx_ddr.tcl │ │ │ │ │ └── stm32/ │ │ │ │ │ ├── stm32.tcl │ │ │ │ │ ├── stm32_rcc.tcl │ │ │ │ │ └── stm32_regs.tcl │ │ │ │ └── ti/ │ │ │ │ └── lm3s/ │ │ │ │ ├── lm3s.tcl │ │ │ │ └── lm3s_regs.tcl │ │ │ ├── cpld/ │ │ │ │ ├── altera-5m570z-cpld.cfg │ │ │ │ ├── altera-epm240.cfg │ │ │ │ ├── jtagspi.cfg │ │ │ │ ├── lattice-lc4032ze.cfg │ │ │ │ ├── xilinx-xc6s.cfg │ │ │ │ ├── xilinx-xc7.cfg │ │ │ │ ├── xilinx-xcf-p.cfg │ │ │ │ ├── xilinx-xcf-s.cfg │ │ │ │ ├── xilinx-xcr3256.cfg │ │ │ │ └── xilinx-xcu.cfg │ │ │ ├── cpu/ │ │ │ │ ├── arc/ │ │ │ │ │ ├── common.tcl │ │ │ │ │ ├── em.tcl │ │ │ │ │ ├── hs.tcl │ │ │ │ │ └── v2.tcl │ │ │ │ └── arm/ │ │ │ │ ├── arm7tdmi.tcl │ │ │ │ ├── arm920.tcl │ │ │ │ ├── arm946.tcl │ │ │ │ ├── arm966.tcl │ │ │ │ └── cortex_m3.tcl │ │ │ ├── fpga/ │ │ │ │ ├── altera-10m50.cfg │ │ │ │ ├── altera-ep3c10.cfg │ │ │ │ ├── altera-ep4ce10.cfg │ │ │ │ ├── lattice_ecp5.cfg │ │ │ │ ├── xilinx-dna.cfg │ │ │ │ └── xilinx-xadc.cfg │ │ │ ├── interface/ │ │ │ │ ├── altera-usb-blaster.cfg │ │ │ │ ├── altera-usb-blaster2.cfg │ │ │ │ ├── arm-jtag-ew.cfg │ │ │ │ ├── at91rm9200.cfg │ │ │ │ ├── beaglebone-jtag-native.cfg │ │ │ │ ├── beaglebone-swd-native.cfg │ │ │ │ ├── buspirate.cfg │ │ │ │ ├── calao-usb-a9260.cfg │ │ │ │ ├── chameleon.cfg │ │ │ │ ├── cmsis-dap.cfg │ │ │ │ ├── dln-2-gpiod.cfg │ │ │ │ ├── dummy.cfg │ │ │ │ ├── estick.cfg │ │ │ │ ├── flashlink.cfg │ │ │ │ ├── ft232r/ │ │ │ │ │ └── radiona_ulx3s.cfg │ │ │ │ ├── ft232r.cfg │ │ │ │ ├── ftdi/ │ │ │ │ │ ├── 100ask-openjtag.cfg │ │ │ │ │ ├── ashling-opella-ld-jtag.cfg │ │ │ │ │ ├── ashling-opella-ld-swd.cfg │ │ │ │ │ ├── axm0432.cfg │ │ │ │ │ ├── c232hm.cfg │ │ │ │ │ ├── calao-usb-a9260-c01.cfg │ │ │ │ │ ├── calao-usb-a9260-c02.cfg │ │ │ │ │ ├── cortino.cfg │ │ │ │ │ ├── digilent-hs1.cfg │ │ │ │ │ ├── digilent-hs2.cfg │ │ │ │ │ ├── digilent_jtag_hs3.cfg │ │ │ │ │ ├── digilent_jtag_smt2.cfg │ │ │ │ │ ├── digilent_jtag_smt2_nc.cfg │ │ │ │ │ ├── dlp-usb1232h.cfg │ │ │ │ │ ├── dp_busblaster.cfg │ │ │ │ │ ├── dp_busblaster_kt-link.cfg │ │ │ │ │ ├── esp32s2_kaluga_v1.cfg │ │ │ │ │ ├── flossjtag-noeeprom.cfg │ │ │ │ │ ├── flossjtag.cfg │ │ │ │ │ ├── flyswatter.cfg │ │ │ │ │ ├── flyswatter2.cfg │ │ │ │ │ ├── ft232h-module-swd.cfg │ │ │ │ │ ├── gw16042.cfg │ │ │ │ │ ├── hie-jtag.cfg │ │ │ │ │ ├── hilscher_nxhx10_etm.cfg │ │ │ │ │ ├── hilscher_nxhx500_etm.cfg │ │ │ │ │ ├── hilscher_nxhx500_re.cfg │ │ │ │ │ ├── hilscher_nxhx50_etm.cfg │ │ │ │ │ ├── hilscher_nxhx50_re.cfg │ │ │ │ │ ├── hitex_lpc1768stick.cfg │ │ │ │ │ ├── hitex_str9-comstick.cfg │ │ │ │ │ ├── icebear.cfg │ │ │ │ │ ├── imx8mp-evk.cfg │ │ │ │ │ ├── incircuit-icprog.cfg │ │ │ │ │ ├── iotlab-usb.cfg │ │ │ │ │ ├── isodebug.cfg │ │ │ │ │ ├── jtag-lock-pick_tiny_2.cfg │ │ │ │ │ ├── jtagkey.cfg │ │ │ │ │ ├── jtagkey2.cfg │ │ │ │ │ ├── jtagkey2p.cfg │ │ │ │ │ ├── kt-link.cfg │ │ │ │ │ ├── lambdaconcept_ecpix-5.cfg │ │ │ │ │ ├── lisa-l.cfg │ │ │ │ │ ├── luminary-icdi.cfg │ │ │ │ │ ├── luminary-lm3s811.cfg │ │ │ │ │ ├── luminary.cfg │ │ │ │ │ ├── m53evk.cfg │ │ │ │ │ ├── mbftdi.cfg │ │ │ │ │ ├── minimodule-swd.cfg │ │ │ │ │ ├── minimodule.cfg │ │ │ │ │ ├── minispartan6.cfg │ │ │ │ │ ├── miniwiggler.cfg │ │ │ │ │ ├── neodb.cfg │ │ │ │ │ ├── ngxtech.cfg │ │ │ │ │ ├── olimex-arm-jtag-swd.cfg │ │ │ │ │ ├── olimex-arm-usb-ocd-h.cfg │ │ │ │ │ ├── olimex-arm-usb-ocd.cfg │ │ │ │ │ ├── olimex-arm-usb-tiny-h.cfg │ │ │ │ │ ├── olimex-jtag-tiny.cfg │ │ │ │ │ ├── oocdlink.cfg │ │ │ │ │ ├── opendous_ftdi.cfg │ │ │ │ │ ├── openocd-usb-hs.cfg │ │ │ │ │ ├── openocd-usb.cfg │ │ │ │ │ ├── openrd.cfg │ │ │ │ │ ├── pipistrello.cfg │ │ │ │ │ ├── pls_spc5.cfg │ │ │ │ │ ├── redbee-econotag.cfg │ │ │ │ │ ├── redbee-usb.cfg │ │ │ │ │ ├── rowley-cc-arm-swd.cfg │ │ │ │ │ ├── sheevaplug.cfg │ │ │ │ │ ├── signalyzer-lite.cfg │ │ │ │ │ ├── signalyzer.cfg │ │ │ │ │ ├── snps_sdp.cfg │ │ │ │ │ ├── steppenprobe.cfg │ │ │ │ │ ├── stm32-stick.cfg │ │ │ │ │ ├── swd-resistor-hack.cfg │ │ │ │ │ ├── ti-icdi.cfg │ │ │ │ │ ├── tigard.cfg │ │ │ │ │ ├── tumpa-lite.cfg │ │ │ │ │ ├── tumpa.cfg │ │ │ │ │ ├── turtelizer2-revB.cfg │ │ │ │ │ ├── turtelizer2-revC.cfg │ │ │ │ │ ├── um232h.cfg │ │ │ │ │ ├── vpaclink.cfg │ │ │ │ │ ├── xds100v2.cfg │ │ │ │ │ └── xds100v3.cfg │ │ │ │ ├── imx-native.cfg │ │ │ │ ├── jlink.cfg │ │ │ │ ├── jtag_dpi.cfg │ │ │ │ ├── jtag_hat_rpi2.cfg │ │ │ │ ├── jtag_vpi.cfg │ │ │ │ ├── kitprog.cfg │ │ │ │ ├── nds32-aice.cfg │ │ │ │ ├── nulink.cfg │ │ │ │ ├── opendous.cfg │ │ │ │ ├── openjtag.cfg │ │ │ │ ├── osbdm.cfg │ │ │ │ ├── parport.cfg │ │ │ │ ├── parport_dlc5.cfg │ │ │ │ ├── raspberrypi-native.cfg │ │ │ │ ├── raspberrypi2-native.cfg │ │ │ │ ├── rlink.cfg │ │ │ │ ├── rshim.cfg │ │ │ │ ├── stlink-dap.cfg │ │ │ │ ├── stlink-v1.cfg │ │ │ │ ├── stlink-v2-1.cfg │ │ │ │ ├── stlink-v2.cfg │ │ │ │ ├── stlink.cfg │ │ │ │ ├── sysfsgpio-raspberrypi.cfg │ │ │ │ ├── ti-icdi.cfg │ │ │ │ ├── ulink.cfg │ │ │ │ ├── usb-jtag.cfg │ │ │ │ ├── usbprog.cfg │ │ │ │ ├── vdebug.cfg │ │ │ │ ├── vsllink.cfg │ │ │ │ └── xds110.cfg │ │ │ ├── mem_helper.tcl │ │ │ ├── memory.tcl │ │ │ ├── mmr_helpers.tcl │ │ │ ├── target/ │ │ │ │ ├── 1986ве1т.cfg │ │ │ │ ├── adsp-sc58x.cfg │ │ │ │ ├── aduc702x.cfg │ │ │ │ ├── aducm360.cfg │ │ │ │ ├── allwinner_v3s.cfg │ │ │ │ ├── alphascale_asm9260t.cfg │ │ │ │ ├── altera_fpgasoc.cfg │ │ │ │ ├── altera_fpgasoc_arria10.cfg │ │ │ │ ├── am335x.cfg │ │ │ │ ├── am437x.cfg │ │ │ │ ├── amdm37x.cfg │ │ │ │ ├── ampere_emag.cfg │ │ │ │ ├── ar71xx.cfg │ │ │ │ ├── arm_corelink_sse200.cfg │ │ │ │ ├── armada370.cfg │ │ │ │ ├── at32ap7000.cfg │ │ │ │ ├── at91r40008.cfg │ │ │ │ ├── at91rm9200.cfg │ │ │ │ ├── at91sam3XXX.cfg │ │ │ │ ├── at91sam3ax_4x.cfg │ │ │ │ ├── at91sam3ax_8x.cfg │ │ │ │ ├── at91sam3ax_xx.cfg │ │ │ │ ├── at91sam3nXX.cfg │ │ │ │ ├── at91sam3sXX.cfg │ │ │ │ ├── at91sam3u1c.cfg │ │ │ │ ├── at91sam3u1e.cfg │ │ │ │ ├── at91sam3u2c.cfg │ │ │ │ ├── at91sam3u2e.cfg │ │ │ │ ├── at91sam3u4c.cfg │ │ │ │ ├── at91sam3u4e.cfg │ │ │ │ ├── at91sam3uxx.cfg │ │ │ │ ├── at91sam4XXX.cfg │ │ │ │ ├── at91sam4c32x.cfg │ │ │ │ ├── at91sam4cXXX.cfg │ │ │ │ ├── at91sam4lXX.cfg │ │ │ │ ├── at91sam4sXX.cfg │ │ │ │ ├── at91sam4sd32x.cfg │ │ │ │ ├── at91sam7a2.cfg │ │ │ │ ├── at91sam7se512.cfg │ │ │ │ ├── at91sam7sx.cfg │ │ │ │ ├── at91sam7x256.cfg │ │ │ │ ├── at91sam7x512.cfg │ │ │ │ ├── at91sam9.cfg │ │ │ │ ├── at91sam9260.cfg │ │ │ │ ├── at91sam9260_ext_RAM_ext_flash.cfg │ │ │ │ ├── at91sam9261.cfg │ │ │ │ ├── at91sam9263.cfg │ │ │ │ ├── at91sam9g10.cfg │ │ │ │ ├── at91sam9g20.cfg │ │ │ │ ├── at91sam9g45.cfg │ │ │ │ ├── at91sam9rl.cfg │ │ │ │ ├── at91sama5d2.cfg │ │ │ │ ├── at91samdXX.cfg │ │ │ │ ├── at91samg5x.cfg │ │ │ │ ├── atheros_ar2313.cfg │ │ │ │ ├── atheros_ar2315.cfg │ │ │ │ ├── atheros_ar9331.cfg │ │ │ │ ├── atheros_ar9344.cfg │ │ │ │ ├── atmega128.cfg │ │ │ │ ├── atmega128rfa1.cfg │ │ │ │ ├── atsame5x.cfg │ │ │ │ ├── atsaml1x.cfg │ │ │ │ ├── atsamv.cfg │ │ │ │ ├── avr32.cfg │ │ │ │ ├── bcm2711.cfg │ │ │ │ ├── bcm281xx.cfg │ │ │ │ ├── bcm2835.cfg │ │ │ │ ├── bcm2836.cfg │ │ │ │ ├── bcm2837.cfg │ │ │ │ ├── bcm4706.cfg │ │ │ │ ├── bcm4718.cfg │ │ │ │ ├── bcm47xx.cfg │ │ │ │ ├── bcm5352e.cfg │ │ │ │ ├── bcm6348.cfg │ │ │ │ ├── bluefield.cfg │ │ │ │ ├── bluenrg-x.cfg │ │ │ │ ├── c100.cfg │ │ │ │ ├── c100config.tcl │ │ │ │ ├── c100helper.tcl │ │ │ │ ├── c100regs.tcl │ │ │ │ ├── cc2538.cfg │ │ │ │ ├── cs351x.cfg │ │ │ │ ├── davinci.cfg │ │ │ │ ├── dragonite.cfg │ │ │ │ ├── dsp56321.cfg │ │ │ │ ├── dsp568013.cfg │ │ │ │ ├── dsp568037.cfg │ │ │ │ ├── efm32.cfg │ │ │ │ ├── em357.cfg │ │ │ │ ├── em358.cfg │ │ │ │ ├── eos_s3.cfg │ │ │ │ ├── epc9301.cfg │ │ │ │ ├── esi32xx.cfg │ │ │ │ ├── esp32s2.cfg │ │ │ │ ├── exynos5250.cfg │ │ │ │ ├── faux.cfg │ │ │ │ ├── feroceon.cfg │ │ │ │ ├── fm3.cfg │ │ │ │ ├── fm4.cfg │ │ │ │ ├── fm4_mb9bf.cfg │ │ │ │ ├── fm4_s6e2cc.cfg │ │ │ │ ├── gd32e23x.cfg │ │ │ │ ├── gd32vf103.cfg │ │ │ │ ├── gp326xxxa.cfg │ │ │ │ ├── hi3798.cfg │ │ │ │ ├── hi6220.cfg │ │ │ │ ├── hilscher_netx10.cfg │ │ │ │ ├── hilscher_netx50.cfg │ │ │ │ ├── hilscher_netx500.cfg │ │ │ │ ├── icepick.cfg │ │ │ │ ├── imx.cfg │ │ │ │ ├── imx21.cfg │ │ │ │ ├── imx25.cfg │ │ │ │ ├── imx27.cfg │ │ │ │ ├── imx28.cfg │ │ │ │ ├── imx31.cfg │ │ │ │ ├── imx35.cfg │ │ │ │ ├── imx51.cfg │ │ │ │ ├── imx53.cfg │ │ │ │ ├── imx6.cfg │ │ │ │ ├── imx6sx.cfg │ │ │ │ ├── imx6ul.cfg │ │ │ │ ├── imx7.cfg │ │ │ │ ├── imx7ulp.cfg │ │ │ │ ├── imx8m.cfg │ │ │ │ ├── imx8qm.cfg │ │ │ │ ├── infineon/ │ │ │ │ │ └── tle987x.cfg │ │ │ │ ├── is5114.cfg │ │ │ │ ├── ixp42x.cfg │ │ │ │ ├── k1921vk01t.cfg │ │ │ │ ├── k40.cfg │ │ │ │ ├── k60.cfg │ │ │ │ ├── ke0x.cfg │ │ │ │ ├── ke1xf.cfg │ │ │ │ ├── ke1xz.cfg │ │ │ │ ├── kl25.cfg │ │ │ │ ├── kl46.cfg │ │ │ │ ├── klx.cfg │ │ │ │ ├── ks869x.cfg │ │ │ │ ├── kx.cfg │ │ │ │ ├── lpc11xx.cfg │ │ │ │ ├── lpc12xx.cfg │ │ │ │ ├── lpc13xx.cfg │ │ │ │ ├── lpc17xx.cfg │ │ │ │ ├── lpc1850.cfg │ │ │ │ ├── lpc1xxx.cfg │ │ │ │ ├── lpc2103.cfg │ │ │ │ ├── lpc2124.cfg │ │ │ │ ├── lpc2129.cfg │ │ │ │ ├── lpc2148.cfg │ │ │ │ ├── lpc2294.cfg │ │ │ │ ├── lpc2378.cfg │ │ │ │ ├── lpc2460.cfg │ │ │ │ ├── lpc2478.cfg │ │ │ │ ├── lpc2900.cfg │ │ │ │ ├── lpc2xxx.cfg │ │ │ │ ├── lpc3131.cfg │ │ │ │ ├── lpc3250.cfg │ │ │ │ ├── lpc40xx.cfg │ │ │ │ ├── lpc4350.cfg │ │ │ │ ├── lpc4357.cfg │ │ │ │ ├── lpc4370.cfg │ │ │ │ ├── lpc84x.cfg │ │ │ │ ├── lpc8nxx.cfg │ │ │ │ ├── lpc8xx.cfg │ │ │ │ ├── ls1012a.cfg │ │ │ │ ├── ls1028a.cfg │ │ │ │ ├── ls1046a.cfg │ │ │ │ ├── ls1088a.cfg │ │ │ │ ├── lsch3_common.cfg │ │ │ │ ├── marvell/ │ │ │ │ │ ├── 88f3710.cfg │ │ │ │ │ ├── 88f3720.cfg │ │ │ │ │ └── 88f37x0.cfg │ │ │ │ ├── max32620.cfg │ │ │ │ ├── max32625.cfg │ │ │ │ ├── max3263x.cfg │ │ │ │ ├── mc13224v.cfg │ │ │ │ ├── mdr32f9q2i.cfg │ │ │ │ ├── nds32v2.cfg │ │ │ │ ├── nds32v3.cfg │ │ │ │ ├── nds32v3m.cfg │ │ │ │ ├── nds32v5.cfg │ │ │ │ ├── nhs31xx.cfg │ │ │ │ ├── npcx.cfg │ │ │ │ ├── nrf51.cfg │ │ │ │ ├── nrf52.cfg │ │ │ │ ├── nuc910.cfg │ │ │ │ ├── numicro.cfg │ │ │ │ ├── omap2420.cfg │ │ │ │ ├── omap3530.cfg │ │ │ │ ├── omap4430.cfg │ │ │ │ ├── omap4460.cfg │ │ │ │ ├── omap5912.cfg │ │ │ │ ├── omapl138.cfg │ │ │ │ ├── or1k.cfg │ │ │ │ ├── pic32mx.cfg │ │ │ │ ├── psoc4.cfg │ │ │ │ ├── psoc5lp.cfg │ │ │ │ ├── psoc6.cfg │ │ │ │ ├── pxa255.cfg │ │ │ │ ├── pxa270.cfg │ │ │ │ ├── pxa3xx.cfg │ │ │ │ ├── qualcomm_qca4531.cfg │ │ │ │ ├── quark_d20xx.cfg │ │ │ │ ├── quark_x10xx.cfg │ │ │ │ ├── readme.txt │ │ │ │ ├── renesas_r7s72100.cfg │ │ │ │ ├── renesas_rcar_gen2.cfg │ │ │ │ ├── renesas_rcar_gen3.cfg │ │ │ │ ├── renesas_rcar_reset_common.cfg │ │ │ │ ├── renesas_rz_five.cfg │ │ │ │ ├── renesas_rz_g2.cfg │ │ │ │ ├── renesas_s7g2.cfg │ │ │ │ ├── rk3308.cfg │ │ │ │ ├── rk3399.cfg │ │ │ │ ├── rp2040-core0.cfg │ │ │ │ ├── samsung_s3c2410.cfg │ │ │ │ ├── samsung_s3c2440.cfg │ │ │ │ ├── samsung_s3c2450.cfg │ │ │ │ ├── samsung_s3c4510.cfg │ │ │ │ ├── samsung_s3c6410.cfg │ │ │ │ ├── sharp_lh79532.cfg │ │ │ │ ├── sim3x.cfg │ │ │ │ ├── smp8634.cfg │ │ │ │ ├── snps_em_sk_fpga.cfg │ │ │ │ ├── snps_hsdk.cfg │ │ │ │ ├── spear3xx.cfg │ │ │ │ ├── stellaris.cfg │ │ │ │ ├── stm32f0x.cfg │ │ │ │ ├── stm32f1x.cfg │ │ │ │ ├── stm32f2x.cfg │ │ │ │ ├── stm32f3x.cfg │ │ │ │ ├── stm32f4x.cfg │ │ │ │ ├── stm32f7x.cfg │ │ │ │ ├── stm32g0x.cfg │ │ │ │ ├── stm32g4x.cfg │ │ │ │ ├── stm32h7x.cfg │ │ │ │ ├── stm32h7x_dual_bank.cfg │ │ │ │ ├── stm32l0.cfg │ │ │ │ ├── stm32l0_dual_bank.cfg │ │ │ │ ├── stm32l1.cfg │ │ │ │ ├── stm32l1x_dual_bank.cfg │ │ │ │ ├── stm32l4x.cfg │ │ │ │ ├── stm32l5x.cfg │ │ │ │ ├── stm32mp13x.cfg │ │ │ │ ├── stm32mp15x.cfg │ │ │ │ ├── stm32u5x.cfg │ │ │ │ ├── stm32w108xx.cfg │ │ │ │ ├── stm32wbx.cfg │ │ │ │ ├── stm32wlx.cfg │ │ │ │ ├── stm32x5x_common.cfg │ │ │ │ ├── stm32xl.cfg │ │ │ │ ├── stm8l.cfg │ │ │ │ ├── stm8l152.cfg │ │ │ │ ├── stm8s.cfg │ │ │ │ ├── stm8s003.cfg │ │ │ │ ├── stm8s103.cfg │ │ │ │ ├── stm8s105.cfg │ │ │ │ ├── str710.cfg │ │ │ │ ├── str730.cfg │ │ │ │ ├── str750.cfg │ │ │ │ ├── str912.cfg │ │ │ │ ├── swj-dp.tcl │ │ │ │ ├── swm050.cfg │ │ │ │ ├── test_reset_syntax_error.cfg │ │ │ │ ├── test_syntax_error.cfg │ │ │ │ ├── ti-ar7.cfg │ │ │ │ ├── ti-cjtag.cfg │ │ │ │ ├── ti_calypso.cfg │ │ │ │ ├── ti_cc13x0.cfg │ │ │ │ ├── ti_cc13x2.cfg │ │ │ │ ├── ti_cc26x0.cfg │ │ │ │ ├── ti_cc26x2.cfg │ │ │ │ ├── ti_cc3220sf.cfg │ │ │ │ ├── ti_cc32xx.cfg │ │ │ │ ├── ti_dm355.cfg │ │ │ │ ├── ti_dm365.cfg │ │ │ │ ├── ti_dm6446.cfg │ │ │ │ ├── ti_k3.cfg │ │ │ │ ├── ti_msp432.cfg │ │ │ │ ├── ti_rm4x.cfg │ │ │ │ ├── ti_tms570.cfg │ │ │ │ ├── ti_tms570ls20xxx.cfg │ │ │ │ ├── ti_tms570ls3137.cfg │ │ │ │ ├── tmpa900.cfg │ │ │ │ ├── tmpa910.cfg │ │ │ │ ├── tnetc4401.cfg │ │ │ │ ├── u8500.cfg │ │ │ │ ├── vd_aarch64.cfg │ │ │ │ ├── vd_cortex_m.cfg │ │ │ │ ├── vd_riscv.cfg │ │ │ │ ├── vybrid_vf6xx.cfg │ │ │ │ ├── xilinx_zynqmp.cfg │ │ │ │ ├── xmc1xxx.cfg │ │ │ │ ├── xmc4xxx.cfg │ │ │ │ ├── xmos_xs1-xau8a-10_arm.cfg │ │ │ │ ├── zynq_7000.cfg │ │ │ │ └── к1879xб1я.cfg │ │ │ ├── test/ │ │ │ │ ├── selftest.cfg │ │ │ │ └── syntax1.cfg │ │ │ └── tools/ │ │ │ ├── firmware-recovery.tcl │ │ │ ├── memtest.tcl │ │ │ └── test_cpu_speed.tcl │ │ └── share/ │ │ ├── info/ │ │ │ ├── dir │ │ │ ├── openocd.info │ │ │ ├── openocd.info-1 │ │ │ └── openocd.info-2 │ │ └── man/ │ │ └── man1/ │ │ └── openocd.1 │ └── OpenOCD_SourceCode_CH347/ │ ├── .checkpatch.conf │ ├── .gitignore │ ├── .gitmodules │ ├── .travis.yml │ ├── AUTHORS │ ├── AUTHORS.ChangeLog │ ├── BUGS │ ├── COPYING │ ├── ChangeLog │ ├── HACKING │ ├── LICENSES/ │ │ ├── exceptions/ │ │ │ └── eCos-exception-2.0 │ │ ├── license-rules.txt │ │ ├── preferred/ │ │ │ ├── BSD-1-Clause │ │ │ ├── BSD-2-Clause │ │ │ ├── BSD-2-Clause-Views │ │ │ ├── BSD-3-Clause │ │ │ ├── BSD-Source-Code │ │ │ ├── GFDL-1.2 │ │ │ ├── GPL-2.0 │ │ │ ├── MIT │ │ │ └── gfdl-1.2.texi.readme │ │ └── stand-alone/ │ │ └── GPL-3.0 │ ├── Makefile.am │ ├── NEWS │ ├── NEWS-0.10.0 │ ├── NEWS-0.11.0 │ ├── NEWS-0.12.0 │ ├── NEWS-0.2.0 │ ├── NEWS-0.3.0 │ ├── NEWS-0.4.0 │ ├── NEWS-0.5.0 │ ├── NEWS-0.6.0 │ ├── NEWS-0.7.0 │ ├── NEWS-0.8.0 │ ├── NEWS-0.9.0 │ ├── NEWTAPS │ ├── README │ ├── README.Windows │ ├── README.macOS │ ├── TODO │ ├── bootstrap │ ├── config_subdir.m4 │ ├── configure.ac │ ├── contrib/ │ │ ├── 60-openocd.rules │ │ ├── buildroot/ │ │ │ └── openocd_be_defconfig │ │ ├── coresight-trace.txt │ │ ├── cross-build.sh │ │ ├── gen-stellaris-part-header.pl │ │ ├── itmdump.c │ │ ├── libdcc/ │ │ │ ├── README │ │ │ ├── dcc_stdio.c │ │ │ ├── dcc_stdio.h │ │ │ └── example.c │ │ ├── list_example.c │ │ ├── loaders/ │ │ │ ├── README │ │ │ ├── checksum/ │ │ │ │ ├── armv4_5_crc.inc │ │ │ │ ├── armv4_5_crc.s │ │ │ │ ├── armv7m_crc.inc │ │ │ │ ├── armv7m_crc.s │ │ │ │ ├── mips32.s │ │ │ │ ├── riscv32_crc.inc │ │ │ │ ├── riscv64_crc.inc │ │ │ │ └── riscv_crc.c │ │ │ ├── debug/ │ │ │ │ └── xscale/ │ │ │ │ ├── debug_handler.S │ │ │ │ ├── debug_handler.inc │ │ │ │ ├── debug_handler.ld │ │ │ │ └── protocol.h │ │ │ ├── erase_check/ │ │ │ │ ├── armv4_5_erase_check.inc │ │ │ │ ├── armv4_5_erase_check.s │ │ │ │ ├── armv7m_erase_check.inc │ │ │ │ ├── armv7m_erase_check.s │ │ │ │ ├── stm8_erase_check.inc │ │ │ │ └── stm8_erase_check.s │ │ │ ├── flash/ │ │ │ │ ├── armv4_5_cfi_intel_16.s │ │ │ │ ├── armv4_5_cfi_intel_32.s │ │ │ │ ├── armv4_5_cfi_intel_8.s │ │ │ │ ├── armv4_5_cfi_span_16.s │ │ │ │ ├── armv4_5_cfi_span_16_dq7.s │ │ │ │ ├── armv4_5_cfi_span_32.s │ │ │ │ ├── armv4_5_cfi_span_8.s │ │ │ │ ├── armv7m_cfi_span_16.s │ │ │ │ ├── armv7m_cfi_span_16_dq7.s │ │ │ │ ├── armv7m_io.s │ │ │ │ ├── at91sam7x/ │ │ │ │ │ ├── at91sam7x_ocl_flash.script │ │ │ │ │ ├── at91sam7x_ram.ld │ │ │ │ │ ├── crt.s │ │ │ │ │ ├── dcc.c │ │ │ │ │ ├── dcc.h │ │ │ │ │ ├── main.c │ │ │ │ │ ├── makefile │ │ │ │ │ ├── ocl.h │ │ │ │ │ ├── platform.h │ │ │ │ │ ├── samflash.c │ │ │ │ │ ├── samflash.h │ │ │ │ │ └── samregs.h │ │ │ │ ├── bluenrg-x/ │ │ │ │ │ ├── bluenrg-x_write.c │ │ │ │ │ └── bluenrg-x_write.inc │ │ │ │ ├── cc26xx/ │ │ │ │ │ ├── cc26x0/ │ │ │ │ │ │ └── cc26x0r2f.lds │ │ │ │ │ ├── cc26x0_algo.inc │ │ │ │ │ ├── cc26x2/ │ │ │ │ │ │ └── cc26x2r1f.lds │ │ │ │ │ ├── cc26x2_algo.inc │ │ │ │ │ ├── flash.c │ │ │ │ │ ├── flash.h │ │ │ │ │ ├── flashloader.c │ │ │ │ │ ├── flashloader.h │ │ │ │ │ ├── hw_regs.h │ │ │ │ │ ├── main.c │ │ │ │ │ └── startup.c │ │ │ │ ├── cc3220sf/ │ │ │ │ │ ├── cc3220sf.inc │ │ │ │ │ └── cc3220sf.s │ │ │ │ ├── cortex-m0.S │ │ │ │ ├── efm32.S │ │ │ │ ├── fespi/ │ │ │ │ │ ├── riscv.lds │ │ │ │ │ ├── riscv32_fespi.inc │ │ │ │ │ ├── riscv64_fespi.inc │ │ │ │ │ ├── riscv_fespi.c │ │ │ │ │ └── riscv_wrapper.S │ │ │ │ ├── fm4/ │ │ │ │ │ ├── erase.S │ │ │ │ │ ├── erase.inc │ │ │ │ │ ├── fm4.h │ │ │ │ │ ├── write.S │ │ │ │ │ └── write.inc │ │ │ │ ├── fpga/ │ │ │ │ │ └── xilinx_bscan_spi.py │ │ │ │ ├── gd32vf103/ │ │ │ │ │ ├── gd32vf103.c │ │ │ │ │ └── gd32vf103.inc │ │ │ │ ├── k1921vk01t.S │ │ │ │ ├── kinetis/ │ │ │ │ │ ├── kinetis_flash.inc │ │ │ │ │ └── kinetis_flash.s │ │ │ │ ├── kinetis_ke/ │ │ │ │ │ ├── kinetis_ke_flash.inc │ │ │ │ │ ├── kinetis_ke_flash.s │ │ │ │ │ ├── kinetis_ke_watchdog.inc │ │ │ │ │ └── kinetis_ke_watchdog.s │ │ │ │ ├── lpcspifi_erase.S │ │ │ │ ├── lpcspifi_init.S │ │ │ │ ├── lpcspifi_write.S │ │ │ │ ├── max32xxx/ │ │ │ │ │ ├── max32xxx.inc │ │ │ │ │ └── max32xxx.s │ │ │ │ ├── mdr32fx.S │ │ │ │ ├── mrvlqspi_write.S │ │ │ │ ├── msp432/ │ │ │ │ │ ├── MSP432E4_FlashLibIf.h │ │ │ │ │ ├── MSP432P4_FlashLibIf.h │ │ │ │ │ ├── driverlib.c │ │ │ │ │ ├── driverlib.h │ │ │ │ │ ├── main_msp432e4x.c │ │ │ │ │ ├── main_msp432p401x.c │ │ │ │ │ ├── main_msp432p411x.c │ │ │ │ │ ├── msp432e4x/ │ │ │ │ │ │ └── msp432e4x.lds │ │ │ │ │ ├── msp432e4x.h │ │ │ │ │ ├── msp432e4x_algo.inc │ │ │ │ │ ├── msp432p401x/ │ │ │ │ │ │ └── msp432p401x.lds │ │ │ │ │ ├── msp432p401x.h │ │ │ │ │ ├── msp432p401x_algo.inc │ │ │ │ │ ├── msp432p411x/ │ │ │ │ │ │ └── msp432p411x.lds │ │ │ │ │ ├── msp432p411x.h │ │ │ │ │ ├── msp432p411x_algo.inc │ │ │ │ │ ├── startup_msp432e4.c │ │ │ │ │ └── startup_msp432p4.c │ │ │ │ ├── npcx/ │ │ │ │ │ ├── npcx_algo.inc │ │ │ │ │ ├── npcx_flash.c │ │ │ │ │ ├── npcx_flash.h │ │ │ │ │ ├── npcx_flash.lds │ │ │ │ │ └── npcx_flash_config.h │ │ │ │ ├── nrf5/ │ │ │ │ │ ├── nrf5.S │ │ │ │ │ └── nrf5.inc │ │ │ │ ├── numicro/ │ │ │ │ │ ├── numicro_m0.S │ │ │ │ │ ├── numicro_m0.inc │ │ │ │ │ ├── numicro_m4.S │ │ │ │ │ └── numicro_m4.inc │ │ │ │ ├── pic32mx.s │ │ │ │ ├── rsl10/ │ │ │ │ │ ├── rom_launcher.S │ │ │ │ │ └── rom_launcher.inc │ │ │ │ ├── sh_qspi/ │ │ │ │ │ ├── sh_qspi.S │ │ │ │ │ ├── sh_qspi.inc │ │ │ │ │ └── sh_qspi.ld │ │ │ │ ├── sim3x.s │ │ │ │ ├── stellaris.s │ │ │ │ ├── stm32/ │ │ │ │ │ ├── stm32f1x.S │ │ │ │ │ ├── stm32f1x.inc │ │ │ │ │ ├── stm32f2x.S │ │ │ │ │ ├── stm32f2x.inc │ │ │ │ │ ├── stm32h7x.S │ │ │ │ │ ├── stm32h7x.inc │ │ │ │ │ ├── stm32l4x.c │ │ │ │ │ ├── stm32l4x.inc │ │ │ │ │ ├── stm32lx.S │ │ │ │ │ └── stm32lx.inc │ │ │ │ ├── stmqspi/ │ │ │ │ │ ├── gpio_conf_stm32.pl │ │ │ │ │ ├── stmoctospi_crc32.S │ │ │ │ │ ├── stmoctospi_crc32.inc │ │ │ │ │ ├── stmoctospi_erase_check.S │ │ │ │ │ ├── stmoctospi_erase_check.inc │ │ │ │ │ ├── stmoctospi_read.S │ │ │ │ │ ├── stmoctospi_read.inc │ │ │ │ │ ├── stmoctospi_write.S │ │ │ │ │ ├── stmoctospi_write.inc │ │ │ │ │ ├── stmqspi_crc32.S │ │ │ │ │ ├── stmqspi_crc32.inc │ │ │ │ │ ├── stmqspi_erase_check.S │ │ │ │ │ ├── stmqspi_erase_check.inc │ │ │ │ │ ├── stmqspi_read.S │ │ │ │ │ ├── stmqspi_read.inc │ │ │ │ │ ├── stmqspi_write.S │ │ │ │ │ └── stmqspi_write.inc │ │ │ │ ├── str7x.s │ │ │ │ ├── str9x.s │ │ │ │ └── xmc1xxx/ │ │ │ │ ├── erase.S │ │ │ │ ├── erase.inc │ │ │ │ ├── erase_check.S │ │ │ │ ├── erase_check.inc │ │ │ │ ├── write.S │ │ │ │ ├── write.inc │ │ │ │ └── xmc1xxx.S │ │ │ ├── reset/ │ │ │ │ └── espressif/ │ │ │ │ ├── common.mk │ │ │ │ ├── esp32/ │ │ │ │ │ ├── cpu_reset_handler_code.inc │ │ │ │ │ └── esp32_cpu_reset_handler.S │ │ │ │ └── esp32s3/ │ │ │ │ ├── cpu_reset_handler_code.inc │ │ │ │ └── esp32s3_cpu_reset_handler.S │ │ │ └── watchdog/ │ │ │ ├── armv7m_kinetis_wdog.inc │ │ │ ├── armv7m_kinetis_wdog.s │ │ │ ├── armv7m_kinetis_wdog32.inc │ │ │ └── armv7m_kinetis_wdog32.s │ │ ├── remote_bitbang/ │ │ │ └── remote_bitbang_sysfsgpio.c │ │ ├── rpc_examples/ │ │ │ ├── ocd_rpc_example.py │ │ │ └── ocdrpc.hs │ │ ├── rtos-helpers/ │ │ │ ├── FreeRTOS-openocd.c │ │ │ └── uCOS-III-openocd.c │ │ └── xsvf_tools/ │ │ ├── svf2xsvf.py │ │ └── xsvfdump.py │ ├── doc/ │ │ ├── .gitattributes │ │ ├── Makefile.am │ │ ├── checkpatch.rst │ │ ├── fdl.texi │ │ ├── manual/ │ │ │ ├── app.txt │ │ │ ├── endianness.txt │ │ │ ├── flash.txt │ │ │ ├── helper.txt │ │ │ ├── jtag/ │ │ │ │ └── drivers/ │ │ │ │ └── remote_bitbang.txt │ │ │ ├── jtag.txt │ │ │ ├── main.txt │ │ │ ├── primer/ │ │ │ │ ├── autotools.txt │ │ │ │ ├── commands.txt │ │ │ │ ├── docs.txt │ │ │ │ ├── jtag.txt │ │ │ │ └── tcl.txt │ │ │ ├── release.txt │ │ │ ├── scripting.txt │ │ │ ├── server.txt │ │ │ ├── style.txt │ │ │ ├── target/ │ │ │ │ ├── mips.txt │ │ │ │ └── notarm.txt │ │ │ └── target.txt │ │ ├── openocd.1 │ │ ├── openocd.texi │ │ └── usb_adapters/ │ │ ├── cmsis_dap/ │ │ │ ├── 04b4_f155_cypress_kitprog3.txt │ │ │ ├── 0d28_0204_nxp_daplink.txt │ │ │ ├── 1a6a_2000_spansion_sk_fm4.txt │ │ │ ├── 2a86_8011_wch_link.txt │ │ │ ├── c251_2722_keil_ulink2.txt │ │ │ ├── c251_2723_keil_ulink_me.txt │ │ │ ├── c251_2750_keil_ulinkplus.txt │ │ │ └── c251_f001_jixin.pro.txt │ │ ├── dump.sh │ │ ├── esp_usb_jtag/ │ │ │ └── 303a_1001_esp_usb_jtag.txt │ │ ├── ft232r/ │ │ │ └── 0403_6001_ft232r.txt │ │ ├── ftdi/ │ │ │ ├── 0403_6010_ft2232h.txt │ │ │ ├── 0403_6014_digilent_hs2.txt │ │ │ ├── 0403_cff8_amontec_jtagkey2.txt │ │ │ ├── 09fb_6001_altera_blaster.txt │ │ │ └── 9e88_9e8f_sheevaplug_jtagkey.txt │ │ ├── icdi/ │ │ │ └── 1cbe_00fd_ti_icdi.txt │ │ ├── jlink/ │ │ │ ├── 1366_0101_segger_jlink.txt │ │ │ └── 1366_0101_segger_jlink_plus_10_1.txt │ │ ├── kitprog/ │ │ │ └── 04b4_f139_cypress_kitprog.txt │ │ ├── nulink/ │ │ │ ├── 0416_511d_nuvoton_nulink.txt │ │ │ └── 0416_5200_nuvoton_nulink.txt │ │ ├── readme.txt │ │ ├── stlink/ │ │ │ ├── 0483_3744_stlinkv1.txt │ │ │ ├── 0483_3748_stlinkv2.txt │ │ │ ├── 0483_374b_stlinkv2.txt │ │ │ ├── 0483_374d_stlinkv3.txt │ │ │ ├── 0483_374e_stlinkv3.txt │ │ │ ├── 0483_374f_stlinkv3.txt │ │ │ ├── 0483_3752_stlinkv2.txt │ │ │ ├── 0483_3753_stlinkv3.txt │ │ │ ├── 0483_3755_stlinkv3pwr.txt │ │ │ └── 0483_3757_stlinkv3pwr.txt │ │ └── xds110/ │ │ └── 0451_0451_ti_xds110.txt │ ├── guess-rev.sh │ ├── src/ │ │ ├── Makefile.am │ │ ├── flash/ │ │ │ ├── Makefile.am │ │ │ ├── common.c │ │ │ ├── common.h │ │ │ ├── nand/ │ │ │ │ ├── Makefile.am │ │ │ │ ├── arm_io.c │ │ │ │ ├── arm_io.h │ │ │ │ ├── at91sam9.c │ │ │ │ ├── core.c │ │ │ │ ├── core.h │ │ │ │ ├── davinci.c │ │ │ │ ├── driver.c │ │ │ │ ├── driver.h │ │ │ │ ├── ecc.c │ │ │ │ ├── ecc_kw.c │ │ │ │ ├── fileio.c │ │ │ │ ├── fileio.h │ │ │ │ ├── imp.h │ │ │ │ ├── lpc3180.c │ │ │ │ ├── lpc3180.h │ │ │ │ ├── lpc32xx.c │ │ │ │ ├── lpc32xx.h │ │ │ │ ├── mx3.c │ │ │ │ ├── mx3.h │ │ │ │ ├── mxc.c │ │ │ │ ├── mxc.h │ │ │ │ ├── nonce.c │ │ │ │ ├── nuc910.c │ │ │ │ ├── nuc910.h │ │ │ │ ├── orion.c │ │ │ │ ├── s3c2410.c │ │ │ │ ├── s3c2412.c │ │ │ │ ├── s3c2440.c │ │ │ │ ├── s3c2443.c │ │ │ │ ├── s3c24xx.c │ │ │ │ ├── s3c24xx.h │ │ │ │ ├── s3c24xx_regs.h │ │ │ │ ├── s3c6400.c │ │ │ │ └── tcl.c │ │ │ ├── nor/ │ │ │ │ ├── Makefile.am │ │ │ │ ├── aduc702x.c │ │ │ │ ├── aducm360.c │ │ │ │ ├── ambiqmicro.c │ │ │ │ ├── at91sam3.c │ │ │ │ ├── at91sam4.c │ │ │ │ ├── at91sam4l.c │ │ │ │ ├── at91sam7.c │ │ │ │ ├── at91samd.c │ │ │ │ ├── ath79.c │ │ │ │ ├── atsame5.c │ │ │ │ ├── atsamv.c │ │ │ │ ├── avrf.c │ │ │ │ ├── bluenrg-x.c │ │ │ │ ├── bluenrg-x.h │ │ │ │ ├── cc26xx.c │ │ │ │ ├── cc26xx.h │ │ │ │ ├── cc3220sf.c │ │ │ │ ├── cc3220sf.h │ │ │ │ ├── cfi.c │ │ │ │ ├── cfi.h │ │ │ │ ├── core.c │ │ │ │ ├── core.h │ │ │ │ ├── driver.h │ │ │ │ ├── drivers.c │ │ │ │ ├── dsp5680xx_flash.c │ │ │ │ ├── efm32.c │ │ │ │ ├── em357.c │ │ │ │ ├── esirisc_flash.c │ │ │ │ ├── faux.c │ │ │ │ ├── fespi.c │ │ │ │ ├── fm3.c │ │ │ │ ├── fm4.c │ │ │ │ ├── imp.h │ │ │ │ ├── jtagspi.c │ │ │ │ ├── kinetis.c │ │ │ │ ├── kinetis_ke.c │ │ │ │ ├── lpc2000.c │ │ │ │ ├── lpc288x.c │ │ │ │ ├── lpc2900.c │ │ │ │ ├── lpcspifi.c │ │ │ │ ├── max32xxx.c │ │ │ │ ├── mdr.c │ │ │ │ ├── mrvlqspi.c │ │ │ │ ├── msp432.c │ │ │ │ ├── msp432.h │ │ │ │ ├── niietcm4.c │ │ │ │ ├── non_cfi.c │ │ │ │ ├── non_cfi.h │ │ │ │ ├── npcx.c │ │ │ │ ├── nrf5.c │ │ │ │ ├── numicro.c │ │ │ │ ├── ocl.c │ │ │ │ ├── ocl.h │ │ │ │ ├── pic32mx.c │ │ │ │ ├── psoc4.c │ │ │ │ ├── psoc5lp.c │ │ │ │ ├── psoc6.c │ │ │ │ ├── qn908x.c │ │ │ │ ├── renesas_rpchf.c │ │ │ │ ├── rp2040.c │ │ │ │ ├── rsl10.c │ │ │ │ ├── sfdp.c │ │ │ │ ├── sfdp.h │ │ │ │ ├── sh_qspi.c │ │ │ │ ├── sim3x.c │ │ │ │ ├── spi.c │ │ │ │ ├── spi.h │ │ │ │ ├── stellaris.c │ │ │ │ ├── stm32f1x.c │ │ │ │ ├── stm32f2x.c │ │ │ │ ├── stm32h7x.c │ │ │ │ ├── stm32l4x.c │ │ │ │ ├── stm32l4x.h │ │ │ │ ├── stm32lx.c │ │ │ │ ├── stmqspi.c │ │ │ │ ├── stmqspi.h │ │ │ │ ├── stmsmi.c │ │ │ │ ├── str7x.c │ │ │ │ ├── str9x.c │ │ │ │ ├── str9xpec.c │ │ │ │ ├── swm050.c │ │ │ │ ├── tcl.c │ │ │ │ ├── tms470.c │ │ │ │ ├── virtual.c │ │ │ │ ├── w600.c │ │ │ │ ├── xcf.c │ │ │ │ ├── xmc1xxx.c │ │ │ │ └── xmc4xxx.c │ │ │ └── startup.tcl │ │ ├── hello.c │ │ ├── hello.h │ │ ├── helper/ │ │ │ ├── Makefile.am │ │ │ ├── align.h │ │ │ ├── bin2char.sh │ │ │ ├── binarybuffer.c │ │ │ ├── binarybuffer.h │ │ │ ├── bits.h │ │ │ ├── command.c │ │ │ ├── command.h │ │ │ ├── compiler.h │ │ │ ├── configuration.c │ │ │ ├── configuration.h │ │ │ ├── crc32.c │ │ │ ├── crc32.h │ │ │ ├── fileio.c │ │ │ ├── fileio.h │ │ │ ├── jep106.c │ │ │ ├── jep106.h │ │ │ ├── jep106.inc │ │ │ ├── jim-nvp.c │ │ │ ├── jim-nvp.h │ │ │ ├── list.h │ │ │ ├── log.c │ │ │ ├── log.h │ │ │ ├── nvp.c │ │ │ ├── nvp.h │ │ │ ├── options.c │ │ │ ├── replacements.c │ │ │ ├── replacements.h │ │ │ ├── startup.tcl │ │ │ ├── system.h │ │ │ ├── time_support.c │ │ │ ├── time_support.h │ │ │ ├── time_support_common.c │ │ │ ├── types.h │ │ │ ├── update_jep106.pl │ │ │ ├── util.c │ │ │ └── util.h │ │ ├── jtag/ │ │ │ ├── Makefile.am │ │ │ ├── adapter.c │ │ │ ├── adapter.h │ │ │ ├── commands.c │ │ │ ├── commands.h │ │ │ ├── core.c │ │ │ ├── drivers/ │ │ │ │ ├── Makefile.am │ │ │ │ ├── Makefile.rlink │ │ │ │ ├── OpenULINK/ │ │ │ │ │ ├── README │ │ │ │ │ ├── include/ │ │ │ │ │ │ ├── common.h │ │ │ │ │ │ ├── delay.h │ │ │ │ │ │ ├── io.h │ │ │ │ │ │ ├── jtag.h │ │ │ │ │ │ ├── main.h │ │ │ │ │ │ ├── msgtypes.h │ │ │ │ │ │ ├── protocol.h │ │ │ │ │ │ ├── reg_ezusb.h │ │ │ │ │ │ └── usb.h │ │ │ │ │ ├── src/ │ │ │ │ │ │ ├── USBJmpTb.a51 │ │ │ │ │ │ ├── delay.c │ │ │ │ │ │ ├── jtag.c │ │ │ │ │ │ ├── main.c │ │ │ │ │ │ ├── protocol.c │ │ │ │ │ │ └── usb.c │ │ │ │ │ └── ulink_firmware.hex │ │ │ │ ├── am335xgpio.c │ │ │ │ ├── amt_jtagaccel.c │ │ │ │ ├── arm-jtag-ew.c │ │ │ │ ├── at91rm9200.c │ │ │ │ ├── bcm2835gpio.c │ │ │ │ ├── bitbang.c │ │ │ │ ├── bitbang.h │ │ │ │ ├── bitq.c │ │ │ │ ├── bitq.h │ │ │ │ ├── buspirate.c │ │ │ │ ├── ch347.c │ │ │ │ ├── cmsis_dap.c │ │ │ │ ├── cmsis_dap.h │ │ │ │ ├── cmsis_dap_usb_bulk.c │ │ │ │ ├── cmsis_dap_usb_hid.c │ │ │ │ ├── driver.c │ │ │ │ ├── dummy.c │ │ │ │ ├── ep93xx.c │ │ │ │ ├── esp_usb_jtag.c │ │ │ │ ├── ft232r.c │ │ │ │ ├── ftdi.c │ │ │ │ ├── gw16012.c │ │ │ │ ├── imx_gpio.c │ │ │ │ ├── jlink.c │ │ │ │ ├── jtag_dpi.c │ │ │ │ ├── jtag_vpi.c │ │ │ │ ├── kitprog.c │ │ │ │ ├── libftdi_helper.h │ │ │ │ ├── libusb_helper.c │ │ │ │ ├── libusb_helper.h │ │ │ │ ├── linuxgpiod.c │ │ │ │ ├── minidriver_imp.h │ │ │ │ ├── mpsse.c │ │ │ │ ├── mpsse.h │ │ │ │ ├── nulink_usb.c │ │ │ │ ├── opendous.c │ │ │ │ ├── openjtag.c │ │ │ │ ├── osbdm.c │ │ │ │ ├── parport.c │ │ │ │ ├── presto.c │ │ │ │ ├── remote_bitbang.c │ │ │ │ ├── rlink.c │ │ │ │ ├── rlink.h │ │ │ │ ├── rlink_call.m4 │ │ │ │ ├── rlink_dtc_cmd.h │ │ │ │ ├── rlink_ep1_cmd.h │ │ │ │ ├── rlink_init.m4 │ │ │ │ ├── rlink_speed_table.c │ │ │ │ ├── rlink_st7.h │ │ │ │ ├── rshim.c │ │ │ │ ├── stlink_usb.c │ │ │ │ ├── sysfsgpio.c │ │ │ │ ├── ti_icdi_usb.c │ │ │ │ ├── ulink.c │ │ │ │ ├── usb_blaster/ │ │ │ │ │ ├── Makefile.am │ │ │ │ │ ├── README.CheapClone │ │ │ │ │ ├── ublast2_access_libusb.c │ │ │ │ │ ├── ublast_access.h │ │ │ │ │ ├── ublast_access_ftdi.c │ │ │ │ │ └── usb_blaster.c │ │ │ │ ├── usbprog.c │ │ │ │ ├── vdebug.c │ │ │ │ ├── versaloon/ │ │ │ │ │ ├── usbtoxxx/ │ │ │ │ │ │ ├── usbtogpio.c │ │ │ │ │ │ ├── usbtojtagraw.c │ │ │ │ │ │ ├── usbtopwr.c │ │ │ │ │ │ ├── usbtoswd.c │ │ │ │ │ │ ├── usbtoxxx.c │ │ │ │ │ │ ├── usbtoxxx.h │ │ │ │ │ │ └── usbtoxxx_internal.h │ │ │ │ │ ├── versaloon.c │ │ │ │ │ ├── versaloon.h │ │ │ │ │ ├── versaloon_include.h │ │ │ │ │ └── versaloon_internal.h │ │ │ │ ├── vsllink.c │ │ │ │ ├── xds110.c │ │ │ │ └── xlnx-pcie-xvc.c │ │ │ ├── hla/ │ │ │ │ ├── Makefile.am │ │ │ │ ├── hla_interface.c │ │ │ │ ├── hla_interface.h │ │ │ │ ├── hla_layout.c │ │ │ │ ├── hla_layout.h │ │ │ │ ├── hla_transport.c │ │ │ │ └── hla_transport.h │ │ │ ├── interface.c │ │ │ ├── interface.h │ │ │ ├── interfaces.c │ │ │ ├── interfaces.h │ │ │ ├── jtag.h │ │ │ ├── minidriver.h │ │ │ ├── startup.tcl │ │ │ ├── swd.h │ │ │ ├── swim.c │ │ │ ├── swim.h │ │ │ ├── tcl.c │ │ │ └── tcl.h │ │ ├── main.c │ │ ├── openocd.c │ │ ├── openocd.h │ │ ├── pld/ │ │ │ ├── Makefile.am │ │ │ ├── certus.c │ │ │ ├── certus.h │ │ │ ├── ecp2_3.c │ │ │ ├── ecp2_3.h │ │ │ ├── ecp5.c │ │ │ ├── ecp5.h │ │ │ ├── efinix.c │ │ │ ├── gatemate.c │ │ │ ├── gowin.c │ │ │ ├── intel.c │ │ │ ├── lattice.c │ │ │ ├── lattice.h │ │ │ ├── lattice_bit.c │ │ │ ├── lattice_bit.h │ │ │ ├── lattice_cmd.h │ │ │ ├── pld.c │ │ │ ├── pld.h │ │ │ ├── raw_bit.c │ │ │ ├── raw_bit.h │ │ │ ├── virtex2.c │ │ │ ├── virtex2.h │ │ │ ├── xilinx_bit.c │ │ │ └── xilinx_bit.h │ │ ├── rtos/ │ │ │ ├── FreeRTOS.c │ │ │ ├── Makefile.am │ │ │ ├── ThreadX.c │ │ │ ├── chibios.c │ │ │ ├── chromium-ec.c │ │ │ ├── eCos.c │ │ │ ├── embKernel.c │ │ │ ├── hwthread.c │ │ │ ├── linux.c │ │ │ ├── linux_header.h │ │ │ ├── mqx.c │ │ │ ├── nuttx.c │ │ │ ├── riot.c │ │ │ ├── rtkernel.c │ │ │ ├── rtos.c │ │ │ ├── rtos.h │ │ │ ├── rtos_chibios_stackings.c │ │ │ ├── rtos_chibios_stackings.h │ │ │ ├── rtos_ecos_stackings.c │ │ │ ├── rtos_ecos_stackings.h │ │ │ ├── rtos_embkernel_stackings.c │ │ │ ├── rtos_embkernel_stackings.h │ │ │ ├── rtos_mqx_stackings.c │ │ │ ├── rtos_mqx_stackings.h │ │ │ ├── rtos_nuttx_stackings.c │ │ │ ├── rtos_nuttx_stackings.h │ │ │ ├── rtos_riot_stackings.c │ │ │ ├── rtos_riot_stackings.h │ │ │ ├── rtos_standard_stackings.c │ │ │ ├── rtos_standard_stackings.h │ │ │ ├── rtos_ucos_iii_stackings.c │ │ │ ├── rtos_ucos_iii_stackings.h │ │ │ ├── uCOS-III.c │ │ │ └── zephyr.c │ │ ├── rtt/ │ │ │ ├── Makefile.am │ │ │ ├── rtt.c │ │ │ ├── rtt.h │ │ │ └── tcl.c │ │ ├── server/ │ │ │ ├── Makefile.am │ │ │ ├── gdb_server.c │ │ │ ├── gdb_server.h │ │ │ ├── ipdbg.c │ │ │ ├── ipdbg.h │ │ │ ├── rtt_server.c │ │ │ ├── rtt_server.h │ │ │ ├── server.c │ │ │ ├── server.h │ │ │ ├── startup.tcl │ │ │ ├── tcl_server.c │ │ │ ├── tcl_server.h │ │ │ ├── telnet_server.c │ │ │ └── telnet_server.h │ │ ├── svf/ │ │ │ ├── Makefile.am │ │ │ ├── svf.c │ │ │ └── svf.h │ │ ├── target/ │ │ │ ├── Makefile.am │ │ │ ├── a64_disassembler.c │ │ │ ├── a64_disassembler.h │ │ │ ├── aarch64.c │ │ │ ├── aarch64.h │ │ │ ├── adi_v5_dapdirect.c │ │ │ ├── adi_v5_jtag.c │ │ │ ├── adi_v5_swd.c │ │ │ ├── algorithm.c │ │ │ ├── algorithm.h │ │ │ ├── arc.c │ │ │ ├── arc.h │ │ │ ├── arc_cmd.c │ │ │ ├── arc_cmd.h │ │ │ ├── arc_jtag.c │ │ │ ├── arc_jtag.h │ │ │ ├── arc_mem.c │ │ │ ├── arc_mem.h │ │ │ ├── arm.h │ │ │ ├── arm11.c │ │ │ ├── arm11.h │ │ │ ├── arm11_dbgtap.c │ │ │ ├── arm11_dbgtap.h │ │ │ ├── arm720t.c │ │ │ ├── arm720t.h │ │ │ ├── arm7_9_common.c │ │ │ ├── arm7_9_common.h │ │ │ ├── arm7tdmi.c │ │ │ ├── arm7tdmi.h │ │ │ ├── arm920t.c │ │ │ ├── arm920t.h │ │ │ ├── arm926ejs.c │ │ │ ├── arm926ejs.h │ │ │ ├── arm946e.c │ │ │ ├── arm946e.h │ │ │ ├── arm966e.c │ │ │ ├── arm966e.h │ │ │ ├── arm9tdmi.c │ │ │ ├── arm9tdmi.h │ │ │ ├── arm_adi_v5.c │ │ │ ├── arm_adi_v5.h │ │ │ ├── arm_coresight.h │ │ │ ├── arm_cti.c │ │ │ ├── arm_cti.h │ │ │ ├── arm_dap.c │ │ │ ├── arm_disassembler.c │ │ │ ├── arm_disassembler.h │ │ │ ├── arm_dpm.c │ │ │ ├── arm_dpm.h │ │ │ ├── arm_jtag.c │ │ │ ├── arm_jtag.h │ │ │ ├── arm_opcodes.h │ │ │ ├── arm_semihosting.c │ │ │ ├── arm_semihosting.h │ │ │ ├── arm_simulator.c │ │ │ ├── arm_simulator.h │ │ │ ├── arm_tpiu_swo.c │ │ │ ├── arm_tpiu_swo.h │ │ │ ├── armv4_5.c │ │ │ ├── armv4_5.h │ │ │ ├── armv4_5_cache.c │ │ │ ├── armv4_5_cache.h │ │ │ ├── armv4_5_mmu.c │ │ │ ├── armv4_5_mmu.h │ │ │ ├── armv7a.c │ │ │ ├── armv7a.h │ │ │ ├── armv7a_cache.c │ │ │ ├── armv7a_cache.h │ │ │ ├── armv7a_cache_l2x.c │ │ │ ├── armv7a_cache_l2x.h │ │ │ ├── armv7a_mmu.c │ │ │ ├── armv7a_mmu.h │ │ │ ├── armv7m.c │ │ │ ├── armv7m.h │ │ │ ├── armv7m_trace.c │ │ │ ├── armv7m_trace.h │ │ │ ├── armv8.c │ │ │ ├── armv8.h │ │ │ ├── armv8_cache.c │ │ │ ├── armv8_cache.h │ │ │ ├── armv8_dpm.c │ │ │ ├── armv8_dpm.h │ │ │ ├── armv8_opcodes.c │ │ │ ├── armv8_opcodes.h │ │ │ ├── avr32_ap7k.c │ │ │ ├── avr32_ap7k.h │ │ │ ├── avr32_jtag.c │ │ │ ├── avr32_jtag.h │ │ │ ├── avr32_mem.c │ │ │ ├── avr32_mem.h │ │ │ ├── avr32_regs.c │ │ │ ├── avr32_regs.h │ │ │ ├── avrt.c │ │ │ ├── avrt.h │ │ │ ├── breakpoints.c │ │ │ ├── breakpoints.h │ │ │ ├── cortex_a.c │ │ │ ├── cortex_a.h │ │ │ ├── cortex_m.c │ │ │ ├── cortex_m.h │ │ │ ├── dsp563xx.c │ │ │ ├── dsp563xx.h │ │ │ ├── dsp563xx_once.c │ │ │ ├── dsp563xx_once.h │ │ │ ├── dsp5680xx.c │ │ │ ├── dsp5680xx.h │ │ │ ├── embeddedice.c │ │ │ ├── embeddedice.h │ │ │ ├── esirisc.c │ │ │ ├── esirisc.h │ │ │ ├── esirisc_jtag.c │ │ │ ├── esirisc_jtag.h │ │ │ ├── esirisc_regs.h │ │ │ ├── esirisc_trace.c │ │ │ ├── esirisc_trace.h │ │ │ ├── espressif/ │ │ │ │ ├── Makefile.am │ │ │ │ ├── esp.c │ │ │ │ ├── esp.h │ │ │ │ ├── esp32.c │ │ │ │ ├── esp32_apptrace.c │ │ │ │ ├── esp32_apptrace.h │ │ │ │ ├── esp32_sysview.c │ │ │ │ ├── esp32_sysview.h │ │ │ │ ├── esp32s2.c │ │ │ │ ├── esp32s3.c │ │ │ │ ├── esp_semihosting.c │ │ │ │ ├── esp_semihosting.h │ │ │ │ ├── esp_xtensa.c │ │ │ │ ├── esp_xtensa.h │ │ │ │ ├── esp_xtensa_apptrace.c │ │ │ │ ├── esp_xtensa_apptrace.h │ │ │ │ ├── esp_xtensa_semihosting.c │ │ │ │ ├── esp_xtensa_semihosting.h │ │ │ │ ├── esp_xtensa_smp.c │ │ │ │ ├── esp_xtensa_smp.h │ │ │ │ └── segger_sysview.h │ │ │ ├── etb.c │ │ │ ├── etb.h │ │ │ ├── etm.c │ │ │ ├── etm.h │ │ │ ├── etm_dummy.c │ │ │ ├── etm_dummy.h │ │ │ ├── fa526.c │ │ │ ├── feroceon.c │ │ │ ├── hla_target.c │ │ │ ├── image.c │ │ │ ├── image.h │ │ │ ├── lakemont.c │ │ │ ├── lakemont.h │ │ │ ├── ls1_sap.c │ │ │ ├── mem_ap.c │ │ │ ├── mips32.c │ │ │ ├── mips32.h │ │ │ ├── mips32_dmaacc.c │ │ │ ├── mips32_dmaacc.h │ │ │ ├── mips32_pracc.c │ │ │ ├── mips32_pracc.h │ │ │ ├── mips64.c │ │ │ ├── mips64.h │ │ │ ├── mips64_pracc.c │ │ │ ├── mips64_pracc.h │ │ │ ├── mips_ejtag.c │ │ │ ├── mips_ejtag.h │ │ │ ├── mips_m4k.c │ │ │ ├── mips_m4k.h │ │ │ ├── mips_mips64.c │ │ │ ├── mips_mips64.h │ │ │ ├── openrisc/ │ │ │ │ ├── Makefile.am │ │ │ │ ├── jsp_server.c │ │ │ │ ├── jsp_server.h │ │ │ │ ├── or1k.c │ │ │ │ ├── or1k.h │ │ │ │ ├── or1k_du.h │ │ │ │ ├── or1k_du_adv.c │ │ │ │ ├── or1k_tap.h │ │ │ │ ├── or1k_tap_mohor.c │ │ │ │ ├── or1k_tap_vjtag.c │ │ │ │ └── or1k_tap_xilinx_bscan.c │ │ │ ├── quark_d20xx.c │ │ │ ├── quark_x10xx.c │ │ │ ├── register.c │ │ │ ├── register.h │ │ │ ├── riscv/ │ │ │ │ ├── Makefile.am │ │ │ │ ├── asm.h │ │ │ │ ├── batch.c │ │ │ │ ├── batch.h │ │ │ │ ├── debug_defines.h │ │ │ │ ├── encoding.h │ │ │ │ ├── gdb_regs.h │ │ │ │ ├── opcodes.h │ │ │ │ ├── program.c │ │ │ │ ├── program.h │ │ │ │ ├── riscv-011.c │ │ │ │ ├── riscv-013.c │ │ │ │ ├── riscv.c │ │ │ │ ├── riscv.h │ │ │ │ └── riscv_semihosting.c │ │ │ ├── rtt.c │ │ │ ├── rtt.h │ │ │ ├── semihosting_common.c │ │ │ ├── semihosting_common.h │ │ │ ├── smp.c │ │ │ ├── smp.h │ │ │ ├── startup.tcl │ │ │ ├── stm8.c │ │ │ ├── stm8.h │ │ │ ├── target.c │ │ │ ├── target.h │ │ │ ├── target_request.c │ │ │ ├── target_request.h │ │ │ ├── target_type.h │ │ │ ├── testee.c │ │ │ ├── trace.c │ │ │ ├── trace.h │ │ │ ├── x86_32_common.c │ │ │ ├── x86_32_common.h │ │ │ ├── xscale.c │ │ │ ├── xscale.h │ │ │ └── xtensa/ │ │ │ ├── Makefile.am │ │ │ ├── xtensa.c │ │ │ ├── xtensa.h │ │ │ ├── xtensa_chip.c │ │ │ ├── xtensa_chip.h │ │ │ ├── xtensa_debug_module.c │ │ │ ├── xtensa_debug_module.h │ │ │ ├── xtensa_fileio.c │ │ │ ├── xtensa_fileio.h │ │ │ └── xtensa_regs.h │ │ ├── transport/ │ │ │ ├── Makefile.am │ │ │ ├── transport.c │ │ │ └── transport.h │ │ └── xsvf/ │ │ ├── Makefile.am │ │ ├── xsvf.c │ │ └── xsvf.h │ ├── tcl/ │ │ ├── bitsbytes.tcl │ │ ├── board/ │ │ │ ├── 8devices-lima.cfg │ │ │ ├── actux3.cfg │ │ │ ├── adapteva_parallella1.cfg │ │ │ ├── adsp-sc584-ezbrd.cfg │ │ │ ├── alphascale_asm9260_ek.cfg │ │ │ ├── altera_sockit.cfg │ │ │ ├── am3517evm.cfg │ │ │ ├── ampere_emag8180.cfg │ │ │ ├── ampere_qs_mq_1s.cfg │ │ │ ├── ampere_qs_mq_2s.cfg │ │ │ ├── arm_evaluator7t.cfg │ │ │ ├── arm_musca_a.cfg │ │ │ ├── arty_s7.cfg │ │ │ ├── asus-rt-n16.cfg │ │ │ ├── asus-rt-n66u.cfg │ │ │ ├── at91cap7a-stk-sdram.cfg │ │ │ ├── at91eb40a.cfg │ │ │ ├── at91rm9200-dk.cfg │ │ │ ├── at91rm9200-ek.cfg │ │ │ ├── at91sam9261-ek.cfg │ │ │ ├── at91sam9263-ek.cfg │ │ │ ├── at91sam9g20-ek.cfg │ │ │ ├── atmel_at91sam7s-ek.cfg │ │ │ ├── atmel_at91sam9260-ek.cfg │ │ │ ├── atmel_at91sam9rl-ek.cfg │ │ │ ├── atmel_sam3n_ek.cfg │ │ │ ├── atmel_sam3s_ek.cfg │ │ │ ├── atmel_sam3u_ek.cfg │ │ │ ├── atmel_sam3x_ek.cfg │ │ │ ├── atmel_sam4e_ek.cfg │ │ │ ├── atmel_sam4l8_xplained_pro.cfg │ │ │ ├── atmel_sam4s_ek.cfg │ │ │ ├── atmel_sam4s_xplained_pro.cfg │ │ │ ├── atmel_samc20_xplained_pro.cfg │ │ │ ├── atmel_samc21_xplained_pro.cfg │ │ │ ├── atmel_samd10_xplained_mini.cfg │ │ │ ├── atmel_samd11_xplained_pro.cfg │ │ │ ├── atmel_samd20_xplained_pro.cfg │ │ │ ├── atmel_samd21_xplained_pro.cfg │ │ │ ├── atmel_same70_xplained.cfg │ │ │ ├── atmel_samg53_xplained_pro.cfg │ │ │ ├── atmel_samg55_xplained_pro.cfg │ │ │ ├── atmel_saml21_xplained_pro.cfg │ │ │ ├── atmel_samr21_xplained_pro.cfg │ │ │ ├── atmel_samv71_xplained_ultra.cfg │ │ │ ├── avnet_ultrazed-eg.cfg │ │ │ ├── balloon3-cpu.cfg │ │ │ ├── bcm28155_ap.cfg │ │ │ ├── bemicro_cycloneiii.cfg │ │ │ ├── bluefield.cfg │ │ │ ├── bt-homehubv1.cfg │ │ │ ├── calao-usb-a9260.cfg │ │ │ ├── calao-usb-a9g20-c01.cfg │ │ │ ├── certuspro_evaluation.cfg │ │ │ ├── colibri.cfg │ │ │ ├── crossbow_tech_imote2.cfg │ │ │ ├── csb337.cfg │ │ │ ├── csb732.cfg │ │ │ ├── da850evm.cfg │ │ │ ├── digi_connectcore_wi-9c.cfg │ │ │ ├── digilent_analog_discovery.cfg │ │ │ ├── digilent_atlys.cfg │ │ │ ├── digilent_nexys_video.cfg │ │ │ ├── digilent_zedboard.cfg │ │ │ ├── diolan_lpc4350-db1.cfg │ │ │ ├── diolan_lpc4357-db1.cfg │ │ │ ├── dk-tm4c129.cfg │ │ │ ├── dm355evm.cfg │ │ │ ├── dm365evm.cfg │ │ │ ├── dm6446evm.cfg │ │ │ ├── dp_busblaster_v3.cfg │ │ │ ├── dp_busblaster_v4.cfg │ │ │ ├── dptechnics_dpt-board-v1.cfg │ │ │ ├── ecp5_evaluation.cfg │ │ │ ├── efikamx.cfg │ │ │ ├── efm32.cfg │ │ │ ├── eir.cfg │ │ │ ├── ek-lm3s1968.cfg │ │ │ ├── ek-lm3s3748.cfg │ │ │ ├── ek-lm3s6965.cfg │ │ │ ├── ek-lm3s811-revb.cfg │ │ │ ├── ek-lm3s811.cfg │ │ │ ├── ek-lm3s8962.cfg │ │ │ ├── ek-lm3s9b9x.cfg │ │ │ ├── ek-lm3s9d92.cfg │ │ │ ├── ek-lm4f120xl.cfg │ │ │ ├── ek-lm4f232.cfg │ │ │ ├── ek-tm4c123gxl.cfg │ │ │ ├── ek-tm4c1294xl.cfg │ │ │ ├── embedded-artists_lpc2478-32.cfg │ │ │ ├── emcraft_imx8m-som-bsb.cfg │ │ │ ├── emcraft_twr-vf6-som-bsb.cfg │ │ │ ├── emcraft_vf6-som.cfg │ │ │ ├── esp32-bridge.cfg │ │ │ ├── esp32-ethernet-kit-3.3v.cfg │ │ │ ├── esp32-wrover-kit-1.8v.cfg │ │ │ ├── esp32-wrover-kit-3.3v.cfg │ │ │ ├── esp32s2-bridge.cfg │ │ │ ├── esp32s2-kaluga-1.cfg │ │ │ ├── esp32s3-bridge.cfg │ │ │ ├── esp32s3-builtin.cfg │ │ │ ├── esp32s3-ftdi.cfg │ │ │ ├── ethernut3.cfg │ │ │ ├── evb-lan9255.cfg │ │ │ ├── frdm-kl25z.cfg │ │ │ ├── frdm-kl46z.cfg │ │ │ ├── fsl_imx6q_sabresd.cfg │ │ │ ├── gatemate_eval.cfg │ │ │ ├── glyn_tonga2.cfg │ │ │ ├── gowin_runber.cfg │ │ │ ├── gti/ │ │ │ │ └── espressobin.cfg │ │ │ ├── gumstix-aerocore.cfg │ │ │ ├── hammer.cfg │ │ │ ├── hilscher_nxdb500sys.cfg │ │ │ ├── hilscher_nxeb500hmi.cfg │ │ │ ├── hilscher_nxhx10.cfg │ │ │ ├── hilscher_nxhx50.cfg │ │ │ ├── hilscher_nxhx500.cfg │ │ │ ├── hilscher_nxsb100.cfg │ │ │ ├── hitex_lpc1768stick.cfg │ │ │ ├── hitex_lpc2929.cfg │ │ │ ├── hitex_stm32-performancestick.cfg │ │ │ ├── hitex_str9-comstick.cfg │ │ │ ├── iar_lpc1768.cfg │ │ │ ├── iar_str912_sk.cfg │ │ │ ├── icnova_imx53_sodimm.cfg │ │ │ ├── icnova_sam9g45_sodimm.cfg │ │ │ ├── imx27ads.cfg │ │ │ ├── imx27lnst.cfg │ │ │ ├── imx28evk.cfg │ │ │ ├── imx31pdk.cfg │ │ │ ├── imx35pdk.cfg │ │ │ ├── imx53-m53evk.cfg │ │ │ ├── imx53loco.cfg │ │ │ ├── imx8mp-evk.cfg │ │ │ ├── insignal_arndale.cfg │ │ │ ├── kasli.cfg │ │ │ ├── kc100.cfg │ │ │ ├── kc705.cfg │ │ │ ├── kcu105.cfg │ │ │ ├── keil_mcb1700.cfg │ │ │ ├── keil_mcb2140.cfg │ │ │ ├── kindle2.cfg │ │ │ ├── kontron_sl28.cfg │ │ │ ├── kwikstik.cfg │ │ │ ├── la_fonera-fon2200.cfg │ │ │ ├── lambdaconcept_ecpix-5.cfg │ │ │ ├── lemaker_hikey.cfg │ │ │ ├── linksys-wag200g.cfg │ │ │ ├── linksys-wrt54gl.cfg │ │ │ ├── linksys_nslu2.cfg │ │ │ ├── lisa-l.cfg │ │ │ ├── logicpd_imx27.cfg │ │ │ ├── lpc1850_spifi_generic.cfg │ │ │ ├── lpc4350_spifi_generic.cfg │ │ │ ├── lubbock.cfg │ │ │ ├── marsohod.cfg │ │ │ ├── marsohod2.cfg │ │ │ ├── marsohod3.cfg │ │ │ ├── mbed-lpc11u24.cfg │ │ │ ├── mbed-lpc1768.cfg │ │ │ ├── mcb1700.cfg │ │ │ ├── microchip_explorer16.cfg │ │ │ ├── microchip_sama5d27_som1_kit1.cfg │ │ │ ├── microchip_same51_curiosity_nano.cfg │ │ │ ├── microchip_same54_xplained_pro.cfg │ │ │ ├── microchip_saml11_xplained_pro.cfg │ │ │ ├── mini2440.cfg │ │ │ ├── mini6410.cfg │ │ │ ├── minispartan6.cfg │ │ │ ├── nds32_corvettef1.cfg │ │ │ ├── nds32_xc7.cfg │ │ │ ├── netgear-dg834v3.cfg │ │ │ ├── netgear-wg102.cfg │ │ │ ├── nordic_nrf51822_mkit.cfg │ │ │ ├── nordic_nrf51_dk.cfg │ │ │ ├── nordic_nrf52_dk.cfg │ │ │ ├── nordic_nrf52_ftx232.cfg │ │ │ ├── novena-internal-fpga.cfg │ │ │ ├── npcx_evb.cfg │ │ │ ├── numato_mimas_a7.cfg │ │ │ ├── numato_opsis.cfg │ │ │ ├── nxp_frdm-k64f.cfg │ │ │ ├── nxp_frdm-ls1012a.cfg │ │ │ ├── nxp_imx7sabre.cfg │ │ │ ├── nxp_lpc-link2.cfg │ │ │ ├── nxp_mcimx8m-evk.cfg │ │ │ ├── nxp_rdb-ls1046a.cfg │ │ │ ├── nxp_rdb-ls1088a.cfg │ │ │ ├── olimex_LPC2378STK.cfg │ │ │ ├── olimex_lpc_h2148.cfg │ │ │ ├── olimex_sam7_ex256.cfg │ │ │ ├── olimex_sam7_la2.cfg │ │ │ ├── olimex_sam9_l9260.cfg │ │ │ ├── olimex_stm32_h103.cfg │ │ │ ├── olimex_stm32_h107.cfg │ │ │ ├── olimex_stm32_h405.cfg │ │ │ ├── olimex_stm32_p107.cfg │ │ │ ├── omap2420_h4.cfg │ │ │ ├── openrd.cfg │ │ │ ├── or1k_generic.cfg │ │ │ ├── osk5912.cfg │ │ │ ├── phone_se_j100i.cfg │ │ │ ├── phytec_lpc3250.cfg │ │ │ ├── pic-p32mx.cfg │ │ │ ├── pico-debug.cfg │ │ │ ├── pipistrello.cfg │ │ │ ├── propox_mmnet1001.cfg │ │ │ ├── pxa255_sst.cfg │ │ │ ├── quark_d2000_refboard.cfg │ │ │ ├── quark_x10xx_board.cfg │ │ │ ├── quicklogic_quickfeather.cfg │ │ │ ├── radiona_ulx3s.cfg │ │ │ ├── redbee.cfg │ │ │ ├── reflexces_achilles_i-dev_kit_arria10.cfg │ │ │ ├── renesas_dk-s7g2.cfg │ │ │ ├── renesas_falcon.cfg │ │ │ ├── renesas_gr_peach.cfg │ │ │ ├── renesas_porter.cfg │ │ │ ├── renesas_salvator-xs.cfg │ │ │ ├── renesas_silk.cfg │ │ │ ├── renesas_stout.cfg │ │ │ ├── rigado_bmd300_ek.cfg │ │ │ ├── rpi3.cfg │ │ │ ├── rpi4b.cfg │ │ │ ├── rsc-w910.cfg │ │ │ ├── sayma_amc.cfg │ │ │ ├── sheevaplug.cfg │ │ │ ├── sifive-e31arty.cfg │ │ │ ├── sifive-e51arty.cfg │ │ │ ├── sifive-hifive1-revb.cfg │ │ │ ├── sifive-hifive1.cfg │ │ │ ├── smdk6410.cfg │ │ │ ├── snps_em_sk.cfg │ │ │ ├── snps_em_sk_v1.cfg │ │ │ ├── snps_em_sk_v2.1.cfg │ │ │ ├── snps_em_sk_v2.2.cfg │ │ │ ├── snps_hsdk.cfg │ │ │ ├── spansion_sk-fm4-176l-s6e2cc.cfg │ │ │ ├── spansion_sk-fm4-u120-9b560.cfg │ │ │ ├── spear300evb.cfg │ │ │ ├── spear300evb_mod.cfg │ │ │ ├── spear310evb20.cfg │ │ │ ├── spear310evb20_mod.cfg │ │ │ ├── spear320cpu.cfg │ │ │ ├── spear320cpu_mod.cfg │ │ │ ├── st_b-l475e-iot01a.cfg │ │ │ ├── st_nucleo_8l152r8.cfg │ │ │ ├── st_nucleo_8s208rb.cfg │ │ │ ├── st_nucleo_f0.cfg │ │ │ ├── st_nucleo_f103rb.cfg │ │ │ ├── st_nucleo_f3.cfg │ │ │ ├── st_nucleo_f4.cfg │ │ │ ├── st_nucleo_f7.cfg │ │ │ ├── st_nucleo_g0.cfg │ │ │ ├── st_nucleo_g4.cfg │ │ │ ├── st_nucleo_h743zi.cfg │ │ │ ├── st_nucleo_h745zi.cfg │ │ │ ├── st_nucleo_l073rz.cfg │ │ │ ├── st_nucleo_l1.cfg │ │ │ ├── st_nucleo_l4.cfg │ │ │ ├── st_nucleo_l5.cfg │ │ │ ├── st_nucleo_wb55.cfg │ │ │ ├── steval-idb007v1.cfg │ │ │ ├── steval-idb008v1.cfg │ │ │ ├── steval-idb011v1.cfg │ │ │ ├── steval-idb012v1.cfg │ │ │ ├── steval_pcc010.cfg │ │ │ ├── stm320518_eval.cfg │ │ │ ├── stm320518_eval_stlink.cfg │ │ │ ├── stm32100b_eval.cfg │ │ │ ├── stm3210b_eval.cfg │ │ │ ├── stm3210c_eval.cfg │ │ │ ├── stm3210e_eval.cfg │ │ │ ├── stm3220g_eval.cfg │ │ │ ├── stm3220g_eval_stlink.cfg │ │ │ ├── stm3241g_eval.cfg │ │ │ ├── stm3241g_eval_stlink.cfg │ │ │ ├── stm32429i_eval.cfg │ │ │ ├── stm32429i_eval_stlink.cfg │ │ │ ├── stm32439i_eval.cfg │ │ │ ├── stm32439i_eval_stlink.cfg │ │ │ ├── stm327x6g_eval.cfg │ │ │ ├── stm32f0discovery.cfg │ │ │ ├── stm32f103c8_blue_pill.cfg │ │ │ ├── stm32f334discovery.cfg │ │ │ ├── stm32f3discovery.cfg │ │ │ ├── stm32f412g-disco.cfg │ │ │ ├── stm32f413h-disco.cfg │ │ │ ├── stm32f429disc1.cfg │ │ │ ├── stm32f429discovery.cfg │ │ │ ├── stm32f469discovery.cfg │ │ │ ├── stm32f469i-disco.cfg │ │ │ ├── stm32f4discovery.cfg │ │ │ ├── stm32f723e-disco.cfg │ │ │ ├── stm32f746g-disco.cfg │ │ │ ├── stm32f769i-disco.cfg │ │ │ ├── stm32f7discovery.cfg │ │ │ ├── stm32h735g-disco.cfg │ │ │ ├── stm32h745i-disco.cfg │ │ │ ├── stm32h747i-disco.cfg │ │ │ ├── stm32h750b-disco.cfg │ │ │ ├── stm32h7b3i-disco.cfg │ │ │ ├── stm32h7x3i_eval.cfg │ │ │ ├── stm32h7x_dual_qspi.cfg │ │ │ ├── stm32l0discovery.cfg │ │ │ ├── stm32l476g-disco.cfg │ │ │ ├── stm32l496g-disco.cfg │ │ │ ├── stm32l4discovery.cfg │ │ │ ├── stm32l4p5g-disco.cfg │ │ │ ├── stm32l4r9i-disco.cfg │ │ │ ├── stm32ldiscovery.cfg │ │ │ ├── stm32mp13x_dk.cfg │ │ │ ├── stm32mp15x_dk2.cfg │ │ │ ├── stm32vldiscovery.cfg │ │ │ ├── str910-eval.cfg │ │ │ ├── telo.cfg │ │ │ ├── ti_am335xevm.cfg │ │ │ ├── ti_am437x_idk.cfg │ │ │ ├── ti_am43xx_evm.cfg │ │ │ ├── ti_am625evm.cfg │ │ │ ├── ti_am642evm.cfg │ │ │ ├── ti_am654evm.cfg │ │ │ ├── ti_beagleboard.cfg │ │ │ ├── ti_beagleboard_xm.cfg │ │ │ ├── ti_beaglebone-base.cfg │ │ │ ├── ti_beaglebone.cfg │ │ │ ├── ti_beaglebone_black.cfg │ │ │ ├── ti_blaze.cfg │ │ │ ├── ti_cc13x0_launchpad.cfg │ │ │ ├── ti_cc13x2_launchpad.cfg │ │ │ ├── ti_cc26x0_launchpad.cfg │ │ │ ├── ti_cc26x2_launchpad.cfg │ │ │ ├── ti_cc3200_launchxl.cfg │ │ │ ├── ti_cc3220sf_launchpad.cfg │ │ │ ├── ti_cc32xx_launchpad.cfg │ │ │ ├── ti_dk-tm4c129.cfg │ │ │ ├── ti_ek-tm4c123gxl.cfg │ │ │ ├── ti_ek-tm4c1294xl.cfg │ │ │ ├── ti_j7200evm.cfg │ │ │ ├── ti_j721evm.cfg │ │ │ ├── ti_j721s2evm.cfg │ │ │ ├── ti_msp432_launchpad.cfg │ │ │ ├── ti_pandaboard.cfg │ │ │ ├── ti_pandaboard_es.cfg │ │ │ ├── ti_tmdx570ls20susb.cfg │ │ │ ├── ti_tmdx570ls31usb.cfg │ │ │ ├── tocoding_poplar.cfg │ │ │ ├── topas910.cfg │ │ │ ├── topasa900.cfg │ │ │ ├── tp-link_tl-mr3020.cfg │ │ │ ├── tp-link_wdr4300.cfg │ │ │ ├── trion_t20_bga256.cfg │ │ │ ├── twr-k60f120m.cfg │ │ │ ├── twr-k60n512.cfg │ │ │ ├── twr-vf65gs10.cfg │ │ │ ├── twr-vf65gs10_cmsisdap.cfg │ │ │ ├── tx25_stk5.cfg │ │ │ ├── tx27_stk5.cfg │ │ │ ├── unknown_at91sam9260.cfg │ │ │ ├── uptech_2410.cfg │ │ │ ├── vd_a53x2_dap.cfg │ │ │ ├── vd_a53x2_jtag.cfg │ │ │ ├── vd_m4_dap.cfg │ │ │ ├── vd_m4_jtag.cfg │ │ │ ├── vd_m7_jtag.cfg │ │ │ ├── vd_pulpissimo_jtag.cfg │ │ │ ├── vd_swerv_jtag.cfg │ │ │ ├── vd_xt8_jtag.cfg │ │ │ ├── verdex.cfg │ │ │ ├── voipac.cfg │ │ │ ├── voltcraft_dso-3062c.cfg │ │ │ ├── x300t.cfg │ │ │ ├── xmc-2go.cfg │ │ │ ├── xmc1100-boot-kit.cfg │ │ │ ├── xmc4200-application-kit-actuator.cfg │ │ │ ├── xmc4300-relax.cfg │ │ │ ├── xmc4500-application-kit-general.cfg │ │ │ ├── xmc4500-application-kit-sdram.cfg │ │ │ ├── xmc4500-relax.cfg │ │ │ ├── xmc4700-relax.cfg │ │ │ ├── xmc4800-relax.cfg │ │ │ ├── xmos_xk-xac-xa8_arm.cfg │ │ │ ├── xtensa-kc705-ext-dap.cfg │ │ │ ├── xtensa-kc705-ext.cfg │ │ │ ├── xtensa-kc705-onboard.cfg │ │ │ ├── xtensa-palladium-vdebug.cfg │ │ │ └── xtensa-rt685-ext.cfg │ │ ├── chip/ │ │ │ ├── atmel/ │ │ │ │ └── at91/ │ │ │ │ ├── aic.tcl │ │ │ │ ├── at91_pio.cfg │ │ │ │ ├── at91_pmc.cfg │ │ │ │ ├── at91_rstc.cfg │ │ │ │ ├── at91_wdt.cfg │ │ │ │ ├── at91sam7x128.tcl │ │ │ │ ├── at91sam7x256.tcl │ │ │ │ ├── at91sam9261.cfg │ │ │ │ ├── at91sam9261_matrix.cfg │ │ │ │ ├── at91sam9263.cfg │ │ │ │ ├── at91sam9263_matrix.cfg │ │ │ │ ├── at91sam9_init.cfg │ │ │ │ ├── at91sam9_sdramc.cfg │ │ │ │ ├── at91sam9_smc.cfg │ │ │ │ ├── hardware.cfg │ │ │ │ ├── pmc.tcl │ │ │ │ ├── rtt.tcl │ │ │ │ ├── sam9_smc.cfg │ │ │ │ └── usarts.tcl │ │ │ ├── st/ │ │ │ │ ├── spear/ │ │ │ │ │ ├── quirk_no_srst.tcl │ │ │ │ │ ├── spear3xx.tcl │ │ │ │ │ └── spear3xx_ddr.tcl │ │ │ │ └── stm32/ │ │ │ │ ├── stm32.tcl │ │ │ │ ├── stm32_rcc.tcl │ │ │ │ └── stm32_regs.tcl │ │ │ └── ti/ │ │ │ └── lm3s/ │ │ │ ├── lm3s.tcl │ │ │ └── lm3s_regs.tcl │ │ ├── cpld/ │ │ │ ├── altera-5m570z-cpld.cfg │ │ │ ├── altera-epm240.cfg │ │ │ ├── altera-max10.cfg │ │ │ ├── altera-maxii.cfg │ │ │ ├── altera-maxv.cfg │ │ │ ├── jtagspi.cfg │ │ │ ├── lattice-lc4032ze.cfg │ │ │ ├── xilinx-xc3s.cfg │ │ │ ├── xilinx-xc4v.cfg │ │ │ ├── xilinx-xc4vfx_40_60_100_140.cfg │ │ │ ├── xilinx-xc5v.cfg │ │ │ ├── xilinx-xc5vfx_100_130_200.cfg │ │ │ ├── xilinx-xc6s.cfg │ │ │ ├── xilinx-xc6v.cfg │ │ │ ├── xilinx-xc7.cfg │ │ │ ├── xilinx-xc7v.cfg │ │ │ ├── xilinx-xc7vh580t.cfg │ │ │ ├── xilinx-xc7vh870t.cfg │ │ │ ├── xilinx-xcf-p.cfg │ │ │ ├── xilinx-xcf-s.cfg │ │ │ ├── xilinx-xcr3256.cfg │ │ │ └── xilinx-xcu.cfg │ │ ├── cpu/ │ │ │ ├── arc/ │ │ │ │ ├── common.tcl │ │ │ │ ├── em.tcl │ │ │ │ ├── hs.tcl │ │ │ │ └── v2.tcl │ │ │ └── arm/ │ │ │ ├── arm7tdmi.tcl │ │ │ ├── arm920.tcl │ │ │ ├── arm946.tcl │ │ │ ├── arm966.tcl │ │ │ └── cortex_m3.tcl │ │ ├── fpga/ │ │ │ ├── altera-10m50.cfg │ │ │ ├── altera-arriaii.cfg │ │ │ ├── altera-cyclone10.cfg │ │ │ ├── altera-cycloneiii.cfg │ │ │ ├── altera-cycloneiv.cfg │ │ │ ├── altera-cyclonev.cfg │ │ │ ├── altera-ep3c10.cfg │ │ │ ├── efinix_titanium.cfg │ │ │ ├── efinix_trion.cfg │ │ │ ├── gatemate.cfg │ │ │ ├── gowin_gw1n.cfg │ │ │ ├── lattice_certus.cfg │ │ │ ├── lattice_certuspro.cfg │ │ │ ├── lattice_ecp2.cfg │ │ │ ├── lattice_ecp3.cfg │ │ │ ├── lattice_ecp5.cfg │ │ │ ├── lattice_machxo3.cfg │ │ │ ├── xilinx-dna.cfg │ │ │ └── xilinx-xadc.cfg │ │ ├── interface/ │ │ │ ├── altera-usb-blaster.cfg │ │ │ ├── altera-usb-blaster2.cfg │ │ │ ├── arm-jtag-ew.cfg │ │ │ ├── ast2600-gpiod.cfg │ │ │ ├── at91rm9200.cfg │ │ │ ├── beaglebone-jtag-native.cfg │ │ │ ├── beaglebone-swd-native.cfg │ │ │ ├── buspirate.cfg │ │ │ ├── chameleon.cfg │ │ │ ├── cmsis-dap.cfg │ │ │ ├── dln-2-gpiod.cfg │ │ │ ├── dummy.cfg │ │ │ ├── esp_usb_bridge.cfg │ │ │ ├── esp_usb_jtag.cfg │ │ │ ├── estick.cfg │ │ │ ├── flashlink.cfg │ │ │ ├── ft232r/ │ │ │ │ └── radiona_ulx3s.cfg │ │ │ ├── ft232r.cfg │ │ │ ├── ftdi/ │ │ │ │ ├── 100ask-openjtag.cfg │ │ │ │ ├── ashling-opella-ld-jtag.cfg │ │ │ │ ├── ashling-opella-ld-swd.cfg │ │ │ │ ├── axm0432.cfg │ │ │ │ ├── c232hm.cfg │ │ │ │ ├── cortino.cfg │ │ │ │ ├── digilent-hs1.cfg │ │ │ │ ├── digilent-hs2.cfg │ │ │ │ ├── digilent_jtag_hs3.cfg │ │ │ │ ├── digilent_jtag_smt2.cfg │ │ │ │ ├── digilent_jtag_smt2_nc.cfg │ │ │ │ ├── dlp-usb1232h.cfg │ │ │ │ ├── dp_busblaster.cfg │ │ │ │ ├── dp_busblaster_kt-link.cfg │ │ │ │ ├── esp32_devkitj_v1.cfg │ │ │ │ ├── esp32s2_kaluga_v1.cfg │ │ │ │ ├── flossjtag-noeeprom.cfg │ │ │ │ ├── flossjtag.cfg │ │ │ │ ├── flyswatter.cfg │ │ │ │ ├── flyswatter2.cfg │ │ │ │ ├── ft232h-module-swd.cfg │ │ │ │ ├── gw16042.cfg │ │ │ │ ├── hie-jtag.cfg │ │ │ │ ├── hilscher_nxhx10_etm.cfg │ │ │ │ ├── hilscher_nxhx500_etm.cfg │ │ │ │ ├── hilscher_nxhx500_re.cfg │ │ │ │ ├── hilscher_nxhx50_etm.cfg │ │ │ │ ├── hilscher_nxhx50_re.cfg │ │ │ │ ├── hitex_lpc1768stick.cfg │ │ │ │ ├── hitex_str9-comstick.cfg │ │ │ │ ├── icebear.cfg │ │ │ │ ├── imx8mp-evk.cfg │ │ │ │ ├── incircuit-icprog.cfg │ │ │ │ ├── iotlab-usb.cfg │ │ │ │ ├── isodebug.cfg │ │ │ │ ├── jtag-lock-pick_tiny_2.cfg │ │ │ │ ├── jtagkey.cfg │ │ │ │ ├── jtagkey2.cfg │ │ │ │ ├── jtagkey2p.cfg │ │ │ │ ├── kt-link.cfg │ │ │ │ ├── lambdaconcept_ecpix-5.cfg │ │ │ │ ├── lisa-l.cfg │ │ │ │ ├── luminary-icdi.cfg │ │ │ │ ├── luminary-lm3s811.cfg │ │ │ │ ├── luminary.cfg │ │ │ │ ├── m53evk.cfg │ │ │ │ ├── mbftdi.cfg │ │ │ │ ├── minimodule-swd.cfg │ │ │ │ ├── minimodule.cfg │ │ │ │ ├── minispartan6.cfg │ │ │ │ ├── miniwiggler.cfg │ │ │ │ ├── neodb.cfg │ │ │ │ ├── ngxtech.cfg │ │ │ │ ├── olimex-arm-jtag-swd.cfg │ │ │ │ ├── olimex-arm-usb-ocd-h.cfg │ │ │ │ ├── olimex-arm-usb-ocd.cfg │ │ │ │ ├── olimex-arm-usb-tiny-h.cfg │ │ │ │ ├── olimex-jtag-tiny.cfg │ │ │ │ ├── oocdlink.cfg │ │ │ │ ├── opendous_ftdi.cfg │ │ │ │ ├── openocd-usb-hs.cfg │ │ │ │ ├── openocd-usb.cfg │ │ │ │ ├── openrd.cfg │ │ │ │ ├── pipistrello.cfg │ │ │ │ ├── pls_spc5.cfg │ │ │ │ ├── redbee-econotag.cfg │ │ │ │ ├── redbee-usb.cfg │ │ │ │ ├── rowley-cc-arm-swd.cfg │ │ │ │ ├── sheevaplug.cfg │ │ │ │ ├── signalyzer-lite.cfg │ │ │ │ ├── signalyzer.cfg │ │ │ │ ├── snps_sdp.cfg │ │ │ │ ├── steppenprobe.cfg │ │ │ │ ├── stm32-stick.cfg │ │ │ │ ├── swd-resistor-hack.cfg │ │ │ │ ├── ti-icdi.cfg │ │ │ │ ├── tigard.cfg │ │ │ │ ├── tumpa-lite.cfg │ │ │ │ ├── tumpa.cfg │ │ │ │ ├── turtelizer2-revB.cfg │ │ │ │ ├── turtelizer2-revC.cfg │ │ │ │ ├── um232h.cfg │ │ │ │ ├── vpaclink.cfg │ │ │ │ ├── xds100v2.cfg │ │ │ │ ├── xds100v3.cfg │ │ │ │ └── xt_kc705_ml605.cfg │ │ │ ├── imx-native.cfg │ │ │ ├── jlink.cfg │ │ │ ├── jtag_dpi.cfg │ │ │ ├── jtag_hat_rpi2.cfg │ │ │ ├── jtag_vpi.cfg │ │ │ ├── kitprog.cfg │ │ │ ├── nulink.cfg │ │ │ ├── opendous.cfg │ │ │ ├── openjtag.cfg │ │ │ ├── osbdm.cfg │ │ │ ├── parport.cfg │ │ │ ├── parport_dlc5.cfg │ │ │ ├── raspberrypi-gpio-connector.cfg │ │ │ ├── raspberrypi-native.cfg │ │ │ ├── raspberrypi2-native.cfg │ │ │ ├── rlink.cfg │ │ │ ├── rshim.cfg │ │ │ ├── stlink-dap.cfg │ │ │ ├── stlink-v1.cfg │ │ │ ├── stlink-v2-1.cfg │ │ │ ├── stlink-v2.cfg │ │ │ ├── stlink.cfg │ │ │ ├── sysfsgpio-raspberrypi.cfg │ │ │ ├── ti-icdi.cfg │ │ │ ├── ulink.cfg │ │ │ ├── usb-jtag.cfg │ │ │ ├── usbprog.cfg │ │ │ ├── vdebug.cfg │ │ │ ├── vsllink.cfg │ │ │ └── xds110.cfg │ │ ├── mem_helper.tcl │ │ ├── memory.tcl │ │ ├── mmr_helpers.tcl │ │ ├── target/ │ │ │ ├── 1986ве1т.cfg │ │ │ ├── adsp-sc58x.cfg │ │ │ ├── aduc702x.cfg │ │ │ ├── aducm360.cfg │ │ │ ├── allwinner_v3s.cfg │ │ │ ├── alphascale_asm9260t.cfg │ │ │ ├── altera_fpgasoc.cfg │ │ │ ├── altera_fpgasoc_arria10.cfg │ │ │ ├── am335x.cfg │ │ │ ├── am437x.cfg │ │ │ ├── amdm37x.cfg │ │ │ ├── ampere_emag.cfg │ │ │ ├── ampere_qs_mq.cfg │ │ │ ├── ar71xx.cfg │ │ │ ├── arm_corelink_sse200.cfg │ │ │ ├── armada370.cfg │ │ │ ├── at32ap7000.cfg │ │ │ ├── at91r40008.cfg │ │ │ ├── at91rm9200.cfg │ │ │ ├── at91sam3XXX.cfg │ │ │ ├── at91sam3ax_4x.cfg │ │ │ ├── at91sam3ax_8x.cfg │ │ │ ├── at91sam3ax_xx.cfg │ │ │ ├── at91sam3nXX.cfg │ │ │ ├── at91sam3sXX.cfg │ │ │ ├── at91sam3u1c.cfg │ │ │ ├── at91sam3u1e.cfg │ │ │ ├── at91sam3u2c.cfg │ │ │ ├── at91sam3u2e.cfg │ │ │ ├── at91sam3u4c.cfg │ │ │ ├── at91sam3u4e.cfg │ │ │ ├── at91sam3uxx.cfg │ │ │ ├── at91sam4XXX.cfg │ │ │ ├── at91sam4c32x.cfg │ │ │ ├── at91sam4cXXX.cfg │ │ │ ├── at91sam4lXX.cfg │ │ │ ├── at91sam4sXX.cfg │ │ │ ├── at91sam4sd32x.cfg │ │ │ ├── at91sam7a2.cfg │ │ │ ├── at91sam7se512.cfg │ │ │ ├── at91sam7sx.cfg │ │ │ ├── at91sam7x256.cfg │ │ │ ├── at91sam7x512.cfg │ │ │ ├── at91sam9.cfg │ │ │ ├── at91sam9260.cfg │ │ │ ├── at91sam9260_ext_RAM_ext_flash.cfg │ │ │ ├── at91sam9261.cfg │ │ │ ├── at91sam9263.cfg │ │ │ ├── at91sam9g10.cfg │ │ │ ├── at91sam9g20.cfg │ │ │ ├── at91sam9g45.cfg │ │ │ ├── at91sam9rl.cfg │ │ │ ├── at91sama5d2.cfg │ │ │ ├── at91samdXX.cfg │ │ │ ├── at91samg5x.cfg │ │ │ ├── atheros_ar2313.cfg │ │ │ ├── atheros_ar2315.cfg │ │ │ ├── atheros_ar9331.cfg │ │ │ ├── atheros_ar9344.cfg │ │ │ ├── atmega128.cfg │ │ │ ├── atmega128rfa1.cfg │ │ │ ├── atmega32u4.cfg │ │ │ ├── atsame5x.cfg │ │ │ ├── atsaml1x.cfg │ │ │ ├── atsamv.cfg │ │ │ ├── avr32.cfg │ │ │ ├── bcm2711.cfg │ │ │ ├── bcm281xx.cfg │ │ │ ├── bcm2835.cfg │ │ │ ├── bcm2836.cfg │ │ │ ├── bcm2837.cfg │ │ │ ├── bcm4706.cfg │ │ │ ├── bcm4718.cfg │ │ │ ├── bcm47xx.cfg │ │ │ ├── bcm5352e.cfg │ │ │ ├── bcm6348.cfg │ │ │ ├── bluefield.cfg │ │ │ ├── bluenrg-x.cfg │ │ │ ├── c100.cfg │ │ │ ├── c100config.tcl │ │ │ ├── c100helper.tcl │ │ │ ├── c100regs.tcl │ │ │ ├── cc2538.cfg │ │ │ ├── cs351x.cfg │ │ │ ├── davinci.cfg │ │ │ ├── dragonite.cfg │ │ │ ├── dsp56321.cfg │ │ │ ├── dsp568013.cfg │ │ │ ├── dsp568037.cfg │ │ │ ├── efm32.cfg │ │ │ ├── em357.cfg │ │ │ ├── em358.cfg │ │ │ ├── eos_s3.cfg │ │ │ ├── epc9301.cfg │ │ │ ├── esi32xx.cfg │ │ │ ├── esp32.cfg │ │ │ ├── esp32s2.cfg │ │ │ ├── esp32s3.cfg │ │ │ ├── esp_common.cfg │ │ │ ├── exynos5250.cfg │ │ │ ├── faux.cfg │ │ │ ├── feroceon.cfg │ │ │ ├── fm3.cfg │ │ │ ├── fm4.cfg │ │ │ ├── fm4_mb9bf.cfg │ │ │ ├── fm4_s6e2cc.cfg │ │ │ ├── gd32e23x.cfg │ │ │ ├── gd32vf103.cfg │ │ │ ├── gp326xxxa.cfg │ │ │ ├── hi3798.cfg │ │ │ ├── hi6220.cfg │ │ │ ├── hilscher_netx10.cfg │ │ │ ├── hilscher_netx50.cfg │ │ │ ├── hilscher_netx500.cfg │ │ │ ├── icepick.cfg │ │ │ ├── imx.cfg │ │ │ ├── imx21.cfg │ │ │ ├── imx25.cfg │ │ │ ├── imx27.cfg │ │ │ ├── imx28.cfg │ │ │ ├── imx31.cfg │ │ │ ├── imx35.cfg │ │ │ ├── imx51.cfg │ │ │ ├── imx53.cfg │ │ │ ├── imx6.cfg │ │ │ ├── imx6sx.cfg │ │ │ ├── imx6ul.cfg │ │ │ ├── imx7.cfg │ │ │ ├── imx7ulp.cfg │ │ │ ├── imx8m.cfg │ │ │ ├── imx8qm.cfg │ │ │ ├── infineon/ │ │ │ │ └── tle987x.cfg │ │ │ ├── is5114.cfg │ │ │ ├── ixp42x.cfg │ │ │ ├── k1921vk01t.cfg │ │ │ ├── k40.cfg │ │ │ ├── k60.cfg │ │ │ ├── ke0x.cfg │ │ │ ├── ke1xf.cfg │ │ │ ├── ke1xz.cfg │ │ │ ├── kl25.cfg │ │ │ ├── kl46.cfg │ │ │ ├── klx.cfg │ │ │ ├── ks869x.cfg │ │ │ ├── kx.cfg │ │ │ ├── lpc11xx.cfg │ │ │ ├── lpc12xx.cfg │ │ │ ├── lpc13xx.cfg │ │ │ ├── lpc17xx.cfg │ │ │ ├── lpc1850.cfg │ │ │ ├── lpc1xxx.cfg │ │ │ ├── lpc2103.cfg │ │ │ ├── lpc2124.cfg │ │ │ ├── lpc2129.cfg │ │ │ ├── lpc2148.cfg │ │ │ ├── lpc2294.cfg │ │ │ ├── lpc2378.cfg │ │ │ ├── lpc2460.cfg │ │ │ ├── lpc2478.cfg │ │ │ ├── lpc2900.cfg │ │ │ ├── lpc2xxx.cfg │ │ │ ├── lpc3131.cfg │ │ │ ├── lpc3250.cfg │ │ │ ├── lpc40xx.cfg │ │ │ ├── lpc4350.cfg │ │ │ ├── lpc4357.cfg │ │ │ ├── lpc4370.cfg │ │ │ ├── lpc84x.cfg │ │ │ ├── lpc8nxx.cfg │ │ │ ├── lpc8xx.cfg │ │ │ ├── ls1012a.cfg │ │ │ ├── ls1028a.cfg │ │ │ ├── ls1046a.cfg │ │ │ ├── ls1088a.cfg │ │ │ ├── lsch3_common.cfg │ │ │ ├── marvell/ │ │ │ │ ├── 88f3710.cfg │ │ │ │ ├── 88f3720.cfg │ │ │ │ └── 88f37x0.cfg │ │ │ ├── max32620.cfg │ │ │ ├── max32625.cfg │ │ │ ├── max3263x.cfg │ │ │ ├── mc13224v.cfg │ │ │ ├── mdr32f9q2i.cfg │ │ │ ├── nds32v5.cfg │ │ │ ├── ngultra.cfg │ │ │ ├── nhs31xx.cfg │ │ │ ├── npcx.cfg │ │ │ ├── nrf51.cfg │ │ │ ├── nrf52.cfg │ │ │ ├── nuc910.cfg │ │ │ ├── numicro.cfg │ │ │ ├── numicro_m4.cfg │ │ │ ├── omap2420.cfg │ │ │ ├── omap3530.cfg │ │ │ ├── omap4430.cfg │ │ │ ├── omap4460.cfg │ │ │ ├── omap5912.cfg │ │ │ ├── omapl138.cfg │ │ │ ├── or1k.cfg │ │ │ ├── pic32mx.cfg │ │ │ ├── psoc4.cfg │ │ │ ├── psoc5lp.cfg │ │ │ ├── psoc6.cfg │ │ │ ├── pxa255.cfg │ │ │ ├── pxa270.cfg │ │ │ ├── pxa3xx.cfg │ │ │ ├── qn908x.cfg │ │ │ ├── qualcomm_qca4531.cfg │ │ │ ├── quark_d20xx.cfg │ │ │ ├── quark_x10xx.cfg │ │ │ ├── readme.txt │ │ │ ├── renesas_r7s72100.cfg │ │ │ ├── renesas_rcar_gen2.cfg │ │ │ ├── renesas_rcar_gen3.cfg │ │ │ ├── renesas_rcar_reset_common.cfg │ │ │ ├── renesas_rz_five.cfg │ │ │ ├── renesas_rz_g2.cfg │ │ │ ├── renesas_s7g2.cfg │ │ │ ├── rk3308.cfg │ │ │ ├── rk3399.cfg │ │ │ ├── rp2040.cfg │ │ │ ├── rsl10.cfg │ │ │ ├── samsung_s3c2410.cfg │ │ │ ├── samsung_s3c2440.cfg │ │ │ ├── samsung_s3c2450.cfg │ │ │ ├── samsung_s3c4510.cfg │ │ │ ├── samsung_s3c6410.cfg │ │ │ ├── sharp_lh79532.cfg │ │ │ ├── sim3x.cfg │ │ │ ├── smp8634.cfg │ │ │ ├── snps_em_sk_fpga.cfg │ │ │ ├── snps_hsdk.cfg │ │ │ ├── spear3xx.cfg │ │ │ ├── stellaris.cfg │ │ │ ├── stm32c0x.cfg │ │ │ ├── stm32f0x.cfg │ │ │ ├── stm32f1x.cfg │ │ │ ├── stm32f2x.cfg │ │ │ ├── stm32f3x.cfg │ │ │ ├── stm32f4x.cfg │ │ │ ├── stm32f7x.cfg │ │ │ ├── stm32g0x.cfg │ │ │ ├── stm32g4x.cfg │ │ │ ├── stm32h7x.cfg │ │ │ ├── stm32h7x_dual_bank.cfg │ │ │ ├── stm32l0.cfg │ │ │ ├── stm32l0_dual_bank.cfg │ │ │ ├── stm32l1.cfg │ │ │ ├── stm32l1x_dual_bank.cfg │ │ │ ├── stm32l4x.cfg │ │ │ ├── stm32l5x.cfg │ │ │ ├── stm32mp13x.cfg │ │ │ ├── stm32mp15x.cfg │ │ │ ├── stm32u5x.cfg │ │ │ ├── stm32w108xx.cfg │ │ │ ├── stm32wbx.cfg │ │ │ ├── stm32wlx.cfg │ │ │ ├── stm32x5x_common.cfg │ │ │ ├── stm32xl.cfg │ │ │ ├── stm8l.cfg │ │ │ ├── stm8l151x2.cfg │ │ │ ├── stm8l151x3.cfg │ │ │ ├── stm8l152.cfg │ │ │ ├── stm8l15xx4.cfg │ │ │ ├── stm8l15xx6.cfg │ │ │ ├── stm8l15xx8.cfg │ │ │ ├── stm8s.cfg │ │ │ ├── stm8s003.cfg │ │ │ ├── stm8s103.cfg │ │ │ ├── stm8s105.cfg │ │ │ ├── str710.cfg │ │ │ ├── str730.cfg │ │ │ ├── str750.cfg │ │ │ ├── str912.cfg │ │ │ ├── swj-dp.tcl │ │ │ ├── swm050.cfg │ │ │ ├── test_reset_syntax_error.cfg │ │ │ ├── test_syntax_error.cfg │ │ │ ├── ti-ar7.cfg │ │ │ ├── ti-cjtag.cfg │ │ │ ├── ti_calypso.cfg │ │ │ ├── ti_cc13x0.cfg │ │ │ ├── ti_cc13x2.cfg │ │ │ ├── ti_cc26x0.cfg │ │ │ ├── ti_cc26x2.cfg │ │ │ ├── ti_cc3220sf.cfg │ │ │ ├── ti_cc32xx.cfg │ │ │ ├── ti_dm355.cfg │ │ │ ├── ti_dm365.cfg │ │ │ ├── ti_dm6446.cfg │ │ │ ├── ti_k3.cfg │ │ │ ├── ti_msp432.cfg │ │ │ ├── ti_rm4x.cfg │ │ │ ├── ti_tms570.cfg │ │ │ ├── ti_tms570lc43xx.cfg │ │ │ ├── ti_tms570ls20xxx.cfg │ │ │ ├── ti_tms570ls3137.cfg │ │ │ ├── tmpa900.cfg │ │ │ ├── tmpa910.cfg │ │ │ ├── tnetc4401.cfg │ │ │ ├── u8500.cfg │ │ │ ├── vd_aarch64.cfg │ │ │ ├── vd_cortex_m.cfg │ │ │ ├── vd_riscv.cfg │ │ │ ├── vybrid_vf6xx.cfg │ │ │ ├── xilinx_zynqmp.cfg │ │ │ ├── xmc1xxx.cfg │ │ │ ├── xmc4xxx.cfg │ │ │ ├── xmos_xs1-xau8a-10_arm.cfg │ │ │ ├── xtensa-core-esp32.cfg │ │ │ ├── xtensa-core-esp32s2.cfg │ │ │ ├── xtensa-core-esp32s3.cfg │ │ │ ├── xtensa-core-nxp_rt600.cfg │ │ │ ├── xtensa-core-xt8.cfg │ │ │ ├── xtensa.cfg │ │ │ ├── zynq_7000.cfg │ │ │ └── к1879xб1я.cfg │ │ ├── test/ │ │ │ ├── selftest.cfg │ │ │ └── syntax1.cfg │ │ └── tools/ │ │ ├── firmware-recovery.tcl │ │ ├── memtest.tcl │ │ └── test_cpu_speed.tcl │ ├── testing/ │ │ ├── examples/ │ │ │ ├── AT91R40008Test/ │ │ │ │ ├── inc/ │ │ │ │ │ └── typedefs.h │ │ │ │ ├── prj/ │ │ │ │ │ ├── at91r40008_reset.script │ │ │ │ │ ├── at91r40008_turtle.cfg │ │ │ │ │ ├── eclipse_ram.gdb │ │ │ │ │ └── ethernut3_ram.ld │ │ │ │ ├── src/ │ │ │ │ │ ├── crt.s │ │ │ │ │ └── main.c │ │ │ │ ├── test_ram.elf │ │ │ │ └── test_ram.hex │ │ │ ├── LPC2148Test/ │ │ │ │ ├── inc/ │ │ │ │ │ └── typedefs.h │ │ │ │ ├── prj/ │ │ │ │ │ ├── eclipse_ram.gdb │ │ │ │ │ ├── eclipse_rom.gdb │ │ │ │ │ ├── lpc2148_jtagkey.cfg │ │ │ │ │ ├── lpc2148_ram.ld │ │ │ │ │ └── lpc2148_rom.ld │ │ │ │ ├── src/ │ │ │ │ │ ├── crt.s │ │ │ │ │ └── main.c │ │ │ │ ├── test_ram.elf │ │ │ │ ├── test_ram.hex │ │ │ │ ├── test_rom.elf │ │ │ │ └── test_rom.hex │ │ │ ├── LPC2294Test/ │ │ │ │ ├── inc/ │ │ │ │ │ └── typedefs.h │ │ │ │ ├── prj/ │ │ │ │ │ ├── eclipse_ram.gdb │ │ │ │ │ ├── eclipse_rom.gdb │ │ │ │ │ ├── lpc2294_jtagkey.cfg │ │ │ │ │ ├── lpc2294_ram.ld │ │ │ │ │ └── lpc2294_rom.ld │ │ │ │ ├── src/ │ │ │ │ │ ├── crt.s │ │ │ │ │ └── main.c │ │ │ │ ├── test_ram.elf │ │ │ │ ├── test_ram.hex │ │ │ │ ├── test_rom.elf │ │ │ │ └── test_rom.hex │ │ │ ├── PIC32/ │ │ │ │ ├── BlinkingLeds.c │ │ │ │ ├── BlinkingLeds.elf │ │ │ │ └── readme.txt │ │ │ ├── SAM7S256Test/ │ │ │ │ ├── inc/ │ │ │ │ │ └── typedefs.h │ │ │ │ ├── prj/ │ │ │ │ │ ├── eclipse_ram.gdb │ │ │ │ │ ├── eclipse_rom.gdb │ │ │ │ │ ├── sam7s256_jtagkey.cfg │ │ │ │ │ ├── sam7s256_ram.ld │ │ │ │ │ ├── sam7s256_reset.script │ │ │ │ │ └── sam7s256_rom.ld │ │ │ │ ├── results/ │ │ │ │ │ └── 607.html │ │ │ │ ├── src/ │ │ │ │ │ ├── crt.s │ │ │ │ │ └── main.c │ │ │ │ ├── test_ram.elf │ │ │ │ ├── test_ram.hex │ │ │ │ ├── test_rom.elf │ │ │ │ └── test_rom.hex │ │ │ ├── SAM7X256Test/ │ │ │ │ ├── inc/ │ │ │ │ │ └── typedefs.h │ │ │ │ ├── prj/ │ │ │ │ │ ├── eclipse_ram.gdb │ │ │ │ │ ├── eclipse_rom.gdb │ │ │ │ │ ├── sam7x256_jtagkey.cfg │ │ │ │ │ ├── sam7x256_ram.ld │ │ │ │ │ ├── sam7x256_reset.script │ │ │ │ │ └── sam7x256_rom.ld │ │ │ │ ├── src/ │ │ │ │ │ ├── crt.s │ │ │ │ │ └── main.c │ │ │ │ ├── test_ram.elf │ │ │ │ ├── test_ram.hex │ │ │ │ ├── test_rom.elf │ │ │ │ └── test_rom.hex │ │ │ ├── STM32-103/ │ │ │ │ ├── main.elf │ │ │ │ └── readme.txt │ │ │ ├── STR710JtagSpeed/ │ │ │ │ ├── inc/ │ │ │ │ │ └── typedefs.h │ │ │ │ ├── prj/ │ │ │ │ │ ├── eclipse_ft2232_ram.gdb │ │ │ │ │ ├── str710_jtagkey.cfg │ │ │ │ │ └── str7_ram.ld │ │ │ │ ├── src/ │ │ │ │ │ ├── crt.s │ │ │ │ │ └── main.c │ │ │ │ ├── test.elf │ │ │ │ └── test.hex │ │ │ ├── STR710Test/ │ │ │ │ ├── .gitignore │ │ │ │ ├── inc/ │ │ │ │ │ └── typedefs.h │ │ │ │ ├── prj/ │ │ │ │ │ ├── eclipse_ram.gdb │ │ │ │ │ ├── eclipse_rom.gdb │ │ │ │ │ ├── hitex_str7_ram.ld │ │ │ │ │ ├── hitex_str7_rom.ld │ │ │ │ │ ├── str710_jtagkey.cfg │ │ │ │ │ └── str710_program.script │ │ │ │ ├── src/ │ │ │ │ │ ├── crt.s │ │ │ │ │ └── main.c │ │ │ │ ├── test_ram.elf │ │ │ │ ├── test_ram.hex │ │ │ │ ├── test_rom.elf │ │ │ │ └── test_rom.hex │ │ │ ├── STR912Test/ │ │ │ │ ├── inc/ │ │ │ │ │ └── typedefs.h │ │ │ │ ├── prj/ │ │ │ │ │ ├── eclipse_ram.gdb │ │ │ │ │ ├── eclipse_rom.gdb │ │ │ │ │ ├── str912_jtagkey.cfg │ │ │ │ │ ├── str912_program.script │ │ │ │ │ ├── str912_ram.ld │ │ │ │ │ └── str912_rom.ld │ │ │ │ ├── src/ │ │ │ │ │ ├── main.c │ │ │ │ │ └── startup.s │ │ │ │ ├── test_ram.elf │ │ │ │ ├── test_ram.hex │ │ │ │ ├── test_rom.elf │ │ │ │ └── test_rom.hex │ │ │ ├── cortex/ │ │ │ │ ├── cm3-ftest.cfg │ │ │ │ ├── fault.c │ │ │ │ ├── lm3s3748.elf │ │ │ │ ├── test.c │ │ │ │ └── test.ld │ │ │ ├── ledtest-imx27ads/ │ │ │ │ ├── crt0.S │ │ │ │ ├── gdbinit-imx27ads │ │ │ │ ├── ldscript │ │ │ │ ├── test.c │ │ │ │ └── test.elf │ │ │ └── ledtest-imx31pdk/ │ │ │ ├── crt0.S │ │ │ ├── gdbinit-imx31pdk │ │ │ ├── ldscript │ │ │ ├── test.c │ │ │ └── test.elf │ │ ├── index.html │ │ ├── profile_stm32.txt │ │ ├── results/ │ │ │ ├── template.html │ │ │ └── v0.4.0-rc1/ │ │ │ ├── AT91FR40162.html │ │ │ ├── LPC2148.html │ │ │ ├── SAM7.html │ │ │ ├── STR710.html │ │ │ └── STR912.html │ │ ├── smoketests.html │ │ ├── tcl_server.tcl │ │ ├── tcl_test.tcl │ │ ├── test-am335xgpio-deprecated-commands.cfg │ │ ├── test-bcm2835gpio-deprecated-commands.cfg │ │ ├── test-linuxgpiod-deprecated-commands.cfg │ │ └── testcases.html │ ├── tools/ │ │ ├── checkpatch.sh │ │ ├── disassemble_inc.sh │ │ ├── initial.sh │ │ ├── logger.pl │ │ ├── release/ │ │ │ ├── helpers.sh │ │ │ ├── test.sh │ │ │ └── version.sh │ │ ├── release.sh │ │ ├── rlink_make_speed_table/ │ │ │ ├── rlink_make_speed_table │ │ │ └── rlink_make_speed_table.pl │ │ ├── scripts/ │ │ │ ├── camelcase.txt │ │ │ ├── checkpatch.pl │ │ │ ├── const_structs.checkpatch │ │ │ ├── spdxcheck.py │ │ │ ├── spdxexclude │ │ │ ├── spelling.txt │ │ │ └── typedefs.txt │ │ ├── st7_dtc_as/ │ │ │ ├── st7_dtc_as │ │ │ └── st7_dtc_as.pl │ │ └── uncrustify1.sh │ └── uncrustify.cfg └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: CN/README-old-2.md ================================================ # **完整设备仿真定制固件开发指南** --- ## **目录** ### **第1部分:基础概念** 1. [介绍](#1-介绍) - [1.1 本指南的目的](#11-本指南的目的) - [1.2 目标受众](#12-目标受众) - [1.3 如何使用本指南](#13-如何使用本指南) 2. [关键定义](#2-关键定义) 3. [设备兼容性](#3-设备兼容性) - [3.1 支持的基于FPGA的硬件](#31-支持的基于fpga的硬件) - [3.2 PCIe硬件注意事项](#32-pcie硬件注意事项) - [3.3 系统要求](#33-系统要求) 4. [要求](#4-要求) - [4.1 硬件](#41-硬件) - [4.2 软件](#42-软件) - [4.3 环境设置](#43-环境设置) 5. [收集捐赠设备信息](#5-收集捐赠设备信息) - [5.1 使用Arbor进行PCIe设备扫描](#51-使用arbor进行pcie设备扫描) - [5.2 提取和记录设备属性](#52-提取和记录设备属性) 6. [初始固件定制](#6-初始固件定制) - [6.1 修改配置空间](#61-修改配置空间) - [6.2 插入设备序列号(DSN)](#62-插入设备序列号dsn) 7. [Vivado项目设置和定制](#7-vivado项目设置和定制) - [7.1 生成Vivado项目文件](#71-生成vivado项目文件) - [7.2 修改IP模块](#72-修改ip模块) ### **第2部分:中级概念与实现** 8. [高级固件定制](#8-高级固件定制) - [8.1 为仿真配置PCIe参数](#81-为仿真配置pcie参数) - [8.2 调整BAR和内存映射](#82-调整bar和内存映射) - [8.3 仿真设备电源管理和中断](#83-仿真设备电源管理和中断) 9. [仿真设备特定功能](#9-仿真设备特定功能) - [9.1 实现高级PCIe功能](#91-实现高级pcie功能) - [9.2 仿真供应商特定特性](#92-仿真供应商特定特性) 10. [事务层数据包(TLP)仿真](#10-事务层数据包tlp仿真) - [10.1 理解和捕获TLP](#101-理解和捕获tlp) - [10.2 为特定操作制作自定义TLP](#102-为特定操作制作自定义tlp) ### **第3部分:高级技术与优化** 11. [构建、烧录和测试](#11-构建烧录和测试) - [11.1 综合与实现](#111-综合与实现) - [11.2 烧录比特流](#112-烧录比特流) - [11.3 测试与验证](#113-测试与验证) 12. [高级调试技术](#12-高级调试技术) - [12.1 使用Vivado的集成逻辑分析器](#121-使用vivado的集成逻辑分析器) - [12.2 PCIe流量分析工具](#122-pcie流量分析工具) 13. [故障排除](#13-故障排除) - [13.1 设备检测问题](#131-设备检测问题) - [13.2 内存映射和BAR配置错误](#132-内存映射和bar配置错误) - [13.3 DMA性能和TLP错误](#133-dma性能和tlp错误) 14. [仿真准确性和优化](#14-仿真准确性和优化) - [14.1 精确计时仿真技术](#141-精确计时仿真技术) - [14.2 对系统调用的动态响应](#142-对系统调用的动态响应) 15. [固件开发最佳实践](#15-固件开发最佳实践) - [15.1 持续测试和文档编制](#151-持续测试和文档编制) - [15.2 管理固件版本](#152-管理固件版本) - [15.3 安全考虑](#153-安全考虑) 16. [其他资源](#16-其他资源) 17. [联系信息](#17-联系信息) 18. [支持与贡献](#18-支持与贡献) --- ## **前言** 对于那些想要学习的人,你们选择了真正启迪的道路。你们用本指南所构建的东西将超越这些人能想象的一切。你们正在走向卓越,我们将一起超越他们所建立的失败。 --- ## **第1部分:基础概念** --- ## **1. 介绍** ### **1.1 本指南的目的** 本指南的主要目的是提供一种分步方法,开发用于基于FPGA设备的自定义直接内存访问(DMA)固件,以准确仿真PCIe硬件。这使得能够实现硬件测试、系统调试、安全研究和硬件仿真等应用。 通过遵循本指南,您将学习如何: - 从捐赠设备收集必要信息。 - 定制固件以仿真特定的硬件设备。 - 使用Vivado和Visual Studio Code等工具设置开发环境。 - 了解与PCIe和DMA操作相关的关键概念。 ### **1.2 目标受众** 本指南适用于: - **固件开发人员**:对创建用于硬件仿真、测试或绕过硬件限制的自定义固件感兴趣的工程师。 - **硬件工程师**:需要仿真特定设备进行硬件测试和开发的专业人员。 - **安全研究人员**:进行漏洞评估、恶意软件分析或需要硬件仿真的安全测试的个人。 - **FPGA爱好者**:对FPGA定制和低级硬件仿真感兴趣的爱好者和学习者。 ### **1.3 如何使用本指南** 本指南分为三个部分: - **第1部分:基础概念**:涵盖开始设备仿真所需的基本概念、设置和初始步骤的固件开发。 - **第2部分:中级概念与实现**:深入讨论更复杂的主题,如高级固件定制、TLP仿真和初始调试技术。 - **第3部分:高级技术与优化**:探索高级调试、故障排除、优化策略和最佳实践。 建议按照指南的顺序进行,以建立牢固的理解,然后再处理高级主题。 --- ## **2. 关键定义** 理解术语对于有效地遵循本指南至关重要。以下是与PCIe、DMA和设备仿真相关的关键定义: - **DMA(直接内存访问)**:一种允许硬件设备直接从系统内存读取或写入数据的功能,无需CPU干预,实现高速数据传输。 - **TLP(事务层数据包)**:PCIe架构中的基本通信单位,封装控制和数据信息。 - **BAR(基地址寄存器)**:PCIe设备中的寄存器,定义内存和I/O地址区域,将设备内存映射到系统内存空间。 - **FPGA(现场可编程门阵列)**:一种可重配置的集成电路,可编程以执行特定的硬件功能。 - **MSI/MSI-X(消息信号中断)**:PCIe设备用于向CPU发送中断的机制,无需使用传统的中断线。 - **设备序列号(DSN)**:与特定设备关联的唯一标识符,通常用于高级设备识别。 - **PCIe配置空间**:标准化的内存区域,PCIe设备在其中提供关于自身的信息并配置操作参数。 - **捐赠设备**:用于提取配置和识别详细信息以在FPGA上仿真其行为的PCIe硬件设备。 --- ## **3. 设备兼容性** ### **3.1 支持的基于FPGA的硬件** 虽然本指南主要关注**Squirrel DMA(35T)**卡,因为它易于获取,但这些方法也可适用于其他基于FPGA的DMA硬件: - **Squirrel(35T)** - **描述**:经济实惠的基于FPGA的DMA设备,适用于标准内存获取和设备仿真。 - **Enigma-X1(75T)** - **描述**:中端FPGA,提供增强的资源,适合更高要求的内存操作。 - **ZDMA(100T)** - **描述**:高性能FPGA,针对快速内存交互进行了优化,适用于广泛的内存读/写。 - **Kintex-7** - **描述**:高级FPGA,具有强大的功能,适用于复杂项目和大规模DMA解决方案。 ### **3.2 PCIe硬件注意事项** 为了确保平滑的仿真,必须解决多个PCIe特定功能: - **IOMMU/VT-d设置** - **建议**:禁用IOMMU(Intel的VT-d)或AMD的等效功能,以允许不受限制的DMA访问。 - **理由**:IOMMU可能会限制DMA操作,可能会干扰内存获取和仿真。 - **内核DMA保护** - **建议**:在现代系统中禁用内核DMA保护功能。 - **步骤**: - **Windows**:在BIOS/UEFI设置中禁用安全启动或基于虚拟化的安全性(VBS)等功能。 - **注意**:禁用这些功能可能会使系统暴露于安全风险中;确保您在安全的环境中操作。 - **PCIe插槽要求** - **建议**:使用与FPGA设备要求匹配的兼容PCIe插槽(例如,x1、x4)。 - **理由**:确保与主机系统的最佳性能和兼容性。 ### **3.3 系统要求** - **主机系统** - **处理器**:多核CPU(Intel i5/i7或AMD等效) - **内存**:至少16 GB RAM - **存储**:至少有100 GB可用空间的SSD - **操作系统**:Windows 10/11(64位)或兼容的Linux发行版 - **外围设备** - **JTAG编程器**:用于将固件烧录到FPGA - **PCIe插槽**:确保主机系统有一个兼容DMA卡的可用PCIe插槽 --- ## **4. 要求** ### **4.1 硬件** - **捐赠PCIe设备** - **目的**:用于仿真提取设备ID和配置数据的来源。 - **示例**:网络适配器、存储控制器或任何未使用的通用PCIe卡。 - **DMA FPGA卡** - **描述**:能够执行DMA操作的基于FPGA的设备。 - **示例**:Squirrel(35T)、Enigma-X1(75T)、ZDMA(100T)、Kintex-7 - **JTAG编程器** - **目的**:用于将固件烧录到FPGA上。 - **示例**:Xilinx Platform Cable USB II、Digilent JTAG-HS3 ### **4.2 软件** - **Xilinx Vivado设计套件** - **描述**:用于综合和构建固件项目的FPGA开发软件。 - **下载**:[Xilinx Vivado](https://www.xilinx.com/support/download.html) - **Visual Studio Code** - **描述**:用于编辑Verilog或VHDL代码的代码编辑器。 - **下载**:[Visual Studio Code](https://code.visualstudio.com/) - **PCILeech-FPGA** - **描述**:用于DMA固件开发的代码库和基础代码。 - **代码库**:[PCILeech-FPGA在GitHub上](https://github.com/ufrisk/pcileech-fpga) - **Arbor** - **描述**:用于收集设备信息的PCIe设备扫描工具。 - **下载**:[Arbor by MindShare](https://www.mindshare.com/software/Arbor) - **注意**:需要创建账户;提供14天试用。 - **替代工具** - **Telescan PE** - **描述**:作为Arbor替代的PCIe流量分析工具。 - **下载**:[Teledyne LeCroy Telescan PE](https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software) - **注意**:免费但需要手动注册批准。 ### **4.3 环境设置** #### **4.3.1 安装Xilinx Vivado设计套件** - **步骤**: 1. 访问[Xilinx Vivado下载页面](https://www.xilinx.com/support/download.html)。 2. 下载与您的FPGA设备兼容的适当版本。 3. 运行安装程序并按照屏幕指示进行操作。 4. 在安装过程中选择必要的组件。 5. 启动Vivado以确保正确安装。 #### **4.3.2 安装Visual Studio Code** - **步骤**: 1. 访问[Visual Studio Code下载页面](https://code.visualstudio.com/)。 2. 下载并安装适用于您的操作系统的版本。 3. 安装支持Verilog或VHDL的扩展(例如,**Verilog-HDL/SystemVerilog**)。 #### **4.3.3 克隆PCILeech-FPGA代码库** - **步骤**: 1. 打开终端或命令提示符。 2. 导航到您想要的目录: ```bash cd ~/Projects/ ``` 3. 克隆代码库: ```bash git clone https://github.com/ufrisk/pcileech-fpga.git ``` 4. 进入克隆的目录: ```bash cd pcileech-fpga ``` #### **4.3.4 设置干净的开发环境** - **建议**:在隔离的环境中工作,以防止意外的交互。 - **步骤**: 1. 使用专用的开发机器或虚拟机。 2. 确保没有其他应用程序干扰PCIe操作或FPGA编程。 --- ## **5. 收集捐赠设备信息** 准确的设备仿真依赖于仔细提取并复制捐赠设备的关键信息。全面的数据收集使您的FPGA能够忠实地模仿目标硬件的PCIe配置和行为,确保与主机系统的兼容性和功能。 ### **5.1 使用Arbor进行PCIe设备扫描** **Arbor**是一款功能强大且用户友好的工具,专为深入扫描PCIe设备而设计。它提供了连接硬件的配置空间的详细见解,使其成为提取设备仿真所需信息的宝贵资源。 #### **5.1.1 安装Arbor** 要开始使用Arbor进行设备扫描,您必须首先在系统上安装该软件。 **步骤**: 1. **访问Arbor下载页面**: - 使用您的首选浏览器,导航到官方[Arbor下载页面](https://www.mindshare.com/software/Arbor)。 - 确保您直接访问该网站,以避免任何恶意重定向。 2. **创建账户(如果需要)**: - Arbor可能需要您创建用户账户以访问下载链接。 - 提供必要的信息,例如您的姓名、电子邮件地址和组织。 - 如果提示,请验证您的电子邮件以激活账户。 3. **下载Arbor**: - 登录后,找到Arbor的下载部分。 - 选择与您的操作系统兼容的版本(例如,Windows 10/11 64位)。 - 点击**下载**按钮,将安装程序保存到计算机上的已知位置。 4. **安装Arbor**: - 找到下载的安装程序文件(例如,`ArborSetup.exe`)。 - 右键单击安装程序,选择**以管理员身份运行**,以确保其具有必要的权限。 - 按照屏幕上的指示完成安装过程。 - 接受许可协议。 - 选择安装目录。 - 如果需要,可选择创建桌面快捷方式。 5. **验证安装**: - 完成后,确保Arbor列在您的开始菜单或桌面上。 - 启动Arbor,确认其无错误打开。 #### **5.1.2 扫描PCIe设备** 安装Arbor后,您可以继续扫描系统中连接的PCIe设备。 **步骤**: 1. **启动Arbor**: - 双击桌面上的Arbor图标,或通过开始菜单找到它。 - 如果用户帐户控制(UAC)提示,请允许应用程序对您的设备进行更改。 2. **导航到本地系统选项卡**: - 在Arbor界面中,找到导航窗格或选项卡。 - 点击**Local System**以访问扫描本地计算机的工具。 3. **扫描PCIe设备**: - 找到通常位于界面顶部或底部的**Scan**或**Rescan**按钮。 - 点击**Scan/Rescan**以启动检测过程。 - 等待扫描过程完成;根据连接的设备数量,这可能需要一些时间。 4. **查看检测到的设备**: - 扫描完成后,Arbor将显示所有检测到的PCIe设备列表。 - 设备通常以其名称、设备ID和其他识别信息列出。 #### **5.1.3 识别捐赠设备** 正确识别捐赠设备对于准确的仿真至关重要。 **步骤**: 1. **在列表中找到您的捐赠设备**: - 滚动浏览Arbor检测到的设备列表。 - 查找与您的捐赠硬件型号匹配的设备。 - 设备可能按供应商名称、设备类型或功能列出。 2. **验证设备详细信息**: - 点击设备以选择它。 - 确认**设备ID**和**供应商ID**与您的捐赠设备匹配。 - **提示**:这些ID通常可以在设备的文档或制造商的网站上找到。 3. **查看详细配置**: - 选择设备后,找到并点击**查看详细信息**或**属性**等选项。 - 这将打开一个详细视图,显示设备的配置空间和功能。 4. **与物理硬件进行交叉引用**: - 如果列出了多个类似的设备,请将**插槽编号**或**总线地址**与安装捐赠设备的物理插槽进行比较。 #### **5.1.4 捕获设备数据** 从捐赠设备中提取详细信息对于准确的仿真至关重要。 **要提取的信息**: - **设备ID(0xXXXX)**: - 一个唯一的16位设备型号标识符。 - **供应商ID(0xYYYY)**: - 分配给制造商的16位标识符。 - **子系统ID(0xZZZZ)**: - 标识特定的子系统或变体。 - **子系统供应商ID(0xWWWW)**: - 标识子系统的供应商。 - **修订ID(0xRR)**: - 指示设备的修订级别。 - **类代码(0xCCCCCC)**: - 定义设备类型的24位代码(例如,网络控制器、存储设备)。 - **基地址寄存器(BARs)**: - 定义设备使用的内存或I/O空间的寄存器。 - 包括BAR0到BAR5,每个可能为32位或64位。 - **功能**: - 列出支持的功能,如MSI/MSI-X、电源管理、PCIe链路速度和宽度。 - **设备序列号(DSN)**: - 如果设备支持,则为64位唯一标识符。 **步骤**: 1. **导航到PCI配置选项卡**: - 在设备的详细视图中,找到并选择**PCI Config**或**Configuration Space**选项卡。 2. **记录相关细节**: - 仔细记录每个所需的字段。 - 为了准确性,可以使用截图或将值复制到文本文件或电子表格中。 - 确保十六进制值记录正确,包括`0x`前缀(如果使用)。 3. **展开功能列表**: - 查找标记为**Capabilities**或**Advanced Features**的部分。 - 记录每个功能及其参数(例如,MSI数量、支持的电源状态)。 4. **详细检查BARs**: - 对于每个BAR,注意: - **BAR编号(例如,BAR0)**: - **类型(内存或I/O)**: - **位宽(32位或64位)**: - **大小(例如,256 MB)**: - **可预取状态(是/否)**: 5. **保存数据以供参考**: - 将所有信息编入组织良好的文档中。 - 清晰地标记每个部分,便于在固件定制期间参考。 6. **仔细检查条目**: - 重新检查所有记录的数据以确保准确性。 - 通过重新访问Arbor界面,纠正任何差异。 ### **5.2 提取和记录设备属性** 在捕获数据后,理解每个属性的意义并确保其已被准确记录至关重要。 **确保您已准确记录以下内容**: 1. **设备ID**: - **目的**:唯一标识设备型号。 - **用途**:对于主机操作系统加载正确的驱动程序至关重要。 2. **供应商ID**: - **目的**:标识制造商。 - **用途**:与设备ID一起用于匹配设备驱动程序。 3. **子系统ID和子系统供应商ID**: - **目的**:指定子系统的设备和供应商ID,允许区分变体。 - **用途**:对于具有多种配置或OEM特定版本的设备很重要。 4. **修订ID**: - **目的**:指示硬件修订版本。 - **用途**:有助于识别可能需要不同驱动程序或固件的特定硬件版本。 5. **类代码**: - **目的**:对设备类型进行分类(例如,大容量存储、网络控制器)。 - **用途**:允许操作系统了解设备的主要功能。 6. **基地址寄存器(BARs)**: - **目的**:定义设备将使用的内存或I/O地址区域。 - **用途**:对于将设备内存映射到系统地址空间至关重要。 7. **功能**: - **目的**:列出设备支持的高级功能。 - **示例**: - **MSI/MSI-X**:用于高效中断处理的消息信号中断。 - **电源管理**:如D0、D1、D2、D3hot、D3cold状态。 - **PCIe链路速度/宽度**:确定数据传输能力。 8. **设备序列号(DSN)**: - **目的**:设备的唯一64位标识符。 - **用途**:用于高级识别,可能是某些驱动程序所必需的。 **最佳实践**: - **组织数据**: - 创建一个结构化的文档或电子表格。 - 使用清晰的标题和子标题标记每个属性。 - **包括单位和格式**: - 指明大小的单位(例如,MB、KB)。 - 对十六进制值使用一致的格式(例如,`0x1234`)。 - **与规格交叉引用**: - 如果可用,请查阅设备的数据表以验证值。 - 这有助于识别任何差异或不寻常的配置。 - **保护数据**: - 安全地存储收集的信息。 - 注意任何专有或机密信息。 --- ## **6. 初始固件定制** 在详细记录了捐赠设备的信息后,下一步是定制您的FPGA固件,以准确仿真捐赠设备。这涉及修改PCIe配置空间,并确保内存映射正确对齐。 ### **6.1 修改配置空间** PCIe配置空间是定义设备如何被识别和与主机系统交互的关键组件。将此空间定制为匹配捐赠设备对于成功的仿真至关重要。 #### **6.1.1 导航到配置文件** 配置空间在您的项目中定义在特定的SystemVerilog(.sv)文件中。 **路径**: - **标准路径**: ``` pcileech-fpga/pcileech-wifi-main/src/pcileech_pcie_cfg_a7.sv ``` - **备用路径(取决于目录结构)**: ``` pcileech-fpga/src/pcileech_pcie_cfg_a7.sv ``` **注意**: - 确保您位于正确的项目目录中。 - 文件名可能会根据FPGA型号略有变化(例如,`_a7`表示Artix-7系列)。 #### **6.1.2 在Visual Studio Code中打开文件** 编辑配置文件需要一个支持SystemVerilog语法高亮的合适代码编辑器。 **步骤**: 1. **启动Visual Studio Code**: - 点击VS Code图标,或通过开始菜单找到它。 2. **打开文件**: - 使用**文件 > 打开文件**,或按`Ctrl + O`。 - 导航到上述的配置文件路径。 - 选择`pcileech_pcie_cfg_a7.sv`,然后点击**打开**。 3. **验证语法高亮**: - 确保编辑器识别`.sv`文件扩展名。 - 如果需要,安装支持SystemVerilog的扩展。 4. **熟悉文件结构**: - 滚动浏览文件,了解现有的赋值和注释。 - 查找定义配置寄存器的部分。 #### **6.1.3 修改设备ID和供应商ID** 更新这些标识符对于主机系统将仿真设备识别为捐赠设备至关重要。 **步骤**: 1. **搜索`cfg_deviceid`**: - 使用搜索功能(`Ctrl + F`)。 - 找到定义`cfg_deviceid`的行。 2. **更新设备ID**: ```verilog cfg_deviceid <= 16'hXXXX; // 用捐赠设备的设备ID替换XXXX ``` - **示例**: - 如果捐赠设备的设备ID是`0x1234`,则更新为: ```verilog cfg_deviceid <= 16'h1234; ``` 3. **搜索`cfg_vendorid`**: - 找到定义`cfg_vendorid`的行。 4. **更新供应商ID**: ```verilog cfg_vendorid <= 16'hYYYY; // 用捐赠设备的供应商ID替换YYYY ``` - **示例**: - 如果捐赠设备的供应商ID是`0xABCD`,则更新为: ```verilog cfg_vendorid <= 16'hABCD; ``` 5. **确保正确的格式**: - 确认十六进制值以`16'h`为前缀。 - 保持一致的缩进和注释风格。 #### **6.1.4 修改子系统ID和修订ID** 这些标识符提供有关设备变体和硬件修订的其他详细信息。 **步骤**: 1. **搜索`cfg_subsysid`**: - 找到定义`cfg_subsysid`的行。 2. **更新子系统ID**: ```verilog cfg_subsysid <= 16'hZZZZ; // 用捐赠设备的子系统ID替换ZZZZ ``` - **示例**: - 如果捐赠设备的子系统ID是`0x5678`,则更新为: ```verilog cfg_subsysid <= 16'h5678; ``` 3. **搜索`cfg_subsysvendorid`**: - 找到定义`cfg_subsysvendorid`的行。 4. **更新子系统供应商ID(如果适用)**: ```verilog cfg_subsysvendorid <= 16'hWWWW; // 用捐赠设备的子系统供应商ID替换WWWW ``` - **示例**: - 如果捐赠设备的子系统供应商ID是`0x9ABC`,则更新为: ```verilog cfg_subsysvendorid <= 16'h9ABC; ``` 5. **搜索`cfg_revisionid`**: - 找到定义`cfg_revisionid`的行。 6. **更新修订ID**: ```verilog cfg_revisionid <= 8'hRR; // 用捐赠设备的修订ID替换RR ``` - **示例**: - 如果捐赠设备的修订ID是`0x01`,则更新为: ```verilog cfg_revisionid <= 8'h01; ``` #### **6.1.5 更新类代码** 类代码告知主机设备的类型和功能。 **步骤**: 1. **搜索`cfg_classcode`**: - 找到定义`cfg_classcode`的行。 2. **更新类代码**: ```verilog cfg_classcode <= 24'hCCCCCC; // 用捐赠设备的类代码替换CCCCCC ``` - **示例**: - 如果捐赠设备的类代码是`0x020000`(以太网控制器),则更新为: ```verilog cfg_classcode <= 24'h020000; ``` 3. **验证正确的位宽**: - 确保类代码是24位值。 - 十六进制值应以`24'h`为前缀。 #### **6.1.6 保存更改** 在进行所有修改后,保存并查看更改非常重要。 **步骤**: 1. **保存文件**: - 点击**文件 > 保存**,或按`Ctrl + S`。 2. **查看更改**: - 重新阅读修改的行以确认准确性。 - 检查是否有任何语法错误或拼写错误。 3. **可选 - 使用版本控制**: - 如果使用Git或其他版本控制系统,用有意义的消息提交您的更改。 - **示例**: ``` git add pcileech_pcie_cfg_a7.sv git commit -m "更新PCIe配置,包含捐赠设备标识符" ``` ### **6.2 插入设备序列号(DSN)** 设备序列号(DSN)是某些设备用于高级功能的唯一标识符。包括它可增强仿真的真实性。 #### **6.2.1 找到DSN字段** DSN通常在同一配置文件中定义。 **步骤**: 1. **搜索`cfg_dsn`**: - 在`pcileech_pcie_cfg_a7.sv`中,使用搜索功能(`Ctrl + F`)查找`cfg_dsn`。 2. **了解现有赋值**: - DSN可能设置为默认值或清零。 ```verilog cfg_dsn <= 64'h0000000000000000; // 默认DSN ``` #### **6.2.2 插入DSN** 更新DSN涉及将其设置为捐赠设备的确切值。 **步骤**: 1. **更新`cfg_dsn`**: ```verilog cfg_dsn <= 64'hXXXXXXXX_YYYYYYYY; // 用捐赠设备的DSN替换 ``` - **示例**: - 如果捐赠设备的DSN是`0x0011223344556677`,则更新为: ```verilog cfg_dsn <= 64'h0011223344556677; ``` 2. **处理DSN不可用的情况**: - 如果捐赠设备没有DSN或不需要DSN,将其设置为零: ```verilog cfg_dsn <= 64'h0000000000000000; // 无DSN ``` 3. **确保正确的格式**: - DSN是一个64位值;确保其格式正确。 - 对十六进制值使用`64'h`前缀。 4. **添加注释以增加清晰度**: - 包括一条注释,指明DSN的来源。 ```verilog cfg_dsn <= 64'h0011223344556677; // 捐赠设备的DSN ``` #### **6.2.3 保存更改** 通过保存和查看,完成修改。 **步骤**: 1. **保存文件**: - 点击**文件 > 保存**,或按`Ctrl + S`。 2. **验证语法**: - 查找编辑器中的任何红色下划线或错误指示。 - 在继续之前,纠正任何问题。 3. **记录更改**: - 如果使用版本控制,请用适当的消息提交更新。 - **示例**: ``` git commit -am "在配置中插入捐赠设备的序列号(DSN)" ``` --- ## **7. Vivado项目设置和定制** 在将固件文件更新为反映捐赠设备的配置后,下一步是将这些更改集成到Vivado项目中。这涉及生成项目文件、定制IP核,并为综合和实现准备设计。 ### **7.1 生成Vivado项目文件** Vivado使用Tcl脚本自动创建和配置项目。通过运行这些脚本,您可以确保所有设置都根据您的FPGA设备正确应用。 #### **7.1.1 打开Vivado** 从一个新的Vivado会话开始,确保先前的设置或项目不会干扰您当前的工作。 **步骤**: 1. **启动Vivado**: - 在开始菜单或桌面上找到Vivado应用程序。 - 点击打开它。 2. **选择正确的版本**: - 如果安装了多个版本,确保您使用的版本与您的FPGA兼容(例如,Vivado 2020.1)。 3. **等待启动屏幕**: - 允许Vivado完全初始化,然后再继续。 #### **7.1.2 访问Tcl控制台** Tcl控制台允许您直接执行脚本和命令。 **步骤**: 1. **打开Tcl控制台**: - 在Vivado界面中,转到菜单栏。 - 点击**窗口** > **Tcl控制台**。 - Tcl控制台将出现在窗口底部。 2. **调整控制台大小(可选)**: - 拖动控制台的顶部边框,以调整其大小,便于查看。 3. **清除先前的命令**: - 如果存在任何命令,您可以清除它们,以便干净地开始。 #### **7.1.3 导航到项目目录** 确保Tcl控制台指向您的项目脚本所在的正确目录。 **对于Squirrel DMA(35T)**: **路径**: - 您的项目目录,通常是: ``` C:/Users/YourUsername/Documents/pcileech-fpga/pcileech-wifi-main/ ``` **步骤**: 1. **设置工作目录**: - 在Tcl控制台中输入: ```tcl cd C:/Users/YourUsername/Documents/pcileech-fpga/pcileech-wifi-main/ ``` - 用您系统上的实际位置替换路径。 2. **验证目录更改**: - 在Tcl控制台中输入`pwd`。 - 控制台应显示当前目录,确认更改。 #### **7.1.4 生成Vivado项目** 运行适当的Tcl脚本将设置项目,包含所有必要的配置。 **步骤**: 1. **运行Tcl脚本**: - 对于**Squirrel(35T)**: ```tcl source vivado_generate_project_squirrel.tcl -notrace ``` - 对于**Enigma-X1(75T)**: ```tcl source vivado_generate_project_enigma_x1.tcl -notrace ``` - 对于**ZDMA(100T)**: ```tcl source vivado_generate_project_100t.tcl -notrace ``` 2. **等待脚本完成**: - 该脚本将执行多个命令: - 创建项目。 - 添加源文件。 - 配置项目设置。 - 监视Tcl控制台的进度消息。 - 解决可能出现的任何错误,例如缺少文件或路径不正确。 3. **确认项目生成**: - 完成后,控制台将指示项目已创建。 - 项目文件(`.xpr`和相关目录)将出现在项目目录中。 #### **7.1.5 打开生成的项目** 现在项目已生成,您可以在Vivado中打开它以进行进一步的定制。 **步骤**: 1. **打开项目**: - 在Vivado中,点击**文件** > **打开项目**。 - 导航到您的项目目录。 2. **选择项目文件**: - 对于**Squirrel**: ``` pcileech_squirrel_top.xpr ``` - 点击`.xpr`文件以选择它。 3. **点击打开**: - Vivado将加载项目,显示设计层次结构和源文件。 4. **验证项目内容**: - 在**项目管理器**窗口中,确保所有源文件都列出。 - 检查打开时是否有任何警告或错误。 ### **7.2 修改IP模块** PCIe IP核是一个关键组件,必须配置以匹配捐赠设备的规格。定制IP核可确保FPGA在PCIe协议级别与捐赠硬件的行为相同。 #### **7.2.1 访问PCIe IP核** PCIe IP核是在您的Vivado项目中实例化的IP模块。 **步骤**: 1. **找到PCIe IP核**: - 在**源文件**窗格中,确保选择了**层次结构**选项卡。 - 展开设计层次结构,找到PCIe IP核。 - 通常命名为`pcie_7x_0.xci`或类似名称。 2. **打开IP定制窗口**: - 右键点击`pcie_7x_0.xci`。 - 从上下文菜单中选择**定制IP**。 - **IP配置**窗口将打开。 3. **等待IP设置加载**: - IP定制界面可能需要一些时间初始化。 - 在继续之前,确保所有选项和选项卡都已完全加载。 #### **7.2.2 定制设备ID和BARs** 在IP核中配置设备标识符对于主机系统正确枚举设备至关重要。 **步骤**: 1. **导航到设备和供应商标识符**: - 在IP定制窗口中,选择**设备和供应商标识符**选项卡或部分。 2. **输入设备ID**: - 找到标记为**Device ID**的字段。 - 输入捐赠设备的设备ID(例如,`0x1234`)。 3. **输入供应商ID**: - 找到**Vendor ID**字段。 - 输入捐赠设备的供应商ID(例如,`0xABCD`)。 4. **输入子系统ID和子系统供应商ID**: - 输入**Subsystem ID**(例如,`0x5678`)。 - 输入**Subsystem Vendor ID**(例如,`0x9ABC`)。 5. **设置修订ID**: - 输入**Revision ID**(例如,`0x01`)。 6. **设置类代码**: - 输入**Class Code**(例如,`0x020000`用于以太网控制器)。 7. **配置其他标识符(如果可用)**: - 一些IP核允许设置**编程接口**、**设备功能**等。 - 根据需要将其与捐赠设备匹配。 #### **7.2.3 配置BAR大小** BAR定义了设备如何将其内部内存和寄存器映射到主机系统。 **步骤**: 1. **导航到基地址寄存器(BARs)**: - 在IP定制窗口中,选择**BARs**选项卡或部分。 2. **配置每个BAR**: - 对于**BAR0**到**BAR5**,根据捐赠设备设置以下参数: - **启用BAR**:选中或取消选中以匹配捐赠设备。 - **BAR大小**:从下拉列表中选择大小(例如,**256 MB**、**64 KB**)。 - **BAR类型**: - **内存(32位寻址)** - **内存(64位寻址)** - **I/O** - **可预取**:如果捐赠设备的BAR可预取,则选中。 3. **示例配置**: - **BAR0**: - 已启用 - 大小:**256 MB** - 类型:**内存(64位)** - 可预取:**是** - **BAR1**: - 已禁用(如果捐赠设备不使用BAR1) 4. **确保对齐和不重叠空间**: - 确认映射的总内存不超过FPGA的能力。 - 确保BAR大小符合PCIe规范要求。 5. **高级设置(如果适用)**: - 某些设备可能有特殊要求,如扩展ROM BAR。 - 如果必要,配置这些设置。 #### **7.2.4 完成IP定制** 在配置所有必要的设置后,您需要应用更改。 **步骤**: 1. **审查所有设置**: - 浏览IP定制窗口中的每个选项卡。 - 确认所有条目与捐赠设备的规格相匹配。 2. **应用更改**: - 点击**OK**或**Generate**以应用设置。 - 如果提示,确认您希望继续更改。 3. **重新生成IP核**: - Vivado将重新生成IP核以反映新配置。 - 监视**消息**窗格以获取任何错误或警告。 4. **更新项目中的IP**: - 确保更新的IP核已正确集成到您的项目中。 - Vivado可能会提示更新IP依赖项;允许其执行此操作。 #### **7.2.5 锁定IP核** 锁定IP核可防止在综合和实现期间的意外更改。 **目的**: - **防止覆盖**:确保您的手动配置被保留。 - **保持一致性**:在整个构建过程中保持IP核处于已知状态。 **步骤**: 1. **打开Tcl控制台**: - 在Vivado中,如果尚未打开,转到**窗口** > **Tcl控制台**。 2. **执行锁定命令**: - 输入以下命令: ```tcl set_property -name {IP_LOCKED} -value true -objects [get_ips pcie_7x_0] ``` - 按**Enter**执行。 3. **验证锁定**: - 检查**消息**窗格以确认。 - IP核现在应标记为已锁定。 4. **解锁(如有必要)**: - 要在将来进行进一步更改,可以解锁IP核: ```tcl set_property -name {IP_LOCKED} -value false -objects [get_ips pcie_7x_0] ``` - 记得在进行更改后重新锁定它。 5. **记录操作**: - 在您的项目文档中注明IP核已被锁定。 - 这有助于团队成员了解项目的配置状态。 --- ### **第2部分:中级概念与实现** --- ## **8. 高级固件定制** 为了实现对捐赠设备的精确仿真,需要进一步深入定制固件。这包括调整PCIe参数、调整基地址寄存器(BARs)、以及仿真电源管理和中断机制,以匹配捐赠设备的规格。这些步骤确保仿真设备能够与主机系统无缝交互,其行为与原始硬件完全一致。 ### **8.1 为仿真配置PCIe参数** 准确的仿真要求您的FPGA设备的PCIe参数与捐赠设备精确匹配。这包括设置如PCIe链路速度、链路宽度、能力指针和最大有效载荷大小等。正确的配置确保与主机系统的兼容性,以及与设备驱动程序和应用程序的正确交互。 #### **8.1.1 匹配PCIe链路速度和宽度** PCIe链路速度和宽度是决定设备数据吞吐量和性能的关键参数。匹配这些设置对于准确仿真至关重要。 **步骤**: 1. **访问PCIe IP核设置**: - **打开您的Vivado项目**: - 启动Vivado并打开您之前创建或修改的项目。 - 确保所有源文件都已正确添加到项目中。 - **找到PCIe IP核**: - 在**源文件**窗格中,展开层次结构,找到PCIe IP核实例,通常命名为`pcie_7x_0`。 - 与IP核关联的文件通常是`pcie_7x_0.xci`。 - **定制IP核**: - 右键点击`pcie_7x_0.xci`,选择**定制IP**。 - IP配置窗口将打开,显示各种配置选项。 2. **设置最大链路速度**: - **导航到链路参数**: - 在IP配置窗口中,点击**Link Parameters**选项卡或部分。 - 该部分包含与PCIe链路特性相关的设置。 - **配置最大链路速度**: - 找到**Maximum Link Speed**选项。 - 设置为与捐赠设备的链路速度相匹配。 - **示例**: - 如果捐赠设备以**Gen2(5.0 GT/s)**运行,选择**5.0 GT/s**。 - 如果以**Gen1(2.5 GT/s)**或**Gen3(8.0 GT/s)**运行,选择相应的选项。 - **注意**:确保您的FPGA和物理硬件支持所选的链路速度。 3. **设置链路宽度**: - **配置链路宽度**: - 在同一**Link Parameters**部分,找到**Link Width**设置。 - 设置为与捐赠设备的链路宽度相匹配。 - **示例**: - 如果捐赠设备使用**x4**链路,将**Link Width**设置为**4**。 - 选项通常包括**1**、**2**、**4**、**8**、**16**通道。 - **注意**:物理连接器和FPGA必须支持所选的链路宽度。 4. **保存并重新生成**: - **应用更改**: - 配置链路速度和宽度后,点击**OK**应用更改。 - Vivado可能提示您由于更改需要重新生成IP核。 - 确认并允许重新生成过程完成。 - **验证设置**: - 重新生成完成后,重新查看IP核设置,确保配置已正确应用。 - 检查**消息**窗口中的任何警告或错误。 #### **8.1.2 设置能力指针** PCIe配置空间中的能力指针指向各种能力结构,如MSI、电源管理等。正确设置这些指针确保主机系统能够找到并利用设备的功能。 **步骤**: 1. **在固件中找到能力指针**: - **打开配置文件**: - 在Visual Studio Code中,打开`pcileech_pcie_cfg_a7.sv`文件,位于: ``` pcileech-fpga/pcileech-wifi-main/src/pcileech_pcie_cfg_a7.sv ``` - **了解能力指针**: - 能力指针是一个8位寄存器,指向PCIe配置空间中的第一个能力结构,通常从标准配置头之后开始。 2. **设置能力指针值**: - **找到`cfg_cap_pointer`的赋值**: - 搜索代码中`cfg_cap_pointer`的定义行。 ```verilog cfg_cap_pointer <= 8'hXX; // 当前值 ``` - **更新能力指针**: - 将`XX`替换为捐赠设备的能力指针值。 - **示例**: - 如果捐赠设备的能力指针是`0x60`,则更新为: ```verilog cfg_cap_pointer <= 8'h60; // 更新以匹配捐赠设备 ``` - **确保正确对齐**: - 能力结构必须在4字节边界上对齐。 - 能力指针应指向配置空间内的有效偏移量。 3. **保存更改**: - **保存配置文件**: - 进行更改后,点击**文件 > 保存**或按`Ctrl + S`保存文件。 - **验证语法**: - 确保更改未引入语法错误。 - **添加注释以增加清晰度**: - 添加注释,说明更改的原因,便于将来参考。 ```verilog cfg_cap_pointer <= 8'h60; // 设置为捐赠设备在偏移量0x60的能力指针 ``` #### **8.1.3 调整最大有效载荷和读取请求大小** 这些参数定义了在单个PCIe事务中可以传输的最大数据量。与捐赠设备匹配这些设置可确保兼容性和最佳性能。 **步骤**: 1. **设置最大有效载荷大小**: - **访问设备功能**: - 在PCIe IP核定制窗口中,导航到**Device Capabilities**或**Capabilities**选项卡。 - **配置支持的最大有效载荷大小**: - 找到**Max Payload Size Supported**设置。 - 将其设置为捐赠设备支持的值。 - **选项**: - **128字节**、**256字节**、**512字节**、**1024字节**、**2048字节**、**4096字节**。 - **示例**: - 如果捐赠设备支持最大有效载荷大小为**256字节**,请选择**256字节**。 2. **设置最大读取请求大小**: - **配置支持的最大读取请求大小**: - 在同一选项卡中,找到**Max Read Request Size Supported**设置。 - 将其设置为与捐赠设备的能力相匹配。 - **示例**: - 如果捐赠设备支持最大读取请求大小为**512字节**,请选择**512字节**。 3. **调整固件参数**: - **打开`pcileech_pcie_cfg_a7.sv`**: - 确保配置文件在Visual Studio Code中打开。 - **更新固件常量**: - 找到定义`max_payload_size_supported`和`max_read_request_size_supported`的行。 ```verilog max_payload_size_supported <= 3'bZZZ; // 当前值 max_read_request_size_supported <= 3'bWWW; // 当前值 ``` - **设置适当的值**: - 将`ZZZ`和`WWW`替换为大小的二进制表示。 - **映射关系**: - **128字节**:`3'b000` - **256字节**:`3'b001` - **512字节**:`3'b010` - **1024字节**:`3'b011` - **2048字节**:`3'b100` - **4096字节**:`3'b101` - **示例**: - 对于**256字节**的有效载荷大小: ```verilog max_payload_size_supported <= 3'b001; // 支持高达256字节 ``` - 对于**512字节**的读取请求大小: ```verilog max_read_request_size_supported <= 3'b010; // 支持高达512字节 ``` 4. **保存更改**: - **保存文件**: - 更新值后,保存文件。 - **验证一致性**: - 确保固件中的值与PCIe IP核中配置的值匹配。 - **添加注释**: - 记录更改,便于将来参考。 ```verilog max_payload_size_supported <= 3'b001; // 根据捐赠设备支持256字节 max_read_request_size_supported <= 3'b010; // 根据捐赠设备支持512字节 ``` ### **8.2 调整BAR和内存映射** 基地址寄存器(BARs)定义了设备向主机暴露的内存区域。正确配置BARs和内存映射对于准确仿真和设备驱动程序的正常运行至关重要。 #### **8.2.1 设置BAR大小** 配置BAR大小可确保设备在枚举期间请求正确的地址空间,并且主机正确映射这些区域。 **步骤**: 1. **访问BAR配置**: - **定制PCIe IP核**: - 在Vivado中,右键点击`pcie_7x_0.xci`,选择**定制IP**。 - **导航到BARs选项卡**: - 在IP配置窗口中,点击**Base Address Registers (BARs)**选项卡。 2. **配置BAR大小和类型**: - **匹配捐赠设备的BARs**: - 对于每个BAR(BAR0至BAR5),设置大小和类型以匹配捐赠设备。 - **设置BAR大小**: - 从下拉菜单中为每个BAR选择适当的大小。 - **示例**: - 如果**BAR0**是**64 KB**,将**BAR0 Size**设置为**64 KB**。 - 如果**BAR1**是**128 MB**,将**BAR1 Size**设置为**128 MB**。 - **设置BAR类型**: - 为每个BAR选择**32位**或**64位**寻址。 - 指定BAR的类型是**内存**还是**I/O**。 - 根据捐赠设备设置**可预取**状态。 - **启用或禁用BARs**: - 确保仅启用了捐赠设备使用的BARs。 3. **更新BRAM配置**: - **调整BRAM IP核**: - 在`ip`目录中,找到与BARs对应的BRAM配置。 - **文件**: ``` pcileech-fpga/pcileech-wifi-main/ip/bram_bar_zero4k.xci pcileech-fpga/pcileech-wifi-main/ip/bram_pcie_cfgspace.xci ``` - **修改BRAM大小**: - 打开每个BRAM IP核,调整内存大小以匹配相应的BAR大小。 - 确保总内存不超过FPGA的容量。 4. **保存并重新生成**: - **应用更改**: - 配置BARs并更新BRAM大小后,点击**OK**。 - **重新生成IP核**: - Vivado可能会提示由于更改需要重新生成IP核。 - 允许重新生成完成。 - **检查错误**: - 查看**消息**窗口中的任何与BAR配置相关的警告或错误。 #### **8.2.2 在固件中定义BAR地址空间** 设置BAR大小和类型后,您需要定义固件如何处理对这些BAR的访问。 **步骤**: 1. **打开BAR控制器文件**: - **找到源文件**: - 在Visual Studio Code中,打开: ``` pcileech-fpga/pcileech-wifi-main/src/pcileech_tlps128_bar_controller.sv ``` 2. **映射地址范围**: - **定义地址解码逻辑**: - 实现逻辑以检测何时访问BAR,基于地址。 ```verilog always_comb begin if (bar_hit[0]) begin // 处理对BAR0的访问 end else if (bar_hit[1]) begin // 处理对BAR1的访问 end // 继续处理其他BAR end ``` - **实现BAR访问处理**: - 对于每个BAR,定义如何管理读写操作。 - **示例**: ```verilog if (bar_hit[0]) begin case (addr_offset) 16'h0000: data_out <= reg0; 16'h0004: data_out <= reg1; // 其他寄存器 default: data_out <= 32'h0; endcase end ``` 3. **实现地址解码逻辑**: - **计算地址偏移量**: ```verilog addr_offset = incoming_address - bar_base_address[0]; ``` - **处理数据传输**: ```verilog if (cfg_write) begin // 将数据写入适当的寄存器 end else if (cfg_read) begin // 从适当的寄存器读取数据 end ``` 4. **保存更改**: - **保存文件**: - 实现逻辑后,保存`pcileech_tlps128_bar_controller.sv`文件。 - **验证功能**: - 确保逻辑正确处理所有可能的访问。 #### **8.2.3 处理多个BAR** 正确管理多个BAR对于暴露多个内存或I/O区域的设备至关重要。 **步骤**: 1. **为每个BAR实现逻辑**: - **分离逻辑块**: - 为了清晰起见,在控制器内为每个BAR创建单独的代码块。 ```verilog // BAR0处理 if (bar_hit[0]) begin // BAR0特定逻辑 end // BAR1处理 if (bar_hit[1]) begin // BAR1特定逻辑 end ``` - **定义寄存器和内存**: - 根据需要为每个BAR分配寄存器或内存块。 2. **确保地址空间不重叠**: - **验证地址范围**: - 确认每个BAR的地址空间不重叠。 - 根据PCIe规范要求,将BAR大小对齐到2的幂边界。 - **更新地址解码**: - 调整地址解码逻辑,以考虑每个BAR的大小和基地址。 3. **测试BAR访问**: - **仿真测试**: - 使用仿真工具测试对每个BAR的读写操作。 - 验证读取或写入的数据是否正确。 - **硬件测试**: - 编程FPGA,使用主机上的软件访问每个BAR。 - **示例**: - 在Linux上使用`lspci`检查BAR映射。 - 编写执行内存映射I/O到BAR的测试程序。 ### **8.3 仿真设备电源管理和中断** 仿真电源管理功能并实现中断对于需要与主机操作系统的电源和中断处理机制紧密交互的设备至关重要。 #### **8.3.1 电源管理配置** 实现电源管理允许设备支持各种电源状态,有助于系统范围的电源效率,并符合操作系统的期望。 **步骤**: 1. **在PCIe IP核中启用电源管理**: - **访问功能选项**: - 在PCIe IP核配置窗口中,选择**Capabilities**选项卡。 - **启用电源管理**: - 勾选**Power Management**选项,以在设备的配置空间中包含此功能。 2. **设置支持的电源状态**: - **配置支持的状态**: - 指定设备支持哪些电源状态,例如: - **D0(完全开启)** - **D1、D2(中间状态)** - **D3hot、D3cold(低功耗状态)** - 将这些设置与捐赠设备的功能相匹配。 3. **在固件中实现电源状态逻辑**: - **打开`pcileech_pcie_cfg_a7.sv`**: - 修改固件以处理电源状态转换。 - **处理电源管理控制和状态寄存器(PMCSR)**: - 实现对PMCSR的读写访问。 ```verilog // PMCSR地址 localparam PMCSR_ADDRESS = 12'h44; // 示例地址 // PMCSR寄存器 reg [15:0] pmcsr_reg; // 处理PMCSR写操作 always @(posedge clk) begin if (cfg_write && cfg_address == PMCSR_ADDRESS) begin pmcsr_reg <= cfg_writedata[15:0]; // 根据pmcsr_reg[1:0]更新电源状态 end end ``` - **管理电源状态效果**: - 实现逻辑,根据当前的电源状态改变设备行为。 4. **保存更改**: - **保存固件文件**: - 确保所有修改都已保存。 - **验证功能**: - 通过仿真或硬件测试,测试电源管理功能。 #### **8.3.2 MSI/MSI-X配置** 实现MSI/MSI-X允许设备使用基于消息的中断,这比传统的基于引脚的中断更高效和可扩展。 **步骤**: 1. **在PCIe IP核中启用MSI/MSI-X**: - **访问中断配置**: - 在PCIe IP核配置窗口中,导航到**Interrupts**或**MSI/MSI-X**选项卡。 - **选择中断类型**: - 根据捐赠设备,选择**MSI**或**MSI-X**。 - **配置支持的向量数量**: - 设置与捐赠设备匹配的中断向量数量。 - **MSI**支持最多32个向量。 - **MSI-X**支持最多2048个向量。 - **启用功能**: - 确保MSI或MSI-X功能包含在设备的配置空间中。 2. **在固件中实现中断逻辑**: - **打开`pcileech_pcie_tlp_a7.sv`**: - 修改固件以处理中断生成。 - **定义中断信号**: ```verilog reg msi_req; ``` - **实现中断生成逻辑**: ```verilog // 示例中断条件 wire interrupt_condition = /* 条件逻辑 */; // 生成MSI中断 always @(posedge clk) begin if (interrupt_condition) begin msi_req <= 1'b1; end else begin msi_req <= 1'b0; end end ``` - **连接到PCIe核心**: - 确保`msi_req`信号正确连接到PCIe IP核的中断接口。 3. **保存更改**: - **保存固件文件**: - 实现中断逻辑后,保存文件。 - **检查时序约束**: - 确认新逻辑未引入时序违规。 #### **8.3.3 实现中断处理逻辑** 定义何时以及如何生成中断对于设备与主机的中断处理机制的交互至关重要。 **步骤**: 1. **定义中断条件**: - **识别触发事件**: - 确定应引起中断的特定事件。 - **示例**: - 数据已准备好处理。 - 错误条件。 - 任务完成。 - **实现条件逻辑**: - 使用组合逻辑或时序逻辑来检测这些事件。 2. **创建中断生成模块**: - **模块化设计**: - 将中断逻辑实现为一个独立的模块,以提高清晰度和可重用性。 ```verilog module interrupt_controller( input wire clk, input wire reset, input wire event_trigger, output reg msi_req ); always @(posedge clk or posedge reset) begin if (reset) begin msi_req <= 1'b0; end else if (event_trigger) begin msi_req <= 1'b1; end else begin msi_req <= 1'b0; end end endmodule ``` - **与主固件集成**: - 实例化模块,并将其连接到主固件逻辑。 3. **确保正确的时序和顺序**: - **遵守PCIe规范**: - 确保中断按照协议正确生成和清除。 - **管理中断延迟**: - 优化逻辑,最小化事件发生和中断生成之间的延迟。 4. **测试中断传递**: - **仿真**: - 使用仿真工具验证中断是否正确生成。 - **硬件测试**: - 编程FPGA,使用主机端软件确认中断已接收并处理。 - **调试工具**: - 利用集成逻辑分析器(ILA)核实时监控信号。 5. **保存更改**: - **最终确定代码**: - 确保所有更改都已保存并记录。 - **审查和改进**: - 根据测试结果迭代设计。 --- ## **10. 事务层数据包(TLP)仿真** 事务层数据包(TLP)是PCIe通信的基本单位。准确的TLP仿真对于设备正确地与主机系统交互至关重要。 ### **10.1 理解和捕获TLP** #### **10.1.1 学习TLP结构** - **组成部分**: - **头部**:包含字段,如**事务层数据包类型(Type)**、**长度**、**请求者ID**、**标签**、**地址**等。 - **数据负载**:存在于内存写入和其他一些TLP中。 - **CRC**:确保数据完整性。 - **理解TLP类型**: - **内存读取请求** - **内存读取完成** - **内存写入** - **配置读取/写入** - **供应商定义的消息** #### **10.1.2 从捐赠设备捕获TLP** - **步骤**: 1. **设置PCIe协议分析仪**: - 使用如**Teledyne LeCroy PCIe分析仪**的硬件工具。 2. **捕获事务**: - 在捐赠设备正常运行期间进行监控,记录TLP。 3. **分析捕获的TLP**: - 使用分析仪的软件,剖析TLP,理解其结构和序列。 #### **10.1.3 记录关键TLP事务** - **步骤**: 1. **识别关键事务**: - 关注设备初始化、配置、数据传输和错误处理所必需的TLP。 2. **创建详细文档**: - 对于每个关键TLP,记录字段值、序列和发送条件。 3. **理解时序和顺序**: - 注意TLP之间的时序,以及所需的响应时间。 ### **10.2 为特定操作制作自定义TLP** #### **10.2.1 在固件中实现TLP处理** - **需要修改的文件**: - `pcileech_pcie_tlp_a7.sv` ``` pcileech-wifi-main/src/pcileech_pcie_tlp_a7.sv ``` - **步骤**: 1. **创建TLP生成函数**: - 在`pcileech_pcie_tlp_a7.sv`中,编写函数,组装具有所需头部和负载的TLP。 - **示例**: ```verilog function automatic [127:0] generate_tlp; input [15:0] requester_id; input [7:0] tag; input [7:0] length; input [31:0] address; input [31:0] data; begin generate_tlp = { /* TLP头部和负载 */ }; end endfunction ``` 2. **处理TLP接收**: - 实现逻辑,解析接收到的TLP,提取必要信息。 - 使用状态机管理不同的TLP类型。 3. **确保合规性**: - 验证TLP符合PCIe规范的格式和时序。 4. **实现完成处理**: - 对于内存读取请求,生成适当的完成TLP。 5. **保存更改**: - 实现更改后,保存文件。 #### **10.2.2 处理不同的TLP类型** - **内存读取请求**: - **实现**: - 解析请求头部。 - 从适当的内存位置获取数据。 - 组装并发送包含数据的完成TLP。 - **内存写入请求**: - **实现**: - 接收TLP并提取数据负载。 - 将数据写入指定的内存位置。 - **配置读取/写入请求**: - **实现**: - 访问配置空间寄存器。 - 对于读取,返回请求的数据。 - 对于写入,更新寄存器值。 - **供应商定义的消息**: - **实现**: - 根据捐赠设备的协议,实现解析和响应逻辑。 #### **10.2.3 验证TLP时序和序列** - **步骤**: 1. **使用仿真工具**: - 使用测试平台仿真固件,验证TLP处理。 2. **使用ILA监控**: - 插入ILA核,捕获TLP相关信号的硬件测试。 3. **检查时序约束**: - 确保TLP在PCIe标准允许的时序窗口内处理和响应。 4. **合规性测试**: - 使用PCIe合规性工具验证对标准的遵从。 5. **保存更改**: - 测试和验证后,保存所有修改的文件。 --- ## **第3部分:高级技术与优化** --- ## **11. 构建、烧录和测试** 完成所有定制后,接下来是构建固件,将其编程到FPGA上,并彻底测试以确保其正常功能。 ### **11.1 综合与实现** #### **11.1.1 运行综合** 综合将您的高级代码转换为门级表示。 - **步骤**: 1. **启动综合**: - 在Vivado中,点击**Flow Navigator**中的**Run Synthesis**。 2. **监视进度**: - 注意任何警告或错误。 - **常见警告**: - **未连接端口**:确保所有必要的信号已连接。 - **未满足时序约束**:可能需要调整约束。 3. **查看综合报告**: - 检查**利用率摘要**,确保设计适合FPGA。 #### **11.1.2 运行实现** 实现将综合的设计映射到FPGA的资源上。 - **步骤**: 1. **启动实现**: - 综合成功后,点击**Run Implementation**。 2. **分析时序报告**: - 确保所有时序约束都已满足。 - **解决违规**: - 调整逻辑或约束,以修复建立或保持时间违规。 3. **验证布局**: - 检查关键组件已被优化地放置。 #### **11.1.3 生成比特流** 比特流是用于编程FPGA的二进制文件。 - **步骤**: 1. **生成比特流**: - 点击**Generate Bitstream**。 2. **等待完成**: - 根据设计的复杂性,这可能需要一些时间。 3. **查看比特流生成日志**: - 确保生成过程中没有发生错误。 ### **11.2 烧录比特流** #### **11.2.1 连接FPGA设备** - **步骤**: 1. **准备硬件**: - 确保FPGA板已通电,并通过JTAG连接。 - 参考您的FPGA板手册,获取特定的连接说明。 2. **打开硬件管理器**: - 在Vivado中,导航到**Flow Navigator > Program and Debug > Open Hardware Manager**。 #### **11.2.2 编程FPGA** - **步骤**: 1. **连接到目标设备**: - 在硬件管理器中,点击**Open Target**,选择**Auto Connect**。 - Vivado应检测到您的FPGA设备。 2. **编程设备**: - 在硬件窗口中,右键点击您的FPGA设备,选择**Program Device**。 - 选择生成的比特流文件(扩展名为`.bit`)。 - 点击**Program**,将固件烧录到FPGA上。 - 等待编程过程完成。 #### **11.2.3 验证编程** - **步骤**: 1. **检查状态**: - 确保编程无错误地完成。 - Vivado将在完成后显示成功消息。 2. **观察LED或指示灯**: - 一些FPGA板具有指示成功编程或活动状态的LED。 ### **11.3 测试与验证** #### **11.3.1 验证设备枚举** - **Windows**: - **步骤**: 1. **打开设备管理器**: - 按`Win + X`,选择**设备管理器**。 2. **检查设备属性**: - 在适当的设备类别下查找(例如,**网络适配器**、**存储控制器**)。 - 确认**设备ID**、**供应商ID**和其他标识符与捐赠设备匹配。 - **Linux**: - **步骤**: 1. **使用lspci**: ```bash lspci -nn ``` 2. **验证设备列表**: - 检查仿真设备是否以正确的ID出现。 - **示例输出**: ``` 03:00.0 Network controller [0280]: VendorID DeviceID ``` #### **11.3.2 测试设备功能** - **步骤**: 1. **安装必要的驱动程序**: - 如有需要,使用捐赠设备的驱动程序。 - 按制造商的说明进行安装。 2. **执行功能测试**: - 运行与设备交互的应用程序。 - 测试数据传输、配置和任何特殊功能。 - **示例**: - 对于网络卡,执行ping测试或数据流传输。 - 对于存储控制器,执行读/写操作。 3. **监视系统行为**: - 检查系统稳定性,是否无错误。 - 确保设备在各种负载下按预期运行。 #### **11.3.3 监控错误** - **Windows**: - **步骤**: 1. **检查事件查看器**: - 按`Win + X`,选择**事件查看器**。 - 导航到**Windows日志 > 系统**。 2. **查找与PCIe相关的错误**: - 搜索与PCIe或特定设备相关的警告或错误。 - **Linux**: - **步骤**: 1. **检查dmesg日志**: ```bash dmesg | grep pci ``` 2. **识别问题**: - 查找指示PCIe通信或设备初始化问题的消息。 --- ## **12. 高级调试技术** 当出现问题时,高级调试工具和技术可以帮助有效地识别和解决问题。 ### **12.1 使用Vivado的集成逻辑分析器** 集成逻辑分析器(ILA)允许实时监控FPGA内部信号。 #### **12.1.1 插入ILA核** - **步骤**: 1. **添加ILA IP核**: - 在Vivado中,打开**IP目录**。 - 搜索**ILA**。 - 在设计中实例化ILA核。 2. **连接信号**: - 将您希望监控的信号连接到ILA探针。 - **示例**: ```verilog ila_0 your_ila_instance ( .clk(clk), .probe0(signal_to_monitor) ); ``` - **文件路径**: ``` pcileech-wifi-main/src/pcileech_squirrel_top.sv ``` #### **12.1.2 配置触发条件** - **步骤**: 1. **设置探针属性**: - 定义每个探针的宽度,以匹配信号宽度。 2. **定义触发器**: - 在ILA仪表板中,设置触发数据捕获的条件。 - **示例**: - 当检测到特定的TLP类型或发生错误条件时触发。 #### **12.1.3 捕获和分析数据** - **步骤**: 1. **运行设计**: - 使用包含ILA的比特流编程FPGA。 2. **打开硬件管理器**: - 在Vivado中访问ILA界面。 3. **捕获数据**: - 臂ILA,等待触发条件。 - 触发后,ILA将捕获波形数据。 4. **分析波形**: - 使用波形查看器检查信号行为。 - 识别异常或验证正确的操作。 ### **12.2 PCIe流量分析工具** 使用外部工具可以深入了解PCIe通信。 #### **12.2.1 PCIe协议分析仪** - **示例**: - **Teledyne LeCroy PCIe分析仪** - **Keysight PCIe分析仪** - **步骤**: 1. **设置分析仪**: - 将分析仪连接在主机系统和FPGA设备之间。 2. **配置捕获设置**: - 定义要捕获的数据范围(例如,特定的TLP类型、错误条件)。 3. **捕获流量**: - 在设备运行期间记录PCIe事务。 4. **分析结果**: - 检查TLP的合规性和正确性。 - 识别任何协议违规或意外行为。 #### **12.2.2 基于软件的工具** - **示例**: - **Wireshark与PCIe插件** - **ChipScope Pro**(适用于Xilinx设备) - **步骤**: 1. **安装必要的插件**: - 确保工具中启用了PCIe支持。 2. **监控PCIe总线**: - 捕获并显示PCIe数据包。 3. **分析通信**: - 查找数据中的异常或错误。 - 验证TLP的正确形成和顺序。 --- ## **13. 故障排除** 本节提供了您在固件开发和测试过程中可能遇到的常见问题的解决方案。 ### **13.1 设备检测问题** **问题**:FPGA设备未被主机系统识别。 #### **可能的原因和解决方案**: 1. **设备ID不正确**: - **原因**:固件中的ID与主机期望的不匹配。 - **解决方案**:验证并纠正固件中的**设备ID**、**供应商ID**和**子系统ID**。 2. **PCIe链路训练失败**: - **原因**:PCIe链路未建立。 - **解决方案**: - 检查物理连接。 - 确保**链路宽度**和**链路速度**已正确配置。 3. **电源问题**: - **原因**:FPGA设备供电不足。 - **解决方案**:验证电源连接和电压水平。 4. **固件错误**: - **原因**:固件中的错误阻止正常运行。 - **解决方案**:检查代码中的语法错误或配置错误。 ### **13.2 内存映射和BAR配置错误** **问题**:设备的内存区域不可访问,或访问它们导致系统错误。 #### **可能的原因和解决方案**: 1. **BAR大小或类型不正确**: - **原因**:BAR配置与捐赠设备不匹配。 - **解决方案**:在PCIe IP核和固件中调整BAR大小和类型。 2. **地址解码错误**: - **原因**:固件未正确解释地址。 - **解决方案**:调试固件中的地址解码逻辑。 3. **地址空间重叠**: - **原因**:BARs重叠或与其他设备冲突。 - **解决方案**:确保BAR地址正确对齐且不重叠。 ### **13.3 DMA性能和TLP错误** **问题**:DMA操作期间发生数据传输速率低或错误,或TLP格式错误。 #### **可能的原因和解决方案**: 1. **DMA逻辑效率低下**: - **原因**:DMA引擎未优化。 - **解决方案**:实现缓冲和流水线以提高吞吐量。 2. **TLP格式错误**: - **原因**:TLP格式不正确。 - **解决方案**:检查TLP组装代码,确保符合PCIe规范。 3. **流控制问题**: - **原因**:未正确处理流控制信用。 - **解决方案**:在固件中实现正确的流控制机制。 --- ## **14. 仿真准确性和优化** 提高仿真准确性可确保兼容性和性能,使仿真设备与捐赠设备无异。 ### **14.1 精确计时仿真技术** - **实施时序约束**: - 使用Vivado的时序约束,匹配捐赠设备的时序特性。 - 将约束应用于关键路径,确保它们满足所需的建立和保持时间。 - **使用时钟域交叉(CDC)技术**: - 正确处理跨越不同时钟域的信号,防止亚稳态。 - 根据需要使用同步器或FIFO。 - **仿真设备行为**: - 使用仿真工具对设备行为进行建模和验证。 - 确认操作的时序和顺序与捐赠设备匹配。 ### **14.2 对系统调用的动态响应** - **实现状态机**: - 设计状态机,允许设备对各种命令和状态进行动态响应。 - 确保设备能够优雅地处理意外或乱序的请求。 - **监控并响应主机命令**: - 实现逻辑,解码并响应配置写入、供应商特定命令和其他交互。 - 相应地更新内部寄存器和状态。 - **优化固件逻辑**: - 精简固件代码,减少延迟,提高响应速度。 - 删除不必要的延迟或数据路径中的瓶颈。 --- ## **15. 固件开发最佳实践** 遵循最佳实践有助于维护代码质量,促进协作,并确保项目的长期可行性。 ### **15.1 持续测试和文档编制** - **定期测试**: - 在每次重要更改后测试固件,及早发现问题。 - 在实现之前,使用测试平台和仿真验证逻辑。 - **自动化测试**: - 实现自动化测试脚本,验证功能和性能。 - 如果在团队环境中工作,使用持续集成工具。 - **维护文档**: - 记录设计,包括框图、状态机和接口。 - 通过清晰的提交消息跟踪更改,并相应地更新设计文档。 ### **15.2 管理固件版本** - **使用版本控制系统**: - 使用**Git**等系统管理代码版本并与他人协作。 - 使用清晰的目录结构和命名约定组织代码库。 - **标记发布和里程碑**: - 为固件的稳定版本打标签,供将来参考。 - 为实验性功能或重大更改使用分支。 - **备份和恢复**: - 定期备份您的工作,以防止数据丢失。 - 根据需要使用云端代码库或本地备份。 ### **15.3 安全考虑** - **安全编码实践**: - 遵循指南,防止常见漏洞,如缓冲区溢出或竞争条件。 - 验证所有输入,优雅地处理错误。 - **数据保护**: - 确保设备处理的任何敏感数据都受到保护。 - 如果必要,实施加密或访问控制。 - **合规和道德**: - 了解与设备仿真相关的法律和道德考虑。 - 确保遵守相关的法律、法规和许可协议。 --- ## **16. 其他资源** 通过以下资源增强您的理解并保持更新: - **Xilinx文档** - [Xilinx用户指南](https://www.xilinx.com/support/documentation/user_guides.htm) - 包含有关Vivado、IP核和FPGA开发的详细信息。 - **PCI-SIG规范** - [PCI Express基本规范](https://pcisig.com/specifications) - PCIe标准的官方规范。 - **FPGA教程和论坛** - [FPGA4Fun](http://www.fpga4fun.com/) - [Stack Overflow的FPGA问题](https://stackoverflow.com/questions/tagged/fpga) - 由社区驱动的讨论和教程。 - **Verilog和VHDL资源** - [ASIC World Verilog教程](https://www.asic-world.com/verilog/index.html) - [VHDL参考指南](https://www.vhdlwhiz.com/vhdl-reference-guide/) - **Vivado设计套件用户指南** - [Vivado用户指南](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2020_1/ug893-vivado-ip-subsystems.pdf) - **PCIe协议分析工具** - [Teledyne LeCroy](https://teledynelecroy.com/protocolanalyzer/) - 提供一系列PCIe分析工具。 --- ## **17. 联系信息** 如果您需要帮助、有疑问或希望合作,欢迎随时联系。我可以提供指导,解决复杂问题,或详细讨论想法。 ### **Discord**: [**VCPU**](https://discord.com/users/196741541094621184) | [**服务器邀请链接**](https://discord.gg/dS2gDUDQmV) --- ## **18. 支持与贡献** 您的支持有助于维护和改进本指南和相关项目。 ### **捐赠** - **加密货币捐赠(LTC)**: - **地址**:`MPMyQD5zgy2b2CpDn1C1KZ31KmHpT7AwRi` 如果您发现本指南有用,并希望支持正在进行的工作,请考虑贡献。每一份捐赠都有助于继续创建、分享和支持社区。 **特别奖励**:如果您进行了捐赠,请在Discord上联系我(VCPU),以收到个人感谢,可能还有额外的资源或帮助。 **注意**:如果您需要我查看您的实现或解决问题,请在相关部分标注`//VCPU-REVIEW//`,并提供您遇到的问题的详细说明。 --- **指南结束** ================================================ FILE: CN/README-old.md ================================================ # **全设备仿真的定制固件开发指南** ## **目录** 1. [介绍](#1-介绍) - [1.1 指南目的](#11-指南目的) - [1.2 目标受众](#12-目标受众) 2. [关键定义](#2-关键定义) 3. [设备兼容性](#3-设备兼容性) - [3.1 支持的基于FPGA的硬件](#31-支持的基于FPGA的硬件) - [3.2 PCIe硬件考虑事项](#32-pcie硬件考虑事项) - [3.3 系统要求](#33-系统要求) 4. [需求](#4-需求) - [4.1 硬件](#41-硬件) - [4.2 软件](#42-软件) - [4.3 环境设置](#43-环境设置) 5. [收集捐赠设备信息](#5-收集捐赠设备信息) - [5.1 使用Arbor进行PCIe设备扫描](#51-使用arbor进行pcie设备扫描) - [5.2 提取和记录设备属性](#52-提取和记录设备属性) 6. [初始固件定制](#6-初始固件定制) - [6.1 修改配置空间](#61-修改配置空间) - [6.2 插入设备序列号(DSN)](#62-插入设备序列号-dsn) 7. [Vivado项目设置与定制](#7-vivado项目设置与定制) - [7.1 生成Vivado项目文件](#71-生成vivado项目文件) - [7.2 修改IP模块](#72-修改ip模块) 8. [高级固件定制](#8-高级固件定制) - [8.1 配置用于仿真的PCIe参数](#81-配置用于仿真的pcie参数) - [8.2 调整BAR和内存映射](#82-调整bar和内存映射) - [8.3 仿真设备电源管理和中断](#83-仿真设备电源管理和中断) 9. [仿真设备特定功能](#9-仿真设备特定功能) - [9.1 实现高级PCIe功能](#91-实现高级pcie功能) - [9.2 仿真厂商特定功能](#92-仿真厂商特定功能) 10. [事务层数据包(TLP)仿真](#10-事务层数据包-tlp-仿真) - [10.1 理解和捕获TLP](#101-理解和捕获tlp) - [10.2 为特定操作制作自定义TLP](#102-为特定操作制作自定义tlp) 11. [构建、闪存和测试](#11-构建、闪存和测试) - [11.1 综合与实现](#111-综合与实现) - [11.2 闪存比特流](#112-闪存比特流) - [11.3 测试与验证](#113-测试与验证) 12. [高级调试技术](#12-高级调试技术) - [12.1 使用Vivado的集成逻辑分析仪](#121-使用vivado的集成逻辑分析仪) - [12.2 PCIe流量分析工具](#122-pcie流量分析工具) 13. [故障排除](#13-故障排除) - [13.1 设备检测问题](#131-设备检测问题) - [13.2 内存映射和BAR配置错误](#132-内存映射和bar配置错误) - [13.3 DMA性能和TLP错误](#133-dma性能和tlp错误) 14. [仿真精度和优化](#14-仿真精度和优化) - [14.1 精确时序仿真的技术](#141-精确时序仿真的技术) - [14.2 对系统调用的动态响应](#142-对系统调用的动态响应) 15. [固件开发的最佳实践](#15-固件开发的最佳实践) - [15.1 持续测试和文档记录](#151-持续测试和文档记录) - [15.2 管理固件版本](#152-管理固件版本) - [15.3 安全考虑](#153-安全考虑) 16. [附加资源](#16-附加资源) --- ## **前言** **注意,你们这些盗贼渣滓。** 我不是来溺爱或纵容你们可悲的阴谋的。**去你妈的AQUA**,也就是更广为人知的Aqua Teen Paster Force——对任何有一点诚信的人来说都是耻辱。**去你妈的DIVINER**,还有DUCK?去别的地方贬低自己。**DMA KINGDOM**?你和你们寄生的帝国以及这些骗子一起在地狱里腐烂。**SHITLETTE**和你们这些贪图金钱的贼人,准备迎接报应。**神的愤怒**?你们即将理解真正毁灭的意义。要么为你们的贪婪赎罪,要么被你们应得的毁灭席卷而去。既然我们谈到这个话题,**比尔·盖茨你也去他妈的。** 对于那些**来学习**的人,你们选择了**真正启蒙**的道路。你们用这本指南构建的东西将超越这些江湖骗子能梦想到的任何东西。你们正走在**卓越**的道路上,携手一起焚烧他们建立财富所基于的失败。 --- ## **联系方式** 如果您需要帮助、有疑问或希望合作,请随时联系。我可以提供指导、排除复杂问题或详细讨论想法。 ### **Discord** - **VCPU** | [**服务器**](https://discord.gg/dS2gDUDQmV) --- ## **支持我的工作** 如果您觉得这本指南有帮助,并希望支持更多项目,请考虑捐助以帮助维持一切运作。每一笔捐款都能帮助我继续创建、分享和支持社区,衷心感谢。 ### **买杯咖啡** - [ko-fi.com/virtualcpu](https://ko-fi.com/virtualcpu) - [buymeacoffee.com/vcpu](https://buymeacoffee.com/vcpu) ### **加密捐赠(LTC)** - MPMyQD5zgy2b2CpDn1C1KZ31KmHpT7AwRi 我通过销售固件赚得不多——大约5笔销售,总额约300美元——但我知道许多使用这本指南的人将会赚得更多。如果这本指南帮助您走上成功之路,请考虑回馈,以便我可以继续为大家提供这些资源。 ### **特别奖励** 如果您捐赠,请通过Discord(VCPU)联系我并告知。我很乐意亲自感谢您,并提供一些回报。我甚至会进行随机抽奖——无论是免费固件、私人源代码,还是一些绕过ACS的见解,都会有特别的东西给您。 您的支持对我意义重大,我们可以一起继续建设和分享未来。谢谢! --- 没有时间或精力自己制作固件?我提供最低60美元的固件服务。也欢迎转售商! 随时联系以获取支持或进一步讨论本指南或相关主题。无论您是需要深入帮助的开发人员,还是深入FPGA仿真的研究人员,我都在这里确保您的成功之路顺利且信息充分。让我们一起构建一些卓越的东西。 如果您不确定是否正确完成了某个步骤,或希望我审核您的实现,我会这样做,但您必须在需要审核的部分标记为 //VCPU-REVIEW// 并解释您的问题,以免浪费我的时间。 我相信你们中的很多人将超越我的能力。如果您发现了新东西或制作了一些很棒的固件,我很想看到它的实际运行。此外,我还有一些非常强大的字节和位可以分享,但如果我在这里分享,Riot PD会把我抓到警车上。 分享知识,传播充满爱的善意。愿上帝保佑。 --- ## **1. 介绍** ### **1.1 指南目的** 本指南的主要目标是为开发人员、安全研究人员和硬件工程师提供必要的知识和实际步骤,以开发用于精确1:1硬件设备仿真的定制DMA固件,使用基于FPGA的系统如**PCILeech-FPGA**。这使得在硬件测试、系统调试、恶意软件分析以及其他需要不可检测或看似合法的设备仿真的场景中应用成为可能。 ### **1.2 目标受众** - **固件开发人员**:为硬件仿真、测试或绕过硬件限制构建定制固件的工程师。 - **硬件测试人员**:仿真故障或过时的硬件设备,以评估系统弹性或兼容性的专业人士。 - **安全研究人员**:利用定制固件进行漏洞测试、恶意软件分析或安全评估的个人。 - **FPGA爱好者**:探索FPGA定制和低级硬件仿真的爱好者。 --- ## **2. 关键定义** 理解术语对于有效地遵循本指南至关重要。以下是与PCIe、DMA和设备仿真相关的关键定义: - **DMA(直接内存访问)**:一种允许硬件设备直接从系统内存读取或写入数据而无需CPU干预的能力,促进快速数据传输。 - **TLP(事务层数据包)**:PCIe架构中通信的基本单元,封装控制和数据信息。 - **BAR(基地址寄存器)**:PCIe设备中的寄存器,将设备内存映射到系统内存空间,定义内存和I/O地址区域。 - **FPGA(现场可编程门阵列)**:一种可重新配置的集成电路,可编程以执行特定的硬件功能,实现定制的设备仿真。 - **MSI/MSI-X(消息信号中断)**:PCIe设备用于向CPU发送中断的机制,处理异步事件。 - **设备序列号(DSN)**:与特定设备相关联的唯一标识符,通常用于高级设备识别和验证。 - **PCIe配置空间**:PCIe设备提供有关自身信息和配置操作参数的内存区域。 - **捐赠卡**:用于提取配置和识别详细信息以在FPGA上仿真其行为的PCIe设备。 --- ## **3. 设备兼容性** ### **3.1 支持的基于FPGA的硬件** 虽然本指南主要关注**Squirrel DMA(35T)**卡,但所述方法可适用于其他基于FPGA的DMA硬件。以下是兼容设备列表: - **Squirrel (35T)** - **描述**:价格实惠且广泛可获取的基于FPGA的DMA设备。 - **使用案例**:适用于标准内存获取和设备仿真任务。 - **EnigmaX1 (75T)** - **描述**:中档FPGA,提供增强的资源和性能。 - **使用案例**:适合需要更高带宽的更具挑战性的内存操作。 - **ZDMA (100T)** - **描述**:高性能FPGA,优化用于快速内存交互。 - **使用案例**:最适合需要快速和广泛内存读写的场景。 - **Kintex-7** - **描述**:先进的FPGA,具备强大的能力用于复杂项目。 - **使用案例**:适用于大规模或高度定制的DMA解决方案。 ### **3.2 PCIe硬件考虑事项** 为确保顺利仿真,必须解决多个PCIe特定功能: - **IOMMU/VT-d设置** - **建议**:禁用IOMMU(英特尔的VT-d),以允许不受限制的DMA访问。 - **理由**:IOMMU可能会限制DMA操作,可能干扰内存获取和仿真。 - **内核DMA保护** - **建议**:禁用现代系统中的内核DMA保护功能。 - **步骤**: - **Windows**:这可能涉及禁用安全启动或基于虚拟化的安全性(VBS)。 - **BIOS/UEFI**:访问固件设置以关闭相关安全功能。 - **注意**:禁用这些功能可能会使系统面临风险;确保在安全和隔离的环境中操作。 - **PCIe插槽要求** - **建议**:使用与FPGA设备要求匹配的兼容PCIe插槽(例如x1、x4、x16)。 - **理由**:确保与主机系统的最佳性能和兼容性。 ### **3.3 系统要求** - **主机系统** - **处理器**:多核CPU(Intel i5/i7或同等) - **内存**:至少16GB RAM - **存储**:至少100GB可用空间的SSD - **操作系统**:Windows 10/11(64位)或兼容的Linux发行版(例如Ubuntu、Debian)及必要的驱动程序 - **外围设备** - **JTAG适配器**:用于将固件闪存到FPGA - **PCIe插槽**:确保主机系统有可用的与DMA卡兼容的PCIe插槽 --- ## **4. 需求** ### **4.1 硬件** - **捐赠PCIe设备** - **用途**:用于欺骗的设备ID和配置数据来源。 - **示例**:网络适配器、存储控制器或任何不在主机PC上使用的通用PCIe卡。 - **DMA FPGA卡** - **描述**:能够执行DMA操作的基于FPGA的设备。 - **示例**:Squirrel (35T)、EnigmaX1 (75T)、ZDMA (100T)、Kintex-7 - **JTAG程序员** - **用途**:用于将固件闪存到FPGA。 - **示例**:Xilinx Platform Cable USB、Digilent JTAG USB Cable ### **4.2 软件** - **Vivado** - **描述**:Xilinx的FPGA开发软件,用于综合和构建固件项目。 - **下载**: [Xilinx Vivado](https://www.xilinx.com/support/download.html) - **Visual Studio** - **描述**:用于编辑Verilog或VHDL代码的集成开发环境(IDE)。 - **下载**: [Visual Studio Community](https://visualstudio.microsoft.com/vs/community/) - **PCILeech-FPGA** - **描述**:用于DMA固件开发的存储库和基础代码。 - **存储库**: [PCILeech-FPGA 在 GitHub 上](https://github.com/ufrisk/pcileech-fpga) - **Arbor** - **描述**:用于收集设备信息的PCIe设备扫描工具。 - **下载**: [MindShare 的 Arbor](https://www.mindshare.com/software/Arbor) - **注意**:需要创建账户;提供14天试用。 - **替代工具** - **Telescan PE** - **描述**:可以作为Arbor替代的PCIe流量分析工具。 - **下载**: [Teledyne LeCroy Telescan PE](https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software) - **注意**:免费但需要手动注册批准。 ### **4.3 环境设置** 1. **安装Vivado** - **步骤**: 1. 访问 [Xilinx Vivado 下载页面](https://www.xilinx.com/support/download.html)。 2. 下载与您的FPGA设备兼容的适当版本。 3. 按照Xilinx提供的安装说明进行安装。 4. 启动Vivado并确保其正确配置。 2. **安装Visual Studio** - **步骤**: 1. 访问 [Visual Studio 下载页面](https://visualstudio.microsoft.com/vs/community/)。 2. 下载并安装 **Visual Studio Community Edition**。 3. 在安装过程中,确保包括与**使用C++进行桌面开发**相关的工作负载,以支持硬件描述语言(HDL)如Verilog或VHDL。 3. **克隆PCILeech-FPGA存储库** - **步骤**: 1. 打开终端或命令提示符。 2. 使用Git克隆存储库: ```bash git clone https://github.com/ufrisk/pcileech-fpga.git ``` 3. 进入克隆的目录: ```bash cd pcileech-fpga ``` 4. **设置干净的开发环境** - **建议**:在隔离的环境中工作,以防止意外交互,尤其是如果使用固件进行敏感任务如恶意软件分析。 - **步骤**: 1. 使用专用的开发机器或虚拟环境。 2. 确保没有其他应用程序干扰PCIe操作或FPGA编程。 --- ## **5. 收集捐赠设备信息** 精确的设备仿真依赖于从捐赠设备中提取关键信息。这些数据使您的FPGA能够在PCIe配置和行为方面模拟目标硬件。 ### **5.1 使用Arbor进行PCIe设备扫描** **Arbor**是一个强大的工具,用于扫描PCIe设备并提取必要的信息。按照以下步骤收集捐赠设备的详细信息: 1. **安装Arbor** - **步骤**: 1. 访问 [Arbor下载页面](https://www.mindshare.com/software/Arbor)。 2. 如果需要,创建一个账户。 3. 下载并安装Arbor到您的系统上。 2. **扫描PCIe设备** - **步骤**: 1. 启动Arbor。 2. 导航到 **本地系统** 标签。 3. 在 **扫描选项** 下,确保默认设置适当。 4. 点击 **扫描/重新扫描** 以检测所有连接的PCIe设备。 3. **识别捐赠设备** - **标准**: - 不应在主机PC上使用。 - 示例:PCIe WiFi卡、存储控制器或通用PCIe设备。 - **步骤**: 1. 在扫描设备列表中找到您的捐赠设备。 2. 点击设备以查看详细配置。 4. **捕获设备数据** - **需要提取的信息**: - **设备ID** - **厂商ID** - **子系统ID** - **修订ID** - **基地址寄存器(BARs)** - **功能**(例如,MSI、电源管理、PCIe链路宽度/速度) - **设备序列号(DSN)**(如果可用) - **步骤**: 1. 导航到Arbor中的 **PCI配置** 标签。 2. 滚动浏览 **解码** 部分,找到并记录上述详细信息。 3. 截屏或记录每个值,以便在固件定制过程中参考。 - **示例提取**: ![设备ID](https://github.com/Silverr12/DMA-CFW-Guide/assets/89455475/8baec3fe-c4bd-478e-9f95-d262804d6f67) ![厂商ID](https://github.com/Silverr12/DMA-CFW-Guide/assets/89455475/39c7de6d-d8db-4744-b0a0-ddeca0dfd7d7) ![修订ID](https://github.com/Silverr12/DMA-CFW-Guide/assets/89455475/c2374ea7-ca9c-47b7-8a8d-4ceff5dffe3b) ![BAR大小](https://github.com/Silverr12/DMA-CFW-Guide/assets/89455475/19239179-057a-4ed5-a79f-45cf242787a5) ![子系统ID](https://github.com/Silverr12/DMA-CFW-Guide/assets/89455475/94522a95-70bd-4336-8e38-58c0839e38ad) ![DSN](https://github.com/Silverr12/DMA-CFW-Guide/assets/89455475/595ae3e2-4cd8-4b3d-bcfa-cf6a59f289d5) - **注意**:并非所有设备都包含DSN。如果不可用,在定制过程中DSN字段使用零即可。 ### **5.2 提取和记录设备属性** 扫描后,确保准确记录捐赠设备的以下属性: 1. **设备ID**:硬件设备的唯一标识符。 2. **厂商ID**:设备制造商的标识符。 3. **子系统ID**:标识与设备相关联的特定子系统。 4. **修订ID**:硬件版本的修订号。 5. **基地址寄存器(BARs)**:定义设备的内存和I/O地址区域。 6. **功能**:如电源管理(PM)、MSI/MSI-X、PCIe链路速度和宽度。 7. **设备序列号(DSN)**:如果适用,与设备关联的唯一序列号。 **重要注意事项**: - **BAR大小**:确保内存映射I/O区域与捐赠设备的配置匹配。 - **功能**:正确仿真所有功能以确保与主机系统的无缝集成。 - **DSN**:提高仿真的逼真度;如果可用,请使用。 --- ## **6. 初始固件定制** 在掌握必要的捐赠设备信息后,继续定制固件中的PCIe配置空间和内存映射,以欺骗捐赠设备。 ### **6.1 修改配置空间** 1. **导航到配置文件** - **路径**:`/PCIeSquirrel/src/pcileech_pcie_cfg_a7.sv` - **描述**:此Verilog文件包含设备的PCIe配置逻辑。 2. **在Visual Studio中打开文件** - **步骤**: 1. 启动 **Visual Studio**。 2. 打开位于 `/PCIeSquirrel/src/` 目录下的 `pcileech_pcie_cfg_a7.sv` 文件。 3. **修改设备ID和厂商ID** - **步骤**: 1. 使用 **Ctrl + F** 搜索 `cfg_deviceid`。 2. 使用捐赠设备的值更新设备ID: ```verilog cfg_deviceid <= 16'hXXXX; // 将XXXX替换为捐赠设备的设备ID ``` 3. 同样,搜索 `cfg_vendorid` 并更新: ```verilog cfg_vendorid <= 16'hYYYY; // 将YYYY替换为捐赠设备的厂商ID ``` 4. **修改子系统ID** - **步骤**: 1. 搜索 `cfg_subsysid`。 2. 更新子系统ID: ```verilog cfg_subsysid <= 16'hZZZZ; // 将ZZZZ替换为捐赠设备的子系统ID ``` 5. **根据捐赠设备调整BARs** - **步骤**: 1. 找到BAR大小配置。 2. 设置BAR大小以匹配捐赠设备: ```verilog bar0_size <= 32'hXXXX_YYYY; // 将XXXX_YYYY替换为捐赠设备的BAR0大小 ``` 3. 根据需要重复设置其他BAR(BAR1, BAR2等)。 - **示例**: ```verilog bar0_size <= 32'h00004000; // BAR0的16KB ``` ### **6.2 插入设备序列号(DSN)** 如果您的捐赠设备有**设备序列号(DSN)**,将其纳入固件可以增强仿真的逼真度。 1. **定位DSN字段** - **步骤**: 1. 在 `pcileech_pcie_cfg_a7.sv` 中搜索 `rw[127:64]`。 2. 该字段代表 `cfg_dsn`(配置空间设备序列号)。 2. **插入DSN** - **步骤**: 1. 用捐赠设备的DSN替换占位符: ```verilog rw[127:64] <= 64'hXXXXXXXX_YYYYYYYY; // 将X和Y替换为捐赠设备的DSN ``` 2. **示例**: - **捐赠设备DSN**:上DW:`01 00 00 00`,下DW:`68 4C E0 00` - **组合DSN**:`64'h01000000684CE000` ```verilog rw[127:64] <= 64'h01000000684CE000; // 捐赠设备的DSN ``` - **无DSN可用**: ```verilog rw[127:64] <= 64'h0000000000000000; // 无DSN ``` 3. **保存更改** - **步骤**: 1. 修改DSN后,保存文件以保留更改。 --- ## **7. Vivado项目设置与定制** 在定制配置空间后,将这些更改集成到Vivado项目中,以准备固件进行综合和实现。 ### **7.1 生成Vivado项目文件** 1. **打开Vivado** - **步骤**: 1. 在您的开发机器上启动 **Vivado**。 2. 确保Vivado已正确安装并为您的FPGA设备配置。 2. **访问Tcl控制台** - **步骤**: 1. 在Vivado中,找到应用程序窗口底部的 **Tcl控制台**。 2. 如果不可见,导航到 **窗口 > Tcl控制台** 以显示它。 3. **导航到PCIeSquirrel目录** - **步骤**: 1. 在Tcl控制台中,确定当前目录: ```tcl pwd ``` 2. 切换到克隆的 `pcileech-fpga` 存储库中的 `PCIeSquirrel` 文件夹: ```tcl cd C:/Users/YourUsername/Desktop/pcileech-fpga/PCIeSquirrel ``` *根据您的设置替换 `YourUsername` 和路径。* - **注意**:如果遇到反斜杠 (`\`) 的错误,使用正斜杠 (`/`): ```tcl cd C:/Users/YourUsername/Desktop/pcileech-fpga/PCIeSquirrel ``` 4. **生成Vivado项目** - **步骤**: 1. 在Tcl控制台中,执行项目生成脚本: ```tcl source vivado_generate_project.tcl -notrace ``` 2. 等待脚本完成。此过程将使用必要的配置设置Vivado项目。 5. **打开生成的项目** - **步骤**: 1. 成功生成后,Vivado应自动打开 `.xpr`(Vivado项目)文件。 2. 保持项目打开以进行进一步的定制。 ### **7.2 修改IP模块** 1. **访问PCIe IP核** - **步骤**: 1. 在 **Sources** 窗格中,导航到: ``` pcileech_squirrel_top > i_pcileech_pcie_a7 : pcileech_pcie_a7 ``` 2. 双击PCIe IP核 (`i_pcie_7x_0 : pcie_7x_0`) 以打开 **重新定制IP** 窗口。 2. **定制设备ID和BARs** - **步骤**: 1. 在 **重新定制IP** 对话框中,导航到 **IDs** 标签。 2. 输入从捐赠设备收集的 **设备ID**、**厂商ID** 和 **子系统ID**。 3. 验证 **类代码**: - 返回Arbor或您的扫描工具,以确定捐赠设备的类代码。 - 在 **重新定制IP** 窗口中,设置类代码以匹配捐赠设备。 4. **示例**: - **设备ID**:`0x1234` - **厂商ID**:`0xABCD` - **子系统ID**:`0x5678` - **类代码**:`0x030000`(例如,网络控制器) 3. **配置BAR大小** - **步骤**: 1. 在 **重新定制IP** 对话框中导航到 **BARs** 标签。 2. 设置 **BAR0大小** 以匹配捐赠设备的BAR0大小。 - **示例**:如果捐赠设备的BAR0是16KB: ```tcl BAR0 Size: 16KB ``` 3. 如果捐赠设备使用了额外的BAR(BAR1、BAR2等),请重复设置。 4. **完成IP定制** - **步骤**: 1. 设置所有必要参数后,点击 **确定** 以应用更改。 2. Vivado可能会提示重新生成IP核;确认并允许过程完成。 5. **锁定IP核** - **目的**:防止Vivado在综合过程中覆盖手动配置。 - **步骤**: 1. 打开Vivado中的 **Tcl控制台**。 2. 执行以下命令以锁定IP核: ```tcl set_property is_managed false [get_files pcie_7x_0.xci] ``` 3. **解锁**(如果将来需要): ```tcl set_property is_managed true [get_files pcie_7x_0.xci] ``` --- ## **8. 高级固件定制** 为了实现精确的1:1仿真,进一步定制PCIe参数、BARs、内存映射、电源管理和中断处理。 ### **8.1 配置用于仿真的PCIe参数** 1. **匹配PCIe链路速度和宽度** - **重要性**:确保仿真设备以与捐赠设备相同的速度和宽度进行通信。 - **步骤**: 1. 在 `pcileech_pcie_cfg_a7.sv` 中,找到PCIe链路速度和宽度配置。 2. 更新这些参数以匹配捐赠设备的规格。 ```verilog pcie_link_speed <= 4'bXXXX; // 将XXXX替换为捐赠设备的PCIe链路速度 pcie_link_width <= 8'b00000100; // 将其替换为捐赠设备的PCIe链路宽度(例如x1、x4、x8) ``` - **示例**: - **捐赠设备PCIe链路速度**:Gen3(8 GT/s) - **捐赠设备PCIe链路宽度**:x4 ```verilog pcie_link_speed <= 4'b0011; // Gen3 pcie_link_width <= 8'b00000100; // x4 ``` 2. **设置能力指针** - **目的**:确保PCIe功能正确链接并被主机系统识别。 - **步骤**: 1. 在 `pcileech_pcie_cfg_a7.sv` 中找到能力指针配置。 2. 设置能力指针以匹配捐赠设备的配置。 ```verilog capability_pointer <= 8'h40; // 示例值;根据捐赠设备的能力指针替换 ``` ### **8.2 调整BAR和内存映射** 精确的内存映射对于仿真硬件设备至关重要。基地址寄存器(BARs)定义设备的内存和寄存器在系统内存空间中的位置。 1. **设置BAR大小** - **步骤**: 1. 在 `pcileech_pcie_cfg_a7.sv` 中,找到BAR大小分配。 2. 将BAR大小设置为与捐赠设备匹配。 ```verilog bar0_size <= 32'h00004000; // BAR0的16KB bar1_size <= 32'h00008000; // BAR1的32KB(如果适用) ``` 2. **定义BAR地址空间** - **步骤**: 1. 确保BAR地址空间不重叠,并与捐赠设备的内存布局匹配。 2. 使用记录的BAR大小适当地设置地址范围。 ```verilog bar0_addr <= 32'hF0000000; // 示例地址;根据捐赠设备的BAR0地址替换 bar1_addr <= 32'hF0004000; // 示例地址;根据需要替换 ``` 3. **处理多个BAR** - **步骤**: 1. 如果捐赠设备使用多个BAR,请重复配置每个BAR。 2. 确保每个BAR的大小和地址与捐赠设备的规格一致。 ### **8.3 仿真设备电源管理和中断** 正确仿真电源管理和中断处理确保主机系统与仿真设备无缝交互。 1. **电源管理(PM)配置** - **步骤**: 1. 在 `pcileech_pcie_cfg_a7.sv` 中,找到电源管理能力设置。 2. 设置PM能力以匹配捐赠设备。 ```verilog PM_CAP_VERSION <= 4'b0011; // 示例版本;根据捐赠设备的PM版本替换 PM_CAP_D1SUPPORT <= 1'b1; // 如果捐赠设备支持D1,则启用 PM_CAP_AUXCURRENT <= 4'b1000; // 示例值;根据捐赠设备调整 PM_CSR_NOSOFTRST <= 1'b0; // 示例值;根据需要调整 ``` 2. **MSI/MSI-X(中断)配置** - **步骤**: 1. 在 `pcileech_pcie_cfg_a7.sv` 中找到MSI/MSI-X配置。 2. 启用并配置MSI/MSI-X以正确处理中断。 ```verilog MSI_CAP_64_BIT_ADDR_CAPABLE <= 1'b1; // 如果支持,启用64位MSI cfg_interrupt <= 1'b1; // 启用MSI中断 ``` 3. **实现中断处理逻辑** - **步骤**: 1. 在 `pcileech_pcie_cfg_a7.sv` 中,确保中断信号正确路由。 ```verilog assign cfg_interrupt_di = cfg_int_di; assign cfg_interrupt_assert = cfg_int_assert; ``` 2. 测试中断功能,确保主机系统正确接收和处理来自仿真设备的中断。 --- ## **9. 仿真设备特定功能** 为了实现真正的1:1仿真,除了基本的PCIe交互之外,还必须复制捐赠设备的独特功能。 ### **9.1 实现高级PCIe功能** 大多数PCIe设备支持**高级错误报告(AER)**、**链路速度协商**和**扩展能力**等高级功能。仿真这些功能确保主机系统将仿真设备视为与捐赠设备相同。 1. **高级错误报告(AER)** - **步骤**: 1. 在 `pcileech_pcie_cfg_a7.sv` 中,找到AER配置。 2. 如果捐赠设备支持,启用AER。 ```verilog AER_CAP_VERSION <= 4'b0001; // 示例版本;根据捐赠设备的AER版本替换 AER_CAP_NEXTPTR <= 8'h00; // 适当地设置下一个指针 ``` 3. 实现错误处理逻辑以管理与AER相关的事件。 2. **链路速度协商** - **步骤**: 1. 确保PCIe链路速度和宽度协商与捐赠设备匹配。 2. 如 **8.1** 所述,调整链路速度设置。 3. **扩展能力** - **步骤**: 1. 确定捐赠设备使用的任何扩展能力(例如,厂商特定的扩展能力、LTR、VSEC)。 2. 通过在 `pcileech_pcie_cfg_a7.sv` 中定义适当的寄存器和逻辑,实现场这些能力。 ```verilog // 示例:厂商特定的扩展能力 VSEC_CAP_ID <= 16'hXXXX; // 将XXXX替换为厂商特定的ID VSEC_CAP_VERSION <= 8'hYY; // 将YY替换为版本 VSEC_CAP_NEXTPTR <= 8'hZZ; // 下一个能力指针 ``` ### **9.2 仿真厂商特定功能** 一些设备包含专有或厂商特定的功能,必须准确仿真以确保与主机系统的无缝集成。 1. **识别厂商特定功能** - **步骤**: 1. 使用PCIe流量分析工具(例如,Wireshark、Teledyne LeCroy)监控厂商特定的TLP。 2. 记录捐赠设备在典型操作中使用的独特寄存器、命令或行为。 2. **实现厂商特定逻辑** - **步骤**: 1. 在 `pcileech_pcie_cfg_a7.sv` 中,添加逻辑以处理厂商特定功能。 ```verilog // 示例:厂商特定寄存器 vendor_specific_reg <= 32'hXXXXXXXX; // 将其替换为实际值 ``` 2. 确保任何专有命令或响应被准确复制。 3. **测试厂商特定功能** - **步骤**: 1. 使用厂商特定的驱动程序或应用程序与仿真设备交互。 2. 验证所有专有功能是否按预期运行。 --- ## **10. 事务层数据包(TLP)仿真** 准确仿真事务层数据包(TLP)对于确保基于FPGA的设备与主机系统无缝通信至关重要,模仿捐赠设备的行为。 ### **10.1 理解和捕获TLP** TLP是PCIe通信的基本单元,处理内存读写、配置访问和中断信号。 1. **从捐赠设备捕获TLP** - **步骤**: 1. 使用PCIe分析工具如 **Teledyne LeCroy的Telescan PE** 或支持PCIe的 **Wireshark** 监控捐赠设备生成的TLP。 2. 记录捐赠设备在典型操作中使用的TLP的结构、类型和模式。 2. **分析TLP结构** - **TLP的组成部分**: - **头字段**:定义类型、格式、地址和其他控制信息。 - **数据载荷**:实际传输的数据。 - **尾字段**:附加信息,如字节计数和序列号。 - **示例TLP结构**: ```verilog tlps_static.tdata[127:0] = {TLP头字段, 数据载荷}; ``` 3. **仿真合法流量** - **步骤**: 1. 确保FPGA生成的TLP在类型、地址、长度和数据方面与捐赠设备捕获的TLP一致。 2. 实现处理不同类型TLP的逻辑,如内存写、内存读和配置访问。 ### **10.2 为特定操作制作自定义TLP** 为了准确模仿捐赠设备,您必须制作自定义TLP,以复制其在各种操作中的行为。 1. **内存写TLP示例** - **描述**:表示对系统内存的写操作。 - **Verilog示例**: ```verilog tlp_mem_write <= { 1'b0, // 保留位 7'b10_00000, // TLP类型:内存写 1'b0, // TLP格式 address[31:0], // 写入地址 data[31:0] // 数据载荷 }; ``` 2. **内存读TLP示例** - **描述**:表示从系统内存的读操作。 - **Verilog示例**: ```verilog tlp_mem_read <= { 1'b0, // 保留位 7'b00_00000, // TLP类型:内存读 1'b0, // TLP格式 address[31:0], // 读取地址 tag[7:0] // 事务识别标签 }; ``` 3. **配置访问TLP示例** - **描述**:表示配置空间访问。 - **Verilog示例**: ```verilog tlp_config_access <= { 1'b0, // 保留位 7'b01_00000, // TLP类型:配置读/写 1'b0, // TLP格式 config_address[31:0], // 配置空间地址 config_data[31:0] // 配置数据载荷 }; ``` 4. **中断信号TLP示例** - **描述**:表示向CPU发送中断信号。 - **Verilog示例**: ```verilog tlp_interrupt <= { 1'b0, // 保留位 7'b11_00000, // TLP类型:中断 1'b0, // TLP格式 interrupt_address[31:0], // 与中断相关的地址 interrupt_data[31:0] // 中断数据载荷 }; ``` 5. **实现TLP处理器** - **步骤**: 1. 在固件中,实现不同TLP类型的处理器,以确保正确处理和响应。 2. 使用状态机或逻辑块管理TLP生成、处理和响应处理。 --- ## **11. 构建、闪存和测试** 在定制固件并确保所有配置与捐赠设备一致后,继续在您的FPGA设备上构建、闪存和测试固件。 ### **11.1 综合与实现** 1. **运行综合** - **步骤**: 1. 在Vivado中,点击 **运行综合**。 2. 监控综合过程中的任何警告或错误。 3. 在继续之前解决任何关键问题。 2. **运行实现** - **步骤**: 1. 综合成功后,启动 **运行实现**。 2. 确保实现阶段在没有关键警告的情况下完成。 3. 查看实现报告以识别任何潜在问题。 3. **生成比特流** - **步骤**: 1. 一旦实现完成,点击 **生成比特流**。 2. 确认生成比特流的任何提示。 3. 等待比特流生成成功完成。 ### **11.2 闪存比特流** 1. **通过JTAG连接FPGA** - **步骤**: 1. 确保您的FPGA设备通过JTAG接口连接到主机系统。 2. 为FPGA设备供电。 2. **打开Vivado硬件管理器** - **步骤**: 1. 在Vivado中,导航到 **窗口 > 硬件管理器**。 2. 点击 **打开目标 > 自动连接** 以检测连接的FPGA设备。 3. **编程FPGA** - **步骤**: 1. 在硬件管理器中,右键点击检测到的设备并选择 **编程设备**。 2. 浏览到生成的比特流文件(`pcileech_squirrel_top.bit`)。 3. 点击 **编程** 以将固件闪存到FPGA。 4. 通过硬件管理器控制台确认编程成功。 ### **11.3 测试与验证** 1. **验证设备检测** - **步骤**: 1. 使用 **lspci**(在Linux上)或 **设备管理器**(在Windows上)验证FPGA是否被检测为捐赠设备。 2. 确认 **设备ID**、**厂商ID**、**子系统ID** 和 **BARs** 是否与捐赠设备的规格匹配。 - **示例(Linux)**: ```bash lspci -vvv -s ``` 2. **内存映射测试** - **步骤**: 1. 访问设备的 **BARs** 以确保正确的内存映射。 2. 使用内存访问工具或简单的读写操作测试响应性。 3. **中断测试** - **步骤**: 1. 通过仿真设备触发中断。 2. 验证主机系统是否正确接收和处理这些中断。 3. 使用系统日志或诊断工具确认中断处理。 4. **性能测试** - **步骤**: 1. 运行DMA速度测试工具以测量数据传输速率。 2. 将性能指标与预期值进行比较,以确保固件的稳定性和效率。 - **示例工具**: - **PCILeech DMA速度测试**:在PCILeech工具集中可用。 - **自定义基准测试脚本**:执行读写操作以测量性能。 5. **配置空间验证** - **步骤**: 1. 使用诊断工具检查PCIe配置空间。 2. 确保所有字段(设备ID、厂商ID、BARs、功能)正确设置并与捐赠设备匹配。 - **示例(Linux)**: ```bash lspci -vvv -s ``` --- ## **12. 高级调试技术** 在开发定制固件时,遇到问题是常见的。高级调试技术可以帮助有效地识别和解决这些问题。 ### **12.1 使用Vivado的集成逻辑分析仪** Vivado的**集成逻辑分析仪(ILA)**允许实时监控内部FPGA信号,有助于调试和验证。 1. **设置ILA探针** - **步骤**: 1. 在Vivado中,导航到 **Sources > 添加源** 并添加一个 **集成逻辑分析仪**。 2. 在PCIe通信路径的关键点插入ILA探针,例如TLP生成器或BAR访问控制器。 ```verilog // 示例:为TLP数据添加ILA探针 wire [127:0] tlp_data; assign tlp_data = tlps_static.tdata[127:0]; ila_0 probe ( .clk(clk), .probe0(tlp_data) ); ``` 2. **配置触发器** - **步骤**: 1. 打开 **ILA** 配置对话框。 2. 根据特定事件设置触发条件,例如TLP生成或内存访问。 ```verilog // 示例触发条件:内存写TLP的开始 if (tlp_type == MEMORY_WRITE && tlp_valid) begin trigger_signal <= 1; end ``` 3. **分析信号波形** - **步骤**: 1. 启用ILA探针运行FPGA。 2. 使用Vivado的 **波形查看器** 检查捕获的信号波形。 3. 识别时序问题、不正确的逻辑状态或意外行为。 - **优势**: - 实时查看内部信号。 - 能够捕获和分析TLP处理过程中的瞬态问题。 ### **12.2 PCIe流量分析工具** 除了Vivado的ILA,外部PCIe流量分析工具提供了深入了解FPGA与主机系统之间PCIe通信的能力。 1. **带有PCIe扩展的Wireshark** - **描述**:Wireshark可以通过适当的扩展或插件捕获和分析PCIe流量。 - **步骤**: 1. 安装带有PCIe支持的Wireshark。 2. 配置Wireshark以捕获PCIe流量。 3. 分析捕获的TLP,以确保其符合预期的捐赠设备行为。 2. **Teledyne LeCroy Telescan PE** - **描述**:专业级PCIe流量分析工具,提供全面的PCIe流量监控和分析功能。 - **步骤**: 1. 安装Teledyne LeCroy的Telescan PE。 2. 将其连接到您的系统以监控PCIe流量。 3. 使用其分析功能捕获和解析FPGA与主机系统之间交换的TLP。 3. **Total Phase Beagle** - **描述**:PCIe流量分析仪,允许实时捕获和分析PCIe通信。 - **步骤**: 1. 使用Total Phase Beagle PCIe分析仪设置您的系统。 2. 配置其以监控和捕获PCIe流量。 3. 使用其分析功能验证TLP的完整性和行为。 **使用PCIe流量分析工具的优势**: - **全面的TLP分析**:详细检查TLP,确保准确的仿真。 - **错误检测**:识别格式错误的TLP或意外的事务模式。 - **性能指标**:测量数据传输速率并识别瓶颈。 --- ## **13. 故障排除** 在固件开发过程中遇到问题是常见的。本节提供了在仿真过程中可能遇到的常见问题的解决方案。 ### **13.1 设备检测问题** **问题**:主机系统未能检测到FPGA作为捐赠设备。 **解决方案**: 1. **验证设备ID** - **步骤**: 1. 仔细检查固件中的 **设备ID**、**厂商ID** 和 **子系统ID** 是否与捐赠设备匹配。 2. 确保配置空间中没有拼写错误或不正确的值。 2. **检查PCIe链路训练** - **步骤**: 1. 使用PCIe诊断工具验证PCIe链路是否正确训练。 2. 确保链路速度和宽度配置与捐赠设备匹配。 3. **确保正确的BAR配置** - **步骤**: 1. 确认 **BAR大小** 和 **地址范围** 是否准确设置。 2. 确保没有重叠或冲突的BAR配置。 4. **电源和连接检查** - **步骤**: 1. 确保FPGA设备已正确连接并通电。 2. 重新插拔PCIe卡以确保连接牢固。 ### **13.2 内存映射和BAR配置错误** **问题**:不正确的内存映射导致内存访问失败或不准确。 **解决方案**: 1. **仔细检查BAR大小和地址** - **步骤**: 1. 验证固件中的每个BAR大小是否与捐赠设备的配置匹配。 2. 确保BAR地址空间设置正确且不重叠。 2. **使用诊断工具** - **步骤**: 1. 利用 **lspci** 或 **Arbor** 等工具检查PCIe配置空间。 2. 确认BARs是否正确映射并可访问。 3. **调整内存区域** - **步骤**: 1. 如果内存区域不可访问,调整BAR配置以更好地匹配系统的内存映射。 2. 确保固件逻辑正确处理内存读/写操作。 ### **13.3 DMA性能和TLP错误** **问题**:DMA性能缓慢或与事务层数据包(TLP)相关的错误。 **解决方案**: 1. **优化TLP生成** - **步骤**: 1. 确保TLP格式正确且无错误。 2. 使用Vivado的ILA和PCIe流量分析工具识别并修正格式错误的TLP。 2. **调整有效载荷大小** - **步骤**: 1. 将最大读取请求和有效载荷大小设置为4KB或捐赠设备支持的最高值。 ```verilog max_read_request_size <= 4; // 4KB max_payload_size <= 4; // 4KB ``` 2. 避免设置超出捐赠设备支持的有效载荷大小,以防止系统不稳定。 3. **检查PCIe链路设置** - **步骤**: 1. 验证PCIe链路速度和宽度是否正确配置。 2. 确保FPGA与主机系统准确协商链路参数。 4. **固件完整性** - **步骤**: 1. 审查并验证固件的所有最近更改,确保没有引入无意的修改。 2. 如果性能问题持续存在,恢复到已知稳定的固件版本。 --- ## **14. 仿真精度和优化** 确保仿真的精度对于无缝集成和不可检测的行为至关重要。本节概述了提高仿真精确度和优化性能的技术。 ### **14.1 精确时序仿真的技术** 匹配捐赠设备的时序特性确保主机系统与仿真设备交互时如同与原始硬件设备一样。 1. **使用匹配的时钟域** - **步骤**: 1. 确保FPGA的时钟与PCIe链路的时钟速率匹配。 2. 同步FPGA内部的时钟,以符合PCIe时序要求。 2. **控制响应延迟** - **步骤**: 1. 实现寄存器或计数器,以管理TLP确认和中断处理的响应时间。 2. 确保响应延迟与捐赠设备的典型响应时间匹配。 3. **实现流水线阶段** - **步骤**: 1. 在FPGA设计中使用流水线技术,以与捐赠设备的数据处理阶段对齐。 2. 这减少了延迟,并确保及时的TLP生成和处理。 ### **14.2 对系统调用的动态响应** 基于系统交互仿真设备的动态行为,确保FPGA设备在各种条件下适当响应。 1. **实现状态机** - **步骤**: 1. 在FPGA中设计状态机,以管理仿真设备的不同操作状态。 2. 确保状态之间的过渡基于系统调用和交互,模仿捐赠设备的行为。 2. **跟踪并响应系统请求** - **步骤**: 1. 监控传入的系统请求,并动态调整设备的响应。 2. 确保FPGA固件能够处理不同的工作负载,并准确响应不同类型的TLP。 3. **处理异步事件** - **步骤**: 1. 实现逻辑,以管理异步事件如中断或错误条件。 2. 确保固件能够以与捐赠设备一致的方式生成和响应这些事件。 --- ## **15. 固件开发的最佳实践** 遵循最佳实践确保开发过程高效、可维护且安全。 ### **15.1 持续测试和文档记录** - **频繁测试** - **步骤**: 1. 每次修改后进行定期测试,以确保固件按预期运行。 2. 使用自动化脚本或测试台持续验证固件功能。 - **记录更改** - **步骤**: 1. 为固件的每次更改保持详细的文档记录。 2. 包括更改的原因及其对整体设计的影响。 ### **15.2 管理固件版本** - **使用版本控制** - **步骤**: 1. 实施版本控制系统(例如 **Git**),以管理固件的不同迭代版本。 2. 定期提交更改,并附上描述性消息,以跟踪项目的演变。 - **分支策略** - **步骤**: 1. 使用分支管理功能开发、修复漏洞和实验性更改。 2. 仅在彻底测试后将稳定分支合并到主分支。 ### **15.3 安全考虑** - **防止未经授权的访问** - **步骤**: 1. 确保固件不会将系统内存或硬件暴露给未经授权的访问。 2. 在固件中实施访问控制和验证检查。 - **保护固件完整性** - **步骤**: 1. 避免在固件开发过程中引入漏洞或后门。 2. 定期进行安全审查和代码审计,以维护固件的完整性。 - **安全处理敏感数据** - **步骤**: 1. 如果固件与敏感数据交互,实施加密和安全的数据处理实践。 2. 确保通过固件接口或日志不泄露敏感信息。 --- ## **16. 附加资源** 为了进一步提升您在开发用于设备仿真的定制固件方面的理解和能力,以下资源非常宝贵: - **PCILeech-FPGA 存储库** - **链接**: [https://github.com/ufrisk/pcileech-fpga](https://github.com/ufrisk/pcileech-fpga) - **Vivado FPGA 文档** - **链接**: [Xilinx Vivado 文档](https://www.xilinx.com/support/documentation.html) - **PCI-SIG 规范** - **链接**: [PCI-SIG](https://pcisig.com) - **PCIe TLP 初学者教程** - **链接**: [PCIe TLP 初学者教程](https://www.xillybus.com/tutorials/pci-express-tlp-pcie-primer-tutorial-guide-1) - **Teledyne LeCroy Telescan PE 文档** - **链接**: [Teledyne LeCroy Telescan PE](https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software) - **Wireshark PCIe 扩展** - **链接**: [Wireshark 扩展](https://www.wireshark.org/docs/) - **现场可编程门阵列(FPGA)基础** - **链接**: [FPGA 基础](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2020_2/ug901-vivado-tutorial.pdf) - **Arbor 软件用户指南** - **链接**: [Arbor 用户指南](https://www.mindshare.com/software/Arbor) - **PCIe 规范和指南** - **链接**: [PCIe 规范](https://pcisig.com/specifications) ================================================ FILE: CN/README.md ================================================ # **全设备仿真的定制固件开发指南** --- **特别鸣谢慷慨捐助的传奇人物,我将很快与您联系。如果您愿意,请DM我,我会在本文中添加鸣谢并提供更多信息!** 正在将此指南整理到[维基](https://github.com/JPShag/PCILeech-DMA-Firmware/wiki/Introduction)中。欢迎提供帮助! ---- **作者留言及指南状态:** 我正在透明地分享这一切,因为最近的日子异常艰难。除了因欺诈性退款造成的巨大经济损失外,我还面临多重生活和健康困境,严重影响了我上网和投入项目的时间。坦率地说,在这些个人困难中,继续创作像本指南这样全面的资源已成为一项深刻的挣扎。 这预计是主指南的最后一次重大迭代。对于已经熟悉基本硬件概念(例如,FTDI芯片的功能)的更有经验的用户,我们将提供一个简洁的精简版。 如果您觉得这项工作有价值并能够提供帮助,任何形式的支持都将不胜感激。您的慷慨使我尽管面临持续的挑战,仍能继续为这个社区做出贡献。我真诚地希望本指南已经并将继续成为一份宝贵的资源。 --- ## 纪念与献词 ![Ross](https://github.com/user-attachments/assets/de7f12fe-8992-4738-a6af-712dc48217ee) 本指南谨献给 **Ross Freeman (1947–1989)** 的记忆 作为一位富有远见的工程师、杰出的密歇根人,以及Xilinx的联合创始人,Ross Freeman被广泛认为是现场可编程门阵列(FPGA)技术之父,该技术彻底改变了计算领域。 在1984年,半导体行业主要专注于固定功能芯片之时,Freeman敢于想象一种不同的范式:制造后可以重新编程的硬件。他的革命性专利(#4,870,302)和对可重构计算的不懈倡导,开启了一个四十年后仍在改变我们世界的科技范式。 他的开创性创新使得在无需承担传统ASIC开发高昂成本的情况下,快速原型化和部署定制芯片解决方案成为可能,从而使硬件设计民主化,并加速了无数领域的技术进步。 如今,Freeman的愿景驱动着人工智能、高性能计算、电信、汽车系统、航空航天应用以及他在世时仅是梦想的许多其他领域的尖端发展。 他于2009年被追授进入国家发明家名人堂,其遗产不仅体现在硅片中,更体现在挑战我们所有人质疑既定限制并想象新可能性的技术勇气精神中。 *"FPGA的最终目标是制造可编程逻辑器件,以取代标准数字芯片。"* — Ross Freeman --- ## **目录** ### **第一部分:基础概念** 1. [引言](#1-引言) * [1.1 本指南的目的](#11-本指南的目的) * [1.2 目标读者](#12-目标读者) * [1.3 如何使用本指南](#13-如何使用本指南) 2. [关键定义](#2-关键定义) 3. [设备兼容性](#3-设备兼容性) * [3.1 支持的基于FPGA的硬件](#31-支持的基于fpga的硬件) * [3.2 PCIe硬件注意事项](#32-pcie硬件注意事项) * [3.3 系统要求](#33-系统要求) 4. [要求](#4-要求) * [4.1 硬件](#41-硬件) * [4.2 软件](#42-软件) * [4.3 环境设置](#43-环境设置) 5. [收集捐赠设备信息](#5-收集捐赠设备信息) * [5.1 使用Arbor进行PCIe设备扫描](#51-使用arbor进行pcie设备扫描) * [5.2 提取和记录设备属性](#52-提取和记录设备属性) 6. [初始固件定制](#6-初始固件定制) * [6.1 修改配置空间](#61-修改配置空间) * [6.2 插入设备序列号(DSN)](#62-插入设备序列号dsn) 7. [Vivado项目设置与定制](#7-vivado项目设置与定制) * [7.1 生成Vivado项目文件](#71-生成vivado项目文件) * [7.2 修改IP核](#72-修改ip核) ### **第二部分:中级概念与实现** 8. [高级固件定制](#8-高级固件定制) * [8.1 配置PCIe参数以进行仿真](#81-配置pcie参数以进行仿真) * [8.2 调整BARs和内存映射](#82-调整bars和内存映射) * [8.3 仿真设备电源管理和中断](#83-仿真设备电源管理和中断) 9. [仿真设备特定功能](#9-仿真设备特定功能) * [9.1 实现高级PCIe功能](#91-实现高级pcie功能) * [9.2 仿真厂商特定功能](#92-仿真厂商特定功能) 10. [事务层数据包(TLP)仿真](#10-事务层数据包tlp仿真) * [10.1 理解和捕获TLP](#101-理解和捕获tlp) * [10.2 制作用于特定操作的定制TLP](#102-制作用于特定操作的定制tlp) ### **第三部分:高级技术与优化** 11. [构建、烧录与测试](#11-构建烧录与测试) * [11.1 综合与实现](#111-综合与实现) * [11.2 烧录比特流](#112-烧录比特流) * [11.3 测试与验证](#113-测试与验证) 12. [高级调试技术](#12-高级调试技术) * [12.1 使用Vivado的集成逻辑分析仪](#121-使用vivado的集成逻辑分析仪) * [12.2 PCIe流量分析工具](#122-pcie流量分析工具) 13. [故障排除](#13-故障排除) * [13.1 设备检测问题](#131-设备检测问题) * [13.2 内存映射和BAR配置错误](#132-内存映射和bar配置错误) * [13.3 DMA性能和TLP错误](#133-dma性能和tlp错误) 14. [仿真精度与优化](#14-仿真精度与优化) * [14.1 精确定时仿真技术](#141-精确定时仿真技术) * [14.2 对系统调用的动态响应](#142-对系统调用的动态响应) 15. [固件开发最佳实践](#15-固件开发最佳实践) * [15.1 持续测试与文档](#151-持续测试与文档) * [15.2 管理固件版本](#152-管理固件版本) * [15.3 安全注意事项](#153-安全注意事项) 16. [其他资源](#16-其他资源) 17. [联系方式](#17-联系方式) 18. [支持与贡献](#18-支持与贡献) --- ## **第一部分:基础概念** --- ## **1. 引言** ### **1.1 本指南的目的** 本指南的总体目标是让您掌握开发基于现场可编程门阵列(FPGA)设备的定制直接内存访问(DMA)固件的知识和实践技能。这种专用固件允许您的FPGA精确地仿真其他PCIe(Peripheral Component Interconnect Express)硬件设备的身份和行为。这种仿真是一种强大的技术,在多个高级领域具有深远意义: **硬件安全研究**: * **漏洞发现**:通过仿真设备,您可以创建一个受控环境,向主机驱动程序发送格式错误或意外数据,系统性地进行模糊测试,以发现可能通过硬件外设利用的漏洞(例如,缓冲区溢出、竞态条件)。 * **驱动程序分析**:观察操作系统和特定驱动程序如何与硬件交互。您可以仿真具有非标准配置或未文档化功能的设备,以了解驱动程序行为、识别安全假设或逆向工程专有协议。 * **侧信道分析**:虽然更复杂,但仿真设备可以通过精确控制外设操作,潜在地协助进行与通过时序或功耗分析进行信息泄漏相关的实验。 **红队演练与渗透测试**: * **绕过安全措施**:仿真一个看似良性或白名单的硬件设备(例如,一个常见的网卡或存储控制器),以获取DMA权限。一旦实现,这允许直接与系统内存交互,可能绕过在更高软件层运行的端点检测和响应(EDR)系统或反恶意软件解决方案。 * **隐蔽持久性**:仿真恶意设备可以提供一种隐蔽的方式来维护对受损系统的访问,因为它可能比基于软件的植入物更难检测。 * **利用信任关系**:系统通常对连接的硬件有隐式信任。定制固件可以通过模仿被授予特定权限或访问的设备来利用这一点。 **系统调试与诊断**: * **可复现的测试平台**:创建高度特定的硬件场景,以可靠地复现可能仅在特定设备状态或数据模式下发生的难以捉摸的错误。 * **故障注入**:故意仿真有缺陷的设备行为(例如,错误的TLP形成、延迟响应),以测试主机系统及其驱动程序的健壮性和错误处理能力。 **硬件测试与验证**: * **驱动程序开发**:在物理原型可用之前,或为了模拟比物理可访问的更广泛的硬件变体,针对仿真硬件配置文件测试新的或修改的驱动程序。 * **合规性测试**:虽然不能替代官方合规性测试,但仿真设备可以帮助预验证PCIe协议遵守的某些方面。 **传统系统支持与互操作性**: * 仿真老旧、停产或难以采购的PCIe设备,以保持传统系统运行或弥合不同硬件代之间的兼容性差距。 通过学习本指南,您将熟练掌握: * 精细地从物理“捐赠”PCIe设备中提取识别属性和配置细节。 * 修改和扩展现有开源FPGA固件框架(主要关注广泛使用的PCILeech-FPGA项目),以采用捐赠设备的身份。 * 配置和利用以Xilinx Vivado为核心的专业FPGA开发工具链,以及Visual Studio Code等基本代码编辑工具。 * 对PCIe架构的分层模型、DMA数据传输机制以及低级别复制硬件行为的固件开发细微之处,形成扎实的理解。 ### **1.2 目标读者** 本指南专为已具备计算机系统、硬件原理和软件开发基础到中级知识的个人量身定制。内容技术性强,并假定读者具备进行详细、低级别工作的能力。具体来说,它面向以下人群: * **固件开发人员**:旨在为FPGA设计或改编固件的工程师,特别是涉及高速数据传输(DMA)和通过PCIe直接硬件接口操作的应用。强烈建议具备Verilog/VHDL背景和FPGA开发工具经验。 * **硬件工程师**:参与PCIe硬件设计、测试或验证的专业人员。本指南可以帮助创建复杂的测试线束或在更大的系统设计中仿真组件。预计熟悉PCIe协议和数字设计。 * **网络安全专业人员与研究人员**: * **漏洞研究员与漏洞利用开发人员**:希望探索硬件级攻击面或开发利用DMA的概念验证漏洞。操作系统内部、内存管理和驱动程序架构的理解至关重要。 * **红队成员**:寻求通过直接硬件操作来获取系统访问、持久性和数据窃取的先进技术操作员。 * **数字取证与事件响应人员**:虽然本指南侧重于攻击,但理解这些技术有助于识别和分析复杂的基于硬件的攻击。 * **FPGA爱好者与高级业余爱好者**:有FPGA项目经验,渴望应对PCIe通信和硬件仿真等复杂挑战的个人。愿意深入研究数据手册和技术规范是关键。 学习曲线可能很陡峭,特别是如果PCIe或高级FPGA概念是新知识。然而,本指南旨在将复杂主题分解为可管理的步骤。 ### **1.3 如何使用本指南** 本指南分为三个逻辑递进的部分,旨在逐步构建您的知识: * **第一部分:基础概念**:这第一部分至关重要。它介绍了核心术语、PCIe和DMA的基本原理、必要的硬件和软件堆栈(包括Xilinx Vivado和PCILeech-FPGA框架等工具的设置说明),以及从目标“捐赠”设备获取重要信息和进行基本固件修改的初始程序。强烈建议按顺序彻底学习本部分。 * **第二部分:中级概念与实现**:(后续章节)在基础知识之上,本部分将引导您进行更高级的固件定制。主题将包括微调PCIe操作参数、仿真设备特定寄存器和功能(如电源管理状态和消息信号中断 - MSI/MSI-X),以及初步理解事务层数据包(TLP)的构建和解释。 * **第三部分:高级技术与优化**:(后续章节)最后一部分将探讨复杂的调试方法(包括使用集成逻辑分析仪 - ILA和外部PCIe协议分析仪)、优化固件性能和仿真精度的技术、常见和复杂问题的全面故障排除,以及关于最佳实践的关键讨论,特别关注开发和部署仿真PCIe设备的安全影响。 **学习本指南的步骤**: * **顺序学习**:特别是对于第一部分和第二部分,请按顺序学习各节,因为后面的概念建立在前面的基础之上。 * **动手实践**:这是一份实践指南。请在您自己的硬件上积极执行设置步骤、代码修改和实验。 * **适应您的环境**:文件路径、特定设备ID和软件版本可能有所不同。理解指令背后的概念,以使其适应您的特定设置。 * **查阅外部资源**:PCIe规范和FPGA文档是您的最终参考。本指南进行简化和引导,但深入研究通常需要查阅原始资料。 * **迭代开发**:固件开发很少是线性的。预期会进行迭代、调试和改进您的设计。广泛使用故障排除部分和调试技术。 您将使用HDL(PCILeech-FPGA中的SystemVerilog)、FPGA综合和实现工具(Vivado),并可能使用主机端编程工具和PCIe分析实用程序。 --- ## **2. 关键定义** 牢固掌握以下术语对于理解PCIe设备仿真和定制固件开发的复杂性至关重要。这些术语将在整个指南中广泛使用。 * **DMA (Direct Memory Access)** (直接内存访问): * **定义**:现代计算机体系结构的一项基本功能,允许硬件外设(如网卡、GPU或您的基于FPGA的仿真设备)直接读取和写入主系统内存(RAM),而无需CPU参与每个字节的传输。 * **重要性**:DMA对于高性能I/O操作至关重要。通过将数据传输任务从CPU卸载,它使CPU能够执行其他计算,显著提高整体系统吞吐量和效率。在本指南中,您的FPGA将利用DMA与主机系统的内存进行交互,这是一种在安全研究和红队演练中经常被利用的强大功能。 * **PCIe (Peripheral Component Interconnect Express)** (外围组件互连高速): * **定义**:一种高速串行计算机扩展总线标准,旨在取代旧的总线标准,如PCI、PCI-X和AGP。它采用点对点拓扑结构,每个设备通过独立的串行链路连接到根联合体(通常是芯片组或CPU的一部分)。通信通过数据包进行。 * **重要性**:PCIe是连接高性能外设到主板的主导标准。理解其协议、分层架构(物理层、数据链路层、事务层)和配置机制对于仿真任何现代硬件设备至关重要。 * **TLP (Transaction Layer Packet)** (事务层数据包): * **定义**:PCIe协议事务层的数据交换基本单位。TLP负责在PCIe设备之间传输请求(例如,内存读/写、I/O读/写、配置读/写)和完成(对请求的响应)。每个TLP由一个报头、一个可选的数据有效载荷和一个可选的端到端CRC(ECRC)组成。 * **重要性**:为了精确仿真设备,您的FPGA固件必须能够正确地形成、传输、接收和解释与捐赠设备行为匹配的TLP。理解TLP类型、格式和流控制对于高级仿真至关重要。 * **BAR (Base Address Register)** (基地址寄存器): * **定义**:位于PCIe设备的配置空间内,BAR是特殊的寄存器,设备通过它们向主机系统请求地址空间资源。一个设备最多可以有六个32位BAR(或更少,或成对的32位BAR可以形成64位BAR)。这些寄存器定义了设备用于向主机CPU公开其寄存器和内部内存的内存映射I/O(MMIO)区域或I/O端口区域的起始地址和大小。 * **重要性**:当主机系统枚举PCIe设备时,它会读取BAR以确定设备的内存和I/O要求,然后分配并用系统中物理地址图中的实际基地址来编程这些BAR。您的仿真设备必须精确定义其BAR以匹配捐赠设备,以便主机操作系统和驱动程序能够正确地与其交互。 * **FPGA (Field-Programmable Gate Array)** (现场可编程门阵列): * **定义**:一种集成电路(IC),可以在制造后由设计者或客户进行配置——因此称为“现场可编程”。FPGA包含一个可编程逻辑块阵列和可重构互连的层次结构,允许这些块“连接”起来以实现定制数字逻辑电路。 * **重要性**:FPGA是本指南中使用的核心硬件。其可重构特性使其成为仿真其他硬件设备的理想选择,因为您可以定义精确的逻辑和接口来模仿捐赠设备的PCIe存在和行为。 * **MSI/MSI-X (Message Signaled Interrupts / Message Signaled Interrupts Extended)** (消息信号中断 / 扩展消息信号中断): * **定义**:允许PCIe设备通过向系统定义的内存地址写入特殊消息(TLP,特别是内存写入TLP)来向CPU传递中断的机制,而不是使用专用的物理中断线(如传统PCI)。MSI-X是MSI的增强版,提供更多的中断向量和更大的灵活性。 * **重要性**:大多数现代PCIe设备使用MSI或MSI-X以实现更高效、更灵活的中断处理。精确仿真通常需要实现捐赠设备选择的中断机制,包括配置MSI/MSI-X能力结构并正确生成中断消息。 * **DSN (Device Serial Number)** (设备序列号): * **定义**:一个64位全局唯一标识符,可由PCIe设备可选实现。如果存在,它通常位于设备配置空间内的扩展能力结构中。 * **重要性**:虽然并非所有设备都具有DSN,但某些驱动程序或管理软件可能会使用它进行唯一标识、许可或跟踪。正确仿真它对于完全透明和避免检测到仿真设备可能很重要。 * **PCIe Configuration Space** (PCIe配置空间): * **定义**:与每个PCIe功能(一个设备可以有多个功能)关联的标准化256字节(对于Type 0、端点设备)或4KB地址区域。此空间包含有关设备的重要信息,包括其厂商ID、设备ID、类别代码、修订ID、BAR、能力指针以及各种状态和控制寄存器。主机系统使用特殊的配置读和配置写TLP访问此空间。 * **重要性**:配置空间是PCIe设备的“身份证”。设备仿真的第一步就是将捐赠设备配置空间的相关部分精确复制到您的FPGA固件中。主机系统使用此信息来识别、配置和分配资源给设备。 * **Donor Device** (捐赠设备): * **定义**:您旨在在FPGA上仿真其身份和行为的物理PCIe硬件设备。该设备作为提取配置细节(厂商ID、设备ID、BAR设置、能力等)和行为模式的来源。 * **重要性**:您的仿真 fidelity 直接取决于您能够多么精确和完整地收集并复制捐赠设备的特性。 * **Root Complex (RC)** (根联合体): * **定义**:PCIe层级结构中将CPU和内存子系统连接到PCIe结构的实体。它代表CPU生成PCIe事务,并处理下游PCIe设备发起的事务。它还执行初始的总线枚举和配置。 * **重要性**:您的仿真设备在与主机系统通信时,将主要与根联合体(或与其连接的交换机)交互。 * **Endpoint (EP)** (端点): * **定义**:位于PCIe结构外围,消费或生产数据的一种PCIe设备。示例包括网卡、显卡、存储控制器以及您将要编程的FPGA设备。端点请求资源并向根联合体发起事务。 * **重要性**:在本指南中,您的FPGA将被编程为充当一个端点设备,仿真一个特定的捐赠端点。 * **HDL (Hardware Description Language)** (硬件描述语言): * **定义**:一种专用计算机语言,用于描述电子电路的结构、设计和操作,特别是数字逻辑电路。常见的HDL包括Verilog和VHDL。 * **重要性**:您将在PCILeech-FPGA项目中使用Verilog(特别是SystemVerilog,Verilog的扩展)来定义仿真设备的定制逻辑。 * **Bitstream** (比特流): * **定义**:加载到FPGA上的最终配置文件,用于编程其逻辑块和互连,从而实现您的定制硬件设计。它是FPGA开发工具(如Xilinx Vivado)的编译输出。 * **重要性**:生成和烧录正确的比特流是将定制固件部署到FPGA的最终步骤。 --- ## **3. 设备兼容性** 成功且精确的PCIe设备仿真取决于确保您选择的基于FPGA的硬件和主机系统配置完全兼容。本节详细介绍了支持的FPGA平台、关键的PCIe硬件注意事项以及设置开发环境所需的系统要求。 ### **3.1 支持的基于FPGA的硬件** 虽然本指南提供了一种可适用于各种基于FPGA的DMA硬件的通用方法,但我们的主要示例和具体说明将侧重于 **Xilinx 7系列FPGA**,由于其性能和可访问性的平衡,它们在开源DMA板中很常见。**Squirrel DMA (35T)** 卡因其受欢迎程度以及与PCILeech-FPGA框架的良好兼容性而受到强调。 定制PCIe IP核和开发硬件描述语言(HDL)逻辑的核心原则和技术广泛适用于以下FPGA系列和特定板卡: * **Squirrel (Artix-7 35T)** * **描述**:一种广泛可用且经济高效的基于FPGA的DMA设备,采用Xilinx Artix-7 35T FPGA。它为标准内存采集任务以及各种基本到中级设备仿真项目提供了足够的逻辑资源和内存。它是初次接触基于FPGA的DMA的优秀起点。 * **主要特点**:Artix-7提供了良好的性能价格比,适用于教育和研究目的。 * **Enigma-X1 (Artix-7 75T)** * **描述**:与35T相比,提供增强的逻辑和内存资源的中级FPGA,通常基于Xilinx Artix-7 75T FPGA。这为更复杂的仿真场景、更大的内存映射区域或需要额外FPGA逻辑的更复杂的DMA操作提供了更大的灵活性。 * **主要特点**:增加的逻辑单元和块RAM(BRAM)支持更复杂的设计。 * **ZDMA (Artix-7 100T)** * **描述**:基于更高性能的Artix-7 100T FPGA,针对要求更高的内存交互和大量的读/写操作进行了优化。此板卡适用于大规模DMA解决方案、高吞吐量仿真或需要大量片上内存的项目。 * **主要特点**:100T变体在资源方面提供了显著升级,是突破仿真界限的理想选择。 * **Kintex-7 (K325T, K410T等)** * **描述**:代表高级别,Kintex-7 FPGA(例如K325T、K410T)为高度复杂的项目、大规模DMA解决方案以及需要更高PCIe通道数或速度(例如,Gen3 x8/x16)的应用提供了强大的功能。虽然价格更昂贵,但它们提供了更多的逻辑、DSP切片和内存,从而能够仿真高度复杂和苛刻的捐赠设备。 * **主要特点**:用于更快PCIe世代的高性能收发器,丰富的逻辑和内存资源,适用于复杂设计。 **关于FPGA系列的重要说明**:尽管原理相似,但不同的Xilinx 7系列FPGA(Artix-7、Kintex-7、Zynq-7000 PS/PL)之间,特定的IP核配置和时钟结构可能略有不同。请始终参考特定板卡文档和您所选FPGA系列的Xilinx PCIe IP核用户指南。PCILeech-FPGA项目通常提供板卡特定的Tcl脚本和源文件以简化此过程。 ### **3.2 PCIe硬件注意事项** 为了确保基于FPGA的DMA设备在仿真中平稳无限制地运行,需要仔细考虑一些PCIe特定和主机系统功能,并在某些情况下进行修改。 * **IOMMU / VT-d / AMD-Vi 设置** * **建议**:对于初始设置和测试,**强烈建议在系统的BIOS/UEFI设置中禁用IOMMU(Intel的定向I/O虚拟化技术 - VT-d)或AMD的等效技术(AMD-Vi)**。 * **理由**:IOMMU是为DMA功能设备提供内存管理单元的硬件组件。它们执行地址转换,类似于CPU的MMU,并且可以强制执行内存访问权限。虽然它们对于安全和虚拟化(防止恶意设备访问未经授权的内存区域)至关重要,但它们**会**限制DMA设备对系统内存的访问,可能干扰内存采集和设备仿真。禁用IOMMU允许DMA设备不受限制地访问内存,这对于高级仿真和安全研究目的通常是必要的。 * **位置**:通常在BIOS/UEFI中的“CPU Configuration”、“Virtualization”、“Advanced Settings”或“I/O Virtualization”下找到。 * **内核DMA保护(Windows)/ Thunderbolt安全级别(Linux)** * **建议(Windows)**:在现代Windows系统中禁用**内核DMA保护**功能。这包括**基于虚拟化的安全性(VBS)**和**内存完整性(HVCI)**等设置。这些功能利用IOMMU来防止通过Thunderbolt或PCIe连接的外部外设进行未经授权的DMA攻击。 * **步骤(Windows)**: * 访问Windows安全设置:**开始 > 设置 > 隐私和安全性 > Windows 安全中心 > 设备安全性**。 * 在“核心隔离”下,点击“核心隔离详细信息”。 * 关闭“内存完整性”。 * 您可能还需要在BIOS/UEFI中禁用安全启动,因为VBS通常依赖于它。 * **注意**:禁用这些功能会显著**降低您系统的安全态势**,使其容易受到包括涉及恶意DMA设备的各种攻击。这应该只在专用测试系统上进行,而不是在您的主机器上,并且在您了解风险的安全、隔离环境中进行。 * **建议(Linux/Thunderbolt)**:如果使用带有Thunderbolt端口的系统,请了解并可能调整BIOS/UEFI中的**Thunderbolt安全级别**。较低的安全级别(例如,“无安全”、“用户授权”)通常是任意Thunderbolt/PCIe设备在未经明确主机批准的情况下执行DMA所必需的。 * **PCIe插槽要求** * **建议**:使用与FPGA设备要求物理匹配的兼容PCIe插槽。大多数基于Artix-7的DMA卡在PCIe Gen2 x1或x4下运行。 * **理由**: * **物理匹配**:x1卡可以插入x1、x4、x8或x16插槽,但x4卡至少需要x4插槽。 * **性能**:虽然x4卡*可能*在x1插槽中工作(如果物理连接是开放式或已修改的),但它将以x1速度运行,严重限制数据传输速率。为了获得最佳性能和精确仿真捐赠设备的功能,请确保FPGA板卡安装在提供至少*仿真*链路宽度和速度的插槽中(例如,如果您要仿真Gen2 x4设备,请在主机上使用Gen2 x4插槽)。 * **主板BIOS设置**:一些主板允许配置PCIe插槽速度(例如,强制Gen1或Gen2)。确保这些设置不与您期望的仿真速度冲突。 ### **3.3 系统要求** 建立一个健壮的开发环境对于高效的固件开发、综合和调试至关重要。 * **主机系统** * **处理器**:现代多核CPU对于运行Vivado等FPGA开发工具至关重要,这些工具在综合和实现过程中计算密集。(例如,Intel Core i5/i7/i9 或 AMD Ryzen 5/7/9 等效处理器,建议8代或更新)。 * **内存(RAM)**:强烈建议最低16 GB RAM;对于复杂FPGA设计,**32 GB 或更高是理想选择**,因为Vivado会消耗大量内存,尤其是在实现阶段。 * **存储**:一个固态硬盘(SSD)并至少有 **200 GB 的可用空间** 至关重要。FPGA工具安装(仅Vivado就可能超过50 GB)、项目文件以及综合/实现输出会迅速占用磁盘空间。SSD的速度能显著缩短构建时间。 * **操作系统**: * **Windows 10/11 (64位 专业版或企业版)**:Xilinx Vivado 和许多硬件调试工具广泛支持。请记住内核DMA保护的注意事项。 * **兼容的Linux发行版 (64位)**:Ubuntu LTS(长期支持)版本(例如 20.04、22.04)是Vivado常用且支持良好的系统。Linux通常为脚本编写和低级PCIe交互工具提供更灵活的环境。 * **外围设备** * **JTAG编程器**:将编译后的比特流烧录到基于FPGA的DMA卡上绝对必需。示例包括Xilinx Platform Cable USB II、Digilent JTAG-HS3 或某些开发板上集成的JTAG编程器。确保它与您的FPGA板卡和Vivado兼容。 * **PCIe插槽**:如第3.2节所述,确保您的主机系统有可用的兼容PCIe插槽用于DMA卡。 * **USB端口**:用于连接JTAG编程器,并可能用于连接FPGA板卡的UART/串行控制台以进行调试输出。 --- ## **4. 要求** 本节概述了进行PCIe设备仿真定制固件开发所必需的基本硬件和软件组件,以及推荐的环境设置。在开始之前,具备这些先决条件将简化您的开发过程。 ### **4.1 硬件** * **捐赠PCIe设备** * **目的**:这是您打算在FPGA上仿真其配置和行为的物理硬件设备。它作为关键识别细节、寄存器值和操作特性的权威来源。 * **示例**:常见示例包括标准网卡(NIC)、SATA或NVMe存储控制器、USB控制器,或任何其他您可以安全地从系统中移除进行分析的通用PCIe扩展卡。强烈建议使用对系统操作非必需的设备,因为您将检查其低级配置。 * **DMA FPGA卡** * **描述**:一种基于FPGA的开发板,专门设计或改编用于通过PCIe接口执行直接内存访问(DMA)操作。这是您的定制固件将加载到的平台。 * **示例**:如第3.1节所述,兼容卡包括 **Squirrel (Artix-7 35T)**、**Enigma-X1 (Artix-7 75T)**、**ZDMA (Artix-7 100T)** 或各种基于 **Kintex-7** 的解决方案。确保您选择的卡具有PCIe金手指连接器。 * **JTAG编程器** * **目的**:这个关键工具促进了您的开发PC与DMA卡上FPGA之间的通信。它用于将编译后的比特流编程(烧录)到FPGA上,更重要的是,用于使用Vivado的硬件管理器和集成逻辑分析仪(ILA)等工具进行交互式调试。 * **示例**: * **Xilinx Platform Cable USB II**:Xilinx FPGA传统且广泛兼容的编程器。确保您已安装必要的驱动程序。 * **Digilent JTAG-HS3 / JTAG-HS2**:流行且可靠的编程器,以良好的Vivado集成和支持而闻名。HS3提供更快的编程速度。 * **集成JTAG**:某些FPGA板可能具有板载USB转JTAG桥(例如FTDI芯片),这消除了对独立编程器的需求。请查阅您的板卡文档。 ### **4.2 软件** * **Xilinx Vivado Design Suite** * **描述**:Xilinx(现为AMD)官方的、全面的FPGA开发环境。Vivado对于综合您的HDL代码、将设计实现到目标FPGA上、生成最终比特流以及执行硬件调试至关重要。它包括必要的IP核、编译器和实用程序。 * **下载**:访问Xilinx(AMD)官方下载页面:[https://www.xilinx.com/support/download.html](https://www.xilinx.com/support/download.html)。 * **版本说明**:虽然一些旧指南可能引用Vivado 2020.1等旧版本,但强烈建议下载与您的目标FPGA系列(Artix-7、Kintex-7)兼容的**最新稳定版本**(例如Vivado 2023.x或更高版本)。PCILeech-FPGA项目通常支持较新的Vivado版本。 * **Visual Studio Code** * **描述**:Microsoft出品的高度可定制且功能丰富的代码编辑器。它是编写和编辑Verilog/SystemVerilog HDL代码的绝佳选择,因为它拥有广泛的扩展生态系统,提供语法高亮、代码检查、自动补全和版本控制集成等功能。 * **下载**:[https://code.visualstudio.com/](https://code.visualstudio.com/) * **PCILeech-FPGA** * **描述**:一个用于基于FPGA的DMA开发的开源框架和基础代码库。它提供了即插即用的PCIe IP核实例化和一个结构良好的项目,是定制固件的绝佳起点。本指南将大量利用其架构。 * **仓库**:[https://github.com/ufrisk/pcileech-fpga](https://github.com/ufrisk/pcileech-fpga) * **Arbor (MindShare)** * **描述**:一款强大且用户友好的软件工具,专门设计用于深入扫描和分析PCIe设备。它提供了对连接PCIe硬件的配置空间、功能和寄存器的详细洞察,对于收集捐赠设备信息来说非常有价值。 * **下载**:可从MindShare网站获取:[https://www.mindshare.com/](https://www.mindshare.com/)(您可能需要导航到他们的软件部分)。 * **注意**:通常需要创建账户,并且可能提供限时试用。 * **替代PCIe设备分析工具** * **Telescan PE (Teledyne LeCroy)**: * **描述**:Teledyne LeCroy提供的一款免费PCIe流量分析和设备枚举工具。虽然它主要是一款与其硬件协议分析仪交互的软件工具,但它也可以在没有专用硬件的情况下提供一些基本的配置空间视图。 * **下载**:[https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software](https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software) * **注意**:需要手动注册和批准才能下载。 * **OS原生工具(用于基本检查)**: * **Windows设备管理器**:在设备属性的“详细信息”选项卡下提供基本的厂商ID、设备ID、子系统ID和类别代码信息。 * **Linux `lspci` 工具**:一个强大的命令行工具,用于检查PCIe设备。使用`lspci -nn`查看厂商/设备ID,`lspci -vvv`查看包括BAR和功能在内的详细信息,`lspci -s -xxxx`用于原始配置空间转储。 ### **4.3 环境设置** 一个干净且正确配置的开发环境对于避免常见陷阱并确保流畅的工作流程至关重要。 #### **4.3.1 安装Xilinx Vivado设计套件** **步骤**: 1. **访问Xilinx (AMD) Vivado下载页面**:[https://www.xilinx.com/support/download.html](https://www.xilinx.com/support/download.html)。 2. **下载适当版本**:选择与您的操作系统兼容的最新稳定版Vivado,更重要的是,它必须与您的特定FPGA设备(例如Artix-7、Kintex-7)兼容。查阅Vivado发行说明以了解设备支持情况。 3. **运行安装程序**:执行下载的安装程序并仔细遵循屏幕上的说明。 4. **选择必要组件**:在安装过程中,系统会提示您选择要安装的设备家族。**至关重要的是,选择与您的FPGA板卡对应的设备家族(例如,Artix-7/Kintex-7的“7 Series”)**。这与安装所有家族相比,能节省大量磁盘空间。确保您选择“设计工具”(综合、实现)和“编程与调试”组件。 5. **启动Vivado**:安装完成后,启动Vivado以确认它能无错误打开,并且许可证(如果适用)已正确配置。 #### **4.3.2 安装Visual Studio Code** **步骤**: 1. **访问Visual Studio Code下载页面**:[https://code.visualstudio.com/](https://code.visualstudio.com/)。 2. **下载并安装**:下载适用于您操作系统的安装程序,并遵循标准安装提示。 3. **安装HDL支持扩展**:安装VS Code后,打开它并导航到扩展视图(Ctrl+Shift+X或Cmd+Shift+X)。搜索并安装适用于Verilog/SystemVerilog的相关扩展,例如: * **Verilog-HDL/SystemVerilog** (由mshr-h提供) * **VHDL** (如果您也使用VHDL) 这些扩展提供了语法高亮、代码检查和其他有用的功能。 #### **4.3.3 克隆PCILeech-FPGA仓库** 此仓库包含您将要修改的基础固件结构和脚本。 **步骤**: 1. **打开终端或命令提示符**:(例如,Windows上的Git Bash,Linux上的Terminal)。 2. **导航到您想要的目录**:选择一个您想存储项目的位置。 ```bash cd ~/Projects/ # 在Linux/macOS上 cd C:\Users\YourUsername\Documents\Projects\ # 在Windows上 ``` 3. **克隆仓库**: ```bash git clone https://github.com/ufrisk/pcileech-fpga.git ``` 4. **导航到克隆的目录**: ```bash cd pcileech-fpga ``` 这将是您的主项目目录。PCILeech-FPGA项目通常包含不同板卡变体的子目录(例如`pcileech-artix-7-50t`、`pcileech-squirrel-35t`)。您将根据您的特定硬件导航到相关的板卡特定目录。 #### **4.3.4 设置一个干净的开发环境** **建议**:始终在隔离或专用的环境中工作,尤其是在处理低级硬件和潜在的安全隐患时。 **步骤**: 1. **使用专用开发机或虚拟机**: * **物理机**:如果可能,使用一台单独的物理计算机进行FPGA开发和测试。这可以防止在您的主机器上发生意外的系统不稳定或安全风险。 * **虚拟机(VM)**:虚拟机可以是隔离开发环境的好选择。然而,通常需要向虚拟机进行直接PCIe直通(PCIe热插拔或VT-d直通),FPGA卡才能被正确检测和操作,这可能配置复杂,并且如果操作不当,仍然可能暴露主机。对于初始工具安装和代码编辑,虚拟机完全没问题。 2. **最小化后台应用程序**:确保没有其他资源密集型应用程序正在运行,这些应用程序可能会干扰Vivado在综合和实现过程中的性能。 3. **禁用冲突软件**:在开发和测试期间,暂时禁用任何可能干扰低级硬件访问或JTAG通信的防病毒、防火墙或安全软件。完成工作后请记得重新启用它们。 --- ## **5. 收集捐赠设备信息** 精确的设备仿真取决于精细地提取和复制捐赠设备的关键信息。这种全面的数据收集使您的FPGA能够忠实地模仿目标硬件的PCIe配置和行为,确保与主机系统接口时的兼容性和功能性。 ### **5.1 使用Arbor进行PCIe设备扫描** **Arbor** 是一款强大且用户友好的工具,专为深入扫描PCIe设备而设计。它提供了对连接硬件配置空间的详细洞察,使其成为提取设备仿真所需信息的宝贵资源。 #### **5.1.1 安装Arbor** 要开始使用Arbor进行设备扫描,您必须首先在系统上安装该软件。 **步骤:** 1. **访问Arbor下载页面:** * 使用您偏好的网页浏览器导航到MindShare官方网站([https://www.mindshare.com/](https://www.mindshare.com/))。您需要找到他们的“Software”或“Downloads”部分来定位Arbor。 * 确保您直接访问该网站,以避免任何恶意重定向。 2. **创建账户(如果需要):** * Arbor可能要求您创建用户账户才能访问下载链接。 * 提供必要的信息,例如您的姓名、电子邮件地址和组织。 * 如果出现提示,请验证您的电子邮件以激活您的账户。 3. **下载Arbor:** * 登录后,找到Arbor的下载部分。 * 选择与您的操作系统兼容的版本(例如,Windows 10/11 64位)。 * 点击 **Download** 按钮并将安装程序保存到计算机上已知的位置。 4. **安装Arbor:** * 找到下载的安装程序文件(例如,`ArborSetup.exe`)。 * 右键单击安装程序并选择 **以管理员身份运行** 以确保它具有必要的权限。 * 按照屏幕上的说明完成安装过程。 * 接受许可协议。 * 选择安装目录。 * 如果需要,选择创建桌面快捷方式。 5. **验证安装:** * 安装完成后,确保Arbor列在您的“开始”菜单或桌面上。 * 启动Arbor以确认它能无错误打开。 #### **5.1.2 扫描PCIe设备** 安装Arbor后,您可以继续扫描系统中的PCIe设备。 **步骤:** 1. **启动Arbor:** * 双击桌面上的Arbor图标或通过“开始”菜单找到它。 * 如果用户账户控制(UAC)提示,允许应用程序对设备进行更改。 2. **导航到本地系统选项卡:** * 在Arbor界面中,找到导航窗格或选项卡。 * 单击 **Local System** 以访问扫描本地机器的工具。 3. **扫描PCIe设备:** * 查找 **Scan** 或 **Rescan** 按钮,通常位于界面的顶部或底部。 * 点击 **Scan/Rescan** 以启动检测过程。 * 等待扫描过程完成;这可能需要几分钟,具体取决于连接的设备数量。 4. **审查检测到的设备:** * 扫描完成后,Arbor将显示所有检测到的PCIe设备的列表。 * 设备通常会列出其名称、设备ID和其他识别信息。 #### **5.1.3 识别捐赠设备** 识别正确的捐赠设备对于精确仿真至关重要。 **步骤:** 1. **在列表中找到您的捐赠设备:** * 滚动浏览Arbor检测到的设备列表。 * 查找与您的捐赠硬件的品牌和型号匹配的设备。 * 设备可能按其厂商名称、设备类型或功能列出。 2. **验证设备详细信息:** * 单击设备以选中它。 * 确认 **Device ID** 和 **Vendor ID** 与您的捐赠设备匹配。 * **提示:** 这些ID通常可以在设备文档或制造商网站上找到。对于常见设备,快速在网上搜索“\[设备名称] Vendor ID Device ID”通常能得到结果。 3. **查看详细配置:** * 选中设备后,找到并单击类似 **View Details** 或 **Properties** 的选项。 * 这将打开一个详细视图,显示设备的配置空间和功能。 4. **与物理硬件交叉引用:** * 如果列出了多个类似设备,请将 **Slot Number** 或 **Bus Address** 与安装捐赠设备的物理插槽交叉引用。这有助于确认您正在分析正确的硬件。 #### **5.1.4 捕获设备数据** 从捐赠设备中提取详细信息对于精确仿真至关重要。 **要提取的信息:** * **设备ID (0xXXXX):** 唯一标识设备型号的16位标识符。 * **厂商ID (0xYYYY):** 分配给制造商的16位标识符。 * **子系统ID (0xZZZZ):** 标识特定子系统或变体(例如,产品线中的特定型号)。 * **子系统厂商ID (0xWWWW):** 标识子系统的厂商(通常与主厂商ID相同,但对于OEM版本可能会有所不同)。 * **修订ID (0xRR):** 指示设备的硬件修订级别。 * **类别代码 (0xCCCCCC):** 一个24位代码,定义设备的主要功能/类型(例如,`0x020000`用于以太网控制器,`0x010802`用于NVMe控制器)。这有助于操作系统加载通用驱动程序。 * **基地址寄存器 (BARs):** * 定义设备使用的内存或I/O地址区域的寄存器。 * 包括BAR0到BAR5,每个都可能是32位或64位。对于每个BAR,请记录其 **类型(内存或I/O)**、**位宽(32位或64位)**、**大小(例如,256 MB,4KB)** 和 **可预取状态(是/否)**。这对于内存映射至关重要。 * **功能:** 列出支持的功能及其配置,通常在配置空间中的链表结构中找到。示例包括: * **PCIe功能结构**:PCIe链路速度(例如,Gen2,Gen3),链路宽度(例如,x1,x4),最大载荷大小,最大读取请求大小。 * **MSI/MSI-X功能结构**:消息信号中断信息,包括支持的向量数量。 * **电源管理功能结构**:支持的电源状态(D0,D1,D2,D3hot,D3cold)。 * **设备序列号 (DSN):** 一个64位唯一标识符,如果设备支持(在“设备序列号”扩展功能中找到)。并非所有设备都实现了此功能。 **步骤:** 1. **导航到PCI配置选项卡:** * 在设备详细视图中,找到并选择 **PCI Config** 或 **Configuration Space** 选项卡。这通常会以解码视图显示原始配置空间寄存器。 2. **记录相关详细信息:** * 仔细记录上面列出的每个所需字段。 * 使用截图或将值复制到文本文件、专用电子表格或结构化文档格式中以确保准确性。 * 确保十六进制值正确记录,包括是否使用`0x`前缀。 3. **展开功能列表:** * 查找标记为 **Capabilities** 或 **Advanced Features** 的部分。这些通常是可点击或可展开以显示子部分的。 * 记录存在的每个功能及其相关参数(例如,MSI消息控制,电源状态标志,当前/最大PCIe链路设置)。 4. **详细检查BAR:** * 在配置空间中,找到BAR0到BAR5的条目。 * 对于每个活动的BAR,记录其分配的大小、是内存映射还是I/O、其位宽(32位或64位)以及是否可预取。这些信息通常在Arbor的GUI中清晰显示。 5. **保存数据以备参考:** * 将所有提取的信息编译成一个组织良好的文档(例如,Markdown文件、`.txt`文件或Excel电子表格)。 * 为每个部分清晰标记,以便在固件定制期间轻松参考。 ### **5.2 提取和记录设备属性** 捕获数据后,理解每个属性的重要性并确保其准确记录对于成功仿真至关重要。 **确保您已准确记录以下内容:** 1. **设备ID:** * **目的:** 唯一标识PCIe设备的特定型号。 * **仿真用法:** 对于主机操作系统(OS)正确识别仿真设备至关重要,更重要的是,它能尝试加载适当的设备驱动程序。 2. **厂商ID:** * **目的:** 标识PCIe设备的制造商。 * **仿真用法:** 与设备ID结合使用,形成主机操作系统用于将设备与相应驱动程序匹配的唯一标识符(`VendorID:DeviceID`)。 3. **子系统ID和子系统厂商ID:** * **目的:** 这些可选ID允许区分同一厂商设备的变体,或区分主厂商/设备ID可能为通用的OEM特定版本。 * **仿真用法:** 对于仿真具有多种配置的设备或OEM提供的设备很重要,因为驱动程序可能会专门查找这些值。 4. **修订ID:** * **目的:** 指示设备的硬件修订级别。 * **仿真用法:** 有助于识别可能需要不同驱动程序、固件或具有细微行为差异的特定硬件版本。 5. **类别代码:** * **目的:** 一个24位代码,用于对设备的通用功能进行分类(例如,`0x020000`用于以太网控制器,`0x010802`用于NVMe控制器,`0x0C0300`用于USB主机控制器)。它由基本类别、子类别和编程接口组成。 * **仿真用法:** 允许操作系统理解设备的通用功能,并在找不到特定厂商驱动程序时加载通用类别驱动程序。这对于初始设备识别至关重要。 6. **基地址寄存器(BARs):** * **目的:** 定义设备用于寄存器、内部缓冲区或配置空间扩展的内存映射或I/O端口地址区域。主机操作系统在枚举期间将物理地址分配给这些BAR。 * **仿真用法:** 对于将仿真设备的内部内存和寄存器映射到主机系统的地址空间至关重要。每个BAR的大小、类型(内存/I/O,32/64位)和可预取状态必须与捐赠设备精确匹配。 7. **功能:** * **目的:** 列出设备支持的高级功能,如高级错误报告、电源管理、MSI/MSI-X、PCIe高级功能(如AER、VC/PF)等。每个功能由一个具有其自身寄存器的结构定义。 * **仿真用法:** 对于准确复制捐赠设备如何宣传其功能以及主机系统如何与这些功能交互(例如,中断传递机制、电源状态转换、错误报告)至关重要。 8. **设备序列号(DSN):** * **目的:** 设备的唯一64位标识符,通常是可选的扩展功能。 * **仿真用法:** 虽然可选,但某些驱动程序或管理应用程序可能会专门查询并依赖DSN进行识别、许可或安全检查。准确仿真此功能可以防止您的设备被检测为通用或修改的外设。 **数据收集的最佳实践:** * **组织数据:** 创建一个结构化的文档或电子表格。为每个属性使用清晰的标题和子标题。模板会很有益。 * **包含单位和格式:** 始终注明大小的单位(例如,MB、KB),并为十六进制值使用一致的格式(例如,`0x1234`、`16'h1234`)。 * **与规范交叉引用(如果可能):** 如果可用,查阅捐赠设备的数据手册或公开可用的规范以验证值。这有助于识别原始扫描中不明显或不寻常的配置。 * **保护数据:** 安全存储收集到的信息。请注意,这些数据可能包含专有或敏感信息。 * **理解“缺少什么”:** 像Arbor这样的专业工具非常出色,但它们可能无法捕捉复杂、高度专有设备的每一个细微之处(例如,标准配置空间之外的特定厂商定义寄存器)。对于高级仿真,您可能需要将此信息与捐赠设备驱动程序的逆向工程结合起来。 --- ## **6. 初始固件定制** 在细致地记录了捐赠设备的信息之后,下一个关键阶段是定制您的FPGA固件,以准确仿真捐赠设备。这个过程首先要修改PCIe配置空间中的关键识别寄存器,并确保设备序列号等特定标识符被正确集成。 ### **6.1 修改配置空间** PCIe配置空间是定义设备如何被识别并与主机系统在枚举期间交互的基本组件。精确定制此空间以匹配捐赠设备的配置文件对于成功仿真绝对至关重要,它能让主机操作系统加载正确的驱动程序并按预期交互。 #### **6.1.1 导航到配置文件** PCIe配置空间参数通常在PCILeech-FPGA项目中的特定SystemVerilog(`.sv`)文件中定义。此文件将综合成配置PCIe IP核并向主机公开设备身份的逻辑。 **PCILeech-FPGA(基于Artix-7的板卡,如Squirrel)的常见路径:** 找到负责为您特定板卡配置PCIe参数的文件。对于许多Artix-7 PCILeech变体,这将是: ``` pcileech-fpga//src/pcileech_pcie_cfg_a7.sv ``` * **示例(对于Squirrel 35T)**: ``` pcileech-fpga/pcileech-squirrel-35t/src/pcileech_pcie_cfg_a7.sv ``` *注意:实际的文件夹名称,如`pcileech-squirrel-35t`,可能会根据您克隆的PCILeech-FPGA的具体版本或分支略有不同。克隆主仓库后,请始终导航到相关的板卡特定子目录。* #### **6.1.2 在Visual Studio Code中打开文件** 编辑配置文件需要一个合适的代码编辑器,该编辑器支持SystemVerilog(或Verilog)的语法高亮,使代码更易于阅读和修改。 **步骤:** 1. **启动Visual Studio Code:** * 点击VS Code图标或通过“开始”菜单找到它。 2. **打开文件:** * 使用 **文件 > 打开文件** 或按下 `Ctrl + O`(macOS上为 `Cmd + O`)。 * 导航到第6.1.1节中确定的配置文件路径(例如,`pcileech-fpga/pcileech-squirrel-35t/src/pcileech_pcie_cfg_a7.sv`)。 * 选择文件并点击 **打开**。 3. **验证语法高亮:** * 确保编辑器识别 `.sv` 文件扩展名并应用正确的SystemVerilog语法高亮。如果不行,请返回第4.3.2节,确保您已安装推荐的Verilog/SystemVerilog扩展程序。 4. **熟悉文件结构:** * 滚动浏览文件。您通常会发现使用`localparam`或`reg`赋值定义的参数,通常附有解释其目的的注释。查找定义和赋值标准PCIe配置寄存器(厂商ID、设备ID等)的部分。 #### **6.1.3 修改设备ID和厂商ID** 更新这些基本标识符是主机系统正确将仿真设备识别为您的捐赠设备的最关键步骤。操作系统严重依赖 `Vendor ID` 和 `Device ID` 对来识别连接的硬件并加载适当的设备驱动程序。 **步骤:** 1. **搜索 `cfg_deviceid`:** * 在VS Code中使用搜索功能(`Ctrl + F`或`Cmd + F`)。 * 找到定义`cfg_deviceid`的行。它通常看起来像这样: ```verilog reg [15:0] cfg_deviceid = 16'hAAAA; // 默认或占位符设备ID ``` 2. **更新设备ID:** * 将`AAAA`替换为您使用Arbor从捐赠设备中提取的16位十六进制设备ID(例如,`0x1234`)。 * **示例:** 如果捐赠设备的设备ID是`0x1234`,则将该行更新为: ```verilog reg [15:0] cfg_deviceid = 16'h1234; // 更新为捐赠设备的设备ID(例如,来自网卡) ``` 3. **搜索 `cfg_vendorid`:** * 找到定义`cfg_vendorid`的行。其格式将类似于`cfg_deviceid`: ```verilog reg [15:0] cfg_vendorid = 16'hBBBB; // 默认或占位符厂商ID ``` 4. **更新厂商ID:** * 将`BBBB`替换为您从捐赠设备中提取的16位十六进制厂商ID(例如,`0xABCD`)。 * **示例:** 如果捐赠设备的厂商ID是`0xABCD`,则将该行更新为: ```verilog reg [15:0] cfg_vendorid = 16'hABCD; // 更新为捐赠设备的厂商ID(例如,Intel Corporation) ``` 5. **确保格式正确:** * 验证十六进制值是否正确以`16'h`为前缀(表示一个16位十六进制数)。 * 保持一致的缩进和注释风格以提高可读性。 #### **6.1.4 修改子系统ID和修订ID** 这些标识符提供了关于设备变体、特定产品型号或硬件修订的额外详细信息。虽然通常是可选的,但匹配它们能增强仿真的真实性,并且对于执行细粒度检查的驱动程序可能至关重要。 **步骤:** 1. **搜索 `cfg_subsysid`:** * 找到定义`cfg_subsysid`的行。 ```verilog reg [15:0] cfg_subsysid = 16'hCCCC; // 占位符子系统ID ``` 2. **更新子系统ID:** * 将`CCCC`替换为您捐赠设备的16位十六进制子系统ID(例如,`0x5678`)。 * **示例:** ```verilog reg [15:0] cfg_subsysid = 16'h5678; // 设置为捐赠设备的子系统ID ``` 3. **搜索 `cfg_subsysvendorid`:** * 找到定义`cfg_subsysvendorid`的行。 ```verilog reg [15:0] cfg_subsysvendorid = 16'hDDDD; // 占位符子系统厂商ID ``` 4. **更新子系统厂商ID(如果适用):** * 将`DDDD`替换为您捐赠设备的16位十六进制子系统厂商ID(例如,`0x9ABC`)。如果您的捐赠设备没有唯一的子系统厂商ID(即与主厂商ID相同),您仍应将其设置为该值。 * **示例:** ```verilog reg [15:0] cfg_subsysvendorid = 16'h9ABC; // 设置为捐赠设备的子系统厂商ID ``` 5. **搜索 `cfg_revisionid`:** * 找到定义`cfg_revisionid`的行。 ```verilog reg [7:0] cfg_revisionid = 8'hEE; // 占位符修订ID ``` 6. **更新修订ID:** * 将`EE`替换为您捐赠设备的8位十六进制修订ID(例如,`0x01`)。 * **示例:** ```verilog reg [7:0] cfg_revisionid = 8'h01; // 设置为捐赠设备的修订ID ``` #### **6.1.5 更新类别代码** 类别代码通知主机操作系统设备的通用类型和功能(例如,网络控制器、存储设备)。这对于操作系统加载通用类别驱动程序至关重要,即使没有安装特定厂商驱动程序。 **步骤:** 1. **搜索 `cfg_classcode`:** * 找到定义`cfg_classcode`的行。 ```verilog reg [23:0] cfg_classcode = 24'hFFFFFF; // 默认或占位符类别代码 ``` 2. **更新类别代码:** * 将`FFFFFF`替换为您从捐赠设备中提取的24位十六进制类别代码(例如,`0x020000`用于以太网控制器)。请记住格式:基本类别、子类别、编程接口。 * **示例:** 如果捐赠设备的类别代码是`0x020000`(表示基本类别:0x02 - 网络控制器,子类别:0x00 - 以太网控制器,编程接口:0x00),则更新为: ```verilog reg [23:0] cfg_classcode = 24'h020000; // 设置为捐赠设备的类别代码(例如,以太网控制器) ``` 3. **验证正确的位宽:** * 确保类别代码使用`24'h`前缀正确表示为24位十六进制值。 #### **6.1.6 保存更改** 在对配置参数进行所有修改后,保存和审查更改至关重要。 **步骤:** 1. **保存文件:** * 在VS Code中点击 **文件 > 保存**,或按下 `Ctrl + S`(macOS上为 `Cmd + S`)。 2. **审查更改:** * 在关闭之前,快速重新阅读修改过的行,以根据您的捐赠设备信息文档确认其准确性。 * 检查是否有任何明显的语法错误或拼写错误(VS Code的扩展可能会高亮显示这些)。 3. **可选 - 使用版本控制:** * 如果您正在使用Git(强烈推荐用于任何代码项目,尤其是固件),请以清晰且有意义的消息提交您的更改。这将创建您的修改历史记录。 * **示例Git命令:** ```bash git add pcileech_pcie_cfg_a7.sv git commit -m "更新PCIe配置寄存器(VID, DID, SubIDs, Revision, Class Code)以匹配捐赠设备:[捐赠设备名称]" ``` ### **6.2 插入设备序列号(DSN)** 设备序列号(DSN)是一些PCIe设备(特别是那些具有高级功能或特定驱动程序的设备)可能使用的独特64位标识符。包含它能增强仿真的真实性,并有助于绕过明确查询此值的驱动程序中的检查。 #### **6.2.1 定位DSN字段** DSN(如果由捐赠设备实现)是PCIe扩展能力的一部分。在PCILeech-FPGA框架中,DSN字段通常作为您一直在编辑的同一配置文件中的可配置参数公开。 **步骤:** 1. **搜索 `cfg_dsn`:** * 在 `pcileech_pcie_cfg_a7.sv`(或您的板卡等效配置文件)中,使用搜索功能(`Ctrl + F` 或 `Cmd + F`)查找 `cfg_dsn`。 2. **理解现有赋值:** * DSN可能被设置为默认值(通常是全零)或被注释掉。它通常看起来像这样: ```verilog reg [63:0] cfg_dsn = 64'h0000000000000000; // 默认DSN(如果未使用,通常为0) ``` #### **6.2.2 插入DSN** 更新DSN涉及将其设置为从捐赠设备捕获的精确64位十六进制值。 **步骤:** 1. **更新 `cfg_dsn`:** * 将现有的十六进制值替换为您使用Arbor从捐赠设备中提取的64位DSN。 * **示例:** 如果捐赠设备的DSN是`0x0011223344556677`,则更新为: ```verilog reg [63:0] cfg_dsn = 64'h0011223344556677; // 捐赠设备序列号 ``` 2. **处理DSN不可用或不相关的情况:** * 如果您的捐赠设备*没有*DSN,或者您已确定它不是您目标驱动程序所需的参数,您可以简单地将其保留为零: ```verilog reg [63:0] cfg_dsn = 64'h0000000000000000; // 捐赠设备没有特定DSN,保留为默认0 ``` * **注意**:对于关键仿真,如果捐赠设备有DSN,最好准确仿真它。 3. **确保格式正确:** * DSN是64位值;确保它以`64'h`前缀正确格式化为十六进制值。 #### **6.2.3 保存更改** 通过保存和审查文件来完成DSN修改。 **步骤:** 1. **保存文件:** * 在VS Code中点击 **文件 > 保存**,或按下 `Ctrl + S`。 2. **验证语法:** * 检查VS Code的语法检查器是否有任何红色下划线或错误指示。立即纠正任何问题。 3. **记录更改:** * 如果使用版本控制,请使用适当的消息提交更新。 * **示例Git命令:** ```bash git commit -am "在PCIe配置中插入捐赠设备序列号(DSN)" ``` --- ## **7. Vivado项目设置与定制** 在固件文件更新以反映捐赠设备的关键识别和配置数据后,下一个关键步骤是将这些更改集成到Vivado项目中。这包括为您的特定FPGA板卡生成项目文件,定制嵌入式PCIe IP核,并准备整个设计以进行综合和实现阶段。 ### **7.1 生成Vivado项目文件** Vivado是Xilinx(AMD)开发套件,使用Tcl(工具命令语言)脚本来自动化项目创建、添加源文件和配置项目设置。通过运行PCILeech-FPGA框架提供的这些脚本,您可以确保您的Vivado项目已为目标FPGA板卡正确设置。 #### **7.1.1 打开Vivado** 启动Vivado的新会话可确保之前会话中没有残留设置或打开项目干扰当前工作。 **步骤:** 1. **启动Vivado:** * 在“开始”菜单(Windows)或“应用程序”文件夹(Linux/macOS)中找到Vivado应用程序图标。 * 点击打开。 2. **选择正确的版本:** * 如果您安装了多个Vivado版本,请确保您启动的是与您的FPGA板卡和PCILeech-FPGA项目兼容的版本(如第4.3.1节所述,建议使用Vivado 2023.x等最新稳定版本)。 3. **等待启动界面:** * 让Vivado完全初始化并显示欢迎界面或项目仪表板,然后才能继续。 #### **7.1.2 访问Tcl控制台** Vivado内的Tcl控制台是您执行脚本和直接命令的主要界面。您将在此处运行项目生成脚本。 **步骤:** 1. **打开Tcl控制台:** * 在Vivado界面中,导航到菜单栏。 * 单击 **Window** > **Tcl Console**。 * Tcl控制台窗格通常会出现在Vivado窗口的底部。 2. **调整控制台大小(可选):** * 您可以拖动控制台的顶部边框来调整其大小,使其更高以便更好地查看命令和输出。 3. **清除先前命令(可选但推荐):** * 如果存在任何先前的命令或消息,您可以在控制台内右键单击并选择“Clear Console”以获得一个干净的开始。 #### **7.1.3 导航到项目目录** 在运行Tcl脚本之前,您必须确保Tcl控制台的当前工作目录已设置为您的板卡特定PCILeech-FPGA项目脚本所在的正确位置。 **对于Squirrel DMA (Artix-7 35T) 或类似板卡:** **典型路径(克隆`pcileech-fpga`并导航到您的板卡变体后):** ``` C:/Users/YourUsername/Documents/pcileech-fpga/pcileech-squirrel-35t/ # 在Windows上 ~/Projects/pcileech-fpga/pcileech-squirrel-35t/ # 在Linux/macOS上 ``` *注意:将``替换为您的板卡子目录的实际名称(例如,`pcileech-squirrel-35t`,`pcileech-artix-7-50t`)。* **步骤:** 1. **在Tcl控制台中设置工作目录:** * 在Vivado Tcl控制台中,输入`cd`命令,后跟您的板卡项目目录的完整路径。 * **示例(Windows):** ```tcl cd C:/Users/YourUsername/Documents/pcileech-fpga/pcileech-squirrel-35t/ ``` * **示例(Linux/macOS):** ```tcl cd ~/Projects/pcileech-fpga/pcileech-squirrel-35t/ ``` * *自我纠正提示:即使在Windows上,Tcl路径也使用正斜杠(`/`)。* 2. **验证目录更改:** * 要确认您处于正确的目录中,请在Tcl控制台中输入`pwd`(打印工作目录)。 * 控制台应显示您刚刚设置的完整路径,确认更改。 #### **7.1.4 生成Vivado项目** 运行适用于您的FPGA板卡的相应Tcl脚本将自动化Vivado内部的整个项目设置过程。这包括创建项目、添加所有必要的源文件(HDL、约束)以及配置核心项目设置。 **步骤:** 1. **运行Tcl脚本:** * 输入`source`命令,后跟您的板卡的项​​目生成脚本的名称。PCILeech-FPGA项目通常在主板卡目录中提供这些脚本。 * **对于Squirrel (Artix-7 35T)(以及类似的Artix-7板卡):** ```tcl source vivado_generate_project_squirrel.tcl -notrace ``` * **对于Enigma-X1 (Artix-7 75T):** ```tcl source vivado_generate_project_enigma_x1.tcl -notrace ``` * **对于ZDMA (Artix-7 100T):** ```tcl source vivado_generate_project_100t.tcl -notrace ``` * `-notrace`选项可防止每个Tcl命令的详细输出,使控制台更整洁。 2. **等待脚本完成:** * 脚本将按顺序执行许多命令。此过程可能需要几分钟,具体取决于您的系统性能和项目的复杂性。 * 监控Tcl控制台的进度消息。脚本将: * 在当前目录中创建一个新的Vivado项目(`.xpr`文件)。 * 添加所有SystemVerilog/Verilog源文件(`.sv`,`.v`)。 * 添加Xilinx IP核配置(`.xci`)。 * 添加XDC(Xilinx设计约束)文件。 * 可能配置各种项目设置。 * **处理任何错误**:如果发生任何错误(例如,“文件未找到”、“无效命令”),脚本通常会停止。检查错误消息,纠正底层问题(例如,路径不正确、文件丢失),然后重新运行脚本。 3. **确认项目生成:** * 成功完成后,Tcl控制台通常会指示项目已创建,并且您应该在项目目录中看到新生成的项目文件(例如,`pcileech_squirrel_top.xpr`)和相关目录(例如,`pcileech_squirrel_top.runs`,`pcileech_squirrel_top.ip`)。 #### **7.1.5 打开生成的项目** 现在Vivado项目文件已成功由Tcl脚本生成,您可以在Vivado GUI中打开该项目以进行进一步检查和定制。 **步骤:** 1. **打开项目:** * 在Vivado中,点击 **文件** > **打开项目**。 * 导航到您的项目目录(与您在第7.1.3节中在Tcl控制台中设置的目录相同)。 2. **选择项目文件:** * 找到并选择与您的板卡对应的Vivado项目文件(`.xpr`扩展名)。 * **对于Squirrel:** 文件名通常为 `pcileech_squirrel_top.xpr`。 * 点击 `.xpr` 文件以选择它。 3. **点击打开:** * Vivado将加载项目,显示设计层次结构、源文件、IP集成器块设计(如果使用)和各种设计视图。这可能需要一些时间。 4. **验证项目内容:** * 在 **项目管理器** 窗口(通常在左侧)中,展开 **源文件** 窗格。 * 确保所有预期的源文件(Verilog/SystemVerilog、XDC、IP核)都已列出,并且设计层次结构看起来正确。 * 检查 **消息** 窗格(底部)中打开项目时出现的任何警告或严重警告,因为这些可能表明潜在问题。 ### **7.2 修改IP核** PCIe IP核是设备PCIe接口的核心。它是一个经过Xilinx(AMD)预验证、可配置的模块,用于处理复杂的PCIe协议层。尽管某些配置空间值在SystemVerilog文件中处理(第6.1节),但其他核心PCIe参数,特别是与链路能力和BAR结构相关的参数,是在Vivado中直接通过PCIe IP核的定制设置进行配置的。定制IP核可确保您的FPGA在PCIe协议级别上与捐赠硬件的行为完全一致。 #### **7.2.1 访问PCIe IP核** PCIe IP核在您的Vivado项目中被实例化为一个IP块。您需要打开其定制GUI来修改其参数。 **步骤:** 1. **定位PCIe IP核:** * 在 **Sources**(源文件)窗格(位于 **Project Manager**(项目管理器)窗口内)中,确保已选择 **Hierarchy**(层次结构)选项卡。 * 展开设计层次结构,直到找到PCIe IP核的实例。 * 对于7系列FPGA(如Squirrel中使用的Artix-7),它通常被命名为 `pcie_7x_0.xci` 或类似名称,通常位于项目源文件的 `ip` 子目录中。 2. **打开IP定制窗口:** * **右键单击** `pcie_7x_0.xci` 文件。 * 从上下文菜单中选择 **Customize IP**(定制IP)。 * 将打开 **IP Configuration**(IP配置)窗口(或类似名称,如“Customize IP”或“Re-customize IP”),显示带有各种选项卡和选项的图形界面,用于配置PCIe核。 3. **等待IP设置加载:** * IP定制界面可能需要几分钟才能初始化并填充所有设置。在您开始进行更改之前,请确保所有选项和选项卡都已完全加载并响应。 #### **7.2.2 在IP核内部定制设备ID和BAR** 尽管某些设备标识符在`pcileech_pcie_cfg_a7.sv`中设置,但PCIe IP核本身也包含设备ID、厂商ID以及至关重要的基地址寄存器(BARs)的定义参数。您必须确保这些参数保持一致。`.sv`文件中的某些值可能会覆盖或输入到IP核中,但在此处也确保一致性是一个好习惯。IP核中的BAR设置尤其重要,因为它们决定了内存映射的硬件实现。 **步骤:** 1. **导航到基本/识别参数:** * 在IP定制窗口中,查找与 **基本**、**设备和厂商标识符**、**通用** 或 **PCIe能力** 相关的选项卡或部分。这是定义基本ID和初始链路设置的地方。 2. **验证/输入设备ID、厂商ID、子系统ID、修订ID、类别代码:** * **至关重要:请确认这些值与您在`pcileech_pcie_cfg_a7.sv`中设置的以及从捐赠设备中获取的值相匹配。** * 查找以下字段: * **设备ID**:输入`0xXXXX`(例如,`0x1234`)。 * **厂商ID**:输入`0xYYYY`(例如,`0xABCD`)。 * **子系统ID**:输入`0xZZZZ`(例如,`0x5678`)。 * **子系统厂商ID**:输入`0xWWWW`(例如,`0x9ABC`)。 * **修订ID**:输入`0xRR`(例如,`0x01`)。 * **类别代码**:输入`0xCCCCCC`(例如,`0x020000`)。 * **重要提示**:某些IP核版本或特定配置可能会直接从用户逻辑(如`pcileech_pcie_cfg_a7.sv`)拉取这些值,或者可能允许直接在此处设置它们。最可靠的方法是,如果IP GUI中提供此选项,则在两个位置都保持一致设置。 3. **导航到基地址寄存器(BARs)选项卡:** * 在IP定制窗口中,找到并选择 **BARs** 选项卡或部分。这是您定义PCIe设备暴露的内存区域的地方。 4. **配置每个BAR:** * 对于您的捐赠设备使用的每个BAR(BAR0到BAR5),根据您使用Arbor提取的信息,仔细配置以下参数: * **启用BAR**:仅当捐赠设备使用此特定BAR时才选中此框。禁用(取消选中)捐赠设备不使用的任何BAR。 * **BAR大小**:从下拉列表中选择精确的大小(例如,**256 MB**,**64 KB**,**4 KB**)。这对于主机操作系统分配正确数量的内存至关重要。 * **BAR类型**:选择适当的类型: * **Memory (32-bit Addressing)**(内存(32位寻址)): 用于32位地址可访问的内存映射区域。 * **Memory (64-bit Addressing)**(内存(64位寻址)): 用于可以驻留在64位地址空间中任何位置的内存映射区域(对于大内存区域或如果捐赠设备使用它,则需要)。 * **I/O**: 用于传统I/O端口区域(在现代PCIe中较不常见,但仍然可能)。 * **可预取**:如果捐赠设备的BAR被标记为可预取,则选中此框。此属性允许主机系统从此区域缓存或预取数据以提高性能。 * **示例配置(基于您的捐赠设备):** * **BAR0**: * 启用:是 * 大小:**256 MB** * 类型:**Memory (64-bit Addressing)** * 可预取:是 * **BAR1**: * 启用:否(如果捐赠设备不使用BAR1) * *继续配置BAR2-BAR5,镜像捐赠设备的配置。* 5. **确保对齐和非重叠空间**: * Vivado IP核通常会根据您选择的大小自动处理对齐。但是,请注意PCIe规范要求BAR大小是2的幂,并且BAR必须对其大小进行对齐。 * 确保所有活动BAR映射的总内存不超过FPGA可用的块RAM(BRAM)或外部内存容量。 #### **7.2.3 完成IP定制** 在IP核定制窗口中配置所有必要的设置后,您必须应用这些更改,使其在Vivado项目中生效。 **步骤:** 1. **审查所有设置:** * 在应用之前,花点时间快速最后一次审查IP定制窗口中的每个选项卡。 * 确认所有条目都与您捐赠设备的文档规范精确匹配。这里的一个小错误可能导致设备检测或功能问题。 2. **应用更改:** * 点击IP定制窗口底部的 **OK** 或 **Generate** 按钮(标签可能不同)。 * 如果Vivado提示您确认是否继续更改并重新生成IP输出产品,请点击 **Yes** 确认。 3. **重新生成IP核:** * Vivado现在将重新生成IP核的输出产品(例如,网表、仿真模型、新的`.xci`配置文件),以反映您的新配置。 * 监控 **消息** 窗格(Vivado窗口底部),查看在此重新生成过程中可能出现的任何错误、警告或严重警告。立即解决任何严重警告。 4. **更新项目中的IP:** * 在IP核重新生成后,Vivado可能会自动更新或提示您更新项目中的任何IP依赖项。允许它这样做,以确保在整个设计中使用最新的配置。 #### **7.2.4 锁定IP核** 锁定IP核是Vivado中推荐的最佳实践,可防止在后续综合和实现运行期间意外修改或重新定制,这可能会潜在地恢复您精心配置的设置。 **锁定的目的:** * **防止覆盖:** 确保您在IP核GUI中进行的手动配置得以保留,不会因Vivado自动化或IP因细微项目更改而被检测为“过时”而意外覆盖。 * **保持一致性:** 在整个构建过程中保持IP核处于已知、稳定的状态,这对于PCIe接口等关键组件尤其重要。 **步骤:** 1. **打开Tcl控制台:** * 在Vivado中,如果Tcl控制台尚未打开,请转到 **Window** > **Tcl Console**。 2. **执行锁定命令:** * 在Tcl控制台中,精确输入以下命令。此命令将PCIe IP核实例(`pcie_7x_0`)的`IP_LOCKED`属性设置为`true`。 ```tcl set_property -name {IP_LOCKED} -value true -objects [get_ips pcie_7x_0] ``` * 按 **Enter** 执行命令。 3. **验证锁定:** * 检查 **消息** 窗格。您应该会看到一条确认属性已设置的消息。 * 您还可以右键单击源文件窗格中的 `pcie_7x_0.xci`,选择“IP Properties”(IP属性),并验证 `IP_LOCKED` 是否设置为 `true`。您可能还会注意到“Customize IP”(定制IP)选项现在已灰显,或者只允许“Re-customize IP”(重新定制IP),然后会警告您关于锁定。 4. **解锁(如果需要):** * 如果您将来需要对PCIe IP核的设置进行进一步修改,则必须先将其解锁。使用以下Tcl命令: ```tcl set_property -name {IP_LOCKED} -value false -objects [get_ips pcie_7x_0] ``` * 请记住在进行和应用更改后重新锁定它。 5. **记录操作:** * 在您的项目文档(例如,README文件、项目说明)中注明PCIe IP核已锁定是一个好习惯。这有助于项目中其他人理解其配置状态并避免混淆。 --- ## **第二部分:中级概念与实现** --- ## **8. 高级固件定制** 为了实现对捐赠设备精确且令人信服的仿真,除了基本识别之外,还需要对FPGA固件进行更深入的定制。这包括调整PCIe参数(例如链路速度和事务大小),细致地调整基地址寄存器(BARs)及其相关的内存映射,以及准确仿真电源管理和中断机制。这些步骤确保仿真设备不仅在主机系统看来与原始硬件相同,而且在协议和功能级别上行为也完全一致。 ### **8.1 配置PCIe参数以进行仿真** 精确仿真要求您的FPGA设备的PCIe操作参数经过细致配置,以匹配捐赠设备的参数。这包括PCIe链路速度、链路宽度、能力指针和最大有效载荷大小等设置。正确的配置可确保与主机系统的兼容性、驱动程序和应用程序与设备交互的正确操作以及数据传输的最佳性能。 #### **8.1.1 匹配PCIe链路速度和宽度** PCIe链路速度(例如,Gen1、Gen2、Gen3)和链路宽度(例如,x1、x4、x8)是决定设备最大理论数据吞吐量和性能的关键参数。将这些设置与捐赠设备匹配对于精确仿真至关重要,因为驱动程序或系统组件可能期望特定的链路能力。 **步骤:** 1. **访问PCIe IP核设置:** * **打开您的Vivado项目:** 启动Vivado并打开您之前创建或修改的项目(例如,`pcileech_squirrel_top.xpr`)。确保所有源文件都已正确添加到项目中。 * **定位PCIe IP核:** 在 **Sources**(源文件)窗格(通常在左侧)中,展开设计层次结构以找到PCIe IP核实例。对于Xilinx 7系列设计(如Squirrel中使用的Artix-7),这通常被命名为 `pcie_7x_0.xci`。 * **定制IP核:** 右键单击 `pcie_7x_0.xci` 并选择 **Customize IP**(定制IP)。IP定制窗口将打开,显示多个选项卡中的各种配置选项。 2. **设置最大链路速度:** * **导航到链路参数:** 在IP定制窗口中,点击 **PCIe Capabilities**(PCIe功能)选项卡(有时是“PCIe Configuration”或“General”)。在此选项卡内,查找与 **Link Parameters**(链路参数)或 **Link Capability Register**(链路能力寄存器)相关的部分。 * **配置最大链路速度:** 找到标有 **Maximum Link Speed**(最大链路速度)的选项(或“Target Link Speed”)。 * 将其设置为与您的捐赠设备支持和广告的最大链路速度相匹配。 * **示例:** * 如果捐赠设备在 **PCIe Gen2 (5.0 GT/s)** 下运行,选择 **5.0 GT/s**。 * 如果它在 **PCIe Gen1 (2.5 GT/s)** 或 **PCIe Gen3 (8.0 GT/s)** 下运行,请选择相应的选项。 * **注意**:确保您的FPGA的收发器和物理硬件(主板PCIe插槽)支持所选的链路速度。FPGA只会协商到其配置的最大速度。 3. **设置链路宽度:** * **配置链路宽度:** 在相同的 **Link Parameters**(链路参数)部分中,找到 **Link Width**(链路宽度)设置(或“PCIe Link Width”、“Target Link Width”)。 * 将其设置为与您的捐赠设备广告的最大链路宽度相匹配。 * **示例:** * 如果捐赠设备使用 **x4** 链路,将 **Link Width** 设置为 **4**。 * 选项通常包括 **1**、**2**、**4**、**8**、**16** 通道。 * **注意**:物理PCIe插槽和FPGA的封装必须支持所选的链路宽度。尝试配置大于物理连接的宽度将导致链路协商问题。 4. **保存并重新生成:** * **应用更改:** 配置链路速度和宽度后,点击 **OK** 以在IP定制窗口中应用更改。 * **重新生成IP输出产品:** Vivado很可能会提示您由于所做的更改而重新生成IP核的输出产品。确认并允许重新生成过程完成。这可能需要一些时间。 * **验证设置:** 一旦重新生成完成,您可以选择性地重新访问IP核设置,以确保配置已正确应用。检查Vivado中 **Messages**(消息)窗口中是否有任何警告或错误。 #### **8.1.2 设置能力指针** PCIe配置空间中的能力指针是8位寄存器,它们形成一个链表,指向各种能力结构(例如,电源管理、MSI/MSI-X、PCIe Express能力)。正确设置这些指针可确保主机系统能够遍历能力列表并定位和利用设备广告的功能。 **步骤:** 1. **在固件中定位能力指针:** * **打开配置文件:** 在Visual Studio Code中,打开您的板卡的主配置文件,通常是`pcileech_pcie_cfg_a7.sv`,位于`pcileech-fpga//src/pcileech_pcie_cfg_a7.sv`。 * **理解能力指针:** 此文件中的能力指针(`cfg_cap_pointer`)指向PCIe配置空间中的*第一个*能力结构,通常从标准64字节配置头之后开始。后续的能力通过其“下一个能力指针”字段链接起来。 2. **设置能力指针值:** * **找到`cfg_cap_pointer`的赋值:** 在代码中搜索定义`cfg_cap_pointer`的行。 ```verilog reg [7:0] cfg_cap_pointer = 8'hXX; // 当前值(例如,默认的8'h40) ``` * **更新能力指针:** 将`XX`替换为您使用Arbor从捐赠设备观察到的8位十六进制能力指针值。此值通常指向设备特定配置空间(通常在偏移量`0x3F`结束)之后第一个能力结构的偏移量。能力常见的起始点是`0x40`或`0x60`。 * **示例:** * 如果捐赠设备的第一个能力指针是`0x60`(表示其第一个能力结构在配置空间中从偏移量`0x60`开始),将该行更新为: ```verilog reg [7:0] cfg_cap_pointer = 8'h60; // 更新以匹配捐赠设备的第一个能力偏移量 ``` * **确保正确对齐:** 能力结构必须对齐到4字节边界。能力指针应始终指向配置空间中有效的4字节对齐偏移量。 3. **保存更改:** * **保存配置文件:** 进行更改后,点击 **文件 > 保存** 或按下 `Ctrl + S` 保存文件。 * **验证语法:** 确保更改未引入任何语法错误(VS Code通常会高亮显示这些错误)。 * **添加注释以清晰说明:** 添加注释解释更改,以便将来参考和维护。 ```verilog reg [7:0] cfg_cap_pointer = 8'h60; // 设置为捐赠设备的能力指针(例如,PCIe能力位于0x60) ``` #### **8.1.3 调整最大载荷和读取请求大小** 这些参数定义了单个PCIe事务层数据包(TLP)中可以传输的最大数据量,以及非posted内存读取请求TLP的最大大小。将这些设置与捐赠设备匹配可确保兼容性并优化数据传输操作的性能。不匹配可能导致吞吐量降低或通信错误。 **步骤:** 1. **设置支持的最大载荷大小(IP核):** * **访问设备功能:** 在PCIe IP核定制窗口(Vivado中的`pcie_7x_0.xci`)中,导航到 **PCIe Capabilities**(PCIe功能)选项卡。 * **配置支持的最大载荷大小:** 找到标有 **Max Payload Size Supported**(支持的最大载荷大小)的设置(或类似名称)。 * 将其设置为与您的捐赠设备支持和广告的值相匹配(例如,128字节、256字节、512字节、1024字节、2048字节、4096字节)。 * **示例:** 如果捐赠设备支持的最大载荷大小为 **256字节**,请从下拉列表中选择 **256字节**。 2. **设置支持的最大读取请求大小(IP核):** * **配置支持的最大读取请求大小:** 在同一选项卡中,找到 **Max Read Request Size Supported**(支持的最大读取请求大小)设置。 * 将其设置为与捐赠设备的能力相匹配。这指定了设备在单个读取事务中可以请求的最大数据量。 * **示例:** 如果捐赠设备支持的最大读取请求大小为 **512字节**,请选择 **512字节**。 3. **调整固件参数(匹配IP核):** * **打开 `pcileech_pcie_cfg_a7.sv`:** 确保配置文件在Visual Studio Code中打开。 * **更新固件常量:** 找到定义`max_payload_size_supported`和`max_read_request_size_supported`的行。这些通常是与您在IP核中选择的字节大小对应的位编码值。 ```verilog reg [2:0] max_payload_size_supported = 3'bZZZ; // 当前值 reg [2:0] max_read_request_size_supported = 3'bWWW; // 当前值 ``` * **设置适当的值:** 将`ZZZ`和`WWW`替换为与所选大小对应的3位二进制表示。 * **映射(根据PCIe规范):** * **128字节**:`3'b000` * **256字节**:`3'b001` * **512字节**:`3'b010` * **1024字节**:`3'b011` * **2048字节**:`3'b100` * **4096字节**:`3'b101` * **示例:** * 对于 **256字节** 载荷大小: ```verilog reg [2:0] max_payload_size_supported = 3'b001; // 支持最大256字节 (0x100) ``` * 对于 **512字节** 读取请求大小: ```verilog reg [2:0] max_read_request_size_supported = 3'b010; // 支持最大512字节 (0x200) ``` * **原因**:这些固件参数通常决定了与PCIe核接口的用户逻辑的行为,确保您的逻辑遵循配置的最大值。 4. **保存更改:** * **保存文件:** 更新`pcileech_pcie_cfg_a7.sv`中的值后,保存文件。 * **验证一致性:** Vivado PCIe IP核GUI中配置的值*必须*与您的HDL配置文件中设置的值*匹配*。任何不匹配都可能导致意外行为或链路训练问题。 * **添加注释:** 在您的代码中清晰地记录这些更改,以便将来参考。 ### **8.2 调整BARs和内存映射** 基地址寄存器(BARs)是PCIe设备向主机系统公开其内部内存和寄存器的基本方式。正确配置BARs并在FPGA的BRAMs(块RAMs)和逻辑中定义它们的内存映射对于精确仿真和主机端设备驱动程序的正常运行至关重要。 #### **8.2.1 设置BAR大小和类型(IP核和BRAM)** 配置BAR大小和类型可确保您的仿真设备在枚举期间向主机请求正确的地址空间量,并且主机适当地分配和映射这些区域。这还涉及将这些地址区域与FPGA内的物理内存块关联起来。 **步骤:** 1. **访问BAR配置(PCIe IP核):** * **定制PCIe IP核:** 在Vivado中,右键单击 `pcie_7x_0.xci` 并选择 **Customize IP**(定制IP)以打开其配置GUI。 * **导航到BARs选项卡:** 在IP定制窗口中,点击 **Base Address Registers (BARs)**(基地址寄存器(BARs))选项卡。 2. **配置每个BAR(IP核):** * **匹配捐赠设备的BARs:** 对于每个BAR(BAR0到BAR5),根据您使用Arbor从捐赠设备中提取的信息,细致地设置大小、类型和可预取状态。 * **启用/禁用BARs:** 确保只启用捐赠设备实际使用的BARs。禁用(取消选中)任何未使用的BARs。 * **设置BAR大小:** 为每个*已启用*的BAR从下拉列表中选择适当的大小。这将是2的幂次(例如,4KB、8KB、64KB、1MB、256MB、1GB)。 * **示例:** * 如果 **BAR0** 是 **64 KB**,将 **BAR0 Size** 设置为 **64 KB**。 * 如果 **BAR1** 是 **128 MB**,将 **BAR1 Size** 设置为 **128 MB**。 * **设置BAR类型:** * 如果BAR是内存映射的,选择 **Memory (32-bit Addressing)**(内存(32位寻址))或 **Memory (64-bit Addressing)**(内存(64位寻址))。如果捐赠设备的BAR是64位或您需要访问4GB以上的地址,请选择 **64-bit Addressing**。 * 如果BAR用于I/O端口空间(现代PCIe设备较少见),选择 **I/O**。 * **设置可预取状态**:如果捐赠设备的BAR被识别为可预取,请选中“Prefetchable”(可预取)框。此位允许主机预取该区域的数据,可能提高性能。 3. **更新BRAM配置(如果适用):** * 许多PCILeech-FPGA项目使用Xilinx块RAM(BRAM)IP核来表示BARs暴露的内存区域。这些BRAM提供仿真设备内存的物理存储。 * **定位BRAM IP核:** 在您的Vivado项目 **Sources**(源文件)窗格中,在`ip`子目录(或类似目录)中,您可能会找到BRAM的`.xci`文件,名称可能类似: ``` pcileech-fpga//ip/bram_bar_zero4k.xci pcileech-fpga//ip/bram_pcie_cfgspace.xci # 可能还有BAR1、BAR2等的其他文件 ``` * **修改BRAM大小:** 对于与*已启用*BAR关联的每个BRAM IP核,您可能需要 **Customize IP**(定制IP)(右键单击`.xci`文件)并调整其内存大小配置,以精确匹配相应的BAR大小。 * **示例:** 如果BAR0是256MB,请确保连接到BAR0的BRAM大小为256MB。 * **注意**:确保所有活动BAR所需的总内存不超过您的FPGA设备的物理BRAM容量。超出容量将导致实现失败。 4. **保存并重新生成:** * **应用更改(IP核):** 在PCIe IP核中配置BAR后,点击IP定制窗口中的 **OK**。 * **重新生成IP核:** Vivado将提示您由于所做的更改而重新生成PCIe IP核和任何相关的BRAM IP核。允许重新生成完成。这可确保硬件网表反映您的新BAR定义。 * **检查错误:** 检查 **Messages**(消息)窗口中是否有与BAR配置或BRAM实例化相关的任何警告或错误。 #### **8.2.2 在固件中定义BAR地址空间** 尽管PCIe IP核配置了BAR的*硬件*方面,但您的定制固件(SystemVerilog代码)需要定义当主机CPU对这些BAR区域内的地址执行读写操作时,仿真设备如何响应的*逻辑*。这涉及地址解码和实现寄存器/内存访问逻辑。 **步骤:** 1. **打开BAR控制器文件:** * 在Visual Studio Code中,打开负责处理BAR访问的SystemVerilog文件。对于PCILeech-FPGA,这通常是: ``` pcileech-fpga//src/pcileech_tlps128_bar_controller.sv ``` 此模块通常接收PCIe内存读/写TLP,并解码地址以确定正在访问哪个BAR(以及该BAR内的哪个偏移量)。 2. **实现地址解码逻辑:** * 在`pcileech_tlps128_bar_controller.sv`模块中,您会找到确定传入事务目标是哪个BAR的逻辑。这通常涉及根据配置的BAR大小检查地址位。 * 您需要定义传入地址`req_addr`(来自TLP)如何映射到您的特定BAR内的偏移量。 * **概念示例:** ```verilog // 示例:BAR0的逻辑(假设它是一个256MB的64位内存BAR,用于寄存器/数据) // 'bar_hit[0]'是一个指示命中BAR0的输入信号,通常来自PCIe核。 // 'req_addr'是传入的PCIe地址。 // 'req_be'是来自TLP的字节使能。 // 'req_data'是传入的写入数据。 // 'rsp_data'是传出的读取数据。 // 假设BAR0是256MB (2^28字节),地址位 [27:0] 在BAR范围内。 localparam BAR0_SIZE_BITS = 28; // 2^28 = 256MB reg [31:0] internal_register_0; // BAR0内的示例寄存器 reg [31:0] internal_register_1; // 另一个示例寄存器 assign bar0_offset = req_addr[BAR0_SIZE_BITS-1:0]; // 提取BAR0内的偏移量 always_comb begin // 默认响应 rsp_data = 32'hFFFFFFFF; // 默认值为全F或类似值,表示未映射区域 if (bar_hit[0]) begin // 如果事务目标是BAR0 if (req_write) begin // 这是写入操作 case (bar0_offset) // 示例:将偏移量0x0映射到internal_register_0 32'h0000_0000: begin if (req_be[3]) internal_register_0[31:24] = req_data[31:24]; if (req_be[2]) internal_register_0[23:16] = req_data[23:16]; if (req_be[1]) internal_register_0[15:8] = req_data[15:8]; if (req_be[0]) internal_register_0[7:0] = req_data[7:0]; end // 示例:将偏移量0x4映射到internal_register_1 32'h0000_0004: begin if (req_be[3]) internal_register_1[31:24] = req_data[31:24]; if (req_be[2]) internal_register_1[23:16] = req_data[23:16]; if (req_be[1]) internal_register_1[15:8] = req_data[15:8]; if (req_be[0]) internal_register_1[7:0] = req_data[7:0]; end // 添加更多寄存器映射或内存访问(例如,BRAM访问) default: begin // 处理BAR0内未映射的写入,例如,忽略或记录 end endcase end else if (req_read) begin // 这是读取操作 case (bar0_offset) // 示例:从internal_register_0读取 32'h0000_0000: rsp_data = internal_register_0; // 示例:从internal_register_1读取 32'h0000_0004: rsp_data = internal_register_1; // 添加更多寄存器映射或内存访问(例如,BRAM访问) default: begin rsp_data = 32'h0; // 对于未映射的读取返回0或特定错误值 end endcase end end end ``` * **处理数据传输:** `always_comb`块(或`always_ff`用于时序逻辑)应定义如何为读取生成`rsp_data`,以及如何根据`bar0_offset`和字节使能(`req_be`)更新内部寄存器/内存。 3. **实现BRAM访问(如果BAR映射到BRAM):** * 如果BAR映射到大块内存(例如,256MB),您通常会实例化一个BRAM IP核(如8.2.1所述)并将其`bar_controller`逻辑与它连接。`bar_controller`将向BRAM提供地址和控制信号。 * **概念性BRAM集成(简化):** ```verilog // 在pcileech_tlps128_bar_controller.sv或子模块中 // BRAM接口 wire [BAR0_SIZE_BITS-1:0] bram_addr; wire [31:0] bram_wr_data; wire [3:0] bram_wr_en; // BRAM的字节使能 wire bram_wr_ce; wire bram_rd_ce; wire [31:0] bram_rd_data; // 将TLP信号映射到BRAM接口 assign bram_addr = bar0_offset; assign bram_wr_data = req_data; assign bram_wr_en = req_be; assign bram_wr_ce = bar_hit[0] && req_write; assign bram_rd_ce = bar_hit[0] && req_read; // 实例化BRAM IP核 bram_bar_zero bram_inst ( // 假设'bram_bar_zero'是您的BRAM IP模块 .clka(clk), .ena(1'b1), .wea(bram_wr_en), .addra(bram_addr), .dina(bram_wr_data), .douta(bram_rd_data) ); // 对于从BAR0的读取,输出BRAM的数据 if (bar_hit[0] && req_read) begin rsp_data = bram_rd_data; end ``` 4. **保存更改:** * 实现每个BAR的逻辑后,保存`pcileech_tlps128_bar_controller.sv`文件。 * **验证功能:** 此逻辑很复杂。彻底的仿真(使用测试平台)和后续的硬件测试对于确保正确行为至关重要。 #### **8.2.3 处理多个BAR** 正确管理多个BAR对于暴露多个独立内存或I/O区域的设备至关重要。`bar_controller`模块通常处理所有BAR。 **步骤:** 1. **实现每个BAR的逻辑:** * 在`pcileech_tlps128_bar_controller.sv`内部,扩展逻辑以处理您的捐赠设备使用的所有已启用BAR(BAR0、BAR1、BAR2等)。 * **独立逻辑块:** 为清晰和可维护性,创建独立的`if/else if`块或`case`语句,根据哪个`bar_hit`信号被断言而激活。 ```verilog // BAR0处理 if (bar_hit[0]) begin // BAR0特定读/写逻辑,用于其寄存器/内存 end else if (bar_hit[1]) begin // BAR1特定读/写逻辑,用于其寄存器/内存 end else if (bar_hit[2]) begin // BAR2特定逻辑 end // ... 继续其他BAR ``` * **定义寄存器和内存:** 根据需要为每个BAR分配独立的寄存器集或连接不同的BRAM实例。 2. **确保非重叠地址空间:** * 虽然PCIe IP核处理与主机操作系统的每个BAR的不同地址空间的协商,但您的内部固件逻辑*必须*假定这些空间是独立的且不重叠的。 * **验证地址范围**:仔细检查PCIe IP核中的BAR大小配置,以确保它们是独立的,并且根据PCIe规范正确地对齐到2的幂次方边界。 * **更新地址解码**:您的`bar_controller`逻辑依赖于PCIe IP核生成的`bar_hit`信号。确保这些信号被正确解释并导致每个BAR的独特处理逻辑。 3. **测试BAR访问:** * **仿真测试:** 在硬件部署之前,使用仿真工具(例如Vivado仿真器)和全面的测试平台来验证对每个BAR的所有读写操作。 * 向每个BAR内的特定偏移量发送内存写入TLP。 * 向每个BAR内的特定偏移量发送内存读取TLP并验证返回的数据。 * **硬件测试:** 编程FPGA后,使用主机端软件工具(如PCILeech客户端软件或定制C/Python脚本)访问和验证每个BAR。 * **Linux**:使用`lspci -vvv`检查BAR映射(`Memory at XXXX (64-bit, prefetchable) [size=YYYY]`)。然后可以使用`devmem2`或自定义内核模块来读/写这些映射地址。 * **Windows**:使用“RW-Everything”等工具或自定义用户模式应用程序来检查和与映射的内存区域交互。 * 执行各种读/写模式以确保所有BAR之间的数据完整性和正确寻址。 --- ### **8.3 仿真设备电源管理和中断** 实现电源管理功能和中断对于需要与主机操作系统的电源管理和中断处理机制密切高效交互的设备至关重要。没有这些,仿真设备可能无法完全正常工作,或者性能可能不理想。 #### **8.3.1 电源管理配置** 实现电源管理允许仿真设备支持各种电源状态(例如D0、D3hot),有助于系统范围的电源效率并符合操作系统的预期。主机操作系统将查询设备的功能并发送命令以在这些状态之间转换。 **步骤:** 1. **在PCIe IP核中启用电源管理:** * **访问功能:** 在PCIe IP核定制窗口(`pcie_7x_0.xci`)中,导航到 **PCIe Capabilities**(PCIe功能)选项卡。 * **启用电源管理:** 查找与 **Power Management Capability**(电源管理功能)相关的部分或选项。确保已选中或启用此选项,以便在设备的配置空间中包含电源管理(PM)功能结构。 2. **设置支持的电源状态:** * **配置支持的状态:** 在IP核的电源管理功能部分,指定设备支持的电源状态。这些通常是复选框或下拉菜单。将这些设置与您通过Arbor观察到的捐赠设备的能力相匹配。 * **D0(完全开启/运行)**:始终支持。 * **D1、D2(中间状态)**:可选,用于低功耗空闲状态。 * **D3hot(断电,辅助电源存在)**:设备逻辑关闭,但可以响应PM事件。 * **D3cold(完全断电)**:设备没有电源。 * **示例**:如果捐赠设备仅支持D0和D3hot,则只启用它们。 3. **在固件中实现电源状态逻辑:** * **打开 `pcileech_pcie_cfg_a7.sv`(或相关控制模块):** 您通常需要修改固件以反映并可能响应主机命令的电源状态转换。PCIe核本身处理大部分协议,但您的用户逻辑需要知道当前状态。 * **处理电源管理控制和状态寄存器(PMCSR)写入:** 主机操作系统通过写入PMCSR中的特定位来改变设备的电源状态,PMCSR是PM能力结构的一部分。您的固件理想情况下应有逻辑来读取这些位并调整设备行为(例如,暂停/恢复操作,启用/禁用时钟)。 ```verilog // 示例:pcileech_pcie_cfg_a7.sv或专用PM模块的一部分 // 假设'cfg_write'在配置写入时被断言,'cfg_address'是偏移量,'cfg_writedata'是数据。 // D状态位位于PM能力结构中偏移量0x04处,位[1:0]。 // PMCSR寄存器(内部表示) reg [15:0] pmcsr_reg = 16'h0000; // 初始化为D0 // 用户逻辑信号,指示当前电源状态 reg [1:0] current_d_state = 2'b00; // 00 = D0, 01 = D1, 10 = D2, 11 = D3hot always @(posedge clk) begin if (reset) begin pmcsr_reg <= 16'h0000; current_d_state <= 2'b00; // 重置为D0 end else begin // 示例:捕获对PMCSR的写入(如果直接在用户逻辑中处理) // 注意:PCIe IP核管理大部分内容,但您的用户逻辑可能需要从中读取值。 // 假设PCIe核提供一个反映当前D状态的输出: // assign current_d_state = pcie_core_d_state_output; // 如果用户逻辑*需要*写入PMCSR(较少见,通常是只读状态) // 或者它需要处理命令 // if (cfg_write && (cfg_address == PM_CAP_OFFSET + 2'h04)) begin // PMCSR在PM Cap基础地址+0x04 // pmcsr_reg[1:0] <= cfg_writedata[1:0]; // 捕获新D状态 // // current_d_state <= cfg_writedata[1:0]; // 更新内部状态 // end // 在PCILeech中,PCIe核管理PMCSR。您可能会从核读取信号。 // 为了演示,假设'pcie_d_state'是来自IP核的输入。 current_d_state <= pcie_d_state; // 根据PCIe核的状态更新 end end // 示例:响应D状态变化的逻辑 always @(*) begin if (current_d_state == 2'b11) begin // D3hot状态 // 禁用非必要模块的电源,暂停操作, // 断言信号给主DMA逻辑以停止活动。 // 例如:dma_engine_enable = 1'b0; end else if (current_d_state == 2'b00) begin // D0状态 // 启用全部功能 // 例如:dma_engine_enable = 1'b1; end end ``` * **管理电源状态效果:** 实现逻辑以根据`current_d_state`更改设备的内部行为(例如,启用/禁用时钟,将子模块置于低功耗模式)。这对于精确的功耗仿真以及确保设备正确响应操作系统命令至关重要。 4. **保存更改:** * 保存任何修改过的固件文件。 * 通过仿真或硬件测试(例如,Windows“睡眠”或“休眠”功能,或Linux `poweroff`命令)彻底测试电源管理功能,以查看设备是否正确转换。 #### **8.3.2 MSI/MSI-X配置** 实现消息信号中断(MSI)或其扩展版本(MSI-X)允许仿真设备使用基于消息的中断。这些中断比传统的引脚中断(INTx)效率更高、可扩展性更强,是现代PCIe设备的优选方法。MSI/MSI-X允许设备通过向特定内存地址写入特殊TLP来通知CPU。 **步骤:** 1. **在PCIe IP核中启用MSI/MSI-X:** * **访问中断配置:** 在PCIe IP核定制窗口(`pcie_7x_0.xci`)中,导航到 **Interrupts**(中断)选项卡或专门标记为 **MSI/MSI-X Capabilities**(MSI/MSI-X功能)的部分。 * **选择中断类型:** 根据捐赠设备的功能,选择 **MSI** 或 **MSI-X**。MSI-X通常因其灵活性(更多向量,每个向量可屏蔽)而受到青睐。 * **配置支持的向量数量:** 设置设备将支持的中断向量(消息)数量。这应与捐赠设备匹配。 * **MSI** 支持最多32个向量(通常是1、2、4、8、16或32)。 * **MSI-X** 支持最多2048个向量,允许更细粒度的中断源。 * **启用功能:** 确保MSI或MSI-X功能结构已明确启用,以便包含在设备的配置空间中。这是主机操作系统发现设备中断能力的方式。 2. **在固件中实现中断逻辑:** * **打开 `pcileech_pcie_tlp_a7.sv`(或用户逻辑模块):** 此文件通常负责用户定义的TLP生成,并且可能是启动MSI/MSI-X消息的合适位置。但是,中断的*触发*将来自您的自定义逻辑。 * **定义中断信号:** 声明内部信号,指示何时需要生成中断。 ```verilog // 在自定义模块中(例如,'my_device_logic.sv'),该模块与TLP生成逻辑接口 reg msi_trigger_signal; // 当发生中断条件时断言此信号 ``` * **实现中断生成逻辑:** 定义应该触发中断的条件。这通常涉及在仿真设备的逻辑中检测事件。 ```verilog // 在'my_device_logic.sv'内部 input wire clk; input wire reset; input wire event_data_ready; // 示例:当数据就绪时来自您的逻辑的输入 always @(posedge clk or posedge reset) begin if (reset) begin msi_trigger_signal <= 1'b0; end else if (event_data_ready) begin // 当特定事件发生时 msi_trigger_signal <= 1'b1; // 触发MSI end else begin msi_trigger_signal <= 1'b0; // 一个周期后或被确认后清除 end end ``` * **连接到PCIe核的MSI接口:** `msi_trigger_signal`(或您的自定义逻辑的类似输出)需要连接到PCIe IP核的适当输入(例如,如果使用AXI-Stream接口进行MSI TLP,则连接到`s_axis_tdata_tready`、`s_axis_tdata_tvalid`、`s_axis_tdata_tlast`;或者连接到IP核提供的专用MSI请求端口)。然后PCIe核会形成并发送实际的MSI/MSI-X TLP。有关精确的接口详细信息,请查阅Xilinx PCIe IP核文档。 3. **保存更改:** * 实现中断逻辑后,保存所有修改过的固件文件。 * **检查时序约束:** 新逻辑,特别是中断路径,可能对时序很敏感。确保综合和实现工具不会报告与您的中断生成逻辑相关的任何时序违规。 #### **8.3.3 实现中断处理逻辑(设备端)** 除了启用功能之外,定义仿真设备何时以及如何生成中断对于其与主机中断处理机制和驱动程序行为的正确交互至关重要。这涉及创建断言中断请求的内部逻辑。 **步骤:** 1. **定义中断条件:** * **识别触发事件:** 根据您的捐赠设备的行为,确定哪些特定的内部事件应导致您的仿真设备生成中断。 * **示例**:数据传输完成、接收缓冲区中有新数据、内部错误条件、特定命令完成、链路状态更改。 * **实现条件逻辑:** 在您的自定义SystemVerilog模块中使用组合逻辑或时序逻辑,精确检测这些事件并生成一个短脉冲或电平信号,指示中断请求。 2. **创建中断生成模块(模块化设计):** * 将中断生成逻辑封装到一个单独的专用模块中是一个好习惯,这样可以提高清晰度、可重用性并方便调试。此模块将内部事件作为输入,并产生一个连接到PCIe核的`msi_req`(或类似)输出。 ```verilog // 文件:interrupt_generator.sv module interrupt_generator ( input wire clk, input wire reset, input wire event_trigger, // 来自您的自定义逻辑的输入信号(例如,data_ready, error_flag) output reg msi_req_o // 输出:断言此信号以请求MSI/MSI-X ); // MSI的简单脉冲发生器(一次性中断) reg event_trigger_d1; always @(posedge clk or posedge reset) begin if (reset) begin msi_req_o <= 1'b0; event_trigger_d1 <= 1'b0; end else begin event_trigger_d1 <= event_trigger; // 当event_trigger从低到高跳变时,生成一个单周期脉冲 if (event_trigger && !event_trigger_d1) begin msi_req_o <= 1'b1; // 断言MSI请求 end else begin msi_req_o <= 1'b0; // 一个周期后取消断言 end end end endmodule // interrupt_generator ``` * **与主固件集成:** 在您的顶层用户逻辑中(例如,在`pcileech_squirrel_top.sv`或其实例化的模块中)实例化此`interrupt_generator`模块,并将其`msi_req_o`输出连接到PCIe IP核的MSI输入。 3. **确保正确的时序和序列:** * **遵守PCIe规范:** MSI/MSI-X消息是TLP。确保这些消息的生成符合PCIe TLP格式、流控制和时序要求。PCIe IP核处理大部分内容,但您提供给它的输入信号必须稳定且时序正确。 * **管理中断延迟:** 优化您的逻辑,以最大限度地减少内部事件发生与`msi_req_o`信号断言之间的任何不必要延迟。 4. **测试中断传递:** * **仿真:** 使用全面的测试平台模拟应生成中断的场景。验证您的`msi_req_o`信号是否按预期工作,以及PCIe核是否生成正确的MSI/MSI-X TLP。 * **硬件测试:** * 用更新的固件编程FPGA。 * 使用主机端软件触发应引起中断的事件(例如,启动完成的DMA传输)。 * 确认主机操作系统接收到中断。在Linux上,`dmesg`可以显示中断消息。在Windows上,您可以使用特定的驱动程序调试工具或事件查看器。 * **调试工具:** 利用Vivado的集成逻辑分析仪(ILA)核(如第12节所述)实时监控`event_trigger`、`msi_req_o`和PCIe核的TLP输出信号,以验证正确的中断生成。 5. **保存更改:** * 完成所有代码修改并保存相关固件文件。 * 根据测试结果审查并改进您的中断逻辑,以确保可靠性。 --- ## **9. 仿真设备特定功能** 除了标准的PCIe配置空间和通用DMA功能之外,许多捐赠设备还具有独特的功能、自定义寄存器或厂商特定功能,这些对于其完整功能或与其专有驱动程序交互至关重要。精确的仿真需要理解和复制这些细微之处。本节将深入探讨如何实现这些高级功能,从而实现更忠实和功能更全面的仿真。 ### **9.1 实现高级PCIe功能** PCIe规范包含除了基本配置空间之外的各种*扩展功能*。这些功能提供了高级错误报告、电源管理、虚拟化等特性。实现这些功能有助于您的仿真设备显得更合法,并与现代主机系统正确交互。 **步骤:** 1. **识别所需的扩展功能:** * 在使用Arbor等工具收集捐赠设备信息时,请仔细查找并记录捐赠设备配置空间中存在的任何扩展功能。这些通常在标准配置空间的初始256字节之外找到。 * **常见示例:** * **高级错误报告(AER)**:为PCIe链路提供强大的错误检测、日志记录和报告机制。 * **设备序列号(DSN)**:(已在第6.2节中介绍)。 * **电源管理(PM)**:(已在第8.3.1节中介绍)。 * **PCI Express(PCIe)功能结构**:(已在第8.1节中介绍链路速度/宽度、最大载荷/读取请求,但也包括其他字段,如设备控制/状态、链路控制/状态)。 * **虚拟通道(VC)/多功能虚拟通道(MFVC)**:用于服务质量(QoS)和流量管理。 * **精确时间测量(PTM)**:用于设备之间的时间同步。 * **延迟容忍报告(LTR)**:基于延迟要求进行电源管理。 * **可重置FPC(功能级重置)**:用于更细粒度的重置。 2. **在Vivado PCIe IP核中启用功能:** * 访问Vivado中的PCIe IP核定制窗口(`pcie_7x_0.xci`)。 * 导航到各个选项卡(例如,“PCIe Capabilities”、“Extended Capabilities”、“Advanced Options”)。 * 查找复选框或下拉菜单,以启用和配置从捐赠设备中识别出的特定扩展功能。 * **示例(AER):** 您会找到一个“高级错误报告”部分,您可以在其中启用它并配置其寄存器(例如,严重性掩码)。 * **注意:** Xilinx PCIe IP核为许多标准和扩展功能提供了高度可配置性。通常只需在GUI中启用正确的选项即可。 3. **实现功能寄存器的固件逻辑(如果需要):** * 虽然PCIe IP核处理这些功能的*存在*和大部分*协议*,但某些功能会暴露您的自定义固件可能需要读写或其值需要固件响应的寄存器。 * **示例(AER):** 如果您的仿真设备检测到应通过AER报告的内部错误,您的固件需要写入特定的AER错误状态寄存器(这些寄存器可能作为BAR的一部分暴露,或由PCIe核内部处理,然后反映到用户逻辑)。然后您的用户逻辑将向PCIe核断言错误输入。 * **示例(电源管理):** 如8.3.1节所述,您的固件需要响应PCIe核发出的D状态变化。 * **流程:** * 识别您的捐赠设备驱动程序交互的每个已启用功能结构中的特定寄存器。 * 在PCILeech-FPGA框架中找到与这些寄存器接口的相应信号或逻辑(通常在`pcileech_pcie_cfg_a7.sv`或`bar_controller`中)。 * 实现这些寄存器的读写逻辑,确保您的仿真设备的内部状态准确反映驱动程序期望的值。 ### **9.2 仿真厂商特定功能** 这是真正的“全设备仿真”变得高度专业化的部分。许多实际设备具有独特的寄存器、未文档化的命令、自定义数据格式或专有控制流程,这些都使其与众不同。复制这些需要更深入的分析和定制HDL开发。 **步骤:** 1. **逆向工程厂商特定行为:** * 这通常是最具挑战性的部分。 * **静态分析(驱动程序/固件):** 反汇编捐赠设备的官方驱动程序(Windows `.sys`,Linux `.ko`)或设备的原始固件(如果可用)。查找独特的I/O或MMIO访问模式、魔术值或寄存器写入序列。Ghidra、IDA Pro或objdump等工具会非常有价值。 * **动态分析(驱动程序执行):** 运行捐赠设备及其驱动程序,并使用**PCIe协议分析仪**(例如,Teledyne LeCroy,Keysight,如第12.2节所述)监控PCIe流量。这是理解实际TLP交换,包括厂商定义消息和寄存器访问序列的黄金标准。请注意: * BARs中访问的特定内存地址。 * 对这些地址的读/写模式。 * 写入或读取特定寄存器的值。 * 命令和响应之间的时序关系。 * **系统调用/API监控**:在主机上,使用Procmon(Windows)或`strace`(Linux)等工具查看驱动程序如何与操作系统交互以及它使用了哪些特定的设备I/O控制(IOCTL)代码,这些代码可能对应于特定的硬件操作。 * **硬件嗅探**:如果可能,使用硬件嗅探器(如Saleae逻辑分析仪)捕获设备内部总线(例如SPI,I2C)上的信号,如果它有外部闪存或组件。 2. **在BARs中实现自定义寄存器和逻辑:** * 一旦您识别出厂商特定的寄存器或命令协议,您将需要将这些定义到您的FPGA固件中,通常作为可通过您的某个BAR访问的内存映射寄存器。 * **创建内部寄存器:** 在您的SystemVerilog代码中声明`reg`变量来表示这些自定义寄存器。 ```verilog // 在pcileech_tlps128_bar_controller.sv或子模块中 reg [31:0] custom_control_reg; reg [31:0] custom_status_reg; reg [31:0] custom_data_reg; // 示例:将它们映射到BAR0中的特定偏移量(假设BAR0足够大) // 调整'bar0_offset' case语句(来自第8.2.2节) // ... if (bar_hit[0]) begin if (req_write) begin case (bar0_offset) 32'h0000_1000: custom_control_reg <= req_data; // 自定义控制寄存器 32'h0000_1004: custom_data_reg <= req_data; // 自定义数据写入寄存器 // ... 其他映射 endcase end else if (req_read) begin case (bar0_offset) 32'h0000_1000: rsp_data = custom_control_reg; // 读取控制寄存器 32'h0000_1008: rsp_data = custom_status_reg; // 自定义状态寄存器 // ... 其他映射 endcase end end // ... ``` * **实现行为逻辑:** 创建SystemVerilog逻辑(状态机、组合逻辑),用于: * 响应对`custom_control_reg`的写入。例如,此寄存器中的某个特定位可能触发DMA传输、清除状态标志或启动内部操作。 * 根据仿真设备的内部状态更新`custom_status_reg`(例如,“操作完成”、“发生错误”、“数据可用”)。 * 处理写入`custom_data_reg`的数据,或在读取时从中提供数据,模仿捐赠设备的数据路径。 3. **仿真厂商特定消息(如果适用):** * 一些复杂设备可能通过PCIe使用“厂商定义消息”(VDM)进行特定控制或通信。如果您的分析揭示了此类消息,您将需要: * 在PCIe IP核中启用VDM支持(如果可用)。 * 实现TLP生成逻辑(如第10节所述)来制作和发送这些VDM。 * 实现TLP接收和解析逻辑来解释来自主机的传入VDM。 4. **验证仿真行为:** * **迭代测试:** 这是一个高度迭代的过程。进行小修改,编译,烧录,然后测试。 * **驱动程序加载:** 捐赠设备的驱动程序是否正确加载而没有错误? * **功能测试:** 驱动程序能否启动基本操作?它是否从您的仿真寄存器获得预期的响应? * **应用程序测试:** 依赖捐赠设备的应用程序能否在您的仿真版本下正常运行? * **调试:** 广泛使用ILA和PCIe协议分析仪来比较您的仿真设备的行为与真实捐赠设备捕获的行为。寻找TLP时序、寄存器值和总体协议流中的差异。 --- ## **10. 事务层数据包(TLP)仿真** 事务层数据包(TLP)是PCIe架构中通信的基本单位。主机系统与PCIe设备之间的每一次交互,从配置读取到数据传输,都被封装在一个或多个TLP中。精确的TLP仿真不仅重要;它对于您的仿真设备与主机系统正确交互,确保驱动程序正常运行和数据按预期移动,是*至关重要*的。 ### **10.1 理解和捕获TLP** 在您能够制作自定义TLP之前,您必须深入理解它们的结构和常见类型。从您的捐赠设备捕获真实世界的TLP可提供最精确的蓝图。 * **TLP结构的学习**: TLP通常由报头、可选数据载荷和可选的端到端CRC(ECRC)组成。报头至关重要,它定义了TLP的类型、事务细节和路由信息。 * **TLP的组成部分**: * **报头(Header)**:最重要的部分,通常是3或4个双字(Dword = 4字节)。它包含定义TLP目的和处理方式的关键字段: * **Fmt(格式)和 Type(类型)**:定义TLP的格式(3DW/4DW,带/不带数据)及其特定目的(例如,内存读取请求、内存写入、完成、配置读取/写入)。 * **Length(长度)**:指定数据载荷的长度(以双字为单位)。 * **Requester ID(总线、设备、功能)**:标识发起请求的PCIe功能。对于将完成数据路由回正确的源头至关重要。 * **Tag(标签)**:由请求者分配给事务的唯一标识符,允许完成者将完成TLP与其原始请求TLP匹配。 * **Address(地址)**:对于内存/IO事务,这是目标内存或I/O地址。 * **First DW Byte Enable (FBE)** 和 **Last DW Byte Enable (LBE)**:指定数据载荷的第一个和最后一个双字中哪些字节对于写入操作有效,或哪些字节正在请求读取完成。 * **Traffic Class (TC)** 和 **Transaction ID (TID)**:用于QoS和排序规则。 * **数据载荷(可选)**:存在于内存写入、配置写入和读取完成等TLP中。它包含实际传输的数据。 * **端到端CRC (ECRC)(可选)**:一个32位CRC,覆盖整个TLP,确保从源到目的地的数据完整性,通常由软件生成/检查。 * **理解常见的TLP类型**:您的固件将主要处理这些类型: * **Memory Read Request (MRd)**:由请求者(例如,主机CPU,或您的FPGA作为DMA主设备)发送的TLP,用于从特定内存地址读取数据。 * **Memory Read Completion (CplD)**:由完成者(例如,您的FPGA响应主机MRd)发送的TLP,携带请求的数据。 * **Memory Write (MWr)**:由请求者(例如,主机CPU,或您的FPGA)发送的TLP,用于向特定内存地址写入数据。 * **Completion Without Data (Cpl)**:由完成者发送的TLP,用于确认不返回数据的请求(例如,成功的MWr)。 * **Configuration Read Request (CfgRd)**:来自主机的TLP,用于读取设备配置空间中的寄存器。 * **Configuration Read Completion (CplD)**:来自设备返回CfgRd数据数据的TLP。 * **Configuration Write Request (CfgWr)**:来自主机的TLP,用于写入设备配置空间中的寄存器。 * **Vendor-Defined Messages (VDM)**:特定厂商用于专有通信的自定义TLP。 #### **10.1.2 从捐赠设备捕获TLP** 从您的捐赠设备捕获真实的PCIe流量是无价的。它提供了TLP结构、序列和时序的具体示例,使您能够精确地复制它们。 * **步骤**: 1. **设置PCIe协议分析仪**: * 最有效的方法是使用专用的硬件工具,通常称为“PCIe协议分析仪”。这些设备位于主机和捐赠PCIe卡之间,被动捕获所有流量。 * **示例**: * **Teledyne LeCroy PCIe 分析仪**:行业标准,功能强大,但投资巨大。 * **Keysight PCIe 分析仪**:另一个领先的供应商。 * (对于基本调试,一些带PCIe解码器的高端逻辑分析仪可能提供有限的TLP查看功能,但真正的协议分析仪更优越)。 2. **捕获事务**: * 在连接了协议分析仪的测试系统中安装捐赠设备。 * 运行捐赠设备的驱动程序和任何相关应用程序。 * 在正常操作期间,尤其是关键阶段,监控和记录PCIe事务,例如: * 设备枚举(操作系统首次检测到它时)。 * 驱动程序加载和初始化。 * 典型数据传输操作(例如,存储设备的大文件复制,网卡的网络流量)。 * 设备特定命令或诊断。 3. **分析捕获的TLP**: * 使用协议分析仪的先进软件解剖捕获的TLP。软件将解码字段,提供时间顺序视图,并允许过滤和搜索。 * 密切关注: * 精确的`Fmt`和`Type`字段。 * `Requester ID`和`Tag`值(特别是对于完成)。 * 内存事务的`Address`和`Length`。 * 写入和读取完成的`Data Payload`内容。 * 任何厂商特定字段或自定义TLP。 #### **10.1.3 记录关键TLP事务** 对捕获的TLP进行结构化文档创建了一个用于您的仿真的蓝图。 * **步骤**: 1. **识别关键事务**: * 重点关注对设备核心功能至关重要的TLP。这包括: * **初始化序列**:操作系统在枚举期间执行的一系列配置读/写。 * **驱动程序初始化**:驱动程序启动时交换的命令和数据。 * **主要数据传输**:`MWr`和`MRd` TLP如何为设备的主要功能构建和完成。 * **错误处理**:设备如何报告错误(例如,带有Completer Abort (CA)、Unsupported Request (UR)的Completion)。 * **电源管理转换**:与D状态变化相关的TLP。 * **中断生成**:MSI/MSI-X消息如何发送。 * 协议分析仪的截图在这里会非常有帮助。 2. **创建详细文档**: * 对于每个关键TLP序列,记录: * **TLP类型**(例如,MWr、MRd、CplD)。 * 其**报头字段**(Fmt、Type、Requester ID、Tag、Length、Address、Byte Enables)。 * **数据载荷**(如果适用)。 * 事务中的**序列号**或顺序。 * 发送它的**条件**(例如,“主机在驱动程序初始化时发送”,“设备在DMA完成时发送”)。 * 任何**预期的响应**或后续TLP。 * 协议分析仪的截图在这里会非常有帮助。 3. **理解时序和序列**: * 除了TLP内容,TLP的*时序*和*序列*至关重要。PCIe有严格的排序规则和流控制机制。注意: * **请求和完成之间的延迟**:真实设备响应的速度。 * **流控制信用**:设备如何管理其传入/传出TLP的缓冲区空间。虽然Xilinx PCIe IP核处理基本的流控制,但对于高级仿真,了解捐赠设备的典型信用使用情况会有所帮助。 * **事务层数据包排序**:理解posted(写入)和non-posted(读取、完成)事务如何排序。 ### **10.2 制作用于特定操作的定制TLP** 一旦您理解了蓝图,您就可以将这些知识转化为您的FPGA固件(SystemVerilog),以主动生成和响应TLP。PCILeech-FPGA框架提供了抽象层,但对于深度仿真,您可能需要直接与TLP生成/解析逻辑交互。 #### **10.2.1 在固件中实现TLP处理** 您的固件需要逻辑来发送和接收TLP。PCIe IP核处理物理层和数据链路层,向您的用户逻辑暴露一个事务层接口(通常是AXI-Stream)。 * **要修改的文件(主要)**: * `pcileech-fpga//src/pcileech_pcie_tlp_a7.sv`(或类似文件,取决于板卡变体) * 此文件通常包含将用户请求转换为出站TLP并将传入TLP解析为用户逻辑信号的核心逻辑。 * `pcileech-fpga//src/pcileech_tlps128_bar_controller.sv` * 此模块专门处理解析目标为设备BAR的传入内存读/写TLP,并生成相应的完成TLP。 * **步骤**: 1. **理解PCIe IP核接口**: * 在编写TLP逻辑之前,请彻底阅读Xilinx PCIe IP核用户指南(特别是关于用户应用接口或AXI4-Stream接口的部分)。这定义了您的SystemVerilog逻辑如何连接到PCIe核以发送和接收TLP。您通常会与`s_axis_rx_tdata`(接收到的TLP数据)、`s_axis_rx_tvalid`(接收到有效TLP)、`m_axis_tx_tdata`(传出TLP数据)、`m_axis_tx_tready`(核已准备好接受TLP)等进行交互。 2. **创建TLP生成函数(用于出站TLP)**: * 在`pcileech_pcie_tlp_a7.sv`(或与`m_axis_tx_*`接口的模块)中,您将编写逻辑来组装具有所需报头和载荷的TLP。这通常涉及将各种字段组合成一个`[127:0]`(对于128位接口)或`[63:0]`(对于64位接口)总线,该总线馈送PCIe核。 * **示例(概念性,简化函数,用于3DW TLP报头):** ```verilog // 这是一个概念性辅助函数。实际上,您将构建一个状态机 // 通过AXI-Stream接口发送TLP,可能使用FIFO。 function automatic [95:0] create_3dw_tlp_header; // 假设3个双字 = 96位 input logic [7:0] tlp_type_fmt; // 格式和类型字段 input logic [15:0] requester_id; // BDF input logic [7:0] tag; input logic [7:0] lower_address_bits; // 或更复杂的地址 input logic [7:0] byte_enables; // 第一个双字字节使能 begin create_3dw_tlp_header = { tlp_type_fmt, // Fmt[6:4], Type[3:0] 8'b0, // 保留 4'b0, // TC[3:0] (流量类别) 3'b0, // Attr[2:0] 1'b0, // TH (TLP提示) 2'b0, // D(igest) (ECRC存在) 1'b0, // EP (Poisoned) 1'b0, // TD (类型依赖) // DW0: Fmt, Type, TC, Attr, TH, D, EP, TD, Length (不在3DW中, 4DW有) requester_id, // 请求者ID (Bus[7:0], Device[4:0], Function[2:0]) tag, // 标签 lower_address_bits, // 示例:地址的低位或数据的一部分 byte_enables, // 第一个双字字节使能 4'b0, // 保留 4'b0 // 最后一个双字字节使能 (通常用于MWr) // DW1, DW2... 字段 }; end endfunction // 示例:在状态机中生成带数据的完成(CplD) // 这只是一个片段,不是完整实现 localparam CPLD_3DW_FMT = 8'h4A; // Fmt=100 (4DW, 带数据), Type=1010 (Cpl) localparam CPL_D_FMT_TYPE_LEN = 8'h4A; // 根据PCIe规范调整。(带数据的4DW报头) // ... 发送TLP的状态机 // 在准备发送CplD的状态下 if (tx_ready_from_pcie_core) begin // 构建报头和载荷 // 对于CplD,您需要Compliter ID, Status, Byte Count, Requester ID, Tag, Completion ID, Lower Address // 然后是实际的读取数据载荷 m_axis_tx_tdata_reg = { CPL_D_FMT_TYPE_LEN, // 字节0: Fmt/Type tlp_length_dw_minus_one, // 字节1: TLP长度 (以双字为单位) - 1 status_completion_bits, // 字节2: Cpl Status, BCM, Rsvd byte_count_dws_upper, // 字节3: 字节计数 (高位) requester_id, // 字节4-5: 请求者ID (来自原始MRd) tag, // 字节6: 标签 (来自原始MRd) byte_count_dws_lower, // 字节7: 字节计数 (低位) completion_id, // 字节8-9: 完成ID (您的BDF) lower_address_from_request // 字节10-11: 请求的低位地址 // ... 接着是实际的数据载荷 }; m_axis_tx_tvalid_reg = 1'b1; m_axis_tx_tlast_reg = 1'b1; // 最后一个TLP片段 // ... 状态转换以等待tready end ``` * **注意**:实际实现涉及状态机、FIFO,以及遵循PCIe IP核的AXI-Stream协议。PCILeech-FPGA框架已经为此提供了良好的基础,但您可能需要为非常特定的TLP行为进行扩展或修改。 3. **处理TLP接收(用于入站TLP)**: * 实现逻辑以解析来自PCIe核接收接口的传入TLP(例如,`s_axis_rx_tdata`、`s_axis_rx_tvalid`)。 * 此解析包括: * 检查`s_axis_rx_tvalid`以判断是否存在TLP。 * 从TLP报头中读取`Fmt`和`Type`字段以确定其目的。 * 提取`Requester ID`、`Tag`、`Address`、`Length`和`Data Payload`等相关字段。 * 使用`case`语句或`if/else if`块,根据TLP类型将信息路由到适当的内部逻辑(例如,用于内存写入的`bar_controller`,用于配置写入的配置模块)。 * **示例(概念性,简化解析):** ```verilog // 在pcileech_pcie_tlp_a7.sv或TLP解析模块中 input wire [127:0] s_axis_rx_tdata; input wire s_axis_rx_tvalid; output wire s_axis_rx_tready; // 需要断言此信号以接受更多数据 reg [7:0] received_tlp_fmt_type; reg [15:0] received_requester_id; // ... 声明其他已解析的字段 assign s_axis_rx_tready = 1'b1; // 为简化起见始终准备好接收,在实际设计中管理反压 always @(posedge clk) begin if (s_axis_rx_tvalid) begin received_tlp_fmt_type = s_axis_rx_tdata[127:120]; // 假设最高位 received_requester_id = s_axis_rx_tdata[111:96]; // 示例偏移量 // 根据TLP类型解码 case (received_tlp_fmt_type[3:0]) // 仅TLP类型位 4'h0: // 内存写入 (3DW或4DW取决于Fmt) // 提取地址、长度、载荷并传递给BAR控制器 begin // 传递给BAR控制器,用于写入仿真内存 // bar_write_enable = 1'b1; // bar_write_address = s_axis_rx_tdata[...]; // bar_write_data = s_axis_rx_tdata[...]; end 4'h1: // 内存读取 // 提取地址、长度,并传递给BAR控制器进行读取 begin // bar_read_enable = 1'b1; // bar_read_address = s_axis_rx_tdata[...]; // (完成将由BAR控制器生成) end // ... 其他TLP类型 default: begin // 处理不支持或保留的TLP类型(例如,日志记录、错误) end endcase end end ``` 4. **确保符合性**: * 严格验证您生成和解析的TLP是否符合PCIe规范的格式、字段定义和时序。偏差将导致通信失败。 5. **实现完成处理**: * 对于从主机接收到的内存读取请求(MRd)和配置读取请求(CfgRd),您的设备必须在指定的时间内返回适当的完成TLP(CplD表示数据,Cpl表示无数据)。`bar_controller`模块(第8.2.2节)是此BAR读取逻辑所在的位置。 6. **保存更改**: * 保存文件(`pcileech_pcie_tlp_a7.sv`、`pcileech_tlps128_bar_controller.sv`或任何自定义模块)后,实现更改。 #### **10.2.2 处理不同TLP类型** 每种TLP类型都有特定的报头格式和行为。您的固件必须擅长处理与您的捐赠设备相关的那些类型。 * **内存读取请求(MRd)**: * **实现**: * 当接收到MRd TLP(由`pcileech_pcie_tlp_a7.sv`解析并路由到`bar_controller`)时,`bar_controller`需要: * 解析请求的地址和长度。 * 从适当的内部内存位置(例如,连接到BAR的BRAM)或内部寄存器中获取数据。 * 组装一个**带数据的完成(CplD)** TLP。关键是,此TLP必须包含来自MRd请求的原始`Requester ID`、`Tag`和`Completion ID`(您的设备BDF),以及获取的数据载荷。 * 通过PCIe IP核的传输接口将CplD TLP发送回主机。 * **内存写入请求(MWr)**: * **实现**: * 当接收到MWr TLP时,`bar_controller`需要: * 解析目标地址、长度和`Byte Enables`(FBE/LBE)。 * 提取`数据载荷`。 * 将数据写入仿真设备内的指定内存位置(例如,BRAM或内部寄存器),并遵循字节使能。 * 内存写入是“posted事务”,这意味着它们不需要完成TLP进行确认,除非发生错误。 * **配置读/写请求(CfgRd/CfgWr)**: * **实现**: * 这些TLP针对设备的配置空间(厂商ID、设备ID、BAR、功能等)。Xilinx PCIe IP核根据其配置自动处理大部分标准配置空间访问。 * 但是,如果您的配置空间中存在非标准的自定义寄存器或扩展功能,您可能需要特定的逻辑来: * 对于CfgRd:从您的内部`cfg_`寄存器返回请求的数据。 * 对于CfgWr:更新您的内部`cfg_`寄存器或根据写入的数据触发操作。 * 配置读取需要**带数据的完成(CplD)**,而配置写入需要**不带数据的完成(Cpl)**。 * **厂商定义消息(VDM)**: * **实现**: * 如果您的捐赠设备使用VDM,这将需要专门的解析和响应逻辑。 * **解析传入VDM**:根据其`Fmt`和`Type`字段识别VDM。提取厂商特定数据并根据您的逆向工程发现进行解释。 * **制作出站VDM**:当您的仿真设备需要发送VDM时,创建逻辑来组装具有精确厂商特定报头和载荷格式的VDM。 #### **10.2.3 验证TLP时序和序列** 即使TLP格式完美,不正确的时序或序列也会导致设备故障或被检测为不兼容。 * **步骤**: 1. **使用仿真工具**: * **测试平台**:为您的TLP生成和解析模块开发全面的SystemVerilog测试平台。 * 模拟各种场景(例如,主机发送MRd,您的设备发送CplD;主机发送MWr;主机枚举设备),以验证TLP是否正确形成、传输、接收和处理。 * 验证TLP的序列,并确保在合理的时间内发送完成。 2. **使用ILA监控(集成逻辑分析仪)**: * 如第12.1节所述,在您的Vivado设计中插入一个ILA核。 * 将ILA探头连接到PCIe IP核的AXI-Stream接口(例如,`s_axis_rx_tdata`、`s_axis_rx_tvalid`、`m_axis_tx_tdata`、`m_axis_tx_tready`)。 * 设置触发器以捕获特定TLP(例如,在`m_axis_tx_tvalid`上针对某种TLP类型触发)。 * 这使您可以在硬件操作期间实时查看FPGA上的实际TLP位,验证您的固件是否向/从PCIe IP核发送/接收正确的数据和控制信号。 3. **检查时序约束**: * PCIe IP核对其AXI-Stream接口有严格的时序要求。确保您的用户逻辑向`m_axis_tx_tdata`提供数据和处理`s_axis_rx_tdata`满足这些时序约束。 * Vivado的时序分析报告(综合和实现后)将标记任何违规。通过优化您的逻辑或在可能的情况下调整时钟来解决这些问题。 4. **符合性测试(高级)**: * 对于高保真仿真,请考虑使用专用的PCIe符合性测试套件(通常与高端协议分析仪集成)。这些测试系统地检查是否符合PCIe规范,揭示细微的协议违规。 5. **保存更改**: * 在彻底测试和验证后保存所有修改过的文件。迭代是TLP级调试的关键。 --- ## **第三部分:高级技术与优化** --- ## **11. 构建、烧录与测试** 完成所有定制后,就到了验证的时刻:构建固件,将其编程到您的FPGA上,并严格测试其功能,以确保它与捐赠设备的行为完全一致。此阶段将您的设计从代码转换为可工作的硬件仿真。 ### **11.1 综合与实现** 这是FPGA设计流程中的核心步骤,您的SystemVerilog高级代码将被转换为可以加载到FPGA上的低级硬件配置。 #### **11.1.1 运行综合** 综合是Vivado将您的HDL代码转换为门级网表(逻辑门及其互连的描述)的过程。它还执行初步的时序分析和资源估算。 * **步骤**: 1. **开始综合**: * 在Vivado GUI中,在 **Flow Navigator**(流程导航器)窗格(通常在左侧)中,在“Synthesis”(综合)下,点击 **Run Synthesis**(运行综合)。 2. **监控进度**: * Vivado将打开一个“Launch Runs”(启动运行)对话框。您通常只需点击“OK”。 * 监控Vivado窗口底部的 **Messages**(消息)选项卡。它将显示综合运行的进度。 * **常见警告/错误关注点**: * **`[Synth 8-327]` Unconnected Ports / Unused Inputs(未连接端口/未使用的输入)**:这表明您设计中的信号或端口未连接到任何东西。虽然有时是故意的(例如,FPGA上未使用的引脚),但它们也可能指向端口名称中的拼写错误或遗忘的连接。检查每个警告以确保这不是功能问题。 * **`[Synth 8-256]` Registers/Wires Not Optimized(寄存器/线未优化)**:这可能表明逻辑推断不正确,或者您有冗余逻辑可以优化。 * **Syntax Errors(语法错误)**:如果您的SystemVerilog代码中有致命的语法错误,综合将立即失败。请在Visual Studio Code中修复这些错误。 3. **审查综合报告**: * 成功完成后,Vivado将询问您下一步要做什么。选择 **Open Synthesized Design**(打开综合设计)或 **Open Report**(打开报告)。 * 最重要的是,查看综合报告中的 **Utilization Summary**(资源利用率摘要)。这显示了您的设计消耗了FPGA多少资源(LUT、触发器、BRAM、DSP)。确保设计适合您的目标FPGA的容量(例如,对于Artix-7 35T,您应该在其限制内)。 #### **11.1.2 运行实现** 实现是最耗时的一步。它接收综合后的网表并将其物理映射到FPGA的资源上(放置逻辑块,布线连接),然后执行详细的时序分析,以确保设计能够以指定的时钟频率运行。 * **步骤**: 1. **开始实现**: * 成功综合后,在 **Flow Navigator**(流程导航器)中,在“Implementation”(实现)下,点击 **Run Implementation**(运行实现)。 * 确认“Launch Runs”(启动运行)对话框。 2. **监控进度**: * 实现包括几个阶段:Opt Design(优化设计)、Power Opt Design(功耗优化设计)、Place Design(放置设计)、Post-Placement Phys Opt Design(后放置物理优化设计)、Route Design(布线设计)、Post-Route Phys Opt Design(后布线物理优化设计)。每个阶段都可能需要大量时间。 * 监控 **Messages**(消息)选项卡以了解进度和潜在问题。 3. **分析时序报告**: * 这是实现后*最关键的步骤*。完成后,Vivado会再次询问下一步做什么。选择 **Open Implemented Design**(打开已实现设计),或者更重要的是,选择 **Open Report**(打开报告),然后选择 **Report Timing Summary**(报告时序摘要)。 * **确保所有时序约束都得到满足。** 查找“WNS (Worst Negative Slack)”值。 * **正WNS**:表示所有时序路径都满足其要求(有余量)。这是您想要的结果。 * **负WNS**:表示**时序违规**,这意味着您的设计无法在所需的时钟频率下运行,或者数据可能不稳定。**这是一个必须解决的关键问题。** * **解决违规**: * 如果您有负余量,请调查失败的具体路径。Vivado的时序报告将显示失败路径的源、目标和组件。 * 解决方案可以包括: * 优化HDL代码以减少逻辑深度或关键路径延迟。 * 添加流水线级(寄存器)以打断长组合路径。 * 改进XDC(约束)文件,确保所有时钟都正确定义和传播。 * 调整时钟频率(如果应用程序允许)。 * 在Vivado中使用更快的时序收敛策略。 * 确保您的自定义逻辑与PCIe核的AXI-Stream接口时序要求正确接口。 4. **验证布局(可选)**: * 在已实现的设计中,您可以打开“Device”(器件)视图,查看您的逻辑如何在FPGA上布局。这通常适用于高级用户,以确认关键组件是否最佳布局(例如,靠近PCIe收发器)。 #### **11.1.3 生成比特流** 比特流是最终的二进制配置文件(`.bit`扩展名),将被加载到您的FPGA上。它是综合和实现的成果。 * **步骤**: 1. **生成比特流**: * 成功实现后(没有严重的时序违规),在 **Flow Navigator**(流程导航器)中,在“Program and Debug”(编程和调试)下,点击 **Generate Bitstream**(生成比特流)。 2. **等待完成**: * 此过程通常比实现花费的时间少,但仍可能因设计复杂性而异。 3. **审查比特流生成日志**: * 完成后,Vivado会指示成功。审查日志中是否有任何警告,但通常如果实现顺利通过,比特流生成也会顺利通过。 * `.bit`文件将生成在您的项目目录`pcileech_squirrel_top.runs/impl_1/`(或您的板卡类似路径)中。 ### **11.2 烧录比特流** 编程(烧录)比特流会将您编译的设计加载到FPGA上,使您的仿真设备激活。 #### **11.2.1 连接FPGA设备** * **步骤**: 1. **准备硬件**: * 确保您的基于FPGA的DMA板卡已正确插入主机系统的兼容PCIe插槽。 * 将JTAG编程器(例如,Digilent HS3,Xilinx Platform Cable)连接到FPGA板卡上的JTAG接口和开发PC的USB端口。 * 打开主机系统电源。 * 请参阅您的特定FPGA板卡手册,了解精确的电源、JTAG和PCIe连接说明。 2. **打开硬件管理器**: * 在Vivado中,导航到 **Flow Navigator > Program and Debug > Open Hardware Manager**(流程导航器 > 编程和调试 > 打开硬件管理器)。 * 如果Vivado未运行,您可以作为独立应用程序启动硬件管理器。 #### **11.2.2 编程FPGA** * **步骤**: 1. **连接到目标**: * 在硬件管理器窗口中,点击 **Open Target**(打开目标)(通常是一个大按钮或链接),然后选择 **Auto Connect**(自动连接)。 * Vivado应该自动检测到您的JTAG编程器,然后检测到JTAG链上连接的FPGA设备。如果检测失败,请检查JTAG电缆连接、板卡电源以及PC上的JTAG驱动程序。 2. **编程设备**: * 一旦您的FPGA设备在硬件窗口中被检测并显示,**右键单击** 您的FPGA设备(例如,`xc7a35t_0`)并选择 **Program Device**(编程设备)。 * 将出现一个对话框。点击“Bitstream file”(比特流文件)字段旁边的“...”按钮,导航到您生成的比特流文件(例如,`pcileech_squirrel_top.runs/impl_1/pcileech_squirrel_top.bit`)。 * 点击 **Program**(编程)开始将固件烧录到FPGA上。 * 等待编程过程完成。您将看到一个进度条。 #### **11.2.3 验证编程** * **步骤**: 1. **检查状态**: * 确保编程在Vivado的硬件管理器中无错误地完成。Vivado将在完成后显示“Program Device”成功消息。 2. **观察LED或指示灯**: * 许多FPGA板卡都有状态LED。成功的编程操作通常会导致特定LED亮起或改变状态(例如,“DONE”LED)。这是一个快速的视觉确认。 3. **主机系统重启(有时需要)**: * 为了让主机操作系统正确识别新编程的PCIe设备,通常需要系统重启,尤其是在Windows上,以触发完整的PCIe枚举过程。 ### **11.3 测试与验证** 编程完成后,关键一步是验证您的仿真设备是否被主机正确检测,并且其功能是否按预期工作,模仿捐赠设备。 #### **11.3.1 验证设备枚举** 这证实主机操作系统根据您编程的ID将您的FPGA识别为捐赠设备。 * **Windows**: * **步骤**: 1. **打开设备管理器**:按下 `Win + X` 并从快速链接菜单中选择 **Device Manager**(设备管理器)。 2. **检查设备属性**: * 在适当的设备类别下查找(例如,**Network Adapters**(网络适配器)、**Storage Controllers**(存储控制器)、**System devices**(系统设备))。 * 找到您的仿真设备。它现在应该显示为*捐赠设备的名称*(例如,“Intel(R) Ethernet Connection...”)。 * 右键单击该设备,选择 **Properties**(属性),然后转到 **Details**(详细信息)选项卡。 * 在“Property”(属性)下拉菜单中,选择“Hardware Ids”(硬件ID)。确认 **设备ID(DID)** 和 **厂商ID(VID)**(例如,`PCI\VEN_ABCD&DEV_1234`)与您编程到固件中的值匹配。 * 还应检查“Class Code”(类别代码)和“Subsystem ID”(子系统ID)以进行进一步验证。 * **Linux**: * **步骤**: 1. **使用 `lspci`**:打开终端并使用`lspci`命令。 ```bash lspci -nn # 显示厂商ID:设备ID lspci -vvv # 显示包括BAR、功能等详细信息 ``` 2. **验证设备列表**: * 检查仿真设备是否在`lspci`输出中显示了正确的厂商ID、设备ID和类别代码。 * **示例输出(仿真Intel NIC)**: ``` 03:00.0 Network controller [0280]: Intel Corporation Ethernet Connection I219-V [8086:1570] (rev 21) ``` (`8086`是Intel的厂商ID,`1570`是I219-V的设备ID,`0280`是网络控制器类别代码)。 * 使用`lspci -vvv`确认BAR是否以正确的大小和类型枚举,与您的捐赠设备配置匹配。 #### **11.3.2 测试设备功能** 一旦设备被枚举,最终的测试是它是否像原始设备一样工作。 * **步骤**: 1. **安装必要的驱动程序**: * 如果主机操作系统未自动加载合适的驱动程序,您将需要手动安装捐赠设备的官方驱动程序。从制造商网站下载它们。 * 按照制造商的说明进行安装。如果仿真成功,驱动程序应该安装并识别您的FPGA为真实硬件。 2. **执行功能测试**: * 运行通常与捐赠设备交互的应用程序或实用程序。 * **示例**: * **网卡**:执行ping测试、浏览网页或启动大文件传输以测试吞吐量。 * **存储控制器**:尝试格式化模拟驱动器(如果您的仿真包括存储功能),执行读/写操作,或运行磁盘基准测试。 * **USB控制器**:连接USB设备(如果您的仿真包括USB主机功能)并测试它们的检测和操作。 * 监控主机系统以获取预期的行为和性能特征。 3. **监控系统行为**: * 检查系统稳定性(Windows上没有蓝屏,Linux上没有内核崩溃)。 * 在系统日志中查找设备特定错误(Windows上的事件查看器,Linux上的`dmesg`或`journalctl`)。 * 确保仿真设备在各种工作负载下(包括大数据传输或压力测试)按预期运行。 #### **11.3.3 监控错误** 主动的错误监控对于识别可能不会立即导致崩溃的细微仿真问题至关重要。 * **Windows**: * **步骤**: 1. **检查事件查看器**:按下 `Win + X` 并选择 **Event Viewer**(事件查看器)。 2. **查找与PCIe相关的错误**:导航到 **Windows Logs > System**(Windows 日志 > 系统)。筛选或搜索与“PCIe”、“PCI Express”相关的警告、错误或关键事件,或源自特定设备驱动程序的事件(查找与您的仿真设备驱动程序匹配的源名称)。 * 常见错误包括资源冲突、驱动程序初始化失败或意外的设备响应。 * **Linux**: * **步骤**: 1. **检查 `dmesg` 日志**:打开终端并输入: ```bash dmesg | grep -i pci # 不区分大小写地搜索pci消息 dmesg | grep -i # 过滤您的设备的厂商ID ``` 2. **识别问题**:查找指示PCIe链路训练问题、设备初始化问题、内存分配失败或意外DMA活动的消息。Linux内核的PCIe子系统非常详细。 * **Systemd Journal (现代Linux)**: ```bash journalctl -b | grep -i pci # 当前引导日志 ``` --- ## **12. 高级调试技术** 当问题出现时,特别是在复杂的PCIe设备仿真中,基本的故障排除可能不足以解决问题。高级调试工具和技术提供对FPGA内部逻辑和PCIe总线的深入可见性,使您能够高效地识别和解决问题。 ### **12.1 使用Vivado的集成逻辑分析仪(ILA)** 集成逻辑分析仪(ILA)是Xilinx提供的一种强大、可配置的调试IP核,您可以直接将其嵌入到FPGA设计中。它允许您监控内部FPGA信号(线和寄存器)的实时行为,而无需外部探测硬件,其功能类似于一个强大的内部示波器或逻辑分析仪。 #### **12.1.1 插入ILA核** * **步骤**: 1. **规划您的探头**:确定您需要观察的关键信号。对于PCIe仿真,这些信号通常包括: * PCIe IP核的AXI-Stream接口(例如,`s_axis_rx_tdata`、`s_axis_rx_tvalid`、`m_axis_tx_tdata`、`m_axis_tx_tready`)。 * 内部状态机信号(`current_state`、`next_state`)。 * BAR地址解码输出(`bar_hit[0]`、`bar_hit[1]`)。 * 自定义寄存器值(`custom_control_reg`、`custom_status_reg`)。 * 中断请求信号(`msi_trigger_signal`)。 2. **添加ILA IP核**: * 在Vivado中,打开 **IP Catalog**(IP目录)(通常在 **Flow Navigator**(流程导航器)窗格中)。 * 搜索“ILA”(Integrated Logic Analyzer)。 * 双击“Debug Bridge”(用于基本ILA)或“Integrated Logic Analyzer (ILA)”以打开其定制GUI。 * 配置ILA: * 设置您需要的**捕获数据端口数量**(探头)。 * 设置每个探头的**宽度**以匹配您计划连接的信号。 * 配置**采样深度**(在触发前/后存储多少个样本)。更深的深度会消耗更多BRAM。 * 点击“OK”并让Vivado生成IP。 3. **实例化并连接信号**: * Vivado将生成ILA的`.xci`文件。您可以将其直接实例化在您的顶层SystemVerilog文件(例如,`pcileech_squirrel_top.sv`)中,或在可用信号的模块中。 * **示例(在`pcileech_squirrel_top.sv`或子模块中):** ```verilog // 假设您已从IP Catalog生成了ila_0 // 连接到您设计的时钟和感兴趣的信号 ila_0 your_ila_instance ( .clk(clk_125mhz), // 连接到您设计中稳定的时钟,通常是PCIe用户时钟 .probe0(pcie_s_axis_rx_tdata), // 示例:PCIe入站TLP数据 .probe1(pcie_s_axis_rx_tvalid), // 示例:PCIe入站TLP有效 .probe2(pcie_m_axis_tx_tdata), // 示例:PCIe出站TLP数据 .probe3(my_bar_controller_state), // 示例:您的BAR逻辑状态 .probe4(my_custom_register), // 示例:自定义寄存器的值 // 根据需要添加更多探头 .probeN(signal_to_monitor_N) ); ``` * **替代方法(标记用于调试):** 对于更简单的信号,有时可以直接在HDL代码中标记它们用于调试。使用`(* mark_debug = "true" *) wire my_signal;` 或 `(* mark_debug = "true" *) reg my_register;`。Vivado随后会自动建议将它们添加到ILA中。 #### **12.1.2 配置触发条件** 当您配置智能触发条件以精确地在感兴趣的事件发生时(例如,错误、特定TLP类型、状态转换)捕获数据时,ILA最强大。 * **步骤**: 1. **生成带有ILA的比特流**:插入并连接ILA后,您必须运行综合、实现并生成新的比特流。ILA核消耗FPGA资源,并将嵌入到您的设计中。 2. **打开硬件管理器**:使用支持ILA的比特流编程您的FPGA(第11.2节)。然后,在Vivado中,打开硬件管理器并连接到您的目标。 3. **访问ILA仪表板**:在硬件管理器中,选择您的ILA实例(例如,`hw_ila_1`)。这将打开ILA仪表板。 4. **定义触发器**: * 选择要用作触发输入的探头。 * 设置特定的**触发模式**(例如,`pcie_s_axis_rx_tdata`为`0x4A`以触发完成TLP)。 * 配置**触发条件**(例如,“等于”、“不等于”、“上升沿”、“下降沿”)。 * 设置**触发位置**(在触发事件*之前*捕获多少样本,用于预触发可见性)。 * 您可以设置多个触发序列以检测复杂事件。 * **触发器示例场景**: * 在收到的TLP中触发特定的`Fmt/Type`以分析传入命令。 * 当特定寄存器(`my_custom_register`)达到某个值时触发。 * 在`pcie_m_axis_tx_tvalid`断言 AND `pcie_m_axis_tx_tdata[3:0]` == `4'hC`(用于内存写入TLP)时触发,以分析出站写入。 * 在错误信号断言时触发。 #### **12.1.3 捕获和分析数据** * **步骤**: 1. **运行设计**:让您的主机系统与已编程的FPGA交互,从而引发您要调试的事件。 2. **布防ILA**:在ILA仪表板中,点击 **Run Trigger**(运行触发器)按钮(通常是绿色的“播放”图标)。ILA将等待定义的触发条件。 3. **捕获数据**:一旦满足触发条件,ILA将把信号快照捕获到其内部内存缓冲区中。 4. **分析波形**: * 捕获的数据将出现在波形查看器中。 * 检查信号随时间的变化行为。放大、添加光标并解码值。 * 寻找: * **意外的跳变**:信号在错误的时间改变。 * **不正确的值**:寄存器中保存了错误的数据。 * **协议违规**:您的逻辑在PCIe接口上发送了不正确的数据。 * **时序问题**:如果信号在预期时不稳定(尽管完整的时序分析在实现中完成,但ILA显示运行时行为)。 * 将捕获到的行为与您的预期设计逻辑和捐赠设备的观察行为(如果您使用协议分析仪捕获了它)进行比较。 ### **12.2 PCIe流量分析工具** 虽然ILA提供了FPGA内部可见性,但外部PCIe流量分析工具提供了对您的仿真设备和主机之间PCIe总线上实际通信的无与伦比的视图。这对于验证协议符合性和调试链路级问题至关重要。 #### **12.2.1 PCIe协议分析仪(硬件)** * **示例**: * **Teledyne LeCroy PCIe 分析仪**:深度分析的黄金标准,完整的协议解码,高级触发,以及错误注入功能。 * **Keysight PCIe 分析仪**:另一个领先的供应商,具有类似的高端功能。 * **步骤**: 1. **设置分析仪**:将硬件分析仪串联连接在主机系统的PCIe插槽和您的基于FPGA的DMA设备之间。这通常涉及一个特殊的中间卡。 2. **配置捕获设置**:使用分析仪的软件定义要捕获的流量。您可以按TLP类型、地址、请求者ID、错误条件等进行过滤,以关注相关事件。 3. **捕获流量**:在主机上运行您的仿真设备。分析仪将被动记录所有PCIe事务。 4. **分析结果**: * 使用分析仪强大的软件查看解码的TLP、事务列表和波形视图。 * **检查TLP的符合性和正确性**:所有字段都正确吗?序列是否正确? * **识别任何协议违规或意外行为**:这是您发现驱动程序可能失败的原因(例如,您的设备发送了带数据的完成,而规范要求不带数据的完成,或者响应太慢)。 * **与捐赠设备捕获进行比较**:直接比较您的仿真设备捕获的流量与您从真实捐赠设备捕获的流量。这是仿真准确性的最终测试。 #### **12.2.2 基于软件的工具** 对于基本的PCIe总线检查,或者在没有专用硬件分析仪的情况下,一些软件工具可以提供有限的洞察。 * **示例**: * **Wireshark with PCIe Plugins**:虽然Wireshark主要用于网络流量,但通过专用硬件(例如,将PCIe跟踪暴露给操作系统的网卡,或特定的捕获硬件/驱动程序),它有时可以捕获和解码PCIe数据包。这高度依赖于系统。 * **ChipScope Pro(传统Xilinx,现已集成到Vivado中)**:Integrated Logic Analyzer (ILA) 是现代的等效工具,但ChipScope曾是一个独立工具。 * **`lspci` (Linux)**:如第11.3.1节所述,`lspci -vvv`提供了广泛的静态配置空间信息。您可以将其与`watch`或脚本结合使用来监控随时间的变化。 * **`pcileech`客户端(来自PCILeech框架)**:`pcileech`客户端软件本身可以通过您的FPGA执行内存和配置空间的读写操作,并可用于测试基本的DMA功能。虽然不是“流量分析仪”,但它对于测试功能接口至关重要。 * **步骤**: 1. **安装必要的工具/插件**:确保工具已安装并配置了任何所需的驱动程序或插件。 2. **监控PCIe总线**:运行软件工具以捕获和显示PCIe相关信息。 3. **分析通信**: * 查找设备配置中的差异。 * 如果工具支持,分析捕获数据包的结构是否存在异常或错误。 * 验证您的仿真设备是否正确响应了配置请求。 --- ## **13. 故障排除** 本节提供了在PCIe设备仿真定制固件开发、比特流编程和硬件测试过程中可能遇到的常见问题的解决方案。固件调试可能具有挑战性,因此采用系统方法是关键。 ### **13.1 设备检测问题** **问题**:您的基于FPGA的DMA设备在编程后未被主机系统识别,或者在设备管理器/lspci中显示为不正确的ID(例如,“未知设备”)或错误符号。 #### **可能原因及解决方案**: 1. **设备ID、厂商ID、子系统ID或类别代码不正确**: * **原因**:最常见的原因。您编程到FPGA固件中的识别值与主机操作系统预期或您打算仿真的值不匹配。 * **解决方案**: * **验证**:仔细检查`pcileech_pcie_cfg_a7.sv`(或等效文件)中的所有`cfg_deviceid`、`cfg_vendorid`、`cfg_subsysid`、`cfg_subsysvendorid`、`cfg_revisionid`和`cfg_classcode`参数,与您精心记录的捐赠设备信息(来自第5节)进行比对。 * **一致性**:确保这些值在Vivado PCIe IP核定制GUI(第7.2.2节)中也保持一致设置。 * **重新构建并重新烧录**:进行任何更改后,始终重新综合、重新实现、生成新的比特流并重新烧录FPGA(第11.1、11.2节)。 * **重启主机**:烧录后务必重启主机系统,因为Windows通常需要完全重启才能正确重新枚举PCIe设备。 2. **PCIe链路训练失败**: * **原因**:主机根联合体与您的FPGA卡之间的基本PCIe链路未能建立。这发生在任何配置空间读取之前。症状包括设备完全不出现(`lspci`在该总线/插槽上没有任何显示,或设备管理器显示“PCI Express Root Port”错误)。 * **解决方案**: * **物理连接**:确保FPGA板卡牢固地插入PCIe插槽,并且所有电源连接都牢固。如果可能,尝试不同的PCIe插槽。 * **电源**:验证FPGA板卡是否获得足够的电源。某些板卡需要辅助PCIe电源连接器。 * **链路速度/宽度**: * 检查Vivado PCIe IP核中的`Max Link Speed`和`Link Width`设置(第8.1.1节)。 * 尝试将链路速度设置为较低的代数(例如,Gen1 / 2.5 GT/s)并将宽度设置为x1,即使您的板卡支持更高。有时,在较高速度下与特定主板会产生兼容性问题。 * 检查主板BIOS设置中的PCIe插槽速度选项。 * **复位**:确保FPGA的复位逻辑正确实现(例如,与PCIe参考时钟同步),并在上电/重启时正确断言/去断言。 * **PCIe IP核**:确保PCIe IP核正确实例化,并且其时钟和复位在您的顶层设计中正确连接。 3. **电源问题(电源不足或不稳定)**: * **原因**:FPGA板卡未获得足够的稳定电源,或电源供应不稳定,导致操作不可靠。 * **解决方案**: * **验证连接**:仔细检查所有电源线(主PCIe插槽电源、辅助PCIe电源、如果使用则包括外部直流插孔)。 * **电源供应**:确保您的主机系统电源(PSU)具有足够的瓦数和稳定的12V电压轨。对于高功耗FPGA,弱电源可能导致问题。 * **外部电源**:如果板卡有外部电源插孔,请确保使用正确电压和电流额定值的电源。 4. **固件错误(早期阶段)**: * **原因**:SystemVerilog代码中的逻辑错误,特别是顶层模块或PCIe核的包装器中,导致PCIe核无法初始化或正确呈现自身。 * **解决方案**: * **Vivado消息**:仔细检查Vivado的综合和实现日志中与PCIe IP核相关的**严重警告**或**错误**。这些通常是配置错误或连接不当的指示。 * **ILA调试**:如果链路尝试训练但失败,请使用连接到PCIe IP核的状态信号(例如,`link_up`、`link_speed`、`link_width`)和AXI-Stream接口的ILA(第12.1节),以查看链路协商在哪个点失败,或者核是否生成了意外流量。 ### **13.2 内存映射和BAR配置错误** **问题**:仿真设备已检测到,但当主机操作系统或驱动程序尝试通过BAR访问其内存映射寄存器或缓冲区时,系统崩溃、冻结或报告错误。 #### **可能原因及解决方案**: 1. **BAR大小或类型不正确(IP核和固件)**: * **原因**:您在Vivado PCIe IP核(第7.2.2节)中配置的BAR大小或类型(32位/64位、内存/I/O、可预取/不可预取)和/或在`pcileech_tlps128_bar_controller.sv`中处理的值与捐赠设备实际提供的值不匹配。这可能导致主机分配不正确的地址空间或尝试不支持的访问。 * **解决方案**: * **交叉验证**:返回到您的Arbor/协议分析仪数据(第5节),重新验证每个BAR配置(大小、类型、可预取)。 * **一致性**:确保这些值在PCIe IP核定制中完全匹配,并且您的`bar_controller`逻辑正确处理每个BAR的大小(地址解码范围)和类型。 * **BRAM大小**:如果您的BAR映射到BRAM,请确认BRAM IP核的大小(第8.2.1节)与BAR大小完全匹配。 2. **固件中的地址解码错误**: * **原因**:您的`pcileech_tlps128_bar_controller.sv`(或自定义BAR逻辑)错误地解释了传入的PCIe地址,导致访问了不正确的内部寄存器或内存位置。 * **解决方案**: * **审查逻辑**:仔细审查`bar_controller`中的`case`语句和地址计算。 * **仿真**:在您的SystemVerilog测试平台中开发特定的测试用例,模拟主机对每个BAR中不同偏移量的读写访问。验证内部`bar_hit`信号是否正确,以及数据是否正确路由到/从正确的内部寄存器/BRAM。 * **ILA调试**:在`req_addr`、`req_write`、`req_read`、`req_data`、`rsp_data`以及`bar_controller`中与您的地址解码和寄存器访问相关的内部信号上放置ILA探头。实时观察地址如何解码以及正在读/写的数据。 3. **内部地址空间重叠**: * **原因**:虽然PCIe标准确保不同设备的BAR在主机的内存映射中不重叠,但在FPGA*内部*,您可能会意外地将不同的逻辑组件映射到单个BAR中的相同物理地址空间。 * **解决方案**: * **仔细映射**:在BAR中定义内部寄存器和内存块时,显式为每个寄存器和内存块分配唯一的、不重叠的偏移量。使用`localparam`来定义这些偏移量以防止错误。 * **设计审查**:需要对您的`bar_controller`进行彻底的设计审查,以确保每个地址范围都得到唯一处理。 4. **BRAM访问问题**: * **原因**:您的逻辑与BRAM IP核接口存在问题(例如,不正确的BRAM时钟、异步复位、错误的字节使能或不正确的写入使能逻辑)。 * **解决方案**: * **BRAM文档**:查阅Xilinx BRAM IP核文档,了解正确的实例化和接口信号。 * **ILA**:在BRAM接口信号(地址、写入使能、数据输入、数据输出)上放置ILA探头,以验证您的逻辑是否向BRAM发送了正确的控制信号。 ### **13.3 DMA性能和TLP错误** **问题**:设备已检测到并功能上看起来正常,但在大型DMA操作期间,数据传输速率缓慢,或者系统间歇性崩溃、挂起或报错。PCIe协议分析仪报告TLP格式错误或流控制问题。 #### **可能原因及解决方案**: 1. **TLP格式错误(报头/载荷)**: * **原因**:您的固件生成的TLP(特别是您的FPGA作为DMA主设备时发送的完成或出站内存写入)具有不正确的报头、长度、字节使能或载荷。主机系统的PCIe核或驱动程序将其检测为违规。 * **解决方案**: * **PCIe协议分析仪**:这是最好的工具(第12.2.1节)。捕获流量并仔细比较您生成的TLP与PCIe规范,更重要的是,与您*真实捐赠设备*的捕获进行比较。 * **TLP生成逻辑**:审查您的TLP组装代码(`pcileech_pcie_tlp_a7.sv`及相关模块)。确保所有字段(Fmt、Type、Requester ID、Tag、Completion ID、Length、Byte Enables、Address)都正确派生并打包到TLP结构中。 * **错误检查**:在固件中实现基本的错误检查(例如,检查是否存在意外的`req_valid`而没有`req_ready`,反之亦然)。 2. **流控制问题**: * **原因**:PCIe使用基于信用的流控制机制。如果您的固件(或PCIe IP核与其的交互)错误地管理信用,可能导致死锁、超时或丢包。症状包括PCIe链路“停滞”、超时或低吞吐量。 * **解决方案**: * **PCIe IP核配置**:确保Vivado PCIe IP核定制中的流控制设置适用于您预期的流量模式。默认设置通常是健壮的。 * **用户逻辑反压**:您的用户逻辑向PCIe IP核发送TLP(`m_axis_tx_*`接口)*必须*遵守来自IP核的`m_axis_tx_tready`信号。如果`tready`被去断言,您*必须*暂停发送数据。否则将导致核的缓冲区溢出。 * **ILA调试**:将ILA探头连接到PCIe IP核的流控制接口信号和您的用户逻辑,以观察`tvalid`/`tready`握手是否正常工作。 3. **DMA逻辑效率低下/缓冲问题**: * **原因**:FPGA内部的DMA引擎实现(读取/写入主机内存数据的部分)未优化,导致瓶颈。这可能涉及: * 缺少流水线。 * BRAM使用效率低下。 * 外部内存访问延迟导致的停滞。 * 突发大小过小。 * **解决方案**: * **流水线**:将长组合路径分解为更小、更连续的阶段,使用寄存器。这允许更高的时钟频率和更好的吞吐量。 * **缓冲**:使用FIFO(先进先出缓冲区)来解耦发送方和接收方逻辑,平滑数据流并防止停滞。 * **突发传输**:利用PCIe执行突发读/写的能力以提高效率。确保您的DMA逻辑以适当的突发大小请求和处理数据。 * **内存带宽**:确保您的BRAM或外部DDR内存接口能够足够快地提供/消耗数据,以满足您所需的DMA速率。 * **ILA**:监控您的DMA引擎的内部状态、读写指针和数据路径信号,以识别瓶颈。 4. **完成超时/不支持的请求**: * **原因**:主机发送请求(例如MRd、CfgRd),但您的FPGA设备未在允许的超时时间内响应完成TLP,或者它以错误状态(例如,带有Unsupported Request (UR) 或 Completer Abort (CA) 的完成)进行响应。 * **解决方案**: * **响应逻辑**:验证您的`bar_controller`(用于MRd)和`pcileech_pcie_cfg_a7.sv`(用于自定义配置空间的CfgRd)是否正确识别请求并生成适当的完成。 * **超时值**:审查您的捐赠设备预期的完成延迟。虽然PCIe定义了默认超时,但某些驱动程序可能对此敏感。 * **ILA/协议分析仪**:对于查明*为什么*未发送完成或完成格式错误至关重要。请求TLP是否甚至到达了您的用户逻辑?您的逻辑是否生成了响应?PCIe核是否成功发送了响应? --- ## **14. 仿真精度与优化** 实现真正令人信服的仿真意味着让您的基于FPGA的设备与捐赠设备难以区分,不仅在ID上,而且在行为上。这需要对时序、响应速度和微妙的操作细节进行细致的关注。 ### **14.1 精确定时仿真技术** 精确的时序在硬件中至关重要,特别是对于PCIe这样的高速接口。不匹配可能导致驱动程序超时、数据解释不正确或系统不稳定。 * **实现时序约束(XDC文件)**: * **目的**:时序约束是 Vivado 综合和实现工具的指令,告诉它们您的设计需要运行多快。它们定义了时钟周期、输入/输出延迟和路径延迟。 * **用法**:PCILeech-FPGA项目包含 XDC 文件(例如,`pcileech_squirrel_top.xdc`),它们定义了主时钟(例如,`create_clock -name sys_clk_p -period 8.0 [get_ports sys_clk_p]`)。 * **优化**:如果您的仿真需要非常特定的内部时序或对时间敏感的命令做出反应,您可能需要在自定义逻辑中添加进一步的约束(`set_max_delay`、`set_input_delay`、`set_output_delay`)到关键路径。 * **目标**:确保 Vivado 在实现后报告所有路径的 **正 WNS(最差负余量)**,表明设计满足其时序要求。 * **使用时钟域交叉(CDC)技术**: * **目的**:PCIe设计通常涉及多个时钟域(例如,125MHz PCIe用户时钟,自定义逻辑的单独时钟)。在这些域之间异步移动信号(没有适当的同步)可能导致**亚稳态**,从而导致不可靠的行为。 * **实现**:对于跨时钟域的信号,始终使用适当的CDC电路: * **双触发器同步器**:用于单比特控制信号。 * **异步FIFO(先进先出)**:用于多比特数据路径,提供时钟域之间的数据缓冲和流控制。 * **格雷码编码器/解码器**:用于跨域的计数器或地址,以确保每次只有一个比特发生变化。 * **Vivado 工具**:Vivado 包含 CDC 分析工具(例如,`report_cdc`),可以识别潜在的亚稳态问题。 * **使用时间精确模型仿真设备行为**: * **高级测试平台**:使用 SystemVerilog 测试平台,其中包含真实的定时延迟,甚至提供时间精确的 PCIe 总线功能模型(BFM)。 * **验证**:这使您可以观察您的仿真设备的内部状态以及外部 TLP 生成/响应时序在各种条件下如何表现,确保它们与您捕获的捐赠设备行为相匹配。 ### **14.2 对系统调用的动态响应** 真正精确的仿真不仅能呈现正确的ID;它还能智能且动态地响应主机系统的命令和查询,模仿真实、活动设备的行为。 * **实现设备控制的状态机**: * **目的**:设计健壮的 SystemVerilog 状态机来管理设备的操作模式、命令处理和数据流。 * **响应性**:确保状态机能够逻辑地、快速地响应传入命令(例如,写入 BAR 中的控制寄存器,特定的 TLP)。 * **优雅处理**:状态机应能够优雅地处理意外或无序的请求,可能返回错误 TLP 或仅仅忽略无效命令,而不是崩溃或冻结。 * **监控和响应主机命令(超越简单的读写)**: * **配置写入**:除了初始枚举之外,驱动程序通常会写入配置空间寄存器以启用功能、设置阈值或清除状态位。您的固件必须处理这些写入并相应地更新内部状态。 * **厂商特定命令**:如第9.2节所述,如果捐赠设备具有专有命令(通过自定义寄存器或厂商定义消息访问),您的固件必须解析这些命令并触发适当的仿真行为。 * **电源管理命令**:通过启用/禁用内部逻辑并确认状态更改来响应主机发起的电源状态转换(D0、D1、D3hot 等)。 * **中断确认**:如果主机驱动程序通过写入特定寄存器来确认中断,请确保您的固件能够检测到此并清除内部中断请求。 * **优化固件逻辑以提高响应性**: * **降低延迟**:关键数据路径和控制路径应优化,以最小化组合逻辑深度和流水线停顿。 * **并行性**:利用 FPGA 固有的并行性来同时执行多个操作,提高吞吐量和响应时间。 * **高效内存访问**:优化对内部 BRAM 或外部 DDR 内存的访问,以确保在需要时为 DMA 传输或寄存器读取提供数据。 * **硬件加速**:对于捐赠设备执行的复杂计算或数据操作,请考虑在 FPGA 上实现专用的硬件加速器,而不是尝试以缓慢、类似软件的方式执行它们。 --- ## **15. 固件开发最佳实践** 在定制固件开发中遵循最佳实践对于保持代码质量、促进协作(如果团队合作)、简化调试以及确保项目的长期可维护性和可靠性至关重要。这对于安全敏感的应用尤为如此。 ### **15.1 持续测试与文档** * **定期、增量测试**: * **单元测试**:使用专用测试平台隔离测试小型独立模块(例如,TLP解析器、寄存器块)。 * **集成测试**:验证不同模块是否协同工作。 * **系统测试**:烧录后,与主机系统执行端到端测试,确保整体功能。 * **尽早测试,经常测试**:在每次重大更改后,无论多小,都要测试固件,以便尽早发现问题,此时问题更容易调试。 * **自动化测试(高级)**: * 对于复杂项目,在主机端实现自动化测试脚本(例如,使用Python和硬件抽象层)以重复验证功能和性能。 * 在团队环境中,考虑与持续集成(CI)工具(例如,Jenkins、GitLab CI)集成,以自动化每次代码提交的构建、测试和静态分析。 * **维护全面的文档**: * **设计文档**:创建并更新描述固件架构的文档,包括: * **框图**:说明主要模块及其互连。 * **状态机图**:适用于所有有状态逻辑。 * **接口规范**:详细说明模块之间的输入/输出信号、时序和协议。 * **内存映射**:针对所有BAR,定义寄存器地址、位域及其功能。 * **代码注释**:在SystemVerilog代码中使用清晰、简洁的注释来解释复杂的逻辑、信号的目的以及任何不明显的设计选择。 * **更改日志/提交消息**:维护更改日志或使用详细的Git提交消息来跟踪所有修改、错误修复和功能添加,解释*为什么*进行更改。 * **用户指南**:对于您的定制固件,一个简单的用户指南,解释如何从主机端构建、烧录和与仿真设备交互,是无价的。 ### **15.2 管理固件版本** 正确的版本控制对于跟踪更改、有效协作和管理发布至关重要。 * **使用版本控制系统(VCS)**: * **Git**:强烈推荐。使用Git管理您的HDL源代码、约束文件和项目脚本。 * **组织仓库**:保持清晰的目录结构(例如,为`src`、`xdc`、`ip`、`scripts`、`doc`等设置单独的文件夹)。 * **分支**:使用功能分支开发新功能或进行重大更改。在彻底测试后合并回`main`或`develop`分支。 * **定期提交**:频繁提交,提交内容原子化,提交消息有意义。 * **标记发布和里程碑**: * **稳定版本**:使用Git标签(例如,`v1.0.0`、`v1.0.1_bugfix`)标记固件的稳定、经过测试的版本。这使得回溯或部署已知良好状态变得容易。 * **里程碑**:标记重要的开发里程碑(例如,“基本枚举工作正常”、“DMA读/写功能正常”)。 * **备份和恢复策略**: * **基于云的仓库**:将您的Git仓库托管在GitHub、GitLab或Bitbucket等平台上。这提供了异地备份并促进了协作。 * **本地备份**:即使有云仓库,也要定期对整个Vivado项目目录进行本地备份(由于生成的文件,它可能非常大)。 ### **15.3 安全注意事项** 开发用于PCIe设备仿真(特别是能够直接内存访问的设备)的定制固件具有重要的安全影响。这项技术本质上是一种“两用”能力,意味着它既可以用于合法目的(例如,硬件测试、安全研究),也可以用于恶意目的(例如,DMA攻击、安全绕过)。**理解并负责任地管理这些风险至关重要。** * **两用性质与道德影响**: * **道德黑客行为与恶意使用**:明确区分将这些知识用于授权安全测试(红队演练、渗透测试)和未经授权的非法活动。 * **负责任的披露**:如果您使用这些技术发现漏洞,请遵循负责任的披露准则。 * **法律和许可合规性**:了解并遵守所有与硬件逆向工程和设备修改相关的法律、法规和许可协议(例如,PCIe-SIG规范、Xilinx EULA)。 * **“武器化”**:认识到精确仿真受信任硬件的能力可以被武器化用于高级持久威胁(APTs)或复杂恶意软件。 * **理解攻击向量(攻击视角)**: * **内存窃取**:恶意仿真设备可以执行DMA读取,以访问任何物理内存地址,包括内核、用户进程中的敏感数据、加密密钥或网络缓冲区。 * **内存注入/修改**:恶意仿真设备可以执行DMA写入以任意修改内存,从而实现: * **权限提升**:修改内核数据结构(例如,进程令牌、SID)以获得管理员或系统权限。 * **代码注入**:将恶意代码注入正在运行的进程或内核,然后触发其执行。 * **安全软件绕过**:通过直接修改内存来禁用或颠覆端点检测和响应(EDR)、防病毒或防火墙软件。 * **模糊测试和崩溃**:发送格式错误或不符合规范的TLP/命令,以触发驱动程序漏洞,导致系统崩溃(蓝屏死机)或潜在的可利用内存损坏。 * **固件/BIOS操作**:在某些高级场景中,DMA设备可能能够与包含BIOS/UEFI的主机SPI闪存进行交互,可能用于持久性修改。 * **防御措施和缓解策略(防御视角)**: * **IOMMU/VT-d/AMD-Vi**:如第3.2节所述,这些技术旨在通过为外设提供内存保护来缓解DMA攻击。**对于合法测试,您会禁用它们,但在生产系统中,它们应始终启用。** 它们阻止外设未经授权的内存访问。 * **内核DMA保护(Windows)/ Thunderbolt安全(Linux)**:现代操作系统功能专门解决“冷启动”DMA攻击(攻击者在系统关闭或锁定时连接恶意设备)。在生产系统上保持这些功能启用。 * **安全启动**:虽然不是直接的DMA保护,但安全启动有助于确保只加载受信任的引导加载程序和内核模块,从而减少攻击者注入恶意内核组件以绕过DMA保护的机会。 * **物理安全**:最基本但最关键的防御。如果攻击者可以物理访问PCIe插槽或Thunderbolt端口,他们可以绕过许多软件保护。保护对关键系统的物理访问。 * **驱动程序强化**:驱动程序应以防御性方式编写,严格验证来自硬件的所有输入并在严格的内存边界内操作。 * **内存强化**:操作系统级的内存保护(例如KASLR、DEP、SMAP/SMEP)有助于减少内存损坏的影响,但直接DMA攻击会绕过这些保护。 * **监控和日志记录**:虽然在硬件层面很难,但异常的DMA活动或未知PCIe设备的枚举应在安全监控系统中触发警报。 * **固件安全编码实践**: * **输入验证**:如果您的固件接受任何输入(例如,通过UART调试接口,或由主机写入的内部寄存器),请严格验证它们,以防止缓冲区溢出、整数溢出或意外行为。 * **最小权限**:设计您的固件逻辑,使其仅执行其功能绝对必要的操作。避免授予不必要的功能。 * **状态管理**:实现健壮的状态机,以防止由于无效状态转换而导致的意外行为。 * **无硬编码秘密**:避免直接在固件中嵌入敏感信息(例如,加密密钥、硬编码凭据),如果它们可以轻易被提取。 * **篡改检测**:对于生产固件,考虑实现检测固件本身是否已被篡改或是否加载了未经授权配置的机制。 --- ## **16. 其他资源** 为了加深您对FPGA开发、PCIe和硬件安全等动态领域的理解并保持更新,请查阅以下资源: * **Xilinx (AMD) 文档**:您获取Vivado和Xilinx FPGA所有信息的主要来源。 * **主文档门户**:[https://docs.amd.com/](https://docs.amd.com/)(原Xilinx.com/support/documentation)。 * **Vivado 设计套件用户指南**: * **UG900 - 入门指南**:Vivado新用户必备。 * **UG901 - 逻辑综合**:深入了解综合。 * **UG904 - 实现**:关于放置和布线的详细指南。 * **UG912 - Tcl 命令参考指南**:对于脚本编写价值巨大。 * **UG939 - 调试**:ILA和其他调试功能的综合指南。 * **PCI Express IP 核用户指南**:理解Xilinx PCIe IP至关重要(例如,**PG054 for 7 Series Integrated Block for PCI Express**)。在文档门户上搜索“PCI Express”。这详细介绍了核的配置、接口和限制。 * **PCI-SIG 规范**:PCIe 标准的权威来源。 * **PCI Express Base Specification**:基础文档。虽然不公开免费,但基于它的摘要和教育材料广泛可用。您通常可以在其网站上找到信息:[https://pcisig.com/specifications](https://pcisig.com/specifications)(注意:完整规范通常需要PCI-SIG会员资格)。 * **FPGA 教程和学习平台**: * **FPGA4Fun**:[http://www.fpga4fun.com/](http://www.fpga4fun.com/) - 一个经典网站,提供许多实用的FPGA项目和教程。 * **Verilog/VHDL 教程**: * **ASIC World Verilog 教程**:[https://www.asic-world.com/verilog/index.html](https://www.asic-world.com/verilog/index.html) - 很好的Verilog基础参考。 * **VHDLwhiz**:[https://www.vhdlwhiz.com/](https://www.vhdlwhiz.com/) - VHDL 参考和教程。 * **Stack Overflow (FPGA/Verilog/PCIe 标签)**:[https://stackoverflow.com/questions/tagged/fpga](https://stackoverflow.com/questions/tagged/fpga) - 社区驱动的针对特定技术问题的问答。 * **PCIe 协议分析工具**: * **Teledyne LeCroy Protocol Analyzers**:[https://teledynelecroy.com/protocolanalyzer/](https://teledynelecroy.com/protocolanalyzer/) - 探索他们的高性能PCIe分析仪和软件系列。 * **Telescan PE Software**:[https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software](https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software) - 一款免费软件工具,提供一些PCIe分析功能(需要注册)。 * **PCILeech 社区和资源**: * `ufrisk/pcileech` GitHub 仓库是核心。积极关注其更新和问题。 * 寻找致力于PCILeech或类似开源DMA项目的社区论坛或Discord服务器。 * **硬件安全与逆向工程**: * 关于硬件黑客、逆向工程和低级系统利用的书籍。 * Black Hat、DEF CON、Recon 和 Troopers 等会议通常会举办关于 PCIe 和 DMA 攻击的讲座。 * 专注于硬件的安全研究人员的博客和研究论文。 --- ## **17. 联系方式** 如果您需要帮助、有疑问或希望就本指南、固件开发或硬件安全相关主题进行合作,请随时联系。我乐意提供指导、解决复杂问题或详细讨论想法。 ### **Discord**: * **用户**:[**VCPU**](https://discord.com/users/196741541094621184) * **服务器邀请链接**:[**加入硬件黑客与固件开发Discord**](https://discord.gg/dS2gDUDQmV) --- ## **18. 支持与贡献** 您的支持有助于维护和改进本指南及相关项目。创建和更新全面的技术文档以及开源硬件项目需要大量时间和精力。 ### **捐赠** 如果您觉得本指南有帮助并希望支持正在进行的工作,请考虑捐赠。每一笔捐款,无论大小,都有助于我们继续通过进一步的研究、开发和文档工作来创建、分享和支持社区。 * **加密货币捐赠(LTC - 莱特币)**: * **地址**:`MPMyQD5zgy2b2CpDn1C1KZ31KmHpT7AwRi` **特别奖励**:如果您捐赠,请随时在Discord上(VCPU)与我联系,以获得个人感谢,并可能获得额外资源、新内容的早期访问或项目上的个性化帮助。 **注意**:如果您需要我审查您实现的特定部分、解决问题或提供详细的代码反馈,请在您的代码中用`//VCPU-REVIEW//`注释标记相关部分,并提供您遇到的问题或疑问的详细说明。这有助于我集中精力并提供最有效的支持。 愿上帝保佑您的灵魂。 --- **指南结束** ================================================ FILE: CN/核对表.md ================================================ # 固件修改清单 使用此清单来指导您的固件创建过程。 --- ## **1. 收集捐赠设备信息** 从捐赠的PCIe设备收集以下信息: - [ ] **设备ID** (`0xXXXX`) - [ ] **供应商ID** (`0xYYYY`) - [ ] **子系统ID** (`0xZZZZ`) - [ ] **子系统供应商ID** (`0xWWWW`) - [ ] **修订ID** (`0xRR`) - [ ] **类代码** (`0xCCCCCC`) - [ ] **基地址寄存器(BARs)配置**: - [ ] **BAR0**至**BAR5**的大小、类型(内存或I/O)、可预取状态 - [ ] **功能**: - [ ] 电源管理设置 - [ ] MSI/MSI-X设置 - [ ] **设备序列号(DSN)** (`0xXXXXXXXXYYYYYYYY`) --- ## **2. 修改固件配置文件** ### **2.1. 打开固件配置文件** - [ ] **要编辑的文件**:`pcileech_pcie_cfg_a7.sv` - [ ] **位置**:`pcileech-fpga/pcileech-wifi-main/src/pcileech_pcie_cfg_a7.sv` ### **2.2. 更新设备和供应商ID** - [ ] **修改** `cfg_deviceid`: ```verilog cfg_deviceid <= 16'hXXXX; // 将XXXX替换为捐赠设备的设备ID ``` - [ ] **修改** `cfg_vendorid`: ```verilog cfg_vendorid <= 16'hYYYY; // 将YYYY替换为捐赠设备的供应商ID ``` ### **2.3. 更新子系统ID和修订ID** - [ ] **修改** `cfg_subsysid`: ```verilog cfg_subsysid <= 16'hZZZZ; // 将ZZZZ替换为捐赠设备的子系统ID ``` - [ ] **修改** `cfg_subsysvendorid`: ```verilog cfg_subsysvendorid <= 16'hWWWW; // 将WWWW替换为捐赠设备的子系统供应商ID ``` - [ ] **修改** `cfg_revisionid`: ```verilog cfg_revisionid <= 8'hRR; // 将RR替换为捐赠设备的修订ID ``` ### **2.4. 更新类代码** - [ ] **修改** `cfg_classcode`: ```verilog cfg_classcode <= 24'hCCCCCC; // 将CCCCCC替换为捐赠设备的类代码 ``` ### **2.5. 插入设备序列号(DSN)** - [ ] **修改** `cfg_dsn`: ```verilog cfg_dsn <= 64'hXXXXXXXXYYYYYYYY; // 替换为捐赠设备的DSN ``` --- ## **3. 定制Vivado项目** ### **3.1. 生成Vivado项目文件** - [ ] **打开Vivado**,并在Tcl控制台中运行相应的Tcl脚本: ```tcl cd source vivado_generate_project_.tcl -notrace ``` - 将``替换为您的项目路径。 - 将``替换为您的FPGA板标识符(例如,`squirrel`)。 ### **3.2. 打开生成的项目** - [ ] **文件**:在Vivado中打开生成的`.xpr`项目文件。 --- ## **4. 修改PCIe IP核** ### **4.1. 打开PCIe IP核配置** - [ ] **要编辑的文件**:`pcie_7x_0.xci` - [ ] **操作**:右键点击并选择**定制IP**。 ### **4.2. 设置设备标识符** - [ ] **设备ID**:设置为捐赠设备的设备ID。 - [ ] **供应商ID**:设置为捐赠设备的供应商ID。 - [ ] **子系统ID**:设置为捐赠设备的子系统ID。 - [ ] **子系统供应商ID**:设置为捐赠设备的子系统供应商ID。 - [ ] **修订ID**:设置为捐赠设备的修订ID。 - [ ] **类代码**:设置为捐赠设备的类代码。 ### **4.3. 配置BARs** 对于每个BAR(BAR0至BAR5): - [ ] **启用/禁用**:与捐赠设备匹配。 - [ ] **类型**:内存(32位或64位)或I/O。 - [ ] **大小**:设置为捐赠设备的BAR大小。 - [ ] **可预取**:与捐赠设备的设置匹配。 ### **4.4. 匹配PCIe链路参数** - [ ] **最大链路速度**:设置为匹配捐赠设备(例如,**Gen2**、**Gen3**)。 - [ ] **链路宽度**:设置为匹配捐赠设备(例如,**x1**、**x4**)。 ### **4.5. 配置功能** - [ ] **启用电源管理**(如果捐赠设备支持)。 - [ ] **启用MSI/MSI-X**(如果捐赠设备支持)。 ### **4.6. 应用更改并锁定IP核** - [ ] **应用**:点击**OK**保存IP核设置。 - [ ] **锁定IP核**:在Tcl控制台中运行: ```tcl set_property -name {IP_LOCKED} -value true -objects [get_ips pcie_7x_0] ``` --- ## **5. 为高级功能调整固件** ### **5.1. 更新能力指针** - [ ] **要编辑的文件**:`pcileech_pcie_cfg_a7.sv` - [ ] **修改** `cfg_cap_pointer`: ```verilog cfg_cap_pointer <= 8'hXX; // 将XX替换为捐赠设备的能力指针 ``` ### **5.2. 调整最大有效载荷和读取请求大小** - [ ] **在PCIe IP核中**:将**最大有效载荷大小**和**最大读取请求大小**设置为匹配捐赠设备。 - [ ] **在固件中(`pcileech_pcie_cfg_a7.sv`)**: ```verilog max_payload_size_supported <= 3'bYYY; // 二进制值,对应于捐赠设备的最大有效载荷大小 ``` - **映射关系**: | 有效载荷大小(字节) | 二进制值 | |----------------------|------------| | 128 | `3'b000` | | 256 | `3'b001` | | 512 | `3'b010` | | 1024 | `3'b011` | | 2048 | `3'b100` | | 4096 | `3'b101` | ### **5.3. 实现电源管理逻辑** - [ ] **要编辑的文件**:`pcileech_pcie_cfg_a7.sv` - [ ] **添加逻辑**以处理电源状态转换(如果适用)。 ### **5.4. 实现MSI/MSI-X中断** - [ ] **在PCIe IP核中**:启用MSI或MSI-X功能,并设置支持的向量数量。 - [ ] **在固件中(`pcileech_pcie_tlp_a7.sv`)**: - [ ] **添加中断逻辑**以处理MSI/MSI-X中断。 --- ## **6. 调整固件中的BAR处理** ### **6.1. 打开BAR控制器文件** - [ ] **要编辑的文件**:`pcileech_tlps128_bar_controller.sv` - [ ] **位置**:`pcileech-fpga/pcileech-wifi-main/src/pcileech_tlps128_bar_controller.sv` ### **6.2. 更新BAR地址解码** - [ ] **修改**地址解码逻辑,以匹配捐赠设备的BAR大小和地址。 ### **6.3. 实现BAR访问逻辑** 对于每个启用的BAR: - [ ] **实现读/写处理程序**,对应于BAR的用途。 --- ## **7. 实现TLP处理** ### **7.1. 打开TLP处理文件** - [ ] **要编辑的文件**:`pcileech_pcie_tlp_a7.sv` ### **7.2. 修改TLP处理逻辑** - [ ] **实现**处理捐赠设备所需的特定TLP类型的逻辑: - [ ] 内存读取请求 - [ ] 内存写入请求 - [ ] 配置读取/写入请求 - [ ] 供应商定义的消息 ### **7.3. 确保TLP合规** - [ ] **验证**TLP按照PCIe规范正确格式化。 --- ## **8. 构建并烧录固件** ### **8.1. 运行综合和实现** 在Vivado中: - [ ] **运行综合** - [ ] **运行实现** - [ ] **生成比特流** ### **8.2. 编程FPGA** - [ ] **通过JTAG连接**您的FPGA设备。 - [ ] **打开硬件管理器**。 - [ ] **使用生成的比特流编程设备**。 --- ## **9. 测试与验证** ### **9.1. 验证设备枚举** - [ ] **检查**FPGA是否在主机系统上显示为捐赠设备。 ### **9.2. 安装必要的驱动程序** - [ ] **使用**捐赠设备的驱动程序(如果需要)。 ### **9.3. 执行功能测试** - [ ] **测试**捐赠设备预期的所有功能。 ### **9.4. 监控错误** - [ ] **检查**系统日志中与设备相关的任何错误或警告。 --- ## **10. 根据需要调试和优化** ### **10.1. 使用集成逻辑分析器(ILA)** - [ ] **插入**ILA核以监控内部信号(如果必要)。 ### **10.2. 分析PCIe流量** - [ ] **使用**PCIe协议分析仪,调试通信问题。 ### **10.3. 精炼固件** - [ ] **迭代**您的固件代码,修复错误并提高性能。 ================================================ FILE: CN/版本 4.md ================================================ # **第一部分:基础概念** ## **1. 引言** ### **1.1 本指南的目的** 本指南概述了一条详细的路线图,用于在基于 FPGA 的设备上创建自定义的直接内存访问 (DMA) 固件,最终目标是精确地仿真 PCIe 硬件。这种仿真可用于以下广泛应用场景: - **硬件开发与测试** - 使用基于 FPGA 的仿真来复制在开发过程中所需的各类硬件设备。 - 在无需昂贵或受限于特定捐赠硬件的情况下,进行系统级测试。 - **系统调试与诊断** - 在可控环境中重现复杂的硬件行为,以便查找驱动程序相关的 bug 或问题。 - 在交易层 (TLP) 或内存映射 I/O 级别进行追踪分析。 - **安全与恶意软件研究** - 调查 PCIe 低级漏洞或与硬件直接交互的高级恶意软件。 - 当硬件签名部分或全部被伪造时,观察特定设备驱动程序的行为。 - **硬件仿真与旧版支持** - 用 FPGA 解决方案替代老化的硬件,通过仿真捐赠设备的 PCIe ID、BAR 布局和中断。 - 在新系统上通过仿真较旧或停产的 PCIe 设备来保持传统工作流程。 通过阅读本指南,你将学会如何: 1. **收集** 实体“捐赠” PCIe 卡的必要设备信息。 2. **定制** FPGA 固件,使其呈现相同的设备/厂商 ID、BAR 布局和功能。 3. **构建与配置** 开发环境(如 Xilinx Vivado、Visual Studio Code 等)。 4. **理解** PCIe 与 DMA 的基本原理,这对于可靠的设备仿真至关重要。 > **为何这很重要** > 适当的硬件仿真可以节省工作量、降低成本,并允许快速迭代。基于 FPGA 的卡可以随时重新编程,从而让你比固定硬件更容易地适应多种设备或固件变体。 --- ### **1.2 目标受众** 本资源适用于广泛的专业人士和爱好者: - **固件开发人员** 对操控低级系统交互、驱动程序设计或高级硬件/固件栈调试感兴趣。 - **硬件与验证工程师** 寻求一种可控方式来测试具有多种设备配置和条件的系统组件——而无需每次都更换 PCIe 卡。 - **安全研究人员** 专注于分析 DMA 引入的威胁向量,探索 PCIe 交互中的潜在漏洞,或对恶意代码进行安全沙箱仿真。 - **FPGA 爱好者与创客** 渴望通过构建自定义 PCIe 核、学习高级硬件描述语言及探索实际设备枚举来扩展他们的 FPGA 知识。 --- ### **1.3 如何使用本指南** 本指南分为三个部分,每个部分都在前一部分的基础上进一步深入: 1. **第一部分:基础概念** - 涵盖先决知识、环境设置、提取捐赠设备数据以及初步固件调整。 2. **第二部分:中级概念与实现** - 深入讨论固件定制、TLP 级别的操作、调试策略,以及如何细化仿真设备的行为以匹配或超越捐赠设备的功能。 3. **第三部分:高级技术与优化** - 探讨深入的调试工具、性能调优和最佳实践,以确保你的基于 FPGA 的 DMA 解决方案具有长期可维护性。 > **建议**:在进入下一部分之前,请彻底完成第一部分。跳过或部分实施这些基础步骤可能会导致后续阶段中的混乱或配置错误。 --- ## **2. 关键定义** 精确定义术语对于成功进行基于 FPGA 的 PCIe 仿真至关重要。下列列表详细解释了各相关术语: 1. **DMA (直接内存访问)** - **定义**:无需 CPU 干预,由硬件直接在设备与系统内存之间传输数据。 - **相关性**:仿真设备高度依赖 DMA 以达到高吞吐量。确保正确配置 DMA 对于功能正常的 FPGA 设计至关重要。 2. **TLP (交易层数据包)** - **定义**:PCIe 中的基本通信单元,封装了头部信息和数据有效载荷。 - **相关性**:理解 TLP 结构对于修改或分析 PCIe 交易层数据十分关键。 3. **BAR (基地址寄存器)** - **定义**:寄存器,用于指定设备资源在系统地址空间中显示的地址范围(内存或 I/O)。 - **相关性**:准确复制捐赠设备的 BAR 布局是确保驱动程序正确加载和内存映射 I/O 处理的关键。 4. **FPGA (现场可编程门阵列)** - **定义**:一种可重构芯片,其内部电路可以通过 HDL 重新设计,以实现定制硬件逻辑。 - **相关性**:FPGA 使你可以快速迭代 PCIe 设备设计,通过最小的硬件更改便可切换仿真设备。 5. **MSI/MSI-X (消息信号中断)** - **定义**:符合 PCIe 标准的中断方法,允许设备通过带内消息而非专用线路触发 CPU 中断。 - **相关性**:复制捐赠中断行为(特别是支持的 MSI 向量数量)对于预期使用特定中断机制的驱动程序至关重要。 6. **设备序列号 (DSN)** - **定义**:某些 PCIe 设备用于许可、认证或高级驱动程序校验的 64 位唯一标识符。 - **相关性**:若捐赠设备依赖 DSN,一些驱动程序可能会拒绝加载或运行,除非 DSN 匹配预期的硬件。 7. **PCIe 配置空间** - **定义**:定义的区域(PCI 为 256 字节,PCIe 扩展为 4 KB),详细列出了设备 ID、厂商 ID、功能和操作参数。 - **相关性**:确保 FPGA 设备的配置空间与捐赠设备完全一致(或包含正确的子集)对于让主机将其视为真实设备至关重要。 8. **捐赠设备** - **定义**:你从中提取数据(如 ID、类代码等)以进行仿真的实际 PCIe 卡。 - **相关性**:你复制的数据越准确,你的 FPGA 在枚举和功能上就越能接近真实硬件。 --- ## **3. 设备兼容性** ### **3.1 支持的基于 FPGA 的硬件** 1. **Squirrel (35T)** - 基于 Artix-7 的性价比较高的 FPGA 板,支持基本的 DMA 操作。推荐给刚接触基于 FPGA 的 PCIe 开发的用户。 2. **Enigma-X1 (75T)** - 提供比 35T 更多的逻辑资源(LUTs、块 RAM),适用于中等复杂度任务或扩展调试/追踪功能。 3. **ZDMA (100T)** - 针对高性能应用,具备大量 FPGA 资源,适合密集数据传输或多个并发 DMA 通道。 4. **Kintex-7** - 一个更高级的 FPGA 系列,具备先进的 PCIe IP 核,通常用于要求高或大规模仿真任务。 > **提示**:始终检查你的 FPGA 卡的具体通道配置(x1、x4、x8)和速度等级(Gen1、Gen2 等),确保它满足或超过主板支持的要求。 --- ### **3.2 PCIe 硬件考虑因素** - **IOMMU / VT-d** - *建议*:为了避免 DMA 区域受限,建议暂时禁用,尤其是在需要完全内存访问以进行充分测试时。 - **内核 DMA 保护** - *Windows VBS / Secure Boot*:在某些情况下,这些功能会截获或限制直接的 PCIe 内存映射。 - *Linux IOMMU 或 AppArmor/SELinux 规则*:请根据需要调整,以确保 FPGA 能够访问仿真所需的内存区域。 - **PCIe 插槽要求** - 选择物理 PCIe 插槽时,确保有足够的通道,并确认 BIOS 已正确分配通道。 - 如果发现性能问题或部分枚举,请确认系统没有将较大插槽强制为 x1 操作。 --- ### **3.3 系统要求** 1. **硬件** - **CPU**:至少需要四核 Intel 或 AMD,以便顺畅运行 Vivado 综合和管理操作系统开销。 - **内存**:建议 16 GB 或更多,以便在多小时的综合运行中获得舒适体验。 - **存储**:建议 100 GB SSD 以加快项目构建;机械硬盘可能会大幅降低构建速度。 - **操作系统**:支持 Windows 10/11(64 位)或主流 Linux 发行版(例如 Ubuntu LTS、RHEL/CentOS),用于运行 Xilinx Vivado。 2. **外设设备** - **JTAG 编程器**: - 如 Xilinx Platform Cable USB II、Digilent HS3 或类似设备,用于将生成的比特流下载到 FPGA 上,或在实时调试固件时使用。 - **专用机器**: - 强烈建议使用专用测试机(或精心配置的双启动/虚拟机)以便在修改 BIOS 设置(如 VT-d)或需要一个无其他 PCIe 设备干扰的环境时使用。 --- ## **4. 需求** ### **4.1 硬件** 1. **捐赠 PCIe 设备** - 目的:你需要提取设备的厂商/设备 ID、子系统 ID、类代码、BAR 大小和功能。 - 示例:旧款网络接口卡(NIC)、基本存储控制器,或其他你希望复制或扩展的专用 PCIe 设备。 2. **DMA FPGA 卡** - 目的:运行 FPGA 逻辑、实现 PCIe 接口的实际硬件平台。 - 示例:Squirrel 35T、Enigma-X1 或 ZDMA 100T 板。 3. **JTAG 编程器** - 用于连接 FPGA 板上的 JTAG 引脚,便于使用 Vivado 加载综合生成的比特流或实时调试固件。 --- ### **4.2 软件** 1. **Xilinx Vivado 设计套件** - 用于创建、综合和实现 FPGA 设计。 - 请从 [Xilinx](https://www.xilinx.com/support/download.html) 下载,确保选择与你的板卡 IP 要求相符的版本。 2. **Visual Studio Code** - 一个灵活的跨平台编辑器,支持 Verilog/SystemVerilog,并有额外插件。 - 帮助保持一致的代码风格,追踪变更,并通过版本控制(如 Git)简化协作。 3. **PCILeech-FPGA** - GitHub 仓库:[PCILeech-FPGA](https://github.com/ufrisk/pcileech-fpga)。 - 提供针对各 FPGA 板的基本 DMA 设计,你可以在此基础上进行定制,以复制捐赠设备的 PCIe 配置。 4. **Arbor(PCIe 设备扫描工具)** - 一个用户友好的 GUI 工具,可对已连接的 PCIe 设备进行详细分析。 - 替代方案:Telescan PE 用于流量捕获,或者在 Linux 中使用命令行工具 `lspci -vvv` 进行检查。 --- ### **4.3 环境设置** 1. **安装 Vivado** - 按照 Xilinx 官方安装程序进行安装,选择相应的 FPGA 系列(Artix-7、Kintex-7 等)。 - 可能需要注册 Xilinx 账户以下载设计套件或获取更新。 2. **安装 Visual Studio Code** - 从 [Visual Studio Code](https://code.visualstudio.com/) 下载。 - 安装推荐插件:*Verilog-HDL/SystemVerilog* 和 *Git* 集成插件(若你计划使用版本控制)。 3. **克隆 PCILeech-FPGA 仓库** ```bash cd ~/Projects/ git clone https://github.com/ufrisk/pcileech-fpga.git cd pcileech-fpga ``` - 确保你已安装并配置 Git。 4. **隔离开发环境** - 建议使用专用测试机(或经过精心配置的双启动/虚拟机),以减少风险。 - 这种方式允许你更自由地禁用内核 DMA 保护、IOMMU 或安全启动,而不会影响主要生产系统。 --- ## **5. 收集捐赠设备信息** 要有效地仿真设备,必须复制其 PCIe 配置空间。这意味着需要捕获从设备/厂商 ID 到高级功能的所有信息。 ### **5.1 使用 Arbor 进行 PCIe 设备扫描** #### **5.1.1 安装并启动 Arbor** 1. **获取 Arbor** - 在 Arbor 官方网站注册并下载。 - 以管理员权限安装。 2. **启动 Arbor** - 如果 Windows 的 UAC 提示,请确认允许该应用以管理员权限运行。 - 你应看到一个列出所有 PCI/PCIe 设备的界面。 #### **5.1.2 扫描设备** 1. **本地系统标签** - 导航至 Arbor 的“Local System”或“Scan”区域。 2. **点击“Scan”** - Arbor 将枚举所有 PCIe 总线上的设备。 3. **识别捐赠设备** - 根据品牌名称或厂商 ID 与已知的捐赠硬件相匹配。如果不易识别,请参照硬件文档中的已知 ID 进行比对。 #### **5.1.3 提取关键属性** 从 Arbor 的详细视图中收集以下信息: - **厂商 ID / 设备 ID**:例如,0x8086 / 0x10D3(Intel NIC)。 - **子系统厂商 ID / 子系统 ID**:例如,0x8086 / 0xA02F。 - **修订版本 ID**:例如,0x01。 - **类代码**:例如,0x020000(用于以太网控制器)。 - **BARs (基地址寄存器)**: - 对于每个 BAR,注意其是否启用、内存大小(256 MB、64 KB 等)以及是否支持预取或是 32 位/64 位。 - **功能**: - MSI 或 MSI-X 详情(支持的中断向量数量)。 - 扩展配置或高级电源管理功能。 - **设备序列号 (DSN)**(如有): - 某些设备具有唯一 DSN 字段,特别是用于许可或特殊驱动检查时。 > **组织提示**: > 使用电子表格或结构化文档记录这些数值,确保你不会忽略高级功能或扩展功能等细节。 --- ## **6. 初步固件定制** 获取捐赠设备的 PCIe 属性后,开始定制 FPGA 固件以匹配这些设置。 ### **6.1 修改 PCIe 配置空间** 你的 FPGA 设计中可能包含一个顶层文件,用于设置 PCIe 配置寄存器。例如,在 `pcileech-fpga` 仓库中,查找类似 `pcileech_pcie_cfg_a7.sv` 或 `pcie_7x_0_core_top.v` 的文件。 1. **在 VS Code 中打开文件** - 搜索定义 `cfg_deviceid`、`cfg_vendorid`、`cfg_subsysid` 等的代码行。 2. **赋予正确的 ID** ```verilog cfg_deviceid <= 16'h10D3; // 示例设备 ID cfg_vendorid <= 16'h8086; // 示例厂商 ID cfg_subsysid <= 16'h1234; cfg_subsysvendorid <= 16'h5678; cfg_revisionid <= 8'h01; cfg_classcode <= 24'h020000; // 例如以太网控制器 ``` - 将上述示例替换为从 Arbor(或捐赠设备数据手册)中获得的确切值。 3. **如有需要,插入 DSN** ```verilog cfg_dsn <= 64'h0011223344556677; ``` - 如果捐赠设备不依赖 DSN,则可省略或置为 0。 4. **保存并检查** - 任一字段的单个数字错误都可能导致操作系统错误识别或拒绝该设备。请仔细核对每一行。 --- ### **6.2 考虑 BAR 配置** 虽然有些 PCIe IP 核会在相同的 SystemVerilog 文件中存储 BAR 设置,但也有些依赖于 Vivado 的 IP 定制 GUI: - **检查捐赠设备使用了多少个 BAR**(0 到 6 个)。 - **设置每个 BAR**(例如,内存类型、大小、是否支持预取、是 64 位还是 32 位)。 - 如果捐赠设备具有较大 BAR 区域(例如 256 MB 或更大),请确保你的 FPGA 板卡在 IP 核设置中可以容纳。 --- ## **7. Vivado 工程设置与定制** ### **7.1 生成 Vivado 工程文件** 为便于组织所有设计文件,许多仓库都包含 Tcl 脚本: 1. **启动 Vivado** - 确保你使用的 Vivado 版本与 FPGA 系列(Artix-7、Kintex-7 等)匹配。 2. **打开 Tcl 控制台** - 在 Vivado 顶部菜单中选择 **Window > Tcl Console**。 3. **进入工程目录** ```tcl cd C:/path/to/pcileech-fpga/pcileech-wifi-main/ pwd ``` - 使用 `pwd` 命令确认控制台已进入正确的文件夹。 4. **运行生成脚本** ```tcl source vivado_generate_project_squirrel.tcl -notrace ``` - 如果使用 Enigma-X1 或 ZDMA,请运行相应的脚本(例如 `vivado_generate_project_enigma_x1.tcl`)。 5. **打开生成的工程** - 通过 **File > Open Project**,定位并选择 `.xpr` 文件(例如 `pcileech_squirrel_top.xpr`)。 - 检查 **Project Manager** 窗口,确保所有源文件已正确导入。 --- ### **7.2 定制 PCIe IP 核** 在 Vivado 中,你可能会找到一个 PCIe IP 核(例如 `pcie_7x_0.xci`),位于 **Sources** 下: 1. **右键点击 -> Customize IP** - 更新厂商/设备 ID、修订版本和子系统字段。 - 按照捐赠设备的 BAR 配置(大小、内存类型等)进行匹配。 2. **生成/更新 IP** - 点击 **OK** 或 **Generate** 以重建 IP 核。 - 如果 IP 版本发生变化,Vivado 可能会提示升级或确认依赖项。 3. **锁定 IP 核** ```tcl set_property -name {IP_LOCKED} -value true -objects [get_ips pcie_7x_0] ``` - 这可以防止将来脚本意外覆盖你的手动更改。 --- ## **附加最佳实践** 1. **版本控制** - *强烈推荐* - 经常提交你的修改(使用 Git 或其他版本控制系统)。 - 对重大更改进行打标签或分支,以便在出现问题时能快速回退。 2. **文档记录** - 保留笔记、电子表格或 Wiki,总结捐赠设备的详细信息、特殊偏移或功能缺陷。 - 记录定制 FPGA 固件的每一步操作。 3. **在主机上测试** - 生成比特流后,将其烧录到 FPGA,然后检查: - **Windows**:使用设备管理器或 `devcon.exe` 检查设备是否以正确的 ID 枚举。 - **Linux**:使用 `lspci -vvv` 检查设备是否正确显示,包括 BAR、类代码、子系统等信息。 4. **安全考虑** - 禁用 VT-d 或安全启动等功能可能会使系统面临安全风险。建议使用专用测试平台或将环境隔离,以确保操作安全。 5. **接下来的内容** - 在 **第二部分** 中,你将学到如何基于这些基础知识进一步进行 TLP 操作、部分重配置策略、固件调试以及任何高级 ID 伪装或握手仿真。 --- # **第二部分:中级概念与实现** --- ## **8. 高级固件定制** 为了精确仿真捐赠设备,你必须扩展基础配置,使高级 PCIe 参数、BAR 设置以及电源管理与中断机制完全与捐赠设备一致。这确保你的基于 FPGA 的仿真设备能与主机像真实硬件一样交互。 --- ### **8.1 配置 PCIe 参数以实现仿真** 精确的 PCIe 仿真要求设备的链路特性、功能指针以及数据传输参数(有效载荷和读请求大小)与捐赠设备一致。 #### **8.1.1 匹配 PCIe 链路速度和宽度** **目的:** PCIe 链路速度(例如,Gen1 为 2.5 GT/s,Gen2 为 5.0 GT/s,Gen3 为 8.0 GT/s)和链路宽度(例如,x1、x4、x8)直接影响性能与兼容性。必须复制捐赠设备的参数,确保主机系统和驱动程序能够无缝识别和操作仿真设备。 **步骤:** 1. **启动 Vivado 并打开工程** - 打开你的 Vivado 工程(例如 `pcileech_squirrel_top.xpr`),确认所有源文件均已导入,工程层次结构完整。 2. **进入 PCIe IP 核设置** - 在 **Sources** 面板中找到 PCIe IP 核(通常命名为 `pcie_7x_0.xci`)。 - 右键点击该文件,选择 **Customize IP** 以打开配置 GUI。 3. **设置最大链路速度** - 导航至 **Link Parameters** 选项卡。 - 找到“Maximum Link Speed”选项,并选择与捐赠设备匹配的速度(例如,对于 Gen2 选择 5.0 GT/s)。 - *注意:* 验证 FPGA 板和物理插槽是否均支持所选速度。 4. **配置链路宽度** - 在同一选项卡中,找到“Link Width”。 - 选择适当的宽度(例如,x4)以匹配捐赠设备。 - *注意:* 常见选项包括 1、2、4、8 或 16 条通道。 5. **应用并重新生成** - 点击 **OK** 保存更改。Vivado 可能会提示你重新生成 IP 核,允许该过程完成。 - 最后,在 **Messages** 窗口检查任何警告或错误信息。 --- #### **8.1.2 设置功能指针** **目的:** PCIe 配置空间中的功能指针引导主机定位扩展功能(如 MSI/MSI‑X、电源管理等)。匹配这些指针可确保主机按照与捐赠设备相同的方式访问这些功能。 **步骤:** 1. **打开固件配置文件** - 在 Visual Studio Code 中,打开位于 `pcileech-fpga/pcileech-wifi-main/src/` 下的文件(例如 `pcileech_pcie_cfg_a7.sv`)。 2. **查找并更新功能指针赋值** - 找到 `cfg_cap_pointer` 的赋值语句,例如: ```verilog cfg_cap_pointer <= 8'hXX; // 当前默认值 ``` - 将 `XX` 替换为正确的捐赠设备偏移(例如,如果捐赠设备的功能指针在 0x60 处,则写为 `8'h60`): ```verilog cfg_cap_pointer <= 8'h60; // 设置为捐赠设备在 0x60 偏移处的功能指针 ``` - *验证:* 确保功能结构按照 PCIe 要求对齐到 4 字节边界。 3. **保存文件并添加注释说明更改** - 保存文件(Ctrl+S),并在代码中添加内联注释以备将来参考。 --- #### **8.1.3 调整最大有效载荷和读请求大小** **目的:** PCIe 设备在交易中协商每个传输的数据量。“最大有效载荷大小”(MPS)和“最大读请求大小”(MRRS)必须设置为与捐赠设备一致,以确保驱动程序兼容性和最佳数据吞吐量。 **步骤:** 1. **在 PCIe IP 核中配置** - 在 IP 定制 GUI 中(位于 PCIe IP 核设置中),导航至 **Device Capabilities** 或 **Capabilities** 选项卡。 - 设置 **Maximum Payload Size Supported**(例如 256 字节)和 **Maximum Read Request Size Supported**(例如 512 字节),使其与捐赠设备一致。 2. **更新固件常量** - 在 Visual Studio Code 中打开 `pcileech_pcie_cfg_a7.sv`。 - 查找定义有效载荷和读请求大小的参数,例如: ```verilog max_payload_size_supported <= 3'bZZZ; // 当前值 max_read_request_size_supported <= 3'bWWW; // 当前值 ``` - 替换为正确的二进制编码: - **示例映射:** - 128 字节: `3'b000` - 256 字节: `3'b001` - 512 字节: `3'b010` - 1024 字节: `3'b011` - 2048 字节: `3'b100` - 4096 字节: `3'b101` - 例如,如果捐赠设备支持 256 字节有效载荷和 512 字节读请求: ```verilog max_payload_size_supported <= 3'b001; // 256 字节 max_read_request_size_supported <= 3'b010; // 512 字节 ``` 3. **重新构建并验证** - 保存修改后重新运行综合,确保 IP 核设置与固件常量之间一致。 --- ### **8.2 调整 BAR 与内存映射** BAR(基地址寄存器)决定了设备用于内存或 I/O 的地址空间。正确配置 BAR 对于驱动程序操作和操作系统资源分配至关重要。 #### **8.2.1 设置 BAR 大小** **目的:** 确保每个 BAR 设置了正确的大小和类型(32 位与 64 位;内存与 I/O)以保证主机分配正确的地址空间。 **步骤:** 1. **在 PCIe IP 核中定制 BAR** - 在 Vivado 中,右键点击 `pcie_7x_0.xci`,选择 **Customize IP**。 - 导航到 **BARs** 选项卡。 - 对于每个 BAR(BAR0–BAR5): - **设置大小:** 选择与捐赠设备相同的大小(例如 64 KB、128 MB)。 - **设置类型:** 选择 32 位或 64 位内存寻址(或 I/O 空间)。 - **启用或禁用:** 仅启用捐赠设备使用的 BAR。 2. **与片上内存(如适用)同步** - 如果使用块 RAM(BRAM)来支持仿真 BAR 区域,请打开相关的 BRAM IP 核文件(例如 `bram_bar_zero4k.xci`),确保内存大小与 BAR 配置相对应。 3. **保存、重新生成并验证** - 保存更改,让 Vivado 重新生成 IP 核。 - 检查 **Messages** 窗口,确保无配置警告。 --- #### **8.2.2 在固件中定义 BAR 地址空间** **目的:** 实现逻辑,用以解码针对 BAR 的地址并正确路由读/写操作。 **步骤:** 1. **打开 BAR 控制器源文件** - 例如,在 Visual Studio Code 中打开 `pcileech_tlps128_bar_controller.sv`。 2. **实现地址解码逻辑** - 使用组合逻辑确定访问的是哪个 BAR: ```verilog always_comb begin if (bar_hit[0]) begin // 处理对 BAR0 的访问 end else if (bar_hit[1]) begin // 处理对 BAR1 的访问 end // 根据需要继续处理其他 BAR end ``` 3. **为每个 BAR 实现读/写处理** - 在每个分支内,创建 case 语句或条件块,将特定地址偏移映射到内部寄存器: ```verilog if (bar_hit[0]) begin case (addr_offset) 16'h0000: data_out <= reg0; 16'h0004: data_out <= reg1; // 根据需要添加其他寄存器 default: data_out <= 32'h0; endcase end ``` 4. **保存并仿真验证** - 保存更改后,进行仿真以验证地址解码与数据传输是否正确。 --- #### **8.2.3 处理多个 BAR** **目的:** 如果设备暴露多个 BAR,必须确保每个 BAR 的逻辑独立,并且它们的地址空间不冲突。 **步骤:** 1. **分离 BAR 逻辑** - 考虑将每个 BAR 的逻辑模块化,分离为不同的代码块或模块(例如 `bar0_controller.sv`、`bar1_controller.sv`)。 2. **验证地址范围** - 确保每个 BAR 分配了唯一且不重叠的地址范围。 - 确保大小符合 PCIe 规范中要求的幂次对齐。 3. **测试** - 既使用测试平台仿真(测试基准)又使用硬件工具(如在 Linux 中用 `lspci -vvv` 或在 Windows 中使用设备管理器)验证映射与访问是否正确。 --- ### **8.3 仿真设备的电源管理与中断** 高级仿真需要支持设备电源管理状态和中断处理,这对于驱动程序的正常工作和系统稳定性至关重要。 --- #### **8.3.1 电源管理配置** **目的:** 启用电源管理功能使设备支持各种电源状态(D0 到 D3),这对提高能效及确保操作系统行为正常非常重要。 **步骤:** 1. **在 PCIe IP 核中启用电源管理** - 在 IP 定制窗口中,导航到 **Capabilities** 选项卡,并启用 “Power Management”。 - 选择支持的电源状态(例如,D0 完全开启、D1/D2 中间状态,以及 D3 低功耗)。 2. **在固件中实现 PMCSR 逻辑** - 在你的配置文件(例如 `pcileech_pcie_cfg_a7.sv`)中,实现处理电源管理控制/状态寄存器(PMCSR)写操作的逻辑: ```verilog localparam PMCSR_ADDRESS = 12'h44; // PMCSR 的示例地址 reg [15:0] pmcsr_reg; always @(posedge clk) begin if (cfg_write && cfg_address == PMCSR_ADDRESS) begin pmcsr_reg <= cfg_writedata[15:0]; // 根据 pmcsr_reg[1:0] 更新内部电源状态 end end ``` - *注意:* 如果进入低功耗状态,请根据需要更新设备操作行为。 3. **测试实现** - 仿真电源状态转换,验证 PMCSR 是否按照预期运行。 --- #### **8.3.2 MSI/MSI-X 配置与设备“激活”行为** **理解“激活设备”:** 在固件术语中,“激活设备”指的是那些定期发起 DMA 传输并在传输完成时通过中断通知主机的设备。这里的“激活”并非泛指激活状态,而是指设备主动“敲门”通知 CPU 数据已就绪。在高效中断信号传递要求较高的系统中,这一概念至关重要。 **MSI 与 MSI-X:** - **MSI:** 使用 Xilinx PCIe IP 核提供的内置中断接口。 - **MSI-X:** 由于内置接口不原生支持 MSI-X,固件需要手动构造并发送一个 MEMWR64 TLP 作为“门铃”中断。 **使用 MSI(基于内置接口)的步骤:** 1. **在 PCIe IP 核中配置 MSI** - 在 IP 核定制中,找到 **Interrupt** 或 **MSI/MSI-X** 部分。 - 启用 MSI 并设置支持的向量数量(通常最多 32 个)。 2. **在固件中实现中断接口** - 在配置文件中,将中断信号连接如下: ```verilog assign ctx.cfg_interrupt_di = cfg_int_di; assign ctx.cfg_pciecap_interrupt_msgnum = cfg_msg_num; assign ctx.cfg_interrupt_assert = cfg_int_assert; assign ctx.cfg_interrupt = cfg_int_valid; assign ctx.cfg_interrupt_stat = cfg_int_stat; ``` - 然后,添加一个进程,当事件发生(例如 DMA 完成)时断言 `cfg_int_valid`: ```verilog always @(posedge clk_pcie) begin if (rst) begin cfg_int_valid <= 1'b0; cfg_msg_num <= 5'b0; cfg_int_assert<= 1'b0; cfg_int_di <= 8'b0; cfg_int_stat <= 1'b0; end else if (cfg_int_ready && cfg_int_valid) begin cfg_int_valid <= 1'b0; end else if (o_int) begin cfg_int_valid <= 1'b0; // 根据中断生成时序进行调整 end end // 示例:中断计数器,用于生成周期性中断: reg [31:0] int_cnt; always @(posedge clk_pcie) begin if (rst) int_cnt <= 0; else if (int_cnt == 32'd100000) int_cnt <= 0; else if (int_enable) int_cnt <= int_cnt + 1; end assign o_int = (int_cnt == 32'd100000); ``` **使用 MSI-X(手动构造 TLP)的步骤:** 1. **手动构造 MSI-X TLP** - 由于 Xilinx IP 核中断接口不支持 MSI-X,你必须构造一个 MEMWR64 TLP 以信号中断。 - 定义 TLP 字段如下(根据捐赠设备的规格适当修改): ```verilog // 定义 MEMWR64 TLP 的头部字段 wire [31:0] HDR_MEMWR64 = 32'b01000000_00000000_00000000_00000001; // 构造后续数据字(注意位拼接正确): wire [31:0] MWR64_DW2 = { _bs16(pcie_id), 8'b0, 8'b00001111 }; wire [31:0] MWR64_DW3 = { i_addr[31:2], 2'b0 }; wire [31:0] MWR64_DW4 = i_data; ``` 2. **与 TLP 输出集成** - 在你的 TLP 发送逻辑中(例如 `pcileech_pcie_tlp_a7.sv` 内),将构造的 TLP 分配如下: ```verilog reg msix_valid; reg msix_has_data; reg [127:0] msix_tlp; assign tlps_static.tdata = msix_tlp; assign tlps_static.tkeepdw = 4'hF; assign tlps_static.tlast = 1'b1; assign tlps_static.tuser[0]= 1'b1; assign tlps_static.tvalid = msix_valid; assign tlps_static.has_data= msix_has_data; always @(posedge clk_pcie) begin if (rst) begin msix_valid <= 1'b0; msix_has_data <= 1'b0; msix_tlp <= 128'b0; end else if (msix_valid) begin msix_valid <= 1'b0; end else if (msix_has_data && tlps_static.tready) begin msix_valid <= 1'b1; msix_has_data <= 1'b0; msix_tlp <= { MWR64_DW4, MWR64_DW3, MWR64_DW2, HDR_MEMWR64 }; end else if (o_int) begin msix_has_data <= 1'b1; end end // 如有需要,使用类似的中断计数器以生成周期性中断。 ``` - *验证:* 确保组装的 TLP 符合 PCIe 对 MEMWR64 数据包的规格要求。建议使用仿真和集成逻辑分析器(ILA)进行硬件测试。 --- #### **8.3 实现中断处理逻辑** **目的:** 定义明确的条件和专用模块,用于在满足特定事件(例如 DMA 传输完成)时生成中断。这对于一个“激活”设备(频繁向主机发起“门铃”通知)至关重要。 **步骤:** 1. **定义中断触发条件** - 确定哪些事件应生成中断,可能包括: - DMA 传输完成。 - 数据就绪。 - 错误状态等。 - 实现组合或时序逻辑检测这些事件。 2. **模块化中断控制器** - 建议将中断逻辑封装在一个独立模块中,例如: ```verilog module interrupt_controller( input wire clk, input wire rst, input wire event_trigger, output reg msi_req ); always @(posedge clk or posedge rst) begin if (rst) msi_req <= 1'b0; else if (event_trigger) msi_req <= 1'b1; else msi_req <= 1'b0; end endmodule ``` - 将该模块集成到你的主固件逻辑中。 3. **确保正确时序** - 验证中断信号的断言与撤销是否符合 PCIe 的时序要求。 - 使用仿真和硬件调试工具(例如 ILA)确认主机能够正确接收中断信号。 --- ### **8.4 “FULL EMU” 与 “DUMP EMU” 有何区别?** **术语理解:** - **DUMP EMU:** 一种固件方法,其基本上“转储”了捐赠设备的 BAR 和功能寄存器(通常通过 Arbor 扫描获得)到 FPGA 中。该方法只复制静态配置数据。 - **FULL EMU:** 真正的全仿真不仅复制静态配置(ID、BAR、功能),而且仿真捐赠设备的动态行为,包括: - 正确生成 TLP(读取、写入、完成、厂商自定义消息)。 - 处理电源管理状态转换。 - 实现中断生成及正确的“门铃”通知(特别是在 MSI‑X 情况下)。 - 支持主动 DMA 传输与实时响应,与捐赠设备完全一致。 **未来改进:** 计划中的更新可能包括检测方法,以验证固件项目是真正的“FULL EMU”(具有主动动态行为)还是仅为静态的“DUMP EMU”。例如,可以使用基于 Realtek 的网卡进行高级测试作为基准。 --- ## **10. 交易层数据包 (TLP) 仿真** TLP 是 PCIe 通信的基本单元。为了实现完全功能的仿真,你的设计不仅要复制配置空间,还必须准确地生成和响应 TLP,就像真实设备一样。 ### **10.1 理解并捕获 TLP** #### **10.1.1 学习 TLP 结构** - **头部:** 包含字段如: - TLP 类型(例如内存读取、内存写入、配置、厂商自定义) - 长度、请求者 ID、标签、地址 - **数据有效载荷:** 存在于如内存写入等交易中。必须遵循协商的最大有效载荷大小。 - **CRC:** 用于数据完整性校验。 #### **10.1.2 捕获捐赠设备的 TLP** 1. **使用 PCIe 协议分析仪** - 使用 Teledyne LeCroy 分析仪或 Xilinx ILA 方案捕获实时 TLP。 2. **捕获并分析交易** - 监控正常操作期间的 TLP,记录头部字段、顺序和时序。 3. **记录关键交易** - 重点关注初始化序列、内存读写交换以及厂商自定义消息。 --- ### **10.2 针对特定操作构造自定义 TLP** #### **10.2.1 在固件中实现 TLP 处理** 1. **TLP 生成函数** - 在你的 TLP 模块(例如 `pcileech_pcie_tlp_a7.sv`)中,创建函数以组装 TLP。例如: ```verilog function automatic [127:0] generate_tlp( input [15:0] requester_id, input [7:0] tag, input [7:0] length, input [31:0] address, input [31:0] data ); // 构造并返回一个包含头部和载荷的 128 位 TLP endfunction ``` 2. **TLP 接收与解析** - 实现状态机以解析传入的 TLP,并根据类型(例如区分内存读与写)进行路由。 3. **完成处理** - 对于内存读请求,生成包含请求数据的完成 TLP,确保遵守 PCIe 的时序和 CRC 要求。 --- #### **10.2.2 处理不同类型的 TLP** 1. **内存读请求:** - 解析 TLP 头部,从正确的内存区域读取数据,并发送完成 TLP。 2. **内存写请求:** - 提取数据有效载荷,并将数据写入仿真寄存器或内存块。 3. **配置读/写:** - 分别访问配置空间寄存器。 4. **厂商自定义消息:** - 如果捐赠设备使用专有 TLP,实现特殊处理。 --- #### **10.2.3 验证 TLP 的时序和顺序** 1. **仿真测试:** - 开发测试平台仿真 TLP 交换,并验证头部、载荷以及响应时序的正确性。 2. **硬件调试:** - 使用 ILA 核实时监控 TLP 总线信号。 3. **合规性验证:** - 如有可能,使用 PCIe 合规性工具验证你的 TLP 实现是否符合规范。 --- ## **结论** 通过遵循第二部分中的详细步骤,你不仅扩展了对静态寄存器复制的仿真,还配置了关键的 PCIe 链路参数,确保正确的 BAR 和内存映射,实现了完整的电源管理以及同时支持 MSI 与 MSI‑X 中断。此外,你已经建立了一个基础,能够构造和验证自定义 TLP,从而实现一个真正“FULL EMU”的固件解决方案——其动态行为与捐赠设备完全一致。 **关键要点:** 1. **精确匹配高级 PCIe 参数:** - 链路速度、链路宽度、功能指针和有效载荷大小必须与捐赠设备一致。 2. **BAR 配置与地址解码:** - 正确设置 BAR 的大小与类型,并实现健壮的地址解码逻辑。 3. **中断 – MSI 与 MSI‑X:** - 对于 MSI 使用内置中断接口;对于 MSI‑X 则需手动构造 MEMWR64 TLP。 4. **主动设备行为:** - 通过仿真频繁的 DMA 传输和“门铃”中断信号,模仿真实硬件的动态行为。 5. **TLP 仿真:** - 确保 TLP 的生成、接收和时序完全符合 PCIe 标准,实现完整仿真。 在 **第三部分** 中,我们将以此为基础,进一步讨论性能优化、深入调试技巧以及生产级最佳实践。请继续根据捐赠设备的规格验证每个功能,以实现真正难以区分的仿真效果。 --- # **第三部分:高级技术与优化** *(第三部分内容将在后续详细介绍,包括性能优化、扩展调试方法以及长远维护的最佳实践。)* ================================================ FILE: Checklist.md ================================================ # Firmware Modification Checklist Use this checklist to guide you through the firmware creation. --- ## **1. Gather Donor Device Information** Collect the following information from the donor PCIe device: - [ ] **Device ID** (`0xXXXX`) - [ ] **Vendor ID** (`0xYYYY`) - [ ] **Subsystem ID** (`0xZZZZ`) - [ ] **Subsystem Vendor ID** (`0xWWWW`) - [ ] **Revision ID** (`0xRR`) - [ ] **Class Code** (`0xCCCCCC`) - [ ] **Base Address Registers (BARs) Configuration**: - [ ] **BAR0** to **BAR5** sizes, types (Memory or I/O), prefetchable status - [ ] **Capabilities**: - [ ] Power Management settings - [ ] MSI/MSI-X settings - [ ] **Device Serial Number (DSN)** (`0xXXXXXXXXYYYYYYYY`) --- ## **2. Modify Firmware Configuration Files** ### **2.1. Open Firmware Configuration File** ### **2.2. Update Device and Vendor IDs** - [ ] **Modify** `cfg_deviceid`: ```verilog cfg_deviceid <= 16'hXXXX; // Replace XXXX with donor's Device ID ``` - [ ] **Modify** `cfg_vendorid`: ```verilog cfg_vendorid <= 16'hYYYY; // Replace YYYY with donor's Vendor ID ``` ### **2.3. Update Subsystem IDs and Revision ID** - [ ] **Modify** `cfg_subsysid`: ```verilog cfg_subsysid <= 16'hZZZZ; // Replace ZZZZ with donor's Subsystem ID ``` - [ ] **Modify** `cfg_subsysvendorid`: ```verilog cfg_subsysvendorid <= 16'hWWWW; // Replace WWWW with donor's Subsystem Vendor ID ``` - [ ] **Modify** `cfg_revisionid`: ```verilog cfg_revisionid <= 8'hRR; // Replace RR with donor's Revision ID ``` ### **2.4. Update Class Code** - [ ] **Modify** `cfg_classcode`: ```verilog cfg_classcode <= 24'hCCCCCC; // Replace CCCCCC with donor's Class Code ``` ### **2.5. Insert Device Serial Number (DSN)** - [ ] **Modify** `cfg_dsn`: ```verilog cfg_dsn <= 64'hXXXXXXXXYYYYYYYY; // Replace with donor's DSN ``` --- ## **3. Customize Vivado Project** ### **3.1. Generate Vivado Project Files** - [ ] **Open Vivado** and run the appropriate Tcl script in the Tcl Console: ```tcl cd source vivado_generate_project_.tcl -notrace ``` - Replace `` with your project path. - Replace `` with your FPGA board identifier (e.g., `squirrel`). ### **3.2. Open Generated Project** - [ ] **File**: Open the generated `.xpr` project file in Vivado. --- ## **4. Modify PCIe IP Core** ### **4.1. Open PCIe IP Core Configuration** - [ ] **File to Edit**: `pcie_7x_0.xci` - [ ] **Action**: Right-click and select **Customize IP**. ### **4.2. Set Device Identifiers** - [ ] **Device ID**: Set to donor's Device ID. - [ ] **Vendor ID**: Set to donor's Vendor ID. - [ ] **Subsystem ID**: Set to donor's Subsystem ID. - [ ] **Subsystem Vendor ID**: Set to donor's Subsystem Vendor ID. - [ ] **Revision ID**: Set to donor's Revision ID. - [ ] **Class Code**: Set to donor's Class Code. ### **4.3. Configure BARs** For each BAR (BAR0 to BAR5): - [ ] **Enable/Disable**: Match donor device. - [ ] **Type**: Memory (32-bit or 64-bit) or I/O. - [ ] **Size**: Set to donor's BAR size. - [ ] **Prefetchable**: Match donor's setting. ### **4.4. Match PCIe Link Parameters** - [ ] **Maximum Link Speed**: Set to match donor device (e.g., **Gen2**, **Gen3**). - [ ] **Link Width**: Set to match donor device (e.g., **x1**, **x4**). ### **4.5. Configure Capabilities** - [ ] **Enable Power Management** if the donor device supports it. - [ ] **Enable MSI/MSI-X** if the donor device supports it. ### **4.6. Apply Changes and Lock IP Core** - [ ] **Apply**: Click **OK** to save IP core settings. - [ ] **Lock IP Core**: In the Tcl Console, run: ```tcl set_property -name {IP_LOCKED} -value true -objects [get_ips pcie_7x_0] ``` --- ## **5. Adjust Firmware for Advanced Features** ### **5.1. Update Capability Pointer** - [ ] **File to Edit**: `pcileech_pcie_cfg_a7.sv` - [ ] **Modify** `cfg_cap_pointer`: ```verilog cfg_cap_pointer <= 8'hXX; // Replace XX with donor's capability pointer ``` ### **5.2. Adjust Max Payload and Read Request Sizes** - [ ] **In PCIe IP Core**: Set **Max Payload Size** and **Max Read Request Size** to match donor device. - [ ] **In Firmware (`pcileech_pcie_cfg_a7.sv`)**: ```verilog max_payload_size_supported <= 3'bYYY; // Binary value corresponding to donor's Max Payload Size ``` - **Mapping**: | Payload Size (Bytes) | Binary Value | |----------------------|--------------| | 128 | `3'b000` | | 256 | `3'b001` | | 512 | `3'b010` | | 1024 | `3'b011` | | 2048 | `3'b100` | | 4096 | `3'b101` | ### **5.3. Implement Power Management Logic** - [ ] **File to Edit**: `pcileech_pcie_cfg_a7.sv` - [ ] **Add Logic** to handle power state transitions if applicable. ### **5.4. Implement MSI/MSI-X Interrupts** - [ ] **In PCIe IP Core**: Enable MSI or MSI-X capability and set the number of supported vectors. - [ ] **In Firmware (`pcileech_pcie_tlp_a7.sv`)**: - [ ] **Add Interrupt Logic** to handle MSI/MSI-X interrupts. --- ## **6. Adjust BAR Handling in Firmware** ### **6.1. Open BAR Controller File** - [ ] **File to Edit**: `pcileech_tlps128_bar_controller.sv` - [ ] **Location**: `pcileech-fpga/pcileech-wifi-main/src/pcileech_tlps128_bar_controller.sv` ### **6.2. Update BAR Address Decoding** - [ ] **Modify** the address decoding logic to match the BAR sizes and addresses of the donor device. ### **6.3. Implement BAR Access Logic** For each enabled BAR: - [ ] **Implement Read/Write Handlers** corresponding to the BAR's purpose. --- ## **7. Implement TLP Handling** ### **7.1. Open TLP Handling File** - [ ] **File to Edit**: `pcileech_pcie_tlp_a7.sv` ### **7.2. Modify TLP Processing Logic** - [ ] **Implement** logic to handle specific TLP types required by the donor device: - [ ] Memory Read Requests - [ ] Memory Write Requests - [ ] Configuration Read/Write Requests - [ ] Vendor-Defined Messages ### **7.3. Ensure TLP Compliance** - [ ] **Verify** that TLPs are correctly formatted according to PCIe specifications. --- ## **8. Build and Flash Firmware** ### **8.1. Run Synthesis and Implementation** In Vivado: - [ ] **Run Synthesis** - [ ] **Run Implementation** - [ ] **Generate Bitstream** ### **8.2. Program the FPGA** - [ ] **Connect** your FPGA device via JTAG. - [ ] **Open Hardware Manager**. - [ ] **Program Device** with the generated bitstream. --- ## **9. Test and Validate** ### **9.1. Verify Device Enumeration** - [ ] **Check** that the FPGA appears as the donor device on the host system. ### **9.2. Install Necessary Drivers** - [ ] **Use** donor device drivers if required. ### **9.3. Perform Functional Testing** - [ ] **Test** all functionalities expected from the donor device. ### **9.4. Monitor for Errors** - [ ] **Check** system logs for any errors or warnings related to the device. --- ## **10. Debug and Optimize as Needed** ### **10.1. Use Integrated Logic Analyzer (ILA)** - [ ] **Insert** ILA cores to monitor internal signals if necessary. ### **10.2. Analyze PCIe Traffic** - [ ] **Use** PCIe protocol analyzers to debug communication issues. ### **10.3. Refine Firmware** - [ ] **Iterate** on your firmware code to fix bugs and improve performance. ================================================ FILE: FW-Guide-v4.md ================================================ ## Need DMA Equiptment? I recommend shopping with [DMAPolice.com](https://dmapolice.com/) # **Part 1: Foundational Concepts** ## **1. Introduction** ### **1.1 Purpose of the Guide** This guide outlines a detailed roadmap for creating custom Direct Memory Access (DMA) firmware on FPGA-based devices, with the ultimate goal of accurately emulating PCIe hardware. Such emulation can serve a wide range of applications, including: - **Hardware Development & Testing** - Use FPGA-based emulation to replicate various hardware devices during development. - Run system-level tests without the expense or availability constraints of specific donor hardware. - **System Debugging & Diagnostics** - Reproduce complex hardware behaviors in a controlled environment to pinpoint bugs or driver-related issues. - Conduct trace analysis at the transaction layer (TLP) or memory-mapped I/O level. - **Security & Malware Research** - Investigate low-level PCIe vulnerabilities or advanced malware that interacts with hardware directly. - Observe how certain device drivers behave when hardware signatures are partially or fully spoofed. - **Hardware Emulation & Legacy Support** - Replace aging hardware with an FPGA-based solution that mimics the original device’s PCIe IDs, BARs, and interrupts. - Preserve legacy workflows on newer systems by emulating older or discontinued PCIe devices. By following this guide, you will learn to: 1. **Gather** essential device information from a physical “donor” PCIe card. 2. **Customize** FPGA firmware to present the same device/vendor IDs, BAR layouts, and capabilities. 3. **Build & Configure** your development environment (Xilinx Vivado, Visual Studio Code, etc.). 4. **Understand** the fundamentals of PCIe and DMA that are crucial to reliable device emulation. > **Why This Matters** > Proper hardware emulation saves effort, reduces costs, and often allows for rapid iteration. FPGA-based cards can be reprogrammed on-the-fly, letting you adapt to multiple devices or firmware variations far more easily than with fixed hardware. --- ### **1.2 Target Audience** This resource caters to a broad spectrum of professionals and enthusiasts: - **Firmware Developers** Interested in manipulating low-level system interactions, driver design, or advanced debugging of hardware/firmware stacks. - **Hardware & Validation Engineers** Seeking a controllable way to test system components with a wide variety of device profiles and conditions—without physically swapping PCIe cards every time. - **Security Researchers** Focused on analyzing the threat vectors introduced by DMA, exploring potential vulnerabilities in PCIe interactions, or performing safe sandbox emulations of malicious code. - **FPGA Hobbyists & Makers** Eager to expand their FPGA knowledge by building custom PCIe cores, learning advanced hardware description languages, and exploring real-world device enumeration. --- ### **1.3 How to Use This Guide** The guide is split into three parts, each building on the last: 1. **Part 1: Foundational Concepts** - Covers the prerequisite knowledge, environment setup, capturing donor device data, and making initial firmware adjustments. 2. **Part 2: Intermediate Concepts and Implementation** - Delves into deeper firmware customization, TLP-level manipulations, debugging strategies, and how to refine an emulated device’s behavior to match or surpass its donor’s functionality. 3. **Part 3: Advanced Techniques and Optimization** - Explores in-depth debugging tools, performance tuning, and best practices to ensure long-term maintainability of your FPGA-based DMA solutions. > **Recommendation**: Complete Part 1 thoroughly before moving on. Skipping or partially implementing these foundational steps can lead to confusion and misconfigurations in later stages. --- ## **2. Key Definitions** Having precise terminology is crucial for success in FPGA-based PCIe emulation. The following list expands on each relevant term: 1. **DMA (Direct Memory Access)** - **Definition**: Hardware-mediated transfers between devices and system memory without CPU intervention. - **Relevance**: Emulated devices heavily rely on DMA for throughput. Ensuring correct DMA configuration is central to a functional FPGA design. 2. **TLP (Transaction Layer Packet)** - **Definition**: The fundamental communication unit in PCIe, encapsulating both header information and data payload. - **Relevance**: Understanding TLP structure is vital if you plan to modify or analyze data at the PCIe transaction layer. 3. **BAR (Base Address Register)** - **Definition**: Registers specifying the address ranges (memory or I/O) where a PCIe device’s resources appear in the system address space. - **Relevance**: Accurately replicating a donor device’s BAR layout is key for correct driver loading and memory-mapped I/O handling. 4. **FPGA (Field-Programmable Gate Array)** - **Definition**: A reconfigurable chip whose internal circuitry can be redesigned (via HDL) to implement custom hardware logic. - **Relevance**: FPGAs let you quickly iterate on PCIe device designs, swapping out emulated devices with minimal hardware changes. 5. **MSI/MSI-X (Message Signaled Interrupts)** - **Definition**: PCIe-compliant interrupt methods allowing devices to trigger CPU interrupts through in-band messages rather than dedicated lines. - **Relevance**: Replicating donor interrupt behavior (especially the number of MSI vectors) can be critical for the driver that expects a specific interrupt mechanism. 6. **Device Serial Number (DSN)** - **Definition**: A 64-bit unique identifier some PCIe devices use for licensing, authentication, or advanced driver checks. - **Relevance**: Some drivers refuse to load or function unless the DSN matches the expected hardware. 7. **PCIe Configuration Space** - **Definition**: A defined region (256 bytes for PCI or 4 KB for PCIe extended) detailing device ID, vendor ID, capabilities, and operational parameters. - **Relevance**: Ensuring your FPGA device’s configuration space mirrors the donor’s (or includes the right subset) is essential to fool a host into treating it as the genuine article. 8. **Donor Device** - **Definition**: The actual PCIe card from which you obtain data (IDs, class codes, etc.) for emulation. - **Relevance**: The more data you accurately replicate, the closer your FPGA will behave to the original hardware in enumerations and function. --- ## **3. Device Compatibility** ### **3.1 Supported FPGA-Based Hardware** 1. **Squirrel (35T)** - A cost-effective Artix-7–based FPGA board that supports basic DMA operations. Recommended if you’re new to FPGA-based PCIe development. 2. **Enigma-X1 (75T)** - Offers more logic resources (LUTs, Block RAM) than a 35T, useful for moderate complexity tasks or extended debugging/tracing features. 3. **ZDMA (100T)** - Targets higher performance applications with substantial FPGA resources for intensive data transfers or multiple concurrent DMA channels. 4. **Kintex-7** - A robust, more premium FPGA family with advanced PCIe IP cores, typically used in demanding or large-scale emulation tasks. > **Tip**: Always check the specific lane configuration (x1, x4, x8) and speed rating (Gen1, Gen2, etc.) for your FPGA card, verifying it meets or exceeds what your host motherboard can support. ### **3.2 PCIe Hardware Considerations** - **IOMMU / VT-d** - *Recommendation*: Temporarily disable to avoid restricted DMA regions, especially important if you need full memory access for thorough testing. - **Kernel DMA Protection** - *Windows VBS / Secure Boot*: In some cases, these features intercept or limit direct PCIe memory mapping. - *Linux IOMMU or AppArmor/SELinux rules*: Adjust accordingly to ensure the FPGA can access the memory ranges it needs for emulation. - **PCIe Slot Requirements** - Choose a physical PCIe slot with enough lanes and confirm the BIOS is set to allocate those lanes appropriately. - If you notice performance issues or partial enumeration, confirm your system is not forcing x1 operation on a physically larger slot. ### **3.3 System Requirements** 1. **Hardware** - **CPU**: At least a quad-core from Intel or AMD for smooth Vivado synthesis and to manage OS overhead. - **RAM**: 16 GB or more for comfortable Vivado usage, especially for multi-hour synthesis runs. - **Storage**: 100 GB of SSD space recommended for faster project builds; mechanical HDDs can slow the build process drastically. - **OS**: Windows 10/11 (64-bit) or a well-supported Linux distribution (e.g., Ubuntu LTS, RHEL/CentOS) to run Xilinx Vivado. 2. **Peripheral Devices** - **JTAG Programmer**: (Xilinx Platform Cable USB II, Digilent HS3, or similar) needed to program your FPGA with the bitstream you create. - **Dedicated Machine**: Strongly suggested if you’re altering BIOS-level settings (VT-d) or require an environment free of unexpected conflicts with existing PCIe devices. --- ## **4. Requirements** ### **4.1 Hardware** 1. **Donor PCIe Device** - Purpose: You’ll extract the vendor/device ID, subsystem IDs, class code, BAR size, and capabilities. - Examples: An older network interface card (NIC), a basic storage controller, or even a specialized PCIe device that you want to replicate/extend. 2. **DMA FPGA Card** - Purpose: The actual hardware platform that runs the FPGA logic implementing the PCIe interface. - Examples: Squirrel 35T, Enigma-X1, or ZDMA 100T boards. 3. **JTAG Programmer** - Connects to the JTAG pins on your FPGA board, letting Vivado load the synthesized bitstream or debug firmware in real time. ### **4.2 Software** 1. **Xilinx Vivado Design Suite** - Required for creating, synthesizing, and implementing the FPGA design. - Download from [Xilinx](https://www.xilinx.com/support/download.html), ensuring you pick the correct version for your board’s IP requirements. 2. **Visual Studio Code** - A flexible, cross-platform editor supporting Verilog/SystemVerilog with additional plugins. - Helps maintain consistent code style, track changes, and streamline collaboration with version control (Git). 3. **PCILeech-FPGA** - GitHub repository: [PCILeech-FPGA](https://github.com/ufrisk/pcileech-fpga). - Offers baseline DMA designs for various FPGA boards, which you can further customize to replicate your donor device’s PCIe configuration. 4. **Arbor** (PCIe Device Scanner) - A user-friendly GUI tool that provides in-depth analysis of connected PCIe devices. - Alternatives: Telescan PE for traffic capture, or `lspci -vvv` in Linux for command-line introspection. ### **4.3 Environment Setup** 1. **Installing Vivado** - Follow Xilinx’s official installer, selecting the appropriate FPGA family (Artix-7, Kintex-7, etc.). - A Xilinx account may be required to download the Design Suite or access updates. 2. **Installing Visual Studio Code** - Download from [Visual Studio Code](https://code.visualstudio.com/). - Install recommended plugins: *Verilog-HDL/SystemVerilog* and a *Git* integration if you plan to maintain your project under source control. 3. **Cloning PCILeech-FPGA** ```bash cd ~/Projects/ git clone https://github.com/ufrisk/pcileech-fpga.git cd pcileech-fpga ``` - Ensure you have Git installed and configured. 4. **Isolated Development Environment** - Consider using a dedicated test machine (or a carefully configured dual-boot/VM) to reduce risk. - This approach allows you to disable kernel DMA protections, IOMMU, or secure boot features more freely, without compromising a primary production system. --- ## **5. Gathering Donor Device Information** Emulating a device effectively requires replicating its PCIe configuration space. That means capturing everything from device/vendor IDs to advanced capabilities. ### **5.1 Using Arbor for PCIe Device Scanning** #### **5.1.1 Install & Launch Arbor** 1. **Obtain Arbor** - Register and download from the official Arbor site. - Install with administrator rights. 2. **Start Arbor** - If prompted by UAC on Windows, confirm the application can run with elevated privileges. - You should see an interface listing PCI/PCIe devices. #### **5.1.2 Scan for Devices** 1. **Local System Tab** - Navigate to the “Local System” or “Scan” area in Arbor. 2. **Click “Scan”** - Arbor enumerates all devices on your PCIe bus. 3. **Identify the Donor** - Match the brand name or vendor ID to your known donor hardware. If it’s not easily recognized, cross-reference with known IDs from hardware documentation. #### **5.1.3 Extract Key Attributes** Collect the following from Arbor’s detailed view: - **Vendor ID / Device ID**: e.g., 0x8086 / 0x10D3 (Intel NIC). - **Subsystem Vendor ID / Subsystem ID**: e.g., 0x8086 / 0xA02F. - **Revision ID**: e.g., 0x01. - **Class Code**: e.g., 0x020000 for an Ethernet controller. - **BARs (Base Address Registers)**: - For each BAR, note if it’s enabled, the memory size (256 MB, 64 KB, etc.), and whether it’s prefetchable or 32-bit/64-bit. - **Capabilities**: - MSI or MSI-X details (number of interrupt vectors supported). - Extended configuration or advanced power management features. - **Device Serial Number (DSN)** (if present): - Some devices have a unique DSN field, especially if used for licensing or special driver checks. > **Organization Tip**: Use a spreadsheet or structured document to save these values. This ensures you don’t overlook details like advanced features or extended capabilities. --- ## **6. Initial Firmware Customization** With the donor’s PCIe attributes in hand, begin customizing your FPGA firmware to match those settings. ### **6.1 Modifying the PCIe Configuration Space** Your FPGA design likely includes a top-level file that sets the PCIe configuration registers. For example, in the `pcileech-fpga` repository, look for a file such as `pcileech_pcie_cfg_a7.sv` or `pcie_7x_0_core_top.v`. 1. **Open File in VS Code** - Search for lines defining `cfg_deviceid`, `cfg_vendorid`, `cfg_subsysid`, etc. 2. **Assign the Correct IDs** ```verilog cfg_deviceid <= 16'h10D3; // Example device ID cfg_vendorid <= 16'h8086; // Example vendor ID cfg_subsysid <= 16'h1234; cfg_subsysvendorid <= 16'h5678; cfg_revisionid <= 8'h01; cfg_classcode <= 24'h020000; // Example for Ethernet ``` - Replace these with the exact values from Arbor (or your donor’s datasheet). 3. **Insert DSN If Needed** ```verilog cfg_dsn <= 64'h0011223344556677; ``` - Omit or set to 0 if your donor device doesn’t rely on a DSN. 4. **Save & Review** - A single-digit error in any field could cause the OS to misidentify or reject the device. Double-check each line. ### **6.2 Consider BAR Configuration** While some PCIe IP cores store BAR settings in the same SystemVerilog file, others rely on Vivado’s IP customization GUI: - **Check how many BARs** your donor device uses (0 to 6). - **Set each BAR** (e.g., memory type, size, prefetchable, 64-bit vs. 32-bit). - If your donor has a large BAR region (e.g., 256 MB or bigger), ensure your FPGA board can accommodate it in the IP core settings. --- ## **7. Vivado Project Setup and Customization** ### **7.1 Generating Vivado Project Files** To organize all design files properly, many repositories include Tcl scripts: 1. **Launch Vivado** - Confirm you are using the correct version for your FPGA series (Artix-7, Kintex-7, etc.). 2. **Open Tcl Console** - **Window > Tcl Console** in Vivado’s top menu. 3. **Navigate to Project Directory** ```tcl cd C:/path/to/pcileech-fpga/pcileech-wifi-main/ pwd ``` - Confirm with `pwd` that the console is in the correct folder. 4. **Run the Generation Script** ```tcl source vivado_generate_project_squirrel.tcl -notrace ``` - If you’re using Enigma-X1 or ZDMA, run the corresponding script (e.g., `vivado_generate_project_enigma_x1.tcl`). 5. **Open the Generated Project** - **File > Open Project**. Locate and select the `.xpr` (e.g., `pcileech_squirrel_top.xpr`). - Check the **Project Manager** window for properly imported sources. ### **7.2 Customizing the PCIe IP Core** In Vivado, you may find a PCIe IP core (e.g., `pcie_7x_0.xci`) under **Sources**: 1. **Right-Click -> Customize IP** - Update vendor/device IDs, revision, and subsystem fields. - Match your desired BAR configurations (sizes, memory type, etc.). 2. **Generate/Update the IP** - Click **OK** or **Generate** to rebuild. - Vivado might prompt you to upgrade or confirm dependencies if IP versions have changed. 3. **Lock the IP Core** ```tcl set_property -name {IP_LOCKED} -value true -objects [get_ips pcie_7x_0] ``` - This prevents future scripts from overwriting your manual changes inadvertently. --- ## **Additional Best Practices** 1. **Version Control** - *Highly Recommended* - Commit your changes often (Git or another SCM). - Tag or branch major changes so you can revert quickly if something breaks. 2. **Documentation** - Keep a notebook, spreadsheet, or wiki summarizing donor device details, any special offsets, or capability quirks. - Document each step you take in customizing your FPGA firmware. 3. **Testing on the Host** - After generating a bitstream, program the FPGA, then check: - **Windows**: Device Manager or `devcon.exe` to confirm the device enumerates with the correct IDs. - **Linux**: `lspci -vvv` to see if the device identifies correctly, including BAR, Class Code, Subsystem, etc. 4. **Security Considerations** - Disabling features like VT-d or Secure Boot can open up the system to vulnerabilities. Use a dedicated test rig or isolate the environment to maintain operational security. 5. **Where to Next?** - In **Part 2**, you will learn to build on these basics with deeper TLP manipulation, partial reconfiguration strategies, firmware debugging, and any advanced ID spoofing or handshake emulations. --- # **Part 2: Intermediate Concepts and Implementation** --- ## **8. Advanced Firmware Customization** To precisely emulate your donor device, you must extend your basic configuration by aligning advanced PCIe parameters, fine-tuning BAR settings, and fully implementing power management and interrupt mechanisms. This ensures that your FPGA-based emulated device interacts with the host exactly as the original hardware would. --- ### **8.1 Configuring PCIe Parameters for Emulation** Accurate PCIe emulation requires that your device’s link characteristics, capability pointers, and data transfer parameters (payload and read request sizes) match the donor device. #### **8.1.1 Matching PCIe Link Speed and Width** **Purpose:** The PCIe link speed (e.g., Gen1 at 2.5 GT/s, Gen2 at 5.0 GT/s, Gen3 at 8.0 GT/s) and the link width (e.g., x1, x4, x8) directly affect performance and compatibility. The donor’s parameters must be mirrored to ensure that the host system and drivers recognize and operate with the emulated device seamlessly. **Steps:** 1. **Launch Vivado and Open Your Project:** - Open the Vivado project (e.g., `pcileech_squirrel_top.xpr`) where your design is maintained. - Confirm that all source files are included and that the project hierarchy is intact. 2. **Access the PCIe IP Core Settings:** - In the **Sources** pane, locate the PCIe IP core (typically named `pcie_7x_0.xci`). - Right-click the file and select **Customize IP** to open the configuration GUI. 3. **Set the Maximum Link Speed:** - Navigate to the **Link Parameters** tab. - Find the option labeled “Maximum Link Speed” and select the speed matching the donor device (e.g., 5.0 GT/s for Gen2). - *Note:* Verify that both your FPGA board and the physical slot support the selected speed. 4. **Configure the Link Width:** - In the same tab, locate “Link Width.” - Choose the appropriate width (e.g., x4) as per the donor device. - *Note:* Options typically include 1, 2, 4, 8, or 16 lanes. 5. **Apply and Regenerate:** - Click **OK** to save your changes. Vivado may prompt you to regenerate the IP core; allow the process to complete. - Finally, check the **Messages** window for any warnings or errors. --- #### **8.1.2 Setting Capability Pointers** **Purpose:** Capability pointers in the PCIe configuration space direct the host to locate extended capabilities (such as MSI/MSI‑X, power management, etc.). Matching these pointers ensures that the host accesses these capabilities exactly as it would with the donor device. **Steps:** 1. **Open the Firmware Configuration File:** - In Visual Studio Code, open the file (for example, `pcileech_pcie_cfg_a7.sv`) located under `pcileech-fpga/pcileech-wifi-main/src/`. 2. **Locate and Update the Capability Pointer Assignment:** - Find the assignment statement for `cfg_cap_pointer`. For example: ```verilog cfg_cap_pointer <= 8'hXX; // Current default value ``` - Replace `XX` with the correct donor offset (e.g., `8'h60` if the donor’s capability pointer is at offset 0x60): ```verilog cfg_cap_pointer <= 8'h60; // Set to donor's capability pointer at offset 0x60 ``` - *Verification:* Ensure that the capability structure is aligned on a 4-byte boundary as required by PCIe. 3. **Save the File and Comment Your Changes:** - Save the file (Ctrl+S) and add inline comments for future reference. --- #### **8.1.3 Adjusting Maximum Payload and Read Request Sizes** **Purpose:** PCIe devices negotiate the maximum amount of data per transaction. The “Maximum Payload Size” (MPS) and “Maximum Read Request Size” (MRRS) must be set to values identical to the donor device to guarantee driver compatibility and optimal data throughput. **Steps:** 1. **Configure in the PCIe IP Core:** - In the IP customization GUI (found in the PCIe IP core), navigate to the **Device Capabilities** or **Capabilities** tab. - Set the **Maximum Payload Size Supported** (e.g., 256 bytes) and **Maximum Read Request Size Supported** (e.g., 512 bytes) to match the donor device. 2. **Update Firmware Constants:** - Open `pcileech_pcie_cfg_a7.sv` in Visual Studio Code. - Locate the definitions for payload and read request sizes, for example: ```verilog max_payload_size_supported <= 3'bZZZ; // Current value max_read_request_size_supported <= 3'bWWW; // Current value ``` - Replace with the correct binary encodings: - **Mapping (example):** - 128 bytes: `3'b000` - 256 bytes: `3'b001` - 512 bytes: `3'b010` - 1024 bytes: `3'b011` - 2048 bytes: `3'b100` - 4096 bytes: `3'b101` - For example, if the donor supports 256 bytes payload and 512 bytes read requests: ```verilog max_payload_size_supported <= 3'b001; // 256 bytes max_read_request_size_supported <= 3'b010; // 512 bytes ``` 3. **Rebuild and Verify:** - Save the changes, re-run synthesis, and check for consistency between the IP core settings and firmware constants. --- ### **8.2 Adjusting BARs and Memory Mapping** BARs (Base Address Registers) determine which address spaces the device uses for memory or I/O. Correct BAR configuration is essential for driver operation and OS resource allocation. #### **8.2.1 Setting BAR Sizes** **Purpose:** Ensuring that each BAR is set to the correct size and type (32-bit vs. 64-bit; memory vs. I/O) guarantees that the host allocates the proper address space. **Steps:** 1. **Customize BARs in the PCIe IP Core:** - In Vivado, right-click on `pcie_7x_0.xci` and select **Customize IP**. - Navigate to the **BARs** tab. - For each BAR (BAR0–BAR5): - **Set the Size:** Select the size (e.g., 64 KB, 128 MB) as defined by the donor. - **Set the Type:** Choose between 32-bit or 64-bit memory addressing (or I/O space). - **Enable or Disable:** Enable only those BARs used by the donor. 2. **Synchronize with On-Chip Memory (if applicable):** - If using Block RAM (BRAM) to back up the emulated BAR regions, open the associated BRAM IP core files (e.g., `bram_bar_zero4k.xci`) and ensure that the memory size corresponds to the BAR configuration. 3. **Save, Regenerate, and Verify:** - Save your changes and allow Vivado to regenerate the IP core. - Review the **Messages** window for any configuration warnings. --- #### **8.2.2 Defining BAR Address Spaces in Firmware** **Purpose:** Implement logic to decode addresses targeting the BARs and route read/write operations correctly. **Steps:** 1. **Open the BAR Controller Source File:** - For example, open `pcileech_tlps128_bar_controller.sv` in Visual Studio Code. 2. **Implement Address Decoding Logic:** - Use combinational logic to determine which BAR is being accessed: ```verilog always_comb begin if (bar_hit[0]) begin // Handle accesses to BAR0 end else if (bar_hit[1]) begin // Handle accesses to BAR1 end // Continue for additional BARs as necessary end ``` 3. **Implement Read/Write Handling for Each BAR:** - Within each branch, create case statements or conditional blocks to map specific address offsets to internal registers: ```verilog if (bar_hit[0]) begin case (addr_offset) 16'h0000: data_out <= reg0; 16'h0004: data_out <= reg1; // Add additional registers as needed default: data_out <= 32'h0; endcase end ``` 4. **Save and Simulate:** - Save your changes, then simulate the design (if possible) to verify that address decoding and data transfers are correctly handled. --- #### **8.2.3 Handling Multiple BARs** **Purpose:** If your device exposes multiple BARs, you must ensure that the logic for each BAR is isolated and that their address spaces do not conflict. **Steps:** 1. **Separate BAR Logic:** - Consider modularizing your code by separating logic for each BAR into distinct blocks or even separate modules (e.g., `bar0_controller.sv`, `bar1_controller.sv`). 2. **Validate Address Ranges:** - Confirm that each BAR is allocated a unique, non-overlapping address range. - Ensure that the sizes are aligned on power-of-two boundaries as required by the PCIe specification. 3. **Testing:** - Perform both simulation (using test benches) and hardware testing (with tools such as `lspci -vvv` on Linux or Device Manager on Windows) to validate proper mapping and access. --- ### **8.3 Emulating Device Power Management and Interrupts** Advanced emulation includes support for device power management states and interrupt handling. This is critical for driver functionality and overall system stability. --- #### **8.3.1 Power Management Configuration** **Purpose:** Enabling power management capabilities lets the device support various power states (D0 through D3), which is important for energy efficiency and proper OS behavior. **Steps:** 1. **Enable Power Management in the PCIe IP Core:** - In the IP customization window, navigate to the **Capabilities** tab and enable “Power Management.” - Select the supported power states (e.g., D0 fully on, D1/D2 intermediate states, and D3 for low power). 2. **Implement PMCSR Logic in Firmware:** - In your configuration file (e.g., `pcileech_pcie_cfg_a7.sv`), implement logic to handle writes to the Power Management Control/Status Register (PMCSR): ```verilog localparam PMCSR_ADDRESS = 12'h44; // Example address for PMCSR reg [15:0] pmcsr_reg; always @(posedge clk) begin if (cfg_write && cfg_address == PMCSR_ADDRESS) begin pmcsr_reg <= cfg_writedata[15:0]; // Update internal power state based on pmcsr_reg[1:0] end end ``` - *Note:* Update the device’s operational behavior if entering lower power states, as required by your donor. 3. **Test the Implementation:** - Simulate power state transitions and verify that the PMCSR behaves as expected. --- #### **8.3.2 MSI/MSI-X Configuration and Active Device Behavior** **Understanding “Active Devices”:** In firmware parlance, an “active device” is one that regularly initiates DMA transfers and signals the host via interrupts when transfers complete. Rather than being “active” in a generic sense, these devices actively “ring the doorbell” to inform the CPU that data is ready. This concept is critical in systems where efficient interrupt signaling is key. **MSI (Message Signaled Interrupts) vs. MSI-X:** - **MSI:** Uses the built-in interrupt interface provided by the Xilinx PCIe IP core. - **MSI-X:** Requires the firmware to manually construct and send a MEMWR64 (Memory Write 64-bit) TLP as the “doorbell” because the built-in interface does not support MSI-X natively. **Steps for MSI (if using the built-in interface):** 1. **Configure MSI in the PCIe IP Core:** - In the IP core customization, locate the **Interrupt** or **MSI/MSI-X** section. - Enable MSI and set the number of supported vectors (typically up to 32). 2. **Implement the Interrupt Interface in Firmware:** - In your configuration file, wire up the interrupt signals as follows: ```verilog assign ctx.cfg_interrupt_di = cfg_int_di; assign ctx.cfg_pciecap_interrupt_msgnum = cfg_msg_num; assign ctx.cfg_interrupt_assert = cfg_int_assert; assign ctx.cfg_interrupt = cfg_int_valid; assign ctx.cfg_interrupt_stat = cfg_int_stat; ``` - Then, include a process that asserts `cfg_int_valid` when an event occurs (for example, DMA completion): ```verilog always @(posedge clk_pcie) begin if (rst) begin cfg_int_valid <= 1'b0; cfg_msg_num <= 5'b0; cfg_int_assert<= 1'b0; cfg_int_di <= 8'b0; cfg_int_stat <= 1'b0; end else if (cfg_int_ready && cfg_int_valid) begin cfg_int_valid <= 1'b0; end else if (o_int) begin cfg_int_valid <= 1'b0; // Adjust based on your interrupt generation timing end end // Example interrupt counter to generate periodic interrupts: reg [31:0] int_cnt; always @(posedge clk_pcie) begin if (rst) int_cnt <= 0; else if (int_cnt == 32'd100000) int_cnt <= 0; else if (int_enable) int_cnt <= int_cnt + 1; end assign o_int = (int_cnt == 32'd100000); ``` **Steps for MSI-X (Manual TLP Construction):** 1. **Manually Build the MSI-X TLP:** - Because the Xilinx IP core interrupt interface does not support MSI-X, you must construct a MEMWR64 TLP that signals an interrupt. - Define the TLP fields as follows (modify as needed based on your donor’s specification): ```verilog // Define the header fields for a MEMWR64 TLP. wire [31:0] HDR_MEMWR64 = 32'b01000000_00000000_00000000_00000001; // Construct subsequent data words (ensure proper bit concatenation): wire [31:0] MWR64_DW2 = { _bs16(pcie_id), 8'b0, 8'b00001111 }; wire [31:0] MWR64_DW3 = { i_addr[31:2], 2'b0 }; wire [31:0] MWR64_DW4 = i_data; ``` 2. **Integrate with TLP Output:** - In your TLP transmit logic (e.g., within `pcileech_pcie_tlp_a7.sv`), assign the constructed TLP: ```verilog reg msix_valid; reg msix_has_data; reg [127:0] msix_tlp; assign tlps_static.tdata = msix_tlp; assign tlps_static.tkeepdw = 4'hF; assign tlps_static.tlast = 1'b1; assign tlps_static.tuser[0]= 1'b1; assign tlps_static.tvalid = msix_valid; assign tlps_static.has_data= msix_has_data; always @(posedge clk_pcie) begin if (rst) begin msix_valid <= 1'b0; msix_has_data <= 1'b0; msix_tlp <= 128'b0; end else if (msix_valid) begin msix_valid <= 1'b0; end else if (msix_has_data && tlps_static.tready) begin msix_valid <= 1'b1; msix_has_data <= 1'b0; msix_tlp <= { MWR64_DW4, MWR64_DW3, MWR64_DW2, HDR_MEMWR64 }; end else if (o_int) begin msix_has_data <= 1'b1; end end // Use a similar interrupt counter for periodic generation if needed. ``` - *Verification:* Confirm that the assembled TLP conforms to the PCIe specification for a MEMWR64 packet. Use simulation and an Integrated Logic Analyzer (ILA) during hardware testing. --- #### **8.3.3 Implementing Interrupt Handling Logic** **Purpose:** Define clear conditions and a dedicated module for generating interrupts when required by events (e.g., DMA transfer completion). This is critical for an “active” device that signals the host frequently. **Steps:** 1. **Define Interrupt Trigger Conditions:** - Identify which events should generate an interrupt. These might include: - DMA transfer completion. - Data availability. - Error conditions. - Implement combinational or sequential logic to detect these events. 2. **Modularize the Interrupt Controller:** - It is advisable to encapsulate interrupt logic in a separate module: ```verilog module interrupt_controller( input wire clk, input wire rst, input wire event_trigger, output reg msi_req ); always @(posedge clk or posedge rst) begin if (rst) msi_req <= 1'b0; else if (event_trigger) msi_req <= 1'b1; else msi_req <= 1'b0; end endmodule ``` - Integrate this module with your main firmware logic. 3. **Ensure Correct Timing:** - Verify that interrupt assertions and de-assertions follow PCIe timing requirements. - Test with simulation and hardware debug tools (such as ILA) to confirm that the host receives interrupts appropriately. --- ### **8.4 What is “FULL EMU” vs. “DUMP EMU”?** **Understanding the Terminology:** - **DUMP EMU:** A firmware approach that essentially “dumps” the donor device’s BAR and capability registers (often obtained via an Arbor scan) into the FPGA. This method replicates only the static configuration data. - **FULL EMU:** True full emulation replicates not only the static configuration (IDs, BARs, capabilities) but also the dynamic behavior of the donor device. This includes: - Generating correct TLPs (for reads, writes, completions, vendor-specific messages). - Handling power management transitions. - Implementing interrupt generation and proper “doorbell” signaling (especially with MSI‑X). - Supporting active DMA transfers and real-time responses as the donor would. **Future Enhancements:** Planned updates may include detection methods that verify whether a firmware project is truly “FULL EMU” (with active dynamic behavior) versus a static “DUMP EMU.” For example, advanced testing on a Realtek-based NIC may be used as a benchmark. --- ## **10. Transaction Layer Packet (TLP) Emulation** TLPs are the fundamental units of communication over PCIe. For a fully functional emulation, your design must not only replicate configuration space but also accurately generate and respond to TLPs as a real device would. ### **10.1 Understanding and Capturing TLPs** #### **10.1.1 Learning the TLP Structure** - **Header:** Contains fields such as: - TLP Type (e.g., Memory Read, Memory Write, Config, Vendor-Defined) - Length, Requester ID, Tag, Address - **Data Payload:** Present in transactions like Memory Write. Must honor the negotiated Maximum Payload Size. - **CRC:** Used for data integrity verification. #### **10.1.2 Capturing TLPs from the Donor Device** 1. **Use a PCIe Protocol Analyzer:** - Tools like Teledyne LeCroy analyzers or Xilinx ILA setups capture real-time TLPs. 2. **Capture and Analyze Transactions:** - Monitor TLPs during normal operation to note header fields, sequence, and timing. 3. **Document Key Transactions:** - Focus on initialization sequences, memory read/write exchanges, and vendor-specific messages. --- ### **10.2 Crafting Custom TLPs for Specific Operations** #### **10.2.1 Implementing TLP Handling in Firmware** 1. **TLP Generation Functions:** - In your TLP module (e.g., `pcileech_pcie_tlp_a7.sv`), create functions to assemble TLPs. For example: ```verilog function automatic [127:0] generate_tlp( input [15:0] requester_id, input [7:0] tag, input [7:0] length, input [31:0] address, input [31:0] data ); // Construct and return a 128-bit TLP comprising header and payload. endfunction ``` 2. **TLP Reception and Parsing:** - Implement state machines to parse incoming TLPs and route them based on type (e.g., distinguishing between memory read and write). 3. **Completion Handling:** - For memory read requests, generate completion TLPs with the requested data, ensuring adherence to PCIe timing and CRC requirements. --- #### **10.2.2 Handling Different TLP Types** 1. **Memory Read Requests:** - Parse the TLP header, read from the correct memory region, and send a completion TLP. 2. **Memory Write Requests:** - Extract data payloads and write the data to emulated registers or memory blocks. 3. **Configuration Read/Write:** - Access the configuration space registers accordingly. 4. **Vendor-Defined Messages:** - Implement special handling if your donor device uses proprietary TLPs. --- #### **10.2.3 Validating TLP Timing and Sequence** 1. **Simulation Testing:** - Develop test benches that simulate TLP exchanges and verify the correctness of headers, payloads, and response timing. 2. **Hardware Debugging:** - Use an ILA core to monitor TLP bus signals in real time. 3. **Compliance Verification:** - Consider using PCIe compliance tools if available to verify that your TLP implementation meets specifications. --- ## **Conclusion** By following these detailed procedures in Part 2, you now extend your emulation beyond static register replication. You are configuring critical PCIe link parameters, ensuring proper BAR and memory mapping, implementing full power management, and handling both MSI and MSI‑X interrupts. Furthermore, you have established a foundation for crafting and validating custom TLPs that enable a fully active, “FULL EMU” firmware solution—one that mirrors the dynamic behavior of the donor device. **Key Takeaways:** 1. **Match Advanced PCIe Parameters Exactly:** - Link speed, link width, capability pointers, and payload sizes must be identical to the donor’s. 2. **BAR Configuration and Address Decoding:** - Correctly size and type your BARs, and implement robust address decoding logic. 3. **Interrupts – MSI vs. MSI‑X:** - Use the built-in interrupt interface for MSI; manually construct MEMWR64 TLPs for MSI‑X. 4. **Active Device Behavior:** - Emulate frequent DMA transfers and “doorbell” interrupt signaling to mirror real hardware activity. 5. **TLP Emulation:** - Ensure that TLP generation, reception, and timing conform to PCIe standards for complete emulation. In **Part 3**, we will build on these intermediate concepts with performance optimizations, extensive debugging techniques, and production-level best practices. Continue to validate each feature against the donor device’s specifications to achieve a truly indistinguishable emulation. ================================================ FILE: Lesson 3_ Advanced PCIe Configuration and Interrupt Handling.md ================================================ # Lesson: Understanding PCIe Configuration and Interrupt Handling on Xilinx Artix-7 Platforms ## **Overview** Please let me know if you guys like the lesson based format over the all in one guide. If so, I will provide a course nd perhaps videos. This lesson delves into the intricacies of PCI Express (PCIe) configuration, specifically focusing on determining maximal payload sizes and handling interrupts within FPGA-based systems using Xilinx Artix-7. Additionally, it explores the PCIe data link layer mechanisms, including Transaction Layer Packets (TLPs), Data Link Layer Packets (DLLPs), and flow control. By the end of this lesson, you will have a comprehensive understanding of configuring PCIe devices, defining interrupts in FPGA designs, and optimizing PCIe performance on Artix-7 platforms. --- ## **Objectives** By the end of this lesson, you will be able to: 1. **Determine Maximal Payload Sizes** for PCIe devices using both automated tools and manual methods. 2. **Define and Handle Interrupts** in FPGA-based PCIe designs for Xilinx Artix-7 platforms. 3. **Understand PCIe Data Link Layer Mechanisms**, including TLPs, DLLPs, and flow control. 4. **Optimize PCIe Performance** by analyzing payload sizes and their impact on data transmission. --- ## **1. Introduction to PCI Express (PCIe)** PCI Express (PCIe) is a high-speed serial computer expansion bus standard designed to replace older bus standards like PCI and PCI-X. It is widely used for connecting peripheral devices to the motherboard, including graphics cards, SSDs, and network cards. Understanding PCIe configuration and interrupt handling is crucial for optimizing system performance and ensuring reliable communication between devices. On FPGA platforms like Xilinx Artix-7, implementing PCIe interfaces allows for the creation of custom peripherals, enabling applications in hardware testing, system debugging, data acquisition, and more. --- ## **2. Determining Maximal Payload Size** ### **2.1. Automated Approach with `lspci`** The `lspci` utility in Linux provides detailed information about all PCI devices connected to the system. It can automatically determine the maximal payload size a PCIe device can handle without manual intervention. **Example Command:** ```bash lspci -vv ``` This command displays verbose information about all PCI devices, including their capabilities and configuration registers. ### **2.2. Manual Approach: Parsing Configuration Space** Understanding how to manually determine the maximal payload size can demystify underlying processes and provide deeper insights into PCIe configurations. #### **2.2.1. PCIe Configuration Space** Each PCIe device has a 256-byte configuration space containing various registers that define its capabilities and settings. Key registers related to payload size include: - **Device Capabilities Register (DevCap):** Located at offset `0x04` in the PCI Express Capability structure. Bits `2-0` indicate the `max_payload_size_capable`. - **Device Control Register (DevCtrl):** Located at offset `0x08` in the PCI Express Capability structure. Bits `7-5` indicate the `max_payload_size_in_effect`. #### **2.2.2. Calculating Maximal Payload Size** The maximal payload size is determined using the following formula: ```c max_payload_size_capable = 1 << ((DevCapReg & 0x07) + 7); // In bytes max_payload_size_in_effect = 1 << (((DevCtrlReg >> 5) & 0x07) + 7); // In bytes ``` - **`DevCapReg`**: Value from the Device Capabilities Register. - **`DevCtrlReg`**: Value from the Device Control Register. #### **2.2.3. Example: Manual Parsing with `lspci -xxx`** Consider the following `lspci -xxx` output for a specific device: ``` 01:00.0 Class ff00: Xilinx Corporation Artix-7 PCIe Core 00: ee 10 34 12 07 04 10 00 00 00 00 ff 01 00 00 00 ... 40: 01 48 03 70 08 00 00 00 05 58 81 00 0c 30 e0 fe ... 58: 00 00 00 00 00 00 00 00 60: 10 28 00 00 11 f4 03 00 ... ``` **Steps:** 1. **Identify the PCI Express Capability Structure:** - Locate the capability with **Cap ID `0x10`**. - Follow the linked list pointers to find the structure at offset `0x58`. 2. **Extract Registers:** - **Device Capabilities Register (`0x5C`):** `0x00288fc2` - Bits `2-0`: `2` → `1 << (2 + 7) = 512 bytes` - **Device Control Register (`0x60`):** `0x00002810` - Bits `7-5`: `0` → `1 << (0 + 7) = 128 bytes` 3. **Interpretation:** - **Max Payload Size Capable:** `512 bytes` - **Max Payload Size in Effect:** `128 bytes` ### **2.3. Impact on Performance** A smaller maximal payload size (e.g., `128 bytes`) can lead to increased overhead, as more TLPs (Transaction Layer Packets) are required to transmit the same amount of data compared to larger payload sizes (e.g., `512 bytes`). This overhead affects the effective bandwidth: - **128-byte TLPs:** - Overhead: ~12% - Effective Bandwidth: ~219 MB/s - **512-byte TLPs:** - Overhead: ~3.4% - Effective Bandwidth: ~241 MB/s Understanding and optimizing payload sizes can significantly enhance system performance, especially in high-throughput applications. --- ## **3. Interrupt Definitions in FPGA-Based PCIe Designs** ### **3.1. Overview of Interrupts in PCIe** Interrupts are essential for asynchronous event handling in PCIe devices. Properly defining and handling interrupts ensures that the FPGA-based PCIe device can notify the host system of events, such as data availability or error conditions. ### **3.2. Defining Interrupts in FPGA Designs** Interrupts in FPGA-based PCIe designs are typically managed through Message Signaled Interrupts (MSI) or MSI-X, which allow devices to generate interrupts by writing to a specific memory address. #### **3.2.1. Example: MSI Interrupt Definition** In the FPGA firmware, defining MSI involves configuring the MSI capability structure and ensuring that the host system can map and handle these interrupts. **Verilog Example:** ```verilog // MSI Capability Structure module msi_cap ( input wire clk, input wire reset, // Other signals output reg [31:0] msi_address, output reg [31:0] msi_data, output reg msi_enable ); // Configuration always @(posedge clk or posedge reset) begin if (reset) begin msi_address <= 32'h00000000; msi_data <= 32'h00000000; msi_enable <= 1'b0; end else begin // Set MSI Address and Data based on host configuration msi_address <= 32'hFEE00000; // Example address msi_data <= 32'h00000001; // Example data msi_enable <= 1'b1; // Enable MSI end end endmodule ``` **Explanation:** - **`msi_address`:** The address where the MSI will write to notify the host. - **`msi_data`:** The data payload sent with the MSI. - **`msi_enable`:** Enables or disables MSI generation. ### **3.3. Handling Interrupts in the Host System** On the host side (e.g., Linux), interrupt handling involves mapping the MSI addresses and ensuring that the kernel can process the interrupts generated by the FPGA. **Example Steps on Linux:** 1. **Device Tree Configuration:** Define the MSI interrupt properties in the device tree to inform the kernel about the interrupt capabilities. ```dts pcie_fpga@0000:01:00.0 { compatible = "xilinx,artix7-pcie-core"; reg = <0x0000 0x0001 0x0000 0x0000>; interrupts = <1 45 4>; interrupt-parent = <&msi_controller>; msix-num = <16>; // Other properties }; ``` **Explanation:** - **`interrupts = <1 45 4>;`** - **`1`**: Indicates MSI interrupt. - **`45`**: Interrupt number. - **`4`**: Level-sensitive, active high. 2. **Kernel Module Driver:** In the FPGA's kernel driver, register the interrupt handler to respond to MSIs. ```c irq = irq_of_parse_and_map(op->dev.of_node, 0); rc = request_irq(irq, artix7_pcie_isr, 0, "artix7_pcie", op->dev); if (rc) { // Handle error } ``` - **`irq_of_parse_and_map`:** Parses the `interrupts` property and maps it to a Linux IRQ number. - **`request_irq`:** Registers the interrupt handler (`artix7_pcie_isr`) for the specified IRQ. --- ## **4. PCIe Data Link Layer Mechanisms** ### **4.1. Transaction Layer Packets (TLPs)** TLPs are the fundamental units of communication in PCIe, carrying both control and data information between devices. **Components of a TLP:** - **Header:** Contains information like type, length, and address. - **3 DWs** for 32-bit addressing. - **4 DWs** for 64-bit addressing. - **Data Payload:** The actual data being transmitted. - **Optional Digest:** Typically a 1-DW TLP digest (ECRC). ### **4.2. Data Link Layer Packets (DLLPs)** DLLPs are used by the Data Link Layer to manage reliable transmission over PCIe. They include: - **Ack DLLP:** Acknowledges successful receipt of TLPs. - **Nack DLLP:** Indicates a corrupted TLP, prompting retransmission. - **Flow Control DLLPs:** Manage credits for data transmission. - **Power Management DLLPs:** Handle power state transitions. ### **4.3. Flow Control Mechanism** Flow Control ensures that a sender does not overwhelm a receiver by transmitting more data than it can handle. **Key Concepts:** - **Flow Control Units:** Correspond to 16 bytes (4 DWs) of traffic. - **Credit Types:** Six distinct types based on the TLP category: 1. Posted Requests TLPs (headers) 2. Posted Requests TLPs (data) 3. Non-Posted Requests TLPs (headers) 4. Non-Posted Requests TLPs (data) 5. Completion TLPs (headers) 6. Completion TLPs (data) - **Doorkeeper Analogy:** Manages the number of flow control units to prevent buffer overflows. **Flow Control Operations:** 1. **Initial Exchange:** Both sides exchange their initial credit limits upon link establishment. 2. **Credit Updates:** As TLPs are transmitted and processed, credit limits are updated via UpdateFC DLLPs. 3. **Credit Overflow Handling:** Uses modulo arithmetic to handle counter overflows gracefully. **Infinite Credit Option:** Endpoints must advertise infinite credit for completion headers and data, ensuring they can always accept completion TLPs without relying on flow control. ### **4.4. Virtual Channels** Virtual Channels (VCs) allow multiple independent streams of TLPs to coexist without interfering with each other. **Key Points:** - **Traffic Class (TC):** Identifies the virtual channel. - **Default Usage:** Most systems use a single virtual channel (`TC0`), rendering VCs optional for standard applications. - **Advanced Usage:** Useful in scenarios requiring segregated traffic streams to prevent blocking. ### **4.5. Packet Reordering** PCIe allows certain degrees of TLP reordering to optimize transmission and prevent deadlocks. **Reordering Rules:** 1. **Posted Writes and MSIs:** Always arrive in the order sent. 2. **Read Requests:** Never arrive before preceding write requests or MSIs. 3. **Write Requests:** May arrive before preceding read requests. 4. **Read Completions:** Ordered per request but can be reordered across different requests. **Implications:** - **Consistency:** Ensures memory operations maintain expected order for data integrity. - **Deadlock Prevention:** Reordering rules are designed to prevent communication deadlocks in complex topologies. ### **4.6. Zero-Length Read Requests** Zero-length read requests are used to ensure write operations have completed without retrieving any actual data. **Behavior:** - **Completion Requirement:** Must return a single DW of data, which is typically disregarded. - **Usage Scenario:** Acts as a synchronization mechanism to confirm the completion of preceding write operations. --- ## **5. Practical Considerations** ### **5.1. FPGA Firmware Probing and Mapping** When developing FPGA firmware for PCIe devices, it's essential to correctly probe and map hardware resources to ensure seamless communication with the host system. **Key Steps:** 1. **Configure PCIe Parameters:** - Set device IDs, vendor IDs, subsystem IDs, and BARs to match the desired emulated device. 2. **Implement Interrupt Handling:** - Configure MSI/MSI-X capabilities in the FPGA firmware. - Ensure the host system can map and handle these interrupts. 3. **Map Memory Regions:** - Define BAR sizes and address spaces accurately to match the target device's configuration. 4. **Integrate with Host Drivers:** - Develop or modify host-side drivers to interact with the FPGA-based PCIe device effectively. ### **5.2. Accessing Hardware Registers Correctly** Directly accessing hardware registers via pointers can lead to cache coherency issues, especially on platforms interfacing with FPGAs like Artix-7. **Best Practices:** - **Use IO Functions:** Utilize provided API functions or interfaces for register access to maintain cache coherency. - **Avoid `volatile`:** The Linux kernel discourages the use of the `volatile` keyword for hardware registers. Instead, use appropriate memory barriers or synchronization mechanisms. **Example in Kernel Module:** ```c #include u32 value; value = ioread32(registers + OFFSET); iowrite32(new_value, registers + OFFSET); ``` ### **5.3. Interrupt Handler Registration** Properly registering interrupt handlers ensures that your FPGA-based PCIe device responds to hardware events correctly. **Example:** ```c irq = irq_of_parse_and_map(op->dev.of_node, 0); rc = request_irq(irq, artix7_pcie_isr, 0, "artix7_pcie", op->dev); if (rc) { dev_err(&op->dev, "Failed to request IRQ\n"); return rc; } ``` - **`irq_of_parse_and_map`:** Parses the `interrupts` property and maps it to a Linux IRQ number. - **`request_irq`:** Registers the interrupt handler (`artix7_pcie_isr`) for the specified IRQ. --- ## **6. Summary and Best Practices** - **Maximal Payload Size:** - Use `lspci -vv` for automated retrieval. - Manual parsing provides deeper insights and can be essential for custom configurations. - Larger payload sizes reduce overhead and improve bandwidth efficiency. - **Interrupt Definitions:** - Clearly define interrupts in FPGA designs with correct flags, numbers, and types. - Understand the distinction between MSI and MSI-X interrupts and their respective configurations. - Ensure the interrupt type aligns with hardware capabilities and kernel expectations. - **PCIe Data Link Layer:** - TLPs and DLLPs manage data transmission and flow control. - Flow control mechanisms prevent buffer overflows and ensure reliable communication. - Virtual Channels and packet reordering enhance transmission efficiency and prevent deadlocks. - **FPGA Firmware Development:** - Always use IO functions for register access to maintain cache coherency. - Properly probe and map hardware resources to avoid conflicts. - Register interrupt handlers accurately to respond to hardware events effectively. --- ## **7. Exercises and Questions** ### **Exercise 1: Calculating Maximal Payload Size** Given a Device Capabilities Register value of `0x00000005` and a Device Control Register value of `0x00000060`, calculate: 1. **Max Payload Size Capable** 2. **Max Payload Size in Effect** *Solution:* 1. **Max Payload Size Capable:** - `(DevCapReg & 0x07) + 7 = (5) + 7 = 12` - `1 << 12 = 4096 bytes` 2. **Max Payload Size in Effect:** - `((DevCtrlReg >> 5) & 0x07) + 7 = ((0x60 >> 5) & 0x07) + 7 = (3 & 0x07) + 7 = 10` - `1 << 10 = 1024 bytes` ### **Question 1: Interrupt Type Flags** Explain the significance of each value in the `interrupts` property `<0x0 0x32 0x0>` for a device in an FPGA-based PCIe design. *Answer:* - **`0x0`:** Indicates the interrupt is an MSI (Message Signaled Interrupt). - **`0x32`:** The interrupt number, used by the host to identify the interrupt source. - **`0x0`:** Specifies the interrupt type as default (leave as set by the FPGA firmware). ### **Question 2: Flow Control Units** Why are flow control units rounded up to the nearest integer when calculating data consumption in TLPs? *Answer:* Flow control units correspond to fixed sizes (16 bytes) and ensure that buffer space is allocated efficiently without mixing data from different TLPs. Rounding up ensures that any partial data payload still consumes a full flow control unit, maintaining alignment and preventing buffer overflow. ### **Exercise 2: FPGA Firmware Interrupt Mapping** Given the following interrupt definition in FPGA firmware: ```verilog interrupts = <1 45 4>; ``` Determine: 1. **Is the interrupt an MSI or MSI-X?** 2. **What is the interrupt number?** 3. **What is the interrupt type?** *Solution:* 1. **`1`:** Indicates it's an MSI (Message Signaled Interrupt). 2. **`45`:** Interrupt number as specified. 3. **`4`:** Level-sensitive, active high. --- ## **8. Further Reading and Resources** - **PCI Express Base Specification:** Comprehensive guide to PCIe standards. - **Xilinx Artix-7 FPGA Documentation:** Official documentation for Artix-7 FPGA configurations and capabilities. - **Linux Device Drivers Documentation:** Official documentation for writing and understanding PCIe drivers in Linux. - **Xilinx Vivado Documentation:** Detailed guides and tutorials for using Vivado with Artix-7 FPGAs. - **PCILeech-FPGA Repository:** [https://github.com/ufrisk/pcileech-fpga](https://github.com/ufrisk/pcileech-fpga) - **Wireshark PCIe Extensions:** [https://www.wireshark.org/docs/](https://www.wireshark.org/docs/) - **Teledyne LeCroy Telescan PE Documentation:** [Teledyne LeCroy Telescan PE](https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software) - **Arbor Software User Guide:** [Arbor User Guide](https://www.mindshare.com/software/Arbor) - **Field Programmable Gate Array (FPGA) Basics:** [FPGA Basics](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2020_2/ug901-vivado-tutorial.pdf) - **PCI-SIG Specifications:** [PCI-SIG](https://pcisig.com/specifications) --- **End of Lesson** --- ## **Feedback and Donation Request** I aimed to provide this lesson in a clear and structured format to enhance understanding and facilitate easier absorption of complex PCIe concepts on Xilinx Artix-7 platforms. Your feedback is invaluable in improving the quality and effectiveness of this content. If you find this lesson helpful and would like to support further development, please consider making a donation. Thank you for your support! --- ## **Support My Work** If you found this guide helpful and want to fuel more projects, consider contributing to help keep everything going. Every donation helps me continue to create, share, and support the community, and it’s greatly appreciated. ### **Crypto Donations (LTC)** - MPMyQD5zgy2b2CpDn1C1KZ31KmHpT7AwRi I don’t make much from selling firmware—maybe 5 sales adding up to around $300 total—but I know many people using this guide will go on to make far more. If this guide helped you on your path to success, consider giving back so I can keep these resources available for everyone. ### **Special Bonus** If you donate, reach out to me on Discord (VCPU) and let me know. I’d love to thank you personally and offer something in return. I’ll even do a random prize spin—whether it's free firmware, private source codes, or some insights on bypassing ACS, there’ll be something special for you. Your support means the world to me, and together we can keep building and sharing for the future. Thank you! --- Don't have the time or energy to develop firmware yourself? I offer custom firmware solutions starting at $60. Resellers are also welcome! Reach out anytime for support or further discussion on this guide or related topics. Whether you’re a developer needing in-depth help or a researcher diving into FPGA emulation, I’m here to ensure your path to success is smooth and informed. Let's build something remarkable together. If you are unsure if you completed a step properly or want me to review your implementation, I will do so, but you must have the section for review marked with `//VCPU-REVIEW//` and explain your problems so my time is not wasted. I am sure quite a few of you will exceed my capabilities. If you find something new or just develop some impressive firmware, I would love to see it in action. Moreover, I also have some very powerful bytes and bits to share, but if I shared here Riot PD would put me in a squad car. Share knowledge and spread loving kindness. God bless. --- ## **Contact Information** If you need assistance, have inquiries, or are looking to collaborate, feel free to reach out. I’m available to provide guidance, troubleshoot complex problems, or discuss ideas in detail. ### **Discord** - **VCPU** | [**Server**](https://discord.gg/dS2gDUDQmV) --- ## **Best Practices for Firmware Development** Adhering to best practices ensures the development process is efficient, maintainable, and secure. ### **15.1. Continuous Testing and Documentation** - **Test Frequently** - **Steps**: 1. Conduct regular tests after each modification to ensure the firmware behaves as expected. 2. Use automated scripts or test benches to validate firmware functionality continuously. - **Document Changes** - **Steps**: 1. Maintain detailed documentation for each change made to the firmware. 2. Include explanations for why changes were made and their impact on the overall design. ### **15.2. Managing Firmware Versioning** - **Use Version Control** - **Steps**: 1. Implement a version control system (e.g., **Git**) to manage different iterations of the firmware. 2. Commit changes regularly with descriptive messages to track the evolution of the project. - **Branching Strategy** - **Steps**: 1. Use branches to manage feature development, bug fixes, and experimental changes. 2. Merge stable branches into the main branch only after thorough testing. ### **15.3. Security Considerations** - **Prevent Unintended Access** - **Steps**: 1. Ensure that the firmware does not expose system memory or hardware to unauthorized access. 2. Implement access controls and validation checks within the firmware. - **Protect Firmware Integrity** - **Steps**: 1. Avoid introducing vulnerabilities or backdoors during firmware development. 2. Conduct regular security reviews and code audits to maintain firmware integrity. - **Handle Sensitive Data Securely** - **Steps**: 1. If the firmware interacts with sensitive data, implement encryption and secure data handling practices. 2. Ensure that sensitive information is not exposed through firmware interfaces or logs. ================================================ FILE: README-old.md ================================================ ## Need DMA Equiptment? I recommend shopping with [DMAPolice.com](https://dmapolice.com/) # **Custom Firmware Development Guide for Full Device Emulation** ***v4 in progress - nearly done*** --- ## **Table of Contents** ### **Part 1: Foundational Concepts** 1. [Introduction](#1-introduction) - [1.1 Purpose of the Guide](#11-purpose-of-the-guide) - [1.2 Target Audience](#12-target-audience) - [1.3 How to Use This Guide](#13-how-to-use-this-guide) 2. [Key Definitions](#2-key-definitions) 3. [Device Compatibility](#3-device-compatibility) - [3.1 Supported FPGA-Based Hardware](#31-supported-fpga-based-hardware) - [3.2 PCIe Hardware Considerations](#32-pcie-hardware-considerations) - [3.3 System Requirements](#33-system-requirements) 4. [Requirements](#4-requirements) - [4.1 Hardware](#41-hardware) - [4.2 Software](#42-software) - [4.3 Environment Setup](#43-environment-setup) 5. [Gathering Donor Device Information](#5-gathering-donor-device-information) - [5.1 Using Arbor for PCIe Device Scanning](#51-using-arbor-for-pcie-device-scanning) - [5.2 Extracting and Recording Device Attributes](#52-extracting-and-recording-device-attributes) 6. [Initial Firmware Customization](#6-initial-firmware-customization) - [6.1 Modifying Configuration Space](#61-modifying-configuration-space) - [6.2 Inserting the Device Serial Number (DSN)](#62-inserting-the-device-serial-number-dsn) 7. [Vivado Project Setup and Customization](#7-vivado-project-setup-and-customization) - [7.1 Generating Vivado Project Files](#71-generating-vivado-project-files) - [7.2 Modifying IP Blocks](#72-modifying-ip-blocks) ### **Part 2: Intermediate Concepts and Implementation** 8. [Advanced Firmware Customization](#8-advanced-firmware-customization) - [8.1 Configuring PCIe Parameters for Emulation](#81-configuring-pcie-parameters-for-emulation) - [8.2 Adjusting BARs and Memory Mapping](#82-adjusting-bars-and-memory-mapping) - [8.3 Emulating Device Power Management and Interrupts](#83-emulating-device-power-management-and-interrupts) 9. [Emulating Device-Specific Capabilities](#9-emulating-device-specific-capabilities) - [9.1 Implementing Advanced PCIe Capabilities](#91-implementing-advanced-pcie-capabilities) - [9.2 Emulating Vendor-Specific Features](#92-emulating-vendor-specific-features) 10. [Transaction Layer Packet (TLP) Emulation](#10-transaction-layer-packet-tlp-emulation) - [10.1 Understanding and Capturing TLPs](#101-understanding-and-capturing-tlps) - [10.2 Crafting Custom TLPs for Specific Operations](#102-crafting-custom-tlps-for-specific-operations) ### **Part 3: Advanced Techniques and Optimization** 11. [Building, Flashing, and Testing](#11-building-flashing-and-testing) - [11.1 Synthesis and Implementation](#111-synthesis-and-implementation) - [11.2 Flashing the Bitstream](#112-flashing-the-bitstream) - [11.3 Testing and Validation](#113-testing-and-validation) 12. [Advanced Debugging Techniques](#12-advanced-debugging-techniques) - [12.1 Using Vivado's Integrated Logic Analyzer](#121-using-vivados-integrated-logic-analyzer) - [12.2 PCIe Traffic Analysis Tools](#122-pcie-traffic-analysis-tools) 13. [Troubleshooting](#13-troubleshooting) - [13.1 Device Detection Issues](#131-device-detection-issues) - [13.2 Memory Mapping and BAR Configuration Errors](#132-memory-mapping-and-bar-configuration-errors) - [13.3 DMA Performance and TLP Errors](#133-dma-performance-and-tlp-errors) 14. [Emulation Accuracy and Optimizations](#14-emulation-accuracy-and-optimizations) - [14.1 Techniques for Accurate Timing Emulation](#141-techniques-for-accurate-timing-emulation) - [14.2 Dynamic Response to System Calls](#142-dynamic-response-to-system-calls) 15. [Best Practices for Firmware Development](#15-best-practices-for-firmware-development) - [15.1 Continuous Testing and Documentation](#151-continuous-testing-and-documentation) - [15.2 Managing Firmware Versioning](#152-managing-firmware-versioning) - [15.3 Security Considerations](#153-security-considerations) 16. [Additional Resources](#16-additional-resources) 17. [Contact Information](#17-contact-information) 18. [Support and Contributions](#18-support-and-contributions) --- ## **Part 1: Foundational Concepts** --- ## **1. Introduction** ### **1.1 Purpose of the Guide** The primary purpose of this guide is to provide a step-by-step approach to developing custom Direct Memory Access (DMA) firmware for FPGA-based devices to emulate PCIe hardware accurately. This enables applications such as hardware testing, system debugging, security research, and hardware emulation. By following this guide, you will learn how to: - Gather necessary information from a donor device. - Customize firmware to emulate a specific hardware device. - Set up the development environment using tools like Vivado and Visual Studio Code. - Understand key concepts related to PCIe and DMA operations. ### **1.2 Target Audience** This guide is intended for: - **Firmware Developers**: Engineers interested in creating custom firmware for hardware emulation, testing, or bypassing hardware restrictions. - **Hardware Engineers**: Professionals working on hardware testing and development who need to emulate specific devices. - **Security Researchers**: Individuals conducting vulnerability assessments, malware analysis, or security testing requiring hardware emulation. - **FPGA Enthusiasts**: Hobbyists and learners interested in FPGA customization and low-level hardware emulation. ### **1.3 How to Use This Guide** The guide is divided into three parts: - **Part 1: Foundational Concepts**: Covers the basic concepts, setup, and initial steps required to start firmware development for device emulation. - **Part 2: Intermediate Concepts and Implementation**: Delves into more complex topics such as advanced firmware customization, TLP emulation, and initial debugging techniques. - **Part 3: Advanced Techniques and Optimization**: Explores advanced debugging, troubleshooting, optimization strategies, and best practices. It is recommended to follow the guide sequentially to build a solid understanding before tackling advanced topics. --- ## **2. Key Definitions** Understanding the terminology is crucial for effectively following this guide. Below are key definitions related to PCIe, DMA, and device emulation: - **DMA (Direct Memory Access)**: A capability that allows hardware devices to read from or write to system memory directly, without CPU intervention, enabling high-speed data transfers. - **TLP (Transaction Layer Packet)**: The fundamental unit of communication in the PCIe architecture, encapsulating control and data information. - **BAR (Base Address Register)**: Registers in PCIe devices that define memory and I/O address regions, mapping device memory into the system memory space. - **FPGA (Field-Programmable Gate Array)**: A reconfigurable integrated circuit that can be programmed to perform specific hardware functions. - **MSI/MSI-X (Message Signaled Interrupts)**: Mechanisms used by PCIe devices to send interrupts to the CPU without using traditional interrupt lines. - **Device Serial Number (DSN)**: A unique identifier associated with a specific device, often used for advanced device identification. - **PCIe Configuration Space**: A standardized memory area where PCIe devices provide information about themselves and configure operational parameters. - **Donor Device**: A PCIe hardware device used to extract configuration and identification details for the purpose of emulating its behavior on an FPGA. --- ## **3. Device Compatibility** ### **3.1 Supported FPGA-Based Hardware** While this guide focuses on the **Squirrel DMA (35T)** card due to its accessibility, the methodologies are adaptable to other FPGA-based DMA hardware: - **Squirrel (35T)** - **Description**: Affordable FPGA-based DMA device suitable for standard memory acquisition and device emulation. - **Enigma-X1 (75T)** - **Description**: Mid-tier FPGA offering enhanced resources, ideal for more demanding memory operations. - **ZDMA (100T)** - **Description**: High-performance FPGA optimized for rapid memory interactions, suitable for extensive memory reads/writes. - **Kintex-7** - **Description**: Advanced FPGA with robust capabilities for complex projects and large-scale DMA solutions. ### **3.2 PCIe Hardware Considerations** To ensure smooth emulation, several PCIe-specific features must be addressed: - **IOMMU/VT-d Settings** - **Recommendation**: Disable IOMMU (Intel's VT-d) or AMD's equivalent to allow unrestricted DMA access. - **Rationale**: IOMMU can restrict DMA operations, potentially interfering with memory acquisition and emulation. - **Kernel DMA Protection** - **Recommendation**: Disable Kernel DMA Protection features in modern systems. - **Steps**: - **Windows**: Disable features like Secure Boot or Virtualization-Based Security (VBS) in BIOS/UEFI settings. - **Caution**: Disabling these features can expose the system to security risks; ensure you're operating in a secure environment. - **PCIe Slot Requirements** - **Recommendation**: Use a compatible PCIe slot that matches the FPGA device's requirements (e.g., x1, x4). - **Rationale**: Ensures optimal performance and compatibility with the host system. ### **3.3 System Requirements** - **Host System** - **Processor**: Multi-core CPU (Intel i5/i7 or AMD equivalent) - **Memory**: Minimum 16 GB RAM - **Storage**: SSD with at least 100 GB free space - **Operating System**: Windows 10/11 (64-bit) or compatible Linux distribution - **Peripheral Devices** - **JTAG Programmer**: For flashing firmware onto the FPGA - **PCIe Slot**: Ensure the host system has an available PCIe slot compatible with the DMA card --- ## **4. Requirements** ### **4.1 Hardware** - **Donor PCIe Device** - **Purpose**: Source of device IDs and configuration data for emulation. - **Examples**: Network adapters, storage controllers, or any generic PCIe card not in use. - **DMA FPGA Card** - **Description**: FPGA-based device capable of performing DMA operations. - **Examples**: Squirrel (35T), Enigma-X1 (75T), ZDMA (100T), Kintex-7 - **JTAG Programmer** - **Purpose**: For flashing firmware onto the FPGA. - **Examples**: Xilinx Platform Cable USB II, Digilent JTAG-HS3 ### **4.2 Software** - **Xilinx Vivado Design Suite** - **Description**: FPGA development software for synthesizing and building firmware projects. - **Download**: [Xilinx Vivado](https://www.xilinx.com/support/download.html) - **Visual Studio Code** - **Description**: Code editor for editing Verilog or VHDL code. - **Download**: [Visual Studio Code](https://code.visualstudio.com/) - **PCILeech-FPGA** - **Description**: Repository and base code for DMA firmware development. - **Repository**: [PCILeech-FPGA on GitHub](https://github.com/ufrisk/pcileech-fpga) - **Arbor** - **Description**: PCIe device scanning tool for gathering device information. - **Download**: [Arbor by MindShare](https://www.mindshare.com/software/Arbor) - **Note**: Requires account creation; offers a 14-day trial. - **Alternative Tools** - **Telescan PE** - **Description**: PCIe traffic analysis tool as an alternative to Arbor. - **Download**: [Teledyne LeCroy Telescan PE](https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software) - **Note**: Free but requires manual registration approval. ### **4.3 Environment Setup** #### **4.3.1 Install Xilinx Vivado Design Suite** - **Steps**: 1. Visit the [Xilinx Vivado Download Page](https://www.xilinx.com/support/download.html). 2. Download the appropriate version compatible with your FPGA device. 3. Run the installer and follow the on-screen instructions. 4. Select necessary components during installation. 5. Launch Vivado to ensure proper installation. #### **4.3.2 Install Visual Studio Code** - **Steps**: 1. Visit the [Visual Studio Code Download Page](https://code.visualstudio.com/). 2. Download and install for your operating system. 3. Install extensions for Verilog or VHDL support (e.g., **Verilog-HDL/SystemVerilog**). #### **4.3.3 Clone the PCILeech-FPGA Repository** - **Steps**: 1. Open a terminal or command prompt. 2. Navigate to your desired directory: ```bash cd ~/Projects/ ``` 3. Clone the repository: ```bash git clone https://github.com/ufrisk/pcileech-fpga.git ``` 4. Navigate to the cloned directory: ```bash cd pcileech-fpga ``` #### **4.3.4 Set Up a Clean Development Environment** - **Recommendation**: Work in an isolated environment to prevent unintended interactions. - **Steps**: 1. Use a dedicated development machine or virtual machine. 2. Ensure no other applications interfere with PCIe operations or FPGA programming. --- ## **5. Gathering Donor Device Information** Accurate device emulation hinges on meticulously extracting and replicating critical information from the donor device. This comprehensive data collection enables your FPGA to faithfully mimic the target hardware's PCIe configuration and behavior, ensuring compatibility and functionality when interfacing with the host system. ### **5.1 Using Arbor for PCIe Device Scanning** **Arbor** is a robust and user-friendly tool designed for in-depth scanning of PCIe devices. It provides detailed insights into the configuration space of connected hardware, making it an invaluable resource for extracting the necessary information for device emulation. #### **5.1.1 Install Arbor** To begin utilizing Arbor for device scanning, you must first install the software on your system. **Steps:** 1. **Visit the Arbor Download Page:** - Navigate to the official [Arbor Download Page](https://www.mindshare.com/software/Arbor) using your preferred web browser. - Ensure you are accessing the site directly to avoid any malicious redirects. 2. **Create an Account (if required):** - Arbor may require you to create a user account to access the download links. - Provide the necessary information, such as your name, email address, and organization. - Verify your email if prompted, to activate your account. 3. **Download Arbor:** - Once logged in, locate the download section for Arbor. - Select the version compatible with your operating system (e.g., Windows 10/11 64-bit). - Click the **Download** button and save the installer to a known location on your computer. 4. **Install Arbor:** - Locate the downloaded installer file (e.g., `ArborSetup.exe`). - Right-click the installer and select **Run as administrator** to ensure it has the necessary permissions. - Follow the on-screen instructions to complete the installation process. - Accept the license agreement. - Choose the installation directory. - Opt to create desktop shortcuts if desired. 5. **Verify Installation:** - Upon completion, ensure that Arbor is listed in your Start Menu or on your desktop. - Launch Arbor to confirm it opens without errors. #### **5.1.2 Scan PCIe Devices** With Arbor installed, you can proceed to scan your system for connected PCIe devices. **Steps:** 1. **Launch Arbor:** - Double-click the Arbor icon on your desktop or find it via the Start Menu. - If prompted by User Account Control (UAC), allow the application to make changes to your device. 2. **Navigate to the Local System Tab:** - In the Arbor interface, locate the navigation pane or tabs. - Click on **Local System** to access tools for scanning the local machine. 3. **Scan for PCIe Devices:** - Look for a **Scan** or **Rescan** button, typically located at the top or bottom of the interface. - Click **Scan/Rescan** to initiate the detection process. - Wait for the scanning process to complete; this may take a few moments depending on the number of devices connected. 4. **Review Detected Devices:** - Once the scan is complete, Arbor will display a list of all detected PCIe devices. - The devices are usually listed with their names, device IDs, and other identifying information. #### **5.1.3 Identify the Donor Device** Identifying the correct donor device is crucial for accurate emulation. **Steps:** 1. **Locate Your Donor Device in the List:** - Scroll through the list of devices detected by Arbor. - Look for the device matching the make and model of your donor hardware. - Devices may be listed by their vendor names, device types, or function. 2. **Verify Device Details:** - Click on the device to select it. - Confirm that the **Device ID** and **Vendor ID** match those of your donor device. - **Tip:** These IDs are typically found in the device's documentation or on the manufacturer's website. 3. **View Detailed Configuration:** - With the device selected, find and click on an option like **View Details** or **Properties**. - This will open a detailed view showing the device's configuration space and capabilities. 4. **Cross-Reference with Physical Hardware:** - If multiple similar devices are listed, cross-reference the **Slot Number** or **Bus Address** with the physical slot where the donor device is installed. #### **5.1.4 Capture Device Data** Extracting detailed information from the donor device is essential for accurate emulation. **Information to Extract:** - **Device ID (0xXXXX):** - A 16-bit identifier unique to the device model. - **Vendor ID (0xYYYY):** - A 16-bit identifier assigned to the manufacturer. - **Subsystem ID (0xZZZZ):** - Identifies the specific subsystem or variant. - **Subsystem Vendor ID (0xWWWW):** - Identifies the vendor of the subsystem. - **Revision ID (0xRR):** - Indicates the revision level of the device. - **Class Code (0xCCCCCC):** - A 24-bit code that defines the type of device (e.g., network controller, storage device). - **Base Address Registers (BARs):** - Registers defining the memory or I/O space the device uses. - Includes BAR0 through BAR5, each potentially 32 or 64 bits. - **Capabilities:** - Lists supported features such as MSI/MSI-X, power management, PCIe link speed, and width. - **Device Serial Number (DSN):** - A 64-bit unique identifier, if the device supports it. **Steps:** 1. **Navigate to the PCI Config Tab:** - Within the device's detailed view, find and select the **PCI Config** or **Configuration Space** tab. 2. **Record Relevant Details:** - Carefully document each of the required fields. - Use screenshots or copy the values into a text file or spreadsheet for accuracy. - Ensure hexadecimal values are noted correctly, including the `0x` prefix if used. 3. **Expand Capability Lists:** - Look for sections labeled **Capabilities** or **Advanced Features**. - Document each capability and its parameters (e.g., MSI count, power states supported). 4. **Examine BARs in Detail:** - For each BAR, note: - **BAR Number (e.g., BAR0):** - **Type (Memory or I/O):** - **Bit Width (32-bit or 64-bit):** - **Size (e.g., 256 MB):** - **Prefetchable Status (Yes/No):** 5. **Save the Data for Reference:** - Compile all the information into a well-organized document. - Label each section clearly for easy reference during firmware customization. 6. **Double-Check Entries:** - Review all recorded data to ensure accuracy. - Correct any discrepancies by revisiting the Arbor interface. ### **5.2 Extracting and Recording Device Attributes** After capturing the data, it's crucial to understand the significance of each attribute and ensure they've been accurately documented. **Ensure You Have Accurately Recorded the Following:** 1. **Device ID:** - **Purpose:** Uniquely identifies the device model. - **Usage:** Essential for the host OS to load the correct driver. 2. **Vendor ID:** - **Purpose:** Identifies the manufacturer. - **Usage:** Used in conjunction with Device ID to match device drivers. 3. **Subsystem ID and Subsystem Vendor ID:** - **Purpose:** Specifies the subsystem's device and vendor IDs, allowing for differentiation between variants. - **Usage:** Important for devices with multiple configurations or OEM-specific versions. 4. **Revision ID:** - **Purpose:** Indicates the hardware revision. - **Usage:** Helps in identifying specific hardware versions that may require different drivers or firmware. 5. **Class Code:** - **Purpose:** Categorizes the device type (e.g., mass storage, network controller). - **Usage:** Allows the OS to understand the device's general function. 6. **Base Address Registers (BARs):** - **Purpose:** Define the memory or I/O address regions that the device will use. - **Usage:** Critical for mapping device memory into the system address space. 7. **Capabilities:** - **Purpose:** Lists the advanced features the device supports. - **Examples:** - **MSI/MSI-X:** Message Signaled Interrupts for efficient interrupt handling. - **Power Management:** States like D0, D1, D2, D3hot, D3cold. - **PCIe Link Speed/Width:** Determines the data transfer capabilities. 8. **Device Serial Number (DSN):** - **Purpose:** A unique 64-bit identifier for the device. - **Usage:** Used for advanced identification and may be required by some drivers. **Best Practices:** - **Organize the Data:** - Create a structured document or spreadsheet. - Use clear headings and subheadings for each attribute. - **Include Units and Formats:** - Indicate units for sizes (e.g., MB, KB). - Use consistent formatting for hexadecimal values (e.g., `0x1234`). - **Cross-Reference with Specifications:** - If available, consult the device's datasheet to verify values. - This can help identify any discrepancies or unusual configurations. - **Secure the Data:** - Store the collected information securely. - Be mindful of any proprietary or confidential information. --- ## **6. Initial Firmware Customization** With the donor device's information meticulously documented, the next phase involves customizing your FPGA's firmware to emulate the donor device accurately. This involves modifying the PCIe configuration space and ensuring that memory mappings align correctly. ### **6.1 Modifying Configuration Space** The PCIe configuration space is a critical component that defines how the device is recognized and interacts with the host system. Customizing this space to match the donor device is essential for successful emulation. #### **6.1.1 Navigate to the Configuration File** The configuration space is defined within a specific SystemVerilog (.sv) file in your project. **Path:** - **Standard Path:** ``` pcileech-fpga/pcileech-wifi-main/src/pcie_7x_0_core_top.v ``` - **Alternative Path (Depending on Directory Structure):** ``` src\pcie_7x\pcie_7x_0_core_top.v ``` #### **6.1.2 Open the File in Visual Studio Code** Editing the configuration file requires a suitable code editor that supports syntax highlighting for SystemVerilog. **Steps:** 1. **Launch Visual Studio Code:** - Click on the VS Code icon or find it via the Start Menu. 2. **Open the File:** - Use **File > Open File** or press `Ctrl + O`. - Navigate to the configuration file path mentioned above. - Select `pcileech_pcie_cfg_a7.sv` and click **Open**. 3. **Verify Syntax Highlighting:** - Ensure that the editor recognizes the `.sv` file extension. - If necessary, install extensions for SystemVerilog support. 4. **Familiarize Yourself with the File Structure:** - Scroll through the file to understand the existing assignments and comments. - Look for sections where configuration registers are defined. #### **6.1.3 Modify Device ID and Vendor ID** Updating these identifiers is crucial for the host system to recognize the emulated device as the donor. **Steps:** 1. **Search for `cfg_deviceid`:** - Use the search functionality (`Ctrl + F`). - Locate the line defining `cfg_deviceid`. 2. **Update Device ID:** ```verilog cfg_deviceid <= 16'hXXXX; // Replace XXXX with the donor's Device ID ``` - **Example:** - If the donor's Device ID is `0x1234`, update as: ```verilog cfg_deviceid <= 16'h1234; ``` 3. **Search for `cfg_vendorid`:** - Locate the line defining `cfg_vendorid`. 4. **Update Vendor ID:** ```verilog cfg_vendorid <= 16'hYYYY; // Replace YYYY with the donor's Vendor ID ``` - **Example:** - If the donor's Vendor ID is `0xABCD`, update as: ```verilog cfg_vendorid <= 16'hABCD; ``` 5. **Ensure Correct Formatting:** - Verify that hexadecimal values are prefixed with `16'h`. - Maintain consistent indentation and commenting style. #### **6.1.4 Modify Subsystem ID and Revision ID** These identifiers provide additional details about the device variant and hardware revision. **Steps:** 1. **Search for `cfg_subsysid`:** - Locate the line defining `cfg_subsysid`. 2. **Update Subsystem ID:** ```verilog cfg_subsysid <= 16'hZZZZ; // Replace ZZZZ with the donor's Subsystem ID ``` - **Example:** - If the donor's Subsystem ID is `0x5678`, update as: ```verilog cfg_subsysid <= 16'h5678; ``` 3. **Search for `cfg_subsysvendorid`:** - Locate the line defining `cfg_subsysvendorid`. 4. **Update Subsystem Vendor ID (if applicable):** ```verilog cfg_subsysvendorid <= 16'hWWWW; // Replace WWWW with the donor's Subsystem Vendor ID ``` - **Example:** - If the donor's Subsystem Vendor ID is `0x9ABC`, update as: ```verilog cfg_subsysvendorid <= 16'h9ABC; ``` 5. **Search for `cfg_revisionid`:** - Locate the line defining `cfg_revisionid`. 6. **Update Revision ID:** ```verilog cfg_revisionid <= 8'hRR; // Replace RR with the donor's Revision ID ``` - **Example:** - If the donor's Revision ID is `0x01`, update as: ```verilog cfg_revisionid <= 8'h01; ``` #### **6.1.5 Update Class Code** The Class Code informs the host of the device type and function. **Steps:** 1. **Search for `cfg_classcode`:** - Locate the line defining `cfg_classcode`. 2. **Update Class Code:** ```verilog cfg_classcode <= 24'hCCCCCC; // Replace CCCCCC with the donor's Class Code ``` - **Example:** - If the donor's Class Code is `0x020000` (Ethernet Controller), update as: ```verilog cfg_classcode <= 24'h020000; ``` 3. **Verify Correct Bit Width:** - Ensure that the Class Code is a 24-bit value. - Hexadecimal values should be prefixed with `24'h`. #### **6.1.6 Save Changes** After making all modifications, it's important to save and review the changes. **Steps:** 1. **Save the File:** - Click **File > Save** or press `Ctrl + S`. 2. **Review Changes:** - Re-read the modified lines to confirm accuracy. - Check for any syntax errors or typos. 3. **Optional - Use Version Control:** - If using Git or another version control system, commit your changes with a meaningful message. - **Example:** ``` git add pcileech_pcie_cfg_a7.sv git commit -m "Updated PCIe configuration with donor device identifiers" ``` ### **6.2 Inserting the Device Serial Number (DSN)** The Device Serial Number (DSN) is a unique identifier that some devices utilize for advanced features. Including it enhances the authenticity of the emulation. #### **6.2.1 Locate the DSN Field** The DSN is typically defined in the same configuration file. **Steps:** 1. **Search for `cfg_dsn`:** - In `pcileech_pcie_cfg_a7.sv`, use the search function (`Ctrl + F`) to find `cfg_dsn`. 2. **Understand the Existing Assignment:** - The DSN may be set to a default value or zeroed out. ```verilog cfg_dsn <= 64'h0000000000000000; // Default DSN ``` #### **6.2.2 Insert the DSN** Updating the DSN involves setting it to the exact value from the donor device. **Steps:** 1. **Update `cfg_dsn`:** ```verilog cfg_dsn <= 64'hXXXXXXXX_YYYYYYYY; // Replace with donor DSN ``` - **Example:** - If the donor's DSN is `0x0011223344556677`, update as: ```verilog cfg_dsn <= 64'h0011223344556677; ``` 2. **Handle DSN Unavailability:** - If the donor device does not have a DSN or it is not required, set it to zero: ```verilog cfg_dsn <= 64'h0000000000000000; // No DSN ``` 3. **Ensure Correct Formatting:** - The DSN is a 64-bit value; ensure it's properly formatted. - Use the `64'h` prefix for hexadecimal values. 4. **Add Comments for Clarity:** - Include a comment indicating the DSN source. ```verilog cfg_dsn <= 64'h0011223344556677; // Donor DSN ``` #### **6.2.3 Save Changes** Finalize the modifications by saving and reviewing. **Steps:** 1. **Save the File:** - Click **File > Save** or press `Ctrl + S`. 2. **Verify the Syntax:** - Look for any red underlines or error indications in the editor. - Correct any issues before proceeding. 3. **Document the Changes:** - If using version control, commit the updates with an appropriate message. - **Example:** ``` git commit -am "Inserted donor Device Serial Number (DSN) into configuration" ``` --- ## **7. Vivado Project Setup and Customization** With the firmware files updated to reflect the donor device's configuration, the next step is to integrate these changes into the Vivado project. This involves generating the project files, customizing IP cores, and preparing the design for synthesis and implementation. ### **7.1 Generating Vivado Project Files** Vivado uses Tcl scripts to automate project creation and configuration. By running these scripts, you ensure that all settings are correctly applied based on your FPGA device. #### **7.1.1 Open Vivado** Starting with a fresh session of Vivado ensures that previous settings or projects do not interfere with your current work. **Steps:** 1. **Launch Vivado:** - Find the Vivado application in your Start Menu or desktop. - Click to open it. 2. **Select the Correct Version:** - If multiple versions are installed, ensure you are using the one compatible with your FPGA (e.g., Vivado 2020.1). 3. **Wait for the Startup Screen:** - Allow Vivado to fully initialize before proceeding. #### **7.1.2 Access the Tcl Console** The Tcl Console allows you to execute scripts and commands directly. **Steps:** 1. **Open the Tcl Console:** - In the Vivado interface, go to the menu bar. - Click on **Window** > **Tcl Console**. - The Tcl Console will appear at the bottom of the window. 2. **Adjust Console Size (Optional):** - Drag the console's top border to resize it for better visibility. 3. **Clear Previous Commands:** - If any commands are present, you can clear them for a clean start. #### **7.1.3 Navigate to the Project Directory** Ensure that the Tcl Console is pointing to the correct directory where your project scripts are located. **For Squirrel DMA (35T):** **Path:** - Your project directory, typically: ``` C:/Users/YourUsername/Documents/pcileech-fpga/pcileech-wifi-main/ ``` **Steps:** 1. **Set the Working Directory:** - In the Tcl Console, enter: ```tcl cd C:/Users/YourUsername/Documents/pcileech-fpga/pcileech-wifi-main/ ``` - Replace the path with the actual location on your system. 2. **Verify the Directory Change:** - Enter `pwd` in the Tcl Console. - The console should display the current directory, confirming the change. #### **7.1.4 Generate the Vivado Project** Running the appropriate Tcl script will set up the project with all necessary configurations. **Steps:** 1. **Run the Tcl Script:** - For **Squirrel (35T)**: ```tcl source vivado_generate_project_squirrel.tcl -notrace ``` - For **Enigma-X1 (75T)**: ```tcl source vivado_generate_project_enigma_x1.tcl -notrace ``` - For **ZDMA (100T)**: ```tcl source vivado_generate_project_100t.tcl -notrace ``` 2. **Wait for Script Completion:** - The script will execute several commands: - Create the project. - Add source files. - Configure project settings. - Monitor the Tcl Console for progress messages. - Address any errors that may occur, such as missing files or incorrect paths. 3. **Confirm Project Generation:** - Upon completion, the console will indicate that the project has been created. - The project files (`.xpr` and associated directories) will be present in the project directory. #### **7.1.5 Open the Generated Project** Now that the project is generated, you can open it within Vivado for further customization. **Steps:** 1. **Open the Project:** - In Vivado, click **File** > **Open Project**. - Navigate to your project directory. 2. **Select the Project File:** - For **Squirrel**: ``` pcileech_squirrel_top.xpr ``` - Click on the `.xpr` file to select it. 3. **Click Open:** - Vivado will load the project, displaying the design hierarchy and sources. 4. **Verify Project Contents:** - In the **Project Manager** window, ensure that all source files are listed. - Check for any warnings or errors upon opening. ### **7.2 Modifying IP Blocks** The PCIe IP core is a critical component that must be configured to match the donor device's specifications. Customizing the IP core ensures that the FPGA behaves identically to the donor hardware at the PCIe protocol level. #### **7.2.1 Access the PCIe IP Core** The PCIe IP core is an instantiated IP block within your Vivado project. **Steps:** 1. **Locate the PCIe IP Core:** - In the **Sources** pane, ensure the **Hierarchy** tab is selected. - Expand the design hierarchy to find the PCIe IP core. - It is typically named `pcie_7x_0.xci` or similar. 2. **Open the IP Customization Window:** - Right-click on `pcie_7x_0.xci`. - Select **Customize IP** from the context menu. - The **IP Configuration** window will open. 3. **Wait for IP Settings to Load:** - The IP customization interface may take a few moments to initialize. - Ensure that all options and tabs are fully loaded before proceeding. #### **7.2.2 Customize Device IDs and BARs** Configuring the device identifiers within the IP core is crucial for correct enumeration by the host system. **Steps:** 1. **Navigate to Device and Vendor Identifiers:** - In the IP customization window, select the **Device and Vendor Identifiers** tab or section. 2. **Enter the Device ID:** - Find the field labeled **Device ID**. - Enter the donor's Device ID (e.g., `0x1234`). 3. **Enter the Vendor ID:** - Locate the **Vendor ID** field. - Input the donor's Vendor ID (e.g., `0xABCD`). 4. **Enter the Subsystem ID and Subsystem Vendor ID:** - Input the **Subsystem ID** (e.g., `0x5678`). - Input the **Subsystem Vendor ID** (e.g., `0x9ABC`). 5. **Set the Revision ID:** - Enter the **Revision ID** (e.g., `0x01`). 6. **Set the Class Code:** - Enter the **Class Code** (e.g., `0x020000` for Ethernet Controller). 7. **Configure Other Identifiers (if available):** - Some IP cores allow setting **Programming Interface**, **Device Capabilities**, etc. - Match these to the donor device as needed. #### **7.2.3 Configure BAR Sizes** The BARs define how the device maps its internal memory and registers to the host system. **Steps:** 1. **Navigate to Base Address Registers (BARs):** - Select the **BARs** tab or section in the IP customization window. 2. **Configure Each BAR:** - For **BAR0** to **BAR5**, set the following parameters based on the donor device: - **Enable BAR**: Check or uncheck to match donor device. - **BAR Size**: Select the size from the dropdown (e.g., **256 MB**, **64 KB**). - **BAR Type**: - **Memory (32-bit Addressing)** - **Memory (64-bit Addressing)** - **I/O** - **Prefetchable**: Check if the donor's BAR is prefetchable. 3. **Example Configuration:** - **BAR0**: - Enabled - Size: **256 MB** - Type: **Memory (64-bit)** - Prefetchable: **Yes** - **BAR1**: - Disabled (if the donor device does not use BAR1) 4. **Ensure Alignment and Non-Overlapping Spaces:** - Verify that the total memory mapped does not exceed the FPGA's capabilities. - Ensure that BAR sizes align with PCIe specification requirements. 5. **Advanced Settings (if applicable):** - Some devices may have special requirements, such as expansion ROM BAR. - Configure these settings if necessary. #### **7.2.4 Finalize IP Customization** After configuring all necessary settings, you need to apply the changes. **Steps:** 1. **Review All Settings:** - Go through each tab in the IP customization window. - Confirm that all entries match the donor device's specifications. 2. **Apply Changes:** - Click **OK** or **Generate** to apply the settings. - If prompted, confirm that you wish to proceed with the changes. 3. **Regenerate IP Core:** - Vivado will regenerate the IP core to reflect the new configurations. - Monitor the **Messages** pane for any errors or warnings. 4. **Update IP in Project:** - Ensure that the updated IP core is correctly integrated into your project. - Vivado may prompt to update IP dependencies; allow it to do so. #### **7.2.5 Lock the IP Core** Locking the IP core prevents unintended changes during synthesis and implementation. **Purpose:** - **Prevent Overwrites:** Ensures that your manual configurations are preserved. - **Maintain Consistency:** Keeps the IP core in a known state throughout the build process. **Steps:** 1. **Open the Tcl Console:** - In Vivado, if not already open, go to **Window** > **Tcl Console**. 2. **Execute the Lock Command:** - Enter the following command: ```tcl set_property -name {IP_LOCKED} -value true -objects [get_ips pcie_7x_0] ``` - Press **Enter** to execute. 3. **Verify the Lock:** - Check the **Messages** pane for confirmation. - The IP core should now be marked as locked. 4. **Unlocking (if necessary):** - To make further changes in the future, you can unlock the IP core: ```tcl set_property -name {IP_LOCKED} -value false -objects [get_ips pcie_7x_0] ``` - Remember to re-lock it after making changes. 5. **Document the Action:** - Note in your project documentation that the IP core has been locked. - This helps team members understand the project's configuration state. --- ## **Part 2: Intermediate Concepts and Implementation** --- ## **8. Advanced Firmware Customization** To achieve a precise emulation of the donor device, further in-depth customization of the firmware is necessary. This involves aligning the PCIe parameters, adjusting Base Address Registers (BARs), and emulating power management and interrupt mechanisms to match the donor device's specifications. These steps ensure that the emulated device interacts seamlessly with the host system and behaves identically to the original hardware. ### **8.1 Configuring PCIe Parameters for Emulation** Accurate emulation requires that the PCIe parameters of your FPGA device are meticulously configured to match those of the donor device. This includes settings such as the PCIe link speed, link width, capability pointers, and maximum payload sizes. Proper configuration ensures compatibility with the host system and the correct operation of drivers and applications that interact with the device. #### **8.1.1 Matching PCIe Link Speed and Width** The PCIe link speed and width are critical parameters that determine the data throughput and performance of the device. Matching these settings with the donor device is essential for accurate emulation. **Steps:** 1. **Access PCIe IP Core Settings:** - **Open Your Vivado Project:** - Launch Vivado and open the project you previously created or modified. - Ensure that all source files are correctly added to the project. - **Locate the PCIe IP Core:** - In the **Sources** pane, expand the hierarchy to find the PCIe IP core instance, typically named `pcie_7x_0`. - The file associated with the IP core is usually `pcie_7x_0.xci`. - **Customize the IP Core:** - Right-click on `pcie_7x_0.xci` and select **Customize IP**. - The IP customization window will open, displaying various configuration options. 2. **Set Maximum Link Speed:** - **Navigate to Link Parameters:** - In the IP customization window, click on the **Link Parameters** tab or section. - This section contains settings related to the PCIe link's characteristics. - **Configure Maximum Link Speed:** - Find the **Maximum Link Speed** option. - Set it to match the donor device's link speed. - **Example:** - If the donor device operates at **Gen2 (5.0 GT/s)**, select **5.0 GT/s**. - If it operates at **Gen1 (2.5 GT/s)** or **Gen3 (8.0 GT/s)**, select the corresponding option. - **Note:** Ensure that your FPGA and the physical hardware support the selected link speed. 3. **Set Link Width:** - **Configure Link Width:** - In the same **Link Parameters** section, locate the **Link Width** setting. - Set it to match the donor device's link width. - **Example:** - If the donor device uses a **x4** link, set the **Link Width** to **4**. - Options typically include **1**, **2**, **4**, **8**, **16** lanes. - **Note:** The physical connectors and the FPGA must support the selected link width. 4. **Save and Regenerate:** - **Apply Changes:** - After configuring the link speed and width, click **OK** to apply the changes. - Vivado may prompt you to regenerate the IP core due to the changes made. - Confirm and allow the regeneration process to complete. - **Verify Settings:** - Once regeneration is complete, revisit the IP core settings to ensure the configurations are correctly applied. - Check for any warnings or errors in the **Messages** window. #### **8.1.2 Setting Capability Pointers** Capability pointers in the PCIe configuration space point to various capability structures, such as MSI, power management, and others. Correctly setting these pointers ensures that the host system can locate and utilize the device's capabilities. **Steps:** 1. **Locate Capability Pointer in Firmware:** - **Open Configuration File:** - In Visual Studio Code, open the `pcileech_pcie_cfg_a7.sv` file located at: ``` pcileech-fpga/pcileech-wifi-main/src/pcileech_pcie_cfg_a7.sv ``` - **Understand the Capability Pointer:** - The capability pointer is an 8-bit register that points to the first capability structure in the PCIe configuration space, usually starting after the standard configuration header. 2. **Set Capability Pointer Value:** - **Find the Assignment for `cfg_cap_pointer`:** - Search for the line in the code where `cfg_cap_pointer` is assigned. ```verilog cfg_cap_pointer <= 8'hXX; // Current value ``` - **Update the Capability Pointer:** - Replace `XX` with the donor device's capability pointer value. - **Example:** - If the donor device's capability pointer is `0x60`, update the line to: ```verilog cfg_cap_pointer <= 8'h60; // Updated to match donor device ``` - **Ensure Correct Alignment:** - Capability structures must be aligned on a 4-byte boundary. - The capability pointer should point to a valid offset within the configuration space. 3. **Save Changes:** - **Save the Configuration File:** - After making the changes, save the file by clicking **File > Save** or pressing `Ctrl + S`. - **Verify Syntax:** - Ensure there are no syntax errors introduced by the changes. - **Comment for Clarity:** - Add a comment explaining the change for future reference. ```verilog cfg_cap_pointer <= 8'h60; // Set to donor's capability pointer at offset 0x60 ``` #### **8.1.3 Adjusting Maximum Payload and Read Request Sizes** These parameters define the maximum amount of data that can be transferred in a single PCIe transaction. Matching these settings with the donor device ensures compatibility and optimal performance. **Steps:** 1. **Set Maximum Payload Size:** - **Access Device Capabilities:** - In the PCIe IP core customization window, navigate to the **Device Capabilities** or **Capabilities** tab. - **Configure Max Payload Size Supported:** - Find the **Max Payload Size Supported** setting. - Set it to the value supported by the donor device. - **Options:** - **128 bytes**, **256 bytes**, **512 bytes**, **1024 bytes**, **2048 bytes**, **4096 bytes**. - **Example:** - If the donor device supports a maximum payload size of **256 bytes**, select **256 bytes**. 2. **Set Maximum Read Request Size:** - **Configure Max Read Request Size Supported:** - In the same tab, find the **Max Read Request Size Supported** setting. - Set it to match the donor device's capability. - **Example:** - If the donor supports a maximum read request size of **512 bytes**, select **512 bytes**. 3. **Adjust Firmware Parameters:** - **Open `pcileech_pcie_cfg_a7.sv`:** - Ensure that the configuration file is open in Visual Studio Code. - **Update Firmware Constants:** - Locate the lines where `max_payload_size_supported` and `max_read_request_size_supported` are defined. ```verilog max_payload_size_supported <= 3'bZZZ; // Current value max_read_request_size_supported <= 3'bWWW; // Current value ``` - **Set the Appropriate Values:** - Replace `ZZZ` and `WWW` with the binary representations of the sizes. - **Mapping:** - **128 bytes**: `3'b000` - **256 bytes**: `3'b001` - **512 bytes**: `3'b010` - **1024 bytes**: `3'b011` - **2048 bytes**: `3'b100` - **4096 bytes**: `3'b101` - **Example:** - For **256 bytes** payload size: ```verilog max_payload_size_supported <= 3'b001; // Supports up to 256 bytes ``` - For **512 bytes** read request size: ```verilog max_read_request_size_supported <= 3'b010; // Supports up to 512 bytes ``` 4. **Save Changes:** - **Save the File:** - After updating the values, save the file. - **Verify Consistency:** - Ensure that the values in the firmware match those configured in the PCIe IP core. - **Add Comments:** - Document the changes for future reference. ```verilog max_payload_size_supported <= 3'b001; // 256 bytes as per donor device max_read_request_size_supported <= 3'b010; // 512 bytes as per donor device ``` ### **8.2 Adjusting BARs and Memory Mapping** Base Address Registers (BARs) define the memory regions that the device exposes to the host. Correctly configuring the BARs and memory mapping is crucial for accurate emulation and proper operation of device drivers. #### **8.2.1 Setting BAR Sizes** Configuring the BAR sizes ensures that the device requests the correct amount of address space during enumeration and that the host maps these regions appropriately. **Steps:** 1. **Access BAR Configuration:** - **Customize PCIe IP Core:** - In Vivado, right-click on `pcie_7x_0.xci` and select **Customize IP**. - **Navigate to BARs Tab:** - In the IP customization window, click on the **Base Address Registers (BARs)** tab. 2. **Configure BAR Sizes and Types:** - **Match Donor Device's BARs:** - For each BAR (BAR0 to BAR5), set the size and type to match the donor device. - **Set BAR Sizes:** - Select the appropriate size from the dropdown for each BAR. - **Example:** - If **BAR0** is **64 KB**, set **BAR0 Size** to **64 KB**. - If **BAR1** is **128 MB**, set **BAR1 Size** to **128 MB**. - **Set BAR Types:** - Choose between **32-bit** or **64-bit** addressing for each BAR. - Specify if the BAR is of type **Memory** or **I/O**. - Set **Prefetchable** status based on the donor device. - **Enable or Disable BARs:** - Ensure that only the BARs used by the donor device are enabled. 3. **Update BRAM Configurations:** - **Adjust BRAM IP Cores:** - In the `ip` directory, locate the BRAM configurations corresponding to the BARs. - **Files:** ``` pcileech-fpga/pcileech-wifi-main/ip/bram_bar_zero4k.xci pcileech-fpga/pcileech-wifi-main/ip/bram_pcie_cfgspace.xci ``` - **Modify BRAM Sizes:** - Open each BRAM IP core and adjust the memory size to match the corresponding BAR size. - Ensure that the total memory does not exceed the FPGA's capacity. 4. **Save and Regenerate:** - **Apply Changes:** - After configuring the BARs and updating BRAM sizes, click **OK** in the IP customization window. - **Regenerate IP Cores:** - Vivado may prompt you to regenerate the IP cores due to the changes. - Allow the regeneration to complete. - **Check for Errors:** - Review the **Messages** window for any warnings or errors related to BAR configurations. #### **8.2.2 Defining BAR Address Spaces in Firmware** With the BAR sizes and types set, you need to define how the firmware handles accesses to these BARs. **Steps:** 1. **Open the BAR Controller File:** - **Locate the Source File:** - In Visual Studio Code, open: ``` pcileech-fpga/pcileech-wifi-main/src/pcileech_tlps128_bar_controller.sv ``` 2. **Map Address Ranges:** - **Define Address Decoding Logic:** - Implement logic to detect when a BAR is accessed based on the address. ```verilog always_comb begin if (bar_hit[0]) begin // Handle accesses to BAR0 end else if (bar_hit[1]) begin // Handle accesses to BAR1 end // Continue for additional BARs end ``` - **Implement BAR Access Handling:** - For each BAR, define how reads and writes are managed. - **Example:** ```verilog if (bar_hit[0]) begin case (addr_offset) 16'h0000: data_out <= reg0; 16'h0004: data_out <= reg1; // Additional registers default: data_out <= 32'h0; endcase end ``` 3. **Implement Address Decoding Logic:** - **Calculate Address Offsets:** - Use the incoming address to calculate offsets within the BAR. ```verilog addr_offset = incoming_address - bar_base_address[0]; ``` - **Handle Data Transfers:** - Implement logic for read and write operations. ```verilog if (cfg_write) begin // Write data to the appropriate register end else if (cfg_read) begin // Read data from the appropriate register end ``` 4. **Save Changes:** - **Save the File:** - After implementing the logic, save the `pcileech_tlps128_bar_controller.sv` file. - **Verify Functionality:** - Ensure that the logic correctly handles all possible accesses. #### **8.2.3 Handling Multiple BARs** Properly managing multiple BARs is essential for devices that expose multiple memory or I/O regions. **Steps:** 1. **Implement Logic for Each BAR:** - **Separate Logic Blocks:** - For clarity, create separate code blocks for each BAR within the controller. ```verilog // BAR0 Handling if (bar_hit[0]) begin // BAR0 specific logic end // BAR1 Handling if (bar_hit[1]) begin // BAR1 specific logic end ``` - **Define Registers and Memories:** - Allocate registers or memory blocks for each BAR as needed. 2. **Ensure Non-Overlapping Address Spaces:** - **Validate Address Ranges:** - Confirm that the address spaces for each BAR do not overlap. - Align BAR sizes to power-of-two boundaries as per PCIe specifications. - **Update Address Decoding:** - Adjust the address decoding logic to account for the sizes and bases of each BAR. 3. **Test BAR Accesses:** - **Simulation Testing:** - Use simulation tools to test read and write operations to each BAR. - Verify that the correct data is read or written. - **Hardware Testing:** - After programming the FPGA, use software tools on the host to access each BAR. - **Example:** - Use `lspci` on Linux to inspect BAR mappings. - Write test programs that perform memory-mapped I/O to the BARs. ### **8.3 Emulating Device Power Management and Interrupts** Emulating power management features and implementing interrupts are critical for devices that need to interact closely with the host operating system's power and interrupt handling mechanisms. #### **8.3.1 Power Management Configuration** Implementing power management allows the device to support various power states, contributing to system-wide power efficiency and compliance with operating system expectations. **Steps:** 1. **Enable Power Management in PCIe IP Core:** - **Access Capabilities:** - In the PCIe IP core customization window, select the **Capabilities** tab. - **Enable Power Management:** - Check the option for **Power Management** to include the capability in the device's configuration space. 2. **Set Power States Supported:** - **Configure Supported States:** - Specify which power states the device supports, such as: - **D0 (Fully On)** - **D1, D2 (Intermediate States)** - **D3hot, D3cold (Low Power States)** - Match these settings to the donor device's capabilities. 3. **Implement Power State Logic in Firmware:** - **Open `pcileech_pcie_cfg_a7.sv`:** - Modify the firmware to handle power state transitions. - **Handle Power Management Registers:** - Implement read and write access to the Power Management Control and Status Register (PMCSR). ```verilog // PMCSR Address localparam PMCSR_ADDRESS = 12'h44; // Example address // PMCSR Register reg [15:0] pmcsr_reg; // Handle PMCSR Writes always @(posedge clk) begin if (cfg_write && cfg_address == PMCSR_ADDRESS) begin pmcsr_reg <= cfg_writedata[15:0]; // Update power state based on pmcsr_reg[1:0] end end ``` - **Manage Power State Effects:** - Implement the logic to alter device behavior based on the current power state. 4. **Save Changes:** - **Save the Firmware File:** - Ensure all modifications are saved. - **Verify Functionality:** - Test the power management features through simulation or hardware testing. #### **8.3.2 MSI/MSI-X Configuration** Implementing MSI/MSI-X allows the device to use message-based interrupts, which are more efficient and scalable than traditional pin-based interrupts. **Steps:** 1. **Enable MSI/MSI-X in PCIe IP Core:** - **Access Interrupts Configuration:** - In the PCIe IP core customization window, navigate to the **Interrupts** or **MSI/MSI-X** tab. - **Select Interrupt Type:** - Choose **MSI** or **MSI-X** based on the donor device. - **Configure Number of Supported Vectors:** - Set the number of interrupt vectors to match the donor device. - **MSI** supports up to 32 vectors. - **MSI-X** supports up to 2048 vectors. - **Enable Capabilities:** - Ensure that the MSI or MSI-X capabilities are included in the device's configuration space. 2. **Implement Interrupt Logic in Firmware:** - **Open `pcileech_pcie_tlp_a7.sv`:** - Modify the firmware to handle interrupt generation. - **Define Interrupt Signals:** - Declare signals for MSI/MSI-X requests. ```verilog reg msi_req; ``` - **Implement Interrupt Generation Logic:** - Define conditions under which an interrupt is triggered. ```verilog // Example Interrupt Condition wire interrupt_condition = /* condition logic */; // Generate MSI Interrupt always @(posedge clk) begin if (interrupt_condition) begin msi_req <= 1'b1; end else begin msi_req <= 1'b0; end end ``` - **Connect to PCIe Core:** - Ensure that the `msi_req` signal is properly connected to the PCIe IP core's interrupt interface. 3. **Save Changes:** - **Save the Firmware File:** - After implementing the interrupt logic, save the file. - **Check for Timing Constraints:** - Verify that the new logic does not introduce timing violations. #### **8.3.3 Implementing Interrupt Handling Logic** Defining when and how interrupts are generated is essential for the device's interaction with the host's interrupt handling mechanisms. **Steps:** 1. **Define Interrupt Conditions:** - **Identify Trigger Events:** - Determine specific events that should cause an interrupt. - **Examples:** - Data ready for processing. - Error conditions. - Completion of a task. - **Implement Condition Logic:** - Use combinational or sequential logic to detect these events. 2. **Create Interrupt Generation Module:** - **Modular Design:** - Implement the interrupt logic as a separate module for clarity and reuse. ```verilog module interrupt_controller( input wire clk, input wire reset, input wire event_trigger, output reg msi_req ); always @(posedge clk or posedge reset) begin if (reset) begin msi_req <= 1'b0; end else if (event_trigger) begin msi_req <= 1'b1; end else begin msi_req <= 1'b0; end end endmodule ``` - **Integrate with Main Firmware:** - Instantiate the module and connect it to the main firmware logic. 3. **Ensure Proper Timing and Sequencing:** - **Adhere to PCIe Specifications:** - Ensure interrupts are generated and cleared according to the protocol. - **Manage Interrupt Latency:** - Optimize logic to minimize delay between event occurrence and interrupt generation. 4. **Test Interrupt Delivery:** - **Simulation:** - Use simulation tools to verify that interrupts are generated correctly. - **Hardware Testing:** - Program the FPGA and use host-side software to confirm that interrupts are received and handled. - **Debugging Tools:** - Utilize Integrated Logic Analyzer (ILA) cores to monitor signals in real time. 5. **Save Changes:** - **Finalize Code:** - Ensure all changes are saved and documented. - **Review and Refine:** - Iterate on the design as needed based on testing results. --- ## **10. Transaction Layer Packet (TLP) Emulation** Transaction Layer Packets (TLPs) are the fundamental units of communication in PCIe. Accurate TLP emulation is crucial for the device to interact properly with the host system. ### **10.1 Understanding and Capturing TLPs** #### **10.1.1 Learning the TLP Structure** - **Components**: - **Header**: Contains fields such as **Transaction Layer Packet Type (Type)**, **Length**, **Requester ID**, **Tag**, **Address**, etc. - **Data Payload**: Present in Memory Write and some other TLPs. - **CRC**: Ensures data integrity. - **Understanding TLP Types**: - **Memory Read Request** - **Memory Read Completion** - **Memory Write** - **Configuration Read/Write** - **Vendor-Defined Messages** #### **10.1.2 Capturing TLPs from the Donor Device** - **Steps**: 1. **Set Up a PCIe Protocol Analyzer**: - Use hardware tools like **Teledyne LeCroy PCIe Analyzers**. 2. **Capture Transactions**: - Monitor the donor device during normal operation and record the TLPs. 3. **Analyze Captured TLPs**: - Use the analyzer's software to dissect the TLPs and understand their structure and sequence. #### **10.1.3 Documenting Key TLP Transactions** - **Steps**: 1. **Identify Critical Transactions**: - Focus on TLPs that are essential for device initialization, configuration, data transfer, and error handling. 2. **Create Detailed Documentation**: - For each key TLP, note the field values, sequence, and conditions under which it is sent. 3. **Understand Timing and Sequencing**: - Pay attention to the timing between TLPs and the required response times. ### **10.2 Crafting Custom TLPs for Specific Operations** #### **10.2.1 Implementing TLP Handling in Firmware** - **Files to Modify**: - `pcileech_pcie_tlp_a7.sv` ``` pcileech-wifi-main/src/pcileech_pcie_tlp_a7.sv ``` - **Steps**: 1. **Create TLP Generation Functions**: - In `pcileech_pcie_tlp_a7.sv`, write functions to assemble TLPs with the required headers and payloads. - **Example**: ```verilog function automatic [127:0] generate_tlp; input [15:0] requester_id; input [7:0] tag; input [7:0] length; input [31:0] address; input [31:0] data; begin generate_tlp = { /* TLP Header and Payload */ }; end endfunction ``` 2. **Handle TLP Reception**: - Implement logic to parse incoming TLPs and extract necessary information. - Use state machines to manage different TLP types. 3. **Ensure Compliance**: - Verify that the TLPs conform to the PCIe specification regarding format and timing. 4. **Implement Completion Handling**: - For Memory Read Requests, generate appropriate Completion TLPs. 5. **Save Changes**: - Save the file after implementing the changes. #### **10.2.2 Handling Different TLP Types** - **Memory Read Requests**: - **Implementation**: - Parse the request header. - Fetch data from the appropriate memory location. - Assemble and send a Completion TLP with the data. - **Memory Write Requests**: - **Implementation**: - Receive the TLP and extract the data payload. - Write the data to the specified memory location. - **Configuration Read/Write Requests**: - **Implementation**: - Access the configuration space registers. - For reads, return the requested data. - For writes, update the register values. - **Vendor-Defined Messages**: - **Implementation**: - Implement parsing and response logic for any vendor-specific messages as per the donor device's protocol. #### **10.2.3 Validating TLP Timing and Sequence** - **Steps**: 1. **Use Simulation Tools**: - Simulate the firmware using test benches to validate TLP handling. 2. **Monitor with ILA**: - Insert an ILA core to capture TLP-related signals during hardware testing. 3. **Check Timing Constraints**: - Ensure that TLPs are processed and responded to within the allowed timing windows specified by the PCIe standard. 4. **Compliance Testing**: - Use PCIe compliance tools to verify adherence to the standard. 5. **Save Changes**: - Save all modified files after testing and validation. --- ## **Part 3: Advanced Techniques and Optimization** --- ## **11. Building, Flashing, and Testing** After all customizations, it's time to build the firmware, program it onto the FPGA, and thoroughly test it to ensure proper functionality. ### **11.1 Synthesis and Implementation** #### **11.1.1 Running Synthesis** Synthesis converts your high-level code into a gate-level representation. - **Steps**: 1. **Start Synthesis**: - In Vivado, click **Run Synthesis** in the **Flow Navigator**. 2. **Monitor Progress**: - Watch for any warnings or errors. - **Common Warnings**: - **Unconnected Ports**: Ensure all necessary signals are connected. - **Timing Constraints Not Met**: May need to adjust constraints. 3. **Review Synthesis Report**: - Check the **Utilization Summary** to ensure the design fits on the FPGA. #### **11.1.2 Running Implementation** Implementation maps the synthesized design onto the FPGA's resources. - **Steps**: 1. **Start Implementation**: - After successful synthesis, click **Run Implementation**. 2. **Analyze Timing Reports**: - Ensure that all timing constraints are met. - **Address Violations**: - Adjust logic or constraints to fix setup or hold time violations. 3. **Verify Placement**: - Check that critical components are placed optimally. #### **11.1.3 Generating Bitstream** The bitstream is the binary file used to program the FPGA. - **Steps**: 1. **Generate Bitstream**: - Click **Generate Bitstream**. 2. **Wait for Completion**: - This may take some time depending on design complexity. 3. **Review Bitstream Generation Log**: - Ensure no errors occurred during generation. ### **11.2 Flashing the Bitstream** #### **11.2.1 Connecting the FPGA Device** - **Steps**: 1. **Prepare Hardware**: - Ensure the FPGA board is powered and connected via JTAG. - Refer to your FPGA board's manual for specific connection instructions. 2. **Open Hardware Manager**: - In Vivado, navigate to **Flow Navigator > Program and Debug > Open Hardware Manager**. #### **11.2.2 Programming the FPGA** - **Steps**: 1. **Connect to the Target**: - In the Hardware Manager, click **Open Target** and select **Auto Connect**. - Vivado should detect your FPGA device. 2. **Program Device**: - In the Hardware window, right-click on your FPGA device and select **Program Device**. - Select the generated bitstream file (with `.bit` extension). - Click **Program** to flash the firmware onto the FPGA. - Wait for the programming process to complete. #### **11.2.3 Verifying Programming** - **Steps**: 1. **Check Status**: - Ensure the programming completes without errors. - Vivado will display a success message upon completion. 2. **Observe LEDs or Indicators**: - Some FPGA boards have LEDs indicating successful programming or active status. ### **11.3 Testing and Validation** #### **11.3.1 Verifying Device Enumeration** - **Windows**: - **Steps**: 1. **Open Device Manager**: - Press `Win + X` and select **Device Manager**. 2. **Check Device Properties**: - Look under the appropriate device category (e.g., **Network Adapters**, **Storage Controllers**). - Confirm that the **Device ID**, **Vendor ID**, and other identifiers match those of the donor device. - **Linux**: - **Steps**: 1. **Use lspci**: ```bash lspci -nn ``` 2. **Verify Device Listing**: - Check that the emulated device appears with correct IDs. - **Example Output**: ``` 03:00.0 Network controller [0280]: VendorID DeviceID ``` #### **11.3.2 Testing Device Functionality** - **Steps**: 1. **Install Necessary Drivers**: - Use the donor device's drivers if required. - Install them as per the manufacturer's instructions. 2. **Perform Functional Tests**: - Run applications that interact with the device. - Test data transfers, configurations, and any special functions. - **Examples**: - For a network card, perform ping tests or data streaming. - For a storage controller, perform read/write operations. 3. **Monitor System Behavior**: - Check for system stability and absence of errors. - Ensure that the device behaves as expected under various workloads. #### **11.3.3 Monitoring for Errors** - **Windows**: - **Steps**: 1. **Check Event Viewer**: - Press `Win + X` and select **Event Viewer**. - Navigate to **Windows Logs > System**. 2. **Look for PCIe-Related Errors**: - Search for warnings or errors related to PCIe or the specific device. - **Linux**: - **Steps**: 1. **Check dmesg Logs**: ```bash dmesg | grep pci ``` 2. **Identify Issues**: - Look for messages indicating problems with PCIe communication or device initialization. --- ## **12. Advanced Debugging Techniques** When issues arise, advanced debugging tools and techniques can help identify and resolve problems efficiently. ### **12.1 Using Vivado's Integrated Logic Analyzer** The Integrated Logic Analyzer (ILA) allows real-time monitoring of internal FPGA signals. #### **12.1.1 Inserting ILA Cores** - **Steps**: 1. **Add ILA IP Core**: - In Vivado, open the **IP Catalog**. - Search for **ILA**. - Instantiate the ILA core in your design. 2. **Connect Signals**: - Attach the signals you wish to monitor to the ILA probes. - **Example**: ```verilog ila_0 your_ila_instance ( .clk(clk), .probe0(signal_to_monitor) ); ``` - **File Path**: ``` pcileech-wifi-main/src/pcileech_squirrel_top.sv ``` #### **12.1.2 Configuring Trigger Conditions** - **Steps**: 1. **Set Probe Properties**: - Define the width of each probe to match the signal widths. 2. **Define Triggers**: - In the ILA dashboard, set conditions that will trigger data capture. - **Example**: - Trigger when a specific TLP type is detected or when an error condition occurs. #### **12.1.3 Capturing and Analyzing Data** - **Steps**: 1. **Run the Design**: - Program the FPGA with the ILA-enabled bitstream. 2. **Open Hardware Manager**: - Access the ILA interface within Vivado. 3. **Capture Data**: - Arm the ILA and wait for the trigger condition. - Once triggered, the ILA will capture the waveform data. 4. **Analyze Waveforms**: - Use the waveform viewer to inspect signal behavior. - Identify anomalies or verify correct operation. ### **12.2 PCIe Traffic Analysis Tools** Using external tools can provide deeper insights into PCIe communications. #### **12.2.1 PCIe Protocol Analyzers** - **Examples**: - **Teledyne LeCroy PCIe Analyzers** - **Keysight PCIe Analyzers** - **Steps**: 1. **Set Up Analyzer**: - Connect the analyzer between the host system and FPGA device. 2. **Configure Capture Settings**: - Define the scope of data to capture (e.g., specific TLP types, error conditions). 3. **Capture Traffic**: - Record PCIe transactions during device operation. 4. **Analyze Results**: - Examine TLPs for compliance and correctness. - Identify any protocol violations or unexpected behaviors. #### **12.2.2 Software-Based Tools** - **Examples**: - **Wireshark with PCIe Plugins** - **ChipScope Pro** (for Xilinx devices) - **Steps**: 1. **Install Necessary Plugins**: - Ensure PCIe support is enabled in the tool. 2. **Monitor PCIe Bus**: - Capture and display PCIe packets. 3. **Analyze Communications**: - Look for anomalies or errors in the data. - Verify that TLPs are correctly formed and sequenced. --- ## **13. Troubleshooting** This section provides solutions to common problems you may encounter during firmware development and testing. ### **13.1 Device Detection Issues** **Problem**: The FPGA device is not recognized by the host system. #### **Possible Causes and Solutions**: 1. **Incorrect Device IDs**: - **Cause**: Mismatch between the IDs in the firmware and what the host expects. - **Solution**: Verify and correct the **Device ID**, **Vendor ID**, and **Subsystem ID** in your firmware. 2. **PCIe Link Training Failure**: - **Cause**: The PCIe link is not established. - **Solution**: - Check physical connections. - Ensure the **Link Width** and **Link Speed** are correctly configured. 3. **Power Issues**: - **Cause**: Insufficient power to the FPGA device. - **Solution**: Verify power supply connections and voltage levels. 4. **Firmware Errors**: - **Cause**: Errors in the firmware prevent proper operation. - **Solution**: Review code for syntax errors or misconfigurations. ### **13.2 Memory Mapping and BAR Configuration Errors** **Problem**: The device's memory regions are not accessible, or accessing them causes system errors. #### **Possible Causes and Solutions**: 1. **Incorrect BAR Sizes or Types**: - **Cause**: BAR configurations do not match the donor device. - **Solution**: Adjust BAR sizes and types in both the PCIe IP Core and firmware. 2. **Address Decoding Errors**: - **Cause**: Firmware fails to correctly interpret addresses. - **Solution**: Debug the address decoding logic in your firmware. 3. **Overlapping Address Spaces**: - **Cause**: BARs overlap or conflict with other devices. - **Solution**: Ensure BAR addresses are correctly aligned and do not overlap. ### **13.3 DMA Performance and TLP Errors** **Problem**: Slow data transfer rates or errors occur during DMA operations, or TLPs are malformed. #### **Possible Causes and Solutions**: 1. **Inefficient DMA Logic**: - **Cause**: DMA engine not optimized. - **Solution**: Implement buffering and pipelining to enhance throughput. 2. **Malformed TLPs**: - **Cause**: Incorrect TLP formatting. - **Solution**: Review TLP assembly code to ensure compliance with the PCIe specification. 3. **Flow Control Issues**: - **Cause**: Improper handling of flow control credits. - **Solution**: Implement proper flow control mechanisms in the firmware. --- ## **14. Emulation Accuracy and Optimizations** Enhancing emulation accuracy ensures compatibility and performance, making the emulated device indistinguishable from the donor. ### **14.1 Techniques for Accurate Timing Emulation** - **Implement Timing Constraints**: - Use Vivado's timing constraints to match the timing characteristics of the donor device. - Apply constraints to critical paths to ensure they meet the required setup and hold times. - **Use Clock Domain Crossing (CDC) Techniques**: - Properly handle signals crossing between different clock domains to prevent metastability. - Use synchronizers or FIFOs as appropriate. - **Simulate Device Behavior**: - Use simulation tools to model and verify the device's behavior under different conditions. - Validate that the timing and sequencing of operations match the donor device. ### **14.2 Dynamic Response to System Calls** - **Implement State Machines**: - Design state machines that allow the device to respond dynamically to various commands and states. - Ensure that the device can handle unexpected or out-of-order requests gracefully. - **Monitor and Respond to Host Commands**: - Implement logic to decode and respond to configuration writes, vendor-specific commands, and other interactions. - Update internal registers and states accordingly. - **Optimize Firmware Logic**: - Refine the firmware code to reduce latency and improve responsiveness. - Remove unnecessary delays or bottlenecks in the data paths. --- ## **15. Best Practices for Firmware Development** Following best practices helps maintain code quality, facilitates collaboration, and ensures the longevity of your project. ### **15.1 Continuous Testing and Documentation** - **Regular Testing**: - Test the firmware after each significant change to catch issues early. - Use test benches and simulation to validate logic before implementation. - **Automated Testing**: - Implement automated test scripts to verify functionality and performance. - Use continuous integration tools if working in a team environment. - **Maintain Documentation**: - Document the design, including block diagrams, state machines, and interfaces. - Keep track of changes with clear commit messages and update design documents accordingly. ### **15.2 Managing Firmware Versioning** - **Use Version Control Systems**: - Employ systems like **Git** to manage code versions and collaborate with others. - Organize the repository with clear directory structures and naming conventions. - **Tag Releases and Milestones**: - Tag stable versions of the firmware for future reference. - Use branches for experimental features or major changes. - **Backup and Recovery**: - Regularly backup your work to prevent data loss. - Use cloud-based repositories or local backups as appropriate. ### **15.3 Security Considerations** - **Secure Coding Practices**: - Follow guidelines to prevent common vulnerabilities such as buffer overflows or race conditions. - Validate all inputs and handle errors gracefully. - **Data Protection**: - Ensure that any sensitive data handled by the device is protected. - Implement encryption or access controls if necessary. - **Compliance and Ethics**: - Be aware of legal and ethical considerations related to device emulation. - Ensure compliance with relevant laws, regulations, and licensing agreements. --- ## **16. Additional Resources** Enhance your understanding and stay updated with the following resources: - **Xilinx Documentation** - [Xilinx User Guides](https://www.xilinx.com/support/documentation/user_guides.htm) - Includes detailed information on Vivado, IP cores, and FPGA development. - **PCI-SIG Specifications** - [PCI Express Base Specification](https://pcisig.com/specifications) - Official specifications for PCIe standards. - **FPGA Tutorials and Forums** - [FPGA4Fun](http://www.fpga4fun.com/) - [Stack Overflow FPGA Questions](https://stackoverflow.com/questions/tagged/fpga) - Community-driven discussions and tutorials. - **Verilog and VHDL Resources** - [ASIC World Verilog Tutorials](https://www.asic-world.com/verilog/index.html) - [VHDL Reference Guide](https://www.vhdlwhiz.com/vhdl-reference-guide/) - **Vivado Design Suite User Guide** - [Vivado User Guide](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2020_1/ug893-vivado-ip-subsystems.pdf) - **PCIe Protocol Analysis Tools** - [Teledyne LeCroy](https://teledynelecroy.com/protocolanalyzer/) - Offers a range of tools for PCIe analysis. --- ## **17. Contact Information** If you need assistance, have questions, or wish to collaborate, feel free to reach out. I'm available to provide guidance, troubleshoot complex problems, or discuss ideas in detail. ### **Discord**: [**VCPU**](https://discord.com/users/196741541094621184) | [**Server Invite Link**](https://discord.gg/dS2gDUDQmV) --- ## **18. Support and Contributions** Your support helps maintain and improve this guide and related projects. ### **Donations** - **Crypto Donations (LTC)**: - **Address**: `MPMyQD5zgy2b2CpDn1C1KZ31KmHpT7AwRi` If you found this guide helpful and want to support ongoing work, consider contributing. Every donation helps in continuing to create, share, and support the community. **Special Bonus**: If you donate, reach out on Discord (VCPU) to receive a personal thank you and possibly additional resources or assistance. **Note**: If you need me to review your implementation or troubleshoot issues, please mark the relevant sections with `//VCPU-REVIEW//` and provide detailed explanations of the problems you're encountering. --- **End of Guide** ================================================ FILE: README-v2-old.md ================================================ # **Custom Firmware Development Guide for Full Device Emulation** ## **Table of Contents** 1. [Introduction](#1-introduction) - [1.1 Purpose of the Guide](#11-purpose-of-the-guide) - [1.2 Target Audience](#12-target-audience) 2. [Key Definitions](#2-key-definitions) 3. [Device Compatibility](#3-device-compatibility) - [3.1 Supported FPGA-Based Hardware](#31-supported-fpga-based-hardware) - [3.2 PCIe Hardware Considerations](#32-pcie-hardware-considerations) - [3.3 System Requirements](#33-system-requirements) 4. [Requirements](#4-requirements) - [4.1 Hardware](#41-hardware) - [4.2 Software](#42-software) - [4.3 Environment Setup](#43-environment-setup) 5. [Gathering Donor Device Information](#5-gathering-donor-device-information) - [5.1 Using Arbor for PCIe Device Scanning](#51-using-arbor-for-pcie-device-scanning) - [5.2 Extracting and Recording Device Attributes](#52-extracting-and-recording-device-attributes) 6. [Initial Firmware Customization](#6-initial-firmware-customization) - [6.1 Modifying Configuration Space](#61-modifying-configuration-space) - [6.2 Inserting the Device Serial Number (DSN)](#62-inserting-the-device-serial-number-dsn) 7. [Vivado Project Setup and Customization](#7-vivado-project-setup-and-customization) - [7.1 Generating Vivado Project Files](#71-generating-vivado-project-files) - [7.2 Modifying IP Blocks](#72-modifying-ip-blocks) 8. [Advanced Firmware Customization](#8-advanced-firmware-customization) - [8.1 Configuring PCIe Parameters for Emulation](#81-configuring-pcie-parameters-for-emulation) - [8.2 Adjusting BARs and Memory Mapping](#82-adjusting-bars-and-memory-mapping) - [8.3 Emulating Device Power Management and Interrupts](#83-emulating-device-power-management-and-interrupts) 9. [Emulating Device-Specific Capabilities](#9-emulating-device-specific-capabilities) - [9.1 Implementing Advanced PCIe Capabilities](#91-implementing-advanced-pcie-capabilities) - [9.2 Emulating Vendor-Specific Features](#92-emulating-vendor-specific-features) 10. [Transaction Layer Packet (TLP) Emulation](#10-transaction-layer-packet-tlp-emulation) - [10.1 Understanding and Capturing TLPs](#101-understanding-and-capturing-tlps) - [10.2 Crafting Custom TLPs for Specific Operations](#102-crafting-custom-tlps-for-specific-operations) 11. [Building, Flashing, and Testing](#11-building-flashing-and-testing) - [11.1 Synthesis and Implementation](#111-synthesis-and-implementation) - [11.2 Flashing the Bitstream](#112-flashing-the-bitstream) - [11.3 Testing and Validation](#113-testing-and-validation) 12. [Advanced Debugging Techniques](#12-advanced-debugging-techniques) - [12.1 Using Vivado's Integrated Logic Analyzer](#121-using-vivados-integrated-logic-analyzer) - [12.2 PCIe Traffic Analysis Tools](#122-pcie-traffic-analysis-tools) 13. [Troubleshooting](#13-troubleshooting) - [13.1 Device Detection Issues](#131-device-detection-issues) - [13.2 Memory Mapping and BAR Configuration Errors](#132-memory-mapping-and-bar-configuration-errors) - [13.3 DMA Performance and TLP Errors](#133-dma-performance-and-tlp-errors) 14. [Emulation Accuracy and Optimizations](#14-emulation-accuracy-and-optimizations) - [14.1 Techniques for Accurate Timing Emulation](#141-techniques-for-accurate-timing-emulation) - [14.2 Dynamic Response to System Calls](#142-dynamic-response-to-system-calls) 15. [Best Practices for Firmware Development](#15-best-practices-for-firmware-development) - [15.1 Continuous Testing and Documentation](#151-continuous-testing-and-documentation) - [15.2 Managing Firmware Versioning](#152-managing-firmware-versioning) - [15.3 Security Considerations](#153-security-considerations) 16. [Additional Resources](#16-additional-resources) --- ## **Preface** **Attention, you thieving scum.** I’m not here to coddle or indulge your pitiful schemes. **FUCK AQUA**, better known as Aqua Teen Paster Force—a disgrace to anyone with a shred of integrity. **FUCK DIVINER**, too. And DUCK? Go degrade yourself elsewhere. **DMA KINGDOM**? You and your parasitic empire can rot in hell with the rest of these frauds. SHITLETTE and all of you money-grubbing thieves, prepare for a reckoning. The **Wrath of God**? You’re about to understand the meaning of true devastation. Either atone for your greed, or get swept away by the destruction you deserve. While we are on this topic, FUCK YOU TOO BILL GATES. For those who’ve come to **learn**, you’ve chosen the path of **true enlightenment**. What you build with this guide will outshine anything these charlatans could dream of. You’re on the road to **excellence**, and together, we’ll torch the failures they’ve built their fortunes on. --- ## **Contact Information** If you need assistance, have inquiries, or are looking to collaborate, feel free to reach out. I’m available to provide guidance, troubleshoot complex problems, or discuss ideas in detail. ### **Discord** - **VCPU** | [**Server**](https://discord.gg/dS2gDUDQmV) --- ## **Support My Work** If you found this guide helpful and want to fuel more projects, consider contributing to help keep everything going. Every donation helps me continue to create, share, and support the community, and it’s greatly appreciated. ### **Crypto Donations (LTC)** - MPMyQD5zgy2b2CpDn1C1KZ31KmHpT7AwRi I don’t make much from selling firmware—maybe 5 sales adding up to around $300 total—but I know many people using this guide will go on to make far more. If this guide helped you on your path to success, consider giving back so I can keep these resources available for everyone. ### **Special Bonus** If you donate, reach out to me on Discord (VCPU) and let me know. I’d love to thank you personally and offer something in return. I’ll even do a random prize spin—whether it's free firmware, private source codes, or some insights on bypassing ACS, there’ll be something special for you. Your support means the world to me, and together we can keep building and sharing for the future. Thank you! --- Don't have the time or energy to make firmware yourself? I offer firmware starting at $60. Resellers are also welcome! Reach out anytime for support or further discussion on this guide or related topics. Whether you’re a developer needing in-depth help or a researcher diving into FPGA emulation, I’m here to ensure your path to success is smooth and informed. Let's build something remarkable together. If you are unsure if you completed a step properly or want me to review your implementation I will do so but you must have the section for review marked with //VCPU-REVIEW// and explain your problems so my time is not wasted. I am sure quite a few of you will exceed my capabilities, If you find something new or just make some sick firmware, I would love to see it in action. Moreover, I also have some very powerful bytes and bits to share, but if I shared here Riot PD would put me in a squad car. Share knowledge and spread loving kindness. God bless. --- ## **1. Introduction** ### **1.1 Purpose of the Guide** The primary objective of this guide is to equip developers, security researchers, and hardware engineers with the knowledge and practical steps necessary to develop custom DMA firmware for accurate 1:1 hardware device emulation using FPGA-based systems like **PCILeech-FPGA**. This enables applications in hardware testing, system debugging, malware analysis, and other scenarios requiring undetectable or legitimate-looking device emulation. ### **1.2 Target Audience** - **Firmware Developers**: Engineers building custom firmware for hardware emulation, testing, or bypassing hardware restrictions. - **Hardware Testers**: Professionals emulating faulty or outdated hardware devices to assess system resilience or compatibility. - **Security Researchers**: Individuals utilizing custom firmware for vulnerability testing, malware analysis, or security assessments. - **FPGA Enthusiasts**: Hobbyists exploring FPGA customization and low-level hardware emulation. --- ## **2. Key Definitions** Understanding the terminology is crucial for effectively following this guide. Below are key definitions related to PCIe, DMA, and device emulation: - **DMA (Direct Memory Access)**: A capability allowing hardware devices to directly read from or write to system memory without CPU intervention, facilitating rapid data transfers. - **TLP (Transaction Layer Packet)**: The fundamental unit of communication in PCIe architecture, encapsulating control and data information. - **BAR (Base Address Register)**: Registers in PCIe devices that map device memory into system memory space, defining memory and I/O address regions. - **FPGA (Field Programmable Gate Array)**: A reconfigurable integrated circuit that can be programmed to perform specific hardware functions, enabling custom device emulation. - **MSI/MSI-X (Message Signaled Interrupts)**: Mechanisms used by PCIe devices to send interrupts to the CPU, handling asynchronous events. - **Device Serial Number (DSN)**: A unique identifier associated with a specific device, often used for advanced device identification and verification. - **PCIe Configuration Space**: A memory area where PCIe devices provide information about themselves and configure operational parameters. - **Donor Card**: A PCIe device used to extract configuration and identification details for the purpose of emulating its behavior on an FPGA. --- ## **3. Device Compatibility** ### **3.1 Supported FPGA-Based Hardware** While this guide primarily focuses on the **Squirrel DMA (35T)** card, the methodologies outlined are adaptable to other FPGA-based DMA hardware. Below is a list of compatible devices: - **Squirrel (35T)** - **Description**: Affordable and widely accessible FPGA-based DMA device. - **Use Case**: Suitable for standard memory acquisition and device emulation tasks. - **EnigmaX1 (75T)** - **Description**: Mid-tier FPGA offering enhanced resources and performance. - **Use Case**: Ideal for more demanding memory operations requiring higher bandwidth. - **ZDMA (100T)** - **Description**: High-performance FPGA, optimized for rapid memory interactions. - **Use Case**: Best suited for scenarios requiring fast and extensive memory reads/writes. - **Kintex-7** - **Description**: Advanced FPGA with robust capabilities for complex projects. - **Use Case**: Suitable for large-scale or highly customized DMA solutions. ### **3.2 PCIe Hardware Considerations** To ensure smooth emulation, several PCIe-specific features must be addressed: - **IOMMU/VT-d Settings** - **Recommendation**: Disable IOMMU (Intel's VT-d) to allow unrestricted DMA access. - **Rationale**: IOMMU can restrict DMA operations, potentially interfering with memory acquisition and emulation. - **Kernel DMA Protection** - **Recommendation**: Disable Kernel DMA Protection features found in modern systems. - **Steps**: - **Windows**: This may involve disabling Secure Boot or Virtualization-Based Security (VBS). - **BIOS/UEFI**: Access firmware settings to turn off related security features. - **Caution**: Disabling these features can expose the system to risks; ensure you're operating within a secure and isolated environment. - **PCIe Slot Requirements** - **Recommendation**: Use a compatible PCIe slot that matches the FPGA device's requirements (e.g., x1, x4, x16). - **Rationale**: Ensures optimal performance and compatibility with the host system. ### **3.3 System Requirements** - **Host System** - **Processor**: Multi-core CPU (Intel i5/i7 or equivalent) - **Memory**: Minimum 16GB RAM - **Storage**: SSD with at least 100GB free space - **Operating System**: Windows 10/11 (64-bit) or a compatible Linux distribution (e.g., Ubuntu, Debian) with necessary drivers - **Peripheral Devices** - **JTAG Adapter**: For flashing firmware onto the FPGA - **PCIe Slot**: Ensure the host system has available PCIe slots compatible with the DMA card --- ## **4. Requirements** ### **4.1 Hardware** - **Donor PCIe Device** - **Purpose**: Source of device IDs and configuration data for spoofing. - **Examples**: Network adapters, storage controllers, or any generic PCIe card not used on the main PC. - **DMA FPGA Card** - **Description**: FPGA-based device capable of performing DMA operations. - **Examples**: Squirrel (35T), EnigmaX1 (75T), ZDMA (100T), Kintex-7 - **JTAG Programmer** - **Purpose**: For flashing firmware onto the FPGA. - **Examples**: Xilinx Platform Cable USB, Digilent JTAG USB Cable ### **4.2 Software** - **Vivado** - **Description**: Xilinx's FPGA development software for synthesizing and building firmware projects. - **Download**: [Xilinx Vivado](https://www.xilinx.com/support/download.html) - **Visual Studio** - **Description**: Integrated Development Environment (IDE) for editing Verilog or VHDL code. - **Download**: [Visual Studio Community](https://visualstudio.microsoft.com/vs/community/) - **PCILeech-FPGA** - **Description**: The repository and base code for DMA firmware development. - **Repository**: [PCILeech-FPGA on GitHub](https://github.com/ufrisk/pcileech-fpga) - **Arbor** - **Description**: PCIe device scanning tool for gathering device information. - **Download**: [Arbor by MindShare](https://www.mindshare.com/software/Arbor) - **Note**: Requires account creation; offers a 14-day trial. - **Alternative Tools** - **Telescan PE** - **Description**: PCIe traffic analysis tool that can be used as an alternative to Arbor. - **Download**: [Teledyne LeCroy Telescan PE](https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software) - **Note**: Free but requires manual registration approval. ### **4.3 Environment Setup** 1. **Install Vivado** - **Steps**: 1. Visit the [Xilinx Vivado Download Page](https://www.xilinx.com/support/download.html). 2. Download the appropriate version compatible with your FPGA device. 3. Follow the installation instructions provided by Xilinx. 4. Launch Vivado and ensure it is properly configured. 2. **Install Visual Studio** - **Steps**: 1. Visit the [Visual Studio Download Page](https://visualstudio.microsoft.com/vs/community/). 2. Download and install the **Visual Studio Community Edition**. 3. During installation, ensure you include workloads related to **Desktop development with C++** to support hardware description languages (HDLs) like Verilog or VHDL. 3. **Clone the PCILeech-FPGA Repository** - **Steps**: 1. Open a terminal or command prompt. 2. Clone the repository using Git: ```bash git clone https://github.com/ufrisk/pcileech-fpga.git ``` 3. Navigate to the cloned directory: ```bash cd pcileech-fpga ``` 4. **Set Up a Clean Development Environment** - **Recommendation**: Work in an isolated environment to prevent unintended interactions, especially if using the firmware for sensitive tasks like malware analysis. - **Steps**: 1. Use a dedicated development machine or a virtual environment. 2. Ensure no other applications interfere with PCIe operations or FPGA programming. --- ## **5. Gathering Donor Device Information** Accurate device emulation relies on extracting critical information from the donor device. This data allows your FPGA to mimic the target hardware in terms of PCIe configuration and behavior. ### **5.1 Using Arbor for PCIe Device Scanning** **Arbor** is a powerful tool for scanning PCIe devices and extracting necessary information. Follow these steps to gather donor device details: 1. **Install Arbor** - **Steps**: 1. Visit the [Arbor Download Page](https://www.mindshare.com/software/Arbor). 2. Create an account if required. 3. Download and install Arbor on your system. 2. **Scan PCIe Devices** - **Steps**: 1. Launch Arbor. 2. Navigate to the **Local System** tab. 3. Under **Scan Options**, ensure default settings are appropriate. 4. Click **Scan/Rescan** to detect all connected PCIe devices. 3. **Identify the Donor Device** - **Criteria**: - Should not be used on your main PC. - Examples: PCIe WiFi cards, storage controllers, or generic PCIe devices. - **Steps**: 1. Locate your donor device in the list of scanned devices. 2. Click on the device to view detailed configuration. 4. **Capture Device Data** - **Information to Extract**: - **Device ID** - **Vendor ID** - **Subsystem ID** - **Revision ID** - **Base Address Registers (BARs)** - **Capabilities** (e.g., MSI, power management, PCIe link width/speed) - **Device Serial Number (DSN)** (if available) - **Steps**: 1. Navigate to the **PCI Config** tab within Arbor. 2. Scroll through the **Decode** section to locate and record the above details. 3. Take screenshots or notes of each value for reference during firmware customization. - **Example Extraction**: ![Device IDs](https://github.com/Silverr12/DMA-CFW-Guide/assets/89455475/8baec3fe-c4bd-478e-9f95-d262804d6f67) ![Vendor ID](https://github.com/Silverr12/DMA-CFW-Guide/assets/89455475/39c7de6d-d8db-4744-b0a0-ddeca0dfd7d7) ![Revision ID](https://github.com/Silverr12/DMA-CFW-Guide/assets/89455475/c2374ea7-ca9c-47b7-8a8d-4ceff5dffe3b) ![BAR Sizing](https://github.com/Silverr12/DMA-CFW-Guide/assets/89455475/19239179-057a-4ed5-a79f-45cf242787a5) ![Subsystem ID](https://github.com/Silverr12/DMA-CFW-Guide/assets/89455475/94522a95-70bd-4336-8e38-58c0839e38ad) ![DSN](https://github.com/Silverr12/DMA-CFW-Guide/assets/89455475/595ae3e2-4cd8-4b3d-bcfa-cf6a59f289d5) - **Note**: The DSN may not be present on all devices. If unavailable, proceed with zeros in the DSN field during customization. ### **5.2 Extracting and Recording Device Attributes** After scanning, ensure you have accurately recorded the following attributes from the donor device: 1. **Device ID**: A unique identifier for the hardware device. 2. **Vendor ID**: The identifier of the device manufacturer. 3. **Subsystem ID**: Identifies the specific subsystem associated with the device. 4. **Revision ID**: The revision number of the hardware version. 5. **Base Address Registers (BARs)**: Defines memory and I/O address regions of the device. 6. **Capabilities**: Such as Power Management (PM), MSI/MSI-X, PCIe link speed, and width. 7. **Device Serial Number (DSN)**: If applicable, the unique serial number associated with the device. **Important Considerations**: - **BAR Sizes**: Ensure the memory-mapped I/O regions match the donor device’s configuration. - **Capabilities**: Properly emulate all capabilities to ensure seamless integration with the host system. - **DSN**: Enhances the fidelity of emulation; use if available. --- ## **6. Initial Firmware Customization** With the necessary donor information in hand, proceed to customize the PCIe configuration space and memory mapping within the firmware to spoof the donor device. ### **6.1 Modifying Configuration Space** 1. **Navigate to the Configuration File** - **Path**: `/PCIeSquirrel/src/pcileech_pcie_cfg_a7.sv` - **Description**: This Verilog file contains the PCIe configuration logic for the device. 2. **Open the File in Visual Studio** - **Steps**: 1. Launch **Visual Studio**. 2. Open the `pcileech_pcie_cfg_a7.sv` file located in the `/PCIeSquirrel/src/` directory. 3. **Modify Device ID and Vendor ID** - **Steps**: 1. Use **Ctrl + F** to search for `cfg_deviceid`. 2. Update the Device ID with the donor's value: ```verilog cfg_deviceid <= 16'hXXXX; // Replace XXXX with donor Device ID ``` 3. Similarly, search for `cfg_vendorid` and update: ```verilog cfg_vendorid <= 16'hYYYY; // Replace YYYY with donor Vendor ID ``` 4. **Modify Subsystem ID** - **Steps**: 1. Search for `cfg_subsysid`. 2. Update the Subsystem ID: ```verilog cfg_subsysid <= 16'hZZZZ; // Replace ZZZZ with donor Subsystem ID ``` 5. **Adjust BARs Based on Donor Device** - **Steps**: 1. Locate the BAR size configurations. 2. Set the BAR sizes to match those of the donor device: ```verilog bar0_size <= 32'hXXXX_YYYY; // Replace with donor's BAR0 size ``` 3. Repeat for additional BARs (BAR1, BAR2, etc.) as necessary. - **Example**: ```verilog bar0_size <= 32'h00004000; // 16KB for BAR0 ``` ### **6.2 Inserting the Device Serial Number (DSN)** If your donor device has a **Device Serial Number (DSN)**, incorporating it into the firmware enhances the emulation's fidelity. 1. **Locate the DSN Field** - **Steps**: 1. In `pcileech_pcie_cfg_a7.sv`, search for `rw[127:64]`. 2. This field represents the `cfg_dsn` (Configuration Space Device Serial Number). 2. **Insert the DSN** - **Steps**: 1. Replace the placeholder with your donor device's DSN: ```verilog rw[127:64] <= 64'hXXXXXXXX_YYYYYYYY; // Replace Xs and Ys with donor DSN ``` 2. **Example**: - **Donor DSN**: Upper DW: `01 00 00 00`, Lower DW: `68 4C E0 00` - **Combined DSN**: `64'h01000000684CE000` ```verilog rw[127:64] <= 64'h01000000684CE000; // Donor DSN ``` - **No DSN Available**: ```verilog rw[127:64] <= 64'h0000000000000000; // No DSN ``` 3. **Save Changes** - **Steps**: 1. After modifying the DSN, save the file to retain changes. --- ## **7. Vivado Project Setup and Customization** After customizing the configuration space, integrate these changes into the Vivado project to prepare the firmware for synthesis and implementation. ### **7.1 Generating Vivado Project Files** 1. **Open Vivado** - **Steps**: 1. Launch **Vivado** on your development machine. 2. Ensure Vivado is properly installed and configured for your FPGA device. 2. **Access the Tcl Console** - **Steps**: 1. In Vivado, locate the **Tcl Console** at the bottom of the application window. 2. If not visible, navigate to **Window > Tcl Console** to display it. 3. **Navigate to the PCIeSquirrel Directory** - **Steps**: 1. In the Tcl Console, determine your current directory: ```tcl pwd ``` 2. Change the directory to the `PCIeSquirrel` folder within the cloned `pcileech-fpga` repository: ```tcl cd C:/Users/YourUsername/Desktop/pcileech-fpga/PCIeSquirrel ``` *Replace `YourUsername` and the path as per your setup.* - **Note**: If you encounter errors with backslashes (`\`), use forward slashes (`/`): ```tcl cd C:/Users/YourUsername/Desktop/pcileech-fpga/PCIeSquirrel ``` 4. **Generate the Vivado Project** - **Steps**: 1. In the Tcl Console, execute the project generation script: ```tcl source vivado_generate_project.tcl -notrace ``` 2. Wait for the script to complete. This process sets up the Vivado project with the necessary configurations. 5. **Open the Generated Project** - **Steps**: 1. Upon successful generation, Vivado should automatically open the `.xpr` (Vivado Project) file. 2. Keep the project open for further customization. ### **7.2 Modifying IP Blocks** 1. **Access the PCIe IP Core** - **Steps**: 1. In the **Sources** pane, navigate to: ``` pcileech_squirrel_top > i_pcileech_pcie_a7 : pcileech_pcie_a7 ``` 2. Double-click on the PCIe IP core (`i_pcie_7x_0 : pcie_7x_0`) to open the **Re-customize IP** window. 2. **Customize Device IDs and BARs** - **Steps**: 1. In the **Re-customize IP** dialog, navigate to the **IDs** tab. 2. Enter the **Device ID**, **Vendor ID**, and **Subsystem ID** gathered from the donor device. 3. Verify the **Class Code**: - Go back to Arbor or your scanning tool to determine the class code of your donor device. - In the **Re-customize IP** window, set the class code accordingly to match the donor device. 4. **Example**: - **Device ID**: `0x1234` - **Vendor ID**: `0xABCD` - **Subsystem ID**: `0x5678` - **Class Code**: `0x030000` (e.g., Network Controller) 3. **Configure BAR Sizes** - **Steps**: 1. Navigate to the **BARs** tab within the **Re-customize IP** dialog. 2. Set the **BAR0 Size** to match the donor device's BAR0 size. - **Example**: If the donor's BAR0 is 16KB: ```tcl BAR0 Size: 16KB ``` 3. Repeat for additional BARs (BAR1, BAR2, etc.) if the donor device utilizes them. 4. **Finalize IP Customization** - **Steps**: 1. After setting all necessary parameters, click **OK** to apply the changes. 2. Vivado may prompt to regenerate the IP core; confirm and allow the process to complete. 5. **Lock the IP Core** - **Purpose**: Prevent Vivado from overwriting manual configurations during synthesis. - **Steps**: 1. Open the **Tcl Console** within Vivado. 2. Execute the following command to lock the IP core: ```tcl set_property is_managed false [get_files pcie_7x_0.xci] ``` 3. **To Unlock** (if needed in the future): ```tcl set_property is_managed true [get_files pcie_7x_0.xci] ``` --- ## **8. Advanced Firmware Customization** To achieve precise 1:1 emulation, further customize PCIe parameters, BARs, memory mapping, power management, and interrupt handling. ### **8.1 Configuring PCIe Parameters for Emulation** 1. **Match PCIe Link Speed and Width** - **Importance**: Ensures the emulated device communicates at the same speed and width as the donor device. - **Steps**: 1. In `pcileech_pcie_cfg_a7.sv`, locate the PCIe link speed and width configurations. 2. Update these parameters to match the donor device's specifications. ```verilog pcie_link_speed <= 4'bXXXX; // Replace XXXX with donor's PCIe link speed pcie_link_width <= 8'b00000100; // Replace with donor's PCIe link width (e.g., x1, x4, x8) ``` - **Example**: - **Donor PCIe Link Speed**: Gen3 (8 GT/s) - **Donor PCIe Link Width**: x4 ```verilog pcie_link_speed <= 4'b0011; // Gen3 pcie_link_width <= 8'b00000100; // x4 ``` 2. **Set Capability Pointers** - **Purpose**: Ensure the PCIe capabilities are correctly linked and recognized by the host system. - **Steps**: 1. Locate the capability pointer configurations in `pcileech_pcie_cfg_a7.sv`. 2. Set the capability pointers to match the donor device's configuration. ```verilog capability_pointer <= 8'h40; // Example value; replace with donor's capability pointer ``` ### **8.2 Adjusting BARs and Memory Mapping** Accurate memory mapping is critical for emulating hardware devices. Base Address Registers (BARs) define where the device's memory and registers appear in system memory space. 1. **Set BAR Sizes** - **Steps**: 1. In `pcileech_pcie_cfg_a7.sv`, locate the BAR size assignments. 2. Set the BAR sizes to match those of the donor device. ```verilog bar0_size <= 32'h00004000; // 16KB for BAR0 bar1_size <= 32'h00008000; // 32KB for BAR1 (if applicable) ``` 2. **Define BAR Address Spaces** - **Steps**: 1. Ensure the BAR address spaces do not overlap and match the donor device's memory layout. 2. Use the recorded BAR sizes to set the address ranges appropriately. ```verilog bar0_addr <= 32'hF0000000; // Example address; replace with donor's BAR0 address bar1_addr <= 32'hF0004000; // Example address; replace as needed ``` 3. **Handle Multiple BARs** - **Steps**: 1. If the donor device uses multiple BARs, repeat the configuration for each BAR. 2. Ensure each BAR's size and address align with the donor device's specifications. ### **8.3 Emulating Device Power Management and Interrupts** Properly emulating power management and interrupt handling ensures the host system interacts seamlessly with the emulated device. 1. **Power Management (PM) Configuration** - **Steps**: 1. In `pcileech_pcie_cfg_a7.sv`, locate the Power Management capability settings. 2. Set the PM capabilities to match the donor device. ```verilog PM_CAP_VERSION <= 4'b0011; // Example version; replace with donor's PM version PM_CAP_D1SUPPORT <= 1'b1; // Enable D1 support if the donor does PM_CAP_AUXCURRENT <= 4'b1000; // Example value; adjust as per donor PM_CSR_NOSOFTRST <= 1'b0; // Example value; adjust as needed ``` 2. **MSI/MSI-X (Interrupts) Configuration** - **Steps**: 1. Locate MSI/MSI-X configuration in `pcileech_pcie_cfg_a7.sv`. 2. Enable and configure MSI/MSI-X to handle interrupts correctly. ```verilog MSI_CAP_64_BIT_ADDR_CAPABLE <= 1'b1; // Enable 64-bit MSI if supported cfg_interrupt <= 1'b1; // Enable MSI interrupts ``` 3. **Implementing Interrupt Handling Logic** - **Steps**: 1. In `pcileech_pcie_cfg_a7.sv`, ensure the interrupt signals are correctly routed. ```verilog assign cfg_interrupt_di = cfg_int_di; assign cfg_interrupt_assert = cfg_int_assert; ``` 2. Test interrupt functionality to ensure the host system correctly receives and handles interrupts from the emulated device. --- ## **9. Emulating Device-Specific Capabilities** To achieve a true 1:1 emulation, it's essential to replicate the unique capabilities of the donor device beyond basic PCIe interactions. ### **9.1 Implementing Advanced PCIe Capabilities** Most PCIe devices support advanced features like **Advanced Error Reporting (AER)**, **Link Speed Negotiation**, and **Extended Capabilities**. Emulating these ensures the host system perceives the emulated device as identical to the donor. 1. **Advanced Error Reporting (AER)** - **Steps**: 1. In `pcileech_pcie_cfg_a7.sv`, locate AER configurations. 2. Enable AER if supported by the donor device. ```verilog AER_CAP_VERSION <= 4'b0001; // Example version; replace with donor's AER version AER_CAP_NEXTPTR <= 8'h00; // Set next pointer appropriately ``` 3. Implement error handling logic to manage AER-related events. 2. **Link Speed Negotiation** - **Steps**: 1. Ensure the PCIe link speed and width negotiation matches the donor device. 2. Adjust link speed settings as previously outlined in **8.1**. 3. **Extended Capabilities** - **Steps**: 1. Identify any extended capabilities used by the donor device (e.g., Vendor-Specific Extended Capabilities, LTR, VSEC). 2. Implement these capabilities within `pcileech_pcie_cfg_a7.sv` by defining the appropriate registers and logic. ```verilog // Example for Vendor-Specific Extended Capability VSEC_CAP_ID <= 16'hXXXX; // Replace XXXX with vendor-specific ID VSEC_CAP_VERSION <= 8'hYY; // Replace YY with version VSEC_CAP_NEXTPTR <= 8'hZZ; // Next capability pointer ``` ### **9.2 Emulating Vendor-Specific Features** Some devices incorporate proprietary or vendor-specific features that must be accurately emulated to ensure seamless integration. 1. **Identify Vendor-Specific Features** - **Steps**: 1. Use PCIe traffic analysis tools (e.g., Wireshark, Teledyne LeCroy) to monitor vendor-specific TLPs. 2. Document unique registers, commands, or behaviors exhibited by the donor device. 2. **Implementing Vendor-Specific Logic** - **Steps**: 1. In `pcileech_pcie_cfg_a7.sv`, add logic to handle vendor-specific features. ```verilog // Example: Vendor-Specific Register vendor_specific_reg <= 32'hXXXXXXXX; // Replace with actual value ``` 2. Ensure that any proprietary commands or responses are accurately replicated. 3. **Testing Vendor-Specific Features** - **Steps**: 1. Use vendor-specific drivers or applications to interact with the emulated device. 2. Verify that all proprietary features function as expected. --- ## **10. Transaction Layer Packet (TLP) Emulation** Accurate emulation of Transaction Layer Packets (TLPs) is vital for ensuring the FPGA-based device communicates seamlessly with the host system, mimicking the behavior of the donor device. ### **10.1 Understanding and Capturing TLPs** TLPs are the fundamental units of PCIe communication, handling memory reads/writes, configuration accesses, and interrupt signaling. 1. **Capture TLPs from the Donor Device** - **Steps**: 1. Use PCIe analysis tools like **Teledyne LeCroy’s Telescan PE** or **Wireshark** with PCIe support to monitor TLPs generated by the donor device. 2. Record the structure, types, and patterns of TLPs used by the donor device during typical operations. 2. **Analyze TLP Structure** - **Components of a TLP**: - **Header Fields**: Define the type, format, address, and other control information. - **Data Payload**: The actual data being transferred. - **Tail Fields**: Additional information such as byte counts and sequence numbers. - **Example TLP Structure**: ```verilog tlps_static.tdata[127:0] = {TLP header fields, Data Payload}; ``` 3. **Emulating Legitimate Traffic** - **Steps**: 1. Ensure that TLPs generated by the FPGA match those captured from the donor device in terms of type, address, length, and data. 2. Implement logic to handle different types of TLPs, such as memory writes, memory reads, and configuration accesses. ### **10.2 Crafting Custom TLPs for Specific Operations** To accurately mimic the donor device, you must craft custom TLPs that replicate its behavior during various operations. 1. **Memory Write TLP Example** - **Description**: Represents a write operation to system memory. - **Verilog Example**: ```verilog tlp_mem_write <= { 1'b0, // Reserved 7'b10_00000, // TLP Type: Memory Write 1'b0, // TLP Format address[31:0], // Address being written to data[31:0] // Data payload }; ``` 2. **Memory Read TLP Example** - **Description**: Represents a read operation from system memory. - **Verilog Example**: ```verilog tlp_mem_read <= { 1'b0, // Reserved 7'b00_00000, // TLP Type: Memory Read 1'b0, // TLP Format address[31:0], // Address being read from tag[7:0] // Tag for transaction identification }; ``` 3. **Configuration Access TLP Example** - **Description**: Represents a configuration space access. - **Verilog Example**: ```verilog tlp_config_access <= { 1'b0, // Reserved 7'b01_00000, // TLP Type: Configuration Read/Write 1'b0, // TLP Format config_address[31:0], // Configuration space address config_data[31:0] // Configuration data payload }; ``` 4. **Interrupt Signaling TLP Example** - **Description**: Represents an interrupt signaling to the CPU. - **Verilog Example**: ```verilog tlp_interrupt <= { 1'b0, // Reserved 7'b11_00000, // TLP Type: Interrupt 1'b0, // TLP Format interrupt_address[31:0], // Address related to the interrupt interrupt_data[31:0] // Interrupt data payload }; ``` 5. **Implement TLP Handlers** - **Steps**: 1. In your firmware, implement handlers for different TLP types to ensure correct processing and response. 2. Use state machines or logic blocks to manage TLP generation, processing, and response handling. --- ## **11. Building, Flashing, and Testing** After customizing the firmware and ensuring all configurations align with the donor device, proceed to build, flash, and test the firmware on your FPGA device. ### **11.1 Synthesis and Implementation** 1. **Run Synthesis** - **Steps**: 1. In Vivado, click on **Run Synthesis**. 2. Monitor the synthesis process for any warnings or errors. 3. Address any critical issues before proceeding. 2. **Run Implementation** - **Steps**: 1. After successful synthesis, initiate **Run Implementation**. 2. Ensure that the implementation phase completes without critical warnings. 3. Review the implementation report for any potential issues. 3. **Generate Bitstream** - **Steps**: 1. Once implementation is complete, click on **Generate Bitstream**. 2. Confirm any prompts to generate the bitstream. 3. Wait for the bitstream generation to finish successfully. ### **11.2 Flashing the Bitstream** 1. **Connect FPGA via JTAG** - **Steps**: 1. Ensure your FPGA device is connected to the host system via the JTAG interface. 2. Power on the FPGA device. 2. **Open Vivado Hardware Manager** - **Steps**: 1. In Vivado, navigate to **Window > Hardware Manager**. 2. Click **Open Target > Auto Connect** to detect the connected FPGA device. 3. **Program the FPGA** - **Steps**: 1. In the Hardware Manager, right-click on the detected device and select **Program Device**. 2. Browse to the generated bitstream file (`pcileech_squirrel_top.bit`). 3. Click **Program** to flash the firmware onto the FPGA. 4. Confirm successful programming via the Hardware Manager console. ### **11.3 Testing and Validation** 1. **Verify Device Detection** - **Steps**: 1. Use **lspci** (on Linux) or **Device Manager** (on Windows) to verify that the FPGA is detected as the donor device. 2. Confirm that the **Device ID**, **Vendor ID**, **Subsystem ID**, and **BARs** match the donor device's specifications. - **Example (Linux)**: ```bash lspci -vvv -s ``` 2. **Memory Mapping Test** - **Steps**: 1. Access the device's **BARs** to ensure correct memory mapping. 2. Use memory access tools or simple read/write operations to test responsiveness. 3. **Interrupts Test** - **Steps**: 1. Trigger interrupts through the emulated device. 2. Verify that the host system correctly receives and handles these interrupts. 3. Use system logs or diagnostic tools to confirm interrupt handling. 4. **Performance Testing** - **Steps**: 1. Run DMA speed test tools to measure data transfer rates. 2. Compare performance metrics against expected values to ensure firmware stability and efficiency. - **Example Tools**: - **PCILeech DMA Speed Test**: Available within the PCILeech toolset. - **Custom Benchmark Scripts**: Scripts that perform read/write operations to measure performance. 5. **Configuration Space Validation** - **Steps**: 1. Use diagnostic tools to inspect the PCIe configuration space. 2. Ensure all fields (Device ID, Vendor ID, BARs, Capabilities) are correctly set and match the donor device. - **Example (Linux)**: ```bash lspci -vvv -s ``` --- ## **12. Advanced Debugging Techniques** When developing custom firmware, encountering issues is common. Advanced debugging techniques can help identify and resolve these problems effectively. ### **12.1 Using Vivado's Integrated Logic Analyzer** Vivado's **Integrated Logic Analyzer (ILA)** allows real-time monitoring of internal FPGA signals, aiding in debugging and verification. 1. **Set Up ILA Probes** - **Steps**: 1. In Vivado, navigate to **Sources > Add Sources** and add an **Integrated Logic Analyzer**. 2. Insert ILA probes at critical points in the PCIe communication path, such as TLP generators or BAR access controllers. ```verilog // Example: Adding ILA probe for TLP data wire [127:0] tlp_data; assign tlp_data = tlps_static.tdata[127:0]; ila_0 probe ( .clk(clk), .probe0(tlp_data) ); ``` 2. **Configure Triggers** - **Steps**: 1. Open the **ILA** configuration dialog. 2. Set trigger conditions based on specific events, such as TLP generation or memory access. ```verilog // Example trigger condition: Start of memory write TLP if (tlp_type == MEMORY_WRITE && tlp_valid) begin trigger_signal <= 1; end ``` 3. **Analyze Signal Waveforms** - **Steps**: 1. Run the FPGA with the ILA probes enabled. 2. Use Vivado’s **Waveform Viewer** to examine captured signal waveforms. 3. Identify timing issues, incorrect logic states, or unexpected behaviors. - **Benefits**: - Real-time visibility into internal signals. - Ability to capture and analyze transient issues during TLP processing. ### **12.2 PCIe Traffic Analysis Tools** Beyond Vivado's ILA, external PCIe traffic analysis tools provide in-depth insights into PCIe communications between the FPGA and the host system. 1. **Wireshark with PCIe Extensions** - **Description**: Wireshark can capture and analyze PCIe traffic with the appropriate extensions or plugins. - **Steps**: 1. Install Wireshark with PCIe support. 2. Configure Wireshark to capture PCIe traffic. 3. Analyze captured TLPs to ensure they align with expected donor device behavior. 2. **Teledyne LeCroy Telescan PE** - **Description**: A professional-grade PCIe traffic analysis tool offering comprehensive PCIe traffic monitoring and analysis capabilities. - **Steps**: 1. Install Teledyne LeCroy’s Telescan PE. 2. Connect it to your system to monitor PCIe traffic. 3. Use it to capture and dissect TLPs exchanged between the FPGA and host system. 3. **Total Phase Beagle** - **Description**: A PCIe traffic analyzer that allows for real-time capture and analysis of PCIe communications. - **Steps**: 1. Set up the Total Phase Beagle PCIe analyzer with your system. 2. Configure it to monitor and capture PCIe traffic. 3. Use its analysis features to verify TLP integrity and behavior. **Benefits of Using PCIe Traffic Analysis Tools**: - **Comprehensive TLP Analysis**: Detailed inspection of TLPs to ensure accurate emulation. - **Error Detection**: Identify malformed TLPs or unexpected transaction patterns. - **Performance Metrics**: Measure data transfer rates and identify bottlenecks. --- ## **13. Troubleshooting** Encountering issues during firmware development is common. This section provides solutions to common problems you may face during the emulation process. ### **13.1 Device Detection Issues** **Problem**: The host system fails to detect the FPGA as the donor device. **Solutions**: 1. **Verify Device IDs** - **Steps**: 1. Double-check that the **Device ID**, **Vendor ID**, and **Subsystem ID** in the firmware match those of the donor device. 2. Ensure there are no typos or incorrect values in the configuration space. 2. **Check PCIe Link Training** - **Steps**: 1. Use PCIe diagnostic tools to verify that the PCIe link is properly trained. 2. Ensure that the link speed and width configurations match the donor device. 3. **Ensure Correct BAR Configuration** - **Steps**: 1. Confirm that the **BAR sizes** and **address ranges** are accurately set. 2. Ensure no overlapping or conflicting BAR configurations. 4. **Power and Connection Check** - **Steps**: 1. Ensure the FPGA device is properly connected and powered. 2. Re-seat the PCIe card to ensure a secure connection. ### **13.2 Memory Mapping and BAR Configuration Errors** **Problem**: Incorrect memory mapping leads to failed or inaccurate memory access. **Solutions**: 1. **Double-Check BAR Sizes and Addresses** - **Steps**: 1. Verify that each BAR size in the firmware matches the donor device's configuration. 2. Ensure that BAR address spaces are correctly set and do not overlap. 2. **Use Diagnostic Tools** - **Steps**: 1. Utilize tools like **lspci** or **Arbor** to inspect the PCIe configuration space. 2. Confirm that the BARs are correctly mapped and accessible. 3. **Adjust Memory Regions** - **Steps**: 1. If memory regions are not accessible, adjust the BAR configurations to better match the system's memory map. 2. Ensure that the firmware logic correctly handles memory read/write operations. ### **13.3 DMA Performance and TLP Errors** **Problem**: Slow DMA performance or errors related to Transaction Layer Packets (TLPs). **Solutions**: 1. **Optimize TLP Generation** - **Steps**: 1. Ensure that TLPs are correctly formatted and free of errors. 2. Use Vivado’s ILA and PCIe traffic analysis tools to identify and rectify malformed TLPs. 2. **Adjust Payload Sizes** - **Steps**: 1. Set the maximum read request and payload sizes to 4KB or the highest supported by the donor device. ```verilog max_read_request_size <= 4; // 4KB max_payload_size <= 4; // 4KB ``` 2. Avoid setting payload sizes beyond what the donor device supports to prevent system instability. 3. **Check PCIe Link Settings** - **Steps**: 1. Verify that the PCIe link speed and width are correctly configured. 2. Ensure that the FPGA is negotiating the link parameters accurately with the host system. 4. **Firmware Integrity** - **Steps**: 1. Review and validate all recent changes to the firmware to ensure no unintended modifications were introduced. 2. Revert to a known stable firmware version if performance issues persist. --- ## **14. Emulation Accuracy and Optimizations** Ensuring the emulation's accuracy is critical for seamless integration and undetectable behavior. This section outlines techniques to enhance emulation precision and optimize performance. ### **14.1 Techniques for Accurate Timing Emulation** Matching the donor device's timing characteristics ensures that the host system interacts with the emulated device as if it were the original hardware. 1. **Use Matching Clock Domains** - **Steps**: 1. Ensure that the FPGA’s clock matches the PCIe link’s clock rate. 2. Synchronize internal clocks within the FPGA to align with PCIe timing requirements. 2. **Control Response Latency** - **Steps**: 1. Implement registers or counters to manage response times for TLP acknowledgments and interrupt handling. 2. Ensure that the latency in responses matches the donor device’s typical response times. 3. **Implement Pipeline Stages** - **Steps**: 1. Use pipelining in the FPGA design to align with the donor device’s data processing stages. 2. This reduces latency and ensures timely TLP generation and processing. ### **14.2 Dynamic Response to System Calls** Emulating dynamic device behavior based on system interactions ensures the FPGA device responds appropriately under various conditions. 1. **Implement State Machines** - **Steps**: 1. Design state machines within the FPGA to manage different operational states of the emulated device. 2. Ensure transitions between states mimic the donor device’s behavior based on system calls and interactions. 2. **Track and Respond to System Requests** - **Steps**: 1. Monitor incoming system requests and adjust the device’s responses dynamically. 2. Ensure that the FPGA firmware can handle varying workloads and respond accurately to different types of TLPs. 3. **Handle Asynchronous Events** - **Steps**: 1. Implement logic to manage asynchronous events such as interrupts or error conditions. 2. Ensure that the firmware can generate and respond to these events in a manner consistent with the donor device. --- ## **15. Best Practices for Firmware Development** Adhering to best practices ensures the development process is efficient, maintainable, and secure. ### **15.1 Continuous Testing and Documentation** - **Test Frequently** - **Steps**: 1. Conduct regular tests after each modification to ensure the firmware behaves as expected. 2. Use automated scripts or test benches to validate firmware functionality continuously. - **Document Changes** - **Steps**: 1. Maintain detailed documentation for each change made to the firmware. 2. Include explanations for why changes were made and their impact on the overall design. ### **15.2 Managing Firmware Versioning** - **Use Version Control** - **Steps**: 1. Implement a version control system (e.g., **Git**) to manage different iterations of the firmware. 2. Commit changes regularly with descriptive messages to track the evolution of the project. - **Branching Strategy** - **Steps**: 1. Use branches to manage feature development, bug fixes, and experimental changes. 2. Merge stable branches into the main branch only after thorough testing. ### **15.3 Security Considerations** - **Prevent Unintended Access** - **Steps**: 1. Ensure that the firmware does not expose system memory or hardware to unauthorized access. 2. Implement access controls and validation checks within the firmware. - **Protect Firmware Integrity** - **Steps**: 1. Avoid introducing vulnerabilities or backdoors during firmware development. 2. Conduct regular security reviews and code audits to maintain firmware integrity. - **Handle Sensitive Data Securely** - **Steps**: 1. If the firmware interacts with sensitive data, implement encryption and secure data handling practices. 2. Ensure that sensitive information is not exposed through firmware interfaces or logs. --- ## **16. Additional Resources** To further enhance your understanding and capabilities in developing custom firmware for device emulation, the following resources are invaluable: - **PCILeech-FPGA Repository** - **Link**: [https://github.com/ufrisk/pcileech-fpga](https://github.com/ufrisk/pcileech-fpga) - **Vivado FPGA Documentation** - **Link**: [Xilinx Vivado Documentation](https://www.xilinx.com/support/documentation.html) - **PCI-SIG Specifications** - **Link**: [PCI-SIG](https://pcisig.com) - **PCIe TLP Primer Tutorial** - **Link**: [PCIe TLP Primer](https://www.xillybus.com/tutorials/pci-express-tlp-pcie-primer-tutorial-guide-1) - **Teledyne LeCroy Telescan PE Documentation** - **Link**: [Teledyne LeCroy Telescan PE](https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software) - **Wireshark PCIe Extensions** - **Link**: [Wireshark Extensions](https://www.wireshark.org/docs/) - **Field Programmable Gate Array (FPGA) Basics** - **Link**: [FPGA Basics](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2020_2/ug901-vivado-tutorial.pdf) - **Arbor Software User Guide** - **Link**: [Arbor User Guide](https://www.mindshare.com/software/Arbor) - **PCIe Specifications and Guides** - **Link**: [PCIe Specifications](https://pcisig.com/specifications) ================================================ FILE: README.md ================================================ # **Custom Firmware Development Guide for Full Device Emulation** --- **Shout out to the legend that donated, I will be in contact soon. I will add a shoutout here if you want + more just DM me if you haven't already!** Working on organizing this into a [wiki](https://github.com/JPShag/PCILeech-DMA-Firmware/wiki/Introduction). Help is welcomed! ---- **A Note from the Author & Guide Status:** I'm sharing this transparently, as recent times have been incredibly challenging. Beyond a significant financial setback from a fraudulent chargeback, I've faced multiple other difficult living and health problems that have severely impacted my ability to be online and dedicate time to projects. Frankly, continuing to create comprehensive resources like this guide has been a profound struggle amidst these personal difficulties. This is anticipated to be the final major iteration of the main guide. For more experienced users already familiar with fundamental hardware concepts (e.g., the function of an FTDI chip), a concise, minified version will also be made available. If you find this work valuable and are in a position to help, any form of support would be profoundly appreciated. Your generosity enables me to continue contributing to this community despite the ongoing challenges. I sincerely hope this guide has been and continues to be a valuable resource. --- ## In Memoriam & Dedication ![Ross](https://github.com/user-attachments/assets/de7f12fe-8992-4738-a6af-712dc48217ee) This guide is humbly dedicated to the memory of **Ross Freeman (1947–1989)** A visionary engineer, pioneering Michigander, and co-founder of Xilinx, Ross Freeman is widely recognized as the father of Field-Programmable Gate Array (FPGA) technology, which revolutionized computing. In 1984, at a time when the semiconductor industry predominantly focused on fixed-function chips, Freeman dared to imagine a different paradigm: hardware that could be reprogrammed after manufacturing. His revolutionary patent (#4,870,302) and tireless advocacy for reconfigurable computing unlocked a technological paradigm that continues to transform our world four decades later. His groundbreaking innovation enabled the rapid prototyping and deployment of custom silicon solutions without the prohibitive costs of traditional ASIC development, democratizing hardware design and accelerating technological progress across countless domains. Today, Freeman's vision powers cutting-edge advancements in artificial intelligence, high-performance computing, telecommunications, automotive systems, aerospace applications, and numerous other fields that were merely dreams during his lifetime. Posthumously inducted into the National Inventors Hall of Fame in 2009, his legacy endures not merely in silicon, but in the spirit of technological audacity that challenges us all to question established limitations and imagine new possibilities. *"The ultimate goal of the FPGA was to make programmable logic devices that could replace standard digital chips."* — Ross Freeman --- ## **Table of Contents** ### **Part 1: Foundational Concepts** 1. [Introduction](#1-introduction) * [1.1 Purpose of the Guide](#11-purpose-of-the-guide) * [1.2 Target Audience](#12-target-audience) * [1.3 How to Use This Guide](#13-how-to-use-this-guide) 2. [Key Definitions](#2-key-definitions) 3. [Device Compatibility](#3-device-compatibility) * [3.1 Supported FPGA-Based Hardware](#31-supported-fpga-based-hardware) * [3.2 PCIe Hardware Considerations](#32-pcie-hardware-considerations) * [3.3 System Requirements](#33-system-requirements) 4. [Requirements](#4-requirements) * [4.1 Hardware](#41-hardware) * [4.2 Software](#42-software) * [4.3 Environment Setup](#43-environment-setup) 5. [Gathering Donor Device Information](#5-gathering-donor-device-information) * [5.1 Using Arbor for PCIe Device Scanning](#51-using-arbor-for-pcie-device-scanning) * [5.2 Extracting and Recording Device Attributes](#52-extracting-and-recording-device-attributes) 6. [Initial Firmware Customization](#6-initial-firmware-customization) * [6.1 Modifying Configuration Space](#61-modifying-configuration-space) * [6.2 Inserting the Device Serial Number (DSN)](#62-inserting-the-device-serial-number-dsn) 7. [Vivado Project Setup and Customization](#7-vivado-project-setup-and-customization) * [7.1 Generating Vivado Project Files](#71-generating-vivado-project-files) * [7.2 Modifying IP Blocks](#72-modifying-ip-blocks) ### **Part 2: Intermediate Concepts and Implementation** 8. [Advanced Firmware Customization](#8-advanced-firmware-customization) * [8.1 Configuring PCIe Parameters for Emulation](#81-configuring-pcie-parameters-for-emulation) * [8.2 Adjusting BARs and Memory Mapping](#82-adjusting-bars-and-memory-mapping) * [8.3 Emulating Device Power Management and Interrupts](#83-emulating-device-power-management-and-interrupts) 9. [Emulating Device-Specific Capabilities](#9-emulating-device-specific-capabilities) * [9.1 Implementing Advanced PCIe Capabilities](#91-implementing-advanced-pcie-capabilities) * [9.2 Emulating Vendor-Specific Features](#92-emulating-vendor-specific-features) 10. [Transaction Layer Packet (TLP) Emulation](#10-transaction-layer-packet-tlp-emulation) * [10.1 Understanding and Capturing TLPs](#101-understanding-and-capturing-tlps) * [10.2 Crafting Custom TLPs for Specific Operations](#102-crafting-custom-tlps-for-specific-operations) ### **Part 3: Advanced Techniques and Optimization** 11. [Building, Flashing, and Testing](#11-building-flashing-and-testing) * [11.1 Synthesis and Implementation](#111-synthesis-and-implementation) * [11.2 Flashing the Bitstream](#112-flashing-the-bitstream) * [11.3 Testing and Validation](#113-testing-and-validation) 12. [Advanced Debugging Techniques](#12-advanced-debugging-techniques) * [12.1 Using Vivado's Integrated Logic Analyzer](#121-using-vivados-integrated-logic-analyzer) * [12.2 PCIe Traffic Analysis Tools](#122-pcie-traffic-analysis-tools) 13. [Troubleshooting](#13-troubleshooting) * [13.1 Device Detection Issues](#131-device-detection-issues) * [13.2 Memory Mapping and BAR Configuration Errors](#132-memory-mapping-and-bar-configuration-errors) * [13.3 DMA Performance and TLP Errors](#133-dma-performance-and-tlp-errors) 14. [Emulation Accuracy and Optimizations](#14-emulation-accuracy-and-optimizations) * [14.1 Techniques for Accurate Timing Emulation](#141-techniques-for-accurate-timing-emulation) * [14.2 Dynamic Response to System Calls](#142-dynamic-response-to-system-calls) 15. [Best Practices for Firmware Development](#15-best-practices-for-firmware-development) * [15.1 Continuous Testing and Documentation](#151-continuous-testing-and-documentation) * [15.2 Managing Firmware Versioning](#152-managing-firmware-versioning) * [15.3 Security Considerations](#153-security-considerations) 16. [Additional Resources](#16-additional-resources) 17. [Contact Information](#17-contact-information) 18. [Support and Contributions](#18-support-and-contributions) --- ## **Part 1: Foundational Concepts** --- ## **1. Introduction** ### **1.1 Purpose of the Guide** The overarching goal of this guide is to empower you with the knowledge and practical skills to develop custom Direct Memory Access (DMA) firmware for Field-Programmable Gate Array (FPGA)-based devices. This specialized firmware allows your FPGA to accurately emulate the identity and behavior of other PCIe (Peripheral Component Interconnect Express) hardware devices. Such emulation is a powerful technique with profound implications across several advanced domains: **Hardware Security Research**: * **Vulnerability Discovery**: By emulating a device, you can create a controlled environment to send malformed or unexpected data to host drivers, systematically fuzzing for vulnerabilities (e.g., buffer overflows, race conditions) that might be exploitable from a hardware peripheral. * **Driver Analysis**: Observe how operating systems and specific drivers interact with hardware. You can emulate devices with non-standard configurations or undocumented features to understand driver behavior, identify security assumptions, or reverse-engineer proprietary protocols. * **Side-Channel Analysis**: While more complex, an emulated device could potentially be programmed to assist in experiments related to information leakage through timing or power analysis, by precisely controlling peripheral operations. **Red Teaming & Penetration Testing**: * **Bypassing Security Measures**: Emulate a seemingly benign or whitelisted hardware device (e.g., a common NIC or storage controller) to gain DMA privileges. Once achieved, this allows direct interaction with system memory, potentially bypassing endpoint detection and response (EDR) systems or anti-malware solutions that operate at higher software layers. * **Stealthy Persistence**: An emulated malicious device could offer a covert way to maintain access to a compromised system, as it might be harder to detect than software-based implants. * **Exploiting Trust Relationships**: Systems often have implicit trust in connected hardware. Custom firmware can exploit this by mimicking devices that are granted specific permissions or access. **System Debugging & Diagnostics**: * **Reproducible Testbeds**: Create highly specific hardware scenarios to reliably reproduce elusive bugs that may only occur with particular device states or data patterns. * **Fault Injection**: Intentionally emulate faulty device behavior (e.g., incorrect TLP formation, delayed responses) to test the robustness and error handling capabilities of the host system and its drivers. **Hardware Testing & Validation**: * **Driver Development**: Test new or modified drivers against an emulated hardware profile before physical prototypes are available, or to simulate a wider range of hardware variants than physically accessible. * **Compliance Testing**: While not a substitute for official compliance tests, an emulated device can help pre-verify certain aspects of PCIe protocol adherence. **Legacy System Support & Interoperability**: * Emulate older, discontinued, or hard-to-source PCIe devices to keep legacy systems operational or to bridge compatibility gaps between different hardware generations. By progressing through this guide, you will gain proficiency in: * Meticulously extracting identifying attributes and configuration details from a physical "donor" PCIe device. * Modifying and extending existing open-source FPGA firmware frameworks (with a primary focus on the widely-used PCILeech-FPGA project) to adopt the identity of the donor device. * Configuring and utilizing a professional FPGA development toolchain, centered around Xilinx Vivado, alongside essential code editing tools like Visual Studio Code. * Developing a solid understanding of the PCIe architecture's layered model, the mechanics of DMA data transfers, and the nuances of crafting firmware that faithfully replicates hardware behavior at a low level. ### **1.2 Target Audience** This guide is tailored for individuals who already possess a foundational to intermediate knowledge of computer systems, hardware principles, and software development. The content is technically demanding and assumes a capacity for detailed, low-level work. Specifically, it caters to: * **Firmware Developers**: Engineers aiming to design or adapt firmware for FPGAs, especially for applications involving high-speed data transfer (DMA) and direct hardware interface manipulation over PCIe. A background in Verilog/VHDL and experience with FPGA development tools are highly recommended. * **Hardware Engineers**: Professionals involved in the design, testing, or validation of PCIe-based hardware. This guide can help in creating sophisticated test harnesses or emulating components within a larger system design. Familiarity with PCIe protocol and digital design is expected. * **Cybersecurity Professionals & Researchers**: * **Vulnerability Researchers & Exploit Developers**: Those looking to explore hardware-level attack surfaces or develop proof-of-concept exploits leveraging DMA. Understanding of OS internals, memory management, and driver architecture is crucial. * **Red Team Members**: Operators seeking advanced techniques for system access, persistence, and data exfiltration by leveraging direct hardware manipulation. * **Digital Forensics & Incident Responders**: While this guide is offensively focused, understanding these techniques can aid in recognizing and analyzing sophisticated hardware-based attacks. * **FPGA Enthusiasts & Advanced Hobbyists**: Individuals with prior FPGA project experience who are eager to tackle complex challenges like PCIe communication and hardware emulation. A willingness to delve into datasheets and technical specifications is key. **Prerequisite Knowledge (Recommended)**: * Solid understanding of digital logic and computer architecture. * Familiarity with at least one Hardware Description Language (HDL), such as Verilog or VHDL. * Basic proficiency in a Linux environment (many tools and scripts are Linux-friendly) and familiarity with command-line interfaces. * Experience with a C/C++ or a scripting language (like Python) for host-side interaction or test scripting. * A conceptual understanding of operating system principles (memory management, drivers, interrupts). * Patience and a methodical approach to debugging, as firmware development can be intricate. The learning curve can be steep, especially if PCIe or advanced FPGA concepts are new. However, the guide aims to break down complex topics into manageable steps. ### **1.3 How to Use This Guide** This guide is segmented into three logically progressing parts designed to build your knowledge incrementally: * **Part 1: Foundational Concepts**: This initial part is crucial. It introduces the core terminology, the underlying principles of PCIe and DMA, the necessary hardware and software stack (including setup instructions for tools like Xilinx Vivado and the PCILeech-FPGA framework), and the initial procedures for acquiring vital information from your target "donor" device and making basic firmware modifications. It is strongly advised to work through this part sequentially and thoroughly. * **Part 2: Intermediate Concepts and Implementation**: (Forthcoming sections) Building on the foundation, this part will guide you through more advanced firmware customizations. Topics will include fine-tuning PCIe operational parameters, emulating device-specific registers and capabilities (such as power management states and Message Signaled Interrupts - MSI/MSI-X), and gaining an initial understanding of constructing and interpreting Transaction Layer Packets (TLPs). * **Part 3: Advanced Techniques and Optimization**: (Forthcoming sections) The final part will explore sophisticated debugging methodologies (including the use of Integrated Logic Analyzers - ILAs and external PCIe protocol analyzers), techniques for optimizing firmware performance and emulation accuracy, comprehensive troubleshooting for common and complex issues, and a critical discussion on best practices, particularly focusing on the security implications of developing and deploying emulated PCIe devices. **Working Through the Guide**: * **Sequential Progression**: Especially for Parts 1 and 2, follow the sections in order, as later concepts build upon earlier ones. * **Hands-On Practice**: This is a practical guide. Actively perform the setup steps, code modifications, and experiments on your own hardware. * **Adapt to Your Environment**: File paths, specific device IDs, and software versions may vary. Understand the concepts behind the instructions to adapt them to your particular setup. * **Consult External Resources**: The PCIe specification and FPGA documentation are your ultimate references. This guide simplifies and directs, but deep dives often require consulting primary sources. * **Iterative Development**: Firmware development is rarely linear. Expect to iterate, debug, and refine your designs. Use the troubleshooting sections and debugging techniques extensively. You will be working with HDLs (SystemVerilog in PCILeech-FPGA), FPGA synthesis and implementation tools (Vivado), and potentially host-side programming tools and PCIe analysis utilities. --- ## **2. Key Definitions** A solid grasp of the following terminology is essential for navigating the complexities of PCIe device emulation and custom firmware development. These terms will be used extensively throughout the guide. * **DMA (Direct Memory Access)**: * **Definition**: A fundamental feature of modern computer architectures that allows hardware peripherals (like network cards, GPUs, or your FPGA-based emulated device) to read from and write to the main system memory (RAM) directly, without involving the Central Processing Unit (CPU) for every byte transferred. * **Significance**: DMA is crucial for high-performance I/O operations. By offloading data transfer tasks from the CPU, it frees up the CPU to perform other computations, significantly improving overall system throughput and efficiency. In the context of this guide, your FPGA will leverage DMA to interact with the host system's memory, which is a powerful capability often targeted in security research and red teaming. * **PCIe (Peripheral Component Interconnect Express)**: * **Definition**: A high-speed serial computer expansion bus standard designed to replace older bus standards like PCI, PCI-X, and AGP. It uses a point-to-point topology, with separate serial links connecting each device to the root complex (typically part of the chipset or CPU). Communication occurs via packets. * **Significance**: PCIe is the dominant standard for connecting high-performance peripherals to motherboards. Understanding its protocol, layered architecture (Physical Layer, Data Link Layer, Transaction Layer), and configuration mechanisms is paramount for emulating any modern hardware device. * **TLP (Transaction Layer Packet)**: * **Definition**: The fundamental unit of data exchange at the Transaction Layer of the PCIe protocol. TLPs are responsible for conveying requests (e.g., memory read/write, I/O read/write, configuration read/write) and completions (responses to requests) between PCIe devices. Each TLP consists of a header, an optional data payload, and an optional End-to-End CRC (ECRC). * **Significance**: To emulate a device accurately, your FPGA firmware must be capable of correctly forming, transmitting, receiving, and interpreting TLPs that match the behavior of the donor device. Understanding TLP types, formats, and flow control is critical for advanced emulation. * **BAR (Base Address Register)**: * **Definition**: Located within a PCIe device's Configuration Space, BARs are special registers used by the device to request address space resources from the host system. A device can have up to six 32-bit BARs (or fewer, or pairs of 32-bit BARs can form 64-bit BARs). These registers define the starting addresses and sizes of memory-mapped I/O (MMIO) regions or I/O port regions that the device uses to expose its registers and internal memory to the host CPU. * **Significance**: When the host system enumerates a PCIe device, it reads the BARs to determine the device's memory and I/O requirements, then allocates and programs these BARs with the actual base addresses in the system's physical address map. Your emulated device must accurately define its BARs to match the donor device so that the host OS and drivers can interact with it correctly. * **FPGA (Field-Programmable Gate Array)**: * **Definition**: An integrated circuit (IC) that can be configured by a designer or customer after manufacturing – hence "field-programmable." FPGAs contain an array of programmable logic blocks and a hierarchy of reconfigurable interconnects that allow the blocks to be "wired together" to implement custom digital logic circuits. * **Significance**: FPGAs are the core hardware used in this guide. Their reconfigurable nature makes them ideal for emulating other hardware devices, as you can define the precise logic and interfaces required to mimic the donor device's PCIe presence and behavior. * **MSI/MSI-X (Message Signaled Interrupts / Message Signaled Interrupts Extended)**: * **Definition**: Mechanisms that allow a PCIe device to deliver interrupts to the CPU by writing a special message (a TLP, specifically a Memory Write TLP) to a system-defined memory address, rather than using dedicated physical interrupt lines (as in legacy PCI). MSI-X is an enhancement of MSI, offering more interrupt vectors and greater flexibility. * **Significance**: Most modern PCIe devices use MSI or MSI-X for more efficient and flexible interrupt handling. Accurate emulation often requires implementing the chosen interrupt mechanism of the donor device, including configuring the MSI/MSI-X capability structures and generating interrupt messages correctly. * **DSN (Device Serial Number)**: * **Definition**: A 64-bit globally unique identifier that can be optionally implemented by a PCIe device. If present, it's typically located in an extended capability structure within the device's Configuration Space. * **Significance**: While not all devices have a DSN, some drivers or management software might use it for unique identification, licensing, or tracking purposes. Emulating it correctly can be important for full transparency and avoiding detection of the emulated device. * **PCIe Configuration Space**: * **Definition**: A standardized 256-byte (for Type 0, endpoint devices) or 4KB address region associated with each PCIe function (a device can have multiple functions). This space contains vital information about the device, including its Vendor ID, Device ID, Class Code, Revision ID, BARs, capability pointers, and various status and control registers. It is accessed by the host system using special Configuration Read and Configuration Write TLPs. * **Significance**: The Configuration Space is the "identity card" of a PCIe device. The very first step in device emulation is to meticulously replicate the relevant parts of the donor device's Configuration Space in your FPGA firmware. The host system uses this information to identify, configure, and allocate resources to the device. * **Donor Device**: * **Definition**: The physical PCIe hardware device whose identity and behavior you aim to emulate on your FPGA. This device serves as the source for extracting configuration details (Vendor ID, Device ID, BAR settings, capabilities, etc.) and behavioral patterns. * **Significance**: The fidelity of your emulation directly depends on how accurately and completely you can gather and replicate the characteristics of the donor device. * **Root Complex (RC)**: * **Definition**: The entity in a PCIe hierarchy that connects the CPU and memory subsystem to the PCIe fabric. It generates PCIe transactions on behalf of the CPU and processes transactions initiated by downstream PCIe devices. It also performs the initial bus enumeration and configuration. * **Significance**: Your emulated device will primarily interact with the Root Complex (or switches connected to it) when communicating with the host system. * **Endpoint (EP)**: * **Definition**: A type of PCIe device that resides at the periphery of the PCIe fabric, consuming or producing data. Examples include network cards, graphics cards, storage controllers, and the FPGA device you will be programming. Endpoints request resources and initiate transactions to the Root Complex. * **Significance**: In this guide, your FPGA will be programmed to act as an Endpoint device, emulating a specific donor Endpoint. * **HDL (Hardware Description Language)**: * **Definition**: A specialized computer language used to describe the structure, design, and operation of electronic circuits, particularly digital logic circuits. Common HDLs include Verilog and VHDL. * **Significance**: You will be working with Verilog (specifically SystemVerilog, an extension of Verilog) within the PCILeech-FPGA project to define the custom logic for your emulated device. * **Bitstream**: * **Definition**: The final configuration file that is loaded onto an FPGA to program its logic blocks and interconnects, thereby implementing your custom hardware design. It's the compiled output from the FPGA development tools (like Xilinx Vivado). * **Significance**: Generating and flashing the correct bitstream is the ultimate step in deploying your custom firmware onto the FPGA. --- ## **3. Device Compatibility** Achieving successful and accurate PCIe device emulation hinges on ensuring your chosen FPGA-based hardware and host system configuration are fully compatible. This section details the supported FPGA platforms, critical PCIe hardware considerations, and the necessary system requirements to set up your development environment. ### **3.1 Supported FPGA-Based Hardware** While this guide provides a generic methodology adaptable to various FPGA-based DMA hardware, our primary examples and specific instructions will focus on **Xilinx 7-series FPGAs**, commonly found in open-source DMA boards due to their balance of performance and accessibility. The **Squirrel DMA (35T)** card is highlighted due to its popularity and well-documented compatibility with the PCILeech-FPGA framework. The core principles and techniques for customizing the PCIe IP core and developing hardware description language (HDL) logic are broadly applicable to the following FPGA families and specific boards: * **Squirrel (Artix-7 35T)** * **Description**: A widely available and cost-effective FPGA-based DMA device featuring the Xilinx Artix-7 35T FPGA. It offers sufficient logic resources and memory for standard memory acquisition tasks and a wide range of basic to intermediate device emulation projects. It's an excellent starting point for those new to FPGA-based DMA. * **Key Features**: Artix-7 offers a good performance-to-cost ratio, making it suitable for educational and research purposes. * **Enigma-X1 (Artix-7 75T)** * **Description**: A mid-tier FPGA offering enhanced logic and memory resources compared to the 35T, typically based on the Xilinx Artix-7 75T FPGA. This provides greater flexibility for more complex emulation scenarios, larger memory-mapped regions, or more intricate DMA operations that require additional FPGA fabric. * **Key Features**: Increased logic cells and Block RAM (BRAM) enable more sophisticated designs. * **ZDMA (Artix-7 100T)** * **Description**: A higher-performance Artix-7 100T-based FPGA, optimized for more demanding memory interactions and extensive reads/writes. This board is suitable for large-scale DMA solutions, high-throughput emulation, or projects that require significant on-chip memory. * **Key Features**: The 100T variant provides a substantial upgrade in resources, ideal for pushing the boundaries of emulation. * **Kintex-7 (K325T, K410T, etc.)** * **Description**: Representing an advanced tier, Kintex-7 FPGAs (e.g., K325T, K410T) offer robust capabilities for highly complex projects, large-scale DMA solutions, and applications requiring higher PCIe lane counts or speeds (e.g., Gen3 x8/x16). While more expensive, they provide significantly more logic, DSP slices, and memory, enabling the emulation of highly sophisticated and demanding donor devices. * **Key Features**: High-performance transceivers for faster PCIe generations, abundant logic and memory resources for complex designs. **Important Note on FPGA Families**: While the principles are similar, specific IP core configurations and clocking structures may vary slightly between different Xilinx 7-series FPGAs (Artix-7, Kintex-7, Zynq-7000 PS/PL). Always refer to the specific board's documentation and the Xilinx PCIe IP Core user guides for your chosen FPGA family. The PCILeech-FPGA project often provides board-specific Tcl scripts and source files to simplify this process. ### **3.2 PCIe Hardware Considerations** To ensure smooth and unrestricted operation of your FPGA-based DMA device for emulation, several PCIe-specific and host system features require careful consideration and, in some cases, modification. * **IOMMU / VT-d / AMD-Vi Settings** * **Recommendation**: For initial setup and testing, it is **highly recommended to disable IOMMU (Intel's Virtualization Technology for Directed I/O - VT-d) or AMD's equivalent (AMD-Vi)** in your system's BIOS/UEFI settings. * **Rationale**: IOMMUs are hardware components that provide memory management units for DMA-capable devices. They perform address translation, similar to a CPU's MMU, and can enforce memory access permissions. While crucial for security and virtualization (preventing a rogue device from accessing unauthorized memory regions), they *will* restrict your DMA device's access to system memory, potentially interfering with memory acquisition and device emulation. Disabling the IOMMU allows your DMA device unrestricted access, which is often necessary for advanced emulation and security research purposes. * **Location**: Typically found under "CPU Configuration," "Virtualization," "Advanced Settings," or "I/O Virtualization" in your BIOS/UEFI. * **Kernel DMA Protection (Windows) / Thunderbolt Security Level (Linux)** * **Recommendation (Windows)**: Disable **Kernel DMA Protection** features in modern Windows systems. This includes settings like **Virtualization-Based Security (VBS)** and **Memory Integrity (HVCI)**. These features leverage the IOMMU to prevent unauthorized DMA attacks from external peripherals connected via Thunderbolt or PCIe. * **Steps (Windows)**: * Access Windows Security settings: **Start > Settings > Privacy & security > Windows Security > Device security**. * Under "Core isolation," click "Core isolation details." * Turn off "Memory integrity." * You may also need to disable Secure Boot in BIOS/UEFI, as VBS often depends on it. * **Caution**: Disabling these features significantly **reduces your system's security posture**, making it vulnerable to various attacks, including those involving malicious DMA devices. This should only be done on a dedicated test system, not on your primary machine, and in a secure, isolated environment where you understand the risks. * **Recommendation (Linux/Thunderbolt)**: If using a system with Thunderbolt ports, understand and potentially adjust the **Thunderbolt Security Level** in your BIOS/UEFI. Lower security levels (e.g., "No Security," "User Authorization") are generally required for arbitrary Thunderbolt/PCIe devices to perform DMA without explicit host approval. * **PCIe Slot Requirements** * **Recommendation**: Use a compatible PCIe slot that physically matches the FPGA device's requirements. Most Artix-7-based DMA cards operate at PCIe Gen2 x1 or x4. * **Rationale**: * **Physical Fit**: An x1 card can fit into x1, x4, x8, or x16 slots, but an x4 card requires at least an x4 slot. * **Performance**: While an x4 card *might* work in an x1 slot (if the physical connector is open-ended or modified), it will operate at the x1 speed, severely limiting data transfer rates. For optimal performance and accurate emulation of a donor device's capabilities, ensure the FPGA board is installed in a slot that provides at least the *emulated* link width and speed (e.g., if you're emulating a Gen2 x4 device, use a Gen2 x4 slot on the host). * **Motherboard BIOS Settings**: Some motherboards allow configuration of PCIe slot speeds (e.g., forcing Gen1 or Gen2). Ensure these settings do not conflict with your desired emulation speed. ### **3.3 System Requirements** Setting up a robust development environment is key for efficient firmware development, synthesis, and debugging. * **Host System** * **Processor**: A modern multi-core CPU is essential for running FPGA development tools like Vivado, which are computationally intensive during synthesis and implementation. (e.g., Intel Core i5/i7/i9 or AMD Ryzen 5/7/9 equivalent, 8th generation or newer recommended). * **Memory (RAM)**: Minimum 16 GB RAM is strongly recommended; **32 GB or more is ideal** for complex FPGA designs, as Vivado can consume significant memory, especially during implementation. * **Storage**: A Solid-State Drive (SSD) with at least **200 GB of free space** is crucial. FPGA tool installations (Vivado alone can be 50+ GB), project files, and synthesis/implementation outputs can quickly consume disk space. The speed of an SSD dramatically reduces build times. * **Operating System**: * **Windows 10/11 (64-bit Professional or Enterprise edition)**: Widely supported by Xilinx Vivado and many hardware debugging tools. Remember the Kernel DMA Protection considerations. * **Compatible Linux Distribution (64-bit)**: Ubuntu LTS (Long Term Support) releases (e.g., 20.04, 22.04) are commonly used and well-supported for Vivado. Linux often provides a more flexible environment for scripting and low-level PCIe interaction tools. * **Peripheral Devices** * **JTAG Programmer**: Absolutely necessary for flashing the compiled bitstream onto your FPGA-based DMA card. Examples include Xilinx Platform Cable USB II, Digilent JTAG-HS3, or integrated JTAG programmers found on some development boards. Ensure it's compatible with your FPGA board and Vivado. * **PCIe Slot**: As discussed in Section 3.2, ensure your host system has an available and compatible PCIe slot for your DMA card. * **USB Port**: For connecting the JTAG programmer and potentially for a UART/serial console to your FPGA board for debug output. --- ## **4. Requirements** This section outlines the essential hardware and software components, along with the recommended environment setup, necessary to embark on custom firmware development for PCIe device emulation. Having these prerequisites in place before you begin will streamline your development process. ### **4.1 Hardware** * **Donor PCIe Device** * **Purpose**: This is the physical hardware device whose configuration and behavior you intend to emulate on your FPGA. It serves as the authoritative source for critical identification details, register values, and operational characteristics. * **Examples**: Common examples include a standard Network Interface Card (NIC), a SATA or NVMe storage controller, a USB controller, or any other generic PCIe expansion card that you can safely remove from a system for analysis. It is highly recommended to use a device that is *not* essential for the system's operation, as you will be inspecting its low-level configuration. * **DMA FPGA Card** * **Description**: An FPGA-based development board specifically designed or adapted to perform Direct Memory Access (DMA) operations over a PCIe interface. This is the platform onto which your custom firmware will be loaded. * **Examples**: As detailed in Section 3.1, compatible cards include the **Squirrel (Artix-7 35T)**, **Enigma-X1 (Artix-7 75T)**, **ZDMA (Artix-7 100T)**, or various **Kintex-7** based solutions. Ensure your chosen card has a PCIe edge connector. * **JTAG Programmer** * **Purpose**: This crucial tool facilitates the communication between your development PC and the FPGA on your DMA card. It's used to program (flash) the compiled bitstream onto the FPGA and, importantly, for interactive debugging using tools like Vivado's Hardware Manager and Integrated Logic Analyzer (ILA). * **Examples**: * **Xilinx Platform Cable USB II**: A traditional, widely compatible programmer for Xilinx FPGAs. Ensure you have the necessary drivers installed. * **Digilent JTAG-HS3 / JTAG-HS2**: Popular and reliable programmers known for good Vivado integration and support. The HS3 offers faster programming speeds. * **Integrated JTAG**: Some FPGA boards may have an onboard USB-to-JTAG bridge (e.g., a FTDI chip) which eliminates the need for a separate programmer. Consult your board's documentation. ### **4.2 Software** * **Xilinx Vivado Design Suite** * **Description**: The official, comprehensive FPGA development environment from Xilinx (now AMD). Vivado is essential for synthesizing your HDL code, implementing the design onto the target FPGA, generating the final bitstream, and performing hardware debugging. It includes the necessary IP cores, compilers, and utilities. * **Download**: Visit the official Xilinx (AMD) downloads page: [https://www.xilinx.com/support/download.html](https://www.xilinx.com/support/download.html). * **Version Note**: While older versions like Vivado 2020.1 might be referenced in some legacy guides, it is strongly recommended to download a **recent stable version** (e.g., Vivado 2023.x or later) compatible with your target FPGA family (Artix-7, Kintex-7). The PCILeech-FPGA project generally supports newer Vivado versions. * **Visual Studio Code** * **Description**: A highly customizable and feature-rich code editor from Microsoft. It's an excellent choice for writing and editing your Verilog/SystemVerilog HDL code due to its extensive extension ecosystem, offering features like syntax highlighting, linting, auto-completion, and version control integration. * **Download**: [https://code.visualstudio.com/](https://code.visualstudio.com/) * **PCILeech-FPGA** * **Description**: An open-source framework and base code repository for FPGA-based DMA development. It provides ready-to-use PCIe IP core instantiations and a well-structured project that serves as an excellent starting point for custom firmware. This guide heavily leverages its architecture. * **Repository**: [https://github.com/ufrisk/pcileech-fpga](https://github.com/ufrisk/pcileech-fpga) * **Arbor (MindShare)** * **Description**: A powerful and user-friendly software tool specifically designed for in-depth scanning and analysis of PCIe devices. It provides detailed insights into the configuration space, capabilities, and registers of connected PCIe hardware, making it invaluable for gathering donor device information. * **Download**: Available from the MindShare website: [https://www.mindshare.com/](https://www.mindshare.com/) (You will likely need to navigate to their software section). * **Note**: Typically requires account creation and may offer a time-limited trial. * **Alternative PCIe Device Analysis Tools** * **Telescan PE (Teledyne LeCroy)**: * **Description**: A no-cost utility from Teledyne LeCroy for PCIe traffic analysis and device enumeration. While it's primarily a software tool that interfaces with their hardware protocol analyzers, it can also provide some basic configuration space views without dedicated hardware. * **Download**: [https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software](https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software) * **Note**: Requires manual registration and approval for download. * **OS-Native Tools (For basic checks)**: * **Windows Device Manager**: Provides basic Vendor ID, Device ID, Subsystem ID, and Class Code information under the "Details" tab of a device's properties. * **Linux `lspci` utility**: A powerful command-line tool for inspecting PCIe devices. Use `lspci -nn` for Vendor/Device IDs, `lspci -vvv` for verbose details including BARs and capabilities, and `lspci -s -xxxx` for raw configuration space dumps. ### **4.3 Environment Setup** A clean and correctly configured development environment is crucial to avoid common pitfalls and ensure a smooth workflow. #### **4.3.1 Install Xilinx Vivado Design Suite** **Steps**: 1. **Visit the Xilinx (AMD) Vivado Download Page**: [https://www.xilinx.com/support/download.html](https://www.xilinx.com/support/download.html). 2. **Download the Appropriate Version**: Select the latest stable version of Vivado that is compatible with your operating system and, importantly, with your specific FPGA device (e.g., Artix-7, Kintex-7). Check the Vivado release notes for device support. 3. **Run the Installer**: Execute the downloaded installer and follow the on-screen instructions carefully. 4. **Select Necessary Components**: During installation, you will be prompted to select which device families to install. **Crucially, select the device family corresponding to your FPGA board (e.g., "7 Series" for Artix-7/Kintex-7).** This saves significant disk space compared to installing all families. Ensure you select the "Design Tools" (Synthesis, Implementation) and "Programming & Debugging" components. 5. **Launch Vivado**: After installation, launch Vivado to confirm it opens without errors and that licenses (if applicable) are correctly configured. #### **4.3.2 Install Visual Studio Code** **Steps**: 1. **Visit the Visual Studio Code Download Page**: [https://code.visualstudio.com/](https://code.visualstudio.com/). 2. **Download and Install**: Download the installer for your operating system and follow the standard installation prompts. 3. **Install Extensions for HDL Support**: Once VS Code is installed, open it and navigate to the Extensions view (Ctrl+Shift+X or Cmd+Shift+X). Search for and install relevant extensions for Verilog/SystemVerilog, such as: * **Verilog-HDL/SystemVerilog** (by mshr-h) * **VHDL** (if you also work with VHDL) These extensions provide syntax highlighting, linting, and other helpful features. #### **4.3.3 Clone the PCILeech-FPGA Repository** This repository contains the base firmware structure and scripts you'll be modifying. **Steps**: 1. **Open a Terminal or Command Prompt**: (e.g., Git Bash on Windows, Terminal on Linux). 2. **Navigate to Your Desired Directory**: Choose a location where you want to store your projects. ```bash cd ~/Projects/ # On Linux/macOS cd C:\Users\YourUsername\Documents\Projects\ # On Windows ``` 3. **Clone the Repository**: ```bash git clone https://github.com/ufrisk/pcileech-fpga.git ``` 4. **Navigate to the Cloned Directory**: ```bash cd pcileech-fpga ``` This will be your main project directory. The PCILeech-FPGA project often contains subdirectories for different board variants (e.g., `pcileech-artix-7-50t`, `pcileech-squirrel-35t`). You will navigate into the relevant board-specific directory for your particular hardware. #### **4.3.4 Set Up a Clean Development Environment** **Recommendation**: Always work in an isolated or dedicated environment, especially when dealing with low-level hardware and potential security implications. **Steps**: 1. **Use a Dedicated Development Machine or Virtual Machine**: * **Physical Machine**: If possible, use a separate physical computer for your FPGA development and testing. This prevents accidental system instability or security risks on your primary machine. * **Virtual Machine (VM)**: A VM can be a good option for isolating the development environment. However, direct PCIe passthrough (PCIe Hotplug or VT-d passthrough) to the VM is generally required for the FPGA card to be detected and operate correctly, which can be complex to configure and may still expose the host if not done carefully. For initial tool installation and code editing, a VM is perfectly fine. 2. **Minimize Background Applications**: Ensure no other resource-intensive applications are running that might interfere with Vivado's performance during synthesis and implementation. 3. **Disable Conflicting Software**: Temporarily disable any anti-virus, firewall, or security software that might interfere with low-level hardware access or JTAG communication during development and testing. Remember to re-enable them when you're done with your work. --- ## **5. Gathering Donor Device Information** Accurate device emulation hinges on meticulously extracting and replicating critical information from the donor device. This comprehensive data collection enables your FPGA to faithfully mimic the target hardware's PCIe configuration and behavior, ensuring compatibility and functionality when interfacing with the host system. ### **5.1 Using Arbor for PCIe Device Scanning** **Arbor** is a robust and user-friendly tool designed for in-depth scanning of PCIe devices. It provides detailed insights into the configuration space of connected hardware, making it an invaluable resource for extracting the necessary information for device emulation. #### **5.1.1 Install Arbor** To begin utilizing Arbor for device scanning, you must first install the software on your system. **Steps:** 1. **Visit the Arbor Download Page:** * Navigate to the official MindShare website ([https://www.mindshare.com/](https://www.mindshare.com/)) using your preferred web browser. You'll need to find their "Software" or "Downloads" section to locate Arbor. * Ensure you are accessing the site directly to avoid any malicious redirects. 2. **Create an Account (if required):** * Arbor may require you to create a user account to access the download links. * Provide the necessary information, such as your name, email address, and organization. * Verify your email if prompted, to activate your account. 3. **Download Arbor:** * Once logged in, locate the download section for Arbor. * Select the version compatible with your operating system (e.g., Windows 10/11 64-bit). * Click the **Download** button and save the installer to a known location on your computer. 4. **Install Arbor:** * Locate the downloaded installer file (e.g., `ArborSetup.exe`). * Right-click the installer and select **Run as administrator** to ensure it has the necessary permissions. * Follow the on-screen instructions to complete the installation process. * Accept the license agreement. * Choose the installation directory. * Opt to create desktop shortcuts if desired. 5. **Verify Installation:** * Upon completion, ensure that Arbor is listed in your Start Menu or on your desktop. * Launch Arbor to confirm it opens without errors. #### **5.1.2 Scan PCIe Devices** With Arbor installed, you can proceed to scan your system for connected PCIe devices. **Steps:** 1. **Launch Arbor:** * Double-click the Arbor icon on your desktop or find it via the Start Menu. * If prompted by User Account Control (UAC), allow the application to make changes to your device. 2. **Navigate to the Local System Tab:** * In the Arbor interface, locate the navigation pane or tabs. * Click on **Local System** to access tools for scanning the local machine. 3. **Scan for PCIe Devices:** * Look for a **Scan** or **Rescan** button, typically located at the top or bottom of the interface. * Click **Scan/Rescan** to initiate the detection process. * Wait for the scanning process to complete; this may take a few moments depending on the number of devices connected. 4. **Review Detected Devices:** * Once the scan is complete, Arbor will display a list of all detected PCIe devices. * The devices are usually listed with their names, device IDs, and other identifying information. #### **5.1.3 Identify the Donor Device** Identifying the correct donor device is crucial for accurate emulation. **Steps:** 1. **Locate Your Donor Device in the List:** * Scroll through the list of devices detected by Arbor. * Look for the device matching the make and model of your donor hardware. * Devices may be listed by their vendor names, device types, or function. 2. **Verify Device Details:** * Click on the device to select it. * Confirm that the **Device ID** and **Vendor ID** match those of your donor device. * **Tip:** These IDs are typically found in the device's documentation or on the manufacturer's website. For common devices, a quick web search for "\[Device Name] Vendor ID Device ID" often yields results. 3. **View Detailed Configuration:** * With the device selected, find and click on an option like **View Details** or **Properties**. * This will open a detailed view showing the device's configuration space and capabilities. 4. **Cross-Reference with Physical Hardware:** * If multiple similar devices are listed, cross-reference the **Slot Number** or **Bus Address** with the physical slot where the donor device is installed. This helps confirm you're analyzing the correct hardware. #### **5.1.4 Capture Device Data** Extracting detailed information from the donor device is essential for accurate emulation. **Information to Extract:** * **Device ID (0xXXXX):** A 16-bit identifier unique to the device model. * **Vendor ID (0xYYYY):** A 16-bit identifier assigned to the manufacturer. * **Subsystem ID (0xZZZZ):** Identifies the specific subsystem or variant (e.g., a specific model within a product line). * **Subsystem Vendor ID (0xWWWW):** Identifies the vendor of the subsystem (often the same as the main Vendor ID, but can differ for OEM versions). * **Revision ID (0xRR):** Indicates the hardware revision level of the device. * **Class Code (0xCCCCCC):** A 24-bit code that defines the primary function/type of device (e.g., `0x020000` for Ethernet Controller, `0x010802` for NVMe controller). This helps the OS load generic drivers. * **Base Address Registers (BARs):** * Registers defining the memory or I/O address regions the device uses. * Includes BAR0 through BAR5, each potentially 32 or 64 bits. For each BAR, note its **Type (Memory or I/O)**, **Bit Width (32-bit or 64-bit)**, **Size (e.g., 256 MB, 4KB)**, and **Prefetchable Status (Yes/No)**. This is crucial for memory mapping. * **Capabilities:** Lists supported features and their configurations, often found in a linked list structure within the configuration space. Examples include: * **PCIe Capability Structure**: PCIe Link Speed (e.g., Gen2, Gen3), Link Width (e.g., x1, x4), Max Payload Size, Max Read Request Size. * **MSI/MSI-X Capability Structure**: Information on Message Signaled Interrupts, including the number of vectors supported. * **Power Management Capability Structure**: Supported power states (D0, D1, D2, D3hot, D3cold). * **Device Serial Number (DSN):** A 64-bit unique identifier, if the device supports it (found in the "Device Serial Number" Extended Capability). Not all devices implement this. **Steps:** 1. **Navigate to the PCI Config Tab:** * Within the device's detailed view, find and select the **PCI Config** or **Configuration Space** tab. This typically presents a decoded view of the raw configuration space registers. 2. **Record Relevant Details:** * Carefully document each of the required fields listed above. * Use screenshots or copy the values into a text file, a dedicated spreadsheet, or a structured documentation format for accuracy. * Ensure hexadecimal values are noted correctly, including the `0x` prefix if used. 3. **Expand Capability Lists:** * Look for sections labeled **Capabilities** or **Advanced Features**. These are often clickable or expandable to reveal sub-sections. * Document each capability present and its relevant parameters (e.g., MSI message control, power state flags, current/max PCIe link settings). 4. **Examine BARs in Detail:** * Within the Configuration Space, locate the entries for BAR0 through BAR5. * For each active BAR, note its allocated size, whether it's Memory-mapped or I/O, its bit width (32-bit or 64-bit), and if it's prefetchable. This information is often presented clearly in Arbor's GUI. 5. **Save the Data for Reference:** * Compile all the extracted information into a well-organized document (e.g., a Markdown file, a `.txt` file, or an Excel spreadsheet). * Label each section clearly for easy reference during firmware customization. https://github.com/user-attachments/assets/0f192c29-d1ad-4e68-aa21-607976037218 ### **5.2 Extracting and Recording Device Attributes** After capturing the data, it's crucial to understand the significance of each attribute and ensure they've been accurately documented for successful emulation. **Ensure You Have Accurately Recorded the Following:** 1. **Device ID:** * **Purpose:** Uniquely identifies the specific model of the PCIe device. * **Usage in Emulation:** Essential for the host Operating System (OS) to correctly identify the emulated device and, crucially, to attempt to load the appropriate device driver. 2. **Vendor ID:** * **Purpose:** Identifies the manufacturer of the PCIe device. * **Usage in Emulation:** Used in conjunction with the Device ID to form a unique identifier (`VendorID:DeviceID`) that the OS uses to match the device to its corresponding driver. 3. **Subsystem ID and Subsystem Vendor ID:** * **Purpose:** These optional IDs allow for differentiation between variants of a device from the same vendor, or for OEM-specific versions where the main Vendor/Device ID might be generic. * **Usage in Emulation:** Important for emulating devices with multiple configurations or those supplied by an OEM, as the driver might specifically look for these values. 4. **Revision ID:** * **Purpose:** Indicates the hardware revision level of the device. * **Usage in Emulation:** Helps in identifying specific hardware versions that might require different drivers, firmware, or possess subtle behavioral differences. 5. **Class Code:** * **Purpose:** A 24-bit code that categorizes the device's general function (e.g., `0x020000` for an Ethernet controller, `0x010802` for an NVMe controller, `0x0C0300` for a USB host controller). It's composed of a Base Class, Sub-Class, and Programming Interface. * **Usage in Emulation:** Allows the OS to understand the device's general function and load a generic class driver if a specific vendor driver isn't found. This is crucial for initial device recognition. 6. **Base Address Registers (BARs):** * **Purpose:** Define the memory-mapped or I/O port address regions that the device uses for registers, internal buffers, or configuration space extensions. The host OS allocates physical addresses to these BARs during enumeration. * **Usage in Emulation:** Critical for mapping the emulated device's internal memory and registers into the host system's address space. The size, type (Memory/I/O, 32/64-bit), and prefetchability status of each BAR must be precisely matched to the donor device. 7. **Capabilities:** * **Purpose:** Lists the advanced features the device supports, such as advanced error reporting, power management, MSI/MSI-X, PCIe Advanced Capabilities (e.g., AER, VC/PF), etc. Each capability is defined by a structure with its own registers. * **Usage in Emulation:** Essential for accurately replicating how the donor device advertises its features and how the host system interacts with these features (e.g., interrupt delivery mechanisms, power state transitions, error reporting). 8. **Device Serial Number (DSN):** * **Purpose:** A unique 64-bit identifier for the device, typically an optional extended capability. * **Usage in Emulation:** While optional, some drivers or management applications might specifically query and rely on the DSN for identification, licensing, or security checks. Emulating this accurately can prevent detection of your device as a generic or modified peripheral. **Best Practices for Data Collection:** * **Organize the Data:** Create a structured document or spreadsheet. Use clear headings and subheadings for each attribute. A template can be beneficial. * **Include Units and Formats:** Always indicate units for sizes (e.g., MB, KB) and use consistent formatting for hexadecimal values (e.g., `0x1234`, `16'h1234`). * **Cross-Reference with Specifications (If Possible):** If available, consult the donor device's datasheet or publicly available specifications to verify values. This can help identify any discrepancies or unusual configurations not immediately obvious from a raw scan. * **Secure the Data:** Store the collected information securely. Be mindful that this data might contain proprietary or sensitive information. * **Understand "What's Missing":** Specialized tools like Arbor are excellent, but they may not capture every single nuance of complex, highly proprietary devices (e.g., specific vendor-defined registers outside standard configuration space). For advanced emulation, you might need to combine this information with reverse engineering of the donor device's drivers. --- ## **6. Initial Firmware Customization** With the donor device's information meticulously documented, the next critical phase involves customizing your FPGA's firmware to emulate the donor device accurately. This process begins by modifying key identification registers within the PCIe configuration space and ensuring that specific identifiers, like the Device Serial Number, are correctly integrated. ### **6.1 Modifying Configuration Space** The PCIe Configuration Space is a fundamental component that defines how the device is recognized and interacts with the host system during enumeration. Customizing this space to precisely match the donor device's profile is absolutely essential for successful emulation, allowing the host OS to load the correct driver and interact as expected. #### **6.1.1 Navigate to the Configuration File** The PCIe configuration space parameters are typically defined within a specific SystemVerilog (`.sv`) file in the PCILeech-FPGA project. This file synthesizes into the logic that configures the PCIe IP core and exposes the device's identity to the host. **Common Path for PCILeech-FPGA (Artix-7 based boards like Squirrel):** Locate the file responsible for configuring the PCIe parameters for your specific board. For many Artix-7 PCILeech variants, this will be: ``` pcileech-fpga//src/pcileech_pcie_cfg_a7.sv ``` * **Example (for Squirrel 35T)**: ``` pcileech-fpga/pcileech-squirrel-35t/src/pcileech_pcie_cfg_a7.sv ``` *Note: The actual folder name like `pcileech-squirrel-35t` might vary slightly based on the specific PCILeech-FPGA version or fork you cloned. Always navigate to the relevant board-specific subdirectory after cloning the main repository.* #### **6.1.2 Open the File in Visual Studio Code** Editing the configuration file requires a suitable code editor that supports syntax highlighting for SystemVerilog (or Verilog), making the code easier to read and modify. **Steps:** 1. **Launch Visual Studio Code:** * Click on the VS Code icon or find it via the Start Menu. 2. **Open the File:** * Use **File > Open File** or press `Ctrl + O` (or `Cmd + O` on macOS). * Navigate to the configuration file path identified in Section 6.1.1 (e.g., `pcileech-fpga/pcileech-squirrel-35t/src/pcileech_pcie_cfg_a7.sv`). * Select the file and click **Open**. 3. **Verify Syntax Highlighting:** * Ensure that the editor recognizes the `.sv` file extension and applies proper SystemVerilog syntax highlighting. If it doesn't, revisit Section 4.3.2 to ensure you've installed the recommended Verilog/SystemVerilog extensions for VS Code. 4. **Familiarize Yourself with the File Structure:** * Scroll through the file. You will typically find parameters defined using `localparam` or `reg` assignments, often with comments explaining their purpose. Look for sections where standard PCIe configuration registers (Vendor ID, Device ID, etc.) are defined and assigned. #### **6.1.3 Modify Device ID and Vendor ID** Updating these fundamental identifiers is the most crucial step for the host system to correctly recognize the emulated device as your donor. The Operating System relies heavily on the `Vendor ID` and `Device ID` pair to identify connected hardware and load the appropriate device driver. **Steps:** 1. **Search for `cfg_deviceid`:** * Use the search functionality (`Ctrl + F` or `Cmd + F`) within VS Code. * Locate the line defining `cfg_deviceid`. It will typically look something like: ```verilog reg [15:0] cfg_deviceid = 16'hAAAA; // Default or placeholder Device ID ``` 2. **Update Device ID:** * Replace `AAAA` with the 16-bit hexadecimal Device ID you extracted from the donor device using Arbor (e.g., `0x1234`). * **Example:** If the donor's Device ID is `0x1234`, update the line as: ```verilog reg [15:0] cfg_deviceid = 16'h1234; // Updated with donor's Device ID (e.g., from network card) ``` 3. **Search for `cfg_vendorid`:** * Locate the line defining `cfg_vendorid`. It will be similar in format to `cfg_deviceid`: ```verilog reg [15:0] cfg_vendorid = 16'hBBBB; // Default or placeholder Vendor ID ``` 4. **Update Vendor ID:** * Replace `BBBB` with the 16-bit hexadecimal Vendor ID extracted from the donor device (e.g., `0xABCD`). * **Example:** If the donor's Vendor ID is `0xABCD`, update the line as: ```verilog reg [15:0] cfg_vendorid = 16'hABCD; // Updated with donor's Vendor ID (e.g., Intel Corporation) ``` 5. **Ensure Correct Formatting:** * Verify that hexadecimal values are correctly prefixed with `16'h` (indicating a 16-bit hexadecimal number). * Maintain consistent indentation and commenting style for readability. #### **6.1.4 Modify Subsystem ID and Revision ID** These identifiers provide additional details about the device variant, specific product models, or hardware revisions. While often optional, matching them enhances the authenticity of the emulation and can be critical for drivers that perform granular checks. **Steps:** 1. **Search for `cfg_subsysid`:** * Locate the line defining `cfg_subsysid`. ```verilog reg [15:0] cfg_subsysid = 16'hCCCC; // Placeholder Subsystem ID ``` 2. **Update Subsystem ID:** * Replace `CCCC` with the 16-bit hexadecimal Subsystem ID from your donor device (e.g., `0x5678`). * **Example:** ```verilog reg [15:0] cfg_subsysid = 16'h5678; // Set to donor's Subsystem ID ``` 3. **Search for `cfg_subsysvendorid`:** * Locate the line defining `cfg_subsysvendorid`. ```verilog reg [15:0] cfg_subsysvendorid = 16'hDDDD; // Placeholder Subsystem Vendor ID ``` 4. **Update Subsystem Vendor ID (if applicable):** * Replace `DDDD` with the 16-bit hexadecimal Subsystem Vendor ID from your donor device (e.g., `0x9ABC`). If your donor device does not have a unique Subsystem Vendor ID (i.e., it's the same as the main Vendor ID), you should still set it to that value. * **Example:** ```verilog reg [15:0] cfg_subsysvendorid = 16'h9ABC; // Set to donor's Subsystem Vendor ID ``` 5. **Search for `cfg_revisionid`:** * Locate the line defining `cfg_revisionid`. ```verilog reg [7:0] cfg_revisionid = 8'hEE; // Placeholder Revision ID ``` 6. **Update Revision ID:** * Replace `EE` with the 8-bit hexadecimal Revision ID from your donor device (e.g., `0x01`). * **Example:** ```verilog reg [7:0] cfg_revisionid = 8'h01; // Set to donor's Revision ID ``` #### **6.1.5 Update Class Code** The Class Code informs the host Operating System about the device's general type and function (e.g., network controller, storage device). This is vital for the OS to load generic class drivers, even if a specific vendor driver isn't installed. **Steps:** 1. **Search for `cfg_classcode`:** * Locate the line defining `cfg_classcode`. ```verilog reg [23:0] cfg_classcode = 24'hFFFFFF; // Default or placeholder Class Code ``` 2. **Update Class Code:** * Replace `FFFFFF` with the 24-bit hexadecimal Class Code you extracted from the donor device (e.g., `0x020000` for an Ethernet Controller). Remember the format: Base Class, Sub-Class, Programming Interface. * **Example:** If the donor's Class Code is `0x020000` (meaning Base Class: 0x02 - Network Controller, Sub-Class: 0x00 - Ethernet Controller, Prog IF: 0x00), update as: ```verilog reg [23:0] cfg_classcode = 24'h020000; // Set to donor's Class Code (e.g., Ethernet Controller) ``` 3. **Verify Correct Bit Width:** * Ensure that the Class Code is correctly represented as a 24-bit value using the `24'h` prefix for hexadecimal. #### **6.1.6 Save Changes** After making all modifications to the configuration parameters, it's critically important to save and review the changes. **Steps:** 1. **Save the File:** * Click **File > Save** in VS Code, or press `Ctrl + S` (or `Cmd + S`). 2. **Review Changes:** * Before closing, quickly re-read the modified lines to confirm their accuracy against your documented donor device information. * Check for any obvious syntax errors or typos (VS Code's extensions may highlight these). 3. **Optional - Use Version Control:** * If you are using Git (highly recommended for any code project, especially firmware), commit your changes with a clear and meaningful message. This creates a historical record of your modifications. * **Example Git Commands:** ```bash git add pcileech_pcie_cfg_a7.sv git commit -m "Updated PCIe configuration registers (VID, DID, SubIDs, Revision, Class Code) to match donor device: [Donor Device Name]" ``` ### **6.2 Inserting the Device Serial Number (DSN)** The Device Serial Number (DSN) is a unique 64-bit identifier that some PCIe devices (especially those with advanced features or specific drivers) may utilize. Including it enhances the authenticity of your emulation and can help bypass checks in drivers that explicitly query for this value. #### **6.2.1 Locate the DSN Field** The DSN, if implemented by the donor device, is part of the PCIe Extended Capabilities. In the PCILeech-FPGA framework, the DSN field is often exposed as a configurable parameter within the same configuration file you've been editing. **Steps:** 1. **Search for `cfg_dsn`:** * In `pcileech_pcie_cfg_a7.sv` (or your board's equivalent configuration file), use the search function (`Ctrl + F` or `Cmd + F`) to find `cfg_dsn`. 2. **Understand the Existing Assignment:** * The DSN may be set to a default value (often all zeros) or commented out. It will typically look like: ```verilog reg [63:0] cfg_dsn = 64'h0000000000000000; // Default DSN (usually 0 if not used) ``` #### **6.2.2 Insert the DSN** Updating the DSN involves setting it to the exact 64-bit hexadecimal value captured from your donor device. **Steps:** 1. **Update `cfg_dsn`:** * Replace the existing hexadecimal value with the 64-bit DSN you extracted from the donor device using Arbor. * **Example:** If the donor's DSN is `0x0011223344556677`, update as: ```verilog reg [63:0] cfg_dsn = 64'h0011223344556677; // Donor Device Serial Number ``` 2. **Handle DSN Unavailability or Irrelevance:** * If your donor device does *not* have a DSN, or if you've determined it's not a required parameter for the driver you're targeting, you can simply leave it as zeros: ```verilog reg [63:0] cfg_dsn = 64'h0000000000000000; // No specific DSN from donor, leaving as default 0 ``` * **Caution**: For critical emulations, if the donor device has a DSN, it's best to emulate it accurately. 3. **Ensure Correct Formatting:** * The DSN is a 64-bit value; ensure it's properly formatted with the `64'h` prefix for hexadecimal values. #### **6.2.3 Save Changes** Finalize the DSN modification by saving and reviewing the file. **Steps:** 1. **Save the File:** * Click **File > Save** in VS Code, or press `Ctrl + S`. 2. **Verify the Syntax:** * Check for any red underlines or error indications from VS Code's syntax checker. Correct any issues immediately. 3. **Document the Changes:** * If using version control, commit the updates with an appropriate message. * **Example Git Commands:** ```bash git commit -am "Inserted donor Device Serial Number (DSN) into PCIe configuration" ``` --- ## **7. Vivado Project Setup and Customization** With the firmware files updated to reflect the donor device's critical identification and configuration data, the next crucial step is to integrate these changes into the Vivado project. This involves generating the project files for your specific FPGA board, customizing the embedded PCIe IP core, and preparing the entire design for the synthesis and implementation phases. ### **7.1 Generating Vivado Project Files** Vivado, the Xilinx (AMD) development suite, uses Tcl (Tool Command Language) scripts to automate project creation, add source files, and configure project settings. By running these scripts provided with the PCILeech-FPGA framework, you ensure that your Vivado project is correctly set up for your target FPGA board. #### **7.1.1 Open Vivado** Starting with a fresh session of Vivado ensures that no lingering settings or open projects from previous sessions interfere with your current work. **Steps:** 1. **Launch Vivado:** * Find the Vivado application icon in your Start Menu (Windows) or Applications folder (Linux/macOS). * Click to open it. 2. **Select the Correct Version:** * If you have multiple Vivado versions installed, ensure you are launching the one compatible with your FPGA board and the PCILeech-FPGA project (as noted in Section 4.3.1, a recent stable version like Vivado 2023.x is recommended). 3. **Wait for the Startup Screen:** * Allow Vivado to fully initialize and present its welcome screen or project dashboard before proceeding. #### **7.1.2 Access the Tcl Console** The Tcl Console within Vivado is your primary interface for executing scripts and direct commands. This is where you will run the project generation scripts. **Steps:** 1. **Open the Tcl Console:** * In the Vivado interface, navigate to the menu bar. * Click on **Window** > **Tcl Console**. * The Tcl Console pane will typically appear at the bottom of the Vivado window. 2. **Adjust Console Size (Optional):** * You can drag the console's top border to resize it, making it taller for better visibility of commands and output. 3. **Clear Previous Commands (Optional but Recommended):** * If there are any previous commands or messages, you can right-click within the console and select "Clear Console" for a clean start. #### **7.1.3 Navigate to the Project Directory** Before running the Tcl script, you must ensure that the Tcl Console's current working directory is set to the correct location where your board-specific PCILeech-FPGA project scripts reside. **For Squirrel DMA (Artix-7 35T) or similar boards:** **Typical Path (after cloning `pcileech-fpga` and navigating to your board variant):** ``` C:/Users/YourUsername/Documents/pcileech-fpga/pcileech-squirrel-35t/ # On Windows ~/Projects/pcileech-fpga/pcileech-squirrel-35t/ # On Linux/macOS ``` *Note: Replace `` with the actual name of the subdirectory for your board (e.g., `pcileech-squirrel-35t`, `pcileech-artix-7-50t`).* **Steps:** 1. **Set the Working Directory in Tcl Console:** * In the Vivado Tcl Console, enter the `cd` command followed by the full path to your board's project directory. * **Example (Windows):** ```tcl cd C:/Users/YourUsername/Documents/pcileech-fpga/pcileech-squirrel-35t/ ``` * **Example (Linux/macOS):** ```tcl cd ~/Projects/pcileech-fpga/pcileech-squirrel-35t/ ``` * *Self-correction tip: Use forward slashes (`/`) even on Windows for Tcl paths.* 2. **Verify the Directory Change:** * To confirm you are in the correct directory, enter `pwd` (print working directory) in the Tcl Console. * The console should display the full path you just set, confirming the change. #### **7.1.4 Generate the Vivado Project** Running the appropriate Tcl script specific to your FPGA board will automate the entire project setup process within Vivado. This includes creating the project, adding all necessary source files (HDL, constraints), and configuring core project settings. **Steps:** 1. **Run the Tcl Script:** * Enter the `source` command followed by the name of the project generation script for your board. The PCILeech-FPGA project typically provides these scripts in the main board directory. * **For Squirrel (Artix-7 35T) (and similar Artix-7 boards):** ```tcl source vivado_generate_project_squirrel.tcl -notrace ``` * **For Enigma-X1 (Artix-7 75T):** ```tcl source vivado_generate_project_enigma_x1.tcl -notrace ``` * **For ZDMA (Artix-7 100T):** ```tcl source vivado_generate_project_100t.tcl -notrace ``` * The `-notrace` option prevents verbose output for every single Tcl command, keeping the console cleaner. 2. **Wait for Script Completion:** * The script will execute many commands in sequence. This process can take several minutes, depending on your system's performance and the complexity of the project. * Monitor the Tcl Console for progress messages. The script will: * Create a new Vivado project (`.xpr` file) in your current directory. * Add all SystemVerilog/Verilog source files (`.sv`, `.v`). * Add Xilinx IP core configurations (`.xci`). * Add XDC (Xilinx Design Constraints) files. * Potentially configure various project settings. * **Address Any Errors**: If any errors occur (e.g., "file not found," "invalid command"), the script will usually stop. Review the error message, correct the underlying issue (e.g., incorrect path, missing file), and re-run the script. 3. **Confirm Project Generation:** * Upon successful completion, the Tcl Console will typically indicate that the project has been created, and you should see the new project files (e.g., `pcileech_squirrel_top.xpr`) and associated directories (e.g., `pcileech_squirrel_top.runs`, `pcileech_squirrel_top.ip`) generated in your project directory. #### **7.1.5 Open the Generated Project** Now that the Vivado project files have been successfully generated by the Tcl script, you can open the project within the Vivado GUI for further inspection and customization. **Steps:** 1. **Open the Project:** * In Vivado, click **File** > **Open Project**. * Navigate to your project directory (the same one you set in the Tcl Console in Section 7.1.3). 2. **Select the Project File:** * Locate and select the Vivado project file (`.xpr` extension) that corresponds to your board. * **For Squirrel:** The file will typically be named `pcileech_squirrel_top.xpr`. * Click on the `.xpr` file to select it. 3. **Click Open:** * Vivado will load the project, displaying the design hierarchy, source files, IP Integrator block design (if used), and various design views. This may take a moment. 4. **Verify Project Contents:** * In the **Project Manager** window (typically on the left), expand the **Sources** pane. * Ensure that all expected source files (Verilog/SystemVerilog, XDC, IP cores) are listed and that the design hierarchy looks correct. * Check the **Messages** pane (bottom) for any warnings or critical warnings that appear upon opening the project, as these might indicate potential issues. ### **7.2 Modifying IP Blocks** The PCIe IP core is the heart of your device's PCIe interface. It's a pre-verified, configurable block from Xilinx that handles the complex PCIe protocol layers. While some configuration space values are handled in the SystemVerilog file (Section 6.1), other core PCIe parameters, especially those related to link capabilities and BAR structures, are configured directly within the PCIe IP core's customization settings in Vivado. Customizing the IP core ensures that your FPGA behaves identically to the donor hardware at the PCIe protocol level. #### **7.2.1 Access the PCIe IP Core** The PCIe IP core is instantiated as an IP block within your Vivado project. You'll need to open its customization GUI to modify its parameters. **Steps:** 1. **Locate the PCIe IP Core:** * In the **Sources** pane (within the **Project Manager** window), ensure the **Hierarchy** tab is selected. * Expand the design hierarchy until you find the instance of the PCIe IP core. * It is commonly named `pcie_7x_0.xci` (for 7-Series FPGAs) or similar, typically found within the `ip` subdirectory of your project sources. 2. **Open the IP Customization Window:** * **Right-click** on the `pcie_7x_0.xci` file. * From the context menu, select **Customize IP**. * The **IP Configuration** window (or similar name, like "Customize IP" or "Re-customize IP") will open, presenting a graphical interface with various tabs and options for configuring the PCIe core. 3. **Wait for IP Settings to Load:** * The IP customization interface may take a few moments to initialize and populate all its settings. Ensure that all options and tabs are fully loaded and responsive before you begin making changes. #### **7.2.2 Customize Device IDs and BARs within the IP Core** While some device identifiers are set in `pcileech_pcie_cfg_a7.sv`, the PCIe IP core itself also contains internal parameters for Device ID, Vendor ID, and crucially, the definitions for the Base Address Registers (BARs). You must ensure these align. Some values set in the `.sv` file might override or be fed into the IP core, but it's good practice to ensure consistency here too. The BAR settings in the IP core are particularly important as they dictate the hardware implementation of memory mapping. **Steps:** 1. **Navigate to Basic/Identification Parameters:** * In the IP customization window, look for a tab or section related to **Basic**, **Device and Vendor Identifiers**, **General**, or **PCIe Capabilities**. This is where fundamental IDs and initial link settings are defined. 2. **Verify/Enter the Device ID, Vendor ID, Subsystem IDs, Revision ID, Class Code:** * **Crucially, confirm these match the values you put in `pcileech_pcie_cfg_a7.sv` and from your donor device.** * Find fields like: * **Device ID**: Enter `0xXXXX` (e.g., `0x1234`). * **Vendor ID**: Enter `0xYYYY` (e.g., `0xABCD`). * **Subsystem ID**: Enter `0xZZZZ` (e.g., `0x5678`). * **Subsystem Vendor ID**: Enter `0xWWWW` (e.g., `0x9ABC`). * **Revision ID**: Enter `0xRR` (e.g., `0x01`). * **Class Code**: Enter `0xCCCCCC` (e.g., `0x020000`). * **Important**: Some IP core versions or specific configurations might pull these directly from the user logic (like `pcileech_pcie_cfg_a7.sv`) or might allow setting them directly here. The most reliable approach is to set them consistently in both places if the option is available in the IP GUI. 3. **Navigate to Base Address Registers (BARs) Tab:** * Within the IP customization window, locate and select the **BARs** tab or section. This is where you define the memory regions the PCIe device exposes. 4. **Configure Each BAR:** * For each BAR (BAR0 through BAR5) that your donor device uses, meticulously configure the following parameters based on the information extracted using Arbor: * **Enable BAR**: Check this box only if the donor device uses this specific BAR. Disable (uncheck) any BARs the donor device does not use. * **BAR Size**: Select the exact size from the dropdown list (e.g., **256 MB**, **64 KB**, **4 KB**). This is critical for the host OS to allocate the correct amount of memory. * **BAR Type**: Choose the appropriate type: * **Memory (32-bit Addressing)**: For memory-mapped regions accessible with 32-bit addresses. * **Memory (64-bit Addressing)**: For memory-mapped regions that can reside anywhere in the 64-bit address space (required for large memory regions or if the donor device uses it). * **I/O**: For legacy I/O port regions (less common in modern PCIe but still possible). * **Prefetchable**: Check this box if the donor's BAR is marked as prefetchable. This property allows the host system to cache or prefetch data from this region for performance. * **Example Configuration (based on your donor device):** * **BAR0**: * Enabled: Yes * Size: **256 MB** * Type: **Memory (64-bit Addressing)** * Prefetchable: Yes * **BAR1**: * Enabled: No (if the donor device does not use BAR1) * *Continue for BAR2-BAR5, mirroring the donor device's configuration.* 5. **Ensure Alignment and Non-Overlapping Spaces**: * The Vivado IP core typically handles the alignment automatically based on the size you select. However, be aware that PCIe specification requires BAR sizes to be a power of two, and BARs must be aligned to their size. * Ensure that the total memory mapped by your BARs does not exceed the FPGA's available Block RAM (BRAM) or external memory capabilities. #### **7.2.3 Finalize IP Customization** After configuring all necessary settings within the IP core's customization window, you must apply these changes for them to take effect in your Vivado project. **Steps:** 1. **Review All Settings:** * Before applying, take a moment to quickly review each tab in the IP customization window one last time. * Confirm that all entries precisely match the documented specifications of your donor device. A small error here can lead to device detection or functionality issues. 2. **Apply Changes:** * Click the **OK** or **Generate** button (the label may vary) at the bottom of the IP customization window. * If Vivado prompts you to confirm that you wish to proceed with the changes and regenerate the IP output products, confirm by clicking **Yes**. 3. **Regenerate IP Core:** * Vivado will now regenerate the IP core's output products (e.g., netlists, simulation models, new `.xci` configuration files) to reflect your new configurations. * Monitor the **Messages** pane (bottom of Vivado window) for any errors, warnings, or critical warnings that may arise during this regeneration process. Address any critical warnings immediately. 4. **Update IP in Project:** * Vivado might automatically update or prompt you to update any IP dependencies in your project after a core is regenerated. Allow it to do so to ensure the latest configuration is used throughout your design. #### **7.2.4 Lock the IP Core** Locking the IP core is a recommended best practice in Vivado to prevent unintended modifications or re-customizations during subsequent synthesis and implementation runs, which could potentially revert your carefully configured settings. **Purpose of Locking:** * **Prevent Overwrites:** Ensures that your manual configurations within the IP core's GUI are preserved and not accidentally overwritten by Vivado's automation or if the IP is detected as "out-of-date" due to subtle project changes. * **Maintain Consistency:** Keeps the IP core in a known, stable state throughout the build process, which is especially important for critical components like the PCIe interface. **Steps:** 1. **Open the Tcl Console:** * In Vivado, if the Tcl Console is not already open, go to **Window** > **Tcl Console**. 2. **Execute the Lock Command:** * In the Tcl Console, enter the following command precisely. This command sets the `IP_LOCKED` property to `true` for your PCIe IP core instance (`pcie_7x_0`). ```tcl set_property -name {IP_LOCKED} -value true -objects [get_ips pcie_7x_0] ``` * Press **Enter** to execute the command. 3. **Verify the Lock:** * Check the **Messages** pane. You should see a confirmation message indicating that the property was set. * You can also right-click on `pcie_7x_0.xci` in the Sources pane, select "IP Properties," and verify that `IP_LOCKED` is set to `true`. You might also notice that the "Customize IP" option is now grayed out or only allows "Re-customize IP" which then warns you about the lock. 4. **Unlocking (if necessary):** * If you need to make further modifications to the PCIe IP core's settings in the future, you must first unlock it. Use the following Tcl command: ```tcl set_property -name {IP_LOCKED} -value false -objects [get_ips pcie_7x_0] ``` * Remember to re-lock it after making and applying your changes. 5. **Document the Action:** * It's a good practice to note in your project documentation (e.g., a README file, project notes) that the PCIe IP core has been locked. This helps anyone else working on the project understand its configuration state and avoid confusion. --- ## **Part 2: Intermediate Concepts and Implementation** --- ## **8. Advanced Firmware Customization** To achieve a precise and convincing emulation of the donor device, further in-depth customization of the FPGA firmware is necessary beyond just basic identification. This involves aligning the PCIe parameters (such as link speed and transaction sizes), meticulously adjusting Base Address Registers (BARs) and their associated memory mappings, and accurately emulating power management and interrupt mechanisms. These steps ensure that the emulated device not only looks like the original hardware to the host system but also behaves identically at the protocol and functional levels. ### **8.1 Configuring PCIe Parameters for Emulation** Accurate emulation requires that the PCIe operational parameters of your FPGA device are meticulously configured to match those of the donor device. This includes settings such as the PCIe link speed, link width, capability pointers, and maximum payload sizes. Proper configuration ensures compatibility with the host system, the correct operation of drivers and applications that interact with the device, and optimal performance for data transfer. #### **8.1.1 Matching PCIe Link Speed and Width** The PCIe link speed (e.g., Gen1, Gen2, Gen3) and link width (e.g., x1, x4, x8) are critical parameters that determine the maximum theoretical data throughput and performance of the device. Matching these settings with the donor device is essential for accurate emulation, as drivers or system components might expect specific link capabilities. **Steps:** 1. **Access PCIe IP Core Settings:** * **Open Your Vivado Project:** Launch Vivado and open the project you previously created or modified (e.g., `pcileech_squirrel_top.xpr`). Ensure that all source files are correctly added to the project. * **Locate the PCIe IP Core:** In the **Sources** pane (typically on the left), expand the design hierarchy to find the PCIe IP core instance. For Xilinx 7-series designs (like Artix-7 used in Squirrel), this is usually named `pcie_7x_0.xci`. * **Customize the IP Core:** Right-click on `pcie_7x_0.xci` and select **Customize IP**. The IP customization window will open, displaying various configuration options across multiple tabs. 2. **Set Maximum Link Speed:** * **Navigate to Link Parameters:** In the IP customization window, click on the **PCIe Capabilities** tab (or sometimes "PCIe Configuration" or "General"). Within this, look for a section related to **Link Parameters** or **Link Capability Register**. * **Configure Maximum Link Speed:** Find the option labeled **Maximum Link Speed** (or "Target Link Speed"). * Set it to match the maximum link speed supported and advertised by your donor device. * **Example:** * If the donor device operates at **PCIe Gen2 (5.0 GT/s)**, select **5.0 GT/s**. * If it operates at **PCIe Gen1 (2.5 GT/s)** or **PCIe Gen3 (8.0 GT/s)**, select the corresponding option. * **Note**: Ensure that your FPGA's transceivers and the physical hardware (motherboard PCIe slot) support the selected link speed. The FPGA will only negotiate up to its configured maximum. 3. **Set Link Width:** * **Configure Link Width:** In the same **Link Parameters** section, locate the **Link Width** setting (or "PCIe Link Width," "Target Link Width"). * Set it to match the maximum link width advertised by your donor device. * **Example:** * If the donor device uses a **x4** link, set the **Link Width** to **4**. * Options typically include **1**, **2**, **4**, **8**, **16** lanes. * **Note**: The physical PCIe slot and the FPGA's package must support the selected link width. Attempting to configure a width greater than the physical connection will result in link negotiation issues. 4. **Save and Regenerate:** * **Apply Changes:** After configuring the link speed and width, click **OK** to apply the changes within the IP customization window. * **Regenerate IP Output Products:** Vivado will likely prompt you to regenerate the IP core's output products due to the changes made. Confirm and allow the regeneration process to complete. This can take some time. * **Verify Settings:** Once regeneration is complete, you can optionally revisit the IP core settings to ensure the configurations are correctly applied. Check for any warnings or errors in the **Messages** window in Vivado. #### **8.1.2 Setting Capability Pointers** Capability pointers within the PCIe configuration space are 8-bit registers that form a linked list, pointing to various capability structures (e.g., Power Management, MSI/MSI-X, PCIe Express Capability). Correctly setting these pointers ensures that the host system can traverse the capability list and locate and utilize the device's advertised features. **Steps:** 1. **Locate Capability Pointer in Firmware:** * **Open Configuration File:** In Visual Studio Code, open the primary configuration file for your board, typically `pcileech_pcie_cfg_a7.sv`, located at `pcileech-fpga//src/pcileech_pcie_cfg_a7.sv`. * **Understand the Capability Pointer:** The capability pointer (`cfg_cap_pointer`) in this file points to the *first* capability structure in the PCIe configuration space, usually starting after the standard 64-byte configuration header. Subsequent capabilities are chained by their "Next Capability Pointer" fields. 2. **Set Capability Pointer Value:** * **Find the Assignment for `cfg_cap_pointer`:** Search for the line in the code where `cfg_cap_pointer` is assigned. ```verilog reg [7:0] cfg_cap_pointer = 8'hXX; // Current value (e.g., 8'h40 for default) ``` * **Update the Capability Pointer:** Replace `XX` with the 8-bit hexadecimal capability pointer value observed from your donor device using Arbor. This value typically points to the offset of the first capability structure after the Device-Specific Configuration Space (which usually ends at offset `0x3F`). A common starting point for capabilities is `0x40` or `0x60`. * **Example:** * If the donor device's first capability pointer is `0x60` (meaning its first capability structure starts at offset `0x60` in the configuration space), update the line to: ```verilog reg [7:0] cfg_cap_pointer = 8'h60; // Updated to match donor device's first capability offset ``` * **Ensure Correct Alignment:** Capability structures must be aligned on a 4-byte boundary. The capability pointer should always point to a valid 4-byte aligned offset within the configuration space. 3. **Save Changes:** * **Save the Configuration File:** After making the changes, save the file by clicking **File > Save** or pressing `Ctrl + S`. * **Verify Syntax:** Ensure there are no syntax errors introduced by the changes (VS Code will usually highlight these). * **Comment for Clarity:** Add a comment explaining the change for future reference and maintainability. ```verilog reg [7:0] cfg_cap_pointer = 8'h60; // Set to donor's capability pointer (e.g., PCIe Cap at 0x60) ``` #### **8.1.3 Adjusting Maximum Payload and Read Request Sizes** These parameters define the maximum amount of data that can be transferred in a single PCIe Transaction Layer Packet (TLP) and the maximum size of a non-posted Memory Read Request TLP. Matching these settings with the donor device ensures compatibility and optimal performance for data transfer operations. Mismatches can lead to reduced throughput or communication errors. **Steps:** 1. **Set Maximum Payload Size Supported (IP Core):** * **Access Device Capabilities:** In the PCIe IP core customization window (`pcie_7x_0.xci` in Vivado), navigate to the **PCIe Capabilities** tab. * **Configure Max Payload Size Supported:** Find the setting labeled **Max Payload Size Supported** (or similar). * Set it to the value supported and advertised by your donor device (e.g., 128 bytes, 256 bytes, 512 bytes, 1024 bytes, 2048 bytes, 4096 bytes). * **Example:** If the donor device supports a maximum payload size of **256 bytes**, select **256 bytes** from the dropdown. 2. **Set Maximum Read Request Size Supported (IP Core):** * **Configure Max Read Request Size Supported:** In the same tab, find the **Max Read Request Size Supported** setting. * Set it to match the donor device's capability. This specifies the maximum amount of data a device can request in a single read transaction. * **Example:** If the donor supports a maximum read request size of **512 bytes**, select **512 bytes**. 3. **Adjust Firmware Parameters (Matching IP Core):** * **Open `pcileech_pcie_cfg_a7.sv`:** Ensure that the configuration file is open in Visual Studio Code. * **Update Firmware Constants:** Locate the lines where `max_payload_size_supported` and `max_read_request_size_supported` are defined. These are typically bit-encoded values that correspond to the byte sizes you selected in the IP core. ```verilog reg [2:0] max_payload_size_supported = 3'bZZZ; // Current value reg [2:0] max_read_request_size_supported = 3'bWWW; // Current value ``` * **Set the Appropriate Values:** Replace `ZZZ` and `WWW` with the 3-bit binary representations corresponding to the selected sizes. * **Mapping (as per PCIe spec):** * **128 bytes**: `3'b000` * **256 bytes**: `3'b001` * **512 bytes**: `3'b010` * **1024 bytes**: `3'b011` * **2048 bytes**: `3'b100` * **4096 bytes**: `3'b101` * **Example:** * For **256 bytes** payload size: ```verilog reg [2:0] max_payload_size_supported = 3'b001; // Supports up to 256 bytes (0x100) ``` * For **512 bytes** read request size: ```verilog reg [2:0] max_read_request_size_supported = 3'b010; // Supports up to 512 bytes (0x200) ``` * **Reasoning**: These firmware parameters often dictate the behavior of your user logic that interfaces with the PCIe core, ensuring that your logic respects the configured maximums. 4. **Save Changes:** * **Save the File:** After updating the values in `pcileech_pcie_cfg_a7.sv`, save the file. * **Verify Consistency:** It's crucial that the values configured in the Vivado PCIe IP core's GUI *match* the values set in your HDL configuration file. Any mismatch can lead to unexpected behavior or link training issues. * **Add Comments:** Document these changes clearly in your code for future reference. ### **8.2 Adjusting BARs and Memory Mapping** Base Address Registers (BARs) are fundamental to how a PCIe device exposes its internal memory and registers to the host system. Correctly configuring the BARs and defining their memory mapping within your FPGA's BRAMs (Block RAMs) and logic is crucial for accurate emulation and the proper operation of host-side device drivers. #### **8.2.1 Setting BAR Sizes and Types (IP Core & BRAMs)** Configuring the BAR sizes and types ensures that your emulated device requests the correct amount of address space from the host during enumeration and that the host allocates and maps these regions appropriately. This also involves associating these address regions with physical memory blocks within your FPGA. **Steps:** 1. **Access BAR Configuration (PCIe IP Core):** * **Customize PCIe IP Core:** In Vivado, right-click on `pcie_7x_0.xci` and select **Customize IP** to open its configuration GUI. * **Navigate to BARs Tab:** In the IP customization window, click on the **Base Address Registers (BARs)** tab. 2. **Configure Each BAR (IP Core):** * **Match Donor Device's BARs:** For each BAR (BAR0 to BAR5), set the size, type, and prefetchable status to precisely match what you extracted from the donor device using Arbor. * **Enable/Disable BARs:** Ensure that only the BARs actually used by the donor device are enabled. Disable (uncheck) any unused BARs. * **Set BAR Sizes:** Select the appropriate size from the dropdown for each *enabled* BAR. This will be a power-of-two size (e.g., 4KB, 8KB, 64KB, 1MB, 256MB, 1GB). * **Example:** * If **BAR0** is **64 KB**, set **BAR0 Size** to **64 KB**. * If **BAR1** is **128 MB**, set **BAR1 Size** to **128 MB**. * **Set BAR Types:** * Choose between **Memory (32-bit Addressing)** or **Memory (64-bit Addressing)** if the BAR is memory-mapped. Select **64-bit Addressing** if the donor device's BAR is 64-bit or if you require access to addresses above 4GB. * Choose **I/O** if the BAR is for I/O port space (less common for modern PCIe devices). * **Set Prefetchable Status**: Check the "Prefetchable" box if the donor's BAR was identified as prefetchable. This bit allows the host to prefetch data from that region, potentially improving performance. 3. **Update BRAM Configurations (if applicable):** * Many PCILeech-FPGA projects use Xilinx Block RAM (BRAM) IP cores to represent the memory regions exposed by the BARs. These BRAMs provide the physical storage for your emulated device's memory. * **Locate BRAM IP Cores:** In your Vivado project's **Sources** pane, within the `ip` subdirectory (or similar), you might find `.xci` files for BRAMs, potentially named like: ``` pcileech-fpga//ip/bram_bar_zero4k.xci pcileech-fpga//ip/bram_pcie_cfgspace.xci # And potentially others for BAR1, BAR2 etc. ``` * **Modify BRAM Sizes:** For each BRAM IP core associated with an *enabled* BAR, you may need to **Customize IP** (right-click on the `.xci` file) and adjust its memory size configuration to exactly match the corresponding BAR size you set in the PCIe IP core. * **Example:** If BAR0 is 256MB, ensure the BRAM connected to BAR0 has a size of 256MB. * **Caution**: Ensure that the total memory required by all active BARs does not exceed the physical BRAM capacity of your FPGA device. Exceeding capacity will lead to implementation failures. 4. **Save and Regenerate:** * **Apply Changes (IP Core):** After configuring the BARs in the PCIe IP core, click **OK** in the IP customization window. * **Regenerate IP Cores:** Vivado will prompt you to regenerate the PCIe IP core and any associated BRAM IP cores due to the size changes. Allow the regeneration to complete. This ensures the hardware netlist reflects your new BAR definitions. * **Check for Errors:** Review the **Messages** window for any warnings or errors related to BAR configurations or BRAM instantiation. #### **8.2.2 Defining BAR Address Spaces in Firmware** While the PCIe IP core configures the *hardware* aspects of the BARs, your custom firmware (SystemVerilog code) needs to define the *logic* for how your emulated device responds when the host CPU performs read or write operations to addresses within these BAR regions. This involves address decoding and implementing register/memory access logic. **Steps:** 1. **Open the BAR Controller File:** * In Visual Studio Code, open the SystemVerilog file responsible for handling BAR accesses. For PCILeech-FPGA, this is often: ``` pcileech-fpga//src/pcileech_tlps128_bar_controller.sv ``` This module typically receives PCIe Memory Read/Write TLPs and decodes the address to determine which BAR (and which offset within that BAR) is being accessed. 2. **Implement Address Decoding Logic:** * Within the `pcileech_tlps128_bar_controller.sv` module, you'll find logic that determines which BAR an incoming transaction targets. This often involves checking the address bits against the configured BAR sizes. * You'll need to define how the incoming address `req_addr` (from the TLP) maps to an offset within your specific BAR. * **Conceptual Example:** ```verilog // Example: Logic for BAR0 (assuming it's a 256MB 64-bit Memory BAR, for registers/data) // 'bar_hit[0]' would be an input signal indicating a hit on BAR0, typically from the PCIe core. // 'req_addr' is the incoming PCIe address. // 'req_be' is the byte enable from the TLP. // 'req_data' is the incoming write data. // 'rsp_data' is the outgoing read data. // Assuming BAR0 is 256MB (2^28 bytes), address bits [27:0] are within the BAR. localparam BAR0_SIZE_BITS = 28; // 2^28 = 256MB reg [31:0] internal_register_0; // Example register within BAR0 reg [31:0] internal_register_1; // Another example register assign bar0_offset = req_addr[BAR0_SIZE_BITS-1:0]; // Extract offset within BAR0 always_comb begin // Default response rsp_data = 32'hFFFFFFFF; // Default to all F's or similar for unmapped regions if (bar_hit[0]) begin // If the transaction targets BAR0 if (req_write) begin // This is a write operation case (bar0_offset) // Example: Map offset 0x0 to internal_register_0 32'h0000_0000: begin if (req_be[3]) internal_register_0[31:24] = req_data[31:24]; if (req_be[2]) internal_register_0[23:16] = req_data[23:16]; if (req_be[1]) internal_register_0[15:8] = req_data[15:8]; if (req_be[0]) internal_register_0[7:0] = req_data[7:0]; end // Example: Map offset 0x4 to internal_register_1 32'h0000_0004: begin if (req_be[3]) internal_register_1[31:24] = req_data[31:24]; if (req_be[2]) internal_register_1[23:16] = req_data[23:16]; if (req_be[1]) internal_register_1[15:8] = req_data[15:8]; if (req_be[0]) internal_register_1[7:0] = req_data[7:0]; end // Add more register mappings or memory accesses (e.g., BRAM access) default: begin // Handle unmapped writes within BAR0, e.g., ignore or log end endcase end else if (req_read) begin // This is a read operation case (bar0_offset) // Example: Read from internal_register_0 32'h0000_0000: rsp_data = internal_register_0; // Example: Read from internal_register_1 32'h0000_0004: rsp_data = internal_register_1; // Add more register mappings or memory accesses (e.g., BRAM access) default: begin rsp_data = 32'h0; // Return 0 for unmapped reads or specific error value end endcase end end end ``` * **Handle Data Transfers:** The `always_comb` block (or `always_ff` for sequential logic) should define how `rsp_data` is generated for reads and how internal registers/memories are updated for writes, based on the `bar0_offset` and byte enables (`req_be`). 3. **Implement BRAM Accesses (if BAR maps to BRAM):** * If a BAR maps to a large block of memory (e.g., 256MB), you'll typically instantiate a BRAM IP core (as discussed in 8.2.1) and interface your `bar_controller` logic to it. The `bar_controller` would provide the address and control signals to the BRAM. * **Conceptual BRAM Integration (simplified):** ```verilog // Inside pcileech_tlps128_bar_controller.sv or a sub-module // Interface to BRAM wire [BAR0_SIZE_BITS-1:0] bram_addr; wire [31:0] bram_wr_data; wire [3:0] bram_wr_en; // Byte enables for BRAM wire bram_wr_ce; wire bram_rd_ce; wire [31:0] bram_rd_data; // Map TLP signals to BRAM interface assign bram_addr = bar0_offset; assign bram_wr_data = req_data; assign bram_wr_en = req_be; assign bram_wr_ce = bar_hit[0] && req_write; assign bram_rd_ce = bar_hit[0] && req_read; // Instantiate the BRAM IP core bram_bar_zero bram_inst ( // Assuming 'bram_bar_zero' is your BRAM IP module .clka(clk), .ena(1'b1), .wea(bram_wr_en), .addra(bram_addr), .dina(bram_wr_data), .douta(bram_rd_data) ); // For reads from BAR0, output data from BRAM if (bar_hit[0] && req_read) begin rsp_data = bram_rd_data; end ``` 4. **Save Changes:** * After implementing the logic for each BAR, save the `pcileech_tlps128_bar_controller.sv` file. * **Verify Functionality:** This logic is complex. Thorough simulation (using a test bench) and later hardware testing will be crucial to ensure correct behavior. #### **8.2.3 Handling Multiple BARs** Properly managing multiple BARs is essential for devices that expose several distinct memory or I/O regions. The `bar_controller` module typically handles all BARs. **Steps:** 1. **Implement Logic for Each BAR:** * Within `pcileech_tlps128_bar_controller.sv`, extend the logic to handle all enabled BARs (BAR0, BAR1, BAR2, etc.) that your donor device uses. * **Separate Logic Blocks:** For clarity and maintainability, create distinct `if/else if` blocks or `case` statements that activate based on which `bar_hit` signal is asserted. ```verilog // BAR0 Handling if (bar_hit[0]) begin // BAR0 specific read/write logic for its registers/memory end else if (bar_hit[1]) begin // BAR1 specific read/write logic for its registers/memory end else if (bar_hit[2]) begin // BAR2 specific logic end // ... continue for other BARs ``` * **Define Registers and Memories:** Allocate separate sets of registers or connect distinct BRAM instances for each BAR as needed. 2. **Ensure Non-Overlapping Address Spaces:** * While the PCIe IP core handles the negotiation of distinct address spaces for each BAR with the host OS, your internal firmware logic *must* assume that these spaces are separate and non-overlapping. * **Validate Address Ranges**: Double-check your BAR size configurations in the PCIe IP core to ensure they are distinct and correctly aligned to power-of-two boundaries as per PCIe specifications. * **Update Address Decoding**: Your `bar_controller` logic relies on the `bar_hit` signals generated by the PCIe IP core. Ensure these are correctly interpreted and lead to the unique handling logic for each BAR. 3. **Test BAR Accesses:** * **Simulation Testing:** Before hardware deployment, use simulation tools (e.g., Vivado Simulator) with a comprehensive test bench to verify all read and write operations to each BAR. * Send Memory Write TLPs to specific offsets within each BAR. * Send Memory Read TLPs to specific offsets within each BAR and verify the returned data. * **Hardware Testing:** After programming the FPGA, use host-side software tools (like PCILeech client software, or custom C/Python scripts) to access and verify each BAR. * **Linux**: Use `lspci -vvv` to inspect BAR mappings (`Memory at XXXX (64-bit, prefetchable) [size=YYYY]`). You can then use `devmem2` or a custom kernel module to read/write to these mapped addresses. * **Windows**: Use tools like "RW-Everything" or custom user-mode applications to inspect and interact with the mapped memory regions. * Perform various read/write patterns to ensure data integrity and correct addressing across all BARs. --- ### **8.3 Emulating Device Power Management and Interrupts** Emulating power management features and implementing interrupts are critical for devices that need to interact closely and efficiently with the host operating system's power management and interrupt handling mechanisms. Without these, the emulated device may not appear fully functional, or performance could be suboptimal. #### **8.3.1 Power Management Configuration** Implementing power management allows the emulated device to support various power states (e.g., D0, D3hot), contributing to system-wide power efficiency and compliance with operating system expectations. The host OS will query the device's capabilities and send commands to transition between these states. **Steps:** 1. **Enable Power Management in PCIe IP Core:** * **Access Capabilities:** In the PCIe IP core customization window (`pcie_7x_0.xci`), navigate to the **PCIe Capabilities** tab. * **Enable Power Management:** Look for a section or option related to **Power Management Capability**. Ensure this is checked or enabled to include the Power Management (PM) capability structure in the device's configuration space. 2. **Set Power States Supported:** * **Configure Supported States:** Within the Power Management Capability section of the IP core, specify which power states the device supports. These are typically checkboxes or dropdowns. Match these settings to the donor device's capabilities as observed by Arbor. * **D0 (Fully On/Operational)**: Always supported. * **D1, D2 (Intermediate States)**: Optional, for low-power idle states. * **D3hot (Power Down, Auxiliary Power Present)**: Device logic is off, but can respond to PM events. * **D3cold (Power Off)**: No power to the device. * **Example**: If the donor device only supports D0 and D3hot, enable only those. 3. **Implement Power State Logic in Firmware:** * **Open `pcileech_pcie_cfg_a7.sv` (or relevant control module):** You'll typically need to modify the firmware to reflect and potentially react to power state transitions commanded by the host. The PCIe core itself handles much of the protocol, but your user logic needs to know the state. * **Handle Power Management Control and Status Register (PMCSR) Writes:** The host OS changes the device's power state by writing to specific bits in the PMCSR, which is part of the PM Capability structure. Your firmware should ideally have logic to read these bits and adjust device behavior (e.g., pausing/resuming operations, enabling/disabling clocks). ```verilog // Example: Part of pcileech_pcie_cfg_a7.sv or a dedicated PM module // Assume 'cfg_write' is asserted for config writes, 'cfg_address' is the offset, 'cfg_writedata' is the data. // The D-state bits are at offset 0x04 within the PM capability structure, bits [1:0]. // PMCSR Register (Internal representation) reg [15:0] pmcsr_reg = 16'h0000; // Initialize to D0 // User logic signal indicating current power state reg [1:0] current_d_state = 2'b00; // 00 = D0, 01 = D1, 10 = D2, 11 = D3hot always @(posedge clk) begin if (reset) begin pmcsr_reg <= 16'h0000; current_d_state <= 2'b00; // Reset to D0 end else begin // Example: Capture writes to PMCSR (if directly handled in user logic) // Note: The PCIe IP core manages much of this, but your user logic might need to read values from it. // Assuming the PCIe core provides an output reflecting the current D-state: // assign current_d_state = pcie_core_d_state_output; // If user logic *needs* to write to PMCSR (less common, usually read-only status) // Or if it needs to process the command // if (cfg_write && (cfg_address == PM_CAP_OFFSET + 2'h04)) begin // PMCSR is at +0x04 from PM Cap base // pmcsr_reg[1:0] <= cfg_writedata[1:0]; // Capture New D-state // // current_d_state <= cfg_writedata[1:0]; // Update internal state // end // In PCILeech, the PCIe core manages the PMCSR. You would likely read a signal from the core. // For demonstration, let's assume 'pcie_d_state' is an input from the IP core. current_d_state <= pcie_d_state; // Update based on PCIe core's status end end // Example: Logic reacting to D-state changes always @(*) begin if (current_d_state == 2'b11) begin // D3hot state // Disable power to non-essential blocks, pause operations, // assert a signal to main DMA logic to stop activity. // For instance: dma_engine_enable = 1'b0; end else if (current_d_state == 2'b00) begin // D0 state // Enable full functionality // For instance: dma_engine_enable = 1'b1; end end ``` * **Manage Power State Effects:** Implement logic to alter the device's internal behavior (e.g., enable/disable clocks, put sub-modules into low-power modes) based on the `current_d_state`. This is crucial for accurate power consumption emulation and to ensure the device responds correctly to OS commands. 4. **Save Changes:** * Save any modified firmware files. * Thoroughly test power management features through simulation or hardware testing (e.g., Windows "Sleep" or "Hibernate" functions, or Linux `poweroff` commands to see if the device transitions correctly). #### **8.3.2 MSI/MSI-X Configuration** Implementing Message Signaled Interrupts (MSI) or its extended version (MSI-X) allows the emulated device to use message-based interrupts. These are significantly more efficient and scalable than traditional pin-based interrupts (INTx) and are the preferred method for modern PCIe devices. MSI/MSI-X allow the device to notify the CPU by writing a special TLP to a specific memory address. **Steps:** 1. **Enable MSI/MSI-X in PCIe IP Core:** * **Access Interrupts Configuration:** In the PCIe IP core customization window (`pcie_7x_0.xci`), navigate to the **Interrupts** tab or a section specifically labeled **MSI/MSI-X Capabilities**. * **Select Interrupt Type:** Choose between **MSI** or **MSI-X** based on the donor device's capabilities. MSI-X is generally preferred for its flexibility (more vectors, per-vector masking). * **Configure Number of Supported Vectors:** Set the number of interrupt vectors (messages) that the device will support. Match this to the donor device. * **MSI** supports up to 32 vectors (typically 1, 2, 4, 8, 16, or 32). * **MSI-X** supports up to 2048 vectors, allowing for more granular interrupt sources. * **Enable Capabilities:** Ensure that the MSI or MSI-X capability structure is explicitly enabled to be included in the device's configuration space. This is how the host OS discovers the device's interrupt capabilities. 2. **Implement Interrupt Logic in Firmware:** * **Open `pcileech_pcie_tlp_a7.sv` (or user logic module):** This file is generally responsible for user-defined TLP generation and might be the appropriate place to initiate MSI/MSI-X messages. However, the *trigger* for the interrupt will come from your custom logic. * **Define Interrupt Signals:** Declare internal signals that will indicate when an interrupt needs to be generated. ```verilog // In a custom module (e.g., 'my_device_logic.sv') that interfaces with TLP generation logic reg msi_trigger_signal; // Assert this when an interrupt condition occurs ``` * **Implement Interrupt Generation Logic:** Define the conditions under which an interrupt should be triggered. This typically involves event detection within your emulated device's logic. ```verilog // Inside 'my_device_logic.sv' input wire clk; input wire reset; input wire event_data_ready; // Example: Input from your logic when data is ready always @(posedge clk or posedge reset) begin if (reset) begin msi_trigger_signal <= 1'b0; end else if (event_data_ready) begin // When a specific event happens msi_trigger_signal <= 1'b1; // Trigger an MSI end else begin msi_trigger_signal <= 1'b0; // Clear after one cycle or when acknowledged end end ``` * **Connect to PCIe Core's MSI Interface:** The `msi_trigger_signal` (or similar output from your custom logic) needs to be connected to the appropriate input of the PCIe IP core (e.g., `s_axis_tdata_tready`, `s_axis_tdata_tvalid`, `s_axis_tdata_tlast` if using an AXI-Stream interface for MSI TLPs, or dedicated MSI request ports provided by the IP core). The PCIe core then forms and sends the actual MSI/MSI-X TLP. Consult the Xilinx PCIe IP core documentation for precise interface details. 3. **Save Changes:** * Save any modified firmware files after implementing the interrupt logic. * **Check for Timing Constraints:** New logic, especially interrupt paths, can be timing-critical. Ensure that the synthesis and implementation tools do not report any timing violations related to your interrupt generation logic. #### **8.3.3 Implementing Interrupt Handling Logic (Device Side)** Beyond just enabling the capability, defining *when* and *how* interrupts are generated by your emulated device is crucial for its proper interaction with the host's interrupt handling mechanisms and driver behavior. This involves creating the internal logic that asserts the interrupt request. **Steps:** 1. **Define Interrupt Conditions:** * **Identify Trigger Events:** Based on your donor device's behavior, determine the specific internal events that should cause your emulated device to generate an interrupt. * **Examples**: Data transfer completion, new data ready in a receive buffer, an internal error condition, completion of a specific command, link status change. * **Implement Condition Logic:** Use combinational or sequential logic within your custom SystemVerilog modules to precisely detect these events and generate a short-duration pulse or level-based signal that indicates an interrupt request. 2. **Create Interrupt Generation Module (Modular Design):** * It's a good practice to encapsulate your interrupt generation logic into a separate, dedicated module for clarity, reusability, and easier debugging. This module would take internal events as inputs and produce an `msi_req` (or similar) output that connects to the PCIe core. ```verilog // File: interrupt_generator.sv module interrupt_generator ( input wire clk, input wire reset, input wire event_trigger, // Input signal from your custom logic (e.g., data_ready, error_flag) output reg msi_req_o // Output: Assert to request an MSI/MSI-X ); // Simple pulse generator for MSI (one-shot interrupt) reg event_trigger_d1; always @(posedge clk or posedge reset) begin if (reset) begin msi_req_o <= 1'b0; event_trigger_d1 <= 1'b0; end else begin event_trigger_d1 <= event_trigger; // Generate a single-cycle pulse when event_trigger goes high if (event_trigger && !event_trigger_d1) begin msi_req_o <= 1'b1; // Assert MSI request end else begin msi_req_o <= 1'b0; // De-assert after one cycle end end end endmodule // interrupt_generator ``` * **Integrate with Main Firmware:** Instantiate this `interrupt_generator` module in your top-level user logic (e.g., within `pcileech_squirrel_top.sv` or a module it instantiates) and connect its `msi_req_o` output to the PCIe IP core's MSI input. 3. **Ensure Proper Timing and Sequencing:** * **Adhere to PCIe Specifications:** MSI/MSI-X messages are TLPs. Ensure that the generation of these messages adheres to PCIe TLP formatting, flow control, and timing requirements. The PCIe IP core handles much of this, but your input signals to it must be stable and correctly timed. * **Manage Interrupt Latency:** Optimize your logic to minimize any unnecessary delay between the internal event occurrence and the assertion of the `msi_req_o` signal. 4. **Test Interrupt Delivery:** * **Simulation:** Use a comprehensive test bench to simulate scenarios where interrupts should be generated. Verify that your `msi_req_o` signal behaves as expected and that the PCIe core generates the correct MSI/MSI-X TLPs. * **Hardware Testing:** * Program the FPGA with the updated firmware. * Use host-side software to trigger the events that should cause an interrupt (e.g., initiating a DMA transfer that completes). * Confirm that the interrupts are received by the host operating system. On Linux, `dmesg` can show interrupt messages. On Windows, you might use specific driver debug tools or Event Viewer. * **Debugging Tools:** Utilize Vivado's Integrated Logic Analyzer (ILA) cores (as discussed later in Section 12) to monitor `event_trigger`, `msi_req_o`, and the PCIe core's TLP output signals in real time to verify correct interrupt generation. 5. **Save Changes:** * Finalize all code modifications and save the relevant firmware files. * Review and refine your interrupt logic based on testing results to ensure reliability. --- ## **9. Emulating Device-Specific Capabilities** Beyond the standard PCIe configuration space and generic DMA functionality, many donor devices possess unique capabilities, custom registers, or vendor-specific features that are critical for their full functionality or for interacting with their proprietary drivers. Accurate emulation requires understanding and replicating these nuances. This section delves into implementing such advanced capabilities, enabling a more faithful and fully functional emulation. ### **9.1 Implementing Advanced PCIe Capabilities** The PCIe specification includes various *extended capabilities* beyond the basic configuration space. These capabilities provide features like advanced error reporting, power management, virtualization, and more. Implementing these helps your emulated device appear more legitimate and interact correctly with modern host systems. **Steps:** 1. **Identify Required Extended Capabilities:** * When gathering donor device information with tools like Arbor, carefully look for and document any Extended Capabilities present in the donor's configuration space. These are usually found beyond the initial 256 bytes of standard configuration space. * **Common Examples:** * **Advanced Error Reporting (AER)**: Provides robust error detection, logging, and reporting mechanisms for PCIe links. * **Device Serial Number (DSN)**: (Already covered in Section 6.2). * **Power Management (PM)**: (Already covered in Section 8.3.1). * **PCI Express (PCIe) Capability Structure**: (Already covered in Section 8.1 for Link Speed/Width, Max Payload/Read Request, but also includes other fields like Device Control/Status, Link Control/Status). * **Virtual Channel (VC)/Multi-Function Virtual Channel (MFVC)**: For Quality of Service (QoS) and traffic management. * **Precision Time Measurement (PTM)**: For synchronizing time across devices. * **Latency Tolerance Reporting (LTR)**: For power management based on latency requirements. * **Resettable FPC (Function-Level Reset)**: For more granular resets. 2. **Enable Capabilities in Vivado PCIe IP Core:** * Access the PCIe IP core customization window (`pcie_7x_0.xci`) in Vivado. * Navigate through the various tabs (e.g., "PCIe Capabilities," "Extended Capabilities," "Advanced Options"). * Look for checkboxes or dropdowns to enable and configure the specific extended capabilities identified from your donor device. * **Example (AER):** You'll find a section for "Advanced Error Reporting" where you can enable it and configure its registers (e.g., severity masks). * **Note:** The Xilinx PCIe IP core provides a high degree of configurability for many standard and extended capabilities. It's often just a matter of enabling the correct options in the GUI. 3. **Implement Firmware Logic for Capability Registers (if necessary):** * While the PCIe IP core handles the *presence* and much of the *protocol* for these capabilities, some capabilities expose registers that your custom firmware might need to read or write, or whose values your firmware needs to react to. * **Example (AER):** If your emulated device detects an internal error that should be reported via AER, your firmware needs to write to specific AER error status registers (which might be exposed as part of the BARs or handled internally by the PCIe core and then reflected to user logic). Your user logic would then assert an error input to the PCIe core. * **Example (Power Management):** As discussed in 8.3.1, your firmware needs to react to the D-state changes signaled by the PCIe core. * **Process:** * Identify the specific registers within each enabled capability structure that your donor device's driver interacts with. * Locate the corresponding signals or logic within the PCILeech-FPGA framework that interface with these registers (often within `pcileech_pcie_cfg_a7.sv` or the `bar_controller`). * Implement read/write logic for these registers, ensuring your emulated device's internal state accurately reflects the values the driver expects. ### **9.2 Emulating Vendor-Specific Features** This is where true "full device emulation" becomes highly specialized. Many real-world devices have unique registers, undocumented commands, custom data formats, or proprietary control flows that differentiate them. Replicating these requires deeper analysis and custom HDL development. **Steps:** 1. **Reverse Engineer Vendor-Specific Behaviors:** * This is often the most challenging part. * **Static Analysis (Driver/Firmware):** Disassemble the donor device's official driver (Windows `.sys`, Linux `.ko`) or the device's original firmware (if available). Look for unique I/O or MMIO access patterns, magic values, or sequences of register writes. Tools like Ghidra, IDA Pro, or objdump can be invaluable. * **Dynamic Analysis (Driver Execution):** Run the donor device with its driver and monitor PCIe traffic using a **PCIe Protocol Analyzer** (e.g., Teledyne LeCroy, Keysight, as discussed in Section 12.2). This is the gold standard for understanding actual TLP exchanges, including vendor-defined messages and sequences of register accesses. Pay attention to: * Specific memory addresses accessed within BARs. * Read/write patterns to these addresses. * The values written to or read from specific registers. * Timing relationships between commands and responses. * **System Calls/API Monitoring**: On the host, use tools like Procmon (Windows) or `strace` (Linux) to see how the driver interacts with the OS and what specific device I/O control (IOCTL) codes it uses, which might correspond to specific hardware operations. * **Hardware Sniffing**: If possible, use a hardware sniffer (like a Saleae Logic Analyzer) to capture signals on the device's internal buses (e.g., SPI, I2C) if it has external flash or components. 2. **Implement Custom Registers and Logic within BARs:** * Once you've identified vendor-specific registers or command protocols, you'll need to define these within your FPGA firmware, typically as memory-mapped registers accessible via one of your BARs. * **Create Internal Registers:** Declare `reg` variables in your SystemVerilog code to represent these custom registers. ```verilog // In your pcileech_tlps128_bar_controller.sv or a sub-module reg [31:0] custom_control_reg; reg [31:0] custom_status_reg; reg [31:0] custom_data_reg; // Example: Map these to specific offsets within BAR0 (assuming BAR0 is large enough) // Adjust the 'bar0_offset' case statement (from Section 8.2.2) // ... if (bar_hit[0]) begin if (req_write) begin case (bar0_offset) 32'h0000_1000: custom_control_reg <= req_data; // Custom control register 32'h0000_1004: custom_data_reg <= req_data; // Custom data write register // ... other mappings endcase end else if (req_read) begin case (bar0_offset) 32'h0000_1000: rsp_data = custom_control_reg; // Read control register 32'h0000_1008: rsp_data = custom_status_reg; // Custom status register // ... other mappings endcase end end // ... ``` * **Implement Behavioral Logic:** Create SystemVerilog logic (state machines, combinational logic) that: * Responds to writes to your `custom_control_reg`. For example, a specific bit in this register might trigger a DMA transfer, clear a status flag, or initiate an internal operation. * Updates your `custom_status_reg` based on the internal state of your emulated device (e.g., "operation complete," "error occurred," "data available"). * Processes data written to `custom_data_reg` or provides data from it on reads, mimicking the donor device's data paths. 3. **Emulate Vendor-Specific Messages (if applicable):** * Some complex devices might use "Vendor Defined Messages" (VDMs) over PCIe for specific control or communication. If your analysis reveals such messages, you would need to: * Enable VDM support in the PCIe IP core (if available). * Implement TLP generation logic (as will be discussed in Section 10) to craft and send these VDMs. * Implement TLP reception and parsing logic to interpret incoming VDMs from the host. 4. **Validate Emulated Behavior:** * **Iterative Testing:** This is a highly iterative process. Make small changes, compile, flash, and test. * **Driver Loading:** Does the donor device's driver load correctly without errors? * **Functional Tests:** Can the driver initiate basic operations? Does it get the expected responses from your emulated registers? * **Application Tests:** Can applications that rely on the donor device function correctly with your emulated version? * **Debugging:** Use ILA and PCIe protocol analyzers extensively to compare your emulated device's behavior against the captured behavior of the real donor device. Look for discrepancies in TLP timing, register values, and overall protocol flow. --- ## **10. Transaction Layer Packet (TLP) Emulation** Transaction Layer Packets (TLPs) are the fundamental units of communication in the PCIe architecture. Every interaction between a host system and a PCIe device, from configuration reads to data transfers, is encapsulated within one or more TLPs. Accurate TLP emulation is not just important; it is *crucial* for your emulated device to interact properly with the host system, ensuring that drivers function correctly and that data moves as expected. ### **10.1 Understanding and Capturing TLPs** Before you can craft custom TLPs, you must deeply understand their structure and common types. Capturing real-world TLPs from your donor device provides the most accurate blueprint. #### **10.1.1 Learning the TLP Structure** A TLP is generally composed of a header, an optional data payload, and an optional End-to-End CRC (ECRC). The header is paramount, defining the TLP's type, transaction specifics, and routing information. * **Components of a TLP**: * **Header**: The most important part, typically 3 or 4 Double Words (Dwords = 4 bytes). It contains critical fields that define the TLP's purpose and how it should be handled: * **Fmt (Format) and Type**: Defines the TLP's format (3DW/4DW, with/without data) and its specific purpose (e.g., Memory Read Request, Memory Write, Completion, Configuration Read/Write). * **Length**: Specifies the size of the data payload in Dwords. * **Requester ID (Bus, Device, Function)**: Identifies the PCIe function that initiated the request. Essential for routing completions back to the correct source. * **Tag**: A unique identifier assigned by the Requester to a transaction, allowing a Completer to match a Completion TLP to its original Request TLP. * **Address**: For Memory/IO transactions, this is the target memory or I/O address. * **First DW Byte Enable (FBE)** and **Last DW Byte Enable (LBE)**: Specify which bytes within the first and last Dwords of the payload are valid for write operations, or which bytes are being requested for read completions. * **Traffic Class (TC)** and **Transaction ID (TID)**: For QoS and ordering rules. * **Data Payload (Optional)**: Present in TLPs like Memory Write, Configuration Write, and Read Completions. It contains the actual data being transferred. * **End-to-End CRC (ECRC) (Optional)**: A 32-bit CRC that covers the entire TLP, ensuring data integrity from source to destination, typically generated/checked by software. * **Understanding Common TLP Types**: Your firmware will primarily deal with these: * **Memory Read Request (MRd)**: A TLP sent by a Requester (e.g., host CPU, or your FPGA as a DMA master) to read data from a specific memory address. * **Memory Read Completion (CplD)**: A TLP sent by a Completer (e.g., your FPGA responding to a host MRd) carrying the requested data. * **Memory Write (MWr)**: A TLP sent by a Requester (e.g., host CPU, or your FPGA) to write data to a specific memory address. * **Completion Without Data (Cpl)**: A TLP sent by a Completer to acknowledge a request that does not return data (e.g., a successful MWr). * **Configuration Read Request (CfgRd)**: A TLP from the host to read registers in the device's Configuration Space. * **Configuration Read Completion (CplD)**: A TLP from the device returning data for a CfgRd. * **Configuration Write Request (CfgWr)**: A TLP from the host to write to registers in the device's Configuration Space. * **Vendor-Defined Messages (VDM)**: Custom TLPs used by specific vendors for proprietary communication. #### **10.1.2 Capturing TLPs from the Donor Device** Capturing real PCIe traffic from your donor device is invaluable. It provides concrete examples of TLP structures, sequences, and timing, allowing you to replicate them precisely. * **Steps**: 1. **Set Up a PCIe Protocol Analyzer**: * The most effective method involves using dedicated hardware tools, often referred to as "PCIe Protocol Analyzers." These devices sit in-line between the host and the donor PCIe card, passively capturing all traffic. * **Examples**: * **Teledyne LeCroy PCIe Analyzers**: Industry standard, highly capable, but significant investment. * **Keysight PCIe Analyzers**: Another leading vendor. * (For basic debugging, some higher-end logic analyzers with PCIe decoders might offer limited TLP viewing, but a true protocol analyzer is superior). 2. **Capture Transactions**: * Install the donor device in a test system with the protocol analyzer connected. * Run the donor device's driver and any associated applications. * Monitor and record the PCIe transactions during normal operation, and especially during critical phases like: * Device enumeration (when the OS first detects it). * Driver loading and initialization. * Typical data transfer operations (e.g., large file copies for a storage device, network traffic for a NIC). * Device-specific commands or diagnostics. 3. **Analyze Captured TLPs**: * Use the protocol analyzer's sophisticated software to dissect the captured TLPs. The software will decode fields, provide chronological views, and allow filtering and searching. * Pay close attention to: * The exact `Fmt` and `Type` fields. * `Requester ID` and `Tag` values (especially for completions). * The `Address` and `Length` for memory transactions. * The contents of `Data Payload` for writes and read completions. * Any vendor-specific fields or custom TLPs. #### **10.1.3 Documenting Key TLP Transactions** Structured documentation of captured TLPs creates a blueprint for your emulation. * **Steps**: 1. **Identify Critical Transactions**: * Focus on TLPs that are essential for the device's core functionality. These include: * **Initialization Sequence**: The series of configuration reads/writes the OS performs during enumeration. * **Driver Initialization**: The commands and data exchanged when the driver starts up. * **Primary Data Transfers**: How `MWr` and `MRd` TLPs are structured and completed for the device's main function. * **Error Handling**: How the device reports errors (e.g., Completion with Completer Abort (CA), Unsupported Request (UR)). * **Power Management Transitions**: TLPs related to D-state changes. * **Interrupt Generation**: How MSI/MSI-X messages are sent. 2. **Create Detailed Documentation**: * For each key TLP sequence, record: * The **TLP Type** (e.g., MWr, MRd, CplD). * Its **header fields** (Fmt, Type, Requester ID, Tag, Length, Address, Byte Enables). * The **data payload** (if applicable). * The **sequence number** or order within a transaction. * The **conditions** under which it is sent (e.g., "sent by host when driver initializes," "sent by device on DMA completion"). * Any **expected responses** or follow-up TLPs. * Screenshots from the protocol analyzer can be very helpful here. 3. **Understand Timing and Sequencing**: * Beyond just the TLP content, the *timing* and *sequence* of TLPs are vital. PCIe has strict ordering rules and flow control mechanisms. Pay attention to: * **Delay between Request and Completion**: How quickly the real device responds. * **Flow Control Credits**: How the device manages its buffer space for incoming/outgoing TLPs. While the Xilinx PCIe IP core handles basic flow control, for advanced emulation, knowing the donor's typical credit usage can be helpful. * **Transaction Layer Packet Ordering**: Understand how posted (writes) and non-posted (reads, completions) transactions are ordered. ### **10.2 Crafting Custom TLPs for Specific Operations** Once you understand the blueprint, you can translate this knowledge into your FPGA firmware (SystemVerilog) to actively generate and respond to TLPs. The PCILeech-FPGA framework provides abstraction layers, but for deep emulation, you might need to interact directly with the TLP generation/parsing logic. #### **10.2.1 Implementing TLP Handling in Firmware** Your firmware will need logic to both send and receive TLPs. The PCIe IP core handles the physical and data link layers, exposing a Transaction Layer interface (often AXI-Stream) to your user logic. * **Files to Modify (Primary)**: * `pcileech-fpga//src/pcileech_pcie_tlp_a7.sv` (or similar, depending on board variant) * This file often contains the core logic for translating user requests into outbound TLPs and parsing incoming TLPs into signals for your user logic. * `pcileech-fpga//src/pcileech_tlps128_bar_controller.sv` * This module specifically handles parsing incoming Memory Read/Write TLPs that target your device's BARs and generating corresponding Completion TLPs. * **Steps**: 1. **Understand the PCIe IP Core Interface**: * Before writing TLP logic, thoroughly read the Xilinx PCIe IP Core User Guide (specifically the sections on the User Application Interface or AXI4-Stream Interface). This defines how your SystemVerilog logic connects to the PCIe core to send and receive TLPs. You'll typically interact with `s_axis_rx_tdata` (received TLP data), `s_axis_rx_tvalid` (valid TLP received), `m_axis_tx_tdata` (outgoing TLP data), `m_axis_tx_tready` (core ready to accept TLP), etc. 2. **Create TLP Generation Functions (for outbound TLPs)**: * In `pcileech_pcie_tlp_a7.sv` (or a module that interfaces with `m_axis_tx_*`), you will write logic to assemble TLPs with the required headers and payloads. This often involves combining various fields into a `[127:0]` (for 128-bit interface) or `[63:0]` (for 64-bit interface) bus that feeds the PCIe core. * **Example (Conceptual, Simplified Function for a 3DW TLP Header):** ```verilog // This is a conceptual helper function. In reality, you'd build a state machine // to send TLPs over an AXI-Stream interface, possibly using a FIFO. function automatic [95:0] create_3dw_tlp_header; // Assuming 3 Dwords = 96 bits input logic [7:0] tlp_type_fmt; // Format and Type fields input logic [15:0] requester_id; // BDF input logic [7:0] tag; input logic [7:0] lower_address_bits; // Or more complex address input logic [7:0] byte_enables; // First DW Byte Enable begin create_3dw_tlp_header = { tlp_type_fmt, // Fmt[6:4], Type[3:0] 8'b0, // Reserved 4'b0, // TC[3:0] (Traffic Class) 3'b0, // Attr[2:0] 1'b0, // TH (TLP Hint) 2'b0, // D(igest) (ECRC presence) 1'b0, // EP (Poisoned) 1'b0, // TD (Type Dependent) // DW0: Fmt, Type, TC, Attr, TH, D, EP, TD, Length (not in 3DW, 4DW has it) requester_id, // Requester ID (Bus[7:0], Device[4:0], Function[2:0]) tag, // Tag lower_address_bits, // Example: lower bits of address or a portion of data byte_enables, // First DW Byte Enable 4'b0, // Reserved 4'b0 // Last DW Byte Enable (for MWr usually) // DW1, DW2... fields }; end endfunction // Example: Generating a Completion with Data (CplD) in a state machine // This is just a snippet, not a full implementation localparam CPLD_3DW_FMT = 8'h4A; // Fmt=100 (4DW, with data), Type=1010 (Cpl) localparam CPL_D_FMT_TYPE_LEN = 8'h4A; // Adjusted based on PCIe spec. (4DW header with data) // ... state machine to send TLP // In a state where you are ready to send CplD if (tx_ready_from_pcie_core) begin // Build the header and payload // For a CplD, you need Complier ID, Status, Byte Count, Requester ID, Tag, Completion ID, Lower Address // And then the actual read data payload m_axis_tx_tdata_reg = { CPL_D_FMT_TYPE_LEN, // Byte 0: Fmt/Type tlp_length_dw_minus_one, // Byte 1: TLP Length (in Dwords) - 1 status_completion_bits, // Byte 2: Cpl Status, BCM, Rsvd byte_count_dws_upper, // Byte 3: Byte Count (upper bits) requester_id, // Byte 4-5: Requester ID (from original MRd) tag, // Byte 6: Tag (from original MRd) byte_count_dws_lower, // Byte 7: Byte Count (lower bits) completion_id, // Byte 8-9: Completion ID (your BDF) lower_address_from_request // Byte 10-11: Lower Address from Request // ...followed by actual data payload }; m_axis_tx_tvalid_reg = 1'b1; m_axis_tx_tlast_reg = 1'b1; // Last TLP segment // ... state transition to wait for tready end ``` * **Note**: The actual implementation involves state machines, FIFOs, and adherence to the AXI-Stream protocol for the PCIe IP core. The PCILeech-FPGA framework already provides a good base for this, but you might extend or modify it for very specific TLP behaviors. 3. **Handle TLP Reception (for inbound TLPs)**: * Implement logic to parse incoming TLPs from the PCIe core's receive interface (e.g., `s_axis_rx_tdata`, `s_axis_rx_tvalid`). * This parsing involves: * Checking `s_axis_rx_tvalid` to know a TLP is present. * Reading the `Fmt` and `Type` fields from the TLP header to determine its purpose. * Extracting relevant fields like `Requester ID`, `Tag`, `Address`, `Length`, and `Data Payload`. * Use `case` statements or `if/else if` blocks based on the TLP type to route the information to the appropriate internal logic (e.g., `bar_controller` for Memory Writes, a configuration module for Configuration Writes). * **Example (Conceptual, Simplified Parsing):** ```verilog // In pcileech_pcie_tlp_a7.sv or a TLP parser module input wire [127:0] s_axis_rx_tdata; input wire s_axis_rx_tvalid; output wire s_axis_rx_tready; // Needs to be asserted to accept more data reg [7:0] received_tlp_fmt_type; reg [15:0] received_requester_id; // ... declare other parsed fields assign s_axis_rx_tready = 1'b1; // Always ready to receive for simplicity, manage backpressure in real design always @(posedge clk) begin if (s_axis_rx_tvalid) begin received_tlp_fmt_type = s_axis_rx_tdata[127:120]; // Assuming highest bits received_requester_id = s_axis_rx_tdata[111:96]; // Example offset // Decode based on TLP type case (received_tlp_fmt_type[3:0]) // Only TLP Type bits 4'h0: // Memory Write (3DW or 4DW depending on Fmt) // Extract address, length, payload and pass to BAR controller begin // Pass to BAR controller for writing to emulated memory // bar_write_enable = 1'b1; // bar_write_address = s_axis_rx_tdata[...]; // bar_write_data = s_axis_rx_tdata[...]; end 4'h1: // Memory Read // Extract address, length, and pass to BAR controller for reading begin // bar_read_enable = 1'b1; // bar_read_address = s_axis_rx_tdata[...]; // (Completion will be generated by BAR controller) end // ... other TLP types default: begin // Handle unsupported or reserved TLP types (e.g., log, error) end endcase end end ``` 4. **Ensure Compliance**: * Strictly verify that both your generated and parsed TLPs conform to the PCIe specification regarding format, field definitions, and timing. Deviations will lead to communication failures. 5. **Implement Completion Handling**: * For Memory Read Requests (MRd) and Configuration Read Requests (CfgRd) received from the host, your device is obligated to send back appropriate Completion TLPs (CplD for data, Cpl for no data) within a specific timeframe. The `bar_controller` module (Section 8.2.2) is where this logic for BAR reads resides. 6. **Save Changes**: * Save the files (`pcileech_pcie_tlp_a7.sv`, `pcileech_tlps128_bar_controller.sv`, or any custom modules) after implementing the changes. #### **10.2.2 Handling Different TLP Types** Each TLP type has a specific header format and behavior. Your firmware must be adept at handling the ones relevant to your donor device. * **Memory Read Requests (MRd)**: * **Implementation**: * When an MRd TLP is received (parsed by `pcileech_pcie_tlp_a7.sv` and routed to the `bar_controller`), the `bar_controller` needs to: * Parse the requested address and length. * Fetch the data from the appropriate internal memory location (e.g., BRAM connected to a BAR) or internal register. * Assemble a **Completion with Data (CplD)** TLP. Crucially, this TLP must include the original `Requester ID`, `Tag`, and `Completion ID` (your device's BDF) from the MRd request, along with the fetched data payload. * Send the CplD TLP back to the host via the PCIe IP core's transmit interface. * **Memory Write Requests (MWr)**: * **Implementation**: * When an MWr TLP is received, the `bar_controller` needs to: * Parse the target address, length, and `Byte Enables` (FBE/LBE). * Extract the `data payload`. * Write the data to the specified memory location within your emulated device (e.g., a BRAM or internal registers), respecting the byte enables. * Memory Writes are "posted transactions," meaning they don't require a completion TLP for acknowledgment unless an error occurs. * **Configuration Read/Write Requests (CfgRd/CfgWr)**: * **Implementation**: * These TLPs target the device's Configuration Space (Vendor ID, Device ID, BARs, Capabilities, etc.). The Xilinx PCIe IP core handles the majority of standard Configuration Space accesses automatically based on its configuration. * However, if you have custom registers or extended capabilities *within* the Configuration Space that are not standard, you might need specific logic to: * For CfgRd: Return the requested data from your internal `cfg_` registers. * For CfgWr: Update your internal `cfg_` registers or trigger actions based on the written data. * Configuration Reads require a **Completion with Data (CplD)**, while Configuration Writes require a **Completion without Data (Cpl)**. * **Vendor-Defined Messages (VDM)**: * **Implementation**: * If your donor device uses VDMs, this requires specialized parsing and response logic. * **Parsing Incoming VDMs**: Identify VDMs based on their `Fmt` and `Type` fields. Extract the vendor-specific data and interpret it according to your reverse-engineering findings. * **Crafting Outbound VDMs**: Create logic to assemble VDMs with the precise vendor-specific header and payload formats when your emulated device needs to send them. #### **10.2.3 Validating TLP Timing and Sequence** Even if TLPs are perfectly formatted, incorrect timing or sequencing will lead to device malfunction or detection as non-compliant. * **Steps**: 1. **Use Simulation Tools**: * **Test Benches**: Develop comprehensive SystemVerilog test benches for your TLP generation and parsing modules. * Simulate various scenarios (e.g., host sending MRd, your device sending CplD; host sending MWr; host enumerating device) to validate that TLPs are correctly formed, transmitted, received, and processed. * Verify the sequence of TLPs and that completions are sent within reasonable timeframes. 2. **Monitor with ILA (Integrated Logic Analyzer)**: * As detailed in Section 12.1, insert an ILA core into your Vivado design. * Connect the ILA probes to the AXI-Stream interfaces of the PCIe IP core (e.g., `s_axis_rx_tdata`, `s_axis_rx_tvalid`, `m_axis_tx_tdata`, `m_axis_tx_tready`). * Set triggers to capture specific TLPs (e.g., on `m_axis_tx_tvalid` for a certain TLP type). * This allows you to see the actual TLP bits on the FPGA in real time during hardware operation, verifying if your firmware is sending/receiving the correct data and control signals to/from the PCIe IP core. 3. **Check Timing Constraints**: * The PCIe IP core has strict timing requirements for its AXI-Stream interfaces. Ensure that your user logic providing data to `m_axis_tx_tdata` and handling `s_axis_rx_tdata` meets these timing constraints. * Vivado's timing analysis reports (after synthesis and implementation) will flag any violations. Address these by optimizing your logic or adjusting clocking where possible. 4. **Compliance Testing (Advanced)**: * For high-fidelity emulation, consider using a dedicated PCIe compliance test suite (often integrated with high-end protocol analyzers). These tests systematically check adherence to the PCIe specification, uncovering subtle protocol violations. 5. **Save Changes**: * Save all modified files after thorough testing and validation. Iteration is key in TLP-level debugging. --- ## **Part 3: Advanced Techniques and Optimization** --- ## **11. Building, Flashing, and Testing** After all your customizations are complete, the moment of truth arrives: building the firmware, programming it onto your FPGA, and rigorously testing its functionality to ensure it behaves exactly like the donor device. This phase transitions your design from code to a working hardware emulation. ### **11.1 Synthesis and Implementation** These are the core steps in the FPGA design flow, where your high-level SystemVerilog code is transformed into a low-level hardware configuration that can be loaded onto the FPGA. #### **11.1.1 Running Synthesis** Synthesis is the process by which Vivado translates your HDL code into a gate-level netlist (a description of logical gates and their interconnections). It also performs preliminary timing analysis and resource estimation. * **Steps**: 1. **Start Synthesis**: * In the Vivado GUI, in the **Flow Navigator** pane (typically on the left), under "Synthesis," click **Run Synthesis**. 2. **Monitor Progress**: * Vivado will open a "Launch Runs" dialog. You can typically just click "OK." * Monitor the **Messages** tab at the bottom of the Vivado window. It will show the progress of the synthesis run. * **Common Warnings/Errors to Watch For**: * **`[Synth 8-327]` Unconnected Ports / Unused Inputs**: These indicate that a signal or port in your design is not connected to anything. While sometimes intentional (e.g., unused pins on the FPGA), they can also point to typos in port names or forgotten connections. Investigate each to ensure it's not a functional issue. * **`[Synth 8-256]` Registers/Wires Not Optimized**: This might indicate that logic is being inferred incorrectly or that you have redundant logic that could be optimized. * **Syntax Errors**: If there are fatal syntax errors in your SystemVerilog code, synthesis will fail immediately. Fix these in Visual Studio Code. 3. **Review Synthesis Report**: * Upon successful completion, Vivado will ask you what to do next. Select **Open Synthesized Design** or **Open Report**. * Crucially, review the **Utilization Summary** in the synthesis report. This shows how much of the FPGA's resources (LUTs, Flip-Flops, BRAMs, DSPs) your design consumes. Ensure that the design fits within your target FPGA's capacity (e.g., for a Artix-7 35T, you should be well within its limits). #### **11.1.2 Running Implementation** Implementation is the most time-consuming step. It takes the synthesized netlist and physically maps it onto the FPGA's resources (placing logic blocks, routing connections) and then performs a detailed timing analysis to ensure the design can operate at the specified clock frequencies. * **Steps**: 1. **Start Implementation**: * After successful synthesis, in the **Flow Navigator**, under "Implementation," click **Run Implementation**. * Confirm the "Launch Runs" dialog. 2. **Monitor Progress**: * Implementation consists of several phases: Opt Design, Power Opt Design, Place Design, Post-Placement Phys Opt Design, Route Design, Post-Route Phys Opt Design. Each phase can take a significant amount of time. * Monitor the **Messages** tab for progress and potential issues. 3. **Analyze Timing Reports**: * This is *the most critical step* after implementation. Upon completion, Vivado will again ask what to do next. Select **Open Implemented Design** or, more importantly, **Open Report** and then select **Report Timing Summary**. * **Ensure that all timing constraints are met.** Look for "WNS (Worst Negative Slack)" values. * **Positive WNS**: Indicates that all timing paths meet their requirements (slack means you have extra time). This is what you want. * **Negative WNS**: Indicates **timing violations**, meaning your design cannot operate at the desired clock frequency or data might not be stable. **This is a critical issue that *must* be addressed.** * **Address Violations**: * If you have negative slack, investigate the specific paths that are failing. Vivado's timing report will show you the source, destination, and components of the failing paths. * Solutions can include: * Optimizing your HDL code to reduce logic depth or critical path delays. * Adding pipeline stages (registers) to break up long combinational paths. * Refining your XDC (constraints) file, ensuring all clocks are correctly defined and propagated. * Adjusting clock frequencies (if the application allows). * Using faster timing-closure strategies in Vivado. * Ensuring your custom logic interfaces correctly with the PCIe core's AXI-Stream interface timing requirements. 4. **Verify Placement (Optional)**: * In the implemented design, you can open the "Device" view to see how your logic has been placed on the FPGA. This is generally for advanced users to confirm that critical components are placed optimally (e.g., close to PCIe transceivers). #### **11.1.3 Generating Bitstream** The bitstream is the final, binary configuration file (`.bit` extension) that will be loaded onto your FPGA. It's the culmination of synthesis and implementation. * **Steps**: 1. **Generate Bitstream**: * After successful implementation (with no critical timing violations), in the **Flow Navigator**, under "Program and Debug," click **Generate Bitstream**. 2. **Wait for Completion**: * This process generally takes less time than implementation but can still vary based on design complexity. 3. **Review Bitstream Generation Log**: * Upon completion, Vivado will indicate success. Review the log for any warnings, though typically if implementation passed cleanly, bitstream generation will too. * The `.bit` file will be generated in your project's `pcileech_squirrel_top.runs/impl_1/` directory (or similar path for your board). ### **11.2 Flashing the Bitstream** Programming (flashing) the bitstream loads your compiled design onto the FPGA, making your emulated device active. #### **11.2.1 Connecting the FPGA Device** * **Steps**: 1. **Prepare Hardware**: * Ensure your FPGA-based DMA board is correctly inserted into a compatible PCIe slot on your host system. * Connect the JTAG programmer (e.g., Digilent HS3, Xilinx Platform Cable) to the JTAG header on your FPGA board and to a USB port on your development PC. * Power on the host system. * Refer to your specific FPGA board's manual for precise power, JTAG, and PCIe connection instructions. 2. **Open Hardware Manager**: * In Vivado, navigate to **Flow Navigator > Program and Debug > Open Hardware Manager**. * If Vivado is not running, you can launch Hardware Manager as a standalone application. #### **11.2.2 Programming the FPGA** * **Steps**: 1. **Connect to the Target**: * In the Hardware Manager window, click **Open Target** (often a large button or link) and select **Auto Connect**. * Vivado should automatically detect your JTAG programmer and then the connected FPGA device(s) on the JTAG chain. If detection fails, check JTAG cable connections, power to the board, and JTAG drivers on your PC. 2. **Program Device**: * Once your FPGA device is detected and displayed in the Hardware window, **right-click** on your FPGA device (e.g., `xc7a35t_0`) and select **Program Device**. * A dialog will appear. Click the "..." button next to the "Bitstream file" field and navigate to your generated bitstream file (e.g., `pcileech_squirrel_top.runs/impl_1/pcileech_squirrel_top.bit`). * Click **Program** to begin flashing the firmware onto the FPGA. * Wait for the programming process to complete. You'll see a progress bar. #### **11.2.3 Verifying Programming** * **Steps**: 1. **Check Status**: * Ensure the programming completes without errors in Vivado's Hardware Manager. Vivado will display a "Program Device" success message upon completion. 2. **Observe LEDs or Indicators**: * Many FPGA boards have status LEDs. A successful programming operation often causes a specific LED to illuminate or change state (e.g., a "DONE" LED). This is a quick visual confirmation. 3. **Host System Reboot (Sometimes Required)**: * For the host operating system to correctly recognize the newly programmed PCIe device, a system reboot is often necessary, especially on Windows, to trigger the full PCIe enumeration process. ### **11.3 Testing and Validation** After programming, the crucial step is to verify that your emulated device is detected correctly by the host and that it functions as expected, mimicking the donor device. #### **11.3.1 Verifying Device Enumeration** This confirms that the host OS sees your FPGA as the donor device based on the IDs you programmed. * **Windows**: * **Steps**: 1. **Open Device Manager**: Press `Win + X` and select **Device Manager** from the Quick Link menu. 2. **Check Device Properties**: * Look under the appropriate device category (e.g., **Network Adapters**, **Storage Controllers**, **System devices**). * Find your emulated device. It should now appear with the *name of the donor device* (e.g., "Intel(R) Ethernet Connection...") * Right-click on the device, select **Properties**, and go to the **Details** tab. * In the "Property" dropdown, select "Hardware Ids." Confirm that the **Device ID (DID)** and **Vendor ID (VID)** (e.g., `PCI\VEN_ABCD&DEV_1234`) match those you programmed into your firmware. * Also check "Class Code" and "Subsystem ID" for further verification. * **Linux**: * **Steps**: 1. **Use `lspci`**: Open a terminal and use the `lspci` command. ```bash lspci -nn # Shows VendorID:DeviceID lspci -vvv # Shows verbose details including BARs, capabilities, and more ``` 2. **Verify Device Listing**: * Check that the emulated device appears in the `lspci` output with the correct Vendor ID, Device ID, and Class Code. * **Example Output (emulating an Intel NIC):** ``` 03:00.0 Network controller [0280]: Intel Corporation Ethernet Connection I219-V [8086:1570] (rev 21) ``` (`8086` is Intel's Vendor ID, `1570` is the Device ID for I219-V, `0280` is the Network Controller Class Code). * Use `lspci -vvv` to confirm that the BARs are enumerated with the correct sizes and types, matching your donor device's configuration. #### **11.3.2 Testing Device Functionality** Once the device is enumerated, the ultimate test is whether it functions like the original. * **Steps**: 1. **Install Necessary Drivers**: * If the host OS doesn't automatically load a suitable driver, you will need to manually install the official drivers for your donor device. Download them from the manufacturer's website. * Install them as per the manufacturer's instructions. If the emulation is successful, the driver should install and recognize your FPGA as the real hardware. 2. **Perform Functional Tests**: * Run applications or utilities that would typically interact with the donor device. * **Examples**: * **Network Card**: Perform ping tests, browse the web, or initiate large file transfers to test throughput. * **Storage Controller**: Attempt to format a simulated drive (if your emulation includes storage features), perform read/write operations, or run disk benchmarks. * **USB Controller**: Connect USB devices (if your emulation includes USB host functionality) and test their detection and operation. * Monitor the host system for expected behavior and performance characteristics. 3. **Monitor System Behavior**: * Check for system stability (no BSODs on Windows, kernel panics on Linux). * Look for device-specific errors in system logs (Event Viewer on Windows, `dmesg` or `journalctl` on Linux). * Ensure that the emulated device behaves as expected under various workloads, including heavy data transfers or stress tests. #### **11.3.3 Monitoring for Errors** Proactive error monitoring is crucial for identifying subtle emulation issues that might not cause immediate crashes. * **Windows**: * **Steps**: 1. **Check Event Viewer**: Press `Win + X` and select **Event Viewer**. 2. **Look for PCIe-Related Errors**: Navigate to **Windows Logs > System**. Filter or search for warnings, errors, or critical events related to "PCIe," "PCI Express," or events originating from the specific device driver (look for source names matching your emulated device's driver). * Common errors include resource conflicts, driver initialization failures, or unexpected device responses. * **Linux**: * **Steps**: 1. **Check `dmesg` Logs**: Open a terminal and type: ```bash dmesg | grep -i pci # Case-insensitive grep for pci messages dmesg | grep -i # Filter for your device's Vendor ID ``` 2. **Identify Issues**: Look for messages indicating problems with PCIe link training, device initialization, memory allocation failures, driver probing errors, or unexpected DMA activity. The Linux kernel's PCIe subsystem is quite verbose. * **Systemd Journal (Modern Linux)**: ```bash journalctl -b | grep -i pci # Current boot log ``` --- ## **12. Advanced Debugging Techniques** When issues arise, especially in complex PCIe device emulation, basic troubleshooting might not suffice. Advanced debugging tools and techniques provide deep visibility into the FPGA's internal logic and the PCIe bus, allowing you to identify and resolve problems efficiently. ### **12.1 Using Vivado's Integrated Logic Analyzer (ILA)** The Integrated Logic Analyzer (ILA) is a powerful, configurable debug IP core provided by Xilinx that you can embed directly into your FPGA design. It allows you to monitor the real-time behavior of internal FPGA signals (wires and registers) without needing external probing hardware, functioning like a powerful, internal oscilloscope or logic analyzer. #### **12.1.1 Inserting ILA Cores** * **Steps**: 1. **Plan Your Probes**: Identify the key signals you need to observe. For PCIe emulation, these often include: * The AXI-Stream interfaces of the PCIe IP core (e.g., `s_axis_rx_tdata`, `s_axis_rx_tvalid`, `m_axis_tx_tdata`, `m_axis_tx_tready`). * Internal state machine signals (`current_state`, `next_state`). * BAR address decoding outputs (`bar_hit[0]`, `bar_hit[1]`). * Custom register values (`custom_control_reg`, `custom_status_reg`). * Interrupt request signals (`msi_trigger_signal`). 2. **Add ILA IP Core**: * In Vivado, open the **IP Catalog** (usually in the **Flow Navigator** pane). * Search for "ILA" (Integrated Logic Analyzer). * Double-click on the "Debug Bridge" (for basic ILA) or "Integrated Logic Analyzer (ILA)" to open its customization GUI. * Configure the ILA: * Set the **Number of Capture Data Ports** (probes) you need. * Set the **Width** of each probe to match the signals you plan to connect. * Configure the **Sample Depth** (how many samples to store before/after a trigger). Larger depths consume more BRAM. * Click "OK" and let Vivado generate the IP. 3. **Instantiate and Connect Signals**: * Vivado will generate an `.xci` file for the ILA. You can instantiate it directly in your top-level SystemVerilog file (e.g., `pcileech_squirrel_top.sv`) or within a module where the signals of interest are available. * **Example (in `pcileech_squirrel_top.sv` or a sub-module):** ```verilog // Assuming you've generated ila_0 from IP Catalog // Connect to your design's clock and signals of interest ila_0 your_ila_instance ( .clk(clk_125mhz), // Connect to a stable clock in your design, typically the PCIe user clock .probe0(pcie_s_axis_rx_tdata), // Example: PCIe inbound TLP data .probe1(pcie_s_axis_rx_tvalid), // Example: PCIe inbound TLP valid .probe2(pcie_m_axis_tx_tdata), // Example: PCIe outbound TLP data .probe3(my_bar_controller_state), // Example: State of your BAR logic .probe4(my_custom_register), // Example: Value of a custom register // Add more probes as needed .probeN(signal_to_monitor_N) ); ``` * **Alternative (Marking for Debugging):** For simpler signals, you can sometimes mark them directly in your HDL code for debugging. Use `(* mark_debug = "true" *) wire my_signal;` or `(* mark_debug = "true" *) reg my_register;`. Vivado will then automatically suggest adding these to an ILA. #### **12.1.2 Configuring Trigger Conditions** ILA is most powerful when you configure intelligent trigger conditions to capture data precisely when an event of interest occurs (e.g., an error, a specific TLP type, a state transition). * **Steps**: 1. **Generate Bitstream with ILA**: After inserting and connecting the ILA, you must run synthesis, implementation, and generate a new bitstream. The ILA core consumes FPGA resources and will be embedded in your design. 2. **Open Hardware Manager**: Program your FPGA with the ILA-enabled bitstream (Section 11.2). Then, in Vivado, open the Hardware Manager and connect to your target. 3. **Access the ILA Dashboard**: In the Hardware Manager, select your ILA instance (e.g., `hw_ila_1`). This will open the ILA dashboard. 4. **Define Triggers**: * Select the probes you want to use as trigger inputs. * Set specific **trigger patterns** (e.g., `0x4A` for `pcie_s_axis_rx_tdata` to trigger on a Completion TLP). * Configure **trigger conditions** (e.g., "equal to," "not equal to," "rising edge," "falling edge"). * Set **trigger positions** (how many samples to capture *before* the trigger event, for pre-trigger visibility). * You can set up multiple trigger sequences for complex event detection. * **Example Scenarios for Triggers**: * Trigger on a specific `Fmt/Type` in a received TLP to analyze incoming commands. * Trigger when a specific register (`my_custom_register`) reaches a certain value. * Trigger on a `pcie_m_axis_tx_tvalid` AND `pcie_m_axis_tx_tdata[3:0]` == `4'hC` (for a Memory Write TLP) to analyze outbound writes. * Trigger on the assertion of an error signal. #### **12.1.3 Capturing and Analyzing Data** * **Steps**: 1. **Run the Design**: Allow your host system to interact with the programmed FPGA, causing the events you want to debug. 2. **Arm the ILA**: In the ILA dashboard, click the **Run Trigger** button (often a green "Play" icon). The ILA will wait for the defined trigger condition. 3. **Capture Data**: Once the trigger condition is met, the ILA will capture a snapshot of the signals into its internal memory buffer. 4. **Analyze Waveforms**: * The captured data will appear in the waveform viewer. * Inspect the signal behavior over time. Zoom in, add cursors, and decode values. * Look for: * **Unexpected transitions**: Signals changing at the wrong time. * **Incorrect values**: Registers holding incorrect data. * **Protocol violations**: Your logic sending incorrect data on PCIe interfaces. * **Timing issues**: If signals are not stable when expected (though full timing analysis is done in implementation, ILA shows runtime behavior). * Compare the captured behavior against your expected design logic and the observed behavior of the donor device (if you captured it with a protocol analyzer). ### **12.2 PCIe Traffic Analysis Tools** While ILA gives you internal FPGA visibility, external PCIe traffic analysis tools provide an unrivaled view of the actual communication on the PCIe bus *between* your emulated device and the host. This is crucial for verifying protocol compliance and debugging link-level issues. #### **12.2.1 PCIe Protocol Analyzers (Hardware)** * **Examples**: * **Teledyne LeCroy PCIe Analyzers**: Gold standard for deep analysis, full protocol decoding, advanced triggering, and error injection capabilities. * **Keysight PCIe Analyzers**: Another leading vendor with similar high-end features. * **Steps**: 1. **Set Up Analyzer**: Connect the hardware analyzer in-line between the host system's PCIe slot and your FPGA-based DMA device. This typically involves a special interposer card. 2. **Configure Capture Settings**: Use the analyzer's software to define what traffic to capture. You can filter by TLP type, address, Requester ID, error conditions, etc., to focus on relevant events. 3. **Capture Traffic**: Run your emulated device on the host. The analyzer will passively record all PCIe transactions. 4. **Analyze Results**: * Use the analyzer's powerful software to view decoded TLPs, transaction lists, and waveform views. * **Examine TLPs for compliance and correctness**: Are all fields correct? Is the sequence proper? * **Identify any protocol violations or unexpected behaviors**: This is where you find why the driver might be failing (e.g., your device sends a Completion with data when the spec requires a Completion without data, or it responds too slowly). * **Compare with Donor Device Captures**: Directly compare the captured traffic from your emulated device to the captures you made from the real donor device. This is the ultimate test of emulation accuracy. #### **12.2.2 Software-Based Tools** For basic PCIe bus inspection, or if a dedicated hardware analyzer is unavailable, some software tools can provide limited insights. * **Examples**: * **Wireshark with PCIe Plugins**: While Wireshark is primarily for network traffic, with specialized hardware (e.g., network cards that expose PCIe traces to the OS, or specific capture hardware/drivers), it can sometimes capture and decode PCIe packets. This is highly dependent on the system. * **ChipScope Pro (Legacy Xilinx, now part of Vivado)**: Integrated Logic Analyzer (ILA) is the modern equivalent, but ChipScope was the standalone tool. * **`lspci` (Linux)**: As mentioned in Section 11.3.1, `lspci -vvv` provides extensive static configuration space information. You can combine it with `watch` or scripting to monitor changes over time. * **`pcileech` client (from the PCILeech framework)**: The `pcileech` client software itself can perform read/write operations to memory and configuration space via your FPGA, and can be used to test basic DMA functionality. While not a "traffic analyzer," it's essential for testing the functional interface. * **Steps**: 1. **Install Necessary Tools/Plugins**: Ensure the tool is installed and any required drivers or plugins are configured. 2. **Monitor PCIe Bus**: Run the software tool to capture and display PCIe-related information. 3. **Analyze Communications**: * Look for discrepancies in device configuration. * If the tool supports it, analyze the structure of captured packets for anomalies or errors. * Verify that your emulated device is responding to configuration requests correctly. --- ## **13. Troubleshooting** This section provides solutions to common problems you may encounter during custom firmware development, bitstream programming, and hardware testing of your PCIe device emulation. Firmware debugging can be challenging, so a methodical approach is key. ### **13.1 Device Detection Issues** **Problem**: Your FPGA-based DMA device, after programming, is not recognized by the host system, or it shows up with incorrect IDs (e.g., "Unknown device") or an error symbol in Device Manager/lspci. #### **Possible Causes and Solutions**: 1. **Incorrect Device IDs, Vendor IDs, Subsystem IDs, or Class Code**: * **Cause**: The most common reason. There is a mismatch between the identification values programmed into your FPGA firmware and what the host operating system expects, or what you intend to emulate. * **Solution**: * **Verify**: Double-check all `cfg_deviceid`, `cfg_vendorid`, `cfg_subsysid`, `cfg_subsysvendorid`, `cfg_revisionid`, and `cfg_classcode` parameters in `pcileech_pcie_cfg_a7.sv` (or equivalent file) against your meticulously recorded donor device information (from Section 5). * **Consistency**: Ensure these values are also consistently set in the Vivado PCIe IP Core customization GUI (Section 7.2.2). * **Rebuild & Re-flash**: After any changes, always re-synthesize, re-implement, generate a new bitstream, and re-flash the FPGA (Section 11.1, 11.2). * **Reboot Host**: Always reboot the host system after flashing, as Windows often needs a full restart to re-enumerate PCIe devices correctly. 2. **PCIe Link Training Failure**: * **Cause**: The fundamental PCIe link between the host's root complex and your FPGA card fails to establish. This happens before any configuration space reads. Symptoms include the device not appearing at all (`lspci` shows nothing at that bus/slot, or Device Manager shows a "PCI Express Root Port" error). * **Solution**: * **Physical Connections**: Ensure the FPGA board is seated firmly in the PCIe slot and all power connections are secure. Try a different PCIe slot if available. * **Power**: Verify that the FPGA board is receiving adequate power. Some boards require auxiliary PCIe power connectors. * **Link Speed/Width**: * Check `Max Link Speed` and `Link Width` settings in your Vivado PCIe IP Core (Section 8.1.1). * Try setting the link speed to a lower generation (e.g., Gen1 / 2.5 GT/s) and width to x1, even if your board supports higher. Sometimes, compatibility issues arise with specific motherboards at higher speeds. * Check motherboard BIOS settings for PCIe slot speed options. * **Reset**: Ensure the FPGA's reset logic is correctly implemented (e.g., synchronized to the PCIe reference clock) and asserted/de-asserted correctly upon power-up/reboot. * **PCIe IP Core**: Ensure the PCIe IP core is correctly instantiated and its clocks and resets are properly connected in your top-level design. 3. **Power Issues (Insufficient or Unstable Power)**: * **Cause**: The FPGA board is not receiving enough stable power, or the power supply is noisy, leading to unreliable operation. * **Solution**: * **Verify Connections**: Double-check all power cables (main PCIe slot power, auxiliary PCIe power, external DC jack if used). * **Power Supply**: Ensure your host system's power supply (PSU) has sufficient wattage and stable 12V rails. For high-power FPGAs, a weak PSU can cause issues. * **External Power**: If the board has an external power jack, ensure it's used with the correct voltage and current rating. 4. **Firmware Errors (Early Stage)**: * **Cause**: Logic errors in your SystemVerilog code, particularly in the top-level module or the PCIe core's wrapper, that prevent the PCIe core from initializing or presenting itself correctly. * **Solution**: * **Vivado Messages**: Scrutinize Vivado's synthesis and implementation logs for **Critical Warnings** or **Errors** related to the PCIe IP core. These are often indicators of misconfigurations or improper connections. * **ILA Debugging**: If the link attempts to train but fails, use an ILA (Section 12.1) connected to the PCIe IP core's status signals (e.g., `link_up`, `link_speed`, `link_width`) and AXI-Stream interfaces to see at what point the link negotiation fails or if the core is generating unexpected traffic. ### **13.2 Memory Mapping and BAR Configuration Errors** **Problem**: The emulated device is detected, but when the host OS or a driver tries to access its memory-mapped registers or buffers (via BARs), it crashes, freezes, or reports errors. #### **Possible Causes and Solutions**: 1. **Incorrect BAR Sizes or Types (IP Core & Firmware)**: * **Cause**: The BAR sizes or types (32-bit/64-bit, Memory/I/O, Prefetchable/Non-prefetchable) configured in your Vivado PCIe IP Core (Section 7.2.2) and/or handled in your `pcileech_tlps128_bar_controller.sv` do not match what the donor device actually provides. This can cause the host to allocate an incorrect address space or attempt unsupported accesses. * **Solution**: * **Cross-Verify**: Go back to your Arbor/protocol analyzer data (Section 5) and re-verify every single BAR configuration (size, type, prefetchable). * **Consistency**: Ensure these match perfectly in the PCIe IP Core customization and that your `bar_controller` logic correctly handles the size (address decoding range) and type of each BAR. * **BRAM Sizing**: If your BARs map to BRAMs, confirm that the BRAM IP core sizes (Section 8.2.1) exactly match the BAR sizes. 2. **Address Decoding Errors in Firmware**: * **Cause**: Your `pcileech_tlps128_bar_controller.sv` (or custom BAR logic) is misinterpreting the incoming PCIe addresses, leading to accesses to incorrect internal registers or memory locations. * **Solution**: * **Review Logic**: Meticulously review the `case` statements and address calculations in your `bar_controller`. * **Simulation**: Develop specific test cases in your SystemVerilog test bench to simulate host read/write accesses to various offsets within each BAR. Verify that the internal `bar_hit` signals are correct and that the data is routed to/from the correct internal registers/BRAMs. * **ILA Debugging**: Place ILA probes on the `req_addr`, `req_write`, `req_read`, `req_data`, `rsp_data`, and the internal signals related to your address decoding and register access within the `bar_controller`. Observe how the address is decoded and what data is being read/written in real time. 3. **Overlapping Address Spaces (Internal)**: * **Cause**: While the PCIe standard ensures that BARs from different devices don't overlap in the host's memory map, *internally* within your FPGA, you might accidentally map different logical components to the same physical address space within a single BAR. * **Solution**: * **Map Carefully**: When defining internal registers and memory blocks within a BAR, explicitly assign unique, non-overlapping offsets to each. Use `localparam` for these offsets to prevent errors. * **Design Review**: A thorough design review of your `bar_controller` is necessary to ensure every address range is uniquely handled. 4. **BRAM Access Issues**: * **Cause**: Problems with interfacing your logic to the BRAM IP cores (e.g., incorrect BRAM clocking, asynchronous resets, wrong byte enables, or incorrect write enable logic). * **Solution**: * **BRAM Documentation**: Consult the Xilinx BRAM IP core documentation for correct instantiation and interface signals. * **ILA**: Place ILA probes on the BRAM interface signals (address, write enable, data in, data out) to verify that your logic is sending the correct control signals to the BRAM. ### **13.3 DMA Performance and TLP Errors** **Problem**: The device is detected and functionally appears to work, but data transfer rates are slow, or the system experiences intermittent crashes, hangs, or errors during large DMA operations. PCIe protocol analyzers report malformed TLPs or flow control issues. #### **Possible Causes and Solutions**: 1. **Malformed TLPs (Header/Payload)**: * **Cause**: Your firmware is generating TLPs (especially Completions or outbound Memory Writes if your FPGA is acting as a DMA master) with incorrect headers, lengths, byte enables, or payloads. The host system's PCIe core or driver detects these as violations. * **Solution**: * **PCIe Protocol Analyzer**: This is the best tool here (Section 12.2.1). Capture traffic and meticulously compare your generated TLPs against the PCIe specification and, more importantly, against captures from your *real donor device*. * **TLP Generation Logic**: Review your TLP assembly code (`pcileech_pcie_tlp_a7.sv` and related modules). Ensure all fields (Fmt, Type, Requester ID, Tag, Completion ID, Length, Byte Enables, Address) are correctly derived and packed into the TLP structure. * **Error Checking**: Implement basic error checking in your firmware (e.g., checking for unexpected `req_valid` without `req_ready` or vice-versa). 2. **Flow Control Issues**: * **Cause**: PCIe uses a credit-based flow control mechanism. If your firmware (or the PCIe IP core's interaction with it) incorrectly manages credits, it can lead to deadlocks, timeouts, or dropped packets. Symptoms include a "stalled" PCIe link, timeouts, or low throughput. * **Solution**: * **PCIe IP Core Configuration**: Ensure the flow control settings within the Vivado PCIe IP Core customization are appropriate for your expected traffic patterns. The default settings are usually robust. * **User Logic Backpressure**: Your user logic that sends TLPs to the PCIe IP core (`m_axis_tx_*` interface) *must* respect the `m_axis_tx_tready` signal from the IP core. If `tready` is de-asserted, you *must* pause sending data. Failing to do so will overflow the core's buffers. * **ILA Debugging**: Connect ILA probes to the flow control interface signals of the PCIe IP core and your user logic to observe if `tvalid`/`tready` handshake is working correctly. 3. **Inefficient DMA Logic / Buffering Issues**: * **Cause**: Your DMA engine implementation within the FPGA (the part that reads/writes data to/from host memory) is not optimized, causing bottlenecks. This can involve: * Lack of pipelining. * Inefficient use of BRAMs. * Stalls due to external memory access latency. * Small burst sizes. * **Solution**: * **Pipelining**: Break down long combinational paths into smaller, sequential stages using registers. This allows higher clock frequencies and better throughput. * **Buffering**: Use FIFOs (First-In, First-Out buffers) to decouple sender and receiver logic, smoothing out data flow and preventing stalls. * **Burst Transfers**: Utilize PCIe's ability to perform burst reads/writes for efficiency. Ensure your DMA logic requests and handles data in appropriate burst sizes. * **Memory Bandwidth**: Ensure your BRAMs or external DDR memory interfaces are capable of supplying/consuming data fast enough for your desired DMA rates. * **ILA**: Monitor your DMA engine's internal state, read/write pointers, and data path signals to identify bottlenecks. 4. **Completion Timeout / Unsupported Request**: * **Cause**: The host sends a request (e.g., MRd, CfgRd), but your FPGA device does not respond with a Completion TLP within the allowed timeout period, or it responds with an error status (e.g., Completion with Unsupported Request (UR) or Completer Abort (CA)). * **Solution**: * **Response Logic**: Verify that your `bar_controller` (for MRds) and `pcileech_pcie_cfg_a7.sv` (for CfgRds to custom config space) correctly identify the request and generate the appropriate Completion. * **Timeout Value**: Review your donor device's expected completion latency. While PCIe defines default timeouts, some drivers might be sensitive. * **ILA/Protocol Analyzer**: Crucial for pinpointing *why* a completion isn't sent or why it's malformed. Is the request TLP even reaching your user logic? Is your logic generating a response? Is the PCIe core successfully sending the response? --- ## **14. Emulation Accuracy and Optimizations** Achieving truly convincing emulation means making your FPGA-based device indistinguishable from the donor, not just in its ID, but in its behavior. This requires meticulous attention to timing, responsiveness, and subtle operational details. ### **14.1 Techniques for Accurate Timing Emulation** Precise timing is paramount in hardware, especially for high-speed interfaces like PCIe. Mismatches can lead to driver timeouts, incorrect data interpretation, or system instability. * **Implement Timing Constraints (XDC Files)**: * **Purpose**: Timing constraints are instructions to Vivado's synthesis and implementation tools, telling them how fast your design needs to operate. They define clock periods, input/output delays, and path delays. * **Usage**: The PCILeech-FPGA project includes XDC files (e.g., `pcileech_squirrel_top.xdc`) that define the main clocks (e.g., `create_clock -name sys_clk_p -period 8.0 [get_ports sys_clk_p]`). * **Refinement**: If your emulation requires very specific internal timing or reacts to time-sensitive commands, you might need to add further constraints to critical paths (`set_max_delay`, `set_input_delay`, `set_output_delay`) within your custom logic. * **Goal**: Ensure Vivado reports **positive WNS (Worst Negative Slack)** for all paths after implementation, indicating the design meets its timing requirements. * **Use Clock Domain Crossing (CDC) Techniques**: * **Purpose**: PCIe designs often involve multiple clock domains (e.g., a 125MHz PCIe user clock, a separate clock for your custom logic). Moving signals between these domains asynchronously (without proper synchronization) can lead to **metastability**, causing unreliable behavior. * **Implementation**: Always use proper CDC circuits for signals crossing clock domains: * **Two-Flip-Flop Synchronizers**: For single bit control signals. * **Asynchronous FIFOs (First-In, First-Out)**: For multi-bit data paths, providing buffering and flow control between clock domains. * **Gray Code Encoders/Decoders**: For counters or addresses crossing domains to ensure only one bit changes at a time. * **Vivado Tools**: Vivado includes CDC analysis tools (e.g., `report_cdc`) that can identify potential metastability issues. * **Simulate Device Behavior with Time-Accurate Models**: * **Advanced Test Benches**: Use SystemVerilog test benches that incorporate realistic timing delays or even provide time-accurate PCIe bus functional models (BFMs). * **Verification**: This allows you to observe how your emulated device's internal state and external TLP generation/response timings behave under various conditions, ensuring they match your captured donor device behavior. ### **14.2 Dynamic Response to System Calls** A truly accurate emulation doesn't just present the correct IDs; it also reacts intelligently and dynamically to the host system's commands and queries, mimicking the behavior of a real, active device. * **Implement State Machines for Device Control**: * **Purpose**: Design robust SystemVerilog state machines that manage the device's operational modes, command processing, and data flow. * **Responsiveness**: Ensure the state machine transitions logically and quickly in response to incoming commands (e.g., writes to control registers in a BAR, specific TLPs). * **Graceful Handling**: The state machine should be able to handle unexpected or out-of-order requests gracefully, perhaps returning an error TLP or simply ignoring invalid commands, rather than crashing or freezing. * **Monitor and Respond to Host Commands (Beyond Simple Reads/Writes)**: * **Configuration Writes**: Beyond initial enumeration, drivers often write to configuration space registers to enable features, set thresholds, or clear status bits. Your firmware must process these writes and update internal state accordingly. * **Vendor-Specific Commands**: As discussed in Section 9.2, if the donor device has proprietary commands (accessed via custom registers or Vendor Defined Messages), your firmware must parse these commands and trigger the appropriate emulated behavior. * **Power Management Commands**: React to host-initiated power state transitions (D0, D1, D3hot, etc.) by enabling/disabling internal logic and acknowledging the state change. * **Interrupt Acknowledgment**: If the host driver acknowledges interrupts by writing to a specific register, ensure your firmware can detect this and clear the internal interrupt request. * **Optimize Firmware Logic for Responsiveness**: * **Reduce Latency**: Critical data paths and control paths should be optimized to minimize combinational logic depth and pipeline stalls. * **Parallelism**: Leverage the FPGA's inherent parallelism to perform multiple operations concurrently, improving throughput and response times. * **Efficient Memory Access**: Optimize access to internal BRAMs or external DDR memory to ensure data is available when needed for DMA transfers or register reads. * **Hardware Acceleration**: For complex computations or data manipulations that the donor device performs, consider implementing dedicated hardware accelerators on the FPGA rather than trying to perform them in a slow, software-like fashion. --- ## **15. Best Practices for Firmware Development** Adhering to best practices in custom firmware development is crucial for maintaining code quality, facilitating collaboration (if working in a team), simplifying debugging, and ensuring the long-term maintainability and reliability of your project. This is especially true for security-sensitive applications. ### **15.1 Continuous Testing and Documentation** * **Regular, Incremental Testing**: * **Unit Testing**: Test small, individual modules (e.g., a TLP parser, a register block) in isolation using dedicated test benches. * **Integration Testing**: Verify that different modules work together correctly. * **System Testing**: After flashing, perform end-to-end tests with the host system to ensure overall functionality. * **Test Early, Test Often**: Test the firmware after each significant change, no matter how small, to catch issues early when they are easier to debug. * **Automated Testing (Advanced)**: * For complex projects, implement automated test scripts (e.g., using Python with a hardware abstraction layer) on the host side to repeatedly verify functionality and performance. * Consider integrating with Continuous Integration (CI) tools (e.g., Jenkins, GitLab CI) in a team environment to automate builds, tests, and static analysis on every code commit. * **Maintain Comprehensive Documentation**: * **Design Documents**: Create and update documents that describe your firmware's architecture, including: * **Block Diagrams**: Illustrating the major modules and their interconnections. * **State Machine Diagrams**: For all stateful logic. * **Interface Specifications**: Detailing input/output signals, timing, and protocols between modules. * **Memory Maps**: For all BARs, defining register addresses, bit fields, and their functionality. * **Code Comments**: Use clear, concise comments within your SystemVerilog code to explain complex logic, purpose of signals, and any non-obvious design choices. * **Change Log/Commit Messages**: Maintain a change log or use detailed Git commit messages to track all modifications, bug fixes, and feature additions, explaining *why* changes were made. * **User Guide**: For your custom firmware, a simple user guide explaining how to build, flash, and interact with the emulated device from the host side is invaluable. ### **15.2 Managing Firmware Versioning** Proper version control is essential for tracking changes, collaborating effectively, and managing releases. * **Use Version Control Systems (VCS)**: * **Git**: Strongly recommended. Use Git to manage your HDL source code, constraints files, and project scripts. * **Organize Repository**: Maintain a clear directory structure (e.g., separate folders for `src`, `xdc`, `ip`, `scripts`, `doc`). * **Branches**: Use feature branches for developing new capabilities or large changes. Merge back to a `main` or `develop` branch after thorough testing. * **Regular Commits**: Commit frequently with atomic, meaningful commit messages. * **Tag Releases and Milestones**: * **Stable Versions**: Use Git tags (e.g., `v1.0.0`, `v1.0.1_bugfix`) to mark stable, tested versions of your firmware. This makes it easy to revert or deploy a known good state. * **Milestones**: Tag significant development milestones (e.g., "Basic Enumeration Working," "DMA Read/Write Functional"). * **Backup and Recovery Strategy**: * **Cloud-Based Repositories**: Host your Git repository on platforms like GitHub, GitLab, or Bitbucket. This provides off-site backups and facilitates collaboration. * **Local Backups**: Even with cloud repositories, maintain regular local backups of your entire Vivado project directory (which can be very large due to generated files). ### **15.3 Security Considerations** Developing custom firmware for PCIe device emulation, especially one capable of Direct Memory Access, carries significant security implications. This technology is inherently a "dual-use" capability, meaning it can be used for both legitimate (e.g., hardware testing, security research) and malicious purposes (e.g., DMA attacks, security bypasses). **It is paramount to understand and responsibly manage these risks.** * **Dual-Use Nature and Ethical Implications**: * **Ethical Hacking vs. Malicious Use**: Clearly distinguish between using this knowledge for authorized security testing (red teaming, penetration testing) and unauthorized, illegal activities. * **Responsible Disclosure**: If you discover vulnerabilities using these techniques, follow responsible disclosure guidelines. * **Legal and Licensing Compliance**: Be aware of and comply with all relevant laws, regulations, and licensing agreements (e.g., PCIe-SIG specifications, Xilinx EULAs) concerning hardware reverse engineering and device modification. * **"Weaponization"**: Recognize that the ability to accurately emulate trusted hardware can be weaponized for advanced persistent threats (APTs) or sophisticated malware. * **Understanding Attack Vectors (Offensive Perspective)**: * **Memory Exfiltration**: A malicious emulated device can perform DMA reads to access any physical memory address, including sensitive data in the kernel, user processes, cryptographic keys, or network buffers. * **Memory Injection/Modification**: A malicious emulated device can perform DMA writes to arbitrarily modify memory, enabling: * **Privilege Escalation**: Modifying kernel data structures (e.g., process tokens, SIDs) to gain administrator or system privileges. * **Code Injection**: Injecting malicious code into running processes or the kernel, then triggering its execution. * **Security Software Bypass**: Disabling or subverting endpoint detection and response (EDR), antivirus, or firewall software by modifying their memory directly. * **Fuzzing and Crashing**: Sending malformed or out-of-spec TLPs/commands to trigger driver vulnerabilities, leading to system crashes (BSODs) or potentially exploitable memory corruption. * **Firmware/BIOS Manipulation**: In some advanced scenarios, a DMA device might be able to interact with the host's SPI flash memory containing the BIOS/UEFI, potentially for persistent modification. * **Defensive Measures and Mitigation Strategies (Defensive Perspective)**: * **IOMMU/VT-d/AMD-Vi**: As noted in Section 3.2, these technologies are designed to mitigate DMA attacks by providing memory protection for peripherals. **For legitimate testing, you disable them, but in production systems, they should always be enabled.** They prevent unauthorized memory access by peripherals. * **Kernel DMA Protection (Windows) / Thunderbolt Security (Linux)**: Modern OS features specifically address "cold boot" DMA attacks (where an attacker connects a malicious device while the system is off or locked). Keep these enabled on production systems. * **Secure Boot**: While not directly a DMA protection, Secure Boot helps ensure that only trusted bootloaders and kernel modules are loaded, reducing the chance of an attacker injecting malicious kernel components to bypass DMA protections. * **Physical Security**: The most basic but critical defense. If an attacker has physical access to a PCIe slot or Thunderbolt port, they can bypass many software protections. Secure physical access to critical systems. * **Driver Hardening**: Drivers should be written defensively, validating all inputs from hardware and operating within strict memory boundaries. * **Memory Hardening**: OS-level memory protections (e.g., KASLR, DEP, SMAP/SMEP) help reduce the impact of memory corruption, but a direct DMA attack bypasses these. * **Monitoring and Logging**: While difficult at the hardware level, unusual DMA activity or enumeration of unknown PCIe devices should trigger alerts in security monitoring systems. * **Secure Coding Practices for Firmware**: * **Input Validation**: If your firmware accepts any inputs (e.g., via a UART debug interface, or internal registers written by the host), validate them rigorously to prevent buffer overflows, integer overflows, or unexpected behavior. * **Least Privilege**: Design your firmware logic to only perform the operations absolutely necessary for its function. Avoid granting unnecessary capabilities. * **State Management**: Implement robust state machines to prevent unintended behavior due to invalid state transitions. * **No Hardcoded Secrets**: Avoid embedding sensitive information (e.g., cryptographic keys, hardcoded credentials) directly in your firmware if it could be easily extracted. * **Tamper Detection**: For production firmware, consider implementing mechanisms to detect if the firmware itself has been tampered with or if non-authorized configurations are loaded. --- ## **16. Additional Resources** To deepen your understanding and stay updated in the dynamic fields of FPGA development, PCIe, and hardware security, consult the following resources: * **Xilinx (AMD) Documentation**: Your primary source for all things Vivado and Xilinx FPGAs. * **Main Documentation Portal**: [https://docs.amd.com/](https://docs.amd.com/) (formerly Xilinx.com/support/documentation). * **Vivado Design Suite User Guides**: * **UG900 - Getting Started**: Essential for new Vivado users. * **UG901 - Logic Synthesis**: Deep dive into synthesis. * **UG904 - Implementation**: Detailed guide on placement and routing. * **UG912 - Tcl Command Reference Guide**: Invaluable for scripting. * **UG939 - Debugging**: Comprehensive guide to ILA and other debug features. * **PCI Express IP Core User Guide**: Critically important for understanding the Xilinx PCIe IP (e.g., **PG054 for 7 Series Integrated Block for PCI Express**). Search for "PCI Express" on the documentation portal. This details the core's configuration, interfaces, and limitations. * **PCI-SIG Specifications**: The definitive source for the PCIe standard. * **PCI Express Base Specification**: The foundational document. While not publicly free, summaries and educational materials based on it are widely available. You can usually find information on their website: [https://pcisig.com/specifications](https://pcisig.com/specifications) (Note: Full specifications typically require PCI-SIG membership). * **FPGA Tutorials and Learning Platforms**: * **FPGA4Fun**: [http://www.fpga4fun.com/](http://www.fpga4fun.com/) - A classic site with many practical FPGA projects and tutorials. * **Verilog/VHDL Tutorials**: * **ASIC World Verilog Tutorials**: [https://www.asic-world.com/verilog/index.html](https://www.asic-world.com/verilog/index.html) - Good fundamental Verilog reference. * **VHDLwhiz**: [https://www.vhdlwhiz.com/](https://www.vhdlwhiz.com/) - VHDL reference and tutorials. * **Stack Overflow (FPGA/Verilog/PCIe tags)**: [https://stackoverflow.com/questions/tagged/fpga](https://stackoverflow.com/questions/tagged/fpga) - Community-driven Q&A for specific technical problems. * **PCIe Protocol Analysis Tools**: * **Teledyne LeCroy Protocol Analyzers**: [https://teledynelecroy.com/protocolanalyzer/](https://teledynelecroy.com/protocolanalyzer/) - Explore their range of high-performance PCIe analyzers and software. * **Telescan PE Software**: [https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software](https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software) - A no-cost software tool that provides some PCIe analysis features (requires registration). * **PCILeech Community & Resources**: * The `ufrisk/pcileech` GitHub repository is the core. Actively follow its updates and issues. * Look for community forums or Discord servers dedicated to PCILeech or similar open-source DMA projects. * **Hardware Security & Reverse Engineering**: * Books on hardware hacking, reverse engineering, and low-level system exploitation. * Conferences like Black Hat, DEF CON, Recon, and Troopers often feature talks on PCIe and DMA attacks. * Blogs and research papers from security researchers focusing on hardware. --- ## **17. Contact Information** If you need assistance, have questions, or wish to collaborate on topics related to this guide, firmware development, or hardware security, please feel free to reach out. I'm available to provide guidance, troubleshoot complex problems, or discuss ideas in detail. ### **Discord**: * **User**: [**VCPU**](https://discord.com/users/196741541094621184) * **Server Invite Link**: [**Join the Hardware Hacking & Firmware Development Discord**](https://discord.gg/dS2gDUDQmV) --- ## **18. Support and Contributions** Your support helps maintain and improve this guide and related projects. Creating and updating comprehensive technical documentation and open-source hardware projects requires significant time and effort. ### **Donations** If you found this guide helpful and want to support ongoing work, consider contributing. Every donation, no matter how small, helps in continuing to create, share, and support the community through further research, development, and documentation efforts. * **Crypto Donations (LTC - Litecoin)**: * **Address**: `MPMyQD5zgy2b2CpDn1C1KZ31KmHpT7AwRi` **Special Bonus**: If you donate, please feel free to reach out on Discord (VCPU) to receive a personal thank you and possibly additional resources, early access to new content, or personalized assistance with your project. **Note**: If you need me to review specific sections of your implementation, troubleshoot issues, or provide detailed feedback on your code, please mark the relevant sections within your code with `//VCPU-REVIEW//` comments and provide detailed explanations of the problems or questions you're encountering. This helps me focus my efforts and provide the most effective support. May God bless your soul. --- **End of Guide** ================================================ FILE: RU/README.md ================================================ # **Руководство по разработке пользовательской прошивки для полной эмуляции устройства** --- **Выражаю огромную благодарность легенде, которая сделала пожертвование, я скоро свяжусь с вами. Я добавлю сюда публичную благодарность, если вы хотите + больше, просто напишите мне в личные сообщения, если вы еще этого не сделали!** Работаю над организацией этого материала в [вики](https://github.com/JPShag/PCILeech-DMA-Firmware/wiki/Introduction). Помощь приветствуется! ---- **Примечание от автора и статус руководства:** Я делюсь этим прозрачно, так как последние времена были невероятно сложными. Помимо значительных финансовых потерь из-за мошеннического оспаривания платежа, я столкнулся с множеством других трудных жизненных проблем и проблем со здоровьем, которые сильно повлияли на мою способность быть онлайн и уделять время проектам. Честно говоря, продолжать создавать такие всеобъемлющие ресурсы, как это руководство, было глубокой борьбой на фоне этих личных трудностей. Ожидается, что это будет последняя крупная итерация основного руководства. Для более опытных пользователей, уже знакомых с фундаментальными аппаратными концепциями (например, с функцией чипа FTDI), будет также доступна краткая, минифицированная версия. Если вы считаете эту работу ценной и имеете возможность помочь, любая форма поддержки будет глубоко оценена. Ваша щедрость позволяет мне продолжать вносить вклад в это сообщество, несмотря на постоянные трудности. Я искренне надеюсь, что это руководство было и остается ценным ресурсом. --- ## В память и посвящение ![Ross](https://github.com/user-attachments/assets/de7f12fe-8992-4738-a6af-712dc48217ee) Это руководство с глубоким уважением посвящается памяти **Росса Фримена (1947–1989)** Дальновидный инженер, новатор из Мичигана и соучредитель Xilinx, Росс Фримен широко признан отцом технологии Field-Programmable Gate Array (FPGA), которая произвела революцию в вычислительной технике. В 1984 году, когда полупроводниковая промышленность преимущественно фокусировалась на чипах с фиксированными функциями, Фримен осмелился представить другую парадигму: оборудование, которое можно было бы перепрограммировать после производства. Его революционный патент (№ 4,870,302) и неустанная поддержка реконфигурируемых вычислений открыли технологическую парадигму, которая продолжает трансформировать наш мир спустя четыре десятилетия. Его новаторское изобретение позволило быстро создавать прототипы и развертывать пользовательские кремниевые решения без непомерных затрат на традиционную разработку ASIC, демократизируя аппаратное проектирование и ускоряя технологический прогресс в бесчисленных областях. Сегодня видение Фримена питает передовые достижения в области искусственного интеллекта, высокопроизводительных вычислений, телекоммуникаций, автомобильных систем, аэрокосмических приложений и многих других областей, которые были лишь мечтами при его жизни. Посмертно введенный в Национальный зал славы изобретателей в 2009 году, его наследие сохраняется не только в кремнии, но и в духе технологической смелости, которая призывает всех нас подвергать сомнению установленные ограничения и представлять новые возможности. *"Конечной целью FPGA было создание программируемых логических устройств, которые могли бы заменить стандартные цифровые чипы."* — Росс Фримен --- ## **Содержание** ### **Часть 1: Основополагающие концепции** 1. [Введение](#1-введение) * [1.1. Цель руководства](#11-цель-руководства) * [1.2. Целевая аудитория](#12-целевая-аудитория) * [1.3. Как пользоваться этим руководством](#13-как-пользоваться-этим-руководством) 2. [Ключевые определения](#2-ключевые-определения) 3. [Совместимость устройств](#3-совместимость-устройств) * [3.1. Поддерживаемое оборудование на базе FPGA](#31-поддерживаемое-оборудование-на-базе-fpga) * [3.2. Аппаратные особенности PCIe](#32-аппаратные-особенности-pcie) * [3.3. Системные требования](#33-системные-требования) 4. [Требования](#4-требования) * [4.1. Аппаратное обеспечение](#41-аппаратное-обеспечение) * [4.2. Программное обеспечение](#42-программное-обеспечение) * [4.3. Настройка среды](#43-настройка-среды) 5. [Сбор информации об устройстве-доноре](#5-сбор-информации-об-устройстве-доноре) * [5.1. Использование Arbor для сканирования устройств PCIe](#51-использование-arbor-для-сканирования-устройств-pcie) * [5.2. Извлечение и запись атрибутов устройства](#52-извлечение-и-запись-атрибутов-устройства) 6. [Начальная настройка прошивки](#6-начальная-настройка-прошивки) * [6.1. Изменение пространства конфигурации](#61-изменение-пространства-конфигурации) * [6.2. Вставка серийного номера устройства (DSN)](#62-вставка-серийного-номера-устройства-dsn) 7. [Настройка проекта Vivado](#7-настройка-проекта-vivado) * [7.1. Генерация файлов проекта Vivado](#71-генерация-файлов-проекта-vivado) * [7.2. Изменение IP-блоков](#72-изменение-ip-блоков) ### **Часть 2: Промежуточные концепции и реализация** 8. [Расширенная настройка прошивки](#8-расширенная-настройка-прошивки) * [8.1. Настройка параметров PCIe для эмуляции](#81-настройка-параметров-pcie-для-эмуляции) * [8.2. Настройка БАР и отображения памяти](#82-настройка-бар-и-отображения-памяти) * [8.3. Эмуляция управления питанием устройства и прерываний](#83-эмуляция-управления-питанием-устройства-и-прерываний) 9. [Эмуляция специфических возможностей устройства](#9-эмуляция-специфических-возможностей-устройства) * [9.1. Реализация расширенных возможностей PCIe](#91-реализация-расширенных-возможностей-pcie) * [9.2. Эмуляция функций, специфичных для поставщика](#92-эмуляция-функций-специфичных-для-поставщика) 10. [Эмуляция пакетов транспортного уровня (TLP)](#10-эмуляция-пакетов-транспортного-уровня-tlp) * [10.1. Понимание и захват TLP-пакетов](#101-понимание-и-захват-tlp-пакетов) * [10.2. Создание пользовательских TLP-пакетов для специфических операций](#102-создание-пользовательских-tlp-пакетов-для-специфических-операций) ### **Часть 3: Продвинутые методы и оптимизация** 11. [Сборка, прошивка и тестирование](#11-сборка-прошивка-и-тестирование) * [11.1. Синтез и реализация](#111-синтез-и-реализация) * [11.2. Прошивка битстрима](#112-прошивка-битстрима) * [11.3. Тестирование и проверка](#113-тестирование-и-проверка) 12. [Продвинутые методы отладки](#12-продвинутые-методы-отладки) * [12.1. Использование встроенного логического анализатора Vivado](#121-использование-встроенного-логического-анализатора-vivado) * [12.2. Инструменты анализа трафика PCIe](#122-инструменты-анализа-трафика-pcie) 13. [Устранение неполадок](#13-устранение-неполадок) * [13.1. Проблемы с обнаружением устройства](#131-проблемы-с-обнаружением-устройства) * [13.2. Ошибки отображения памяти и конфигурации BAR](#132-ошибки-отображения-памяти-и-конфигурации-bar) * [13.3. Ошибки производительности DMA и TLP](#133-ошибки-производительности-dma-и-tlp) 14. [Точность эмуляции и оптимизация](#14-точность-эмуляции-и-оптимизация) * [14.1. Методы для точной эмуляции временных характеристик](#141-методы-для-точной-эмуляции-временных-характеристик) * [14.2. Динамический отклик на системные вызовы](#142-динамический-отклик-на-системные-вызовы) 15. [Лучшие практики разработки прошивок](#15-лучшие-практики-разработки-прошивок) * [15.1. Непрерывное тестирование и документирование](#151-непрерывное-тестирование-и-документирование) * [15.2. Управление версиями прошивки](#152-управление-версиями-прошивки) * [15.3. Вопросы безопасности](#153-вопросы-безопасности) 16. [Дополнительные ресурсы](#16-дополнительные-ресурсы) 17. [Контактная информация](#17-контактная-информация) 18. [Поддержка и вклад](#18-поддержка-и-вклад) --- ## **Часть 1: Основополагающие концепции** --- ## **1. Введение** ### **1.1. Цель руководства** Основная цель этого руководства — предоставить вам знания и практические навыки для разработки пользовательской прошивки для прямого доступа к памяти (DMA) на устройствах на базе программируемых логических интегральных схем (FPGA). Эта специализированная прошивка позволяет вашей FPGA точно эмулировать идентичность и поведение других аппаратных устройств с интерфейсом PCIe (Peripheral Component Interconnect Express). Такая эмуляция является мощным методом с глубокими последствиями в нескольких продвинутых областях: **Исследования аппаратной безопасности**: * **Обнаружение уязвимостей**: Эмулируя устройство, вы можете создать контролируемую среду для отправки некорректных или неожиданных данных драйверам хоста, систематически проводя фаззинг для поиска уязвимостей (например, переполнений буфера, состояний гонки), которые могут быть использованы с периферийного аппаратного обеспечения. * **Анализ драйверов**: Наблюдайте, как операционные системы и конкретные драйверы взаимодействуют с оборудованием. Вы можете эмулировать устройства с нестандартными конфигурациями или недокументированными функциями, чтобы понять поведение драйвера, выявить предположения безопасности или реверс-инжинирить проприетарные протоколы. * **Анализ побочных каналов**: Хотя это более сложно, эмулируемое устройство потенциально может быть запрограммировано для помощи в экспериментах, связанных с утечкой информации через анализ временных характеристик или энергопотребления, путем точного управления периферийными операциями. **Red Teaming и тестирование на проникновение**: * **Обход мер безопасности**: Эмулируйте внешне безопасное или внесенное в белый список аппаратное устройство (например, обычный сетевой контроллер или контроллер хранилища) для получения привилегий DMA. После достижения этого, это позволяет напрямую взаимодействовать с системной памятью, потенциально обходя системы обнаружения и реагирования на конечных точках (EDR) или антивирусные решения, которые работают на более высоких программных уровнях. * **Скрытое закрепление**: Эмулируемое вредоносное устройство может предложить скрытый способ сохранения доступа к скомпрометированной системе, поскольку его может быть труднее обнаружить, чем программные импланты. * **Использование доверительных отношений**: Системы часто неявно доверяют подключенному оборудованию. Пользовательская прошивка может использовать это, имитируя устройства, которым предоставлены определенные разрешения или доступ. **Отладка и диагностика систем**: * **Воспроизводимые тестовые стенды**: Создавайте высокоспецифичные аппаратные сценарии для надежного воспроизведения трудноуловимых ошибок, которые могут возникать только при определенных состояниях устройства или шаблонах данных. * **Инъекция ошибок**: Намеренно эмулируйте неисправное поведение устройства (например, некорректное формирование TLP-пакетов, задержки ответов) для проверки надежности и возможностей обработки ошибок хост-системы и ее драйверов. **Тестирование и валидация оборудования**: * **Разработка драйверов**: Тестируйте новые или измененные драйверы на эмулированном аппаратном профиле до того, как физические прототипы станут доступны, или для имитации более широкого спектра аппаратных вариантов, чем физически доступно. * **Тестирование на соответствие**: Хотя это не заменяет официальные тесты на соответствие, эмулируемое устройство может помочь предварительно проверить некоторые аспекты соответствия протоколу PCIe. **Поддержка устаревших систем и совместимость**: * Эмулируйте старые, снятые с производства или труднодоступные устройства PCIe, чтобы поддерживать работоспособность устаревших систем или устранять пробелы в совместимости между различными поколениями оборудования. Проходя это руководство, вы приобретете навыки в: * Тщательном извлечении идентификационных атрибутов и деталей конфигурации из физического устройства-«донора» PCIe. * Модификации и расширении существующих открытых фреймворков прошивок FPGA (с основным акцентом на широко используемый проект PCILeech-FPGA) для принятия идентичности устройства-донора. * Настройке и использовании профессионального набора инструментов для разработки FPGA, сосредоточенного вокруг Xilinx Vivado, наряду с основными инструментами редактирования кода, такими как Visual Studio Code. * Развитии твердого понимания многоуровневой архитектуры PCIe, механики передачи данных DMA и нюансов создания прошивки, которая точно воспроизводит поведение оборудования на низком уровне. ### **1.2. Целевая аудитория** Это руководство предназначено для лиц, уже обладающих базовыми или средними знаниями компьютерных систем, аппаратных принципов и разработки программного обеспечения. Содержание технически требовательно и предполагает способность к детальной работе на низком уровне. В частности, оно подходит для: * **Разработчиков прошивок**: Инженеров, стремящихся проектировать или адаптировать прошивки для FPGA, особенно для приложений, включающих высокоскоростную передачу данных (DMA) и прямое манипулирование аппаратными интерфейсами через PCIe. Настоятельно рекомендуется знание Verilog/VHDL и опыт работы с инструментами разработки FPGA. * **Аппаратных инженеров**: Специалистов, занимающихся проектированием, тестированием или валидацией оборудования на базе PCIe. Это руководство может помочь в создании сложных тестовых стендов или эмуляции компонентов в рамках более крупного системного проектирования. Ожидается знакомство с протоколом PCIe и цифровым проектированием. * **Специалистов и исследователей в области кибербезопасности**: * **Исследователей уязвимостей и разработчиков эксплойтов**: Тех, кто хочет исследовать аппаратные поверхности атаки или разрабатывать прототипы эксплойтов, использующих DMA. Крайне важно понимание внутренней структуры ОС, управления памятью и архитектуры драйверов. * **Членов Red Team**: Операторов, ищущих продвинутые методы доступа к системе, закрепления и эксфильтрации данных путем использования прямого манипулирования аппаратным обеспечением. * **Специалистов по цифровой криминалистике и реагированию на инциденты**: Хотя это руководство ориентировано на атаку, понимание этих методов может помочь в распознавании и анализе сложных аппаратных атак. * **Энтузиастов FPGA и продвинутых любителей**: Лиц с предыдущим опытом работы с проектами FPGA, которые стремятся решать сложные задачи, такие как связь по PCIe и аппаратная эмуляция. Важна готовность углубляться в спецификации и технические описания. Кривая обучения может быть крутой, особенно если концепции PCIe или продвинутых FPGA являются новыми. Однако руководство нацелено на разбиение сложных тем на управляемые шаги. ### **1.3. Как пользоваться этим руководством** Это руководство разделено на три логически последовательные части, разработанные для постепенного наращивания ваших знаний: * **Часть 1: Основополагающие концепции**: Эта начальная часть имеет решающее значение. Она вводит основную терминологию, базовые принципы PCIe и DMA, необходимый аппаратный и программный стек (включая инструкции по настройке инструментов, таких как Xilinx Vivado и фреймворк PCILeech-FPGA), а также начальные процедуры для получения жизненно важной информации от вашего целевого устройства-«донора» и выполнения базовых модификаций прошивки. Настоятельно рекомендуется последовательно и тщательно изучить эту часть. * **Часть 2: Промежуточные концепции и реализация**: (Предстоящие разделы) Опираясь на фундамент, эта часть проведет вас через более продвинутые настройки прошивки. Темы будут включать тонкую настройку рабочих параметров PCIe, эмуляцию специфических для устройства регистров и возможностей (таких как состояния управления питанием и прерывания, генерируемые сообщениями – MSI/MSI-X), а также первоначальное понимание построения и интерпретации пакетов транспортного уровня (TLP). * **Часть 3: Продвинутые методы и оптимизация**: (Предстоящие разделы) Заключительная часть будет посвящена сложным методам отладки (включая использование встроенных логических анализаторов – ILA и внешних анализаторов протокола PCIe), методам оптимизации производительности прошивки и точности эмуляции, всестороннему устранению распространенных и сложных проблем, а также критическому обсуждению лучших практик, с особым акцентом на вопросы безопасности при разработке и развертывании эмулированных устройств PCIe. **Работа с руководством**: * **Последовательное прохождение**: Особенно для Частей 1 и 2, следуйте разделам по порядку, так как последующие концепции строятся на предыдущих. * **Практика**: Это практическое руководство. Активно выполняйте шаги по настройке, модификации кода и эксперименты на вашем собственном оборудовании. * **Адаптация к вашей среде**: Пути к файлам, конкретные ID устройств и версии программного обеспечения могут отличаться. Поймите концепции, лежащие в основе инструкций, чтобы адаптировать их к вашей конкретной настройке. * **Обращение к внешним ресурсам**: Спецификация PCIe и документация FPGA являются вашими окончательными справочниками. Это руководство упрощает и направляет, но для глубокого погружения часто требуется обращение к первоисточникам. * **Итеративная разработка**: Разработка прошивки редко бывает линейной. Ожидайте итераций, отладки и доработки ваших проектов. Широко используйте разделы по устранению неполадок и методы отладки. Вы будете работать с ЯОА (SystemVerilog в PCILeech-FPGA), инструментами синтеза и реализации FPGA (Vivado) и, возможно, с хост-стороной программирования и утилитами анализа PCIe. --- ## **2. Ключевые определения** Твердое понимание следующей терминологии необходимо для навигации по сложностям эмуляции устройств PCIe и разработки пользовательской прошивки. Эти термины будут широко использоваться на протяжении всего руководства. * **DMA (Прямой доступ к памяти)**: * **Определение**: Фундаментальная особенность современной компьютерной архитектуры, позволяющая аппаратным периферийным устройствам (таким как сетевые карты, графические процессоры или ваше эмулируемое устройство на базе FPGA) считывать и записывать данные непосредственно в основную системную память (ОЗУ) без участия центрального процессора (CPU) для каждого переданного байта. * **Значение**: DMA имеет решающее значение для высокопроизводительных операций ввода-вывода. Снимая задачи передачи данных с CPU, он освобождает CPU для выполнения других вычислений, значительно повышая общую пропускную способность и эффективность системы. В контексте этого руководства ваша FPGA будет использовать DMA для взаимодействия с памятью хост-системы, что является мощной возможностью, часто используемой в исследованиях безопасности и ред-тиминге. * **PCIe (Peripheral Component Interconnect Express)**: * **Определение**: Высокоскоростной последовательный компьютерный стандарт шины расширения, разработанный для замены более старых стандартов шин, таких как PCI, PCI-X и AGP. Он использует топологию "точка-точка" с отдельными последовательными линиями, соединяющими каждое устройство с корневым комплексом (обычно являющимся частью чипсета или CPU). Связь осуществляется с помощью пакетов. * **Значение**: PCIe является доминирующим стандартом для подключения высокопроизводительных периферийных устройств к материнским платам. Понимание его протокола, многоуровневой архитектуры (физический уровень, уровень канала данных, уровень транзакций) и механизмов конфигурации имеет первостепенное значение для эмуляции любого современного аппаратного устройства. * **TLP (Пакет транспортного уровня)**: * **Определение**: Фундаментальная единица обмена данными на уровне транзакций протокола PCIe. TLP-пакеты отвечают за передачу запросов (например, чтение/запись памяти, чтение/запись ввода-вывода, чтение/запись конфигурации) и завершений (ответов на запросы) между устройствами PCIe. Каждый TLP-пакет состоит из заголовка, необязательного блока данных и необязательного CRC от начала до конца (ECRC). * **Значение**: Для точной эмуляции устройства ваша прошивка FPGA должна быть способна правильно формировать, передавать, принимать и интерпретировать TLP-пакеты, соответствующие поведению устройства-донора. Понимание типов, форматов и управления потоком TLP-пакетов критически важно для продвинутой эмуляции. * **BAR (Базовый адресный регистр)**: * **Определение**: Расположенные в пространстве конфигурации устройства PCIe, BARы — это специальные регистры, используемые устройством для запроса ресурсов адресного пространства у хост-системы. Устройство может иметь до шести 32-битных BARов (или меньше, или пары 32-битных BARов могут образовывать 64-битные BARы). Эти регистры определяют начальные адреса и размеры областей памяти, отображаемой на ввод-вывод (MMIO), или областей портов ввода-вывода, которые устройство использует для предоставления своих регистров и внутренней памяти хост-процессору. * **Значение**: Когда хост-система перечисляет устройство PCIe, она считывает BARы, чтобы определить требования устройства к памяти и вводу-выводу, затем выделяет и программирует эти BARы фактическими базовыми адресами в карте физических адресов системы. Ваше эмулируемое устройство должно точно определить свои BARы, чтобы они соответствовали устройству-донору, чтобы ОС хоста и драйверы могли правильно взаимодействовать с ним. * **FPGA (Программируемая логическая интегральная схема)**: * **Определение**: Интегральная схема (ИС), которая может быть сконфигурирована разработчиком или заказчиком после изготовления – отсюда и "field-programmable" (программируемая на месте). FPGA содержат массив программируемых логических блоков и иерархию реконфигурируемых межсоединений, которые позволяют "соединять" блоки для реализации пользовательских цифровых логических схем. * **Значение**: FPGA являются основным аппаратным обеспечением, используемым в этом руководстве. Их реконфигурируемая природа делает их идеальными для эмуляции других аппаратных устройств, так как вы можете определить точную логику и интерфейсы, необходимые для имитации присутствия и поведения устройства-донора по PCIe. * **MSI/MSI-X (Прерывания, генерируемые сообщениями / Расширенные прерывания, генерируемые сообщениями)**: * **Определение**: Механизмы, позволяющие устройству PCIe доставлять прерывания CPU путем записи специального сообщения (TLP-пакета, в частности, TLP-пакета записи в память) в системно-определенный адрес памяти, а не с использованием выделенных физических линий прерываний (как в устаревшем PCI). MSI-X является усовершенствованием MSI, предлагающим больше векторов прерываний и большую гибкость. * **Значение**: Большинство современных устройств PCIe используют MSI или MSI-X для более эффективной и гибкой обработки прерываний. Точная эмуляция часто требует реализации выбранного механизма прерываний устройства-донора, включая настройку структур возможностей MSI/MSI-X и правильную генерацию сообщений прерываний. * **DSN (Серийный номер устройства)**: * **Определение**: 64-битный глобально уникальный идентификатор, который может быть опционально реализован устройством PCIe. Если он присутствует, он обычно находится в расширенной структуре возможностей в пространстве конфигурации устройства. * **Значение**: Хотя не все устройства имеют DSN, некоторые драйверы или программное обеспечение для управления могут использовать его для уникальной идентификации, лицензирования или отслеживания. Правильная его эмуляция может быть важна для полной прозрачности и предотвращения обнаружения эмулируемого устройства. * **Пространство конфигурации PCIe**: * **Определение**: Стандартизированная область адресов размером 256 байт (для устройств конечной точки типа 0) или 4 КБ, связанная с каждой функцией PCIe (устройство может иметь несколько функций). Это пространство содержит жизненно важную информацию об устройстве, включая его Vendor ID, Device ID, Class Code, Revision ID, BARы, указатели на возможности и различные регистры состояния и управления. Доступ к нему осуществляется хост-системой с помощью специальных TLP-пакетов чтения и записи конфигурации. * **Значение**: Пространство конфигурации — это "удостоверение личности" устройства PCIe. Самым первым шагом в эмуляции устройства является тщательное воспроизведение соответствующих частей пространства конфигурации устройства-донора в прошивке вашей FPGA. Хост-система использует эту информацию для идентификации, настройки и выделения ресурсов устройству. * **Устройство-донор**: * **Определение**: Физическое аппаратное устройство PCIe, идентичность и поведение которого вы стремитесь эмулировать на своей FPGA. Это устройство служит источником для извлечения деталей конфигурации (Vendor ID, Device ID, настройки BAR, возможности и т.д.) и поведенческих шаблонов. * **Значение**: Точность вашей эмуляции напрямую зависит от того, насколько точно и полно вы сможете собрать и воспроизвести характеристики устройства-донора. * **Корневой комплекс (RC)**: * **Определение**: Сущность в иерархии PCIe, которая соединяет CPU и подсистему памяти с PCIe-фабрикой. Он генерирует транзакции PCIe от имени CPU и обрабатывает транзакции, инициированные нижестоящими устройствами PCIe. Он также выполняет начальное перечисление и конфигурацию шины. * **Значение**: Ваше эмулируемое устройство будет преимущественно взаимодействовать с корневым комплексом (или коммутаторами, подключенными к нему) при связи с хост-системой. * **Конечная точка (EP)**: * **Определение**: Тип устройства PCIe, которое находится на периферии PCIe-фабрики, потребляя или производя данные. Примеры включают сетевые карты, графические карты, контроллеры хранилища и устройство FPGA, которое вы будете программировать. Конечные точки запрашивают ресурсы и инициируют транзакции к корневому комплексу. * **Значение**: В этом руководстве ваша FPGA будет запрограммирована действовать как устройство конечной точки, эмулируя конкретную конечную точку донора. * **HDL (Язык описания аппаратуры)**: * **Определение**: Специализированный компьютерный язык, используемый для описания структуры, дизайна и работы электронных схем, в частности цифровых логических схем. Распространенные HDL включают Verilog и VHDL. * **Значение**: Вы будете работать с Verilog (в частности, SystemVerilog, расширением Verilog) в проекте PCILeech-FPGA для определения пользовательской логики для вашего эмулируемого устройства. * **Битстрим**: * **Определение**: Конечный файл конфигурации, который загружается в FPGA для программирования ее логических блоков и межсоединений, тем самым реализуя ваш пользовательский аппаратный дизайн. Это скомпилированный вывод из инструментов разработки FPGA (таких как Xilinx Vivado). * **Значение**: Генерация и прошивка правильного битстрима является конечным шагом в развертывании вашей пользовательской прошивки на FPGA. --- ## **3. Совместимость устройств** Успешная и точная эмуляция устройства PCIe зависит от обеспечения полной совместимости выбранного аппаратного обеспечения на базе FPGA и конфигурации хост-системы. В этом разделе подробно описаны поддерживаемые платформы FPGA, критические аппаратные особенности PCIe и необходимые системные требования для настройки среды разработки. ### **3.1. Поддерживаемое оборудование на базе FPGA** Хотя это руководство предоставляет общую методологию, адаптируемую к различному аппаратному обеспечению DMA на базе FPGA, наши основные примеры и конкретные инструкции будут сосредоточены на **ПЛИС Xilinx 7-й серии**, обычно встречающихся в открытых платах DMA благодаря их балансу производительности и доступности. Карта **Squirrel DMA (35T)** выделена из-за ее популярности и хорошо документированной совместимости с фреймворком PCILeech-FPGA. Основные принципы и методы настройки IP-ядра PCIe и разработки логики на языке описания аппаратуры (HDL) широко применимы к следующим семействам FPGA и конкретным платам: * **Squirrel (Artix-7 35T)** * **Описание**: Широкодоступное и экономичное устройство DMA на базе FPGA с ПЛИС Xilinx Artix-7 35T. Оно предлагает достаточные логические ресурсы и память для стандартных задач сбора памяти и широкого спектра проектов по базовой и промежуточной эмуляции устройств. Это отличная отправная точка для тех, кто новичок в DMA на базе FPGA. * **Ключевые особенности**: Artix-7 предлагает хорошее соотношение производительности и стоимости, что делает его подходящим для образовательных и исследовательских целей. * **Enigma-X1 (Artix-7 75T)** * **Описание**: Среднеуровневая FPGA, предлагающая расширенные логические и запоминающие ресурсы по сравнению с 35T, обычно основанная на ПЛИС Xilinx Artix-7 75T. Это обеспечивает большую гибкость для более сложных сценариев эмуляции, больших областей отображения памяти или более сложных операций DMA, требующих дополнительного аппаратного обеспечения FPGA. * **Ключевые особенности**: Увеличенное количество логических ячеек и блочной памяти (BRAM) позволяет создавать более сложные конструкции. * **ZDMA (Artix-7 100T)** * **Описание**: Более производительная FPGA на базе Artix-7 100T, оптимизированная для более требовательных взаимодействий с памятью и обширных операций чтения/записи. Эта плата подходит для крупномасштабных решений DMA, высокопроизводительной эмуляции или проектов, требующих значительного объема встроенной памяти. * **Ключевые особенности**: Вариант 100T обеспечивает существенное увеличение ресурсов, идеально подходящее для расширения границ эмуляции. * **Kintex-7 (K325T, K410T и т.д.)** * **Описание**: Представляя собой продвинутый уровень, ПЛИС Kintex-7 (например, K325T, K410T) предлагают надежные возможности для очень сложных проектов, крупномасштабных решений DMA и приложений, требующих большего количества линий PCIe или более высоких скоростей (например, Gen3 x8/x16). Хотя они дороже, они предоставляют значительно больше логики, DSP-слайсов и памяти, что позволяет эмулировать высокосложные и требовательные устройства-доноры. * **Ключевые особенности**: Высокопроизводительные трансиверы для более быстрых поколений PCIe, обильные логические и запоминающие ресурсы для сложных проектов. **Важное примечание о семействах FPGA**: Хотя принципы схожи, конкретные конфигурации IP-ядер и тактовые структуры могут немного отличаться между различными ПЛИС Xilinx 7-й серии (Artix-7, Kintex-7, Zynq-7000 PS/PL). Всегда обращайтесь к документации конкретной платы и руководствам пользователя IP-ядер Xilinx PCIe для выбранного вами семейства FPGA. Проект PCILeech-FPGA часто предоставляет специфические для платы Tcl-скрипты и исходные файлы для упрощения этого процесса. ### **3.2. Аппаратные особенности PCIe** Для обеспечения бесперебойной и неограниченной работы вашего DMA-устройства на базе FPGA для эмуляции, несколько особенностей PCIe и хост-системы требуют тщательного рассмотрения, а в некоторых случаях — модификации. * **Настройки IOMMU / VT-d / AMD-Vi** * **Рекомендация**: Для первоначальной настройки и тестирования **настоятельно рекомендуется отключить IOMMU (Intel's Virtualization Technology for Directed I/O - VT-d) или его аналог от AMD (AMD-Vi)** в настройках BIOS/UEFI вашей системы. * **Обоснование**: IOMMU — это аппаратные компоненты, которые обеспечивают блоки управления памятью для устройств, поддерживающих DMA. Они выполняют преобразование адресов, аналогично MMU CPU, и могут применять разрешения на доступ к памяти. Хотя они имеют решающее значение для безопасности и виртуализации (предотвращая несанкционированный доступ к памяти несанкционированным устройством), они *будут* ограничивать доступ вашего DMA-устройства к системной памяти, потенциально мешая получению памяти и эмуляции устройства. Отключение IOMMU позволяет вашему DMA-устройству неограниченный доступ, что часто необходимо для продвинутых исследований эмуляции и безопасности. * **Расположение**: Обычно находится в разделах "CPU Configuration", "Virtualization", "Advanced Settings" или "I/O Virtualization" в вашем BIOS/UEFI. * **Защита DMA на уровне ядра (Windows) / Уровень безопасности Thunderbolt (Linux)** * **Рекомендация (Windows)**: Отключите функции **Защиты DMA на уровне ядра** в современных системах Windows. Это включает такие настройки, как **Виртуализация на основе безопасности (VBS)** и **Целостность памяти (HVCI)**. Эти функции используют IOMMU для предотвращения несанкционированных DMA-атак от внешних периферийных устройств, подключенных через Thunderbolt или PCIe. * **Шаги (Windows)**: * Получите доступ к настройкам безопасности Windows: **Пуск > Параметры > Конфиденциальность и безопасность > Безопасность Windows > Безопасность устройства**. * В разделе "Изоляция ядра" нажмите "Сведения об изоляции ядра". * Отключите "Целостность памяти". * Вам также может потребоваться отключить Secure Boot в BIOS/UEFI, поскольку VBS часто зависит от него. * **Внимание**: Отключение этих функций значительно **снижает уровень безопасности вашей системы**, делая ее уязвимой для различных атак, включая те, которые используют вредоносные DMA-устройства. Это следует делать только на выделенной тестовой системе, а не на вашей основной машине, и в безопасной, изолированной среде, где вы понимаете риски. * **Рекомендация (Linux/Thunderbolt)**: Если вы используете систему с портами Thunderbolt, изучите и потенциально настройте **Уровень безопасности Thunderbolt** в вашем BIOS/UEFI. Более низкие уровни безопасности (например, "No Security", "User Authorization") обычно требуются для произвольных устройств Thunderbolt/PCIe для выполнения DMA без явного одобрения хоста. * **Требования к слотам PCIe** * **Рекомендация**: Используйте совместимый слот PCIe, который физически соответствует требованиям FPGA-устройства. Большинство DMA-карт на базе Artix-7 работают на PCIe Gen2 x1 или x4. * **Обоснование**: * **Физическое соответствие**: Карта x1 может быть установлена в слоты x1, x4, x8 или x16, но карта x4 требует как минимум слота x4. * **Производительность**: Хотя карта x4 *может* работать в слоте x1 (если физический разъем открытый или модифицирован), она будет работать со скоростью x1, что серьезно ограничит скорость передачи данных. Для оптимальной производительности и точной эмуляции возможностей устройства-донора убедитесь, что плата FPGA установлена в слот, который обеспечивает как минимум *эмулируемую* ширину и скорость канала (например, если вы эмулируете устройство Gen2 x4, используйте слот Gen2 x4 на хосте). * **Настройки BIOS материнской платы**: Некоторые материнские платы позволяют настраивать скорость слотов PCIe (например, принудительно Gen1 или Gen2). Убедитесь, что эти настройки не конфликтуют с желаемой скоростью эмуляции. ### **3.3. Системные требования** Настройка надежной среды разработки является ключом к эффективной разработке прошивки, синтезу и отладке. * **Хост-система** * **Процессор**: Современный многоядерный процессор необходим для запуска инструментов разработки FPGA, таких как Vivado, которые требуют значительных вычислительных мощностей во время синтеза и реализации. (Например, Intel Core i5/i7/i9 или AMD Ryzen 5/7/9 эквивалент, рекомендуется 8-е поколение или новее). * **Оперативная память (ОЗУ)**: Минимум 16 ГБ ОЗУ настоятельно рекомендуется; **32 ГБ и более идеально** для сложных проектов FPGA, так как Vivado может потреблять значительный объем памяти, особенно во время реализации. * **Хранилище**: Твердотельный накопитель (SSD) с минимум **200 ГБ свободного места** крайне важен. Установка инструментов FPGA (один Vivado может занимать более 50 ГБ), файлы проекта и результаты синтеза/реализации могут быстро заполнить дисковое пространство. Скорость SSD значительно сокращает время сборки. * **Операционная система**: * **Windows 10/11 (64-битная Professional или Enterprise)**: Широко поддерживается Xilinx Vivado и многими инструментами отладки оборудования. Помните о соображениях защиты DMA на уровне ядра. * **Совместимый дистрибутив Linux (64-битный)**: Выпуски Ubuntu LTS (Long Term Support) (например, 20.04, 22.04) обычно используются и хорошо поддерживаются Vivado. Linux часто предоставляет более гибкую среду для написания скриптов и низкоуровневых инструментов взаимодействия с PCIe. * **Периферийные устройства** * **JTAG-программатор**: Абсолютно необходим для прошивки скомпилированного битстрима на вашу DMA-карту на базе FPGA. Примеры включают Xilinx Platform Cable USB II, Digilent JTAG-HS3 или встроенные JTAG-программаторы, встречающиеся на некоторых платах разработки. Убедитесь, что он совместим с вашей платой FPGA и Vivado. * **Слот PCIe**: Как обсуждалось в разделе 3.2, убедитесь, что в вашей хост-системе есть доступный и совместимый слот PCIe для вашей DMA-карты. * **USB-порт**: Для подключения JTAG-программатора и, возможно, для UART/последовательной консоли к вашей плате FPGA для вывода отладочной информации. --- ## **4. Требования** В этом разделе излагаются основные аппаратные и программные компоненты, а также рекомендуемая настройка среды, необходимые для начала разработки пользовательской прошивки для эмуляции устройств PCIe. Наличие этих предварительных условий до начала работы значительно упростит процесс разработки. ### **4.1. Аппаратное обеспечение** * **Устройство-донор PCIe** * **Назначение**: Это физическое аппаратное устройство, конфигурацию и поведение которого вы собираетесь эмулировать на вашей FPGA. Оно служит авторитетным источником для получения критических идентификационных данных, значений регистров и рабочих характеристик. * **Примеры**: Распространенные примеры включают стандартную сетевую карту (NIC), контроллер хранения SATA или NVMe, контроллер USB или любую другую стандартную карту расширения PCIe, которую вы можете безопасно извлечь из системы для анализа. Настоятельно рекомендуется использовать устройство, которое *не* является необходимым для работы системы, так как вы будете проверять его низкоуровневую конфигурацию. * **Плата ПЛИС для ПДП (DMA FPGA Card)** * **Описание**: Плата разработки на базе FPGA, специально разработанная или адаптированная для выполнения операций прямого доступа к памяти (DMA) через интерфейс PCIe. Это платформа, на которую будет загружена ваша пользовательская прошивка. * **Примеры**: Как подробно описано в разделе 3.1, совместимые карты включают **Squirrel (Artix-7 35T)**, **Enigma-X1 (Artix-7 75T)**, **ZDMA (Artix-7 100T)** или различные решения на базе **Kintex-7**. Убедитесь, что выбранная вами карта имеет краевой разъем PCIe. * **JTAG-программатор** * **Назначение**: Этот важный инструмент облегчает связь между вашим компьютером для разработки и FPGA на вашей DMA-карте. Он используется для программирования (прошивки) скомпилированного битстрима на FPGA и, что важно, для интерактивной отладки с использованием таких инструментов, как Hardware Manager Vivado и встроенный логический анализатор (ILA). * **Примеры**: * **Xilinx Platform Cable USB II**: Традиционный, широко совместимый программатор для FPGA Xilinx. Убедитесь, что у вас установлены необходимые драйверы. * **Digilent JTAG-HS3 / JTAG-HS2**: Популярные и надежные программаторы, известные хорошей интеграцией с Vivado и поддержкой. HS3 предлагает более высокие скорости программирования. * **Встроенный JTAG**: Некоторые платы FPGA могут иметь встроенный мост USB-в-JTAG (например, чип FTDI), что устраняет необходимость в отдельном программаторе. Обратитесь к документации вашей платы. ### **4.2. Программное обеспечение** * **Xilinx Vivado Design Suite** * **Описание**: Официальная, всеобъемлющая среда разработки FPGA от Xilinx (теперь AMD). Vivado необходим для синтеза вашего HDL-кода, реализации проекта на целевой FPGA, генерации окончательного битстрима и выполнения аппаратной отладки. Он включает необходимые IP-ядра, компиляторы и утилиты. * **Загрузка**: Посетите официальную страницу загрузок Xilinx (AMD): [https://www.xilinx.com/support/download.html](https://www.xilinx.com/support/download.html). * **Примечание о версии**: Хотя в некоторых устаревших руководствах могут упоминаться старые версии, такие как Vivado 2020.1, настоятельно рекомендуется загрузить **последнюю стабильную версию** (например, Vivado 2023.x или новее), совместимую с вашим целевым семейством FPGA (Artix-7, Kintex-7). Проект PCILeech-FPGA обычно поддерживает более новые версии Vivado. * **Visual Studio Code** * **Описание**: Высоко настраиваемый и многофункциональный редактор кода от Microsoft. Это отличный выбор для написания и редактирования вашего HDL-кода на Verilog/SystemVerilog благодаря его обширной экосистеме расширений, предлагающей такие функции, как подсветка синтаксиса, линтинг, автодополнение и интеграция с системой контроля версий. * **Загрузка**: [https://code.visualstudio.com/](https://code.visualstudio.com/) * **PCILeech-FPGA** * **Описание**: Проект с открытым исходным кодом и базовая кодовая база для разработки DMA на базе FPGA. Он предоставляет готовые к использованию экземпляры IP-ядер PCIe и хорошо структурированный проект, который служит отличной отправной точкой для пользовательской прошивки. Это руководство активно использует его архитектуру. * **Репозиторий**: [https://github.com/ufrisk/pcileech-fpga](https://github.com/ufrisk/pcileech-fpga) * **Arbor (MindShare)** * **Описание**: Мощный и удобный программный инструмент, специально разработанный для глубокого сканирования и анализа устройств PCIe. Он предоставляет подробную информацию о пространстве конфигурации, возможностях и регистрах подключенного оборудования PCIe, что делает его бесценным для сбора информации об устройстве-доноре. * **Загрузка**: Доступно на веб-сайте MindShare: [https://www.mindshare.com/](https://www.mindshare.com/) (Вам, вероятно, потребуется перейти в раздел программного обеспечения). * **Примечание**: Обычно требуется создание учетной записи и может предлагаться ограниченная по времени пробная версия. * **Альтернативные инструменты анализа устройств PCIe** * **Telescan PE (Teledyne LeCroy)**: * **Описание**: Бесплатная утилита от Teledyne LeCroy для анализа трафика PCIe и перечисления устройств. Хотя это в первую очередь программный инструмент, который взаимодействует с их аппаратными анализаторами протоколов, он также может предоставлять некоторые базовые представления пространства конфигурации без специального оборудования. * **Загрузка**: [https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software](https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software) * **Примечание**: Требуется ручная регистрация и одобрение для загрузки. * **Собственные инструменты ОС (для базовых проверок)**: * **Диспетчер устройств Windows**: Предоставляет базовую информацию о Vendor ID, Device ID, Subsystem ID и Class Code на вкладке "Сведения" в свойствах устройства. * **Утилита `lspci` Linux**: Мощный инструмент командной строки для проверки устройств PCIe. Используйте `lspci -nn` для Vendor/Device ID, `lspci -vvv` для подробных сведений, включая BARы и возможности, и `lspci -s -xxxx` для дампов необработанного пространства конфигурации. ### **4.3. Настройка среды** Чистая и правильно настроенная среда разработки имеет решающее значение для предотвращения распространенных ловушек и обеспечения бесперебойного рабочего процесса. #### **4.3.1. Установка Xilinx Vivado Design Suite** **Шаги**: 1. **Посетите страницу загрузки Vivado Xilinx (AMD)**: [https://www.xilinx.com/support/download.html](https://www.xilinx.com/support/download.html). 2. **Загрузите соответствующую версию**: Выберите последнюю стабильную версию Vivado, которая совместима с вашей операционной системой и, что важно, с вашим конкретным устройством FPGA (например, Artix-7, Kintex-7). Проверьте примечания к выпуску Vivado на предмет поддержки устройств. 3. **Запустите установщик**: Запустите загруженный установщик и внимательно следуйте инструкциям на экране. 4. **Выберите необходимые компоненты**: Во время установки вам будет предложено выбрать, какие семейства устройств установить. **Критически важно выбрать семейство устройств, соответствующее вашей плате FPGA (например, "7 Series" для Artix-7/Kintex-7).** Это значительно экономит место на диске по сравнению с установкой всех семейств. Убедитесь, что вы выбрали компоненты "Design Tools" (Synthesis, Implementation) и "Programming & Debugging". 5. **Запустите Vivado**: После установки запустите Vivado, чтобы убедиться, что он открывается без ошибок и что лицензии (если применимо) настроены правильно. #### **4.3.2. Установка Visual Studio Code** **Шаги**: 1. **Посетите страницу загрузки Visual Studio Code**: [https://code.visualstudio.com/](https://code.visualstudio.com/). 2. **Загрузка и установка**: Загрузите установщик для вашей операционной системы и следуйте стандартным инструкциям по установке. 3. **Установка расширений для поддержки HDL**: После установки VS Code откройте его и перейдите в представление расширений (Ctrl+Shift+X или Cmd+Shift+X). Найдите и установите соответствующие расширения для Verilog/SystemVerilog, такие как: * **Verilog-HDL/SystemVerilog** (от mshr-h) * **VHDL** (если вы также работаете с VHDL) Эти расширения обеспечивают подсветку синтаксиса, линтинг и другие полезные функции. #### **4.3.3. Клонирование репозитория PCILeech-FPGA** Этот репозиторий содержит базовую структуру прошивки и скрипты, которые вы будете изменять. **Шаги**: 1. **Откройте терминал или командную строку**: (например, Git Bash в Windows, Terminal в Linux). 2. **Перейдите в желаемый каталог**: Выберите место, где вы хотите хранить свои проекты. ```bash cd ~/Projects/ # В Linux/macOS cd C:\Users\YourUsername\Documents\Projects\ # В Windows ``` 3. **Клонируйте репозиторий**: ```bash git clone https://github.com/ufrisk/pcileech-fpga.git ``` 4. **Перейдите в клонированный каталог**: ```bash cd pcileech-fpga ``` Это будет ваш основной каталог проекта. Проект PCILeech-FPGA часто содержит подкаталоги для различных вариантов плат (например, `pcileech-artix-7-50t`, `pcileech-squirrel-35t`). Вам нужно будет перейти в соответствующий подкаталог, специфичный для вашей платы. #### **4.3.4. Настройка чистой среды разработки** **Рекомендация**: Всегда работайте в изолированной или выделенной среде, особенно при работе с низкоуровневым оборудованием и потенциальными последствиями для безопасности. **Шаги**: 1. **Используйте выделенную машину для разработки или виртуальную машину**: * **Физическая машина**: Если возможно, используйте отдельный физический компьютер для разработки и тестирования FPGA. Это предотвращает случайную нестабильность системы или риски безопасности на вашей основной машине. * **Виртуальная машина (ВМ)**: ВМ может быть хорошим вариантом для изоляции среды разработки. Однако прямой сквозной проброс PCIe (PCIe Hotplug или VT-d passthrough) в ВМ обычно требуется для правильного обнаружения и работы карты FPGA, что может быть сложно настроить и все еще может представлять риск для хоста, если не сделано осторожно. Для первоначальной установки инструментов и редактирования кода ВМ вполне подходит. 2. **Минимизируйте фоновые приложения**: Убедитесь, что не запущены другие ресурсоемкие приложения, которые могут мешать производительности Vivado во время синтеза и реализации. 3. **Отключите конфликтующее программное обеспечение**: Временно отключите любое антивирусное, брандмауэрное или защитное программное обеспечение, которое может мешать низкоуровневому доступу к оборудованию или JTAG-связи во время разработки и тестирования. Не забудьте включить их снова, когда закончите работу. --- ## **5. Сбор информации об устройстве-доноре** Точная эмуляция устройства зависит от тщательного извлечения и воспроизведения критической информации с устройства-донора. Этот всесторонний сбор данных позволяет вашей FPGA точно имитировать конфигурацию и поведение целевого оборудования по PCIe, обеспечивая совместимость и функциональность при взаимодействии с хост-системой. ### **5.1. Использование Arbor для сканирования устройств PCIe** **Arbor** — это мощный и удобный инструмент, разработанный для глубокого сканирования устройств PCIe. Он предоставляет подробную информацию о пространстве конфигурации подключенного оборудования, что делает его бесценным ресурсом для извлечения необходимой информации для эмуляции устройства. #### **5.1.1. Установка Arbor** Чтобы начать использовать Arbor для сканирования устройств, вы должны сначала установить программное обеспечение на свою систему. **Шаги:** 1. **Посетите страницу загрузки Arbor:** * Перейдите на официальный сайт MindShare ([https://www.mindshare.com/](https://www.mindshare.com/)) с помощью вашего любимого веб-браузера. Вам нужно будет найти раздел "Software" или "Downloads", чтобы найти Arbor. * Убедитесь, что вы заходите на сайт напрямую, чтобы избежать вредоносных перенаправлений. 2. **Создайте учетную запись (если требуется):** * Arbor может потребовать от вас создания учетной записи пользователя для доступа к ссылкам для скачивания. * Предоставьте необходимую информацию, такую как ваше имя, адрес электронной почты и организацию. * Подтвердите свой адрес электронной почты, если потребуется, для активации вашей учетной записи. 3. **Скачайте Arbor:** * После входа в систему найдите раздел загрузки для Arbor. * Выберите версию, совместимую с вашей операционной системой (например, Windows 10/11 64-бит). * Нажмите кнопку **Download** и сохраните установщик в известном месте на вашем компьютере. 4. **Установите Arbor:** * Найдите загруженный файл установщика (например, `ArborSetup.exe`). * Щелкните правой кнопкой мыши по установщику и выберите **Run as administrator**, чтобы убедиться, что у него есть необходимые разрешения. * Следуйте инструкциям на экране, чтобы завершить процесс установки. * Примите лицензионное соглашение. * Выберите каталог установки. * Выберите создание ярлыков на рабочем столе, если это необходимо. 5. **Проверка установки:** * По завершении убедитесь, что Arbor отображается в меню "Пуск" или на рабочем столе. * Запустите Arbor, чтобы убедиться, что он открывается без ошибок. #### **5.1.2. Сканирование устройств PCIe** После установки Arbor вы можете приступить к сканированию вашей системы на наличие подключенных устройств PCIe. **Шаги:** 1. **Запустите Arbor:** * Дважды щелкните по значку Arbor на рабочем столе или найдите его через меню "Пуск". * Если появится запрос контроля учетных записей (UAC), разрешите приложению вносить изменения в ваше устройство. 2. **Перейдите на вкладку "Local System":** * В интерфейсе Arbor найдите панель навигации или вкладки. * Нажмите **Local System** для доступа к инструментам сканирования локальной машины. 3. **Сканирование устройств PCIe:** * Найдите кнопку **Scan** или **Rescan**, обычно расположенную вверху или внизу интерфейса. * Нажмите **Scan/Rescan**, чтобы начать процесс обнаружения. * Дождитесь завершения процесса сканирования; это может занять несколько мгновений в зависимости от количества подключенных устройств. 4. **Просмотр обнаруженных устройств:** * После завершения сканирования Arbor отобразит список всех обнаруженных устройств PCIe. * Устройства обычно перечисляются с их именами, идентификаторами устройств и другой идентификационной информацией. #### **5.1.3. Идентификация устройства-донора** Идентификация правильного устройства-донора имеет решающее значение для точной эмуляции. **Шаги:** 1. **Найдите ваше устройство-донор в списке:** * Прокрутите список устройств, обнаруженных Arbor. * Ищите устройство, соответствующее марке и модели вашего донорского оборудования. * Устройства могут быть перечислены по именам поставщиков, типам устройств или функциям. 2. **Проверьте детали устройства:** * Нажмите на устройство, чтобы выбрать его. * Убедитесь, что **Device ID** и **Vendor ID** соответствуют идентификаторам вашего устройства-донора. * **Совет:** Эти идентификаторы обычно можно найти в документации устройства или на веб-сайте производителя. Для распространенных устройств быстрый поиск в Интернете по запросу "[Название устройства] Vendor ID Device ID" часто дает результаты. 3. **Просмотр подробной конфигурации:** * Выбрав устройство, найдите и нажмите на опцию, такую как **View Details** или **Properties**. * Это откроет подробное представление, показывающее пространство конфигурации и возможности устройства. 4. **Перекрестная проверка с физическим оборудованием:** * Если в списке несколько похожих устройств, перекрестно проверьте **номер слота** или **адрес шины** с физическим слотом, где установлено устройство-донор. Это поможет убедиться, что вы анализируете правильное оборудование. #### **5.1.4. Захват данных устройства** Извлечение подробной информации из устройства-донора необходимо для точной эмуляции. **Информация для извлечения:** * **Device ID (0xXXXX):** 16-битный идентификатор, уникальный для модели устройства. * **Vendor ID (0xYYYY):** 16-битный идентификатор, присвоенный производителю. * **Subsystem ID (0xZZZZ):** Идентифицирует конкретную подсистему или вариант (например, конкретную модель в рамках линейки продуктов). * **Subsystem Vendor ID (0xWWWW):** Идентифицирует поставщика подсистемы (часто совпадает с основным Vendor ID, но может отличаться для OEM-версий). * **Revision ID (0xRR):** Указывает уровень аппаратной ревизии устройства. * **Class Code (0xCCCCCC):** 24-битный код, определяющий основную функцию/тип устройства (например, `0x020000` для контроллера Ethernet, `0x010802` для контроллера NVMe). Это помогает ОС загружать общие драйверы. * **Базовые адресные регистры (BARs):** * Регистры, определяющие области адресов памяти или ввода-вывода, используемые устройством. * Включает BAR0 до BAR5, каждый потенциально 32 или 64 бита. Для каждого BAR отметьте его **Тип (Память или Ввод-вывод)**, **Разрядность (32-битный или 64-битный)**, **Размер (например, 256 МБ, 4 КБ)** и **Статус Prefetchable (Да/Нет)**. Это критически важно для отображения памяти. * **Возможности (Capabilities):** Перечисляет поддерживаемые функции и их конфигурации, часто находятся в структуре связанного списка в пространстве конфигурации. Примеры включают: * **Структура возможностей PCIe**: Скорость канала PCIe (например, Gen2, Gen3), Ширина канала (например, x1, x4), Максимальный размер полезной нагрузки, Максимальный размер запроса на чтение. * **Структура возможностей MSI/MSI-X**: Информация о прерываниях, генерируемых сообщениями, включая количество поддерживаемых векторов. * **Структура возможностей управления питанием**: Поддерживаемые состояния питания (D0, D1, D2, D3hot, D3cold). * **Серийный номер устройства (DSN):** 64-битный уникальный идентификатор, если устройство его поддерживает (находится в расширенной возможности "Device Serial Number"). Не все устройства реализуют это. **Шаги:** 1. **Перейдите на вкладку PCI Config:** * В подробном представлении устройства найдите и выберите вкладку **PCI Config** или **Configuration Space**. Обычно это представляет собой декодированный вид необработанных регистров пространства конфигурации. 2. **Запишите соответствующие детали:** * Тщательно задокументируйте каждое из требуемых полей, перечисленных выше. * Используйте скриншоты или скопируйте значения в текстовый файл, выделенную электронную таблицу или структурированный формат документации для точности. * Убедитесь, что шестнадцатеричные значения записаны правильно, включая префикс `0x`, если он используется. 3. **Разверните списки возможностей:** * Ищите разделы, помеченные как **Capabilities** или **Advanced Features**. Они часто являются кликабельными или расширяются, чтобы показать подразделы. * Задокументируйте каждую присутствующую возможность и ее соответствующие параметры (например, управление сообщениями MSI, флаги состояния питания, текущие/максимальные настройки канала PCIe). 4. **Подробно изучите BARы:** * В пространстве конфигурации найдите записи для BAR0 до BAR5. * Для каждого активного BAR отметьте его выделенный размер, является ли он отображаемым на память или I/O, его разрядность (32-битную или 64-битную) и является ли он prefetchable. Эта информация часто четко представлена в графическом интерфейсе Arbor. 5. **Сохраните данные для справки:** * Скомпилируйте всю извлеченную информацию в хорошо организованный документ (например, файл Markdown, файл `.txt` или электронную таблицу Excel). * Четко пометьте каждый раздел для удобства ссылки при настройке прошивки. ### **5.2. Извлечение и запись атрибутов устройства** После захвата данных крайне важно понять значение каждого атрибута и убедиться, что они были точно задокументированы для успешной эмуляции. **Убедитесь, что вы точно записали следующее:** 1. **Device ID:** * **Назначение:** Уникально идентифицирует конкретную модель устройства PCIe. * **Использование в эмуляции:** Необходим для корректного распознавания эмулируемого устройства операционной системой хоста и, что крайне важно, для попытки загрузки соответствующего драйвера устройства. 2. **Vendor ID:** * **Назначение:** Идентифицирует производителя устройства PCIe. * **Использование в эмуляции:** Используется в сочетании с Device ID для формирования уникального идентификатора (`VendorID:DeviceID`), который ОС использует для сопоставления устройства с соответствующим драйвером. 3. **Subsystem ID и Subsystem Vendor ID:** * **Назначение:** Эти необязательные идентификаторы позволяют различать варианты устройства от одного и того же поставщика или OEM-версии, где основной Vendor/Device ID может быть общим. * **Использование в эмуляции:** Важно для эмуляции устройств с несколькими конфигурациями или тех, которые поставляются OEM-производителем, поскольку драйвер может специально искать эти значения. 4. **Revision ID:** * **Назначение:** Указывает уровень аппаратной ревизии устройства. * **Использование в эмуляции:** Помогает в идентификации конкретных аппаратных версий, которые могут требовать разных драйверов, прошивок или иметь тонкие поведенческие различия. 5. **Class Code:** * **Назначение:** 24-битный код, который классифицирует общую функцию устройства (например, `0x020000` для контроллера Ethernet, `0x010802` для контроллера NVMe, `0x0C0300` для контроллера USB-хоста). Он состоит из базового класса, подкласса и программного интерфейса. * **Использование в эмуляции:** Позволяет ОС понять общую функцию устройства и загрузить общий драйвер класса, если специфический драйвер поставщика не найден. Это крайне важно для первоначального распознавания устройства. 6. **Базовые адресные регистры (BARs):** * **Назначение:** Определяют области адресов, отображаемые на память или порты ввода-вывода, которые устройство использует для регистров, внутренних буферов или расширений пространства конфигурации. ОС хоста выделяет физические адреса этим BARам во время перечисления. * **Использование в эмуляции:** Критически важно для отображения внутренней памяти и регистров эмулируемого устройства в адресное пространство хост-системы. Размер, тип (Память/Ввод-вывод, 32/64-бит) и статус prefetchable для каждого BAR должны точно соответствовать устройству-донору. 7. **Возможности (Capabilities):** * **Назначение:** Перечисляет расширенные функции, поддерживаемые устройством, такие как расширенная отчетность об ошибках, управление питанием, MSI/MSI-X, расширенные возможности PCIe (например, AER, VC/PF) и т.д. Каждая возможность определяется структурой со своими регистрами. * **Использование в эмуляции:** Необходимы для точного воспроизведения того, как устройство-донор объявляет свои функции и как хост-система взаимодействует с этими функциями (например, механизмы доставки прерываний, переходы состояний питания, отчетность об ошибках). 8. **Серийный номер устройства (DSN):** * **Назначение:** Уникальный 64-битный идентификатор для устройства, обычно необязательная расширенная возможность. * **Использование в эмуляции:** Хотя это необязательно, некоторые драйверы или приложения управления могут специально запрашивать и полагаться на DSN для идентификации, лицензирования или проверок безопасности. Точная эмуляция этого может предотвратить обнаружение вашего устройства как общего или модифицированного периферийного устройства. **Лучшие практики сбора данных:** * **Организуйте данные:** Создайте структурированный документ или электронную таблицу. Используйте четкие заголовки и подзаголовки для каждого атрибута. Шаблон может быть полезен. * **Включайте единицы измерения и форматы:** Всегда указывайте единицы измерения для размеров (например, МБ, КБ) и используйте последовательное форматирование для шестнадцатеричных значений (например, `0x1234`, `16'h1234`). * **Перекрестная проверка со спецификациями (если возможно):** Если доступны, обратитесь к техническим описаниям устройства-донора или общедоступным спецификациям для проверки значений. Это может помочь выявить любые расхождения или необычные конфигурации, не сразу очевидные из необработанного сканирования. * **Защитите данные:** Храните собранную информацию в безопасности. Помните, что эти данные могут содержать проприетарную или конфиденциальную информацию. * **Поймите "что отсутствует":** Специализированные инструменты, такие как Arbor, превосходны, но они могут не охватывать каждую тонкость сложных, высокопроприетарных устройств (например, специфические регистры, определяемые поставщиком, за пределами стандартного пространства конфигурации). Для продвинутой эмуляции вам может потребоваться объединить эту информацию с обратным инжинирингом драйверов устройства-донора. --- ## **6. Начальная настройка прошивки** После того как информация об устройстве-доноре тщательно задокументирована, следующий критически важный этап включает настройку прошивки вашей FPGA для точной эмуляции устройства-донора. Этот процесс начинается с изменения ключевых идентификационных регистров в пространстве конфигурации PCIe и обеспечения правильной интеграции специфических идентификаторов, таких как серийный номер устройства. ### **6.1. Изменение пространства конфигурации** Пространство конфигурации PCIe является фундаментальным компонентом, который определяет, как устройство распознается и взаимодействует с хост-системой во время перечисления. Настройка этого пространства для точного соответствия профилю устройства-донора абсолютно необходима для успешной эмуляции, позволяя ОС хоста загружать правильный драйвер и взаимодействовать, как ожидается. #### **6.1.1. Переход к файлу конфигурации** Параметры пространства конфигурации PCIe обычно определяются в определенном файле SystemVerilog (`.sv`) в проекте PCILeech-FPGA. Этот файл синтезируется в логику, которая конфигурирует IP-ядро PCIe и предоставляет идентификационные данные устройства хосту. **Обычный путь для PCILeech-FPGA (платы на базе Artix-7, такие как Squirrel):** Найдите файл, отвечающий за настройку параметров PCIe для вашей конкретной платы. Для многих вариантов PCILeech на базе Artix-7 это будет: ``` pcileech-fpga//src/pcileech_pcie_cfg_a7.sv ``` * **Пример (для Squirrel 35T)**: ``` pcileech-fpga/pcileech-squirrel-35t/src/pcileech_pcie_cfg_a7.sv ``` *Примечание: Фактическое имя папки, например `pcileech-squirrel-35t`, может немного отличаться в зависимости от конкретной версии PCILeech-FPGA или форка, который вы клонировали. Всегда переходите в соответствующий подкаталог, специфичный для платы, после клонирования основного репозитория.* #### **6.1.2. Открытие файла в Visual Studio Code** Редактирование файла конфигурации требует подходящего редактора кода, поддерживающего подсветку синтаксиса для SystemVerilog (или Verilog), что делает код более легким для чтения и модификации. **Шаги:** 1. **Запустите Visual Studio Code:** * Щелкните по значку VS Code или найдите его через меню "Пуск". 2. **Откройте файл:** * Используйте **File > Open File** или нажмите `Ctrl + O` (или `Cmd + O` на macOS). * Перейдите по пути к файлу конфигурации, указанному в разделе 6.1.1 (например, `pcileech-fpga/pcileech-squirrel-35t/src/pcileech_pcie_cfg_a7.sv`). * Выберите файл и нажмите **Open**. 3. **Проверьте подсветку синтаксиса:** * Убедитесь, что редактор распознает расширение файла `.sv` и применяет правильную подсветку синтаксиса SystemVerilog. Если этого не происходит, пересмотрите раздел 4.3.2, чтобы убедиться, что вы установили рекомендуемые расширения Verilog/SystemVerilog для VS Code. 4. **Ознакомьтесь со структурой файла:** * Прокрутите файл. Вы обычно найдете параметры, определенные с помощью `localparam` или `reg` присвоений, часто с комментариями, объясняющими их назначение. Ищите разделы, где определены и присвоены стандартные регистры конфигурации PCIe (Vendor ID, Device ID и т.д.). #### **6.1.3. Изменение Device ID и Vendor ID** Обновление этих фундаментальных идентификаторов является наиболее важным шагом для правильного распознавания эмулируемого устройства хост-системой как вашего донора. Операционная система в значительной степени полагается на пару `Vendor ID` и `Device ID` для идентификации подключенного оборудования и загрузки соответствующего драйвера устройства. **Шаги:** 1. **Поиск `cfg_deviceid`:** * Используйте функцию поиска (`Ctrl + F` или `Cmd + F`) в VS Code. * Найдите строку, определяющую `cfg_deviceid`. Она обычно выглядит примерно так: ```verilog reg [15:0] cfg_deviceid = 16'hAAAA; // Идентификатор устройства по умолчанию или заполнитель ``` 2. **Обновление Device ID:** * Замените `AAAA` на 16-битный шестнадцатеричный Device ID, извлеченный из устройства-донора с помощью Arbor (например, `0x1234`). * **Пример:** Если Device ID донора `0x1234`, обновите строку следующим образом: ```verilog reg [15:0] cfg_deviceid = 16'h1234; // Обновлен Device ID донора (например, из сетевой карты) ``` 3. **Поиск `cfg_vendorid`:** * Найдите строку, определяющую `cfg_vendorid`. Она будет аналогична по формату `cfg_deviceid`: ```verilog reg [15:0] cfg_vendorid = 16'hBBBB; // Идентификатор поставщика по умолчанию или заполнитель ``` 4. **Обновление Vendor ID:** * Замените `BBBB` на 16-битный шестнадцатеричный Vendor ID, извлеченный из устройства-донора (например, `0xABCD`). * **Пример:** Если Vendor ID донора `0xABCD`, обновите строку следующим образом: ```verilog reg [15:0] cfg_vendorid = 16'hABCD; // Обновлен Vendor ID донора (например, Intel Corporation) ``` 5. **Обеспечение правильного форматирования:** * Убедитесь, что шестнадцатеричные значения правильно предваряются `16'h` (указывает на 16-битное шестнадцатеричное число). * Поддерживайте последовательный отступ и стиль комментариев для удобочитаемости. #### **6.1.4. Изменение Subsystem ID и Revision ID** Эти идентификаторы предоставляют дополнительные сведения о варианте устройства, конкретных моделях продуктов или аппаратных ревизиях. Хотя они часто являются необязательными, их соответствие повышает аутентичность эмуляции и может быть критически важным для драйверов, выполняющих детальные проверки. **Шаги:** 1. **Поиск `cfg_subsysid`:** * Найдите строку, определяющую `cfg_subsysid`. ```verilog reg [15:0] cfg_subsysid = 16'hCCCC; // Заполнитель Subsystem ID ``` 2. **Обновление Subsystem ID:** * Замените `CCCC` на 16-битный шестнадцатеричный Subsystem ID из вашего устройства-донора (например, `0x5678`). * **Пример:** ```verilog reg [15:0] cfg_subsysid = 16'h5678; // Установлен Subsystem ID донора ``` 3. **Поиск `cfg_subsysvendorid`:** * Найдите строку, определяющую `cfg_subsysvendorid`. ```verilog reg [15:0] cfg_subsysvendorid = 16'hDDDD; // Заполнитель Subsystem Vendor ID ``` 4. **Обновление Subsystem Vendor ID (если применимо):** * Замените `DDDD` на 16-битный шестнадцатеричный Subsystem Vendor ID из вашего устройства-донора (например, `0x9ABC`). Если ваше устройство-донор не имеет уникального Subsystem Vendor ID (т.е. он такой же, как и основной Vendor ID), вы все равно должны установить его на это значение. * **Пример:** ```verilog reg [15:0] cfg_subsysvendorid = 16'h9ABC; // Установлен Subsystem Vendor ID донора ``` 5. **Поиск `cfg_revisionid`:** * Найдите строку, определяющую `cfg_revisionid`. ```verilog reg [7:0] cfg_revisionid = 8'hEE; // Заполнитель Revision ID ``` 6. **Обновление Revision ID:** * Замените `EE` на 8-битный шестнадцатеричный Revision ID из вашего устройства-донора (например, `0x01`). * **Пример:** ```verilog reg [7:0] cfg_revisionid = 8'h01; // Установлен Revision ID донора ``` #### **6.1.5. Обновление Class Code** Class Code информирует операционную систему хоста об общем типе и функции устройства (например, сетевой контроллер, устройство хранения данных). Это жизненно важно для ОС, чтобы загрузить общие драйверы класса, даже если специфический драйвер поставщика не установлен. **Шаги:** 1. **Поиск `cfg_classcode`:** * Найдите строку, определяющую `cfg_classcode`. ```verilog reg [23:0] cfg_classcode = 24'hFFFFFF; // Код класса по умолчанию или заполнитель ``` 2. **Обновление Class Code:** * Замените `FFFFFF` на 24-битный шестнадцатеричный Class Code, который вы извлекли из устройства-донора (например, `0x020000` для контроллера Ethernet). Помните формат: Базовый класс, Подкласс, Интерфейс программирования. * **Пример:** Если Class Code донора `0x020000` (что означает Базовый класс: 0x02 - Сетевой контроллер, Подкласс: 0x00 - Контроллер Ethernet, Prog IF: 0x00), обновите следующим образом: ```verilog reg [23:0] cfg_classcode = 24'h020000; // Установлен Class Code донора (например, контроллер Ethernet) ``` 3. **Проверка правильной разрядности:** * Убедитесь, что Class Code правильно представлен как 24-битное значение с использованием префикса `24'h` для шестнадцатеричных значений. #### **6.1.6. Сохранение изменений** После внесения всех изменений в параметры конфигурации крайне важно сохранить и просмотреть их. **Шаги:** 1. **Сохраните файл:** * Нажмите **File > Save** в VS Code или нажмите `Ctrl + S` (или `Cmd + S`). 2. **Просмотрите изменения:** * Перед закрытием быстро перечитайте измененные строки, чтобы подтвердить их точность по сравнению с задокументированной информацией об устройстве-доноре. * Проверьте наличие очевидных синтаксических ошибок или опечаток (расширения VS Code могут их подсветить). 3. **Опционально - Использование контроля версий:** * Если вы используете Git (настоятельно рекомендуется для любого проекта кода, особенно прошивки), зафиксируйте свои изменения с четким и значимым сообщением. Это создает историческую запись ваших модификаций. * **Пример команд Git:** ```bash git add pcileech_pcie_cfg_a7.sv git commit -m "Обновлены регистры конфигурации PCIe (VID, DID, SubIDs, Revision, Class Code) в соответствии с устройством-донором: [Название устройства-донора]" ``` ### **6.2. Вставка серийного номера устройства (DSN)** Серийный номер устройства (DSN) — это уникальный 64-битный идентификатор, который могут использовать некоторые устройства PCIe (особенно те, которые имеют расширенные функции или специальные драйверы). Включение его повышает аутентичность вашей эмуляции и может помочь обойти проверки в драйверах, которые явно запрашивают это значение. #### **6.2.1. Определение поля DSN** DSN, если реализован устройством-донором, является частью расширенных возможностей PCIe. В рамках PCILeech-FPGA поле DSN часто представлено как настраиваемый параметр в том же файле конфигурации, который вы редактировали. **Шаги:** 1. **Поиск `cfg_dsn`:** * В `pcileech_pcie_cfg_a7.sv` (или эквивалентном файле конфигурации вашей платы) используйте функцию поиска (`Ctrl + F` или `Cmd + F`), чтобы найти `cfg_dsn`. 2. **Понимание существующего назначения:** * DSN может быть установлен в значение по умолчанию (часто все нули) или закомментирован. Обычно он выглядит примерно так: ```verilog reg [63:0] cfg_dsn = 64'h0000000000000000; // DSN по умолчанию (обычно 0, если не используется) ``` #### **6.2.2. Вставка DSN** Обновление DSN включает установку его точного 64-битного шестнадцатеричного значения, полученного с вашего устройства-донора. **Шаги:** 1. **Обновление `cfg_dsn`:** * Замените существующее шестнадцатеричное значение 64-битным DSN, который вы извлекли из устройства-донора с помощью Arbor. * **Пример:** Если DSN донора `0x0011223344556677`, обновите следующим образом: ```verilog reg [63:0] cfg_dsn = 64'h0011223344556677; // Серийный номер устройства-донора ``` 2. **Обработка недоступности или неактуальности DSN:** * Если ваше устройство-донор *не* имеет DSN, или если вы определили, что это не обязательный параметр для драйвера, на который вы ориентируетесь, вы можете просто оставить его нулями: ```verilog reg [63:0] cfg_dsn = 64'h0000000000000000; // DSN не указан донором, оставлено значение по умолчанию 0 ``` * **Внимание**: Для критически важных эмуляций, если устройство-донор имеет DSN, лучше эмулировать его точно. 3. **Обеспечение правильного форматирования:** * DSN — это 64-битное значение; убедитесь, что оно правильно отформатировано с префиксом `64'h` для шестнадцатеричных значений. #### **6.2.3. Сохранение изменений** Завершите модификацию DSN, сохранив и просмотрев файл. **Шаги:** 1. **Сохраните файл:** * Нажмите **File > Save** в VS Code или нажмите `Ctrl + S`. 2. **Проверьте синтаксис:** * Проверьте наличие красных подчеркиваний или индикаторов ошибок от синтаксического анализатора VS Code. Немедленно исправьте любые проблемы. 3. **Задокументируйте изменения:** * Если используется контроль версий, зафиксируйте обновления с соответствующим сообщением. * **Пример команд Git:** ```bash git commit -am "Вставлен серийный номер устройства (DSN) донора в конфигурацию PCIe" ``` --- ## **7. Настройка проекта Vivado** После обновления файлов прошивки для отражения критически важных идентификационных и конфигурационных данных устройства-донора, следующим важным шагом является интеграция этих изменений в проект Vivado. Это включает генерацию файлов проекта для вашей конкретной платы FPGA, настройку встроенного IP-ядра PCIe и подготовку всего проекта к этапам синтеза и реализации. ### **7.1. Генерация файлов проекта Vivado** Vivado, пакет разработки Xilinx (AMD), использует скрипты Tcl (Tool Command Language) для автоматизации создания проектов, добавления исходных файлов и настройки параметров проекта. Запуская эти скрипты, предоставленные с фреймворком PCILeech-FPGA, вы гарантируете, что ваш проект Vivado правильно настроен для вашей целевой платы FPGA. #### **7.1.1. Открытие Vivado** Запуск новой сессии Vivado гарантирует, что никакие оставшиеся настройки или открытые проекты из предыдущих сессий не будут мешать вашей текущей работе. **Шаги:** 1. **Запустите Vivado:** * Найдите значок приложения Vivado в меню "Пуск" (Windows) или папке "Приложения" (Linux/macOS). * Щелкните, чтобы открыть его. 2. **Выберите правильную версию:** * Если у вас установлено несколько версий Vivado, убедитесь, что вы запускаете ту, которая совместима с вашей платой FPGA и проектом PCILeech-FPGA (как отмечено в разделе 4.3.1, рекомендуется использовать последнюю стабильную версию, такую как Vivado 2023.x). 3. **Дождитесь экрана запуска:** * Дождитесь полной инициализации Vivado и появления приветственного экрана или панели управления проектами, прежде чем продолжить. #### **7.1.2. Доступ к консоли Tcl** Консоль Tcl в Vivado — это ваш основной интерфейс для выполнения скриптов и прямых команд. Здесь вы будете запускать скрипты генерации проекта. **Шаги:** 1. **Откройте консоль Tcl:** * В интерфейсе Vivado перейдите в строку меню. * Нажмите **Window** > **Tcl Console**. * Панель Tcl Console обычно появляется в нижней части окна Vivado. 2. **Изменение размера консоли (необязательно):** * Вы можете перетащить верхнюю границу консоли, чтобы изменить ее размер, сделав ее выше для лучшей видимости команд и вывода. 3. **Очистка предыдущих команд (необязательно, но рекомендуется):** * Если есть какие-либо предыдущие команды или сообщения, вы можете щелкнуть правой кнопкой мыши внутри консоли и выбрать "Clear Console" для чистого старта. #### **7.1.3. Переход в каталог проекта** Перед запуском Tcl-скрипта вы должны убедиться, что текущий рабочий каталог Tcl Console установлен в правильное место, где находятся скрипты проекта PCILeech-FPGA, специфичные для вашей платы. **Для Squirrel DMA (Artix-7 35T) или аналогичных плат:** **Типичный путь (после клонирования `pcileech-fpga` и перехода к вашему варианту платы):** ``` C:/Users/YourUsername/Documents/pcileech-fpga/pcileech-squirrel-35t/ # В Windows ~/Projects/pcileech-fpga/pcileech-squirrel-35t/ # В Linux/macOS ``` *Примечание: Замените `` на фактическое имя подкаталога для вашей платы (например, `pcileech-squirrel-35t`, `pcileech-artix-7-50t`).* **Шаги:** 1. **Установите рабочий каталог в Tcl Console:** * В консоли Vivado Tcl введите команду `cd`, за которой следует полный путь к каталогу проекта вашей платы. * **Пример (Windows):** ```tcl cd C:/Users/YourUsername/Documents/pcileech-fpga/pcileech-squirrel-35t/ ``` * **Пример (Linux/macOS):** ```tcl cd ~/Projects/pcileech-fpga/pcileech-squirrel-35t/ ``` * *Совет для самокоррекции: Используйте прямые слеши (`/`) даже в Windows для путей Tcl.* 2. **Проверьте изменение каталога:** * Чтобы убедиться, что вы находитесь в правильном каталоге, введите `pwd` (print working directory) в Tcl Console. * Консоль должна отобразить полный путь, который вы только что установили, подтверждая изменение. #### **7.1.4. Генерация проекта Vivado** Запуск соответствующего Tcl-скрипта, специфичного для вашей платы FPGA, автоматизирует весь процесс настройки проекта в Vivado. Это включает создание проекта, добавление всех необходимых исходных файлов (HDL, ограничения) и настройку основных параметров проекта. **Шаги:** 1. **Запустите Tcl-скрипт:** * Введите команду `source`, за которой следует имя скрипта генерации проекта для вашей платы. Проект PCILeech-FPGA обычно предоставляет эти скрипты в основном каталоге платы. * **Для Squirrel (Artix-7 35T) (и аналогичных плат Artix-7):** ```tcl source vivado_generate_project_squirrel.tcl -notrace ``` * **Для Enigma-X1 (Artix-7 75T):** ```tcl source vivado_generate_project_enigma_x1.tcl -notrace ``` * **Для ZDMA (Artix-7 100T):** ```tcl source vivado_generate_project_100t.tcl -notrace ``` * Опция `-notrace` предотвращает подробный вывод для каждой команды Tcl, сохраняя консоль более чистой. 2. **Дождитесь завершения скрипта:** * Скрипт будет выполнять множество команд последовательно. Этот процесс может занять несколько минут, в зависимости от производительности вашей системы и сложности проекта. * Следите за сообщениями о ходе выполнения в Tcl Console. Скрипт будет: * Создавать новый проект Vivado (файл `.xpr`) в вашем текущем каталоге. * Добавлять все исходные файлы SystemVerilog/Verilog (`.sv`, `.v`). * Добавлять конфигурации IP-ядер Xilinx (`.xci`). * Добавлять файлы XDC (Xilinx Design Constraints). * Потенциально настраивать различные параметры проекта. * **Устранение любых ошибок**: Если возникают какие-либо ошибки (например, "file not found," "invalid command"), скрипт обычно останавливается. Просмотрите сообщение об ошибке, исправьте основную проблему (например, неверный путь, отсутствующий файл) и перезапустите скрипт. 3. **Подтвердите генерацию проекта:** * После успешного завершения Tcl Console обычно указывает, что проект создан, и вы должны увидеть новые файлы проекта (например, `pcileech_squirrel_top.xpr`) и связанные каталоги (например, `pcileech_squirrel_top.runs`, `pcileech_squirrel_top.ip`), сгенерированные в вашем каталоге проекта. #### **7.1.5. Открытие сгенерированного проекта** Теперь, когда файлы проекта Vivado были успешно сгенерированы Tcl-скриптом, вы можете открыть проект в графическом интерфейсе Vivado для дальнейшего изучения и настройки. **Шаги:** 1. **Откройте проект:** * В Vivado нажмите **File** > **Open Project**. * Перейдите в каталог вашего проекта (тот же, который вы установили в Tcl Console в разделе 7.1.3). 2. **Выберите файл проекта:** * Найдите и выберите файл проекта Vivado (расширение `.xpr`), который соответствует вашей плате. * **Для Squirrel:** Файл обычно будет называться `pcileech_squirrel_top.xpr`. * Нажмите на файл `.xpr`, чтобы выбрать его. 3. **Нажмите Открыть:** * Vivado загрузит проект, отображая иерархию проекта, исходные файлы, блочный дизайн IP Integrator (если используется) и различные представления дизайна. Это может занять некоторое время. 4. **Проверьте содержимое проекта:** * В окне **Project Manager** (обычно слева) разверните панель **Sources**. * Убедитесь, что все ожидаемые исходные файлы (Verilog/SystemVerilog, XDC, IP-ядра) перечислены и что иерархия проекта выглядит правильно. * Проверьте панель **Messages** (внизу) на наличие любых предупреждений или критических предупреждений, которые появляются при открытии проекта, так как они могут указывать на потенциальные проблемы. ### **7.2. Изменение IP-блоков** IP-ядро PCIe является сердцем интерфейса PCIe вашего устройства. Это предварительно проверенный, настраиваемый блок от Xilinx, который обрабатывает сложные уровни протокола PCIe. Хотя некоторые значения пространства конфигурации обрабатываются в файле SystemVerilog (Раздел 6.1), другие основные параметры PCIe, особенно те, что связаны с возможностями канала и структурами BAR, настраиваются непосредственно в параметрах настройки IP-ядра PCIe в Vivado. Настройка IP-ядра гарантирует, что ваша FPGA ведет себя идентично донорскому оборудованию на уровне протокола PCIe. #### **7.2.1. Доступ к IP-ядру PCIe** IP-ядро PCIe является экземпляром IP-блока в вашем проекте Vivado. Вам нужно будет открыть его графический интерфейс настройки, чтобы изменить его параметры. **Шаги:** 1. **Найдите IP-ядро PCIe:** * На панели **Sources** (в окне **Project Manager**) убедитесь, что выбрана вкладка **Hierarchy**. * Разверните иерархию проекта, пока не найдете экземпляр IP-ядра PCIe. * Обычно он называется `pcie_7x_0.xci` (для FPGA 7-й серии) или аналогично, и находится в подкаталоге `ip` исходных файлов вашего проекта. 2. **Откройте окно настройки IP:** * **Щелкните правой кнопкой мыши** по файлу `pcie_7x_0.xci`. * В контекстном меню выберите **Customize IP**. * Откроется окно **IP Configuration** (или аналогичное название, например "Customize IP" или "Re-customize IP"), представляющее графический интерфейс с различными вкладками и опциями для настройки IP-ядра PCIe. 3. **Дождитесь загрузки настроек IP:** * Интерфейс настройки IP может занять несколько мгновений для инициализации и заполнения всех своих настроек. Убедитесь, что все опции и вкладки полностью загружены и реагируют, прежде чем вы начнете вносить изменения. #### **7.2.2. Настройка идентификаторов устройств и BAR в IP-ядре** Хотя некоторые идентификаторы устройств устанавливаются в `pcileech_pcie_cfg_a7.sv`, само IP-ядро PCIe также содержит внутренние параметры для Device ID, Vendor ID и, что важно, определения для базовых адресных регистров (BAR). Вы должны убедиться, что они совпадают. Некоторые значения, установленные в файле `.sv`, могут переопределять или передаваться в IP-ядро, но рекомендуется обеспечить согласованность и здесь. Настройки BAR в IP-ядре особенно важны, так как они определяют аппаратную реализацию отображения памяти. **Шаги:** 1. **Перейдите к базовым/идентификационным параметрам:** * В окне настройки IP найдите вкладку или раздел, относящийся к **Basic**, **Device and Vendor Identifiers**, **General** или **PCIe Capabilities**. Здесь определяются основные идентификаторы и начальные настройки канала. 2. **Проверьте/введите Device ID, Vendor ID, Subsystem ID, Revision ID, Class Code:** * **Критически важно убедиться, что они соответствуют значениям, которые вы ввели в `pcileech_pcie_cfg_a7.sv` и которые вы получили от устройства-донора.** * Найдите поля, такие как: * **Device ID**: Введите `0xXXXX` (например, `0x1234`). * **Vendor ID**: Введите `0xYYYY` (например, `0xABCD`). * **Subsystem ID**: Введите `0xZZZZ` (например, `0x5678`). * **Subsystem Vendor ID**: Введите `0xWWWW` (например, `0x9ABC`). * **Revision ID**: Введите `0xRR` (например, `0x01`). * **Class Code**: Введите `0xCCCCCC` (например, `0x020000`). * **Важно**: Некоторые версии IP-ядра или конкретные конфигурации могут получать эти данные непосредственно из пользовательской логики (например, `pcileech_pcie_cfg_a7.00`), или могут позволять устанавливать их непосредственно здесь. Наиболее надежный подход — устанавливать их согласованно в обоих местах, если эта опция доступна в графическом интерфейсе IP. 3. **Перейдите на вкладку базовых адресных регистров (BARs):** * В окне настройки IP найдите и выберите вкладку или раздел **BARs**. Здесь вы определяете области памяти, которые предоставляет устройство PCIe. 4. **Настройте каждый BAR:** * Для каждого BAR (BAR0 до BAR5), который использует ваше устройство-донор, тщательно настройте следующие параметры на основе информации, извлеченной с помощью Arbor: * **Enable BAR**: Установите этот флажок только в том случае, если устройство-донор использует этот конкретный BAR. Отключите (снимите флажок) любые BARы, которые устройство-донор не использует. * **BAR Size**: Выберите точный размер из выпадающего списка (например, **256 МБ**, **64 КБ**, **4 КБ**). Это критически важно для того, чтобы ОС хоста выделила правильный объем памяти. * **BAR Type**: Выберите соответствующий тип: * **Memory (32-bit Addressing)**: Для областей, отображаемых на память, доступных по 32-битным адресам. * **Memory (64-bit Addressing)**: Для областей, отображаемых на память, которые могут располагаться в любом месте 64-битного адресного пространства (требуется для больших областей памяти или если устройство-донор использует это). * **I/O**: Для устаревших областей портов ввода-вывода (менее распространены в современных PCIe, но все еще возможны). * **Prefetchable**: Установите этот флажок, если BAR донора помечен как prefetchable. Это свойство позволяет хост-системе кэшировать или предвыбирать данные из этой области для повышения производительности. * **Пример конфигурации (на основе вашего устройства-донора):** * **BAR0**: * Включено: Да * Размер: **256 МБ** * Тип: **Memory (64-bit Addressing)** * Предвыбираемое: Да * **BAR1**: * Включено: Нет (если устройство-донор не использует BAR1) * *Продолжайте для BAR2-BAR5, зеркально отображая конфигурацию устройства-донора.* 5. **Обеспечьте выравнивание и отсутствие перекрывающихся пространств**: * IP-ядро Vivado обычно автоматически обрабатывает выравнивание на основе выбранного вами размера. Однако имейте в виду, что спецификация PCIe требует, чтобы размеры BAR были степенью двойки, и BARы должны быть выровнены по их размеру. * Убедитесь, что общая память, отображаемая вашими BAR, не превышает доступную блочную память (BRAM) или возможности внешней памяти FPGA. #### **7.2.3. Завершение настройки IP** После настройки всех необходимых параметров в окне настройки IP-ядра вы должны применить эти изменения, чтобы они вступили в силу в вашем проекте Vivado. **Шаги:** 1. **Просмотрите все настройки:** * Перед применением уделите немного времени, чтобы еще раз быстро просмотреть каждую вкладку в окне настройки IP. * Убедитесь, что все записи точно соответствуют задокументированным спецификациям вашего устройства-донора. Небольшая ошибка здесь может привести к проблемам с обнаружением устройства или функциональностью. 2. **Примените изменения:** * Нажмите кнопку **OK** или **Generate** (метка может варьироваться) в нижней части окна настройки IP. * Если Vivado предложит вам подтвердить, что вы хотите продолжить изменения и регенерировать выходные продукты IP, подтвердите, нажав **Yes**. 3. **Регенерация IP-ядра:** * Vivado теперь регенерирует выходные продукты IP-ядра (например, списки соединений, модели симуляции, новые файлы конфигурации `.xci`), чтобы отразить ваши новые конфигурации. * Следите за панелью **Messages** (внизу окна Vivado) на наличие любых ошибок, предупреждений или критических предупреждений, которые могут возникнуть во время этого процесса регенерации. Немедленно устраняйте любые критические предупреждения. 4. **Обновление IP в проекте:** * Vivado может автоматически обновить или предложить вам обновить любые IP-зависимости в вашем проекте после регенерации ядра. Разрешите это, чтобы убедиться, что последняя конфигурация используется во всем вашем проекте. #### **7.2.4. Блокировка IP-ядра** Блокировка IP-ядра — это рекомендуемая лучшая практика в Vivado для предотвращения непреднамеренных модификаций или повторных настроек во время последующих запусков синтеза и реализации, что потенциально может отменить ваши тщательно настроенные параметры. **Назначение блокировки:** * **Предотвращение перезаписи:** Гарантирует, что ваши ручные конфигурации в графическом интерфейсе IP-ядра сохраняются и не перезаписываются случайно автоматизацией Vivado или если IP обнаруживается как "устаревший" из-за тонких изменений проекта. * **Сохранение согласованности:** Поддерживает IP-ядро в известном, стабильном состоянии на протяжении всего процесса сборки, что особенно важно для критически важных компонентов, таких как интерфейс PCIe. **Шаги:** 1. **Откройте консоль Tcl:** * В Vivado, если консоль Tcl еще не открыта, перейдите в **Window** > **Tcl Console**. 2. **Выполните команду блокировки:** * В консоли Tcl введите следующую команду точно. Эта команда устанавливает свойство `IP_LOCKED` в `true` для вашего экземпляра IP-ядра PCIe (`pcie_7x_0`). ```tcl set_property -name {IP_LOCKED} -value true -objects [get_ips pcie_7x_0] ``` * Нажмите **Enter**, чтобы выполнить команду. 3. **Проверьте блокировку:** * Проверьте панель **Messages**. Вы должны увидеть сообщение о подтверждении, указывающее, что свойство было установлено. * Вы также можете щелкнуть правой кнопкой мыши по `pcie_7x_0.xci` на панели Sources, выбрать "IP Properties" и убедиться, что `IP_LOCKED` установлено в `true`. Вы также можете заметить, что опция "Customize IP" теперь неактивна или позволяет только "Re-customize IP", которая затем предупреждает вас о блокировке. 4. **Разблокировка (при необходимости):** * Если вам потребуется внести дальнейшие изменения в настройки IP-ядра PCIe в будущем, вы должны сначала разблокировать его. Используйте следующую команду Tcl: ```tcl set_property -name {IP_LOCKED} -value false -objects [get_ips pcie_7x_0] ``` * Не забудьте снова заблокировать его после внесения и применения изменений. 5. **Задокументируйте действие:** * Хорошей практикой является отметить в документации вашего проекта (например, в файле README, заметках проекта), что IP-ядро PCIe было заблокировано. Это помогает любому, кто работает над проектом, понять его состояние конфигурации и избежать путаницы. --- ## **Часть 2: Промежуточные концепции и реализация** --- ## **8. Расширенная настройка прошивки** Для достижения точной и убедительной эмуляции устройства-донора необходима дальнейшая глубокая настройка прошивки FPGA, выходящая за рамки просто базовой идентификации. Это включает согласование параметров PCIe (таких как скорость канала и размеры транзакций), тщательную настройку базовых адресных регистров (BAR) и связанного с ними отображения памяти, а также точную эмуляцию управления питанием и механизмов прерываний. Эти шаги гарантируют, что эмулируемое устройство не только выглядит как оригинальное аппаратное обеспечение для хост-системы, но и ведет себя идентично на протокольном и функциональном уровнях. ### **8.1. Настройка параметров PCIe для эмуляции** Точная эмуляция требует, чтобы рабочие параметры PCIe вашего FPGA-устройства были тщательно настроены в соответствии с параметрами устройства-донора. Это включает такие настройки, как скорость канала PCIe, ширина канала, указатели возможностей и максимальные размеры полезной нагрузки. Правильная настройка обеспечивает совместимость с хост-системой, корректную работу драйверов и приложений, взаимодействующих с устройством, а также оптимальную производительность для передачи данных. #### **8.1.1. Согласование скорости и ширины канала PCIe** Скорость канала PCIe (например, Gen1, Gen2, Gen3) и ширина канала (например, x1, x4, x8) являются критически важными параметрами, которые определяют максимальную теоретическую пропускную способность и производительность устройства. Согласование этих настроек с устройством-донором необходимо для точной эмуляции, поскольку драйверы или системные компоненты могут ожидать определенных возможностей канала. **Шаги:** 1. **Доступ к настройкам IP-ядра PCIe:** * **Откройте ваш проект Vivado:** Запустите Vivado и откройте проект, который вы ранее создали или изменили (например, `pcileech_squirrel_top.xpr`). Убедитесь, что все исходные файлы правильно добавлены в проект. * **Найдите IP-ядро PCIe:** На панели **Sources** (обычно слева) разверните иерархию проекта, чтобы найти экземпляр IP-ядра PCIe. Для проектов Xilinx 7-й серии (например, Artix-7, используемой в Squirrel) он обычно называется `pcie_7x_0.xci`. * **Настройте IP-ядро:** Щелкните правой кнопкой мыши по `pcie_7x_0.xci` и выберите **Customize IP**. Откроется окно настройки IP, отображающее различные параметры конфигурации на нескольких вкладках. 2. **Установите максимальную скорость канала:** * **Перейдите к параметрам канала:** В окне настройки IP нажмите на вкладку **PCIe Capabilities** (или иногда "PCIe Configuration" или "General"). Внутри нее найдите раздел, связанный с **Link Parameters** или **Link Capability Register**. * **Настройте максимальную скорость канала:** Найдите опцию с надписью **Maximum Link Speed** (или "Target Link Speed"). * Установите ее в соответствии с максимальной скоростью канала, поддерживаемой и объявленной вашим устройством-донором. * **Пример:** * Если устройство-донор работает на **PCIe Gen2 (5.0 GT/s)**, выберите **5.0 GT/s**. * Если оно работает на **PCIe Gen1 (2.5 GT/s)** или **PCIe Gen3 (8.0 GT/s)**, выберите соответствующую опцию. * **Примечание**: Убедитесь, что трансиверы вашей FPGA и физическое оборудование (слот PCIe материнской платы) поддерживают выбранную скорость канала. FPGA будет согласовывать только до своей настроенной максимальной скорости. 3. **Установите ширину канала:** * **Настройте ширину канала:** В том же разделе **Link Parameters** найдите настройку **Link Width** (или "PCIe Link Width", "Target Link Width"). * Установите ее в соответствии с максимальной шириной канала, объявленной вашим устройством-донором. * **Пример:** * Если устройство-донор использует **x4** канал, установите **Link Width** в **4**. * Опции обычно включают **1**, **2**, **4**, **8**, **16** линий. * **Примечание**: Физический слот PCIe и корпус FPGA должны поддерживать выбранную ширину канала. Попытка настроить ширину, превышающую физическое соединение, приведет к проблемам с согласованием канала. 4. **Сохраните и регенерируйте:** * **Примените изменения:** После настройки скорости и ширины канала нажмите **OK**, чтобы применить изменения в окне настройки IP. * **Регенерация выходных продуктов IP:** Vivado, вероятно, предложит вам регенерировать выходные продукты IP-ядра из-за внесенных изменений. Подтвердите и дождитесь завершения процесса регенерации. Это может занять некоторое время. * **Проверьте настройки:** После завершения регенерации вы можете по желанию снова открыть настройки IP-ядра, чтобы убедиться, что конфигурации применены правильно. Проверьте окно **Messages** в Vivado на наличие предупреждений или ошибок. #### **8.1.2. Установка указателей возможностей** Указатели возможностей в пространстве конфигурации PCIe — это 8-битные регистры, образующие связанный список, указывающий на различные структуры возможностей (например, управление питанием, MSI/MSI-X, PCIe Express Capability). Правильная установка этих указателей гарантирует, что хост-система сможет пройти по списку возможностей, найти и использовать объявленные функции устройства. **Шаги:** 1. **Найдите указатель возможностей в прошивке:** * **Откройте файл конфигурации:** В Visual Studio Code откройте основной файл конфигурации для вашей платы, обычно `pcileech_pcie_cfg_a7.sv`, расположенный по адресу `pcileech-fpga//src/pcileech_pcie_cfg_a7.sv`. * **Поймите указатель возможностей:** Указатель возможностей (`cfg_cap_pointer`) в этом файле указывает на *первую* структуру возможностей в пространстве конфигурации PCIe, обычно начинающуюся после стандартного 64-байтового заголовка конфигурации. Последующие возможности связаны через поля "Next Capability Pointer". 2. **Установите значение указателя возможностей:** * **Найдите присвоение для `cfg_cap_pointer`:** Найдите строку в коде, где присваивается `cfg_cap_pointer`. ```verilog reg [7:0] cfg_cap_pointer = 8'hXX; // Текущее значение (например, 8'h40 по умолчанию) ``` * **Обновите указатель возможностей:** Замените `XX` на 8-битное шестнадцатеричное значение указателя возможностей, полученное от вашего устройства-донора с помощью Arbor. Это значение обычно указывает на смещение первой структуры возможностей после пространства конфигурации, специфичного для устройства (которое обычно заканчивается по смещению `0x3F`). Обычная отправная точка для возможностей — `0x40` или `0x60`. * **Пример:** * Если первый указатель возможностей устройства-донора равен `0x60` (что означает, что его первая структура возможностей начинается со смещения `0x60` в пространстве конфигурации), обновите строку следующим образом: ```verilog reg [7:0] cfg_cap_pointer = 8'h60; // Обновлено в соответствии со смещением первой возможности донора ``` * **Обеспечьте правильное выравнивание:** Структуры возможностей должны быть выровнены по 4-байтовой границе. Указатель возможностей всегда должен указывать на допустимое 4-байтовое выровненное смещение в пространстве конфигурации. 3. **Сохраните изменения:** * **Сохраните файл конфигурации:** После внесения изменений сохраните файл, нажав **File > Save** или `Ctrl + S`. * **Проверьте синтаксис:** Убедитесь, что изменения не привели к синтаксическим ошибкам (VS Code обычно подсвечивает их). * **Прокомментируйте для ясности:** Добавьте комментарий, объясняющий изменение, для будущих ссылок и удобства поддержки. ```verilog reg [7:0] cfg_cap_pointer = 8'h60; // Установлен указатель возможностей донора (например, PCIe Cap по 0x60) ``` #### **8.1.3. Настройка максимального размера полезной нагрузки и запроса на чтение** Эти параметры определяют максимальный объем данных, который может быть передан в одном пакете транспортного уровня PCIe (TLP), и максимальный размер непостированных TLP-запросов на чтение памяти. Согласование этих настроек с устройством-донором обеспечивает совместимость и оптимальную производительность для операций передачи данных. Несоответствия могут привести к снижению пропускной способности или ошибкам связи. **Шаги:** 1. **Установите максимально поддерживаемый размер полезной нагрузки (IP-ядро):** * **Доступ к возможностям устройства:** В окне настройки IP-ядра PCIe (`pcie_7x_0.xci` в Vivado) перейдите на вкладку **PCIe Capabilities**. * **Настройте Max Payload Size Supported:** Найдите настройку с надписью **Max Payload Size Supported** (или аналогичной). * Установите ее в значение, поддерживаемое и объявляемое вашим устройством-донором (например, 128 байт, 256 байт, 512 байт, 1024 байта, 2048 байт, 4096 байт). * **Пример:** Если устройство-донор поддерживает максимальный размер полезной нагрузки **256 байт**, выберите **256 bytes**. 2. **Установите максимально поддерживаемый размер запроса на чтение (IP-ядро):** * **Настройте Max Read Request Size Supported:** На той же вкладке найдите настройку **Max Read Request Size Supported**. * Установите ее в соответствии с возможностями устройства-донора. Это определяет максимальный объем данных, который устройство может запросить в одной транзакции чтения. * **Пример:** Если донор поддерживает максимальный размер запроса на чтение **512 байт**, выберите **512 bytes**. 3. **Настройка параметров прошивки (соответствие IP-ядру):** * **Откройте `pcileech_pcie_cfg_a7.sv`:** Убедитесь, что файл конфигурации открыт в Visual Studio Code. * **Обновите константы прошивки:** Найдите строки, где определены `max_payload_size_supported` и `max_read_request_size_supported`. Обычно это битовое кодирование значений, которые соответствуют размерам в байтах, выбранным вами в IP-ядре. ```verilog reg [2:0] max_payload_size_supported = 3'bZZZ; // Текущее значение reg [2:0] max_read_request_size_supported = 3'bWWW; // Текущее значение ``` * **Установите соответствующие значения:** Замените `ZZZ` и `WWW` на 3-битные двоичные представления, соответствующие выбранным размерам. * **Сопоставление (согласно спецификации PCIe):** * **128 байт**: `3'b000` * **256 байт**: `3'b001` * **512 байт**: `3'b010` * **1024 байт**: `3'b011` * **2048 байт**: `3'b100` * **4096 байт**: `3'b101` * **Пример:** * Для размера полезной нагрузки **256 байт**: ```verilog reg [2:0] max_payload_size_supported = 3'b001; // Поддерживает до 256 байт (0x100) ``` * Для размера запроса на чтение **512 байт**: ```verilog reg [2:0] max_read_request_size_supported = 3'b010; // Поддерживает до 512 байт (0x200) ``` * **Обоснование**: Эти параметры прошивки часто определяют поведение вашей пользовательской логики, которая взаимодействует с ядром PCIe, гарантируя, что ваша логика соблюдает настроенные максимумы. 4. **Сохраните изменения:** * **Сохраните файл:** После обновления значений в `pcileech_pcie_cfg_a7.sv` сохраните файл. * **Проверьте согласованность:** Крайне важно, чтобы значения, настроенные в графическом интерфейсе IP-ядра PCIe Vivado, *совпадали* со значениями, установленными в вашем файле конфигурации HDL. Любое несоответствие может привести к неожиданному поведению или проблемам с обучением канала. * **Добавьте комментарии:** Четко задокументируйте эти изменения в своем коде для будущих ссылок. ### **8.2. Настройка БАР и отображения памяти** Базовые адресные регистры (BAR) являются фундаментальными для того, как устройство PCIe предоставляет свою внутреннюю память и регистры хост-системе. Правильная настройка BAR и определение их отображения памяти в БПА (блочной памяти) вашей FPGA и логике имеет решающее значение для точной эмуляции и правильной работы драйверов устройств на стороне хоста. #### **8.2.1. Установка размеров и типов BAR (IP-ядро и BRAM)** Настройка размеров и типов BAR гарантирует, что ваше эмулируемое устройство запрашивает правильный объем адресного пространства у хоста во время перечисления и что хост выделяет и отображает эти области соответствующим образом. Это также включает связывание этих адресных областей с физическими блоками памяти внутри вашей FPGA. **Шаги:** 1. **Доступ к конфигурации BAR (IP-ядро PCIe):** * **Настройте IP-ядро PCIe:** В Vivado щелкните правой кнопкой мыши по `pcie_7x_0.xci` и выберите **Customize IP**, чтобы открыть его графический интерфейс конфигурации. * **Перейдите на вкладку BARs:** В окне настройки IP нажмите на вкладку **Base Address Registers (BARs)**. 2. **Настройте каждый BAR (IP-ядро):** * **Согласуйте BARы устройства-донора:** Для каждого BAR (BAR0 до BAR5) установите размер, тип и статус prefetchable, чтобы они точно соответствовали тому, что вы извлекли из устройства-донора с помощью Arbor. * **Включение/отключение BAR:** Убедитесь, что включены только те BARы, которые фактически используются устройством-донором. Отключите (снимите флажок) любые неиспользуемые BARы. * **Установка размеров BAR:** Выберите соответствующий размер из выпадающего списка для каждого *включенного* BAR. Это будет степень двойки (например, 4КБ, 8КБ, 64КБ, 1МБ, 256МБ, 1ГБ). * **Пример:** * Если **BAR0** равен **64 КБ**, установите **BAR0 Size** в **64 KB**. * Если **BAR1** равен **128 МБ**, установите **BAR1 Size** в **128 MB**. * **Установка типов BAR:** * Выберите между **Memory (32-bit Addressing)** или **Memory (64-bit Addressing)**, если BAR отображается на память. Выберите **64-bit Addressing**, если BAR устройства-донора 64-битный или если вам нужен доступ к адресам выше 4 ГБ. * Выберите **I/O**, если BAR предназначен для адресного пространства портов ввода-вывода (менее распространено для современных устройств PCIe). * **Установите статус Prefetchable**: Установите флажок "Prefetchable", если BAR донора был идентифицирован как prefetchable. Этот бит позволяет хосту предвыбирать данные из этой области, потенциально повышая производительность. 3. **Обновление конфигураций BRAM (если применимо):** * Многие проекты PCILeech-FPGA используют IP-ядра Xilinx Block RAM (BRAM) для представления областей памяти, предоставляемых BAR. Эти BRAM обеспечивают физическое хранилище для памяти вашего эмулируемого устройства. * **Найдите IP-ядра BRAM:** В панели **Sources** вашего проекта Vivado, в подкаталоге `ip` (или аналогичном), вы можете найти файлы `.xci` для BRAM, потенциально названные так: ``` pcileech-fpga//ip/bram_bar_zero4k.xci pcileech-fpga//ip/bram_pcie_cfgspace.xci # И, возможно, другие для BAR1, BAR2 и т.д. ``` * **Изменение размеров BRAM:** Для каждого IP-ядра BRAM, связанного с *включенным* BAR, вам может потребоваться **Customize IP** (щелкните правой кнопкой мыши по файлу `.xci`) и настроить его конфигурацию размера памяти, чтобы она точно соответствовала соответствующему размеру BAR, который вы установили в IP-ядре PCIe. * **Пример:** Если BAR0 равен 256 МБ, убедитесь, что BRAM, подключенный к BAR0, имеет размер 256 МБ. * **Внимание**: Убедитесь, что общий объем памяти, требуемый всеми активными BAR, не превышает физическую емкость BRAM вашего FPGA-устройства. Превышение емкости приведет к ошибкам реализации. 4. **Сохраните и регенерируйте:** * **Примените изменения (IP-ядро):** После настройки BAR в IP-ядре PCIe нажмите **OK** в окне настройки IP. * **Регенерация IP-ядер:** Vivado предложит вам регенерировать IP-ядро PCIe и любые связанные IP-ядра BRAM из-за изменений размера. Дождитесь завершения регенерации. Это гарантирует, что аппаратный список соединений отражает ваши новые определения BAR. * **Проверьте на ошибки:** Просмотрите окно **Messages** на наличие любых предупреждений или ошибок, связанных с конфигурацией BAR или экземплярами BRAM. #### **8.2.2. Определение адресных пространств BAR в прошивке** В то время как IP-ядро PCIe конфигурирует *аппаратные* аспекты BAR, ваша пользовательская прошивка (код SystemVerilog) должна определять *логику* того, как ваше эмулируемое устройство реагирует, когда хост-ЦП выполняет операции чтения или записи по адресам в этих областях BAR. Это включает декодирование адресов и реализацию логики доступа к регистрам/памяти. **Шаги:** 1. **Откройте файл контроллера BAR:** * В Visual Studio Code откройте файл SystemVerilog, отвечающий за обработку доступов к BAR. Для PCILeech-FPGA это часто: ``` pcileech-fpga//src/pcileech_tlps128_bar_controller.sv ``` Этот модуль обычно принимает TLP-пакеты чтения/записи памяти PCIe и декодирует адрес, чтобы определить, какой BAR (и какое смещение внутри этого BAR) доступно. 2. **Реализуйте логику декодирования адресов:** * Внутри модуля `pcileech_tlps128_bar_controller.sv` вы найдете логику, которая определяет, какой BAR является целью входящей транзакции. Это часто включает проверку битов адреса относительно настроенных размеров BAR. * Вам нужно будет определить, как входящий адрес `req_addr` (из TLP) отображается на смещение внутри вашего конкретного BAR. * **Концептуальный пример:** ```verilog // Пример: Логика для BAR0 (предполагается, что это 256 МБ 64-битный BAR памяти, для регистров/данных) // 'bar_hit[0]' будет входным сигналом, указывающим на попадание в BAR0, обычно от ядра PCIe. // 'req_addr' - это входящий адрес PCIe. // 'req_be' - это байтовое разрешение из TLP. // 'req_data' - это входящие данные для записи. // 'rsp_data' - это исходящие данные для чтения. // Предположим, что BAR0 составляет 256 МБ (2^28 байт), биты адреса [27:0] находятся в BAR. localparam BAR0_SIZE_BITS = 28; // 2^28 = 256 МБ reg [31:0] internal_register_0; // Пример регистра внутри BAR0 reg [31:0] internal_register_1; // Другой пример регистра assign bar0_offset = req_addr[BAR0_SIZE_BITS-1:0]; // Извлечение смещения внутри BAR0 always_comb begin // Ответ по умолчанию rsp_data = 32'hFFFFFFFF; // По умолчанию все F's или аналогичное для не отображенных областей if (bar_hit[0]) begin // Если транзакция нацелена на BAR0 if (req_write) begin // Это операция записи case (bar0_offset) // Пример: Отображение смещения 0x0 на internal_register_0 32'h0000_0000: begin if (req_be[3]) internal_register_0[31:24] = req_data[31:24]; if (req_be[2]) internal_register_0[23:16] = req_data[23:16]; if (req_be[1]) internal_register_0[15:8] = req_data[15:8]; if (req_be[0]) internal_register_0[7:0] = req_data[7:0]; end // Пример: Отображение смещения 0x4 на internal_register_1 32'h0000_0004: begin if (req_be[3]) internal_register_1[31:24] = req_data[31:24]; if (req_be[2]) internal_register_1[23:16] = req_data[23:16]; if (req_be[1]) internal_register_1[15:8] = req_data[15:8]; if (req_be[0]) internal_register_1[7:0] = req_data[7:0]; end // Добавьте больше сопоставлений регистров или доступов к памяти (например, доступ к BRAM) default: begin // Обработка не отображенных записей внутри BAR0, например, игнорировать или логировать end endcase end else if (req_read) begin // Это операция чтения case (bar0_offset) // Пример: Чтение из internal_register_0 32'h0000_0000: rsp_data = internal_register_0; // Пример: Чтение из internal_register_1 32'h0000_0004: rsp_data = internal_register_1; // Добавьте больше сопоставлений регистров или доступов к памяти (например, доступ к BRAM) default: begin rsp_data = 32'h0; // Возвращаем 0 для не отображенных чтений или специальное значение ошибки end endcase end end end ``` * **Обработка передачи данных:** Блок `always_comb` (или `always_ff` для последовательной логики) должен определять, как генерируется `rsp_data` для чтений и как обновляются внутренние регистры/память для записей, на основе `bar0_offset` и байтовых разрешений (`req_be`). 3. **Реализуйте доступы к BRAM (если BAR отображается на BRAM):** * Если BAR отображается на большой блок памяти (например, 256 МБ), вы обычно создаете экземпляр IP-ядра BRAM (как обсуждалось в 8.2.1) и подключаете к нему логику вашего `bar_controller`. `bar_controller` будет предоставлять адрес и управляющие сигналы BRAM. * **Концептуальная интеграция BRAM (упрощенная):** ```verilog // Внутри pcileech_tlps128_bar_controller.sv или подмодуля // Интерфейс к BRAM wire [BAR0_SIZE_BITS-1:0] bram_addr; wire [31:0] bram_wr_data; wire [3:0] bram_wr_en; // Байтовые разрешения для BRAM wire bram_wr_ce; wire bram_rd_ce; wire [31:0] bram_rd_data; // Сопоставление сигналов TLP с интерфейсом BRAM assign bram_addr = bar0_offset; assign bram_wr_data = req_data; assign bram_wr_en = req_be; assign bram_wr_ce = bar_hit[0] && req_write; assign bram_rd_ce = bar_hit[0] && req_read; // Создание экземпляра IP-ядра BRAM bram_bar_zero bram_inst ( // Предполагается, что 'bram_bar_zero' - это ваш модуль BRAM IP .clka(clk), .ena(1'b1), .wea(bram_wr_en), .addra(bram_addr), .dina(bram_wr_data), .douta(bram_rd_data) ); // Для чтения из BAR0, вывод данных из BRAM if (bar_hit[0] && req_read) begin rsp_data = bram_rd_data; end ``` 4. **Сохраните изменения:** * После реализации логики для каждого BAR сохраните файл `pcileech_tlps128_bar_controller.sv`. * **Проверка функциональности:** Эта логика сложна. Тщательная симуляция (с использованием тестового стенда) и последующее аппаратное тестирование будут иметь решающее значение для обеспечения правильного поведения. #### **8.2.3. Обработка нескольких BAR** Правильное управление несколькими BAR необходимо для устройств, которые предоставляют несколько различных областей памяти или ввода-вывода. Модуль `bar_controller` обычно обрабатывает все BAR. **Шаги:** 1. **Реализуйте логику для каждого BAR:** * Внутри `pcileech_tlps128_bar_controller.sv` расширьте логику для обработки всех включенных BAR (BAR0, BAR1, BAR2 и т.д.), которые использует ваше устройство-донор. * **Раздельные блоки логики:** Для ясности и удобства поддержки создавайте отдельные блоки `if/else if` или операторы `case`, которые активируются в зависимости от того, какой сигнал `bar_hit` активен. ```verilog // Обработка BAR0 if (bar_hit[0]) begin // Логика чтения/записи, специфичная для BAR0, для его регистров/памяти end else if (bar_hit[1]) begin // Логика чтения/записи, специфичная для BAR1, для его регистров/памяти end else if (bar_hit[2]) begin // Логика, специфичная для BAR2 end // ... продолжайте для других BAR ``` * **Определите регистры и память:** Выделите отдельные наборы регистров или подключите отдельные экземпляры BRAM для каждого BAR по мере необходимости. 2. **Обеспечьте отсутствие перекрывающихся адресных пространств:** * Хотя IP-ядро PCIe обрабатывает согласование различных адресных пространств для каждого BAR с ОС хоста, ваша внутренняя логика прошивки *должна* предполагать, что эти пространства являются раздельными и неперекрывающимися. * **Проверка диапазонов адресов**: Дважды проверьте конфигурации размеров BAR в IP-ядре PCIe, чтобы убедиться, что они являются дискретными и правильно выровнены по степеням двойки в соответствии со спецификациями PCIe. * **Обновление декодирования адресов**: Логика вашего `bar_controller` полагается на сигналы `bar_hit`, генерируемые IP-ядром PCIe. Убедитесь, что они правильно интерпретируются и приводят к уникальной логике обработки для каждого BAR. 3. **Тестирование доступов к BAR:** * **Имитационное тестирование:** Перед развертыванием оборудования используйте инструменты имитации (например, Vivado Simulator) с всеобъемлющим тестовым стендом для проверки всех операций чтения и записи для каждого BAR. * Отправьте TLP-пакеты записи в память по определенным смещениям внутри каждого BAR. * Отправьте TLP-пакеты чтения памяти по определенным смещениям внутри каждого BAR и проверьте возвращенные данные. * **Аппаратное тестирование:** После программирования FPGA используйте программные инструменты на стороне хоста (такие как клиентское ПО PCILeech или пользовательские скрипты на C/Python) для доступа и проверки каждого BAR. * **Linux**: Используйте `lspci -vvv` для проверки отображений BAR (`Memory at XXXX (64-bit, prefetchable) [size=YYYY]`). Затем вы можете использовать `devmem2` или пользовательский модуль ядра для чтения/записи по этим отображенным адресам. * **Windows**: Используйте такие инструменты, как "RW-Everything" или пользовательские приложения, для проверки и взаимодействия с отображенными областями памяти. * Выполняйте различные шаблоны чтения/записи, чтобы обеспечить целостность данных и правильную адресацию по всем BAR. --- ### **8.3. Эмуляция управления питанием устройства и прерываний** Эмуляция функций управления питанием и реализация прерываний критически важны для устройств, которым необходимо тесно и эффективно взаимодействовать с механизмами управления питанием и обработки прерываний операционной системы хоста. Без них эмулируемое устройство может не выглядеть полностью функциональным, или производительность может быть субоптимальной. #### **8.3.1. Конфигурация управления питанием** Реализация управления питанием позволяет эмулируемому устройству поддерживать различные состояния питания (например, D0, D3hot), способствуя общей энергоэффективности системы и соответствию ожиданиям операционной системы. ОС хоста будет запрашивать возможности устройства и отправлять команды для перехода между этими состояниями. **Шаги:** 1. **Включите управление питанием в IP-ядре PCIe:** * **Доступ к возможностям:** В окне настройки IP-ядра PCIe (`pcie_7x_0.xci`) перейдите на вкладку **PCIe Capabilities**. * **Включите управление питанием:** Найдите раздел или опцию, связанную с **Power Management Capability**. Убедитесь, что она отмечена или включена, чтобы включить структуру возможностей управления питанием (PM) в пространство конфигурации устройства. 2. **Установите поддерживаемые состояния питания:** * **Настройте поддерживаемые состояния:** В разделе возможностей управления питанием IP-ядра укажите, какие состояния питания поддерживает устройство. Обычно это флажки или выпадающие списки. Согласуйте эти настройки с возможностями устройства-донора, как это было замечено Arbor. * **D0 (Полностью включено/работоспособно)**: Всегда поддерживается. * **D1, D2 (Промежуточные состояния)**: Необязательные, для состояний низкого энергопотребления в режиме ожидания. * **D3hot (Выключено, вспомогательное питание присутствует)**: Логика устройства выключена, но может отвечать на события PM. * **D3cold (Выключено полностью)**: Питание на устройство не подается. * **Пример**: Если устройство-донор поддерживает только D0 и D3hot, включите только их. 3. **Реализуйте логику состояний питания в прошивке:** * **Откройте `pcileech_pcie_cfg_a7.sv` (или соответствующий модуль управления):** Вам обычно потребуется изменить прошивку, чтобы она отражала и потенциально реагировала на переходы состояний питания, управляемые хостом. Само ядро PCIe обрабатывает большую часть протокола, но ваша пользовательская логика должна знать состояние. * **Обработка записей в регистр управления и состояния управления питанием (PMCSR):** ОС хоста изменяет состояние питания устройства, записывая данные в определенные биты PMCSR, который является частью структуры возможностей PM. Ваша прошивка должна иметь логику для чтения этих битов и соответствующей настройки поведения устройства (например, приостановка/возобновления операций, включение/отключение тактовых сигналов). ```verilog // Пример: Часть pcileech_pcie_cfg_a7.sv или выделенный модуль PM // Предположим, что 'cfg_write' активен для записей конфигурации, 'cfg_address' - смещение, 'cfg_writedata' - данные. // Биты D-состояния находятся по смещению 0x04 внутри структуры возможностей PM, биты [1:0]. // Регистр PMCSR (внутреннее представление) reg [15:0] pmcsr_reg = 16'h0000; // Инициализация в D0 // Сигнал пользовательской логики, указывающий на текущее состояние питания reg [1:0] current_d_state = 2'b00; // 00 = D0, 01 = D1, 10 = D2, 11 = D3hot always @(posedge clk) begin if (reset) begin pmcsr_reg <= 16'h0000; current_d_state <= 2'b00; // Сброс в D0 end else begin // Пример: Захват записей в PMCSR (если обрабатывается непосредственно в пользовательской логике) // Примечание: Ядро PCIe управляет большей частью этого, но вашей пользовательской логике может потребоваться считывать значения из него. // Предположим, что ядро PCIe предоставляет выход, отражающий текущее D-состояние: // assign current_d_state = pcie_core_d_state_output; // Если пользовательская логика *нуждается* в записи в PMCSR (менее распространено, обычно только для чтения статуса) // Или если ей нужно обработать команду // if (cfg_write && (cfg_address == PM_CAP_OFFSET + 2'h04)) begin // PMCSR находится по +0x04 от базового адреса PM Cap // pmcsr_reg[1:0] <= cfg_writedata[1:0]; // Захват нового D-состояния // // current_d_state <= cfg_writedata[1:0]; // Обновление внутреннего состояния // end // В PCILeech ядро PCIe управляет PMCSR. Вы, вероятно, будете считывать сигнал из ядра. // Для демонстрации предположим, что 'pcie_d_state' - это вход из IP-ядра. current_d_state <= pcie_d_state; // Обновление на основе статуса ядра PCIe end end // Пример: Логика, реагирующая на изменения D-состояния always @(*) begin if (current_d_state == 2'b11) begin // Состояние D3hot // Отключить питание второстепенных блоков, приостановить операции, // активировать сигнал для основной логики DMA для остановки активности. // Например: dma_engine_enable = 1'b0; end else if (current_d_state == 2'b00) begin // Состояние D0 // Включить полную функциональность // Например: dma_engine_enable = 1'b1; end end ``` * **Управление эффектами состояния питания:** Реализуйте логику для изменения внутреннего поведения устройства (например, включение/отключение тактовых сигналов, перевод подмодулей в режимы низкого энергопотребления) на основе `current_d_state`. Это имеет решающее значение для точной эмуляции энергопотребления и обеспечения правильной реакции устройства на команды ОС. 4. **Сохраните изменения:** * Сохраните все измененные файлы прошивки. * Тщательно протестируйте функции управления питанием с помощью симуляции или аппаратного тестирования (например, функции "Сон" или "Гибернация" Windows, или команды Linux `poweroff`, чтобы увидеть, правильно ли устройство переходит в эти состояния). #### **8.3.2. Конфигурация MSI/MSI-X** Реализация прерываний, генерируемых сообщениями (MSI), или их расширенной версии (MSI-X) позволяет эмулируемому устройству использовать прерывания на основе сообщений. Они значительно более эффективны и масштабируемы, чем традиционные прерывания на основе контактов (INTx), и являются предпочтительным методом для современных устройств PCIe. MSI/MSI-X позволяют устройству уведомлять ЦП, записывая специальный TLP-пакет в определенный адрес памяти. **Шаги:** 1. **Включите MSI/MSI-X в IP-ядре PCIe:** * **Доступ к конфигурации прерываний:** В окне настройки IP-ядра PCIe (`pcie_7x_0.xci`) перейдите на вкладку **Interrupts** или в раздел, специально помеченный **MSI/MSI-X Capabilities**. * **Выберите тип прерывания:** Выберите **MSI** или **MSI-X** на основе возможностей устройства-донора. MSI-X обычно предпочтительнее из-за его гибкости (больше векторов, маскирование каждого вектора). * **Настройте количество поддерживаемых векторов:** Установите количество векторов прерываний (сообщений), которое будет поддерживать устройство. Согласуйте это с устройством-донором. * **MSI** поддерживает до 32 векторов (обычно 1, 2, 4, 8, 16 или 32). * **MSI-X** поддерживает до 2048 векторов, что позволяет более детально определять источники прерываний. * **Включите возможности:** Убедитесь, что структура возможностей MSI или MSI-X явно включена для включения в пространство конфигурации устройства. Именно так ОС хоста обнаруживает возможности прерываний устройства. 2. **Реализуйте логику прерываний в прошивке:** * **Откройте `pcileech_pcie_tlp_a7.sv` (или модуль пользовательской логики):** Этот файл обычно отвечает за генерацию TLP-папакетов, определяемых пользователем, и может быть подходящим местом для инициации сообщений MSI/MSI-X. Однако *триггер* прерывания будет исходить от вашей пользовательской логики. * **Определите сигналы прерываний:** Объявите внутренние сигналы, которые будут указывать, когда необходимо сгенерировать прерывание. ```verilog // В пользовательском модуле (например, 'my_device_logic.sv'), который взаимодействует с логикой генерации TLP reg msi_trigger_signal; // Установите его, когда возникает условие прерывания ``` * **Реализуйте логику генерации прерываний:** Определите условия, при которых должно быть вызвано прерывание. Обычно это включает обнаружение событий внутри логики вашего эмулируемого устройства. ```verilog // Внутри 'my_device_logic.sv' input wire clk; input wire reset; input wire event_data_ready; // Пример: Входной сигнал от вашей логики, когда данные готовы always @(posedge clk or posedge reset) begin if (reset) begin msi_trigger_signal <= 1'b0; end else if (event_data_ready) begin // Когда происходит определенное событие msi_trigger_signal <= 1'b1; // Вызвать MSI end else begin msi_trigger_signal <= 1'b0; // Сбросить после одного цикла или при подтверждении end end ``` * **Подключение к интерфейсу MSI ядра PCIe:** Сигнал `msi_trigger_signal` (или аналогичный выход от вашей пользовательской логики) должен быть подключен к соответствующему входу IP-ядра PCIe (например, `s_axis_tdata_tready`, `s_axis_tdata_tvalid`, `s_axis_tdata_tlast`, если используется интерфейс AXI-Stream для MSI TLP-пакетов, или выделенные порты запросов MSI, предоставляемые IP-ядром). Затем ядро PCIe формирует и отправляет фактический TLP-пакет MSI/MSI-X. Обратитесь к документации IP-ядра Xilinx PCIe для получения точных сведений об интерфейсе. 3. **Сохраните изменения:** * Сохраните все измененные файлы прошивки после реализации логики прерываний. * **Проверка временных ограничений:** Новая логика, особенно пути прерываний, может быть критичной ко времени. Убедитесь, что инструменты синтеза и реализации не сообщают о каких-либо нарушениях временных ограничений, связанных с вашей логикой генерации прерываний. #### **8.3.3. Реализация логики обработки прерываний (на стороне устройства)** Помимо простого включения возможности, определение *когда* и *как* прерывания генерируются вашим эмулируемым устройством, имеет решающее значение для его правильного взаимодействия с механизмами обработки прерываний хоста и поведением драйверов. Это включает создание внутренней логики, которая активирует запрос на прерывание. **Шаги:** 1. **Определите условия прерывания:** * **Определите события-триггеры:** Основываясь на поведении вашего устройства-донора, определите конкретные внутренние события, которые должны вызывать прерывание вашим эмулируемым устройством. * **Примеры**: Завершение передачи данных, готовность новых данных в буфере приема, внутреннее состояние ошибки, завершение конкретной команды, изменение состояния канала. * **Реализуйте логику условий:** Используйте комбинационную или последовательную логику в ваших пользовательских модулях SystemVerilog для точного обнаружения этих событий и генерации короткого импульса или сигнала на основе уровня, который указывает на запрос прерывания. 2. **Создайте модуль генерации прерываний (модульный дизайн):** * Хорошей практикой является инкапсуляция логики генерации прерываний в отдельный, выделенный модуль для ясности, повторного использования и облегчения отладки. Этот модуль будет принимать внутренние события в качестве входных данных и выдавать выходной сигнал `msi_req` (или аналогичный), который подключается к ядру PCIe. ```verilog // Файл: interrupt_generator.sv module interrupt_generator ( input wire clk, input wire reset, input wire event_trigger, // Входной сигнал от вашей пользовательской логики (например, data_ready, error_flag) output reg msi_req_o // Выход: Активировать для запроса MSI/MSI-X ); // Простой генератор импульсов для MSI (однократное прерывание) reg event_trigger_d1; always @(posedge clk or posedge reset) begin if (reset) begin msi_req_o <= 1'b0; event_trigger_d1 <= 1'b0; end else begin event_trigger_d1 <= event_trigger; // Генерируем одноцикловый импульс, когда event_trigger переходит в высокий уровень if (event_trigger && !event_trigger_d1) begin msi_req_o <= 1'b1; // Активируем запрос MSI end else begin msi_req_o <= 1'b0; // Деактивируем после одного цикла end end end endmodule // interrupt_generator ``` * **Интеграция с основной прошивкой:** Создайте экземпляр этого модуля `interrupt_generator` в вашей высокоуровневой пользовательской логике (например, в `pcileech_squirrel_top.sv` или в модуле, который он инстанциирует) и подключите его выход `msi_req_o` к входу MSI IP-ядра PCIe. 3. **Обеспечьте правильную синхронизацию и последовательность:** * **Соблюдайте спецификации PCIe:** Сообщения MSI/MSI-X являются TLP-пакетами. Убедитесь, что генерация этих сообщений соответствует формату TLP PCIe, управлению потоком и временным требованиям. IP-ядро PCIe обрабатывает большую часть этого, но ваши входные сигналы к нему должны быть стабильными и правильно синхронизированными. * **Управление задержкой прерывания:** Оптимизируйте свою логику, чтобы минимизировать любые ненужные задержки между возникновением внутреннего события и активацией сигнала `msi_req_o`. 4. **Протестируйте доставку прерываний:** * **Симуляция:** Используйте комплексный тестовый стенд для имитации сценариев, в которых должны генерироваться прерывания. Убедитесь, что ваш сигнал `msi_req_o` ведет себя ожидаемым образом и что ядро PCIe генерирует правильные TLP-пакеты MSI/MSI-X. * **Аппаратное тестирование:** * Прошейте FPGA обновленной прошивкой. * Используйте программное обеспечение на стороне хоста для запуска событий, которые должны вызывать прерывание (например, инициирование передачи DMA, которая завершается). * Подтвердите, что прерывания получены операционной системой хоста. В Linux `dmesg` может показывать сообщения прерываний. В Windows вы можете использовать специальные инструменты отладки драйверов или Просмотр событий. * **Инструменты отладки:** Используйте встроенные логические анализаторы (ILA) Vivado (как будет обсуждаться далее в Разделе 12) для мониторинга `event_trigger`, `msi_req_o` и выходных сигналов TLP ядра PCIe в реальном времени, чтобы проверить правильность генерации прерываний. 5. **Сохраните изменения:** * Завершите все изменения кода и сохраните соответствующие файлы прошивки. * Просмотрите и доработайте логику прерываний на основе результатов тестирования, чтобы обеспечить надежность. --- ## **9. Эмуляция специфических возможностей устройства** Помимо стандартного пространства конфигурации PCIe и общей функциональности DMA, многие устройства-доноры обладают уникальными возможностями, пользовательскими регистрами или функциями, специфичными для поставщика, которые критически важны для их полной функциональности или для взаимодействия с их проприетарными драйверами. Точная эмуляция требует понимания и воспроизведения этих нюансов. В этом разделе рассматривается реализация таких расширенных возможностей, что позволяет добиться более точной и полнофункциональной эмуляции. ### **9.1. Реализация расширенных возможностей PCIe** Спецификация PCIe включает различные *расширенные возможности* помимо базового пространства конфигурации. Эти возможности предоставляют такие функции, как расширенная отчетность об ошибках, управление питанием, виртуализация и многое другое. Их реализация помогает вашему эмулируемому устройству выглядеть более легитимно и корректно взаимодействовать с современными хост-системами. **Шаги:** 1. **Определите требуемые расширенные возможности:** * При сборе информации об устройстве-доноре с помощью таких инструментов, как Arbor, тщательно ищите и документируйте любые расширенные возможности, присутствующие в пространстве конфигурации донора. Они обычно находятся за пределами первоначальных 256 байтов стандартного пространства конфигурации. * **Распространенные примеры:** * **Расширенная отчетность об ошибках (AER)**: Обеспечивает надежные механизмы обнаружения, регистрации и отчетности об ошибках для каналов PCIe. * **Серийный номер устройства (DSN)**: (Уже рассмотрено в Разделе 6.2). * **Управление питанием (PM)**: (Уже рассмотрено в Разделе 8.3.1). * **Структура возможностей PCI Express (PCIe)**: (Уже рассмотрено в Разделе 8.1 для скорости/ширины канала, максимальной полезной нагрузки/запроса на чтение, но также включает другие поля, такие как Device Control/Status, Link Control/Status). * **Виртуальный канал (VC)/Многофункциональный виртуальный канал (MFVC)**: Для качества обслуживания (QoS) и управления трафиком. * **Точное измерение времени (PTM)**: Для синхронизации времени между устройствами. * **Отчетность о задержках (LTR)**: Для управления питанием на основе требований к задержкам. * **Сбрасываемый FPC (сброс на уровне функции)**: Для более гранулированных сбросов. 2. **Включите возможности в IP-ядре PCIe Vivado:** * Получите доступ к окну настройки IP-ядра PCIe (`pcie_7x_0.xci`) в Vivado. * Перейдите по различным вкладкам (например, "PCIe Capabilities", "Extended Capabilities", "Advanced Options"). * Ищите флажки или выпадающие списки для включения и настройки конкретных расширенных возможностей, идентифицированных у вашего устройства-донора. * **Пример (AER):** Вы найдете раздел "Advanced Error Reporting", где вы можете включить его и настроить его регистры (например, маски серьезности). * **Примечание:** IP-ядро Xilinx PCIe обеспечивает высокую степень настраиваемости для многих стандартных и расширенных возможностей. Часто это просто вопрос включения правильных опций в графическом интерфейсе. 3. **Реализуйте логику прошивки для регистров возможностей (при необходимости):** * Хотя IP-ядро PCIe обрабатывает *присутствие* и большую часть *протокола* для этих возможностей, некоторые возможности предоставляют регистры, которые вашей пользовательской прошивке может потребоваться читать или записывать, или на значения которых вашей прошивке нужно реагировать. * **Пример (AER):** Если ваше эмулируемое устройство обнаруживает внутреннюю ошибку, которую следует сообщить через AER, вашей прошивке необходимо записать данные в конкретные регистры состояния ошибок AER (которые могут быть представлены как часть BAR или обрабатываться внутренне ядром PCIe, а затем отражаться в пользовательской логике). Ваша пользовательская логика затем активирует вход ошибки для ядра PCIe. * **Пример (Управление питанием):** Как обсуждалось в 8.3.1, вашей прошивке необходимо реагировать на изменения D-состояния, сигнализируемые ядром PCIe. * **Процесс:** * Определите конкретные регистры в каждой включенной структуре возможностей, с которыми взаимодействует драйвер вашего устройства-донора. * Найдите соответствующие сигналы или логику в рамках PCILeech-FPGA, которые взаимодействуют с этими регистрами (часто в `pcileech_pcie_cfg_a7.sv` или `bar_controller`). * Реализуйте логику чтения/записи для этих регистров, убедившись, что внутреннее состояние вашего эмулируемого устройства точно отражает значения, которые ожидает драйвер. ### **9.2. Эмуляция функций, специфичных для поставщика** Здесь начинается истинная "полная эмуляция устройства", которая становится высокоспециализированной. Многие реальные устройства имеют уникальные регистры, недокументированные команды, пользовательские форматы данных или проприетарные потоки управления, которые отличают их. Воспроизведение этих нюансов требует более глубокого анализа и пользовательской разработки HDL. **Шаги:** 1. **Обратный инжиниринг поведения, специфичного для поставщика:** * Это часто самая сложная часть. * **Статический анализ (драйвер/прошивка):** Дизассемблируйте официальный драйвер устройства-донора (Windows `.sys`, Linux `.ko`) или оригинальную прошивку устройства (если доступна). Ищите уникальные шаблоны доступа к вводу-выводу или MMIO, "магические" значения или последовательности записей в регистры. Такие инструменты, как Ghidra, IDA Pro или objdump, могут быть бесценны. * **Динамический анализ (выполнение драйвера):** Запустите устройство-донор с его драйвером и отслеживайте трафик PCIe с помощью **анализатора протокола PCIe** (например, Teledyne LeCroy, Keysight, как обсуждается в Разделе 12.2). Это золотой стандарт для понимания фактических обменов TLP, включая сообщения, определяемые поставщиком, и последовательности доступов к регистрам. Обратите внимание на: * Конкретные адреса памяти, к которым осуществляется доступ в BAR. * Шаблоны чтения/записи по этим адресам. * Значения, записываемые в конкретные регистры или считываемые из них. * Временные зависимости между командами и ответами. * **Мониторинг системных вызовов/API**: На хосте используйте такие инструменты, как Procmon (Windows) или `strace` (Linux), чтобы увидеть, как драйвер взаимодействует с ОС и какие конкретные коды управления вводом-выводом устройства (IOCTL) он использует, которые могут соответствовать конкретным аппаратным операциям. * **Аппаратное перехватывание (Hardware Sniffing)**: Если возможно, используйте аппаратный сниффер (например, Saleae Logic Analyzer) для захвата сигналов на внутренних шинах устройства (например, SPI, I2C), если у него есть внешняя флэш-память или компоненты. 2. **Реализация пользовательских регистров и логики в BAR:** * Как только вы определили регистры, специфичные для поставщика, или командные протоколы, вам нужно будет определить их в вашей прошивке FPGA, обычно как регистры, отображаемые на память, доступные через один из ваших BAR. * **Создайте внутренние регистры:** Объявите переменные `reg` в вашем коде SystemVerilog для представления этих пользовательских регистров. ```verilog // В вашем pcileech_tlps128_bar_controller.sv или подмодуле reg [31:0] custom_control_reg; reg [31:0] custom_status_reg; reg [31:0] custom_data_reg; // Пример: Сопоставьте их с конкретными смещениями в BAR0 (предполагая, что BAR0 достаточно большой) // Измените оператор case 'bar0_offset' (из раздела 8.2.2) // ... if (bar_hit[0]) begin if (req_write) begin case (bar0_offset) 32'h0000_1000: custom_control_reg <= req_data; // Пользовательский управляющий регистр 32'h0000_1004: custom_data_reg <= req_data; // Пользовательский регистр записи данных // ... другие сопоставления endcase end else if (req_read) begin case (bar0_offset) 32'h0000_1000: rsp_data = custom_control_reg; // Чтение управляющего регистра 32'h0000_1008: rsp_data = custom_status_reg; // Пользовательский регистр состояния // ... другие сопоставления endcase end end // ... ``` * **Реализация поведенческой логики:** Создайте логику SystemVerilog (конечные автоматы, комбинационную логику), которая: * Реагирует на записи в ваш `custom_control_reg`. Например, определенный бит в этом регистре может запускать передачу DMA, сбрасывать флаг состояния или инициировать внутреннюю операцию. * Обновляет ваш `custom_status_reg` на основе внутреннего состояния вашего эмулируемого устройства (например, "операция завершена", "произошла ошибка", "данные доступны"). * Обрабатывает данные, записанные в `custom_data_reg`, или предоставляет данные из него при чтении, имитируя пути данных устройства-донора. 3. **Эмуляция сообщений, специфичных для поставщика (если применимо):** * Некоторые сложные устройства могут использовать "Сообщения, определяемые поставщиком" (VDM) через PCIe для специфического управления или связи. Если ваш анализ выявляет такие сообщения, вам потребуется: * Включить поддержку VDM в IP-ядре PCIe (если доступно). * Реализовать логику генерации TLP (как будет обсуждаться в Разделе 10) для создания и отправки этих VDM. * Реализовать логику приема и анализа TLP для интерпретации входящих VDM от хоста. 4. **Проверка эмулируемого поведения:** * **Итеративное тестирование:** Это очень итеративный процесс. Вносите небольшие изменения, компилируйте, прошивайте и тестируйте. * **Загрузка драйвера:** Загружается ли драйвер устройства-донора корректно, без ошибок? * **Функциональные тесты:** Может ли драйвер инициировать базовые операции? Получает ли он ожидаемые ответы от ваших эмулированных регистров? * **Тесты приложений:** Могут ли приложения, которые полагаются на устройство-донор, корректно работать с вашей эмулированной версией? * **Отладка:** Широко используйте ILA и анализаторы протокола PCIe для сравнения поведения вашего эмулируемого устройства с захваченным поведением реального устройства-донора. Ищите расхождения во времени TLP, значениях регистров и общем потоке протокола. --- ## **10. Эмуляция пакетов транспортного уровня (TLP)** Пакеты транспортного уровня (TLP) являются фундаментальными единицами связи в архитектуре PCIe. Каждое взаимодействие между хост-системой и устройством PCIe, от чтения конфигурации до передачи данных, инкапсулируется в один или несколько TLP-пакетов. Точная эмуляция TLP-пакетов не просто важна; она *критически* важна для правильного взаимодействия эмулируемого устройства с хост-системой, гарантируя корректную работу драйверов и ожидаемое перемещение данных. ### **10.1. Понимание и захват TLP-пакетов** Прежде чем вы сможете создавать пользовательские TLP-пакеты, вы должны глубоко понять их структуру и общие типы. Захват реальных TLP-пакетов с вашего устройства-донора предоставляет наиболее точный шаблон. * **Компоненты TLP-пакета**: * **Заголовок**: Наиболее важная часть, обычно 3 или 4 двойных слова (Dword = 4 байта). Он содержит критически важные поля, которые определяют назначение TLP-пакета и то, как он должен обрабатываться: * **Fmt (Формат) и Type (Тип)**: Определяет формат TLP-пакета (3DW/4DW, с данными/без данных) и его конкретное назначение (например, запрос на чтение памяти, запись в память, завершение, чтение/запись конфигурации). * **Length (Длина)**: Указывает размер полезной нагрузки в Dword. * **Requester ID (Шина, Устройство, Функция)**: Идентифицирует функцию PCIe, которая инициировала запрос. Важно для маршрутизации завершений обратно к правильному источнику. * **Tag (Тег)**: Уникальный идентификатор, присвоенный запрашивающим устройством транзакции, позволяющий завершающему устройству сопоставить TLP-пакет завершения с исходным TLP-запросом. * **Address (Адрес)**: Для транзакций памяти/ввода-вывода это целевой адрес памяти или ввода-вывода. * **First DW Byte Enable (FBE)** и **Last DW Byte Enable (LBE)**: Указывают, какие байты в первом и последнем Dword полезной нагрузки действительны для операций записи, или какие байты запрашиваются для завершений чтения. * **Traffic Class (TC)** и **Transaction ID (TID)**: Для QoS и правил упорядочивания. * **Полезная нагрузка (Optional)**: Присутствует в TLP-пакетах, таких как запись в память, запись конфигурации и завершения чтения. Она содержит фактические передаваемые данные. * **End-to-End CRC (ECRC) (Optional)**: 32-битный CRC, охватывающий весь TLP-пакет, обеспечивающий целостность данных от источника до получателя, обычно генерируется/проверяется программным обеспечением. * **Понимание общих типов TLP-пакетов**: Ваша прошивка будет в основном иметь дело с ними: * **Запрос на чтение памяти (MRd)**: TLP-пакет, отправленный запрашивающим устройством (например, хост-ЦП или вашей FPGA в качестве мастера DMA) для чтения данных из определенного адреса памяти. * **Завершение чтения памяти с данными (CplD)**: TLP-пакет, отправленный завершающим устройством (например, вашей FPGA, отвечающей на MRd хоста), несущий запрошенные данные. * **Запись в память (MWr)**: TLP-пакет, отправленный запрашивающим устройством (например, хост-ЦП или вашей FPGA) для записи данных в определенный адрес памяти. * **Завершение без данных (Cpl)**: TLP-пакет, отправленный завершающим устройством для подтверждения запроса, который не возвращает данных (например, успешная MWr). * **Запрос на чтение конфигурации (CfgRd)**: TLP-пакет от хоста для чтения регистров в пространстве конфигурации устройства. * **Завершение чтения конфигурации с данными (CplD)**: TLP-пакет от устройства, возвращающий данные для CfgRd. * **Запрос на запись конфигурации (CfgWr)**: TLP-пакет от хоста для записи в регистры в пространстве конфигурации устройства. * **Сообщения, определяемые поставщиком (VDM)**: Пользовательские TLP-пакеты, используемые конкретными поставщиками для проприетарной связи. #### **10.1.2. Захват TLP-пакетов с устройства-донора** Захват реального трафика PCIe с вашего устройства-донора бесценен. Он предоставляет конкретные примеры структур TLP-пакетов, последовательностей и временных характеристик, позволяя вам точно их воспроизвести. * **Шаги**: 1. **Настройте анализатор протокола PCIe**: * Наиболее эффективный метод включает использование специализированных аппаратных средств, часто называемых "Анализаторами протокола PCIe". Эти устройства располагаются между хостом и платой PCIe-донора, пассивно захватывая весь трафик. * **Примеры**: * **Анализаторы PCIe Teledyne LeCroy**: Отраслевой стандарт, высокопроизводительные, но требуют значительных инвестиций. * **Анализаторы PCIe Keysight**: Еще один ведущий производитель. * (Для базовой отладки некоторые высококлассные логические анализаторы с декодерами PCIe могут предлагать ограниченный просмотр TLP-пакетов, но настоящий анализатор протокола превосходит их). 2. **Захват транзакций**: * Установите устройство-донор в тестовую систему с подключенным анализатором протокола. * Запустите драйвер устройства-донора и любые связанные приложения. * Отслеживайте и записывайте транзакции PCIe во время нормальной работы, и особенно во время критических фаз, таких как: * Перечисление устройства (когда ОС впервые его обнаруживает). * Загрузка и инициализация драйвера. * Типичные операции передачи данных (например, копирование больших файлов для устройства хранения данных, сетевой трафик для сетевой карты). * Команды или диагностика, специфичные для устройства. 3. **Анализ захваченных TLP-пакетов**: * Используйте сложное программное обеспечение анализатора протокола для анализа захваченных TLP-пакетов. Программное обеспечение будет декодировать поля, предоставлять хронологические представления, а также позволять фильтровать и искать. * Обратите пристальное внимание на: * Точные поля `Fmt` и `Type`. * Значения `Requester ID` и `Tag` (особенно для завершений). * `Address` и `Length` для транзакций памяти. * Содержимое `Data Payload` для записей и завершений чтения. * Любые поля, специфичные для поставщика, или пользовательские TLP-пакеты. #### **10.1.3. Документирование ключевых TLP-транзакций** Структурированная документация захваченных TLP-пакетов создает шаблон для вашей эмуляции. * **Шаги**: 1. **Определите критически важные транзакции**: * Сосредоточьтесь на TLP-пакетах, которые необходимы для основной функциональности устройства. К ним относятся: * **Последовательность инициализации**: Серия чтений/записей конфигурации, которые ОС выполняет во время перечисления. * **Инициализация драйвера**: Команды и данные, обмениваемые при запуске драйвера. * **Основные передачи данных**: Как TLP-пакеты `MWr` и `MRd` структурируются и завершаются для основной функции устройства. * **Обработка ошибок**: Как устройство сообщает об ошибках (например, завершение с прерыванием от завершающего устройства (CA), неподдерживаемый запрос (UR)). * **Переходы состояний управления питанием**: TLP-пакеты, связанные с изменениями D-состояния. * **Генерация прерываний**: Как отправляются сообщения MSI/MSI-X. 2. **Создайте подробную документацию**: * Для каждой ключевой последовательности TLP-пакетов запишите: * **Тип TLP-пакета** (например, MWr, MRd, CplD). * Его **поля заголовка** (Fmt, Type, Requester ID, Tag, Length, Address, Byte Enables). * **Полезная нагрузка данных** (если применимо). * **Порядковый номер** или порядок в транзакции. * **Условия**, при которых он отправляется (например, "отправлено хостом при инициализации драйвера", "отправлено устройством по завершении DMA"). * Любые **ожидаемые ответы** или последующие TLP-пакеты. * Снимки экрана с анализатора протокола могут быть очень полезны здесь. 3. **Поймите временные характеристики и последовательность**: * Помимо содержимого TLP-пакетов, *время* и *последовательность* TLP-пакетов жизненно важны. PCIe имеет строгие правила упорядочивания и механизмы управления потоком. Обратите внимание на: * **Задержка между запросом и завершением**: Как быстро реагирует реальное устройство. * **Кредиты управления потоком**: Как устройство управляет своим буферным пространством для входящих/исходящих TLP-пакетов. Хотя IP-ядро Xilinx PCIe обрабатывает базовое управление потоком, для расширенной эмуляции знание типичного использования кредитов донора может быть полезно. * **Порядок пакетов транспортного уровня**: Поймите, как упорядочиваются постированные (записи) и непостированные (чтения, завершения) транзакции. ### **10.2. Создание пользовательских TLP-пакетов для специфических операций** Как только вы поймете шаблон, вы сможете применить эти знания в прошивке вашей FPGA (SystemVerilog) для активной генерации и ответа на TLP-пакеты. Фреймворк PCILeech-FPGA предоставляет уровни абстракции, но для глубокой эмуляции вам может потребоваться прямое взаимодействие с логикой генерации/анализа TLP-пакетов. #### **10.2.1. Реализация обработки TLP в прошивке** Ваша прошивка должна иметь логику для отправки и приема TLP-пакетов. IP-ядро PCIe обрабатывает физический уровень и уровень канала данных, предоставляя интерфейс уровня транзакций (часто AXI-Stream) вашей пользовательской логике. * **Файлы для изменения (основные)**: * `pcileech-fpga//src/pcileech_pcie_tlp_a7.sv` (или аналогичный, в зависимости от варианта платы) * Этот файл часто содержит основную логику для преобразования пользовательских запросов в исходящие TLP-пакеты и анализа входящих TLP-пакетов в сигналы для вашей пользовательской логики. * `pcileech-fpga//src/pcileech_tlps128_bar_controller.sv` * Этот модуль специально обрабатывает анализ входящих TLP-пакетов чтения/записи памяти, которые нацелены на BARы вашего устройства, и генерацию соответствующих TLP-пакетов завершения. * **Шаги**: 1. **Поймите интерфейс IP-ядра PCIe**: * Прежде чем писать логику TLP-папакетов, тщательно изучите Руководство пользователя IP-ядра PCIe Xilinx (в частности, разделы об интерфейсе пользовательского приложения или интерфейсе AXI4-Stream). В нем определяется, как ваша логика SystemVerilog подключается к ядру PCIe для отправки и приема TLP-пакетов. Вы обычно будете взаимодействовать с `s_axis_rx_tdata` (полученные данные TLP), `s_axis_rx_tvalid` (получен действительный TLP), `m_axis_tx_tdata` (исходящие данные TLP), `m_axis_tx_tready` (ядро готово принять TLP) и т. д. 2. **Создайте функции генерации TLP (для исходящих TLP-пакетов)**: * В `pcileech_pcie_tlp_a7.sv` (или модуле, который взаимодействует с `m_axis_tx_*`), вы будете писать логику для сборки TLP-пакетов с требуемыми заголовками и полезными нагрузками. Это часто включает объединение различных полей в шину `[127:0]` (для 128-битного интерфейса) или `[63:0]` (для 64-битного интерфейса), которая подается на ядро PCIe. * **Пример (концептуальная, упрощенная функция для 3DW заголовка TLP):** ```verilog // Это концептуальная вспомогательная функция. В реальности вы бы построили конечный автомат // для отправки TLP-пакетов через интерфейс AXI-Stream, возможно, используя FIFO. function automatic [95:0] create_3dw_tlp_header; // Предполагается, что 3 Dword = 96 бит input logic [7:0] tlp_type_fmt; // Поля формата и типа input logic [15:0] requester_id; // BDF input logic [7:0] tag; input logic [7:0] lower_address_bits; // Или более сложный адрес input logic [7:0] byte_enables; // Разрешение байтов первого DW begin create_3dw_tlp_header = { tlp_type_fmt, // Fmt[6:4], Type[3:0] 8'b0, // Зарезервировано 4'b0, // TC[3:0] (класс трафика) 3'b0, // Attr[2:0] 1'b0, // TH (подсказка TLP) 2'b0, // D(igest) (присутствие ECRC) 1'b0, // EP (отравлено) 1'b0, // TD (зависит от типа) // DW0: Fmt, Type, TC, Attr, TH, D, EP, TD, Length (не в 3DW, в 4DW есть) requester_id, // ID запрашивающего (Bus[7:0], Device[4:0], Function[2:0]) tag, // Тег lower_address_bits, // Пример: младшие биты адреса или часть данных byte_enables, // Разрешение байтов первого DW 4'b0, // Зарезервировано 4'b0 // Разрешение байтов последнего DW (обычно для MWr) // Поля DW1, DW2... }; end endfunction // Пример: Генерация завершения с данными (CplD) в конечном автомате // Это всего лишь фрагмент, не полная реализация localparam CPLD_3DW_FMT = 8'h4A; // Fmt=100 (4DW, с данными), Type=1010 (Cpl) localparam CPL_D_FMT_TYPE_LEN = 8'h4A; // Скорректировано на основе спецификации PCIe. (4DW заголовок с данными) // ... конечный автомат для отправки TLP // В состоянии, когда вы готовы отправить CplD if (tx_ready_from_pcie_core) begin // Построить заголовок и полезную нагрузку // Для CplD вам нужны Complier ID, Status, Byte Count, Requester ID, Tag, Completion ID, Lower Address // А затем фактическая полезная нагрузка прочитанных данных m_axis_tx_tdata_reg = { CPL_D_FMT_TYPE_LEN, // Байт 0: Fmt/Type tlp_length_dw_minus_one, // Байт 1: Длина TLP (в Dword) - 1 status_completion_bits, // Байт 2: Статус Cpl, BCM, Rsvd byte_count_dws_upper, // Байт 3: Количество байтов (старшие биты) requester_id, // Байт 4-5: ID запрашивающего (из оригинального MRd) tag, // Байт 6: Тег (из оригинального MRd) byte_count_dws_lower, // Байт 7: Количество байтов (младшие биты) completion_id, // Байт 8-9: ID завершения (ваш BDF) lower_address_from_request // Байт 10-11: Младший адрес из запроса // ...затем фактическая полезная нагрузка данных }; m_axis_tx_tvalid_reg = 1'b1; m_axis_tx_tlast_reg = 1'b1; // Последний сегмент TLP // ... переход состояния для ожидания tready end ``` * **Примечание**: Фактическая реализация включает конечные автоматы, FIFO и соответствие протоколу AXI-Stream для IP-ядра PCIe. Фреймворк PCILeech-FPGA уже предоставляет хорошую основу для этого, но вам может потребоваться расширить или изменить его для очень специфического поведения TLP-пакетов. 3. **Обработка приема TLP (для входящих TLP-пакетов)**: * Реализуйте логику для анализа входящих TLP-пакетов с интерфейса приема ядра PCIe (например, `s_axis_rx_tdata`, `s_axis_rx_tvalid`). * Этот анализ включает: * Проверку `s_axis_rx_tvalid`, чтобы узнать, присутствует ли TLP. * Чтение полей `Fmt` и `Type` из заголовка TLP, чтобы определить его назначение. * Извлечение соответствующих полей, таких как `Requester ID`, `Tag`, `Address`, `Length` и `Data Payload`. * Используйте операторы `case` или блоки `if/else if` на основе типа TLP-пакета, чтобы маршрутизировать информацию к соответствующей внутренней логике (например, `bar_controller` для записей в память, модуль конфигурации для записей конфигурации). * **Пример (концептуальный, упрощенный парсинг):** ```verilog // В pcileech_pcie_tlp_a7.sv или модуле парсера TLP input wire [127:0] s_axis_rx_tdata; input wire s_axis_rx_tvalid; output wire s_axis_rx_tready; // Должен быть установлен для приема дополнительных данных reg [7:0] received_tlp_fmt_type; reg [15:0] received_requester_id; // ... объявить другие разобранные поля assign s_axis_rx_tready = 1'b1; // Всегда готов к приему для простоты, управляйте обратным давлением в реальном проекте always @(posedge clk) begin if (s_axis_rx_tvalid) begin received_tlp_fmt_type = s_axis_rx_tdata[127:120]; // Предполагается, что это старшие биты received_requester_id = s_axis_rx_tdata[111:96]; // Пример смещения // Декодирование на основе типа TLP case (received_tlp_fmt_type[3:0]) // Только биты типа TLP 4'h0: // Запись в память (3DW или 4DW в зависимости от Fmt) // Извлечь адрес, длину, полезную нагрузку и передать контроллеру BAR begin // Передать контроллеру BAR для записи в эмулируемую память // bar_write_enable = 1'b1; // bar_write_address = s_axis_rx_tdata[...]; // bar_write_data = s_axis_rx_tdata[...]; end 4'h1: // Чтение памяти // Извлечь адрес, длину и передать контроллеру BAR для чтения begin // bar_read_enable = 1'b1; // bar_read_address = s_axis_rx_tdata[...]; // (Завершение будет сгенерировано контроллером BAR) end // ... другие типы TLP default: begin // Обработка неподдерживаемых или зарезервированных типов TLP (например, логирование, ошибка) end endcase end end ``` 4. **Обеспечьте соответствие**: * Строго проверяйте, что как ваши сгенерированные, так и проанализированные TLP-пакеты соответствуют спецификации PCIe в отношении формата, определений полей и временных характеристик. Отклонения приведут к сбоям связи. 5. **Реализуйте обработку завершений**: * Для запросов на чтение памяти (MRd) и запросов на чтение конфигурации (CfgRd), полученных от хоста, ваше устройство обязано отправить обратно соответствующие TLP-пакеты завершения (CplD для данных, Cpl для без данных) в течение определенного временного окна. Модуль `bar_controller` (Раздел 8.2.2) — это место, где находится эта логика для чтения BAR. 6. **Сохраните изменения**: * Сохраните файлы (`pcileech_pcie_tlp_a7.sv`, `pcileech_tlps128_bar_controller.sv` или любые пользовательские модули) после реализации изменений. #### **10.2.2. Обработка различных типов TLP** Каждый тип TLP имеет специфический формат заголовка и поведение. Ваша прошивка должна уметь обрабатывать те, которые имеют отношение к вашему устройству-донору. * **Запросы на чтение памяти (MRd)**: * **Реализация**: * При получении TLP-пакета MRd (разобранного `pcileech_pcie_tlp_a7.sv` и перенаправленного в `bar_controller`), `bar_controller` должен: * Разобрать запрошенный адрес и длину. * Получить данные из соответствующего внутреннего местоположения памяти (например, BRAM, подключенного к BAR) или внутреннего регистра. * Собрать TLP-пакет **завершения с данными (CplD)**. Крайне важно, чтобы этот TLP-пакет включал исходный `Requester ID`, `Tag` и `Completion ID` (BDF вашего устройства) из запроса MRd, а также полученную полезную нагрузку данных. * Отправить TLP-пакет CplD обратно хосту через интерфейс передачи IP-ядра PCIe. * **Запросы на запись в память (MWr)**: * **Реализация**: * При получении TLP-пакета MWr, `bar_controller` должен: * Разобрать целевой адрес, длину и `Byte Enables` (FBE/LBE). * Извлечь `data payload` (полезную нагрузку данных). * Записать данные в указанное местоположение памяти внутри вашего эмулируемого устройства (например, BRAM или внутренние регистры), соблюдая байтовые разрешения. * Записи в память являются "постированными транзакциями", что означает, что они не требуют TLP-пакета завершения для подтверждения, если только не возникает ошибка. * **Запросы на чтение/запись конфигурации (CfgRd/CfgWr)**: * **Реализация**: * Эти TLP-пакеты нацелены на пространство конфигурации устройства (Vendor ID, Device ID, BAR, Capabilities и т.д.). IP-ядро Xilinx PCIe автоматически обрабатывает большинство стандартных доступов к пространству конфигурации на основе своей конфигурации. * Однако, если у вас есть пользовательские регистры или расширенные возможности *внутри* пространства конфигурации, которые не являются стандартными, вам может потребоваться специальная логика для: * Для CfgRd: Возврата запрошенных данных из ваших внутренних `cfg_` регистров. * Для CfgWr: Обновления ваших внутренних `cfg_` регистров или запуска действий на основе записанных данных. * Чтения конфигурации требуют **завершения с данными (CplD)**, в то время как записи конфигурации требуют **завершения без данных (Cpl)**. * **Сообщения, определяемые поставщиком (VDM)**: * **Реализация**: * Если ваше устройство-донор использует VDM, это требует специализированной логики анализа и ответа. * **Анализ входящих VDM**: Идентифицируйте VDM на основе их полей `Fmt` и `Type`. Извлеките данные, специфичные для поставщика, и интерпретируйте их в соответствии с вашими результатами обратного инжиниринга. * **Создание исходящих VDM**: Создайте логику для сборки VDM с точными форматами заголовка и полезной нагрузки, специфичными для поставщика, когда ваше эмулируемое устройство должно их отправить. #### **10.2.3. Проверка временных характеристик и последовательности TLP** Даже если TLP-пакеты идеально отформатированы, некорректное время или последовательность приведут к сбою устройства или обнаружению его как несоответствующего. * **Шаги**: 1. **Использование инструментов симуляции**: * **Тестовые стенды**: Разработайте комплексные тестовые стенды SystemVerilog для ваших модулей генерации и анализа TLP-пакетов. * Имитируйте различные сценарии (например, хост отправляет MRd, ваше устройство отправляет CplD; хост отправляет MWr; хост перечисляет устройство), чтобы убедиться, что TLP-пакеты правильно формируются, передаются, принимаются и обрабатываются. * Проверьте последовательность TLP-пакетов и убедитесь, что завершения отправляются в разумные сроки. 2. **Мониторинг с помощью ILA (встроенного логического анализатора)**: * Как подробно описано в Разделе 12.1, вставьте ядро ILA в ваш проект Vivado. * Подключите пробники ILA к интерфейсам AXI-Stream IP-ядра PCIe (например, `s_axis_rx_tdata`, `s_axis_rx_tvalid`, `m_axis_tx_tdata`, `m_axis_tx_tready`). * Установите триггеры для захвата конкретных TLP-пакетов (например, на `m_axis_tx_tvalid` для определенного типа TLP). * Это позволяет вам видеть фактические биты TLP-пакетов на FPGA в реальном времени во время работы оборудования, проверяя, отправляет/принимает ли ваша прошивка правильные данные и управляющие сигналы к/от IP-ядра PCIe. 3. **Проверка временных ограничений**: * IP-ядро PCIe имеет строгие требования к временным характеристикам своих интерфейсов AXI-Stream. Убедитесь, что ваша пользовательская логика, предоставляющая данные `m_axis_tx_tdata` и обрабатывающая `s_axis_rx_tdata`, соответствует этим временным ограничениям. * Отчеты Vivado по временному анализу (после синтеза и реализации) отметят любые нарушения. Устраните их путем оптимизации вашей логики или корректировки тактовых сигналов, где это возможно. 4. **Тестирование на соответствие (Продвинутое)**: * Для высокоточной эмуляции рассмотрите возможность использования специализированного набора тестов на соответствие PCIe (часто интегрированного с высококлассными анализаторами протокола). Эти тесты систематически проверяют соблюдение спецификации PCIe, выявляя тонкие нарушения протокола. 5. **Сохраните изменения**: * Сохраните все измененные файлы после тщательного тестирования и проверки. Итерации являются ключевыми при отладке на уровне TLP. --- ## **Часть 3: Продвинутые методы и оптимизация** --- ## **11. Сборка, прошивка и тестирование** После завершения всех настроек наступает момент истины: сборка прошивки, программирование ее на вашу FPGA и тщательное тестирование ее функциональности, чтобы убедиться, что она ведет себя точно так же, как устройство-донор. Этот этап переводит ваш проект из кода в работающую аппаратную эмуляцию. ### **11.1. Синтез и реализация** Это основные шаги в процессе проектирования FPGA, где ваш высокоуровневый код SystemVerilog преобразуется в низкоуровневую аппаратную конфигурацию, которая может быть загружена на FPGA. #### **11.1.1. Запуск синтеза** Синтез — это процесс, в ходе которого Vivado преобразует ваш HDL-код в логическую схему на уровне вентилей (описание логических вентилей и их взаимосвязей). Он также выполняет предварительный анализ временных характеристик и оценку ресурсов. * **Шаги**: 1. **Начните синтез**: * В графическом интерфейсе Vivado, на панели **Flow Navigator** (обычно слева), в разделе "Synthesis", нажмите **Run Synthesis**. 2. **Отслеживайте прогресс**: * Vivado откроет диалоговое окно "Launch Runs". Обычно можно просто нажать "OK". * Следите за вкладкой **Messages** в нижней части окна Vivado. Там будет отображаться ход выполнения синтеза. * **Распространенные предупреждения/ошибки, на которые следует обратить внимание**: * **`[Synth 8-327]` Неподключенные порты / Неиспользуемые входы**: Указывает на то, что сигнал или порт в вашем проекте ни к чему не подключены. Хотя иногда это намеренно (например, неиспользуемые контакты на FPGA), они также могут указывать на опечатки в именах портов или забытые соединения. Изучите каждый, чтобы убедиться, что это не функциональная проблема. * **`[Synth 8-256]` Регистры/провода не оптимизированы**: Это может указывать на неправильное определение логики или наличие избыточной логики, которую можно оптимизировать. * **Синтаксические ошибки**: Если в вашем коде SystemVerilog есть фатальные синтаксические ошибки, синтез немедленно завершится сбоем. Исправьте их в Visual Studio Code. 3. **Просмотрите отчет о синтезе**: * После успешного завершения Vivado спросит, что делать дальше. Выберите **Open Synthesized Design** или **Open Report**. * Критически важно просмотреть **Utilization Summary** в отчете о синтезе. Это показывает, сколько ресурсов FPGA (LUT, Flip-Flops, BRAM, DSP) потребляет ваш проект. Убедитесь, что проект соответствует емкости вашей целевой FPGA (например, для Artix-7 35T вы должны находиться в пределах ее ограничений). #### **11.1.2. Запуск реализации** Реализация — самый трудоемкий шаг. Он берет синтезированный список соединений и физически отображает его на ресурсы FPGA (размещая логические блоки, трассируя соединения), а затем выполняет детальный анализ временных характеристик, чтобы убедиться, что проект может работать на заданных тактовых частотах. * **Шаги**: 1. **Начните реализацию**: * После успешного синтеза, на панели **Flow Navigator**, в разделе "Implementation", нажмите **Run Implementation**. * Подтвердите диалоговое окно "Launch Runs". 2. **Отслеживайте прогресс**: * Реализация состоит из нескольких фаз: Opt Design, Power Opt Design, Place Design, Post-Placement Phys Opt Design, Route Design, Post-Route Phys Opt Design. Каждая фаза может занимать значительное количество времени. * Следите за вкладкой **Messages** для отслеживания прогресса и потенциальных проблем. 3. **Анализируйте временные отчеты**: * Это *самый важный шаг* после реализации. По завершении Vivado снова спросит, что делать дальше. Выберите **Open Implemented Design** или, что более важно, **Open Report**, а затем выберите **Report Timing Summary**. * **Убедитесь, что все временные ограничения соблюдены.** Ищите значения "WNS (Worst Negative Slack)". * **Положительный WNS**: Указывает на то, что все временные пути соответствуют своим требованиям (slack означает, что у вас есть дополнительное время). Это то, что вы хотите. * **Отрицательный WNS**: Указывает на **нарушения временных характеристик**, что означает, что ваш дизайн не может работать на желаемой тактовой частоте или данные могут быть нестабильными. **Это критическая проблема, которую *необходимо* устранить.** * **Устранение нарушений**: * Если у вас отрицательный запас по времени, исследуйте конкретные пути, которые не проходят. Отчет о временных характеристиках Vivado покажет вам источник, назначение и компоненты неисправных путей. * Решения могут включать: * Оптимизация вашего HDL-кода для уменьшения глубины логики или задержек критических путей. * Добавление стадий конвейера (регистров) для разбиения длинных комбинационных путей. * Уточнение вашего XDC-файла (ограничений), убедившись, что все тактовые сигналы правильно определены и распространяются. * Настройка тактовых частот (если позволяет приложение). * Использование более быстрых стратегий временного закрытия в Vivado. * Обеспечение правильного взаимодействия вашей пользовательской логики с временными требованиями интерфейса AXI-Stream ядра PCIe. 4. **Проверка размещения (необязательно)**: * В реализованном проекте вы можете открыть представление "Device", чтобы увидеть, как ваша логика была размещена на FPGA. Это, как правило, для продвинутых пользователей, чтобы убедиться, что критически важные компоненты размещены оптимально (например, близко к трансиверам PCIe). #### **11.1.3. Генерация битстрима** Битстрим — это окончательный, двоичный файл конфигурации (расширение `.bit`), который будет загружен на вашу FPGA. Это кульминация синтеза и реализации. * **Шаги**: 1. **Сгенерируйте битстрим**: * После успешной реализации (без критических нарушений временных характеристик), на панели **Flow Navigator**, в разделе "Program and Debug", нажмите **Generate Bitstream**. 2. **Дождитесь завершения**: * Этот процесс обычно занимает меньше времени, чем реализация, но все еще может варьироваться в зависимости от сложности проекта. 3. **Просмотрите журнал генерации битстрима**: * По завершении Vivado укажет на успех. Просмотрите журнал на наличие предупреждений, хотя обычно, если реализация прошла чисто, генерация битстрима тоже пройдет. * Файл `.bit` будет сгенерирован в каталоге вашего проекта `pcileech_squirrel_top.runs/impl_1/` (или аналогичном пути для вашей платы). ### **11.2. Прошивка битстрима** Программирование (прошивка) битстрима загружает ваш скомпилированный дизайн на FPGA, делая ваше эмулируемое устройство активным. #### **11.2.1. Подключение устройства FPGA** * **Шаги**: 1. **Подготовьте оборудование**: * Убедитесь, что ваша DMA-плата на базе FPGA правильно установлена в совместимый слот PCIe на вашей хост-системе. * Подключите JTAG-программатор (например, Digilent HS3, Xilinx Platform Cable) к JTAG-разъему на вашей плате FPGA и к USB-порту вашего компьютера разработчика. * Включите хост-систему. * Обратитесь к руководству вашей конкретной платы FPGA для получения точных инструкций по питанию, JTAG и подключению PCIe. 2. **Откройте Hardware Manager**: * В Vivado перейдите в **Flow Navigator > Program and Debug > Open Hardware Manager**. * Если Vivado не запущен, вы можете запустить Hardware Manager как отдельное приложение. #### **11.2.2. Программирование FPGA** * **Шаги**: 1. **Подключитесь к цели**: * В окне Hardware Manager нажмите **Open Target** (часто большая кнопка или ссылка) и выберите **Auto Connect**. * Vivado должен автоматически обнаружить ваш JTAG-программатор, а затем подключенные устройства FPGA в цепочке JTAG. Если обнаружение не удалось, проверьте соединения JTAG-кабеля, питание платы и драйверы JTAG на вашем ПК. 2. **Программирование устройства**: * Как только ваше устройство FPGA будет обнаружено и отображено в окне Hardware, **щелкните правой кнопкой мыши** по вашему устройству FPGA (например, `xc7a35t_0`) и выберите **Program Device**. * Появится диалоговое окно. Нажмите кнопку "..." рядом с полем "Bitstream file" и перейдите к файлу сгенерированного битстрима (например, `pcileech_squirrel_top.runs/impl_1/pcileech_squirrel_top.bit`). * Нажмите **Program**, чтобы начать прошивку на FPGA. * Дождитесь завершения процесса программирования. Вы увидите индикатор выполнения. #### **11.2.3. Проверка программирования** * **Шаги**: 1. **Проверьте статус**: * Убедитесь, что программирование завершилось без ошибок в Vivado's Hardware Manager. Vivado отобразит сообщение об успешном завершении "Program Device". 2. **Наблюдайте за светодиодами или индикаторами**: * Многие платы FPGA имеют светодиодные индикаторы состояния. Успешная операция программирования часто приводит к загоранию или изменению состояния определенного светодиода (например, светодиод "DONE"). Это быстрое визуальное подтверждение. 3. **Перезагрузка хост-системы (иногда требуется)**: * Для корректного распознавания вновь запрограммированного устройства PCIe операционной системой хоста часто требуется перезагрузка системы, особенно в Windows, чтобы запустить полный процесс перечисления PCIe. ### **11.3. Тестирование и проверка** После программирования решающим шагом является проверка того, что ваше эмулируемое устройство правильно обнаруживается хостом и что оно функционирует, как ожидается, имитируя устройство-донор. #### **11.3.1. Проверка перечисления устройства** Это подтверждает, что ОС хоста видит вашу FPGA как устройство-донор на основе запрограммированных вами идентификаторов. * **Windows**: * **Шаги**: 1. **Откройте диспетчер устройств**: Нажмите `Win + X` и выберите **Диспетчер устройств** из меню быстрого доступа. 2. **Проверьте свойства устройства**: * Посмотрите в соответствующей категории устройств (например, **Сетевые адаптеры**, **Контроллеры хранилищ**, **Системные устройства**). * Найдите свое эмулируемое устройство. Теперь оно должно отображаться с *именем устройства-донора* (например, "Intel(R) Ethernet Connection..."). * Щелкните правой кнопкой мыши по устройству, выберите **Свойства** и перейдите на вкладку **Сведения**. * В выпадающем списке "Свойство" выберите "ИД оборудования". Убедитесь, что **Device ID (DID)** и **Vendor ID (VID)** (например, `PCI\VEN_ABCD&DEV_1234`) совпадают с теми, что вы запрограммировали в свою прошивку. * Также проверьте "Class Code" и "Subsystem ID" для дальнейшей проверки. * **Linux**: * **Шаги**: 1. **Используйте `lspci`**: Откройте терминал и используйте команду `lspci`. ```bash lspci -nn # Показывает VendorID:DeviceID lspci -vvv # Показывает подробные сведения, включая BAR, возможности и многое другое ``` 2. **Проверьте список устройств**: * Убедитесь, что эмулируемое устройство отображается в выводе `lspci` с правильными Vendor ID, Device ID и Class Code. * **Пример вывода (эмуляция сетевой карты Intel):** ``` 03:00.0 Network controller [0280]: Intel Corporation Ethernet Connection I219-V [8086:1570] (rev 21) ``` (`8086` — Vendor ID Intel, `1570` — Device ID для I219-V, `0280` — Class Code сетевого контроллера). * Используйте `lspci -vvv`, чтобы убедиться, что BAR перечисляются с правильными размерами и типами, соответствующими конфигурации вашего устройства-донора. #### **11.3.2. Тестирование функциональности устройства** Как только устройство перечислено, окончательной проверкой является то, функционирует ли оно как оригинал. * **Шаги**: 1. **Установите необходимые драйверы**: * Если ОС хоста не загружает автоматически подходящий драйвер, вам потребуется вручную установить официальные драйверы для вашего устройства-донора. Загрузите их с веб-сайта производителя. * Установите их в соответствии с инструкциями производителя. Если эмуляция прошла успешно, драйвер должен установиться и распознать вашу FPGA как реальное оборудование. 2. **Выполните функциональные тесты**: * Запустите приложения или утилиты, которые обычно взаимодействуют с устройством-донором. * **Примеры**: * **Сетевая карта**: Выполните тесты ping, просмотрите веб-страницы или инициируйте большие передачи файлов для проверки пропускной способности. * **Контроллер хранилища**: Попробуйте отформатировать имитированный диск (если ваша эмуляция включает функции хранения), выполните операции чтения/записи или запустите тесты производительности диска. * **USB-контроллер**: Подключите USB-устройства (если ваша эмуляция включает функциональность USB-хоста) и проверьте их обнаружение и работу. * Отслеживайте хост-систему на предмет ожидаемого поведения и характеристик производительности. 3. **Мониторинг поведения системы**: * Проверьте стабильность системы (отсутствие BSOD в Windows, паник ядра в Linux). * Ищите ошибки, специфичные для устройства, в системных журналах (Просмотр событий в Windows, `dmesg` или `journalctl` в Linux). * Убедитесь, что эмулируемое устройство ведет себя, как ожидается, при различных нагрузках, включая интенсивные передачи данных или стресс-тесты. #### **11.3.3. Мониторинг ошибок** Активный мониторинг ошибок крайне важен для выявления тонких проблем эмуляции, которые могут не вызывать немедленных сбоев. * **Windows**: * **Шаги**: 1. **Проверьте Просмотр событий**: Нажмите `Win + X` и выберите **Просмотр событий**. 2. **Ищите ошибки, связанные с PCIe**: Перейдите в **Журналы Windows > Система**. Отфильтруйте или найдите предупреждения, ошибки или критические события, связанные с "PCIe", "PCI Express" или события, исходящие от конкретного драйвера устройства (ищите имена источников, соответствующие драйверу вашего эмулируемого устройства). * Распространенные ошибки включают конфликты ресурсов, сбои инициализации драйвера или неожиданные ответы устройства. * **Linux**: * **Шаги**: 1. **Проверьте журналы `dmesg`**: Откройте терминал и введите: ```bash dmesg | grep -i pci # Регистронезависимый поиск сообщений pci dmesg | grep -i # Фильтр по Vendor ID вашего устройства ``` 2. **Выявите проблемы**: Ищите сообщения, указывающие на проблемы с обучением канала PCIe, инициализацией устройства, сбои выделения памяти или ошибки при проверке драйвера, или неожиданную активность DMA. Подсистема PCIe ядра Linux довольно многословна. * **Журнал Systemd (современный Linux)**: ```bash journalctl -b | grep -i pci # Журнал текущей загрузки ``` --- ## **12. Продвинутые методы отладки** Когда возникают проблемы, особенно в сложной эмуляции устройств PCIe, базового устранения неполадок может быть недостаточно. Продвинутые инструменты и методы отладки обеспечивают глубокую видимость внутренней логики FPGA и шины PCIe, позволяя эффективно выявлять и устранять проблемы. ### **12.1. Использование встроенного логического анализатора Vivado (ILA)** Встроенный логический анализатор (ILA) — это мощное, настраиваемое отладочное IP-ядро, предоставляемое Xilinx, которое можно встраивать непосредственно в ваш проект FPGA. Оно позволяет отслеживать поведение внутренних сигналов FPGA (проводов и регистров) в реальном времени без необходимости внешнего зондирующего оборудования, функционируя как мощный внутренний осциллограф или логический анализатор. #### **12.1.1. Вставка ядер ILA** * **Шаги**: 1. **Спланируйте ваши пробники**: Определите ключевые сигналы, которые вам необходимо наблюдать. Для эмуляции PCIe это часто включает: * Интерфейсы AXI-Stream IP-ядра PCIe (например, `s_axis_rx_tdata`, `s_axis_rx_tvalid`, `m_axis_tx_tdata`, `m_axis_tx_tready`). * Сигналы внутреннего конечного автомата (`current_state`, `next_state`). * Выходы декодирования адресов BAR (`bar_hit[0]`, `bar_hit[1]`). * Значения пользовательских регистров (`custom_control_reg`, `custom_status_reg`). * Сигналы запросов на прерывание (`msi_trigger_signal`). 2. **Добавьте IP-ядро ILA**: * В Vivado откройте **IP Catalog** (обычно на панели **Flow Navigator**). * Найдите "ILA" (Integrated Logic Analyzer). * Дважды щелкните по "Debug Bridge" (для базового ILA) или "Integrated Logic Analyzer (ILA)", чтобы открыть его графический интерфейс настройки. * Настройте ILA: * Установите **Number of Capture Data Ports** (пробников), которые вам нужны. * Установите **Width** каждого пробника, чтобы он соответствовал сигналам, которые вы планируете подключить. * Настройте **Sample Depth** (сколько образцов хранить до/после триггера). Большая глубина потребляет больше BRAM. * Нажмите "OK" и позвольте Vivado сгенерировать IP. 3. **Создайте экземпляр и подключите сигналы**: * Vivado сгенерирует файл `.xci` для ILA. Вы можете создать его экземпляр непосредственно в вашем SystemVerilog-файле верхнего уровня (например, `pcileech_squirrel_top.sv`) или в модуле, где доступны интересующие сигналы. * **Пример (в `pcileech_squirrel_top.sv` или подмодуле):** ```verilog // Предполагается, что вы сгенерировали ila_0 из IP Catalog // Подключите к тактовому сигналу и интересующим сигналам вашего проекта ila_0 your_ila_instance ( .clk(clk_125mhz), // Подключите к стабильному тактовому сигналу в вашем проекте, обычно к пользовательскому тактовому сигналу PCIe .probe0(pcie_s_axis_rx_tdata), // Пример: входящие данные TLP PCIe .probe1(pcie_s_axis_rx_tvalid), // Пример: входящий TLP PCIe действителен .probe2(pcie_m_axis_tx_tdata), // Пример: исходящие данные TLP PCIe .probe3(my_bar_controller_state), // Пример: состояние логики вашего BAR .probe4(my_custom_register), // Пример: значение пользовательского регистра // Добавьте больше пробников по мере необходимости .probeN(signal_to_monitor_N) ); ``` * **Альтернатива (пометка для отладки):** Для более простых сигналов иногда можно пометить их непосредственно в вашем HDL-коде для отладки. Используйте `(* mark_debug = "true" *) wire my_signal;` или `(* mark_debug = "true" *) reg my_register;`. Vivado затем автоматически предложит добавить их в ILA. #### **12.1.2. Настройка условий срабатывания** ILA наиболее мощен, когда вы настраиваете интеллектуальные условия срабатывания для точного захвата данных при возникновении интересующего события (например, ошибки, определенного типа TLP, перехода состояния). * **Шаги**: 1. **Сгенерируйте битстрим с ILA**: После вставки и подключения ILA вы должны запустить синтез, реализацию и сгенерировать новый битстрим. Ядро ILA потребляет ресурсы FPGA и будет встроено в ваш проект. 2. **Откройте Hardware Manager**: Программируйте свою FPGA битстримом с включенным ILA (Раздел 11.2). Затем в Vivado откройте Hardware Manager и подключитесь к вашей цели. 3. **Доступ к панели ILA**: В Hardware Manager выберите ваш экземпляр ILA (например, `hw_ila_1`). Откроется панель ILA. 4. **Определите триггеры**: * Выберите пробники, которые вы хотите использовать в качестве входных данных триггера. * Установите конкретные **шаблоны триггеров** (например, `0x4A` для `pcie_s_axis_rx_tdata`, чтобы сработать при TLP завершения). * Настройте **условия триггера** (например, "равно", "не равно", "положительный фронт", "отрицательный фронт"). * Установите **позиции триггера** (сколько образцов захватить *до* события триггера, для предварительной видимости). * Вы можете настроить несколько последовательностей триггеров для сложного обнаружения событий. * **Пример сценариев для триггеров**: * Триггер по определенному `Fmt/Type` в полученном TLP для анализа входящих команд. * Триггер, когда определенный регистр (`my_custom_register`) достигает определенного значения. * Триггер по `pcie_m_axis_tx_tvalid` И `pcie_m_axis_tx_tdata[3:0]` == `4'hC` (для TLP записи в память) для анализа исходящих записей. * Триггер по активации сигнала ошибки. #### **12.1.3. Захват и анализ данных** * **Шаги**: 1. **Запустите проект**: Позвольте вашей хост-системе взаимодействовать с запрограммированной FPGA, вызывая события, которые вы хотите отладить. 2. **Взведите ILA**: На панели ILA нажмите кнопку **Run Trigger** (часто зеленая иконка "Play"). ILA будет ждать определенного условия срабатывания. 3. **Захватите данные**: Как только условие срабатывания будет выполнено, ILA захватит снимок сигналов в свой внутренний буфер памяти. 4. **Анализируйте формы сигналов**: * Захваченные данные появятся в окне просмотра форм сигналов. * Изучите поведение сигнала во времени. Увеличивайте масштаб, добавляйте курсоры и декодируйте значения. * Ищите: * **Неожиданные переходы**: Сигналы, изменяющиеся в неподходящее время. * **Некорректные значения**: Регистры, содержащие неверные данные. * **Нарушения протокола**: Ваша логика отправляет некорректные данные по интерфейсам PCIe. * **Проблемы с временными характеристиками**: Если сигналы не стабильны в ожидаемое время (хотя полный временной анализ выполняется при реализации, ILA показывает поведение во время выполнения). * Сравните захваченное поведение с ожидаемой логикой вашего проекта и наблюдаемым поведением устройства-донора (если вы захватывали его с помощью анализатора протокола). ### **12.2. Инструменты анализа трафика PCIe** В то время как ILA дает вам внутреннюю видимость FPGA, внешние инструменты анализа трафика PCIe предоставляют непревзойденный обзор фактической связи по шине PCIe *между* вашим эмулируемым устройством и хостом. Это крайне важно для проверки соответствия протоколу и отладки проблем на уровне канала. #### **12.2.1. Анализаторы протокола PCIe (аппаратные)** * **Примеры**: * **Анализаторы PCIe Teledyne LeCroy**: Золотой стандарт для глубокого анализа, полного декодирования протокола, расширенных функций триггеров и возможностей инъекции ошибок. * **Анализаторы PCIe Keysight**: Еще один ведущий производитель с аналогичными высококлассными функциями. * **Шаги**: 1. **Настройка анализатора**: Подключите аппаратный анализатор последовательно между слотом PCIe хост-системы и вашим DMA-устройством на базе FPGA. Это обычно включает использование специальной карты-переходника. 2. **Настройка параметров захвата**: Используйте программное обеспечение анализатора для определения трафика, который нужно захватить. Вы можете фильтровать по типу TLP, адресу, Requester ID, условиям ошибок и т.д., чтобы сосредоточиться на соответствующих событиях. 3. **Захват трафика**: Запустите ваше эмулируемое устройство на хосте. Анализатор будет пассивно записывать все транзакции PCIe. 4. **Анализ результатов**: * Используйте мощное программное обеспечение анализатора для просмотра декодированных TLP-пакетов, списков транзакций и временных диаграмм. * **Проверьте TLP-пакеты на соответствие и корректность**: Правильны ли все поля? Правильна ли последовательность? * **Выявите любые нарушения протокола или неожиданное поведение**: Здесь вы найдете причину сбоя драйвера (например, ваше устройство отправляет завершение с данными, когда спецификация требует завершения без данных, или оно отвечает слишком медленно). * **Сравните с захватами устройства-донора**: Напрямую сравните захваченный трафик с вашего эмулируемого устройства с захватами, которые вы сделали с реального устройства-донора. Это окончательный тест на точность эмуляции. #### **12.2.2. Программные средства** Для базовой проверки шины PCIe, или если выделенный аппаратный анализатор недоступен, некоторые программные средства могут предоставить ограниченную информацию. * **Примеры**: * **Wireshark с плагинами PCIe**: Хотя Wireshark в первую очередь предназначен для сетевого трафика, со специализированным оборудованием (например, сетевыми картами, которые предоставляют трассы PCIe ОС, или специфическим оборудованием/драйверами захвата) он иногда может захватывать и декодировать пакеты PCIe. Это сильно зависит от системы. * **ChipScope Pro (устаревшая Xilinx, теперь часть Vivado)**: Встроенный логический анализатор (ILA) является современным эквивалентом, но ChipScope был отдельным инструментом. * **`lspci` (Linux)**: Как упоминалось в разделе 11.3.1, `lspci -vvv` предоставляет обширную статическую информацию о пространстве конфигурации. Вы можете объединить его с `watch` или скриптами для отслеживания изменений во времени. * **Клиент `pcileech` (из фреймворка PCILeech)**: Само клиентское программное обеспечение `pcileech` может выполнять операции чтения/записи в память и пространство конфигурации через вашу FPGA и может использоваться для тестирования базовой функциональности DMA. Хотя это не "анализатор трафика", он необходим для тестирования функционального интерфейса. * **Шаги**: 1. **Установите необходимые инструменты/плагины**: Убедитесь, что инструмент установлен и все необходимые драйверы или плагины настроены. 2. **Мониторинг шины PCIe**: Запустите программный инструмент для захвата и отображения информации, связанной с PCIe. 3. **Анализ коммуникаций**: * Ищите расхождения в конфигурации устройства. * Если инструмент поддерживает это, анализируйте структуру захваченных пакетов на наличие аномалий или ошибок. * Убедитесь, что ваше эмулируемое устройство правильно отвечает на запросы конфигурации. --- ## **13. Устранение неполадок** В этом разделе приведены решения распространенных проблем, с которыми вы можете столкнуться при разработке пользовательской прошивки, программировании битстрима и аппаратном тестировании вашей эмуляции устройства PCIe. Отладка прошивки может быть сложной, поэтому методический подход является ключевым. ### **13.1. Проблемы с обнаружением устройства** **Проблема**: Ваше DMA-устройство на базе FPGA, после программирования, не распознается хост-системой, или оно отображается с некорректными ID (например, "Неизвестное устройство") или с символом ошибки в Диспетчере устройств/lspci. #### **Возможные причины и решения**: 1. **Некорректные Device ID, Vendor ID, Subsystem ID или Class Code**: * **Причина**: Наиболее распространенная причина. Существует несоответствие между идентификационными значениями, запрограммированными в вашу прошивку FPGA, и тем, что ожидает операционная система хоста, или тем, что вы намереваетесь эмулировать. * **Решение**: * **Проверьте**: Дважды проверьте все параметры `cfg_deviceid`, `cfg_vendorid`, `cfg_subsysid`, `cfg_subsysvendorid`, `cfg_revisionid` и `cfg_classcode` в `pcileech_pcie_cfg_a7.sv` (или эквивалентном файле) по отношению к тщательно записанной информации о вашем устройстве-доноре (из Раздела 5). * **Согласованность**: Убедитесь, что эти значения также последовательно установлены в графическом интерфейсе настройки IP-ядра PCIe Vivado (Раздел 7.2.2). * **Пересборка и перепрошивка**: После любых изменений всегда проводите повторный синтез, повторную реализацию, генерируйте новый битстрим и перепрошивайте FPGA (Разделы 11.1, 11.2). * **Перезагрузка хоста**: Всегда перезагружайте хост-систему после прошивки, так как Windows часто требует полной перезагрузки для корректного повторного перечисления устройств PCIe. 2. **Сбой обучения канала PCIe**: * **Причина**: Фундаментальный канал PCIe между корневым комплексом хоста и вашей картой FPGA не может быть установлен. Это происходит до любых чтений пространства конфигурации. Симптомы включают полное отсутствие устройства (lspci ничего не показывает на этой шине/слоте, или Диспетчер устройств показывает ошибку "PCI Express Root Port"). * **Решение**: * **Физические соединения**: Убедитесь, что плата FPGA плотно вставлена в слот PCIe и все силовые соединения надежны. Попробуйте другой слот PCIe, если доступен. * **Питание**: Убедитесь, что плата FPGA получает достаточное питание. Некоторым платам требуются дополнительные разъемы питания PCIe. * **Скорость/ширина канала**: * Проверьте настройки `Max Link Speed` и `Link Width` в вашем IP-ядре PCIe Vivado (Раздел 8.1.1). * Попробуйте установить скорость канала на более низкое поколение (например, Gen1 / 2.5 GT/s) и ширину на x1, даже если ваша плата поддерживает более высокую скорость. Иногда возникают проблемы совместимости с конкретными материнскими платами на более высоких скоростях. * Проверьте настройки BIOS материнской платы для опций скорости слотов PCIe. * **Сброс**: Убедитесь, что логика сброса FPGA правильно реализована (например, синхронизирована с опорной тактовой частотой PCIe) и правильно активируется/деактивируется при включении/перезагрузке. * **IP-ядро PCIe**: Убедитесь, что IP-ядро PCIe правильно инстанциировано и его тактовые сигналы и сбросы правильно подключены в вашем проекте верхнего уровня. 3. **Проблемы с питанием (недостаточное или нестабильное питание)**: * **Причина**: Плата FPGA не получает достаточно стабильного питания, или блок питания шумит, что приводит к ненадежной работе. * **Решение**: * **Проверьте соединения**: Дважды проверьте все кабели питания (питание основного слота PCIe, дополнительное питание PCIe, внешний разъем постоянного тока, если используется). * **Блок питания**: Убедитесь, что блок питания вашей хост-системы (PSU) имеет достаточную мощность и стабильные линии 12 В. Для высокомощных FPGA слабый блок питания может вызывать проблемы. * **Внешнее питание**: Если на плате есть внешний разъем питания, убедитесь, что он используется с правильным напряжением и номинальным током. 4. **Ошибки прошивки (ранняя стадия)**: * **Причина**: Логические ошибки в вашем коде SystemVerilog, особенно в модуле верхнего уровня или обертке ядра PCIe, которые препятствуют правильной инициализации или представлению ядра PCIe. * **Решение**: * **Сообщения Vivado**: Внимательно изучите журналы синтеза и реализации Vivado на наличие **критических предупреждений** или **ошибок**, связанных с IP-ядром PCIe. Они часто указывают на неправильные конфигурации или неверные соединения. * **Отладка ILA**: Если канал пытается обучиться, но терпит неудачу, используйте ILA (Раздел 12.1), подключенный к сигналам состояния IP-ядра PCIe (например, `link_up`, `link_speed`, `link_width`) и интерфейсам AXI-Stream, чтобы увидеть, на каком этапе происходит сбой согласования канала или генерирует ли ядро неожиданный трафик. ### **13.2. Ошибки отображения памяти и конфигурации BAR** **Проблема**: Эмулируемое устройство обнаружено, но когда ОС хоста или драйвер пытается получить доступ к его регистрам или буферам, отображаемым на память (через BAR), происходит сбой, зависание или сообщаются ошибки. #### **Возможные причины и решения**: 1. **Неправильные размеры или типы BAR (IP-ядро и прошивка)**: * **Причина**: Размеры или типы BAR (32-бит/64-бит, Память/Ввод-вывод, Предвыбираемые/Непредвыбираемые), настроенные в вашем IP-ядре PCIe Vivado (Раздел 7.2.2) и/или обрабатываемые в вашем `pcileech_tlps128_bar_controller.sv`, не соответствуют тому, что фактически предоставляет устройство-донор. Это может привести к тому, что хост выделит неправильное адресное пространство или попытается выполнить неподдерживаемые обращения. * **Решение**: * **Перепроверка**: Вернитесь к данным Arbor/анализатора протокола (Раздел 5) и повторно проверьте каждую конфигурацию BAR (размер, тип, prefetchable). * **Согласованность**: Убедитесь, что они идеально совпадают в настройках IP-ядра PCIe, и что ваша логика `bar_controller` правильно обрабатывает размер (диапазон декодирования адресов) и тип каждого BAR. * **Размер BRAM**: Если ваши BARы отображаются на BRAM, убедитесь, что размеры IP-ядер BRAM (Раздел 8.2.1) точно соответствуют размерам BAR. 2. **Ошибки декодирования адресов в прошивке**: * **Причина**: Ваш `pcileech_tlps128_bar_controller.sv` (или пользовательская логика BAR) неправильно интерпретирует входящие адреса PCIe, что приводит к доступу к некорректным внутренним регистрам или ячейкам памяти. * **Решение**: * **Просмотрите логику**: Тщательно проверьте операторы `case` и расчеты адресов в вашем `bar_controller`. * **Симуляция**: Разработайте конкретные тестовые примеры в вашем тестовом стенде SystemVerilog для имитации операций чтения/записи хоста по различным смещениям внутри каждого BAR. Убедитесь, что внутренние сигналы `bar_hit` верны и что данные направляются в/из правильных внутренних регистров/BRAM. * **Отладка ILA**: Разместите пробники ILA на `req_addr`, `req_write`, `req_read`, `req_data`, `rsp_data` и внутренних сигналах, связанных с декодированием адресов и доступом к регистрам в `bar_controller`. Наблюдайте, как декодируется адрес и какие данные считываются/записываются в реальном времени. 3. **Перекрывающиеся адресные пространства (внутренние)**: * **Причина**: Хотя стандарт PCIe гарантирует, что BAR разных устройств не перекрываются в карте памяти хоста, *внутри* вашей FPGA вы можете случайно отобразить разные логические компоненты на одно и то же физическое адресное пространство внутри одного BAR. * **Решение**: * **Осторожное отображение**: При определении внутренних регистров и блоков памяти в пределах BAR явно назначайте каждому уникальные, неперекрывающиеся смещения. Используйте `localparam` для этих смещений, чтобы предотвратить ошибки. * **Просмотр проекта**: Необходим тщательный просмотр вашего `bar_controller`, чтобы убедиться, что каждый диапазон адресов обрабатывается уникальным образом. 4. **Проблемы с доступом к BRAM**: * **Причина**: Проблемы с интерфейсом вашей логики к IP-ядрам BRAM (например, некорректная тактовая частота BRAM, асинхронные сбросы, неверные разрешения на запись байтов или некорректная логика разрешения записи). * **Решение**: * **Документация BRAM**: Обратитесь к документации IP-ядра BRAM Xilinx для правильного создания экземпляров и сигналов интерфейса. * **ILA**: Разместите пробники ILA на сигналах интерфейса BRAM (адрес, разрешение на запись, входные данные, выходные данные), чтобы убедиться, что ваша логика отправляет правильные управляющие сигналы BRAM. ### **13.3. Ошибки производительности DMA и TLP** **Проблема**: Устройство обнаружено и функционально, кажется, работает, но скорость передачи данных низкая, или система испытывает периодические сбои, зависания или ошибки во время больших операций DMA. Анализаторы протокола PCIe сообщают о некорректных TLP или проблемах с управлением потоком. #### **Возможные причины и решения**: 1. **Некорректно сформированные TLP-пакеты (заголовок/полезная нагрузка)**: * **Причина**: Ваша прошивка генерирует TLP-пакеты (особенно завершения или исходящие записи в память, если ваша FPGA действует как мастер DMA) с некорректными заголовками, длинами, разрешениями на байты или полезными нагрузками. Ядро PCIe хост-системы или драйвер обнаруживают их как нарушения. * **Решение**: * **Анализатор протокола PCIe**: Это лучший инструмент здесь (Раздел 12.2.1). Захватите трафик и тщательно сравните ваши сгенерированные TLP-пакеты со спецификацией PCIe и, что более важно, с захватами с вашего *реального устройства-донора*. * **Логика генерации TLP**: Просмотрите ваш код сборки TLP-пакетов (`pcileech_pcie_tlp_a7.sv` и связанные модули). Убедитесь, что все поля (Fmt, Type, Requester ID, Tag, Completion ID, Length, Byte Enables, Address) правильно получены и упакованы в структуру TLP-пакета. * **Проверка ошибок**: Реализуйте базовую проверку ошибок в вашей прошивке (например, проверку на неожиданный `req_valid` без `req_ready` или наоборот). 2. **Проблемы с управлением потоком**: * **Причина**: PCIe использует механизм управления потоком на основе кредитов. Если ваша прошивка (или взаимодействие IP-ядра PCIe с ней) неправильно управляет кредитами, это может привести к взаимоблокировкам, таймаутам или потере пакетов. Симптомы включают "застопоренный" канал PCIe, таймауты или низкую пропускную способность. * **Решение**: * **Конфигурация IP-ядра PCIe**: Убедитесь, что настройки управления потоком в графическом интерфейсе настройки IP-ядра PCIe Vivado соответствуют вашим ожидаемым шаблонам трафика. Настройки по умолчанию обычно надежны. * **Обратное давление пользовательской логики**: Ваша пользовательская логика, отправляющая TLP-пакеты в IP-ядро PCIe (интерфейс `m_axis_tx_*`), *должна* учитывать сигнал `m_axis_tx_tready` от IP-ядра. Если `tready` деактивирован, вы *должны* приостановить отправку данных. Невыполнение этого приведет к переполнению буферов ядра. * **Отладка ILA**: Подключите пробники ILA к сигналам интерфейса управления потоком IP-ядра PCIe и вашей пользовательской логики, чтобы наблюдать, правильно ли работает квитирование `tvalid`/`tready`. 3. **Неэффективная логика DMA / проблемы с буферизацией**: * **Причина**: Ваша реализация DMA-движка внутри FPGA (часть, которая считывает/записывает данные из/в память хоста) не оптимизирована, что создает узкие места. Это может включать: * Отсутствие конвейеризации. * Неэффективное использование BRAM. * Задержки из-за задержки доступа к внешней памяти. * Малые размеры пакетов. * **Решение**: * **Конвейеризация**: Разделите длинные комбинационные пути на более мелкие, последовательные стадии с использованием регистров. Это позволяет увеличить тактовую частоту и улучшить пропускную способность. * **Буферизация**: Используйте FIFOs (буферы "первым пришел - первым вышел") для разделения логики отправителя и получателя, сглаживая поток данных и предотвращая задержки. * **Пакетные передачи**: Используйте возможность PCIe выполнять пакетные чтения/записи для эффективности. Убедитесь, что ваша логика DMA запрашивает и обрабатывает данные в соответствующих размерах пакетов. * **Пропускная способность памяти**: Убедитесь, что ваши BRAM или внешние интерфейсы памяти DDR способны обеспечивать/потреблять данные достаточно быстро для желаемых скоростей DMA. * **ILA**: Отслеживайте внутреннее состояние вашего DMA-движка, указатели чтения/записи и сигналы путей данных для выявления узких мест. 4. **Таймаут завершения / Неподдерживаемый запрос**: * **Причина**: Хост отправляет запрос (например, MRd, CfgRd), но ваше устройство FPGA не отвечает TLP-пакетом завершения в течение разрешенного периода таймаута, или оно отвечает со статусом ошибки (например, завершение с неподдерживаемым запросом (UR) или прерыванием завершения (CA)). * **Решение**: * **Логика ответа**: Убедитесь, что ваш `bar_controller` (для MRd) и `pcileech_pcie_cfg_a7.sv` (для CfgRd к пользовательскому пространству конфигурации) правильно идентифицируют запрос и генерируют соответствующее завершение. * **Значение таймаута**: Просмотрите ожидаемую задержку завершения вашего устройства-донора. Хотя PCIe определяет таймауты по умолчанию, некоторые драйверы могут быть чувствительны. * **ILA/Анализатор протокола**: Крайне важны для выяснения *почему* завершение не отправляется или почему оно некорректно. Достигает ли TLP-запрос вообще вашей пользовательской логики? Генерирует ли ваша логика ответ? Успешно ли ядро PCIe отправляет ответ? --- ## **14. Точность эмуляции и оптимизация** Достижение по-настоящему убедительной эмуляции означает сделать ваше устройство на базе FPGA неотличимым от донора не только по ID, но и по его поведению. Это требует пристального внимания к временным характеристикам, отзывчивости и тонким операционным деталям. ### **14.1. Методы для точной эмуляции временных характеристик** Точная синхронизация имеет первостепенное значение в аппаратном обеспечении, особенно для высокоскоростных интерфейсов, таких как PCIe. Несоответствия могут привести к таймаутам драйверов, неправильной интерпретации данных или нестабильности системы. * **Реализация временных ограничений (файлы XDC)**: * **Назначение**: Временные ограничения — это инструкции для инструментов синтеза и реализации Vivado, сообщающие им, насколько быстро должен работать ваш проект. Они определяют периоды тактовых импульсов, задержки ввода/вывода и задержки путей. * **Использование**: Проект PCILeech-FPGA включает файлы XDC (например, `pcileech_squirrel_top.xdc`), которые определяют основные тактовые импульсы (например, `create_clock -name sys_clk_p -period 8.0 [get_ports sys_clk_p]`). * **Уточнение**: Если ваша эмуляция требует очень специфических внутренних временных характеристик или реагирует на чувствительные ко времени команды, вам может потребоваться добавить дополнительные ограничения для критических путей (`set_max_delay`, `set_input_delay`, `set_output_delay`) в вашей пользовательской логике. * **Цель**: Убедитесь, что Vivado сообщает **положительный WNS (Worst Negative Slack)** для всех путей после реализации, что указывает на соответствие проекта его временным требованиям. * **Использование методов перехода между тактовыми доменами (CDC)**: * **Назначение**: Проекты PCIe часто включают несколько тактовых доменов (например, пользовательский тактовый сигнал PCIe 125 МГц, отдельный тактовый сигнал для вашей пользовательской логики). Перемещение сигналов между этими доменами асинхронно (без надлежащей синхронизации) может привести к **метастабильности**, вызывая ненадежное поведение. * **Реализация**: Всегда используйте правильные схемы CDC для сигналов, пересекающих тактовые домены: * **Двухтриггерные синхронизаторы**: Для однобитовых управляющих сигналов. * **Асинхронные FIFO (First-In, First-Out)**: Для многобитовых путей данных, обеспечивающие буферизацию и управление потоком между тактовыми доменами. * **Кодировщики/декодировщики Грея**: Для счетчиков или адресов, пересекающих домены, чтобы гарантировать изменение только одного бита за раз. * **Инструменты Vivado**: Vivado включает инструменты анализа CDC (например, `report_cdc`), которые могут выявлять потенциальные проблемы метастабильности. * **Моделирование поведения устройства с временными моделями**: * **Расширенные тестовые стенды**: Используйте тестовые стенды SystemVerilog, которые включают реалистичные временные задержки или даже предоставляют временные функциональные модели шины PCIe (BFM). * **Проверка**: Это позволяет вам наблюдать, как внутреннее состояние вашего эмулируемого устройства и временные характеристики генерации/ответа TLP-пакетов ведут себя в различных условиях, гарантируя их соответствие захваченному поведению устройства-донора. ### **14.2. Динамический отклик на системные вызовы** Действительно точная эмуляция не просто представляет правильные идентификаторы; она также интеллектуально и динамично реагирует на команды и запросы хост-системы, имитируя поведение реального, активного устройства. * **Реализация конечных автоматов для управления устройством**: * **Назначение**: Разработайте надежные конечные автоматы SystemVerilog, которые управляют режимами работы устройства, обработкой команд и потоком данных. * **Отзывчивость**: Убедитесь, что конечный автомат переходит логически и быстро в ответ на входящие команды (например, записи в управляющие регистры в BAR, специфические TLP-пакеты). * **Корректная обработка**: Конечный автомат должен уметь корректно обрабатывать неожиданные или внеочередные запросы, возможно, возвращая TLP-пакет ошибки или просто игнорируя недопустимые команды, вместо сбоя или зависания. * **Мониторинг и отклик на команды хоста (помимо простых операций чтения/записи)**: * **Записи конфигурации**: Помимо первоначального перечисления, драйверы часто записывают данные в регистры пространства конфигурации, чтобы включить функции, установить пороги или очистить биты состояния. Ваша прошивка должна обрабатывать эти записи и соответствующим образом обновлять внутреннее состояние. * **Команды, специфичные для поставщика**: Как обсуждалось в Разделе 9.2, если устройство-донор имеет проприетарные команды (доступ к которым осуществляется через пользовательские регистры или сообщения, определяемые поставщиком), ваша прошивка должна анализировать эти команды и запускать соответствующее эмулируемое поведение. * **Команды управления питанием**: Реагируйте на инициированные хостом переходы состояний питания (D0, D1, D3hot и т.д.), включая/отключая внутреннюю логику и подтверждая изменение состояния. * **Подтверждение прерывания**: Если драйвер хоста подтверждает прерывания записью в определенный регистр, убедитесь, что ваша прошивка может обнаружить это и сбросить внутренний запрос на прерывание. * **Оптимизация логики прошивки для повышения отзывчивости**: * **Уменьшение задержки**: Критически важные пути данных и управляющие пути должны быть оптимизированы для минимизации глубины комбинационной логики и задержек конвейера. * **Параллелизм**: Используйте присущий FPGA параллелизм для одновременного выполнения нескольких операций, что улучшает пропускную способность и время отклика. * **Эффективный доступ к памяти**: Оптимизируйте доступ к внутренним BRAM или внешней памяти DDR, чтобы обеспечить доступность данных по мере необходимости для передач DMA или чтения регистров. * **Аппаратное ускорение**: Для сложных вычислений или манипуляций с данными, которые выполняет устройство-донор, рассмотрите возможность реализации выделенных аппаратных ускорителей на FPGA, вместо попытки выполнять их медленным, программным способом. --- ## **15. Лучшие практики разработки прошивок** Соблюдение лучших практик в разработке пользовательской прошивки крайне важно для поддержания качества кода, облегчения сотрудничества (при работе в команде), упрощения отладки и обеспечения долгосрочной поддерживаемости и надежности вашего проекта. Это особенно актуально для приложений, чувствительных к безопасности. ### **15.1. Непрерывное тестирование и документирование** * **Регулярное, инкрементальное тестирование**: * **Модульное тестирование**: Тестируйте небольшие, отдельные модули (например, анализатор TLP, блок регистров) изолированно, используя выделенные тестовые стенды. * **Интеграционное тестирование**: Убедитесь, что различные модули работают вместе корректно. * **Системное тестирование**: После прошивки выполните сквозные тесты с хост-системой, чтобы убедиться в общей функциональности. * **Тестируйте рано, тестируйте часто**: Тестируйте прошивку после каждого значительного изменения, независимо от того, насколько оно мало, чтобы выявить проблемы на ранней стадии, когда их легче отладить. * **Автоматизированное тестирование (расширенное)**: * Для сложных проектов реализуйте автоматизированные тестовые скрипты (например, с использованием Python с уровнем аппаратной абстракции) на стороне хоста для многократной проверки функциональности и производительности. * Рассмотрите возможность интеграции с инструментами непрерывной интеграции (CI) (например, Jenkins, GitLab CI) в командной среде для автоматизации сборок, тестов и статического анализа при каждом коммите кода. * **Поддерживайте всеобъемлющую документацию**: * **Документы по проектированию**: Создавайте и обновляйте документы, описывающие архитектуру вашей прошивки, включая: * **Блок-схемы**: Иллюстрирующие основные модули и их взаимосвязи. * **Диаграммы конечных автоматов**: Для всей логики с состоянием. * **Спецификации интерфейсов**: Подробно описывающие входные/выходные сигналы, временные характеристики и протоколы между модулями. * **Карты памяти**: Для всех BAR, определяющие адреса регистров, битовые поля и их функциональность. * **Комментарии к коду**: Используйте четкие, лаконичные комментарии в вашем коде SystemVerilog для объяснения сложной логики, назначения сигналов и любых неочевидных дизайнерских решений. * **Журнал изменений/сообщения коммитов**: Ведите журнал изменений или используйте подробные сообщения коммитов Git для отслеживания всех модификаций, исправлений ошибок и добавлений функций, объясняя *почему* были внесены изменения. * **Руководство пользователя**: Для вашей пользовательской прошивки бесценным является простое руководство пользователя, объясняющее, как собирать, прошивать и взаимодействовать с эмулируемым устройством со стороны хоста. ### **15.2. Управление версиями прошивки** Правильный контроль версий необходим для отслеживания изменений, эффективного сотрудничества (если работаете в команде) и управления выпусками. * **Используйте системы контроля версий (VCS)**: * **Git**: Настоятельно рекомендуется. Используйте Git для управления исходным кодом HDL, файлами ограничений и скриптами проекта. * **Организуйте репозиторий**: Поддерживайте четкую структуру каталогов (например, отдельные папки для `src`, `xdc`, `ip`, `scripts`, `doc`). * **Ветви**: Используйте ветви функций для разработки новых возможностей или крупных изменений. Объединяйте обратно в ветку `main` или `develop` после тщательного тестирования. * **Регулярные коммиты**: Коммитьте часто с атомарными, осмысленными сообщениями коммитов. * **Отмечайте выпуски и вехи**: * **Стабильные версии**: Используйте теги Git (например, `v1.0.0`, `v1.0.1_bugfix`) для отметки стабильных, протестированных версий вашей прошивки. Это облегчает откат или развертывание заведомо работоспособного состояния. * **Вехи**: Отмечайте значимые вехи разработки (например, "Базовое перечисление работает", "Чтение/запись DMA функционально"). * **Стратегия резервного копирования и восстановления**: * **Облачные репозитории**: Размещайте ваш репозиторий Git на платформах, таких как GitHub, GitLab или Bitbucket. Это обеспечивает резервное копирование вне сайта и облегчает сотрудничество. * **Локальные резервные копии**: Даже с облачными репозиториями регулярно создавайте локальные резервные копии всего каталога вашего проекта Vivado (который может быть очень большим из-за сгенерированных файлов). ### **15.3. Вопросы безопасности** Разработка пользовательской прошивки для эмуляции устройств PCIe, особенно способной к прямому доступу к памяти, имеет значительные последствия для безопасности. Эта технология по своей сути является "двойного назначения", что означает, что она может использоваться как для законных (например, тестирование оборудования, исследования безопасности), так и для вредоносных целей (например, атаки DMA, обход защиты). **Крайне важно понимать и ответственно управлять этими рисками.** * **Двойное назначение и этические последствия**: * **Этичный хакинг против вредоносного использования**: Четко различайте использование этих знаний для авторизованного тестирования безопасности (red teaming, тестирование на проникновение) и несанкционированной, незаконной деятельности. * **Ответственное разглашение**: Если вы обнаружите уязвимости, используя эти методы, следуйте рекомендациям по ответственному разглашению. * **Соблюдение законодательства и лицензий**: Ознакомьтесь и соблюдайте все соответствующие законы, правила и лицензионные соглашения (например, спецификации PCIe-SIG, лицензионные соглашения Xilinx) относительно обратного инжиниринга оборудования и модификации устройств. * **"Вооружение"**: Признайте, что возможность точно эмулировать доверенное оборудование может быть использована для постоянных угроз повышенной сложности (APT) или сложного вредоносного ПО. * **Понимание векторов атак (наступательная перспектива)**: * **Эксфильтрация памяти**: Вредоносное эмулируемое устройство может выполнять операции чтения DMA для доступа к любому физическому адресу памяти, включая конфиденциальные данные в ядре, пользовательских процессах, криптографические ключи или сетевые буферы. * **Инъекция/модификация памяти**: Вредоносное эмулируемое устройство может выполнять операции записи DMA для произвольного изменения памяти, что позволяет: * **Повышение привилегий**: Модификация структур данных ядра (например, токенов процессов, SID) для получения прав администратора или системных привилегий. * **Инъекция кода**: Внедрение вредоносного кода в запущенные процессы или ядро, а затем запуск его выполнения. * **Обход защитного ПО**: Отключение или подрыв систем обнаружения и реагирования на конечных точках (EDR), антивирусного или брандмауэрного программного обеспечения путем прямого изменения их памяти. * **Фаззинг и сбои**: Отправка некорректных или не соответствующих спецификации TLP-пакетов/команд для выявления уязвимостей драйверов, что приводит к сбоям системы (BSOD) или потенциально эксплуатируемому повреждению памяти. * **Манипуляции с прошивкой/BIOS**: В некоторых продвинутых сценариях DMA-устройство может взаимодействовать с SPI-флэш-памятью хоста, содержащей BIOS/UEFI, потенциально для постоянной модификации. * **Меры защиты и стратегии смягчения (оборонительная перспектива)**: * **IOMMU/VT-d/AMD-Vi**: Как отмечалось в Разделе 3.2, эти технологии предназначены для смягчения DMA-атак путем обеспечения защиты памяти для периферийных устройств. **Для законного тестирования вы их отключаете, но в производственных системах они всегда должны быть включены.** Они предотвращают несанкционированный доступ к памяти периферийными устройствами. * **Защита DMA на уровне ядра (Windows) / Безопасность Thunderbolt (Linux)**: Современные функции ОС специально предназначены для борьбы с DMA-атаками "холодной загрузки" (когда злоумышленник подключает вредоносное устройство, пока система выключена или заблокирована). Держите их включенными на производственных системах. * **Безопасная загрузка (Secure Boot)**: Хотя это не прямая защита DMA, Secure Boot помогает гарантировать, что загружаются только доверенные загрузчики и модули ядра, что снижает вероятность внедрения злоумышленником вредоносных компонентов ядра для обхода DMA-защит. * **Физическая безопасность**: Самая базовая, но критически важная защита. Если злоумышленник имеет физический доступ к слоту PCIe или порту Thunderbolt, он может обойти многие программные защиты. Обеспечьте безопасный физический доступ к критически важным системам. * **Укрепление драйверов**: Драйверы должны быть написаны с учетом защиты, строго проверяя все входные данные от оборудования и работая в строгих границах памяти. * **Укрепление памяти**: Защита памяти на уровне ОС (например, KASLR, DEP, SMAP/SMEP) помогает уменьшить влияние повреждения памяти, но прямая DMA-атака обходит эти защиты. * **Мониторинг и логирование**: Хотя это сложно на аппаратном уровне, необычная активность DMA или обнаружение неизвестных устройств PCIe должно вызывать оповещения в системах мониторинга безопасности. * **Практики безопасного кодирования прошивки**: * **Валидация входных данных**: Если ваша прошивка принимает какие-либо входные данные (например, через отладочный интерфейс UART или внутренние регистры, записываемые хостом), тщательно проверяйте их, чтобы предотвратить переполнение буфера, переполнение целых чисел или неожиданное поведение. * **Минимальные привилегии**: Проектируйте логику вашей прошивки так, чтобы она выполняла только те операции, которые абсолютно необходимы для ее функции. Избегайте предоставления ненужных возможностей. * **Управление состоянием**: Реализуйте надежные конечные автоматы для предотвращения непреднамеренного поведения из-за недопустимых переходов состояний. * **Отсутствие жестко закодированных секретов**: Избегайте встраивания конфиденциальной информации (например, криптографических ключей, жестко закодированных учетных данных) непосредственно в вашу прошивку, если ее можно легко извлечь. * **Обнаружение несанкционированного доступа**: Для производственной прошивки рассмотрите возможность реализации механизмов для обнаружения того, была ли сама прошивка изменена или загружены ли несанкционированные конфигурации. --- ## **16. Дополнительные ресурсы** Для углубления вашего понимания и поддержания актуальности в динамичных областях разработки FPGA, PCIe и аппаратной безопасности обратитесь к следующим ресурсам: * **Документация Xilinx (AMD)**: Ваш основной источник всей информации о Vivado и FPGA Xilinx. * **Главный портал документации**: [https://docs.amd.com/](https://docs.amd.com/) (ранее Xilinx.com/support/documentation). * **Руководства пользователя Vivado Design Suite**: * **UG900 - Начало работы**: Необходим для новых пользователей Vivado. * **UG901 - Синтез логики**: Глубокое погружение в синтез. * **UG904 - Реализация**: Подробное руководство по размещению и трассировке. * **UG912 - Справочное руководство по командам Tcl**: Бесценно для написания скриптов. * **UG939 - Отладка**: Всеобъемлющее руководство по ILA и другим функциям отладки. * **Руководство пользователя IP-ядра PCI Express**: Крайне важно для понимания IP-ядра PCIe Xilinx (например, **PG054 для встроенного блока PCI Express 7-й серии**). Ищите "PCI Express" на портале документации. В нем подробно описаны конфигурация ядра, интерфейсы и ограничения. * * **Спецификации PCI-SIG**: Определяющий источник стандарта PCIe. * **Базовая спецификация PCI Express**: Фундаментальный документ. Хотя он не является общедоступным и бесплатным, широко доступны его резюме и обучающие материалы. Обычно информацию можно найти на их веб-сайте: [https://pcisig.com/specifications](https://pcisig.com/specifications) (Примечание: полные спецификации обычно требуют членства в PCI-SIG). * **Учебные пособия и платформы для изучения FPGA**: * **FPGA4Fun**: [http://www.fpga4fun.com/](http://www.fpga4fun.com/) – Классический сайт со множеством практических проектов и учебных пособий по FPGA. * **Учебные пособия по Verilog/VHDL**: * **Учебные пособия по Verilog на ASIC World**: [https://www.asic-world.com/verilog/index.html](https://www.asic-world.com/verilog/index.html) – Хороший фундаментальный справочник по Verilog. * **VHDLwhiz**: [https://www.vhdlwhiz.com/](https://www.vhdlwhiz.com/) – Справочник и учебные пособия по VHDL. * **Stack Overflow (теги FPGA/Verilog/PCIe)**: [https://stackoverflow.com/questions/tagged/fpga](https://stackoverflow.com/questions/tagged/fpga) – Q&A, управляемый сообществом, для решения конкретных технических проблем. * **Инструменты анализа протокола PCIe**: * **Анализаторы протокола Teledyne LeCroy**: [https://teledynelecroy.com/protocolanalyzer/](https://teledynelecroy.com/protocolanalyzer/) – Изучите их ассортимент высокопроизводительных анализаторов PCIe и программного обеспечения. * **Программное обеспечение Telescan PE**: [https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software](https://www.teledynelecroy.com/protocolanalyzer/pci-express/telescan-pe-software/resources/analysis-software) – Бесплатный программный инструмент, предоставляющий некоторые функции анализа PCIe (требуется регистрация). * **Сообщество и ресурсы PCILeech**: * Репозиторий `ufrisk/pcileech` на GitHub — это основа проекта. Активно следите за его обновлениями и проблемами. * Ищите форумы сообщества или Discord-серверы, посвященные PCILeech или аналогичным проектам DMA с открытым исходным кодом. * **Аппаратная безопасность и обратный инжиниринг**: * Книги по аппаратному хакингу, обратному инжинирингу и низкоуровневой эксплуатации систем. * Конференции, такие как Black Hat, DEF CON, Recon и Troopers, часто включают доклады по атакам на PCIe и DMA. * Блоги и исследовательские статьи от исследователей безопасности, специализирующихся на аппаратном обеспечении. --- ## **17. Контактная информация** Если вам нужна помощь, у вас есть вопросы или вы хотите сотрудничать по темам, связанным с этим руководством, разработкой прошивок или аппаратной безопасностью, пожалуйста, не стесняйтесь обращаться. Я готов предоставить руководство, помочь в решении сложных проблем или обсудить идеи в деталях. ### **Discord**: * **Пользователь**: [**VCPU**](https://discord.com/users/196741541094621184) * **Ссылка-приглашение на сервер**: [**Присоединиться к Discord-серверу по аппаратному хакингу и разработке прошивок**](https://discord.gg/dS2gDUDQmV) --- ## **18. Поддержка и вклад** Ваша поддержка помогает поддерживать и улучшать это руководство и связанные с ним проекты. Создание и обновление всеобъемлющей технической документации и проектов аппаратного обеспечения с открытым исходным кодом требует значительных временных и трудовых затрат. ### **Пожертвования** Если вы нашли это руководство полезным и хотите поддержать текущую работу, рассмотрите возможность внесения вклада. Каждое пожертвование, независимо от размера, помогает продолжать создавать, делиться и поддерживать сообщество через дальнейшие исследования, разработки и усилия по документированию. * **Криптовалютные пожертвования (LTC - Litecoin)**: * **Адрес**: `MPMyQD5zgy2b2CpDn1C1KZ31KmHpT7AwRi` **Специальный бонус**: Если вы сделаете пожертвование, пожалуйста, свяжитесь со мной в Discord (VCPU), чтобы получить личную благодарность и, возможно, доступ к дополнительным ресурсам, ранний доступ к новому контенту или персонализированную помощь с вашим проектом. **Примечание**: Если вам нужно, чтобы я просмотрел определенные разделы вашей реализации, устранил проблемы или предоставил подробный отзыв о вашем коде, пожалуйста, пометьте соответствующие разделы в вашем коде комментариями `//VCPU-REVIEW//` и предоставьте подробные объяснения проблем или вопросов, с которыми вы сталкиваетесь. Это поможет мне сосредоточить свои усилия и предоставить наиболее эффективную поддержку. Да благословит Бог вашу душу. --- **Конец руководства** ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/bin/ch347.cfg ================================================ # 指定CH347-JTAG 调试器 adapter driver ch347 ch347 vid_pid 0x1a86 0x55dd # 设置TCK时钟频率 adapter speed 10000 source [find cpld/xilinx-xc7.cfg] # source [find cpld/jtagspi.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/contrib/60-openocd.rules ================================================ # Copy this file to /etc/udev/rules.d/ # If rules fail to reload automatically, you can refresh udev rules # with the command "udevadm control --reload" ACTION!="add|change", GOTO="openocd_rules_end" SUBSYSTEM=="gpio", MODE="0660", GROUP="plugdev", TAG+="uaccess" SUBSYSTEM!="usb|tty|hidraw", GOTO="openocd_rules_end" # Please keep this list sorted by VID:PID # opendous and estick ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204f", MODE="660", GROUP="plugdev", TAG+="uaccess" # Original FT232/FT245 VID:PID ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="660", GROUP="plugdev", TAG+="uaccess" # Original FT2232 VID:PID ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess" # Original FT4232 VID:PID ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="660", GROUP="plugdev", TAG+="uaccess" # Original FT232H VID:PID ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="660", GROUP="plugdev", TAG+="uaccess" # Original FT231XQ VID:PID ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", MODE="660", GROUP="plugdev", TAG+="uaccess" # DISTORTEC JTAG-lock-pick Tiny 2 ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8220", MODE="660", GROUP="plugdev", TAG+="uaccess" # TUMPA, TUMPA Lite ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a98", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a99", MODE="660", GROUP="plugdev", TAG+="uaccess" # Marvell OpenRD JTAGKey FT2232D B ATTRS{idVendor}=="0403", ATTRS{idProduct}=="9e90", MODE="660", GROUP="plugdev", TAG+="uaccess" # XDS100v2 ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d0", MODE="660", GROUP="plugdev", TAG+="uaccess" # XDS100v3 ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d1", MODE="660", GROUP="plugdev", TAG+="uaccess" # OOCDLink ATTRS{idVendor}=="0403", ATTRS{idProduct}=="baf8", MODE="660", GROUP="plugdev", TAG+="uaccess" # Kristech KT-Link ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bbe2", MODE="660", GROUP="plugdev", TAG+="uaccess" # Xverve Signalyzer Tool (DT-USB-ST), Signalyzer LITE (DT-USB-SLITE) ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca1", MODE="660", GROUP="plugdev", TAG+="uaccess" # TI/Luminary Stellaris Evaluation Board FTDI (several) ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd9", MODE="660", GROUP="plugdev", TAG+="uaccess" # TI/Luminary Stellaris In-Circuit Debug Interface FTDI (ICDI) Board ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcda", MODE="660", GROUP="plugdev", TAG+="uaccess" # egnite Turtelizer 2 ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bdc8", MODE="660", GROUP="plugdev", TAG+="uaccess" # Section5 ICEbear ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c140", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="660", GROUP="plugdev", TAG+="uaccess" # Amontec JTAGkey and JTAGkey-tiny ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="660", GROUP="plugdev", TAG+="uaccess" # ASIX Presto programmer ATTRS{idVendor}=="0403", ATTRS{idProduct}=="f1a0", MODE="660", GROUP="plugdev", TAG+="uaccess" # Nuvoton NuLink ATTRS{idVendor}=="0416", ATTRS{idProduct}=="511b", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0416", ATTRS{idProduct}=="511c", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0416", ATTRS{idProduct}=="511d", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0416", ATTRS{idProduct}=="5200", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0416", ATTRS{idProduct}=="5201", MODE="660", GROUP="plugdev", TAG+="uaccess" # TI ICDI ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="660", GROUP="plugdev", TAG+="uaccess" # STMicroelectronics ST-LINK V1 ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3744", MODE="660", GROUP="plugdev", TAG+="uaccess" # STMicroelectronics ST-LINK/V2 ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE="660", GROUP="plugdev", TAG+="uaccess" # STMicroelectronics ST-LINK/V2.1 ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3752", MODE="660", GROUP="plugdev", TAG+="uaccess" # STMicroelectronics STLINK-V3 ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374d", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374e", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374f", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3753", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3754", MODE="660", GROUP="plugdev", TAG+="uaccess" # Cypress SuperSpeed Explorer Kit ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="0007", MODE="660", GROUP="plugdev", TAG+="uaccess" # Cypress KitProg in KitProg mode ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="f139", MODE="660", GROUP="plugdev", TAG+="uaccess" # Cypress KitProg in CMSIS-DAP mode ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="f138", MODE="660", GROUP="plugdev", TAG+="uaccess" # Infineon DAP miniWiggler v3 ATTRS{idVendor}=="058b", ATTRS{idProduct}=="0043", MODE="660", GROUP="plugdev", TAG+="uaccess" # Hitex LPC1768-Stick ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0026", MODE="660", GROUP="plugdev", TAG+="uaccess" # Hilscher NXHX Boards ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="660", GROUP="plugdev", TAG+="uaccess" # Hitex STR9-comStick ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002c", MODE="660", GROUP="plugdev", TAG+="uaccess" # Hitex STM32-PerformanceStick ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="660", GROUP="plugdev", TAG+="uaccess" # Hitex Cortino ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0032", MODE="660", GROUP="plugdev", TAG+="uaccess" # Altera USB Blaster ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6001", MODE="660", GROUP="plugdev", TAG+="uaccess" # Altera USB Blaster2 ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6810", MODE="660", GROUP="plugdev", TAG+="uaccess" # Ashling Opella-LD ATTRS{idVendor}=="0B6B", ATTRS{idProduct}=="0040", MODE="660", GROUP="plugdev", TAG+="uaccess" # Amontec JTAGkey-HiSpeed ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="660", GROUP="plugdev", TAG+="uaccess" # SEGGER J-Link ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0101", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0102", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0103", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0104", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0105", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0107", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0108", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1010", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1011", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1012", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1013", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1014", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1015", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1016", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1017", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1018", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1020", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1051", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1055", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1061", MODE="660", GROUP="plugdev", TAG+="uaccess" # Raisonance RLink ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="660", GROUP="plugdev", TAG+="uaccess" # Debug Board for Neo1973 ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="660", GROUP="plugdev", TAG+="uaccess" # OSBDM ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="0042", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="0058", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="005e", MODE="660", GROUP="plugdev", TAG+="uaccess" # Olimex ARM-USB-OCD ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="660", GROUP="plugdev", TAG+="uaccess" # Olimex ARM-USB-OCD-TINY ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0004", MODE="660", GROUP="plugdev", TAG+="uaccess" # Olimex ARM-JTAG-EW ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="001e", MODE="660", GROUP="plugdev", TAG+="uaccess" # Olimex ARM-USB-OCD-TINY-H ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="660", GROUP="plugdev", TAG+="uaccess" # Olimex ARM-USB-OCD-H ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002b", MODE="660", GROUP="plugdev", TAG+="uaccess" # ixo-usb-jtag - Emulation of a Altera Bus Blaster I on a Cypress FX2 IC ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="06ad", MODE="660", GROUP="plugdev", TAG+="uaccess" # USBprog with OpenOCD firmware ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="660", GROUP="plugdev", TAG+="uaccess" # TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="660", GROUP="plugdev", TAG+="uaccess" # TI XDS110 Debug Probe (Launchpads and Standalone) ATTRS{idVendor}=="0451", ATTRS{idProduct}=="bef3", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0451", ATTRS{idProduct}=="bef4", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="02a5", MODE="660", GROUP="plugdev", TAG+="uaccess" # TI Tiva-based ICDI and XDS110 probes in DFU mode ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00ff", MODE="660", GROUP="plugdev", TAG+="uaccess" # isodebug v1 ATTRS{idVendor}=="22b7", ATTRS{idProduct}=="150d", MODE="660", GROUP="plugdev", TAG+="uaccess" # PLS USB/JTAG Adapter for SPC5xxx ATTRS{idVendor}=="263d", ATTRS{idProduct}=="4001", MODE="660", GROUP="plugdev", TAG+="uaccess" # Numato Mimas A7 - Artix 7 FPGA Board ATTRS{idVendor}=="2a19", ATTRS{idProduct}=="1009", MODE="660", GROUP="plugdev", TAG+="uaccess" # Ambiq Micro EVK and Debug boards. ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6011", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="1106", MODE="660", GROUP="plugdev", TAG+="uaccess" # Marvell Sheevaplug ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="660", GROUP="plugdev", TAG+="uaccess" # Keil Software, Inc. ULink ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2710", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2750", MODE="660", GROUP="plugdev", TAG+="uaccess" # CMSIS-DAP compatible adapters ATTRS{product}=="*CMSIS-DAP*", MODE="660", GROUP="plugdev", TAG+="uaccess" LABEL="openocd_rules_end" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/contrib/libdcc/README ================================================ This code is an example of using the openocd debug message system. Before the message output is seen in the debug window, the functionality will need enabling: From the gdb prompt: monitor target_request debugmsgs enable monitor trace point 1 From the Telnet prompt: target_request debugmsgs enable trace point 1 To see how many times the trace point was hit: (monitor) trace point 1 Spen spen@spen-soft.co.uk ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/contrib/libdcc/dcc_stdio.c ================================================ /*************************************************************************** * Copyright (C) 2008 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * Copyright (C) 2008 by Frederik Kriewtz * * frederik@kriewitz.eu * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * ***************************************************************************/ #include "dcc_stdio.h" #define TARGET_REQ_TRACEMSG 0x00 #define TARGET_REQ_DEBUGMSG_ASCII 0x01 #define TARGET_REQ_DEBUGMSG_HEXMSG(size) (0x01 | ((size & 0xff) << 8)) #define TARGET_REQ_DEBUGCHAR 0x02 #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_6SM__) /* we use the System Control Block DCRDR reg to simulate a arm7_9 dcc channel * DCRDR[7:0] is used by target for status * DCRDR[15:8] is used by target for write buffer * DCRDR[23:16] is used for by host for status * DCRDR[31:24] is used for by host for write buffer */ #define NVIC_DBG_DATA_R (*((volatile unsigned short *)0xE000EDF8)) #define BUSY 1 void dbg_write(unsigned long dcc_data) { int len = 4; while (len--) { /* wait for data ready */ while (NVIC_DBG_DATA_R & BUSY); /* write our data and set write flag - tell host there is data*/ NVIC_DBG_DATA_R = (unsigned short)(((dcc_data & 0xff) << 8) | BUSY); dcc_data >>= 8; } } #elif defined(__ARM_ARCH_4T__) || defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5T__) void dbg_write(unsigned long dcc_data) { unsigned long dcc_status; do { asm volatile("mrc p14, 0, %0, c0, c0" : "=r" (dcc_status)); } while (dcc_status & 0x2); asm volatile("mcr p14, 0, %0, c1, c0" : : "r" (dcc_data)); } #else #error unsupported target #endif void dbg_trace_point(unsigned long number) { dbg_write(TARGET_REQ_TRACEMSG | (number << 8)); } void dbg_write_u32(const unsigned long *val, long len) { dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(4) | ((len & 0xffff) << 16)); while (len > 0) { dbg_write(*val); val++; len--; } } void dbg_write_u16(const unsigned short *val, long len) { unsigned long dcc_data; dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(2) | ((len & 0xffff) << 16)); while (len > 0) { dcc_data = val[0] | ((len > 1) ? val[1] << 16: 0x0000); dbg_write(dcc_data); val += 2; len -= 2; } } void dbg_write_u8(const unsigned char *val, long len) { unsigned long dcc_data; dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(1) | ((len & 0xffff) << 16)); while (len > 0) { dcc_data = val[0] | ((len > 1) ? val[1] << 8 : 0x00) | ((len > 2) ? val[2] << 16 : 0x00) | ((len > 3) ? val[3] << 24 : 0x00); dbg_write(dcc_data); val += 4; len -= 4; } } void dbg_write_str(const char *msg) { long len; unsigned long dcc_data; for (len = 0; msg[len] && (len < 65536); len++); dbg_write(TARGET_REQ_DEBUGMSG_ASCII | ((len & 0xffff) << 16)); while (len > 0) { dcc_data = msg[0] | ((len > 1) ? msg[1] << 8 : 0x00) | ((len > 2) ? msg[2] << 16 : 0x00) | ((len > 3) ? msg[3] << 24 : 0x00); dbg_write(dcc_data); msg += 4; len -= 4; } } void dbg_write_char(char msg) { dbg_write(TARGET_REQ_DEBUGCHAR | ((msg & 0xff) << 16)); } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/contrib/libdcc/dcc_stdio.h ================================================ /*************************************************************************** * Copyright (C) 2008 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * ***************************************************************************/ #ifndef DCC_STDIO_H #define DCC_STDIO_H void dbg_trace_point(unsigned long number); void dbg_write_u32(const unsigned long *val, long len); void dbg_write_u16(const unsigned short *val, long len); void dbg_write_u8(const unsigned char *val, long len); void dbg_write_str(const char *msg); void dbg_write_char(char msg); #endif /* DCC_STDIO_H */ ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/contrib/libdcc/example.c ================================================ /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * Copyright (C) 2008 by Frederik Kriewtz * * frederik@kriewitz.eu * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * ***************************************************************************/ #include "dcc_stdio.h" /* enable openocd debugmsg at the gdb prompt: * monitor target_request debugmsgs enable * * create a trace point: * monitor trace point 1 * * to show how often the trace point was hit: * monitor trace point */ int main(void) { dbg_write_str("hello world"); dbg_write_char('t'); dbg_write_char('e'); dbg_write_char('s'); dbg_write_char('t'); dbg_write_char('\n'); unsigned long test_u32 = 0x01234567; dbg_write_u32(&test_u32, 1); static const unsigned short test_u16[] = {0x0123, 0x4567, 0x89AB, 0xCDEF, 0x0123, 0x4567, 0x89AB, 0xCDEF}; dbg_write_u16(test_u16, 8); static const unsigned char test_u8[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0XDD, 0xEE, 0xFF}; dbg_write_u8(test_u8, 16); while(1) { dbg_trace_point(0); } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/bitsbytes.tcl ================================================ #---------------------------------------- # Purpose - Create some $BIT variables # Create $K and $M variables # and some bit field extraction variables. # Create helper variables ... # BIT0.. BIT31 for { set x 0 } { $x < 32 } { set x [expr {$x + 1}]} { set vn [format "BIT%d" $x] global $vn set $vn [expr {1 << $x}] } # Create K bytes values # __1K ... to __2048K for { set x 1 } { $x < 2048 } { set x [expr {$x * 2}]} { set vn [format "__%dK" $x] global $vn set $vn [expr {1024 * $x}] } # Create M bytes values # __1M ... to __2048K for { set x 1 } { $x < 2048 } { set x [expr {$x * 2}]} { set vn [format "__%dM" $x] global $vn set $vn [expr {1024 * 1024 * $x}] } proc create_mask { MSB LSB } { return [expr {((1 << ($MSB - $LSB + 1))-1) << $LSB}] } # Cut Bits $MSB to $LSB out of this value. # Example: % format "0x%08x" [extract_bitfield 0x12345678 27 16] # Result: 0x02340000 proc extract_bitfield { VALUE MSB LSB } { return [expr {[create_mask $MSB $LSB] & $VALUE}] } # Cut bits $MSB to $LSB out of this value # and shift (normalize) them down to bit 0. # # Example: % format "0x%08x" [normalize_bitfield 0x12345678 27 16] # Result: 0x00000234 # proc normalize_bitfield { VALUE MSB LSB } { return [expr {[extract_bitfield $VALUE $MSB $LSB ] >> $LSB}] } proc show_normalize_bitfield { VALUE MSB LSB } { set m [create_mask $MSB $LSB] set mr [expr {$VALUE & $m}] set sr [expr {$mr >> $LSB}] echo [format "((0x%08x & 0x%08x) -> 0x%08x) >> %2d => (0x%x) %5d " $VALUE $m $mr $LSB $sr $sr] return $sr } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/8devices-lima.cfg ================================================ # Product page: # https://www.8devices.com/products/lima # # Location of JTAG pins: # J2 GPIO0 JTAG TCK # J2 GPIO1 JTAG TDI # J2 GPIO2 JTAG TDO # J2 GPIO3 JTAG TMS # J2 RST directly connected to RESET_L of the SoC and can be used as # JTAG SRST. Note: this pin will also reset the debug engine. # J1 +3,3V Can be use as JTAG Vref # J1 or J2 GND Can be used for JTAG GND # # This board is powered from mini USB connecter which is also used # as USB to UART converted based on FTDI FT230XQ chip source [find target/qualcomm_qca4531.cfg] proc board_init { } { qca4531_ddr2_550_550_init } $_TARGETNAME configure -event reset-init { board_init } set ram_boot_address 0xa0000000 $_TARGETNAME configure -work-area-phys 0xa1FFE000 -work-area-size 0x1000 flash bank flash0 ath79 0xbf000000 0 0 0 $_TARGETNAME cs0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/actux3.cfg ================================================ # board config file for AcTux3/XBA IXP42x board # Date: 2010-12-16 # Author: Michael Schwingen reset_config trst_and_srst separate adapter srst delay 100 jtag_ntrst_delay 100 source [find target/ixp42x.cfg] $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 0x10000 -work-area-backup 0 $_TARGETNAME configure -event reset-init { init_actux3 } proc init_actux3 { } { ########################################################################## # setup expansion bus CS ########################################################################## mww 0xc4000000 0xbd113842 ;#CS0 : Flash, write enabled @0x50000000 mww 0xc4000004 0x94d10013 ;#CS1 mww 0xc4000008 0x95960003 ;#CS2 mww 0xc400000c 0x00000000 ;#CS3 mww 0xc4000010 0x80900003 ;#CS4 mww 0xc4000014 0x9d520003 ;#CS5 mww 0xc4000018 0x81860001 ;#CS6 mww 0xc400001c 0x80900003 ;#CS7 ixp42x_init_sdram $::IXP42x_SDRAM_16MB_4Mx16_1BANK 2100 3 #mww 0xc4000020 0xffffee ;# CFG0: remove expansion bus boot flash mirror at 0x00000000 ixp42x_set_bigendian flash probe 0 } proc flash_boot { {FILE "/tftpboot/actux3/u-boot.bin"} } { echo "writing bootloader: $FILE" flash write_image erase $FILE 0x50000000 bin } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x50000000 0x400000 2 2 $_TARGETNAME init reset init # setup to debug u-boot in flash proc uboot_debug {} { gdb_breakpoint_override hard xscale vector_catch 0xFF xscale vector_table low 1 0xe59ff018 xscale vector_table low 2 0xe59ff018 xscale vector_table low 3 0xe59ff018 xscale vector_table low 4 0xe59ff018 xscale vector_table low 5 0xe59ff018 xscale vector_table low 6 0xe59ff018 xscale vector_table low 7 0xe59ff018 xscale vector_table high 1 0xe59ff018 xscale vector_table high 2 0xe59ff018 xscale vector_table high 3 0xe59ff018 xscale vector_table high 4 0xe59ff018 xscale vector_table high 5 0xe59ff018 xscale vector_table high 6 0xe59ff018 xscale vector_table high 7 0xe59ff018 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/adapteva_parallella1.cfg ================================================ # # Adapteva Parallella-I board (via Porcupine-1 adapter board) # reset_config srst_only source [find target/zynq_7000.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/adsp-sc584-ezbrd.cfg ================================================ # # Analog Devices ADSP-SC584-EZBRD evaluation board # # Evaluation boards by Analog Devices (and designs derived from them) use a # non-standard 10-pin 0.05" ARM Cortex Debug Connector. In this bastardized # implementation, pin 9 (GND or GNDDetect) has been usurped with JTAG /TRST. # # As a result, a standards-compliant debug pod will force /TRST active, # putting the processor's debug interface into reset and preventing usage. # # A connector adapter must be employed on these boards to isolate or remap # /TRST so that it is only asserted when intended. # Analog expects users to use their proprietary ICE-1000 / ICE-2000 with all # ADSP-SC58x designs, but this is an ARM target (and subject to the # qualifications above) many ARM debug pods should be compatible. #source [find interface/cmsis-dap.cfg] source [find interface/jlink.cfg] # Analog's silicon supports SWD and JTAG, but their proprietary ICE is limited # to JTAG. (This is presumably why their connector pinout was modified.) # SWD is chosen here, as it is more efficient and doesn't require /TRST. transport select swd # chosen speed is 'safe' choice, but your adapter may be capable of more adapter speed 400 source [find target/adsp-sc58x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/alphascale_asm9260_ek.cfg ================================================ source [find target/alphascale_asm9260t.cfg] reset_config trst_and_srst $_TARGETNAME configure -event reset-init { echo "Configure clock" # Enable SRAM clk mww 0x80040024 0x4 # Enable IRQ clk mww 0x80040034 0x100 # Enable DMA0,1 clk mww 0x80040024 0x600 # Make sysre syspll is enabled mww 0x80040238 0x750 #CPU = PLLCLK/2 mww 0x8004017C 0x2 #SYSAHBCLK = CPUCLK/2 mww 0x80040180 0x2 # Set PLL freq to 480MHz mww 0x80040100 480 # normally we shoul waiting here until we get 0x1 (0x80040104)&0x1)==0x0) sleep 100 # select PLL as main source mww 0x80040120 0x1 # disable and enable main clk to update changes? mww 0x80040124 0x0 mww 0x80040124 0x1 echo "Configure memory" #enable EMI CLK mww 0x80040024 0x40 # configure memory controller for internal SRAM mww 0x80700000 0x1188 # change default emi clk delay mww 0x8004034C 0xA0503 # make sure chip_select_register2_low has correct value (why?) mww 0x8070001c 0x20000000 # set type to sdram and size to 32MB mww 0x8070005c 0xa # configure internal SDRAM timing mww 0x80700004 0x024996d9 # configure Static Memory timing mww 0x80700094 0x00542b4f echo "Configure uart4" # enable pinctrl clk mww 0x80040024 0x2000000 # mux GPIO3_0 and GPIO3_1 to UART4 mww 0x80044060 0x2 mww 0x80044064 0x2 # configure UART4CLKDIV mww 0x800401a8 0x1 # enable uart4 clk mww 0x80040024 0x8000 # clear softrst and clkgate on uart4 mww 0x80010008 0xC0000000 # set bandrate 115200 12M mww 0x80010030 0x00062070 # enable Rx&Tx mww 0x80010024 0x301 # clear hw control mww 0x80010028 0xc000 } $_TARGETNAME configure -work-area-phys 0x21ffe000 -work-area-virt 0xc1ffe000 -work-area-size 0x1000 $_TARGETNAME arm7_9 fast_memory_access enable $_TARGETNAME arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/altera_sockit.cfg ================================================ # # Cyclone V SocKit board # http://www.altera.com/b/arrow-sockit.html # # Software support page: # http://www.rocketboards.org/ # openocd does not currently support the on-board USB Blaster II. # Install the JTAG header and use a USB Blaster instead. adapter driver usb_blaster source [find target/altera_fpgasoc.cfg] # If the USB Blaster II were supported, these settings would be needed #usb_blaster vid_pid 0x09fb 0x6810 #usb_blaster device_desc "USB-Blaster II" adapter speed 100 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/am3517evm.cfg ================================================ # DANGER!!!! early work in progress for this PCB/target. # # The most basic operations work well enough that it is # useful to have this in the repository for cooperation # alpha testing purposes. # # TI AM3517 # # http://focus.ti.com/docs/prod/folders/print/am3517.html # http://processors.wiki.ti.com/index.php/Debug_Access_Port_(DAP) # http://processors.wiki.ti.com/index.php?title=How_to_Find_the_Silicon_Revision_of_your_OMAP35x set CHIPTYPE "am35x" source [find target/amdm37x.cfg] # The TI-14 JTAG connector does not have srst. CPU reset is handled in # hardware. reset_config trst_only # "amdm37x_dbginit am35x.cpu" needs to be run after init. ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ampere_emag8180.cfg ================================================ # # OpenOCD Board Configuration for eMAG Development Platform # # Copyright (c) 2019-2021, Ampere Computing LLC # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; # # # # Configure JTAG speed # adapter speed 2000 # # Configure Resets # jtag_ntrst_delay 100 reset_config trst_only # # Configure Targets # source [find target/ampere_emag.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/arm_evaluator7t.cfg ================================================ # This board is from ARM and has an samsung s3c45101x01 chip source [find target/samsung_s3c4510.cfg] # # FIXME: # Add (A) sdram configuration # Add (B) flash cfi programming configuration # ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/arm_musca_a.cfg ================================================ # # Configuration script for ARM Musca-A development board # # For now we do not support Musca A flash programming using OpenOCD. However, a # work area is configured for flash programming speed up. # # GDB considers all memory as RAM unless target supplies a memory map. # OpenOCD will only send memory map if flash banks are configured. Otherwise, # configure GDB after connection by issuing following commands: # (gdb) mem 0x10200000 0x109FFFFF ro # (gdb) mem 0x00200000 0x009FFFFF ro # (gdb) set mem inaccessible-by-default off # ARM Musca A board supports both JTAG and SWD transports. source [find target/swj-dp.tcl] # set a safe JTAG clock speed, can be overridden adapter speed 1000 global _CHIPNAME if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME MUSCA_A } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x6ba00477 } # Enable CPU1 debugging as a separate GDB target set _ENABLE_CPU1 1 # Musca A1 has 32KB SRAM banks. Override default work-area-size to 8KB per CPU set WORKAREASIZE_CPU0 0x2000 set WORKAREASIZE_CPU1 0x2000 # Set SRAM bank 1 to be used for work area. Override here if needed. set WORKAREAADDR_CPU0 0x30008000 set WORKAREAADDR_CPU1 0x3000A000 source [find target/arm_corelink_sse200.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/arty_s7.cfg ================================================ # # Arty S7: Spartan7 25/50 FPGA Board for Makers and Hobbyists # # https://www.xilinx.com/products/boards-and-kits/1-pnziih.html # https://store.digilentinc.com/arty-s7-spartan-7-fpga-board-for-makers-and-hobbyists/ source [find interface/ftdi/digilent-hs1.cfg] # Xilinx Spartan7-25/50 FPGA (XC7S{25,50}-CSGA324) source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] adapter speed 25000 # Usage: # # Load Bitstream into FPGA: # openocd -f board/arty_s7.cfg -c "init;\ # pld load 0 bitstream.bit;\ # shutdown" # # Write Bitstream to Flash: # openocd -f board/arty_s7.cfg -c "init;\ # jtagspi_init 0 bscan_spi_xc7s??.bit;\ # jtagspi_program bitstream.bin 0;\ # xc7_program xc7.tap;\ # shutdown" # # jtagspi flash proxies can be found at: # https://github.com/quartiq/bscan_spi_bitstreams # # For the Spartan 50 variant, use # - https://github.com/quartiq/bscan_spi_bitstreams/raw/master/bscan_spi_xc7s50.bit # For the Spartan 25 variant, use # - https://github.com/quartiq/bscan_spi_bitstreams/raw/master/bscan_spi_xc7s25.bit ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/asus-rt-n16.cfg ================================================ # # http://wikidevi.com/wiki/ASUS_RT-N16 # set partition_list { CFE { Bootloader 0xbc000000 0x00040000 } firmware { "Kernel+rootfs" 0xbc040000 0x01fa0000 } nvram { "Config space" 0xbdfe0000 0x00020000 } } source [find target/bcm4718.cfg] # External 32MB NOR Flash (Macronix MX29GL256EHTI2I-90Q) set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0xbc000000 0x02000000 1 1 $_TARGETNAME x16_as_x8 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/asus-rt-n66u.cfg ================================================ # # http://wikidevi.com/wiki/Asus_RT-N66U # echo "ATTENTION: you need to solder a 4.7-10k pullup resistor to pin 21 of flash IC" echo "to enable JTAG, see http://wl500g.info/album.php?albumid=28&attachmentid=8991 ," echo "there is an unpopulated footprint near U8.\n" set partition_list { CFE { Bootloader 0xbc000000 0x00040000 } firmware { "Kernel+rootfs" 0xbc040000 0x01fa0000 } nvram { "Config space" 0xbdfe0000 0x00020000 } } source [find target/bcm4706.cfg] # External 32MB NOR Flash (Spansion S29GL256P10TF101 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0xbc000000 0x02000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/at91cap7a-stk-sdram.cfg ================================================ # http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4394 # # use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cap7 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x40700f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-start { # start off real slow when we're running off internal RC oscillator adapter speed 32 } proc peek32 {address} { return [read_memory $address 32 1] } # Wait for an expression to be true with a timeout proc wait_state {expression} { for {set i 0} {$i < 1000} {set i [expr {$i + 1}]} { if {[uplevel 1 $expression] == 0} { return } } return -code 1 "Timed out" } # Use a global variable here to be able to tinker interactively with # post reset jtag frequency. global post_reset_khz # Danger!!!! Even 16MHz kinda works with this target, but # it needs to be as low as 2000kHz to be stable. set post_reset_khz 2000 $_TARGETNAME configure -event reset-init { echo "Configuring master clock" # disable watchdog mww 0xfffffd44 0xff008000 # enable user reset mww 0xfffffd08 0xa5000001 # Enable main oscillator mww 0xFFFFFc20 0x00000f01 wait_state {expr {([peek32 0xFFFFFC68] & 0x1) == 0}} # Set PLLA to 96MHz mww 0xFFFFFc28 0x20072801 wait_state {expr {([peek32 0xFFFFFC68] & 0x2) == 0}} # Select prescaler mww 0xFFFFFC30 0x00000004 wait_state {expr {([peek32 0xFFFFFC68] & 0x8) == 0}} # Select master clock to 48MHz mww 0xFFFFFC30 0x00000006 wait_state {expr {([peek32 0xFFFFFC68] & 0x8) == 0}} echo "Master clock ok." # Now that we're up and running, crank up speed! global post_reset_khz ; adapter speed $post_reset_khz echo "Configuring the SDRAM controller..." # Configure EBI Chip select for SDRAM mww 0xFFFFEF30 0x00000102 # Enable clock on EBI PIOs mww 0xFFFFFC10 0x00000004 # Configure PIO for SDRAM mww 0xFFFFF470 0xFFFF0000 mww 0xFFFFF474 0x00000000 mww 0xFFFFF404 0xFFFF0000 # Configure SDRAMC CR mww 0xFFFFEA08 0xA63392F9 # NOP command mww 0xFFFFEA00 0x1 mww 0x20000000 0 # Precharge All Banks command mww 0xFFFFEA00 0x2 mww 0x20000000 0 # Set 1st CBR mww 0xFFFFEA00 0x00000004 mww 0x20000010 0x00000001 # Set 2nd CBR mww 0xFFFFEA00 0x00000004 mww 0x20000020 0x00000002 # Set 3rd CBR mww 0xFFFFEA00 0x00000004 mww 0x20000030 0x00000003 # Set 4th CBR mww 0xFFFFEA00 0x00000004 mww 0x20000040 0x00000004 # Set 5th CBR mww 0xFFFFEA00 0x00000004 mww 0x20000050 0x00000005 # Set 6th CBR mww 0xFFFFEA00 0x00000004 mww 0x20000060 0x00000006 # Set 7th CBR mww 0xFFFFEA00 0x00000004 mww 0x20000070 0x00000007 # Set 8th CBR mww 0xFFFFEA00 0x00000004 mww 0x20000080 0x00000008 # Set LMR operation mww 0xFFFFEA00 0x00000003 # Perform LMR burst=1, lat=2 mww 0x20000020 0xCAFEDEDE # Set Refresh Timer mww 0xFFFFEA04 0x00000203 # Set Normal mode mww 0xFFFFEA00 0x00000000 mww 0x20000000 0x00000000 #remap internal memory at address 0x0 mww 0xffffef00 0x3 echo "SDRAM configuration ok." } $_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup 0 arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable #set _FLASHNAME $_CHIPNAME.flash #flash bank $_FLASHNAME at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 0 18432 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/at91eb40a.cfg ================================================ #Script for AT91EB40a # FIXME use some standard target config, maybe create one from this # # source [find target/...cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91eb40a } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x1f0f0f0f } #Atmel ties SRST & TRST together, at which point it makes #no sense to use TRST, but use TMS instead. # #The annoying thing with tying SRST & TRST together is that #there is no way to halt the CPU *before and during* the #SRST reset, which means that the CPU will run a number #of cycles before it can be halted(as much as milliseconds). reset_config srst_only srst_pulls_trst #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID #target configuration set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME # speed up memory downloads arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable #flash driver set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x01000000 0x200000 2 2 $_TARGETNAME # required for usable performance. Used for lots of # other things than flash programming. $_TARGETNAME configure -work-area-phys 0x00030000 -work-area-size 0x10000 -work-area-backup 0 $_TARGETNAME configure -event reset-init { echo "Running reset init script for AT91EB40A" # Reset script for AT91EB40a reg cpsr 0x000000D3 mww 0xFFE00020 0x1 mww 0xFFE00024 0x00000000 mww 0xFFE00000 0x01002539 mww 0xFFFFF124 0xFFFFFFFF mww 0xffff0010 0x100 mww 0xffff0034 0x100 } # This target is pretty snappy... adapter speed 16000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/at91rm9200-dk.cfg ================================================ # # This is for the "at91rm9200-DK" (not the EK) eval board. # # The two are probably very simular.... I have DK... # # It has atmel at91rm9200 chip. source [find target/at91rm9200.cfg] reset_config trst_and_srst $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { at91rm9200_dk_init } #flash bank set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x10000000 0x00200000 2 2 $_TARGETNAME proc at91rm9200_dk_init { } { # Try to run at 1khz... Yea, that slow! # Chip is really running @ 32khz adapter speed 8 mww 0xfffffc64 0xffffffff ## disable all clocks but system clock mww 0xfffffc04 0xfffffffe ## disable all clocks to pioa and piob mww 0xfffffc14 0xffffffc3 ## master clock = slow cpu = slow ## (means the CPU is running at 32khz!) mww 0xfffffc30 0 ## main osc enable mww 0xfffffc20 0x0000ff01 ## program pllA mww 0xfffffc28 0x20263e04 ## program pllB mww 0xfffffc2c 0x10483e0e ## let pll settle... sleep 100msec sleep 100 ## switch to fast clock mww 0xfffffc30 0x202 ## Sleep some - (go read) sleep 100 #======================================== # CPU now runs at 180mhz # SYS runs at 60mhz. adapter speed 40000 #======================================== ## set memc for all memories mww 0xffffff60 0x02 ## program smc controller mww 0xffffff70 0x3284 ## init sdram mww 0xffffff98 0x7fffffd0 ## all banks precharge mww 0xffffff80 0x02 ## touch sdram chip to make it work mww 0x20000000 0 ## sdram controller mode register mww 0xffffff90 0x04 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 ## sdram controller mode register ## Refresh, etc.... mww 0xffffff90 0x03 mww 0x20000080 0 mww 0xffffff94 0x1f4 mww 0x20000080 0 mww 0xffffff90 0x10 mww 0x20000000 0 mww 0xffffff00 0x01 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/at91rm9200-ek.cfg ================================================ # # Copyright 2010 Jean-Christophe PLAGNIOL-VILLARD # # under GPLv2 Only # # This is for the "at91rm9200-ek" eval board. # # # It has atmel at91rm9200 chip. source [find target/at91rm9200.cfg] reset_config trst_and_srst $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { at91rm9200_ek_init } ## flash bank set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x10000000 0x00800000 2 2 $_TARGETNAME # The chip may run @ 32khz, so set a really low JTAG speed adapter speed 8 proc at91rm9200_ek_init { } { # Try to run at 1khz... Yea, that slow! # Chip is really running @ 32khz adapter speed 8 mww 0xfffffc64 0xffffffff ## disable all clocks but system clock mww 0xfffffc04 0xfffffffe ## disable all clocks to pioa and piob mww 0xfffffc14 0xffffffc3 ## master clock = slow cpu = slow ## (means the CPU is running at 32khz!) mww 0xfffffc30 0 ## main osc enable mww 0xfffffc20 0x0000ff01 ## MC_PUP mww 0xFFFFFF50 0x00000000 ## MC_PUER: Memory controller protection unit disable mww 0xFFFFFF54 0x00000000 ## EBI_CFGR mww 0xFFFFFF64 0x00000000 ## SMC2_CSR[0]: 16bit, 2 TDF, 4 WS mww 0xFFFFFF70 0x00003284 ## Init Clocks ## CKGR_PLLAR mww 0xFFFFFC28 0x2000BF05 ## PLLAR: 179,712000 MHz for PCK mww 0xFFFFFC28 0x20263E04 sleep 100 ## PMC_MCKR mww 0xFFFFFC30 0x00000100 sleep 100 ## ;MCKR : PCK/3 = MCK Master Clock = 59,904000MHz from PLLA mww 0xFFFFFC30 0x00000202 sleep 100 #======================================== # CPU now runs at 180mhz # SYS runs at 60mhz. adapter speed 40000 #======================================== ## Init SDRAM ## PIOC_ASR: Configure PIOC as peripheral (D16/D31) mww 0xFFFFF870 0xFFFF0000 ## PIOC_BSR: mww 0xFFFFF874 0x00000000 ## PIOC_PDR: mww 0xFFFFF804 0xFFFF0000 ## EBI_CSA : CS1=SDRAM mww 0xFFFFFF60 0x00000002 ## EBI_CFGR: mww 0xFFFFFF64 0x00000000 ## SDRC_CR : mww 0xFFFFFF98 0x2188c155 ## SDRC_MR : Precharge All mww 0xFFFFFF90 0x00000002 ## access SDRAM mww 0x20000000 0x00000000 ## SDRC_MR : Refresh mww 0xFFFFFF90 0x00000004 ## access SDRAM mww 0x20000000 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 ## SDRC_MR : Load Mode Register mww 0xFFFFFF90 0x00000003 ## access SDRAM mww 0x20000080 0x00000000 ## SDRC_TR : Write refresh rate mww 0xFFFFFF94 0x000002E0 ## access SDRAM mww 0x20000000 0x00000000 ## SDRC_MR : Normal Mode mww 0xFFFFFF90 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/at91sam9261-ek.cfg ================================================ ################################################################################ # Atmel AT91SAM9261-EK eval board ################################################################################ source [find mem_helper.tcl] source [find target/at91sam9261.cfg] uplevel #0 [list source [find chip/atmel/at91/hardware.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91sam9261.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91sam9261_matrix.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91sam9_init.cfg]] # By default S1 is open and this means that NTRST is not connected. # The reset_config in target/at91sam9261.cfg is overridden here. # (or S1 must be populated with a 0 Ohm resistor) reset_config srst_only scan_chain $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { at91sam9261ek_reset_init } $_TARGETNAME configure -event reset-start { at91sam9_reset_start } proc at91sam9261ek_reset_init { } { ;# for ppla at 199 Mhz set config(master_pll_div) 15 set config(master_pll_mul) 162 ;# for ppla at 239 Mhz ;# set master_pll_div 1 ;# set master_pll_mul 13 set val $::AT91_WDT_WDV ;# Counter Value set val [expr {$val | $::AT91_WDT_WDDIS}] ;# Watchdog Disable set val [expr {$val | $::AT91_WDT_WDD}] ;# Delta Value set val [expr {$val | $::AT91_WDT_WDDBGHLT}] ;# Debug Halt set val [expr {$val | $::AT91_WDT_WDIDLEHLT}] ;# Idle Halt set config(wdt_mr_val) $val ;# EBI_CSA, no pull-ups for D[15:0], CS1 SDRAM, CS3 NAND Flash set config(matrix_ebicsa_addr) $::AT91_MATRIX_EBICSA set config(matrix_ebicsa_val) [expr {$::AT91_MATRIX_DBPUC | $::AT91_MATRIX_CS1A_SDRAMC}] ;# SDRAMC_CR - Configuration register set val $::AT91_SDRAMC_NC_9 set val [expr {$val | $::AT91_SDRAMC_NR_13}] set val [expr {$val | $::AT91_SDRAMC_NB_4}] set val [expr {$val | $::AT91_SDRAMC_CAS_3}] set val [expr {$val | $::AT91_SDRAMC_DBW_32}] set val [expr {$val | (2 << 8)}] ;# Write Recovery Delay set val [expr {$val | (7 << 12)}] ;# Row Cycle Delay set val [expr {$val | (3 << 16)}] ;# Row Precharge Delay set val [expr {$val | (2 << 20)}] ;# Row to Column Delay set val [expr {$val | (5 << 24)}] ;# Active to Precharge Delay set val [expr {$val | (8 << 28)}] ;# Exit Self Refresh to Active Delay set config(sdram_cr_val) $val set config(sdram_tr_val) 0x13c set config(sdram_base) $::AT91_CHIPSELECT_1 at91sam9_reset_init $config } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/at91sam9263-ek.cfg ================================================ ################################################################################ # Atmel AT91SAM9263-EK eval board ################################################################################ source [find mem_helper.tcl] source [find target/at91sam9263.cfg] uplevel #0 [list source [find chip/atmel/at91/hardware.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91sam9263.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91sam9263_matrix.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91sam9_init.cfg]] # By default S1 is open and this means that NTRST is not connected. # The reset_config in target/at91sam9263.cfg is overridden here. # (or S1 must be populated with a 0 Ohm resistor) reset_config srst_only scan_chain $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { at91sam9263ek_reset_init } $_TARGETNAME configure -event reset-start { at91sam9_reset_start } proc at91sam9263ek_reset_init { } { set config(master_pll_div) 14 set config(master_pll_mul) 171 set val $::AT91_WDT_WDV ;# Counter Value set val [expr {$val | $::AT91_WDT_WDDIS}] ;# Watchdog Disable set val [expr {$val | $::AT91_WDT_WDD}] ;# Delta Value set val [expr {$val | $::AT91_WDT_WDDBGHLT}] ;# Debug Halt set val [expr {$val | $::AT91_WDT_WDIDLEHLT}] ;# Idle Halt set config(wdt_mr_val) $val set config(sdram_piod) 1 ;# EBI_CSA, no pull-ups for D[15:0], CS1 SDRAM, CS3 NAND Flash set config(matrix_ebicsa_addr) $::AT91_MATRIX_EBI0CSA set val $::AT91_MATRIX_EBI0_DBPUC set val [expr {$val | $::AT91_MATRIX_EBI0_VDDIOMSEL_3_3V}] set val [expr {$val | $::AT91_MATRIX_EBI0_CS1A_SDRAMC}] set config(matrix_ebicsa_val) $val ;# SDRAMC_CR - Configuration register set val $::AT91_SDRAMC_NC_9 set val [expr {$val | $::AT91_SDRAMC_NR_13}] set val [expr {$val | $::AT91_SDRAMC_NB_4}] set val [expr {$val | $::AT91_SDRAMC_CAS_3}] set val [expr {$val | $::AT91_SDRAMC_DBW_32}] set val [expr {$val | (1 << 8)}] ;# Write Recovery Delay set val [expr {$val | (7 << 12)}] ;# Row Cycle Delay set val [expr {$val | (2 << 16)}] ;# Row Precharge Delay set val [expr {$val | (2 << 20)}] ;# Row to Column Delay set val [expr {$val | (5 << 24)}] ;# Active to Precharge Delay set val [expr {$val | (1 << 28)}] ;# Exit Self Refresh to Active Delay set config(sdram_cr_val) $val set config(sdram_tr_val) 0x13c set config(sdram_base) $::AT91_CHIPSELECT_1 at91sam9_reset_init $config } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/at91sam9g20-ek.cfg ================================================ ################################################################################################# # # # Author: Gary Carlson (gcarlson@carlson-minot.com) # # Generated for Atmel AT91SAM9G20-EK evaluation board using Atmel SAM-ICE (J-Link) version 8. # # # ################################################################################################# # FIXME use some standard target config, maybe create one from this # # source [find target/...cfg] source [find target/at91sam9g20.cfg] set _FLASHTYPE nandflash_cs3 # Set reset type. Note that the AT91SAM9G20-EK board has the trst signal disconnected. Therefore # the reset needs to be configured for "srst_only". If for some reason, a zero-ohm jumper is # added to the board to connect the trst signal, then this parameter may need to be changed. reset_config srst_only adapter srst delay 200 jtag_ntrst_delay 200 # If you don't want to execute built-in boot rom code (and there are good reasons at times not to do that) in the # AT91SAM9 family, the microcontroller is a lump on a log without initialization. Because this family has # some powerful features, we want to have a special function that handles "reset init". To do this we declare # an event handler where these special activities can take place. scan_chain $_TARGETNAME configure -event reset-init {at91sam9g20_reset_init} $_TARGETNAME configure -event reset-start {at91sam9g20_reset_start} # NandFlash configuration and definition nand device nandflash_cs3 at91sam9 $_TARGETNAME 0x40000000 0xfffffe800 at91sam9 cle 0 22 at91sam9 ale 0 21 at91sam9 rdy_busy 0 0xfffff800 13 at91sam9 ce 0 0xfffff800 14 proc read_register {register} { return [read_memory $register 32 1] } proc at91sam9g20_reset_start { } { # Make sure that the the jtag is running slow, since there are a number of different ways the board # can be configured coming into this state that can cause communication problems with the jtag # adapter. Also since this call can be made following a "reset init" where fast memory accesses # are enabled, need to temporarily shut this down so that the RSTC_MR register can be written at slower # jtag speed without causing GDB keep alive problem. arm7_9 fast_memory_access disable adapter speed 2 ;# Slow-speed oscillator enabled at reset, so run jtag speed slow. halt ;# Make sure processor is halted, or error will result in following steps. wait_halt 10000 mww 0xfffffd08 0xa5000501 ;# RSTC_MR : enable user reset. } proc at91sam9g20_reset_init { } { # At reset AT91SAM9G20 chip runs on slow clock (32.768 kHz). To shift over to a normal clock requires # a number of steps that must be carefully performed. The process outline below follows the # recommended procedure outlined in the AT91SAM9G20 technical manual. # # Several key and very important things to keep in mind: # The SDRAM parts used currently on the Atmel evaluation board are -75 grade parts. This # means the master clock (MCLK) must be at or below 133 MHz or timing errors will occur. The processor # core can operate up to 400 MHz and therefore PCLK must be at or below this to function properly. mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog. # Enable the main 18.432 MHz oscillator in CKGR_MOR register. # Wait for MOSCS in PMC_SR to assert indicating oscillator is again stable after change to CKGR_MOR. mww 0xfffffc20 0x00004001 while { [expr {[read_register 0xfffffc68] & 0x01}] != 1 } { sleep 1 } # Set PLLA Register for 792.576 MHz (divider: bypass, multiplier: 43). # Wait for LOCKA signal in PMC_SR to assert indicating PLLA is stable. mww 0xfffffc28 0x202a3f01 while { [expr {[read_register 0xfffffc68] & 0x02}] != 2 } { sleep 1 } # Set master system clock prescaler divide by 6 and processor clock divide by 2 in PMC_MCKR. # Wait for MCKRDY signal from PMC_SR to assert. mww 0xfffffc30 0x00000101 while { [expr {[read_register 0xfffffc68] & 0x08}] != 8 } { sleep 1 } # Now change PMC_MCKR register to select PLLA. # Wait for MCKRDY signal from PMC_SR to assert. mww 0xfffffc30 0x00001302 while { [expr {[read_register 0xfffffc68] & 0x08}] != 8 } { sleep 1 } # Processor and master clocks are now operating and stable at maximum frequency possible: # -> MCLK = 132.096 MHz # -> PCLK = 396.288 MHz # Switch over to adaptive clocking. adapter speed 0 # Enable faster DCC downloads and memory accesses. arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable # To be able to use external SDRAM, several peripheral configuration registers must # be modified. The first change is made to PIO_ASR to select peripheral functions # for D15 through D31. The second change is made to the PIO_PDR register to disable # this for D15 through D31. mww 0xfffff870 0xffff0000 mww 0xfffff804 0xffff0000 # The EBI chip select register EBI_CS must be specifically configured to enable the internal SDRAM controller # using CS1. Additionally we want CS3 assigned to NandFlash. Also VDDIO is connected physically on # the board to the 3.3 VDC power supply so set the appropriate register bit to notify the micrcontroller. mww 0xffffef1c 0x000100a # The AT91SAM9G20-EK evaluation board has built-in NandFlash. The exact physical timing characteristics # for the memory type used on the current board (MT29F2G08AACWP) can be established by setting # a number of registers. The first step involves setting up the general I/O pins on the processor # to be able to interface and support the external memory. mww 0xfffffc10 0x00000010 ;# PMC_PCER : enable PIOC clock mww 0xfffff800 0x00006000 ;# PIOC_PER : enable PIO function for 13(RDY/~BSY) and 14(~CS) mww 0xfffff810 0x00004000 ;# PIOC_OER : enable output on 14 mww 0xfffff814 0x00002000 ;# PIOC_ODR : disable output on 13 mww 0xfffff830 0x00004000 ;# PIOC_SODR : set 14 to disable NAND # The exact physical timing characteristics for the memory type used on the current board # (MT29F2G08AACWP) can be established by setting four registers in order: SMC_SETUP3, # SMC_PULSE3, SMC_CYCLE3, and SMC_MODE3. Computing the exact values of these registers # is a little tedious to do here. If you have questions about how to do this, Atmel has # a decent application note #6255B that covers this process. mww 0xffffec30 0x00020002 ;# SMC_SETUP3 : 2 clock cycle setup for NRD and NWE mww 0xffffec34 0x04040404 ;# SMC_PULSE3 : 4 clock cycle pulse for all signals mww 0xffffec38 0x00070006 ;# SMC_CYCLE3 : 7 clock cycle NRD and 6 NWE cycle mww 0xffffec3C 0x00020003 ;# SMC_MODE3 : NRD and NWE control, no NWAIT, 8-bit DBW, mww 0xffffe800 0x00000001 ;# ECC_CR : reset the ECC parity registers mww 0xffffe804 0x00000002 ;# ECC_MR : page size is 2112 words (word is 8 bits) # Identify NandFlash bank 0. nand probe nandflash_cs3 # The AT91SAM9G20-EK evaluation board has built-in serial data flash also. # Now setup SDRAM. This is tricky and configuration is very important for reliability! The current calculations # are based on 2 x Micron MT48LC16M16A2-75 memory (4 M x 16 bit x 4 banks). If you use this file as a reference # for a new board that uses different SDRAM devices or clock rates, you need to recalculate the value inserted # into the SDRAM_CR register. Using the memory datasheet for the -75 grade part and assuming a master clock # of 132.096 MHz then the SDCLK period is equal to 7.6 ns. This means the device requires: # # CAS latency = 3 cycles # TXSR = 10 cycles # TRAS = 6 cycles # TRCD = 3 cycles # TRP = 3 cycles # TRC = 9 cycles # TWR = 2 cycles # 9 column, 13 row, 4 banks # refresh equal to or less then 7.8 us for commercial/industrial rated devices # # Thus SDRAM_CR = 0xa6339279 mww 0xffffea08 0xa6339279 # Next issue a 'NOP' command through the SDRAMC_MR register followed by writing a zero value into # the starting memory location for the SDRAM. mww 0xffffea00 0x00000001 mww 0x20000000 0 # Issue an 'All Banks Precharge' command through the SDRAMC_MR register followed by writing a zero # value into the starting memory location for the SDRAM. mww 0xffffea00 0x00000002 mww 0x20000000 0 # Now issue an 'Auto-Refresh' command through the SDRAMC_MR register. Follow this operation by writing # zero values eight times into the starting memory location for the SDRAM. mww 0xffffea00 0x4 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 # Almost done, so next issue a 'Load Mode Register' command followed by a zero value write to the # the starting memory location for the SDRAM. mww 0xffffea00 0x3 mww 0x20000000 0 # Signal normal mode using the SDRAMC_MR register and follow with a zero value write the the starting # memory location for the SDRAM. mww 0xffffea00 0x0 mww 0x20000000 0 # Finally set the refresh rate to about every 7 us (7.5 ns x 924 cycles). mww 0xffffea04 0x0000039c } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_at91sam7s-ek.cfg ================================================ # Atmel AT91SAM7S-EK # http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3784 set CHIPNAME at91sam7s256 source [find target/at91sam7sx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_at91sam9260-ek.cfg ================================================ ################################################################################ # Atmel AT91SAM9260-EK eval board # # http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3933 # # Atmel AT91SAM9260 : PLLA = 198.656 MHz, MCK = 99.328 MHz # OSCSEL configured for external 32.768 kHz crystal # # 32-bit SDRAM : 2 x Micron MT48LC16M16A2, 4M x 16Bit x 4 Banks # ################################################################################ # We add to the minimal configuration. source [find target/at91sam9260.cfg] # By default S1 is open and this means that NTRST is not connected. # The reset_config in target/at91sam9260.cfg is overridden here. # (or S1 must be populated with a 0 Ohm resistor) reset_config srst_only $_TARGETNAME configure -event reset-start { # At reset CPU runs at 32.768 kHz. # JTAG Frequency must be 6 times slower if RCLK is not supported. jtag_rclk 5 halt # RSTC_MR : enable user reset, MMU may be enabled... use physical address mww phys 0xfffffd08 0xa5000501 } $_TARGETNAME configure -event reset-init { mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog mww 0xfffffc20 0x00004001 ;# CKGR_MOR : enable the main oscillator sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000001 ;# PMC_MCKR : switch to main oscillator sleep 10 ;# wait 10 ms mww 0xfffffc28 0x2060bf09 ;# CKGR_PLLAR: Set PLLA Register for 198.656 MHz sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000101 ;# PMC_MCKR : Select prescaler (divide by 2) sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000102 ;# PMC_MCKR : Clock from PLLA is selected (99.328 MHz) sleep 10 ;# wait 10 ms # Increase JTAG Speed to 6 MHz if RCLK is not supported jtag_rclk 6000 arm7_9 dcc_downloads enable ;# Enable faster DCC downloads mww 0xfffff870 0xffff0000 ;# PIO_ASR : Select peripheral function for D15..D31 mww 0xfffff804 0xffff0000 ;# PIO_PDR : Disable PIO function for D15..D31 mww 0xffffef1c 0x00010002 ;# EBI_CSA : Assign EBI Chip Select 1 to SDRAM, VDDIOMSEL set for +3V3 memory mww 0xffffea08 0x85227259 ;# SDRAMC_CR : Configure SDRAM (2 x Micron MT48LC16M16A2 : 4M x 16Bit x 4 Banks) mww 0xffffea00 0x1 ;# SDRAMC_MR : issue a NOP command mww 0x20000000 0 mww 0xffffea00 0x2 ;# SDRAMC_MR : issue an 'All Banks Precharge' command mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue 8 x 'Auto-Refresh' Command mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x3 ;# SDRAMC_MR : issue a 'Load Mode Register' command mww 0x20000000 0 mww 0xffffea00 0x0 ;# SDRAMC_MR : normal mode mww 0x20000000 0 mww 0xffffea04 0x2b6 ;# SDRAMC_TR : Set refresh timer count to 7us } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_at91sam9rl-ek.cfg ================================================ ################################################################################ # # Generated for Atmel AT91SAM9RL-EK evaluation board using Atmel SAM-ICE (J-Link) V6 # # Atmel AT91SAM9RL : PLL = 200 MHz, MCK = 100 MHz # OSCSEL configured for external 32.768 kHz crystal # # 32-bit SDRAM : 2 x Micron MT48LC16M16A2, 4M x 16Bit x 4 Banks # ################################################################################ # We add to the minimal configuration. source [find target/at91sam9rl.cfg] $_TARGETNAME configure -event reset-start { # At reset CPU runs at 32.768 kHz. # JTAG Frequency must be 6 times slower if RCLK is not supported. jtag_rclk 5 halt # RSTC_MR : enable user reset, MMU may be enabled... use physical address mww phys 0xfffffd08 0xa5000501 } $_TARGETNAME configure -event reset-init { mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog mww 0xfffffc20 0x00004001 ;# CKGR_MOR : enable the main oscillator sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000001 ;# PMC_MCKR : switch to main oscillator sleep 10 ;# wait 10 ms mww 0xfffffc28 0x2031bf03 ;# CKGR_PLLR: Set PLL Register for 200 MHz sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000101 ;# PMC_MCKR : Select prescaler (divide by 2) sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000102 ;# PMC_MCKR : Clock from PLL is selected (100 MHz) sleep 10 ;# wait 10 ms # Increase JTAG Speed to 6 MHz if RCLK is not supported jtag_rclk 6000 arm7_9 dcc_downloads enable ;# Enable faster DCC downloads mww 0xfffff670 0xffff0000 ;# PIO_ASR : Select peripheral function for D16..D31 (PIOB) mww 0xfffff604 0xffff0000 ;# PIO_PDR : Disable PIO function for D16..D31 (PIOB) mww 0xffffef20 0x00010002 ;# EBI_CSA : Assign EBI Chip Select 1 to SDRAM, VDDIOMSEL set for +3V3 memory mww 0xffffea08 0x85227259 ;# SDRAMC_CR : Configure SDRAM (2 x Micron MT48LC16M16A2 : 4M x 16Bit x 4 Banks) mww 0xffffea00 0x1 ;# SDRAMC_MR : issue a NOP command mww 0x20000000 0 mww 0xffffea00 0x2 ;# SDRAMC_MR : issue an 'All Banks Precharge' command mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue 8 x 'Auto-Refresh' Command mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x3 ;# SDRAMC_MR : issue a 'Load Mode Register' command mww 0x20000000 0 mww 0xffffea00 0x0 ;# SDRAMC_MR : normal mode mww 0x20000000 0 mww 0xffffea04 0x2b6 ;# SDRAMC_TR : Set refresh timer count to 7us } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_sam3n_ek.cfg ================================================ # # Board configuration for Atmel's SAM3N-EK # reset_config srst_only set CHIPNAME at91sam3n4c adapter speed 32 source [find target/at91sam3nXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_sam3s_ek.cfg ================================================ source [find target/at91sam3sXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_sam3u_ek.cfg ================================================ source [find target/at91sam3u4e.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_sam3x_ek.cfg ================================================ source [find target/at91sam3ax_8x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_sam4e_ek.cfg ================================================ # This is an SAM4E-EK board with a single SAM4E16 chip. # http://www.atmel.com/tools/sam4e-ek.aspx # chip name set CHIPNAME SAM4E16E source [find target/at91sam4sXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_sam4l8_xplained_pro.cfg ================================================ # # Atmel SAM4L8 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAM4L8-XPRO.aspx # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME ATSAM4LC8CA source [find target/at91sam4lXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_sam4s_ek.cfg ================================================ source [find target/at91sam4sXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_sam4s_xplained_pro.cfg ================================================ # # Atmel SAM4S Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAM4S-XPRO.aspx # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME ATSAM4SD32C source [find target/at91sam4sd32x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_samc20_xplained_pro.cfg ================================================ # # Atmel SAMC20 Xplained Pro evaluation kit. # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91samc20j18 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_samc21_xplained_pro.cfg ================================================ # # Atmel SAMC21 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAMC21-XPRO.aspx # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91samc21j18 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_samd10_xplained_mini.cfg ================================================ # # Atmel SAMD10 Xplained mini evaluation kit. # http://www.atmel.com/tools/atsamd10-xmini.aspx source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91samd10d14 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_samd11_xplained_pro.cfg ================================================ # # Atmel SAMD11 Xplained Pro evaluation kit. # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91samd11d14 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_samd20_xplained_pro.cfg ================================================ # # Atmel SAMD20 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAMD20-XPRO.aspx # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91samd20j18 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_samd21_xplained_pro.cfg ================================================ # # Atmel SAMD21 Xplained Pro evaluation kit. # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91samd21j18 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_same70_xplained.cfg ================================================ # # Atmel SAME70 Xplained evaluation kit. # http://www.atmel.com/tools/ATSAME70-XPLD.aspx # # Connect using the EDBG chip on the dev kit over USB source [find interface/cmsis-dap.cfg] set CHIPNAME atsame70q21 source [find target/atsamv.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_samg53_xplained_pro.cfg ================================================ # # Atmel SAMG53 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAMG53-XPRO.aspx # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME ATSAMG53N19 source [find target/at91samg5x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_samg55_xplained_pro.cfg ================================================ # # Atmel SAMG55 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAMG55-XPRO.aspx # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME ATSAMG55J19 source [find target/at91samg5x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_saml21_xplained_pro.cfg ================================================ # # Atmel SAML21 Xplained Pro evaluation kit. # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91saml21j18 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_samr21_xplained_pro.cfg ================================================ # # Atmel SAMR21 Xplained Pro evaluation kit. # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91samr21g18 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/atmel_samv71_xplained_ultra.cfg ================================================ # # Atmel SAMV71 Xplained Ultra evaluation kit. # http://www.atmel.com/tools/ATSAMV71-XULT.aspx # # To connect using the EDBG chip on the dev kit over USB, you will # first need to source [find interface/cmsis-dap.cfg] # however, since this board also has a SWD+ETM connector, we don't # automatically source that file here. set CHIPNAME samv71 source [find target/atsamv.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/avnet_ultrazed-eg.cfg ================================================ # # AVNET UltraZED EG StarterKit # ZynqMP UlraScale-EG plus IO Carrier with on-board digilent smt2 # source [find interface/ftdi/digilent_jtag_smt2_nc.cfg] # jtag transport only transport select jtag # reset lines are not wired reset_config none # slow default clock adapter speed 1000 set CHIPNAME uscale source [find target/xilinx_zynqmp.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/balloon3-cpu.cfg ================================================ # Config for balloon3 board, cpu JTAG port. http://balloonboard.org/ # The board has separate JTAG ports for cpu and CPLD/FPGA devices # Chaining is done on IO interfaces if desired. source [find target/pxa270.cfg] # The board supports separate reset lines # Override this in the interface config for parallel dongles reset_config trst_and_srst separate # flash bank # 29LV650 64Mbit Flash set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x800000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/bcm28155_ap.cfg ================================================ # BCM28155_AP adapter speed 20000 set CHIPNAME bcm28155 source [find target/bcm281xx.cfg] reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/bluefield.cfg ================================================ # # Board configuration for BlueField SoC. # source [find interface/rshim.cfg] source [find target/bluefield.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/bt-homehubv1.cfg ================================================ # # BT HomeHub v1 # set partition_list { CFE { Bootloader 0xbe400000 0x00020000 } firmware { "Kernel+rootfs" 0xbe420000 0x007d0000 } fisdir { "FIS Directory" 0xbebf0000 0x0000f000 } nvram { "Config space" 0xbebff000 0x00001000 } } source [find target/bcm6348.cfg] set _FLASHNAME $_CHIPNAME.norflash flash bank $_FLASHNAME cfi 0xbe400000 0x00800000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/colibri.cfg ================================================ # Toradex Colibri PXA270 source [find target/pxa270.cfg] reset_config trst_and_srst srst_push_pull adapter srst pulse_width 40 # CS0 -- one bank of CFI flash, 32 MBytes # the bank is 32-bits wide, two 16-bit chips in parallel set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/crossbow_tech_imote2.cfg ================================================ # Crossbow Technology iMote2 set CHIPNAME imote2 source [find target/pxa270.cfg] # longer-than-normal reset delay adapter srst delay 800 reset_config trst_and_srst separate # works for P30 flash set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x2000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/csb337.cfg ================================================ # Cogent CSB337 # http://cogcomp.com/csb_csb337.htm source [find target/at91rm9200.cfg] # boots from NOR on CS0: 8 MBytes CFI flash, 16-bit bus set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x10000000 0x00800000 2 2 $_TARGETNAME # ETM9 trace port connector present on this board, 16 data pins. if { [info exists ETM_DRIVER] } { etm config $_TARGETNAME 16 normal half $ETM_DRIVER # OpenOCD may someday support a real trace port driver... # system config file would need to configure it. } else { etm config $_TARGETNAME 16 normal half dummy etm_dummy config $_TARGETNAME } proc csb337_clk_init { } { # CPU is in Slow Clock Mode (32KiHz) ... needs slow JTAG clock adapter speed 8 # CKGR_MOR: start main oscillator (3.6864 MHz) mww 0xfffffc20 0xff01 sleep 10 # CKGR_PLLAR: start PLL A for CPU and peripherals (184.32 MHz) mww 0xfffffc28 0x20313e01 # CKGR_PLLBR: start PLL B for USB timing (96 MHz, with div2) mww 0xfffffc2c 0x12703e18 # let PLLs lock sleep 10 # PMC_MCKR: switch to CPU clock = PLLA, master clock = CPU/4 mww 0xfffffc30 0x0302 sleep 20 # CPU is in Normal Mode ... allows faster JTAG clock speed adapter speed 40000 } proc csb337_nor_init { } { # SMC_CSR0: adjust timings (10 wait states) mww 0xffffff70 0x1100318a flash probe 0 } proc csb337_sdram_init { } { # enable PIOC clock mww 0xfffffc10 0x0010 # PC31..PC16 are D31..D16, with internal pullups like D15..D0 mww 0xfffff870 0xffff0000 mww 0xfffff874 0x0 mww 0xfffff804 0xffff0000 # SDRC_CR: set timings mww 0xffffff98 0x2188b0d5 # SDRC_MR: issue all banks precharge to SDRAM mww 0xffffff90 2 mww 0x20000000 0 # SDRC_MR: 8 autorefresh cycles mww 0xffffff90 4 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 # SDRC_MR: set SDRAM mode registers (CAS, burst len, etc) mww 0xffffff90 3 mww 0x20000080 0 # SDRC_TR: set refresh rate mww 0xffffff94 0x200 mww 0x20000000 0 # SDRC_MR: normal mode, 32 bit bus mww 0xffffff90 0 mww 0x20000000 0 } # The rm9200 chip has just been reset. Bring it up far enough # that we can write flash or run code from SDRAM. proc csb337_reset_init { } { csb337_clk_init # EBI_CSA: CS0 = NOR, CS1 = SDRAM mww 0xffffff60 0x02 csb337_nor_init csb337_sdram_init # Update CP15 control register ... we don't seem to be able to # read/modify/write its value through a TCL variable, so just # write it. Fields are zero unless listed here ... and note # that OpenOCD numbers this register "2", not "1" (!). # # - Core to use Async Clocking mode (so it uses 184 MHz most # of the time instead of limiting to the master clock rate): # iA(31) = 1, nF(30) = 1 # - Icache on (it's disabled now, slowing i-fetches) # I(12) = 1 # - Reserved/ones # 6:3 = 1 arm920t cp15 2 0xc0001078 } $_TARGETNAME configure -event reset-init {csb337_reset_init} arm7_9 fast_memory_access enable ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/csb732.cfg ================================================ # The Cogent CSB732 board has a single i.MX35 chip source [find target/imx35.cfg] # Determined by trial and error reset_config trst_and_srst combined adapter srst delay 200 jtag_ntrst_delay 200 $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { csb732_init } # Bare-bones initialization of core clocks and SDRAM proc csb732_init { } { # Disable fast writing only for init memwrite burst disable # All delay loops are omitted. # We assume the interpreter latency is enough. # Allow access to all coprocessors arm mcr 15 0 15 1 0 0x2001 # Disable MMU, caches, write buffer arm mcr 15 0 1 0 0 0x78 # Grant manager access to all domains arm mcr 15 0 3 0 0 0xFFFFFFFF # Set ARM clock to 532 MHz, AHB to 133 MHz mww 0x53F80004 0x1000 # Set core clock to 2 * 24 MHz * (11 + 1/12) = 532 MHz mww 0x53F8001C 0xB2C01 set ESDMISC 0xB8001010 set ESDCFG0 0xB8001004 set ESDCTL0 0xB8001000 # Enable DDR mww $ESDMISC 0x4 # Timing mww $ESDCFG0 0x007fff3f # CS0 mww $ESDCTL0 0x92120080 # Precharge all dummy write mww 0x80000400 0 # Enable CS) auto-refresh mww $ESDCTL0 0xA2120080 # Refresh twice (dummy writes) mww 0x80000000 0 mww 0x80000000 0 # Enable CS0 load mode register mww $ESDCTL0 0xB2120080 # Dummy writes mwb 0x80000033 0x01 mwb 0x81000000 0x01 mww $ESDCTL0 0x82226080 mww 0x80000000 0 # Re-enable fast writing memwrite burst enable } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/da850evm.cfg ================================================ #DA850 EVM board # http://focus.ti.com/dsp/docs/thirdparty/catalog/devtoolsproductfolder.tsp?actionPerformed=productFolder&productId=5939 # http://www.logicpd.com/products/development-kits/zoom-omap-l138-evm-development-kit source [find target/omapl138.cfg] reset_config trst_and_srst separate #currently any pinmux/timing must be setup by UBL before openocd can do debug #TODO: implement pinmux/timing on reset like in board/dm365evm.cfg ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/digi_connectcore_wi-9c.cfg ================================================ ###################################### # Target: DIGI ConnectCore Wi-9C ###################################### reset_config trst_and_srst # FIXME use some standard target config, maybe create one from this # # source [find target/...cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ns9360 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # This config file was defaulting to big endian.. set _ENDIAN big } # What's a good fallback frequency for this board if RCLK is # not available?? jtag_rclk 1000 if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926031 } set _TARGETNAME $_CHIPNAME.cpu jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID adapter srst delay 200 jtag_ntrst_delay 0 ###################### # Target configuration ###################### target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-init { mww 0x90600104 0x33313333 mww 0xA0700000 0x00000001 ;# Enable the memory controller. mww 0xA0700024 0x00000006 ;# Set the refresh counter 6 mww 0xA0700028 0x00000001 ;# mww 0xA0700030 0x00000001 ;# Set the precharge period mww 0xA0700034 0x00000004 ;# Active to precharge command period is 16 clock cycles mww 0xA070003C 0x00000001 ;# tAPR mww 0xA0700040 0x00000005 ;# tDAL mww 0xA0700044 0x00000001 ;# tWR mww 0xA0700048 0x00000006 ;# tRC 32 clock cycles mww 0xA070004C 0x00000006 ;# tRFC 32 clock cycles mww 0xA0700054 0x00000001 ;# tRRD mww 0xA0700058 0x00000001 ;# tMRD mww 0xA0700100 0x00004280 ;# Dynamic Config 0 (cs4) mww 0xA0700120 0x00004280 ;# Dynamic Config 1 (cs5) mww 0xA0700140 0x00004280 ;# Dynamic Config 2 (cs6) mww 0xA0700160 0x00004280 ;# Dynamic Config 3 (cs7) # mww 0xA0700104 0x00000203 ;# CAS latency is 2 at 100 MHz mww 0xA0700124 0x00000203 ;# CAS latency is 2 at 100 MHz mww 0xA0700144 0x00000203 ;# CAS latency is 2 at 100 MHz mww 0xA0700164 0x00000203 ;# CAS latency is 2 at 100 MHz # mww 0xA0700020 0x00000103 ;# issue SDRAM PALL command # mww 0xA0700024 0x00000001 ;# Set the refresh counter to be as small as possible # # Add some dummy writes to give the SDRAM time to settle, it needs two # AHB clock cycles, here we poke in the debugger flag, this lets # the software know that we are in the debugger mww 0xA0900000 0x00000002 mww 0xA0900000 0x00000002 mww 0xA0900000 0x00000002 mww 0xA0900000 0x00000002 mww 0xA0900000 0x00000002 # mdw 0xA0900000 mdw 0xA0900000 mdw 0xA0900000 mdw 0xA0900000 mdw 0xA0900000 # mww 0xA0700024 0x00000030 ;# Set the refresh counter to 30 mww 0xA0700020 0x00000083 ;# Issue SDRAM MODE command # # Next we perform a read of RAM. # mw = move word. mdw 0x00022000 # mw 0x00022000:P, r3 # 22000 for cas2 latency, 32000 for cas 3 # mww 0xA0700020 0x00000003 ;# issue SDRAM NORMAL command mww 0xA0700100 0x00084280 ;# Enable buffer access mww 0xA0700120 0x00084280 ;# Enable buffer access mww 0xA0700140 0x00084280 ;# Enable buffer access mww 0xA0700160 0x00084280 ;# Enable buffer access #Set byte lane state (static mem 1)" mww 0xA0700220 0x00000082 #Flash Start mww 0xA09001F8 0x50000000 #Flash Mask Reg mww 0xA09001FC 0xFF000001 mww 0xA0700028 0x00000001 # RAMAddr = 0x00020000 # RAMSize = 0x00004000 # Set the processor mode reg cpsr 0xd3 } $_TARGETNAME configure -work-area-phys 0x00000000 -work-area-size 0x1000 -work-area-backup 1 ##################### # Flash configuration ##################### #M29DW323DB - not working #flash bank cfi set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x50000000 0x0400000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/digilent_analog_discovery.cfg ================================================ # # Digilent Analog Discovery # # http://www.digilentinc.com/Products/Detail.cfm?NavPath=2,842,1018&Prod=ANALOG-DISCOVERY # # Config is based on data from # https://github.com/bvanheu/urjtag-ad/commit/8bd883ee01d134f94b79cbbd00df42cd03bafd71 # adapter driver ftdi ftdi device_desc "Digilent USB Device" ftdi vid_pid 0x0403 0x6014 ftdi layout_init 0x8008 0x800b adapter speed 25000 source [find cpld/xilinx-xc6s.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/digilent_atlys.cfg ================================================ # http://digilentinc.com/atlys/ # # The Digilent Atlys normally requires proprietary tools to program and will # enumerate as: # ID 1443:0007 Digilent Development board JTAG # # However, the ixo-usb-jtag project provides an alternative open firmware for # the on board programmer. When using this firmware the board will then # enumerate as: # ID 16c0:06ad Van Ooijen Technische Informatica # (With SerialNumber == hw_nexys) # # See the interface/usb-jtag.cfg for more information. source [find interface/usb-jtag.cfg] source [find cpld/xilinx-xc6s.cfg] source [find cpld/jtagspi.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/digilent_nexys_video.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Digilent Nexys Video with Xilinx Artix-7 FPGA # https://reference.digilentinc.com/programmable-logic/nexys-video/start adapter driver ftdi adapter speed 30000 ftdi device_desc "Digilent USB Device" ftdi vid_pid 0x0403 0x6010 # channel 0 is dedicated for Digilent's DPTI Interface # channel 1 is used for JTAG ftdi channel 1 # just TCK TDI TDO TMS, no reset ftdi layout_init 0x0088 0x008b reset_config none # Enable sampling on falling edge for high JTAG speeds. ftdi tdo_sample_edge falling transport select jtag source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/digilent_zedboard.cfg ================================================ # # Digilent Zedboard Rev.C, Rev.D with Xilinx Zynq chip # # http://zedboard.com/product/zedboard # source [find interface/ftdi/digilent_jtag_smt2.cfg] reset_config srst_only srst_push_pull source [find target/zynq_7000.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/diolan_lpc4350-db1.cfg ================================================ # # Diolan LPC-4350-DB1 development board # set CHIPNAME lpc4350 source [find target/lpc4350.cfg] flash bank $_CHIPNAME.nor cfi 0x1C000000 0x00200000 2 2 $_CHIPNAME.m4 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/diolan_lpc4357-db1.cfg ================================================ # # Diolan LPC-4357-DB1 development board # set CHIPNAME lpc4357 source [find target/lpc4357.cfg] flash bank $_CHIPNAME.nor cfi 0x1C000000 0x00200000 2 2 $_CHIPNAME.m4 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/dk-tm4c129.cfg ================================================ echo "WARNING: board/dk-tm4c129.cfg is deprecated, please switch to board/ti_dk-tm4c129.cfg" source [find board/ti_dk-tm4c129.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/dm355evm.cfg ================================================ # DM355 EVM board # http://focus.ti.com/docs/toolsw/folders/print/tmdsevm355.html # http://c6000.spectrumdigital.com/evmdm355/ source [find target/ti_dm355.cfg] reset_config trst_and_srst separate # NOTE: disable or replace this call to dm355evm_init if you're # debugging new UBL code from SRAM. $_TARGETNAME configure -event reset-init { dm355evm_init } # # This post-reset init is called when the MMU isn't active, all IRQs # are disabled, etc. It should do most of what a UBL does, except for # loading code (like U-Boot) into DRAM and running it. # proc dm355evm_init {} { global dm355 echo "Initialize DM355 EVM board" # CLKIN = 24 MHz ... can't talk quickly to ARM yet jtag_rclk 1500 ######################## # PLL1 = 432 MHz (/8, x144) # ...SYSCLK1 = 216 MHz (/2) ... ARM, MJCP # ...SYSCLK2 = 108 MHz (/4) ... Peripherals # ...SYSCLK3 = 27 MHz (/16) ... VPBE, DAC # ...SYSCLK4 = 108 MHz (/4) ... VPSS # pll1.{prediv,div1,div2} are fixed # pll1.postdiv set in MISC (for *this* speed grade) set addr [dict get $dm355 pllc1] set pll_divs [dict create] dict set pll_divs div3 16 dict set pll_divs div4 4 pll_v02_setup $addr 144 $pll_divs # ARM is now running at 216 MHz, so JTAG can go faster jtag_rclk 20000 ######################## # PLL2 = 342 MHz (/8, x114) # ....SYSCLK1 = 342 MHz (/1) ... DDR PHY at 171 MHz, 2x clock # pll2.{postdiv,div1} are fixed set addr [dict get $dm355 pllc2] set pll_divs [dict create] dict set pll_divs div1 1 dict set pll_divs prediv 8 pll_v02_setup $addr 114 $pll_divs ######################## # PINMUX # All Video Inputs davinci_pinmux $dm355 0 0x00007f55 # All Video Outputs davinci_pinmux $dm355 1 0x00145555 # EMIFA (NOTE: more could be set up for use as GPIOs) davinci_pinmux $dm355 2 0x00000c08 # SPI0, SPI1, UART1, I2C, SD0, SD1, McBSP0, CLKOUTs davinci_pinmux $dm355 3 0x1bff55ff # MMC/SD0 instead of MS; SPI0 davinci_pinmux $dm355 4 0x00000000 ######################## # PSC setup (minimal) # DDR EMIF/13, AEMIF/14, UART0/19 psc_enable 13 psc_enable 14 psc_enable 19 psc_go ######################## # DDR2 EMIF # VTPIOCR impedance calibration set addr [dict get $dm355 sysbase] set addr [expr {$addr + 0x70}] # clear CLR, LOCK, PWRDN; wait a clock; set CLR mmw $addr 0 0x20c0 mmw $addr 0x2000 0 # wait for READY while { [expr {[mrw $addr] & 0x8000}] == 0 } { sleep 1 } # set IO_READY; then LOCK and PWRSAVE; then PWRDN mmw $addr 0x4000 0 mmw $addr 0x0180 0 mmw $addr 0x0040 0 # NOTE: this DDR2 initialization sequence borrows from # both UBL 1.50 and the SPRUEH7D DDR2 EMIF spec. # reset (then re-enable) DDR controller psc_reset 13 psc_go psc_enable 13 psc_go # now set it up for Micron MT47H64M16HR-37E @ 171 MHz set addr [dict get $dm355 ddr_emif] # DDRPHYCR1 mww [expr {$addr + 0xe4}] 0x50006404 # PBBPR -- burst priority mww [expr {$addr + 0x20}] 0xfe # SDCR -- unlock boot config; init for DDR2, relock, unlock SDTIM* mmw [expr {$addr + 0x08}] 0x00800000 0 mmw [expr {$addr + 0x08}] 0x0013c632 0x03870fff # SDTIMR0, SDTIMR1 mww [expr {$addr + 0x10}] 0x2a923249 mww [expr {$addr + 0x14}] 0x4c17c763 # SDCR -- relock SDTIM* mmw [expr {$addr + 0x08}] 0 0x00008000 # SDRCR -- refresh rate (171 MHz * 7.8usec) mww [expr {$addr + 0x0c}] 1336 ######################## # ASYNC EMIF set addr [dict get $dm355 a_emif] # slow/pessimistic timings set nand_timings 0x40400204 # fast (25% faster page reads) #set nand_timings 0x0400008c # AWCCR mww [expr {$addr + 0x04}] 0xff # CS0 == socketed NAND (default MT29F16G08FAA, 2GByte) mww [expr {$addr + 0x10}] $nand_timings # CS1 == dm9000 Ethernet mww [expr {$addr + 0x14}] 0x00a00505 # NANDFCR -- only CS0 has NAND mww [expr {$addr + 0x60}] 0x01 # default: both chipselects to the NAND socket are used nand probe 0 nand probe 1 ######################## # UART0 set addr [dict get $dm355 uart0] # PWREMU_MGNT -- rx + tx in reset mww [expr {$addr + 0x30}] 0 # DLL, DLH -- 115200 baud mwb [expr {$addr + 0x20}] 0x0d mwb [expr {$addr + 0x24}] 0x00 # FCR - clear and disable FIFOs mwb [expr {$addr + 0x08}] 0x07 mwb [expr {$addr + 0x08}] 0x00 # IER - disable IRQs mwb [expr {$addr + 0x04}] 0x00 # LCR - 8-N-1 mwb [expr {$addr + 0x0c}] 0x03 # MCR - no flow control or loopback mwb [expr {$addr + 0x10}] 0x00 # PWREMU_MGNT -- rx + tx normal, free running during JTAG halt mww [expr {$addr + 0x30}] 0xe001 ######################## # turn on icache - set I bit in cp15 register c1 arm mcr 15 0 0 1 0 0x00051078 } # NAND -- socket has two chipselects, MT29F16G08FAA puts 1GByte on each one. # # NOTE: "hwecc4" here presumes that if you're using the standard 2GB NAND # you either (a) have 'new' DM355 chips, with boot ROMs that don't need to # use "hwecc4_infix" for the UBL; or else (b) aren't updating anything that # needs infix layout ... like an old UBL, old U-Boot, old MVL kernel, etc. set _FLASHNAME $_CHIPNAME.boot nand device $_FLASHNAME davinci $_TARGETNAME 0x02000000 hwecc4 0x01e10000 set _FLASHNAME $_CHIPNAME.flash nand device $_FLASHNAME davinci $_TARGETNAME 0x02004000 hwecc4 0x01e10000 # FIXME # - support writing UBL with its header (new layout only with new ROMs) # - support writing ABL/U-Boot with its header (new layout) ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/dm365evm.cfg ================================================ # DM365 EVM board -- Beta # http://focus.ti.com/docs/toolsw/folders/print/tmdxevm365.html # http://support.spectrumdigital.com/boards/evmdm365 source [find target/ti_dm365.cfg] # NOTE: in Rev C boards, the CPLD ignores SRST from the ARM-20 JTAG # connector, so it doesn't affect generation of the reset signal. # Accordingly, resets require something else. ICEpick could do it; # but its docs aren't generally available. # # At this writing, newer boards aren't available ... so assume no SRST. # Also ICEpick docs aren't available ... so we must use watchdog reset, # and hope the CPU isn't wedged or in a WFI loop (either of which can # block access to CPU and thus watchdog registers). reset_config trst_only $_TARGETNAME configure -event reset-assert "davinci_wdog_reset" # SW5.1 routes CS0: NAND vs OneNAND. # SW4.6:4 controls AEMIF width (8 for NAND, 16 for OneNand) # for boot-from-flash, those must agree with SW4.3:1 settings. if { [info exists CS0MODE] } { # NAND or OneNAND set CS0 $CS0MODE } else { set CS0 "" echo "WARNING: CS0 configuration not known" proc cs0_setup {a_emif} {} proc flashprobe {} {} } set a_emif [dict get $dm365 a_emif] # As shipped: boot from NAND. if { $CS0 == "NAND" } { echo "CS0 NAND" # NAND socket has two chipselects. Default MT29F16G08FAA chip # has 1GByte on each one. # NOTE: "hwecc4" here presumes that you're not updating anything # that needs infix layout (e.g. UBL, old U-Boot, etc) nand device low davinci $_TARGETNAME 0x02000000 hwecc4 $a_emif nand device high davinci $_TARGETNAME 0x02004000 hwecc4 $a_emif proc cs0_setup {a_emif} { global dm365 # 8 bit EMIF davinci_pinmux $dm365 2 0x00000016 # slow/pessimistic timings set nand_timings 0x40400204 # fast (25% faster page reads) #set nand_timings 0x0400008c # CS0 == socketed NAND (default MT29F16G08FAA, 2 GBytes) mww [expr {$a_emif + 0x10}] $nand_timings # NANDFCR -- CS0 has NAND mww [expr {$a_emif + 0x60}] 0x01 } proc flashprobe {} { nand probe 0 nand probe 1 } } elseif { $CS0 == "OneNAND" } { echo "CS0 OneNAND" # No support for this OneNAND in OpenOCD (yet) or Linux ... # REVISIT OneNAND timings not verified to work! echo "WARNING -- OneNAND not yet tested!" proc cs0_setup {a_emif} { global dm365 # 16 bit EMIF davinci_pinmux $dm365 2 0x00000055 # CS0 == OneNAND (KFG1G16U2B-DIB6, 128 KBytes) mww [expr {$a_emif + 0x10}] 0x00000001 # ONENANDCTRL -- CS0 has OneNAND, enable sync reads mww [expr {$a_emif + 0x5c}] 0x0441 } proc flashprobe {} { } } # NOTE: disable or replace this call to dm365evm_init if you're # debugging new UBL/NANDboot code from SRAM. $_TARGETNAME configure -event reset-init { dm365evm_init } # # This post-reset init is called when the MMU isn't active, all IRQs # are disabled, etc. It should do most of what a UBL does, except for # loading code (like U-Boot) into DRAM and running it. # proc dm365evm_init {} { global dm365 echo "Initialize DM365 EVM board" # CLKIN = 24 MHz ... can't talk quickly to ARM yet adapter speed 1500 # FIXME -- PLL init ######################## # PINMUX setup davinci_pinmux $dm365 0 0x00fd0000 davinci_pinmux $dm365 1 0x00145555 # mux2 controls AEMIF ... 8 bit for NAND, 16 for OneNand davinci_pinmux $dm365 3 0x375affff davinci_pinmux $dm365 4 0x55556555 ######################## # PSC setup (minimal) # DDR EMIF/13, AEMIF/14, UART0/19 psc_enable 13 psc_enable 14 psc_enable 19 psc_go # FIXME setup DDR2 (needs PLL) ######################## # ASYNC EMIF set a_emif [dict get $dm365 a_emif] # AWCCR mww [expr {$a_emif + 0x04}] 0xff # CS0 == NAND or OneNAND cs0_setup $a_emif # CS1 == CPLD mww [expr {$a_emif + 0x14}] 0x00a00505 # FIXME setup UART0 flashprobe } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/dm6446evm.cfg ================================================ # DM6446 EVM board # http://focus.ti.com/docs/toolsw/folders/print/tmdsevm6446.html # http://c6000.spectrumdigital.com/davincievm/ # EVM is just the board; buy that at Spectrum. # The "kit" from TI also has: video camera, LCD video monitor, more. source [find target/ti_dm6446.cfg] # J4 controls what CS2 hooks up to, usually NOR or NAND flash. # S3.1/S3.2 controls boot mode, which may force J4 and S3.3 settings. # S3.3 controls AEMIF bus width. if { [info exists J4_OPTION] } { # NOR, NAND, SRAM, ... set CS2_MODE $J4_OPTION } else { set CS2_MODE "" } # ARM boot: # S3.1 = 0, S3.2 = 0 ==> ROM/UBL boot via NAND (J4 == NAND) # S3.1 = 1, S3.2 = 0 ==> AEMIF boot (J4 == NOR or SRAM) # S3.1 = 0, S3.2 = 1 ==> ROM/UBL boot via HPI # S3.1 = 1, S3.2 = 1 ==> ROM/UBL boot via UART (J4 == don't care) # AEMIF bus width: # S3.3 = 0 ==> 8 bit bus width # S3.3 = 1 ==> 16 bit bus width # DSP boot: # S3.4 = 0 ==> controlled by ARM if { $CS2_MODE == "NOR" } { # 16 Mbytes address space; 16 bit bus width # (older boards used 32MB parts, with upper 16 MB unusable) set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x02000000 0x01000000 2 2 $_TARGETNAME proc flashprobe {} { flash probe 0 } } elseif { $CS2_MODE == "NAND" } { # 64 Mbyte small page; 8 bit bus width nand device davinci $_TARGETNAME 0x02000000 hwecc1 0x01e00000 proc flashprobe {} { nand probe 0 } } elseif { $CS2_MODE == "SRAM" } { # 4 Mbyte address space; 16 bit bus width # loaded via JTAG or HPI proc flashprobe {} {} } else { # maybe it's HPI boot? can't tell... echo "WARNING: CS2/flash configuration not recognized" proc flashprobe {} {} } # NOTE: disable or replace this call to dm6446evm_init if you're # debugging new UBL code from SRAM (for NAND boot). $_TARGETNAME configure -event reset-init { dm6446evm_init } # # This post-reset init is called when the MMU isn't active, all IRQs # are disabled, etc. It should do most of what a UBL does, except for # loading code (like U-Boot) into DRAM and running it. # proc dm6446evm_init {} { echo "Initialize DM6446 EVM board" # FIXME initialize everything: # - PLL1 # - PLL2 # - PINMUX # - PSC # - DDR # - AEMIF # - UART0 # - icache flashprobe } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/dp_busblaster_v3.cfg ================================================ # # Dangerous Prototypes - Bus Blaster # # http://dangerousprototypes.com/docs/Bus_Blaster # # To reprogram the on-board CPLD do: # openocd -f board/dp_busblaster_v3.cfg -c "adapter speed 1000; init; svf ; shutdown" # source [find interface/ftdi/dp_busblaster.cfg] ftdi channel 1 jtag newtap xc2c32a tap -expected-id 0x06e1c093 -irlen 8 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/dp_busblaster_v4.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Dangerous Prototypes - Bus Blaster # # http://dangerousprototypes.com/docs/Bus_Blaster # # The Bus Blaster has a configurable buffer between the FTDI FT2232H # and the JTAG header which allows it to emulate various debugger # types. This config works with KT-Link compatible implementation from # https://raw.githubusercontent.com/dergraaf/busblaster_v4/master/ktlink/ktlink.svf # # To reprogram the on-board CPLD do: # openocd -f board/dp_busblaster_v4.cfg -c "adapter speed 1000; init; svf ; shutdown" # source [find interface/ftdi/dp_busblaster.cfg] ftdi channel 1 jtag newtap xc2c64a tap -expected-id 0x06e5c093 -irlen 8 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/dptechnics_dpt-board-v1.cfg ================================================ # Product page: # https://www.dptechnics.com/en/products/dpt-board-v1.html # # JTAG is a 5 pin array located close to main module in following order: # 1. JTAG TCK # 2. JTAG TDO # 3. JTAG TDI # 4. JTAG TMS # 5. GND The GND is located near letter G of word JTAG on board. # # Two RST pins are connected to: # 1. GND # 2. GPIO11 this pin is located near letter R of word RST. # # To enable EJTAG mode, GPIO11 (RST[1]) pin should be pulled up. For example # with 10K resistor connected to V3.3 pin. # # This board is powered from micro USB connector. No real reset pin or button, for # example RESET_L is available. source [find target/atheros_ar9331.cfg] $_TARGETNAME configure -event reset-init { ar9331_25mhz_pll_init sleep 1 ar9331_ddr2_init } set ram_boot_address 0xa0000000 $_TARGETNAME configure -work-area-phys 0xa1FFE000 -work-area-size 0x1000 flash bank flash0 ath79 0xbf000000 0 0 0 $_TARGETNAME cs0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/efikamx.cfg ================================================ # Genesi USA EfikaMX # http://www.genesi-usa.com/products/efika # Fall back to 6MHz if RTCK is not supported jtag_rclk 6000 $_TARGETNAME configure -event "reset-start" { jtag_rclk 6000 } source [find target/imx51.cfg] reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/efm32.cfg ================================================ # Configuration for EFM32 boards with on-board SEGGER J-Link # # Tested with Tiny, Giant and Zero Gecko Starter Kit. # source [find interface/jlink.cfg] transport select swd adapter speed 1000 set CHIPNAME efm32 source [find target/efm32.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/eir.cfg ================================================ # Elector Internet Radio board # http://www.ethernut.de/en/hardware/eir/index.html source [find target/at91sam7se512.cfg] $_TARGETNAME configure -event reset-init { # WDT_MR, disable watchdog mww 0xFFFFFD44 0x00008000 # RSTC_MR, enable user reset mww 0xfffffd08 0xa5000001 # CKGR_MOR mww 0xFFFFFC20 0x00000601 sleep 10 # CKGR_PLLR mww 0xFFFFFC2C 0x00481c0e sleep 10 # PMC_MCKR mww 0xFFFFFC30 0x00000007 sleep 10 # PMC_IER mww 0xFFFFFF60 0x00480100 # # Enable SDRAM interface. # # Enable SDRAM control at PIO A. mww 0xfffff474 0x3f800000 ;# PIO_BSR_OFF mww 0xfffff404 0x3f800000 ;# PIO_PDR_OFF # Enable address bus (A0, A2-A11, A13-A17) at PIO B mww 0xfffff674 0x0003effd ;# PIO_BSR_OFF mww 0xfffff604 0x0003effd ;# PIO_PDR_OFF # Enable 16 bit data bus at PIO C mww 0xfffff870 0x0000ffff ;# PIO_ASR_OFF mww 0xfffff804 0x0000ffff ;# PIO_PDR_OFF # Enable SDRAM chip select mww 0xffffff80 0x00000002 ;# EBI_CSA_OFF # Set SDRAM characteristics in configuration register. # Hard coded values for MT48LC32M16A2 with 48MHz CPU. mww 0xffffffb8 0x2192215a ;# SDRAMC_CR_OFF sleep 10 # Issue 16 bit SDRAM command: NOP mww 0xffffffb0 0x00000011 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 # Issue 16 bit SDRAM command: Precharge all mww 0xffffffb0 0x00000012 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 # Issue 8 auto-refresh cycles mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 # Issue 16 bit SDRAM command: Set mode register mww 0xffffffb0 0x00000013 ;# SDRAMC_MR_OFF mww 0x20000014 0xcafedede # Set refresh rate count ??? mww 0xffffffb4 0x00000013 ;# SDRAMC_TR_OFF # Issue 16 bit SDRAM command: Normal mode mww 0xffffffb0 0x00000010 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000180 # # Enable external reset key. # mww 0xfffffd08 0xa5000001 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ek-lm3s1968.cfg ================================================ # # TI/Luminary Stellaris LM3S1968 Evaluation Kits # # http://www.ti.com/tool/ek-lm3s1968 # # NOTE: to use J-Link instead of the on-board interface, # you may also need to reduce adapter speed to be about 1200. # source [find interface/jlink.cfg] # include the FT2232 interface config for on-board JTAG interface # NOTE: using the on-board FT2232 JTAG/SWD/SWO interface is optional! # so is using in JTAG mode, as done here. source [find interface/ftdi/luminary.cfg] # include the target config set WORKAREASIZE 0x2000 set CHIPNAME lm3s1968 source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ek-lm3s3748.cfg ================================================ # # TI/Luminary Stellaris lm3s3748 Evaluation Kits # # http://www.ti.com/tool/ek-lm3s3748 # # NOTE: using the on-board FT2232 JTAG/SWD/SWO interface is optional! # so is using it in JTAG mode, as done here. source [find interface/ftdi/luminary.cfg] # 20k working area set WORKAREASIZE 0x4000 set CHIPNAME lm3s3748 source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ek-lm3s6965.cfg ================================================ # # TI/Luminary Stellaris LM3S6965 Evaluation Kits # # http://www.ti.com/tool/ek-lm3s6965 # # NOTE: using the on-board FT2232 JTAG/SWD/SWO interface is optional! # so is using it in JTAG mode, as done here. source [find interface/ftdi/luminary.cfg] # 20k working area set WORKAREASIZE 0x5000 set CHIPNAME lm3s6965 # include the target config source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ek-lm3s811-revb.cfg ================================================ # # TI/Luminary Stellaris LM3S811 Evaluation Kits (rev B and earlier) # # http://www.ti.com/tool/ek-lm3s811 # # NOTE: newer 811-EK boards (rev C and above) shouldn't use this. # use board/ek-lm3s811.cfg source [find interface/ftdi/luminary-lm3s811.cfg] # include the target config set WORKAREASIZE 0x2000 set CHIPNAME lm3s811 source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ek-lm3s811.cfg ================================================ # # TI/Luminary Stellaris LM3S811 Evaluation Kits # # http://www.ti.com/tool/ek-lm3s811 # # NOTE: using the on-board FT2232 JTAG/SWD/SWO interface is optional! # so is using it in JTAG mode, as done here. # NOTE: older '811-EK boards (before rev C) shouldn't use this. source [find interface/ftdi/luminary.cfg] # include the target config set WORKAREASIZE 0x2000 set CHIPNAME lm3s811 source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ek-lm3s8962.cfg ================================================ # # TI/Luminary Stellaris LM3S8962 Evaluation Kits # # http://www.ti.com/tool/ek-lm3s8962 # # NOTE: using the on-board FT2232 JTAG/SWD/SWO interface is optional! # so is using it in JTAG mode, as done here. source [find interface/ftdi/luminary.cfg] # 64k working area set WORKAREASIZE 0x10000 set CHIPNAME lm3s8962 # include the target config source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ek-lm3s9b9x.cfg ================================================ # # TI/Luminary Stellaris LM3S9B9x Evaluation Kits # # http://www.ti.com/tool/ek-lm3s9b90 # http://www.ti.com/tool/ek-lm3s9b92 # # NOTE: using the bundled FT2232 JTAG/SWD/SWO interface is optional! # so is using in JTAG mode, as done here. source [find interface/ftdi/luminary-icdi.cfg] set WORKAREASIZE 0x4000 set CHIPNAME lm3s9b9x source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ek-lm3s9d92.cfg ================================================ # # TI/Luminary Stellaris LM3S9D92 Evaluation Kits # # http://www.ti.com/tool/ek-lm3s9d92 # # NOTE: using the bundled FT2232 JTAG/SWD/SWO interface is optional! # so is using in JTAG mode, as done here. source [find interface/ftdi/luminary-icdi.cfg] # 64k working area set WORKAREASIZE 0x10000 set CHIPNAME lm3s9d92 source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ek-lm4f120xl.cfg ================================================ # # TI Stellaris Launchpad ek-lm4f120xl Evaluation Kits # # http://www.ti.com/tool/ek-lm4f120xl # # # NOTE: using the bundled ICDI interface is optional! # This interface is not ftdi based as previous boards were # source [find interface/ti-icdi.cfg] transport select hla_jtag set WORKAREASIZE 0x8000 set CHIPNAME lm4f120h5qr source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ek-lm4f232.cfg ================================================ # # TI Stellaris LM4F232 Evaluation Kits # # http://www.ti.com/tool/ek-lm4f232 # # # NOTE: using the bundled ICDI interface is optional! # This interface is not ftdi based as previous boards were # source [find interface/ti-icdi.cfg] transport select hla_jtag set WORKAREASIZE 0x8000 set CHIPNAME lm4f23x source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ek-tm4c123gxl.cfg ================================================ echo "WARNING: board/ek-tm4c123gxl.cfg is deprecated, please switch to board/ti_ek-tm4c123gxl.cfg" source [find board/ti_ek-tm4c123gxl.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ek-tm4c1294xl.cfg ================================================ echo "WARNING: board/ek-tm4c1294xl.cfg is deprecated, please switch to board/ti_ek-tm4c1294xl.cfg" source [find board/ti_ek-tm4c1294xl.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/embedded-artists_lpc2478-32.cfg ================================================ # Embedded Artists eval board for LPC2478 # http://www.embeddedartists.com/ # Target device: LPC2478 set CCLK 72000 source [find target/lpc2478.cfg] # Helper # proc read_register {register} { return [read_memory $register 32 1] } proc init_board {} { # Delays on reset lines adapter srst delay 500 jtag_ntrst_delay 1 # Adaptive JTAG clocking through RTCK. # jtag_rclk 20 global _TARGETNAME global _CHIPNAME # A working area will help speeding the flash programming $_TARGETNAME configure -work-area-phys 0x40000200 -work-area-size [expr {0x10000-0x200-0x20}] -work-area-backup 0 # External 16-bit flash at chip select CS0 (SST39VF3201-70, 4 MiB) flash bank $_CHIPNAME.extflash cfi 0x80000000 0x400000 2 2 $_TARGETNAME jedec_probe # Event handlers # $_TARGETNAME configure -event reset-start { # Back to the slow JTAG clock jtag_rclk 20 } $_TARGETNAME configure -event reset-init { arm core_state arm arm7_9 dcc_downloads enable ;# Speed up downloads by using DCC transfer arm7_9 fast_memory_access enable # Peripheral clocks mww 0xE01FC0C4 0x04280FFE ;# PCONP: (reset value) # Map the user flash to the vector table area (0x00...0x3F) mww 0xE01FC040 0x00000001 ;# MEMMAP: User flash # Memory accelerator module mww 0xE01FC004 0x00000003 ;# MAMTIM: 3 clock cycles mww 0xE01FC000 0x00000002 ;# MAMCR: fully enabled # Enable external memory bus (32-bit SDRAM at DYCS0, 16-bit flash at CS0) mww 0xE002C014 0x55010115 ;# PINSEL5: P2.16=CAS, P2.17=RAS, P2.18=CLKOUT0, # P2.20=DYCS0, P2.24=CKEOUT0, P2.28=DQMOUT0, # P2.29=DQMOUT1, P2.30=DQMOUT2, P2.31=DQMOUT3 mww 0xE002C018 0x55555555 ;# PINSEL6: P3.0...P3.15=D0...D15 mww 0xE002C01C 0x55555555 ;# PINSEL7: P3.16...P3.31=D16...D31 mww 0xE002C020 0x55555555 ;# PINSEL8: P4.0...P4.15=A0...A15 mww 0xE002C024 0x50051555 ;# PINSEL9: P4.16...P4.22=A16...A22, P4.24=OE, # P4.25=WE, P4.30=CS0, P4.31=CS1 mww 0xFFE08000 0x00000001 ;# EMCControl: Enable EMC # Start PLL, then use faster JTAG clock enable_pll jtag_rclk 3000 # 16-bit flash @ CS0 (SST39VF3201-70) mww 0xFFE08200 0x00080081 ;# EMCStaticConfig0: 16 bit, PB=1, buffers on mww 0xFFE08204 0x00000000 ;# EMCStaticWaitWen0 mww 0xFFE08208 0x00000000 ;# EMCStaticWaitOen0 mww 0xFFE0820C 0x00000005 ;# EMCStaticWaitRd0 mww 0xFFE08210 0x00000005 ;# EMCStaticWaitPage0 mww 0xFFE08214 0x00000003 ;# EMCStaticWaitWr0 mww 0xFFE08218 0x00000001 ;# EMCStaticWaitTurn0 # 8-bit NAND @ CS1 # TODO # 32-bit SDRAM @ DYCS0 (K4M563233G-HN75) mww 0xFFE08028 0x00000001 ;# EMCDynamicReadConfig mww 0xFFE08030 0x00000001 ;# EMCDynamicRP mww 0xFFE08034 0x00000003 ;# EMCDynamicRAS mww 0xFFE08038 0x00000005 ;# EMCDynamicSREX mww 0xFFE0803C 0x00000001 ;# EMCDynamicAPR mww 0xFFE08040 0x00000005 ;# EMCDynamicDAL mww 0xFFE08044 0x00000001 ;# EMCDynamicWR mww 0xFFE08048 0x00000005 ;# EMCDynamicRC mww 0xFFE0804C 0x00000005 ;# EMCDynamicRFC mww 0xFFE08050 0x00000005 ;# EMCDynamicXSR mww 0xFFE08054 0x00000001 ;# EMCDynamicRRD mww 0xFFE08058 0x00000001 ;# EMCDynamicMRD # mww 0xFFE08104 0x00000202 ;# EMCDynamicRasCas0 mww 0xFFE08100 0x00005488 ;# EMCDynamicConfig0 sleep 100 mww 0xFFE08020 0x00000183 ;# EMCDynamicControl: Clock on continuously, NOP sleep 10 mww 0xFFE08020 0x00000103 ;# EMCDynamicControl: PRECHARGE-ALL mww 0xFFE08024 0x00000046 ;# EMCDynamicRefresh sleep 100 mww 0xFFE08020 0x00000083 ;# EMCDynamicControl: MODE mdw 0xA0011000 1 ;# Set SDRAM mode register mww 0xFFE08020 0x00000000 ;# EMCDynamicControl: NORMAL mww 0xFFE08100 0x00085488 ;# EMCDynamicConfig0: Enable buffers } $_TARGETNAME configure -event gdb-attach { # Without this gdb-attach will first time as probe will fail reset init } } # Enable the PLL. # Generate maximum CPU clock (72 MHz) Run from internal RC oscillator. # Note: The PLL output runs at a frequency N times the desired CPU clock. # It in unavoidable that the CPU clock drops down to (4 MHz/N) during # the initialization! # Here: N=4 # Note that if the PLL is already active at the time this script is # called, the effective value of N is the value of CCLKCFG at that time! # proc enable_pll {} { # Disconnect PLL in case it is already connected if {[expr {[read_register 0xE01FC080] & 0x03}] == 3} { # Disconnect it, but leave it enabled # (This MUST be done in two steps) mww 0xE01FC080 0x00000001 ;# PLLCON: disconnect PLL mww 0xE01FC08C 0x000000AA ;# PLLFEED mww 0xE01FC08C 0x00000055 ;# PLLFEED } # Disable PLL (as it might already be enabled at this time!) mww 0xE01FC080 0x00000000 ;# PLLCON: disable PLL mww 0xE01FC08C 0x000000AA ;# PLLFEED mww 0xE01FC08C 0x00000055 ;# PLLFEED # Setup PLL to generate 288 MHz from internal RC oscillator mww 0xE01FC10C 0x00000000 ;# CLKSRCSEL: IRC mww 0xE01FC084 0x00000023 ;# PLLCFG: N=1, M=36 mww 0xE01FC08C 0x000000AA ;# PLLFEED mww 0xE01FC08C 0x00000055 ;# PLLFEED mww 0xE01FC080 0x00000001 ;# PLLCON: enable PLL mww 0xE01FC08C 0x000000AA ;# PLLFEED mww 0xE01FC08C 0x00000055 ;# PLLFEED sleep 100 mww 0xE01FC104 0x00000003 ;# CCLKCFG: divide by 4 (72 MHz) mww 0xE01FC080 0x00000003 ;# PLLCON: connect PLL mww 0xE01FC08C 0x000000AA ;# PLLFEED mww 0xE01FC08C 0x00000055 ;# PLLFEED } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/emcraft_imx8m-som-bsb.cfg ================================================ # # configuration file for Emcraft IMX8M-SOM-BSB # # only JTAG supported transport select jtag # set a safe JTAG clock speed, can be overridden adapter speed 1000 # SRST and TRST are wired up reset_config trst_and_srst # delay after SRST goes inactive adapter srst delay 70 # board has an i.MX8MQ with 4 Cortex-A53 cores set CHIPNAME imx8mq set CHIPCORES 4 # source SoC configuration source [find target/imx8m.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/emcraft_twr-vf6-som-bsb.cfg ================================================ # # EmCraft Systems TWR-VF6-SOM-BSB # # http://www.emcraft.com/products/259#twr-kit # source [find board/emcraft_vf6-som.cfg] reset_config srst_only srst_nogate ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/emcraft_vf6-som.cfg ================================================ # # EmCraft Systems Vybrid VF6 SOM # # http://www.emcraft.com/products/259#som # set CHIPNAME vf610 source [find target/vybrid_vf6xx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/esp32s2-kaluga-1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Example OpenOCD configuration file for ESP32-S2 Kaluga board. # # For example, OpenOCD can be started for ESP32-S2 debugging on # # openocd -f board/esp32s2-kaluga-1.cfg # source [find interface/ftdi/esp32s2_kaluga_v1.cfg] source [find target/esp32s2.cfg] # The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they # do not relate to OpenOCD trying to read from a memory range without physical # memory being present there), you can try lowering this. # On ESP32-S2, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz # if CPU frequency is 160MHz or 240MHz. adapter speed 20000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ethernut3.cfg ================================================ # # Ethernut 3 board configuration file # # http://www.ethernut.de/en/hardware/enut3/ # AT91R40008-66AU ARM7TDMI Microcontroller # 256kB internal RAM source [find target/at91r40008.cfg] # AT49BV322A-70TU NOR Flash # 2M x 16 mode at address 0x10000000 # Common flash interface supported # set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x10000000 0x400000 2 2 $_TARGETNAME # Micrel MIC2775-29YM5 Supervisor # Reset output will remain active for 280ms (maximum) # adapter srst delay 300 jtag_ntrst_delay 300 arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable adapter speed 16000 # Target events # $_TARGETNAME configure -event reset-init { board_init } # Initialize board hardware # proc board_init { } { board_remap flash probe 0 } # Memory remap # proc board_remap {{VERBOSE 0}} { # CS0: NOR flash # 16MB @ 0x10000000 # 16-bit data bus # 4 wait states # mww 0xffe00000 0x1000212d # CS1: Ethernet controller # 1MB @ 0x20000000 # 16-bit data bus # 2 wait states # Byte select access # mww 0xffe00004 0x20003025 # CS2: CPLD registers # 1MB @ 0x21000000 # 8-bit data bus # 2 wait states # mww 0xffe00008 0x21002026 # CS3: Expansion bus # 1MB @ 0x22000000 # 8-bit data bus # 8 wait states # mww 0xffe00010 0x22002e3e # Remap command # mww 0xffe00020 0x00000001 if {$VERBOSE != 0} { echo "0x00000000 RAM" echo "0x10000000 Flash" echo "0x20000000 Ethernet" echo "0x21000000 CPLD" echo "0x22000000 Expansion" } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/evb-lan9255.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Microchip LAN9255 evaluation board # https://www.microchip.com/en-us/development-tool/EV25Y25A # set CHIPNAME same53 source [find target/atsame5x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/frdm-kl25z.cfg ================================================ # This is an Freescale Freedom eval board with a single MKL25Z128VLK4 chip. # http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=FRDM-KL25Z # source [find interface/cmsis-dap.cfg] # increase working area to 16KB set WORKAREASIZE 0x4000 # chip name set CHIPNAME MKL25Z128VLK4 reset_config srst_only source [find target/kl25.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/frdm-kl46z.cfg ================================================ # This is an Freescale Freedom eval board with a single MKL46Z256VLL4 chip. # http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=FRDM-KL46Z # source [find interface/cmsis-dap.cfg] # increase working area to 16KB set WORKAREASIZE 0x4000 # chip name set CHIPNAME MKL46Z256VLL4 reset_config srst_only source [find target/kl46.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/fsl_imx6q_sabresd.cfg ================================================ # # Board configuration file for the Freescale IMX6Q Sabre SD EVM # # This board does not have an embedded JTAG adapter, you must source # a suitable adapter configuration before sourcing this file. # Sabre SD has a standard ARM-20 JTAG connector with # nTRST and nSRST available. reset_config trst_and_srst # the only possible transport is JTAG transport select jtag # iMX6Q POR gates JTAG and the chip is completely incommunicado # over JTAG for at least 10ms after nSRST is deasserted adapter srst delay 11 # Source generic iMX6Q target configuration set CHIPNAME imx6q source [find target/imx6.cfg] # function to apply initial configuration after a reset. It # provides a basic pad configuration and also DDR memory and clocks # sufficient to load and execute a boot loader (e.g. barebox) from # DDR memory. This list is extracted from the barebox flash image # header. proc apply_dcd { } { mww 0x020e05a8 0x00000030 mww 0x020e05b0 0x00000030 mww 0x020e0524 0x00000030 mww 0x020e051c 0x00000030 mww 0x020e0518 0x00000030 mww 0x020e050c 0x00000030 mww 0x020e05b8 0x00000030 mww 0x020e05c0 0x00000030 mww 0x020e05ac 0x00020030 mww 0x020e05b4 0x00020030 mww 0x020e0528 0x00020030 mww 0x020e0520 0x00020030 mww 0x020e0514 0x00020030 mww 0x020e0510 0x00020030 mww 0x020e05bc 0x00020030 mww 0x020e05c4 0x00020030 mww 0x020e056c 0x00020030 mww 0x020e0578 0x00020030 mww 0x020e0588 0x00020030 mww 0x020e0594 0x00020030 mww 0x020e057c 0x00020030 mww 0x020e0590 0x00003000 mww 0x020e0598 0x00003000 mww 0x020e058c 0x00000000 mww 0x020e059c 0x00003030 mww 0x020e05a0 0x00003030 mww 0x020e0784 0x00000030 mww 0x020e0788 0x00000030 mww 0x020e0794 0x00000030 mww 0x020e079c 0x00000030 mww 0x020e07a0 0x00000030 mww 0x020e07a4 0x00000030 mww 0x020e07a8 0x00000030 mww 0x020e0748 0x00000030 mww 0x020e074c 0x00000030 mww 0x020e0750 0x00020000 mww 0x020e0758 0x00000000 mww 0x020e0774 0x00020000 mww 0x020e078c 0x00000030 mww 0x020e0798 0x000c0000 mww 0x021b081c 0x33333333 mww 0x021b0820 0x33333333 mww 0x021b0824 0x33333333 mww 0x021b0828 0x33333333 mww 0x021b481c 0x33333333 mww 0x021b4820 0x33333333 mww 0x021b4824 0x33333333 mww 0x021b4828 0x33333333 mww 0x021b0018 0x00081740 mww 0x021b001c 0x00008000 mww 0x021b000c 0x555a7975 mww 0x021b0010 0xff538e64 mww 0x021b0014 0x01ff00db mww 0x021b002c 0x000026d2 mww 0x021b0030 0x005b0e21 mww 0x021b0008 0x09444040 mww 0x021b0004 0x00025576 mww 0x021b0040 0x00000027 mww 0x021b0000 0x831a0000 mww 0x021b001c 0x04088032 mww 0x021b001c 0x0408803a mww 0x021b001c 0x00008033 mww 0x021b001c 0x0000803b mww 0x021b001c 0x00428031 mww 0x021b001c 0x00428039 mww 0x021b001c 0x09408030 mww 0x021b001c 0x09408038 mww 0x021b001c 0x04008040 mww 0x021b001c 0x04008048 mww 0x021b0800 0xa1380003 mww 0x021b4800 0xa1380003 mww 0x021b0020 0x00005800 mww 0x021b0818 0x00022227 mww 0x021b4818 0x00022227 mww 0x021b083c 0x434b0350 mww 0x021b0840 0x034c0359 mww 0x021b483c 0x434b0350 mww 0x021b4840 0x03650348 mww 0x021b0848 0x4436383b mww 0x021b4848 0x39393341 mww 0x021b0850 0x35373933 mww 0x021b4850 0x48254A36 mww 0x021b080c 0x001f001f mww 0x021b0810 0x001f001f mww 0x021b480c 0x00440044 mww 0x021b4810 0x00440044 mww 0x021b08b8 0x00000800 mww 0x021b48b8 0x00000800 mww 0x021b001c 0x00000000 mww 0x021b0404 0x00011006 mww 0x020c4068 0x00c03f3f mww 0x020c406c 0x0030fc03 mww 0x020c4070 0x0fffc000 mww 0x020c4074 0x3ff00000 mww 0x020c4078 0x00fff300 mww 0x020c407c 0x0f0000c3 mww 0x020c4080 0x000003ff mww 0x020e0010 0xf00000cf mww 0x020e0018 0x007f007f mww 0x020e001c 0x007f007f } # disable watchdog proc disable_wdog { } { mwh 0x020bc000 0x30 } # This function applies the initial configuration after a "reset init" # command proc imx6q_sabresd_init { } { disable_wdog apply_dcd } # prevent cortex-a code from asserting SRST again $_TARGETNAME.0 configure -event reset-assert { } # hook the init function into the reset-init event $_TARGETNAME.0 configure -event reset-init { imx6q_sabresd_init } # set a slow default JTAG clock, can be overridden later adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/glyn_tonga2.cfg ================================================ # # Glyn Tonga2 SO-DIMM CPU module (Toshiba TMPA900CMXBG, ARM9) # # http://toshiba-mikrocontroller.de/sites/TMPA900CPUBOARDStarter.htm # # Hardware on the S0-DIMM module: # - Toshiba TMPA900CMXBG (ARM9, ARM926EJ-S, max. 200MHz) # - DDR SDRAM: Hynix H5MS5162DFR-J3M (64Mbyte, x16, 1.8V, 166/83MHz at CL3/2) # - NAND flash: Samsung K9F2G08U0B-PIB0 (256M x 8 Bit, 3.3V) # - Ethernet: SMSC LAN9221I-ABZJ (10/100Mbit, Non-PCI, 16 bit interface) # source [find target/tmpa900.cfg] ######################## # Target configuration # ######################## # Initial JTAG speed should not exceed 1/6 of the initial CPU clock # frequency (24MHz). Be conservative and use 1/8 of the frequency. # (24MHz / 8 = 3MHz) adapter speed 3000 $_TARGETNAME configure -event reset-start { # Upon reset, set the JTAG frequency to 3MHz again, see above. echo "Setting JTAG speed to 3MHz until clocks are initialized." adapter speed 3000 # Halt the CPU. halt # Disable faster memory access for now. arm7_9 fast_memory_access disable } $_TARGETNAME configure -event reset-init { # Setup clocks, and initialize SRAM and DDR SDRAM. tonga2_init # At this point the CPU is running at 192MHz, increase JTAG speed. # Tests showed that 15MHz works OK, higher speeds can cause problems, # though. Not sure if this is a CPU issue or JTAG adapter issue. echo "Increasing JTAG speed to 15MHz." adapter speed 15000 # Enable faster memory access. arm7_9 fast_memory_access enable } proc tonga2_init { } { ###################### # PLL initialization # ###################### # Clock overview (see datasheet chapter 3.5.2, page 57): # - fs: Low-frequency oscillator # - fOSCH: High-frequency oscillator (24MHz on this board) # - fPLL = fOSCH * multiplier (where multiplier can be 6 or 8) # - fFCLK = fPLL / gear (where gear can be 1/2/4/8) # - fHCLK is always fFCLK/2. fPCLK is also fFCLK/2. # # We select multiplier = 8 and gear = 1, so # fFCLK = fOSCH * 8 / 1 = 192MHz. # SYSCR3 (System Control Register 3): Disable and configure PLL. # - PLL operation control: off # - PLL constant value setting 1: always 0, as per datasheet # - PLL constant value setting 2: x8 (multiplier = 8) mww 0xf005000c 0x00000007 # SYSCR4 (System Control Register 4): Configure PLL. # - PLL constant value setting 3: 140MHz or more # - PLL constant value setting 4: always 1, as per datasheet # - PLL constant value setting 5: 140MHz or more mww 0xf0050010 0x00000065 # SYSCR3 (System Control Register 3): Enable PLL. # - PLL operation control: on # - All other bits remain set as above. mww 0xf005000c 0x00000087 # Wait for PLL to stabilize. sleep 10 # SYSCR2 (System Control Register 2): Switch from fOSCH to fPLL. # - Selection of the PLL output clock: fPLL mww 0xf0050008 0x00000002 # SYSCR1 (System Control Register 1): # - Clock gear programming: fc/1 (i.e., gear = 1, don't divide). mww 0xf0050004 0x00000000 # CLKCR5 (Clock Control Register 5): Set bits 3 and 6. The datasheet # says the bits are reserved, but also recommends "Write as one". mww 0xf0050054 0x00000048 ############################################################## # Dynamic Memory Controller (DMC) / DDR SDRAM initialization # ############################################################## # PMC (Power Management Controller): # PMCDRV (External Port "Driverbility" control register): # Bits DRV_MEM0/DRV_MEM1 (memory relation port drive power): mww 0xf0020260 0x00000003 ;# Select 1.8V +/- 0.1V # Setup DDR SDRAM timing parameters for our specific chip. mww 0xf4310014 0x00000004 ;# cas_latency = 2 mww 0xf4310018 0x00000001 ;# t_dqss = 1 mww 0xf431001c 0x00000002 ;# t_mrd = 2 mww 0xf4310020 0x0000000a ;# t_ras = 10 mww 0xf4310024 0x0000000a ;# t_rc = 10 mww 0xf4310028 0x00000013 ;# t_rcd = 3, schedule_rcd = 2 mww 0xf431002c 0x0000010a ;# t_rfc = 10, schedule_rfc = 8 mww 0xf4310030 0x00000013 ;# t_rp = 3, schedule_rp = 2 mww 0xf4310034 0x00000002 ;# t_rrd = 2 mww 0xf4310038 0x00000002 ;# t_wr = 2 mww 0xf431003c 0x00000001 ;# t_wtr = 1 mww 0xf4310040 0x0000000a ;# t_xp = 10 mww 0xf4310044 0x0000000c ;# t_xsr = 12 mww 0xf4310048 0x00000014 ;# t_esr = 20 # dmc_memory_cfg_5 (DMC Memory Configuration register): # Set memory configuration: # column_bits = 10, row_bits = 13, ap-bit = 10, power_down_prd = 0, # auto_power_down = disable, stop_mem_clock = disable, memory_burst = 4 mww 0xf431000c 0x00010012 # dmc_user_config_5 (DMC user_config register): # Data bus width of DDR SDRAM: 16 bit mww 0xf4310304 0x00000058 # dmc_refresh_prd_5 (DMC Refresh Period register): # Auto refresh: every 2656 (0xa60) DMCSCLK periods. mww 0xf4310010 0x00000a60 # dmc_chip_0_cfg_5 (DMC chip_0_cfg registers): # - SDRAM address structure: bank, row, column # - address_match = 01000000 (start address [31:24]) # - address_mask = 11111100 (start address [31:24] mask value) mww 0xf4310200 0x000140fc # Initialize the DDR SDRAM chip. # dmc_direct_cmd_5 (DMC Direct Command register). # See datasheet chapter 3.10.5.1, page 268. mww 0xf4310008 0x000c0000 ;# RAM init: NOP mww 0xf4310008 0x00000000 ;# RAM init: Precharge all mww 0xf4310008 0x00040000 ;# RAM init: Autorefresh mww 0xf4310008 0x00040000 ;# RAM init: Autorefresh mww 0xf4310008 0x00080032 ;# RAM init: addr_13_to_0 = 0x32 mww 0xf4310008 0x000c0000 ;# RAM init: NOP mww 0xf4310008 0x000a0000 ;# RAM init: bank_addr = bank 2 # dmc_id_<0-5>_cfg_5 (DMC id_<0-5>_cfg registers): # Set min./max. QoS values. # - 0x5: Enable QoS, max. QoS = 1 # - 0xb: Enable QoS, min. QoS = 2 mww 0xf4310100 0x00000005 ;# AHB0: CPU Data mww 0xf4310104 0x00000005 ;# AHB1: CPU Inst mww 0xf4310108 0x0000000b ;# AHB2: LCDC mww 0xf431010c 0x00000005 ;# AHB3: LCDDA, USB mww 0xf4310110 0x00000005 ;# AHB4: DMA1 mww 0xf4310114 0x00000005 ;# AHB5: DMA2 # dmc_memc_cmd_5 (DMC Memory Controller Command register): # Change DMC state to ready. mww 0xf4310004 0x00000000 ;# memc_cmd = "Go" # EBI: SMC Timeout register mww 0xf00a0050 0x00000001 ;# smc_timeout = 1 ######################################################## # Static Memory Controller (SMC) / SRAM initialization # ######################################################## # smc_set_cycles_5 (SMC Set Cycles register): # tRC = 10, tWC = 10, tCEOE = 7, tWP = 5, tPC=2, tTR=2 mww 0xf4311014 0x0004afaa # smc_set_opmode_5 (SMC Set Opmode register): # Memory data bus width = 16 bits, async read mode, read burst # length = 1 beat, async write mode, write burst length = 1 beat, # byte enable (SMCBE0-1) timing = SMCCSn timing, memory burst boundary # split setting = burst can cross any address boundary mww 0xf4311018 0x00000001 # smc_direct_cmd_5 (SMC Direct Command register): # cmd_type = UpdateRegs, chip_select = CS1 mww 0xf4311010 0x00c00000 echo "Clocks, SRAM, and DDR SDRAM are now initialized." } ####################### # Flash configuration # ####################### # TODO: Implement NAND support. ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/gti/espressobin.cfg ================================================ # config for ESPRESSObin from # Globalscale Technologies Inc. # srst is isolated through missing resistor reset_config trst_only source [find target/marvell/88f3720.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/gumstix-aerocore.cfg ================================================ # JTAG for the STM32F4x chip used on the Gumstix AeroCore is available on # the first interface of a Quad FTDI chip. nTRST is bit 4. adapter driver ftdi ftdi vid_pid 0x0403 0x6011 ftdi layout_init 0x0000 0x001b ftdi layout_signal nTRST -data 0x0010 source [find target/stm32f4x.cfg] reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/hammer.cfg ================================================ # Target Configuration for the TinCanTools S3C2410 Based Hammer Module # http://www.tincantools.com source [find target/samsung_s3c2410.cfg] $_TARGETNAME configure -event reset-init { # Reset Script for the TinCanTools S3C2410 Based Hammer Module # http://www.tincantools.com # # Setup primary clocks and initialize the SDRAM mww 0x53000000 0x00000000 mww 0x4a000008 0xffffffff mww 0x4a00000c 0x000007ff mww 0x4c000000 0x00ffffff mww 0x4c000014 0x00000003 mww 0x4c000004 0x000a1031 mww 0x48000000 0x11111122 mww 0x48000004 0x00000700 mww 0x48000008 0x00000700 mww 0x4800000c 0x00000700 mww 0x48000010 0x00000700 mww 0x48000014 0x00000700 mww 0x48000018 0x00000700 mww 0x4800001c 0x00018005 mww 0x48000020 0x00018005 mww 0x48000024 0x009c0459 mww 0x48000028 0x000000b2 mww 0x4800002c 0x00000030 mww 0x48000030 0x00000030 flash probe 0 } #flash configuration #flash bank [driver_options ...] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x1000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/hilscher_nxdb500sys.cfg ================================================ ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ source [find target/hilscher_netx500.cfg] reset_config trst_and_srst adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x1000 -work-area-phys 0x1000 -work-area-size 0x4000 -work-area-backup 1 $_TARGETNAME configure -event reset-init { halt arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable sdram_fix puts "Configuring SDRAM controller for paired K4S561632C (64MB) " mww 0x00100140 0 mww 0x00100144 0x03C13261 mww 0x00100140 0x030D0121 puts "Configuring SRAM nCS0 for 150ns paired Par. Flash (x32)" mww 0x00100100 0x0201000E flash probe 0 } ##################### # Flash configuration ##################### #flash bank flash bank parflash cfi 0xC0000000 0x02000000 4 4 $_TARGETNAME init reset init ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/hilscher_nxeb500hmi.cfg ================================================ ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ source [find target/hilscher_netx500.cfg] reset_config trst_and_srst adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x1000 -work-area-phys 0x1000 -work-area-size 0x4000 -work-area-backup 1 $_TARGETNAME configure -event reset-init { halt arm7_9 fast_memory_access enable arm7_9 dcc_downloads disable sdram_fix puts "Configuring SDRAM controller for MT48LC8M32 (32MB) " mww 0x00100140 0 mww 0x00100144 0x03C23251 mww 0x00100140 0x030D0111 puts "Configuring SRAM nCS0 for 150ns Par. Flash (x16)" mww 0x00100100 0x0101000E flash probe 0 } ##################### # Flash configuration ##################### #flash bank flash bank parflash cfi 0xC0000000 0x01000000 2 2 $_TARGETNAME init reset init ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/hilscher_nxhx10.cfg ================================================ ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ source [find target/hilscher_netx10.cfg] # Usually it is not needed to set srst_pulls_trst # but sometimes it does not work without it. If you encounter # problems try to line below # reset_config trst_and_srst srst_pulls_trst reset_config trst_and_srst adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x08000000 -work-area-phys 0x08000000 -work-area-size 0x4000 -work-area-backup 1 # Par. Flash can only be accessed if DIP switch on the board is set in proper # position and init_sdrambus was called. Don't call these functions if the DIP # switch is in invalid position, as some outputs may collide. This is why this # function is not called automatically proc flash_init { } { puts "Configuring SRAM nCS0 for 90ns Par. Flash (x16)" mww 0x101C0100 0x01010008 flash probe 0 } proc mread32 {addr} { return [read_memory $addr 32 1] } proc init_clocks { } { puts "Enabling all clocks " set accesskey [mread32 0x101c0070] mww 0x101c0070 $accesskey mww 0x101c0028 0x00007511 } proc init_sdrambus { } { puts "Initializing external SDRAM Bus 16 Bit " set accesskey [mread32 0x101c0070] mww 0x101c0070 $accesskey mww 0x101c0C40 0x00000050 puts "Configuring SDRAM controller for K4S561632E (32MB) " mww 0x101C0140 0 sleep 100 #mww 0x101C0144 0x00a13262 mww 0x101C0144 0x00a13251 mww 0x101C0148 0x00000033 mww 0x101C0140 0x030d0121 } $_TARGETNAME configure -event reset-init { halt wait_halt 1000 arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable init_clocks # init_sdrambus puts "" puts "-------------------------------------------------" puts "Call 'init_clocks' to enable all clocks" puts "Call 'init_sdrambus' to enable external SDRAM bus" puts "-------------------------------------------------" } ##################### # Flash configuration ##################### #flash bank #flash bank parflash cfi 0xC0000000 0x01000000 2 2 $_TARGETNAME init reset init ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/hilscher_nxhx50.cfg ================================================ ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ source [find target/hilscher_netx50.cfg] reset_config trst_and_srst adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x10000000 -work-area-phys 0x10000000 -work-area-size 0x4000 -work-area-backup 1 $_TARGETNAME configure -event reset-init { halt arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable sdram_fix puts "Configuring SDRAM controller for MT48LC2M32 (8MB) " mww 0x1C000140 0 mww 0x1C000144 0x00A12151 mww 0x1C000140 0x030D0001 puts "Configuring SRAM nCS0 for 90ns Par. Flash (x16)" mww 0x1C000100 0x01010008 flash probe 0 } ##################### # Flash configuration ##################### #flash bank flash bank parflash cfi 0xC0000000 0x01000000 2 2 $_TARGETNAME init reset init ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/hilscher_nxhx500.cfg ================================================ ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ source [find target/hilscher_netx500.cfg] reset_config trst_and_srst adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x1000 -work-area-phys 0x1000 -work-area-size 0x4000 -work-area-backup 1 $_TARGETNAME configure -event reset-init { halt arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable sleep 100 sdram_fix puts "Configuring SDRAM controller for MT48LC2M32 (8MB) " mww 0x00100140 0 mww 0x00100144 0x03C23251 mww 0x00100140 0x030D0001 puts "Configuring SRAM nCS0 for 90ns Par. Flash (x16)" mww 0x00100100 0x01010008 flash probe 0 } ##################### # Flash configuration ##################### #flash bank flash bank parflash cfi 0xC0000000 0x01000000 2 2 $_TARGETNAME init reset init ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/hilscher_nxsb100.cfg ================================================ ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ source [find target/hilscher_netx500.cfg] reset_config trst_and_srst adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x1000 -work-area-phys 0x1000 -work-area-size 0x4000 -work-area-backup 1 $_TARGETNAME configure -event reset-init { halt arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable sdram_fix puts "Configuring SDRAM controller for MT48LC2M32 (8MB) " mww 0x00100140 0 mww 0x00100144 0x03C23251 mww 0x00100140 0x030D0001 } init reset init ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/hitex_lpc1768stick.cfg ================================================ # Hitex LPC1768 Stick # # http://www.hitex.com/?id=1602 # reset_config trst_and_srst source [find interface/ftdi/hitex_lpc1768stick.cfg] source [find target/lpc17xx.cfg] # startup @ 500kHz adapter speed 500 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/hitex_lpc2929.cfg ================================================ # Hitex eval board for LPC2929/LPC2939 # http://www.hitex.com/ # Delays on reset lines adapter srst delay 50 jtag_ntrst_delay 1 # Maximum of 1/8 of clock frequency (XTAL = 16 MHz). # Adaptive clocking through RTCK is not supported. adapter speed 2000 # Target device: LPC29xx with ETB # The following variables are used by the LPC2900 script: # HAS_ETB Must be set to 1. The CPU on this board has ETB. # FLASH_CLOCK CPU frequency at the time of flash programming (in kHz) set HAS_ETB 1 set FLASH_CLOCK 112000 source [find target/lpc2900.cfg] # A working area will help speeding the flash programming #$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 0x2000 -work-area-backup 0 $_TARGETNAME configure -work-area-phys 0x58000000 -work-area-size 0x10000 -work-area-backup 0 # Event handlers $_TARGETNAME configure -event reset-start { # Back to the slow JTAG clock adapter speed 2000 } # External 16-bit flash at chip select CS7 (SST39VF3201-70, 4 MiB) set _FLASHNAME $_CHIPNAME.extflash flash bank $_FLASHNAME cfi 0x5C000000 0x400000 2 2 $_TARGETNAME jedec_probe $_TARGETNAME configure -event reset-init { # Flash mww 0x20200010 0x00000007 ;# FBWST: 7 wait states, not cached # Use PLL mww 0xFFFF8020 0x00000001 ;# XTAL_OSC_CONTROL: enable, 1-20 MHz mww 0xFFFF8070 0x01000000 ;# SYS_CLK_CONF: Crystal mww 0xFFFF8028 0x00000005 ;# PLL: (power down) mww 0xFFFF8028 0x01060004 ;# PLL: M=7, 2P=2 (power up) # --> f=112 MHz, fcco=224 MHz sleep 100 mww 0xFFFF8070 0x02000000 ;# SYS_CLK_CONF: PLL # Increase JTAG speed adapter speed 6000 # Enable external memory bus (16-bit SRAM at CS6, 16-bit flash at CS7) mww 0xE0001138 0x0000001F ;# P1.14 = D0 mww 0xE000113C 0x0000001F ;# P1.15 = D1 mww 0xE0001140 0x0000001F ;# P1.16 = D2 mww 0xE0001144 0x0000001F ;# P1.17 = D3 mww 0xE0001148 0x0000001F ;# P1.18 = D4 mww 0xE000114C 0x0000001F ;# P1.19 = D5 mww 0xE0001150 0x0000001F ;# P1.20 = D6 mww 0xE0001154 0x0000001F ;# P1.21 = D7 mww 0xE0001200 0x0000001F ;# P2.0 = D8 mww 0xE0001204 0x0000001F ;# P2.1 = D9 mww 0xE0001208 0x0000001F ;# P2.2 = D10 mww 0xE000120C 0x0000001F ;# P2.3 = D11 mww 0xE0001210 0x0000001F ;# P2.4 = D12 mww 0xE0001214 0x0000001F ;# P2.5 = D13 mww 0xE0001218 0x0000001F ;# P2.6 = D14 mww 0xE000121C 0x0000001F ;# P2.7 = D15 mww 0xE0001104 0x00000007 ;# P1.1 = A1 mww 0xE0001108 0x00000007 ;# P1.2 = A2 mww 0xE000110C 0x00000007 ;# P1.3 = A3 mww 0xE0001110 0x00000007 ;# P1.4 = A4 mww 0xE0001114 0x00000007 ;# P1.5 = A5 mww 0xE0001118 0x00000007 ;# P1.6 = A6 mww 0xE000111C 0x00000007 ;# P1.7 = A7 mww 0xE0001028 0x00000007 ;# P0.10 = A8 mww 0xE000102C 0x00000007 ;# P0.11 = A9 mww 0xE0001030 0x00000007 ;# P0.12 = A10 mww 0xE0001034 0x00000007 ;# P0.13 = A11 mww 0xE0001038 0x00000007 ;# P0.14 = A12 mww 0xE000103C 0x00000007 ;# P0.15 = A13 mww 0xE0001048 0x00000007 ;# P0.18 = A14 mww 0xE000104C 0x00000007 ;# P0.19 = A15 mww 0xE0001050 0x00000007 ;# P0.20 = A16 mww 0xE0001054 0x00000007 ;# P0.21 = A17 mww 0xE0001058 0x00000007 ;# P0.22 = A18 mww 0xE000105C 0x00000007 ;# P0.23 = A19 mww 0xE0001238 0x00000007 ;# P2.14 = BLS0 mww 0xE000123C 0x00000007 ;# P2.15 = BLS1 mww 0xE0001300 0x00000007 ;# P3.0 = CS6 mww 0xE0001304 0x00000007 ;# P3.1 = CS7 mww 0xE0001130 0x00000007 ;# P1.12 = OE_N mww 0xE0001134 0x00000007 ;# P1.13 = WE_N mww 0x600000BC 0x00000041 ;# Bank6 16-bit mode, RBLE=1 mww 0x600000B4 0x00000000 ;# Bank6 WSTOEN=0 mww 0x600000AC 0x00000005 ;# Bank6 WST1=5 mww 0x600000B8 0x00000001 ;# Bank6 WSTWEN=1 mww 0x600000B0 0x00000006 ;# Bank6 WST2=6 mww 0x600000A8 0x00000002 ;# Bank6 IDCY=2 mww 0x600000D8 0x00000041 ;# Bank7 16-bit mode, RBLE=1 mww 0x600000D0 0x00000000 ;# Bank7 WSTOEN=0 mww 0x600000C8 0x0000000A ;# Bank7 WST1=10 mww 0x600000D4 0x00000001 ;# Bank7 WSTWEN=1 mww 0x600000CC 0x0000000C ;# Bank7 WST2=8 mww 0x600000C4 0x00000002 ;# Bank7 IDCY=2 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/hitex_stm32-performancestick.cfg ================================================ # Hitex stm32 performance stick reset_config trst_and_srst source [find interface/ftdi/stm32-stick.cfg] set CHIPNAME stm32_hitex source [find target/stm32f1x.cfg] # configure str750 connected to jtag chain # FIXME -- source [find target/str750.cfg] after cleaning that up jtag newtap str750 cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id 0x4f1f0041 # for some reason this board like to startup @ 500kHz adapter speed 500 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/hitex_str9-comstick.cfg ================================================ # Hitex STR9-comStick # http://www.hitex.com/index.php?id=383 # This works for the STR9-comStick revisions STR912CS-A1 and STR912CS-A2. source [find interface/ftdi/hitex_str9-comstick.cfg] # set jtag speed adapter speed 3000 adapter srst delay 100 jtag_ntrst_delay 100 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst # # FIXME use the standard str912 target config; that script might need # updating to "-ignore-version" for the boundary scan TAP # # source [find target/str912.cfg] # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME str912 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists FLASHTAPID] } { set _FLASHTAPID $FLASHTAPID } else { set _FLASHTAPID 0x04570041 } jtag newtap $_CHIPNAME flash -irlen 8 -ircapture 0x1 -irmask 0x1 -expected-id $_FLASHTAPID if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x25966041 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID if { [info exists BSTAPID] } { set _BSTAPID $BSTAPID } else { # Found on STR9-comStick, revision STR912CS-A1 set _BSTAPID1 0x1457f041 # Found on STR9-comStick, revision STR912CS-A2 set _BSTAPID2 0x2457f041 } jtag newtap $_CHIPNAME bs -irlen 5 -ircapture 0x1 -irmask 0x1 -expected-id $_BSTAPID1 -expected-id $_BSTAPID2 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-init { # We can increase speed now that we know the target is halted. #jtag_rclk 3000 # -- Enable 96K RAM # PFQBC enabled / DTCM & AHB wait-states disabled mww 0x5C002034 0x0191 str9x flash_config 0 4 2 0 0x80000 flash protect 0 0 7 off } $_TARGETNAME configure -work-area-phys 0x50000000 -work-area-size 16384 -work-area-backup 0 #flash bank set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME str9x 0x00000000 0x00080000 0 0 0 set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME str9x 0x00080000 0x00008000 0 0 0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/iar_lpc1768.cfg ================================================ # Board from IAR KickStart Kit for LPC1768 # See www.iar.com and also # http://www.olimex.com/dev/lpc-1766stk.html # source [find target/lpc17xx.cfg] # The chip has just been reset. # $_TARGETNAME configure -event reset-init { # FIXME update the core clock to run at 100 MHz; # and update JTAG clocking similarly; then # make CCLK match, flash probe 0 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/iar_str912_sk.cfg ================================================ # The IAR str912-sk evaluation kick start board has an str912 source [find target/str912.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/icnova_imx53_sodimm.cfg ================================================ ################################################################################################# # Author: Benjamin Tietz ;# # based on work from: Wjatscheslaw Stoljarski (Slawa) ;# # Kiwigrid GmbH ;# # Generated for In-Circuit i.MX53 SO-Dimm ;# ################################################################################################# # The In-Circuit ICnova IMX53SODIMM board has a single IMX53 chip source [find target/imx53.cfg] # Helper for common memory read/modify/write procedures source [find mem_helper.tcl] echo "i.MX53 SO-Dimm board lodaded." # Set reset type #reset_config srst_only adapter speed 3000 # Slow speed to be sure it will work jtag_rclk 1000 $_TARGETNAME configure -event "reset-start" { jtag_rclk 1000 } $_TARGETNAME configure -event "reset-assert" { echo "Resetting ...." #cortex_a dbginit } $_TARGETNAME configure -event reset-init { sodimm_init } global AIPS1_BASE_ADDR set AIPS1_BASE_ADDR 0x53F00000 global AIPS2_BASE_ADDR set AIPS2_BASE_ADDR 0x63F00000 proc sodimm_init { } { echo "Reset-init..." ; # halt the CPU halt echo "HW version [format %x [mrw 0x48]]" dap apsel 1 DCD ; # ARM errata ID #468414 set tR [arm mrc 15 0 1 0 1] arm mcr 15 0 1 0 1 [expr {$tR | (1<<5)}] ; # enable L1NEON bit init_l2cc init_aips init_clock dap apsel 0 ; # Force ARM state ; #reg cpsr 0x000001D3 arm core_state arm jtag_rclk 3000 # adapter speed 3000 } # L2CC Cache setup/invalidation/disable proc init_l2cc { } { ; #/* explicitly disable L2 cache */ ; #mrc 15, 0, r0, c1, c0, 1 set tR [arm mrc 15 0 1 0 1] ; #bic r0, r0, #0x2 ; #mcr 15, 0, r0, c1, c0, 1 arm mcr 15 0 1 0 1 [expr {$tR & ~(1 << 2)}] ; #/* reconfigure L2 cache aux control reg */ ; #mov r0, #0xC0 /* tag RAM */ ; #add r0, r0, #0x4 /* data RAM */ ; #orr r0, r0, #(1 << 24) /* disable write allocate delay */ ; #orr r0, r0, #(1 << 23) /* disable write allocate combine */ ; #orr r0, r0, #(1 << 22) /* disable write allocate */ ; #mcr 15, 1, r0, c9, c0, 2 arm mcr 15 1 9 0 2 [expr {0xC4 | (1<<24) | (1<<23) | (1<<22)}] } # AIPS setup - Only setup MPROTx registers. # The PACR default values are good. proc init_aips { } { ; # Set all MPROTx to be non-bufferable, trusted for R/W, ; # not forced to user-mode. global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR set VAL 0x77777777 # dap apsel 1 mww [expr {$AIPS1_BASE_ADDR + 0x0}] $VAL mww [expr {$AIPS1_BASE_ADDR + 0x4}] $VAL mww [expr {$AIPS2_BASE_ADDR + 0x0}] $VAL mww [expr {$AIPS2_BASE_ADDR + 0x4}] $VAL # dap apsel 0 } proc init_clock { } { global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR set CCM_BASE_ADDR [expr {$AIPS1_BASE_ADDR + 0x000D4000}] set CLKCTL_CCSR 0x0C set CLKCTL_CBCDR 0x14 set CLKCTL_CBCMR 0x18 set PLL1_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00080000}] set PLL2_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00084000}] set PLL3_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00088000}] set PLL4_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x0008C000}] set CLKCTL_CSCMR1 0x1C set CLKCTL_CDHIPR 0x48 set PLATFORM_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x000A0000}] set CLKCTL_CSCDR1 0x24 set CLKCTL_CCDR 0x04 ; # Switch ARM to step clock mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x4 return echo "not returned" setup_pll $PLL1_BASE_ADDR 800 setup_pll $PLL3_BASE_ADDR 400 ; # Switch peripheral to PLL3 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00015154 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x02888945 | (1<<16)}] while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL2_BASE_ADDR 400 ; # Switch peripheral to PLL2 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x00808145 | (2<<10) | (9<<16) | (1<<19)}] mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00016154 ; # change uart clk parent to pll2 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}]] & 0xfcffffff | 0x01000000}] ; # make sure change is effective while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL3_BASE_ADDR 216 setup_pll $PLL4_BASE_ADDR 455 ; # Set the platform clock dividers mww [expr {$PLATFORM_BASE_ADDR + 0x14}] 0x00000124 mww [expr {$CCM_BASE_ADDR + 0x10}] 0 ; # Switch ARM back to PLL 1. mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x0 ; # make uart div=6 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}]] & 0xffffffc0 | 0x0a}] ; # Restore the default values in the Gate registers mww [expr {$CCM_BASE_ADDR + 0x68}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x6C}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x70}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x74}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x78}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x7C}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x80}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x84}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCDR}] 0x00000 ; # for cko - for ARM div by 8 mww [expr {$CCM_BASE_ADDR + 0x60}] [expr {0x000A0000 & 0x00000F0}] } proc setup_pll { PLL_ADDR CLK } { set PLL_DP_CTL 0x00 set PLL_DP_CONFIG 0x04 set PLL_DP_OP 0x08 set PLL_DP_HFS_OP 0x1C set PLL_DP_MFD 0x0C set PLL_DP_HFS_MFD 0x20 set PLL_DP_MFN 0x10 set PLL_DP_HFS_MFN 0x24 if {$CLK == 1000} { set DP_OP [expr {(10 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {12 - 1}] set DP_MFN 5 } elseif {$CLK == 850} { set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {48 - 1}] set DP_MFN 41 } elseif {$CLK == 800} { set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 700} { set DP_OP [expr {(7 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {24 - 1}] set DP_MFN 7 } elseif {$CLK == 600} { set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {4 - 1}] set DP_MFN 1 } elseif {$CLK == 665} { set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {96 - 1}] set DP_MFN 89 } elseif {$CLK == 532} { set DP_OP [expr {(5 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {24 - 1}] set DP_MFN 13 } elseif {$CLK == 455} { set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] set DP_MFD [expr {48 - 1}] set DP_MFN 71 } elseif {$CLK == 400} { set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 216} { set DP_OP [expr {(6 << 4) + ((3 - 1) << 0)}] set DP_MFD [expr {4 - 1}] set DP_MFN 3 } else { error "Error (setup_dll): clock not found!" } mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 mww [expr {$PLL_ADDR + $PLL_DP_CONFIG}] 0x2 mww [expr {$PLL_ADDR + $PLL_DP_OP}] $DP_OP mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_OP mww [expr {$PLL_ADDR + $PLL_DP_MFD}] $DP_MFD mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_MFD mww [expr {$PLL_ADDR + $PLL_DP_MFN}] $DP_MFN mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFN}] $DP_MFN mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 while {[expr {[mrw [expr {$PLL_ADDR + $PLL_DP_CTL}]] & 0x1}] == 0} { sleep 1 } } proc CPU_2_BE_32 { L } { return [expr {(($L & 0x000000FF) << 24) | (($L & 0x0000FF00) << 8) | (($L & 0x00FF0000) >> 8) | (($L & 0xFF000000) >> 24)}] } # Device Configuration Data proc DCD { } { # dap apsel 1 #*========================================================================================== ====== # Initialization script for 32 bit DDR3 (CS0+CS1) #*========================================================================================== ====== # Remux D24/D25 to perform Flash-access mww 0x53fa818C 0x00000000 ; #EIM_RW mww 0x53fa8180 0x00000000 ; #EIM_CS0 mww 0x53fa8188 0x00000000 ; #EIM_OE mww 0x53fa817C 0x00000000 ; #A16 mww 0x53fa8178 0x00000000 ; #A17 mww 0x53fa8174 0x00000000 ; #A18 mww 0x53fa8170 0x00000000 ; #A19 mww 0x53fa816C 0x00000000 ; #A20 mww 0x53fa8168 0x00000000 ; #A21 mww 0x53fa819C 0x00000000 ; #DA0 mww 0x53fa81A0 0x00000000 ; #DA1 mww 0x53fa81A4 0x00000000 ; #DA2 mww 0x53fa81A8 0x00000000 ; #DA3 mww 0x53fa81AC 0x00000000 ; #DA4 mww 0x53fa81B0 0x00000000 ; #DA5 mww 0x53fa81B4 0x00000000 ; #DA6 mww 0x53fa81B8 0x00000000 ; #DA7 mww 0x53fa81BC 0x00000000 ; #DA8 mww 0x53fa81C0 0x00000000 ; #DA9 mww 0x53fa81C4 0x00000000 ; #DA10 mww 0x53fa81C8 0x00000000 ; #DA11 mww 0x53fa81CC 0x00000000 ; #DA12 mww 0x53fa81D0 0x00000000 ; #DA13 mww 0x53fa81D4 0x00000000 ; #DA14 mww 0x53fa81D8 0x00000000 ; #DA15 mww 0x53fa8118 0x00000000 ; #D16 mww 0x53fa811C 0x00000000 ; #D17 mww 0x53fa8120 0x00000000 ; #D18 mww 0x53fa8124 0x00000000 ; #D19 mww 0x53fa8128 0x00000000 ; #D20 mww 0x53fa812C 0x00000000 ; #D21 mww 0x53fa8130 0x00000000 ; #D22 mww 0x53fa8134 0x00000000 ; #D23 mww 0x53fa813c 0x00000000 ; #IOMUXC_SW_PAD_CTL_PAD_EIM_D24 mww 0x53fa8140 0x00000000 ; #IOMUXC_SW_PAD_CTL_PAD_EIM_D25 mww 0x53fa8144 0x00000000 ; #D26 mww 0x53fa8148 0x00000000 ; #D27 mww 0x53fa814C 0x00000000 ; #D28 mww 0x53fa8150 0x00000000 ; #D29 mww 0x53fa8154 0x00000000 ; #D30 mww 0x53fa8158 0x00000000 ; #D31 # DDR3 IOMUX configuration #* Global pad control options */ mww 0x53fa8554 0x00380000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM3 mww 0x53fa8558 0x00380040 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS3 mww 0x53fa8560 0x00380000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM2 mww 0x53fa8564 0x00380040 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT1 mww 0x53fa8568 0x00380040 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS2 mww 0x53fa8570 0x00200000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_1 - boazp: weaker sdclk EVK DDR max frequency mww 0x53fa8574 0x00380000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_CAS mww 0x53fa8578 0x00200000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_0 - boazp: weaker sdclk EVK DDR max frequency mww 0x53fa857c 0x00380040 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0 mww 0x53fa8580 0x00380040 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT0 mww 0x53fa8584 0x00380000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM0 mww 0x53fa8588 0x00380000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_RAS mww 0x53fa8590 0x00380040 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS1 mww 0x53fa8594 0x00380000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM1 mww 0x53fa86f0 0x00380000 ; #IOMUXC_SW_PAD_CTL_GRP_ADDDS mww 0x53fa86f4 0x00000200 ; #IOMUXC_SW_PAD_CTL_GRP_DDRMODE_CTL mww 0x53fa86fc 0x00000000 ; #IOMUXC_SW_PAD_CTL_GRP_DDRPKE # mww 0x53fa8714 0x00000200 ; #IOMUXC_SW_PAD_CTL_GRP_DDRMODE - CMOS mode XXX mww 0x53fa8714 0x00000000 ; #IOMUXC_SW_PAD_CTL_GRP_DDRMODE - CMOS mode XXX mww 0x53fa8718 0x00380000 ; #IOMUXC_SW_PAD_CTL_GRP_B0DS mww 0x53fa871c 0x00380000 ; #IOMUXC_SW_PAD_CTL_GRP_B1DS mww 0x53fa8720 0x00380000 ; #IOMUXC_SW_PAD_CTL_GRP_CTLDS mww 0x53fa8724 0x00000000 ; #IOMUXC_SW_PAD_CTL_GRP_DDR_TYPE - DDR_SEL=0 XXX mww 0x53fa8728 0x00380000 ; #IOMUXC_SW_PAD_CTL_GRP_B2DS mww 0x53fa872c 0x00380000 ; #IOMUXC_SW_PAD_CTL_GRP_B3DS # mww 0x53fa86f4 0x00000000 ;IOMUXC_SW_PAD_CTL_GRP_DDRMODE_CTL for sDQS[3:0], 1=DDR2, 0=CMOS mode # mww 0x53fa8714 0x00000000 ;IOMUXC_SW_PAD_CTL_GRP_DDRMODE for D[31:0], 1=DDR2, 0=CMOS mode # mww 0x53fa86fc 0x00000000 ;IOMUXC_SW_PAD_CTL_GRP_DDRPKE # mww 0x53fa8724 0x00000000 ;IOMUXC_SW_PAD_CTL_GRP_DDR_TYPE - DDR_SEL=00 #* Data bus byte lane pad drive strength control options */ # mww 0x53fa872c 0x00300000 ;IOMUXC_SW_PAD_CTL_GRP_B3DS # mww 0x53fa8554 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM3 # mww 0x53fa8558 0x00300040 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS3 # mww 0x53fa8728 0x00300000 ;IOMUXC_SW_PAD_CTL_GRP_B2DS # mww 0x53fa8560 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM2 # mww 0x53fa8568 0x00300040 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS2 # mww 0x53fa871c 0x00300000 ;IOMUXC_SW_PAD_CTL_GRP_B1DS # mww 0x53fa8594 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM1 # mww 0x53fa8590 0x00300040 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS1 # mww 0x53fa8718 0x00300000 ;IOMUXC_SW_PAD_CTL_GRP_B0DS # mww 0x53fa8584 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM0 # mww 0x53fa857c 0x00300040 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0 #* SDCLK pad drive strength control options */ # mww 0x53fa8578 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_0 # mww 0x53fa8570 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_1 #* Control and addr bus pad drive strength control options */ # mww 0x53fa8574 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_CAS # mww 0x53fa8588 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_RAS # mww 0x53fa86f0 0x00300000 ;IOMUXC_SW_PAD_CTL_GRP_ADDDS for DDR addr bus # mww 0x53fa8720 0x00300000 ;IOMUXC_SW_PAD_CTL_GRP_CTLDS for CSD0, CSD1, SDCKE0, SDCKE1, SDWE # mww 0x53fa8564 0x00300040 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT1 # mww 0x53fa8580 0x00300040 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT0 # Initialize DDR3 memory - Micron MT41J128M16-187Er #** Keep for now, same setting as CPU3 board **# mww 0x63fd901c 0x00008000 # mww 0x63fd904c 0x01680172 ; #write leveling reg 0 # mww 0x63fd9050 0x0021017f ; #write leveling reg 1 mww 0x63fd9088 0x32383535 ; #read delay lines mww 0x63fd9090 0x40383538 ; #write delay lines # mww 0x63fd90F8 0x00000800 ; #Measure unit mww 0x63fd907c 0x0136014d ; #DQS gating 0 mww 0x63fd9080 0x01510141 ; #DQS gating 1 #* CPU3 Board settingr # Enable bank interleaving, Address mirror on, WALAT 0x1, RALAT = 0x5, DDR2_EN = 0 # mww 0x63fd9018 0x00091740 ; #Misc register: #* Quick Silver board setting # Enable bank interleaving, Address mirror off, WALAT 0x1, RALAT = 0x5, DDR2_EN = 0 mww 0x63fd9018 0x00011740 ; #Misc register # Enable CSD0 and CSD1, row width = 14, column width = 10, burst length = 8, data width = 32bit # mww 0x63fd9000 0xc3190000 ; #Main control register # Enable CSD0 and CSD1, row width = 14, column width = 10, burst length = 8, data width = 32bit mww 0x63fd9000 0x83190000 ; #Main control register # tRFC=64ck;tXS=68;tXP=3;tXPDLL=10;tFAW=15;CAS=6ck mww 0x63fd900C 0x555952E3 ; #timing configuration Reg 0 # tRCD=6;tRP=6;tRC=21;tRAS=15;tRPA=1;tWR=6;tMRD=4;tCWL=5ck mww 0x63fd9010 0xb68e8b63 ; #timing configuration Reg 1 # tDLLK(tXSRD)=512 cycles; tRTP=4;tWTR=4;tRRD=4 mww 0x63fd9014 0x01ff00db ; #timing configuration Reg 2 mww 0x63fd902c 0x000026d2 ; #command delay (default) mww 0x63fd9030 0x009f0e21 ; #out of reset delays # Keep tAOFPD, tAONPD, tANPD, and tAXPD as default since they are bigger than calc values mww 0x63fd9008 0x12273030 ; #ODT timings # tCKE=3; tCKSRX=5; tCKSRE=5 mww 0x63fd9004 0x0002002d #Power down control #********************************** #DDR device configuration: #********************************** #********************************** # CS0: #********************************** mww 0x63fd901c 0x00008032 ; #write mode reg MR2 with cs0 (see below for settings) # Full array self refresh # Rtt_WR disabled (no ODT at IO CMOS operation) # Manual self refresh # CWS=5 mww 0x63fd901c 0x00008033 ; #write mode reg MR3 with cs0. mww 0x63fd901c 0x00028031 ; #write mode reg MR1 with cs0. ODS=01: out buff= RZQ/7 (see below for settings) # out impedance = RZQ/7 # Rtt_nom disabled (no ODT at IO CMOS operation) # Aditive latency off # write leveling disabled # tdqs (differential?) disabled mww 0x63fd901c 0x09208030 ; #write mode reg MR0 with cs0 , with dll_rst0 mww 0x63fd901c 0x04008040 ; #ZQ calibration with cs0 (A10 high indicates ZQ cal long ZQCL) #********************************** # CS1: #********************************** # mww 0x63fd901c 0x0000803a ; #write mode reg MR2 with cs1. # mww 0x63fd901c 0x0000803b ; #write mode reg MR3 with cs1. # mww 0x63fd901c 0x00028039 ; #write mode reg MR1 with cs1. ODS=01: out buff= RZQ/7 # mww 0x63fd901c 0x09208138 ; #write mode reg MR0 with cs1. # mww 0x63fd901c 0x04008048 ; #ZQ calibration with cs1(A10 high indicates ZQ cal long ZQCL) #********************************** mww 0x63fd9020 0x00001800 ; # Refresh control register mww 0x63fd9040 0x04b80003 ; # ZQ HW control mww 0x63fd9058 0x00022227 ; # ODT control register mww 0x63fd901c 0x00000000 # CLKO muxing (comment out for now till needed to avoid conflicts with intended usage of signals) # mww 0x53FA8314 = 0 # mww 0x53FA8320 0x4 # mww 0x53FD4060 0x01e900f0 # dap apsel 0 } # IRAM $_TARGETNAME configure -work-area-phys 0xF8000000 -work-area-size 0x20000 -work-area-backup 1 flash bank mx535_nor cfi 0xf0000000 0x800000 2 2 $_TARGETNAME # vim:filetype=tcl ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/icnova_sam9g45_sodimm.cfg ================================================ ################################################################################################# # # # Author: Lars Poeschel (larsi@wh2.tu-dresden.de) # # Generated for In-Circuit ICnova SAM9G45 SODIMM # # http://www.ic-board.de/product_info.php?info=p214_ICnova-SAM9G45-SODIMM.html|ICnova # # # ################################################################################################# # FIXME use some standard target config, maybe create one from this # # source [find target/...cfg] source [find target/at91sam9g45.cfg] # Set reset type. # reset_config trst_and_srst # adapter srst delay 200 # jtag_ntrst_delay 200 # If you don't want to execute built-in boot rom code (and there are good reasons at times not to do that) in the # AT91SAM9 family, the microcontroller is a lump on a log without initialization. Because this family has # some powerful features, we want to have a special function that handles "reset init". To do this we declare # an event handler where these special activities can take place. scan_chain $_TARGETNAME configure -event reset-init {at91sam9g45_init} # Set fallback clock to 1/6 of worst-case clock speed (which would be the 32.768 kHz slow clock). # Slow-speed oscillator enabled at reset, so run jtag speed slow. $_TARGETNAME configure -event reset-start {at91sam9g45_start} # NandFlash configuration and definition # Future TBD # Flash configuration # flash bank cfi set _FLASHNAME $_CHIPNAME.flash # set _NANDNAME $_CHIPNAME.nand flash bank $_FLASHNAME cfi 0x10000000 0x00800000 2 2 $_TARGETNAME # nand device $_NANDNAME at91sam9 $_TARGETNAME 0x40000000 0xFFFFE800 proc read_register {register} { return [read_memory $register 32 1] } proc at91sam9g45_start { } { # Make sure that the the jtag is running slow, since there are a number of different ways the board # can be configured coming into this state that can cause communication problems with the jtag # adapter. Also since this call can be made following a "reset init" where fast memory accesses # are enabled, need to temporarily shut this down so that the RSTC_MR register can be written at slower # jtag speed without causing GDB keep alive problem. arm7_9 fast_memory_access disable # Slow-speed oscillator enabled at reset, so run jtag speed slow. adapter speed 4 # Make sure processor is halted, or error will result in following steps. halt wait_halt 10000 # RSTC_MR : enable user reset. mww 0xfffffd08 0xa5000501 } proc at91sam9g45_init { } { # At reset AT91SAM9G45 chip runs on slow clock (32.768 kHz). To shift over to a normal clock requires # a number of steps that must be carefully performed. The process outline below follows the # recommended procedure outlined in the AT91SAM9G45 technical manual. # # Several key and very important things to keep in mind: # The SDRAM parts used currently on the board are -75 grade parts. This # means the master clock (MCLK) must be at or below 133 MHz or timing errors will occur. The processor # core can operate up to 400 MHz and therefore PCLK must be at or below this to function properly. # Make sure processor is halted, or error will result in following steps. halt # RSTC_MR : enable user reset. mww 0xfffffd08 0xa5000501 # WDT_MR : disable watchdog. mww 0xfffffd44 0x00008000 # Enable the main 15.000 MHz oscillator in CKGR_MOR register. # Wait for MOSCS in PMC_SR to assert indicating oscillator is again stable after change to CKGR_MOR. mww 0xfffffc20 0x00004001 while { [expr {[read_register 0xfffffc68] & 0x01}] != 1 } { sleep 1 } # Set PLLA Register for 792.576 MHz (divider: bypass, multiplier: 43). # Wait for LOCKA signal in PMC_SR to assert indicating PLLA is stable. #mww 0xfffffc28 0x202a3f01 mww 0xfffffc28 0x20c73f03 while { [expr {[read_register 0xfffffc68] & 0x02}] != 2 } { sleep 1 } # Set master system clock prescaler divide by 6 and processor clock divide by 2 in PMC_MCKR. # Wait for MCKRDY signal from PMC_SR to assert. #mww 0xfffffc30 0x00000101 mww 0xfffffc30 0x00001301 while { [expr {[read_register 0xfffffc68] & 0x08}] != 8 } { sleep 1 } # Now change PMC_MCKR register to select PLLA. # Wait for MCKRDY signal from PMC_SR to assert. mww 0xfffffc30 0x00001302 while { [expr {[read_register 0xfffffc68] & 0x08}] != 8 } { sleep 1 } # Processor and master clocks are now operating and stable at maximum frequency possible: # -> MCLK = 132.096 MHz # -> PCLK = 396.288 MHz # Switch over to adaptive clocking. adapter speed 6000 # Enable faster DCC downloads. arm7_9 dcc_downloads enable # To be able to use external SDRAM, several peripheral configuration registers must # be modified. The first change is made to PIO_ASR to select peripheral functions # for D15 through D31. The second change is made to the PIO_PDR register to disable # this for D15 through D31. # mww 0xfffff870 0xffff0000 # mww 0xfffff804 0xffff0000 # The EBI chip select register EBI_CS must be specifically configured to enable the internal SDRAM controller # using CS1. Additionally we want CS3 assigned to NandFlash. Also VDDIO is connected physically on # the board to the 3.3 VDC power supply so set the appropriate register bit to notify the micrcontroller. # mww 0xffffef1c 0x000100a # The ICnova SAM9G45 SODIMM has built-in NandFlash. The exact physical timing characteristics # for the memory type used on the current board (MT29F2G08AACWP) can be established by setting # four registers in order: SMC_SETUP3, SMC_PULSE3, SMC_CYCLE3, and SMC_MODE3. # mww 0xffffec30 0x00020002 # mww 0xffffec34 0x04040404 # mww 0xffffec38 0x00070007 # mww 0xffffec3c 0x00030003 # Identify NandFlash bank 0. Disabled at the moment because a memory driver is not yet complete. # nand probe 0 # SMC_SETUP0 : Setup SMC for NOR Flash mww 0xffffe800 0x0012000a # SMC_PULSE0 mww 0xffffe804 0x3b38343b # SMC_CYCLE0 mww 0xffffe808 0x003f003f # SMC_MODE0 mww 0xffffe80c 0x00001000 # Identify flash bank 0 flash probe 0 # Now setup SDRAM. This is tricky and configuration is very important for reliability! The current calculations # are based on 2 x Samsung K4T51083QG memory. # 0. Enable DDR2 Clock mww 0xfffffc00 0x4 # 1. Program memory device type # 1.1 configure the DDR controller mww 0xffffe620 0x16 # 1.2 program the DDR controller mww 0xffffe608 0x3d # 2. program memory device features # 2.1 assume timings for 7.5ns min clock period mww 0xffffe60c 0x21128226 # 2.2 pSDDRC->HDDRSDRC2_T1PR mww 0xffffe610 0x02c8100e # 2.3 pSDDRC->HDDRSDRC2_T2PR mww 0xffffe614 0x01000702 # 3. NOP mww 0xffffe600 0x1 mww 0x70000000 0x1 # 3.1 delay 200us sleep 1 # jim tcl alternative: after ms # after 0.2 # 4. NOP mww 0xffffe600 0x1 mww 0x70000000 0x1 # 4.1 delay 400ns # 5. set all bank precharge mww 0xffffe600 0x2 mww 0x70000000 0x1 # 5.1 delay 400ns # 6. set EMR operation (EMRS2) mww 0xffffe600 0x5 mww 0x74000000 0x1 # 6.1 delay 2 cycles # 7. set EMR operation (EMRS3) mww 0xffffe600 0x5 mww 0x76000000 0x1 # 7.1 delay 2 cycles # 8. set EMR operation (EMRS1) mww 0xffffe600 0x5 mww 0x72000000 0x1 # 8.1 delay 200 cycles (400Mhz -> 5 * 10^-7s) sleep 1 # 9. Enable DLL Reset (set DLL bit) set CR [expr {[read_register 0xffffe608] | 0x80}] mww 0xffffe608 $CR # 10. mode register cycle to reset the DLL mww 0xffffe600 0x5 mww 0x70000000 0x1 # 10.1 delay 2 cycles # 11. set all bank precharge mww 0xffffe600 0x2 mww 0x70000000 0x1 # 11.1 delay 400 ns # 12. two auto-refresh (CBR) cycles are provided. mww 0xffffe600 0x4 mww 0x70000000 0x1 # 12.1 delay 10 cycles # 12.2 2nd cycle (schreiben des Mode Register sparen wir uns) mww 0x70000000 0x1 # 12.3 delay 10 cycles # 13. disable DLL reset (clear DLL bit) set CR [expr {[read_register 0xffffe608] & 0xffffff7f}] mww 0xffffe608 $CR # 14. mode register set cycle mww 0xffffe600 0x3 mww 0x70000000 0x1 # 15. program OCD field (set OCD bits) set CR [expr {[read_register 0xffffe608] | 0x7000}] mww 0xffffe608 $CR # 16. (EMRS1) mww 0xffffe600 0x5 mww 0x72000000 0x1 # 16.1 delay 2 cycles # 17. disable OCD field (clear OCD bits) set CR [expr {[read_register 0xffffe608] & 0xffff8fff}] mww 0xffffe608 $CR # 18. (EMRS1) mww 0xffffe600 0x5 mww 0x76000000 0x1 # 18.1 delay 2 cycles # 19. normal mode command mww 0xffffe600 0x0 mww 0x70000000 0x1 # 20. perform write to any address #mww 0x70000000 0x1 # 21. write refresh rate into the count field of the refresh rate register mww 0xffffe604 0x24b # 21.1 delay (500 * 6 cycles) arm7_9 fast_memory_access enable } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/imx27ads.cfg ================================================ # The IMX27 ADS eval board has a single IMX27 chip # Note: tested on IMX27ADS Board REV-2.6 and REV-2.8 source [find target/imx27.cfg] $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { imx27ads_init } # The IMX27 ADS board has a NOR flash on CS0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0xc0000000 0x00200000 2 2 $_TARGETNAME proc imx27ads_init { } { # This setup puts RAM at 0xA0000000 # reset the board correctly reset run reset halt mww 0x10000000 0x20040304 mww 0x10020000 0x00000000 mww 0x10000004 0xDFFBFCFB mww 0x10020004 0xFFFFFFFF sleep 100 # ======================================== # Configure DDR on CSD0 -- initial reset # ======================================== mww 0xD8001010 0x00000008 # ======================================== # Configure PSRAM on CS5 # ======================================== mww 0xd8002050 0x0000dcf6 mww 0xd8002054 0x444a4541 mww 0xd8002058 0x44443302 # ======================================== # Configure16 bit NorFlash on CS0 # ======================================== mww 0xd8002000 0x0000CC03 mww 0xd8002004 0xa0330D01 mww 0xd8002008 0x00220800 # ======================================== # Configure CPLD on CS4 # ======================================== mww 0xd8002040 0x0000DCF6 mww 0xd8002044 0x444A4541 mww 0xd8002048 0x44443302 # ======================================== # Configure DDR on CSD0 -- wait 5000 cycle # ======================================== mww 0x10027828 0x55555555 mww 0x10027830 0x55555555 mww 0x10027834 0x55555555 mww 0x10027838 0x00005005 mww 0x1002783C 0x15555555 mww 0xD8001010 0x00000004 mww 0xD8001004 0x00795729 mww 0xD8001000 0x92200000 mww 0xA0000F00 0x0 mww 0xD8001000 0xA2200000 mww 0xA0000F00 0x0 mww 0xA0000F00 0x0 mww 0xD8001000 0xB2200000 mwb 0xA0000033 0xFF mwb 0xA1000000 0xAA mww 0xD8001000 0x82228085 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/imx27lnst.cfg ================================================ # The Linuxstamp-mx27 is board has a single IMX27 chip # For further info see http://opencircuits.com/Linuxstamp_mx27#OpenOCD source [find target/imx27.cfg] $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { imx27lnst_init } proc imx27lnst_init { } { # This setup puts RAM at 0xA0000000 # reset the board correctly adapter speed 500 reset run reset halt mww 0x10000000 0x20040304 mww 0x10020000 0x00000000 mww 0x10000004 0xDFFBFCFB mww 0x10020004 0xFFFFFFFF sleep 100 # ======================================== # Configure DDR on CSD0 -- initial reset # ======================================== mww 0xD8001010 0x00000008 sleep 100 # ======================================== # Configure DDR on CSD0 -- wait 5000 cycle # ======================================== mww 0x10027828 0x55555555 mww 0x10027830 0x55555555 mww 0x10027834 0x55555555 mww 0x10027838 0x00005005 mww 0x1002783C 0x15555555 mww 0xD8001010 0x00000004 mww 0xD8001004 0x00795729 #mww 0xD8001000 0x92200000 mww 0xD8001000 0x91120000 mww 0xA0000F00 0x0 #mww 0xD8001000 0xA2200000 mww 0xD8001000 0xA1120000 mww 0xA0000F00 0x0 mww 0xA0000F00 0x0 #mww 0xD8001000 0xB2200000 mww 0xD8001000 0xB1120000 mwb 0xA0000033 0xFF mwb 0xA1000000 0xAA #mww 0xD8001000 0x82228085 mww 0xD8001000 0x81128080 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/imx28evk.cfg ================================================ # The IMX28EVK eval board has a IMX28 chip # Tested on SCH-26241 Rev D board with Olimex ARM-USB-OCD # Date: 201-02-01 # Authors: James Robinson & Fabio Estevam source [find target/imx28.cfg] $_TARGETNAME configure -event gdb-attach { imx28evk_init } $_TARGETNAME configure -event reset-init { imx28evk_init } proc imx28evk_init { } { halt #**************************** # VDDD setting #**************************** # set VDDD =1.55V =(0.8v + TRIG x 0.025v), TRIG=0x1e mww 0x80044010 0x0003F503 mww 0x80044040 0x0002041E #**************************** # CLOCK set up #**************************** # Power up PLL0 HW_CLKCTRL_PLL0CTRL0 mww 0x80040000 0x00020000 # Set up fractional dividers for CPU and EMI - HW_CLKCTRL_FRAC0 # EMI - first set DIV_EMI to div-by-2 before programming frac divider mww 0x800400F0 0x80000002 # CPU: CPUFRAC=19 480*18/29=454.7MHz, EMI: EMIFRAC=22, (480/2)*18/22=196.4MHz mww 0x800401B0 0x92921613 # Clear the bypass bits for CPU and EMI clocks in HW_CLKCTRL_CLKSEQ_CLR mww 0x800401D8 0x00040080 # HCLK = 227MHz,HW_CLKCTRL_HBUS DIV =0x2 mww 0x80040060 0x00000002 #**************************** # POWER up DCDD_VDDA (DDR2) #**************************** # Now set the voltage level to 1.8V HW_POWER_VDDACTRL bits TRC=0xC mww 0x80044050 0x0000270C #**************************** # DDR2 DCDD_VDDA #**************************** # First set up pin muxing and drive strength # Ungate module clock and bring out of reset HW_PINCTRL_CTRL_CLR mww 0x80018008 0xC0000000 #**************************** # EMI PAD setting #**************************** # Set up drive strength for EMI pins mww 0x80019B80 0x00030000 #IOMUXC_SW_PAD_CTL_GRP_CTLDS # Set up pin muxing for EMI, HW_PINCTRL_MUXSEL10, 11, 12, 13 mww 0x800181A8 0xFFFFFFFF mww 0x800181B8 0xFFFFFFFF mww 0x800181C8 0xFFFFFFFF mww 0x800181D8 0xFFFFFFFF #** Ungate EMI clock in CCM mww 0x800400F0 0x00000002 #============================================================================ # DDR Controller Registers #============================================================================ # Manufacturer: Elpida # Device Part Number: EDE1116AEBG # Clock Freq.: 200MHz # Density: 1Gb # Chip Selects: 1 # Number of Banks: 8 # Row address: 13 # Column address: 10 #============================================================================ mww 0x800E0000 0x00000000 mww 0x800E0040 0x00000000 mww 0x800E0054 0x00000000 mww 0x800E0058 0x00000000 mww 0x800E005C 0x00000000 mww 0x800E0060 0x00000000 mww 0x800E0064 0x00000000 mww 0x800E0068 0x00010101 mww 0x800E006C 0x01010101 mww 0x800E0070 0x000f0f01 mww 0x800E0074 0x0102020A mww 0x800E007C 0x00010101 mww 0x800E0080 0x00000100 mww 0x800E0084 0x00000100 mww 0x800E0088 0x00000000 mww 0x800E008C 0x00000002 mww 0x800E0090 0x01010000 mww 0x800E0094 0x07080403 mww 0x800E0098 0x06005003 mww 0x800E009C 0x0A0000C8 mww 0x800E00A0 0x02009C40 mww 0x800E00A4 0x0002030C mww 0x800E00A8 0x0036B009 mww 0x800E00AC 0x031A0612 mww 0x800E00B0 0x02030202 mww 0x800E00B4 0x00C8001C mww 0x800E00C0 0x00011900 mww 0x800E00C4 0xffff0303 mww 0x800E00C8 0x00012100 mww 0x800E00CC 0xffff0303 mww 0x800E00D0 0x00012100 mww 0x800E00D4 0xffff0303 mww 0x800E00D8 0x00012100 mww 0x800E00DC 0xffff0303 mww 0x800E00E0 0x00000003 mww 0x800E00E8 0x00000000 mww 0x800E0108 0x00000612 mww 0x800E010C 0x01000f02 mww 0x800E0114 0x00000200 mww 0x800E0118 0x00020007 mww 0x800E011C 0xf4004a27 mww 0x800E0120 0xf4004a27 mww 0x800E012C 0x07400300 mww 0x800E0130 0x07400300 mww 0x800E013C 0x00000005 mww 0x800E0140 0x00000000 mww 0x800E0144 0x00000000 mww 0x800E0148 0x01000000 mww 0x800E014C 0x01020408 mww 0x800E0150 0x08040201 mww 0x800E0154 0x000f1133 mww 0x800E015C 0x00001f04 mww 0x800E0160 0x00001f04 mww 0x800E016C 0x00001f04 mww 0x800E0170 0x00001f04 mww 0x800E0288 0x00010000 mww 0x800E028C 0x00030404 mww 0x800E0290 0x00000003 mww 0x800E02AC 0x01010000 mww 0x800E02B0 0x01000000 mww 0x800E02B4 0x03030000 mww 0x800E02B8 0x00010303 mww 0x800E02BC 0x01020202 mww 0x800E02C0 0x00000000 mww 0x800E02C4 0x02030303 mww 0x800E02C8 0x21002103 mww 0x800E02CC 0x00061200 mww 0x800E02D0 0x06120612 mww 0x800E02D4 0x04420442 # Mode register 0 for CS1 and CS0, ok to program CS1 even if not used mww 0x800E02D8 0x00000000 # Mode register 0 for CS2 and CS3, not supported in this processor mww 0x800E02DC 0x00040004 # Mode register 1 for CS1 and CS0, ok to program CS1 even if not used mww 0x800E02E0 0x00000000 # Mode register 1 for CS2 and CS3, not supported in this processor mww 0x800E02E4 0x00000000 # Mode register 2 for CS1 and CS0, ok to program CS1 even if not used mww 0x800E02E8 0x00000000 # Mode register 2 for CS2 and CS3, not supported in this processor mww 0x800E02EC 0x00000000 # Mode register 3 for CS1 and CS0, ok to program CS1 even if not used mww 0x800E02F0 0x00000000 # Mode register 3 for CS2 and CS3, not supported in this processor mww 0x800E02F4 0xffffffff #** start controller **# mww 0x800E0040 0x00000001 # bit[0]: start } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/imx31pdk.cfg ================================================ # The IMX31PDK eval board has a single IMX31 chip source [find target/imx31.cfg] source [find target/imx.cfg] $_TARGETNAME configure -event reset-init { imx31pdk_init } proc self_test {} { echo "Running 100 iterations of test." dump_image /ram/test 0x80000000 0x40000 for {set i 0} {$i < 100} {set i [expr {$i+1}]} { echo "Iteration $i" reset init mww 0x80000000 0x12345678 0x10000 load_image /ram/test 0x80000000 bin verify_image /ram/test 0x80000000 bin } } # Slow fallback frequency # measure_clk indicates ca. 3-4MHz. jtag_rclk 1000 proc imx31pdk_init { } { imx3x_reset # This setup puts RAM at 0x80000000 mww 0x53FC0000 0x040 mww 0x53F80000 0x074B0B7D # 399MHz - 26MHz input, PD=1,MFI=7, MFN=27, MFD=40 #mww 0x53F80004 0xFF871D50 #mww 0x53F80010 0x00271C1B # Start 16 bit NorFlash Initialization on CS0 mww 0xb8002000 0x0000CC03 mww 0xb8002004 0xa0330D01 mww 0xb8002008 0x00220800 # Configure CPLD on CS4 mww 0xb8002040 0x0000DCF6 mww 0xb8002044 0x444A4541 mww 0xb8002048 0x44443302 # SDCLK mww 0x43FAC26C 0 # CAS mww 0x43FAC270 0 # RAS mww 0x43FAC274 0 # CS2 (CSD0) mww 0x43FAC27C 0x1000 # DQM3 mww 0x43FAC284 0 # DQM2, DQM1, DQM0, SD31-SD0, A25-A0, MA10 (0x288..0x2DC) mww 0x43FAC288 0 mww 0x43FAC28C 0 mww 0x43FAC290 0 mww 0x43FAC294 0 mww 0x43FAC298 0 mww 0x43FAC29C 0 mww 0x43FAC2A0 0 mww 0x43FAC2A4 0 mww 0x43FAC2A8 0 mww 0x43FAC2AC 0 mww 0x43FAC2B0 0 mww 0x43FAC2B4 0 mww 0x43FAC2B8 0 mww 0x43FAC2BC 0 mww 0x43FAC2C0 0 mww 0x43FAC2C4 0 mww 0x43FAC2C8 0 mww 0x43FAC2CC 0 mww 0x43FAC2D0 0 mww 0x43FAC2D4 0 mww 0x43FAC2D8 0 mww 0x43FAC2DC 0 # Initialization script for 32 bit DDR on MX31 ADS mww 0xB8001010 0x00000004 mww 0xB8001004 0x006ac73a mww 0xB8001000 0x92100000 mww 0x80000f00 0x12344321 mww 0xB8001000 0xa2100000 mww 0x80000000 0x12344321 mww 0x80000000 0x12344321 mww 0xB8001000 0xb2100000 mwb 0x80000033 0xda mwb 0x81000000 0xff mww 0xB8001000 0x82226080 mww 0x80000000 0xDEADBEEF mww 0xB8001010 0x0000000c } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/imx35pdk.cfg ================================================ # The IMX35PDK eval board has a single IMX35 chip source [find target/imx35.cfg] source [find target/imx.cfg] $_TARGETNAME configure -event reset-init { imx35pdk_init } # Stick to *really* low clock rate or reset will fail # without RTCK / RCLK jtag_rclk 10 proc imx35pdk_init { } { imx3x_reset mww 0x43f00040 0x00000000 mww 0x43f00044 0x00000000 mww 0x43f00048 0x00000000 mww 0x43f0004C 0x00000000 mww 0x43f00050 0x00000000 mww 0x43f00000 0x77777777 mww 0x43f00004 0x77777777 mww 0x53f00040 0x00000000 mww 0x53f00044 0x00000000 mww 0x53f00048 0x00000000 mww 0x53f0004C 0x00000000 mww 0x53f00050 0x00000000 mww 0x53f00000 0x77777777 mww 0x53f00004 0x77777777 # clock setup mww 0x53F80004 0x00821000 ;# first need to set IPU_HND_BYP mww 0x53F80004 0x00821000 ;#arm clock is 399Mhz and ahb clock is 133Mhz. #================================================= # WEIM config #================================================= # CS0U mww 0xB8002000 0x0000CC03 # CS0L mww 0xB8002004 0xA0330D01 # CS0A mww 0xB8002008 0x00220800 # CS5U mww 0xB8002050 0x0000dcf6 # CS5L mww 0xB8002054 0x444a4541 # CS5A mww 0xB8002058 0x44443302 # IO SW PAD Control registers - setting of 0x0002 is high drive, mDDR mww 0x43FAC368 0x00000006 mww 0x43FAC36C 0x00000006 mww 0x43FAC370 0x00000006 mww 0x43FAC374 0x00000006 mww 0x43FAC378 0x00000006 mww 0x43FAC37C 0x00000006 mww 0x43FAC380 0x00000006 mww 0x43FAC384 0x00000006 mww 0x43FAC388 0x00000006 mww 0x43FAC38C 0x00000006 mww 0x43FAC390 0x00000006 mww 0x43FAC394 0x00000006 mww 0x43FAC398 0x00000006 mww 0x43FAC39C 0x00000006 mww 0x43FAC3A0 0x00000006 mww 0x43FAC3A4 0x00000006 mww 0x43FAC3A8 0x00000006 mww 0x43FAC3AC 0x00000006 mww 0x43FAC3B0 0x00000006 mww 0x43FAC3B4 0x00000006 mww 0x43FAC3B8 0x00000006 mww 0x43FAC3BC 0x00000006 mww 0x43FAC3C0 0x00000006 mww 0x43FAC3C4 0x00000006 mww 0x43FAC3C8 0x00000006 mww 0x43FAC3CC 0x00000006 mww 0x43FAC3D0 0x00000006 mww 0x43FAC3D4 0x00000006 mww 0x43FAC3D8 0x00000006 # DDR data bus SD 0 through 31 mww 0x43FAC3DC 0x00000082 mww 0x43FAC3E0 0x00000082 mww 0x43FAC3E4 0x00000082 mww 0x43FAC3E8 0x00000082 mww 0x43FAC3EC 0x00000082 mww 0x43FAC3F0 0x00000082 mww 0x43FAC3F4 0x00000082 mww 0x43FAC3F8 0x00000082 mww 0x43FAC3FC 0x00000082 mww 0x43FAC400 0x00000082 mww 0x43FAC404 0x00000082 mww 0x43FAC408 0x00000082 mww 0x43FAC40C 0x00000082 mww 0x43FAC410 0x00000082 mww 0x43FAC414 0x00000082 mww 0x43FAC418 0x00000082 mww 0x43FAC41c 0x00000082 mww 0x43FAC420 0x00000082 mww 0x43FAC424 0x00000082 mww 0x43FAC428 0x00000082 mww 0x43FAC42c 0x00000082 mww 0x43FAC430 0x00000082 mww 0x43FAC434 0x00000082 mww 0x43FAC438 0x00000082 mww 0x43FAC43c 0x00000082 mww 0x43FAC440 0x00000082 mww 0x43FAC444 0x00000082 mww 0x43FAC448 0x00000082 mww 0x43FAC44c 0x00000082 mww 0x43FAC450 0x00000082 mww 0x43FAC454 0x00000082 mww 0x43FAC458 0x00000082 # DQM setup mww 0x43FAC45c 0x00000082 mww 0x43FAC460 0x00000082 mww 0x43FAC464 0x00000082 mww 0x43FAC468 0x00000082 mww 0x43FAC46c 0x00000006 mww 0x43FAC470 0x00000006 mww 0x43FAC474 0x00000006 mww 0x43FAC478 0x00000006 mww 0x43FAC47c 0x00000006 mww 0x43FAC480 0x00000006 ;# CSD0 mww 0x43FAC484 0x00000006 ;# CSD1 mww 0x43FAC488 0x00000006 mww 0x43FAC48c 0x00000006 mww 0x43FAC490 0x00000006 mww 0x43FAC494 0x00000006 mww 0x43FAC498 0x00000006 mww 0x43FAC49c 0x00000006 mww 0x43FAC4A0 0x00000006 mww 0x43FAC4A4 0x00000006 ;# RAS mww 0x43FAC4A8 0x00000006 ;# CAS mww 0x43FAC4Ac 0x00000006 ;# SDWE mww 0x43FAC4B0 0x00000006 ;# SDCKE0 mww 0x43FAC4B4 0x00000006 ;# SDCKE1 mww 0x43FAC4B8 0x00000002 ;# SDCLK # SDQS0 through SDQS3 mww 0x43FAC4Bc 0x00000082 mww 0x43FAC4C0 0x00000082 mww 0x43FAC4C4 0x00000082 mww 0x43FAC4C8 0x00000082 # *================================================== # Initialization script for 32 bit DDR2 on RINGO 3DS # *================================================== #-------------------------------------------- # Init CCM #-------------------------------------------- mww 0x53F80028 0x7D000028 #-------------------------------------------- # Init IOMUX for JTAG #-------------------------------------------- mww 0x43FAC5EC 0x000000C3 mww 0x43FAC5F0 0x000000C3 mww 0x43FAC5F4 0x000000F3 mww 0x43FAC5F8 0x000000F3 mww 0x43FAC5FC 0x000000F3 mww 0x43FAC600 0x000000F3 mww 0x43FAC604 0x000000F3 # ESD_MISC : enable DDR2 mww 0xB8001010 0x00000304 #-------------------------------------------- # Init 32-bit DDR2 memory on CSD0 # COL=10-bit, ROW=13-bit, BA[1:0]=Addr[26:25] #-------------------------------------------- # ESD_ESDCFG0 : set timing parameters mww 0xB8001004 0x007ffC2f # ESD_ESDCTL0 : select Prechare-All mode mww 0xB8001000 0x92220000 # DDR2 : Prechare-All mww 0x80000400 0x12345678 # ESD_ESDCTL0 : select Load-Mode-Register mode mww 0xB8001000 0xB2220000 # DDR2 : Load reg EMR2 mwb 0x84000000 0xda # DDR2 : Load reg EMR3 mwb 0x86000000 0xda # DDR2 : Load reg EMR1 -- enable DLL mwb 0x82000400 0xda # DDR2 : Load reg MR -- reset DLL mwb 0x80000333 0xda # ESD_ESDCTL0 : select Prechare-All mode mww 0xB8001000 0x92220000 # DDR2 : Prechare-All mwb 0x80000400 0x12345678 # ESD_ESDCTL0 : select Manual-Refresh mode mww 0xB8001000 0xA2220000 # DDR2 : Manual-Refresh 2 times mww 0x80000000 0x87654321 mww 0x80000000 0x87654321 # ESD_ESDCTL0 : select Load-Mode-Register mode mww 0xB8001000 0xB2220000 # DDR2 : Load reg MR -- CL=3, BL=8, end DLL reset mwb 0x80000233 0xda # DDR2 : Load reg EMR1 -- OCD default mwb 0x82000780 0xda # DDR2 : Load reg EMR1 -- OCD exit mwb 0x82000400 0xda ;# ODT disabled # ESD_ESDCTL0 : select normal-operation mode # DSIZ=32-bit, BL=8, COL=10-bit, ROW=13-bit # disable PWT & PRCT # disable Auto-Refresh mww 0xB8001000 0x82220080 ## ESD_ESDCTL0 : enable Auto-Refresh mww 0xB8001000 0x82228080 ## ESD_ESDCTL1 : enable Auto-Refresh mww 0xB8001008 0x00002000 #*********************************************** # Adjust the ESDCDLY5 register #*********************************************** # Vary DQS_ABS_OFFSET5 for writes mww 0xB8001020 0x00F48000 ;# this is the default value mww 0xB8001024 0x00F48000 ;# this is the default value mww 0xB8001028 0x00F48000 ;# this is the default value mww 0xB800102c 0x00F48000 ;# this is the default value #Then you can make force measure with the dedicated bit (Bit 7 at ESDMISC) mww 0xB8001010 0x00000384 # wait a while sleep 1000 # now clear the force measurement bit mww 0xB8001010 0x00000304 # dummy write to DDR memory to set DQS low mww 0x80000000 0x00000000 mww 0x30000100 0x0 mww 0x30000104 0x31024 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/imx53-m53evk.cfg ================================================ ####################################### # DENX M53EVK # # http://www.denx-cs.de/?q=M53EVK # # Author: Marek Vasut # # Based on imx53loco.cfg # ####################################### # The DENX M53EVK has on-board JTAG adapter source [find interface/ftdi/m53evk.cfg] # The DENX M53EVK board has a single i.MX53 chip source [find target/imx53.cfg] # Helper for common memory read/modify/write procedures source [find mem_helper.tcl] echo "iMX53 M53EVK board lodaded." # Set reset type reset_config trst_and_srst separate trst_open_drain srst_open_drain # Run at 6 MHz adapter speed 6000 $_TARGETNAME configure -event "reset-assert" { echo "Resetting ...." #cortex_a dbginit } $_TARGETNAME configure -event reset-init { m53evk_init } global AIPS1_BASE_ADDR set AIPS1_BASE_ADDR 0x53F00000 global AIPS2_BASE_ADDR set AIPS2_BASE_ADDR 0x63F00000 proc m53evk_init { } { echo "Reset-init..." ; # halt the CPU halt echo "HW version [format %x [mrw 0x48]]" dap apsel 1 DCD ; # ARM errata ID #468414 set tR [arm mrc 15 0 1 0 1] arm mcr 15 0 1 0 1 [expr {$tR | (1<<5)}] ; # enable L1NEON bit init_l2cc init_aips init_clock dap apsel 0 ; # Force ARM state ; #reg cpsr 0x000001D3 arm core_state arm } # L2CC Cache setup/invalidation/disable proc init_l2cc { } { ; #/* explicitly disable L2 cache */ ; #mrc 15, 0, r0, c1, c0, 1 set tR [arm mrc 15 0 1 0 1] ; #bic r0, r0, #0x2 ; #mcr 15, 0, r0, c1, c0, 1 arm mcr 15 0 1 0 1 [expr {$tR & ~(1 << 2)}] ; #/* reconfigure L2 cache aux control reg */ ; #mov r0, #0xC0 /* tag RAM */ ; #add r0, r0, #0x4 /* data RAM */ ; #orr r0, r0, #(1 << 24) /* disable write allocate delay */ ; #orr r0, r0, #(1 << 23) /* disable write allocate combine */ ; #orr r0, r0, #(1 << 22) /* disable write allocate */ ; #mcr 15, 1, r0, c9, c0, 2 arm mcr 15 1 9 0 2 [expr {0xC4 | (1<<24) | (1<<23) | (1<<22)}] } # AIPS setup - Only setup MPROTx registers. # The PACR default values are good. proc init_aips { } { ; # Set all MPROTx to be non-bufferable, trusted for R/W, ; # not forced to user-mode. global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR set VAL 0x77777777 # dap apsel 1 mww [expr {$AIPS1_BASE_ADDR + 0x0}] $VAL mww [expr {$AIPS1_BASE_ADDR + 0x4}] $VAL mww [expr {$AIPS2_BASE_ADDR + 0x0}] $VAL mww [expr {$AIPS2_BASE_ADDR + 0x4}] $VAL # dap apsel 0 } proc init_clock { } { global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR set CCM_BASE_ADDR [expr {$AIPS1_BASE_ADDR + 0x000D4000}] set CLKCTL_CCSR 0x0C set CLKCTL_CBCDR 0x14 set CLKCTL_CBCMR 0x18 set PLL1_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00080000}] set PLL2_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00084000}] set PLL3_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00088000}] set PLL4_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x0008C000}] set CLKCTL_CSCMR1 0x1C set CLKCTL_CDHIPR 0x48 set PLATFORM_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x000A0000}] set CLKCTL_CSCDR1 0x24 set CLKCTL_CCDR 0x04 ; # Switch ARM to step clock mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x4 return echo "not returned" setup_pll $PLL1_BASE_ADDR 800 setup_pll $PLL3_BASE_ADDR 400 ; # Switch peripheral to PLL3 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00015154 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x02888945 | (1<<16)}] while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL2_BASE_ADDR 400 ; # Switch peripheral to PLL2 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x00808145 | (2<<10) | (9<<16) | (1<<19)}] mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00016154 ; # change uart clk parent to pll2 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}]] & 0xfcffffff | 0x01000000}] ; # make sure change is effective while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL3_BASE_ADDR 216 setup_pll $PLL4_BASE_ADDR 455 ; # Set the platform clock dividers mww [expr {$PLATFORM_BASE_ADDR + 0x14}] 0x00000124 mww [expr {$CCM_BASE_ADDR + 0x10}] 0 ; # Switch ARM back to PLL 1. mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x0 ; # make uart div=6 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}]] & 0xffffffc0 | 0x0a}] ; # Restore the default values in the Gate registers mww [expr {$CCM_BASE_ADDR + 0x68}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x6C}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x70}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x74}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x78}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x7C}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x80}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x84}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCDR}] 0x00000 ; # for cko - for ARM div by 8 mww [expr {$CCM_BASE_ADDR + 0x60}] [expr {0x000A0000 & 0x00000F0}] } proc setup_pll { PLL_ADDR CLK } { set PLL_DP_CTL 0x00 set PLL_DP_CONFIG 0x04 set PLL_DP_OP 0x08 set PLL_DP_HFS_OP 0x1C set PLL_DP_MFD 0x0C set PLL_DP_HFS_MFD 0x20 set PLL_DP_MFN 0x10 set PLL_DP_HFS_MFN 0x24 if {$CLK == 1000} { set DP_OP [expr {(10 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {12 - 1}] set DP_MFN 5 } elseif {$CLK == 850} { set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {48 - 1}] set DP_MFN 41 } elseif {$CLK == 800} { set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 700} { set DP_OP [expr {(7 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {24 - 1}] set DP_MFN 7 } elseif {$CLK == 600} { set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {4 - 1}] set DP_MFN 1 } elseif {$CLK == 665} { set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {96 - 1}] set DP_MFN 89 } elseif {$CLK == 532} { set DP_OP [expr {(5 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {24 - 1}] set DP_MFN 13 } elseif {$CLK == 455} { set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] set DP_MFD [expr {48 - 1}] set DP_MFN 71 } elseif {$CLK == 400} { set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 216} { set DP_OP [expr {(6 << 4) + ((3 - 1) << 0)}] set DP_MFD [expr {4 - 1}] set DP_MFN 3 } else { error "Error (setup_dll): clock not found!" } mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 mww [expr {$PLL_ADDR + $PLL_DP_CONFIG}] 0x2 mww [expr {$PLL_ADDR + $PLL_DP_OP}] $DP_OP mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_OP mww [expr {$PLL_ADDR + $PLL_DP_MFD}] $DP_MFD mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_MFD mww [expr {$PLL_ADDR + $PLL_DP_MFN}] $DP_MFN mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFN}] $DP_MFN mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 while {[expr {[mrw [expr {$PLL_ADDR + $PLL_DP_CTL}]] & 0x1}] == 0} { sleep 1 } } proc CPU_2_BE_32 { L } { return [expr {(($L & 0x000000FF) << 24) | (($L & 0x0000FF00) << 8) | (($L & 0x00FF0000) >> 8) | (($L & 0xFF000000) >> 24)}] } # Device Configuration Data proc DCD { } { # dap apsel 1 mww 0x53fa86f4 0x00000000 ;# GRP_DDRMODE_CTL mww 0x53fa8714 0x00000000 ;# GRP_DDRMODE mww 0x53fa86fc 0x00000000 ;# GRP_DDRPKE mww 0x53fa8724 0x04000000 ;# GRP_DDR_TYPE mww 0x53fa872c 0x00300000 ;# GRP_B3DS mww 0x53fa8554 0x00300000 ;# DRAM_DQM3 mww 0x53fa8558 0x00300040 ;# DRAM_SDQS3 mww 0x53fa8728 0x00300000 ;# GRP_B2DS mww 0x53fa8560 0x00300000 ;# DRAM_DQM2 mww 0x53fa8568 0x00300040 ;# DRAM_SDQS2 mww 0x53fa871c 0x00300000 ;# GRP_B1DS mww 0x53fa8594 0x00300000 ;# DRAM_DQM1 mww 0x53fa8590 0x00300040 ;# DRAM_SDQS1 mww 0x53fa8718 0x00300000 ;# GRP_B0DS mww 0x53fa8584 0x00300000 ;# DRAM_DQM0 mww 0x53fa857c 0x00300040 ;# DRAM_SDQS0 mww 0x53fa8578 0x00300000 ;# DRAM_SDCLK_0 mww 0x53fa8570 0x00300000 ;# DRAM_SDCLK_1 mww 0x53fa8574 0x00300000 ;# DRAM_CAS mww 0x53fa8588 0x00300000 ;# DRAM_RAS mww 0x53fa86f0 0x00300000 ;# GRP_ADDDS mww 0x53fa8720 0x00300000 ;# GRP_CTLDS mww 0x53fa8564 0x00300040 ;# DRAM_SDODT1 mww 0x53fa8580 0x00300040 ;# DRAM_SDODT0 # Initialize DDR2 memory mww 0x63fd9088 0x32383535 mww 0x63fd9090 0x40383538 mww 0x63fd907c 0x0136014d mww 0x63fd9080 0x01510141 mww 0x63fd9018 0x00011740 mww 0x63fd9000 0xc3190000 mww 0x63fd900c 0x555952e3 mww 0x63fd9010 0xb68e8b63 mww 0x63fd9014 0x01ff00db mww 0x63fd902c 0x000026d2 mww 0x63fd9030 0x009f0e21 mww 0x63fd9008 0x12273030 mww 0x63fd9004 0x0002002d mww 0x63fd901c 0x00008032 mww 0x63fd901c 0x00008033 mww 0x63fd901c 0x00028031 mww 0x63fd901c 0x092080b0 mww 0x63fd901c 0x04008040 mww 0x63fd901c 0x0000803a mww 0x63fd901c 0x0000803b mww 0x63fd901c 0x00028039 mww 0x63fd901c 0x09208138 mww 0x63fd901c 0x04008048 mww 0x63fd9020 0x00001800 mww 0x63fd9040 0x04b80003 mww 0x63fd9058 0x00022227 mww 0x63fd901c 0x00000000 # dap apsel 0 } # vim:filetype=tcl ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/imx53loco.cfg ================================================ ################################################################################## # Author: Wjatscheslaw Stoljarski (Slawa) # # Kiwigrid GmbH # ################################################################################## # The IMX53LOCO (QSB) board has a single IMX53 chip source [find target/imx53.cfg] # Helper for common memory read/modify/write procedures source [find mem_helper.tcl] echo "iMX53 Loco board lodaded." # Set reset type #reset_config srst_only adapter speed 3000 # Slow speed to be sure it will work jtag_rclk 1000 $_TARGETNAME configure -event "reset-start" { jtag_rclk 1000 } #adapter srst delay 200 #jtag_ntrst_delay 200 $_TARGETNAME configure -event "reset-assert" { echo "Resetting ...." #cortex_a dbginit } $_TARGETNAME configure -event reset-init { loco_init } global AIPS1_BASE_ADDR set AIPS1_BASE_ADDR 0x53F00000 global AIPS2_BASE_ADDR set AIPS2_BASE_ADDR 0x63F00000 proc loco_init { } { echo "Reset-init..." ; # halt the CPU halt echo "HW version [format %x [mrw 0x48]]" dap apsel 1 DCD ; # ARM errata ID #468414 set tR [arm mrc 15 0 1 0 1] arm mcr 15 0 1 0 1 [expr {$tR | (1<<5)}] ; # enable L1NEON bit init_l2cc init_aips init_clock dap apsel 0 ; # Force ARM state ; #reg cpsr 0x000001D3 arm core_state arm jtag_rclk 3000 # adapter speed 3000 } # L2CC Cache setup/invalidation/disable proc init_l2cc { } { ; #/* explicitly disable L2 cache */ ; #mrc 15, 0, r0, c1, c0, 1 set tR [arm mrc 15 0 1 0 1] ; #bic r0, r0, #0x2 ; #mcr 15, 0, r0, c1, c0, 1 arm mcr 15 0 1 0 1 [expr {$tR & ~(1 << 2)}] ; #/* reconfigure L2 cache aux control reg */ ; #mov r0, #0xC0 /* tag RAM */ ; #add r0, r0, #0x4 /* data RAM */ ; #orr r0, r0, #(1 << 24) /* disable write allocate delay */ ; #orr r0, r0, #(1 << 23) /* disable write allocate combine */ ; #orr r0, r0, #(1 << 22) /* disable write allocate */ ; #mcr 15, 1, r0, c9, c0, 2 arm mcr 15 1 9 0 2 [expr {0xC4 | (1<<24) | (1<<23) | (1<<22)}] } # AIPS setup - Only setup MPROTx registers. # The PACR default values are good. proc init_aips { } { ; # Set all MPROTx to be non-bufferable, trusted for R/W, ; # not forced to user-mode. global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR set VAL 0x77777777 # dap apsel 1 mww [expr {$AIPS1_BASE_ADDR + 0x0}] $VAL mww [expr {$AIPS1_BASE_ADDR + 0x4}] $VAL mww [expr {$AIPS2_BASE_ADDR + 0x0}] $VAL mww [expr {$AIPS2_BASE_ADDR + 0x4}] $VAL # dap apsel 0 } proc init_clock { } { global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR set CCM_BASE_ADDR [expr {$AIPS1_BASE_ADDR + 0x000D4000}] set CLKCTL_CCSR 0x0C set CLKCTL_CBCDR 0x14 set CLKCTL_CBCMR 0x18 set PLL1_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00080000}] set PLL2_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00084000}] set PLL3_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00088000}] set PLL4_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x0008C000}] set CLKCTL_CSCMR1 0x1C set CLKCTL_CDHIPR 0x48 set PLATFORM_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x000A0000}] set CLKCTL_CSCDR1 0x24 set CLKCTL_CCDR 0x04 ; # Switch ARM to step clock mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x4 return echo "not returned" setup_pll $PLL1_BASE_ADDR 800 setup_pll $PLL3_BASE_ADDR 400 ; # Switch peripheral to PLL3 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00015154 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x02888945 | (1<<16)}] while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL2_BASE_ADDR 400 ; # Switch peripheral to PLL2 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x00808145 | (2<<10) | (9<<16) | (1<<19)}] mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00016154 ; # change uart clk parent to pll2 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}]] & 0xfcffffff | 0x01000000}] ; # make sure change is effective while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL3_BASE_ADDR 216 setup_pll $PLL4_BASE_ADDR 455 ; # Set the platform clock dividers mww [expr {$PLATFORM_BASE_ADDR + 0x14}] 0x00000124 mww [expr {$CCM_BASE_ADDR + 0x10}] 0 ; # Switch ARM back to PLL 1. mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x0 ; # make uart div=6 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}]] & 0xffffffc0 | 0x0a}] ; # Restore the default values in the Gate registers mww [expr {$CCM_BASE_ADDR + 0x68}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x6C}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x70}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x74}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x78}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x7C}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x80}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x84}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCDR}] 0x00000 ; # for cko - for ARM div by 8 mww [expr {$CCM_BASE_ADDR + 0x60}] [expr {0x000A0000 & 0x00000F0}] } proc setup_pll { PLL_ADDR CLK } { set PLL_DP_CTL 0x00 set PLL_DP_CONFIG 0x04 set PLL_DP_OP 0x08 set PLL_DP_HFS_OP 0x1C set PLL_DP_MFD 0x0C set PLL_DP_HFS_MFD 0x20 set PLL_DP_MFN 0x10 set PLL_DP_HFS_MFN 0x24 if {$CLK == 1000} { set DP_OP [expr {(10 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {12 - 1}] set DP_MFN 5 } elseif {$CLK == 850} { set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {48 - 1}] set DP_MFN 41 } elseif {$CLK == 800} { set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 700} { set DP_OP [expr {(7 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {24 - 1}] set DP_MFN 7 } elseif {$CLK == 600} { set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {4 - 1}] set DP_MFN 1 } elseif {$CLK == 665} { set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {96 - 1}] set DP_MFN 89 } elseif {$CLK == 532} { set DP_OP [expr {(5 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {24 - 1}] set DP_MFN 13 } elseif {$CLK == 455} { set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] set DP_MFD [expr {48 - 1}] set DP_MFN 71 } elseif {$CLK == 400} { set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 216} { set DP_OP [expr {(6 << 4) + ((3 - 1) << 0)}] set DP_MFD [expr {4 - 1}] set DP_MFN 3 } else { error "Error (setup_dll): clock not found!" } mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 mww [expr {$PLL_ADDR + $PLL_DP_CONFIG}] 0x2 mww [expr {$PLL_ADDR + $PLL_DP_OP}] $DP_OP mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_OP mww [expr {$PLL_ADDR + $PLL_DP_MFD}] $DP_MFD mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_MFD mww [expr {$PLL_ADDR + $PLL_DP_MFN}] $DP_MFN mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFN}] $DP_MFN mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 while {[expr {[mrw [expr {$PLL_ADDR + $PLL_DP_CTL}]] & 0x1}] == 0} { sleep 1 } } proc CPU_2_BE_32 { L } { return [expr {(($L & 0x000000FF) << 24) | (($L & 0x0000FF00) << 8) | (($L & 0x00FF0000) >> 8) | (($L & 0xFF000000) >> 24)}] } # Device Configuration Data proc DCD { } { # dap apsel 1 mww 0x53FA8554 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM3 mww 0x53FA8558 0x00300040 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS3 mww 0x53FA8560 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM2 mww 0x53FA8564 0x00300040 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT mww 0x53FA8568 0x00300040 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS2 mww 0x53FA8570 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_1 mww 0x53FA8574 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_CAS mww 0x53FA8578 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_0 mww 0x53FA857c 0x00300040 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0 mww 0x53FA8580 0x00300040 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT0 mww 0x53FA8584 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM0 mww 0x53FA8588 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_RAS mww 0x53FA8590 0x00300040 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS1 mww 0x53FA8594 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM1 mww 0x53FA86f0 0x00300000 ;# IOMUXC_SW_PAD_CTL_GRP_ADDDS mww 0x53FA86f4 0x00000000 ;# IOMUXC_SW_PAD_CTL_GRP_DDRMODE_CTL mww 0x53FA86fc 0x00000000 ;# IOMUXC_SW_PAD_CTL_GRP_DDRPKE mww 0x53FA8714 0x00000000 ;# IOMUXC_SW_PAD_CTL_GRP_DDRMODE - CMOS mode mww 0x53FA8718 0x00300000 ;# IOMUXC_SW_PAD_CTL_GRP_B0DS mww 0x53FA871c 0x00300000 ;# IOMUXC_SW_PAD_CTL_GRP_B1DS mww 0x53FA8720 0x00300000 ;# IOMUXC_SW_PAD_CTL_GRP_CTLDS mww 0x53FA8724 0x04000000 ;# IOMUXC_SW_PAD_CTL_GRP_DDR_TYPE - DDR_SEL0= mww 0x53FA8728 0x00300000 ;# IOMUXC_SW_PAD_CTL_GRP_B2DS mww 0x53FA872c 0x00300000 ;# IOMUXC_SW_PAD_CTL_GRP_B3DS # Initialize DDR2 memory mww 0x63FD9088 0x35343535 ;# ESDCTL_RDDLCTL mww 0x63FD9090 0x4d444c44 ;# ESDCTL_WRDLCTL mww 0x63FD907c 0x01370138 ;# ESDCTL_DGCTRL0 mww 0x63FD9080 0x013b013c ;# ESDCTL_DGCTRL1 mww 0x63FD9018 0x00011740 ;# ESDCTL_ESDMISC mww 0x63FD9000 0xc3190000 ;# ESDCTL_ESDCTL mww 0x63FD900c 0x9f5152e3 ;# ESDCTL_ESDCFG0 mww 0x63FD9010 0xb68e8a63 ;# ESDCTL_ESDCFG1 mww 0x63FD9014 0x01ff00db ;# ESDCTL_ESDCFG2 mww 0x63FD902c 0x000026d2 ;# ESDCTL_ESDRWD mww 0x63FD9030 0x009f0e21 ;# ESDCTL_ESDOR mww 0x63FD9008 0x12273030 ;# ESDCTL_ESDOTC mww 0x63FD9004 0x0002002d ;# ESDCTL_ESDPDC mww 0x63FD901c 0x00008032 ;# ESDCTL_ESDSCR mww 0x63FD901c 0x00008033 ;# ESDCTL_ESDSCR mww 0x63FD901c 0x00028031 ;# ESDCTL_ESDSCR mww 0x63FD901c 0x052080b0 ;# ESDCTL_ESDSCR mww 0x63FD901c 0x04008040 ;# ESDCTL_ESDSCR mww 0x63FD901c 0x0000803a ;# ESDCTL_ESDSCR mww 0x63FD901c 0x0000803b ;# ESDCTL_ESDSCR mww 0x63FD901c 0x00028039 ;# ESDCTL_ESDSCR mww 0x63FD901c 0x05208138 ;# ESDCTL_ESDSCR mww 0x63FD901c 0x04008048 ;# ESDCTL_ESDSCR mww 0x63FD9020 0x00005800 ;# ESDCTL_ESDREF mww 0x63FD9040 0x04b80003 ;# ESDCTL_ZQHWCTRL mww 0x63FD9058 0x00022227 ;# ESDCTL_ODTCTRL mww 0x63FD901C 0x00000000 ;# ESDCTL_ESDSCR # dap apsel 0 } # vim:filetype=tcl ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/imx8mp-evk.cfg ================================================ # # configuration file for NXP MC-IMX8MP-EVK # # Board includes FTDI-based JTAG adapter: interface/ftdi/imx8mp-evk.cfg # transport select jtag adapter speed 1000 reset_config srst_only adapter srst delay 100 set CHIPNAME imx8mp set CHIPCORES 4 source [find target/imx8m.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/insignal_arndale.cfg ================================================ # # InSignal Arndale board # source [find target/exynos5250.cfg] # Experimentally determined highest working speed adapter speed 200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/kasli.cfg ================================================ adapter driver ftdi ftdi device_desc "Quad RS232-HS" ftdi vid_pid 0x0403 0x6011 ftdi channel 0 ftdi layout_init 0x0008 0x000b # adapter usb location 1:8 reset_config none transport select jtag adapter speed 25000 source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] source [find fpga/xilinx-xadc.cfg] source [find fpga/xilinx-dna.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/kc100.cfg ================================================ # Knovative KC-100 cable modem # TNETC4401PYP, 208-QFP U3 source [find target/tnetc4401.cfg] # 14-pin EJTAG on JP1. Standard pinout, 1-3-5-7-9-11 = nTRST-TDI-TDO-TMS-TCK-nSRST. Use 2 for GND. # Was initially disabled in hardware; had to add a solder bridge reenabling R124, R125 on back. reset_config trst_and_srst separate # 16Mb Intel CFI flash. Note this CPU has an internal ROM at 0x1FC0000 (phys) for cold boot. # All that really does is some minimal checks before jumping to external flash at 0x00000000 phys. # That is remapped to 0xB0000000 uncached, 0x90000000 cached. flash bank intel cfi 0xB0000000 0x200000 2 2 $_TARGETNAME # Perform this after a clean reboot, halt, and reset init (which should also leave it halted). proc kc100_dump_flash {} { echo "Probing 48 TSOP Intel CFI flash chip (2MB)..." flash probe intel echo "Dumping 2MB flash chip to flashdump.bin. flash read_bank 0 flashdump.bin 0 0x200000 } #TODO figure out memory init sequence to be able to dump from cached segment instead # There is also a serial console on JP2, 3-5-6 = TX-RX-GND. 9600/8/N/1. # Possibly of note, this modem's ancient ethernet port does not support Auto-MDIX. # This modem in many ways appears to be essentially a clone of the SB5120. See usbjtag.com. # The firmware/OS is also susceptible to many of the same procedures in "Hacking the Cable Modem" # by DerEngel (Ryan Harris), available from No Starch Press. ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/kc705.cfg ================================================ # http://www.xilinx.com/products/boards-and-kits/ek-k7-kc705-g.html source [find interface/ftdi/digilent-hs1.cfg] source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] source [find fpga/xilinx-xadc.cfg] source [find fpga/xilinx-dna.cfg] adapter speed 25000 # example command to write bitstream, soft-cpu bios and runtime: # openocd -f board/kc705.cfg -c "init;\ # jtagspi_init 0 bscan_spi_xc7k325t.bit;\ # jtagspi_program bitstream-kc705.bin 0;\ # jtagspi_program bios.bin 0xaf0000;\ # jtagspi_program runtime.fbi 0xb00000;\ # xc7_program xc7.tap;\ # exit" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/kcu105.cfg ================================================ # xilinx ultrascale # http://www.xilinx.com/support/documentation/user_guides/ug570-ultrascale-configuration.pdf source [find interface/ftdi/digilent_jtag_smt2_nc.cfg] set CHIP XCKU040 source [find cpld/xilinx-xcu.cfg] source [find cpld/jtagspi.cfg] adapter speed 25000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/keil_mcb1700.cfg ================================================ # # Keil MCB1700 eval board # # http://www.keil.com/mcb1700/picture.asp # source [find target/lpc17xx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/keil_mcb2140.cfg ================================================ # # Keil MCB2140 eval board # # http://www.keil.com/mcb2140/picture.asp # source [find target/lpc2148.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/kindle2.cfg ================================================ # Board configuration file for Amazon Kindle Model No. D00701 and D00801 # AKA Kindle 2nd generation and Kindle DX # using a Freescale MCIMX31LDVKN5D i.MX31 processor # # Pins at J9 40-Pin FFC-A: # 1 - GND # 16 - TRSTB # 17 - TDI # 18 - TMS # 19 - TCK # 20 - RTCK # 21 - TDO # 22 - DE # 25 - BOOT_MODE4 # 27 - BOOT_MODE2 source [find target/imx31.cfg] source [find target/imx.cfg] $_TARGETNAME configure -event reset-init { kindle2_init } $_TARGETNAME configure -event reset-start { adapter speed 1000 } # 8MiB NOR Flash set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0xa0000000 0x800000 2 2 $_TARGETNAME # 16kiB internal SRAM $_TARGETNAME configure -work-area-phys 0x1fffc000 \ -work-area-size 0x4000 -work-area-backup 0 # FIXME: currently SRST is not wired to the system reset_config trst_only jtag_ntrst_assert_width 10 jtag_ntrst_delay 30 # this is broken but enabled by default arm11 memwrite burst disable adapter speed 1000 ftdi tdo_sample_edge falling proc kindle2_init {} { imx3x_reset kindle2_clock_setup disable_mmu_and_cache kindle2_misc_init kindle2_sdram_init arm core_state arm } proc kindle2_clock_setup {} { # CCMR: clock from FPM/CKIL mww 0x53f80000 0x074b0b7b # IPU_CONF mww 0x53fc0000 0x040 # 398MHz mww 0x53f80004 0xff871650 mww 0x53f80010 0x00331c23 } proc kindle2_misc_init { } { # AIPS1 mww 0x43f00040 0x0 mww 0x43f00044 0x0 mww 0x43f00048 0x0 mww 0x43f0004c 0x0 mww 0x43f00050 0x0 mww 0x43f00000 0x77777777 mww 0x43f00004 0x77777777 # AIPS2 mww 0x53f00040 0x0 mww 0x53f00044 0x0 mww 0x53f00048 0x0 mww 0x53f0004c 0x0 mww 0x53f00050 0x0 mww 0x53f00000 0x77777777 mww 0x53f00004 0x77777777 # Start 16 bit NorFlash Initialization on CS0 mww 0xb8002000 0x0000cc03 mww 0xb8002004 0xa0330d01 mww 0xb8002008 0x00220800 } proc disable_mmu_and_cache {} { # Mode Supervisor, disable FIQ, IRQ and imprecise data aborts reg cpsr 0x1d3 # flush entire BTAC arm mcr 15 0 7 5 6 0 # invalidate instruction and data cache # MCR CP15, 0, R1, C7, C7, 0 arm mcr 15 0 7 7 0 # clean and invalidate cache arm mcr 15 0 7 15 0 # disable MMU and caches arm mcr 15 0 1 0 0 0 arm mcr 15 0 15 2 4 0 # invalidate TLBs arm mcr 15 0 8 7 0 0 # Drain the write buffer arm mcr 15 0 7 10 4 0 # start from AIPS 2GB region arm mcr 15 0 15 2 4 0x40000015 } proc kindle2_sdram_init {} { #-------------------------------------------- # Samsung K4X1G323PC-8GC3 32Mx32 Mobile DDR SDRAM #-------------------------------------------- # SDCLK mww 0x43fac26c 0 # CAS mww 0x43fac270 0 # RAS mww 0x43fac274 0 # CS2 (CSD0) mww 0x43fac27c 0x1000 # DQM3 mww 0x43fac284 0 # DQM2, DQM1, DQM0, SD31-SD0, A25-A0, MA10 (0x288..0x2dc) mww 0x43fac288 0 mww 0x43fac28c 0 mww 0x43fac290 0 mww 0x43fac294 0 mww 0x43fac298 0 mww 0x43fac29c 0 mww 0x43fac2a0 0 mww 0x43fac2a4 0 mww 0x43fac2a8 0 mww 0x43fac2ac 0 mww 0x43fac2b0 0 mww 0x43fac2b4 0 mww 0x43fac2b8 0 mww 0x43fac2bc 0 mww 0x43fac2c0 0 mww 0x43fac2c4 0 mww 0x43fac2c8 0 mww 0x43fac2cc 0 mww 0x43fac2d0 0 mww 0x43fac2d4 0 mww 0x43fac2d8 0 mww 0x43fac2dc 0 # ? mww 0xb8002000 0x00006602 mww 0xb8002004 0x00000501 mww 0xb8002008 0x00000000 # LPDDR1 Initialization script mww 0xb8001010 0x00000002 mww 0xb8001010 0x00000004 # ESDCFG0: set timing parameters mww 0xb8001004 0x007fff7f # ESDCTL0: select Prechare-All mode mww 0xb8001000 0x92100000 mww 0x80000f00 0x12344321 # ESDCTL0: Auto Refresh mww 0xb8001000 0xa2100000 mww 0x80000000 0x12344321 mww 0x80000000 0x12344321 # ESDCTL0: Load Mode Register mww 0xb8001000 0xb2100000 mwb 0x80000033 0xda mwb 0x81000000 0xff # ESDCTL0: enable Auto-Refresh mww 0xb8001000 0x82226080 mww 0x80000000 0xdeadbeef } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/kontron_sl28.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Kontron SMARC-sAL28 transport select jtag reset_config srst_only srst_nogate jtag newtap unknown0 tap -irlen 12 set _CPUS 2 source [find target/ls1028a.cfg] source [find tcl/cpld/altera-epm240.cfg] adapter speed 2000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/kwikstik.cfg ================================================ # # Freescale KwikStik development board # # # JLINK interface is onboard # source [find interface/jlink.cfg] source [find target/k40.cfg] reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/la_fonera-fon2200.cfg ================================================ source [find target/atheros_ar2315.cfg] reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/lambdaconcept_ecpix-5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # LambdaConcept ECPIX-5 # http://docs.lambdaconcept.com/ecpix-5/ # Currently there are following board variants: # ECPIX-5 45F - LFE5UM5G-45F # ECPIX-5 85F - LFE5UM5G-85F # # This boards have two JTAG interfaces: # - CN4, micro USB port connected to FT2232HQ chip: # ADBUS0 TCK # ADBUS1 TDI # ADBUS2 TDO # ADBUS3 TMS # BDBUS0 UART_TXD # BDBUS1 UART_RXD # This interface should be used with following config: # interface/ftdi/lambdaconcept_ecpix-5.cfg # - CN3, 6 pin connector # See schematics for more details: # http://docs.lambdaconcept.com/ecpix-5/_static/resources/SCH_ECPIX-5_R02.PDF # # No reset lines are implemented. So it is not possible to remote reset the FPGA # by using any of this interfaces source [find interface/ftdi/lambdaconcept_ecpix-5.cfg] source [find fpga/lattice_ecp5.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/lemaker_hikey.cfg ================================================ # # board configuration for LeMaker Hikey # # board does not feature anything but JTAG transport select jtag # SRST-only reset configuration reset_config srst_only srst_push_pull source [find target/hi6220.cfg] # make sure the default target is the boot core targets ${_TARGETNAME}0 proc core_up { args } { global _TARGETNAME # examine remaining cores foreach _core $args { ${_TARGETNAME}$_core arp_examine } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/linksys-wag200g.cfg ================================================ # # Linksys WAG200G Router # # The stock firmware Flash layout is organized as follow: # # Start End Device # 0x90000000 0x90020000 /dev/mtdblock/2 # 0x90020000 0x900d0000 /dev/mtdblock/1 # 0x900d0000 0x903a0000 /dev/mtdblock/0 # 0x903a0000 0x903e0000 /dev/mtdblock/5 # 0x903e0000 0x903f0000 /dev/mtdblock/3 # 0x903f0000 0x90400000 /dev/mtdblock/4 set partition_list { adam2 { "Adam2 bootloader" 0x90000000 0x00020000 } kernel { "Kernel" 0x90020000 0x000b0000 } rootfs { "Root FS" 0x900d0000 0x002d0000 } lang { "Minix language part" 0x903a0000 0x00040000 } config { "Firmware config" 0x903e0000 0x00010000 } adam2env { "Adam2 environment" 0x903f0000 0x00010000 } } source [find target/ti-ar7.cfg] # External 4MB MXIC 29LV320MBTC Flash (Manufacturer/Device: 0x00c2 0x227e) set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x90000000 0x00400000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/linksys-wrt54gl.cfg ================================================ # # Linksys WRT54GL v1.1 # source [find target/bcm5352e.cfg] set partition_list { CFE { Bootloader 0x1c000000 0x00040000 } firmware { "Kernel+rootfs" 0x1c040000 0x003b0000 } nvram { "Config space" 0x1c3f0000 0x00010000 } } # External 4MB NOR Flash (Intel TE28F320C3BD90 or similar) set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x1c000000 0x00400000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/linksys_nslu2.cfg ================================================ # This is for the LinkSys (CISCO) NSLU2 board # It is an Intel XSCALE IXP420 CPU. source [find target/ixp42x.cfg] # The _TARGETNAME is set by the above. $_TARGETNAME configure -work-area-phys 0x00020000 -work-area-size 0x10000 -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/lisa-l.cfg ================================================ # the Lost Illusions Serendipitous Autopilot # http://paparazzi.enac.fr/wiki/Lisa # Work-area size (RAM size) = 20kB for STM32F103RB device set WORKAREASIZE 0x5000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/logicpd_imx27.cfg ================================================ # The LogicPD Eval IMX27 eval board has a single IMX27 chip source [find target/imx27.cfg] # The Logic PD board has a NOR flash on CS0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0xc0000000 0x00200000 2 2 $_TARGETNAME # # FIX ME, Add support to # # (A) hard reset the board. # (B) Initialize the SDRAM on the board # ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/lpc1850_spifi_generic.cfg ================================================ # # Generic LPC1850 board w/ SPIFI flash. # This config file is intended as an example of how to # use the lpcspifi flash driver, but it should be functional # for most LPC1850 boards utilizing SPIFI flash. set CHIPNAME lpc1850 source [find target/lpc1850.cfg] #A large working area greatly reduces flash write times set _WORKAREASIZE 0x4000 $_CHIPNAME.m3 configure -work-area-phys 0x10000000 -work-area-size $_WORKAREASIZE #Configure the flash bank; 0x14000000 is the base address for #lpc43xx/lpc18xx family micros. flash bank SPIFI_FLASH lpcspifi 0x14000000 0 0 0 $_CHIPNAME.m3 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/lpc4350_spifi_generic.cfg ================================================ # # Generic LPC4350 board w/ SPIFI flash. # This config file is intended as an example of how to # use the lpcspifi flash driver, but it should be functional # for most LPC4350 boards utilizing SPIFI flash. set CHIPNAME lpc4350 source [find target/lpc4350.cfg] #Configure the flash bank; 0x14000000 is the base address for #lpc43xx/lpc18xx family micros. flash bank SPIFI_FLASH lpcspifi 0x14000000 0 0 0 $_CHIPNAME.m4 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/lubbock.cfg ================================================ # Intel "Lubbock" Development Board with PXA255 (dbpxa255) # Obsolete; this was Intel's original PXA255 development system # Board also had CPU cards for SA1100, PXA210, PXA250, and more. source [find target/pxa255.cfg] adapter srst delay 250 jtag_ntrst_delay 250 # NOTE: until after pinmux and such are set up, only CS0 is # available ... not 2nd bank of CFI, or FPGA, SRAM, ENET, etc. # CS0, CS1 -- two banks of CFI flash, 32 MBytes each # each bank is 32-bits wide, two 16-bit chips in parallel set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME cfi 0x04000000 0x02000000 2 4 $_TARGETNAME # CS2 low -- FPGA registers # CS2 high -- 1 MByte SRAM at 0x0a00.0000 ... last 64K for scratch $_TARGETNAME configure -work-area-phys 0x0a0f0000 $_TARGETNAME configure -event reset-assert-pre \ "$_TARGETNAME configure -work-area-size 0" # Make the hex led display a number, assuming CS2 is set up # and all digits have been enabled through the FPGA. proc hexled {u32} { mww 0x08000010 $u32 } # CS3 -- Ethernet # CS4 -- SA1111 # CS5 -- PCMCIA # NOTE: system console normally uses the FF UART connector proc lubbock_init {target} { echo "Initialize PXA255 Lubbock board" # (1) pinmux # GPSR0..GPSR2 mww 0x40e00018 0x00008000 mww 0x40e0001c 0x00FC0382 mww 0x40e00020 0x0001FFFF # GPDR0..GPDR2 mww 0x40e0000c 0x0060A800 mww 0x40e00010 0x00FF0382 mww 0x40e00014 0x0001C000 # GAFR0_[LU]..GAFR2_[LU] mww 0x40e00054 0x98400000 mww 0x40e00058 0x00002950 mww 0x40e0005c 0x000A9558 mww 0x40e00060 0x0005AAAA mww 0x40e00064 0xA0000000 mww 0x40e00068 0x00000002 # write PSSR, enable GPIOs mww 0x40f00000 0x00000020 # write LED ctrl register ... ones disable # high byte, 8 hex leds; low byte, 8 discretes mwh 0x08000040 0xf0ff hexled 0x0000 # (2) Address space setup # MSC0/MSC1/MSC2 mww 0x48000008 0x23f223f2 mww 0x4800000c 0x3ff1a441 mww 0x48000010 0x7ff97ff1 # pcmcia/cf mww 0x48000014 0x00000000 mww 0x48000028 0x00010504 mww 0x4800002c 0x00010504 mww 0x48000030 0x00010504 mww 0x48000034 0x00010504 mww 0x48000038 0x00004715 mww 0x4800003c 0x00004715 hexled 0x1111 # (3) SDRAM setup # REVISIT this looks dubious ... no refresh cycles mww 0x48000004 0x03CA4018 mww 0x48000004 0x004B4018 mww 0x48000004 0x000B4018 mww 0x48000004 0x000BC018 mww 0x48000000 0x00001AC8 mww 0x48000000 0x00001AC9 mww 0x48000040 0x00000000 # FIXME -- setup: # CLOCKS (and faster JTAG) # enable icache # FIXME SRAM isn't working # $target configure -work-area-size 0x10000 hexled 0x2222 flash probe 0 flash probe 1 hexled 0xcafe } $_TARGETNAME configure -event reset-init "lubbock_init $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/marsohod.cfg ================================================ # # Marsohod CPLD Development and Education board # # http://marsohod.org/howtostart/plata # # Recommended MBFTDI programmer source [find interface/ftdi/mbftdi.cfg] adapter speed 2000 transport select jtag # Altera MAXII EPM240T100C CPLD source [find cpld/altera-epm240.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/marsohod2.cfg ================================================ # # Marsohod2 FPGA Development and Education board # # http://www.marsohod.org/prodmarsohod2 # # Built-in MBFTDI programmer source [find interface/ftdi/mbftdi.cfg] adapter speed 2000 transport select jtag # Cyclone III EP3C10E144 FPGA source [find fpga/altera-ep3c10.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/marsohod3.cfg ================================================ # # Marsohod3 FPGA Development and Education board # # http://www.marsohod.org/plata-marsokhod3 # # Built-in MBFTDI programmer source [find interface/ftdi/mbftdi.cfg] adapter speed 2000 transport select jtag # MAX10 10M50SAE144C8GES FPGA source [find fpga/altera-10m50.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/mbed-lpc11u24.cfg ================================================ # This is an mbed eval board with a single NXP LPC11U24 chip. # http://mbed.org/handbook/mbed-NXP-LPC11U24 # source [find interface/cmsis-dap.cfg] # NXP LPC11U24 Cortex-M0 with 32kB Flash and 8kB SRAM set WORKAREASIZE 0x2000 source [find target/lpc11xx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/mbed-lpc1768.cfg ================================================ # This is an mbed eval board with a single NXP LPC1768 chip. # http://mbed.org/handbook/mbed-NXP-LPC1768 # source [find interface/cmsis-dap.cfg] source [find target/lpc17xx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/mcb1700.cfg ================================================ # Keil MCB1700 PCB with 1768 # # Reset init script sets it to 100MHz set CCLK 100000 source [find target/lpc17xx.cfg] global MCB1700_CCLK set MCB1700_CCLK $CCLK $_TARGETNAME configure -event reset-start { # Start *real slow* as we do not know the # state the boot rom left the clock in adapter speed 10 } # Set up 100MHz clock to CPU $_TARGETNAME configure -event reset-init { # PLL0CON: Disable PLL mww 0x400FC080 0x00000000 # PLLFEED mww 0x400FC08C 0x000000AA # PLLFEED mww 0x400FC08C 0x00000055 # CCLK=PLL/4 (=100 MHz) mww 0x400FC104 0x00000003 # CLKSRCSEL: Clock source = internal RC oscillator mww 0x400FC10C 0x00000000 # PLL0CFG: M=50,N=1 -> PLL=400 MHz mww 0x400FC084 0x00000031 # PLLFEED mww 0x400FC08C 0x000000AA # PLLFEED mww 0x400FC08C 0x00000055 # PLL0CON: Enable PLL mww 0x400FC080 0x00000001 # PLLFEED mww 0x400FC08C 0x000000AA # PLLFEED mww 0x400FC08C 0x00000055 sleep 50 # PLL0CON: Connect PLL mww 0x400FC080 0x00000003 # PLLFEED mww 0x400FC08C 0x000000AA # PLLFEED mww 0x400FC08C 0x00000055 # Dividing CPU clock by 8 should be pretty conservative # # global MCB1700_CCLK adapter speed [expr {$MCB1700_CCLK / 8}] # Do not remap 0x0000-0x0020 to anything but the flash (i.e. select # "User Flash Mode" where interrupt vectors are _not_ remapped, # and reside in flash instead). # # See Table 612. Memory Mapping Control register (MEMMAP - 0x400F C040) bit description # Bit Symbol Value Description Reset # value # 0 MAP Memory map control. 0 # 0 Boot mode. A portion of the Boot ROM is mapped to address 0. # 1 User mode. The on-chip Flash memory is mapped to address 0. # 31:1 - Reserved. The value read from a reserved bit is not defined. NA # # http://ics.nxp.com/support/documents/microcontrollers/?scope=LPC1768&type=user mww 0x400FC040 0x01 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/microchip_explorer16.cfg ================================================ # Microchip Explorer 16 with PIC32MX360F512L PIM module. # http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en024858 # TAPID for PIC32MX360F512L set CPUTAPID 0x30938053 # use 32k working area set WORKAREASIZE 32768 source [find target/pic32mx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/microchip_sama5d27_som1_kit1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Microchip SAMA5D27-SOM1-EK1 # https://www.microchip.com/DevelopmentTools/ProductDetails/PartNO/ATSAMA5D27-SOM1-EK1 # This board provide two jtag interfaces: # J11 - 10 pin interface # J10 - USB interface connected to the J-Link-OB. # This functionality is implemented with an ATSAM3U4C microcontroller and # provides JTAG functions and a bridge USB/Serial debug port (CDC). # # Jumper J7 disables the J-Link-OB-ATSAM3U4C JTAG functionality. # - Jumper J7 not installed: J-Link-OB-ATSAM3U4C is enabled and fully functional. # - Jumper J7 installed: J-Link-OB-ATSAM3U4C is disabled and an external JTAG # controller can be used through the 10-pin JTAG port J11. source [find interface/jlink.cfg] reset_config srst_only source [find target/at91sama5d2.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/microchip_same51_curiosity_nano.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Microchip SAME51 Curiosity Nano evaluation kit. # # https://www.microchip.com/en-us/development-tool/EV76S68A # source [find interface/cmsis-dap.cfg] set CHIPNAME same51 source [find target/atsame5x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/microchip_same54_xplained_pro.cfg ================================================ # # Microchip (former Atmel) SAM E54 Xplained Pro evaluation kit. # http://www.microchip.com/developmenttools/productdetails.aspx?partno=atsame54-xpro # source [find interface/cmsis-dap.cfg] set CHIPNAME same54 source [find target/atsame5x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/microchip_saml11_xplained_pro.cfg ================================================ # # Microchip (formerly Atmel) SAM L11 Xplained Pro Evaluation Kit. # https://www.microchip.com/DevelopmentTools/ProductDetails/dm320205 # source [find interface/cmsis-dap.cfg] adapter speed 1000 set CHIPNAME saml11 source [find target/atsaml1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/mini2440.cfg ================================================ #------------------------------------------------------------------------- # Mini2440 Samsung s3c2440A Processor with 64MB DRAM, 64MB NAND, 2 MB N0R # NOTE: Configured for NAND boot (switch S2 in NANDBOOT) # 64 MB NAND (Samsung K9D1208V0M) # B Findlay 08/09 # # ----------- Important notes to help you on your way ---------- # README: # NOR/NAND Boot Switch - I have not read the vivi source, but from # what I could tell from reading the registers it appears that vivi # loads itself into DRAM and then flips NFCONT (0x4E000004) bits # Mode (bit 0 = 1), and REG_nCE (bit 1 = 0) which maps the NAND # FLASH at the bottom 64MB of memory. This essentially takes the # NOR Flash out of the circuit so you can't trash it. # # I adapted the samsung_s3c2440.cfg file which is why I did not # include "source [find target/samsung_s3c2440.cfg]". I believe # the -work-area-phys 0x200000 is incorrect, but also had to pad # some additional resets. I didn't modify it as if it is working # for someone, the work-area-phys is not used by most. # # JTAG ADAPTER SPECIFIC # IMPORTANT! Any JTAG device that uses ADAPTIVE CLOCKING will likely # FAIL as the pin RTCK on the mini2440 10 pin JTAG Conn doesn't exist. # This is Pin 11 (RTCK) on 20 pin JTAG connector. Therefore it is # necessary to FORCE setting the clock. Normally this should be configured # in the openocd.cfg file, but was placed here as it can be a tough # problem to figure out. THIS MAY NOT FIX YOUR PROBLEM.. I modified # the openOCD driver jlink.c and posted it here. It may eventually end # up changed in openOCD, but its a hack in the driver and really should # be in the jtag layer (core.c me thinks), but haven't done it yet. My # hack for jlink.c may be found here. # # http://forum.sparkfun.com/viewtopic.php?t=16763&sid=946e65abdd3bab39cc7d90dee33ff135 # # Note: Also if you have a USB JTAG, you will need the USB library installed # on your system "libusb-dev" or the make of openocd will fail. I *think* # it's apt-get install libusb-dev. When I made my config I only included # --enable-jlink and --enable-usbdevs # # I HAVE NOT Tested this thoroughly, so there could still be problems. # But it should get you way ahead of the game from where I started. # If you find problems (and fixes) please post them to # openocd-development@lists.berlios.de and join the developers and # check in fixes to this and anything else you find. I do not # provide support, but if you ask really nice and I see anything # obvious I will tell you.. mostly just dig, fix, and submit to openocd. # # best! brfindla@yahoo.com Nashua, NH USA # # Recommended resources: # - first two are the best Mini2440 resources anywhere # - maintained by buserror... thanks guy! # # http://bliterness.blogspot.com/ # http://code.google.com/p/mini2440/ # # others.... # # http://forum.sparkfun.com/viewforum.php?f=18 # http://labs.kernelconcepts.de/Publications/Micro24401/ # http://www.friendlyarm.net/home # http://www.amontec.com/jtag_pinout.shtml # #------------------------------------------------------------------------- # # # Your openocd.cfg file should contain: # source [find interface/.cfg] # source [find board/mini2440.cfg] # # # # FIXME use some standard target config, maybe create one from this # # source [find target/...cfg] #------------------------------------------------------------------------- # Target configuration for the Samsung 2440 system on chip # Tested on a S3C2440 Evaluation board by keesj # Processor : ARM920Tid(wb) rev 0 (v4l) # Info: JTAG tap: s3c2440.cpu tap/device found: 0x0032409d # (Manufacturer: 0x04e, Part: 0x0324, Version: 0x0) #------------------------------------------------------------------------- if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME s3c2440 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a bigendian set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0032409d } #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm920t -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x40000000 -work-area-size 0x4000 -work-area-backup 1 #reset configuration adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst #------------------------------------------------------------------------- # JTAG ADAPTER SPECIFIC # IMPORTANT! See README at top of this file. #------------------------------------------------------------------------- adapter speed 12000 jtag interface #------------------------------------------------------------------------- # GDB Setup #------------------------------------------------------------------------- gdb_breakpoint_override hard #------------------------------------------------ # ARM SPECIFIC #------------------------------------------------ targets # arm7_9 dcc_downloads enable # arm7_9 fast_memory_access enable nand device s3c2440 0 adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst init echo " " echo "-------------------------------------------" echo "--- login with - telnet localhost 4444 ---" echo "--- then type help_2440 ---" echo "-------------------------------------------" echo " " #------------------------------------------------ # Processor Initialialization # Note: Processor writes can only occur when # the state is in SYSTEM. When you call init_2440 # one of the first lines will tell you what state # you are in. If a linux image is booting # when you run this, it will not work # a vivi boot loader will run with this just # fine. The reg values were obtained by a combination # of figuring them out fromt the manual, and looking # at post vivi values with the debugger. Don't # place too much faith in them, but seem to work. #------------------------------------------------ proc init_2440 { } { halt s3c2440.cpu curstate #----------------------------------------------- # Set Processor Clocks - mini2440 xtal=12mHz # we set main clock for 405mHZ # we set the USB Clock for 48mHz # OM2 OM3 pulled to ground so main clock and # usb clock are off 12mHz xtal #----------------------------------------------- mww phys 0x4C000014 0x00000005 ;# Clock Divider control Reg mww phys 0x4C000000 0xFFFFFFFF ;# LOCKTIME count register mww phys 0x4C000008 0x00038022 ;# UPPLCON USB clock config Reg mww phys 0x4C000004 0x0007F021 ;# MPPLCON Proc clock config Reg #----------------------------------------------- # Configure Memory controller # BWSCON configures all banks, NAND, NOR, DRAM # DRAM - 64MB - 32 bit bus, uses BANKCON6 BANKCON7 #----------------------------------------------- mww phys 0x48000000 0x22111112 ;# BWSCON - Bank and Bus Width mww phys 0x48000010 0x00001112 ;# BANKCON4 - ? mww phys 0x4800001c 0x00018009 ;# BANKCON6 - DRAM mww phys 0x48000020 0x00018009 ;# BANKCON7 - DRAM mww phys 0x48000024 0x008E04EB ;# REFRESH - DRAM mww phys 0x48000028 0x000000B2 ;# BANKSIZE - DRAM mww phys 0x4800002C 0x00000030 ;# MRSRB6 - DRAM mww phys 0x48000030 0x00000030 ;# MRSRB7 - DRAM #----------------------------------------------- # Now port configuration for enables for memory # and other stuff. #----------------------------------------------- mww phys 0x56000000 0x007FFFFF ;# GPACON mww phys 0x56000010 0x00295559 ;# GPBCON mww phys 0x56000018 0x000003FF ;# GPBUP (PULLUP ENABLE) mww phys 0x56000014 0x000007C2 ;# GPBDAT mww phys 0x56000020 0xAAAAA6AA ;# GPCCON mww phys 0x56000028 0x0000FFFF ;# GPCUP mww phys 0x56000024 0x00000020 ;# GPCDAT mww phys 0x56000030 0xAAAAAAAA ;# GPDCON mww phys 0x56000038 0x0000FFFF ;# GPDUP mww phys 0x56000040 0xAAAAAAAA ;# GPECON mww phys 0x56000048 0x0000FFFF ;# GPEUP mww phys 0x56000050 0x00001555 ;# GPFCON mww phys 0x56000058 0x0000007F ;# GPFUP mww phys 0x56000054 0x00000000 ;# GPFDAT mww phys 0x56000060 0x00150114 ;# GPGCON mww phys 0x56000068 0x0000007F ;# GPGUP mww phys 0x56000070 0x0015AAAA ;# GPHCON mww phys 0x56000078 0x000003FF ;# GPGUP } proc flash_config { } { #----------------------------------------- # Finish Flash Configuration #----------------------------------------- halt #flash configuration (K9D1208V0M: 512Mbit, x8, 3.3V, Mode: Normal, 1st gen) nand probe 0 nand list } proc flash_uboot { } { # flash the u-Boot binary and reboot into it init_2440 flash_config nand erase 0 0x0 0x40000 nand write 0 /tftpboot/u-boot-nand512.bin 0 oob_softecc_kw resume } proc load_uboot { } { echo " " echo " " echo "----------------------------------------------------------" echo "---- Load U-Boot into RAM and execute it. ---" echo "---- NOTE: loads, partially runs, and hangs ---" echo "---- U-Boot is fine, this image runs from vivi. ---" echo "---- I burned u-boot into NAND so I didn't finish ---" echo "---- debugging it. I am leaving this here as it is ---" echo "---- part of the way there if you want to fix it. ---" echo "---- ---" echo "---- mini2440 U-boot here: ---" echo "---- http://repo.or.cz/w/u-boot-openmoko/mini2440.git ---" echo "---- Also this: ---" echo "---- http://code.google.com/p/mini2440/wiki/MiniBringup --" echo "----------------------------------------------------------" init_2440 echo "Loading /tftpboot/u-boot-nand512.bin" load_image /tftpboot/u-boot-nand512.bin 0x33f80000 bin echo "Verifying image...." verify_image /tftpboot/u-boot-nand512.bin 0x33f80000 bin echo "jumping to u-boot" #bp 0x33f80068 4 hw reg 0 0 reg 1 0 reg 2 0 reg 3 0 reg 4 0x33f80000 resume 0x33f80000 } # this may help a little bit debugging the load_uboot proc s {} { step reg arm disassemble 0x33F80068 0x10 } proc help_2440 {} { echo " " echo " " echo "-----------------------------------------------------------" echo "---- The following mini2440 funcs are supported ----" echo "---- init_2440 - initialize clocks, DRAM, IO ----" echo "---- flash_config - configures nand flash ----" echo "---- load_uboot - loads uboot into ram ----" echo "---- flash_uboot - flashes uboot to nand (untested) ----" echo "---- help_2440 - this help display ----" echo "-----------------------------------------------------------" echo " " echo " " } #---------------------------------------------------------------------------- #----------------------------------- END ------------------------------------ #---------------------------------------------------------------------------- ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/mini6410.cfg ================================================ # Target configuration for the Samsung s3c6410 system on chip # Tested on a tiny6410 # Processor : ARM1176 # Info : JTAG tap: s3c6410.etb tap/device found: 0x2b900f0f (mfg: 0x787, part: 0xb900, ver: 0x2) # Info : JTAG tap: s3c6410.cpu tap/device found: 0x07b76f0f (mfg: 0x787, part: 0x7b76, ver: 0x0) source [find target/samsung_s3c6410.cfg] proc init_6410 {} { halt reg cpsr 0x1D3 arm mcr 15 0 15 2 4 0x70000013 #----------------------------------------------- # Clock and Timer Setting #----------------------------------------------- mww 0x7e004000 0 ;# WATCHDOG - Disable mww 0x7E00F120 0x0003 ;# MEM_SYS_CFG - CS0:8 bit, Mem1:32bit, CS2=NAND #mww 0x7E00F120 0x1000 ;# MEM_SYS_CFG - CS0:16bit, Mem1:32bit, CS2=SROMC #mww 0x7E00F120 0x1002 ;# MEM_SYS_CFG - CS0:16bit, Mem1:32bit, CS2=OND mww 0x7E00F900 0x805e ;# OTHERS - Change SYNCMUX[6] to “1” sleep 1000 mww 0x7E00F900 0x80de ;# OTHERS - Assert SYNCREQ&VICSYNCEN to “1”(rb1004modify) sleep 1000 ;# - Others[11:8] to 0xF mww 0x7E00F000 0xffff ;# APLL_LOCK - APLL LockTime mww 0x7E00F004 0xffff ;# MPLL_LOCK - MPLL LockTime mww 0x7E00F020 0x1047310 ;# CLK_DIV0 - ARMCLK:HCLK:PCLK = 1:4:16 mww 0x7E00F00c 0x81900302 ;# APLL_CON - A:400, P:3, S:2 => 400MHz mww 0x7E00F010 0x81900303 ;# MPLL_CON - M:400, P:3, S:3 => 200MHz mww 0x7E00F01c 0x3 ;# CLK_SRC - APLL,MPLL Clock Select #----------------------------------------------- # DRAM initialization #----------------------------------------------- mww 0x7e001004 0x4 ;# P1MEMCCMD - Enter the config state mww 0x7e001010 0x30C ;# P1REFRESH - Refresh Period register (7800ns), 100MHz # mww 0x7e001010 0x40e ;# P1REFRESH - Refresh Period register (7800ns), 133MHz mww 0x7e001014 0x6 ;# P1CASLAT - CAS Latency = 3 mww 0x7e001018 0x1 ;# P1T_DQSS mww 0x7e00101c 0x2 ;# P1T_MRD mww 0x7e001020 0x7 ;# P1T_RAS - 45 ns mww 0x7e001024 0xA ;# P1T_RC - 67.5 ns mww 0x7e001028 0xC ;# P1T_RCD - 22.5 ns mww 0x7e00102C 0x10B ;# P1T_RFC - 80 ns mww 0x7e001030 0xC ;# P1T_RP - 22.5 ns mww 0x7e001034 0x3 ;# P1T_RRD - 15 ns mww 0x7e001038 0x3 ;# P1T_WR - 15 ns mww 0x7e00103C 0x2 ;# P1T_WTR mww 0x7e001040 0x2 ;# P1T_XP mww 0x7e001044 0x11 ;# P1T_XSR - 120 ns mww 0x7e001048 0x11 ;# P1T_ESR #----------------------------------------------- # Memory Configuration Registers #----------------------------------------------- mww 0x7e00100C 0x00010012 ;# P1MEMCFG - 1 CKE, 1Chip, 4burst, Alw, AP[10],ROW/Column bit mww 0x7e00104C 0x0B41 ;# P1MEMCFG2 - Read delay 1 Cycle, mDDR, 32bit, Sync. mww 0x7e001200 0x150F0 ;# CHIP_N_CFG - 0x150F0 for 256M, 0x150F8 for 128M #----------------------------------------------- # Memory Direct Commands #----------------------------------------------- mww 0x7e001008 0xc0000 ;# Chip0 Direct Command :NOP5 mww 0x7e001008 0x0 ;# Chip0 Direct Command :PreCharge al mww 0x7e001008 0x40000 ;# Chip0 Direct Command :AutoRefresh mww 0x7e001008 0x40000 ;# Chip0 Direct Command :AutoRefresh mww 0x7e001008 0xA0000 ;# EMRS, DS:Full, PASR:Full mww 0x7e001008 0x80032 ;# MRS, CAS3, BL4 mww 0x7e001004 0x0 ;# Enable DMC1 } proc install_6410_uboot {} { # write U-boot magic number mww 0x50000000 0x24564236 mww 0x50000004 0x20764316 load_image u-boot_nand-ram256.bin 0x50008000 bin load_image u-boot_nand-ram256.bin 0x57E00000 bin #Kick in reg pc 0x57E00000 resume } proc init_6410_flash {} { halt nand probe 0 nand list } adapter speed 1000 adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst gdb_breakpoint_override hard targets nand device $_CHIPNAME.flash s3c6400 $_CHIPNAME.cpu init echo " " echo " " echo "-------------------------------------------------------------------" echo "---- The following mini6410/tiny6410 functions are available: ----" echo "---- init_6410 - initialize clock, timer, DRAM ----" echo "---- init_6410_flash - initializes NAND flash support ----" echo "---- install_6410_uboot - copies u-boot image into RAM and ----" echo "---- runs it ----" echo "-------------------------------------------------------------------" echo " " echo " " ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/minispartan6.cfg ================================================ # https://www.scarabhardware.com/minispartan6/ source [find interface/ftdi/minispartan6.cfg] source [find cpld/xilinx-xc6s.cfg] source [find cpld/jtagspi.cfg] # example command to read the device dna of the FPGA on the board; # openocd -f board/minispartan6.cfg -c "init;xc6s_print_dna xc6s.tap;shutdown" # example command to write bitstream # openocd -f board/minispartan6.cfg -c "init;\ # jtagspi_init 0 bscan_spi_xc6slx??.bit;\ # jtagspi_program bitstream.bin 0;\ # xc6s_program xc6s.tap;\ # shutdown" # # jtagspi flash procies can be found in the contrib/loaders/flash/fpga/ # directory, with prebuilt versions available at # https://github.com/jordens/bscan_spi_bitstreams # # For the SLX25 variant, use # - https://github.com/jordens/bscan_spi_bitstreams/raw/master/bscan_spi_xc6slx25.bit # For the SLX9 variant, use # - https://github.com/jordens/bscan_spi_bitstreams/raw/master/bscan_spi_xc6slx9.bit ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/nds32_corvettef1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # ADP-Corvette-F1 R1.0 # http://www.andestech.com/en/products-solutions/andeshape-platforms/corvette-f1-r1/ # ADP-Corvette-F1 R2.0 # http://www.andestech.com/en/products-solutions/andeshape-platforms/corvette-f1-r2/ adapter speed 10000 adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 reset_config srst_only source [find target/nds32v5.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/nds32_xc5.cfg ================================================ set _CPUTAPID 0x1000063d set _CHIPNAME nds32 source [find target/nds32v3.cfg] jtag init ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/nds32_xc7.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # ADP-XC7K160/410 # http://www.andestech.com/en/products-solutions/andeshape-platforms/adp-xc7k160-410/ source [find target/nds32v5.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/netgear-dg834v3.cfg ================================================ # # Netgear DG834v3 Router # Internal 4Kb RAM (@0x80000000) # Flash is located at 0x90000000 (CS0) and RAM is located at 0x94000000 (CS1) # set partition_list { loader { "Bootloader (ADAM2)" 0x90000000 0x00020000 } firmware { "Kernel+rootfs" 0x90020000 0x003d0000 } config { "Bootloader config space" 0x903f0000 0x00010000 } } source [find target/ti-ar7.cfg] # External 16MB SDRAM - disabled as we use internal sram #$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 0x00001000 # External 4MB NOR Flash set _FLASHNAME $_CHIPNAME.norflash flash bank $_FLASHNAME cfi 0x90000000 0x00400000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/netgear-wg102.cfg ================================================ source [find target/atheros_ar2313.cfg] reset_config trst_and_srst $_TARGETNAME configure -event reset-init { mips32 cp0 12 0 0x10400000 # configure sdram controller mww 0xb8300004 0x0e03 sleep 100 mww 0xb8300004 0x0e01 mww 0xb8300008 0x10 sleep 500 mww 0xb8300004 0x0e02 mww 0xb8300000 0x6c0088 mww 0xb8300008 0x57e mww 0xb8300004 0x0e00 mww 0xb8300004 0xb00 # configure flash # 0x00000001 - 0x01 << FLASHCTL_IDCY_S # 0x000000e0 - 0x07 << FLASHCTL_WST1_S # FLASHCTL_RBLE 0x00000400 - Read byte lane enable # 0x00003800 - 0x07 << FLASHCTL_WST2_S # FLASHCTL_AC_8M 0x00060000 - Size of flash # FLASHCTL_E 0x00080000 - Flash bank enable (added) # FLASHCTL_WP 0x04000000 - write protect. If used, CFI mode wont work!! # FLASHCTL_MWx16 0x10000000 - 16bit mode. Do not use it!! # FLASHCTL_MWx8 0x00000000 - 8bit mode. mww 0xb8400000 0x000d3ce1 } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0xbe000000 0x00400000 1 1 $_TARGETNAME x16_as_x8 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/nordic_nrf51822_mkit.cfg ================================================ # # Nordic Semiconductor PCA10024 board (aka nRF51822-mKIT) # source [find interface/cmsis-dap.cfg] source [find target/nrf51.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/nordic_nrf51_dk.cfg ================================================ # # Nordic Semiconductor NRF51 Development Kit (nRF6824) # source [find interface/jlink.cfg] transport select swd source [find target/nrf51.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/nordic_nrf52_dk.cfg ================================================ # # Nordic Semiconductor NRF52 Development Kit (nRF52832) # source [find interface/jlink.cfg] transport select swd source [find target/nrf52.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/nordic_nrf52_ftx232.cfg ================================================ # # nordic module NRF52 (nRF52832/52840) attached to an adafruit ft232h module # or any FT232H/FT2232H/FT4232H based board/module # source [find interface/ftdi/ft232h-module-swd.cfg] #source [find interface/ftdi/minimodule-swd.cfg] transport select swd source [find target/nrf52.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/novena-internal-fpga.cfg ================================================ # # Novena open hardware and F/OSS-friendly computing platform # # Design documentation: # http://www.kosagi.com/w/index.php?title=Novena_PVT_Design_Source # # +-------------+--------------+------+-------+---------+ # | Pad name | Schematic | GPIO | sysfs | JTAG | # +-------------+--------------+------+-------+---------+ # | DISP0_DAT13 | FPGA_RESET_N | 5-07 | 135 | RESET_N | # | DISP0_DAT14 | FPGA_TCK | 5-08 | 136 | TCK | # | DISP0_DAT15 | FPGA_TDI | 5-09 | 137 | TDI | # | DISP0_DAT16 | FPGA_TDO | 5-10 | 138 | TDO | # | DISP0_DAT17 | FPGA_TMS | 5-11 | 139 | TMS | # +-------------+--------------+------+-------+---------+ adapter driver sysfsgpio transport select jtag # TCK TMS TDI TDO sysfsgpio jtag_nums 136 139 137 138 source [find cpld/xilinx-xc6s.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/npcx_evb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Nuvoton NPCX Evaluation Board source [find interface/jlink.cfg] transport select swd source [find target/npcx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/numato_mimas_a7.cfg ================================================ # # Numato Mimas A7 - Artix 7 FPGA Board # # https://numato.com/product/mimas-a7-artix-7-fpga-development-board-with-ddr-sdram-and-gigabit-ethernet # # Note: Connect external DC power supply if programming a heavy design onto FPGA. # Programming while powering via USB may lead to programming failure. # Therefore, prefer external power supply. adapter driver ftdi ftdi device_desc "Mimas Artix 7 FPGA Module" ftdi vid_pid 0x2a19 0x1009 # channel 0 is for custom purpose by users (like uart, fifo etc) # channel 1 is reserved for JTAG (by-default) or SPI (possible via changing solder jumpers) ftdi channel 1 ftdi tdo_sample_edge falling # FTDI Pin Layout # # +--------+-------+-------+-------+-------+-------+-------+-------+ # | DBUS7 | DBUS6 | DBUS5 | DBUS4 | DBUS3 | DBUS2 | DBUS1 | DBUS0 | # +--------+-------+-------+-------+-------+-------+-------+-------+ # | PROG_B | OE_N | NC | NC | TMS | TDO | TDI | TCK | # +--------+-------+-------+-------+-------+-------+-------+-------+ # # OE_N is JTAG buffer output enable signal (active-low) # PROG_B is not used, so left as input to FTDI. # ftdi layout_init 0x0008 0x004b reset_config none adapter speed 30000 source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/numato_opsis.cfg ================================================ # http://opsis.hdmi2usb.tv # # The Numato Opsis is an FPGA based, open video platform. # # The board is supported via ixo-usb-jtag project. See the # interface/usb-jtag.cfg for more information. source [find interface/usb-jtag.cfg] source [find cpld/xilinx-xc6s.cfg] source [find cpld/jtagspi.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/nxp_frdm-k64f.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an NXP Freedom eval board with a single MK64FN1M0VLL12 chip. # https://www.nxp.com/design/development-boards/freedom-development-boards/mcu-boards/freedom-development-platform-for-kinetis-k64-k63-and-k24-mcus:FRDM-K64F # source [find interface/cmsis-dap.cfg] # Set working area to 16 KiB set WORKAREASIZE 0x4000 set CHIPNAME k64f reset_config srst_only source [find target/kx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/nxp_frdm-ls1012a.cfg ================================================ # # NXP FRDM-LS1012A (Freedom) # # # NXP Kinetis K20 # source [find interface/cmsis-dap.cfg] transport select jtag # Also offers a 10-pin 0.05" CoreSight JTAG connector. source [find target/ls1012a.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/nxp_imx7sabre.cfg ================================================ # NXP IMX7SABRE board # use on-board JTAG header transport select jtag # set a safe speed, can be overridden adapter speed 1000 # reset configuration has TRST and SRST support reset_config trst_and_srst srst_push_pull # need at least 100ms delay after SRST release for JTAG adapter srst delay 100 # source the target file source [find target/imx7.cfg] # import mrw proc source [find mem_helper.tcl] # function to disable the on-chip watchdog proc imx7_disable_wdog { } { # echo "disable watchdog power-down counter" mwh phys 0x30280008 0x00 } proc imx7_uart_dbgconf { } { # disable response to debug_req signal for uart1 mww phys 0x308600b4 0x0a60 } proc check_bits_set_32 { addr mask } { while { [expr {[mrw $addr] & $mask} == 0] } { } } proc apply_dcd { } { # echo "apply dcd" mww phys 0x30340004 0x4F400005 # Clear then set bit30 to ensure exit from DDR retention mww phys 0x30360388 0x40000000 mww phys 0x30360384 0x40000000 mww phys 0x30391000 0x00000002 mww phys 0x307a0000 0x01040001 mww phys 0x307a01a0 0x80400003 mww phys 0x307a01a4 0x00100020 mww phys 0x307a01a8 0x80100004 mww phys 0x307a0064 0x00400046 mww phys 0x307a0490 0x00000001 mww phys 0x307a00d0 0x00020083 mww phys 0x307a00d4 0x00690000 mww phys 0x307a00dc 0x09300004 mww phys 0x307a00e0 0x04080000 mww phys 0x307a00e4 0x00100004 mww phys 0x307a00f4 0x0000033f mww phys 0x307a0100 0x09081109 mww phys 0x307a0104 0x0007020d mww phys 0x307a0108 0x03040407 mww phys 0x307a010c 0x00002006 mww phys 0x307a0110 0x04020205 mww phys 0x307a0114 0x03030202 mww phys 0x307a0120 0x00000803 mww phys 0x307a0180 0x00800020 mww phys 0x307a0184 0x02000100 mww phys 0x307a0190 0x02098204 mww phys 0x307a0194 0x00030303 mww phys 0x307a0200 0x00000016 mww phys 0x307a0204 0x00171717 mww phys 0x307a0214 0x04040404 mww phys 0x307a0218 0x0f040404 mww phys 0x307a0240 0x06000604 mww phys 0x307a0244 0x00000001 mww phys 0x30391000 0x00000000 mww phys 0x30790000 0x17420f40 mww phys 0x30790004 0x10210100 mww phys 0x30790010 0x00060807 mww phys 0x307900b0 0x1010007e mww phys 0x3079009c 0x00000d6e mww phys 0x30790020 0x08080808 mww phys 0x30790030 0x08080808 mww phys 0x30790050 0x01000010 mww phys 0x30790050 0x00000010 mww phys 0x307900c0 0x0e407304 mww phys 0x307900c0 0x0e447304 mww phys 0x307900c0 0x0e447306 check_bits_set_32 0x307900c4 0x1 mww phys 0x307900c0 0x0e447304 mww phys 0x307900c0 0x0e407304 mww phys 0x30384130 0x00000000 mww phys 0x30340020 0x00000178 mww phys 0x30384130 0x00000002 mww phys 0x30790018 0x0000000f check_bits_set_32 0x307a0004 0x1 } # disable internal reset-assert handling to # allow reset-init to work $_TARGETNAME.0 configure -event reset-assert "" $_TARGETNAME.1 configure -event reset-assert "" $_TARGETNAME_2 configure -event reset-assert "" $_TARGETNAME.0 configure -event reset-init { global _CHIPNAME imx7_disable_wdog imx7_uart_dbgconf apply_dcd $_CHIPNAME.dap memaccess 0 } target smp $_TARGETNAME.0 $_TARGETNAME.1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/nxp_lpc-link2.cfg ================================================ # # NXP LPC-Link2 # # http://www.nxp.com/board/OM13054.html # https://www.lpcware.com/lpclink2 # http://embeddedartists.com/products/lpcxpresso/lpclink2.php # source [find target/lpc4370.cfg] # W25Q80BVSSIG w/ 1 MB flash flash bank SPIFI_FLASH lpcspifi 0x14000000 0 0 0 $_CHIPNAME.m4 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/nxp_mcimx8m-evk.cfg ================================================ # # configuration file for NXP MC-IMX8M-EVK # # only JTAG supported transport select jtag # set a safe JTAG clock speed, can be overridden adapter speed 1000 # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive adapter srst delay 70 # board has an i.MX8MQ with 4 Cortex-A53 cores set CHIPNAME imx8mq set CHIPCORES 4 # source SoC configuration source [find target/imx8m.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/nxp_rdb-ls1046a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LS1046ARDB (Reference Design Board) # This is for the "console" USB port on the front panel # You must ensure that SW4-7 is in the "off" position # NXP K20 # The firmware implements the old CMSIS-DAP v1 USB HID interface # You must pass --enable-cmsis-dap to ./configure to enable it source [find interface/cmsis-dap.cfg] transport select jtag reset_config srst_only source [find target/ls1046a.cfg] # The adapter can't handle 10MHz adapter speed 5000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/nxp_rdb-ls1088a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LS1088ARDB (Reference Design Board) # This is for the "main" JTAG connector J55 transport select jtag reset_config srst_only # To access the CPLD, populate J48 and add `-c 'set CWTAP 1'` to your command # line. At the time of this writing, programming is unsupported. if { [info exists CWTAP] } { source [find cpld/altera-epm240.cfg] } else { source [find target/ls1088a.cfg] } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/olimex_LPC2378STK.cfg ================================================ ##################################################### # Olimex LPC2378STK eval board # # http://olimex.com/dev/lpc-2378stk.html # # Author: Sten, debian@sansys-electronic.com ##################################################### # source [find target/lpc2378.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/olimex_lpc_h2148.cfg ================================================ # # Olimex LPC-H2148 eval board # # http://www.olimex.com/dev/lpc-h2148.html # source [find target/lpc2148.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/olimex_sam7_ex256.cfg ================================================ # Olimex SAM7-EX256 has a single Atmel at91sam7ex256 on it. source [find target/at91sam7x256.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/olimex_sam7_la2.cfg ================================================ source [find target/at91sam7a2.cfg] # delays needed to get stable reads of cpu state jtag_ntrst_delay 10 adapter srst delay 200 # board uses pullup and connects only srst reset_config srst_open_drain # srst is connected to NRESET of CPU and fully resets everything... reset_config srst_only srst_pulls_trst adapter speed 1 $_TARGETNAME configure -event reset-start { adapter speed 1 } $_TARGETNAME configure -event reset-init { # init script from http://www.mikrocontroller.net/topic/107462 # AT91SAM7A2 # AMC (advanced memory controller) echo "setting up AMC" # AMC_CS0 - FLASH 1MB (0x40000000-0x400FFFFF) + DM9000E (0x40100000) mww 0xFFE00000 0x40003EBD # AMC_CS1 - RAM low 2MB (0x40400000-0x405FFFFF) mww 0xFFE00004 0x404030A9 # AMC_CS2 - RAM high 2MB (0x40800000-0x405FFFFF) #mww 0xFFE00008 0x404030A9 # changed to 0x40_8_ mww 0xFFE00008 0x408030A9 # AMC_MCR mww 0xFFE00024 0x00000004 # AMC_RCR force remap mww 0xFFE00020 0x00000001 echo "set up AMC" sleep 100 # the following base addresses from the original script did not correspond to those from datasheet # changed bases from 0xFF000000 to 0xFFF00000 # disable watchdog, to prevent unwanted resets mww 0xFFFA0068 0x00000000 echo "disabled watchdog" sleep 50 # disable PLL mww 0xFFFEC004 0x18070004 # PLL = 10 ==> Coreclock = 6Mhz*10/2 = 30 Mhz mww 0xFFFEC010 0x762D800A # enable PLL mww 0xFFFEC000 0x23050004 echo "set up pll" sleep 100 adapter speed 5000 } $_TARGETNAME arm7_9 dcc_downloads enable $_TARGETNAME arm7_9 fast_memory_access enable # remap: ram at 0, flash at 0x40000000, like reset-init above does $_TARGETNAME configure -work-area-phys 0x00000000 -work-area-size 0x4000 -work-area-backup 1 flash bank onboard.flash cfi 0x40000000 0x00100000 2 2 at91sam7a2.cpu # boot: ram at 0x300000, flash at 0x0, useful if board is in funny configuration #$_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x4000 -work-area-backup 1 #flash bank onboard1.flash cfi 0x00000000 0x00100000 2 2 at91sam7a2.cpu ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/olimex_sam9_l9260.cfg ================================================ ################################################################################ # Olimex SAM9-L9260 Development Board # # http://www.olimex.com/dev/sam9-L9260.html # # Atmel AT91SAM9260 : PLLA = 198.656 MHz, MCK = 99.328 MHz # PMC configured for external 18.432 MHz crystal # # 32-bit SDRAM : 2 x Samsung K4S561632J-UC75, 4M x 16Bit x 4 Banks # 8-bit NAND Flash : 1 x Samsung K9F4G08U0M, 512M x 8Bit # Dataflash : 1 x Atmel AT45DB161D, 16Mbit # ################################################################################ source [find target/at91sam9260.cfg] # NTRST_E jumper is enabled by default, so we don't need to override the reset # config. #reset_config srst_only $_TARGETNAME configure -event reset-start { # At reset, CPU runs at 32.768 kHz. JTAG frequency must be 6 times slower if # RCLK is not supported. jtag_rclk 5 halt # RSTC_MR : enable user reset, reset length is 64 slow clock cycles. MMU may # be enabled... use physical address. mww phys 0xfffffd08 0xa5000501 } $_TARGETNAME configure -event reset-init { mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog ## # Clock configuration for 99.328 MHz main clock. ## echo "Setting up clock" mww 0xfffffc20 0x00004001 ;# CKGR_MOR : enable main oscillator, 512 slow clock startup sleep 20 ;# wait 20 ms (need 15.6 ms for startup) mww 0xfffffc30 0x00000001 ;# PMC_MCKR : switch to main oscillator (18.432 MHz) sleep 10 ;# wait 10 ms mww 0xfffffc28 0x2060bf09 ;# CKGR_PLLAR : 18.432 MHz / 9 * 97 = 198.656 MHz, 63 slow clock startup sleep 20 ;# wait 20 ms (need 1.9 ms for startup) mww 0xfffffc30 0x00000101 ;# PMC_MCKR : no scale on proc clock, master is proc / 2 sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000102 ;# PMC_MCKR : switch to PLLA (99.328 MHz) # Increase JTAG speed to 6 MHz if RCLK is not supported. jtag_rclk 6000 arm7_9 dcc_downloads enable ;# Enable faster DCC downloads. ## # SDRAM configuration for 2 x Samsung K4S561632J-UC75, 4M x 16Bit x 4 Banks. ## echo "Configuring SDRAM" mww 0xfffff870 0xffff0000 ;# PIOC_ASR : select peripheral function for D15..D31 mww 0xfffff804 0xffff0000 ;# PIOC_PDR : disable PIO function for D15..D31 mww 0xffffef1c 0x00010002 ;# EBI_CSA : assign EBI CS1 to SDRAM, VDDIOMSEL set for +3V3 memory mww 0xffffea08 0x85237259 ;# SDRAMC_CR : configure SDRAM for Samsung chips mww 0xffffea00 0x1 ;# SDRAMC_MR : issue NOP command mww 0x20000000 0 mww 0xffffea00 0x2 ;# SDRAMC_MR : issue an 'All Banks Precharge' command mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue 8 x 'Auto-Refresh' command mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x3 ;# SDRAMC_MR : issue a 'Load Mode Register' command mww 0x20000000 0 mww 0xffffea00 0x0 ;# SDRAMC_MR : normal mode mww 0x20000000 0 mww 0xffffea04 0x2b6 ;# SDRAMC_TR : set refresh timer count to 7 us ## # NAND Flash Configuration for 1 x Samsung K9F4G08U0M, 512M x 8Bit. ## echo "Configuring NAND flash" mww 0xfffffc10 0x00000010 ;# PMC_PCER : enable PIOC clock mww 0xfffff800 0x00006000 ;# PIOC_PER : enable PIO function for 13(RDY/~BSY) and 14(~CS) mww 0xfffff810 0x00004000 ;# PIOC_OER : enable output on 14 mww 0xfffff814 0x00002000 ;# PIOC_ODR : disable output on 13 mww 0xfffff830 0x00004000 ;# PIOC_SODR : set 14 to disable NAND mww 0xfffff864 0x00002000 ;# PIOC_PUER : enable pull-up on 13 mww 0xffffef1c 0x0001000A ;# EBI_CSA : assign EBI CS3 to NAND, same settings as before mww 0xffffec30 0x00010001 ;# SMC_SETUP3 : 1 clock cycle setup for NRD and NWE mww 0xffffec34 0x03030303 ;# SMC_PULSE3 : 3 clock cycle pulse for all signals mww 0xffffec38 0x00050005 ;# SMC_CYCLE3 : 5 clock cycle NRD and NWE cycle mww 0xffffec3C 0x00020003 ;# SMC_MODE3 : NRD and NWE control, no NWAIT, 8-bit DBW, # 3 TDF cycles, no optimization mww 0xffffe800 0x00000001 ;# ECC_CR : reset the ECC parity registers mww 0xffffe804 0x00000002 ;# ECC_MR : page size is 2112 words (word is 8 bits) nand probe at91sam9260.flash ## # Dataflash configuration for 1 x Atmel AT45DB161D, 16Mbit ## echo "Setting up dataflash" mww 0xfffff404 0x00000807 ;# PIOA_PDR : disable PIO function for 0(SPI0_MISO), 1(SPI0_MOSI), # 2(SPI0_SPCK), and 11(SPI0_NPCS1) mww 0xfffff470 0x00000007 ;# PIOA_ASR : select peripheral A function for 0, 1, and 2 mww 0xfffff474 0x00000800 ;# PIOA_BSR : select peripheral B function for 11 mww 0xfffffc10 0x00001000 ;# PMC_PCER : enable SPI0 clock mww 0xfffc8000 0x00000080 ;# SPI0_CR : software reset SPI0 mww 0xfffc8000 0x00000080 ;# SPI0_CR : again to be sure mww 0xfffc8004 0x000F0011 ;# SPI0_MR : master mode with nothing selected mww 0xfffc8034 0x011a0302 ;# SPI0_CSR1 : capture on leading edge, 8-bits/tx. 33MHz baud, # 250ns delay before SPCK, 250ns b/n tx mww 0xfffc8004 0x000D0011 ;# SPI0_MR : same config, select NPCS1 mww 0xfffc8000 0x00000001 ;# SPI0_CR : enable SPI0 } nand device at91sam9260.flash at91sam9 at91sam9260.cpu 0x40000000 0xffffe800 at91sam9 cle 0 22 at91sam9 ale 0 21 at91sam9 rdy_busy 0 0xfffff800 13 at91sam9 ce 0 0xfffff800 14 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/olimex_stm32_h103.cfg ================================================ # Olimex STM32-H103 eval board # http://olimex.com/dev/stm32-h103.html # Work-area size (RAM size) = 20kB for STM32F103RB device set WORKAREASIZE 0x5000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/olimex_stm32_h107.cfg ================================================ # # Olimex STM32-H107 # # http://olimex.com/dev/stm32-h107.html # # Work-area size (RAM size) = 64kB for STM32F107VC device set WORKAREASIZE 0x10000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/olimex_stm32_h405.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Olimex STM32-H405 eval board # https://www.olimex.com/Products/ARM/ST/STM32-H405/ # Work-area size (RAM size) = 128kB for STM32F405RG device set WORKAREASIZE 0x20000 source [find target/stm32f4x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/olimex_stm32_p107.cfg ================================================ # # Olimex STM32-P107 # # http://olimex.com/dev/stm32-p107.html # # Work-area size (RAM size) = 64kB for STM32F107VC device set WORKAREASIZE 0x10000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/omap2420_h4.cfg ================================================ # OMAP2420 SDP board ("H4") source [find target/omap2420.cfg] # NOTE: this assumes you're *NOT* using a TI-14 connector. reset_config trst_and_srst separate # Board configs can vary a *LOT* ... parts, jumpers, etc. # This GP board boots from cs0 using NOR (2x32M), and also # has 64M NAND on cs6. flash bank h4.u10 cfi 0x04000000 0x02000000 2 2 $_TARGETNAME flash bank h4.u11 cfi 0x06000000 0x02000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/openrd.cfg ================================================ # Marvell OpenRD source [find interface/ftdi/openrd.cfg] source [find target/feroceon.cfg] adapter speed 2000 $_TARGETNAME configure \ -work-area-phys 0x10000000 \ -work-area-size 65536 \ -work-area-backup 0 arm7_9 dcc_downloads enable # this assumes the hardware default peripherals location before u-Boot moves it set _FLASHNAME $_CHIPNAME.flash nand device $_FLASHNAME orion 0 0xd8000000 proc openrd_init { } { # We need to assert DBGRQ while holding nSRST down. # However DBGACK will be set only when nSRST is released. # Furthermore, the JTAG interface doesn't respond at all when # the CPU is in the WFI (wait for interrupts) state, so it is # possible that initial tap examination failed. So let's # re-examine the target again here when nSRST is asserted which # should then succeed. adapter assert srst feroceon.cpu arp_examine halt 0 adapter deassert srst wait_halt arm mcr 15 0 0 1 0 0x00052078 mww 0xD0001400 0x43000C30 ;# DDR SDRAM Configuration Register mww 0xD0001404 0x37543000 ;# Dunit Control Low Register mww 0xD0001408 0x22125451 ;# DDR SDRAM Timing (Low) Register mww 0xD000140C 0x00000A33 ;# DDR SDRAM Timing (High) Register mww 0xD0001410 0x000000CC ;# DDR SDRAM Address Control Register mww 0xD0001414 0x00000000 ;# DDR SDRAM Open Pages Control Register mww 0xD0001418 0x00000000 ;# DDR SDRAM Operation Register mww 0xD000141C 0x00000C52 ;# DDR SDRAM Mode Register mww 0xD0001420 0x00000004 ;# DDR SDRAM Extended Mode Register mww 0xD0001424 0x0000F17F ;# Dunit Control High Register mww 0xD0001428 0x00085520 ;# Dunit Control High Register mww 0xD000147c 0x00008552 ;# Dunit Control High Register mww 0xD0001504 0x0FFFFFF1 ;# CS0n Size Register mww 0xD0001508 0x10000000 ;# CS1n Base Register mww 0xD000150C 0x0FFFFFF5 ;# CS1n Size Register mww 0xD0001514 0x00000000 ;# CS2n Size Register mww 0xD000151C 0x00000000 ;# CS3n Size Register mww 0xD0001494 0x00120012 ;# DDR2 SDRAM ODT Control (Low) Register mww 0xD0001498 0x00000000 ;# DDR2 SDRAM ODT Control (High) REgister mww 0xD000149C 0x0000E40F ;# DDR2 Dunit ODT Control Register mww 0xD0001480 0x00000001 ;# DDR SDRAM Initialization Control Register mww 0xD0020204 0x00000000 ;# Main IRQ Interrupt Mask Register mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0010000 0x01111111 ;# MPP 0 to 7 mww 0xD0010004 0x11113322 ;# MPP 8 to 15 mww 0xD0010008 0x00001111 ;# MPP 16 to 23 mww 0xD0010418 0x003E07CF ;# NAND Read Parameters REgister mww 0xD001041C 0x000F0F0F ;# NAND Write Parameters Register mww 0xD0010470 0x01C7D943 ;# NAND Flash Control Register } proc openrd_reflash_uboot { } { # reflash the u-Boot binary and reboot into it openrd_init nand probe 0 nand erase 0 0x0 0xa0000 nand write 0 uboot.bin 0 oob_softecc_kw resume } proc openrd_load_uboot { } { # load u-Boot into RAM and execute it openrd_init load_image uboot.elf verify_image uboot.elf resume 0x00600000 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/or1k_generic.cfg ================================================ # If you want to use the VJTAG TAP or the XILINX BSCAN, # you must set your FPGA TAP ID here set FPGATAPID 0x020b30dd # Choose your TAP core (VJTAG , MOHOR or XILINX_BSCAN) if { [info exists TAP_TYPE] == 0} { set TAP_TYPE VJTAG } # Set your chip name set CHIPNAME or1200 source [find target/or1k.cfg] # Set the servers polling period to 1ms (needed to JSP Server) poll_period 1 # Set the adapter speed adapter speed 3000 # Enable the target description feature gdb_target_description enable # Add a new register in the cpu register list. This register will be # included in the generated target descriptor file. # format is addreg [name] [address] [feature] [reg_group] addreg rtest 0x1234 org.gnu.gdb.or1k.group0 system # Override default init_reset proc init_reset {mode} { soft_reset_halt resume } # Target initialization init echo "Halting processor" halt foreach name [target names] { set y [$name cget -endian] set z [$name cget -type] puts [format "Chip is %s, Endian: %s, type: %s" \ $name $y $z] } set c_blue "\033\[01;34m" set c_reset "\033\[0m" puts [format "%sTarget ready...%s" $c_blue $c_reset] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/osk5912.cfg ================================================ # http://omap.spectrumdigital.com/osk5912/ source [find target/omap5912.cfg] # NOTE: this assumes you're using the ARM 20-pin ("Multi-ICE") # JTAG connector, and accordingly have J1 connecting pins 1 & 2. # The TI-14 pin needs "trst_only", and J1 connecting 2 & 3. reset_config trst_and_srst separate # NOTE: boards with XOMAP parts wire nSRST to nPWRON_RESET. # That resets everything -- including JTAG and EmbeddedICE. # So they must use "reset_config srst_pulls_trst". # NOTE: an expansion board could add a trace connector ... if # it does, change this appropriately. And reset_config too, # assuming JTAG_DIS reroutes JTAG to that connector. etm config $_TARGETNAME 8 demultiplexed full dummy etm_dummy config $_TARGETNAME # standard boards populate two 16 MB chips, but manufacturing # options or an expansion board could change this config. flash bank osk.u1 cfi 0x00000000 0x01000000 2 2 $_TARGETNAME flash bank osk.u2 cfi 0x01000000 0x01000000 2 2 $_TARGETNAME proc osk5912_init {} { omap5912_reset # detect flash flash probe 0 flash probe 1 } $_TARGETNAME configure -event reset-init { osk5912_init } arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/phone_se_j100i.cfg ================================================ # # Sony Ericsson J100I Phone # # more information can be found on # http://bb.osmocom.org/trac/wiki/SonyEricssonJ100i # source [find target/ti_calypso.cfg] # external flash set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x400000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/phytec_lpc3250.cfg ================================================ source [find target/lpc3250.cfg] adapter srst delay 200 jtag_ntrst_delay 1 adapter speed 200 reset_config trst_and_srst separate arm7_9 dcc_downloads enable $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-start { arm7_9 fast_memory_access disable adapter speed 200 } $_TARGETNAME configure -event reset-end { adapter speed 6000 arm7_9 fast_memory_access enable } $_TARGETNAME configure -event reset-init { phytec_lpc3250_init } # Bare-bones initialization of core clocks and SDRAM proc phytec_lpc3250_init { } { # Set clock dividers # ARMCLK = 266.5 MHz # HCLK = 133.25 MHz # PERIPHCLK = 13.325 MHz mww 0x400040BC 0 mww 0x40004050 0x140 mww 0x40004040 0x4D mww 0x40004058 0x16250 # Init PLLs mww 0x40004044 0x006 sleep 1 busy mww 0x40004044 0x106 sleep 1 busy mww 0x40004044 0x006 sleep 1 busy mww 0x40004048 0x2 # Init SDRAM with 133 MHz timings mww 0x40028134 0x00FFFFFF mww 0x4002802C 0x00000008 mww 0x31080000 1 mww 0x31080008 0 mww 0x40004068 0x1C000 mww 0x31080028 0x11 mww 0x31080400 0 mww 0x31080440 0 mww 0x31080460 0 mww 0x31080480 0 # Delays mww 0x31080030 1 mww 0x31080034 6 mww 0x31080038 10 mww 0x31080044 1 mww 0x31080048 9 mww 0x3108004C 12 mww 0x31080050 10 mww 0x31080054 1 mww 0x31080058 1 mww 0x3108005C 0 mww 0x31080100 0x5680 mww 0x31080104 0x302 # Init sequence mww 0x31080020 0x193 sleep 1 busy mww 0x31080024 1 mww 0x31080020 0x113 sleep 1 busy mww 0x31080020 0x013 sleep 1 busy mww 0x31080024 65 mww 0x31080020 0x093 mdw 0x80020000 mww 0x31080020 0x013 # SYS_CTRL remapping mww 0x40004014 1 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/pic-p32mx.cfg ================================================ # The Olimex PIC-P32MX has a PIC32MX set CPUTAPID 0x40916053 source [find target/pic32mx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/pico-debug.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # pico-debug is a virtual CMSIS-DAP debug adapter # it runs on the very same RP2040 target being debugged without additional hardware # https://github.com/majbthrd/pico-debug source [find interface/cmsis-dap.cfg] adapter speed 4000 set CHIPNAME rp2040 source [find target/rp2040-core0.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/pipistrello.cfg ================================================ # http://pipistrello.saanlima.com/ source [find interface/ftdi/pipistrello.cfg] source [find cpld/xilinx-xc6s.cfg] source [find cpld/jtagspi.cfg] # example command to write bitstream, soft-cpu bios and runtime: # openocd -f board/pipistrello.cfg -c "init;\ # jtagspi_init 0 bscan_spi_xc6slx45.bit;\ # jtagspi_program bitstream-pistrello.bin 0;\ # jtagspi_program bios.bin 0x170000;\ # jtagspi_program runtime.fbi 0x180000;\ # xc6s_program xc6s.tap;\ # exit" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/propox_mmnet1001.cfg ================================================ ## Chip: set CHIPNAME at91sam9260 set CPUTAPID 0x0792603f set ENDIAN little source [find target/at91sam9260.cfg] $_TARGETNAME configure -event reset-init {at91sam_init} proc at91sam_init { } { # at reset chip runs at 32 kHz => 1/8 * 32 kHz = 4 kHz jtag_rclk 4 # Enable user reset and disable watchdog mww 0xfffffd08 0xa5000501 ;# RSTC_MR : enable user reset mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog # Oscillator setup mww 0xfffffc20 0x00004001 ;# CKGR_MOR : enable the main oscillator (18.432 MHz) sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000001 ;# PMC_MCKR : switch to main oscillator sleep 10 ;# wait 10 ms # now we are running at 18.432 MHz kHz => 1/8 * 18.432 MHz = 2.304 MHz jtag_rclk 2000 mww 0xfffffc28 0x2060bf09 ;# CKGR_PLLAR: Set PLLA Register for 198,656MHz sleep 20 ;# wait 20 ms mww 0xfffffc2c 0x207c3f0c ;# CKGR_PLLBR: Set PLLB Register for USB usage (USB_CLK = 48 MHz) sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000101 ;# PMC_MCKR : Select prescaler sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000102 ;# PMC_MCKR : Clock from PLLA is selected sleep 10 ;# wait 10 ms # now we are running at 198.656 MHz kHz => full speed jtag jtag_rclk 30000 arm7_9 dcc_downloads enable ;# Enable faster DCC downloads # Configure PIO Controller for SDRAM data-lines D16-D31 # PC16-PC31 = Peripheral A: D16-D32 mww 0xfffff844 0xffff0000 ;# Interrupt Disable mww 0xfffff854 0xffff0000 ;# Multi-Drive Disable mww 0xfffff860 0xffff0000 ;# Pull-Up Disable mww 0xfffff870 0xffff0000 ;# PIO_ASR : Select peripheral A function for D15..D31 mww 0xfffff804 0xffff0000 ;# PIO_PDR : Disable PIO function for D15..D31 (Peripheral function enable) mww 0xfffffc10 0x00000010 ;# Enable PIO-C Clock in PMC (PID=4) # SD-Ram setup mww 0xffffef1c 0x2 ;# EBI_CSA : Assign EBI Chip Select 1 to SDRAM mww 0xffffea08 0x85227259 ;# SDRAMC_CR : Configure SDRAM (IS42S32160A: 4M Words x 32 Bits x 4 Banks (512-Mbit)) mww 0xffffea00 0x1 ;# SDRAMC_MR : issue a NOP command mww 0x20000000 0 mww 0xffffea00 0x2 ;# SDRAMC_MR : issue an 'All Banks Precharge' command mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (1st) mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (2nd) mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (3th) mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (4th) mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (5th) mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (6th) mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (7th) mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (8th) mww 0x20000000 0 mww 0xffffea00 0x3 ;# SDRAMC_MR : issue a 'Load Mode Register' command mww 0x20000000 0 mww 0xffffea00 0x0 ;# SDRAMC_MR : Normal Mode mww 0x20000000 0 mww 0xFFFFEA04 0x30d ;# SDRAM Refresh Time Register # datasheet: 8k refresh cycles / 64 ms # MCLK / (8*1024 / 64e-3) = 100e6 / 128000 = 781 = 0x30d } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/pxa255_sst.cfg ================================================ # A PXA255 test board with SST 39LF400A flash # # At reset the memory map is as follows. Note that # the memory map changes later on as the application # starts... # # RAM at 0x4000000 # Flash at 0x00000000 # source [find target/pxa255.cfg] # Target name is set by above $_TARGETNAME configure -work-area-phys 0x4000000 -work-area-size 0x4000 -work-area-backup 0 # flash bank [options] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x80000 2 2 $_TARGETNAME jedec_probe proc pxa255_sst_init {} { xscale cp15 15 0x00002001 ;#Enable CP0 and CP13 access # # setup GPIO # mww 0x40E00018 0x00008000 ;#CPSR0 sleep 20 mww 0x40E0001C 0x00000002 ;#GPSR1 sleep 20 mww 0x40E00020 0x00000008 ;#GPSR2 sleep 20 mww 0x40E0000C 0x00008000 ;#GPDR0 sleep 20 mww 0x40E00054 0x80000000 ;#GAFR0_L sleep 20 mww 0x40E00058 0x00188010 ;#GAFR0_H sleep 20 mww 0x40E0005C 0x60908018 ;#GAFR1_L sleep 20 mww 0x40E0000C 0x0280E000 ;#GPDR0 sleep 20 mww 0x40E00010 0x821C88B2 ;#GPDR1 sleep 20 mww 0x40E00014 0x000F03DB ;#GPDR2 sleep 20 mww 0x40E00000 0x000F03DB ;#GPLR0 sleep 20 mww 0x40F00004 0x00000020 ;#PSSR sleep 20 # # setup memory controller # mww 0x48000008 0x01111998 ;#MSC0 sleep 20 mww 0x48000010 0x00047ff0 ;#MSC2 sleep 20 mww 0x48000014 0x00000000 ;#MECR sleep 20 mww 0x48000028 0x00010504 ;#MCMEM0 sleep 20 mww 0x4800002C 0x00010504 ;#MCMEM1 sleep 20 mww 0x48000030 0x00010504 ;#MCATT0 sleep 20 mww 0x48000034 0x00010504 ;#MCATT1 sleep 20 mww 0x48000038 0x00004715 ;#MCIO0 sleep 20 mww 0x4800003C 0x00004715 ;#MCIO1 sleep 20 # mww 0x48000004 0x03CA4018 ;#MDREF sleep 20 mww 0x48000004 0x004B4018 ;#MDREF sleep 20 mww 0x48000004 0x000B4018 ;#MDREF sleep 20 mww 0x48000004 0x000BC018 ;#MDREF sleep 20 mww 0x48000000 0x00001AC8 ;#MDCNFG sleep 20 sleep 20 mww 0x48000000 0x00001AC9 ;#MDCNFG sleep 20 mww 0x48000040 0x00000000 ;#MDMRS sleep 20 } $_TARGETNAME configure -event reset-init {pxa255_sst_init} reset_config trst_and_srst adapter srst delay 200 jtag_ntrst_delay 200 #xscale debug_handler 0 0xFFFF0800 ;# debug handler base address ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/quark_d2000_refboard.cfg ================================================ # Intel Quark microcontroller D2000 Reference Board (web search for doc num 333582) # the board has an onboard FTDI FT232H chip adapter driver ftdi ftdi vid_pid 0x0403 0x6014 ftdi channel 0 ftdi layout_init 0x0000 0x030b ftdi layout_signal nTRST -data 0x0100 -noe 0x0100 source [find target/quark_d20xx.cfg] adapter speed 1000 reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/quark_x10xx_board.cfg ================================================ # There are many Quark boards that can host the quark_x10xx SoC # Galileo is an example board source [find target/quark_x10xx.cfg] #default frequency but this can be adjusted at runtime adapter speed 4000 reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/quicklogic_quickfeather.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # QuickLogic EOS S3 QuickFeather # https://www.quicklogic.com/products/eos-s3/quickfeather-development-kit/ source [find target/eos_s3.cfg] reset_config srst_only transport select swd ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/radiona_ulx3s.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Radiona ULX3S # https://radiona.org/ulx3s/ # Currently there are following board variants: # CS-ULX3S-01 - LFE5U 12F # CS-ULX3S-02 - LFE5U 45F # CS-ULX3S-03 - LFE5U 85F # # two JTAG interfaces: # - US1, micro USB port connected to FT231XQ # This interface should be used with following config: # interface/ft232r/radiona_ulx3s.cfg # - J4, 6 pin connector # # Both of this interfaces share the JTAG lines (TDI, TMS, TCK, TDO) between # Lattice ECP5 FPGA chip and ESP32 WiFi controller. # Note: TRST_N of the ESP32 is pulled up by default and can be pulled down over # J3 interface. # See schematics for more information: # https://github.com/emard/ulx3s/blob/master/doc/schematics_v308.pdf # https://github.com/emard/ulx3s/blob/master/doc/schematics_v314.pdf # https://github.com/emard/ulx3s/blob/master/doc/schematics_v315.pdf # https://github.com/emard/ulx3s/blob/master/doc/schematics_v316.pdf source [find interface/ft232r/radiona_ulx3s.cfg] source [find fpga/lattice_ecp5.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/redbee.cfg ================================================ source [find target/mc13224v.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/reflexces_achilles_i-dev_kit_arria10.cfg ================================================ # Achilles Instant-Development Kit Arria 10 SoC SoM # https://www.reflexces.com/products-solutions/achilles-instant-development-kit-arria-10-soc-som # if { [info exists USE_EXTERNAL_DEBUGGER] } { echo "Using external debugger" } else { source [find interface/altera-usb-blaster2.cfg] usb_blaster device_desc "Arria10 IDK" } source [find fpga/altera-10m50.cfg] source [find target/altera_fpgasoc_arria10.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/renesas_dk-s7g2.cfg ================================================ # # Renesas Synergy DK-S7G2 # source [find interface/jlink.cfg] transport select swd # XXX 19-pin SWD+TRACE connector also available # Synergy R7FS7G27H2A01CBD source [find target/renesas_s7g2.cfg] # 32 MB QSPI flash (Micron N25Q256A13EF840E) ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/renesas_falcon.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas R-Car V3U Falcon Board Config # The Falcon board comes with either an V3U SOC. echo "\nFalcon:" if { ![info exists SOC] } { set SOC V3U } source [find target/renesas_rcar_gen3.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/renesas_gr_peach.cfg ================================================ # Renesas RZ/A1H GR-Peach board reset_config srst_only source [find target/renesas_r7s72100.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/renesas_porter.cfg ================================================ # Renesas R-Car M2 Evaluation Board set SOC M2 source [find target/renesas_rcar_gen2.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/renesas_salvator-xs.cfg ================================================ # Renesas R-Car Gen3 Salvator-X(S) Board Config # The Salvator-X(S) boards come with either an H3, M3W, or M3N SOC. echo "\nSalvator-X(S):" if { ![info exists SOC] } { set SOC H3 } source [find target/renesas_rcar_gen3.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/renesas_silk.cfg ================================================ # Renesas R-Car E2 Evaluation Board set SOC E2 source [find target/renesas_rcar_gen2.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/renesas_stout.cfg ================================================ # Renesas R-Car H2 Evaluation Board set SOC H2 source [find target/renesas_rcar_gen2.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/rigado_bmd300_ek.cfg ================================================ # # Rigado BMD-300 Evaluation Kit # # https://www.rigado.com/products/modules/bmd-300/ # source [find interface/jlink.cfg] transport select swd adapter speed 1000 source [find target/nrf52.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/rpi3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is the Raspberry Pi 3 board with BCM2837 chip # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837/README.md # # Enable JTAG GPIO on Raspberry Pi boards # https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md source [find target/bcm2837.cfg] transport select jtag # Raspberry Pi boards only expose Test Reset (TRST) pin, no System Reset (SRST) reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/rpi4b.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is the Raspberry Pi 4 model B board with BCM2711 chip # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/README.md # # Enable JTAG GPIO on Raspberry Pi boards # https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md source [find target/bcm2711.cfg] transport select jtag # Raspberry Pi boards only expose Test Reset (TRST) pin, no System Reset (SRST) reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/rsc-w910.cfg ================================================ # Avalue RSC-W8910 sbc # http://www.avalue.com.tw/products/RSC-W910.cfm # 2MB NOR Flash # 64MB SDRAM # 128MB NAND Flash # Based on Nuvoton nuc910 source [find target/nuc910.cfg] # # reset only behaves correctly if we use srst_pulls_trst # reset_config trst_and_srst srst_pulls_trst adapter speed 1000 adapter srst delay 100 jtag_ntrst_delay 100 $_TARGETNAME configure -work-area-phys 0x00000000 -work-area-size 0x04000000 -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x20000000 0x00200000 2 2 $_TARGETNAME set _NANDNAME $_CHIPNAME.nand nand device $_NANDNAME nuc910 $_TARGETNAME # # Target events # $_TARGETNAME configure -event reset-start {adapter speed 1000} $_TARGETNAME configure -event reset-init { # switch on PLL for 200MHz operation # running from 15MHz input clock mww 0xB0000200 0x00000030 ;# CLKEN mww 0xB0000204 0x00000f3c ;# CLKSEL mww 0xB0000208 0x05007000 ;# CLKDIV mww 0xB000020C 0x00004f24 ;# PLLCON0 mww 0xB0000210 0x00002b63 ;# PLLCON1 mww 0xB000000C 0x08817fa6 ;# MFSEL sleep 10 # we are now running @ 200MHz # enable all openocd speed tweaks arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable adapter speed 15000 # map nor flash to 0x20000000 # map sdram to 0x00000000 mww 0xb0001000 0x000530c1 ;# EBICON mww 0xb0001004 0x40030084 ;# ROMCON mww 0xb0001008 0x000010ee ;# SDCONF0 mww 0xb000100C 0x00000000 ;# SDCONF1 mww 0xb0001010 0x0000015b ;# SDTIME0 mww 0xb0001014 0x0000015b ;# SDTIME1 mww 0xb0001018 0x00000000 ;# EXT0CON mww 0xb000101C 0x00000000 ;# EXT1CON mww 0xb0001020 0x00000000 ;# EXT2CON mww 0xb0001024 0x00000000 ;# EXT3CON mww 0xb000102c 0x00ff0048 ;# CKSKEW } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/sayma_amc.cfg ================================================ # Sayma AMC is an FPGA board for the µTCA AMC format # The board is open hardware (CERN OHL) and the gateware and software # running on it are open source (ARTIQ, LGPLv3+). # # https://github.com/m-labs/sinara/wiki/Sayma # # It contains a Xilinx Kintex Ultrascale 040 FPGA (xcku040). # There is a SCANSTA112SM JTAG router on the board which is configured to # automatically add devices to the JTAG svcan chain when they are added. # Sayma AMC is usually combined with Sayma RTM (rear transition module) # which features an Artix 7 FPGA. adapter driver ftdi ftdi device_desc "Quad RS232-HS" ftdi vid_pid 0x0403 0x6011 ftdi channel 0 # Use this to distinguish multiple boards by topology #adapter usb location 5:1 # sampling on falling edge generally seems to work and accelerates things but # is not fully tested #ftdi tdo_sample_edge falling # EN_USB_JTAG on ADBUS7: out, high # USB_nTRST on ADBUS4: out, high, but R46 is DNP ftdi layout_init 0x0098 0x008b #ftdi layout_signal EN_USB -data 0x0080 #ftdi layout_signal nTRST -data 0x0010 reset_config none adapter speed 5000 transport select jtag # Add the RTM Artix to the chain. Note that this changes the PLD numbering. # Unfortunately openocd TAPs can't be disabled after they have been added and # before `init`. #source [find cpld/xilinx-xc7.cfg] set CHIP XCKU040 source [find cpld/xilinx-xcu.cfg] set XILINX_USER1 0x02 set XILINX_USER2 0x03 set JTAGSPI_IR $XILINX_USER1 source [find cpld/jtagspi.cfg] flash bank xcu.spi1 jtagspi 0 0 0 0 xcu.proxy $XILINX_USER2 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/sheevaplug.cfg ================================================ # Marvell SheevaPlug source [find interface/ftdi/sheevaplug.cfg] source [find target/feroceon.cfg] adapter speed 2000 $_TARGETNAME configure \ -work-area-phys 0x10000000 \ -work-area-size 65536 \ -work-area-backup 0 arm7_9 dcc_downloads enable # this assumes the hardware default peripherals location before u-Boot moves it set _FLASHNAME $_CHIPNAME.flash nand device $_FLASHNAME orion 0 0xd8000000 proc sheevaplug_init { } { # We need to assert DBGRQ while holding nSRST down. # However DBGACK will be set only when nSRST is released. # Furthermore, the JTAG interface doesn't respond at all when # the CPU is in the WFI (wait for interrupts) state, so it is # possible that initial tap examination failed. So let's # re-examine the target again here when nSRST is asserted which # should then succeed. adapter assert srst feroceon.cpu arp_examine halt 0 adapter deassert srst wait_halt arm mcr 15 0 0 1 0 0x00052078 mww 0xD0001400 0x43000C30 ;# DDR SDRAM Configuration Register mww 0xD0001404 0x39543000 ;# Dunit Control Low Register mww 0xD0001408 0x22125451 ;# DDR SDRAM Timing (Low) Register mww 0xD000140C 0x00000833 ;# DDR SDRAM Timing (High) Register mww 0xD0001410 0x000000CC ;# DDR SDRAM Address Control Register mww 0xD0001414 0x00000000 ;# DDR SDRAM Open Pages Control Register mww 0xD0001418 0x00000000 ;# DDR SDRAM Operation Register mww 0xD000141C 0x00000C52 ;# DDR SDRAM Mode Register mww 0xD0001420 0x00000042 ;# DDR SDRAM Extended Mode Register mww 0xD0001424 0x0000F17F ;# Dunit Control High Register mww 0xD0001428 0x00085520 ;# Dunit Control High Register mww 0xD000147c 0x00008552 ;# Dunit Control High Register mww 0xD0001504 0x0FFFFFF1 ;# CS0n Size Register mww 0xD0001508 0x10000000 ;# CS1n Base Register mww 0xD000150C 0x0FFFFFF5 ;# CS1n Size Register mww 0xD0001514 0x00000000 ;# CS2n Size Register mww 0xD000151C 0x00000000 ;# CS3n Size Register mww 0xD0001494 0x003C0000 ;# DDR2 SDRAM ODT Control (Low) Register mww 0xD0001498 0x00000000 ;# DDR2 SDRAM ODT Control (High) REgister mww 0xD000149C 0x0000F80F ;# DDR2 Dunit ODT Control Register mww 0xD0001480 0x00000001 ;# DDR SDRAM Initialization Control Register mww 0xD0020204 0x00000000 ;# Main IRQ Interrupt Mask Register mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0010000 0x01111111 ;# MPP 0 to 7 mww 0xD0010004 0x11113322 ;# MPP 8 to 15 mww 0xD0010008 0x00001111 ;# MPP 16 to 23 mww 0xD0010418 0x003E07CF ;# NAND Read Parameters REgister mww 0xD001041C 0x000F0F0F ;# NAND Write Parameters Register mww 0xD0010470 0x01C7D943 ;# NAND Flash Control Register } proc sheevaplug_reflash_uboot { } { # reflash the u-Boot binary and reboot into it sheevaplug_init nand probe 0 nand erase 0 0x0 0xa0000 nand write 0 uboot.bin 0 oob_softecc_kw resume } proc sheevaplug_reflash_uboot_env { } { # reflash the u-Boot environment variables area sheevaplug_init nand probe 0 nand erase 0 0xa0000 0x40000 nand write 0 uboot-env.bin 0xa0000 oob_softecc_kw resume } proc sheevaplug_load_uboot { } { # load u-Boot into RAM and execute it sheevaplug_init load_image uboot.elf verify_image uboot.elf resume 0x00600000 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/sifive-e31arty.cfg ================================================ # # Be sure you include the speed and interface before this file # Example: # -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e31arty.cfg" set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME $_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 init if {[ info exists pulse_srst]} { ftdi set_signal nSRST 0 ftdi set_signal nSRST z } halt flash protect 0 64 last off echo "Ready for Remote Connections" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/sifive-e51arty.cfg ================================================ # # Be sure you include the speed and interface before this file # Example: # -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e51arty.cfg" set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME $_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 init if {[ info exists pulse_srst]} { ftdi set_signal nSRST 0 ftdi set_signal nSRST z } halt flash protect 0 64 last off echo "Ready for Remote Connections" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/sifive-hifive1-revb.cfg ================================================ adapter speed 4000 adapter driver jlink transport select jtag set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000913 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME $_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 0x4000 -work-area-backup 0 flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME.0 init jlink jtag 3 halt flash protect 0 1 last off echo "Ready for Remote Connections" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/sifive-hifive1.cfg ================================================ adapter speed 10000 adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x001b ftdi layout_signal nSRST -oe 0x0020 -data 0x0020 #Reset Stretcher logic on FE310 is ~1 second long #This doesn't apply if you use # ftdi set_signal, but still good to document #adapter srst delay 1500 set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME init #reset -- This type of reset is not implemented yet if {[ info exists pulse_srst]} { ftdi set_signal nSRST 0 ftdi set_signal nSRST z #Wait for the reset stretcher #It will work without this, but #will incur lots of delays for later commands. sleep 1500 } halt flash protect 0 64 last off ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/smdk6410.cfg ================================================ # Target configuration for the Samsung s3c6410 system on chip # Tested on a SMDK6410 # Processor : ARM1176 # Info: JTAG device found: 0x0032409d (Manufacturer: 0x04e, Part: 0x0324, Version: 0x0) source [find target/samsung_s3c6410.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x00100000 2 2 $_TARGETNAME jedec_probe ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/snps_em_sk.cfg ================================================ # Copyright (C) 2014-2016,2020 Synopsys, Inc. # Anton Kolesov # Didin Evgeniy # # SPDX-License-Identifier: GPL-2.0-or-later # # Synopsys DesignWare ARC EM Starter Kit v2.x # # Configure JTAG cable # EM Starter Kit has built-in FT2232 chip, which is similar to Digilent HS-1. source [find interface/ftdi/digilent-hs1.cfg] # 5MHz seems to work good with all cores that might happen in 2.x adapter speed 5000 # ARCs support only JTAG. transport select jtag # Configure FPGA. This script supports both LX45 and LX150. source [find target/snps_em_sk_fpga.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/snps_em_sk_v1.cfg ================================================ # Copyright (C) 2014-2016,2020 Synopsys, Inc. # Anton Kolesov # Didin Evgeniy # # SPDX-License-Identifier: GPL-2.0-or-later # # Synopsys DesignWare ARC EM Starter Kit v1.0 and v1.1 # # Configure JTAG cable # EM Starter Kit has built-in FT2232 chip, which is similar to Digilent HS-1. source [find interface/ftdi/digilent-hs1.cfg] adapter speed 10000 # ARCs support only JTAG. transport select jtag # Configure FPGA. This script supports both LX45 and LX150. source [find target/snps_em_sk_fpga.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/snps_em_sk_v2.1.cfg ================================================ # Copyright (C) 2014-2016,2020 Synopsys, Inc. # Anton Kolesov # Didin Evgeniy # # SPDX-License-Identifier: GPL-2.0-or-later # # Synopsys DesignWare ARC EM Starter Kit v2.1 # # Configure JTAG cable # EM Starter Kit has built-in FT2232 chip, which is similar to Digilent HS-1. source [find interface/ftdi/digilent-hs1.cfg] # JTAG 10MHz is too fast for EM7D FPU in EM SK 2.1 which has core frequency # 20MHz. 7.5 MHz seems to work fine. adapter speed 7500 # ARCs support only JTAG. transport select jtag # Configure FPGA. This script supports both LX45 and LX150. source [find target/snps_em_sk_fpga.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/snps_em_sk_v2.2.cfg ================================================ # Copyright (C) 2016,2020 Synopsys, Inc. # Anton Kolesov # Didin Evgeniy # # SPDX-License-Identifier: GPL-2.0-or-later # # Synopsys DesignWare ARC EM Starter Kit v2.2 # # Configure JTAG cable # EM Starter Kit has built-in FT2232 chip, which is similar to Digilent HS-1. source [find interface/ftdi/digilent-hs1.cfg] # EM11D reportedly requires 5 MHz. Other cores and board can work faster. adapter speed 5000 # ARCs support only JTAG. transport select jtag # Configure FPGA. This script supports both LX45 and LX150. source [find target/snps_em_sk_fpga.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/snps_hsdk.cfg ================================================ # Copyright (C) 2019, 2020 Synopsys, Inc. # Anton Kolesov # Didin Evgeniy # # SPDX-License-Identifier: GPL-2.0-or-later # # Synopsys DesignWare ARC HSDK Software Development Platform (HS38 cores) # source [find interface/ftdi/snps_sdp.cfg] adapter speed 10000 # ARCs supports only JTAG. transport select jtag # Configure SoC source [find target/snps_hsdk.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/spansion_sk-fm4-176l-s6e2cc.cfg ================================================ # # Spansion SK-FM4-176L-S6E2CC # # # FM3 MB9AF312K # source [find interface/cmsis-dap.cfg] # There's also an unpopulated 10-pin 0.05" pinout. # # FM4 S6E2CCAJ0A w/ 192 KB SRAM0 # set CHIPNAME s6e2cc set CHIPSERIES S6E2CCAJ0A set WORKAREASIZE 0x30000 source [find target/fm4_s6e2cc.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/spansion_sk-fm4-u120-9b560.cfg ================================================ # # Spansion SK-FM4-U120-9B560 # # # FM3 MB9AF312K # # source [find interface/cmsis-dap.cfg] # # FM4 MB9BF568R w/ 64 KB SRAM0 # set CHIPNAME mb9bf568 set CHIPSERIES MB9BF568R set WORKAREASIZE 0x10000 source [find target/fm4_mb9bf.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/spear300evb.cfg ================================================ # Configuration for the ST SPEAr300 Evaluation board # EVALSPEAr300 Rev. 1.0 # http://www.st.com/spear # # Date: 2010-11-27 # Author: Antonio Borneo # The standard board has JTAG SRST not connected. # This script targets such boards using quirky code to bypass the issue. source [find mem_helper.tcl] source [find target/spear3xx.cfg] source [find chip/st/spear/spear3xx_ddr.tcl] source [find chip/st/spear/spear3xx.tcl] arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable # Serial NOR on SMI CS0. 8Mbyte. set _FLASHNAME1 $_CHIPNAME.snor flash bank $_FLASHNAME1 stmsmi 0xf8000000 0 0 0 $_TARGETNAME if { [info exists BOARD_HAS_SRST] } { # Modified board has SRST on JTAG connector reset_config trst_and_srst separate srst_gates_jtag \ trst_push_pull srst_open_drain } else { # Standard board has no SRST on JTAG connector reset_config trst_only separate srst_gates_jtag trst_push_pull source [find chip/st/spear/quirk_no_srst.tcl] } $_TARGETNAME configure -event reset-init { spear300evb_init } proc spear300evb_init {} { reg pc 0xffff0020; # loop forever sp3xx_clock_default sp3xx_common_init sp3xx_ddr_init "mt47h64m16_3_333_cl5_async" sp300_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/spear300evb_mod.cfg ================================================ # Configuration for the ST SPEAr300 Evaluation board # EVALSPEAr300 Rev. 1.0, modified to enable SRST on JTAG connector # http://www.st.com/spear # # List of board modifications to enable SRST, as reported in # ST Application Note (FIXME: add reference). # - Modifications on the top layer: # 1. replace reset chip U4 with a STM6315SDW13F; # - Modifications on the bottom layer: # 2. add 0 ohm resistor R10. It is located close to JTAG connector. # 3. add a 10K ohm pull-up resistor on the reset wire named as # POWERGOOD in the schematic. # # The easier way to do modification 3, is to use a resistor in package # 0603 and solder it between R10 and R54: # - one pad soldered with the pad of R54 connected to 3.3V (this # is the pad of R54 far from JTAG connector J4) # - the other pad soldered with the nearest pad of R10. # # Date: 2011-11-18 # Author: Antonio Borneo # Modified boards has SRST on JTAG connector set BOARD_HAS_SRST 1 source [find board/spear300evb.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/spear310evb20.cfg ================================================ # Configuration for the ST SPEAr310 Evaluation board # EVALSPEAr310 Rev. 2.0 # http://www.st.com/spear # # Date: 2010-08-17 # Author: Antonio Borneo # The standard board has JTAG SRST not connected. # This script targets such boards using quirky code to bypass the issue. # # Check ST Application Note AN3321 on how to fix SRST on # the board, then use the script board/spear310evb20_mod.cfg source [find mem_helper.tcl] source [find target/spear3xx.cfg] source [find chip/st/spear/spear3xx_ddr.tcl] source [find chip/st/spear/spear3xx.tcl] arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable # CFI parallel NOR on EMI CS0. 2x 16bit 8M devices = 16Mbyte. set _FLASHNAME0 $_CHIPNAME.pnor flash bank $_FLASHNAME0 cfi 0x50000000 0x01000000 2 4 $_TARGETNAME # Serial NOR on SMI CS0. 8Mbyte. set _FLASHNAME1 $_CHIPNAME.snor flash bank $_FLASHNAME1 stmsmi 0xf8000000 0 0 0 $_TARGETNAME if { [info exists BOARD_HAS_SRST] } { # Modified board has SRST on JTAG connector reset_config trst_and_srst separate srst_gates_jtag \ trst_push_pull srst_open_drain } else { # Standard board has no SRST on JTAG connector reset_config trst_only separate srst_gates_jtag trst_push_pull source [find chip/st/spear/quirk_no_srst.tcl] } $_TARGETNAME configure -event reset-init { spear310evb20_init } proc spear310evb20_init {} { reg pc 0xffff0020 ;# loop forever sp3xx_clock_default sp3xx_common_init sp3xx_ddr_init "mt47h64m16_3_333_cl5_async" sp310_init sp310_emi_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/spear310evb20_mod.cfg ================================================ # Configuration for the ST SPEAr310 Evaluation board # EVALSPEAr310 Rev. 2.0, modified to enable SRST on JTAG connector # http://www.st.com/spear # # List of board modifications to enable SRST, as reported in # ST Application Note AN3321. # - Modifications on the top layer: # 1. remove R137 and C57, located near the SMII PHY U18; # 2. remove R172 and C75, located near the SMII PHY U19; # 3. remove R207 and C90, located near the SMII PHY U20; # 4. remove C236, located near the SMII PHY U21; # 5. remove U12, located near the JTAG connector; # 6. solder together pins 7, 8 and 9 of U12; # 7. solder together pins 11, 12, 13, 14, 15, 16, 17 and 18 of U12. # - Modifications on the bottom layer: # 8. replace reset chip U11 with a STM6315SDW13F; # 9. add 0 ohm resistor R329. It is located close to JTAG connector. # # Date: 2009-10-31 # Author: Antonio Borneo # Modified boards has SRST on JTAG connector set BOARD_HAS_SRST 1 source [find board/spear310evb20.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/spear320cpu.cfg ================================================ # Configuration for the ST SPEAr320 CPU board # EVAL_SPEAr320CPU Rev. 2.0 # http://www.st.com/spear # # Date: 2011-11-18 # Author: Antonio Borneo # The standard board has JTAG SRST not connected. # This script targets such boards using quirky code to bypass the issue. source [find mem_helper.tcl] source [find target/spear3xx.cfg] source [find chip/st/spear/spear3xx_ddr.tcl] source [find chip/st/spear/spear3xx.tcl] arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable # Serial NOR on SMI CS0. 8Mbyte. set _FLASHNAME1 $_CHIPNAME.snor flash bank $_FLASHNAME1 stmsmi 0xf8000000 0 0 0 $_TARGETNAME if { [info exists BOARD_HAS_SRST] } { # Modified board has SRST on JTAG connector reset_config trst_and_srst separate srst_gates_jtag \ trst_push_pull srst_open_drain } else { # Standard board has no SRST on JTAG connector reset_config trst_only separate srst_gates_jtag trst_push_pull source [find chip/st/spear/quirk_no_srst.tcl] } $_TARGETNAME configure -event reset-init { spear320cpu_init } if { [info exists DDR_CHIPS] } { set _DDR_CHIPS $DDR_CHIPS } else { set _DDR_CHIPS 1 } proc spear320cpu_init {} { global _DDR_CHIPS reg pc 0xffff0020; # loop forever sp3xx_clock_default sp3xx_common_init sp3xx_ddr_init "mt47h64m16_3_333_cl5_async" $_DDR_CHIPS sp320_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/spear320cpu_mod.cfg ================================================ # Configuration for the ST SPEAr320 Evaluation board # EVAL_SPEAr320CPU Rev. 2.0, modified to enable SRST on JTAG connector # http://www.st.com/spear # # List of board modifications to enable SRST, as reported in # ST Application Note (FIXME: add reference). # - Modifications on the bottom layer: # 1. replace reset chip U7 with a STM6315SDW13F; # 2. add 0 ohm resistor R45. It is located close to JTAG connector. # 3. add a 10K ohm pull-up resistor on the reset wire named as # POWERGOOD in the schematic. # # The easier way to do modification 3, is to use a resistor in package # 0603 or 0402 and solder it between R15 and R45: # - one pad soldered with the pad of R15 connected to 3.3V (this # is the pad of R15 closer to R45) # - the other pad soldered with the nearest pad of R45. # # Date: 2011-11-18 # Author: Antonio Borneo # Modified boards has SRST on JTAG connector set BOARD_HAS_SRST 1 source [find board/spear320cpu.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_b-l475e-iot01a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an B-L475E-IOT01A Discovery kit for IoT node with a single STM32L475VGT6 chip. # http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 96KB set WORKAREASIZE 0x18000 # enable stmqspi set QUADSPI 1 source [find target/stm32l4x.cfg] # QUADSPI initialization proc qspi_init { } { global a mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks) mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PE11: NCS, PE10: CLK, PE15: BK1_IO3, PE14: BK1_IO2, PE13: BK1_IO1, PE12: BK1_IO0 # PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V # Port E: PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V mmw 0x48001000 0xAAA00000 0x55500000 ;# MODER mmw 0x48001008 0xFFF00000 0x00000000 ;# OSPEEDR mmw 0x48001024 0xAAAAAA00 0x55555500 ;# AFRH mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00160100 ;# QUADSPI_DCR: FSIZE=0x16, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # memory-mapped read mode with 3-byte addresses mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK sleep 1 mmw 0x40021000 0x00000100 0x00000000 ;# HSI on mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 mmw 0x40021000 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_8l152r8.cfg ================================================ # This is a ST NUCLEO 8L152R8 board with a single STM8L152R8T6 chip. # http://www.st.com/en/evaluation-tools/nucleo-8l152r8.html source [find interface/stlink-dap.cfg] transport select swim source [find target/stm8l152.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_8s208rb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is a ST NUCLEO 8S208RB board with a single STM8S208RBT6 chip. # https://www.st.com/en/evaluation-tools/nucleo-8s208rb.html source [find interface/stlink-dap.cfg] transport select swim # 128 KiB flash and 2 KiB EEPROM set FLASHEND 0x27fff set EEPROMEND 0x47ff source [find target/stm8s.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_f0.cfg ================================================ # This is for all ST NUCLEO with any STM32F0. Known boards at the moment: # STM32F030R8 # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF259997 # NUCLEO-F072RB # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF259997 # STM32F091RC # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260944 source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32f0x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_f103rb.cfg ================================================ # This is an ST NUCLEO F103RB board with a single STM32F103RBT6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF259875 source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32f1x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_f3.cfg ================================================ # This is an ST NUCLEO F334R8 board with a single STM32F334R8T6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260004 source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32f3x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_f4.cfg ================================================ # This is for all ST NUCLEO with any STM32F4. Known boards at the moment: # STM32F401RET6 # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260000 # STM32F411RET6 # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260320 source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_f7.cfg ================================================ # STMicroelectronics STM32F7 Nucleo development board # Known boards: NUCLEO-F746ZG and NUCLEO-F767ZI source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32f7x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_g0.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is for all ST NUCLEO with any STM32G0. Known boards at the moment: # NUCLEO-G031K8 # https://www.st.com/en/evaluation-tools/nucleo-g031k8.html # NUCLEO-G070RB # https://www.st.com/en/evaluation-tools/nucleo-g070rb.html # NUCLEO-G071RB # https://www.st.com/en/evaluation-tools/nucleo-g071rb.html # NUCLEO-G0B1RE # https://www.st.com/en/evaluation-tools/nucleo-g0b1re.html source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32g0x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_g4.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is for all ST NUCLEO with any STM32G4. Known boards at the moment: # NUCLEO-G431KB # https://www.st.com/en/evaluation-tools/nucleo-g431kb.html # NUCLEO-G431RB # https://www.st.com/en/evaluation-tools/nucleo-g431rb.html # NUCLEO-G474RE # https://www.st.com/en/evaluation-tools/nucleo-g474re.html # NUCLEO-G491RE # https://www.st.com/en/evaluation-tools/nucleo-g491re.html source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32g4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_h743zi.cfg ================================================ # This is an ST NUCLEO-H743ZI board with single STM32H743ZI chip. # http://www.st.com/en/evaluation-tools/nucleo-h743zi.html source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32h7x_dual_bank.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_h745zi.cfg ================================================ # This is an ST NUCLEO-H745ZI-Q board with single STM32H745ZITx chip. source [find interface/stlink-dap.cfg] transport select dapdirect_swd # STM32H745xx devices are dual core (Cortex-M7 and Cortex-M4) set DUAL_CORE 1 # enable CTI for cross halting both cores set USE_CTI 1 source [find target/stm32h7x_dual_bank.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_l073rz.cfg ================================================ # This is an ST NUCLEO-L073RZ board with single STM32L073RZ chip. # http://www.st.com/en/evaluation-tools/nucleo-l073rz.html source [find interface/stlink.cfg] transport select hla_swd set WORKAREASIZE 0x2000 source [find target/stm32l0_dual_bank.cfg] # There is only system reset line and JTAG/SWD command can be issued when SRST reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_l1.cfg ================================================ # This is an ST NUCLEO L152RE board with a single STM32L152RET6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260002 source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32l1x_dual_bank.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_l4.cfg ================================================ # Should work with all STM32L4 Nucleo Dev Boards. # http://www.st.com/en/evaluation-tools/stm32-mcu-nucleo.html source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32l4x.cfg] # use hardware reset reset_config srst_only srst_nogate ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_l5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is for STM32L5 Nucleo Dev Boards. # http://www.st.com/en/evaluation-tools/stm32-mcu-nucleo.html source [find interface/stlink-dap.cfg] transport select dapdirect_swd source [find target/stm32l5x.cfg] # use hardware reset reset_config srst_only srst_nogate ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/st_nucleo_wb55.cfg ================================================ # # Configuration for STM32WB55 Nucleo board (STM32WB55RGV6) # source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32wbx.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/steval-idb007v1.cfg ================================================ # This is an evaluation board with a single BlueNRG-1 chip. # http://www.st.com/content/st_com/en/products/evaluation-tools/solution-evaluation-tools/communication-and-connectivity-solution-eval-boards/steval-idb008v1.html set CHIPNAME bluenrg-1 source [find target/bluenrg-x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/steval-idb008v1.cfg ================================================ # This is an evaluation board with a single BlueNRG-2 chip. # http://www.st.com/content/st_com/en/products/evaluation-tools/solution-evaluation-tools/communication-and-connectivity-solution-eval-boards/steval-idb007v1.html set CHIPNAME bluenrg-2 source [find target/bluenrg-x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/steval-idb011v1.cfg ================================================ # This is an evaluation board with a single BlueNRG-LP chip. set CHIPNAME bluenrg-lp source [find target/bluenrg-x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/steval-idb012v1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later. # This is an evaluation board with a single BlueNRG-LPS chip. set CHIPNAME bluenrg-lps source [find interface/cmsis-dap.cfg] source [find target/bluenrg-x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/steval_pcc010.cfg ================================================ # Use for the STM207VG plug-in board (1 MiB Flash and 112+16 KiB Ram # coming with the STEVAL-PCC010 board # http://www.st.com/internet/evalboard/product/251530.jsp # or any other board with only a STM32F2x in the JTAG chain # increase working area to 32KB for faster flash programming set WORKAREASIZE 0x8000 source [find target/stm32f2x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm320518_eval.cfg ================================================ # STM320518-EVAL: This is an STM32F0 eval board with a single STM32F051R8T6 # (64KB) chip. # http://www.st.com/internet/evalboard/product/252994.jsp # # increase working area to 8KB set WORKAREASIZE 0x2000 # chip name set CHIPNAME STM32F051R8T6 source [find target/stm32f0x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm320518_eval_stlink.cfg ================================================ # STM320518-EVAL: This is an STM32F0 eval board with a single STM32F051R8T6 # (64KB) chip. # http://www.st.com/internet/evalboard/product/252994.jsp # # This is for using the onboard STLINK/V2 source [find interface/stlink.cfg] transport select hla_swd # increase working area to 8KB set WORKAREASIZE 0x2000 # chip name set CHIPNAME STM32F051R8T6 source [find target/stm32f0x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32100b_eval.cfg ================================================ # This is an STM32 eval board with a single STM32F100VBT6 chip. # http://www.st.com/internet/evalboard/product/247099.jsp # The chip has only 8KB sram set WORKAREASIZE 0x2000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm3210b_eval.cfg ================================================ # This is an STM32 eval board with a single STM32F10x (128KB) chip. # http://www.st.com/internet/evalboard/product/176090.jsp # increase working area to 32KB for faster flash programming set WORKAREASIZE 0x8000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm3210c_eval.cfg ================================================ # This is an STM32 eval board with a single STM32F107VCT chip. # http://www.st.com/internet/evalboard/product/217965.jsp # increase working area to 32KB for faster flash programming set WORKAREASIZE 0x8000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm3210e_eval.cfg ================================================ # This is an STM32 eval board with a single STM32F103ZET6 chip. # http://www.st.com/internet/evalboard/product/204176.jsp # increase working area to 32KB for faster flash programming set WORKAREASIZE 0x8000 source [find target/stm32f1x.cfg] # # configure FSMC Bank 1 (NOR/PSRAM Bank 2) NOR flash # M29W128GL70ZA6E # set _FLASHNAME $_CHIPNAME.norflash flash bank $_FLASHNAME cfi 0x64000000 0x01000000 2 2 $_TARGETNAME proc stm32_enable_fsmc {} { echo "Enabling FSMC Bank 1 (NOR/PSRAM Bank 2)" # enable gpio (defg) clocks for fsmc # RCC_APB2ENR mww 0x40021018 0x000001E0 # enable fsmc clock # RCC_AHBENR mww 0x40021014 0x00000114 # configure gpio to alternate function # GPIOD_CRL mww 0x40011400 0x44BB44BB # GPIOD_CRH mww 0x40011404 0xBBBBBBBB # GPIOE_CRL mww 0x40011800 0xBBBBB444 # GPIOE_CRH mww 0x40011804 0xBBBBBBBB # GPIOF_CRL mww 0x40011C00 0x44BBBBBB # GPIOF_CRH mww 0x40011C04 0xBBBB4444 # GPIOG_CRL mww 0x40012000 0x44BBBBBB # GPIOG_CRH mww 0x40012004 0x444444B4 # setup fsmc timings # FSMC_BCR1 mww 0xA0000008 0x00001058 # FSMC_BTR1 mww 0xA000000C 0x10000502 # FSMC_BCR1 - enable fsmc mww 0xA0000008 0x00001059 } $_TARGETNAME configure -event reset-init { stm32_enable_fsmc } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm3220g_eval.cfg ================================================ # STM3220G-EVAL: This is an STM32F2 eval board with a single STM32F207IGH6 # (128KB) chip. # http://www.st.com/internet/evalboard/product/250374.jsp # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F207IGH6 source [find target/stm32f2x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm3220g_eval_stlink.cfg ================================================ # STM3220G-EVAL: This is an STM32F2 eval board with a single STM32F207IGH6 # (128KB) chip. # http://www.st.com/internet/evalboard/product/250374.jsp # # This is for using the onboard STLINK/V2 source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F207IGH6 source [find target/stm32f2x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm3241g_eval.cfg ================================================ # STM3241G-EVAL: This is an STM32F4 eval board with a single STM32F417IGH6 # (1024KB) chip. # http://www.st.com/internet/evalboard/product/252216.jsp # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F417IGH6 source [find target/stm32f4x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm3241g_eval_stlink.cfg ================================================ # STM3241G-EVAL: This is an STM32F4 eval board with a single STM32F417IGH6 # (1024KB) chip. # http://www.st.com/internet/evalboard/product/252216.jsp # # This is for using the onboard STLINK/V2 source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F417IGH6 source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32429i_eval.cfg ================================================ # STM32429I-EVAL: This is an STM32F4 eval board with a single STM32F429NIH6 # (2048KB) chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF259093 # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F429NIH6 source [find target/stm32f4x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32429i_eval_stlink.cfg ================================================ # STM32429I-EVAL: This is an STM32F4 eval board with a single STM32F429NIH6 # (2048KB) chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF259093 # # This is for using the onboard STLINK/V2 source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F429NIH6 source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32439i_eval.cfg ================================================ # STM32439I-EVAL: This is an STM32F4 eval board with a single STM32F439NIH6 # (2048KB) chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF259094 # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F439NIH6 source [find target/stm32f4x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32439i_eval_stlink.cfg ================================================ # STM32439I-EVAL: This is an STM32F4 eval board with a single STM32F439NIH6 # (2048KB) chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF259094 # # This is for using the onboard STLINK/V2 source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F439NIH6 source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm327x6g_eval.cfg ================================================ # STM327[4|5]6G-EVAL: This is for the STM32F7 eval boards. # STM32746G-EVAL # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF261639 # STM32756G-EVAL # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF261640 # increase working area to 256KB set WORKAREASIZE 0x40000 source [find target/stm32f7x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f0discovery.cfg ================================================ # This is an STM32F0 discovery board with a single STM32F051R8T6 chip. # http://www.st.com/internet/evalboard/product/253215.jsp source [find interface/stlink.cfg] transport select hla_swd set WORKAREASIZE 0x2000 source [find target/stm32f0x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f103c8_blue_pill.cfg ================================================ # STM32F103C8 "Blue Pill" # NOTE: # There is a fair bit of confusion about whether the "Blue Pill" has 128kB or 64kB flash size. # The most likely cause is that there exist a -C8 and a -CB variant of the STM32F103, where # the C8 has 64kB, the CB has 128kB as per specification. "Blue Pill" boards are manufactured # by a lot of different vendors, some may actually use the CB variant but from a cursory look # it very hard to tell them apart ("C8" and "CB" look very similar). Nevertheless, people have # tried using the full 128kB of flash on the C8 and found it to be working. Hence this board file # overrides the internal size detection. Be aware though that you may be using you particular # board outside of its specification. If in doubt, comment the following line. set FLASH_SIZE 0x20000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f334discovery.cfg ================================================ # This is an STM32F334 discovery board with a single STM32F334C8T6 chip. # As it is one of the few boards with stlink V.2-1, we source the corresponding # nucleo file. # http://www.st.com/web/en/catalog/tools/FM116/SC959/SS1532/LN1848/PF260318 source [find board/st_nucleo_f3.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f3discovery.cfg ================================================ # This is an STM32F3 discovery board with a single STM32F303VCT6 chip. # http://www.st.com/internet/evalboard/product/254044.jsp source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32f3x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f412g-disco.cfg ================================================ # This is an STM32F412G discovery board with a single STM32F412ZGT6 chip. # http://www.st.com/en/evaluation-tools/32f412gdiscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # enable stmqspi set QUADSPI 1 source [find target/stm32f4x.cfg] # QUADSPI initialization proc qspi_init { } { global a mmw 0x40023830 0x000000FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOHEN (enable clocks) mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PB02: CLK, PG06: BK1_NCS, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0 # PB02:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V, PG06:AF10:V # Port B: PB02:AF09:V mmw 0x40020400 0x00000020 0x00000010 ;# MODER mmw 0x40020408 0x00000030 0x00000000 ;# OSPEEDR mmw 0x40020420 0x00000900 0x00000600 ;# AFRL # Port F: PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V mmw 0x40021400 0x000AA000 0x00055000 ;# MODER mmw 0x40021408 0x000FF000 0x00000000 ;# OSPEEDR mmw 0x40021420 0x99000000 0x66000000 ;# AFRL mmw 0x40021424 0x000000AA 0x00000055 ;# AFRH # Port G: PG06:AF10:V mmw 0x40021800 0x00002000 0x00001000 ;# MODER mmw 0x40021808 0x00003000 0x00000000 ;# OSPEEDR mmw 0x40021820 0x0A000000 0x05000000 ;# AFRL mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # 1-line spi mode mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO sleep 1 # memory-mapped read mode with 3-byte addresses mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mww 0x40023C00 0x00000003 ;# 3 WS for 96 MHz HCLK sleep 1 mww 0x40023804 0x24001808 ;# 96 MHz: HSI, PLLM=8, PLLN=96, PLLP=2 mww 0x40023808 0x00001000 ;# APB1: /2, APB2: /1 mmw 0x40023800 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f413h-disco.cfg ================================================ # This is an STM32F413H discovery board with a single STM32F413ZHT6 chip. # http://www.st.com/en/evaluation-tools/32f413hdiscovery.html # # Untested!!! # # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # enable stmqspi set QUADSPI 1 source [find target/stm32f4x.cfg] # QUADSPI initialization proc qspi_init { } { global a mmw 0x40023830 0x000000FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOHEN (enable clocks) mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PG06: BK1_NCS, PB02: CLK, PD13: BK1_IO3, PE02: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0 # PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PF09:AF10:V, PF08:AF10:V, PG06:AF10:V # Port B: PB02:AF09:V mmw 0x40020400 0x00000020 0x00000010 ;# MODER mmw 0x40020408 0x00000030 0x00000000 ;# OSPEEDR mmw 0x40020420 0x00000900 0x00000600 ;# AFRL # Port D: PD13:AF09:V mmw 0x40020C00 0x08000000 0x04000000 ;# MODER mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH # Port E: PE02:AF09:V mmw 0x40021000 0x00000020 0x00000010 ;# MODER mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR mmw 0x40021020 0x00000900 0x00000600 ;# AFRL # Port F: PF09:AF10:V, PF08:AF10:V mmw 0x40021400 0x000A0000 0x00050000 ;# MODER mmw 0x40021408 0x000F0000 0x00000000 ;# OSPEEDR mmw 0x40021424 0x000000AA 0x00000055 ;# AFRH # Port G: PG06:AF10:V mmw 0x40021800 0x00002000 0x00001000 ;# MODER mmw 0x40021808 0x00003000 0x00000000 ;# OSPEEDR mmw 0x40021820 0x0A000000 0x05000000 ;# AFRL mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # 1-line spi mode mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO sleep 1 # memory-mapped read mode with 3-byte addresses mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mww 0x40023C00 0x00000003 ;# 3 WS for 96 MHz HCLK sleep 1 mww 0x40023804 0x24001808 ;# 96 MHz: HSI, PLLM=8, PLLN=96, PLLP=2 mww 0x40023808 0x00001000 ;# APB1: /2, APB2: /1 mmw 0x40023800 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f429disc1.cfg ================================================ # # This is an STM32F429 discovery board with a single STM32F429ZI chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF259090 # source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f429discovery.cfg ================================================ # # This is an STM32F429 discovery board with a single STM32F429ZI chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF259090 # source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f469discovery.cfg ================================================ # # This is an STM32F469 discovery board with a single STM32F469NI chip. # http://www.st.com/web/catalog/tools/FM116/CL1620/SC959/SS1532/LN1848/PF262395 # source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f469i-disco.cfg ================================================ # This is an STM32F469I discovery board with a single STM32F469NIH6 chip. # http://www.st.com/en/evaluation-tools/32f469idiscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # enable stmqspi set QUADSPI 1 source [find target/stm32f4x.cfg] # QUADSPI initialization proc qspi_init { } { global a mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PF10: CLK, PB06: BK1_NCS, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0 # PB06:AF10:V, PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V # Port B: PB06:AF10:V mmw 0x40020400 0x00002000 0x00001000 ;# MODER mmw 0x40020408 0x00003000 0x00000000 ;# OSPEEDR mmw 0x40020420 0x0A000000 0x05000000 ;# AFRL # Port F: PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V mmw 0x40021400 0x002AA000 0x00155000 ;# MODER mmw 0x40021408 0x003FF000 0x00000000 ;# OSPEEDR mmw 0x40021420 0x99000000 0x66000000 ;# AFRL mmw 0x40021424 0x000009AA 0x00000655 ;# AFRH mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # 1-line spi mode mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO sleep 1 # memory-mapped read mode with 3-byte addresses mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mww 0x40023C00 0x00000005 ;# 5 WS for 160 MHz HCLK sleep 1 mww 0x40023804 0x24002808 ;# 160 MHz: HSI, PLLM=8, PLLN=160, PLLP=2 mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 mmw 0x40023800 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f4discovery.cfg ================================================ # This is an STM32F4 discovery board with a single STM32F407VGT6 chip. # http://www.st.com/internet/evalboard/product/252419.jsp source [find interface/stlink.cfg] transport select hla_swd # increase working area to 64KB set WORKAREASIZE 0x10000 source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f723e-disco.cfg ================================================ # This is an STM32F723E discovery board with a single STM32F723IEK6 chip. # http://www.st.com/en/evaluation-tools/32f723ediscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # enable stmqspi set QUADSPI 1 source [find target/stm32f7x.cfg] reset_config srst_only # QUADSPI initialization proc qspi_init { } { global a mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PC10: BK1_IO1, PC09: BK1_IO0 # PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V # Port B: PB06:AF10:V, PB02:AF09:V mmw 0x40020400 0x00002020 0x00001010 ;# MODER mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL # Port C: PC10:AF09:V, PC09:AF09:V mmw 0x40020800 0x00280000 0x00140000 ;# MODER mmw 0x40020808 0x003C0000 0x00000000 ;# OSPEEDR mmw 0x40020824 0x00000990 0x00000660 ;# AFRH # Port D: PD13:AF09:V mmw 0x40020C00 0x08000000 0x04000000 ;# MODER mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH # Port E: PE02:AF09:V mmw 0x40021000 0x00000020 0x00000010 ;# MODER mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR mmw 0x40021020 0x00000900 0x00000600 ;# AFRL mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00190100 ;# QUADSPI_DCR: FSIZE=0x19, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # 1-line spi mode mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO sleep 1 # memory-mapped read mode with 4-byte addresses mww 0xA0001014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK sleep 1 mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2 mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 mmw 0x40023800 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f746g-disco.cfg ================================================ # This is an STM32F746G discovery board with a single STM32F746NGH6 chip. # http://www.st.com/en/evaluation-tools/32f746gdiscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 256KB set WORKAREASIZE 0x40000 # enable stmqspi set QUADSPI 1 source [find target/stm32f7x.cfg] reset_config srst_only # QUADSPI initialization proc qspi_init { } { global a mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PD12: BK1_IO1, PD11: BK1_IO0 # PB06:AF10:V, PB02:AF09:V, PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PE02:AF09:V # Port B: PB06:AF10:V, PB02:AF09:V mmw 0x40020400 0x00002020 0x00001010 ;# MODER mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL # Port D: PD13:AF09:V, PD12:AF09:V, PD11:AF09:V mmw 0x40020C00 0x0A800000 0x05400000 ;# MODER mmw 0x40020C08 0x0FC00000 0x00000000 ;# OSPEEDR mmw 0x40020C24 0x00999000 0x00666000 ;# AFRH # Port E: PE02:AF09:V mmw 0x40021000 0x00000020 0x00000010 ;# MODER mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR mmw 0x40021020 0x00000900 0x00000600 ;# AFRL mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # 1-line spi mode mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO sleep 1 # memory-mapped read mode with 3-byte addresses mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK sleep 1 mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2 mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 mmw 0x40023800 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f769i-disco.cfg ================================================ # This is an STM32F769I discovery board with a single STM32F769NIH6 chip. # http://www.st.com/en/evaluation-tools/32f769idiscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 256KB set WORKAREASIZE 0x40000 # enable stmqspi set QUADSPI 1 source [find target/stm32f7x.cfg] reset_config srst_only # QUADSPI initialization proc qspi_init { } { global a mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PC10: BK1_IO1, PC09: BK1_IO0 # PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V # Port B: PB06:AF10:V, PB02:AF09:V mmw 0x40020400 0x00002020 0x00001010 ;# MODER mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL # Port C: PC10:AF09:V, PC09:AF09:V mmw 0x40020800 0x00280000 0x00140000 ;# MODER mmw 0x40020808 0x003C0000 0x00000000 ;# OSPEEDR mmw 0x40020824 0x00000990 0x00000660 ;# AFRH # Port D: PD13:AF09:V mmw 0x40020C00 0x08000000 0x04000000 ;# MODER mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH # Port E: PE02:AF09:V mmw 0x40021000 0x00000020 0x00000010 ;# MODER mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR mmw 0x40021020 0x00000900 0x00000600 ;# AFRL mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00190100 ;# QUADSPI_DCR: FSIZE=0x19, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # exit qpi mode mww 0xA0001014 0x000033f5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO # 1-line memory-mapped read mode with 4-byte addresses mww 0xA0001014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ # 4-line qpi mode mww 0xA0001014 0x00003135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=EQIO # 4-line memory-mapped read mode with 4-byte addresses mww 0xA0001014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0xA, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=4READ4B } $_TARGETNAME configure -event reset-init { mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK sleep 1 mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2 mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 mmw 0x40023800 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32f7discovery.cfg ================================================ # This is an STM32F7 discovery board with a single STM32F756NGH6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1848/PF261641 # This is for using the onboard STLINK/V2-1 source [find interface/stlink.cfg] transport select hla_swd # increase working area to 256KB set WORKAREASIZE 0x40000 source [find target/stm32f7x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32h735g-disco.cfg ================================================ # This is a stm32h735g-dk with a single STM32H735IGK6 chip. # https://www.st.com/en/evaluation-tools/stm32h735g-dk.html # # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd set CHIPNAME stm32h735igk6 # enable stmqspi if {![info exists OCTOSPI1]} { set OCTOSPI1 1 set OCTOSPI2 0 } source [find target/stm32h7x.cfg] reset_config srst_only # OCTOSPI initialization # octo: 8-line mode proc octospi_init { octo } { global a b mmw 0x58024540 0x000006FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x58024534 0x00284000 0 ;# RCC_AHB3ENR |= IOMNGREN, OSPI2EN, OSPI1EN (enable clocks) sleep 1 ;# Wait for clock startup mww 0x5200B404 0x03010111 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI1 mww 0x5200B408 0x00000000 ;# OCTOSPIM_P2CR: disable Port 2 # PG06: OCSPI1_NCS, PF10: OCSPI1_CLK, PB02: OCSPI1_DQS, PD07: OCSPI1_IO7, PG09: OCSPI1_IO6, PD05: OCSPI1_IO5, # PD04: OCSPI1_IO4, PD13: OCSPI1_IO3, PE02: OCSPI1_IO2, PD12: OCSPI1_IO1, PD11: OCSPI1_IO0 # PB02:AF10:V, PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PD07:AF10:V, PD05:AF10:V # PD04:AF10:V, PE02:AF09:V, PF10:AF09:V, PG09:AF09:V, PG06:AF10:V # Port B: PB02:AF10:V mmw 0x58020400 0x00000020 0x00000010 ;# MODER mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR mmw 0x5802040C 0x00000000 0x00000030 ;# PUPDR mmw 0x58020420 0x00000A00 0x00000500 ;# AFRL # Port D: PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V mmw 0x58020C00 0x0A808A00 0x05404500 ;# MODER mmw 0x58020C08 0x0FC0CF00 0x00000000 ;# OSPEEDR mmw 0x58020C0C 0x00000000 0x0FC0CF00 ;# PUPDR mmw 0x58020C20 0xA0AA0000 0x50550000 ;# AFRL mmw 0x58020C24 0x00999000 0x00666000 ;# AFRH # Port E: PE02:AF09:V mmw 0x58021000 0x00000020 0x00000010 ;# MODER mmw 0x58021008 0x00000030 0x00000000 ;# OSPEEDR mmw 0x5802100C 0x00000000 0x00000030 ;# PUPDR mmw 0x58021020 0x00000900 0x00000600 ;# AFRL # Port F: PF10:AF09:V mmw 0x58021400 0x00200000 0x00100000 ;# MODER mmw 0x58021408 0x00300000 0x00000000 ;# OSPEEDR mmw 0x5802140C 0x00000000 0x00300000 ;# PUPDR mmw 0x58021424 0x00000900 0x00000600 ;# AFRH # Port G: PG09:AF09:V, PG06:AF10:V mmw 0x58021800 0x00082000 0x00041000 ;# MODER mmw 0x58021808 0x000C3000 0x00000000 ;# OSPEEDR mmw 0x5802180C 0x00000000 0x000C3000 ;# PUPDR mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL mmw 0x58021824 0x00000090 0x00000060 ;# AFRH # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses mww 0x52005130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 mww 0x52005008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 mww 0x5200500C 0x00000005 ;# OCTOSPI_DCR2: PRESCALER=5 mww 0x52005108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 mww 0x52005100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 mww 0x52005110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B flash probe $a ;# load configuration from CR, TCR, CCR, IR register values if { $octo == 1 } { stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 ;# Read Status Register stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 mww 0x52005108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 mww 0x52005100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 mww 0x52005110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 0 0x04 ;# Write Disable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits } } $_CHIPNAME.cpu0 configure -event reset-init { global OCTOSPI1 global OCTOSPI2 mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 sleep 1 mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock sleep 1 adapter speed 24000 if { $OCTOSPI1 } { octospi_init 1 } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32h745i-disco.cfg ================================================ # This is a stm32h745i-disco with a single STM32H745XIH6 chip. # www.st.com/en/product/stm32h745i-disco.html # # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd set CHIPNAME stm32h745xih6 # enable stmqspi if {![info exists QUADSPI]} { set QUADSPI 1 } source [find target/stm32h7x_dual_bank.cfg] reset_config srst_only source [find board/stm32h7x_dual_qspi.cfg] $_CHIPNAME.cpu0 configure -event reset-init { global QUADSPI mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 sleep 1 mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock sleep 1 adapter speed 24000 if { $QUADSPI } { qspi_init 1 } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32h747i-disco.cfg ================================================ # This is a stm32h747i-disco with a single STM32H747XIH6 chip. # www.st.com/en/product/stm32h747i-disco.html # # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd set CHIPNAME stm32h747xih6 # enable stmqspi if {![info exists QUADSPI]} { set QUADSPI 1 } source [find target/stm32h7x_dual_bank.cfg] reset_config srst_only # QUADSPI initialization # qpi: 4-line mode proc qspi_init { qpi } { global a mmw 0x580244E0 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x580244D4 0x00004000 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PG06: BK1_NCS, PB02: CLK, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PD11: BK1_IO0, # PG14: BK2_IO3, PG09: BK2_IO2, PH03: BK2_IO1, PH02: BK2_IO0 # PB02:AF09:V, PD11:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V, PG14:AF09:H # PG09:AF09:V, PG06:AF10:H, PH03:AF09:V, PH02:AF09:V # Port B: PB02:AF09:V mmw 0x58020400 0x00000020 0x00000010 ;# MODER mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR mmw 0x58020420 0x00000900 0x00000600 ;# AFRL # Port D: PD11:AF09:V mmw 0x58020C00 0x00800000 0x00400000 ;# MODER mmw 0x58020C08 0x00C00000 0x00000000 ;# OSPEEDR mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH # Port F: PF09:AF10:V, PF07:AF09:V, PF06:AF09:V mmw 0x58021400 0x0008A000 0x00045000 ;# MODER mmw 0x58021408 0x000CF000 0x00000000 ;# OSPEEDR mmw 0x58021420 0x99000000 0x66000000 ;# AFRL mmw 0x58021424 0x000000A0 0x00000050 ;# AFRH # Port G: PG14:AF09:H, PG09:AF09:V, PG06:AF10:H mmw 0x58021800 0x20082000 0x10041000 ;# MODER mmw 0x58021808 0x200C2000 0x10001000 ;# OSPEEDR mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL mmw 0x58021824 0x09000090 0x06000060 ;# AFRH # Port H: PH03:AF09:V, PH02:AF09:V mmw 0x58021C00 0x000000A0 0x00000050 ;# MODER mmw 0x58021C08 0x000000F0 0x00000000 ;# OSPEEDR mmw 0x58021C20 0x00009900 0x00006600 ;# AFRL # correct FSIZE is 0x1A, however, this causes trouble when # reading the last bytes at end of bank in *memory mapped* mode # for dual flash mode 2 * mt25ql512 mww 0x52005000 0x05500058 ;# QUADSPI_CR: PRESCALER=5, APMS=1, FTHRES=0, FSEL=0, DFM=1, SSHIFT=1, TCEN=1 mww 0x52005004 0x001A0200 ;# QUADSPI_DCR: FSIZE=0x1A, CSHT=0x02, CKMODE=0 mww 0x52005030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0x52005014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1 mmw 0x52005000 0x00000001 0 ;# QUADSPI_CR: EN=1 # Exit QPI mode mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=Exit QPI sleep 1 if { $qpi == 1 } { # Write Enable mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable sleep 1 # Configure dummy clocks via volatile configuration register mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes mww 0x52005014 0x01000181 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Volatile Conf. Reg. mwh 0x52005020 0xABAB ;# QUADSPI_DR: 0xAB 0xAB for 10 dummy clocks sleep 1 # Write Enable mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable sleep 1 # Enable QPI mode via enhanced volatile configuration register mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes mww 0x52005014 0x01000161 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enhanced Conf. Reg. mwh 0x52005020 0x3F3F ;# QUADSPI_DR: 0x3F 0x3F to enable QPI and DPI mode sleep 1 # Enter QPI mode mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x00000135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Enter QPI sleep 1 # memory-mapped fast read mode with 4-byte addresses and 10 dummy cycles (for read only) mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x3, DCYC=0xA, ADSIZE=0x3, ADMODE=0x3, IMODE=0x3, INSTR=Fast READ } else { # memory-mapped read mode with 4-byte addresses mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ } } $_CHIPNAME.cpu0 configure -event reset-init { global QUADSPI mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 sleep 1 mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock sleep 1 adapter speed 24000 if { $QUADSPI } { qspi_init 1 } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32h750b-disco.cfg ================================================ # This is a stm32h750b-dk with a single STM32H750XBH6 chip. # www.st.com/en/product/stm32h750b-dk.html # # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd set CHIPNAME stm32h750xbh6 # enable stmqspi if {![info exists QUADSPI]} { set QUADSPI 1 } source [find target/stm32h7x.cfg] reset_config srst_only source [find board/stm32h7x_dual_qspi.cfg] $_CHIPNAME.cpu0 configure -event reset-init { global QUADSPI mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 sleep 1 mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock sleep 1 adapter speed 24000 if { $QUADSPI } { qspi_init 1 } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32h7b3i-disco.cfg ================================================ # This is a stm32h7b3i-dk with a single STM32H7B3LIH6Q chip. # https://www.st.com/en/evaluation-tools/stm32h7b3i-dk.html # # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd set CHIPNAME stm32h7b3lih6q # enable stmqspi if {![info exists OCTOSPI1]} { set OCTOSPI1 1 set OCTOSPI2 0 } source [find target/stm32h7x_dual_bank.cfg] reset_config srst_only # OCTOSPI initialization # octo: 8-line mode proc octospi_init { octo } { global a b mmw 0x58024540 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x58024534 0x00284000 0 ;# RCC_AHB3ENR |= IOMNGREN, OSPI2EN, OSPI1EN (enable clocks) sleep 1 ;# Wait for clock startup mww 0x5200B404 0x03010111 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI1 mww 0x5200B408 0x00000000 ;# OCTOSPIM_P2CR: disable Port 2 # PG06: OCSPI1_NCS, PB02: OCSPI1_CLK, PC05: OCSPI1_DQS, PD07: OCSPI1_IO7, PG09: OCSPI1_IO6, PH03: OCSPI1_IO5, # PC01: OCSPI1_IO4, PF06: OCSPI1_IO3, PF07: OCSPI1_IO2, PF09: OCSPI1_IO1, PD11: OCSPI1_IO0 # PB02:AF09:V, PC05:AF10:V, PC01:AF10:V, PD11:AF09:V, PD07:AF10:V, PF09:AF10:V # PF07:AF10:V, PF06:AF10:V, PG09:AF09:V, PG06:AF10:V, PH03:AF09:V # Port B: PB02:AF09:V mmw 0x58020400 0x00000020 0x00000010 ;# MODER mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR mmw 0x5802040C 0x00000000 0x00000030 ;# PUPDR mmw 0x58020420 0x00000900 0x00000600 ;# AFRL # Port C: PC05:AF10:V, PC01:AF10:V mmw 0x58020800 0x00000808 0x00000404 ;# MODER mmw 0x58020808 0x00000C0C 0x00000000 ;# OSPEEDR mmw 0x5802080C 0x00000000 0x00000C0C ;# PUPDR mmw 0x58020820 0x00A000A0 0x00500050 ;# AFRL # Port D: PD11:AF09:V, PD07:AF10:V mmw 0x58020C00 0x00808000 0x00404000 ;# MODER mmw 0x58020C08 0x00C0C000 0x00000000 ;# OSPEEDR mmw 0x58020C0C 0x00000000 0x00C0C000 ;# PUPDR mmw 0x58020C20 0xA0000000 0x50000000 ;# AFRL mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH # Port F: PF09:AF10:V, PF07:AF10:V, PF06:AF10:V mmw 0x58021400 0x0008A000 0x00045000 ;# MODER mmw 0x58021408 0x000CF000 0x00000000 ;# OSPEEDR mmw 0x5802140C 0x00000000 0x000CF000 ;# PUPDR mmw 0x58021420 0xAA000000 0x55000000 ;# AFRL mmw 0x58021424 0x000000A0 0x00000050 ;# AFRH # Port G: PG09:AF09:V, PG06:AF10:V mmw 0x58021800 0x00082000 0x00041000 ;# MODER mmw 0x58021808 0x000C3000 0x00000000 ;# OSPEEDR mmw 0x5802180C 0x00000000 0x000C3000 ;# PUPDR mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL mmw 0x58021824 0x00000090 0x00000060 ;# AFRH # Port H: PH03:AF09:V mmw 0x58021C00 0x00000080 0x00000040 ;# MODER mmw 0x58021C08 0x000000C0 0x00000000 ;# OSPEEDR mmw 0x58021C0C 0x00000000 0x000000C0 ;# PUPDR mmw 0x58021C20 0x00009000 0x00006000 ;# AFRL # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses mww 0x52005130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 mww 0x52005008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 mww 0x5200500C 0x00000005 ;# OCTOSPI_DCR2: PRESCALER=5 mww 0x52005108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 mww 0x52005100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 mww 0x52005110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B flash probe $a ;# load configuration from CR, TCR, CCR, IR register values if { $octo == 1 } { stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 ;# Read Status Register stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 mww 0x52005108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 mww 0x52005100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 mww 0x52005110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 0 0x04 ;# Write Disable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits } } $_CHIPNAME.cpu0 configure -event reset-init { global OCTOSPI1 global OCTOSPI2 mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 sleep 1 mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock sleep 1 adapter speed 24000 if { $OCTOSPI1 } { octospi_init 1 } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32h7x3i_eval.cfg ================================================ # STM32H7[4|5]3I-EVAL: this is for the H7 eval boards. # This is an ST EVAL-H743XI board with single STM32H743XI chip. # http://www.st.com/en/evaluation-tools/stm32h743i-eval.html # This is an ST EVAL-H753XI board with single STM32H753XI chip. # http://www.st.com/en/evaluation-tools/stm32h753i-eval.html source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32h7x_dual_bank.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32h7x_dual_qspi.cfg ================================================ # stm32h754i-disco and stm32h750b-dk dual quad qspi. # QUADSPI initialization # qpi: 4-line mode proc qspi_init { qpi } { global a mmw 0x580244E0 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x580244D4 0x00004000 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PG06: BK1_NCS, PF10: CLK, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PD11: BK1_IO0, # PG14: BK2_IO3, PG09: BK2_IO2, PH03: BK2_IO1, PH02: BK2_IO0 # PD11:AF09:V, PF10:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V, PG14:AF09:H # PG09:AF09:V, PG06:AF10:H, PH03:AF09:V, PH02:AF09:V # Port D: PD11:AF09:V mmw 0x58020C00 0x00800000 0x00400000 ;# MODER mmw 0x58020C08 0x00C00000 0x00000000 ;# OSPEEDR mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH # Port F: PF10:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V mmw 0x58021400 0x0028A000 0x00145000 ;# MODER mmw 0x58021408 0x003CF000 0x00000000 ;# OSPEEDR mmw 0x58021420 0x99000000 0x66000000 ;# AFRL mmw 0x58021424 0x000009A0 0x00000650 ;# AFRH # Port G: PG14:AF09:H, PG09:AF09:V, PG06:AF10:H mmw 0x58021800 0x20082000 0x10041000 ;# MODER mmw 0x58021808 0x200C2000 0x10001000 ;# OSPEEDR mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL mmw 0x58021824 0x09000090 0x06000060 ;# AFRH # Port H: PH03:AF09:V, PH02:AF09:V mmw 0x58021C00 0x000000A0 0x00000050 ;# MODER mmw 0x58021C08 0x000000F0 0x00000000 ;# OSPEEDR mmw 0x58021C20 0x00009900 0x00006600 ;# AFRL # correct FSIZE is 0x1A, however, this causes trouble when # reading the last bytes at end of bank in *memory mapped* mode # for dual flash mode 2 * mt25ql512 mww 0x52005000 0x05500058 ;# QUADSPI_CR: PRESCALER=5, APMS=1, FTHRES=0, FSEL=0, DFM=1, SSHIFT=1, TCEN=1 mww 0x52005004 0x001A0200 ;# QUADSPI_DCR: FSIZE=0x1A, CSHT=0x02, CKMODE=0 mww 0x52005030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0x52005014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1 mmw 0x52005000 0x00000001 0 ;# QUADSPI_CR: EN=1 # Exit QPI mode mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=Exit QPI sleep 1 if { $qpi == 1 } { # Write Enable mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable sleep 1 # Configure dummy clocks via volatile configuration register mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes mww 0x52005014 0x01000181 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Volatile Conf. Reg. mwh 0x52005020 0xABAB ;# QUADSPI_DR: 0xAB 0xAB for 10 dummy clocks sleep 1 # Write Enable mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable sleep 1 # Enable QPI mode via enhanced volatile configuration register mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes mww 0x52005014 0x01000161 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enhanced Conf. Reg. mwh 0x52005020 0x3F3F ;# QUADSPI_DR: 0x3F 0x3F to enable QPI and DPI mode sleep 1 # Enter QPI mode mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x00000135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Enter QPI sleep 1 # memory-mapped fast read mode with 4-byte addresses and 10 dummy cycles (for read only) mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x3, DCYC=0xA, ADSIZE=0x3, ADMODE=0x3, IMODE=0x3, INSTR=Fast READ } else { # memory-mapped read mode with 4-byte addresses mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32l0discovery.cfg ================================================ # This is an STM32L053 discovery board with a single STM32L053 chip. # http://www.st.com/web/en/catalog/tools/PF260319 source [find interface/stlink.cfg] transport select hla_swd set WORKAREASIZE 0x2000 source [find target/stm32l0.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32l476g-disco.cfg ================================================ # This is an STM32L476G discovery board with a single STM32L476VGT6 chip. # http://www.st.com/en/evaluation-tools/32l476gdiscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 96KB set WORKAREASIZE 0x18000 # enable stmqspi set QUADSPI 1 source [find target/stm32l4x.cfg] # QUADSPI initialization proc qspi_init { } { global a mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks) mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PE11: NCS, PE10: CLK, PE15: BK1_IO3, PE14: BK1_IO2, PE13: BK1_IO1, PE12: BK1_IO0 # PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V # Port E: PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V mmw 0x48001000 0xAAA00000 0x55500000 ;# MODER mmw 0x48001008 0xFFF00000 0x00000000 ;# OSPEEDR mmw 0x48001024 0xAAAAAA00 0x55555500 ;# AFRH mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # memory-mapped read mode with 3-byte addresses mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK sleep 1 mmw 0x40021000 0x00000100 0x00000000 ;# HSI on mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 mmw 0x40021000 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32l496g-disco.cfg ================================================ # This is an STM32L496G discovery board with a single STM32L496AGI6 chip. # http://www.st.com/en/evaluation-tools/32l496gdiscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 96KB set WORKAREASIZE 0x18000 # enable stmqspi set QUADSPI 1 source [find target/stm32l4x.cfg] # QUADSPI initialization proc qspi_init { } { global a mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks) mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PB11: BK1_NCS, PA03: CLK, PA06: BK1_IO3, PA07: BK1_IO2, PB00: BK1_IO1, PB01: BK1_IO0 # PA07:AF10:V, PA06:AF10:V, PA03:AF10:V, PB11:AF10:V, PB01:AF10:V, PB00:AF10:V # Port A: PA07:AF10:V, PA06:AF10:V, PA03:AF10:V mmw 0x48000000 0x0000A080 0x00005040 ;# MODER mmw 0x48000008 0x0000F0C0 0x00000000 ;# OSPEEDR mmw 0x48000020 0xAA00A000 0x55005000 ;# AFRL # Port B: PB11:AF10:V, PB01:AF10:V, PB00:AF10:V mmw 0x48000400 0x0080000A 0x00400005 ;# MODER mmw 0x48000408 0x00C0000F 0x00000000 ;# OSPEEDR mmw 0x48000420 0x000000AA 0x00000055 ;# AFRL mmw 0x48000424 0x0000A000 0x00005000 ;# AFRH mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00160100 ;# QUADSPI_DCR: FSIZE=0x16, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # 1-line spi mode mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO sleep 1 # memory-mapped read mode with 3-byte addresses mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK sleep 1 mmw 0x40021000 0x00000100 0x00000000 ;# HSI on mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 mmw 0x40021000 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32l4discovery.cfg ================================================ # Explicitly for the STM32L476 discovery board: # http://www.st.com/web/en/catalog/tools/PF261635 # but perfectly functional for any other STM32L4 board connected via # an stlink-v2-1 interface. # This is for STM32L4 boards that are connected via stlink-v2-1. source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32l4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32l4p5g-disco.cfg ================================================ # This is a STM32L4P5G discovery board with a single STM32L4R9AGI6 chip. # http://www.st.com/en/evaluation-tools/stm32l4p5g-dk.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 96KB set WORKAREASIZE 0x18000 # enable stmqspi set OCTOSPI1 1 set OCTOSPI2 0 source [find target/stm32l4x.cfg] # OCTOSPI initialization # octo: 8-line mode proc octospi_init { octo } { global a b mmw 0x4002104C 0x001001FF 0 ;# RCC_AHB2ENR |= OSPIMEN, GPIOAEN-GPIOIEN (enable clocks) mmw 0x40021050 0x00000300 0 ;# RCC_AHB3ENR |= OSPI2EN, OSPI1EN (enable clocks) mmw 0x40021058 0x10000000 0 ;# RCC_APB1ENR1 |= PWREN (enable clock) sleep 1 ;# Wait for clock startup mmw 0x40007004 0x00000200 0 ;# PWR_CR2 |= IOSV (required for use of GPOIG, cf. RM0432) mww 0x50061C04 0x07050333 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI2 mww 0x50061C08 0x03010111 ;# OCTOSPIM_P2CR: assign Port 2 to OCTOSPI1 # PE11: P1_NCS, PE10: P1_CLK, PG06: P1_DQS, PD07: P1_IO7, PC03: P1_IO6, PD05: P1_IO5 # PD04: P1_IO4, PA06: P1_IO3, PA07: P1_IO2, PE13: P1_IO1, PE11: P1_IO0 # PA07:AF10:V, PA06:AF10:V, PC03:AF10:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V # PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V, PG06:AF03:V # Port A: PA07:AF10:V, PA06:AF10:V mmw 0x48000000 0x0000A000 0x00005000 ;# MODER mmw 0x48000008 0x0000F000 0x00000000 ;# OSPEEDR mmw 0x4800000C 0x00000000 0x0000F000 ;# PUPDR mmw 0x48000020 0xAA000000 0x55000000 ;# AFRL # Port C: PC03:AF10:V mmw 0x48000800 0x00000080 0x00000040 ;# MODER mmw 0x48000808 0x000000C0 0x00000000 ;# OSPEEDR mmw 0x4800080C 0x00000000 0x000000C0 ;# PUPDR mmw 0x48000820 0x0000A000 0x00005000 ;# AFRL # Port D: PD07:AF10:V, PD05:AF10:V, PD04:AF10:V mmw 0x48000C00 0x00008A00 0x00004500 ;# MODER mmw 0x48000C08 0x0000CF00 0x00000000 ;# OSPEEDR mmw 0x48000C0C 0x00000000 0x0000CF00 ;# PUPDR mmw 0x48000C20 0xA0AA0000 0x50550000 ;# AFRL # Port E: PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V mmw 0x48001000 0x0AA00000 0x05500000 ;# MODER mmw 0x48001008 0x0FF00000 0x00000000 ;# OSPEEDR mmw 0x4800100C 0x00000000 0x0FF00000 ;# PUPDR mmw 0x48001024 0x00AAAA00 0x00555500 ;# AFRH # Port G: PG06:AF03:V mmw 0x48001800 0x00002000 0x00001000 ;# MODER mmw 0x48001808 0x00003000 0x00000000 ;# OSPEEDR mmw 0x4800180C 0x00000000 0x00003000 ;# PUPDR mmw 0x48001820 0x03000000 0x0C000000 ;# AFRL # PG12: P2_NCS, PF04: P2_CLK, PF12: P2_DQS, PG10: P2_IO7, PG09: P2_IO6, PG01: P2_IO5 # PG00: P2_IO4, PF03: P2_IO3, PF02: P2_IO2, PF01: P2_IO1, PF00: P2_IO0 # PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V # PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V # Port F: PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V mmw 0x48001400 0x020002AA 0x01000155 ;# MODER mmw 0x48001408 0x030003FF 0x00000000 ;# OSPEEDR mmw 0x4800140C 0x00000000 0x030003FF ;# PUPDR mmw 0x48001420 0x00055555 0x000AAAAA ;# AFRL mmw 0x48001424 0x00050000 0x000A0000 ;# AFRH # Port G: PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V mmw 0x48001800 0x0228000A 0x01140005 ;# MODER mmw 0x48001808 0x033C000F 0x00000000 ;# OSPEEDR mmw 0x4800180C 0x00000000 0x033C000F ;# PUPDR mmw 0x48001820 0x00000055 0x000000AA ;# AFRL mmw 0x48001824 0x00050550 0x000A0AA0 ;# AFRH # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses mww 0xA0001130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 mww 0xA0001008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 mww 0xA000100C 0x00000001 ;# OCTOSPI_DCR2: PRESCALER=1 mww 0xA0001108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 mww 0xA0001100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 mww 0xA0001110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B if { $octo == 1 } { stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 ;# Read Status Register stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 mww 0xA0001108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 mww 0xA0001100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 mww 0xA0001110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 0 0x04 ;# Write Disable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits } } $_TARGETNAME configure -event reset-init { mmw 0x40022000 0x00000003 0x0000000C ;# 3 WS for 72 MHz HCLK sleep 1 mmw 0x40021000 0x00000100 0x00000000 ;# HSI on mww 0x4002100C 0x01002432 ;# RCC_PLLCFGR 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 mmw 0x40021000 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL sleep 1 adapter speed 24000 octospi_init 1 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32l4r9i-disco.cfg ================================================ # This is a STM32L4R9I discovery board with a single STM32L4R9AII6 chip. # http://www.st.com/en/evaluation-tools/32l4r9idiscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 96KB set WORKAREASIZE 0x18000 # enable stmqspi set OCTOSPI1 1 set OCTOSPI2 0 source [find target/stm32l4x.cfg] # OCTOSPI initialization # octo: 8-line mode proc octospi_init { octo } { global a b mmw 0x4002104C 0x001001FF 0 ;# RCC_AHB2ENR |= OSPIMEN, GPIOAEN-GPIOIEN (enable clocks) mmw 0x40021050 0x00000300 0 ;# RCC_AHB3ENR |= OSPI2EN, OSPI1EN (enable clocks) mmw 0x40021058 0x10000000 0 ;# RCC_APB1ENR1 |= PWREN (enable clock) sleep 1 ;# Wait for clock startup mmw 0x40007004 0x00000200 0 ;# PWR_CR2 |= IOSV (required for use of GPOIG, cf. RM0432) mww 0x50061C04 0x00000000 ;# OCTOSPIM_P1CR: disable Port 1 mww 0x50061C08 0x03010111 ;# OCTOSPIM_P2CR: assign Port 2 to OCTOSPI1 # PG12: P2_NCS, PI06: P2_CLK, PG15: P2_DQS, PG10: P2_IO7, PG09: P2_IO6, PH10: P2_IO5, # PH09: P2_IO4, PH08: P2_IO3, PI09: P2_IO2, PI10: P2_IO1, PI11: P2_IO0 # PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PH10:AF05:V, PH09:AF05:V # PH08:AF05:V, PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V # Port G: PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V mmw 0x48001800 0x82280000 0x41140000 ;# MODER mmw 0x48001808 0xC33C0000 0x00000000 ;# OSPEEDR mmw 0x48001824 0x50050550 0xA00A0AA0 ;# AFRH # Port H: PH10:AF05:V, PH09:AF05:V, PH08:AF05:V mmw 0x48001C00 0x002A0000 0x00150000 ;# MODER mmw 0x48001C08 0x003F0000 0x00000000 ;# OSPEEDR mmw 0x48001C24 0x00000555 0x00000AAA ;# AFRH # Port I: PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V mmw 0x48002000 0x00A82000 0x00541000 ;# MODER mmw 0x48002008 0x00FC3000 0x00000000 ;# OSPEEDR mmw 0x48002020 0x05000000 0x0A000000 ;# AFRL mmw 0x48002024 0x00005550 0x0000AAA0 ;# AFRH # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses mww 0xA0001130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 mww 0xA0001008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 mww 0xA000100C 0x00000001 ;# OCTOSPI_DCR2: PRESCALER=1 mww 0xA0001108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 mww 0xA0001100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 mww 0xA0001110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B if { $octo == 1 } { stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 ;# Read Status Register stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 mww 0xA0001108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 mww 0xA0001100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 mww 0xA0001110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 0 0x04 ;# Write Disable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits } } $_TARGETNAME configure -event reset-init { mmw 0x40022000 0x00000003 0x0000000C ;# 3 WS for 72 MHz HCLK sleep 1 mmw 0x40021000 0x00000100 0x00000000 ;# HSI on mww 0x4002100C 0x01002432 ;# RCC_PLLCFGR 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 mmw 0x40021000 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 octospi_init 1 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32ldiscovery.cfg ================================================ # This is an STM32L discovery board with a single STM32L152RBT6 chip. # http://www.st.com/internet/evalboard/product/250990.jsp source [find interface/stlink.cfg] transport select hla_swd set WORKAREASIZE 0x4000 source [find target/stm32l1.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32mp13x_dk.cfg ================================================ # board MB1635x # http://www.st.com/en/evaluation-tools/stm32mp135f-dk.html source [find interface/stlink-dap.cfg] transport select dapdirect_swd source [find target/stm32mp13x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32mp15x_dk2.cfg ================================================ # board MB1272B # http://www.st.com/en/evaluation-tools/stm32mp157a-dk1.html # http://www.st.com/en/evaluation-tools/stm32mp157c-dk2.html source [find interface/stlink-dap.cfg] transport select dapdirect_swd source [find target/stm32mp15x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/stm32vldiscovery.cfg ================================================ # This is an STM32VL discovery board with a single STM32F100RB chip. # http://www.st.com/internet/evalboard/product/250863.jsp source [find interface/stlink.cfg] transport select hla_swd set WORKAREASIZE 0x2000 source [find target/stm32f1x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/str910-eval.cfg ================================================ # str910-eval eval board # # Need reset scripts reset_config trst_and_srst # FIXME use some standard target config, maybe create one from this # # source [find target/...cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME str912 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists FLASHTAPID] } { set _FLASHTAPID $FLASHTAPID } else { set _FLASHTAPID 0x04570041 } jtag newtap $_CHIPNAME flash -irlen 8 -ircapture 0x1 -irmask 0x1 -expected-id $_FLASHTAPID if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x25966041 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID if { [info exists BSTAPID] } { set _BSTAPID $BSTAPID } else { set _BSTAPID 0x1457f041 } jtag newtap $_CHIPNAME bs -irlen 5 -ircapture 0x1 -irmask 0x1 -expected-id $_BSTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x50000000 -work-area-size 16384 -work-area-backup 1 $_TARGETNAME configure -event reset-init { # We can increase speed now that we know the target is halted. #jtag_rclk 3000 # -- Enable 96K RAM # PFQBC enabled / DTCM & AHB wait-states disabled mww 0x5C002034 0x0191 str9x flash_config 0 4 2 0 0x80000 flash protect 0 0 7 off } #flash bank str9x 0 0 set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME str9x 0x00000000 0x00080000 0 0 0 set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME str9x 0x00080000 0x00008000 0 0 0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/telo.cfg ================================================ source [find target/c100.cfg] # basic register definition for C100 source [find target/c100regs.tcl] # board-config info source [find target/c100config.tcl] # C100 helper functions source [find target/c100helper.tcl] # Telo board & C100 support trst and srst # make the reset asserted to # allow RC circuit to discharge for: [ms] adapter srst pulse_width 100 jtag_ntrst_assert_width 100 # don't talk to JTAG after reset for: [ms] adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst separate # issue telnet: reset init # issue gdb: monitor reset init $_TARGETNAME configure -event reset-init { adapter speed 100 # this will setup Telo board setupTelo #turn up the JTAG speed adapter speed 3000 echo "JTAG speek now 3MHz" echo "type helpC100 to get help on C100" } $_TARGETNAME configure -event reset-deassert-post { # Force target into ARM state. # soft_reset_halt ;# not implemented on ARM11 echo "Detected SRSRT asserted on C100.CPU" } $_TARGETNAME configure -event reset-assert-post { echo "Assering reset" #sleep 10 } proc power_restore {} { echo "Sensed power restore. No action." } proc srst_deasserted {} { echo "Sensed nSRST deasserted. No action." } # boots from NOR on CS0: 8 MBytes CFI flash, 16-bit bus # it's really 16MB but the upper 8mb is controller via gpio # openocd does not support 'complex reads/writes' to NOR set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x20000000 0x01000000 2 2 $_TARGETNAME # writing data to memory does not work without this arm11 memwrite burst disable ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_am335xevm.cfg ================================================ # # TI AM335x Evaluation Module # # For more information please see http://www.ti.com/tool/tmdxevm3358 # jtag_rclk 6000 source [find target/am335x.cfg] reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_am437x_idk.cfg ================================================ # Texas Instruments AM437x Industrial Development Kit # The JTAG interface is built directly on the board. source [find interface/ftdi/xds100v2.cfg] transport select jtag adapter speed 30000 source [find target/am437x.cfg] $_TARGETNAME configure -event reset-init { init_platform 0x61a11b32 } reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_am43xx_evm.cfg ================================================ # Works on both AM437x GP EVM and AM438x ePOS EVM transport select jtag adapter speed 16000 source [find target/am437x.cfg] reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_am625evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2021-2022 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments am625 EVM/SK # Link: https://www.ti.com/lit/zip/sprr448 # # AM625 EVM has an xds110 onboard. source [find interface/xds110.cfg] transport select jtag # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive adapter srst delay 20 if { ![info exists SOC] } { set SOC am625 } source [find target/ti_k3.cfg] adapter speed 2500 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_am642evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments AM642 EVM # # AM642 EVM has an xds110 onboard. source [find interface/xds110.cfg] transport select jtag # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive adapter srst delay 20 if { ![info exists SOC] } { set SOC am642 } source [find target/ti_k3.cfg] adapter speed 250 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_am654evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments AM654 EVM/IDK Base Board # # AM654 EVM has an xds110 onboard. source [find interface/xds110.cfg] transport select jtag # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive adapter srst delay 70 if { ![info exists SOC] } { set SOC am654 } source [find target/ti_k3.cfg] adapter speed 2500 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_beagleboard.cfg ================================================ # OMAP3 BeagleBoard # http://beagleboard.org # Fall back to 6MHz if RTCK is not supported jtag_rclk 6000 source [find target/omap3530.cfg] # TI-14 JTAG connector reset_config trst_only # Later run: omap3_dbginit ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_beagleboard_xm.cfg ================================================ # BeagleBoard xM (DM37x) # http://beagleboard.org set CHIPTYPE "dm37x" source [find target/amdm37x.cfg] # The TI-14 JTAG connector does not have srst. CPU reset is handled in # hardware. reset_config trst_only # "amdm37x_dbginit dm37x.cpu" needs to be run after init. ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_beaglebone-base.cfg ================================================ # AM335x Beaglebone family base configuration # http://beagleboard.org/bone source [find target/am335x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_beaglebone.cfg ================================================ # AM335x Beaglebone # http://beagleboard.org/bone # The JTAG interface is built directly on the board. source [find interface/ftdi/xds100v2.cfg] adapter speed 16000 reset_config trst_and_srst source [find board/ti_beaglebone-base.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_beaglebone_black.cfg ================================================ # AM335x Beaglebone Black # http://beagleboard.org/bone adapter speed 1000 reset_config trst_and_srst source [find board/ti_beaglebone-base.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_blaze.cfg ================================================ jtag_rclk 6000 source [find target/omap4430.cfg] reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_cc13x0_launchpad.cfg ================================================ # # TI CC13x0 LaunchPad Evaluation Kit # source [find interface/xds110.cfg] transport select jtag adapter speed 5500 source [find target/ti_cc13x0.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_cc13x2_launchpad.cfg ================================================ # # TI CC13x2 LaunchPad Evaluation Kit # source [find interface/xds110.cfg] adapter speed 5500 transport select jtag source [find target/ti_cc13x2.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_cc26x0_launchpad.cfg ================================================ # # TI CC26x0 LaunchPad Evaluation Kit # source [find interface/xds110.cfg] adapter speed 5500 transport select jtag source [find target/ti_cc26x0.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_cc26x2_launchpad.cfg ================================================ # # TI CC26x2 LaunchPad Evaluation Kit # source [find interface/xds110.cfg] adapter speed 5500 transport select jtag source [find target/ti_cc26x2.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_cc3200_launchxl.cfg ================================================ # # TI SimpleLink Wi-Fi CC3200 LaunchPad # # http://www.ti.com/tool/cc3200-launchxl # source [find interface/ftdi/ti-icdi.cfg] if { [info exists TRANSPORT] } { transport select $TRANSPORT } else { transport select jtag } adapter speed 2500 set WORKAREASIZE 0x40000 source [find target/ti_cc32xx.cfg] reset_config srst_only adapter srst delay 1100 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_cc3220sf_launchpad.cfg ================================================ # # TI CC3220SF-LaunchXL LaunchPad Evaluation Kit # source [find interface/xds110.cfg] adapter speed 8500 transport select swd source [find target/ti_cc3220sf.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_cc32xx_launchpad.cfg ================================================ # # TI CC32xx-LaunchXL LaunchPad Evaluation Kit # source [find interface/xds110.cfg] adapter speed 8500 transport select swd source [find target/ti_cc32xx.cfg] reset_config srst_only adapter srst delay 1100 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_dk-tm4c129.cfg ================================================ # # TI Tiva C DK-TM4C129X Connected Development Kit # # http://www.ti.com/tool/dk-tm4c129x # source [find interface/ti-icdi.cfg] transport select hla_jtag set WORKAREASIZE 0x8000 set CHIPNAME tm4c129xnczad source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_ek-tm4c123gxl.cfg ================================================ # # TI Tiva C Series ek-tm4c123gxl Launchpad Evaluation Kit # # http://www.ti.com/tool/ek-tm4c123gxl # source [find interface/ti-icdi.cfg] transport select hla_jtag set WORKAREASIZE 0x8000 set CHIPNAME tm4c123gh6pm source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_ek-tm4c1294xl.cfg ================================================ # # TI Tiva C Series ek-tm4c1294xl Launchpad Evaluation Kit # # http://www.ti.com/tool/ek-tm4c1294xl # source [find interface/ti-icdi.cfg] transport select hla_jtag set WORKAREASIZE 0x8000 set CHIPNAME tm4c1294ncpdt source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_j7200evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments J7200 EVM # # J7200 EVM has an xds110 onboard. source [find interface/xds110.cfg] transport select jtag # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive adapter srst delay 20 if { ![info exists SOC] } { set SOC j7200 } source [find target/ti_k3.cfg] adapter speed 2500 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_j721evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments J721E EVM # # J721E EVM has an xds110 onboard. source [find interface/xds110.cfg] transport select jtag # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive adapter srst delay 20 if { ![info exists SOC] } { set SOC j721e } source [find target/ti_k3.cfg] adapter speed 2500 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_j721s2evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments J721s2 EVM # Link(SoM): https://www.ti.com/lit/zip/sprr439 # # J721s2 EVM has an xds110 onboard. source [find interface/xds110.cfg] transport select jtag # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive adapter srst delay 20 if { ![info exists SOC] } { set SOC j721s2 } source [find target/ti_k3.cfg] adapter speed 2500 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_msp432_launchpad.cfg ================================================ # # TI MSP432 LaunchPad Evaluation Kit # source [find interface/xds110.cfg] adapter speed 10000 transport select swd source [find target/ti_msp432.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_pandaboard.cfg ================================================ jtag_rclk 6000 source [find target/omap4430.cfg] reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_pandaboard_es.cfg ================================================ jtag_rclk 6000 source [find target/omap4460.cfg] reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_tmdx570ls20susb.cfg ================================================ # TMS570 Microcontroller USB Kit # http://www.ti.com/tool/TMDX570LS20SUSB # Board uses a FT2232H to emulate an XDS100v2 JTAG debugger # TODO: board also supports an SCI UART on the 2232's B Bus source [find interface/ftdi/xds100v2.cfg] # Processor is TMS570LS20216 source [find target/ti_tms570ls20xxx.cfg] reset_config trst_only # xds100v2 config says add this to the end init ftdi set_signal PWR_RST 1 jtag arp_init ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/ti_tmdx570ls31usb.cfg ================================================ adapter speed 1500 source [find interface/ftdi/xds100v2.cfg] source [find target/ti_tms570.cfg] reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/tocoding_poplar.cfg ================================================ # # board configuration for Tocoding Poplar # # board does not feature anything but JTAG transport select jtag adapter speed 10000 # SRST-only reset configuration reset_config srst_only srst_push_pull source [find target/hi3798.cfg] # make sure the default target is the boot core targets ${_TARGETNAME}0 proc core_up { args } { global _TARGETNAME # examine remaining cores foreach _core $args { ${_TARGETNAME}$_core arp_examine } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/topas910.cfg ================================================ ###################################### # Target: Toshiba TOPAS910 -- TMPA910 Starterkit # ###################################### # We add to the minimal configuration. source [find target/tmpa910.cfg] ###################### # Target configuration ###################### #$_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { topas910_init } proc topas910_init { } { # Init PLL # my settings mww 0xf005000c 0x00000007 mww 0xf0050010 0x00000065 mww 0xf005000c 0x000000a7 sleep 10 mdw 0xf0050008 mww 0xf0050008 0x00000002 mww 0xf0050004 0x00000000 # NEW: set CLKCR5 mww 0xf0050054 0x00000040 # sleep 10 # Init SDRAM # _PMCDRV = 0x00000071; # // # // Initialize SDRAM timing parameter # // # _DMC_CAS_LATENCY = 0x00000006; # _DMC_T_DQSS = 0x00000000; # _DMC_T_MRD = 0x00000002; # _DMC_T_RAS = 0x00000007; # # _DMC_T_RC = 0x0000000A; # _DMC_T_RCD = 0x00000013; # # _DMC_T_RFC = 0x0000010A; # # _DMC_T_RP = 0x00000013; # _DMC_T_RRD = 0x00000002; # _DMC_T_WR = 0x00000002; # _DMC_T_WTR = 0x00000001; # _DMC_T_XP = 0x0000000A; # _DMC_T_XSR = 0x0000000B; # _DMC_T_ESR = 0x00000014; # # // # // Configure SDRAM type parameter # _DMC_MEMORY_CFG = 0x00008011; # _DMC_USER_CONFIG = 0x00000011; # // 32 bit memory interface # # # _DMC_REFRESH_PRD = 0x00000A60; # _DMC_CHIP_0_CFG = 0x000140FC; # # _DMC_DIRECT_CMD = 0x000C0000; # _DMC_DIRECT_CMD = 0x00000000; # # _DMC_DIRECT_CMD = 0x00040000; # _DMC_DIRECT_CMD = 0x00040000; # _DMC_DIRECT_CMD = 0x00080031; # // # // Finally start SDRAM # // # _DMC_MEMC_CMD = MEMC_CMD_GO; # */ mww 0xf0020260 0x00000071 mww 0xf4300014 0x00000006 mww 0xf4300018 0x00000000 mww 0xf430001C 0x00000002 mww 0xf4300020 0x00000007 mww 0xf4300024 0x0000000A mww 0xf4300028 0x00000013 mww 0xf430002C 0x0000010A mww 0xf4300030 0x00000013 mww 0xf4300034 0x00000002 mww 0xf4300038 0x00000002 mww 0xf430003C 0x00000001 mww 0xf4300040 0x0000000A mww 0xf4300044 0x0000000B mww 0xf4300048 0x00000014 mww 0xf430000C 0x00008011 mww 0xf4300304 0x00000011 mww 0xf4300010 0x00000A60 mww 0xf4300200 0x000140FC mww 0xf4300008 0x000C0000 mww 0xf4300008 0x00000000 mww 0xf4300008 0x00040000 mww 0xf4300008 0x00040000 mww 0xf4300008 0x00080031 mww 0xf4300004 0x00000000 sleep 10 # adapter speed NNNN # remap off in case of IROM boot mww 0xf0000004 0x00000001 } # comment the following out if usinf J-Link, it soes not support DCC arm7_9 dcc_downloads enable ;# Enable faster DCC downloads ##################### # Flash configuration ##################### #flash bank cfi set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x20000000 0x2000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/topasa900.cfg ================================================ # Thanks to Pieter Conradie for this script! # Target: Toshiba TOPAS900 -- TMPA900 Starterkit ###################################### # We add to the minimal configuration. source [find target/tmpa900.cfg] ###################### # Target configuration ###################### #$_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { topasa900_init } proc topasa900_init { } { # Init PLL # my settings mww 0xf005000c 0x00000007 mww 0xf0050010 0x00000065 mww 0xf005000c 0x000000a7 sleep 10 mdw 0xf0050008 mww 0xf0050008 0x00000002 mww 0xf0050004 0x00000000 # NEW: set CLKCR5 mww 0xf0050054 0x00000040 # # bplan settings # mww 0xf0050004 0x00000000 # mww 0xf005000c 0x000000a7 # sleep 10 # mdw 0xf0050008 # mww 0xf0050008 0x00000002 # mww 0xf0050010 0x00000065 # mww 0xf0050054 0x00000040 sleep 10 # Init SDRAM # _PMCDRV = 0x00000071; # // # // Initialize SDRAM timing parameter # // # _DMC_CAS_LATENCY = 0x00000006; # _DMC_T_DQSS = 0x00000000; # _DMC_T_MRD = 0x00000002; # _DMC_T_RAS = 0x00000007; # # _DMC_T_RC = 0x0000000A; # _DMC_T_RCD = 0x00000013; # # _DMC_T_RFC = 0x0000010A; # # _DMC_T_RP = 0x00000013; # _DMC_T_RRD = 0x00000002; # _DMC_T_WR = 0x00000002; # _DMC_T_WTR = 0x00000001; # _DMC_T_XP = 0x0000000A; # _DMC_T_XSR = 0x0000000B; # _DMC_T_ESR = 0x00000014; # # // # // Configure SDRAM type parameter # _DMC_MEMORY_CFG = 0x00008011; # _DMC_USER_CONFIG = 0x00000011; // 32 bit memory interface # # # _DMC_REFRESH_PRD = 0x00000A60; # _DMC_CHIP_0_CFG = 0x000140FC; # # _DMC_DIRECT_CMD = 0x000C0000; # _DMC_DIRECT_CMD = 0x00000000; # # _DMC_DIRECT_CMD = 0x00040000; # _DMC_DIRECT_CMD = 0x00040000; # _DMC_DIRECT_CMD = 0x00080031; # // # // Finally start SDRAM # // # _DMC_MEMC_CMD = MEMC_CMD_GO; # */ mww 0xf0020260 0x00000071 mww 0xf4300014 0x00000006 mww 0xf4300018 0x00000000 mww 0xf430001C 0x00000002 mww 0xf4300020 0x00000007 mww 0xf4300024 0x0000000A mww 0xf4300028 0x00000013 mww 0xf430002C 0x0000010A mww 0xf4300030 0x00000013 mww 0xf4300034 0x00000002 mww 0xf4300038 0x00000002 mww 0xf430003C 0x00000001 mww 0xf4300040 0x0000000A mww 0xf4300044 0x0000000B mww 0xf4300048 0x00000014 mww 0xf430000C 0x00008011 mww 0xf4300304 0x00000011 mww 0xf4300010 0x00000A60 mww 0xf4300200 0x000140FC mww 0xf4300008 0x000C0000 mww 0xf4300008 0x00000000 mww 0xf4300008 0x00040000 mww 0xf4300008 0x00040000 mww 0xf4300008 0x00080031 mww 0xf4300004 0x00000000 sleep 10 # adapter speed NNNN # remap off in case of IROM boot mww 0xf0000004 0x00000001 } # comment the following out if usinf J-Link, it soes not support DCC arm7_9 dcc_downloads enable ;# Enable faster DCC downloads ##################### # Flash configuration ##################### #flash bank cfi set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x20000000 0x1000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/tp-link_tl-mr3020.cfg ================================================ source [find target/atheros_ar9331.cfg] $_TARGETNAME configure -event reset-init { ar9331_25mhz_pll_init sleep 1 ar9331_ddr1_init } set ram_boot_address 0xa0000000 $_TARGETNAME configure -work-area-phys 0xa1FFE000 -work-area-size 0x1000 flash bank flash0 ath79 0xbf000000 0 0 0 $_TARGETNAME cs0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/tp-link_wdr4300.cfg ================================================ source [find target/atheros_ar9344.cfg] reset_config trst_only separate proc ar9344_40mhz_pll_init {} { # QCA_PLL_SRIF_CPU_DPLL2_REG mww 0xb81161C4 0x13210f00 # QCA_PLL_SRIF_CPU_DPLL3_REG mww 0xb81161C8 0x03000000 # QCA_PLL_SRIF_DDR_DPLL2_REG mww 0xb8116244 0x13210f00 # QCA_PLL_SRIF_DDR_DPLL3_REG mww 0xb8116248 0x03000000 # QCA_PLL_SRIF_BB_DPLL_BASE_REG mww 0xb8116188 0x03000000 # QCA_PLL_CPU_DDR_CLK_CTRL_REG mww 0xb8050008 0x0130001C mww 0xb8050008 0x0130001C mww 0xb8050008 0x0130001C # QCA_PLL_CPU_PLL_CFG_REG mww 0xb8050000 0x40021380 # QCA_PLL_DDR_PLL_CFG_REG mww 0xb8050004 0x40815800 # QCA_PLL_CPU_DDR_CLK_CTRL_REG mww 0xb8050008 0x0130801C # QCA_PLL_SRIF_CPU_DPLL2_REG mww 0xb81161C4 0x10810F00 mww 0xb81161C0 0x41C00000 # QCA_PLL_SRIF_CPU_DPLL2_REG mww 0xb81161C4 0xD0810F00 # QCA_PLL_SRIF_CPU_DPLL3_REG mww 0xb81161C8 0x03000000 # QCA_PLL_SRIF_CPU_DPLL2_REG mww 0xb81161C4 0xD0800F00 # QCA_PLL_SRIF_CPU_DPLL3_REG mww 0xb81161C8 0x03000000 # QCA_PLL_SRIF_CPU_DPLL3_REG mww 0xb81161C8 0x43000000 # QCA_PLL_SRIF_CPU_DPLL3_REG mww 0xb81161C8 0x030003E8 # QCA_PLL_SRIF_DDR_DPLL2_REG mww 0xb8116244 0x10810F00 mww 0xb8116240 0x41680000 # QCA_PLL_SRIF_DDR_DPLL2_REG mww 0xb8116244 0xD0810F00 # QCA_PLL_SRIF_DDR_DPLL3_REG mww 0xb8116248 0x03000000 # QCA_PLL_SRIF_DDR_DPLL2_REG mww 0xb8116244 0xD0800F00 # QCA_PLL_SRIF_DDR_DPLL3_REG mww 0xb8116248 0x03000000 # QCA_PLL_SRIF_DDR_DPLL3_REG mww 0xb8116248 0x43000000 # QCA_PLL_SRIF_DDR_DPLL3_REG mww 0xb8116248 0x03000718 # QCA_PLL_CPU_DDR_CLK_CTRL_REG mww 0xb8050008 0x01308018 mww 0xb8050008 0x01308010 mww 0xb8050008 0x01308000 # QCA_PLL_DDR_PLL_DITHER_REG mww 0xb8050044 0x78180200 # QCA_PLL_CPU_PLL_DITHER_REG mww 0xb8050048 0x41C00000 } proc ar9344_ddr_init {} { # QCA_DDR_CTRL_CFG_REG mww 0xb8000108 0x40 # QCA_DDR_RD_DATA_THIS_CYCLE_REG mww 0xb8000018 0xFF # QCA_DDR_BURST_REG mww 0xb80000C4 0x74444444 # QCA_DDR_BURST2_REG mww 0xb80000C8 0x0222 # QCA_AHB_MASTER_TOUT_MAX_REG mww 0xb80000CC 0xFFFFF # QCA_DDR_CFG_REG mww 0xb8000000 0xC7D48CD0 # QCA_DDR_CFG2_REG mww 0xb8000004 0x9DD0E6A8 # QCA_DDR_DDR2_CFG_REG mww 0xb80000B8 0x0E59 # QCA_DDR_CFG2_REG mww 0xb8000004 0x9DD0E6A8 # QCA_DDR_CTRL_REG mww 0xb8000010 0x08 mww 0xb8000010 0x08 mww 0xb8000010 0x10 mww 0xb8000010 0x20 # QCA_DDR_EMR_REG mww 0xb800000C 0x02 # QCA_DDR_CTRL_REG mww 0xb8000010 0x02 # QCA_DDR_MR_REG mww 0xb8000008 0x0133 # QCA_DDR_CTRL_REG mww 0xb8000010 0x1 mww 0xb8000010 0x8 mww 0xb8000010 0x8 mww 0xb8000010 0x4 mww 0xb8000010 0x4 # QCA_DDR_MR_REG mww 0xb8000008 0x33 # QCA_DDR_CTRL_REG mww 0xb8000010 0x1 # QCA_DDR_EMR_REG mww 0xb800000C 0x0382 # QCA_DDR_CTRL_REG mww 0xb8000010 0x2 # QCA_DDR_EMR_REG mww 0xb800000C 0x0402 # QCA_DDR_CTRL_REG mww 0xb8000010 0x2 # QCA_DDR_REFRESH_REG mww 0xb8000014 0x4270 # QCA_DDR_TAP_CTRL_0_REG mww 0xb800001C 0x0e # QCA_DDR_TAP_CTRL_1_REG mww 0xb8000020 0x0e # QCA_DDR_TAP_CTRL_2_REG mww 0xb8000024 0x0e # QCA_DDR_TAP_CTRL_3_REG mww 0xb8000028 0x0e } $_TARGETNAME configure -event reset-init { # mww 0xb806001c 0x1000000 ar9344_40mhz_pll_init sleep 100 # flash remap # SPI_CONTROL_ADDR mww 0xbF000004 0x43 ar9344_ddr_init sleep 100 } set ram_boot_address 0xa0000000 $_TARGETNAME configure -work-area-phys 0x1d000000 -work-area-size 0x1000 flash bank flash0 ath79 0xbf000000 0 0 0 $_TARGETNAME cs0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/twr-k60f120m.cfg ================================================ # # Freescale TWRK60F120M development board # source [find target/k60.cfg] $_TARGETNAME configure -event reset-init { puts "-event reset-init occurred" } # # Definitions for the additional 'program flash' banks # (instructions and/or data) # flash bank pflash.1 kinetis 0x00040000 0x40000 0 4 $_TARGETNAME flash bank pflash.2 kinetis 0x00080000 0x40000 0 4 $_TARGETNAME flash bank pflash.3 kinetis 0x000c0000 0x40000 0 4 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/twr-k60n512.cfg ================================================ # # Freescale TWRK60N512 development board # source [find target/k60.cfg] $_TARGETNAME configure -event reset-init { puts "-event reset-init occurred" } # # Definitions for the additional 'program flash' bank # (instructions and/or data) # flash bank pflash.1 kinetis 0x00040000 0x40000 0 4 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/twr-vf65gs10.cfg ================================================ # # Board configuration file for the Freescale VF65GS10 tower board # # Board has a 20 pin Cortex+ETM debug connector with only nSRST available reset_config srst_only # This configuration file only deals with the hardware JTAG. # There is has also an embedded Kinetis K20 with OpenSDA # where a CMSIS-DAP application can be installed. # Source generic VF6xx target configuration source [find target/vybrid_vf6xx.cfg] # basic DDR memory init, setting up pad configuration # for DDR first then configuring the DDRMC for the # board proc ddr_init { } { # iomux ddr mww phys 0x40048220 0x00000180 mww phys 0x40048224 0x00000180 mww phys 0x40048228 0x00000180 mww phys 0x4004822c 0x00000180 mww phys 0x40048230 0x00000180 mww phys 0x40048234 0x00000180 mww phys 0x40048238 0x00000180 mww phys 0x4004823c 0x00000180 mww phys 0x40048240 0x00000180 mww phys 0x40048244 0x00000180 mww phys 0x40048248 0x00000180 mww phys 0x4004824c 0x00000180 mww phys 0x40048250 0x00000180 mww phys 0x40048254 0x00000180 mww phys 0x40048258 0x00000180 mww phys 0x4004825c 0x00000180 mww phys 0x40048260 0x00000180 mww phys 0x40048264 0x00000180 mww phys 0x40048268 0x00000180 mww phys 0x4004826c 0x00000180 mww phys 0x40048270 0x00000180 mww phys 0x40048274 0x00000180 mww phys 0x40048278 0x00000180 mww phys 0x4004827c 0x00010180 mww phys 0x40048280 0x00010180 mww phys 0x40048284 0x00010180 mww phys 0x40048288 0x00010180 mww phys 0x4004828c 0x00010180 mww phys 0x40048290 0x00010180 mww phys 0x40048294 0x00010180 mww phys 0x40048298 0x00010180 mww phys 0x4004829c 0x00010180 mww phys 0x400482a0 0x00010180 mww phys 0x400482a4 0x00010180 mww phys 0x400482a8 0x00010180 mww phys 0x400482ac 0x00010180 mww phys 0x400482b0 0x00010180 mww phys 0x400482b4 0x00010180 mww phys 0x400482b8 0x00010180 mww phys 0x400482bc 0x00010180 mww phys 0x400482c0 0x00010180 mww phys 0x400482c4 0x00010180 mww phys 0x400482c8 0x00010180 mww phys 0x400482cc 0x00000180 mww phys 0x400482d0 0x00000180 mww phys 0x400482d4 0x00000180 mww phys 0x400482d8 0x00000180 mww phys 0x4004821c 0x000001a0 # ddr_ctrl_init mww phys 0x400ae000 0x00000600 mww phys 0x400ae008 0x00000020 mww phys 0x400ae028 0x00013880 mww phys 0x400ae02c 0x00030d40 mww phys 0x400ae030 0x0000050c mww phys 0x400ae034 0x15040400 mww phys 0x400ae038 0x1406040f mww phys 0x400ae040 0x04040000 mww phys 0x400ae044 0x006db00c mww phys 0x400ae048 0x00000403 mww phys 0x400ae050 0x01000000 mww phys 0x400ae054 0x00060001 mww phys 0x400ae058 0x000c0000 mww phys 0x400ae05c 0x03000200 mww phys 0x400ae060 0x00000006 mww phys 0x400ae064 0x00010000 mww phys 0x400ae068 0x0c30002c mww phys 0x400ae070 0x00000000 mww phys 0x400ae074 0x00000003 mww phys 0x400ae078 0x0000000a mww phys 0x400ae07c 0x003001d4 mww phys 0x400ae084 0x00010000 mww phys 0x400ae088 0x00050500 mww phys 0x400ae098 0x00000000 mww phys 0x400ae09c 0x04001002 mww phys 0x400ae0a4 0x00000001 mww phys 0x400ae0c0 0x00460420 mww phys 0x400ae108 0x01000200 mww phys 0x400ae10c 0x00000040 mww phys 0x400ae114 0x00000200 mww phys 0x400ae118 0x00000040 mww phys 0x400ae120 0x00000000 mww phys 0x400ae124 0x0a010300 mww phys 0x400ae128 0x01014040 mww phys 0x400ae12c 0x01010101 mww phys 0x400ae130 0x03030100 mww phys 0x400ae134 0x01000101 mww phys 0x400ae138 0x0700000c mww phys 0x400ae13c 0x00000000 mww phys 0x400ae148 0x10000000 mww phys 0x400ae15c 0x01000000 mww phys 0x400ae160 0x00040000 mww phys 0x400ae164 0x00000002 mww phys 0x400ae16c 0x00020000 mww phys 0x400ae180 0x00002819 mww phys 0x400ae184 0x01000000 mww phys 0x400ae188 0x00000000 mww phys 0x400ae18c 0x00000000 mww phys 0x400ae198 0x00000000 mww phys 0x400ae1a4 0x00000c00 mww phys 0x400ae1a8 0x00000000 mww phys 0x400ae1b8 0x0000000c mww phys 0x400ae1c8 0x00000000 mww phys 0x400ae1cc 0x00000000 mww phys 0x400ae1d4 0x00000000 mww phys 0x400ae1d8 0x01010000 mww phys 0x400ae1e0 0x02020000 mww phys 0x400ae1e4 0x00000202 mww phys 0x400ae1e8 0x01010064 mww phys 0x400ae1ec 0x00010101 mww phys 0x400ae1f0 0x00000064 mww phys 0x400ae1f8 0x00000800 mww phys 0x400ae210 0x00000506 mww phys 0x400ae224 0x00020000 mww phys 0x400ae228 0x01000000 mww phys 0x400ae22c 0x04070303 mww phys 0x400ae230 0x00000040 mww phys 0x400ae23c 0x06000080 mww phys 0x400ae240 0x04070303 mww phys 0x400ae244 0x00000040 mww phys 0x400ae248 0x00000040 mww phys 0x400ae24c 0x000f0000 mww phys 0x400ae250 0x000f0000 mww phys 0x400ae25c 0x00000101 mww phys 0x400ae268 0x682c4000 mww phys 0x400ae26c 0x00000012 mww phys 0x400ae278 0x00000006 mww phys 0x400ae284 0x00010202 mww phys 0x400ae400 0x00002613 mww phys 0x400ae440 0x00002613 mww phys 0x400ae404 0x00002615 mww phys 0x400ae444 0x00002615 mww phys 0x400ae408 0x00210000 mww phys 0x400ae448 0x00210000 mww phys 0x400ae488 0x00210000 mww phys 0x400ae40c 0x0001012a mww phys 0x400ae44c 0x0001012a mww phys 0x400ae48c 0x0001012a mww phys 0x400ae410 0x00002400 mww phys 0x400ae450 0x00002400 mww phys 0x400ae490 0x00002400 mww phys 0x400ae4c4 0x00000000 mww phys 0x400ae4c8 0x00001100 mww phys 0x400ae4d0 0x00010101 mww phys 0x400ae000 0x00000601 } # clock control init, setting up basic # clocks proc clock_init { } { # captured from u-boot mww phys 0x4006b040 0xffffffff mww phys 0x4006b044 0xffffffff mww phys 0x4006b048 0xffffffff mww phys 0x4006b04c 0xffffffff mww phys 0x4006b050 0xffffffff mww phys 0x4006b058 0xffffffff mww phys 0x4006b05c 0xffffffff mww phys 0x4006b060 0xffffffff mww phys 0x4006b064 0xffffffff mww phys 0x4006b068 0xffffffff mww phys 0x40050030 0x00002001 mww phys 0x40050270 0x80002001 mww phys 0x4006b000 0x00011005 mww phys 0x4006b008 0x0001ff24 mww phys 0x4006b00c 0x00000810 mww phys 0x4006b010 0x00cc0000 mww phys 0x4006b014 0x01000000 mww phys 0x4006b018 0x20000000 mww phys 0x4006b01c 0x0000001f mww phys 0x4006b020 0x00000000 } # This function applies the initial configuration after a "reset init" # command proc board_init { } { clock_init ddr_init } # hook the init function into the reset-init event ${_TARGETNAME}0 configure -event reset-init { board_init } # set a slow default JTAG clock, can be overridden later adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/twr-vf65gs10_cmsisdap.cfg ================================================ # # Board configuration file for the Freescale VF65GS10 tower board # # CMSIS-DAP via USB-OTG connector # source [find interface/cmsis-dap.cfg] # only SWD is supported by the CMSIS-DAP on this board transport select swd # Source generic part of twr-vf65gs10 configuration source [find board/twr-vf65gs10.cfg] # override reset configuration reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/tx25_stk5.cfg ================================================ # ------------------------------------------------------------------------- # KaRo TX25 CPU Module on a StarterkitV base board # http://www.karo-electronics.com/tx25.html # ------------------------------------------------------------------------- source [find target/imx25.cfg] #------------------------------------------------------------------------- # Declare Nand #------------------------------------------------------------------------- nand device K9F1G08UOC mxc imx25.cpu mx25 hwecc biswap $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { tx25_init } proc tx25_init { } { #------------------------------------------------------------------------- # AIPS setup - Only setup MPROTx registers. The PACR default values are good. # Set all MPROTx to be non-bufferable, trusted for R/W, # not forced to user-mode. #------------------------------------------------------------------------- mww 0x43f00000 0x77777777 mww 0x43f00004 0x77777777 mww 0x53f00000 0x77777777 mww 0x53f00004 0x77777777 sleep 100 #------------------------------------------------------------------------- # MAX (Multi-Layer AHB Crossbar Switch) setup # MPR - priority for MX25 is (SDHC2/SDMA)>USBOTG>RTIC>IAHB>DAHB #------------------------------------------------------------------------- mww 0x43f04000 0x00043210 mww 0x43f04100 0x00043210 mww 0x43f04200 0x00043210 mww 0x43f04300 0x00043210 mww 0x43f04400 0x00043210 # SGPCR - always park on last master mww 0x43f04010 0x10 mww 0x43f04110 0x10 mww 0x43f04210 0x10 mww 0x43f04310 0x10 mww 0x43f04410 0x10 # MGPCR - restore default values mww 0x43f04800 0x0 mww 0x43f04900 0x0 mww 0x43f04a00 0x0 mww 0x43f04b00 0x0 mww 0x43f04c00 0x0 # Configure M3IF registers # M3IF Control Register (M3IFCTL) for MX25 # MRRP[0] = LCDC on priority list (1 << 0) = 0x00000001 # MRRP[1] = MAX1 not on priority list (0 << 1) = 0x00000000 # MRRP[2] = MAX0 not on priority list (0 << 2) = 0x00000000 # MRRP[3] = USB HOST not on priority list (0 << 3) = 0x00000000 # MRRP[4] = SDMA not on priority list (0 << 4) = 0x00000000 # MRRP[5] = SD/ATA/FEC not on priority list (0 << 5) = 0x00000000 # MRRP[6] = SCMFBC not on priority list (0 << 6) = 0x00000000 # MRRP[7] = CSI not on priority list (0 << 7) = 0x00000000 # ---------- # 0x00000001 mww 0xb8003000 0x00000001 #------------------------------------------------------------------------- # configure ARM CLK #------------------------------------------------------------------------- # Set the Clock CTL (HRM p. 355) mww 0x53F80008 0x20034000 # Setup Clock Gating CTL 0-2 (HRM p. 357) mww 0x53F8000C 0x1fffffff mww 0x53F80010 0xffffffff mww 0x53F80014 0x000fdfff #------------------------------------------------------------------------- # SDRAM initialization #------------------------------------------------------------------------- # set to 3.3v SDRAM mww 0x43FAC454 0x00000800 # reset (set up ESDMISC) mww 0xB8001010 0x00000002 # Setup for SDRAM Bank 0 #------------------------------------------------------------------------- # Write ESDCFG0 mww 0xB8001004 0x00095728 # CTL SMode = Precharge command mww 0xB8001000 0x92116480 mww 0x80000400 0x00000000 # CTL SMode = Auto Refresh command mww 0xB8001000 0xA2116480 mww 0x80000000 0x0 mww 0x80000000 0x0 mww 0x80000000 0x0 mww 0x80000000 0x0 mww 0x80000000 0x0 mww 0x80000000 0x0 mww 0x80000000 0x0 mww 0x80000000 0x0 # CTL SMode = Load Mode Register command mww 0xB8001000 0xB2116480 mwb 0x80000033 0x00 # CTL SMode = normal mww 0xB8001000 0x82116480 # Setup for SDRAM Bank 1 #------------------------------------------------------------------------- # Write ESDCFG1 mww 0xB800100C 0x00095728 # CTL SMode = Precharge command mww 0xB8001008 0x92116480 mww 0x90000400 0x00000000 # CTL SMode = Auto Refresh command mww 0xB8001008 0xA2116480 mww 0x90000000 0x00000000 mww 0x90000000 0x00000000 mww 0x90000000 0x00000000 mww 0x90000000 0x00000000 mww 0x90000000 0x00000000 mww 0x90000000 0x00000000 mww 0x90000000 0x00000000 mww 0x90000000 0x00000000 # CTL SMode = Load Mode Register command mww 0xB8001008 0xB2116480 mwb 0x90000033 0x00 # CTL SMode = normal mww 0xB8001008 0x82116480 # GPIO configuration #------------------------------------------------------------------------- mww 0x43FAC02C 0x00000015 mww 0x53FD0000 0x01000000 mww 0x53FD0004 0x00000080 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/tx27_stk5.cfg ================================================ # KaRo TX27 CPU Module on a StarterkitV base board # # http://www.karo-electronics.com/tx27.html # source [find target/imx27.cfg] $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { tx27_init } proc tx27_init { } { # This setup puts RAM at 0xA0000000 # init_aipi (AIPI1.PSR0, AIPI2.PSR0, AIPI1.PSR1 and AIPI2.PSR1) mww 0x10000000 0x20040304 mww 0x10020000 0x00000000 mww 0x10000004 0xDFFBFCFB mww 0x10020004 0xFFFFFFFF sleep 100 #init_max ( PORT0.MPR, #PORT0.AMPR, #PORT1.MPR, #PORT1.AMPR, #PORT2.MPR, #PORT2.AMPR) mww 0x1003F000 0x00302145 mww 0x1003F004 0x00302145 mww 0x1003F100 0x00302145 mww 0x1003F104 0x00302145 mww 0x1003F200 0x00302145 mww 0x1003F204 0x00302145 #init_drive_strength (#DSCR3, #DSCR5, #DSCR6, #DSCR7, #DSCR8 ) mww 0x10027828 0x55555555 mww 0x10027830 0x55555555 mww 0x10027834 0x55555555 mww 0x10027838 0x00005005 mww 0x1002783C 0x15555555 #init_sdram_speed #mww 0xD8001010 0x00000004 mww 0xD8001010 0x00000024 mww 0xD8001004 0x00395729 mww 0xD8001000 0x92120000 mww 0xA0000400 0x0 mww 0xD8001000 0xA2120000 mww 0xA0000000 0x0 mww 0xA0000000 0x0 mww 0xD8001000 0xB2120000 mdb 0xA0000000 mdb 0xA0000033 mww 0xD8001000 0x82126485 # ============================================= # Sync mode (AHB Clk = 133MHz ; BCLK = 44.3MHz) # ============================================= mww 0xD8002000 0x23524E80 mww 0xD8002004 0x10000D03 mww 0xD8002008 0x00720900 nand probe 0 } nand device tx27.nand mxc $_TARGETNAME mx27 hwecc biswap ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/unknown_at91sam9260.cfg ================================================ # Thanks to Pieter Conradie for this script! # # Unknown vendor board contains: # # Atmel AT91SAM9260 : PLLA = 192.512MHz, MCK = 96.256 MHz # OSCSEL configured for internal RC oscillator (22 to 42 kHz) # # 16-bit NOR FLASH : Intel JS28F128P30T85 128MBit # 32-bit SDRAM : 2 x Samsung K4S561632H-UC75, 4M x 16Bit x 4 Banks ################################################################## # We add to the minimal configuration. source [find target/at91sam9260.cfg] $_TARGETNAME configure -event reset-start { # At reset CPU runs at 22 to 42 kHz. # JTAG Frequency must be 6 times slower. jtag_rclk 3 halt # RSTC_MR : enable user reset, MMU may be enabled... use physical address mww phys 0xfffffd08 0xa5000501 } $_TARGETNAME configure -event reset-init { mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog mww 0xfffffc20 0x00004001 ;# CKGR_MOR : enable the main oscillator sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000001 ;# PMC_MCKR : switch to main oscillator sleep 10 ;# wait 10 ms mww 0xfffffc28 0x205dbf09 ;# CKGR_PLLAR: Set PLLA Register for 192.512MHz sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000101 ;# PMC_MCKR : Select prescaler (divide by 2) sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000102 ;# PMC_MCKR : Clock from PLLA is selected (96.256 MHz) sleep 10 ;# wait 10 ms # Increase JTAG Speed to 6 MHz if RCLK is not supported jtag_rclk 6000 arm7_9 dcc_downloads enable ;# Enable faster DCC downloads mww 0xffffec00 0x01020102 ;# SMC_SETUP0 : Setup SMC for Intel NOR Flash JS28F128P30T85 128MBit mww 0xffffec04 0x09070806 ;# SMC_PULSE0 mww 0xffffec08 0x000d000b ;# SMC_CYCLE0 mww 0xffffec0c 0x00001003 ;# SMC_MODE0 flash probe 0 ;# Identify flash bank 0 mww 0xfffff870 0xffff0000 ;# PIO_ASR : Select peripheral function for D15..D31 mww 0xfffff804 0xffff0000 ;# PIO_PDR : Disable PIO function for D15..D31 mww 0xfffff860 0xffff0000 ;# PIO_PUDR : Disable D15..D31 pull-ups mww 0xffffef1c 0x00010102 ;# EBI_CSA : Assign EBI Chip Select 1 to SDRAM # VDDIOMSEL set for +3V3 memory # Disable D0..D15 pull-ups mww 0xffffea08 0x85227259 ;# SDRAMC_CR : Configure SDRAM (2 x Samsung K4S561632H-UC75 : 4M x 16Bit x 4 Banks) mww 0xffffea00 0x1 ;# SDRAMC_MR : issue a NOP command mww 0x20000000 0 mww 0xffffea00 0x2 ;# SDRAMC_MR : issue an 'All Banks Precharge' command mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue 8 x 'Auto-Refresh' Command mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x3 ;# SDRAMC_MR : issue a 'Load Mode Register' command mww 0x20000000 0 mww 0xffffea00 0x0 ;# SDRAMC_MR : normal mode mww 0x20000000 0 mww 0xffffea04 0x2a2 ;# SDRAMC_TR : Set refresh timer count to 7us } ##################### # Flash configuration ##################### #flash bank cfi set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x10000000 0x01000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/uptech_2410.cfg ================================================ # Target Configuration for the Uptech 2410 board. # This configuration should also work on smdk2410, but I haven't tested it yet. # Author: xionglingfeng@Gmail.com source [find target/samsung_s3c2410.cfg] $_TARGETNAME configure -event reset-init { uptech2410_init } $_TARGETNAME configure -event gdb-attach { reset init } proc init_pll_sdram { } { #echo "---------- Initializing PLL and SDRAM ---------" #watchdog timer disable mww phys 0x53000000 0x00000000 #disable all interrupts mww phys 0x4a000008 0xffffffff #disable all sub-interrupts mww phys 0x4a00001c 0x000007ff #clear all source pending bits mww phys 0x4a000000 0xffffffff #clear all sub-source pending bits mww phys 0x4a000018 0x000007ff #clear interrupt pending bit mww phys 0x4a000010 0xffffffff #PLL locktime counter mww phys 0x4c000000 0x00ffffff #Fin=12MHz Fout=202.8MHz #mww phys 0x4c000004 0x000a1031 #FCLK:HCLK:PCLK = 1:2:4 mww phys 0x4c000014 0x00000003 mww phys 0x48000000 0x11111110 mww phys 0x48000004 0x00007FFC mww phys 0x48000008 0x00007FFC mww phys 0x4800000c 0x00000700 mww phys 0x48000010 0x00000700 mww phys 0x48000014 0x00002E50 mww phys 0x48000018 0x00002E50 mww phys 0x4800001c 0x00018005 mww phys 0x48000020 0x00018005 mww phys 0x48000024 0x008c04e9 mww phys 0x48000028 0x000000b2 mww phys 0x4800002c 0x00000030 mww phys 0x48000030 0x00000030 } proc uptech2410_init { } { init_pll_sdram #echo "---------- Probing Nand flash ----------" nand probe 0 #echo "---------- Enable some functions ----------" } set _NANDNAME $_CHIPNAME.nand nand device $_NANDNAME s3c2410 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/vd_a53x2_jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # Arm Cortex A53x2 through JTAG source [find interface/vdebug.cfg] set _CORES 2 set _CHIPNAME a53 set _MEMSTART 0x00000000 set _MEMSIZE 0x1000000 set _CPUTAPID 0x5ba00477 # vdebug select transport #transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst adapter speed 50000 adapter srst delay 5 # BFM hierarchical path and input clk period vdebug bfm_path tbench.u_vd_jtag_bfm 10ns # DMA Memories to access backdoor (up to 4) vdebug mem_path tbench.u_memory.mem_array $_MEMSTART $_MEMSIZE jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID jtag arp_init-reset source [find target/vd_aarch64.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/vd_m4_jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # Arm Cortex m4 through JTAG source [find interface/vdebug.cfg] set _CHIPNAME m4 set _MEMSTART 0x00000000 set _MEMSIZE 0x10000 set _CPUTAPID 0x4ba00477 # vdebug select transport #transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst adapter speed 25000 adapter srst delay 5 # BFM hierarchical path and input clk period vdebug bfm_path tbench.u_vd_jtag_bfm 20ns # DMA Memories to access backdoor (up to 4) vdebug mem_path tbench.u_mcu.u_sys.u_rom.rom $_MEMSTART $_MEMSIZE jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID jtag arp_init-reset source [find target/vd_cortex_m.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/vd_pulpissimo_jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # RISCV Ibex core with Pulpissimo through JTAG source [find interface/vdebug.cfg] set _CHIPNAME ibex set _HARTID 0x20 set _CPUTAPID 0x249511c3 # vdebug select transport #transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst adapter speed 12500 adapter srst delay 10 # BFM hierarchical path and input clk period vdebug bfm_path tbench.u_vd_jtag_bfm 40ns # DMA Memories to access backdoor (up to 4) vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[0\].sram_i.mem_array 0x1c000000 0x8000 vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[1\].sram_i.mem_array 0x1c008000 0x8000 vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2\[0\].sram_i.mem_array 0x1c010000 0x80000 # need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01 jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x05 -irmask 0x1f -expected-id $_CPUTAPID jtag arp_init-reset source [find target/vd_riscv.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/vd_swerv_jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # RISCV swerv core with Swerv through JTAG source [find interface/vdebug.cfg] set _CHIPNAME rv32 set _HARTID 0x00 set _CPUTAPID 0x1000008b set _MEMSTART 0x00000000 set _MEMSIZE 0x10000 # vdebug select transport #transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst adapter speed 50000 adapter srst delay 5 # BFM hierarchical path and input clk period vdebug bfm_path tbench.u_vd_jtag_bfm 10ns # DMA Memories to access backdoor (up to 4) vdebug mem_path tbench.i_ahb_ic.mem $_MEMSTART $_MEMSIZE # need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01 jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x01 -irmask 0x1f -expected-id $_CPUTAPID jtag arp_init-reset source [find target/vd_riscv.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/verdex.cfg ================================================ # Config for Gumstix Verdex XM4 and XL6P (PXA270) set CHIPNAME verdex source [find target/pxa270.cfg] # The board supports separate reset lines # Override this in the interface config for parallel dongles reset_config trst_and_srst separate # XM4 = 400MHz, XL6P = 600MHz...let's run at 0.1*400MHz=40MHz adapter speed 40000 # flash bank # XL6P has 32 MB flash flash bank $_CHIPNAME.flash0 cfi 0x00000000 0x02000000 2 2 $_TARGETNAME # XM4 has 16 MB flash #flash bank $_CHIPNAME.flash0 cfi 0x00000000 0x01000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/voipac.cfg ================================================ # Config for Voipac PXA270/PXA270M module. set CHIPNAME voipac source [find target/pxa270.cfg] # The board supports separate reset lines # Override this in the interface config for parallel dongles reset_config trst_and_srst separate # flash bank flash bank $_CHIPNAME.flash0 cfi 0x00000000 0x2000000 2 2 $_TARGETNAME flash bank $_CHIPNAME.flash1 cfi 0x02000000 0x2000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/voltcraft_dso-3062c.cfg ================================================ # # Voltcraft DSO-3062C digital oscilloscope (uses a Samsung S3C2440) # # http://www.eevblog.com/forum/general-chat/hantek-tekway-dso-hack-get-200mhz-bw-for-free/ # http://www.mikrocontroller.net/topic/249628 # http://elinux.org/Das_Oszi # http://randomprojects.org/wiki/Voltcraft_DSO-3062C # # Enable this if your JTAG adapter supports multiple transports (JTAG or SWD). # Otherwise comment it out, as it will cause an OpenOCD error. ### transport select jtag source [find target/samsung_s3c2440.cfg] adapter speed 16000 # Samsung K9F1208U0C NAND flash chip (64MiB, 3.3V, 8-bit) nand device $_CHIPNAME.nand s3c2440 $_TARGETNAME # arm7_9 fast_memory_access enable # arm7_9 dcc_downloads enable init reset halt scan_chain targets nand probe 0 nand list ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/x300t.cfg ================================================ # This is for the T-Home X300T / X301T IPTV box, # which are based on IPTV reference designs from Kiss/Cisco KMM-3*** # # It has Sigma Designs SMP8634 chip. source [find target/smp8634.cfg] $_TARGETNAME configure -event reset-init { x300t_init } # 1MB CFI capable flash # flash bank set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0xac000000 0x100000 2 2 $_TARGETNAME proc x300t_init { } { # Setup SDRAM config and flash mapping # initialize ram mww 0xa003fffc 3 mww 0xa003fffc 2 mww 0xa0030000 0xE34111BA mww 0xa003fffc 0xa4444 mww 0xa003fffc 0 # remap boot vector in CPU local RAM mww 0xa006f000 0x60000 # map flash to CPU address space REG_BASE_cpu_block+CPU_remap4 mww 0x0006f010 0x48000000 # map flash addr to REG_BASE_cpu_block + LR_XENV_LOCATION (normally done by XOS) mww 0x00061ff0 0x48000000 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/xmc-2go.cfg ================================================ # # Infineon XMC 2Go # # # Segger J-Link Lite XMC4200 on-board # source [find interface/jlink.cfg] transport select swd set CHIPNAME xmc1100 set WORKAREASIZE 0x4000 source [find target/xmc1xxx.cfg] reset_config srst_only srst_nogate ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/xmc1100-boot-kit.cfg ================================================ # # Infineon XMC1100 Boot Kit # # # Segger J-Link Lite XMC4200 on-board # source [find interface/jlink.cfg] transport select swd set CHIPNAME xmc1100 set WORKAREASIZE 0x4000 source [find target/xmc1xxx.cfg] reset_config srst_only srst_nogate ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/xmc4200-application-kit-actuator.cfg ================================================ # # Infineon XMC4200 Application Kit - Actuator # # # Segger J-Link Lite XMC4200 on-board # source [find interface/jlink.cfg] transport select swd set CHIPNAME xmc4200 source [find target/xmc4xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/xmc4300-relax.cfg ================================================ # # Infineon XMC4300 Relax EtherCAT Kit # # # Segger J-Link Lite XMC4200 on-board # source [find interface/jlink.cfg] transport select swd set CHIPNAME xmc4300 source [find target/xmc4xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/xmc4500-application-kit-general.cfg ================================================ # # Infineon XMC4500 Application Kit - General Purpose # set CHIPNAME xmc4500 source [find target/xmc4xxx.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/xmc4500-application-kit-sdram.cfg ================================================ # # Infineon XMC4500 Application Kit - SDRAM # # # Segger J-Link Lite XMC4200 on-board # set CHIPNAME xmc4500 source [find target/xmc4xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/xmc4500-relax.cfg ================================================ # # Infineon XMC4500 Relax Kit / Relax Lite Kit # # # Segger J-Link Lite XMC4500 on-board # source [find interface/jlink.cfg] transport select swd # There's also an unpopulated 10-pin 0.05" pinout. set CHIPNAME xmc4500 source [find target/xmc4xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/xmc4700-relax.cfg ================================================ # # Infineon XMC4700 Relax Lite Kit / Relax Kit for 5V Shields / Relax Kit # # # Segger J-Link Lite XMC4200 on-board # source [find interface/jlink.cfg] transport select swd # There's also an unpopulated 10-pin 0.05" pinout. set CHIPNAME xmc4700 source [find target/xmc4xxx.cfg] # Relax Kit only: N25Q032A qSPI flash ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/xmc4800-relax.cfg ================================================ # # Infineon XMC4800 Relax EtherCAT Kit # # # Segger J-Link Lite XMC4200 on-board # source [find interface/jlink.cfg] transport select swd # There's also an unpopulated 10-pin 0.05" pinout. set CHIPNAME xmc4800 source [find target/xmc4xxx.cfg] # N25Q032A qSPI flash ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/board/xmos_xk-xac-xa8_arm.cfg ================================================ # # xCORE-XA Core Module # # https://www.xmos.com/support/boards?product=17940 # # # J-Link OB STM32F103 # source [find interface/jlink.cfg] transport select swd # # XS1-XAU8A-10 # source [find target/xmos_xs1-xau8a-10_arm.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/aic.tcl ================================================ set AIC_SMR [expr {$AT91C_BASE_AIC + 0x00000000} ] global AIC_SMR set AIC_SVR [expr {$AT91C_BASE_AIC + 0x00000080} ] global AIC_SVR set AIC_IVR [expr {$AT91C_BASE_AIC + 0x00000100} ] global AIC_IVR set AIC_FVR [expr {$AT91C_BASE_AIC + 0x00000104} ] global AIC_FVR set AIC_ISR [expr {$AT91C_BASE_AIC + 0x00000108} ] global AIC_ISR set AIC_IPR [expr {$AT91C_BASE_AIC + 0x0000010C} ] global AIC_IPR set AIC_IMR [expr {$AT91C_BASE_AIC + 0x00000110} ] global AIC_IMR set AIC_CISR [expr {$AT91C_BASE_AIC + 0x00000114} ] global AIC_CISR set AIC_IECR [expr {$AT91C_BASE_AIC + 0x00000120} ] global AIC_IECR set AIC_IDCR [expr {$AT91C_BASE_AIC + 0x00000124} ] global AIC_IDCR set AIC_ICCR [expr {$AT91C_BASE_AIC + 0x00000128} ] global AIC_ICCR set AIC_ISCR [expr {$AT91C_BASE_AIC + 0x0000012C} ] global AIC_ISCR set AIC_EOICR [expr {$AT91C_BASE_AIC + 0x00000130} ] global AIC_EOICR set AIC_SPU [expr {$AT91C_BASE_AIC + 0x00000134} ] global AIC_SPU set AIC_DCR [expr {$AT91C_BASE_AIC + 0x00000138} ] global AIC_DCR set AIC_FFER [expr {$AT91C_BASE_AIC + 0x00000140} ] global AIC_FFER set AIC_FFDR [expr {$AT91C_BASE_AIC + 0x00000144} ] global AIC_FFDR set AIC_FFSR [expr {$AT91C_BASE_AIC + 0x00000148} ] global AIC_FFSR proc aic_enable_disable_list { VAL ENAME DNAME } { global AT91C_ID show_mmr32_bits AT91C_ID $VAL } proc show_AIC_IPR_helper { NAME ADDR VAL } { aic_enable_disable_list $VAL "IRQ PENDING" "irq not-pending" } proc show_AIC_IMR_helper { NAME ADDR VAL } { aic_enable_disable_list $VAL "IRQ ENABLED" "irq disabled" } proc show_AIC { } { global AIC_SMR if [catch { set aaa [read_memory $AIC_SMR 32 [expr {32 * 4}]] } msg ] { error [format "%s (%s)" $msg AIC_SMR] } echo "AIC_SMR: Mode & Type" global AT91C_ID for { set x 0 } { $x < 32 } { } { echo -n " " echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) [lindex $aaa $x]] incr x } global AIC_SVR if [catch { set aaa [read_memory $AIC_SVR 32 [expr {32 * 4}]] } msg ] { error [format "%s (%s)" $msg AIC_SVR] } echo "AIC_SVR: Vectors" for { set x 0 } { $x < 32 } { } { echo -n " " echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) [lindex $aaa $x]] incr x } foreach REG { AIC_IVR AIC_FVR AIC_ISR AIC_IPR AIC_IMR AIC_CISR AIC_IECR AIC_IDCR AIC_ICCR AIC_ISCR AIC_EOICR AIC_SPU AIC_DCR AIC_FFER AIC_FFDR AIC_FFSR } { if [catch { show_mmr32_reg $REG } msg ] { error $msg break } } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/at91_pio.cfg ================================================ set PIO_PER 0x00 ;# Enable Register set PIO_PDR 0x04 ;# Disable Register set PIO_PSR 0x08 ;# Status Register set PIO_OER 0x10 ;# Output Enable Register set PIO_ODR 0x14 ;# Output Disable Register set PIO_OSR 0x18 ;# Output Status Register set PIO_IFER 0x20 ;# Glitch Input Filter Enable set PIO_IFDR 0x24 ;# Glitch Input Filter Disable set PIO_IFSR 0x28 ;# Glitch Input Filter Status set PIO_SODR 0x30 ;# Set Output Data Register set PIO_CODR 0x34 ;# Clear Output Data Register set PIO_ODSR 0x38 ;# Output Data Status Register set PIO_PDSR 0x3c ;# Pin Data Status Register set PIO_IER 0x40 ;# Interrupt Enable Register set PIO_IDR 0x44 ;# Interrupt Disable Register set PIO_IMR 0x48 ;# Interrupt Mask Register set PIO_ISR 0x4c ;# Interrupt Status Register set PIO_MDER 0x50 ;# Multi-driver Enable Register set PIO_MDDR 0x54 ;# Multi-driver Disable Register set PIO_MDSR 0x58 ;# Multi-driver Status Register set PIO_PUDR 0x60 ;# Pull-up Disable Register set PIO_PUER 0x64 ;# Pull-up Enable Register set PIO_PUSR 0x68 ;# Pull-up Status Register set PIO_ASR 0x70 ;# Peripheral A Select Register set PIO_BSR 0x74 ;# Peripheral B Select Register set PIO_ABSR 0x78 ;# AB Status Register set PIO_OWER 0xa0 ;# Output Write Enable Register set PIO_OWDR 0xa4 ;# Output Write Disable Register set PIO_OWSR 0xa8 ;# Output Write Status Register ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/at91_pmc.cfg ================================================ set AT91_PMC_SCER [expr {$AT91_PMC + 0x00}] ;# System Clock Enable Register set AT91_PMC_SCDR [expr {$AT91_PMC + 0x04}] ;# System Clock Disable Register set AT91_PMC_SCSR [expr {$AT91_PMC + 0x08}] ;# System Clock Status Register set AT91_PMC_PCK [expr {1 << 0}] ;# Processor Clock set AT91RM9200_PMC_UDP [expr {1 << 1}] ;# USB Devcice Port Clock [AT91RM9200 only] set AT91RM9200_PMC_MCKUDP [expr {1 << 2}] ;# USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] set AT91CAP9_PMC_DDR [expr {1 << 2}] ;# DDR Clock [CAP9 revC & some SAM9 only] set AT91RM9200_PMC_UHP [expr {1 << 4}] ;# USB Host Port Clock [AT91RM9200 only] set AT91SAM926x_PMC_UHP [expr {1 << 6}] ;# USB Host Port Clock [AT91SAM926x only] set AT91CAP9_PMC_UHP [expr {1 << 6}] ;# USB Host Port Clock [AT91CAP9 only] set AT91SAM926x_PMC_UDP [expr {1 << 7}] ;# USB Devcice Port Clock [AT91SAM926x only] set AT91_PMC_PCK0 [expr {1 << 8}] ;# Programmable Clock 0 set AT91_PMC_PCK1 [expr {1 << 9}] ;# Programmable Clock 1 set AT91_PMC_PCK2 [expr {1 << 10}] ;# Programmable Clock 2 set AT91_PMC_PCK3 [expr {1 << 11}] ;# Programmable Clock 3 set AT91_PMC_HCK0 [expr {1 << 16}] ;# AHB Clock (USB host) [AT91SAM9261 only] set AT91_PMC_HCK1 [expr {1 << 17}] ;# AHB Clock (LCD) [AT91SAM9261 only] set AT91_PMC_PCER [expr {$AT91_PMC + 0x10}] ;# Peripheral Clock Enable Register set AT91_PMC_PCDR [expr {$AT91_PMC + 0x14}] ;# Peripheral Clock Disable Register set AT91_PMC_PCSR [expr {$AT91_PMC + 0x18}] ;# Peripheral Clock Status Register set AT91_CKGR_UCKR [expr {$AT91_PMC + 0x1C}] ;# UTMI Clock Register [some SAM9, CAP9] set AT91_PMC_UPLLEN [expr {1 << 16}] ;# UTMI PLL Enable set AT91_PMC_UPLLCOUNT [expr {0xf << 20}] ;# UTMI PLL Start-up Time set AT91_PMC_BIASEN [expr {1 << 24}] ;# UTMI BIAS Enable set AT91_PMC_BIASCOUNT [expr {0xf << 28}] ;# UTMI BIAS Start-up Time set AT91_CKGR_MOR [expr {$AT91_PMC + 0x20}] ;# Main Oscillator Register [not on SAM9RL] set AT91_PMC_MOSCEN [expr {1 << 0}] ;# Main Oscillator Enable set AT91_PMC_OSCBYPASS [expr {1 << 1}] ;# Oscillator Bypass [SAM9x, CAP9] set AT91_PMC_OSCOUNT [expr {0xff << 8}] ;# Main Oscillator Start-up Time set AT91_CKGR_MCFR [expr {$AT91_PMC + 0x24}] ;# Main Clock Frequency Register set AT91_PMC_MAINF [expr {0xffff << 0}] ;# Main Clock Frequency set AT91_PMC_MAINRDY [expr {1 << 16}] ;# Main Clock Ready set AT91_CKGR_PLLAR [expr {$AT91_PMC + 0x28}] ;# PLL A Register set AT91_CKGR_PLLBR [expr {$AT91_PMC + 0x2c}] ;# PLL B Register set AT91_PMC_DIV [expr {0xff << 0}] ;# Divider set AT91_PMC_PLLCOUNT [expr {0x3f << 8}] ;# PLL Counter set AT91_PMC_OUT [expr {3 << 14}] ;# PLL Clock Frequency Range set AT91_PMC_MUL [expr {0x7ff << 16}] ;# PLL Multiplier set AT91_PMC_USBDIV [expr {3 << 28}] ;# USB Divisor (PLLB only) set AT91_PMC_USBDIV_1 [expr {0 << 28}] set AT91_PMC_USBDIV_2 [expr {1 << 28}] set AT91_PMC_USBDIV_4 [expr {2 << 28}] set AT91_PMC_USB96M [expr {1 << 28}] ;# Divider by 2 Enable (PLLB only) set AT91_PMC_PLLA_WR_ERRATA [expr {1 << 29}] ;# Bit 29 must always be set to 1 when programming the CKGR_PLLAR register set AT91_PMC_MCKR [expr {$AT91_PMC + 0x30}] ;# Master Clock Register set AT91_PMC_CSS [expr {3 << 0}] ;# Master Clock Selection set AT91_PMC_CSS_SLOW [expr {0 << 0}] set AT91_PMC_CSS_MAIN [expr {1 << 0}] set AT91_PMC_CSS_PLLA [expr {2 << 0}] set AT91_PMC_CSS_PLLB [expr {3 << 0}] set AT91_PMC_CSS_UPLL [expr {3 << 0}] ;# [some SAM9 only] set AT91_PMC_PRES [expr {7 << 2}] ;# Master Clock Prescaler set AT91_PMC_PRES_1 [expr {0 << 2}] set AT91_PMC_PRES_2 [expr {1 << 2}] set AT91_PMC_PRES_4 [expr {2 << 2}] set AT91_PMC_PRES_8 [expr {3 << 2}] set AT91_PMC_PRES_16 [expr {4 << 2}] set AT91_PMC_PRES_32 [expr {5 << 2}] set AT91_PMC_PRES_64 [expr {6 << 2}] set AT91_PMC_MDIV [expr {3 << 8}] ;# Master Clock Division set AT91RM9200_PMC_MDIV_1 [expr {0 << 8}] ;# [AT91RM9200 only] set AT91RM9200_PMC_MDIV_2 [expr {1 << 8}] set AT91RM9200_PMC_MDIV_3 [expr {2 << 8}] set AT91RM9200_PMC_MDIV_4 [expr {3 << 8}] set AT91SAM9_PMC_MDIV_1 [expr {0 << 8}] ;# [SAM9,CAP9 only] set AT91SAM9_PMC_MDIV_2 [expr {1 << 8}] set AT91SAM9_PMC_MDIV_4 [expr {2 << 8}] set AT91SAM9_PMC_MDIV_6 [expr {3 << 8}] ;# [some SAM9 only] set AT91SAM9_PMC_MDIV_3 [expr {3 << 8}] ;# [some SAM9 only] set AT91_PMC_PDIV [expr {1 << 12}] ;# Processor Clock Division [some SAM9 only] set AT91_PMC_PDIV_1 [expr {0 << 12}] set AT91_PMC_PDIV_2 [expr {1 << 12}] set AT91_PMC_PLLADIV2 [expr {1 << 12}] ;# PLLA divisor by 2 [some SAM9 only] set AT91_PMC_PLLADIV2_OFF [expr {0 << 12}] set AT91_PMC_PLLADIV2_ON [expr {1 << 12}] set AT91_PMC_USB [expr {$AT91_PMC + 0x38}] ;# USB Clock Register [some SAM9 only] set AT91_PMC_USBS [expr {0x1 << 0}] ;# USB OHCI Input clock selection set AT91_PMC_USBS_PLLA [expr {0 << 0}] set AT91_PMC_USBS_UPLL [expr {1 << 0}] set AT91_PMC_OHCIUSBDIV [expr {0xF << 8}] ;# Divider for USB OHCI Clock ;# set AT91_PMC_PCKR(n) [expr {$AT91_PMC + 0x40 + ((n) * 4)}] ;# Programmable Clock 0-N Registers set AT91_PMC_CSSMCK [expr {0x1 << 8}] ;# CSS or Master Clock Selection set AT91_PMC_CSSMCK_CSS [expr {0 << 8}] set AT91_PMC_CSSMCK_MCK [expr {1 << 8}] set AT91_PMC_IER [expr {$AT91_PMC + 0x60}] ;# Interrupt Enable Register set AT91_PMC_IDR [expr {$AT91_PMC + 0x64}] ;# Interrupt Disable Register set AT91_PMC_SR [expr {$AT91_PMC + 0x68}] ;# Status Register set AT91_PMC_MOSCS [expr {1 << 0}] ;# MOSCS Flag set AT91_PMC_LOCKA [expr {1 << 1}] ;# PLLA Lock set AT91_PMC_LOCKB [expr {1 << 2}] ;# PLLB Lock set AT91_PMC_MCKRDY [expr {1 << 3}] ;# Master Clock set AT91_PMC_LOCKU [expr {1 << 6}] ;# UPLL Lock [some SAM9, AT91CAP9 only] set AT91_PMC_OSCSEL [expr {1 << 7}] ;# Slow Clock Oscillator [AT91CAP9 revC only] set AT91_PMC_PCK0RDY [expr {1 << 8}] ;# Programmable Clock 0 set AT91_PMC_PCK1RDY [expr {1 << 9}] ;# Programmable Clock 1 set AT91_PMC_PCK2RDY [expr {1 << 10}] ;# Programmable Clock 2 set AT91_PMC_PCK3RDY [expr {1 << 11}] ;# Programmable Clock 3 set AT91_PMC_IMR [expr {$AT91_PMC + 0x6c}] ;# Interrupt Mask Register set AT91_PMC_PROT [expr {$AT91_PMC + 0xe4}] ;# Protect Register [AT91CAP9 revC only] set AT91_PMC_PROTKEY 0x504d4301 ;# Activation Code set AT91_PMC_VER [expr {$AT91_PMC + 0xfc}] ;# PMC Module Version [AT91CAP9 only] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/at91_rstc.cfg ================================================ set AT91_RSTC_CR [expr {$AT91_RSTC + 0x00}] ;# Reset Controller Control Register set AT91_RSTC_PROCRST [expr {1 << 0}] ;# Processor Reset set AT91_RSTC_PERRST [expr {1 << 2}] ;# Peripheral Reset set AT91_RSTC_EXTRST [expr {1 << 3}] ;# External Reset set AT91_RSTC_KEY [expr {0xa5 << 24}] ;# KEY Password set AT91_RSTC_SR [expr {$AT91_RSTC + 0x04}] ;# Reset Controller Status Register set AT91_RSTC_URSTS [expr {1 << 0}] ;# User Reset Status set AT91_RSTC_RSTTYP [expr {7 << 8}] ;# Reset Type set AT91_RSTC_RSTTYP_GENERAL [expr {0 << 8}] set AT91_RSTC_RSTTYP_WAKEUP [expr {1 << 8}] set AT91_RSTC_RSTTYP_WATCHDOG [expr {2 << 8}] set AT91_RSTC_RSTTYP_SOFTWARE [expr {3 << 8}] set AT91_RSTC_RSTTYP_USER [expr {4 << 8}] set AT91_RSTC_NRSTL [expr {1 << 16}] ;# NRST Pin Level set AT91_RSTC_SRCMP [expr {1 << 17}] ;# Software Reset Command in Progress set AT91_RSTC_MR [expr {$AT91_RSTC + 0x08}] ;# Reset Controller Mode Register set AT91_RSTC_URSTEN [expr {1 << 0}] ;# User Reset Enable set AT91_RSTC_URSTIEN [expr {1 << 4}] ;# User Reset Interrupt Enable set AT91_RSTC_ERSTL [expr {0xf << 8}] ;# External Reset Length ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/at91_wdt.cfg ================================================ set AT91_WDT_CR [expr {$AT91_WDT + 0x00}] ;# Watchdog Control Register set AT91_WDT_WDRSTT [expr {1 << 0}] ;# Restart set AT91_WDT_KEY [expr {0xa5 << 24}] ;# KEY Password set AT91_WDT_MR [expr {$AT91_WDT + 0x04}] ;# Watchdog Mode Register set AT91_WDT_WDV [expr {0xfff << 0}] ;# Counter Value set AT91_WDT_WDFIEN [expr {1 << 12}] ;# Fault Interrupt Enable set AT91_WDT_WDRSTEN [expr {1 << 13}] ;# Reset Processor set AT91_WDT_WDRPROC [expr {1 << 14}] ;# Timer Restart set AT91_WDT_WDDIS [expr {1 << 15}] ;# Watchdog Disable set AT91_WDT_WDD [expr {0xfff << 16}] ;# Delta Value set AT91_WDT_WDDBGHLT [expr {1 << 28}] ;# Debug Halt set AT91_WDT_WDIDLEHLT [expr {1 << 29}] ;# Idle Halt set AT91_WDT_SR [expr {$AT91_WDT + 0x08}] ;# Watchdog Status Register set AT91_WDT_WDUNF [expr {1 << 0}] ;# Watchdog Underflow set AT91_WDT_WDERR [expr {1 << 1}] ;# Watchdog Error ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/at91sam7x128.tcl ================================================ source [find bitsbytes.tcl] source [find cpu/arm/arm7tdmi.tcl] source [find memory.tcl] source [find mmr_helpers.tcl] set CHIP_MAKER atmel set CHIP_FAMILY at91sam7 set CHIP_NAME at91sam7x128 # how many flash regions. set N_FLASH 1 set FLASH(0,CHIPSELECT) -1 set FLASH(0,BASE) 0x00100000 set FLASH(0,LEN) $__128K set FLASH(0,HUMAN) "internal flash" set FLASH(0,TYPE) "flash" set FLASH(0,RWX) $RWX_R_X set FLASH(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY # how many ram regions. set N_RAM 1 set RAM(0,CHIPSELECT) -1 set RAM(0,BASE) 0x00200000 set RAM(0,LEN) $__32K set RAM(0,HUMAN) "internal ram" set RAM(0,TYPE) "ram" set RAM(0,RWX) $RWX_RWX set RAM(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY # I AM LAZY... I create 1 region for all MMRs. set N_MMREGS 1 set MMREGS(0,CHIPSELECT) -1 set MMREGS(0,BASE) 0xfff00000 set MMREGS(0,LEN) 0x000fffff set MMREGS(0,HUMAN) "mm-regs" set MMREGS(0,TYPE) "mmr" set MMREGS(0,RWX) $RWX_RW set MMREGS(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY # no external memory set N_XMEM 0 set AT91C_BASE_SYS 0xFFFFF000 set AT91C_BASE_AIC 0xFFFFF000 set AT91C_BASE_PDC_DBGU 0xFFFFF300 set AT91C_BASE_DBGU 0xFFFFF200 set AT91C_BASE_PIOA 0xFFFFF400 set AT91C_BASE_PIOB 0xFFFFF600 set AT91C_BASE_CKGR 0xFFFFFC20 set AT91C_BASE_PMC 0xFFFFFC00 set AT91C_BASE_RSTC 0xFFFFFD00 set AT91C_BASE_RTTC 0xFFFFFD20 set AT91C_BASE_PITC 0xFFFFFD30 set AT91C_BASE_WDTC 0xFFFFFD40 set AT91C_BASE_VREG 0xFFFFFD60 set AT91C_BASE_MC 0xFFFFFF00 set AT91C_BASE_PDC_SPI1 0xFFFE4100 set AT91C_BASE_SPI1 0xFFFE4000 set AT91C_BASE_PDC_SPI0 0xFFFE0100 set AT91C_BASE_SPI0 0xFFFE0000 set AT91C_BASE_PDC_US1 0xFFFC4100 set AT91C_BASE_US1 0xFFFC4000 set AT91C_BASE_PDC_US0 0xFFFC0100 set AT91C_BASE_US0 0xFFFC0000 set AT91C_BASE_PDC_SSC 0xFFFD4100 set AT91C_BASE_SSC 0xFFFD4000 set AT91C_BASE_TWI 0xFFFB8000 set AT91C_BASE_PWMC_CH3 0xFFFCC260 set AT91C_BASE_PWMC_CH2 0xFFFCC240 set AT91C_BASE_PWMC_CH1 0xFFFCC220 set AT91C_BASE_PWMC_CH0 0xFFFCC200 set AT91C_BASE_PWMC 0xFFFCC000 set AT91C_BASE_UDP 0xFFFB0000 set AT91C_BASE_TC0 0xFFFA0000 set AT91C_BASE_TC1 0xFFFA0040 set AT91C_BASE_TC2 0xFFFA0080 set AT91C_BASE_TCB 0xFFFA0000 set AT91C_BASE_CAN_MB0 0xFFFD0200 set AT91C_BASE_CAN_MB1 0xFFFD0220 set AT91C_BASE_CAN_MB2 0xFFFD0240 set AT91C_BASE_CAN_MB3 0xFFFD0260 set AT91C_BASE_CAN_MB4 0xFFFD0280 set AT91C_BASE_CAN_MB5 0xFFFD02A0 set AT91C_BASE_CAN_MB6 0xFFFD02C0 set AT91C_BASE_CAN_MB7 0xFFFD02E0 set AT91C_BASE_CAN 0xFFFD0000 set AT91C_BASE_EMAC 0xFFFDC000 set AT91C_BASE_PDC_ADC 0xFFFD8100 set AT91C_BASE_ADC 0xFFFD8000 set AT91C_ID(0) FIQ set AT91C_ID(1) SYS set AT91C_ID(2) PIOA set AT91C_ID(3) PIOB set AT91C_ID(4) SPI0 set AT91C_ID(5) SPI1 set AT91C_ID(6) US0 set AT91C_ID(7) US1 set AT91C_ID(8) SSC set AT91C_ID(9) TWI set AT91C_ID(10) PWMC set AT91C_ID(11) UDP set AT91C_ID(12) TC0 set AT91C_ID(13) TC1 set AT91C_ID(14) TC2 set AT91C_ID(15) CAN set AT91C_ID(16) EMAC set AT91C_ID(17) ADC set AT91C_ID(18) "" set AT91C_ID(19) "" set AT91C_ID(20) "" set AT91C_ID(21) "" set AT91C_ID(22) "" set AT91C_ID(23) "" set AT91C_ID(24) "" set AT91C_ID(25) "" set AT91C_ID(26) "" set AT91C_ID(27) "" set AT91C_ID(28) "" set AT91C_ID(29) "" set AT91C_ID(30) IRQ0 set AT91C_ID(31) IRQ1 source [find chip/atmel/at91/aic.tcl] source [find chip/atmel/at91/usarts.tcl] source [find chip/atmel/at91/pmc.tcl] source [find chip/atmel/at91/rtt.tcl] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/at91sam7x256.tcl ================================================ source [find bitsbytes.tcl] source [find cpu/arm/arm7tdmi.tcl] source [find memory.tcl] source [find mmr_helpers.tcl] set CHIP_MAKER atmel set CHIP_FAMILY at91sam7 set CHIP_NAME at91sam7x256 # how many flash regions. set N_FLASH 1 set FLASH(0,CHIPSELECT) -1 set FLASH(0,BASE) 0x00100000 set FLASH(0,LEN) $__256K set FLASH(0,HUMAN) "internal flash" set FLASH(0,TYPE) "flash" set FLASH(0,RWX) $RWX_R_X set FLASH(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY # how many ram regions. set N_RAM 1 set RAM(0,CHIPSELECT) -1 set RAM(0,BASE) 0x00200000 set RAM(0,LEN) $__64K set RAM(0,HUMAN) "internal ram" set RAM(0,TYPE) "ram" set RAM(0,RWX) $RWX_RWX set RAM(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY # I AM LAZY... I create 1 region for all MMRs. set N_MMREGS 1 set MMREGS(0,CHIPSELECT) -1 set MMREGS(0,BASE) 0xfff00000 set MMREGS(0,LEN) 0x000fffff set MMREGS(0,HUMAN) "mm-regs" set MMREGS(0,TYPE) "mmr" set MMREGS(0,RWX) $RWX_RW set MMREGS(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY # no external memory set N_XMEM 0 set AT91C_BASE_SYS 0xFFFFF000 set AT91C_BASE_AIC 0xFFFFF000 set AT91C_BASE_PDC_DBGU 0xFFFFF300 set AT91C_BASE_DBGU 0xFFFFF200 set AT91C_BASE_PIOA 0xFFFFF400 set AT91C_BASE_PIOB 0xFFFFF600 set AT91C_BASE_CKGR 0xFFFFFC20 set AT91C_BASE_PMC 0xFFFFFC00 set AT91C_BASE_RSTC 0xFFFFFD00 set AT91C_BASE_RTTC 0xFFFFFD20 set AT91C_BASE_PITC 0xFFFFFD30 set AT91C_BASE_WDTC 0xFFFFFD40 set AT91C_BASE_VREG 0xFFFFFD60 set AT91C_BASE_MC 0xFFFFFF00 set AT91C_BASE_PDC_SPI1 0xFFFE4100 set AT91C_BASE_SPI1 0xFFFE4000 set AT91C_BASE_PDC_SPI0 0xFFFE0100 set AT91C_BASE_SPI0 0xFFFE0000 set AT91C_BASE_PDC_US1 0xFFFC4100 set AT91C_BASE_US1 0xFFFC4000 set AT91C_BASE_PDC_US0 0xFFFC0100 set AT91C_BASE_US0 0xFFFC0000 set AT91C_BASE_PDC_SSC 0xFFFD4100 set AT91C_BASE_SSC 0xFFFD4000 set AT91C_BASE_TWI 0xFFFB8000 set AT91C_BASE_PWMC_CH3 0xFFFCC260 set AT91C_BASE_PWMC_CH2 0xFFFCC240 set AT91C_BASE_PWMC_CH1 0xFFFCC220 set AT91C_BASE_PWMC_CH0 0xFFFCC200 set AT91C_BASE_PWMC 0xFFFCC000 set AT91C_BASE_UDP 0xFFFB0000 set AT91C_BASE_TC0 0xFFFA0000 set AT91C_BASE_TC1 0xFFFA0040 set AT91C_BASE_TC2 0xFFFA0080 set AT91C_BASE_TCB 0xFFFA0000 set AT91C_BASE_CAN_MB0 0xFFFD0200 set AT91C_BASE_CAN_MB1 0xFFFD0220 set AT91C_BASE_CAN_MB2 0xFFFD0240 set AT91C_BASE_CAN_MB3 0xFFFD0260 set AT91C_BASE_CAN_MB4 0xFFFD0280 set AT91C_BASE_CAN_MB5 0xFFFD02A0 set AT91C_BASE_CAN_MB6 0xFFFD02C0 set AT91C_BASE_CAN_MB7 0xFFFD02E0 set AT91C_BASE_CAN 0xFFFD0000 set AT91C_BASE_EMAC 0xFFFDC000 set AT91C_BASE_PDC_ADC 0xFFFD8100 set AT91C_BASE_ADC 0xFFFD8000 set AT91C_ID(0) "FIQ" set AT91C_ID(1) "SYS" set AT91C_ID(2) "PIOA" set AT91C_ID(3) "PIOB" set AT91C_ID(4) "SPI0" set AT91C_ID(5) "SPI1" set AT91C_ID(6) "US0" set AT91C_ID(7) "US1" set AT91C_ID(8) "SSC" set AT91C_ID(9) "TWI" set AT91C_ID(10) "PWMC" set AT91C_ID(11) "UDP" set AT91C_ID(12) "TC0" set AT91C_ID(13) "TC1" set AT91C_ID(14) "TC2" set AT91C_ID(15) "CAN" set AT91C_ID(16) "EMAC" set AT91C_ID(17) "ADC" set AT91C_ID(18) "" set AT91C_ID(19) "" set AT91C_ID(20) "" set AT91C_ID(21) "" set AT91C_ID(22) "" set AT91C_ID(23) "" set AT91C_ID(24) "" set AT91C_ID(25) "" set AT91C_ID(26) "" set AT91C_ID(27) "" set AT91C_ID(28) "" set AT91C_ID(29) "" set AT91C_ID(30) "IRQ0" set AT91C_ID(31) "IRQ1" source [find chip/atmel/at91/aic.tcl] source [find chip/atmel/at91/usarts.tcl] source [find chip/atmel/at91/pmc.tcl] source [find chip/atmel/at91/rtt.tcl] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/at91sam9261.cfg ================================================ # # Peripheral identifiers/interrupts. # set AT91_ID_FIQ 0 ;# Advanced Interrupt Controller (FIQ) set AT91_ID_SYS 1 ;# System Peripherals set AT91SAM9261_ID_PIOA 2 ;# Parallel IO Controller A set AT91SAM9261_ID_PIOB 3 ;# Parallel IO Controller B set AT91SAM9261_ID_PIOC 4 ;# Parallel IO Controller C set AT91SAM9261_ID_US0 6 ;# USART 0 set AT91SAM9261_ID_US1 7 ;# USART 1 set AT91SAM9261_ID_US2 8 ;# USART 2 set AT91SAM9261_ID_MCI 9 ;# Multimedia Card Interface set AT91SAM9261_ID_UDP 10 ;# USB Device Port set AT91SAM9261_ID_TWI 11 ;# Two-Wire Interface set AT91SAM9261_ID_SPI0 12 ;# Serial Peripheral Interface 0 set AT91SAM9261_ID_SPI1 13 ;# Serial Peripheral Interface 1 set AT91SAM9261_ID_SSC0 14 ;# Serial Synchronous Controller 0 set AT91SAM9261_ID_SSC1 15 ;# Serial Synchronous Controller 1 set AT91SAM9261_ID_SSC2 16 ;# Serial Synchronous Controller 2 set AT91SAM9261_ID_TC0 17 ;# Timer Counter 0 set AT91SAM9261_ID_TC1 18 ;# Timer Counter 1 set AT91SAM9261_ID_TC2 19 ;# Timer Counter 2 set AT91SAM9261_ID_UHP 20 ;# USB Host port set AT91SAM9261_ID_LCDC 21 ;# LDC Controller set AT91SAM9261_ID_IRQ0 29 ;# Advanced Interrupt Controller (IRQ0) set AT91SAM9261_ID_IRQ1 30 ;# Advanced Interrupt Controller (IRQ1) set AT91SAM9261_ID_IRQ2 31 ;# Advanced Interrupt Controller (IRQ2) # # User Peripheral physical base addresses. # set AT91SAM9261_BASE_TCB0 0xfffa0000 set AT91SAM9261_BASE_TC0 0xfffa0000 set AT91SAM9261_BASE_TC1 0xfffa0040 set AT91SAM9261_BASE_TC2 0xfffa0080 set AT91SAM9261_BASE_UDP 0xfffa4000 set AT91SAM9261_BASE_MCI 0xfffa8000 set AT91SAM9261_BASE_TWI 0xfffac000 set AT91SAM9261_BASE_US0 0xfffb0000 set AT91SAM9261_BASE_US1 0xfffb4000 set AT91SAM9261_BASE_US2 0xfffb8000 set AT91SAM9261_BASE_SSC0 0xfffbc000 set AT91SAM9261_BASE_SSC1 0xfffc0000 set AT91SAM9261_BASE_SSC2 0xfffc4000 set AT91SAM9261_BASE_SPI0 0xfffc8000 set AT91SAM9261_BASE_SPI1 0xfffcc000 set AT91_BASE_SYS 0xffffea00 # # System Peripherals (offset from AT91_BASE_SYS) # set AT91_SDRAMC 0xffffea00 set AT91_SMC 0xffffec00 set AT91_MATRIX 0xffffee00 set AT91_AIC 0xfffff000 set AT91_DBGU 0xfffff200 set AT91_PIOA 0xfffff400 set AT91_PIOB 0xfffff600 set AT91_PIOC 0xfffff800 set AT91_PMC 0xfffffc00 set AT91_RSTC 0xfffffd00 set AT91_SHDWC 0xfffffd10 set AT91_RTT 0xfffffd20 set AT91_PIT 0xfffffd30 set AT91_WDT 0xfffffd40 set AT91_GPBR 0xfffffd50 set AT91_USART0 $AT91SAM9261_BASE_US0 set AT91_USART1 $AT91SAM9261_BASE_US1 set AT91_USART2 $AT91SAM9261_BASE_US2 # # Internal Memory. # set AT91SAM9261_SRAM_BASE 0x00300000 ;# Internal SRAM base address set AT91SAM9261_SRAM_SIZE 0x00028000 ;# Internal SRAM size (160Kb) set AT91SAM9261_ROM_BASE 0x00400000 ;# Internal ROM base address set AT91SAM9261_ROM_SIZE 0x00008000 ;# Internal ROM size (32Kb) set AT91SAM9261_UHP_BASE 0x00500000 ;# USB Host controller set AT91SAM9261_LCDC_BASE 0x00600000 ;# LDC controller # # Cpu Name # set AT91_CPU_NAME "AT91SAM9261" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/at91sam9261_matrix.cfg ================================================ set AT91_MATRIX_MCFG [expr {$AT91_MATRIX + 0x00}] ;# Master Configuration Register # set AT91_MATRIX_RCB0 [expr {1 << 0}] ;# Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) set AT91_MATRIX_RCB1 [expr {1 << 1}] ;# Remap Command for AHB Master 1 (ARM926EJ-S Data Master) set AT91_MATRIX_SCFG0 [expr {$AT91_MATRIX + 0x04}] ;# Slave Configuration Register 0 set AT91_MATRIX_SCFG1 [expr {$AT91_MATRIX + 0x08}] ;# Slave Configuration Register 1 set AT91_MATRIX_SCFG2 [expr {$AT91_MATRIX + 0x0C}] ;# Slave Configuration Register 2 set AT91_MATRIX_SCFG3 [expr {$AT91_MATRIX + 0x10}] ;# Slave Configuration Register 3 set AT91_MATRIX_SCFG4 [expr {$AT91_MATRIX + 0x14}] ;# Slave Configuration Register 4 set AT91_MATRIX_SLOT_CYCLE [expr {0xff << 0}] ;# Maximum Number of Allowed Cycles for a Burst set AT91_MATRIX_DEFMSTR_TYPE [expr {3 << 16}] ;# Default Master Type set AT91_MATRIX_DEFMSTR_TYPE_NONE [expr {0 << 16}] set AT91_MATRIX_DEFMSTR_TYPE_LAST [expr {1 << 16}] set AT91_MATRIX_DEFMSTR_TYPE_FIXED [expr {2 << 16}] set AT91_MATRIX_FIXED_DEFMSTR [expr {7 << 18}] ;# Fixed Index of Default Master set AT91_MATRIX_TCR [expr {$AT91_MATRIX + 0x24}] ;# TCM Configuration Register set AT91_MATRIX_ITCM_SIZE [expr {0xf << 0}] ;# Size of ITCM enabled memory block set AT91_MATRIX_ITCM_0 [expr {0 << 0}] set AT91_MATRIX_ITCM_16 [expr {5 << 0}] set AT91_MATRIX_ITCM_32 [expr {6 << 0}] set AT91_MATRIX_ITCM_64 [expr {7 << 0}] set AT91_MATRIX_DTCM_SIZE [expr {0xf << 4}] ;# Size of DTCM enabled memory block set AT91_MATRIX_DTCM_0 [expr {0 << 4}] set AT91_MATRIX_DTCM_16 [expr {5 << 4}] set AT91_MATRIX_DTCM_32 [expr {6 << 4}] set AT91_MATRIX_DTCM_64 [expr {7 << 4}] set AT91_MATRIX_EBICSA [expr {$AT91_MATRIX + 0x30}] ;# EBI Chip Select Assignment Register set AT91_MATRIX_CS1A [expr {1 << 1}] ;# Chip Select 1 Assignment set AT91_MATRIX_CS1A_SMC [expr {0 << 1}] set AT91_MATRIX_CS1A_SDRAMC [expr {1 << 1}] set AT91_MATRIX_CS3A [expr {1 << 3}] ;# Chip Select 3 Assignment set AT91_MATRIX_CS3A_SMC [expr {0 << 3}] set AT91_MATRIX_CS3A_SMC_SMARTMEDIA [expr {1 << 3}] set AT91_MATRIX_CS4A [expr {1 << 4}] ;# Chip Select 4 Assignment set AT91_MATRIX_CS4A_SMC [expr {0 << 4}] set AT91_MATRIX_CS4A_SMC_CF1 [expr {1 << 4}] set AT91_MATRIX_CS5A [expr {1 << 5}] ;# Chip Select 5 Assignment set AT91_MATRIX_CS5A_SMC [expr {0 << 5}] set AT91_MATRIX_CS5A_SMC_CF2 [expr {1 << 5}] set AT91_MATRIX_DBPUC [expr {1 << 8}] ;# Data Bus Pull-up Configuration set AT91_MATRIX_USBPUCR [expr {$AT91_MATRIX + 0x34}] ;# USB Pad Pull-Up Control Register set AT91_MATRIX_USBPUCR_PUON [expr {1 << 30}] ;# USB Device PAD Pull-up Enable ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/at91sam9263.cfg ================================================ # # Peripheral identifiers/interrupts. # set AT91_ID_FIQ 0 ;# Advanced Interrupt Controller (FIQ) set AT91_ID_SYS 1 ;# System Peripherals set AT91SAM9263_ID_PIOA 2 ;# Parallel IO Controller A set AT91SAM9263_ID_PIOB 3 ;# Parallel IO Controller B set AT91SAM9263_ID_PIOCDE 4 ;# Parallel IO Controller C, D and E set AT91SAM9263_ID_US0 7 ;# USART 0 set AT91SAM9263_ID_US1 8 ;# USART 1 set AT91SAM9263_ID_US2 9 ;# USART 2 set AT91SAM9263_ID_MCI0 10 ;# Multimedia Card Interface 0 set AT91SAM9263_ID_MCI1 11 ;# Multimedia Card Interface 1 set AT91SAM9263_ID_CAN 12 ;# CAN set AT91SAM9263_ID_TWI 13 ;# Two-Wire Interface set AT91SAM9263_ID_SPI0 14 ;# Serial Peripheral Interface 0 set AT91SAM9263_ID_SPI1 15 ;# Serial Peripheral Interface 1 set AT91SAM9263_ID_SSC0 16 ;# Serial Synchronous Controller 0 set AT91SAM9263_ID_SSC1 17 ;# Serial Synchronous Controller 1 set AT91SAM9263_ID_AC97C 18 ;# AC97 Controller set AT91SAM9263_ID_TCB 19 ;# Timer Counter 0, 1 and 2 set AT91SAM9263_ID_PWMC 20 ;# Pulse Width Modulation Controller set AT91SAM9263_ID_EMAC 21 ;# Ethernet set AT91SAM9263_ID_2DGE 23 ;# 2D Graphic Engine set AT91SAM9263_ID_UDP 24 ;# USB Device Port set AT91SAM9263_ID_ISI 25 ;# Image Sensor Interface set AT91SAM9263_ID_LCDC 26 ;# LCD Controller set AT91SAM9263_ID_DMA 27 ;# DMA Controller set AT91SAM9263_ID_UHP 29 ;# USB Host port set AT91SAM9263_ID_IRQ0 30 ;# Advanced Interrupt Controller (IRQ0) set AT91SAM9263_ID_IRQ1 31 ;# Advanced Interrupt Controller (IRQ1) # # User Peripheral physical base addresses. # set AT91SAM9263_BASE_UDP 0xfff78000 set AT91SAM9263_BASE_TCB0 0xfff7c000 set AT91SAM9263_BASE_TC0 0xfff7c000 set AT91SAM9263_BASE_TC1 0xfff7c040 set AT91SAM9263_BASE_TC2 0xfff7c080 set AT91SAM9263_BASE_MCI0 0xfff80000 set AT91SAM9263_BASE_MCI1 0xfff84000 set AT91SAM9263_BASE_TWI 0xfff88000 set AT91SAM9263_BASE_US0 0xfff8c000 set AT91SAM9263_BASE_US1 0xfff90000 set AT91SAM9263_BASE_US2 0xfff94000 set AT91SAM9263_BASE_SSC0 0xfff98000 set AT91SAM9263_BASE_SSC1 0xfff9c000 set AT91SAM9263_BASE_AC97C 0xfffa0000 set AT91SAM9263_BASE_SPI0 0xfffa4000 set AT91SAM9263_BASE_SPI1 0xfffa8000 set AT91SAM9263_BASE_CAN 0xfffac000 set AT91SAM9263_BASE_PWMC 0xfffb8000 set AT91SAM9263_BASE_EMAC 0xfffbc000 set AT91SAM9263_BASE_ISI 0xfffc4000 set AT91SAM9263_BASE_2DGE 0xfffc8000 set AT91_BASE_SYS 0xffffe000 # # System Peripherals (offset from AT91_BASE_SYS) # set AT91_ECC0 0xffffe000 set AT91_SDRAMC0 0xffffe200 set AT91_SMC0 0xffffe400 set AT91_ECC1 0xffffe600 set AT91_SDRAMC1 0xffffe800 set AT91_SMC1 0xffffea00 set AT91_MATRIX 0xffffec00 set AT91_CCFG 0xffffed10 set AT91_DBGU 0xffffee00 set AT91_AIC 0xfffff000 set AT91_PIOA 0xfffff200 set AT91_PIOB 0xfffff400 set AT91_PIOC 0xfffff600 set AT91_PIOD 0xfffff800 set AT91_PIOE 0xfffffa00 set AT91_PMC 0xfffffc00 set AT91_RSTC 0xfffffd00 set AT91_SHDWC 0xfffffd10 set AT91_RTT0 0xfffffd20 set AT91_PIT 0xfffffd30 set AT91_WDT 0xfffffd40 set AT91_RTT1 0xfffffd50 set AT91_GPBR 0xfffffd60 set AT91_USART0 $AT91SAM9263_BASE_US0 set AT91_USART1 $AT91SAM9263_BASE_US1 set AT91_USART2 $AT91SAM9263_BASE_US2 set AT91_SMC $AT91_SMC0 set AT91_SDRAMC $AT91_SDRAMC0 # # Internal Memory. # set AT91SAM9263_SRAM0_BASE 0x00300000 ;# Internal SRAM 0 base address set AT91SAM9263_SRAM0_SIZE 0x00014000 ;# Internal SRAM 0 size (80Kb) set AT91SAM9263_ROM_BASE 0x00400000 ;# Internal ROM base address set AT91SAM9263_ROM_SIZE 0x00020000 ;# Internal ROM size (128Kb) set AT91SAM9263_SRAM1_BASE 0x00500000 ;# Internal SRAM 1 base address set AT91SAM9263_SRAM1_SIZE 0x00004000 ;# Internal SRAM 1 size (16Kb) set AT91SAM9263_LCDC_BASE 0x00700000 ;# LCD Controller set AT91SAM9263_DMAC_BASE 0x00800000 ;# DMA Controller set AT91SAM9263_UHP_BASE 0x00a00000 ;# USB Host controller # # Cpu Name # set AT91_CPU_NAME "AT91SAM9263" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/at91sam9263_matrix.cfg ================================================ set AT91_MATRIX_MCFG0 [expr {$AT91_MATRIX + 0x00}] ;# Master Configuration Register 0 set AT91_MATRIX_MCFG1 [expr {$AT91_MATRIX + 0x04}] ;# Master Configuration Register 1 set AT91_MATRIX_MCFG2 [expr {$AT91_MATRIX + 0x08}] ;# Master Configuration Register 2 set AT91_MATRIX_MCFG3 [expr {$AT91_MATRIX + 0x0C}] ;# Master Configuration Register 3 set AT91_MATRIX_MCFG4 [expr {$AT91_MATRIX + 0x10}] ;# Master Configuration Register 4 set AT91_MATRIX_MCFG5 [expr {$AT91_MATRIX + 0x14}] ;# Master Configuration Register 5 set AT91_MATRIX_MCFG6 [expr {$AT91_MATRIX + 0x18}] ;# Master Configuration Register 6 set AT91_MATRIX_MCFG7 [expr {$AT91_MATRIX + 0x1C}] ;# Master Configuration Register 7 set AT91_MATRIX_MCFG8 [expr {$AT91_MATRIX + 0x20}] ;# Master Configuration Register 8 set AT91_MATRIX_ULBT [expr {7 << 0}] ;# Undefined Length Burst Type set AT91_MATRIX_ULBT_INFINITE [expr {0 << 0}] set AT91_MATRIX_ULBT_SINGLE [expr {1 << 0}] set AT91_MATRIX_ULBT_FOUR [expr {2 << 0}] set AT91_MATRIX_ULBT_EIGHT [expr {3 << 0}] set AT91_MATRIX_ULBT_SIXTEEN [expr {4 << 0}] set AT91_MATRIX_SCFG0 [expr {$AT91_MATRIX + 0x40}] ;# Slave Configuration Register 0 set AT91_MATRIX_SCFG1 [expr {$AT91_MATRIX + 0x44}] ;# Slave Configuration Register 1 set AT91_MATRIX_SCFG2 [expr {$AT91_MATRIX + 0x48}] ;# Slave Configuration Register 2 set AT91_MATRIX_SCFG3 [expr {$AT91_MATRIX + 0x4C}] ;# Slave Configuration Register 3 set AT91_MATRIX_SCFG4 [expr {$AT91_MATRIX + 0x50}] ;# Slave Configuration Register 4 set AT91_MATRIX_SCFG5 [expr {$AT91_MATRIX + 0x54}] ;# Slave Configuration Register 5 set AT91_MATRIX_SCFG6 [expr {$AT91_MATRIX + 0x58}] ;# Slave Configuration Register 6 set AT91_MATRIX_SCFG7 [expr {$AT91_MATRIX + 0x5C}] ;# Slave Configuration Register 7 set AT91_MATRIX_SLOT_CYCLE [expr {0xff << 0}] ;# Maximum Number of Allowed Cycles for a Burst set AT91_MATRIX_DEFMSTR_TYPE [expr {3 << 16}] ;# Default Master Type set AT91_MATRIX_DEFMSTR_TYPE_NONE [expr {0 << 16}] set AT91_MATRIX_DEFMSTR_TYPE_LAST [expr {1 << 16}] set AT91_MATRIX_DEFMSTR_TYPE_FIXED [expr {2 << 16}] set AT91_MATRIX_FIXED_DEFMSTR [expr {0xf << 18}] ;# Fixed Index of Default Master set AT91_MATRIX_ARBT [expr {3 << 24}] ;# Arbitration Type set AT91_MATRIX_ARBT_ROUND_ROBIN [expr {0 << 24}] set AT91_MATRIX_ARBT_FIXED_PRIORITY [expr {1 << 24}] set AT91_MATRIX_PRAS0 [expr {$AT91_MATRIX + 0x80}] ;# Priority Register A for Slave 0 set AT91_MATRIX_PRBS0 [expr {$AT91_MATRIX + 0x84}] ;# Priority Register B for Slave 0 set AT91_MATRIX_PRAS1 [expr {$AT91_MATRIX + 0x88}] ;# Priority Register A for Slave 1 set AT91_MATRIX_PRBS1 [expr {$AT91_MATRIX + 0x8C}] ;# Priority Register B for Slave 1 set AT91_MATRIX_PRAS2 [expr {$AT91_MATRIX + 0x90}] ;# Priority Register A for Slave 2 set AT91_MATRIX_PRBS2 [expr {$AT91_MATRIX + 0x94}] ;# Priority Register B for Slave 2 set AT91_MATRIX_PRAS3 [expr {$AT91_MATRIX + 0x98}] ;# Priority Register A for Slave 3 set AT91_MATRIX_PRBS3 [expr {$AT91_MATRIX + 0x9C}] ;# Priority Register B for Slave 3 set AT91_MATRIX_PRAS4 [expr {$AT91_MATRIX + 0xA0}] ;# Priority Register A for Slave 4 set AT91_MATRIX_PRBS4 [expr {$AT91_MATRIX + 0xA4}] ;# Priority Register B for Slave 4 set AT91_MATRIX_PRAS5 [expr {$AT91_MATRIX + 0xA8}] ;# Priority Register A for Slave 5 set AT91_MATRIX_PRBS5 [expr {$AT91_MATRIX + 0xAC}] ;# Priority Register B for Slave 5 set AT91_MATRIX_PRAS6 [expr {$AT91_MATRIX + 0xB0}] ;# Priority Register A for Slave 6 set AT91_MATRIX_PRBS6 [expr {$AT91_MATRIX + 0xB4}] ;# Priority Register B for Slave 6 set AT91_MATRIX_PRAS7 [expr {$AT91_MATRIX + 0xB8}] ;# Priority Register A for Slave 7 set AT91_MATRIX_PRBS7 [expr {$AT91_MATRIX + 0xBC}] ;# Priority Register B for Slave 7 set AT91_MATRIX_M0PR [expr {3 << 0}] ;# Master 0 Priority set AT91_MATRIX_M1PR [expr {3 << 4}] ;# Master 1 Priority set AT91_MATRIX_M2PR [expr {3 << 8}] ;# Master 2 Priority set AT91_MATRIX_M3PR [expr {3 << 12}] ;# Master 3 Priority set AT91_MATRIX_M4PR [expr {3 << 16}] ;# Master 4 Priority set AT91_MATRIX_M5PR [expr {3 << 20}] ;# Master 5 Priority set AT91_MATRIX_M6PR [expr {3 << 24}] ;# Master 6 Priority set AT91_MATRIX_M7PR [expr {3 << 28}] ;# Master 7 Priority set AT91_MATRIX_M8PR [expr {3 << 0}] ;# Master 8 Priority (in Register B) set AT91_MATRIX_MRCR [expr {$AT91_MATRIX + 0x100}] ;# Master Remap Control Register set AT91_MATRIX_RCB0 [expr {1 << 0}] ;# Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) set AT91_MATRIX_RCB1 [expr {1 << 1}] ;# Remap Command for AHB Master 1 (ARM926EJ-S Data Master) set AT91_MATRIX_RCB2 [expr {1 << 2}] set AT91_MATRIX_RCB3 [expr {1 << 3}] set AT91_MATRIX_RCB4 [expr {1 << 4}] set AT91_MATRIX_RCB5 [expr {1 << 5}] set AT91_MATRIX_RCB6 [expr {1 << 6}] set AT91_MATRIX_RCB7 [expr {1 << 7}] set AT91_MATRIX_RCB8 [expr {1 << 8}] set AT91_MATRIX_TCMR [expr {$AT91_MATRIX + 0x114}] ;# TCM Configuration Register set AT91_MATRIX_ITCM_SIZE [expr {0xf << 0}] ;# Size of ITCM enabled memory block set AT91_MATRIX_ITCM_0 [expr {0 << 0}] set AT91_MATRIX_ITCM_16 [expr {5 << 0}] set AT91_MATRIX_ITCM_32 [expr {6 << 0}] set AT91_MATRIX_DTCM_SIZE [expr {0xf << 4}] ;# Size of DTCM enabled memory block set AT91_MATRIX_DTCM_0 [expr {0 << 4}] set AT91_MATRIX_DTCM_16 [expr {5 << 4}] set AT91_MATRIX_DTCM_32 [expr {6 << 4}] set AT91_MATRIX_EBI0CSA [expr {$AT91_MATRIX + 0x120}] ;# EBI0 Chip Select Assignment Register set AT91_MATRIX_EBI0_CS1A [expr {1 << 1}] ;# Chip Select 1 Assignment set AT91_MATRIX_EBI0_CS1A_SMC [expr {0 << 1}] set AT91_MATRIX_EBI0_CS1A_SDRAMC [expr {1 << 1}] set AT91_MATRIX_EBI0_CS3A [expr {1 << 3}] ;# Chip Select 3 Assignmen set AT91_MATRIX_EBI0_CS3A_SMC [expr {0 << 3}] set AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA [expr {1 << 3}] set AT91_MATRIX_EBI0_CS4A [expr {1 << 4}] ;# Chip Select 4 Assignment set AT91_MATRIX_EBI0_CS4A_SMC [expr {0 << 4}] set AT91_MATRIX_EBI0_CS4A_SMC_CF1 [expr {1 << 4}] set AT91_MATRIX_EBI0_CS5A [expr {1 << 5}] ;# Chip Select 5 Assignment set AT91_MATRIX_EBI0_CS5A_SMC [expr {0 << 5}] set AT91_MATRIX_EBI0_CS5A_SMC_CF2 [expr {1 << 5}] set AT91_MATRIX_EBI0_DBPUC [expr {1 << 8}] ;# Data Bus Pull-up Configuration set AT91_MATRIX_EBI0_VDDIOMSEL [expr {1 << 16}] ;# Memory voltage selection set AT91_MATRIX_EBI0_VDDIOMSEL_1_8V [expr {0 << 16}] set AT91_MATRIX_EBI0_VDDIOMSEL_3_3V [expr {1 << 16}] set AT91_MATRIX_EBI1CSA [expr {$AT91_MATRIX + 0x124}] ;# EBI1 Chip Select Assignment Register set AT91_MATRIX_EBI1_CS1A [expr {1 << 1}] ;# Chip Select 1 Assignment set AT91_MATRIX_EBI1_CS1A_SMC [expr {0 << 1}] set AT91_MATRIX_EBI1_CS1A_SDRAMC [expr {1 << 1}] set AT91_MATRIX_EBI1_CS2A [expr {1 << 3}] ;# Chip Select 3 Assignment set AT91_MATRIX_EBI1_CS2A_SMC [expr {0 << 3}] set AT91_MATRIX_EBI1_CS2A_SMC_SMARTMEDIA [expr {1 << 3}] set AT91_MATRIX_EBI1_DBPUC [expr {1 << 8}] ;# Data Bus Pull-up Configuration set AT91_MATRIX_EBI1_VDDIOMSEL [expr {1 << 16}] ;# Memory voltage selection set AT91_MATRIX_EBI1_VDDIOMSEL_1_8V [expr {0 << 16}] set AT91_MATRIX_EBI1_VDDIOMSEL_3_3V [expr {1 << 16}] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/at91sam9_init.cfg ================================================ uplevel #0 [list source [find chip/atmel/at91/at91sam9_sdramc.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91_pmc.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91_pio.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91_rstc.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91_wdt.cfg]] proc at91sam9_reset_start { } { arm7_9 fast_memory_access disable jtag_rclk 8 halt wait_halt 10000 set rstc_mr_val $::AT91_RSTC_KEY set rstc_mr_val [expr {$rstc_mr_val | (5 << 8)}] set rstc_mr_val [expr {$rstc_mr_val | $::AT91_RSTC_URSTEN}] mww $::AT91_RSTC_MR $rstc_mr_val ;# RSTC_MR : enable user reset. } proc at91sam9_reset_init { config } { mww $::AT91_WDT_MR $config(wdt_mr_val) ;# disable watchdog set ckgr_mor [expr {$::AT91_PMC_MOSCEN | (255 << 8)}] mww $::AT91_CKGR_MOR $ckgr_mor ;# CKGR_MOR - enable main osc. while { [expr {[mrw $::AT91_PMC_SR] & $::AT91_PMC_MOSCS}] != $::AT91_PMC_MOSCS } { sleep 1 } set pllar_val $::AT91_PMC_PLLA_WR_ERRATA ;# Bit 29 must be 1 when prog set pllar_val [expr {$pllar_val | $::AT91_PMC_OUT}] set pllar_val [expr {$pllar_val | $::AT91_PMC_PLLCOUNT}] set pllar_val [expr {$pllar_val | ($config(master_pll_mul) - 1) << 16}] set pllar_val [expr {$pllar_val | $config(master_pll_div)}] mww $::AT91_CKGR_PLLAR $pllar_val ;# CKGR_PLLA - (18.432MHz/13)*141 = 199.9 MHz while { [expr {[mrw $::AT91_PMC_SR] & $::AT91_PMC_LOCKA}] != $::AT91_PMC_LOCKA } { sleep 1 } ;# PCK/2 = MCK Master Clock from PLLA set mckr_val $::AT91_PMC_CSS_PLLA set mckr_val [expr {$mckr_val | $::AT91_PMC_PRES_1}] set mckr_val [expr {$mckr_val | $::AT91SAM9_PMC_MDIV_2}] set mckr_val [expr {$mckr_val | $::AT91_PMC_PDIV_1}] mww $::AT91_PMC_MCKR $mckr_val ;# PMC_MCKR (MCLK: 0x102 - (CLK/2)MHZ, 0x202 - (CLK/3)MHz) while { [expr {[mrw $::AT91_PMC_SR] & $::AT91_PMC_MCKRDY}] != $::AT91_PMC_MCKRDY } { sleep 1 } ## switch JTAG clock to highspeed clock jtag_rclk 0 arm7_9 dcc_downloads enable ;# Enable faster DCC downloads arm7_9 fast_memory_access enable set rstc_mr_val $::AT91_RSTC_KEY set rstc_mr_val [expr {$rstc_mr_val | $::AT91_RSTC_URSTEN}] mww $::AT91_RSTC_MR $rstc_mr_val ;# user reset enable if { [info exists config(sdram_piod)] } { set pdr_addr [expr {$::AT91_PIOD + $::PIO_PDR}] set pudr_addr [expr {$::AT91_PIOD + $::PIO_PUDR}] set asr_addr [expr {$::AT91_PIOD + $::PIO_ASR}] mww $pdr_addr 0xffff0000 ;# define PDC[31:16] as DATA[31:16] mww $pudr_addr 0xffff0000 ;# no pull-up for D[31:16] mww $asr_addr 0xffff0000 } else { set pdr_addr [expr {$::AT91_PIOC + $::PIO_PDR}] set pudr_addr [expr {$::AT91_PIOC + $::PIO_PUDR}] mww $pdr_addr 0xffff0000 ;# define PDC[31:16] as DATA[31:16] mww $pudr_addr 0xffff0000 ;# no pull-up for D[31:16] } mww $config(matrix_ebicsa_addr) $config(matrix_ebicsa_val) mww $::AT91_SDRAMC_MR $::AT91_SDRAMC_MODE_NORMAL ;# SDRAMC_MR Mode register mww $::AT91_SDRAMC_TR $config(sdram_tr_val) ;# SDRAMC_TR - Refresh Timer register mww $::AT91_SDRAMC_CR $config(sdram_cr_val) ;# SDRAMC_CR - Configuration register mww $::AT91_SDRAMC_MDR $::AT91_SDRAMC_MD_SDRAM ;# Memory Device Register -> SDRAM mww $::AT91_SDRAMC_MR $::AT91_SDRAMC_MODE_PRECHARGE ;# SDRAMC_MR mww $config(sdram_base) 0 ;# SDRAM_BASE mww $::AT91_SDRAMC_MR $::AT91_SDRAMC_MODE_REFRESH ;# SDRC_MR mww $config(sdram_base) 0 ;# SDRAM_BASE mww $config(sdram_base) 0 ;# SDRAM_BASE mww $config(sdram_base) 0 ;# SDRAM_BASE mww $config(sdram_base) 0 ;# SDRAM_BASE mww $config(sdram_base) 0 ;# SDRAM_BASE mww $config(sdram_base) 0 ;# SDRAM_BASE mww $config(sdram_base) 0 ;# SDRAM_BASE mww $config(sdram_base) 0 ;# SDRAM_BASE mww $::AT91_SDRAMC_MR $::AT91_SDRAMC_MODE_LMR ;# SDRC_MR mww $config(sdram_base) 0 ;# SDRAM_BASE mww $::AT91_SDRAMC_MR $::AT91_SDRAMC_MODE_NORMAL ;# SDRC_MR mww $config(sdram_base) 0 ;# SDRAM_BASE mww $::AT91_SDRAMC_TR 1200 ;# SDRAM_TR mww $config(sdram_base) 0 ;# SDRAM_BASE mww $::AT91_MATRIX 0xf ;# MATRIX_MCFG - REMAP all masters } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/at91sam9_sdramc.cfg ================================================ # SDRAM Controller (SDRAMC) registers set AT91_SDRAMC_MR [expr {$AT91_SDRAMC + 0x00}] ;# SDRAM Controller Mode Register set AT91_SDRAMC_MODE [expr {0xf << 0}] ;# Command Mode set AT91_SDRAMC_MODE_NORMAL 0 set AT91_SDRAMC_MODE_NOP 1 set AT91_SDRAMC_MODE_PRECHARGE 2 set AT91_SDRAMC_MODE_LMR 3 set AT91_SDRAMC_MODE_REFRESH 4 set AT91_SDRAMC_MODE_EXT_LMR 5 set AT91_SDRAMC_MODE_DEEP 6 set AT91_SDRAMC_TR [expr {$AT91_SDRAMC + 0x04}] ;# SDRAM Controller Refresh Timer Register set AT91_SDRAMC_COUNT [expr {0xfff << 0}] ;# Refresh Timer Counter set AT91_SDRAMC_CR [expr {$AT91_SDRAMC + 0x08}] ;# SDRAM Controller Configuration Register set AT91_SDRAMC_NC [expr {3 << 0}] ;# Number of Column Bits set AT91_SDRAMC_NC_8 [expr {0 << 0}] set AT91_SDRAMC_NC_9 [expr {1 << 0}] set AT91_SDRAMC_NC_10 [expr {2 << 0}] set AT91_SDRAMC_NC_11 [expr {3 << 0}] set AT91_SDRAMC_NR [expr {3 << 2}] ;# Number of Row Bits set AT91_SDRAMC_NR_11 [expr {0 << 2}] set AT91_SDRAMC_NR_12 [expr {1 << 2}] set AT91_SDRAMC_NR_13 [expr {2 << 2}] set AT91_SDRAMC_NB [expr {1 << 4}] ;# Number of Banks set AT91_SDRAMC_NB_2 [expr {0 << 4}] set AT91_SDRAMC_NB_4 [expr {1 << 4}] set AT91_SDRAMC_CAS [expr {3 << 5}] ;# CAS Latency set AT91_SDRAMC_CAS_1 [expr {1 << 5}] set AT91_SDRAMC_CAS_2 [expr {2 << 5}] set AT91_SDRAMC_CAS_3 [expr {3 << 5}] set AT91_SDRAMC_DBW [expr {1 << 7}] ;# Data Bus Width set AT91_SDRAMC_DBW_32 [expr {0 << 7}] set AT91_SDRAMC_DBW_16 [expr {1 << 7}] set AT91_SDRAMC_TWR [expr {0xf << 8}] ;# Write Recovery Delay set AT91_SDRAMC_TRC [expr {0xf << 12}] ;# Row Cycle Delay set AT91_SDRAMC_TRP [expr {0xf << 16}] ;# Row Precharge Delay set AT91_SDRAMC_TRCD [expr {0xf << 20}] ;# Row to Column Delay set AT91_SDRAMC_TRAS [expr {0xf << 24}] ;# Active to Precharge Delay set AT91_SDRAMC_TXSR [expr {0xf << 28}] ;# Exit Self Refresh to Active Delay set AT91_SDRAMC_LPR [expr {$AT91_SDRAMC + 0x10}] ;# SDRAM Controller Low Power Register set AT91_SDRAMC_LPCB [expr {3 << 0}] ;# Low-power Configurations set AT91_SDRAMC_LPCB_DISABLE 0 set AT91_SDRAMC_LPCB_SELF_REFRESH 1 set AT91_SDRAMC_LPCB_POWER_DOWN 2 set AT91_SDRAMC_LPCB_DEEP_POWER_DOWN 3 set AT91_SDRAMC_PASR [expr {7 << 4}] ;# Partial Array Self Refresh set AT91_SDRAMC_TCSR [expr {3 << 8}] ;# Temperature Compensated Self Refresh set AT91_SDRAMC_DS [expr {3 << 10}] ;# Drive Strength set AT91_SDRAMC_TIMEOUT [expr {3 << 12}] ;# Time to define when Low Power Mode is enabled set AT91_SDRAMC_TIMEOUT_0_CLK_CYCLES [expr {0 << 12}] set AT91_SDRAMC_TIMEOUT_64_CLK_CYCLES [expr {1 << 12}] set AT91_SDRAMC_TIMEOUT_128_CLK_CYCLES [expr {2 << 12}] set AT91_SDRAMC_IER [expr {$AT91_SDRAMC + 0x14}] ;# SDRAM Controller Interrupt Enable Register set AT91_SDRAMC_IDR [expr {$AT91_SDRAMC + 0x18}] ;# SDRAM Controller Interrupt Disable Register set AT91_SDRAMC_IMR [expr {$AT91_SDRAMC + 0x1C}] ;# SDRAM Controller Interrupt Mask Register set AT91_SDRAMC_ISR [expr {$AT91_SDRAMC + 0x20}] ;# SDRAM Controller Interrupt Status Register set AT91_SDRAMC_RES [expr {1 << 0}] ;# Refresh Error Status set AT91_SDRAMC_MDR [expr {$AT91_SDRAMC + 0x24}] ;# SDRAM Memory Device Register set AT91_SDRAMC_MD [expr {3 << 0}] ;# Memory Device Type set AT91_SDRAMC_MD_SDRAM 0 set AT91_SDRAMC_MD_LOW_POWER_SDRAM 1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/at91sam9_smc.cfg ================================================ set AT91_SMC_READMODE [expr {1 << 0}] ;# Read Mode set AT91_SMC_WRITEMODE [expr {1 << 1}] ;# Write Mode set AT91_SMC_EXNWMODE [expr {3 << 4}] ;# NWAIT Mode set AT91_SMC_EXNWMODE_DISABLE [expr {0 << 4}] set AT91_SMC_EXNWMODE_FROZEN [expr {2 << 4}] set AT91_SMC_EXNWMODE_READY [expr {3 << 4}] set AT91_SMC_BAT [expr {1 << 8}] ;# Byte Access Type set AT91_SMC_BAT_SELECT [expr {0 << 8}] set AT91_SMC_BAT_WRITE [expr {1 << 8}] set AT91_SMC_DBW [expr {3 << 12}] ;# Data Bus Width */ set AT91_SMC_DBW_8 [expr {0 << 12}] set AT91_SMC_DBW_16 [expr {1 << 12}] set AT91_SMC_DBW_32 [expr {2 << 12}] set AT91_SMC_TDFMODE [expr {1 << 20}] ;# TDF Optimization - Enabled set AT91_SMC_PMEN [expr {1 << 24}] ;# Page Mode Enabled set AT91_SMC_PS [expr {3 << 28}] ;# Page Size set AT91_SMC_PS_4 [expr {0 << 28}] set AT91_SMC_PS_8 [expr {1 << 28}] set AT91_SMC_PS_16 [expr {2 << 28}] set AT91_SMC_PS_32 [expr {3 << 28}] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/hardware.cfg ================================================ # External Memory Map set AT91_CHIPSELECT_0 0x10000000 set AT91_CHIPSELECT_1 0x20000000 set AT91_CHIPSELECT_2 0x30000000 set AT91_CHIPSELECT_3 0x40000000 set AT91_CHIPSELECT_4 0x50000000 set AT91_CHIPSELECT_5 0x60000000 set AT91_CHIPSELECT_6 0x70000000 set AT91_CHIPSELECT_7 0x80000000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/pmc.tcl ================================================ if [info exists AT91C_MAINOSC_FREQ] { # user set this... let it be. } { # 18.432mhz is a common thing... set AT91C_MAINOSC_FREQ 18432000 } global AT91C_MAINOSC_FREQ if [info exists AT91C_SLOWOSC_FREQ] { # user set this... let it be. } { # 32khz is the norm set AT91C_SLOWOSC_FREQ 32768 } global AT91C_SLOWOSC_FREQ ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/rtt.tcl ================================================ set RTTC_RTMR [expr {$AT91C_BASE_RTTC + 0x00}] set RTTC_RTAR [expr {$AT91C_BASE_RTTC + 0x04}] set RTTC_RTVR [expr {$AT91C_BASE_RTTC + 0x08}] set RTTC_RTSR [expr {$AT91C_BASE_RTTC + 0x0c}] global RTTC_RTMR global RTTC_RTAR global RTTC_RTVR global RTTC_RTSR proc show_RTTC_RTMR_helper { NAME ADDR VAL } { set rtpres [expr {$VAL & 0x0ffff}] global BIT16 BIT17 if { $rtpres == 0 } { set rtpres 65536; } global AT91C_SLOWOSC_FREQ # Nasty hack, make this a float by tacking a .0 on the end # otherwise, jim makes the value an integer set f [expr "$AT91C_SLOWOSC_FREQ.0 / $rtpres.0"] echo [format "\tPrescale value: 0x%04x (%5d) => %f Hz" $rtpres $rtpres $f] if { $VAL & $BIT16 } { echo "\tBit16 -> Alarm IRQ Enabled" } else { echo "\tBit16 -> Alarm IRQ Disabled" } if { $VAL & $BIT17 } { echo "\tBit17 -> RTC Inc IRQ Enabled" } else { echo "\tBit17 -> RTC Inc IRQ Disabled" } # Bit 18 is write only. } proc show_RTTC_RTSR_helper { NAME ADDR VAL } { global BIT0 BIT1 if { $VAL & $BIT0 } { echo "\tBit0 -> ALARM PENDING" } else { echo "\tBit0 -> alarm not pending" } if { $VAL & $BIT1 } { echo "\tBit0 -> RTINC PENDING" } else { echo "\tBit0 -> rtinc not pending" } } proc show_RTTC { } { show_mmr32_reg RTTC_RTMR show_mmr32_reg RTTC_RTAR show_mmr32_reg RTTC_RTVR show_mmr32_reg RTTC_RTSR } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/sam9_smc.cfg ================================================ # Setup register # # ncs_read_setup # nrd_setup # ncs_write_setup # set nwe_setup # # # Pulse register # # ncs_read_pulse # nrd_pulse # ncs_write_pulse # nwe_pulse # # # Cycle register # # read_cycle 0 # write_cycle 0 # # # Mode register # # mode # tdf_cycles proc sam9_smc_config { cs smc_config } { ;# Setup Register for CS n set AT91_SMC_SETUP [expr {$::AT91_SMC + 0x00 + $cs * 0x10}] set val [expr {$smc_config(nwe_setup) << 0}] set val [expr {$val | $smc_config(ncs_write_setup) << 8}] set val [expr {$val | $smc_config(nrd_setup)) << 16}] set val [expr {$val | $smc_config(ncs_read_setup) << 24}] mww $AT91_SMC_SETUP $val ;# Pulse Register for CS n set AT91_SMC_PULSE [expr {$::AT91_SMC + 0x04 + $cs * 0x10}] set val [expr {$smc_config(nwe_pulse) << 0}] set val [expr {$val | $smc_config(ncs_write_pulse) << 8}] set val [expr {$val | $smc_config(nrd_pulse) << 16}] set val [expr {$val | $smc_config(ncs_read_pulse) << 24}] mww $AT91_SMC_PULSE $val ;# Cycle Register for CS n set AT91_SMC_CYCLE [expr {$::AT91_SMC + 0x08 + $cs * 0x10}] set val [expr {$smc_config(write_cycle) << 0}] set val [expr {$val | $smc_config(read_cycle) << 16}] mww $AT91_SMC_CYCLE $val ;# Mode Register for CS n set AT91_SMC_MODE [expr {$::AT91_SMC + 0x0c + $cs * 0x10}] set val [expr {$smc_config(mode) << 0}] set val [expr {$val | $smc_config(tdf_cycles) << 16}] mww $AT91_SMC_MODE $val } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/atmel/at91/usarts.tcl ================================================ # the DBGU and USARTs are 'almost' indentical' set DBGU_CR [expr {$AT91C_BASE_DBGU + 0x00000000}] set DBGU_MR [expr {$AT91C_BASE_DBGU + 0x00000004}] set DBGU_IER [expr {$AT91C_BASE_DBGU + 0x00000008}] set DBGU_IDR [expr {$AT91C_BASE_DBGU + 0x0000000C}] set DBGU_IMR [expr {$AT91C_BASE_DBGU + 0x00000010}] set DBGU_CSR [expr {$AT91C_BASE_DBGU + 0x00000014}] set DBGU_RHR [expr {$AT91C_BASE_DBGU + 0x00000018}] set DBGU_THR [expr {$AT91C_BASE_DBGU + 0x0000001C}] set DBGU_BRGR [expr {$AT91C_BASE_DBGU + 0x00000020}] # no RTOR # no TTGR # no FIDI # no NER set DBGU_CIDR [expr {$AT91C_BASE_DBGU + 0x00000040}] set DBGU_EXID [expr {$AT91C_BASE_DBGU + 0x00000044}] set DBGU_FNTR [expr {$AT91C_BASE_DBGU + 0x00000048}] set USx_CR 0x00000000 set USx_MR 0x00000004 set USx_IER 0x00000008 set USx_IDR 0x0000000C set USx_IMR 0x00000010 set USx_CSR 0x00000014 set USx_RHR 0x00000018 set USx_THR 0x0000001C set USx_BRGR 0x00000020 set USx_RTOR 0x00000024 set USx_TTGR 0x00000028 set USx_FIDI 0x00000040 set USx_NER 0x00000044 set USx_IF 0x0000004C # Create all the uarts that exist.. # we blow up if there are >9 proc show_mmr_USx_MR_helper { NAME ADDR VAL } { # First - just print it set x [show_normalize_bitfield $VAL 3 0] if { $x == 0 } { echo "\tNormal operation" } else { echo [format "\tNon Normal operation mode: 0x%02x" $x] } set x [show_normalize_bitfield $VAL 11 9] set s "unknown" switch -exact $x { 0 { set s "Even" } 1 { set s "Odd" } 2 { set s "Force=0" } 3 { set s "Force=1" } * { set $x [expr {$x & 6}] switch -exact $x { 4 { set s "None" } 6 { set s "Multidrop Mode" } } } } echo [format "\tParity: %s " $s] set x [expr {5 + [show_normalize_bitfield $VAL 7 6]}] echo [format "\tDatabits: %d" $x] set x [show_normalize_bitfield $VAL 13 12] switch -exact $x { 0 { echo "\tStop bits: 1" } 1 { echo "\tStop bits: 1.5" } 2 { echo "\tStop bits: 2" } 3 { echo "\tStop bits: Illegal/Reserved" } } } # For every possbile usart... foreach WHO { US0 US1 US2 US3 US4 US5 US6 US7 US8 US9 } { set n AT91C_BASE_[set WHO] set str "" # Only if it exists on the chip if [ info exists $n ] { # Hence: $n - is like AT91C_BASE_USx # For every sub-register foreach REG {CR MR IER IDR IMR CSR RHR THR BRGR RTOR TTGR FIDI NER IF} { # vn = variable name set vn [set WHO]_[set REG] # vn = USx_IER # vv = variable value set vv [expr "$$n + [set USx_[set REG]]"] # And VV is the address in memory of that register # make that VN a GLOBAL so others can find it global $vn set $vn $vv # Create a command for this specific register. proc show_$vn { } "show_mmr32_reg $vn" # Add this command to the Device(as a whole) command set str "$str\nshow_$vn" } # Now - create the DEVICE(as a whole) command set fn show_$WHO proc $fn { } $str } } # The Debug Uart is special.. set str "" # For every sub-register foreach REG {DBGU_CR DBGU_MR DBGU_IER DBGU_IDR DBGU_IMR DBGU_CSR DBGU_RHR DBGU_THR DBGU_BRGR DBGU_CIDR DBGU_EXID DBGU_FNTR} { # Create a command for this specific register. proc show_$REG { } "show_mmr32_reg $REG" # Add this command to the Device(as a whole) command set str "$str\nshow_$REG" } # Now - create the DEVICE(as a whole) command proc show_DBGU { } $str unset str proc show_DBGU_MR_helper { NAME ADDR VAL } { show_mmr_USx_MR_helper $NAME $ADDR $VAL } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/st/spear/quirk_no_srst.tcl ================================================ # Quirks to bypass missing SRST on JTAG connector # EVALSPEAr310 Rev. 2.0 # http://www.st.com/spear # # Date: 2010-08-17 # Author: Antonio Borneo # For boards that have JTAG SRST not connected. # We use "arm9 vector_catch reset" to catch button reset event. $_TARGETNAME configure -event reset-assert sp_reset_assert $_TARGETNAME configure -event reset-deassert-post sp_reset_deassert_post # keeps the name of the SPEAr target global sp_target_name set sp_target_name $_TARGETNAME # Keeps the argument of "reset" command (run, init, halt). global sp_reset_mode set sp_reset_mode "" # Helper procedure. Returns 0 is target is halted. proc sp_is_halted {} { global sp_target_name return [expr {[string compare [$sp_target_name curstate] "halted" ] == 0}] } # wait for reset button to be pressed, causing CPU to get halted proc sp_reset_deassert_post {} { global sp_reset_mode set bar(0) | set bar(1) / set bar(2) - set bar(3) \\ poll on echo "====> Press reset button on the board <====" for {set i 0} { [sp_is_halted] == 0 } { set i [expr {$i + 1}]} { echo -n "$bar([expr {$i & 3}])\r" sleep 200 } # Remove catch reset event arm9 vector_catch none # CPU is halted, but we typed "reset run" ... if { [string compare $sp_reset_mode "run"] == 0 } { resume } } # Override reset-assert, since no SRST available # Catch reset event proc sp_reset_assert {} { arm9 vector_catch reset } # Override default init_reset{mode} to catch parameter "mode" proc init_reset {mode} { global sp_reset_mode set sp_reset_mode $mode # We need to detect CPU get halted, so exit from halt if { [sp_is_halted] } { echo "Resuming CPU to detect reset" resume } # Execute default init_reset{mode} jtag arp_init-reset } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/st/spear/spear3xx.tcl ================================================ # Generic init scripts for all ST SPEAr3xx family # http://www.st.com/spear # # Date: 2010-09-23 # Author: Antonio Borneo # Initialize internal clock # Default: # - Crystal = 24 MHz # - PLL1 = 332 MHz # - PLL2 = 332 MHz # - CPU_CLK = 332 MHz # - DDR_CLK = 332 MHz async # - HCLK = 166 MHz # - PCLK = 83 MHz proc sp3xx_clock_default {} { mww 0xfca00000 0x00000002 ;# set sysclk slow mww 0xfca00014 0x0ffffff8 ;# set pll timeout to minimum (100us ?!?) # DDRCORE disable to change frequency set val [expr {([mrw 0xfca8002c] & ~0x20000000) | 0x40000000}] mww 0xfca8002c $val mww 0xfca8002c $val ;# Yes, write twice! # programming PLL1 mww 0xfca8000c 0xa600010c ;# M=166 P=1 N=12 mww 0xfca80008 0x00001c0a ;# power down mww 0xfca80008 0x00001c0e ;# enable mww 0xfca80008 0x00001c06 ;# strobe mww 0xfca80008 0x00001c0e while { [expr {[mrw 0xfca80008] & 0x01}] == 0x00 } { sleep 1 } # programming PLL2 mww 0xfca80018 0xa600010c ;# M=166, P=1, N=12 mww 0xfca80014 0x00001c0a ;# power down mww 0xfca80014 0x00001c0e ;# enable mww 0xfca80014 0x00001c06 ;# strobe mww 0xfca80014 0x00001c0e while { [expr {[mrw 0xfca80014] & 0x01}] == 0x00 } { sleep 1 } mww 0xfca80028 0x00000082 ;# enable plltimeen mww 0xfca80024 0x00000511 ;# set hclkdiv="/2" & pclkdiv="/2" mww 0xfca00000 0x00000004 ;# setting SYSCTL to NORMAL mode while { [expr {[mrw 0xfca00000] & 0x20}] != 0x20 } { sleep 1 } # Select source of DDR clock #mmw 0xfca80020 0x10000000 0x70000000 ;# PLL1 mmw 0xfca80020 0x30000000 0x70000000 ;# PLL2 # DDRCORE enable after change frequency mmw 0xfca8002c 0x20000000 0x00000000 } proc sp3xx_common_init {} { mww 0xfca8002c 0xfffffff8 ;# enable clock of all peripherals mww 0xfca80038 0x00000000 ;# remove reset of all peripherals mww 0xfca80034 0x0000ffff ;# enable all RAS clocks mww 0xfca80040 0x00000000 ;# remove all RAS resets mww 0xfca800e4 0x78000008 ;# COMP1V8_REG mww 0xfca800ec 0x78000008 ;# COMP3V3_REG mww 0xfc000000 0x10000f5f ;# init SMI and set HW mode mww 0xfc000000 0x00000f5f # Initialize Bus Interconnection Matrix # All ports Round-Robin and lowest priority mww 0xfca8007c 0x80000007 mww 0xfca80080 0x80000007 mww 0xfca80084 0x80000007 mww 0xfca80088 0x80000007 mww 0xfca8008c 0x80000007 mww 0xfca80090 0x80000007 mww 0xfca80094 0x80000007 mww 0xfca80098 0x80000007 mww 0xfca8009c 0x80000007 } # Specific init scripts for ST SPEAr300 proc sp300_init {} { mww 0x99000000 0x00003fff ;# RAS function enable } # Specific init scripts for ST SPEAr310 proc sp310_init {} { mww 0xb4000008 0x00002ff4 ;# RAS function enable mww 0xfca80050 0x00000001 ;# Enable clk mem port 1 mww 0xfca8013c 0x2f7bc210 ;# plgpio_pad_drv mww 0xfca80140 0x017bdef6 } proc sp310_emi_init {} { # set EMI pad strength mmw 0xfca80134 0x0e000000 0x00000000 mmw 0xfca80138 0x0e739ce7 0x00000000 mmw 0xfca8013c 0x00039ce7 0x00000000 # set safe EMI timing as in BootROM #mww 0x4f000000 0x0000000f ;# tAP_0_reg #mww 0x4f000004 0x00000000 ;# tSDP_0_reg #mww 0x4f000008 0x000000ff ;# tDPw_0_reg #mww 0x4f00000c 0x00000111 ;# tDPr_0_reg #mww 0x4f000010 0x00000002 ;# tDCS_0_reg # set fast EMI timing as in Linux mww 0x4f000000 0x00000010 ;# tAP_0_reg mww 0x4f000004 0x00000005 ;# tSDP_0_reg mww 0x4f000008 0x0000000a ;# tDPw_0_reg mww 0x4f00000c 0x0000000a ;# tDPr_0_reg mww 0x4f000010 0x00000005 ;# tDCS_0_re # 32bit wide, 8/16/32bit access mww 0x4f000014 0x0000000e ;# control_0_reg mww 0x4f000094 0x0000003f ;# ack_reg } # Specific init scripts for ST SPEAr320 proc sp320_init {} { mww 0xb300000c 0xffffac04 ;# RAS function enable mww 0xb3000010 0x00000001 ;# RAS mode select } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/st/spear/spear3xx_ddr.tcl ================================================ # Init scripts to configure DDR controller of SPEAr3xx # http://www.st.com/spear # Original values taken from XLoader source code # # Date: 2010-09-23 # Author: Antonio Borneo proc sp3xx_ddr_init {ddr_type {ddr_chips 1}} { if { $ddr_chips != 1 && $ddr_chips != 2 } { error "Only 1 or 2 DDR chips permitted. Wrong value "$ddr_chips } if { $ddr_type == "mt47h64m16_3_333_cl5_async" } { ddr_spr3xx_mt47h64m16_3_333_cl5_async $ddr_chips set ddr_size 0x08000000 ## add here new DDR chip definition. Prototype: #} elseif { $ddr_type == "?????" } { # ????? $ddr_chips # set ddr_size 0x????? } else { error "sp3xx_ddr_init: unrecognized DDR type "$ddr_type } # MPMC START mww 0xfc60001c 0x01000100 if { $ddr_chips == 2 } { echo [format \ "Double chip DDR memory. Total memory size 0x%08x byte" \ [expr {2 * $ddr_size}]] } else { echo [format \ "Single chip DDR memory. Memory size 0x%08x byte" \ $ddr_size] } } # from Xloader file ddr/spr300_mt47h64m16_3_333_cl5_async.S proc ddr_spr3xx_mt47h64m16_3_333_cl5_async {ddr_chips} { # DDR_PAD_REG mww 0xfca800f0 0x00003aa5 # Use "1:2 sync" only when DDR clock source is PLL1 and # HCLK is half of PLL1 mww 0xfc600000 0x00000001 ;# MEMCTL_AHB_SET_00 # This is async mww 0xfc600004 0x00000000 ;# MEMCTL_AHB_SET_01 # mww 0xfc600000 0x02020201 ;# MEMCTL_AHB_SET_00 # This is 1:2 sync # mww 0xfc600004 0x02020202 ;# MEMCTL_AHB_SET_01 mww 0xfc600008 0x01000000 ;# MEMCTL_RFSH_SET_00 mww 0xfc60000c 0x00000101 ;# MEMCTL_DLL_SET_00 mww 0xfc600010 0x00000101 ;# MEMCTL_GP_00 mww 0xfc600014 0x01000000 ;# MEMCTL_GP_01 mww 0xfc600018 0x00010001 ;# MEMCTL_GP_02 mww 0xfc60001c 0x00000100 ;# MEMCTL_GP_03 mww 0xfc600020 0x00010001 ;# MEMCTL_GP_04 if { $ddr_chips == 2 } { mww 0xfc600024 0x01020203 ;# MEMCTL_GP_05 mww 0xfc600028 0x01000102 ;# MEMCTL_GP_06 mww 0xfc60002c 0x02000202 ;# MEMCTL_AHB_SET_02 } else { mww 0xfc600024 0x00000201 ;# MEMCTL_GP_05 mww 0xfc600028 0x02000001 ;# MEMCTL_GP_06 mww 0xfc60002c 0x02000201 ;# MEMCTL_AHB_SET_02 } mww 0xfc600030 0x04040105 ;# MEMCTL_AHB_SET_03 mww 0xfc600034 0x03030302 ;# MEMCTL_AHB_SET_04 mww 0xfc600038 0x02040101 ;# MEMCTL_AHB_SET_05 mww 0xfc60003c 0x00000002 ;# MEMCTL_AHB_SET_06 mww 0xfc600044 0x03000405 ;# MEMCTL_DQS_SET_0 mww 0xfc600048 0x03040002 ;# MEMCTL_TIME_SET_01 mww 0xfc60004c 0x04000305 ;# MEMCTL_TIME_SET_02 mww 0xfc600050 0x0505053f ;# MEMCTL_AHB_RELPR_00 mww 0xfc600054 0x05050505 ;# MEMCTL_AHB_RELPR_01 mww 0xfc600058 0x04040405 ;# MEMCTL_AHB_RELPR_02 mww 0xfc60005c 0x04040404 ;# MEMCTL_AHB_RELPR_03 mww 0xfc600060 0x03030304 ;# MEMCTL_AHB_RELPR_04 mww 0xfc600064 0x03030303 ;# MEMCTL_AHB_RELPR_05 mww 0xfc600068 0x02020203 ;# MEMCTL_AHB_RELPR_06 mww 0xfc60006c 0x02020202 ;# MEMCTL_AHB_RELPR_07 mww 0xfc600070 0x01010102 ;# MEMCTL_AHB_RELPR_08 mww 0xfc600074 0x01010101 ;# MEMCTL_AHB_RELPR_09 mww 0xfc600078 0x00000001 ;# MEMCTL_AHB_RELPR_10 mww 0xfc600088 0x0a0c0a00 ;# MEMCTL_DQS_SET_1 mww 0xfc60008c 0x0000023f ;# MEMCTL_GP_07 mww 0xfc600090 0x00050a00 ;# MEMCTL_GP_08 mww 0xfc600094 0x11000000 ;# MEMCTL_GP_09 mww 0xfc600098 0x00001302 ;# MEMCTL_GP_10 mww 0xfc60009c 0x00001c1c ;# MEMCTL_DLL_SET_01 mww 0xfc6000a0 0x7c000000 ;# MEMCTL_DQS_OUT_SHIFT mww 0xfc6000a4 0x005c0000 ;# MEMCTL_WR_DQS_SHIFT mww 0xfc6000a8 0x2b050e00 ;# MEMCTL_TIME_SET_03 mww 0xfc6000ac 0x00640064 ;# MEMCTL_AHB_PRRLX_00 mww 0xfc6000b0 0x00640064 ;# MEMCTL_AHB_PRRLX_01 mww 0xfc6000b4 0x00000064 ;# MEMCTL_AHB_PRRLX_02 mww 0xfc6000b8 0x00000000 ;# MEMCTL_OUTRANGE_LGTH mww 0xfc6000bc 0x00200020 ;# MEMCTL_AHB_RW_SET_00 mww 0xfc6000c0 0x00200020 ;# MEMCTL_AHB_RW_SET_01 mww 0xfc6000c4 0x00200020 ;# MEMCTL_AHB_RW_SET_02 mww 0xfc6000c8 0x00200020 ;# MEMCTL_AHB_RW_SET_03 mww 0xfc6000cc 0x00200020 ;# MEMCTL_AHB_RW_SET_04 mww 0xfc6000d8 0x00000a24 ;# MEMCTL_TREF mww 0xfc6000dc 0x00000000 ;# MEMCTL_EMRS3_DATA mww 0xfc6000e0 0x5b1c00c8 ;# MEMCTL_TIME_SET_04 mww 0xfc6000e4 0x00c8002e ;# MEMCTL_TIME_SET_05 mww 0xfc6000e8 0x00000000 ;# MEMCTL_VERSION mww 0xfc6000ec 0x0001046b ;# MEMCTL_TINIT mww 0xfc6000f0 0x00000000 ;# MEMCTL_OUTRANGE_ADDR_01 mww 0xfc6000f4 0x00000000 ;# MEMCTL_OUTRANGE_ADDR_02 mww 0xfc600104 0x001c0000 ;# MEMCTL_DLL_DQS_DELAY_BYPASS_0 mww 0xfc600108 0x0019001c ;# MEMCTL_DLL_SET_02 mww 0xfc60010c 0x00100000 ;# MEMCTL_DLL_SET_03 mww 0xfc600110 0x001e007a ;# MEMCTL_DQS_SET_2 mww 0xfc600188 0x00000000 ;# MEMCTL_USER_DEF_REG_0 mww 0xfc60018c 0x00000000 ;# MEMCTL_USER_DEF_REG_1 mww 0xfc600190 0x01010001 ;# MEMCTL_GP_11 mww 0xfc600194 0x01000000 ;# MEMCTL_GP_12 mww 0xfc600198 0x00000001 ;# MEMCTL_GP_13 mww 0xfc60019c 0x00400000 ;# MEMCTL_GP_14 mww 0xfc6001a0 0x00000000 ;# MEMCTL_EMRS2_DATA_X mww 0xfc6001a4 0x00000000 ;# MEMCTL_LWPWR_CNT mww 0xfc6001a8 0x00000000 ;# MEMCTL_LWPWR_REG mww 0xfc6001ac 0x00860000 ;# MEMCTL_GP_15 mww 0xfc6001b0 0x00000002 ;# MEMCTL_TPDEX } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/st/stm32/stm32.tcl ================================================ source [find bitsbytes.tcl] source [find cpu/arm/cortex_m3.tcl] source [find memory.tcl] source [find mmr_helpers.tcl] source [find chip/st/stm32/stm32_regs.tcl] source [find chip/st/stm32/stm32_rcc.tcl] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/st/stm32/stm32_rcc.tcl ================================================ set RCC_CR [expr {$RCC_BASE + 0x00}] set RCC_CFGR [expr {$RCC_BASE + 0x04}] set RCC_CIR [expr {$RCC_BASE + 0x08}] set RCC_APB2RSTR [expr {$RCC_BASE + 0x0c}] set RCC_APB1RSTR [expr {$RCC_BASE + 0x10}] set RCC_AHBENR [expr {$RCC_BASE + 0x14}] set RCC_APB2ENR [expr {$RCC_BASE + 0x18}] set RCC_APB1ENR [expr {$RCC_BASE + 0x1c}] set RCC_BDCR [expr {$RCC_BASE + 0x20}] set RCC_CSR [expr {$RCC_BASE + 0x24}] proc show_RCC_CR { } { if [ catch { set val [show_mmr32_reg RCC_CR] } msg ] { error $msg } show_mmr_bitfield 0 0 $val HSI { OFF ON } show_mmr_bitfield 1 1 $val HSIRDY { NOTRDY RDY } show_mmr_bitfield 7 3 $val HSITRIM { _NUMBER_ } show_mmr_bitfield 15 8 $val HSICAL { _NUMBER_ } show_mmr_bitfield 16 16 $val HSEON { OFF ON } show_mmr_bitfield 17 17 $val HSERDY { NOTRDY RDY } show_mmr_bitfield 18 18 $val HSEBYP { NOTBYPASSED BYPASSED } show_mmr_bitfield 19 19 $val CSSON { OFF ON } show_mmr_bitfield 24 24 $val PLLON { OFF ON } show_mmr_bitfield 25 25 $val PLLRDY { NOTRDY RDY } } proc show_RCC_CFGR { } { if [ catch { set val [show_mmr32_reg RCC_CFGR] } msg ] { error $msg } show_mmr_bitfield 1 0 $val SW { HSI HSE PLL ILLEGAL } show_mmr_bitfield 3 2 $val SWS { HSI HSE PLL ILLEGAL } show_mmr_bitfield 7 4 $val HPRE { sysclk_div_1 sysclk_div_1 sysclk_div_1 sysclk_div_1 sysclk_div_1 sysclk_div_1 sysclk_div_1 sysclk_div_1 sysclk_div_2 sysclk_div_4 sysclk_div_8 sysclk_div_16 sysclk_div_64 sysclk_div_128 sysclk_div_256 sysclk_div_512 } show_mmr_bitfield 10 8 $val PPRE1 { hclk_div1 hclk_div1 hclk_div1 hclk_div1 hclk_div2 hclk_div4 hclk_div8 hclk_div16 } show_mmr_bitfield 13 11 $val PPRE2 { hclk_div1 hclk_div1 hclk_div1 hclk_div1 hclk_div2 hclk_div4 hclk_div8 hclk_div16 } show_mmr_bitfield 15 14 $val ADCPRE { pclk2_div1 pclk2_div1 pclk2_div1 pclk2_div1 pclk2_div2 pclk2_div4 pclk2_div8 pclk2_div16 } show_mmr_bitfield 16 16 $val PLLSRC { HSI_div_2 HSE } show_mmr_bitfield 17 17 $val PLLXTPRE { hse_div1 hse_div2 } show_mmr_bitfield 21 18 $val PLLMUL { x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 x16 } show_mmr_bitfield 22 22 $val USBPRE { div1 div1_5 } show_mmr_bitfield 26 24 $val MCO { none none none none SysClk HSI HSE PLL_div2 } } proc show_RCC_CIR { } { if [ catch { set val [show_mmr32_reg RCC_CIR] } msg ] { error $msg } } proc show_RCC_APB2RSTR { } { if [ catch { set val [ show_mmr32_reg RCC_APB2RSTR] } msg ] { error $msg } for { set x 0 } { $x < 32 } { incr x } { set bits($x) xxx } set bits(15) adc3 set bits(14) usart1 set bits(13) tim8 set bits(12) spi1 set bits(11) tim1 set bits(10) adc2 set bits(9) adc1 set bits(8) iopg set bits(7) iopf set bits(6) iope set bits(5) iopd set bits(4) iopc set bits(3) iopb set bits(2) iopa set bits(1) xxx set bits(0) afio show_mmr32_bits bits $val } proc show_RCC_APB1RSTR { } { if [ catch { set val [ show_mmr32_reg RCC_APB1RSTR] } msg ] { error $msg } set bits(31) xxx set bits(30) xxx set bits(29) dac set bits(28) pwr set bits(27) bkp set bits(26) xxx set bits(25) can set bits(24) xxx set bits(23) usb set bits(22) i2c2 set bits(21) i2c1 set bits(20) uart5 set bits(19) uart4 set bits(18) uart3 set bits(17) uart2 set bits(16) xxx set bits(15) spi3 set bits(14) spi2 set bits(13) xxx set bits(12) xxx set bits(11) wwdg set bits(10) xxx set bits(9) xxx set bits(8) xxx set bits(7) xxx set bits(6) xxx set bits(5) tim7 set bits(4) tim6 set bits(3) tim5 set bits(2) tim4 set bits(1) tim3 set bits(0) tim2 show_mmr32_bits bits $val } proc show_RCC_AHBENR { } { if [ catch { set val [ show_mmr32_reg RCC_AHBENR ] } msg ] { error $msg } set bits(31) xxx set bits(30) xxx set bits(29) xxx set bits(28) xxx set bits(27) xxx set bits(26) xxx set bits(25) xxx set bits(24) xxx set bits(23) xxx set bits(22) xxx set bits(21) xxx set bits(20) xxx set bits(19) xxx set bits(18) xxx set bits(17) xxx set bits(16) xxx set bits(15) xxx set bits(14) xxx set bits(13) xxx set bits(12) xxx set bits(11) xxx set bits(10) sdio set bits(9) xxx set bits(8) fsmc set bits(7) xxx set bits(6) crce set bits(5) xxx set bits(4) flitf set bits(3) xxx set bits(2) sram set bits(1) dma2 set bits(0) dma1 show_mmr32_bits bits $val } proc show_RCC_APB2ENR { } { if [ catch { set val [ show_mmr32_reg RCC_APB2ENR ] } msg ] { error $msg } set bits(31) xxx set bits(30) xxx set bits(29) xxx set bits(28) xxx set bits(27) xxx set bits(26) xxx set bits(25) xxx set bits(24) xxx set bits(23) xxx set bits(22) xxx set bits(21) xxx set bits(20) xxx set bits(19) xxx set bits(18) xxx set bits(17) xxx set bits(16) xxx set bits(15) adc3 set bits(14) usart1 set bits(13) tim8 set bits(12) spi1 set bits(11) tim1 set bits(10) adc2 set bits(9) adc1 set bits(8) iopg set bits(7) iopf set bits(6) iope set bits(5) iopd set bits(4) iopc set bits(3) iopb set bits(2) iopa set bits(1) xxx set bits(0) afio show_mmr32_bits bits $val } proc show_RCC_APB1ENR { } { if [ catch { set val [ show_mmr32_reg RCC_APB1ENR ] } msg ] { error $msg } set bits(31) xxx set bits(30) xxx set bits(29) dac set bits(28) pwr set bits(27) bkp set bits(26) xxx set bits(25) can set bits(24) xxx set bits(23) usb set bits(22) i2c2 set bits(21) i2c1 set bits(20) usart5 set bits(19) usart4 set bits(18) usart3 set bits(17) usart2 set bits(16) xxx set bits(15) spi3 set bits(14) spi2 set bits(13) xxx set bits(12) xxx set bits(11) wwdg set bits(10) xxx set bits(9) xxx set bits(8) xxx set bits(7) xxx set bits(6) xxx set bits(5) tim7 set bits(4) tim6 set bits(3) tim5 set bits(2) tim4 set bits(1) tim3 set bits(0) tim2 show_mmr32_bits bits $val } proc show_RCC_BDCR { } { if [ catch { set val [ show_mmr32_reg RCC_BDCR ] } msg ] { error $msg } for { set x 0 } { $x < 32 } { incr x } { set bits($x) xxx } set bits(0) lseon set bits(1) lserdy set bits(2) lsebyp set bits(8) rtcsel0 set bits(9) rtcsel1 set bits(15) rtcen set bits(16) bdrst show_mmr32_bits bits $val } proc show_RCC_CSR { } { if [ catch { set val [ show_mmr32_reg RCC_CSR ] } msg ] { error $msg } for { set x 0 } { $x < 32 } { incr x } { set bits($x) xxx } set bits(0) lsion set bits(1) lsirdy set bits(24) rmvf set bits(26) pin set bits(27) por set bits(28) sft set bits(29) iwdg set bits(30) wwdg set bits(31) lpwr show_mmr32_bits bits $val } proc show_RCC { } { show_RCC_CR show_RCC_CFGR show_RCC_CIR show_RCC_APB2RSTR show_RCC_APB1RSTR show_RCC_AHBENR show_RCC_APB2ENR show_RCC_APB1ENR show_RCC_BDCR show_RCC_CSR } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/st/stm32/stm32_regs.tcl ================================================ # /* Peripheral and SRAM base address in the alias region */ set PERIPH_BB_BASE 0x42000000 set SRAM_BB_BASE 0x22000000 # /*Peripheral and SRAM base address in the bit-band region */ set SRAM_BASE 0x20000000 set PERIPH_BASE 0x40000000 # /*FSMC registers base address */ set FSMC_R_BASE 0xA0000000 # /*Peripheral memory map */ set APB1PERIPH_BASE [set PERIPH_BASE] set APB2PERIPH_BASE [expr {$PERIPH_BASE + 0x10000}] set AHBPERIPH_BASE [expr {$PERIPH_BASE + 0x20000}] set TIM2_BASE [expr {$APB1PERIPH_BASE + 0x0000}] set TIM3_BASE [expr {$APB1PERIPH_BASE + 0x0400}] set TIM4_BASE [expr {$APB1PERIPH_BASE + 0x0800}] set TIM5_BASE [expr {$APB1PERIPH_BASE + 0x0C00}] set TIM6_BASE [expr {$APB1PERIPH_BASE + 0x1000}] set TIM7_BASE [expr {$APB1PERIPH_BASE + 0x1400}] set RTC_BASE [expr {$APB1PERIPH_BASE + 0x2800}] set WWDG_BASE [expr {$APB1PERIPH_BASE + 0x2C00}] set IWDG_BASE [expr {$APB1PERIPH_BASE + 0x3000}] set SPI2_BASE [expr {$APB1PERIPH_BASE + 0x3800}] set SPI3_BASE [expr {$APB1PERIPH_BASE + 0x3C00}] set USART2_BASE [expr {$APB1PERIPH_BASE + 0x4400}] set USART3_BASE [expr {$APB1PERIPH_BASE + 0x4800}] set UART4_BASE [expr {$APB1PERIPH_BASE + 0x4C00}] set UART5_BASE [expr {$APB1PERIPH_BASE + 0x5000}] set I2C1_BASE [expr {$APB1PERIPH_BASE + 0x5400}] set I2C2_BASE [expr {$APB1PERIPH_BASE + 0x5800}] set CAN_BASE [expr {$APB1PERIPH_BASE + 0x6400}] set BKP_BASE [expr {$APB1PERIPH_BASE + 0x6C00}] set PWR_BASE [expr {$APB1PERIPH_BASE + 0x7000}] set DAC_BASE [expr {$APB1PERIPH_BASE + 0x7400}] set AFIO_BASE [expr {$APB2PERIPH_BASE + 0x0000}] set EXTI_BASE [expr {$APB2PERIPH_BASE + 0x0400}] set GPIOA_BASE [expr {$APB2PERIPH_BASE + 0x0800}] set GPIOB_BASE [expr {$APB2PERIPH_BASE + 0x0C00}] set GPIOC_BASE [expr {$APB2PERIPH_BASE + 0x1000}] set GPIOD_BASE [expr {$APB2PERIPH_BASE + 0x1400}] set GPIOE_BASE [expr {$APB2PERIPH_BASE + 0x1800}] set GPIOF_BASE [expr {$APB2PERIPH_BASE + 0x1C00}] set GPIOG_BASE [expr {$APB2PERIPH_BASE + 0x2000}] set ADC1_BASE [expr {$APB2PERIPH_BASE + 0x2400}] set ADC2_BASE [expr {$APB2PERIPH_BASE + 0x2800}] set TIM1_BASE [expr {$APB2PERIPH_BASE + 0x2C00}] set SPI1_BASE [expr {$APB2PERIPH_BASE + 0x3000}] set TIM8_BASE [expr {$APB2PERIPH_BASE + 0x3400}] set USART1_BASE [expr {$APB2PERIPH_BASE + 0x3800}] set ADC3_BASE [expr {$APB2PERIPH_BASE + 0x3C00}] set SDIO_BASE [expr {$PERIPH_BASE + 0x18000}] set DMA1_BASE [expr {$AHBPERIPH_BASE + 0x0000}] set DMA1_Channel1_BASE [expr {$AHBPERIPH_BASE + 0x0008}] set DMA1_Channel2_BASE [expr {$AHBPERIPH_BASE + 0x001C}] set DMA1_Channel3_BASE [expr {$AHBPERIPH_BASE + 0x0030}] set DMA1_Channel4_BASE [expr {$AHBPERIPH_BASE + 0x0044}] set DMA1_Channel5_BASE [expr {$AHBPERIPH_BASE + 0x0058}] set DMA1_Channel6_BASE [expr {$AHBPERIPH_BASE + 0x006C}] set DMA1_Channel7_BASE [expr {$AHBPERIPH_BASE + 0x0080}] set DMA2_BASE [expr {$AHBPERIPH_BASE + 0x0400}] set DMA2_Channel1_BASE [expr {$AHBPERIPH_BASE + 0x0408}] set DMA2_Channel2_BASE [expr {$AHBPERIPH_BASE + 0x041C}] set DMA2_Channel3_BASE [expr {$AHBPERIPH_BASE + 0x0430}] set DMA2_Channel4_BASE [expr {$AHBPERIPH_BASE + 0x0444}] set DMA2_Channel5_BASE [expr {$AHBPERIPH_BASE + 0x0458}] set RCC_BASE [expr {$AHBPERIPH_BASE + 0x1000}] set CRC_BASE [expr {$AHBPERIPH_BASE + 0x3000}] # /*Flash registers base address */ set FLASH_R_BASE [expr {$AHBPERIPH_BASE + 0x2000}] # /*Flash Option Bytes base address */ set OB_BASE 0x1FFFF800 # /*FSMC Bankx registers base address */ set FSMC_Bank1_R_BASE [expr {$FSMC_R_BASE + 0x0000}] set FSMC_Bank1E_R_BASE [expr {$FSMC_R_BASE + 0x0104}] set FSMC_Bank2_R_BASE [expr {$FSMC_R_BASE + 0x0060}] set FSMC_Bank3_R_BASE [expr {$FSMC_R_BASE + 0x0080}] set FSMC_Bank4_R_BASE [expr {$FSMC_R_BASE + 0x00A0}] # /*Debug MCU registers base address */ set DBGMCU_BASE 0xE0042000 # /*System Control Space memory map */ set SCS_BASE 0xE000E000 set SysTick_BASE [expr {$SCS_BASE + 0x0010}] set NVIC_BASE [expr {$SCS_BASE + 0x0100}] set SCB_BASE [expr {$SCS_BASE + 0x0D00}] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/ti/lm3s/lm3s.tcl ================================================ source [find chip/ti/lm3s/lm3s_regs.tcl] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/chip/ti/lm3s/lm3s_regs.tcl ================================================ #***************************************************************************** # # The following are defines for the System Control register addresses. # #***************************************************************************** set SYSCTL_DID0 0x400FE000 ;# Device Identification 0 set SYSCTL_DID1 0x400FE004 ;# Device Identification 1 set SYSCTL_DC0 0x400FE008 ;# Device Capabilities 0 set SYSCTL_DC1 0x400FE010 ;# Device Capabilities 1 set SYSCTL_DC2 0x400FE014 ;# Device Capabilities 2 set SYSCTL_DC3 0x400FE018 ;# Device Capabilities 3 set SYSCTL_DC4 0x400FE01C ;# Device Capabilities 4 set SYSCTL_DC5 0x400FE020 ;# Device Capabilities 5 set SYSCTL_DC6 0x400FE024 ;# Device Capabilities 6 set SYSCTL_DC7 0x400FE028 ;# Device Capabilities 7 set SYSCTL_DC8 0x400FE02C ;# Device Capabilities 8 ADC ;# Channels set SYSCTL_PBORCTL 0x400FE030 ;# Brown-Out Reset Control set SYSCTL_LDOPCTL 0x400FE034 ;# LDO Power Control set SYSCTL_SRCR0 0x400FE040 ;# Software Reset Control 0 set SYSCTL_SRCR1 0x400FE044 ;# Software Reset Control 1 set SYSCTL_SRCR2 0x400FE048 ;# Software Reset Control 2 set SYSCTL_RIS 0x400FE050 ;# Raw Interrupt Status set SYSCTL_IMC 0x400FE054 ;# Interrupt Mask Control set SYSCTL_MISC 0x400FE058 ;# Masked Interrupt Status and ;# Clear set SYSCTL_RESC 0x400FE05C ;# Reset Cause set SYSCTL_RCC 0x400FE060 ;# Run-Mode Clock Configuration set SYSCTL_PLLCFG 0x400FE064 ;# XTAL to PLL Translation set SYSCTL_GPIOHSCTL 0x400FE06C ;# GPIO High-Speed Control set SYSCTL_GPIOHBCTL 0x400FE06C ;# GPIO High-Performance Bus ;# Control set SYSCTL_RCC2 0x400FE070 ;# Run-Mode Clock Configuration 2 set SYSCTL_MOSCCTL 0x400FE07C ;# Main Oscillator Control set SYSCTL_RCGC0 0x400FE100 ;# Run Mode Clock Gating Control ;# Register 0 set SYSCTL_RCGC1 0x400FE104 ;# Run Mode Clock Gating Control ;# Register 1 set SYSCTL_RCGC2 0x400FE108 ;# Run Mode Clock Gating Control ;# Register 2 set SYSCTL_SCGC0 0x400FE110 ;# Sleep Mode Clock Gating Control ;# Register 0 set SYSCTL_SCGC1 0x400FE114 ;# Sleep Mode Clock Gating Control ;# Register 1 set SYSCTL_SCGC2 0x400FE118 ;# Sleep Mode Clock Gating Control ;# Register 2 set SYSCTL_DCGC0 0x400FE120 ;# Deep Sleep Mode Clock Gating ;# Control Register 0 set SYSCTL_DCGC1 0x400FE124 ;# Deep-Sleep Mode Clock Gating ;# Control Register 1 set SYSCTL_DCGC2 0x400FE128 ;# Deep Sleep Mode Clock Gating ;# Control Register 2 set SYSCTL_DSLPCLKCFG 0x400FE144 ;# Deep Sleep Clock Configuration set SYSCTL_CLKVCLR 0x400FE150 ;# Clock Verification Clear set SYSCTL_PIOSCCAL 0x400FE150 ;# Precision Internal Oscillator ;# Calibration set SYSCTL_PIOSCSTAT 0x400FE154 ;# Precision Internal Oscillator ;# Statistics set SYSCTL_LDOARST 0x400FE160 ;# Allow Unregulated LDO to Reset ;# the Part set SYSCTL_I2SMCLKCFG 0x400FE170 ;# I2S MCLK Configuration set SYSCTL_DC9 0x400FE190 ;# Device Capabilities 9 ADC ;# Digital Comparators set SYSCTL_NVMSTAT 0x400FE1A0 ;# Non-Volatile Memory Information set SYSCTL_RCC_USESYSDIV 0x00400000 ;# Enable System Clock Divider set SYSCTL_RCC2_BYPASS2 0x00000800 ;# PLL Bypass 2 set SYSCTL_RCC_MOSCDIS 0x00000001 ;# Main Oscillator Disable set SYSCTL_SRCR0 0x400FE040 ;# Software Reset Control 0 set SYSCTL_SRCR1 0x400FE044 ;# Software Reset Control 1 set SYSCTL_SRCR2 0x400FE048 ;# Software Reset Control 2 set SYSCTL_MISC 0x400FE058 ;# Masked Interrupt Status and Clear set FLASH_FMA 0x400FD000 ;# Flash Memory Address set FLASH_FMD 0x400FD004 ;# Flash Memory Data set FLASH_FMC 0x400FD008 ;# Flash Memory Control set FLASH_FCRIS 0x400FD00C ;# Flash Controller Raw Interrupt Status set FLASH_FCIM 0x400FD010 ;# Flash Controller Interrupt Mask set FLASH_FCMISC 0x400FD014 ;# Flash Controller Masked Interrupt Status and Clear set FLASH_FMC2 0x400FD020 ;# Flash Memory Control 2 set FLASH_FWBVAL 0x400FD030 ;# Flash Write Buffer Valid ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpld/altera-5m570z-cpld.cfg ================================================ # Altera MAXV 5M24OZ/5M570Z CPLD # see MAX V Device Handbook # Table 6-3: 32-Bit MAX V Device IDCODE # Version Part Number Manuf. ID LSB # 0000 0010 0000 1010 0111 000 0110 1110 1 jtag newtap 5m570z tap -expected-id 0x020a60dd -irlen 10 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpld/altera-epm240.cfg ================================================ # Altera MAXII EPM240T100C CPLD if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME epm240 } # see MAX II Device Handbook # Table 3-3: 32-Bit MAX II Device IDCODE # Version Part Number Manuf. ID LSB # 0000 0010 0000 1010 0001 000 0110 1110 1 jtag newtap $_CHIPNAME tap -irlen 10 \ -expected-id 0x020a10dd \ -expected-id 0x020a20dd \ -expected-id 0x020a30dd \ -expected-id 0x020a40dd \ -expected-id 0x020a50dd \ -expected-id 0x020a60dd # 200ns seems like a good speed # c.f. Table 5-34: MAX II JTAG Timing Parameters adapter speed 5000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpld/jtagspi.cfg ================================================ set _USER1 0x02 if { [info exists JTAGSPI_IR] } { set _JTAGSPI_IR $JTAGSPI_IR } else { set _JTAGSPI_IR $_USER1 } if { [info exists TARGETNAME] } { set _TARGETNAME $TARGETNAME } else { set _TARGETNAME $_CHIPNAME.proxy } if { [info exists FLASHNAME] } { set _FLASHNAME $FLASHNAME } else { set _FLASHNAME $_CHIPNAME.spi } target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME $_JTAGSPI_IR proc jtagspi_init {chain_id proxy_bit} { # load proxy bitstream $proxy_bit and probe spi flash global _FLASHNAME pld load $chain_id $proxy_bit reset halt flash probe $_FLASHNAME } proc jtagspi_program {bin addr} { # write and verify binary file $bin at offset $addr global _FLASHNAME flash write_image erase $bin $addr flash verify_bank $_FLASHNAME $bin $addr } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpld/lattice-lc4032ze.cfg ================================================ # Lattice ispMACH 4000ZE family, device LC4032ZE # just configure a tap jtag newtap LC4032ZE tap -irlen 8 -expected-id 0x01806043 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpld/xilinx-xc6s.cfg ================================================ # xilinx spartan6 # http://www.xilinx.com/support/documentation/user_guides/ug380.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xc6s } # the 4 top bits (28:31) are the die stepping. ignore it. jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ -expected-id 0x04000093 \ -expected-id 0x04001093 \ -expected-id 0x04002093 \ -expected-id 0x04004093 \ -expected-id 0x04024093 \ -expected-id 0x04008093 \ -expected-id 0x04028093 \ -expected-id 0x0400E093 \ -expected-id 0x0402E093 \ -expected-id 0x04011093 \ -expected-id 0x04031093 \ -expected-id 0x0401D093 \ -expected-id 0x0403D093 pld device virtex2 $_CHIPNAME.tap set XC6S_CFG_IN 0x05 set XC6S_JSHUTDOWN 0x0d set XC6S_JPROGRAM 0x0b set XC6S_JSTART 0x0c set XC6S_BYPASS 0x3f proc xc6s_program {tap} { global XC6S_JSHUTDOWN XC6S_JPROGRAM XC6S_JSTART XC6S_BYPASS irscan $tap $XC6S_JSHUTDOWN irscan $tap $XC6S_JPROGRAM irscan $tap $XC6S_JSTART irscan $tap $XC6S_BYPASS } #xtp038 and xc3sprog approach proc xc6s_program_iprog {tap} { global XC6S_JSHUTDOWN XC6S_JSTART XC6S_BYPASS XC6S_CFG_IN irscan $tap $XC6S_JSHUTDOWN runtest 16 irscan $tap $XC6S_CFG_IN # xtp038 IPROG 16bit flipped drscan $tap 16 0xffff 16 0x9955 16 0x66aa 16 0x850c 16 0x7000 16 0x0004 irscan $tap $XC6S_JSTART runtest 32 irscan $tap $XC6S_BYPASS runtest 1 } set XC6S_ISC_ENABLE 0x10 set XC6S_ISC_DISABLE 0x16 set XC6S_ISC_DNA 0x30 # Get the "Device DNA" from the Spartan 6. # Most Xilinx FPGA devices contain an embedded, unique device identifier called # the "Device DNA". The identifier is nonvolatile, permanently programmed into # the FPGA, and is unchangeable providing a great serial / tracking number. proc xc6s_get_dna {tap} { global XC6S_ISC_ENABLE XC6S_ISC_DISABLE XC6S_ISC_DNA irscan $tap $XC6S_ISC_ENABLE runtest 64 irscan $tap $XC6S_ISC_DNA # Device DNA is 57 bits long, but we can only read 32bits at a time # with OpenOCD. set dna [drscan $tap 16 0 16 0 16 0 9 0] runtest 64 irscan $tap $XC6S_ISC_DISABLE runtest 64 # Convert the binary data into the order impact uses scan $dna "%x %x %x %x" v1 v2 v3 v4 set bin_dna [string reverse [concat [format "%09b" $v4][format "%016b" $v3][format "%016b" $v2][format "%016b" $v1]]] # Return a hex version of binary scan [format "0b%s" $bin_dna] "%i" hex_dna return $hex_dna } # Print out the "Device DNA" in the same format that impact uses. proc xc6s_print_dna {tap} { set hex_dna [xc6s_get_dna $tap] puts [format "DNA = %57b (0x%x)\n" $hex_dna $hex_dna] } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpld/xilinx-xc7.cfg ================================================ # xilinx series 7 (artix, kintex, virtex) # http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xc7 } # the 4 top bits (28:31) are the die stepping/revisions. ignore it. jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ -expected-id 0x03622093 \ -expected-id 0x03620093 \ -expected-id 0x037C4093 \ -expected-id 0x0362F093 \ -expected-id 0x037C8093 \ -expected-id 0x037C7093 \ -expected-id 0x037C3093 \ -expected-id 0x0362E093 \ -expected-id 0x037C2093 \ -expected-id 0x0362D093 \ -expected-id 0x0362C093 \ -expected-id 0x03632093 \ -expected-id 0x03631093 \ -expected-id 0x03636093 \ -expected-id 0x03647093 \ -expected-id 0x0364C093 \ -expected-id 0x03651093 \ -expected-id 0x03747093 \ -expected-id 0x03656093 \ -expected-id 0x03752093 \ -expected-id 0x03751093 \ -expected-id 0x03671093 \ -expected-id 0x036B3093 \ -expected-id 0x036B7093 \ -expected-id 0x036BB093 \ -expected-id 0x036BF093 \ -expected-id 0x03667093 \ -expected-id 0x03682093 \ -expected-id 0x03687093 \ -expected-id 0x03692093 \ -expected-id 0x03691093 \ -expected-id 0x03696093 \ -expected-id 0x036D5093 \ -expected-id 0x036D9093 \ -expected-id 0x036DB093 pld device virtex2 $_CHIPNAME.tap 1 set XC7_JSHUTDOWN 0x0d set XC7_JPROGRAM 0x0b set XC7_JSTART 0x0c set XC7_BYPASS 0x3f proc xc7_program {tap} { global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS irscan $tap $XC7_JSHUTDOWN irscan $tap $XC7_JPROGRAM runtest 60000 #JSTART prevents this from working... #irscan $tap $XC7_JSTART runtest 2000 irscan $tap $XC7_BYPASS runtest 2000 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpld/xilinx-xcf-p.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xcf } # IDs acquired from Xilinx's DS123.pdf # XCF08P 5057093 # XCF16P 5058093 # XCF32P 5059093 # The 4 top bits (28:31) are the device revision. Ignore it. jtag newtap $_CHIPNAME flash -irlen 16 -ignore-version \ -expected-id 0x05057093 \ -expected-id 0x05058093 \ -expected-id 0x05059093 target create xcf.flash testee -chain-position $_CHIPNAME.flash flash bank XCF_P xcf 0 0 0 0 xcf.flash ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpld/xilinx-xcf-s.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xcf } # IDs acquired from Xilinx's DS123.pdf # XCF01S 5044093 # XCF02S 5045093 # XCF04S 5046093 # The 4 top bits (28:31) are the device revision. Ignore it. jtag newtap $_CHIPNAME flash -irlen 8 -ignore-version \ -expected-id 0x05044093 \ -expected-id 0x05045093 \ -expected-id 0x05046093 target create xcf.flash testee -chain-position $_CHIPNAME.flash flash bank XCF_S xcf 0 0 0 0 xcf.flash ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpld/xilinx-xcr3256.cfg ================================================ #xilinx coolrunner xcr3256 #simple device - just configure a tap jtag newtap xcr tap -irlen 5 -ircapture 0x01 -irmask 0x1f -expected-id 0x0494c093 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpld/xilinx-xcu.cfg ================================================ # Xilinx Ultrascale (Kintex, Virtex, Zynq) # https://www.xilinx.com/support/documentation/user_guides/ug570-ultrascale-configuration.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xcu } # The cvarious chips in the Ultrascale family have different IR length. # Set $CHIP before including this file to determine the device. array set _XCU_DATA { XCKU025 {0x03824093 6} XCKU035 {0x03823093 6} XCKU040 {0x03822093 6} XCKU060 {0x03919093 6} XCKU095 {0x03844093 6} XCKU3P {0x04A63093 6} XCKU5P {0x04A62093 6} XCKU9P {0x0484A093 6} XCKU11P {0x04A4E093 6} XCKU13P {0x04A52093 6} XCKU15P {0x04A56093 6} XCVU065 {0x03939093 6} XCVU080 {0x03843093 6} XCVU095 {0x03842093 6} XCVU3P {0x04B39093 6} XCKU085 {0x0380F093 12} XCKU115 {0x0390D093 12} XCVU125 {0x0392D093 12} XCVU5P {0x04B2B093 12} XCVU7P {0x04B29093 12} XCVU160 {0x03933093 18} XCVU190 {0x03931093 18} XCVU440 {0x0396D093 18} XCVU9P {0x04B31093 18} XCVU11P {0x04B49093 18} XCVU13P {0x04B51093 24} } if { ![info exists CHIP] } { error "set CHIP to one of "[concat [array names _XCU_DATA]] } if { ![llength [array names _XCU_DATA $CHIP]] } { error "unknown CHIP: "$CHIP } set _EXPID [lindex $_XCU_DATA($CHIP) 0] set _IRLEN [lindex $_XCU_DATA($CHIP) 1] # the 4 top bits (28:31) are the die stepping/revisions. ignore it. jtag newtap $_CHIPNAME tap -irlen $_IRLEN -ignore-version -expected-id $_EXPID pld device virtex2 $_CHIPNAME.tap 1 set XCU_JSHUTDOWN 0x0d set XCU_JPROGRAM 0x0b set XCU_JSTART 0x0c set XCU_BYPASS 0x3f proc xcu_program {tap} { global XCU_JSHUTDOWN XCU_JPROGRAM XCU_JSTART XCU_BYPASS irscan $tap $XCU_JSHUTDOWN irscan $tap $XCU_JPROGRAM runtest 60000 #JSTART prevents this from working... #irscan $tap $XCU_JSTART runtest 2000 irscan $tap $XCU_BYPASS runtest 2000 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpu/arc/common.tcl ================================================ # Copyright (C) 2015, 2020 Synopsys, Inc. # Anton Kolesov # Didin Evgeniy # # SPDX-License-Identifier: GPL-2.0-or-later # Things common to all ARCs # It is assumed that target is already halted. proc arc_common_reset { {target ""} } { if { $target != "" } { targets $target } halt # 1. Interrupts are disabled (STATUS32.IE) # 2. The status register flags are cleared. # All fields, except the H bit, are set to 0 when the processor is Reset. arc jtag set-aux-reg 0xA 0x1 # 3. The loop count, loop start, and loop end registers are cleared. arc jtag set-core-reg 60 0 arc jtag set-aux-reg 0x2 0 arc jtag set-aux-reg 0x3 0 # Program execution begins at the address referenced by the four byte reset # vector located at the interrupt vector base address, which is the first # entry (offset 0x00) in the vector table. set int_vector_base [arc jtag get-aux-reg 0x25] set start_pc [read_memory $int_vector_base 32 1] arc jtag set-aux-reg 0x6 $start_pc # It is OK to do uncached writes - register cache will be invalidated by # the reset_assert() function. } # vim:expandtab: ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpu/arc/em.tcl ================================================ # Copyright (C) 2015, 2020 Synopsys, Inc. # Anton Kolesov # Didin Evgeniy # # SPDX-License-Identifier: GPL-2.0-or-later source [find cpu/arc/v2.tcl] proc arc_em_examine_target { {target ""} } { # Will set current target arc_v2_examine_target $target } proc arc_em_init_regs { } { arc_v2_init_regs [target current] configure \ -event examine-end "arc_em_examine_target [target current]" } # Scripts in "target" folder should call this function instead of direct # invocation of arc_common_reset. proc arc_em_reset { {target ""} } { arc_v2_reset $target # Set DEBUG.ED bit to enable clock in actionpoint module. # This is specific to ARC EM. set debug [arc jtag get-aux-reg 5] if { !($debug & (1 << 20)) } { arc jtag set-aux-reg 5 [expr {$debug | (1 << 20)}] } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpu/arc/hs.tcl ================================================ # Copyright (C) 2015, 2020 Synopsys, Inc. # Anton Kolesov # Didin Evgeniy # # SPDX-License-Identifier: GPL-2.0-or-later source [find cpu/arc/v2.tcl] proc arc_hs_examine_target { target } { # Will set current target for us. arc_v2_examine_target $target } proc arc_hs_init_regs { } { arc_v2_init_regs [target current] configure \ -event examine-end "arc_hs_examine_target [target current]" } # Scripts in "target" folder should call this function instead of direct # invocation of arc_common_reset. proc arc_hs_reset { {target ""} } { arc_v2_reset $target # Invalidate L2 cache if there is one. set l2_config [$target arc jtag get-aux-reg 0x901] # Will return 0, if cache is not present and register doesn't exist. set l2_ctrl [$target arc jtag get-aux-reg 0x903] if { ($l2_config != 0) && (($l2_ctrl & 1) == 0) } { puts "L2 cache is present and not disabled" # Wait until BUSY bit is 0. puts "Invalidating L2 cache..." $target arc jtag set-aux-reg 0x905 1 # Dummy read of SLC_AUX_CACHE_CTRL bit, as described in: # https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/commit/arch/arc?id=c70c473396cbdec1168a6eff60e13029c0916854 set l2_ctrl [$target arc jtag get-aux-reg 0x903] set l2_ctrl [$target arc jtag get-aux-reg 0x903] while { ($l2_ctrl & 0x100) != 0 } { set l2_ctrl [$target arc jtag get-aux-reg 0x903] } # Flush cache if needed. If SLC_AUX_CACHE_CTRL.IM is 1, then invalidate # operation already flushed everything. if { ($l2_ctrl & 0x40) == 0 } { puts "Flushing L2 cache..." $target arc jtag set-aux-reg 0x904 1 set l2_ctrl [$target arc jtag get-aux-reg 0x903] set l2_ctrl [$target arc jtag get-aux-reg 0x903] while { [expr {$l2_ctrl & 0x100}] != 0 } { set l2_ctrl [$target arc jtag get-aux-reg 0x903] } } puts "L2 cache has been flushed and invalidated." } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpu/arc/v2.tcl ================================================ # Copyright (C) 2015, 2020 Synopsys, Inc. # Anton Kolesov # Didin Evgeniy # # SPDX-License-Identifier: GPL-2.0-or-later source [find cpu/arc/common.tcl] # Currently 'examine_target' can only read JTAG registers and set properties - # but it shouldn't write any of registers - writes will be cached, but cache # will be invalidated before flushing after examine_target, and changes will be # lost. Perhaps that would be fixed later - perhaps writes shouldn't be cached # after all. But if write to register is really needed from TCL - then it # should be done via "arc jtag" for now. proc arc_v2_examine_target { {target ""} } { # Set current target, because OpenOCD event handlers don't do this for us. if { $target != "" } { targets $target } # Those registers always exist. DEBUG and DEBUGI are formally optional, # however they come with JTAG interface, and so far there is no way # OpenOCD can communicate with target without JTAG interface. arc set-reg-exists identity pc status32 bta debug lp_start lp_end \ eret erbta erstatus ecr efa # 32 core registers arc set-reg-exists \ r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 \ r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 r24 r25 \ gp fp sp ilink r30 blink lp_count pcl # Actionpoints if { [arc get-reg-field ap_build version] == 5 } { set ap_build_type [arc get-reg-field ap_build type] # AP_BUILD.TYPE > 0b0110 is reserved in current ISA. # Current ISA supports up to 8 actionpoints. if { $ap_build_type < 8 } { # Two LSB bits of AP_BUILD.TYPE define amount of actionpoints: # 0b00 - 2 actionpoints # 0b01 - 4 actionpoints # 0b10 - 8 actionpoints # 0b11 - reserved. set ap_num [expr {0x2 << ($ap_build_type & 3)}] # Expression on top may produce 16 action points - which is a # reserved value for now. if { $ap_num < 16 } { # Enable actionpoint registers for {set i 0} {$i < $ap_num} {incr i} { arc set-reg-exists ap_amv$i ap_amm$i ap_ac$i } # Set amount of actionpoints arc num-actionpoints $ap_num } } } # DCCM set dccm_version [arc get-reg-field dccm_build version] if { $dccm_version == 3 || $dccm_version == 4 } { arc set-reg-exists aux_dccm } # ICCM if { [arc get-reg-field iccm_build version] == 4 } { arc set-reg-exists aux_iccm } # MPU if { [arc get-reg-field mpu_build version] >= 2 && [arc get-reg-field mpu_build version] <= 4 } { arc set-reg-exists mpu_en mpu_ecr set mpu_regions [arc get-reg-field mpu_build regions] for {set i 0} {$i < $mpu_regions} {incr i} { arc set-reg-exists mpu_rdp$i mpu_rdb$i } # Secure MPU if { [arc get-reg-field mpu_build version] == 4 } { arc set-reg-exists mpu_index mpu_rstart mpu_rend mpu_rper } } } proc arc_v2_init_regs { } { # XML features set core_feature "org.gnu.gdb.arc.core.v2" set aux_min_feature "org.gnu.gdb.arc.aux-minimal" set aux_other_feature "org.gnu.gdb.arc.aux-other" # Describe types # Types are sorted alphabetically according to their name. arc add-reg-type-struct -name ap_build_t -bitfield version 0 7 \ -bitfield type 8 11 arc add-reg-type-struct -name ap_control_t -bitfield at 0 3 -bitfield tt 4 5 \ -bitfield m 6 6 -bitfield p 7 7 -bitfield aa 8 8 -bitfield q 9 9 # Cycles field added in version 4. arc add-reg-type-struct -name dccm_build_t -bitfield version 0 7 \ -bitfield size0 8 11 -bitfield size1 12 15 -bitfield cycles 17 19 arc add-reg-type-struct -name debug_t \ -bitfield fh 1 1 -bitfield ah 2 2 -bitfield asr 3 10 \ -bitfield is 11 11 -bitfield ep 19 19 -bitfield ed 20 20 \ -bitfield eh 21 21 -bitfield ra 22 22 -bitfield zz 23 23 \ -bitfield sm 24 26 -bitfield ub 28 28 -bitfield bh 29 29 \ -bitfield sh 30 30 -bitfield ld 31 31 arc add-reg-type-struct -name ecr_t \ -bitfield parameter 0 7 \ -bitfield cause 8 15 \ -bitfield vector 16 23 \ -bitfield U 30 30 \ -bitfield P 31 31 arc add-reg-type-struct -name iccm_build_t -bitfield version 0 7 \ -bitfield iccm0_size0 8 11 -bitfield iccm1_size0 12 15 \ -bitfield iccm0_size1 16 19 -bitfield iccm1_size1 20 23 arc add-reg-type-struct -name identity_t \ -bitfield arcver 0 7 -bitfield arcnum 8 15 -bitfield chipid 16 31 arc add-reg-type-struct -name isa_config_t -bitfield version 0 7 \ -bitfield pc_size 8 11 -bitfield lpc_size 12 15 -bitfield addr_size 16 19 \ -bitfield b 20 20 -bitfield a 21 21 -bitfield n 22 22 -bitfield l 23 23 \ -bitfield c 24 27 -bitfield d 28 31 arc add-reg-type-struct -name mpu_build_t -bitfield version 0 7 \ -bitfield regions 8 15 \ -bitfield s 16 16 \ -bitfield i 17 17 arc add-reg-type-struct -name mpu_ecr_t \ -bitfield MR 0 7 \ -bitfield VT 8 9 \ -bitfield EC_CODE 16 31 arc add-reg-type-struct -name mpu_en_t \ -bitfield UE 3 3 -bitfield UW 4 4 -bitfield UR 5 5 \ -bitfield KE 6 6 -bitfield KW 7 7 -bitfield KR 8 8 \ -bitfield S 15 15 -bitfield SID 16 23 \ -bitfield EN 30 30 arc add-reg-type-struct -name mpu_index_t \ -bitfield I 0 3 -bitfield M 30 30 -bitfield D 31 31 arc add-reg-type-struct -name mpu_rper_t \ -bitfield V 0 0 \ -bitfield UE 3 3 -bitfield UW 4 4 -bitfield UR 5 5 \ -bitfield KE 6 6 -bitfield KW 7 7 -bitfield KR 8 8 \ -bitfield S 15 15 -bitfield SID 16 23 arc add-reg-type-flags -name status32_t \ -flag H 0 -flag E0 1 -flag E1 2 -flag E2 3 \ -flag E3 4 -flag AE 5 -flag DE 6 -flag U 7 \ -flag V 8 -flag C 9 -flag N 10 -flag Z 11 \ -flag L 12 -flag DZ 13 -flag SC 14 -flag ES 15 \ -flag RB0 16 -flag RB1 17 -flag RB2 18 \ -flag AD 19 -flag US 20 -flag IE 31 # Core registers set core_regs { r0 0 uint32 r1 1 uint32 r2 2 uint32 r3 3 uint32 r4 4 uint32 r5 5 uint32 r6 6 uint32 r7 7 uint32 r8 8 uint32 r9 9 uint32 r10 10 uint32 r11 11 uint32 r12 12 uint32 r13 13 uint32 r14 14 uint32 r15 15 uint32 r16 16 uint32 r17 17 uint32 r18 18 uint32 r19 19 uint32 r20 20 uint32 r21 21 uint32 r22 23 uint32 r23 24 uint32 r24 24 uint32 r25 25 uint32 gp 26 data_ptr fp 27 data_ptr sp 28 data_ptr ilink 29 code_ptr r30 30 uint32 blink 31 code_ptr r32 32 uint32 r33 33 uint32 r34 34 uint32 r35 35 uint32 r36 36 uint32 r37 37 uint32 r38 38 uint32 r39 39 uint32 r40 40 uint32 r41 41 uint32 r42 42 uint32 r43 43 uint32 r44 44 uint32 r45 45 uint32 r46 46 uint32 r47 47 uint32 r48 48 uint32 r49 49 uint32 r50 50 uint32 r51 51 uint32 r52 52 uint32 r53 53 uint32 r54 54 uint32 r55 55 uint32 r56 56 uint32 r57 57 uint32 accl 58 uint32 acch 59 uint32 lp_count 60 uint32 limm 61 uint32 reserved 62 uint32 pcl 63 code_ptr } foreach {reg count type} $core_regs { arc add-reg -name $reg -num $count -core -type $type -g \ -feature $core_feature } # AUX min set aux_min { 0x6 pc code_ptr 0x2 lp_start code_ptr 0x3 lp_end code_ptr 0xA status32 status32_t } foreach {num name type} $aux_min { arc add-reg -name $name -num $num -type $type -feature $aux_min_feature -g } # AUX other set aux_other { 0x004 identity identity_t 0x005 debug debug_t 0x018 aux_dccm int 0x208 aux_iccm int 0x220 ap_amv0 uint32 0x221 ap_amm0 uint32 0x222 ap_ac0 ap_control_t 0x223 ap_amv1 uint32 0x224 ap_amm1 uint32 0x225 ap_ac1 ap_control_t 0x226 ap_amv2 uint32 0x227 ap_amm2 uint32 0x228 ap_ac2 ap_control_t 0x229 ap_amv3 uint32 0x22A ap_amm3 uint32 0x22B ap_ac3 ap_control_t 0x22C ap_amv4 uint32 0x22D ap_amm4 uint32 0x22E ap_ac4 ap_control_t 0x22F ap_amv5 uint32 0x230 ap_amm5 uint32 0x231 ap_ac5 ap_control_t 0x232 ap_amv6 uint32 0x233 ap_amm6 uint32 0x234 ap_ac6 ap_control_t 0x235 ap_amv7 uint32 0x236 ap_amm7 uint32 0x237 ap_ac7 ap_control_t 0x400 eret code_ptr 0x401 erbta code_ptr 0x402 erstatus status32_t 0x403 ecr ecr_t 0x404 efa data_ptr 0x409 mpu_en mpu_en_t 0x412 bta code_ptr 0x420 mpu_ecr mpu_ecr_t 0x422 mpu_rdb0 int 0x423 mpu_rdp0 int 0x424 mpu_rdb1 int 0x425 mpu_rdp1 int 0x426 mpu_rdb2 int 0x427 mpu_rdp2 int 0x428 mpu_rdb3 int 0x429 mpu_rdp3 int 0x42A mpu_rdb4 int 0x42B mpu_rdp4 int 0x42C mpu_rdb5 int 0x42D mpu_rdp5 int 0x42E mpu_rdb6 int 0x42F mpu_rdp6 int 0x430 mpu_rdb7 int 0x431 mpu_rdp7 int 0x432 mpu_rdb8 int 0x433 mpu_rdp8 int 0x434 mpu_rdb9 int 0x435 mpu_rdp9 int 0x436 mpu_rdb10 int 0x437 mpu_rdp10 int 0x438 mpu_rdb11 int 0x439 mpu_rdp11 int 0x43A mpu_rdb12 int 0x43B mpu_rdp12 int 0x43C mpu_rdb13 int 0x43D mpu_rdp13 int 0x43E mpu_rdb14 int 0x43F mpu_rdp14 int 0x440 mpu_rdb15 int 0x441 mpu_rdp15 int 0x448 mpu_index mpu_index_t 0x449 mpu_rstart uint32 0x44A mpu_rend uint32 0x44B mpu_rper mpu_rper_t 0x44C mpu_probe uint32 } foreach {num name type} $aux_other { arc add-reg -name $name -num $num -type $type -feature $aux_other_feature } # AUX BCR set bcr { 0x6D mpu_build 0x74 dccm_build 0x76 ap_build 0x78 iccm_build 0xC1 isa_config } foreach {num reg} $bcr { arc add-reg -name $reg -num $num -type ${reg}_t -bcr -feature $aux_other_feature } [target current] configure \ -event examine-end "arc_v2_examine_target [target current]" } proc arc_v2_reset { {target ""} } { arc_common_reset $target # Disable all actionpoints. Cannot write via regcache yet, because it will # not be flushed and all changes to registers will get lost. Therefore has # to write directly via JTAG layer... set num_ap [arc num-actionpoints] for {set i 0} {$i < $num_ap} {incr i} { arc jtag set-aux-reg [expr {0x222 + $i * 3}] 0 } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpu/arm/arm7tdmi.tcl ================================================ set CPU_TYPE arm set CPU_NAME arm7tdmi set CPU_ARCH armv4t set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpu/arm/arm920.tcl ================================================ set CPU_TYPE arm set CPU_NAME arm920 set CPU_ARCH armv4t set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpu/arm/arm946.tcl ================================================ set CPU_TYPE arm set CPU_NAME arm946 set CPU_ARCH armv5te set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpu/arm/arm966.tcl ================================================ set CPU_TYPE arm set CPU_NAME arm966 set CPU_ARCH armv5te set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/cpu/arm/cortex_m3.tcl ================================================ set CPU_TYPE arm set CPU_NAME cortex_m3 set CPU_ARCH armv7 set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/fpga/altera-10m50.cfg ================================================ # see MAX 10 FPGA Device Architecture # Table 3-1: IDCODE Information for MAX 10 Devices # Intel MAX 10M02 0x31810dd # Intel MAX 10M04 0x318a0dd # Intel MAX 10M08 0x31820dd # Intel MAX 10M16 0x31830dd # Intel MAX 10M25 0x31840dd # Intel MAX 10M40 0x318d0dd # Intel MAX 10M50 0x31850dd # Intel MAX 10M02 0x31010dd # Intel MAX 10M04 0x310a0dd # Intel MAX 10M08 0x31020dd # Intel MAX 10M16 0x31030dd # Intel MAX 10M25 0x31040dd # Intel MAX 10M40 0x310d0dd # Intel MAX 10M50 0x31050dd jtag newtap 10m50 tap -irlen 10 -expected-id 0x31810dd -expected-id 0x318a0dd \ -expected-id 0x31820dd -expected-id 0x31830dd -expected-id 0x31840dd \ -expected-id 0x318d0dd -expected-id 0x31850dd -expected-id 0x31010dd \ -expected-id 0x310a0dd -expected-id 0x31020dd -expected-id 0x31030dd \ -expected-id 0x31040dd -expected-id 0x310d0dd -expected-id 0x31050dd ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/fpga/altera-ep3c10.cfg ================================================ # Altera Cyclone III EP3C10 # see Cyclone III Device Handbook, Volume 1; # Table 14–5. 32-Bit Cyclone III Device IDCODE jtag newtap ep3c10 tap -expected-id 0x020f10dd -irlen 10 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/fpga/altera-ep4ce10.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ecp4 } jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ -expected-id -0x020f10ddc ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/fpga/lattice_ecp5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME ecp5 } # Lattice ECP5 family # TAP IDs are extracted from BSDL files found on this page: # https://www.latticesemi.com/Products/FPGAandCPLD/ECP5 # # 0x01111043 - LAE5UM_25F/LFE5UM_25F # 0x01112043 - LAE5UM_45F/LFE5UM_45F # 0x01113043 - LAE5UM_85F/LFE5UM_85 # 0x21111043 - LFE5U_12F # 0x41111043 - LFE5U_25F # 0x41112043 - LFE5U_45F # 0x41113043 - LFE5U_85F # 0x81111043 - LFE5UM5G-25 # 0x81112043 - LFE5UM5G-45 # 0x81113043 - LFE5UM5G-85 jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ -expected-id 0x01111043 -expected-id 0x01112043 -expected-id 0x01113043 \ -expected-id 0x21111043 -expected-id 0x41111043 -expected-id 0x41112043 \ -expected-id 0x41113043 -expected-id 0x81111043 -expected-id 0x81112043 \ -expected-id 0x81113043 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/fpga/xilinx-dna.cfg ================================================ proc xilinx_dna_addr {chip} { array set addrs { Spartan6 0x30 Series7 0x17 } return $addrs($chip) } # Get the "Device DNA". # Most Xilinx FPGA devices contain an embedded, unique device identifier. # The identifier is nonvolatile, permanently programmed into # the FPGA, and is unchangeable providing a great serial / tracking number. # This function returns the DNA as a 64 bit integer with the 7 LSBs zeroed. # This is compatible with the FUSE DNA which contains all 64 bits. proc xilinx_get_dna {tap chip} { set XC7_ISC_ENABLE 0x10 set XC7_ISC_DISABLE 0x16 set XC7_ISC_DNA [xilinx_dna_addr $chip] irscan $tap $XC7_ISC_ENABLE runtest 64 irscan $tap $XC7_ISC_DNA scan [drscan $tap 32 0 32 0] "%08x %08x" hi lo runtest 64 irscan $tap $XC7_ISC_DISABLE runtest 64 # openocd interprets DR scans as LSB first, bit-reverse it return [scan [string reverse [format "%032b%032bb0" $lo $hi]] "%i"] } # Print out the "Device DNA" in the same format that impact uses. proc xilinx_print_dna {dna} { set dna [expr {$dna >> 64 - 57}] echo [format "DNA = %057b (0x%016x)" $dna $dna] } proc xc7_get_dna {tap} { return [xilinx_get_dna $tap Series7] } proc xc6s_get_dna {tap} { return [xilinx_get_dna $tap Spartan6] } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/fpga/xilinx-xadc.cfg ================================================ # Xilinx XADC support for 7 Series FPGAs # # The 7 Series FPGAs contain an on-chip 12 bit ADC that can probe die # temperature, internal power supply rail voltages as well as external # voltages. The XADC is available both from fabric as well as through the # JTAG TAP. # # This code implements access through the JTAG TAP. # # https://www.xilinx.com/support/documentation/user_guides/ug480_7Series_XADC.pdf # build a 32 bit DRP command for the XADC DR proc xadc_cmd {cmd addr data} { array set cmds { NOP 0x00 READ 0x01 WRITE 0x02 } return [expr {($cmds($cmd) << 26) | ($addr << 16) | ($data << 0)}] } # XADC register addresses # Some addresses (status registers 0-3) have special function when written to. proc XADC {key} { array set addrs { TEMP 0x00 LOCK 0x00 VCCINT 0x01 VCCAUX 0x02 VAUXEN 0x02 VPVN 0x03 RESET 0x03 VREFP 0x04 VREFN 0x05 VCCBRAM 0x06 SUPAOFFS 0x08 ADCAOFFS 0x09 ADCAGAIN 0x0a VCCPINT 0x0d VCCPAUX 0x0e VCCODDR 0x0f VAUX0 0x10 VAUX1 0x11 VAUX2 0x12 VAUX3 0x13 VAUX4 0x14 VAUX5 0x15 VAUX6 0x16 VAUX7 0x17 VAUX8 0x18 VAUX9 0x19 VAUX10 0x1a VAUX11 0x1b VAUX12 0x1c VAUX13 0x1d VAUX14 0x1e VAUX15 0x1f SUPBOFFS 0x30 ADCBOFFS 0x31 ADCBGAIN 0x32 FLAG 0x3f CFG0 0x40 CFG1 0x41 CFG2 0x42 SEQ0 0x48 SEQ1 0x49 SEQ2 0x4a SEQ3 0x4b SEQ4 0x4c SEQ5 0x4d SEQ6 0x4e SEQ7 0x4f ALARM0 0x50 ALARM1 0x51 ALARM2 0x52 ALARM3 0x53 ALARM4 0x54 ALARM5 0x55 ALARM6 0x56 ALARM7 0x57 ALARM8 0x58 ALARM9 0x59 ALARM10 0x5a ALARM11 0x5b ALARM12 0x5c ALARM13 0x5d ALARM14 0x5e ALARM15 0x5f } return $addrs($key) } # Select the XADC DR proc xadc_select {tap} { set XADC_IR 0x37 irscan $tap $XADC_IR runtest 10 } # XADC transfer proc xadc_xfer {tap cmd addr data} { set ret [drscan $tap 32 [xadc_cmd $cmd $addr $data]] runtest 10 return [expr "0x$ret"] } # XADC register write proc xadc_write {tap addr data} { xadc_xfer $tap WRITE $addr $data } # XADC register read, non-pipelined proc xadc_read {tap addr} { xadc_xfer $tap READ $addr 0 return [xadc_xfer $tap NOP 0 0] } # convert 16 bit register code from ADC measurement on # external voltages (VAUX) to Volt proc xadc_volt {code} { return [expr {$code * 1./(1 << 16)}] } # convert 16 bit temperature measurement to Celsius proc xadc_temp {code} { return [expr {$code * 503.975/(1 << 16) - 273.15}] } # convert 16 bit suppply voltage measurement to Volt proc xadc_sup {code} { return [expr {$code * 3./(1 << 16)}] } # perform a single channel measurement using default settings proc xadc_single {tap ch} { set cfg0 [xadc_read $tap [XADC CFG0]] set cfg1 [xadc_read $tap [XADC CFG1]] # set channel xadc_write $tap [XADC CFG0] $cfg0 # single channel, disable the sequencer xadc_write $tap [XADC CFG1] 0x3000 # leave some time for the conversion runtest 100 set ret [xadc_read $tap [XADC $ch]] # restore CFG0/1 xadc_write $tap [XADC CFG0] $cfg0 xadc_write $tap [XADC CFG1] $cfg1 return $ret } # measure all internal voltages proc xadc_report {tap} { xadc_select $tap echo "TEMP [format %.2f [xadc_temp [xadc_single $tap TEMP]]] C" foreach ch [list VCCINT VCCAUX VCCBRAM VPVN VREFP VREFN \ VCCPINT VCCPAUX VCCODDR] { echo "$ch [format %.3f [xadc_sup [xadc_single $tap $ch]]] V" } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/altera-usb-blaster.cfg ================================================ # # Altera USB-Blaster # # http://www.altera.com/literature/ug/ug_usb_blstr.pdf # adapter driver usb_blaster usb_blaster lowlevel_driver ftdi # These are already the defaults. # usb_blaster vid_pid 0x09FB 0x6001 # usb_blaster device_desc "USB-Blaster" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/altera-usb-blaster2.cfg ================================================ # # Altera USB-Blaster II # adapter driver usb_blaster usb_blaster vid_pid 0x09fb 0x6010 0x09fb 0x6810 usb_blaster lowlevel_driver ublast2 usb_blaster firmware /path/to/quartus/blaster_6810.hex ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/arm-jtag-ew.cfg ================================================ # # Olimex ARM-JTAG-EW # # http://www.olimex.com/dev/arm-jtag-ew.html # adapter driver arm-jtag-ew ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/at91rm9200.cfg ================================================ # # Various Atmel AT91RM9200 boards # # TODO: URL? # adapter driver at91rm9200 at91rm9200_device rea_ecr ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/beaglebone-jtag-native.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # BeagleBone native GPIO interface for JTAG # # This is best used with a fast buffer but it is also suitable for a direct # connection if the target voltage matches the host's IO voltage (typically # 3.3V) and the cable is short. # # DO NOT APPLY VOLTAGE TO THE GPIO PINS UNTIL SYS_RESETN IS HIGH. # # Do not forget the GND connection. adapter driver am335xgpio # Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET # These depend on the system clock, calibrated for stock 1 GHz BeagleBoneBlack # am335xgpio speed SPEED_COEFF SPEED_OFFSET am335xgpio speed_coeffs 600000 575 am335xgpio tdo_num 20 am335xgpio tdi_num 60 am335xgpio tms_num 4 am335xgpio tck_num 2 am335xgpio led_num 51 am335xgpio led_on_state on am335xgpio srst_num 65 reset_config srst_only srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/beaglebone-swd-native.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # BeagleBone native GPIO interface for SWD # # This is best used with a fast buffer but it is also suitable for a direct # connection if the target voltage matches the host's IO voltage (typically # 3.3V) and the cable is short. # # DO NOT APPLY VOLTAGE TO THE GPIO PINS UNTIL SYS_RESETN IS HIGH. # # Do not forget the GND connection. adapter driver am335xgpio # Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET # These depend on the system clock, calibrated for stock 1 GHz BeagleBoneBlack # am335xgpio speed SPEED_COEFF SPEED_OFFSET am335xgpio speed_coeffs 600000 575 am335xgpio swclk_num 2 am335xgpio swdio_num 4 am335xgpio swdio_dir_num 60 am335xgpio swdio_dir_output_state on # USR0 LED am335xgpio led_num 53 am335xgpio led_on_state on am335xgpio srst_num 65 reset_config srst_only srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/buspirate.cfg ================================================ # # Buspirate with OpenOCD support # # http://dangerousprototypes.com/bus-pirate-manual/ # adapter driver buspirate # you need to specify port on which BP lives #buspirate port /dev/ttyUSB0 # communication speed setting buspirate speed normal ;# or fast # voltage regulator Enabled = 1 Disabled = 0 #buspirate vreg 0 # pin mode normal or open-drain (jtag only) #buspirate mode normal # pullup state Enabled = 1 Disabled = 0 #buspirate pullup 0 # this depends on the cable, you are safe with this option reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/calao-usb-a9260.cfg ================================================ # # CALAO Systems USB-A9260 common -C01 -C02 setup # # http://www.calao-systems.com/ # # See calao-usb-a9260-c01.cfg and calao-usb-a9260-c02.cfg. # adapter srst delay 200 jtag_ntrst_delay 200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/chameleon.cfg ================================================ # # Amontec Chameleon POD # # http://www.amontec.com/chameleon.shtml # adapter driver parport parport cable chameleon ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/cmsis-dap.cfg ================================================ # # ARM CMSIS-DAP compliant adapter # # http://www.keil.com/support/man/docs/dapdebug/ # adapter driver cmsis-dap # Optionally specify the serial number of CMSIS-DAP usb device. # adapter serial 02200201E6661E601B98E3B9 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/dln-2-gpiod.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Use DLN-2 GPIO through linuxgpiod # # +-----------+-------------+-------------+ # | signal | DLN-2 | gpio offset | # +-----------+-------------+-------------+ # | nSRST | J3.1 (PA0) | 0 | # | TDO | J3.2 (PA1) | 1 | # | TCK/SWCLK | J3.3 (PA2) | 2 | # | TMS/SWDIO | J3.4 (PA3) | 3 | # | TDI | J3.5 (PA4) | 4 | # | nTRST | J3.6 (PA5) | 5 | # | LED | J3.7 (PA6) | 6 | # | GND | J3.12 (GND) | | # +-----------+-------------+-------------+ adapter driver linuxgpiod linuxgpiod gpiochip 0 linuxgpiod jtag_nums 2 3 4 1 linuxgpiod trst_num 5 linuxgpiod swd_nums 2 3 linuxgpiod srst_num 0 linuxgpiod led_num 6 reset_config trst_and_srst separate srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/dummy.cfg ================================================ # # Dummy interface (for testing purposes) # adapter driver dummy ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/estick.cfg ================================================ # # eStick # # http://code.google.com/p/estick-jtag/ # adapter driver opendous ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/flashlink.cfg ================================================ # # ST FlashLINK JTAG parallel cable # # http://www.st.com/internet/evalboard/product/94023.jsp # http://www.st.com/stonline/products/literature/um/7889.pdf # if { [info exists PARPORTADDR] } { set _PARPORTADDR $PARPORTADDR } else { set _PARPORTADDR 0 } adapter driver parport parport port $_PARPORTADDR parport cable flashlink ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ft232r/radiona_ulx3s.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # This adapter is integrated in to Radiona ULX3S board: # board/radiona_ulx3s.cfg # See schematics for the ft232r layout: # https://github.com/emard/ulx3s/blob/master/doc/schematics_v316.pdf adapter driver ft232r adapter speed 1000 ft232r_vid_pid 0x0403 0x6015 ft232r_tck_num DSR ft232r_tms_num DCD ft232r_tdi_num RI ft232r_tdo_num CTS ft232r_trst_num RTS ft232r_srst_num DTR ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ft232r.cfg ================================================ adapter driver ft232r adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/100ask-openjtag.cfg ================================================ # # www.100ask.org OpenJTAG # # http://www.100ask.net/OpenJTAG.html # # Schematics are available from # https://blog.matthiasbock.net/wp-content/uploads/2015/04/100ask-JTAGv3.pdf # adapter driver ftdi ftdi device_desc "USB<=>JTAG&RS232" ftdi vid_pid 0x1457 0x5118 ftdi layout_init 0x0f08 0x0f1b ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/ashling-opella-ld-jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Ashling Opella-LD # # https://www.ashling.com/Opella-LD/ # adapter driver ftdi ftdi device_desc "Opella-LD Debug Probe" ftdi vid_pid 0x0B6B 0x0040 ftdi tdo_sample_edge falling ftdi layout_init 0x0A68 0xFF7B ftdi channel 0 ftdi layout_signal JTAGOE -ndata 0x0010 ftdi layout_signal nTRST -data 0x0020 ftdi layout_signal nSRST -data 0x0040 ftdi layout_signal SWD_EN -data 0x0100 ftdi layout_signal SWDIO_OE -data 0x0200 ftdi layout_signal LED -ndata 0x0800 transport select jtag ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/ashling-opella-ld-swd.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Ashling Opella-LD # # https://www.ashling.com/Opella-LD/ # adapter driver ftdi ftdi device_desc "Opella-LD Debug Probe" ftdi vid_pid 0x0B6B 0x0040 ftdi layout_init 0x0860 0x0b7b ftdi channel 0 ftdi layout_signal JTAGOE -data 0x0010 ftdi layout_signal nTRST -data 0x0020 ftdi layout_signal nSRST -data 0x0040 ftdi layout_signal SWD_EN -data 0x0100 ftdi layout_signal SWDIO_OE -data 0x0200 ftdi layout_signal LED -ndata 0x0800 transport select swd ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/axm0432.cfg ================================================ # # Axiom axm0432 # # http://www.axman.com # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "Symphony SoundBite" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0c08 0x0c2b ftdi layout_signal nTRST -data 0x0800 ftdi layout_signal nSRST -data 0x0400 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/c232hm.cfg ================================================ # FTDI USB Hi-Speed to MPSSE Cable # # http://www.ftdichip.com/Products/Cables/USBMPSSE.htm # # C232HM-DDHSL-0 and C232HM-EDSL-0 provide 3.3V and 5V on pin 1 (Red), # respectively. # # Adapter: http://www.ftdichip.com/Support/Documents/DataSheets/Cables/DS_C232HM_MPSSE_CABLE.PDF # Chip: http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232H.pdf # See pinout/colors at end of this file. # # Tech notes: # http://www.ftdichip.com/Support/Documents/AppNotes/AN_135_MPSSE_Basics.pdf # http://www.ftdichip.com/Support/Documents/AppNotes/AN_129_FTDI_Hi_Speed_USB_To_JTAG_Example.pdf adapter driver ftdi #ftdi device_desc "C232HM-DDHSL-0" #ftdi device_desc "C232HM-EDHSL-0" # Common PID for FT232H ftdi vid_pid 0x0403 0x6014 # Layout # High data byte 0x40 configures red LED on ACBUS6 initially high (unlit, since active-low) # Low data byte 0x08 configures TMS on ACBUS3 initially high (asserted); TCK, TDI low # High direction byte 0x40 configures red LED on ACBUS6 as high (output) # Low direction byte 0x0b configures TDO on ACBUS2 as low (input) ftdi layout_init 0x4008 0x400b # ---A*BUS-------CCCCCCCC|DDDDDDDD # --------\______76543210|76543210 # LED 0x4000 = 01000000|00000000 = ACBUS6 #GPIOL0 0x0010 = 00000000|00010000 = ADBUS4 #GPIOL1 0x0020 = 00000000|00100000 = ADBUS5 #GPIOL2 0x0040 = 00000000|01000000 = ADBUS6 #GPIOL3 0x0080 = 00000000|10000000 = ADBUS7 # -ndata treats the LED as active-low for expected behavior (toggle when transferring) ftdi layout_signal LED -ndata 0x4000 # Available for aliasing as desired ftdi layout_signal GPIOL0 -data 0x0010 -oe 0x0010 ftdi layout_signal GPIOL1 -data 0x0020 -oe 0x0020 ftdi layout_signal GPIOL2 -data 0x0040 -oe 0x0040 ftdi layout_signal GPIOL3 -data 0x0080 -oe 0x0080 # C232HM FT232H JTAG/Other # Num Color Name Func # 1 Red VCC Optionally, can power the board if it is not using its own power supply. # 2 Orange ADBUS0 TCK # 3 Yellow ADBUS1 TDI # 4 Green ADBUS2 TDO # 5 Brown ADBUS3 TMS # 6 Grey ADBUS4 GPIOL0 # 7 Purple ADBUS5 GPIOL1 # 8 White ADBUS6 GPIOL2 # 9 Blue ADBUS7 GPIOL3 # 10 Black GND Connect to ground ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/calao-usb-a9260-c01.cfg ================================================ # # CALAO Systems USB-A9260-C01 # # http://www.calao-systems.com/ # echo "WARNING!" echo "This file was not tested with real interface, but is assumed to work as this" echo "interface uses the same layout as configs that were verified. Please report your" echo "experience with this file to openocd-devel mailing list, so it could be marked" echo "as working or fixed." adapter driver ftdi ftdi device_desc "USB-A9260" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 script interface/calao-usb-a9260.cfg script target/at91sam9260minimal.cfg ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/calao-usb-a9260-c02.cfg ================================================ # # CALAO Systems USB-A9260-C02 # # http://www.calao-systems.com/ # echo "WARNING!" echo "This file was not tested with real interface, but is assumed to work as this" echo "interface uses the same layout as configs that were verified. Please report your" echo "experience with this file to openocd-devel mailing list, so it could be marked" echo "as working or fixed." adapter driver ftdi ftdi device_desc "USB-A9260" ftdi vid_pid 0x0403 0x6001 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 script interface/calao-usb-a9260.cfg script target/at91sam9260minimal.cfg ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/cortino.cfg ================================================ # # Hitex Cortino # # http://www.hitex.com/index.php?id=cortino # adapter driver ftdi ftdi device_desc "Cortino" ftdi vid_pid 0x0640 0x0032 ftdi layout_init 0x0108 0x010b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0200 -oe 0x0200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/digilent-hs1.cfg ================================================ # this supports JTAG-HS1 and JTAG-SMT1 # (the later being the OEM on-board version) adapter driver ftdi ftdi device_desc "Digilent Adept USB Device" ftdi vid_pid 0x0403 0x6010 # channel 1 does not have any functionality ftdi channel 0 # just TCK TDI TDO TMS, no reset ftdi layout_init 0x0088 0x008b reset_config none ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/digilent-hs2.cfg ================================================ # this supports JTAG-HS2 (and apparently Nexys4 as well) adapter driver ftdi ftdi device_desc "Digilent Adept USB Device" ftdi vid_pid 0x0403 0x6014 ftdi channel 0 ftdi layout_init 0x00e8 0x60eb reset_config none ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/digilent_jtag_hs3.cfg ================================================ # # Digilent JTAG-HS3 # adapter driver ftdi ftdi vid_pid 0x0403 0x6014 ftdi device_desc "Digilent USB Device" # From Digilent support: # The SRST pin is [...] 0x20 and 0x10 is the /OE (active low output enable) ftdi layout_init 0x2088 0x308b ftdi layout_signal nSRST -data 0x2000 -noe 0x1000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/digilent_jtag_smt2.cfg ================================================ # # Digilent JTAG-SMT2 # # http://www.digilentinc.com/Products/Detail.cfm?NavPath=2,395,1053&Prod=JTAG-SMT2 # # Config is based on data from # http://electronix.ru/forum/index.php?showtopic=114633&view=findpost&p=1215497 and ZedBoard schematics # adapter driver ftdi ftdi vid_pid 0x0403 0x6014 ftdi layout_init 0x20e8 0x3feb ftdi layout_signal nSRST -data 0x2000 ftdi layout_signal GPIO2 -data 0x2000 ftdi layout_signal GPIO1 -data 0x0200 ftdi layout_signal GPIO0 -data 0x0100 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/digilent_jtag_smt2_nc.cfg ================================================ # # Digilent JTAG-SMT2-NC # # http://store.digilentinc.com/jtag-smt2-nc-surface-mount-programming-module/ # https://reference.digilentinc.com/_media/jtag_smt2nc/jtag-smt2-nc_rm.pdf # # Based on reference sheet (above) and Xilinx KCU105 schematics # https://www.xilinx.com/products/boards-and-kits/kcu105.html#documentation # # Note that the digilent_jtag_smt2 layout does not work and hangs while # the ftdi device_desc from digilent_hs2 is wrong. adapter driver ftdi ftdi device_desc "Digilent USB Device" ftdi vid_pid 0x0403 0x6014 ftdi channel 0 ftdi layout_init 0x00e8 0x60eb reset_config none ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/dlp-usb1232h.cfg ================================================ # # DLP Design DLP-USB1232H USB-to-UART/FIFO interface module # # http://www.dlpdesign.com/usb/usb1232h.shtml # # Schematics for OpenOCD usage: # http://randomprojects.org/wiki/DLP-USB1232H_and_OpenOCD_based_JTAG_adapter # echo "WARNING!" echo "This file was not tested with real interface, it is based on schematics and code" echo "in ft2232.c. Please report your experience with this file to openocd-devel" echo "mailing list, so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/dp_busblaster.cfg ================================================ # # Dangerous Prototypes - Bus Blaster # # The Bus Blaster has a configurable buffer between the FTDI FT2232H and the # JTAG header which allows it to emulate various debugger types. It comes # configured as a JTAGkey device. # # http://dangerousprototypes.com/docs/Bus_Blaster # echo "Info : If you need SWD support, flash KT-Link buffer from https://github.com/bharrisau/busblaster and use dp_busblaster_kt-link.cfg instead" adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/dp_busblaster_kt-link.cfg ================================================ # # Dangerous Prototypes - Bus Blaster (with KT-Link buffer) # # The Bus Blaster has a configurable buffer between the FTDI FT2232H # and the JTAG header which allows it to emulate various debugger # types. This config works with KT-Link compatible implementation from # https://github.com/bharrisau/busblaster and is SWD-enabled. # # http://dangerousprototypes.com/docs/Bus_Blaster # adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x8c28 0xff3b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ftdi layout_signal LED -ndata 0x8000 ftdi layout_signal SWD_EN -ndata 0x0020 -oe 0x2000 ftdi layout_signal SWDIO_OE -ndata 0x1000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/esp32s2_kaluga_v1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Driver for the FT2232H JTAG chip on the Espressif Kaluga-1 ESP32-S2 board # (and most other FT2232H and FT232H based boards) # # JTAG DIP switch (labelled SW5 in the schematic) should be "ON" for lines # labelled TCK, TDO, TDI and TWS, to connect the FT2232H to the ESP32-S2. # adapter driver ftdi ftdi vid_pid 0x0403 0x6010 0x0403 0x6014 # interface 1 is the uart ftdi channel 0 # TCK, TDI, TDO, TMS: ADBUS0-3 # TRST/SRST: ADBUS5 (unused for now) # LEDs: ACBUS3-4 (inverted) ftdi layout_init 0x0008 0x180b ftdi layout_signal LED -ndata 0x0800 ftdi layout_signal LED2 -ndata 0x1000 # ESP32* series chips do not have a TRST input, and the SRST line is connected # to the EN pin. # The target code doesn't handle SRST reset properly yet, so this is # commented out: # ftdi layout_signal nSRST -oe 0x0020 # reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/flossjtag-noeeprom.cfg ================================================ # # FlossJTAG # # http://github.com/esden/floss-jtag # # This is the pre v0.3 Floss-JTAG compatible config file. It can also be used # for newer versions of Floss-JTAG with empty or not populated EEPROM. If you # have several Floss-JTAG connected you have to use the USB ID to select a # specific one. # # If you have a Floss-JTAG WITH EEPROM that is programmed, use the # flossjtag.cfg file. # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/flossjtag.cfg ================================================ # # FlossJTAG # # http://github.com/esden/floss-jtag # # This is the v0.3 and v1.0 Floss-JTAG compatible config file. It relies on the # existence of an EEPROM on Floss-JTAG containing a name. If you have several # Floss-JTAG adapters connected you can use the serial number to select a # specific device. # # If your Floss-JTAG does not have an EEPROM, or the EEPROM is empty, use the # flossjtag-noeeprom.cfg file. # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi device_desc "FLOSS-JTAG" # adapter serial "FJ000001" ftdi layout_init 0x0008 0x180b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 ftdi layout_signal LED -data 0x0800 ftdi layout_signal LED2 -data 0x1000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/flyswatter.cfg ================================================ # # TinCanTools Flyswatter # # http://web.archive.org/web/20150419072034/http://www.tincantools.com/JTAG/Flyswatter.html # adapter driver ftdi ftdi device_desc "Flyswatter" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0818 0x0cfb ftdi layout_signal nTRST -data 0x0010 ftdi layout_signal nSRST -oe 0x0020 ftdi layout_signal LED -data 0x0c00 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/flyswatter2.cfg ================================================ # # TinCanTools Flyswatter2 # # https://www.tincantools.com/product/flyswatter2/ # adapter driver ftdi ftdi device_desc "Flyswatter2" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0538 0x057b ftdi layout_signal LED -ndata 0x0400 ftdi layout_signal nTRST -data 0x0010 ftdi layout_signal nSRST -data 0x0020 -noe 0x0100 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/ft232h-module-swd.cfg ================================================ # # ADAFRUIT FTDI FT232H as a SWD direct connect interface # Any FT232H based board may work # # http://www.ftdichip.com/Products/ICs/FT232H.htm # # adapter driver ftdi ftdi vid_pid 0x0403 0x6014 # data MSB..LSB direction (1:out) MSB..LSB # 0000'0000'0011'0000 0000'0000'0011'1011 ftdi layout_init 0x0030 0x003b # 0xfff8 0xfffb # Those signal are only required on some platforms or may required to be # enabled explicitly (e.g. nrf5x chips). ftdi layout_signal nSRST -data 0x0010 -oe 0x0010 ftdi layout_signal nTRST -data 0x0020 -oe 0x0020 # swd enable ftdi layout_signal SWD_EN -data 0 # tri-state (configure as input) TDO/TIO when reading ftdi layout_signal SWDIO_OE -data 0 transport select swd # re-configure TDO as tri-state #ftdi layout_signal TDO -data 0x0002 -oe 0x0002 #ftdi layout_signal TDI -data 0x0004 # Adafruit FT232H JTAG SWD # Name Pin Name Func Func # D0 J1-3 ADBUS0 TCK SWDCLK # D1 J1-4 ADBUS1 TDO/DI SWDIO # D2 J1-5 ADBUS2 TDI/DO SWDIO # D3 J1-6 ADBUS3 TMS N/A # D4 J1-7 ADBUS4 (GPIOL0) /nSRST optional module reset # D5 J1-8 ADBUS5 (GPIOL1) /nTRST optional target reset # D6 J1-9 ADBUS6 (GPIOL2) # D7 J1-10 ADBUS7 (GPIOL3) # C0 J2-1 ACBUS0 (GPIOH0) # C1 J2-2 ACBUS1 (GPIOH1) # C2 J2-3 ACBUS2 (GPIOH2) # C3 J2-4 ACBUS3 (GPIOH3) # C4 J2-5 ACBUS4 (GPIOH4) # C5 J2-6 ACBUS5 (GPIOH5) # C6 J2-7 ACBUS6 (GPIOH6) # C7 J2-8 ACBUS7 (GPIOH7) # C8 J2-9 ACBUS8 # C9 J2-10 ACBUS9 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/gw16042.cfg ================================================ # # Gateworks GW16042 JTAG Dongle # # http://www.gateworks.com/ # # Layout: FTDI FT2232H # ADBUS0 TCK # ADBUS1 TDI # ADBUS2 TDO (input) # ADBUS3 TMS # ADBUS4 nTRST # ADBUS5 nSRST # ADBUS6 OE (active high) for TRST, TDI, TMS, TCK # ADBUS7 NC # ACBUS0-7 NC # BDBUS0 RXD # BDBUS1 TXD (input) # adapter driver ftdi ftdi device_desc "USB-JTAG" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0058 0x007b ftdi layout_signal nTRST -data 0x0010 ftdi layout_signal nSRST -oe 0x0020 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/hie-jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Hofstädtler Industrie-Electronic (HIE) JTAG Debugger # # https://www.hofstaedtler.com/jtag # adapter driver ftdi ftdi channel 0 ftdi vid_pid 0x0403 0x6014 ftdi device_desc "HIE JTAG Debugger" ftdi layout_init 0x0c08 0x4f1b # define both Reset signals ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 # Toggle USB LED ftdi layout_signal LED -ndata 0x4000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/hilscher_nxhx10_etm.cfg ================================================ # # Hilscher NXHX 10-ETM # # http://de.hilscher.com/products_details_hardware.html?p_id=P_4ce145a5983e6 # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "NXHX 10-ETM" ftdi vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/hilscher_nxhx500_etm.cfg ================================================ # # Hilscher NXHX 500-ETM # # http://de.hilscher.com/files_design/8/NXHX500-ETM_description_Rev01_EN.pdf # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "NXHX 500-ETM" ftdi vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/hilscher_nxhx500_re.cfg ================================================ # # Hilscher NXHX 500-RE # # http://de.hilscher.com/products_details_hardware.html?p_id=P_461ff2053bad1&bs=20 # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "NXHX 500-RE" ftdi vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/hilscher_nxhx50_etm.cfg ================================================ # # Hilscher NXHX 50-ETM # # http://de.hilscher.com/files_design/8/NXHX50-ETM_description_Rev01_EN.pdf # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "NXHX 50-ETM" ftdi vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/hilscher_nxhx50_re.cfg ================================================ # # Hilscher NXHX 50-RE # # http://de.hilscher.com/products_details_hardware.html?p_id=P_483c0f582ad36&bs=20 # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "NXHX50-RE" ftdi vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/hitex_lpc1768stick.cfg ================================================ # # Hitex LPC1768-Stick # # http://www.hitex.com/?id=1602 # adapter driver ftdi ftdi device_desc "LPC1768-Stick" ftdi vid_pid 0x0640 0x0026 ftdi layout_init 0x0388 0x038b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0080 -noe 0x200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/hitex_str9-comstick.cfg ================================================ # # Hitex STR9-comStick # # http://www.hitex.com/index.php?id=383 # adapter driver ftdi ftdi device_desc "STR9-comStick" ftdi vid_pid 0x0640 0x002c ftdi layout_init 0x0108 0x010b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0200 -oe 0x0200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/icebear.cfg ================================================ # # Section5 ICEBear # # http://section5.ch/icebear # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "ICEbear JTAG adapter" ftdi vid_pid 0x0403 0xc140 ftdi layout_init 0x0028 0x002b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0020 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/imx8mp-evk.cfg ================================================ # # Configuration file for NXP MC-IMX8MP-EVK on-board internal JTAG # # Using this interface requires enabling "remote mode" for the board using the # NXP bcu tool (see https://github.com/NXPmicro/bcu) # # bcu set_gpio remote_en 1 -board=imx8mpevk # # The REMOTE_EN gpio is accessible through the same FTDI adapter but it's # behind an I2C GPIO expander. # adapter driver ftdi ftdi vid_pid 0x0403 0x6011 ftdi channel 0 ftdi layout_init 0x00f8 0x000b ftdi layout_signal RESET_B -data 0x0010 -oe 0x0010 # Called SYS_nRST in schematics ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 ftdi layout_signal IO_nRST -data 0x0040 -oe 0x0040 ftdi layout_signal ONOFF_B -data 0x0080 -oe 0x0080 ftdi layout_signal GPIO1 -data 0x0100 -oe 0x0100 ftdi layout_signal GPIO2 -data 0x0200 -oe 0x0200 ftdi layout_signal GPIO3 -data 0x0400 -oe 0x0400 ftdi layout_signal GPIO4 -data 0x0800 -oe 0x0800 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/incircuit-icprog.cfg ================================================ # # In-Circuit's ICprog OpenOCD JTAG Adapter # https://shop.in-circuit.de/product_info.php?products_id=112 # # Schematics available at # http://wiki.in-circuit.de/images/0/06/610000158A_openocd.pdf # adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nSRST -noe 0x0400 -data 0x0800 ftdi layout_signal nTRST -noe 0x0100 -data 0x0200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/iotlab-usb.cfg ================================================ # # This is the integrated adapter as found on the IoT-LAB boards # https://github.com/iot-lab/iot-lab/wiki # adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/isodebug.cfg ================================================ # isodebug v1 # 5 kV isolated JTAG/SWD + UART adapter by Unjo AB adapter driver ftdi ftdi vid_pid 0x22b7 0x150d ftdi layout_init 0x0ff8 0xfffb ftdi layout_signal LED -ndata 0x0100 ftdi layout_signal nTRST -data 0x0200 ftdi layout_signal nSRST -noe 0x0400 ftdi layout_signal SWDIO_OE -data 0x0008 # Mode signals, either of these needs to be high to drive the JTAG/SWD pins. # The power-on state is low for both signals but the init setting above sets # JTAG_EN high. ftdi layout_signal SWD_EN -data 0x1000 ftdi layout_signal JTAG_EN -data 0x0800 # In SWD mode, the JTAG_EN signal doubles as SWO_EN_N which switches the # second FTDI channel UART RxD to the SWO pin instead of the separate RxD # pin. Note that the default init state has this pin high so when OpenOCD # starts in SWD mode, SWO is by default disabled. To enable SWO tracing, # issue the command 'ftdi set_signal SWO_EN 1' where tracing is configured. # To switch back to using the separate UART, SWO_EN needs to be disabled # before exiting OpenOCD, or the adapter replugged. ftdi layout_signal SWO_EN -nalias JTAG_EN ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/jtag-lock-pick_tiny_2.cfg ================================================ # # DISTORTEC JTAG-lock-pick Tiny 2 # # http://www.distortec.com # adapter driver ftdi ftdi device_desc "JTAG-lock-pick Tiny 2" ftdi vid_pid 0x0403 0x8220 ftdi layout_init 0x8c28 0xff3b ftdi layout_signal SWD_EN -ndata 0x0020 -oe 0x2000 ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ftdi layout_signal SWDIO_OE -ndata 0x1000 ftdi layout_signal LED -ndata 0x8000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/jtagkey.cfg ================================================ # # Amontec JTAGkey # # http://www.amontec.com/jtagkey.shtml # adapter driver ftdi ftdi device_desc "Amontec JTAGkey" ftdi vid_pid 0x0403 0xcff8 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/jtagkey2.cfg ================================================ # # Amontec JTAGkey2 # # http://www.amontec.com/jtagkey2.shtml # adapter driver ftdi ftdi device_desc "Amontec JTAGkey-2" ftdi vid_pid 0x0403 0xcff8 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/jtagkey2p.cfg ================================================ # # Amontec JTAGkey2P # # http://www.amontec.com/jtagkey2p.shtml # adapter driver ftdi ftdi device_desc "Amontec JTAGkey-2P" ftdi vid_pid 0x0403 0xcff8 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/kt-link.cfg ================================================ # # Kristech KT-Link # # http://www.kristech.eu # adapter driver ftdi ftdi device_desc "KT-LINK" ftdi vid_pid 0x0403 0xbbe2 ftdi layout_init 0x8c28 0xff3b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ftdi layout_signal LED -data 0x8000 ftdi layout_signal SWD_EN -ndata 0x0020 -oe 0x2000 ftdi layout_signal SWDIO_OE -ndata 0x1000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/lambdaconcept_ecpix-5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # This adapter is integrated in to LambdaConcept ECPIX-5 board: # interface/ftdi/lambdaconcept_ecpix-5.cfg # See schematics for the ftdi layout: # http://docs.lambdaconcept.com/ecpix-5/_static/resources/SCH_ECPIX-5_R02.PDF adapter driver ftdi adapter speed 10000 ftdi_device_desc "Dual RS232-HS" ftdi_vid_pid 0x0403 0x6010 ftdi_layout_init 0xfff8 0xfffb transport select jtag ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/lisa-l.cfg ================================================ # # Lisa/L # # http://paparazzi.enac.fr/wiki/Lisa # echo "WARNING!" echo "This file was not tested with real interface, it is based on schematics and code" echo "in ft2232.c. Please report your experience with this file to openocd-devel" echo "mailing list, so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "Lisa/L" ftdi vid_pid 0x0403 0x6010 ftdi channel 1 ftdi layout_init 0x0008 0x180b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 ftdi layout_signal LED -data 0x1800 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/luminary-icdi.cfg ================================================ # # Luminary Micro Stellaris LM3S9B9x Evaluation Kits # In-Circuit Debug Interface (ICDI) Board # # Essentially all Luminary debug hardware is the same, (with both # JTAG and SWD support compatible with ICDI boards. This ICDI adapter # configuration is JTAG-only, but the same hardware handles SWD too. # # This is a discrete ftdi based debug board which supports ARM's # JTAG/SWD connectors in both backwards-compatible 20-pin format and # in the new-style compact 10-pin. There's also an 8-pin connector # with serial port support. It's included with LM3S9B9x eval boards. # # http://www.luminarymicro.com/products/ek-lm3s9b90.html # http://www.luminarymicro.com/products/ek-lm3s9b92.html # adapter driver ftdi ftdi device_desc "Luminary Micro ICDI Board" ftdi vid_pid 0x0403 0xbcda ftdi layout_init 0x00a8 0x00eb ftdi layout_signal nSRST -noe 0x0020 ftdi layout_signal SWD_EN -ndata 0x0080 ftdi layout_signal SWDIO_OE -data 0x0008 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/luminary-lm3s811.cfg ================================================ # # Luminary Micro Stellaris LM3S811 Evaluation Kit # # http://www.luminarymicro.com/products/stellaris_811_evaluation_kits.html # # NOTE: this is only for boards *before* Rev C, which adds support # for SWO tracing with ADBUS_6 DBG_ENn and BDBUS_4 SWO_EN signals. # The "evb_lm3s811" layout doesn't set up those signals. # # Rev C boards work more like the other Stellaris eval boards. They # need to use the "luminary_icdi" layout to work correctly. # adapter driver ftdi ftdi device_desc "LM3S811 Evaluation Board" ftdi vid_pid 0x0403 0xbcd9 ftdi layout_init 0x0088 0x008b ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 ftdi layout_signal SWD_EN -ndata 0x0080 ftdi layout_signal SWDIO_OE -data 0x0008 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/luminary.cfg ================================================ # # Luminary Micro Stellaris Evaluation Kits # # http://www.luminarymicro.com/products/evaluation_kits.html # # There are a number of evaluation kits for Stellaris Cortex-M3 chips. # Currently they all bundle ftdi based debug support. When that is # used (instead of an external adapter), use this config file in one # of these two modes: # # - Eval board debug ... debug of the Stellaris chip via port A. # # - Other board debug ... same thing, but the board acts as a debug # adapter for another board (using a standard ARM JTAG connector). # The Stellaris chip stays in reset. # # Those support both JTAG and SWD. SWD is an ARM-only two-wire debug # protocol; in 2009, OpenOCD does not support SWD. # # Port B of the ftdi chip is normally used as a serial link to the # Stellaris chip. On most boards (but not older LM3S811 eval boards), # when SWD is used Port B may instead be used to read low-bandwidth # "SWO trace" data, including so-called "printf style" output from # firmware via the ITM module as well as profile data. # adapter driver ftdi ftdi device_desc "Stellaris Evaluation Board" ftdi vid_pid 0x0403 0xbcd9 ftdi layout_init 0x00a8 0x00eb ftdi layout_signal nSRST -noe 0x0020 ftdi layout_signal SWD_EN -ndata 0x0080 ftdi layout_signal SWDIO_OE -data 0x0008 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/m53evk.cfg ================================================ # # DENX M53EVK # # http://www.denx-cs.de/?q=M53EVK # adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi channel 0 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/mbftdi.cfg ================================================ # # MBFTDI # # http://www.marsohod.org/prodmbftdi # # Also the Marsohod2 and the Marsohod3 boards # include a built-in MBFTDI for FPGA programming. # See http://www.marsohod.org/prodmarsohod2 # and http://www.marsohod.org/plata-marsokhod3 for details. # adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x000b ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/minimodule-swd.cfg ================================================ # # Supports SWD using the FT2232H or FT4232H minimodule. # Each can support 2 SWD interfaces. # # FT2232H or FT4232H minimodule channel 0 (Channel A) # Connector FTDI Target # Pin Name # --------- ------ ------ # CN2-11 VIO VDD_IO (Or connect to CN2-5 on the minimodule instead for a 3V3 interface) # CN2-2 GND GND # CN2-7 ADBUS0 (TCK) SWCLK # CN2-9 ADBUS2 (TDI/TDO) SWDIO # CN2-10 ADBUS1 (TDO/TDI) SWDIO # CN2-14 ADBUS4 (GPIOL0) nRESET # # FT2232H minimodule channel 1 (Channel B) # FTDI Target # ---- ------ # CN2-11 - VDD_IO # CN2-2 - GND # CN3-26 - SWCLK # CN3-25 - SWDIO # CN3-24 - SWDIO # CN3-21 - nRESET # # FT4232H minimodule channel 1 (Channel B) # FTDI Target # ---- ------ # CN2-11 - VDD_IO # CN2-2 - GND # CN2-18 - SWCLK # CN2-17 - SWDIO # CN2-20 - SWDIO # CN2-22 - nRESET # adapter driver ftdi #Select your module type and channel #ftdi device_desc "FT2232H MiniModule" ftdi vid_pid 0x0403 0x6010 #ftdi channel 1 #ftdi device_desc "FT4232H MiniModule" #ftdi vid_pid 0x0403 0x6011 #ftdi channel 1 ftdi layout_init 0x0000 0x000b ftdi layout_signal nSRST -data 0x0010 -oe 0x0010 ftdi layout_signal SWD_EN -data 0 ftdi layout_signal SWDIO_OE -data 0 transport select swd ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/minimodule.cfg ================================================ # # FTDI MiniModule # # http://www.ftdichip.com/Support/Documents/DataSheets/Modules/DS_FT2232H_Mini_Module.pdf # adapter driver ftdi ftdi device_desc "FT2232H MiniModule" ftdi vid_pid 0x0403 0x6010 # Every pin set as high impedance except TCK, TDI, TDO and TMS ftdi layout_init 0x0008 0x000b # nSRST defined on pin CN2-13 of the MiniModule (pin ADBUS5 [AD5] on the FT2232H chip) # This choice is arbitrary. Use other GPIO pin if desired. ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/minispartan6.cfg ================================================ # https://www.scarabhardware.com/minispartan6/ # https://github.com/scarabhardware/miniSpartan6-plus/raw/master/miniSpartan6%2B_Rev_B.pdf adapter driver ftdi # The miniSpartan6+ sadly doesn't have a custom device description, so we just # have to hope you got it right. #ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 # interface 1 is the uart ftdi channel 0 # just TCK TDI TDO TMS, no reset ftdi layout_init 0x0008 0x000b reset_config none # this generally works fast: the fpga can handle 30MHz, the spi flash can handle # 54MHz with simple read, no dummy cycles, and wait-for-write-completion adapter speed 30000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/miniwiggler.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Infineon DAP miniWiggler V3 # # https://www.infineon.com/cms/en/product/evaluation-boards/kit_miniwiggler_3_usb/ # # Layout: FTDI FT2232 # ADBUS0 TCK # ADBUS1 TDI # ADBUS2 TDO # ADBUS3 TMS # ADBUS4 nOE (output enable) # ADBUS5 # ADBUS6 # ADBUS7 Blue LED # # ACBUS0 nTRST # ACBUS1 nSRST # ACUBS2 # ACBUS3 # ACBUS4 # ACBUS5 # ACBUS6 # ACBUS7 # adapter driver ftdi ftdi device_desc "DAS JDS miniWiggler V3.1" ftdi vid_pid 0x058b 0x0043 ftdi channel 0 ftdi layout_init 0x0008 0x001b ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 ftdi layout_signal nSRST -data 0x0200 -oe 0x0200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/neodb.cfg ================================================ # # Openmoko USB JTAG/RS232 adapter # # http://wiki.openmoko.org/wiki/Debug_Board_v3 # adapter driver ftdi ftdi device_desc "Debug Board for Neo1973" ftdi vid_pid 0x1457 0x5118 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 ftdi layout_signal nNOR_WP -data 0x0010 -oe 0x0010 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/ngxtech.cfg ================================================ # # NGX ARM USB JTAG # # http://shop.ngxtechnologies.com/product_info.php?cPath=26&products_id=30 # echo "WARNING!" echo "This file was not tested with real interface, but is assumed to work as this" echo "interface uses the same layout as configs that were verified. Please report your" echo "experience with this file to openocd-devel mailing list, so it could be marked" echo "as working or fixed." adapter driver ftdi ftdi device_desc "NGX JTAG" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/olimex-arm-jtag-swd.cfg ================================================ # # Olimex ARM JTAG SWD adapter # https://www.olimex.com/Products/ARM/JTAG/ARM-JTAG-SWD/ # transport select swd ftdi layout_signal SWD_EN -nalias nTRST ftdi layout_signal SWDIO_OE -alias TMS ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/olimex-arm-usb-ocd-h.cfg ================================================ # # Olimex ARM-USB-OCD-H # # http://www.olimex.com/dev/arm-usb-ocd-h.html # adapter driver ftdi ftdi device_desc "Olimex OpenOCD JTAG ARM-USB-OCD-H" ftdi vid_pid 0x15ba 0x002b ftdi layout_init 0x0908 0x0b1b ftdi layout_signal nSRST -oe 0x0200 ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal LED -data 0x0800 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/olimex-arm-usb-ocd.cfg ================================================ # # Olimex ARM-USB-OCD # # http://www.olimex.com/dev/arm-usb-ocd.html # adapter driver ftdi ftdi device_desc "Olimex OpenOCD JTAG" ftdi vid_pid 0x15ba 0x0003 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nSRST -oe 0x0200 ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal LED -data 0x0800 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/olimex-arm-usb-tiny-h.cfg ================================================ # # Olimex ARM-USB-TINY-H # # http://www.olimex.com/dev/arm-usb-tiny-h.html # adapter driver ftdi ftdi device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H" ftdi vid_pid 0x15ba 0x002a ftdi layout_init 0x0808 0x0a1b ftdi layout_signal nSRST -oe 0x0200 ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 ftdi layout_signal LED -data 0x0800 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/olimex-jtag-tiny.cfg ================================================ # # Olimex ARM-USB-TINY # # http://www.olimex.com/dev/arm-usb-tiny.html # adapter driver ftdi ftdi device_desc "Olimex OpenOCD JTAG TINY" ftdi vid_pid 0x15ba 0x0004 ftdi layout_init 0x0808 0x0a1b ftdi layout_signal nSRST -oe 0x0200 ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 ftdi layout_signal LED -data 0x0800 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/oocdlink.cfg ================================================ # # Joern Kaipf's OOCDLink # # http://www.joernonline.de/contrexx2/cms/index.php?page=126 # echo "WARNING!" echo "This file was not tested with real interface, but is assumed to work as this" echo "interface uses the same layout as configs that were verified. Please report your" echo "experience with this file to openocd-devel mailing list, so it could be marked" echo "as working or fixed." adapter driver ftdi ftdi device_desc "OOCDLink" ftdi vid_pid 0x0403 0xbaf8 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/opendous_ftdi.cfg ================================================ # # Opendous # # http://code.google.com/p/opendous/wiki/JTAG # # According to the website, it is similar to jtagkey, but it uses channel B # (and it has a different pid number). # adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi channel 1 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/openocd-usb-hs.cfg ================================================ # # embedded projects openocd usb adapter v3 # # http://shop.embedded-projects.net/index.php?module=artikel&action=artikel&id=14 # adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/openocd-usb.cfg ================================================ # # Hubert Hoegl's USB to JTAG # # http://www.hs-augsburg.de/~hhoegl/proj/usbjtag/usbjtag.html # adapter driver ftdi ftdi device_desc "Dual RS232" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/openrd.cfg ================================================ # # Marvell OpenRD # # http://www.marvell.com/products/embedded_processors/developer/kirkwood/openrd.jsp # adapter driver ftdi ftdi device_desc "OpenRD JTAGKey FT2232D B" ftdi vid_pid 0x0403 0x9e90 ftdi channel 0 ftdi layout_init 0x0608 0x0f1b ftdi layout_signal nTRST -data 0x0200 ftdi layout_signal nSRST -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/pipistrello.cfg ================================================ # http://pipistrello.saanlima.com/ # http://www.saanlima.com/download/pipistrello-v2.0/pipistrello_v2_schematic.pdf adapter driver ftdi ftdi device_desc "Pipistrello LX45" ftdi vid_pid 0x0403 0x6010 # interface 1 is the uart ftdi channel 0 # just TCK TDI TDO TMS, no reset ftdi layout_init 0x0008 0x000b reset_config none # this generally works fast: the fpga can handle 30MHz, the spi flash can handle # 54MHz with simple read, no dummy cycles, and wait-for-write-completion adapter speed 10000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/pls_spc5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # PLS SPC5-UDESTK # # https://www.st.com/en/development-tools/spc5-udestk.html # # Reference the SPC56D Discovery schematics. # # Layout: FTDI FT2232 # ADBUS0 TCK # ADBUS1 TDI # ADBUS2 TDO # ADBUS3 TMS # ADBUS4 TMS # ADBUS5 RTCK # ADBUS6 # ADBUS7 LED1 # # ACBUS0 nTRST # ACBUS1 nSRST (external pull-down) # ACUBS2 # ACBUS3 # ACBUS4 # ACBUS5 nSRST direction (input=L, output=H, external pull-down) # ACBUS6 TMS direction (input=L, output=H, external pull-up) # ACBUS7 LED2 # adapter driver ftdi ftdi device_desc "PLS USB/JTAG Adapter for SPC5xxx" ftdi vid_pid 0x263d 0x4001 ftdi channel 0 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 ftdi layout_signal nSRST -ndata 0x2000 -oe 0x2000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/redbee-econotag.cfg ================================================ # # Redwire Redbee-Econotag # # http://www.redwirellc.com/store/node/1 # # The Redbee-Econotag has an onboard FT2232H with: # - FT2232H channel A wired to mc13224v JTAG # - FT2232H channel B wired to mc13224v UART1 # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0c08 0x0c2b ftdi layout_signal nTRST -data 0x0800 ftdi layout_signal nSRST -data 0x0400 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/redbee-usb.cfg ================================================ # # Redwire Redbee-USB # # http://www.redwirellc.com # # The Redbee-USB has an onboard FT2232H with: # - FT2232H channel B wired to mc13224v JTAG # - FT2232H channel A wired to mc13224v UART1 # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi channel 1 ftdi layout_init 0x0c08 0x0c2b ftdi layout_signal nTRST -data 0x0800 ftdi layout_signal nSRST -data 0x0400 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/rowley-cc-arm-swd.cfg ================================================ # # Rowley ARM SWD Adapter # http://sites.fastspring.com/rowley/product/armswdadapter # https://drive.google.com/file/d/0Bzv7UpKpOQhnTUNNdzI5OUR4WGs/edit?usp=sharing # transport select swd ftdi layout_signal SWD_EN -nalias nTRST ftdi layout_signal SWDIO_OE -alias TMS ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/sheevaplug.cfg ================================================ # # Marvel SheevaPlug Development Kit # # http://www.marvell.com/products/embedded_processors/developer/kirkwood/sheevaplug.jsp # adapter driver ftdi ftdi device_desc "SheevaPlug JTAGKey FT2232D B" ftdi vid_pid 0x9e88 0x9e8f ftdi channel 0 ftdi layout_init 0x0608 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/signalyzer-lite.cfg ================================================ # # Xverve Signalyzer LITE (DT-USB-SLITE) # # http://www.signalyzer.com # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "Signalyzer LITE" ftdi vid_pid 0x0403 0xbca1 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/signalyzer.cfg ================================================ # # Xverve Signalyzer Tool (DT-USB-ST) # # http://www.signalyzer.com # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "Signalyzer" ftdi vid_pid 0x0403 0xbca0 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/snps_sdp.cfg ================================================ # Copyright (C) 2020 Synopsys, Inc. # Anton Kolesov # Didin Evgeniy # # SPDX-License-Identifier: GPL-2.0-or-later # # Synopsys SDP Mainboard has embdded FT2232 chip, which is similar to Digilent # HS-1, except that it uses channel B for JTAG communication, instead of # channel A. # adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0088 0x008b ftdi channel 1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/steppenprobe.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Steppenprobe # https://github.com/diegoherranz/steppenprobe # adapter driver ftdi ftdi vid_pid 0x0403 0x6010 # Initial Layout ftdi layout_init 0x0058 0x99fb # Signal Data Direction Notes # TCK 0 1 (out) # TDI 0 1 (out) # TDO 0 0 (in) # TMS 1 1 (out) JTAG IEEE std recommendation # LED 1 1 (out) LED off # SWD_EN 0 1 (out) OpenOCD sets this high for SWD # SWDIO_OE 1 1 (out) Ext. buffer tristated # SRST 0 1 (out) Translates to nSRST=Z # Unused 0 1 (out) # GPIO_A 0 0 (in) # GPIO_B 0 0 (in) # Unused 0 1 (out) # Unused 0 1 (out) # GPIO_C 0 0 (in) # GPIO_D 0 0 (in) # Unused 0 1 (out) # Signals definition ftdi layout_signal LED -ndata 0x0010 ftdi layout_signal SWD_EN -data 0x0020 ftdi layout_signal SWDIO_OE -ndata 0x0040 ftdi layout_signal nSRST -oe 0x0080 ftdi layout_signal GPIO_A -data 0x0200 -oe 0x0200 -input 0x0200 ftdi layout_signal GPIO_B -data 0x0400 -oe 0x0400 -input 0x0400 ftdi layout_signal GPIO_C -data 0x2000 -oe 0x2000 -input 0x2000 ftdi layout_signal GPIO_D -data 0x4000 -oe 0x4000 -input 0x4000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/stm32-stick.cfg ================================================ # # Hitex STM32-PerformanceStick # # http://www.hitex.com/index.php?id=340 # adapter driver ftdi ftdi device_desc "STM32-PerformanceStick" ftdi vid_pid 0x0640 0x002d ftdi layout_init 0x0388 0x038b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0080 -noe 0x200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/swd-resistor-hack.cfg ================================================ # # Connect TDI to SWDIO via a suitable series resistor (220-470 Ohm or # so depending on the drive capability of the target and adapter); # connect TDO directly to SWDIO. # # You also need to have reliable GND connection between the target and # adapter. Vref of the adapter should be supplied with a voltage equal # to the target's (preferably connect it to Vcc). You can also # optionally connect nSRST. Leave everything else unconnected. # # FTDI Target # ---- ------ # 1 - Vref ----------------- Vcc # 3 - nTRST - # 4 - GND ----------------- GND # 5 - TDI ---/\470 Ohm/\--- SWDIO # 7 - TMS - # 9 - TCK ----------------- SWCLK # 11 - RTCK - # 13 - TDO ----------------- SWDIO # 15 - nSRST - - - - - - - - - nRESET # transport select swd ftdi layout_signal SWD_EN -data 0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/ti-icdi.cfg ================================================ # # This is an FTDI-based debugging solution as found on some TI boards, # e.g. CC3200 LaunchPad. # # The schematics are identical to luminary-icdi (including SWD # support) but the USB IDs are different. # adapter driver ftdi ftdi vid_pid 0x0451 0xc32a ftdi layout_init 0x00a8 0x00eb ftdi layout_signal nSRST -noe 0x0020 ftdi layout_signal SWD_EN -ndata 0x0080 ftdi layout_signal SWDIO_OE -data 0x0008 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/tigard.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Tigard: An FTDI FT2232H-based multi-protocol tool for hardware hacking. # https://github.com/tigard-tools/tigard adapter driver ftdi ftdi device_desc "Tigard V1.1" ftdi vid_pid 0x0403 0x6010 ftdi channel 1 ftdi layout_init 0x0038 0x003b ftdi layout_signal nTRST -data 0x0010 ftdi layout_signal nSRST -data 0x0020 # This board doesn't support open-drain reset modes since its output buffer is # always enabled. reset_config srst_push_pull trst_push_pull ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/tumpa-lite.cfg ================================================ # # TIAO USB Multi-Protocol Adapter (TUMPA) Lite # # http://www.diygadget.com/tiao-usb-multi-protocol-adapter-lite-jtag-spi-i2c-serial.html # adapter driver ftdi ftdi vid_pid 0x0403 0x8a99 ftdi layout_init 0x0038 0x087b ftdi layout_signal nTRST -data 0x0020 -oe 0x0020 ftdi layout_signal nSRST -data 0x0010 -oe 0x0010 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/tumpa.cfg ================================================ # # TIAO USB Multi-Protocol Adapter (TUMPA) # # http://www.diygadget.com/tiao-usb-multi-protocol-adapter-jtag-spi-i2c-serial.html # adapter driver ftdi ftdi vid_pid 0x0403 0x8a98 0x0403 0x6010 ftdi layout_init 0x0038 0x087b ftdi layout_signal nTRST -data 0x0020 ftdi layout_signal nSRST -data 0x0010 reset_config srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/turtelizer2-revB.cfg ================================================ # # egnite Turtelizer 2 rev B (with SRST only) # # http://www.ethernut.de/en/hardware/turtelizer/index.html # echo "WARNING!" echo "This file was not tested with real interface, it is based on schematics and code" echo "in ft2232.c. Please report your experience with this file to openocd-devel" echo "mailing list, so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "Turtelizer JTAG/RS232 Adapter" ftdi vid_pid 0x0403 0xbdc8 ftdi layout_init 0x0008 0x0c5b ftdi layout_signal nSRST -oe 0x0040 ftdi layout_signal LED -data 0x0c00 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/turtelizer2-revC.cfg ================================================ # # egnite Turtelizer 2 revC (with TRST and SRST) # # http://www.ethernut.de/en/hardware/turtelizer/index.html # adapter driver ftdi ftdi device_desc "Turtelizer JTAG/RS232 Adapter" ftdi vid_pid 0x0403 0xbdc8 ftdi layout_init 0x0008 0x0c7b ftdi layout_signal nTRST -oe 0x0020 ftdi layout_signal nSRST -oe 0x0040 ftdi layout_signal LED -ndata 0x0c00 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/um232h.cfg ================================================ # # FTDI UM232H as a JTAG interface # # http://www.ftdichip.com/Products/Modules/DevelopmentModules.htm#UM232H # # This should also work with a UM232H-B, but that has not been tested. # Note that UM232H and UM232H-B are 3.3V only. # adapter driver ftdi #ftdi device_desc "UM232H" ftdi vid_pid 0x0403 0x6014 ftdi layout_init 0xfff8 0xfffb ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 ftdi layout_signal nSRST -data 0x0200 -oe 0x0200 # UM232H FT232H JTAG # Name Pin Name Func # AD0 J2-6 ADBUS0 TCK # AD1 J2-7 ADBUS1 TDI # AD2 J2-8 ADBUS2 TDO # AD3 J2-9 ADBUS3 TMS # AD4 J2-10 ADBUS4 (GPIOL0) # AD5 J2-11 ADBUS5 (GPIOL1) # AD6 J2-12 ADBUS6 (GPIOL2) # AD7 J2-13 ADBUS7 (GPIOL3) # AD0 J1-14 ACBUS0 /TRST # AD1 J1-13 ACBUS1 /SRST # AD2 J1-12 ACBUS2 (GPIOH2) # AD3 J1-11 ACBUS3 (GPIOH3) # AD4 J1-10 ACBUS4 (GPIOH4) # AD5 J1-9 ACBUS5 (GPIOH5) # AD6 J1-8 ACBUS6 (GPIOH6) # AD7 J1-7 ACBUS7 (GPIOH7) ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/vpaclink.cfg ================================================ # # Voipac VPACLink # # http://voipac.com/27M-JTG-000 # echo "WARNING!" echo "This file was not tested with real interface, but is assumed to work as this" echo "interface uses the same layout as configs that were verified. Please report your" echo "experience with this file to openocd-devel mailing list, so it could be marked" echo "as working or fixed." adapter driver ftdi ftdi device_desc "VPACLink" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/xds100v2.cfg ================================================ # # Texas Instruments XDS100v2 # # http://processors.wiki.ti.com/index.php/XDS100#XDS100v2_Features # # Detailed documentation is available only as CPLD verilog source code # to the registered TI users. # adapter driver ftdi ftdi vid_pid 0x0403 0xa6d0 0x0403 0x6010 ftdi layout_init 0x0038 0x597b # 8000 z - unused # 4000 0 > CPLD loopback (all target side pins high-Z) # 2000 z < !( cable connected ) (open drain on CPLD side for $reasons) # 1000 0 > EMU1_oe # # 800 0 > PWR_RST = clear power-loss flag on rising edge # 400 z < !( power-loss flag ) # 200 z < nSRST # 100 0 > nSRST_oe # # 80 z < RTCK # 40 0 > EMU0_oe # 20 1 > EMU_EN # 10 1 > nTRST # # 8 1 > TMS # 4 z < TDO # 2 0 > TDI # 1 0 > TCK # # As long as the power-loss flag is set, all target-side pins are # high-Z except the EMU-pins for which the opposite holds unless # EMU_EN is high. # # To use wait-in-reset, drive EMU0 low at power-on reset. If the # target normally reuses EMU0 for other purposes, clear EMU_EN to # keep the EMU pins high-Z until the target is power-cycled. # # The LED only turns off at USB suspend, which is also the only way to # set the power-loss flag manually. (Can be done in software e.g. by # changing the USB configuration to zero.) # ftdi layout_signal nTRST -data 0x0010 ftdi layout_signal nSRST -oe 0x0100 ftdi layout_signal EMU_EN -data 0x0020 ftdi layout_signal EMU0 -oe 0x0040 ftdi layout_signal EMU1 -oe 0x1000 ftdi layout_signal PWR_RST -data 0x0800 ftdi layout_signal LOOPBACK -data 0x4000 echo "\nInfo : to use this adapter you MUST add ``init; ftdi set_signal PWR_RST 1; jtag arp_init'' to the end of your config file!\n" # note: rising edge on PWR_RST is also needed after power-cycling the # target ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ftdi/xds100v3.cfg ================================================ # # Texas Instruments XDS100 ver 3.0 # # http://processors.wiki.ti.com/index.php/XDS100 # # Version 3.0 is the same as 2.0 as far as OpenOCD is concerned source [find interface/ftdi/xds100v2.cfg] # The USB ids are different. ftdi vid_pid 0x0403 0xa6d1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/imx-native.cfg ================================================ # # Config for using NXP IMX CPU # # This is best used with a fast enough buffer but also # is suitable for direct connection if the target voltage # matches to host voltage and the cable is short enough. # # adapter driver imx_gpio # For most IMX processors 0x0209c000 imx_gpio_peripheral_base 0x0209c000 # Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET # These depend on system clock, calibrated for IMX6UL@528MHz # imx_gpio_speed SPEED_COEFF SPEED_OFFSET imx_gpio_speed_coeffs 50000 50 # Each of the JTAG lines need a gpio number set: tck tms tdi tdo. # Example configuration: # imx_gpio_jtag_nums 6 7 8 9 # SWD interface pins: swclk swdio # Example configuration: imx_gpio_swd_nums 1 6 # imx_gpio_trst_num 10 # reset_config trst_only # imx_gpio_srst_num 11 # reset_config srst_only srst_push_pull # or if you have both connected, # reset_config trst_and_srst srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/jlink.cfg ================================================ # # SEGGER J-Link # # http://www.segger.com/jlink.html # adapter driver jlink # The serial number can be used to select a specific device in case more than # one is connected to the host. # # Example: Select J-Link with serial number 123456789 # # adapter serial 123456789 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/jtag_dpi.cfg ================================================ # # Provide support for the Cadence JTAG BFM # # Copyright (c) 2020, Ampere Computing LLC # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; # # adapter driver jtag_dpi # Set the DPI JTAG server port if { [info exists DPI_PORT] } { set _DPI_PORT $DPI_PORT } else { set _DPI_PORT 5555 } # Set the DPI JTAG server address if { [info exists DPI_ADDRESS] } { set _DPI_ADDRESS $DPI_ADDRESS } else { set _DPI_ADDRESS "127.0.0.1" } jtag_dpi set_port $_DPI_PORT jtag_dpi set_address $_DPI_ADDRESS ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/jtag_hat_rpi2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Blinkinlabs JTAG_Hat # # https://github.com/blinkinlabs/jtag_hat # adapter driver bcm2835gpio bcm2835gpio_peripheral_base 0x3F000000 # Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET # These depend on system clock, calibrated for stock 700MHz # bcm2835gpio_speed SPEED_COEFF SPEED_OFFSET bcm2835gpio_speed_coeffs 146203 36 # Each of the JTAG lines need a gpio number set: tck tms tdi tdo # Header pin numbers: 23 22 19 21 bcm2835gpio_jtag_nums 11 25 10 9 # Each of the SWD lines need a gpio number set: swclk swdio # Header pin numbers: 23 22 bcm2835gpio_swd_nums 11 25 # Direction pin for SWDIO level shifting buffer bcm2835gpio_swdio_dir_num 6 # If you define trst or srst, use appropriate reset_config # Header pin numbers: TRST - 26, SRST - 18 bcm2835gpio_trst_num 7 #reset_config trst_only bcm2835gpio_srst_num 24 #reset_config srst_only # or if you have both connected #reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/jtag_vpi.cfg ================================================ adapter driver jtag_vpi # Set the VPI JTAG server port if { [info exists VPI_PORT] } { set _VPI_PORT $VPI_PORT } else { set _VPI_PORT 5555 } # Set the VPI JTAG server address if { [info exists VPI_ADDRESS] } { set _VPI_ADDRESS $VPI_ADDRESS } else { set _VPI_ADDRESS "127.0.0.1" } jtag_vpi set_port $_VPI_PORT jtag_vpi set_address $_VPI_ADDRESS ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/kitprog.cfg ================================================ # # Cypress Semiconductor KitProg # # Note: This is the driver for the proprietary KitPtog protocol. If the # KitProg is in CMSIS-DAP mode, you should either use the cmsis-dap # interface driver or switch the KitProg to KitProg mode. # adapter driver kitprog # Optionally specify the serial number of the KitProg you want to use. # adapter serial 1926402735485200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/nds32-aice.cfg ================================================ # # Andes AICE # # http://www.andestech.com # adapter driver aice aice desc "Andes AICE adapter" # adapter serial "C001-42163" aice vid_pid 0x1CFC 0x0000 aice port aice_usb reset_config trst_and_srst adapter speed 24000 aice retry_times 50 aice count_to_check_dbger 30 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/nulink.cfg ================================================ # # Nuvoton Nu-Link in-circuit debugger/programmer # adapter driver hla hla_layout nulink hla_device_desc "Nu-Link" hla_vid_pid 0x0416 0x511b 0x0416 0x511c 0x0416 0x511d 0x0416 0x5200 0x0416 0x5201 # Only swd is supported transport select hla_swd ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/opendous.cfg ================================================ # # opendous-jtag # # http://code.google.com/p/opendous-jtag/ # adapter driver opendous ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/openjtag.cfg ================================================ # # OpenJTAG # # www.openjtag.org # adapter driver openjtag openjtag device_desc "Open JTAG Project" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/osbdm.cfg ================================================ # # P&E Micro OSBDM (aka OSJTAG) interface # # http://pemicro.com/osbdm/ # adapter driver osbdm reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/parport.cfg ================================================ # # Parallel port wiggler (many clones available) on port 0x378 # # Addresses: 0x378/LPT1 or 0x278/LPT2 ... # if { [info exists PARPORTADDR] } { set _PARPORTADDR $PARPORTADDR } else { if {$tcl_platform(platform) eq "windows"} { set _PARPORTADDR 0x378 } { set _PARPORTADDR 0 } } adapter driver parport parport port $_PARPORTADDR parport cable wiggler ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/parport_dlc5.cfg ================================================ # # Xilinx Parallel Cable III 'DLC 5' (and various clones) # # http://www.xilinx.com/itp/xilinx4/data/docs/pac/appendixb.html # if { [info exists PARPORTADDR] } { set _PARPORTADDR $PARPORTADDR } else { set _PARPORTADDR 0 } adapter driver parport parport port $_PARPORTADDR parport cable dlc5 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/raspberrypi-native.cfg ================================================ # # Config for using Raspberry Pi's expansion header # # This is best used with a fast enough buffer but also # is suitable for direct connection if the target voltage # matches RPi's 3.3V and the cable is short enough. # # Do not forget the GND connection, pin 6 of the expansion header. # adapter driver bcm2835gpio bcm2835gpio peripheral_base 0x20000000 # Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET # These depend on system clock, calibrated for stock 700MHz # bcm2835gpio speed SPEED_COEFF SPEED_OFFSET bcm2835gpio speed_coeffs 113714 28 # Each of the JTAG lines need a gpio number set: tck tms tdi tdo # Header pin numbers: 23 22 19 21 bcm2835gpio jtag_nums 11 25 10 9 # Each of the SWD lines need a gpio number set: swclk swdio # Header pin numbers: 23 22 bcm2835gpio swd_nums 11 25 # If you define trst or srst, use appropriate reset_config # Header pin numbers: TRST - 26, SRST - 18 # bcm2835gpio trst_num 7 # reset_config trst_only # bcm2835gpio srst_num 24 # reset_config srst_only srst_push_pull # or if you have both connected, # reset_config trst_and_srst srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/raspberrypi2-native.cfg ================================================ # # Config for using Raspberry Pi's expansion header # # This is best used with a fast enough buffer but also # is suitable for direct connection if the target voltage # matches RPi's 3.3V and the cable is short enough. # # Do not forget the GND connection, pin 6 of the expansion header. # adapter driver bcm2835gpio bcm2835gpio peripheral_base 0x3F000000 # Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET # These depend on system clock, calibrated for stock 700MHz # bcm2835gpio speed SPEED_COEFF SPEED_OFFSET bcm2835gpio speed_coeffs 146203 36 # Each of the JTAG lines need a gpio number set: tck tms tdi tdo # Header pin numbers: 23 22 19 21 bcm2835gpio jtag_nums 11 25 10 9 # Each of the SWD lines need a gpio number set: swclk swdio # Header pin numbers: 23 22 bcm2835gpio swd_nums 11 25 # If you define trst or srst, use appropriate reset_config # Header pin numbers: TRST - 26, SRST - 18 # bcm2835gpio trst_num 7 # reset_config trst_only # bcm2835gpio srst_num 24 # reset_config srst_only srst_push_pull # or if you have both connected, # reset_config trst_and_srst srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/rlink.cfg ================================================ # # Raisonance RLink # # http://www.mcu-raisonance.com/~rlink-debugger-programmer__microcontrollers__tool~tool__T018:4cn9ziz4bnx6.html # adapter driver rlink ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/rshim.cfg ================================================ # # BlueField SoC in-circuit debugger/programmer # adapter driver rshim transport select dapdirect_swd ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/stlink-dap.cfg ================================================ # # STMicroelectronics ST-LINK/V1, ST-LINK/V2, ST-LINK/V2-1, STLINK-V3 in-circuit # debugger/programmer # # This new interface driver creates a ST-Link wrapper for ARM-DAP named "dapdirect" # Old ST-LINK/V1 and ST-LINK/V2 pre version V2J24 don't support "dapdirect" # # SWIM transport is natively supported # adapter driver st-link st-link vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 # transport select dapdirect_jtag # transport select dapdirect_swd # transport select swim # Optionally specify the serial number of usb device # e.g. # adapter serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/stlink-v1.cfg ================================================ echo "WARNING: interface/stlink-v1.cfg is deprecated, please switch to interface/stlink.cfg" source [find interface/stlink.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/stlink-v2-1.cfg ================================================ echo "WARNING: interface/stlink-v2-1.cfg is deprecated, please switch to interface/stlink.cfg" source [find interface/stlink.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/stlink-v2.cfg ================================================ echo "WARNING: interface/stlink-v2.cfg is deprecated, please switch to interface/stlink.cfg" source [find interface/stlink.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/stlink.cfg ================================================ # # STMicroelectronics ST-LINK/V1, ST-LINK/V2, ST-LINK/V2-1, STLINK-V3 in-circuit # debugger/programmer # adapter driver hla hla_layout stlink hla_device_desc "ST-LINK" hla_vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 # Optionally specify the serial number of ST-LINK/V2 usb device. ST-LINK/V2 # devices seem to have serial numbers with unreadable characters. ST-LINK/V2 # firmware version >= V2.J21.S4 recommended to avoid issues with adapter serial # number reset issues. # eg. # adapter serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/sysfsgpio-raspberrypi.cfg ================================================ # # Config for using RaspberryPi's expansion header # # This is best used with a fast enough buffer but also # is suitable for direct connection if the target voltage # matches RPi's 3.3V # # Do not forget the GND connection, pin 6 of the expansion header. # adapter driver sysfsgpio # Each of the JTAG lines need a gpio number set: tck tms tdi tdo # Header pin numbers: 23 22 19 21 sysfsgpio jtag_nums 11 25 10 9 # Each of the SWD lines need a gpio number set: swclk swdio # Header pin numbers: 23 22 sysfsgpio swd_nums 11 25 # If you define trst or srst, use appropriate reset_config # Header pin numbers: TRST - 26, SRST - 18 # sysfsgpio trst_num 7 # reset_config trst_only # sysfsgpio srst_num 24 # reset_config srst_only srst_push_pull # or if you have both connected, # reset_config trst_and_srst srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ti-icdi.cfg ================================================ # # TI Stellaris In-Circuit Debug Interface (ICDI) Board # # This is the propriety ICDI interface used on newer boards such as # LM4F232 Evaluation Kit - http://www.ti.com/tool/ek-lm4f232 # Stellaris Launchpad - http://www.ti.com/stellaris-launchpad # http://www.ti.com/tool/ek-lm4f232 # adapter driver hla hla_layout ti-icdi hla_vid_pid 0x1cbe 0x00fd # Optionally specify the serial number of TI-ICDI devices, for when using # multiple devices. Serial numbers can be obtained using lsusb -v # Ex. # adapter serial "0F003065" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/ulink.cfg ================================================ # # Keil ULINK running OpenULINK firmware. # # http://www.keil.com/ulink1/ # http://article.gmane.org/gmane.comp.debugging.openocd.devel/17362 # adapter driver ulink ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/usb-jtag.cfg ================================================ # ixo-usb-jtag - Emulation of a Altera Bus Blaster I on a Cypress FX2 IC. # # The ixo-usb-jtag firmware can be loaded onto a bunch of different hardware # including; # * Xilinx USB Platform Cable # * Many Digilent boards such as the Nexys, Nexys 2 and Atlys boards # * Many fpga4fun.com boards from such as the Saxo and Xylo boards # * The Numato Opsis # # Original version - http://www.ixo.de/info/usb_jtag/ # Updated version - http://ixo-jtag.sourceforge.net/ # Newest version - http://github.com/mithro/ixo-usb-jtag # # Procedure for using is; # * Get the ixo-usb-jtag firmware for your hardware (or build it yourself). # * Load the firmware using the fxload tool. # * Use openocd. # # Unless you burn the firmware into the EEPROM on your device, power cycling # will require you to reload the firmware using the fxload tool. This can be # automated by using udev rules (which can be found in the firmware # repository). # # Ubuntu packages built from mithro's version (with prebuilt firmware and udev # rules) can be found at # https://launchpad.net/~timvideos/+archive/ubuntu/fpga-support # # TODO: Refactor the usb_blaster driver to allow loading firmware using any low # level driver. Loading firmware is currently only supported on the ublast2 # driver but ixo-usb-jtag requires the ftdi driver. adapter driver usb_blaster usb_blaster vid_pid 0x16C0 0x06AD usb_blaster device_desc "Van Ooijen Technische Informatica" # ixo-usb-jtag is only compatible with the ublast1 protocol implemented via the # ftdi modes, using ublast2 will cause openocd to hang. usb_blaster lowlevel_driver ftdi ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/usbprog.cfg ================================================ # # Embedded Projects USBprog # # http://embedded-projects.net/index.php?page_id=135 # adapter driver usbprog # USBprog is broken w/short TMS sequences, this is a workaround # until the C code can be fixed. tms_sequence long ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/vdebug.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface if { [info exists VDEBUGHOST] } { set _VDEBUGHOST $VDEBUGHOST } else { set _VDEBUGHOST localhost } if { [info exists VDEBUGPORT] } { set _VDEBUGPORT $VDEBUGPORT } else { set _VDEBUGPORT 8192 } adapter driver vdebug # vdebug server:port vdebug server $_VDEBUGHOST:$_VDEBUGPORT # example config debug level and log #debug_level 3 #log_output vd_ocd.log # example config listen on all interfaces, disable tcl/telnet server bindto 0.0.0.0 #gdb_port 3333 #telnet_port disabled tcl_port disabled # transaction batching: 0 - no batching, 1 - (default) wr, 2 - rw vdebug batching 1 # Polling values vdebug polling 100 1000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/vsllink.cfg ================================================ # # Versaloon Link -- VSLLink # # http://www.versaloon.com/ # adapter driver vsllink ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/interface/xds110.cfg ================================================ # # Texas Instruments XDS110 # # http://processors.wiki.ti.com/index.php/XDS110 # http://processors.wiki.ti.com/index.php/Emulation_Software_Package#XDS110_Support_Utilities # adapter driver xds110 # Use serial number option to use a specific XDS110 # when more than one are connected to the host. # adapter serial 00000000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/mem_helper.tcl ================================================ # Helper for common memory read/modify/write procedures # mrw: "memory read word", returns value of $reg proc mrw {reg} { return [read_memory $reg 32 1] } add_usage_text mrw "address" add_help_text mrw "Returns value of word in memory." # mrh: "memory read halfword", returns value of $reg proc mrh {reg} { return [read_memory $reg 16 1] } add_usage_text mrh "address" add_help_text mrh "Returns value of halfword in memory." # mrb: "memory read byte", returns value of $reg proc mrb {reg} { return [read_memory $reg 8 1] } add_usage_text mrb "address" add_help_text mrb "Returns value of byte in memory." # mmw: "memory modify word", updates value of $reg # $reg <== ((value & ~$clearbits) | $setbits) proc mmw {reg setbits clearbits} { set old [mrw $reg] set new [expr {($old & ~$clearbits) | $setbits}] mww $reg $new } add_usage_text mmw "address setbits clearbits" add_help_text mmw "Modify word in memory. new_val = (old_val & ~clearbits) | setbits;" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/memory.tcl ================================================ # MEMORY # # All Memory regions have two components. # (1) A count of regions, in the form N_NAME # (2) An array within info about each region. # # The ARRAY # # ( RegionNumber , ATTRIBUTE ) # # Where is one of: # # N_FLASH & FLASH (internal memory) # N_RAM & RAM (internal memory) # N_MMREGS & MMREGS (for memory mapped registers) # N_XMEM & XMEM (off chip memory, ie: flash on cs0, sdram on cs2) # or N_UNKNOWN & UNKNOWN for things that do not exist. # # We have 1 unknown region. set N_UNKNOWN 1 # All MEMORY regions must have these attributes # CS - chip select (if internal, use -1) set UNKNOWN(0,CHIPSELECT) -1 # BASE - base address in memory set UNKNOWN(0,BASE) 0 # LEN - length in bytes set UNKNOWN(0,LEN) $CPU_MAX_ADDRESS # HUMAN - human name of the region set UNKNOWN(0,HUMAN) "unknown" # TYPE - one of: # flash, ram, mmr, unknown # For harvard arch: # iflash, dflash, iram, dram set UNKNOWN(0,TYPE) "unknown" # RWX - access ablity # unix style chmod bits # 0 - no access # 1 - execute # 2 - write # 4 - read # hence: 7 - readwrite execute set RWX_NO_ACCESS 0 set RWX_X_ONLY $BIT0 set RWX_W_ONLY $BIT1 set RWX_R_ONLY $BIT2 set RWX_RW [expr {$RWX_R_ONLY + $RWX_W_ONLY}] set RWX_R_X [expr {$RWX_R_ONLY + $RWX_X_ONLY}] set RWX_RWX [expr {$RWX_R_ONLY + $RWX_W_ONLY + $RWX_X_ONLY}] set UNKNOWN(0,RWX) $RWX_NO_ACCESS # WIDTH - access width # 8,16,32 [0 means ANY] set ACCESS_WIDTH_NONE 0 set ACCESS_WIDTH_8 $BIT0 set ACCESS_WIDTH_16 $BIT1 set ACCESS_WIDTH_32 $BIT2 set ACCESS_WIDTH_ANY [expr {$ACCESS_WIDTH_8 + $ACCESS_WIDTH_16 + $ACCESS_WIDTH_32}] set UNKNOWN(0,ACCESS_WIDTH) $ACCESS_WIDTH_NONE proc iswithin { ADDRESS BASE LEN } { return [expr {(($ADDRESS - $BASE) >= 0) && (($BASE + $LEN - $ADDRESS) > 0)}] } proc address_info { ADDRESS } { foreach WHERE { FLASH RAM MMREGS XMEM UNKNOWN } { if { info exists $WHERE } { set lmt [set N_[set WHERE]] for { set region 0 } { $region < $lmt } { incr region } { if { iswithin $ADDRESS $WHERE($region,BASE) $WHERE($region,LEN) } { return "$WHERE $region"; } } } } # Return the 'unknown' return "UNKNOWN 0" } proc memread32 {ADDR} { if ![ catch { set foo [read_memory $ADDR 32 1] } msg ] { return $foo } else { error "memread32: $msg" } } proc memread16 {ADDR} { if ![ catch { set foo [read_memory $ADDR 16 1] } msg ] { return $foo } else { error "memread16: $msg" } } proc memread8 {ADDR} { if ![ catch { set foo [read_memory $ADDR 8 1] } msg ] { return $foo } else { error "memread8: $msg" } } proc memwrite32 {ADDR DATA} { if ![ catch { write_memory $ADDR 32 $DATA } msg ] { return $DATA } else { error "memwrite32: $msg" } } proc memwrite16 {ADDR DATA} { if ![ catch { write_memory $ADDR 16 $DATA } msg ] { return $DATA } else { error "memwrite16: $msg" } } proc memwrite8 {ADDR DATA} { if ![ catch { write_memory $ADDR 8 $DATA } msg ] { return $DATA } else { error "memwrite8: $msg" } } proc memread32_phys {ADDR} { if ![ catch { set foo [read_memory $ADDR 32 1 phys] } msg ] { return $foo } else { error "memread32: $msg" } } proc memread16_phys {ADDR} { if ![ catch { set foo [read_memory $ADDR 16 1 phys] } msg ] { return $foo } else { error "memread16: $msg" } } proc memread8_phys {ADDR} { if ![ catch { set foo [read_memory $ADDR 8 1 phys] } msg ] { return $foo } else { error "memread8: $msg" } } proc memwrite32_phys {ADDR DATA} { if ![ catch { write_memory $ADDR 32 $DATA phys } msg ] { return $DATA } else { error "memwrite32: $msg" } } proc memwrite16_phys {ADDR DATA} { if ![ catch { write_memory $ADDR 16 $DATA phys } msg ] { return $DATA } else { error "memwrite16: $msg" } } proc memwrite8_phys {ADDR DATA} { if ![ catch { write_memory $ADDR 8 $DATA phys } msg ] { return $DATA } else { error "memwrite8: $msg" } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/mmr_helpers.tcl ================================================ proc proc_exists { NAME } { set n [info commands $NAME] set l [string length $n] return [expr {$l != 0}] } # Give: REGISTER name - must be a global variable. proc show_mmr32_reg { NAME } { global $NAME # we want $($NAME) set a [set [set NAME]] if ![catch { set v [memread32 $a] } msg ] { echo [format "%15s: (0x%08x): 0x%08x" $NAME $a $v] # Was a helper defined? set fn show_${NAME}_helper if [ proc_exists $fn ] { # Then call it $fn $NAME $a $v } return $v; } else { error [format "%s (%s)" $msg $NAME ] } } # Give: NAMES - an array of names accessible # in the callers symbol-scope. # VAL - the bits to display. proc show_mmr32_bits { NAMES VAL } { upvar $NAMES MYNAMES set w 5 foreach {IDX N} $MYNAMES { set l [string length $N] if { $l > $w } { set w $l } } for { set x 24 } { $x >= 0 } { incr x -8 } { echo -n " " for { set y 7 } { $y >= 0 } { incr y -1 } { set s $MYNAMES([expr {$x + $y}]) echo -n [format "%2d: %-*s | " [expr {$x + $y}] $w $s ] } echo "" echo -n " " for { set y 7 } { $y >= 0 } { incr y -1 } { echo -n [format " %d%*s | " [expr {!!($VAL & (1 << ($x + $y)))}] [expr {$w -1}] ""] } echo "" } } proc show_mmr_bitfield { MSB LSB VAL FIELDNAME FIELDVALUES } { set width [expr {(($MSB - $LSB + 1) + 7) / 4}] set nval [show_normalize_bitfield $VAL $MSB $LSB ] set name0 [lindex $FIELDVALUES 0 ] if [ string compare $name0 _NUMBER_ ] { set sval [lindex $FIELDVALUES $nval] } else { set sval "" } echo [format "%-15s: %d (0x%0*x) %s" $FIELDNAME $nval $width $nval $sval ] } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/1986ве1т.cfg ================================================ # 1986ВЕ1Т # http://milandr.ru/index.php?mact=Products,cntnt01,details,0&cntnt01productid=236&cntnt01returnid=68 source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME 1986ве1т } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x4ba00477 } { # SWD IDCODE set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # use AHB-Lite SRAM for work area $_TARGETNAME configure -work-area-phys 0x20100000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # can't handle overlapping memory regions if { [info exists IMEMORY] && [string equal $IMEMORY true] } { flash bank ${_CHIPNAME}_info.flash mdr 0x00000000 0x01000 0 0 $_TARGETNAME 1 1 4 } else { flash bank $_CHIPNAME.flash mdr 0x00000000 0x20000 0 0 $_TARGETNAME 0 32 4 } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz adapter speed 1000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/adsp-sc58x.cfg ================================================ # # Analog Devices ADSP-SC58x (ARM Cortex-A5 plus one or two SHARC+ DSPs) # # Evaluation boards by Analog Devices (and designs derived from them) use a # non-standard 10-pin 0.05" ARM Cortex Debug Connector. In this bastardized # implementation, pin 9 (GND or GNDDetect) has been usurped with JTAG /TRST. # # As a result, a standards-compliant debug pod will force /TRST active, # putting the processor's debug interface into reset and preventing usage. # # A connector adapter must be employed on these boards to isolate or remap # /TRST so that it is only asserted when intended. source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ADSP-SC58x } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3BA02477 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create ap0.mem mem_ap -dap $_CHIPNAME.dap -ap-num 0 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -event examine-end { global _TARGETNAME sc58x_enabledebug } proc sc58x_enabledebug {} { # Enable debugging functionality by setting bits in the TAPC_DBGCTL register # it is not possible to halt the target unless these bits have been set ap0.mem mww 0x31131000 0xFFFF } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/aduc702x.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME aduc702x } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # This config file was defaulting to big endian.. set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } adapter srst delay 200 jtag_ntrst_delay 200 ## JTAG scan chain #format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE) jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID ## ## Target configuration ## set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME # allocate the entire SRAM as working area $_TARGETNAME configure -work-area-phys 0x10000 -work-area-size 0x2000 ## flash configuration # only target number is needed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME aduc702x 0 0 0 0 $_TARGETNAME ## If you use the watchdog, the following code makes sure that the board ## doesn't reboot when halted via JTAG. Yes, on the older generation ## AdUC702x, timer3 continues running even when the CPU is halted. proc watchdog_service {} { global watchdog_hdl mww 0xffff036c 0 # echo "watchdog!!" set watchdog_hdl [after 500 watchdog_service] } $_TARGETNAME configure -event reset-halt-post { watchdog_service } $_TARGETNAME configure -event resume-start { global watchdog_hdl; after cancel $watchdog_hdl } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/aducm360.cfg ================================================ # # This file was created using as references the stm32f1x.cfg and aduc702x.cfg # source [find target/swj-dp.tcl] # Chip name if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME aducm360 } # Endianness if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # Eventually, the whole SRAM of ADuCM360 will be used (8kB) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x2000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x2ba01477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # SWD/JTAG speed adapter speed 1000 ## ## Target configuration ## set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # allocate the working area $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME aducm360 0x00 0 0 0 $_TARGETNAME adapter srst delay 100 cortex_m reset_config sysresetreq ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/allwinner_v3s.cfg ================================================ # This is the config for an Allwinner V3/V3s (sun8iw8). # # Notes: # - Single core ARM Cortex-A7 with a maximum frequency of 1.2 GHz. # - Thumb-2 Technology # - Support NEON Advanced SIMD(Single Instruction Multiple Data)instruction # for acceleration of media and signal processing functions # - Support Large Physical Address Extensions(LPAE) # - VFPv4 Floating Point Unit # - 32KB L1 Instruction cache and 32KB L1 Data cache # - 128KB L2 cache # - has some integrated DDR2 RAM. # # Pins related for debug and bootstrap: # JTAG # JTAG_TMS PF0, SDC0_D1 # JTAG_TDI PF1, SDC0_D0 # JTAG_TDO PF3, SDC0_CMD # JTAG_TCK PF5, SDC0_D2 # UART # None of UART ports seems to be enabled by ROM. # UART0_TX PF2, SDC0_CLK Per default disabled # UART0_RX PF4, SDC0_D3 Per default disabled # UART1_TX PE21 Per default disabled # UART1_RX PE22 Per default disabled # UART2_TX PB0 Per default disabled # UART2_RX PB1 Per default disabled # # JTAG is enabled by default after power on on listed JTAG_* pins. So far the # boot sequence is: # Time Action # 0000ms Power ON # 0200ms JTAG enabled # 0220ms JTAG pins switched to SD mode # # The time frame of 20ms can be not enough to init and halt the CPU. In this # case I would recommend to set: "adapter speed 15000" # To get more or less precise timings, the board should provide reset pin, # or some bench power supply with remote function. In my case I used # EEZ H24005 with this command to power on and halt the target: # "exec echo "*TRG" > /dev/ttyACM0; sleep 220; reset halt" # After this it is possible to enable JTAG mode again from boot loader or OS. # Following DAPs are available: # dap[0]->MEM-AP AHB # dap[1]->MEM-AP APB->CA7[0] # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME v3s } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } # No NRST or SRST is present on the SoC. Boards may provide # some sort of Power cycle reset for complete board or SoC. # For this case we provide srst_pulls_trst so the board config # only needs to set srst_only. reset_config none srst_pulls_trst jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # Add Cortex A7 core set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/alphascale_asm9260t.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME asm9260t } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x079264F3 } # And srst_pulls_trst by chip design. reset_config srst_pulls_trst jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/altera_fpgasoc.cfg ================================================ # # Altera cyclone V SoC family, 5Cxxx # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME fpgasoc } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # Subsidiary TAP: fpga if { [info exists FPGA_TAPID] } { set _FPGA_TAPID $FPGA_TAPID } else { set _FPGA_TAPID 0x02d020dd } jtag newtap $_CHIPNAME.fpga tap -irlen 10 -ircapture 0x01 -irmask 0x3 -expected-id $_FPGA_TAPID # # Cortex-A9 target # # GDB target: Cortex-A9, using DAP, configuring only one core # Base addresses of cores: # core 0 - 0x80110000 # core 1 - 0x80112000 # Slow speed to be sure it will work adapter speed 1000 set _TARGETNAME1 $_CHIPNAME.cpu.0 set _TARGETNAME2 $_CHIPNAME.cpu.1 # A9 core 0 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME1 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80110000 $_TARGETNAME1 configure -event reset-start { adapter speed 1000 } $_TARGETNAME1 configure -event reset-assert-post "cycv_dbginit $_TARGETNAME1" # A9 core 1 #target create $_TARGETNAME2 cortex_a -dap $_CHIPNAME.dap \ # -coreid 1 -dbgbase 0x80112000 #$_TARGETNAME2 configure -event reset-start { adapter speed 1000 } #$_TARGETNAME2 configure -event reset-assert-post "cycv_dbginit $_TARGETNAME2" proc cycv_dbginit {target} { # General Cortex-A8/A9 debug initialisation cortex_a dbginit } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/altera_fpgasoc_arria10.cfg ================================================ # Intel (Altera) Arria10 FPGA SoC if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME arria10 } # ARM CoreSight Debug Access Port (dap HPS) if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_DAP_TAPID # Subsidiary TAP: fpga (tap) # See Intel Arria 10 Handbook # https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/hb/arria-10/a10_handbook.pdf # Intel Arria 10 GX 160 0x02ee20dd # Intel Arria 10 GX 220 0x02e220dd # Intel Arria 10 GX 270 0x02ee30dd # Intel Arria 10 GX 320 0x02e230dd # Intel Arria 10 GX 480 0x02e240dd # Intel Arria 10 GX 570 0x02ee50dd # Intel Arria 10 GX 660 0x02e250dd # Intel Arria 10 GX 900 0x02ee60dd # Intel Arria 10 GX 1150 0x02e660dd # Intel Arria 10 GT 900 0x02e260dd # Intel Arria 10 GT 1150 0x02e060dd # Intel Arria 10 SX 160 0x02e620dd # Intel Arria 10 SX 220 0x02e020dd # Intel Arria 10 SX 270 0x02e630dd # Intel Arria 10 SX 320 0x02e030dd # Intel Arria 10 SX 480 0x02e040dd # Intel Arria 10 SX 570 0x02e650dd # Intel Arria 10 SX 660 0x02e050dd jtag newtap $_CHIPNAME.fpga tap -irlen 10 -expected-id 0x02ee20dd -expected-id 0x02e220dd \ -expected-id 0x02ee30dd -expected-id 0x02e230dd -expected-id 0x02e240dd \ -expected-id 0x02ee50dd -expected-id 0x02e250dd -expected-id 0x02ee60dd \ -expected-id 0x02e660dd -expected-id 0x02e260dd -expected-id 0x02e060dd \ -expected-id 0x02e620dd -expected-id 0x02e020dd -expected-id 0x02e630dd \ -expected-id 0x02e030dd -expected-id 0x02e040dd -expected-id 0x02e650dd \ -expected-id 0x02e050dd set _TARGETNAME $_CHIPNAME.cpu # # Cortex-A9 target dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME.0 cortex_a -dap $_CHIPNAME.dap -coreid 0 target create $_TARGETNAME.1 cortex_a -dap $_CHIPNAME.dap -coreid 1 \ -defer-examine target smp $_TARGETNAME.0 $_TARGETNAME.1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/am335x.cfg ================================================ source [find target/icepick.cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME am335x } # set the taps to be enabled by default. this can be overridden # by setting DEFAULT_TAPS in a separate configuration file # or directly on the command line. if { [info exists DEFAULT_TAPS] } { set _DEFAULT_TAPS "$DEFAULT_TAPS" } else { set _DEFAULT_TAPS "$_CHIPNAME.tap" } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4b6b902f } jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.tap -event tap-enable "icepick_d_tapenable $_CHIPNAME.jrc 12 0" dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap # # M3 DAP # if { [info exists M3_DAP_TAPID] } { set _M3_DAP_TAPID $M3_DAP_TAPID } else { set _M3_DAP_TAPID 0x4b6b902f } jtag newtap $_CHIPNAME m3_tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_M3_DAP_TAPID -disable jtag configure $_CHIPNAME.m3_tap -event tap-enable "icepick_d_tapenable $_CHIPNAME.jrc 11 0" dap create $_CHIPNAME.m3_dap -chain-position $_CHIPNAME.m3_tap # # ICEpick-D (JTAG route controller) # if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0b94402f } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version jtag configure $_CHIPNAME.jrc -event setup { global _DEFAULT_TAPS enable_default_taps $_DEFAULT_TAPS } # some TCK tycles are required to activate the DEBUG power domain jtag configure $_CHIPNAME.jrc -event post-reset "runtest 100" # # helper function that enables all taps passed as argument # proc enable_default_taps { taps } { foreach tap $taps { jtag tapenable $tap } } # # Cortex-M3 target # set _TARGETNAME_2 $_CHIPNAME.m3 target create $_TARGETNAME_2 cortex_m -dap $_CHIPNAME.m3_dap # # Cortex-A8 target # set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap -dbgbase 0x80001000 # SRAM: 64K at 0x4030.0000; use the first 16K $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x4000 # when putting the target into 'reset halt', we need to disable the watchdog as # it would otherwise trigger while we're in JTAG # FIXME: unify with target/am437x.cfg source [find mem_helper.tcl] set WDT1_BASE_ADDR 0x44e35000 set WDT1_W_PEND_WSPR [expr {$WDT1_BASE_ADDR + 0x0034}] set WDT1_WSPR [expr {$WDT1_BASE_ADDR + 0x0048}] proc disable_watchdog { } { global WDT1_WSPR global WDT1_W_PEND_WSPR global _TARGETNAME set curstate [$_TARGETNAME curstate] if { [string compare $curstate halted] == 0 } { set WDT_DISABLE_SEQ1 0xaaaa set WDT_DISABLE_SEQ2 0x5555 mww phys $WDT1_WSPR $WDT_DISABLE_SEQ1 # Empty body to make sure this executes as fast as possible. # We don't want any delays here otherwise romcode might start # executing and end up changing state of certain IPs. while { [expr {[mrw $WDT1_W_PEND_WSPR] & 0x10}] } { } mww phys $WDT1_WSPR $WDT_DISABLE_SEQ2 while { [expr {[mrw $WDT1_W_PEND_WSPR] & 0x10}] } { } } } $_TARGETNAME configure -event reset-end { disable_watchdog } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/am437x.cfg ================================================ source [find target/icepick.cfg] source [find mem_helper.tcl] ############################################################################### ## AM437x Registers ## ############################################################################### set PRCM_BASE_ADDR 0x44df0000 set REVISION_PRM [expr {$PRCM_BASE_ADDR + 0x0000}] set PRM_IRQSTATUS_MPU [expr {$PRCM_BASE_ADDR + 0x0004}] set PRM_IRQENABLE_MPU [expr {$PRCM_BASE_ADDR + 0x0008}] set PRM_IRQSTATUS_M3 [expr {$PRCM_BASE_ADDR + 0x000c}] set PRM_IRQENABLE_M3 [expr {$PRCM_BASE_ADDR + 0x0010}] set PM_MPU_PWRSTCTRL [expr {$PRCM_BASE_ADDR + 0x0300}] set PM_MPU_PWRSTST [expr {$PRCM_BASE_ADDR + 0x0304}] set RM_MPU_RSTST [expr {$PRCM_BASE_ADDR + 0x0314}] set RM_MPU_CONTEXT [expr {$PRCM_BASE_ADDR + 0x0324}] set PM_GFX_PWRSTCTRL [expr {$PRCM_BASE_ADDR + 0x0400}] set PM_GFX_PWRSTST [expr {$PRCM_BASE_ADDR + 0x0404}] set RM_GFX_RSTCTRL [expr {$PRCM_BASE_ADDR + 0x0410}] set RM_GFX_RSTST [expr {$PRCM_BASE_ADDR + 0x0414}] set RM_GFX_CONTEXT [expr {$PRCM_BASE_ADDR + 0x0424}] set RM_RTC_CONTEXT [expr {$PRCM_BASE_ADDR + 0x0524}] set RM_WKUP_RSTCTRL [expr {$PRCM_BASE_ADDR + 0x2010}] set RM_WKUP_RSTST [expr {$PRCM_BASE_ADDR + 0x2014}] set CM_L3_AON_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x2800}] set CM_WKUP_DEBUGSS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2820}] set CM_L3S_TSC_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x2900}] set CM_WKUP_ADC_TSC_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2920}] set CM_L4_WKUP_AON_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x2a00}] set CM_WKUP_L4WKUP_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a20}] set CM_WKUP_WKUP_M3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a28}] set CM_WKUP_SYNCTIMER_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a30}] set CM_WKUP_CLKDIV32K_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a38}] set CM_WKUP_USBPHY0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a40}] set CM_WKUP_USBPHY1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a48}] set CM_WKUP_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x2b00}] set CM_WKUP_TIMER0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b20}] set CM_WKUP_TIMER1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b28}] set CM_WKUP_WDT0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b30}] set CM_WKUP_WDT1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b38}] set CM_WKUP_I2C0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b40}] set CM_WKUP_UART0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b48}] set CM_WKUP_SMARTREFLEX0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b50}] set CM_WKUP_SMARTREFLEX1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b58}] set CM_WKUP_CONTROL_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b60}] set CM_WKUP_GPIO0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b68}] set CM_CLKMODE_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d20}] set CM_IDLEST_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d24}] set CM_CLKSEL_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d2c}] set CM_DIV_M4_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d38}] set CM_DIV_M5_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d3c}] set CM_DIV_M6_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d40}] set CM_SSC_DELTAMSTEP_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d48}] set CM_SSC_MODFREQDIV_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d4c}] set CM_CLKMODE_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d60}] set CM_IDLEST_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d64}] set CM_CLKSEL_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d6c}] set CM_DIV_M2_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d70}] set CM_SSC_DELTAMSTEP_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d88}] set CM_SSC_MODFREQDIV_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d8c}] set CM_CLKMODE_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2da0}] set CM_IDLEST_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2da4}] set CM_CLKSEL_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2dac}] set CM_DIV_M2_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2db0}] set CM_DIV_M4_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2db8}] set CM_SSC_DELTAMSTEP_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2dc8}] set CM_SSC_MODFREQDIV_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2dcc}] set CM_CLKMODE_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2de0}] set CM_IDLEST_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2de4}] set CM_CLKSEL_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2dec}] set CM_DIV_M2_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2df0}] set CM_CLKSEL2_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2e04}] set CM_SSC_DELTAMSTEP_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2e08}] set CM_SSC_MODFREQDIV_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2e0c}] set CM_CLKDCOLDO_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2e14}] set CM_CLKMODE_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e20}] set CM_IDLEST_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e24}] set CM_CLKSEL_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e2c}] set CM_DIV_M2_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e30}] set CM_SSC_DELTAMSTEP_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e48}] set CM_SSC_MODFREQDIV_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e4c}] set CM_CLKMODE_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e60}] set CM_IDLEST_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e64}] set CM_CLKSEL_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e6c}] set CM_DIV_M2_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e70}] set CM_CLKSEL2_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e84}] set CM_SSC_DELTAMSTEP_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e88}] set CM_SSC_MODFREQDIV_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e8c}] set CM_SHADOW_FREQ_CONFIG1 [expr {$PRCM_BASE_ADDR + 0x2fa0}] set CM_SHADOW_FREQ_CONFIG2 [expr {$PRCM_BASE_ADDR + 0x2fa4}] set CM_CLKOUT1_CTRL [expr {$PRCM_BASE_ADDR + 0x4100}] set CM_DLL_CTRL [expr {$PRCM_BASE_ADDR + 0x4104}] set CM_CLKOUT2_CTRL [expr {$PRCM_BASE_ADDR + 0x4108}] set CLKSEL_TIMER1MS_CLK [expr {$PRCM_BASE_ADDR + 0x4200}] set CLKSEL_TIMER2_CLK [expr {$PRCM_BASE_ADDR + 0x4204}] set CLKSEL_TIMER3_CLK [expr {$PRCM_BASE_ADDR + 0x4208}] set CLKSEL_TIMER4_CLK [expr {$PRCM_BASE_ADDR + 0x420c}] set CLKSEL_TIMER5_CLK [expr {$PRCM_BASE_ADDR + 0x4210}] set CLKSEL_TIMER6_CLK [expr {$PRCM_BASE_ADDR + 0x4214}] set CLKSEL_TIMER7_CLK [expr {$PRCM_BASE_ADDR + 0x4218}] set CLKSEL_TIMER8_CLK [expr {$PRCM_BASE_ADDR + 0x421c}] set CLKSEL_TIMER9_CLK [expr {$PRCM_BASE_ADDR + 0x4220}] set CLKSEL_TIMER10_CLK [expr {$PRCM_BASE_ADDR + 0x4224}] set CLKSEL_TIMER11_CLK [expr {$PRCM_BASE_ADDR + 0x4228}] set CLKSEL_WDT1_CLK [expr {$PRCM_BASE_ADDR + 0x422c}] set CLKSEL_SYNCTIMER_CLK [expr {$PRCM_BASE_ADDR + 0x4230}] set CLKSEL_MAC_CLK [expr {$PRCM_BASE_ADDR + 0x4234}] set CLKSEL_CPTS_RFT_CLK [expr {$PRCM_BASE_ADDR + 0x4238}] set CLKSEL_GFX_FCLK [expr {$PRCM_BASE_ADDR + 0x423c}] set CLKSEL_GPIO0_DBCLK [expr {$PRCM_BASE_ADDR + 0x4240}] set CLKSEL_LCDC_PIXEL_CLK [expr {$PRCM_BASE_ADDR + 0x4244}] set CLKSEL_ICSS_OCP_CLK [expr {$PRCM_BASE_ADDR + 0x4248}] set CLKSEL_DLL_AGING_CLK [expr {$PRCM_BASE_ADDR + 0x4250}] set CLKSEL_USBPHY32KHZ_GCLK [expr {$PRCM_BASE_ADDR + 0x4260}] set CM_MPU_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8300}] set CM_MPU_MPU_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8320}] set CM_GFX_L3_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8400}] set CM_GFX_GFX_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8420}] set CM_RTC_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8500}] set CM_RTC_RTC_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8520}] set CM_PER_L3_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8800}] set CM_PER_L3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8820}] set CM_PER_AES0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8828}] set CM_PER_DES_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8830}] set CM_PER_CRYPTODMA_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8838}] set CM_PER_L3_INSTR_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8840}] set CM_PER_MSTR_EXPS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8848}] set CM_PER_OCMCRAM_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8850}] set CM_PER_SHA0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8858}] set CM_PER_SLV_EXPS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8860}] set CM_PER_VPFE0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8868}] set CM_PER_VPFE1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8870}] set CM_PER_TPCC_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8878}] set CM_PER_TPTC0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8880}] set CM_PER_TPTC1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8888}] set CM_PER_TPTC2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8890}] set CM_PER_DLL_AGING_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8898}] set CM_PER_L4HS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x88a0}] set CM_PER_L4FW_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x88a8}] set CM_PER_L3S_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8a00}] set CM_PER_GPMC_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a20}] set CM_PER_IEEE5000_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a28}] set CM_PER_MCASP0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a38}] set CM_PER_MCASP1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a40}] set CM_PER_MMC2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a48}] set CM_PER_QSPI_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a58}] set CM_PER_USB_OTG_SS0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a60}] set CM_PER_USB_OTG_SS1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a68}] set CM_PER_ICSS_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8b00}] set CM_PER_ICSS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8b20}] set CM_PER_L4LS_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8c00}] set CM_PER_L4LS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c20}] set CM_PER_DCAN0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c28}] set CM_PER_DCAN1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c30}] set CM_PER_EPWMSS0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c38}] set CM_PER_EPWMSS1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c40}] set CM_PER_EPWMSS2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c48}] set CM_PER_EPWMSS3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c50}] set CM_PER_EPWMSS4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c58}] set CM_PER_EPWMSS5_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c60}] set CM_PER_ELM_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c68}] set CM_PER_GPIO1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c78}] set CM_PER_GPIO2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c80}] set CM_PER_GPIO3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c88}] set CM_PER_GPIO4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c90}] set CM_PER_GPIO5_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c98}] set CM_PER_HDQ1W_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8ca0}] set CM_PER_I2C1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8ca8}] set CM_PER_I2C2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cb0}] set CM_PER_MAILBOX0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cb8}] set CM_PER_MMC0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cc0}] set CM_PER_MMC1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cc8}] set CM_PER_PKA_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cd0}] set CM_PER_RNG_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8ce0}] set CM_PER_SPARE0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8ce8}] set CM_PER_SPARE1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cf0}] set CM_PER_SPI0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d00}] set CM_PER_SPI1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d08}] set CM_PER_SPI2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d10}] set CM_PER_SPI3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d18}] set CM_PER_SPI4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d20}] set CM_PER_SPINLOCK_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d28}] set CM_PER_TIMER2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d30}] set CM_PER_TIMER3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d38}] set CM_PER_TIMER4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d40}] set CM_PER_TIMER5_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d48}] set CM_PER_TIMER6_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d50}] set CM_PER_TIMER7_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d58}] set CM_PER_TIMER8_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d60}] set CM_PER_TIMER9_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d68}] set CM_PER_TIMER10_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d70}] set CM_PER_TIMER11_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d78}] set CM_PER_UART1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d80}] set CM_PER_UART2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d88}] set CM_PER_UART3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d90}] set CM_PER_UART4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d98}] set CM_PER_UART5_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8da0}] set CM_PER_USBPHYOCP2SCP0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8db8}] set CM_PER_USBPHYOCP2SCP1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8dc0}] set CM_PER_EMIF_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8f00}] set CM_PER_EMIF_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8f20}] set CM_PER_DLL_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8f28}] set CM_PER_EMIF_FW_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8f30}] set CM_PER_OTFA_EMIF_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8f38}] set CM_PER_DSS_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x9200}] set CM_PER_DSS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x9220}] set CM_PER_CPSW_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x9300}] set CM_PER_CPGMAC0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x9320}] set CM_PER_OCPWP_L3_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x9400}] set CM_PER_OCPWP_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x9420}] set CONTROL_BASE_ADDR 0x44e10000 set CONTROL_STATUS [expr {$CONTROL_BASE_ADDR + 0x0040}] set DEVICE_ID [expr {$CONTROL_BASE_ADDR + 0x0600}] set DEV_FEATURE [expr {$CONTROL_BASE_ADDR + 0x0604}] set DEV_ATTRIBUTE [expr {$CONTROL_BASE_ADDR + 0x0610}] set MAC_ID0_LO [expr {$CONTROL_BASE_ADDR + 0x0630}] set MAC_ID0_HI [expr {$CONTROL_BASE_ADDR + 0x0634}] set MAC_ID1_LO [expr {$CONTROL_BASE_ADDR + 0x0638}] set MAC_ID1_HI [expr {$CONTROL_BASE_ADDR + 0x063c}] set USB_VID_PID [expr {$CONTROL_BASE_ADDR + 0x07f4}] set CONTROL_CONF_ECAP0_IN_PWM0_OUT [expr {$CONTROL_BASE_ADDR + 0x0964}] set CONTROL_CONF_SPI4_CS0 [expr {$CONTROL_BASE_ADDR + 0x0a5c}] set CONTROL_CONF_SPI2_SCLK [expr {$CONTROL_BASE_ADDR + 0x0a60}] set CONTROL_CONF_SPI2_D0 [expr {$CONTROL_BASE_ADDR + 0x0a64}] set CONTROL_CONF_XDMA_EVENT_INTR0 [expr {$CONTROL_BASE_ADDR + 0x0a70}] set CONTROL_CONF_XDMA_EVENT_INTR1 [expr {$CONTROL_BASE_ADDR + 0x0a74}] set CONTROL_CONF_GPMC_A0 [expr {$CONTROL_BASE_ADDR + 0x0840}] set DDR_IO_CTRL [expr {$CONTROL_BASE_ADDR + 0x0e04}] set VTP_CTRL_REG [expr {$CONTROL_BASE_ADDR + 0x0e0c}] set VREF_CTRL [expr {$CONTROL_BASE_ADDR + 0x0e14}] set DDR_CKE_CTRL [expr {$CONTROL_BASE_ADDR + 0x131c}] set DDR_ADDRCTRL_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1404}] set DDR_ADDRCTRL_WD0_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1408}] set DDR_ADDRCTRL_WD1_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x140c}] set DDR_DATA0_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1440}] set DDR_DATA1_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1444}] set DDR_DATA2_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1448}] set DDR_DATA3_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x144c}] set EMIF_SDRAM_CONFIG_EXT [expr {$CONTROL_BASE_ADDR + 0x1460}] set EMIF_SDRAM_STATUS_EXT [expr {$CONTROL_BASE_ADDR + 0x1464}] set GPIO0_BASE_ADDR 0x44e07000 set GPIO0_SYSCONFIG [expr {$GPIO0_BASE_ADDR + 0x0010}] set GPIO0_SYSSTATUS [expr {$GPIO0_BASE_ADDR + 0x0114}] set GPIO0_CTRL [expr {$GPIO0_BASE_ADDR + 0x0130}] set GPIO0_OE [expr {$GPIO0_BASE_ADDR + 0x0134}] set GPIO0_CLEARDATAOUT [expr {$GPIO0_BASE_ADDR + 0x0190}] set GPIO0_SETDATAOUT [expr {$GPIO0_BASE_ADDR + 0x0194}] set GPIO5_BASE_ADDR 0x48322000 set GPIO5_SYSCONFIG [expr {$GPIO5_BASE_ADDR + 0x0010}] set GPIO5_SYSSTATUS [expr {$GPIO5_BASE_ADDR + 0x0114}] set GPIO5_CTRL [expr {$GPIO5_BASE_ADDR + 0x0130}] set GPIO5_OE [expr {$GPIO5_BASE_ADDR + 0x0134}] set GPIO5_CLEARDATAOUT [expr {$GPIO5_BASE_ADDR + 0x0190}] set GPIO5_SETDATAOUT [expr {$GPIO5_BASE_ADDR + 0x0194}] set GPIO1_BASE_ADDR 0x4804c000 set GPIO1_SYSCONFIG [expr {$GPIO1_BASE_ADDR + 0x0010}] set GPIO1_SYSSTATUS [expr {$GPIO1_BASE_ADDR + 0x0114}] set GPIO1_CTRL [expr {$GPIO1_BASE_ADDR + 0x0130}] set GPIO1_OE [expr {$GPIO1_BASE_ADDR + 0x0134}] set GPIO1_CLEARDATAOUT [expr {$GPIO1_BASE_ADDR + 0x0190}] set GPIO1_SETDATAOUT [expr {$GPIO1_BASE_ADDR + 0x0194}] set EMIF_BASE_ADDR 0x4c000000 set EMIF_STATUS [expr {$EMIF_BASE_ADDR + 0x0004}] set EMIF_SDRAM_CONFIG [expr {$EMIF_BASE_ADDR + 0x0008}] set EMIF_SDRAM_CONFIG_2 [expr {$EMIF_BASE_ADDR + 0x000c}] set EMIF_SDRAM_REF_CTRL [expr {$EMIF_BASE_ADDR + 0x0010}] set EMIF_SDRAM_REF_CTRL_SHDW [expr {$EMIF_BASE_ADDR + 0x0014}] set EMIF_SDRAM_TIM_1 [expr {$EMIF_BASE_ADDR + 0x0018}] set EMIF_SDRAM_TIM_1_SHDW [expr {$EMIF_BASE_ADDR + 0x001c}] set EMIF_SDRAM_TIM_2 [expr {$EMIF_BASE_ADDR + 0x0020}] set EMIF_SDRAM_TIM_2_SHDW [expr {$EMIF_BASE_ADDR + 0x0024}] set EMIF_SDRAM_TIM_3 [expr {$EMIF_BASE_ADDR + 0x0028}] set EMIF_SDRAM_TIM_3_SHDW [expr {$EMIF_BASE_ADDR + 0x002c}] set EMIF_LPDDR2_NVM_TIM [expr {$EMIF_BASE_ADDR + 0x0030}] set EMIF_LPDDR2_NVM_TIM_SHDW [expr {$EMIF_BASE_ADDR + 0x0034}] set EMIF_PWR_MGMT_CTRL [expr {$EMIF_BASE_ADDR + 0x0038}] set EMIF_PWR_MGMT_CTRL_SHDW [expr {$EMIF_BASE_ADDR + 0x003c}] set EMIF_LPDDR2_MODE_REG_DATA [expr {$EMIF_BASE_ADDR + 0x0040}] set EMIF_LPDDR2_MODE_REG_CFG [expr {$EMIF_BASE_ADDR + 0x0050}] set EMIF_OCP_CONFIG [expr {$EMIF_BASE_ADDR + 0x0054}] set EMIF_OCP_CFG_VAL_1 [expr {$EMIF_BASE_ADDR + 0x0058}] set EMIF_OCP_CFG_VAL_2 [expr {$EMIF_BASE_ADDR + 0x005c}] set EMIF_IODFT_TLGC [expr {$EMIF_BASE_ADDR + 0x0060}] set EMIF_IODFT_CTRL_MISR_RSLT [expr {$EMIF_BASE_ADDR + 0x0064}] set EMIF_IODFT_ADDR_MISR_RSLT [expr {$EMIF_BASE_ADDR + 0x0068}] set EMIF_IODFT_DATA_MISR_RSLT_1 [expr {$EMIF_BASE_ADDR + 0x006c}] set EMIF_IODFT_DATA_MISR_RSLT_2 [expr {$EMIF_BASE_ADDR + 0x0070}] set EMIF_IODFT_DATA_MISR_RSLT_3 [expr {$EMIF_BASE_ADDR + 0x0074}] set EMIF_PERF_CNT_1 [expr {$EMIF_BASE_ADDR + 0x0080}] set EMIF_PERF_CNT_2 [expr {$EMIF_BASE_ADDR + 0x0084}] set EMIF_PERF_CNT_CFG [expr {$EMIF_BASE_ADDR + 0x0088}] set EMIF_PERF_CNT_SEL [expr {$EMIF_BASE_ADDR + 0x008c}] set EMIF_PERF_CNT_TIM [expr {$EMIF_BASE_ADDR + 0x0090}] set EMIF_MISC_REG [expr {$EMIF_BASE_ADDR + 0x0094}] set EMIF_DLL_CALIB_CTRL [expr {$EMIF_BASE_ADDR + 0x0098}] set EMIF_DLL_CALIB_CTRL_SHDW [expr {$EMIF_BASE_ADDR + 0x009c}] set EMIF_IRQ_EOI [expr {$EMIF_BASE_ADDR + 0x00a0}] set EMIF_IRQSTATUS_RAW_SYS [expr {$EMIF_BASE_ADDR + 0x00a4}] set EMIF_IRQSTATUS_SYS [expr {$EMIF_BASE_ADDR + 0x00ac}] set EMIF_IRQENABLE_SET_SYS [expr {$EMIF_BASE_ADDR + 0x00b4}] set EMIF_IRQENABLE_CLR_SYS [expr {$EMIF_BASE_ADDR + 0x00bc}] set EMIF_ZQ_CONFIG [expr {$EMIF_BASE_ADDR + 0x00c8}] set EMIF_TEMP_ALERT_CONFIG [expr {$EMIF_BASE_ADDR + 0x00cc}] set EMIF_OCP_ERR_LOG [expr {$EMIF_BASE_ADDR + 0x00d0}] set EMIF_RDWR_LVL_RMP_WIN [expr {$EMIF_BASE_ADDR + 0x00d4}] set EMIF_RDWR_LVL_RMP_CTRL [expr {$EMIF_BASE_ADDR + 0x00d8}] set EMIF_RDWR_LVL_CTRL [expr {$EMIF_BASE_ADDR + 0x00dc}] set EMIF_DDR_PHY_CTRL_1 [expr {$EMIF_BASE_ADDR + 0x00e4}] set EMIF_DDR_PHY_CTRL_1_SHDW [expr {$EMIF_BASE_ADDR + 0x00e8}] set EMIF_DDR_PHY_CTRL_2 [expr {$EMIF_BASE_ADDR + 0x00ec}] set EMIF_PRI_COS_MAP [expr {$EMIF_BASE_ADDR + 0x0100}] set EMIF_CONNID_COS_1_MAP [expr {$EMIF_BASE_ADDR + 0x0104}] set EMIF_CONNID_COS_2_MAP [expr {$EMIF_BASE_ADDR + 0x0108}] set ECC_CTRL [expr {$EMIF_BASE_ADDR + 0x0110}] set ECC_ADDR_RNG_1 [expr {$EMIF_BASE_ADDR + 0x0114}] set ECC_ADDR_RNG_2 [expr {$EMIF_BASE_ADDR + 0x0118}] set EMIF_RD_WR_EXEC_THRSH [expr {$EMIF_BASE_ADDR + 0x0120}] set COS_CONFIG [expr {$EMIF_BASE_ADDR + 0x0124}] set PHY_STATUS_1 [expr {$EMIF_BASE_ADDR + 0x0144}] set PHY_STATUS_2 [expr {$EMIF_BASE_ADDR + 0x0148}] set PHY_STATUS_3 [expr {$EMIF_BASE_ADDR + 0x014c}] set PHY_STATUS_4 [expr {$EMIF_BASE_ADDR + 0x0150}] set PHY_STATUS_5 [expr {$EMIF_BASE_ADDR + 0x0154}] set PHY_STATUS_6 [expr {$EMIF_BASE_ADDR + 0x0158}] set PHY_STATUS_7 [expr {$EMIF_BASE_ADDR + 0x015c}] set PHY_STATUS_8 [expr {$EMIF_BASE_ADDR + 0x0160}] set PHY_STATUS_9 [expr {$EMIF_BASE_ADDR + 0x0164}] set PHY_STATUS_10 [expr {$EMIF_BASE_ADDR + 0x0168}] set PHY_STATUS_11 [expr {$EMIF_BASE_ADDR + 0x016c}] set PHY_STATUS_12 [expr {$EMIF_BASE_ADDR + 0x0170}] set PHY_STATUS_13 [expr {$EMIF_BASE_ADDR + 0x0174}] set PHY_STATUS_14 [expr {$EMIF_BASE_ADDR + 0x0178}] set PHY_STATUS_15 [expr {$EMIF_BASE_ADDR + 0x017c}] set PHY_STATUS_16 [expr {$EMIF_BASE_ADDR + 0x0180}] set PHY_STATUS_17 [expr {$EMIF_BASE_ADDR + 0x0184}] set PHY_STATUS_18 [expr {$EMIF_BASE_ADDR + 0x0188}] set PHY_STATUS_19 [expr {$EMIF_BASE_ADDR + 0x018c}] set PHY_STATUS_20 [expr {$EMIF_BASE_ADDR + 0x0190}] set PHY_STATUS_21 [expr {$EMIF_BASE_ADDR + 0x0194}] set PHY_STATUS_22 [expr {$EMIF_BASE_ADDR + 0x0198}] set PHY_STATUS_23 [expr {$EMIF_BASE_ADDR + 0x019c}] set PHY_STATUS_24 [expr {$EMIF_BASE_ADDR + 0x01a0}] set PHY_STATUS_25 [expr {$EMIF_BASE_ADDR + 0x01a4}] set PHY_STATUS_26 [expr {$EMIF_BASE_ADDR + 0x01a8}] set PHY_STATUS_27 [expr {$EMIF_BASE_ADDR + 0x01ac}] set PHY_STATUS_28 [expr {$EMIF_BASE_ADDR + 0x01b0}] set EXT_PHY_CTRL_1 [expr {$EMIF_BASE_ADDR + 0x0200}] set EXT_PHY_CTRL_1_SHDW [expr {$EMIF_BASE_ADDR + 0x0204}] set EXT_PHY_CTRL_2 [expr {$EMIF_BASE_ADDR + 0x0208}] set EXT_PHY_CTRL_2_SHDW [expr {$EMIF_BASE_ADDR + 0x020c}] set EXT_PHY_CTRL_3 [expr {$EMIF_BASE_ADDR + 0x0210}] set EXT_PHY_CTRL_3_SHDW [expr {$EMIF_BASE_ADDR + 0x0214}] set EXT_PHY_CTRL_4 [expr {$EMIF_BASE_ADDR + 0x0218}] set EXT_PHY_CTRL_4_SHDW [expr {$EMIF_BASE_ADDR + 0x021c}] set EXT_PHY_CTRL_5 [expr {$EMIF_BASE_ADDR + 0x0220}] set EXT_PHY_CTRL_5_SHDW [expr {$EMIF_BASE_ADDR + 0x0224}] set EXT_PHY_CTRL_6 [expr {$EMIF_BASE_ADDR + 0x0228}] set EXT_PHY_CTRL_6_SHDW [expr {$EMIF_BASE_ADDR + 0x022c}] set EXT_PHY_CTRL_7 [expr {$EMIF_BASE_ADDR + 0x0230}] set EXT_PHY_CTRL_7_SHDW [expr {$EMIF_BASE_ADDR + 0x0234}] set EXT_PHY_CTRL_8 [expr {$EMIF_BASE_ADDR + 0x0238}] set EXT_PHY_CTRL_8_SHDW [expr {$EMIF_BASE_ADDR + 0x023c}] set EXT_PHY_CTRL_9 [expr {$EMIF_BASE_ADDR + 0x0240}] set EXT_PHY_CTRL_9_SHDW [expr {$EMIF_BASE_ADDR + 0x0244}] set EXT_PHY_CTRL_10 [expr {$EMIF_BASE_ADDR + 0x0248}] set EXT_PHY_CTRL_10_SHDW [expr {$EMIF_BASE_ADDR + 0x024c}] set EXT_PHY_CTRL_11 [expr {$EMIF_BASE_ADDR + 0x0250}] set EXT_PHY_CTRL_11_SHDW [expr {$EMIF_BASE_ADDR + 0x0254}] set EXT_PHY_CTRL_12 [expr {$EMIF_BASE_ADDR + 0x0258}] set EXT_PHY_CTRL_12_SHDW [expr {$EMIF_BASE_ADDR + 0x025c}] set EXT_PHY_CTRL_13 [expr {$EMIF_BASE_ADDR + 0x0260}] set EXT_PHY_CTRL_13_SHDW [expr {$EMIF_BASE_ADDR + 0x0264}] set EXT_PHY_CTRL_14 [expr {$EMIF_BASE_ADDR + 0x0268}] set EXT_PHY_CTRL_14_SHDW [expr {$EMIF_BASE_ADDR + 0x026c}] set EXT_PHY_CTRL_15 [expr {$EMIF_BASE_ADDR + 0x0270}] set EXT_PHY_CTRL_15_SHDW [expr {$EMIF_BASE_ADDR + 0x0274}] set EXT_PHY_CTRL_16 [expr {$EMIF_BASE_ADDR + 0x0278}] set EXT_PHY_CTRL_16_SHDW [expr {$EMIF_BASE_ADDR + 0x027c}] set EXT_PHY_CTRL_17 [expr {$EMIF_BASE_ADDR + 0x0280}] set EXT_PHY_CTRL_17_SHDW [expr {$EMIF_BASE_ADDR + 0x0284}] set EXT_PHY_CTRL_18 [expr {$EMIF_BASE_ADDR + 0x0288}] set EXT_PHY_CTRL_18_SHDW [expr {$EMIF_BASE_ADDR + 0x028c}] set EXT_PHY_CTRL_19 [expr {$EMIF_BASE_ADDR + 0x0290}] set EXT_PHY_CTRL_19_SHDW [expr {$EMIF_BASE_ADDR + 0x0294}] set EXT_PHY_CTRL_20 [expr {$EMIF_BASE_ADDR + 0x0298}] set EXT_PHY_CTRL_20_SHDW [expr {$EMIF_BASE_ADDR + 0x029c}] set EXT_PHY_CTRL_21 [expr {$EMIF_BASE_ADDR + 0x02a0}] set EXT_PHY_CTRL_21_SHDW [expr {$EMIF_BASE_ADDR + 0x02a4}] set EXT_PHY_CTRL_22 [expr {$EMIF_BASE_ADDR + 0x02a8}] set EXT_PHY_CTRL_22_SHDW [expr {$EMIF_BASE_ADDR + 0x02ac}] set EXT_PHY_CTRL_23 [expr {$EMIF_BASE_ADDR + 0x02b0}] set EXT_PHY_CTRL_23_SHDW [expr {$EMIF_BASE_ADDR + 0x02b4}] set EXT_PHY_CTRL_24 [expr {$EMIF_BASE_ADDR + 0x02b8}] set EXT_PHY_CTRL_24_SHDW [expr {$EMIF_BASE_ADDR + 0x02bc}] set EXT_PHY_CTRL_25 [expr {$EMIF_BASE_ADDR + 0x02c0}] set EXT_PHY_CTRL_25_SHDW [expr {$EMIF_BASE_ADDR + 0x02c4}] set EXT_PHY_CTRL_26 [expr {$EMIF_BASE_ADDR + 0x02c8}] set EXT_PHY_CTRL_26_SHDW [expr {$EMIF_BASE_ADDR + 0x02cc}] set EXT_PHY_CTRL_27 [expr {$EMIF_BASE_ADDR + 0x02d0}] set EXT_PHY_CTRL_27_SHDW [expr {$EMIF_BASE_ADDR + 0x02d4}] set EXT_PHY_CTRL_28 [expr {$EMIF_BASE_ADDR + 0x02d8}] set EXT_PHY_CTRL_28_SHDW [expr {$EMIF_BASE_ADDR + 0x02dc}] set EXT_PHY_CTRL_29 [expr {$EMIF_BASE_ADDR + 0x02e0}] set EXT_PHY_CTRL_29_SHDW [expr {$EMIF_BASE_ADDR + 0x02e4}] set EXT_PHY_CTRL_30 [expr {$EMIF_BASE_ADDR + 0x02e8}] set EXT_PHY_CTRL_30_SHDW [expr {$EMIF_BASE_ADDR + 0x02ec}] set EXT_PHY_CTRL_31 [expr {$EMIF_BASE_ADDR + 0x02f0}] set EXT_PHY_CTRL_31_SHDW [expr {$EMIF_BASE_ADDR + 0x02f4}] set EXT_PHY_CTRL_32 [expr {$EMIF_BASE_ADDR + 0x02f8}] set EXT_PHY_CTRL_32_SHDW [expr {$EMIF_BASE_ADDR + 0x02fc}] set EXT_PHY_CTRL_33 [expr {$EMIF_BASE_ADDR + 0x0300}] set EXT_PHY_CTRL_33_SHDW [expr {$EMIF_BASE_ADDR + 0x0304}] set EXT_PHY_CTRL_34 [expr {$EMIF_BASE_ADDR + 0x0308}] set EXT_PHY_CTRL_34_SHDW [expr {$EMIF_BASE_ADDR + 0x030c}] set EXT_PHY_CTRL_35 [expr {$EMIF_BASE_ADDR + 0x0310}] set EXT_PHY_CTRL_35_SHDW [expr {$EMIF_BASE_ADDR + 0x0314}] set EXT_PHY_CTRL_36 [expr {$EMIF_BASE_ADDR + 0x0318}] set EXT_PHY_CTRL_36_SHDW [expr {$EMIF_BASE_ADDR + 0x031c}] set WDT1_BASE_ADDR 0x44e35000 set WDT1_W_PEND_WSPR [expr {$WDT1_BASE_ADDR + 0x0034}] set WDT1_WSPR [expr {$WDT1_BASE_ADDR + 0x0048}] set RTC_BASE_ADDR 0x44e3e000 set RTC_KICK0R [expr {$RTC_BASE_ADDR + 0x6c}] set RTC_KICK1R [expr {$RTC_BASE_ADDR + 0x70}] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME am437x } set JRC_MODULE icepick_d set DEBUGSS_MODULE debugss set M3_MODULE m3_wakeupss set JRC_NAME $_CHIPNAME.$JRC_MODULE set DEBUGSS_NAME $_CHIPNAME.$DEBUGSS_MODULE set M3_NAME $_CHIPNAME.$M3_MODULE set _TARGETNAME $_CHIPNAME.mpuss # # M3 WakeupSS DAP # if { [info exists M3_DAP_TAPID] } { set _M3_DAP_TAPID $M3_DAP_TAPID } else { set _M3_DAP_TAPID 0x4b6b902f } jtag newtap $_CHIPNAME $M3_MODULE -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_M3_DAP_TAPID -disable jtag configure $M3_NAME -event tap-enable "icepick_d_tapenable $JRC_NAME 11 0" dap create $M3_NAME.dap -chain-position $M3_NAME # # DebugSS DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x46b6902f } jtag newtap $_CHIPNAME $DEBUGSS_MODULE -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable jtag configure $DEBUGSS_NAME -event tap-enable "icepick_d_tapenable $JRC_NAME 12 0" dap create $DEBUGSS_NAME.dap -chain-position $DEBUGSS_NAME # # ICEpick-D (JTAG route controller) # if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0b98c02f } jtag newtap $_CHIPNAME $JRC_MODULE -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version jtag configure $JRC_NAME -event setup "jtag tapenable $DEBUGSS_NAME" # some TCK tycles are required to activate the DEBUG power domain jtag configure $JRC_NAME -event post-reset "runtest 100" # # Cortex-A9 target # target create $_TARGETNAME cortex_a -dap $DEBUGSS_NAME.dap -coreid 0 -dbgbase 0x80000000 # SRAM: 256K at 0x4030.0000 $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x40000 # Disables watchdog timer after reset otherwise board won't stay in # halted state. proc disable_watchdog { } { global WDT1_WSPR global WDT1_W_PEND_WSPR global _TARGETNAME set curstate [$_TARGETNAME curstate] if { [string compare $curstate halted] == 0 } { set WDT_DISABLE_SEQ1 0xaaaa set WDT_DISABLE_SEQ2 0x5555 mww phys $WDT1_WSPR $WDT_DISABLE_SEQ1 # Empty body to make sure this executes as fast as possible. # We don't want any delays here otherwise romcode might start # executing and end up changing state of certain IPs. while { [expr {[mrw $WDT1_W_PEND_WSPR] & 0x10}] } { } mww phys $WDT1_WSPR $WDT_DISABLE_SEQ2 while { [expr {[mrw $WDT1_W_PEND_WSPR] & 0x10}] } { } } } proc ceil { x y } { return [ expr {($x + $y - 1) / $y} ] } proc device_type { } { global CONTROL_STATUS set tmp [ mrw $CONTROL_STATUS ] set tmp [ expr {$tmp & 0x700} ] set tmp [ expr {$tmp >> 8} ] return $tmp } proc get_input_clock_frequency { } { global CONTROL_STATUS if { [ device_type ] != 3 } { error "Unknown device type\n" return -1 } set freq [ mrw $CONTROL_STATUS ] set freq [ expr {$freq & 0x00c00000} ] set freq [ expr {$freq >> 22} ] switch $freq { 0 { set CLKIN 19200000 } 1 { set CLKIN 24000000 } 2 { set CLKIN 25000000 } 3 { set CLKIN 26000000 } } return $CLKIN } proc mpu_pll_config { CLKIN N M M2 } { global CM_CLKMODE_DPLL_MPU global CM_CLKSEL_DPLL_MPU global CM_DIV_M2_DPLL_MPU global CM_IDLEST_DPLL_MPU set clksel [ mrw $CM_CLKSEL_DPLL_MPU ] set div_m2 [ mrw $CM_DIV_M2_DPLL_MPU ] mww $CM_CLKMODE_DPLL_MPU 0x4 while { !([ mrw $CM_IDLEST_DPLL_MPU ] & 0x0100) } { } set clksel [ expr {$clksel & (~0x7ffff)} ] set clksel [ expr {$clksel | ($M << 0x8) | $N} ] mww $CM_CLKSEL_DPLL_MPU $clksel set div_m2 [ expr {$div_m2 & (~0x1f)} ] set div_m2 [ expr {$div_m2 | $M2} ] mww $CM_DIV_M2_DPLL_MPU $div_m2 mww $CM_CLKMODE_DPLL_MPU 0x7 while { [ mrw $CM_IDLEST_DPLL_MPU ] != 1 } { } echo "MPU DPLL locked" } proc core_pll_config { CLKIN N M M4 M5 M6 } { global CM_CLKMODE_DPLL_CORE global CM_CLKSEL_DPLL_CORE global CM_DIV_M4_DPLL_CORE global CM_DIV_M5_DPLL_CORE global CM_DIV_M6_DPLL_CORE global CM_IDLEST_DPLL_CORE set clksel [ mrw $CM_CLKSEL_DPLL_CORE ] mww $CM_CLKMODE_DPLL_CORE 0x4 while { !([ mrw $CM_IDLEST_DPLL_CORE ] & 0x0100) } { } set clksel [ expr {$clksel & (~0x7ffff)} ] set clksel [ expr {$clksel | ($M << 0x8) | $N} ] mww $CM_CLKSEL_DPLL_CORE $clksel mww $CM_DIV_M4_DPLL_CORE $M4 mww $CM_DIV_M5_DPLL_CORE $M5 mww $CM_DIV_M6_DPLL_CORE $M6 mww $CM_CLKMODE_DPLL_CORE 0x7 while { !([ mrw $CM_IDLEST_DPLL_CORE ] & 0x01) } { } echo "CORE DPLL locked" } proc per_pll_config { CLKIN N M M2 } { global CM_CLKMODE_DPLL_PER global CM_CLKSEL_DPLL_PER global CM_DIV_M2_DPLL_PER global CM_IDLEST_DPLL_PER set x [ expr {$M * $CLKIN / 1000000} ] set y [ expr {($N + 1) * 250} ] set sd [ ceil $x $y ] set clksel [ mrw $CM_CLKSEL_DPLL_PER ] set div_m2 [ mrw $CM_DIV_M2_DPLL_PER ] mww $CM_CLKMODE_DPLL_PER 0x4 while { !([ mrw $CM_IDLEST_DPLL_PER ] & 0x0100) } { } set clksel [ expr {$clksel & (~0xff0fffff)} ] set clksel [ expr {$clksel | ($M << 0x8) | $N} ] set clksel [ expr {$clksel | ($sd << 24)} ] mww $CM_CLKSEL_DPLL_PER $clksel set div_m2 [ expr {0xffffff80 | $M2} ] mww $CM_CLKMODE_DPLL_PER 0x7 while { !([ mrw $CM_IDLEST_DPLL_PER ] & 0x01) } { } echo "PER DPLL locked" } proc ddr_pll_config { CLKIN N M M2 M4 } { global CM_CLKMODE_DPLL_DDR global CM_CLKSEL_DPLL_DDR global CM_DIV_M2_DPLL_DDR global CM_DIV_M4_DPLL_DDR global CM_IDLEST_DPLL_DDR set clksel [ mrw $CM_CLKSEL_DPLL_DDR ] set div_m2 [ mrw $CM_DIV_M2_DPLL_DDR ] mww $CM_CLKMODE_DPLL_DDR 0x4 while { !([ mrw $CM_IDLEST_DPLL_DDR ] & 0x0100) } { } set clksel [ expr {$clksel & (~0x7ffff)} ] set clksel [ expr {$clksel | ($M << 8) | $N} ] mww $CM_CLKSEL_DPLL_DDR $clksel set div_m2 [ expr {($div_m2 & 0xffffffe0) | $M2} ] mww $CM_DIV_M2_DPLL_DDR $div_m2 mww $CM_DIV_M4_DPLL_DDR $M4 mww $CM_CLKMODE_DPLL_DDR 0x7 while { !([ mrw $CM_IDLEST_DPLL_DDR ] & 0x01) } { } echo "DDR DPLL Locked" } proc config_opp100 { } { set CLKIN [ get_input_clock_frequency ] if { $CLKIN == -1 } { return -1 } switch $CLKIN { 24000000 { mpu_pll_config $CLKIN 0 25 1 core_pll_config $CLKIN 2 125 10 8 4 per_pll_config $CLKIN 9 400 5 ddr_pll_config $CLKIN 2 50 1 2 } 25000000 { mpu_pll_config $CLKIN 0 24 1 core_pll_config $CLKIN 0 40 10 8 4 per_pll_config $CLKIN 9 384 5 ddr_pll_config $CLKIN 0 16 1 2 } 26000000 { mpu_pll_config $CLKIN 12 300 1 core_pll_config $CLKIN 12 500 10 8 4 per_pll_config $CLKIN 12 480 5 ddr_pll_config $CLKIN 12 200 1 2 } 19200000 { mpu_pll_config $CLKIN 3 125 1 core_pll_config $CLKIN 11 625 10 8 4 per_pll_config $CLKIN 7 400 5 ddr_pll_config $CLKIN 2 125 1 2 } } } proc emif_prcm_clk_enable { } { global CM_PER_EMIF_FW_CLKCTRL global CM_PER_EMIF_CLKCTRL mww $CM_PER_EMIF_FW_CLKCTRL 0x02 mww $CM_PER_EMIF_CLKCTRL 0x02 while { [ mrw $CM_PER_EMIF_CLKCTRL ] != 0x02 } { } } proc vtp_enable { } { global VTP_CTRL_REG set vtp [ expr {[ mrw $VTP_CTRL_REG ] | 0x40 }] mww $VTP_CTRL_REG $vtp set vtp [ expr {[ mrw $VTP_CTRL_REG ] & ~0x01 }] mww $VTP_CTRL_REG $vtp set vtp [ expr {[ mrw $VTP_CTRL_REG ] | 0x01 }] mww $VTP_CTRL_REG $vtp } proc config_ddr_ioctrl { } { global DDR_ADDRCTRL_IOCTRL global DDR_ADDRCTRL_WD0_IOCTRL global DDR_ADDRCTRL_WD1_IOCTRL global DDR_CKE_CTRL global DDR_DATA0_IOCTRL global DDR_DATA1_IOCTRL global DDR_DATA2_IOCTRL global DDR_DATA3_IOCTRL global DDR_IO_CTRL mww $DDR_ADDRCTRL_IOCTRL 0x84 mww $DDR_ADDRCTRL_WD0_IOCTRL 0x00 mww $DDR_ADDRCTRL_WD1_IOCTRL 0x00 mww $DDR_DATA0_IOCTRL 0x84 mww $DDR_DATA1_IOCTRL 0x84 mww $DDR_DATA2_IOCTRL 0x84 mww $DDR_DATA3_IOCTRL 0x84 mww $DDR_IO_CTRL 0x00 mww $DDR_CKE_CTRL 0x03 } proc config_ddr_phy { } { global EMIF_DDR_PHY_CTRL_1 global EMIF_DDR_PHY_CTRL_1_SHDW global EXT_PHY_CTRL_1 global EXT_PHY_CTRL_1_SHDW global EXT_PHY_CTRL_2 global EXT_PHY_CTRL_2_SHDW global EXT_PHY_CTRL_3 global EXT_PHY_CTRL_3_SHDW global EXT_PHY_CTRL_4 global EXT_PHY_CTRL_4_SHDW global EXT_PHY_CTRL_5 global EXT_PHY_CTRL_5_SHDW global EXT_PHY_CTRL_6 global EXT_PHY_CTRL_6_SHDW global EXT_PHY_CTRL_7 global EXT_PHY_CTRL_7_SHDW global EXT_PHY_CTRL_8 global EXT_PHY_CTRL_8_SHDW global EXT_PHY_CTRL_9 global EXT_PHY_CTRL_9_SHDW global EXT_PHY_CTRL_10 global EXT_PHY_CTRL_10_SHDW global EXT_PHY_CTRL_11 global EXT_PHY_CTRL_11_SHDW global EXT_PHY_CTRL_12 global EXT_PHY_CTRL_12_SHDW global EXT_PHY_CTRL_13 global EXT_PHY_CTRL_13_SHDW global EXT_PHY_CTRL_14 global EXT_PHY_CTRL_14_SHDW global EXT_PHY_CTRL_15 global EXT_PHY_CTRL_15_SHDW global EXT_PHY_CTRL_16 global EXT_PHY_CTRL_16_SHDW global EXT_PHY_CTRL_17 global EXT_PHY_CTRL_17_SHDW global EXT_PHY_CTRL_18 global EXT_PHY_CTRL_18_SHDW global EXT_PHY_CTRL_19 global EXT_PHY_CTRL_19_SHDW global EXT_PHY_CTRL_20 global EXT_PHY_CTRL_20_SHDW global EXT_PHY_CTRL_21 global EXT_PHY_CTRL_21_SHDW global EXT_PHY_CTRL_22 global EXT_PHY_CTRL_22_SHDW global EXT_PHY_CTRL_23 global EXT_PHY_CTRL_23_SHDW global EXT_PHY_CTRL_24 global EXT_PHY_CTRL_24_SHDW global EXT_PHY_CTRL_25 global EXT_PHY_CTRL_25_SHDW global EXT_PHY_CTRL_26 global EXT_PHY_CTRL_26_SHDW global EXT_PHY_CTRL_27 global EXT_PHY_CTRL_27_SHDW global EXT_PHY_CTRL_28 global EXT_PHY_CTRL_28_SHDW global EXT_PHY_CTRL_29 global EXT_PHY_CTRL_29_SHDW global EXT_PHY_CTRL_30 global EXT_PHY_CTRL_30_SHDW global EXT_PHY_CTRL_31 global EXT_PHY_CTRL_31_SHDW global EXT_PHY_CTRL_32 global EXT_PHY_CTRL_32_SHDW global EXT_PHY_CTRL_33 global EXT_PHY_CTRL_33_SHDW global EXT_PHY_CTRL_34 global EXT_PHY_CTRL_34_SHDW global EXT_PHY_CTRL_35 global EXT_PHY_CTRL_35_SHDW global EXT_PHY_CTRL_36 global EXT_PHY_CTRL_36_SHDW mww $EMIF_DDR_PHY_CTRL_1 0x8009 mww $EMIF_DDR_PHY_CTRL_1_SHDW 0x8009 set slave_ratio 0x80 set gatelvl_init_ratio 0x20 set wr_dqs_slave_delay 0x60 set rd_dqs_slave_delay 0x60 set dq_offset 0x40 set gatelvl_init_mode 0x01 set wr_data_slave_delay 0x80 set gatelvl_num_dq0 0x0f set wrlvl_num_dq0 0x0f mww $EXT_PHY_CTRL_1 [ expr {($slave_ratio << 20) | ($slave_ratio << 10) | $slave_ratio} ] mww $EXT_PHY_CTRL_1_SHDW [ expr {($slave_ratio << 20) | ($slave_ratio << 10) | $slave_ratio} ] mww $EXT_PHY_CTRL_26 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_26_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_27 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_27_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_28 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_28_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_29 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_29_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_30 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_30_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_31 0x00 mww $EXT_PHY_CTRL_31_SHDW 0x00 mww $EXT_PHY_CTRL_32 0x00 mww $EXT_PHY_CTRL_32_SHDW 0x00 mww $EXT_PHY_CTRL_33 0x00 mww $EXT_PHY_CTRL_33_SHDW 0x00 mww $EXT_PHY_CTRL_34 0x00 mww $EXT_PHY_CTRL_34_SHDW 0x00 mww $EXT_PHY_CTRL_35 0x00 mww $EXT_PHY_CTRL_35_SHDW 0x00 mww $EXT_PHY_CTRL_22 0x00 mww $EXT_PHY_CTRL_22_SHDW 0x00 mww $EXT_PHY_CTRL_23 [ expr {($wr_dqs_slave_delay << 16) | $rd_dqs_slave_delay} ] mww $EXT_PHY_CTRL_23_SHDW [ expr {($wr_dqs_slave_delay << 16) | $rd_dqs_slave_delay} ] mww $EXT_PHY_CTRL_24 [ expr {($dq_offset << 24) | ($gatelvl_init_mode << 16) | $wr_data_slave_delay} ] mww $EXT_PHY_CTRL_24_SHDW [ expr {($dq_offset << 24) | ($gatelvl_init_mode << 16) | $wr_data_slave_delay << 0} ] mww $EXT_PHY_CTRL_25 [ expr {($dq_offset << 21) | ($dq_offset << 14) | ($dq_offset << 7) | $dq_offset} ] mww $EXT_PHY_CTRL_25_SHDW [ expr {($dq_offset << 21) | ($dq_offset << 14) | ($dq_offset << 7) | $dq_offset} ] mww $EXT_PHY_CTRL_36 [ expr {($wrlvl_num_dq0 << 4) | $gatelvl_num_dq0} ] mww $EXT_PHY_CTRL_36_SHDW [ expr {($wrlvl_num_dq0 << 4) | $gatelvl_num_dq0} ] } proc config_ddr_timing { } { global EMIF_SDRAM_TIM_1 global EMIF_SDRAM_TIM_2 global EMIF_SDRAM_TIM_3 global EMIF_SDRAM_TIM_1_SHDW global EMIF_SDRAM_TIM_2_SHDW global EMIF_SDRAM_TIM_3_SHDW global EMIF_ZQ_CONFIG mww $EMIF_SDRAM_TIM_1 0xeaaad4db mww $EMIF_SDRAM_TIM_1_SHDW 0xeaaad4db mww $EMIF_SDRAM_TIM_2 0x266b7fda mww $EMIF_SDRAM_TIM_2_SHDW 0x266b7fda mww $EMIF_SDRAM_TIM_3 0x107f8678 mww $EMIF_SDRAM_TIM_3_SHDW 0x107f8678 mww $EMIF_ZQ_CONFIG 0x50074be4 } proc config_ddr_pm { } { global EMIF_PWR_MGMT_CTRL global EMIF_PWR_MGMT_CTRL_SHDW global EMIF_DLL_CALIB_CTRL global EMIF_DLL_CALIB_CTRL_SHDW global EMIF_TEMP_ALERT_CONFIG mww $EMIF_PWR_MGMT_CTRL 0x00 mww $EMIF_PWR_MGMT_CTRL_SHDW 0x00 mww $EMIF_DLL_CALIB_CTRL 0x00050000 mww $EMIF_DLL_CALIB_CTRL_SHDW 0x00050000 mww $EMIF_TEMP_ALERT_CONFIG 0x00 } proc config_ddr_priority { } { global EMIF_PRI_COS_MAP global EMIF_CONNID_COS_1_MAP global EMIF_CONNID_COS_2_MAP global EMIF_RD_WR_EXEC_THRSH global COS_CONFIG mww $EMIF_PRI_COS_MAP 0x00 mww $EMIF_CONNID_COS_1_MAP 0x00 mww $EMIF_CONNID_COS_2_MAP 0x0 mww $EMIF_RD_WR_EXEC_THRSH 0x0405 mww $COS_CONFIG 0x00ffffff } proc config_ddr3 { SDRAM_CONFIG } { global CM_DLL_CTRL global EMIF_IODFT_TLGC global EMIF_RDWR_LVL_CTRL global EMIF_RDWR_LVL_RMP_CTRL global EMIF_SDRAM_CONFIG global EMIF_SDRAM_CONFIG_EXT global EMIF_SDRAM_REF_CTRL global EMIF_SDRAM_REF_CTRL_SHDW global EMIF_STATUS global EXT_PHY_CTRL_36 global EXT_PHY_CTRL_36_SHDW emif_prcm_clk_enable vtp_enable set dll [ expr {[ mrw $CM_DLL_CTRL ] & ~0x01 }] mww $CM_DLL_CTRL $dll while { !([ mrw $CM_DLL_CTRL ] & 0x04) } { } config_ddr_ioctrl mww $EMIF_SDRAM_CONFIG_EXT 0xc163 mww $EMIF_IODFT_TLGC 0x2011 mww $EMIF_IODFT_TLGC 0x2411 mww $EMIF_IODFT_TLGC 0x2011 mww $EMIF_SDRAM_REF_CTRL 0x80003000 config_ddr_phy mww $EMIF_IODFT_TLGC 0x2011 mww $EMIF_IODFT_TLGC 0x2411 mww $EMIF_IODFT_TLGC 0x2011 config_ddr_timing config_ddr_pm config_ddr_priority mww $EMIF_SDRAM_REF_CTRL 0x3000 mww $EMIF_SDRAM_CONFIG $SDRAM_CONFIG mww $EMIF_SDRAM_REF_CTRL 0x0c30 mww $EMIF_SDRAM_REF_CTRL_SHDW 0x0c30 sleep 10 set tmp [ expr {[ mrw $EXT_PHY_CTRL_36 ] | 0x0100 }] mww $EXT_PHY_CTRL_36 $tmp mww $EXT_PHY_CTRL_36_SHDW $tmp mww $EMIF_RDWR_LVL_RMP_CTRL 0x80000000 mww $EMIF_RDWR_LVL_CTRL 0x80000000 while { [ mrw $EMIF_RDWR_LVL_CTRL ] & 0x80000000 } { } if { [ mrw $EMIF_STATUS ] & 0x70 } { error "DDR3 Hardware Leveling incomplete!!!" } } proc init_platform { SDRAM_CONFIG } { config_opp100 config_ddr3 $SDRAM_CONFIG } $_TARGETNAME configure -event reset-init { init_platform 0x61a013b2 } $_TARGETNAME configure -event reset-end { disable_watchdog } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/amdm37x.cfg ================================================ # # Copyright (C) 2010-2011 by Karl Kurbjun # Copyright (C) 2009-2011 by Øyvind Harboe # Copyright (C) 2009 by David Brownell # Copyright (C) 2009 by Magnus Lundin # # TI AM/DM37x Technical Reference Manual (Version R) # http://www.ti.com/lit/ug/sprugn4r/sprugn4r.pdf # # This script is based on the AM3517 initialization. It should be considered # preliminary since it needs more complete testing and only the basic # operations work. # ############################################################################### # User modifiable parameters ############################################################################### # This script uses the variable CHIPTYPE to determine whether this is an AM35x # or DM37x target. If CHIPTYPE is not set it will error out. if { [info exists CHIPTYPE] } { if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME $CHIPTYPE } switch $CHIPTYPE { dm37x { # Primary TAP: ICEPick-C (JTAG route controller) and boundary scan set _JRC_TAPID "-expected-id 0x2b89102f -expected-id 0x1b89102f -expected-id 0x0b89102f" } am35x { # Primary TAP: ICEPick-C (JTAG route controller) and boundary scan set _JRC_TAPID "-expected-id 0x0b7ae02f -expected-id 0x0b86802f" } default { error "ERROR: CHIPTYPE was set, but it was not set to a valid value. Acceptable values are \"dm37x\" or \"am35x\"." } } } else { error "ERROR: CHIPTYPE was not defined. Please set CHIPTYPE to \"am35x\" for the AM35x or \"dm37x\" for the DM37x series in the board configuration." } # Run the adapter at the fastest acceptable speed with the slowest possible # core clock. adapter speed 10 ############################################################################### # JTAG setup # The OpenOCD commands are described in the TAP Declaration section # http://openocd.org/doc/html/TAP-Declaration.html ############################################################################### # The AM/DM37x has an ICEPick module in it like many of TI's other devices. More # can be read about this module in sprugn4r in chapter 27: "Debug and # Emulation". The module is used to route the JTAG chain to the various # subsystems in the chip. source [find target/icepick.cfg] # The TAP order should be described from the TDO connection in OpenOCD to the # TDI pin. The OpenOCD FAQ describes this in more detail: # http://openocd.org/doc/html/FAQ.html # From SPRUGN4R CH27 the available secondary TAPs are in this order from TDO: # # Device | TAP number # ---------|------------ # DAP | 3 # Sequencer| 2 Note: The sequencer is an ARM968 # DSP | 1 # D2D | 0 # # Right now the only secondary tap enabled is the DAP so the rest are left # undescribed. ###### # Start of Chain Description # The Secondary TAPs all have enable functions defined for use with the ICEPick # Only the DAP is enabled. The AM37xx does not have the Sequencer or DSP but # the TAP numbers for ICEPick do not change. # # TODO: A disable function should also be added. ###### # Secondary TAP: DAP is closest to the TDO output # The TAP enable event also needs to be described jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -disable jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 3" # These taps are only present in the DM37x series. if { $CHIPTYPE == "dm37x" } { # Secondary TAP: Sequencer (ARM968) it is not in the chain by default # The ICEPick can be used to enable it in the chain. jtag newtap $_CHIPNAME arm2 -irlen 4 -ircapture 0x1 -irmask 0x0f -disable jtag configure $_CHIPNAME.arm2 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 2" # Secondary TAP: C64x+ DSP - it is not in the chain by default (-disable) # The ICEPick can be used to enable it in the chain. jtag newtap $_CHIPNAME dsp -irlen 38 -ircapture 0x25 -irmask 0x3f -disable jtag configure $_CHIPNAME.dsp -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 1" } # Secondary TAP: D2D it is not in the chain by default (-disable) # The ICEPick can be used to enable it in the chain. # This IRLEN is probably incorrect - not sure where the documentation is. jtag newtap $_CHIPNAME d2d -irlen 4 -ircapture 0x1 -irmask 0x0f -disable jtag configure $_CHIPNAME.d2d -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 0" # Primary TAP: ICEPick - it is closest to TDI so last in the chain eval "jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f $_JRC_TAPID" ###### # End of Chain Description ###### ###### # Start JTAG TAP events ###### # some TCK tycles are required to activate the DEBUG power domain jtag configure $_CHIPNAME.jrc -event post-reset "runtest 100" # Enable the DAP TAP jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.dap" ###### # End JTAG TAP events ###### ############################################################################### # Target Setup: # This section is described in the OpenOCD documentation under CPU Configuration # http://openocd.org/doc/html/CPU-Configuration.html ############################################################################### # Create the CPU target to be used with GDB: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # The DM37x has 64K of SRAM starting at address 0x4020_0000. Allow the first # 16K to be used as a scratchpad for OpenOCD. $_TARGETNAME configure -work-area-phys 0x40200000 -work-area-size 0x4000 ###### # Start Target Reset Event Setup: ###### # Set the JTAG clock down to 10 kHz to be sure that it will work with the # slowest possible core clock (16.8MHz/2 = 8.4MHz). It is OK to speed up # *after* PLL and clock tree setup. $_TARGETNAME configure -event "reset-start" { adapter speed 10 } # Describe the reset assert process for openocd - this is asserted with the # ICEPick $_TARGETNAME configure -event "reset-assert" { global _CHIPNAME # assert warm system reset through ICEPick icepick_c_wreset $_CHIPNAME.jrc } # After the reset is asserted we need to re-initialize debugging and speed up # the JTAG clock. $_TARGETNAME configure -event reset-assert-post { global _TARGETNAME amdm37x_dbginit $_TARGETNAME adapter speed 1000 } $_TARGETNAME configure -event gdb-attach { global _TARGETNAME amdm37x_dbginit $_TARGETNAME echo "Halting target" halt } ###### # End Target Reset Event Setup: ###### ############################################################################### # Target Functions # Add any functions needed for the target here ############################################################################### # Run this to enable invasive debugging. This is run automatically in the # reset sequence. proc amdm37x_dbginit {target} { # General Cortex-A8 debug initialisation cortex_a dbginit # Enable DBGEN signal. This signal is described in the ARM v7 TRM, but # access to the signal appears to be implementation specific. TI does not # describe this register much except a quick line that states DBGEM (sic) is # at this address and this bit. $target mww phys 0x5401d030 0x00002000 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ampere_emag.cfg ================================================ # # OpenOCD Target Configuration for eMAG ARMv8 Processor # # Copyright (c) 2019-2021, Ampere Computing LLC # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; # # # # Configure defaults for target # Can be overriden in board configuration file # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME emag } if { [info exists NUMCORES] } { set _NUMCORES $NUMCORES } else { set _NUMCORES 32 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID ] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4BA00477 } # # Configure JTAG TAP # jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x3 -expected-id $_CPUTAPID set _TAPNAME $_CHIPNAME.cpu set _DAPNAME ${_TAPNAME}_dap set _APNUM 1 dap create $_DAPNAME -chain-position $_TAPNAME $_DAPNAME apsel $_APNUM # Create the DAP AP0 MEM-AP AHB-AP target target create AHB mem_ap -endian $_ENDIAN -dap $_DAPNAME -ap-num 0 # Create the DAP AP1 MEM-AP APB-AP target target create APB mem_ap -endian $_ENDIAN -dap $_DAPNAME -ap-num 1 # # Configure target CPUs # # Build string used to enable smp mode set _SMP_STR "target smp" for {set _i 0} {$_i < $_NUMCORES} {incr _i} { # Format a string to reference which CPU target to use set _TARGETNAME [format "${_TAPNAME}_%02d" $_i] # Create and configure Cross Trigger Interface (CTI) - required for halt and resume set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $_DAPNAME -ap-num $_APNUM -baseaddr [expr {0xFC020000 + ($_i << 20)}] # Create the target target create $_TARGETNAME aarch64 -endian $_ENDIAN -dap $_DAPNAME -ap-num $_APNUM -cti $_CTINAME -coreid $_i set _SMP_STR "$_SMP_STR $_TARGETNAME" # Clear CTI output/input enables that are not configured by OpenOCD for aarch64 $_TARGETNAME configure -event examine-start [subst { $_CTINAME write INEN0 0x00000000 $_CTINAME write INEN1 0x00000000 $_CTINAME write INEN2 0x00000000 $_CTINAME write INEN3 0x00000000 $_CTINAME write INEN4 0x00000000 $_CTINAME write INEN5 0x00000000 $_CTINAME write INEN6 0x00000000 $_CTINAME write INEN7 0x00000000 $_CTINAME write INEN8 0x00000000 $_CTINAME write OUTEN2 0x00000000 $_CTINAME write OUTEN3 0x00000000 $_CTINAME write OUTEN4 0x00000000 $_CTINAME write OUTEN5 0x00000000 $_CTINAME write OUTEN6 0x00000000 $_CTINAME write OUTEN7 0x00000000 $_CTINAME write OUTEN8 0x00000000 }] # Enable OpenOCD HWTHREAD RTOS feature for GDB thread (CPU) selection support # This feature presents CPU cores ("hardware threads") in an SMP system as threads to GDB $_TARGETNAME configure -rtos hwthread } eval $_SMP_STR ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ar71xx.cfg ================================================ # Atheros AR71xx MIPS 24Kc SoC. # tested on PB44 refererence board adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst set CHIPNAME ar71xx jtag newtap $CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id 1 set _TARGETNAME $CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-halt-post { #setup PLL to lowest common denominator 300/300/150 setting mww 0xb8050000 0x000f40a3 ;# reset val + CPU:3 DDR:3 AHB:0 mww 0xb8050000 0x800f40a3 ;# send to PLL #next command will reset for PLL changes to take effect mww 0xb8050008 3 ;# set reset_switch and clock_switch (resets SoC) } $_TARGETNAME configure -event reset-init { #complete pll initialization mww 0xb8050000 0x800f0080 ;# set sw_update bit mww 0xb8050008 0 ;# clear reset_switch bit mww 0xb8050000 0x800f00e8 ;# clr pwrdwn & bypass mww 0xb8050008 1 ;# set clock_switch bit sleep 1 ;# wait for lock # Setup DDR config and flash mapping mww 0xb8000000 0xefbc8cd0 ;# DDR cfg cdl val (rst: 0x5bfc8d0) mww 0xb8000004 0x8e7156a2 ;# DDR cfg2 cdl val (rst: 0x80d106a8) mww 0xb8000010 8 ;# force precharge all banks mww 0xb8000010 1 ;# force EMRS update cycle mww 0xb800000c 0 ;# clr ext. mode register mww 0xb8000010 2 ;# force auto refresh all banks mww 0xb8000010 8 ;# force precharge all banks mww 0xb8000008 0x31 ;# set DDR mode value CAS=3 mww 0xb8000010 1 ;# force EMRS update cycle mww 0xb8000014 0x461b ;# DDR refresh value mww 0xb8000018 0xffff ;# DDR Read Data This Cycle value (16bit: 0xffff) mww 0xb800001c 0x7 ;# delay added to the DQS line (normal = 7) mww 0xb8000020 0 mww 0xb8000024 0 mww 0xb8000028 0 } # setup working area somewhere in RAM $_TARGETNAME configure -work-area-phys 0xa0600000 -work-area-size 0x20000 # serial SPI capable flash # flash bank ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/arm_corelink_sse200.cfg ================================================ # # Configuration script for Arm CoreLink SSE-200 Subsystem based IoT SoCs. # global TARGET set TARGET $_CHIPNAME swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # # SRAM on ARM CoreLink SSE-200 can be 4 banks of 8/16/32/64 KB # We will configure work area assuming 8-KB bank size in SRAM bank 1. # Also SRAM start addresses defaults to secure mode alias. # These values can be overridden as per board configuration # global _WORKAREASIZE_CPU0 if { [info exists WORKAREASIZE_CPU0] } { set _WORKAREASIZE_CPU0 $WORKAREASIZE_CPU0 } else { set _WORKAREASIZE_CPU0 0x1000 } global _WORKAREAADDR_CPU0 if { [info exists WORKAREAADDR_CPU0] } { set _WORKAREAADDR_CPU0 $WORKAREAADDR_CPU0 } else { set _WORKAREAADDR_CPU0 0x30008000 } # # Target configuration for Cortex M33 Core 0 on ARM CoreLink SSE-200 # Core 0 is the boot core and will always be configured. # target create ${TARGET}.CPU0 cortex_m -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 ${TARGET}.CPU0 configure -work-area-phys $_WORKAREAADDR_CPU0 -work-area-size $_WORKAREASIZE_CPU0 -work-area-backup 0 ${TARGET}.CPU0 cortex_m reset_config sysresetreq # # Target configuration for Cortex M33 Core 1 on ARM CoreLink SSE-200 # Core 1 is optional and locked at boot until core 0 unlocks it. # if { $_ENABLE_CPU1 } { global _WORKAREASIZE_CPU1 if { [info exists WORKAREASIZE_CPU1] } { set _WORKAREASIZE_CPU1 $WORKAREASIZE_CPU1 } else { set _WORKAREASIZE_CPU1 0x1000 } global _WORKAREAADDR_CPU1 if { [info exists WORKAREAADDR_CPU1] } { set _WORKAREAADDR_CPU1 $WORKAREAADDR_CPU1 } else { set _WORKAREAADDR_CPU1 0x30009000 } target create ${TARGET}.CPU1 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -coreid 1 ${TARGET}.CPU1 configure -work-area-phys $_WORKAREAADDR_CPU1 -work-area-size $_WORKAREASIZE_CPU1 -work-area-backup 0 ${TARGET}.CPU1 cortex_m reset_config vectreset } # Make sure the default target is the boot core targets ${TARGET}.CPU0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/armada370.cfg ================================================ # # armada370 -- support for the Marvell Armada/370 CPU family # # gerg@uclinux.org, OCT-2013 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME armada370 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap proc armada370_dbginit {target} { cortex_a dbginit } $_TARGETNAME configure -event reset-assert-post "armada370_dbginit $_TARGETNAME" dap apsel 1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at32ap7000.cfg ================================================ # Atmel AT32AP7000 # # This is the only core in the now-inactive high end AVR32 product line, # with MMU, Java Acceleration, and "pixel coprocessor". The AP7 line # is for "Application Processors" (AP) with 7-stage pipelines. # # Most current AVR32 parts are in the UC3 flash based microcontroller (UC) # product line with 3-stage pipelines and without those extras. # # All AVR32 parts provide the Nexus Class 3 on-chip debug interfaces # through their JTAG interfaces. jtag newtap ap7 nexus -irlen 5 -expected-id 0x21e8203f # REVISIT declare an avr32 target ... needs OpenOCD infrastructure # for both Nexus (generic) and AVR32 (Atmel-specific). ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91r40008.cfg ================================================ # AT91R40008 target configuration file # TRST is tied to SRST on the AT91X40 family. reset_config srst_only srst_pulls_trst if {[info exists CHIPNAME]} { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91r40008 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Setup the JTAG scan chain. if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x1f0f0f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x20000 -work-area-size 0x20000 -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91rm9200.cfg ================================================ # Atmel AT91rm9200 # http://atmel.com/products/at91/ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91rm9200 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x05b0203f } # Never allow the following! if { $_CPUTAPID == 0x15b0203f } { echo "-------------------------------------------------------" echo "- ERROR: -" echo "- ERROR: TapID 0x15b0203f is wrong for at91rm9200 -" echo "- ERROR: The chip/board has a JTAG select pin/jumper -" echo "- ERROR: -" echo "- ERROR: In one position (0x05b0203f) it selects the -" echo "- ERROR: ARM CPU, in the other position (0x1b0203f) -" echo "- ERROR: it selects boundary-scan not the ARM -" echo "- ERROR: -" echo "-------------------------------------------------------" } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Create the GDB Target. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm920t -endian $_ENDIAN -chain-position $_TARGETNAME # AT91RM9200 has a 16K block of sram @ 0x0020.0000 $_TARGETNAME configure -work-area-phys 0x00200000 \ -work-area-size 0x4000 -work-area-backup 1 # This chip has a DCC ... use it arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam3XXX.cfg ================================================ # script for ATMEL sam3, a Cortex-M3 chip # # at91sam3u4e # at91sam3u2e # at91sam3u1e # at91sam3u4c # at91sam3u2c # at91sam3u1c # # at91sam3s4c # at91sam3s4b # at91sam3s4a # at91sam3s2c # at91sam3s2b # at91sam3s2a # at91sam3s1c # at91sam3s1b # at91sam3s1a # # at91sam3A4C # at91sam3A8C # at91sam3X4C # at91sam3X4E # at91sam3X8C # at91sam3X8E # at91sam3X8H source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sam3 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # By default use 64kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # 16K is plenty, the smallest chip has this much $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 $_TARGETNAME configure -event gdb-flash-erase-start { halt } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 4 MHz, so use F_JTAG = 0.5MHz # # Since we may be running of an RC oscilator, we crank down the speed a # bit more to be on the safe side. Perhaps superstition, but if are # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. adapter speed 500 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam3ax_4x.cfg ================================================ # common stuff source [find target/at91sam3ax_xx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME # This is a 256K chip - it has the 2nd bank set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam3 0x0000A0000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam3ax_8x.cfg ================================================ # common stuff source [find target/at91sam3ax_xx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME # This is a 512K chip - it has the 2nd bank set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam3 0x0000C0000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam3ax_xx.cfg ================================================ # script for ATMEL sam3, a Cortex-M3 chip # # at91sam3A4C # at91sam3A8C # at91sam3X4C # at91sam3X4E # at91sam3X8C # at91sam3X8E # at91sam3X8H source [find target/at91sam3XXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam3nXX.cfg ================================================ # # Configuration for Atmel's SAM3N series # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91sam3n } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap set _FLASHNAME $_CHIPNAME.flash flash bank flash0 at91sam3 0x00400000 0 0 0 $_TARGETNAME if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam3sXX.cfg ================================================ # script for ATMEL sam3, a Cortex-M3 chip # # at91sam3s4c # at91sam3s4b # at91sam3s4a # at91sam3s2c # at91sam3s2b # at91sam3s2a # at91sam3s1c # at91sam3s1b # at91sam3s1a source [find target/at91sam3XXX.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam3 0x00400000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam3u1c.cfg ================================================ # common stuff source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam3u1e.cfg ================================================ # common stuff source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam3u2c.cfg ================================================ # common stuff source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam3u2e.cfg ================================================ # common stuff source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam3u4c.cfg ================================================ # common stuff source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME # This is a 256K chip, it has the 2nd bank set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam3 0x000100000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam3u4e.cfg ================================================ # common stuff source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME # This is a 256K chip - it has the 2nd bank set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam3 0x000100000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam3uxx.cfg ================================================ # script for ATMEL sam3, a Cortex-M3 chip # # at91sam3u4e # at91sam3u2e # at91sam3u1e # at91sam3u4c # at91sam3u2c # at91sam3u1c source [find target/at91sam3XXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam4XXX.cfg ================================================ # # script for ATMEL sam4, a Cortex-M4 chip # # # sam4 devices can support both JTAG and SWD transports. # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sam4 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # By default use 64kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # 16K is plenty, the smallest chip has this much $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # JTAG speed should be <= F_CPU/6. F_CPU after reset is 4 MHz, so use F_JTAG = 0.5MHz # # Since we may be running of an RC oscilator, we crank down the speed a # bit more to be on the safe side. Perhaps superstition, but if are # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. adapter speed 500 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam4c32x.cfg ================================================ # script for ATMEL sam4c32, a Cortex-M4 chip # source [find target/at91sam4XXX.cfg] set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME at91sam4 0x01000000 0 1 1 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam4 0x01100000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam4cXXX.cfg ================================================ # script for ATMEL sam4c, a Cortex-M4 chip # source [find target/at91sam4XXX.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam4 0x01000000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam4lXX.cfg ================================================ # script for ATMEL sam4l, a Cortex-M4 chip # source [find target/at91sam4XXX.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam4l 0x00000000 0 1 1 $_TARGETNAME # SAM4L SMAP will hold the CPU in reset if TCK is low when RESET_N # deasserts (see datasheet 42023E-SAM-07/2013 sec 8.11.3). # # smap_reset_deassert configures whether we want to run or halt out of reset, # then instruct the SMAP to let us out of reset. $_TARGETNAME configure -event reset-deassert-post "at91sam4l smap_reset_deassert" # SRST (wired to RESET_N) resets debug circuitry # srst_pulls_trst is not configured here to avoid an error raised in reset halt reset_config srst_gates_jtag # SAM4L starts from POR with SYSCLK set to 115kHz RCSYS, needs slow JTAG speed. # Datasheet does not specify SYSCLK to JTAG/SWD clock ratio. # Usually used SYSCLK/6 is hell slow, testing shows that debugging can work @ SYSCLK/2 # but your mileage may vary. adapter speed 50 # System RC oscillator RCSYS starts in 3 cycles adapter srst delay 0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam4sXX.cfg ================================================ # script for ATMEL sam4, a Cortex-M4 chip # source [find target/at91sam4XXX.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam4 0x00400000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam4sd32x.cfg ================================================ # script for ATMEL sam4sd32, a Cortex-M4 chip # source [find target/at91sam4XXX.cfg] set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME at91sam4 0x00400000 0 1 1 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam4 0x00500000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam7a2.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91sam7a2 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x1f0f0f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam7se512.cfg ================================================ # ATMEL sam7se512 # Example: the "Elektor Internet Radio" - EIR # http://www.ethernut.de/en/hardware/eir/index.html if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sam7se512 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # Force an error until we get a good number. set _CPUTAPID 0xffffffff } #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only srst_pulls_trst #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # The target set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup 0 #flash bank [ ] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 0 18432 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam7sx.cfg ================================================ #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only srst_pulls_trst if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91sam7s } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-init { soft_reset_halt # RSTC_CR : Reset peripherals mww 0xfffffd00 0xa5000004 # disable watchdog mww 0xfffffd44 0x00008000 # enable user reset mww 0xfffffd08 0xa5000001 # CKGR_MOR : enable the main oscillator mww 0xfffffc20 0x00000601 sleep 10 # CKGR_PLLR: 96.1097 MHz mww 0xfffffc2c 0x00481c0e sleep 10 # PMC_MCKR : MCK = PLL / 2 ~= 48 MHz mww 0xfffffc30 0x00000007 sleep 10 # MC_FMR: flash mode (FWS=1,FMCN=73) mww 0xffffff60 0x00490100 sleep 100 } $_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup 0 #flash bank [ ] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 0 18432 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam7x256.cfg ================================================ #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only srst_pulls_trst if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sam7x256 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-init { # disable watchdog mww 0xfffffd44 0x00008000 # enable user reset mww 0xfffffd08 0xa5000001 # CKGR_MOR : enable the main oscillator mww 0xfffffc20 0x00000601 sleep 10 # CKGR_PLLR: 96.1097 MHz mww 0xfffffc2c 0x00481c0e sleep 10 # PMC_MCKR : MCK = PLL / 2 ~= 48 MHz mww 0xfffffc30 0x00000007 sleep 10 # MC_FMR: flash mode (FWS=1,FMCN=60) mww 0xffffff60 0x003c0100 sleep 100 } $_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup 0 #flash bank [ ] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 0 18432 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam7x512.cfg ================================================ #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only srst_pulls_trst if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sam7x512 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-init { # disable watchdog mww 0xfffffd44 0x00008000 # enable user reset mww 0xfffffd08 0xa5000001 # CKGR_MOR : enable the main oscillator mww 0xfffffc20 0x00000601 sleep 10 # CKGR_PLLR: 96.1097 MHz mww 0xfffffc2c 0x00481c0e sleep 10 # PMC_MCKR : MCK = PLL / 2 ~= 48 MHz mww 0xfffffc30 0x00000007 sleep 10 # MC_FMR: flash mode (FWS=1,FMCN=60) mww 0xffffff60 0x003c0100 sleep 100 } $_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup 0 #flash bank [ ] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME.0 at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 0 18432 flash bank $_FLASHNAME.1 at91sam7 0 0 0 0 $_TARGETNAME 1 0 0 0 0 0 0 18432 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam9.cfg ================================================ ###################################### # Target: Atmel AT91SAM9 ###################################### if { [info exists AT91_CHIPNAME] } { set _CHIPNAME $AT91_CHIPNAME } else { error "you must specify a chip name" } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0792603f } reset_config trst_and_srst separate trst_push_pull srst_open_drain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID adapter srst delay 300 jtag_ntrst_delay 200 adapter speed 3 ###################### # Target configuration ###################### set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam9260.cfg ================================================ ###################################### # Target: Atmel AT91SAM9260 ###################################### if { [info exists CHIPNAME] } { set AT91_CHIPNAME $CHIPNAME } else { set AT91_CHIPNAME at91sam9260 } source [find target/at91sam9.cfg] # Establish internal SRAM memory work areas that are important to pre-bootstrap loaders, etc. The # AT91SAM9260 has two SRAM areas, one starting at 0x00200000 and the other starting at 0x00300000. # Both areas are 4 kB long. #$_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x1000 -work-area-backup 1 $_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x1000 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam9260_ext_RAM_ext_flash.cfg ================================================ ###################################### # Target: Atmel AT91SAM9260 ###################################### source [find target/at91sam9261.cfg] reset_config trst_and_srst adapter speed 4 adapter srst delay 200 jtag_ntrst_delay 200 scan_chain $_TARGETNAME configure -event reset-start { # at reset chip runs at 32khz adapter speed 8 } $_TARGETNAME configure -event reset-init {at91sam_init} # Flash configuration #flash bank cfi set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x10000000 0x01000000 2 2 $_TARGETNAME # Faster memory downloads. This is disabled automatically during # reset init since all reset init sequences are too short for # fast memory access arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable proc at91sam_init { } { mww 0xfffffd08 0xa5000501 ;# RSTC_MR : enable user reset mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog mww 0xfffffc20 0x00004001 ;# CKGR_MOR : enable the main oscillator sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000001 ;# PMC_MCKR : switch to main oscillator sleep 10 ;# wait 10 ms mww 0xfffffc28 0x2060bf09 ;# CKGR_PLLAR: Set PLLA Register for 198,656MHz sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000101 ;# PMC_MCKR : Select prescaler sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000102 ;# PMC_MCKR : Clock from PLLA is selected sleep 10 ;# wait 10 ms # Now run at anything fast... ie: 10mhz! adapter speed 10000 ;# Increase JTAG Speed to 6 MHz mww 0xffffec00 0x0a0a0a0a ;# SMC_SETUP0 : Setup SMC for Intel NOR Flash JS28F128P30T85 128MBit mww 0xffffec04 0x0b0b0b0b ;# SMC_PULSE0 mww 0xffffec08 0x00160016 ;# SMC_CYCLE0 mww 0xffffec0c 0x00161003 ;# SMC_MODE0 mww 0xfffff870 0xffff0000 ;# PIO_ASR : Select peripheral function for D15..D31 mww 0xfffff804 0xffff0000 ;# PIO_PDR : Disable PIO function for D15..D31 mww 0xffffef1c 0x2 ;# EBI_CSA : Assign EBI Chip Select 1 to SDRAM mww 0xffffea08 0x85227259 ;# SDRAMC_CR : Configure SDRAM (2 x Samsung K4S561632H-UC75 : 4M x 16Bit x 4 Banks) #mww 0xffffea08 0x85227254 ;# SDRAMC_CR : Configure SDRAM (2 x Samsung K4S641632H-UC75 : 1M x 16Bit x 4 Banks) mww 0xffffea00 0x1 ;# SDRAMC_MR : issue a NOP command mww 0x20000000 0 mww 0xffffea00 0x2 ;# SDRAMC_MR : issue an 'All Banks Precharge' command mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue 8 x 'Auto-Refresh' Command mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x3 ;# SDRAMC_MR : issue a 'Load Mode Register' command mww 0x20000000 0 mww 0xffffea00 0x0 ;# SDRAMC_MR : normal mode mww 0x20000000 0 mww 0xffffea04 0x5d2 ;# SDRAMC_TR : Set refresh timer count to 15us } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam9261.cfg ================================================ ###################################### # Target: Atmel AT91SAM9261 ###################################### if { [info exists CHIPNAME] } { set AT91_CHIPNAME $CHIPNAME } else { set AT91_CHIPNAME at91sam9261 } source [find target/at91sam9.cfg] # Internal sram1 memory $_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x28000 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam9263.cfg ================================================ ###################################### # Target: Atmel AT91SAM9263 ###################################### if { [info exists CHIPNAME] } { set AT91_CHIPNAME $CHIPNAME } else { set AT91_CHIPNAME at91sam9263 } source [find target/at91sam9.cfg] # Establish internal SRAM memory work areas that are important to pre-bootstrap loaders, etc. The # AT91SAM9263 has two SRAM areas, # one starting at 0x00300000 of 80KiB # and the other starting at 0x00500000 of 16KiB. # Internal sram1 memory $_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x14000 -work-area-backup 1 #$_TARGETNAME configure -work-area-phys 0x00500000 -work-area-size 0x4000 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam9g10.cfg ================================================ ###################################### # Target: Atmel AT91SAM9G10 ###################################### if { [info exists CHIPNAME] } { set AT91_CHIPNAME $CHIPNAME } else { set AT91_CHIPNAME at91sam9g10 } source [find target/at91sam9.cfg] # Establish internal SRAM memory work areas that are important to pre-bootstrap loaders, etc. The # AT91SAM9G10 has one SRAM area at 0x00300000 of 16KiB $_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x4000 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam9g20.cfg ================================================ ###################################### # Target: Atmel AT91SAM9G20 ###################################### if { [info exists CHIPNAME] } { set AT91_CHIPNAME $CHIPNAME } else { set AT91_CHIPNAME at91sam9g20 } source [find target/at91sam9.cfg] # Set fallback clock to 1/6 of worst-case clock speed (which would be the 32.768 kHz slow clock). adapter speed 5 # Establish internal SRAM memory work areas that are important to pre-bootstrap loaders, etc. The # AT91SAM9G20 has two SRAM areas, one starting at 0x00200000 and the other starting at 0x00300000. # Both areas are 16 kB long. #$_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup 1 $_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x4000 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam9g45.cfg ================================================ ###################################### # Target: Atmel AT91SAM9G45 ###################################### if { [info exists CHIPNAME] } { set AT91_CHIPNAME $CHIPNAME } else { set AT91_CHIPNAME at91sam9g45 } source [find target/at91sam9.cfg] # Establish internal SRAM memory work areas that are important to pre-bootstrap loaders, etc. The # AT91SAM9G45 has one SRAM area starting at 0x00300000 of 64 KiB. $_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x200000 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sam9rl.cfg ================================================ ###################################### # Target: Atmel AT91SAM9RL ###################################### if { [info exists CHIPNAME] } { set AT91_CHIPNAME $CHIPNAME } else { set AT91_CHIPNAME at91sam9rl } source [find target/at91sam9.cfg] # Internal sram1 memory $_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x10000 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91sama5d2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # The JTAG connection is disabled at reset, and during the ROM Code execution. # It is re-enabled when the ROM code jumps in the boot file copied from an # external Flash memory into the internalSRAM, or when the ROM code launches # the SAM-BA monitor, when no boot file has been found in any external Flash # memory. # For more JTAG related information see, : # https://ww1.microchip.com/downloads/en/DeviceDoc/SAMA5D2-Series-Data-sheet-ds60001476G.pdf # # If JTAGSEL pin: # - if enabled, boundary Scan mode is activated. JTAG ID Code value is 0x05B3F03F. # - if disabled, ICE mode is activated. Debug Port JTAG IDCODE value is 0x5BA00477 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91sama5d2 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id 0x5ba00477 # Cortex-A5 target set _TARGETNAME $_CHIPNAME.cpu_a5 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME.0 cortex_a -dap $_CHIPNAME.dap ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91samdXX.cfg ================================================ # # script for Atmel SAMD, SAMR, SAML or SAMC, a Cortex-M0 chip # # # samdXX devices only support SWD transports. # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91samd } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # By default use 2kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x800 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # SAMD DSU will hold the CPU in reset if TCK is low when RESET_N # deasserts (see datasheet Atmel-42181E–SAM-D21_Datasheet–02/2015, section 12.6.2) # # dsu_reset_deassert configures whether we want to run or halt out of reset, # then instruct the DSU to let us out of reset. $_TARGETNAME configure -event reset-deassert-post { at91samd dsu_reset_deassert } # SRST (wired to RESET_N) resets debug circuitry # srst_pulls_trst is not configured here to avoid an error raised in reset halt reset_config srst_gates_jtag # Do not use a reset button with other SWD adapter than Atmel's EDBG. # DSU usually locks MCU in reset state until you issue a reset command # in OpenOCD. # SAMD runs at SYSCLK = 1 MHz divided from RC oscillator after reset. # Other members of family usually use SYSCLK = 4 MHz after reset. # Datasheet does not specify SYSCLK to SWD clock ratio. # Usually used SYSCLK/6 is slow, testing shows that debugging can # work @ SYSCLK/2 but your mileage may vary. # This limit is most probably imposed by incorrectly handled SWD WAIT # on some SWD adapters. adapter speed 400 # Atmel's EDBG (on-board cmsis-dap adapter of Xplained kits) works # without problem at maximal clock speed. Atmel recommends # adapter speed less than 10 * CPU clock. # adapter speed 5000 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91samd 0x00000000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/at91samg5x.cfg ================================================ # script for the ATMEL samg5x Cortex-M4F chip family # source [find target/at91sam4XXX.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam4 0x00400000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/atheros_ar2313.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME ar2313 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x00000001 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/atheros_ar2315.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME ar2315 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x00000001 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/atheros_ar9331.cfg ================================================ # The Atheros AR9331 is a highly integrated and cost effective # IEEE 802.11n 1x1 2.4 GHz System- on-a-Chip (SoC) for wireless # local area network (WLAN) AP and router platforms. # # Notes: # - MIPS Processor ID (PRId): 0x00019374 # - 24Kc MIPS processor with 64 KB I-Cache and 32 KB D-Cache, # operating at up to 400 MHz # - External 16-bit DDR1, DDR2, or SDRAM memory interface # - TRST is not available. # - EJTAG PrRst signal is not supported # - RESET_L pin A72 on the SoC will reset internal JTAG logic. # # Pins related for debug and bootstrap: # Name Pin Description # JTAG # JTAG_TCK GPIO0, (A27) Software configurable, default JTAG # JTAG_TDI GPIO6, (B46) Software configurable, default JTAG # JTAG_TDO GPIO7, (A54) Software configurable, default JTAG # JTAG_TMS GPIO8, (A52) Software configurable, default JTAG # Reset # RESET_L -, (A72) Input only # SYS_RST_L ???????? Output reset request or GPIO # Bootstrap # MEM_TYPE[1] GPIO28, (A74) 0 - SDRAM, 1 - DDR1 RAM, 2 - DDR2 RAM # MEM_TYPE[0] GPIO12, (A56) # FW_DOWNLOAD GPIO16, (A75) Used if BOOT_FROM_SPI = 0. 0 - boot from USB # 1 - boot from MDIO. # JTAG_MODE(JS) GPIO11, (B48) 0 - JTAG (Default); 1 - EJTAG # BOOT_FROM_SPI GPIO1, (A77) 0 - ROM boot; 1 - SPI boot # SEL_25M_40M GPIO0, (A78) 0 - 25MHz; 1 - 40MHz # UART # UART0_SOUT GPIO10, (A79) # UART0_SIN GPIO9, (B68) # Per default we need to use "none" variant to be able properly "reset init" # or "reset halt" the CPU. reset_config none srst_pulls_trst # For SRST based variant we still need proper timings. # For ETH part the reset should be asserted at least for 10ms # Since there is no other information let's take 100ms to be sure. adapter srst pulse_width 100 # according to the SoC documentation it should take at least 5ms from # reset end till bootstrap end. In the practice we need 8ms to get JTAG back # to live. adapter srst delay 8 if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME ar9331 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00000001 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME # provide watchdog helper. proc disable_watchdog { } { mww 0xb8060008 0x0 } $_TARGETNAME configure -event halted { disable_watchdog } # Since PrRst is not supported and SRST will reset complete chip # with JTAG engine, we need to reset CPU from CPU itself. $_TARGETNAME configure -event reset-assert-pre { halt } $_TARGETNAME configure -event reset-assert { catch "mww 0xb806001C 0x01000000" } # To be able to trigger complete chip reset, in case JTAG is blocked # or CPU not responding, we still can use this helper. proc full_reset { } { reset_config srst_only reset halt reset_config none } proc disable_watchdog { } { ;# disable watchdog mww 0xb8060008 0x0 } $_TARGETNAME configure -event reset-end { disable_watchdog } # Section with helpers which can be used by boards proc ar9331_25mhz_pll_init {} { mww 0xb8050008 0x00018004 ;# bypass PLL; AHB_POST_DIV - ratio 4 mww 0xb8050004 0x00000352 ;# 34000(ns)/40ns(25MHz) = 0x352 (850) mww 0xb8050000 0x40818000 ;# Power down control for CPU PLL ;# OUTDIV | REFDIV | DIV_INT mww 0xb8050010 0x001003e8 ;# CPU PLL Dither FRAC Register ;# (disabled?) mww 0xb8050000 0x00818000 ;# Power on | OUTDIV | REFDIV | DIV_INT mww 0xb8050008 0x00008000 ;# remove bypass; ;# AHB_POST_DIV - ratio 2 } proc ar9331_ddr1_init {} { mww 0xb8000000 0x7fbc8cd0 ;# DDR_CONFIG - lots of DRAM confs mww 0xb8000004 0x9dd0e6a8 ;# DDR_CONFIG2 - more DRAM confs mww 0xb8000010 0x8 ;# Forces a PRECHARGE ALL cycle mww 0xb8000008 0x133 ;# mode reg: 0x133 - default mww 0xb8000010 0x1 ;# Forces an MRS update cycl mww 0xb800000c 0x2 ;# Extended mode register value. ;# default 0x2 - Reset to weak driver, DLL on mww 0xb8000010 0x2 ;# Forces an EMRS update cycle mww 0xb8000010 0x8 ;# Forces a PRECHARGE ALL cycle mww 0xb8000008 0x33 ;# mode reg: remove some bit? mww 0xb8000010 0x1 ;# Forces an MRS update cycl mww 0xb8000014 0x4186 ;# enable refres: bit(14) - set refresh rate mww 0xb800001c 0x8 ;# This register is used along with DQ Lane 0, ;# DQ[7:0], DQS_0 mww 0xb8000020 0x9 ;# This register is used along with DQ Lane 1, ;# DQ[15:8], DQS_1. mww 0xb8000018 0xff ;# DDR read and capture bit mask. ;# Each bit represents a cycle of valid data. } proc ar9331_ddr2_init {} { mww 0xb8000000 0x7fbc8cd0 ;# DDR_CONFIG - lots of DRAM confs mww 0xb8000004 0x9dd0e6a8 ;# DDR_CONFIG2 - more DRAM confs mww 0xb800008c 0x00000a59 mww 0xb8000010 0x00000008 ;# PRECHARGE ALL cycle mww 0xb8000090 0x00000000 mww 0xb8000010 0x00000010 ;# EMR2S update cycle mww 0xb8000094 0x00000000 mww 0xb8000010 0x00000020 ;# EMR3S update cycle mww 0xb800000c 0x00000000 mww 0xb8000010 0x00000002 ;# EMRS update cycle mww 0xb8000008 0x00000100 mww 0xb8000010 0x00000001 ;# MRS update cycle mww 0xb8000010 0x00000008 ;# PRECHARGE ALL cycle mww 0xb8000010 0x00000004 mww 0xb8000010 0x00000004 ;# AUTO REFRESH cycle mww 0xb8000008 0x00000a33 mww 0xb8000010 0x00000001 ;# MRS update cycle mww 0xb800000c 0x00000382 mww 0xb8000010 0x00000002 ;# EMRS update cycle mww 0xb800000c 0x00000402 mww 0xb8000010 0x00000002 ;# EMRS update cycle mww 0xb8000014 0x00004186 ;# DDR_REFRESH mww 0xb800001c 0x00000008 ;# DDR_TAP_CTRL0 mww 0xb8000020 0x00000009 ;# DDR_TAP_CTRL1 ;# DDR read and capture bit mask. ;# Each bit represents a cycle of valid data. ;# 0xff: use 16-bit DDR mww 0xb8000018 0x000000ff } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/atheros_ar9344.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME ar9344 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x00000001 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME proc test_ar9344_uart0_tx {} { echo "configuring uart0.." mww 0xb802000c 0x87 mww 0xb8020000 0x15 mww 0xb8020004 0 mww 0xb802000c 7 mww 0xb8020004 0 echo "send message: hallo world" mww 0xb8020000 0x68 mww 0xb8020000 0x65 mww 0xb8020000 0x6c mww 0xb8020000 0x6c mww 0xb8020000 0x6f mww 0xb8020000 0x20 mww 0xb8020000 0x77 mww 0xb8020000 0x6f mww 0xb8020000 0x72 mww 0xb8020000 0x6c mww 0xb8020000 0x64 mww 0xb8020000 0x0a } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/atmega128.cfg ================================================ # for avr set _CHIPNAME avr set _ENDIAN little # jtag speed adapter speed 4500 reset_config srst_only adapter srst delay 100 #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x8970203F } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME avr -endian $_ENDIAN -chain-position $_TARGETNAME #$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 16384 -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME avr 0 0 0 0 $_TARGETNAME #to use it, script will be like: #init #adapter speed 4500 #reset init #verify_ircapture disable # #halt #wait halt #poll #avr mass_erase 0 #flash write_image E:/Versaloon/Software/CAMERAPROTOCOLAGENT.hex #reset run #shutdown ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/atmega128rfa1.cfg ================================================ set _CHIPNAME avr set _ENDIAN little # jtag speed adapter speed 4500 # avr jtag docs never connect RSTN reset_config none #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0a70103f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME avr -endian $_ENDIAN -chain-position $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME avr 0 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/atsame5x.cfg ================================================ # # Microchip (former Atmel) SAM E54, E53, E51 and D51 devices # with a Cortex-M4 core # # # Devices only support SWD transports. # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME atsame5 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # By default use 32kB (the smallest RAM size is 128kB) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x8000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # SAM DSU will hold the CPU in reset if TCK is low when RESET_N # deasserts # # dsu_reset_deassert configures whether we want to run or halt out of reset, # then instruct the DSU to let us out of reset. $_TARGETNAME configure -event reset-deassert-post { atsame5 dsu_reset_deassert } # SRST (wired to RESET_N) resets debug circuitry # srst_pulls_trst is not configured here to avoid an error raised in reset halt reset_config srst_gates_jtag # Do not use a reset button with other SWD adapter than Atmel's EDBG. # DSU usually locks MCU in reset state until you issue a reset command # in OpenOCD. # SAM E5x/D51 runs at SYSCLK = 48 MHz from RC oscillator after reset. # Atmel's EDBG (on-board cmsis-dap adapter of Xplained kits) works # without problem at clock speed over 5000 khz. Atmel recommends # adapter speed less than 10 * CPU clock. adapter speed 2000 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME atsame5 0x00000000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/atsaml1x.cfg ================================================ # # Microchip (formerly Atmel) SAM L1x target # # Note: These devices support SWD only. # transport select swd if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME saml1x } if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x800 } swd newdap $_CHIPNAME cpu -expected-id 0x0bf11477 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 if {![using_hla]} { cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/atsamv.cfg ================================================ # ATMEL SAMV, SAMS, and SAME chips are Cortex-M7 parts # The chips are very similar; the SAMV series just has # more peripherals and seems like the "flagship" of the # family. This script will work for all of them. source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME samv } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # By default use 16kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0bd11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20400000 -work-area-size $_WORKAREASIZE -work-area-backup 0 adapter speed 1800 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq # Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal # HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 # makes the data access cacheable. This allows reading and writing data in the # CPU cache from the debugger, which is far more useful than going straight to # RAM when operating on typical variables, and is generally no worse when # operating on special memory locations. $_CHIPNAME.dap apcsw 0x08000000 0x08000000 } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME atsamv 0x00400000 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/avr32.cfg ================================================ set _CHIPNAME avr32 set _ENDIAN big set _CPUTAPID 0x21e8203f adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst separate # jtag scan chain # format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE) jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1 -expected-id $_CPUTAPID set _TARGETNAME [format "%s.cpu" $_CHIPNAME] target create $_TARGETNAME avr32_ap7k -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/bcm2711.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The Broadcom BCM2711 used in Raspberry Pi 4 # No documentation was found on Broadcom website # Partial information is available in raspberry pi website: # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME bcm2711 } if { [info exists CHIPCORES] } { set _cores $CHIPCORES } else { set _cores 4 } if { [info exists USE_SMP] } { set _USE_SMP $USE_SMP } else { set _USE_SMP 0 } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 adapter speed 4000 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # MEM-AP for direct access target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0 # these addresses are obtained from the ROM table via 'dap info 0' command set _DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} set _CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} set _smp_command "target smp" for { set _core 0 } { $_core < $_cores } { incr _core } { set _CTINAME $_CHIPNAME.cti$_core set _TARGETNAME $_CHIPNAME.cpu$_core cti create $_CTINAME -dap $_CHIPNAME.dap -ap-num 0 -baseaddr [lindex $_CTIBASE $_core] target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase [lindex $_DBGBASE $_core] -cti $_CTINAME set _smp_command "$_smp_command $_TARGETNAME" } if {$_USE_SMP} { eval $_smp_command } # default target is cpu0 targets $_CHIPNAME.cpu0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/bcm281xx.cfg ================================================ # BCM281xx if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME bcm281xx } # Main CPU DAP if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 # Dual Cortex-A9 set _TARGETNAME0 $_CHIPNAME.cpu0 set _TARGETNAME1 $_CHIPNAME.cpu1 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME0 cortex_a -dap $_CHIPNAME.dap -coreid 0 -dbgbase 0x3fe10000 target create $_TARGETNAME1 cortex_a -dap $_CHIPNAME.dap -coreid 1 -dbgbase 0x3fe12000 target smp $_TARGETNAME0 $_TARGETNAME1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/bcm2835.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is the Broadcom chip used in the Raspberry Pi Model A, B, B+, # the Compute Module, and the Raspberry Pi Zero. # Partial information is available in raspberry pi website: # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME bcm2835 } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x07b7617F } jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 5 adapter speed 4000 target create $_CHIPNAME.cpu0 arm11 -chain-position $_CHIPNAME.cpu ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/bcm2836.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The Broadcom chip used in the Raspberry Pi 2 Model B # Partial information is available in raspberry pi website: # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME bcm2836 } if { [info exists CHIPCORES] } { set _cores $CHIPCORES } else { set _cores 4 } if { [info exists USE_SMP] } { set _USE_SMP $USE_SMP } else { set _USE_SMP 0 } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 adapter speed 4000 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # MEM-AP for direct access target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0 # these addresses are obtained from the ROM table via 'dap info 0' command set _DBGBASE {0x80010000 0x80012000 0x80014000 0x80016000} set _smp_command "target smp" for { set _core 0 } { $_core < $_cores } { incr _core } { set _TARGETNAME $_CHIPNAME.cpu$_core target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap -coreid $_core -dbgbase [lindex $_DBGBASE $_core] $_TARGETNAME configure -event reset-assert-post { cortex_a dbginit } set _smp_command "$_smp_command $_CHIPNAME.cpu$_core" } if {$_USE_SMP} { eval $_smp_command } # default target is cpu0 targets $_CHIPNAME.cpu0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/bcm2837.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is the Broadcom chip used in the Raspberry Pi 3, # and in later models of the Raspberry Pi 2. # Partial information is available in raspberry pi website: # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837 # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837b0 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME bcm2837 } if { [info exists CHIPCORES] } { set _cores $CHIPCORES } else { set _cores 4 } if { [info exists USE_SMP] } { set _USE_SMP $USE_SMP } else { set _USE_SMP 0 } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 adapter speed 4000 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # MEM-AP for direct access target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0 # these addresses are obtained from the ROM table via 'dap info 0' command set _DBGBASE {0x80010000 0x80012000 0x80014000 0x80016000} set _CTIBASE {0x80018000 0x80019000 0x8001a000 0x8001b000} set _smp_command "target smp" for { set _core 0 } { $_core < $_cores } { incr _core } { set _CTINAME $_CHIPNAME.cti$_core set _TARGETNAME $_CHIPNAME.cpu$_core cti create $_CTINAME -dap $_CHIPNAME.dap -ap-num 0 -baseaddr [lindex $_CTIBASE $_core] target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase [lindex $_DBGBASE $_core] -cti $_CTINAME $_TARGETNAME configure -event reset-assert-post { aarch64 dbginit } set _smp_command "$_smp_command $_TARGETNAME" } if {$_USE_SMP} { eval $_smp_command } # default target is cpu0 targets $_CHIPNAME.cpu0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/bcm4706.cfg ================================================ set _CHIPNAME bcm4706 set _CPUID 0x1008c17f jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian little -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/bcm4718.cfg ================================================ set _CHIPNAME bcm4718 set _LVTAPID 0x1471617f set _CPUID 0x0008c17f source [find target/bcm47xx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/bcm47xx.cfg ================================================ echo "Forcing reset_config to none to prevent OpenOCD from pulling SRST after the switch from LV is already performed" reset_config none jtag newtap $_CHIPNAME-lv tap -irlen 32 -ircapture 0x1 -irmask 0x1f -expected-id $_LVTAPID -expected-id $_CPUID jtag configure $_CHIPNAME-lv.tap -event setup "jtag tapenable $_CHIPNAME.cpu" jtag configure $_CHIPNAME-lv.tap -event tap-disable {} jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUID -disable jtag configure $_CHIPNAME.cpu -event tap-enable "switch_lv_to_ejtag" set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian little -chain-position $_TARGETNAME proc switch_lv_to_ejtag {} { global _CHIPNAME poll 0 irscan $_CHIPNAME-lv.tap 0x143ff3a drscan $_CHIPNAME-lv.tap 32 1 jtag tapdisable $_CHIPNAME-lv.tap poll 1 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/bcm5352e.cfg ================================================ set _CHIPNAME bcm5352e set _CPUID 0x0535217f jtag newtap $_CHIPNAME cpu -irlen 8 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian little -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/bcm6348.cfg ================================================ set _CHIPNAME bcm6348 set _CPUID 0x0634817f adapter speed 1000 jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/bluefield.cfg ================================================ # BlueField SoC Target set _CHIPNAME bluefield # Specify the target device #rshim device /dev/rshim0/rshim # Main DAP if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } adapter speed 1500 swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # Initialize the target name and command variable. set _TARGETNAME $_CHIPNAME.cpu set _smp_command "" # CTI relative address set $_TARGETNAME.cti(0) 0xC4020000 set $_TARGETNAME.cti(1) 0xC4120000 set $_TARGETNAME.cti(2) 0xC8020000 set $_TARGETNAME.cti(3) 0xC8120000 set $_TARGETNAME.cti(4) 0xCC020000 set $_TARGETNAME.cti(5) 0xCC120000 set $_TARGETNAME.cti(6) 0xD0020000 set $_TARGETNAME.cti(7) 0xD0120000 set $_TARGETNAME.cti(8) 0xD4020000 set $_TARGETNAME.cti(9) 0xD4120000 set $_TARGETNAME.cti(10) 0xD8020000 set $_TARGETNAME.cti(11) 0xD8120000 set $_TARGETNAME.cti(12) 0xDC020000 set $_TARGETNAME.cti(13) 0xDC120000 set $_TARGETNAME.cti(14) 0xE0020000 set $_TARGETNAME.cti(15) 0xE0120000 # Create debug targets for a number of cores starting from core '_core_start'. # Adjust the numbers according to board configuration. set _core_start 0 set _cores 16 # Create each core for { set _core $_core_start } { $_core < $_core_start + $_cores } { incr _core 1 } { cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" if { $_core != $_core_start } { set _smp_command "$_smp_command ${_TARGETNAME}$_core" } else { set _smp_command "target smp ${_TARGETNAME}$_core" } eval $_command } # Configure SMP if { $_cores > 1 } { eval $_smp_command } # Make sure the default target is the boot core targets ${_TARGETNAME}0 proc core_up { args } { global _TARGETNAME # Examine remaining cores foreach _core $args { ${_TARGETNAME}$_core arp_examine } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/bluenrg-x.cfg ================================================ # # bluenrg-1/2 and bluenrg-lp devices support only SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME bluenrg-1 } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 24kB-256bytes if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x5F00 } adapter speed 4000 swj_newdap $_CHIPNAME cpu -expected-id 0x0bb11477 -expected-id 0x0bc11477 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu set WDOG_VALUE 0 set WDOG_VALUE_SET 0 target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000100 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME bluenrg-x 0 0 0 0 $_TARGETNAME # In BlueNRG-X reset pin is actually a shutdown (power-off), so define reset as none reset_config none if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } set JTAG_IDCODE_B2 0x0200A041 set JTAG_IDCODE_B1 0x0 $_TARGETNAME configure -event halted { global WDOG_VALUE global WDOG_VALUE_SET set _JTAG_IDCODE [mrw 0x40000004] if {$_JTAG_IDCODE == $JTAG_IDCODE_B2 || $_JTAG_IDCODE == $JTAG_IDCODE_B1} { # Stop watchdog during halt, if enabled. Only Bluenrg-1/2 set WDOG_VALUE [mrw 0x40700008] if [expr {$WDOG_VALUE & (1 << 1)}] { set WDOG_VALUE_SET 1 mww 0x40700008 [expr {$WDOG_VALUE & 0xFFFFFFFD}] } } } $_TARGETNAME configure -event resumed { global WDOG_VALUE global WDOG_VALUE_SET set _JTAG_IDCODE [mrw 0x40000004] if {$_JTAG_IDCODE == $JTAG_IDCODE_B2 || $_JTAG_IDCODE == $JTAG_IDCODE_B1} { if {$WDOG_VALUE_SET} { # Restore watchdog enable value after resume. Only Bluenrg-1/2 mww 0x40700008 $WDOG_VALUE set WDOG_VALUE_SET 0 } } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/c100.cfg ================================================ # c100 config. # This is ARM1136 dual core # this script only configures one core (that is used to run Linux) # assume no PLL lock, start slowly adapter speed 100 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME c100 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x27b3645b } if { [info exists DSPTAPID] } { set _DSPTAPID $DSPTAPID } else { set _DSPTAPID 0x27b3645b } jtag newtap $_CHIPNAME dsp -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_DSPTAPID # Per ARM: DDI0211J_arm1136_r1p5_trm.pdf - the ARM 1136 as a 5 bit IR register jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm11 -endian $_ENDIAN -chain-position $_TARGETNAME # C100's ARAM 64k SRAM $_TARGETNAME configure -work-area-phys 0x0a000000 -work-area-size 0x10000 -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/c100config.tcl ================================================ # board(-config) specific parameters file. # set CFG_REFCLKFREQ [configC100 CFG_REFCLKFREQ] proc config {label} { return [dict get [configC100] $label ] } # show the value for the param. with label proc showconfig {label} { echo [format "0x%x" [dict get [configC100] $label ]] } # Telo board config # when there are more then one board config # use soft links to c100board-config.tcl # so that only the right board-config gets # included (just like include/configs/board-configs.h # in u-boot. proc configC100 {} { # xtal freq. 24MHz dict set configC100 CFG_REFCLKFREQ 24000000 # Amba Clk 165MHz dict set configC100 CONFIG_SYS_HZ_CLOCK 165000000 dict set configC100 w_amba 1 dict set configC100 x_amba 1 # y = amba_clk * (w+1)*(x+1)*2/xtal_clk dict set configC100 y_amba [expr {[dict get $configC100 CONFIG_SYS_HZ_CLOCK] * ( ([dict get $configC100 w_amba]+1 ) * ([dict get $configC100 x_amba]+1 ) *2 ) / [dict get $configC100 CFG_REFCLKFREQ]} ] # Arm Clk 450MHz, must be a multiple of 25 MHz dict set configC100 CFG_ARM_CLOCK 450000000 dict set configC100 w_arm 0 dict set configC100 x_arm 1 # y = arm_clk * (w+1)*(x+1)*2/xtal_clk dict set configC100 y_arm [expr {[dict get $configC100 CFG_ARM_CLOCK] * ( ([dict get $configC100 w_arm]+1 ) * ([dict get $configC100 x_arm]+1 ) *2 ) / [dict get $configC100 CFG_REFCLKFREQ]} ] } # This should be called for reset init event handler proc setupTelo {} { # setup GPIO used as control signals for C100 setupGPIO # This will allow access to lower 8MB or NOR lowGPIO5 # setup NOR size,timing,etc. setupNOR # setup internals + PLL + DDR2 initC100 } proc setupNOR {} { echo "Setting up NOR: 16MB, 16-bit wide bus, CS0" # this is taken from u-boot/boards/mindspeed/ooma-darwin/board.c:nor_hw_init() set EX_CSEN_REG [regs EX_CSEN_REG ] set EX_CS0_SEG_REG [regs EX_CS0_SEG_REG ] set EX_CS0_CFG_REG [regs EX_CS0_CFG_REG ] set EX_CS0_TMG1_REG [regs EX_CS0_TMG1_REG ] set EX_CS0_TMG2_REG [regs EX_CS0_TMG2_REG ] set EX_CS0_TMG3_REG [regs EX_CS0_TMG3_REG ] set EX_CLOCK_DIV_REG [regs EX_CLOCK_DIV_REG ] set EX_MFSM_REG [regs EX_MFSM_REG ] set EX_CSFSM_REG [regs EX_CSFSM_REG ] set EX_WRFSM_REG [regs EX_WRFSM_REG ] set EX_RDFSM_REG [regs EX_RDFSM_REG ] # enable Expansion Bus Clock + CS0 (NOR) mww $EX_CSEN_REG 0x3 # set the address space for CS0=16MB mww $EX_CS0_SEG_REG 0x7ff # set the CS0 bus width to 16-bit mww $EX_CS0_CFG_REG 0x202 # set timings to NOR mww $EX_CS0_TMG1_REG 0x03034006 mww $EX_CS0_TMG2_REG 0x04040002 #mww $EX_CS0_TMG3_REG # set EBUS clock 165/5=33MHz mww $EX_CLOCK_DIV_REG 0x5 # everything else is OK with default } proc bootNOR {} { set EXP_CS0_BASEADDR [regs EXP_CS0_BASEADDR] set BLOCK_RESET_REG [regs BLOCK_RESET_REG] set DDR_RST [regs DDR_RST] # put DDR controller in reset (so that it comes reset in u-boot) mmw $BLOCK_RESET_REG 0x0 $DDR_RST # setup CS0 controller for NOR setupNOR # make sure we are accessing the lower part of NOR lowGPIO5 # set PC to start of NOR (at boot 0x20000000 = 0x0) reg pc $EXP_CS0_BASEADDR # run resume } proc setupGPIO {} { echo "Setting up GPIO block for Telo" # This is current setup for Telo (see sch. for details): #GPIO0 reset for FXS-FXO IC, leave as input, the IC has internal pullup #GPIO1 irq line for FXS-FXO #GPIO5 addr22 for NOR flash (access to upper 8MB) #GPIO17 reset for DECT module. #GPIO29 CS_n for NAND set GPIO_OUTPUT_REG [regs GPIO_OUTPUT_REG] set GPIO_OE_REG [regs GPIO_OE_REG] # set GPIO29=GPIO17=1, GPIO5=0 mww $GPIO_OUTPUT_REG [expr {1<<29 | 1<<17}] # enable [as output] GPIO29,GPIO17,GPIO5 mww $GPIO_OE_REG [expr {1<<29 | 1<<17 | 1<<5}] } proc highGPIO5 {} { echo "GPIO5 high" set GPIO_OUTPUT_REG [regs GPIO_OUTPUT_REG] # set GPIO5=1 mmw $GPIO_OUTPUT_REG [expr {1 << 5}] 0x0 } proc lowGPIO5 {} { echo "GPIO5 low" set GPIO_OUTPUT_REG [regs GPIO_OUTPUT_REG] # set GPIO5=0 mmw $GPIO_OUTPUT_REG 0x0 [expr {1 << 5}] } proc boardID {id} { # so far built: # 4'b1111 dict set boardID 15 name "EVT1" dict set boardID 15 ddr2size 128M # dict set boardID 15 nandsize 1G # dict set boardID 15 norsize 16M # 4'b0000 dict set boardID 0 name "EVT2" dict set boardID 0 ddr2size 128M # 4'b0001 dict set boardID 1 name "EVT3" dict set boardID 1 ddr2size 256M # 4'b1110 dict set boardID 14 name "EVT3_old" dict set boardID 14 ddr2size 128M # 4'b0010 dict set boardID 2 name "EVT4" dict set boardID 2 ddr2size 256M return $boardID } # converted from u-boot/boards/mindspeed/ooma-darwin/board.c:ooma_board_detect() # figure out what board revision this is, uses BOOTSTRAP register to read stuffed resistors proc ooma_board_detect {} { set GPIO_BOOTSTRAP_REG [regs GPIO_BOOTSTRAP_REG] # read the current value of the BOOTSTRAP pins set tmp [mrw $GPIO_BOOTSTRAP_REG] echo [format "GPIO_BOOTSTRAP_REG (0x%x): 0x%x" $GPIO_BOOTSTRAP_REG $tmp] # extract the GPBP bits set gpbt [expr {($tmp &0x1C00) >> 10 | ($tmp & 0x40) >>3}] # display board ID echo [format "This is %s (0x%x)" [dict get [boardID $gpbt] $gpbt name] $gpbt] # show it on serial console putsUART0 [format "This is %s (0x%x)\n" [dict get [boardID $gpbt] $gpbt name] $gpbt] # return the ddr2 size, used to configure DDR2 on a given board. return [dict get [boardID $gpbt] $gpbt ddr2size] } proc configureDDR2regs_256M {} { set DENALI_CTL_00_DATA [regs DENALI_CTL_00_DATA] set DENALI_CTL_01_DATA [regs DENALI_CTL_01_DATA] set DENALI_CTL_02_DATA [regs DENALI_CTL_02_DATA] set DENALI_CTL_03_DATA [regs DENALI_CTL_03_DATA] set DENALI_CTL_04_DATA [regs DENALI_CTL_04_DATA] set DENALI_CTL_05_DATA [regs DENALI_CTL_05_DATA] set DENALI_CTL_06_DATA [regs DENALI_CTL_06_DATA] set DENALI_CTL_07_DATA [regs DENALI_CTL_07_DATA] set DENALI_CTL_08_DATA [regs DENALI_CTL_08_DATA] set DENALI_CTL_09_DATA [regs DENALI_CTL_09_DATA] set DENALI_CTL_10_DATA [regs DENALI_CTL_10_DATA] set DENALI_CTL_11_DATA [regs DENALI_CTL_11_DATA] set DENALI_CTL_12_DATA [regs DENALI_CTL_12_DATA] set DENALI_CTL_13_DATA [regs DENALI_CTL_13_DATA] set DENALI_CTL_14_DATA [regs DENALI_CTL_14_DATA] set DENALI_CTL_15_DATA [regs DENALI_CTL_15_DATA] set DENALI_CTL_16_DATA [regs DENALI_CTL_16_DATA] set DENALI_CTL_17_DATA [regs DENALI_CTL_17_DATA] set DENALI_CTL_18_DATA [regs DENALI_CTL_18_DATA] set DENALI_CTL_19_DATA [regs DENALI_CTL_19_DATA] set DENALI_CTL_20_DATA [regs DENALI_CTL_20_DATA] set DENALI_CTL_02_VAL 0x0100000000010100 set DENALI_CTL_11_VAL 0x433a32164a560a00 mw64bit $DENALI_CTL_00_DATA 0x0100000101010101 # 01_DATA mod [40]=1, enable BA2 mw64bit $DENALI_CTL_01_DATA 0x0100010100000001 mw64bit $DENALI_CTL_02_DATA $DENALI_CTL_02_VAL mw64bit $DENALI_CTL_03_DATA 0x0102020202020201 mw64bit $DENALI_CTL_04_DATA 0x0000010100000001 mw64bit $DENALI_CTL_05_DATA 0x0203010300010101 mw64bit $DENALI_CTL_06_DATA 0x060a020200020202 mw64bit $DENALI_CTL_07_DATA 0x0000000300000206 mw64bit $DENALI_CTL_08_DATA 0x6400003f3f0a0209 mw64bit $DENALI_CTL_09_DATA 0x1a000000001a1a1a mw64bit $DENALI_CTL_10_DATA 0x0120202020191a18 # 11_DATA mod [39-32]=16,more refresh mw64bit $DENALI_CTL_11_DATA $DENALI_CTL_11_VAL mw64bit $DENALI_CTL_12_DATA 0x0000000000000800 mw64bit $DENALI_CTL_13_DATA 0x0010002000100040 mw64bit $DENALI_CTL_14_DATA 0x0010004000100040 mw64bit $DENALI_CTL_15_DATA 0x04f8000000000000 mw64bit $DENALI_CTL_16_DATA 0x000000002cca0000 mw64bit $DENALI_CTL_17_DATA 0x0000000000000000 mw64bit $DENALI_CTL_18_DATA 0x0302000000000000 mw64bit $DENALI_CTL_19_DATA 0x00001300c8030600 mw64bit $DENALI_CTL_20_DATA 0x0000000081fe00c8 set wr_dqs_shift 0x40 # start DDRC mw64bit $DENALI_CTL_02_DATA [expr {$DENALI_CTL_02_VAL | (1 << 32)}] # wait int_status[2] (DRAM init complete) echo -n "Waiting for DDR2 controller to init..." set tmp [mrw [expr {$DENALI_CTL_08_DATA + 4}]] while { [expr {$tmp & 0x040000}] == 0 } { sleep 1 set tmp [mrw [expr {$DENALI_CTL_08_DATA + 4}]] } echo "done." # do ddr2 training sequence # TBD (for now, if you need it, run trainDDR command) } # converted from u-boot/cpu/arm1136/comcerto/bsp100.c:config_board99() # The values are computed based on Mindspeed and Nanya datasheets proc configureDDR2regs_128M {} { set DENALI_CTL_00_DATA [regs DENALI_CTL_00_DATA] set DENALI_CTL_01_DATA [regs DENALI_CTL_01_DATA] set DENALI_CTL_02_DATA [regs DENALI_CTL_02_DATA] set DENALI_CTL_03_DATA [regs DENALI_CTL_03_DATA] set DENALI_CTL_04_DATA [regs DENALI_CTL_04_DATA] set DENALI_CTL_05_DATA [regs DENALI_CTL_05_DATA] set DENALI_CTL_06_DATA [regs DENALI_CTL_06_DATA] set DENALI_CTL_07_DATA [regs DENALI_CTL_07_DATA] set DENALI_CTL_08_DATA [regs DENALI_CTL_08_DATA] set DENALI_CTL_09_DATA [regs DENALI_CTL_09_DATA] set DENALI_CTL_10_DATA [regs DENALI_CTL_10_DATA] set DENALI_CTL_11_DATA [regs DENALI_CTL_11_DATA] set DENALI_CTL_12_DATA [regs DENALI_CTL_12_DATA] set DENALI_CTL_13_DATA [regs DENALI_CTL_13_DATA] set DENALI_CTL_14_DATA [regs DENALI_CTL_14_DATA] set DENALI_CTL_15_DATA [regs DENALI_CTL_15_DATA] set DENALI_CTL_16_DATA [regs DENALI_CTL_16_DATA] set DENALI_CTL_17_DATA [regs DENALI_CTL_17_DATA] set DENALI_CTL_18_DATA [regs DENALI_CTL_18_DATA] set DENALI_CTL_19_DATA [regs DENALI_CTL_19_DATA] set DENALI_CTL_20_DATA [regs DENALI_CTL_20_DATA] set DENALI_CTL_02_VAL 0x0100010000010100 set DENALI_CTL_11_VAL 0x433A42124A650A37 # set some default values mw64bit $DENALI_CTL_00_DATA 0x0100000101010101 mw64bit $DENALI_CTL_01_DATA 0x0100000100000101 mw64bit $DENALI_CTL_02_DATA $DENALI_CTL_02_VAL mw64bit $DENALI_CTL_03_DATA 0x0102020202020201 mw64bit $DENALI_CTL_04_DATA 0x0201010100000201 mw64bit $DENALI_CTL_05_DATA 0x0203010300010101 mw64bit $DENALI_CTL_06_DATA 0x050A020200020202 mw64bit $DENALI_CTL_07_DATA 0x000000030E0B0205 mw64bit $DENALI_CTL_08_DATA 0x6427003F3F0A0209 mw64bit $DENALI_CTL_09_DATA 0x1A00002F00001A00 mw64bit $DENALI_CTL_10_DATA 0x01202020201A1A1A mw64bit $DENALI_CTL_11_DATA $DENALI_CTL_11_VAL mw64bit $DENALI_CTL_12_DATA 0x0000080000000800 mw64bit $DENALI_CTL_13_DATA 0x0010002000100040 mw64bit $DENALI_CTL_14_DATA 0x0010004000100040 mw64bit $DENALI_CTL_15_DATA 0x0508000000000000 mw64bit $DENALI_CTL_16_DATA 0x000020472D200000 mw64bit $DENALI_CTL_17_DATA 0x0000000008000000 mw64bit $DENALI_CTL_18_DATA 0x0302000000000000 mw64bit $DENALI_CTL_19_DATA 0x00001400C8030604 mw64bit $DENALI_CTL_20_DATA 0x00000000823600C8 set wr_dqs_shift 0x40 # start DDRC mw64bit $DENALI_CTL_02_DATA [expr {$DENALI_CTL_02_VAL | (1 << 32)}] # wait int_status[2] (DRAM init complete) echo -n "Waiting for DDR2 controller to init..." set tmp [mrw [expr {$DENALI_CTL_08_DATA + 4}]] while { [expr {$tmp & 0x040000}] == 0 } { sleep 1 set tmp [mrw [expr {$DENALI_CTL_08_DATA + 4}]] } # This is not necessary #mw64bit $DENALI_CTL_11_DATA [expr {($DENALI_CTL_11_VAL & ~0x00007F0000000000) | ($wr_dqs_shift << 40)} ] echo "done." # do ddr2 training sequence # TBD (for now, if you need it, run trainDDR command) } proc setupUART0 {} { # configure UART0 to 115200, 8N1 set GPIO_LOCK_REG [regs GPIO_LOCK_REG] set GPIO_IOCTRL_REG [regs GPIO_IOCTRL_REG] set GPIO_IOCTRL_VAL [regs GPIO_IOCTRL_VAL] set GPIO_IOCTRL_UART0 [regs GPIO_IOCTRL_UART0] set UART0_LCR [regs UART0_LCR] set LCR_DLAB [regs LCR_DLAB] set UART0_DLL [regs UART0_DLL] set UART0_DLH [regs UART0_DLH] set UART0_IIR [regs UART0_IIR] set UART0_IER [regs UART0_IER] set LCR_ONE_STOP [regs LCR_ONE_STOP] set LCR_CHAR_LEN_8 [regs LCR_CHAR_LEN_8] set FCR_XMITRES [regs FCR_XMITRES] set FCR_RCVRRES [regs FCR_RCVRRES] set FCR_FIFOEN [regs FCR_FIFOEN] set IER_UUE [regs IER_UUE] # unlock writing to IOCTRL register mww $GPIO_LOCK_REG $GPIO_IOCTRL_VAL # enable UART0 mmw $GPIO_IOCTRL_REG $GPIO_IOCTRL_UART0 0x0 # baudrate 115200 # This should really be amba_clk/(16*115200) but amba_clk=165MHz set tmp 89 # Enable Divisor Latch access mmw $UART0_LCR $LCR_DLAB 0x0 # set the divisor to $tmp mww $UART0_DLL [expr {$tmp & 0xff}] mww $UART0_DLH [expr {$tmp >> 8}] # Disable Divisor Latch access mmw $UART0_LCR 0x0 $LCR_DLAB # set the UART to 8N1 mmw $UART0_LCR [expr {$LCR_ONE_STOP | $LCR_CHAR_LEN_8} ] 0x0 # reset FIFO mmw $UART0_IIR [expr {$FCR_XMITRES | $FCR_RCVRRES | $FCR_FIFOEN} ] 0x0 # enable FFUART mww $UART0_IER $IER_UUE } proc putcUART0 {char} { set UART0_LSR [regs UART0_LSR] set UART0_THR [regs UART0_THR] set LSR_TEMT [regs LSR_TEMT] # convert the 'char' to digit set tmp [ scan $char %c ] # /* wait for room in the tx FIFO on FFUART */ while {[expr {[mrw $UART0_LSR] & $LSR_TEMT}] == 0} { sleep 1 } mww $UART0_THR $tmp if { $char == "\n" } { putcUART0 \r } } proc putsUART0 {str} { set index 0 set len [string length $str] while { $index < $len } { putcUART0 [string index $str $index] set index [expr {$index + 1}] } } proc trainDDR2 {} { set ARAM_BASEADDR [regs ARAM_BASEADDR] # you must have run 'reset init' or u-boot # load the training code to ARAM load_image ./images/ddr2train.bin $ARAM_BASEADDR bin # set PC to start of NOR (at boot 0x20000000 = 0x0) reg pc $ARAM_BASEADDR # run resume } proc flashUBOOT {file} { # this will update uboot on NOR partition set EXP_CS0_BASEADDR [regs EXP_CS0_BASEADDR] # setup CS0 controller for NOR setupNOR # make sure we are accessing the lower part of NOR lowGPIO5 flash probe 0 echo "Erasing sectors 0-3 for uboot" putsUART0 "Erasing sectors 0-3 for uboot\n" flash erase_sector 0 0 3 echo "Programming u-boot" putsUART0 "Programming u-boot..." arm11 memwrite burst enable flash write_image $file $EXP_CS0_BASEADDR arm11 memwrite burst disable putsUART0 "done.\n" putsUART0 "Rebooting, please wait!\n" reboot } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/c100helper.tcl ================================================ proc helpC100 {} { echo "List of useful functions for C100 processor:" echo "1) reset init: will set up your Telo board" echo "2) setupNOR: will setup NOR access" echo "3) showNOR: will show current NOR config registers for 16-bit, 16MB NOR" echo "4) setupGPIO: will setup GPIOs for Telo board" echo "5) showGPIO: will show current GPIO config registers" echo "6) highGPIO5: will set GPIO5=NOR_addr22=1 to access upper 8MB" echo "7) lowGPIO5: will set GPIO5=NOR_addr22=0 to access lower 8MB" echo "8) showAmbaClk: will show current config registers for Amba Bus Clock" echo "9) setupAmbaClk: will setup Amba Bus Clock=165MHz" echo "10) showArmClk: will show current config registers for Arm Bus Clock" echo "11) setupArmClk: will setup Amba Bus Clock=450MHz" echo "12) ooma_board_detect: will show which version of Telo you have" echo "13) setupDDR2: will configure DDR2 controller, you must have PLLs configured" echo "14) showDDR2: will show DDR2 config registers" echo "15) showWatchdog: will show current register config for watchdog" echo "16) reboot: will trigger watchdog and reboot Telo (hw reset)" echo "17) bootNOR: will boot Telo from NOR" echo "18) setupUART0: will configure UART0 for 115200 8N1, PLLs have to be configured" echo "19) putcUART0: will print a character on UART0" echo "20) putsUART0: will print a string on UART0" echo "21) trainDDR2: will run DDR2 training program" echo "22) flashUBOOT: will program NOR sectors 0-3 with u-boot.bin" } source [find mem_helper.tcl] # read a 64-bit register (memory mapped) proc mr64bit {reg} { return [read_memory $reg 32 2] } # write a 64-bit register (memory mapped) proc mw64bit {reg value} { set high [expr {$value >> 32}] set low [expr {$value & 0xffffffff}] #echo [format "mw64bit(0x%x): 0x%08x%08x" $reg $high $low] mww $reg $low mww [expr {$reg+4}] $high } proc showNOR {} { echo "This is the current NOR setup" set EX_CSEN_REG [regs EX_CSEN_REG ] set EX_CS0_SEG_REG [regs EX_CS0_SEG_REG ] set EX_CS0_CFG_REG [regs EX_CS0_CFG_REG ] set EX_CS0_TMG1_REG [regs EX_CS0_TMG1_REG ] set EX_CS0_TMG2_REG [regs EX_CS0_TMG2_REG ] set EX_CS0_TMG3_REG [regs EX_CS0_TMG3_REG ] set EX_CLOCK_DIV_REG [regs EX_CLOCK_DIV_REG ] set EX_MFSM_REG [regs EX_MFSM_REG ] set EX_CSFSM_REG [regs EX_CSFSM_REG ] set EX_WRFSM_REG [regs EX_WRFSM_REG ] set EX_RDFSM_REG [regs EX_RDFSM_REG ] echo [format "EX_CSEN_REG (0x%x): 0x%x" $EX_CSEN_REG [mrw $EX_CSEN_REG]] echo [format "EX_CS0_SEG_REG (0x%x): 0x%x" $EX_CS0_SEG_REG [mrw $EX_CS0_SEG_REG]] echo [format "EX_CS0_CFG_REG (0x%x): 0x%x" $EX_CS0_CFG_REG [mrw $EX_CS0_CFG_REG]] echo [format "EX_CS0_TMG1_REG (0x%x): 0x%x" $EX_CS0_TMG1_REG [mrw $EX_CS0_TMG1_REG]] echo [format "EX_CS0_TMG2_REG (0x%x): 0x%x" $EX_CS0_TMG2_REG [mrw $EX_CS0_TMG2_REG]] echo [format "EX_CS0_TMG3_REG (0x%x): 0x%x" $EX_CS0_TMG3_REG [mrw $EX_CS0_TMG3_REG]] echo [format "EX_CLOCK_DIV_REG (0x%x): 0x%x" $EX_CLOCK_DIV_REG [mrw $EX_CLOCK_DIV_REG]] echo [format "EX_MFSM_REG (0x%x): 0x%x" $EX_MFSM_REG [mrw $EX_MFSM_REG]] echo [format "EX_CSFSM_REG (0x%x): 0x%x" $EX_CSFSM_REG [mrw $EX_CSFSM_REG]] echo [format "EX_WRFSM_REG (0x%x): 0x%x" $EX_WRFSM_REG [mrw $EX_WRFSM_REG]] echo [format "EX_RDFSM_REG (0x%x): 0x%x" $EX_RDFSM_REG [mrw $EX_RDFSM_REG]] } proc showGPIO {} { echo "This is the current GPIO register setup" # GPIO outputs register set GPIO_OUTPUT_REG [regs GPIO_OUTPUT_REG] # GPIO Output Enable register set GPIO_OE_REG [regs GPIO_OE_REG] set GPIO_HI_INT_ENABLE_REG [regs GPIO_HI_INT_ENABLE_REG] set GPIO_LO_INT_ENABLE_REG [regs GPIO_LO_INT_ENABLE_REG] # GPIO input register set GPIO_INPUT_REG [regs GPIO_INPUT_REG] set APB_ACCESS_WS_REG [regs APB_ACCESS_WS_REG] set MUX_CONF_REG [regs MUX_CONF_REG] set SYSCONF_REG [regs SYSCONF_REG] set GPIO_ARM_ID_REG [regs GPIO_ARM_ID_REG] set GPIO_BOOTSTRAP_REG [regs GPIO_BOOTSTRAP_REG] set GPIO_LOCK_REG [regs GPIO_LOCK_REG] set GPIO_IOCTRL_REG [regs GPIO_IOCTRL_REG] set GPIO_DEVID_REG [regs GPIO_DEVID_REG] echo [format "GPIO_OUTPUT_REG (0x%x): 0x%x" $GPIO_OUTPUT_REG [mrw $GPIO_OUTPUT_REG]] echo [format "GPIO_OE_REG (0x%x): 0x%x" $GPIO_OE_REG [mrw $GPIO_OE_REG]] echo [format "GPIO_HI_INT_ENABLE_REG(0x%x): 0x%x" $GPIO_HI_INT_ENABLE_REG [mrw $GPIO_HI_INT_ENABLE_REG]] echo [format "GPIO_LO_INT_ENABLE_REG(0x%x): 0x%x" $GPIO_LO_INT_ENABLE_REG [mrw $GPIO_LO_INT_ENABLE_REG]] echo [format "GPIO_INPUT_REG (0x%x): 0x%x" $GPIO_INPUT_REG [mrw $GPIO_INPUT_REG]] echo [format "APB_ACCESS_WS_REG (0x%x): 0x%x" $APB_ACCESS_WS_REG [mrw $APB_ACCESS_WS_REG]] echo [format "MUX_CONF_REG (0x%x): 0x%x" $MUX_CONF_REG [mrw $MUX_CONF_REG]] echo [format "SYSCONF_REG (0x%x): 0x%x" $SYSCONF_REG [mrw $SYSCONF_REG]] echo [format "GPIO_ARM_ID_REG (0x%x): 0x%x" $GPIO_ARM_ID_REG [mrw $GPIO_ARM_ID_REG]] echo [format "GPIO_BOOTSTRAP_REG (0x%x): 0x%x" $GPIO_BOOTSTRAP_REG [mrw $GPIO_BOOTSTRAP_REG]] echo [format "GPIO_LOCK_REG (0x%x): 0x%x" $GPIO_LOCK_REG [mrw $GPIO_LOCK_REG]] echo [format "GPIO_IOCTRL_REG (0x%x): 0x%x" $GPIO_IOCTRL_REG [mrw $GPIO_IOCTRL_REG]] echo [format "GPIO_DEVID_REG (0x%x): 0x%x" $GPIO_DEVID_REG [mrw $GPIO_DEVID_REG]] } # converted from u-boot/cpu/arm1136/comcerto/bsp100.c (HAL_get_amba_clk()) proc showAmbaClk {} { set CFG_REFCLKFREQ [config CFG_REFCLKFREQ] set CLKCORE_AHB_CLK_CNTRL [regs CLKCORE_AHB_CLK_CNTRL] set PLL_CLK_BYPASS [regs PLL_CLK_BYPASS] echo [format "CLKCORE_AHB_CLK_CNTRL (0x%x): 0x%x" $CLKCORE_AHB_CLK_CNTRL [mrw $CLKCORE_AHB_CLK_CNTRL]] set value [read_memory $CLKCORE_AHB_CLK_CNTRL 32 1] # see if the PLL is in bypass mode set bypass [expr {($value & $PLL_CLK_BYPASS) >> 24}] echo [format "PLL bypass bit: %d" $bypass] if {$bypass == 1} { echo [format "Amba Clk is set to REFCLK: %d (MHz)" [expr {$CFG_REFCLKFREQ/1000000}]] } else { # nope, extract x,y,w and compute the PLL output freq. set x [expr {($value & 0x0001F0000) >> 16}] echo [format "x: %d" $x] set y [expr {($value & 0x00000007F)}] echo [format "y: %d" $y] set w [expr {($value & 0x000000300) >> 8}] echo [format "w: %d" $w] echo [format "Amba PLL Clk: %d (MHz)" [expr {($CFG_REFCLKFREQ * $y / (($w + 1) * ($x + 1) * 2))/1000000}]] } } # converted from u-boot/cpu/arm1136/comcerto/bsp100.c (HAL_set_amba_clk()) # this clock is useb by all peripherals (DDR2, ethernet, ebus, etc) proc setupAmbaClk {} { set CLKCORE_PLL_STATUS [regs CLKCORE_PLL_STATUS] set CLKCORE_AHB_CLK_CNTRL [regs CLKCORE_AHB_CLK_CNTRL] set ARM_PLL_BY_CTRL [regs ARM_PLL_BY_CTRL] set ARM_AHB_BYP [regs ARM_AHB_BYP] set PLL_DISABLE [regs PLL_DISABLE] set PLL_CLK_BYPASS [regs PLL_CLK_BYPASS] set AHB_PLL_BY_CTRL [regs AHB_PLL_BY_CTRL] set DIV_BYPASS [regs DIV_BYPASS] set AHBCLK_PLL_LOCK [regs AHBCLK_PLL_LOCK] set CFG_REFCLKFREQ [config CFG_REFCLKFREQ] set CONFIG_SYS_HZ_CLOCK [config CONFIG_SYS_HZ_CLOCK] set w [config w_amba] set x [config x_amba] set y [config y_amba] echo [format "Setting Amba PLL to lock to %d MHz" [expr {$CONFIG_SYS_HZ_CLOCK/1000000}]] #echo [format "setupAmbaClk: w= %d" $w] #echo [format "setupAmbaClk: x= %d" $x] #echo [format "setupAmbaClk: y= %d" $y] # set PLL into BYPASS mode using MUX mmw $CLKCORE_AHB_CLK_CNTRL $PLL_CLK_BYPASS 0x0 # do an internal PLL bypass mmw $CLKCORE_AHB_CLK_CNTRL $AHB_PLL_BY_CTRL 0x0 # wait 500us (ARM running @24Mhz -> 12000 cycles => 500us) # openocd smallest resolution is 1ms so, wait 1ms sleep 1 # disable the PLL mmw $CLKCORE_AHB_CLK_CNTRL $PLL_DISABLE 0x0 # wait 1ms sleep 1 # enable the PLL mmw $CLKCORE_AHB_CLK_CNTRL 0x0 $PLL_DISABLE sleep 1 # set X, W and X mmw $CLKCORE_AHB_CLK_CNTRL 0x0 0xFFFFFF mmw $CLKCORE_AHB_CLK_CNTRL [expr {($x << 16) + ($w << 8) + $y}] 0x0 # wait for PLL to lock echo "Waiting for Amba PLL to lock" while {[expr {[mrw $CLKCORE_PLL_STATUS] & $AHBCLK_PLL_LOCK]} == 0} { sleep 1 } # remove the internal PLL bypass mmw $CLKCORE_AHB_CLK_CNTRL 0x0 $AHB_PLL_BY_CTRL # remove PLL from BYPASS mode using MUX mmw $CLKCORE_AHB_CLK_CNTRL 0x0 $PLL_CLK_BYPASS } # converted from u-boot/cpu/arm1136/comcerto/bsp100.c (HAL_get_arm_clk()) proc showArmClk {} { set CFG_REFCLKFREQ [config CFG_REFCLKFREQ] set CLKCORE_ARM_CLK_CNTRL [regs CLKCORE_ARM_CLK_CNTRL] set PLL_CLK_BYPASS [regs PLL_CLK_BYPASS] echo [format "CLKCORE_ARM_CLK_CNTRL (0x%x): 0x%x" $CLKCORE_ARM_CLK_CNTRL [mrw $CLKCORE_ARM_CLK_CNTRL]] set value [read_memory $CLKCORE_ARM_CLK_CNTRL 32 1] # see if the PLL is in bypass mode set bypass [expr {($value & $PLL_CLK_BYPASS) >> 24}] echo [format "PLL bypass bit: %d" $bypass] if {$bypass == 1} { echo [format "Amba Clk is set to REFCLK: %d (MHz)" [expr {$CFG_REFCLKFREQ/1000000}]] } else { # nope, extract x,y,w and compute the PLL output freq. set x [expr {($value & 0x0001F0000) >> 16}] echo [format "x: %d" $x] set y [expr {($value & 0x00000007F)}] echo [format "y: %d" $y] set w [expr {($value & 0x000000300) >> 8}] echo [format "w: %d" $w] echo [format "Arm PLL Clk: %d (MHz)" [expr {($CFG_REFCLKFREQ * $y / (($w + 1) * ($x + 1) * 2))/1000000}]] } } # converted from u-boot/cpu/arm1136/comcerto/bsp100.c (HAL_set_arm_clk()) # Arm Clock is used by two ARM1136 cores proc setupArmClk {} { set CLKCORE_PLL_STATUS [regs CLKCORE_PLL_STATUS] set CLKCORE_ARM_CLK_CNTRL [regs CLKCORE_ARM_CLK_CNTRL] set ARM_PLL_BY_CTRL [regs ARM_PLL_BY_CTRL] set ARM_AHB_BYP [regs ARM_AHB_BYP] set PLL_DISABLE [regs PLL_DISABLE] set PLL_CLK_BYPASS [regs PLL_CLK_BYPASS] set AHB_PLL_BY_CTRL [regs AHB_PLL_BY_CTRL] set DIV_BYPASS [regs DIV_BYPASS] set FCLK_PLL_LOCK [regs FCLK_PLL_LOCK] set CFG_REFCLKFREQ [config CFG_REFCLKFREQ] set CFG_ARM_CLOCK [config CFG_ARM_CLOCK] set w [config w_arm] set x [config x_arm] set y [config y_arm] echo [format "Setting Arm PLL to lock to %d MHz" [expr {$CFG_ARM_CLOCK/1000000}]] #echo [format "setupArmClk: w= %d" $w] #echo [format "setupArmaClk: x= %d" $x] #echo [format "setupArmaClk: y= %d" $y] # set PLL into BYPASS mode using MUX mmw $CLKCORE_ARM_CLK_CNTRL $PLL_CLK_BYPASS 0x0 # do an internal PLL bypass mmw $CLKCORE_ARM_CLK_CNTRL $ARM_PLL_BY_CTRL 0x0 # wait 500us (ARM running @24Mhz -> 12000 cycles => 500us) # openocd smallest resolution is 1ms so, wait 1ms sleep 1 # disable the PLL mmw $CLKCORE_ARM_CLK_CNTRL $PLL_DISABLE 0x0 # wait 1ms sleep 1 # enable the PLL mmw $CLKCORE_ARM_CLK_CNTRL 0x0 $PLL_DISABLE sleep 1 # set X, W and X mmw $CLKCORE_ARM_CLK_CNTRL 0x0 0xFFFFFF mmw $CLKCORE_ARM_CLK_CNTRL [expr {($x << 16) + ($w << 8) + $y}] 0x0 # wait for PLL to lock echo "Waiting for Amba PLL to lock" while {[expr {[mrw $CLKCORE_PLL_STATUS] & $FCLK_PLL_LOCK]} == 0} { sleep 1 } # remove the internal PLL bypass mmw $CLKCORE_ARM_CLK_CNTRL 0x0 $ARM_PLL_BY_CTRL # remove PLL from BYPASS mode using MUX mmw $CLKCORE_ARM_CLK_CNTRL 0x0 $PLL_CLK_BYPASS } proc setupPLL {} { echo "PLLs setup" setupAmbaClk setupArmClk } # converted from u-boot/cpu/arm1136/bsp100.c:SoC_mem_init() proc setupDDR2 {} { echo "Configuring DDR2" set MEMORY_BASE_ADDR [regs MEMORY_BASE_ADDR] set MEMORY_MAX_ADDR [regs MEMORY_MAX_ADDR] set MEMORY_CR [regs MEMORY_CR] set BLOCK_RESET_REG [regs BLOCK_RESET_REG] set DDR_RST [regs DDR_RST] # put DDR controller in reset (so that it is reset and correctly configured) # this is only necessary if DDR was previously confiured # and not reset. mmw $BLOCK_RESET_REG 0x0 $DDR_RST set M [expr {1024 * 1024}] set DDR_SZ_1024M [expr {1024 * $M}] set DDR_SZ_256M [expr {256 * $M}] set DDR_SZ_128M [expr {128 * $M}] set DDR_SZ_64M [expr {64 * $M}] # ooma_board_detect returns DDR2 memory size set tmp [ooma_board_detect] if {$tmp == "128M"} { echo "DDR2 size 128MB" set ddr_size $DDR_SZ_128M } elseif {$tmp == "256M"} { echo "DDR2 size 256MB" set ddr_size $DDR_SZ_256M } else { echo "Don't know how to handle this DDR2 size?" } # Memory setup register mww $MEMORY_MAX_ADDR [expr {($ddr_size - 1) + $MEMORY_BASE_ADDR}] # disable ROM remap mww $MEMORY_CR 0x0 # Take DDR controller out of reset mmw $BLOCK_RESET_REG $DDR_RST 0x0 # min. 20 ops delay sleep 1 # This will setup Denali DDR2 controller if {$tmp == "128M"} { configureDDR2regs_128M } elseif {$tmp == "256M"} { configureDDR2regs_256M } else { echo "Don't know how to configure DDR2 setup?" } } proc showDDR2 {} { set DENALI_CTL_00_DATA [regs DENALI_CTL_00_DATA] set DENALI_CTL_01_DATA [regs DENALI_CTL_01_DATA] set DENALI_CTL_02_DATA [regs DENALI_CTL_02_DATA] set DENALI_CTL_03_DATA [regs DENALI_CTL_03_DATA] set DENALI_CTL_04_DATA [regs DENALI_CTL_04_DATA] set DENALI_CTL_05_DATA [regs DENALI_CTL_05_DATA] set DENALI_CTL_06_DATA [regs DENALI_CTL_06_DATA] set DENALI_CTL_07_DATA [regs DENALI_CTL_07_DATA] set DENALI_CTL_08_DATA [regs DENALI_CTL_08_DATA] set DENALI_CTL_09_DATA [regs DENALI_CTL_09_DATA] set DENALI_CTL_10_DATA [regs DENALI_CTL_10_DATA] set DENALI_CTL_11_DATA [regs DENALI_CTL_11_DATA] set DENALI_CTL_12_DATA [regs DENALI_CTL_12_DATA] set DENALI_CTL_13_DATA [regs DENALI_CTL_13_DATA] set DENALI_CTL_14_DATA [regs DENALI_CTL_14_DATA] set DENALI_CTL_15_DATA [regs DENALI_CTL_15_DATA] set DENALI_CTL_16_DATA [regs DENALI_CTL_16_DATA] set DENALI_CTL_17_DATA [regs DENALI_CTL_17_DATA] set DENALI_CTL_18_DATA [regs DENALI_CTL_18_DATA] set DENALI_CTL_19_DATA [regs DENALI_CTL_19_DATA] set DENALI_CTL_20_DATA [regs DENALI_CTL_20_DATA] set tmp [mr64bit $DENALI_CTL_00_DATA] echo [format "DENALI_CTL_00_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_00_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_01_DATA] echo [format "DENALI_CTL_01_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_01_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_02_DATA] echo [format "DENALI_CTL_02_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_02_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_03_DATA] echo [format "DENALI_CTL_03_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_03_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_04_DATA] echo [format "DENALI_CTL_04_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_04_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_05_DATA] echo [format "DENALI_CTL_05_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_05_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_06_DATA] echo [format "DENALI_CTL_06_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_06_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_07_DATA] echo [format "DENALI_CTL_07_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_07_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_08_DATA] echo [format "DENALI_CTL_08_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_08_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_09_DATA] echo [format "DENALI_CTL_09_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_09_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_10_DATA] echo [format "DENALI_CTL_10_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_10_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_11_DATA] echo [format "DENALI_CTL_11_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_11_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_12_DATA] echo [format "DENALI_CTL_12_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_12_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_13_DATA] echo [format "DENALI_CTL_13_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_13_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_14_DATA] echo [format "DENALI_CTL_14_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_14_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_15_DATA] echo [format "DENALI_CTL_15_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_15_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_16_DATA] echo [format "DENALI_CTL_16_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_16_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_17_DATA] echo [format "DENALI_CTL_17_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_17_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_18_DATA] echo [format "DENALI_CTL_18_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_18_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_19_DATA] echo [format "DENALI_CTL_19_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_19_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_20_DATA] echo [format "DENALI_CTL_20_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_20_DATA $tmp(1) $tmp(0)] } proc initC100 {} { # this follows u-boot/cpu/arm1136/start.S set GPIO_LOCK_REG [regs GPIO_LOCK_REG] set GPIO_IOCTRL_REG [regs GPIO_IOCTRL_REG] set GPIO_IOCTRL_VAL [regs GPIO_IOCTRL_VAL] set APB_ACCESS_WS_REG [regs APB_ACCESS_WS_REG] set ASA_ARAM_BASEADDR [regs ASA_ARAM_BASEADDR] set ASA_ARAM_TC_CR_REG [regs ASA_ARAM_TC_CR_REG] set ASA_EBUS_BASEADDR [regs ASA_EBUS_BASEADDR] set ASA_EBUS_TC_CR_REG [regs ASA_EBUS_TC_CR_REG] set ASA_TC_REQIDMAEN [regs ASA_TC_REQIDMAEN] set ASA_TC_REQTDMEN [regs ASA_TC_REQTDMEN] set ASA_TC_REQIPSECUSBEN [regs ASA_TC_REQIPSECUSBEN] set ASA_TC_REQARM0EN [regs ASA_TC_REQARM0EN] set ASA_TC_REQARM1EN [regs ASA_TC_REQARM1EN] set ASA_TC_REQMDMAEN [regs ASA_TC_REQMDMAEN] set INTC_ARM1_CONTROL_REG [regs INTC_ARM1_CONTROL_REG] # unlock writing to IOCTRL register mww $GPIO_LOCK_REG $GPIO_IOCTRL_VAL # enable address lines A15-A21 mmw $GPIO_IOCTRL_REG 0xf 0x0 # set ARM into supervisor mode (SVC32) # disable IRQ, FIQ # Do I need this in JTAG mode? # it really should be done as 'and ~0x1f | 0xd3 but # openocd does not support this yet reg cpsr 0xd3 # /* # * flush v4 I/D caches # */ # mov r0, #0 # mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ arm mcr 15 0 7 7 0 0x0 # mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ arm mcr 15 0 8 7 0 0x0 # /* # * disable MMU stuff and caches # */ # mrc p15, 0, r0, c1, c0, 0 arm mrc 15 0 1 0 0 # bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) # bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) # orr r0, r0, #0x00000002 @ set bit 2 (A) Align # orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache # orr r0, r0, #0x00400000 @ set bit 22 (U) # mcr p15, 0, r0, c1, c0, 0 arm mcr 15 0 1 0 0 0x401002 # This is from bsp_init() in u-boot/boards/mindspeed/ooma-darwin/board.c # APB init # // Setting APB Bus Wait states to 1, set post write # (*(volatile u32*)(APB_ACCESS_WS_REG)) = 0x40; mww $APB_ACCESS_WS_REG 0x40 # AHB init # // enable all 6 masters for ARAM mmw $ASA_ARAM_TC_CR_REG [expr {$ASA_TC_REQIDMAEN | $ASA_TC_REQTDMEN | $ASA_TC_REQIPSECUSBEN | $ASA_TC_REQARM0EN | $ASA_TC_REQARM1EN | $ASA_TC_REQMDMAEN}] 0x0 # // enable all 6 masters for EBUS mmw $ASA_EBUS_TC_CR_REG [expr {$ASA_TC_REQIDMAEN | $ASA_TC_REQTDMEN | $ASA_TC_REQIPSECUSBEN | $ASA_TC_REQARM0EN | $ASA_TC_REQARM1EN | $ASA_TC_REQMDMAEN}] 0x0 # ARAM init # // disable pipeline mode in ARAM # I don't think this is documented anywhere? mww $INTC_ARM1_CONTROL_REG 0x1 # configure clocks setupPLL # setupUART0 must be run before setupDDR2 as setupDDR2 uses UART. setupUART0 # enable cache # ? (u-boot does nothing here) # DDR2 memory init setupDDR2 putsUART0 "C100 initialization complete.\n" echo "C100 initialization complete." } # show current state of watchdog timer proc showWatchdog {} { set TIMER_WDT_HIGH_BOUND [regs TIMER_WDT_HIGH_BOUND] set TIMER_WDT_CONTROL [regs TIMER_WDT_CONTROL] set TIMER_WDT_CURRENT_COUNT [regs TIMER_WDT_CURRENT_COUNT] echo [format "TIMER_WDT_HIGH_BOUND (0x%x): 0x%x" $TIMER_WDT_HIGH_BOUND [mrw $TIMER_WDT_HIGH_BOUND]] echo [format "TIMER_WDT_CONTROL (0x%x): 0x%x" $TIMER_WDT_CONTROL [mrw $TIMER_WDT_CONTROL]] echo [format "TIMER_WDT_CURRENT_COUNT (0x%x): 0x%x" $TIMER_WDT_CURRENT_COUNT [mrw $TIMER_WDT_CURRENT_COUNT]] } # converted from u-boot/cpu/arm1136/comcerto/intrrupts.c:void reset_cpu (ulong ignored) # this will trigger watchdog reset # the sw. reset does not work on C100 # watchdog reset effectively works as hw. reset proc reboot {} { set TIMER_WDT_HIGH_BOUND [regs TIMER_WDT_HIGH_BOUND] set TIMER_WDT_CONTROL [regs TIMER_WDT_CONTROL] set TIMER_WDT_CURRENT_COUNT [regs TIMER_WDT_CURRENT_COUNT] # allow the counter to count to high value before triggering # this is because register writes are slow over JTAG and # I don't want to miss the high_bound==curr_count condition mww $TIMER_WDT_HIGH_BOUND 0xffffff mww $TIMER_WDT_CURRENT_COUNT 0x0 echo "JTAG speed lowered to 100kHz" adapter speed 100 mww $TIMER_WDT_CONTROL 0x1 # wait until the reset echo -n "Waiting for watchdog to trigger..." #while {[mrw $TIMER_WDT_CONTROL] == 1} { # echo [format "TIMER_WDT_CURRENT_COUNT (0x%x): 0x%x" $TIMER_WDT_CURRENT_COUNT [mrw $TIMER_WDT_CURRENT_COUNT]] # sleep 1 # #} while {[c100.cpu curstate] != "running"} { sleep 1} echo "done." echo [format "Note that C100 is in %s state, type halt to stop" [c100.cpu curstate]] } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/c100regs.tcl ================================================ # Note that I basically converted # u-boot/include/asm-arm/arch/comcerto_100.h # defines # this is a work-around for 'global' not working under Linux # access registers by calling this routine. # For example: # set EX_CS_TMG1_REG [regs EX_CS0_TMG1_REG] proc regs {reg} { return [dict get [regsC100] $reg ] } proc showreg {reg} { echo [format "0x%x" [dict get [regsC100] $reg ]] } proc regsC100 {} { #/* memcore */ #/* device memory base addresses */ #// device memory sizes #/* ARAM SIZE=64K */ dict set regsC100 ARAM_SIZE 0x00010000 dict set regsC100 ARAM_BASEADDR 0x0A000000 #/* Hardware Interface Units */ dict set regsC100 APB_BASEADDR 0x10000000 #/* APB_SIZE=16M address range */ dict set regsC100 APB_SIZE 0x01000000 dict set regsC100 EXP_CS0_BASEADDR 0x20000000 dict set regsC100 EXP_CS1_BASEADDR 0x24000000 dict set regsC100 EXP_CS2_BASEADDR 0x28000000 dict set regsC100 EXP_CS3_BASEADDR 0x2C000000 dict set regsC100 EXP_CS4_BASEADDR 0x30000000 dict set regsC100 DDR_BASEADDR 0x80000000 dict set regsC100 TDM_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x000000}] dict set regsC100 PHI_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x010000}] dict set regsC100 TDMA_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x020000}] dict set regsC100 ASA_DDR_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x040000}] dict set regsC100 ASA_ARAM_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x048000}] dict set regsC100 TIMER_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x050000}] dict set regsC100 ASD_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x060000}] dict set regsC100 GPIO_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x070000}] dict set regsC100 UART0_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x090000}] dict set regsC100 UART1_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x094000}] dict set regsC100 SPI_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x098000}] dict set regsC100 I2C_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x09C000}] dict set regsC100 INTC_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0A0000}] dict set regsC100 CLKCORE_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0B0000}] dict set regsC100 PUI_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0B0000}] dict set regsC100 GEMAC_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0D0000}] dict set regsC100 IDMA_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0E0000}] dict set regsC100 MEMCORE_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0F0000}] dict set regsC100 ASA_EBUS_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x100000}] dict set regsC100 ASA_AAB_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x108000}] dict set regsC100 GEMAC1_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x190000}] dict set regsC100 EBUS_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x1A0000}] dict set regsC100 MDMA_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x1E0000}] #//////////////////////////////////////////////////////////// #// AHB block // #//////////////////////////////////////////////////////////// dict set regsC100 ASA_ARAM_PRI_REG [expr {[dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x00}] dict set regsC100 ASA_ARAM_TC_REG [expr {[dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x04}] dict set regsC100 ASA_ARAM_TC_CR_REG [expr {[dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x08}] dict set regsC100 ASA_ARAM_STAT_REG [expr {[dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x0C}] dict set regsC100 ASA_EBUS_PRI_REG [expr {[dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x00}] dict set regsC100 ASA_EBUS_TC_REG [expr {[dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x04}] dict set regsC100 ASA_EBUS_TC_CR_REG [expr {[dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x08}] dict set regsC100 ASA_EBUS_STAT_REG [expr {[dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x0C}] dict set regsC100 IDMA_MASTER 0 dict set regsC100 TDMA_MASTER 1 dict set regsC100 USBIPSEC_MASTER 2 dict set regsC100 ARM0_MASTER 3 dict set regsC100 ARM1_MASTER 4 dict set regsC100 MDMA_MASTER 5 #define IDMA_PRIORITY(level) (level) #define TDM_PRIORITY(level) (level << 4) #define USBIPSEC_PRIORITY(level) (level << 8) #define ARM0_PRIORITY(level) (level << 12) #define ARM1_PRIORITY(level) (level << 16) #define MDMA_PRIORITY(level) (level << 20) dict set regsC100 ASA_TC_REQIDMAEN [expr {1<<18}] dict set regsC100 ASA_TC_REQTDMEN [expr {1<<19}] dict set regsC100 ASA_TC_REQIPSECUSBEN [expr {1<<20}] dict set regsC100 ASA_TC_REQARM0EN [expr {1<<21}] dict set regsC100 ASA_TC_REQARM1EN [expr {1<<22}] dict set regsC100 ASA_TC_REQMDMAEN [expr {1<<23}] dict set regsC100 MEMORY_BASE_ADDR 0x80000000 dict set regsC100 MEMORY_MAX_ADDR [expr {[dict get $regsC100 ASD_BASEADDR ] + 0x10}] dict set regsC100 MEMORY_CR [expr {[dict get $regsC100 ASD_BASEADDR ] + 0x14}] dict set regsC100 ROM_REMAP_EN 0x1 #define HAL_asb_priority(level) \ #*(volatile unsigned *)ASA_PRI_REG = level #define HAL_aram_priority(level) \ #*(volatile unsigned *)ASA_ARAM_PRI_REG = level #define HAL_aram_arbitration(arbitration_mask) \ #*(volatile unsigned *)ASA_ARAM_TC_CR_REG |= arbitration_mask #define HAL_aram_defmaster(mask) \ #*(volatile unsigned *)ASA_ARAM_TC_CR_REG = (*(volatile unsigned *)ASA_TC_CR_REG & 0xFFFF) | (mask << 24) #//////////////////////////////////////////////////////////// #// INTC block // #//////////////////////////////////////////////////////////// dict set regsC100 INTC_ARM1_CONTROL_REG [expr {[dict get $regsC100 INTC_BASEADDR ] + 0x18}] #//////////////////////////////////////////////////////////// #// TIMER block // #//////////////////////////////////////////////////////////// dict set regsC100 TIMER0_CNTR_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x00}] dict set regsC100 TIMER0_CURR_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x04}] dict set regsC100 TIMER1_CNTR_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x08}] dict set regsC100 TIMER1_CURR_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x0C}] dict set regsC100 TIMER2_CNTR_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x18}] dict set regsC100 TIMER2_LBOUND_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x10}] dict set regsC100 TIMER2_HBOUND_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x14}] dict set regsC100 TIMER2_CURR_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x1C}] dict set regsC100 TIMER3_LOBND [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x20}] dict set regsC100 TIMER3_HIBND [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x24}] dict set regsC100 TIMER3_CTRL [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x28}] dict set regsC100 TIMER3_CURR_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x2C}] dict set regsC100 TIMER_MASK [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x40}] dict set regsC100 TIMER_STATUS [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x50}] dict set regsC100 TIMER_ACK [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x50}] dict set regsC100 TIMER_WDT_HIGH_BOUND [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0xD0}] dict set regsC100 TIMER_WDT_CONTROL [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0xD4}] dict set regsC100 TIMER_WDT_CURRENT_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0xD8}] #//////////////////////////////////////////////////////////// #// EBUS block #//////////////////////////////////////////////////////////// dict set regsC100 EX_SWRST_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x00}] dict set regsC100 EX_CSEN_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x04}] dict set regsC100 EX_CS0_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x08}] dict set regsC100 EX_CS1_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x0C}] dict set regsC100 EX_CS2_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x10}] dict set regsC100 EX_CS3_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x14}] dict set regsC100 EX_CS4_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x18}] dict set regsC100 EX_CS0_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x1C}] dict set regsC100 EX_CS1_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x20}] dict set regsC100 EX_CS2_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x24}] dict set regsC100 EX_CS3_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x28}] dict set regsC100 EX_CS4_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x2C}] dict set regsC100 EX_CS0_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x30}] dict set regsC100 EX_CS1_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x34}] dict set regsC100 EX_CS2_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x38}] dict set regsC100 EX_CS3_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x3C}] dict set regsC100 EX_CS4_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x40}] dict set regsC100 EX_CS0_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x44}] dict set regsC100 EX_CS1_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x48}] dict set regsC100 EX_CS2_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x4C}] dict set regsC100 EX_CS3_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x50}] dict set regsC100 EX_CS4_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x54}] dict set regsC100 EX_CS0_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x58}] dict set regsC100 EX_CS1_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x5C}] dict set regsC100 EX_CS2_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x60}] dict set regsC100 EX_CS3_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x64}] dict set regsC100 EX_CS4_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x68}] dict set regsC100 EX_CLOCK_DIV_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x6C}] dict set regsC100 EX_MFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x100}] dict set regsC100 EX_MFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x100}] dict set regsC100 EX_CSFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x104}] dict set regsC100 EX_WRFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x108}] dict set regsC100 EX_RDFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x10C}] dict set regsC100 EX_CLK_EN 0x00000001 dict set regsC100 EX_CSBOOT_EN 0x00000002 dict set regsC100 EX_CS0_EN 0x00000002 dict set regsC100 EX_CS1_EN 0x00000004 dict set regsC100 EX_CS2_EN 0x00000008 dict set regsC100 EX_CS3_EN 0x00000010 dict set regsC100 EX_CS4_EN 0x00000020 dict set regsC100 EX_MEM_BUS_8 0x00000000 dict set regsC100 EX_MEM_BUS_16 0x00000002 dict set regsC100 EX_MEM_BUS_32 0x00000004 dict set regsC100 EX_CS_HIGH 0x00000008 dict set regsC100 EX_WE_HIGH 0x00000010 dict set regsC100 EX_RE_HIGH 0x00000020 dict set regsC100 EX_ALE_MODE 0x00000040 dict set regsC100 EX_STRB_MODE 0x00000080 dict set regsC100 EX_DM_MODE 0x00000100 dict set regsC100 EX_NAND_MODE 0x00000200 dict set regsC100 EX_RDY_EN 0x00000400 dict set regsC100 EX_RDY_EDGE 0x00000800 #//////////////////////////////////////////////////////////// #// GPIO block #//////////////////////////////////////////////////////////// # GPIO outputs register dict set regsC100 GPIO_OUTPUT_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x00}] # GPIO Output Enable register dict set regsC100 GPIO_OE_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x04}] dict set regsC100 GPIO_HI_INT_ENABLE_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x08}] dict set regsC100 GPIO_LO_INT_ENABLE_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x0C}] # GPIO input register dict set regsC100 GPIO_INPUT_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x10}] dict set regsC100 APB_ACCESS_WS_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x14}] dict set regsC100 MUX_CONF_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x18}] dict set regsC100 SYSCONF_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x1C}] dict set regsC100 GPIO_ARM_ID_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x30}] dict set regsC100 GPIO_BOOTSTRAP_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x40}] dict set regsC100 GPIO_LOCK_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x38}] dict set regsC100 GPIO_IOCTRL_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x44}] dict set regsC100 GPIO_DEVID_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x50}] dict set regsC100 GPIO_IOCTRL_A15A16 0x00000001 dict set regsC100 GPIO_IOCTRL_A17A18 0x00000002 dict set regsC100 GPIO_IOCTRL_A19A21 0x00000004 dict set regsC100 GPIO_IOCTRL_TMREVT0 0x00000008 dict set regsC100 GPIO_IOCTRL_TMREVT1 0x00000010 dict set regsC100 GPIO_IOCTRL_GPBT3 0x00000020 dict set regsC100 GPIO_IOCTRL_I2C 0x00000040 dict set regsC100 GPIO_IOCTRL_UART0 0x00000080 dict set regsC100 GPIO_IOCTRL_UART1 0x00000100 dict set regsC100 GPIO_IOCTRL_SPI 0x00000200 dict set regsC100 GPIO_IOCTRL_HBMODE 0x00000400 dict set regsC100 GPIO_IOCTRL_VAL 0x55555555 dict set regsC100 GPIO_0 0x01 dict set regsC100 GPIO_1 0x02 dict set regsC100 GPIO_2 0x04 dict set regsC100 GPIO_3 0x08 dict set regsC100 GPIO_4 0x10 dict set regsC100 GPIO_5 0x20 dict set regsC100 GPIO_6 0x40 dict set regsC100 GPIO_7 0x80 dict set regsC100 GPIO_RISING_EDGE 1 dict set regsC100 GPIO_FALLING_EDGE 2 dict set regsC100 GPIO_BOTH_EDGES 3 #//////////////////////////////////////////////////////////// #// UART #//////////////////////////////////////////////////////////// dict set regsC100 UART0_RBR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x00}] dict set regsC100 UART0_THR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x00}] dict set regsC100 UART0_DLL [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x00}] dict set regsC100 UART0_IER [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x04}] dict set regsC100 UART0_DLH [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x04}] dict set regsC100 UART0_IIR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x08}] dict set regsC100 UART0_FCR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x08}] dict set regsC100 UART0_LCR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x0C}] dict set regsC100 UART0_MCR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x10}] dict set regsC100 UART0_LSR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x14}] dict set regsC100 UART0_MSR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x18}] dict set regsC100 UART0_SCR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x1C}] dict set regsC100 UART1_RBR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x00}] dict set regsC100 UART1_THR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x00}] dict set regsC100 UART1_DLL [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x00}] dict set regsC100 UART1_IER [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x04}] dict set regsC100 UART1_DLH [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x04}] dict set regsC100 UART1_IIR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x08}] dict set regsC100 UART1_FCR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x08}] dict set regsC100 UART1_LCR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x0C}] dict set regsC100 UART1_MCR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x10}] dict set regsC100 UART1_LSR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x14}] dict set regsC100 UART1_MSR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x18}] dict set regsC100 UART1_SCR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x1C}] # /* default */ dict set regsC100 LCR_CHAR_LEN_5 0x00 dict set regsC100 LCR_CHAR_LEN_6 0x01 dict set regsC100 LCR_CHAR_LEN_7 0x02 dict set regsC100 LCR_CHAR_LEN_8 0x03 #/* One stop bit! - default */ dict set regsC100 LCR_ONE_STOP 0x00 #/* Two stop bit! */ dict set regsC100 LCR_TWO_STOP 0x04 #/* Parity Enable */ dict set regsC100 LCR_PEN 0x08 dict set regsC100 LCR_PARITY_NONE 0x00 #/* Even Parity Select */ dict set regsC100 LCR_EPS 0x10 #/* Enable Parity Stuff */ dict set regsC100 LCR_PS 0x20 #/* Start Break */ dict set regsC100 LCR_SBRK 0x40 #/* Parity Stuff Bit */ dict set regsC100 LCR_PSB 0x80 #/* UART 16550 Divisor Latch Assess */ dict set regsC100 LCR_DLAB 0x80 #/* FIFO Error Status */ dict set regsC100 LSR_FIFOE [expr {1 << 7}] #/* Transmitter Empty */ dict set regsC100 LSR_TEMT [expr {1 << 6}] #/* Transmit Data Request */ dict set regsC100 LSR_TDRQ [expr {1 << 5}] #/* Break Interrupt */ dict set regsC100 LSR_BI [expr {1 << 4}] #/* Framing Error */ dict set regsC100 LSR_FE [expr {1 << 3}] #/* Parity Error */ dict set regsC100 LSR_PE [expr {1 << 2}] #/* Overrun Error */ dict set regsC100 LSR_OE [expr {1 << 1}] #/* Data Ready */ dict set regsC100 LSR_DR [expr {1 << 0}] #/* DMA Requests Enable */ dict set regsC100 IER_DMAE [expr {1 << 7}] #/* UART Unit Enable */ dict set regsC100 IER_UUE [expr {1 << 6}] #/* NRZ coding Enable */ dict set regsC100 IER_NRZE [expr {1 << 5}] #/* Receiver Time Out Interrupt Enable */ dict set regsC100 IER_RTIOE [expr {1 << 4}] #/* Modem Interrupt Enable */ dict set regsC100 IER_MIE [expr {1 << 3}] #/* Receiver Line Status Interrupt Enable */ dict set regsC100 IER_RLSE [expr {1 << 2}] #/* Transmit Data request Interrupt Enable */ dict set regsC100 IER_TIE [expr {1 << 1}] #/* Receiver Data Available Interrupt Enable */ dict set regsC100 IER_RAVIE [expr {1 << 0}] #/* FIFO Mode Enable Status */ dict set regsC100 IIR_FIFOES1 [expr {1 << 7}] #/* FIFO Mode Enable Status */ dict set regsC100 IIR_FIFOES0 [expr {1 << 6}] #/* Time Out Detected */ dict set regsC100 IIR_TOD [expr {1 << 3}] #/* Interrupt Source Encoded */ dict set regsC100 IIR_IID2 [expr {1 << 2}] #/* Interrupt Source Encoded */ dict set regsC100 IIR_IID1 [expr {1 << 1}] #/* Interrupt Pending (active low) */ dict set regsC100 IIR_IP [expr {1 << 0}] #/* UART 16550 FIFO Control Register */ dict set regsC100 FCR_FIFOEN 0x01 dict set regsC100 FCR_RCVRRES 0x02 dict set regsC100 FCR_XMITRES 0x04 #/* Interrupt Enable Register */ #// UART 16550 #// Enable Received Data Available Interrupt dict set regsC100 IER_RXTH 0x01 #// Enable Transmitter Empty Interrupt dict set regsC100 IER_TXTH 0x02 #//////////////////////////////////////////////////////////// #// CLK + RESET block #//////////////////////////////////////////////////////////// dict set regsC100 CLKCORE_ARM_CLK_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x00}] dict set regsC100 CLKCORE_AHB_CLK_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x04}] dict set regsC100 CLKCORE_PLL_STATUS [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x08}] dict set regsC100 CLKCORE_CLKDIV_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x0C}] dict set regsC100 CLKCORE_TDM_CLK_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x10}] dict set regsC100 CLKCORE_FSYNC_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x14}] dict set regsC100 CLKCORE_CLK_PWR_DWN [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x18}] dict set regsC100 CLKCORE_RNG_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x1C}] dict set regsC100 CLKCORE_RNG_STATUS [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x20}] dict set regsC100 CLKCORE_ARM_CLK_CNTRL2 [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x24}] dict set regsC100 CLKCORE_TDM_REF_DIV_RST [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x40}] dict set regsC100 ARM_PLL_BY_CTRL 0x80000000 dict set regsC100 ARM_AHB_BYP 0x04000000 dict set regsC100 PLL_DISABLE 0x02000000 dict set regsC100 PLL_CLK_BYPASS 0x01000000 dict set regsC100 AHB_PLL_BY_CTRL 0x80000000 dict set regsC100 DIV_BYPASS 0x40000000 dict set regsC100 SYNC_MODE 0x20000000 dict set regsC100 EPHY_CLKDIV_BYPASS 0x00200000 dict set regsC100 EPHY_CLKDIV_RATIO_SHIFT 16 dict set regsC100 PUI_CLKDIV_BYPASS 0x00004000 dict set regsC100 PUI_CLKDIV_SRCCLK 0x00002000 dict set regsC100 PUI_CLKDIV_RATIO_SHIFT 8 dict set regsC100 PCI_CLKDIV_BYPASS 0x00000020 dict set regsC100 PCI_CLKDIV_RATIO_SHIFT 0 dict set regsC100 ARM0_CLK_PD 0x00200000 dict set regsC100 ARM1_CLK_PD 0x00100000 dict set regsC100 EPHY_CLK_PD 0x00080000 dict set regsC100 TDM_CLK_PD 0x00040000 dict set regsC100 PUI_CLK_PD 0x00020000 dict set regsC100 PCI_CLK_PD 0x00010000 dict set regsC100 MDMA_AHBCLK_PD 0x00000400 dict set regsC100 I2CSPI_AHBCLK_PD 0x00000200 dict set regsC100 UART_AHBCLK_PD 0x00000100 dict set regsC100 IPSEC_AHBCLK_PD 0x00000080 dict set regsC100 TDM_AHBCLK_PD 0x00000040 dict set regsC100 USB1_AHBCLK_PD 0x00000020 dict set regsC100 USB0_AHBCLK_PD 0x00000010 dict set regsC100 GEMAC1_AHBCLK_PD 0x00000008 dict set regsC100 GEMAC0_AHBCLK_PD 0x00000004 dict set regsC100 PUI_AHBCLK_PD 0x00000002 dict set regsC100 HIF_AHBCLK_PD 0x00000001 dict set regsC100 ARM1_DIV_BP 0x00001000 dict set regsC100 ARM1_DIV_VAL_SHIFT 8 dict set regsC100 ARM0_DIV_BP 0x00000010 dict set regsC100 ARM0_DIV_VAL_SHIFT 0 dict set regsC100 AHBCLK_PLL_LOCK 0x00000002 dict set regsC100 FCLK_PLL_LOCK 0x00000001 #// reset block dict set regsC100 BLOCK_RESET_REG [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x100}] dict set regsC100 CSP_RESET_REG [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x104}] dict set regsC100 RNG_RST 0x1000 dict set regsC100 IPSEC_RST 0x0800 dict set regsC100 DDR_RST 0x0400 dict set regsC100 USB1_PHY_RST 0x0200 dict set regsC100 USB0_PHY_RST 0x0100 dict set regsC100 USB1_RST 0x0080 dict set regsC100 USB0_RST 0x0040 dict set regsC100 GEMAC1_RST 0x0020 dict set regsC100 GEMAC0_RST 0x0010 dict set regsC100 TDM_RST 0x0008 dict set regsC100 PUI_RST 0x0004 dict set regsC100 HIF_RST 0x0002 dict set regsC100 PCI_RST 0x0001 #//////////////////////////////////////////////////////////////// #// DDR CONTROLLER block #//////////////////////////////////////////////////////////////// dict set regsC100 DDR_CONFIG_BASEADDR 0x0D000000 dict set regsC100 DENALI_CTL_00_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x00}] dict set regsC100 DENALI_CTL_01_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x08}] dict set regsC100 DENALI_CTL_02_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x10}] dict set regsC100 DENALI_CTL_03_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x18}] dict set regsC100 DENALI_CTL_04_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x20}] dict set regsC100 DENALI_CTL_05_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x28}] dict set regsC100 DENALI_CTL_06_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x30}] dict set regsC100 DENALI_CTL_07_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x38}] dict set regsC100 DENALI_CTL_08_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x40}] dict set regsC100 DENALI_CTL_09_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x48}] dict set regsC100 DENALI_CTL_10_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x50}] dict set regsC100 DENALI_CTL_11_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x58}] dict set regsC100 DENALI_CTL_12_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x60}] dict set regsC100 DENALI_CTL_13_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x68}] dict set regsC100 DENALI_CTL_14_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x70}] dict set regsC100 DENALI_CTL_15_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x78}] dict set regsC100 DENALI_CTL_16_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x80}] dict set regsC100 DENALI_CTL_17_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x88}] dict set regsC100 DENALI_CTL_18_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x90}] dict set regsC100 DENALI_CTL_19_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x98}] dict set regsC100 DENALI_CTL_20_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0xA0}] # 32-bit value dict set regsC100 DENALI_READY_CHECK [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x44}] # 8-bit dict set regsC100 DENALI_WR_DQS [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x5D}] # 8-bit dict set regsC100 DENALI_DQS_OUT [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x5A}] # 8-bit dict set regsC100 DENALI_DQS_DELAY0 [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x4F}] # 8-bit dict set regsC100 DENALI_DQS_DELAY1 [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] +0x50}] # 8-bit dict set regsC100 DENALI_DQS_DELAY2 [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] +0x51}] # 8-bit dict set regsC100 DENALI_DQS_DELAY3 [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] +0x52}] # end of proc regsC100 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/cc2538.cfg ================================================ # Config for Texas Instruments low power RF SoC CC2538 # http://www.ti.com/lit/pdf/swru319 adapter speed 100 source [find target/icepick.cfg] source [find target/ti-cjtag.cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cc2538 } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x8B96402F } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" # # ICEpick-C (JTAG route controller) # if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x8B96402F } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version # A start sequence is needed to change from cJTAG (Compact JTAG) to # 4-pin JTAG before talking via JTAG commands jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu" jtag configure $_CHIPNAME.jrc -event post-reset "ti_cjtag_to_4pin_jtag $_CHIPNAME.jrc" # # Cortex-M3 target # set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/cs351x.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cs351x } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x00526fa1 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Create the GDB Target. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME fa526 -endian $_ENDIAN -chain-position $_TARGETNAME # There is 16K of SRAM on this chip # FIXME: flash programming is not working by using this work area. So comment this out for now. #$_TARGETNAME configure -work-area-phys 0x00000000 -work-area-size 0x4000 -work-area-backup 1 # This chip has a DCC ... use it arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/davinci.cfg ================================================ # # Utility code for DaVinci-family chips # # davinci_pinmux: assigns PINMUX$reg <== $value proc davinci_pinmux {soc reg value} { mww [expr {[dict get $soc sysbase] + 4 * $reg}] $value } source [find mem_helper.tcl] # # pll_setup: initialize PLL # - pll_addr ... physical addr of controller # - mult ... pll multiplier # - config ... dict mapping { prediv, postdiv, div[1-9] } to dividers # # For PLLs that don't have a given register (e.g. plldiv8), or where a # given divider is non-programmable, caller provides *NO* config mapping. # # PLL version 0x02: tested on dm355 # REVISIT: On dm6446/dm357 the PLLRST polarity is different. proc pll_v02_setup {pll_addr mult config} { set pll_ctrl_addr [expr {$pll_addr + 0x100}] set pll_ctrl [mrw $pll_ctrl_addr] # 1 - clear CLKMODE (bit 8) iff using on-chip oscillator # NOTE: this assumes we should clear that bit set pll_ctrl [expr {$pll_ctrl & ~0x0100}] mww $pll_ctrl_addr $pll_ctrl # 2 - clear PLLENSRC (bit 5) set pll_ctrl [expr {$pll_ctrl & ~0x0020}] mww $pll_ctrl_addr $pll_ctrl # 3 - clear PLLEN (bit 0) ... enter bypass mode set pll_ctrl [expr {$pll_ctrl & ~0x0001}] mww $pll_ctrl_addr $pll_ctrl # 4 - wait at least 4 refclk cycles sleep 1 # 5 - set PLLRST (bit 3) set pll_ctrl [expr {$pll_ctrl | 0x0008}] mww $pll_ctrl_addr $pll_ctrl # 6 - set PLLDIS (bit 4) set pll_ctrl [expr {$pll_ctrl | 0x0010}] mww $pll_ctrl_addr $pll_ctrl # 7 - clear PLLPWRDN (bit 1) set pll_ctrl [expr {$pll_ctrl & ~0x0002}] mww $pll_ctrl_addr $pll_ctrl # 8 - clear PLLDIS (bit 4) set pll_ctrl [expr {$pll_ctrl & ~0x0010}] mww $pll_ctrl_addr $pll_ctrl # 9 - optional: write prediv, postdiv, and pllm # NOTE: for dm355 PLL1, postdiv is controlled via MISC register mww [expr {$pll_addr + 0x0110}] [expr {($mult - 1) & 0xff}] if { [dict exists $config prediv] } { set div [dict get $config prediv] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0114}] $div } if { [dict exists $config postdiv] } { set div [dict get $config postdiv] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0128}] $div } # 10 - optional: set plldiv1, plldiv2, ... # NOTE: this assumes some registers have their just-reset values: # - PLLSTAT.GOSTAT is clear when we enter # - ALNCTL has everything set set go 0 if { [dict exists $config div1] } { set div [dict get $config div1] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0118}] $div set go 1 } if { [dict exists $config div2] } { set div [dict get $config div2] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x011c}] $div set go 1 } if { [dict exists $config div3] } { set div [dict get $config div3] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0120}] $div set go 1 } if { [dict exists $config div4] } { set div [dict get $config div4] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0160}] $div set go 1 } if { [dict exists $config div5] } { set div [dict get $config div5] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0164}] $div set go 1 } if {$go != 0} { # write pllcmd.GO; poll pllstat.GO mww [expr {$pll_addr + 0x0138}] 0x01 set pllstat [expr {$pll_addr + 0x013c}] while {[expr {[mrw $pllstat] & 0x01}] != 0} { sleep 1 } } mww [expr {$pll_addr + 0x0138}] 0x00 # 11 - wait at least 5 usec for reset to finish # (assume covered by overheads including JTAG messaging) # 12 - clear PLLRST (bit 3) set pll_ctrl [expr {$pll_ctrl & ~0x0008}] mww $pll_ctrl_addr $pll_ctrl # 13 - wait at least 8000 refclk cycles for PLL to lock # if we assume 24 MHz (slowest osc), that's 1/3 msec sleep 3 # 14 - set PLLEN (bit 0) ... leave bypass mode set pll_ctrl [expr {$pll_ctrl | 0x0001}] mww $pll_ctrl_addr $pll_ctrl } # PLL version 0x03: tested on dm365 proc pll_v03_setup {pll_addr mult config} { set pll_ctrl_addr [expr {$pll_addr + 0x100}] set pll_secctrl_addr [expr {$pll_addr + 0x108}] set pll_ctrl [mrw $pll_ctrl_addr] # 1 - power up the PLL set pll_ctrl [expr {$pll_ctrl & ~0x0002}] mww $pll_ctrl_addr $pll_ctrl # 2 - clear PLLENSRC (bit 5) set pll_ctrl [expr {$pll_ctrl & ~0x0020}] mww $pll_ctrl_addr $pll_ctrl # 2 - clear PLLEN (bit 0) ... enter bypass mode set pll_ctrl [expr {$pll_ctrl & ~0x0001}] mww $pll_ctrl_addr $pll_ctrl # 3 - wait at least 4 refclk cycles sleep 1 # 4 - set PLLRST (bit 3) set pll_ctrl [expr {$pll_ctrl | 0x0008}] mww $pll_ctrl_addr $pll_ctrl # 5 - wait at least 5 usec sleep 1 # 6 - clear PLLRST (bit 3) set pll_ctrl [expr {$pll_ctrl & ~0x0008}] mww $pll_ctrl_addr $pll_ctrl # 9 - optional: write prediv, postdiv, and pllm mww [expr {$pll_addr + 0x0110}] [expr {($mult / 2) & 0x1ff}] if { [dict exists $config prediv] } { set div [dict get $config prediv] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0114}] $div } if { [dict exists $config postdiv] } { set div [dict get $config postdiv] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0128}] $div } # 10 - write start sequence to PLLSECCTL mww $pll_secctrl_addr 0x00470000 mww $pll_secctrl_addr 0x00460000 mww $pll_secctrl_addr 0x00400000 mww $pll_secctrl_addr 0x00410000 # 11 - optional: set plldiv1, plldiv2, ... # NOTE: this assumes some registers have their just-reset values: # - PLLSTAT.GOSTAT is clear when we enter set aln 0 if { [dict exists $config div1] } { set div [dict get $config div1] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0118}] $div set aln [expr {$aln | 0x1}] } else { mww [expr {$pll_addr + 0x0118}] 0 } if { [dict exists $config div2] } { set div [dict get $config div2] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x011c}] $div set aln [expr {$aln | 0x2}] } else { mww [expr {$pll_addr + 0x011c}] 0 } if { [dict exists $config div3] } { set div [dict get $config div3] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0120}] $div set aln [expr {$aln | 0x4}] } else { mww [expr {$pll_addr + 0x0120}] 0 } if { [dict exists $config oscdiv] } { set div [dict get $config oscdiv] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0124}] $div } else { mww [expr {$pll_addr + 0x0124}] 0 } if { [dict exists $config div4] } { set div [dict get $config div4] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0160}] $div set aln [expr {$aln | 0x8}] } else { mww [expr {$pll_addr + 0x0160}] 0 } if { [dict exists $config div5] } { set div [dict get $config div5] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0164}] $div set aln [expr {$aln | 0x10}] } else { mww [expr {$pll_addr + 0x0164}] 0 } if { [dict exists $config div6] } { set div [dict get $config div6] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0168}] $div set aln [expr {$aln | 0x20}] } else { mww [expr {$pll_addr + 0x0168}] 0 } if { [dict exists $config div7] } { set div [dict get $config div7] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x016c}] $div set aln [expr {$aln | 0x40}] } else { mww [expr {$pll_addr + 0x016c}] 0 } if { [dict exists $config div8] } { set div [dict get $config div8] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0170}] $div set aln [expr {$aln | 0x80}] } else { mww [expr {$pll_addr + 0x0170}] 0 } if { [dict exists $config div9] } { set div [dict get $config div9] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0174}] $div set aln [expr {$aln | 0x100}] } else { mww [expr {$pll_addr + 0x0174}] 0 } if {$aln != 0} { # clear pllcmd.GO mww [expr {$pll_addr + 0x0138}] 0x00 # write alignment flags mww [expr {$pll_addr + 0x0140}] $aln # write pllcmd.GO; poll pllstat.GO mww [expr {$pll_addr + 0x0138}] 0x01 set pllstat [expr {$pll_addr + 0x013c}] while {[expr {[mrw $pllstat] & 0x01}] != 0} { sleep 1 } } mww [expr {$pll_addr + 0x0138}] 0x00 set addr [dict get $config ctladdr] while {[expr {[mrw $addr] & 0x0e000000}] != 0x0e000000} { sleep 1 } # 12 - set PLLEN (bit 0) ... leave bypass mode set pll_ctrl [expr {$pll_ctrl | 0x0001}] mww $pll_ctrl_addr $pll_ctrl } # NOTE: dm6446 requires EMURSTIE set in MDCTL before certain # modules can be enabled. # prepare a non-DSP module to be enabled; finish with psc_go proc psc_enable {module} { set psc_addr 0x01c41000 # write MDCTL mmw [expr {$psc_addr + 0x0a00 + (4 * $module)}] 0x03 0x1f } # prepare a non-DSP module to be reset; finish with psc_go proc psc_reset {module} { set psc_addr 0x01c41000 # write MDCTL mmw [expr {$psc_addr + 0x0a00 + (4 * $module)}] 0x01 0x1f } # execute non-DSP PSC transition(s) set up by psc_enable, psc_reset, etc proc psc_go {} { set psc_addr 0x01c41000 set ptstat_addr [expr {$psc_addr + 0x0128}] # just in case PTSTAT.go isn't clear while { [expr {[mrw $ptstat_addr] & 0x01}] != 0 } { sleep 1 } # write PTCMD.go ... ignoring any DSP power domain mww [expr {$psc_addr + 0x0120}] 1 # wait for PTSTAT.go to clear (again ignoring DSP power domain) while { [expr {[mrw $ptstat_addr] & 0x01}] != 0 } { sleep 1 } } # # A reset using only SRST is a "Warm Reset", resetting everything in the # chip except ARM emulation (and everything _outside_ the chip that hooks # up to SRST). But many boards don't expose SRST via their JTAG connectors # (it's not present on TI-14 headers). # # From the chip-only perspective, a "Max Reset" is a "Warm" reset ... except # without any board-wide side effects, since it's triggered using JTAG using # either (a) ARM watchdog timer, or (b) ICEpick. # proc davinci_wdog_reset {} { set timer2_phys 0x01c21c00 # NOTE -- on entry # - JTAG communication with the ARM *must* be working OK; this # may imply using adaptive clocking or disabling WFI-in-idle # - current target must be the DaVinci ARM # - that ARM core must be halted # - timer2 clock is still enabled (PSC 29 on most chips) # # Part I -- run regardless of being halted via JTAG # # NOTE: for now, we assume there's no DSP that could control the # watchdog; or, equivalently, SUSPSRC.TMR2SRC says the watchdog # suspend signal is controlled via ARM emulation suspend. # # EMUMGT_CLKSPEED: write FREE bit to run despite emulation halt mww phys [expr {$timer2_phys + 0x28}] 0x00004000 # # Part II -- in case watchdog hasn't been set up # # TCR: disable, force internal clock source mww phys [expr {$timer2_phys + 0x20}] 0 # TGCR: reset, force to 64-bit wdog mode, un-reset ("initial" state) mww phys [expr {$timer2_phys + 0x24}] 0 mww phys [expr {$timer2_phys + 0x24}] 0x110b # clear counter (TIM12, TIM34) and period (PRD12, PRD34) registers # so watchdog triggers ASAP mww phys [expr {$timer2_phys + 0x10}] 0 mww phys [expr {$timer2_phys + 0x14}] 0 mww phys [expr {$timer2_phys + 0x18}] 0 mww phys [expr {$timer2_phys + 0x1c}] 0 # WDTCR: put into pre-active state, then active mww phys [expr {$timer2_phys + 0x28}] 0xa5c64000 mww phys [expr {$timer2_phys + 0x28}] 0xda7e4000 # # Part III -- it's ready to rumble # # WDTCR: write invalid WDKEY to trigger reset mww phys [expr {$timer2_phys + 0x28}] 0x00004000 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/dragonite.cfg ================================================ ###################################### # Target: Marvell Dragonite CPU core ###################################### if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dragonite } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x121003d3 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME dragonite -endian $_ENDIAN -chain-position $_TARGETNAME reset_config trst_and_srst adapter srst delay 200 jtag_ntrst_delay 200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/dsp56321.cfg ================================================ # Script for freescale DSP56321 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dsp56321 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a big endian set _ENDIAN big } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x1181501d } #jtag speed adapter speed 4500 #has only srst reset_config srst_only #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 1 -irmask 0x1 -expected-id $_CPUTAPID #target configuration set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME dsp563xx -endian $_ENDIAN -chain-position $_TARGETNAME #working area at base of ram $_TARGETNAME configure -work-area-virt 0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/dsp568013.cfg ================================================ # Script for freescale DSP568013 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dsp568013 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a big endian set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x01f2401d } #jtag speed adapter speed 800 reset_config srst_only #MASTER tap jtag newtap $_CHIPNAME chp -irlen 8 -ircapture 1 -irmask 0x03 -expected-id $_CPUTAPID #CORE tap jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 1 -irmask 0x03 -disable -expected-id 0x02211004 #target configuration - There is only 1 tap at a time, hence only 1 target is defined. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME dsp5680xx -endian $_ENDIAN -chain-position $_TARGETNAME # Setup the interesting tap # Disable polling to be able to get idcode from core tap. If re enabled, can be re enabled, but it should be disabled to correctly unlock flash (operations require certain instruction to be in the IR register during reset, and polling would change this) jtag configure $_CHIPNAME.chp -event setup " jtag tapenable $_TARGETNAME poll off " #select CORE tap by modifying the TLM register. #to be used when MASTER tap is selected. jtag configure $_TARGETNAME -event tap-enable " irscan $_CHIPNAME.chp 0x05; drscan $_CHIPNAME.chp 4 0x02; jtag tapdisable $_CHIPNAME.chp; " #select MASTER tap by modifying the TLM register. #to be used when CORE tap is selected. jtag configure $_CHIPNAME.chp -event tap-enable " irscan $_TARGETNAME 0x08; drscan $_TARGETNAME 4 0x1; jtag tapdisable $_TARGETNAME; " #disables the master tap jtag configure $_TARGETNAME -event tap-disable " " #TODO FIND SMARTER WAY. jtag configure $_CHIPNAME.chp -event tap-disable " " #TODO FIND SMARTER WAY. #working area at base of ram $_TARGETNAME configure -work-area-virt 0 #setup flash set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME dsp5680xx_flash 0 0 2 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/dsp568037.cfg ================================================ # Script for freescale DSP568037 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dsp568037 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a big endian set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x01f2801d } #jtag speed adapter speed 800 reset_config srst_only #MASTER tap jtag newtap $_CHIPNAME chp -irlen 8 -ircapture 1 -irmask 0x03 -expected-id $_CPUTAPID #CORE tap jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 1 -irmask 0x03 -disable -expected-id 0x02211004 #target configuration - There is only 1 tap at a time, hence only 1 target is defined. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME dsp5680xx -endian $_ENDIAN -chain-position $_TARGETNAME # Setup the interesting tap jtag configure $_CHIPNAME.chp -event setup "jtag tapenable $_TARGETNAME" #select CORE tap by modifying the TLM register. #to be used when MASTER tap is selected. jtag configure $_TARGETNAME -event tap-enable " irscan $_CHIPNAME.chp 0x05; drscan $_CHIPNAME.chp 4 0x02; jtag tapdisable $_CHIPNAME.chp; " #select MASTER tap by modifying the TLM register. #to be used when CORE tap is selected. jtag configure $_CHIPNAME.chp -event tap-enable " irscan $_TARGETNAME 0x08; drscan $_TARGETNAME 4 0x1; jtag tapdisable $_TARGETNAME; " #disables the master tap jtag configure $_TARGETNAME -event tap-disable " " #TODO FIND SMARTER WAY. jtag configure $_CHIPNAME.chp -event tap-disable " " #TODO FIND SMARTER WAY. #working area at base of ram $_TARGETNAME configure -work-area-virt 0 #setup flash set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME dsp5680xx_flash 0 0 2 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/efm32.cfg ================================================ # # Silicon Labs (formerly Energy Micro) EFM32 target # # Note: All EFM32 chips have SWD support, but only newer series 1 # chips have JTAG support. # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME efm32 } # Work-area is a space in RAM used for flash programming # By default use 2kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x800 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu adapter speed 1000 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME efm32 0 0 0 0 $_TARGETNAME flash bank userdata.flash efm32 0x0FE00000 0 0 0 $_TARGETNAME flash bank lockbits.flash efm32 0x0FE04000 0 0 0 $_TARGETNAME if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/em357.cfg ================================================ # # Target configuration for the Silicon Labs EM357 chips # # # em357 family supports JTAG and SWD transports # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME em357 } # Work-area is a space in RAM used for flash programming # By default use 4kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x3ba00477 } else { set _CPUTAPID 0x1ba00477 } } if { [info exists BSTAPID] } { set _BSTAPID $BSTAPID } else { set _BSTAPID 0x069a962b } if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME em358 } if { [info exists FLASHSIZE] } { set _FLASHSIZE $FLASHSIZE } else { set _FLASHSIZE 0x30000 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if { [using_jtag] } { jtag newtap $_CHIPNAME bs -irlen 4 -expected-id $_BSTAPID -ircapture 0xe -irmask 0xf } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME em357 0x08000000 $_FLASHSIZE 0 0 $_TARGETNAME if { ![using_hla]} { # according to errata, we need to use vectreset rather than sysresetreq to avoid lockup # There is a bug in the chip, which means that when using external debuggers the chip # may lock up in certain CPU clock modes. Affected modes are operating the CPU at # 24MHz derived from the 24MHz crystal, or 12MHz derived from the high frequency RC # oscillator. If an external debugger tool asserts SYSRESETREQ, the chip will lock up and # require a pin reset or power cycle. # # for details, refer to: # http://www.silabs.com/Support%20Documents/TechnicalDocs/EM35x-Errata.pdf cortex_m reset_config vectreset } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/em358.cfg ================================================ # Target configuration for the Silicon Labs EM358 chips # # em357 family supports JTAG and SWD transports # if { ![info exists CHIPNAME] } { set CHIPNAME em358 } if { ![info exists BSTAPID] } { set BSTAPID 0x069aa62b } # 512K of flash in the em358 chips set FLASHSIZE 0x80000 source [find target/em357.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/eos_s3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # QuickLogic EOS S3 # https://www.quicklogic.com/products/soc/eos-s3-microcontroller/ source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME eos_s3 } if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x80000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap # For now we use SRAM only for software upload $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 adapter speed 4000 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/epc9301.cfg ================================================ # Cirrus Logic EP9301 processor on an Olimex CS-E9301 board. if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ep9301 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # Force an error until we get a good number. set _CPUTAPID 0xffffffff } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID adapter srst delay 100 jtag_ntrst_delay 100 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm920t -endian $_ENDIAN -chain-position $_TARGETNAME -work-area-phys 0x80014000 -work-area-size 0x1000 -work-area-backup 1 #flash configuration #flash bank [driver_options ...] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x60000000 0x1000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/esi32xx.cfg ================================================ # # EnSilica eSi-32xx SoC (eSi-RISC Family) # http://www.ensilica.com/risc-ip/ # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME esi32xx } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x11234001 } jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME esirisc -chain-position $_CHIPNAME.cpu # Targets with the UNIFIED_ADDRESS_SPACE option disabled should set # CACHEARCH to 'harvard'. By default, 'von_neumann' is assumed. if { [info exists CACHEARCH] } { $_TARGETNAME esirisc cache_arch $CACHEARCH } adapter speed 2000 reset_config none # The default linker scripts provided by the eSi-RISC toolchain do not # specify attributes on memory regions, which results in incorrect # application of software breakpoints by GDB. gdb_breakpoint_override hard ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/esp32s2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # The ESP32-S2 only supports JTAG. transport select jtag if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME esp32s2 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x120034e5 } set _TARGETNAME $_CHIPNAME set _CPUNAME cpu set _TAPNAME $_CHIPNAME.$_CPUNAME jtag newtap $_CHIPNAME $_CPUNAME -irlen 5 -expected-id $_CPUTAPID target create $_TARGETNAME esp32s2 -endian little -chain-position $_TAPNAME xtensa maskisr on $_TARGETNAME configure -event reset-assert-post { soft_reset_halt } gdb_breakpoint_override hard ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/exynos5250.cfg ================================================ # # Samsung Exynos 5250 - dual-core ARM Cortex-A15 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME exynos5250 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create ${_TARGETNAME}0 cortex_a -dap $_CHIPNAME.dap target create ${_TARGETNAME}1 cortex_a -dap $_CHIPNAME.dap target smp ${_TARGETNAME}0 ${_TARGETNAME}1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/faux.cfg ================================================ #Script for faux target - used for testing if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91eb40a } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x00000000 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID #target configuration set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME #dummy flash driver set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME faux 0x01000000 0x200000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/feroceon.cfg ================================================ ###################################### # Target: Marvell Feroceon CPU core ###################################### if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME feroceon } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x20a023d3 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME feroceon -endian $_ENDIAN -chain-position $_TARGETNAME reset_config trst_and_srst adapter srst delay 200 jtag_ntrst_delay 200 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/fm3.cfg ================================================ # MB9BF506 # Fujitsu Cortex-M3 with 512kB Flash and 64kB RAM source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME mb9bfxx6 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } # delays on reset lines adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } # Fujitsu Cortex-M3 reset configuration reset_config trst_only swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # MB9BF506 has 64kB of SRAM on its main system bus $_TARGETNAME configure -work-area-phys 0x1FFF8000 -work-area-size 0x10000 -work-area-backup 0 # MB9BF506 has 512kB internal FLASH set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME fm3 0 0 0 0 $_TARGETNAME # 4MHz / 6 = 666kHz, so use 500 adapter speed 500 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/fm4.cfg ================================================ # # Spansion FM4 (ARM Cortex-M4) # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME fm4 } source [find target/swj-dp.tcl] if { [info exists CPUTAPID] } { set _CPU_TAPID $CPUTAPID } elseif { [using_jtag] } { set _CPU_TAPID 0x4ba00477 } else { set _CPU_TAPID 0x2ba01477 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap adapter speed 500 if {![using_hla]} { cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/fm4_mb9bf.cfg ================================================ # # Spansion FM4 MB9BFxxx (ARM Cortex-M4) # source [find target/fm4.cfg] # MB9BF566 M/N/R have 32 KB SRAM0 if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x8000 } $_TARGETNAME configure -work-area-phys [expr {0x20000000 - $_WORKAREASIZE}] \ -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME fm4 0x00000000 0 0 0 $_TARGETNAME $CHIPSERIES ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/fm4_s6e2cc.cfg ================================================ # # Spansion FM4 S6E2CC (ARM Cortex-M4) # source [find target/fm4.cfg] # S6E2CC8 H/J/L have 96 KB SRAM0 if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x18000 } $_TARGETNAME configure -work-area-phys [expr {0x20000000 - $_WORKAREASIZE}] \ -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank ${_FLASHNAME}0 fm4 0x00000000 0 0 0 $_TARGETNAME $CHIPSERIES flash bank ${_FLASHNAME}1 fm4 0x00100000 0 0 0 $_TARGETNAME $CHIPSERIES ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/gd32e23x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for GigaDevice gd32e23x Cortex-M23 Series # https://www.gigadevice.com/microcontroller/gd32e230c8t6/ # # gd32e23x devices support SWD transports only. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME gd32e23x } # Work-area is a space in RAM used for flash programming # By default use 4kB (as found on some GD32E230s) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } # Allow overriding the Flash bank size if { [info exists FLASH_SIZE] } { set _FLASH_SIZE $FLASH_SIZE } else { # autodetect size set _FLASH_SIZE 0 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # this is the SW-DP tap id not the jtag tap id set _CPUTAPID 0x0bf11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME # SWD speed (may be updated to higher value in board config file) adapter speed 1000 reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event examine-end { # Debug clock enable # RCU_APB2EN |= DBGMCUEN mmw 0x40021018 0x00400000 0 # Stop watchdog counters during halt # DBG_CTL0 |= WWDGT_HOLD | FWDGT_HOLD | STB_HOLD | DSLP_HOLD | SLP_HOLD mmw 0x40015804 0x00000307 0 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/gd32vf103.cfg ================================================ # # GigaDevice GD32VF103 target # # https://www.gigadevice.com/products/microcontrollers/gd32/risc-v/ # source [find mem_helper.tcl] transport select jtag if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME gd32vf103 } # The smallest RAM size 6kB (GD32VF103C4/T4/R4) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1800 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f1x 0x08000000 0 0 0 $_TARGETNAME # DBGMCU_CR register cannot be set in examine-end event as the running RISC-V CPU # does not allow the debugger to access memory. # Stop watchdogs at least before flash programming. $_TARGETNAME configure -event reset-init { # DBGMCU_CR |= DBG_WWDG_STOP | DBG_IWDG_STOP mmw 0xE0042004 0x00000300 0 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/gp326xxxa.cfg ================================================ # # Support for General Plus GP326XXXA chips # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME gp326xxxa } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4f1f0f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME # Use internal SRAM as a work area $_TARGETNAME configure -work-area-phys 0xf8000000 -work-area-size 0x8000 -work-area-backup 0 # The chip has both lines connected together reset_config trst_and_srst srst_pulls_trst # This delay is needed otherwise communication with the target would # be unreliable adapter srst delay 100 # Set the adapter speed ridiculously low just in case we are # running off of a 32kHz clock adapter speed 2 proc gp32xxxa_halt_and_reset_control_registers {} { # System control registers set P_SYSTEM_CTRL_NEW 0xD0000008 set P_SYSTEM_CTRL 0xD000000C set P_SYSTEM_CLK_EN0 0xD0000010 set P_SYSTEM_CLK_EN1 0xD0000014 set P_SYSTEM_RESET_FLAG 0xD0000018 set P_SYSTEM_CLK_CTRL 0xD000001C set P_SYSTEM_LVR_CTRL 0xD0000020 set P_SYSTEM_WATCHDOG_CTRL 0xD0000024 set P_SYSTEM_PLLEN 0xD000005C # Since we can't use SRST without pulling TRST # we can't assume the state of the clock configuration # or watchdog settings. So reset them before porceeding # Set the adapter speed ridiculously low just in case we are # running off of a 32kHz clock adapter speed 2 # Disable any advanced features at this stage arm7_9 dcc_downloads disable arm7_9 fast_memory_access disable # Do a "soft reset" soft_reset_halt # Reset all system control registers to their default "after-reset" values mwh $P_SYSTEM_WATCHDOG_CTRL 0x0000 mwh $P_SYSTEM_LVR_CTRL 0x0000 mwh $P_SYSTEM_CTRL_NEW 0x0001 mwh $P_SYSTEM_CTRL 0x0001 # Clear all reset flags by writing 1's mwh $P_SYSTEM_RESET_FLAG 0x001C mwh $P_SYSTEM_CLK_CTRL 0x8000 mwh $P_SYSTEM_CLK_EN0 0xFFFF mwh $P_SYSTEM_CLK_EN1 0xFFFF mwh $P_SYSTEM_PLLEN 0x0010 # Unfortunately there's no register that would allow us to # know if PLL is locked. So just wait for 100ms in hopes that # it would be enough. sleep 100 # Now that we know that we are running at 48Mhz # Increase JTAG speed and enable speed optimization features adapter speed 5000 arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable } $_TARGETNAME configure -event reset-end { gp32xxxa_halt_and_reset_control_registers } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/hi3798.cfg ================================================ # Hisilicon Hi3798 Target if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME hi3798 } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } # declare the one JTAG tap to access the DAP jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # declare the 4 main application cores set _TARGETNAME $_CHIPNAME.cpu set _smp_command "" set $_TARGETNAME.cti(0) 0x80020000 set $_TARGETNAME.cti(1) 0x80120000 set $_TARGETNAME.cti(2) 0x80220000 set $_TARGETNAME.cti(3) 0x80320000 set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" if { $_core != 0 } { # non-boot core examination may fail #set _command "$_command -defer-examine" set _smp_command "$_smp_command ${_TARGETNAME}$_core" } else { # uncomment when "hawt" rtos is merged # set _command "$_command -rtos hawt" set _smp_command "target smp ${_TARGETNAME}$_core" } eval $_command } eval $_smp_command ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/hi6220.cfg ================================================ # Hisilicon Hi6220 Target if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME hi6220 } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } # declare the one JTAG tap to access the DAP jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version # create the DAP dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap # declare the 8 main application cores set _TARGETNAME $_CHIPNAME.cpu set _smp_command "" set $_TARGETNAME.cti(0) 0x80198000 set $_TARGETNAME.cti(1) 0x80199000 set $_TARGETNAME.cti(2) 0x8019A000 set $_TARGETNAME.cti(3) 0x8019B000 set $_TARGETNAME.cti(4) 0x801D8000 set $_TARGETNAME.cti(5) 0x801D9000 set $_TARGETNAME.cti(6) 0x801DA000 set $_TARGETNAME.cti(7) 0x801DB000 set _cores 8 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" if { $_core != 0 } { # non-boot core examination may fail set _command "$_command -defer-examine" set _smp_command "$_smp_command ${_TARGETNAME}$_core" } else { # uncomment when "hawt" rtos is merged # set _command "$_command -rtos hawt" set _smp_command "target smp ${_TARGETNAME}$_core" } eval $_command } eval $_smp_command cti create cti.sys -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80003000 # declare the auxiliary Cortex-M3 core on AP #2 (runs mcuimage.bin) target create ${_TARGETNAME}.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -defer-examine # declare the auxiliary Cortex-A7 core target create ${_TARGETNAME}.a7 cortex_a -dap $_CHIPNAME.dap -dbgbase 0x80210000 -defer-examine ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/hilscher_netx10.cfg ================================================ ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ #Hilscher netX 10 CPU if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME netx10 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x25966021 } # jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # that TAP is associated with a target set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/hilscher_netx50.cfg ================================================ ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ #Hilscher netX 50 CPU if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME netx50 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x25966021 } # jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # that TAP is associated with a target set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME # On netX50 SDRAM is not accessible at offset 0xDEAD0-0xDEADF as it is busy from # DMA controller at init. This function will setup a dummy DMA to free this ares # and must be called before using SDRAM proc sdram_fix { } { mww 0x1c005830 0x00000001 mww 0x1c005104 0xBFFFFFFC mww 0x1c00510c 0x00480001 mww 0x1c005110 0x00000001 sleep 100 mww 0x1c00510c 0 mww 0x1c005110 0 mww 0x1c005830 0x00000000 puts "SDRAM Fix executed!" } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/hilscher_netx500.cfg ================================================ #Hilscher netX 500 CPU if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME netx500 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926021 } # jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # that TAP is associated with a target set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME proc mread32 {addr} { return [read_memory $addr 32 1] } # This function must be called on netX100/500 right after halt # If it is called later the needed register cannot be written anymore proc sdram_fix { } { set accesskey [mread32 0x00100070] mww 0x00100070 $accesskey mww 0x0010002c 0x00000001 if {[expr {[mread32 0x0010002c] & 0x07}] == 0x07} { puts "SDRAM Fix was not executed. Probably your CPU halted too late and the register is already locked!" } else { puts "SDRAM Fix succeeded!" } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/icepick.cfg ================================================ # # Copyright (C) 2011 by Karl Kurbjun # Copyright (C) 2009 by David Brownell # # Utilities for TI ICEpick-C/D used in most TI SoCs # Details about the ICEPick are available in the the TRM for each SoC # and http://processors.wiki.ti.com/index.php/ICEPICK # create "constants" proc CONST { key } { array set constant { # define ICEPick instructions IR_BYPASS 0x00 IR_ROUTER 0x02 IR_CONNECT 0x07 IF_BYPASS 0x3F } return $constant($key) } # Instruction to connect to the icepick module proc icepick_c_connect {jrc} { # Send CONNECT instruction in IR state irscan $jrc [CONST IR_CONNECT] -endstate IRPAUSE # Send write and connect key drscan $jrc 8 0x89 -endstate DRPAUSE } # Instruction to disconnect to the icepick module proc icepick_c_disconnect {jrc} { # Send CONNECT instruction in IR state irscan $jrc [CONST IR_CONNECT] -endstate IRPAUSE # Send write and connect key drscan $jrc 8 0x86 -endstate DRPAUSE } # # icepick_c_router: # this function is for sending router commands # arguments are: # jrc: TAP name for the ICEpick # rw: read/write (0 for read, 1 for write) # block: icepick or DAP # register: which register to read/write # payload: value to read/write # this function is for sending router commands # proc icepick_c_router {jrc rw block register payload} { set new_dr_value \ [expr { ( ($rw & 0x1) << 31) | ( ($block & 0x7) << 28) | \ ( ($register & 0xF) << 24) | ( $payload & 0xFFFFFF ) } ] # echo "\tNew router value:\t0x[format %x $new_dr_value]" # select router irscan $jrc [CONST IR_ROUTER] -endstate IRPAUSE # ROUTER instructions are 32 bits wide set old_dr_value 0x[drscan $jrc 32 $new_dr_value -endstate DRPAUSE] # echo "\tOld router value:\t0x[format %x $old_dr_value]" } # Configure the icepick control register proc icepick_c_setup {jrc} { # send a router write, block is 0, register is 1, value is 0x2100 icepick_c_router $jrc 1 0x0 0x1 0x001000 } # jrc == TAP name for the ICEpick # port == a port number, 0..15 for debug tap, 16..31 for test tap proc icepick_c_tapenable {jrc port} { if { ($port >= 0) && ($port < 16) } { # Debug tap" set tap $port set block 0x2 } elseif { $port < 32 } { # Test tap set tap [expr {$port - 16}] set block 0x1 } else { echo "ERROR: Invalid ICEPick C port number: $port" return } # First CONNECT to the ICEPick # echo "Connecting to ICEPick" icepick_c_connect $jrc # echo "Configuring the ICEpick" icepick_c_setup $jrc # NOTE: it's important not to enter RUN/IDLE state until # done sending these instructions and data to the ICEpick. # And never to enter RESET, which will disable the TAPs. # first enable power and clock for TAP icepick_c_router $jrc 1 $block $tap 0x110048 # TRM states that the register should be read back here, skipped for now # enable debug "default" mode icepick_c_router $jrc 1 $block $tap 0x112048 # TRM states that debug enable and debug mode should be read back and # confirmed - skipped for now # Finally select the tap icepick_c_router $jrc 1 $block $tap 0x112148 # Enter the bypass state irscan $jrc [CONST IR_BYPASS] -endstate RUN/IDLE runtest 10 } # jrc == TAP name for the ICEpick # coreid== core id number 0..15 (not same as port number!) proc icepick_d_set_core_control {jrc coreid value } { icepick_c_router $jrc 1 0x6 $coreid $value } # jrc == TAP name for the ICEpick # port == a port number, 0..15 # Follow the sequence described in # http://processors.wiki.ti.com/images/f/f6/Router_Scan_Sequence-ICEpick-D.pdf proc icepick_d_tapenable {jrc port coreid { value 0x2008 } } { # First CONNECT to the ICEPick icepick_c_connect $jrc icepick_c_setup $jrc # Select the port icepick_c_router $jrc 1 0x2 $port 0x2108 # Set icepick core control for $coreid icepick_d_set_core_control $jrc $coreid $value # Enter the bypass state irscan $jrc [CONST IF_BYPASS] -endstate RUN/IDLE runtest 10 } # This function uses the ICEPick to send a warm system reset proc icepick_c_wreset {jrc} { # send a router write, block is 0, register is 1, value is 0x2100 icepick_c_router $jrc 1 0x0 0x1 0x002101 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx.cfg ================================================ # utility fn's for Freescale i.MX series global TARGETNAME set TARGETNAME $_TARGETNAME # rewrite commands of the form below to arm11 mcr... # Data.Set c15:0x042f %long 0x40000015 proc setc15 {regs value} { global TARGETNAME echo [format "set p15 0x%04x, 0x%08x" $regs $value] arm mcr 15 [expr {($regs>>12)&0x7}] [expr {($regs>>0)&0xf}] [expr {($regs>>4)&0xf}] [expr {($regs>>8)&0x7}] $value } proc imx3x_reset {} { # this reset script comes from the Freescale PDK # # http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=IMX35PDK echo "Target Setup: initialize DRAM controller and peripherals" # Data.Set c15:0x01 %long 0x00050078 setc15 0x01 0x00050078 echo "configuring CP15 for enabling the peripheral bus" # Data.Set c15:0x042f %long 0x40000015 setc15 0x042f 0x40000015 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx21.cfg ================================================ #use combined on interfaces or targets that can't set TRST/SRST separately # # Hmmm.... should srst_pulls_trst be used here like i.MX27??? reset_config trst_and_srst if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx21 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Note above there is 1 tap # The CPU tap if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0792611f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Create the GDB Target. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx25.cfg ================================================ # # imx25 config # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx25 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists ETBTAPID] } { set _ETBTAPID $ETBTAPID } else { set _ETBTAPID 0x1b900f0f } jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0x0f -expected-id $_ETBTAPID if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926041 } jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID jtag newtap $_CHIPNAME whatchacallit -irlen 4 -ircapture 0x0 -irmask 0x0 -expected-id 0x0 if { [info exists SDMATAPID] } { set _SDMATAPID $SDMATAPID } else { set _SDMATAPID 0x0882301d } jtag newtap $_CHIPNAME sdma -irlen 5 -expected-id $_SDMATAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN \ -chain-position $_TARGETNAME # trace setup etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx27.cfg ================================================ # page 3-34 of "MCIMC27 Multimedia Applications Processor Reference Manual, Rev 0.3" # SRST pulls TRST # # Without setting these options correctly you'll see all sorts # of weird errors, e.g. MOE=0xe, invalid cpsr values, reset # failing, etc. reset_config trst_and_srst srst_pulls_trst if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx27 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Note above there are 2 taps # trace buffer if { [info exists ETBTAPID] } { set _ETBTAPID $ETBTAPID } else { set _ETBTAPID 0x1b900f0f } jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0xf -expected-id $_ETBTAPID # The CPU tap if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926121 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Create the GDB Target. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME # REVISIT what operating environment sets up this virtual address mapping? $_TARGETNAME configure -work-area-virt 0xffff4c00 -work-area-phys 0xffff4c00 \ -work-area-size 0x8000 -work-area-backup 1 # Internal to the chip, there is 45K of SRAM # arm7_9 dcc_downloads enable # trace setup etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx28.cfg ================================================ # i.MX28 config file. # based off of the imx21.cfg file. reset_config trst_and_srst #jtag nTRST and nSRST delay adapter srst delay 100 jtag_ntrst_delay 100 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx28 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Note above there is 1 tap # The CPU tap if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x079264f3 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Create the GDB Target. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx31.cfg ================================================ # imx31 config # reset_config trst_and_srst srst_gates_jtag adapter srst delay 5 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx31 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07b3601d } if { [info exists SDMATAPID] } { set _SDMATAPID $SDMATAPID } else { set _SDMATAPID 0x2190101d } if { [info exists ETBTAPID] } { set _ETBTAPID $ETBTAPID } else { set _ETBTAPID 0x2b900f0f } #======================================== jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0xf -expected-id $_ETBTAPID # The "SDMA" - mart controller debug tap # Based on some IO pins - this can be disabled & removed # See diagram: 6-14 # SIGNAL NAME: # SJC_MOD - controls multiplexer - disables ARM1136 # SDMA_BYPASS - disables SDMA - # # Per ARM: DDI0211J_arm1136_r1p5_trm.pdf - the ARM 1136 as a 5 bit IR register jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUTAPID # No IDCODE for this TAP jtag newtap $_CHIPNAME whatchacallit -irlen 4 -ircapture 0 -irmask 0xf -expected-id 0x0 # Per section 40.17.1, table 40-85 the IR register is 4 bits # But this conflicts with Diagram 6-13, "3bits ir and drs" jtag newtap $_CHIPNAME smda -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_SDMATAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm11 -endian $_ENDIAN -chain-position $_TARGETNAME proc power_restore {} { echo "Sensed power restore. No action." } proc srst_deasserted {} { echo "Sensed nSRST deasserted. No action." } # trace setup ... NOTE, "normal full" mode fudges the real ETMv3.1 mode etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx35.cfg ================================================ # imx35 config # reset_config trst_and_srst srst_gates_jtag jtag_ntrst_delay 100 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx35 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07b3601d } if { [info exists SDMATAPID] } { set _SDMATAPID $SDMATAPID } else { set _SDMATAPID 0x0882601d } if { [info exists ETBTAPID] } { set _ETBTAPID $ETBTAPID } else { set _ETBTAPID 0x2b900f0f } #======================================== jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0xf -expected-id $_ETBTAPID jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUTAPID # No IDCODE for this TAP jtag newtap $_CHIPNAME whatchacallit -irlen 4 -ircapture 0 -irmask 0x0 -expected-id 0x0 jtag newtap $_CHIPNAME smda -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_SDMATAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm11 -endian $_ENDIAN -chain-position $_TARGETNAME proc power_restore {} { echo "Sensed power restore. No action." } proc srst_deasserted {} { echo "Sensed nSRST deasserted. No action." } # trace setup ... NOTE, "normal full" mode fudges the real ETMv3.1 mode etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx51.cfg ================================================ # Freescale i.MX51 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx51 } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x1ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID # SDMA / no IDCODE jtag newtap $_CHIPNAME sdma -irlen 4 -ircapture 0x0 -irmask 0xf # SJC if { [info exists SJC_TAPID] } { set _SJC_TAPID SJC_TAPID } else { set _SJC_TAPID 0x0190c01d } jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x1 -irmask 0x1f \ -expected-id $_SJC_TAPID -ignore-version # GDB target: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # some TCK tycles are required to activate the DEBUG power domain jtag configure $_CHIPNAME.sjc -event post-reset "runtest 100" proc imx51_dbginit {target} { # General Cortex-A8 debug initialisation cortex_a dbginit } $_TARGETNAME configure -event reset-assert-post "imx51_dbginit $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx53.cfg ================================================ # Freescale i.MX53 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx53 } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x1ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID # SDMA / no IDCODE jtag newtap $_CHIPNAME sdma -irlen 4 -ircapture 0x0 -irmask 0xf # SJC if { [info exists SJC_TAPID] } { set _SJC_TAPID SJC_TAPID } else { set _SJC_TAPID 0x0190d01d } jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x1 -irmask 0x1f \ -expected-id $_SJC_TAPID -ignore-version # GDB target: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # some TCK tycles are required to activate the DEBUG power domain jtag configure $_CHIPNAME.sjc -event post-reset "runtest 100" proc imx53_dbginit {target} { # General Cortex-A8 debug initialisation cortex_a dbginit } $_TARGETNAME configure -event reset-assert-post "imx53_dbginit $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx6.cfg ================================================ # # Freescale i.MX6 series # # Supports 6Q 6D 6QP 6DP 6DL 6S 6SL 6SLL # # Some imx6 chips have Cortex-A7 or an Cortex-M and need special handling # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx6 } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # SDMA / no IDCODE jtag newtap $_CHIPNAME sdma -irlen 4 -ircapture 0x00 -irmask 0x0f # System JTAG Controller # List supported SJC TAPIDs from imx reference manuals: set _SJC_TAPID_6Q 0x0191c01d set _SJC_TAPID_6D 0x0191e01d set _SJC_TAPID_6QP 0x3191c01d set _SJC_TAPID_6DP 0x3191d01d set _SJC_TAPID_6DL 0x0891a01d set _SJC_TAPID_6S 0x0891b01d set _SJC_TAPID_6SL 0x0891f01d set _SJC_TAPID_6SLL 0x088c201d # Allow external override of the first SJC TAPID if { [info exists SJC_TAPID] } { set _SJC_TAPID $SJC_TAPID } else { set _SJC_TAPID $_SJC_TAPID_6Q } jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x01 -irmask 0x1f \ -ignore-version \ -expected-id $_SJC_TAPID \ -expected-id $_SJC_TAPID_6QP \ -expected-id $_SJC_TAPID_6DP \ -expected-id $_SJC_TAPID_6D \ -expected-id $_SJC_TAPID_6DL \ -expected-id $_SJC_TAPID_6S \ -expected-id $_SJC_TAPID_6SL \ -expected-id $_SJC_TAPID_6SLL # GDB target: Cortex-A9, using DAP, configuring only one core # Base addresses of cores: # core 0 - 0x82150000 # core 1 - 0x82152000 # core 2 - 0x82154000 # core 3 - 0x82156000 set _TARGETNAME $_CHIPNAME.cpu.0 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x82150000 # some TCK cycles are required to activate the DEBUG power domain jtag configure $_CHIPNAME.sjc -event post-reset "runtest 100" proc imx6_dbginit {target} { # General Cortex-A8/A9 debug initialisation cortex_a dbginit } # Slow speed to be sure it will work adapter speed 1000 $_TARGETNAME configure -event reset-start { adapter speed 1000 } $_TARGETNAME configure -event reset-assert-post "imx6_dbginit $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx6sx.cfg ================================================ # # Freescale i.MX6SoloX # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx6sx } # 2x CoreSight Debug Access Port for Cortex-M4 and Cortex-A9 if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu_m4 -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap_m4 -chain-position $_CHIPNAME.cpu_m4 jtag newtap $_CHIPNAME cpu_a9 -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap_a9 -chain-position $_CHIPNAME.cpu_a9 # SDMA / no IDCODE jtag newtap $_CHIPNAME sdma -irlen 4 -ircapture 0x00 -irmask 0x0f # System JTAG Controller if { [info exists SJC_TAPID] } { set _SJC_TAPID $SJC_TAPID } else { set _SJC_TAPID 0x0891c01d } jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x01 -irmask 0x1f \ -expected-id $_SJC_TAPID -ignore-version # Cortex-A9 (boot core) target create $_CHIPNAME.cpu_a9 cortex_a -dap $_CHIPNAME.dap_a9 \ -coreid 0 -dbgbase 0x82150000 # Cortex-M4 (default off) target create $_CHIPNAME.cpu_m4 cortex_m -dap $_CHIPNAME.dap_m4 \ -ap-num 0 -defer-examine # AHB mem-ap target target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap_a9 -ap-num 0 # Default target is Cortex-A9 targets $_CHIPNAME.cpu_a9 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx6ul.cfg ================================================ # # Freescale i.MX6UltraLite series: 6UL 6ULL 6ULZ # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx6ul } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # SDMA / no IDCODE jtag newtap $_CHIPNAME sdma -irlen 4 -ircapture 0x00 -irmask 0x0f # System JTAG Controller set _SJC_TAPID_6UL 0x0891d01d set _SJC_TAPID_6ULL 0x0891e01d set _SJC_TAPID_6ULZ 0x1891e01d # Allow external override of the first SJC TAPID if { [info exists SJC_TAPID] } { set _SJC_TAPID $SJC_TAPID } else { set _SJC_TAPID $_SJC_TAPID_6UL } jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x01 -irmask 0x1f \ -ignore-version \ -expected-id $_SJC_TAPID \ -expected-id $_SJC_TAPID_6ULL \ -expected-id $_SJC_TAPID_6ULZ \ # Create DAP dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # Main AHB bus target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 # Cortex-A7 single core set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap -dbgbase 0x82130000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx7.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx7 } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # # Cortex-A7 target # # GDB target: Cortex-A7, using DAP, configuring only one core # Base addresses of cores: # core 0 - 0x80070000 # core 1 - 0x80072000 set _TARGETNAME $_CHIPNAME.cpu_a7 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME.0 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80070000 target create $_TARGETNAME.1 cortex_a -dap $_CHIPNAME.dap \ -coreid 1 -dbgbase 0x80072000 -defer-examine # # Cortex-M4 target # set _TARGETNAME_2 $_CHIPNAME.cpu_m4 target create $_TARGETNAME_2 cortex_m -dap $_CHIPNAME.dap -ap-num 4 \ -defer-examine # # AHB mem-ap target # target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 targets $_TARGETNAME.0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx7ulp.cfg ================================================ # # NXP i.MX7ULP: Cortex-A7 + Cortex-M4 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx7ulp } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { # TAPID is from FreeScale! set _DAP_TAPID 0x188e101d } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # Cortex-A7 target create $_CHIPNAME.cpu_a7 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80030000 # Cortex-M4 # Boots by default so don't defer examination target create $_CHIPNAME.cpu_m4 cortex_m -dap $_CHIPNAME.dap -ap-num 3 # AHB main soc bus target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 # Default is Cortex-A7 targets $_CHIPNAME.cpu_a7 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx8m.cfg ================================================ # # configuration file for NXP i.MX8M family of SoCs # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx8m } if { [info exists CHIPCORES] } { set _cores $CHIPCORES } else { set _cores 1 } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } # the DAP tap jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.a53 set _CTINAME $_CHIPNAME.cti set DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} set CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} for { set _core 0 } { $_core < $_cores } { incr _core } { cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [lindex $CTIBASE $_core] set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core" if { $_core != 0 } { # non-boot core examination may fail set _command "$_command -defer-examine" set _smp_command "$_smp_command $_TARGETNAME.$_core" } else { set _smp_command "target smp $_TARGETNAME.$_core" } eval $_command } eval $_smp_command # declare the auxiliary Cortex-M4 core on AP #4 target create ${_CHIPNAME}.m4 cortex_m -dap ${_CHIPNAME}.dap -ap-num 4 \ -defer-examine # AHB-AP for direct access to soc bus target create ${_CHIPNAME}.ahb mem_ap -dap ${_CHIPNAME}.dap -ap-num 0 # default target is A53 core 0 targets $_TARGETNAME.0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/imx8qm.cfg ================================================ # # NXP i.MX8QuadMax # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx8qm } # CoreSight Debug Access Port (DAP) if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { # TAPID is from FreeScale! set _DAP_TAPID 0x1890101d } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # AXI: Main SOC bus on AP #0 target create ${_CHIPNAME}.axi mem_ap -dap ${_CHIPNAME}.dap -ap-num 0 # 4x Cortex-A53 on AP #6 set _A53_DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} set _A53_CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} cti create $_CHIPNAME.a53_cti.0 -dap $_CHIPNAME.dap \ -ap-num 6 -baseaddr [lindex $_A53_CTIBASE 0] cti create $_CHIPNAME.a53_cti.1 -dap $_CHIPNAME.dap \ -ap-num 6 -baseaddr [lindex $_A53_CTIBASE 1] cti create $_CHIPNAME.a53_cti.2 -dap $_CHIPNAME.dap \ -ap-num 6 -baseaddr [lindex $_A53_CTIBASE 2] cti create $_CHIPNAME.a53_cti.3 -dap $_CHIPNAME.dap \ -ap-num 6 -baseaddr [lindex $_A53_CTIBASE 3] target create $_CHIPNAME.a53.0 aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.a53_cti.0 -dbgbase [lindex $_A53_DBGBASE 0] target create $_CHIPNAME.a53.1 aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.a53_cti.1 -dbgbase [lindex $_A53_DBGBASE 1] -defer-examine target create $_CHIPNAME.a53.2 aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.a53_cti.2 -dbgbase [lindex $_A53_DBGBASE 2] -defer-examine target create $_CHIPNAME.a53.3 aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.a53_cti.3 -dbgbase [lindex $_A53_DBGBASE 3] -defer-examine # 2x Cortex-A72 on AP #6 set _A72_DBGBASE {0x80210000 0x80310000} set _A72_CTIBASE {0x80220000 0x80220000} cti create $_CHIPNAME.a72_cti.0 -dap $_CHIPNAME.dap \ -ap-num 6 -baseaddr [lindex $_A72_CTIBASE 0] cti create $_CHIPNAME.a72_cti.1 -dap $_CHIPNAME.dap \ -ap-num 6 -baseaddr [lindex $_A72_CTIBASE 1] target create $_CHIPNAME.a72.0 aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.a72_cti.0 -dbgbase [lindex $_A72_DBGBASE 0] -defer-examine target create $_CHIPNAME.a72.1 aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.a72_cti.1 -dbgbase [lindex $_A72_DBGBASE 1] -defer-examine # All Cortex-A in SMP target smp \ $_CHIPNAME.a53.0 \ $_CHIPNAME.a53.1 \ $_CHIPNAME.a53.2 \ $_CHIPNAME.a53.3 \ $_CHIPNAME.a72.0 \ $_CHIPNAME.a72.1 # SCU: Cortex-M4 core # always running imx SC firmware target create ${_CHIPNAME}.scu cortex_m -dap ${_CHIPNAME}.dap -ap-num 1 # AHB from SCU perspective target create ${_CHIPNAME}.scu_ahb mem_ap -dap ${_CHIPNAME}.dap -ap-num 4 # Cortex-M4 M4_0 core on AP #2 (default off) target create ${_CHIPNAME}.m4_0 cortex_m -dap ${_CHIPNAME}.dap -ap-num 2 \ -defer-examine # Cortex-M4 M4_1 core on AP #3 (default off) target create ${_CHIPNAME}.m4_1 cortex_m -dap ${_CHIPNAME}.dap -ap-num 3 \ -defer-examine # Debug APB bus target create ${_CHIPNAME}.apb mem_ap -dap ${_CHIPNAME}.dap -ap-num 6 # Default target is boot core a53.0 targets $_CHIPNAME.a53.0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/infineon/tle987x.cfg ================================================ # # Infineon TLE987x family (Arm Cortex-M3 @ up to 40 MHz) # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME tle987x } source [find target/swj-dp.tcl] if { [info exists CPU_SWD_TAPID] } { set _CPU_SWD_TAPID $CPU_SWD_TAPID } else { set _CPU_SWD_TAPID 0x2BA01477 } if { [using_jtag] } { # JTAG not supported, only SWD set _CPU_TAPID 0 } else { set _CPU_TAPID $_CPU_SWD_TAPID } swj_newdap $_CHIPNAME dap -irlen 4 -expected-id $_CPU_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { ![using_hla] } { cortex_m reset_config sysresetreq } adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/is5114.cfg ================================================ # script for Insilica IS-5114 # AKA: Atmel AT76C114 - an ARM946 chip # ATMEL sold his product line to Insilica... if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME is5114 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a little endian set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # Force an error until we get a good number. set _CPUTAPID 0xffffffff } # jtag speed. We need to stick to 16kHz until we've finished reset. adapter speed 16 reset_config trst_and_srst # Do not specify a tap id here... jtag newtap $_CHIPNAME unknown1 -irlen 8 -ircapture 0x01 -irmask 1 # This is the "arm946" chip. jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x0e -irmask 0xf jtag newtap $_CHIPNAME unknown2 -irlen 5 -ircapture 1 -irmask 1 #arm946e-s and set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-start { adapter speed 16 } $_TARGETNAME configure -event reset-init { # We can increase speed now that we know the target is halted. adapter speed 3000 } $_TARGETNAME configure -work-area-phys 0x50000000 -work-area-size 16384 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ixp42x.cfg ================================================ #xscale ixp42x CPU if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ixp42x } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a bigendian set _ENDIAN big } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x19274013 } set _CPUTAPID2 0x19275013 set _CPUTAPID3 0x19277013 set _CPUTAPID4 0x29274013 set _CPUTAPID5 0x29275013 set _CPUTAPID6 0x29277013 jtag newtap $_CHIPNAME cpu -irlen 7 -ircapture 0x1 -irmask 0x7f -expected-id $_CPUTAPID -expected-id $_CPUTAPID2 -expected-id $_CPUTAPID3 -expected-id $_CPUTAPID4 -expected-id $_CPUTAPID5 -expected-id $_CPUTAPID6 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME xscale -endian $_ENDIAN -chain-position $_TARGETNAME # register constants for IXP42x SDRAM controller global IXP425_SDRAM_IR_MODE_SET_CAS2_CMD global IXP425_SDRAM_IR_MODE_SET_CAS3_CMD set IXP425_SDRAM_IR_MODE_SET_CAS2_CMD 0x0000 set IXP425_SDRAM_IR_MODE_SET_CAS3_CMD 0x0001 global IXP42x_SDRAM_CL3 global IXP42x_SDRAM_CL2 set IXP42x_SDRAM_CL3 0x0008 set IXP42x_SDRAM_CL2 0x0000 global IXP42x_SDRAM_8MB_2Mx32_1BANK global IXP42x_SDRAM_16MB_2Mx32_2BANK global IXP42x_SDRAM_16MB_4Mx16_1BANK global IXP42x_SDRAM_32MB_4Mx16_2BANK global IXP42x_SDRAM_32MB_8Mx16_1BANK global IXP42x_SDRAM_64MB_8Mx16_2BANK global IXP42x_SDRAM_64MB_16Mx16_1BANK global IXP42x_SDRAM_128MB_16Mx16_2BANK global IXP42x_SDRAM_128MB_32Mx16_1BANK global IXP42x_SDRAM_256MB_32Mx16_2BANK set IXP42x_SDRAM_8MB_2Mx32_1BANK 0x0030 set IXP42x_SDRAM_16MB_2Mx32_2BANK 0x0031 set IXP42x_SDRAM_16MB_4Mx16_1BANK 0x0032 set IXP42x_SDRAM_32MB_4Mx16_2BANK 0x0033 set IXP42x_SDRAM_32MB_8Mx16_1BANK 0x0010 set IXP42x_SDRAM_64MB_8Mx16_2BANK 0x0011 set IXP42x_SDRAM_64MB_16Mx16_1BANK 0x0012 set IXP42x_SDRAM_128MB_16Mx16_2BANK 0x0013 set IXP42x_SDRAM_128MB_32Mx16_1BANK 0x0014 set IXP42x_SDRAM_256MB_32Mx16_2BANK 0x0015 # helper function to init SDRAM on IXP42x. # SDRAM_CFG: one of IXP42X_SDRAM_xxx # REFRESH: refresh counter reload value (integer) # CASLAT: 2 or 3 proc ixp42x_init_sdram { SDRAM_CFG REFRESH CASLAT } { switch $CASLAT { 2 { set SDRAM_CFG [expr {$SDRAM_CFG | $::IXP42x_SDRAM_CL2} ] set CASCMD $::IXP425_SDRAM_IR_MODE_SET_CAS2_CMD } 3 { set SDRAM_CFG [expr {$SDRAM_CFG | $::IXP42x_SDRAM_CL3} ] set CASCMD $::IXP425_SDRAM_IR_MODE_SET_CAS3_CMD } default { error [format "unsupported cas latency \"%s\" " $CASLAT] } } echo [format "\tIXP42x SDRAM Config: 0x%x, Refresh %d " $SDRAM_CFG $REFRESH] mww 0xCC000000 $SDRAM_CFG ;# SDRAM_CFG: 0x2A: 64MBit, CL3 mww 0xCC000004 0 ;# disable refresh mww 0xCC000008 3 ;# NOP sleep 100 mww 0xCC000004 $REFRESH ;# set refresh counter mww 0xCC000008 2 ;# Precharge All Banks sleep 100 mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 $CASCMD ;# Mode Select CL2/CL3 } proc ixp42x_set_bigendian { } { reg XSCALE_CTRL 0xF8 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/k1921vk01t.cfg ================================================ # K1921VK01T # http://niiet.ru/chips/nis?id=354 source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME k1921vk01t } set _ENDIAN little # Work-area is a space in RAM used for flash programming if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x10000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x4ba00477 } { # SWD IDCODE set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.flash niietcm4 0 0 0 0 $_TARGETNAME adapter speed 2000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/k40.cfg ================================================ # # Freescale Kinetis K40 devices # set CHIPNAME k40 source [find target/kx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/k60.cfg ================================================ # # Freescale Kinetis K60 devices # set CHIPNAME k60 source [find target/kx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ke0x.cfg ================================================ # # Freescale Kinetis KE0x and KEAx series devices # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ke } # Work-area is a space in RAM used for flash programming # By default use 1kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x400 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0bc11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME kinetis_ke 0 0 0 0 $_TARGETNAME adapter speed 1000 reset_config srst_nogate if {![using_hla]} { # It is important that "kinetis_ke mdm check_security" is called for # 'examine-end' event and not 'eximine-start'. Calling it in 'examine-start' # causes "kinetis_ke mdm check_security" to fail the first time openocd # calls it when it tries to connect after the CPU has been power-cycled. $_CHIPNAME.cpu configure -event examine-end { kinetis_ke mdm check_security } # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ke1xf.cfg ================================================ # # NXP (Freescale) Kinetis KE1xF devices # set CHIPNAME ke source [find target/kx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ke1xz.cfg ================================================ # # NXP (Freescale) Kinetis KE1xZ devices # set CHIPNAME ke source [find target/klx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/kl25.cfg ================================================ # # Freescale Kinetis KL25 devices # set CHIPNAME kl25 source [find target/klx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/kl46.cfg ================================================ # # Freescale Kinetis KL46 devices # set CHIPNAME kl46 source [find target/klx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/klx.cfg ================================================ # # NXP (former Freescale) Kinetis KL series devices # Also used for Cortex-M0+ equipped members of KVx and KE1xZ series # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME klx } # Work-area is a space in RAM used for flash programming # By default use 1KiB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x400 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0bc11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.pflash flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME kinetis create_banks # Table 5-1. Clock Summary of KL25 Sub-Family Reference Manual # specifies up to 1MHz for VLPR mode and up to 24MHz for run mode; # Table 17 of Sub-Family Data Sheet rev4 lists 25MHz as the maximum frequency. adapter speed 1000 reset_config srst_nogate if {[using_hla]} { echo "" echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" echo " Kinetis MCUs have a MDM-AP dedicated mainly to MCU security related functions." echo " A high level adapter (like a ST-Link) you are currently using cannot access" echo " the MDM-AP, so commands like 'mdm mass_erase' are not available in your" echo " configuration. Also security locked state of the device will not be reported." echo "" echo " Be very careful as you can lock the device though there is no way to unlock" echo " it without mass erase. Don't set write protection on the first block." echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" echo "" } else { # Detect secured MCU $_TARGETNAME configure -event examine-fail { kinetis mdm check_security } # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } # Disable watchdog not to disturb OpenOCD algorithms running on MCU # (e.g. armv7m_checksum_memory() in verify_image) # Flash driver also disables watchdog before FTFA flash programming. $_TARGETNAME configure -event reset-init { kinetis disable_wdog } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ks869x.cfg ================================================ # ARM920T CPU if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ks869x } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x00922f0f } adapter speed 6000 # jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm920t -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x20000 -work-area-size 0x20000 -work-area-backup 0 # speed up memory downloads arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/kx.cfg ================================================ # # NXP (former Freescale) Kinetis Kx series devices # Also used for Cortex-M4 equipped members of KVx and KE1xF series # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME kx } # Work-area is a space in RAM used for flash programming # By default use 4kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.pflash flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME kinetis create_banks adapter speed 1000 reset_config srst_nogate if {[using_hla]} { echo "" echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" echo " Kinetis MCUs have a MDM-AP dedicated mainly to MCU security related functions." echo " A high level adapter (like a ST-Link) you are currently using cannot access" echo " the MDM-AP, so commands like 'mdm mass_erase' are not available in your" echo " configuration. Also security locked state of the device will not be reported." echo " Expect problems connecting to a blank device without boot ROM." echo "" echo " Be very careful as you can lock the device though there is no way to unlock" echo " it without mass erase. Don't set write protection on the first block." echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" echo "" } else { # Detect secured MCU or boot lock-up in RESET/WDOG loop $_TARGETNAME configure -event examine-fail { kinetis mdm check_security } # During RESET/WDOG loop the target is sometimes falsely examined $_TARGETNAME configure -event examine-end { kinetis mdm check_security } # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } # Disable watchdog not to disturb OpenOCD algorithms running on MCU # (e.g. armv7m_checksum_memory() in verify_image) # Flash driver also disables watchdog before FTFA flash programming. $_TARGETNAME configure -event reset-init { kinetis disable_wdog } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc11xx.cfg ================================================ # NXP LPC11xx Cortex-M0 with at least 1kB SRAM set CHIPNAME lpc11xx set CHIPSERIES lpc1100 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x400 } source [find target/lpc1xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc12xx.cfg ================================================ # NXP LPC12xx Cortex-M0 with at least 4kB SRAM set CHIPNAME lpc12xx set CHIPSERIES lpc1200 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x1000 } source [find target/lpc1xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc13xx.cfg ================================================ # NXP LPC13xx Cortex-M3 with at least 4kB SRAM set CHIPNAME lpc13xx set CHIPSERIES lpc1300 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x1000 } source [find target/lpc1xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc17xx.cfg ================================================ # NXP LPC17xx Cortex-M3 with at least 8kB SRAM set CHIPNAME lpc17xx set CHIPSERIES lpc1700 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x2000 } source [find target/lpc1xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc1850.cfg ================================================ source [find target/swj-dp.tcl] adapter speed 500 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lpc1850 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # # M3 JTAG mode TAP # if { [info exists M3_JTAG_TAPID] } { set _M3_JTAG_TAPID $M3_JTAG_TAPID } else { set _M3_JTAG_TAPID 0x4ba00477 } swj_newdap $_CHIPNAME m3 -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_M3_JTAG_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.m3 set _TARGETNAME $_CHIPNAME.m3 target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc1xxx.cfg ================================================ # Main file for NXP LPC1xxx/LPC40xx series Cortex-M0/0+/3/4F parts # # !!!!!! # # This file should not be included directly, rather by the lpc11xx.cfg, # lpc13xx.cfg, lpc17xx.cfg, etc. which set the needed variables to the # appropriate values. # # !!!!!! # LPC8xx chips support only SWD transport. # LPC11xx chips support only SWD transport. # LPC12xx chips support only SWD transport. # LPC11Uxx chips support only SWD transports. # LPC13xx chips support only SWD transports. # LPC17xx chips support both JTAG and SWD transports. # LPC40xx chips support both JTAG and SWD transports. # Adapt based on what transport is active. source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { error "CHIPNAME not set. Please do not include lpc1xxx.cfg directly, but the specific chip configuration file (lpc11xx.cfg, lpc13xx.cfg, lpc17xx.cfg, etc)." } if { [info exists CHIPSERIES] } { # Validate chip series is supported if { $CHIPSERIES != "lpc800" && $CHIPSERIES != "lpc1100" && $CHIPSERIES != "lpc1200" && $CHIPSERIES != "lpc1300" && $CHIPSERIES != "lpc1700" && $CHIPSERIES != "lpc4000" } { error "Unsupported LPC1xxx chip series specified." } set _CHIPSERIES $CHIPSERIES } else { error "CHIPSERIES not set. Please do not include lpc1xxx.cfg directly, but the specific chip configuration file (lpc11xx.cfg, lpc13xx.cfg, lpc17xx.cfg, etc)." } # After reset, the chip is clocked by an internal RC oscillator. # When board-specific code (reset-init handler or device firmware) # configures another oscillator and/or PLL0, set CCLK to match; if # you don't, then flash erase and write operations may misbehave. # (The ROM code doing those updates cares about core clock speed...) # CCLK is the core clock frequency in KHz if { [info exists CCLK] } { # Allow user override set _CCLK $CCLK } else { # LPC8xx/LPC11xx/LPC12xx/LPC13xx use a 12MHz one, LPC17xx uses a 4MHz one(except for LPC177x/8x,LPC407x/8x) if { $_CHIPSERIES == "lpc800" || $_CHIPSERIES == "lpc1100" || $_CHIPSERIES == "lpc1200" || $_CHIPSERIES == "lpc1300" } { set _CCLK 12000 } elseif { $_CHIPSERIES == "lpc1700" || $_CHIPSERIES == "lpc4000" } { set _CCLK 4000 } } if { [info exists CPUTAPID] } { # Allow user override set _CPUTAPID $CPUTAPID } else { # LPC8xx/LPC11xx/LPC12xx use a Cortex-M0/M0+ core, LPC13xx/LPC17xx use a Cortex-M3 core, LPC40xx use a Cortex-M4F core. if { $_CHIPSERIES == "lpc800" || $_CHIPSERIES == "lpc1100" || $_CHIPSERIES == "lpc1200" } { set _CPUTAPID 0x0bb11477 } elseif { $_CHIPSERIES == "lpc1300" || $_CHIPSERIES == "lpc1700" || $_CHIPSERIES == "lpc4000" } { if { [using_jtag] } { set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } } if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { error "WORKAREASIZE is not set. The $CHIPNAME part is available in several Flash and RAM size configurations. Please set WORKAREASIZE." } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap # The LPC11xx devices have 2/4/8kB of SRAM in the ARMv7-M "Code" area (at 0x10000000) # The LPC12xx devices have 4/8kB of SRAM in the ARMv7-M "Code" area (at 0x10000000) # The LPC11Uxx devices have 4/6/8kB of SRAM in the ARMv7-M "Code" area (at 0x10000000) # The LPC13xx devices have 4/8kB of SRAM in the ARMv7-M "Code" area (at 0x10000000) # The LPC17xx devices have 8/16/32/64kB of SRAM in the ARMv7-M "Code" area (at 0x10000000) # The LPC40xx devices have 16/32/64kB of SRAM in the ARMv7-ME "Code" area (at 0x10000000) $_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size $_WORKAREASIZE # The LPC11xx devies have 8/16/24/32/48/56/64kB of flash memory (at 0x00000000) # The LPC12xx devies have 32/48/64/80/96/128kB of flash memory (at 0x00000000) # The LPC11Uxx devies have 16/24/32/40/48/64/96/128kB of flash memory (at 0x00000000) # The LPC13xx devies have 8/16/32kB of flash memory (at 0x00000000) # The LPC17xx devies have 32/64/128/256/512kB of flash memory (at 0x00000000) # The LPC40xx devies have 64/128/256/512kB of flash memory (at 0x00000000) # # All are compatible with the "lpc1700" variant of the LPC2000 flash driver # (same cmd51 destination boundary alignment, and all three support 256 byte # transfers). # # flash bank lpc2000 0 0 [calc checksum] [iap entry] set _IAP_ENTRY 0 if { [info exists IAP_ENTRY] } { set _IAP_ENTRY $IAP_ENTRY } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME lpc2000 0x0 0 0 0 $_TARGETNAME \ auto $_CCLK calc_checksum $_IAP_ENTRY if { $_CHIPSERIES == "lpc800" || $_CHIPSERIES == "lpc1100" || $_CHIPSERIES == "lpc1200" || $_CHIPSERIES == "lpc1300" } { # Do not remap 0x0000-0x0200 to anything but the flash (i.e. select # "User Flash Mode" where interrupt vectors are _not_ remapped, # and reside in flash instead). # # Table 8. System memory remap register (SYSMEMREMAP, address 0x4004 8000) bit description # Bit Symbol Value Description # 1:0 MAP System memory remap # 0x0 Boot Loader Mode. Interrupt vectors are re-mapped to Boot ROM. # 0x1 User RAM Mode. Interrupt vectors are re-mapped to Static RAM. # 0x2 User Flash Mode. Interrupt vectors are not re-mapped and reside in Flash. # 31:2 - - Reserved. $_TARGETNAME configure -event reset-init { mww 0x40048000 0x02 } } elseif { $_CHIPSERIES == "lpc1700" || $_CHIPSERIES == "lpc4000" } { # Do not remap 0x0000-0x0020 to anything but the flash (i.e. select # "User Flash Mode" where interrupt vectors are _not_ remapped, # and reside in flash instead). # # See Table 612. Memory Mapping Control register (MEMMAP - 0x400F C040) bit description # Bit Symbol Value Description Reset # value # 0 MAP Memory map control. 0 # 0 Boot mode. A portion of the Boot ROM is mapped to address 0. # 1 User mode. The on-chip Flash memory is mapped to address 0. # 31:1 - Reserved. The value read from a reserved bit is not defined. NA # # http://ics.nxp.com/support/documents/microcontrollers/?scope=LPC1768&type=user $_TARGETNAME configure -event reset-init { mww 0x400FC040 0x01 } } # Run with *real slow* clock by default since the # boot rom could have been playing with the PLL, so # we have no idea what clock the target is running at. adapter speed 10 # delays on reset lines adapter srst delay 200 if {[using_jtag]} { jtag_ntrst_delay 200 } # LPC8xx (Cortex-M0+ core) support SYSRESETREQ # LPC11xx/LPC12xx (Cortex-M0 core) support SYSRESETREQ # LPC13xx/LPC17xx (Cortex-M3 core) support SYSRESETREQ # LPC40xx (Cortex-M4F core) support SYSRESETREQ if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc2103.cfg ================================================ # NXP LPC2103 ARM7TDMI-S with 32kB flash and 8kB SRAM, clocked with 12MHz crystal source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2103 {core_freq_khz adapter_freq_khz} { # 32kB flash and 8kB SRAM # setup_lpc2xxx setup_lpc2xxx lpc2103 0x4f1f0f0f 0x8000 lpc2000_v2 0x2000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." # setup_lpc2103 setup_lpc2103 12000 1500 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc2124.cfg ================================================ # NXP LPC2124 ARM7TDMI-S with 256kB flash and 16kB SRAM, clocked with 12MHz crystal source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2124 {core_freq_khz adapter_freq_khz} { # 256kB flash and 16kB SRAM # setup_lpc2xxx setup_lpc2xxx lpc2124 0x4f1f0f0f 0x40000 lpc2000_v1 0x4000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." # setup_lpc2124 setup_lpc2124 12000 1500 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc2129.cfg ================================================ # NXP LPC2129 ARM7TDMI-S with 256kB flash and 16kB SRAM, clocked with 12MHz crystal source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2129 {core_freq_khz adapter_freq_khz} { # 256kB flash and 16kB SRAM # setup_lpc2xxx setup_lpc2xxx lpc2129 0xcf1f0f0f 0x40000 lpc2000_v1 0x4000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." # setup_lpc2129 setup_lpc2129 12000 1500 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc2148.cfg ================================================ # NXP LPC2148 ARM7TDMI-S with 512kB flash (12kB used by bootloader) and 40kB SRAM (8kB for USB DMA), clocked with 12MHz crystal source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2148 {core_freq_khz adapter_freq_khz} { # 500kB flash and 32kB SRAM # setup_lpc2xxx setup_lpc2xxx lpc2148 "0x3f0f0f0f 0x4f1f0f0f" 0x7d000 lpc2000_v2 0x8000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." # setup_lpc2148 setup_lpc2148 12000 1500 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc2294.cfg ================================================ # NXP LPC2294 ARM7TDMI-S with 256kB flash and 16kB SRAM, clocked with 12MHz crystal source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2294 {core_freq_khz adapter_freq_khz} { # 256kB flash and 16kB SRAM # setup_lpc2xxx # !! TAPID unknown !! setup_lpc2xxx lpc2294 0xffffffff 0x40000 lpc2000_v1 0x4000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." # setup_lpc2294 setup_lpc2294 12000 1500 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc2378.cfg ================================================ # NXP LPC2378 ARM7TDMI-S with 512kB flash (8kB used by bootloader) and 56kB SRAM (16kB for ETH, 8kB for DMA), clocked with 4MHz internal oscillator source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2378 {core_freq_khz adapter_freq_khz} { # 504kB flash and 32kB SRAM # setup_lpc2xxx setup_lpc2xxx lpc2378 0x4f1f0f0f 0x7e000 lpc2000_v2 0x8000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 4MHz internal oscillator echo "Warning - assuming default core clock 4MHz! Flashing may fail if actual core clock is different." # setup_lpc2378 setup_lpc2378 4000 500 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc2460.cfg ================================================ # NXP LPC2460 ARM7TDMI-S with 98kB SRAM (16kB for ETH, 16kB for DMA, 2kB for RTC), clocked with 4MHz internal oscillator source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2460 {core_freq_khz adapter_freq_khz} { # 64kB SRAM # setup_lpc2xxx setup_lpc2xxx lpc2460 0x4f1f0f0f 0 lpc2000_v2 0x10000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 4MHz internal oscillator echo "Warning - assuming default core clock 4MHz! Flashing may fail if actual core clock is different." # setup_lpc2460 setup_lpc2460 4000 500 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc2478.cfg ================================================ # NXP LPC2478 ARM7TDMI-S with 512kB flash (8kB used by bootloader) and 98kB SRAM (16kB for ETH, 16kB for DMA, 2kB for RTC), clocked with 4MHz internal oscillator source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2478 {core_freq_khz adapter_freq_khz} { # 504kB flash and 64kB SRAM # setup_lpc2xxx setup_lpc2xxx lpc2478 0x4f1f0f0f 0x7e000 lpc2000_v2 0x10000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 4MHz internal oscillator echo "Warning - assuming default core clock 4MHz! Flashing may fail if actual core clock is different." # setup_lpc2478 setup_lpc2478 4000 500 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc2900.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lpc2900 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0596802B } if { [info exists HAS_ETB] } { } else { # Set default (no ETB). # Show a warning, because this should have been configured explicitly. set HAS_ETB 0 # TODO: warning? } if { [info exists ETBTAPID] } { set _ETBTAPID $ETBTAPID } else { set _ETBTAPID 0x1B900F0F } # TRST and SRST both exist, and can be controlled independently reset_config trst_and_srst separate # Define the _TARGETNAME set _TARGETNAME $_CHIPNAME.cpu # Include the ETB tap controller if asked for. # Has to be done manually for newer devices (not an "old" LPC2917/2919). if { $HAS_ETB == 1 } { # Clear the HAS_ETB flag. Must be set again for a new tap in the chain. set HAS_ETB 0 # Add the ETB tap controller and the ARM9 core debug tap jtag newtap $_CHIPNAME etb -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_ETBTAPID jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Create the ".cpu" target target create $_TARGETNAME arm966e -endian little -chain-position $_TARGETNAME # Configure ETM and ETB etm config $_TARGETNAME 8 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb } else { # Add the ARM9 core debug tap jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Create the ".cpu" target target create $_TARGETNAME arm966e -endian little -chain-position $_TARGETNAME } arm7_9 dbgrq enable arm7_9 dcc_downloads enable # Flash bank configuration: # Flash: flash bank lpc2900 0 0 0 0 # Flash base address, total flash size, and number of sectors are all configured automatically. set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME lpc2900 0 0 0 0 $_TARGETNAME $FLASH_CLOCK ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc2xxx.cfg ================================================ # Common setup for the LPC2xxx parts # parameters: # - chip_name - name of the chip, e.g. lpc2103 # - cputapids - TAP IDs of the core, should be quoted if more than one, e.g. 0x4f1f0f0f or "0x3f0f0f0f 0x4f1f0f0f" # - flash_size - size of on-chip flash (available for code, not including the bootloader) in bytes, e.g. 0x8000 # - flash_variant - "type" of LPC2xxx device, lpc2000_v1 (LPC22xx and older LPC21xx) or lpc2000_v2 (LPC213x, LPC214x, LPC210[123], LPC23xx and LPC24xx) # - workarea_size - size of work-area in RAM for flashing procedures, must not exceed the size of RAM available at 0x40000000, e.g. 0x2000 # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2xxx {chip_name cputapids flash_size flash_variant workarea_size core_freq_khz adapter_freq_khz} { reset_config trst_and_srst # reset delays adapter srst delay 100 jtag_ntrst_delay 100 adapter speed $adapter_freq_khz foreach i $cputapids { append expected_ids "-expected-id " $i " " } eval "jtag newtap $chip_name cpu -irlen 4 -ircapture 0x1 -irmask 0xf $expected_ids" global _TARGETNAME set _TARGETNAME $chip_name.cpu target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x40000000 -work-area-size $workarea_size -work-area-backup 0 if { $flash_size > 0 } { # flash bank lpc2000 0 0 [calc checksum] set _FLASHNAME $chip_name.flash flash bank $_FLASHNAME lpc2000 0x0 $flash_size 0 0 $_TARGETNAME $flash_variant $core_freq_khz calc_checksum } } proc init_targets {} { # FIX!!! read out CPUTAPID here and choose right setup. In addition to the # CPUTAPID some querying of the target would be required. return -error "This is a generic LPC2xxx configuration file, use a specific target file." } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc3131.cfg ================================================ ###################################### # Target: NXP lpc3131 ###################################### if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lpc3131 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # ARM926EJS core if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926f0f } # Scan Tap # Wired to separate STDO pin on the lpc3131, externally muxed to TDO on ea3131 module # JTAGSEL pin must be 0 to activate, which reassigns arm tdo to a pass through. if { [info exists SJCTAPID] } { set _SJCTAPID $SJCTAPID } else { set _SJCTAPID 0x1541E02B } jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID ################################################################## # various symbol definitions, to avoid hard-wiring addresses ################################################################## global lpc313x set lpc313x [ dict create ] # Physical addresses for controllers and memory dict set lpc313x sram0 0x11028000 dict set lpc313x sram1 0x11040000 dict set lpc313x uart 0x15001000 dict set lpc313x cgu 0x13004000 dict set lpc313x ioconfig 0x13003000 dict set lpc313x sysconfig 0x13002800 dict set lpc313x wdt 0x13002400 ################################################################## # Target configuration ################################################################## adapter srst delay 1000 jtag_ntrst_delay 0 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME invoke-event halted $_TARGETNAME configure -work-area-phys [dict get $lpc313x sram0] -work-area-size 0x30000 -work-area-backup 0 $_TARGETNAME configure -event reset-init { echo "\nRunning reset init script for LPC3131\n" halt wait_halt reg cpsr 0xa00000d3 ;#Supervisor mode reg pc 0x11029000 poll sleep 500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc3250.cfg ================================================ # lpc3250 config # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lpc3250 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x17900f0f } if { [info exists CPUTAPID_REV_A0] } { set _CPUTAPID_REV_A0 $CPUTAPID_REV_A0 } else { set _CPUTAPID_REV_A0 0x17926f0f } if { [info exists SJCTAPID] } { set _SJCTAPID $SJCTAPID } else { set _SJCTAPID 0x1b900f0f } jtag newtap $_CHIPNAME sjc -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_SJCTAPID jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID \ -expected-id $_CPUTAPID_REV_A0 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian little -chain-position $_TARGETNAME -work-area-phys 0x00000000 -work-area-size 0x7d0000 -work-area-backup 0 proc power_restore {} { echo "Sensed power restore. No action." } proc srst_deasserted {} { echo "Sensed nSRST deasserted. No action." } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc40xx.cfg ================================================ # NXP LPC40xx Cortex-M4F with at least 16kB SRAM set CHIPNAME lpc40xx set CHIPSERIES lpc4000 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x4000 } source [find target/lpc1xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc4350.cfg ================================================ source [find target/swj-dp.tcl] adapter speed 500 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lpc4350 } # # M4 JTAG mode TAP # if { [info exists M4_JTAG_TAPID] } { set _M4_JTAG_TAPID $M4_JTAG_TAPID } else { set _M4_JTAG_TAPID 0x4ba00477 } # # M4 SWD mode TAP # if { [info exists M4_SWD_TAPID] } { set _M4_SWD_TAPID $M4_SWD_TAPID } else { set _M4_SWD_TAPID 0x2ba01477 } if { [using_jtag] } { set _M4_TAPID $_M4_JTAG_TAPID } { set _M4_TAPID $_M4_SWD_TAPID } # # M0 TAP # if { [info exists M0_JTAG_TAPID] } { set _M0_JTAG_TAPID $M0_JTAG_TAPID } else { set _M0_JTAG_TAPID 0x0ba01477 } swj_newdap $_CHIPNAME m4 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M4_TAPID dap create $_CHIPNAME.m4.dap -chain-position $_CHIPNAME.m4 target create $_CHIPNAME.m4 cortex_m -dap $_CHIPNAME.m4.dap if { [using_jtag] } { swj_newdap $_CHIPNAME m0 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M0_JTAG_TAPID dap create $_CHIPNAME.m0.dap -chain-position $_CHIPNAME.m0 target create $_CHIPNAME.m0 cortex_m -dap $_CHIPNAME.m0.dap } # LPC4350 has 96+32 KB SRAM if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x20000 } $_CHIPNAME.m4 configure -work-area-phys 0x10000000 \ -work-area-size $_WORKAREASIZE -work-area-backup 0 if {![using_hla]} { # on this CPU we should use VECTRESET to perform a soft reset and # manually reset the periphery # SRST or SYSRESETREQ disable the debug interface for the time of # the reset and will not fit our requirements for a consistent debug # session cortex_m reset_config vectreset } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc4357.cfg ================================================ # # NXP LPC4357 # if { ![info exists CHIPNAME] } { set CHIPNAME lpc4357 } set WORKAREASIZE 0x8000 source [find target/lpc4350.cfg] flash bank $_CHIPNAME.flasha lpc2000 0x1A000000 0x80000 0 0 $_CHIPNAME.m4 lpc4300 204000 calc_checksum flash bank $_CHIPNAME.flashb lpc2000 0x1B000000 0x80000 0 0 $_CHIPNAME.m4 lpc4300 204000 calc_checksum ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc4370.cfg ================================================ # # NXP LPC4370 - 1x ARM Cortex-M4 + 2x ARM Cortex-M0 @ up to 204 MHz each # adapter speed 500 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lpc4370 } # # M4 JTAG mode TAP # if { [info exists M4_JTAG_TAPID] } { set _M4_JTAG_TAPID $M4_JTAG_TAPID } else { set _M4_JTAG_TAPID 0x4ba00477 } # # M4 SWD mode TAP # if { [info exists M4_SWD_TAPID] } { set _M4_SWD_TAPID $M4_SWD_TAPID } else { set _M4_SWD_TAPID 0x2ba01477 } source [find target/swj-dp.tcl] if { [using_jtag] } { set _M4_TAPID $_M4_JTAG_TAPID } else { set _M4_TAPID $_M4_SWD_TAPID } # # M0 TAP # if { [info exists M0_JTAG_TAPID] } { set _M0_JTAG_TAPID $M0_JTAG_TAPID } else { set _M0_JTAG_TAPID 0x0ba01477 } swj_newdap $_CHIPNAME m4 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M4_TAPID dap create $_CHIPNAME.m4.dap -chain-position $_CHIPNAME.m4 target create $_CHIPNAME.m4 cortex_m -dap $_CHIPNAME.m4.dap # LPC4370 has 96+32 KB contiguous SRAM if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x20000 } $_CHIPNAME.m4 configure -work-area-phys 0x10000000 \ -work-area-size $_WORKAREASIZE -work-area-backup 0 if { [using_jtag] } { jtag newtap $_CHIPNAME m0app -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M0_JTAG_TAPID jtag newtap $_CHIPNAME m0sub -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M0_JTAG_TAPID dap create $_CHIPNAME.m0app.dap -chain-position $_CHIPNAME.m0app dap create $_CHIPNAME.m0sub.dap -chain-position $_CHIPNAME.m0sub target create $_CHIPNAME.m0app cortex_m -dap $_CHIPNAME.m0app.dap target create $_CHIPNAME.m0sub cortex_m -dap $_CHIPNAME.m0sub.dap # 32+8+32 KB SRAM $_CHIPNAME.m0app configure -work-area-phys 0x10080000 \ -work-area-size 0x92000 -work-area-backup 0 # 16+2 KB M0 subsystem SRAM $_CHIPNAME.m0sub configure -work-area-phys 0x18000000 \ -work-area-size 0x4800 -work-area-backup 0 # Default to the Cortex-M4 targets $_CHIPNAME.m4 } if { ![using_hla] } { cortex_m reset_config vectreset } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc84x.cfg ================================================ # NXP LPC84x Cortex-M0+ with at least 8kB SRAM if { ![info exists CHIPNAME] } { set CHIPNAME lpc84x } set CHIPSERIES lpc800 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x1fe0 } set IAP_ENTRY 0x0F001FF1 source [find target/lpc1xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc8nxx.cfg ================================================ # NXP LPC8Nxx NHS31xx Cortex-M0+ with 8kB SRAM # Copyright (C) 2018 by Jean-Christian de Rivaz # Based on NXP proposal https://community.nxp.com/message/1011149 # Many thanks to Dries Moors from NXP support. # SWD only transport source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lpc8nxx } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id 0 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap if {![using_hla]} { # If srst is not fitted use SYSRESETREQ to perform a soft reset cortex_m reset_config sysresetreq } adapter srst delay 100 $_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size 0x1ff0 -work-area-backup 0 flash bank $_CHIPNAME.flash lpc2000 0x0 0x7800 0 0 $_TARGETNAME lpc800 500 echo "*********************************************************************************" echo "* !!!!! IMPORTANT NOTICE FOR LPC8Nxx and NHS31xx CHIPS !!!!!" echo "* When this IC is in power-off or peep power down mode, the SWD HW block is also" echo "* unpowered. These modes can be entered by firmware. The default firmware image" echo "* (flashed in production) makes use of this. Best is to avoid these power modes" echo "* during development, and only later add them when the functionality is complete." echo "* Hardware reset or NFC field are the only ways to connect in case the SWD is" echo "* powered off. OpenOCD can do a hardware reset if you wire the adapter SRST" echo "* signal to the chip RESETN pin and add the following in your configuration:" echo "* reset_config srst_only; flash init; catch init; reset" echo "* But if the actual firmware immediately set the power down mode after reset," echo "* OpenOCD might be not fast enough to halt the CPU before the SWD lost power. In" echo "* that case the only solution is to apply a NFC field to keep the SWD powered." echo "*********************************************************************************" # Using soft-reset 'reset_config none' is strongly discouraged. # RESETN sets the system clock to 500 kHz. Unlike soft-reset does not. # Set the system clock to 500 kHz before reset to simulate the functionality of hw reset. # proc set_sysclk_500khz {} { set SYSCLKCTRL 0x40048020 set SYSCLKUEN 0x40048024 mww $SYSCLKUEN 0 mmw $SYSCLKCTRL 0x8 0xe mww $SYSCLKUEN 1 echo "Notice: sysclock set to 500kHz." } # Do not remap the ARM interrupt vectors to anything but the beginning of the flash. # Table System memory remap register (SYSMEMREMAP, address 0x4004 8000) bit description # Bit Symbol Value Description # 0 map - interrupt vector remap. 0 after boot. # 0 interrupt vector reside in Flash # 1 interrupt vector reside in SRAM # 5:1 offset - system memory remap offset. 00000b after boot. # 00000b interrupt vectors in flash or remapped to SRAM but no offset # 00001b - # 00111b interrupt vectors offset in flash or SRAM to 1K word segment # 01000b - # 11111b interrupt vectors offset in flash to 1K word segment 8 to 31 # 31:6 reserved # proc set_no_remap {} { mww 0x40048000 0x00 echo "Notice: interrupt vector set to no remap." } $_TARGETNAME configure -event reset-init { set_sysclk_500khz set_no_remap } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lpc8xx.cfg ================================================ # NXP LPC8xx Cortex-M0+ with at least 1kB SRAM if { ![info exists CHIPNAME] } { set CHIPNAME lpc8xx } set CHIPSERIES lpc800 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x400 } source [find target/lpc1xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ls1012a.cfg ================================================ # # NXP LS1012A # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ls1012a } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } if { [info exists SAP_TAPID] } { set _SAP_TAPID $SAP_TAPID } else { set _SAP_TAPID 0x06b2001d } jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID jtag newtap $_CHIPNAME sap -irlen 8 -expected-id $_SAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap cti create $_CHIPNAME.cti -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0x80420000 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -dbgbase 0x80410000 -cti $_CHIPNAME.cti target smp $_TARGETNAME adapter speed 2000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ls1028a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LS1028A if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ls1028a } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x6ba00477 } set _CPUS 2 source [find target/lsch3_common.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ls1046a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LS1046A if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ls1046a } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } if { [info exists SAP_TAPID] } { set _SAP_TAPID $SAP_TAPID } else { set _SAP_TAPID 0x06b3001d } jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 0 set _CPU_BASE 0x80400000 set _CPU_STRIDE 0x100000 set _CPU_DBGOFF 0x10000 set _CPU_CTIOFF 0x20000 set _TARGETS {} for {set i 0} {$i < 4} {incr i} { set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}] cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [expr {$_BASE + $_CPU_CTIOFF}] target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \ -coreid $i {*}[expr {$i ? {-defer-examine} : {-rtos hwthread} }] lappend _TARGETS $_CHIPNAME.cpu$i } target smp {*}$_TARGETS jtag newtap $_CHIPNAME sap -irlen 8 -expected-id $_SAP_TAPID target create $_CHIPNAME.sap ls1_sap -chain-position $_CHIPNAME.sap -endian big proc core_up { args } { foreach core $args { $::_CHIPNAME.cpu$core arp_examine } } targets $_CHIPNAME.cpu0 adapter speed 10000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ls1088a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LS1088A if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ls1088a } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } set _CPUS 8 source [find target/lsch3_common.cfg] # Seems to work OK in testing adapter speed 10000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/lsch3_common.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This contains common configuration for NXP Layerscape chassis generation 3 if { ![info exists _CPUS] } { error "_CPUS must be set to the number of cores" } jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 1 set _CPU_BASE 0x81000000 set _CPU_STRIDE 0x100000 set _CPU_DBGOFF 0x10000 set _CPU_CTIOFF 0x20000 set _TARGETS {} for {set i 0} {$i < $_CPUS} {incr i} { set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}] cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 0 \ -baseaddr [expr {$_BASE + $_CPU_CTIOFF}] target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \ {*}[expr {$i ? "-coreid $i" : "-rtos hwthread" }] lappend _TARGETS $_CHIPNAME.cpu$i } target smp {*}$_TARGETS # Service processor target create $_CHIPNAME.sp cortex_a -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80138000 # Normally you will not need to call this, but if you are using the hard-coded # Reset Configuration Word (RCW) you will need to call this manually. The CPU's # reset vector is 0, and the boot ROM at that location contains ARMv7-A 32-bit # instructions. This will cause the CPU to almost immediately execute an # illegal instruction. # # This code is idempotent; releasing a released CPU has no effect, although it # will halt/resume the service processor. add_help_text release_cpu "Release a cpu which is held off" proc release_cpu {cpu} { set RST_BRRL 0x1e60060 set old [target current] targets $::_CHIPNAME.sp set not_halted [string compare halted [$::_CHIPNAME.sp curstate]] if {$not_halted} { halt } # Release the cpu; it will start executing something bogus mem2array regs 32 $RST_BRRL 1 mww $RST_BRRL [expr {$regs(0) | 1 << $cpu}] if {$not_halted} { resume } targets $old } targets $_CHIPNAME.cpu0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/marvell/88f3710.cfg ================================================ # Marvell Armada 3710 set CORES 1 source [find target/marvell/88f37x0.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/marvell/88f3720.cfg ================================================ # Marvell Armada 3720 set CORES 2 source [find target/marvell/88f37x0.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/marvell/88f37x0.cfg ================================================ # Main file for Marvell Armada 3700 series targets # # !!!!!! # # This file should not be included directly. Instead, please include # either marvell/88f3710.cfg or marvell/88f3720.cfg, which set the needed # variables to the appropriate values. # # !!!!!! # Armada 3700 supports both JTAG and SWD transports. source [find target/swj-dp.tcl] if { [info exists CORES] } { set _cores $CORES } else { error "CORES not set. Please do not include marvell/88f37x0.cfg directly, but the specific chip configuration file (marvell/88f3710.cfg, marvell/88f3720.cfg, etc.)." } if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME [format a37%s0 $_cores] } set _ctis {0x80820000 0x80920000} # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } # declare the one JTAG tap to access the DAP swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # declare the main application cores set _TARGETNAME $_CHIPNAME.cpu set _smp_command "" for { set _core 0 } { $_core < $_cores } { incr _core 1 } { cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [lindex $_ctis $_core] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core \ -cti cti$_core" if { $_core != 0 } { # non-boot core examination may fail set _command "$_command -defer-examine" set _smp_command "$_smp_command ${_TARGETNAME}$_core" } else { # uncomment when "hawt" rtos is merged # set _command "$_command -rtos hawt" set _smp_command "target smp ${_TARGETNAME}$_core" } eval $_command } eval $_smp_command # declare the auxiliary Cortex-M3 core on AP #3 target create ${_TARGETNAME}.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 3 -defer-examine targets ${_TARGETNAME}0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/max32620.cfg ================================================ # Maxim Integrated MAX32620 OpenOCD target configuration file # www.maximintegrated.com # adapter speed adapter speed 4000 # reset pin configuration reset_config srst_only if {[using_jtag]} { jtag newtap max32620 cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -ignore-version } else { swd newdap max32620 cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version } # target configuration target create max32620.cpu cortex_m -chain-position max32620.cpu max32620.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 # Config Command: flash bank name driver base size chip_width bus_width target [driver_options] # flash bank max32xxx 0 0 # max32620 flash base address 0x00000000 # max32620 flash size 0x200000 (2MB) # max32620 FLC base address 0x40002000 # max32620 sector (page) size 0x2000 (8kB) # max32620 clock speed 96 (MHz) flash bank max32620.flash max32xxx 0x00000000 0x200000 0 0 max32620.cpu 0x40002000 0x2000 96 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/max32625.cfg ================================================ # Maxim Integrated MAX32625 OpenOCD target configuration file # www.maximintegrated.com # adapter speed adapter speed 4000 # reset pin configuration reset_config srst_only if {[using_jtag]} { jtag newtap max32625 cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -expected-id 0x07f71197 -ignore-version } else { swd newdap max32625 cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version } # target configuration target create max32625.cpu cortex_m -chain-position max32625.cpu max32625.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 # Config Command: flash bank name driver base size chip_width bus_width target [driver_options] # flash bank max32xxx 0 0 # max32625 flash base address 0x00000000 # max32625 flash size 0x80000 (512k) # max32625 FLC base address 0x40002000 # max32625 sector (page) size 0x2000 (8kB) # max32625 clock speed 96 (MHz) flash bank max32625.flash max32xxx 0x00000000 0x80000 0 0 max32625.cpu 0x40002000 0x2000 96 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/max3263x.cfg ================================================ # Maxim Integrated MAX3263X OpenOCD target configuration file # www.maximintegrated.com # adapter speed adapter speed 4000 # reset pin configuration reset_config srst_only if {[using_jtag]} { jtag newtap max3263x cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -expected-id 0x07f76197 -ignore-version } else { swd newdap max3263x cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version } # target configuration target create max3263x.cpu cortex_m -chain-position max3263x.cpu max3263x.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 # Config Command: flash bank name driver base size chip_width bus_width target [driver_options] # flash bank max32xxx 0 0 # max3263x flash base address 0x00000000 # max3263x flash size 0x200000 (2MB) # max3263x FLC base address 0x40002000 # max3263x sector (page) size 0x2000 (8kB) # max3263x clock speed 96 (MHz) flash bank max3263x.flash max32xxx 0x00000000 0x200000 0 0 max3263x.cpu 0x40002000 0x2000 96 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/mc13224v.cfg ================================================ source [find bitsbytes.tcl] source [find cpu/arm/arm7tdmi.tcl] source [find memory.tcl] source [find mmr_helpers.tcl] set CHIP_MAKER freescale set CHIP_FAMILY mc1322x set CHIP_NAME mc13224 set N_RAM 1 set RAM(0,BASE) 0x00400000 set RAM(0,LEN) 0x18000 set RAM(0,HUMAN) "internal SRAM" set RAM(0,TYPE) "ram" set RAM(0,RWX) $RWX_RWX set RAM(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY # I AM LAZY... I create 1 region for all MMRs. set N_MMREGS 1 set MMREGS(0,CHIPSELECT) -1 set MMREGS(0,BASE) 0x80000000 set MMREGS(0,LEN) 0x00030000 set MMREGS(0,HUMAN) "mm-regs" set MMREGS(0,TYPE) "mmr" set MMREGS(0,RWX) $RWX_RW set MMREGS(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY set N_XMEM 0 set _CHIPNAME mc13224v set _CPUTAPID 0x1f1f001d jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID reset_config srst_only jtag_ntrst_delay 200 # rclk hasn't been working well. This maybe the mc13224v or something else. #adapter speed 2000 adapter speed 2000 ###################### # Target configuration ###################### set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME # Internal sram memory $_TARGETNAME configure -work-area-phys 0x00408000 \ -work-area-size 0x1000 \ -work-area-backup 1 # flash support is pending (should be straightforward to implement) #flash bank mc1322x 0 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/mdr32f9q2i.cfg ================================================ # MDR32F9Q2I (1986ВЕ92У) # http://milandr.ru/index.php?mact=Products,cntnt01,details,0&cntnt01productid=57&cntnt01returnid=68 source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME mdr32f9q2i } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x8000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x4ba00477 } { # SWD IDCODE set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # can't handle overlapping memory regions if { [info exists IMEMORY] && [string equal $IMEMORY true] } { flash bank ${_CHIPNAME}_info.flash mdr 0x08000000 0x01000 0 0 $_TARGETNAME 1 1 4 } else { flash bank $_CHIPNAME.flash mdr 0x08000000 0x20000 0 0 $_TARGETNAME 0 32 4 } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz adapter speed 1000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/nds32v2.cfg ================================================ # # Andes Core # # http://www.andestech.com # jtag newtap $_CHIPNAME cpu -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME nds32_v2 -endian little -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/nds32v3.cfg ================================================ # # Andes Core # # http://www.andestech.com # jtag newtap $_CHIPNAME cpu -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME nds32_v3 -endian little -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/nds32v3m.cfg ================================================ # # Andes Core # # http://www.andestech.com # jtag newtap $_CHIPNAME cpu -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME nds32_v3m -endian little -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/nds32v5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Andes Core # # http://www.andestech.com # set _CHIPNAME nds jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563D set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/nhs31xx.cfg ================================================ # NXP NHS31xx Cortex-M0+ with 8kB SRAM set CHIPNAME nhs31xx source [find target/lpc8nxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/npcx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for Nuvoton NPCX Cortex-M4 Series # Adapt based on what transport is active. source [find target/swj-dp.tcl] # Set Chipname if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME NPCX_M4 } # SWD DAP ID of Nuvoton NPCX Cortex-M4. if { [info exists CPUDAPID ] } { set _CPUDAPID $CPUDAPID } else { set _CPUDAPID 0x4BA00477 } # Work-area is a space in RAM used for flash programming # By default use 32kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x8000 } # Debug Adapter Target Settings swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUDAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x200c0000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # Initial JTAG/SWD speed # For safety purposes, set for the lowest cpu clock configuration # 4MHz / 6 = 666KHz, so use 600KHz for it adapter speed 600 # For safety purposes, set for the lowest cpu clock configuration $_TARGETNAME configure -event reset-start {adapter speed 600} # use sysresetreq to perform a system reset cortex_m reset_config sysresetreq # flash configuration set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME npcx 0x64000000 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/nrf51.cfg ================================================ # # script for Nordic nRF51 series, a Cortex-M0 chip # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME nrf51 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # By default use 16kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0bb11477 } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 if {![using_hla]} { # The chip supports standard ARM/Cortex-M0 SYSRESETREQ signal cortex_m reset_config sysresetreq } flash bank $_CHIPNAME.flash nrf51 0x00000000 0 1 1 $_TARGETNAME flash bank $_CHIPNAME.uicr nrf51 0x10001000 0 1 1 $_TARGETNAME # # The chip should start up from internal 16Mhz RC, so setting adapter # clock to 1Mhz should be OK # adapter speed 1000 proc enable_all_ram {} { # nRF51822 Product Anomaly Notice (PAN) #16 explains that not all RAM banks # are reliably enabled after reset on some revisions (contrary to spec.) So after # resetting we enable all banks via the RAMON register mww 0x40000524 0xF } $_TARGETNAME configure -event reset-end { enable_all_ram } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/nrf52.cfg ================================================ # # Nordic nRF52 series: ARM Cortex-M4 @ 64 MHz # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME nrf52 } # Work-area is a space in RAM used for flash programming # By default use 16kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x2ba01477 } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap adapter speed 1000 $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 if { [using_hla] } { echo "" echo "nRF52 device has a CTRL-AP dedicated to recover the device from AP lock." echo "A high level adapter (like a ST-Link) you are currently using cannot access" echo "the CTRL-AP so 'nrf52_recover' command will not work." echo "Do not enable UICR APPROTECT." echo "" } else { cortex_m reset_config sysresetreq $_TARGETNAME configure -event examine-fail nrf52_check_ap_lock } flash bank $_CHIPNAME.flash nrf5 0x00000000 0 1 1 $_TARGETNAME flash bank $_CHIPNAME.uicr nrf5 0x10001000 0 1 1 $_TARGETNAME # Test if MEM-AP is locked by UICR APPROTECT proc nrf52_check_ap_lock {} { set dap [[target current] cget -dap] set err [catch {set APPROTECTSTATUS [$dap apreg 1 0xc]}] if {$err == 0 && $APPROTECTSTATUS != 1} { echo "****** WARNING ******" echo "nRF52 device has AP lock engaged (see UICR APPROTECT register)." echo "Debug access is denied." echo "Use 'nrf52_recover' to erase and unlock the device." echo "" poll off } } # Mass erase and unlock the device using proprietary nRF CTRL-AP (AP #1) # http://www.ebyte.com produces modules with nRF52 locked by default, # use nrf52_recover to enable flashing and debug. proc nrf52_recover {} { set target [target current] set dap [$target cget -dap] set IDR [$dap apreg 1 0xfc] if {$IDR != 0x02880000} { echo "Error: Cannot access nRF52 CTRL-AP!" return } poll off # Reset and trigger ERASEALL task $dap apreg 1 4 0 $dap apreg 1 4 1 for {set i 0} {1} {incr i} { set ERASEALLSTATUS [$dap apreg 1 8] if {$ERASEALLSTATUS == 0} { echo "$target device has been successfully erased and unlocked." break } if {$i == 0} { echo "Waiting for chip erase..." } if {$i >= 150} { echo "Error: $target recovery failed." break } sleep 100 } # Assert reset $dap apreg 1 0 1 # Deassert reset $dap apreg 1 0 0 # Reset ERASEALL task $dap apreg 1 4 0 sleep 100 $target arp_examine poll on } add_help_text nrf52_recover "Mass erase and unlock nRF52 device" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/nuc910.cfg ================================================ # # Nuvoton nuc910 (previously W90P910) based soc # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME nuc910 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # set useful default set _CPUTAPID 0x07926f0f } set _TARGETNAME $_CHIPNAME.cpu jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/numicro.cfg ================================================ # script for Nuvoton MuMicro Cortex-M0 Series # Adapt based on what transport is active. source [find target/swj-dp.tcl] # Set Chipname if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME NuMicro } # SWD DP-ID Nuvoton NuMicro Cortex-M0 has SWD Transport only. if { [info exists CPUDAPID] } { set _CPUDAPID $CPUDAPID } else { set _CPUDAPID 0x0BB11477 } # Work-area is a space in RAM used for flash programming # By default use 2kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x800 } # Debug Adapter Target Settings swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUDAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash bank numicro 0 0 #set _FLASHNAME $_CHIPNAME.flash #flash bank $_FLASHNAME numicro 0 $_FLASHSIZE 0 0 $_TARGETNAME # flash size will be probed set _FLASHNAME $_CHIPNAME.flash_aprom flash bank $_FLASHNAME numicro 0x00000000 0 0 0 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash_data flash bank $_FLASHNAME numicro 0x0001F000 0 0 0 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash_ldrom flash bank $_FLASHNAME numicro 0x00100000 0 0 0 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash_config flash bank $_FLASHNAME numicro 0x00300000 0 0 0 $_TARGETNAME # set default SWCLK frequency adapter speed 1000 # set default srst setting "none" reset_config none # HLA doesn't have cortex_m commands if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/omap2420.cfg ================================================ # Texas Instruments OMAP 2420 # http://www.ti.com/omap # as seen in Nokia N8x0 tablets if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME omap2420 } # NOTE: likes slowish clock on reset (1.5 MBit/s or less) or use RCLK reset_config srst_nogate # Subsidiary TAP: ARM7TDMIr4 plus imaging ... must add via ICEpick (addr 6). jtag newtap $_CHIPNAME iva -irlen 4 -disable # Subsidiary TAP: C55x DSP ... must add via ICEpick (addr 2). jtag newtap $_CHIPNAME dsp -irlen 38 -disable # Subsidiary TAP: ARM ETB11, with scan chain for 4K of ETM trace buffer if { [info exists ETB_TAPID] } { set _ETB_TAPID $ETB_TAPID } else { set _ETB_TAPID 0x2b900f0f } jtag newtap $_CHIPNAME etb -irlen 4 -expected-id $_ETB_TAPID # Subsidiary TAP: ARM1136jf-s with scan chains for ARM Debug, EmbeddedICE-RT, ETM. if { [info exists CPU_TAPID] } { set _CPU_TAPID $CPU_TAPID } else { set _CPU_TAPID 0x07b3602f } jtag newtap $_CHIPNAME arm -irlen 5 -expected-id $_CPU_TAPID # Primary TAP: ICEpick-B (JTAG route controller) and boundary scan if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x01ce4801 } jtag newtap $_CHIPNAME jrc -irlen 2 -expected-id $_JRC_TAPID # GDB target: the ARM. set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm11 -chain-position $_TARGETNAME # scratch: framebuffer, may be initially unavailable in some chips $_TARGETNAME configure -work-area-phys 0x40210000 $_TARGETNAME configure -work-area-size 0x00081000 $_TARGETNAME configure -work-area-backup 0 # trace setup ... NOTE, "normal full" mode fudges the real ETMv3.1 mode etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb # RM_RSTCTRL_WKUP.RST.GS - Trigger a global software reset, and # give it a chance to finish before we talk to the chip again. set RM_RSTCTRL_WKUP 0x48008450 $_TARGETNAME configure -event reset-assert \ "halt; $_TARGETNAME mww $RM_RSTCTRL_WKUP 2; sleep 200" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/omap3530.cfg ================================================ # TI OMAP3530 # http://focus.ti.com/docs/prod/folders/print/omap3530.html # Other OMAP3 chips remove DSP and/or the OpenGL support if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME omap3530 } # ICEpick-C ... used to route Cortex, DSP, and more not shown here source [find target/icepick.cfg] # Subsidiary TAP: C64x+ DSP ... must enable via ICEpick jtag newtap $_CHIPNAME dsp -irlen 38 -ircapture 0x25 -irmask 0x3f -disable # Subsidiary TAP: CoreSight Debug Access Port (DAP) if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x0b6d602f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 3" # Primary TAP: ICEpick-C (JTAG route controller) and boundary scan if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0b7ae02f } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \ -expected-id $_JRC_TAPID # GDB target: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # SRAM: 64K at 0x4020.0000; use the first 16K $_TARGETNAME configure -work-area-phys 0x40200000 -work-area-size 0x4000 ################### # the reset sequence is event-driven # and kind of finicky... # some TCK tycles are required to activate the DEBUG power domain jtag configure $_CHIPNAME.jrc -event post-reset "runtest 100" # have the DAP "always" be active jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.dap" proc omap3_dbginit {target} { # General Cortex-A8 debug initialisation cortex_a dbginit # Enable DBGU signal for OMAP353x $target mww phys 0x5401d030 0x00002000 } # be absolutely certain the JTAG clock will work with the worst-case # 16.8MHz/2 = 8.4MHz core clock, even before a bootloader kicks in. # OK to speed up *after* PLL and clock tree setup. adapter speed 1000 $_TARGETNAME configure -event "reset-start" { adapter speed 1000 } # Assume SRST is unavailable (e.g. TI-14 JTAG), so we must assert reset # ourselves using PRM_RSTCTRL. RST_GS (2) is a warm reset, like ICEpick # would issue. RST_DPLL3 (4) is a cold reset. set PRM_RSTCTRL 0x48307250 $_TARGETNAME configure -event reset-assert "$_TARGETNAME mww $PRM_RSTCTRL 2" $_TARGETNAME configure -event reset-assert-post "omap3_dbginit $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/omap4430.cfg ================================================ # OMAP4430 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME omap4430 } # Although the OMAP4430 supposedly has an ICEpick-D, only the # ICEpick-C router commands seem to work. # See http://processors.wiki.ti.com/index.php/ICEPICK source [find target/icepick.cfg] # # A9 DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x3BA00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 9" # # M3 DAPs, one per core # if { [info exists M3_DAP_TAPID] } { set _M3_DAP_TAPID $M3_DAP_TAPID } else { set _M3_DAP_TAPID 0x4BA00477 } jtag newtap $_CHIPNAME m31 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable jtag configure $_CHIPNAME.m31 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 5" jtag newtap $_CHIPNAME m30 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable jtag configure $_CHIPNAME.m30 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 4" # # ICEpick-D JRC (JTAG route controller) # if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x3b95c02f set _JRC_TAPID2 0x1b85202f } # PandaBoard REV EA1 (PEAP platforms) if { [info exists JRC_TAPID2] } { set _JRC_TAPID2 $JRC_TAPID2 } else { set _JRC_TAPID2 0x1b85202f } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \ -expected-id $_JRC_TAPID -expected-id $_JRC_TAPID2 # Required by ICEpick to power-up the debug domain jtag configure $_CHIPNAME.jrc -event post-reset "runtest 200" # # GDB target: Cortex-A9, using DAP # # The debugger can connect to either core of the A9, but currently # not both simultaneously. Change -coreid to 1 to connect to the # second core. # set _TARGETNAME $_CHIPNAME.cpu # APB DBGBASE reads 0x80040000, but this points to an empty ROM table. # 0x80000000 is cpu0 coresight region # # # CORTEX_A8_PADDRDBG_CPU_SHIFT 13 # 0x80000000 | (coreid << CORTEX_A8_PADDRDBG_CPU_SHIFT) set _coreid 0 set _dbgbase [expr {0x80000000 | ($_coreid << 13)}] echo "Using dbgbase = [format 0x%x $_dbgbase]" dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase $_dbgbase # SRAM: 56KiB at 0x4030.0000 $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x1000 # # M3 targets, separate TAP/DAP for each core # dap create $_CHIPNAME.m30_dap -chain-position $_CHIPNAME.m30 dap create $_CHIPNAME.m31_dap -chain-position $_CHIPNAME.m31 target create $_CHIPNAME.m30 cortex_m -dap $_CHIPNAME.m30_dap target create $_CHIPNAME.m31 cortex_m -dap $_CHIPNAME.m31_dap # Once the JRC is up, enable our TAPs jtag configure $_CHIPNAME.jrc -event setup " jtag tapenable $_CHIPNAME.cpu jtag tapenable $_CHIPNAME.m30 jtag tapenable $_CHIPNAME.m31 " # Assume SRST is unavailable (e.g. TI-14 JTAG), so we must assert reset # ourselves using PRM_RSTCTRL. 1 is a warm reset, 2 a cold reset. set PRM_RSTCTRL 0x4A307B00 $_TARGETNAME configure -event reset-assert "$_TARGETNAME mww phys $PRM_RSTCTRL 0x1" $_CHIPNAME.m30 configure -event reset-assert { } $_CHIPNAME.m31 configure -event reset-assert { } # Soft breakpoints don't currently work due to broken cache handling gdb_breakpoint_override hard ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/omap4460.cfg ================================================ # OMAP4460 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME omap4460 } # Although the OMAP4430 supposedly has an ICEpick-D, only the # ICEpick-C router commands seem to work. # See http://processors.wiki.ti.com/index.php/ICEPICK source [find target/icepick.cfg] # # A9 DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x3BA00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 9" # # M3 DAPs, one per core # if { [info exists M3_DAP_TAPID] } { set _M3_DAP_TAPID $M3_DAP_TAPID } else { set _M3_DAP_TAPID 0x4BA00477 } jtag newtap $_CHIPNAME m31 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable jtag configure $_CHIPNAME.m31 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 5" jtag newtap $_CHIPNAME m30 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable jtag configure $_CHIPNAME.m30 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 4" # # ICEpick-D JRC (JTAG route controller) # if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x2b94e02f set _JRC_TAPID2 0x1b85202f } # PandaBoard REV EA1 (PEAP platforms) if { [info exists JRC_TAPID2] } { set _JRC_TAPID2 $JRC_TAPID2 } else { set _JRC_TAPID2 0x1b85202f } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \ -expected-id $_JRC_TAPID -expected-id $_JRC_TAPID2 # Required by ICEpick to power-up the debug domain jtag configure $_CHIPNAME.jrc -event post-reset "runtest 200" # # GDB target: Cortex-A9, using DAP # # The debugger can connect to either core of the A9, but currently # not both simultaneously. Change -coreid to 1 to connect to the # second core. # set _TARGETNAME $_CHIPNAME.cpu # APB DBGBASE reads 0x80040000, but this points to an empty ROM table. # 0x80000000 is cpu0 coresight region # # # CORTEX_A8_PADDRDBG_CPU_SHIFT 13 # 0x80000000 | (coreid << CORTEX_A8_PADDRDBG_CPU_SHIFT) set _coreid 0 set _dbgbase [expr {0x80000000 | ($_coreid << 13)}] echo "Using dbgbase = [format 0x%x $_dbgbase]" dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase $_dbgbase # SRAM: 56KiB at 0x4030.0000 $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x1000 # # M3 targets, separate TAP/DAP for each core # dap create $_CHIPNAME.m30_dap -chain-position $_CHIPNAME.m30 dap create $_CHIPNAME.m31_dap -chain-position $_CHIPNAME.m31 target create $_CHIPNAME.m30 cortex_m -dap $_CHIPNAME.m30_dap target create $_CHIPNAME.m31 cortex_m -dap $_CHIPNAME.m31_dap # Once the JRC is up, enable our TAPs jtag configure $_CHIPNAME.jrc -event setup " jtag tapenable $_CHIPNAME.cpu jtag tapenable $_CHIPNAME.m30 jtag tapenable $_CHIPNAME.m31 " # Assume SRST is unavailable (e.g. TI-14 JTAG), so we must assert reset # ourselves using PRM_RSTCTRL. 1 is a warm reset, 2 a cold reset. set PRM_RSTCTRL 0x4A307B00 $_TARGETNAME configure -event reset-assert "$_TARGETNAME mww phys $PRM_RSTCTRL 0x1" $_CHIPNAME.m30 configure -event reset-assert { } $_CHIPNAME.m31 configure -event reset-assert { } # Soft breakpoints don't currently work due to broken cache handling gdb_breakpoint_override hard ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/omap5912.cfg ================================================ # TI OMAP5912 dual core processor # http://focus.ti.com/docs/prod/folders/print/omap5912.html if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME omap5912 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # NOTE: validated with XOMAP5912 part set _CPUTAPID 0x0692602f } adapter srst delay 100 # NOTE: presumes irlen 38 is the C55x DSP, matching BSDL for # its standalone siblings (like TMS320VC5502) of the same era #jtag scan chain jtag newtap $_CHIPNAME dsp -irlen 38 -expected-id 0x03df1d81 jtag newtap $_CHIPNAME arm -irlen 4 -expected-id $_CPUTAPID jtag newtap $_CHIPNAME unknown -irlen 8 set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm926ejs -chain-position $_TARGETNAME proc omap5912_reset {} { # # halt target # poll sleep 1 halt wait_halt # # disable wdt # mww 0xfffec808 0x000000f5 mww 0xfffec808 0x000000a0 mww 0xfffeb048 0x0000aaaa sleep 500 mww 0xfffeb048 0x00005555 sleep 500 } # omap5912 lcd frame buffer as working area $_TARGETNAME configure -work-area-phys 0x20000000 \ -work-area-size 0x3e800 -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/omapl138.cfg ================================================ # # Texas Instruments DaVinci family: OMAPL138 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME omapl138 } source [find target/icepick.cfg] # Subsidiary TAP: ARM ETB11, with scan chain for 4K of ETM trace buffer if { [info exists ETB_TAPID] } { set _ETB_TAPID $ETB_TAPID } else { set _ETB_TAPID 0x2b900f0f } jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0xf -expected-id $_ETB_TAPID -disable jtag configure $_CHIPNAME.etb -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 3" # Subsidiary TAP: ARM926ejs with scan chains for ARM Debug, EmbeddedICE-RT, ETM. if { [info exists CPU_TAPID] } { set _CPU_TAPID $CPU_TAPID } else { set _CPU_TAPID 0x07926001 } jtag newtap $_CHIPNAME arm -irlen 4 -irmask 0xf -expected-id $_CPU_TAPID -disable jtag configure $_CHIPNAME.arm -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 2" # Primary TAP: ICEpick-C (JTAG route controller) and boundary scan if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0b7d102f } jtag newtap $_CHIPNAME jrc -irlen 6 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version jtag configure $_CHIPNAME.jrc -event setup \ "jtag tapenable $_CHIPNAME.etb; jtag tapenable $_CHIPNAME.arm" ################ # GDB target: the ARM, using SRAM1 for scratch. SRAM0 (also 8K) # and the ETB memory (4K) are other options, while trace is unused. # Little-endian; use the OpenOCD default. set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm926ejs -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 0x2000 # be absolutely certain the JTAG clock will work with the worst-case # CLKIN = 20 MHz (best case: 30 MHz) even when no bootloader turns # on the PLL and starts using it. OK to speed up after clock setup. adapter speed 1500 $_TARGETNAME configure -event "reset-start" { adapter speed 1500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable # trace setup etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb gdb_breakpoint_override hard arm7_9 dbgrq enable ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/or1k.cfg ================================================ set _ENDIAN big if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME or1k } if { [info exists TAP_TYPE] } { set _TAP_TYPE $TAP_TYPE } else { puts "You need to select a tap type" shutdown } # Configure the target if { [string compare $_TAP_TYPE "VJTAG"] == 0 } { if { [info exists FPGATAPID] } { set _FPGATAPID $FPGATAPID } else { puts "You need to set your FPGA JTAG ID" shutdown } jtag newtap $_CHIPNAME cpu -irlen 10 -expected-id $_FPGATAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME or1k -endian $_ENDIAN -chain-position $_TARGETNAME # Select the TAP core we are using tap_select vjtag } elseif { [string compare $_TAP_TYPE "XILINX_BSCAN"] == 0 } { if { [info exists FPGATAPID] } { set _FPGATAPID $FPGATAPID } else { puts "You need to set your FPGA JTAG ID" shutdown } jtag newtap $_CHIPNAME cpu -irlen 6 -expected-id $_FPGATAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME or1k -endian $_ENDIAN -chain-position $_TARGETNAME # Select the TAP core we are using tap_select xilinx_bscan } else { # OpenCores Mohor JTAG TAP ID set _CPUTAPID 0x14951185 jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME or1k -endian $_ENDIAN -chain-position $_TARGETNAME # Select the TAP core we are using tap_select mohor } # Select the debug unit core we are using. This debug unit as an option. set ADBG_USE_HISPEED 1 set ENABLE_JSP_SERVER 2 set ENABLE_JSP_MULTI 4 # If ADBG_USE_HISPEED is set (options bit 1), status bits will be skipped # on burst reads and writes to improve download speeds. # This option must match the RTL configured option. du_select adv [expr {$ADBG_USE_HISPEED | $ENABLE_JSP_SERVER | $ENABLE_JSP_MULTI}] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/pic32mx.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME pic32mx } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x30938053 } # default working area is 16384 if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } adapter srst delay 100 jtag_ntrst_delay 100 #jtag scan chain #format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE) jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian $_ENDIAN -chain-position $_TARGETNAME # # At reset the pic32mx does not allow code execution from RAM # we have to setup the BMX registers to allow this. # One limitation is that we loose the first 2k of RAM. # global _PIC32MX_DATASIZE global _WORKAREASIZE set _PIC32MX_DATASIZE 0x800 set _PIC32MX_PROGSIZE [expr {$_WORKAREASIZE - $_PIC32MX_DATASIZE}] $_TARGETNAME configure -work-area-phys 0xa0000800 -work-area-size $_PIC32MX_PROGSIZE -work-area-backup 0 $_TARGETNAME configure -event reset-init { # # from reset the pic32 cannot execute code in ram - enable ram execution # minimum offset from start of ram is 2k # global _PIC32MX_DATASIZE global _WORKAREASIZE # BMXCON set 0 wait state option by clearing BMXWSDRM bit, bit 6 mww 0xbf882000 0x001f0000 # BMXDKPBA: 2k kernel data @ 0xa0000000 mww 0xbf882010 $_PIC32MX_DATASIZE # BMXDUDBA: 14k kernel program @ 0xa0000800 - (BMXDUDBA - BMXDKPBA) mww 0xbf882020 $_WORKAREASIZE # BMXDUPBA: 0k user program - (BMXDUPBA - BMXDUDBA) mww 0xbf882030 $_WORKAREASIZE # # Set system clock to 8Mhz if the default clock configuration is set # # SYSKEY register, make sure OSCCON is locked mww 0xbf80f230 0x0 # SYSKEY register, write unlock sequence mww 0xbf80f230 0xaa996655 mww 0xbf80f230 0x556699aa # OSCCON register + 4, clear OSCCON FRCDIV bits: 24, 25 and 26, divided by 1 mww 0xbf80f004 0x07000000 # SYSKEY register, relock OSCCON mww 0xbf80f230 0x0 } set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME pic32mx 0x1fc00000 0 0 0 $_TARGETNAME # add virtual banks for kseg0 and kseg1 flash bank vbank0 virtual 0xbfc00000 0 0 0 $_TARGETNAME $_FLASHNAME flash bank vbank1 virtual 0x9fc00000 0 0 0 $_TARGETNAME $_FLASHNAME set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME pic32mx 0x1d000000 0 0 0 $_TARGETNAME # add virtual banks for kseg0 and kseg1 flash bank vbank2 virtual 0xbd000000 0 0 0 $_TARGETNAME $_FLASHNAME flash bank vbank3 virtual 0x9d000000 0 0 0 $_TARGETNAME $_FLASHNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/psoc4.cfg ================================================ # script for Cypress PSoC 4 devices # # PSoC 4 devices support SWD transports only. # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME psoc4 } # Work-area is a space in RAM used for flash programming # By default use 4kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0bb11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME psoc4 0 0 0 0 $_TARGETNAME adapter speed 1500 # Reset, bloody PSoC 4 reset # # 1) XRES (nSRST) resets also SWD DP so SWD line reset and DP reinit is needed. # High level adapter stops working after SRST and needs OpenOCD restart. # If your hw does not use SRST for other circuits, use sysresetreq instead # # 2) PSoC 4 executes initialization code from system ROM after reset. # This code subsequently jumps to user flash reset vector address. # Unfortunately the system ROM code is protected from reading and debugging. # Protection breaks vector catch VC_CORERESET used for "reset halt" by cortex_m. # # Cypress uses TEST_MODE flag to loop CPU in system ROM before executing code # from user flash. Programming specifications states that TEST_MODE flag must be # set in time frame 400 usec delayed about 1 msec from reset. # # OpenOCD have no standard way how to set TEST_MODE in specified time frame. # As a workaround the TEST_MODE flag is set before reset instead. # It worked for the oldest family PSoC4100/4200 even though it is not guaranteed # by specification. # # Newer families like PSoC 4000, 4100M, 4200M, 4100L, 4200L and PSoC 4 BLE # clear TEST_MODE flag during device reset so workaround is not possible. # Use a KitProg adapter for these devices or "reset halt" will not stop # before executing user code. # # 3) SWD cannot be connected during system initialization after reset. # This might be a reason for unconnecting ST-Link v2 when deasserting reset. # As a workaround arp_reset deassert is not called for hla if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } proc psoc4_get_family_id {} { set err [catch {set romtable_pid [read_memory 0xF0000FE0 32 3]}] if { $err } { return 0 } if { [expr {[lindex $romtable_pid 0] & 0xffffff00 }] || [expr {[lindex $romtable_pid 1] & 0xffffff00 }] || [expr {[lindex $romtable_pid 2] & 0xffffff00 }] } { echo "Unexpected data in ROMTABLE" return 0 } set designer_id [expr {(( [lindex $romtable_pid 1] & 0xf0 ) >> 4) | (( [lindex $romtable_pid 2] & 0xf ) << 4 ) }] if { $designer_id != 0xb4 } { echo [format "ROMTABLE Designer ID 0x%02x is not Cypress" $designer_id] return 0 } set family_id [expr {( [lindex $romtable_pid 0] & 0xff ) | (( [lindex $romtable_pid 1] & 0xf ) << 8 ) }] return $family_id } proc ocd_process_reset_inner { MODE } { global PSOC4_USE_ACQUIRE PSOC4_TEST_MODE_WORKAROUND global _TARGETNAME if { 0 != [string compare $_TARGETNAME [target names]] } { return -code error "PSoC 4 reset can handle only one $_TARGETNAME target"; } set t $_TARGETNAME # If this target must be halted... set halt -1 if { 0 == [string compare $MODE halt] } { set halt 1 } if { 0 == [string compare $MODE init] } { set halt 1; } if { 0 == [string compare $MODE run ] } { set halt 0; } if { $halt < 0 } { return -code error "Invalid mode: $MODE, must be one of: halt, init, or run"; } if { ! [info exists PSOC4_USE_ACQUIRE] } { if { 0 == [string compare [adapter name] kitprog ] } { set PSOC4_USE_ACQUIRE 1 } else { set PSOC4_USE_ACQUIRE 0 } } if { $PSOC4_USE_ACQUIRE } { set PSOC4_TEST_MODE_WORKAROUND 0 } elseif { ! [info exists PSOC4_TEST_MODE_WORKAROUND] } { if { [psoc4_get_family_id] == 0x93 } { set PSOC4_TEST_MODE_WORKAROUND 1 } else { set PSOC4_TEST_MODE_WORKAROUND 0 } } #$t invoke-event reset-start $t invoke-event reset-assert-pre if { $halt && $PSOC4_USE_ACQUIRE } { catch { [adapter name] acquire_psoc } $t arp_examine } else { if { $PSOC4_TEST_MODE_WORKAROUND } { set TEST_MODE 0x40030014 if { $halt == 1 } { catch { mww $TEST_MODE 0x80000000 } } else { catch { mww $TEST_MODE 0 } } } $t arp_reset assert 0 } $t invoke-event reset-assert-post $t invoke-event reset-deassert-pre if {![using_hla]} { # workaround ST-Link v2 fails and forcing reconnect $t arp_reset deassert 0 } $t invoke-event reset-deassert-post # Pass 1 - Now wait for any halt (requested as part of reset # assert/deassert) to happen. Ideally it takes effect without # first executing any instructions. if { $halt } { # Now PSoC CPU should loop in system ROM $t arp_waitstate running 200 $t arp_halt # Catch, but ignore any errors. catch { $t arp_waitstate halted 1000 } # Did we succeed? set s [$t curstate] if { 0 != [string compare $s "halted" ] } { return -code error [format "TARGET: %s - Not halted" $t] } # Check if PSoC CPU is stopped in system ROM set pc [reg pc] regsub {pc[^:]*: } $pc "" pc if { $pc < 0x10000000 || $pc > 0x1000ffff } { set hint "" set family_id [psoc4_get_family_id] if { $family_id == 0x93 } { set hint ", use 'reset_config none'" } elseif { $family_id > 0x93 } { set hint ", use a KitProg adapter" } return -code error [format "TARGET: %s - Not halted in system ROM%s" $t $hint] } # Set registers to reset vector values set value [read_memory 0x0 32 2] reg pc [expr {[lindex $value 1] & 0xfffffffe}] reg msp [lindex $value 0] if { $PSOC4_TEST_MODE_WORKAROUND } { catch { mww $TEST_MODE 0 } } } #Pass 2 - if needed "init" if { 0 == [string compare init $MODE] } { set err [catch "$t arp_waitstate halted 5000"] # Did it halt? if { $err == 0 } { $t invoke-event reset-init } } $t invoke-event reset-end } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/psoc5lp.cfg ================================================ # # Cypress PSoC 5LP # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME psoc5lp } if { [info exists CPUTAPID] } { set _CPU_TAPID $CPUTAPID } else { set _CPU_TAPID 0x4BA00477 } if { [using_jtag] } { set _CPU_DAP_ID $_CPU_TAPID } else { set _CPU_DAP_ID 0x2ba01477 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_DAP_ID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x2000 } $_TARGETNAME configure -work-area-phys [expr {0x20000000 - $_WORKAREASIZE / 2}] \ -work-area-size $_WORKAREASIZE -work-area-backup 0 source [find mem_helper.tcl] $_TARGETNAME configure -event reset-init { # Configure Target Device (PSoC 5LP Device Programming Specification 5.2) set PANTHER_DBG_CFG 0x4008000C set PANTHER_DBG_CFG_BYPASS [expr {1 << 1}] mmw $PANTHER_DBG_CFG $PANTHER_DBG_CFG_BYPASS 0 set PM_ACT_CFG0 0x400043A0 mww $PM_ACT_CFG0 0xBF set FASTCLK_IMO_CR 0x40004200 set FASTCLK_IMO_CR_F_RANGE_2 [expr {2 << 0}] set FASTCLK_IMO_CR_F_RANGE_MASK [expr {7 << 0}] mmw $FASTCLK_IMO_CR $FASTCLK_IMO_CR_F_RANGE_2 $FASTCLK_IMO_CR_F_RANGE_MASK } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME psoc5lp 0x00000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.eeprom psoc5lp_eeprom 0x40008000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.nvl psoc5lp_nvl 0 0 0 0 $_TARGETNAME if {![using_hla]} { cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/psoc6.cfg ================================================ # # Configuration script for Cypress PSoC6 family of microcontrollers (CY8C6xxx) # PSoC6 is a dual-core device with CM0+ and CM4 cores. Both cores share # the same Flash/RAM/MMIO address space. # source [find target/swj-dp.tcl] adapter speed 1000 global _CHIPNAME if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME psoc6 } global TARGET set TARGET $_CHIPNAME.cpu swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # Is CM0 Debugging enabled ? global _ENABLE_CM0 if { [info exists ENABLE_CM0] } { set _ENABLE_CM0 $ENABLE_CM0 } else { set _ENABLE_CM0 1 } # Is CM4 Debugging enabled ? global _ENABLE_CM4 if { [info exists ENABLE_CM4] } { set _ENABLE_CM4 $ENABLE_CM4 } else { set _ENABLE_CM4 1 } global _WORKAREASIZE_CM0 if { [info exists WORKAREASIZE_CM0] } { set _WORKAREASIZE_CM0 $WORKAREASIZE_CM0 } else { set _WORKAREASIZE_CM0 0x4000 } global _WORKAREASIZE_CM4 if { [info exists WORKAREASIZE_CM4] } { set _WORKAREASIZE_CM4 $WORKAREASIZE_CM4 } else { set _WORKAREASIZE_CM4 0x4000 } global _WORKAREAADDR_CM0 if { [info exists WORKAREAADDR_CM0] } { set _WORKAREAADDR_CM0 $WORKAREAADDR_CM0 } else { set _WORKAREAADDR_CM0 0x08000000 } global _WORKAREAADDR_CM4 if { [info exists WORKAREAADDR_CM4] } { set _WORKAREAADDR_CM4 $WORKAREAADDR_CM4 } else { set _WORKAREAADDR_CM4 0x08000000 } proc init_reset { mode } { global RESET_MODE set RESET_MODE $mode if {[using_jtag]} { jtag arp_init-reset } } # Utility to make 'reset halt' work as reset;halt on a target # It does not prevent running code after reset proc psoc6_deassert_post { target } { # PSoC6 cleared AP registers including TAR during reset # Force examine to synchronize OpenOCD target status $target arp_examine global RESET_MODE global TARGET if { $RESET_MODE ne "run" } { $target arp_poll $target arp_poll set st [$target curstate] if { $st eq "reset" } { # we assume running state follows # if reset accidentally halts, waiting is useless catch { $target arp_waitstate running 100 } set st [$target curstate] } if { $st eq "running" } { echo "$target: Ran after reset and before halt..." if { $target eq "${TARGET}.cm0" } { # Try to cleanly reset whole system # and halt the CM0 at entry point psoc6 reset_halt $target arp_waitstate halted 100 } else { $target arp_halt } } } } if { $_ENABLE_CM0 } { target create ${TARGET}.cm0 cortex_m -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 ${TARGET}.cm0 configure -work-area-phys $_WORKAREAADDR_CM0 -work-area-size $_WORKAREASIZE_CM0 -work-area-backup 0 flash bank main_flash_cm0 psoc6 0x10000000 0 0 0 ${TARGET}.cm0 flash bank work_flash_cm0 psoc6 0x14000000 0 0 0 ${TARGET}.cm0 flash bank super_flash_user_cm0 psoc6 0x16000800 0 0 0 ${TARGET}.cm0 flash bank super_flash_nar_cm0 psoc6 0x16001A00 0 0 0 ${TARGET}.cm0 flash bank super_flash_key_cm0 psoc6 0x16005A00 0 0 0 ${TARGET}.cm0 flash bank super_flash_toc2_cm0 psoc6 0x16007C00 0 0 0 ${TARGET}.cm0 ${TARGET}.cm0 cortex_m reset_config sysresetreq ${TARGET}.cm0 configure -event reset-deassert-post "psoc6_deassert_post ${TARGET}.cm0" } if { $_ENABLE_CM4 } { target create ${TARGET}.cm4 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -coreid 1 ${TARGET}.cm4 configure -work-area-phys $_WORKAREAADDR_CM4 -work-area-size $_WORKAREASIZE_CM4 -work-area-backup 0 flash bank main_flash_cm4 psoc6 0x10000000 0 0 0 ${TARGET}.cm4 flash bank work_flash_cm4 psoc6 0x14000000 0 0 0 ${TARGET}.cm4 flash bank super_flash_user_cm4 psoc6 0x16000800 0 0 0 ${TARGET}.cm4 flash bank super_flash_nar_cm4 psoc6 0x16001A00 0 0 0 ${TARGET}.cm4 flash bank super_flash_key_cm4 psoc6 0x16005A00 0 0 0 ${TARGET}.cm4 flash bank super_flash_toc2_cm4 psoc6 0x16007C00 0 0 0 ${TARGET}.cm4 ${TARGET}.cm4 cortex_m reset_config vectreset ${TARGET}.cm4 configure -event reset-deassert-post "psoc6_deassert_post ${TARGET}.cm4" } if { $_ENABLE_CM0 } { # Use CM0+ by default on dual-core devices targets ${TARGET}.cm0 } if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 18 -expected-id 0x2e200069 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/pxa255.cfg ================================================ # PXA255 chip ... originally from Intel, PXA line was sold to Marvell. # This chip is now at end-of-life. Final orders have been taken. if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME pxa255 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x69264013 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME xscale -endian $_ENDIAN \ -chain-position $_CHIPNAME.cpu # PXA255 comes out of reset using 3.6864 MHz oscillator. # Until the PLL kicks in, keep the JTAG clock slow enough # that we get no errors. adapter speed 300 $_TARGETNAME configure -event "reset-start" { adapter speed 300 } # both TRST and SRST are *required* for debug # DCSR is often accessed with SRST active reset_config trst_and_srst separate srst_nogate # reset processing that works with PXA proc init_reset {mode} { # assert both resets; equivalent to power-on reset adapter assert trst assert srst # drop TRST after at least 32 cycles sleep 1 adapter deassert trst assert srst # minimum 32 TCK cycles to wake up the controller runtest 50 # now the TAP will be responsive; validate scanchain jtag arp_init # ... and take it out of reset adapter deassert trst deassert srst } proc jtag_init {} { init_reset startup } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/pxa270.cfg ================================================ #Marvell/Intel PXA270 Script if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME pxa270 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } #IDs for pxa270. Are there more? if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # set useful default set _CPUTAPID 0x49265013 } if { [info exists CPUTAPID2] } { set _CPUTAPID2 $CPUTAPID2 } else { # set useful default set _CPUTAPID2 0x79265013 } if { [info exists CPUTAPID3] } { set _CPUTAPID2 $CPUTAPID3 } else { # set useful default set _CPUTAPID3 0x89265013 } # set adapter srst delay to the delay introduced by your reset circuit # the rest of the needed delays are built into the openocd program adapter srst delay 260 # set the jtag_ntrst_delay to the delay introduced by a reset circuit # the rest of the needed delays are built into the openocd program jtag_ntrst_delay 250 set _TARGETNAME $_CHIPNAME.cpu jtag newtap $_CHIPNAME cpu -irlen 7 -ircapture 0x1 -irmask 0x7f -expected-id $_CPUTAPID -expected-id $_CPUTAPID2 -expected-id $_CPUTAPID3 target create $_TARGETNAME xscale -endian $_ENDIAN -chain-position $_TARGETNAME # maps to PXA internal RAM. If you are using a PXA255 # you must initialize SDRAM or leave this option off $_TARGETNAME configure -work-area-phys 0x5c000000 -work-area-size 0x10000 -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/pxa3xx.cfg ================================================ # Marvell PXA3xx if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME pxa3xx } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # IDs for all currently known PXA3xx chips if { [info exists CPUTAPID_PXA30X_A0] } { set _CPUTAPID_PXA30X_A0 $CPUTAPID_PXA30X_A0 } else { set _CPUTAPID_PXA30X_A0 0x0E648013 } if { [info exists CPUTAPID_PXA30X_A1] } { set _CPUTAPID_PXA30X_A1 $CPUTAPID_PXA30X_A1 } else { set _CPUTAPID_PXA30X_A1 0x1E648013 } if { [info exists CPUTAPID_PXA31X_A0] } { set _CPUTAPID_PXA31X_A0 $CPUTAPID_PXA31X_A0 } else { set _CPUTAPID_PXA31X_A0 0x0E649013 } if { [info exists CPUTAPID_PXA31X_A1] } { set _CPUTAPID_PXA31X_A1 $CPUTAPID_PXA31X_A1 } else { set _CPUTAPID_PXA31X_A1 0x1E649013 } if { [info exists CPUTAPID_PXA31X_A2] } { set _CPUTAPID_PXA31X_A2 $CPUTAPID_PXA31X_A2 } else { set _CPUTAPID_PXA31X_A2 0x2E649013 } if { [info exists CPUTAPID_PXA31X_B0] } { set _CPUTAPID_PXA31X_B0 $CPUTAPID_PXA31X_B0 } else { set _CPUTAPID_PXA31X_B0 0x3E649013 } if { [info exists CPUTAPID_PXA32X_B1] } { set _CPUTAPID_PXA32X_B1 $CPUTAPID_PXA32X_B1 } else { set _CPUTAPID_PXA32X_B1 0x5E642013 } if { [info exists CPUTAPID_PXA32X_B2] } { set _CPUTAPID_PXA32X_B2 $CPUTAPID_PXA32X_B2 } else { set _CPUTAPID_PXA32X_B2 0x6E642013 } if { [info exists CPUTAPID_PXA32X_C0] } { set _CPUTAPID_PXA32X_C0 $CPUTAPID_PXA32X_C0 } else { set _CPUTAPID_PXA32X_C0 0x7E642013 } # set adapter srst delay to the delay introduced by your reset circuit # the rest of the needed delays are built into the openocd program adapter srst delay 260 # set the jtag_ntrst_delay to the delay introduced by a reset circuit # the rest of the needed delays are built into the openocd program jtag_ntrst_delay 250 set _TARGETNAME $_CHIPNAME.cpu jtag newtap $_CHIPNAME cpu -irlen 11 -ircapture 0x1 -irmask 0x7f \ -expected-id $_CPUTAPID_PXA30X_A0 \ -expected-id $_CPUTAPID_PXA30X_A1 \ -expected-id $_CPUTAPID_PXA31X_A0 \ -expected-id $_CPUTAPID_PXA31X_A1 \ -expected-id $_CPUTAPID_PXA31X_A2 \ -expected-id $_CPUTAPID_PXA31X_B0 \ -expected-id $_CPUTAPID_PXA32X_B1 \ -expected-id $_CPUTAPID_PXA32X_B2 \ -expected-id $_CPUTAPID_PXA32X_C0 target create $_TARGETNAME xscale -endian $_ENDIAN \ -chain-position $_TARGETNAME # work area in internal RAM. $_TARGETNAME configure -work-area-phys 0x5c030000 -work-area-size 0x10000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/qualcomm_qca4531.cfg ================================================ # The QCA4531 is a two stream (2x2) 802.11b/g/n single-band programmable # Wi-Fi System-on-Chip (SoC) for the Internet of Things (IoT). # # Product page: # https://www.qualcomm.com/products/qca4531 # # Notes: # - MIPS Processor ID (PRId): 0x00019374 # - 24Kc MIPS processor with 64 KB I-Cache and 32 KB D-Cache, # operating at up to 650 MHz # - External 16-bit DDR1, operating at up to 200 MHz, DDR2 operating at up # to 300 MHz # - TRST is not available. # - EJTAG PrRst signal is not supported # - RESET_L pin B56 on the SoC will reset internal JTAG logic. # # Pins related for debug and bootstrap: # Name Pin Description # JTAG # JTAG_TCK GPIO0, (A27) Software configurable, default JTAG # JTAG_TDI GPIO1, (B23) Software configurable, default JTAG # JTAG_TDO GPIO2, (A28) Software configurable, default JTAG # JTAG_TMS GPIO3, (A29) Software configurable, default JTAG # Reset # RESET_L -, (B56) Input only # SYS_RST_L GPIO17, (A79) Output reset request or GPIO # Bootstrap # JTAG_MODE GPIO16, (A78) 0 - JTAG (Default); 1 - EJTAG # DDR_SELECT GPIO10, (A57) 0 - DDR2; 1 - DDR1 # UART # UART0_SOUT GPIO10, (A57) # UART0_SIN GPIO9, (B49) # Per default we need to use "none" variant to be able properly "reset init" # or "reset halt" the CPU. reset_config none srst_pulls_trst # For SRST based variant we still need proper timings. # For ETH part the reset should be asserted at least for 10ms # Since there is no other information let's take 100ms to be sure. adapter srst pulse_width 100 # according to the SoC documentation it should take at least 5ms from # reset end till bootstrap end. In the practice we need 8ms to get JTAG back # to live. adapter srst delay 8 if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME qca4531 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00000001 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME # provide watchdog helper. proc disable_watchdog { } { mww 0xb8060008 0x0 } $_TARGETNAME configure -event halted { disable_watchdog } # Since PrRst is not supported and SRST will reset complete chip # with JTAG engine, we need to reset CPU from CPU itself. $_TARGETNAME configure -event reset-assert-pre { halt } $_TARGETNAME configure -event reset-assert { catch "mww 0xb806001C 0x01000000" } # To be able to trigger complete chip reset, in case JTAG is blocked # or CPU not responding, we still can use this helper. proc full_reset { } { reset_config srst_only reset halt reset_config none } # Section with helpers which can be used by boards proc qca4531_ddr2_550_550_init {} { # Clear reset flags for different SoC components mww 0xb806001c 0xfeceffff mww 0xb806001c 0xeeceffff mww 0xb806001c 0xe6ceffff # PMU configurations # Internal Switcher mww 0xb8116c40 0x633c8176 # Increase the DDR voltage mww 0xb8116c44 0x10200000 # XTAL Configurations mww 0xb81162c0 0x4b962100 mww 0xb81162c4 0x480 mww 0xb81162c8 0x04000144 # Recommended PLL configurations mww 0xb81161c4 0x54086000 mww 0xb8116244 0x54086000 # PLL init mww 0xb8050008 0x0131001c mww 0xb8050000 0x40001580 mww 0xb8050004 0x40015800 mww 0xb8050008 0x0131001c mww 0xb8050000 0x00001580 mww 0xb8050004 0x00015800 mww 0xb8050008 0x01310000 mww 0xb8050044 0x781003ff mww 0xb8050048 0x003c103f # DDR2 init mww 0xb8000108 0x401f0042 mww 0xb80000b8 0x0000166d mww 0xb8000000 0xcfaaf33b mww 0xb800015c 0x0000000f mww 0xb8000004 0xa272efa8 mww 0xb8000018 0x0000ffff mww 0xb80000c4 0x74444444 mww 0xb80000c8 0x00000444 mww 0xb8000004 0xa210ee28 mww 0xb8000004 0xa2b2e1a8 mww 0xb8000010 0x8 mww 0xb80000bc 0x0 mww 0xb8000010 0x10 mww 0xb80000c0 0x0 mww 0xb8000010 0x40 mww 0xb800000c 0x2 mww 0xb8000010 0x2 mww 0xb8000008 0xb43 mww 0xb8000010 0x1 mww 0xb8000010 0x8 mww 0xb8000010 0x4 mww 0xb8000010 0x4 mww 0xb8000008 0xa43 mww 0xb8000010 0x1 mww 0xb800000c 0x382 mww 0xb8000010 0x2 mww 0xb800000c 0x402 mww 0xb8000010 0x2 mww 0xb8000014 0x40be mww 0xb800001C 0x20 mww 0xb8000020 0x20 mww 0xb80000cc 0xfffff # UART GPIO programming mww 0xb8040000 0xff30b mww 0xb8040044 0x908 mww 0xb8040034 0x160000 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/quark_d20xx.cfg ================================================ if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x38289013 } jtag newtap quark_d20xx quark -irlen 8 -irmask 0xff -expected-id $_CPUTAPID -disable jtag newtap quark_d20xx cltap -irlen 8 -irmask 0xff -expected-id 0x0e786013 -enable proc quark_d20xx_tapenable {} { echo "enabling quark core tap" irscan quark_d20xx.cltap 0x11 drscan quark_d20xx.cltap 12 1 runtest 10 } proc quark_d20xx_tapdisable {} { echo "disabling quark core tap" irscan quark_d20xx.cltap 0x11 drscan quark_d20xx.cltap 12 0 runtest 10 } proc quark_d20xx_setup {} { jtag tapenable quark_d20xx.quark } jtag configure quark_d20xx.quark -event tap-enable \ "quark_d20xx_tapenable" jtag configure quark_d20xx.quark -event tap-disable \ "quark_d20xx_tapdisable" target create quark_d20xx.quark quark_d20xx -endian little -chain-position quark_d20xx.quark quark_d20xx.quark configure -event reset-start { # need to halt the target to write to memory if {[quark_d20xx.quark curstate] ne "halted"} { halt } # set resetbreak via the core tap irscan quark_d20xx.quark 0x35 ; drscan quark_d20xx.quark 1 0x1 # trigger a warm reset mww 0xb0800570 0x2 # clear resetbreak irscan quark_d20xx.quark 0x35 ; drscan quark_d20xx.quark 1 0x0 } jtag configure quark_d20xx.quark -event setup \ "quark_d20xx_setup" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/quark_x10xx.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME quark_x10xx } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x18289013 } jtag newtap quark_x10xx cpu -irlen 8 -irmask 0xff -expected-id $_CPUTAPID -disable jtag newtap quark_x10xx cltap -irlen 8 -irmask 0xff -expected-id 0x0e681013 -enable #openocd puts tap at front of chain not end of chain proc quark_x10xx_tapenable {} { echo "enabling core tap" irscan quark_x10xx.cltap 0x11 drscan quark_x10xx.cltap 64 1 runtest 10 } proc quark_x10xx_tapdisable {} { echo "disabling core tap" irscan quark_x10xx.cltap 0x11 drscan quark_x10xx.cltap 64 0 runtest 10 } proc quark_x10xx_setup {} { jtag tapenable quark_x10xx.cpu } jtag configure $_CHIPNAME.cpu -event tap-enable \ "quark_x10xx_tapenable" jtag configure $_CHIPNAME.cpu -event tap-disable \ "quark_x10xx_tapdisable" set _TARGETNAME $_CHIPNAME.cpu target create quark_x10xx.cpu quark_x10xx -endian $_ENDIAN -chain-position quark_x10xx.cpu jtag configure $_CHIPNAME.cpu -event setup \ "quark_x10xx_setup" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/readme.txt ================================================ Prerequisites: The users of OpenOCD as well as computer programs interacting with OpenOCD are expecting that certain commands do the same thing across all the targets. Rules to follow when writing scripts: 1. The configuration script should be defined such as , for example, the following sequences are working: reset flash info and reset flash erase_address and reset init load In most cases this can be accomplished by specifying the default startup mode as reset_init (target command in the configuration file). 2. If the target is correctly configured, flash must be writable without any other helper commands. It is assumed that all write-protect mechanisms should be disabled. 3. The configuration scripts should be defined such as the binary that was written to flash verifies (turn off remapping, checksums, etc...) flash write_image [file] verify_image [file] 4. adapter speed sets the maximum speed (or alternatively RCLK). If invoked multiple times only the last setting is used. interface/xxx.cfg files are always executed *before* target/xxx.cfg files, so any adapter speed in interface/xxx.cfg will be overridden by target/xxx.cfg. adapter speed in interface/xxx.cfg would then, effectively, set the default JTAG speed. Note that a target/xxx.cfg file can invoke another target/yyy.cfg file, so one can create target subtype configurations where e.g. only amount of DRAM, oscillator speeds differ and having a single config file for the default/common settings. ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/renesas_r7s72100.cfg ================================================ # Renesas RZ/A1H # https://www.renesas.com/eu/en/products/microcontrollers-microprocessors/rz/rza/rza1h.html if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME r7s72100 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID # Configuring only one core using DAP. # Base addresses of cores: # core 0 - 0x80030000 set _TARGETNAME $_CHIPNAME.ca9 dap create ${_CHIPNAME}.dap -chain-position $_CHIPNAME.cpu target create ${_TARGETNAME} cortex_a -dap ${_CHIPNAME}.dap -coreid 0 -dbgbase 0x80030000 targets ${_TARGETNAME} ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/renesas_rcar_gen2.cfg ================================================ # Renesas R-Car Generation 2 SOCs # - There are a combination of Cortex-A15s and Cortex-A7s for each Gen2 SOC # - Each SOC can boot through any of the, up to 2, core types that it has # e.g. H2 can boot through Cortex-A15 or Cortex-A7 # Supported Gen2 SOCs and their cores: # H2: Cortex-A15 x 4, Cortex-A7 x 4 # M2: Cortex-A15 x 2 # V2H: Cortex-A15 x 2 # M2N: Cortex-A15 x 2 # E2: Cortex-A7 x 2 # Usage: # There are 2 configuration options: # SOC: Selects the supported SOC. (Default 'H2') # BOOT_CORE: Selects the booting core. 'CA15', or 'CA7' # Defaults to 'CA15' if the SOC has one, else defaults to 'CA7' if { [info exists SOC] } { set _soc $SOC } else { set _soc H2 } # Set configuration for each SOC and the default 'BOOT_CORE' switch $_soc { H2 { set _CHIPNAME r8a7790 set _num_ca15 4 set _num_ca7 4 set _boot_core CA15 } M2 { set _CHIPNAME r8a7791 set _num_ca15 2 set _num_ca7 0 set _boot_core CA15 } V2H { set _CHIPNAME r8a7792 set _num_ca15 2 set _num_ca7 0 set _boot_core CA15 } M2N { set _CHIPNAME r8a7793 set _num_ca15 2 set _num_ca7 0 set _boot_core CA15 } E2 { set _CHIPNAME r8a7794 set _num_ca15 0 set _num_ca7 2 set _boot_core CA7 } default { error "'$_soc' is invalid!" } } # If configured, override the default 'CHIPNAME' if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } # If configured, override the default 'BOOT_CORE' if { [info exists BOOT_CORE] } { set _boot_core $BOOT_CORE } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } echo "\t$_soc - $_num_ca15 CA15(s), $_num_ca7 CA7(s)" echo "\tBoot Core - $_boot_core\n" set _DAPNAME $_CHIPNAME.dap # TAP and DAP jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID dap create $_DAPNAME -chain-position $_CHIPNAME.cpu set CA15_DBGBASE {0x800B0000 0x800B2000 0x800B4000 0x800B6000} set CA7_DBGBASE {0x800F0000 0x800F2000 0x800F4000 0x800F6000} set _targets "" set smp_targets "" proc setup_ca {core_name dbgbase num boot} { global _CHIPNAME global _DAPNAME global smp_targets global _targets for { set _core 0 } { $_core < $num } { incr _core } { set _TARGETNAME $_CHIPNAME.$core_name.$_core set _CTINAME $_TARGETNAME.cti set _command "target create $_TARGETNAME cortex_a -dap $_DAPNAME \ -coreid $_core -dbgbase [lindex $dbgbase $_core]" if { $_core == 0 && $boot == 1 } { set _targets "$_TARGETNAME" } else { set _command "$_command -defer-examine" } set smp_targets "$smp_targets $_TARGETNAME" eval $_command } } # Organize target list based on the boot core if { [string equal $_boot_core CA15] } { setup_ca a15 $CA15_DBGBASE $_num_ca15 1 setup_ca a7 $CA7_DBGBASE $_num_ca7 0 } elseif { [string equal $_boot_core CA7] } { setup_ca a7 $CA7_DBGBASE $_num_ca7 1 setup_ca a15 $CA15_DBGBASE $_num_ca15 0 } else { setup_ca a15 $CA15_DBGBASE $_num_ca15 0 setup_ca a7 $CA7_DBGBASE $_num_ca7 0 } source [find target/renesas_rcar_reset_common.cfg] eval "target smp $smp_targets" targets $_targets ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/renesas_rcar_gen3.cfg ================================================ # Renesas R-Car Generation 3 SOCs # - There are a combination of Cortex-A57s, Cortex-A53s, and Cortex-R7 for each Gen3 SOC # - Each SOC can boot through any of the, up to 3, core types that it has # e.g. H3 can boot through Cortex-A57, Cortex-A53, or Cortex-R7 # Supported Gen3 SOCs and their cores: # H3: Cortex-A57 x 4, Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step) # M3W: Cortex-A57 x 2, Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step) # M3N: Cortex-A57 x 2, Cortex-R7 x 2 (Lock-Step) # V3U: Cortex-A76 x 8, Cortex-R52 x2 (Lock-Step) # V3H: Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step) # V3M: Cortex-A53 x 2, Cortex-R7 x 2 (Lock-Step) # E3: Cortex-A53 x 1, Cortex-R7 x 2 (Lock-Step) # D3: Cortex-A53 x 1 # Usage: # There are 2 configuration options: # SOC: Selects the supported SOC. (Default 'H3') # BOOT_CORE: Selects the booting core. 'CA57', 'CA53', or 'CR7' # Defaults to 'CA57' if the SOC has one, else defaults to 'CA53' if { [info exists SOC] } { set _soc $SOC } else { set _soc H3 } set _num_ca53 0 set _num_ca57 0 set _num_ca76 0 set _num_cr52 0 set _num_cr7 0 # Set configuration for each SOC and the default 'BOOT_CORE' switch $_soc { H3 { set _CHIPNAME r8a77950 set _num_ca57 4 set _num_ca53 4 set _num_cr7 1 set _boot_core CA57 } M3W { set _CHIPNAME r8a77960 set _num_ca57 2 set _num_ca53 4 set _num_cr7 1 set _boot_core CA57 } M3N { set _CHIPNAME r8a77965 set _num_ca57 2 set _num_ca53 4 set _num_cr7 1 set _boot_core CA57 } V3M { set _CHIPNAME r8a77970 set _num_ca57 0 set _num_ca53 2 set _num_cr7 1 set _boot_core CA53 } V3H { set _CHIPNAME r8a77980 set _num_ca57 0 set _num_ca53 4 set _num_cr7 1 set _boot_core CA53 } E3 { set _CHIPNAME r8a77990 set _num_ca57 0 set _num_ca53 1 set _num_cr7 1 set _boot_core CA53 } D3 { set _CHIPNAME r8a77995 set _num_ca57 0 set _num_ca53 1 set _num_cr7 0 set _boot_core CA53 } V3U { set _CHIPNAME r8a779a0 set _num_ca76 8 set _num_cr52 1 set _boot_core CA76 } default { error "'$_soc' is invalid!" } } # If configured, override the default 'CHIPNAME' if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } # If configured, override the default 'BOOT_CORE' if { [info exists BOOT_CORE] } { set _boot_core $BOOT_CORE } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } echo "\t$_soc - $_num_ca76 CA76(s), $_num_ca57 CA57(s), $_num_ca53 CA53(s), $_num_cr52 CR52(s), $_num_cr7 CR7(s)" echo "\tBoot Core - $_boot_core\n" set _DAPNAME $_CHIPNAME.dap # TAP and DAP jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID dap create $_DAPNAME -chain-position $_CHIPNAME.cpu set CA76_DBGBASE {0x81410000 0x81510000 0x81610000 0x81710000 0x81c10000 0x81d10000 0x81e10000 0x81f10000} set CA76_CTIBASE {0x81420000 0x81520000 0x81620000 0x81720000 0x81c20000 0x81d20000 0x81e20000 0x81f20000} set CA57_DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} set CA57_CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} set CA53_DBGBASE {0x80C10000 0x80D10000 0x80E10000 0x80F10000} set CA53_CTIBASE {0x80C20000 0x80D20000 0x80E20000 0x80F20000} set CR52_DBGBASE 0x80c10000 set CR52_CTIBASE 0x80c20000 set CR7_DBGBASE 0x80910000 set CR7_CTIBASE 0x80918000 set _targets "" set smp_targets "" proc setup_a5x {core_name dbgbase ctibase num boot} { global _CHIPNAME global _DAPNAME global smp_targets global _targets for { set _core 0 } { $_core < $num } { incr _core } { set _TARGETNAME $_CHIPNAME.$core_name.$_core set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $_DAPNAME -ap-num 1 \ -baseaddr [lindex $ctibase $_core] set _command "target create $_TARGETNAME aarch64 -dap $_DAPNAME \ -ap-num 1 -dbgbase [lindex $dbgbase $_core] -cti $_CTINAME" if { $_core == 0 && $boot == 1 } { set _targets "$_TARGETNAME" } else { set _command "$_command -defer-examine" } set smp_targets "$smp_targets $_TARGETNAME" eval $_command } } proc setup_cr7 {core_name dbgbase ctibase num boot} { global _CHIPNAME global _DAPNAME for { set _core 0 } { $_core < $num } { incr _core } { set _TARGETNAME $_CHIPNAME.$core_name set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -baseaddr $ctibase set _command "target create $_TARGETNAME cortex_r4 -dap $_DAPNAME \ -ap-num 1 -dbgbase $dbgbase" if { $boot == 1 } { set _targets "$_TARGETNAME" } else { set _command "$_command -defer-examine" } eval $_command } } # Organize target list based on the boot core if { [string equal $_boot_core CA76] } { setup_a5x a76 $CA76_DBGBASE $CA76_CTIBASE $_num_ca76 1 setup_cr7 r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 0 } elseif { [string equal $_boot_core CA57] } { setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 1 setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0 setup_cr7 r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0 } elseif { [string equal $_boot_core CA53] } { setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 1 setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0 setup_cr7 r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0 } elseif { [string equal $_boot_core CR52] } { setup_cr7 r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 1 setup_a5x a76 $CA76_DBGBASE $CA76_CTIBASE $_num_ca76 0 } else { setup_cr7 r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 1 setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0 setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0 } source [find target/renesas_rcar_reset_common.cfg] eval "target smp $smp_targets" targets $_targets ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/renesas_rcar_reset_common.cfg ================================================ # Renesas R-Car Gen2 Evaluation Board common settings reset_config trst_and_srst srst_nogate proc init_reset {mode} { # Assert both resets: equivalent to a power-on reset adapter assert trst assert srst # Deassert TRST to begin TAP communication adapter deassert trst assert srst # TAP should now be responsive, validate the scan-chain jtag arp_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/renesas_rz_five.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas RZ/Five SoC # # General-purpose Microprocessors with RISC-V CPU Core (Andes AX45MP Single) (1.0 GHz) transport select jtag reset_config trst_and_srst srst_gates_jtag adapter speed 4000 adapter srst delay 500 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME r9A07g043u } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/renesas_rz_g2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas RZ/G2 SOCs # - There are a combination of Cortex-A57s, Cortex-A53s, Cortex-A55, Cortex-R7 # and Cortex-M33 for each SOC # - Each SOC can boot through the Cortex-A5x cores # Supported RZ/G2 SOCs and their cores: # RZ/G2H: Cortex-A57 x4, Cortex-A53 x4, Cortex-R7 # RZ/G2M: Cortex-A57 x2, Cortex-A53 x4, Cortex-R7 # RZ/G2N: Cortex-A57 x2, Cortex-R7 # RZ/G2E: Cortex-A53 x2, Cortex-R7 # RZ/G2L: Cortex-A55 x2, Cortex-M33 # RZ/G2LC: Cortex-A55 x2, Cortex-M33 # RZ/G2UL: Cortex-A55 x1, Cortex-M33 # Usage: # There are 2 configuration options: # SOC: Selects the supported SOC. (Default 'G2L') # BOOT_CORE: Selects the booting core. 'CA57', 'CA53' or 'CA55' transport select jtag reset_config trst_and_srst srst_gates_jtag adapter speed 4000 adapter srst delay 500 if { [info exists SOC] } { set _soc $SOC } else { set _soc G2L } set _num_ca57 0 set _num_ca55 0 set _num_ca53 0 set _num_cr7 0 set _num_cm33 0 # Set configuration for each SOC and the default 'BOOT_CORE' switch $_soc { G2H { set _CHIPNAME r8a774ex set _num_ca57 4 set _num_ca53 4 set _num_cr7 1 set _boot_core CA57 set _ap_num 1 } G2M { set _CHIPNAME r8a774ax set _num_ca57 2 set _num_ca53 4 set _num_cr7 1 set _boot_core CA57 set _ap_num 1 } G2N { set _CHIPNAME r8a774bx set _num_ca57 2 set _num_ca53 0 set _num_cr7 1 set _boot_core CA57 set _ap_num 1 } G2E { set _CHIPNAME r8a774c0 set _num_ca57 0 set _num_ca53 2 set _num_cr7 1 set _boot_core CA53 set _ap_num 1 } G2L { set _CHIPNAME r9a07g044l set _num_ca55 2 set _num_cm33 1 set _boot_core CA55 set _ap_num 0 } G2LC { set _CHIPNAME r9a07g044c set _num_ca55 2 set _num_cm33 1 set _boot_core CA55 set _ap_num 0 } G2UL { set _CHIPNAME r9a07g043u set _num_ca55 1 set _num_cm33 1 set _boot_core CA55 set _ap_num 0 } default { error "'$_soc' is invalid!" } } # If configured, override the default 'CHIPNAME' if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } # If configured, override the default 'BOOT_CORE' if { [info exists BOOT_CORE] } { set _boot_core $BOOT_CORE } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x6ba00477 } echo "\t$_soc - $_num_ca57 CA57(s), $_num_ca55 CA55(s), $_num_ca53 CA53(s), $_num_cr7 CR7(s), \ $_num_cm33 CM33(s)" echo "\tBoot Core - $_boot_core\n" set _DAPNAME $_CHIPNAME.dap # TAP and DAP jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID \ -ignore-version dap create $_DAPNAME -chain-position $_CHIPNAME.cpu echo "$_CHIPNAME.cpu" set CA57_DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} set CA57_CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} set CA55_DBGBASE {0x10E10000 0x10F10000} set CA55_CTIBASE {0x10E20000 0x10F20000} set CA53_DBGBASE {0x80C10000 0x80D10000 0x80E10000 0x80F10000} set CA53_CTIBASE {0x80C20000 0x80D20000 0x80E20000 0x80F20000} set CR7_DBGBASE 0x80910000 set CR7_CTIBASE 0x80918000 set CM33_DBGBASE 0xE000E000 set CM33_CTIBASE 0xE0042000 set smp_targets "" proc setup_a5x {core_name dbgbase ctibase num boot} { for { set _core 0 } { $_core < $num } { incr _core } { set _TARGETNAME $::_CHIPNAME.$core_name.$_core set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $::_DAPNAME -ap-num $::_ap_num \ -baseaddr [lindex $ctibase $_core] target create $_TARGETNAME aarch64 -dap $::_DAPNAME \ -ap-num $::_ap_num -dbgbase [lindex $dbgbase $_core] -cti $_CTINAME if { $_core > 0 || $boot == 0 } { $_TARGETNAME configure -defer-examine } set ::smp_targets "$::smp_targets $_TARGETNAME" } } proc setup_cr7 {dbgbase ctibase} { set _TARGETNAME $::_CHIPNAME.r7 set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $::_DAPNAME -ap-num 1 -baseaddr $ctibase target create $_TARGETNAME cortex_r4 -dap $::_DAPNAME \ -ap-num 1 -dbgbase $dbgbase -defer-examine } proc setup_cm33 {dbgbase ctibase} { set _TARGETNAME $::_CHIPNAME.m33 set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $::_DAPNAME -ap-num 2 -baseaddr $ctibase target create $_TARGETNAME cortex_m -dap $::_DAPNAME \ -ap-num 2 -dbgbase $dbgbase -defer-examine } # Organize target list based on the boot core if { $_boot_core == "CA57" } { setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 1 setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0 setup_cr7 $CR7_DBGBASE $CR7_CTIBASE } elseif { $_boot_core == "CA53" } { setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 1 setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0 setup_cr7 $CR7_DBGBASE $CR7_CTIBASE } elseif { $_boot_core == "CA55" } { setup_a5x a55 $CA55_DBGBASE $CA55_CTIBASE $_num_ca55 1 setup_cm33 $CM33_DBGBASE $CM33_CTIBASE } echo "SMP targets:$smp_targets" eval "target smp $smp_targets" if { $_soc == "G2L" || $_soc == "G2LC" || $_soc == "G2UL" } { target create $_CHIPNAME.axi_ap mem_ap -dap $_DAPNAME -ap-num 1 } proc init_reset {mode} { # Assert both resets: equivalent to a power-on reset adapter assert trst assert srst # Deassert TRST to begin TAP communication adapter deassert trst assert srst # TAP should now be responsive, validate the scan-chain jtag arp_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/renesas_s7g2.cfg ================================================ # # Renesas Synergy S7 G2 w/ ARM Cortex-M4 @ 240 MHz # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME s7g2 } if { [info exists CPU_JTAG_TAPID] } { set _CPU_JTAG_TAPID $CPU_JTAG_TAPID } else { set _CPU_JTAG_TAPID 0x5ba00477 } if { [info exists CPU_SWD_TAPID] } { set _CPU_SWD_TAPID $CPU_SWD_TAPID } else { set _CPU_SWD_TAPID 0x5ba02477 } source [find target/swj-dp.tcl] if { [using_jtag] } { set _CPU_TAPID $_CPU_JTAG_TAPID } else { set _CPU_TAPID $_CPU_SWD_TAPID } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { # 640 KB On-Chip SRAM set _WORKAREASIZE 0xa0000 } $_TARGETNAME configure -work-area-phys 0x1ffe0000 \ -work-area-size $_WORKAREASIZE -work-area-backup 0 if { ![using_hla] } { cortex_m reset_config sysresetreq } adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/rk3308.cfg ================================================ # Rockchip RK3308 Target # https://rockchip.fr/RK3308%20datasheet%20V1.5.pdf # https://dl.radxa.com/rockpis/docs/hw/datasheets/Rockchip%20RK3308TRM%20V1.1%20Part1-20180810.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME rk3308 } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x2ba01477 } adapter speed 12000 transport select swd # declare the one SWD tap to access the DAP swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID -ignore-version # create the DAP dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 # declare the 4 main application cores set _TARGETNAME $_CHIPNAME.core set _smp_command "" set $_TARGETNAME.base(0) 0x81010000 set $_TARGETNAME.base(1) 0x81012000 set $_TARGETNAME.base(2) 0x81014000 set $_TARGETNAME.base(3) 0x81016000 set $_TARGETNAME.cti(0) 0x81018000 set $_TARGETNAME.cti(1) 0x81019000 set $_TARGETNAME.cti(2) 0x8101a000 set $_TARGETNAME.cti(3) 0x8101b000 set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core \ -dbgbase [set $_TARGETNAME.base($_core)]" if { $_core != 0 } { set _smp_command "$_smp_command ${_TARGETNAME}$_core" set _command "$_command -defer-examine" } else { # uncomment to use hardware threads pseudo rtos # set _command "$_command -rtos hwthread" set _command "$_command -work-area-size 0x40000 -work-area-phys 0xfff80000 \ -work-area-backup 0" set _smp_command "target smp ${_TARGETNAME}$_core" } eval $_command } eval $_smp_command targets ${_TARGETNAME}0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/rk3399.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Rockchip RK3399 Target # https://rockchip.fr/RK3399%20datasheet%20V1.8.pdf # https://rockchip.fr/Rockchip%20RK3399%20TRM%20V1.4%20Part1.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME rk3399 } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba02477 } adapter speed 12000 transport select swd # declare the one SWD tap to access the DAP swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID -ignore-version # create the DAP dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 set _TARGETNAME $_CHIPNAME.lcore # declare the 6 main application cores set _smp_command "" set $_TARGETNAME.base(0) 0x80030000 set $_TARGETNAME.base(1) 0x80032000 set $_TARGETNAME.base(2) 0x80034000 set $_TARGETNAME.base(3) 0x80036000 set $_TARGETNAME.cti(0) 0x80038000 set $_TARGETNAME.cti(1) 0x80039000 set $_TARGETNAME.cti(2) 0x8003a000 set $_TARGETNAME.cti(3) 0x8003b000 set _TARGETNAME $_CHIPNAME.bcore set $_TARGETNAME.base(4) 0x80210000 set $_TARGETNAME.base(5) 0x80310000 set $_TARGETNAME.cti(4) 0x80220000 set $_TARGETNAME.cti(5) 0x80320000 set _cores 6 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { if {$_core < 4} { set _TARGETNAME $_CHIPNAME.lcore } else { set _TARGETNAME $_CHIPNAME.bcore } cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 1 target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core \ -dbgbase [set $_TARGETNAME.base($_core)] if { $_core != 0 } { ${_TARGETNAME}$_core configure -defer-examine } else { # uncomment to use hardware threads pseudo rtos # ${_TARGETNAME}$_core configure -rtos hwthread" ${_TARGETNAME}$_core configure -work-area-size 0x30000 -work-area-phys 0xff8c0000 \ -work-area-backup 0 } set _smp_command "$_smp_command ${_TARGETNAME}$_core" } target smp $_smp_command targets rk3399.lcore0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/rp2040-core0.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later transport select swd source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME rp2040 } if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x10000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x01002927 } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20010000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash set _FLASHSIZE 0x200000 set _FLASHBASE 0x10000000 flash bank $_FLASHNAME rp2040_flash $_FLASHBASE $_FLASHSIZE 1 32 $_TARGETNAME # srst does not exist; use SYSRESETREQ to perform a soft reset cortex_m reset_config sysresetreq ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/samsung_s3c2410.cfg ================================================ # Found on the 'TinCanTools' Hammer board. if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME s3c2410 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # This config file was defaulting to big endian.. set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # Force an error until we get a good number. set _CPUTAPID 0xffffffff } #use combined on interfaces or targets that cannot set TRST/SRST separately reset_config trst_and_srst #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm920t -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x30800000 -work-area-size 0x20000 -work-area-backup 0 # speed up memory downloads arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/samsung_s3c2440.cfg ================================================ # Target configuration for the Samsung 2440 system on chip # Tested on a S3C2440 Evaluation board by keesj # Processor : ARM920Tid(wb) rev 0 (v4l) # Info: JTAG tap: s3c2440.cpu tap/device found: 0x0032409d (Manufacturer: 0x04e, Part: 0x0324, Version: 0x0) if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME s3c2440 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a bigendian set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0032409d } #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm920t -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x200000 -work-area-size 0x4000 -work-area-backup 1 #reset configuration reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/samsung_s3c2450.cfg ================================================ # Target configuration for the Samsung 2450 system on chip # Processor : ARM926ejs (wb) rev 0 (v4l) # Info: JTAG tap: s3c2450.cpu tap/device found: 0x07926F0F # FIX!!! what to use here? # # RCLK? # # adapter speed 0 # # Really low clock during reset? # # adapter speed 1 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME s3c2450 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a bigendian set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926f0f } #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0xE -irmask 0x0f -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME # FIX!!!!! should this really use srst_pulls_trst? # With srst_pulls_trst "reset halt" will not reset into the # halted mode, but rather "reset run" and then halt the target. # # However, without "srst_pulls_trst", then "reset halt" produces weird # errors: # WARNING: unknown debug reason: 0x0 reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/samsung_s3c4510.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME s3c4510 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # This appears to be a "Version 1" arm7tdmi. if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x1f0f0f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/samsung_s3c6410.cfg ================================================ # -*- tcl -*- # Target configuration for the Samsung s3c6410 system on chip # Tested on a SMDK6410 # Processor : ARM1176 # Info: JTAG device found: 0x0032409d (Manufacturer: 0x04e, Part: 0x0324, Version: 0x0) # [Duane Ellis 27/nov/2008: Above 0x0032409d appears to be copy/paste from other places] # [and I do not believe it to be accurate, hence the 0xffffffff below] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME s3c6410 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a bigendian set _ENDIAN little } # trace buffer if { [info exists ETBTAPID] } { set _ETBTAPID $ETBTAPID } else { set _ETBTAPID 0x2b900f0f } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07b76f0f } #jtag scan chain jtag newtap $_CHIPNAME etb -irlen 4 -expected-id $_ETBTAPID jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm11 -endian $_ENDIAN -chain-position $_TARGETNAME adapter srst delay 500 jtag_ntrst_delay 500 #reset configuration reset_config trst_and_srst # trace setup ... NOTE, "normal full" mode fudges the real ETMv3.1 mode etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/sharp_lh79532.cfg ================================================ reset_config srst_only srst_pulls_trst if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lh79532 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # sharp changed the number! set _CPUTAPID 0x00002061 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/sim3x.cfg ================================================ # # Silicon Laboratories SiM3x Cortex-M3 # # SiM3x devices support both JTAG and SWD transports. source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME SiM3x } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } if { [info exists CPURAMSIZE] } { set _CPURAMSIZE $CPURAMSIZE } else { # Minimum size of RAM in the Silicon Labs product matrix (8KB) set _CPURAMSIZE 0x2000 } if { [info exists CPUROMSIZE] } { set _CPUROMSIZE $CPUROMSIZE } else { # Minimum size of FLASH in the Silicon Labs product matrix (32KB) set _CPUROMSIZE 0x8000 } if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE $_CPURAMSIZE } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME sim3x 0 $_CPUROMSIZE 0 0 $_TARGETNAME adapter speed 1000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/smp8634.cfg ================================================ # script for Sigma Designs SMP8634 (eventually even SMP8635) if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME smp8634 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x08630001 } adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst separate # jtag scan chain # format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE) jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian $_ENDIAN ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/snps_em_sk_fpga.cfg ================================================ # Copyright (C) 2014-2015,2020 Synopsys, Inc. # Anton Kolesov # Didin Evgeniy # # SPDX-License-Identifier: GPL-2.0-or-later # # Xilinx Spartan-6 XC6SLX45 FPGA on EM Starter Kit v1. # Xilinx Spartan-6 XC6SLX150 FPGA on EM Starter Kit v2. # source [find cpu/arc/em.tcl] set _CHIPNAME arc-em set _TARGETNAME $_CHIPNAME.cpu # EM SK IDENTITY is 0x200444b1 # EM SK v2 IDENTITY is 0x200044b1 jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -expected-id 0x200444b1 \ -expected-id 0x200044b1 set _coreid 0 set _dbgbase [expr {0x00000000 | ($_coreid << 13)}] target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME \ -coreid 0 -dbgbase $_dbgbase -endian little # There is no SRST, so do a software reset $_TARGETNAME configure -event reset-assert "arc_em_reset $_TARGETNAME" arc_em_init_regs # vim:ft=tcl ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/snps_hsdk.cfg ================================================ # Copyright (C) 2019,2020 Synopsys, Inc. # Anton Kolesov # Didin Evgeniy # # SPDX-License-Identifier: GPL-2.0-or-later # # HS Development Kit SoC. # # Contains quad-core ARC HS38. # source [find cpu/arc/hs.tcl] set _coreid 0 set _dbgbase [expr {$_coreid << 13}] # CHIPNAME will be used to choose core family (600, 700 or EM). As far as # OpenOCD is concerned EM and HS are identical. set _CHIPNAME arc-em # OpenOCD discovers JTAG TAPs in reverse order. # ARC HS38 core 4 set _TARGETNAME $_CHIPNAME.cpu4 jtag newtap $_CHIPNAME cpu4 -irlen 4 -ircapture 0x1 -expected-id 0x200c24b1 target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME $_TARGETNAME configure -coreid $_coreid $_TARGETNAME configure -dbgbase $_dbgbase # Flush L2$. $_TARGETNAME configure -event reset-assert "arc_hs_reset $_TARGETNAME" set _coreid [expr {$_coreid + 1}] set _dbgbase [expr {$_coreid << 13}] arc_hs_init_regs # Enable L2 cache support for core 4. $_TARGETNAME arc cache l2 auto 1 # ARC HS38 core 3 set _TARGETNAME $_CHIPNAME.cpu3 jtag newtap $_CHIPNAME cpu3 -irlen 4 -ircapture 0x1 -expected-id 0x200824b1 target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME $_TARGETNAME configure -coreid $_coreid $_TARGETNAME configure -dbgbase $_dbgbase $_TARGETNAME configure -event reset-assert "arc_common_reset $_TARGETNAME" set _coreid [expr {$_coreid + 1}] set _dbgbase [expr {$_coreid << 13}] arc_hs_init_regs # Enable L2 cache support for core 3. $_TARGETNAME arc cache l2 auto 1 # ARC HS38 core 2 set _TARGETNAME $_CHIPNAME.cpu2 jtag newtap $_CHIPNAME cpu2 -irlen 4 -ircapture 0x1 -expected-id 0x200424b1 target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME $_TARGETNAME configure -coreid $_coreid $_TARGETNAME configure -dbgbase $_dbgbase $_TARGETNAME configure -event reset-assert "arc_common_reset $_TARGETNAME" set _coreid [expr {$_coreid + 1}] set _dbgbase [expr {$_coreid << 13}] arc_hs_init_regs # Enable L2 cache support for core 2. $_TARGETNAME arc cache l2 auto 1 # ARC HS38 core 1 set _TARGETNAME $_CHIPNAME.cpu1 jtag newtap $_CHIPNAME cpu1 -irlen 4 -ircapture 0x1 -expected-id 0x200024b1 target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME $_TARGETNAME configure -coreid $_coreid $_TARGETNAME configure -dbgbase $_dbgbase $_TARGETNAME configure -event reset-assert "arc_common_reset $_TARGETNAME" set _coreid [expr {$_coreid + 1}] set _dbgbase [expr {0x00000000 | ($_coreid << 13)}] arc_hs_init_regs # Enable L2 cache support for core 1. $_TARGETNAME arc cache l2 auto 1 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/spear3xx.cfg ================================================ # Target configuration for the ST SPEAr3xx family of system on chip # Supported SPEAr300, SPEAr310, SPEAr320 # http://www.st.com/spear # # Processor: ARM926ejs # Info: JTAG tap: spear3xx.cpu tap/device found: 0x07926041 # Date: 2009-10-31 # Author: Antonio Borneo if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME spear3xx } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926041 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x03 \ -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN \ -chain-position $_TARGETNAME # SPEAr3xx has a 8K block of sram @ 0xd280.0000 # REVISIT: what OS puts virtual address equal to phys? $_TARGETNAME configure \ -work-area-virt 0xd2800000 \ -work-area-phys 0xd2800000 \ -work-area-size 0x2000 \ -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stellaris.cfg ================================================ # TI/Luminary Stellaris LM3S chip family # Some devices have errata in returning their device class. # DEVICECLASS is provided as a manual override # Manual setting of a device class of 0xff is not allowed global _DEVICECLASS if { [info exists DEVICECLASS] } { set _DEVICECLASS $DEVICECLASS } else { set _DEVICECLASS 0xff } # Luminary chips support both JTAG and SWD transports. # Adapt based on what transport is active. source [find target/swj-dp.tcl] # For now we ignore the SPI and UART options, which # are usable only for ISP style initial flash programming. if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lm3s } # CPU TAP ID 0x1ba00477 for early Sandstorm parts # CPU TAP ID 0x2ba00477 for later SandStorm parts, e.g. lm3s811 Rev C2 # CPU TAP ID 0x3ba00477 for Cortex-M3 r1p2 (on Fury, DustDevil) # CPU TAP ID 0x4ba00477 for Cortex-M3 r2p0 (on Tempest, Firestorm) # CPU TAP ID 0x4ba00477 for Cortex-M4 r0p1 (on Blizzard) # ... we'll ignore the JTAG version field, rather than list every # chip revision that turns up. if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0ba00477 } # SWD DAP, and JTAG TAP, take same params for now; # ... even though SWD ignores all except TAPID, and # JTAG shouldn't need anything more then irlen. (and TAPID). swj_newdap $_CHIPNAME cpu -irlen 4 -irmask 0xf \ -expected-id $_CPUTAPID -ignore-version dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { # default to 2K working area set _WORKAREASIZE 0x800 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap # 8K working area at base of ram, not backed up # # NOTE: you may need or want to reconfigure the work area; # some parts have just 6K, and you may want to use other # addresses (at end of mem not beginning) or back it up. $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE # JTAG speed ... slow enough to work with a 12 MHz RC oscillator; # LM3S parts don't support RTCK # # NOTE: this may be increased by a reset-init handler, after it # configures and enables the PLL. Or you might need to decrease # this, if you're using a slower clock. adapter speed 500 source [find mem_helper.tcl] proc reset_peripherals {family} { source [find chip/ti/lm3s/lm3s.tcl] echo "Resetting Core Peripherals" # Disable the PLL and the system clock divider (nop if disabled) mmw $SYSCTL_RCC 0 $SYSCTL_RCC_USESYSDIV mmw $SYSCTL_RCC2 $SYSCTL_RCC2_BYPASS2 0 # RCC and RCC2 to their reset values mww $SYSCTL_RCC [expr {0x078e3ad0 | ([mrw $SYSCTL_RCC] & $SYSCTL_RCC_MOSCDIS)}] mww $SYSCTL_RCC2 0x07806810 mww $SYSCTL_RCC 0x078e3ad1 # Reset the deep sleep clock configuration register mww $SYSCTL_DSLPCLKCFG 0x07800000 # Reset the clock gating registers mww $SYSCTL_RCGC0 0x00000040 mww $SYSCTL_RCGC1 0 mww $SYSCTL_RCGC2 0 mww $SYSCTL_SCGC0 0x00000040 mww $SYSCTL_SCGC1 0 mww $SYSCTL_SCGC2 0 mww $SYSCTL_DCGC0 0x00000040 mww $SYSCTL_DCGC1 0 mww $SYSCTL_DCGC2 0 # Reset the remaining SysCtl registers mww $SYSCTL_PBORCTL 0 mww $SYSCTL_IMC 0 mww $SYSCTL_GPIOHBCTL 0 mww $SYSCTL_MOSCCTL 0 mww $SYSCTL_PIOSCCAL 0 mww $SYSCTL_I2SMCLKCFG 0 # Reset the peripherals mww $SYSCTL_SRCR0 0xffffffff mww $SYSCTL_SRCR1 0xffffffff mww $SYSCTL_SRCR2 0xffffffff mww $SYSCTL_SRCR0 0 mww $SYSCTL_SRCR1 0 mww $SYSCTL_SRCR2 0 # Clear any pending SysCtl interrupts mww $SYSCTL_MISC 0xffffffff # Wait for any pending flash operations to complete while {[expr {[mrw $FLASH_FMC] & 0xffff}] != 0} { sleep 1 } while {[expr {[mrw $FLASH_FMC2] & 0xffff}] != 0} { sleep 1 } # Reset the flash controller registers mww $FLASH_FMA 0 mww $FLASH_FCIM 0 mww $FLASH_FCMISC 0xffffffff mww $FLASH_FWBVAL 0 } $_TARGETNAME configure -event reset-start { adapter speed 500 # # When nRST is asserted on most Stellaris devices, it clears some of # the debug state. The ARMv7M and Cortex-M3 TRMs say that's wrong; # and OpenOCD depends on those TRMs. So we won't use SRST on those # chips. (Only power-on reset should affect debug state, beyond a # few specified bits; not the chip's nRST input, wired to SRST.) # # REVISIT current errata specs don't seem to cover this issue. # Do we have more details than this email? # https://lists.berlios.de/pipermail # /openocd-development/2008-August/003065.html # global _DEVICECLASS if {$_DEVICECLASS != 0xff} { set device_class $_DEVICECLASS } else { set device_class [expr {([mrw 0x400fe000] >> 16) & 0xff}] } if {$device_class == 0 || $device_class == 1 || $device_class == 3 || $device_class == 5 || $device_class == 0xa} { if {![using_hla]} { # Sandstorm, Fury, DustDevil, Blizzard and Snowflake are able to use NVIC SYSRESETREQ cortex_m reset_config sysresetreq } } else { if {![using_hla]} { # Tempest and Firestorm default to using NVIC VECTRESET # peripherals will need resetting manually, see proc reset_peripherals cortex_m reset_config vectreset } # reset peripherals, based on code in # http://www.ti.com/lit/er/spmz573a/spmz573a.pdf reset_peripherals $device_class } } # flash configuration ... autodetects sizes, autoprobed flash bank $_CHIPNAME.flash stellaris 0 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32f0x.cfg ================================================ # script for stm32f0x family # # stm32 devices support SWD transports only. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32f0x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 4kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } # Allow overriding the Flash bank size if { [info exists FLASH_SIZE] } { set _FLASH_SIZE $FLASH_SIZE } else { # autodetect size set _FLASH_SIZE 0 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # See STM Document RM0091 # Section 29.5.3 set _CPUTAPID 0x0bb11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME # adapter speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz adapter speed 1000 adapter srst delay 100 reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } proc stm32f0x_default_reset_start {} { # Reset clock is HSI (8 MHz) adapter speed 1000 } proc stm32f0x_default_examine_end {} { # Enable debug during low power modes (uses more power) mmw 0x40015804 0x00000006 0 ;# DBGMCU_CR |= DBG_STANDBY | DBG_STOP # Stop watchdog counters during halt mmw 0x40015808 0x00001800 0 ;# DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP } proc stm32f0x_default_reset_init {} { # Configure PLL to boost clock to HSI x 6 (48 MHz) mww 0x40021004 0x00100000 ;# RCC_CFGR = PLLMUL[2] mmw 0x40021000 0x01000000 0 ;# RCC_CR[31:16] |= PLLON mww 0x40022000 0x00000011 ;# FLASH_ACR = PRFTBE | LATENCY[0] sleep 10 ;# Wait for PLL to lock mmw 0x40021004 0x00000002 0 ;# RCC_CFGR |= SW[1] # Boost JTAG frequency adapter speed 8000 } # Default hooks $_TARGETNAME configure -event examine-end { stm32f0x_default_examine_end } $_TARGETNAME configure -event reset-start { stm32f0x_default_reset_start } $_TARGETNAME configure -event reset-init { stm32f0x_default_reset_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32f1x.cfg ================================================ # script for stm32f1x family # # stm32 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32f1x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 4kB (as found on some STM32F100s) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } # Allow overriding the Flash bank size if { [info exists FLASH_SIZE] } { set _FLASH_SIZE $FLASH_SIZE } else { # autodetect size set _FLASH_SIZE 0 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0008 Section 26.6.3 set _CPUTAPID 0x3ba00477 } { # this is the SW-DP tap id not the jtag tap id set _CPUTAPID 0x1ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz adapter speed 1000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_WWDG_STOP | DBG_IWDG_STOP | # DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000307 0 } $_TARGETNAME configure -event trace-config { # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32f2x.cfg ================================================ # script for stm32f2x family # # stm32 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32f2x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 64kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x10000 } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz # # Since we may be running of an RC oscilator, we crank down the speed a # bit more to be on the safe side. Perhaps superstition, but if are # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. adapter speed 1000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0033 # Section 32.6.3 - corresponds to Cortex-M3 r2p0 set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32f2x 0x1fff7800 0 0 0 $_TARGETNAME reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0042008 0x00001800 0 } $_TARGETNAME configure -event trace-config { # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32f3x.cfg ================================================ # script for stm32f3x family # # stm32 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32f3x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 16kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz # # Since we may be running of an RC oscilator, we crank down the speed a # bit more to be on the safe side. Perhaps superstition, but if are # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. adapter speed 1000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0316 # Section 29.6.3 - corresponds to Cortex-M4 r0p1 set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f1x 0 0 0 0 $_TARGETNAME reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } proc stm32f3x_default_reset_start {} { # Reset clock is HSI (8 MHz) adapter speed 1000 } proc stm32f3x_default_examine_end {} { # Enable debug during low power modes (uses more power) mmw 0xe0042004 0x00000007 0 ;# DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP # Stop watchdog counters during halt mmw 0xe0042008 0x00001800 0 ;# DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP } proc stm32f3x_default_reset_init {} { # Configure PLL to boost clock to HSI x 8 (64 MHz) mww 0x40021004 0x00380400 ;# RCC_CFGR = PLLMUL[3:1] | PPRE1[2] mmw 0x40021000 0x01000000 0 ;# RCC_CR |= PLLON mww 0x40022000 0x00000012 ;# FLASH_ACR = PRFTBE | LATENCY[1] sleep 10 ;# Wait for PLL to lock mmw 0x40021004 0x00000002 0 ;# RCC_CFGR |= SW[1] # Boost JTAG frequency adapter speed 8000 } # Default hooks $_TARGETNAME configure -event examine-end { stm32f3x_default_examine_end } $_TARGETNAME configure -event reset-start { stm32f3x_default_reset_start } $_TARGETNAME configure -event reset-init { stm32f3x_default_reset_init } $_TARGETNAME configure -event trace-config { # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xe0042004 0x00000020 0 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32f4x.cfg ================================================ # script for stm32f4x family # # stm32f4 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32f4x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 32kB (Available RAM in smallest device STM32F410) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x8000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0090 # Section 38.6.3 - corresponds to Cortex-M4 r0p1 set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32f2x 0x1fff7800 0 0 0 $_TARGETNAME if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] set _QSPINAME $_CHIPNAME.qspi flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 16MHz, so use F_JTAG = 2MHz # # Since we may be running of an RC oscilator, we crank down the speed a # bit more to be on the safe side. Perhaps superstition, but if are # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. adapter speed 2000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event examine-end { # Enable debug during low power modes (uses more power) # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0042008 0x00001800 0 } proc proc_post_enable {_chipname} { targets $_chipname.cpu if { [$_chipname.tpiu cget -protocol] eq "sync" } { switch [$_chipname.tpiu cget -port-width] { 1 { mmw 0xE0042004 0x00000060 0x000000c0 mmw 0x40021020 0x00000000 0x0000ff00 mmw 0x40021000 0x000000a0 0x000000f0 mmw 0x40021008 0x000000f0 0x00000000 } 2 { mmw 0xE0042004 0x000000a0 0x000000c0 mmw 0x40021020 0x00000000 0x000fff00 mmw 0x40021000 0x000002a0 0x000003f0 mmw 0x40021008 0x000003f0 0x00000000 } 4 { mmw 0xE0042004 0x000000e0 0x000000c0 mmw 0x40021020 0x00000000 0x0fffff00 mmw 0x40021000 0x00002aa0 0x00003ff0 mmw 0x40021008 0x00003ff0 0x00000000 } } } else { mmw 0xE0042004 0x00000020 0x000000c0 } } $_CHIPNAME.tpiu configure -event post-enable "proc_post_enable $_CHIPNAME" $_TARGETNAME configure -event reset-init { # Configure PLL to boost clock to HSI x 4 (64 MHz) mww 0x40023804 0x08012008 ;# RCC_PLLCFGR 16 Mhz /8 (M) * 128 (N) /4(P) mww 0x40023C00 0x00000102 ;# FLASH_ACR = PRFTBE | 2(Latency) mmw 0x40023800 0x01000000 0 ;# RCC_CR |= PLLON sleep 10 ;# Wait for PLL to lock mmw 0x40023808 0x00001000 0 ;# RCC_CFGR |= RCC_CFGR_PPRE1_DIV2 mmw 0x40023808 0x00000002 0 ;# RCC_CFGR |= RCC_CFGR_SW_PLL # Boost JTAG frequency adapter speed 8000 } $_TARGETNAME configure -event reset-start { # Reduce speed since CPU speed will slow down to 16MHz with the reset adapter speed 2000 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32f7x.cfg ================================================ # script for stm32f7x family # # stm32f7 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32f7x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 128kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x20000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0385 # Section 40.6.3 - corresponds to Cortex-M7 with FPU r0p0 set _CPUTAPID 0x5ba00477 } { set _CPUTAPID 0x5ba02477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32f2x 0x1ff0f000 0 0 0 $_TARGETNAME # On the STM32F7, the Flash is mapped at address 0x08000000 via the AXI and # also address 0x00200000 via the ITCM. The former mapping is read-write in # hardware, while the latter is read-only. By presenting an alias, we # accomplish two things: # (1) We allow writing at 0x00200000 (because the alias acts identically to the # original bank), which allows code intended to run from that address to # also be linked for loading at that address, simplifying linking. # (2) We allow the proper memory map to be delivered to GDB, which will cause # it to use hardware breakpoints at the 0x00200000 mapping (correctly # identifying it as Flash), which it would otherwise not do. Configuring # the Flash via ITCM alias as virtual flash bank $_CHIPNAME.itcm-flash.alias virtual 0x00200000 0 0 0 $_TARGETNAME $_FLASHNAME if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] set _QSPINAME $_CHIPNAME.qspi flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 } # adapter speed should be <= F_CPU/6. F_CPU after reset is 16MHz, so use F_JTAG = 2MHz adapter speed 2000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } # Use hardware reset. # # This target is compatible with connect_assert_srst, which may be set in a # board file. reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq # Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal # HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 # makes the data access cacheable. This allows reading and writing data in the # CPU cache from the debugger, which is far more useful than going straight to # RAM when operating on typical variables, and is generally no worse when # operating on special memory locations. $_CHIPNAME.dap apcsw 0x08000000 0x08000000 } $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0042008 0x00001800 0 } $_TARGETNAME configure -event trace-config { # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } $_TARGETNAME configure -event reset-init { # If the HSE was previously enabled and the external clock source # disappeared, RCC_CR.HSERDY can get stuck at 1 and the PLL cannot be # properly switched back to HSI. This situation persists even over a system # reset, including a pin reset via SRST. However, activating the clock # security system will detect the problem and clear HSERDY to 0, which in # turn allows the PLL to switch back to HSI properly. Since we just came # out of reset, HSEON should be 0. If HSERDY is 1, then this situation must # have happened; in that case, activate the clock security system to clear # HSERDY. if {[mrw 0x40023800] & 0x00020000} { mmw 0x40023800 0x00090000 0 ;# RCC_CR = CSSON | HSEON sleep 10 ;# Wait for CSS to fire, if it wants to mmw 0x40023800 0 0x00090000 ;# RCC_CR &= ~CSSON & ~HSEON mww 0x4002380C 0x00800000 ;# RCC_CIR = CSSC sleep 1 ;# Wait for CSSF to clear } # If the clock security system fired, it will pend an NMI. A pending NMI # will cause a bad time for any subsequent executing code, such as a # programming algorithm. if {[mrw 0xE000ED04] & 0x80000000} { # ICSR.NMIPENDSET reads as 1. Need to clear it. A pending NMI can’t be # cleared by any normal means (such as ICSR or NVIC). It can only be # cleared by entering the NMI handler or by resetting the processor. echo "[target current]: Clock security system generated NMI. Clearing." # Keep the old DEMCR value. set old [mrw 0xE000EDFC] # Enable vector catch on reset. mww 0xE000EDFC 0x01000001 # Issue local reset via AIRCR. mww 0xE000ED0C 0x05FA0001 # Restore old DEMCR value. mww 0xE000EDFC $old } # Configure PLL to boost clock to HSI x 10 (160 MHz) mww 0x40023804 0x08002808 ;# RCC_PLLCFGR 16 Mhz /10 (M) * 128 (N) /2(P) mww 0x40023C00 0x00000107 ;# FLASH_ACR = PRFTBE | 7(Latency) mmw 0x40023800 0x01000000 0 ;# RCC_CR |= PLLON sleep 10 ;# Wait for PLL to lock mww 0x40023808 0x00009400 ;# RCC_CFGR_PPRE1 = 5(div 4), PPRE2 = 4(div 2) mmw 0x40023808 0x00000002 0 ;# RCC_CFGR |= RCC_CFGR_SW_PLL # Boost SWD frequency # Do not boost JTAG frequency and slow down JTAG memory access or flash write algo # suffers from DAP WAITs if {[using_jtag]} { [[target current] cget -dap] memaccess 16 } { adapter speed 8000 } } $_TARGETNAME configure -event reset-start { # Reduce speed since CPU speed will slow down to 16MHz with the reset adapter speed 2000 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32g0x.cfg ================================================ # script for stm32g0x family # # stm32g0 devices support SWD transports only. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32g0x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # Smallest proposed target has 8kB ram, use 4kB by default to avoid surprises if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # Section 37.5.5 - corresponds to Cortex-M0+ set _CPUTAPID 0x0bc11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME # reasonable default adapter speed 2000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } proc stm32g0x_default_reset_start {} { # Reset clock is HSI16 (16 MHz) adapter speed 2000 } proc stm32g0x_default_examine_end {} { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP mmw 0x40015804 0x00000006 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0x40015808 0x00001800 0 } proc stm32g0x_default_reset_init {} { # Increase clock to 64 Mhz mmw 0x40022000 0x00000002 0x00000005 ;# FLASH_ACR: Latency = 2 mww 0x4002100C 0x30000802 ;# RCC_PLLCFGR = PLLR=/2, PLLN=8, PLLM=/1, PLLSRC=0x2 mmw 0x40021000 0x01000000 0x00000000 ;# RCC_CR |= PLLON mmw 0x40021008 0x00000002 0x00000005 ;# RCC_CFGR: SW=PLLRCLK # Boost JTAG frequency adapter speed 4000 } # Default hooks $_TARGETNAME configure -event examine-end { stm32g0x_default_examine_end } $_TARGETNAME configure -event reset-start { stm32g0x_default_reset_start } $_TARGETNAME configure -event reset-init { stm32g0x_default_reset_init } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32g4x.cfg ================================================ # script for stm32g4x family # # stm32g4 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32g4x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # Smallest current target has 32kB ram, use 16kB by default to avoid surprises if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0440 # Section 46.6.3 - corresponds to Cortex-M4 r0p1 set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] set _QSPINAME $_CHIPNAME.qspi flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 } # reasonable default adapter speed 2000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event reset-init { # CPU comes out of reset with HSION | HSIRDY. # Use HSI 16 MHz clock, compliant even with VOS == 2. # 1 WS compliant with VOS == 2 and 16 MHz. mmw 0x40022000 0x00000001 0x0000000E ;# FLASH_ACR: Latency = 1 mmw 0x40021000 0x00000100 0x00000000 ;# RCC_CR |= HSION mmw 0x40021008 0x00000001 0x00000002 ;# RCC_CFGR: SW=HSI16 } $_TARGETNAME configure -event reset-start { # Reset clock is HSI (16 MHz) adapter speed 2000 } $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZR1 |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0042008 0x00001800 0 } $_TARGETNAME configure -event trace-config { # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32h7x.cfg ================================================ # script for stm32h7x family # # stm32h7 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32h7x } if { [info exists DUAL_BANK] } { set $_CHIPNAME.DUAL_BANK $DUAL_BANK unset DUAL_BANK } else { set $_CHIPNAME.DUAL_BANK 0 } if { [info exists DUAL_CORE] } { set $_CHIPNAME.DUAL_CORE $DUAL_CORE unset DUAL_CORE } else { set $_CHIPNAME.DUAL_CORE 0 } # Issue a warning when hla is used, and fallback to single core configuration if { [set $_CHIPNAME.DUAL_CORE] && [using_hla] } { echo "Warning : hla does not support multicore debugging" set $_CHIPNAME.DUAL_CORE 0 } if { [info exists USE_CTI] } { set $_CHIPNAME.USE_CTI $USE_CTI unset USE_CTI } else { set $_CHIPNAME.USE_CTI 0 } # Issue a warning when DUAL_CORE=0 and USE_CTI=1, and fallback to USE_CTI=0 if { ![set $_CHIPNAME.DUAL_CORE] && [set $_CHIPNAME.USE_CTI] } { echo "Warning : could not use CTI with a single core device, CTI is disabled" set $_CHIPNAME.USE_CTI 0 } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 64kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x10000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x6ba00477 } { set _CPUTAPID 0x6ba02477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } if {![using_hla]} { # STM32H7 provides an APB-AP at access port 2, which allows the access to # the debug and trace features on the system APB System Debug Bus (APB-D). target create $_CHIPNAME.ap2 mem_ap -dap $_CHIPNAME.dap -ap-num 2 swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xE00E3000 tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xE00F5000 } target create $_CHIPNAME.cpu0 cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap -ap-num 0 $_CHIPNAME.cpu0 configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.bank1.cpu0 stm32h7x 0x08000000 0 0 0 $_CHIPNAME.cpu0 if {[set $_CHIPNAME.DUAL_BANK]} { flash bank $_CHIPNAME.bank2.cpu0 stm32h7x 0x08100000 0 0 0 $_CHIPNAME.cpu0 } if {[set $_CHIPNAME.DUAL_CORE]} { target create $_CHIPNAME.cpu1 cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap -ap-num 3 $_CHIPNAME.cpu1 configure -work-area-phys 0x38000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.bank1.cpu1 stm32h7x 0x08000000 0 0 0 $_CHIPNAME.cpu1 if {[set $_CHIPNAME.DUAL_BANK]} { flash bank $_CHIPNAME.bank2.cpu1 stm32h7x 0x08100000 0 0 0 $_CHIPNAME.cpu1 } } # Make sure that cpu0 is selected targets $_CHIPNAME.cpu0 if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] set _QSPINAME $_CHIPNAME.qspi flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_CHIPNAME.cpu0 0x52005000 } else { if { [info exists OCTOSPI1] && $OCTOSPI1 } { set a [llength [flash list]] set _OCTOSPINAME1 $_CHIPNAME.octospi1 flash bank $_OCTOSPINAME1 stmqspi 0x90000000 0 0 0 $_CHIPNAME.cpu0 0x52005000 } if { [info exists OCTOSPI2] && $OCTOSPI2 } { set b [llength [flash list]] set _OCTOSPINAME2 $_CHIPNAME.octospi2 flash bank $_OCTOSPINAME2 stmqspi 0x70000000 0 0 0 $_CHIPNAME.cpu0 0x5200A000 } } # Clock after reset is HSI at 64 MHz, no need of PLL adapter speed 1800 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } # use hardware reset # # The STM32H7 does not support connect_assert_srst mode because the AXI is # unavailable while SRST is asserted, and that is used to access the DBGMCU # component at 0x5C001000 in the examine-end event handler. # # It is possible to access the DBGMCU component at 0xE00E1000 via AP2 instead # of the default AP0, and that works with SRST asserted; however, nonzero AP # usage does not work with HLA, so is not done by default. That change could be # made in a local configuration file if connect_assert_srst mode is needed for # a specific application and a non-HLA adapter is in use. reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset $_CHIPNAME.cpu0 cortex_m reset_config sysresetreq if {[set $_CHIPNAME.DUAL_CORE]} { $_CHIPNAME.cpu1 cortex_m reset_config sysresetreq } # Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal # HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 # makes the data access cacheable. This allows reading and writing data in the # CPU cache from the debugger, which is far more useful than going straight to # RAM when operating on typical variables, and is generally no worse when # operating on special memory locations. $_CHIPNAME.dap apcsw 0x08000000 0x08000000 } $_CHIPNAME.cpu0 configure -event examine-end { # Enable D3 and D1 DBG clocks # DBGMCU_CR |= D3DBGCKEN | D1DBGCKEN stm32h7x_dbgmcu_mmw 0x004 0x00600000 0 # Enable debug during low power modes (uses more power) # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP D1 Domain stm32h7x_dbgmcu_mmw 0x004 0x00000007 0 # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP D2 Domain stm32h7x_dbgmcu_mmw 0x004 0x00000038 0 # Stop watchdog counters during halt # DBGMCU_APB3FZ1 |= WWDG1 stm32h7x_dbgmcu_mmw 0x034 0x00000040 0 # DBGMCU_APB1LFZ1 |= WWDG2 stm32h7x_dbgmcu_mmw 0x03C 0x00000800 0 # DBGMCU_APB4FZ1 |= WDGLSD1 | WDGLSD2 stm32h7x_dbgmcu_mmw 0x054 0x000C0000 0 # Enable clock for tracing # DBGMCU_CR |= TRACECLKEN stm32h7x_dbgmcu_mmw 0x004 0x00100000 0 # RM0399 (id 0x450) M7+M4 with SWO Funnel # RM0433 (id 0x450) M7 with SWO Funnel # RM0455 (id 0x480) M7 without SWO Funnel # RM0468 (id 0x483) M7 without SWO Funnel # Enable CM7 and CM4 slave ports in SWO trace Funnel # Works ok also on devices single core and without SWO funnel # Hack, use stm32h7x_dbgmcu_mmw with big offset to control SWTF # SWTF_CTRL |= ENS0 | ENS1 stm32h7x_dbgmcu_mmw 0x3000 0x00000003 0 } $_CHIPNAME.cpu0 configure -event reset-init { # Clock after reset is HSI at 64 MHz, no need of PLL adapter speed 4000 } # get _CHIPNAME from current target proc stm32h7x_get_chipname {} { set t [target current] set sep [string last "." $t] if {$sep == -1} { return $t } return [string range $t 0 [expr {$sep - 1}]] } if {[set $_CHIPNAME.DUAL_CORE]} { $_CHIPNAME.cpu1 configure -event examine-end { set _CHIPNAME [stm32h7x_get_chipname] global $_CHIPNAME.USE_CTI # Stop watchdog counters during halt # DBGMCU_APB3FZ2 |= WWDG1 stm32h7x_dbgmcu_mmw 0x038 0x00000040 0 # DBGMCU_APB1LFZ2 |= WWDG2 stm32h7x_dbgmcu_mmw 0x040 0x00000800 0 # DBGMCU_APB4FZ2 |= WDGLSD1 | WDGLSD2 stm32h7x_dbgmcu_mmw 0x058 0x000C0000 0 if {[set $_CHIPNAME.USE_CTI]} { stm32h7x_cti_start } } } # like mrw, but with target selection proc stm32h7x_mrw {used_target reg} { return [$used_target read_memory $reg 32 1] } # like mmw, but with target selection proc stm32h7x_mmw {used_target reg setbits clearbits} { set old [stm32h7x_mrw $used_target $reg] set new [expr {($old & ~$clearbits) | $setbits}] $used_target mww $reg $new } # mmw for dbgmcu component registers, it accepts the register offset from dbgmcu base # this procedure will use the mem_ap on AP2 whenever possible proc stm32h7x_dbgmcu_mmw {reg_offset setbits clearbits} { # use $_CHIPNAME.ap2 if possible, and use the proper dbgmcu base address if {![using_hla]} { set _CHIPNAME [stm32h7x_get_chipname] set used_target $_CHIPNAME.ap2 set reg_addr [expr {0xE00E1000 + $reg_offset}] } { set used_target [target current] set reg_addr [expr {0x5C001000 + $reg_offset}] } stm32h7x_mmw $used_target $reg_addr $setbits $clearbits } if {[set $_CHIPNAME.USE_CTI]} { # create CTI instances for both cores cti create $_CHIPNAME.cti0 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0043000 cti create $_CHIPNAME.cti1 -dap $_CHIPNAME.dap -ap-num 3 -baseaddr 0xE0043000 $_CHIPNAME.cpu0 configure -event halted { stm32h7x_cti_prepare_restart_all } $_CHIPNAME.cpu1 configure -event halted { stm32h7x_cti_prepare_restart_all } $_CHIPNAME.cpu0 configure -event debug-halted { stm32h7x_cti_prepare_restart_all } $_CHIPNAME.cpu1 configure -event debug-halted { stm32h7x_cti_prepare_restart_all } proc stm32h7x_cti_start {} { set _CHIPNAME [stm32h7x_get_chipname] # Configure Cores' CTIs to halt each other # TRIGIN0 (DBGTRIGGER) and TRIGOUT0 (EDBGRQ) at CTM_CHANNEL_0 $_CHIPNAME.cti0 write INEN0 0x1 $_CHIPNAME.cti0 write OUTEN0 0x1 $_CHIPNAME.cti1 write INEN0 0x1 $_CHIPNAME.cti1 write OUTEN0 0x1 # enable CTIs $_CHIPNAME.cti0 enable on $_CHIPNAME.cti1 enable on } proc stm32h7x_cti_stop {} { set _CHIPNAME [stm32h7x_get_chipname] $_CHIPNAME.cti0 enable off $_CHIPNAME.cti1 enable off } proc stm32h7x_cti_prepare_restart_all {} { stm32h7x_cti_prepare_restart cti0 stm32h7x_cti_prepare_restart cti1 } proc stm32h7x_cti_prepare_restart {cti} { set _CHIPNAME [stm32h7x_get_chipname] # Acknowlodge EDBGRQ at TRIGOUT0 $_CHIPNAME.$cti write INACK 0x01 $_CHIPNAME.$cti write INACK 0x00 } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32h7x_dual_bank.cfg ================================================ # script for stm32h7x family (dual flash bank) # STM32H7xxxI 2Mo have a dual bank flash. set DUAL_BANK 1 source [find target/stm32h7x.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32l0.cfg ================================================ # # M0+ devices only have SW-DP, but swj-dp code works, just don't # set any jtag related features # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32l0 } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 2kB (max ram on smallest part) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x800 } # JTAG speed should be <= F_CPU/6. # F_CPU after reset is ~2MHz, so use F_JTAG max = 333kHz adapter speed 300 adapter srst delay 100 if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # Arm, m0+, non-multidrop. # http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka16088.html set _CPUTAPID 0x0bc11477 } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32lx 0x08000000 0 0 0 $_TARGETNAME reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } proc stm32l0_enable_HSI16 {} { # Enable HSI16 as clock source echo "STM32L0: Enabling HSI16" # Set HSI16ON in RCC_CR (leave MSI enabled) mmw 0x40021000 0x00000101 0 # Set HSI16 as SYSCLK (RCC_CFGR) mmw 0x4002100c 0x00000001 0 # Wait until System clock switches to HSI16 while { ([ mrw 0x4002100c ] & 0x0c) != 0x04 } { } # Increase speed adapter speed 2500 } $_TARGETNAME configure -event reset-init { stm32l0_enable_HSI16 } $_TARGETNAME configure -event reset-start { adapter speed 300 } $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0x40015804 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0x40015808 0x00001800 0 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32l0_dual_bank.cfg ================================================ source [find target/stm32l0.cfg] # Add the second flash bank. set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME stm32lx 0 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32l1.cfg ================================================ # # stm32l1 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32l1 } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 10kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x2800 } # JTAG speed should be <= F_CPU/6. # F_CPU after reset is 2MHz, so use F_JTAG max = 333kHz adapter speed 300 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0038 # Section 30.6.3 - corresponds to Cortex-M3 r2p0 set _CPUTAPID 0x4ba00477 } else { # SWD IDCODE (single drop, arm) set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32lx 0x08000000 0 0 0 $_TARGETNAME reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } proc stm32l_enable_HSI {} { # Enable HSI as clock source echo "STM32L: Enabling HSI" # Set HSION in RCC_CR mmw 0x40023800 0x00000101 0 # Set HSI as SYSCLK mmw 0x40023808 0x00000001 0 # Increase JTAG speed adapter speed 2000 } $_TARGETNAME configure -event reset-init { stm32l_enable_HSI } $_TARGETNAME configure -event reset-start { adapter speed 300 } $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0042008 0x00001800 0 } $_TARGETNAME configure -event trace-config { # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32l1x_dual_bank.cfg ================================================ source [find target/stm32l1.cfg] # The stm32l1x 384kb have a dual bank flash. # Let's add a definition for the second bank here. # Add the second flash bank. set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME stm32lx 0 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32l4x.cfg ================================================ # script for stm32l4x family # # stm32l4 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32l4x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 40kB (Available RAM in smallest device STM32L412) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0xa000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0351 # Section 44.6.3 - corresponds to Cortex-M4 r0p1 set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32l4x 0x08000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] set _QSPINAME $_CHIPNAME.qspi flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 } else { if { [info exists OCTOSPI1] && $OCTOSPI1 } { set a [llength [flash list]] set _OCTOSPINAME1 $_CHIPNAME.octospi1 flash bank $_OCTOSPINAME1 stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 } if { [info exists OCTOSPI2] && $OCTOSPI2 } { set b [llength [flash list]] set _OCTOSPINAME2 $_CHIPNAME.octospi2 flash bank $_OCTOSPINAME2 stmqspi 0x70000000 0 0 0 $_TARGETNAME 0xA0001400 } } # Common knowledges tells JTAG speed should be <= F_CPU/6. # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on # the safe side. # # Note that there is a pretty wide band where things are # more or less stable, see http://openocd.zylin.com/#/c/3366/ adapter speed 500 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event examine-end { # Enable debug during low power modes (uses more power) # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0042008 0x00001800 0 } proc proc_post_enable {_chipname} { targets $_chipname.cpu if { [$_chipname.tpiu cget -protocol] eq "sync" } { switch [$_chipname.tpiu cget -port-width] { 1 { mmw 0xE0042004 0x00000060 0x000000c0 mmw 0x48001020 0x00000000 0x0000ff00 mmw 0x48001000 0x000000a0 0x000000f0 mmw 0x48001008 0x000000f0 0x00000000 } 2 { mmw 0xE0042004 0x000000a0 0x000000c0 mmw 0x48001020 0x00000000 0x000fff00 mmw 0x48001000 0x000002a0 0x000003f0 mmw 0x48001008 0x000003f0 0x00000000 } 4 { mmw 0xE0042004 0x000000e0 0x000000c0 mmw 0x48001020 0x00000000 0x0fffff00 mmw 0x48001000 0x00002aa0 0x00003ff0 mmw 0x48001008 0x00003ff0 0x00000000 } } } else { mmw 0xE0042004 0x00000020 0x000000c0 } } $_CHIPNAME.tpiu configure -event post-enable "proc_post_enable $_CHIPNAME" $_TARGETNAME configure -event reset-init { # CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 6 (4 MHz). # Use MSI 24 MHz clock, compliant even with VOS == 2. # 3 WS compliant with VOS == 2 and 24 MHz. mww 0x40022000 0x00000103 ;# FLASH_ACR = PRFTBE | 3(Latency) mww 0x40021000 0x00000099 ;# RCC_CR = MSI_ON | MSIRGSEL | MSI Range 9 # Boost JTAG frequency adapter speed 4000 } $_TARGETNAME configure -event reset-start { # Reset clock is MSI (4 MHz) adapter speed 500 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32l5x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32l5x family # stm32l5x devices support both JTAG and SWD transports. source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32l5x } source [find target/stm32x5x_common.cfg] proc stm32l5x_clock_config {} { set offset [expr {[stm32x5x_is_secure] ? 0x10000000 : 0}] # MCU clock is MSI (4MHz) after reset, set MCU freq at 110 MHz with PLL # RCC_APB1ENR1 = PWREN mww [expr {0x40021058 + $offset}] 0x10000000 # delay for register clock enable (read back reg) mrw [expr {0x40021058 + $offset}] # PWR_CR1 : VOS Range 0 mww [expr {0x40007000 + $offset}] 0 # while (PWR_SR2 & VOSF) while {([mrw [expr {0x40007014 + $offset}]] & 0x0400)} {} # FLASH_ACR : 5 WS for 110 MHz HCLK mww 0x40022000 0x00000005 # RCC_PLLCFGR = PLLP=PLLQ=0, PLLR=00=2, PLLREN=1, PLLN=55, PLLM=0000=1, PLLSRC=MSI 4MHz # fVCO = 4 x 55 /1 = 220 # SYSCLOCK = fVCO/PLLR = 220/2 = 110 MHz mww [expr {0x4002100C + $offset}] 0x01003711 # RCC_CR |= PLLON mmw [expr {0x40021000 + $offset}] 0x01000000 0 # while !(RCC_CR & PLLRDY) while {!([mrw [expr {0x40021000 + $offset}]] & 0x02000000)} {} # RCC_CFGR |= SW_PLL mmw [expr {0x40021008 + $offset}] 0x00000003 0 # while ((RCC_CFGR & SWS) != PLL) while {([mrw [expr {0x40021008 + $offset}]] & 0x0C) != 0x0C} {} } $_TARGETNAME configure -event reset-init { stm32l5x_clock_config # Boost JTAG frequency adapter speed 4000 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32mp13x.cfg ================================================ # STMicroelectronics STM32MP13x (Single Cortex-A7) # http://www.st.com/stm32mp1 # HLA does not support custom CSW nor AP other than 0 if { [using_hla] } { echo "ERROR: HLA transport cannot work with this target." echo "ERROR: To use STLink switch to DAP mode, as in \"board/stm32mp13x_dk.cfg\"." shutdown } source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32mp13x } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x6ba00477 } else { set _CPUTAPID 0x6ba02477 } } # Chip Level TAP Controller, only in jtag mode if { [info exists CLCTAPID] } { set _CLCTAPID $CLCTAPID } else { set _CLCTAPID 0x06501041 } swj_newdap $_CHIPNAME tap -expected-id $_CPUTAPID -irlen 4 if { [using_jtag] } { jtag newtap $_CHIPNAME.clc tap -expected-id $_CLCTAPID -irlen 5 } dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -ignore-syspwrupack # NOTE: keep ap-num and dbgbase to speed-up examine after reset # NOTE: do not change the order of target create target create $_CHIPNAME.ap1 mem_ap -dap $_CHIPNAME.dap -ap-num 1 target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 0 target create $_CHIPNAME.cpu cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 -dbgbase 0xE00D0000 $_CHIPNAME.cpu cortex_a maskisr on $_CHIPNAME.cpu cortex_a dacrfixup on # interface does not work while srst is asserted # this is target specific, valid for every board # srst resets the debug unit, behavior equivalent to "srst_pulls_trst" reset_config srst_gates_jtag srst_pulls_trst adapter speed 5000 adapter srst pulse_width 200 # bootrom has an internal timeout of 1 second for detecting the boot flash. # wait at least 1 second to guarantee we are out of bootrom adapter srst delay 1100 add_help_text axi_secure "Set secure mode for following AXI accesses" proc axi_secure {} { $::_CHIPNAME.dap apsel 0 $::_CHIPNAME.dap apcsw 0x10006000 } add_help_text axi_nsecure "Set non-secure mode for following AXI accesses" proc axi_nsecure {} { $::_CHIPNAME.dap apsel 0 $::_CHIPNAME.dap apcsw 0x30006000 } axi_secure proc dbgmcu_enable_debug {} { # keep clock enabled in low-power ## catch {$::_CHIPNAME.ap1 mww 0xe0081004 0x00000004} # freeze watchdog 1 and 2 on core halted catch {$::_CHIPNAME.ap1 mww 0xe008102c 0x00000004} catch {$::_CHIPNAME.ap1 mww 0xe008104c 0x00000008} } proc toggle_cpu_dbg_claim0 {} { # toggle CPU0 DBG_CLAIM[0] $::_CHIPNAME.ap1 mww 0xe00d0fa0 1 $::_CHIPNAME.ap1 mww 0xe00d0fa4 1 } # FIXME: most of handlers below will be removed once reset framework get merged $_CHIPNAME.ap1 configure -event reset-deassert-pre { adapter deassert srst deassert trst catch {dap init} catch {$::_CHIPNAME.dap apid 1} } $_CHIPNAME.cpu configure -event reset-deassert-pre {$::_CHIPNAME.cpu arp_examine} $_CHIPNAME.cpu configure -event reset-deassert-post {toggle_cpu_dbg_claim0; dbgmcu_enable_debug} $_CHIPNAME.ap1 configure -event examine-start {dap init} $_CHIPNAME.ap1 configure -event examine-end {dbgmcu_enable_debug} ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32mp15x.cfg ================================================ # STMicroelectronics STM32MP15x (Single/Dual Cortex-A7 plus Cortex-M4) # http://www.st.com/stm32mp1 # HLA does not support multi-cores nor custom CSW nor AP other than 0 if { [using_hla] } { echo "ERROR: HLA transport cannot work with this target." echo "ERROR: To use STLink switch to DAP mode, as in \"board/stm32mp15x_dk2.cfg\"." shutdown } source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32mp15x } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x6ba00477 } else { set _CPUTAPID 0x6ba02477 } } # Chip Level TAP Controller, only in jtag mode if { [info exists CLCTAPID] } { set _CLCTAPID $CLCTAPID } else { set _CLCTAPID 0x06500041 } swj_newdap $_CHIPNAME tap -expected-id $_CPUTAPID -irlen 4 if { [using_jtag] } { jtag newtap $_CHIPNAME.clc tap -expected-id $_CLCTAPID -irlen 5 } dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -ignore-syspwrupack # FIXME: Cortex-M code requires target accessible during reset, but this is not possible in STM32MP1 # so defer-examine it until the reset framework get merged # NOTE: keep ap-num and dbgbase to speed-up examine after reset # NOTE: do not change the order of target create target create $_CHIPNAME.ap1 mem_ap -dap $_CHIPNAME.dap -ap-num 1 target create $_CHIPNAME.ap2 mem_ap -dap $_CHIPNAME.dap -ap-num 2 target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 0 target create $_CHIPNAME.cpu0 cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 -dbgbase 0xE00D0000 target create $_CHIPNAME.cpu1 cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 1 -dbgbase 0xE00D2000 target create $_CHIPNAME.cm4 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -defer-examine targets $_CHIPNAME.cpu0 target smp $_CHIPNAME.cpu0 $_CHIPNAME.cpu1 $_CHIPNAME.cpu0 cortex_a maskisr on $_CHIPNAME.cpu1 cortex_a maskisr on $_CHIPNAME.cpu0 cortex_a dacrfixup on $_CHIPNAME.cpu1 cortex_a dacrfixup on cti create $_CHIPNAME.cti.sys -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE0094000 cti create $_CHIPNAME.cti.cpu0 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE00D8000 cti create $_CHIPNAME.cti.cpu1 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE00D9000 cti create $_CHIPNAME.cti.cm4 -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xE0043000 swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE0083000 tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE0093000 # interface does not work while srst is asserted # this is target specific, valid for every board # Errata "2.3.5 Incorrect reset of glitch-free kernel clock switch" requires # srst to force VDDCORE power cycle or pull srst_core. Both cases reset the # debug unit, behavior equivalent to "srst_pulls_trst" reset_config srst_gates_jtag srst_pulls_trst adapter speed 5000 adapter srst pulse_width 200 # bootrom has an internal timeout of 1 second for detecting the boot flash. # wait at least 1 second to guarantee we are out of bootrom adapter srst delay 1100 add_help_text axi_secure "Set secure mode for following AXI accesses" proc axi_secure {} { $::_CHIPNAME.dap apsel 0 $::_CHIPNAME.dap apcsw 0x10006000 } add_help_text axi_nsecure "Set non-secure mode for following AXI accesses" proc axi_nsecure {} { $::_CHIPNAME.dap apsel 0 $::_CHIPNAME.dap apcsw 0x30006000 } axi_secure proc dbgmcu_enable_debug {} { # set debug enable bits in DBGMCU_CR to get ap2 and cm4 visible catch {$::_CHIPNAME.ap1 mww 0xe0081004 0x00000007} # freeze watchdog 1 and 2 on cores halted catch {$::_CHIPNAME.ap1 mww 0xe008102c 0x00000004} catch {$::_CHIPNAME.ap1 mww 0xe008104c 0x00000008} } proc toggle_cpu0_dbg_claim0 {} { # toggle CPU0 DBG_CLAIM[0] $::_CHIPNAME.ap1 mww 0xe00d0fa0 1 $::_CHIPNAME.ap1 mww 0xe00d0fa4 1 } proc detect_cpu1 {} { set cpu1_prsr [$::_CHIPNAME.ap1 read_memory 0xE00D2314 32 1] set dual_core [expr {$cpu1_prsr & 1}] if {! $dual_core} {$::_CHIPNAME.cpu1 configure -defer-examine} } proc rcc_enable_traceclk {} { $::_CHIPNAME.ap2 mww 0x5000080c 0x301 } # FIXME: most of handler below will be removed once reset framework get merged $_CHIPNAME.ap1 configure -event reset-deassert-pre {adapter deassert srst deassert trst;catch {dap init};catch {$::_CHIPNAME.dap apid 1}} $_CHIPNAME.ap2 configure -event reset-deassert-pre {dbgmcu_enable_debug;rcc_enable_traceclk} $_CHIPNAME.cpu0 configure -event reset-deassert-pre {$::_CHIPNAME.cpu0 arp_examine} $_CHIPNAME.cpu1 configure -event reset-deassert-pre {$::_CHIPNAME.cpu1 arp_examine allow-defer} $_CHIPNAME.cpu0 configure -event reset-deassert-post {toggle_cpu0_dbg_claim0} $_CHIPNAME.cm4 configure -event reset-deassert-post {$::_CHIPNAME.cm4 arp_examine;if {[$::_CHIPNAME.ap2 curstate] == "halted"} {$::_CHIPNAME.cm4 arp_poll;$::_CHIPNAME.cm4 arp_poll;$::_CHIPNAME.cm4 arp_halt}} $_CHIPNAME.ap1 configure -event examine-start {dap init} $_CHIPNAME.ap2 configure -event examine-start {dbgmcu_enable_debug} $_CHIPNAME.cpu0 configure -event examine-end {detect_cpu1} $_CHIPNAME.ap2 configure -event examine-end {rcc_enable_traceclk;$::_CHIPNAME.cm4 arp_examine} ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32u5x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32u5x family # stm32u5x devices support both JTAG and SWD transports. source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32u5x } source [find target/stm32x5x_common.cfg] proc stm32u5x_clock_config {} { set offset [expr {[stm32x5x_is_secure] ? 0x10000000 : 0}] # MCU clock is at MSI 4MHz after reset, set MCU freq at 160 MHz with PLL # Enable voltage range 1 for frequency above 100 Mhz # RCC_AHB3ENR = PWREN mww [expr {0x46020C94 + $offset}] 0x00000004 # delay for register clock enable (read back reg) mrw [expr {0x46020C94 + $offset}] # PWR_VOSR : VOS Range 1 mmw [expr {0x4602080C + $offset}] 0x00030000 0 # while !(PWR_VOSR & VOSRDY) while {!([mrw [expr {0x4602080C + $offset}]] & 0x00008000)} {} # FLASH_ACR : 4 WS for 160 MHz HCLK mww [expr {0x40022000 + $offset}] 0x00000004 # RCC_PLL1CFGR => PLL1MBOOST=0, PLL1M=0=/1, PLL1FRACEN=0, PLL1SRC=MSI 4MHz # PLL1REN=1, PLL1RGE => VCOInputRange=PLLInputRange_4_8 mww [expr {0x46020C28 + $offset}] 0x00040009 # Enable EPOD Booster mmw [expr {0x4602080C + $offset}] 0x00040000 0 # while !(PWR_VOSR & BOOSTRDY) while {!([mrw [expr {0x4602080C + $offset}]] & 0x00004000)} {} # RCC_PLL1DIVR => PLL1P=PLL1Q=PLL1R=000001=/2, PLL1N=0x4F=80 # fVCO = 4 x 80 /1 = 320 # SYSCLOCK = fVCO/PLL1R = 320/2 = 160 MHz mww [expr {0x46020C34 + $offset}] 0x0101024F # RCC_CR |= PLL1ON mmw [expr {0x46020C00 + $offset}] 0x01000000 0 # while !(RCC_CR & PLL1RDY) while {!([mrw [expr {0x46020C00 + $offset}]] & 0x02000000)} {} # RCC_CFGR1 |= SW_PLL mmw [expr {0x46020C1C + $offset}] 0x00000003 0 # while ((RCC_CFGR1 & SWS) != PLL) while {([mrw [expr {0x46020C1C + $offset}]] & 0x0C) != 0x0C} {} } $_TARGETNAME configure -event reset-init { stm32u5x_clock_config # Boost JTAG frequency adapter speed 4000 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32w108xx.cfg ================================================ # # Target configuration for the ST STM32W108xx chips # # Processor: ARM Cortex-M3 # Date: 2013-06-09 # Author: Giuseppe Barba # # stm32 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] == 0 } { set _CHIPNAME stm32w108 } else { set _CHIPNAME $CHIPNAME } # Work-area is a space in RAM used for flash programming # By default use 8kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x2000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x3ba00477 } { set _CPUTAPID 0x1ba01477 } } set _ENDIAN little swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { if { [info exists BSTAPID] } { set _BSTAPID $BSTAPID jtag newtap $_CHIPNAME bs -irlen 4 -ircapture 0xe -irmask 0xf -expected-id _BSTAPID } else { set _BSTAPID_1 0x169a862b set _BSTAPID_2 0x269a862b jtag newtap $_CHIPNAME bs -irlen 4 -ircapture 0xe -irmask 0xf \ -expected-id $_BSTAPID_1 -expected-id $_BSTAPID_2 } } # # Set Target # set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # Use the flash driver from the EM357 set _FLASHNAME $_CHIPNAME.flash # 64k (0x10000) of flash flash bank $_FLASHNAME em357 0x08000000 0x10000 0 0 $_TARGETNAME reset_config srst_nogate if {![using_hla]} { cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32wbx.cfg ================================================ # script for stm32wbx family # # stm32wb devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32wbx } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 64kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x10000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x6ba00477 } else { # SWD IDCODE (single drop, arm) set _CPUTAPID 0x6ba02477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME # Common knowledges tells JTAG speed should be <= F_CPU/6. # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on # the safe side. # # Note that there is a pretty wide band where things are # more or less stable, see http://openocd.zylin.com/#/c/3366/ adapter speed 500 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event reset-init { # CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 4 MHz. # Configure system to use MSI 24 MHz clock, compliant with VOS default Range1. # 2 WS compliant with VOS=Range1 and 24 MHz. mmw 0x58004000 0x00000102 0 ;# FLASH_ACR |= PRFTBE | 2(Latency) mmw 0x58000000 0x00000091 0 ;# RCC_CR = MSI_ON | MSI Range 24 MHz # Boost JTAG frequency adapter speed 4000 } $_TARGETNAME configure -event reset-start { # Reset clock is MSI (4 MHz) adapter speed 500 } $_TARGETNAME configure -event examine-end { # Enable debug during low power modes (uses more power) # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZR1 |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE004203C 0x00001800 0 } $_TARGETNAME configure -event trace-config { # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32wlx.cfg ================================================ # script for stm32wlx family # # stm32wl devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32wlx } if { [info exists DUAL_CORE] } { set $_CHIPNAME.DUAL_CORE $DUAL_CORE unset DUAL_CORE } else { set $_CHIPNAME.DUAL_CORE 0 } if { [info exists WKUP_CM0P] } { set $_CHIPNAME.WKUP_CM0P $WKUP_CM0P unset WKUP_CM0P } else { set $_CHIPNAME.WKUP_CM0P 0 } # Issue a warning when hla is used, and fallback to single core configuration if { [set $_CHIPNAME.DUAL_CORE] && [using_hla] } { echo "Warning : hla does not support multicore debugging" set $_CHIPNAME.DUAL_CORE 0 set $_CHIPNAME.WKUP_CM0P 0 } # setup the Work-area start address and size # Work-area is a space in RAM used for flash programming # Memory map for known devices: # STM32WL x5JC x5JB x5J8 # FLASH 256 128 64 # SRAM1 32 16 0 # SRAM2 32 32 20 # By default use 8kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x2000 } # Use SRAM2 as work area (some devices do not have SRAM1): set WORKAREASTART_CM4 0x20008000 set WORKAREASTART_CM0P [expr {$WORKAREASTART_CM4 + $_WORKAREASIZE}] #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x6ba00477 } else { # SWD IDCODE (single drop, arm) set _CPUTAPID 0x6ba02477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } target create $_CHIPNAME.cpu0 cortex_m -endian little -dap $_CHIPNAME.dap $_CHIPNAME.cpu0 configure -work-area-phys $WORKAREASTART_CM4 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.flash.cpu0 stm32l4x 0x08000000 0 0 0 $_CHIPNAME.cpu0 flash bank $_CHIPNAME.otp.cpu0 stm32l4x 0x1fff7000 0 0 0 $_CHIPNAME.cpu0 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset $_CHIPNAME.cpu0 cortex_m reset_config sysresetreq } $_CHIPNAME.cpu0 configure -event reset-init { # CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 4 MHz. # Configure system to use MSI 24 MHz clock, compliant with VOS default Range1. # 2 WS compliant with VOS=Range1 and 24 MHz. mmw 0x58004000 0x00000102 0 ;# FLASH_ACR |= PRFTEN | 2(Latency) mmw 0x58000000 0x00000091 0 ;# RCC_CR = MSI_ON | MSI Range 24 MHz # Boost JTAG frequency adapter speed 4000 } $_CHIPNAME.cpu0 configure -event reset-start { # Reset clock is MSI (4 MHz) adapter speed 500 } $_CHIPNAME.cpu0 configure -event examine-end { # Enable debug during low power modes (uses more power) # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZR1 |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE004203C 0x00001800 0 set _CHIPNAME [stm32wlx_get_chipname] global $_CHIPNAME.WKUP_CM0P if {[set $_CHIPNAME.WKUP_CM0P]} { stm32wlx_wkup_cm0p } } $_CHIPNAME.cpu0 configure -event trace-config { # nothing to do } if {[set $_CHIPNAME.DUAL_CORE]} { target create $_CHIPNAME.cpu1 cortex_m -endian little -dap $_CHIPNAME.dap -ap-num 1 $_CHIPNAME.cpu0 configure -work-area-phys $WORKAREASTART_CM0P -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.flash.cpu1 stm32l4x 0x08000000 0 0 0 $_CHIPNAME.cpu1 flash bank $_CHIPNAME.otp.cpu1 stm32l4x 0x1fff7000 0 0 0 $_CHIPNAME.cpu1 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset $_CHIPNAME.cpu1 cortex_m reset_config sysresetreq } proc stm32wlx_wkup_cm0p {} { set _CHIPNAME [stm32wlx_get_chipname] # enable CPU2 boot after reset and after wakeup from Stop or Standby mode # PWR_CR4 |= C2BOOT stm32wlx_mmw $_CHIPNAME.cpu0 0x5800040C 0x00008000 0 } } # get _CHIPNAME from current target proc stm32wlx_get_chipname {} { set t [target current] set sep [string last "." $t] if {$sep == -1} { return $t } return [string range $t 0 [expr {$sep - 1}]] } # like mrw, but with target selection proc stm32wlx_mrw {used_target reg} { return [$used_target read_memory $reg 32 1] } # like mmw, but with target selection proc stm32wlx_mmw {used_target reg setbits clearbits} { set old [stm32wlx_mrw $used_target $reg] set new [expr {($old & ~$clearbits) | $setbits}] $used_target mww $reg $new } # Make sure that cpu0 is selected targets $_CHIPNAME.cpu0 # Common knowledges tells JTAG speed should be <= F_CPU/6. # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on # the safe side. # # Note that there is a pretty wide band where things are # more or less stable, see http://openocd.zylin.com/#/c/3366/ adapter speed 500 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32x5x_common.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # common script for stm32l5x and stm32u5x families # Work-area is a space in RAM used for flash programming # By default use 64kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x10000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # STM32L5x: RM0438 Rev5, Section 52.2.8 JTAG debug port - Table 425. JTAG-DP data registers # STM32U5x: RM0456 Rev1, Section 65.2.8 JTAG debug port - Table 661. JTAG-DP data registers # Corresponds to Cortex®-M33 JTAG debug port ID code set _CPUTAPID 0x0ba04477 } { # SWD IDCODE (single drop, arm) set _CPUTAPID 0x0be12477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap # use non-secure RAM by default $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # create sec/ns flash and otp memories (sizes will be probed) flash bank $_CHIPNAME.flash_ns stm32l4x 0x08000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.flash_alias_s stm32l4x 0x0C000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32l4x 0x0BFA0000 0 0 0 $_TARGETNAME # Common knowledge tells JTAG speed should be <= F_CPU/6. # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on # the safe side. # # Note that there is a pretty wide band where things are # more or less stable, see http://review.openocd.org/3366 adapter speed 500 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } proc stm32x5x_is_secure {} { # read Debug Security Control and Status Register (DSCSR) and check CDS (bit 16) set DSCSR [mrw 0xE000EE08] return [expr {($DSCSR & (1 << 16)) != 0}] } proc stm32x5x_ahb_ap_non_secure_access {} { # SPROT=1=Non Secure access, Priv=1 [[target current] cget -dap] apcsw 0x4B000000 0x4F000000 } proc stm32x5x_ahb_ap_secure_access {} { # SPROT=0=Secure access, Priv=1 [[target current] cget -dap] apcsw 0x0B000000 0x4F000000 } $_TARGETNAME configure -event reset-start { # Reset clock is MSI (4 MHz) adapter speed 480 } $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP mmw 0xE0044004 0x00000006 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0044008 0x00001800 0 } $_TARGETNAME configure -event halted { set secure [stm32x5x_is_secure] if {$secure} { set secure_str "Secure" stm32x5x_ahb_ap_secure_access } else { set secure_str "Non-Secure" stm32x5x_ahb_ap_non_secure_access } # print the secure state only when it changes set _TARGETNAME [target current] global $_TARGETNAME.secure if {![info exists $_TARGETNAME.secure] || $secure != [set $_TARGETNAME.secure]} { echo "CPU in $secure_str state" # update saved security state set $_TARGETNAME.secure $secure } } $_TARGETNAME configure -event gdb-flash-erase-start { set use_secure_workarea 0 # check if FLASH_OPTR.TZEN is enabled set FLASH_OPTR [mrw 0x40022040] if {[expr {$FLASH_OPTR & 0x80000000}] == 0} { echo "TZEN option bit disabled" stm32x5x_ahb_ap_non_secure_access } else { stm32x5x_ahb_ap_secure_access echo "TZEN option bit enabled" # check if FLASH_OPTR.RDP is not Level 0.5 if {[expr {$FLASH_OPTR & 0xFF}] != 0x55} { set use_secure_workarea 1 } } set _TARGETNAME [target current] set workarea_addr [$_TARGETNAME cget -work-area-phys] echo "workarea_addr $workarea_addr" if {$use_secure_workarea} { set workarea_addr [expr {$workarea_addr | 0x10000000}] } else { set workarea_addr [expr {$workarea_addr & ~0x10000000}] } $_TARGETNAME configure -work-area-phys $workarea_addr } $_TARGETNAME configure -event trace-config { # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0044004 0x00000020 0 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm32xl.cfg ================================================ # script for stm32xl family (dual flash bank) source [find target/stm32f1x.cfg] # flash size will be probed set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME stm32f1x 0x08080000 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm8l.cfg ================================================ # script for stm8l family # # stm8 devices support SWIM transports only. # transport select swim if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm8l } # Work-area is a space in RAM used for flash programming # By default use 1kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x400 } if { [info exists FLASHSTART] } { set _FLASHSTART $FLASHSTART } else { set _FLASHSTART 0x8000 } if { [info exists FLASHEND] } { set _FLASHEND $FLASHEND } else { set _FLASHEND 0xffff } if { [info exists EEPROMSTART] } { set _EEPROMSTART $EEPROMSTART } else { set _EEPROMSTART 0x4000 } if { [info exists EEPROMEND] } { set _EEPROMEND $EEPROMEND } else { set _EEPROMEND 0x43ff } if { [info exists OPTIONSTART] } { set _OPTIONSTART $OPTIONSTART } else { set _OPTIONSTART 0x4800 } if { [info exists OPTIONEND] } { set _OPTIONEND $OPTIONEND } else { set _OPTIONEND 0x487f } if { [info exists BLOCKSIZE] } { set _BLOCKSIZE $BLOCKSIZE } else { set _BLOCKSIZE 0x80 } swim newtap $_CHIPNAME cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME stm8 -chain-position $_CHIPNAME.cpu $_TARGETNAME configure -work-area-phys 0x0 -work-area-size $_WORKAREASIZE -work-area-backup 1 $_TARGETNAME configure -flashstart $_FLASHSTART -flashend $_FLASHEND -eepromstart $_EEPROMSTART -eepromend $_EEPROMEND $_TARGETNAME configure -optionstart $_OPTIONSTART -optionend $_OPTIONEND -blocksize $_BLOCKSIZE # Uncomment this line to enable interrupts while instruction step #$_TARGETNAME configure -enable_step_irq # Set stm8l type $_TARGETNAME configure -enable_stm8l # Set high speed adapter speed 800 # Set low speed #adapter speed 363 reset_config srst_only #uncomment this line to connect under reset #reset_config srst_nogate connect_assert_srst ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm8l152.cfg ================================================ #config script for STM8L152 set EEPROMSTART 0x1000 set EEPROMEND 0x13ff proc stm8_reset_rop {} { mwb 0x4800 0xaa mwb 0x4800 0xaa reset halt } source [find target/stm8l.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm8s.cfg ================================================ # script for stm8s family # # stm8 devices support SWIM transports only. # transport select swim if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm8s } # Work-area is a space in RAM used for flash programming # By default use 1kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x400 } if { [info exists FLASHSTART] } { set _FLASHSTART $FLASHSTART } else { set _FLASHSTART 0x8000 } if { [info exists FLASHEND] } { set _FLASHEND $FLASHEND } else { set _FLASHEND 0xffff } if { [info exists EEPROMSTART] } { set _EEPROMSTART $EEPROMSTART } else { set _EEPROMSTART 0x4000 } if { [info exists EEPROMEND] } { set _EEPROMEND $EEPROMEND } else { set _EEPROMEND 0x43ff } if { [info exists OPTIONSTART] } { set _OPTIONSTART $OPTIONSTART } else { set _OPTIONSTART 0x4800 } if { [info exists OPTIONEND] } { set _OPTIONEND $OPTIONEND } else { set _OPTIONEND 0x487f } if { [info exists BLOCKSIZE] } { set _BLOCKSIZE $BLOCKSIZE } else { set _BLOCKSIZE 0x80 } swim newtap $_CHIPNAME cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME stm8 -chain-position $_CHIPNAME.cpu $_TARGETNAME configure -work-area-phys 0x0 -work-area-size $_WORKAREASIZE -work-area-backup 1 $_TARGETNAME configure -flashstart $_FLASHSTART -flashend $_FLASHEND -eepromstart $_EEPROMSTART -eepromend $_EEPROMEND $_TARGETNAME configure -optionstart $_OPTIONSTART -optionend $_OPTIONEND -blocksize $_BLOCKSIZE # Uncomment this line to enable interrupts while instruction step #$_TARGETNAME configure -enable_step_irq # Set high speed adapter speed 800 # Set low speed #adapter speed 363 reset_config srst_only # uncomment this line to connect under reset #reset_config srst_nogate connect_assert_srst ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm8s003.cfg ================================================ #config script for STM8S003 set FLASHEND 0x9FFF set BLOCKSIZE 0x40 proc stm8_reset_rop {} { mwb 0x4800 0x00 reset halt } source [find target/stm8s.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm8s103.cfg ================================================ #config script for STM8S103 set FLASHEND 0x9FFF set EEPROMEND 0x427F set OPTIONEND 0x480A set BLOCKSIZE 0x40 proc stm8_reset_rop {} { mwb 0x4800 0x00 reset halt } source [find target/stm8s.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/stm8s105.cfg ================================================ #config script for STM8S105 proc stm8_reset_rop {} { mwb 0x4800 0x00 reset halt } source [find target/stm8s.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/str710.cfg ================================================ #start slow, speed up after reset adapter speed 10 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME str710 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-start { adapter speed 10 } $_TARGETNAME configure -event reset-init { adapter speed 6000 # Because the hardware cannot be interrogated for the protection state # of sectors, initialize all the sectors to be unprotected. The initial # state is reflected by the driver, too. flash protect 0 0 last off flash protect 1 0 last off } $_TARGETNAME configure -event gdb-flash-erase-start { flash protect 0 0 7 off flash protect 1 0 1 off } $_TARGETNAME configure -work-area-phys 0x2000C000 -work-area-size 0x4000 -work-area-backup 0 #flash bank str7x 0 0 set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME str7x 0x40000000 0x00040000 0 0 $_TARGETNAME STR71x set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME str7x 0x400C0000 0x00004000 0 0 $_TARGETNAME STR71x ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/str730.cfg ================================================ #STR730 CPU adapter speed 3000 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME str730 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id $_CPUTAPID #jtag nTRST and nSRST delay adapter srst delay 500 jtag_ntrst_delay 500 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian little -chain-position 0 $_TARGETNAME configure -event reset-start { adapter speed 10 } $_TARGETNAME configure -event reset-init { adapter speed 3000 # Because the hardware cannot be interrogated for the protection state # of sectors, initialize all the sectors to be unprotected. The initial # state is reflected by the driver, too. flash protect 0 0 last off } $_TARGETNAME configure -event gdb-flash-erase-start { flash protect 0 0 7 off } $_TARGETNAME configure -work-area-phys 0xA0000000 -work-area-size 0x4000 -work-area-backup 0 #flash bank set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME str7x 0x80000000 0x00040000 0 0 $_TARGETNAME STR73x ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/str750.cfg ================================================ #STR750 CPU if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME str750 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4f1f0041 } # jtag speed adapter speed 10 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id $_CPUTAPID #jtag nTRST and nSRST delay adapter srst delay 500 jtag_ntrst_delay 500 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian little -chain-position 0 $_TARGETNAME configure -event reset-start { adapter speed 10 } $_TARGETNAME configure -event reset-init { adapter speed 3000 init_smi # Because the hardware cannot be interrogated for the protection state # of sectors, initialize all the sectors to be unprotected. The initial # state is reflected by the driver, too. flash protect 0 0 last off flash protect 1 0 last off } $_TARGETNAME configure -event gdb-flash-erase-start { flash protect 0 0 7 off flash protect 1 0 1 off } $_TARGETNAME configure -work-area-phys 0x40000000 -work-area-size 0x4000 -work-area-backup 0 #flash bank set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME str7x 0x20000000 0x00040000 0 0 $_TARGETNAME STR75x set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME str7x 0x200C0000 0x00004000 0 0 $_TARGETNAME STR75x # Serial NOR on SMI CS0. set _FLASHNAME $_CHIPNAME.snor flash bank $_FLASHNAME stmsmi 0x80000000 0 0 0 $_TARGETNAME source [find mem_helper.tcl] proc init_smi {} { mmw 0x60000030 0x01000000 0x00000000; # enable clock for GPIO regs mmw 0xffffe420 0x00000001 0x00000000; # set SMI_EN bit mmw 0x90000000 0x00000001 0x00000000; # set BLOCK_EN_1 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/str912.cfg ================================================ # script for str9 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME str912 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # jtag speed. We need to stick to 16kHz until we've finished reset. adapter speed 16 adapter srst delay 100 jtag_ntrst_delay 100 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst if { [info exists FLASHTAPID] } { set _FLASHTAPID $FLASHTAPID } else { set _FLASHTAPID 0x04570041 } jtag newtap $_CHIPNAME flash -irlen 8 -ircapture 0x1 -irmask 0x1 -expected-id $_FLASHTAPID if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x25966041 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID if { [info exists BSTAPID] } { set _BSTAPID $BSTAPID } else { # possible values: 0x1457f041, 0x2457f041 # we ignore version in check below set _BSTAPID 0x1457f041 } jtag newtap $_CHIPNAME bs -irlen 5 -ircapture 0x1 -irmask 0x1 -expected-id $_BSTAPID -ignore-version set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-start { adapter speed 16 } $_TARGETNAME configure -event reset-init { # We can increase speed now that we know the target is halted. #adapter speed 3000 # -- Enable 96K RAM # PFQBC enabled / DTCM & AHB wait-states disabled mww 0x5C002034 0x0191 str9x flash_config 0 4 2 0 0x80000 flash protect 0 0 7 off } $_TARGETNAME configure -work-area-phys 0x50000000 -work-area-size 16384 -work-area-backup 0 #flash bank str9x 0 0 set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME str9x 0x00000000 0x00080000 0 0 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME str9x 0x00080000 0x00008000 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/swj-dp.tcl ================================================ # ARM Debug Interface V5 (ADI_V5) utility # ... Mostly for SWJ-DP (not SW-DP or JTAG-DP, since # SW-DP and JTAG-DP targets don't need to switch based # on which transport is active. # # declare a JTAG or SWD Debug Access Point (DAP) # based on the transport in use with this session. # You can't access JTAG ops when SWD is active, etc. # params are currently what "jtag newtap" uses # because OpenOCD internals are still strongly biased # to JTAG .... but for SWD, "irlen" etc are ignored, # and the internals work differently # for now, ignore non-JTAG and non-SWD transports # (e.g. initial flash programming via SPI or UART) # split out "chip" and "tag" so we can someday handle # them more uniformly irlen too...) if [catch {transport select}] { echo "Error: unable to select a session transport. Can't continue." shutdown } proc swj_newdap {chip tag args} { if [using_jtag] { eval jtag newtap $chip $tag $args } elseif [using_swd] { eval swd newdap $chip $tag $args } else { echo "Error: transport '[ transport select ]' not supported by swj_newdap" shutdown } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/swm050.cfg ================================================ # Synwit SWM050 source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME swm050 } set _CHIPSERIES swm050 if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x400 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0bb11477 } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME swm050 0x0 0x2000 0 0 $_TARGETNAME adapter speed 1000 $_TARGETNAME configure -event reset-init { # Stop the watchdog, just to be safe mww 0x40019000 0x00 # Set clock divider value to 1 mww 0x400F0000 0x01 # Set system clock to 18Mhz mww 0x400F0008 0x00 } # SWM050 (Cortex-M0 core) supports SYSRESETREQ if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/test_reset_syntax_error.cfg ================================================ # Test script to check that syntax error in reset # script is reported properly. # at91eb40a target #jtag scan chain set _CHIPNAME syntaxtest jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf #target configuration set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-init { syntax error } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/test_syntax_error.cfg ================================================ # This script tests a syntax error in the startup # config script syntax error here ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti-ar7.cfg ================================================ # # Texas Instruments AR7 SOC - used in many adsl modems. # http://www.linux-mips.org/wiki/AR7 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ti-ar7 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0000100f } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian $_ENDIAN -chain-position $_CHIPNAME.cpu # use onboard 4k sram as working area $_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 0x00001000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti-cjtag.cfg ================================================ # A start sequence to change from cJTAG to 4-pin JTAG # This is needed for CC2538 and CC26xx to be able to communicate through JTAG # Read section 6.3 in http://www.ti.com/lit/pdf/swru319 for more information. proc ti_cjtag_to_4pin_jtag {jrc} { # Bypass irscan $jrc 0x3f -endstate RUN/IDLE # Two zero bit scans and a one bit drshift pathmove RUN/IDLE DRSELECT DRCAPTURE DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRUPDATE RUN/IDLE pathmove RUN/IDLE DRSELECT DRCAPTURE DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRUPDATE RUN/IDLE pathmove RUN/IDLE DRSELECT DRCAPTURE DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRSHIFT DREXIT1 DRUPDATE RUN/IDLE pathmove RUN/IDLE DRSELECT DRCAPTURE DREXIT1 DRPAUSE # A two bit drhift and a 9 bit drshift pathmove DRPAUSE DREXIT2 DRSHIFT DRSHIFT DREXIT1 DRUPDATE RUN/IDLE pathmove RUN/IDLE DRSELECT DRCAPTURE DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRSHIFT DRSHIFT DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRSHIFT DRSHIFT DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRSHIFT DRSHIFT DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRSHIFT DRSHIFT DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRSHIFT DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRUPDATE RUN/IDLE pathmove RUN/IDLE DRSELECT DRCAPTURE DREXIT1 DRPAUSE # Bypass irscan $jrc 0x3f -endstate RUN/IDLE # Set ICEPick IDCODE in data register irscan $jrc 0x04 -endstate RUN/IDLE } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_calypso.cfg ================================================ # # TI Calypso (lite) G2 C035 Digital Base Band chip # # ARM7TDMIE + DSP subchip (S28C128) # # 512K SRAM Calypso # 256K SRAM Calypso lite # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME calypso } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3100e02f } # Work-area is a space in RAM used for flash programming # By default use 64kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x10000 } adapter speed 1000 reset_config trst_and_srst jtag newtap $_CHIPNAME dsp -expected-id 0x00000000 -irlen 8 jtag newtap $_CHIPNAME arm -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # target set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm7tdmi -endian little -chain-position $_TARGETNAME # workarea $_TARGETNAME configure -work-area-phys 0x00800000 -work-area-size $_WORKAREASIZE -work-area-backup 1 arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable $_TARGETNAME configure -event examine-start { irscan calypso.arm 0x0b -endstate DRPAUSE drscan calypso.arm 2 2 -endstate RUN/IDLE } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_cc13x0.cfg ================================================ # # Texas Instruments CC13x0 - ARM Cortex-M3 # # http://www.ti.com # set CHIPNAME cc13x0 set JRC_TAPID 0x0B9BE02F set WORKAREASIZE 0x4000 source [find target/ti_cc26x0.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_cc13x2.cfg ================================================ # # Texas Instruments CC13x2 - ARM Cortex-M4 # # http://www.ti.com # set CHIPNAME cc13x2 set JRC_TAPID 0x0BB4102F set WORKAREASIZE 0x7000 source [find target/ti_cc26x0.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_cc26x0.cfg ================================================ # # Texas Instruments CC26x0 - ARM Cortex-M3 # # http://www.ti.com # source [find target/icepick.cfg] source [find target/ti-cjtag.cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cc26x0 } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4BA00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" # # ICEpick-C (JTAG route controller) # if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0B99A02F } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu" # A start sequence is needed to change from 2-pin cJTAG to 4-pin JTAG jtag configure $_CHIPNAME.jrc -event post-reset "ti_cjtag_to_4pin_jtag $_CHIPNAME.jrc" set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cc26xx 0 0 0 0 $_TARGETNAME cortex_m reset_config vectreset ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_cc26x2.cfg ================================================ # # Texas Instruments CC26x2 - ARM Cortex-M4 # # http://www.ti.com # set CHIPNAME cc26x2 set JRC_TAPID 0x0BB4102F set WORKAREASIZE 0x7000 source [find target/ti_cc26x0.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_cc3220sf.cfg ================================================ # # Texas Instruments CC3220SF - ARM Cortex-M4 # # http://www.ti.com/CC3220SF # source [find target/swj-dp.tcl] source [find target/icepick.cfg] source [find target/ti_cc32xx.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cc3220sf 0 0 0 0 $_TARGETNAME # # On CC32xx family of devices, sysreqreset is disabled, and vectreset is # blocked by the boot loader (stops in a while(1) statement). srst reset can # leave the target in a state that prevents debug. The following uses the # soft_reset_halt command to reset and halt the target. Then the PC and stack # are initialized from internal flash. This allows for a more reliable reset, # but with two caveats: it only works for the SF variant that has internal # flash, and it only resets the CPU and not any peripherals. # proc ocd_process_reset_inner { MODE } { soft_reset_halt # Initialize MSP, PSP, and PC from vector table at flash 0x01000800 set boot [read_memory 0x01000800 32 2] reg msp [lindex $boot 0] reg psp [lindex $boot 0] reg pc [lindex $boot 1] if { 0 == [string compare $MODE run ] } { resume } cc32xx.cpu invoke-event reset-end } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_cc32xx.cfg ================================================ # # Texas Instruments CC32xx - ARM Cortex-M4 # # http://www.ti.com/product/CC3200 # http://www.ti.com/product/CC3220 # source [find target/swj-dp.tcl] source [find target/icepick.cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cc32xx } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { if {[using_jtag]} { set _DAP_TAPID 0x4BA00477 } else { set _DAP_TAPID 0x2BA01477 } } if {[using_jtag]} { jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" } else { swj_newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID } # # ICEpick-C (JTAG route controller) # if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0B97C02F } if {[using_jtag]} { jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu" } set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x2000 } $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_dm355.cfg ================================================ # # Texas Instruments DaVinci family: TMS320DM355 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dm355 } # TI boards default to EMU0/EMU1 *high* -- ARM and ETB are *disabled* # after JTAG reset until ICEpick is used to route them in. set EMU01 "-disable" # With EMU0/EMU1 jumpered *low* ARM and ETB are *enabled* without # needing any ICEpick interaction. #set EMU01 "-enable" source [find target/icepick.cfg] # # Also note: when running without RTCK before the PLLs are set up, you # may need to slow the JTAG clock down quite a lot (under 2 MHz). # # Subsidiary TAP: ARM ETB11, with scan chain for 4K of ETM trace buffer if { [info exists ETB_TAPID] } { set _ETB_TAPID $ETB_TAPID } else { set _ETB_TAPID 0x2b900f0f } jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0xf -expected-id $_ETB_TAPID $EMU01 jtag configure $_CHIPNAME.etb -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 1" # Subsidiary TAP: ARM926ejs with scan chains for ARM Debug, EmbeddedICE-RT, ETM. if { [info exists CPU_TAPID] } { set _CPU_TAPID $CPU_TAPID } else { set _CPU_TAPID 0x07926001 } jtag newtap $_CHIPNAME arm -irlen 4 -irmask 0xf -expected-id $_CPU_TAPID $EMU01 jtag configure $_CHIPNAME.arm -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 0" # Primary TAP: ICEpick (JTAG route controller) and boundary scan if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0b73b02f } jtag newtap $_CHIPNAME jrc -irlen 6 -irmask 0x3f -expected-id $_JRC_TAPID jtag configure $_CHIPNAME.jrc -event setup \ "jtag tapenable $_CHIPNAME.etb; jtag tapenable $_CHIPNAME.arm" ################ # various symbol definitions, to avoid hard-wiring addresses # and enable some sharing of DaVinci-family utility code global dm355 set dm355 [ dict create ] # Physical addresses for controllers and memory # (Some of these are valid for many DaVinci family chips) dict set dm355 sram0 0x00010000 dict set dm355 sram1 0x00014000 dict set dm355 sysbase 0x01c40000 dict set dm355 pllc1 0x01c40800 dict set dm355 pllc2 0x01c40c00 dict set dm355 psc 0x01c41000 dict set dm355 gpio 0x01c67000 dict set dm355 a_emif 0x01e10000 dict set dm355 a_emif_cs0 0x02000000 dict set dm355 a_emif_cs1 0x04000000 dict set dm355 ddr_emif 0x20000000 dict set dm355 ddr 0x80000000 dict set dm355 uart0 0x01c20000 dict set dm355 uart1 0x01c20400 dict set dm355 uart2 0x01e06000 source [find target/davinci.cfg] ################ # GDB target: the ARM, using SRAM1 for scratch. SRAM0 (also 16K) # and the ETB memory (4K) are other options, while trace is unused. set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm926ejs -chain-position $_TARGETNAME # NOTE that work-area-virt presumes a Linux 2.6.30-rc2+ kernel, # and that the work area is used only with a kernel mmu context ... $_TARGETNAME configure \ -work-area-virt [expr {0xfffe0000 + 0x4000}] \ -work-area-phys [dict get $dm355 sram1] \ -work-area-size 0x4000 \ -work-area-backup 0 # be absolutely certain the JTAG clock will work with the worst-case # CLKIN = 24 MHz (best case: 36 MHz) even when no bootloader turns # on the PLL and starts using it. OK to speed up after clock setup. adapter speed 1500 $_TARGETNAME configure -event "reset-start" { adapter speed 1500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable # trace setup etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_dm365.cfg ================================================ # # Texas Instruments DaVinci family: TMS320DM365 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dm365 } # TI boards default to EMU0/EMU1 *high* -- ARM and ETB are *disabled* # after JTAG reset until ICEpick is used to route them in. set EMU01 "-disable" # With EMU0/EMU1 jumpered *low* ARM and ETB are *enabled* without # needing any ICEpick interaction. #set EMU01 "-enable" source [find target/icepick.cfg] # Subsidiary TAP: ARM ETB11, with scan chain for 4K of ETM trace buffer if { [info exists ETB_TAPID] } { set _ETB_TAPID $ETB_TAPID } else { set _ETB_TAPID 0x2b900f0f } jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0xf -expected-id $_ETB_TAPID $EMU01 jtag configure $_CHIPNAME.etb -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 1" # Subsidiary TAP: ARM926ejs with scan chains for ARM Debug, EmbeddedICE-RT, ETM. if { [info exists CPU_TAPID] } { set _CPU_TAPID $CPU_TAPID } else { set _CPU_TAPID 0x0792602f } jtag newtap $_CHIPNAME arm -irlen 4 -irmask 0xf -expected-id $_CPU_TAPID $EMU01 jtag configure $_CHIPNAME.arm -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 0" # Primary TAP: ICEpick (JTAG route controller) and boundary scan if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0b83e02f } jtag newtap $_CHIPNAME jrc -irlen 6 -irmask 0x3f -expected-id $_JRC_TAPID jtag configure $_CHIPNAME.jrc -event setup \ "jtag tapenable $_CHIPNAME.etb; jtag tapenable $_CHIPNAME.arm" ################ # various symbol definitions, to avoid hard-wiring addresses # and enable some sharing of DaVinci-family utility code global dm365 set dm365 [ dict create ] # Physical addresses for controllers and memory # (Some of these are valid for many DaVinci family chips) dict set dm365 sram0 0x00010000 dict set dm365 sram1 0x00014000 dict set dm365 sysbase 0x01c40000 dict set dm365 pllc1 0x01c40800 dict set dm365 pllc2 0x01c40c00 dict set dm365 psc 0x01c41000 dict set dm365 gpio 0x01c67000 dict set dm365 a_emif 0x01d10000 dict set dm365 a_emif_cs0 0x02000000 dict set dm365 a_emif_cs1 0x04000000 dict set dm365 ddr_emif 0x20000000 dict set dm365 ddr 0x80000000 source [find target/davinci.cfg] ################ # GDB target: the ARM, using SRAM1 for scratch. SRAM0 (also 16K) # and the ETB memory (4K) are other options, while trace is unused. set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm926ejs -chain-position $_TARGETNAME # NOTE that work-area-virt presumes a Linux 2.6.30-rc2+ kernel, # and that the work area is used only with a kernel mmu context ... $_TARGETNAME configure \ -work-area-virt [expr {0xfffe0000 + 0x4000}] \ -work-area-phys [dict get $dm365 sram1] \ -work-area-size 0x4000 \ -work-area-backup 0 # be absolutely certain the JTAG clock will work with the worst-case # CLKIN = 19.2 MHz (best case: 36 MHz) even when no bootloader turns # on the PLL and starts using it. OK to speed up after clock setup. adapter speed 1500 $_TARGETNAME configure -event "reset-start" { adapter speed 1500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable # trace setup etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_dm6446.cfg ================================================ # # Texas Instruments DaVinci family: TMS320DM6446 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dm6446 } # TI boards default to EMU0/EMU1 *high* -- ARM and ETB are *disabled* # after JTAG reset until ICEpick is used to route them in. set EMU01 "-disable" # With EMU0/EMU1 jumpered *low* ARM and ETB are *enabled* without # needing any ICEpick interaction. #set EMU01 "-enable" source [find target/icepick.cfg] # Subsidiary TAP: unknown ... must enable via ICEpick jtag newtap $_CHIPNAME unknown -irlen 8 -disable jtag configure $_CHIPNAME.unknown -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 3" # Subsidiary TAP: C64x+ DSP ... must enable via ICEpick jtag newtap $_CHIPNAME dsp -irlen 38 -ircapture 0x25 -irmask 0x3f -disable jtag configure $_CHIPNAME.dsp -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 2" # Subsidiary TAP: ARM ETB11, with scan chain for 4K of ETM trace buffer if { [info exists ETB_TAPID] } { set _ETB_TAPID $ETB_TAPID } else { set _ETB_TAPID 0x2b900f0f } jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0xf -expected-id $_ETB_TAPID $EMU01 jtag configure $_CHIPNAME.etb -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 1" # Subsidiary TAP: ARM926ejs with scan chains for ARM Debug, EmbeddedICE-RT, ETM. if { [info exists CPU_TAPID] } { set _CPU_TAPID $CPU_TAPID } else { set _CPU_TAPID 0x07926001 } jtag newtap $_CHIPNAME arm -irlen 4 -irmask 0xf -expected-id $_CPU_TAPID $EMU01 jtag configure $_CHIPNAME.arm -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 0" # Primary TAP: ICEpick-C (JTAG route controller) and boundary scan if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0b70002f } jtag newtap $_CHIPNAME jrc -irlen 6 -irmask 0x3f -expected-id $_JRC_TAPID jtag configure $_CHIPNAME.jrc -event setup \ "jtag tapenable $_CHIPNAME.etb; jtag tapenable $_CHIPNAME.arm" ################ # GDB target: the ARM, using SRAM1 for scratch. SRAM0 (also 8K) # and the ETB memory (4K) are other options, while trace is unused. # Little-endian; use the OpenOCD default. set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm926ejs -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x0000a000 -work-area-size 0x2000 # be absolutely certain the JTAG clock will work with the worst-case # CLKIN = 20 MHz (best case: 30 MHz) even when no bootloader turns # on the PLL and starts using it. OK to speed up after clock setup. adapter speed 1500 $_TARGETNAME configure -event "reset-start" { adapter speed 1500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable # trace setup etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_k3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments K3 devices: # * AM654x: https://www.ti.com/lit/pdf/spruid7 # Has 4 ARMV8 Cores and 2 R5 Cores and an M3 # * J721E: https://www.ti.com/lit/pdf/spruil1 # Has 2 ARMV8 Cores and 6 R5 Cores and an M3 # * J7200: https://www.ti.com/lit/pdf/spruiu1 # Has 2 ARMV8 Cores and 4 R5 Cores and an M3 # * AM642: https://www.ti.com/lit/pdf/spruim2 # Has 2 ARMV8 Cores and 4 R5 Cores, M4F and an M3 # if { [info exists SOC] } { set _soc $SOC } else { set _soc am654 } # set V8_SMP_DEBUG to non 0 value in board if you'd like to use SMP debug if { [info exists V8_SMP_DEBUG] } { set _v8_smp_debug $V8_SMP_DEBUG } else { set _v8_smp_debug 0 } # Common Definitions # System Controller is the very first processor - all current SoCs have it. set CM3_CTIBASE {0x3C016000} # sysctrl power-ap unlock offsets set _sysctrl_ap_unlock_offsets {0xf0 0x44} # All the ARMV8s are the next processors. # CL0,CORE0 CL0,CORE1 CL1,CORE0 CL1,CORE1 set ARMV8_DBGBASE {0x90410000 0x90510000 0x90810000 0x90910000} set ARMV8_CTIBASE {0x90420000 0x90520000 0x90820000 0x90920000} # And we add up the R5s # (0)MCU 0 (1)MCU 1 (2)MAIN_0_0 (3)MAIN_0_1 (4)MAIN_1_0 (5)MAIN_1_1 set R5_DBGBASE {0x9d010000 0x9d012000 0x9d410000 0x9d412000 0x9d510000 0x9d512000} set R5_CTIBASE {0x9d018000 0x9d019000 0x9d418000 0x9d419000 0x9d518000 0x9d519000} set R5_NAMES {mcu_r5.0 mcu_r5.1 main0_r5.0 main0_r5.1 main1_r5.0 main1_r5.1} # Finally an General Purpose(GP) MCU set CM4_CTIBASE {0x20001000} # General Purpose MCU (M4) may be present on some very few SoCs set _gp_mcu_cores 0 # General Purpose MCU power-ap unlock offsets set _gp_mcu_ap_unlock_offsets {0xf0 0x60} # Set configuration overrides for each SOC switch $_soc { am654 { set _CHIPNAME am654 set _K3_DAP_TAPID 0x0bb5a02f # AM654 has 2 clusters of 2 A53 cores each. set _armv8_cpu_name a53 set _armv8_cores 4 # AM654 has 1 cluster of 2 R5s cores. set _r5_cores 2 set R5_NAMES {mcu_r5.0 mcu_r5.1} # Sysctrl power-ap unlock offsets set _sysctrl_ap_unlock_offsets {0xf0 0x50} } am642 { set _CHIPNAME am642 set _K3_DAP_TAPID 0x0bb3802f # AM642 has 1 clusters of 2 A53 cores each. set _armv8_cpu_name a53 set _armv8_cores 2 set ARMV8_DBGBASE {0x90010000 0x90110000} set ARMV8_CTIBASE {0x90020000 0x90120000} # AM642 has 2 cluster of 2 R5s cores. set _r5_cores 4 set R5_NAMES {main0_r5.0 main0_r5.1 main1_r5.0 main1_r5.1} set R5_DBGBASE {0x9d410000 0x9d412000 0x9d510000 0x9d512000} set R5_CTIBASE {0x9d418000 0x9d419000 0x9d518000 0x9d519000} # M4 processor set _gp_mcu_cores 1 } am625 { set _CHIPNAME am625 set _K3_DAP_TAPID 0x0bb7e02f # AM625 has 1 clusters of 4 A53 cores. set _armv8_cpu_name a53 set _armv8_cores 4 set ARMV8_DBGBASE {0x90010000 0x90110000 0x90210000 0x90310000} set ARMV8_CTIBASE {0x90020000 0x90120000 0x90220000 0x90320000} # AM625 has 1 cluster of 1 R5s core. set _r5_cores 1 set R5_NAMES {main0_r5.0} set R5_DBGBASE {0x9d410000} set R5_CTIBASE {0x9d418000} # sysctrl CTI base set CM3_CTIBASE {0x20001000} # Sysctrl power-ap unlock offsets set _sysctrl_ap_unlock_offsets {0xf0 0x78} # M4 processor set _gp_mcu_cores 1 set _gp_mcu_ap_unlock_offsets {0xf0 0x7c} } j721e { set _CHIPNAME j721e set _K3_DAP_TAPID 0x0bb6402f # J721E has 1 cluster of 2 A72 cores. set _armv8_cpu_name a72 set _armv8_cores 2 # J721E has 3 clusters of 2 R5 cores each. set _r5_cores 6 } j7200 { set _CHIPNAME j7200 set _K3_DAP_TAPID 0x0bb6d02f # J7200 has 1 cluster of 2 A72 cores. set _armv8_cpu_name a72 set _armv8_cores 2 # J7200 has 2 clusters of 2 R5 cores each. set _r5_cores 4 set R5_DBGBASE {0x9d010000 0x9d012000 0x9d110000 0x9d112000} set R5_CTIBASE {0x9d018000 0x9d019000 0x9d118000 0x9d119000} # M3 CTI base set CM3_CTIBASE {0x20001000} } j721s2 { set _CHIPNAME j721s2 set _K3_DAP_TAPID 0x0bb7502f # J721s2 has 1 cluster of 2 A72 cores. set _armv8_cpu_name a72 set _armv8_cores 2 # J721s2 has 3 clusters of 2 R5 cores each. set _r5_cores 6 # sysctrl CTI base set CM3_CTIBASE {0x20001000} # Sysctrl power-ap unlock offsets set _sysctrl_ap_unlock_offsets {0xf0 0x78} # M4 processor set _gp_mcu_cores 1 set _gp_mcu_ap_unlock_offsets {0xf0 0x7c} } default { echo "'$_soc' is invalid!" } } jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_K3_DAP_TAPID -ignore-version dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu set _CTINAME $_CHIPNAME.cti # sysctrl is always present cti create $_CTINAME.sysctrl -dap $_CHIPNAME.dap -ap-num 7 -baseaddr [lindex $CM3_CTIBASE 0] target create $_TARGETNAME.sysctrl cortex_m -dap $_CHIPNAME.dap -ap-num 7 -defer-examine $_TARGETNAME.sysctrl configure -event reset-assert { } proc sysctrl_up {} { # To access sysctrl, we need to enable the JTAG access for the same. # Ensure Power-AP unlocked $::_CHIPNAME.dap apreg 3 [lindex $::_sysctrl_ap_unlock_offsets 0] 0x00190000 $::_CHIPNAME.dap apreg 3 [lindex $::_sysctrl_ap_unlock_offsets 1] 0x00102098 $::_TARGETNAME.sysctrl arp_examine } $_TARGETNAME.sysctrl configure -event gdb-attach { sysctrl_up # gdb-attach default rule halt 1000 } proc _cpu_no_smp_up {} { set _current_target [target current] set _current_type [$_current_target cget -type] $_current_target arp_examine $_current_target $_current_type dbginit } proc _armv8_smp_up {} { for { set _core 0 } { $_core < $::_armv8_cores } { incr _core } { $::_TARGETNAME.$::_armv8_cpu_name.$_core arp_examine $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 dbginit $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 smp on } # Set Default target as core 0 targets $::_TARGETNAME.$::_armv8_cpu_name.0 } set _v8_smp_targets "" for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { cti create $_CTINAME.$_armv8_cpu_name.$_core -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [lindex $ARMV8_CTIBASE $_core] target create $_TARGETNAME.$_armv8_cpu_name.$_core aarch64 -dap $_CHIPNAME.dap \ -dbgbase [lindex $ARMV8_DBGBASE $_core] -cti $_CTINAME.$_armv8_cpu_name.$_core -defer-examine set _v8_smp_targets "$_v8_smp_targets $_TARGETNAME.$_armv8_cpu_name.$_core" if { $_v8_smp_debug == 0 } { $_TARGETNAME.$_armv8_cpu_name.$_core configure -event gdb-attach { _cpu_no_smp_up # gdb-attach default rule halt 1000 } } else { $_TARGETNAME.$_armv8_cpu_name.$_core configure -event gdb-attach { _armv8_smp_up # gdb-attach default rule halt 1000 } } } # Setup ARMV8 proc commands based on CPU to prevent people confusing SoCs set _armv8_up_cmd "$_armv8_cpu_name"_up # Available if V8_SMP_DEBUG is set to non-zero value set _armv8_smp_cmd "$_armv8_cpu_name"_smp if { $_v8_smp_debug == 0 } { proc $_armv8_up_cmd { args } { foreach _core $args { targets $_core _cpu_no_smp_up } } } else { proc $_armv8_smp_cmd { args } { _armv8_smp_up } # Declare SMP target smp $:::_v8_smp_targets } for { set _core 0 } { $_core < $_r5_cores } { incr _core } { set _r5_name [lindex $R5_NAMES $_core] cti create $_CTINAME.$_r5_name -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [lindex $R5_CTIBASE $_core] # inactive core examination will fail - wait till startup of additional core target create $_TARGETNAME.$_r5_name cortex_r4 -dap $_CHIPNAME.dap \ -dbgbase [lindex $R5_DBGBASE $_core] -ap-num 1 -defer-examine $_TARGETNAME.$_r5_name configure -event gdb-attach { _cpu_no_smp_up # gdb-attach default rule halt 1000 } } proc r5_up { args } { foreach _core $args { targets $_core _cpu_no_smp_up } } if { $_gp_mcu_cores != 0 } { cti create $_CTINAME.gp_mcu -dap $_CHIPNAME.dap -ap-num 8 -baseaddr [lindex $CM4_CTIBASE 0] target create $_TARGETNAME.gp_mcu cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine $_TARGETNAME.gp_mcu configure -event reset-assert { } proc gp_mcu_up {} { # To access GP MCU, we need to enable the JTAG access for the same. # Ensure Power-AP unlocked $::_CHIPNAME.dap apreg 3 [lindex $::_gp_mcu_ap_unlock_offsets 0] 0x00190000 $::_CHIPNAME.dap apreg 3 [lindex $::_gp_mcu_ap_unlock_offsets 1] 0x00102098 $::_TARGETNAME.gp_mcu arp_examine } $_TARGETNAME.gp_mcu configure -event gdb-attach { gp_mcu_up # gdb-attach default rule halt 1000 } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_msp432.cfg ================================================ # # Texas Instruments MSP432 - ARM Cortex-M4F @ up to 48 MHz # # http://www.ti.com/MSP432 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME msp432 } if { [info exists CPUTAPID] } { set _DAP_TAPID $CPUTAPID } else { set _DAP_TAPID 0x4ba00477 } if { [info exists DAP_SWD_ID] } { set _DAP_SWD_ID $DAP_SWD_ID } else { set _DAP_SWD_ID 0x2ba01477 } source [find target/swj-dp.tcl] if { [using_jtag] } { set _DAP_ID $_DAP_TAPID } else { set _DAP_ID $_DAP_SWD_ID } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_DAP_ID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME msp432 0 0 0 0 $_TARGETNAME cortex_m reset_config sysresetreq ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_rm4x.cfg ================================================ source [find target/ti_tms570.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_tms570.cfg ================================================ adapter speed 1500 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME tms570 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN big } # TMS570 has an ICEpick-C on which we need the router commands. source [find target/icepick.cfg] # Main DAP # DAP_TAPID should be set before source-ing this file if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" # ICEpick-C (JTAG route controller) # JRC_TAPID should be set before source-ing this file if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } set _JRC_TAPID2 0x0B7B302F set _JRC_TAPID3 0x0B95502F set _JRC_TAPID4 0x0B97102F set _JRC_TAPID5 0x0D8A002F set _JRC_TAPID6 0x2B8A002F set _JRC_TAPID7 0x2D8A002F set _JRC_TAPID8 0x3B8A002F set _JRC_TAPID9 0x3D8A002F jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \ -expected-id $_JRC_TAPID \ -expected-id $_JRC_TAPID2 \ -expected-id $_JRC_TAPID3 \ -expected-id $_JRC_TAPID4 \ -expected-id $_JRC_TAPID5 \ -expected-id $_JRC_TAPID6 \ -expected-id $_JRC_TAPID7 \ -expected-id $_JRC_TAPID8 \ -expected-id $_JRC_TAPID9 \ -ignore-version jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu" jtag configure $_CHIPNAME.jrc -event post-reset "runtest 100" dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # Cortex-R4 target set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_r4 -endian $_ENDIAN \ -dap $_CHIPNAME.dap -coreid 0 -dbgbase 0x00001003 # TMS570 uses quirky BE-32 mode $_CHIPNAME.dap ti_be_32_quirks 1 $_TARGETNAME configure -event "reset-assert" { global _CHIPNAME # assert warm system reset through ICEPick icepick_c_wreset $_CHIPNAME.jrc } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_tms570ls20xxx.cfg ================================================ # TMS570LS20216, TMS570LS20206, TMS570LS10216 # TMS570LS10206, TMS570LS10116, TMS570LS10106 set DAP_TAPID 0x0B7B302F set JRC_TAPID 0x0B7B302F source [find target/ti_tms570.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/ti_tms570ls3137.cfg ================================================ # TMS570LS3137 set DAP_TAPID 0x0B8A002F set JRC_TAPID 0x0B8A002F source [find target/ti_tms570.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/tmpa900.cfg ================================================ ###################################### # Target: Toshiba TMPA900 ###################################### if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME tmpa900 } # Toshiba TMPA900 series MCUs are always little endian as per datasheet. set _ENDIAN little if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926031 } #TMPA900 has following IDs: # CP15.0 register 0x41069265 # CP15.1 register 0x1d152152 # ARM core 0x07926031 # jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst adapter srst delay 20 jtag_ntrst_delay 20 ###################### # Target configuration ###################### set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME # Internal RAM-0 (16kB): 0xf8004000 # Internal RAM-1 (8kB): 0xf8008000 # Use internal RAM-0 and RAM-1 as working area (24kB total). $_TARGETNAME configure -work-area-phys 0xf8004000 -work-area-size 0x6000 \ -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/tmpa910.cfg ================================================ ###################################### # Target: Toshiba TMPA910 ###################################### if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME tmpa910 } # Toshiba TMPA910 series MCUs are always little endian as per datasheet. set _ENDIAN little if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926031 } #TMPA910 has following IDs: # CP15.0 register 0x41069265 # CP15.1 register 0x1d152152 # ARM core 0x07926031 # jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst adapter srst delay 20 jtag_ntrst_delay 20 ###################### # Target configuration ###################### set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME # Internal RAM-0 (16kB): 0xf8004000 # Internal RAM-1 (16kB): 0xf8008000 # Internal RAM-2 (16kB): 0xf800c000 # Use internal RAM-0, RAM-1, and RAM-2 as working area (48kB total). $_TARGETNAME configure -work-area-phys 0xf8004000 -work-area-size 0xc000 \ -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/tnetc4401.cfg ================================================ # Texas Instruments (TI) TNETC4401, MIPS32 DOCSIS-tailored SoC (4Kc-based) # Used in Knovative KC-100 and Motorola Surfboard SB5120 cable modems. # Datasheet: https://brezn.muc.ccc.de/~mazzoo/DOCSIS/tnetc4401.pdf transport select jtag set _TARGETNAME tnetc4401 set _CPUTAPID 0x0000100f jtag newtap $_TARGETNAME tap -irlen 5 -ircapture 0x01 -irmask 0x1f -expected-id $_CPUTAPID target create $_TARGETNAME mips_m4k -chain-position $_TARGETNAME.tap -endian big # May need to halt manually before calling reset init $_TARGETNAME configure -event reset-init { halt echo "Attempting to disable watchdog..." mwb phys 0xa8610b00 0 256 halt wait_halt } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/u8500.cfg ================================================ # Copyright (C) ST-Ericsson SA 2011 # Author : michel.jaouen@stericsson.com # U8500 target proc mmu_off {} { set cp [arm mrc 15 0 1 0 0] set cp [expr {$cp & ~1}] arm mcr 15 0 1 0 0 $cp } proc mmu_on {} { set cp [arm mrc 15 0 1 0 0] set cp [expr {$cp | 1}] arm mcr 15 0 1 0 0 $cp } proc ocd_gdb_restart {target_id} { global _TARGETNAME_1 global _SMP targets $_TARGETNAME_1 if { $_SMP == 1 } { cortex_a smp off } rst_run halt if { $_SMP == 1 } { cortex_a smp on } } proc smp_reg {} { global _TARGETNAME_1 global _TARGETNAME_2 targets $_TARGETNAME_1 echo "$_TARGETNAME_1" set pc1 [reg pc] set stck1 [reg sp_svc] targets $_TARGETNAME_2 echo "$_TARGETNAME_1" set pc2 [reg pc] set stck2 [reg sp_svc] } proc u8500_tapenable {chip val} { echo "JTAG tap enable $chip" } proc pwrsts { } { global _CHIPNAME irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 0 set pwrsts [drscan $_CHIPNAME.jrc 16 0] echo "pwrsts ="$pwrsts set a9 [expr "0x$pwrsts & 0xc"] set ape [expr "0x$pwrsts & 0x3"] if {[string equal "0" $ape]} { echo "ape off" } else { echo "ape on" } echo "$a9" switch $a9 { 4 { echo "A9 in retention" } 8 { echo "A9 100% DVFS" } c { echo "A9 50% DVFS" } } } proc poll_pwrsts { } { global _CHIPNAME set result 1 set i 0 irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 0 set pwrsts [drscan $_CHIPNAME.jrc 16 0] set pwrsts [expr "0x$pwrsts & 0xc"] while {[string equal "4" $pwrsts] && $i<20} { irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 0; set pwrsts [drscan $_CHIPNAME.jrc 16 0] set pwrsts [expr "0x$pwrsts & 0xc"] if {![string equal "4" $pwrsts]} { set result 1 } else { set result 0 sleep 200 echo "loop $i" } incr i } return $result } proc halt_ { } { if {[poll_pwrsts]==1} { halt } else { echo "halt failed : target in retention" } } proc u8500_dapenable {chip} { } proc u8500_tapdisable {chip val} { echo "JTAG tap disable $chip" } proc enable_apetap {} { global _CHIPNAME global _TARGETNAME_2 global _TARGETNAME_1 poll off irscan $_CHIPNAME.jrc 0x3e drscan $_CHIPNAME.jrc 8 0xcf jtag tapenable $_CHIPNAME.dap irscan $_CHIPNAME.jrc 0x6 drscan $_CHIPNAME.jrc 32 0 irscan $_CHIPNAME.jrc 0x6 drscan $_CHIPNAME.jrc 32 0 set status [$_TARGETNAME_1 curstate] if {[string equal "unknown" $status]} { $_TARGETNAME_1 arp_examine cache_config l2x 0xa0412000 8 } set status [$_TARGETNAME_2 curstate] if {[string equal "unknown" $status]} { $_TARGETNAME_2 arp_examine } } tcl_port 5555 telnet_port 4444 gdb_port 3333 if { [info exists CHIPNAME] } { global _CHIPNAME set _CHIPNAME $CHIPNAME } else { global _CHIPNAME set _CHIPNAME u8500 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a bigendian set _ENDIAN little } # Subsidiary TAP: APE with scan chains for ARM Debug, EmbeddedICE-RT, if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0xe -irmask 0xf -expected-id $_CPUTAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable \ "u8500_dapenable $_CHIPNAME.cpu" jtag configure $_CHIPNAME.cpu -event tap-disable \ "u8500_tapdisable $_CHIPNAME.cpu 0xc0" #CLTAPC TAP JRC equivalent if { [info exists CLTAPC_ID] } { set _CLTAPC_ID $CLTAPC_ID } else { set _CLTAPC_ID 0x22286041 } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x6 -irmask 0xf -expected-id $_CLTAPC_ID -ignore-version if { ![info exists TARGETNAME_1] } { global _TARGETNAME_1 set _TARGETNAME_1 $_CHIPNAME.cpu1 } else { global _TARGETNAME_1 set _TARGETNAME_1 $TARGETNAME_1 } if { [info exists DAP_DBG1] } { set _DAP_DBG1 $DAP_DBG1 } else { set _DAP_DBG1 0x801A8000 } if { [info exists DAP_DBG2] } { set _DAP_DBG2 $DAP_DBG2 } else { set _DAP_DBG2 0x801AA000 } dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME_1 cortex_a -dap $_CHIPNAME.dap -dbgbase $_DAP_DBG1 -coreid 0 -rtos linux if { ![info exists TARGETNAME_2] } { global _TARGETNAME_2 set _TARGETNAME_2 $_CHIPNAME.cpu2 } else { global _TARGETNAME_2 set _TARGETNAME_2 $TARGETNAME_2 } target create $_TARGETNAME_2 cortex_a -dap $_CHIPNAME.dap -dbgbase $_DAP_DBG2 -coreid 1 -rtos linux if {![info exists SMP]} { global _SMP set _SMP 1 } else { global _SMP set _SMP $SMP } global SMP if { $_SMP == 1} { target smp $_CHIPNAME.cpu2 $_CHIPNAME.cpu1 } proc secsts1 { } { global _CHIPNAME irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 4 set secsts1 [drscan $_CHIPNAME.jrc 16 0] echo "secsts1 ="$secsts1 set secsts1 [expr "0x$secsts1 & 0x4"] if {![string equal "4" $secsts1]} { echo "APE target secured" } else { echo "APE target not secured" } } proc att { } { global _CHIPNAME jtag arp_init irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 4 set secsts1 [drscan $_CHIPNAME.jrc 16 0] echo "secsts1 ="$secsts1 set secsts1 [expr "0x$secsts1 & 0x4"] if {[string equal "4" $secsts1]} { if {[poll_pwrsts]==1} { enable_apetap } else { echo "target in retention" } } else { echo "target secured" } } proc rst_run { } { global _CHIPNAME global _TARGETNAME_2 global _TARGETNAME_1 set status [$_TARGETNAME_1 curstate] if {[string equal "halted" $status]} { resume targets $_TARGETNAME_1 } set status [$_TARGETNAME_2 curstate] if {[string equal "halted" $status]} { resume targets $_TARGETNAME_2 } poll off jtag arp_init reset sleep 20 irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 4 set secsts1 [drscan $_CHIPNAME.jrc 16 0] echo "secsts1 ="$secsts1 set secsts1 [expr "0x$secsts1 & 0x4"] while {![string equal "4" $secsts1]} { irscan u8500.jrc 0x3a drscan u8500.jrc 4 4 set secsts1 [drscan $_CHIPNAME.jrc 16 0] echo "secsts1 ="$secsts1 set secsts1 [expr "0x$secsts1 & 0x4"] } echo "ape debugable" enable_apetap poll on targets $_TARGETNAME_1 dap apsel 1 } if {![info exists MAXSPEED]} { global _MAXSPEED set _MAXSPEED 15000 } else { global _MAXSPEED set _MAXSPEED $MAXSPEED } global _MAXSPEED adapter speed $_MAXSPEED gdb_breakpoint_override hard set mem inaccessible-by-default-off jtag_ntrst_delay 100 reset_config trst_and_srst combined ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/vd_aarch64.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # Arm v8 64b Cortex A if {![info exists _CORES]} { set _CORES 1 } if {![info exists _CHIPNAME]} { set _CHIPNAME aarch64 } set _TARGETNAME $_CHIPNAME.cpu set _CTINAME $_CHIPNAME.cti set DBGBASE {0x80810000 0x80910000} set CTIBASE {0x80820000 0x80920000} dap create $_CHIPNAME.dap -chain-position $_TARGETNAME $_CHIPNAME.dap apsel 1 for { set _core 0 } { $_core < $_CORES } { incr _core } \ { cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 -baseaddr [lindex $CTIBASE $_core] set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core -coreid $_core" if { $_core != 0 } { # non-boot core examination may fail set _command "$_command -defer-examine" set _smp_command "$_smp_command $_TARGETNAME.$_core" } else { set _smp_command "target smp $_TARGETNAME.$_core" } eval $_command } eval $_smp_command # default target is core 0 targets $_TARGETNAME.0 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/vd_cortex_m.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # ARM Cortex M if {![info exists _CHIPNAME]} { set _CHIPNAME cortex_m } set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_TARGETNAME target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/vd_riscv.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # RISCV core if {![info exists _HARTID]} { set _HARTID 0x00 } if {![info exists _CHIPNAME]} { set _CHIPNAME riscv } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid $_HARTID riscv set_reset_timeout_sec 120 riscv set_command_timeout_sec 120 # prefer to use sba for system bus access riscv set_prefer_sba on ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/vybrid_vf6xx.cfg ================================================ # # Freescale Vybrid VF610 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME vf610 } if { [info exists A5_JTAG_TAPID] } { set _A5_JTAG_TAPID $A5_JTAG_TAPID } else { set _A5_JTAG_TAPID 0x4BA00477 } if { [info exists A5_SWD_TAPID] } { set _A5_SWD_TAPID $A5_SWD_TAPID } else { set _A5_SWD_TAPID 0x3BA02477 } if { [using_jtag] } { set _A5_TAPID $_A5_JTAG_TAPID } else { set _A5_TAPID $_A5_SWD_TAPID } source [find target/swj-dp.tcl] swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_A5_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create ${_TARGETNAME}0 cortex_a -dap $_CHIPNAME.dap -dbgbase 0xc0088000 target create ${_TARGETNAME}1 cortex_m -dap $_CHIPNAME.dap -ap-num 3 -defer-examine adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/xilinx_zynqmp.cfg ================================================ # # target configuration for # Xilinx ZynqMP (UltraScale+ / A53) # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME uscale } # # DAP tap (Quard core A53) # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap # # PS tap (UltraScale+) # if { [info exists PS_TAPID] } { set _PS_TAPID $PS_TAPID jtag newtap $_CHIPNAME ps -irlen 12 -ircapture 0x1 -irmask 0x03 -expected-id $_PS_TAPID } else { # FPGA Programmable logic. Values take from Table 39-1 in UG1085: jtag newtap $_CHIPNAME ps -irlen 12 -ircapture 0x1 -irmask 0x03 -ignore-version \ -expected-id 0x04711093 \ -expected-id 0x04710093 \ -expected-id 0x04721093 \ -expected-id 0x04720093 \ -expected-id 0x04739093 \ -expected-id 0x04730093 \ -expected-id 0x04738093 \ -expected-id 0x04740093 \ -expected-id 0x04750093 \ -expected-id 0x04759093 \ -expected-id 0x04758093 } set jtag_configured 0 jtag configure $_CHIPNAME.ps -event setup { global _CHIPNAME global jtag_configured if { $jtag_configured == 0 } { # add the DAP tap to the chain # See https://forums.xilinx.com/t5/UltraScale-Architecture/JTAG-Chain-Configuration-for-Zynq-UltraScale-MPSoC/td-p/758924 irscan $_CHIPNAME.ps 0x824 drscan $_CHIPNAME.ps 32 0x00000003 runtest 100 # setup event will be re-entered through jtag arp_init # break the recursion set jtag_configured 1 # re-initialized the jtag chain jtag arp_init } } set _TARGETNAME $_CHIPNAME.a53 set _CTINAME $_CHIPNAME.cti set _smp_command "" set DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} set CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core } { cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [lindex $CTIBASE $_core] set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core" if { $_core != 0 } { # non-boot core examination may fail set _command "$_command -defer-examine" set _smp_command "$_smp_command $_TARGETNAME.$_core" } else { # uncomment when "hawt" rtos is merged #set _command "$_command -rtos hawt" set _smp_command "target smp $_TARGETNAME.$_core" } eval $_command } target create uscale.axi mem_ap -dap uscale.dap -ap-num 0 eval $_smp_command targets $_TARGETNAME.0 proc core_up { args } { global _TARGETNAME foreach core $args { $_TARGETNAME.$core arp_examine } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/xmc1xxx.cfg ================================================ # # Infineon XMC1100/XMC1200/XMC1300 family (ARM Cortex-M0 @ 32 MHz) # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xmc1000 } # # Only SWD and SPD supported # source [find target/swj-dp.tcl] if { [info exists CPUTAPID] } { set _CPU_SWD_TAPID $CPUTAPID } else { set _CPU_SWD_TAPID 0x0BB11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_SWD_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } $_TARGETNAME configure -work-area-phys 0x20000000 \ -work-area-size $_WORKAREASIZE \ -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME xmc1xxx 0x10000000 0 0 0 $_TARGETNAME adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/xmc4xxx.cfg ================================================ # # Infineon XMC4100/XMC4200/XMC4400/XMC4500 family (ARM Cortex-M4 @ 80-120 MHz) # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xmc4000 } source [find target/swj-dp.tcl] # # SWJ-DP # if { [info exists CPU_JTAG_TAPID] } { set _CPU_JTAG_TAPID $CPU_JTAG_TAPID } else { set _CPU_JTAG_TAPID 0x4BA00477 } # # SW_DP # if { [info exists CPU_SWD_TAPID] } { set _CPU_SWD_TAPID $CPU_SWD_TAPID } else { set _CPU_SWD_TAPID 0x2BA01477 } if { [using_jtag] } { set _CPU_TAPID $_CPU_JTAG_TAPID } else { set _CPU_TAPID $_CPU_SWD_TAPID } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap # Work-area is a space in RAM used for flash programming # By default use 16 kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME xmc4xxx 0x0C000000 0 0 0 $_TARGETNAME if { ![using_hla] } { cortex_m reset_config sysresetreq } adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/xmos_xs1-xau8a-10_arm.cfg ================================================ # # XMOS xCORE-XA XS1-XAU8A-10: ARM Cortex-M3 @ 48 MHz # # http://www.xmos.com/products/silicon/xcore-xa/xa-series # if { ![info exists CHIPNAME] } { set CHIPNAME xcorexa } if { ![info exists WORKAREASIZE] } { # XS1-XAU8A-10-FB265: 128 KB SRAM set WORKAREASIZE 0x20000 } source [find target/efm32.cfg] ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/zynq_7000.cfg ================================================ # # Xilinx Zynq-7000 All Programmable SoC # # http://www.xilinx.com/products/silicon-devices/soc/zynq-7000/index.htm # set _CHIPNAME zynq set _TARGETNAME $_CHIPNAME.cpu jtag newtap zynq_pl bs -irlen 6 -ircapture 0x1 -irmask 0x03 \ -expected-id 0x23727093 \ -expected-id 0x13722093 \ -expected-id 0x03727093 \ -expected-id 0x03736093 jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4ba00477 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create ${_TARGETNAME}0 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80090000 target create ${_TARGETNAME}1 cortex_a -dap $_CHIPNAME.dap \ -coreid 1 -dbgbase 0x80092000 target smp ${_TARGETNAME}0 ${_TARGETNAME}1 adapter speed 1000 ${_TARGETNAME}0 configure -event reset-assert-post "cortex_a dbginit" ${_TARGETNAME}1 configure -event reset-assert-post "cortex_a dbginit" pld device virtex2 zynq_pl.bs 1 set XC7_JSHUTDOWN 0x0d set XC7_JPROGRAM 0x0b set XC7_JSTART 0x0c set XC7_BYPASS 0x3f proc zynqpl_program {tap} { global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS irscan $tap $XC7_JSHUTDOWN irscan $tap $XC7_JPROGRAM runtest 60000 #JSTART prevents this from working... #irscan $tap $XC7_JSTART runtest 2000 irscan $tap $XC7_BYPASS runtest 2000 } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/target/к1879xб1я.cfg ================================================ # СБИС К1879ХБ1Я # http://www.module.ru/catalog/micro/mikroshema_dekodera_cifrovogo_televizionnogo_signala_sbis_k1879hb1ya/ adapter speed 1000 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME к1879хб1я } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists DSP_TAPID] } { set _DSP_TAPID $DSP_TAPID } else { set _DSP_TAPID 0x2b900f0f } jtag newtap $_CHIPNAME dsp -irlen 4 -expected-id $_DSP_TAPID if { [info exists CPU_TAPID] } { set _CPU_TAPID $CPU_TAPID } else { set _CPU_TAPID 0x07b76f0f } jtag newtap $_CHIPNAME arm -irlen 5 -expected-id $_CPU_TAPID set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm11 -chain-position $_CHIPNAME.arm ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/test/selftest.cfg ================================================ add_help_text selftest "run selftest using working ram
" proc selftest {tmpfile address size} { for {set i 0} {$i < $size } {set i [expr {$i+4}]} { mww [expr {$address+$i}] $i } for {set i 0} {$i < 10 } {set i [expr {$i+1}]} { echo "Test iteration $i" dump_image $tmpfile $address $size verify_image $tmpfile $address bin load_image $tmpfile $address bin } } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/test/syntax1.cfg ================================================ adapter srst delay 200 jtag_ntrst_delay 200 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst #LPCs need reset pulled while RTCK is low. 0 to activate JTAG, power-on reset is not enough adapter assert trst assert srst adapter deassert trst deassert srst #jtag scan chain #format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE) jtag newtap lpc2148 one -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4f1f0f0f #target configuration #daemon_startup reset set _TARGETNAME [format "%s.cpu" lpc2148] target create lpc2148.cpu arm7tdmi -endian little -work-area-size 0x4000 -work-area-phys 0x40000000 -work-area-backup 0 $_TARGETNAME configure -event reset-init { soft_reset_halt mvb 0xE01FC040 0x01 } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME lpc2000 0x0 0x7d000 0 0 0 lpc2000_v2 14765 ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/tools/firmware-recovery.tcl ================================================ echo "\n\nFirmware recovery helpers" echo "Use -c firmware_help to get help\n" set known_boards { "asus-rt-n16 ASUS RT-N16" "asus-rt-n66u ASUS RT-N66U" "linksys-wag200g Linksys WAG200G" "linksys-wrt54gl Linksys WRT54GL v1.1" "netgear-dg834v3 Netgear DG834G v3" "tp-link_tl-mr3020 TP-LINK TL-MR3020" "bt-homehubv1 BT HomeHub v1" } proc firmware_help { } { echo " Your OpenOCD command should look like this: openocd -f interface/.cfg -f tools/firmware-recovery.tcl -c \"*; shutdown\" Where: is one of the supported devices, e.g. ftdi/jtagkey2 are firmware-recovery commands separated by semicolon Supported commands: firmware_help get this help list_boards list known boards and exit board select board you work with list_partitions list partitions of the currently selected board dump_part save partition's contents to a file erase_part erase the given partition flash_part erase, flash and verify the given partition ram_boot load binary file to RAM and run it adapter speed set JTAG clock frequency in kHz For example, to clear nvram and reflash CFE on an RT-N16 using TUMPA, run: openocd -f interface/ftdi/tumpa.cfg -f tools/firmware-recovery.tcl \\ -c \"board asus-rt-n16; erase_part nvram; flash_part CFE cfe-n16.bin; shutdown\" \n\n" shutdown } # set default, can be overridden later adapter speed 1000 proc get_partition { name } { global partition_list dict get $partition_list $name } proc partition_desc { name } { lindex [get_partition $name] 0 } proc partition_start { name } { lindex [get_partition $name] 1 } proc partition_size { name } { lindex [get_partition $name] 2 } proc list_boards { } { global known_boards echo "List of the supported boards:\n" echo "Board name\t\tDescription" echo "-----------------------------------" foreach i $known_boards { echo $i } echo "\n\n" } proc board { name } { script [find board/$name.cfg] } proc list_partitions { } { global partition_list set fstr "%-16s%-14s%-14s%s" echo "\nThe currently selected board is known to have these partitions:\n" echo [format $fstr Name Start Size Description] echo "-------------------------------------------------------" for {set i 0} {$i < [llength $partition_list]} {incr i 2} { set key [lindex $partition_list $i] echo [format $fstr $key [partition_start $key] [partition_size $key] [partition_desc $key]] } echo "\n\n" } # Magic to work with any targets, including semi-functional proc prepare_target { } { init catch {halt} catch {reset init} catch {halt} } proc dump_part { name filename } { prepare_target dump_image $filename [partition_start $name] [partition_size $name] } proc erase_part { name } { prepare_target flash erase_address [partition_start $name] [partition_size $name] } proc flash_part { name filename } { prepare_target flash write_image erase $filename [partition_start $name] bin echo "Verifying:" verify_image $filename [partition_start $name] } proc ram_boot { filename } { global ram_boot_address prepare_target load_image $filename $ram_boot_address bin resume $ram_boot_address } echo "" ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/tools/memtest.tcl ================================================ # Algorithms by Michael Barr, released into public domain # Ported to OpenOCD by Shane Volpe, additional fixes by Paul Fertser set CPU_MAX_ADDRESS 0xFFFFFFFF source [find bitsbytes.tcl] source [find memory.tcl] proc runAllMemTests { baseAddress nBytes } { memTestDataBus $baseAddress memTestAddressBus $baseAddress $nBytes memTestDevice $baseAddress $nBytes } #*********************************************************************************** # * # * Function: memTestDataBus() # * # * Description: Test the data bus wiring in a memory region by # * performing a walking 1's test at a fixed address # * within that region. The address (and hence the # * memory region) is selected by the caller. # * Ported from: # * http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C # * Notes: # * # * Returns: Empty string if the test succeeds. # * A non-zero result is the first pattern that failed. # * #*********************************************************************************** proc memTestDataBus { address } { echo "Running memTestDataBus" for {set i 0} {$i < 32} {incr i} { # Shift bit set pattern [expr {1 << $i}] # Write pattern to memory memwrite32 $address $pattern # Read pattern from memory set data [memread32 $address] if {$data != $pattern} { echo "FAILED DATABUS: Address: $address, Pattern: $pattern, Returned: $data" return $pattern } } } #*********************************************************************************** # * # * Function: memTestAddressBus() # * # * Description: Perform a walking 1's test on the relevant bits # * of the address and check for aliasing. This test # * will find single-bit address failures such as stuck # * -high, stuck-low, and shorted pins. The base address # * and size of the region are selected by the caller. # * Ported from: # * http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C # * # * Notes: For best results, the selected base address should # * have enough LSB 0's to guarantee single address bit # * changes. For example, to test a 64-Kbyte region, # * select a base address on a 64-Kbyte boundary. Also, # * select the region size as a power-of-two--if at all # * possible. # * # * Returns: Empty string if the test succeeds. # * A non-zero result is the first address at which an # * aliasing problem was uncovered. By examining the # * contents of memory, it may be possible to gather # * additional information about the problem. # * #*********************************************************************************** proc memTestAddressBus { baseAddress nBytes } { set addressMask [expr {$nBytes - 1}] set pattern 0xAAAAAAAA set antipattern 0x55555555 echo "Running memTestAddressBus" echo "addressMask: [convertToHex $addressMask]" echo "memTestAddressBus: Writing the default pattern at each of the power-of-two offsets..." for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}] } { set addr [expr {$baseAddress + $offset}] memwrite32 $addr $pattern } echo "memTestAddressBus: Checking for address bits stuck high..." memwrite32 $baseAddress $antipattern for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}]} { set addr [expr {$baseAddress + $offset}] set data [memread32 $addr] if {$data != $pattern} { echo "FAILED DATA_ADDR_BUS_SHIGH: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data]" return $pattern } } echo "memTestAddressBus: Checking for address bits stuck low or shorted..." memwrite32 $baseAddress $pattern for {set testOffset 32} {[expr {$testOffset & $addressMask}] != 0} {set testOffset [expr {$testOffset << 1}] } { set addr [expr {$baseAddress + $testOffset}] memwrite32 $addr $antipattern set data [memread32 $baseAddress] if {$data != $pattern} { echo "FAILED DATA_ADDR_BUS_SLOW: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data]" return $pattern } for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}]} { set addr [expr {$baseAddress + $offset}] set data [memread32 $baseAddress] if {(($data != $pattern) && ($offset != $testOffset))} { echo "FAILED DATA_ADDR_BUS_SLOW2: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data], offset: [convertToHex $offset], testOffset [convertToHex $testOffset]" return $pattern } } set addr [expr {$baseAddress + $testOffset}] memwrite32 $addr $pattern } } #*********************************************************************************** # * # * Function: memTestDevice() # * # * Description: Test the integrity of a physical memory device by # * performing an increment/decrement test over the # * entire region. In the process every storage bit # * in the device is tested as zero and as one. The # * base address and the size of the region are # * selected by the caller. # * Ported from: # * http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C # * Notes: # * # * Returns: Empty string if the test succeeds. # * A non-zero result is the first address at which an # * incorrect value was read back. By examining the # * contents of memory, it may be possible to gather # * additional information about the problem. # * #*********************************************************************************** proc memTestDevice { baseAddress nBytes } { echo "Running memTestDevice" echo "memTestDevice: Filling memory with a known pattern..." for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} { memwrite32 [expr {$baseAddress + $offset}] $pattern } echo "memTestDevice: Checking each location and inverting it for the second pass..." for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} { set addr [expr {$baseAddress + $offset}] set data [memread32 $addr] if {$data != $pattern} { echo "FAILED memTestDevice_pattern: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data], offset: [convertToHex $offset]" return $pattern } set antiPattern [expr {~$pattern}] memwrite32 [expr {$baseAddress + $offset}] $antiPattern } echo "memTestDevice: Checking each location for the inverted pattern and zeroing it..." for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} { set antiPattern [expr {~$pattern & ((1<<32) - 1)}] set addr [expr {$baseAddress + $offset}] set data [memread32 $addr] set dataHex [convertToHex $data] set antiPatternHex [convertToHex $antiPattern] if {$dataHex != $antiPatternHex} { echo "FAILED memTestDevice_antipattern: Address: [convertToHex $addr], antiPattern: $antiPatternHex, Returned: $dataHex, offset: $offset" return $pattern } } } proc convertToHex { value } { format 0x%08x $value } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/scripts/tools/test_cpu_speed.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Description: # Measure the CPU clock frequency of an ARM Cortex-M based device. # # Return: # The CPU clock frequency in Hz. A negative value indicates that the loop # counter was saturated. # # Note: # You may need to adapt the number of cycles for your device. # add_help_text cortex_m_test_cpu_speed "Measure the CPU clock frequency of an ARM Cortex-M based device" add_usage_text cortex_m_test_cpu_speed {address [timeout [cycles_per_loop]]} proc cortex_m_test_cpu_speed { address { timeout 200 } { cycles_per_loop 4 } } { set loop_counter_start 0xffffffff halt # Backup registers and memory. set backup_regs [get_reg -force {pc r0 xPSR}] set backup_mem [read_memory $address 16 3] # We place the following code at the given address to measure the # CPU clock frequency: # # 3801: subs r0, #1 # d1fd: bne #-2 # e7fe: b #-4 write_memory $address 16 {0x3801 0xd1fd 0xe7fe} set_reg "pc $address r0 $loop_counter_start" resume sleep $timeout halt # Get the loop counter value from register r0. set loop_counter_end [dict values [get_reg r0]] set loop_counter_diff [expr {$loop_counter_start - $loop_counter_end}] # Restore registers and memory. set_reg $backup_regs write_memory $address 16 $backup_mem if { [expr {$loop_counter_end == 0}] } { return -1 } return [expr {double($loop_counter_diff) * $cycles_per_loop / $timeout * 1000}] } ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/share/info/dir ================================================ This is the file .../info/dir, which contains the topmost node of the Info hierarchy, called (dir)Top. The first time you invoke Info you start off looking at this node.  File: dir, Node: Top This is the top of the INFO tree This (the Directory node) gives a menu of major topics. Typing "q" exits, "H" lists all Info commands, "d" returns here, "h" gives a primer for first-timers, "mEmacs" visits the Emacs manual, etc. In Emacs, you can click mouse button 2 on a menu item or cross reference to select it. * Menu: Development * OpenOCD: (openocd). OpenOCD User's Guide ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/share/info/openocd.info ================================================ This is openocd.info, produced by makeinfo version 6.8 from openocd.texi. This User's Guide documents release 0.11.0+dev, dated 8 June 2022, of the Open On-Chip Debugger (OpenOCD). * Copyright (C) 2008 The OpenOCD Project * Copyright (C) 2007-2008 Spencer Oliver * Copyright (C) 2008-2010 Oyvind Harboe * Copyright (C) 2008 Duane Ellis * Copyright (C) 2009-2010 David Brownell Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". INFO-DIR-SECTION Development START-INFO-DIR-ENTRY * OpenOCD: (openocd). OpenOCD User's Guide END-INFO-DIR-ENTRY  Indirect: openocd.info-1: 986 openocd.info-2: 336375  Tag Table: (Indirect) Node: Top986 Node: About3443 Node: Developers7775 Node: Debug Adapter Hardware11115 Node: About Jim-Tcl23272 Node: Running25417 Node: OpenOCD Project Setup30813 Ref: OpenOCD Project Setup-Footnote-150765 Ref: OpenOCD Project Setup-Footnote-251105 Ref: OpenOCD Project Setup-Footnote-351373 Node: Config File Guidelines51701 Ref: theinitboardprocedure62880 Ref: definecputargetsworkinginsmp69740 Ref: theinittargetsprocedure74220 Ref: theinittargeteventsprocedure76039 Ref: translatingconfigurationfiles77892 Ref: Config File Guidelines-Footnote-179143 Node: Server Configuration79218 Ref: configurationstage79540 Ref: enteringtherunstage81015 Ref: tcpipports84468 Ref: gdb_port84963 Ref: gdbconfiguration87221 Ref: gdbbreakpointoverride87536 Ref: gdbflashprogram87905 Ref: eventpolling89384 Node: Debug Adapter Configuration91816 Ref: adapter_usb_location94131 Ref: hla_interface122277 Ref: st_link_dap_interface123830 Ref: swimtransport148030 Ref: jtagspeed148797 Node: Reset Configuration151759 Ref: srstandtrstissues154687 Ref: reset_config158869 Node: TAP Declaration166781 Ref: enablinganddisablingtaps178689 Ref: autoprobing181336 Ref: dapdeclaration183991 Ref: dap_create184505 Ref: DAP subcommand apreg186750 Ref: TAP Declaration-Footnote-1189681 Node: CPU Configuration189881 Ref: targettypes192775 Ref: targetconfiguration197095 Ref: rtostype202889 Ref: gdbportoverride204038 Ref: targetcurstate209063 Ref: targetevents211051 Node: Flash Commands218097 Ref: norconfiguration219630 Ref: flashprogrammingcommands222867 Ref: flashprotect230643 Ref: program231465 Ref: flashdriverlist231745 Ref: at91samd251325 Ref: at91sam3255006 Ref: atsame5258360 Ref: nandconfiguration320278 Ref: nanddriverlist330660 Node: Flash Programming336375 Node: PLD/FPGA Commands337988 Node: General Commands340152 Ref: debuglevel343120 Ref: targetstatehandling344425 Ref: resetcommand350250 Ref: memoryaccess352669 Ref: imageaccess354537 Node: Architecture and Core Commands362228 Ref: armhardwaretracing362698 Ref: traceportdrivers370608 Ref: armcrosstrigger372339 Ref: arm9vectorcatch381733 Ref: xscalevectorcatch389604 Ref: add-reg-type-struct429891 Ref: softwaredebugmessagesandtracing436790 Node: JTAG Commands440249 Node: Boundary Scan Commands447727 Node: Utility Commands453407 Node: GDB and OpenOCD455252 Ref: programmingusinggdb460364 Ref: gdbmeminspect462010 Ref: gdbrtossupport463947 Ref: usingopenocdsmpwithgdb466389 Node: Tcl Scripting API467063 Node: FAQ470546 Ref: faqrtck470656 Ref: faqtaporder482547 Node: Tcl Crash Course484313 Node: License496321 Node: OpenOCD Concept Index518733 Node: Command and Driver Index542795  End Tag Table  Local Variables: coding: utf-8 End: ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/share/info/openocd.info-1 ================================================ This is openocd.info, produced by makeinfo version 6.8 from openocd.texi. This User's Guide documents release 0.11.0+dev, dated 8 June 2022, of the Open On-Chip Debugger (OpenOCD). * Copyright (C) 2008 The OpenOCD Project * Copyright (C) 2007-2008 Spencer Oliver * Copyright (C) 2008-2010 Oyvind Harboe * Copyright (C) 2008 Duane Ellis * Copyright (C) 2009-2010 David Brownell Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". INFO-DIR-SECTION Development START-INFO-DIR-ENTRY * OpenOCD: (openocd). OpenOCD User's Guide END-INFO-DIR-ENTRY  File: openocd.info, Node: Top, Next: About, Up: (dir) OpenOCD User's Guide ******************** This User's Guide documents release 0.11.0+dev, dated 8 June 2022, of the Open On-Chip Debugger (OpenOCD). * Copyright (C) 2008 The OpenOCD Project * Copyright (C) 2007-2008 Spencer Oliver * Copyright (C) 2008-2010 Oyvind Harboe * Copyright (C) 2008 Duane Ellis * Copyright (C) 2009-2010 David Brownell Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". * Menu: * About:: About OpenOCD * Developers:: OpenOCD Developer Resources * Debug Adapter Hardware:: Debug Adapter Hardware * About Jim-Tcl:: About Jim-Tcl * Running:: Running OpenOCD * OpenOCD Project Setup:: OpenOCD Project Setup * Config File Guidelines:: Config File Guidelines * Server Configuration:: Server Configuration * Debug Adapter Configuration:: Debug Adapter Configuration * Reset Configuration:: Reset Configuration * TAP Declaration:: TAP Declaration * CPU Configuration:: CPU Configuration * Flash Commands:: Flash Commands * Flash Programming:: Flash Programming * PLD/FPGA Commands:: PLD/FPGA Commands * General Commands:: General Commands * Architecture and Core Commands:: Architecture and Core Commands * JTAG Commands:: JTAG Commands * Boundary Scan Commands:: Boundary Scan Commands * Utility Commands:: Utility Commands * GDB and OpenOCD:: Using GDB and OpenOCD * Tcl Scripting API:: Tcl Scripting API * FAQ:: Frequently Asked Questions * Tcl Crash Course:: Tcl Crash Course * License:: GNU Free Documentation License * OpenOCD Concept Index:: Concept Index * Command and Driver Index:: Command and Driver Index  File: openocd.info, Node: About, Next: Developers, Prev: Top, Up: Top About ***** OpenOCD was created by Dominic Rath as part of a 2005 diploma thesis written at the University of Applied Sciences Augsburg (). Since that time, the project has grown into an active open-source project, supported by a diverse community of software and hardware developers from around the world. What is OpenOCD? ================ The Open On-Chip Debugger (OpenOCD) aims to provide debugging, in-system programming and boundary-scan testing for embedded target devices. It does so with the assistance of a "debug adapter", which is a small hardware module which helps provide the right kind of electrical signaling to the target being debugged. These are required since the debug host (on which OpenOCD runs) won't usually have native support for such signaling, or the connector needed to hook up to the target. Such debug adapters support one or more "transport" protocols, each of which involves different electrical signaling (and uses different messaging protocols on top of that signaling). There are many types of debug adapter, and little uniformity in what they are called. (There are also product naming differences.) These adapters are sometimes packaged as discrete dongles, which may generically be called "hardware interface dongles". Some development boards also integrate them directly, which may let the development board connect directly to the debug host over USB (and sometimes also to power it over USB). For example, a "JTAG Adapter" supports JTAG signaling, and is used to communicate with JTAG (IEEE 1149.1) compliant TAPs on your target board. A "TAP" is a "Test Access Port", a module which processes special instructions and data. TAPs are daisy-chained within and between chips and boards. JTAG supports debugging and boundary scan operations. There are also "SWD Adapters" that support Serial Wire Debug (SWD) signaling to communicate with some newer ARM cores, as well as debug adapters which support both JTAG and SWD transports. SWD supports only debugging, whereas JTAG also supports boundary scan operations. For some chips, there are also "Programming Adapters" supporting special transports used only to write code to flash memory, without support for on-chip debugging or boundary scan. (At this writing, OpenOCD does not support such non-debug adapters.) Dongles: OpenOCD currently supports many types of hardware dongles: USB-based, parallel port-based, and other standalone boxes that run OpenOCD internally. *Note Debug Adapter Hardware::. GDB Debug: It allows ARM7 (ARM7TDMI and ARM720t), ARM9 (ARM920T, ARM922T, ARM926EJ-S, ARM966E-S), XScale (PXA25x, IXP42x), Cortex-M3 (Stellaris LM3, STMicroelectronics STM32 and Energy Micro EFM32) and Intel Quark (x10xx) based cores to be debugged via the GDB protocol. Flash Programming: Flash writing is supported for external CFI-compatible NOR flashes (Intel and AMD/Spansion command set) and several internal flashes (LPC1700, LPC1800, LPC2000, LPC4300, AT91SAM7, AT91SAM3U, STR7x, STR9x, LM3, STM32x and EFM32). Preliminary support for various NAND flash controllers (LPC3180, Orion, S3C24xx, more) is included. OpenOCD Web Site ================ The OpenOCD web site provides the latest public news from the community: Latest User's Guide: ==================== The user's guide you are now reading may not be the latest one available. A version for more recent code may be available. Its HTML form is published regularly at: PDF form is likewise published at: OpenOCD User's Forum ==================== There is an OpenOCD forum (phpBB) hosted by SparkFun, which might be helpful to you. Note that if you want anything to come to the attention of developers, you should post it to the OpenOCD Developer Mailing List instead of this forum. OpenOCD User's Mailing List =========================== The OpenOCD User Mailing List provides the primary means of communication between users: OpenOCD IRC =========== Support can also be found on irc:  File: openocd.info, Node: Developers, Next: Debug Adapter Hardware, Prev: About, Up: Top 1 OpenOCD Developer Resources ***************************** If you are interested in improving the state of OpenOCD's debugging and testing support, new contributions will be welcome. Motivated developers can produce new target, flash or interface drivers, improve the documentation, as well as more conventional bug fixes and enhancements. The resources in this chapter are available for developers wishing to explore or expand the OpenOCD source code. 1.1 OpenOCD Git Repository ========================== During the 0.3.x release cycle, OpenOCD switched from Subversion to a Git repository hosted at SourceForge. The repository URL is: or via http You may prefer to use a mirror and the HTTP protocol: With standard Git tools, use 'git clone' to initialize a local repository, and 'git pull' to update it. There are also gitweb pages letting you browse the repository with a web browser, or download arbitrary snapshots without needing a Git client: The 'README' file contains the instructions for building the project from the repository or a snapshot. Developers that want to contribute patches to the OpenOCD system are strongly encouraged to work against mainline. Patches created against older versions may require additional work from their submitter in order to be updated for newer releases. 1.2 Doxygen Developer Manual ============================ During the 0.2.x release cycle, the OpenOCD project began providing a Doxygen reference manual. This document contains more technical information about the software internals, development processes, and similar documentation: This document is a work-in-progress, but contributions would be welcome to fill in the gaps. All of the source files are provided in-tree, listed in the Doxyfile configuration at the top of the source tree. 1.3 Gerrit Review System ======================== All changes in the OpenOCD Git repository go through the web-based Gerrit Code Review System: After a one-time registration and repository setup, anyone can push commits from their local Git repository directly into Gerrit. All users and developers are encouraged to review, test, discuss and vote for changes in Gerrit. The feedback provides the basis for a maintainer to eventually submit the change to the main Git repository. The 'HACKING' file, also available as the Patch Guide in the Doxygen Developer Manual, contains basic information about how to connect a repository to Gerrit, prepare and push patches. Patch authors are expected to maintain their changes while they're in Gerrit, respond to feedback and if necessary rework and push improved versions of the change. 1.4 OpenOCD Developer Mailing List ================================== The OpenOCD Developer Mailing List provides the primary means of communication between developers: 1.5 OpenOCD Bug Tracker ======================= The OpenOCD Bug Tracker is hosted on SourceForge:  File: openocd.info, Node: Debug Adapter Hardware, Next: About Jim-Tcl, Prev: Developers, Up: Top 2 Debug Adapter Hardware ************************ Defined: dongle: A small device that plugs into a computer and serves as an adapter .... [snip] In the OpenOCD case, this generally refers to a small adapter that attaches to your computer via USB or the parallel port. 2.1 Choosing a Dongle ===================== There are several things you should keep in mind when choosing a dongle. 1. Transport Does it support the kind of communication that you need? OpenOCD focuses mostly on JTAG. Your version may also support other ways to communicate with target devices. 2. Voltage What voltage is your target - 1.8, 2.8, 3.3, or 5V? Does your dongle support it? You might need a level converter. 3. Pinout What pinout does your target board use? Does your dongle support it? You may be able to use jumper wires, or an "octopus" connector, to convert pinouts. 4. Connection Does your computer have the USB, parallel, or Ethernet port needed? 5. RTCK Do you expect to use it with ARM chips and boards with RTCK support (also known as "adaptive clocking")? 2.2 USB FT2232 Based ==================== There are many USB JTAG dongles on the market, many of them based on a chip from "Future Technology Devices International" (FTDI) known as the FTDI FT2232; this is a USB full speed (12 Mbps) chip. See: for more information. In summer 2009, USB high speed (480 Mbps) versions of these FTDI chips started to become available in JTAG adapters. Around 2012, a new variant appeared - FT232H - this is a single-channel version of FT2232H. (Adapters using those high speed FT2232H or FT232H chips may support adaptive clocking.) The FT2232 chips are flexible enough to support some other transport options, such as SWD or the SPI variants used to program some chips. They have two communications channels, and one can be used for a UART adapter at the same time the other one is used to provide a debug adapter. Also, some development boards integrate an FT2232 chip to serve as a built-in low-cost debug adapter and USB-to-serial solution. * usbjtag Link * jtagkey See: * jtagkey2 See: * oocdlink See: By Joern Kaipf * signalyzer See: * Stellaris Eval Boards See: - The Stellaris eval boards bundle FT2232-based JTAG and SWD support, which can be used to debug the Stellaris chips. Using separate JTAG adapters is optional. These boards can also be used in a "pass through" mode as JTAG adapters to other target boards, disabling the Stellaris chip. * TI/Luminary ICDI See: - TI/Luminary In-Circuit Debug Interface (ICDI) Boards are included in Stellaris LM3S9B9x Evaluation Kits. Like the non-detachable FT2232 support on the other Stellaris eval boards, they can be used to debug other target boards. * olimex-jtag See: * Flyswatter/Flyswatter2 See: * turtelizer2 See: Turtelizer 2 (http://www.ethernut.de/en/hardware/turtelizer/index.html), or * comstick Link: * stm32stick Link * axm0432_jtag Axiom AXM-0432 Link - NOTE: This JTAG does not appear to be available anymore as of April 2012. * cortino Link * dlp-usb1232h Link * digilent-hs1 Link * opendous Link FT2232H-based (OpenHardware). * JTAG-lock-pick Tiny 2 Link FT232H-based * GW16042 Link: FT2232H-based 2.3 USB-JTAG / Altera USB-Blaster compatibles ============================================= These devices also show up as FTDI devices, but are not protocol-compatible with the FT2232 devices. They are, however, protocol-compatible among themselves. USB-JTAG devices typically consist of a FT245 followed by a CPLD that understands a particular protocol, or emulates this protocol using some other hardware. They may appear under different USB VID/PID depending on the particular product. The driver can be configured to search for any VID/PID pair (see the section on driver commands). * USB-JTAG Kolja Waschk's USB Blaster-compatible adapter Link: * Altera USB-Blaster Link: 2.4 USB J-Link based ==================== There are several OEM versions of the SEGGER J-Link adapter. It is an example of a microcontroller based JTAG adapter, it uses an AT91SAM764 internally. * SEGGER J-Link Link: * Atmel SAM-ICE (Only works with Atmel chips!) Link: * IAR J-Link 2.5 USB RLINK based =================== Raisonance has an adapter called RLink. It exists in a stripped-down form on the STM32 Primer, permanently attached to the JTAG lines. It also exists on the STM32 Primer2, but that is wired for SWD and not JTAG, thus not supported. * Raisonance RLink Link: * STM32 Primer Link: * STM32 Primer2 Link: 2.6 USB ST-LINK based ===================== STMicroelectronics has an adapter called ST-LINK. They only work with STMicroelectronics chips, notably STM32 and STM8. * ST-LINK This is available standalone and as part of some kits, eg. STM32VLDISCOVERY. Link: * ST-LINK/V2 This is available standalone and as part of some kits, eg. STM32F4DISCOVERY. Link: * STLINK-V3 This is available standalone and as part of some kits. Link: For info the original ST-LINK enumerates using the mass storage usb class; however, its implementation is completely broken. The result is this causes issues under Linux. The simplest solution is to get Linux to ignore the ST-LINK using one of the following methods: * modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:i * add "options usb-storage quirks=483:3744:i" to /etc/modprobe.conf 2.7 USB TI/Stellaris ICDI based =============================== Texas Instruments has an adapter called ICDI. It is not to be confused with the FTDI based adapters that were originally fitted to their evaluation boards. This is the adapter fitted to the Stellaris LaunchPad. 2.8 USB Nuvoton Nu-Link ======================= Nuvoton has an adapter called Nu-Link. It is available either as stand-alone dongle and embedded on development boards. It supports SWD, serial port bridge and mass storage for firmware update. Both Nu-Link v1 and v2 are supported. 2.9 USB CMSIS-DAP based ======================= ARM has released a interface standard called CMSIS-DAP that simplifies connecting debuggers to ARM Cortex based targets . 2.10 USB Other ============== * USBprog Link: - which uses an Atmel MEGA32 and a UBN9604 * USB - Presto Link: * Versaloon-Link Link: * ARM-JTAG-EW Link: * Buspirate Link: * opendous Link: - which uses an AT90USB162 * estick Link: * Keil ULINK v1 Link: * TI XDS110 Debug Probe Link: Link: 2.11 IBM PC Parallel Printer Port Based ======================================= The two well-known "JTAG Parallel Ports" cables are the Xilinx DLC5 and the Macraigor Wiggler. There are many clones and variations of these on the market. Note that parallel ports are becoming much less common, so if you have the choice you should probably avoid these adapters in favor of USB-based ones. * Wiggler - There are many clones of this. Link: * DLC5 - From XILINX - There are many clones of this Link: Search the web for: "XILINX DLC5" - it is no longer produced, PDF schematics are easily found and it is easy to make. * Amontec - JTAG Accelerator Link: * Wiggler2 Link: * Wiggler_ntrst_inverted Yet another variation - See the source code, src/jtag/parport.c * old_amt_wiggler Unknown - probably not on the market today * arm-jtag Link: Most likely [another wiggler clone] * chameleon Link: * Triton Unknown. * Lattice ispDownload from Lattice Semiconductor * flashlink From STMicroelectronics; Link: 2.12 Other... ============= * ep93xx An EP93xx based Linux machine using the GPIO pins directly. * at91rm9200 Like the EP93xx - but an ATMEL AT91RM9200 based solution using the GPIO pins on the chip. * bcm2835gpio A BCM2835-based board (e.g. Raspberry Pi) using the GPIO pins of the expansion header. * imx_gpio A NXP i.MX-based board (e.g. Wandboard) using the GPIO pins (should work on any i.MX processor). * am335xgpio A Texas Instruments AM335x-based board (e.g. BeagleBone Black) using the GPIO pins of the expansion headers. * jtag_vpi A JTAG driver acting as a client for the JTAG VPI server interface. Link: * vdebug A driver for Cadence virtual Debug Interface to emulated or simulated targets. It implements a client connecting to the vdebug server, which in turn communicates with the emulated or simulated RTL model through a transactor. The current version supports only JTAG as a transport, but other virtual transports, like DAP are planned. * jtag_dpi A JTAG driver acting as a client for the SystemVerilog Direct Programming Interface (DPI) for JTAG devices. DPI allows OpenOCD to connect to the JTAG interface of a hardware model written in SystemVerilog, for example, on an emulation model of target hardware. * xlnx_pcie_xvc A JTAG driver exposing Xilinx Virtual Cable over PCI Express to OpenOCD as JTAG/SWD interface. * linuxgpiod A bitbang JTAG driver using Linux GPIO through library libgpiod. * sysfsgpio A bitbang JTAG driver using Linux legacy sysfs GPIO. This is deprecated from Linux v5.3; prefer using linuxgpiod.  File: openocd.info, Node: About Jim-Tcl, Next: Running, Prev: Debug Adapter Hardware, Up: Top 3 About Jim-Tcl *************** OpenOCD uses a small "Tcl Interpreter" known as Jim-Tcl. This programming language provides a simple and extensible command interpreter. All commands presented in this Guide are extensions to Jim-Tcl. You can use them as simple commands, without needing to learn much of anything about Tcl. Alternatively, you can write Tcl programs with them. You can learn more about Jim at its website, . There is an active and responsive community, get on the mailing list if you have any questions. Jim-Tcl maintainers also lurk on the OpenOCD mailing list. * Jim vs. Tcl Jim-Tcl is a stripped down version of the well known Tcl language, which can be found here: . Jim-Tcl has far fewer features. Jim-Tcl is several dozens of .C files and .H files and implements the basic Tcl command set. In contrast: Tcl 8.6 is a 4.2 MB .zip file containing 1540 files. * Missing Features Our practice has been: Add/clone the real Tcl feature if/when needed. We welcome Jim-Tcl improvements, not bloat. Also there are a large number of optional Jim-Tcl features that are not enabled in OpenOCD. * Scripts OpenOCD configuration scripts are Jim-Tcl Scripts. OpenOCD's command interpreter today is a mixture of (newer) Jim-Tcl commands, and the (older) original command interpreter. * Commands At the OpenOCD telnet command line (or via the GDB monitor command) one can type a Tcl for() loop, set variables, etc. Some of the commands documented in this guide are implemented as Tcl scripts, from a 'startup.tcl' file internal to the server. * Historical Note Jim-Tcl was introduced to OpenOCD in spring 2008. Fall 2010, before OpenOCD 0.5 release, OpenOCD switched to using Jim-Tcl as a Git submodule, which greatly simplified upgrading Jim-Tcl to benefit from new features and bugfixes in Jim-Tcl. * Need a crash course in Tcl? *Note Tcl Crash Course::.  File: openocd.info, Node: Running, Next: OpenOCD Project Setup, Prev: About Jim-Tcl, Up: Top 4 Running ********* Properly installing OpenOCD sets up your operating system to grant it access to the debug adapters. On Linux, this usually involves installing a file in '/etc/udev/rules.d,' so OpenOCD has permissions. An example rules file that works for many common adapters is shipped with OpenOCD in the 'contrib' directory. MS-Windows needs complex and confusing driver configuration for every peripheral. Such issues are unique to each operating system, and are not detailed in this User's Guide. Then later you will invoke the OpenOCD server, with various options to tell it how each debug session should work. The '--help' option shows: bash$ openocd --help --help | -h display this help --version | -v display OpenOCD version --file | -f use configuration file --search | -s dir to search for config files and scripts --debug | -d set debug level to 3 | -d set debug level to --log_output | -l redirect log output to file --command | -c run If you don't give any '-f' or '-c' options, OpenOCD tries to read the configuration file 'openocd.cfg'. To specify one or more different configuration files, use '-f' options. For example: openocd -f config1.cfg -f config2.cfg -f config3.cfg Configuration files and scripts are searched for in 1. the current directory, 2. any search dir specified on the command line using the '-s' option, 3. any search dir specified using the 'add_script_search_dir' command, 4. a directory in the 'OPENOCD_SCRIPTS' environment variable (if set), 5. '%APPDATA%/OpenOCD' (only on Windows), 6. '$HOME/Library/Preferences/org.openocd' (only on Darwin), 7. '$XDG_CONFIG_HOME/openocd' ('$XDG_CONFIG_HOME' defaults to '$HOME/.config'), 8. '$HOME/.openocd', 9. the site wide script library '$pkgdatadir/site' and 10. the OpenOCD-supplied script library '$pkgdatadir/scripts'. The first found file with a matching file name will be used. Note: Don't try to use configuration script names or paths which include the "#" character. That character begins Tcl comments. 4.1 Simple setup, no customization ================================== In the best case, you can use two scripts from one of the script libraries, hook up your JTAG adapter, and start the server ... and your JTAG setup will just work "out of the box". Always try to start by reusing those scripts, but assume you'll need more customization even if this works. *Note OpenOCD Project Setup::. If you find a script for your JTAG adapter, and for your board or target, you may be able to hook up your JTAG adapter then start the server with some variation of one of the following: openocd -f interface/ADAPTER.cfg -f board/MYBOARD.cfg openocd -f interface/ftdi/ADAPTER.cfg -f board/MYBOARD.cfg You might also need to configure which reset signals are present, using '-c 'reset_config trst_and_srst'' or something similar. If all goes well you'll see output something like Open On-Chip Debugger 0.4.0 (2010-01-14-15:06) For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : JTAG tap: lm3s.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3) Seeing that "tap/device found" message, and no warnings, means the JTAG communication is working. That's a key milestone, but you'll probably need more project-specific setup. 4.2 What OpenOCD does as it starts ================================== OpenOCD starts by processing the configuration commands provided on the command line or, if there were no '-c command' or '-f file.cfg' options given, in 'openocd.cfg'. *Note Configuration Stage: configurationstage. At the end of the configuration stage it verifies the JTAG scan chain defined using those commands; your configuration should ensure that this always succeeds. Normally, OpenOCD then starts running as a server. Alternatively, commands may be used to terminate the configuration stage early, perform work (such as updating some flash memory), and then shut down without acting as a server. Once OpenOCD starts running as a server, it waits for connections from clients (Telnet, GDB, RPC) and processes the commands issued through those channels. If you are having problems, you can enable internal debug messages via the '-d' option. Also it is possible to interleave Jim-Tcl commands w/config scripts using the '-c' command line switch. To enable debug output (when reporting problems or working on OpenOCD itself), use the '-d' command line switch. This sets the 'debug_level' to "3", outputting the most information, including debug messages. The default setting is "2", outputting only informational messages, warnings and errors. You can also change this setting from within a telnet or gdb session using 'debug_level' (*note debug_level: debuglevel.). You can redirect all output from the server to a file using the '-l ' switch. Note! OpenOCD will launch the GDB & telnet server even if it can not establish a connection with the target. In general, it is possible for the JTAG controller to be unresponsive until the target is set up correctly via e.g. GDB monitor commands in a GDB init script.  File: openocd.info, Node: OpenOCD Project Setup, Next: Config File Guidelines, Prev: Running, Up: Top 5 OpenOCD Project Setup *********************** To use OpenOCD with your development projects, you need to do more than just connect the JTAG adapter hardware (dongle) to your development board and start the OpenOCD server. You also need to configure your OpenOCD server so that it knows about your adapter and board, and helps your work. You may also want to connect OpenOCD to GDB, possibly using Eclipse or some other GUI. 5.1 Hooking up the JTAG Adapter =============================== Today's most common case is a dongle with a JTAG cable on one side (such as a ribbon cable with a 10-pin or 20-pin IDC connector) and a USB cable on the other. Instead of USB, some dongles use Ethernet; older ones may use a PC parallel port, or even a serial port. 1. _Start with power to your target board turned off_, and nothing connected to your JTAG adapter. If you're particularly paranoid, unplug power to the board. It's important to have the ground signal properly set up, unless you are using a JTAG adapter which provides galvanic isolation between the target board and the debugging host. 2. _Be sure it's the right kind of JTAG connector._ If your dongle has a 20-pin ARM connector, you need some kind of adapter (or octopus, see below) to hook it up to boards using 14-pin or 10-pin connectors ... or to 20-pin connectors which don't use ARM's pinout. In the same vein, make sure the voltage levels are compatible. Not all JTAG adapters have the level shifters needed to work with 1.2 Volt boards. 3. _Be certain the cable is properly oriented_ or you might damage your board. In most cases there are only two possible ways to connect the cable. Connect the JTAG cable from your adapter to the board. Be sure it's firmly connected. In the best case, the connector is keyed to physically prevent you from inserting it wrong. This is most often done using a slot on the board's male connector housing, which must match a key on the JTAG cable's female connector. If there's no housing, then you must look carefully and make sure pin 1 on the cable hooks up to pin 1 on the board. Ribbon cables are frequently all grey except for a wire on one edge, which is red. The red wire is pin 1. Sometimes dongles provide cables where one end is an "octopus" of color coded single-wire connectors, instead of a connector block. These are great when converting from one JTAG pinout to another, but are tedious to set up. Use these with connector pinout diagrams to help you match up the adapter signals to the right board pins. 4. _Connect the adapter's other end_ once the JTAG cable is connected. A USB, parallel, or serial port connector will go to the host which you are using to run OpenOCD. For Ethernet, consult the documentation and your network administrator. For USB-based JTAG adapters you have an easy sanity check at this point: does the host operating system see the JTAG adapter? If you're running Linux, try the 'lsusb' command. If that host is an MS-Windows host, you'll need to install a driver before OpenOCD works. 5. _Connect the adapter's power supply, if needed._ This step is primarily for non-USB adapters, but sometimes USB adapters need extra power. 6. _Power up the target board._ Unless you just let the magic smoke escape, you're now ready to set up the OpenOCD server so you can use JTAG to work with that board. Talk with the OpenOCD server using telnet ('telnet localhost 4444' on many systems) or GDB. *Note GDB and OpenOCD::. 5.2 Project Directory ===================== There are many ways you can configure OpenOCD and start it up. A simple way to organize them all involves keeping a single directory for your work with a given board. When you start OpenOCD from that directory, it searches there first for configuration files, scripts, files accessed through semihosting, and for code you upload to the target board. It is also the natural place to write files, such as log files and data you download from the board. 5.3 Configuration Basics ======================== There are two basic ways of configuring OpenOCD, and a variety of ways you can mix them. Think of the difference as just being how you start the server: * Many '-f file' or '-c command' options on the command line * No options, but a "user config file" in the current directory named 'openocd.cfg' Here is an example 'openocd.cfg' file for a setup using a Signalyzer FT2232-based JTAG adapter to talk to a board with an Atmel AT91SAM7X256 microcontroller: source [find interface/ftdi/signalyzer.cfg] # GDB can also flash my flash! gdb_memory_map enable gdb_flash_program enable source [find target/sam7x256.cfg] Here is the command line equivalent of that configuration: openocd -f interface/ftdi/signalyzer.cfg \ -c "gdb_memory_map enable" \ -c "gdb_flash_program enable" \ -f target/sam7x256.cfg You could wrap such long command lines in shell scripts, each supporting a different development task. One might re-flash the board with a specific firmware version. Another might set up a particular debugging or run-time environment. Important: At this writing (October 2009) the command line method has problems with how it treats variables. For example, after '-c "set VAR value"', or doing the same in a script, the variable VAR will have no value that can be tested in a later script. Here we will focus on the simpler solution: one user config file, including basic configuration plus any TCL procedures to simplify your work. 5.4 User Config Files ===================== A user configuration file ties together all the parts of a project in one place. One of the following will match your situation best: * Ideally almost everything comes from configuration files provided by someone else. For example, OpenOCD distributes a 'scripts' directory (probably in '/usr/share/openocd/scripts' on Linux). Board and tool vendors can provide these too, as can individual user sites; the '-s' command line option lets you say where to find these files. (*Note Running::.) The AT91SAM7X256 example above works this way. Three main types of non-user configuration file each have their own subdirectory in the 'scripts' directory: 1. interface - one for each different debug adapter; 2. board - one for each different board 3. target - the chips which integrate CPUs and other JTAG TAPs Best case: include just two files, and they handle everything else. The first is an interface config file. The second is board-specific, and it sets up the JTAG TAPs and their GDB targets (by deferring to some 'target.cfg' file), declares all flash memory, and leaves you nothing to do except meet your deadline: source [find interface/olimex-jtag-tiny.cfg] source [find board/csb337.cfg] Boards with a single microcontroller often won't need more than the target config file, as in the AT91SAM7X256 example. That's because there is no external memory (flash, DDR RAM), and the board differences are encapsulated by application code. * Maybe you don't know yet what your board looks like to JTAG. Once you know the 'interface.cfg' file to use, you may need help from OpenOCD to discover what's on the board. Once you find the JTAG TAPs, you can just search for appropriate target and board configuration files ... or write your own, from the bottom up. *Note Autoprobing: autoprobing. * You can often reuse some standard config files but need to write a few new ones, probably a 'board.cfg' file. You will be using commands described later in this User's Guide, and working with the guidelines in the next chapter. For example, there may be configuration files for your JTAG adapter and target chip, but you need a new board-specific config file giving access to your particular flash chips. Or you might need to write another target chip configuration file for a new chip built around the Cortex-M3 core. Note: When you write new configuration files, please submit them for inclusion in the next OpenOCD release. For example, a 'board/newboard.cfg' file will help the next users of that board, and a 'target/newcpu.cfg' will help support users of any board using that chip. * You may need to write some C code. It may be as simple as supporting a new FT2232 or parport based adapter; a bit more involved, like a NAND or NOR flash controller driver; or a big piece of work like supporting a new chip architecture. Reuse the existing config files when you can. Look first in the 'scripts/boards' area, then 'scripts/targets'. You may find a board configuration that's a good example to follow. When you write config files, separate the reusable parts (things every user of that interface, chip, or board needs) from ones specific to your environment and debugging approach. * For example, a 'gdb-attach' event handler that invokes the 'reset init' command will interfere with debugging early boot code, which performs some of the same actions that the 'reset-init' event handler does. * Likewise, the 'arm9 vector_catch' command (or its siblings 'xscale vector_catch' and 'cortex_m vector_catch') can be a time-saver during some debug sessions, but don't make everyone use that either. Keep those kinds of debugging aids in your user config file, along with messaging and tracing setup. (*Note Software Debug Messages and Tracing: softwaredebugmessagesandtracing.) * You might need to override some defaults. For example, you might need to move, shrink, or back up the target's work area if your application needs much SRAM. * TCP/IP port configuration is another example of something which is environment-specific, and should only appear in a user config file. *Note TCP/IP Ports: tcpipports. 5.5 Project-Specific Utilities ============================== A few project-specific utility routines may well speed up your work. Write them, and keep them in your project's user config file. For example, if you are making a boot loader work on a board, it's nice to be able to debug the "after it's loaded to RAM" parts separately from the finicky early code which sets up the DDR RAM controller and clocks. A script like this one, or a more GDB-aware sibling, may help: proc ramboot { } { # Reset, running the target's "reset-init" scripts # to initialize clocks and the DDR RAM controller. # Leave the CPU halted. reset init # Load CONFIG_SKIP_LOWLEVEL_INIT version into DDR RAM. load_image u-boot.bin 0x20000000 # Start running. resume 0x20000000 } Then once that code is working you will need to make it boot from NOR flash; a different utility would help. Alternatively, some developers write to flash using GDB. (You might use a similar script if you're working with a flash based microcontroller application instead of a boot loader.) proc newboot { } { # Reset, leaving the CPU halted. The "reset-init" event # proc gives faster access to the CPU and to NOR flash; # "reset halt" would be slower. reset init # Write standard version of U-Boot into the first two # sectors of NOR flash ... the standard version should # do the same lowlevel init as "reset-init". flash protect 0 0 1 off flash erase_sector 0 0 1 flash write_bank 0 u-boot.bin 0x0 flash protect 0 0 1 on # Reboot from scratch using that new boot loader. reset run } You may need more complicated utility procedures when booting from NAND. That often involves an extra bootloader stage, running from on-chip SRAM to perform DDR RAM setup so it can load the main bootloader code (which won't fit into that SRAM). Other helper scripts might be used to write production system images, involving considerably more than just a three stage bootloader. 5.6 Target Software Changes =========================== Sometimes you may want to make some small changes to the software you're developing, to help make JTAG debugging work better. For example, in C or assembly language code you might use '#ifdef JTAG_DEBUG' (or its converse) around code handling issues like: * Watchdog Timers... Watchdog timers are typically used to automatically reset systems if some application task doesn't periodically reset the timer. (The assumption is that the system has locked up if the task can't run.) When a JTAG debugger halts the system, that task won't be able to run and reset the timer ... potentially causing resets in the middle of your debug sessions. It's rarely a good idea to disable such watchdogs, since their usage needs to be debugged just like all other parts of your firmware. That might however be your only option. Look instead for chip-specific ways to stop the watchdog from counting while the system is in a debug halt state. It may be simplest to set that non-counting mode in your debugger startup scripts. You may however need a different approach when, for example, a motor could be physically damaged by firmware remaining inactive in a debug halt state. That might involve a type of firmware mode where that "non-counting" mode is disabled at the beginning then re-enabled at the end; a watchdog reset might fire and complicate the debug session, but hardware (or people) would be protected.(1) * ARM Semihosting... When linked with a special runtime library provided with many toolchains(2), your target code can use I/O facilities on the debug host. That library provides a small set of system calls which are handled by OpenOCD. It can let the debugger provide your system console and a file system, helping with early debugging or providing a more capable environment for sometimes-complex tasks like installing system firmware onto NAND or SPI flash. * ARM Wait-For-Interrupt... Many ARM chips synchronize the JTAG clock using the core clock. Low power states which stop that core clock thus prevent JTAG access. Idle loops in tasking environments often enter those low power states via the 'WFI' instruction (or its coprocessor equivalent, before ARMv7). You may want to _disable that instruction_ in source code, or otherwise prevent using that state, to ensure you can get JTAG access at any time.(3) For example, the OpenOCD 'halt' command may not work for an idle processor otherwise. * Delay after reset... Not all chips have good support for debugger access right after reset; many LPC2xxx chips have issues here. Similarly, applications that reconfigure pins used for JTAG access as they start will also block debugger access. To work with boards like this, _enable a short delay loop_ the first thing after reset, before "real" startup activities. For example, one second's delay is usually more than enough time for a JTAG debugger to attach, so that early code execution can be debugged or firmware can be replaced. * Debug Communications Channel (DCC)... Some processors include mechanisms to send messages over JTAG. Many ARM cores support these, as do some cores from other vendors. (OpenOCD may be able to use this DCC internally, speeding up some operations like writing to memory.) Your application may want to deliver various debugging messages over JTAG, by _linking with a small library of code_ provided with OpenOCD and using the utilities there to send various kinds of message. *Note Software Debug Messages and Tracing: softwaredebugmessagesandtracing. 5.7 Target Hardware Setup ========================= Chip vendors often provide software development boards which are highly configurable, so that they can support all options that product boards may require. _Make sure that any jumpers or switches match the system configuration you are working with._ Common issues include: * JTAG setup ... Boards may support more than one JTAG configuration. Examples include jumpers controlling pullups versus pulldowns on the nTRST and/or nSRST signals, and choice of connectors (e.g. which of two headers on the base board, or one from a daughtercard). For some Texas Instruments boards, you may need to jumper the EMU0 and EMU1 signals (which OpenOCD won't currently control). * Boot Modes ... Complex chips often support multiple boot modes, controlled by external jumpers. Make sure this is set up correctly. For example many i.MX boards from NXP need to be jumpered to "ATX mode" to start booting using the on-chip ROM, when using second stage bootloader code stored in a NAND flash chip. Such explicit configuration is common, and not limited to booting from NAND. You might also need to set jumpers to start booting using code loaded from an MMC/SD card; external SPI flash; Ethernet, UART, or USB links; NOR flash; OneNAND flash; some external host; or various other sources. * Memory Addressing ... Boards which support multiple boot modes may also have jumpers to configure memory addressing. One board, for example, jumpers external chipselect 0 (used for booting) to address either a large SRAM (which must be pre-loaded via JTAG), NOR flash, or NAND flash. When it's jumpered to address NAND flash, that board must also be told to start booting from on-chip ROM. Your 'board.cfg' file may also need to be told this jumper configuration, so that it can know whether to declare NOR flash using 'flash bank' or instead declare NAND flash with 'nand device'; and likewise which probe to perform in its 'reset-init' handler. A closely related issue is bus width. Jumpers might need to distinguish between 8 bit or 16 bit bus access for the flash used to start booting. * Peripheral Access ... Development boards generally provide access to every peripheral on the chip, sometimes in multiple modes (such as by providing multiple audio codec chips). This interacts with software configuration of pin multiplexing, where for example a given pin may be routed either to the MMC/SD controller or the GPIO controller. It also often interacts with configuration jumpers. One jumper may be used to route signals to an MMC/SD card slot or an expansion bus (which might in turn affect booting); others might control which audio or video codecs are used. Plus you should of course have 'reset-init' event handlers which set up the hardware to match that jumper configuration. That includes in particular any oscillator or PLL used to clock the CPU, and any memory controllers needed to access external memory and peripherals. Without such handlers, you won't be able to access those resources without working target firmware which can do that setup ... this can be awkward when you're trying to debug that target firmware. Even if there's a ROM bootloader which handles a few issues, it rarely provides full access to all board-specific capabilities. ---------- Footnotes ---------- (1) Note that many systems support a "monitor mode" debug that is a somewhat cleaner way to address such issues. You can think of it as only halting part of the system, maybe just one task, instead of the whole thing. At this writing, January 2010, OpenOCD based debugging does not support monitor mode debug, only "halt mode" debug. (2) See chapter 8 "Semihosting" in ARM DUI 0203I (http://infocenter.arm.com/help/topic/com.arm.doc.dui0203i/DUI0203I_rvct_developer_guide.pdf), the "RealView Compilation Tools Developer Guide". The CodeSourcery EABI toolchain also includes a semihosting library. (3) As a more polite alternative, some processors have special debug-oriented registers which can be used to change various features including how the low power states are clocked while debugging. The STM32 DBGMCU_CR register is an example; at the cost of extra power consumption, JTAG can be used during low power states.  File: openocd.info, Node: Config File Guidelines, Next: Server Configuration, Prev: OpenOCD Project Setup, Up: Top 6 Config File Guidelines ************************ This chapter is aimed at any user who needs to write a config file, including developers and integrators of OpenOCD and any user who needs to get a new board working smoothly. It provides guidelines for creating those files. You should find the following directories under $(INSTALLDIR)/scripts, with config files maintained upstream. Use them as-is where you can; or as models for new files. * 'interface' ... These are for debug adapters. Files that specify configuration to use specific JTAG, SWD and other adapters go here. * 'board' ... Think Circuit Board, PWA, PCB, they go by many names. Board files contain initialization items that are specific to a board. They reuse target configuration files, since the same microprocessor chips are used on many boards, but support for external parts varies widely. For example, the SDRAM initialization sequence for the board, or the type of external flash and what address it uses. Any initialization sequence to enable that external flash or SDRAM should be found in the board file. Boards may also contain multiple targets: two CPUs; or a CPU and an FPGA. * 'target' ... Think chip. The "target" directory represents the JTAG TAPs on a chip which OpenOCD should control, not a board. Two common types of targets are ARM chips and FPGA or CPLD chips. When a chip has multiple TAPs (maybe it has both ARM and DSP cores), the target config file defines all of them. * _more_ ... browse for other library files which may be useful. For example, there are various generic and CPU-specific utilities. The 'openocd.cfg' user config file may override features in any of the above files by setting variables before sourcing the target file, or by adding commands specific to their situation. 6.1 Interface Config Files ========================== The user config file should be able to source one of these files with a command like this: source [find interface/FOOBAR.cfg] A preconfigured interface file should exist for every debug adapter in use today with OpenOCD. That said, perhaps some of these config files have only been used by the developer who created it. A separate chapter gives information about how to set these up. *Note Debug Adapter Configuration::. Read the OpenOCD source code (and Developer's Guide) if you have a new kind of hardware interface and need to provide a driver for it. -- Command: find 'filename' Prints full path to FILENAME according to OpenOCD search rules. -- Command: ocd_find 'filename' Prints full path to FILENAME according to OpenOCD search rules. This is a low level function used by the 'find'. Usually you want to use 'find', instead. 6.2 Board Config Files ====================== The user config file should be able to source one of these files with a command like this: source [find board/FOOBAR.cfg] The point of a board config file is to package everything about a given board that user config files need to know. In summary the board files should contain (if present) 1. One or more 'source [find target/...cfg]' statements 2. NOR flash configuration (*note NOR Configuration: norconfiguration.) 3. NAND flash configuration (*note NAND Configuration: nandconfiguration.) 4. Target 'reset' handlers for SDRAM and I/O configuration 5. JTAG adapter reset configuration (*note Reset Configuration::) 6. All things that are not "inside a chip" Generic things inside target chips belong in target config files, not board config files. So for example a 'reset-init' event handler should know board-specific oscillator and PLL parameters, which it passes to target-specific utility code. The most complex task of a board config file is creating such a 'reset-init' event handler. Define those handlers last, after you verify the rest of the board configuration works. 6.2.1 Communication Between Config files ---------------------------------------- In addition to target-specific utility code, another way that board and target config files communicate is by following a convention on how to use certain variables. The full Tcl/Tk language supports "namespaces", but Jim-Tcl does not. Thus the rule we follow in OpenOCD is this: Variables that begin with a leading underscore are temporary in nature, and can be modified and used at will within a target configuration file. Complex board config files can do the things like this, for a board with three chips: # Chip #1: PXA270 for network side, big endian set CHIPNAME network set ENDIAN big source [find target/pxa270.cfg] # on return: _TARGETNAME = network.cpu # other commands can refer to the "network.cpu" target. $_TARGETNAME configure .... events for this CPU.. # Chip #2: PXA270 for video side, little endian set CHIPNAME video set ENDIAN little source [find target/pxa270.cfg] # on return: _TARGETNAME = video.cpu # other commands can refer to the "video.cpu" target. $_TARGETNAME configure .... events for this CPU.. # Chip #3: Xilinx FPGA for glue logic set CHIPNAME xilinx unset ENDIAN source [find target/spartan3.cfg] That example is oversimplified because it doesn't show any flash memory, or the 'reset-init' event handlers to initialize external DRAM or (assuming it needs it) load a configuration into the FPGA. Such features are usually needed for low-level work with many boards, where "low level" implies that the board initialization software may not be working. (That's a common reason to need JTAG tools. Another is to enable working with microcontroller-based systems, which often have no debugging support except a JTAG connector.) Target config files may also export utility functions to board and user config files. Such functions should use name prefixes, to help avoid naming collisions. Board files could also accept input variables from user config files. For example, there might be a 'J4_JUMPER' setting used to identify what kind of flash memory a development board is using, or how to set up other clocks and peripherals. 6.2.2 Variable Naming Convention -------------------------------- Most boards have only one instance of a chip. However, it should be easy to create a board with more than one such chip (as shown above). Accordingly, we encourage these conventions for naming variables associated with different 'target.cfg' files, to promote consistency and so that board files can override target defaults. Inputs to target config files include: * 'CHIPNAME' ... This gives a name to the overall chip, and is used as part of tap identifier dotted names. While the default is normally provided by the chip manufacturer, board files may need to distinguish between instances of a chip. * 'ENDIAN' ... By default 'little' - although chips may hard-wire 'big'. Chips that can't change endianness don't need to use this variable. * 'CPUTAPID' ... When OpenOCD examines the JTAG chain, it can be told verify the chips against the JTAG IDCODE register. The target file will hold one or more defaults, but sometimes the chip in a board will use a different ID (perhaps a newer revision). Outputs from target config files include: * '_TARGETNAME' ... By convention, this variable is created by the target configuration script. The board configuration file may make use of this variable to configure things like a "reset init" script, or other things specific to that board and that target. If the chip has 2 targets, the names are '_TARGETNAME0', '_TARGETNAME1', ... etc. 6.2.3 The reset-init Event Handler ---------------------------------- Board config files run in the OpenOCD configuration stage; they can't use TAPs or targets, since they haven't been fully set up yet. This means you can't write memory or access chip registers; you can't even verify that a flash chip is present. That's done later in event handlers, of which the target 'reset-init' handler is one of the most important. Except on microcontrollers, the basic job of 'reset-init' event handlers is setting up flash and DRAM, as normally handled by boot loaders. Microcontrollers rarely use boot loaders; they run right out of their on-chip flash and SRAM memory. But they may want to use one of these handlers too, if just for developer convenience. Note: Because this is so very board-specific, and chip-specific, no examples are included here. Instead, look at the board config files distributed with OpenOCD. If you have a boot loader, its source code will help; so will configuration files for other JTAG tools (*note Translating Configuration Files: translatingconfigurationfiles.). Some of this code could probably be shared between different boards. For example, setting up a DRAM controller often doesn't differ by much except the bus width (16 bits or 32?) and memory timings, so a reusable TCL procedure loaded by the 'target.cfg' file might take those as parameters. Similarly with oscillator, PLL, and clock setup; and disabling the watchdog. Structure the code cleanly, and provide comments to help the next developer doing such work. (_You might be that next person_ trying to reuse init code!) The last thing normally done in a 'reset-init' handler is probing whatever flash memory was configured. For most chips that needs to be done while the associated target is halted, either because JTAG memory access uses the CPU or to prevent conflicting CPU access. 6.2.4 JTAG Clock Rate --------------------- Before your 'reset-init' handler has set up the PLLs and clocking, you may need to run with a low JTAG clock rate. *Note JTAG Speed: jtagspeed. Then you'd increase that rate after your handler has made it possible to use the faster JTAG clock. When the initial low speed is board-specific, for example because it depends on a board-specific oscillator speed, then you should probably set it up in the board config file; if it's target-specific, it belongs in the target config file. For most ARM-based processors the fastest JTAG clock(1) is one sixth of the CPU clock; or one eighth for ARM11 cores. Consult chip documentation to determine the peak JTAG clock rate, which might be less than that. Warning: On most ARMs, JTAG clock detection is coupled to the core clock, so software using a 'wait for interrupt' operation blocks JTAG access. Adaptive clocking provides a partial workaround, but a more complete solution just avoids using that instruction with JTAG debuggers. If both the chip and the board support adaptive clocking, use the 'jtag_rclk' command, in case your board is used with JTAG adapter which also supports it. Otherwise use 'adapter speed'. Set the slow rate at the beginning of the reset sequence, and the faster rate as soon as the clocks are at full speed. 6.2.5 The init_board procedure ------------------------------ The concept of 'init_board' procedure is very similar to 'init_targets' (*Note The init_targets procedure: theinittargetsprocedure.) - it's a replacement of "linear" configuration scripts. This procedure is meant to be executed when OpenOCD enters run stage (*Note Entering the Run Stage: enteringtherunstage,) after 'init_targets'. The idea to have separate 'init_targets' and 'init_board' procedures is to allow the first one to configure everything target specific (internal flash, internal RAM, etc.) and the second one to configure everything board specific (reset signals, chip frequency, reset-init event handler, external memory, etc.). Additionally "linear" board config file will most likely fail when target config file uses 'init_targets' scheme ("linear" script is executed before 'init' and 'init_targets' - after), so separating these two configuration stages is very convenient, as the easiest way to overcome this problem is to convert board config file to use 'init_board' procedure. Board config scripts don't need to override 'init_targets' defined in target config files when they only need to add some specifics. Just as 'init_targets', the 'init_board' procedure can be overridden by "next level" script (which sources the original), allowing greater code reuse. ### board_file.cfg ### # source target file that does most of the config in init_targets source [find target/target.cfg] proc enable_fast_clock {} { # enables fast on-board clock source # configures the chip to use it } # initialize only board specifics - reset, clock, adapter frequency proc init_board {} { reset_config trst_and_srst trst_pulls_srst $_TARGETNAME configure -event reset-start { adapter speed 100 } $_TARGETNAME configure -event reset-init { enable_fast_clock adapter speed 10000 } } 6.3 Target Config Files ======================= Board config files communicate with target config files using naming conventions as described above, and may source one or more target config files like this: source [find target/FOOBAR.cfg] The point of a target config file is to package everything about a given chip that board config files need to know. In summary the target files should contain 1. Set defaults 2. Add TAPs to the scan chain 3. Add CPU targets (includes GDB support) 4. CPU/Chip/CPU-Core specific features 5. On-Chip flash As a rule of thumb, a target file sets up only one chip. For a microcontroller, that will often include a single TAP, which is a CPU needing a GDB target, and its on-chip flash. More complex chips may include multiple TAPs, and the target config file may need to define them all before OpenOCD can talk to the chip. For example, some phone chips have JTAG scan chains that include an ARM core for operating system use, a DSP, another ARM core embedded in an image processing engine, and other processing engines. 6.3.1 Default Value Boiler Plate Code ------------------------------------- All target configuration files should start with code like this, letting board config files express environment-specific differences in how things should be set up. # Boards may override chip names, perhaps based on role, # but the default should match what the vendor uses if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sam7x256 } # ONLY use ENDIAN with targets that can change it. if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # TAP identifiers may change as chips mature, for example with # new revision fields (the "3" here). Pick a good default; you # can pass several such identifiers to the "jtag newtap" command. if { [info exists CPUTAPID ] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } _Remember:_ Board config files may include multiple target config files, or the same target file multiple times (changing at least 'CHIPNAME'). Likewise, the target configuration file should define '_TARGETNAME' (or '_TARGETNAME0' etc) and use it later on when defining debug targets: set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME 6.3.2 Adding TAPs to the Scan Chain ----------------------------------- After the "defaults" are set up, add the TAPs on each chip to the JTAG scan chain. *Note TAP Declaration::, and the naming convention for taps. In the simplest case the chip has only one TAP, probably for a CPU or FPGA. The config file for the Atmel AT91SAM7X256 looks (in part) like this: jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID A board with two such at91sam7 chips would be able to source such a config file twice, with different values for 'CHIPNAME', so it adds a different TAP each time. If there are nonzero '-expected-id' values, OpenOCD attempts to verify the actual tap id against those values. It will issue error messages if there is mismatch, which can help to pinpoint problems in OpenOCD configurations. JTAG tap: sam7x256.cpu tap/device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3) ERROR: Tap: sam7x256.cpu - Expected id: 0x12345678, Got: 0x3f0f0f0f ERROR: expected: mfg: 0x33c, part: 0x2345, ver: 0x1 ERROR: got: mfg: 0x787, part: 0xf0f0, ver: 0x3 There are more complex examples too, with chips that have multiple TAPs. Ones worth looking at include: * 'target/omap3530.cfg' - with disabled ARM and DSP, plus a JRC to enable them * 'target/str912.cfg' - with flash, CPU, and boundary scan * 'target/ti_dm355.cfg' - with ETM, ARM, and JRC (this JRC is not currently used) 6.3.3 Add CPU targets --------------------- After adding a TAP for a CPU, you should set it up so that GDB and other commands can use it. *Note CPU Configuration::. For the at91sam7 example above, the command can look like this; note that '$_ENDIAN' is not needed, since OpenOCD defaults to little endian, and this chip doesn't support changing that. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME Work areas are small RAM areas associated with CPU targets. They are used by OpenOCD to speed up downloads, and to download small snippets of code to program flash chips. If the chip includes a form of "on-chip-ram" - and many do - define a work area if you can. Again using the at91sam7 as an example, this can look like: $_TARGETNAME configure -work-area-phys 0x00200000 \ -work-area-size 0x4000 -work-area-backup 0 6.3.4 Define CPU targets working in SMP --------------------------------------- After setting targets, you can define a list of targets working in SMP. set _TARGETNAME_1 $_CHIPNAME.cpu1 set _TARGETNAME_2 $_CHIPNAME.cpu2 target create $_TARGETNAME_1 cortex_a -chain-position $_CHIPNAME.dap \ -coreid 0 -dbgbase $_DAP_DBG1 target create $_TARGETNAME_2 cortex_a -chain-position $_CHIPNAME.dap \ -coreid 1 -dbgbase $_DAP_DBG2 #define 2 targets working in smp. target smp $_CHIPNAME.cpu2 $_CHIPNAME.cpu1 In the above example on cortex_a, 2 cpus are working in SMP. In SMP only one GDB instance is created and : * a set of hardware breakpoint sets the same breakpoint on all targets in the list. * halt command triggers the halt of all targets in the list. * resume command triggers the write context and the restart of all targets in the list. * following a breakpoint: the target stopped by the breakpoint is displayed to the GDB session. * dedicated GDB serial protocol packets are implemented for switching/retrieving the target displayed by the GDB session *note Using OpenOCD SMP with GDB: usingopenocdsmpwithgdb. The SMP behaviour can be disabled/enabled dynamically. On cortex_a following command have been implemented. * cortex_a smp on : enable SMP mode, behaviour is as described above. * cortex_a smp off : disable SMP mode, the current target is the one displayed in the GDB session, only this target is now controlled by GDB session. This behaviour is useful during system boot up. * cortex_a smp : display current SMP mode. * cortex_a smp_gdb : display/fix the core id displayed in GDB session see following example. >cortex_a smp_gdb gdb coreid 0 -> -1 #0 : coreid 0 is displayed to GDB , #-> -1 : next resume triggers a real resume > cortex_a smp_gdb 1 gdb coreid 0 -> 1 #0 :coreid 0 is displayed to GDB , #->1 : next resume displays coreid 1 to GDB > resume > cortex_a smp_gdb gdb coreid 1 -> 1 #1 :coreid 1 is displayed to GDB , #->1 : next resume displays coreid 1 to GDB > cortex_a smp_gdb -1 gdb coreid 1 -> -1 #1 :coreid 1 is displayed to GDB, #->-1 : next resume triggers a real resume 6.3.5 Chip Reset Setup ---------------------- As a rule, you should put the 'reset_config' command into the board file. Most things you think you know about a chip can be tweaked by the board. Some chips have specific ways the TRST and SRST signals are managed. In the unusual case that these are _chip specific_ and can never be changed by board wiring, they could go here. For example, some chips can't support JTAG debugging without both signals. Provide a 'reset-assert' event handler if you can. Such a handler uses JTAG operations to reset the target, letting this target config be used in systems which don't provide the optional SRST signal, or on systems where you don't want to reset all targets at once. Such a handler might write to chip registers to force a reset, use a JRC to do that (preferable - the target may be wedged!), or force a watchdog timer to trigger. (For Cortex-M targets, this is not necessary. The target driver knows how to use trigger an NVIC reset when SRST is not available.) Some chips need special attention during reset handling if they're going to be used with JTAG. An example might be needing to send some commands right after the target's TAP has been reset, providing a 'reset-deassert-post' event handler that writes a chip register to report that JTAG debugging is being done. Another would be reconfiguring the watchdog so that it stops counting while the core is halted in the debugger. JTAG clocking constraints often change during reset, and in some cases target config files (rather than board config files) are the right places to handle some of those issues. For example, immediately after reset most chips run using a slower clock than they will use later. That means that after reset (and potentially, as OpenOCD first starts up) they must use a slower JTAG clock rate than they will use later. *Note JTAG Speed: jtagspeed. Important: When you are debugging code that runs right after chip reset, getting these issues right is critical. In particular, if you see intermittent failures when OpenOCD verifies the scan chain after reset, look at how you are setting up JTAG clocking. 6.3.6 The init_targets procedure -------------------------------- Target config files can either be "linear" (script executed line-by-line when parsed in configuration stage, *Note Configuration Stage: configurationstage,) or they can contain a special procedure called 'init_targets', which will be executed when entering run stage (after parsing all config files or after 'init' command, *Note Entering the Run Stage: enteringtherunstage.) Such procedure can be overridden by "next level" script (which sources the original). This concept facilitates code reuse when basic target config files provide generic configuration procedures and 'init_targets' procedure, which can then be sourced and enhanced or changed in a "more specific" target config file. This is not possible with "linear" config scripts, because sourcing them executes every initialization commands they provide. ### generic_file.cfg ### proc setup_my_chip {chip_name flash_size ram_size} { # basic initialization procedure ... } proc init_targets {} { # initializes generic chip with 4kB of flash and 1kB of RAM setup_my_chip MY_GENERIC_CHIP 4096 1024 } ### specific_file.cfg ### source [find target/generic_file.cfg] proc init_targets {} { # initializes specific chip with 128kB of flash and 64kB of RAM setup_my_chip MY_CHIP_WITH_128K_FLASH_64KB_RAM 131072 65536 } The easiest way to convert "linear" config files to 'init_targets' version is to enclose every line of "code" (i.e. not 'source' commands, procedures, etc.) in this procedure. For an example of this scheme see LPC2000 target config files. The 'init_boards' procedure is a similar concept concerning board config files (*Note The init_board procedure: theinitboardprocedure.) 6.3.7 The init_target_events procedure -------------------------------------- A special procedure called 'init_target_events' is run just after 'init_targets' (*Note The init_targets procedure: theinittargetsprocedure.) and before 'init_board' (*Note The init_board procedure: theinitboardprocedure.) It is used to set up default target events for the targets that do not have those events already assigned. 6.3.8 ARM Core Specific Hacks ----------------------------- If the chip has a DCC, enable it. If the chip is an ARM9 with some special high speed download features - enable it. If present, the MMU, the MPU and the CACHE should be disabled. Some ARM cores are equipped with trace support, which permits examination of the instruction and data bus activity. Trace activity is controlled through an "Embedded Trace Module" (ETM) on one of the core's scan chains. The ETM emits voluminous data through a "trace port". (*Note ARM Hardware Tracing: armhardwaretracing.) If you are using an external trace port, configure it in your board config file. If you are using an on-chip "Embedded Trace Buffer" (ETB), configure it in your target config file. etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb 6.3.9 Internal Flash Configuration ---------------------------------- This applies ONLY TO MICROCONTROLLERS that have flash built in. Never ever in the "target configuration file" define any type of flash that is external to the chip. (For example a BOOT flash on Chip Select 0.) Such flash information goes in a board file - not the TARGET (chip) file. Examples: * at91sam7x256 - has 256K flash YES enable it. * str912 - has flash internal YES enable it. * imx27 - uses boot flash on CS0 - it goes in the board file. * pxa270 - again - CS0 flash - it goes in the board file. 6.4 Translating Configuration Files =================================== If you have a configuration file for another hardware debugger or toolset (Abatron, BDI2000, BDI3000, CCS, Lauterbach, SEGGER, Macraigor, etc.), translating it into OpenOCD syntax is often quite straightforward. The most tricky part of creating a configuration script is oftentimes the reset init sequence where e.g. PLLs, DRAM and the like is set up. One trick that you can use when translating is to write small Tcl procedures to translate the syntax into OpenOCD syntax. This can avoid manual translation errors and make it easier to convert other scripts later on. Example of transforming quirky arguments to a simple search and replace job: # Lauterbach syntax(?) # # Data.Set c15:0x042f %long 0x40000015 # # OpenOCD syntax when using procedure below. # # setc15 0x01 0x00050078 proc setc15 {regs value} { global TARGETNAME echo [format "set p15 0x%04x, 0x%08x" $regs $value] arm mcr 15 [expr {($regs >> 12) & 0x7}] \ [expr {($regs >> 0) & 0xf}] [expr {($regs >> 4) & 0xf}] \ [expr {($regs >> 8) & 0x7}] $value } ---------- Footnotes ---------- (1) A FAQ gives details.  File: openocd.info, Node: Server Configuration, Next: Debug Adapter Configuration, Prev: Config File Guidelines, Up: Top 7 Server Configuration ********************** The commands here are commonly found in the openocd.cfg file and are used to specify what TCP/IP ports are used, and how GDB should be supported. 7.1 Configuration Stage ======================= When the OpenOCD server process starts up, it enters a _configuration stage_ which is the only time that certain commands, _configuration commands_, may be issued. Normally, configuration commands are only available inside startup scripts. In this manual, the definition of a configuration command is presented as a _Config Command_, not as a _Command_ which may be issued interactively. The runtime 'help' command also highlights configuration commands, and those which may be issued at any time. Those configuration commands include declaration of TAPs, flash banks, the interface used for JTAG communication, and other basic setup. The server must leave the configuration stage before it may access or activate TAPs. After it leaves this stage, configuration commands may no longer be issued. -- Command: command mode [command_name] Returns the command modes allowed by a command: 'any', 'config', or 'exec'. If no command is specified, returns the current command mode. Returns 'unknown' if an unknown command is given. Command can be multiple tokens. (command valid any time) In this document, the modes are described as stages, 'config' and 'exec' mode correspond configuration stage and run stage. 'any' means the command can be executed in either stages. *Note Configuration Stage: configurationstage, and *Note Entering the Run Stage: enteringtherunstage. 7.2 Entering the Run Stage ========================== The first thing OpenOCD does after leaving the configuration stage is to verify that it can talk to the scan chain (list of TAPs) which has been configured. It will warn if it doesn't find TAPs it expects to find, or finds TAPs that aren't supposed to be there. You should see no errors at this point. If you see errors, resolve them by correcting the commands you used to configure the server. Common errors include using an initial JTAG speed that's too fast, and not providing the right IDCODE values for the TAPs on the scan chain. Once OpenOCD has entered the run stage, a number of commands become available. A number of these relate to the debug targets you may have declared. For example, the 'mww' command will not be available until a target has been successfully instantiated. If you want to use those commands, you may need to force entry to the run stage. -- Config Command: init This command terminates the configuration stage and enters the run stage. This helps when you need to have the startup scripts manage tasks such as resetting the target, programming flash, etc. To reset the CPU upon startup, add "init" and "reset" at the end of the config script or at the end of the OpenOCD command line using the '-c' command line switch. If this command does not appear in any startup/configuration file OpenOCD executes the command for you after processing all configuration files and/or command line options. NOTE: This command normally occurs near the end of your openocd.cfg file to force OpenOCD to "initialize" and make the targets ready. For example: If your openocd.cfg file needs to read/write memory on your target, 'init' must occur before the memory read/write commands. This includes 'nand probe'. 'init' calls the following internal OpenOCD commands to initialize corresponding subsystems: -- Config Command: target init -- Command: transport init -- Command: dap init -- Config Command: flash init -- Config Command: nand init -- Config Command: pld init -- Command: tpiu init At last, 'init' executes all the commands that are specified in the TCL list POST_INIT_COMMANDS. The commands are executed in the same order they occupy in the list. If one of the commands fails, then the error is propagated and OpenOCD fails too. lappend post_init_commands {echo "OpenOCD successfully initialized."} lappend post_init_commands {echo "Have fun with OpenOCD !"} -- Config Command: noinit Prevent OpenOCD from implicit 'init' call at the end of startup. Allows issuing configuration commands over telnet or Tcl connection. When you are done with configuration use 'init' to enter the run stage. -- Overridable Procedure: jtag_init This is invoked at server startup to verify that it can talk to the scan chain (list of TAPs) which has been configured. The default implementation first tries 'jtag arp_init', which uses only a lightweight JTAG reset before examining the scan chain. If that fails, it tries again, using a harder reset from the overridable procedure 'init_reset'. Implementations must have verified the JTAG scan chain before they return. This is done by calling 'jtag arp_init' (or 'jtag arp_init-reset'). 7.3 TCP/IP Ports ================ The OpenOCD server accepts remote commands in several syntaxes. Each syntax uses a different TCP/IP port, which you may specify only during configuration (before those ports are opened). For reasons including security, you may wish to prevent remote access using one or more of these ports. In such cases, just specify the relevant port number as "disabled". If you disable all access through TCP/IP, you will need to use the command line '-pipe' option. -- Config Command: gdb_port [number] Normally gdb listens to a TCP/IP port, but GDB can also communicate via pipes(stdin/out or named pipes). The name "gdb_port" stuck because it covers probably more than 90% of the normal use cases. No arguments reports GDB port. "pipe" means listen to stdin output to stdout, an integer is base port number, "disabled" disables the gdb server. When using "pipe", also use log_output to redirect the log output to a file so as not to flood the stdin/out pipes. Any other string is interpreted as named pipe to listen to. Output pipe is the same name as input pipe, but with 'o' appended, e.g. /var/gdb, /var/gdbo. The GDB port for the first target will be the base port, the second target will listen on gdb_port + 1, and so on. When not specified during the configuration stage, the port NUMBER defaults to 3333. When NUMBER is not a numeric value, incrementing it to compute the next port number does not work. In this case, specify the proper NUMBER for each target by using the option '-gdb-port' of the commands 'target create' or '$target_name configure'. *Note option -gdb-port: gdbportoverride. Note: when using "gdb_port pipe", increasing the default remote timeout in gdb (with 'set remotetimeout') is recommended. An insufficient timeout may cause initialization to fail with "Unknown remote qXfer reply: OK". -- Config Command: tcl_port [number] Specify or query the port used for a simplified RPC connection that can be used by clients to issue TCL commands and get the output from the Tcl engine. Intended as a machine interface. When not specified during the configuration stage, the port NUMBER defaults to 6666. When specified as "disabled", this service is not activated. -- Config Command: telnet_port [number] Specify or query the port on which to listen for incoming telnet connections. This port is intended for interaction with one human through TCL commands. When not specified during the configuration stage, the port NUMBER defaults to 4444. When specified as "disabled", this service is not activated. 7.4 GDB Configuration ===================== You can reconfigure some GDB behaviors if needed. The ones listed here are static and global. *Note Target Configuration: targetconfiguration, about configuring individual targets. *Note Target Events: targetevents, about configuring target-specific event handling. -- Command: gdb_breakpoint_override [hard|soft|disable] Force breakpoint type for gdb 'break' commands. This option supports GDB GUIs which don't distinguish hard versus soft breakpoints, if the default OpenOCD and GDB behaviour is not sufficient. GDB normally uses hardware breakpoints if the memory map has been set up for flash regions. -- Config Command: gdb_flash_program (enable|disable) Set to 'enable' to cause OpenOCD to program the flash memory when a vFlash packet is received. The default behaviour is 'enable'. -- Config Command: gdb_memory_map (enable|disable) Set to 'enable' to cause OpenOCD to send the memory configuration to GDB when requested. GDB will then know when to set hardware breakpoints, and program flash using the GDB load command. 'gdb_flash_program enable' must also be enabled for flash programming to work. Default behaviour is 'enable'. *Note gdb_flash_program: gdbflashprogram. -- Config Command: gdb_report_data_abort (enable|disable) Specifies whether data aborts cause an error to be reported by GDB memory read packets. The default behaviour is 'disable'; use 'enable' see these errors reported. -- Config Command: gdb_report_register_access_error (enable|disable) Specifies whether register accesses requested by GDB register read/write packets report errors or not. The default behaviour is 'disable'; use 'enable' see these errors reported. -- Config Command: gdb_target_description (enable|disable) Set to 'enable' to cause OpenOCD to send the target descriptions to gdb via qXfer:features:read packet. The default behaviour is 'enable'. -- Command: gdb_save_tdesc Saves the target description file to the local file system. The file name is target_name.xml. 7.5 Event Polling ================= Hardware debuggers are parts of asynchronous systems, where significant events can happen at any time. The OpenOCD server needs to detect some of these events, so it can report them to through TCL command line or to GDB. Examples of such events include: * One of the targets can stop running ... maybe it triggers a code breakpoint or data watchpoint, or halts itself. * Messages may be sent over "debug message" channels ... many targets support such messages sent over JTAG, for receipt by the person debugging or tools. * Loss of power ... some adapters can detect these events. * Resets not issued through JTAG ... such reset sources can include button presses or other system hardware, sometimes including the target itself (perhaps through a watchdog). * Debug instrumentation sometimes supports event triggering such as "trace buffer full" (so it can quickly be emptied) or other signals (to correlate with code behavior). None of those events are signaled through standard JTAG signals. However, most conventions for JTAG connectors include voltage level and system reset (SRST) signal detection. Some connectors also include instrumentation signals, which can imply events when those signals are inputs. In general, OpenOCD needs to periodically check for those events, either by looking at the status of signals on the JTAG connector or by sending synchronous "tell me your status" JTAG requests to the various active targets. There is a command to manage and monitor that polling, which is normally done in the background. -- Command: poll [on|off] Poll the current target for its current state. (Also, *note target curstate: targetcurstate.) If that target is in debug mode, architecture specific information about the current state is printed. An optional parameter allows background polling to be enabled and disabled. You could use this from the TCL command shell, or from GDB using 'monitor poll' command. Leave background polling enabled while you're using GDB. > poll background polling: on target state: halted target halted in ARM state due to debug-request, \ current mode: Supervisor cpsr: 0x800000d3 pc: 0x11081bfc MMU: disabled, D-Cache: disabled, I-Cache: enabled >  File: openocd.info, Node: Debug Adapter Configuration, Next: Reset Configuration, Prev: Server Configuration, Up: Top 8 Debug Adapter Configuration ***************************** Correctly installing OpenOCD includes making your operating system give OpenOCD access to debug adapters. Once that has been done, Tcl commands are used to select which one is used, and to configure how it is used. Note: Because OpenOCD started out with a focus purely on JTAG, you may find places where it wrongly presumes JTAG is the only transport protocol in use. Be aware that recent versions of OpenOCD are removing that limitation. JTAG remains more functional than most other transports. Other transports do not support boundary scan operations, or may be specific to a given chip vendor. Some might be usable only for programming flash memory, instead of also for debugging. Debug Adapters/Interfaces/Dongles are normally configured through commands in an interface configuration file which is sourced by your 'openocd.cfg' file, or through a command line '-f interface/....cfg' option. source [find interface/olimex-jtag-tiny.cfg] These commands tell OpenOCD what type of JTAG adapter you have, and how to talk to it. A few cases are so simple that you only need to say what driver to use: # jlink interface adapter driver jlink Most adapters need a bit more configuration than that. 8.1 Adapter Configuration ========================= The 'adapter driver' command tells OpenOCD what type of debug adapter you are using. Depending on the type of adapter, you may need to use one or more additional commands to further identify or configure the adapter. -- Config Command: adapter driver name Use the adapter driver NAME to connect to the target. -- Command: adapter list List the debug adapter drivers that have been built into the running copy of OpenOCD. -- Config Command: adapter transports transport_name+ Specifies the transports supported by this debug adapter. The adapter driver builds-in similar knowledge; use this only when external configuration (such as jumpering) changes what the hardware can support. -- Command: adapter name Returns the name of the debug adapter driver being used. -- Config Command: adapter usb location [-[.]...] Displays or specifies the physical USB port of the adapter to use. The path roots at BUS and walks down the physical ports, with each PORT option specifying a deeper level in the bus topology, the last PORT denoting where the target adapter is actually plugged. The USB bus topology can be queried with the command _lsusb -t_ or _dmesg_. This command is only available if your libusb1 is at least version 1.0.16. -- Config Command: adapter serial serial_string Specifies the SERIAL_STRING of the adapter to use. If this command is not specified, serial strings are not checked. Only the following adapter drivers use the serial string from this command: aice (aice_usb), arm-jtag-ew, cmsis_dap, ft232r, ftdi, hla (stlink, ti-icdi), jlink, kitprog, opendus, openjtag, osbdm, presto, rlink, st-link, usb_blaster (ublast2), usbprog, vsllink, xds110. 8.2 Interface Drivers ===================== Each of the interface drivers listed here must be explicitly enabled when OpenOCD is configured, in order to be made available at run time. -- Interface Driver: amt_jtagaccel Amontec Chameleon in its JTAG Accelerator configuration, connected to a PC's EPP mode parallel port. This defines some driver-specific commands: -- Config Command: parport port number Specifies either the address of the I/O port (default: 0x378 for LPT1) or the number of the '/dev/parport' device. -- Config Command: rtck [enable|disable] Displays status of RTCK option. Optionally sets that option first. -- Interface Driver: arm-jtag-ew Olimex ARM-JTAG-EW USB adapter This has one driver-specific command: -- Command: armjtagew_info Logs some status -- Interface Driver: at91rm9200 Supports bitbanged JTAG from the local system, presuming that system is an Atmel AT91rm9200 and a specific set of GPIOs is used. -- Interface Driver: cmsis-dap ARM CMSIS-DAP compliant based adapter v1 (USB HID based) or v2 (USB bulk). -- Config Command: cmsis_dap_vid_pid [vid pid]+ The vendor ID and product ID of the CMSIS-DAP device. If not specified the driver will attempt to auto detect the CMSIS-DAP device. Currently, up to eight [VID, PID] pairs may be given, e.g. cmsis_dap_vid_pid 0xc251 0xf001 0x0d28 0x0204 -- Config Command: cmsis_dap_backend [auto|usb_bulk|hid] Specifies how to communicate with the adapter: - 'hid' Use HID generic reports - CMSIS-DAP v1 - 'usb_bulk' Use USB bulk - CMSIS-DAP v2 - 'auto' First try USB bulk CMSIS-DAP v2, if not found try HID CMSIS-DAP v1. This is the default if 'cmsis_dap_backend' is not specified. -- Config Command: cmsis_dap_usb interface [number] Specifies the NUMBER of the USB interface to use in v2 mode (USB bulk). In most cases need not to be specified and interfaces are searched by interface string or for user class interface. -- Command: cmsis-dap info Display various device information, like hardware version, firmware version, current bus status. -- Command: cmsis-dap cmd number number ... Execute an arbitrary CMSIS-DAP command. Use for adapter testing or for handling of an adapter vendor specific command from a Tcl script. Take given numbers as bytes, assemble a CMSIS-DAP protocol command packet from them and send it to the adapter. The first 4 bytes of the adapter response are logged. See -- Interface Driver: dummy A dummy software-only driver for debugging. -- Interface Driver: ep93xx Cirrus Logic EP93xx based single-board computer bit-banging (in development) -- Interface Driver: ftdi This driver is for adapters using the MPSSE (Multi-Protocol Synchronous Serial Engine) mode built into many FTDI chips, such as the FT2232, FT4232 and FT232H. The driver is using libusb-1.0 in asynchronous mode to talk to the FTDI device, bypassing intermediate libraries like libftdi. Support for new FTDI based adapters can be added completely through configuration files, without the need to patch and rebuild OpenOCD. The driver uses a signal abstraction to enable Tcl configuration files to define outputs for one or several FTDI GPIO. These outputs can then be controlled using the 'ftdi set_signal' command. Special signal names are reserved for nTRST, nSRST and LED (for blink) so that they, if defined, will be used for their customary purpose. Inputs can be read using the 'ftdi get_signal' command. To support SWD, a signal named SWD_EN must be defined. It is set to 1 when the SWD protocol is selected. When set, the adapter should route the SWDIO pin to the data input. An SWDIO_OE signal, if defined, will be set to 1 or 0 as required by the protocol, to tell the adapter to drive the data output onto the SWDIO pin or keep the SWDIO pin Hi-Z, respectively. Depending on the type of buffer attached to the FTDI GPIO, the outputs have to be controlled differently. In order to support tristateable signals such as nSRST, both a data GPIO and an output-enable GPIO can be specified for each signal. The following output buffer configurations are supported: - Push-pull with one FTDI output as (non-)inverted data line - Open drain with one FTDI output as (non-)inverted output-enable - Tristate with one FTDI output as (non-)inverted data line and another FTDI output as (non-)inverted output-enable - Unbuffered, using the FTDI GPIO as a tristate output directly by switching data and direction as necessary These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: -- Config Command: ftdi vid_pid [vid pid]+ The vendor ID and product ID of the adapter. Up to eight [VID, PID] pairs may be given, e.g. ftdi vid_pid 0x0403 0xcff8 0x15ba 0x0003 -- Config Command: ftdi device_desc description Provides the USB device description (the _iProduct string_) of the adapter. If not specified, the device description is ignored during device selection. -- Config Command: ftdi channel channel Selects the channel of the FTDI device to use for MPSSE operations. Most adapters use the default, channel 0, but there are exceptions. -- Config Command: ftdi layout_init data direction Specifies the initial values of the FTDI GPIO data and direction registers. Each value is a 16-bit number corresponding to the concatenation of the high and low FTDI GPIO registers. The values should be selected based on the schematics of the adapter, such that all signals are set to safe levels with minimal impact on the target system. Avoid floating inputs, conflicting outputs and initially asserted reset signals. -- Command: ftdi layout_signal name [-data|-ndata data_mask] [-input|-ninput input_mask] [-oe|-noe oe_mask] [-alias|-nalias name] Creates a signal with the specified NAME, controlled by one or more FTDI GPIO pins via a range of possible buffer connections. The masks are FTDI GPIO register bitmasks to tell the driver the connection and type of the output buffer driving the respective signal. DATA_MASK is the bitmask for the pin(s) connected to the data input of the output buffer. '-ndata' is used with inverting data inputs and '-data' with non-inverting inputs. The '-oe' (or '-noe') option tells where the output-enable (or not-output-enable) input to the output buffer is connected. The options '-input' and '-ninput' specify the bitmask for pins to be read with the method 'ftdi get_signal'. Both DATA_MASK and OE_MASK need not be specified. For example, a simple open-collector transistor driver would be specified with '-oe' only. In that case the signal can only be set to drive low or to Hi-Z and the driver will complain if the signal is set to drive high. Which means that if it's a reset signal, 'reset_config' must be specified as 'srst_open_drain', not 'srst_push_pull'. A special case is provided when '-data' and '-oe' is set to the same bitmask. Then the FTDI pin is considered being connected straight to the target without any buffer. The FTDI pin is then switched between output and input as necessary to provide the full set of low, high and Hi-Z characteristics. In all other cases, the pins specified in a signal definition are always driven by the FTDI. If '-alias' or '-nalias' is used, the signal is created identical (or with data inverted) to an already specified signal NAME. -- Command: ftdi set_signal name 0|1|z Set a previously defined signal to the specified level. - '0', drive low - '1', drive high - 'z', set to high-impedance -- Command: ftdi get_signal name Get the value of a previously defined signal. -- Command: ftdi tdo_sample_edge rising|falling Configure TCK edge at which the adapter samples the value of the TDO signal Due to signal propagation delays, sampling TDO on rising TCK can become quite peculiar at high JTAG clock speeds. However, FTDI chips offer a possibility to sample TDO on falling edge of TCK. With some board/adapter configurations, this may increase stability at higher JTAG clocks. - 'rising', sample TDO on rising edge of TCK - this is the default - 'falling', sample TDO on falling edge of TCK For example adapter definitions, see the configuration files shipped in the 'interface/ftdi' directory. -- Interface Driver: ft232r This driver is implementing synchronous bitbang mode of an FTDI FT232R, FT230X, FT231X and similar USB UART bridge ICs by reusing RS232 signals as GPIO. It currently doesn't support using CBUS pins as GPIO. List of connections (default physical pin numbers for FT232R in 28-pin SSOP package): - RXD(5) - TDI - TXD(1) - TCK - RTS(3) - TDO - CTS(11) - TMS - DTR(2) - TRST - DCD(10) - SRST User can change default pinout by supplying configuration commands with GPIO numbers or RS232 signal names. GPIO numbers correspond to bit numbers in FTDI GPIO register. They differ from physical pin numbers. For details see actual FTDI chip datasheets. Every JTAG line must be configured to unique GPIO number different than any other JTAG line, even those lines that are sometimes not used like TRST or SRST. FT232R - bit 7 - RI - bit 6 - DCD - bit 5 - DSR - bit 4 - DTR - bit 3 - CTS - bit 2 - RTS - bit 1 - RXD - bit 0 - TXD These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: -- Config Command: ft232r vid_pid VID PID The vendor ID and product ID of the adapter. If not specified, default 0x0403:0x6001 is used. -- Config Command: ft232r jtag_nums TCK TMS TDI TDO Set four JTAG GPIO numbers at once. If not specified, default 0 3 1 2 or TXD CTS RXD RTS is used. -- Config Command: ft232r tck_num TCK Set TCK GPIO number. If not specified, default 0 or TXD is used. -- Config Command: ft232r tms_num TMS Set TMS GPIO number. If not specified, default 3 or CTS is used. -- Config Command: ft232r tdi_num TDI Set TDI GPIO number. If not specified, default 1 or RXD is used. -- Config Command: ft232r tdo_num TDO Set TDO GPIO number. If not specified, default 2 or RTS is used. -- Config Command: ft232r trst_num TRST Set TRST GPIO number. If not specified, default 4 or DTR is used. -- Config Command: ft232r srst_num SRST Set SRST GPIO number. If not specified, default 6 or DCD is used. -- Config Command: ft232r restore_serial WORD Restore serial port after JTAG. This USB bitmode control word (16-bit) will be sent before quit. Lower byte should set GPIO direction register to a "sane" state: 0x15 for TXD RTS DTR as outputs (1), others as inputs (0). Higher byte is usually 0 to disable bitbang mode. When kernel driver reattaches, serial port should continue to work. Value 0xFFFF disables sending control word and serial port, then kernel driver will not reattach. If not specified, default 0xFFFF is used. -- Interface Driver: remote_bitbang Drive JTAG from a remote process. This sets up a UNIX or TCP socket connection with a remote process and sends ASCII encoded bitbang requests to that process instead of directly driving JTAG. The remote_bitbang driver is useful for debugging software running on processors which are being simulated. -- Config Command: remote_bitbang port number Specifies the TCP port of the remote process to connect to or 0 to use UNIX sockets instead of TCP. -- Config Command: remote_bitbang host hostname Specifies the hostname of the remote process to connect to using TCP, or the name of the UNIX socket to use if remote_bitbang port is 0. For example, to connect remotely via TCP to the host foobar you might have something like: adapter driver remote_bitbang remote_bitbang port 3335 remote_bitbang host foobar To connect to another process running locally via UNIX sockets with socket named mysocket: adapter driver remote_bitbang remote_bitbang port 0 remote_bitbang host mysocket -- Interface Driver: usb_blaster USB JTAG/USB-Blaster compatibles over one of the userspace libraries for FTDI chips. These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: -- Config Command: usb_blaster vid_pid vid pid The vendor ID and product ID of the FTDI FT245 device. If not specified, default values are used. Currently, only one VID, PID pair may be given, e.g. for Altera USB-Blaster (default): usb_blaster vid_pid 0x09FB 0x6001 The following VID/PID is for Kolja Waschk's USB JTAG: usb_blaster vid_pid 0x16C0 0x06AD -- Command: usb_blaster pin (pin6|pin8) (0|1|s|t) Sets the state or function of the unused GPIO pins on USB-Blasters (pins 6 and 8 on the female JTAG header). These pins can be used as SRST and/or TRST provided the appropriate connections are made on the target board. For example, to use pin 6 as SRST: usb_blaster pin pin6 s reset_config srst_only -- Config Command: usb_blaster lowlevel_driver (ftdi|ublast2) Chooses the low level access method for the adapter. If not specified, 'ftdi' is selected unless it wasn't enabled during the configure stage. USB-Blaster II needs 'ublast2'. -- Config Command: usb_blaster firmware PATH This command specifies PATH to access USB-Blaster II firmware image. To be used with USB-Blaster II only. -- Interface Driver: gw16012 Gateworks GW16012 JTAG programmer. This has one driver-specific command: -- Config Command: parport port [port_number] Display either the address of the I/O port (default: 0x378 for LPT1) or the number of the '/dev/parport' device. If a parameter is provided, first switch to use that port. This is a write-once setting. -- Interface Driver: jlink SEGGER J-Link family of USB adapters. It currently supports JTAG and SWD transports. Compatibility Note: SEGGER released many firmware versions for the many hardware versions they produced. OpenOCD was extensively tested and intended to run on all of them, but some combinations were reported as incompatible. As a general recommendation, it is advisable to use the latest firmware version available for each hardware version. However the current V8 is a moving target, and SEGGER firmware versions released after the OpenOCD was released may not be compatible. In such cases it is recommended to revert to the last known functional version. For 0.5.0, this is from "Feb 8 2012 14:30:39", packed with 4.42c. For 0.6.0, the last known version is from "May 3 2012 18:36:22", packed with 4.46f. -- Command: jlink hwstatus Display various hardware related information, for example target voltage and pin states. -- Command: jlink freemem Display free device internal memory. -- Command: jlink jtag [2|3] Set the JTAG command version to be used. Without argument, show the actual JTAG command version. -- Command: jlink config Display the device configuration. -- Command: jlink config targetpower [on|off] Set the target power state on JTAG-pin 19. Without argument, show the target power state. -- Command: jlink config mac [ff:ff:ff:ff:ff:ff] Set the MAC address of the device. Without argument, show the MAC address. -- Command: jlink config ip [A.B.C.D(/E|F.G.H.I)] Set the IP configuration of the device, where A.B.C.D is the IP address, E the bit of the subnet mask and F.G.H.I the subnet mask. Without arguments, show the IP configuration. -- Command: jlink config usb [0 to 3] Set the USB address of the device. This will also change the USB Product ID (PID) of the device. Without argument, show the USB address. -- Command: jlink config reset Reset the current configuration. -- Command: jlink config write Write the current configuration to the internal persistent storage. -- Command: jlink emucom write Write data to an EMUCOM channel. The data needs to be encoded as hexadecimal pairs. The following example shows how to write the three bytes 0xaa, 0x0b and 0x23 to the EMUCOM channel 0x10: > jlink emucom write 0x10 aa0b23 -- Command: jlink emucom read Read data from an EMUCOM channel. The read data is encoded as hexadecimal pairs. The following example shows how to read 4 bytes from the EMUCOM channel 0x0: > jlink emucom read 0x0 4 77a90000 -- Config Command: jlink usb <0 to 3> Set the USB address of the interface, in case more than one adapter is connected to the host. If not specified, USB addresses are not considered. Device selection via USB address is not always unambiguous. It is recommended to use the serial number instead, if possible. As a configuration command, it can be used only before 'init'. -- Interface Driver: kitprog This driver is for Cypress Semiconductor's KitProg adapters. The KitProg is an SWD-only adapter that is designed to be used with Cypress's PSoC and PRoC device families, but it is possible to use it with some other devices. If you are using this adapter with a PSoC or a PRoC, you may need to add 'kitprog_init_acquire_psoc' or 'kitprog acquire_psoc' to your configuration script. Note that this driver is for the proprietary KitProg protocol, not the CMSIS-DAP mode introduced in firmware 2.14. If the KitProg is in CMSIS-DAP mode, it cannot be used with this driver, and must either be used with the cmsis-dap driver or switched back to KitProg mode. See the Cypress KitProg User Guide for instructions on how to switch KitProg modes. Known limitations: * The frequency of SWCLK cannot be configured, and varies between 1.6 MHz and 2.7 MHz. * For firmware versions below 2.14, "JTAG to SWD" sequences are replaced by "SWD line reset" in the driver. This is for two reasons. First, the KitProg does not support sending arbitrary SWD sequences, and only firmware 2.14 and later implement both "JTAG to SWD" and "SWD line reset" in firmware. Earlier firmware versions only implement "SWD line reset". Second, due to a firmware quirk, an SWD sequence must be sent after every target reset in order to re-establish communications with the target. * Due in part to the limitation above, KitProg devices with firmware below version 2.14 will need to use 'kitprog_init_acquire_psoc' in order to communicate with PSoC 5LP devices. This is because, assuming debug is not disabled on the PSoC, the PSoC 5LP needs its JTAG interface switched to SWD mode before communication can begin, but prior to firmware 2.14, "JTAG to SWD" could only be sent with an acquisition sequence. -- Config Command: kitprog_init_acquire_psoc Indicate that a PSoC acquisition sequence needs to be run during adapter init. Please be aware that the acquisition sequence hard-resets the target. -- Command: kitprog acquire_psoc Run a PSoC acquisition sequence immediately. Typically, this should not be used outside of the target-specific configuration scripts since it hard-resets the target as a side-effect. This is necessary for "reset halt" on some PSoC 4 series devices. -- Command: kitprog info Display various adapter information, such as the hardware version, firmware version, and target voltage. -- Interface Driver: parport Supports PC parallel port bit-banging cables: Wigglers, PLD download cable, and more. These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: -- Config Command: parport cable name Set the layout of the parallel port cable used to connect to the target. This is a write-once setting. Currently valid cable NAME values include: - altium Altium Universal JTAG cable. - arm-jtag Same as original wiggler except SRST and TRST connections reversed and TRST is also inverted. - chameleon The Amontec Chameleon's CPLD when operated in configuration mode. This is only used to program the Chameleon itself, not a connected target. - dlc5 The Xilinx Parallel cable III. - flashlink The ST Parallel cable. - lattice Lattice ispDOWNLOAD Cable - old_amt_wiggler The Wiggler configuration that comes with some versions of Amontec's Chameleon Programmer. The new version available from the website uses the original Wiggler layout ('WIGGLER') - triton The parallel port adapter found on the "Karo Triton 1 Development Board". This is also the layout used by the HollyGates design (see ). - wiggler The original Wiggler layout, also supported by several clones, such as the Olimex ARM-JTAG - wiggler2 Same as original wiggler except an led is fitted on D5. - wiggler_ntrst_inverted Same as original wiggler except TRST is inverted. -- Config Command: parport port [port_number] Display either the address of the I/O port (default: 0x378 for LPT1) or the number of the '/dev/parport' device. If a parameter is provided, first switch to use that port. This is a write-once setting. When using PPDEV to access the parallel port, use the number of the parallel port: 'parport port 0' (the default). If 'parport port 0x378' is specified you may encounter a problem. -- Config Command: parport toggling_time [nanoseconds] Displays how many nanoseconds the hardware needs to toggle TCK; the parport driver uses this value to obey the 'adapter speed' configuration. When the optional NANOSECONDS parameter is given, that setting is changed before displaying the current value. The default setting should work reasonably well on commodity PC hardware. However, you may want to calibrate for your specific hardware. Tip: To measure the toggling time with a logic analyzer or a digital storage oscilloscope, follow the procedure below: > parport toggling_time 1000 > adapter speed 500 This sets the maximum JTAG clock speed of the hardware, but the actual speed probably deviates from the requested 500 kHz. Now, measure the time between the two closest spaced TCK transitions. You can use 'runtest 1000' or something similar to generate a large set of samples. Update the setting to match your measurement: > parport toggling_time Now the clock speed will be a better match for 'adapter speed' command given in OpenOCD scripts and event handlers. You can do something similar with many digital multimeters, but note that you'll probably need to run the clock continuously for several seconds before it decides what clock rate to show. Adjust the toggling time up or down until the measured clock rate is a good match with the rate you specified in the 'adapter speed' command; be conservative. -- Config Command: parport write_on_exit (on|off) This will configure the parallel driver to write a known cable-specific value to the parallel interface on exiting OpenOCD. For example, the interface configuration file for a classic "Wiggler" cable on LPT2 might look something like this: adapter driver parport parport port 0x278 parport cable wiggler -- Interface Driver: presto ASIX PRESTO USB JTAG programmer. -- Interface Driver: rlink Raisonance RLink USB adapter -- Interface Driver: usbprog usbprog is a freely programmable USB adapter. -- Interface Driver: vsllink vsllink is part of Versaloon which is a versatile USB programmer. Note: This defines quite a few driver-specific commands, which are not currently documented here. -- Interface Driver: hla This is a driver that supports multiple High Level Adapters. This type of adapter does not expose some of the lower level api's that OpenOCD would normally use to access the target. Currently supported adapters include the STMicroelectronics ST-LINK, TI ICDI and Nuvoton Nu-Link. ST-LINK firmware version >= V2.J21.S4 recommended due to issues with earlier versions of firmware where serial number is reset after first use. Suggest using ST firmware update utility to upgrade ST-LINK firmware even if current version reported is V2.J21.S4. -- Config Command: hla_device_desc description Currently Not Supported. -- Config Command: hla_layout (stlink|icdi|nulink) Specifies the adapter layout to use. -- Config Command: hla_vid_pid [vid pid]+ Pairs of vendor IDs and product IDs of the device. -- Config Command: hla_stlink_backend (usb | tcp [port]) _ST-Link only:_ Choose between 'exclusive' USB communication (the default backend) or 'shared' mode using ST-Link TCP server (the default port is 7184). _Note:_ ST-Link TCP server is a binary application provided by ST available from ST-LINK server software module (https://www.st.com/en/development-tools/st-link-server.html). -- Command: hla_command command Execute a custom adapter-specific command. The COMMAND string is passed as is to the underlying adapter layout handler. -- Interface Driver: st-link This is a driver that supports STMicroelectronics adapters ST-LINK/V2 (from firmware V2J24) and STLINK-V3, thanks to a new API that provides directly access the arm ADIv5 DAP. The new API provide access to multiple AP on the same DAP, but the maximum number of the AP port is limited by the specific firmware version (e.g. firmware V2J29 has 3 as maximum AP number, while V2J32 has 8). An error is returned for any AP number above the maximum allowed value. _Note:_ Either these same adapters and their older versions are also supported by *note the hla interface driver: hla_interface. -- Config Command: st-link backend (usb | tcp [port]) Choose between 'exclusive' USB communication (the default backend) or 'shared' mode using ST-Link TCP server (the default port is 7184). _Note:_ ST-Link TCP server is a binary application provided by ST available from ST-LINK server software module (https://www.st.com/en/development-tools/st-link-server.html). _Note:_ ST-Link TCP server does not support the SWIM transport. -- Config Command: st-link vid_pid [vid pid]+ Pairs of vendor IDs and product IDs of the device. -- Command: st-link cmd rx_n (tx_byte)+ Sends an arbitrary command composed by the sequence of bytes TX_BYTE and receives RX_N bytes. For example, the command to read the target's supply voltage is one byte 0xf7 followed by 15 bytes zero. It returns 8 bytes, where the first 4 bytes represent the ADC sampling of the reference voltage 1.2V and the last 4 bytes represent the ADC sampling of half the target's supply voltage. > st-link cmd 8 0xf7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0xf1 0x05 0x00 0x00 0x0b 0x08 0x00 0x00 The result can be converted to Volts (ignoring the most significant bytes, always zero) > set a [st-link cmd 8 0xf7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] > set n [expr {[lindex $a 4] + 256 * [lindex $a 5]}] > set d [expr {[lindex $a 0] + 256 * [lindex $a 1]}] > echo [expr {2 * 1.2 * $n / $d}] 3.24891518738 -- Interface Driver: opendous opendous-jtag is a freely programmable USB adapter. -- Interface Driver: ulink This is the Keil ULINK v1 JTAG debugger. -- Interface Driver: xds110 The XDS110 is included as the embedded debug probe on many Texas Instruments LaunchPad evaluation boards. The XDS110 is also available as a stand-alone USB debug probe with the added capability to supply power to the target board. The following commands are supported by the XDS110 driver: -- Config Command: xds110 supply voltage_in_millivolts Available only on the XDS110 stand-alone probe. Sets the voltage level of the XDS110 power supply. A value of 0 leaves the supply off. Otherwise, the supply can be set to any value in the range 1800 to 3600 millivolts. -- Command: xds110 info Displays information about the connected XDS110 debug probe (e.g. firmware version). -- Interface Driver: xlnx_pcie_xvc This driver supports the Xilinx Virtual Cable (XVC) over PCI Express. It is commonly found in Xilinx based PCI Express designs. It allows debugging fabric based JTAG/SWD devices such as Cortex-M1/M3 microcontrollers. Access to this is exposed via extended capability registers in the PCI Express configuration space. For more information see Xilinx PG245 (Section on From_PCIE_to_JTAG mode). -- Config Command: xlnx_pcie_xvc config device Specifies the PCI Express device via parameter DEVICE to use. The correct value for DEVICE can be obtained by looking at the output of lscpi -D (first column) for the corresponding device. The string will be of the format "DDDD:BB:SS.F" such as "0000:65:00.1". -- Interface Driver: bcm2835gpio This SoC is present in Raspberry Pi which is a cheap single-board computer exposing some GPIOs on its expansion header. The driver accesses memory-mapped GPIO peripheral registers directly for maximum performance, but the only possible race condition is for the pins' modes/muxing (which is highly unlikely), so it should be able to coexist nicely with both sysfs bitbanging and various peripherals' kernel drivers. The driver restores the previous configuration on exit. GPIO numbers >= 32 can't be used for performance reasons. See 'interface/raspberrypi-native.cfg' for a sample config and pinout. -- Config Command: bcm2835gpio jtag_nums TCK TMS TDI TDO Set JTAG transport GPIO numbers for TCK, TMS, TDI, and TDO (in that order). Must be specified to enable JTAG transport. These pins can also be specified individually. -- Config Command: bcm2835gpio tck_num TCK Set TCK GPIO number. Must be specified to enable JTAG transport. Can also be specified using the configuration command 'bcm2835gpio jtag_nums'. -- Config Command: bcm2835gpio tms_num TMS Set TMS GPIO number. Must be specified to enable JTAG transport. Can also be specified using the configuration command 'bcm2835gpio jtag_nums'. -- Config Command: bcm2835gpio tdo_num TDO Set TDO GPIO number. Must be specified to enable JTAG transport. Can also be specified using the configuration command 'bcm2835gpio jtag_nums'. -- Config Command: bcm2835gpio tdi_num TDI Set TDI GPIO number. Must be specified to enable JTAG transport. Can also be specified using the configuration command 'bcm2835gpio jtag_nums'. -- Config Command: bcm2835gpio swd_nums SWCLK SWDIO Set SWD transport GPIO numbers for SWCLK and SWDIO (in that order). Must be specified to enable SWD transport. These pins can also be specified individually. -- Config Command: bcm2835gpio swclk_num SWCLK Set SWCLK GPIO number. Must be specified to enable SWD transport. Can also be specified using the configuration command 'bcm2835gpio swd_nums'. -- Config Command: bcm2835gpio swdio_num SWDIO Set SWDIO GPIO number. Must be specified to enable SWD transport. Can also be specified using the configuration command 'bcm2835gpio swd_nums'. -- Config Command: bcm2835gpio swdio_dir_num SWDIO DIR Set SWDIO direction control pin GPIO number. If specified, this pin can be used to control the direction of an external buffer on the SWDIO pin (set=output mode, clear=input mode). If not specified, this feature is disabled. -- Config Command: bcm2835gpio srst_num SRST Set SRST GPIO number. Must be specified to enable SRST. -- Config Command: bcm2835gpio trst_num TRST Set TRST GPIO number. Must be specified to enable TRST. -- Config Command: bcm2835gpio speed_coeffs SPEED_COEFF SPEED_OFFSET Set SPEED_COEFF and SPEED_OFFSET for delay calculations. If unspecified, speed_coeff defaults to 113714, and speed_offset defaults to 28. -- Config Command: bcm2835gpio peripheral_base BASE Set the peripheral base register address to access GPIOs. For the RPi1, use 0x20000000. For RPi2 and RPi3, use 0x3F000000. For RPi4, use 0xFE000000. A full list can be found in the official guide (https://www.raspberrypi.org/documentation/hardware/raspberrypi/peripheral_addresses.md). -- Interface Driver: imx_gpio i.MX SoC is present in many community boards. Wandboard is an example of the one which is most popular. This driver is mostly the same as bcm2835gpio. See 'interface/imx-native.cfg' for a sample config and pinout. -- Interface Driver: am335xgpio The AM335x SoC is present in BeagleBone Black and BeagleBone Green single-board computers which expose some of the GPIOs on the two expansion headers. For maximum performance the driver accesses memory-mapped GPIO peripheral registers directly. The memory mapping requires read and write permission to kernel memory; if /dev/gpiomem exists it will be used, otherwise /dev/mem will be used. The driver restores the GPIO state on exit. All four GPIO ports are available. GPIOs numbered 0 to 31 are mapped to GPIO port 0, GPIO numbers 32 to 63 are mapped to GPIO port 1 and so on. See 'interface/beaglebone-swd-native.cfg' for a sample configuration file. -- Config Command: am335xgpio jtag_nums TCK TMS TDI TDO Set JTAG transport GPIO numbers for TCK, TMS, TDI, and TDO (in that order). Must be specified to enable JTAG transport. These pins can also be specified individually. -- Config Command: am335xgpio tck_num TCK Set TCK GPIO number. Must be specified to enable JTAG transport. Can also be specified using the configuration command 'am335xgpio jtag_nums'. -- Config Command: am335xgpio tms_num TMS Set TMS GPIO number. Must be specified to enable JTAG transport. Can also be specified using the configuration command 'am335xgpio jtag_nums'. -- Config Command: am335xgpio tdo_num TDO Set TDO GPIO number. Must be specified to enable JTAG transport. Can also be specified using the configuration command 'am335xgpio jtag_nums'. -- Config Command: am335xgpio tdi_num TDI Set TDI GPIO number. Must be specified to enable JTAG transport. Can also be specified using the configuration command 'am335xgpio jtag_nums'. -- Config Command: am335xgpio swd_nums SWCLK SWDIO Set SWD transport GPIO numbers for SWCLK and SWDIO (in that order). Must be specified to enable SWD transport. These pins can also be specified individually. -- Config Command: am335xgpio swclk_num SWCLK Set SWCLK GPIO number. Must be specified to enable SWD transport. Can also be specified using the configuration command 'am335xgpio swd_nums'. -- Config Command: am335xgpio swdio_num SWDIO Set SWDIO GPIO number. Must be specified to enable SWD transport. Can also be specified using the configuration command 'am335xgpio swd_nums'. -- Config Command: am335xgpio swdio_dir_num SWDIO_DIR Set SWDIO direction control pin GPIO number. If specified, this pin can be used to control the direction of an external buffer on the SWDIO pin. The direction control state can be set with the command 'am335xgpio swdio_dir_output_state'. If not specified this feature is disabled. -- Config Command: am335xgpio swdio_dir_output_state OUTPUT_STATE Set the state required for an external SWDIO buffer to be an output. Valid values are 'on' (default) and 'off'. -- Config Command: am335xgpio srst_num SRST Set SRST GPIO number. Must be specified to enable SRST. -- Config Command: am335xgpio trst_num TRST Set TRST GPIO number. Must be specified to enable TRST. -- Config Command: am335xgpio led_num LED Set activity LED GPIO number. If not specified an activity LED is not enabled. -- Config Command: am335xgpio led_on_state ON_STATE Set required logic level for the LED to be on. Valid values are 'on' (default) and 'off'. -- Config Command: am335xgpio speed_coeffs SPEED_COEFF SPEED_OFFSET Set SPEED_COEFF and SPEED_OFFSET for delay calculations. If unspecified speed_coeff defaults to 600000 and speed_offset defaults to 575. -- Interface Driver: linuxgpiod Linux provides userspace access to GPIO through libgpiod since Linux kernel version v4.6. The driver emulates either JTAG or SWD transport through bitbanging. See 'interface/dln-2-gpiod.cfg' for a sample config. -- Config Command: linuxgpiod gpiochip CHIP Set the GPIO chip number for all GPIOs used by linuxgpiod. If GPIOs use different GPIO chips then the individual GPIO configuration commands (i.e., not 'linuxgpiod jtag_nums' or 'linuxgpiod swd_nums') can be used to set chip numbers independently for each GPIO. -- Config Command: linuxgpiod jtag_nums TCK TMS TDI TDO Set JTAG transport GPIO numbers for TCK, TMS, TDI, and TDO (in that order). Must be specified to enable JTAG transport. These pins can also be specified individually. -- Config Command: linuxgpiod tck_num [CHIP] TCK Set TCK GPIO number, and optionally TCK chip number. Must be specified to enable JTAG transport. Can also be specified using the configuration command 'linuxgpiod jtag_nums'. -- Config Command: linuxgpiod tms_num [CHIP] TMS Set TMS GPIO number, and optionally TMS chip number. Must be specified to enable JTAG transport. Can also be specified using the configuration command 'linuxgpiod jtag_nums'. -- Config Command: linuxgpiod tdo_num [CHIP] TDO Set TDO GPIO number, and optionally TDO chip number. Must be specified to enable JTAG transport. Can also be specified using the configuration command 'linuxgpiod jtag_nums'. -- Config Command: linuxgpiod tdi_num [CHIP] TDI Set TDI GPIO number, and optionally TDI chip number. Must be specified to enable JTAG transport. Can also be specified using the configuration command 'linuxgpiod jtag_nums'. -- Config Command: linuxgpiod trst_num [CHIP] TRST Set TRST GPIO number, and optionally TRST chip number. Must be specified to enable TRST. -- Config Command: linuxgpiod swd_nums SWCLK SWDIO Set SWD transport GPIO numbers for SWCLK and SWDIO (in that order). Must be specified to enable SWD transport. These pins can also be specified individually. -- Config Command: linuxgpiod swclk_num [CHIP] SWCLK Set SWCLK GPIO number, and optionally SWCLK chip number. Must be specified to enable SWD transport. Can also be specified using the configuration command 'linuxgpiod swd_nums'. -- Config Command: linuxgpiod swdio_num [CHIP] SWDIO Set SWDIO GPIO number, and optionally SWDIO chip number. Must be specified to enable SWD transport. Can also be specified using the configuration command 'linuxgpiod swd_nums'. -- Config Command: linuxgpiod swdio_dir_num [CHIP] SWDIO_DIR Set SWDIO direction control GPIO number, and optionally SWDIO direction control chip number. If specified, this GPIO can be used to control the direction of an external buffer connected to the SWDIO GPIO (set=output mode, clear=input mode). -- Config Command: linuxgpiod srst_num [CHIP] SRST Set SRST GPIO number, and optionally SRST chip number. Must be specified to enable SRST. -- Config Command: linuxgpiod led_num [CHIP] LED Set activity LED GPIO number, and optionally activity LED chip number. If not specified an activity LED is not enabled. -- Interface Driver: sysfsgpio Linux legacy userspace access to GPIO through sysfs is deprecated from Linux kernel version v5.3. Prefer using linuxgpiod, instead. See 'interface/sysfsgpio-raspberrypi.cfg' for a sample config. -- Interface Driver: openjtag OpenJTAG compatible USB adapter. This defines some driver-specific commands: -- Config Command: openjtag variant variant Specifies the variant of the OpenJTAG adapter (see ). Currently valid VARIANT values include: - standard Standard variant (default). - cy7c65215 Cypress CY7C65215 Dual Channel USB-Serial Bridge Controller (see ). -- Config Command: openjtag device_desc string The USB device description string of the adapter. This value is only used with the standard variant. -- Interface Driver: vdebug Cadence Virtual Debug Interface driver. -- Config Command: vdebug server host:port Specifies the host and TCP port number where the vdebug server runs. -- Config Command: vdebug batching value Specifies the batching method for the vdebug request. Possible values are 0 for no batching 1 or wr to batch write transactions together (default) 2 or rw to batch both read and write transactions -- Config Command: vdebug polling min max Takes two values, representing the polling interval in ms. Lower values mean faster debugger responsiveness, but lower emulation performance. The minimum should be around 10, maximum should not exceed 1000, which is the default gdb and keepalive timeout value. -- Config Command: vdebug bfm_path path clk_period Specifies the hierarchical path and input clk period of the vdebug BFM in the design. The hierarchical path uses Verilog notation top.inst.inst The clock period must include the unit, for instance 40ns. -- Config Command: vdebug mem_path path base size Specifies the hierarchical path to the design memory instance for backdoor access. Up to 4 memories can be specified. The hierarchical path uses Verilog notation. The base specifies start address in the design address space, size its size in bytes. Both values can use hexadecimal notation with prefix 0x. -- Interface Driver: jtag_dpi SystemVerilog Direct Programming Interface (DPI) compatible driver for JTAG devices in emulation. The driver acts as a client for the SystemVerilog DPI server interface. -- Config Command: jtag_dpi set_port port Specifies the TCP/IP port number of the SystemVerilog DPI server interface. -- Config Command: jtag_dpi set_address address Specifies the TCP/IP address of the SystemVerilog DPI server interface. -- Interface Driver: buspirate This driver is for the Bus Pirate (see ) and compatible devices. It uses a simple data protocol over a serial port connection. Most hardware development boards have a UART, a real serial port, or a virtual USB serial device, so this driver allows you to start building your own JTAG adapter without the complexity of a custom USB connection. -- Config Command: buspirate port serial_port Specify the serial port's filename. For example: buspirate port /dev/ttyUSB0 -- Config Command: buspirate speed (normal|fast) Set the communication speed to 115k (normal) or 1M (fast). For example: buspirate speed normal -- Config Command: buspirate mode (normal|open-drain) Set the Bus Pirate output mode. - In normal mode (push/pull), do not enable the pull-ups, and do not connect I/O header pin VPU to JTAG VREF. - In open drain mode, you will then need to enable the pull-ups. For example: buspirate mode normal -- Config Command: buspirate pullup (0|1) Whether to connect (1) or not (0) the I/O header pin VPU (JTAG VREF) to the pull-up/pull-down resistors on MOSI (JTAG TDI), CLK (JTAG TCK), MISO (JTAG TDO) and CS (JTAG TMS). For example: buspirate pullup 0 -- Config Command: buspirate vreg (0|1) Whether to enable (1) or disable (0) the built-in voltage regulator, which can be used to supply power to a test circuit through I/O header pins +3V3 and +5V. For example: buspirate vreg 0 -- Command: buspirate led (0|1) Turns the Bus Pirate's LED on (1) or off (0). For example: buspirate led 1 8.3 Transport Configuration =========================== As noted earlier, depending on the version of OpenOCD you use, and the debug adapter you are using, several transports may be available to communicate with debug targets (or perhaps to program flash memory). -- Command: transport list displays the names of the transports supported by this version of OpenOCD. -- Command: transport select transport_name Select which of the supported transports to use in this OpenOCD session. When invoked with 'transport_name', attempts to select the named transport. The transport must be supported by the debug adapter hardware and by the version of OpenOCD you are using (including the adapter's driver). If no transport has been selected and no 'transport_name' is provided, 'transport select' auto-selects the first transport supported by the debug adapter. 'transport select' always returns the name of the session's selected transport, if any. 8.3.1 JTAG Transport -------------------- JTAG is the original transport supported by OpenOCD, and most of the OpenOCD commands support it. JTAG transports expose a chain of one or more Test Access Points (TAPs), each of which must be explicitly declared. JTAG supports both debugging and boundary scan testing. Flash programming support is built on top of debug support. JTAG transport is selected with the command 'transport select jtag'. Unless your adapter uses either *note the hla interface driver: hla_interface. (in which case the command is 'transport select hla_jtag') or *note the st-link interface driver: st_link_dap_interface. (in which case the command is 'transport select dapdirect_jtag'). 8.3.2 SWD Transport ------------------- SWD (Serial Wire Debug) is an ARM-specific transport which exposes one Debug Access Point (DAP, which must be explicitly declared. (SWD uses fewer signal wires than JTAG.) SWD is debug-oriented, and does not support boundary scan testing. Flash programming support is built on top of debug support. (Some processors support both JTAG and SWD.) SWD transport is selected with the command 'transport select swd'. Unless your adapter uses either *note the hla interface driver: hla_interface. (in which case the command is 'transport select hla_swd') or *note the st-link interface driver: st_link_dap_interface. (in which case the command is 'transport select dapdirect_swd'). -- Config Command: swd newdap ... Declares a single DAP which uses SWD transport. Parameters are currently the same as "jtag newtap" but this is expected to change. The newer SWD devices (SW-DP v2 or SWJ-DP v2) support the multi-drop extension of SWD protocol: two or more devices can be connected to one SWD adapter. SWD transport works in multi-drop mode if *note DAP: dap_create. is configured with both '-dp-id' and '-instance-id' parameters regardless how many DAPs are created. Not all adapters and adapter drivers support SWD multi-drop. Only the following adapter drivers are SWD multi-drop capable: cmsis_dap (use an adapter with CMSIS-DAP version 2.0), ftdi, all bitbang based. 8.3.3 SPI Transport ------------------- The Serial Peripheral Interface (SPI) is a general purpose transport which uses four wire signaling. Some processors use it as part of a solution for flash programming. 8.3.4 SWIM Transport -------------------- The Single Wire Interface Module (SWIM) is a low-pin-count debug protocol used by the STMicroelectronics MCU family STM8 and documented in the User Manual UM470 (https://www.st.com/resource/en/user_manual/cd00173911.pdf). SWIM does not support boundary scan testing nor multiple cores. The SWIM transport is selected with the command 'transport select swim'. The concept of TAPs does not fit in the protocol since SWIM does not implement a scan chain. Nevertheless, the current SW model of OpenOCD requires defining a virtual SWIM TAP through the command 'swim newtap basename tap_type'. The TAP definition must precede the target definition command 'target create target_name stm8 -chain-position basename.tap_type'. 8.4 JTAG Speed ============== JTAG clock setup is part of system setup. It _does not belong with interface setup_ since any interface only knows a few of the constraints for the JTAG clock speed. Sometimes the JTAG speed is changed during the target initialization process: (1) slow at reset, (2) program the CPU clocks, (3) run fast. Both the "slow" and "fast" clock rates are functions of the oscillators used, the chip, the board design, and sometimes power management software that may be active. The speed used during reset, and the scan chain verification which follows reset, can be adjusted using a 'reset-start' target event handler. It can then be reconfigured to a faster speed by a 'reset-init' target event handler after it reprograms those CPU clocks, or manually (if something else, such as a boot loader, sets up those clocks). *Note Target Events: targetevents. When the initial low JTAG speed is a chip characteristic, perhaps because of a required oscillator speed, provide such a handler in the target config file. When that speed is a function of a board-specific characteristic such as which speed oscillator is used, it belongs in the board config file instead. In both cases it's safest to also set the initial JTAG clock rate to that same slow speed, so that OpenOCD never starts up using a clock speed that's faster than the scan chain can support. jtag_rclk 3000 $_TARGET.cpu configure -event reset-start { jtag_rclk 3000 } If your system supports adaptive clocking (RTCK), configuring JTAG to use that is probably the most robust approach. However, it introduces delays to synchronize clocks; so it may not be the fastest solution. NOTE: Script writers should consider using 'jtag_rclk' instead of 'adapter speed', but only for (ARM) cores and boards which support adaptive clocking. -- Command: adapter speed max_speed_kHz A non-zero speed is in KHZ. Hence: 3000 is 3mhz. JTAG interfaces usually support a limited number of speeds. The speed actually used won't be faster than the speed specified. Chip data sheets generally include a top JTAG clock rate. The actual rate is often a function of a CPU core clock, and is normally less than that peak rate. For example, most ARM cores accept at most one sixth of the CPU clock. Speed 0 (khz) selects RTCK method. *Note FAQ RTCK: faqrtck. If your system uses RTCK, you won't need to change the JTAG clocking after setup. Not all interfaces, boards, or targets support "rtck". If the interface device can not support it, an error is returned when you try to use RTCK. -- Function: jtag_rclk fallback_speed_kHz This Tcl proc (defined in 'startup.tcl') attempts to enable RTCK/RCLK. If that fails (maybe the interface, board, or target doesn't support it), falls back to the specified frequency. # Fall back to 3mhz if RTCK is not supported jtag_rclk 3000  File: openocd.info, Node: Reset Configuration, Next: TAP Declaration, Prev: Debug Adapter Configuration, Up: Top 9 Reset Configuration ********************* Every system configuration may require a different reset configuration. This can also be quite confusing. Resets also interact with RESET-INIT event handlers, which do things like setting up clocks and DRAM, and JTAG clock rates. (*Note JTAG Speed: jtagspeed.) They can also interact with JTAG routers. Please see the various board files for examples. Note: To maintainers and integrators: Reset configuration touches several things at once. Normally the board configuration file should define it and assume that the JTAG adapter supports everything that's wired up to the board's JTAG connector. However, the target configuration file could also make note of something the silicon vendor has done inside the chip, which will be true for most (or all) boards using that chip. And when the JTAG adapter doesn't support everything, the user configuration file will need to override parts of the reset configuration provided by other files. 9.1 Types of Reset ================== There are many kinds of reset possible through JTAG, but they may not all work with a given board and adapter. That's part of why reset configuration can be error prone. * _System Reset_ ... the _SRST_ hardware signal resets all chips connected to the JTAG adapter, such as processors, power management chips, and I/O controllers. Normally resets triggered with this signal behave exactly like pressing a RESET button. * _JTAG TAP Reset_ ... the _TRST_ hardware signal resets just the TAP controllers connected to the JTAG adapter. Such resets should not be visible to the rest of the system; resetting a device's TAP controller just puts that controller into a known state. * _Emulation Reset_ ... many devices can be reset through JTAG commands. These resets are often distinguishable from system resets, either explicitly (a "reset reason" register says so) or implicitly (not all parts of the chip get reset). * _Other Resets_ ... system-on-chip devices often support several other types of reset. You may need to arrange that a watchdog timer stops while debugging, preventing a watchdog reset. There may be individual module resets. In the best case, OpenOCD can hold SRST, then reset the TAPs via TRST and send commands through JTAG to halt the CPU at the reset vector before the 1st instruction is executed. Then when it finally releases the SRST signal, the system is halted under debugger control before any code has executed. This is the behavior required to support the 'reset halt' and 'reset init' commands; after 'reset init' a board-specific script might do things like setting up DRAM. (*Note Reset Command: resetcommand.) 9.2 SRST and TRST Issues ======================== Because SRST and TRST are hardware signals, they can have a variety of system-specific constraints. Some of the most common issues are: * _Signal not available_ ... Some boards don't wire SRST or TRST to the JTAG connector. Some JTAG adapters don't support such signals even if they are wired up. Use the 'reset_config' SIGNALS options to say when either of those signals is not connected. When SRST is not available, your code might not be able to rely on controllers having been fully reset during code startup. Missing TRST is not a problem, since JTAG-level resets can be triggered using with TMS signaling. * _Signals shorted_ ... Sometimes a chip, board, or adapter will connect SRST to TRST, instead of keeping them separate. Use the 'reset_config' COMBINATION options to say when those signals aren't properly independent. * _Timing_ ... Reset circuitry like a resistor/capacitor delay circuit, reset supervisor, or on-chip features can extend the effect of a JTAG adapter's reset for some time after the adapter stops issuing the reset. For example, there may be chip or board requirements that all reset pulses last for at least a certain amount of time; and reset buttons commonly have hardware debouncing. Use the 'adapter srst delay' and 'jtag_ntrst_delay' commands to say when extra delays are needed. * _Drive type_ ... Reset lines often have a pullup resistor, letting the JTAG interface treat them as open-drain signals. But that's not a requirement, so the adapter may need to use push/pull output drivers. Also, with weak pullups it may be advisable to drive signals to both levels (push/pull) to minimize rise times. Use the 'reset_config' TRST_TYPE and SRST_TYPE parameters to say how to drive reset signals. * _Special initialization_ ... Targets sometimes need special JTAG initialization sequences to handle chip-specific issues (not limited to errata). For example, certain JTAG commands might need to be issued while the system as a whole is in a reset state (SRST active) but the JTAG scan chain is usable (TRST inactive). Many systems treat combined assertion of SRST and TRST as a trigger for a harder reset than SRST alone. Such custom reset handling is discussed later in this chapter. There can also be other issues. Some devices don't fully conform to the JTAG specifications. Trivial system-specific differences are common, such as SRST and TRST using slightly different names. There are also vendors who distribute key JTAG documentation for their chips only to developers who have signed a Non-Disclosure Agreement (NDA). Sometimes there are chip-specific extensions like a requirement to use the normally-optional TRST signal (precluding use of JTAG adapters which don't pass TRST through), or needing extra steps to complete a TAP reset. In short, SRST and especially TRST handling may be very finicky, needing to cope with both architecture and board specific constraints. 9.3 Commands for Handling Resets ================================ -- Command: adapter srst pulse_width milliseconds Minimum amount of time (in milliseconds) OpenOCD should wait after asserting nSRST (active-low system reset) before allowing it to be deasserted. -- Command: adapter srst delay milliseconds How long (in milliseconds) OpenOCD should wait after deasserting nSRST (active-low system reset) before starting new JTAG operations. When a board has a reset button connected to SRST line it will probably have hardware debouncing, implying you should use this. -- Command: jtag_ntrst_assert_width milliseconds Minimum amount of time (in milliseconds) OpenOCD should wait after asserting nTRST (active-low JTAG TAP reset) before allowing it to be deasserted. -- Command: jtag_ntrst_delay milliseconds How long (in milliseconds) OpenOCD should wait after deasserting nTRST (active-low JTAG TAP reset) before starting new JTAG operations. -- Command: reset_config mode_flag ... This command displays or modifies the reset configuration of your combination of JTAG board and target in target configuration scripts. Information earlier in this section describes the kind of problems the command is intended to address (*note SRST and TRST Issues: srstandtrstissues.). As a rule this command belongs only in board config files, describing issues like _board doesn't connect TRST_; or in user config files, addressing limitations derived from a particular combination of interface and board. (An unlikely example would be using a TRST-only adapter with a board that only wires up SRST.) The MODE_FLAG options can be specified in any order, but only one of each type - SIGNALS, COMBINATION, GATES, TRST_TYPE, SRST_TYPE and CONNECT_TYPE - may be specified at a time. If you don't provide a new value for a given type, its previous value (perhaps the default) is unchanged. For example, this means that you don't need to say anything at all about TRST just to declare that if the JTAG adapter should want to drive SRST, it must explicitly be driven high ('srst_push_pull'). * SIGNALS can specify which of the reset signals are connected. For example, If the JTAG interface provides SRST, but the board doesn't connect that signal properly, then OpenOCD can't use it. Possible values are 'none' (the default), 'trst_only', 'srst_only' and 'trst_and_srst'. Tip: If your board provides SRST and/or TRST through the JTAG connector, you must declare that so those signals can be used. * The COMBINATION is an optional value specifying broken reset signal implementations. The default behaviour if no option given is 'separate', indicating everything behaves normally. 'srst_pulls_trst' states that the test logic is reset together with the reset of the system (e.g. NXP LPC2000, "broken" board layout), 'trst_pulls_srst' says that the system is reset together with the test logic (only hypothetical, I haven't seen hardware with such a bug, and can be worked around). 'combined' implies both 'srst_pulls_trst' and 'trst_pulls_srst'. * The GATES tokens control flags that describe some cases where JTAG may be unavailable during reset. 'srst_gates_jtag' (default) indicates that asserting SRST gates the JTAG clock. This means that no communication can happen on JTAG while SRST is asserted. Its converse is 'srst_nogate', indicating that JTAG commands can safely be issued while SRST is active. * The CONNECT_TYPE tokens control flags that describe some cases where SRST is asserted while connecting to the target. 'srst_nogate' is required to use this option. 'connect_deassert_srst' (default) indicates that SRST will not be asserted while connecting to the target. Its converse is 'connect_assert_srst', indicating that SRST will be asserted before any target connection. Only some targets support this feature, STM32 and STR9 are examples. This feature is useful if you are unable to connect to your target due to incorrect options byte config or illegal program execution. The optional TRST_TYPE and SRST_TYPE parameters allow the driver mode of each reset line to be specified. These values only affect JTAG interfaces with support for different driver modes, like the Amontec JTAGkey and JTAG Accelerator. Also, they are necessarily ignored if the relevant signal (TRST or SRST) is not connected. * Possible TRST_TYPE driver modes for the test reset signal (TRST) are the default 'trst_push_pull', and 'trst_open_drain'. Most boards connect this signal to a pulldown, so the JTAG TAPs never leave reset unless they are hooked up to a JTAG adapter. * Possible SRST_TYPE driver modes for the system reset signal (SRST) are the default 'srst_open_drain', and 'srst_push_pull'. Most boards connect this signal to a pullup, and allow the signal to be pulled low by various events including system power-up and pressing a reset button. 9.4 Custom Reset Handling ========================= OpenOCD has several ways to help support the various reset mechanisms provided by chip and board vendors. The commands shown in the previous section give standard parameters. There are also _event handlers_ associated with TAPs or Targets. Those handlers are Tcl procedures you can provide, which are invoked at particular points in the reset sequence. _When SRST is not an option_ you must set up a 'reset-assert' event handler for your target. For example, some JTAG adapters don't include the SRST signal; and some boards have multiple targets, and you won't always want to reset everything at once. After configuring those mechanisms, you might still find your board doesn't start up or reset correctly. For example, maybe it needs a slightly different sequence of SRST and/or TRST manipulations, because of quirks that the 'reset_config' mechanism doesn't address; or asserting both might trigger a stronger reset, which needs special attention. Experiment with lower level operations, such as 'adapter assert', 'adapter deassert' and the 'jtag arp_*' operations shown here, to find a sequence of operations that works. *Note JTAG Commands::. When you find a working sequence, it can be used to override 'jtag_init', which fires during OpenOCD startup (*note Configuration Stage: configurationstage.); or 'init_reset', which fires during reset processing. You might also want to provide some project-specific reset schemes. For example, on a multi-target board the standard 'reset' command would reset all targets, but you may need the ability to reset only one target at time and thus want to avoid using the board-wide SRST signal. -- Overridable Procedure: init_reset mode This is invoked near the beginning of the 'reset' command, usually to provide as much of a cold (power-up) reset as practical. By default it is also invoked from 'jtag_init' if the scan chain does not respond to pure JTAG operations. The MODE parameter is the parameter given to the low level reset command ('halt', 'init', or 'run'), 'setup', or potentially some other value. The default implementation just invokes 'jtag arp_init-reset'. Replacements will normally build on low level JTAG operations such as 'adapter assert' and 'adapter deassert'. Operations here must not address individual TAPs (or their associated targets) until the JTAG scan chain has first been verified to work. Implementations must have verified the JTAG scan chain before they return. This is done by calling 'jtag arp_init' (or 'jtag arp_init-reset'). -- Command: jtag arp_init This validates the scan chain using just the four standard JTAG signals (TMS, TCK, TDI, TDO). It starts by issuing a JTAG-only reset. Then it performs checks to verify that the scan chain configuration matches the TAPs it can observe. Those checks include checking IDCODE values for each active TAP, and verifying the length of their instruction registers using TAP '-ircapture' and '-irmask' values. If these tests all pass, TAP 'setup' events are issued to all TAPs with handlers for that event. -- Command: jtag arp_init-reset This uses TRST and SRST to try resetting everything on the JTAG scan chain (and anything else connected to SRST). It then invokes the logic of 'jtag arp_init'.  File: openocd.info, Node: TAP Declaration, Next: CPU Configuration, Prev: Reset Configuration, Up: Top 10 TAP Declaration ****************** _Test Access Ports_ (TAPs) are the core of JTAG. TAPs serve many roles, including: * Debug Target A CPU TAP can be used as a GDB debug target. * Flash Programming Some chips program the flash directly via JTAG. Others do it indirectly, making a CPU do it. * Program Download Using the same CPU support GDB uses, you can initialize a DRAM controller, download code to DRAM, and then start running that code. * Boundary Scan Most chips support boundary scan, which helps test for board assembly problems like solder bridges and missing connections. OpenOCD must know about the active TAPs on your board(s). Setting up the TAPs is the core task of your configuration files. Once those TAPs are set up, you can pass their names to code which sets up CPUs and exports them as GDB targets, probes flash memory, performs low-level JTAG operations, and more. 10.1 Scan Chains ================ TAPs are part of a hardware "scan chain", which is a daisy chain of TAPs. They also need to be added to OpenOCD's software mirror of that hardware list, giving each member a name and associating other data with it. Simple scan chains, with a single TAP, are common in systems with a single microcontroller or microprocessor. More complex chips may have several TAPs internally. Very complex scan chains might have a dozen or more TAPs: several in one chip, more in the next, and connecting to other boards with their own chips and TAPs. You can display the list with the 'scan_chain' command. (Don't confuse this with the list displayed by the 'targets' command, presented in the next chapter. That only displays TAPs for CPUs which are configured as debugging targets.) Here's what the scan chain might look like for a chip more than one TAP: TapName Enabled IdCode Expected IrLen IrCap IrMask -- ------------------ ------- ---------- ---------- ----- ----- ------ 0 omap5912.dsp Y 0x03df1d81 0x03df1d81 38 0x01 0x03 1 omap5912.arm Y 0x0692602f 0x0692602f 4 0x01 0x0f 2 omap5912.unknown Y 0x00000000 0x00000000 8 0x01 0x03 OpenOCD can detect some of that information, but not all of it. *Note Autoprobing: autoprobing. Unfortunately, those TAPs can't always be autoconfigured, because not all devices provide good support for that. JTAG doesn't require supporting IDCODE instructions, and chips with JTAG routers may not link TAPs into the chain until they are told to do so. The configuration mechanism currently supported by OpenOCD requires explicit configuration of all TAP devices using 'jtag newtap' commands, as detailed later in this chapter. A command like this would declare one tap and name it 'chip1.cpu': jtag newtap chip1 cpu -irlen 4 -expected-id 0x3ba00477 Each target configuration file lists the TAPs provided by a given chip. Board configuration files combine all the targets on a board, and so forth. Note that _the order in which TAPs are declared is very important._ That declaration order must match the order in the JTAG scan chain, both inside a single chip and between them. *Note FAQ TAP Order: faqtaporder. For example, the STMicroelectronics STR912 chip has three separate TAPs(1). To configure those taps, 'target/str912.cfg' includes commands something like this: jtag newtap str912 flash ... params ... jtag newtap str912 cpu ... params ... jtag newtap str912 bs ... params ... Actual config files typically use a variable such as '$_CHIPNAME' instead of literals like 'str912', to support more than one chip of each type. *Note Config File Guidelines::. -- Command: jtag names Returns the names of all current TAPs in the scan chain. Use 'jtag cget' or 'jtag tapisenabled' to examine attributes and state of each TAP. foreach t [jtag names] { puts [format "TAP: %s\n" $t] } -- Command: scan_chain Displays the TAPs in the scan chain configuration, and their status. The set of TAPs listed by this command is fixed by exiting the OpenOCD configuration stage, but systems with a JTAG router can enable or disable TAPs dynamically. 10.2 TAP Names ============== When TAP objects are declared with 'jtag newtap', a "dotted.name" is created for the TAP, combining the name of a module (usually a chip) and a label for the TAP. For example: 'xilinx.tap', 'str912.flash', 'omap3530.jrc', 'dm6446.dsp', or 'stm32.cpu'. Many other commands use that dotted.name to manipulate or refer to the TAP. For example, CPU configuration uses the name, as does declaration of NAND or NOR flash banks. The components of a dotted name should follow "C" symbol name rules: start with an alphabetic character, then numbers and underscores are OK; while others (including dots!) are not. 10.3 TAP Declaration Commands ============================= -- Config Command: jtag newtap chipname tapname configparams... Declares a new TAP with the dotted name CHIPNAME.TAPNAME, and configured according to the various CONFIGPARAMS. The CHIPNAME is a symbolic name for the chip. Conventionally target config files use '$_CHIPNAME', defaulting to the model name given by the chip vendor but overridable. The TAPNAME reflects the role of that TAP, and should follow this convention: * 'bs' - For boundary scan if this is a separate TAP; * 'cpu' - The main CPU of the chip, alternatively 'arm' and 'dsp' on chips with both ARM and DSP CPUs, 'arm1' and 'arm2' on chips with two ARMs, and so forth; * 'etb' - For an embedded trace buffer (example: an ARM ETB11); * 'flash' - If the chip has a flash TAP, like the str912; * 'jrc' - For JTAG route controller (example: the ICEPick modules on many Texas Instruments chips, like the OMAP3530 on Beagleboards); * 'tap' - Should be used only for FPGA- or CPLD-like devices with a single TAP; * 'unknownN' - If you have no idea what the TAP is for (N is a number); * _when in doubt_ - Use the chip maker's name in their data sheet. For example, the Freescale i.MX31 has a SDMA (Smart DMA) with a JTAG TAP; that TAP should be named 'sdma'. Every TAP requires at least the following CONFIGPARAMS: * '-irlen' NUMBER The length in bits of the instruction register, such as 4 or 5 bits. A TAP may also provide optional CONFIGPARAMS: * '-disable' (or '-enable') Use the '-disable' parameter to flag a TAP which is not linked into the scan chain after a reset using either TRST or the JTAG state machine's RESET state. You may use '-enable' to highlight the default state (the TAP is linked in). *Note Enabling and Disabling TAPs: enablinganddisablingtaps. * '-expected-id' NUMBER A non-zero NUMBER represents a 32-bit IDCODE which you expect to find when the scan chain is examined. These codes are not required by all JTAG devices. _Repeat the option_ as many times as required if more than one ID code could appear (for example, multiple versions). Specify NUMBER as zero to suppress warnings about IDCODE values that were found but not included in the list. Provide this value if at all possible, since it lets OpenOCD tell when the scan chain it sees isn't right. These values are provided in vendors' chip documentation, usually a technical reference manual. Sometimes you may need to probe the JTAG hardware to find these values. *Note Autoprobing: autoprobing. * '-ignore-version' Specify this to ignore the JTAG version field in the '-expected-id' option. When vendors put out multiple versions of a chip, or use the same JTAG-level ID for several largely-compatible chips, it may be more practical to ignore the version field than to update config files to handle all of the various chip IDs. The version field is defined as bit 28-31 of the IDCODE. * '-ignore-bypass' Specify this to ignore the 'bypass' bit of the idcode. Some vendor put an invalid idcode regarding this bit. Specify this to ignore this bit and to not consider this tap in bypass mode. * '-ircapture' NUMBER The bit pattern loaded by the TAP into the JTAG shift register on entry to the IRCAPTURE state, such as 0x01. JTAG requires the two LSBs of this value to be 01. By default, '-ircapture' and '-irmask' are set up to verify that two-bit value. You may provide additional bits if you know them, or indicate that a TAP doesn't conform to the JTAG specification. * '-irmask' NUMBER A mask used with '-ircapture' to verify that instruction scans work correctly. Such scans are not used by OpenOCD except to verify that there seems to be no problems with JTAG scan chain operations. * '-ignore-syspwrupack' Specify this to ignore the CSYSPWRUPACK bit in the ARM DAP DP CTRL/STAT register during initial examination and when checking the sticky error bit. This bit is normally checked after setting the CSYSPWRUPREQ bit, but some devices do not set the ack bit until sometime later. 10.4 Other TAP commands ======================= -- Command: jtag cget dotted.name -idcode Get the value of the IDCODE found in hardware. -- Command: jtag cget dotted.name -event event_name -- Command: jtag configure dotted.name -event event_name handler At this writing this TAP attribute mechanism is limited and used mostly for event handling. (It is not a direct analogue of the 'cget'/'configure' mechanism for debugger targets.) See the next section for information about the available events. The 'configure' subcommand assigns an event handler, a TCL string which is evaluated when the event is triggered. The 'cget' subcommand returns that handler. 10.5 TAP Events =============== OpenOCD includes two event mechanisms. The one presented here applies to all JTAG TAPs. The other applies to debugger targets, which are associated with certain TAPs. The TAP events currently defined are: * post-reset The TAP has just completed a JTAG reset. The tap may still be in the JTAG RESET state. Handlers for these events might perform initialization sequences such as issuing TCK cycles, TMS sequences to ensure exit from the ARM SWD mode, and more. Because the scan chain has not yet been verified, handlers for these events _should not issue commands which scan the JTAG IR or DR registers_ of any particular target. NOTE: As this is written (September 2009), nothing prevents such access. * setup The scan chain has been reset and verified. This handler may enable TAPs as needed. * tap-disable The TAP needs to be disabled. This handler should implement 'jtag tapdisable' by issuing the relevant JTAG commands. * tap-enable The TAP needs to be enabled. This handler should implement 'jtag tapenable' by issuing the relevant JTAG commands. If you need some action after each JTAG reset which isn't actually specific to any TAP (since you can't yet trust the scan chain's contents to be accurate), you might: jtag configure CHIP.jrc -event post-reset { echo "JTAG Reset done" ... non-scan jtag operations to be done after reset } 10.6 Enabling and Disabling TAPs ================================ In some systems, a "JTAG Route Controller" (JRC) is used to enable and/or disable specific JTAG TAPs. Many ARM-based chips from Texas Instruments include an "ICEPick" module, which is a JRC. Such chips include DaVinci and OMAP3 processors. A given TAP may not be visible until the JRC has been told to link it into the scan chain; and if the JRC has been told to unlink that TAP, it will no longer be visible. Such routers address problems that JTAG "bypass mode" ignores, such as: * The scan chain can only go as fast as its slowest TAP. * Having many TAPs slows instruction scans, since all TAPs receive new instructions. * TAPs in the scan chain must be powered up, which wastes power and prevents debugging some power management mechanisms. The IEEE 1149.1 JTAG standard has no concept of a "disabled" tap, as implied by the existence of JTAG routers. However, the upcoming IEEE 1149.7 framework (layered on top of JTAG) does include a kind of JTAG router functionality. In OpenOCD, tap enabling/disabling is invoked by the Tcl commands shown below, and is implemented using TAP event handlers. So for example, when defining a TAP for a CPU connected to a JTAG router, your 'target.cfg' file should define TAP event handlers using code that looks something like this: jtag configure CHIP.cpu -event tap-enable { ... jtag operations using CHIP.jrc } jtag configure CHIP.cpu -event tap-disable { ... jtag operations using CHIP.jrc } Then you might want that CPU's TAP enabled almost all the time: jtag configure $CHIP.jrc -event setup "jtag tapenable $CHIP.cpu" Note how that particular setup event handler declaration uses quotes to evaluate '$CHIP' when the event is configured. Using brackets { } would cause it to be evaluated later, at runtime, when it might have a different value. -- Command: jtag tapdisable dotted.name If necessary, disables the tap by sending it a 'tap-disable' event. Returns the string "1" if the tap specified by DOTTED.NAME is enabled, and "0" if it is disabled. -- Command: jtag tapenable dotted.name If necessary, enables the tap by sending it a 'tap-enable' event. Returns the string "1" if the tap specified by DOTTED.NAME is enabled, and "0" if it is disabled. -- Command: jtag tapisenabled dotted.name Returns the string "1" if the tap specified by DOTTED.NAME is enabled, and "0" if it is disabled. Note: Humans will find the 'scan_chain' command more helpful for querying the state of the JTAG taps. 10.7 Autoprobing ================ TAP configuration is the first thing that needs to be done after interface and reset configuration. Sometimes it's hard finding out what TAPs exist, or how they are identified. Vendor documentation is not always easy to find and use. To help you get past such problems, OpenOCD has a limited _autoprobing_ ability to look at the scan chain, doing a "blind interrogation" and then reporting the TAPs it finds. To use this mechanism, start the OpenOCD server with only data that configures your JTAG interface, and arranges to come up with a slow clock (many devices don't support fast JTAG clocks right when they come out of reset). For example, your 'openocd.cfg' file might have: source [find interface/olimex-arm-usb-tiny-h.cfg] reset_config trst_and_srst jtag_rclk 8 When you start the server without any TAPs configured, it will attempt to autoconfigure the TAPs. There are two parts to this: 1. _TAP discovery_ ... After a JTAG reset (sometimes a system reset may be needed too), each TAP's data registers will hold the contents of either the IDCODE or BYPASS register. If JTAG communication is working, OpenOCD will see each TAP, and report what '-expected-id' to use with it. 2. _IR Length discovery_ ... Unfortunately JTAG does not provide a reliable way to find out the value of the '-irlen' parameter to use with a TAP that is discovered. If OpenOCD can discover the length of a TAP's instruction register, it will report it. Otherwise you may need to consult vendor documentation, such as chip data sheets or BSDL files. In many cases your board will have a simple scan chain with just a single device. Here's what OpenOCD reported with one board that's a bit more complex: clock speed 8 kHz There are no enabled taps. AUTO PROBING MIGHT NOT WORK!! AUTO auto0.tap - use "jtag newtap auto0 tap -expected-id 0x2b900f0f ..." AUTO auto1.tap - use "jtag newtap auto1 tap -expected-id 0x07926001 ..." AUTO auto2.tap - use "jtag newtap auto2 tap -expected-id 0x0b73b02f ..." AUTO auto0.tap - use "... -irlen 4" AUTO auto1.tap - use "... -irlen 4" AUTO auto2.tap - use "... -irlen 6" no gdb ports allocated as no target has been specified Given that information, you should be able to either find some existing config files to use, or create your own. If you create your own, you would configure from the bottom up: first a 'target.cfg' file with these TAPs, any targets associated with them, and any on-chip resources; then a 'board.cfg' with off-chip resources, clocking, and so forth. 10.8 DAP declaration (ARMv6-M, ARMv7 and ARMv8 targets) ======================================================= Since OpenOCD version 0.11.0, the Debug Access Port (DAP) is no longer implicitly created together with the target. It must be explicitly declared using the 'dap create' command. For all ARMv6-M, ARMv7 and ARMv8 targets, the option "'-dap' DAP_NAME" has to be used instead of "'-chain-position' DOTTED.NAME" when the target is created. The 'dap' command group supports the following sub-commands: -- Command: dap create dap_name -chain-position dotted.name configparams... Declare a DAP instance named DAP_NAME linked to the JTAG tap DOTTED.NAME. This also creates a new command ('dap_name') which is used for various purposes including additional configuration. There can only be one DAP for each JTAG tap in the system. A DAP may also provide optional CONFIGPARAMS: * '-ignore-syspwrupack' Specify this to ignore the CSYSPWRUPACK bit in the ARM DAP DP CTRL/STAT register during initial examination and when checking the sticky error bit. This bit is normally checked after setting the CSYSPWRUPREQ bit, but some devices do not set the ack bit until sometime later. * '-dp-id' NUMBER Debug port identification number for SWD DPv2 multidrop. The NUMBER is written to bits 0..27 of DP TARGETSEL during DP selection. To find the id number of a single connected device read DP TARGETID: 'device.dap dpreg 0x24' Use bits 0..27 of TARGETID. * '-instance-id' NUMBER Instance identification number for SWD DPv2 multidrop. The NUMBER is written to bits 28..31 of DP TARGETSEL during DP selection. To find the instance number of a single connected device read DP DLPIDR: 'device.dap dpreg 0x34' The instance number is in bits 28..31 of DLPIDR value. -- Command: dap names This command returns a list of all registered DAP objects. It it useful mainly for TCL scripting. -- Command: dap info [num] Displays the ROM table for MEM-AP NUM, defaulting to the currently selected AP of the currently selected target. -- Command: dap init Initialize all registered DAPs. This command is used internally during initialization. It can be issued at any time after the initialization, too. The following commands exist as subcommands of DAP instances: -- Command: $dap_name info [num] Displays the ROM table for MEM-AP NUM, defaulting to the currently selected AP. -- Command: $dap_name apid [num] Displays ID register from AP NUM, defaulting to the currently selected AP. -- Command: $dap_name apreg ap_num reg [value] Displays content of a register REG from AP AP_NUM or set a new value VALUE. REG is byte address of a word register, 0, 4, 8 ... 0xfc. -- Command: $dap_name apsel [num] Select AP NUM, defaulting to 0. -- Command: $dap_name dpreg reg [value] Displays the content of DP register at address REG, or set it to a new value VALUE. In case of SWD, REG is a value in packed format dpbanksel << 4 | addr and assumes values 0, 4, 8 ... 0xfc. In case of JTAG it only assumes values 0, 4, 8 and 0xc. _Note:_ Consider using 'poll off' to avoid any disturbing background activity by OpenOCD while you are operating at such low-level. -- Command: $dap_name baseaddr [num] Displays debug base address from MEM-AP NUM, defaulting to the currently selected AP. -- Command: $dap_name memaccess [value] Displays the number of extra tck cycles in the JTAG idle to use for MEM-AP memory bus access [0-255], giving additional time to respond to reads. If VALUE is defined, first assigns that. -- Command: $dap_name apcsw [value [mask]] Displays or changes CSW bit pattern for MEM-AP transfers. At the begin of each memory access the CSW pattern is extended (bitwise or-ed) by "Size" and "AddrInc" bit-fields according to transfer requirements and the result is written to the real CSW register. All bits except dynamically updated fields "Size" and "AddrInc" can be changed by changing the CSW pattern. Refer to ARM ADI v5 manual chapter 7.6.4 and appendix A for details. Use VALUE only syntax if you want to set the new CSW pattern as a whole. The example sets HPROT1 bit (required by Cortex-M) and clears the rest of the pattern: kx.dap apcsw 0x2000000 If MASK is also used, the CSW pattern is changed only on bit positions where the mask bit is 1. The following example sets HPROT3 (cacheable) and leaves the rest of the pattern intact. It configures memory access through DCache on Cortex-M7. set CSW_HPROT3_CACHEABLE [expr {1 << 27}] samv.dap apcsw $CSW_HPROT3_CACHEABLE $CSW_HPROT3_CACHEABLE Another example clears SPROT bit and leaves the rest of pattern intact: set CSW_SPROT [expr {1 << 30}] samv.dap apcsw 0 $CSW_SPROT _Note:_ If you want to check the real value of CSW, not CSW pattern, use 'xxx.dap apreg 0'. *Note DAP subcommand apreg::. _Warning:_ Some of the CSW bits are vital for working memory transfer. If you set a wrong CSW pattern and MEM-AP stopped working, use the following example with a proper dap name: xxx.dap apcsw default -- Config Command: $dap_name ti_be_32_quirks [enable] Set/get quirks mode for TI TMS450/TMS570 processors Disabled by default ---------- Footnotes ---------- (1) See the ST document titled: _STR91xFAxxx, Section 3.15 Jtag Interface, Page: 28/102, Figure 3: JTAG chaining inside the STR91xFA_.  File: openocd.info, Node: CPU Configuration, Next: Flash Commands, Prev: TAP Declaration, Up: Top 11 CPU Configuration ******************** This chapter discusses how to set up GDB debug targets for CPUs. You can also access these targets without GDB (*note Architecture and Core Commands::, and *note Target State handling: targetstatehandling.) and through various kinds of NAND and NOR flash commands. If you have multiple CPUs you can have multiple such targets. We'll start by looking at how to examine the targets you have, then look at how to add one more target and how to configure it. 11.1 Target List ================ All targets that have been set up are part of a list, where each member has a name. That name should normally be the same as the TAP name. You can display the list with the 'targets' (plural!) command. This display often has only one CPU; here's what it might look like with more than one: TargetName Type Endian TapName State -- ------------------ ---------- ------ ------------------ ------------ 0* at91rm9200.cpu arm920t little at91rm9200.cpu running 1 MyTarget cortex_m little mychip.foo tap-disabled One member of that list is the "current target", which is implicitly referenced by many commands. It's the one marked with a '*' near the target name. In particular, memory addresses often refer to the address space seen by that current target. Commands like 'mdw' (memory display words) and 'flash erase_address' (erase NOR flash blocks) are examples; and there are many more. Several commands let you examine the list of targets: -- Command: target current Returns the name of the current target. -- Command: target names Lists the names of all current targets in the list. foreach t [target names] { puts [format "Target: %s\n" $t] } -- Command: targets [name] _Note: the name of this command is plural. Other target command names are singular._ With no parameter, this command displays a table of all known targets in a user friendly form. With a parameter, this command sets the current target to the given target with the given NAME; this is only relevant on boards which have more than one target. 11.2 Target CPU Types ===================== Each target has a "CPU type", as shown in the output of the 'targets' command. You need to specify that type when calling 'target create'. The CPU type indicates more than just the instruction set. It also indicates how that instruction set is implemented, what kind of debug support it integrates, whether it has an MMU (and if so, what kind), what core-specific commands may be available (*note Architecture and Core Commands::), and more. It's easy to see what target types are supported, since there's a command to list them. -- Command: target types Lists all supported target types. At this writing, the supported CPU types are: * 'aarch64' - this is an ARMv8-A core with an MMU. * 'arm11' - this is a generation of ARMv6 cores. * 'arm720t' - this is an ARMv4 core with an MMU. * 'arm7tdmi' - this is an ARMv4 core. * 'arm920t' - this is an ARMv4 core with an MMU. * 'arm926ejs' - this is an ARMv5 core with an MMU. * 'arm946e' - this is an ARMv5 core with an MMU. * 'arm966e' - this is an ARMv5 core. * 'arm9tdmi' - this is an ARMv4 core. * 'avr' - implements Atmel's 8-bit AVR instruction set. (Support for this is preliminary and incomplete.) * 'avr32_ap7k' - this an AVR32 core. * 'cortex_a' - this is an ARMv7-A core with an MMU. * 'cortex_m' - this is an ARMv7-M core, supporting only the compact Thumb2 instruction set. Supports also ARMv6-M and ARMv8-M cores * 'cortex_r4' - this is an ARMv7-R core. * 'dragonite' - resembles arm966e. * 'dsp563xx' - implements Freescale's 24-bit DSP. (Support for this is still incomplete.) * 'dsp5680xx' - implements Freescale's 5680x DSP. * 'esirisc' - this is an EnSilica eSi-RISC core. The current implementation supports eSi-32xx cores. * 'esp32s2' - this is an Espressif SoC with single Xtensa core. * 'fa526' - resembles arm920 (w/o Thumb). * 'feroceon' - resembles arm926. * 'hla_target' - a Cortex-M alternative to work with HL adapters like ST-Link. * 'ls1_sap' - this is the SAP on NXP LS102x CPUs, allowing access to physical memory addresses independently of CPU cores. * 'mem_ap' - this is an ARM debug infrastructure Access Port without a CPU, through which bus read and write cycles can be generated; it may be useful for working with non-CPU hardware behind an AP or during development of support for new CPUs. It's possible to connect a GDB client to this target (the GDB port has to be specified, *Note option -gdb-port: gdbportoverride.), and a fake ARM core will be emulated to comply to GDB remote protocol. * 'mips_m4k' - a MIPS core. * 'mips_mips64' - a MIPS64 core. * 'nds32_v2' - this is an Andes NDS32 v2 core (deprecated; would be removed in v0.13.0). * 'nds32_v3' - this is an Andes NDS32 v3 core (deprecated; would be removed in v0.13.0). * 'nds32_v3m' - this is an Andes NDS32 v3m core (deprecated; would be removed in v0.13.0). * 'or1k' - this is an OpenRISC 1000 core. The current implementation supports three JTAG TAP cores: - 'OpenCores TAP' (See: ) - 'Altera Virtual JTAG TAP' (See: ) - 'Xilinx BSCAN_* virtual JTAG interface' (See: ) And two debug interfaces cores: - 'Advanced debug interface' (See: ) - 'SoC Debug Interface' (See: ) * 'quark_d20xx' - an Intel Quark D20xx core. * 'quark_x10xx' - an Intel Quark X10xx core. * 'riscv' - a RISC-V core. * 'stm8' - implements an STM8 core. * 'testee' - a dummy target for cases without a real CPU, e.g. CPLD. * 'xscale' - this is actually an architecture, not a CPU type. It is based on the ARMv5 architecture. To avoid being confused by the variety of ARM based cores, remember this key point: _ARM is a technology licencing company_. (See: .) The CPU name used by OpenOCD will reflect the CPU design that was licensed, not a vendor brand which incorporates that design. Name prefixes like arm7, arm9, arm11, and cortex reflect design generations; while names like ARMv4, ARMv5, ARMv6, ARMv7 and ARMv8 reflect an architecture version implemented by a CPU design. 11.3 Target Configuration ========================= Before creating a "target", you must have added its TAP to the scan chain. When you've added that TAP, you will have a 'dotted.name' which is used to set up the CPU support. The chip-specific configuration file will normally configure its CPU(s) right after it adds all of the chip's TAPs to the scan chain. Although you can set up a target in one step, it's often clearer if you use shorter commands and do it in two steps: create it, then configure optional parts. All operations on the target after it's created will use a new command, created as part of target creation. The two main things to configure after target creation are a work area, which usually has target-specific defaults even if the board setup code overrides them later; and event handlers (*note Target Events: targetevents.), which tend to be much more board-specific. The key steps you use might look something like this dap create mychip.dap -chain-position mychip.cpu target create MyTarget cortex_m -dap mychip.dap MyTarget configure -work-area-phys 0x08000 -work-area-size 8096 MyTarget configure -event reset-deassert-pre { jtag_rclk 5 } MyTarget configure -event reset-init { myboard_reinit } You should specify a working area if you can; typically it uses some on-chip SRAM. Such a working area can speed up many things, including bulk writes to target memory; flash operations like checking to see if memory needs to be erased; GDB memory checksumming; and more. Warning: On more complex chips, the work area can become inaccessible when application code (such as an operating system) enables or disables the MMU. For example, the particular MMU context used to access the virtual address will probably matter ... and that context might not have easy access to other addresses needed. At this writing, OpenOCD doesn't have much MMU intelligence. It's often very useful to define a 'reset-init' event handler. For systems that are normally used with a boot loader, common tasks include updating clocks and initializing memory controllers. That may be needed to let you write the boot loader into flash, in order to "de-brick" your board; or to load programs into external DDR memory without having run the boot loader. -- Config Command: target create target_name type configparams... This command creates a GDB debug target that refers to a specific JTAG tap. It enters that target into a list, and creates a new command ('TARGET_NAME') which is used for various purposes including additional configuration. * TARGET_NAME ... is the name of the debug target. By convention this should be the same as the _dotted.name_ of the TAP associated with this target, which must be specified here using the '-chain-position DOTTED.NAME' configparam. This name is also used to create the target object command, referred to here as '$target_name', and in other places the target needs to be identified. * TYPE ... specifies the target type. *Note target types: targettypes. * CONFIGPARAMS ... all parameters accepted by '$target_name configure' are permitted. If the target is big-endian, set it here with '-endian big'. You _must_ set the '-chain-position DOTTED.NAME' or '-dap DAP_NAME' here. -- Command: $target_name configure configparams... The options accepted by this command may also be specified as parameters to 'target create'. Their values can later be queried one at a time by using the '$target_name cget' command. _Warning:_ changing some of these after setup is dangerous. For example, moving a target from one TAP to another; and changing its endianness. * '-chain-position' DOTTED.NAME - names the TAP used to access this target. * '-dap' DAP_NAME - names the DAP used to access this target. *Note DAP declaration: dapdeclaration, on how to create and manage DAP instances. * '-endian' ('big'|'little') - specifies whether the CPU uses big or little endian conventions * '-event' EVENT_NAME EVENT_BODY - *Note Target Events: targetevents. Note that this updates a list of named event handlers. Calling this twice with two different event names assigns two different handlers, but calling it twice with the same event name assigns only one handler. Current target is temporarily overridden to the event issuing target before handler code starts and switched back after handler is done. * '-work-area-backup' ('0'|'1') - says whether the work area gets backed up; by default, _it is not backed up._ When possible, use a working_area that doesn't need to be backed up, since performing a backup slows down operations. For example, the beginning of an SRAM block is likely to be used by most build systems, but the end is often unused. * '-work-area-size' SIZE - specify work are size, in bytes. The same size applies regardless of whether its physical or virtual address is being used. * '-work-area-phys' ADDRESS - set the work area base ADDRESS to be used when no MMU is active. * '-work-area-virt' ADDRESS - set the work area base ADDRESS to be used when an MMU is active. _Do not specify a value for this except on targets with an MMU._ The value should normally correspond to a static mapping for the '-work-area-phys' address, set up by the current operating system. * '-rtos' RTOS_TYPE - enable rtos support for target, RTOS_TYPE can be one of 'auto', 'eCos', 'ThreadX', 'FreeRTOS', 'linux', 'ChibiOS', 'embKernel', 'mqx', 'uCOS-III', 'nuttx', 'RIOT', 'Zephyr' *Note RTOS Support: gdbrtossupport. * '-defer-examine' - skip target examination at initial JTAG chain scan and after a reset. A manual call to arp_examine is required to access the target for debugging. * '-ap-num' AP_NUMBER - set DAP access port for target, AP_NUMBER is the numeric index of the DAP AP the target is connected to. Use this option with systems where multiple, independent cores are connected to separate access ports of the same DAP. * '-cti' CTI_NAME - set Cross-Trigger Interface (CTI) connected to the target. Currently, only the 'aarch64' target makes use of this option, where it is a mandatory configuration for the target run control. *Note ARM Cross-Trigger Interface: armcrosstrigger, for instruction on how to declare and control a CTI instance. * '-gdb-port' NUMBER - see command 'gdb_port' for the possible values of the parameter NUMBER, which are not only numeric values. Use this option to override, for this target only, the global parameter set with command 'gdb_port'. *Note command gdb_port: gdb_port. * '-gdb-max-connections' NUMBER - EXPERIMENTAL: set the maximum number of GDB connections that are allowed for the target. Default is 1. A negative value for NUMBER means unlimited connections. See *Note Using GDB as a non-intrusive memory inspector: gdbmeminspect. 11.4 Other $target_name Commands ================================ The Tcl/Tk language has the concept of object commands, and OpenOCD adopts that same model for targets. A good Tk example is a on screen button. Once a button is created a button has a name (a path in Tk terms) and that name is useable as a first class command. For example in Tk, one can create a button and later configure it like this: # Create button .foobar -background red -command { foo } # Modify .foobar configure -foreground blue # Query set x [.foobar cget -background] # Report puts [format "The button is %s" $x] In OpenOCD's terms, the "target" is an object just like a Tcl/Tk button, and its object commands are invoked the same way. str912.cpu mww 0x1234 0x42 omap3530.cpu mww 0x5555 123 The commands supported by OpenOCD target objects are: -- Command: $target_name arp_examine allow-defer -- Command: $target_name arp_halt -- Command: $target_name arp_poll -- Command: $target_name arp_reset -- Command: $target_name arp_waitstate Internal OpenOCD scripts (most notably 'startup.tcl') use these to deal with specific reset cases. They are not otherwise documented here. -- Command: $target_name set_reg dict Set register values of the target. * DICT ... Tcl dictionary with pairs of register names and values. For example, the following command sets the value 0 to the program counter (pc) register and 0x1000 to the stack pointer (sp) register: set_reg {pc 0 sp 0x1000} -- Command: $target_name get_reg [-force] list Get register values from the target and return them as Tcl dictionary with pairs of register names and values. If option "-force" is set, the register values are read directly from the target, bypassing any caching. * LIST ... List of register names For example, the following command retrieves the values from the program counter (pc) and stack pointer (sp) register: get_reg {pc sp} -- Command: $target_name write_memory address width data ['phys'] This function provides an efficient way to write to the target memory from a Tcl script. * ADDRESS ... target memory address * WIDTH ... memory access bit size, can be 8, 16, 32 or 64 * DATA ... Tcl list with the elements to write * ['phys'] ... treat the memory address as physical instead of virtual address For example, the following command writes two 32 bit words into the target memory at address 0x20000000: write_memory 0x20000000 32 {0xdeadbeef 0x00230500} -- Command: $target_name read_memory address width count ['phys'] This function provides an efficient way to read the target memory from a Tcl script. A Tcl list containing the requested memory elements is returned by this function. * ADDRESS ... target memory address * WIDTH ... memory access bit size, can be 8, 16, 32 or 64 * COUNT ... number of elements to read * ['phys'] ... treat the memory address as physical instead of virtual address For example, the following command reads two 32 bit words from the target memory at address 0x20000000: read_memory 0x20000000 32 2 -- Command: $target_name cget queryparm Each configuration parameter accepted by '$target_name configure' can be individually queried, to return its current value. The QUERYPARM is a parameter name accepted by that command, such as '-work-area-phys'. There are a few special cases: * '-event' EVENT_NAME - returns the handler for the event named EVENT_NAME. This is a special case because setting a handler requires two parameters. * '-type' - returns the target type. This is a special case because this is set using 'target create' and can't be changed using '$target_name configure'. For example, if you wanted to summarize information about all the targets you might use something like this: foreach name [target names] { set y [$name cget -endian] set z [$name cget -type] puts [format "Chip %d is %s, Endian: %s, type: %s" \ $x $name $y $z] } -- Command: $target_name curstate Displays the current target state: 'debug-running', 'halted', 'reset', 'running', or 'unknown'. (Also, *note Event Polling: eventpolling.) -- Command: $target_name eventlist Displays a table listing all event handlers currently associated with this target. *Note Target Events: targetevents. -- Command: $target_name invoke-event event_name Invokes the handler for the event named EVENT_NAME. (This is primarily intended for use by OpenOCD framework code, for example by the reset code in 'startup.tcl'.) -- Command: $target_name mdd [phys] addr [count] -- Command: $target_name mdw [phys] addr [count] -- Command: $target_name mdh [phys] addr [count] -- Command: $target_name mdb [phys] addr [count] Display contents of address ADDR, as 64-bit doublewords ('mdd'), 32-bit words ('mdw'), 16-bit halfwords ('mdh'), or 8-bit bytes ('mdb'). When the current target has an MMU which is present and active, ADDR is interpreted as a virtual address. Otherwise, or if the optional PHYS flag is specified, ADDR is interpreted as a physical address. If COUNT is specified, displays that many units. (If you want to process the data instead of displaying it, see the 'read_memory' primitives.) -- Command: $target_name mwd [phys] addr doubleword [count] -- Command: $target_name mww [phys] addr word [count] -- Command: $target_name mwh [phys] addr halfword [count] -- Command: $target_name mwb [phys] addr byte [count] Writes the specified DOUBLEWORD (64 bits), WORD (32 bits), HALFWORD (16 bits), or BYTE (8-bit) value, at the specified address ADDR. When the current target has an MMU which is present and active, ADDR is interpreted as a virtual address. Otherwise, or if the optional PHYS flag is specified, ADDR is interpreted as a physical address. If COUNT is specified, fills that many units of consecutive address. 11.5 Target Events ================== At various times, certain things can happen, or you want them to happen. For example: * What should happen when GDB connects? Should your target reset? * When GDB tries to flash the target, do you need to enable the flash via a special command? * Is using SRST appropriate (and possible) on your system? Or instead of that, do you need to issue JTAG commands to trigger reset? SRST usually resets everything on the scan chain, which can be inappropriate. * During reset, do you need to write to certain memory locations to set up system clocks or to reconfigure the SDRAM? How about configuring the watchdog timer, or other peripherals, to stop running while you hold the core stopped for debugging? All of the above items can be addressed by target event handlers. These are set up by '$target_name configure -event' or 'target create ... -event'. The programmer's model matches the '-command' option used in Tcl/Tk buttons and events. The two examples below act the same, but one creates and invokes a small procedure while the other inlines it. proc my_init_proc { } { echo "Disabling watchdog..." mww 0xfffffd44 0x00008000 } mychip.cpu configure -event reset-init my_init_proc mychip.cpu configure -event reset-init { echo "Disabling watchdog..." mww 0xfffffd44 0x00008000 } The following target events are defined: * debug-halted The target has halted for debug reasons (i.e.: breakpoint) * debug-resumed The target has resumed (i.e.: GDB said run) * early-halted Occurs early in the halt process * examine-start Before target examine is called. * examine-end After target examine is called with no errors. * examine-fail After target examine fails. * gdb-attach When GDB connects. Issued before any GDB communication with the target starts. GDB expects the target is halted during attachment. *Note GDB as a non-intrusive memory inspector: gdbmeminspect, how to connect GDB to running target. The event can be also used to set up the target so it is possible to probe flash. Probing flash is necessary during GDB connect if you want to use *note programming using GDB: programmingusinggdb. Another use of the flash memory map is for GDB to automatically choose hardware or software breakpoints depending on whether the breakpoint is in RAM or read only memory. Default is 'halt' * gdb-detach When GDB disconnects * gdb-end When the target has halted and GDB is not doing anything (see early halt) * gdb-flash-erase-start Before the GDB flash process tries to erase the flash (default is 'reset init') * gdb-flash-erase-end After the GDB flash process has finished erasing the flash * gdb-flash-write-start Before GDB writes to the flash * gdb-flash-write-end After GDB writes to the flash (default is 'reset halt') * gdb-start Before the target steps, GDB is trying to start/resume the target * halted The target has halted * reset-assert-pre Issued as part of 'reset' processing after 'reset-start' was triggered but before either SRST alone is asserted on the scan chain, or 'reset-assert' is triggered. * reset-assert Issued as part of 'reset' processing after 'reset-assert-pre' was triggered. When such a handler is present, cores which support this event will use it instead of asserting SRST. This support is essential for debugging with JTAG interfaces which don't include an SRST line (JTAG doesn't require SRST), and for selective reset on scan chains that have multiple targets. * reset-assert-post Issued as part of 'reset' processing after 'reset-assert' has been triggered. or the target asserted SRST on the entire scan chain. * reset-deassert-pre Issued as part of 'reset' processing after 'reset-assert-post' has been triggered. * reset-deassert-post Issued as part of 'reset' processing after 'reset-deassert-pre' has been triggered and (if the target is using it) after SRST has been released on the scan chain. * reset-end Issued as the final step in 'reset' processing. * reset-init Used by reset init command for board-specific initialization. This event fires after _reset-deassert-post_. This is where you would configure PLLs and clocking, set up DRAM so you can download programs that don't fit in on-chip SRAM, set up pin multiplexing, and so on. (You may be able to switch to a fast JTAG clock rate here, after the target clocks are fully set up.) * reset-start Issued as the first step in 'reset' processing before 'reset-assert-pre' is called. This is the most robust place to use 'jtag_rclk' or 'adapter speed' to switch to a low JTAG clock rate, when reset disables PLLs needed to use a fast clock. * resume-start Before any target is resumed * resume-end After all targets have resumed * resumed Target has resumed * step-start Before a target is single-stepped * step-end After single-step has completed * trace-config After target hardware trace configuration was changed * semihosting-user-cmd-0x100 The target made a semihosting call with user-defined operation number 0x100 * semihosting-user-cmd-0x101 The target made a semihosting call with user-defined operation number 0x101 * semihosting-user-cmd-0x102 The target made a semihosting call with user-defined operation number 0x102 * semihosting-user-cmd-0x103 The target made a semihosting call with user-defined operation number 0x103 * semihosting-user-cmd-0x104 The target made a semihosting call with user-defined operation number 0x104 * semihosting-user-cmd-0x105 The target made a semihosting call with user-defined operation number 0x105 * semihosting-user-cmd-0x106 The target made a semihosting call with user-defined operation number 0x106 * semihosting-user-cmd-0x107 The target made a semihosting call with user-defined operation number 0x107 Note: OpenOCD events are not supposed to be preempt by another event, but this is not enforced in current code. Only the target event resumed is executed with polling disabled; this avoids polling to trigger the event halted, reversing the logical order of execution of their handlers. Future versions of OpenOCD will prevent the event preemption and will disable the schedule of polling during the event execution. Do not rely on polling in any event handler; this means, don't expect the status of a core to change during the execution of the handler. The event handler will have to enable polling or use '$target_name arp_poll' to check if the core has changed status.  File: openocd.info, Node: Flash Commands, Next: Flash Programming, Prev: CPU Configuration, Up: Top 12 Flash Commands ***************** OpenOCD has different commands for NOR and NAND flash; the "flash" command works with NOR flash, while the "nand" command works with NAND flash. This partially reflects different hardware technologies: NOR flash usually supports direct CPU instruction and data bus access, while data from a NAND flash must be copied to memory before it can be used. (SPI flash must also be copied to memory before use.) However, the documentation also uses "flash" as a generic term; for example, "Put flash configuration in board-specific files". Flash Steps: 1. Configure via the command 'flash bank' Do this in a board-specific configuration file, passing parameters as needed by the driver. 2. Operate on the flash via 'flash subcommand' Often commands to manipulate the flash are typed by a human, or run via a script in some automated way. Common tasks include writing a boot loader, operating system, or other data. 3. GDB Flashing Flashing via GDB requires the flash be configured via "flash bank", and the GDB flash features be enabled. *Note GDB Configuration: gdbconfiguration. Many CPUs have the ability to "boot" from the first flash bank. This means that misprogramming that bank can "brick" a system, so that it can't boot. JTAG tools, like OpenOCD, are often then used to "de-brick" the board by (re)installing working boot firmware. 12.1 Flash Configuration Commands ================================= -- Config Command: flash bank name driver base size chip_width bus_width target [driver_options] Configures a flash bank which provides persistent storage for addresses from base to base + size - 1. These banks will often be visible to GDB through the target's memory map. In some cases, configuring a flash bank will activate extra commands; see the driver-specific documentation. * NAME ... may be used to reference the flash bank in other flash commands. A number is also available. * DRIVER ... identifies the controller driver associated with the flash bank being declared. This is usually 'cfi' for external flash, or else the name of a microcontroller with embedded flash memory. *Note Flash Driver List: flashdriverlist. * BASE ... Base address of the flash chip. * SIZE ... Size of the chip, in bytes. For some drivers, this value is detected from the hardware. * CHIP_WIDTH ... Width of the flash chip, in bytes; ignored for most microcontroller drivers. * BUS_WIDTH ... Width of the data bus used to access the chip, in bytes; ignored for most microcontroller drivers. * TARGET ... Names the target used to issue commands to the flash controller. * DRIVER_OPTIONS ... drivers may support, or require, additional parameters. See the driver-specific documentation for more information. Note: This command is not available after OpenOCD initialization has completed. Use it in board specific configuration files, not interactively. -- Command: flash banks Prints a one-line summary of each device that was declared using 'flash bank', numbered from zero. Note that this is the _plural_ form; the _singular_ form is a very different command. -- Command: flash list Retrieves a list of associative arrays for each device that was declared using 'flash bank', numbered from zero. This returned list can be manipulated easily from within scripts. -- Command: flash probe num Identify the flash, or validate the parameters of the configured flash. Operation depends on the flash type. The NUM parameter is a value shown by 'flash banks'. Most flash commands will implicitly _autoprobe_ the bank; flash drivers can distinguish between probing and autoprobing, but most don't bother. 12.2 Preparing a Target before Flash Programming ================================================ The target device should be in well defined state before the flash programming begins. _Always issue_ 'reset init' before *note Flash Programming Commands: flashprogrammingcommands. Do not issue another 'reset' or 'reset halt' or 'resume' until the programming session is finished. If you use *note Programming using GDB: programmingusinggdb, the target is prepared automatically in the event gdb-flash-erase-start The jimtcl script 'program' calls 'reset init' explicitly. 12.3 Erasing, Reading, Writing to Flash ======================================= One feature distinguishing NOR flash from NAND or serial flash technologies is that for read access, it acts exactly like any other addressable memory. This means you can use normal memory read commands like 'mdw' or 'dump_image' with it, with no special 'flash' subcommands. *Note Memory access: memoryaccess, and *note Image access: imageaccess. Write access works differently. Flash memory normally needs to be erased before it's written. Erasing a sector turns all of its bits to ones, and writing can turn ones into zeroes. This is why there are special commands for interactive erasing and writing, and why GDB needs to know which parts of the address space hold NOR flash memory. Note: Most of these erase and write commands leverage the fact that NOR flash chips consume target address space. They implicitly refer to the current JTAG target, and map from an address in that target's address space back to a flash bank. A few commands use abstract addressing based on bank and sector numbers, and don't depend on searching the current target and its address space. Avoid confusing the two command models. Some flash chips implement software protection against accidental writes, since such buggy writes could in some cases "brick" a system. For such systems, erasing and writing may require sector protection to be disabled first. Examples include CFI flash such as "Intel Advanced Bootblock flash", and AT91SAM7 on-chip flash. *Note flash protect: flashprotect. -- Command: flash erase_sector num first last Erase sectors in bank NUM, starting at sector FIRST up to and including LAST. Sector numbering starts at 0. Providing a LAST sector of 'last' specifies "to the end of the flash bank". The NUM parameter is a value shown by 'flash banks'. -- Command: flash erase_address [pad] [unlock] address length Erase sectors starting at ADDRESS for LENGTH bytes. Unless 'pad' is specified, address must begin a flash sector, and address + length - 1 must end a sector. Specifying 'pad' erases extra data at the beginning and/or end of the specified region, as needed to erase only full sectors. The flash bank to use is inferred from the ADDRESS, and the specified length must stay within that bank. As a special case, when LENGTH is zero and ADDRESS is the start of the bank, the whole flash is erased. If 'unlock' is specified, then the flash is unprotected before erase starts. -- Command: flash filld address double-word length -- Command: flash fillw address word length -- Command: flash fillh address halfword length -- Command: flash fillb address byte length Fills flash memory with the specified DOUBLE-WORD (64 bits), WORD (32 bits), HALFWORD (16 bits), or BYTE (8-bit) pattern, starting at ADDRESS and continuing for LENGTH units (word/halfword/byte). No erasure is done before writing; when needed, that must be done before issuing this command. Writes are done in blocks of up to 1024 bytes, and each write is verified by reading back the data and comparing it to what was written. The flash bank to use is inferred from the ADDRESS of each block, and the specified length must stay within that bank. -- Command: flash mdw addr [count] -- Command: flash mdh addr [count] -- Command: flash mdb addr [count] Display contents of address ADDR, as 32-bit words ('mdw'), 16-bit halfwords ('mdh'), or 8-bit bytes ('mdb'). If COUNT is specified, displays that many units. Reads from flash using the flash driver, therefore it enables reading from a bank not mapped in target address space. The flash bank to use is inferred from the ADDRESS of each block, and the specified length must stay within that bank. -- Command: flash write_bank num filename [offset] Write the binary 'filename' to flash bank NUM, starting at OFFSET bytes from the beginning of the bank. If OFFSET is omitted, start at the beginning of the flash bank. The NUM parameter is a value shown by 'flash banks'. -- Command: flash read_bank num filename [offset [length]] Read LENGTH bytes from the flash bank NUM starting at OFFSET and write the contents to the binary 'filename'. If OFFSET is omitted, start at the beginning of the flash bank. If LENGTH is omitted, read the remaining bytes from the flash bank. The NUM parameter is a value shown by 'flash banks'. -- Command: flash verify_bank num filename [offset] Compare the contents of the binary file FILENAME with the contents of the flash bank NUM starting at OFFSET. If OFFSET is omitted, start at the beginning of the flash bank. Fail if the contents do not match. The NUM parameter is a value shown by 'flash banks'. -- Command: flash write_image [erase] [unlock] filename [offset] [type] Write the image 'filename' to the current target's flash bank(s). Only loadable sections from the image are written. A relocation OFFSET may be specified, in which case it is added to the base address for each section in the image. The file [TYPE] can be specified explicitly as 'bin' (binary), 'ihex' (Intel hex), 'elf' (ELF file), 's19' (Motorola s19). 'mem', or 'builder'. The relevant flash sectors will be erased prior to programming if the 'erase' parameter is given. If 'unlock' is provided, then the flash banks are unlocked before erase and program. The flash bank to use is inferred from the address of each image section. Warning: Be careful using the 'erase' flag when the flash is holding data you want to preserve. Portions of the flash outside those described in the image's sections might be erased with no notice. * When a section of the image being written does not fill out all the sectors it uses, the unwritten parts of those sectors are necessarily also erased, because sectors can't be partially erased. * Data stored in sector "holes" between image sections are also affected. For example, "'flash write_image erase ...'" of an image with one byte at the beginning of a flash bank and one byte at the end erases the entire bank - not just the two sectors being written. Also, when flash protection is important, you must re-apply it after it has been removed by the 'unlock' flag. -- Command: flash verify_image filename [offset] [type] Verify the image 'filename' to the current target's flash bank(s). Parameters follow the description of 'flash write_image'. In contrast to the 'verify_image' command, for banks with specific verify method, that one is used instead of the usual target's read memory methods. This is necessary for flash banks not readable by ordinary memory reads. This command gives only an overall good/bad result for each bank, not addresses of individual failed bytes as it's intended only as quick check for successful programming. 12.4 Other Flash commands ========================= -- Command: flash erase_check num Check erase state of sectors in flash bank NUM, and display that status. The NUM parameter is a value shown by 'flash banks'. -- Command: flash info num [sectors] Print info about flash bank NUM, a list of protection blocks and their status. Use 'sectors' to show a list of sectors instead. The NUM parameter is a value shown by 'flash banks'. This command will first query the hardware, it does not print cached and possibly stale information. -- Command: flash protect num first last (on|off) Enable ('on') or disable ('off') protection of flash blocks in flash bank NUM, starting at protection block FIRST and continuing up to and including LAST. Providing a LAST block of 'last' specifies "to the end of the flash bank". The NUM parameter is a value shown by 'flash banks'. The protection block is usually identical to a flash sector. Some devices may utilize a protection block distinct from flash sector. See 'flash info' for a list of protection blocks. -- Command: flash padded_value num value Sets the default value used for padding any image sections, This should normally match the flash bank erased value. If not specified by this command or the flash driver then it defaults to 0xff. -- Command: program filename [preverify] [verify] [reset] [exit] [offset] This is a helper script that simplifies using OpenOCD as a standalone programmer. The only required parameter is 'filename', the others are optional. *Note Flash Programming::. 12.5 Flash Driver List ====================== As noted above, the 'flash bank' command requires a driver name, and allows driver-specific options and behaviors. Some drivers also activate driver-specific commands. -- Flash Driver: virtual This is a special driver that maps a previously defined bank to another address. All bank settings will be copied from the master physical bank. The VIRTUAL driver defines one mandatory parameters, * MASTER_BANK The bank that this virtual address refers to. So in the following example addresses 0xbfc00000 and 0x9fc00000 refer to the flash bank defined at address 0x1fc00000. Any command executed on the virtual banks is actually performed on the physical banks. flash bank $_FLASHNAME pic32mx 0x1fc00000 0 0 0 $_TARGETNAME flash bank vbank0 virtual 0xbfc00000 0 0 0 \ $_TARGETNAME $_FLASHNAME flash bank vbank1 virtual 0x9fc00000 0 0 0 \ $_TARGETNAME $_FLASHNAME 12.5.1 External Flash --------------------- -- Flash Driver: cfi The "Common Flash Interface" (CFI) is the main standard for external NOR flash chips, each of which connects to a specific external chip select on the CPU. Frequently the first such chip is used to boot the system. Your board's 'reset-init' handler might need to configure additional chip selects using other commands (like: 'mww' to configure a bus and its timings), or perhaps configure a GPIO pin that controls the "write protect" pin on the flash chip. The CFI driver can use a target-specific working area to significantly speed up operation. The CFI driver can accept the following optional parameters, in any order: * JEDEC_PROBE ... is used to detect certain non-CFI flash ROMs, like AM29LV010 and similar types. * X16_AS_X8 ... when a 16-bit flash is hooked up to an 8-bit bus. * BUS_SWAP ... when data bytes in a 16-bit flash needs to be swapped. * DATA_SWAP ... when data bytes in a 16-bit flash needs to be swapped when writing data values (i.e. not CFI commands). To configure two adjacent banks of 16 MBytes each, both sixteen bits (two bytes) wide on a sixteen bit bus: flash bank $_FLASHNAME cfi 0x00000000 0x01000000 2 2 $_TARGETNAME flash bank $_FLASHNAME cfi 0x01000000 0x01000000 2 2 $_TARGETNAME To configure one bank of 32 MBytes built from two sixteen bit (two byte) wide parts wired in parallel to create a thirty-two bit (four byte) bus with doubled throughput: flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 $_TARGETNAME -- Flash Driver: jtagspi Several FPGAs and CPLDs can retrieve their configuration (bitstream) from a SPI flash connected to them. To access this flash from the host, the device is first programmed with a special proxy bitstream that exposes the SPI flash on the device's JTAG interface. The flash can then be accessed through JTAG. Since signaling between JTAG and SPI is compatible, all that is required for a proxy bitstream is to connect TDI-MOSI, TDO-MISO, TCK-CLK and activate the flash chip select when the JTAG state machine is in SHIFT-DR. Such a bitstream for several Xilinx FPGAs can be found in 'contrib/loaders/flash/fpga/xilinx_bscan_spi.py'. It requires migen (https://github.com/m-labs/migen) and a Xilinx toolchain to build. This flash bank driver requires a target on a JTAG tap and will access that tap directly. Since no support from the target is needed, the target can be a "testee" dummy. Since the target does not expose the flash memory mapping, target commands that would otherwise be expected to access the flash will not work. These include all '*_image' and '$target_name m*' commands as well as 'program'. Equivalent functionality is available through the 'flash write_bank', 'flash read_bank', and 'flash verify_bank' commands. According to device size, 1- to 4-byte addresses are sent. However, some flash chips additionally have to be switched to 4-byte addresses by an extra command, see below. * IR ... is loaded into the JTAG IR to map the flash as the JTAG DR. For the bitstreams generated from 'xilinx_bscan_spi.py' this is the USER1 instruction. target create $_TARGETNAME testee -chain-position $_CHIPNAME.fpga set _XILINX_USER1 0x02 flash bank $_FLASHNAME spi 0x0 0 0 0 \ $_TARGETNAME $_XILINX_USER1 -- Command: jtagspi set bank_id name total_size page_size read_cmd unused pprg_cmd mass_erase_cmd sector_size sector_erase_cmd Sets flash parameters: NAME human readable string, TOTAL_SIZE size in bytes, PAGE_SIZE is write page size. READ_CMD and PPRG_CMD are commands for read and page program, respectively. MASS_ERASE_CMD, SECTOR_SIZE and SECTOR_ERASE_CMD are optional. jtagspi set 0 w25q128 0x1000000 0x100 0x03 0 0x02 0xC7 0x10000 0xD8 -- Command: jtagspi cmd bank_id resp_num cmd_byte ... Sends command CMD_BYTE and at most 20 following bytes and reads RESP_NUM bytes afterwards. E.g. for 'Enter 4-byte address mode' jtagspi cmd 0 0 0xB7 -- Command: jtagspi always_4byte bank_id [ on | off ] Some devices use 4-byte addresses for all commands except the legacy 0x03 read regardless of device size. This command controls the corresponding hack. -- Flash Driver: xcf Xilinx FPGAs can be configured from specialized flash ICs named Platform Flash. It is (almost) regular NOR flash with erase sectors, program pages, etc. The only difference is special registers controlling its FPGA specific behavior. They must be properly configured for successful FPGA loading using additional XCF driver command: -- Command: xcf ccb command accepts additional parameters: * EXTERNAL|INTERNAL ... selects clock source. * SERIAL|PARALLEL ... selects serial or parallel data bus mode. * SLAVE|MASTER ... selects slave of master mode for flash device. * 40|20 ... selects clock frequency in MHz for internal clock in master mode. xcf ccb 0 external parallel slave 40 All of them must be specified even if clock frequency is pointless in slave mode. If only bank id specified than command prints current CCB register value. Note: there is no need to write this register every time you erase/program data sectors because it stores in dedicated sector. -- Command: xcf configure Initiates FPGA loading procedure. Useful if your board has no "configure" button. xcf configure 0 Additional driver notes: * Only single revision supported. * Driver automatically detects need of bit reverse, but only "bin" (raw binary, do not confuse it with "bit") and "mcs" (Intel hex) file types supported. * For additional info check xapp972.pdf and ug380.pdf. -- Flash Driver: lpcspifi NXP's LPC43xx and LPC18xx families include a proprietary SPI Flash Interface (SPIFI) peripheral that can drive and provide memory mapped access to external SPI flash devices. The lpcspifi driver initializes this interface and provides program and erase functionality for these serial flash devices. Use of this driver requires a working area of at least 1kB to be configured on the target device; more than this will significantly reduce flash programming times. The setup command only requires the BASE parameter. All other parameters are ignored, and the flash size and layout are configured by the driver. flash bank $_FLASHNAME lpcspifi 0x14000000 0 0 0 $_TARGETNAME -- Flash Driver: stmsmi Some devices from STMicroelectronics (e.g. STR75x MCU family, SPEAr MPU family) include a proprietary "Serial Memory Interface" (SMI) controller able to drive external SPI flash devices. Depending on specific device and board configuration, up to 4 external flash devices can be connected. SMI makes the flash content directly accessible in the CPU address space; each external device is mapped in a memory bank. CPU can directly read data, execute code and boot from SMI banks. Normal OpenOCD commands like 'mdw' can be used to display the flash content. The setup command only requires the BASE parameter in order to identify the memory bank. All other parameters are ignored. Additional information, like flash size, are detected automatically. flash bank $_FLASHNAME stmsmi 0xf8000000 0 0 0 $_TARGETNAME -- Flash Driver: stmqspi Some devices from STMicroelectronics include a proprietary "QuadSPI Interface" (e.g. STM32F4, STM32F7, STM32L4) or "OctoSPI Interface" (e.g. STM32L4+) controller able to drive one or even two (dual mode) external SPI flash devices. The OctoSPI is a superset of QuadSPI, its presence is detected automatically. Currently only the regular command mode is supported, whereas the HyperFlash mode is not. QuadSPI/OctoSPI makes the flash contents directly accessible in the CPU address space; in case of dual mode both devices must be of the same type and are mapped in the same memory bank (even and odd addresses interleaved). CPU can directly read data, execute code (but not boot) from QuadSPI bank. The 'flash bank' command only requires the BASE parameter and the extra parameter IO_BASE in order to identify the memory bank. Both are fixed by hardware, see datasheet or RM. All other parameters are ignored. The controller must be initialized after each reset and properly configured for memory-mapped read operation for the particular flash chip(s), for the full list of available register settings cf. the controller's RM. This setup is quite board specific (that's why booting from this memory is not possible). The flash driver infers all parameters from current controller register values when 'flash probe BANK_ID' is executed. Normal OpenOCD commands like 'mdw' can be used to display the flash content, but only after proper controller initialization as described above. However, due to a silicon bug in some devices, attempting to access the very last word should be avoided. It is possible to use two (even different) flash chips alternatingly, if individual bank chip selects are available. For some package variants, this is not the case due to limited pin count. To switch from one to another, adjust FSEL bit accordingly and re-issue 'flash probe bank_id'. Note that the bank base address will _not_ change, so the address spaces of both devices will overlap. In dual flash mode both chips must be identical regarding size and most other properties. Block or sector protection internal to the flash chip is not handled by this driver at all, but can be dealt with manually by the 'cmd' command, see below. The sector protection via 'flash protect' command etc. is completely internal to openocd, intended only to prevent accidental erase or overwrite and it does not persist across openocd invocations. OpenOCD contains a hardcoded list of flash devices with their properties, these are auto-detected. If a device is not included in this list, SFDP discovery is attempted. If this fails or gives inappropriate results, manual setting is required (see 'set' command). flash bank $_FLASHNAME stmqspi 0x90000000 0 0 0 \ $_TARGETNAME 0xA0001000 flash bank $_FLASHNAME stmqspi 0x70000000 0 0 0 \ $_TARGETNAME 0xA0001400 There are three specific commands -- Command: stmqspi mass_erase bank_id Clears sector protections and performs a mass erase. Works only if there is no chip specific write protection engaged. -- Command: stmqspi set bank_id name total_size page_size read_cmd fread_cmd pprg_cmd mass_erase_cmd sector_size sector_erase_cmd Set flash parameters: NAME human readable string, TOTAL_SIZE size in bytes, PAGE_SIZE is write page size. READ_CMD, FREAD_CMD and PPRG_CMD are commands for reading and page programming. FREAD_CMD is used in DPI and QPI modes, READ_CMD in normal SPI (single line) mode. MASS_ERASE_CMD, SECTOR_SIZE and SECTOR_ERASE_CMD are optional. This command is required if chip id is not hardcoded yet and e.g. for EEPROMs or FRAMs which don't support an id command. In dual mode parameters of both chips are set identically. The parameters refer to a single chip, so the whole bank gets twice the specified capacity etc. -- Command: stmqspi cmd bank_id resp_num cmd_byte ... If RESP_NUM is zero, sends command CMD_BYTE and following data bytes. In dual mode command byte is sent to _both_ chips but data bytes are sent _alternatingly_ to chip 1 and 2, first to flash 1, second to flash 2, etc., i.e. the total number of bytes (including cmd_byte) must be odd. If RESP_NUM is not zero, cmd and at most four following data bytes are sent, in dual mode _simultaneously_ to both chips. Then RESP_NUM bytes are read interleaved from both chips starting with chip 1. In this case RESP_NUM must be even. Note the hardware dictated subtle difference of those two cases in dual-flash mode. To check basic communication settings, issue stmqspi cmd bank_id 0 0x04; stmqspi cmd bank_id 1 0x05 stmqspi cmd bank_id 0 0x06; stmqspi cmd bank_id 1 0x05 for single flash mode or stmqspi cmd bank_id 0 0x04; stmqspi cmd bank_id 2 0x05 stmqspi cmd bank_id 0 0x06; stmqspi cmd bank_id 2 0x05 for dual flash mode. This should return the status register contents. In 8-line mode, CMD_BYTE is sent twice - first time as given, second time complemented. Additionally, in 8-line mode only, some commands (e.g. Read Status) need a dummy address, e.g. stmqspi cmd bank_id 1 0x05 0x00 0x00 0x00 0x00 should return the status register contents. -- Flash Driver: mrvlqspi This driver supports QSPI flash controller of Marvell's Wireless Microcontroller platform. The flash size is autodetected based on the table of known JEDEC IDs hardcoded in the OpenOCD sources. flash bank $_FLASHNAME mrvlqspi 0x0 0 0 0 $_TARGETNAME 0x46010000 -- Flash Driver: ath79 Members of ATH79 SoC family from Atheros include a SPI interface with 3 chip selects. On reset a SPI flash connected to the first chip select (CS0) is made directly read-accessible in the CPU address space (up to 16MBytes) and is usually used to store the bootloader and operating system. Normal OpenOCD commands like 'mdw' can be used to display the flash content while it is in memory-mapped mode (only the first 4MBytes are accessible without additional configuration on reset). The setup command only requires the BASE parameter in order to identify the memory bank. The actual value for the base address is not otherwise used by the driver. However the mapping is passed to gdb. Thus for the memory mapped flash (chipselect CS0) the base address should be the actual memory mapped base address. For unmapped chipselects (CS1 and CS2) care should be taken to use a base address that does not overlap with real memory regions. Additional information, like flash size, are detected automatically. An optional additional parameter sets the chipselect for the bank, with the default CS0. CS1 and CS2 require additional GPIO setup before they can be used since the alternate function must be enabled on the GPIO pin CS1/CS2 is routed to on the given SoC. flash bank $_FLASHNAME ath79 0xbf000000 0 0 0 $_TARGETNAME # When using multiple chipselects the base should be different # for each, otherwise the write_image command is not able to # distinguish the banks. flash bank flash0 ath79 0xbf000000 0 0 0 $_TARGETNAME cs0 flash bank flash1 ath79 0x10000000 0 0 0 $_TARGETNAME cs1 flash bank flash2 ath79 0x20000000 0 0 0 $_TARGETNAME cs2 -- Flash Driver: fespi SiFive's Freedom E SPI controller, used in HiFive and other boards. flash bank $_FLASHNAME fespi 0x20000000 0 0 0 $_TARGETNAME 12.5.2 Internal Flash (Microcontrollers) ---------------------------------------- -- Flash Driver: aduc702x The ADUC702x analog microcontrollers from Analog Devices include internal flash and use ARM7TDMI cores. The aduc702x flash driver works with models ADUC7019 through ADUC7028. The setup command only requires the TARGET argument since all devices in this family have the same memory layout. flash bank $_FLASHNAME aduc702x 0 0 0 0 $_TARGETNAME -- Flash Driver: ambiqmicro All members of the Apollo microcontroller family from Ambiq Micro include internal flash and use ARM's Cortex-M4 core. The host connects over USB to an FTDI interface that communicates with the target using SWD. The AMBIQMICRO driver reads the Chip Information Register detect the device class of the MCU. The Flash and SRAM sizes directly follow device class, and are used to set up the flash banks. If this fails, the driver will use default values set to the minimum sizes of an Apollo chip. All Apollo chips have two flash banks of the same size. In all cases the first flash bank starts at location 0, and the second bank starts after the first. # Flash bank 0 flash bank $_FLASHNAME ambiqmicro 0 0x00040000 0 0 $_TARGETNAME # Flash bank 1 - same size as bank0, starts after bank 0. flash bank $_FLASHNAME ambiqmicro 0x00040000 0x00040000 0 0 \ $_TARGETNAME Flash is programmed using custom entry points into the bootloader. This is the only way to program the flash as no flash control registers are available to the user. The AMBIQMICRO driver adds some additional commands: -- Command: ambiqmicro mass_erase Erase entire bank. -- Command: ambiqmicro page_erase Erase device pages. -- Command: ambiqmicro program_otp Program OTP is a one time operation to create write protected flash. The user writes sectors to SRAM starting at 0x10000010. Program OTP will write these sectors from SRAM to flash, and write protect the flash. -- Flash Driver: at91samd All members of the ATSAM D2x, D1x, D0x, ATSAMR, ATSAML and ATSAMC microcontroller families from Atmel include internal flash and use ARM's Cortex-M0+ core. Do not use for ATSAM D51 and E5x: use *Note atsame5::. The devices have one flash bank: flash bank $_FLASHNAME at91samd 0x00000000 0 1 1 $_TARGETNAME -- Command: at91samd chip-erase Issues a complete Flash erase via the Device Service Unit (DSU). This can be used to erase a chip back to its factory state and does not require the processor to be halted. -- Command: at91samd set-security Secures the Flash via the Set Security Bit (SSB) command. This prevents access to the Flash and can only be undone by using the chip-erase command which erases the Flash contents and turns off the security bit. Warning: at this time, openocd will not be able to communicate with a secured chip and it is therefore not possible to chip-erase it without using another tool. at91samd set-security enable -- Command: at91samd eeprom Shows or sets the EEPROM emulation size configuration, stored in the User Row of the Flash. When setting, the EEPROM size must be specified in bytes and it must be one of the permitted sizes according to the datasheet. Settings are written immediately but only take effect on MCU reset. EEPROM emulation requires additional firmware support and the minimum EEPROM size may not be the same as the minimum that the hardware supports. Set the EEPROM size to 0 in order to disable this feature. at91samd eeprom at91samd eeprom 1024 -- Command: at91samd bootloader Shows or sets the bootloader size configuration, stored in the User Row of the Flash. This is called the BOOTPROT region. When setting, the bootloader size must be specified in bytes and it must be one of the permitted sizes according to the datasheet. Settings are written immediately but only take effect on MCU reset. Setting the bootloader size to 0 disables bootloader protection. at91samd bootloader at91samd bootloader 16384 -- Command: at91samd dsu_reset_deassert This command releases internal reset held by DSU and prepares reset vector catch in case of reset halt. Command is used internally in event reset-deassert-post. -- Command: at91samd nvmuserrow Writes or reads the entire 64 bit wide NVM user row register which is located at 0x804000. This register includes various fuses lock-bits and factory calibration data. Reading the register is done by invoking this command without any arguments. Writing is possible by giving 1 or 2 hex values. The first argument is the register value to be written and the second one is an optional changemask. Every bit which value in changemask is 0 will stay unchanged. The lock- and reserved-bits are masked out and cannot be changed. # Read user row >at91samd nvmuserrow NVMUSERROW: 0xFFFFFC5DD8E0C788 # Write 0xFFFFFC5DD8E0C788 to user row >at91samd nvmuserrow 0xFFFFFC5DD8E0C788 # Write 0x12300 to user row but leave other bits and low # byte unchanged >at91samd nvmuserrow 0x12345 0xFFF00 -- Flash Driver: at91sam3 All members of the AT91SAM3 microcontroller family from Atmel include internal flash and use ARM's Cortex-M3 core. The driver currently (6/22/09) recognizes the AT91SAM3U[1/2/4][C/E] chips. Note that the driver was orginaly developed and tested using the AT91SAM3U4E, using a SAM3U-EK eval board. Support for other chips in the family was cribbed from the data sheet. _Note to future readers/updaters: Please remove this worrisome comment after other chips are confirmed._ The AT91SAM3U4[E/C] (256K) chips have two flash banks; most other chips have one flash bank. In all cases the flash banks are at the following fixed locations: # Flash bank 0 - all chips flash bank $_FLASHNAME at91sam3 0x00080000 0 1 1 $_TARGETNAME # Flash bank 1 - only 256K chips flash bank $_FLASHNAME at91sam3 0x00100000 0 1 1 $_TARGETNAME Internally, the AT91SAM3 flash memory is organized as follows. Unlike the AT91SAM7 chips, these are not used as parameters to the 'flash bank' command: * _N-Banks:_ 256K chips have 2 banks, others have 1 bank. * _Bank Size:_ 128K/64K Per flash bank * _Sectors:_ 16 or 8 per bank * _SectorSize:_ 8K Per Sector * _PageSize:_ 256 bytes per page. Note that OpenOCD operates on 'sector' sizes, not page sizes. The AT91SAM3 driver adds some additional commands: -- Command: at91sam3 gpnvm -- Command: at91sam3 gpnvm clear number -- Command: at91sam3 gpnvm set number -- Command: at91sam3 gpnvm show [all|number] With no parameters, 'show' or 'show all', shows the status of all GPNVM bits. With 'show' NUMBER, displays that bit. With 'set' NUMBER or 'clear' NUMBER, modifies that GPNVM bit. -- Command: at91sam3 info This command attempts to display information about the AT91SAM3 chip. _First_ it read the 'CHIPID_CIDR' [address 0x400e0740, see Section 28.2.1, page 505 of the AT91SAM3U 29/may/2009 datasheet, document id: doc6430A] and decodes the values. _Second_ it reads the various clock configuration registers and attempts to display how it believes the chip is configured. By default, the SLOWCLK is assumed to be 32768 Hz, see the command 'at91sam3 slowclk'. -- Command: at91sam3 slowclk [value] This command shows/sets the slow clock frequency used in the 'at91sam3 info' command calculations above. -- Flash Driver: at91sam4 All members of the AT91SAM4 microcontroller family from Atmel include internal flash and use ARM's Cortex-M4 core. This driver uses the same command names/syntax as *Note at91sam3::. -- Flash Driver: at91sam4l All members of the AT91SAM4L microcontroller family from Atmel include internal flash and use ARM's Cortex-M4 core. This driver uses the same command names/syntax as *Note at91sam3::. The AT91SAM4L driver adds some additional commands: -- Command: at91sam4l smap_reset_deassert This command releases internal reset held by SMAP and prepares reset vector catch in case of reset halt. Command is used internally in event reset-deassert-post. -- Flash Driver: atsame5 All members of the SAM E54, E53, E51 and D51 microcontroller families from Microchip (former Atmel) include internal flash and use ARM's Cortex-M4 core. The devices have two ECC flash banks with a swapping feature. This driver handles both banks together as it were one. Bank swapping is not supported yet. flash bank $_FLASHNAME atsame5 0x00000000 0 1 1 $_TARGETNAME -- Command: atsame5 bootloader Shows or sets the bootloader size configuration, stored in the User Page of the Flash. This is called the BOOTPROT region. When setting, the bootloader size must be specified in bytes. The nearest bigger protection size is used. Settings are written immediately but only take effect on MCU reset. Setting the bootloader size to 0 disables bootloader protection. atsame5 bootloader atsame5 bootloader 16384 -- Command: atsame5 chip-erase Issues a complete Flash erase via the Device Service Unit (DSU). This can be used to erase a chip back to its factory state and does not require the processor to be halted. -- Command: atsame5 dsu_reset_deassert This command releases internal reset held by DSU and prepares reset vector catch in case of reset halt. Command is used internally in event reset-deassert-post. -- Command: atsame5 userpage Writes or reads the first 64 bits of NVM User Page which is located at 0x804000. This field includes various fuses. Reading is done by invoking this command without any arguments. Writing is possible by giving 1 or 2 hex values. The first argument is the value to be written and the second one is an optional bit mask (a zero bit in the mask means the bit stays unchanged). The reserved fields are always masked out and cannot be changed. # Read >atsame5 userpage USER PAGE: 0xAEECFF80FE9A9239 # Write >atsame5 userpage 0xAEECFF80FE9A9239 # Write 2 to SEESBLK and 4 to SEEPSZ fields but leave other # bits unchanged (setup SmartEEPROM of virtual size 8192 # bytes) >atsame5 userpage 0x4200000000 0x7f00000000 -- Flash Driver: atsamv All members of the ATSAMV7x, ATSAMS70, and ATSAME70 families from Atmel include internal flash and use ARM's Cortex-M7 core. This driver uses the same command names/syntax as *Note at91sam3::. flash bank $_FLASHNAME atsamv 0x00400000 0 0 0 $_TARGETNAME -- Command: atsamv gpnvm [show [all|number]] -- Command: atsamv gpnvm (clr|set) number With no parameters, 'show' or 'show all', shows the status of all GPNVM bits. With 'show' NUMBER, displays that bit. With 'set' NUMBER or 'clear' NUMBER, modifies that GPNVM bit. -- Flash Driver: at91sam7 All members of the AT91SAM7 microcontroller family from Atmel include internal flash and use ARM7TDMI cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. flash bank $_FLASHNAME at91sam7 0 0 0 0 $_TARGETNAME For chips which are not recognized by the controller driver, you must provide additional parameters in the following order: * CHIP_MODEL ... label used with 'flash info' * BANKS * SECTORS_PER_BANK * PAGES_PER_SECTOR * PAGES_SIZE * NUM_NVM_BITS * FREQ_KHZ ... required if an external clock is provided, optional (but recommended) when the oscillator frequency is known It is recommended that you provide zeroes for all of those values except the clock frequency, so that everything except that frequency will be autoconfigured. Knowing the frequency helps ensure correct timings for flash access. The flash controller handles erases automatically on a page (128/256 byte) basis, so explicit erase commands are not necessary for flash programming. However, there is an "EraseAll" command that can erase an entire flash plane (of up to 256KB), and it will be used automatically when you issue 'flash erase_sector' or 'flash erase_address' commands. -- Command: at91sam7 gpnvm bitnum (set|clear) Set or clear a "General Purpose Non-Volatile Memory" (GPNVM) bit for the processor. Each processor has a number of such bits, used for controlling features such as brownout detection (so they are not truly general purpose). Note: This assumes that the first flash bank (number 0) is associated with the appropriate at91sam7 target. -- Flash Driver: avr The AVR 8-bit microcontrollers from Atmel integrate flash memory. _The current implementation is incomplete._ -- Flash Driver: bluenrg-x STMicroelectronics BlueNRG-1, BlueNRG-2 and BlueNRG-LP/LPS Bluetooth low energy wireless system-on-chip. They include ARM Cortex-M0/M0+ core and internal flash memory. The driver automatically recognizes these chips using the chip identification registers, and autoconfigures itself. flash bank $_FLASHNAME bluenrg-x 0 0 0 0 $_TARGETNAME Note that when users ask to erase all the sectors of the flash, a mass erase command is used which is faster than erasing each single sector one by one. flash erase_sector 0 0 last # It will perform a mass erase Triggering a mass erase is also useful when users want to disable readout protection. -- Flash Driver: cc26xx All versions of the SimpleLink CC13xx and CC26xx microcontrollers from Texas Instruments include internal flash. The cc26xx flash driver supports both the CC13xx and CC26xx family of devices. The driver automatically recognizes the specific version's flash parameters and autoconfigures itself. The flash bank starts at address 0. flash bank $_FLASHNAME cc26xx 0 0 0 0 $_TARGETNAME -- Flash Driver: cc3220sf The CC3220SF version of the SimpleLink CC32xx microcontrollers from Texas Instruments includes 1MB of internal flash. The cc3220sf flash driver only supports the internal flash. The serial flash on SimpleLink boards is programmed via the bootloader over a UART connection. Security features of the CC3220SF may erase the internal flash during power on reset. Refer to documentation at for details on security features and programming the serial flash. flash bank $_FLASHNAME cc3220sf 0 0 0 0 $_TARGETNAME -- Flash Driver: efm32 All members of the EFM32/EFR32 microcontroller family from Energy Micro (now Silicon Labs) include internal flash and use Arm Cortex-M3 or Cortex-M4 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. flash bank $_FLASHNAME efm32 0 0 0 0 $_TARGETNAME It supports writing to the user data page, as well as the portion of the lockbits page past 512 bytes on chips with larger page sizes. The latter is used by the SiLabs bootloader/AppLoader system for encryption keys. Setting protection on these pages is currently not supported. flash bank userdata.flash efm32 0x0FE00000 0 0 0 $_TARGETNAME flash bank lockbits.flash efm32 0x0FE04000 0 0 0 $_TARGETNAME A special feature of efm32 controllers is that it is possible to completely disable the debug interface by writing the correct values to the 'Debug Lock Word'. OpenOCD supports this via the following command: efm32 debuglock num The NUM parameter is a value shown by 'flash banks'. Note that in order for this command to take effect, the target needs to be reset. _The current implementation is incomplete. Unprotecting flash pages is not supported._ -- Flash Driver: esirisc Members of the eSi-RISC family may optionally include internal flash programmed via the eSi-TSMC Flash interface. Additional parameters are required to configure the driver: 'cfg_address' is the base address of the configuration register interface, 'clock_hz' is the expected clock frequency, and 'wait_states' is the number of configured read wait states. flash bank $_FLASHNAME esirisc base_address size_bytes 0 0 \ $_TARGETNAME cfg_address clock_hz wait_states -- Command: esirisc flash mass_erase bank_id Erase all pages in data memory for the bank identified by 'bank_id'. -- Command: esirisc flash ref_erase bank_id Erase the reference cell for the bank identified by 'bank_id'. _This is an uncommon operation._ -- Flash Driver: fm3 All members of the FM3 microcontroller family from Fujitsu include internal flash and use ARM Cortex-M3 cores. The FM3 driver uses the TARGET parameter to select the correct bank config, it can currently be one of the following: 'mb9bfxx1.cpu', 'mb9bfxx2.cpu', 'mb9bfxx3.cpu', 'mb9bfxx4.cpu', 'mb9bfxx5.cpu' or 'mb9bfxx6.cpu'. flash bank $_FLASHNAME fm3 0 0 0 0 $_TARGETNAME -- Flash Driver: fm4 All members of the FM4 microcontroller family from Spansion (formerly Fujitsu) include internal flash and use ARM Cortex-M4 cores. The FM4 driver uses a FAMILY parameter to select the correct bank config, it can currently be one of the following: 'MB9BFx64', 'MB9BFx65', 'MB9BFx66', 'MB9BFx67', 'MB9BFx68', 'S6E2Cx8', 'S6E2Cx9', 'S6E2CxA' or 'S6E2Dx', with 'x' treated as wildcard and otherwise case (and any trailing characters) ignored. flash bank ${_FLASHNAME}0 fm4 0x00000000 0 0 0 \ $_TARGETNAME S6E2CCAJ0A flash bank ${_FLASHNAME}1 fm4 0x00100000 0 0 0 \ $_TARGETNAME S6E2CCAJ0A _The current implementation is incomplete. Protection is not supported, nor is Chip Erase (only Sector Erase is implemented)._ -- Flash Driver: kinetis Kx, KLx, KVx and KE1x members of the Kinetis microcontroller family from NXP (former Freescale) include internal flash and use ARM Cortex-M0+ or M4 cores. The driver automatically recognizes flash size and a number of flash banks (1-4) using the chip identification register, and autoconfigures itself. Use kinetis_ke driver for KE0x and KEAx devices. The KINETIS driver defines option: * -sim-base ADDR ... base of System Integration Module where chip identification resides. Driver tries two known locations if option is omitted. flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME -- Config Command: kinetis create_banks Configuration command enables automatic creation of additional flash banks based on real flash layout of device. Banks are created during device probe. Use 'flash probe 0' to force probe. -- Command: kinetis fcf_source [protection|write] Select what source is used when writing to a Flash Configuration Field. 'protection' mode builds FCF content from protection bits previously set by 'flash protect' command. This mode is default. MCU is protected from unwanted locking by immediate writing FCF after erase of relevant sector. 'write' mode enables direct write to FCF. Protection cannot be set by 'flash protect' command. FCF is written along with the rest of a flash image. _BEWARE: Incorrect flash configuration may permanently lock the device!_ -- Command: kinetis fopt [num] Set value to write to FOPT byte of Flash Configuration Field. Used in kinetis 'fcf_source protection' mode only. -- Command: kinetis mdm check_security Checks status of device security lock. Used internally in examine-end and examine-fail event. -- Command: kinetis mdm halt Issues a halt via the MDM-AP. This command can be used to break a watchdog reset loop when connecting to an unsecured target. -- Command: kinetis mdm mass_erase Issues a complete flash erase via the MDM-AP. This can be used to erase a chip back to its factory state, removing security. It does not require the processor to be halted, however the target will remain in a halted state after this command completes. -- Command: kinetis nvm_partition For FlexNVM devices only (KxxDX and KxxFX). Command shows or sets data flash or EEPROM backup size in kilobytes, sets two EEPROM blocks sizes in bytes and enables/disables loading of EEPROM contents to FlexRAM during reset. For details see device reference manual, Flash Memory Module, Program Partition command. Setting is possible only once after mass_erase. Reset the device after partition setting. Show partition size: kinetis nvm_partition info Set 32 KB data flash, rest of FlexNVM is EEPROM backup. EEPROM has two blocks of 512 and 1536 bytes and its contents is loaded to FlexRAM during reset: kinetis nvm_partition dataflash 32 512 1536 on Set 16 KB EEPROM backup, rest of FlexNVM is a data flash. EEPROM has two blocks of 1024 bytes and its contents is not loaded to FlexRAM during reset: kinetis nvm_partition eebkp 16 1024 1024 off -- Command: kinetis mdm reset Issues a reset via the MDM-AP. This causes the MCU to output a low pulse on the RESET pin, which can be used to reset other hardware on board. -- Command: kinetis disable_wdog For Kx devices only (KLx has different COP watchdog, it is not supported). Command disables watchdog timer. -- Flash Driver: kinetis_ke KE0x and KEAx members of the Kinetis microcontroller family from NXP include internal flash and use ARM Cortex-M0+. The driver automatically recognizes the KE0x sub-family using the chip identification register, and autoconfigures itself. Use kinetis (not kinetis_ke) driver for KE1x devices. flash bank $_FLASHNAME kinetis_ke 0 0 0 0 $_TARGETNAME -- Command: kinetis_ke mdm check_security Checks status of device security lock. Used internally in examine-end event. -- Command: kinetis_ke mdm mass_erase Issues a complete Flash erase via the MDM-AP. This can be used to erase a chip back to its factory state. Command removes security lock from a device (use of SRST highly recommended). It does not require the processor to be halted. -- Command: kinetis_ke disable_wdog Command disables watchdog timer. -- Flash Driver: lpc2000 This is the driver to support internal flash of all members of the LPC11(x)00 and LPC1300 microcontroller families and most members of the LPC800, LPC1500, LPC1700, LPC1800, LPC2000, LPC4000, LPC54100, LPC8Nxx and NHS31xx microcontroller families from NXP. Note: There are LPC2000 devices which are not supported by the LPC2000 driver: The LPC2888 is supported by the LPC288X driver. The LPC29xx family is supported by the LPC2900 driver. The LPC2000 driver defines two mandatory and two optional parameters, which must appear in the following order: * VARIANT ... required, may be 'lpc2000_v1' (older LPC21xx and LPC22xx) 'lpc2000_v2' (LPC213x, LPC214x, LPC210[123], LPC23xx and LPC24xx) 'lpc1700' (LPC175x and LPC176x and LPC177x/8x) 'lpc4300' - available also as 'lpc1800' alias (LPC18x[2357] and LPC43x[2357]) 'lpc800' (LPC8xx) 'lpc1100' (LPC11(x)xx and LPC13xx) 'lpc1500' (LPC15xx) 'lpc54100' (LPC541xx) 'lpc4000' (LPC40xx) or 'auto' - automatically detects flash variant and size for LPC11(x)00, LPC8xx, LPC13xx, LPC17xx, LPC40xx, LPC8Nxx and NHS31xx * CLOCK_KHZ ... the frequency, in kiloHertz, at which the core is running * 'calc_checksum' ... optional (but you probably want to provide this!), telling the driver to calculate a valid checksum for the exception vector table. Note: If you don't provide 'calc_checksum' when you're writing the vector table, the boot ROM will almost certainly ignore your flash image. However, if you do provide it, with most tool chains 'verify_image' will fail. * 'iap_entry' ... optional telling the driver to use a different ROM IAP entry point. LPC flashes don't require the chip and bus width to be specified. flash bank $_FLASHNAME lpc2000 0x0 0x7d000 0 0 $_TARGETNAME \ lpc2000_v2 14765 calc_checksum -- Command: lpc2000 part_id bank Displays the four byte part identifier associated with the specified flash BANK. -- Flash Driver: lpc288x The LPC2888 microcontroller from NXP needs slightly different flash support from its lpc2000 siblings. The LPC288X driver defines one mandatory parameter, the programming clock rate in Hz. LPC flashes don't require the chip and bus width to be specified. flash bank $_FLASHNAME lpc288x 0 0 0 0 $_TARGETNAME 12000000 -- Flash Driver: lpc2900 This driver supports the LPC29xx ARM968E based microcontroller family from NXP. The predefined parameters BASE, SIZE, CHIP_WIDTH and BUS_WIDTH of the 'flash bank' command are ignored. Flash size and sector layout are auto-configured by the driver. The driver has one additional mandatory parameter: The CPU clock rate (in kHz) at the time the flash operations will take place. Most of the time this will not be the crystal frequency, but a higher PLL frequency. The 'reset-init' event handler in the board script is usually the place where you start the PLL. The driver rejects flashless devices (currently the LPC2930). The EEPROM in LPC2900 devices is not mapped directly into the address space. It must be handled much more like NAND flash memory, and will therefore be handled by a separate 'lpc2900_eeprom' driver (not yet available). Sector protection in terms of the LPC2900 is handled transparently. Every time a sector needs to be erased or programmed, it is automatically unprotected. What is shown as protection status in the 'flash info' command, is actually the LPC2900 _sector security_. This is a mechanism to prevent a sector from ever being erased or programmed again. As this is an irreversible mechanism, it is handled by a special command ('lpc2900 secure_sector'), and not by the standard 'flash protect' command. Example for a 125 MHz clock frequency: flash bank $_FLASHNAME lpc2900 0 0 0 0 $_TARGETNAME 125000 Some 'lpc2900'-specific commands are defined. In the following command list, the BANK parameter is the bank number as obtained by the 'flash banks' command. -- Command: lpc2900 signature bank Calculates a 128-bit hash value, the _signature_, from the whole flash content. This is a hardware feature of the flash block, hence the calculation is very fast. You may use this to verify the content of a programmed device against a known signature. Example: lpc2900 signature 0 signature: 0x5f40cdc8:0xc64e592e:0x10490f89:0x32a0f317 -- Command: lpc2900 read_custom bank filename Reads the 912 bytes of customer information from the flash index sector, and saves it to a file in binary format. Example: lpc2900 read_custom 0 /path_to/customer_info.bin The index sector of the flash is a _write-only_ sector. It cannot be erased! In order to guard against unintentional write access, all following commands need to be preceded by a successful call to the 'password' command: -- Command: lpc2900 password bank password You need to use this command right before each of the following commands: 'lpc2900 write_custom', 'lpc2900 secure_sector', 'lpc2900 secure_jtag'. The password string is fixed to "I_know_what_I_am_doing". Example: lpc2900 password 0 I_know_what_I_am_doing Potentially dangerous operation allowed in next command! -- Command: lpc2900 write_custom bank filename type Writes the content of the file into the customer info space of the flash index sector. The filetype can be specified with the TYPE field. Possible values for TYPE are: BIN (binary), IHEX (Intel hex format), ELF (ELF binary) or S19 (Motorola S-records). The file must contain a single section, and the contained data length must be exactly 912 bytes. Attention: This cannot be reverted! Be careful! Example: lpc2900 write_custom 0 /path_to/customer_info.bin bin -- Command: lpc2900 secure_sector bank first last Secures the sector range from FIRST to LAST (including) against further program and erase operations. The sector security will be effective after the next power cycle. Attention: This cannot be reverted! Be careful! Secured sectors appear as _protected_ in the 'flash info' command. Example: lpc2900 secure_sector 0 1 1 flash info 0 #0 : lpc2900 at 0x20000000, size 0x000c0000, (...) # 0: 0x00000000 (0x2000 8kB) not protected # 1: 0x00002000 (0x2000 8kB) protected # 2: 0x00004000 (0x2000 8kB) not protected -- Command: lpc2900 secure_jtag bank Irreversibly disable the JTAG port. The new JTAG security setting will be effective after the next power cycle. Attention: This cannot be reverted! Be careful! Examples: lpc2900 secure_jtag 0 -- Flash Driver: mdr This drivers handles the integrated NOR flash on Milandr Cortex-M based controllers. A known limitation is that the Info memory can't be read or verified as it's not memory mapped. flash bank mdr \ 0 0 TYPE PAGE_COUNT SEC_COUNT * TYPE - 0 for main memory, 1 for info memory * PAGE_COUNT - total number of pages * SEC_COUNT - number of sector per page count Example usage: if { [info exists IMEMORY] && [string equal $IMEMORY true] } { flash bank ${_CHIPNAME}_info.flash mdr 0x00000000 0x01000 \ 0 0 $_TARGETNAME 1 1 4 } else { flash bank $_CHIPNAME.flash mdr 0x00000000 0x20000 \ 0 0 $_TARGETNAME 0 32 4 } -- Flash Driver: msp432 All versions of the SimpleLink MSP432 microcontrollers from Texas Instruments include internal flash. The msp432 flash driver automatically recognizes the specific version's flash parameters and autoconfigures itself. Main program flash starts at address 0. The information flash region on MSP432P4 versions starts at address 0x200000. flash bank $_FLASHNAME msp432 0 0 0 0 $_TARGETNAME -- Command: msp432 mass_erase bank_id [main|all] Performs a complete erase of flash. By default, 'mass_erase' will erase only the main program flash. On MSP432P4 versions, using 'mass_erase all' will erase both the main program and information flash regions. To also erase the BSL in information flash, the user must first use the 'bsl' command. -- Command: msp432 bsl bank_id [unlock|lock] On MSP432P4 versions, 'bsl' unlocks and locks the bootstrap loader (BSL) region in information flash so that flash commands can erase or write the BSL. Leave the BSL locked to prevent accidentally corrupting the bootstrap loader. To erase and program the BSL: msp432 bsl unlock flash erase_address 0x202000 0x2000 flash write_image bsl.bin 0x202000 msp432 bsl lock -- Flash Driver: niietcm4 This drivers handles the integrated NOR flash on NIIET Cortex-M4 based controllers. Flash size and sector layout are auto-configured by the driver. Main flash memory is called "Bootflash" and has main region and info region. Info region is NOT memory mapped by default, but it can replace first part of main region if needed. Full erase, single and block writes are supported for both main and info regions. There is additional not memory mapped flash called "Userflash", which also have division into regions: main and info. Purpose of userflash - to store system and user settings. Driver has special commands to perform operations with this memory. flash bank $_FLASHNAME niietcm4 0 0 0 0 $_TARGETNAME Some niietcm4-specific commands are defined: -- Command: niietcm4 uflash_read_byte bank ('main'|'info') address Read byte from main or info userflash region. -- Command: niietcm4 uflash_write_byte bank ('main'|'info') address value Write byte to main or info userflash region. -- Command: niietcm4 uflash_full_erase bank Erase all userflash including info region. -- Command: niietcm4 uflash_erase bank ('main'|'info') first_sector last_sector Erase sectors of main or info userflash region, starting at sector first up to and including last. -- Command: niietcm4 uflash_protect_check bank ('main'|'info') Check sectors protect. -- Command: niietcm4 uflash_protect bank ('main'|'info') first_sector last_sector ('on'|'off') Protect sectors of main or info userflash region, starting at sector first up to and including last. -- Command: niietcm4 bflash_info_remap bank ('on'|'off') Enable remapping bootflash info region to 0x00000000 (or 0x40000000 if external memory boot used). -- Command: niietcm4 extmem_cfg bank ('gpioa'|'gpiob'|'gpioc'|'gpiod'|'gpioe'|'gpiof'|'gpiog'|'gpioh') pin_num ('func1'|'func3') Configure external memory interface for boot. -- Command: niietcm4 service_mode_erase bank Perform emergency erase of all flash (bootflash and userflash). -- Command: niietcm4 driver_info bank Show information about flash driver. -- Flash Driver: npcx All versions of the NPCX microcontroller families from Nuvoton include internal flash. The NPCX flash driver supports the NPCX family of devices. The driver automatically recognizes the specific version's flash parameters and autoconfigures itself. The flash bank starts at address 0x64000000. flash bank $_FLASHNAME npcx 0x64000000 0 0 0 $_TARGETNAME -- Flash Driver: nrf5 All members of the nRF51 microcontroller families from Nordic Semiconductor include internal flash and use ARM Cortex-M0 core. nRF52 family powered by ARM Cortex-M4 or M4F core is supported too. nRF52832 is fully supported including BPROT flash protection scheme. nRF52833 and nRF52840 devices are supported with the exception of security extensions (flash access control list - ACL). flash bank $_FLASHNAME nrf5 0 0x00000000 0 0 $_TARGETNAME Some nrf5-specific commands are defined: -- Command: nrf5 mass_erase Erases the contents of the code memory and user information configuration registers as well. It must be noted that this command works only for chips that do not have factory pre-programmed region 0 code. -- Command: nrf5 info Decodes and shows information from FICR and UICR registers. -- Flash Driver: ocl This driver is an implementation of the "on chip flash loader" protocol proposed by Pavel Chromy. It is a minimalistic command-response protocol intended to be used over a DCC when communicating with an internal or external flash loader running from RAM. An example implementation for AT91SAM7x is available in 'contrib/loaders/flash/at91sam7x/'. flash bank $_FLASHNAME ocl 0 0 0 0 $_TARGETNAME -- Flash Driver: pic32mx The PIC32MX microcontrollers are based on the MIPS 4K cores, and integrate flash memory. flash bank $_FLASHNAME pix32mx 0x1fc00000 0 0 0 $_TARGETNAME flash bank $_FLASHNAME pix32mx 0x1d000000 0 0 0 $_TARGETNAME Some pic32mx-specific commands are defined: -- Command: pic32mx pgm_word address value bank Programs the specified 32-bit VALUE at the given ADDRESS in the specified chip BANK. -- Command: pic32mx unlock bank Unlock and erase specified chip BANK. This will remove any Code Protection. -- Flash Driver: psoc4 All members of the PSoC 41xx/42xx microcontroller family from Cypress include internal flash and use ARM Cortex-M0 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. Note: Erased internal flash reads as 00. System ROM of PSoC 4 does not implement erase of a flash sector. flash bank $_FLASHNAME psoc4 0 0 0 0 $_TARGETNAME psoc4-specific commands -- Command: psoc4 flash_autoerase num (on|off) Enables or disables autoerase mode for a flash bank. If flash_autoerase is off, use mass_erase before flash programming. Flash erase command fails if region to erase is not whole flash memory. If flash_autoerase is on, a sector is both erased and programmed in one system ROM call. Flash erase command is ignored. This mode is suitable for gdb load. The NUM parameter is a value shown by 'flash banks'. -- Command: psoc4 mass_erase num Erases the contents of the flash memory, protection and security lock. The NUM parameter is a value shown by 'flash banks'. -- Flash Driver: psoc5lp All members of the PSoC 5LP microcontroller family from Cypress include internal program flash and use ARM Cortex-M3 cores. The driver probes for a number of these chips and autoconfigures itself, apart from the base address. flash bank $_FLASHNAME psoc5lp 0x00000000 0 0 0 $_TARGETNAME Note: PSoC 5LP chips can be configured to have ECC enabled or disabled. Attention: If flash operations are performed in ECC-disabled mode, they will also affect the ECC flash region. Erasing a 16k flash sector in the 0x00000000 area will then also erase the corresponding 2k data bytes in the 0x48000000 area. Writing to the ECC data bytes in ECC-disabled mode is not implemented. Commands defined in the PSOC5LP driver: -- Command: psoc5lp mass_erase Erases all flash data and ECC/configuration bytes, all flash protection rows, and all row latches in all flash arrays on the device. -- Flash Driver: psoc5lp_eeprom All members of the PSoC 5LP microcontroller family from Cypress include internal EEPROM and use ARM Cortex-M3 cores. The driver probes for a number of these chips and autoconfigures itself, apart from the base address. flash bank $_CHIPNAME.eeprom psoc5lp_eeprom 0x40008000 0 0 0 \ $_TARGETNAME -- Flash Driver: psoc5lp_nvl All members of the PSoC 5LP microcontroller family from Cypress include internal Nonvolatile Latches and use ARM Cortex-M3 cores. The driver probes for a number of these chips and autoconfigures itself. flash bank $_CHIPNAME.nvl psoc5lp_nvl 0 0 0 0 $_TARGETNAME PSoC 5LP chips have multiple NV Latches: * Device Configuration NV Latch - 4 bytes * Write Once (WO) NV Latch - 4 bytes Note: This driver only implements the Device Configuration NVL. The PSOC5LP driver reads the ECC mode from Device Configuration NVL. Attention: Switching ECC mode via write to Device Configuration NVL will require a reset after successful write. -- Flash Driver: psoc6 Supports PSoC6 (CY8C6xxx) family of Cypress microcontrollers. PSoC6 is a dual-core device with CM0+ and CM4 cores. Both cores share the same Flash/RAM/MMIO address space. Flash in PSoC6 is split into three regions: * Main Flash - this is the main storage for user application. Total size varies among devices, sector size: 256 kBytes, row size: 512 bytes. Supports erase operation on individual rows. * Work Flash - intended to be used as storage for user data (e.g. EEPROM emulation). Total size: 32 KBytes, sector size: 32 KBytes, row size: 512 bytes. * Supervisory Flash - special region which contains device-specific service data. This region does not support erase operation. Only few rows can be programmed by the user, most of the rows are read only. Programming operation will erase row automatically. All three flash regions are supported by the driver. Flash geometry is detected automatically by parsing data in SPCIF_GEOMETRY register. PSoC6 is equipped with NOR Flash so erased Flash reads as 0x00. flash bank main_flash_cm0 psoc6 0x10000000 0 0 0 \ ${TARGET}.cm0 flash bank work_flash_cm0 psoc6 0x14000000 0 0 0 \ ${TARGET}.cm0 flash bank super_flash_user_cm0 psoc6 0x16000800 0 0 0 \ ${TARGET}.cm0 flash bank super_flash_nar_cm0 psoc6 0x16001A00 0 0 0 \ ${TARGET}.cm0 flash bank super_flash_key_cm0 psoc6 0x16005A00 0 0 0 \ ${TARGET}.cm0 flash bank super_flash_toc2_cm0 psoc6 0x16007C00 0 0 0 \ ${TARGET}.cm0 flash bank main_flash_cm4 psoc6 0x10000000 0 0 0 \ ${TARGET}.cm4 flash bank work_flash_cm4 psoc6 0x14000000 0 0 0 \ ${TARGET}.cm4 flash bank super_flash_user_cm4 psoc6 0x16000800 0 0 0 \ ${TARGET}.cm4 flash bank super_flash_nar_cm4 psoc6 0x16001A00 0 0 0 \ ${TARGET}.cm4 flash bank super_flash_key_cm4 psoc6 0x16005A00 0 0 0 \ ${TARGET}.cm4 flash bank super_flash_toc2_cm4 psoc6 0x16007C00 0 0 0 \ ${TARGET}.cm4 psoc6-specific commands -- Command: psoc6 reset_halt Command can be used to simulate broken Vector Catch from gdbinit or tcl scripts. When invoked for CM0+ target, it will set break point at application entry point and issue SYSRESETREQ. This will reset both cores and all peripherals. CM0+ will reset CM4 during boot anyway so this is safe. On CM4 target, VECTRESET is used instead of SYSRESETREQ to avoid unwanted reset of CM0+; -- Command: psoc6 mass_erase num Erases the contents given flash bank. The NUM parameter is a value shown by 'flash banks'. Note: only Main and Work flash regions support Erase operation. -- Flash Driver: rp2040 Supports RP2040 "Raspberry Pi Pico" microcontroller. RP2040 is a dual-core device with two CM0+ cores. Both cores share the same Flash/RAM/MMIO address space. Non-volatile storage is achieved with an external QSPI flash; a Boot ROM provides helper functions. flash bank $_FLASHNAME rp2040_flash $_FLASHBASE $_FLASHSIZE 1 32 $_TARGETNAME -- Flash Driver: sim3x All members of the SiM3 microcontroller family from Silicon Laboratories include internal flash and use ARM Cortex-M3 cores. It supports both JTAG and SWD interface. The SIM3X driver tries to probe the device to auto detect the MCU. If this fails, it will use the SIZE parameter as the size of flash bank. flash bank $_FLASHNAME sim3x 0 $_CPUROMSIZE 0 0 $_TARGETNAME There are 2 commands defined in the SIM3X driver: -- Command: sim3x mass_erase Erases the complete flash. This is used to unlock the flash. And this command is only possible when using the SWD interface. -- Command: sim3x lock Lock the flash. To unlock use the 'sim3x mass_erase' command. -- Flash Driver: stellaris All members of the Stellaris LM3Sxxx, LM4x and Tiva C microcontroller families from Texas Instruments include internal flash. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. flash bank $_FLASHNAME stellaris 0 0 0 0 $_TARGETNAME -- Command: stellaris recover Performs the _Recovering a "Locked" Device_ procedure to restore the flash and its associated nonvolatile registers to their factory default values (erased). This is the only way to remove flash protection or re-enable debugging if that capability has been disabled. Note that the final "power cycle the chip" step in this procedure must be performed by hand, since OpenOCD can't do it. Warning: if more than one Stellaris chip is connected, the procedure is applied to all of them. -- Flash Driver: stm32f1x All members of the STM32F0, STM32F1 and STM32F3 microcontroller families from STMicroelectronics and all members of the GD32F1x0, GD32F3x0 and GD32E23x microcontroller families from GigaDevice include internal flash and use ARM Cortex-M0/M3/M4/M23 cores. The driver also works with GD32VF103 powered by RISC-V core. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. flash bank $_FLASHNAME stm32f1x 0 0 0 0 $_TARGETNAME Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. flash bank $_FLASHNAME stm32f1x 0 0x20000 0 0 $_TARGETNAME If you have a target with dual flash banks then define the second bank as per the following example. flash bank $_FLASHNAME stm32f1x 0x08080000 0 0 0 $_TARGETNAME Some stm32f1x-specific commands are defined: -- Command: stm32f1x lock num Locks the entire stm32 device against reading. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32f1x unlock num Unlocks the entire stm32 device for reading. This command will cause a mass erase of the entire stm32 device if previously locked. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32f1x mass_erase num Mass erases the entire stm32 device. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32f1x options_read num Reads and displays active stm32 option bytes loaded during POR or upon executing the 'stm32f1x options_load' command. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32f1x options_write num (SWWDG|HWWDG) (RSTSTNDBY|NORSTSTNDBY) (RSTSTOP|NORSTSTOP) (USEROPT user_data) Writes the stm32 option byte with the specified values. The NUM parameter is a value shown by 'flash banks'. The USER_DATA parameter is content of higher 16 bits of the option byte register (Data0 and Data1 as one 16bit number). -- Command: stm32f1x options_load num Generates a special kind of reset to re-load the stm32 option bytes written by the 'stm32f1x options_write' or 'flash protect' commands without having to power cycle the target. Not applicable to stm32f1x devices. The NUM parameter is a value shown by 'flash banks'. -- Flash Driver: stm32f2x All members of the STM32F2, STM32F4 and STM32F7 microcontroller families from STMicroelectronics include internal flash and use ARM Cortex-M3/M4/M7 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME If you use OTP (One-Time Programmable) memory define it as a second bank as per the following example. flash bank $_FLASHNAME stm32f2x 0x1FFF7800 0 0 0 $_TARGETNAME -- Command: stm32f2x otp num (enable|disable|show) Enables or disables OTP write commands for bank NUM. The NUM parameter is a value shown by 'flash banks'. Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. flash bank $_FLASHNAME stm32f2x 0 0x20000 0 0 $_TARGETNAME Some stm32f2x-specific commands are defined: -- Command: stm32f2x lock num Locks the entire stm32 device. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32f2x unlock num Unlocks the entire stm32 device. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32f2x mass_erase num Mass erases the entire stm32f2x device. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32f2x options_read num Reads and displays user options and (where implemented) boot_addr0, boot_addr1, optcr2. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32f2x options_write num user_options boot_addr0 boot_addr1 Writes user options and (where implemented) boot_addr0 and boot_addr1 in raw format. Warning: The meaning of the various bits depends on the device, always check datasheet! The NUM parameter is a value shown by 'flash banks', USER_OPTIONS a 12 bit value, consisting of bits 31-28 and 7-0 of FLASH_OPTCR, BOOT_ADDR0 and BOOT_ADDR1 two halfwords (of FLASH_OPTCR1). -- Command: stm32f2x optcr2_write num optcr2 Writes FLASH_OPTCR2 options. Warning: Clearing PCROPi bits requires a full mass erase! The NUM parameter is a value shown by 'flash banks', OPTCR2 a 32-bit word. -- Flash Driver: stm32h7x All members of the STM32H7 microcontroller families from STMicroelectronics include internal flash and use ARM Cortex-M7 core. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. flash bank $_FLASHNAME stm32h7x 0 0 0 0 $_TARGETNAME Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. flash bank $_FLASHNAME stm32h7x 0 0x20000 0 0 $_TARGETNAME Some stm32h7x-specific commands are defined: -- Command: stm32h7x lock num Locks the entire stm32 device. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32h7x unlock num Unlocks the entire stm32 device. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32h7x mass_erase num Mass erases the entire stm32h7x device. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32h7x option_read num reg_offset Reads an option byte register from the stm32h7x device. The NUM parameter is a value shown by 'flash banks', REG_OFFSET is the register offset of the option byte to read from the used bank registers' base. For example: in STM32H74x/H75x the bank 1 registers' base is 0x52002000 and 0x52002100 for bank 2. Example usage: # read OPTSR_CUR stm32h7x option_read 0 0x1c # read WPSN_CUR1R stm32h7x option_read 0 0x38 # read WPSN_CUR2R stm32h7x option_read 1 0x38 -- Command: stm32h7x option_write num reg_offset value [reg_mask] Writes an option byte register of the stm32h7x device. The NUM parameter is a value shown by 'flash banks', REG_OFFSET is the register offset of the option byte to write from the used bank register base, and REG_MASK is the mask to apply when writing the register (only bits with a '1' will be touched). Example usage: # swap bank 1 and bank 2 in dual bank devices # by setting SWAP_BANK_OPT bit in OPTSR_PRG stm32h7x option_write 0 0x20 0x8000000 0x8000000 -- Flash Driver: stm32lx All members of the STM32L0 and STM32L1 microcontroller families from STMicroelectronics include internal flash and use ARM Cortex-M3 and Cortex-M0+ cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. flash bank $_FLASHNAME stm32lx 0 0 0 0 $_TARGETNAME Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. If you use 0 as the bank base address, it tells the driver to autodetect the bank location assuming you're configuring the second bank. flash bank $_FLASHNAME stm32lx 0x08000000 0x20000 0 0 $_TARGETNAME Some stm32lx-specific commands are defined: -- Command: stm32lx lock num Locks the entire stm32 device. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32lx unlock num Unlocks the entire stm32 device. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32lx mass_erase num Mass erases the entire stm32lx device (all flash banks and EEPROM data). This is the only way to unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). The NUM parameter is a value shown by 'flash banks'. -- Flash Driver: stm32l4x All members of the STM32 G0, G4, L4, L4+, L5, U5, WB and WL microcontroller families from STMicroelectronics include internal flash and use ARM Cortex-M0+, M4 and M33 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME If you use OTP (One-Time Programmable) memory define it as a second bank as per the following example. flash bank $_FLASHNAME stm32l4x 0x1FFF7000 0 0 0 $_TARGETNAME -- Command: stm32l4x otp num (enable|disable|show) Enables or disables OTP write commands for bank NUM. The NUM parameter is a value shown by 'flash banks'. Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. However, specifying a wrong value might lead to a completely wrong flash layout, so this feature must be used carefully. flash bank $_FLASHNAME stm32l4x 0x08000000 0x40000 0 0 $_TARGETNAME Some stm32l4x-specific commands are defined: -- Command: stm32l4x lock num Locks the entire stm32 device. The NUM parameter is a value shown by 'flash banks'. _Note:_ To apply the protection change immediately, use 'stm32l4x option_load'. -- Command: stm32l4x unlock num Unlocks the entire stm32 device. The NUM parameter is a value shown by 'flash banks'. _Note:_ To apply the protection change immediately, use 'stm32l4x option_load'. -- Command: stm32l4x mass_erase num Mass erases the entire stm32l4x device. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32l4x option_read num reg_offset Reads an option byte register from the stm32l4x device. The NUM parameter is a value shown by 'flash banks', REG_OFFSET is the register offset of the Option byte to read. For example to read the FLASH_OPTR register: stm32l4x option_read 0 0x20 # Option Register (for STM32L4x): <0x40022020> = 0xffeff8aa # Option Register (for STM32WBx): <0x58004020> = ... # The correct flash base address will be used automatically The above example will read out the FLASH_OPTR register which contains the RDP option byte, Watchdog configuration, BOR level etc. -- Command: stm32l4x option_write num reg_offset reg_mask Write an option byte register of the stm32l4x device. The NUM parameter is a value shown by 'flash banks', REG_OFFSET is the register offset of the Option byte to write, and REG_MASK is the mask to apply when writing the register (only bits with a '1' will be touched). _Note:_ To apply the option bytes change immediately, use 'stm32l4x option_load'. For example to write the WRP1AR option bytes: stm32l4x option_write 0 0x28 0x00FF0000 0x00FF00FF The above example will write the WRP1AR option register configuring the Write protection Area A for bank 1. The above example set WRP1AR_END=255, WRP1AR_START=0. This will effectively write protect all sectors in flash bank 1. -- Command: stm32l4x wrp_info num [device_bank] List the protected areas using WRP. The NUM parameter is a value shown by 'flash banks'. DEVICE_BANK parameter is optional, possible values 'bank1' or 'bank2', if not specified, the command will display the whole flash protected areas. Note: DEVICE_BANK is different from banks created using 'flash bank'. Devices supported in this flash driver, can have main flash memory organized in single or dual-banks mode. Thus the usage of DEVICE_BANK is meaningful only in dual-bank mode, to get write protected areas in a specific DEVICE_BANK -- Command: stm32l4x option_load num Forces a re-load of the option byte registers. Will cause a system reset of the device. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32l4x trustzone num [enable | disable] Enables or disables Global TrustZone Security, using the TZEN option bit. If neither 'enabled' nor 'disable' are specified, the command will display the TrustZone status. _Note:_ This command works only with devices with TrustZone, eg. STM32L5. _Note:_ This command will perform an OBL_Launch after modifying the TZEN. -- Flash Driver: str7x All members of the STR7 microcontroller family from STMicroelectronics include internal flash and use ARM7TDMI cores. The STR7X driver defines one mandatory parameter, VARIANT, which is either 'STR71x', 'STR73x' or 'STR75x'. flash bank $_FLASHNAME str7x \ 0x40000000 0x00040000 0 0 $_TARGETNAME STR71x -- Command: str7x disable_jtag bank Activate the Debug/Readout protection mechanism for the specified flash bank. -- Flash Driver: str9x Most members of the STR9 microcontroller family from STMicroelectronics include internal flash and use ARM966E cores. The str9 needs the flash controller to be configured using the 'str9x flash_config' command prior to Flash programming. flash bank $_FLASHNAME str9x 0x40000000 0x00040000 0 0 $_TARGETNAME str9x flash_config 0 4 2 0 0x80000 -- Command: str9x flash_config num bbsr nbbsr bbadr nbbadr Configures the str9 flash controller. The NUM parameter is a value shown by 'flash banks'. * BBSR - Boot Bank Size register * NBBSR - Non Boot Bank Size register * BBADR - Boot Bank Start Address register * NBBADR - Boot Bank Start Address register -- Flash Driver: str9xpec Only use this driver for locking/unlocking the device or configuring the option bytes. Use the standard str9 driver for programming. Before using the flash commands the turbo mode must be enabled using the 'str9xpec enable_turbo' command. Here is some background info to help you better understand how this driver works. OpenOCD has two flash drivers for the str9: 1. Standard driver 'str9x' programmed via the str9 core. Normally used for flash programming as it is faster than the 'str9xpec' driver. 2. Direct programming 'str9xpec' using the flash controller. This is an ISC compliant (IEEE 1532) tap connected in series with the str9 core. The str9 core does not need to be running to program using this flash driver. Typical use for this driver is locking/unlocking the target and programming the option bytes. Before we run any commands using the 'str9xpec' driver we must first disable the str9 core. This example assumes the 'str9xpec' driver has been configured for flash bank 0. # assert srst, we do not want core running # while accessing str9xpec flash driver adapter assert srst # turn off target polling poll off # disable str9 core str9xpec enable_turbo 0 # read option bytes str9xpec options_read 0 # re-enable str9 core str9xpec disable_turbo 0 poll on reset halt The above example will read the str9 option bytes. When performing a unlock remember that you will not be able to halt the str9 - it has been locked. Halting the core is not required for the 'str9xpec' driver as mentioned above, just issue the commands above manually or from a telnet prompt. Several str9xpec-specific commands are defined: -- Command: str9xpec disable_turbo num Restore the str9 into JTAG chain. -- Command: str9xpec enable_turbo num Enable turbo mode, will simply remove the str9 from the chain and talk directly to the embedded flash controller. -- Command: str9xpec lock num Lock str9 device. The str9 will only respond to an unlock command that will erase the device. -- Command: str9xpec part_id num Prints the part identifier for bank NUM. -- Command: str9xpec options_cmap num (bank0|bank1) Configure str9 boot bank. -- Command: str9xpec options_lvdsel num (vdd|vdd_vddq) Configure str9 lvd source. -- Command: str9xpec options_lvdthd num (2.4v|2.7v) Configure str9 lvd threshold. -- Command: str9xpec options_lvdwarn bank (vdd|vdd_vddq) Configure str9 lvd reset warning source. -- Command: str9xpec options_read num Read str9 option bytes. -- Command: str9xpec options_write num Write str9 option bytes. -- Command: str9xpec unlock num unlock str9 device. -- Flash Driver: swm050 All members of the swm050 microcontroller family from Foshan Synwit Tech. flash bank $_FLASHNAME swm050 0x0 0x2000 0 0 $_TARGETNAME One swm050-specific command is defined: -- Command: swm050 mass_erase bank_id Erases the entire flash bank. -- Flash Driver: tms470 Most members of the TMS470 microcontroller family from Texas Instruments include internal flash and use ARM7TDMI cores. This driver doesn't require the chip and bus width to be specified. Some tms470-specific commands are defined: -- Command: tms470 flash_keyset key0 key1 key2 key3 Saves programming keys in a register, to enable flash erase and write commands. -- Command: tms470 osc_megahertz clock_mhz Reports the clock speed, which is used to calculate timings. -- Command: tms470 plldis (0|1) Disables (1) or enables (0) use of the PLL to speed up the flash clock. -- Flash Driver: w600 W60x series Wi-Fi SoC from WinnerMicro are designed with ARM Cortex-M3 and have 1M Byte QFLASH inside. The W600 driver uses the TARGET parameter to select the correct bank config. flash bank $_FLASHNAME w600 0x08000000 0 0 0 $_TARGETNAMEs -- Flash Driver: xmc1xxx All members of the XMC1xxx microcontroller family from Infineon. This driver does not require the chip and bus width to be specified. -- Flash Driver: xmc4xxx All members of the XMC4xxx microcontroller family from Infineon. This driver does not require the chip and bus width to be specified. Some xmc4xxx-specific commands are defined: -- Command: xmc4xxx flash_password bank_id passwd1 passwd2 Saves flash protection passwords which are used to lock the user flash -- Command: xmc4xxx flash_unprotect bank_id user_level[0-1] Removes Flash write protection from the selected user bank 12.6 NAND Flash Commands ======================== Compared to NOR or SPI flash, NAND devices are inexpensive and high density. Today's NAND chips, and multi-chip modules, commonly hold multiple GigaBytes of data. NAND chips consist of a number of "erase blocks" of a given size (such as 128 KBytes), each of which is divided into a number of pages (of perhaps 512 or 2048 bytes each). Each page of a NAND flash has an "out of band" (OOB) area to hold Error Correcting Code (ECC) and other metadata, usually 16 bytes of OOB for every 512 bytes of page data. One key characteristic of NAND flash is that its error rate is higher than that of NOR flash. In normal operation, that ECC is used to correct and detect errors. However, NAND blocks can also wear out and become unusable; those blocks are then marked "bad". NAND chips are even shipped from the manufacturer with a few bad blocks. The highest density chips use a technology (MLC) that wears out more quickly, so ECC support is increasingly important as a way to detect blocks that have begun to fail, and help to preserve data integrity with techniques such as wear leveling. Software is used to manage the ECC. Some controllers don't support ECC directly; in those cases, software ECC is used. Other controllers speed up the ECC calculations with hardware. Single-bit error correction hardware is routine. Controllers geared for newer MLC chips may correct 4 or more errors for every 512 bytes of data. You will need to make sure that any data you write using OpenOCD includes the appropriate kind of ECC. For example, that may mean passing the 'oob_softecc' flag when writing NAND data, or ensuring that the correct hardware ECC mode is used. The basic steps for using NAND devices include: 1. Declare via the command 'nand device' Do this in a board-specific configuration file, passing parameters as needed by the controller. 2. Configure each device using 'nand probe'. Do this only after the associated target is set up, such as in its reset-init script or in procures defined to access that device. 3. Operate on the flash via 'nand subcommand' Often commands to manipulate the flash are typed by a human, or run via a script in some automated way. Common task include writing a boot loader, operating system, or other data needed to initialize or de-brick a board. NOTE: At the time this text was written, the largest NAND flash fully supported by OpenOCD is 2 GiBytes (16 GiBits). This is because the variables used to hold offsets and lengths are only 32 bits wide. (Larger chips may work in some cases, unless an offset or length is larger than 0xffffffff, the largest 32-bit unsigned integer.) Some larger devices will work, since they are actually multi-chip modules with two smaller chips and individual chipselect lines. 12.6.1 NAND Configuration Commands ---------------------------------- NAND chips must be declared in configuration scripts, plus some additional configuration that's done after OpenOCD has initialized. -- Config Command: nand device name driver target [configparams...] Declares a NAND device, which can be read and written to after it has been configured through 'nand probe'. In OpenOCD, devices are single chips; this is unlike some operating systems, which may manage multiple chips as if they were a single (larger) device. In some cases, configuring a device will activate extra commands; see the controller-specific documentation. NOTE: This command is not available after OpenOCD initialization has completed. Use it in board specific configuration files, not interactively. * NAME ... may be used to reference the NAND bank in most other NAND commands. A number is also available. * DRIVER ... identifies the NAND controller driver associated with the NAND device being declared. *Note NAND Driver List: nanddriverlist. * TARGET ... names the target used when issuing commands to the NAND controller. * CONFIGPARAMS ... controllers may support, or require, additional parameters. See the controller-specific documentation for more information. -- Command: nand list Prints a summary of each device declared using 'nand device', numbered from zero. Note that un-probed devices show no details. > nand list #0: NAND 1GiB 3,3V 8-bit (Micron) pagesize: 2048, buswidth: 8, blocksize: 131072, blocks: 8192 #1: NAND 1GiB 3,3V 8-bit (Micron) pagesize: 2048, buswidth: 8, blocksize: 131072, blocks: 8192 > -- Command: nand probe num Probes the specified device to determine key characteristics like its page and block sizes, and how many blocks it has. The NUM parameter is the value shown by 'nand list'. You must (successfully) probe a device before you can use it with most other NAND commands. 12.6.2 Erasing, Reading, Writing to NAND Flash ---------------------------------------------- -- Command: nand dump num filename offset length [oob_option] Reads binary data from the NAND device and writes it to the file, starting at the specified offset. The NUM parameter is the value shown by 'nand list'. Use a complete path name for FILENAME, so you don't depend on the directory used to start the OpenOCD server. The OFFSET and LENGTH must be exact multiples of the device's page size. They describe a data region; the OOB data associated with each such page may also be accessed. NOTE: At the time this text was written, no error correction was done on the data that's read, unless raw access was disabled and the underlying NAND controller driver had a 'read_page' method which handled that error correction. By default, only page data is saved to the specified file. Use an OOB_OPTION parameter to save OOB data: * no oob_* parameter Output file holds only page data; OOB is discarded. * 'oob_raw' Output file interleaves page data and OOB data; the file will be longer than "length" by the size of the spare areas associated with each data page. Note that this kind of "raw" access is different from what's implied by 'nand raw_access', which just controls whether a hardware-aware access method is used. * 'oob_only' Output file has only raw OOB data, and will be smaller than "length" since it will contain only the spare areas associated with each data page. -- Command: nand erase num [offset length] Erases blocks on the specified NAND device, starting at the specified OFFSET and continuing for LENGTH bytes. Both of those values must be exact multiples of the device's block size, and the region they specify must fit entirely in the chip. If those parameters are not specified, the whole NAND chip will be erased. The NUM parameter is the value shown by 'nand list'. NOTE: This command will try to erase bad blocks, when told to do so, which will probably invalidate the manufacturer's bad block marker. For the remainder of the current server session, 'nand info' will still report that the block "is" bad. -- Command: nand write num filename offset [option...] Writes binary data from the file into the specified NAND device, starting at the specified offset. Those pages should already have been erased; you can't change zero bits to one bits. The NUM parameter is the value shown by 'nand list'. Use a complete path name for FILENAME, so you don't depend on the directory used to start the OpenOCD server. The OFFSET must be an exact multiple of the device's page size. All data in the file will be written, assuming it doesn't run past the end of the device. Only full pages are written, and any extra space in the last page will be filled with 0xff bytes. (That includes OOB data, if that's being written.) NOTE: At the time this text was written, bad blocks are ignored. That is, this routine will not skip bad blocks, but will instead try to write them. This can cause problems. Provide at most one OPTION parameter. With some NAND drivers, the meanings of these parameters may change if 'nand raw_access' was used to disable hardware ECC. * no oob_* parameter File has only page data, which is written. If raw access is in use, the OOB area will not be written. Otherwise, if the underlying NAND controller driver has a 'write_page' routine, that routine may write the OOB with hardware-computed ECC data. * 'oob_only' File has only raw OOB data, which is written to the OOB area. Each page's data area stays untouched. This can be a dangerous option, since it can invalidate the ECC data. You may need to force raw access to use this mode. * 'oob_raw' File interleaves data and OOB data, both of which are written If raw access is enabled, the data is written first, then the un-altered OOB. Otherwise, if the underlying NAND controller driver has a 'write_page' routine, that routine may modify the OOB before it's written, to include hardware-computed ECC data. * 'oob_softecc' File has only page data, which is written. The OOB area is filled with 0xff, except for a standard 1-bit software ECC code stored in conventional locations. You might need to force raw access to use this mode, to prevent the underlying driver from applying hardware ECC. * 'oob_softecc_kw' File has only page data, which is written. The OOB area is filled with 0xff, except for a 4-bit software ECC specific to the boot ROM in Marvell Kirkwood SoCs. You might need to force raw access to use this mode, to prevent the underlying driver from applying hardware ECC. -- Command: nand verify num filename offset [option...] Verify the binary data in the file has been programmed to the specified NAND device, starting at the specified offset. The NUM parameter is the value shown by 'nand list'. Use a complete path name for FILENAME, so you don't depend on the directory used to start the OpenOCD server. The OFFSET must be an exact multiple of the device's page size. All data in the file will be read and compared to the contents of the flash, assuming it doesn't run past the end of the device. As with 'nand write', only full pages are verified, so any extra space in the last page will be filled with 0xff bytes. The same OPTIONS accepted by 'nand write', and the file will be processed similarly to produce the buffers that can be compared against the contents produced from 'nand dump'. NOTE: This will not work when the underlying NAND controller driver's 'write_page' routine must update the OOB with a hardware-computed ECC before the data is written. This limitation may be removed in a future release. 12.6.3 Other NAND commands -------------------------- -- Command: nand check_bad_blocks num [offset length] Checks for manufacturer bad block markers on the specified NAND device. If no parameters are provided, checks the whole device; otherwise, starts at the specified OFFSET and continues for LENGTH bytes. Both of those values must be exact multiples of the device's block size, and the region they specify must fit entirely in the chip. The NUM parameter is the value shown by 'nand list'. NOTE: Before using this command you should force raw access with 'nand raw_access enable' to ensure that the underlying driver will not try to apply hardware ECC. -- Command: nand info num The NUM parameter is the value shown by 'nand list'. This prints the one-line summary from "nand list", plus for devices which have been probed this also prints any known status for each block. -- Command: nand raw_access num (enable|disable) Sets or clears an flag affecting how page I/O is done. The NUM parameter is the value shown by 'nand list'. This flag is cleared (disabled) by default, but changing that value won't affect all NAND devices. The key factor is whether the underlying driver provides 'read_page' or 'write_page' methods. If it doesn't provide those methods, the setting of this flag is irrelevant; all access is effectively "raw". When those methods exist, they are normally used when reading data ('nand dump' or reading bad block markers) or writing it ('nand write'). However, enabling raw access (setting the flag) prevents use of those methods, bypassing hardware ECC logic. This can be a dangerous option, since writing blocks with the wrong ECC data can cause them to be marked as bad. 12.6.4 NAND Driver List ----------------------- As noted above, the 'nand device' command allows driver-specific options and behaviors. Some controllers also activate controller-specific commands. -- NAND Driver: at91sam9 This driver handles the NAND controllers found on AT91SAM9 family chips from Atmel. It takes two extra parameters: address of the NAND chip; address of the ECC controller. nand device $NANDFLASH at91sam9 $CHIPNAME 0x40000000 0xfffffe800 AT91SAM9 chips support single-bit ECC hardware. The 'write_page' and 'read_page' methods are used to utilize the ECC hardware unless they are disabled by using the 'nand raw_access' command. There are four additional commands that are needed to fully configure the AT91SAM9 NAND controller. Two are optional; most boards use the same wiring for ALE/CLE: -- Config Command: at91sam9 cle num addr_line Configure the address line used for latching commands. The NUM parameter is the value shown by 'nand list'. -- Config Command: at91sam9 ale num addr_line Configure the address line used for latching addresses. The NUM parameter is the value shown by 'nand list'. For the next two commands, it is assumed that the pins have already been properly configured for input or output. -- Config Command: at91sam9 rdy_busy num pio_base_addr pin Configure the RDY/nBUSY input from the NAND device. The NUM parameter is the value shown by 'nand list'. PIO_BASE_ADDR is the base address of the PIO controller and PIN is the pin number. -- Config Command: at91sam9 ce num pio_base_addr pin Configure the chip enable input to the NAND device. The NUM parameter is the value shown by 'nand list'. PIO_BASE_ADDR is the base address of the PIO controller and PIN is the pin number. -- NAND Driver: davinci This driver handles the NAND controllers found on DaVinci family chips from Texas Instruments. It takes three extra parameters: address of the NAND chip; hardware ECC mode to use ('hwecc1', 'hwecc4', 'hwecc4_infix'); address of the AEMIF controller on this processor. nand device davinci dm355.arm 0x02000000 hwecc4 0x01e10000 All DaVinci processors support the single-bit ECC hardware, and newer ones also support the four-bit ECC hardware. The 'write_page' and 'read_page' methods are used to implement those ECC modes, unless they are disabled using the 'nand raw_access' command. -- NAND Driver: lpc3180 These controllers require an extra 'nand device' parameter: the clock rate used by the controller. -- Command: lpc3180 select num [mlc|slc] Configures use of the MLC or SLC controller mode. MLC implies use of hardware ECC. The NUM parameter is the value shown by 'nand list'. At this writing, this driver includes 'write_page' and 'read_page' methods. Using 'nand raw_access' to disable those methods will prevent use of hardware ECC in the MLC controller mode, but won't change SLC behavior. -- NAND Driver: mx3 This driver handles the NAND controller in i.MX31. The mxc driver should work for this chip as well. -- NAND Driver: mxc This driver handles the NAND controller found in Freescale i.MX chips. It has support for v1 (i.MX27 and i.MX31) and v2 (i.MX35). The driver takes 3 extra arguments, chip ('mx27', 'mx31', 'mx35'), ecc ('noecc', 'hwecc') and optionally if bad block information should be swapped between main area and spare area ('biswap'), defaults to off. nand device mx35.nand mxc imx35.cpu mx35 hwecc biswap -- Command: mxc biswap bank_num [enable|disable] Turns on/off bad block information swapping from main area, without parameter query status. -- NAND Driver: orion These controllers require an extra 'nand device' parameter: the address of the controller. nand device orion 0xd8000000 These controllers don't define any specialized commands. At this writing, their drivers don't include 'write_page' or 'read_page' methods, so 'nand raw_access' won't change any behavior. -- NAND Driver: s3c2410 -- NAND Driver: s3c2412 -- NAND Driver: s3c2440 -- NAND Driver: s3c2443 -- NAND Driver: s3c6400 These S3C family controllers don't have any special 'nand device' options, and don't define any specialized commands. At this writing, their drivers don't include 'write_page' or 'read_page' methods, so 'nand raw_access' won't change any behavior. ================================================ FILE: Tools/CH347/ch347-main/CH347FPGATool/OpenOCD_CH347/share/info/openocd.info-2 ================================================ This is openocd.info, produced by makeinfo version 6.8 from openocd.texi. This User's Guide documents release 0.11.0+dev, dated 8 June 2022, of the Open On-Chip Debugger (OpenOCD). * Copyright (C) 2008 The OpenOCD Project * Copyright (C) 2007-2008 Spencer Oliver * Copyright (C) 2008-2010 Oyvind Harboe * Copyright (C) 2008 Duane Ellis * Copyright (C) 2009-2010 David Brownell Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". INFO-DIR-SECTION Development START-INFO-DIR-ENTRY * OpenOCD: (openocd). OpenOCD User's Guide END-INFO-DIR-ENTRY  File: openocd.info, Node: Flash Programming, Next: PLD/FPGA Commands, Prev: Flash Commands, Up: Top 13 Flash Programming ******************** OpenOCD implements numerous ways to program the target flash, whether internal or external. Programming can be achieved by either using *note Programming using GDB: programmingusinggdb, or using the commands given in *note Flash Programming Commands: flashprogrammingcommands. To simplify using the flash commands directly a jimtcl script is available that handles the programming and verify stage. OpenOCD will program/verify/reset the target and optionally shutdown. The script is executed as follows and by default the following actions will be performed. 1. 'init' is executed. 2. 'reset init' is called to reset and halt the target, any 'reset init' scripts are executed. 3. 'flash write_image' is called to erase and write any flash using the filename given. 4. If the 'preverify' parameter is given, the target is "verified" first and only flashed if this fails. 5. 'verify_image' is called if 'verify' parameter is given. 6. 'reset run' is called if 'reset' parameter is given. 7. OpenOCD is shutdown if 'exit' parameter is given. An example of usage is given below. *Note program::. # program and verify using elf/hex/s19. verify and reset # are optional parameters openocd -f board/stm32f3discovery.cfg \ -c "program filename.elf verify reset exit" # binary files need the flash address passing openocd -f board/stm32f3discovery.cfg \ -c "program filename.bin exit 0x08000000"  File: openocd.info, Node: PLD/FPGA Commands, Next: General Commands, Prev: Flash Programming, Up: Top 14 PLD/FPGA Commands ******************** Programmable Logic Devices (PLDs) and the more flexible Field Programmable Gate Arrays (FPGAs) are both types of programmable hardware. OpenOCD can support programming them. Although PLDs are generally restrictive (cells are less functional, and there are no special purpose cells for memory or computational tasks), they share the same OpenOCD infrastructure. Accordingly, both are called PLDs here. 14.1 PLD/FPGA Configuration and Commands ======================================== As it does for JTAG TAPs, debug targets, and flash chips (both NOR and NAND), OpenOCD maintains a list of PLDs available for use in various commands. Also, each such PLD requires a driver. They are referenced by the number shown by the 'pld devices' command, and new PLDs are defined by 'pld device driver_name'. -- Config Command: pld device driver_name tap_name [driver_options] Defines a new PLD device, supported by driver DRIVER_NAME, using the TAP named TAP_NAME. The driver may make use of any DRIVER_OPTIONS to configure its behavior. -- Command: pld devices Lists the PLDs and their numbers. -- Command: pld load num filename Loads the file 'filename' into the PLD identified by NUM. The file format must be inferred by the driver. 14.2 PLD/FPGA Drivers, Options, and Commands ============================================ Drivers may support PLD-specific options to the 'pld device' definition command, and may also define commands usable only with that particular type of PLD. -- FPGA Driver: virtex2 [no_jstart] Virtex-II is a family of FPGAs sold by Xilinx. It supports the IEEE 1532 standard for In-System Configuration (ISC). If NO_JSTART is non-zero, the JSTART instruction is not used after loading the bitstream. While required for Series2, Series3, and Series6, it breaks bitstream loading on Series7. -- Command: virtex2 read_stat num Reads and displays the Virtex-II status register (STAT) for FPGA NUM.  File: openocd.info, Node: General Commands, Next: Architecture and Core Commands, Prev: PLD/FPGA Commands, Up: Top 15 General Commands ******************* The commands documented in this chapter here are common commands that you, as a human, may want to type and see the output of. Configuration type commands are documented elsewhere. Intent: * Source Of Commands OpenOCD commands can occur in a configuration script (discussed elsewhere) or typed manually by a human or supplied programmatically, or via one of several TCP/IP Ports. * From the human A human should interact with the telnet interface (default port: 4444) or via GDB (default port 3333). To issue commands from within a GDB session, use the 'monitor' command, e.g. use 'monitor poll' to issue the 'poll' command. All output is relayed through the GDB session. * Machine Interface The Tcl interface's intent is to be a machine interface. The default Tcl port is 5555. 15.1 Server Commands ==================== -- Command: exit Exits the current telnet session. -- Command: help [string] With no parameters, prints help text for all commands. Otherwise, prints each helptext containing STRING. Not every command provides helptext. Configuration commands, and commands valid at any time, are explicitly noted in parenthesis. In most cases, no such restriction is listed; this indicates commands which are only available after the configuration stage has completed. -- Command: usage [string] With no parameters, prints usage text for all commands. Otherwise, prints all usage text of which command, help text, and usage text containing STRING. Not every command provides helptext. -- Command: sleep msec [busy] Wait for at least MSEC milliseconds before resuming. If 'busy' is passed, busy-wait instead of sleeping. (This option is strongly discouraged.) Useful in connection with script files ('script' command and 'target_name' configuration). -- Command: shutdown [error] Close the OpenOCD server, disconnecting all clients (GDB, telnet, other). If option 'error' is used, OpenOCD will return a non-zero exit code to the parent process. If user types CTRL-C or kills OpenOCD, the command 'shutdown' will be automatically executed to cause OpenOCD to exit. It is possible to specify, in the TCL list PRE_SHUTDOWN_COMMANDS , a set of commands to be automatically executed before 'shutdown' , e.g.: lappend pre_shutdown_commands {echo "Goodbye, my friend ..."} lappend pre_shutdown_commands {echo "see you soon !"} The commands in the list will be executed (in the same order they occupy in the list) before OpenOCD exits. If one of the commands in the list fails, then the remaining commands are not executed anymore while OpenOCD will proceed to quit. -- Command: debug_level [n] Display debug level. If N (from 0..4) is provided, then set it to that level. This affects the kind of messages sent to the server log. Level 0 is error messages only; level 1 adds warnings; level 2 adds informational messages; level 3 adds debugging messages; and level 4 adds verbose low-level debug messages. The default is level 2, but that can be overridden on the command line along with the location of that log file (which is normally the server's standard output). *Note Running::. -- Command: echo [-n] message Logs a message at "user" priority. Option "-n" suppresses trailing newline. echo "Downloading kernel -- please wait" -- Command: log_output [filename | "default"] Redirect logging to FILENAME or set it back to default output; the default log output channel is stderr. -- Command: add_script_search_dir [directory] Add DIRECTORY to the file/script search path. -- Config Command: bindto [NAME] Specify hostname or IPv4 address on which to listen for incoming TCP/IP connections. By default, OpenOCD will listen on the loopback interface only. If your network environment is safe, 'bindto 0.0.0.0' can be used to cover all available interfaces. 15.2 Target State handling ========================== In this section "target" refers to a CPU configured as shown earlier (*note CPU Configuration::). These commands, like many, implicitly refer to a current target which is used to perform the various operations. The current target may be changed by using 'targets' command with the name of the target which should become current. -- Command: reg [(number|name) [(value|'force')]] Access a single register by NUMBER or by its NAME. The target must generally be halted before access to CPU core registers is allowed. Depending on the hardware, some other registers may be accessible while the target is running. _With no arguments_: list all available registers for the current target, showing number, name, size, value, and cache status. For valid entries, a value is shown; valid entries which are also dirty (and will be written back later) are flagged as such. _With number/name_: display that register's value. Use FORCE argument to read directly from the target, bypassing any internal cache. _With both number/name and value_: set register's value. Writes may be held in a writeback cache internal to OpenOCD, so that setting the value marks the register as dirty instead of immediately flushing that value. Resuming CPU execution (including by single stepping) or otherwise activating the relevant module will flush such values. Cores may have surprisingly many registers in their Debug and trace infrastructure: > reg ===== ARM registers (0) r0 (/32): 0x0000D3C2 (dirty) (1) r1 (/32): 0xFD61F31C (2) r2 (/32) ... (164) ETM_contextid_comparator_mask (/32) > -- Command: set_reg dict Set register values of the target. * DICT ... Tcl dictionary with pairs of register names and values. For example, the following command sets the value 0 to the program counter (pc) register and 0x1000 to the stack pointer (sp) register: set_reg {pc 0 sp 0x1000} -- Command: get_reg [-force] list Get register values from the target and return them as Tcl dictionary with pairs of register names and values. If option "-force" is set, the register values are read directly from the target, bypassing any caching. * LIST ... List of register names For example, the following command retrieves the values from the program counter (pc) and stack pointer (sp) register: get_reg {pc sp} -- Command: write_memory address width data ['phys'] This function provides an efficient way to write to the target memory from a Tcl script. * ADDRESS ... target memory address * WIDTH ... memory access bit size, can be 8, 16, 32 or 64 * DATA ... Tcl list with the elements to write * ['phys'] ... treat the memory address as physical instead of virtual address For example, the following command writes two 32 bit words into the target memory at address 0x20000000: write_memory 0x20000000 32 {0xdeadbeef 0x00230500} -- Command: read_memory address width count ['phys'] This function provides an efficient way to read the target memory from a Tcl script. A Tcl list containing the requested memory elements is returned by this function. * ADDRESS ... target memory address * WIDTH ... memory access bit size, can be 8, 16, 32 or 64 * COUNT ... number of elements to read * ['phys'] ... treat the memory address as physical instead of virtual address For example, the following command reads two 32 bit words from the target memory at address 0x20000000: read_memory 0x20000000 32 2 -- Command: halt [ms] -- Command: wait_halt [ms] The 'halt' command first sends a halt request to the target, which 'wait_halt' doesn't. Otherwise these behave the same: wait up to MS milliseconds, or 5 seconds if there is no parameter, for the target to halt (and enter debug mode). Using 0 as the MS parameter prevents OpenOCD from waiting. Warning: On ARM cores, software using the _wait for interrupt_ operation often blocks the JTAG access needed by a 'halt' command. This is because that operation also puts the core into a low power mode by gating the core clock; but the core clock is needed to detect JTAG clock transitions. One partial workaround uses adaptive clocking: when the core is interrupted the operation completes, then JTAG clocks are accepted at least until the interrupt handler completes. However, this workaround is often unusable since the processor, board, and JTAG adapter must all support adaptive JTAG clocking. Also, it can't work until an interrupt is issued. A more complete workaround is to not use that operation while you work with a JTAG debugger. Tasking environments generally have idle loops where the body is the _wait for interrupt_ operation. (On older cores, it is a coprocessor action; newer cores have a 'wfi' instruction.) Such loops can just remove that operation, at the cost of higher power consumption (because the CPU is needlessly clocked). -- Command: resume [address] Resume the target at its current code position, or the optional ADDRESS if it is provided. OpenOCD will wait 5 seconds for the target to resume. -- Command: step [address] Single-step the target at its current code position, or the optional ADDRESS if it is provided. -- Command: reset -- Command: reset run -- Command: reset halt -- Command: reset init Perform as hard a reset as possible, using SRST if possible. _All defined targets will be reset, and target events will fire during the reset sequence._ The optional parameter specifies what should happen after the reset. If there is no parameter, a 'reset run' is executed. The other options will not work on all systems. *Note Reset Configuration::. - run Let the target run - halt Immediately halt the target - init Immediately halt the target, and execute the reset-init script -- Command: soft_reset_halt Requesting target halt and executing a soft reset. This is often used when a target cannot be reset and halted. The target, after reset is released begins to execute code. OpenOCD attempts to stop the CPU and then sets the program counter back to the reset vector. Unfortunately the code that was executed may have left the hardware in an unknown state. -- Command: adapter assert [signal [assert|deassert signal]] -- Command: adapter deassert [signal [assert|deassert signal]] Set values of reset signals. Without parameters returns current status of the signals. The SIGNAL parameter values may be 'srst', indicating that srst signal is to be asserted or deasserted, 'trst', indicating that trst signal is to be asserted or deasserted. The 'reset_config' command should already have been used to configure how the board and the adapter treat these two signals, and to say if either signal is even present. *Note Reset Configuration::. Trying to assert a signal that is not present triggers an error. If a signal is present on the adapter and not specified in the command, the signal will not be modified. Note: TRST is specially handled. It actually signifies JTAG's RESET state. So if the board doesn't support the optional TRST signal, or it doesn't support it along with the specified SRST value, JTAG reset is triggered with TMS and TCK signals instead of the TRST signal. And no matter how that JTAG reset is triggered, once the scan chain enters RESET with TRST inactive, TAP 'post-reset' events are delivered to all TAPs with handlers for that event. 15.3 Memory access commands =========================== These commands allow accesses of a specific size to the memory system. Often these are used to configure the current target in some special way. For example - one may need to write certain values to the SDRAM controller to enable SDRAM. 1. Use the 'targets' (plural) command to change the current target. 2. In system level scripts these commands are deprecated. Please use their TARGET object siblings to avoid making assumptions about what TAP is the current target, or about MMU configuration. -- Command: mdd [phys] addr [count] -- Command: mdw [phys] addr [count] -- Command: mdh [phys] addr [count] -- Command: mdb [phys] addr [count] Display contents of address ADDR, as 64-bit doublewords ('mdd'), 32-bit words ('mdw'), 16-bit halfwords ('mdh'), or 8-bit bytes ('mdb'). When the current target has an MMU which is present and active, ADDR is interpreted as a virtual address. Otherwise, or if the optional PHYS flag is specified, ADDR is interpreted as a physical address. If COUNT is specified, displays that many units. (If you want to process the data instead of displaying it, see the 'read_memory' primitives.) -- Command: mwd [phys] addr doubleword [count] -- Command: mww [phys] addr word [count] -- Command: mwh [phys] addr halfword [count] -- Command: mwb [phys] addr byte [count] Writes the specified DOUBLEWORD (64 bits), WORD (32 bits), HALFWORD (16 bits), or BYTE (8-bit) value, at the specified address ADDR. When the current target has an MMU which is present and active, ADDR is interpreted as a virtual address. Otherwise, or if the optional PHYS flag is specified, ADDR is interpreted as a physical address. If COUNT is specified, fills that many units of consecutive address. 15.4 Image loading commands =========================== -- Command: dump_image filename address size Dump SIZE bytes of target memory starting at ADDRESS to the binary file named FILENAME. -- Command: fast_load Loads an image stored in memory by 'fast_load_image' to the current target. Must be preceded by fast_load_image. -- Command: fast_load_image filename address [bin|ihex|elf|s19] Normally you should be using 'load_image' or GDB load. However, for testing purposes or when I/O overhead is significant(OpenOCD running on an embedded host), storing the image in memory and uploading the image to the target can be a way to upload e.g. multiple debug sessions when the binary does not change. Arguments are the same as 'load_image', but the image is stored in OpenOCD host memory, i.e. does not affect target. This approach is also useful when profiling target programming performance as I/O and target programming can easily be profiled separately. -- Command: load_image filename address [[bin|ihex|elf|s19] min_addr max_length] Load image from file FILENAME to target memory offset by ADDRESS from its load address. The file format may optionally be specified ('bin', 'ihex', 'elf', or 's19'). In addition the following arguments may be specified: MIN_ADDR - ignore data below MIN_ADDR (this is w.r.t. to the target's load address + ADDRESS) MAX_LENGTH - maximum number of bytes to load. proc load_image_bin {fname foffset address length } { # Load data from fname filename at foffset offset to # target at address. Load at most length bytes. load_image $fname [expr {$address - $foffset}] bin \ $address $length } -- Command: test_image filename [address [bin|ihex|elf]] Displays image section sizes and addresses as if FILENAME were loaded into target memory starting at ADDRESS (defaults to zero). The file format may optionally be specified ('bin', 'ihex', or 'elf') -- Command: verify_image filename address [bin|ihex|elf] Verify FILENAME against target memory starting at ADDRESS. The file format may optionally be specified ('bin', 'ihex', or 'elf') This will first attempt a comparison using a CRC checksum, if this fails it will try a binary compare. -- Command: verify_image_checksum filename address [bin|ihex|elf] Verify FILENAME against target memory starting at ADDRESS. The file format may optionally be specified ('bin', 'ihex', or 'elf') This perform a comparison using a CRC checksum only 15.5 Breakpoint and Watchpoint commands ======================================= CPUs often make debug modules accessible through JTAG, with hardware support for a handful of code breakpoints and data watchpoints. In addition, CPUs almost always support software breakpoints. -- Command: bp [address len [hw]] With no parameters, lists all active breakpoints. Else sets a breakpoint on code execution starting at ADDRESS for LENGTH bytes. This is a software breakpoint, unless 'hw' is specified in which case it will be a hardware breakpoint. (*Note arm9 vector_catch: arm9vectorcatch, or *note xscale vector_catch: xscalevectorcatch, for similar mechanisms that do not consume hardware breakpoints.) -- Command: rbp all | address Remove the breakpoint at ADDRESS or all breakpoints. -- Command: rwp address Remove data watchpoint on ADDRESS -- Command: wp [address len [(r|w|a) [value [mask]]]] With no parameters, lists all active watchpoints. Else sets a data watchpoint on data from ADDRESS for LENGTH bytes. The watch point is an "access" watchpoint unless the 'r' or 'w' parameter is provided, defining it as respectively a read or write watchpoint. If a VALUE is provided, that value is used when determining if the watchpoint should trigger. The value may be first be masked using MASK to mark "don't care" fields. 15.6 Real Time Transfer (RTT) ============================= Real Time Transfer (RTT) is an interface specified by SEGGER based on basic memory reads and writes to transfer data bidirectionally between target and host. The specification is independent of the target architecture. Every target that supports so called "background memory access", which means that the target memory can be accessed by the debugger while the target is running, can be used. This interface is especially of interest for targets without Serial Wire Output (SWO), such as ARM Cortex-M0, or where semihosting is not applicable because of real-time constraints. Note: The current implementation supports only single target devices. The data transfer between host and target device is organized through unidirectional up/down-channels for target-to-host and host-to-target communication, respectively. Note: The current implementation does not respect channel buffer flags. They are used to determine what happens when writing to a full buffer, for example. Channels are exposed via raw TCP/IP connections. One or more RTT servers can be assigned to each channel to make them accessible to an unlimited number of TCP/IP connections. -- Command: rtt setup address size ID Configure RTT for the currently selected target. Once RTT is started, OpenOCD searches for a control block with the identifier ID starting at the memory address ADDRESS within the next SIZE bytes. -- Command: rtt start Start RTT. If the control block location is not known, OpenOCD starts searching for it. -- Command: rtt stop Stop RTT. -- Command: rtt polling_interval [interval] Display the polling interval. If INTERVAL is provided, set the polling interval. The polling interval determines (in milliseconds) how often the up-channels are checked for new data. -- Command: rtt channels Display a list of all channels and their properties. -- Command: rtt channellist Return a list of all channels and their properties as Tcl list. The list can be manipulated easily from within scripts. -- Command: rtt server start port channel Start a TCP server on PORT for the channel CHANNEL. -- Command: rtt server stop port Stop the TCP sever with port PORT. The following example shows how to setup RTT using the SEGGER RTT implementation on the target device. resume rtt setup 0x20000000 2048 "SEGGER RTT" rtt start rtt server start 9090 0 In this example, OpenOCD searches the control block with the ID "SEGGER RTT" starting at 0x20000000 for 2048 bytes. The RTT channel 0 is exposed through the TCP/IP port 9090. 15.7 Misc Commands ================== -- Command: profile seconds filename [start end] Profiling samples the CPU's program counter as quickly as possible, which is useful for non-intrusive stochastic profiling. Saves up to 10000 samples in 'filename' using "gmon.out" format. Optional 'start' and 'end' parameters allow to limit the address range. -- Command: version Displays a string identifying the version of this OpenOCD server. -- Command: virt2phys virtual_address Requests the current target to map the specified VIRTUAL_ADDRESS to its corresponding physical address, and displays the result. -- Command: add_help_text 'command_name' 'help-string' Add or replace help text on the given COMMAND_NAME. -- Command: add_usage_text 'command_name' 'help-string' Add or replace usage text on the given COMMAND_NAME.  File: openocd.info, Node: Architecture and Core Commands, Next: JTAG Commands, Prev: General Commands, Up: Top 16 Architecture and Core Commands ********************************* Most CPUs have specialized JTAG operations to support debugging. OpenOCD packages most such operations in its standard command framework. Some of those operations don't fit well in that framework, so they are exposed here as architecture or implementation (core) specific commands. 16.1 ARM Hardware Tracing ========================= CPUs based on ARM cores may include standard tracing interfaces, based on an "Embedded Trace Module" (ETM) which sends voluminous address and data bus trace records to a "Trace Port". * Development-oriented boards will sometimes provide a high speed trace connector for collecting that data, when the particular CPU supports such an interface. (The standard connector is a 38-pin Mictor, with both JTAG and trace port support.) Those trace connectors are supported by higher end JTAG adapters and some logic analyzer modules; frequently those modules can buffer several megabytes of trace data. Configuring an ETM coupled to such an external trace port belongs in the board-specific configuration file. * If the CPU doesn't provide an external interface, it probably has an "Embedded Trace Buffer" (ETB) on the chip, which is a dedicated SRAM. 4KBytes is one common ETB size. Configuring an ETM coupled only to an ETB belongs in the CPU-specific (target) configuration file, since it works the same on all boards. ETM support in OpenOCD doesn't seem to be widely used yet. Issues: ETM support may be buggy, and at least some 'etm config' parameters should be detected by asking the ETM for them. ETM trigger events could also implement a kind of complex hardware breakpoint, much more powerful than the simple watchpoint hardware exported by EmbeddedICE modules. _Such breakpoints can be triggered even when using the dummy trace port driver_. It seems like a GDB hookup should be possible, as well as tracing only during specific states (perhaps _handling IRQ 23_ or _calls foo()_). There should be GUI tools to manipulate saved trace data and help analyse it in conjunction with the source code. It's unclear how much of a common interface is shared with the current XScale trace support, or should be shared with eventual Nexus-style trace module support. At this writing (November 2009) only ARM7, ARM9, and ARM11 support for ETM modules is available. The code should be able to work with some newer cores; but not all of them support this original style of JTAG access. 16.1.1 ETM Configuration ------------------------ ETM setup is coupled with the trace port driver configuration. -- Config Command: etm config target width mode clocking driver Declares the ETM associated with TARGET, and associates it with a given trace port DRIVER. *Note Trace Port Drivers: traceportdrivers. Several of the parameters must reflect the trace port capabilities, which are a function of silicon capabilities (exposed later using 'etm info') and of what hardware is connected to that port (such as an external pod, or ETB). The WIDTH must be either 4, 8, or 16, except with ETMv3.0 and newer modules which may also support 1, 2, 24, 32, 48, and 64 bit widths. (With those versions, 'etm info' also shows whether the selected port width and mode are supported.) The MODE must be 'normal', 'multiplexed', or 'demultiplexed'. The CLOCKING must be 'half' or 'full'. Warning: With ETMv3.0 and newer, the bits set with the MODE and CLOCKING parameters both control the mode. This modified mode does not map to the values supported by previous ETM modules, so this syntax is subject to change. Note: You can see the ETM registers using the 'reg' command. Not all possible registers are present in every ETM. Most of the registers are write-only, and are used to configure what CPU activities are traced. -- Command: etm info Displays information about the current target's ETM. This includes resource counts from the 'ETM_CONFIG' register, as well as silicon capabilities (except on rather old modules). from the 'ETM_SYS_CONFIG' register. -- Command: etm status Displays status of the current target's ETM and trace port driver: is the ETM idle, or is it collecting data? Did trace data overflow? Was it triggered? -- Command: etm tracemode [type context_id_bits cycle_accurate branch_output] Displays what data that ETM will collect. If arguments are provided, first configures that data. When the configuration changes, tracing is stopped and any buffered trace data is invalidated. * TYPE ... describing how data accesses are traced, when they pass any ViewData filtering that was set up. The value is one of 'none' (save nothing), 'data' (save data), 'address' (save addresses), 'all' (save data and addresses) * CONTEXT_ID_BITS ... 0, 8, 16, or 32 * CYCLE_ACCURATE ... 'enable' or 'disable' cycle-accurate instruction tracing. Before ETMv3, enabling this causes much extra data to be recorded. * BRANCH_OUTPUT ... 'enable' or 'disable'. Disable this unless you need to try reconstructing the instruction trace stream without an image of the code. -- Command: etm trigger_debug (enable|disable) Displays whether ETM triggering debug entry (like a breakpoint) is enabled or disabled, after optionally modifying that configuration. The default behaviour is 'disable'. Any change takes effect after the next 'etm start'. By using script commands to configure ETM registers, you can make the processor enter debug state automatically when certain conditions, more complex than supported by the breakpoint hardware, happen. 16.1.2 ETM Trace Operation -------------------------- After setting up the ETM, you can use it to collect data. That data can be exported to files for later analysis. It can also be parsed with OpenOCD, for basic sanity checking. To configure what is being traced, you will need to write various trace registers using 'reg ETM_*' commands. For the definitions of these registers, read ARM publication _IHI 0014, "Embedded Trace Macrocell, Architecture Specification"_. Be aware that most of the relevant registers are write-only, and that ETM resources are limited. There are only a handful of address comparators, data comparators, counters, and so on. Examples of scenarios you might arrange to trace include: * Code flow within a function, _excluding_ subroutines it calls. Use address range comparators to enable tracing for instruction access within that function's body. * Code flow within a function, _including_ subroutines it calls. Use the sequencer and address comparators to activate tracing on an "entered function" state, then deactivate it by exiting that state when the function's exit code is invoked. * Code flow starting at the fifth invocation of a function, combining one of the above models with a counter. * CPU data accesses to the registers for a particular device, using address range comparators and the ViewData logic. * Such data accesses only during IRQ handling, combining the above model with sequencer triggers which on entry and exit to the IRQ handler. * _... more_ At this writing, September 2009, there are no Tcl utility procedures to help set up any common tracing scenarios. -- Command: etm analyze Reads trace data into memory, if it wasn't already present. Decodes and prints the data that was collected. -- Command: etm dump filename Stores the captured trace data in 'filename'. -- Command: etm image filename [base_address] [type] Opens an image file. -- Command: etm load filename Loads captured trace data from 'filename'. -- Command: etm start Starts trace data collection. -- Command: etm stop Stops trace data collection. 16.1.3 Trace Port Drivers ------------------------- To use an ETM trace port it must be associated with a driver. -- Trace Port Driver: dummy Use the 'dummy' driver if you are configuring an ETM that's not connected to anything (on-chip ETB or off-chip trace connector). _This driver lets OpenOCD talk to the ETM, but it does not expose any trace data collection._ -- Config Command: etm_dummy config target Associates the ETM for TARGET with a dummy driver. -- Trace Port Driver: etb Use the 'etb' driver if you are configuring an ETM to use on-chip ETB memory. -- Config Command: etb config target etb_tap Associates the ETM for TARGET with the ETB at ETB_TAP. You can see the ETB registers using the 'reg' command. -- Command: etb trigger_percent [percent] This displays, or optionally changes, ETB behavior after the ETM's configured _trigger_ event fires. It controls how much more trace data is saved after the (single) trace trigger becomes active. * The default corresponds to _trace around_ usage, recording 50 percent data before the event and the rest afterwards. * The minimum value of PERCENT is 2 percent, recording almost exclusively data before the trigger. Such extreme _trace before_ usage can help figure out what caused that event to happen. * The maximum value of PERCENT is 100 percent, recording data almost exclusively after the event. This extreme _trace after_ usage might help sort out how the event caused trouble. 16.2 ARM Cross-Trigger Interface ================================ The ARM Cross-Trigger Interface (CTI) is a generic CoreSight component that connects event sources like tracing components or CPU cores with each other through a common trigger matrix (CTM). For ARMv8 architecture, a CTI is mandatory for core run control and each core has an individual CTI instance attached to it. OpenOCD has limited support for CTI using the _cti_ group of commands. -- Command: cti create cti_name -dap dap_name -ap-num apn -baseaddr base_address Creates a CTI instance CTI_NAME on the DAP instance DAP_NAME on MEM-AP APN. The BASE_ADDRESS must match the base address of the CTI on the respective MEM-AP. All arguments are mandatory. This creates a new command '$cti_name' which is used for various purposes including additional configuration. -- Command: $cti_name enable on|off Enable ('on') or disable ('off') the CTI. -- Command: $cti_name dump Displays a register dump of the CTI. -- Command: $cti_name write REG_NAME VALUE Write VALUE to the CTI register with the symbolic name REG_NAME. -- Command: $cti_name read REG_NAME Print the value read from the CTI register with the symbolic name REG_NAME. -- Command: $cti_name ack EVENT Acknowledge a CTI EVENT. -- Command: $cti_name channel CHANNEL_NUMBER OPERATION Perform a specific channel operation, the possible operations are: gate, ungate, set, clear and pulse -- Command: $cti_name testmode on|off Enable ('on') or disable ('off') the integration test mode of the CTI. -- Command: cti names Prints a list of names of all CTI objects created. This command is mainly useful in TCL scripting. 16.3 Generic ARM ================ These commands should be available on all ARM processors. They are available in addition to other core-specific commands that may be available. -- Command: arm core_state [arm|thumb] Displays the core_state, optionally changing it to process either 'arm' or 'thumb' instructions. The target may later be resumed in the currently set core_state. (Processors may also support the Jazelle state, but that is not currently supported in OpenOCD.) -- Command: arm disassemble address [count [thumb]] Disassembles COUNT instructions starting at ADDRESS. If COUNT is not specified, a single instruction is disassembled. If 'thumb' is specified, or the low bit of the address is set, Thumb2 (mixed 16/32-bit) instructions are used; else ARM (32-bit) instructions are used. (Processors may also support the Jazelle state, but those instructions are not currently understood by OpenOCD.) Note that all Thumb instructions are Thumb2 instructions, so older processors (without Thumb2 support) will still see correct disassembly of Thumb code. Also, ThumbEE opcodes are the same as Thumb2, with a handful of exceptions. ThumbEE disassembly currently has no explicit support. -- Command: arm mcr pX op1 CRn CRm op2 value Write VALUE to a coprocessor PX register passing parameters CRN, CRM, opcodes OPC1 and OPC2, and using the MCR instruction. (Parameter sequence matches the ARM instruction, but omits an ARM register.) -- Command: arm mrc pX coproc op1 CRn CRm op2 Read a coprocessor PX register passing parameters CRN, CRM, opcodes OPC1 and OPC2, and the MRC instruction. Returns the result so it can be manipulated by Jim scripts. (Parameter sequence matches the ARM instruction, but omits an ARM register.) -- Command: arm reg Display a table of all banked core registers, fetching the current value from every core mode if necessary. -- Command: arm semihosting [enable|disable] Display status of semihosting, after optionally changing that status. Semihosting allows for code executing on an ARM target to use the I/O facilities on the host computer i.e. the system where OpenOCD is running. The target application must be linked against a library implementing the ARM semihosting convention that forwards operation requests by using a special SVC instruction that is trapped at the Supervisor Call vector by OpenOCD. -- Command: arm semihosting_redirect (disable | tcp ['debug'|'stdio'|'all') Redirect semihosting messages to a specified TCP port. This command redirects debug (READC, WRITEC and WRITE0) and stdio (READ, WRITE) semihosting operations to the specified TCP port. The command allows to select which type of operations to redirect (debug, stdio, all (default)). Note: for stdio operations, only I/O from/to ':tt' file descriptors are redirected. -- Command: arm semihosting_cmdline [enable|disable] Set the command line to be passed to the debugger. arm semihosting_cmdline argv0 argv1 argv2 ... This option lets one set the command line arguments to be passed to the program. The first argument (argv0) is the program name in a standard C environment (argv[0]). Depending on the program (not much programs look at argv[0]), argv0 is ignored and can be any string. -- Command: arm semihosting_fileio [enable|disable] Display status of semihosting fileio, after optionally changing that status. Enabling this option forwards semihosting I/O to GDB process using the File-I/O remote protocol extension. This is especially useful for interacting with remote files or displaying console messages in the debugger. -- Command: arm semihosting_resexit [enable|disable] Enable resumable SEMIHOSTING_SYS_EXIT. When SEMIHOSTING_SYS_EXIT is called outside a debug session, things are simple, the openocd process calls exit() and passes the value returned by the target. When SEMIHOSTING_SYS_EXIT is called during a debug session, by default execution returns to the debugger, leaving the debugger in a HALT state, similar to the state entered when encountering a break. In some use cases, it is useful to have SEMIHOSTING_SYS_EXIT return normally, as any semihosting call, and do not break to the debugger. The standard allows this to happen, but the condition to trigger it is a bit obscure ("by performing an RDI_Execute request or equivalent"). To make the SEMIHOSTING_SYS_EXIT call return normally, enable this option (default: disabled). -- Command: arm semihosting_read_user_param Read parameter of the semihosting call from the target. Usable in semihosting-user-cmd-0x10* event handlers, returning a string. When the target makes semihosting call with operation number from range 0x100- 0x107, an optional string parameter can be passed to the server. This parameter is valid during the run of the event handlers and is accessible with this command. -- Command: arm semihosting_basedir [dir] Set the base directory for semihosting I/O, either an absolute path or a path relative to OpenOCD working directory. Use "." for the current directory. 16.4 ARMv4 and ARMv5 Architecture ================================= The ARMv4 and ARMv5 architectures are widely used in embedded systems, and introduced core parts of the instruction set in use today. That includes the Thumb instruction set, introduced in the ARMv4T variant. 16.4.1 ARM7 and ARM9 specific commands -------------------------------------- These commands are specific to ARM7 and ARM9 cores, like ARM7TDMI, ARM720T, ARM9TDMI, ARM920T or ARM926EJ-S. They are available in addition to the ARM commands, and any other core-specific commands that may be available. -- Command: arm7_9 dbgrq [enable|disable] Displays the value of the flag controlling use of the EmbeddedIce DBGRQ signal to force entry into debug mode, instead of breakpoints. If a boolean parameter is provided, first assigns that flag. This should be safe for all but ARM7TDMI-S cores (like NXP LPC). This feature is enabled by default on most ARM9 cores, including ARM9TDMI, ARM920T, and ARM926EJ-S. -- Command: arm7_9 dcc_downloads [enable|disable] Displays the value of the flag controlling use of the debug communications channel (DCC) to write larger (>128 byte) amounts of memory. If a boolean parameter is provided, first assigns that flag. DCC downloads offer a huge speed increase, but might be unsafe, especially with targets running at very low speeds. This command was introduced with OpenOCD rev. 60, and requires a few bytes of working area. -- Command: arm7_9 fast_memory_access [enable|disable] Displays the value of the flag controlling use of memory writes and reads that don't check completion of the operation. If a boolean parameter is provided, first assigns that flag. This provides a huge speed increase, especially with USB JTAG cables (FT2232), but might be unsafe if used with targets running at very low speeds, like the 32kHz startup clock of an AT91RM9200. 16.4.2 ARM9 specific commands ----------------------------- ARM9-family cores are built around ARM9TDMI or ARM9E (including ARM9EJS) integer processors. Such cores include the ARM920T, ARM926EJ-S, and ARM966. -- Command: arm9 vector_catch [all|none|list] Vector Catch hardware provides a sort of dedicated breakpoint for hardware events such as reset, interrupt, and abort. You can use this to conserve normal breakpoint resources, so long as you're not concerned with code that branches directly to those hardware vectors. This always finishes by listing the current configuration. If parameters are provided, it first reconfigures the vector catch hardware to intercept 'all' of the hardware vectors, 'none' of them, or a list with one or more of the following: 'reset' 'undef' 'swi' 'pabt' 'dabt' 'irq' 'fiq'. 16.4.3 ARM920T specific commands -------------------------------- These commands are available to ARM920T based CPUs, which are implementations of the ARMv4T architecture built using the ARM9TDMI integer core. They are available in addition to the ARM, ARM7/ARM9, and ARM9 commands. -- Command: arm920t cache_info Print information about the caches found. This allows to see whether your target is an ARM920T (2x16kByte cache) or ARM922T (2x8kByte cache). -- Command: arm920t cp15 regnum [value] Display cp15 register REGNUM; else if a VALUE is provided, that value is written to that register. This uses "physical access" and the register number is as shown in bits 38..33 of table 9-9 in the ARM920T TRM. (Not all registers can be written.) -- Command: arm920t read_cache filename Dump the content of ICache and DCache to a file named 'filename'. -- Command: arm920t read_mmu filename Dump the content of the ITLB and DTLB to a file named 'filename'. 16.4.4 ARM926ej-s specific commands ----------------------------------- These commands are available to ARM926ej-s based CPUs, which are implementations of the ARMv5TEJ architecture based on the ARM9EJ-S integer core. They are available in addition to the ARM, ARM7/ARM9, and ARM9 commands. The Feroceon cores also support these commands, although they are not built from ARM926ej-s designs. -- Command: arm926ejs cache_info Print information about the caches found. 16.4.5 ARM966E specific commands -------------------------------- These commands are available to ARM966 based CPUs, which are implementations of the ARMv5TE architecture. They are available in addition to the ARM, ARM7/ARM9, and ARM9 commands. -- Command: arm966e cp15 regnum [value] Display cp15 register REGNUM; else if a VALUE is provided, that value is written to that register. The six bit REGNUM values are bits 37..32 from table 7-2 of the ARM966E-S TRM. There is no current control over bits 31..30 from that table, as required for BIST support. 16.4.6 XScale specific commands ------------------------------- Some notes about the debug implementation on the XScale CPUs: The XScale CPU provides a special debug-only mini-instruction cache (mini-IC) in which exception vectors and target-resident debug handler code are placed by OpenOCD. In order to get access to the CPU, OpenOCD must point vector 0 (the reset vector) to the entry of the debug handler. However, this means that the complete first cacheline in the mini-IC is marked valid, which makes the CPU fetch all exception handlers from the mini-IC, ignoring the code in RAM. To address this situation, OpenOCD provides the 'xscale vector_table' command, which allows the user to explicitly write individual entries to either the high or low vector table stored in the mini-IC. It is recommended to place a pc-relative indirect branch in the vector table, and put the branch destination somewhere in memory. Doing so makes sure the code in the vector table stays constant regardless of code layout in memory: _vectors: ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] .org 0x100 .long real_reset_vector .long real_ui_handler .long real_swi_handler .long real_pf_abort .long real_data_abort .long 0 /* unused */ .long real_irq_handler .long real_fiq_handler Alternatively, you may choose to keep some or all of the mini-IC vector table entries synced with those written to memory by your system software. The mini-IC can not be modified while the processor is executing, but for each vector table entry not previously defined using the 'xscale vector_table' command, OpenOCD will copy the value from memory to the mini-IC every time execution resumes from a halt. This is done for both high and low vector tables (although the table not in use may not be mapped to valid memory, and in this case that copy operation will silently fail). This means that you will need to briefly halt execution at some strategic point during system start-up; e.g., after the software has initialized the vector table, but before exceptions are enabled. A breakpoint can be used to accomplish this once the appropriate location in the start-up code has been identified. A watchpoint over the vector table region is helpful in finding the location if you're not sure. Note that the same situation exists any time the vector table is modified by the system software. The debug handler must be placed somewhere in the address space using the 'xscale debug_handler' command. The allowed locations for the debug handler are either (0x800 - 0x1fef800) or (0xfe000800 - 0xfffff800). The default value is 0xfe000800. XScale has resources to support two hardware breakpoints and two watchpoints. However, the following restrictions on watchpoint functionality apply: (1) the value and mask arguments to the 'wp' command are not supported, (2) the watchpoint length must be a power of two and not less than four, and can not be greater than the watchpoint address, and (3) a watchpoint with a length greater than four consumes all the watchpoint hardware resources. This means that at any one time, you can have enabled either two watchpoints with a length of four, or one watchpoint with a length greater than four. These commands are available to XScale based CPUs, which are implementations of the ARMv5TE architecture. -- Command: xscale analyze_trace Displays the contents of the trace buffer. -- Command: xscale cache_clean_address address Changes the address used when cleaning the data cache. -- Command: xscale cache_info Displays information about the CPU caches. -- Command: xscale cp15 regnum [value] Display cp15 register REGNUM; else if a VALUE is provided, that value is written to that register. -- Command: xscale debug_handler target address Changes the address used for the specified target's debug handler. -- Command: xscale dcache [enable|disable] Enables or disable the CPU's data cache. -- Command: xscale dump_trace filename Dumps the raw contents of the trace buffer to 'filename'. -- Command: xscale icache [enable|disable] Enables or disable the CPU's instruction cache. -- Command: xscale mmu [enable|disable] Enables or disable the CPU's memory management unit. -- Command: xscale trace_buffer [enable|disable [fill [n] | wrap]] Displays the trace buffer status, after optionally enabling or disabling the trace buffer and modifying how it is emptied. -- Command: xscale trace_image filename [offset [type]] Opens a trace image from 'filename', optionally rebasing its segment addresses by OFFSET. The image TYPE may be one of 'bin' (binary), 'ihex' (Intel hex), 'elf' (ELF file), 's19' (Motorola s19), 'mem', or 'builder'. -- Command: xscale vector_catch [mask] Display a bitmask showing the hardware vectors to catch. If the optional parameter is provided, first set the bitmask to that value. The mask bits correspond with bit 16..23 in the DCSR: 0x01 Trap Reset 0x02 Trap Undefined Instructions 0x04 Trap Software Interrupt 0x08 Trap Prefetch Abort 0x10 Trap Data Abort 0x20 reserved 0x40 Trap IRQ 0x80 Trap FIQ -- Command: xscale vector_table [(low|high) index value] Set an entry in the mini-IC vector table. There are two tables: one for low vectors (at 0x00000000), and one for high vectors (0xFFFF0000), each holding the 8 exception vectors. INDEX can be 1-7, because vector 0 points to the debug handler entry and can not be overwritten. VALUE holds the 32-bit opcode that is placed in the mini-IC. Without arguments, the current settings are displayed. 16.5 ARMv6 Architecture ======================= 16.5.1 ARM11 specific commands ------------------------------ -- Command: arm11 memwrite burst [enable|disable] Displays the value of the memwrite burst-enable flag, which is enabled by default. If a boolean parameter is provided, first assigns that flag. Burst writes are only used for memory writes larger than 1 word. They improve performance by assuming that the CPU has read each data word over JTAG and completed its write before the next word arrives, instead of polling for a status flag to verify that completion. This is usually safe, because JTAG runs much slower than the CPU. -- Command: arm11 memwrite error_fatal [enable|disable] Displays the value of the memwrite error_fatal flag, which is enabled by default. If a boolean parameter is provided, first assigns that flag. When set, certain memory write errors cause earlier transfer termination. -- Command: arm11 step_irq_enable [enable|disable] Displays the value of the flag controlling whether IRQs are enabled during single stepping; they are disabled by default. If a boolean parameter is provided, first assigns that. -- Command: arm11 vcr [value] Displays the value of the _Vector Catch Register (VCR)_, coprocessor 14 register 7. If VALUE is defined, first assigns that. Vector Catch hardware provides dedicated breakpoints for certain hardware events. The specific bit values are core-specific (as in fact is using coprocessor 14 register 7 itself) but all current ARM11 cores _except the ARM1176_ use the same six bits. 16.6 ARMv7 and ARMv8 Architecture ================================= 16.6.1 ARMv7-A specific commands -------------------------------- -- Command: cortex_a cache_info display information about target caches -- Command: cortex_a dacrfixup [on|off] Work around issues with software breakpoints when the program text is mapped read-only by the operating system. This option sets the CP15 DACR to "all-manager" to bypass MMU permission checks on memory access. Defaults to 'off'. -- Command: cortex_a dbginit Initialize core debug Enables debug by unlocking the Software Lock and clearing sticky powerdown indications -- Command: cortex_a smp [on|off] Display/set the current SMP mode -- Command: cortex_a smp_gdb [core_id] Display/set the current core displayed in GDB -- Command: cortex_a maskisr [on|off] Selects whether interrupts will be processed when single stepping -- Command: cache_config l2x [base way] configure l2x cache -- Command: cortex_a mmu dump [0|1|addr address [num_entries]] Dump the MMU translation table from TTB0 or TTB1 register, or from physical memory location ADDRESS. When dumping the table from ADDRESS, print at most NUM_ENTRIES page table entries. NUM_ENTRIES is optional, if omitted, the maximum possible (4096) entries are printed. 16.6.2 ARMv7-R specific commands -------------------------------- -- Command: cortex_r4 dbginit Initialize core debug Enables debug by unlocking the Software Lock and clearing sticky powerdown indications -- Command: cortex_r4 maskisr [on|off] Selects whether interrupts will be processed when single stepping 16.6.3 ARM CoreSight TPIU and SWO specific commands --------------------------------------------------- ARM CoreSight provides several modules to generate debugging information internally (ITM, DWT and ETM). Their output is directed through TPIU or SWO modules to be captured externally either on an SWO pin (this configuration is called SWV) or on a synchronous parallel trace port. ARM CoreSight provides independent HW blocks named TPIU and SWO each with its own functionality. Embedded in Cortex-M3 and M4, ARM provides an optional HW block that includes both TPIU and SWO functionalities and is again named TPIU, which causes quite some confusion. The registers map of all the TPIU and SWO implementations allows using a single driver that detects at runtime the features available. The 'tpiu' is used for either TPIU or SWO. A convenient alias 'swo' is available to help distinguish, in scripts, the commands for SWO from the commands for TPIU. -- Command: swo ... Alias of 'tpiu ...'. Can be used in scripts to distinguish the commands for SWO from the commands for TPIU. -- Command: tpiu create tpiu_name configparams... Creates a TPIU or a SWO object. The two commands are equivalent. Add the object in a list and add new commands ('TPIU_NAME') which are used for various purposes including additional configuration. * TPIU_NAME - the name of the TPIU or SWO object. This name is also used to create the object's command, referred to here as '$tpiu_name', and in other places where the TPIU or SWO needs to be identified. * CONFIGPARAMS - all parameters accepted by '$tpiu_name configure' are permitted. You _must_ set here the AP and MEM_AP base_address through '-dap DAP_NAME', '-ap-num AP_NUMBER' and '-baseaddr BASE_ADDRESS'. -- Command: tpiu names Lists all the TPIU or SWO objects created so far. The two commands are equivalent. -- Command: tpiu init Initialize all registered TPIU and SWO. The two commands are equivalent. These commands are used internally during initialization. They can be issued at any time after the initialization, too. -- Command: $tpiu_name cget queryparm Each configuration parameter accepted by '$tpiu_name configure' can be individually queried, to return its current value. The QUERYPARM is a parameter name accepted by that command, such as '-dap'. -- Command: $tpiu_name configure configparams... The options accepted by this command may also be specified as parameters to 'tpiu create'. Their values can later be queried one at a time by using the '$tpiu_name cget' command. * '-dap' DAP_NAME - names the DAP used to access this TPIU. *Note DAP declaration: dapdeclaration, on how to create and manage DAP instances. * '-ap-num' AP_NUMBER - sets DAP access port for TPIU, AP_NUMBER is the numeric index of the DAP AP the TPIU is connected to. * '-baseaddr' BASE_ADDRESS - sets the TPIU BASE_ADDRESS where to access the TPIU in the DAP AP memory space. * '-protocol' ('sync'|'uart'|'manchester') - sets the protocol used for trace data: - 'sync' - synchronous parallel trace output mode, using PORT_WIDTH data bits (default); - 'uart' - use asynchronous SWO mode with NRZ (same as regular UART 8N1) coding; - 'manchester' - use asynchronous SWO mode with Manchester coding. * '-event' EVENT_NAME EVENT_BODY - assigns an event handler, a TCL string which is evaluated when the event is triggered. The events 'pre-enable', 'post-enable', 'pre-disable' and 'post-disable' are defined for TPIU/SWO. A typical use case for the event 'pre-enable' is to enable the trace clock of the TPIU. * '-output' ('external'|':'PORT|FILENAME|'-') - specifies the destination of the trace data: - 'external' - configure TPIU/SWO to let user capture trace output externally, either with an additional UART or with a logic analyzer (default); - '-' - configure TPIU/SWO and debug adapter to gather trace data and forward it to 'tcl_trace' command; - ':'PORT - configure TPIU/SWO and debug adapter to gather trace data, open a TCP server at port PORT and send the trace data to each connected client; - FILENAME - configure TPIU/SWO and debug adapter to gather trace data and append it to FILENAME, which can be either a regular file or a named pipe. * '-traceclk' TRACECLKIN_FREQ - mandatory parameter. Specifies the frequency in Hz of the trace clock. For the TPIU embedded in Cortex-M3 or M4, this is usually the same frequency as HCLK. For protocol 'sync' this is twice the frequency of the pin data rate. * '-pin-freq' TRACE_FREQ - specifies the expected data rate in Hz of the SWO pin. Parameter used only on protocols 'uart' and 'manchester'. Can be omitted to let the adapter driver select the maximum supported rate automatically. * '-port-width' PORT_WIDTH - sets to PORT_WIDTH the width of the synchronous parallel port used for trace output. Parameter used only on protocol 'sync'. If not specified, default value is 1. * '-formatter' ('0'|'1') - specifies if the formatter should be enabled. Parameter used only on protocol 'sync'. If not specified, default value is 0. -- Command: $tpiu_name enable Uses the parameters specified by the previous '$tpiu_name configure' to configure and enable the TPIU or the SWO. If required, the adapter is also configured and enabled to receive the trace data. This command can be used before 'init', but it will take effect only after the 'init'. -- Command: $tpiu_name disable Disable the TPIU or the SWO, terminating the receiving of the trace data. Example usage: 1. STM32L152 board is programmed with an application that configures PLL to provide core clock with 24MHz frequency; to use ITM output it's enough to: #include ... ITM_STIM8(0) = c; ... (the most obvious way is to use the first stimulus port for printf, for that this ITM_STIM8 assignment can be used inside _write(); to make it blocking to avoid data loss, add 'while (!(ITM_STIM8(0) & ITM_STIM_FIFOREADY));'); 2. An FT2232H UART is connected to the SWO pin of the board; 3. Commands to configure UART for 12MHz baud rate: $ setserial /dev/ttyUSB1 spd_cust divisor 5 $ stty -F /dev/ttyUSB1 38400 (FT2232H's base frequency is 60MHz, spd_cust allows to alias 38400 baud with our custom divisor to get 12MHz) 4. 'itmdump -f /dev/ttyUSB1 -d1' 5. OpenOCD invocation line: openocd -f interface/stlink.cfg \ -c "transport select hla_swd" \ -f target/stm32l1.cfg \ -c "stm32l1.tpiu configure -protocol uart" \ -c "stm32l1.tpiu configure -traceclk 24000000 -pin-freq 12000000" \ -c "stm32l1.tpiu enable" 16.6.4 ARMv7-M specific commands -------------------------------- -- Command: itm port PORT (0|1|on|off) Enable or disable trace output for ITM stimulus PORT (counting from 0). Port 0 is enabled on target creation automatically. -- Command: itm ports (0|1|on|off) Enable or disable trace output for all ITM stimulus ports. 16.6.5 Cortex-M specific commands --------------------------------- -- Command: cortex_m maskisr (auto|on|off|steponly) Control masking (disabling) interrupts during target step/resume. The 'auto' option handles interrupts during stepping in a way that they get served but don't disturb the program flow. The step command first allows pending interrupt handlers to execute, then disables interrupts and steps over the next instruction where the core was halted. After the step interrupts are enabled again. If the interrupt handlers don't complete within 500ms, the step command leaves with the core running. The 'steponly' option disables interrupts during single-stepping but enables them during normal execution. This can be used as a partial workaround for 702596 erratum in Cortex-M7 r0p1. See "Cortex-M7 (AT610) and Cortex-M7 with FPU (AT611) Software Developer Errata Notice" from ARM for further details. Note that a free hardware (FPB) breakpoint is required for the 'auto' option. If no breakpoint is available at the time of the step, then the step is taken with interrupts enabled, i.e. the same way the 'off' option does. Default is 'auto'. -- Command: cortex_m vector_catch [all|none|list] Vector Catch hardware provides dedicated breakpoints for certain hardware events. Parameters request interception of 'all' of these hardware event vectors, 'none' of them, or one or more of the following: 'hard_err' for a HardFault exception; 'mm_err' for a MemManage exception; 'bus_err' for a BusFault exception; 'irq_err', 'state_err', 'chk_err', or 'nocp_err' for various UsageFault exceptions; or 'reset'. If NVIC setup code does not enable them, MemManage, BusFault, and UsageFault exceptions are mapped to HardFault. UsageFault checks for divide-by-zero and unaligned access must also be explicitly enabled. This finishes by listing the current vector catch configuration. -- Command: cortex_m reset_config (sysresetreq|vectreset) Control reset handling if hardware srst is not fitted *Note reset_config: reset_config. - 'sysresetreq' use AIRCR SYSRESETREQ to reset system. - 'vectreset' use AIRCR VECTRESET to reset system (default). Using 'vectreset' is a safe option for Cortex-M3, M4 and M7 cores. This however has the disadvantage of only resetting the core, all peripherals are unaffected. A solution would be to use a 'reset-init' event handler to manually reset the peripherals. *Note Target Events: targetevents. Cortex-M0, M0+ and M1 do not support 'vectreset', use 'sysresetreq' instead. 16.6.6 ARMv8-A specific commands -------------------------------- -- Command: aarch64 cache_info Display information about target caches -- Command: aarch64 dbginit This command enables debugging by clearing the OS Lock and sticky power-down and reset indications. It also establishes the expected, basic cross-trigger configuration the aarch64 target code relies on. In a configuration file, the command would typically be called from a 'reset-end' or 'reset-deassert-post' handler, to re-enable debugging after a system reset. However, normally it is not necessary to use the command at all. -- Command: aarch64 disassemble address [count] Disassembles COUNT instructions starting at ADDRESS. If COUNT is not specified, a single instruction is disassembled. -- Command: aarch64 smp [on|off] Display, enable or disable SMP handling mode. The state of SMP handling influences the way targets in an SMP group are handled by the run control. With SMP handling enabled, issuing halt or resume to one core will trigger halting or resuming of all cores in the group. The command 'target smp' defines which targets are in the SMP group. With SMP handling disabled, all targets need to be treated individually. -- Command: aarch64 maskisr [on|off] Selects whether interrupts will be processed when single stepping. The default configuration is 'on'. -- Command: $target_name catch_exc [off|sec_el1|sec_el3|nsec_el1|nsec_el2]+ Cause '$target_name' to halt when an exception is taken. Any combination of Secure (sec) EL1/EL3 or Non-Secure (nsec) EL1/EL2 is valid. The target '$target_name' will halt before taking the exception. In order to resume the target, the exception catch must be disabled again with '$target_name catch_exc off'. Issuing the command without options prints the current configuration. 16.7 EnSilica eSi-RISC Architecture =================================== eSi-RISC is a highly configurable microprocessor architecture for embedded systems provided by EnSilica. (See: .) 16.7.1 eSi-RISC Configuration ----------------------------- -- Command: esirisc cache_arch (harvard|von_neumann) Configure the caching architecture. Targets with the 'UNIFIED_ADDRESS_SPACE' option disabled employ a Harvard architecture. By default, 'von_neumann' is assumed. -- Command: esirisc hwdc (all|none|mask ...) Configure hardware debug control. The HWDC register controls which exceptions return control back to the debugger. Possible masks are 'all', 'none', 'reset', 'interrupt', 'syscall', 'error', and 'debug'. By default, 'reset', 'error', and 'debug' are enabled. 16.7.2 eSi-RISC Operation ------------------------- -- Command: esirisc flush_caches Flush instruction and data caches. This command requires that the target is halted when the command is issued and configured with an instruction or data cache. 16.7.3 eSi-Trace Configuration ------------------------------ eSi-RISC targets may be configured with support for instruction tracing. Trace data may be written to an in-memory buffer or FIFO. If a FIFO is configured, DMA is typically employed to move trace data off-device using a high-speed peripheral (eg. SPI). Collected trace data is encoded in one of three different formats. At a minimum, 'esirisc trace buffer' or 'esirisc trace fifo' must be issued along with 'esirisc trace format' before trace data can be collected. OpenOCD provides rudimentary analysis of collected trace data. If more detail is needed, collected trace data can be dumped to a file and processed by external tooling. Issues: OpenOCD is unable to process trace data sent to a FIFO. A potential workaround for this issue is to configure DMA to copy trace data to an in-memory buffer, which can then be passed to the 'esirisc trace analyze' and 'esirisc trace dump' commands. It is possible to corrupt trace data when using a FIFO if the peripheral responsible for draining data from the FIFO is not fast enough. This can be managed by enabling flow control, however this can impact timing-sensitive software operation on the CPU. -- Command: esirisc trace buffer address size [wrap] Configure trace buffer using the provided address and size. If the 'wrap' option is specified, trace collection will continue once the end of the buffer is reached. By default, wrap is disabled. -- Command: esirisc trace fifo address Configure trace FIFO using the provided address. -- Command: esirisc trace flow_control (enable|disable) Enable or disable stalling the CPU to collect trace data. By default, flow control is disabled. -- Command: esirisc trace format (full|branch|icache) pc_bits Configure trace format and number of PC bits to be captured. 'pc_bits' must be within 1 and 31 as the LSB is not collected. If external tooling is used to analyze collected trace data, these values must match. Supported trace formats: * 'full' capture full trace data, allowing execution history and timing to be determined. * 'branch' capture taken branch instructions and branch target addresses. * 'icache' capture instruction cache misses. -- Command: esirisc trace trigger start (condition) [start_data start_mask] Configure trigger start condition using the provided start data and mask. A brief description of each condition is provided below; for more detail on how these values are used, see the eSi-RISC Architecture Manual. Supported conditions: * 'none' manual tracing (see 'esirisc trace start'). * 'pc' start tracing if the PC matches start data and mask. * 'load' start tracing if the effective address of a load instruction matches start data and mask. * 'store' start tracing if the effective address of a store instruction matches start data and mask. * 'exception' start tracing if the EID of an exception matches start data and mask. * 'eret' start tracing when an 'ERET' instruction is executed. * 'wait' start tracing when a 'WAIT' instruction is executed. * 'stop' start tracing when a 'STOP' instruction is executed. * 'high' start tracing when an external signal is a logical high. * 'low' start tracing when an external signal is a logical low. -- Command: esirisc trace trigger stop (condition) [stop_data stop_mask] Configure trigger stop condition using the provided stop data and mask. A brief description of each condition is provided below; for more detail on how these values are used, see the eSi-RISC Architecture Manual. Supported conditions: * 'none' manual tracing (see 'esirisc trace stop'). * 'pc' stop tracing if the PC matches stop data and mask. * 'load' stop tracing if the effective address of a load instruction matches stop data and mask. * 'store' stop tracing if the effective address of a store instruction matches stop data and mask. * 'exception' stop tracing if the EID of an exception matches stop data and mask. * 'eret' stop tracing when an 'ERET' instruction is executed. * 'wait' stop tracing when a 'WAIT' instruction is executed. * 'stop' stop tracing when a 'STOP' instruction is executed. -- Command: esirisc trace trigger delay (trigger) [cycles] Configure trigger start/stop delay in clock cycles. Supported triggers: * 'none' no delay to start or stop collection. * 'start' delay 'cycles' after trigger to start collection. * 'stop' delay 'cycles' after trigger to stop collection. * 'both' delay 'cycles' after both triggers to start or stop collection. 16.7.4 eSi-Trace Operation -------------------------- -- Command: esirisc trace init Initialize trace collection. This command must be called any time the configuration changes. If a trace buffer has been configured, the contents will be overwritten when trace collection starts. -- Command: esirisc trace info Display trace configuration. -- Command: esirisc trace status Display trace collection status. -- Command: esirisc trace start Start manual trace collection. -- Command: esirisc trace stop Stop manual trace collection. -- Command: esirisc trace analyze [address size] Analyze collected trace data. This command may only be used if a trace buffer has been configured. If a trace FIFO has been configured, trace data must be copied to an in-memory buffer identified by the 'address' and 'size' options using DMA. -- Command: esirisc trace dump [address size] filename Dump collected trace data to file. This command may only be used if a trace buffer has been configured. If a trace FIFO has been configured, trace data must be copied to an in-memory buffer identified by the 'address' and 'size' options using DMA. 16.8 Intel Architecture ======================= Intel Quark X10xx is the first product in the Quark family of SoCs. It is an IA-32 (Pentium x86 ISA) compatible SoC. The core CPU in the X10xx is codenamed Lakemont. Lakemont version 1 (LMT1) is used in X10xx. The CPU TAP (Lakemont TAP) is used for software debug and the CLTAP is used for SoC level operations. Useful docs are here: https://communities.intel.com/community/makers/documentation * Intel Quark SoC X1000 OpenOCD/GDB/Eclipse App Note (web search for doc num 330015) * Intel Quark SoC X1000 Debug Operations User Guide (web search for doc num 329866) * Intel Quark SoC X1000 Datasheet (web search for doc num 329676) 16.8.1 x86 32-bit specific commands ----------------------------------- The three main address spaces for x86 are memory, I/O and configuration space. These commands allow a user to read and write to the 64Kbyte I/O address space. -- Command: x86_32 idw address Display the contents of a 32-bit I/O port from address range 0x0000 - 0xffff. -- Command: x86_32 idh address Display the contents of a 16-bit I/O port from address range 0x0000 - 0xffff. -- Command: x86_32 idb address Display the contents of a 8-bit I/O port from address range 0x0000 - 0xffff. -- Command: x86_32 iww address Write the contents of a 32-bit I/O port to address range 0x0000 - 0xffff. -- Command: x86_32 iwh address Write the contents of a 16-bit I/O port to address range 0x0000 - 0xffff. -- Command: x86_32 iwb address Write the contents of a 8-bit I/O port to address range 0x0000 - 0xffff. 16.9 OpenRISC Architecture ========================== The OpenRISC CPU is a soft core. It is used in a programmable SoC which can be configured with any of the TAP / Debug Unit available. 16.9.1 TAP and Debug Unit selection commands -------------------------------------------- -- Command: tap_select (vjtag|mohor|xilinx_bscan) Select between the Altera Virtual JTAG , Xilinx Virtual JTAG and Mohor TAP. -- Command: du_select (adv|mohor) [option] Select between the Advanced Debug Interface and the classic one. An option can be passed as a second argument to the debug unit. When using the Advanced Debug Interface, option = 1 means the RTL core is configured with ADBG_USE_HISPEED = 1. This configuration skips status checking between bytes while doing read or write bursts. 16.9.2 Registers commands ------------------------- -- Command: addreg [name] [address] [feature] [reg_group] Add a new register in the cpu register list. This register will be included in the generated target descriptor file. *[feature]* must be "org.gnu.gdb.or1k.group[0..10]". *[reg_group]* can be anything. The default register list defines "system", "dmmu", "immu", "dcache", "icache", "mac", "debug", "perf", "power", "pic" and "timer" groups. _example:_ addreg rtest 0x1234 org.gnu.gdb.or1k.group0 system 16.10 RISC-V Architecture ========================= RISC-V (http://riscv.org/) is a free and open ISA. OpenOCD supports JTAG debug of RV32 and RV64 cores in heterogeneous multicore systems of up to 32 harts. (It's possible to increase this limit to 1024 by changing RISCV_MAX_HARTS in riscv.h.) OpenOCD primarily supports 0.13 of the RISC-V Debug Specification, but there is also support for legacy targets that implement version 0.11. 16.10.1 RISC-V Terminology -------------------------- A _hart_ is a hardware thread. A hart may share resources (eg. FPU) with another hart, or may be a separate core. RISC-V treats those the same, and OpenOCD exposes each hart as a separate core. 16.10.2 Vector Registers ------------------------ For harts that implement the vector extension, OpenOCD provides access to the relevant CSRs, as well as the vector registers (v0-v31). The size of each vector register is dependent on the value of vlenb. RISC-V allows each vector register to be divided into selected-width elements, and this division can be changed at run-time. Because OpenOCD cannot update register definitions at run-time, it exposes each vector register to gdb as a union of fields of vectors so that users can easily access individual bytes, shorts, words, longs, and quads inside each vector register. It is left to gdb or higher-level debuggers to present this data in a more intuitive format. In the XML register description, the vector registers (when vlenb=16) look as follows: ... 16.10.3 RISC-V Debug Configuration Commands ------------------------------------------- -- Config Command: riscv expose_csrs n[-m|=name] [...] Configure which CSRs to expose in addition to the standard ones. The CSRs to expose can be specified as individual register numbers or register ranges (inclusive). For the individually listed CSRs, a human-readable name can optionally be set using the 'n=name' syntax, which will get 'csr_' prepended to it. If no name is provided, the register will be named 'csr'. By default OpenOCD attempts to expose only CSRs that are mentioned in a spec, and then only if the corresponding extension appears to be implemented. This command can be used if OpenOCD gets this wrong, or if the target implements custom CSRs. # Expose a single RISC-V CSR number 128 under the name "csr128": $_TARGETNAME expose_csrs 128 # Expose multiple RISC-V CSRs 128..132 under names "csr128" through "csr132": $_TARGETNAME expose_csrs 128-132 # Expose a single RISC-V CSR number 1996 under custom name "csr_myregister": $_TARGETNAME expose_csrs 1996=myregister -- Config Command: riscv expose_custom n[-m|=name] [...] The RISC-V Debug Specification allows targets to expose custom registers through abstract commands. (See Section 3.5.1.1 in that document.) This command configures individual registers or register ranges (inclusive) that shall be exposed. Number 0 indicates the first custom register, whose abstract command number is 0xc000. For individually listed registers, a human-readable name can be optionally provided using the 'n=name' syntax, which will get 'custom_' prepended to it. If no name is provided, the register will be named 'custom'. # Expose one RISC-V custom register with number 0xc010 (0xc000 + 16) # under the name "custom16": $_TARGETNAME expose_custom 16 # Expose a range of RISC-V custom registers with numbers 0xc010 .. 0xc018 # (0xc000+16 .. 0xc000+24) under the names "custom16" through "custom24": $_TARGETNAME expose_custom 16-24 # Expose one RISC-V custom register with number 0xc020 (0xc000 + 32) under # user-defined name "custom_myregister": $_TARGETNAME expose_custom 32=myregister -- Command: riscv set_command_timeout_sec [seconds] Set the wall-clock timeout (in seconds) for individual commands. The default should work fine for all but the slowest targets (eg. simulators). -- Command: riscv set_reset_timeout_sec [seconds] Set the maximum time to wait for a hart to come out of reset after reset is deasserted. -- Command: riscv set_scratch_ram none|[address] Set the address of 16 bytes of scratch RAM the debugger can use, or 'none'. This is used to access 64-bit floating point registers on 32-bit targets. -- Command: riscv set_mem_access method1 [method2] [method3] Specify which RISC-V memory access method(s) shall be used, and in which order of priority. At least one method must be specified. Available methods are: * 'progbuf' - Use RISC-V Debug Program Buffer to access memory. * 'sysbus' - Access memory via RISC-V Debug System Bus interface. * 'abstract' - Access memory via RISC-V Debug abstract commands. By default, all memory access methods are enabled in the following order: 'progbuf sysbus abstract'. This command can be used to change the memory access methods if the default behavior is not suitable for a particular target. -- Command: riscv set_enable_virtual on|off When on, memory accesses are performed on physical or virtual memory depending on the current system configuration. When off (default), all memory accessses are performed on physical memory. -- Command: riscv set_enable_virt2phys on|off When on (default), memory accesses are performed on physical or virtual memory depending on the current satp configuration. When off, all memory accessses are performed on physical memory. -- Command: riscv resume_order normal|reversed Some software assumes all harts are executing nearly continuously. Such software may be sensitive to the order that harts are resumed in. On harts that don't support hasel, this option allows the user to choose the order the harts are resumed in. If you are using this option, it's probably masking a race condition problem in your code. Normal order is from lowest hart index to highest. This is the default behavior. Reversed order is from highest hart index to lowest. -- Command: riscv set_ir (idcode|dtmcs|dmi) [value] Set the IR value for the specified JTAG register. This is useful, for example, when using the existing JTAG interface on a Xilinx FPGA by way of BSCANE2 primitives that only permit a limited selection of IR values. When utilizing version 0.11 of the RISC-V Debug Specification, 'dtmcs' and 'dmi' set the IR values for the DTMCONTROL and DBUS registers, respectively. -- Command: riscv use_bscan_tunnel value Enable or disable use of a BSCAN tunnel to reach DM. Supply the width of the DM transport TAP's instruction register to enable. Supply a value of 0 to disable. -- Command: riscv set_ebreakm on|off Control dcsr.ebreakm. When on (default), M-mode ebreak instructions trap to OpenOCD. When off, they generate a breakpoint exception handled internally. -- Command: riscv set_ebreaks on|off Control dcsr.ebreaks. When on (default), S-mode ebreak instructions trap to OpenOCD. When off, they generate a breakpoint exception handled internally. -- Command: riscv set_ebreaku on|off Control dcsr.ebreaku. When on (default), U-mode ebreak instructions trap to OpenOCD. When off, they generate a breakpoint exception handled internally. 16.10.4 RISC-V Authentication Commands -------------------------------------- The following commands can be used to authenticate to a RISC-V system. Eg. a trivial challenge-response protocol could be implemented as follows in a configuration file, immediately following 'init': set challenge [riscv authdata_read] riscv authdata_write [expr {$challenge + 1}] -- Command: riscv authdata_read Return the 32-bit value read from authdata. -- Command: riscv authdata_write value Write the 32-bit value to authdata. 16.10.5 RISC-V DMI Commands --------------------------- The following commands allow direct access to the Debug Module Interface, which can be used to interact with custom debug features. -- Command: riscv dmi_read address Perform a 32-bit DMI read at address, returning the value. -- Command: riscv dmi_write address value Perform a 32-bit DMI write of value at address. 16.11 ARC Architecture ====================== Synopsys DesignWare ARC Processors are a family of 32-bit CPUs that SoC designers can optimize for a wide range of uses, from deeply embedded to high-performance host applications in a variety of market segments. See more at: . OpenOCD currently supports ARC EM processors. There is a set ARC-specific OpenOCD commands that allow low-level access to the core and provide necessary support for ARC extensibility and configurability capabilities. ARC processors has much more configuration capabilities than most of the other processors and in addition there is an extension interface that allows SoC designers to add custom registers and instructions. For the OpenOCD that mostly means that set of core and AUX registers in target will vary and is not fixed for a particular processor model. To enable extensibility several TCL commands are provided that allow to describe those optional registers in OpenOCD configuration files. Moreover those commands allow for a dynamic target features discovery. 16.11.1 General ARC commands ---------------------------- -- Config Command: arc add-reg configparams Add a new register to processor target. By default newly created register is marked as not existing. CONFIGPARAMS must have following required arguments: * '-name' name Name of a register. * '-num' number Architectural register number: core register number or AUX register number. * '-feature' XML_feature Name of GDB XML target description feature. CONFIGPARAMS may have following optional arguments: * '-gdbnum' number GDB register number. It is recommended to not assign GDB register number manually, because there would be a risk that two register will have same number. When register GDB number is not set with this option, then register will get a previous register number + 1. This option is required only for those registers that must be at particular address expected by GDB. * '-core' This option specifies that register is a core registers. If not - this is an AUX register. AUX registers and core registers reside in different address spaces. * '-bcr' This options specifies that register is a BCR register. BCR means Build Configuration Registers - this is a special type of AUX registers that are read only and non-volatile, that is - they never change their value. Therefore OpenOCD never invalidates values of those registers in internal caches. Because BCR is a type of AUX registers, this option cannot be used with '-core'. * '-type' type_name Name of type of this register. This can be either one of the basic GDB types, or a custom types described with 'arc add-reg-type-[flags|struct]'. * '-g' If specified then this is a "general" register. General registers are always read by OpenOCD on context save (when core has just been halted) and is always transferred to GDB client in a response to g-packet. Contrary to this, non-general registers are read and sent to GDB client on-demand. In general it is not recommended to apply this option to custom registers. -- Config Command: arc add-reg-type-flags -name name flags... Adds new register type of "flags" class. "Flags" types can contain only one-bit fields. Each flag definition looks like '-flag name bit-position'. -- Config Command: arc add-reg-type-struct -name name structs... Adds new register type of "struct" class. "Struct" types can contain either bit-fields or fields of other types, however at the moment only bit fields are supported. Structure bit field definition looks like '-bitfield name startbit endbit'. -- Command: arc get-reg-field reg-name field-name Returns value of bit-field in a register. Register must be "struct" register type, *Note add-reg-type-struct::. command definition. -- Command: arc set-reg-exists reg-names... Specify that some register exists. Any amount of names can be passed as an argument for a single command invocation. 16.11.2 ARC JTAG commands ------------------------- -- Command: arc jtag set-aux-reg regnum value This command writes value to AUX register via its number. This command access register in target directly via JTAG, bypassing any OpenOCD internal caches, therefore it is unsafe to use if that register can be operated by other means. -- Command: arc jtag set-core-reg regnum value This command is similar to 'arc jtag set-aux-reg' but is for core registers. -- Command: arc jtag get-aux-reg regnum This command returns the value storded in AUX register via its number. This commands access register in target directly via JTAG, bypassing any OpenOCD internal caches, therefore it is unsafe to use if that register can be operated by other means. -- Command: arc jtag get-core-reg regnum This command is similar to 'arc jtag get-aux-reg' but is for core registers. 16.12 STM8 Architecture ======================= STM8 (http://st.com/stm8/) is a 8-bit microcontroller platform from STMicroelectronics, based on a proprietary 8-bit core architecture. OpenOCD supports debugging STM8 through the STMicroelectronics debug protocol SWIM, *note SWIM: swimtransport. 16.13 Xtensa Architecture ========================= Xtensa processors are based on a modular, highly flexible 32-bit RISC architecture that can easily scale from a tiny, cache-less controller or task engine to a high-performance SIMD/VLIW DSP provided by Cadence. . OpenOCD supports generic Xtensa processors implementation which can be customized by simply providing vendor-specific core configuration which controls every configurable Xtensa architecture option, e.g. number of address registers, exceptions, reduced size instructions support, memory banks configuration etc. Also OpenOCD supports SMP configurations for Xtensa processors with any number of cores and allows to configure their debug signals interconnection (so-called "break/stall networks") which control how debug signals are distributed among cores. Xtensa "break networks" are compatible with ARM's Cross Trigger Interface (CTI). For debugging code on Xtensa chips OpenOCD uses JTAG protocol. Currently OpenOCD implements several Epsressif Xtensa-based chips of ESP32 family (https://www.espressif.com/en/products/socs). 16.13.1 General Xtensa Commands ------------------------------- -- Command: xtensa set_permissive (0|1) By default accessing memory beyond defined regions is forbidden. This commnd controls memory access address check. When set to (1), skips access controls and address range check before read/write memory. -- Command: xtensa maskisr (on|off) Selects whether interrupts will be disabled during stepping over single instruction. The default configuration is (off). -- Command: xtensa smpbreak [none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut] Configures debug signals connection ("break network") for currently selected core. * 'none' - Core's "break/stall network" is disconnected. Core is not affected by any debug signal from other cores. * 'breakinout' - Core's "break network" is fully connected (break inputs and outputs are enabled). Core will receive debug break signals from other cores and send such signals to them. For example when another core is stopped due to breakpoint hit this core will be stopped too and vice versa. * 'runstall' - Core's "stall network" is fully connected (stall inputs and outputs are enabled). This feature is not well implemented and tested yet. * 'BreakIn' - Core's "break-in" signal is enabled. Core will receive debug break signals from other cores. For example when another core is stopped due to breakpoint hit this core will be stopped too. * 'BreakOut' - Core's "break-out" signal is enabled. Core will send debug break signal to other cores. For example when this core is stopped due to breakpoint hit other cores with enabled break-in signals will be stopped too. * 'RunStallIn' - Core's "runstall-in" signal is enabled. This feature is not well implemented and tested yet. * 'DebugModeOut' - Core's "debugmode-out" signal is enabled. This feature is not well implemented and tested yet. -- Command: xtensa perfmon_enable [mask] [kernelcnt] [tracelevel] Enable and start performance counter. * 'counter_id' - Counter ID (0-1). * 'select' - Selects performance metric to be counted by the counter, e.g. 0 - CPU cycles, 2 - retired instructions. * 'mask' - Selects input subsets to be counted (counter will increment only once even if more than one condition corresponding to a mask bit occurs). * 'kernelcnt' - 0 - count events with "CINTLEVEL <= tracelevel", 1 - count events with "CINTLEVEL > tracelevel". * 'tracelevel' - Compares this value to "CINTLEVEL" when deciding whether to count. -- Command: xtensa perfmon_dump (counter_id) Dump performance counter value. If no argument specified, dumps all counters. -- Command: xtensa tracestart [pc /[]] [after [ins|words]] Set up and start a HW trace. Optionally set PC address range to trigger tracing stop when reached during program execution. This command also allows to specify the amount of data to capture after stop trigger activation. * 'pcval' - PC value which will trigger trace data collection stop. * 'maskbitcount' - PC value mask. * 'n' - Maximum number of instructions/words to capture after trace stop trigger. -- Command: xtensa tracestop Stop current trace as started by the tracestart command. -- Command: xtensa tracedump Dump trace memory to a file. 16.14 Software Debug Messages and Tracing ========================================= OpenOCD can process certain requests from target software, when the target uses appropriate libraries. The most powerful mechanism is semihosting, but there is also a lighter weight mechanism using only the DCC channel. Currently 'target_request debugmsgs' is supported only for 'arm7_9' and 'cortex_m' cores. These messages are received as part of target polling, so you need to have 'poll on' active to receive them. They are intrusive in that they will affect program execution times. If that is a problem, *note ARM Hardware Tracing: armhardwaretracing. See 'libdcc' in the contrib dir for more details. In addition to sending strings, characters, and arrays of various size integers from the target, 'libdcc' also exports a software trace point mechanism. The target being debugged may issue trace messages which include a 24-bit "trace point" number. Trace point support includes two distinct mechanisms, each supported by a command: * _History_ ... A circular buffer of trace points can be set up, and then displayed at any time. This tracks where code has been, which can be invaluable in finding out how some fault was triggered. The buffer may overflow, since it collects records continuously. It may be useful to use some of the 24 bits to represent a particular event, and other bits to hold data. * _Counting_ ... An array of counters can be set up, and then displayed at any time. This can help establish code coverage and identify hot spots. The array of counters is directly indexed by the trace point number, so trace points with higher numbers are not counted. Linux-ARM kernels have a "Kernel low-level debugging via EmbeddedICE DCC channel" option (CONFIG_DEBUG_ICEDCC, depends on CONFIG_DEBUG_LL) which uses this mechanism to deliver messages before a serial console can be activated. This is not the same format used by 'libdcc'. Other software, such as the U-Boot boot loader, sometimes does the same thing. -- Command: target_request debugmsgs [enable|disable|charmsg] Displays current handling of target DCC message requests. These messages may be sent to the debugger while the target is running. The optional 'enable' and 'charmsg' parameters both enable the messages, while 'disable' disables them. With 'charmsg' the DCC words each contain one character, as used by Linux with CONFIG_DEBUG_ICEDCC; otherwise the libdcc format is used. -- Command: trace history [clear|count] With no parameter, displays all the trace points that have triggered in the order they triggered. With the parameter 'clear', erases all current trace history records. With a COUNT parameter, allocates space for that many history records. -- Command: trace point [clear|identifier] With no parameter, displays all trace point identifiers and how many times they have been triggered. With the parameter 'clear', erases all current trace point counters. With a numeric IDENTIFIER parameter, creates a new a trace point counter and associates it with that identifier. _Important:_ The identifier and the trace point number are not related except by this command. These trace point numbers always start at zero (from server startup, or after 'trace point clear') and count up from there.  File: openocd.info, Node: JTAG Commands, Next: Boundary Scan Commands, Prev: Architecture and Core Commands, Up: Top 17 JTAG Commands **************** Most general purpose JTAG commands have been presented earlier. (*Note JTAG Speed: jtagspeed, *note Reset Configuration::, and *note TAP Declaration::.) Lower level JTAG commands, as presented here, may be needed to work with targets which require special attention during operations such as reset or initialization. To use these commands you will need to understand some of the basics of JTAG, including: * A JTAG scan chain consists of a sequence of individual TAP devices such as a CPUs. * Control operations involve moving each TAP through the same standard state machine (in parallel) using their shared TMS and clock signals. * Data transfer involves shifting data through the chain of instruction or data registers of each TAP, writing new register values while the reading previous ones. * Data register sizes are a function of the instruction active in a given TAP, while instruction register sizes are fixed for each TAP. All TAPs support a BYPASS instruction with a single bit data register. * The way OpenOCD differentiates between TAP devices is by shifting different instructions into (and out of) their instruction registers. 17.1 Low Level JTAG Commands ============================ These commands are used by developers who need to access JTAG instruction or data registers, possibly controlling the order of TAP state transitions. If you're not debugging OpenOCD internals, or bringing up a new JTAG adapter or a new type of TAP device (like a CPU or JTAG router), you probably won't need to use these commands. In a debug session that doesn't use JTAG for its transport protocol, these commands are not available. -- Command: drscan tap [numbits value]+ [-endstate tap_state] Loads the data register of TAP with a series of bit fields that specify the entire register. Each field is NUMBITS bits long with a numeric VALUE (hexadecimal encouraged). The return value holds the original value of each of those fields. For example, a 38 bit number might be specified as one field of 32 bits then one of 6 bits. _For portability, never pass fields which are more than 32 bits long. Many OpenOCD implementations do not support 64-bit (or larger) integer values._ All TAPs other than TAP must be in BYPASS mode. The single bit in their data registers does not matter. When TAP_STATE is specified, the JTAG state machine is left in that state. For example DRPAUSE might be specified, so that more instructions can be issued before re-entering the RUN/IDLE state. If the end state is not specified, the RUN/IDLE state is entered. Warning: OpenOCD does not record information about data register lengths, so _it is important that you get the bit field lengths right_. Remember that different JTAG instructions refer to different data registers, which may have different lengths. Moreover, those lengths may not be fixed; the SCAN_N instruction can change the length of the register accessed by the INTEST instruction (by connecting a different scan chain). -- Command: flush_count Returns the number of times the JTAG queue has been flushed. This may be used for performance tuning. For example, flushing a queue over USB involves a minimum latency, often several milliseconds, which does not change with the amount of data which is written. You may be able to identify performance problems by finding tasks which waste bandwidth by flushing small transfers too often, instead of batching them into larger operations. -- Command: irscan [tap instruction]+ [-endstate tap_state] For each TAP listed, loads the instruction register with its associated numeric INSTRUCTION. (The number of bits in that instruction may be displayed using the 'scan_chain' command.) For other TAPs, a BYPASS instruction is loaded. When TAP_STATE is specified, the JTAG state machine is left in that state. For example IRPAUSE might be specified, so the data register can be loaded before re-entering the RUN/IDLE state. If the end state is not specified, the RUN/IDLE state is entered. Note: OpenOCD currently supports only a single field for instruction register values, unlike data register values. For TAPs where the instruction register length is more than 32 bits, portable scripts currently must issue only BYPASS instructions. -- Command: pathmove start_state [next_state ...] Start by moving to START_STATE, which must be one of the _stable_ states. Unless it is the only state given, this will often be the current state, so that no TCK transitions are needed. Then, in a series of single state transitions (conforming to the JTAG state machine) shift to each NEXT_STATE in sequence, one per TCK cycle. The final state must also be stable. -- Command: runtest NUM_CYCLES Move to the RUN/IDLE state, and execute at least NUM_CYCLES of the JTAG clock (TCK). Instructions often need some time to execute before they take effect. -- Command: verify_ircapture (enable|disable) Verify values captured during IRCAPTURE and returned during IR scans. Default is enabled, but this can be overridden by 'verify_jtag'. This flag is ignored when validating JTAG chain configuration. -- Command: verify_jtag (enable|disable) Enables verification of DR and IR scans, to help detect programming errors. For IR scans, 'verify_ircapture' must also be enabled. Default is enabled. 17.2 TAP state names ==================== The TAP_STATE names used by OpenOCD in the 'drscan', 'irscan', and 'pathmove' commands are the same as those used in SVF boundary scan documents, except that SVF uses IDLE instead of RUN/IDLE. * RESET ... _stable_ (with TMS high); acts as if TRST were pulsed * RUN/IDLE ... _stable_; don't assume this always means IDLE * DRSELECT * DRCAPTURE * DRSHIFT ... _stable_; TDI/TDO shifting through the data register * DREXIT1 * DRPAUSE ... _stable_; data register ready for update or more shifting * DREXIT2 * DRUPDATE * IRSELECT * IRCAPTURE * IRSHIFT ... _stable_; TDI/TDO shifting through the instruction register * IREXIT1 * IRPAUSE ... _stable_; instruction register ready for update or more shifting * IREXIT2 * IRUPDATE Note that only six of those states are fully "stable" in the face of TMS fixed (low except for RESET) and a free-running JTAG clock. For all the others, the next TCK transition changes to a new state. * From DRSHIFT and IRSHIFT, clock transitions will produce side effects by changing register contents. The values to be latched in upcoming DRUPDATE or IRUPDATE states may not be as expected. * RUN/IDLE, DRPAUSE, and IRPAUSE are reasonable choices after 'drscan' or 'irscan' commands, since they are free of JTAG side effects. * RUN/IDLE may have side effects that appear at non-JTAG levels, such as advancing the ARM9E-S instruction pipeline. Consult the documentation for the TAP(s) you are working with.  File: openocd.info, Node: Boundary Scan Commands, Next: Utility Commands, Prev: JTAG Commands, Up: Top 18 Boundary Scan Commands ************************* One of the original purposes of JTAG was to support boundary scan based hardware testing. Although its primary focus is to support On-Chip Debugging, OpenOCD also includes some boundary scan commands. 18.1 SVF: Serial Vector Format ============================== The Serial Vector Format, better known as "SVF", is a way to represent JTAG test patterns in text files. In a debug session using JTAG for its transport protocol, OpenOCD supports running such test files. -- Command: svf filename [-tap TAPNAME] [[-]quiet] [[-]nil] [[-]progress] [[-]ignore_error] This issues a JTAG reset (Test-Logic-Reset) and then runs the SVF script from 'filename'. Arguments can be specified in any order; the optional dash doesn't affect their semantics. Command options: - '-tap TAPNAME' ignore IR and DR headers and footers specified by the SVF file with HIR, TIR, HDR and TDR commands; instead, calculate them automatically according to the current JTAG chain configuration, targeting TAPNAME; - '[-]quiet' do not log every command before execution; - '[-]nil' "dry run", i.e., do not perform any operations on the real interface; - '[-]progress' enable progress indication; - '[-]ignore_error' continue execution despite TDO check errors. 18.2 XSVF: Xilinx Serial Vector Format ====================================== The Xilinx Serial Vector Format, better known as "XSVF", is a binary representation of SVF which is optimized for use with Xilinx devices. In a debug session using JTAG for its transport protocol, OpenOCD supports running such test files. Important: Not all XSVF commands are supported. -- Command: xsvf (tapname|plain) filename [virt2] [quiet] This issues a JTAG reset (Test-Logic-Reset) and then runs the XSVF script from 'filename'. When a TAPNAME is specified, the commands are directed at that TAP. When 'virt2' is specified, the XRUNTEST command counts are interpreted as TCK cycles instead of microseconds. Unless the 'quiet' option is specified, messages are logged for comments and some retries. The OpenOCD sources also include two utility scripts for working with XSVF; they are not currently installed after building the software. You may find them useful: * _svf2xsvf_ ... converts SVF files into the extended XSVF syntax understood by the 'xsvf' command; see notes below. * _xsvfdump_ ... converts XSVF files into a text output format; understands the OpenOCD extensions. The input format accepts a handful of non-standard extensions. These include three opcodes corresponding to SVF extensions from Lattice Semiconductor (LCOUNT, LDELAY, LDSR), and two opcodes supporting a more accurate translation of SVF (XTRST, XWAITSTATE). If _xsvfdump_ shows a file is using those opcodes, it probably will not be usable with other XSVF tools. 18.3 IPDBG: JTAG-Host server ============================ IPDBG is a set of tools to debug IP-Cores. It comprises, among others, a logic analyzer and an arbitrary waveform generator. These are synthesize-able hardware descriptions of logic circuits in addition to software for control, visualization and further analysis. In a session using JTAG for its transport protocol, OpenOCD supports the function of a JTAG-Host. The JTAG-Host is needed to connect the circuit over JTAG to the control-software. For more details see . -- Command: ipdbg [-start|-stop] -tap TAPNAME -hub IR_VALUE [DR_LENGTH] [-port NUMBER] [-tool NUMBER] [-vir [VIR_VALUE [LENGTH [INSTR_CODE]]]] Starts or stops a IPDBG JTAG-Host server. Arguments can be specified in any order. Command options: * '-start|-stop' starts or stops a IPDBG JTAG-Host server (default: start). * '-tap TAPNAME' targeting the TAP TAPNAME. * '-hub IR_VALUE' states that the JTAG hub is reachable with dr-scans while the JTAG instruction register has the value IR_VALUE. * '-port NUMBER' tcp port number where the JTAG-Host is listening. * '-tool NUMBER' number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. * '-vir [VIR_VALUE [LENGTH [INSTR_CODE]]]' On some devices, the user data-register is only reachable if there is a specific value in a second dr. This second dr is called vir (virtual ir). With this parameter given, the IPDBG satisfies this condition prior an access to the IPDBG-Hub. The value shifted into the vir is given by the first parameter VIR_VALUE (default: 0x11). The second parameter LENGTH is the length of the vir data register (default: 5). With the INSTR_CODE (default: 0x00e) parameter the ir value to shift data through vir can be configured. Examples: ipdbg -start -tap xc6s.tap -hub 0x02 -port 4242 -tool 4 Starts a server listening on tcp-port 4242 which connects to tool 4. The connection is through the TAP of a Xilinx Spartan 6 on USER1 instruction (tested with a papillion pro board). ipdbg -start -tap 10m50.tap -hub 0x00C -vir -port 60000 -tool 1 Starts a server listening on tcp-port 60000 which connects to tool 1 (data_up_1/data_down_1). The connection is through the TAP of a Intel MAX10 virtual jtag component (sld_instance_index is 0; sld_ir_width is smaller than 5).  File: openocd.info, Node: Utility Commands, Next: GDB and OpenOCD, Prev: Boundary Scan Commands, Up: Top 19 Utility Commands ******************* 19.1 RAM testing ================ There is often a need to stress-test random access memory (RAM) for errors. OpenOCD comes with a Tcl implementation of well-known memory testing procedures allowing the detection of all sorts of issues with electrical wiring, defective chips, PCB layout and other common hardware problems. To use them, you usually need to initialise your RAM controller first; consult your SoC's documentation to get the recommended list of register operations and translate them to the corresponding 'mww'/'mwb' commands. Load the memory testing functions with source [find tools/memtest.tcl] to get access to the following facilities: -- Command: memTestDataBus address Test the data bus wiring in a memory region by performing a walking 1's test at a fixed address within that region. -- Command: memTestAddressBus baseaddress size Perform a walking 1's test on the relevant bits of the address and check for aliasing. This test will find single-bit address failures such as stuck-high, stuck-low, and shorted pins. -- Command: memTestDevice baseaddress size Test the integrity of a physical memory device by performing an increment/decrement test over the entire region. In the process every storage bit in the device is tested as zero and as one. -- Command: runAllMemTests baseaddress size Run all of the above tests over a specified memory region. 19.2 Firmware recovery helpers ============================== OpenOCD includes an easy-to-use script to facilitate mass-market devices recovery with JTAG. For quickstart instructions run: openocd -f tools/firmware-recovery.tcl -c firmware_help  File: openocd.info, Node: GDB and OpenOCD, Next: Tcl Scripting API, Prev: Utility Commands, Up: Top 20 GDB and OpenOCD ****************** OpenOCD complies with the remote gdbserver protocol and, as such, can be used to debug remote targets. Setting up GDB to work with OpenOCD can involve several components: * The OpenOCD server support for GDB may need to be configured. *Note GDB Configuration: gdbconfiguration. * GDB's support for OpenOCD may need configuration, as shown in this chapter. * If you have a GUI environment like Eclipse, that also will probably need to be configured. Of course, the version of GDB you use will need to be one which has been built to know about the target CPU you're using. It's probably part of the tool chain you're using. For example, if you are doing cross-development for ARM on an x86 PC, instead of using the native x86 'gdb' command you might use 'arm-none-eabi-gdb' if that's the tool chain used to compile your code. 20.1 Connecting to GDB ====================== Use GDB 6.7 or newer with OpenOCD if you run into trouble. For instance GDB 6.3 has a known bug that produces bogus memory access errors, which has since been fixed; see OpenOCD can communicate with GDB in two ways: 1. A socket (TCP/IP) connection is typically started as follows: target extended-remote localhost:3333 This would cause GDB to connect to the gdbserver on the local pc using port 3333. The extended remote protocol is a super-set of the remote protocol and should be the preferred choice. More details are available in GDB documentation To speed-up typing, any GDB command can be abbreviated, including the extended remote command above that becomes: tar ext :3333 Note: If any backward compatibility issue requires using the old remote protocol in place of the extended remote one, the former protocol is still available through the command: target remote localhost:3333 2. A pipe connection is typically started as follows: target extended-remote | \ openocd -c "gdb_port pipe; log_output openocd.log" This would cause GDB to run OpenOCD and communicate using pipes (stdin/stdout). Using this method has the advantage of GDB starting/stopping OpenOCD for the debug session. log_output sends the log output to a file to ensure that the pipe is not saturated when using higher debug level outputs. To list the available OpenOCD commands type 'monitor help' on the GDB command line. 20.2 Sample GDB session startup =============================== With the remote protocol, GDB sessions start a little differently than they do when you're debugging locally. Here's an example showing how to start a debug session with a small ARM program. In this case the program was linked to be loaded into SRAM on a Cortex-M3. Most programs would be written into flash (address 0) and run from there. $ arm-none-eabi-gdb example.elf (gdb) target extended-remote localhost:3333 Remote debugging using localhost:3333 ... (gdb) monitor reset halt ... (gdb) load Loading section .vectors, size 0x100 lma 0x20000000 Loading section .text, size 0x5a0 lma 0x20000100 Loading section .data, size 0x18 lma 0x200006a0 Start address 0x2000061c, load size 1720 Transfer rate: 22 KB/sec, 573 bytes/write. (gdb) continue Continuing. ... You could then interrupt the GDB session to make the program break, type 'where' to show the stack, 'list' to show the code around the program counter, 'step' through code, set breakpoints or watchpoints, and so on. 20.3 Configuring GDB for OpenOCD ================================ OpenOCD supports the gdb 'qSupported' packet, this enables information to be sent by the GDB remote server (i.e. OpenOCD) to GDB. Typical information includes packet size and the device's memory map. You do not need to configure the packet size by hand, and the relevant parts of the memory map should be automatically set up when you declare (NOR) flash banks. However, there are other things which GDB can't currently query. You may need to set those up by hand. As OpenOCD starts up, you will often see a line reporting something like: Info : lm3s.cpu: hardware has 6 breakpoints, 4 watchpoints You can pass that information to GDB with these commands: set remote hardware-breakpoint-limit 6 set remote hardware-watchpoint-limit 4 With that particular hardware (Cortex-M3) the hardware breakpoints only work for code running from flash memory. Most other ARM systems do not have such restrictions. Rather than typing such commands interactively, you may prefer to save them in a file and have GDB execute them as it starts, perhaps using a '.gdbinit' in your project directory or starting GDB using 'gdb -x filename'. 20.4 Programming using GDB ========================== By default the target memory map is sent to GDB. This can be disabled by the following OpenOCD configuration option: gdb_memory_map disable For this to function correctly a valid flash configuration must also be set in OpenOCD. For faster performance you should also configure a valid working area. Informing GDB of the memory map of the target will enable GDB to protect any flash areas of the target and use hardware breakpoints by default. This means that the OpenOCD option 'gdb_breakpoint_override' is not required when using a memory map. *Note gdb_breakpoint_override: gdbbreakpointoverride. To view the configured memory map in GDB, use the GDB command 'info mem'. All other unassigned addresses within GDB are treated as RAM. GDB 6.8 and higher set any memory area not in the memory map as inaccessible. This can be changed to the old behaviour by using the following GDB command set mem inaccessible-by-default off If 'gdb_flash_program enable' is also used, GDB will be able to program any flash memory using the vFlash interface. GDB will look at the target memory map when a load command is given, if any areas to be programmed lie within the target flash area the vFlash packets will be used. If the target needs configuring before GDB programming, set target event gdb-flash-erase-start: $_TARGETNAME configure -event gdb-flash-erase-start BODY *Note Target Events: targetevents, for other GDB programming related events. To verify any flash programming the GDB command 'compare-sections' can be used. 20.5 Using GDB as a non-intrusive memory inspector ================================================== If your project controls more than a blinking LED, let's say a heavy industrial robot or an experimental nuclear reactor, stopping the controlling process just because you want to attach GDB is not a good option. OpenOCD does not support GDB non-stop mode (might be implemented in the future). Though there is a possible setup where the target does not get stopped and GDB treats it as it were running. If the target supports background access to memory while it is running, you can use GDB in this mode to inspect memory (mainly global variables) without any intrusion of the target process. Remove default setting of gdb-attach event. *Note Target Events: targetevents. Place following command after target configuration: $_TARGETNAME configure -event gdb-attach {} If any of installed flash banks does not support probe on running target, switch off gdb_memory_map: gdb_memory_map disable Ensure GDB is configured without interrupt-on-connect. Some GDB versions set it by default, some does not. set remote interrupt-on-connect off If you switched gdb_memory_map off, you may want to setup GDB memory map manually or issue 'set mem inaccessible-by-default off' Now you can issue GDB command 'target extended-remote ...' and inspect memory of a running target. Do not use GDB commands 'continue', 'step' or 'next' as they synchronize GDB with your target and GDB would require stopping the target to get the prompt back. Do not use this mode under an IDE like Eclipse as it caches values of previously shown variables. It's also possible to connect more than one GDB to the same target by the target's configuration option '-gdb-max-connections'. This allows, for example, one GDB to run a script that continuously polls a set of variables while other GDB can be used interactively. Be extremely careful in this case, because the two GDB can easily get out-of-sync. 20.6 RTOS Support ================= OpenOCD includes RTOS support, this will however need enabling as it defaults to disabled. It can be enabled by passing '-rtos' arg to the target. *Note RTOS Type: rtostype. *Note Debugging Programs with Multiple Threads: (gdb)Threads, for details about relevant GDB commands. An example setup is below: $_TARGETNAME configure -rtos auto This will attempt to auto detect the RTOS within your application. Currently supported rtos's include: * 'eCos' * 'ThreadX' * 'FreeRTOS' * 'linux' * 'ChibiOS' * 'embKernel' * 'mqx' * 'uCOS-III' * 'nuttx' * 'RIOT' * 'hwthread' (This is not an actual RTOS. *Note Using OpenOCD SMP with GDB: usingopenocdsmpwithgdb.) * 'Zephyr' Before an RTOS can be detected, it must export certain symbols; otherwise, it cannot be used by OpenOCD. Below is a list of the required symbols for each supported RTOS. 'eCos symbols' Cyg_Thread::thread_list, Cyg_Scheduler_Base::current_thread. 'ThreadX symbols' _tx_thread_current_ptr, _tx_thread_created_ptr, _tx_thread_created_count. 'FreeRTOS symbols' pxCurrentTCB, pxReadyTasksLists, xDelayedTaskList1, xDelayedTaskList2, pxDelayedTaskList, pxOverflowDelayedTaskList, xPendingReadyList, uxCurrentNumberOfTasks, uxTopUsedPriority. 'linux symbols' init_task. 'ChibiOS symbols' rlist, ch_debug, chSysInit. 'embKernel symbols' Rtos::sCurrentTask, Rtos::sListReady, Rtos::sListSleep, Rtos::sListSuspended, Rtos::sMaxPriorities, Rtos::sCurrentTaskCount. 'mqx symbols' _mqx_kernel_data, MQX_init_struct. 'uC/OS-III symbols' OSRunning, OSTCBCurPtr, OSTaskDbgListPtr, OSTaskQty. 'nuttx symbols' g_readytorun, g_tasklisttable. 'RIOT symbols' sched_threads, sched_num_threads, sched_active_pid, max_threads, _tcb_name_offset. 'Zephyr symbols' _kernel, _kernel_openocd_offsets, _kernel_openocd_size_t_size For most RTOS supported the above symbols will be exported by default. However for some, eg. FreeRTOS, uC/OS-III and Zephyr, extra steps must be taken. Zephyr must be compiled with the DEBUG_THREAD_INFO option. This will generate some symbols with information needed in order to build the list of threads. FreeRTOS and uC/OS-III RTOSes may require additional OpenOCD-specific file to be linked along with the project: 'FreeRTOS' contrib/rtos-helpers/FreeRTOS-openocd.c 'uC/OS-III' contrib/rtos-helpers/uCOS-III-openocd.c 20.7 Using OpenOCD SMP with GDB =============================== OpenOCD includes a pseudo RTOS called _hwthread_ that presents CPU cores ("hardware threads") in an SMP system as threads to GDB. With this extension, GDB can be used to inspect the state of an SMP system in a natural way. After halting the system, using the GDB command 'info threads' will list the context of each active CPU core in the system. GDB's 'thread' command can be used to switch the view to a different CPU core. The 'step' and 'stepi' commands can be used to step a specific core while other cores are free-running or remain halted, depending on the scheduler-locking mode configured in GDB.  File: openocd.info, Node: Tcl Scripting API, Next: FAQ, Prev: GDB and OpenOCD, Up: Top 21 Tcl Scripting API ******************** 21.1 API rules ============== Tcl commands are stateless; e.g. the 'telnet' command has a concept of currently active target, the Tcl API proc's take this sort of state information as an argument to each proc. There are three main types of return values: single value, name value pair list and lists. Name value pair. The proc 'foo' below returns a name/value pair list. > set foo(me) Duane > set foo(you) Oyvind > set foo(mouse) Micky > set foo(duck) Donald If one does this: > set foo The result is: me Duane you Oyvind mouse Micky duck Donald Thus, to get the names of the associative array is easy: foreach { name value } [set foo] { puts "Name: $name, Value: $value" } Lists returned should be relatively small. Otherwise, a range should be passed in to the proc in question. 21.2 Internal low-level Commands ================================ By "low-level", we mean commands that a human would typically not invoke directly. * flash banks ['driver options' ...] Return information about the flash banks * capture Run and return full log output that was produced during its execution. Example: > capture "reset init" OpenOCD commands can consist of two words, e.g. "flash banks". The 'startup.tcl' "unknown" proc will translate this into a Tcl proc called "flash_banks". 21.3 Tcl RPC server =================== OpenOCD provides a simple RPC server that allows to run arbitrary Tcl commands and receive the results. To access it, your application needs to connect to a configured TCP port (see 'tcl_port'). Then it can pass any string to the interpreter terminating it with '0x1a' and wait for the return value (it will be terminated with '0x1a' as well). This can be repeated as many times as desired without reopening the connection. It is not needed anymore to prefix the OpenOCD commands with 'ocd_' to get the results back. But sometimes you might need the 'capture' command. See 'contrib/rpc_examples/' for specific client implementations. 21.4 Tcl RPC server notifications ================================= Notifications are sent asynchronously to other commands being executed over the RPC server, so the port must be polled continuously. Target event, state and reset notifications are emitted as Tcl associative arrays in the following format. type target_event event [event-name] type target_state state [state-name] type target_reset mode [reset-mode] -- Command: tcl_notifications [on/off] Toggle output of target notifications to the current Tcl RPC server. Only available from the Tcl RPC server. Defaults to off. 21.5 Tcl RPC server trace output ================================ Trace data is sent asynchronously to other commands being executed over the RPC server, so the port must be polled continuously. Target trace data is emitted as a Tcl associative array in the following format. type target_trace data [trace-data-hex-encoded] -- Command: tcl_trace [on/off] Toggle output of target trace data to the current Tcl RPC server. Only available from the Tcl RPC server. Defaults to off. See an example application here: [OpenOcdTraceUtil]  File: openocd.info, Node: FAQ, Next: Tcl Crash Course, Prev: Tcl Scripting API, Up: Top 22 FAQ ****** 1. RTCK, also known as: Adaptive Clocking - What is it? In digital circuit design it is often referred to as "clock synchronisation" the JTAG interface uses one clock (TCK or TCLK) operating at some speed, your CPU target is operating at another. The two clocks are not synchronised, they are "asynchronous" In order for the two to work together they must be synchronised well enough to work; JTAG can't go ten times faster than the CPU, for example. There are 2 basic options: 1. Use a special "adaptive clocking" circuit to change the JTAG clock rate to match what the CPU currently supports. 2. The JTAG clock must be fixed at some speed that's enough slower than the CPU clock that all TMS and TDI transitions can be detected. Does this really matter? For some chips and some situations, this is a non-issue, like a 500MHz ARM926 with a 5 MHz JTAG link; the CPU has no difficulty keeping up with JTAG. Startup sequences are often problematic though, as are other situations where the CPU clock rate changes (perhaps to save power). For example, Atmel AT91SAM chips start operation from reset with a 32kHz system clock. Boot firmware may activate the main oscillator and PLL before switching to a faster clock (perhaps that 500 MHz ARM926 scenario). If you're using JTAG to debug that startup sequence, you must slow the JTAG clock to sometimes 1 to 4kHz. After startup completes, JTAG can use a faster clock. Consider also debugging a 500MHz ARM926 hand held battery powered device that enters a low power "deep sleep" mode, at 32kHz CPU clock, between keystrokes unless it has work to do. When would that 5 MHz JTAG clock be usable? Solution #1 - A special circuit In order to make use of this, your CPU, board, and JTAG adapter must all support the RTCK feature. Not all of them support this; keep reading! The RTCK ("Return TCK") signal in some ARM chips is used to help with this problem. ARM has a good description of the problem described at this link: [checked 28/nov/2008]. Link title: "How does the JTAG synchronisation logic work? / how does adaptive clocking work?". The nice thing about adaptive clocking is that "battery powered hand held device example" - the adaptiveness works perfectly all the time. One can set a break point or halt the system in the deep power down code, slow step out until the system speeds up. Note that adaptive clocking may also need to work at the board level, when a board-level scan chain has multiple chips. Parallel clock voting schemes are good way to implement this, both within and between chips, and can easily be implemented with a CPLD. It's not difficult to have logic fan a module's input TCK signal out to each TAP in the scan chain, and then wait until each TAP's RTCK comes back with the right polarity before changing the output RTCK signal. Texas Instruments makes some clock voting logic available for free (with no support) in VHDL form; see Solution #2 - Always works - but may be slower Often this is a perfectly acceptable solution. In most simple terms: Often the JTAG clock must be 1/10 to 1/12 of the target clock speed. But what that "magic division" is varies depending on the chips on your board. ARM rule of thumb Most ARM based systems require an 6:1 division; ARM11 cores use an 8:1 division. Xilinx rule of thumb is 1/12 the clock speed. Note: most full speed FT2232 based JTAG adapters are limited to a maximum of 6MHz. The ones using USB high speed chips (FT2232H) often support faster clock rates (and adaptive clocking). You can still debug the 'low power' situations - you just need to either use a fixed and very slow JTAG clock rate ... or else manually adjust the clock speed at every step. (Adjusting is painful and tedious, and is not always practical.) It is however easy to "code your way around it" - i.e.: Cheat a little, have a special debug mode in your application that does a "high power sleep". If you are careful - 98% of your problems can be debugged this way. Note that on ARM you may need to avoid using the _wait for interrupt_ operation in your idle loops even if you don't otherwise change the CPU clock rate. That operation gates the CPU clock, and thus the JTAG clock; which prevents JTAG access. One consequence is not being able to 'halt' cores which are executing that _wait for interrupt_ operation. To set the JTAG frequency use the command: # Example: 1.234MHz adapter speed 1234 2. Win32 Pathnames Why don't backslashes work in Windows paths? OpenOCD uses Tcl and a backslash is an escape char. Use { and } around Windows filenames. > echo \a > echo {\a} \a > echo "\a" > 3. Missing: cygwin1.dll OpenOCD complains about a missing cygwin1.dll. Make sure you have Cygwin installed, or at least a version of OpenOCD that claims to come with all the necessary DLLs. When using Cygwin, try launching OpenOCD from the Cygwin shell. 4. Breakpoint Issue I'm trying to set a breakpoint using GDB (or a front-end like Insight or Eclipse), but OpenOCD complains that "Info: arm7_9_common.c:213 arm7_9_add_breakpoint(): sw breakpoint requested, but software breakpoints not enabled". GDB issues software breakpoints when a normal breakpoint is requested, or to implement source-line single-stepping. On ARMv4T systems, like ARM7TDMI, ARM720T or ARM920T, software breakpoints consume one of the two available hardware breakpoints. 5. LPC2000 Flash When erasing or writing LPC2000 on-chip flash, the operation fails at random. Make sure the core frequency specified in the 'flash lpc2000' line matches the clock at the time you're programming the flash. If you've specified the crystal's frequency, make sure the PLL is disabled. If you've specified the full core speed (e.g. 60MHz), make sure the PLL is enabled. 6. Amontec Chameleon When debugging using an Amontec Chameleon in its JTAG Accelerator configuration, I keep getting "Error: amt_jtagaccel.c:184 amt_wait_scan_busy(): amt_jtagaccel timed out while waiting for end of scan, rtck was disabled". Make sure your PC's parallel port operates in EPP mode. You might have to try several settings in your PC BIOS (ECP, EPP, and different versions of those). 7. Data Aborts When debugging with OpenOCD and GDB (plain GDB, Insight, or Eclipse), I get lots of "Error: arm7_9_common.c:1771 arm7_9_read_memory(): memory read caused data abort". The errors are non-fatal, and are the result of GDB trying to trace stack frames beyond the last valid frame. It might be possible to prevent this by setting up a proper "initial" stack frame, if you happen to know what exactly has to be done, feel free to add this here. Simple: In your startup code - push 8 registers of zeros onto the stack before calling main(). What GDB is doing is "climbing" the run time stack by reading various values on the stack using the standard call frame for the target. GDB keeps going - until one of 2 things happen #1 an invalid frame is found, or #2 some huge number of stackframes have been processed. By pushing zeros on the stack, GDB gracefully stops. Debugging Interrupt Service Routines - In your ISR before you call your C code, do the same - artificially push some zeros onto the stack, remember to pop them off when the ISR is done. Also note: If you have a multi-threaded operating system, they often do not in the interest of saving memory waste these few bytes. Painful... 8. JTAG Reset Config I get the following message in the OpenOCD console (or log file): "Warning: arm7_9_common.c:679 arm7_9_assert_reset(): srst resets test logic, too". This warning doesn't indicate any serious problem, as long as you don't want to debug your core right out of reset. Your .cfg file specified 'reset_config trst_and_srst srst_pulls_trst' to tell OpenOCD that either your board, your debugger or your target uC (e.g. LPC2000) can't assert the two reset signals independently. With this setup, it's not possible to halt the core right out of reset, everything else should work fine. 9. USB Power When using OpenOCD in conjunction with Amontec JTAGkey and the Yagarto toolchain (Eclipse, arm-elf-gcc, arm-elf-gdb), the debugging seems to be unstable. When single-stepping over large blocks of code, GDB and OpenOCD quit with an error message. Is there a stability issue with OpenOCD? No, this is not a stability issue concerning OpenOCD. Most users have solved this issue by simply using a self-powered USB hub, which they connect their Amontec JTAGkey to. Apparently, some computers do not provide a USB power supply stable enough for the Amontec JTAGkey to be operated. Laptops running on battery have this problem too... 10. GDB Disconnects When using the Amontec JTAGkey, sometimes OpenOCD crashes with the following error message: "Error: gdb_server.c:101 gdb_get_char(): read: 10054". What does that mean and what might be the reason for this? Error code 10054 corresponds to WSAECONNRESET, which means that the debugger (GDB) has closed the connection to OpenOCD. This might be a GDB issue. 11. LPC2000 Flash In the configuration file in the section where flash device configurations are described, there is a parameter for specifying the clock frequency for LPC2000 internal flash devices (e.g. 'flash bank $_FLASHNAME lpc2000 0x0 0x40000 0 0 $_TARGETNAME lpc2000_v1 14746 calc_checksum'), which must be specified in kilohertz. However, I do have a quartz crystal of a frequency that contains fractions of kilohertz (e.g. 14,745,600 Hz, i.e. 14,745.600 kHz). Is it possible to specify real numbers for the clock frequency? No. The clock frequency specified here must be given as an integral number. However, this clock frequency is used by the In-Application-Programming (IAP) routines of the LPC2000 family only, which seems to be very tolerant concerning the given clock frequency, so a slight difference between the specified clock frequency and the actual clock frequency will not cause any trouble. 12. Command Order Do I have to keep a specific order for the commands in the configuration file? Well, yes and no. Commands can be given in arbitrary order, yet the devices listed for the JTAG scan chain must be given in the right order (jtag newdevice), with the device closest to the TDO-Pin being listed first. In general, whenever objects of the same type exist which require an index number, then these objects must be given in the right order (jtag newtap, targets and flash banks - a target references a jtag newtap and a flash bank references a target). You can use the "scan_chain" command to verify and display the tap order. Also, some commands can't execute until after 'init' has been processed. Such commands include 'nand probe' and everything else that needs to write to controller registers, perhaps for setting up DRAM and loading it with code. 13. JTAG TAP Order Do I have to declare the TAPS in some particular order? Yes; whenever you have more than one, you must declare them in the same order used by the hardware. Many newer devices have multiple JTAG TAPs. For example: STMicroelectronics STM32 chips have two TAPs, a "boundary scan TAP" and "Cortex-M3" TAP. Example: The STM32 reference manual, Document ID: RM0008, Section 26.5, Figure 259, page 651/681, the "TDI" pin is connected to the boundary scan TAP, which then connects to the Cortex-M3 TAP, which then connects to the TDO pin. Thus, the proper order for the STM32 chip is: (1) The Cortex-M3, then (2) The boundary scan TAP. If your board includes an additional JTAG chip in the scan chain (for example a Xilinx CPLD or FPGA) you could place it before or after the STM32 chip in the chain. For example: * OpenOCD_TDI(output) -> STM32 TDI Pin (BS Input) * STM32 BS TDO (output) -> STM32 Cortex-M3 TDI (input) * STM32 Cortex-M3 TDO (output) -> SM32 TDO Pin * STM32 TDO Pin (output) -> Xilinx TDI Pin (input) * Xilinx TDO Pin -> OpenOCD TDO (input) The "jtag device" commands would thus be in the order shown below. Note: * jtag newtap Xilinx tap -irlen ... * jtag newtap stm32 cpu -irlen ... * jtag newtap stm32 bs -irlen ... * # Create the debug target and say where it is * target create stm32.cpu -chain-position stm32.cpu ... 14. SYSCOMP Sometimes my debugging session terminates with an error. When I look into the log file, I can see these error messages: Error: arm7_9_common.c:561 arm7_9_execute_sys_speed(): timeout waiting for SYSCOMP TODO.  File: openocd.info, Node: Tcl Crash Course, Next: License, Prev: FAQ, Up: Top 23 Tcl Crash Course ******************* Not everyone knows Tcl - this is not intended to be a replacement for learning Tcl, the intent of this chapter is to give you some idea of how the Tcl scripts work. This chapter is written with two audiences in mind. (1) OpenOCD users who need to understand a bit more of how Jim-Tcl works so they can do something useful, and (2) those that want to add a new command to OpenOCD. 23.1 Tcl Rule #1 ================ There is a famous joke, it goes like this: 1. Rule #1: The wife is always correct 2. Rule #2: If you think otherwise, See Rule #1 The Tcl equal is this: 1. Rule #1: Everything is a string 2. Rule #2: If you think otherwise, See Rule #1 As in the famous joke, the consequences of Rule #1 are profound. Once you understand Rule #1, you will understand Tcl. 23.2 Tcl Rule #1b ================= There is a second pair of rules. 1. Rule #1: Control flow does not exist. Only commands For example: the classic FOR loop or IF statement is not a control flow item, they are commands, there is no such thing as control flow in Tcl. 2. Rule #2: If you think otherwise, See Rule #1 Actually what happens is this: There are commands that by convention, act like control flow key words in other languages. One of those commands is the word "for", another command is "if". 23.3 Per Rule #1 - All Results are strings ========================================== Every Tcl command results in a string. The word "result" is used deliberately. No result is just an empty string. Remember: Rule #1 - Everything is a string 23.4 Tcl Quoting Operators ========================== In life of a Tcl script, there are two important periods of time, the difference is subtle. 1. Parse Time 2. Evaluation Time The two key items here are how "quoted things" work in Tcl. Tcl has three primary quoting constructs, the [square-brackets] the {curly-braces} and "double-quotes" By now you should know $VARIABLES always start with a $DOLLAR sign. BTW: To set a variable, you actually use the command "set", as in "set VARNAME VALUE" much like the ancient BASIC language "let x = 1" statement, but without the equal sign. * [square-brackets] [square-brackets] are command substitutions. It operates much like Unix Shell 'back-ticks'. The result of a [square-bracket] operation is exactly 1 string. Remember Rule #1 - Everything is a string. These two statements are roughly identical: # bash example X=`date` echo "The Date is: $X" # Tcl example set X [date] puts "The Date is: $X" * "double-quoted-things" "double-quoted-things" are just simply quoted text. $VARIABLES and [square-brackets] are expanded in place - the result however is exactly 1 string. Remember Rule #1 - Everything is a string set x "Dinner" puts "It is now \"[date]\", $x is in 1 hour" * {Curly-Braces} {Curly-Braces} are magic: $VARIABLES and [square-brackets] are parsed, but are NOT expanded or executed. {Curly-Braces} are like 'single-quote' operators in BASH shell scripts, with the added feature: {curly-braces} can be nested, single quotes can not. {{{this is nested 3 times}}} NOTE: [date] is a bad example; at this writing, Jim/OpenOCD does not have a date command. 23.5 Consequences of Rule 1/2/3/4 ================================= The consequences of Rule 1 are profound. 23.5.1 Tokenisation & Execution. -------------------------------- Of course, whitespace, blank lines and #comment lines are handled in the normal way. As a script is parsed, each (multi) line in the script file is tokenised and according to the quoting rules. After tokenisation, that line is immediately executed. Multi line statements end with one or more "still-open" {curly-braces} which - eventually - closes a few lines later. 23.5.2 Command Execution ------------------------ Remember earlier: There are no "control flow" statements in Tcl. Instead there are COMMANDS that simply act like control flow operators. Commands are executed like this: 1. Parse the next line into (argc) and (argv[]). 2. Look up (argv[0]) in a table and call its function. 3. Repeat until End Of File. It sort of works like this: for(;;){ ReadAndParse( &argc, &argv ); cmdPtr = LookupCommand( argv[0] ); (*cmdPtr->Execute)( argc, argv ); } When the command "proc" is parsed (which creates a procedure function) it gets 3 parameters on the command line. 1 the name of the proc (function), 2 the list of parameters, and 3 the body of the function. Note the choice of words: LIST and BODY. The PROC command stores these items in a table somewhere so it can be found by "LookupCommand()" 23.5.3 The FOR command ---------------------- The most interesting command to look at is the FOR command. In Tcl, the FOR command is normally implemented in C. Remember, FOR is a command just like any other command. When the ascii text containing the FOR command is parsed, the parser produces 5 parameter strings, (If in doubt: Refer to Rule #1) they are: 0. The ascii text 'for' 1. The start text 2. The test expression 3. The next text 4. The body text Sort of reminds you of "main( int argc, char **argv )" does it not? Remember Rule #1 - Everything is a string. The key point is this: Often many of those parameters are in {curly-braces} - thus the variables inside are not expanded or replaced until later. Remember that every Tcl command looks like the classic "main( argc, argv )" function in C. In JimTCL - they actually look like this: int MyCommand( Jim_Interp *interp, int *argc, Jim_Obj * const *argvs ); Real Tcl is nearly identical. Although the newer versions have introduced a byte-code parser and interpreter, but at the core, it still operates in the same basic way. 23.5.4 FOR command implementation --------------------------------- To understand Tcl it is perhaps most helpful to see the FOR command. Remember, it is a COMMAND not a control flow structure. In Tcl there are two underlying C helper functions. Remember Rule #1 - You are a string. The first helper parses and executes commands found in an ascii string. Commands can be separated by semicolons, or newlines. While parsing, variables are expanded via the quoting rules. The second helper evaluates an ascii string as a numerical expression and returns a value. Here is an example of how the FOR command could be implemented. The pseudo code below does not show error handling. void Execute_AsciiString( void *interp, const char *string ); int Evaluate_AsciiExpression( void *interp, const char *string ); int MyForCommand( void *interp, int argc, char **argv ) { if( argc != 5 ){ SetResult( interp, "WRONG number of parameters"); return ERROR; } // argv[0] = the ascii string just like C // Execute the start statement. Execute_AsciiString( interp, argv[1] ); // Top of loop test for(;;){ i = Evaluate_AsciiExpression(interp, argv[2]); if( i == 0 ) break; // Execute the body Execute_AsciiString( interp, argv[3] ); // Execute the LOOP part Execute_AsciiString( interp, argv[4] ); } // Return no error SetResult( interp, "" ); return SUCCESS; } Every other command IF, WHILE, FORMAT, PUTS, EXPR, everything works in the same basic way. 23.6 OpenOCD Tcl Usage ====================== 23.6.1 source and find commands ------------------------------- Where: In many configuration files Example: source [find FILENAME] Remember the parsing rules 1. The 'find' command is in square brackets, and is executed with the parameter FILENAME. It should find and return the full path to a file with that name; it uses an internal search path. The RESULT is a string, which is substituted into the command line in place of the bracketed 'find' command. (Don't try to use a FILENAME which includes the "#" character. That character begins Tcl comments.) 2. The 'source' command is executed with the resulting filename; it reads a file and executes as a script. 23.6.2 format command --------------------- Where: Generally occurs in numerous places. Tcl has no command like printf(), instead it has format, which is really more like sprintf(). Example set x 6 set y 7 puts [format "The answer: %d" [expr {$x * $y}]] 1. The SET command creates 2 variables, X and Y. 2. The double [nested] EXPR command performs math The EXPR command produces numerical result as a string. Refer to Rule #1 3. The format command is executed, producing a single string Refer to Rule #1. 4. The PUTS command outputs the text. 23.6.3 Body or Inlined Text --------------------------- Where: Various TARGET scripts. #1 Good proc someproc {} { ... multiple lines of stuff ... } $_TARGETNAME configure -event FOO someproc #2 Good - no variables $_TARGETNAME configure -event foo "this ; that;" #3 Good Curly Braces $_TARGETNAME configure -event FOO { puts "Time: [date]" } #4 DANGER DANGER DANGER $_TARGETNAME configure -event foo "puts \"Time: [date]\"" 1. The $_TARGETNAME is an OpenOCD variable convention. $_TARGETNAME represents the last target created, the value changes each time a new target is created. Remember the parsing rules. When the ascii text is parsed, the $_TARGETNAME becomes a simple string, the name of the target which happens to be a TARGET (object) command. 2. The 2nd parameter to the '-event' parameter is a TCBODY There are 4 examples: 1. The TCLBODY is a simple string that happens to be a proc name 2. The TCLBODY is several simple commands separated by semicolons 3. The TCLBODY is a multi-line {curly-brace} quoted string 4. The TCLBODY is a string with variables that get expanded. In the end, when the target event FOO occurs the TCLBODY is evaluated. Method #1 and #2 are functionally identical. For Method #3 and #4 it is more interesting. What is the TCLBODY? Remember the parsing rules. In case #3, {curly-braces} mean the $VARS and [square-brackets] are expanded later, when the EVENT occurs, and the text is evaluated. In case #4, they are replaced before the "Target Object Command" is executed. This occurs at the same time $_TARGETNAME is replaced. In case #4 the date will never change. {BTW: [date] is a bad example; at this writing, Jim/OpenOCD does not have a date command} 23.6.4 Global Variables ----------------------- Where: You might discover this when writing your own procs In simple terms: Inside a PROC, if you need to access a global variable you must say so. See also "upvar". Example: proc myproc { } { set y 0 #Local variable Y global x #Global variable X puts [format "X=%d, Y=%d" $x $y] } 23.7 Other Tcl Hacks ==================== Dynamic variable creation # Dynamically create a bunch of variables. for { set x 0 } { $x < 32 } { set x [expr {$x + 1}]} { # Create var name set vn [format "BIT%d" $x] # Make it a global global $vn # Set it. set $vn [expr {1 << $x}] } Dynamic proc/command creation # One "X" function - 5 uart functions. foreach who {A B C D E} proc [format "show_uart%c" $who] { } "show_UARTx $who" }  File: openocd.info, Node: License, Next: OpenOCD Concept Index, Prev: Tcl Crash Course, Up: Top Appendix A The GNU Free Documentation License. ********************************************** Version 1.2, November 2002 Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. C. State on the Title page the name of the publisher of the Modified Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section. O. Preserve any Warranty Disclaimers. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements." 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See . Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. ADDENDUM: How to use this License for your documents ==================================================== To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright (C) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the "with...Texts." line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.  File: openocd.info, Node: OpenOCD Concept Index, Next: Command and Driver Index, Prev: License, Up: Top OpenOCD Concept Index ********************* [index] * Menu: * aarch64: Architecture and Core Commands. (line 959) * about: About. (line 6) * adaptive clocking: Debug Adapter Configuration. (line 1304) * adaptive clocking <1>: FAQ. (line 6) * ambiqmicro: Flash Commands. (line 632) * apollo: Flash Commands. (line 632) * ARC: Architecture and Core Commands. (line 1459) * Architecture Specific Commands: Architecture and Core Commands. (line 6) * ARM: Architecture and Core Commands. (line 271) * ARM semihosting: OpenOCD Project Setup. (line 314) * ARM semihosting <1>: Architecture and Core Commands. (line 312) * ARM semihosting <2>: Architecture and Core Commands. (line 323) * ARM semihosting <3>: Architecture and Core Commands. (line 333) * ARM semihosting <4>: Architecture and Core Commands. (line 344) * ARM semihosting <5>: Architecture and Core Commands. (line 353) * ARM semihosting <6>: Architecture and Core Commands. (line 374) * ARM semihosting <7>: Architecture and Core Commands. (line 383) * ARM11: Architecture and Core Commands. (line 650) * ARM7: Architecture and Core Commands. (line 397) * ARM9: Architecture and Core Commands. (line 397) * ARM9 <1>: Architecture and Core Commands. (line 435) * ARM920T: Architecture and Core Commands. (line 455) * ARM926ej-s: Architecture and Core Commands. (line 480) * ARM966E: Architecture and Core Commands. (line 494) * ARMv4: Architecture and Core Commands. (line 390) * ARMv5: Architecture and Core Commands. (line 390) * ARMv6: Architecture and Core Commands. (line 646) * ARMv7: Architecture and Core Commands. (line 684) * ARMv8: Architecture and Core Commands. (line 683) * ARMv8-A: Architecture and Core Commands. (line 959) * at91sam3: Flash Commands. (line 748) * at91sam4: Flash Commands. (line 803) * at91sam4l: Flash Commands. (line 808) * at91samd: Flash Commands. (line 670) * ath79: Flash Commands. (line 581) * Atheros ath79 SPI driver: Flash Commands. (line 581) * atsame5: Flash Commands. (line 819) * atsamv: Flash Commands. (line 872) * autoprobe: TAP Declaration. (line 323) * board config file: Config File Guidelines. (line 68) * breakpoint: General Commands. (line 383) * bscan_spi: Flash Commands. (line 329) * CFI: Flash Commands. (line 294) * command line options: Running. (line 6) * commands: General Commands. (line 6) * Common Flash Interface: Flash Commands. (line 294) * config command: Server Configuration. (line 13) * config file, board: Config File Guidelines. (line 68) * config file, interface: Debug Adapter Configuration. (line 6) * config file, overview: OpenOCD Project Setup. (line 139) * config file, target: Config File Guidelines. (line 298) * config file, user: OpenOCD Project Setup. (line 139) * configuration stage: Server Configuration. (line 13) * Connecting to GDB: GDB and OpenOCD. (line 27) * Core Specific Commands: Architecture and Core Commands. (line 6) * Cortex-A: Architecture and Core Commands. (line 687) * Cortex-M: Architecture and Core Commands. (line 900) * Cortex-R: Architecture and Core Commands. (line 722) * CPU type: CPU Configuration. (line 60) * CTI: Architecture and Core Commands. (line 225) * DAP declaration: TAP Declaration. (line 379) * DCC: Architecture and Core Commands. (line 413) * DCC <1>: Architecture and Core Commands. (line 1686) * developers: Developers. (line 6) * directory search: Running. (line 6) * disassemble: Architecture and Core Commands. (line 282) * disassemble <1>: Architecture and Core Commands. (line 972) * dongles: Debug Adapter Hardware. (line 6) * dotted name: TAP Declaration. (line 98) * ETB: Architecture and Core Commands. (line 14) * ETM: Architecture and Core Commands. (line 14) * ETM <1>: Architecture and Core Commands. (line 890) * event, reset-init: Config File Guidelines. (line 184) * events: Reset Configuration. (line 226) * events <1>: TAP Declaration. (line 222) * events <2>: CPU Configuration. (line 462) * faq: FAQ. (line 6) * fespi: Flash Commands. (line 614) * Firmware recovery: Utility Commands. (line 45) * flash configuration: Flash Commands. (line 36) * flash erasing: Flash Commands. (line 102) * flash programming: Flash Commands. (line 102) * flash protection: Flash Commands. (line 230) * flash reading: Flash Commands. (line 102) * flash writing: Flash Commands. (line 102) * FPGA: PLD/FPGA Commands. (line 6) * Freedom E SPI: Flash Commands. (line 614) * FTDI: Debug Adapter Hardware. (line 6) * GDB: Server Configuration. (line 173) * GDB <1>: GDB and OpenOCD. (line 6) * GDB configuration: Server Configuration. (line 173) * GDB server: Server Configuration. (line 126) * GDB target: CPU Configuration. (line 6) * Generic JTAG2SPI driver: Flash Commands. (line 329) * halt: General Commands. (line 103) * hwthread: GDB and OpenOCD. (line 292) * image dumping: General Commands. (line 329) * image loading: General Commands. (line 329) * initialization: Server Configuration. (line 6) * init_board procedure: Config File Guidelines. (line 249) * init_targets procedure: Config File Guidelines. (line 522) * init_target_events procedure: Config File Guidelines. (line 567) * interface config file: Debug Adapter Configuration. (line 6) * IPDBG: Boundary Scan Commands. (line 73) * IPDBG JTAG-Host server: Boundary Scan Commands. (line 73) * ITM: Architecture and Core Commands. (line 890) * Jim-Tcl: About Jim-Tcl. (line 6) * jrc: TAP Declaration. (line 260) * JTAG: About. (line 15) * JTAG <1>: Debug Adapter Configuration. (line 1184) * JTAG autoprobe: TAP Declaration. (line 323) * JTAG Commands: JTAG Commands. (line 6) * JTAG Route Controller: TAP Declaration. (line 260) * jtagspi: Flash Commands. (line 329) * kinetis: Flash Commands. (line 1040) * kinetis_ke: Flash Commands. (line 1127) * libdcc: Architecture and Core Commands. (line 1686) * Linux-ARM DCC support: Architecture and Core Commands. (line 1686) * logfile: Running. (line 6) * lpcspifi: Flash Commands. (line 423) * memory access: General Commands. (line 291) * message level: General Commands. (line 73) * NAND: Flash Commands. (line 2132) * NAND configuration: Flash Commands. (line 2187) * NAND erasing: Flash Commands. (line 2267) * NAND other commands: Flash Commands. (line 2358) * NAND programming: Flash Commands. (line 2267) * NAND programming <1>: Flash Commands. (line 2280) * NAND programming <2>: Flash Commands. (line 2333) * NAND reading: Flash Commands. (line 2234) * NAND verification: Flash Commands. (line 2333) * NAND writing: Flash Commands. (line 2280) * NXP SPI Flash Interface: Flash Commands. (line 423) * object command: CPU Configuration. (line 307) * OctoSPI: Flash Commands. (line 460) * PLD: PLD/FPGA Commands. (line 6) * port: Server Configuration. (line 116) * printer port: Debug Adapter Hardware. (line 6) * profiling: General Commands. (line 488) * Programming using GDB: GDB and OpenOCD. (line 127) * QuadSPI: Flash Commands. (line 460) * RAM testing: Utility Commands. (line 9) * reset: General Commands. (line 103) * Reset Configuration: Reset Configuration. (line 6) * reset-init handler: Config File Guidelines. (line 184) * RPC: Tcl Scripting API. (line 65) * RPC Notifications: Tcl Scripting API. (line 83) * RPC trace output: Tcl Scripting API. (line 100) * RTCK: Debug Adapter Hardware. (line 6) * RTCK <1>: Debug Adapter Configuration. (line 1304) * RTCK <2>: FAQ. (line 6) * RTOS: GDB and OpenOCD. (line 292) * RTOS Support: GDB and OpenOCD. (line 211) * scan chain: TAP Declaration. (line 28) * security: Server Configuration. (line 116) * Serial Peripheral Interface: Debug Adapter Configuration. (line 1228) * Serial Vector Format: Boundary Scan Commands. (line 13) * Serial Wire Debug: Debug Adapter Configuration. (line 1199) * server: Server Configuration. (line 116) * Single Wire Interface Module: Debug Adapter Configuration. (line 1235) * SMI: Flash Commands. (line 440) * SMP: Config File Guidelines. (line 425) * SMP <1>: GDB and OpenOCD. (line 292) * SPI: Debug Adapter Configuration. (line 1228) * SPI <1>: Flash Commands. (line 329) * SPIFI: Flash Commands. (line 423) * STMicroelectronics QuadSPI/OctoSPI Interface: Flash Commands. (line 460) * STMicroelectronics Serial Memory Interface: Flash Commands. (line 440) * stmqspi: Flash Commands. (line 460) * stmsmi: Flash Commands. (line 440) * str9xpec: Flash Commands. (line 1997) * SVF: Boundary Scan Commands. (line 13) * SWD: Debug Adapter Configuration. (line 1199) * SWD multi-drop: Debug Adapter Configuration. (line 1215) * SWIM: Debug Adapter Configuration. (line 1235) * swm050: Flash Commands. (line 2075) * SWO: Architecture and Core Commands. (line 732) * SWO <1>: Architecture and Core Commands. (line 890) * SWV: Architecture and Core Commands. (line 732) * SWV <1>: Architecture and Core Commands. (line 890) * TAP: About. (line 15) * TAP configuration: TAP Declaration. (line 6) * TAP declaration: TAP Declaration. (line 6) * TAP events: TAP Declaration. (line 222) * TAP naming convention: TAP Declaration. (line 121) * TAP state names: JTAG Commands. (line 125) * target config file: Config File Guidelines. (line 298) * target events: CPU Configuration. (line 462) * target initialization: General Commands. (line 103) * target type: CPU Configuration. (line 60) * target, current: CPU Configuration. (line 18) * target, list: CPU Configuration. (line 18) * tcl: About Jim-Tcl. (line 6) * Tcl: Tcl Crash Course. (line 6) * Tcl Scripting API: Tcl Scripting API. (line 6) * Tcl scripts: Tcl Scripting API. (line 5) * TCP port: Server Configuration. (line 116) * TPIU: Architecture and Core Commands. (line 732) * tracing: Architecture and Core Commands. (line 14) * tracing <1>: Architecture and Core Commands. (line 732) * tracing <2>: Architecture and Core Commands. (line 890) * tracing <3>: Architecture and Core Commands. (line 1686) * translation: Config File Guidelines. (line 612) * Transport: Debug Adapter Configuration. (line 1158) * USB Adapter: Debug Adapter Hardware. (line 6) * user config file: OpenOCD Project Setup. (line 139) * Using GDB as a non-intrusive memory inspector: GDB and OpenOCD. (line 167) * Utility Commands: Utility Commands. (line 5) * variable names: Config File Guidelines. (line 152) * vector_catch: OpenOCD Project Setup. (line 213) * vector_catch <1>: Architecture and Core Commands. (line 440) * vector_catch <2>: Architecture and Core Commands. (line 619) * vector_catch <3>: Architecture and Core Commands. (line 672) * vector_catch <4>: Architecture and Core Commands. (line 925) * vector_table: Architecture and Core Commands. (line 634) * watchpoint: General Commands. (line 383) * wiggler: Debug Adapter Hardware. (line 6) * xcf: Flash Commands. (line 387) * Xilinx Platform flash driver: Flash Commands. (line 387) * Xilinx Serial Vector Format: Boundary Scan Commands. (line 39) * XScale: Architecture and Core Commands. (line 508) * XSVF: Boundary Scan Commands. (line 39)  File: openocd.info, Node: Command and Driver Index, Prev: OpenOCD Concept Index, Up: Top Command and Driver Index ************************ [index] * Menu: * $cti_name ack: Architecture and Core Commands. (line 253) * $cti_name channel: Architecture and Core Commands. (line 256) * $cti_name dump: Architecture and Core Commands. (line 243) * $cti_name enable: Architecture and Core Commands. (line 240) * $cti_name read: Architecture and Core Commands. (line 249) * $cti_name testmode: Architecture and Core Commands. (line 260) * $cti_name write: Architecture and Core Commands. (line 246) * $dap_name apcsw: TAP Declaration. (line 469) * $dap_name apid: TAP Declaration. (line 436) * $dap_name apreg: TAP Declaration. (line 440) * $dap_name apsel: TAP Declaration. (line 445) * $dap_name baseaddr: TAP Declaration. (line 460) * $dap_name dpreg: TAP Declaration. (line 448) * $dap_name info: TAP Declaration. (line 432) * $dap_name memaccess: TAP Declaration. (line 464) * $dap_name ti_be_32_quirks: TAP Declaration. (line 504) * $target_name arp_examine: CPU Configuration. (line 332) * $target_name arp_halt: CPU Configuration. (line 333) * $target_name arp_poll: CPU Configuration. (line 334) * $target_name arp_reset: CPU Configuration. (line 335) * $target_name arp_waitstate: CPU Configuration. (line 336) * $target_name catch_exc: Architecture and Core Commands. (line 988) * $target_name cget: CPU Configuration. (line 397) * $target_name configure: CPU Configuration. (line 221) * $target_name curstate: CPU Configuration. (line 420) * $target_name eventlist: CPU Configuration. (line 425) * $target_name get_reg: CPU Configuration. (line 353) * $target_name invoke-event: CPU Configuration. (line 429) * $target_name mdb: CPU Configuration. (line 437) * $target_name mdd: CPU Configuration. (line 434) * $target_name mdh: CPU Configuration. (line 436) * $target_name mdw: CPU Configuration. (line 435) * $target_name mwb: CPU Configuration. (line 450) * $target_name mwd: CPU Configuration. (line 447) * $target_name mwh: CPU Configuration. (line 449) * $target_name mww: CPU Configuration. (line 448) * $target_name read_memory: CPU Configuration. (line 381) * $target_name set_reg: CPU Configuration. (line 341) * $target_name write_memory: CPU Configuration. (line 366) * $tpiu_name cget: Architecture and Core Commands. (line 778) * $tpiu_name configure: Architecture and Core Commands. (line 784) * $tpiu_name disable: Architecture and Core Commands. (line 856) * $tpiu_name enable: Architecture and Core Commands. (line 849) * aarch64 cache_info: Architecture and Core Commands. (line 959) * aarch64 dbginit: Architecture and Core Commands. (line 962) * aarch64 disassemble: Architecture and Core Commands. (line 971) * aarch64 maskisr: Architecture and Core Commands. (line 984) * aarch64 smp: Architecture and Core Commands. (line 975) * adapter assert: General Commands. (line 264) * adapter deassert: General Commands. (line 265) * adapter driver: Debug Adapter Configuration. (line 43) * adapter list: Debug Adapter Configuration. (line 46) * adapter name: Debug Adapter Configuration. (line 55) * adapter serial: Debug Adapter Configuration. (line 69) * adapter speed: Debug Adapter Configuration. (line 1287) * adapter srst delay: Reset Configuration. (line 126) * adapter srst pulse_width: Reset Configuration. (line 121) * adapter transports: Debug Adapter Configuration. (line 49) * adapter usb location: Debug Adapter Configuration. (line 58) * addreg: Architecture and Core Commands. (line 1232) * add_help_text: General Commands. (line 501) * add_script_search_dir: General Commands. (line 91) * add_usage_text: General Commands. (line 504) * aduc702x: Flash Commands. (line 622) * am335xgpio: Debug Adapter Configuration. (line 877) * am335xgpio jtag_nums: Debug Adapter Configuration. (line 894) * am335xgpio led_num: Debug Adapter Configuration. (line 951) * am335xgpio led_on_state: Debug Adapter Configuration. (line 955) * am335xgpio speed_coeffs: Debug Adapter Configuration. (line 959) * am335xgpio srst_num: Debug Adapter Configuration. (line 945) * am335xgpio swclk_num: Debug Adapter Configuration. (line 924) * am335xgpio swdio_dir_num: Debug Adapter Configuration. (line 934) * am335xgpio swdio_dir_output_state: Debug Adapter Configuration. (line 941) * am335xgpio swdio_num: Debug Adapter Configuration. (line 929) * am335xgpio swd_nums: Debug Adapter Configuration. (line 919) * am335xgpio tck_num: Debug Adapter Configuration. (line 899) * am335xgpio tdi_num: Debug Adapter Configuration. (line 914) * am335xgpio tdo_num: Debug Adapter Configuration. (line 909) * am335xgpio tms_num: Debug Adapter Configuration. (line 904) * am335xgpio trst_num: Debug Adapter Configuration. (line 948) * ambiqmicro: Flash Commands. (line 631) * ambiqmicro mass_erase: Flash Commands. (line 659) * ambiqmicro page_erase: Flash Commands. (line 661) * ambiqmicro program_otp: Flash Commands. (line 663) * amt_jtagaccel: Debug Adapter Configuration. (line 83) * arc add-reg: Architecture and Core Commands. (line 1480) * arc add-reg-type-flags: Architecture and Core Commands. (line 1534) * arc add-reg-type-struct: Architecture and Core Commands. (line 1539) * arc get-reg-field: Architecture and Core Commands. (line 1545) * arc jtag get-aux-reg: Architecture and Core Commands. (line 1567) * arc jtag get-core-reg: Architecture and Core Commands. (line 1573) * arc jtag set-aux-reg: Architecture and Core Commands. (line 1557) * arc jtag set-core-reg: Architecture and Core Commands. (line 1563) * arc set-reg-exists: Architecture and Core Commands. (line 1550) * arm core_state: Architecture and Core Commands. (line 275) * arm disassemble: Architecture and Core Commands. (line 281) * arm mcr: Architecture and Core Commands. (line 295) * arm mrc: Architecture and Core Commands. (line 301) * arm reg: Architecture and Core Commands. (line 307) * arm semihosting: Architecture and Core Commands. (line 311) * arm semihosting_basedir: Architecture and Core Commands. (line 382) * arm semihosting_cmdline: Architecture and Core Commands. (line 332) * arm semihosting_fileio: Architecture and Core Commands. (line 343) * arm semihosting_read_user_param: Architecture and Core Commands. (line 373) * arm semihosting_redirect: Architecture and Core Commands. (line 322) * arm semihosting_resexit: Architecture and Core Commands. (line 352) * arm-jtag-ew: Debug Adapter Configuration. (line 96) * arm11 memwrite burst: Architecture and Core Commands. (line 650) * arm11 memwrite error_fatal: Architecture and Core Commands. (line 660) * arm11 step_irq_enable: Architecture and Core Commands. (line 666) * arm11 vcr: Architecture and Core Commands. (line 671) * arm7_9 dbgrq: Architecture and Core Commands. (line 402) * arm7_9 dcc_downloads: Architecture and Core Commands. (line 412) * arm7_9 fast_memory_access: Architecture and Core Commands. (line 423) * arm9 vector_catch: Architecture and Core Commands. (line 439) * arm920t cache_info: Architecture and Core Commands. (line 460) * arm920t cp15: Architecture and Core Commands. (line 465) * arm920t read_cache: Architecture and Core Commands. (line 471) * arm920t read_mmu: Architecture and Core Commands. (line 474) * arm926ejs cache_info: Architecture and Core Commands. (line 488) * arm966e cp15: Architecture and Core Commands. (line 498) * armjtagew_info: Debug Adapter Configuration. (line 100) * at91rm9200: Debug Adapter Configuration. (line 103) * at91sam3: Flash Commands. (line 747) * at91sam3 gpnvm: Flash Commands. (line 779) * at91sam3 gpnvm clear: Flash Commands. (line 780) * at91sam3 gpnvm set: Flash Commands. (line 781) * at91sam3 gpnvm show: Flash Commands. (line 782) * at91sam3 info: Flash Commands. (line 788) * at91sam3 slowclk: Flash Commands. (line 798) * at91sam4: Flash Commands. (line 802) * at91sam4l: Flash Commands. (line 807) * at91sam4l smap_reset_deassert: Flash Commands. (line 813) * at91sam7: Flash Commands. (line 885) * at91sam7 gpnvm: Flash Commands. (line 918) * at91sam9: Flash Commands. (line 2399) * at91sam9 ale: Flash Commands. (line 2413) * at91sam9 ce: Flash Commands. (line 2424) * at91sam9 cle: Flash Commands. (line 2410) * at91sam9 rdy_busy: Flash Commands. (line 2419) * at91samd: Flash Commands. (line 669) * at91samd bootloader: Flash Commands. (line 710) * at91samd chip-erase: Flash Commands. (line 680) * at91samd dsu_reset_deassert: Flash Commands. (line 722) * at91samd eeprom: Flash Commands. (line 696) * at91samd nvmuserrow: Flash Commands. (line 727) * at91samd set-security: Flash Commands. (line 685) * ath79: Flash Commands. (line 580) * atsame5: Flash Commands. (line 818) * atsame5 bootloader: Flash Commands. (line 829) * atsame5 chip-erase: Flash Commands. (line 841) * atsame5 dsu_reset_deassert: Flash Commands. (line 846) * atsame5 userpage: Flash Commands. (line 851) * atsamv: Flash Commands. (line 871) * atsamv gpnvm: Flash Commands. (line 878) * atsamv gpnvm <1>: Flash Commands. (line 879) * avr: Flash Commands. (line 926) * bcm2835gpio: Debug Adapter Configuration. (line 788) * bcm2835gpio jtag_nums: Debug Adapter Configuration. (line 804) * bcm2835gpio peripheral_base: Debug Adapter Configuration. (line 862) * bcm2835gpio speed_coeffs: Debug Adapter Configuration. (line 856) * bcm2835gpio srst_num: Debug Adapter Configuration. (line 850) * bcm2835gpio swclk_num: Debug Adapter Configuration. (line 834) * bcm2835gpio swdio_dir_num: Debug Adapter Configuration. (line 844) * bcm2835gpio swdio_num: Debug Adapter Configuration. (line 839) * bcm2835gpio swd_nums: Debug Adapter Configuration. (line 829) * bcm2835gpio tck_num: Debug Adapter Configuration. (line 809) * bcm2835gpio tdi_num: Debug Adapter Configuration. (line 824) * bcm2835gpio tdo_num: Debug Adapter Configuration. (line 819) * bcm2835gpio tms_num: Debug Adapter Configuration. (line 814) * bcm2835gpio trst_num: Debug Adapter Configuration. (line 853) * bindto: General Commands. (line 94) * bluenrg-x: Flash Commands. (line 930) * bp: General Commands. (line 387) * buspirate: Debug Adapter Configuration. (line 1108) * buspirate led: Debug Adapter Configuration. (line 1151) * buspirate mode: Debug Adapter Configuration. (line 1129) * buspirate port: Debug Adapter Configuration. (line 1120) * buspirate pullup: Debug Adapter Configuration. (line 1138) * buspirate speed: Debug Adapter Configuration. (line 1124) * buspirate vreg: Debug Adapter Configuration. (line 1145) * cache_config l2x: Architecture and Core Commands. (line 709) * cc26xx: Flash Commands. (line 948) * cc3220sf: Flash Commands. (line 958) * cfi: Flash Commands. (line 293) * cmsis-dap: Debug Adapter Configuration. (line 107) * cmsis-dap cmd: Debug Adapter Configuration. (line 137) * cmsis-dap info: Debug Adapter Configuration. (line 133) * cmsis_dap_backend: Debug Adapter Configuration. (line 118) * cmsis_dap_usb interface: Debug Adapter Configuration. (line 127) * cmsis_dap_vid_pid: Debug Adapter Configuration. (line 111) * command mode: Server Configuration. (line 29) * cortex_a cache_info: Architecture and Core Commands. (line 687) * cortex_a dacrfixup: Architecture and Core Commands. (line 690) * cortex_a dbginit: Architecture and Core Commands. (line 696) * cortex_a maskisr: Architecture and Core Commands. (line 706) * cortex_a mmu dump: Architecture and Core Commands. (line 712) * cortex_a smp: Architecture and Core Commands. (line 700) * cortex_a smp_gdb: Architecture and Core Commands. (line 703) * cortex_m maskisr: Architecture and Core Commands. (line 900) * cortex_m reset_config: Architecture and Core Commands. (line 940) * cortex_m vector_catch: Architecture and Core Commands. (line 924) * cortex_r4 dbginit: Architecture and Core Commands. (line 722) * cortex_r4 maskisr: Architecture and Core Commands. (line 726) * cti create: Architecture and Core Commands. (line 232) * cti names: Architecture and Core Commands. (line 264) * dap create: TAP Declaration. (line 387) * dap info: TAP Declaration. (line 421) * dap init: Server Configuration. (line 81) * dap init <1>: TAP Declaration. (line 425) * dap names: TAP Declaration. (line 417) * davinci: Flash Commands. (line 2430) * debug_level: General Commands. (line 72) * drscan: JTAG Commands. (line 42) * dummy: Debug Adapter Configuration. (line 147) * dummy <1>: Architecture and Core Commands. (line 190) * dump_image: General Commands. (line 329) * du_select: Architecture and Core Commands. (line 1219) * echo: General Commands. (line 82) * efm32: Flash Commands. (line 970) * ep93xx: Debug Adapter Configuration. (line 150) * esirisc: Flash Commands. (line 995) * esirisc cache_arch: Architecture and Core Commands. (line 1007) * esirisc flash mass_erase: Flash Commands. (line 1006) * esirisc flash ref_erase: Flash Commands. (line 1010) * esirisc flush_caches: Architecture and Core Commands. (line 1021) * esirisc hwdc: Architecture and Core Commands. (line 1012) * esirisc trace analyze: Architecture and Core Commands. (line 1149) * esirisc trace buffer: Architecture and Core Commands. (line 1051) * esirisc trace dump: Architecture and Core Commands. (line 1155) * esirisc trace fifo: Architecture and Core Commands. (line 1056) * esirisc trace flow_control: Architecture and Core Commands. (line 1059) * esirisc trace format: Architecture and Core Commands. (line 1063) * esirisc trace info: Architecture and Core Commands. (line 1137) * esirisc trace init: Architecture and Core Commands. (line 1132) * esirisc trace start: Architecture and Core Commands. (line 1143) * esirisc trace status: Architecture and Core Commands. (line 1140) * esirisc trace stop: Architecture and Core Commands. (line 1146) * esirisc trace trigger delay: Architecture and Core Commands. (line 1119) * esirisc trace trigger start: Architecture and Core Commands. (line 1076) * esirisc trace trigger stop: Architecture and Core Commands. (line 1099) * etb: Architecture and Core Commands. (line 198) * etb config: Architecture and Core Commands. (line 201) * etb trigger_percent: Architecture and Core Commands. (line 204) * etm analyze: Architecture and Core Commands. (line 166) * etm config: Architecture and Core Commands. (line 63) * etm dump: Architecture and Core Commands. (line 170) * etm image: Architecture and Core Commands. (line 173) * etm info: Architecture and Core Commands. (line 89) * etm load: Architecture and Core Commands. (line 176) * etm start: Architecture and Core Commands. (line 179) * etm status: Architecture and Core Commands. (line 95) * etm stop: Architecture and Core Commands. (line 182) * etm tracemode: Architecture and Core Commands. (line 100) * etm trigger_debug: Architecture and Core Commands. (line 119) * etm_dummy config: Architecture and Core Commands. (line 195) * exit: General Commands. (line 30) * fast_load: General Commands. (line 333) * fast_load_image: General Commands. (line 337) * fespi: Flash Commands. (line 613) * find: Config File Guidelines. (line 57) * flash bank: Flash Commands. (line 36) * flash banks: Flash Commands. (line 67) * flash erase_address: Flash Commands. (line 135) * flash erase_check: Flash Commands. (line 230) * flash erase_sector: Flash Commands. (line 129) * flash fillb: Flash Commands. (line 149) * flash filld: Flash Commands. (line 146) * flash fillh: Flash Commands. (line 148) * flash fillw: Flash Commands. (line 147) * flash info: Flash Commands. (line 234) * flash init: Server Configuration. (line 82) * flash list: Flash Commands. (line 72) * flash mdb: Flash Commands. (line 162) * flash mdh: Flash Commands. (line 161) * flash mdw: Flash Commands. (line 160) * flash padded_value: Flash Commands. (line 252) * flash probe: Flash Commands. (line 77) * flash protect: Flash Commands. (line 242) * flash read_bank: Flash Commands. (line 176) * flash verify_bank: Flash Commands. (line 183) * flash verify_image: Flash Commands. (line 217) * flash write_bank: Flash Commands. (line 170) * flash write_image: Flash Commands. (line 189) * flush_count: JTAG Commands. (line 70) * fm3: Flash Commands. (line 1014) * fm4: Flash Commands. (line 1023) * ft232r: Debug Adapter Configuration. (line 282) * ft232r jtag_nums: Debug Adapter Configuration. (line 322) * ft232r restore_serial: Debug Adapter Configuration. (line 350) * ft232r srst_num: Debug Adapter Configuration. (line 346) * ft232r tck_num: Debug Adapter Configuration. (line 326) * ft232r tdi_num: Debug Adapter Configuration. (line 334) * ft232r tdo_num: Debug Adapter Configuration. (line 338) * ft232r tms_num: Debug Adapter Configuration. (line 330) * ft232r trst_num: Debug Adapter Configuration. (line 342) * ft232r vid_pid: Debug Adapter Configuration. (line 318) * ftdi: Debug Adapter Configuration. (line 154) * ftdi channel: Debug Adapter Configuration. (line 206) * ftdi device_desc: Debug Adapter Configuration. (line 201) * ftdi get_signal: Debug Adapter Configuration. (line 263) * ftdi layout_init: Debug Adapter Configuration. (line 211) * ftdi layout_signal: Debug Adapter Configuration. (line 221) * ftdi set_signal: Debug Adapter Configuration. (line 257) * ftdi tdo_sample_edge: Debug Adapter Configuration. (line 266) * ftdi vid_pid: Debug Adapter Configuration. (line 196) * gdb_breakpoint_override: Server Configuration. (line 178) * gdb_flash_program: Server Configuration. (line 185) * gdb_memory_map: Server Configuration. (line 189) * gdb_port: Server Configuration. (line 125) * gdb_report_data_abort: Server Configuration. (line 197) * gdb_report_register_access_error: Server Configuration. (line 202) * gdb_save_tdesc: Server Configuration. (line 212) * gdb_target_description: Server Configuration. (line 207) * get_reg: General Commands. (line 155) * gw16012: Debug Adapter Configuration. (line 424) * halt: General Commands. (line 199) * help: General Commands. (line 33) * hla: Debug Adapter Configuration. (line 662) * hla_command: Debug Adapter Configuration. (line 692) * hla_device_desc: Debug Adapter Configuration. (line 674) * hla_layout: Debug Adapter Configuration. (line 677) * hla_stlink_backend: Debug Adapter Configuration. (line 683) * hla_vid_pid: Debug Adapter Configuration. (line 680) * imx_gpio: Debug Adapter Configuration. (line 869) * init: Server Configuration. (line 59) * init_reset: Reset Configuration. (line 258) * ipdbg: Boundary Scan Commands. (line 81) * irscan: JTAG Commands. (line 81) * itm port: Architecture and Core Commands. (line 890) * itm ports: Architecture and Core Commands. (line 894) * jlink: Debug Adapter Configuration. (line 434) * jlink config: Debug Adapter Configuration. (line 459) * jlink config ip: Debug Adapter Configuration. (line 467) * jlink config mac: Debug Adapter Configuration. (line 464) * jlink config reset: Debug Adapter Configuration. (line 475) * jlink config targetpower: Debug Adapter Configuration. (line 461) * jlink config usb: Debug Adapter Configuration. (line 471) * jlink config write: Debug Adapter Configuration. (line 477) * jlink emucom read: Debug Adapter Configuration. (line 487) * jlink emucom write: Debug Adapter Configuration. (line 480) * jlink freemem: Debug Adapter Configuration. (line 454) * jlink hwstatus: Debug Adapter Configuration. (line 451) * jlink jtag: Debug Adapter Configuration. (line 456) * jlink usb: Debug Adapter Configuration. (line 495) * jtag arp_init: Reset Configuration. (line 276) * jtag arp_init-reset: Reset Configuration. (line 286) * jtag cget: TAP Declaration. (line 205) * jtag cget <1>: TAP Declaration. (line 208) * jtag configure: TAP Declaration. (line 209) * jtag names: TAP Declaration. (line 81) * jtag newtap: TAP Declaration. (line 113) * jtag tapdisable: TAP Declaration. (line 303) * jtag tapenable: TAP Declaration. (line 308) * jtag tapisenabled: TAP Declaration. (line 313) * jtagspi: Flash Commands. (line 328) * jtagspi always_4byte: Flash Commands. (line 381) * jtagspi cmd: Flash Commands. (line 375) * jtagspi set: Flash Commands. (line 366) * jtag_dpi: Debug Adapter Configuration. (line 1095) * jtag_dpi set_address: Debug Adapter Configuration. (line 1104) * jtag_dpi set_port: Debug Adapter Configuration. (line 1100) * jtag_init: Server Configuration. (line 100) * jtag_ntrst_assert_width: Reset Configuration. (line 133) * jtag_ntrst_delay: Reset Configuration. (line 138) * jtag_rclk: Debug Adapter Configuration. (line 1303) * kinetis: Flash Commands. (line 1039) * kinetis create_banks: Flash Commands. (line 1054) * kinetis disable_wdog: Flash Commands. (line 1122) * kinetis fcf_source: Flash Commands. (line 1060) * kinetis fopt: Flash Commands. (line 1072) * kinetis mdm check_security: Flash Commands. (line 1076) * kinetis mdm halt: Flash Commands. (line 1080) * kinetis mdm mass_erase: Flash Commands. (line 1085) * kinetis mdm reset: Flash Commands. (line 1117) * kinetis nvm_partition: Flash Commands. (line 1092) * kinetis_ke: Flash Commands. (line 1126) * kinetis_ke disable_wdog: Flash Commands. (line 1145) * kinetis_ke mdm check_security: Flash Commands. (line 1135) * kinetis_ke mdm mass_erase: Flash Commands. (line 1139) * kitprog: Debug Adapter Configuration. (line 504) * kitprog acquire_psoc: Debug Adapter Configuration. (line 545) * kitprog info: Debug Adapter Configuration. (line 552) * kitprog_init_acquire_psoc: Debug Adapter Configuration. (line 540) * linuxgpiod: Debug Adapter Configuration. (line 965) * linuxgpiod gpiochip: Debug Adapter Configuration. (line 972) * linuxgpiod jtag_nums: Debug Adapter Configuration. (line 979) * linuxgpiod led_num: Debug Adapter Configuration. (line 1033) * linuxgpiod srst_num: Debug Adapter Configuration. (line 1029) * linuxgpiod swclk_num: Debug Adapter Configuration. (line 1013) * linuxgpiod swdio_dir_num: Debug Adapter Configuration. (line 1023) * linuxgpiod swdio_num: Debug Adapter Configuration. (line 1018) * linuxgpiod swd_nums: Debug Adapter Configuration. (line 1008) * linuxgpiod tck_num: Debug Adapter Configuration. (line 984) * linuxgpiod tdi_num: Debug Adapter Configuration. (line 999) * linuxgpiod tdo_num: Debug Adapter Configuration. (line 994) * linuxgpiod tms_num: Debug Adapter Configuration. (line 989) * linuxgpiod trst_num: Debug Adapter Configuration. (line 1004) * load_image: General Commands. (line 348) * log_output: General Commands. (line 87) * lpc2000: Flash Commands. (line 1148) * lpc2000 part_id: Flash Commands. (line 1189) * lpc288x: Flash Commands. (line 1193) * lpc2900: Flash Commands. (line 1201) * lpc2900 password: Flash Commands. (line 1257) * lpc2900 read_custom: Flash Commands. (line 1246) * lpc2900 secure_jtag: Flash Commands. (line 1292) * lpc2900 secure_sector: Flash Commands. (line 1278) * lpc2900 signature: Flash Commands. (line 1237) * lpc2900 write_custom: Flash Commands. (line 1267) * lpc3180: Flash Commands. (line 2443) * lpc3180 select: Flash Commands. (line 2446) * lpcspifi: Flash Commands. (line 422) * mdb: General Commands. (line 304) * mdd: General Commands. (line 301) * mdh: General Commands. (line 303) * mdr: Flash Commands. (line 1299) * mdw: General Commands. (line 302) * memTestAddressBus: Utility Commands. (line 29) * memTestDataBus: Utility Commands. (line 25) * memTestDevice: Utility Commands. (line 34) * mrvlqspi: Flash Commands. (line 571) * msp432: Flash Commands. (line 1320) * msp432 bsl: Flash Commands. (line 1339) * msp432 mass_erase: Flash Commands. (line 1330) * mwb: General Commands. (line 317) * mwd: General Commands. (line 314) * mwh: General Commands. (line 316) * mww: General Commands. (line 315) * mx3: Flash Commands. (line 2456) * mxc: Flash Commands. (line 2460) * mxc biswap: Flash Commands. (line 2468) * nand check_bad_blocks: Flash Commands. (line 2358) * nand device: Flash Commands. (line 2190) * nand dump: Flash Commands. (line 2233) * nand erase: Flash Commands. (line 2266) * nand info: Flash Commands. (line 2370) * nand init: Server Configuration. (line 83) * nand list: Flash Commands. (line 2213) * nand probe: Flash Commands. (line 2223) * nand raw_access: Flash Commands. (line 2375) * nand verify: Flash Commands. (line 2332) * nand write: Flash Commands. (line 2279) * niietcm4: Flash Commands. (line 1351) * niietcm4 bflash_info_remap: Flash Commands. (line 1391) * niietcm4 driver_info: Flash Commands. (line 1404) * niietcm4 extmem_cfg: Flash Commands. (line 1395) * niietcm4 service_mode_erase: Flash Commands. (line 1400) * niietcm4 uflash_erase: Flash Commands. (line 1378) * niietcm4 uflash_full_erase: Flash Commands. (line 1375) * niietcm4 uflash_protect: Flash Commands. (line 1386) * niietcm4 uflash_protect_check: Flash Commands. (line 1383) * niietcm4 uflash_read_byte: Flash Commands. (line 1368) * niietcm4 uflash_write_byte: Flash Commands. (line 1371) * noinit: Server Configuration. (line 94) * npcx: Flash Commands. (line 1407) * nrf5: Flash Commands. (line 1416) * nrf5 info: Flash Commands. (line 1434) * nrf5 mass_erase: Flash Commands. (line 1428) * ocd_find: Config File Guidelines. (line 60) * ocl: Flash Commands. (line 1437) * opendous: Debug Adapter Configuration. (line 744) * openjtag: Debug Adapter Configuration. (line 1043) * openjtag device_desc: Debug Adapter Configuration. (line 1057) * openjtag variant: Debug Adapter Configuration. (line 1047) * orion: Flash Commands. (line 2472) * parport: Debug Adapter Configuration. (line 556) * parport cable: Debug Adapter Configuration. (line 562) * parport port: Debug Adapter Configuration. (line 88) * parport port <1>: Debug Adapter Configuration. (line 428) * parport port <2>: Debug Adapter Configuration. (line 591) * parport toggling_time: Debug Adapter Configuration. (line 601) * parport write_on_exit: Debug Adapter Configuration. (line 635) * pathmove: JTAG Commands. (line 98) * pic32mx: Flash Commands. (line 1448) * pic32mx pgm_word: Flash Commands. (line 1456) * pic32mx unlock: Flash Commands. (line 1459) * pld device: PLD/FPGA Commands. (line 23) * pld devices: PLD/FPGA Commands. (line 28) * pld init: Server Configuration. (line 84) * pld load: PLD/FPGA Commands. (line 31) * poll: Server Configuration. (line 252) * presto: Debug Adapter Configuration. (line 647) * profile: General Commands. (line 488) * program: Flash Commands. (line 258) * psoc4: Flash Commands. (line 1463) * psoc4 flash_autoerase: Flash Commands. (line 1475) * psoc4 mass_erase: Flash Commands. (line 1488) * psoc5lp: Flash Commands. (line 1494) * psoc5lp mass_erase: Flash Commands. (line 1513) * psoc5lp_eeprom: Flash Commands. (line 1518) * psoc5lp_nvl: Flash Commands. (line 1527) * psoc6: Flash Commands. (line 1547) * psoc6 mass_erase: Flash Commands. (line 1607) * psoc6 reset_halt: Flash Commands. (line 1598) * rbp: General Commands. (line 397) * read_memory: General Commands. (line 183) * reg: General Commands. (line 109) * remote_bitbang: Debug Adapter Configuration. (line 360) * remote_bitbang host: Debug Adapter Configuration. (line 372) * remote_bitbang port: Debug Adapter Configuration. (line 368) * reset: General Commands. (line 238) * reset halt: General Commands. (line 240) * reset init: General Commands. (line 241) * reset run: General Commands. (line 239) * reset_config: Reset Configuration. (line 143) * resume: General Commands. (line 229) * riscv authdata_read: Architecture and Core Commands. (line 1438) * riscv authdata_write: Architecture and Core Commands. (line 1441) * riscv dmi_read: Architecture and Core Commands. (line 1450) * riscv dmi_write: Architecture and Core Commands. (line 1453) * riscv expose_csrs: Architecture and Core Commands. (line 1302) * riscv expose_custom: Architecture and Core Commands. (line 1324) * riscv resume_order: Architecture and Core Commands. (line 1387) * riscv set_command_timeout_sec: Architecture and Core Commands. (line 1347) * riscv set_ebreakm: Architecture and Core Commands. (line 1414) * riscv set_ebreaks: Architecture and Core Commands. (line 1419) * riscv set_ebreaku: Architecture and Core Commands. (line 1424) * riscv set_enable_virt2phys: Architecture and Core Commands. (line 1382) * riscv set_enable_virtual: Architecture and Core Commands. (line 1377) * riscv set_ir: Architecture and Core Commands. (line 1399) * riscv set_mem_access: Architecture and Core Commands. (line 1361) * riscv set_reset_timeout_sec: Architecture and Core Commands. (line 1352) * riscv set_scratch_ram: Architecture and Core Commands. (line 1356) * riscv use_bscan_tunnel: Architecture and Core Commands. (line 1409) * rlink: Debug Adapter Configuration. (line 650) * rp2040: Flash Commands. (line 1612) * rtck: Debug Adapter Configuration. (line 92) * rtt channellist: General Commands. (line 461) * rtt channels: General Commands. (line 458) * rtt polling_interval: General Commands. (line 453) * rtt server start: General Commands. (line 465) * rtt server stop: General Commands. (line 468) * rtt setup: General Commands. (line 440) * rtt start: General Commands. (line 446) * rtt stop: General Commands. (line 450) * runAllMemTests: Utility Commands. (line 39) * runtest: JTAG Commands. (line 106) * rwp: General Commands. (line 400) * s3c2410: Flash Commands. (line 2480) * s3c2412: Flash Commands. (line 2481) * s3c2440: Flash Commands. (line 2482) * s3c2443: Flash Commands. (line 2483) * s3c6400: Flash Commands. (line 2484) * scan_chain: TAP Declaration. (line 89) * set_reg: General Commands. (line 143) * shutdown: General Commands. (line 54) * sim3x: Flash Commands. (line 1620) * sim3x lock: Flash Commands. (line 1636) * sim3x mass_erase: Flash Commands. (line 1631) * sleep: General Commands. (line 48) * soft_reset_halt: General Commands. (line 256) * st-link: Debug Adapter Configuration. (line 696) * st-link backend: Debug Adapter Configuration. (line 710) * st-link cmd: Debug Adapter Configuration. (line 725) * st-link vid_pid: Debug Adapter Configuration. (line 722) * stellaris: Flash Commands. (line 1639) * stellaris recover: Flash Commands. (line 1647) * step: General Commands. (line 234) * stm32f1x: Flash Commands. (line 1660) * stm32f1x lock: Flash Commands. (line 1683) * stm32f1x mass_erase: Flash Commands. (line 1693) * stm32f1x options_load: Flash Commands. (line 1710) * stm32f1x options_read: Flash Commands. (line 1697) * stm32f1x options_write: Flash Commands. (line 1702) * stm32f1x unlock: Flash Commands. (line 1687) * stm32f2x: Flash Commands. (line 1717) * stm32f2x lock: Flash Commands. (line 1742) * stm32f2x mass_erase: Flash Commands. (line 1750) * stm32f2x optcr2_write: Flash Commands. (line 1768) * stm32f2x options_read: Flash Commands. (line 1754) * stm32f2x options_write: Flash Commands. (line 1759) * stm32f2x otp: Flash Commands. (line 1730) * stm32f2x unlock: Flash Commands. (line 1746) * stm32h7x: Flash Commands. (line 1773) * stm32h7x lock: Flash Commands. (line 1789) * stm32h7x mass_erase: Flash Commands. (line 1797) * stm32h7x option_read: Flash Commands. (line 1801) * stm32h7x option_write: Flash Commands. (line 1816) * stm32h7x unlock: Flash Commands. (line 1793) * stm32l4x: Flash Commands. (line 1861) * stm32l4x lock: Flash Commands. (line 1888) * stm32l4x mass_erase: Flash Commands. (line 1902) * stm32l4x option_load: Flash Commands. (line 1952) * stm32l4x option_read: Flash Commands. (line 1906) * stm32l4x option_write: Flash Commands. (line 1921) * stm32l4x otp: Flash Commands. (line 1874) * stm32l4x trustzone: Flash Commands. (line 1957) * stm32l4x unlock: Flash Commands. (line 1895) * stm32l4x wrp_info: Flash Commands. (line 1939) * stm32lx: Flash Commands. (line 1828) * stm32lx lock: Flash Commands. (line 1847) * stm32lx mass_erase: Flash Commands. (line 1855) * stm32lx unlock: Flash Commands. (line 1851) * stmqspi: Flash Commands. (line 459) * stmqspi cmd: Flash Commands. (line 541) * stmqspi mass_erase: Flash Commands. (line 520) * stmqspi set: Flash Commands. (line 524) * stmsmi: Flash Commands. (line 439) * str7x: Flash Commands. (line 1965) * str7x disable_jtag: Flash Commands. (line 1974) * str9x: Flash Commands. (line 1978) * str9x flash_config: Flash Commands. (line 1987) * str9xpec: Flash Commands. (line 1996) * str9xpec disable_turbo: Flash Commands. (line 2039) * str9xpec enable_turbo: Flash Commands. (line 2042) * str9xpec lock: Flash Commands. (line 2046) * str9xpec options_cmap: Flash Commands. (line 2053) * str9xpec options_lvdsel: Flash Commands. (line 2056) * str9xpec options_lvdthd: Flash Commands. (line 2059) * str9xpec options_lvdwarn: Flash Commands. (line 2062) * str9xpec options_read: Flash Commands. (line 2065) * str9xpec options_write: Flash Commands. (line 2068) * str9xpec part_id: Flash Commands. (line 2050) * str9xpec unlock: Flash Commands. (line 2071) * svf: Boundary Scan Commands. (line 17) * swd newdap: Debug Adapter Configuration. (line 1211) * swm050: Flash Commands. (line 2074) * swm050 mass_erase: Flash Commands. (line 2082) * swo: Architecture and Core Commands. (line 748) * sysfsgpio: Debug Adapter Configuration. (line 1037) * tap_select: Architecture and Core Commands. (line 1216) * target create: CPU Configuration. (line 198) * target current: CPU Configuration. (line 37) * target init: Server Configuration. (line 79) * target names: CPU Configuration. (line 40) * target types: CPU Configuration. (line 71) * targets: CPU Configuration. (line 46) * target_request debugmsgs: Architecture and Core Commands. (line 1725) * tcl_notifications: Tcl Scripting API. (line 93) * tcl_port: Server Configuration. (line 155) * tcl_trace: Tcl Scripting API. (line 108) * telnet_port: Server Configuration. (line 163) * test_image: General Commands. (line 363) * tms470: Flash Commands. (line 2085) * tms470 flash_keyset: Flash Commands. (line 2092) * tms470 osc_megahertz: Flash Commands. (line 2096) * tms470 plldis: Flash Commands. (line 2099) * tpiu create: Architecture and Core Commands. (line 752) * tpiu init: Server Configuration. (line 85) * tpiu init <1>: Architecture and Core Commands. (line 772) * tpiu names: Architecture and Core Commands. (line 768) * trace history: Architecture and Core Commands. (line 1735) * trace point: Architecture and Core Commands. (line 1741) * transport init: Server Configuration. (line 80) * transport list: Debug Adapter Configuration. (line 1161) * transport select: Debug Adapter Configuration. (line 1165) * ulink: Debug Adapter Configuration. (line 747) * usage: General Commands. (line 43) * usbprog: Debug Adapter Configuration. (line 653) * usb_blaster: Debug Adapter Configuration. (line 391) * usb_blaster firmware: Debug Adapter Configuration. (line 420) * usb_blaster lowlevel_driver: Debug Adapter Configuration. (line 415) * usb_blaster pin: Debug Adapter Configuration. (line 405) * usb_blaster vid_pid: Debug Adapter Configuration. (line 397) * vdebug: Debug Adapter Configuration. (line 1061) * vdebug batching: Debug Adapter Configuration. (line 1068) * vdebug bfm_path: Debug Adapter Configuration. (line 1081) * vdebug mem_path: Debug Adapter Configuration. (line 1087) * vdebug polling: Debug Adapter Configuration. (line 1074) * vdebug server: Debug Adapter Configuration. (line 1064) * verify_image: General Commands. (line 369) * verify_image_checksum: General Commands. (line 375) * verify_ircapture: JTAG Commands. (line 111) * verify_jtag: JTAG Commands. (line 117) * version: General Commands. (line 494) * virt2phys: General Commands. (line 497) * virtex2: PLD/FPGA Commands. (line 42) * virtex2 read_stat: PLD/FPGA Commands. (line 50) * virtual: Flash Commands. (line 271) * vsllink: Debug Adapter Configuration. (line 656) * w600: Flash Commands. (line 2103) * wait_halt: General Commands. (line 200) * wp: General Commands. (line 403) * write_memory: General Commands. (line 168) * x86_32 idb: Architecture and Core Commands. (line 1191) * x86_32 idh: Architecture and Core Commands. (line 1187) * x86_32 idw: Architecture and Core Commands. (line 1183) * x86_32 iwb: Architecture and Core Commands. (line 1203) * x86_32 iwh: Architecture and Core Commands. (line 1199) * x86_32 iww: Architecture and Core Commands. (line 1195) * xcf: Flash Commands. (line 386) * xcf ccb: Flash Commands. (line 394) * xcf configure: Flash Commands. (line 410) * xds110: Debug Adapter Configuration. (line 750) * xds110 info: Debug Adapter Configuration. (line 763) * xds110 supply: Debug Adapter Configuration. (line 757) * xlnx_pcie_xvc: Debug Adapter Configuration. (line 767) * xlnx_pcie_xvc config: Debug Adapter Configuration. (line 778) * xmc1xxx: Flash Commands. (line 2110) * xmc4xxx: Flash Commands. (line 2115) * xmc4xxx flash_password: Flash Commands. (line 2122) * xmc4xxx flash_unprotect: Flash Commands. (line 2126) * xscale analyze_trace: Architecture and Core Commands. (line 580) * xscale cache_clean_address: Architecture and Core Commands. (line 583) * xscale cache_info: Architecture and Core Commands. (line 586) * xscale cp15: Architecture and Core Commands. (line 589) * xscale dcache: Architecture and Core Commands. (line 596) * xscale debug_handler: Architecture and Core Commands. (line 593) * xscale dump_trace: Architecture and Core Commands. (line 599) * xscale icache: Architecture and Core Commands. (line 602) * xscale mmu: Architecture and Core Commands. (line 605) * xscale trace_buffer: Architecture and Core Commands. (line 608) * xscale trace_image: Architecture and Core Commands. (line 612) * xscale vector_catch: Architecture and Core Commands. (line 618) * xscale vector_table: Architecture and Core Commands. (line 633) * xsvf: Boundary Scan Commands. (line 46) * xtensa maskisr: Architecture and Core Commands. (line 1616) * xtensa perfmon_dump: Architecture and Core Commands. (line 1661) * xtensa perfmon_enable: Architecture and Core Commands. (line 1647) * xtensa set_permissive: Architecture and Core Commands. (line 1610) * xtensa smpbreak: Architecture and Core Commands. (line 1620) * xtensa tracedump: Architecture and Core Commands. (line 1680) * xtensa tracestart: Architecture and Core Commands. (line 1665) * xtensa tracestop: Architecture and Core Commands. (line 1677) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_CH347/share/man/man1/openocd.1 ================================================ .TH "OPENOCD" "1" "November 24, 2009" .SH "NAME" openocd \- A free and open on\-chip debugging, in\-system programming and boundary\-scan testing tool for ARM and MIPS systems .SH "SYNOPSIS" .B openocd \fR[\fB\-fsdlcphv\fR] [\fB\-\-file\fR ] [\fB\-\-search\fR ] [\fB\-\-debug\fR ] [\fB\-\-log_output\fR ] [\fB\-\-command\fR ] [\fB\-\-pipe\fR] [\fB\-\-help\fR] [\fB\-\-version\fR] .SH "DESCRIPTION" .B OpenOCD is an on\-chip debugging, in\-system programming and boundary\-scan testing tool for various ARM and MIPS systems. .PP The debugger uses an IEEE 1149\-1 compliant JTAG TAP bus master to access on\-chip debug functionality available on ARM based microcontrollers or system-on-chip solutions. For MIPS systems the EJTAG interface is supported. .PP User interaction is realized through a telnet command line interface, a gdb (the GNU debugger) remote protocol server, and a simplified RPC connection that can be used to interface with OpenOCD's Jim Tcl engine. .PP OpenOCD supports various different types of JTAG interfaces/programmers, please check the \fIopenocd\fR info page for the complete list. .SH "OPTIONS" .TP .B "\-f, \-\-file " This is a shortcut for a \fB\-c "[script \fI\fB]"\fR command, using a search path to load the configuration file .IR . In order to specify multiple config files, you can use multiple .B \-\-file arguments. If no such \fB\-c\fR options are included, the first config file .B openocd.cfg in the search path will be used. .TP .B "\-s, \-\-search " Add .I to the search path used for config files and scripts. The search path begins with the current directory, then includes these additional directories before other components such as the standard OpenOCD script libraries. .TP .B "\-d, \-\-debug " Set debug level. Possible values are: .br .RB " * " 0 " (errors)" .br .RB " * " 1 " (warnings)" .br .RB " * " 2 " (informational messages)" .br .RB " * " 3 " (debug messages)" .br The default level is .BR 2 . .TP .B "\-l, \-\-log_output " Redirect log output to the file .IR . Per default the log output is printed on .BR stderr . .TP .B "\-c, \-\-command " Add the command .I to a list of commands executed on server startup. Note that you will need to explicitly invoke .I init if the command requires access to a target or flash. .TP .B "\-p, \-\-pipe" Use pipes when talking to gdb. .TP .B "\-h, \-\-help" Show a help text and exit. .TP .B "\-v, \-\-version" Show version information and exit. .SH "BUGS" Please report any bugs on the mailing list at .BR openocd\-devel@lists.sourceforge.net . .SH "LICENCE" .B OpenOCD is covered by the GNU General Public License (GPL), version 2 or later. .SH "SEE ALSO" .BR jtag (1) .PP The full documentation for .B openocd is maintained as a Texinfo manual. If the .BR info (or .BR pinfo ) and .BR openocd programs are properly installed at your site, the command .B info openocd should give you access to the complete manual. .SH "AUTHORS" Please see the file AUTHORS. .PP This manual page was written by Uwe Hermann . It is licensed under the terms of the GNU GPL (version 2 or later). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/.checkpatch.conf ================================================ # SPDX-License-Identifier: GPL-2.0-or-later --max-line-length=120 --tab-size=4 --show-types --strict --typedefsfile tools/scripts/typedefs.txt --ignore AVOID_EXTERNS --ignore BLOCK_COMMENT_STYLE --ignore COMPLEX_MACRO --ignore CONST_STRUCT --ignore ENOSYS --ignore FILE_PATH_CHANGES --ignore GERRIT_CHANGE_ID --ignore LINE_SPACING --ignore LOGICAL_CONTINUATIONS --ignore MACRO_WITH_FLOW_CONTROL --ignore NEW_TYPEDEFS --ignore PARENTHESIS_ALIGNMENT --ignore PREFER_DEFINED_ATTRIBUTE_MACRO --ignore PREFER_FALLTHROUGH --ignore PREFER_KERNEL_TYPES --ignore SPLIT_STRING --ignore SSCANF_TO_KSTRTO --ignore SWITCH_CASE_INDENT_LEVEL --ignore TRACING_LOGGING --ignore VOLATILE ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/.gitignore ================================================ # stuff "git status" should ignore # build output .libs .deps .dirstamp *.o *.o.?????? *.a *.lo *.la *.in # generated source files src/jtag/minidriver_imp.h src/jtag/jtag_minidriver.h # OpenULINK driver files generated by SDCC src/jtag/drivers/OpenULINK/*.rel src/jtag/drivers/OpenULINK/*.asm src/jtag/drivers/OpenULINK/*.lst src/jtag/drivers/OpenULINK/*.sym src/jtag/drivers/OpenULINK/*.map src/jtag/drivers/OpenULINK/*.mem src/jtag/drivers/OpenULINK/*.lk src/jtag/drivers/OpenULINK/*.ihx src/jtag/drivers/OpenULINK/*.rst # editor files *.swp src/startup.tcl startup_tcl.inc xscale_debug.inc bin2char bin2char.exe doc/openocd.aux doc/openocd.cp doc/openocd.cps doc/openocd.fn doc/openocd.fns doc/openocd.html doc/openocd.info doc/openocd.info-1 doc/openocd.info-2 doc/openocd.ky doc/openocd.log doc/openocd.pdf doc/openocd.pg doc/openocd.toc doc/openocd.tp doc/openocd.vr doc/version.texi src/openocd src/openocd.exe # configure/autotools output /build-aux/ aclocal.m4 autom4te.cache config.h config.log config.status configure doxygen doxygen.log Doxyfile libtool Makefile !contrib/loaders/**/Makefile stamp-h1 stamp-vti INSTALL NOTES # coexist with quilt patches *.patch # Eclipse stuff .project .cproject .settings # Emacs temp files *~ # Emacs TAGS file TAGS # CScope database files *cscope.out # ctags tag files tags # GNU Global tag files GPATH GRTAGS GTAGS # checkpatch script files .checkpatch-camelcase.* # clangd (e.g. for advanced code completion and linting) generates cache files # into .cache .cache # A compile_commands.json can be generated using bear and will help tools such # as clangd to locate header files and use correct $CFLAGS compile_commands.json ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/.gitmodules ================================================ [submodule "tools/git2cl"] path = tools/git2cl url = https://git.savannah.nongnu.org/git/git2cl.git [submodule "jimtcl"] path = jimtcl url = https://github.com/msteveb/jimtcl.git [submodule "src/jtag/drivers/libjaylink"] path = src/jtag/drivers/libjaylink url = https://gitlab.zapb.de/libjaylink/libjaylink.git ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/.travis.yml ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright Marek Vasut # OpenOCD on Travis CI - https://travis-ci.org/ sudo: required dist: bionic arch: - amd64 - arm64 - ppc64le - s390x addons: apt: sources: - sourceline: 'ppa:ubuntu-toolchain-r/test' - sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main' key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' packages: - libftdi-dev - libhidapi-dev - libjaylink-dev env: - CC=gcc-9 - CC=clang-9 language: c git: depth: 1 autocrlf: input script: - $mingw64 ${CC} --version - $mingw64 env - $mingw64 ./bootstrap - $mingw64 ./configure - $mingw64 make before_install: - |- case $TRAVIS_OS_NAME in linux) sudo apt install ${CC} libusb-1.0-0-dev ;; osx) brew install libtool automake libusb libusb-compat hidapi libftdi ;; windows) [[ ! -f C:/tools/msys64/msys2_shell.cmd ]] && rm -rf C:/tools/msys64 choco uninstall -y mingw choco upgrade --no-progress -y msys2 export msys2='cmd //C RefreshEnv.cmd ' export msys2+='& set MSYS=winsymlinks:nativestrict ' export msys2+='& C:\\tools\\msys64\\msys2_shell.cmd -defterm -no-start' export mingw64="$msys2 -mingw64 -full-path -here -c \$\* --" export msys2+=" -msys2 -c \$\* --" $msys2 pacman --sync --noconfirm --needed mingw-w64-x86_64-toolchain autoconf autoconf-archive automake automake-wrapper binutils gcc gettext git libtool m4 make pkg-config tcl texinfo mingw-w64-x86_64-libusb mingw-w64-x86_64-libusb-compat-git mingw-w64-x86_64-libjaylink-git mingw-w64-x86_64-libftdi mingw-w64-x86_64-hidapi mingw-w64-x86_64-clang ## FIXME: Also build for i686? ## Install more MSYS2 packages from https://packages.msys2.org/base here taskkill //IM gpg-agent.exe //F # https://travis-ci.community/t/4967 export PATH=/C/tools/msys64/mingw64/bin:$PATH export MAKE=mingw32-make # so that Autotools can find it ;; esac before_cache: - |- case $TRAVIS_OS_NAME in windows) # https://unix.stackexchange.com/a/137322/107554 $msys2 pacman --sync --clean --noconfirm ;; esac cache: directories: - $HOME/AppData/Local/Temp/chocolatey - /C/tools/msys64 matrix: include: - os: osx env: - CC=clang - os: windows env: - CC=gcc ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/AUTHORS ================================================ Dominic Rath Magnus Lundin Michael Fischer Spencer Oliver Carsten Schlote Øyvind Harboe Duane Ellis Michael Schwingen Rick Altherr David Brownell Vincint Palatin Zachary T Welch ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/AUTHORS.ChangeLog ================================================ drath:Dominic Rath mlu:Magnus Lundin mifi:Michael Fischer ntfreak:Spencer Oliver duane:Duane Ellis oharboe:Øyvind Harboe kc8apf:Rick Altherr zwelch:Zachary T Welch vpalatin:Vincent Palatin bodylove:Carsten Schlote ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/BUGS ================================================ // This file is part of the Doxygen Developer Manual /** @page bugs Bug Reporting Please report bugs by subscribing to the OpenOCD mailing list and posting a message with your report: openocd-devel@lists.sourceforge.net Also, please check the bug database to see if a ticket for the bug has already been opened. You might be asked to open such a ticket, or to update an existing ticket with more data. http://bugs.openocd.org/ To minimize work for OpenOCD developers, you should try to include all of the information listed below. If you feel that some of the items below are unnecessary for a clear bug report, you may leave them out; likewise, feel free to include additional information that may be important. - Target PCB/board description - Configuration scripts - OpenOCD command line - List of commands issued or GDB operations performed - Expected result - Actual result - Logs using debug_level 3 (or with '-d 3' on the command line) - If the report is for a regression: - Include logs for both working and broken versions. - Find the precise version that caused the regression by binary search. You can use "git bisect" to expedite this binary search: http://www.kernel.org/pub/software/scm/git/docs/git-bisect.html If possible, please develop and attach a patch that helps to expose or solve the reported problem. See the HACKING file for information about that process. Attach all files directly to your posting. The mailing list knows to transform attachments to links, but attachments must be less than 300KB in total. @section bugscrashdump Obtaining Crash Backtraces If OpenOCD is crashing, there are two very effective things you can do to improve your chances of getting help on the development mailing list. Try to reproduce the problem using the dummy JTAG interface to allow other developers to replicate your problem robustly and use GDB to get a trace:@par @code % OPENOCDSRC/configure --enable-dummy ... % openocd -f interface/dummy.cfg -f target/xxx.cfg => SEGFAULT % gdb --args openocd .... (gdb) run (gdb) bt => here a stack trace is dumped. @endcode @section bugsintreedebug Running and Debugging In-Tree To run or debug the in-tree executable (not recommended), you must use libtool to set up the correct shared library paths: @code libtool gdb --args openocd .... @endcode or the more pedantic (and forward-compatible): @code libtool --mode=execute gdb --args openocd .... @endcode */ /** @file This file contains the @ref bugs page. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/COPYING ================================================ OpenOCD is provided under: SPDX-License-Identifier: GPL-2.0-or-later Being under the terms of the GNU General Public License version 2 or later, according with: LICENSES/preferred/GPL-2.0 In addition, other licenses may also apply. Please see: LICENSES/license-rules.txt for more details. All contributions to OpenOCD are subject to this COPYING file. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/ChangeLog ================================================ Retired in favor of git log. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/HACKING ================================================ // This file is part of the Doxygen Developer Manual /** @page patchguide Patch Guidelines \attention You can't send patches to the mailing list anymore at all. Nowadays you are expected to send patches to the OpenOCD Gerrit GIT server for a review. \attention If you already have a Gerrit account and want to try a different sign in method, please first sign in as usually, press your name in the upper-right corner, go to @a Settings, select @a Identities pane, press Link Another Identity button. In case you already have duplicated accounts, ask administrators for manual merging. \attention If you're behind a corporate wall with http only access to the world, you can still use these instructions! @section gerrit Submitting patches to the OpenOCD Gerrit server OpenOCD is to some extent a "self service" open source project, so to contribute, you must follow the standard procedures to have the best possible chance to get your changes accepted. The procedure to create a patch is essentially: - make the changes - create a commit - send the changes to the Gerrit server for review - correct the patch and re-send it according to review feedback Your patch (or commit) should be a "good patch": focus it on a single issue, and make it easily reviewable. Don't make it so large that it's hard to review; split large patches into smaller ones (this will also help to track down bugs later). All patches should be "clean", which includes preserving the existing coding style and updating documentation as needed. When adding a new command, the corresponding documentation should be added to @c doc/openocd.texi in the same commit. OpenOCD runs on both Little Endian and Big Endian hosts so the code can't count on specific byte ordering (in other words, must be endian-clean). There are several additional methods of improving the quality of your patch: - Runtime testing with Valgrind Memcheck This helps to spot memory leaks, undefined behaviour due to uninitialized data or wrong indexing, memory corruption, etc. - Clang Static Analyzer Using this tool uncovers many different kinds of bugs in C code, with problematic execution paths fully explained. It is a part of standard Clang installation. To generate a report, run this in the OpenOCD source directory: @code mkdir build-scanbuild; cd build-scanbuild scan-build ../configure scan-build make CFLAGS="-std=gnu99 -I. -I../../jimtcl" @endcode - Runtime testing with sanitizers Both GCC and LLVM/Clang include advanced instrumentation options to detect undefined behaviour and many kinds of memory errors. Available with @c -fsanitize=* command arguments. Example usage: @code mkdir build-sanitizers; cd build-sanitizers ../configure CC=clang CFLAGS="-fno-omit-frame-pointer \ -fsanitize=address -fsanitize=undefined -ggdb3" make export ASAN_OPTIONS=detect_stack_use_after_return=1 src/openocd -s ../tcl -f /path/to/openocd.cfg @endcode - Sparse Static Analyzer Using this tool allows identifying some bug in C code. In the future, OpenOCD would use the sparse attribute 'bitwise' to detect incorrect endianness assignments. Example usage: @code mkdir build-sparse; cd build-sparse ../configure CC=cgcc CFLAGS="-Wsparse-all -Wno-declaration-after-statement \ -Wno-unknown-attribute -Wno-transparent-union -Wno-tautological-compare \ -Wno-vla -Wno-flexible-array-array -D__FLT_EVAL_METHOD__=0" make @endcode Please consider performing these additional checks where appropriate (especially Clang Static Analyzer for big portions of new code) and mention the results (e.g. "Valgrind-clean, no new Clang analyzer warnings") in the commit message. Say in the commit message if it's a bugfix (describe the bug) or a new feature. Don't expect patches to merge immediately for the next release. Be ready to rework patches in response to feedback. Add yourself to the GPL copyright for non-trivial changes. @section stepbystep Step by step procedure -# Create a Gerrit account at: https://review.openocd.org - On subsequent sign ins, use the full URL prefaced with 'http://' For example: http://user_identifier.open_id_provider.com -# Add a username to your profile. After creating the Gerrit account and signing in, you will need to add a username to your profile. To do this, go to 'Settings', and add a username of your choice. Your username will be required in step 3 and substituted wherever the string 'USERNAME' is found. -# Create an SSH public key following the directions on github: https://help.github.com/articles/generating-ssh-keys . You can skip step 3 (adding key to Github account) and 4 (testing) - these are useful only if you actually use Github or want to test whether the new key works fine. -# Add this new SSH key to your Gerrit account: go to 'Settings' > 'SSH Public Keys', paste the contents of ~/.ssh/id_rsa.pub into the text field (if it's not visible click on 'Add Key ...' button) and confirm by clicking 'Add' button. -# Clone the git repository, rather than just download the source: @code git clone git://git.code.sf.net/p/openocd/code openocd @endcode or if you have problems with the "git:" protocol, use the slower http protocol: @code git clone http://git.code.sf.net/p/openocd/code openocd @endcode -# Set up Gerrit with your local repository. All this does it to instruct git locally how to send off the changes. -# Add a new remote to git using Gerrit username: @code git remote add review ssh://USERNAME@review.openocd.org:29418/openocd.git git config remote.review.push HEAD:refs/for/master @endcode Or with http only: @code git remote add review https://USERNAME@review.openocd.org/p/openocd.git git config remote.review.push HEAD:refs/for/master @endcode The http password is configured from your gerrit settings - https://review.openocd.org/#/settings/http-password. \note If you want to simplify http access you can also add your http password to the url as follows: @code git remote add review https://USERNAME:PASSWORD@review.openocd.org/p/openocd.git @endcode \note All contributions should be pushed to @c refs/for/master on the Gerrit server, even if you plan to use several local branches for different topics. It is possible because @c for/master is not a traditional Git branch. -# You will need to install this hook, we will look into a better solution: @code scp -p -P 29418 USERNAME@review.openocd.org:hooks/commit-msg .git/hooks/ @endcode Or with http only: @code wget https://review.openocd.org/tools/hooks/commit-msg mv commit-msg .git/hooks chmod +x .git/hooks/commit-msg @endcode \note A script exists to simplify the two items above. Execute: @code tools/initial.sh @endcode With @ being your Gerrit username. -# Set up git with your name and email: @code git config --global user.name "John Smith" git config --global user.email "john@smith.org" @endcode -# Work on your patches. Split the work into multiple small patches that can be reviewed and applied separately and safely to the OpenOCD repository. @code while(!done) { work - edit files using your favorite editor. run "git commit -s -a" to commit all changes. run tools/checkpatch.sh to verify your patch style is ok. } @endcode \note use "git add ." before commit to add new files. \note check @ref checkpatch for hint about checkpatch script Commit message template, notice the short first line. The field 'specify touched area' should identify the main part or subsystem the patch touches. @code{.unparsed} specify touched area: short comment Longer comments over several lines, explaining (where applicable) the reason for the patch and the general idea the solution is based on, any major design decisions, etc. Limit each comment line's length to 75 characters; since 75 it's too short for a URL, you can put the URL in a separate line preceded by 'Link: '. Signed-off-by: ... @endcode Examples: @code{.unparsed} flash/nor/atsame5: add SAME59 support Add new device ID @endcode @code{.unparsed} flash/nor: flash driver for XYZ123 Add new flash driver for internal flash of ... @endcode @code{.unparsed} target/cortex_m: fix segmentation fault in cmd 'soft_reset_halt' soft_reset_halt command failed reproducibly under following conditions: ... Test for NULL pointer and return error ... Reported-by: John Reporter Fixes: 123456789abc ("target: the commit where the problem started") BugLink: https://sourceforge.net/p/openocd/tickets/999/ @endcode @code{.unparsed} doc: fix typos @endcode See "git log" for more examples. -# Next you need to make sure that your patches are on top of the latest stuff on the server and that there are no conflicts: @code git pull --rebase origin master @endcode -# Send the patches to the Gerrit server for review: @code git push review @endcode -# Forgot something, want to add more? Just make the changes and do: @code git commit --amend git push review @endcode Further reading: http://www.coreboot.org/Git @section checkpatch About checkpatch script OpenOCD source code includes the script checkpatch to let developers to verify their patches before submitting them for review (see @ref gerrit). Every patch for OpenOCD project that is submitted for review on Gerrit is tested by Jenkins. Jenkins will run the checkpatch script to analyze each patch. If the script highlights either errors or warnings, Gerrit will add the score "-1" to the patch and maintainers will probably ignore the patch, waiting for the developer to send a fixed version. The script checkpatch verifies the SPDX tag for new files against a very short list of license tags. If the license of your contribution is not listed there, but compatible with OpenOCD license, please alert the maintainers or add the missing license in the first patch of your patch series. The script checkpatch has been originally developed for the Linux kernel source code, thus includes specific tests and checks related to Linux coding style and to Linux code structure. While the script has been adapted for OpenOCD specificities, it still includes some Linux related test. It is then possible that it triggers sometimes some false positive! If you think that the error identified by checkpatch is a false positive, please report it to the openocd-devel mailing list or prepare a patch for fixing checkpatch and send it to Gerrit for review. \attention The procedure below is allowed only for exceptional cases. Do not use it to submit normal patches. There are exceptional cases in which you need to skip some of the tests from checkpatch in order to pass the approval from Gerrit. For example, a patch that modify one line inside a big comment block will not show the beginning or the end of the comment block. This can prevent checkpatch to detect the comment block. Checkpatch can wrongly consider the modified comment line as a code line, triggering a set of false errors. Only for exceptional cases, it is allowed to submit patches to Gerrit with the special field 'Checkpatch-ignore:' in the commit message. This field will cause checkpatch to ignore the error types listed in the field, only for the patch itself. The error type is printed by checkpatch on failure. For example the names of Windows APIs mix lower and upper case chars, in violation of OpenOCD coding style, triggering a 'CAMELCASE' error: @code CHECK:CAMELCASE: Avoid CamelCase: #96105: FILE: src/helper/log.c:505: + error_code = WSAGetLastError(); @endcode Adding in the commit message of the patch the line: @code Checkpatch-ignore: CAMELCASE @endcode will force checkpatch to ignore the CAMELCASE error. @section timeline When can I expect my contribution to be committed? The code review is intended to take as long as a week or two to allow maintainers and contributors who work on OpenOCD only in their spare time opportunity to perform a review and raise objections. With Gerrit much of the urgency of getting things committed has been removed as the work in progress is safely stored in Gerrit and available if someone needs to build on your work before it is submitted to the official repository. Another factor that contributes to the desire for longer cool-off times (the time a patch lies around without any further changes or comments), it means that the chances of quality regression on the master branch will be much reduced. If a contributor pushes a patch, it is considered good form if another contributor actually approves and submits that patch. It should be noted that a negative review in Gerrit ("-1" or "-2") may (but does not have to) be disregarded if all conditions listed below are met: - the concerns raised in the review have been addressed (or explained), - reviewer does not re-examine the change in a month, - reviewer does not answer e-mails for another month. @section browsing Browsing Patches All OpenOCD patches can be reviewed here. @section reviewing Reviewing Patches From the main Review page select the patch you want to review and click on that patch. On the appearing page select the download method (top right). Apply the patch. After building and testing you can leave a note with the "Reply" button and mark the patch with -1, 0 and +1. */ /** @file This file contains the @ref patchguide page. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/LICENSES/exceptions/eCos-exception-2.0 ================================================ SPDX-Exception-Identifier: eCos-exception-2.0 SPDX-URL: https://spdx.org/licenses/eCos-exception-2.0.html SPDX-Licenses: GPL-2.0-only, GPL-2.0-or-later Usage-Guide: This exception is used together with one of the above SPDX-Licenses. To use this exception add it with the keyword WITH to one of the identifiers in the SPDX-Licenses tag: SPDX-License-Identifier: WITH eCos-exception-2.0 License-Text: As a special exception, if other files instantiate templates or use macros or inline functions from this file, or you compile this file and link it with other works to produce a work based on this file, this file does not by itself cause the resulting work to be covered by the GNU General Public License. However the source code for this file must still be made available in accordance with section (3) of the GNU General Public License. This exception does not invalidate any other reasons why a work based on this file might be covered by the GNU General Public License. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/LICENSES/license-rules.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later OpenOCD licensing rules ======================= The OpenOCD source code is provided under the terms of the GNU General Public License version 2 or later (GPL-2.0-or-later), as provided in LICENSES/preferred/GPL-2.0. The OpenOCD documentation is provided under the terms of the GNU Free Documentation License version 1.2 or later without Invariant Sections (GFDL-1.2-no-invariants-or-later). Few stand-alone applications coexist in the same code tree of OpenOCD and are provided under the terms of the GNU General Public License version 3 (GPL-3.0), as provided in LICENSES/stand-alone/GPL-3.0. This documentation file provides a description of how each source file should be annotated to make its license clear and unambiguous. It doesn't replace the OpenOCD's license. The license described in the COPYING file applies to the OpenOCD source as a whole, though individual source files can have a different license which is required to be compatible with the GPL-2.0: GPL-1.0-or-later : GNU General Public License v1.0 or later GPL-2.0-or-later : GNU General Public License v2.0 or later LGPL-2.0 : GNU Library General Public License v2 only LGPL-2.0-or-later : GNU Library General Public License v2 or later LGPL-2.1 : GNU Lesser General Public License v2.1 only LGPL-2.1-or-later : GNU Lesser General Public License v2.1 or later Aside from that, individual files can be provided under a dual license, e.g. one of the compatible GPL variants and alternatively under a permissive license like BSD, MIT etc. The common way of expressing the license of a source file is to add the matching boilerplate text into the top comment of the file. Due to formatting, typos etc. these "boilerplates" are hard to validate for tools which are used in the context of license compliance. An alternative to boilerplate text is the use of Software Package Data Exchange (SPDX) license identifiers in each source file. SPDX license identifiers are machine parsable and precise shorthands for the license under which the content of the file is contributed. SPDX license identifiers are managed by the SPDX Workgroup at the Linux Foundation and have been agreed on by partners throughout the industry, tool vendors, and legal teams. For further information see https://spdx.org/ OpenOCD requires the precise SPDX identifier in all source files. The valid identifiers used in OpenOCD are explained in the section `License identifiers` and have been retrieved from the official SPDX license list at https://spdx.org/licenses/ along with the license texts. License identifier syntax ------------------------- 1. Placement: The SPDX license identifier in OpenOCD files shall be added at the first possible line in a file which can contain a comment. For the majority of files this is the first line, except for scripts which require the '#!PATH_TO_INTERPRETER' in the first line. For those scripts the SPDX identifier goes into the second line. 2. Style: The SPDX license identifier is added in form of a comment. The comment style depends on the file type:: C source: // SPDX-License-Identifier: C header: /* SPDX-License-Identifier: */ ASM: /* SPDX-License-Identifier: */ makefiles: # SPDX-License-Identifier: scripts: # SPDX-License-Identifier: texinfo: @c SPDX-License-Identifier: text: # SPDX-License-Identifier: If a specific tool cannot handle the standard comment style, then the appropriate comment mechanism which the tool accepts shall be used. This is the reason for having the "/\* \*/" style comment in C header files. There was build breakage observed with generated .lds files where 'ld' failed to parse the C++ comment. This has been fixed by now, but there are still older assembler tools which cannot handle C++ style comments. 3. Syntax: A is either an SPDX short form license identifier found on the SPDX License List, or the combination of two SPDX short form license identifiers separated by "WITH" when a license exception applies. When multiple licenses apply, an expression consists of keywords "AND", "OR" separating sub-expressions and surrounded by "(", ")" . License identifiers for licenses like [L]GPL with the 'or later' option are constructed by using a "-or-later": // SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: LGPL-2.1-or-later WITH should be used when there is a modifier to a license needed. Exceptions can only be used with particular License identifiers. The valid License identifiers are listed in the tags of the exception text file. OR should be used if the file is dual licensed and only one license is to be selected. For example, some source files are available under dual licenses: // SPDX-License-Identifier: GPL-2.0-or-later OR BSD-1-Clause // SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause // SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause AND should be used if the file has multiple licenses whose terms all apply to use the file. For example, if code is inherited from another project and permission has been given to put it in OpenOCD, but the original license terms need to remain in effect:: // SPDX-License-Identifier: GPL-2.0-or-later AND MIT License identifiers ------------------- The licenses currently used, as well as the licenses for code added to OpenOCD, can be broken down into: 1. `Preferred licenses`: Whenever possible these licenses should be used as they are known to be fully compatible and widely used. These licenses are available from the directory: LICENSES/preferred/ in the OpenOCD source tree. The files in this directory contain the full license text and `Metatags`. The file names are identical to the SPDX license identifier which shall be used for the license in source files. Examples: LICENSES/preferred/GPL-2.0 Contains the GPL version 2 license text and the required metatags. `Metatags`: The following meta tags must be available in a license file: - Valid-License-Identifier: One or more lines which declare which License Identifiers are valid inside the project to reference this particular license text. Usually this is a single valid identifier, but e.g. for licenses with the 'or later' options two identifiers are valid. - SPDX-URL: The URL of the SPDX page which contains additional information related to the license. - Usage-Guidance: Freeform text for usage advice. The text must include correct examples for the SPDX license identifiers as they should be put into source files according to the `License identifier syntax` guidelines. - License-Text: All text after this tag is treated as the original license text File format examples:: Valid-License-Identifier: GPL-2.0 Valid-License-Identifier: GPL-2.0-only Valid-License-Identifier: GPL-2.0-or-later SPDX-URL: https://spdx.org/licenses/GPL-2.0.html Usage-Guide: To use this license in source code, put one of the following SPDX tag/value pairs into a comment according to the placement guidelines in the licensing rules documentation. For 'GNU General Public License (GPL) version 2 only' use: SPDX-License-Identifier: GPL-2.0 or SPDX-License-Identifier: GPL-2.0-only For 'GNU General Public License (GPL) version 2 or any later version' use: SPDX-License-Identifier: GPL-2.0-or-later License-Text: Full license text 2. Exceptions: Some licenses can be amended with exceptions which grant certain rights which the original license does not. These exceptions are available from the directory:: LICENSES/exceptions/ in the OpenOCD source tree. The files in this directory contain the full exception text and the required `Exception Metatags`_. Examples:: LICENSES/exceptions/eCos-exception-2.0 Exception Metatags: The following meta tags must be available in an exception file: - SPDX-Exception-Identifier: One exception identifier which can be used with SPDX license identifiers. - SPDX-URL: The URL of the SPDX page which contains additional information related to the exception. - SPDX-Licenses: A comma separated list of SPDX license identifiers for which the exception can be used. - Usage-Guidance: Freeform text for usage advice. The text must be followed by correct examples for the SPDX license identifiers as they should be put into source files according to the `License identifier syntax`_ guidelines. - Exception-Text: All text after this tag is treated as the original exception text File format examples:: SPDX-Exception-Identifier: eCos-exception-2.0 SPDX-URL: https://spdx.org/licenses/eCos-exception-2.0.html SPDX-Licenses: GPL-2.0-only, GPL-2.0-or-later Usage-Guide: This exception is used together with one of the above SPDX-Licenses. To use this exception add it with the keyword WITH to one of the identifiers in the SPDX-Licenses tag: SPDX-License-Identifier: WITH eCos-exception-2.0 License-Text: Full license text 3. Stand-alone licenses: These licenses should only be used for stand-alone applications that are distributed with OpenOCD but are not included in the OpenOCD binary. These licenses are available from the directory: LICENSES/stand-alone/ in the OpenOCD source tree. Examples: SPDX-License-Identifier: GPL-3.0 The format and requirements of the license files in the other sub-directories of directory LICENSES have to follow the same format and requirements of the `Preferred licenses`. All SPDX license identifiers and exceptions must have a corresponding file in the LICENSES subdirectories. This is required to allow tool verification (e.g. checkpatch.pl) and to have the licenses ready to read and extract right from the source, which is recommended by various FOSS organizations, e.g. the `FSFE REUSE initiative `. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/LICENSES/preferred/BSD-1-Clause ================================================ Valid-License-Identifier: BSD-1-Clause SPDX-URL: https://spdx.org/licenses/BSD-1-Clause.html Usage-Guide: To use the BSD 1-clause License put the following SPDX tag/value pair into a comment according to the placement guidelines in the licensing rules documentation: SPDX-License-Identifier: BSD-1-Clause License-Text: Copyright (c) . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/LICENSES/preferred/BSD-2-Clause ================================================ Valid-License-Identifier: BSD-2-Clause SPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html Usage-Guide: To use the BSD 2-clause "Simplified" License put the following SPDX tag/value pair into a comment according to the placement guidelines in the licensing rules documentation: SPDX-License-Identifier: BSD-2-Clause License-Text: Copyright (c) . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/LICENSES/preferred/BSD-2-Clause-Views ================================================ Valid-License-Identifier: BSD-2-Clause-Views SPDX-URL: https://spdx.org/licenses/BSD-2-Clause-Views.html Usage-Guide: To use the BSD 2-clause with views sentence License put the following SPDX tag/value pair into a comment according to the placement guidelines in the licensing rules documentation: SPDX-License-Identifier: BSD-2-Clause-Views License-Text: Copyright (c) . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of the copyright holders or contributors. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/LICENSES/preferred/BSD-3-Clause ================================================ Valid-License-Identifier: BSD-3-Clause SPDX-URL: https://spdx.org/licenses/BSD-3-Clause.html Usage-Guide: To use the BSD 3-clause "New" or "Revised" License put the following SPDX tag/value pair into a comment according to the placement guidelines in the licensing rules documentation: SPDX-License-Identifier: BSD-3-Clause License-Text: Copyright (c) . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/LICENSES/preferred/BSD-Source-Code ================================================ Valid-License-Identifier: BSD-Source-Code SPDX-URL: https://spdx.org/licenses/BSD-Source-Code.html Usage-Guide: To use the BSD Source Code Attribution License put the following SPDX tag/value pair into a comment according to the placement guidelines in the licensing rules documentation: SPDX-License-Identifier: BSD-Source-Code License-Text: Copyright (c) . All rights reserved. Redistribution and use of this software in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/LICENSES/preferred/GFDL-1.2 ================================================ Valid-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later Valid-License-Identifier: GFDL-1.2-no-invariants-or-later SPDX-URL: https://spdx.org/licenses/GFDL-1.2-no-invariants-or-later.html Usage-Guide: The GNU Free Documentation License should only be used without Invariant Sections, Front-Cover Texts or Back-Cover Texts. It should not be used for new documents. To use the license in source code, put the following SPDX tag/value pair into a comment according to the placement guidelines in the licensing rules documentation: SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later or SPDX-License-Identifier: GFDL-1.2-no-invariants-or-later License-Text: GNU Free Documentation License Version 1.2, November 2002 Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. C. State on the Title page the name of the publisher of the Modified Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section. O. Preserve any Warranty Disclaimers. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements". 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See https://www.gnu.org/licenses/. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright (c) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the "with...Texts." line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/LICENSES/preferred/GPL-2.0 ================================================ Valid-License-Identifier: GPL-2.0 Valid-License-Identifier: GPL-2.0-only Valid-License-Identifier: GPL-2.0-or-later SPDX-URL: https://spdx.org/licenses/GPL-2.0.html Usage-Guide: To use this license in source code, put one of the following SPDX tag/value pairs into a comment according to the placement guidelines in the licensing rules documentation. For 'GNU General Public License (GPL) version 2 only' use: SPDX-License-Identifier: GPL-2.0 or SPDX-License-Identifier: GPL-2.0-only For 'GNU General Public License (GPL) version 2 or any later version' use: SPDX-License-Identifier: GPL-2.0-or-later License-Text: GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/LICENSES/preferred/MIT ================================================ Valid-License-Identifier: MIT SPDX-URL: https://spdx.org/licenses/MIT.html Usage-Guide: To use the MIT License put the following SPDX tag/value pair into a comment according to the placement guidelines in the licensing rules documentation: SPDX-License-Identifier: MIT License-Text: MIT License Copyright (c) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/LICENSES/preferred/gfdl-1.2.texi.readme ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later The texinfo version of the license gfdl-1.2 is distributed in the file doc/fdl.texi . ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/LICENSES/stand-alone/GPL-3.0 ================================================ Valid-License-Identifier: GPL-3.0 Valid-License-Identifier: GPL-3.0-only Valid-License-Identifier: GPL-3.0-or-later SPDX-URL: https://spdx.org/licenses/GPL-3.0.html Usage-Guide: To use this license in source code, put one of the following SPDX tag/value pairs into a comment according to the placement guidelines in the licensing rules documentation. For 'GNU General Public License (GPL) version 3 only' use: SPDX-License-Identifier: GPL-3.0 or SPDX-License-Identifier: GPL-3.0-only For 'GNU General Public License (GPL) version 3 or any later version' use: SPDX-License-Identifier: GPL-3.0-or-later License-Text: GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # not a GNU package. You can remove this line, if # have all needed files, that a GNU package needs AUTOMAKE_OPTIONS = gnu 1.6 .DELETE_ON_ERROR: # make sure we pass the correct jimtcl flags to distcheck DISTCHECK_CONFIGURE_FLAGS = --disable-install-jim # do not run Jim Tcl tests (esp. during distcheck) check-recursive: SUBDIRS := nobase_dist_pkgdata_DATA = \ contrib/libdcc/dcc_stdio.c \ contrib/libdcc/dcc_stdio.h \ contrib/libdcc/example.c \ contrib/libdcc/README \ contrib/60-openocd.rules SUBDIRS = DIST_SUBDIRS = bin_PROGRAMS = noinst_LTLIBRARIES = info_TEXINFOS = dist_man_MANS = EXTRA_DIST = DISTCLEANFILES = if INTERNAL_JIMTCL SUBDIRS += jimtcl DIST_SUBDIRS += jimtcl EXTRA_DIST += jimtcl/configure.gnu # jimtcl from 0.79 to 0.82 miss cleaning jsmn.o DISTCLEANFILES += jimtcl/jsmn/jsmn.o endif # common flags used in openocd build AM_CFLAGS = $(GCC_WARNINGS) AM_CPPFLAGS = $(HOST_CPPFLAGS)\ -I$(top_srcdir)/src \ -I$(top_builddir)/src \ -DPKGDATADIR=\"$(pkgdatadir)\" \ -DBINDIR=\"$(bindir)\" if INTERNAL_JIMTCL AM_CPPFLAGS += -I$(top_srcdir)/jimtcl \ -I$(top_builddir)/jimtcl endif EXTRA_DIST += \ BUGS \ HACKING \ NEWTAPS \ README.Windows \ README.macOS \ $(EXTRA_DIST_NEWS) \ Doxyfile.in \ LICENSES/license-rules.txt \ LICENSES/exceptions/eCos-exception-2.0 \ LICENSES/preferred/BSD-1-Clause \ LICENSES/preferred/BSD-2-Clause \ LICENSES/preferred/BSD-2-Clause-Views \ LICENSES/preferred/BSD-3-Clause \ LICENSES/preferred/BSD-Source-Code \ LICENSES/preferred/GFDL-1.2 \ LICENSES/preferred/gfdl-1.2.texi.readme \ LICENSES/preferred/GPL-2.0 \ LICENSES/preferred/MIT \ LICENSES/stand-alone/GPL-3.0 \ tools/logger.pl \ tools/rlink_make_speed_table \ tools/st7_dtc_as \ contrib libtool: $(LIBTOOL_DEPS) $(SHELL) ./config.status --recheck docs: pdf html doxygen Doxyfile: $(srcdir)/Doxyfile.in @echo "Creating $@ from $<..." @( \ echo "### @@@ -= DO NOT EDIT THIS FILE =- @@@ ###" && \ echo "### @@@ Make changes to Doxyfile.in @@@ ###" && \ sed -e 's,@srcdir\@,$(srcdir),' \ -e 's,@builddir\@,$(builddir),' \ -e 's,@doxygen_as_html\@,$(doxygen_as_html),' \ -e 's,@doxygen_as_pdf\@,$(doxygen_as_pdf),' $< \ ) > $@ THE_MANUAL = doxygen/latex/refman.pdf doxygen:: $(MAKE) Doxyfile doxygen Doxyfile 2>&1 | perl $(srcdir)/tools/logger.pl > doxygen.log @if [ -f doxygen/latex/refman.tex ]; then \ echo "Creating $(THE_MANUAL)..."; \ $(MAKE) $(THE_MANUAL); \ else \ echo "Skipping Doxygen PDF..."; \ fi $(THE_MANUAL): %.pdf: %.tex -cd $$(dirname $*) && pdflatex $$(basename $*) -cd $$(dirname $*) && pdflatex $$(basename $*) TCL_PATH = tcl # command to find paths of script files, relative to TCL_PATH TCL_FILES = find $(srcdir)/$(TCL_PATH) -name '*.cfg' -o -name '*.tcl' -o -name '*.txt' | \ sed -e 's,^$(srcdir)/$(TCL_PATH),,' dist-hook: if test -d $(srcdir)/.git -a \( ! -e $(distdir)/ChangeLog -o -w $(distdir)/ChangeLog \) ; then \ git --git-dir $(srcdir)/.git log | $(srcdir)/tools/git2cl/git2cl > $(distdir)/ChangeLog ; \ fi for i in $$($(TCL_FILES)); do \ j="$(distdir)/$(TCL_PATH)/$$i" && \ mkdir -p "$$(dirname $$j)" && \ $(INSTALL_DATA) $(srcdir)/$(TCL_PATH)/$$i $$j; \ done install-data-hook: for i in $$($(TCL_FILES)); do \ j="$(DESTDIR)$(pkgdatadir)/scripts/$$i" && \ mkdir -p "$$(dirname $$j)" && \ $(INSTALL_DATA) $(srcdir)/$(TCL_PATH)/$$i $$j; \ done uninstall-hook: rm -rf $(DESTDIR)$(pkgdatadir)/scripts distclean-local: rm -rf Doxyfile doxygen -rm -f $(srcdir)/jimtcl/configure.gnu DISTCLEANFILES += doxygen.log METASOURCES = AUTO BUILT_SOURCES = CLEANFILES = MAINTAINERCLEANFILES = \ %D%/INSTALL \ %D%/configure \ %D%/Makefile.in \ %D%/depcomp \ %D%/config.guess \ %D%/config.sub \ %D%/config.h.in \ %D%/config.h.in~ \ %D%/compile \ %D%/ltmain.sh \ %D%/missing \ %D%/aclocal.m4 \ %D%/install-sh \ %D%/texinfo.tex include src/Makefile.am include doc/Makefile.am ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/NEWS ================================================ This file includes highlights of the changes made in the OpenOCD source archive release. JTAG Layer: Boundary Scan: Target Layer: Flash Layer: Board, Target, and Interface Configuration Scripts: Server Layer: RTOS: Documentation: Build and Release: This release also contains a number of other important functional and cosmetic bugfixes. For more details about what has changed since the last release, see the git repository history: http://sourceforge.net/p/openocd/code/ci/v0.x.0/log/?path= For older NEWS, see the NEWS files associated with each release (i.e. NEWS-). For more information about contributing test reports, bug fixes, or new features and device support, please read the new Developer Manual (or the BUGS and PATCHES.txt files in the source archive). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/NEWS-0.10.0 ================================================ This file includes highlights of the changes made in the OpenOCD source archive release. JTAG Layer: * New driver for J-Link adapters based on libjaylink (including support for FPGA configuration, SWO and EMUCOM) * FTDI improvements to work at 30MHz clock * BCM2835 native driver SWD and Raspberry Pi2 support * BCM2835 is set to 4ma drive, slow slew rate * ixo-usb-jtag (emulation of an Altera Bus Blaster I on Cypress FX2 IC) support * JTAG pass-through mode for CMSIS-DAP (including support for FPGA configuration) * OpenJTAG support for Cypress CY7C65215 * connect_assert_srst support for SWD * Xilinx Virtex-II Series7 bitstream loading support * Use JEP106 data to decode IDs * Deprecated "ft2232" driver removed (use "ftdi" instead) * GPL-incompatible FTDI D2XX library support dropped (Presto, OpenJTAG and USB-Blaster I are using libftdi only now) * ZY1000 support dropped (unmaintained since long) * oocd_trace support dropped Boundary Scan: Target Layer: * ARMv7-A, Cortex-M, Cortex-A/R important fixes and improvements (allowing e.g. simultaneous debugging of A8 and M3 cores, JTAG WAIT support etc.) * ARM Cortex-A,R allow interrupt disable during single-step (maskisr command) * Semihosting support for ARMv7-A * ARM Cortex-M7 support * Intel Quark mcu D2000 support * Freescale LS102x SAP support * ThreadX RTOS support on ARM926E-JS * Cortex-M RTOS stack alignment fixes * FreeRTOS FPU support * uC/OS-III RTOS support * bridging semihosting to GDB's File-I/O support * -defer-examine option added to target create command * verify_image_checksum command added Flash Layer: * Atmel SAM4S, SAM4N, SAM4C support * Atmel SAMV, SAMS, SAME (Cortex-M7) support * Atmel AT91SAMD handle reset run/halt in DSU, other fixes * Atmel AT91SAML21, SAML22, SAMC20/SAMC21, SAMD09 support * ST STM32F4x support * ST STM32F74x/76x/77x, STM32L4 support * ST STM32L0 categories 1, 2 and 5 support * Kinetis K02, K21, K22, K24, K26, K63, K64, K66 support * Kinetis KE, KVx, K8x families support * Kinetis FlexNVM handling * Kinetis flash protection, security, mass_erase improvements * Infineon XMC4xxx family support * Infineon XMC1000 flash driver * Energy Micro EFM32 Happy Gecko support * Energy Micro EFM32 debug interface lock support * Analog Devices ADuCM360 support * Unified Nuvoton NuMicro flash driver * NIIET K1921VK01T (Cortex-M4) support * Nordic Semiconductor nRF51 improvements * Spansion FM4 flash (including MB9BFx64/x65, S6E2DH) driver * Ambiq Micro Apollo flash driver * PIC32MX new device IDs, 17x/27x flash support * read_bank() and verify_bank() NOR flash internal API to allow reading (and verifying) non-memory-mapped devices * JTAGSPI driver to access SPI NOR flashes via a trivial FPGA proxy * Milandr read/verify for Info memory support * Various discrete SPI NOR flashes support * CFI 16-bit flash reversed endianness support Board, Target, and Interface Configuration Scripts: * Digilent JTAG-HS2, JTAG-HS3 interfaces configs * FTDI UM232H module as JTAG interface config * 100ask's OpenJTAG interface config * MBFTDI interface config * XDS100v3 interface config * Freescale Vybrid VF6xx target config * EmCraft VF6 SOM and baseboard configs * Freescale SabreSD board config * Freescale VF65GS10 tower board config * Pipistrello Xilinx Spartan6 LX45 FPGA board config * miniSpartan6+ board config * Xilinx Kintex7 Development board config * Parallella-I board config * Digilent Atlys and Analog Discovery board configs * Numato Opsis board config * Xilinx Spartan 6 FPGA "Device DNA" reading support * Altera 10M50 FPGA (MAX10 family) target config * Altera EPM240 CPLD (MAXII family) target config * Marsohod2, Marsohod3 FPGA, Marsohod CPLD boards configs * Novena's integrated FPGA board config * XMOS XS1-XAU8A-10's ARM core config * XMOS xCORE-XA Core Module board config * Exynos5250 target config * Arndale board config * FM4 MB9BFxxx family configs * Spansion SK-FM4-U120-9B560 board config * Diolan LPC4357-DB1 board config * ST STM32F469 discovery board config * ST STM32F7-DISCO, STM327[4|5]6G-EVAL boards configs * ST STM32L4 discovery, NUCLEO L476RG, STM32F429I-DISC1 boards configs * Atheros AR2313, AR2315 targets config * Netgear WP102 board config * La Fonera FON2200 board config * Linksys WAG200G board config * LPC-Link2 board config * NXP LPC4370 target config * Atmel SAMV, SAMS, SAME target configs * Atmel SAM E70 Xplained, SAM V71 Xplained Ultra boards configs * Nordic nRF52 target config * Nordic nRF51-DK, nRF52-DK boards configs * Infineon XMC4700 Relax Kit, XMC4800 Relax EtherCAT Kit, XMC4300 Relax EtherCAT Kit boards configs * Renesas S7G2 target config * Renesas DK-S7G2 board config * Altera EP3C10 FPGA (Cyclone III family) target config * TI MSP432P4xx target config * Cypress PSoC 5LP target config * Analog Devices ADSP-SC58x target config (Cortex-A5 core only) Server Layer: * tcl_trace command for async target trace output via Tcl RPC Documentation: Build and Release: * Various fixes thanks to http://coccinellery.org/ * libftdi is now autodetected with pkgconfig * Releases should now support reproducible builds * Conversion to non-recursive make, requires automake >= 1.14 * Udev rules modified to add uaccess tag and moved to 60-openocd.rules * Support searching for scripts relative to the openocd binary for all major architectures This release also contains a number of other important functional and cosmetic bugfixes. For more details about what has changed since the last release, see the git repository history: http://sourceforge.net/p/openocd/code/ci/v0.10.0/log/?path= For older NEWS, see the NEWS files associated with each release (i.e. NEWS-). For more information about contributing test reports, bug fixes, or new features and device support, please read the new Developer Manual (or the BUGS and PATCHES.txt files in the source archive). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/NEWS-0.11.0 ================================================ This file includes highlights of the changes made in the OpenOCD source archive release. JTAG Layer: * add debug level 4 for verbose I/O debug * bitbang, add read buffer to improve performance * Cadence SystemVerilog Direct Programming Interface (DPI) adapter driver * CMSIS-DAP v2 (USB bulk based) adapter driver * Cypress KitProg adapter driver * FTDI FT232R sync bitbang adapter driver * Linux GPIOD bitbang adapter driver through libgpiod * Mellanox rshim USB or PCIe adapter driver * Nuvoton Nu-Link and Nu-Link2 adapter drivers * NXP IMX GPIO mmap based adapter driver * ST-Link consolidate all versions in single config * ST-Link read properly old USB serial numbers * STLink/V3 support (for ST devices only !) * STM8 SWIM transport * TI XDS110 adapter driver * Xilinx XVC/PCIe adapter driver Boundary Scan: Target Layer: * 64 bit address support * ARCv2 target support * ARM Cortex-A hypervisor mode support * ARM Cortex-M fast PC sampling support for profiling * ARM generic CTI support * ARM generic mem-ap target support * ARMv7-A MMU tools * ARMv7m traces add TCP stream server * ARMv8 AARCH64 target support and semihosting support * ARMv8 AARCH64 disassembler support through capstone library * ARMv8-M target support * EnSilica eSi-RISC target support, including instruction tracing eSi-Trace support * MIPS64 target support * Motorola SREC S6 record image file support * RISC-V target support * SEGGER Real Time Transfer (RTT) initial support (for single target, Cortex-M only) * ST STM8 target support * Various MIPS32 target improvements Flash Layer: * Atheros (ath79) SPI interface support * Atmel atmega128rfa1 support * Atmel SAM D21, D51, DA1, E51, E53, E54, G55, R30 support * Atmel SAMC2?N* support * Cypress PSoC5LP, PSoC6 support * EnSilica eSi-RISC support * Foshan Synwit Tech SWM050 support * Maxim Integrated MAX32XXX support * Nordic Semiconductor nRF51822, nRF52810, nRF52832 support * NXP Kinetis K27, K28, KE1x, KEAx, KL28, KL8x, KV5x, KWx support * Renesas RPC HF support * SH QSPI support * SiFive Freedom E support * Silicon Labs EFR-family, EZR32HG support * ST BlueNRG support * ST STM32 QUAD/OCTO-SPI interface support for Flash, FRAM and EEPROM * ST STM32F72x, STM32F4x3, STM32H7xx support * ST STM32G0xx, STM32G4xx, STM32L4x, STM32WB, STM32WL support * ST STM32L5x support (non secure mode) * TI CC13xx, CC26xx, CC32xx support * TI MSP432 support * Winner Micro w600 support * Xilinx XCF platform support * Various discrete SPI NOR flashes support Board, Target, and Interface Configuration Scripts: * 8devices LIMA board config * Achilles Instant-Development Kit Arria 10 board config * Amazon Kindle 2 and DX board config * Analog Devices ADSP-SC58x, ADSP-SC584-EZBRD board config * Andes Technology ADP-XC7KFF676 board config * Andes Technology Corvette-F1 board config * ARM Musca A board config * Arty Spartan 7 FPGA board config * Atmel SAMD10 Xplained mini board config * Atmel SAMD11 Xplained Pro board config * Atmel SAM G55 Xplained Pro board config * AVNET UltraZED EG StarterKit board config * Blue Pill STM32F103C8 board config * DP Busblaster v4.1a board config * DPTechnics DPT-Board-v1 board config * Emcraft imx8 SOM BSB board config * Globalscale ESPRESSObin board config * Kasli board config * Kintex Ultrascale XCKU040 board config * Knovative KC-100 board config * LeMaker HiKey board config * Microchip (Atmel) SAME54 Xplained Pro board config * Microchip (Atmel) SAML11 Xplained Pro board config * Nordic module NRF52 board config * Numato Lab Mimas A7 board config * NXP Freedom FRDM-LS1012A board config * NXP IMX7SABRE board config * NXP IMX8MP-EVK board config * NXP MC-IMX8M-EVK board config * QuickLogic QuickFeather board config * Renesas R-Car E2, H2, M2 board config * Renesas R-Car Salvator-X(S) board config * Renesas RZ/A1H GR-Peach board config * Rigado BMD-300 board config * Sayma AMC board config * Sifive e31arty, e51arty, hifive1 board config * ST B-L475E-IOT01A board config * ST BlueNRG idb007v1, idb008v1, idb011v1 board config * ST STM32F412g discovery board config * ST STM32F413h discovery board config * ST STM32F469i discovery board config * ST STM32F7 Nucleo board config * ST STM32F723e discovery board config * ST STM32F746g discovery board config * ST STM32F769i discovery board config * ST STM32H735g discovery board config * ST STM32H743zi Nucleo board config * ST STM32H745i discovery board config * ST STM32H747i discovery board config * ST STM32H750b discovery board config * ST STM32H7b3i discovery board config * ST STM32H7x_dual_qspi board config * ST STM32H7x3i Eval boards config * ST STM32L073 Nucleo board config * ST STM32L476g discovery board config * ST STM32L496g discovery board config * ST STM32L4p5g discovery board config * ST STM32L4r9i discovery board config * ST STM32L5 Nucleo board config * ST STM32MP15x DK2 board config * ST STM32WB Nucleo board config * ST STM8L152R8 Nucleo board config * Synopsys DesignWare ARC EM board config * Synopsys DesignWare ARC HSDK board config * TI BeagleBone family boards config * TI CC13xx, CC26xx, CC32xx LaunchPad board config * TI MSP432 LaunchPad board config * Tocoding Poplar board config * TP-Link WDR4300 board config * Allwinner V3s target config * Andes Technology NDS V5 target config * Atmel atmega128rfa1 target config * ARM corelink SSE-200 target config * Atheros_ar9344 target config * Cypress PSoC5LP, PSoC6 target config * EnSilica eSi-RISC target config * Foshan Synwit Tech SWM050 target config * GigaDevice GD32VF103 target config * Hisilicon Hi3798 target config * Hisilicon Hi6220 target config * Infineon TLE987x target config * Marvell Armada 3700 target config * Maxim Integrated MAX32XXX target config * Mellanox BlueField target config * Microchip (Atmel) SAME5x, SAML1x target config * NXP IMX6SX, IMX6UL, IMX7, IMX7ULP, IMX8 target config * NXP Kinetis KE1xZ, KE1xF target config * NXP LPC84x, LPC8Nxx, LS1012A, NHS31xx target config * Qualcomm QCA4531 target config * QuickLogic EOS S3 target config * Renesas R-Car E2, H2, M2 target config * Renesas R-Car Gen3 target config * Renesas RZ/A1H target config * Rockchip RK3308 target config * ST BlueNRG target config * ST STM32G0, STM32G4, STM32H7, STM32L0, STM32L5 target config * ST STM32MP15x target config * ST STM32WBx, STM32WLEx target config * ST STM8L152, S003, S103, S105 target config * Synopsys DesignWare ARC EM target config * Synopsys DesignWare ARC HS Development Kit SoC target config * TI CC13xx, CC26xx, CC32xx target config * TI TNETC4401 target config * Xilinx UltraScale+ target config * Altera 5M570Z (MAXV family) CPLD config * Xilinx Ultrascale, XCF CPLD config * Intel (Altera) Arria10 FPGA config * Cadence SystemVerilog Direct Programming Interface (DPI) interface config * Cypress KitProg interface config * Digilent SMT2 NC interface config * DLN-2 example of Linux GPIOD interface config * FTDI C232HM interface config * HIE JTAG Debugger interface config * In-Circuit's ICprog interface config * isodebug isolated JTAG/SWD+UART interface config * Mellanox rshim USB or PCIe interface config * Nuvoton Nu-Link interface config * NXP IMX GPIO mmap based interface config * Steppenprobe open hardware interface config * TI XDS110 interface config Server Layer: * 64 bit address support * default bind to IPv4 localhost * gdb: allow multiple connections * gdb: architecture element support * gdb: vCont, vRun support * telnet: handle Ctrl+A, Ctrl+E and Ctrl+K RTOS: * Chromium-EC rtos support * hwthread pseudo rtos support * NuttX rtos support * RIOT rtos support Documentation: * Improve STM32 flash driver * Various typo fix and improvements Build and Release: * Add libutil to support jimtcl version 0.80 * Clang warning fixes * GitHub workflow for Win32 snapshot binaries * Handle Tcl return values consistently * Mitigation for CVE-2018-5704: Prevent some forms of Cross Protocol Scripting attacks * Support for libftdi 1.5 * Travis-CI basic support * Update libjaylink to version 0.2.0 * Update jimtcl to version 0.79 * Use external (optional) library capstone for ARM and AARCH64 disassembly This release also contains a number of other important functional and cosmetic bugfixes. For more details about what has changed since the last release, see the git repository history: http://sourceforge.net/p/openocd/code/ci/v0.11.0/log/?path= For older NEWS, see the NEWS files associated with each release (i.e. NEWS-). For more information about contributing test reports, bug fixes, or new features and device support, please read the new Developer Manual (or the BUGS and PATCHES.txt files in the source archive). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/NEWS-0.12.0 ================================================ This file includes highlights of the changes made in the OpenOCD source archive release. JTAG Layer: * add default to adapter speed when unspecified (100 kHz) * AM335X gpio (BeagleBones) adapter driver * BCM2835 support for SWD * Cadence Virtual Debug (vdebug) adapter driver * CMSIS-DAP support for SWO and SWD multidrop * Espressif USB JTAG Programmer adapter driver * Remote bitbang support for Windows host * ST-LINK add TCP server support to adapter driver * SWD multidrop support Boundary Scan: Target Layer: * aarch64: support watchpoints * arm: support independent TPIU and SWO for trace * arm adi v5: support Large Physical Address Extension * arm adi v6: support added, for jtag and swd transport * cortex_a: support watchpoints * elf 64bit load support * Espressif: support ESP32, ESP32-S2 and ESP32-S3 cores * semihosting: support user defined operations * Xtensa: support Xtensa LX architecture via JTAG and ADIv5 DAP Flash Layer: * Atmel/Microchip SAM E51G18A, E51G19A, R35J18B, LAN9255 support * GigaDevice GD32E23x, GD32F1x0/3x0, GD32VF103 support * Nuvoton NPCX series support * onsemi RSL10 support * Raspberry Pi Pico RP2040 support * ST BlueNRG-LPS support * ST STM32 G05x, G06x, G0Bx, G0Cx, U57x, U58x, WB1x, WL5x support * ST STM32 G0, G4, L4, L4+, L5, WB, WL OTP support Board, Target, and Interface Configuration Scripts: * Ampere Computing eMAG8180, Altra ("Quicksilver") and Altra Max ("Mystique") board config * Cadence KC705 FPGA (Xtensa Development Platform) via JTAG and ADIv5 DAP board config * Digilent Nexys Video board config * Espressif ESP32 ETHERNET-KIT and WROVER-KIT board config * Espressif ESP32 via ESP USB Bridge generic board config * Espressif ESP32-S2 Kaluga 1 board config * Espressif ESP32-S2 with ESP USB Bridge board config * Espressif ESP32-S3 example board config * Kontron SMARC-sAL28 board config * LambdaConcept ECPIX-5 board config * Microchip ATSAMA5D27-SOM1-EK1 board config * Microchip EVB-LAN9255 board config * Microchip SAME51 Curiosity Nano board config * NXP FRDM-K64F, LS1046ARDB and LS1088ARDB board config * NXP RT6XX board config * Olimex H405 board config * Radiona ULX3S board config * Raspberry Pi 3 and Raspberry Pi 4 model B board config * Raspberry Pi Pico-Debug board config * Renesas R-Car V3U Falcon board config * ST BlueNRG-LPS steval-idb012v1 board config * ST NUCLEO-8S208RB board config * ST NUCLEO-G031K8, NUCLEO-G070RB, NUCLEO-G071RB board config * ST NUCLEO-G431KB, NUCLEO-G431RB, NUCLEO-G474RE board config * ST STM32MP13x-DK board config * TI AM625 EVM, AM642 EVM and AM654 EVM board config * TI J721E EVM, J721S2 EVM and J7200 EVM board config * Ampere Computing eMAG, Altra ("Quicksilver") and Altra Max ("Mystique") target config * Cadence Xtensa generic and Xtensa VDebug target config * Broadcom BCM2711, BCM2835, BCM2836 and BCM2837 target config * Espressif ESP32, ESP32-S2 and ESP32-S3 target config * Microchip ATSAMA5D2 series target config * NanoXplore NG-Ultra SoC target config * NXP IMX8QM target config * NXP LS1028A, LS1046A and LS1088A target config * NXP RT600 (Xtensa HiFi DSP) target config * onsemi RSL10 target config * Raspberry Pi Pico RP2040 target config * Renesas R8A779A0 V3U target config * Renesas RZ/Five target config * Renesas RZ/G2 MPU family target config * Rockchip RK3399 target config * ST BlueNRG-LPS target config * ST STM32MP13x target config * TI AM625, AM654, J721E and J721S2 target config * Ashling Opella-LD interface config * Aspeed AST2600 linuxgpiod based interface config * Blinkinlabs JTAG_Hat interface config * Cadence Virtual Debug (vdebug) interface config * Espressif ESP32-S2 Kaluga 1 board's interface config * Espressif USB Bridge jtag interface config * Infineon DAP miniWiggler V3 interface config * PLS SPC5 interface config * Tigard interface config * Lattice MachXO3 family FPGA config Server Layer: * GDB: add per-target remote protocol extensions * GDB: more 'Z' packets support * IPDBG JtagHost server functionality * semihosting: I/O redirection to TCP server * telnet: support for command's autocomplete RTOS: * 'none' rtos support * Zephyr rtos support Documentation: Build and Release: * Add json extension to jimtcl build * Drop dependency from libusb0 * Drop repository repo.or.cz for submodules * Move gerrit to https://review.openocd.org/ * Require autoconf 2.69 or newer * Update jep106 to revision JEP106BF.01 * Update jimtcl to version 0.81 * Update libjaylink to version 0.3.1 * New configure flag '--enable-jimtcl-maintainer' for jimtcl build This release also contains a number of other important functional and cosmetic bugfixes. For more details about what has changed since the last release, see the git repository history: http://sourceforge.net/p/openocd/code/ci/v0.12.0/log/?path= For older NEWS, see the NEWS files associated with each release (i.e. NEWS-). For more information about contributing test reports, bug fixes, or new features and device support, please read the new Developer Manual (or the BUGS and PATCHES.txt files in the source archive). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/NEWS-0.2.0 ================================================ The OpenOCD 0.2.0 source archive release includes numerous improvements that were made since the initial 0.1.0 source archive release. Many contributors helped make this release a great success, and the community of developers and maintainers look forward to any response. In addition to the list of changes below, countless bug fixing and cleaning was performed across the tree. Various TCL command parameters must past stricter value checks, and many more error conditions have been handled correctly. These efforts helped to make the 0.2.0 release more stable and robust, though some changes may expose latent bugs in your existing configuration scripts. This release does not maintain backward compatibility in all respects, so some target or configuration scripts may need to be updated. In some cases, you may also see warnings; resolve those, because they indicate commands that will be removed in the future. The following areas of OpenOCD functionality changed in this release: JTAG Layer: - Improves modularity: core, TCL, driver commands, and interface have been separated, encapsulated, and documented for developers. Mostly. - Improves JTAG TAP transition tables: * Makes TAP paths variable length, rather than being fixed at 7 steps. * Fixes problems with some targets that did not like longer paths. - Improves JTAG driver/minidriver modularity and encapsulation. - New drivers: * Adds stub minidriver for developing new embedded JTAG interfaces. - Improves drivers: * ft2232+ftd2xx: + Adds initial high-speed device support: --enable-ftd2xx-highspeed + Supports more types of FTDI-based devices. * jlink: + Works with more versions of the firmware (v3 and newer) + Supports dynamically detects device capabilities and limits * vsllink: + Supports very long scan chains * amtjtagaccel: + Fixes broken ID code detection problems. Target Layer: - New devices: AVR, FA526 - Improved support: ARM ADI, ARM11, MIPS - Numerous other bug fixes and improvements Flash Layer: - Improved drivers: mflash - New drivers: AT91SAM3, AVR, Davinci NAND Board, Interface, and Target Configuration Scripts: - Many new and improved targets and boards are now available. - Better separation of "board" and "target" configuration - Moved all TCL files to top-level "tcl" directory in the source tree - Installation moved from '$pkglibdir/' to '$pkgdatadir/scripts/'. - Site-specific files should be installed under '$pkgdatadir/site/'; files that exist this tree will be used in preference to default distribution configurations in '$pkgdatadir/scripts/'. Documentation: - Updated User Guide: http://openocd.berlios.de/doc/html/index.html * Partially re-written and re-organized. * Standardized presentation for all commands. * Covers many drivers and commands that were previously omitted. * New index for commands and drivers. - Added Developer Manual: http://openocd.berlios.de/doc/doxygen/index.html * Now includes architecture, technical primers, style guides, and more. * Available in-tree and on-line. Build and Release: - Increased configuration and compilation warning coverage. * Use --disable-werror to work around build errors caused by warnings. - Use libtool to produce helper libraries as a step toward "libopenocd". - New processes and scripting to facilitate future source releases. For more details about what has changed since 0.1.0, see the ChangeLog associated with this release. For more information about contributing test reports, bug fixes, or new features and device support, please read the new Developer Manual (or the BUGS and PATCHES files in the source archive). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/NEWS-0.3.0 ================================================ This file should include highlights of the changes made in the OpenOCD openocd-0.3.0 source archive release. See the repository history for details about what changed, including bugfixes and other issues not mentioned here. JTAG Layer: FT2232H (high speed USB) support doesn't need separate configuration New FT2232H JTAG adapters: Amontec, Olimex, Signalyzer New reset_config options for SRST gating the JTAG clock (or not) TAP declaration no longer requires ircapture and mask attributes Scan chain setup should be more robust, with better diagnostics New TAP events: "post-reset" for TAP-invariant setup code (TAPs not usable yet) "setup" for use once TAPs are addressable (e.g. with ICEpick) Overridable Tcl "init_reset" and "jtag_init" procedures Simple "autoprobe" mechanism to help simplify server setup Boundary Scan: SVF bugfixes ... parsing fixes, better STATE switch conformance XSVF bugfixes ... be more correct, handle Xilinx tool output Target Layer: Warn on use of obsolete numeric target IDs New commands for use with Cortex-M3 processors: "cortex_m3 disassemble" ... Thumb2 disassembly (UAL format) "cortex_m3 vector_catch" ... traps certain hardware faults without tying up breakpoint resources If you're willing to help debug it VERY EARLY Cortex-A8 and ARMv7A support Updated BeagleBoard.org hardware support you may need to explicitly "reset" after connect-to-Beagle New commands for use with XScale processors: "xscale vector_table" ARM bugfixes to single-stepping Thumb code ETM: unavailable registers are not listed ETB, ETM: report actual hardware status ARM9 name change: "arm9 vector_catch" not "arm9tdmi vector_catch" ARM11 single stepping support for i.MX31 bugfix for missing "arm11" prefix on "arm11 memwrite ..." GDB support gdb_attach command is gone Flash Layer: The lpc2000 driver handles the new NXP LPC1700 (Cortex-M3) chips New drivers: lpc2900, for NXP LPC2900 chips (ARM968 based) mx3_nand, for imx31 New "last" flag for NOR "flash erase_sector" and "flash protect" The "nand erase N" command now erases all of bank N Speed up davinci_nand by about 3x Board, Target, and Interface Configuration Scripts: Amontec JTAGkey2 support Cleanup and additions for the TI/Luminary Stellaris scripts LPC1768 target (and flash) support Keil MCB1700 eval board Samsung s3c2450 Mini2440 board Numeric TAP and Target identifiers now trigger warnings PXA255 partially enumerates Documentation: Capture more debugging and setup advice Notes on target source code changes that may help debugging Build and Release: Repository moved from SVN at Berlios to GIT at SourceForge Clean builds on (32-bit) Cygwin Clean builds on 64-bit MinGW For more details about what has changed since the last release, see the git repository history. With gitweb, you can browse that in various levels of detail. For older NEWS, see the NEWS files associated with each release (i.e. NEWS-). For more information about contributing test reports, bug fixes, or new features and device support, please read the new Developer Manual (or the BUGS and PATCHES files in the source archive). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/NEWS-0.4.0 ================================================ This file includes highlights of the changes made in the OpenOCD 0.4.0 source archive release. See the repository history for details about what changed, including bugfixes and other issues not mentioned here. JTAG Layer: Support KT-Link JTAG adapter. Support USB-JTAG, Altera USB-Blaster and compatibles. Boundary Scan: Target Layer: General - Removed commands which have been obsolete for at least a year (from both documentation and, sometimes, code). - new "reset-assert" event, for systems without SRST ARM - supports "reset-assert" event (except on Cortex-M3) - renamed "armv4_5" command prefix as "arm" - recognize TrustZone "Secure Monitor" mode - "arm regs" command output changed - register names use "sp" not "r13" - add top-level "mcr" and "mrc" commands, replacing various core-specific operations - basic semihosting support (ARM7/ARM9 only, for now) ARM11 - Should act much more like other ARM cores: * Preliminary ETM and ETB hookup * accelerated "flash erase_check" * accelerated GDB memory checksum * support "arm regs" command * can access all core modes and registers * watchpoint support - Shares some core debug code with Cortex-A8 Cortex-A8 - Should act much more like other ARM cores: * support "arm regs" command * can access all core modes and registers * watchpoint support - Shares some core debug code with ARM11 Cortex-M3 - Exposed DWT registers like cycle counter - vector_catch settings not clobbered by resets - no longer interferes with firmware's fault handling ETM, ETB - "trigger_percent" command moved ETM --> ETB - "etm trigger_debug" command added MIPS - use fastdata writes Freescale DSP563xx cores (partial support) Flash Layer: 'flash bank' and 'nand device' take as first argument. With this, flash/NAND commands allow referencing banks by name: - : reference the bank with its defined name - [.N]: reference the driver's Nth bank New 'nand verify' command to check bank against an image file. The "flash erase_address" command now rejects partial sectors; previously it would silently erase extra data. If you want to erase the rest of the first and/or last sectors instead of failing, you must pass an explicit "pad" flag. New at91sam9 NAND controller driver. New s3c64xx NAND controller driver. Board, Target, and Interface Configuration Scripts: ARM9 - ETM and ETB hookup for iMX2* targets Add $HOME/.openocd to the search path. Handle Rev C of LM3S811 eval boards. - use "luminary-lm3s811.cfg" for older boards - use "luminary.cfg" for RevC and newer Core Jim/TCL Scripting: New 'usage' command to provide terse command help. Improved command 'help' command output (sorted and indented). Improved command handling: - Most boolean settings now accept any of the following: on/off, enable/disable, true/false, yes/no, 1/0 - More error checking and reporting. Documentation: New built-in command development documentation and primer. Build and Release: Use --enable-doxygen-pdf to build PDF developer documentation. Consider upgrading to libftdi 0.17 if you use that library; it includes bugfixes which improve FT2232H support. For more details about what has changed since the last release, see the git repository history. With gitweb, you can browse that in various levels of detail. For older NEWS, see the NEWS files associated with each release (i.e. NEWS-). For more information about contributing test reports, bug fixes, or new features and device support, please read the new Developer Manual (or the BUGS and PATCHES.txt files in the source archive). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/NEWS-0.5.0 ================================================ This file includes highlights of the changes made in the OpenOCD 0.5.0 source archive release. See the repository history for details about what changed, including bugfixes and other issues not mentioned here. JTAG Layer: New driver for "Bus Pirate" Rename various commands so they're not JTAG-specific There are migration procedures for most of these, but you should convert your scripts to the new names, since those procedures will not be around forever. jtag jinterface ... is now adapter_name jtag_khz ... is now adapter_khz jtag_nsrst_delay ... is now adapter_nsrst_delay jtag_nsrst_assert_width ... is now adapter_nsrst_assert_width Support Voipac VPACLink JTAG Adapter. Boundary Scan: Transport framework core ... supporting future work for SWD, SPI, and other non-JTAG ways to debug targets or program flash. Target Layer: ARM: - basic semihosting support for ARMv7M. - renamed "armv7m" command prefix as "arm" MIPS: - "ejtag_srst" variant removed. The same functionality is obtained by using "reset_config none". - added PIC32MX software reset support, this means srst is not required to be connected anymore. OTHER: - preliminary AVR32 AP7000 support. Flash Layer: New "stellaris recover" command, implements the procedure to recover locked devices (restoring non-volatile state to the factory defaults, including erasing the flash and its protection bits, and possibly re-enabling hardware debugging). PIC32MX now uses algorithm for flash programming, this has increased the performance by approx 96%. New 'pic32mx unlock' cmd to remove readout protection. New STM32 Value Line Support. New 'virtual' flash driver, used to associate other addresses with a flash bank. See pic32mx.cfg for usage. New iMX27 NAND flash controller driver. Board, Target, and Interface Configuration Scripts: Support IAR LPC1768 kickstart board (by Olimex) Support Voipac PXA270/PXA270M module. New $PARPORTADDR tcl variable used to change default parallel port address used. Remove lm3s811.cfg; use "stellaris.cfg" instead Core Jim/TCL Scripting: New "add_script_search_dir" command, behaviour is the same as the "-s" cmd line option. Documentation: Build and Release: For more details about what has changed since the last release, see the git repository history. With gitweb, you can browse that in various levels of detail. For older NEWS, see the NEWS files associated with each release (i.e. NEWS-). For more information about contributing test reports, bug fixes, or new features and device support, please read the new Developer Manual (or the BUGS and PATCHES.txt files in the source archive). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/NEWS-0.6.0 ================================================ This file includes highlights of the changes made in the OpenOCD source archive release. See the repository history for details about what changed, including bugfixes and other issues not mentioned here. JTAG Layer: New STLINK V1/V2 JTAG/SWD adapter support. New OSJTAG adapter support. New Tincantools Flyswatter2 support. Improved ULINK driver. Improved RLINK driver. Support for adapters based on FT232H chips. New experimental driver for FTDI based adapters, using libusb-1.0 in asynchronous mode. Boundary Scan: Target Layer: New Cortex-M0 support. New Cortex-M4 support. Improved Working area algorithm. New RTOS support. Currently linux, FreeRTOS, ThreadX and eCos. Connecting under reset to Cortex-Mx and MIPS chips. Flash Layer: New SST39WF1601 support. New EN29LV800BB support. New async algorithm support for selected targets, stm32, stellaris and pic32. New Atmel SAM3S, SAM3N support. New ST STM32L support. New Microchip PIC32MX1xx/2xx support. New Freescale Kinetis K40 support. Board, Target, and Interface Configuration Scripts: Support Dangerous Prototypes Bus Blaster. Support ST SPEAr Family. Support Gumstix Verdex boards. Support TI Beaglebone. Documentation: Improved HACKING info for submitting patches. Fixed numerous broken links. Build and Release: For more details about what has changed since the last release, see the git repository history. With gitweb, you can browse that in various levels of detail. For older NEWS, see the NEWS files associated with each release (i.e. NEWS-). For more information about contributing test reports, bug fixes, or new features and device support, please read the new Developer Manual (or the BUGS and PATCHES.txt files in the source archive). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/NEWS-0.7.0 ================================================ This file includes highlights of the changes made in the OpenOCD source archive release. See the repository history for details about what changed, including bugfixes and other issues not mentioned here. JTAG Layer: New TI ICDI adapter support. Support Latest OSBDM firmware. Improved MIPS EJTAG Support. Boundary Scan: Target Layer: New ARMv7R and Cortex-R4 support. Added ChibiOS/RT support. Flash Layer: New NXP LPC1850 support. New NXP LPC4300 support. New NXP SPIFI support. New Energy Micro EFM32 support. New ST STM32W support. New ST STM32f2 write protection and lock/unlock support. Ability to override STM32 flash bank size. Board, Target, and Interface Configuration Scripts: Support Freescale i.MX6 series targets. Documentation: New MIPS debugging info. Build and Release: For more details about what has changed since the last release, see the git repository history. With gitweb, you can browse that in various levels of detail. For older NEWS, see the NEWS files associated with each release (i.e. NEWS-). For more information about contributing test reports, bug fixes, or new features and device support, please read the new Developer Manual (or the BUGS and PATCHES.txt files in the source archive). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/NEWS-0.8.0 ================================================ This file includes highlights of the changes made in the OpenOCD source archive release. JTAG Layer: * New CMSIS-DAP driver * Andes AICE debug adapter support * New OpenJTAG driver * New BCM2835 (RaspberryPi) driver * JTAG VPI client driver (for OpenRISC Reference Platform SoC) * Xilinx BSCAN_* for OpenRISC support * ST-LINKv2-1 support * ST-LINKv2 SWO tracing support (UART emulation) * JLink-OB (onboard) support * Altera USB Blaster driver rewrite, initial Blaster II support * ULINK driver ported to libusb-1.0, OpenULINK build fixes * Support up to 64 bit IR lengths * SVF playback (FPGA programming) fixes * "ftdi" interface driver got extensive testing and is now recommended over the old ft2232 implementation Boundary Scan: Target Layer: * New target: Andes nds32 * New target: OpenRISC OR1K * New target: Intel Quark X10xx * MIPS EJTAG 1.5/2.0 support * MIPS speed improvements * Cortex-M, Cortex-A (MEM-AP, APB-AP) targets working with BE hosts now * XScale vector_catch support, reset fixes * dsp563xx ad-hoc breakpoint/watchpoint support * RTOS support for embKernel * Target profiling improvements * Memory access functions testbench Flash Layer: * STM32 family sync with reference manuals, other bugfixes * STM32F401, STM32F07x support * Atmel SAM4L, SAMG5x support * at91sam3sd8{a,b}, at91sam3s8{a,b,c}, at91sam4s, at91sam3n0{a,b,0a,0b} support, bugfixes * Atmel SAMD support * Milandr 1986ВЕ* support * Kinetis KL, K21 support * Nuvoton NuMicro MINI5{1,2,4} support * Nuvoton NUC910 series support * NXP LPC43xx, LPC2000 fixes * NXP LPC800, LPC810 support * More ATmega parts supported * Fujitsu MB9Ax family support * EFM32 Wonder Gecko family support * Nordic nRF51 support Board, Target, and Interface Configuration Scripts: * STM32W108xx generic target config * STM32F429 discovery board config * STM32 Nucleo boards configs * DENX M53EVK board config * Altera Cyclone V SoC, SoCkit config * New TI Launchpads board configs * TI am43xx devices, AM437x GP EVM, AM438x ePOS EVM board configs * Marvell Armada 370 family initial support * TI TMDX570LS31USB (TMS570, Cortex-R4) support scripts * Freescale FRDM-KL25Z, KL46Z board configs * Digilent Zedboard config * Asus RT-N16, Linksys WRT54GL, BT HomeHub board configs * Atmel Xplained initial support * Broadcom bcm28155_ap board config * TUMPA, TUMPA Lite interface configs * Digilent JTAG-SMT2 interface config * New RAM testing functions * Easy-to-use firmware recovery helpers targetting ordinary users with common equipment Server Layer: * Auto-generation of GDB target description for ARMv7-M, ARM4, nds32, OR1K, Quark * GDB File-I/O Remote Protocol extension support * Default GDB flashing events handlers to initialise and reset the target automatically when "load" is used Documentation: * Extensive README* changes * The official User's Guide was proofread * Example cross-build script * RTOS documentation improvements * Tcl RPC documentation and examples added Build and Release: * *BSD, OS X, clang, ARM, windows build fixes * New pkg-config support changes the way libusb (and other dependencies) are handled. Many adapter drivers are now selected automatically during the configure stage. This release also contains a number of other important functional and cosmetic bugfixes. For more details about what has changed since the last release, see the git repository history: http://sourceforge.net/p/openocd/code/ci/v0.8.0/log/?path= For older NEWS, see the NEWS files associated with each release (i.e. NEWS-). For more information about contributing test reports, bug fixes, or new features and device support, please read the new Developer Manual (or the BUGS and PATCHES.txt files in the source archive). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/NEWS-0.9.0 ================================================ This file includes highlights of the changes made in the OpenOCD source archive release. JTAG Layer: * SWD support with FTDI, Versaloon, J-Link, sysfsgpio * CMSIS-DAP massive speed and stability improvements * Versaloon driver ported to libusb-1.0 * STLink can reestablish communication with a target that was disconnected or rebooted * STLink FAULT and WAIT SWD handling improved * New hla_serial command to distinguish between several HLA adapters attached to a single machine * Serial number support for CMSIS-DAP and J-Link adapters * Support for more J-Link adapters * TAP autoprobing improvements * Big speedup for SVF playback with USB Blaster Boundary Scan: Target Layer: * Stability improvements for targets that get disconnected or rebooted during a debug session * MIPS speed and reliability improvements * MIPS 1.5/2.0 fixes * ARMv7-R improvements * Cortex-A improvements, A7, A15 MPCores support * FPU support for ARMv7-M (Cortex-M4F) * TPIU/ITM support (including SWO/SWV tracing), can be captured with external tools or STLink * JTAG Serial Port (Advanced Debug System softcore) support * Profiling support for OpenRISC * ChibiOS/RT 3.0 support (with and without FPU) * FreeRTOS current versions support * Freescale MQX RTOS support * GDB target description support for MIPS * The last created target is auto-selected as the current Flash Layer: * nRF51 async loader to improve flashing performance and stability * Cypress PSoC 41xx/42xx and CCG1 families flash driver * Silabs SiM3 family flash driver * Marvell Wireless Microcontroller SPI flash driver * Kinetis mass erase (part unsecuring) implemented * lpcspifi stability fixes * STM32 family sync with reference manuals, L0 support, bugfixes * LPC2000 driver automatically determines part and flash size * NXP LPC11(x)xx, LPC13xx, LPC15xx, LPC8xx, LPC5410x, LPC407x support * Atmel SAMD, SAMR, SAML21 devices support * Atmel SAM4E16 support * ZeroGecko family support * TI Tiva C Blizzard and Snowflake families support * Nuvoton NuMicro M051 support * EZR32 support in EFM32 driver Board, Target, and Interface Configuration Scripts: * Normal target configs can work with HLA (STLink, ICDI) adapters * STM32 discovery and Nucleo boards configs * Gumstix AeroCore board config * General Plus GP326XXXA target config * Micrel KS869x target config * ASUS RT-N66U board config * Atmel SAM4E-EK board config * Atmel AT91SAM4L proper reset handling implemented * TI OMAP/AM 3505, 3517 target configs * nRF51822-mKIT board config * RC Module К1879ХБ1Я target config * TI TMDX570LS20SUSB board config * TI TMS570 USB Kit board config * TI CC2538, CC26xx target configs * TI AM437x major config improvements, DDR support * TI AM437X IDK board config * TI SimpleLink Wi-Fi CC3200 LaunchPad configs * Silicon Labs EM357, EM358 target configs * Infineon XMC1000, XMC4000 family targets and boards configs * Atheros AR9331 target config * TP-LINK TL-MR3020 board config * Alphascale asm9260t target and eval kit configs * Olimex SAM7-LA2 (AT91SAM7A2) board config * EFM32 Gecko boards configs * Spansion FM4 target and SK-FM4-176L-S6E2CC board configs * LPC1xxx target configs were restructured * IoT-LAB debug adapter config * DP BusBlaster KT-Link compatible config Server Layer: * Polling period can be configured * "shutdown" command has an immediate effect * The "program" command doesn't lead to a shutdown by default, use optional "exit" parameter for the old behaviour * Proper OS signal handling was implemented * Async target notifications for the Tcl RPC Documentation: Build and Release: This release also contains a number of other important functional and cosmetic bugfixes. For more details about what has changed since the last release, see the git repository history: http://sourceforge.net/p/openocd/code/ci/v0.9.0/log/?path= For older NEWS, see the NEWS files associated with each release (i.e. NEWS-). For more information about contributing test reports, bug fixes, or new features and device support, please read the new Developer Manual (or the BUGS and PATCHES.txt files in the source archive). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/NEWTAPS ================================================ Reporting Unknown JTAG TAP IDS ------------------------------ If OpenOCD reports an UNKNOWN or Unexpected Tap ID please report it to the development mailing list - However - keep reading. openocd-devel@lists.sourceforge.net. ======================================== About "UNEXPECTED" tap ids. Before reporting an "UNEXPECTED TAP ID" - take a closer look. Perhaps you have your OpenOCD configured the wrong way, maybe you have the tap configured the wrong way? Or something else is wrong. (Remember: OpenOCD does not stop if the tap is not present) This "tap id check" is there for a purpose. The goal is to help get the *right* configuration. The idea is this: Every JTAG tap is suppose to have "a unique 32bit tap id" number. They are suppose to be "sort of unique" but they are not. There are no guarantees. Version Number Changes: Sometimes, the tap ID only differs by VERSION number. If so - it's not a big deal. Please do report this information. We'd like to know about it. For example Error: ERROR: Tap: s3c4510.cpu - Expected id: 0x3f0f0f0f, Got: 0x1f0f0f0f Error: ERROR: expected: mfg: 0x787, part: 0xf0f0, ver: 0x3 Error: ERROR: got: mfg: 0x787, part: 0xf0f0, ver: 0x1 ======================================== Updating the Tap ID number your self Why do this? You just want the warning to go away. And don't want to update your version/instance of OpenOCD. On simple systems, to fix this problem, in your "openocd.cfg" file, override the tap id. Depending on the tap, add one of these 3 commands: set CPUTAPID newvalue or set BSTAPID newvalue or set FLASHTAPID newvalue or set ETMTAPID newvalue Where "newvalue" is the new value you are seeing. On complex systems, (with many taps and chips) you probably have a custom configuration file. Its is more complicated, you're going to have to read through the configuration files ======================================== What to send: Cut & paste the output of OpenOCD that pointed you at this file. Please include the VERSION number of OpenOCD you are using. And please include the information below. ======================================== A) The JTAG TAP ID code. This is always a 32bit hex number. Examples: 0x1f0f0f0f - is an old ARM7TDMI 0x3f0f0f0f - is a newer ARM7TDMI 0x3ba00477 - is an ARM Cortex-M3 Some chips have multiple JTAG taps - be sure to list each one individually - ORDER is important! ======================================== B) The maker of the part Examples: Xilinx, Atmel, ST Micro Systems, Freescale ======================================== C) The family of parts it belongs to Examples: "NXP LPC Series" "Atmel SAM7 Series" ======================================== D) The actual part number on the package For example: "S3C45101x01" ======================================== E) What type of board it is. ie: a "commercial off the self eval board" that one can purchase (as opposed to your private internal custom board) For example: ST Micro systems has Eval boards, so does Analog Devices Or - if it is inside something "hackers like to hack" that information is helpful too. For example: A consumer GPS unit or a cellphone ======================================== (F) The maker of the board ie: Olimex, LogicPD, Freescale(eval board) ======================================== (G) Identifying information on the board. Not good: "iar red ST eval board" Really good: "IAR STR912-SK evaluation board" ======================================== (H) Are there other interesting (JTAG) chips on the board? ie: An FPGA or CPLD ... ======================================== (I) What target config files need updating? In fact it's best if you submit a patch with those updates. Most of the other information listed here is just to help create a good patch. ======================================== ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/README ================================================ Welcome to OpenOCD! =================== OpenOCD provides on-chip programming and debugging support with a layered architecture of JTAG interface and TAP support including: - (X)SVF playback to facilitate automated boundary scan and FPGA/CPLD programming; - debug target support (e.g. ARM, MIPS): single-stepping, breakpoints/watchpoints, gprof profiling, etc; - flash chip drivers (e.g. CFI, NAND, internal flash); - embedded TCL interpreter for easy scripting. Several network interfaces are available for interacting with OpenOCD: telnet, TCL, and GDB. The GDB server enables OpenOCD to function as a "remote target" for source-level debugging of embedded systems using the GNU GDB program (and the others who talk GDB protocol, e.g. IDA Pro). This README file contains an overview of the following topics: - quickstart instructions, - how to find and build more OpenOCD documentation, - list of the supported hardware, - the installation and build process, - packaging tips. ============================ Quickstart for the impatient ============================ If you have a popular board then just start OpenOCD with its config, e.g.: openocd -f board/stm32f4discovery.cfg If you are connecting a particular adapter with some specific target, you need to source both the jtag interface and the target configs, e.g.: openocd -f interface/ftdi/jtagkey2.cfg -c "transport select jtag" \ -f target/ti_calypso.cfg openocd -f interface/stlink.cfg -c "transport select hla_swd" \ -f target/stm32l0.cfg After OpenOCD startup, connect GDB with (gdb) target extended-remote localhost:3333 ===================== OpenOCD Documentation ===================== In addition to the in-tree documentation, the latest manuals may be viewed online at the following URLs: OpenOCD User's Guide: http://openocd.org/doc/html/index.html OpenOCD Developer's Manual: http://openocd.org/doc/doxygen/html/index.html These reflect the latest development versions, so the following section introduces how to build the complete documentation from the package. For more information, refer to these documents or contact the developers by subscribing to the OpenOCD developer mailing list: openocd-devel@lists.sourceforge.net Building the OpenOCD Documentation ---------------------------------- By default the OpenOCD build process prepares documentation in the "Info format" and installs it the standard way, so that "info openocd" can access it. Additionally, the OpenOCD User's Guide can be produced in the following different formats: # If PDFVIEWER is set, this creates and views the PDF User Guide. make pdf && ${PDFVIEWER} doc/openocd.pdf # If HTMLVIEWER is set, this creates and views the HTML User Guide. make html && ${HTMLVIEWER} doc/openocd.html/index.html The OpenOCD Developer Manual contains information about the internal architecture and other details about the code: # NB! make sure doxygen is installed, type doxygen --version make doxygen && ${HTMLVIEWER} doxygen/index.html ================== Supported hardware ================== JTAG adapters ------------- AM335x, ARM-JTAG-EW, ARM-USB-OCD, ARM-USB-TINY, AT91RM9200, axm0432, BCM2835, Bus Blaster, Buspirate, Cadence DPI, Cadence vdebug, Chameleon, CMSIS-DAP, Cortino, Cypress KitProg, DENX, Digilent JTAG-SMT2, DLC 5, DLP-USB1232H, embedded projects, Espressif USB JTAG Programmer, eStick, FlashLINK, FlossJTAG, Flyswatter, Flyswatter2, FTDI FT232R, Gateworks, Hoegl, ICDI, ICEBear, J-Link, JTAG VPI, JTAGkey, JTAGkey2, JTAG-lock-pick, KT-Link, Linux GPIOD, Lisa/L, LPC1768-Stick, Mellanox rshim, MiniModule, NGX, Nuvoton Nu-Link, Nu-Link2, NXHX, NXP IMX GPIO, OOCDLink, Opendous, OpenJTAG, Openmoko, OpenRD, OSBDM, Presto, Redbee, Remote Bitbang, RLink, SheevaPlug devkit, Stellaris evkits, ST-LINK (SWO tracing supported), STM32-PerformanceStick, STR9-comStick, sysfsgpio, Tigard, TI XDS110, TUMPA, Turtelizer, ULINK, USB-A9260, USB-Blaster, USB-JTAG, USBprog, VPACLink, VSLLink, Wiggler, XDS100v2, Xilinx XVC/PCIe, Xverve. Debug targets ------------- ARM: AArch64, ARM11, ARM7, ARM9, Cortex-A/R (v7-A/R), Cortex-M (ARMv{6/7/8}-M), FA526, Feroceon/Dragonite, XScale. ARCv2, AVR32, DSP563xx, DSP5680xx, EnSilica eSi-RISC, EJTAG (MIPS32, MIPS64), ESP32, ESP32-S2, ESP32-S3, Intel Quark, LS102x-SAP, RISC-V, ST STM8, Xtensa. Flash drivers ------------- ADUC702x, AT91SAM, AT91SAM9 (NAND), ATH79, ATmega128RFA1, Atmel SAM, AVR, CFI, DSP5680xx, EFM32, EM357, eSi-RISC, eSi-TSMC, EZR32HG, FM3, FM4, Freedom E SPI, GD32, i.MX31, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPC3180, LPC32xx, LPCSPIFI, Marvell QSPI, MAX32, Milandr, MXC, NIIET, nRF51, nRF52 , NuMicro, NUC910, Nuvoton NPCX, onsemi RSL10, Orion/Kirkwood, PIC32mx, PSoC4/5LP/6, Raspberry RP2040, Renesas RPC HF and SH QSPI, S3C24xx, S3C6400, SiM3x, SiFive Freedom E, Stellaris, ST BlueNRG, STM32, STM32 QUAD/OCTO-SPI for Flash/FRAM/EEPROM, STMSMI, STR7x, STR9x, SWM050, TI CC13xx, TI CC26xx, TI CC32xx, TI MSP432, Winner Micro w600, Xilinx XCF, XMC1xxx, XMC4xxx. ================== Installing OpenOCD ================== A Note to OpenOCD Users ----------------------- If you would rather be working "with" OpenOCD rather than "on" it, your operating system or JTAG interface supplier may provide binaries for you in a convenient-enough package. Such packages may be more stable than git mainline, where bleeding-edge development takes place. These "Packagers" produce binary releases of OpenOCD after the developers produces new "release" versions of the source code. Previous versions of OpenOCD cannot be used to diagnose problems with the current release, so users are encouraged to keep in contact with their distribution package maintainers or interface vendors to ensure suitable upgrades appear regularly. Users of these binary versions of OpenOCD must contact their Packager to ask for support or newer versions of the binaries; the OpenOCD developers do not support packages directly. A Note to OpenOCD Packagers --------------------------- You are a PACKAGER of OpenOCD if you: - Sell dongles and include pre-built binaries; - Supply tools or IDEs (a development solution integrating OpenOCD); - Build packages (e.g. RPM or DEB files for a GNU/Linux distribution). As a PACKAGER, you will experience first reports of most issues. When you fix those problems for your users, your solution may help prevent hundreds (if not thousands) of other questions from other users. If something does not work for you, please work to inform the OpenOCD developers know how to improve the system or documentation to avoid future problems, and follow-up to help us ensure the issue will be fully resolved in our future releases. That said, the OpenOCD developers would also like you to follow a few suggestions: - Send patches, including config files, upstream, participate in the discussions; - Enable all the options OpenOCD supports, even those unrelated to your particular hardware; - Use "ftdi" interface adapter driver for the FTDI-based devices. ================ Building OpenOCD ================ The INSTALL file contains generic instructions for running 'configure' and compiling the OpenOCD source code. That file is provided by default for all GNU autotools packages. If you are not familiar with the GNU autotools, then you should read those instructions first. The remainder of this document tries to provide some instructions for those looking for a quick-install. OpenOCD Dependencies -------------------- GCC or Clang is currently required to build OpenOCD. The developers have begun to enforce strict code warnings (-Wall, -Werror, -Wextra, and more) and use C99-specific features: inline functions, named initializers, mixing declarations with code, and other tricks. While it may be possible to use other compilers, they must be somewhat modern and could require extending support to conditionally remove GCC-specific extensions. You'll also need: - make - libtool - pkg-config >= 0.23 or pkgconf OpenOCD uses jimtcl library; build from git can retrieve jimtcl as git submodule. Additionally, for building from git: - autoconf >= 2.69 - automake >= 1.14 - texinfo >= 5.0 Optional USB-based adapter drivers need libusb-1.0. Optional USB-Blaster, ASIX Presto and OpenJTAG interface adapter drivers need: - libftdi: http://www.intra2net.com/en/developer/libftdi/index.php Optional CMSIS-DAP adapter driver needs HIDAPI library. Optional linuxgpiod adapter driver needs libgpiod library. Optional J-Link adapter driver needs libjaylink library. Optional ARM disassembly needs capstone library. Optional development script checkpatch needs: - perl - python - python-ply Permissions delegation ---------------------- Running OpenOCD with root/administrative permissions is strongly discouraged for security reasons. For USB devices on GNU/Linux you should use the contrib/60-openocd.rules file. It probably belongs somewhere in /etc/udev/rules.d, but consult your operating system documentation to be sure. Do not forget to add yourself to the "plugdev" group. For parallel port adapters on GNU/Linux and FreeBSD please change your "ppdev" (parport* or ppi*) device node permissions accordingly. For parport adapters on Windows you need to run install_giveio.bat (it's also possible to use "ioperm" with Cygwin instead) to give ordinary users permissions for accessing the "LPT" registers directly. Compiling OpenOCD ----------------- To build OpenOCD, use the following sequence of commands: ./bootstrap (when building from the git repository) ./configure [options] make sudo make install The 'configure' step generates the Makefiles required to build OpenOCD, usually with one or more options provided to it. The first 'make' step will build OpenOCD and place the final executable in './src/'. The final (optional) step, ``make install'', places all of the files in the required location. To see the list of all the supported options, run ./configure --help Cross-compiling Options ----------------------- Cross-compiling is supported the standard autotools way, you just need to specify the cross-compiling target triplet in the --host option, e.g. for cross-building for Windows 32-bit with MinGW on Debian: ./configure --host=i686-w64-mingw32 [options] To make pkg-config work nicely for cross-compiling, you might need an additional wrapper script as described at https://autotools.io/pkgconfig/cross-compiling.html This is needed to tell pkg-config where to look for the target libraries that OpenOCD depends on. Alternatively, you can specify *_CFLAGS and *_LIBS environment variables directly, see "./configure --help" for the details. For a more or less complete script that does all this for you, see contrib/cross-build.sh Parallel Port Dongles --------------------- If you want to access the parallel port using the PPDEV interface you have to specify both --enable-parport AND --enable-parport-ppdev, since the later option is an option to the parport driver. The same is true for the --enable-parport-giveio option, you have to use both the --enable-parport AND the --enable-parport-giveio option if you want to use giveio instead of ioperm parallel port access method. ========================== Obtaining OpenOCD From GIT ========================== You can download the current GIT version with a GIT client of your choice from the main repository: git://git.code.sf.net/p/openocd/code You may prefer to use a mirror: http://repo.or.cz/r/openocd.git git://repo.or.cz/openocd.git Using the GIT command line client, you might use the following command to set up a local copy of the current repository (make sure there is no directory called "openocd" in the current directory): git clone git://git.code.sf.net/p/openocd/code openocd Then you can update that at your convenience using git pull There is also a gitweb interface, which you can use either to browse the repository or to download arbitrary snapshots using HTTP: http://repo.or.cz/w/openocd.git Snapshots are compressed tarballs of the source tree, about 1.3 MBytes each at this writing. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/README.Windows ================================================ Building OpenOCD for Windows ---------------------------- You can build OpenOCD for Windows natively with either MinGW-w64/MSYS or Cygwin (plain MinGW might work with --disable-werror but is not recommended as it doesn't provide enough C99 compatibility). Alternatively, one can cross-compile it using MinGW-w64 on a *nix host. See README for the generic instructions. Also, the MSYS2 project provides both ready-made binaries and an easy way to self-compile from their software repository out of the box. Native MinGW-w64/MSYS compilation ----------------------------- As MSYS doesn't come with pkg-config pre-installed, you need to add it manually. The easiest way to do that is to download pkg-config-lite from: http://sourceforge.net/projects/pkgconfiglite/ Then simply unzip the archive to the root directory of your MinGW-w64 installation. USB adapters ------------ For the adapters that use a HID-based protocol, e.g. CMSIS-DAP, you do not need to perform any additional configuration. For all the others you usually need to have WinUSB.sys (or libusbK.sys) driver installed. Some vendor software (e.g. for ST-LINKv2) does it on its own. For the other cases the easiest way to assign WinUSB to a device is to use the latest Zadig installer: http://zadig.akeo.ie When using a composite USB device, it's often necessary to assign WinUSB.sys to the composite parent instead of the specific interface. To do that one needs to activate an advanced option in the Zadig installer. If you need to use the same adapter with other applications that may require another driver, a solution for Windows Vista and above is to activate the IgnoreHWSerNum registry setting for the USB device. That setting forces Windows to associate the driver per port instead of per serial number, the same behaviour as when the device does not contain a serial number. So different drivers can be installed for the adapter on different ports and you just need to plug the adapter into the correct port depending on which application to use. For more information, see: https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-device-specific-registry-settings http://www.ftdichip.com/Support/Knowledgebase/index.html?ignorehardwareserialnumber.htm ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/README.macOS ================================================ Building OpenOCD for macOS -------------------------- There are a few prerequisites you will need first: - Xcode (install from the AppStore) - Command Line Tools (install from Xcode -> Preferences -> Downloads) - Gentoo Prefix (http://www.gentoo.org/proj/en/gentoo-alt/prefix/bootstrap.xml) or - Homebrew (http://mxcl.github.io/homebrew/) or - MacPorts (http://www.macports.org/install.php) If you're building manually you need Texinfo version 5.0 or later. The simplest way to get it is to use Homebrew (brew install texinfo) and then ``export PATH=/usr/local/opt/texinfo/bin:$PATH``. With Gentoo Prefix you can build the release version or the latest devel version (-9999) the usual way described in the Gentoo documentation. Alternatively, install the prerequisites and build manually from the sources. With Homebrew you can either run: brew install [--HEAD] openocd (where optional --HEAD asks brew to install the current git version) or brew install libtool automake libusb [hidapi] [libftdi] (to install the needed dependencies and then proceed with the manual building procedure) For building with MacPorts you need to run: sudo port install libtool automake autoconf pkgconfig \ libusb [libftdi1] You should also specify LDFLAGS and CPPFLAGS to allow configure to use MacPorts' libraries, so run configure like this: LDFLAGS=-L/opt/local/lib CPPFLAGS=-I/opt/local/include ./configure [options] See README for the generic building instructions. If you're using a USB adapter and have a driver kext matched to it, you will need to unload it prior to running OpenOCD. E.g. with Apple driver (OS X 10.9 or later) for FTDI run: sudo kextunload -b com.apple.driver.AppleUSBFTDI for FTDI vendor driver use: sudo kextunload FTDIUSBSerialDriver.kext To learn more on the topic please refer to the official libusb FAQ: https://github.com/libusb/libusb/wiki/FAQ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/TODO ================================================ // This file is part of the Doxygen Developer Manual /** @page tasks Pending and Open Tasks This page lists pending and open tasks being considered or worked upon by the OpenOCD community. @section thelist The List Most items are open for the taking, but please post to the mailing list before spending much time working on anything lists here. The community may have evolved an idea since it was added here. Feel free to send patches to add or clarify items on this list, too. @section thelisttcl TCL This section provides possible things to improve with OpenOCD's TCL support. - Fix problem with incorrect line numbers reported for a syntax error in a reset init event. - organize the TCL configurations: - provide more directory structure for boards/targets? - factor configurations into layers (encapsulation and re-use) - Fix handling of variables between multiple command line "-c" and "-f" parameters. Currently variables assigned through one such parameter command/script are unset before the next one is invoked. - Isolate all TCL command support: - Pure C CLI implementations using --disable-builtin-tcl. - Allow developers to build new dongles using OpenOCD's JTAG core. - At first, provide only low-level JTAG support; target layer and above rely heavily on scripting event mechanisms. - Allow full TCL support? add --with-tcl=/path/to/installed/tcl - Move TCL support out of foo.[ch] and into foo_tcl.[ch] (other ideas?) - See src/jtag/core.c and src/jtag/tcl.c for an example. - allow some of these TCL command modules to be dynamically loadable? @section thelistadapter Adapter This section list issues that need to be resolved in the Adapter layer. @subsection thelistadapterrework Code restructuring This section lists pending reworks to complete the restructure from the old JTAG centric implementation to a generic Adapter layer. This restructuring is very invasive and will prevent the merge of several changes pending in gerrit. - rename folder src/jtag/ to src/adapter/ - rename var "jtag" to "adapter" in src/jtag/core.c - split content of src/adapter/ in the different protocols jtag.[ch], swd.[ch], ... - wrap the calls to adapter->transport_ops->api() with transport_api() and reduce the visibility of global var "adapter" - complete the migration of JTAG-only drivers to adapter->reset() - try to remove JTAG_SLEEP also from JTAG mode? - tap_set_state(TAP_RESET) is already done in src/jtag/core.c. No need to replicate it in the drivers, apart in case the driver sets TRST independently - add .hla_ops to "adapter" - HLA is a API level (.hla_ops). Transport should simply be {jtag,swd}, not {hla_jtag,hla_swd}. @subsection thelistadapterjtagcore JTAG Core The following tasks have been suggested for cleaning up the JTAG layer: - use tap_set_state everywhere to allow logging TAP state transitions - Encapsulate cmd_queue_cur_state and related variable handling. - add slick 32 bit versions of jtag_add_xxx_scan() that avoids buf_set_u32() calls and other evidence of poor impedance match between API and calling code. New API should cut down # of lines in calling code by 100's and make things clearer. Also potentially be supported directly in minidriver API for better embedded host performance. The following tasks have been suggested for adding new core JTAG support: - Improve autodetection of TAPs by supporting tcl escape procedures that can configure discovered TAPs based on IDCODE value ... they could: - Remove guessing for irlen - Allow non-default irmask/ircapture values - SPI/UART emulation: - (ab)use bit-banging JTAG interfaces to emulate SPI/UART - allow SPI to program flash, MCUs, etc. @subsection thelistadapterinterfaces Interface drivers There are some known bugs to fix in Interface drivers: - For JTAG_STATEMOVE to TAP_RESET, all drivers must ignore the current recorded state. The tap_get_state() call won't necessarily return the correct value, especially at server startup. Fix is easy: in that case, always issue five clocks with TMS high. - amt_jtagaccel.c - arm-jtag-ew.c - bitbang.c - bitq.c - gw16012.c - jlink.c - usbprog.c - vsllink.c - rlink/rlink.c - bug: USBprog is broken with new tms sequence; it needs 7-clock cycles. Fix promised from Peter Denison openwrt at marshadder.org Workaround: use "tms_sequence long" @par https://lists.berlios.de/pipermail/openocd-development/2009-July/009426.html The following tasks have been suggested for improving OpenOCD's JTAG interface support: - rework USB communication to be more robust. Two possible options are: -# use libusb-1.0.1 with libusb-compat-0.1.1 (non-blocking I/O wrapper) -# rewrite implementation to use non-blocking I/O - J-Link driver: - fix to work with long scan chains, such as R.Doss's svf test. - Autodetect USB based adapters; this should be easy on Linux. If there's more than one, list the options; otherwise, just select that one. The following tasks have been suggested for adding new JTAG interfaces: - TCP driver: allow client/server for remote JTAG interface control. This requires a client and a server. The server is built into the normal OpenOCD and takes commands from the client and executes them on the interface returning the result of TCP/IP. The client is an OpenOCD which is built with a TCP/IP minidriver. The use of a minidriver is required to capture all the jtag_add_xxx() fn's at a high enough level and repackage these cmd's as TCP/IP packets handled by the server. @section thelistbs Boundary Scan Support - add STAPL support? - add BSDL support? A few possible options for the above: -# Fake a TCL equivalent? -# Integrate an existing library? -# Write a new C implementation a la Jim? Once the above are completed: - add support for programming flash using boundary scan techniques - add integration with a modified gerber view program: - provide means to view the PCB and select pins and traces - allow use-cases such as the following: - @b Stimulus -# Double-click on a pin (or trace) with the mouse. - @b Effects -# The trace starts blinking, and -# OpenOCD toggles the pin(s) 0/1. @section thelisttargets Target Support - Many common ARM cores could be autodetected using IDCODE - general layer cleanup: @par https://lists.berlios.de/pipermail/openocd-development/2009-May/006590.html - regression: "reset halt" between 729(works) and 788(fails): @par https://lists.berlios.de/pipermail/openocd-development/2009-July/009206.html - registers - add flush-value operation, call them all on resume/reset - mcr/mrc target->type support - missing from ARM920t, ARM966e, XScale. It's possible that the current syntax is unable to support read-modify-write operations(see arm966e). - mcr/mrc - retire cp15 commands when there the mrc/mrc commands have been tested from: arm926ejs, arm720t, cortex_a8 - ARM7/9: - clean up "arm9tdmi vector_catch". Available for some arm7 cores? @par https://lists.berlios.de/pipermail/openocd-development/2009-October/011488.html https://lists.berlios.de/pipermail/openocd-development/2009-October/011506.html - add reset option to allow programming embedded ice while srst is asserted. Some CPUs will gate the JTAG clock when srst is asserted and in this case, it is necessary to program embedded ice and then assert srst afterwards. - ARM926EJS: - reset run/halt/step is not robust; needs testing to map out problems. - ARM11 improvements (MB?) - add support for asserting srst to reset the core. - Single stepping works, but should automatically use hardware stepping if available. - mdb can return garbage data if read byte operation fails for a memory region(16 & 32 byte access modes may be supported). Is this a bug in the .MX31 PDK init script? Try on i.MX31 PDK: mdw 0xb80005f0 0x8, mdh 0xb80005f0 0x10, mdb 0xb80005f0 0x20. mdb returns garabage. - implement missing functionality (grep FNC_INFO_NOTIMPLEMENTED ...) - Thumb2 single stepping: ARM1156T2 needs simulator support - Cortex-A8 support (ML) - add target implementation (ML) - Cortex-M3 support - when stepping, only write dirtied registers (be faster) - when connecting to halted core, fetch registers (startup is quirky) - Generic ARM run_algorithm() interface - tagged struct wrapping ARM instructions and metadata - not revision-specific (current: ARMv4+ARMv5 -or- ARMv6 -or- ARMv7) - usable with at least arm_nandwrite() and generic CFI drivers - ETM - don't show FIFOFULL registers if they're not supported - use comparators to get more breakpoints and watchpoints - add "etm drivers" command - trace driver init() via examine() paths only, not setup()/reset - MC1322x support (JW/DE?) - integrate and test support from JW (and DE?) - get working with a known good interface (i.e. not today's jlink) - STR9x: (ZW) - improvements to str912.cfg to be more general purpose - AVR: (SQ) - independently verify implementation - incrementally improve working prototype in trunk. (SQ) - work out how to debug this target - AVR debugging protocol. - FPGA: - Altera Nios Soft-CPU support - Coldfire (suggested by NC) - can we draw from the BDM project? @par http://bdm.sourceforge.net/ or the OSBDM package @par http://forums.freescale.com/freescale/board/message?board.id=OSBDM08&thread.id=422 @section thelistsvf SVF/XSVF - develop SVF unit tests - develop XSVF unit tests @section thelistflash Flash Support - finish documentation for the following flash drivers: - avr - pic32mx - ocl - str9xpec - Don't expect writing all-ones to be a safe way to write without changing bit values. Minimally it loses on flash modules with internal ECC, where it may change the ECC. - NOR flash_write_unlock() does that between sectors - there may be other cases too - Make sure all commands accept either a bank name or a bank number, and be sure both identifiers show up in "flash banks" and "nand list". Right now the user-friendly names are pretty much hidden... @subsection thelistflashcfi CFI - finish implementing bus width/chip width handling (suggested by NC) - factor vendor-specific code into separate source files - add new callback interface for vendor-specific code - investigate/implement "thin wrapper" to use eCos CFI drivers (ØH) @section thelistdebug Debugger Support - add support for masks in watchpoints? @par https://lists.berlios.de/pipermail/openocd-development/2009-October/011507.html - breakpoints can get lost in some circumstances: @par https://lists.berlios.de/pipermail/openocd-development/2009-June/008853.html - add support for masks in watchpoints. The trick is that GDB does not support a breakpoint mask in the remote protocol. One way to work around this is to add a separate command "watchpoint_mask add/rem ", that is run to register a list of masks that the gdb_server knows to use with a particular watchpoint address. - integrate Keil AGDI interface to OpenOCD? (submitted by Dario Vecchio) @section thelisttesting Testing Suite This section includes several related groups of ideas: - @ref thelistunittests - @ref thelistsmoketests - @ref thelisttestreports - @ref thelisttestgenerichw @subsection thelistunittests Unit Tests - add testing skeleton to provide frameworks for adding tests - implement server unit tests - implement JTAG core unit tests - implement JTAG interface unit tests - implement flash unit tests - implement target unit tests @subsection thelistsmoketests Smoke Test Tools -# extend 'make check' with a smoketest app - checks for OOCD_TEST_CONFIG, etc. in environment (or config file) - if properly set, runs the smoke test with specified parameters - openocd -f ${OOCD_TEST_CONFIG} - implies a modular test suite (see below) - should be able to run some minimal tests with dummy interface: - compare results of baseline sanity checks with expected results -# builds a more complete test suite: - existing testing/examples/ look like a great start - all targets should be tested fully and for all capabilities - we do NOT want a "lowest common denominator" test suite - ... but can we start with one to get going? - probably requires one test configuration file per board/target - modularization can occur here, just like with targets/boards/chips - coverage can increase over time, building up bundles of tests -# add new 'smoketest' Makefile target: - calls 'make check' (and the smoketest app) - gather inputs and output into a report file @subsection thelisttestreports Test Feedback Tools These ideas were first introduced here: @par https://lists.berlios.de/pipermail/openocd-development/2009-May/006358.html - provide report submission scripts for e-mail and web forms - add new Makefile targets to post the report: - 'checkreportsend' -- send to list via e-mail (via sendmail) - 'checkreportpost' -- send web form (via curl or other script) @subsection thelisttestgenerichw Generic Hardware Tester - implement VHDL to use for FPGA-based JTAG TAP testing device - develop test suite that utilizes this testing device @section thelistautotools Autotools Build System - make entire configure process require less user consideration: - automatically detect the features that are available, unless options were specifically provided to configure - provide a report of the drivers that will be build at the end of running configure, so the users can verify which drivers will be built during 'make' (and their options) . - eliminate sources of confusion in @c bootstrap script: -# Make @c bootstrap call 'configure --enable-maintainer-mode \'? -# Add @c buildstrap script to assist with bootstrap and configure steps. - automatically build tool-chains required for cross-compiling - produce mingw32, arm-elf, others using in-tree scripts - build all required target code from sources - make JTAG and USB debug output a run-time configuration option @section thelistarchitecture Architectural Tasks The following architectural tasks need to be accomplished and should be fairly easy to complete: - use dynamic allocations for working memory. Scan & fix code for excessive stack allocations. take linux/scripts/checkstack.pl and see what the worst offenders are. Dynamic stack allocations are found at the bottom of the list below. Example, on amd64: $ objdump -d | checkstack.pl | head -10 0x004311e3 image_open [openocd]: 13464 0x00431301 image_open [openocd]: 13464 0x004237a4 target_array2mem [openocd]: 4376 0x0042382b target_array2mem [openocd]: 4376 0x00423e74 target_mem2array [openocd]: 4360 0x00423ef9 target_mem2array [openocd]: 4360 0x00404aed handle_svf_command [openocd]: 2248 0x00404b7e handle_svf_command [openocd]: 2248 0x00413581 handle_flash_fill_command [openocd]: 2200 0x004135fa handle_flash_fill_command [openocd]: 2200 - clean-up code to match style guides - factor code to eliminate duplicated functionality - rewrite code that uses casts to access 16-bit and larger types from unaligned memory addresses - libopenocd support: @par https://lists.berlios.de/pipermail/openocd-development/2009-May/006405.html - review and clean up interface/target/flash APIs The following strategic tasks will require ambition, knowledge, and time to complete: - overhaul use of types to improve 32/64-bit portability - types for both host and target word sizes? - can we use GDB's CORE_TYPE support? - Allow N:M:P mapping of servers, targets, and interfaces - loadable module support for interface/target/flash drivers and commands - support both static and dynamic modules. - should probably use libltdl for dynamic library handing. @section thelistadmin Documentation Tasks - Develop milestone and release guidelines, processes, and scripts. - Develop "style" guidelines (and scripts) for maintainers: - reviewing patches - committing to git - Review Users' Guide for documentation errors or omissions - "capture" and "ocd_find" commands - Update Developer's Manual (doxygen output) - Add documentation describing the architecture of each module - Provide more Technical Primers to bootstrap contributor knowledge */ /** @file This file contains the @ref thelist page. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/bootstrap ================================================ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Run the autotools bootstrap sequence to create the configure script # Abort execution on error set -e if which libtoolize > /dev/null; then libtoolize="libtoolize" elif which glibtoolize >/dev/null; then libtoolize="glibtoolize" else echo "$0: Error: libtool is required" >&2 exit 1 fi if [ "$1" = "nosubmodule" ]; then SKIP_SUBMODULE=1 elif [ -n "$1" ]; then echo "$0: Illegal argument $1" echo "USAGE: $0 [nosubmodule]" exit 1 fi # bootstrap the autotools ( set -x aclocal --warnings=all # Apparently, not all versions of libtoolize support option --warnings=all . ${libtoolize} --automake --copy autoconf --warnings=all autoheader --warnings=all automake --warnings=all --gnu --add-missing --copy ) if [ -n "$SKIP_SUBMODULE" ]; then echo "Skipping submodule setup" else echo "Setting up submodules" git submodule init git submodule update fi if [ -x src/jtag/drivers/libjaylink/autogen.sh ]; then ( cd src/jtag/drivers/libjaylink ./autogen.sh ) fi echo "Bootstrap complete. Quick build instructions:" echo "./configure ...." ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/config_subdir.m4 ================================================ dnl AC_CONFIG_SUBDIRS does not allow configure options to be passed dnl to subdirs, this function allows that by creating a configure.gnu dnl script that prepends configure options and then calls the real dnl configure script AC_DEFUN([AX_CONFIG_SUBDIR_OPTION], [ AC_CONFIG_SUBDIRS([$1]) m4_ifblank([$2], [rm -f $srcdir/$1/configure.gnu], [echo -e '#!/bin/sh\nexec "`dirname "'\$'0"`/configure" '"$2"' "'\$'@"' > "$srcdir/$1/configure.gnu" ]) ]) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/configure.ac ================================================ # SPDX-License-Identifier: GPL-2.0-or-later AC_PREREQ([2.69]) AC_INIT([openocd], [0.12.0+dev], [OpenOCD Mailing List ]) AC_CONFIG_SRCDIR([src/openocd.c]) AC_CONFIG_AUX_DIR([build-aux]) m4_include([config_subdir.m4])dnl # check for makeinfo before calling AM_INIT_AUTOMAKE AC_CHECK_PROG([MAKEINFO], [makeinfo], [makeinfo]) AS_IF([test "x$MAKEINFO" = "x"], [ MAKEINFO='echo makeinfo missing; true' AC_MSG_WARN([Info documentation will not be built.]) ]) AC_SUBST([MAKEINFO]) AM_INIT_AUTOMAKE([-Wall -Wno-portability dist-bzip2 dist-zip subdir-objects]) AC_CONFIG_HEADERS([config.h]) AC_LANG([C]) AC_PROG_CC # autoconf 2.70 obsoletes AC_PROG_CC_C99 and includes it in AC_PROG_CC m4_version_prereq([2.70],[],[AC_PROG_CC_C99]) AM_PROG_CC_C_O AC_PROG_RANLIB # If macro PKG_PROG_PKG_CONFIG is not available, Autoconf generates a misleading error message, # so check for existence first, and otherwise provide helpful advice. m4_ifndef([PKG_PROG_PKG_CONFIG], [m4_fatal(m4_normalize([ Macro PKG_PROG_PKG_CONFIG is not available. It is usually defined in file pkg.m4 provided by package pkg-config.]))]) PKG_PROG_PKG_CONFIG([0.23]) dnl disable checks for C++, Fortran and GNU Java Compiler m4_defun([_LT_AC_LANG_CXX_CONFIG], [:]) m4_defun([_LT_AC_LANG_F77_CONFIG], [:]) m4_defun([_LT_AC_LANG_GCJ_CONFIG], [:]) AC_DISABLE_SHARED LT_INIT AC_SUBST([LIBTOOL_DEPS]) dnl configure checks required for Jim files (these are obsolete w/ C99) AC_C_CONST AC_TYPE_LONG_LONG_INT AC_SEARCH_LIBS([ioperm], [ioperm]) AC_SEARCH_LIBS([dlopen], [dl]) AC_SEARCH_LIBS([openpty], [util]) AC_CHECK_HEADERS([sys/socket.h]) AC_CHECK_HEADERS([elf.h]) AC_EGREP_HEADER(Elf64_Ehdr, [elf.h], [ AC_DEFINE([HAVE_ELF64], [1], [Define to 1 if the system has the type `Elf64_Ehdr'.]) ]) AC_CHECK_HEADERS([fcntl.h]) AC_CHECK_HEADERS([malloc.h]) AC_CHECK_HEADERS([netdb.h]) AC_CHECK_HEADERS([poll.h]) AC_CHECK_HEADERS([strings.h]) AC_CHECK_HEADERS([sys/ioctl.h]) AC_CHECK_HEADERS([sys/param.h]) AC_CHECK_HEADERS([sys/select.h]) AC_CHECK_HEADERS([sys/stat.h]) AC_CHECK_HEADERS([sys/sysctl.h]) AC_CHECK_HEADERS([sys/time.h]) AC_CHECK_HEADERS([sys/types.h]) AC_CHECK_HEADERS([unistd.h]) AC_CHECK_HEADERS([arpa/inet.h netinet/in.h netinet/tcp.h], [], [], [dnl #include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_SYS_SOCKET_H # include #endif ]) AC_HEADER_ASSERT AC_HEADER_STDBOOL AC_C_BIGENDIAN AC_CHECK_FUNCS([strndup]) AC_CHECK_FUNCS([strnlen]) AC_CHECK_FUNCS([gettimeofday]) AC_CHECK_FUNCS([usleep]) AC_CHECK_FUNCS([realpath]) # guess-rev.sh only exists in the repository, not in the released archives AC_MSG_CHECKING([whether to build a release]) AS_IF([test -x "$srcdir/guess-rev.sh"], [ build_release=no ], [ build_release=yes ]) AC_MSG_RESULT([$build_release]) # Adapter drivers # 1st column -- configure option # 2nd column -- description # 3rd column -- symbol used for both config.h and automake m4_define([ADAPTER_ARG], [m4_argn([1], $1)]) m4_define([ADAPTER_DESC], [m4_argn([2], $1)]) m4_define([ADAPTER_SYM], [m4_argn([3], $1)]) m4_define([ADAPTER_VAR], [enable_[]ADAPTER_ARG($1)]) m4_define([ADAPTER_OPT], [m4_translit(ADAPTER_ARG($1), [_], [-])]) m4_define([USB1_ADAPTERS], [[[ftdi], [MPSSE mode of FTDI based devices], [FTDI]], [[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]], [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]], [[ulink], [Keil ULINK JTAG Programmer], [ULINK]], [[usb_blaster_2], [Altera USB-Blaster II Compatible], [USB_BLASTER_2]], [[ft232r], [Bitbang mode of FT232R based devices], [FT232R]], [[vsllink], [Versaloon-Link JTAG Programmer], [VSLLINK]], [[xds110], [TI XDS110 Debug Probe], [XDS110]], [[cmsis_dap_v2], [CMSIS-DAP v2 Compliant Debugger], [CMSIS_DAP_USB]], [[osbdm], [OSBDM (JTAG only) Programmer], [OSBDM]], [[opendous], [eStick/opendous JTAG Programmer], [OPENDOUS]], [[armjtagew], [Olimex ARM-JTAG-EW Programmer], [ARMJTAGEW]], [[rlink], [Raisonance RLink JTAG Programmer], [RLINK]], [[usbprog], [USBProg JTAG Programmer], [USBPROG]], [[esp_usb_jtag], [Espressif JTAG Programmer], [ESP_USB_JTAG]], [[ch347], [Mode 3 of the CH347 devices], [CH347]]]) m4_define([HIDAPI_ADAPTERS], [[[cmsis_dap], [CMSIS-DAP Compliant Debugger], [CMSIS_DAP_HID]], [[nulink], [Nu-Link Programmer], [HLADAPTER_NULINK]]]) m4_define([HIDAPI_USB1_ADAPTERS], [[[kitprog], [Cypress KitProg Programmer], [KITPROG]]]) m4_define([LIBFTDI_ADAPTERS], [[[usb_blaster], [Altera USB-Blaster Compatible], [USB_BLASTER]], [[presto], [ASIX Presto Adapter], [PRESTO]]]) m4_define([LIBFTDI_USB1_ADAPTERS], [[[openjtag], [OpenJTAG Adapter], [OPENJTAG]]]) m4_define([LIBGPIOD_ADAPTERS], [[[linuxgpiod], [Linux GPIO bitbang through libgpiod], [LINUXGPIOD]]]) m4_define([LIBJAYLINK_ADAPTERS], [[[jlink], [SEGGER J-Link Programmer], [JLINK]]]) m4_define([PCIE_ADAPTERS], [[[xlnx_pcie_xvc], [Xilinx XVC/PCIe], [XLNX_PCIE_XVC]]]) m4_define([SERIAL_PORT_ADAPTERS], [[[buspirate], [Bus Pirate], [BUS_PIRATE]]]) m4_define([OPTIONAL_LIBRARIES], [[[capstone], [Use Capstone disassembly framework], []]]) AC_ARG_ENABLE([doxygen-html], AS_HELP_STRING([--disable-doxygen-html], [Disable building Doxygen manual as HTML.]), [doxygen_as_html=$enableval], [doxygen_as_html=yes]) AC_SUBST([doxygen_as_html]) AC_MSG_CHECKING([whether to build Doxygen as HTML]) AC_MSG_RESULT([$doxygen_as_html]) AC_ARG_ENABLE([doxygen-pdf], AS_HELP_STRING([--enable-doxygen-pdf], [Enable building Doxygen manual as PDF.]), [doxygen_as_pdf=$enableval], [doxygen_as_pdf=no]) AC_SUBST([doxygen_as_pdf]) AC_MSG_CHECKING([whether to build Doxygen as PDF]) AC_MSG_RESULT([$doxygen_as_pdf]) AC_ARG_ENABLE([gccwarnings], AS_HELP_STRING([--disable-gccwarnings], [Disable compiler warnings]), [gcc_warnings=$enableval], [gcc_warnings=yes]) AC_ARG_ENABLE([wextra], AS_HELP_STRING([--disable-wextra], [Disable extra compiler warnings]), [gcc_wextra=$enableval], [gcc_wextra=$gcc_warnings]) AC_ARG_ENABLE([werror], AS_HELP_STRING([--disable-werror], [Do not treat warnings as errors]), [gcc_werror=$enableval], [gcc_werror=$gcc_warnings]) # set default verbose options, overridden by following options debug_usb_io=no debug_usb_comms=no AC_ARG_ENABLE([verbose], AS_HELP_STRING([--enable-verbose], [Enable verbose JTAG I/O messages (for debugging).]), [ debug_usb_io=$enableval debug_usb_comms=$enableval ], []) AC_ARG_ENABLE([verbose_usb_io], AS_HELP_STRING([--enable-verbose-usb-io], [Enable verbose USB I/O messages (for debugging)]), [debug_usb_io=$enableval], []) AC_ARG_ENABLE([verbose_usb_comms], AS_HELP_STRING([--enable-verbose-usb-comms], [Enable verbose USB communication messages (for debugging)]), [debug_usb_comms=$enableval], []) AC_MSG_CHECKING([whether to enable verbose USB I/O messages]); AC_MSG_RESULT([$debug_usb_io]) AS_IF([test "x$debug_usb_io" = "xyes"], [ AC_DEFINE([_DEBUG_USB_IO_],[1], [Print verbose USB I/O messages]) ]) AC_MSG_CHECKING([whether to enable verbose USB communication messages]); AC_MSG_RESULT([$debug_usb_comms]) AS_IF([test "x$debug_usb_comms" = "xyes"], [ AC_DEFINE([_DEBUG_USB_COMMS_],[1], [Print verbose USB communication messages]) ]) debug_malloc=no AC_ARG_ENABLE([malloc_logging], AS_HELP_STRING([--enable-malloc-logging], [Include free space in logging messages (requires malloc.h).]), [debug_malloc=$enableval], []) AC_MSG_CHECKING([whether to enable malloc free space logging]); AC_MSG_RESULT([$debug_malloc]) AS_IF([test "x$debug_malloc" = "xyes"], [ AC_DEFINE([_DEBUG_FREE_SPACE_],[1], [Include malloc free space in logging]) ]) AC_ARG_ENABLE([dummy], AS_HELP_STRING([--enable-dummy], [Enable building the dummy port driver]), [build_dummy=$enableval], [build_dummy=no]) AC_ARG_ENABLE([rshim], AS_HELP_STRING([--enable-rshim], [Enable building the rshim driver]), [build_rshim=$enableval], [build_rshim=no]) m4_define([AC_ARG_ADAPTERS], [ m4_foreach([adapter], [$1], [AC_ARG_ENABLE(ADAPTER_OPT([adapter]), AS_HELP_STRING([--enable-ADAPTER_OPT([adapter])], [Enable building support for the ]ADAPTER_DESC([adapter])[ (default is $2)]), [], [ADAPTER_VAR([adapter])=$2]) ]) ]) AC_ARG_ADAPTERS([ USB1_ADAPTERS, HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, LIBFTDI_USB1_ADAPTERS LIBGPIOD_ADAPTERS, SERIAL_PORT_ADAPTERS, LIBJAYLINK_ADAPTERS ],[auto]) AC_ARG_ENABLE([parport], AS_HELP_STRING([--enable-parport], [Enable building the pc parallel port driver]), [build_parport=$enableval], [build_parport=no]) AC_ARG_ENABLE([parport_ppdev], AS_HELP_STRING([--disable-parport-ppdev], [Disable use of ppdev (/dev/parportN) for parport (for x86 only)]), [parport_use_ppdev=$enableval], [parport_use_ppdev=yes]) AC_ARG_ENABLE([parport_giveio], AS_HELP_STRING([--enable-parport-giveio], [Enable use of giveio for parport (for CygWin only)]), [parport_use_giveio=$enableval], [parport_use_giveio=]) AC_ARG_ENABLE([jtag_vpi], AS_HELP_STRING([--enable-jtag_vpi], [Enable building support for JTAG VPI]), [build_jtag_vpi=$enableval], [build_jtag_vpi=no]) AC_ARG_ENABLE([vdebug], AS_HELP_STRING([--enable-vdebug], [Enable building support for Cadence Virtual Debug Interface]), [build_vdebug=$enableval], [build_vdebug=no]) AC_ARG_ENABLE([jtag_dpi], AS_HELP_STRING([--enable-jtag_dpi], [Enable building support for JTAG DPI]), [build_jtag_dpi=$enableval], [build_jtag_dpi=no]) AC_ARG_ENABLE([amtjtagaccel], AS_HELP_STRING([--enable-amtjtagaccel], [Enable building the Amontec JTAG-Accelerator driver]), [build_amtjtagaccel=$enableval], [build_amtjtagaccel=no]) AS_CASE(["${host_cpu}"], [arm*|aarch64], [ AC_ARG_ENABLE([bcm2835gpio], AS_HELP_STRING([--enable-bcm2835gpio], [Enable building support for bitbanging on BCM2835 (as found in Raspberry Pi)]), [build_bcm2835gpio=$enableval], [build_bcm2835gpio=no]) AC_ARG_ENABLE([imx_gpio], AS_HELP_STRING([--enable-imx_gpio], [Enable building support for bitbanging on NXP IMX processors]), [build_imx_gpio=$enableval], [build_imx_gpio=no]) AC_ARG_ENABLE([am335xgpio], AS_HELP_STRING([--enable-am335xgpio], [Enable building support for bitbanging on AM335x (as found in Beaglebones)]), [build_am335xgpio=$enableval], [build_am335xgpio=no]) ], [ build_bcm2835gpio=no build_imx_gpio=no build_am335xgpio=no ]) AS_CASE(["${host_cpu}"], [arm*], [ AC_ARG_ENABLE([ep93xx], AS_HELP_STRING([--enable-ep93xx], [Enable building support for EP93xx based SBCs]), [build_ep93xx=$enableval], [build_ep93xx=no]) AC_ARG_ENABLE([at91rm9200], AS_HELP_STRING([--enable-at91rm9200], [Enable building support for AT91RM9200 based SBCs]), [build_at91rm9200=$enableval], [build_at91rm9200=no]) ], [ build_ep93xx=no build_at91rm9200=no ]) AC_ARG_ENABLE([gw16012], AS_HELP_STRING([--enable-gw16012], [Enable building support for the Gateworks GW16012 JTAG Programmer]), [build_gw16012=$enableval], [build_gw16012=no]) AC_ARG_ENABLE([sysfsgpio], AS_HELP_STRING([--enable-sysfsgpio], [Enable building support for programming driven via sysfs gpios.]), [build_sysfsgpio=$enableval], [build_sysfsgpio=no]) AC_ARG_ENABLE([xlnx_pcie_xvc], AS_HELP_STRING([--enable-xlnx-pcie-xvc], [Enable building support for Xilinx XVC/PCIe.]), [build_xlnx_pcie_xvc=$enableval], [build_xlnx_pcie_xvc=no]) AS_CASE([$host_os], [linux*], [], [ AS_IF([test "x$build_sysfsgpio" = "xyes"], [ AC_MSG_ERROR([sysfsgpio is only available on linux]) ]) AS_IF([test "x$enable_linuxgpiod" = "xyes"], [ AC_MSG_ERROR([linuxgpiod is only available on linux]) ]) AS_IF([test "x$build_xlnx_pcie_xvc" = "xyes"], [ AC_MSG_ERROR([xlnx_pcie_xvc is only available on linux]) ]) AS_CASE([$host_os], [freebsd*], [], [ AS_IF([test "x$build_rshim" = "xyes"], [ AC_MSG_ERROR([build_rshim is only available on linux or freebsd]) ]) ]) ]) AC_ARG_ENABLE([internal-jimtcl], AS_HELP_STRING([--disable-internal-jimtcl], [Disable building internal jimtcl]), [use_internal_jimtcl=$enableval], [use_internal_jimtcl=yes]) AC_ARG_ENABLE([jimtcl-maintainer], AS_HELP_STRING([--enable-jimtcl-maintainer], [Enable maintainer mode when building internal jimtcl]), [use_internal_jimtcl_maintainer=$enableval], [use_internal_jimtcl_maintainer=no]) AC_ARG_ENABLE([internal-libjaylink], AS_HELP_STRING([--enable-internal-libjaylink], [Enable building internal libjaylink]), [use_internal_libjaylink=$enableval], [use_internal_libjaylink=no]) AC_ARG_ENABLE([remote-bitbang], AS_HELP_STRING([--enable-remote-bitbang], [Enable building support for the Remote Bitbang jtag driver]), [build_remote_bitbang=$enableval], [build_remote_bitbang=no]) AS_CASE(["${host_cpu}"], [i?86|x86*], [], [ AS_IF([test "x$parport_use_ppdev" = "xno"], [ AC_MSG_WARN([--disable-parport-ppdev is not supported by the host CPU]) ]) parport_use_ppdev=yes ]) AS_CASE([$host], [*-cygwin*], [ is_win32=yes parport_use_ppdev=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[return __MINGW32__;]])], [is_mingw=yes],[is_mingw=no]) AS_IF([test "x$is_mingw" = "xyes"], [ AS_IF([test "x$parport_use_giveio" = "xno"], [ AC_MSG_WARN([--disable-parport-giveio is not supported by MinGW32 hosts]) ]) parport_use_giveio=yes is_cygwin=no ], [ is_cygwin=yes # sys/io.h needed under cygwin for parport access AS_IF([test "x$build_parport" = "xyes"], [ AC_CHECK_HEADERS([sys/io.h],[],AC_MSG_ERROR([Please install the cygwin ioperm package])) ]) ]) ], [*-mingw* | *-msys*], [ is_mingw=yes is_win32=yes parport_use_ppdev=no AS_IF([test "x$parport_use_giveio" = "xno"], [ AC_MSG_WARN([--disable-parport-giveio is not supported by MinGW32 hosts]) ]) parport_use_giveio=yes AS_IF([test "x$enable_buspirate" = "xyes"], [ AC_MSG_ERROR([buspirate currently not supported by MinGW32 hosts]) ]) # In case enable_buspirate=auto, make sure it will not be built. enable_buspirate=no AC_SUBST([HOST_CPPFLAGS], [-D__USE_MINGW_ANSI_STDIO]) ], [*darwin*], [ is_darwin=yes AS_IF([test "x$parport_use_giveio" = "xyes"], [ AC_MSG_WARN([--enable-parport-giveio cannot be used by Darwin hosts]) ]) parport_use_giveio=no ], [ AS_IF([test "x$parport_use_giveio" = "xyes"], [ AC_MSG_WARN([--enable-parport-giveio cannot be used by ]$host[ hosts]) ]) parport_use_giveio=no ]) AS_IF([test "x$is_cygwin" = "xyes"], [ AC_DEFINE([IS_CYGWIN], [1], [1 if building for Cygwin.]) ], [ AC_DEFINE([IS_CYGWIN], [0], [0 if not building for Cygwin.]) ]) AS_IF([test "x$is_mingw" = "xyes"], [ AC_DEFINE([IS_MINGW], [1], [1 if building for Mingw.]) ], [ AC_DEFINE([IS_MINGW], [0], [0 if not building for Mingw.]) ]) AS_IF([test "x$is_win32" = "xyes"], [ AC_DEFINE([IS_WIN32], [1], [1 if building for Win32.]) ], [ AC_DEFINE([IS_WIN32], [0], [0 if not building for Win32.]) ]) AS_IF([test "x$is_darwin" = "xyes"], [ AC_DEFINE([IS_DARWIN], [1], [1 if building for Darwin.]) ], [ AC_DEFINE([IS_DARWIN], [0], [0 if not building for Darwin.]) ]) AS_IF([test "x$build_parport" = "xyes"], [ build_bitbang=yes AC_DEFINE([BUILD_PARPORT], [1], [1 if you want parport.]) ], [ AC_DEFINE([BUILD_PARPORT], [0], [0 if you don't want parport.]) ]) AS_IF([test "x$build_rshim" = "xyes"], [ AC_DEFINE([BUILD_RSHIM], [1], [1 if you want to debug BlueField SoC via rshim.]) ], [ AC_DEFINE([BUILD_RSHIM], [0], [0 if you don't want to debug BlueField SoC via rshim.]) ]) AS_IF([test "x$build_dummy" = "xyes"], [ build_bitbang=yes AC_DEFINE([BUILD_DUMMY], [1], [1 if you want dummy driver.]) ], [ AC_DEFINE([BUILD_DUMMY], [0], [0 if you don't want dummy driver.]) ]) AS_IF([test "x$build_ep93xx" = "xyes"], [ build_bitbang=yes AC_DEFINE([BUILD_EP93XX], [1], [1 if you want ep93xx.]) ], [ AC_DEFINE([BUILD_EP93XX], [0], [0 if you don't want ep93xx.]) ]) AS_IF([test "x$build_at91rm9200" = "xyes"], [ build_bitbang=yes AC_DEFINE([BUILD_AT91RM9200], [1], [1 if you want at91rm9200.]) ], [ AC_DEFINE([BUILD_AT91RM9200], [0], [0 if you don't want at91rm9200.]) ]) AS_IF([test "x$build_bcm2835gpio" = "xyes"], [ build_bitbang=yes AC_DEFINE([BUILD_BCM2835GPIO], [1], [1 if you want bcm2835gpio.]) ], [ AC_DEFINE([BUILD_BCM2835GPIO], [0], [0 if you don't want bcm2835gpio.]) ]) AS_IF([test "x$build_imx_gpio" = "xyes"], [ build_bitbang=yes AC_DEFINE([BUILD_IMX_GPIO], [1], [1 if you want imx_gpio.]) ], [ AC_DEFINE([BUILD_IMX_GPIO], [0], [0 if you don't want imx_gpio.]) ]) AS_IF([test "x$build_am335xgpio" = "xyes"], [ build_bitbang=yes AC_DEFINE([BUILD_AM335XGPIO], [1], [1 if you want am335xgpio.]) ], [ AC_DEFINE([BUILD_AM335XGPIO], [0], [0 if you don't want am335xgpio.]) ]) AS_IF([test "x$parport_use_ppdev" = "xyes"], [ AC_DEFINE([PARPORT_USE_PPDEV], [1], [1 if you want parport to use ppdev.]) ], [ AC_DEFINE([PARPORT_USE_PPDEV], [0], [0 if you don't want parport to use ppdev.]) ]) AS_IF([test "x$parport_use_giveio" = "xyes"], [ AC_DEFINE([PARPORT_USE_GIVEIO], [1], [1 if you want parport to use giveio.]) ], [ AC_DEFINE([PARPORT_USE_GIVEIO], [0], [0 if you don't want parport to use giveio.]) ]) AS_IF([test "x$build_jtag_vpi" = "xyes"], [ AC_DEFINE([BUILD_JTAG_VPI], [1], [1 if you want JTAG VPI.]) ], [ AC_DEFINE([BUILD_JTAG_VPI], [0], [0 if you don't want JTAG VPI.]) ]) AS_IF([test "x$build_vdebug" = "xyes"], [ AC_DEFINE([BUILD_VDEBUG], [1], [1 if you want Cadence vdebug interface.]) ], [ AC_DEFINE([BUILD_VDEBUG], [0], [0 if you don't want Cadence vdebug interface.]) ]) AS_IF([test "x$build_jtag_dpi" = "xyes"], [ AC_DEFINE([BUILD_JTAG_DPI], [1], [1 if you want JTAG DPI.]) ], [ AC_DEFINE([BUILD_JTAG_DPI], [0], [0 if you don't want JTAG DPI.]) ]) AS_IF([test "x$build_amtjtagaccel" = "xyes"], [ AC_DEFINE([BUILD_AMTJTAGACCEL], [1], [1 if you want the Amontec JTAG-Accelerator driver.]) ], [ AC_DEFINE([BUILD_AMTJTAGACCEL], [0], [0 if you don't want the Amontec JTAG-Accelerator driver.]) ]) AS_IF([test "x$build_gw16012" = "xyes"], [ AC_DEFINE([BUILD_GW16012], [1], [1 if you want the Gateworks GW16012 driver.]) ], [ AC_DEFINE([BUILD_GW16012], [0], [0 if you don't want the Gateworks GW16012 driver.]) ]) AS_IF([test "x$enable_buspirate" != "xno"], [ AC_DEFINE([BUILD_BUSPIRATE], [1], [1 if you want the Buspirate JTAG driver.]) ], [ AC_DEFINE([BUILD_BUSPIRATE], [0], [0 if you don't want the Buspirate JTAG driver.]) ]) AS_IF([test "x$use_internal_jimtcl" = "xyes"], [ AS_IF([test -f "$srcdir/jimtcl/configure"], [ AS_IF([test "x$use_internal_jimtcl_maintainer" = "xyes"], [ jimtcl_config_options="--disable-install-jim --with-ext=json --minimal --disable-ssl --maintainer" ], [ jimtcl_config_options="--disable-install-jim --with-ext=json --minimal --disable-ssl" ]) AX_CONFIG_SUBDIR_OPTION([jimtcl], [$jimtcl_config_options]) ], [ AC_MSG_ERROR([jimtcl not found, run git submodule init and git submodule update.]) ]) ]) AS_IF([test "x$build_remote_bitbang" = "xyes"], [ build_bitbang=yes AC_DEFINE([BUILD_REMOTE_BITBANG], [1], [1 if you want the Remote Bitbang JTAG driver.]) ], [ AC_DEFINE([BUILD_REMOTE_BITBANG], [0], [0 if you don't want the Remote Bitbang JTAG driver.]) ]) AS_IF([test "x$build_sysfsgpio" = "xyes"], [ build_bitbang=yes AC_DEFINE([BUILD_SYSFSGPIO], [1], [1 if you want the SysfsGPIO driver.]) ], [ AC_DEFINE([BUILD_SYSFSGPIO], [0], [0 if you don't want SysfsGPIO driver.]) ]) AS_IF([test "x$build_xlnx_pcie_xvc" = "xyes"], [ build_xlnx_pcie_xvc=yes AC_DEFINE([BUILD_XLNX_PCIE_XVC], [1], [1 if you want the Xilinx XVC/PCIe driver.]) ], [ AC_DEFINE([BUILD_XLNX_PCIE_XVC], [0], [0 if you don't want Xilinx XVC/PCIe driver.]) ]) PKG_CHECK_MODULES([LIBUSB1], [libusb-1.0], [ use_libusb1=yes AC_DEFINE([HAVE_LIBUSB1], [1], [Define if you have libusb-1.x]) LIBUSB1_CFLAGS=`echo $LIBUSB1_CFLAGS | sed 's/-I/-isystem /'` AC_MSG_NOTICE([libusb-1.0 header bug workaround: LIBUSB1_CFLAGS changed to "$LIBUSB1_CFLAGS"]) PKG_CHECK_EXISTS([libusb-1.0 >= 1.0.16], [AC_DEFINE([HAVE_LIBUSB_GET_PORT_NUMBERS], [1], [Define if your libusb has libusb_get_port_numbers()])]) ], [ use_libusb1=no AC_MSG_WARN([libusb-1.x not found, trying legacy libusb-0.1 as a fallback; consider installing libusb-1.x instead]) ]) AC_ARG_WITH([capstone], AS_HELP_STRING([--with-capstone], [Use Capstone disassembly library (default=auto)]) , [ enable_capstone=$withval ], [ enable_capstone=auto ]) AS_IF([test "x$enable_capstone" != xno], [ PKG_CHECK_MODULES([CAPSTONE], [capstone], [ AC_DEFINE([HAVE_CAPSTONE], [1], [1 if you have Capstone disassembly framework.]) ], [ if test "x$enable_capstone" != xauto; then AC_MSG_ERROR([--with-capstone was given, but test for Capstone failed]) fi enable_capstone=no ]) ]) AS_IF([test "x$enable_capstone" == xno], [ AC_DEFINE([HAVE_CAPSTONE], [0], [0 if you don't have Capstone disassembly framework.]) ]) for hidapi_lib in hidapi hidapi-hidraw hidapi-libusb; do PKG_CHECK_MODULES([HIDAPI],[$hidapi_lib],[ use_hidapi=yes break ],[ use_hidapi=no ]) done PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [ use_libftdi=yes PKG_CHECK_EXISTS([libftdi1 >= 1.5], [AC_DEFINE([HAVE_LIBFTDI_TCIOFLUSH], [1], [Define if your libftdi has ftdi_tcioflush()])]) ], [ PKG_CHECK_MODULES([LIBFTDI], [libftdi], [use_libftdi=yes], [use_libftdi=no]) ]) PKG_CHECK_MODULES([LIBGPIOD], [libgpiod], [use_libgpiod=yes], [use_libgpiod=no]) PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.2], [use_libjaylink=yes], [use_libjaylink=no]) m4_define([PROCESS_ADAPTERS], [ m4_foreach([adapter], [$1], [ AS_IF([test $2], [ AS_IF([test "x$ADAPTER_VAR([adapter])" != "xno"], [ AC_DEFINE([BUILD_]ADAPTER_SYM([adapter]), [1], [1 if you want the ]ADAPTER_DESC([adapter]).) ], [ AC_DEFINE([BUILD_]ADAPTER_SYM([adapter]), [0], [0 if you do not want the ]ADAPTER_DESC([adapter]).) ]) ], [ AS_IF([test "x$ADAPTER_VAR([adapter])" = "xyes"], [ AC_MSG_ERROR([$3 is required for the ADAPTER_DESC([adapter])]) ]) ADAPTER_VAR([adapter])=no AC_DEFINE([BUILD_]ADAPTER_SYM([adapter]), [0], [0 if you do not want the ]ADAPTER_DESC([adapter]).) ]) AM_CONDITIONAL(ADAPTER_SYM([adapter]), [test "x$ADAPTER_VAR([adapter])" != "xno"]) ]) ]) PROCESS_ADAPTERS([USB1_ADAPTERS], ["x$use_libusb1" = "xyes"], [libusb-1.x]) PROCESS_ADAPTERS([HIDAPI_ADAPTERS], ["x$use_hidapi" = "xyes"], [hidapi]) PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libusb1" = "xyes"], [hidapi and libusb-1.x]) PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi]) PROCESS_ADAPTERS([LIBFTDI_USB1_ADAPTERS], ["x$use_libftdi" = "xyes" -a "x$use_libusb1" = "xyes"], [libftdi and libusb-1.x]) PROCESS_ADAPTERS([LIBGPIOD_ADAPTERS], ["x$use_libgpiod" = "xyes"], [libgpiod]) PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libjaylink-0.2]) AS_IF([test "x$enable_linuxgpiod" != "xno"], [ build_bitbang=yes ]) AS_IF([test "x$enable_stlink" != "xno" -o "x$enable_ti_icdi" != "xno" -o "x$enable_nulink" != "xno"], [ AC_DEFINE([BUILD_HLADAPTER], [1], [1 if you want the High Level JTAG driver.]) AM_CONDITIONAL([HLADAPTER], [true]) ], [ AC_DEFINE([BUILD_HLADAPTER], [0], [0 if you want the High Level JTAG driver.]) AM_CONDITIONAL([HLADAPTER], [false]) ]) AM_CONDITIONAL([HLADAPTER_STLINK], [test "x$enable_stlink" != "xno"]) AM_CONDITIONAL([HLADAPTER_ICDI], [test "x$enable_ti_icdi" != "xno"]) AM_CONDITIONAL([HLADAPTER_NULINK], [test "x$enable_nulink" != "xno"]) AS_IF([test "x$enable_jlink" != "xno"], [ AS_IF([test "x$use_internal_libjaylink" = "xyes"], [ AS_IF([test -f "$srcdir/src/jtag/drivers/libjaylink/configure.ac"], [ AX_CONFIG_SUBDIR_OPTION([src/jtag/drivers/libjaylink], [--enable-subproject-build]) ], [ AC_MSG_ERROR([Internal libjaylink not found, run 'git submodule init' and 'git submodule update'.]) ]) ]) ]) # Presto needs the bitq module AS_IF([test "x$enable_presto" != "xno"], [ build_bitq=yes ]) # esp-usb-jtag also needs the bitq module AS_IF([test "x$enable_esp_usb_jtag" != "xno"], [ build_bitq=yes ]) AM_CONDITIONAL([RELEASE], [test "x$build_release" = "xyes"]) AM_CONDITIONAL([PARPORT], [test "x$build_parport" = "xyes"]) AM_CONDITIONAL([DUMMY], [test "x$build_dummy" = "xyes"]) AM_CONDITIONAL([GIVEIO], [test "x$parport_use_giveio" = "xyes"]) AM_CONDITIONAL([EP93XX], [test "x$build_ep93xx" = "xyes"]) AM_CONDITIONAL([AT91RM9200], [test "x$build_at91rm9200" = "xyes"]) AM_CONDITIONAL([BCM2835GPIO], [test "x$build_bcm2835gpio" = "xyes"]) AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"]) AM_CONDITIONAL([AM335XGPIO], [test "x$build_am335xgpio" = "xyes"]) AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "xyes"]) AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes"]) AM_CONDITIONAL([VDEBUG], [test "x$build_vdebug" = "xyes"]) AM_CONDITIONAL([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes"]) AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o "x$enable_usb_blaster_2" != "xno"]) AM_CONDITIONAL([AMTJTAGACCEL], [test "x$build_amtjtagaccel" = "xyes"]) AM_CONDITIONAL([GW16012], [test "x$build_gw16012" = "xyes"]) AM_CONDITIONAL([REMOTE_BITBANG], [test "x$build_remote_bitbang" = "xyes"]) AM_CONDITIONAL([BUSPIRATE], [test "x$enable_buspirate" != "xno"]) AM_CONDITIONAL([SYSFSGPIO], [test "x$build_sysfsgpio" = "xyes"]) AM_CONDITIONAL([XLNX_PCIE_XVC], [test "x$build_xlnx_pcie_xvc" = "xyes"]) AM_CONDITIONAL([USE_LIBUSB1], [test "x$use_libusb1" = "xyes"]) AM_CONDITIONAL([IS_CYGWIN], [test "x$is_cygwin" = "xyes"]) AM_CONDITIONAL([IS_MINGW], [test "x$is_mingw" = "xyes"]) AM_CONDITIONAL([IS_WIN32], [test "x$is_win32" = "xyes"]) AM_CONDITIONAL([IS_DARWIN], [test "x$is_darwin" = "xyes"]) AM_CONDITIONAL([BITQ], [test "x$build_bitq" = "xyes"]) AM_CONDITIONAL([USE_LIBFTDI], [test "x$use_libftdi" = "xyes"]) AM_CONDITIONAL([USE_LIBGPIOD], [test "x$use_libgpiod" = "xyes"]) AM_CONDITIONAL([USE_HIDAPI], [test "x$use_hidapi" = "xyes"]) AM_CONDITIONAL([USE_LIBJAYLINK], [test "x$use_libjaylink" = "xyes"]) AM_CONDITIONAL([RSHIM], [test "x$build_rshim" = "xyes"]) AM_CONDITIONAL([HAVE_CAPSTONE], [test "x$enable_capstone" != "xno"]) AM_CONDITIONAL([INTERNAL_JIMTCL], [test "x$use_internal_jimtcl" = "xyes"]) AM_CONDITIONAL([INTERNAL_LIBJAYLINK], [test "x$use_internal_libjaylink" = "xyes"]) # Look for environ alternatives. Possibility #1: is environ in unistd.h or stdlib.h? AC_MSG_CHECKING([for environ in unistd.h and stdlib.h]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #define _GNU_SOURCE #include #include ]], [[char **ep = environ;]] )], [ AC_MSG_RESULT([yes]) has_environ=yes ], [ AC_MSG_RESULT([no]) # Possibility #2: can environ be found in an available library? AC_MSG_CHECKING([for extern environ]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ extern char **environ; ]], [[char **ep = environ;]] )], [ AC_DEFINE(NEED_ENVIRON_EXTERN, [1], [Must declare 'environ' to use it.]) has_environ=yes ], [ has_environ=no ]) AC_MSG_RESULT([${has_environ}]) ]) AS_IF([test "x${has_environ}" != "xyes" ], [ AC_MSG_FAILURE([Could not find 'environ' in unistd.h or available libraries.]) ]) AC_DEFINE([_GNU_SOURCE],[1],[Use GNU C library extensions (e.g. stdndup).]) # set default gcc warnings GCC_WARNINGS="-Wall -Wstrict-prototypes -Wformat-security -Wshadow" AS_IF([test "x${gcc_wextra}" = "xyes"], [ GCC_WARNINGS="${GCC_WARNINGS} -Wextra -Wno-unused-parameter" GCC_WARNINGS="${GCC_WARNINGS} -Wbad-function-cast" GCC_WARNINGS="${GCC_WARNINGS} -Wcast-align" GCC_WARNINGS="${GCC_WARNINGS} -Wredundant-decls" GCC_WARNINGS="${GCC_WARNINGS} -Wpointer-arith" GCC_WARNINGS="${GCC_WARNINGS} -Wundef" ]) AS_IF([test "x${gcc_werror}" = "xyes"], [ GCC_WARNINGS="${GCC_WARNINGS} -Werror" ]) # override default gcc cflags AS_IF([test "x$gcc_warnings" = "xyes"], [ AC_SUBST([GCC_WARNINGS], [$GCC_WARNINGS]) ]) AC_SUBST(EXTRA_DIST_NEWS, ["$(echo $srcdir/NEWS-*)"]) AC_CONFIG_FILES([ Makefile ]) AC_OUTPUT AS_IF([test "x$enable_jlink" != "xno"], [ AS_IF([test "x$use_internal_libjaylink" = "xyes"], [ AC_MSG_WARN([Using the internal libjaylink is deprecated and will not be possible in the future.]) ]]) ) echo echo echo OpenOCD configuration summary echo -------------------------------------------------- m4_foreach([adapter], [USB1_ADAPTERS, HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, LIBFTDI_USB1_ADAPTERS, LIBGPIOD_ADAPTERS, LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS, SERIAL_PORT_ADAPTERS, OPTIONAL_LIBRARIES], [s=m4_format(["%-40s"], ADAPTER_DESC([adapter])) AS_CASE([$ADAPTER_VAR([adapter])], [auto], [ echo "$s"yes '(auto)' ], [yes], [ echo "$s"yes ], [no], [ echo "$s"no ]) ]) echo ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/60-openocd.rules ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copy this file to /etc/udev/rules.d/ # If rules fail to reload automatically, you can refresh udev rules # with the command "udevadm control --reload" ACTION!="add|change", GOTO="openocd_rules_end" SUBSYSTEM=="gpio", MODE="0660", GROUP="plugdev", TAG+="uaccess" SUBSYSTEM!="usb|tty|hidraw", GOTO="openocd_rules_end" # Please keep this list sorted by VID:PID # opendous and estick ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204f", MODE="660", GROUP="plugdev", TAG+="uaccess" # Original FT232/FT245 VID:PID ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="660", GROUP="plugdev", TAG+="uaccess" # Original FT2232 VID:PID ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess" # Original FT4232 VID:PID ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="660", GROUP="plugdev", TAG+="uaccess" # Original FT232H VID:PID ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="660", GROUP="plugdev", TAG+="uaccess" # Original FT231XQ VID:PID ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", MODE="660", GROUP="plugdev", TAG+="uaccess" # DISTORTEC JTAG-lock-pick Tiny 2 ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8220", MODE="660", GROUP="plugdev", TAG+="uaccess" # TUMPA, TUMPA Lite ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a98", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a99", MODE="660", GROUP="plugdev", TAG+="uaccess" # Marvell OpenRD JTAGKey FT2232D B ATTRS{idVendor}=="0403", ATTRS{idProduct}=="9e90", MODE="660", GROUP="plugdev", TAG+="uaccess" # XDS100v2 ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d0", MODE="660", GROUP="plugdev", TAG+="uaccess" # XDS100v3 ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d1", MODE="660", GROUP="plugdev", TAG+="uaccess" # OOCDLink ATTRS{idVendor}=="0403", ATTRS{idProduct}=="baf8", MODE="660", GROUP="plugdev", TAG+="uaccess" # Kristech KT-Link ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bbe2", MODE="660", GROUP="plugdev", TAG+="uaccess" # Xverve Signalyzer Tool (DT-USB-ST), Signalyzer LITE (DT-USB-SLITE) ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca1", MODE="660", GROUP="plugdev", TAG+="uaccess" # TI/Luminary Stellaris Evaluation Board FTDI (several) ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd9", MODE="660", GROUP="plugdev", TAG+="uaccess" # TI/Luminary Stellaris In-Circuit Debug Interface FTDI (ICDI) Board ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcda", MODE="660", GROUP="plugdev", TAG+="uaccess" # egnite Turtelizer 2 ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bdc8", MODE="660", GROUP="plugdev", TAG+="uaccess" # Section5 ICEbear ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c140", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="660", GROUP="plugdev", TAG+="uaccess" # Amontec JTAGkey and JTAGkey-tiny ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="660", GROUP="plugdev", TAG+="uaccess" # ASIX Presto programmer ATTRS{idVendor}=="0403", ATTRS{idProduct}=="f1a0", MODE="660", GROUP="plugdev", TAG+="uaccess" # Nuvoton NuLink ATTRS{idVendor}=="0416", ATTRS{idProduct}=="511b", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0416", ATTRS{idProduct}=="511c", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0416", ATTRS{idProduct}=="511d", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0416", ATTRS{idProduct}=="5200", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0416", ATTRS{idProduct}=="5201", MODE="660", GROUP="plugdev", TAG+="uaccess" # TI ICDI ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="660", GROUP="plugdev", TAG+="uaccess" # STMicroelectronics ST-LINK V1 ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3744", MODE="660", GROUP="plugdev", TAG+="uaccess" # STMicroelectronics ST-LINK/V2 ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE="660", GROUP="plugdev", TAG+="uaccess" # STMicroelectronics ST-LINK/V2.1 ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3752", MODE="660", GROUP="plugdev", TAG+="uaccess" # STMicroelectronics STLINK-V3 ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374d", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374e", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374f", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3753", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3754", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3755", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3757", MODE="660", GROUP="plugdev", TAG+="uaccess" # Cypress SuperSpeed Explorer Kit ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="0007", MODE="660", GROUP="plugdev", TAG+="uaccess" # Cypress KitProg in KitProg mode ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="f139", MODE="660", GROUP="plugdev", TAG+="uaccess" # Cypress KitProg in CMSIS-DAP mode ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="f138", MODE="660", GROUP="plugdev", TAG+="uaccess" # Infineon DAP miniWiggler v3 ATTRS{idVendor}=="058b", ATTRS{idProduct}=="0043", MODE="660", GROUP="plugdev", TAG+="uaccess" # Hitex LPC1768-Stick ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0026", MODE="660", GROUP="plugdev", TAG+="uaccess" # Hilscher NXHX Boards ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="660", GROUP="plugdev", TAG+="uaccess" # Hitex STR9-comStick ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002c", MODE="660", GROUP="plugdev", TAG+="uaccess" # Hitex STM32-PerformanceStick ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="660", GROUP="plugdev", TAG+="uaccess" # Hitex Cortino ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0032", MODE="660", GROUP="plugdev", TAG+="uaccess" # Altera USB Blaster ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6001", MODE="660", GROUP="plugdev", TAG+="uaccess" # Altera USB Blaster2 ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6810", MODE="660", GROUP="plugdev", TAG+="uaccess" # Ashling Opella-LD ATTRS{idVendor}=="0B6B", ATTRS{idProduct}=="0040", MODE="660", GROUP="plugdev", TAG+="uaccess" # Amontec JTAGkey-HiSpeed ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="660", GROUP="plugdev", TAG+="uaccess" # SEGGER J-Link ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0101", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0102", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0103", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0104", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0105", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0107", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0108", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1010", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1011", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1012", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1013", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1014", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1015", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1016", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1017", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1018", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1020", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1051", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1055", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1061", MODE="660", GROUP="plugdev", TAG+="uaccess" # Raisonance RLink ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="660", GROUP="plugdev", TAG+="uaccess" # Debug Board for Neo1973 ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="660", GROUP="plugdev", TAG+="uaccess" # OSBDM ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="0042", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="0058", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="005e", MODE="660", GROUP="plugdev", TAG+="uaccess" # Olimex ARM-USB-OCD ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="660", GROUP="plugdev", TAG+="uaccess" # Olimex ARM-USB-OCD-TINY ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0004", MODE="660", GROUP="plugdev", TAG+="uaccess" # Olimex ARM-JTAG-EW ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="001e", MODE="660", GROUP="plugdev", TAG+="uaccess" # Olimex ARM-USB-OCD-TINY-H ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="660", GROUP="plugdev", TAG+="uaccess" # Olimex ARM-USB-OCD-H ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002b", MODE="660", GROUP="plugdev", TAG+="uaccess" # ixo-usb-jtag - Emulation of a Altera Bus Blaster I on a Cypress FX2 IC ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="06ad", MODE="660", GROUP="plugdev", TAG+="uaccess" # USBprog with OpenOCD firmware ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="660", GROUP="plugdev", TAG+="uaccess" # TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="660", GROUP="plugdev", TAG+="uaccess" # TI XDS110 Debug Probe (Launchpads and Standalone) ATTRS{idVendor}=="0451", ATTRS{idProduct}=="bef3", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0451", ATTRS{idProduct}=="bef4", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="02a5", MODE="660", GROUP="plugdev", TAG+="uaccess" # TI Tiva-based ICDI and XDS110 probes in DFU mode ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00ff", MODE="660", GROUP="plugdev", TAG+="uaccess" # isodebug v1 ATTRS{idVendor}=="22b7", ATTRS{idProduct}=="150d", MODE="660", GROUP="plugdev", TAG+="uaccess" # PLS USB/JTAG Adapter for SPC5xxx ATTRS{idVendor}=="263d", ATTRS{idProduct}=="4001", MODE="660", GROUP="plugdev", TAG+="uaccess" # Numato Mimas A7 - Artix 7 FPGA Board ATTRS{idVendor}=="2a19", ATTRS{idProduct}=="1009", MODE="660", GROUP="plugdev", TAG+="uaccess" # Ambiq Micro EVK and Debug boards. ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6011", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="1106", MODE="660", GROUP="plugdev", TAG+="uaccess" # Espressif USB JTAG/serial debug units ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1002", MODE="660", GROUP="plugdev", TAG+="uaccess" # Marvell Sheevaplug ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="660", GROUP="plugdev", TAG+="uaccess" # Keil Software, Inc. ULink ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2710", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2750", MODE="660", GROUP="plugdev", TAG+="uaccess" # CMSIS-DAP compatible adapters ATTRS{product}=="*CMSIS-DAP*", MODE="660", GROUP="plugdev", TAG+="uaccess" LABEL="openocd_rules_end" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/buildroot/openocd_be_defconfig ================================================ # SPDX-License-Identifier: GPL-2.0-or-later BR2_armeb=y BR2_cortex_a7=y BR2_TOOLCHAIN_EXTERNAL=y BR2_PACKAGE_OPENOCD=y BR2_PACKAGE_OPENOCD_FTDI=y BR2_PACKAGE_OPENOCD_STLINK=y BR2_PACKAGE_OPENOCD_TI_ICDI=y BR2_PACKAGE_OPENOCD_ULINK=y BR2_PACKAGE_OPENOCD_UBLASTER2=y BR2_PACKAGE_OPENOCD_JLINK=y BR2_PACKAGE_OPENOCD_OSDBM=y BR2_PACKAGE_OPENOCD_OPENDOUS=y BR2_PACKAGE_OPENOCD_VSLLINK=y BR2_PACKAGE_OPENOCD_USBPROG=y BR2_PACKAGE_OPENOCD_RLINK=y BR2_PACKAGE_OPENOCD_ARMEW=y BR2_PACKAGE_OPENOCD_XDS110=y BR2_PACKAGE_OPENOCD_PARPORT=y BR2_PACKAGE_OPENOCD_VPI=y BR2_PACKAGE_OPENOCD_UBLASTER=y BR2_PACKAGE_OPENOCD_AMTJT=y BR2_PACKAGE_OPENOCD_GW16012=y BR2_PACKAGE_OPENOCD_PRESTO=y BR2_PACKAGE_OPENOCD_OPENJTAG=y BR2_PACKAGE_OPENOCD_BUSPIRATE=y BR2_PACKAGE_OPENOCD_SYSFS=y ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/coresight-trace.txt ================================================ +OpenOCD and CoreSight Tracing + Many recent ARM chips (Using e..g. Cortex-M3 and Cortex-M4 cores) support CoreSight debug/trace. This note sketches an approach currently planned for those cores with OpenOCD. This tracing data can help debug and tune ARM software, but not all cores support tracing. Some support more extensive tracing other cores with trace support +should be able to use the same approach and maybe some of the same analysis code. +the Cortex-M3 is assumed here to be the +core in use, for simplicity and to reflect current OpenOCD users. This note summarizes a software model to generate, collect, and analyze such trace data . That is not fully implemented as of early January 2011, +and thus is not *yet* usable. + + +Some microcontroller cores support a low pin-count Single-wire trace, with a mode where +trace data is emitted (usually to a UART. To use this mode, +SWD must be in use. +At this writing, OpenOCD SWD support is not yet complete either. (There are also multi-wire trace ports requiring more complex debug adapters than OpenOCD currently supports, and offering richer data. + + +* ENABLING involves activating SWD and (single wire) trace. + +current expectations are that OpenOCD itself will handle enabling; activating single wire trace involves a debug adapter interaction, and collecting that trace data requires particular (re)wiring. + +* CONFIGURATION involves setting up ITM and/or ETM modules to emit the +desired data from the Cortex core. (This might include dumping +event counters printf-style messages; code profiling; and more. Not all +cores offer the same trace capabilities. + +current expectations are that Tcl scripts will be used to configure these +modules for the desired tracing, by direct writes to registers. In some +cases (as with RTOS event tracking and similar messaging, this might +be augmented or replaced by user code running on the ARM core. + +COLLECTION involves reading that trace data, probably through UART, and +saving it in a useful format to analyse For now, deferred analysis modes are assumed, not than real-time or interactive ones. + + +current expectations are to to dump data in text using contrib/itmdump.c +or derived tools, and to post-process it into reports. Such reports might +include program messaging (such as application data streams via ITM, maybe +using printf type messaging; code coverage analysis or so forth. Recent +versions of CMSIS software reserve some ITM codespace for RTOS event tracing and include ITM messaging support. Clearly some of that data would be valuable for interactive debugging. + +Should someone get ambitious, GUI reports should be possible. GNU tools +for simpler reports like gprof may be simpler to support at first. +In any case, OpenOCD is not currently GUI-oriented. Accordingly, we now +expect any such graphics to come from postprocessing. measurements for RTOS event timings should also be easy to collect. +Examples include context and message switch times, as well as times for application interactions. + ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/cross-build.sh ================================================ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # This is an example of how to do a cross-build of OpenOCD using pkg-config. # Cross-building with pkg-config is deceptively hard and most guides and # tutorials are incomplete or give bad advice. Some of the traps that are easy # to fall in but handled by this script are: # # * Polluting search paths and flags with values from the build system. # * Faulty pkg-config wrappers shipped with distribution packaged cross- # toolchains. # * Build failing because pkg-config discards some paths even though they are # correctly listed in the .pc file. # * Getting successfully built binaries that cannot find runtime data because # paths refer to the build file system. # # This script is probably more useful as a reference than as a complete build # tool but for some configurations it may be usable as-is. It only cross-builds # libusb-1.0, hidapi, libftdi and capstone from source, but the script can be # extended to build other prerequisites in a similar manner. # # Usage: # export LIBUSB1_SRC=/path/to/libusb-1.0 # export HIDAPI_SRC=/path/to/hidapi # export OPENOCD_CONFIG="--enable-..." # cd /work/dir # /path/to/openocd/contrib/cross-build.sh # # For static linking, a workaround is to # export LIBUSB1_CONFIG="--enable-static --disable-shared" # # All the paths must not contain any spaces. set -e -x WORK_DIR=$PWD ## Source code paths, customize as necessary : ${OPENOCD_SRC:="`dirname "$0"`/.."} : ${LIBUSB1_SRC:=/path/to/libusb1} : ${HIDAPI_SRC:=/path/to/hidapi} : ${LIBFTDI_SRC:=/path/to/libftdi} : ${CAPSTONE_SRC:=/path/to/capstone} : ${LIBJAYLINK_SRC:=/path/to/libjaylink} OPENOCD_SRC=`readlink -m $OPENOCD_SRC` LIBUSB1_SRC=`readlink -m $LIBUSB1_SRC` HIDAPI_SRC=`readlink -m $HIDAPI_SRC` LIBFTDI_SRC=`readlink -m $LIBFTDI_SRC` CAPSTONE_SRC=`readlink -m $CAPSTONE_SRC` LIBJAYLINK_SRC=`readlink -m $LIBJAYLINK_SRC` HOST_TRIPLET=$1 BUILD_DIR=$WORK_DIR/$HOST_TRIPLET-build LIBUSB1_BUILD_DIR=$BUILD_DIR/libusb1 HIDAPI_BUILD_DIR=$BUILD_DIR/hidapi LIBFTDI_BUILD_DIR=$BUILD_DIR/libftdi CAPSTONE_BUILD_DIR=$BUILD_DIR/capstone LIBJAYLINK_BUILD_DIR=$BUILD_DIR/libjaylink OPENOCD_BUILD_DIR=$BUILD_DIR/openocd ## Root of host file tree SYSROOT=$WORK_DIR/$HOST_TRIPLET-root ## Install location within host file tree : ${PREFIX=/usr} ## Make parallel jobs : ${MAKE_JOBS:=1} ## OpenOCD-only install dir for packaging : ${OPENOCD_TAG:=`git --git-dir=$OPENOCD_SRC/.git describe --tags`} PACKAGE_DIR=$WORK_DIR/openocd_${OPENOCD_TAG}_${HOST_TRIPLET} ####### # Create pkg-config wrapper and make sure it's used export PKG_CONFIG=$WORK_DIR/$HOST_TRIPLET-pkg-config cat > $PKG_CONFIG <.cmake file ESCAPED_SYSROOT=$(printf '%s\n' "$SYSROOT" | sed -e 's/[\/&]/\\&/g') sed -i -E "s/(SET\(CMAKE_FIND_ROOT_PATH\s+).+\)/\1${ESCAPED_SYSROOT})/" \ ${LIBFTDI_SRC}/cmake/Toolchain-${HOST_TRIPLET}.cmake cmake $LIBFTDI_CONFIG \ -DCMAKE_TOOLCHAIN_FILE=${LIBFTDI_SRC}/cmake/Toolchain-${HOST_TRIPLET}.cmake \ -DCMAKE_INSTALL_PREFIX=${PREFIX} \ -DPKG_CONFIG_EXECUTABLE=`which pkg-config` \ $LIBFTDI_SRC make install DESTDIR=$SYSROOT fi # capstone build & install into sysroot if [ -d $CAPSTONE_SRC ] ; then mkdir -p $CAPSTONE_BUILD_DIR cd $CAPSTONE_BUILD_DIR cp -r $CAPSTONE_SRC/* . make install DESTDIR=$SYSROOT PREFIX=$PREFIX \ CROSS="${HOST_TRIPLET}-" \ $CAPSTONE_CONFIG # fix the generated capstone.pc CAPSTONE_PC_FILE=${SYSROOT}${PREFIX}/lib/pkgconfig/capstone.pc sed -i '/^libdir=/d' $CAPSTONE_PC_FILE sed -i '/^includedir=/d' $CAPSTONE_PC_FILE sed -i '/^archive=/d' $CAPSTONE_PC_FILE sed -i '1s;^;prefix=/usr \ exec_prefix=${prefix} \ libdir=${exec_prefix}/lib \ includedir=${prefix}/include/capstone\n\n;' $CAPSTONE_PC_FILE fi # libjaylink build & install into sysroot if [ -d $LIBJAYLINK_SRC ] ; then mkdir -p $LIBJAYLINK_BUILD_DIR cd $LIBJAYLINK_BUILD_DIR $LIBJAYLINK_SRC/configure --build=`$LIBJAYLINK_SRC/config.guess` --host=$HOST_TRIPLET \ --with-sysroot=$SYSROOT --prefix=$PREFIX \ $LIBJAYLINK_CONFIG make -j $MAKE_JOBS make install DESTDIR=$SYSROOT fi # OpenOCD build & install into sysroot mkdir -p $OPENOCD_BUILD_DIR cd $OPENOCD_BUILD_DIR $OPENOCD_SRC/configure --build=`$OPENOCD_SRC/config.guess` --host=$HOST_TRIPLET \ --with-sysroot=$SYSROOT --prefix=$PREFIX \ $OPENOCD_CONFIG make -j $MAKE_JOBS make install-strip DESTDIR=$SYSROOT # Separate OpenOCD install w/o dependencies. OpenOCD will have to be linked # statically or have dependencies packaged/installed separately. make install-strip DESTDIR=$PACKAGE_DIR ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/gen-stellaris-part-header.pl ================================================ #!/usr/bin/perl # SPDX-License-Identifier: GPL-2.0-or-later # Automatically generates the StellarisParts struct in src/flash/nor/stellaris.c # Uses the header files from TI/Luminary's StellarisWare complete Firmware Development Package # available from: http://www.luminarymicro.com/products/software_updates.html $comment = "// Autogenerated by contrib/gen-stellaris-part-header.pl // From Stellaris Firmware Development Package revision"; $struct_header = "static const struct { uint8_t class; uint8_t partno; const char *partname; } StellarisParts[] = { "; $struct_footer = "\t{0xFF, 0x00, \"Unknown Part\"}\n};\n"; $#ARGV == 1 || die "Usage: $0 \n"; -d $ARGV[0] || die $ARGV[0]." is not a directory\n"; $dir = $ARGV[0]; -f $ARGV[1] || die $ARGV[1]." is not a file\n"; $file = $ARGV[1]; print STDERR "Scanning $dir, Updating $file\n"; opendir(DIR, $dir) || die "can't open $dir: $!"; @files = readdir(DIR); closedir(DIR); @header_files = sort(grep(/lm.+\.h/, @files)); $ver = 0; $new_struct = $struct_header; process_file(@header_files); $new_struct .= $struct_footer; $dump = "$comment $ver\n$new_struct"; { local($/, *INPUT); open(INPUT, $file) || die "can't open $file: $!"; $contents = ; close(INPUT); } $old_struct = qr/((^\/\/.*?\n)*)\Q$struct_header\E.*?$struct_footer/sm; $contents =~ s/$old_struct/$dump/; open(OUTPUT, ">$file") || die "can't open file $file for writing: $!"; print OUTPUT $contents; close(OUTPUT); sub process_file { foreach $h_file (@_) { ($base) = ($h_file =~ m/lm..(.{3,7})\.h/ig); $base = uc($base); local($/, *FILE); open(FILE, "$dir/$h_file"); $content = ; close(FILE); $invalid = 0; if ($content =~ /This is part of revision (\d+) of/) { if ($ver != 0 and $ver != $1) { print STDERR "File version mismatch: $ver != $1\n"; $ver = max($ver, $1); } else { $ver = $1; } } if ($content =~ /SYSCTL_DID0_CLASS_[^M].+?0x(\S+)/s) { $class = hex($1) >> 16; } else { # attempt another way to get class if ($content =~ /\s(\S+)-class/) { $class = getclass($1); if ($class eq 0xFF) { print STDERR "$h_file unknown class\n"; $invalid = 1; } } else { print STDERR "$h_file is missing SYSCTL_DID0_CLASS_\n"; $class = 0; $invalid = 1; } } if ($content =~ /SYSCTL_DID1_PRTNO_$base.+0x(\S+)/) { $prtno = hex($1); $base = "LM3S" . $base; } else { # LM4F have a changed header if ($content =~ /SYSCTL_DID1_PRTNO_LM4F$base.+?0x(\S+)/s) { $prtno = hex($1); $base = "LM4F" . $base; } else { print STDERR "$h_file is missing SYSCTL_DID1_PRTNO\n"; $prtno = 0; $invalid = 1; } } $new_member = sprintf "{0x%02X, 0x%02X, \"%s\"},", $class, $prtno >> 16, $base; if ($invalid == 1) { #$new_struct .= "\t//$new_member\t// Invalid\n"; } else { $new_struct .= "\t$new_member\n"; } } } sub getclass { $class = $_[0]; if ($class =~ /Sandstorm/i) { return 0; } elsif ($class =~ /Fury/i) { return 1; } elsif ($class =~ /DustDevil/i) { return 3; } elsif ($class =~ /Tempest/i) { return 4; } elsif ($class =~ /Blizzard/i) { return 5; } elsif ($class =~ /Firestorm/i) { return 6; } return 0xFF; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/itmdump.c ================================================ // SPDX-License-Identifier: GPL-3.0-or-later /* Copyright (C) 2010 by David Brownell */ /* * Simple utility to parse and dump ARM Cortex-M3 SWO trace output. Once the * mechanisms work right, this information can be used for various purposes * including profiling (particularly easy for flat PC-sample profiles) and * for debugging. * * SWO is the Single Wire Output found on some ARM cores, most notably on the * Cortex-M3. It combines data from several sources: * * - Software trace (ITM): so-called "printf-style" application messaging * using "ITM stimulus ports"; and differential timestamps. * - Hardware trace (DWT): for profiling counters and comparator matches. * - TPIU may issue sync packets. * * The trace data format is defined in Appendix E, "Debug ITM and DWT packet * protocol", of the ARMv7-M Architecture Reference Manual (DDI 0403C). It * is a superset of the ITM data format from the Coresight TRM. * * The trace data has two encodings. The working assumption is that data * gets into this program using the UART encoding. */ #include #include #include #include #include #include #include unsigned int dump_swit; /* Example ITM trace word (0xWWXXYYZZ) parsing for task events, sent * on port 31 (Reserved for "the" RTOS in CMSIS v1.30) * WWXX: event code (0..3 pre-assigned, 4..15 reserved) * YY: task priority * ZZ: task number * * NOTE that this specific encoding could be space-optimized; and that * trace data streams could also be history-sensitive. */ static void show_task(int port, unsigned data) { unsigned code = data >> 16; char buf[16]; if (dump_swit) return; switch (code) { case 0: strcpy(buf, "run"); break; case 1: strcpy(buf, "block"); break; case 2: strcpy(buf, "create"); break; case 3: strcpy(buf, "destroy"); break; /* 4..15 reserved for other infrastructure ops */ default: sprintf(buf, "code %d", code); break; } printf("TASK %d, pri %d: %s", (data >> 0) & 0xff, (data >> 8) & 0xff, buf); } static void show_reserved(FILE *f, char *label, int c) { unsigned i; if (dump_swit) return; printf("%s - %#02x", label, c); for (i = 0; (c & 0x80) && i < 4; i++) { c = fgetc(f); if (c == EOF) { printf("(ERROR %d - %s) ", errno, strerror(errno)); break; } printf(" %#02x", c); } printf("\n"); } static bool read_varlen(FILE *f, int c, unsigned *value) { unsigned size; unsigned char buf[4]; *value = 0; switch (c & 3) { case 3: size = 4; break; case 2: size = 2; break; case 1: size = 1; break; default: printf("INVALID SIZE\n"); return false; } memset(buf, 0, sizeof buf); if (fread(buf, 1, size, f) != size) goto err; *value = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + (buf[0] << 0); return true; err: printf("(ERROR %d - %s)\n", errno, strerror(errno)); return false; } static void show_hard(FILE *f, int c) { unsigned type = c >> 3; unsigned value; char *label; if (dump_swit) return; printf("DWT - "); if (!read_varlen(f, c, &value)) return; printf("%#x", value); switch (type) { case 0: /* event counter wrapping */ printf("overflow %s%s%s%s%s%s", (value & (1 << 5)) ? "cyc " : "", (value & (1 << 4)) ? "fold " : "", (value & (1 << 3)) ? "lsu " : "", (value & (1 << 2)) ? "slp " : "", (value & (1 << 1)) ? "exc " : "", (value & (1 << 0)) ? "cpi " : ""); break; case 1: /* exception tracing */ switch (value >> 12) { case 1: label = "entry to"; break; case 2: label = "exit from"; break; case 3: label = "return to"; break; default: label = "?"; break; } printf("%s exception %d", label, value & 0x1ff); break; case 2: /* PC sampling */ if (c == 0x15) printf("PC - sleep"); else printf("PC - %#08x", value); break; case 8: /* data tracing, pc value */ case 10: case 12: case 14: printf("Data trace %d, PC %#08x", (c >> 4) & 3, value); /* optionally followed by data value */ break; case 9: /* data tracing, address offset */ case 11: case 13: case 15: printf("Data trace %d, address offset %#04x", (c >> 4) & 3, value); /* always followed by data value */ break; case 16 ... 23: /* data tracing, data value */ printf("Data trace %d, ", (c >> 4) & 3); label = (c & 0x8) ? "write" : "read"; switch (c & 3) { case 3: printf("word %s, value %#08x", label, value); break; case 2: printf("halfword %s, value %#04x", label, value); break; case 1: printf("byte %s, value %#02x", label, value); break; } break; default: printf("UNDEFINED, rawtype: %x", type); break; } printf("\n"); return; } /* * Table of SWIT (SoftWare InstrumentTation) message dump formats, for * ITM port 0..31 application data. * * Eventually this should be customizable; all usage is application defined. * * REVISIT there can be up to 256 trace ports, via "ITM Extension" packets */ struct { int port; void (*show)(int port, unsigned data); } format[] = { { .port = 31, .show = show_task, }, }; static void show_swit(FILE *f, int c) { unsigned port = c >> 3; unsigned value = 0; unsigned i; if (port + 1 == dump_swit) { if (!read_varlen(f, c, &value)) return; printf("%c", value); return; } if (!read_varlen(f, c, &value)) return; if (dump_swit) return; printf("SWIT %u - ", port); printf("%#08x", value); for (i = 0; i < sizeof(format) / sizeof(format[0]); i++) { if (format[i].port == port) { printf(", "); format[i].show(port, value); break; } } printf("\n"); return; } static void show_timestamp(FILE *f, int c) { unsigned counter = 0; char *label = ""; bool delayed = false; if (dump_swit) return; printf("TIMESTAMP - "); /* Format 2: header only */ if (!(c & 0x80)) { switch (c) { case 0: /* sync packet -- coding error! */ case 0x70: /* overflow -- ditto! */ printf("ERROR - %#02x\n", c); break; default: /* synchronous to ITM */ counter = c >> 4; goto done; } return; } /* Format 1: one to four bytes of data too */ switch (c >> 4) { default: label = ", reserved control\n"; break; case 0xc: /* synchronous to ITM */ break; case 0xd: label = ", timestamp delayed"; delayed = true; break; case 0xe: label = ", packet delayed"; delayed = true; break; case 0xf: label = ", packet and timestamp delayed"; delayed = true; break; } c = fgetc(f); if (c == EOF) goto err; counter = c & 0x7f; if (!(c & 0x80)) goto done; c = fgetc(f); if (c == EOF) goto err; counter |= (c & 0x7f) << 7; if (!(c & 0x80)) goto done; c = fgetc(f); if (c == EOF) goto err; counter |= (c & 0x7f) << 14; if (!(c & 0x80)) goto done; c = fgetc(f); if (c == EOF) goto err; counter |= (c & 0x7f) << 21; done: /* REVISIT should we try to convert from delta values? */ printf("+%u%s\n", counter, label); return; err: printf("(ERROR %d - %s) ", errno, strerror(errno)); goto done; } int main(int argc, char **argv) { FILE *f = stdin; int c; /* parse arguments */ while ((c = getopt(argc, argv, "f:d:")) != EOF) { switch (c) { case 'f': /* e.g. from UART connected to /dev/ttyUSB0 */ f = fopen(optarg, "r"); if (!f) { perror(optarg); return 1; } break; case 'd': dump_swit = atoi(optarg); break; default: fprintf(stderr, "usage: %s [-f input]", basename(argv[0])); return 1; } } /* Parse data ... records have a header then data bytes. * NOTE: we assume getc() deals in 8-bit bytes. */ bool overflow = false; while ((c = getc(f)) != EOF) { /* Sync packet ... 7 zeroes, 0x80 */ if (c == 0) { int i; for (i = 0; i < 6; i++) { c = fgetc(f); if (c == EOF) break; if (c != 0) goto bad_sync; } c = fgetc(f); if (c == 0x80) { printf("SYNC\n"); continue; } bad_sync: printf("BAD SYNC\n"); continue; } /* Overflow packet */ if (c == 0x70) { /* REVISIT later, report just what overflowed! * Timestamp and SWIT can happen. Non-ITM too? */ overflow = true; printf("OVERFLOW ...\n"); continue; } overflow = false; switch (c & 0x0f) { case 0x00: /* Timestamp */ show_timestamp(f, c); break; case 0x04: /* "Reserved" */ show_reserved(f, "RESERVED", c); break; case 0x08: /* ITM Extension */ /* FIXME someday, handle these ... */ show_reserved(f, "ITM EXT", c); break; case 0x0c: /* DWT Extension */ show_reserved(f, "DWT EXT", c); break; default: if (c & 4) show_hard(f, c); else show_swit(f, c); break; } } return 0; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/libdcc/README ================================================ This code is an example of using the openocd debug message system. Before the message output is seen in the debug window, the functionality will need enabling: From the gdb prompt: monitor target_request debugmsgs enable monitor trace point 1 From the Telnet prompt: target_request debugmsgs enable trace point 1 To see how many times the trace point was hit: (monitor) trace point 1 Spen spen@spen-soft.co.uk ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/libdcc/dcc_stdio.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2008 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * Copyright (C) 2008 by Frederik Kriewtz * * frederik@kriewitz.eu * ***************************************************************************/ #include "dcc_stdio.h" #define TARGET_REQ_TRACEMSG 0x00 #define TARGET_REQ_DEBUGMSG_ASCII 0x01 #define TARGET_REQ_DEBUGMSG_HEXMSG(size) (0x01 | ((size & 0xff) << 8)) #define TARGET_REQ_DEBUGCHAR 0x02 #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_6SM__) /* we use the System Control Block DCRDR reg to simulate a arm7_9 dcc channel * DCRDR[7:0] is used by target for status * DCRDR[15:8] is used by target for write buffer * DCRDR[23:16] is used for by host for status * DCRDR[31:24] is used for by host for write buffer */ #define NVIC_DBG_DATA_R (*((volatile unsigned short *)0xE000EDF8)) #define BUSY 1 void dbg_write(unsigned long dcc_data) { int len = 4; while (len--) { /* wait for data ready */ while (NVIC_DBG_DATA_R & BUSY); /* write our data and set write flag - tell host there is data*/ NVIC_DBG_DATA_R = (unsigned short)(((dcc_data & 0xff) << 8) | BUSY); dcc_data >>= 8; } } #elif defined(__ARM_ARCH_4T__) || defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5T__) void dbg_write(unsigned long dcc_data) { unsigned long dcc_status; do { asm volatile("mrc p14, 0, %0, c0, c0" : "=r" (dcc_status)); } while (dcc_status & 0x2); asm volatile("mcr p14, 0, %0, c1, c0" : : "r" (dcc_data)); } #else #error unsupported target #endif void dbg_trace_point(unsigned long number) { dbg_write(TARGET_REQ_TRACEMSG | (number << 8)); } void dbg_write_u32(const unsigned long *val, long len) { dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(4) | ((len & 0xffff) << 16)); while (len > 0) { dbg_write(*val); val++; len--; } } void dbg_write_u16(const unsigned short *val, long len) { unsigned long dcc_data; dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(2) | ((len & 0xffff) << 16)); while (len > 0) { dcc_data = val[0] | ((len > 1) ? val[1] << 16: 0x0000); dbg_write(dcc_data); val += 2; len -= 2; } } void dbg_write_u8(const unsigned char *val, long len) { unsigned long dcc_data; dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(1) | ((len & 0xffff) << 16)); while (len > 0) { dcc_data = val[0] | ((len > 1) ? val[1] << 8 : 0x00) | ((len > 2) ? val[2] << 16 : 0x00) | ((len > 3) ? val[3] << 24 : 0x00); dbg_write(dcc_data); val += 4; len -= 4; } } void dbg_write_str(const char *msg) { long len; unsigned long dcc_data; for (len = 0; msg[len] && (len < 65536); len++); dbg_write(TARGET_REQ_DEBUGMSG_ASCII | ((len & 0xffff) << 16)); while (len > 0) { dcc_data = msg[0] | ((len > 1) ? msg[1] << 8 : 0x00) | ((len > 2) ? msg[2] << 16 : 0x00) | ((len > 3) ? msg[3] << 24 : 0x00); dbg_write(dcc_data); msg += 4; len -= 4; } } void dbg_write_char(char msg) { dbg_write(TARGET_REQ_DEBUGCHAR | ((msg & 0xff) << 16)); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/libdcc/dcc_stdio.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2008 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef DCC_STDIO_H #define DCC_STDIO_H void dbg_trace_point(unsigned long number); void dbg_write_u32(const unsigned long *val, long len); void dbg_write_u16(const unsigned short *val, long len); void dbg_write_u8(const unsigned char *val, long len); void dbg_write_str(const char *msg); void dbg_write_char(char msg); #endif /* DCC_STDIO_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/libdcc/example.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * Copyright (C) 2008 by Frederik Kriewtz * * frederik@kriewitz.eu * ***************************************************************************/ #include "dcc_stdio.h" /* enable openocd debugmsg at the gdb prompt: * monitor target_request debugmsgs enable * * create a trace point: * monitor trace point 1 * * to show how often the trace point was hit: * monitor trace point */ int main(void) { dbg_write_str("hello world"); dbg_write_char('t'); dbg_write_char('e'); dbg_write_char('s'); dbg_write_char('t'); dbg_write_char('\n'); unsigned long test_u32 = 0x01234567; dbg_write_u32(&test_u32, 1); static const unsigned short test_u16[] = {0x0123, 0x4567, 0x89AB, 0xCDEF, 0x0123, 0x4567, 0x89AB, 0xCDEF}; dbg_write_u16(test_u16, 8); static const unsigned char test_u8[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0XDD, 0xEE, 0xFF}; dbg_write_u8(test_u8, 16); while(1) { dbg_trace_point(0); } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/list_example.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* Copyright (C) 2021 by Andreas Fritiofson */ /* * Simple example of using a circular doubly linked list through list.h * * gcc -I ../src/ list_example.c -o list_example */ #include #include #include #include static LIST_HEAD(threads); struct thread { int id; uint64_t tcb_address; struct list_head lh; }; void insert(struct thread *t) { list_add_tail(&t->lh, &threads); } void remove(struct thread *t) { list_del(&t->lh); } struct thread *lookup_id(int id) { struct thread *t; list_for_each_entry(t, &threads, lh) { if (t->id == id) return t; } return NULL; } struct thread *lookup_tcb(uint64_t addr) { struct thread *t; list_for_each_entry(t, &threads, lh) { if (t->tcb_address == addr) return t; } return NULL; } int main(void) { struct thread t1 = { .id = 1, .tcb_address = 111111111 }; struct thread t2 = { .id = 2, .tcb_address = 222222222 }; struct thread t3 = { .id = 3, .tcb_address = 333333333 }; insert(&t1); insert(&t2); assert(lookup_id(1) == &t1); assert(lookup_tcb(111111111) == &t1); assert(lookup_id(2) == &t2); assert(lookup_id(42) == NULL); remove(&t1); assert(lookup_id(1) == NULL); insert(&t3); remove(&t2); assert(lookup_id(3) == &t3); assert(lookup_tcb(333333333) == &t3); assert(lookup_id(2) == NULL); remove(&t3); assert(list_empty(&threads)); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/README ================================================ Included in these directories are the src to the various ram loaders used within openocd. ** target checksum loaders ** checksum/armv4_5_crc.s : - ARMv4 and ARMv5 checksum loader : see target/arm_crc_code.c:arm_crc_code checksum/armv7m_crc.s : - ARMv7m checksum loader : see target/armv7m.c:cortex_m_crc_code checksum/mips32.s : - MIPS32 checksum loader : see target/mips32.c:mips_crc_code ** target flash loaders ** flash/pic32mx.s : - Microchip PIC32 flash loader : see flash/nor/pic32mx.c:pic32mx_flash_write_code flash/stellaris.s : - TI Stellaris flash loader : see flash/nor/stellaris.c:stellaris_write_code flash/stm32x.s : - ST STM32 flash loader : see flash/nor/stm32x.c:stm32x_flash_write_code flash/str7x.s : - ST STR7 flash loader : see flash/nor/str7x.c:str7x_flash_write_code flash/str9x.s : - ST STR9 flash loader : see flash/nor/str9x.c:str9x_flash_write_code Spencer Oliver spen@spen-soft.co.uk ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/checksum/armv4_5_crc.inc ================================================ /* Autogenerated with ../../../src/helper/bin2char.sh */ 0x00,0x20,0xa0,0xe1,0x00,0x00,0xe0,0xe3,0x01,0x30,0xa0,0xe1,0x00,0x40,0xa0,0xe3, 0x0b,0x00,0x00,0xea,0x04,0x10,0xd2,0xe7,0x30,0x70,0x9f,0xe5,0x01,0x0c,0x20,0xe0, 0x00,0x50,0xa0,0xe3,0x00,0x00,0x50,0xe3,0x80,0x60,0xa0,0xe1,0x01,0x50,0x85,0xe2, 0x06,0x00,0xa0,0xe1,0x07,0x00,0x26,0xb0,0x08,0x00,0x55,0xe3,0xf8,0xff,0xff,0x1a, 0x01,0x40,0x84,0xe2,0x03,0x00,0x54,0xe1,0xf1,0xff,0xff,0x1a,0x70,0x00,0x20,0xe1, 0xb7,0x1d,0xc1,0x04, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/checksum/armv4_5_crc.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ /* r0 - address in - crc out r1 - char count */ .text .arm _start: main: mov r2, r0 mov r0, #0xffffffff /* crc */ mov r3, r1 mov r4, #0 b ncomp nbyte: ldrb r1, [r2, r4] ldr r7, CRC32XOR eor r0, r0, r1, asl #24 mov r5, #0 loop: cmp r0, #0 mov r6, r0, asl #1 add r5, r5, #1 mov r0, r6 eorlt r0, r6, r7 cmp r5, #8 bne loop add r4, r4, #1 ncomp: cmp r4, r3 bne nbyte end: bkpt #0 CRC32XOR: .word 0x04c11db7 .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/checksum/armv7m_crc.inc ================================================ /* Autogenerated with ../../../src/helper/bin2char.sh */ 0x02,0x46,0x00,0x20,0xc0,0x43,0x0a,0x4e,0x0b,0x46,0x00,0x24,0x0d,0xe0,0x11,0x5d, 0x09,0x06,0x48,0x40,0x00,0x25,0x00,0x28,0x02,0xda,0x40,0x00,0x70,0x40,0x00,0xe0, 0x40,0x00,0x01,0x35,0x08,0x2d,0xf6,0xd1,0x01,0x34,0x9c,0x42,0xef,0xd1,0x00,0xbe, 0xb7,0x1d,0xc1,0x04, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/checksum/armv7m_crc.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ /* parameters: r0 - address in - crc out r1 - char count */ .text .syntax unified .cpu cortex-m0 .thumb .thumb_func .align 2 _start: main: mov r2, r0 movs r0, #0 mvns r0, r0 ldr r6, CRC32XOR mov r3, r1 movs r4, #0 b ncomp nbyte: ldrb r1, [r2, r4] lsls r1, r1, #24 eors r0, r0, r1 movs r5, #0 loop: cmp r0, #0 bge notset lsls r0, r0, #1 eors r0, r0, r6 b cont notset: lsls r0, r0, #1 cont: adds r5, r5, #1 cmp r5, #8 bne loop adds r4, r4, #1 ncomp: cmp r4, r3 bne nbyte bkpt #0 .align 2 CRC32XOR: .word 0x04c11db7 .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/checksum/mips32.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ .global main .text .set noreorder /* params: * $a0 address in * $a1 byte count * vars * $a0 crc * $a1 crc data byte * temps: * t3 v0 a3 a2 t0 v1 */ .ent main main: addiu $t4, $a0, 0 /* address in */ addiu $t2, $a1, 0 /* count */ addiu $a0, $zero, 0xffffffff /* a0 crc - result */ beq $zero, $zero, ncomp addiu $t3, $zero, 0 /* clear bytes read */ nbyte: lb $a1, ($t4) /* load byte from source address */ addi $t4, $t4, 1 /* inc byte count */ crc: sll $a1, $a1, 24 lui $v0, 0x04c1 xor $a0, $a0, $a1 ori $a3, $v0, 0x1db7 addu $a2, $zero, $zero /* clear bit count */ loop: sll $t0, $a0, 1 addiu $a2, $a2, 1 /* inc bit count */ slti $a0, $a0, 0 xor $t1, $t0, $a3 movn $t0, $t1, $a0 slti $v1, $a2, 8 /* 8bits processed */ bne $v1, $zero, loop addu $a0, $t0, $zero ncomp: bne $t2, $t3, nbyte /* all bytes processed */ addiu $t3, $t3, 1 wait: sdbbp .end main ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/checksum/riscv32_crc.inc ================================================ /* Autogenerated with ../../../src/helper/bin2char.sh */ 0xb3,0x05,0xb5,0x00,0x93,0x07,0xf0,0xff,0x17,0x07,0x00,0x00,0x13,0x07,0x47,0x04, 0x63,0x1a,0xb5,0x00,0x13,0x85,0x07,0x00,0x73,0x00,0x10,0x00,0x13,0x85,0x07,0x00, 0x67,0x80,0x00,0x00,0x03,0x46,0x05,0x00,0x93,0x96,0x87,0x00,0x93,0xd7,0x87,0x01, 0xb3,0xc7,0xc7,0x00,0x93,0x97,0x27,0x00,0xb3,0x07,0xf7,0x00,0x83,0xa7,0x07,0x00, 0x13,0x05,0x15,0x00,0xb3,0xc7,0xf6,0x00,0x6f,0xf0,0x9f,0xfc,0x00,0x00,0x00,0x00, 0xb7,0x1d,0xc1,0x04,0x6e,0x3b,0x82,0x09,0xd9,0x26,0x43,0x0d,0xdc,0x76,0x04,0x13, 0x6b,0x6b,0xc5,0x17,0xb2,0x4d,0x86,0x1a,0x05,0x50,0x47,0x1e,0xb8,0xed,0x08,0x26, 0x0f,0xf0,0xc9,0x22,0xd6,0xd6,0x8a,0x2f,0x61,0xcb,0x4b,0x2b,0x64,0x9b,0x0c,0x35, 0xd3,0x86,0xcd,0x31,0x0a,0xa0,0x8e,0x3c,0xbd,0xbd,0x4f,0x38,0x70,0xdb,0x11,0x4c, 0xc7,0xc6,0xd0,0x48,0x1e,0xe0,0x93,0x45,0xa9,0xfd,0x52,0x41,0xac,0xad,0x15,0x5f, 0x1b,0xb0,0xd4,0x5b,0xc2,0x96,0x97,0x56,0x75,0x8b,0x56,0x52,0xc8,0x36,0x19,0x6a, 0x7f,0x2b,0xd8,0x6e,0xa6,0x0d,0x9b,0x63,0x11,0x10,0x5a,0x67,0x14,0x40,0x1d,0x79, 0xa3,0x5d,0xdc,0x7d,0x7a,0x7b,0x9f,0x70,0xcd,0x66,0x5e,0x74,0xe0,0xb6,0x23,0x98, 0x57,0xab,0xe2,0x9c,0x8e,0x8d,0xa1,0x91,0x39,0x90,0x60,0x95,0x3c,0xc0,0x27,0x8b, 0x8b,0xdd,0xe6,0x8f,0x52,0xfb,0xa5,0x82,0xe5,0xe6,0x64,0x86,0x58,0x5b,0x2b,0xbe, 0xef,0x46,0xea,0xba,0x36,0x60,0xa9,0xb7,0x81,0x7d,0x68,0xb3,0x84,0x2d,0x2f,0xad, 0x33,0x30,0xee,0xa9,0xea,0x16,0xad,0xa4,0x5d,0x0b,0x6c,0xa0,0x90,0x6d,0x32,0xd4, 0x27,0x70,0xf3,0xd0,0xfe,0x56,0xb0,0xdd,0x49,0x4b,0x71,0xd9,0x4c,0x1b,0x36,0xc7, 0xfb,0x06,0xf7,0xc3,0x22,0x20,0xb4,0xce,0x95,0x3d,0x75,0xca,0x28,0x80,0x3a,0xf2, 0x9f,0x9d,0xfb,0xf6,0x46,0xbb,0xb8,0xfb,0xf1,0xa6,0x79,0xff,0xf4,0xf6,0x3e,0xe1, 0x43,0xeb,0xff,0xe5,0x9a,0xcd,0xbc,0xe8,0x2d,0xd0,0x7d,0xec,0x77,0x70,0x86,0x34, 0xc0,0x6d,0x47,0x30,0x19,0x4b,0x04,0x3d,0xae,0x56,0xc5,0x39,0xab,0x06,0x82,0x27, 0x1c,0x1b,0x43,0x23,0xc5,0x3d,0x00,0x2e,0x72,0x20,0xc1,0x2a,0xcf,0x9d,0x8e,0x12, 0x78,0x80,0x4f,0x16,0xa1,0xa6,0x0c,0x1b,0x16,0xbb,0xcd,0x1f,0x13,0xeb,0x8a,0x01, 0xa4,0xf6,0x4b,0x05,0x7d,0xd0,0x08,0x08,0xca,0xcd,0xc9,0x0c,0x07,0xab,0x97,0x78, 0xb0,0xb6,0x56,0x7c,0x69,0x90,0x15,0x71,0xde,0x8d,0xd4,0x75,0xdb,0xdd,0x93,0x6b, 0x6c,0xc0,0x52,0x6f,0xb5,0xe6,0x11,0x62,0x02,0xfb,0xd0,0x66,0xbf,0x46,0x9f,0x5e, 0x08,0x5b,0x5e,0x5a,0xd1,0x7d,0x1d,0x57,0x66,0x60,0xdc,0x53,0x63,0x30,0x9b,0x4d, 0xd4,0x2d,0x5a,0x49,0x0d,0x0b,0x19,0x44,0xba,0x16,0xd8,0x40,0x97,0xc6,0xa5,0xac, 0x20,0xdb,0x64,0xa8,0xf9,0xfd,0x27,0xa5,0x4e,0xe0,0xe6,0xa1,0x4b,0xb0,0xa1,0xbf, 0xfc,0xad,0x60,0xbb,0x25,0x8b,0x23,0xb6,0x92,0x96,0xe2,0xb2,0x2f,0x2b,0xad,0x8a, 0x98,0x36,0x6c,0x8e,0x41,0x10,0x2f,0x83,0xf6,0x0d,0xee,0x87,0xf3,0x5d,0xa9,0x99, 0x44,0x40,0x68,0x9d,0x9d,0x66,0x2b,0x90,0x2a,0x7b,0xea,0x94,0xe7,0x1d,0xb4,0xe0, 0x50,0x00,0x75,0xe4,0x89,0x26,0x36,0xe9,0x3e,0x3b,0xf7,0xed,0x3b,0x6b,0xb0,0xf3, 0x8c,0x76,0x71,0xf7,0x55,0x50,0x32,0xfa,0xe2,0x4d,0xf3,0xfe,0x5f,0xf0,0xbc,0xc6, 0xe8,0xed,0x7d,0xc2,0x31,0xcb,0x3e,0xcf,0x86,0xd6,0xff,0xcb,0x83,0x86,0xb8,0xd5, 0x34,0x9b,0x79,0xd1,0xed,0xbd,0x3a,0xdc,0x5a,0xa0,0xfb,0xd8,0xee,0xe0,0x0c,0x69, 0x59,0xfd,0xcd,0x6d,0x80,0xdb,0x8e,0x60,0x37,0xc6,0x4f,0x64,0x32,0x96,0x08,0x7a, 0x85,0x8b,0xc9,0x7e,0x5c,0xad,0x8a,0x73,0xeb,0xb0,0x4b,0x77,0x56,0x0d,0x04,0x4f, 0xe1,0x10,0xc5,0x4b,0x38,0x36,0x86,0x46,0x8f,0x2b,0x47,0x42,0x8a,0x7b,0x00,0x5c, 0x3d,0x66,0xc1,0x58,0xe4,0x40,0x82,0x55,0x53,0x5d,0x43,0x51,0x9e,0x3b,0x1d,0x25, 0x29,0x26,0xdc,0x21,0xf0,0x00,0x9f,0x2c,0x47,0x1d,0x5e,0x28,0x42,0x4d,0x19,0x36, 0xf5,0x50,0xd8,0x32,0x2c,0x76,0x9b,0x3f,0x9b,0x6b,0x5a,0x3b,0x26,0xd6,0x15,0x03, 0x91,0xcb,0xd4,0x07,0x48,0xed,0x97,0x0a,0xff,0xf0,0x56,0x0e,0xfa,0xa0,0x11,0x10, 0x4d,0xbd,0xd0,0x14,0x94,0x9b,0x93,0x19,0x23,0x86,0x52,0x1d,0x0e,0x56,0x2f,0xf1, 0xb9,0x4b,0xee,0xf5,0x60,0x6d,0xad,0xf8,0xd7,0x70,0x6c,0xfc,0xd2,0x20,0x2b,0xe2, 0x65,0x3d,0xea,0xe6,0xbc,0x1b,0xa9,0xeb,0x0b,0x06,0x68,0xef,0xb6,0xbb,0x27,0xd7, 0x01,0xa6,0xe6,0xd3,0xd8,0x80,0xa5,0xde,0x6f,0x9d,0x64,0xda,0x6a,0xcd,0x23,0xc4, 0xdd,0xd0,0xe2,0xc0,0x04,0xf6,0xa1,0xcd,0xb3,0xeb,0x60,0xc9,0x7e,0x8d,0x3e,0xbd, 0xc9,0x90,0xff,0xb9,0x10,0xb6,0xbc,0xb4,0xa7,0xab,0x7d,0xb0,0xa2,0xfb,0x3a,0xae, 0x15,0xe6,0xfb,0xaa,0xcc,0xc0,0xb8,0xa7,0x7b,0xdd,0x79,0xa3,0xc6,0x60,0x36,0x9b, 0x71,0x7d,0xf7,0x9f,0xa8,0x5b,0xb4,0x92,0x1f,0x46,0x75,0x96,0x1a,0x16,0x32,0x88, 0xad,0x0b,0xf3,0x8c,0x74,0x2d,0xb0,0x81,0xc3,0x30,0x71,0x85,0x99,0x90,0x8a,0x5d, 0x2e,0x8d,0x4b,0x59,0xf7,0xab,0x08,0x54,0x40,0xb6,0xc9,0x50,0x45,0xe6,0x8e,0x4e, 0xf2,0xfb,0x4f,0x4a,0x2b,0xdd,0x0c,0x47,0x9c,0xc0,0xcd,0x43,0x21,0x7d,0x82,0x7b, 0x96,0x60,0x43,0x7f,0x4f,0x46,0x00,0x72,0xf8,0x5b,0xc1,0x76,0xfd,0x0b,0x86,0x68, 0x4a,0x16,0x47,0x6c,0x93,0x30,0x04,0x61,0x24,0x2d,0xc5,0x65,0xe9,0x4b,0x9b,0x11, 0x5e,0x56,0x5a,0x15,0x87,0x70,0x19,0x18,0x30,0x6d,0xd8,0x1c,0x35,0x3d,0x9f,0x02, 0x82,0x20,0x5e,0x06,0x5b,0x06,0x1d,0x0b,0xec,0x1b,0xdc,0x0f,0x51,0xa6,0x93,0x37, 0xe6,0xbb,0x52,0x33,0x3f,0x9d,0x11,0x3e,0x88,0x80,0xd0,0x3a,0x8d,0xd0,0x97,0x24, 0x3a,0xcd,0x56,0x20,0xe3,0xeb,0x15,0x2d,0x54,0xf6,0xd4,0x29,0x79,0x26,0xa9,0xc5, 0xce,0x3b,0x68,0xc1,0x17,0x1d,0x2b,0xcc,0xa0,0x00,0xea,0xc8,0xa5,0x50,0xad,0xd6, 0x12,0x4d,0x6c,0xd2,0xcb,0x6b,0x2f,0xdf,0x7c,0x76,0xee,0xdb,0xc1,0xcb,0xa1,0xe3, 0x76,0xd6,0x60,0xe7,0xaf,0xf0,0x23,0xea,0x18,0xed,0xe2,0xee,0x1d,0xbd,0xa5,0xf0, 0xaa,0xa0,0x64,0xf4,0x73,0x86,0x27,0xf9,0xc4,0x9b,0xe6,0xfd,0x09,0xfd,0xb8,0x89, 0xbe,0xe0,0x79,0x8d,0x67,0xc6,0x3a,0x80,0xd0,0xdb,0xfb,0x84,0xd5,0x8b,0xbc,0x9a, 0x62,0x96,0x7d,0x9e,0xbb,0xb0,0x3e,0x93,0x0c,0xad,0xff,0x97,0xb1,0x10,0xb0,0xaf, 0x06,0x0d,0x71,0xab,0xdf,0x2b,0x32,0xa6,0x68,0x36,0xf3,0xa2,0x6d,0x66,0xb4,0xbc, 0xda,0x7b,0x75,0xb8,0x03,0x5d,0x36,0xb5,0xb4,0x40,0xf7,0xb1, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/checksum/riscv64_crc.inc ================================================ /* Autogenerated with ../../../src/helper/bin2char.sh */ 0x93,0x07,0xf0,0xff,0x93,0x06,0xf0,0xff,0x17,0x06,0x00,0x00,0x13,0x06,0x06,0x05, 0x9b,0x85,0xf5,0xff,0x63,0x9a,0xd5,0x00,0x13,0x85,0x07,0x00,0x73,0x00,0x10,0x00, 0x13,0x85,0x07,0x00,0x67,0x80,0x00,0x00,0x83,0x48,0x05,0x00,0x1b,0xd7,0x87,0x01, 0x1b,0x98,0x87,0x00,0x33,0x47,0x17,0x01,0x13,0x17,0x27,0x00,0x33,0x07,0xe6,0x00, 0x83,0x27,0x07,0x00,0x13,0x05,0x15,0x00,0xb3,0xc7,0x07,0x01,0x9b,0x87,0x07,0x00, 0x6f,0xf0,0x1f,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb7,0x1d,0xc1,0x04, 0x6e,0x3b,0x82,0x09,0xd9,0x26,0x43,0x0d,0xdc,0x76,0x04,0x13,0x6b,0x6b,0xc5,0x17, 0xb2,0x4d,0x86,0x1a,0x05,0x50,0x47,0x1e,0xb8,0xed,0x08,0x26,0x0f,0xf0,0xc9,0x22, 0xd6,0xd6,0x8a,0x2f,0x61,0xcb,0x4b,0x2b,0x64,0x9b,0x0c,0x35,0xd3,0x86,0xcd,0x31, 0x0a,0xa0,0x8e,0x3c,0xbd,0xbd,0x4f,0x38,0x70,0xdb,0x11,0x4c,0xc7,0xc6,0xd0,0x48, 0x1e,0xe0,0x93,0x45,0xa9,0xfd,0x52,0x41,0xac,0xad,0x15,0x5f,0x1b,0xb0,0xd4,0x5b, 0xc2,0x96,0x97,0x56,0x75,0x8b,0x56,0x52,0xc8,0x36,0x19,0x6a,0x7f,0x2b,0xd8,0x6e, 0xa6,0x0d,0x9b,0x63,0x11,0x10,0x5a,0x67,0x14,0x40,0x1d,0x79,0xa3,0x5d,0xdc,0x7d, 0x7a,0x7b,0x9f,0x70,0xcd,0x66,0x5e,0x74,0xe0,0xb6,0x23,0x98,0x57,0xab,0xe2,0x9c, 0x8e,0x8d,0xa1,0x91,0x39,0x90,0x60,0x95,0x3c,0xc0,0x27,0x8b,0x8b,0xdd,0xe6,0x8f, 0x52,0xfb,0xa5,0x82,0xe5,0xe6,0x64,0x86,0x58,0x5b,0x2b,0xbe,0xef,0x46,0xea,0xba, 0x36,0x60,0xa9,0xb7,0x81,0x7d,0x68,0xb3,0x84,0x2d,0x2f,0xad,0x33,0x30,0xee,0xa9, 0xea,0x16,0xad,0xa4,0x5d,0x0b,0x6c,0xa0,0x90,0x6d,0x32,0xd4,0x27,0x70,0xf3,0xd0, 0xfe,0x56,0xb0,0xdd,0x49,0x4b,0x71,0xd9,0x4c,0x1b,0x36,0xc7,0xfb,0x06,0xf7,0xc3, 0x22,0x20,0xb4,0xce,0x95,0x3d,0x75,0xca,0x28,0x80,0x3a,0xf2,0x9f,0x9d,0xfb,0xf6, 0x46,0xbb,0xb8,0xfb,0xf1,0xa6,0x79,0xff,0xf4,0xf6,0x3e,0xe1,0x43,0xeb,0xff,0xe5, 0x9a,0xcd,0xbc,0xe8,0x2d,0xd0,0x7d,0xec,0x77,0x70,0x86,0x34,0xc0,0x6d,0x47,0x30, 0x19,0x4b,0x04,0x3d,0xae,0x56,0xc5,0x39,0xab,0x06,0x82,0x27,0x1c,0x1b,0x43,0x23, 0xc5,0x3d,0x00,0x2e,0x72,0x20,0xc1,0x2a,0xcf,0x9d,0x8e,0x12,0x78,0x80,0x4f,0x16, 0xa1,0xa6,0x0c,0x1b,0x16,0xbb,0xcd,0x1f,0x13,0xeb,0x8a,0x01,0xa4,0xf6,0x4b,0x05, 0x7d,0xd0,0x08,0x08,0xca,0xcd,0xc9,0x0c,0x07,0xab,0x97,0x78,0xb0,0xb6,0x56,0x7c, 0x69,0x90,0x15,0x71,0xde,0x8d,0xd4,0x75,0xdb,0xdd,0x93,0x6b,0x6c,0xc0,0x52,0x6f, 0xb5,0xe6,0x11,0x62,0x02,0xfb,0xd0,0x66,0xbf,0x46,0x9f,0x5e,0x08,0x5b,0x5e,0x5a, 0xd1,0x7d,0x1d,0x57,0x66,0x60,0xdc,0x53,0x63,0x30,0x9b,0x4d,0xd4,0x2d,0x5a,0x49, 0x0d,0x0b,0x19,0x44,0xba,0x16,0xd8,0x40,0x97,0xc6,0xa5,0xac,0x20,0xdb,0x64,0xa8, 0xf9,0xfd,0x27,0xa5,0x4e,0xe0,0xe6,0xa1,0x4b,0xb0,0xa1,0xbf,0xfc,0xad,0x60,0xbb, 0x25,0x8b,0x23,0xb6,0x92,0x96,0xe2,0xb2,0x2f,0x2b,0xad,0x8a,0x98,0x36,0x6c,0x8e, 0x41,0x10,0x2f,0x83,0xf6,0x0d,0xee,0x87,0xf3,0x5d,0xa9,0x99,0x44,0x40,0x68,0x9d, 0x9d,0x66,0x2b,0x90,0x2a,0x7b,0xea,0x94,0xe7,0x1d,0xb4,0xe0,0x50,0x00,0x75,0xe4, 0x89,0x26,0x36,0xe9,0x3e,0x3b,0xf7,0xed,0x3b,0x6b,0xb0,0xf3,0x8c,0x76,0x71,0xf7, 0x55,0x50,0x32,0xfa,0xe2,0x4d,0xf3,0xfe,0x5f,0xf0,0xbc,0xc6,0xe8,0xed,0x7d,0xc2, 0x31,0xcb,0x3e,0xcf,0x86,0xd6,0xff,0xcb,0x83,0x86,0xb8,0xd5,0x34,0x9b,0x79,0xd1, 0xed,0xbd,0x3a,0xdc,0x5a,0xa0,0xfb,0xd8,0xee,0xe0,0x0c,0x69,0x59,0xfd,0xcd,0x6d, 0x80,0xdb,0x8e,0x60,0x37,0xc6,0x4f,0x64,0x32,0x96,0x08,0x7a,0x85,0x8b,0xc9,0x7e, 0x5c,0xad,0x8a,0x73,0xeb,0xb0,0x4b,0x77,0x56,0x0d,0x04,0x4f,0xe1,0x10,0xc5,0x4b, 0x38,0x36,0x86,0x46,0x8f,0x2b,0x47,0x42,0x8a,0x7b,0x00,0x5c,0x3d,0x66,0xc1,0x58, 0xe4,0x40,0x82,0x55,0x53,0x5d,0x43,0x51,0x9e,0x3b,0x1d,0x25,0x29,0x26,0xdc,0x21, 0xf0,0x00,0x9f,0x2c,0x47,0x1d,0x5e,0x28,0x42,0x4d,0x19,0x36,0xf5,0x50,0xd8,0x32, 0x2c,0x76,0x9b,0x3f,0x9b,0x6b,0x5a,0x3b,0x26,0xd6,0x15,0x03,0x91,0xcb,0xd4,0x07, 0x48,0xed,0x97,0x0a,0xff,0xf0,0x56,0x0e,0xfa,0xa0,0x11,0x10,0x4d,0xbd,0xd0,0x14, 0x94,0x9b,0x93,0x19,0x23,0x86,0x52,0x1d,0x0e,0x56,0x2f,0xf1,0xb9,0x4b,0xee,0xf5, 0x60,0x6d,0xad,0xf8,0xd7,0x70,0x6c,0xfc,0xd2,0x20,0x2b,0xe2,0x65,0x3d,0xea,0xe6, 0xbc,0x1b,0xa9,0xeb,0x0b,0x06,0x68,0xef,0xb6,0xbb,0x27,0xd7,0x01,0xa6,0xe6,0xd3, 0xd8,0x80,0xa5,0xde,0x6f,0x9d,0x64,0xda,0x6a,0xcd,0x23,0xc4,0xdd,0xd0,0xe2,0xc0, 0x04,0xf6,0xa1,0xcd,0xb3,0xeb,0x60,0xc9,0x7e,0x8d,0x3e,0xbd,0xc9,0x90,0xff,0xb9, 0x10,0xb6,0xbc,0xb4,0xa7,0xab,0x7d,0xb0,0xa2,0xfb,0x3a,0xae,0x15,0xe6,0xfb,0xaa, 0xcc,0xc0,0xb8,0xa7,0x7b,0xdd,0x79,0xa3,0xc6,0x60,0x36,0x9b,0x71,0x7d,0xf7,0x9f, 0xa8,0x5b,0xb4,0x92,0x1f,0x46,0x75,0x96,0x1a,0x16,0x32,0x88,0xad,0x0b,0xf3,0x8c, 0x74,0x2d,0xb0,0x81,0xc3,0x30,0x71,0x85,0x99,0x90,0x8a,0x5d,0x2e,0x8d,0x4b,0x59, 0xf7,0xab,0x08,0x54,0x40,0xb6,0xc9,0x50,0x45,0xe6,0x8e,0x4e,0xf2,0xfb,0x4f,0x4a, 0x2b,0xdd,0x0c,0x47,0x9c,0xc0,0xcd,0x43,0x21,0x7d,0x82,0x7b,0x96,0x60,0x43,0x7f, 0x4f,0x46,0x00,0x72,0xf8,0x5b,0xc1,0x76,0xfd,0x0b,0x86,0x68,0x4a,0x16,0x47,0x6c, 0x93,0x30,0x04,0x61,0x24,0x2d,0xc5,0x65,0xe9,0x4b,0x9b,0x11,0x5e,0x56,0x5a,0x15, 0x87,0x70,0x19,0x18,0x30,0x6d,0xd8,0x1c,0x35,0x3d,0x9f,0x02,0x82,0x20,0x5e,0x06, 0x5b,0x06,0x1d,0x0b,0xec,0x1b,0xdc,0x0f,0x51,0xa6,0x93,0x37,0xe6,0xbb,0x52,0x33, 0x3f,0x9d,0x11,0x3e,0x88,0x80,0xd0,0x3a,0x8d,0xd0,0x97,0x24,0x3a,0xcd,0x56,0x20, 0xe3,0xeb,0x15,0x2d,0x54,0xf6,0xd4,0x29,0x79,0x26,0xa9,0xc5,0xce,0x3b,0x68,0xc1, 0x17,0x1d,0x2b,0xcc,0xa0,0x00,0xea,0xc8,0xa5,0x50,0xad,0xd6,0x12,0x4d,0x6c,0xd2, 0xcb,0x6b,0x2f,0xdf,0x7c,0x76,0xee,0xdb,0xc1,0xcb,0xa1,0xe3,0x76,0xd6,0x60,0xe7, 0xaf,0xf0,0x23,0xea,0x18,0xed,0xe2,0xee,0x1d,0xbd,0xa5,0xf0,0xaa,0xa0,0x64,0xf4, 0x73,0x86,0x27,0xf9,0xc4,0x9b,0xe6,0xfd,0x09,0xfd,0xb8,0x89,0xbe,0xe0,0x79,0x8d, 0x67,0xc6,0x3a,0x80,0xd0,0xdb,0xfb,0x84,0xd5,0x8b,0xbc,0x9a,0x62,0x96,0x7d,0x9e, 0xbb,0xb0,0x3e,0x93,0x0c,0xad,0xff,0x97,0xb1,0x10,0xb0,0xaf,0x06,0x0d,0x71,0xab, 0xdf,0x2b,0x32,0xa6,0x68,0x36,0xf3,0xa2,0x6d,0x66,0xb4,0xbc,0xda,0x7b,0x75,0xb8, 0x03,0x5d,0x36,0xb5,0xb4,0x40,0xf7,0xb1, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/checksum/riscv_crc.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* Copyright (C) 2009-2021 Free Software Foundation, Inc. */ /* Copied from https://github.com/gcc-mirror/gcc/blob/master/libiberty/crc32.c * and then tweaked a little. */ /* This table was generated by the following program. #include int main () { unsigned int i, j; unsigned int c; int table[256]; for (i = 0; i < 256; i++) { for (c = i << 24, j = 8; j > 0; --j) c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); table[i] = c; } printf ("static const unsigned int crc32_table[] =\n{\n"); for (i = 0; i < 256; i += 4) { printf (" 0x%08x, 0x%08x, 0x%08x, 0x%08x", table[i + 0], table[i + 1], table[i + 2], table[i + 3]); if (i + 4 < 256) putchar (','); putchar ('\n'); } printf ("};\n"); return 0; } For more information on CRC, see, e.g., http://www.ross.net/crc/download/crc_v3.txt. */ static const unsigned int crc32_table[] = { 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 }; /* @deftypefn Extension {unsigned int} crc32 (const unsigned char *@var{buf}, @ int @var{len}, unsigned int @var{init}) Compute the 32-bit CRC of @var{buf} which has length @var{len}. The starting value is 0xffffffff. This is used by the @command{gdb} remote protocol for the @samp{qCRC} command. This CRC can be specified as: Width : 32 Poly : 0x04c11db7 Init : 0xffffffff RefIn : false RefOut : false XorOut : 0 This differs from the "standard" CRC-32 algorithm in that the values are not reflected, and there is no final XOR value. These differences make it easy to compose the values of multiple blocks. @end deftypefn */ #include unsigned int xcrc32(const unsigned char *buf, int len) { uint32_t crc = 0xffffffff; while (len--) { crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255]; buf++; } asm("mv a0, %0;" "ebreak;" : : "r"(crc)); return crc; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/debug/xscale/debug_handler.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #include "protocol.h" .text .align 4 @ Disable thumb mode .code 32 @ send word to debugger .macro m_send_to_debugger reg 1: mrc p14, 0, r15, c14, c0, 0 bvs 1b mcr p14, 0, \reg, c8, c0, 0 .endm @ receive word from debugger .macro m_receive_from_debugger reg 1: mrc p14, 0, r15, c14, c0, 0 bpl 1b mrc p14, 0, \reg, c9, c0, 0 .endm @ save register on debugger, small .macro m_small_save_reg reg mov r0, \reg bl send_to_debugger .endm @ save status register on debugger, small .macro m_small_save_psr mrs r0, spsr bl send_to_debugger .endm @ wait for all outstanding coprocessor accesses to complete .macro m_cpwait mrc p15, 0, r0, c2, c0, 0 mov r0, r0 sub pc, pc, #4 .endm .global reset_handler .global undef_handler .global swi_handler .global prefetch_abort_handler .global data_abort_handler .global irq_handler .global fiq_handler .section .part1 , "ax" reset_handler: @ read DCSR mrc p14, 0, r13, c10, c0 @ check if global enable bit (GE) is set ands r13, r13, #0x80000000 bne debug_handler @ set global enable bit (GE) mov r13, #0xc0000000 mcr p14, 0, r13, c10, c0 debug_handler: @ save r0 without modifying other registers m_send_to_debugger r0 @ save lr (program PC) without branching (use macro) m_send_to_debugger r14 @ save non-banked registers and spsr (program CPSR) m_small_save_reg r1 m_small_save_reg r2 m_small_save_reg r3 m_small_save_reg r4 m_small_save_reg r5 m_small_save_reg r6 m_small_save_reg r7 m_small_save_psr mrs r0, spsr @ prepare program PSR for debug use (clear Thumb, set I/F to disable interrupts) bic r0, r0, #PSR_T orr r0, r0, #(PSR_I | PSR_F) @ examine mode bits and r1, r0, #MODE_MASK cmp r1, #MODE_USR bne not_user_mode @ replace USR mode with SYS bic r0, r0, #MODE_MASK orr r0, r0, #MODE_SYS not_user_mode: b save_banked_registers @ command loop @ wait for command from debugger, than execute desired function get_command: bl receive_from_debugger @ 0x0n - register access cmp r0, #0x0 beq get_banked_registers cmp r0, #0x1 beq set_banked_registers @ 0x1n - read memory cmp r0, #0x11 beq read_byte cmp r0, #0x12 beq read_half_word cmp r0, #0x14 beq read_word @ 0x2n - write memory cmp r0, #0x21 beq write_byte cmp r0, #0x22 beq write_half_word cmp r0, #0x24 beq write_word @ 0x3n - program execution cmp r0, #0x30 beq resume cmp r0, #0x31 beq resume_w_trace @ 0x4n - coprocessor access cmp r0, #0x40 beq read_cp_reg cmp r0, #0x41 beq write_cp_reg @ 0x5n - cache and mmu functions cmp r0, #0x50 beq clean_d_cache cmp r0, #0x51 beq invalidate_d_cache cmp r0, #0x52 beq invalidate_i_cache cmp r0, #0x53 beq cpwait @ 0x6n - misc functions cmp r0, #0x60 beq clear_sa cmp r0, #0x61 beq read_trace_buffer cmp r0, #0x62 beq clean_trace_buffer @ return (back to get_command) b get_command @ ---- @ resume program execution resume: @ restore CPSR (SPSR_dbg) bl receive_from_debugger msr spsr, r0 @ restore registers (r7 - r0) bl receive_from_debugger @ r7 mov r7, r0 bl receive_from_debugger @ r6 mov r6, r0 bl receive_from_debugger @ r5 mov r5, r0 bl receive_from_debugger @ r4 mov r4, r0 bl receive_from_debugger @ r3 mov r3, r0 bl receive_from_debugger @ r2 mov r2, r0 bl receive_from_debugger @ r1 mov r1, r0 bl receive_from_debugger @ r0 @ resume addresss m_receive_from_debugger lr @ branch back to application code, restoring CPSR subs pc, lr, #0 @ get banked registers @ receive mode bits from host, then run into save_banked_registers to get_banked_registers: bl receive_from_debugger @ save banked registers @ r0[4:0]: desired mode bits save_banked_registers: @ backup CPSR mrs r7, cpsr msr cpsr_c, r0 nop @ keep current mode bits in r1 for later use and r1, r0, #MODE_MASK @ backup banked registers m_send_to_debugger r8 m_send_to_debugger r9 m_send_to_debugger r10 m_send_to_debugger r11 m_send_to_debugger r12 m_send_to_debugger r13 m_send_to_debugger r14 @ if not in SYS mode (or USR, which we replaced with SYS before) cmp r1, #MODE_SYS beq no_spsr_to_save @ backup SPSR mrs r0, spsr m_send_to_debugger r0 no_spsr_to_save: @ restore CPSR for SDS msr cpsr_c, r7 nop @ return b get_command @ ---- @ set banked registers @ receive mode bits from host, then run into save_banked_registers to set_banked_registers: bl receive_from_debugger @ restore banked registers @ r0[4:0]: desired mode bits restore_banked_registers: @ backup CPSR mrs r7, cpsr msr cpsr_c, r0 nop @ keep current mode bits in r1 for later use and r1, r0, #MODE_MASK @ set banked registers m_receive_from_debugger r8 m_receive_from_debugger r9 m_receive_from_debugger r10 m_receive_from_debugger r11 m_receive_from_debugger r12 m_receive_from_debugger r13 m_receive_from_debugger r14 @ if not in SYS mode (or USR, which we replaced with SYS before) cmp r1, #MODE_SYS beq no_spsr_to_restore @ set SPSR m_receive_from_debugger r0 msr spsr, r0 no_spsr_to_restore: @ restore CPSR for SDS msr cpsr_c, r7 nop @ return b get_command @ ---- read_byte: @ r2: address bl receive_from_debugger mov r2, r0 @ r1: count bl receive_from_debugger mov r1, r0 rb_loop: ldrb r0, [r2], #1 @ drain write- (and fill-) buffer to work around XScale errata mcr p15, 0, r8, c7, c10, 4 bl send_to_debugger subs r1, r1, #1 bne rb_loop @ return b get_command @ ---- read_half_word: @ r2: address bl receive_from_debugger mov r2, r0 @ r1: count bl receive_from_debugger mov r1, r0 rh_loop: ldrh r0, [r2], #2 @ drain write- (and fill-) buffer to work around XScale errata mcr p15, 0, r8, c7, c10, 4 bl send_to_debugger subs r1, r1, #1 bne rh_loop @ return b get_command @ ---- read_word: @ r2: address bl receive_from_debugger mov r2, r0 @ r1: count bl receive_from_debugger mov r1, r0 rw_loop: ldr r0, [r2], #4 @ drain write- (and fill-) buffer to work around XScale errata mcr p15, 0, r8, c7, c10, 4 bl send_to_debugger subs r1, r1, #1 bne rw_loop @ return b get_command @ ---- write_byte: @ r2: address bl receive_from_debugger mov r2, r0 @ r1: count bl receive_from_debugger mov r1, r0 wb_loop: bl receive_from_debugger strb r0, [r2], #1 @ drain write- (and fill-) buffer to work around XScale errata mcr p15, 0, r8, c7, c10, 4 subs r1, r1, #1 bne wb_loop @ return b get_command @ ---- write_half_word: @ r2: address bl receive_from_debugger mov r2, r0 @ r1: count bl receive_from_debugger mov r1, r0 wh_loop: bl receive_from_debugger strh r0, [r2], #2 @ drain write- (and fill-) buffer to work around XScale errata mcr p15, 0, r8, c7, c10, 4 subs r1, r1, #1 bne wh_loop @ return b get_command @ ---- write_word: @ r2: address bl receive_from_debugger mov r2, r0 @ r1: count bl receive_from_debugger mov r1, r0 ww_loop: bl receive_from_debugger str r0, [r2], #4 @ drain write- (and fill-) buffer to work around XScale errata mcr p15, 0, r8, c7, c10, 4 subs r1, r1, #1 bne ww_loop @ return b get_command @ ---- clear_sa: @ read DCSR mrc p14, 0, r0, c10, c0 @ clear SA bit bic r0, r0, #0x20 @ write DCSR mcr p14, 0, r0, c10, c0 @ return b get_command @ ---- clean_d_cache: @ r0: cache clean area bl receive_from_debugger mov r1, #1024 clean_loop: mcr p15, 0, r0, c7, c2, 5 add r0, r0, #32 subs r1, r1, #1 bne clean_loop @ return b get_command @ ---- invalidate_d_cache: mcr p15, 0, r0, c7, c6, 0 @ return b get_command @ ---- invalidate_i_cache: mcr p15, 0, r0, c7, c5, 0 @ return b get_command @ ---- cpwait: m_cpwait @return b get_command @ ---- .section .part2 , "ax" read_cp_reg: @ requested cp register bl receive_from_debugger adr r1, read_cp_table add pc, r1, r0, lsl #3 read_cp_table: mrc p15, 0, r0, c0, c0, 0 @ XSCALE_MAINID b read_cp_reg_reply mrc p15, 0, r0, c0, c0, 1 @ XSCALE_CACHETYPE b read_cp_reg_reply mrc p15, 0, r0, c1, c0, 0 @ XSCALE_CTRL b read_cp_reg_reply mrc p15, 0, r0, c1, c0, 1 @ XSCALE_AUXCTRL b read_cp_reg_reply mrc p15, 0, r0, c2, c0, 0 @ XSCALE_TTB b read_cp_reg_reply mrc p15, 0, r0, c3, c0, 0 @ XSCALE_DAC b read_cp_reg_reply mrc p15, 0, r0, c5, c0, 0 @ XSCALE_FSR b read_cp_reg_reply mrc p15, 0, r0, c6, c0, 0 @ XSCALE_FAR b read_cp_reg_reply mrc p15, 0, r0, c13, c0, 0 @ XSCALE_PID b read_cp_reg_reply mrc p15, 0, r0, c15, c0, 0 @ XSCALE_CP_ACCESS b read_cp_reg_reply mrc p15, 0, r0, c14, c8, 0 @ XSCALE_IBCR0 b read_cp_reg_reply mrc p15, 0, r0, c14, c9, 0 @ XSCALE_IBCR1 b read_cp_reg_reply mrc p15, 0, r0, c14, c0, 0 @ XSCALE_DBR0 b read_cp_reg_reply mrc p15, 0, r0, c14, c3, 0 @ XSCALE_DBR1 b read_cp_reg_reply mrc p15, 0, r0, c14, c4, 0 @ XSCALE_DBCON b read_cp_reg_reply mrc p14, 0, r0, c11, c0, 0 @ XSCALE_TBREG b read_cp_reg_reply mrc p14, 0, r0, c12, c0, 0 @ XSCALE_CHKPT0 b read_cp_reg_reply mrc p14, 0, r0, c13, c0, 0 @ XSCALE_CHKPT1 b read_cp_reg_reply mrc p14, 0, r0, c10, c0, 0 @ XSCALE_DCSR b read_cp_reg_reply read_cp_reg_reply: bl send_to_debugger @ return b get_command @ ---- write_cp_reg: @ requested cp register bl receive_from_debugger mov r1, r0 @ value to be written bl receive_from_debugger adr r2, write_cp_table add pc, r2, r1, lsl #3 write_cp_table: mcr p15, 0, r0, c0, c0, 0 @ XSCALE_MAINID (0x0) b get_command mcr p15, 0, r0, c0, c0, 1 @ XSCALE_CACHETYPE (0x1) b get_command mcr p15, 0, r0, c1, c0, 0 @ XSCALE_CTRL (0x2) b get_command mcr p15, 0, r0, c1, c0, 1 @ XSCALE_AUXCTRL (0x3) b get_command mcr p15, 0, r0, c2, c0, 0 @ XSCALE_TTB (0x4) b get_command mcr p15, 0, r0, c3, c0, 0 @ XSCALE_DAC (0x5) b get_command mcr p15, 0, r0, c5, c0, 0 @ XSCALE_FSR (0x6) b get_command mcr p15, 0, r0, c6, c0, 0 @ XSCALE_FAR (0x7) b get_command mcr p15, 0, r0, c13, c0, 0 @ XSCALE_PID (0x8) b get_command mcr p15, 0, r0, c15, c0, 0 @ XSCALE_CP_ACCESS (0x9) b get_command mcr p15, 0, r0, c14, c8, 0 @ XSCALE_IBCR0 (0xa) b get_command mcr p15, 0, r0, c14, c9, 0 @ XSCALE_IBCR1 (0xb) b get_command mcr p15, 0, r0, c14, c0, 0 @ XSCALE_DBR0 (0xc) b get_command mcr p15, 0, r0, c14, c3, 0 @ XSCALE_DBR1 (0xd) b get_command mcr p15, 0, r0, c14, c4, 0 @ XSCALE_DBCON (0xe) b get_command mcr p14, 0, r0, c11, c0, 0 @ XSCALE_TBREG (0xf) b get_command mcr p14, 0, r0, c12, c0, 0 @ XSCALE_CHKPT0 (0x10) b get_command mcr p14, 0, r0, c13, c0, 0 @ XSCALE_CHKPT1 (0x11) b get_command mcr p14, 0, r0, c10, c0, 0 @ XSCALE_DCSR (0x12) b get_command @ ---- read_trace_buffer: @ dump 256 entries from trace buffer mov r1, #256 read_tb_loop: mrc p14, 0, r0, c11, c0, 0 @ XSCALE_TBREG bl send_to_debugger subs r1, r1, #1 bne read_tb_loop @ dump checkpoint register 0 mrc p14, 0, r0, c12, c0, 0 @ XSCALE_CHKPT0 (0x10) bl send_to_debugger @ dump checkpoint register 1 mrc p14, 0, r0, c13, c0, 0 @ XSCALE_CHKPT1 (0x11) bl send_to_debugger @ return b get_command @ ---- clean_trace_buffer: @ clean 256 entries from trace buffer mov r1, #256 clean_tb_loop: mrc p14, 0, r0, c11, c0, 0 @ XSCALE_TBREG subs r1, r1, #1 bne clean_tb_loop @ return b get_command @ ---- @ resume program execution with trace buffer enabled resume_w_trace: @ restore CPSR (SPSR_dbg) bl receive_from_debugger msr spsr, r0 @ restore registers (r7 - r0) bl receive_from_debugger @ r7 mov r7, r0 bl receive_from_debugger @ r6 mov r6, r0 bl receive_from_debugger @ r5 mov r5, r0 bl receive_from_debugger @ r4 mov r4, r0 bl receive_from_debugger @ r3 mov r3, r0 bl receive_from_debugger @ r2 mov r2, r0 bl receive_from_debugger @ r1 mov r1, r0 bl receive_from_debugger @ r0 @ resume addresss m_receive_from_debugger lr mrc p14, 0, r13, c10, c0, 0 @ XSCALE_DCSR orr r13, r13, #1 mcr p14, 0, r13, c10, c0, 0 @ XSCALE_DCSR @ branch back to application code, restoring CPSR subs pc, lr, #0 undef_handler: swi_handler: prefetch_abort_handler: data_abort_handler: irq_handler: fiq_handler: 1: b 1b send_to_debugger: m_send_to_debugger r0 mov pc, lr receive_from_debugger: m_receive_from_debugger r0 mov pc, lr ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/debug/xscale/debug_handler.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x10,0xde,0x1a,0xee,0x02,0xd1,0x1d,0xe2,0x01,0x00,0x00,0x1a,0x03,0xd1,0xa0,0xe3, 0x10,0xde,0x0a,0xee,0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x6a,0x10,0x0e,0x08,0xee, 0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x6a,0x10,0xee,0x08,0xee,0x01,0x00,0xa0,0xe1, 0x70,0x01,0x00,0xeb,0x02,0x00,0xa0,0xe1,0x6e,0x01,0x00,0xeb,0x03,0x00,0xa0,0xe1, 0x6c,0x01,0x00,0xeb,0x04,0x00,0xa0,0xe1,0x6a,0x01,0x00,0xeb,0x05,0x00,0xa0,0xe1, 0x68,0x01,0x00,0xeb,0x06,0x00,0xa0,0xe1,0x66,0x01,0x00,0xeb,0x07,0x00,0xa0,0xe1, 0x64,0x01,0x00,0xeb,0x00,0x00,0x4f,0xe1,0x62,0x01,0x00,0xeb,0x00,0x00,0x4f,0xe1, 0x20,0x00,0xc0,0xe3,0xc0,0x00,0x80,0xe3,0x1f,0x10,0x00,0xe2,0x10,0x00,0x51,0xe3, 0x01,0x00,0x00,0x1a,0x1f,0x00,0xc0,0xe3,0x1f,0x00,0x80,0xe3,0x3d,0x00,0x00,0xea, 0x5c,0x01,0x00,0xeb,0x00,0x00,0x50,0xe3,0x39,0x00,0x00,0x0a,0x01,0x00,0x50,0xe3, 0x5a,0x00,0x00,0x0a,0x11,0x00,0x50,0xe3,0x7b,0x00,0x00,0x0a,0x12,0x00,0x50,0xe3, 0x83,0x00,0x00,0x0a,0x14,0x00,0x50,0xe3,0x8b,0x00,0x00,0x0a,0x21,0x00,0x50,0xe3, 0x93,0x00,0x00,0x0a,0x22,0x00,0x50,0xe3,0x9b,0x00,0x00,0x0a,0x24,0x00,0x50,0xe3, 0xa3,0x00,0x00,0x0a,0x30,0x00,0x50,0xe3,0x14,0x00,0x00,0x0a,0x31,0x00,0x50,0xe3, 0x2b,0x01,0x00,0x0a,0x40,0x00,0x50,0xe3,0xc4,0x00,0x00,0x0a,0x41,0x00,0x50,0xe3, 0xed,0x00,0x00,0x0a,0x50,0x00,0x50,0xe3,0xa7,0x00,0x00,0x0a,0x51,0x00,0x50,0xe3, 0xac,0x00,0x00,0x0a,0x52,0x00,0x50,0xe3,0xac,0x00,0x00,0x0a,0x53,0x00,0x50,0xe3, 0xac,0x00,0x00,0x0a,0x60,0x00,0x50,0xe3,0x9b,0x00,0x00,0x0a,0x61,0x00,0x50,0xe3, 0x0c,0x01,0x00,0x0a,0x62,0x00,0x50,0xe3,0x14,0x01,0x00,0x0a,0xd7,0xff,0xff,0xea, 0x34,0x01,0x00,0xeb,0x00,0xf0,0x69,0xe1,0x32,0x01,0x00,0xeb,0x00,0x70,0xa0,0xe1, 0x30,0x01,0x00,0xeb,0x00,0x60,0xa0,0xe1,0x2e,0x01,0x00,0xeb,0x00,0x50,0xa0,0xe1, 0x2c,0x01,0x00,0xeb,0x00,0x40,0xa0,0xe1,0x2a,0x01,0x00,0xeb,0x00,0x30,0xa0,0xe1, 0x28,0x01,0x00,0xeb,0x00,0x20,0xa0,0xe1,0x26,0x01,0x00,0xeb,0x00,0x10,0xa0,0xe1, 0x24,0x01,0x00,0xeb,0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x5a,0x10,0xee,0x19,0xee, 0x00,0xf0,0x5e,0xe2,0x1f,0x01,0x00,0xeb,0x00,0x70,0x0f,0xe1,0x00,0xf0,0x21,0xe1, 0x00,0x00,0xa0,0xe1,0x1f,0x10,0x00,0xe2,0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x6a, 0x10,0x8e,0x08,0xee,0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x6a,0x10,0x9e,0x08,0xee, 0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x6a,0x10,0xae,0x08,0xee,0x10,0xfe,0x1e,0xee, 0xfd,0xff,0xff,0x6a,0x10,0xbe,0x08,0xee,0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x6a, 0x10,0xce,0x08,0xee,0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x6a,0x10,0xde,0x08,0xee, 0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x6a,0x10,0xee,0x08,0xee,0x1f,0x00,0x51,0xe3, 0x03,0x00,0x00,0x0a,0x00,0x00,0x4f,0xe1,0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x6a, 0x10,0x0e,0x08,0xee,0x07,0xf0,0x21,0xe1,0x00,0x00,0xa0,0xe1,0x9f,0xff,0xff,0xea, 0xfc,0x00,0x00,0xeb,0x00,0x70,0x0f,0xe1,0x00,0xf0,0x21,0xe1,0x00,0x00,0xa0,0xe1, 0x1f,0x10,0x00,0xe2,0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x5a,0x10,0x8e,0x19,0xee, 0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x5a,0x10,0x9e,0x19,0xee,0x10,0xfe,0x1e,0xee, 0xfd,0xff,0xff,0x5a,0x10,0xae,0x19,0xee,0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x5a, 0x10,0xbe,0x19,0xee,0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x5a,0x10,0xce,0x19,0xee, 0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x5a,0x10,0xde,0x19,0xee,0x10,0xfe,0x1e,0xee, 0xfd,0xff,0xff,0x5a,0x10,0xee,0x19,0xee,0x1f,0x00,0x51,0xe3,0x03,0x00,0x00,0x0a, 0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x5a,0x10,0x0e,0x19,0xee,0x00,0xf0,0x69,0xe1, 0x07,0xf0,0x21,0xe1,0x00,0x00,0xa0,0xe1,0x7c,0xff,0xff,0xea,0xd9,0x00,0x00,0xeb, 0x00,0x20,0xa0,0xe1,0xd7,0x00,0x00,0xeb,0x00,0x10,0xa0,0xe1,0x01,0x00,0xd2,0xe4, 0x9a,0x8f,0x07,0xee,0xcf,0x00,0x00,0xeb,0x01,0x10,0x51,0xe2,0xfa,0xff,0xff,0x1a, 0x72,0xff,0xff,0xea,0xcf,0x00,0x00,0xeb,0x00,0x20,0xa0,0xe1,0xcd,0x00,0x00,0xeb, 0x00,0x10,0xa0,0xe1,0xb2,0x00,0xd2,0xe0,0x9a,0x8f,0x07,0xee,0xc5,0x00,0x00,0xeb, 0x01,0x10,0x51,0xe2,0xfa,0xff,0xff,0x1a,0x68,0xff,0xff,0xea,0xc5,0x00,0x00,0xeb, 0x00,0x20,0xa0,0xe1,0xc3,0x00,0x00,0xeb,0x00,0x10,0xa0,0xe1,0x04,0x00,0x92,0xe4, 0x9a,0x8f,0x07,0xee,0xbb,0x00,0x00,0xeb,0x01,0x10,0x51,0xe2,0xfa,0xff,0xff,0x1a, 0x5e,0xff,0xff,0xea,0xbb,0x00,0x00,0xeb,0x00,0x20,0xa0,0xe1,0xb9,0x00,0x00,0xeb, 0x00,0x10,0xa0,0xe1,0xb7,0x00,0x00,0xeb,0x01,0x00,0xc2,0xe4,0x9a,0x8f,0x07,0xee, 0x01,0x10,0x51,0xe2,0xfa,0xff,0xff,0x1a,0x54,0xff,0xff,0xea,0xb1,0x00,0x00,0xeb, 0x00,0x20,0xa0,0xe1,0xaf,0x00,0x00,0xeb,0x00,0x10,0xa0,0xe1,0xad,0x00,0x00,0xeb, 0xb2,0x00,0xc2,0xe0,0x9a,0x8f,0x07,0xee,0x01,0x10,0x51,0xe2,0xfa,0xff,0xff,0x1a, 0x4a,0xff,0xff,0xea,0xa7,0x00,0x00,0xeb,0x00,0x20,0xa0,0xe1,0xa5,0x00,0x00,0xeb, 0x00,0x10,0xa0,0xe1,0xa3,0x00,0x00,0xeb,0x04,0x00,0x82,0xe4,0x9a,0x8f,0x07,0xee, 0x01,0x10,0x51,0xe2,0xfa,0xff,0xff,0x1a,0x40,0xff,0xff,0xea,0x10,0x0e,0x1a,0xee, 0x20,0x00,0xc0,0xe3,0x10,0x0e,0x0a,0xee,0x3c,0xff,0xff,0xea,0x99,0x00,0x00,0xeb, 0x01,0x1b,0xa0,0xe3,0xb2,0x0f,0x07,0xee,0x20,0x00,0x80,0xe2,0x01,0x10,0x51,0xe2, 0xfb,0xff,0xff,0x1a,0x35,0xff,0xff,0xea,0x16,0x0f,0x07,0xee,0x33,0xff,0xff,0xea, 0x15,0x0f,0x07,0xee,0x31,0xff,0xff,0xea,0x10,0x0f,0x12,0xee,0x00,0x00,0xa0,0xe1, 0x04,0xf0,0x4f,0xe2,0x2d,0xff,0xff,0xea,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x80,0x00,0x00,0xeb,0x00,0x10,0x8f,0xe2,0x80,0xf1,0x81,0xe0,0x10,0x0f,0x10,0xee, 0x23,0x00,0x00,0xea,0x30,0x0f,0x10,0xee,0x21,0x00,0x00,0xea,0x10,0x0f,0x11,0xee, 0x1f,0x00,0x00,0xea,0x30,0x0f,0x11,0xee,0x1d,0x00,0x00,0xea,0x10,0x0f,0x12,0xee, 0x1b,0x00,0x00,0xea,0x10,0x0f,0x13,0xee,0x19,0x00,0x00,0xea,0x10,0x0f,0x15,0xee, 0x17,0x00,0x00,0xea,0x10,0x0f,0x16,0xee,0x15,0x00,0x00,0xea,0x10,0x0f,0x1d,0xee, 0x13,0x00,0x00,0xea,0x10,0x0f,0x1f,0xee,0x11,0x00,0x00,0xea,0x18,0x0f,0x1e,0xee, 0x0f,0x00,0x00,0xea,0x19,0x0f,0x1e,0xee,0x0d,0x00,0x00,0xea,0x10,0x0f,0x1e,0xee, 0x0b,0x00,0x00,0xea,0x13,0x0f,0x1e,0xee,0x09,0x00,0x00,0xea,0x14,0x0f,0x1e,0xee, 0x07,0x00,0x00,0xea,0x10,0x0e,0x1b,0xee,0x05,0x00,0x00,0xea,0x10,0x0e,0x1c,0xee, 0x03,0x00,0x00,0xea,0x10,0x0e,0x1d,0xee,0x01,0x00,0x00,0xea,0x10,0x0e,0x1a,0xee, 0xff,0xff,0xff,0xea,0x53,0x00,0x00,0xeb,0xf8,0xfe,0xff,0xea,0x55,0x00,0x00,0xeb, 0x00,0x10,0xa0,0xe1,0x53,0x00,0x00,0xeb,0x00,0x20,0x8f,0xe2,0x81,0xf1,0x82,0xe0, 0x10,0x0f,0x00,0xee,0xf1,0xfe,0xff,0xea,0x30,0x0f,0x00,0xee,0xef,0xfe,0xff,0xea, 0x10,0x0f,0x01,0xee,0xed,0xfe,0xff,0xea,0x30,0x0f,0x01,0xee,0xeb,0xfe,0xff,0xea, 0x10,0x0f,0x02,0xee,0xe9,0xfe,0xff,0xea,0x10,0x0f,0x03,0xee,0xe7,0xfe,0xff,0xea, 0x10,0x0f,0x05,0xee,0xe5,0xfe,0xff,0xea,0x10,0x0f,0x06,0xee,0xe3,0xfe,0xff,0xea, 0x10,0x0f,0x0d,0xee,0xe1,0xfe,0xff,0xea,0x10,0x0f,0x0f,0xee,0xdf,0xfe,0xff,0xea, 0x18,0x0f,0x0e,0xee,0xdd,0xfe,0xff,0xea,0x19,0x0f,0x0e,0xee,0xdb,0xfe,0xff,0xea, 0x10,0x0f,0x0e,0xee,0xd9,0xfe,0xff,0xea,0x13,0x0f,0x0e,0xee,0xd7,0xfe,0xff,0xea, 0x14,0x0f,0x0e,0xee,0xd5,0xfe,0xff,0xea,0x10,0x0e,0x0b,0xee,0xd3,0xfe,0xff,0xea, 0x10,0x0e,0x0c,0xee,0xd1,0xfe,0xff,0xea,0x10,0x0e,0x0d,0xee,0xcf,0xfe,0xff,0xea, 0x10,0x0e,0x0a,0xee,0xcd,0xfe,0xff,0xea,0x01,0x1c,0xa0,0xe3,0x10,0x0e,0x1b,0xee, 0x24,0x00,0x00,0xeb,0x01,0x10,0x51,0xe2,0xfb,0xff,0xff,0x1a,0x10,0x0e,0x1c,0xee, 0x20,0x00,0x00,0xeb,0x10,0x0e,0x1d,0xee,0x1e,0x00,0x00,0xeb,0xc3,0xfe,0xff,0xea, 0x01,0x1c,0xa0,0xe3,0x10,0x0e,0x1b,0xee,0x01,0x10,0x51,0xe2,0xfc,0xff,0xff,0x1a, 0xbe,0xfe,0xff,0xea,0x1b,0x00,0x00,0xeb,0x00,0xf0,0x69,0xe1,0x19,0x00,0x00,0xeb, 0x00,0x70,0xa0,0xe1,0x17,0x00,0x00,0xeb,0x00,0x60,0xa0,0xe1,0x15,0x00,0x00,0xeb, 0x00,0x50,0xa0,0xe1,0x13,0x00,0x00,0xeb,0x00,0x40,0xa0,0xe1,0x11,0x00,0x00,0xeb, 0x00,0x30,0xa0,0xe1,0x0f,0x00,0x00,0xeb,0x00,0x20,0xa0,0xe1,0x0d,0x00,0x00,0xeb, 0x00,0x10,0xa0,0xe1,0x0b,0x00,0x00,0xeb,0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x5a, 0x10,0xee,0x19,0xee,0x10,0xde,0x1a,0xee,0x01,0xd0,0x8d,0xe3,0x10,0xde,0x0a,0xee, 0x00,0xf0,0x5e,0xe2,0xfe,0xff,0xff,0xea,0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x6a, 0x10,0x0e,0x08,0xee,0x0e,0xf0,0xa0,0xe1,0x10,0xfe,0x1e,0xee,0xfd,0xff,0xff,0x5a, 0x10,0x0e,0x19,0xee,0x0e,0xf0,0xa0,0xe1, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/debug/xscale/debug_handler.ld ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* identify the Entry Point */ ENTRY(reset_handler) /* specify the mini-ICache memory areas */ MEMORY { mini_icache_0 (x) : ORIGIN = 0x0, LENGTH = 1024 /* first part of mini icache (sets 0-31) */ mini_icache_1 (x) : ORIGIN = 0x400, LENGTH = 1024 /* second part of mini icache (sets 0-31) */ } /* now define the output sections */ SECTIONS { .part1 : { LONG(0) LONG(0) LONG(0) LONG(0) LONG(0) LONG(0) LONG(0) LONG(0) *(.part1) } >mini_icache_0 .part2 : { LONG(0) LONG(0) LONG(0) LONG(0) LONG(0) LONG(0) LONG(0) LONG(0) *(.part2) FILL(0x0) } >mini_icache_1 /DISCARD/ : { *(.text) *(.glue_7) *(.glue_7t) *(.data) *(.bss) } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/debug/xscale/protocol.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #define REG_R0 0 #define REG_R1 1 #define REG_R2 2 #define REG_R3 3 #define REG_R4 4 #define REG_R5 5 #define REG_R6 6 #define REG_R7 7 #define REG_R8 8 #define REG_R9 9 #define REG_R10 10 #define REG_R11 11 #define REG_R12 12 #define REG_R13 13 #define REG_R14 14 #define REG_R15 15 #define REG_CPSR 16 #define REG_SPSR 17 #define MODE_USR 0x10 #define MODE_FIQ 0x11 #define MODE_IRQ 0x12 #define MODE_SVC 0x13 #define MODE_ABT 0x17 #define MODE_UND 0x1b #define MODE_SYS 0x1f #define MODE_ANY 0x40 #define MODE_CURRENT 0x80 #define MODE_MASK 0x1f #define PSR_I 0x80 #define PSR_F 0x40 #define PSR_T 0x20 #define XSCALE_DBG_MAINID 0x0 #define XSCALE_DBG_CACHETYPE 0x1 #define XSCALE_DBG_CTRL 0x2 #define XSCALE_DBG_AUXCTRL 0x3 #define XSCALE_DBG_TTB 0x4 #define XSCALE_DBG_DAC 0x5 #define XSCALE_DBG_FSR 0x6 #define XSCALE_DBG_FAR 0x7 #define XSCALE_DBG_PID 0x8 #define XSCALE_DBG_CPACCESS 0x9 #define XSCALE_DBG_IBCR0 0xa #define XSCALE_DBG_IBCR1 0xb #define XSCALE_DBG_DBR0 0xc #define XSCALE_DBG_DBR1 0xd #define XSCALE_DBG_DBCON 0xe ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/erase_check/armv4_5_erase_check.inc ================================================ /* Autogenerated with ../../../src/helper/bin2char.sh */ 0x01,0x30,0xd0,0xe4,0x03,0x20,0x02,0xe0,0x01,0x10,0x51,0xe2,0xfb,0xff,0xff,0x1a, 0x70,0x00,0x20,0xe1, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/erase_check/armv4_5_erase_check.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ /* parameters: r0 - address in r1 - byte count r2 - mask - result out */ .text .arm loop: ldrb r3, [r0], #1 and r2, r2, r3 subs r1, r1, #1 bne loop end: bkpt #0 .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/erase_check/armv7m_erase_check.inc ================================================ /* Autogenerated with ../../../src/helper/bin2char.sh */ 0x02,0x68,0x12,0x42,0x0d,0xd0,0x43,0x68,0x1c,0x68,0x04,0x33,0x8c,0x42,0x05,0xd1, 0x01,0x3a,0xf9,0xd1,0x01,0x24,0x04,0x60,0x08,0x30,0xf1,0xe7,0x00,0x24,0xfa,0xe7, 0x00,0x00,0x00,0xbe, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/erase_check/armv7m_erase_check.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ /* parameters: r0 - pointer to struct { uint32_t size_in_result_out, uint32_t addr } r1 - value to check */ .text .syntax unified .cpu cortex-m0 .thumb .thumb_func .align 2 BLOCK_SIZE_RESULT = 0 BLOCK_ADDRESS = 4 SIZEOF_STRUCT_BLOCK = 8 start: block_loop: ldr r2, [r0, #BLOCK_SIZE_RESULT] /* get size */ tst r2, r2 beq done ldr r3, [r0, #BLOCK_ADDRESS] /* get address */ word_loop: ldr r4, [r3] /* read word */ adds r3, #4 cmp r4, r1 bne not_erased subs r2, #1 bne word_loop movs r4, #1 /* block is erased */ save_result: str r4, [r0, #BLOCK_SIZE_RESULT] adds r0, #SIZEOF_STRUCT_BLOCK b block_loop not_erased: movs r4, #0 b save_result /* Avoid padding at .text segment end. Otherwise exit point check fails. */ .skip ( . - start + 2) & 2, 0 done: bkpt #0 .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/erase_check/stm8_erase_check.inc ================================================ /* Autogenerated with ../../../src/helper/bin2char.sh */ 0x00,0x80,0x00,0x00,0x80,0x00,0x96,0xcf,0x00,0x22,0x1e,0x01,0x16,0x04,0xa6,0xff, 0x90,0x5d,0x26,0x04,0x0d,0x03,0x27,0x17,0x90,0x5d,0x26,0x02,0x0a,0x03,0x90,0x5a, 0x92,0xbc,0x00,0x00,0xa1,0xff,0x26,0x07,0x5c,0x26,0xe5,0x0c,0x00,0x20,0xe1,0x1f, 0x01,0x17,0x04,0x8b, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/erase_check/stm8_erase_check.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2017 Ake Rehnman * ake.rehnman(at)gmail.com */ ;; ;; erase check memory code ;; .org 0x0 ;; start address start_addr: .byte 0x00 .word 0x8000 ;; byte count byte_cnt: .byte 0x00 .word 0x8000 ; ; SP must point to start_addr on entry ; first relocate start_addr to the location ; we are running at start: ldw X,SP ldw .cont+2,X ldw X,(start_addr+1,SP) ;start addr ldw Y,(byte_cnt+1,SP) ;count ld A,#0xff ; ; if count == 0 return .L1: tnzw Y jrne .decrcnt ;continue if low word != 0 tnz (byte_cnt,SP) ;high byte jreq .exit ;goto exit ; ; decrement count (byte_cnt) .decrcnt: tnzw Y ;low word count jrne .decr1 dec (byte_cnt,SP) ;high byte .decr1: decw Y; decr low word ; ; first check if [start_addr] is 0xff .cont: ldf A, [start_addr.e] cp A,#0xff jrne .exit ;exit if not 0xff ; ; increment start_addr (addr) incw X jrne .L1 inc (start_addr,SP) ;increment high byte jra .L1 ; .exit: ldw (start_addr+1,SP),X ;start addr ldw (byte_cnt+1,SP),Y ;count break ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/armv4_5_cfi_intel_16.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ .text .arm .arch armv4 .section .init /* algorithm register usage: * r0: source address (in RAM) * r1: target address (in Flash) * r2: count * r3: flash write command * r4: status byte (returned to host) * r5: busy test pattern * r6: error test pattern */ loop: ldrh r4, [r0], #2 strh r3, [r1] strh r4, [r1] busy: ldrh r4, [r1] and r7, r4, r5 cmp r7, r5 bne busy tst r4, r6 bne done subs r2, r2, #1 beq done add r1, r1, #2 b loop done: b done .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/armv4_5_cfi_intel_32.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ .text .arm .arch armv4 .section .init /* algorithm register usage: * r0: source address (in RAM) * r1: target address (in Flash) * r2: count * r3: flash write command * r4: status byte (returned to host) * r5: busy test pattern * r6: error test pattern */ loop: ldr r4, [r0], #4 str r3, [r1] str r4, [r1] busy: ldr r4, [r1] and r7, r4, r5 cmp r7, r5 bne busy tst r4, r6 bne done subs r2, r2, #1 beq done add r1, r1, #4 b loop done: b done .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/armv4_5_cfi_intel_8.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ .text .arm .arch armv4 .section .init /* algorithm register usage: * r0: source address (in RAM) * r1: target address (in Flash) * r2: count * r3: flash write command * r4: status byte (returned to host) * r5: busy test pattern * r6: error test pattern */ loop: ldrb r4, [r0], #1 strb r3, [r1] strb r4, [r1] busy: ldrb r4, [r1] and r7, r4, r5 cmp r7, r5 bne busy tst r4, r6 bne done subs r2, r2, #1 beq done add r1, r1, #1 b loop done: b done .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/armv4_5_cfi_span_16.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ .text .arm .arch armv4 .section .init /* input parameters - */ /* R0 = source address */ /* R1 = destination address */ /* R2 = number of writes */ /* R3 = flash write command */ /* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */ /* output parameters - */ /* R5 = 0x80 ok 0x00 bad */ /* temp registers - */ /* R6 = value read from flash to test status */ /* R7 = holding register */ /* unlock registers - */ /* R8 = unlock1_addr */ /* R9 = unlock1_cmd */ /* R10 = unlock2_addr */ /* R11 = unlock2_cmd */ code: ldrh r5, [r0], #2 strh r9, [r8] strh r11, [r10] strh r3, [r8] strh r5, [r1] nop busy: ldrh r6, [r1] eor r7, r5, r6 ands r7, r4, r7 beq cont /* b if DQ7 == Data7 */ ands r6, r6, r4, lsr #2 beq busy /* b if DQ5 low */ ldrh r6, [r1] eor r7, r5, r6 ands r7, r4, r7 beq cont /* b if DQ7 == Data7 */ mov r5, #0 /* 0x0 - return 0x00, error */ bne done cont: subs r2, r2, #1 /* 0x1 */ moveq r5, #128 /* 0x80 */ beq done add r1, r1, #2 /* 0x2 */ b code done: b done .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/armv4_5_cfi_span_16_dq7.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ .text .arm .arch armv4 .section .init /* input parameters - */ /* R0 = source address */ /* R1 = destination address */ /* R2 = number of writes */ /* R3 = flash write command */ /* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */ /* output parameters - */ /* R5 = 0x80 ok 0x00 bad */ /* temp registers - */ /* R6 = value read from flash to test status */ /* R7 = holding register */ /* unlock registers - */ /* R8 = unlock1_addr */ /* R9 = unlock1_cmd */ /* R10 = unlock2_addr */ /* R11 = unlock2_cmd */ code: ldrh r5, [r0], #2 strh r9, [r8] strh r11, [r10] strh r3, [r8] strh r5, [r1] nop busy: ldrh r6, [r1] eor r7, r5, r6 ands r7, #0x80 bne busy subs r2, r2, #1 /* 0x1 */ moveq r5, #128 /* 0x80 */ beq done add r1, r1, #2 /* 0x2 */ b code done: b done .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/armv4_5_cfi_span_32.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ .text .arm .arch armv4 .section .init /* input parameters - */ /* R0 = source address */ /* R1 = destination address */ /* R2 = number of writes */ /* R3 = flash write command */ /* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */ /* output parameters - */ /* R5 = 0x80 ok 0x00 bad */ /* temp registers - */ /* R6 = value read from flash to test status */ /* R7 = holding register */ /* unlock registers - */ /* R8 = unlock1_addr */ /* R9 = unlock1_cmd */ /* R10 = unlock2_addr */ /* R11 = unlock2_cmd */ code: ldr r5, [r0], #4 str r9, [r8] str r11, [r10] str r3, [r8] str r5, [r1] nop busy: ldr r6, [r1] eor r7, r5, r6 ands r7, r4, r7 beq cont /* b if DQ7 == Data7 */ ands r6, r6, r4, lsr #2 beq busy /* b if DQ5 low */ ldr r6, [r1] eor r7, r5, r6 ands r7, r4, r7 beq cont /* b if DQ7 == Data7 */ mov r5, #0 /* 0x0 - return 0x00, error */ bne done cont: subs r2, r2, #1 /* 0x1 */ moveq r5, #128 /* 0x80 */ beq done add r1, r1, #4 /* 0x4 */ b code done: b done .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/armv4_5_cfi_span_8.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ .text .arm .arch armv4 .section .init /* input parameters - */ /* R0 = source address */ /* R1 = destination address */ /* R2 = number of writes */ /* R3 = flash write command */ /* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */ /* output parameters - */ /* R5 = 0x80 ok 0x00 bad */ /* temp registers - */ /* R6 = value read from flash to test status */ /* R7 = holding register */ /* unlock registers - */ /* R8 = unlock1_addr */ /* R9 = unlock1_cmd */ /* R10 = unlock2_addr */ /* R11 = unlock2_cmd */ code: ldrb r5, [r0], #1 strb r9, [r8] strb r11, [r10] strb r3, [r8] strb r5, [r1] nop busy: ldrb r6, [r1] eor r7, r5, r6 ands r7, r4, r7 beq cont /* b if DQ7 == Data7 */ ands r6, r6, r4, lsr #2 beq busy /* b if DQ5 low */ ldrb r6, [r1] eor r7, r5, r6 ands r7, r4, r7 beq cont /* b if DQ7 == Data7 */ mov r5, #0 /* 0x0 - return 0x00, error */ bne done cont: subs r2, r2, #1 /* 0x1 */ moveq r5, #128 /* 0x80 */ beq done add r1, r1, #1 /* 0x1 */ b code done: b done .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/armv7m_cfi_span_16.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ .text .syntax unified .arch armv7-m .thumb .thumb_func .align 2 /* input parameters - */ /* R0 = source address */ /* R1 = destination address */ /* R2 = number of writes */ /* R3 = flash write command */ /* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */ /* output parameters - */ /* R5 = 0x80 ok 0x00 bad */ /* temp registers - */ /* R6 = value read from flash to test status */ /* R7 = holding register */ /* unlock registers - */ /* R8 = unlock1_addr */ /* R9 = unlock1_cmd */ /* R10 = unlock2_addr */ /* R11 = unlock2_cmd */ code: ldrh r5, [r0], #2 strh r9, [r8] strh r11, [r10] strh r3, [r8] strh r5, [r1] nop busy: ldrh r6, [r1] eor r7, r5, r6 ands r7, r4, r7 beq cont /* b if DQ7 == Data7 */ ands r6, r6, r4, lsr #2 beq busy /* b if DQ5 low */ ldrh r6, [r1] eor r7, r5, r6 ands r7, r4, r7 beq cont /* b if DQ7 == Data7 */ mov r5, #0 /* 0x0 - return 0x00, error */ bne done cont: subs r2, r2, #1 /* 0x1 */ beq success add r1, r1, #2 /* 0x2 */ b code success: mov r5, #128 /* 0x80 */ b done done: bkpt #0 .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/armv7m_cfi_span_16_dq7.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ .text .syntax unified .arch armv7-m .thumb .thumb_func .align 2 /* input parameters - */ /* R0 = source address */ /* R1 = destination address */ /* R2 = number of writes */ /* R3 = flash write command */ /* R4 = constant to mask DQ7 bits */ /* output parameters - */ /* R5 = 0x80 ok 0x00 bad */ /* temp registers - */ /* R6 = value read from flash to test status */ /* R7 = holding register */ /* unlock registers - */ /* R8 = unlock1_addr */ /* R9 = unlock1_cmd */ /* R10 = unlock2_addr */ /* R11 = unlock2_cmd */ code: ldrh r5, [r0], #2 strh r9, [r8] strh r11, [r10] strh r3, [r8] strh r5, [r1] nop busy: ldrh r6, [r1] eor r7, r5, r6 ands r7, r4, r7 bne busy subs r2, r2, #1 /* 0x1 */ beq success add r1, r1, #2 /* 0x2 */ b code success: mov r5, #128 /* 0x80 */ b done done: bkpt #0 .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/armv7m_io.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2013 by Henrik Nilsson * * henrik.nilsson@bytequest.se * ***************************************************************************/ .text .syntax unified .arch armv7-m .thumb .thumb_func .align 4 /* Inputs: * r0 buffer address * r1 NAND data address (byte wide) * r2 buffer length */ read: ldrb r3, [r1] strb r3, [r0], #1 subs r2, r2, #1 bne read done_read: bkpt #0 .align 4 /* Inputs: * r0 NAND data address (byte wide) * r1 buffer address * r2 buffer length */ write: ldrb r3, [r1], #1 strb r3, [r0] subs r2, r2, #1 bne write done_write: bkpt #0 .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/at91sam7x/at91sam7x_ocl_flash.script ================================================ # SPDX-License-Identifier: GPL-2.0-or-later soft_reset_halt load_image at91sam7x_ocl.bin 0x200000 resume 0x200000 flash probe 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/at91sam7x/at91sam7x_ram.ld ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. **************************************************************************** * * History: * * 30.03.06 mifi First Version ****************************************************************************/ ENTRY(ResetHandler) SEARCH_DIR(.) /* * Define stack size here */ FIQ_STACK_SIZE = 0x0100; IRQ_STACK_SIZE = 0x0100; ABT_STACK_SIZE = 0x0100; UND_STACK_SIZE = 0x0100; SVC_STACK_SIZE = 0x0100; MEMORY { ram : org = 0x00200000, len = 64k } /* * Do not change the next code */ SECTIONS { .text : { *(.vectors); . = ALIGN(4); *(.init); . = ALIGN(4); *(.text); . = ALIGN(4); *(.rodata); . = ALIGN(4); *(.rodata*); . = ALIGN(4); *(.glue_7t); . = ALIGN(4); *(.glue_7); . = ALIGN(4); etext = .; } > ram .data : { PROVIDE (__data_start = .); *(.data) . = ALIGN(4); edata = .; _edata = .; PROVIDE (__data_end = .); } > ram .bss : { PROVIDE (__bss_start = .); *(.bss) *(COMMON) . = ALIGN(4); PROVIDE (__bss_end = .); . = ALIGN(256); PROVIDE (__stack_start = .); PROVIDE (__stack_fiq_start = .); . += FIQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_fiq_end = .); PROVIDE (__stack_irq_start = .); . += IRQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_irq_end = .); PROVIDE (__stack_abt_start = .); . += ABT_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_abt_end = .); PROVIDE (__stack_und_start = .); . += UND_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_und_end = .); PROVIDE (__stack_svc_start = .); . += SVC_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_svc_end = .); PROVIDE (__stack_end = .); PROVIDE (__heap_start = .); } > ram } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/at91sam7x/crt.s ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. **************************************************************************** * * History: * * 18.12.06 mifi First Version * The hardware initialization is based on the startup file * crtat91sam7x256_rom.S from NutOS 4.2.1. * Therefore partial copyright by egnite Software GmbH. ****************************************************************************/ /* * Some defines for the program status registers */ ARM_MODE_USER = 0x10 /* Normal User Mode */ ARM_MODE_FIQ = 0x11 /* FIQ Fast Interrupts Mode */ ARM_MODE_IRQ = 0x12 /* IRQ Standard Interrupts Mode */ ARM_MODE_SVC = 0x13 /* Supervisor Interrupts Mode */ ARM_MODE_ABORT = 0x17 /* Abort Processing memory Faults Mode */ ARM_MODE_UNDEF = 0x1B /* Undefined Instructions Mode */ ARM_MODE_SYS = 0x1F /* System Running in Privileged Operating Mode */ ARM_MODE_MASK = 0x1F I_BIT = 0x80 /* disable IRQ when I bit is set */ F_BIT = 0x40 /* disable IRQ when I bit is set */ /* * Register Base Address */ AIC_BASE = 0xFFFFF000 AIC_EOICR_OFF = 0x130 AIC_IDCR_OFF = 0x124 RSTC_MR = 0xFFFFFD08 RSTC_KEY = 0xA5000000 RSTC_URSTEN = 0x00000001 WDT_BASE = 0xFFFFFD40 WDT_MR_OFF = 0x00000004 WDT_WDDIS = 0x00008000 MC_BASE = 0xFFFFFF00 MC_FMR_OFF = 0x00000060 MC_FWS_1FWS = 0x00480100 .section .vectors,"ax" .code 32 /****************************************************************************/ /* Vector table and reset entry */ /****************************************************************************/ _vectors: ldr pc, ResetAddr /* Reset */ ldr pc, UndefAddr /* Undefined instruction */ ldr pc, SWIAddr /* Software interrupt */ ldr pc, PAbortAddr /* Prefetch abort */ ldr pc, DAbortAddr /* Data abort */ ldr pc, ReservedAddr /* Reserved */ ldr pc, IRQAddr /* IRQ interrupt */ ldr pc, FIQAddr /* FIQ interrupt */ ResetAddr: .word ResetHandler UndefAddr: .word UndefHandler SWIAddr: .word SWIHandler PAbortAddr: .word PAbortHandler DAbortAddr: .word DAbortHandler ReservedAddr: .word 0 IRQAddr: .word IRQHandler FIQAddr: .word FIQHandler .ltorg .section .init, "ax" .code 32 .global ResetHandler .global ExitFunction .extern main /****************************************************************************/ /* Reset handler */ /****************************************************************************/ ResetHandler: /* * The watchdog is enabled after processor reset. Disable it. */ ldr r1, =WDT_BASE ldr r0, =WDT_WDDIS str r0, [r1, #WDT_MR_OFF] /* * Enable user reset: assertion length programmed to 1ms */ ldr r0, =(RSTC_KEY | RSTC_URSTEN | (4 << 8)) ldr r1, =RSTC_MR str r0, [r1, #0] /* * Use 2 cycles for flash access. */ ldr r1, =MC_BASE ldr r0, =MC_FWS_1FWS str r0, [r1, #MC_FMR_OFF] /* * Disable all interrupts. Useful for debugging w/o target reset. */ ldr r1, =AIC_BASE mvn r0, #0 str r0, [r1, #AIC_EOICR_OFF] str r0, [r1, #AIC_IDCR_OFF] /* * Setup a stack for each mode */ msr CPSR_c, #ARM_MODE_UNDEF | I_BIT | F_BIT /* Undefined Instruction Mode */ ldr sp, =__stack_und_end msr CPSR_c, #ARM_MODE_ABORT | I_BIT | F_BIT /* Abort Mode */ ldr sp, =__stack_abt_end msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT /* FIQ Mode */ ldr sp, =__stack_fiq_end msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT /* IRQ Mode */ ldr sp, =__stack_irq_end msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT /* Supervisor Mode */ ldr sp, =__stack_svc_end /* * Clear .bss section */ ldr r1, =__bss_start ldr r2, =__bss_end ldr r3, =0 bss_clear_loop: cmp r1, r2 strne r3, [r1], #+4 bne bss_clear_loop /* * Jump to main */ mrs r0, cpsr bic r0, r0, #I_BIT | F_BIT /* Enable FIQ and IRQ interrupt */ msr cpsr, r0 mov r0, #0 /* No arguments */ mov r1, #0 /* No arguments */ ldr r2, =main mov lr, pc bx r2 /* And jump... */ ExitFunction: nop nop nop b ExitFunction /****************************************************************************/ /* Default interrupt handler */ /****************************************************************************/ UndefHandler: b UndefHandler SWIHandler: b SWIHandler PAbortHandler: b PAbortHandler DAbortHandler: b DAbortHandler IRQHandler: b IRQHandler FIQHandler: b FIQHandler .weak ExitFunction .weak UndefHandler, PAbortHandler, DAbortHandler .weak IRQHandler, FIQHandler .ltorg /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/at91sam7x/dcc.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * ***************************************************************************/ #include "dcc.h" /* debug channel read (debugger->MCU) */ uint32 dcc_rd(void) { volatile uint32 dcc_reg; do { asm volatile ("mrc p14, 0, %0, C0, C0" : "=r" (dcc_reg) :); } while ((dcc_reg&1) == 0); asm volatile ("mrc p14, 0, %0, C1, C0" : "=r" (dcc_reg) :); return dcc_reg; } /* debug channel write (MCU->debugger) */ int dcc_wr(uint32 data) { volatile uint32 dcc_reg; do { asm volatile ("mrc p14, 0, %0, C0, C0" : "=r" (dcc_reg) :); /* operation controlled by master, cancel operation upon reception of data for immediate response */ if (dcc_reg&1) return -1; } while (dcc_reg&2); asm volatile ("mcr p14, 0, %0, C1, C0" : : "r" (data)); return 0; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/at91sam7x/dcc.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * ***************************************************************************/ #ifndef dccH #define dccH #include "platform.h" /* debug channel read (debugger->MCU) */ uint32 dcc_rd(void); /* debug channel write (MCU->debugger) */ int dcc_wr(uint32 data); #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/at91sam7x/main.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * ***************************************************************************/ #include "platform.h" #include #include "dcc.h" #include "samflash.h" #define BUFSIZE 1024 /* words, i.e. 4 KiB */ uint32 buffer[1024]; void cmd_flash(uint32 cmd) { unsigned int len; uint32 adr; uint32 chksum; unsigned int bi; /* buffer index */ unsigned int bi_start; /* receive start mark */ unsigned int bi_end; /* receive end mark */ unsigned int ofs; int pagenum; int result; adr = dcc_rd(); len = cmd&0xffff; ofs = adr%flash_page_size; bi_start = ofs/4; bi_end = (ofs + len + 3)/4; if (bi_end > BUFSIZE) { dcc_wr(OCL_BUFF_OVER); return; } chksum = OCL_CHKS_INIT; for (bi = 0; bi < bi_end; bi++) chksum^=buffer[bi]=dcc_rd(); if (dcc_rd() != chksum) { dcc_wr(OCL_CHKS_FAIL); return; } /* fill in unused positions with unprogrammed values */ for (bi = 0; bi < bi_start; bi++) buffer[bi]=0xffffffff; for (bi = bi_end; bi%flash_page_size; bi++) buffer[bi]=0xffffffff; result = 0; pagenum = adr/flash_page_size; for (bi = 0; bi < bi_end; bi += flash_page_size/4) { result = flash_page_program(buffer + bi, pagenum++); if (result) break; } /* verify written data */ if (!result) result = flash_verify(adr, len, ((uint8 *)buffer) + ofs); dcc_wr(OCL_CMD_DONE | result); } int main (void) { uint32 cmd; for (;;) { cmd = dcc_rd(); switch (cmd&OCL_CMD_MASK) { case OCL_PROBE: dcc_wr(OCL_CMD_DONE | flash_init()); dcc_wr(0x100000); /* base */ dcc_wr(flash_page_count*flash_page_size); /* size */ dcc_wr(1); /* num_sectors */ dcc_wr(4096 | ((unsigned long) flash_page_size << 16)); /* buflen and bufalign */ break; case OCL_ERASE_ALL: dcc_wr(OCL_CMD_DONE | flash_erase_all()); break; case OCL_FLASH_BLOCK: cmd_flash(cmd); break; default: /* unknown command */ dcc_wr(OCL_CMD_ERR); break; } } return 0; /* we shall never get here, just to suppress compiler warning */ } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/at91sam7x/makefile ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ############################################################################################## # Start of default section # TRGT = arm-elf- CC = $(TRGT)gcc CP = $(TRGT)objcopy AS = $(TRGT)gcc -x assembler-with-cpp HEX = $(CP) -O ihex BIN = $(CP) -O binary OBJDUMP = $(TRGT)objdump MCU = arm7tdmi # List all default C defines here, like -D_DEBUG=1 DDEFS = # List all default ASM defines here, like -D_DEBUG=1 DADEFS = # List all default directories to look for include files here DINCDIR = # List the default directory to look for the libraries here DLIBDIR = # List all default libraries here DLIBS = # # End of default section ############################################################################################## ############################################################################################## # Start of user section # # Define project name here PROJECT = at91sam7x_ocl # Define linker script file here LDSCRIPT= at91sam7x_ram.ld # List all user C define here, like -D_DEBUG=1 UDEFS = # Define ASM defines here UADEFS = # List C source files here SRC = main.c dcc.c samflash.c # List ASM source files here ASRC = crt.s # List all user directories here UINCDIR = # List the user directory to look for the libraries here ULIBDIR = # List all user libraries here ULIBS = # Define optimisation level here OPT = -O2 # # End of user defines ############################################################################################## INCDIR = $(patsubst %,-I%,$(DINCDIR) $(UINCDIR)) LIBDIR = $(patsubst %,-L%,$(DLIBDIR) $(ULIBDIR)) DEFS = $(DDEFS) $(UDEFS) ADEFS = $(DADEFS) $(UADEFS) OBJS = $(ASRC:.s=.o) $(SRC:.c=.o) LIBS = $(DLIBS) $(ULIBS) MCFLAGS = -mcpu=$(MCU) ASFLAGS = $(MCFLAGS) -g -gdwarf-2 -Wa,-amhls=$(<:.s=.lst) $(ADEFS) CPFLAGS = $(MCFLAGS) $(OPT) -gdwarf-2 -mthumb-interwork -fomit-frame-pointer -Wall -Wstrict-prototypes -fverbose-asm -Wa,-ahlms=$(<:.c=.lst) $(DEFS) LDFLAGS = $(MCFLAGS) -nostartfiles -T$(LDSCRIPT) -Wl,-Map=$(PROJECT).map,--cref,--no-warn-mismatch $(LIBDIR) # Generate dependency information #CPFLAGS += -MD -MP -MF .dep/$(@F).d # # makefile rules # all: $(OBJS) $(PROJECT).elf $(PROJECT).hex $(PROJECT).bin $(PROJECT).lst %o : %c $(CC) -c $(CPFLAGS) -I . $(INCDIR) $< -o $@ %o : %s $(AS) -c $(ASFLAGS) $< -o $@ %elf: $(OBJS) $(CC) $(OBJS) $(LDFLAGS) $(LIBS) -o $@ %hex: %elf $(HEX) $< $@ %bin: %elf $(BIN) $< $@ %.lst: %.elf $(OBJDUMP) -h -S $< > $@ clean: -rm -f $(OBJS) -rm -f $(PROJECT).elf -rm -f $(PROJECT).map -rm -f $(PROJECT).hex -rm -f $(PROJECT).bin -rm -f $(PROJECT).lst -rm -f $(SRC:.c=.c.bak) -rm -f $(SRC:.c=.lst) -rm -f $(ASRC:.s=.s.bak) -rm -f $(ASRC:.s=.lst) -rm -fR .dep # # Include the dependency files, should be the last of the makefile # #-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) # *** EOF *** ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/at91sam7x/ocl.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * ***************************************************************************/ #ifndef OCL_H #define OCL_H /* command/response mask */ #define OCL_CMD_MASK 0xFFFF0000L /* commands */ #define OCL_FLASH_BLOCK 0x0CFB0000L #define OCL_ERASE_BLOCK 0x0CEB0000L #define OCL_ERASE_ALL 0x0CEA0000L #define OCL_PROBE 0x0CBE0000L /* responses */ #define OCL_CMD_DONE 0x0ACD0000L #define OCL_CMD_ERR 0x0ACE0000L #define OCL_CHKS_FAIL 0x0ACF0000L #define OCL_BUFF_OVER 0x0AB00000L #define OCL_CHKS_INIT 0xC100CD0CL #endif /* OCL_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/at91sam7x/platform.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * ***************************************************************************/ #ifndef platformH #define platformH #include "samregs.h" #define outb(_reg, _val) (*((volatile unsigned char *)(_reg)) = (_val)) #define outw(_reg, _val) (*((volatile unsigned short *)(_reg)) = (_val)) #define outr(_reg, _val) (*((volatile unsigned int *)(_reg)) = (_val)) #define inb(_reg) (*((volatile unsigned char *)(_reg))) #define inw(_reg) (*((volatile unsigned short *)(_reg))) #define inr(_reg) (*((volatile unsigned int *)(_reg))) #define _BV(bit) (1 << (bit)) typedef signed char int8; typedef unsigned char uint8; typedef signed short int16; typedef unsigned short uint16; typedef signed int int32; typedef unsigned int uint32; #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/at91sam7x/samflash.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * ***************************************************************************/ #include "samflash.h" unsigned int flash_page_count = 1024; unsigned int flash_page_size = 256; /* pages per lock bit */ unsigned int flash_lock_pages = 1024/16; /* detect chip and set loader parameters */ int flash_init(void) { unsigned int nvpsiz; nvpsiz = (inr(DBGU_CIDR) >> 8)&0xf; switch (nvpsiz) { case 3: /* AT91SAM7x32 */ flash_page_count = 256; flash_page_size = 128; flash_lock_pages = 256/8; break; case 5: /* AT91SAM7x64 */ flash_page_count = 512; flash_page_size = 128; flash_lock_pages = 512/16; break; case 7: /* AT91SAM7x128*/ flash_page_count = 512; flash_page_size = 256; flash_lock_pages = 512/8; break; case 9: /* AT91SAM7x256 */ flash_page_count = 1024; flash_page_size = 256; flash_lock_pages = 1024/16; break; case 10: /* AT91SAM7x512 */ flash_page_count = 2048; flash_page_size = 256; flash_lock_pages = 2048/32; break; default: return FLASH_STAT_INITE; } return FLASH_STAT_OK; } /* program single flash page */ int flash_page_program(uint32 *data, int page_num) { int i; int efc_ofs; uint32 *flash_ptr; uint32 *data_ptr; /* select proper controller */ if (page_num >= 1024) efc_ofs = 0x10; else efc_ofs = 0; /* wait until FLASH is ready, just for sure */ while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0); /* calculate page address, only lower 8 bits are used to address the latch, but the upper part of address is needed for writing to proper EFC */ flash_ptr = (uint32 *)(FLASH_AREA_ADDR + (page_num*flash_page_size)); data_ptr = data; /* copy data to latch */ for (i = flash_page_size/4; i; i--) { /* we do not use memcpy to be sure that only 32 bit access is used */ *(flash_ptr++)=*(data_ptr++); } /* page number and page write command to FCR */ outr(MC_FCR + efc_ofs, ((page_num&0x3ff) << 8) | MC_KEY | MC_FCMD_WP); /* wait until it's done */ while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0); /* check for errors */ if ((inr(MC_FSR + efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE; if ((inr(MC_FSR + efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE; #if 0 /* verify written data */ flash_ptr = (uint32 *)(FLASH_AREA_ADDR + (page_num*flash_page_size)); data_ptr = data; for (i = flash_page_size/4; i; i--) { if (*(flash_ptr++)!=*(data_ptr++)) return FLASH_STAT_VERIFE; } #endif return FLASH_STAT_OK; } int flash_erase_plane(int efc_ofs) { unsigned int lockbits; int page_num; page_num = 0; lockbits = inr(MC_FSR + efc_ofs) >> 16; while (lockbits) { if (lockbits&1) { /* wait until FLASH is ready, just for sure */ while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0); outr(MC_FCR + efc_ofs, ((page_num&0x3ff) << 8) | 0x5a000004); /* wait until it's done */ while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0); /* check for errors */ if ((inr(MC_FSR + efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE; if ((inr(MC_FSR + efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE; } if ((page_num += flash_lock_pages) > flash_page_count) break; lockbits>>=1; } /* wait until FLASH is ready, just for sure */ while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0); /* erase all command to FCR */ outr(MC_FCR + efc_ofs, 0x5a000008); /* wait until it's done */ while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0); /* check for errors */ if ((inr(MC_FSR + efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE; if ((inr(MC_FSR + efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE; /* set no erase before programming */ outr(MC_FMR + efc_ofs, inr(MC_FMR + efc_ofs) | 0x80); return FLASH_STAT_OK; } /* erase whole chip */ int flash_erase_all(void) { int result; if ((result = flash_erase_plane(0)) != FLASH_STAT_OK) return result; /* the second flash controller, if any */ if (flash_page_count > 1024) result = flash_erase_plane(0x10); return result; } int flash_verify(uint32 adr, unsigned int len, uint8 *src) { unsigned char *flash_ptr; flash_ptr = (uint8 *)FLASH_AREA_ADDR + adr; for (;len; len--) { if (*(flash_ptr++)!=*(src++)) return FLASH_STAT_VERIFE; } return FLASH_STAT_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/at91sam7x/samflash.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * ***************************************************************************/ #ifndef samflashH #define samflashH #include "platform.h" #define FLASH_AREA_ADDR 0x100000 #define FLASH_STAT_OK 0 #define FLASH_STAT_PROGE 1 #define FLASH_STAT_LOCKE 2 #define FLASH_STAT_VERIFE 3 #define FLASH_STAT_INITE 4 extern unsigned int flash_page_count; extern unsigned int flash_page_size; /* words */ /* detect chip and set loader parameters */ int flash_init(void); /* program single flash page */ int flash_page_program(uint32 *data, int page_num); /* erase whole chip */ int flash_erase_all(void); /* verify written data */ int flash_verify(uint32 adr, unsigned int len, uint8 *src); #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/at91sam7x/samregs.h ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright (C) 2005-2006 by egnite Software GmbH. All rights reserved. * * For additional information see http://www.ethernut.de/ */ #ifndef samregsH #define samregsH /* * Register definitions below copied from NutOS */ #define DBGU_BASE 0xFFFFF200 /*!< \brief DBGU base address. */ #define DBGU_CIDR_OFF 0x00000040 /*!< \brief DBGU chip ID register offset. */ #define DBGU_CIDR (DBGU_BASE + DBGU_CIDR_OFF) /*!< \brief DBGU chip ID register. */ #define MC_BASE 0xFFFFFF00 /*!< \brief Memory controller base. */ #define MC_FMR_OFF 0x00000060 /*!< \brief MC flash mode register offset. */ #define MC_FMR (MC_BASE + MC_FMR_OFF) /*!< \brief MC flash mode register address. */ #define MC_FRDY 0x00000001 /*!< \brief Flash ready. */ #define MC_LOCKE 0x00000004 /*!< \brief Lock error. */ #define MC_PROGE 0x00000008 /*!< \brief Programming error. */ #define MC_NEBP 0x00000080 /*!< \brief No erase before programming. */ #define MC_FWS_MASK 0x00000300 /*!< \brief Flash wait state mask. */ #define MC_FWS_1R2W 0x00000000 /*!< \brief 1 cycle for read, 2 for write operations. */ #define MC_FWS_2R3W 0x00000100 /*!< \brief 2 cycles for read, 3 for write operations. */ #define MC_FWS_3R4W 0x00000200 /*!< \brief 3 cycles for read, 4 for write operations. */ #define MC_FWS_4R4W 0x00000300 /*!< \brief 4 cycles for read and write operations. */ #define MC_FMCN_MASK 0x00FF0000 /*!< \brief Flash microsecond cycle number mask. */ #define MC_FCR_OFF 0x00000064 /*!< \brief MC flash command register offset. */ #define MC_FCR (MC_BASE + MC_FCR_OFF) /*!< \brief MC flash command register address. */ #define MC_FCMD_MASK 0x0000000F /*!< \brief Flash command mask. */ #define MC_FCMD_NOP 0x00000000 /*!< \brief No command. */ #define MC_FCMD_WP 0x00000001 /*!< \brief Write page. */ #define MC_FCMD_SLB 0x00000002 /*!< \brief Set lock bit. */ #define MC_FCMD_WPL 0x00000003 /*!< \brief Write page and lock. */ #define MC_FCMD_CLB 0x00000004 /*!< \brief Clear lock bit. */ #define MC_FCMD_EA 0x00000008 /*!< \brief Erase all. */ #define MC_FCMD_SGPB 0x0000000B /*!< \brief Set general purpose NVM bit. */ #define MC_FCMD_CGPB 0x0000000D /*!< \brief Clear general purpose NVM bit. */ #define MC_FCMD_SSB 0x0000000F /*!< \brief Set security bit. */ #define MC_PAGEN_MASK 0x0003FF00 /*!< \brief Page number mask. */ #define MC_KEY 0x5A000000 /*!< \brief Writing protect key. */ #define MC_FSR_OFF 0x00000068 /*!< \brief MC flash status register offset. */ #define MC_FSR (MC_BASE + MC_FSR_OFF) /*!< \brief MC flash status register address. */ #define MC_SECURITY 0x00000010 /*!< \brief Security bit status. */ #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* To be built with arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m0 -O3 bluenrgx.c */ /* Then postprocess output of command "arm-none-eabi-objdump -d bluenrgx.o" to make a C array of bytes */ #include #include "../../../../src/flash/nor/bluenrg-x.h" /* Status Values ----------------------------------------------------------*/ #define SUCCESS 0 #define ERR_UNALIGNED 1 #define ERR_INVALID_ADDRESS 2 #define ERR_INVALID_TYPE 3 #define ERR_WRITE_PROTECTED 4 #define ERR_WRITE_FAILED 5 #define ERR_ERASE_REQUIRED 6 #define ERR_VERIFY_FAILED 7 #define MFB_MASS_ERASE 0x01 #define MFB_PAGE_ERASE 0x02 #define DO_ERASE 0x0100 #define DO_VERIFY 0x0200 #define MFB_BOTTOM (0x10040000) #define MFB_SIZE_B(regs_base) ((16 * (((*(volatile uint32_t *)(regs_base + FLASH_SIZE_REG)) + 1) >> 12)) * 1024) #define MFB_SIZE_W (MFB_SIZE_B/4) #define MFB_TOP (MFB_BOTTOM+MFB_SIZE_B-1) #define MFB_PAGE_SIZE_B (2048) #define MFB_PAGE_SIZE_W (MFB_PAGE_SIZE_B/4) #define AREA_ERROR 0x01 #define AREA_MFB 0x04 typedef struct { volatile uint8_t *wp; uint8_t *rp; } work_area_t; /* Flash Commands --------------------------------------------------------*/ static inline __attribute__((always_inline)) uint32_t flashWrite(uint32_t address, uint8_t **data, uint32_t writeLength, uint32_t flash_regs_base) { uint32_t index, flash_word[4]; uint8_t i; *((volatile uint32_t *)(flash_regs_base + FLASH_REG_IRQMASK)) = 0; for (index = 0; index < writeLength; index += (FLASH_WORD_LEN*4)) { for (i = 0; i < 4; i++) flash_word[i] = (*(uint32_t *) (*data + i*4)); /* Clear the IRQ flags */ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_IRQRAW)) = 0x0000003F; /* Load the flash address to write */ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_ADDRESS)) = (uint16_t)((address + index - MFB_BOTTOM) >> 2); /* Prepare and load the data to flash */ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA0)) = flash_word[0]; *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA1)) = flash_word[1]; *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA2)) = flash_word[2]; *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA3)) = flash_word[3]; /* Flash write command */ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_COMMAND)) = FLASH_CMD_BURSTWRITE; /* Wait the end of the flash write command */ while ((*((volatile uint32_t *)(flash_regs_base + FLASH_REG_IRQRAW)) & FLASH_INT_CMDDONE) == 0) ; *data += (FLASH_WORD_LEN * 4); } return SUCCESS; } __attribute__((naked)) __attribute__((noreturn)) void write(uint8_t *work_area_p, uint8_t *fifo_end, uint8_t *target_address, uint32_t count, uint32_t flash_regs_base) { uint32_t retval; volatile work_area_t *work_area = (work_area_t *) work_area_p; uint8_t *fifo_start = (uint8_t *) work_area->rp; while (count) { volatile int32_t fifo_linear_size; /* Wait for some data in the FIFO */ while (work_area->rp == work_area->wp) ; if (work_area->wp == 0) { /* Aborted by other party */ break; } if (work_area->rp > work_area->wp) { fifo_linear_size = fifo_end-work_area->rp; } else { fifo_linear_size = (work_area->wp - work_area->rp); if (fifo_linear_size < 0) fifo_linear_size = 0; } if (fifo_linear_size < 16) { /* We should never get here */ continue; } retval = flashWrite((uint32_t) target_address, (uint8_t **) &work_area->rp, fifo_linear_size, flash_regs_base); if (retval != SUCCESS) { work_area->rp = (uint8_t *)retval; break; } target_address += fifo_linear_size; if (work_area->rp >= fifo_end) work_area->rp = fifo_start; count -= fifo_linear_size; } __asm("bkpt 0"); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x05,0x93,0x43,0x68,0x14,0x9e,0x09,0x93,0x05,0x9b,0x05,0x00,0x07,0x91,0x06,0x92, 0x01,0x24,0xb1,0x46,0x00,0x2b,0x68,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0xfb,0xd0, 0x2b,0x68,0x00,0x2b,0x61,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0x5e,0xd9,0x6b,0x68, 0x07,0x9a,0xd3,0x1a,0x0f,0x2b,0xef,0xdd,0x4a,0x46,0x00,0x21,0x03,0x93,0xd1,0x60, 0x00,0x2b,0x42,0xd0,0x40,0x22,0x4a,0x44,0x90,0x46,0x44,0x22,0x4a,0x44,0x00,0x92, 0x48,0x22,0x4a,0x44,0x93,0x46,0x4c,0x22,0x27,0x4f,0x4a,0x44,0xbc,0x46,0x4e,0x46, 0x92,0x46,0x06,0x99,0x4b,0x46,0x61,0x44,0x08,0x00,0x00,0x99,0x18,0x36,0x6a,0x68, 0x08,0x95,0x8c,0x46,0x55,0x46,0xda,0x46,0xb3,0x46,0x10,0x33,0x04,0x92,0x11,0x68, 0x5e,0x46,0x00,0x91,0x51,0x68,0x97,0x68,0x01,0x91,0xd1,0x68,0x02,0x91,0x3f,0x21, 0x19,0x60,0x81,0x03,0x09,0x0c,0x31,0x60,0x46,0x46,0x00,0x99,0x31,0x60,0x66,0x46, 0x01,0x99,0x31,0x60,0x56,0x46,0x02,0x99,0x37,0x60,0x29,0x60,0xcc,0x26,0x49,0x46, 0x0e,0x60,0x19,0x68,0x0c,0x42,0xfc,0xd0,0x04,0x99,0x03,0x9e,0x10,0x32,0x10,0x30, 0x51,0x1a,0x8e,0x42,0xdb,0xd8,0x08,0x9d,0x6a,0x60,0x03,0x9a,0x06,0x9b,0x94,0x46, 0x63,0x44,0x06,0x93,0x07,0x9a,0x6b,0x68,0x9a,0x42,0x01,0xd8,0x09,0x9b,0x6b,0x60, 0x05,0x9b,0x03,0x9a,0x9b,0x1a,0x05,0x93,0x96,0xd1,0x00,0xbe,0x2b,0x68,0x6a,0x68, 0x9b,0x1a,0x9f,0xd5,0x90,0xe7,0xc0,0x46,0x00,0x00,0xfc,0xef, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/cc26xx/cc26x0/cc26x0r2f.lds ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ /* Entry Point */ ENTRY( entry ) /* System memory map */ MEMORY { /* Application is stored in and executes from SRAM */ PROGRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0x1BD8 BUFFERS (RWX) : ORIGIN = 0x20001BD8, LENGTH = 0x3028 } /* Section allocation in memory */ SECTIONS { .text : { _text = .; *(.entry*) *(.text*) _etext = .; } > PROGRAM .data : { _data = .; *(.rodata*) *(.data*) _edata = .; } .bss : { __bss_start__ = .; _bss = .; *(.bss*) *(COMMON) _ebss = .; __bss_end__ = .; } > PROGRAM .stack : { _stack = .; *(.stack*) _estack = .; } > PROGRAM .buffers : { _buffers = .; *(.buffers.g_cfg) *(.buffers.g_buf1) *(.buffers.g_buf2) *(.buffers*) _ebuffers = .; } > BUFFERS } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/cc26xx/cc26x0_algo.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x08,0xb5,0x00,0xbf,0x00,0xbf,0x00,0xbf,0x00,0xbf,0xdf,0xf8,0x1c,0xd0,0x07,0x48, 0x07,0x49,0x4f,0xf0,0x00,0x02,0x88,0x42,0xb8,0xbf,0x40,0xf8,0x04,0x2b,0xfa,0xdb, 0x00,0xf0,0xa8,0xf9,0xfe,0xe7,0x00,0x00,0xf0,0x0e,0x00,0x20,0x54,0x13,0x00,0x20, 0x98,0x13,0x00,0x20,0x08,0xb5,0x07,0x4b,0x07,0x48,0x03,0x33,0x1b,0x1a,0x06,0x2b, 0x04,0xd9,0x06,0x4b,0x00,0x2b,0x01,0xd0,0x00,0xf0,0x5c,0xf8,0x08,0xbc,0x01,0xbc, 0x00,0x47,0xc0,0x46,0x50,0x13,0x00,0x20,0x50,0x13,0x00,0x20,0x00,0x00,0x00,0x00, 0x08,0x48,0x09,0x49,0x09,0x1a,0x89,0x10,0x08,0xb5,0xcb,0x0f,0x59,0x18,0x49,0x10, 0x04,0xd0,0x06,0x4b,0x00,0x2b,0x01,0xd0,0x00,0xf0,0x44,0xf8,0x08,0xbc,0x01,0xbc, 0x00,0x47,0xc0,0x46,0x50,0x13,0x00,0x20,0x50,0x13,0x00,0x20,0x00,0x00,0x00,0x00, 0x10,0xb5,0x08,0x4c,0x23,0x78,0x00,0x2b,0x09,0xd1,0xff,0xf7,0xcb,0xff,0x06,0x4b, 0x00,0x2b,0x02,0xd0,0x05,0x48,0xaf,0xf3,0x00,0x80,0x01,0x23,0x23,0x70,0x10,0xbc, 0x01,0xbc,0x00,0x47,0x54,0x13,0x00,0x20,0x00,0x00,0x00,0x00,0xe0,0x0e,0x00,0x20, 0x08,0xb5,0x0b,0x4b,0x00,0x2b,0x03,0xd0,0x0a,0x48,0x0b,0x49,0xaf,0xf3,0x00,0x80, 0x0a,0x48,0x03,0x68,0x00,0x2b,0x04,0xd1,0xff,0xf7,0xc2,0xff,0x08,0xbc,0x01,0xbc, 0x00,0x47,0x07,0x4b,0x00,0x2b,0xf7,0xd0,0x00,0xf0,0x0c,0xf8,0xf4,0xe7,0xc0,0x46, 0x00,0x00,0x00,0x00,0xe0,0x0e,0x00,0x20,0x58,0x13,0x00,0x20,0x4c,0x13,0x00,0x20, 0x00,0x00,0x00,0x00,0x18,0x47,0xc0,0x46,0xd4,0x30,0x9f,0xe5,0x00,0x00,0x53,0xe3, 0xc8,0x30,0x9f,0x05,0x03,0xd0,0xa0,0xe1,0x00,0x20,0x0f,0xe1,0x0f,0x00,0x12,0xe3, 0x15,0x00,0x00,0x0a,0xd1,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1,0x01,0xaa,0x4d,0xe2, 0x0a,0x30,0xa0,0xe1,0xd7,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1,0x01,0x3a,0x43,0xe2, 0xdb,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1,0x01,0x3a,0x43,0xe2,0xd2,0xf0,0x21,0xe3, 0x03,0xd0,0xa0,0xe1,0x02,0x3a,0x43,0xe2,0xd3,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1, 0x02,0x39,0x43,0xe2,0xff,0x30,0xc3,0xe3,0xff,0x3c,0xc3,0xe3,0x04,0x30,0x03,0xe5, 0x00,0x20,0x53,0xe9,0xc0,0x20,0x82,0xe3,0x02,0xf0,0x21,0xe1,0x01,0xa8,0x43,0xe2, 0x00,0x10,0xb0,0xe3,0x01,0xb0,0xa0,0xe1,0x01,0x70,0xa0,0xe1,0x5c,0x00,0x9f,0xe5, 0x5c,0x20,0x9f,0xe5,0x00,0x20,0x52,0xe0,0x01,0x30,0x8f,0xe2,0x13,0xff,0x2f,0xe1, 0x00,0xf0,0x42,0xfd,0x10,0x4b,0x00,0x2b,0x01,0xd0,0xfe,0x46,0x9f,0x46,0x0f,0x4b, 0x00,0x2b,0x01,0xd0,0xfe,0x46,0x9f,0x46,0x00,0x20,0x00,0x21,0x04,0x00,0x0d,0x00, 0x0d,0x48,0x00,0xf0,0x89,0xfc,0x00,0xf0,0xc3,0xfc,0x20,0x00,0x29,0x00,0x00,0xf0, 0xd1,0xf8,0x00,0xf0,0x8b,0xfc,0x7b,0x46,0x18,0x47,0x00,0x00,0x11,0x00,0x00,0xef, 0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x54,0x13,0x00,0x20,0x98,0x13,0x00,0x20,0x15,0x0b,0x00,0x20,0x70,0xb5,0x04,0x46, 0x0e,0x46,0x15,0x46,0x00,0x21,0x28,0x22,0x00,0xf0,0x0e,0xfd,0x26,0x61,0x65,0x62, 0x00,0x21,0x20,0x22,0x02,0x48,0x00,0xf0,0x07,0xfd,0x00,0x20,0x70,0xbd,0x00,0xbf, 0x70,0x13,0x00,0x20,0x10,0xb5,0x01,0x20,0x00,0xf0,0xac,0xf9,0x04,0x46,0x28,0xb9, 0x01,0x21,0x20,0x22,0x03,0x48,0x00,0xf0,0xf7,0xfc,0x01,0xe0,0x40,0xf2,0x01,0x14, 0x20,0x46,0x10,0xbd,0x70,0x13,0x00,0x20,0x01,0x39,0xf8,0xb5,0x04,0x0b,0x08,0x44, 0x05,0x0b,0x26,0x03,0xac,0x42,0x14,0xd8,0x0b,0x4f,0xe3,0x5d,0x6b,0xb9,0x30,0x46, 0x00,0xf0,0xfc,0xf8,0x38,0xb1,0x00,0x04,0x00,0xf4,0x7f,0x00,0x40,0xea,0x04,0x60, 0x40,0xf4,0x81,0x70,0xf8,0xbd,0x01,0x23,0xe3,0x55,0x01,0x34,0x06,0xf5,0x80,0x56, 0xe8,0xe7,0x00,0x20,0xf8,0xbd,0x00,0xbf,0x70,0x13,0x00,0x20,0x2d,0xe9,0xf0,0x4f, 0x0d,0x46,0x53,0x1e,0x85,0xb0,0x0b,0x44,0x02,0x90,0x4f,0xea,0x11,0x38,0x1b,0x0b, 0x16,0x46,0x23,0x48,0x00,0x21,0x20,0x22,0x01,0x93,0x4f,0xea,0x08,0x37,0x00,0xf0, 0xbb,0xfc,0x4f,0xf0,0x00,0x09,0xc5,0xf3,0x0b,0x0c,0x01,0x9b,0x98,0x45,0x33,0xd8, 0x74,0x19,0x07,0xf5,0x80,0x5a,0x54,0x45,0x98,0xbf,0x34,0x46,0xdf,0xf8,0x64,0xb0, 0x88,0xbf,0xc4,0xf3,0x0b,0x04,0x39,0x46,0x4f,0xf4,0x80,0x52,0x58,0x46,0x88,0xbf, 0x34,0x1b,0xcd,0xf8,0x0c,0xc0,0x00,0xf0,0x5f,0xfc,0xdd,0xf8,0x0c,0xc0,0x02,0x9b, 0x0b,0xeb,0x0c,0x00,0x03,0xeb,0x09,0x01,0x22,0x46,0x00,0xf0,0x55,0xfc,0x38,0x46, 0x4f,0xf4,0x80,0x51,0x08,0xf1,0x01,0x08,0xff,0xf7,0x9e,0xff,0x68,0xb9,0x39,0x46, 0x58,0x46,0x4f,0xf4,0x80,0x52,0x25,0x44,0x00,0xf0,0xae,0xf8,0x36,0x1b,0xc5,0xf3, 0x0b,0x0c,0xa1,0x44,0x57,0x46,0xc8,0xe7,0x00,0x20,0x05,0xb0,0xbd,0xe8,0xf0,0x8f, 0x70,0x13,0x00,0x20,0x00,0x3c,0x00,0x20,0xb2,0xf5,0x80,0x5f,0xf8,0xb5,0x07,0x46, 0x0e,0x46,0x15,0x46,0x0b,0xd8,0x08,0x46,0x11,0x46,0xff,0xf7,0x7d,0xff,0x04,0x46, 0x40,0xb9,0x38,0x46,0x31,0x46,0x2a,0x46,0x00,0xf0,0x8e,0xf8,0x02,0xe0,0x4f,0xf4, 0x82,0x70,0xf8,0xbd,0x20,0x46,0xf8,0xbd,0x08,0xb5,0x00,0xf0,0x85,0xf8,0x00,0x20, 0x08,0xbd,0x00,0x00,0xf8,0xb5,0x31,0x48,0x31,0x49,0x32,0x4a,0x32,0x4c,0xff,0xf7, 0x3d,0xff,0x00,0x23,0x23,0x60,0x22,0x68,0x2c,0x4f,0x14,0x23,0x03,0xfb,0x02,0x73, 0x08,0x33,0x5b,0x68,0x00,0x2b,0xf7,0xd0,0x2c,0x4b,0x1a,0x68,0x11,0x07,0xfb,0xd4, 0x2b,0x4d,0x2c,0x4e,0x2a,0x68,0x32,0x60,0x42,0xf0,0x33,0x02,0x2a,0x60,0x1a,0x68, 0x12,0x07,0xfc,0xd4,0x21,0x68,0x14,0x22,0x02,0xfb,0x01,0x73,0x98,0x68,0x13,0x46, 0x01,0x38,0x04,0x28,0x26,0xd8,0xdf,0xe8,0x00,0xf0,0x03,0x06,0x0e,0x16,0x1e,0x00, 0xff,0xf7,0x28,0xff,0x20,0xe0,0x4b,0x43,0xfa,0x18,0x10,0x69,0xf9,0x58,0x52,0x68, 0xff,0xf7,0xc2,0xff,0x18,0xe0,0x4b,0x43,0xfa,0x18,0x10,0x69,0xf9,0x58,0x52,0x68, 0xff,0xf7,0xa2,0xff,0x10,0xe0,0x4b,0x43,0xfa,0x18,0x10,0x69,0xf9,0x58,0x52,0x68, 0xff,0xf7,0x44,0xff,0x08,0xe0,0x4b,0x43,0xfa,0x18,0xf8,0x58,0x51,0x68,0xff,0xf7, 0x1b,0xff,0x01,0xe0,0x40,0xf2,0x05,0x10,0x33,0x68,0x2b,0x60,0x0b,0x4b,0x1b,0x68, 0x1b,0x07,0xfb,0xd4,0x22,0x68,0x14,0x23,0x03,0xfb,0x02,0x77,0xfb,0x68,0xf8,0x60, 0x00,0xb1,0xfe,0xe7,0x82,0xf0,0x01,0x02,0x22,0x60,0xa4,0xe7,0xd8,0x1b,0x00,0x20, 0x00,0x1c,0x00,0x20,0x00,0x2c,0x00,0x20,0x90,0x13,0x00,0x20,0x00,0x40,0x03,0x40, 0x04,0x40,0x03,0x40,0x94,0x13,0x00,0x20,0xfe,0xe7,0x00,0x00,0x08,0xb5,0x04,0x4b, 0x1b,0x68,0x5b,0x69,0x98,0x47,0x03,0x4b,0x00,0x22,0x1a,0x60,0x08,0xbd,0x00,0xbf, 0xa8,0x01,0x00,0x10,0x84,0x04,0x60,0x42,0x08,0xb5,0x04,0x4b,0x1b,0x68,0x9b,0x69, 0x98,0x47,0x03,0x4b,0x00,0x22,0x1a,0x60,0x08,0xbd,0x00,0xbf,0xa8,0x01,0x00,0x10, 0x84,0x04,0x60,0x42,0x10,0xb5,0x33,0x4b,0x33,0x48,0x1b,0x68,0x33,0x4a,0x13,0xf0, 0x02,0x0f,0x03,0x68,0x43,0xf0,0x02,0x03,0x03,0x60,0x13,0x68,0x01,0x68,0x19,0xd0, 0x21,0xf4,0xe1,0x72,0xc3,0xf3,0xc1,0x04,0x22,0xf0,0x01,0x02,0x22,0x43,0xc3,0xf3, 0xc0,0x11,0x42,0xea,0x01,0x22,0xc3,0xf3,0x41,0x11,0x42,0xea,0x81,0x12,0x02,0x60, 0x02,0x68,0xd4,0x07,0x03,0xd5,0x26,0x4a,0x12,0x68,0x50,0x07,0xfb,0xd5,0x03,0xf0, 0x07,0x03,0x18,0xe0,0x21,0xf4,0xe1,0x72,0xc3,0xf3,0xc1,0x24,0x22,0xf0,0x01,0x02, 0xc3,0xf3,0xc0,0x31,0x22,0x43,0x42,0xea,0x01,0x22,0xc3,0xf3,0x41,0x31,0x42,0xea, 0x81,0x12,0x02,0x60,0x02,0x68,0xd1,0x07,0x03,0xd5,0x19,0x4a,0x12,0x68,0x52,0x07, 0xfb,0xd5,0xc3,0xf3,0x02,0x23,0x4a,0xf6,0xaa,0x22,0x16,0x49,0x16,0x48,0x0a,0x60, 0x02,0x68,0x1b,0x03,0xb3,0xf5,0xe0,0x4f,0x22,0xf4,0xe2,0x42,0x18,0xbf,0x43,0xf4, 0x80,0x73,0x13,0x43,0x03,0x60,0x45,0xf2,0xaa,0x53,0x0b,0x60,0x0f,0x4b,0x10,0x49, 0x01,0x22,0x1a,0x60,0x00,0x22,0x0a,0x60,0x1a,0x60,0x05,0x22,0xc3,0xf8,0x58,0x22, 0x4f,0xf0,0xff,0x32,0xc1,0xf8,0x8c,0x22,0xc1,0xf8,0x90,0x22,0x02,0x22,0xc3,0xf8, 0x58,0x22,0x10,0xbd,0x00,0x00,0x09,0x40,0x24,0x00,0x03,0x40,0x08,0x13,0x00,0x50, 0x1c,0x00,0x03,0x40,0x64,0x20,0x03,0x40,0xa8,0x20,0x03,0x40,0x30,0x20,0x03,0x40, 0x34,0x20,0x03,0x40,0x2d,0xe9,0xf8,0x4f,0xd4,0x4d,0x29,0x68,0x11,0xf0,0x01,0x01, 0x40,0xf0,0x95,0x81,0xdf,0xf8,0x90,0xe3,0x05,0x27,0xd1,0x4b,0xce,0xf8,0x00,0x70, 0x1b,0x68,0x4f,0xf4,0x40,0x72,0xc3,0xf3,0x03,0x23,0x01,0x33,0xb2,0xfb,0xf3,0xf3, 0xdf,0xf8,0x78,0xc3,0xdf,0xf8,0x78,0x83,0xdc,0xf8,0x00,0x20,0xd8,0xf8,0x00,0x40, 0x92,0xb2,0x5a,0x43,0xc2,0xf3,0x8f,0x16,0x22,0x0c,0x12,0x04,0x32,0x43,0xc8,0xf8, 0x00,0x20,0xc4,0x4a,0xc4,0x4c,0x12,0x68,0x26,0x68,0x5a,0x43,0xc3,0x4e,0x92,0x09, 0x22,0x60,0x32,0x68,0x54,0xf8,0x24,0x8c,0xc2,0xf3,0x07,0x42,0x5a,0x43,0x28,0xf0, 0xff,0x08,0xc2,0xf3,0x87,0x12,0xdf,0xf8,0x3c,0x93,0x42,0xea,0x08,0x02,0xdf,0xf8, 0x38,0x83,0x44,0xf8,0x24,0x2c,0xd9,0xf8,0x00,0xa0,0xd8,0xf8,0x00,0x20,0xca,0xf3, 0x07,0x4a,0x22,0xf0,0xff,0x02,0x4a,0xea,0x02,0x02,0xc8,0xf8,0x00,0x20,0xd9,0xf8, 0x00,0x20,0xdf,0xf8,0x18,0xa3,0x12,0x0e,0x5a,0x43,0xda,0xf8,0x00,0x80,0x92,0x00, 0x28,0xf4,0x7f,0x48,0x02,0xf4,0x7f,0x42,0x42,0xea,0x08,0x02,0xdf,0xf8,0x00,0x83, 0xca,0xf8,0x00,0x20,0xd8,0xf8,0x00,0x20,0xae,0xf5,0x09,0x7e,0x4f,0xea,0x12,0x6b, 0x0b,0xfb,0x03,0xfb,0xda,0xf8,0x04,0x20,0xcb,0xf3,0x8f,0x1b,0x12,0x0c,0x12,0x04, 0x4b,0xea,0x02,0x02,0xca,0xf8,0x04,0x20,0xd9,0xf8,0x00,0x20,0xc2,0xf3,0x07,0x22, 0x53,0x43,0x9f,0x4a,0x9b,0x00,0xd2,0xf8,0x00,0x90,0x03,0xf4,0x7f,0x43,0x29,0xf4, 0x7f,0x49,0x43,0xea,0x09,0x03,0xdf,0xf8,0xbc,0x92,0x13,0x60,0xd9,0xf8,0x00,0xa0, 0x52,0xf8,0x24,0x3c,0x4f,0xea,0x1a,0x6a,0x23,0xf4,0x7f,0x43,0x43,0xea,0x0a,0x23, 0x42,0xf8,0x24,0x3c,0xd9,0xf8,0x00,0xa0,0x52,0xf8,0x24,0x3c,0xca,0xf3,0x07,0x4a, 0x23,0xf0,0xff,0x03,0x4a,0xea,0x03,0x03,0x42,0xf8,0x24,0x3c,0xd9,0xf8,0x00,0xa0, 0x52,0xf8,0x1c,0x3c,0x0a,0xf4,0x7f,0x4a,0x23,0xf4,0x7f,0x43,0x4a,0xea,0x03,0x03, 0x42,0xf8,0x1c,0x3c,0xd9,0xf8,0x00,0x90,0x52,0xf8,0x1c,0x3c,0x5f,0xfa,0x89,0xf9, 0x23,0xf0,0xff,0x03,0x49,0xea,0x03,0x03,0xdf,0xf8,0x5c,0x92,0x42,0xf8,0x1c,0x3c, 0x32,0x68,0xd9,0xf8,0x00,0x30,0x02,0xf4,0x70,0x42,0x23,0xf4,0x70,0x43,0x13,0x43, 0xc9,0xf8,0x00,0x30,0xd8,0xf8,0x00,0x20,0xdf,0xf8,0x40,0x82,0x02,0xf4,0x70,0x42, 0xd8,0xf8,0x00,0x30,0x23,0xf4,0x70,0x43,0x13,0x43,0xc8,0xf8,0x00,0x30,0x32,0x68, 0x54,0xf8,0x24,0x3c,0x12,0x0e,0x23,0xf4,0x7f,0x43,0x43,0xea,0x02,0x23,0x44,0xf8, 0x24,0x3c,0x70,0x4b,0x1b,0x68,0x62,0x6a,0xc3,0xf3,0x0b,0x06,0x22,0xf4,0x7f,0x63, 0x23,0xf0,0x0f,0x03,0x33,0x43,0x6c,0x4e,0x63,0x62,0x32,0x68,0x63,0x6a,0x02,0xf4, 0x70,0x22,0x23,0xf4,0x70,0x23,0x13,0x43,0x63,0x62,0x68,0x4c,0x22,0x68,0xd8,0xf8, 0x58,0x30,0xc2,0xf3,0x83,0x42,0x23,0xf4,0x70,0x23,0x43,0xea,0x02,0x43,0xc8,0xf8, 0x58,0x30,0xdc,0xf8,0x00,0x30,0xd8,0xf8,0x58,0x20,0xc3,0xf3,0x0b,0x4c,0x22,0xf4, 0x7f,0x63,0x23,0xf0,0x0f,0x03,0x4c,0xea,0x03,0x03,0xc8,0xf8,0x58,0x30,0x23,0x68, 0xd8,0xf8,0x5c,0x20,0x4f,0xea,0xd3,0x5c,0x22,0xf0,0xff,0x73,0x23,0xf4,0x80,0x33, 0x43,0xea,0x0c,0x43,0xc8,0xf8,0x5c,0x30,0x33,0x68,0x55,0x4a,0x0f,0x33,0x03,0xf0, 0x0f,0x03,0x13,0x60,0x26,0x68,0x53,0x68,0xc6,0xf3,0x80,0x56,0x23,0xf4,0x00,0x03, 0x43,0xea,0xc6,0x53,0x53,0x60,0x53,0x68,0x4e,0x4e,0x43,0xf4,0x80,0x43,0x53,0x60, 0x02,0x23,0xce,0xf8,0x24,0x32,0x4a,0xf6,0xaa,0x23,0xdf,0xf8,0x74,0xc1,0xce,0xf8, 0x00,0x30,0xdc,0xf8,0x00,0x30,0x32,0x68,0x03,0xf0,0x0f,0x08,0x22,0xf4,0x7f,0x02, 0x42,0xea,0x08,0x42,0xc3,0xf3,0x03,0x23,0x42,0xea,0x03,0x53,0xdf,0xf8,0x54,0x81, 0x33,0x60,0xd8,0xf8,0x00,0x30,0x32,0x68,0xc3,0xf3,0x03,0x49,0x22,0xf0,0xff,0x02, 0x49,0xea,0x02,0x02,0xc3,0xf3,0x03,0x63,0x42,0xea,0x03,0x13,0x33,0x60,0xdc,0xf8, 0x00,0x60,0xdf,0xf8,0x34,0xc1,0x06,0xf4,0x70,0x22,0xdc,0xf8,0x00,0x30,0x23,0xf4, 0x7f,0x03,0x1a,0x43,0xc6,0xf3,0x03,0x63,0x42,0xea,0x03,0x53,0x32,0x4e,0xcc,0xf8, 0x00,0x30,0x32,0x68,0x5c,0xf8,0x08,0x3c,0xc2,0xf3,0x03,0x22,0x23,0xf0,0x0f,0x03, 0x13,0x43,0x4c,0xf8,0x08,0x3c,0xd8,0xf8,0x00,0x20,0xdc,0xf8,0x08,0x30,0x02,0xf4, 0xf8,0x52,0x23,0xf4,0xf8,0x53,0x13,0x43,0xcc,0xf8,0x08,0x30,0x32,0x68,0xdc,0xf8, 0x0c,0x30,0x12,0x0b,0x02,0xf4,0x70,0x42,0x23,0xf4,0x70,0x43,0x13,0x43,0xcc,0xf8, 0x0c,0x30,0x32,0x68,0x21,0x4e,0xc2,0xf3,0x04,0x42,0x33,0x68,0x23,0xf0,0x1f,0x03, 0x13,0x43,0x33,0x60,0x22,0x68,0x1e,0x4c,0xc2,0xf3,0x01,0x42,0x23,0x68,0x23,0xf4, 0x40,0x13,0x43,0xea,0x02,0x53,0x23,0x60,0x45,0xf2,0xaa,0x53,0x19,0x4a,0xce,0xf8, 0x00,0x30,0x17,0x60,0x2b,0x68,0x43,0xf0,0x01,0x03,0x2b,0x60,0x11,0x60,0x16,0x4b, 0x16,0x4c,0x1b,0x68,0x16,0x4a,0x13,0xf0,0x02,0x0f,0x23,0x68,0x15,0x4d,0x43,0xf0, 0x02,0x03,0x23,0x60,0x13,0x68,0x21,0x68,0x59,0xd0,0x3f,0xe0,0x40,0x00,0x03,0x40, 0x00,0x20,0x03,0x40,0x8c,0x11,0x00,0x50,0x44,0x22,0x03,0x40,0x74,0x11,0x00,0x50, 0x34,0x22,0x03,0x40,0x84,0x11,0x00,0x50,0x80,0x11,0x00,0x50,0xb0,0x12,0x00,0x50, 0x78,0x22,0x03,0x40,0x84,0x20,0x03,0x40,0x98,0x11,0x00,0x50,0x98,0x20,0x03,0x40, 0xa8,0x20,0x03,0x40,0x3c,0x00,0x03,0x40,0x00,0x00,0x09,0x40,0x24,0x00,0x03,0x40, 0x08,0x13,0x00,0x50,0x1c,0x00,0x03,0x40,0x88,0x22,0x03,0x40,0x88,0x11,0x00,0x50, 0x40,0x22,0x03,0x40,0x78,0x11,0x00,0x50,0x24,0x22,0x03,0x40,0x28,0x22,0x03,0x40, 0x7c,0x11,0x00,0x50,0x70,0x11,0x00,0x50,0x1c,0x22,0x03,0x40,0x14,0x22,0x03,0x40, 0x90,0x11,0x00,0x50,0x94,0x11,0x00,0x50,0x88,0x20,0x03,0x40,0x21,0xf4,0xe1,0x72, 0xc3,0xf3,0xc1,0x46,0x22,0xf0,0x01,0x02,0xc3,0xf3,0xc0,0x51,0x32,0x43,0x42,0xea, 0x01,0x22,0xc3,0xf3,0x41,0x51,0x42,0xea,0x81,0x12,0x22,0x60,0x22,0x68,0xd7,0x07, 0x02,0xd5,0x2a,0x68,0x56,0x07,0xfc,0xd5,0xc3,0xf3,0x02,0x43,0x16,0xe0,0xc3,0xf3, 0xc1,0x62,0xde,0x0f,0x42,0xea,0x06,0x26,0x21,0xf4,0xe1,0x72,0x22,0xf0,0x01,0x02, 0x32,0x43,0xc3,0xf3,0x41,0x71,0x42,0xea,0x81,0x12,0x22,0x60,0x22,0x68,0xd4,0x07, 0x02,0xd5,0x2a,0x68,0x51,0x07,0xfc,0xd5,0xc3,0xf3,0x02,0x63,0x4a,0xf6,0xaa,0x22, 0x3a,0x49,0x3b,0x4c,0x0a,0x60,0x22,0x68,0x1b,0x03,0xb3,0xf5,0xe0,0x4f,0x22,0xf4, 0xe2,0x42,0x18,0xbf,0x43,0xf4,0x80,0x73,0x13,0x43,0x23,0x60,0x45,0xf2,0xaa,0x53, 0x4f,0xf6,0xff,0x74,0x0b,0x60,0x33,0x4b,0x00,0x21,0x01,0x22,0x19,0x60,0x43,0xf8, 0x20,0x2c,0x31,0x4a,0x4f,0xf0,0x05,0x0e,0x14,0x60,0x30,0x4c,0x43,0xf8,0x20,0x1c, 0x02,0xf5,0xec,0x72,0x10,0x23,0xc4,0xf8,0x00,0xe0,0x13,0x60,0x2c,0x4b,0x15,0x26, 0x1e,0x60,0x02,0x26,0x26,0x60,0x2b,0x4e,0x37,0x68,0xc4,0xf8,0x00,0xe0,0xdf,0xf8, 0xb4,0xe0,0xce,0xf8,0x00,0x10,0xce,0xf8,0x04,0x10,0x18,0xb1,0x31,0x68,0x41,0xf4, 0x00,0x01,0x31,0x60,0x02,0x21,0x05,0x20,0x21,0x60,0x20,0x60,0x08,0x20,0x10,0x60, 0x15,0x22,0x1a,0x60,0x21,0x60,0x2b,0x68,0x9a,0x07,0xfc,0xd4,0x1e,0x4b,0x1b,0x68, 0x13,0xf0,0x10,0x0f,0x14,0xbf,0x04,0x25,0x00,0x25,0xff,0xf7,0x1b,0xfd,0x3b,0x02, 0x07,0xd4,0x05,0x23,0x23,0x60,0x33,0x68,0x23,0xf4,0x00,0x03,0x33,0x60,0x02,0x23, 0x23,0x60,0xbd,0xb9,0x15,0x4b,0x16,0x48,0x19,0x68,0x03,0xf5,0x10,0x53,0x04,0x33, 0x1a,0x68,0xc9,0xb2,0x02,0xf0,0x0f,0x02,0x51,0x43,0x1b,0x68,0x14,0x22,0x03,0xf0, 0x0f,0x03,0x9b,0x02,0xc3,0xeb,0x81,0x21,0x01,0xf6,0xd8,0x71,0xbd,0xe8,0xf8,0x4f, 0xff,0xf7,0xea,0xbc,0x28,0x46,0xbd,0xe8,0xf8,0x8f,0x00,0xbf,0x64,0x20,0x03,0x40, 0xa8,0x20,0x03,0x40,0x50,0x20,0x03,0x40,0x34,0x20,0x03,0x40,0x88,0x22,0x03,0x40, 0xb4,0x22,0x03,0x40,0x7c,0x22,0x03,0x40,0x54,0x20,0x03,0x40,0x2c,0x00,0x03,0x40, 0xf4,0x0e,0x00,0x20,0xc0,0x22,0x03,0x40,0x08,0xb5,0x01,0x1c,0x00,0x22,0x00,0x20, 0x00,0x23,0x00,0xf0,0xeb,0xf8,0x08,0xbc,0x02,0xbc,0x08,0x47,0x10,0xb5,0x00,0x21, 0x04,0x1c,0x00,0xf0,0x5d,0xf9,0x05,0x4b,0x18,0x68,0xc3,0x6b,0x00,0x2b,0x01,0xd0, 0x00,0xf0,0x06,0xf8,0x20,0x1c,0xff,0xf7,0xa7,0xfc,0xc0,0x46,0x0c,0x0f,0x00,0x20, 0x18,0x47,0xc0,0x46,0x38,0xb5,0x0a,0x4b,0x0a,0x4c,0xe4,0x1a,0xa4,0x10,0x0a,0xd0, 0x09,0x4a,0xa5,0x18,0xad,0x00,0xed,0x18,0x2b,0x68,0x01,0x3c,0x00,0xf0,0x0e,0xf8, 0x04,0x3d,0x00,0x2c,0xf8,0xd1,0x00,0xf0,0xcd,0xf9,0x38,0xbc,0x01,0xbc,0x00,0x47, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x3f,0x18,0x47,0xc0,0x46, 0x70,0xb5,0x10,0x4e,0x10,0x4d,0xad,0x1b,0xad,0x10,0x00,0x24,0x00,0x2d,0x06,0xd0, 0xa3,0x00,0xf3,0x58,0x01,0x34,0x00,0xf0,0x1d,0xf8,0xa5,0x42,0xf8,0xd1,0x00,0xf0, 0xab,0xf9,0x0a,0x4e,0x0a,0x4d,0xad,0x1b,0xad,0x10,0x00,0x24,0x00,0x2d,0x06,0xd0, 0xa3,0x00,0xf3,0x58,0x01,0x34,0x00,0xf0,0x0d,0xf8,0xa5,0x42,0xf8,0xd1,0x70,0xbc, 0x01,0xbc,0x00,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x18,0x47,0xc0,0x46,0x70,0xb5,0x0f,0x2a,0x34,0xd9,0x04,0x1c, 0x0c,0x43,0x0b,0x1c,0xa4,0x07,0x33,0xd1,0x15,0x1c,0x04,0x1c,0x10,0x3d,0x2d,0x09, 0x01,0x35,0x2d,0x01,0x49,0x19,0x1e,0x68,0x26,0x60,0x5e,0x68,0x66,0x60,0x9e,0x68, 0xa6,0x60,0xde,0x68,0x10,0x33,0xe6,0x60,0x10,0x34,0x99,0x42,0xf3,0xd1,0x0f,0x23, 0x45,0x19,0x13,0x40,0x03,0x2b,0x1d,0xd9,0x1c,0x1f,0x00,0x23,0xa4,0x08,0x01,0x34, 0xa4,0x00,0xce,0x58,0xee,0x50,0x04,0x33,0xa3,0x42,0xfa,0xd1,0xed,0x18,0xc9,0x18, 0x03,0x23,0x1a,0x40,0x05,0xd0,0x00,0x23,0xcc,0x5c,0xec,0x54,0x01,0x33,0x93,0x42, 0xfa,0xd1,0x70,0xbc,0x02,0xbc,0x08,0x47,0x05,0x1c,0x00,0x2a,0xf3,0xd1,0xf8,0xe7, 0x05,0x1c,0xf0,0xe7,0x1a,0x1c,0xf8,0xe7,0x70,0xb5,0x83,0x07,0x43,0xd0,0x54,0x1e, 0x00,0x2a,0x3d,0xd0,0x0d,0x06,0x2d,0x0e,0x03,0x1c,0x03,0x26,0x03,0xe0,0x62,0x1e, 0x00,0x2c,0x35,0xd0,0x14,0x1c,0x01,0x33,0x5a,0x1e,0x15,0x70,0x33,0x42,0xf6,0xd1, 0x03,0x2c,0x24,0xd9,0xff,0x25,0x0d,0x40,0x2a,0x02,0x15,0x43,0x2a,0x04,0x15,0x43, 0x0f,0x2c,0x11,0xd9,0x26,0x1c,0x10,0x3e,0x36,0x09,0x01,0x36,0x36,0x01,0x1a,0x1c, 0x9b,0x19,0x15,0x60,0x55,0x60,0x95,0x60,0xd5,0x60,0x10,0x32,0x93,0x42,0xf8,0xd1, 0x0f,0x22,0x14,0x40,0x03,0x2c,0x0a,0xd9,0x26,0x1f,0xb6,0x08,0x01,0x36,0xb6,0x00, 0x1a,0x1c,0x9b,0x19,0x20,0xc2,0x93,0x42,0xfc,0xd1,0x03,0x22,0x14,0x40,0x00,0x2c, 0x06,0xd0,0x09,0x06,0x1c,0x19,0x09,0x0e,0x19,0x70,0x01,0x33,0xa3,0x42,0xfb,0xd1, 0x70,0xbc,0x02,0xbc,0x08,0x47,0x14,0x1c,0x03,0x1c,0xc9,0xe7,0xf8,0xb5,0x44,0x46, 0x5f,0x46,0x56,0x46,0x4d,0x46,0x9b,0x46,0x30,0x4b,0xf0,0xb4,0x1c,0x68,0xa4,0x23, 0x5b,0x00,0x05,0x1c,0xe0,0x58,0x0e,0x1c,0x90,0x46,0x00,0x28,0x4d,0xd0,0x43,0x68, 0x1f,0x2b,0x0f,0xdc,0x5c,0x1c,0x00,0x2d,0x23,0xd1,0x02,0x33,0x9b,0x00,0x44,0x60, 0x1e,0x50,0x00,0x20,0x3c,0xbc,0x90,0x46,0x99,0x46,0xa2,0x46,0xab,0x46,0xf8,0xbc, 0x02,0xbc,0x08,0x47,0x22,0x4b,0x00,0x2b,0x3c,0xd0,0xc8,0x20,0x40,0x00,0xaf,0xf3, 0x00,0x80,0x00,0x28,0x36,0xd0,0xa4,0x22,0x00,0x23,0x52,0x00,0xa1,0x58,0x43,0x60, 0x01,0x60,0xa0,0x50,0x40,0x32,0x83,0x50,0x04,0x32,0x83,0x50,0x01,0x24,0x00,0x2d, 0xdb,0xd0,0x9a,0x00,0x91,0x46,0x81,0x44,0x42,0x46,0x88,0x21,0x4f,0x46,0x7a,0x50, 0xc4,0x22,0x52,0x00,0x90,0x46,0x80,0x44,0x42,0x46,0x87,0x39,0x99,0x40,0x12,0x68, 0x0a,0x43,0x94,0x46,0x8a,0x46,0x42,0x46,0x61,0x46,0x11,0x60,0x84,0x22,0x49,0x46, 0x5f,0x46,0x52,0x00,0x8f,0x50,0x02,0x2d,0xbf,0xd1,0x02,0x1c,0x55,0x46,0x8d,0x32, 0xff,0x32,0x11,0x68,0x0d,0x43,0x15,0x60,0xb7,0xe7,0x20,0x1c,0x4d,0x30,0xff,0x30, 0xe0,0x50,0xac,0xe7,0x01,0x20,0x40,0x42,0xb4,0xe7,0xc0,0x46,0x0c,0x0f,0x00,0x20, 0x00,0x00,0x00,0x00,0x08,0xb5,0x04,0x4b,0x00,0x2b,0x02,0xd0,0x03,0x48,0xff,0xf7, 0x9b,0xfe,0x08,0xbc,0x01,0xbc,0x00,0x47,0x00,0x00,0x00,0x00,0x15,0x0b,0x00,0x20, 0xf0,0xb5,0x56,0x46,0x5f,0x46,0x4d,0x46,0x44,0x46,0xf0,0xb4,0x0e,0x1c,0x3f,0x4b, 0x1b,0x68,0x87,0xb0,0x03,0x93,0x49,0x33,0xff,0x33,0x01,0x90,0x04,0x93,0xa4,0x22, 0x03,0x9b,0x52,0x00,0x9f,0x58,0x00,0x2f,0x4d,0xd0,0x04,0x9b,0x98,0x46,0x00,0x23, 0x9b,0x46,0xc4,0x23,0x5b,0x00,0x9c,0x46,0xbc,0x44,0x63,0x46,0x02,0x93,0xc6,0x23, 0x5b,0x00,0x9a,0x46,0x7c,0x68,0xa5,0x00,0x7d,0x19,0xba,0x44,0x01,0x3c,0x08,0xd5, 0x27,0xe0,0x6b,0x1d,0xff,0x33,0x1b,0x68,0xb3,0x42,0x04,0xd0,0x04,0x3d,0x01,0x3c, 0x1f,0xd3,0x00,0x2e,0xf5,0xd1,0x7b,0x68,0x01,0x3b,0x6a,0x68,0xa3,0x42,0x3e,0xd0, 0x5b,0x46,0x6b,0x60,0x00,0x2a,0xf1,0xd0,0x7b,0x68,0x99,0x46,0x01,0x23,0xa3,0x40, 0x02,0x99,0x09,0x68,0x05,0x91,0x19,0x42,0x26,0xd1,0x00,0xf0,0x43,0xf8,0x7b,0x68, 0x4b,0x45,0xc4,0xd1,0x43,0x46,0x1b,0x68,0xbb,0x42,0xc0,0xd1,0x04,0x3d,0x01,0x3c, 0xdf,0xd2,0x1b,0x4b,0x00,0x2b,0x0e,0xd0,0x7b,0x68,0x00,0x2b,0x27,0xd1,0x3b,0x68, 0x00,0x2b,0x28,0xd0,0x42,0x46,0x38,0x1c,0x13,0x60,0xaf,0xf3,0x00,0x80,0x43,0x46, 0x1f,0x68,0x00,0x2f,0xb5,0xd1,0x07,0xb0,0x3c,0xbc,0x90,0x46,0x99,0x46,0xa2,0x46, 0xab,0x46,0xf0,0xbc,0x01,0xbc,0x00,0x47,0x51,0x46,0x09,0x68,0x19,0x42,0x08,0xd1, 0x2b,0x1c,0x84,0x33,0x19,0x68,0x01,0x98,0x00,0xf0,0x14,0xf8,0xcf,0xe7,0x7c,0x60, 0xc0,0xe7,0x2b,0x1c,0x84,0x33,0x18,0x68,0x00,0xf0,0x0c,0xf8,0xc7,0xe7,0x3b,0x68, 0xb8,0x46,0x1f,0x1c,0xdd,0xe7,0x00,0x23,0xfa,0xe7,0xc0,0x46,0x0c,0x0f,0x00,0x20, 0x00,0x00,0x00,0x00,0x10,0x47,0xc0,0x46,0xf8,0xb5,0xc0,0x46,0xf8,0xbc,0x08,0xbc, 0x9e,0x46,0x70,0x47,0xf8,0xb5,0xc0,0x46,0xf8,0xbc,0x08,0xbc,0x9e,0x46,0x70,0x47, 0x00,0x00,0x00,0x00,0x24,0xf2,0xff,0x7f,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x28,0x15,0x00,0x20,0xff,0xff,0xff,0xc5,0xff,0xff,0xff,0xff,0xc5,0xff,0xff,0xff, 0xc5,0xc5,0xc5,0xff,0xc5,0xc5,0xc5,0xff,0x43,0x00,0x00,0x00,0x18,0x0f,0x00,0x20, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x12,0x00,0x20, 0x6c,0x12,0x00,0x20,0xd4,0x12,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x0f,0x00,0x20, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x33,0xcd,0xab,0x34,0x12,0x6d,0xe6, 0xec,0xde,0x05,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x18,0x0f,0x00,0x20,0xc1,0x00,0x00,0x20,0x91,0x00,0x00,0x20,0x00,0x00,0x00,0x00, 0x95,0x0d,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/cc26xx/cc26x2/cc26x2r1f.lds ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ /* Entry Point */ ENTRY( entry ) /* System memory map */ MEMORY { /* Application is stored in and executes from SRAM */ PROGRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0x1FD8 BUFFERS (RWX) : ORIGIN = 0x20001FD8, LENGTH = 0x6028 } /* Section allocation in memory */ SECTIONS { .text : { _text = .; *(.entry*) *(.text*) _etext = .; } > PROGRAM .data : { _data = .; *(.rodata*) *(.data*) _edata = .; } .bss : { __bss_start__ = .; _bss = .; *(.bss*) *(COMMON) _ebss = .; __bss_end__ = .; } > PROGRAM .stack : { _stack = .; *(.stack*) _estack = .; } > PROGRAM .buffers : { _buffers = .; *(.buffers.g_cfg) *(.buffers.g_buf1) *(.buffers.g_buf2) *(.buffers*) _ebuffers = .; } > BUFFERS } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/cc26xx/cc26x2_algo.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x08,0xb5,0x00,0xbf,0x00,0xbf,0x00,0xbf,0x00,0xbf,0xdf,0xf8,0x1c,0xd0,0x07,0x48, 0x07,0x49,0x4f,0xf0,0x00,0x02,0x88,0x42,0xb8,0xbf,0x40,0xf8,0x04,0x2b,0xfa,0xdb, 0x00,0xf0,0xa8,0xf9,0xfe,0xe7,0x00,0x00,0xf0,0x0e,0x00,0x20,0x54,0x13,0x00,0x20, 0xfc,0x13,0x00,0x20,0x08,0xb5,0x07,0x4b,0x07,0x48,0x03,0x33,0x1b,0x1a,0x06,0x2b, 0x04,0xd9,0x06,0x4b,0x00,0x2b,0x01,0xd0,0x00,0xf0,0x5c,0xf8,0x08,0xbc,0x01,0xbc, 0x00,0x47,0xc0,0x46,0x50,0x13,0x00,0x20,0x50,0x13,0x00,0x20,0x00,0x00,0x00,0x00, 0x08,0x48,0x09,0x49,0x09,0x1a,0x89,0x10,0x08,0xb5,0xcb,0x0f,0x59,0x18,0x49,0x10, 0x04,0xd0,0x06,0x4b,0x00,0x2b,0x01,0xd0,0x00,0xf0,0x44,0xf8,0x08,0xbc,0x01,0xbc, 0x00,0x47,0xc0,0x46,0x50,0x13,0x00,0x20,0x50,0x13,0x00,0x20,0x00,0x00,0x00,0x00, 0x10,0xb5,0x08,0x4c,0x23,0x78,0x00,0x2b,0x09,0xd1,0xff,0xf7,0xcb,0xff,0x06,0x4b, 0x00,0x2b,0x02,0xd0,0x05,0x48,0xaf,0xf3,0x00,0x80,0x01,0x23,0x23,0x70,0x10,0xbc, 0x01,0xbc,0x00,0x47,0x54,0x13,0x00,0x20,0x00,0x00,0x00,0x00,0xe0,0x0e,0x00,0x20, 0x08,0xb5,0x0b,0x4b,0x00,0x2b,0x03,0xd0,0x0a,0x48,0x0b,0x49,0xaf,0xf3,0x00,0x80, 0x0a,0x48,0x03,0x68,0x00,0x2b,0x04,0xd1,0xff,0xf7,0xc2,0xff,0x08,0xbc,0x01,0xbc, 0x00,0x47,0x07,0x4b,0x00,0x2b,0xf7,0xd0,0x00,0xf0,0x0c,0xf8,0xf4,0xe7,0xc0,0x46, 0x00,0x00,0x00,0x00,0xe0,0x0e,0x00,0x20,0x58,0x13,0x00,0x20,0x4c,0x13,0x00,0x20, 0x00,0x00,0x00,0x00,0x18,0x47,0xc0,0x46,0xd4,0x30,0x9f,0xe5,0x00,0x00,0x53,0xe3, 0xc8,0x30,0x9f,0x05,0x03,0xd0,0xa0,0xe1,0x00,0x20,0x0f,0xe1,0x0f,0x00,0x12,0xe3, 0x15,0x00,0x00,0x0a,0xd1,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1,0x01,0xaa,0x4d,0xe2, 0x0a,0x30,0xa0,0xe1,0xd7,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1,0x01,0x3a,0x43,0xe2, 0xdb,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1,0x01,0x3a,0x43,0xe2,0xd2,0xf0,0x21,0xe3, 0x03,0xd0,0xa0,0xe1,0x02,0x3a,0x43,0xe2,0xd3,0xf0,0x21,0xe3,0x03,0xd0,0xa0,0xe1, 0x02,0x39,0x43,0xe2,0xff,0x30,0xc3,0xe3,0xff,0x3c,0xc3,0xe3,0x04,0x30,0x03,0xe5, 0x00,0x20,0x53,0xe9,0xc0,0x20,0x82,0xe3,0x02,0xf0,0x21,0xe1,0x01,0xa8,0x43,0xe2, 0x00,0x10,0xb0,0xe3,0x01,0xb0,0xa0,0xe1,0x01,0x70,0xa0,0xe1,0x5c,0x00,0x9f,0xe5, 0x5c,0x20,0x9f,0xe5,0x00,0x20,0x52,0xe0,0x01,0x30,0x8f,0xe2,0x13,0xff,0x2f,0xe1, 0x00,0xf0,0x42,0xfd,0x10,0x4b,0x00,0x2b,0x01,0xd0,0xfe,0x46,0x9f,0x46,0x0f,0x4b, 0x00,0x2b,0x01,0xd0,0xfe,0x46,0x9f,0x46,0x00,0x20,0x00,0x21,0x04,0x00,0x0d,0x00, 0x0d,0x48,0x00,0xf0,0x89,0xfc,0x00,0xf0,0xc3,0xfc,0x20,0x00,0x29,0x00,0x00,0xf0, 0xd1,0xf8,0x00,0xf0,0x8b,0xfc,0x7b,0x46,0x18,0x47,0x00,0x00,0x11,0x00,0x00,0xef, 0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x54,0x13,0x00,0x20,0xfc,0x13,0x00,0x20,0x15,0x0b,0x00,0x20,0x70,0xb5,0x04,0x46, 0x0e,0x46,0x15,0x46,0x00,0x21,0x28,0x22,0x00,0xf0,0x0e,0xfd,0x26,0x61,0x65,0x62, 0x00,0x21,0x84,0x22,0x02,0x48,0x00,0xf0,0x07,0xfd,0x00,0x20,0x70,0xbd,0x00,0xbf, 0x70,0x13,0x00,0x20,0x10,0xb5,0x01,0x20,0x00,0xf0,0xac,0xf9,0x04,0x46,0x28,0xb9, 0x01,0x21,0x84,0x22,0x03,0x48,0x00,0xf0,0xf7,0xfc,0x01,0xe0,0x40,0xf2,0x01,0x14, 0x20,0x46,0x10,0xbd,0x70,0x13,0x00,0x20,0x01,0x39,0xf8,0xb5,0x44,0x0b,0x08,0x44, 0x45,0x0b,0x66,0x03,0xac,0x42,0x14,0xd8,0x0b,0x4f,0xe3,0x5d,0x6b,0xb9,0x30,0x46, 0x00,0xf0,0xfc,0xf8,0x38,0xb1,0x00,0x04,0x00,0xf4,0x7f,0x00,0x40,0xea,0x04,0x60, 0x40,0xf4,0x81,0x70,0xf8,0xbd,0x01,0x23,0xe3,0x55,0x01,0x34,0x06,0xf5,0x00,0x56, 0xe8,0xe7,0x00,0x20,0xf8,0xbd,0x00,0xbf,0x70,0x13,0x00,0x20,0x2d,0xe9,0xf0,0x4f, 0x53,0x1e,0x85,0xb0,0x0b,0x44,0x02,0x90,0x0d,0x46,0x4f,0xea,0x51,0x38,0x5b,0x0b, 0x16,0x46,0x23,0x48,0x01,0x93,0x00,0x21,0x84,0x22,0x00,0xf0,0xbd,0xfc,0x4f,0xea, 0x48,0x37,0xc5,0xf3,0x0c,0x0c,0x4f,0xf0,0x00,0x09,0x01,0x9b,0x98,0x45,0x32,0xd8, 0x74,0x19,0xdf,0xf8,0x70,0xb0,0xcd,0xf8,0x0c,0xc0,0x07,0xf5,0x00,0x5a,0x54,0x45, 0x88,0xbf,0xc4,0xf3,0x0c,0x04,0x39,0x46,0x4f,0xf4,0x00,0x52,0x58,0x46,0x8c,0xbf, 0x34,0x1b,0x34,0x46,0x00,0xf0,0x60,0xfc,0xdd,0xf8,0x0c,0xc0,0x02,0x9b,0x0b,0xeb, 0x0c,0x00,0x03,0xeb,0x09,0x01,0x22,0x46,0x00,0xf0,0x56,0xfc,0x38,0x46,0x4f,0xf4, 0x00,0x51,0x08,0xf1,0x01,0x08,0xff,0xf7,0x9f,0xff,0x68,0xb9,0x39,0x46,0x58,0x46, 0x4f,0xf4,0x00,0x52,0x25,0x44,0x00,0xf0,0xaf,0xf8,0x36,0x1b,0xc5,0xf3,0x0c,0x0c, 0xa1,0x44,0x57,0x46,0xc9,0xe7,0x00,0x20,0x05,0xb0,0xbd,0xe8,0xf0,0x8f,0x00,0xbf, 0x70,0x13,0x00,0x20,0x00,0x60,0x00,0x20,0xb2,0xf5,0x00,0x5f,0xf8,0xb5,0x07,0x46, 0x0e,0x46,0x15,0x46,0x0b,0xd8,0x08,0x46,0x11,0x46,0xff,0xf7,0x7d,0xff,0x04,0x46, 0x40,0xb9,0x38,0x46,0x31,0x46,0x2a,0x46,0x00,0xf0,0x8e,0xf8,0x02,0xe0,0x4f,0xf4, 0x82,0x70,0xf8,0xbd,0x20,0x46,0xf8,0xbd,0x08,0xb5,0x00,0xf0,0x85,0xf8,0x00,0x20, 0x08,0xbd,0x00,0x00,0xf8,0xb5,0x31,0x48,0x31,0x49,0x32,0x4a,0x32,0x4c,0xff,0xf7, 0x3d,0xff,0x00,0x23,0x23,0x60,0x22,0x68,0x2c,0x4f,0x14,0x23,0x03,0xfb,0x02,0x73, 0x08,0x33,0x5b,0x68,0x00,0x2b,0xf7,0xd0,0x2c,0x4b,0x1a,0x68,0x11,0x07,0xfb,0xd4, 0x2b,0x4d,0x2c,0x4e,0x2a,0x68,0x32,0x60,0x42,0xf0,0x33,0x02,0x2a,0x60,0x1a,0x68, 0x12,0x07,0xfc,0xd4,0x21,0x68,0x14,0x22,0x02,0xfb,0x01,0x73,0x98,0x68,0x01,0x38, 0x13,0x46,0x04,0x28,0x26,0xd8,0xdf,0xe8,0x00,0xf0,0x03,0x06,0x0e,0x16,0x1e,0x00, 0xff,0xf7,0x28,0xff,0x20,0xe0,0x4b,0x43,0xfa,0x18,0x10,0x69,0xf9,0x58,0x52,0x68, 0xff,0xf7,0xc2,0xff,0x18,0xe0,0x4b,0x43,0xfa,0x18,0x10,0x69,0xf9,0x58,0x52,0x68, 0xff,0xf7,0xa2,0xff,0x10,0xe0,0x4b,0x43,0xfa,0x18,0x10,0x69,0xf9,0x58,0x52,0x68, 0xff,0xf7,0x44,0xff,0x08,0xe0,0x4b,0x43,0xfa,0x18,0xf8,0x58,0x51,0x68,0xff,0xf7, 0x1b,0xff,0x01,0xe0,0x40,0xf2,0x05,0x10,0x33,0x68,0x2b,0x60,0x0b,0x4b,0x1b,0x68, 0x1b,0x07,0xfb,0xd4,0x22,0x68,0x14,0x23,0x03,0xfb,0x02,0x77,0xfb,0x68,0xf8,0x60, 0x00,0xb1,0xfe,0xe7,0x82,0xf0,0x01,0x02,0x22,0x60,0xa4,0xe7,0xd8,0x1f,0x00,0x20, 0x00,0x20,0x00,0x20,0x00,0x40,0x00,0x20,0xf4,0x13,0x00,0x20,0x00,0x40,0x03,0x40, 0x04,0x40,0x03,0x40,0xf8,0x13,0x00,0x20,0xfe,0xe7,0x00,0x00,0x08,0xb5,0x04,0x4b, 0x1b,0x68,0x5b,0x69,0x98,0x47,0x03,0x4b,0x00,0x22,0x1a,0x60,0x08,0xbd,0x00,0xbf, 0xa8,0x01,0x00,0x10,0x84,0x04,0x60,0x42,0x08,0xb5,0x04,0x4b,0x1b,0x68,0x9b,0x69, 0x98,0x47,0x03,0x4b,0x00,0x22,0x1a,0x60,0x08,0xbd,0x00,0xbf,0xa8,0x01,0x00,0x10, 0x84,0x04,0x60,0x42,0x10,0xb5,0x33,0x4b,0x33,0x48,0x1b,0x68,0x33,0x4a,0x13,0xf0, 0x02,0x0f,0x03,0x68,0x43,0xf0,0x02,0x03,0x03,0x60,0x13,0x68,0x01,0x68,0x19,0xd0, 0x21,0xf4,0xe1,0x72,0xc3,0xf3,0xc1,0x04,0x22,0xf0,0x01,0x02,0x22,0x43,0xc3,0xf3, 0xc0,0x11,0x42,0xea,0x01,0x22,0xc3,0xf3,0x41,0x11,0x42,0xea,0x81,0x12,0x02,0x60, 0x02,0x68,0xd4,0x07,0x03,0xd5,0x26,0x4a,0x12,0x68,0x50,0x07,0xfb,0xd5,0x03,0xf0, 0x07,0x03,0x18,0xe0,0x21,0xf4,0xe1,0x72,0xc3,0xf3,0xc1,0x24,0x22,0xf0,0x01,0x02, 0xc3,0xf3,0xc0,0x31,0x22,0x43,0x42,0xea,0x01,0x22,0xc3,0xf3,0x41,0x31,0x42,0xea, 0x81,0x12,0x02,0x60,0x02,0x68,0xd1,0x07,0x03,0xd5,0x19,0x4a,0x12,0x68,0x52,0x07, 0xfb,0xd5,0xc3,0xf3,0x02,0x23,0x17,0x49,0x17,0x48,0x4a,0xf6,0xaa,0x22,0x0a,0x60, 0x02,0x68,0x1b,0x03,0xb3,0xf5,0xe0,0x4f,0x22,0xf4,0xe2,0x42,0x18,0xbf,0x43,0xf4, 0x80,0x73,0x13,0x43,0x03,0x60,0x45,0xf2,0xaa,0x53,0x0b,0x60,0x0f,0x4b,0x10,0x49, 0x01,0x22,0x1a,0x60,0x00,0x22,0x0a,0x60,0x1a,0x60,0x05,0x22,0xc3,0xf8,0x58,0x22, 0x4f,0xf0,0xff,0x32,0xc1,0xf8,0x8c,0x22,0xc1,0xf8,0x90,0x22,0x02,0x22,0xc3,0xf8, 0x58,0x22,0x10,0xbd,0x10,0x00,0x09,0x40,0x24,0x00,0x03,0x40,0x08,0x13,0x00,0x50, 0x1c,0x00,0x03,0x40,0x64,0x20,0x03,0x40,0xa8,0x20,0x03,0x40,0x30,0x20,0x03,0x40, 0x34,0x20,0x03,0x40,0x2d,0xe9,0xf8,0x4f,0xd4,0x4d,0x29,0x68,0x11,0xf0,0x01,0x01, 0x40,0xf0,0x95,0x81,0xdf,0xf8,0x90,0xe3,0xd1,0x4b,0xdf,0xf8,0x90,0xc3,0xdf,0xf8, 0x90,0x83,0xdf,0xf8,0x90,0x93,0x05,0x27,0xce,0xf8,0x00,0x70,0x1b,0x68,0xc3,0xf3, 0x03,0x23,0x4f,0xf4,0x40,0x72,0x01,0x33,0xb2,0xfb,0xf3,0xf3,0xdc,0xf8,0x00,0x20, 0xd8,0xf8,0x00,0x40,0x92,0xb2,0x5a,0x43,0xc2,0xf3,0x8f,0x16,0x22,0x0c,0x12,0x04, 0x32,0x43,0xc8,0xf8,0x00,0x20,0xc3,0x4a,0xc3,0x4c,0x12,0x68,0x26,0x68,0xc3,0x4e, 0x5a,0x43,0x92,0x09,0x22,0x60,0x32,0x68,0x54,0xf8,0x24,0x8c,0xc2,0xf3,0x07,0x42, 0x5a,0x43,0x28,0xf0,0xff,0x08,0xc2,0xf3,0x87,0x12,0x42,0xea,0x08,0x02,0xdf,0xf8, 0x38,0x83,0x44,0xf8,0x24,0x2c,0xd9,0xf8,0x00,0xa0,0xd8,0xf8,0x00,0x20,0xca,0xf3, 0x07,0x4a,0x22,0xf0,0xff,0x02,0x4a,0xea,0x02,0x02,0xc8,0xf8,0x00,0x20,0xd9,0xf8, 0x00,0x20,0xdf,0xf8,0x18,0xa3,0x12,0x0e,0xda,0xf8,0x00,0x80,0x5a,0x43,0x92,0x00, 0x28,0xf4,0x7f,0x48,0x02,0xf4,0x7f,0x42,0x42,0xea,0x08,0x02,0xdf,0xf8,0x00,0x83, 0xca,0xf8,0x00,0x20,0xd8,0xf8,0x00,0x20,0x4f,0xea,0x12,0x6b,0xda,0xf8,0x04,0x20, 0x0b,0xfb,0x03,0xfb,0x12,0x0c,0xcb,0xf3,0x8f,0x1b,0x12,0x04,0x4b,0xea,0x02,0x02, 0xca,0xf8,0x04,0x20,0xd9,0xf8,0x00,0x20,0xc2,0xf3,0x07,0x22,0x53,0x43,0xa0,0x4a, 0xd2,0xf8,0x00,0x90,0x9b,0x00,0x29,0xf4,0x7f,0x49,0x03,0xf4,0x7f,0x43,0x43,0xea, 0x09,0x03,0xdf,0xf8,0xc0,0x92,0x13,0x60,0xd9,0xf8,0x00,0xa0,0x52,0xf8,0x24,0x3c, 0x4f,0xea,0x1a,0x6a,0x23,0xf4,0x7f,0x43,0x43,0xea,0x0a,0x23,0x42,0xf8,0x24,0x3c, 0xd9,0xf8,0x00,0xa0,0x52,0xf8,0x24,0x3c,0xca,0xf3,0x07,0x4a,0x23,0xf0,0xff,0x03, 0x4a,0xea,0x03,0x03,0x42,0xf8,0x24,0x3c,0xd9,0xf8,0x00,0xa0,0x52,0xf8,0x1c,0x3c, 0x0a,0xf4,0x7f,0x4a,0x23,0xf4,0x7f,0x43,0x4a,0xea,0x03,0x03,0x42,0xf8,0x1c,0x3c, 0xd9,0xf8,0x00,0x90,0x52,0xf8,0x1c,0x3c,0x5f,0xfa,0x89,0xf9,0x23,0xf0,0xff,0x03, 0x49,0xea,0x03,0x03,0xdf,0xf8,0x60,0x92,0x42,0xf8,0x1c,0x3c,0x32,0x68,0xd9,0xf8, 0x00,0x30,0x02,0xf4,0x70,0x42,0x23,0xf4,0x70,0x43,0x13,0x43,0xc9,0xf8,0x00,0x30, 0xd8,0xf8,0x00,0x20,0xdf,0xf8,0x44,0x82,0xd8,0xf8,0x00,0x30,0x02,0xf4,0x70,0x42, 0x23,0xf4,0x70,0x43,0x13,0x43,0xc8,0xf8,0x00,0x30,0x32,0x68,0x54,0xf8,0x24,0x3c, 0x12,0x0e,0x23,0xf4,0x7f,0x43,0x43,0xea,0x02,0x23,0x44,0xf8,0x24,0x3c,0x71,0x4b, 0x1b,0x68,0x62,0x6a,0xc3,0xf3,0x0b,0x06,0x22,0xf4,0x7f,0x63,0x23,0xf0,0x0f,0x03, 0x33,0x43,0x6d,0x4e,0x63,0x62,0x32,0x68,0x63,0x6a,0x02,0xf4,0x70,0x22,0x23,0xf4, 0x70,0x23,0x13,0x43,0x63,0x62,0x69,0x4c,0x22,0x68,0xd8,0xf8,0x58,0x30,0xc2,0xf3, 0x83,0x42,0x23,0xf4,0x70,0x23,0x43,0xea,0x02,0x43,0xc8,0xf8,0x58,0x30,0xdc,0xf8, 0x00,0x30,0xd8,0xf8,0x58,0x20,0xc3,0xf3,0x0b,0x4c,0x22,0xf4,0x7f,0x63,0x23,0xf0, 0x0f,0x03,0x4c,0xea,0x03,0x03,0xc8,0xf8,0x58,0x30,0x23,0x68,0xd8,0xf8,0x5c,0x20, 0x4f,0xea,0xd3,0x5c,0x22,0xf0,0xff,0x73,0x23,0xf4,0x80,0x33,0x43,0xea,0x0c,0x43, 0xc8,0xf8,0x5c,0x30,0x33,0x68,0x56,0x4a,0xdf,0xf8,0xa4,0xc1,0x0f,0x33,0x03,0xf0, 0x0f,0x03,0x13,0x60,0x26,0x68,0x53,0x68,0xc6,0xf3,0x80,0x56,0x23,0xf4,0x00,0x03, 0x43,0xea,0xc6,0x53,0x53,0x60,0x53,0x68,0x4e,0x4e,0x43,0xf4,0x80,0x43,0x53,0x60, 0x02,0x23,0xce,0xf8,0x00,0x30,0xae,0xf5,0x09,0x7e,0x4a,0xf6,0xaa,0x23,0xce,0xf8, 0x00,0x30,0xdc,0xf8,0x00,0x30,0x32,0x68,0x03,0xf0,0x0f,0x08,0x22,0xf4,0x7f,0x02, 0x42,0xea,0x08,0x42,0xc3,0xf3,0x03,0x23,0x42,0xea,0x03,0x53,0xdf,0xf8,0x54,0x81, 0x33,0x60,0xd8,0xf8,0x00,0x30,0x32,0x68,0xc3,0xf3,0x03,0x49,0x22,0xf0,0xff,0x02, 0x49,0xea,0x02,0x02,0xc3,0xf3,0x03,0x63,0x42,0xea,0x03,0x13,0x33,0x60,0xdc,0xf8, 0x00,0x60,0xdf,0xf8,0x34,0xc1,0xdc,0xf8,0x00,0x30,0x06,0xf4,0x70,0x22,0x23,0xf4, 0x7f,0x03,0x1a,0x43,0xc6,0xf3,0x03,0x63,0x42,0xea,0x03,0x53,0x32,0x4e,0xcc,0xf8, 0x00,0x30,0x32,0x68,0x5c,0xf8,0x08,0x3c,0xc2,0xf3,0x03,0x22,0x23,0xf0,0x0f,0x03, 0x13,0x43,0x4c,0xf8,0x08,0x3c,0xd8,0xf8,0x00,0x20,0xdc,0xf8,0x08,0x30,0x02,0xf4, 0xf8,0x52,0x23,0xf4,0xf8,0x53,0x13,0x43,0xcc,0xf8,0x08,0x30,0x32,0x68,0xdc,0xf8, 0x0c,0x30,0x12,0x0b,0x02,0xf4,0x70,0x42,0x23,0xf4,0x70,0x43,0x13,0x43,0xcc,0xf8, 0x0c,0x30,0x32,0x68,0x21,0x4e,0x33,0x68,0xc2,0xf3,0x04,0x42,0x23,0xf0,0x1f,0x03, 0x13,0x43,0x33,0x60,0x22,0x68,0x1e,0x4c,0x23,0x68,0xc2,0xf3,0x01,0x42,0x23,0xf4, 0x40,0x13,0x43,0xea,0x02,0x53,0x1b,0x4a,0x23,0x60,0x45,0xf2,0xaa,0x53,0xce,0xf8, 0x00,0x30,0x17,0x60,0x2b,0x68,0x43,0xf0,0x01,0x03,0x2b,0x60,0x11,0x60,0x16,0x4b, 0x16,0x4c,0x1b,0x68,0x16,0x4a,0x17,0x4d,0x13,0xf0,0x02,0x0f,0x23,0x68,0x43,0xf0, 0x02,0x03,0x23,0x60,0x13,0x68,0x21,0x68,0x59,0xd0,0x3f,0xe0,0x40,0x00,0x03,0x40, 0x00,0x20,0x03,0x40,0x8c,0x11,0x00,0x50,0x44,0x22,0x03,0x40,0x74,0x11,0x00,0x50, 0x34,0x22,0x03,0x40,0x84,0x11,0x00,0x50,0x80,0x11,0x00,0x50,0xb0,0x12,0x00,0x50, 0x78,0x22,0x03,0x40,0x84,0x20,0x03,0x40,0x98,0x11,0x00,0x50,0x98,0x20,0x03,0x40, 0xa8,0x20,0x03,0x40,0x3c,0x00,0x03,0x40,0x10,0x00,0x09,0x40,0x24,0x00,0x03,0x40, 0x08,0x13,0x00,0x50,0x1c,0x00,0x03,0x40,0x88,0x22,0x03,0x40,0x88,0x11,0x00,0x50, 0x40,0x22,0x03,0x40,0x78,0x11,0x00,0x50,0x24,0x22,0x03,0x40,0x28,0x22,0x03,0x40, 0x7c,0x11,0x00,0x50,0x70,0x11,0x00,0x50,0x1c,0x22,0x03,0x40,0x14,0x22,0x03,0x40, 0x90,0x11,0x00,0x50,0x94,0x11,0x00,0x50,0x88,0x20,0x03,0x40,0x21,0xf4,0xe1,0x72, 0xc3,0xf3,0xc1,0x46,0x22,0xf0,0x01,0x02,0xc3,0xf3,0xc0,0x51,0x32,0x43,0x42,0xea, 0x01,0x22,0xc3,0xf3,0x41,0x51,0x42,0xea,0x81,0x12,0x22,0x60,0x22,0x68,0xd7,0x07, 0x02,0xd5,0x2a,0x68,0x56,0x07,0xfc,0xd5,0xc3,0xf3,0x02,0x43,0x16,0xe0,0xc3,0xf3, 0xc1,0x62,0xde,0x0f,0x42,0xea,0x06,0x26,0x21,0xf4,0xe1,0x72,0x22,0xf0,0x01,0x02, 0x32,0x43,0xc3,0xf3,0x41,0x71,0x42,0xea,0x81,0x12,0x22,0x60,0x22,0x68,0xd4,0x07, 0x02,0xd5,0x2a,0x68,0x51,0x07,0xfc,0xd5,0xc3,0xf3,0x02,0x63,0x3b,0x49,0x3c,0x4c, 0x4a,0xf6,0xaa,0x22,0x0a,0x60,0x22,0x68,0x1b,0x03,0xb3,0xf5,0xe0,0x4f,0x22,0xf4, 0xe2,0x42,0x18,0xbf,0x43,0xf4,0x80,0x73,0x13,0x43,0x23,0x60,0x45,0xf2,0xaa,0x53, 0x0b,0x60,0x34,0x4b,0x00,0x21,0x01,0x22,0x19,0x60,0x43,0xf8,0x20,0x2c,0x32,0x4a, 0x4f,0xf6,0xff,0x74,0x14,0x60,0x31,0x4c,0x43,0xf8,0x20,0x1c,0x02,0xf5,0xec,0x72, 0x4f,0xf0,0x05,0x0e,0x10,0x23,0xc4,0xf8,0x00,0xe0,0x13,0x60,0x2c,0x4b,0x15,0x26, 0x1e,0x60,0x02,0x26,0x26,0x60,0x2b,0x4e,0x37,0x68,0xc4,0xf8,0x00,0xe0,0xdf,0xf8, 0xb4,0xe0,0xce,0xf8,0x00,0x10,0xce,0xf8,0x04,0x10,0x18,0xb1,0x31,0x68,0x41,0xf4, 0x00,0x01,0x31,0x60,0x02,0x21,0x05,0x20,0x21,0x60,0x20,0x60,0x08,0x20,0x10,0x60, 0x15,0x22,0x1a,0x60,0x21,0x60,0x2b,0x68,0x9a,0x07,0xfc,0xd4,0x1e,0x4b,0x1b,0x68, 0x13,0xf0,0x10,0x0f,0x14,0xbf,0x04,0x25,0x00,0x25,0xff,0xf7,0x1b,0xfd,0x3b,0x02, 0x07,0xd4,0x05,0x23,0x23,0x60,0x33,0x68,0x23,0xf4,0x00,0x03,0x33,0x60,0x02,0x23, 0x23,0x60,0xc5,0xb9,0x15,0x4b,0x16,0x48,0x19,0x68,0x03,0xf5,0x10,0x53,0x04,0x33, 0x1a,0x68,0x1b,0x68,0x02,0xf0,0x0f,0x02,0xc9,0xb2,0x03,0xf0,0x0f,0x03,0x51,0x43, 0x9b,0x02,0xc3,0xeb,0x81,0x21,0x01,0xf5,0xfe,0x51,0x18,0x31,0x14,0x22,0xbd,0xe8, 0xf8,0x4f,0xff,0xf7,0xe9,0xbc,0x28,0x46,0xbd,0xe8,0xf8,0x8f,0x64,0x20,0x03,0x40, 0xa8,0x20,0x03,0x40,0x50,0x20,0x03,0x40,0x34,0x20,0x03,0x40,0x88,0x22,0x03,0x40, 0xb4,0x22,0x03,0x40,0x7c,0x22,0x03,0x40,0x54,0x20,0x03,0x40,0x2c,0x00,0x03,0x40, 0xf4,0x0e,0x00,0x20,0xc0,0x22,0x03,0x40,0x08,0xb5,0x01,0x1c,0x00,0x22,0x00,0x20, 0x00,0x23,0x00,0xf0,0xeb,0xf8,0x08,0xbc,0x02,0xbc,0x08,0x47,0x10,0xb5,0x00,0x21, 0x04,0x1c,0x00,0xf0,0x5d,0xf9,0x05,0x4b,0x18,0x68,0xc3,0x6b,0x00,0x2b,0x01,0xd0, 0x00,0xf0,0x06,0xf8,0x20,0x1c,0xff,0xf7,0xa7,0xfc,0xc0,0x46,0x0c,0x0f,0x00,0x20, 0x18,0x47,0xc0,0x46,0x38,0xb5,0x0a,0x4b,0x0a,0x4c,0xe4,0x1a,0xa4,0x10,0x0a,0xd0, 0x09,0x4a,0xa5,0x18,0xad,0x00,0xed,0x18,0x2b,0x68,0x01,0x3c,0x00,0xf0,0x0e,0xf8, 0x04,0x3d,0x00,0x2c,0xf8,0xd1,0x00,0xf0,0xcd,0xf9,0x38,0xbc,0x01,0xbc,0x00,0x47, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x3f,0x18,0x47,0xc0,0x46, 0x70,0xb5,0x10,0x4e,0x10,0x4d,0xad,0x1b,0xad,0x10,0x00,0x24,0x00,0x2d,0x06,0xd0, 0xa3,0x00,0xf3,0x58,0x01,0x34,0x00,0xf0,0x1d,0xf8,0xa5,0x42,0xf8,0xd1,0x00,0xf0, 0xab,0xf9,0x0a,0x4e,0x0a,0x4d,0xad,0x1b,0xad,0x10,0x00,0x24,0x00,0x2d,0x06,0xd0, 0xa3,0x00,0xf3,0x58,0x01,0x34,0x00,0xf0,0x0d,0xf8,0xa5,0x42,0xf8,0xd1,0x70,0xbc, 0x01,0xbc,0x00,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x18,0x47,0xc0,0x46,0x70,0xb5,0x0f,0x2a,0x34,0xd9,0x04,0x1c, 0x0c,0x43,0x0b,0x1c,0xa4,0x07,0x33,0xd1,0x15,0x1c,0x04,0x1c,0x10,0x3d,0x2d,0x09, 0x01,0x35,0x2d,0x01,0x49,0x19,0x1e,0x68,0x26,0x60,0x5e,0x68,0x66,0x60,0x9e,0x68, 0xa6,0x60,0xde,0x68,0x10,0x33,0xe6,0x60,0x10,0x34,0x99,0x42,0xf3,0xd1,0x0f,0x23, 0x45,0x19,0x13,0x40,0x03,0x2b,0x1d,0xd9,0x1c,0x1f,0x00,0x23,0xa4,0x08,0x01,0x34, 0xa4,0x00,0xce,0x58,0xee,0x50,0x04,0x33,0xa3,0x42,0xfa,0xd1,0xed,0x18,0xc9,0x18, 0x03,0x23,0x1a,0x40,0x05,0xd0,0x00,0x23,0xcc,0x5c,0xec,0x54,0x01,0x33,0x93,0x42, 0xfa,0xd1,0x70,0xbc,0x02,0xbc,0x08,0x47,0x05,0x1c,0x00,0x2a,0xf3,0xd1,0xf8,0xe7, 0x05,0x1c,0xf0,0xe7,0x1a,0x1c,0xf8,0xe7,0x70,0xb5,0x83,0x07,0x43,0xd0,0x54,0x1e, 0x00,0x2a,0x3d,0xd0,0x0d,0x06,0x2d,0x0e,0x03,0x1c,0x03,0x26,0x03,0xe0,0x62,0x1e, 0x00,0x2c,0x35,0xd0,0x14,0x1c,0x01,0x33,0x5a,0x1e,0x15,0x70,0x33,0x42,0xf6,0xd1, 0x03,0x2c,0x24,0xd9,0xff,0x25,0x0d,0x40,0x2a,0x02,0x15,0x43,0x2a,0x04,0x15,0x43, 0x0f,0x2c,0x11,0xd9,0x26,0x1c,0x10,0x3e,0x36,0x09,0x01,0x36,0x36,0x01,0x1a,0x1c, 0x9b,0x19,0x15,0x60,0x55,0x60,0x95,0x60,0xd5,0x60,0x10,0x32,0x93,0x42,0xf8,0xd1, 0x0f,0x22,0x14,0x40,0x03,0x2c,0x0a,0xd9,0x26,0x1f,0xb6,0x08,0x01,0x36,0xb6,0x00, 0x1a,0x1c,0x9b,0x19,0x20,0xc2,0x93,0x42,0xfc,0xd1,0x03,0x22,0x14,0x40,0x00,0x2c, 0x06,0xd0,0x09,0x06,0x1c,0x19,0x09,0x0e,0x19,0x70,0x01,0x33,0xa3,0x42,0xfb,0xd1, 0x70,0xbc,0x02,0xbc,0x08,0x47,0x14,0x1c,0x03,0x1c,0xc9,0xe7,0xf8,0xb5,0x44,0x46, 0x5f,0x46,0x56,0x46,0x4d,0x46,0x9b,0x46,0x30,0x4b,0xf0,0xb4,0x1c,0x68,0xa4,0x23, 0x5b,0x00,0x05,0x1c,0xe0,0x58,0x0e,0x1c,0x90,0x46,0x00,0x28,0x4d,0xd0,0x43,0x68, 0x1f,0x2b,0x0f,0xdc,0x5c,0x1c,0x00,0x2d,0x23,0xd1,0x02,0x33,0x9b,0x00,0x44,0x60, 0x1e,0x50,0x00,0x20,0x3c,0xbc,0x90,0x46,0x99,0x46,0xa2,0x46,0xab,0x46,0xf8,0xbc, 0x02,0xbc,0x08,0x47,0x22,0x4b,0x00,0x2b,0x3c,0xd0,0xc8,0x20,0x40,0x00,0xaf,0xf3, 0x00,0x80,0x00,0x28,0x36,0xd0,0xa4,0x22,0x00,0x23,0x52,0x00,0xa1,0x58,0x43,0x60, 0x01,0x60,0xa0,0x50,0x40,0x32,0x83,0x50,0x04,0x32,0x83,0x50,0x01,0x24,0x00,0x2d, 0xdb,0xd0,0x9a,0x00,0x91,0x46,0x81,0x44,0x42,0x46,0x88,0x21,0x4f,0x46,0x7a,0x50, 0xc4,0x22,0x52,0x00,0x90,0x46,0x80,0x44,0x42,0x46,0x87,0x39,0x99,0x40,0x12,0x68, 0x0a,0x43,0x94,0x46,0x8a,0x46,0x42,0x46,0x61,0x46,0x11,0x60,0x84,0x22,0x49,0x46, 0x5f,0x46,0x52,0x00,0x8f,0x50,0x02,0x2d,0xbf,0xd1,0x02,0x1c,0x55,0x46,0x8d,0x32, 0xff,0x32,0x11,0x68,0x0d,0x43,0x15,0x60,0xb7,0xe7,0x20,0x1c,0x4d,0x30,0xff,0x30, 0xe0,0x50,0xac,0xe7,0x01,0x20,0x40,0x42,0xb4,0xe7,0xc0,0x46,0x0c,0x0f,0x00,0x20, 0x00,0x00,0x00,0x00,0x08,0xb5,0x04,0x4b,0x00,0x2b,0x02,0xd0,0x03,0x48,0xff,0xf7, 0x9b,0xfe,0x08,0xbc,0x01,0xbc,0x00,0x47,0x00,0x00,0x00,0x00,0x15,0x0b,0x00,0x20, 0xf0,0xb5,0x56,0x46,0x5f,0x46,0x4d,0x46,0x44,0x46,0xf0,0xb4,0x0e,0x1c,0x3f,0x4b, 0x1b,0x68,0x87,0xb0,0x03,0x93,0x49,0x33,0xff,0x33,0x01,0x90,0x04,0x93,0xa4,0x22, 0x03,0x9b,0x52,0x00,0x9f,0x58,0x00,0x2f,0x4d,0xd0,0x04,0x9b,0x98,0x46,0x00,0x23, 0x9b,0x46,0xc4,0x23,0x5b,0x00,0x9c,0x46,0xbc,0x44,0x63,0x46,0x02,0x93,0xc6,0x23, 0x5b,0x00,0x9a,0x46,0x7c,0x68,0xa5,0x00,0x7d,0x19,0xba,0x44,0x01,0x3c,0x08,0xd5, 0x27,0xe0,0x6b,0x1d,0xff,0x33,0x1b,0x68,0xb3,0x42,0x04,0xd0,0x04,0x3d,0x01,0x3c, 0x1f,0xd3,0x00,0x2e,0xf5,0xd1,0x7b,0x68,0x01,0x3b,0x6a,0x68,0xa3,0x42,0x3e,0xd0, 0x5b,0x46,0x6b,0x60,0x00,0x2a,0xf1,0xd0,0x7b,0x68,0x99,0x46,0x01,0x23,0xa3,0x40, 0x02,0x99,0x09,0x68,0x05,0x91,0x19,0x42,0x26,0xd1,0x00,0xf0,0x43,0xf8,0x7b,0x68, 0x4b,0x45,0xc4,0xd1,0x43,0x46,0x1b,0x68,0xbb,0x42,0xc0,0xd1,0x04,0x3d,0x01,0x3c, 0xdf,0xd2,0x1b,0x4b,0x00,0x2b,0x0e,0xd0,0x7b,0x68,0x00,0x2b,0x27,0xd1,0x3b,0x68, 0x00,0x2b,0x28,0xd0,0x42,0x46,0x38,0x1c,0x13,0x60,0xaf,0xf3,0x00,0x80,0x43,0x46, 0x1f,0x68,0x00,0x2f,0xb5,0xd1,0x07,0xb0,0x3c,0xbc,0x90,0x46,0x99,0x46,0xa2,0x46, 0xab,0x46,0xf0,0xbc,0x01,0xbc,0x00,0x47,0x51,0x46,0x09,0x68,0x19,0x42,0x08,0xd1, 0x2b,0x1c,0x84,0x33,0x19,0x68,0x01,0x98,0x00,0xf0,0x14,0xf8,0xcf,0xe7,0x7c,0x60, 0xc0,0xe7,0x2b,0x1c,0x84,0x33,0x18,0x68,0x00,0xf0,0x0c,0xf8,0xc7,0xe7,0x3b,0x68, 0xb8,0x46,0x1f,0x1c,0xdd,0xe7,0x00,0x23,0xfa,0xe7,0xc0,0x46,0x0c,0x0f,0x00,0x20, 0x00,0x00,0x00,0x00,0x10,0x47,0xc0,0x46,0xf8,0xb5,0xc0,0x46,0xf8,0xbc,0x08,0xbc, 0x9e,0x46,0x70,0x47,0xf8,0xb5,0xc0,0x46,0xf8,0xbc,0x08,0xbc,0x9e,0x46,0x70,0x47, 0x00,0x00,0x00,0x00,0x24,0xf2,0xff,0x7f,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x8c,0x15,0x00,0x20,0xff,0xff,0xff,0xc5,0xff,0xff,0xff,0xff,0xc5,0xff,0xff,0xff, 0xc5,0xc5,0xc5,0xff,0xc5,0xc5,0xc5,0xff,0x43,0x00,0x00,0x00,0x18,0x0f,0x00,0x20, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x12,0x00,0x20, 0x6c,0x12,0x00,0x20,0xd4,0x12,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x0f,0x00,0x20, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x33,0xcd,0xab,0x34,0x12,0x6d,0xe6, 0xec,0xde,0x05,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x18,0x0f,0x00,0x20,0xc1,0x00,0x00,0x20,0x91,0x00,0x00,0x20,0x00,0x00,0x00,0x00, 0x95,0x0d,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/cc26xx/flash.c ================================================ // SPDX-License-Identifier: BSD-3-Clause /****************************************************************************** * * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #include #include #include "flash.h" /****************************************************************************** * * Defines for accesses to the security control in the customer configuration * area in flash top sector. * ******************************************************************************/ #define CCFG_OFFSET_SECURITY CCFG_O_BL_CONFIG #define CCFG_SIZE_SECURITY 0x00000014 /****************************************************************************** * * Default values for security control in customer configuration area in flash * top sector. * ******************************************************************************/ const uint8_t g_ccfg_default_sec[] = { 0xFF, 0xFF, 0xFF, 0xC5, 0xFF, 0xFF, 0xFF, 0xFF, 0xC5, 0xFF, 0xFF, 0xFF, 0xC5, 0xC5, 0xC5, 0xFF, 0xC5, 0xC5, 0xC5, 0xFF }; typedef uint32_t (*flash_prg_pntr_t) (uint8_t *, uint32_t, uint32_t); typedef uint32_t (*flash_sector_erase_pntr_t) (uint32_t); /****************************************************************************** * * Function prototypes for static functions * ******************************************************************************/ static void issue_fsm_command(flash_state_command_t command); static void enable_sectors_for_write(void); static uint32_t scale_cycle_values(uint32_t specified_timing, uint32_t scale_value); static void set_write_mode(void); static void trim_for_write(void); static void set_read_mode(void); /****************************************************************************** * * Erase a flash sector * ******************************************************************************/ uint32_t flash_sector_erase(uint32_t sector_address) { uint32_t error_return; flash_sector_erase_pntr_t func_pntr; /* Call ROM function */ func_pntr = (uint32_t (*)(uint32_t))(ROM_API_FLASH_TABLE[5]); error_return = func_pntr(sector_address); /* Enable standby because ROM function might have disabled it */ HWREGBITW(FLASH_BASE + FLASH_O_CFG, FLASH_CFG_DIS_STANDBY_BITN) = 0; /* Return status of operation. */ return error_return; } /****************************************************************************** * * Erase all unprotected sectors in the flash main bank * ******************************************************************************/ uint32_t flash_bank_erase(bool force_precondition) { uint32_t error_return; uint32_t sector_address; uint32_t reg_val; /* Enable all sectors for erase. */ enable_sectors_for_write(); /* Clear the Status register. */ issue_fsm_command(FAPI_CLEAR_STATUS); /* Enable erase of all sectors and enable precondition if required. */ reg_val = HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE); HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR1) = 0x00000000; HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR2) = 0x00000000; if (force_precondition) HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) |= FLASH_FSM_ST_MACHINE_DO_PRECOND; HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; /* Issue the bank erase command to the FSM. */ issue_fsm_command(FAPI_ERASE_BANK); /* Wait for erase to finish. */ while (flash_check_fsm_for_ready() == FAPI_STATUS_FSM_BUSY) ; /* Update status. */ error_return = flash_check_fsm_for_error(); /* Disable sectors for erase. */ flash_disable_sectors_for_write(); /* Set configured precondition mode since it may have been forced on. */ if (!(reg_val & FLASH_FSM_ST_MACHINE_DO_PRECOND)) { HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) &= ~FLASH_FSM_ST_MACHINE_DO_PRECOND; HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; } /* Program security data to default values in the customer configuration */ /* area within the flash top sector if erase was successful. */ if (error_return == FAPI_STATUS_SUCCESS) { sector_address = FLASHMEM_BASE + flash_size_get() - flash_sector_size_get(); error_return = flash_program((uint8_t *)g_ccfg_default_sec, (sector_address + CCFG_OFFSET_SECURITY), CCFG_SIZE_SECURITY); } /* Return status of operation. */ return error_return; } /****************************************************************************** * * Programs unprotected main bank flash sectors * ******************************************************************************/ uint32_t flash_program(uint8_t *data_buffer, uint32_t address, uint32_t count) { uint32_t error_return; flash_prg_pntr_t func_pntr; /* Call ROM function */ func_pntr = (uint32_t (*)(uint8_t *, uint32_t, uint32_t)) (ROM_API_FLASH_TABLE[6]); error_return = func_pntr(data_buffer, address, count); /* Enable standby because ROM function might have disabled it */ HWREGBITW(FLASH_BASE + FLASH_O_CFG, FLASH_CFG_DIS_STANDBY_BITN) = 0; /* Return status of operation. */ return error_return; } /****************************************************************************** * * Disables all sectors for erase and programming on the active bank * ******************************************************************************/ void flash_disable_sectors_for_write(void) { /* Configure flash back to read mode */ set_read_mode(); /* Disable Level 1 Protection. */ HWREG(FLASH_BASE + FLASH_O_FBPROT) = FLASH_FBPROT_PROTL1DIS; /* Disable all sectors for erase and programming. */ HWREG(FLASH_BASE + FLASH_O_FBSE) = 0x0000; /* Enable Level 1 Protection. */ HWREG(FLASH_BASE + FLASH_O_FBPROT) = 0; /* Protect sectors from sector erase. */ HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR1) = 0xFFFFFFFF; HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR2) = 0xFFFFFFFF; HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; } /****************************************************************************** * * Issues a command to the Flash State Machine. * ******************************************************************************/ static void issue_fsm_command(flash_state_command_t command) { /* Enable write to FSM register. */ HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; /* Issue FSM command. */ HWREG(FLASH_BASE + FLASH_O_FSM_CMD) = command; /* Start command execute. */ HWREG(FLASH_BASE + FLASH_O_FSM_EXECUTE) = FLASH_CMD_EXEC; /* Disable write to FSM register. */ HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; } /****************************************************************************** * * Enables all sectors for erase and programming on the active bank. * * This function disables the idle reading power reduction mode, selects the * flash bank and enables all sectors for erase and programming on the active * bank. * Sectors may be protected from programming depending on the value of the * FLASH_O_FSM_BSLPx registers. * Sectors may be protected from erase depending on the value of the * FLASH_O_FSM_BSLEx registers. Additional sector erase protection is set by * the FLASH_O_FSM_SECTOR1 register. * ******************************************************************************/ static void enable_sectors_for_write(void) { /* Trim flash module for program/erase operation. */ trim_for_write(); /* Configure flash to write mode */ set_write_mode(); /* Select flash bank. */ HWREG(FLASH_BASE + FLASH_O_FMAC) = 0x00; /* Disable Level 1 Protection. */ HWREG(FLASH_BASE + FLASH_O_FBPROT) = FLASH_FBPROT_PROTL1DIS; /* Enable all sectors for erase and programming. */ HWREG(FLASH_BASE + FLASH_O_FBSE) = 0xFFFF; /* Enable Level 1 Protection */ HWREG(FLASH_BASE + FLASH_O_FBPROT) = 0; } /****************************************************************************** * * Trims the Flash Bank and Flash Pump for program/erase functionality * * This trimming will make it possible to perform erase and program operations * of the flash. Trim values are loaded from factory configuration area * (referred to as FCGF1). The trimming done by this function is valid until * reset of the flash module. * * Some registers shall be written with a value that is a number of FCLK * cycles. The trim values controlling these registers have a value of * number of half us. FCLK = SysClk / ((RWAIT+1) x 2). * ******************************************************************************/ static void trim_for_write(void) { uint32_t value; uint32_t temp_val; uint32_t fclk_scale; uint32_t rwait; /* Return if flash is already trimmed for program/erase operations. */ if (HWREG(FLASH_BASE + FLASH_O_FWFLAG) & FW_WRT_TRIMMED) return; /* Configure the FSM registers */ /* Enable access to the FSM registers. */ HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE; /* Determine the scaling value to be used on timing related trim values. */ /* The value is based on the flash module clock frequency and RWAIT */ rwait = (HWREG(FLASH_BASE + FLASH_O_FRDCTL) & FLASH_FRDCTL_RWAIT_M) >> FLASH_FRDCTL_RWAIT_S; fclk_scale = (16 * FLASH_MODULE_CLK_FREQ) / (rwait + 1); /* Configure Program pulse width bits 15:0. */ /* (FCFG1 offset 0x188 bits 15:0). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_PROG_EP) & FCFG1_FLASH_PROG_EP_PROGRAM_PW_M) >> FCFG1_FLASH_PROG_EP_PROGRAM_PW_S; value = scale_cycle_values(value, fclk_scale); HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PW) = (HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PW) & ~FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_M) | ((value << FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_S) & FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_M); /* Configure Erase pulse width bits 31:0. */ /* (FCFG1 offset 0x18C bits 31:0). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_ERA_PW) & FCFG1_FLASH_ERA_PW_ERASE_PW_M) >> FCFG1_FLASH_ERA_PW_ERASE_PW_S; value = scale_cycle_values(value, fclk_scale); HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PW) = (HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PW) & ~FLASH_FSM_ERA_PW_FSM_ERA_PW_M) | ((value << FLASH_FSM_ERA_PW_FSM_ERA_PW_S) & FLASH_FSM_ERA_PW_FSM_ERA_PW_M); /* Configure no of flash clock cycles from EXECUTEZ going low to the the verify data can be read in the program verify mode bits 7:0. */ /* (FCFG1 offset 0x174 bits 23:16). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_C_E_P_R) & FCFG1_FLASH_C_E_P_R_PV_ACCESS_M) >> FCFG1_FLASH_C_E_P_R_PV_ACCESS_S; value = scale_cycle_values(value, fclk_scale); HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) = (HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) & ~FLASH_FSM_EX_VAL_EXE_VALD_M) | ((value << FLASH_FSM_EX_VAL_EXE_VALD_S) & FLASH_FSM_EX_VAL_EXE_VALD_M); /* Configure the number of flash clocks from the start of the Read mode at the end of the operations until the FSM clears the BUSY bit in FMSTAT. */ /* (FCFG1 offset 0x178 bits 23:16). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_P_R_PV) & FCFG1_FLASH_P_R_PV_RH_M) >> FCFG1_FLASH_P_R_PV_RH_S; HWREG(FLASH_BASE + FLASH_O_FSM_RD_H) = (HWREG(FLASH_BASE + FLASH_O_FSM_RD_H) & ~FLASH_FSM_RD_H_RD_H_M) | ((value << FLASH_FSM_RD_H_RD_H_S) & FLASH_FSM_RD_H_RD_H_M); /* Configure Program hold time */ /* (FCFG1 offset 0x178 bits 31:24). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_P_R_PV) & FCFG1_FLASH_P_R_PV_PH_M) >> FCFG1_FLASH_P_R_PV_PH_S; value = scale_cycle_values(value, fclk_scale); HWREG(FLASH_BASE + FLASH_O_FSM_P_OH) = (HWREG(FLASH_BASE + FLASH_O_FSM_P_OH) & ~FLASH_FSM_P_OH_PGM_OH_M) | ((value << FLASH_FSM_P_OH_PGM_OH_S) & FLASH_FSM_P_OH_PGM_OH_M); /* Configure Erase hold time */ /* (FCFG1 offset 0x17C bits 31:24). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_EH_SEQ) & FCFG1_FLASH_EH_SEQ_EH_M) >> FCFG1_FLASH_EH_SEQ_EH_S; value = scale_cycle_values(value, fclk_scale); HWREG(FLASH_BASE + FLASH_O_FSM_ERA_OH) = (HWREG(FLASH_BASE + FLASH_O_FSM_ERA_OH) & ~FLASH_FSM_ERA_OH_ERA_OH_M) | ((value << FLASH_FSM_ERA_OH_ERA_OH_S) & FLASH_FSM_ERA_OH_ERA_OH_M); /* Configure Program verify row switch time */ /* (FCFG1 offset0x178 bits 15:8). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_P_R_PV) & FCFG1_FLASH_P_R_PV_PVH_M) >> FCFG1_FLASH_P_R_PV_PVH_S; value = scale_cycle_values(value, fclk_scale); HWREG(FLASH_BASE + FLASH_O_FSM_PE_VH) = (HWREG(FLASH_BASE + FLASH_O_FSM_PE_VH) & ~FLASH_FSM_PE_VH_PGM_VH_M) | ((value << FLASH_FSM_PE_VH_PGM_VH_S) & FLASH_FSM_PE_VH_PGM_VH_M); /* Configure Program Operation Setup time */ /* (FCFG1 offset 0x170 bits 31:24). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) & FCFG1_FLASH_E_P_PSU_M) >> FCFG1_FLASH_E_P_PSU_S; HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) = (HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) & ~FLASH_FSM_PE_OSU_PGM_OSU_M) | ((value << FLASH_FSM_PE_OSU_PGM_OSU_S) & FLASH_FSM_PE_OSU_PGM_OSU_M); /* Configure Erase Operation Setup time */ /* (FCGF1 offset 0x170 bits 23:16). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) & FCFG1_FLASH_E_P_ESU_M) >> FCFG1_FLASH_E_P_ESU_S; HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) = (HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) & ~FLASH_FSM_PE_OSU_ERA_OSU_M) | ((value << FLASH_FSM_PE_OSU_ERA_OSU_S) & FLASH_FSM_PE_OSU_ERA_OSU_M); /* Confgure Program Verify Setup time */ /* (FCFG1 offset 0x170 bits 15:8). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) & FCFG1_FLASH_E_P_PVSU_M) >> FCFG1_FLASH_E_P_PVSU_S; HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) = (HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) & ~FLASH_FSM_PE_VSU_PGM_VSU_M) | ((value << FLASH_FSM_PE_VSU_PGM_VSU_S) & FLASH_FSM_PE_VSU_PGM_VSU_M); /* Configure Erase Verify Setup time */ /* (FCFG1 offset 0x170 bits 7:0). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) & FCFG1_FLASH_E_P_EVSU_M) >> FCFG1_FLASH_E_P_EVSU_S; HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) = (HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) & ~FLASH_FSM_PE_VSU_ERA_VSU_M) | ((value << FLASH_FSM_PE_VSU_ERA_VSU_S) & FLASH_FSM_PE_VSU_ERA_VSU_M); /* Configure Addr to EXECUTEZ low setup time */ /* (FCFG1 offset 0x174 bits 15:12). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_C_E_P_R) & FCFG1_FLASH_C_E_P_R_A_EXEZ_SETUP_M) >> FCFG1_FLASH_C_E_P_R_A_EXEZ_SETUP_S; HWREG(FLASH_BASE + FLASH_O_FSM_CMP_VSU) = (HWREG(FLASH_BASE + FLASH_O_FSM_CMP_VSU) & ~FLASH_FSM_CMP_VSU_ADD_EXZ_M) | ((value << FLASH_FSM_CMP_VSU_ADD_EXZ_S) & FLASH_FSM_CMP_VSU_ADD_EXZ_M); /* Configure Voltage Status Count */ /* (FCFG1 offset 0x17C bits 15:12). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_EH_SEQ) & FCFG1_FLASH_EH_SEQ_VSTAT_M) >> FCFG1_FLASH_EH_SEQ_VSTAT_S; HWREG(FLASH_BASE + FLASH_O_FSM_VSTAT) = (HWREG(FLASH_BASE + FLASH_O_FSM_VSTAT) & ~FLASH_FSM_VSTAT_VSTAT_CNT_M) | ((value << FLASH_FSM_VSTAT_VSTAT_CNT_S) & FLASH_FSM_VSTAT_VSTAT_CNT_M); /* Configure Repeat Verify action setup */ /* (FCFG1 offset 0x174 bits 31:24). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_C_E_P_R) & FCFG1_FLASH_C_E_P_R_RVSU_M) >> FCFG1_FLASH_C_E_P_R_RVSU_S; HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) = (HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) & ~FLASH_FSM_EX_VAL_REP_VSU_M) | ((value << FLASH_FSM_EX_VAL_REP_VSU_S) & FLASH_FSM_EX_VAL_REP_VSU_M); /* Configure Maximum Programming Pulses */ /* (FCFG1 offset 0x184 bits 15:0). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_PP) & FCFG1_FLASH_PP_MAX_PP_M) >> FCFG1_FLASH_PP_MAX_PP_S; HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) = (HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) & ~FLASH_FSM_PRG_PUL_MAX_PRG_PUL_M) | ((value << FLASH_FSM_PRG_PUL_MAX_PRG_PUL_S) & FLASH_FSM_PRG_PUL_MAX_PRG_PUL_M); /* Configure Beginning level for VHVCT used during erase modes */ /* (FCFG1 offset 0x180 bits 31:16). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_E) & FCFG1_FLASH_VHV_E_VHV_E_START_M) >> FCFG1_FLASH_VHV_E_VHV_E_START_S; HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) = (HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) & ~FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_M) | ((value << FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_S) & FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_M); /* Configure Maximum EC Level */ /* (FCFG1 offset 0x2B0 bits 21:18). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) & FCFG1_FLASH_OTP_DATA3_MAX_EC_LEVEL_M) >> FCFG1_FLASH_OTP_DATA3_MAX_EC_LEVEL_S; HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) = (HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) & ~FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_M) | ((value << FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_S) & FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_M); /* Configure Maximum Erase Pulses */ /* (FCFG1 offset 0x188 bits 31:16). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_PROG_EP) & FCFG1_FLASH_PROG_EP_MAX_EP_M) >> FCFG1_FLASH_PROG_EP_MAX_EP_S; HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) = (HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) & ~FLASH_FSM_ERA_PUL_MAX_ERA_PUL_M) | ((value << FLASH_FSM_ERA_PUL_MAX_ERA_PUL_S) & FLASH_FSM_ERA_PUL_MAX_ERA_PUL_M); /* Configure the VHVCT Step Size. This is the number of erase pulses that must be completed for each level before the FSM increments the CUR_EC_LEVEL to the next higher level. Actual erase pulses per level equals (EC_STEP_SIZE +1). The stepping is only needed for the VHVCT voltage. */ /* (FCFG1 offset 0x2B0 bits 31:23). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) & FCFG1_FLASH_OTP_DATA3_EC_STEP_SIZE_M) >> FCFG1_FLASH_OTP_DATA3_EC_STEP_SIZE_S; HWREG(FLASH_BASE + FLASH_O_FSM_STEP_SIZE) = (HWREG(FLASH_BASE + FLASH_O_FSM_STEP_SIZE) & ~FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_M) | ((value << FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_S) & FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_M); /* Configure the hight of each EC step. This is the number of counts that the CUR_EC_LEVEL will increment when going to a new level. Actual count size equals (EC_STEP_HEIGHT + 1). The stepping applies only to the VHVCT voltage. The read trim value is decremented by 1 before written to the register since actual counts equals (register value + 1). */ /* (FCFG1 offset 0x180 bits 15:0). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_E) & FCFG1_FLASH_VHV_E_VHV_E_STEP_HIGHT_M) >> FCFG1_FLASH_VHV_E_VHV_E_STEP_HIGHT_S; HWREG(FLASH_BASE + FLASH_O_FSM_EC_STEP_HEIGHT) = ((value - 1) & FLASH_FSM_EC_STEP_HEIGHT_EC_STEP_HEIGHT_M); /* Configure Precondition used in erase operations */ /* (FCFG1 offset 0x2B0 bit 22). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) & FCFG1_FLASH_OTP_DATA3_DO_PRECOND_M) >> FCFG1_FLASH_OTP_DATA3_DO_PRECOND_S; HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) = (HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) & ~FLASH_FSM_ST_MACHINE_DO_PRECOND_M) | ((value << FLASH_FSM_ST_MACHINE_DO_PRECOND_S) & FLASH_FSM_ST_MACHINE_DO_PRECOND_M); /* Enable the recommended Good Time function. */ HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) |= FLASH_FSM_ST_MACHINE_ONE_TIME_GOOD; /* Disable write access to FSM registers. */ HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE; /* Configure the voltage registers */ /* Unlock voltage registers (0x2080 - 0x2098). */ HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; /* Configure voltage level for the specified pump voltage of high voltage supply input during erase operation VHVCT_E and TRIM13_E */ /* (FCFG1 offset 0x190 bits[3:0] and bits[11:8]). */ temp_val = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV); value = ((temp_val & FCFG1_FLASH_VHV_TRIM13_E_M)>> FCFG1_FLASH_VHV_TRIM13_E_S) << FLASH_FVHVCT1_TRIM13_E_S; value |= ((temp_val & FCFG1_FLASH_VHV_VHV_E_M)>> FCFG1_FLASH_VHV_VHV_E_S) << FLASH_FVHVCT1_VHVCT_E_S; HWREG(FLASH_BASE + FLASH_O_FVHVCT1) = (HWREG(FLASH_BASE + FLASH_O_FVHVCT1) & ~(FLASH_FVHVCT1_TRIM13_E_M | FLASH_FVHVCT1_VHVCT_E_M)) | value; /* Configure voltage level for the specified pump voltage of high voltage supply input during program verify operation VHVCT_PV and TRIM13_PV */ /* (OTP offset 0x194 bits[19:16] and bits[27:24]). */ temp_val = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_PV); value = ((temp_val & FCFG1_FLASH_VHV_PV_TRIM13_PV_M) >> FCFG1_FLASH_VHV_PV_TRIM13_PV_S) << FLASH_FVHVCT1_TRIM13_PV_S; value |= ((temp_val & FCFG1_FLASH_VHV_PV_VHV_PV_M) >> FCFG1_FLASH_VHV_PV_VHV_PV_S) << FLASH_FVHVCT1_VHVCT_PV_S; HWREG(FLASH_BASE + FLASH_O_FVHVCT1) = (HWREG(FLASH_BASE + FLASH_O_FVHVCT1) & ~(FLASH_FVHVCT1_TRIM13_PV_M | FLASH_FVHVCT1_VHVCT_PV_M)) | value; /* Configure voltage level for the specified pump voltage of high voltage supply input during program operation VHVCT_P and TRIM13_P */ /* (FCFG1 offset 0x190 bits[19:16] and bits[27:24]). */ temp_val = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV); value = ((temp_val & FCFG1_FLASH_VHV_TRIM13_P_M) >> FCFG1_FLASH_VHV_TRIM13_P_S) << FLASH_FVHVCT2_TRIM13_P_S; value |= ((temp_val & FCFG1_FLASH_VHV_VHV_P_M) >> FCFG1_FLASH_VHV_VHV_P_S) << FLASH_FVHVCT2_VHVCT_P_S; HWREG(FLASH_BASE + FLASH_O_FVHVCT2) = (HWREG(FLASH_BASE + FLASH_O_FVHVCT2) & ~(FLASH_FVHVCT2_TRIM13_P_M | FLASH_FVHVCT2_VHVCT_P_M)) | value; /* Configure voltage level for the specified pump voltage of wordline power supply for read mode */ /* (FCFG1 offset 0x198 Bits 15:8). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_V) & FCFG1_FLASH_V_V_READ_M) >> FCFG1_FLASH_V_V_READ_S; HWREG(FLASH_BASE + FLASH_O_FVREADCT) = (HWREG(FLASH_BASE + FLASH_O_FVREADCT) & ~FLASH_FVREADCT_VREADCT_M) | ((value << FLASH_FVREADCT_VREADCT_S) & FLASH_FVREADCT_VREADCT_M); /* Configure the voltage level for the VCG 2.5 CT pump voltage */ /* (FCFG1 offset 0x194 bits 15:8). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_PV) & FCFG1_FLASH_VHV_PV_VCG2P5_M) >> FCFG1_FLASH_VHV_PV_VCG2P5_S; HWREG(FLASH_BASE + FLASH_O_FVNVCT) = (HWREG(FLASH_BASE + FLASH_O_FVNVCT) & ~FLASH_FVNVCT_VCG2P5CT_M) | ((value << FLASH_FVNVCT_VCG2P5CT_S) & FLASH_FVNVCT_VCG2P5CT_M); /* Configure the voltage level for the specified pump voltage of high current power input during program operation */ /* (FCFG1 offset 0x198 bits 31:24). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_V) & FCFG1_FLASH_V_VSL_P_M) >> FCFG1_FLASH_V_VSL_P_S; HWREG(FLASH_BASE + FLASH_O_FVSLP) = (HWREG(FLASH_BASE + FLASH_O_FVSLP) & ~FLASH_FVSLP_VSL_P_M) | ((value << FLASH_FVSLP_VSL_P_S) & FLASH_FVSLP_VSL_P_M); /* Configure the voltage level for the specified pump voltage of wordline power supply during programming operations */ /* (OTP offset 0x198 bits 23:16). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_V) & FCFG1_FLASH_V_VWL_P_M) >> FCFG1_FLASH_V_VWL_P_S; HWREG(FLASH_BASE + FLASH_O_FVWLCT) = (HWREG(FLASH_BASE + FLASH_O_FVWLCT) & ~FLASH_FVWLCT_VWLCT_P_M) | ((value << FLASH_FVWLCT_VWLCT_P_S) & FLASH_FVWLCT_VWLCT_P_M); /* Configure the pump's TRIM_1P7 port pins. */ /* (FCFG1 offset 0x2B0 bits 17:16). */ value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) & FCFG1_FLASH_OTP_DATA3_TRIM_1P7_M) >> FCFG1_FLASH_OTP_DATA3_TRIM_1P7_S; HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & ~FLASH_FSEQPMP_TRIM_1P7_M) | ((value << FLASH_FSEQPMP_TRIM_1P7_S) & FLASH_FSEQPMP_TRIM_1P7_M); /* Lock the voltage registers. */ HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; /* Set trimmed flag. */ HWREG(FLASH_BASE + FLASH_O_FWLOCK) = 5; HWREG(FLASH_BASE + FLASH_O_FWFLAG) |= FW_WRT_TRIMMED; HWREG(FLASH_BASE + FLASH_O_FWLOCK) = 0; } /****************************************************************************** * * Used to scale the TI OTP values based on the FClk scaling value. * ******************************************************************************/ static uint32_t scale_cycle_values(uint32_t specified_timing, uint32_t scale_value) { uint32_t scaled_value = (specified_timing * scale_value) >> 6; return scaled_value; } /****************************************************************************** * * Used to set flash in read mode. * * Flash is configured with values loaded from OTP dependent on the current * regulator mode. * ******************************************************************************/ static void set_read_mode(void) { uint32_t trim_value; uint32_t value; /* Configure the STANDBY_MODE_SEL, STANDBY_PW_SEL, DIS_STANDBY, DIS_IDLE, VIN_AT_X and VIN_BY_PASS for read mode */ if (HWREG(AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL) & AON_PMCTL_PWRCTL_EXT_REG_MODE) { /* Select trim values for external regulator mode: Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 7) Configure STANDBY_PW_SEL (OTP offset 0x308 bit 6:5) Must be done while the register bit field CONFIG.DIS_STANDBY = 1 */ HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY; trim_value = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4); value = ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_RD_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_RD_S) << FLASH_CFG_STANDBY_MODE_SEL_S; value |= ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_RD_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_RD_S) << FLASH_CFG_STANDBY_PW_SEL_S; /* Configure DIS_STANDBY (OTP offset 0x308 bit 4). Configure DIS_IDLE (OTP offset 0x308 bit 3). */ value |= ((trim_value & (FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_EXT_RD_M | FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_RD_M)) >> FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_RD_S) << FLASH_CFG_DIS_IDLE_S; HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) & ~(FLASH_CFG_STANDBY_MODE_SEL_M | FLASH_CFG_STANDBY_PW_SEL_M | FLASH_CFG_DIS_STANDBY_M | FLASH_CFG_DIS_IDLE_M)) | value; /* Check if sample and hold functionality is disabled. */ if (HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE) { /* Wait for disabled sample and hold functionality to be stable. */ while (!(HWREG(FLASH_BASE+FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS)) ; } /* Configure VIN_AT_X (OTP offset 0x308 bits 2:0) */ value = ((trim_value & FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_RD_M) >> FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_RD_S) << FLASH_FSEQPMP_VIN_AT_X_S; /* Configure VIN_BY_PASS which is dependent on the VIN_AT_X value. If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise VIN_BY_PASS should be 1 */ if (((value & FLASH_FSEQPMP_VIN_AT_X_M) >> FLASH_FSEQPMP_VIN_AT_X_S) != 0x7) value |= FLASH_FSEQPMP_VIN_BY_PASS; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & ~(FLASH_FSEQPMP_VIN_BY_PASS_M | FLASH_FSEQPMP_VIN_AT_X_M)) | value; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; } else { /* Select trim values for internal regulator mode: Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 15) COnfigure STANDBY_PW_SEL (OTP offset 0x308 bit 14:13) Must be done while the register bit field CONFIG.DIS_STANDBY = 1 */ HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY; trim_value = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4); value = ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_RD_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_RD_S) << FLASH_CFG_STANDBY_MODE_SEL_S; value |= ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_RD_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_RD_S) << FLASH_CFG_STANDBY_PW_SEL_S; /* Configure DIS_STANDBY (OTP offset 0x308 bit 12). Configure DIS_IDLE (OTP offset 0x308 bit 11). */ value |= ((trim_value & (FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_INT_RD_M | FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_RD_M)) >> FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_RD_S) << FLASH_CFG_DIS_IDLE_S; HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) & ~(FLASH_CFG_STANDBY_MODE_SEL_M | FLASH_CFG_STANDBY_PW_SEL_M | FLASH_CFG_DIS_STANDBY_M | FLASH_CFG_DIS_IDLE_M)) | value; /* Check if sample and hold functionality is disabled. */ if (HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE) { /* Wait for disabled sample and hold functionality to be stable. */ while (!(HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS)) ; } /* Configure VIN_AT_X (OTP offset 0x308 bits 10:8) */ value = (((trim_value & FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_RD_M) >> FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_RD_S) << FLASH_FSEQPMP_VIN_AT_X_S); /* Configure VIN_BY_PASS which is dependent on the VIN_AT_X value. If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise VIN_BY_PASS should be 1 */ if (((value & FLASH_FSEQPMP_VIN_AT_X_M) >> FLASH_FSEQPMP_VIN_AT_X_S) != 0x7) value |= FLASH_FSEQPMP_VIN_BY_PASS; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & ~(FLASH_FSEQPMP_VIN_BY_PASS_M | FLASH_FSEQPMP_VIN_AT_X_M)) | value; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; } } /****************************************************************************** * * Used to set flash in write mode. * * Flash is configured with values loaded from OTP dependent on the current * regulator mode. * ******************************************************************************/ static void set_write_mode(void) { uint32_t trim_value; uint32_t value; /* Configure the STANDBY_MODE_SEL, STANDBY_PW_SEL, DIS_STANDBY, DIS_IDLE, VIN_AT_X and VIN_BY_PASS for program/erase mode */ if (HWREG(AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL) & AON_PMCTL_PWRCTL_EXT_REG_MODE) { /* Select trim values for external regulator mode: Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 23) Configure STANDBY_PW_SEL (OTP offset 0x308 bit 22:21) Must be done while the register bit field CONFIG.DIS_STANDBY = 1 */ HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY; trim_value = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4); value = ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_WRT_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_WRT_S) << FLASH_CFG_STANDBY_MODE_SEL_S; value |= ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_WRT_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_WRT_S) << FLASH_CFG_STANDBY_PW_SEL_S; /* Configure DIS_STANDBY (OTP offset 0x308 bit 20). Configure DIS_IDLE (OTP offset 0x308 bit 19). */ value |= ((trim_value & (FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_EXT_WRT_M | FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_WRT_M)) >> FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_WRT_S) << FLASH_CFG_DIS_IDLE_S; HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) & ~(FLASH_CFG_STANDBY_MODE_SEL_M | FLASH_CFG_STANDBY_PW_SEL_M | FLASH_CFG_DIS_STANDBY_M | FLASH_CFG_DIS_IDLE_M)) | value; /* Check if sample and hold functionality is disabled. */ if (HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE) { /* Wait for disabled sample and hold functionality to be stable. */ while (!(HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS)) ; } /* Configure VIN_AT_X (OTP offset 0x308 bits 18:16) */ value = ((trim_value & FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_WRT_M) >> FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_WRT_S) << FLASH_FSEQPMP_VIN_AT_X_S; /* Configure VIN_BY_PASS which is dependent on the VIN_AT_X value. If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise VIN_BY_PASS should be 1 */ if (((value & FLASH_FSEQPMP_VIN_AT_X_M) >> FLASH_FSEQPMP_VIN_AT_X_S) != 0x7) value |= FLASH_FSEQPMP_VIN_BY_PASS; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & ~(FLASH_FSEQPMP_VIN_BY_PASS_M | FLASH_FSEQPMP_VIN_AT_X_M)) | value; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; } else { /* Select trim values for internal regulator mode: Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 31) COnfigure STANDBY_PW_SEL (OTP offset 0x308 bit 30:29) Must be done while the register bit field CONFIG.DIS_STANDBY = 1 */ HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY; trim_value = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4); value = ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_WRT_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_WRT_S) << FLASH_CFG_STANDBY_MODE_SEL_S; value |= ((trim_value & FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_WRT_M) >> FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_WRT_S) << FLASH_CFG_STANDBY_PW_SEL_S; /* Configure DIS_STANDBY (OTP offset 0x308 bit 28). Configure DIS_IDLE (OTP offset 0x308 bit 27). */ value |= ((trim_value & (FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_INT_WRT_M | FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_WRT_M)) >> FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_WRT_S) << FLASH_CFG_DIS_IDLE_S; HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) & ~(FLASH_CFG_STANDBY_MODE_SEL_M | FLASH_CFG_STANDBY_PW_SEL_M | FLASH_CFG_DIS_STANDBY_M | FLASH_CFG_DIS_IDLE_M)) | value; /* Check if sample and hold functionality is disabled. */ if (HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE) { /* Wait for disabled sample and hold functionality to be stable. */ while (!(HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS)) ; } /* Configure VIN_AT_X (OTP offset 0x308 bits 26:24) */ value = ((trim_value & FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_WRT_M) >> FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_WRT_S) << FLASH_FSEQPMP_VIN_AT_X_S; /* Configure VIN_BY_PASS which is dependent on the VIN_AT_X value. If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise VIN_BY_PASS should be 1 */ if (((value & FLASH_FSEQPMP_VIN_AT_X_M) >> FLASH_FSEQPMP_VIN_AT_X_S) != 0x7) value |= FLASH_FSEQPMP_VIN_BY_PASS; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA; HWREG(FLASH_BASE + FLASH_O_FSEQPMP) = (HWREG(FLASH_BASE + FLASH_O_FSEQPMP) & ~(FLASH_FSEQPMP_VIN_BY_PASS_M | FLASH_FSEQPMP_VIN_AT_X_M)) | value; HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA; } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/cc26xx/flash.h ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_CC26XX_FLASH_H #define OPENOCD_LOADERS_FLASH_CC26XX_FLASH_H #ifdef __cplusplus extern "C" { #endif #include #include #include "hw_regs.h" /* Location of flash in memory map */ #define FLASHMEM_BASE 0 /* Defines to access flash API calls in ROM */ #define ROM_API_TABLE ((uint32_t *) 0x10000180) #define ROM_VERSION (ROM_API_TABLE[0]) #define ROM_API_FLASH_TABLE ((uint32_t *) (ROM_API_TABLE[10])) #if defined(DEVICE_CC26X2) /* Agama (CC26x2) specific definitions */ #define FLASH_ERASE_SIZE 8192 /* Agama (and Agama 1M) has a maximum of 132 flash sectors (1056KB / 8KB) */ #define FLASH_MAX_SECTOR_COUNT 132 #define FLASH_SECTOR_BASE_M 0xFFFFE000 /* Bootloader Configuration */ #define CCFG_O_BL_CONFIG 0x00001FD8 #elif defined(DEVICE_CC26X0) /* Chameleon (CC26x0) specific definitions */ #define FLASH_ERASE_SIZE 4096 /* Chameleon has a maximum of 32 flash sectors (128KB / 4KB) */ #define FLASH_MAX_SECTOR_COUNT 32 #define FLASH_SECTOR_BASE_M 0xFFFFF000 /* Bootloader Configuration */ #define CCFG_O_BL_CONFIG 0x00000FD8 #else #error No DEVICE defined. #endif /****************************************************************************** * * Values that can be returned from the API functions * ******************************************************************************/ #define FAPI_STATUS_SUCCESS 0x00000000 /* Function completed successfully */ #define FAPI_STATUS_FSM_BUSY 0x00000001 /* FSM is Busy */ #define FAPI_STATUS_FSM_READY 0x00000002 /* FSM is Ready */ #define FAPI_STATUS_INCORRECT_DATABUFFER_LENGTH \ 0x00000003 /* Incorrect parameter value */ #define FAPI_STATUS_FSM_ERROR 0x00000004 /* Operation failed */ /****************************************************************************** * * Define used by the flash programming and erase functions * ******************************************************************************/ #define ADDR_OFFSET (0x1F800000 - FLASHMEM_BASE) /****************************************************************************** * * Define used for access to factory configuration area. * ******************************************************************************/ #define FCFG1_OFFSET 0x1000 /****************************************************************************** * * Define for the clock frequency input to the flash module in number of MHz * ******************************************************************************/ #define FLASH_MODULE_CLK_FREQ 48 /****************************************************************************** * * Defined values for Flash State Machine commands * ******************************************************************************/ typedef enum { FAPI_PROGRAM_DATA = 0x0002, /* Program data. */ FAPI_ERASE_SECTOR = 0x0006, /* Erase sector. */ FAPI_ERASE_BANK = 0x0008, /* Erase bank. */ FAPI_VALIDATE_SECTOR = 0x000E, /* Validate sector. */ FAPI_CLEAR_STATUS = 0x0010, /* Clear status. */ FAPI_PROGRAM_RESUME = 0x0014, /* Program resume. */ FAPI_ERASE_RESUME = 0x0016, /* Erase resume. */ FAPI_CLEAR_MORE = 0x0018, /* Clear more. */ FAPI_PROGRAM_SECTOR = 0x0020, /* Program sector. */ FAPI_ERASE_OTP = 0x0030 /* Erase OTP. */ } flash_state_command_t; /****************************************************************************** * * Defines for values written to the FLASH_O_FSM_WR_ENA register * ******************************************************************************/ #define FSM_REG_WRT_ENABLE 5 #define FSM_REG_WRT_DISABLE 2 /****************************************************************************** * * Defines for the bank power mode field the FLASH_O_FBFALLBACK register * ******************************************************************************/ #define FBFALLBACK_SLEEP 0 #define FBFALLBACK_DEEP_STDBY 1 #define FBFALLBACK_ACTIVE 3 /****************************************************************************** * * Defines for the bank grace period and pump grace period * ******************************************************************************/ #define FLASH_BAGP 0x14 #define FLASH_PAGP 0x14 /****************************************************************************** * * Defines for the FW flag bits in the FLASH_O_FWFLAG register * ******************************************************************************/ #define FW_WRT_TRIMMED 0x00000001 /****************************************************************************** * * Defines used by the flash programming functions * ******************************************************************************/ typedef volatile uint8_t fwp_write_byte; #define FWPWRITE_BYTE_ADDRESS \ ((fwp_write_byte *)((FLASH_BASE + FLASH_O_FWPWRITE0))) /****************************************************************************** * * Define for FSM command execution * ******************************************************************************/ #define FLASH_CMD_EXEC 0x15 /****************************************************************************** * * Get size of a flash sector in number of bytes. * * This function will return the size of a flash sector in number of bytes. * * Returns size of a flash sector in number of bytes. * ******************************************************************************/ static inline uint32_t flash_sector_size_get(void) { uint32_t sector_size_in_kbyte; sector_size_in_kbyte = (HWREG(FLASH_BASE + FLASH_O_FCFG_B0_SSIZE0) & FLASH_FCFG_B0_SSIZE0_B0_SECT_SIZE_M) >> FLASH_FCFG_B0_SSIZE0_B0_SECT_SIZE_S; /* Return flash sector size in number of bytes. */ return sector_size_in_kbyte * 1024; } /****************************************************************************** * * Get the size of the flash. * * This function returns the size of the flash main bank in number of bytes. * * Returns the flash size in number of bytes. * ******************************************************************************/ static inline uint32_t flash_size_get(void) { uint32_t num_of_sectors; /* Get number of flash sectors */ num_of_sectors = (HWREG(FLASH_BASE + FLASH_O_FLASH_SIZE) & FLASH_FLASH_SIZE_SECTORS_M) >> FLASH_FLASH_SIZE_SECTORS_S; /* Return flash size in number of bytes */ return num_of_sectors * flash_sector_size_get(); } /****************************************************************************** * * Checks if the Flash state machine has detected an error. * * This function returns the status of the Flash State Machine indicating if * an error is detected or not. Primary use is to check if an Erase or * Program operation has failed. * * Please note that code can not execute in flash while any part of the flash * is being programmed or erased. This function must be called from ROM or * SRAM while any part of the flash is being programmed or erased. * * Returns status of Flash state machine: * FAPI_STATUS_FSM_ERROR * FAPI_STATUS_SUCCESS * ******************************************************************************/ static inline uint32_t flash_check_fsm_for_error(void) { if (HWREG(FLASH_BASE + FLASH_O_FMSTAT) & FLASH_FMSTAT_CSTAT) return FAPI_STATUS_FSM_ERROR; else return FAPI_STATUS_SUCCESS; } /****************************************************************************** * * Checks if the Flash state machine is ready. * * This function returns the status of the Flash State Machine indicating if * it is ready to accept a new command or not. Primary use is to check if an * Erase or Program operation has finished. * * Please note that code can not execute in flash while any part of the flash * is being programmed or erased. This function must be called from ROM or * SRAM while any part of the flash is being programmed or erased. * * Returns readiness status of Flash state machine: * FAPI_STATUS_FSM_READY * FAPI_STATUS_FSM_BUSY * ******************************************************************************/ static inline uint32_t flash_check_fsm_for_ready(void) { if (HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_BUSY) return FAPI_STATUS_FSM_BUSY; else return FAPI_STATUS_FSM_READY; } /****************************************************************************** * * Erase a flash sector. * * This function will erase the specified flash sector. The function will * not return until the flash sector has been erased or an error condition * occurred. If flash top sector is erased the function will program the * device security data bytes with default values. The device security * data located in the customer configuration area of the flash top sector, * must have valid values at all times. These values affect the configuration * of the device during boot. * * Please note that code can not execute in flash while any part of the flash * is being programmed or erased. This function must only be executed from ROM * or SRAM. * * sector_address is the starting address in flash of the sector to be * erased. * * Returns the status of the sector erase: * FAPI_STATUS_SUCCESS : Success. * FAPI_STATUS_INCORRECT_DATABUFFER_LENGTH : Invalid argument. * FAPI_STATUS_FSM_ERROR : Programming error was encountered. * ******************************************************************************/ extern uint32_t flash_sector_erase(uint32_t sector_address); /****************************************************************************** * * Erase all unprotected sectors in the flash main bank. * * This function will erase all unprotected flash sectors. The function will * not return until the flash sectors has been erased or an error condition * occurred. Since the flash top sector is erased the function will program * the device security data bytes with default values. The device security * data located in the customer configuration area of the flash top sector, * must have valid values at all times. These values affect the configuration * of the device during boot. The execution time of the operation increases if * erase precondition is forced. This will cause the flash module to first * program all 1 bits in the bank to 0 before the actual erase is started. * * force_precondition controls if erase precondition should be forced. * * Returns the status of the sector erase: * FAPI_STATUS_SUCCESS : Success * FAPI_STATUS_FSM_ERROR : Erase error was encountered. * ******************************************************************************/ extern uint32_t flash_bank_erase(bool force_precondition); /****************************************************************************** * * Programs unprotected main bank flash sectors. * * This function will program a sequence of bytes into the on-chip flash. * Programming each location consists of the result of an AND operation * of the new data and the existing data; in other words bits that contain * 1 can remain 1 or be changed to 0, but bits that are 0 cannot be changed * to 1. Therefore, a byte can be programmed multiple times as long as these * rules are followed; if a program operation attempts to change a 0 bit to * a 1 bit, that bit will not have its value changed. * * This function will not return until the data has been programmed or an * programming error has occurred. * * Please note that code can not execute in flash while any part of the flash * is being programmed or erased. This function must only be executed from ROM * or SRAM. * * The data_buffer pointer cannot point to flash. * * data_buffer is a pointer to the data to be programmed. * address is the starting address in flash to be programmed. * count is the number of bytes to be programmed. * * Returns status of the flash programming: * FAPI_STATUS_SUCCESS : Success. * FAPI_STATUS_INCORRECT_DATABUFFER_LENGTH : Too many bytes were requested. * FAPI_STATUS_FSM_ERROR : Programming error was encountered. * ******************************************************************************/ extern uint32_t flash_program(uint8_t *data_buffer, uint32_t address, uint32_t count); /****************************************************************************** * * Disables all sectors for erase and programming on the active bank. * * This function disables all sectors for erase and programming on the active * bank and enables the Idle Reading Power reduction mode if no low power * mode is configured. Furthermore, an additional level of protection from * erase is enabled. * * Please note that code can not execute in flash while any part of the flash * is being programmed or erased. * ******************************************************************************/ extern void flash_disable_sectors_for_write(void); #ifdef __cplusplus } #endif #endif /* #ifndef OPENOCD_LOADERS_FLASH_CC26XX_FLASH_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/cc26xx/flashloader.c ================================================ // SPDX-License-Identifier: BSD-3-Clause /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #include #include #include "flashloader.h" #include "flash.h" /* Array holding erased state of the flash sectors. */ static bool g_is_erased[FLASH_MAX_SECTOR_COUNT]; extern uint8_t g_retain_buf[]; uint32_t flashloader_init(struct flash_params *params, uint8_t *buf1, uint8_t *buf2) { /* Initialize params buffers */ memset((void *)params, 0, 2 * sizeof(struct flash_params)); params[0].buf_addr = (uint32_t)buf1; params[1].buf_addr = (uint32_t)buf2; /* Mark all sectors at "not erased" */ memset(g_is_erased, false, sizeof(g_is_erased)); return STATUS_OK; } uint32_t flashloader_erase_and_program(uint8_t *src, uint32_t address, uint32_t byte_count) { if (byte_count > BUFFER_LEN) return STATUS_FAILED_INVALID_ARGUMENTS; /* Erase affected sectors */ uint32_t status = flashloader_erase_sectors(address, byte_count); if (status != STATUS_OK) return status; /* Program data */ status = flashloader_program(src, address, byte_count); return status; } uint32_t flashloader_program_with_retain(uint8_t *src, uint32_t address, uint32_t byte_count) { #if (BUFFER_LEN > FLASH_ERASE_SIZE) #error Buffer size cannot be larger than the flash sector size! #endif uint32_t first_sector_idx; uint32_t last_sector_idx; uint32_t status = STATUS_OK; uint32_t i; first_sector_idx = flashloader_address_to_sector(address); last_sector_idx = flashloader_address_to_sector(address + byte_count - 1); /* Mark all sectors as "not erased" before starting */ memset(g_is_erased, false, sizeof(g_is_erased)); uint32_t sec_offset = address % FLASH_ERASE_SIZE; uint32_t curr_count; uint32_t src_offset = 0; for (i = first_sector_idx; i <= last_sector_idx; i++) { /* Chop off at sector boundary if data goes into the next sector. */ curr_count = byte_count; if ((address + byte_count) > ((i+1) * FLASH_ERASE_SIZE)) curr_count -= (address + byte_count) % FLASH_ERASE_SIZE; /* Copy flash sector to retain buffer */ memcpy(g_retain_buf, (void *)(i * FLASH_ERASE_SIZE), FLASH_ERASE_SIZE); /* Copy data buffer to retain buffer */ memcpy(&g_retain_buf[sec_offset], &src[src_offset], curr_count); /* Erase and program from retain buffer */ status = flashloader_erase_and_program(g_retain_buf, (i * FLASH_ERASE_SIZE), FLASH_ERASE_SIZE); if (status != STATUS_OK) return status; address += curr_count; sec_offset = address % FLASH_ERASE_SIZE; byte_count -= curr_count; src_offset += curr_count; } return status; } uint32_t flashloader_erase_all(void) { if (flash_bank_erase(true) != FAPI_STATUS_SUCCESS) return STATUS_FAILED_ERASE_ALL; memset(g_is_erased, true, sizeof(g_is_erased)); return STATUS_OK; } uint32_t flashloader_erase_sectors(uint32_t address, uint32_t byte_count) { uint32_t first_sector_idx; uint32_t last_sector_idx; uint32_t status; uint32_t idx; /* Floor address to the start of the sector and convert to sector number */ first_sector_idx = flashloader_address_to_sector(address); last_sector_idx = flashloader_address_to_sector(address + byte_count - 1); /* Erase given sector(s) */ for (idx = first_sector_idx; idx <= last_sector_idx; idx++) { /* Only erase sectors that haven't already been erased */ if (g_is_erased[idx] == false) { status = flash_sector_erase(idx * FLASH_ERASE_SIZE); if (status != FAPI_STATUS_SUCCESS) { status = (STATUS_FAILED_SECTOR_ERASE | ((idx << STATUS_EXT_INFO_S) & STATUS_EXT_INFO_M) | ((status << STATUS_ROM_CODE_S) & STATUS_ROM_CODE_M)); return status; } g_is_erased[idx] = true; } } return STATUS_OK; } uint32_t flashloader_program(uint8_t *src, uint32_t address, uint32_t byte_count) { uint32_t status = flash_program(src, address, byte_count); if (status != FAPI_STATUS_SUCCESS) { status = (STATUS_FAILED_PROGRAM | ((status << STATUS_ROM_CODE_S) & STATUS_ROM_CODE_M)); } return STATUS_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/cc26xx/flashloader.h ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_CC26XX_FLASHLOADER_H #define OPENOCD_LOADERS_FLASH_CC26XX_FLASHLOADER_H #include #include #include #include "flash.h" /* Number of elements in an array */ #define NELEMS(a) (sizeof(a) / sizeof(a[0])) struct __attribute__((__packed__)) flash_params { uint32_t dest; /* Destination address in flash */ uint32_t len; /* Number of bytes */ uint32_t cmd; /* Command */ uint32_t full; /* Handshake signal. Is buffer ready? */ uint32_t buf_addr; /* Address of data buffer. */ }; typedef enum { CMD_NO_ACTION = 0, /* No action, default value */ CMD_ERASE_ALL = 1, /* Erase all unprotected sectors */ CMD_PROGRAM = 2, /* Program data */ CMD_ERASE_AND_PROGRAM = 3, /* Erase and program data */ CMD_ERASE_AND_PROGRAM_WITH_RETAIN = 4, /* Erase and program, but retain */ /* sector data outside given range */ CMD_ERASE_SECTORS = 5 /* Erase unprotected sectors */ } flash_commands_t; typedef enum { BUFFER_EMPTY = 0x0, /* No data in buffer, flags last task complete */ BUFFER_FULL = 0xFFFFFFFF /* Buffer has data, flags next task to start */ } flash_handshake_t; #define STATUS_FLASHLOADER_STATUS_M 0x0000FFFF #define STATUS_FLASHLOADER_STATUS_S 0 #define STATUS_ROM_CODE_M 0x00FF0000 #define STATUS_ROM_CODE_S 16 #define STATUS_EXT_INFO_M 0xFF000000 #define STATUS_EXT_INFO_S 24 typedef enum { STATUS_OK = 0, STATUS_FAILED_ERASE_ALL = 0x101, STATUS_FAILED_SECTOR_ERASE = 0x102, STATUS_FAILED_PROGRAM = 0x103, STATUS_FAILED_INVALID_ARGUMENTS = 0x104, STATUS_FAILED_UNKNOWN_COMMAND = 0x105, } flash_status_t; /* The buffer size used by the flashloader. The size of 1 flash sector. */ #define BUFFER_LEN FLASH_ERASE_SIZE /* * This function initializes the flashloader. The application must * allocate memory for the two data buffers and the flash_params structures. * * params Pointer an flash_params array with 2 elements. * buf1 Pointer to data buffer 1 * buf2 Pointer to data buffer 2 * * Returns STATUS_OK * */ extern uint32_t flashloader_init(struct flash_params *params, uint8_t *buf1, uint8_t *buf2); /* * Erase and program the necessary sectors. Data outside the given * range will be deleted. * * src Pointer to buffer containing the data. * address Start address in device flash * byte_count The number of bytes to program * * Returns STATUS_OK on success. For status on failure: * See flashloader_program() and flashloader_erase_sectors(). * */ extern uint32_t flashloader_erase_and_program(uint8_t *src, uint32_t address, uint32_t byte_count); /* * Erase and program the device sectors. Data outside the given * data range will be kept unchanged. * * src Pointer to buffer containing the data. * address Start address in device flash * byte_count The number of bytes to program * * Returns STATUS_OK on success. For status on failure: * See flashloader_program() and flashloader_erase_sectors(). * */ extern uint32_t flashloader_program_with_retain(uint8_t *src, uint32_t address, uint32_t byte_count); /* * Erases all flash sectors (that are not write-protected). * * Returns STATUS_OK on success. * */ extern uint32_t flashloader_erase_all(void); /* * Erases the flash sectors affected by the given range. * * This function only erases sectors that are not already erased. * * start_addr The first address in the range. * byte_count The number of bytes in the range. * * Returns STATUS_OK on success. Returns a combined status on failure: * [31:24] The sector that failed. * [23:16] ROM function status code. 0 means success. * [16: 0] STATUS_FAILED_SECTOR_ERASE * */ extern uint32_t flashloader_erase_sectors(uint32_t start_addr, uint32_t byte_count); /* * Program the given range. * * This function does not erase anything, it assumes the sectors are ready to * be programmed. * * src Pointer to buffer containing the data. * address Start address in device flash * byte_count The number of bytes to program * * Returns STATUS_OK on success. Returns a combined status value on failure: * [31:16] ROM function status code. 0 means success. * [15:0 ] STATUS_FAILED_PROGRAM * */ extern uint32_t flashloader_program(uint8_t *src, uint32_t address, uint32_t byte_count); /* * Convert the input address into a sector number. * * address The address. * * Returns the flash sector which the address resides in. The first sector * is sector 0. * */ static inline uint32_t flashloader_address_to_sector(uint32_t address) { return (address / FLASH_ERASE_SIZE); }; #endif /* #ifndef OPENOCD_LOADERS_FLASH_CC26XX_FLASHLOADER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/cc26xx/hw_regs.h ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_CC26XX_HW_REGS_H #define OPENOCD_LOADERS_FLASH_CC26XX_HW_REGS_H /****************************************************************************** * * Macros for direct hardware access. * * If using these macros the programmer should be aware of any limitations to * the address accessed i.e. if it supports word and/or byte access. * ******************************************************************************/ /* Word (32 bit) access to address x */ /* Read example : my32BitVar = HWREG(base_addr + offset) ; */ /* Write example : HWREG(base_addr + offset) = my32BitVar ; */ #define HWREG(x) (*((volatile unsigned long *)(x))) /* Half word (16 bit) access to address x */ /* Read example : my16BitVar = HWREGH(base_addr + offset) ; */ /* Write example : HWREGH(base_addr + offset) = my16BitVar ; */ #define HWREGH(x) (*((volatile unsigned short *)(x))) /* Byte (8 bit) access to address x */ /* Read example : my8BitVar = HWREGB(base_addr + offset) ; */ /* Write example : HWREGB(base_addr + offset) = my8BitVar ; */ #define HWREGB(x) (*((volatile unsigned char *)(x))) /****************************************************************************** * * Macro for access to bit-band supported addresses via the bit-band region. * * Macro calculates the corresponding address to access in the bit-band region * based on the actual address of the memory/register and the bit number. * * Do NOT use this macro to access the bit-band region directly! * ******************************************************************************/ /* Bit-band access to address x bit number b using word access (32 bit) */ #define HWREGBITW(x, b) \ HWREG(((unsigned long)(x) & 0xF0000000) | 0x02000000 | \ (((unsigned long)(x) & 0x000FFFFF) << 5) | ((b) << 2)) /****************************************************************************** * * Memory mapped components base address definitions * ******************************************************************************/ #define FLASH_BASE 0x40030000 #define FLASH_CFG_BASE 0x50000000 #define AON_PMCTL_BASE 0x40090000 /****************************************************************************** * * This section defines the register offsets of FLASH component * ******************************************************************************/ /* FMC and Efuse Status */ #define FLASH_O_STAT 0x0000001C /* Configuration */ #define FLASH_O_CFG 0x00000024 /* Flash Size Configuration */ #define FLASH_O_FLASH_SIZE 0x0000002C /* Firmware Lock */ #define FLASH_O_FWLOCK 0x0000003C /* Firmware Flags */ #define FLASH_O_FWFLAG 0x00000040 /* FMC Read Control */ #define FLASH_O_FRDCTL 0x00002000 /* FMC Bank Protection */ #define FLASH_O_FBPROT 0x00002030 /* FMC Bank Sector Enable */ #define FLASH_O_FBSE 0x00002034 /* FMC Module Access Control */ #define FLASH_O_FMAC 0x00002050 /* FMC Module Status */ #define FLASH_O_FMSTAT 0x00002054 /* FMC Flash Lock */ #define FLASH_O_FLOCK 0x00002064 /* FMC VREADCT Trim */ #define FLASH_O_FVREADCT 0x00002080 /* FMC VHVCT1 Trim */ #define FLASH_O_FVHVCT1 0x00002084 /* FMC VHVCT2 Trim */ #define FLASH_O_FVHVCT2 0x00002088 /* FMC VNVCT Trim */ #define FLASH_O_FVNVCT 0x00002090 /* FMC VSL_P Trim */ #define FLASH_O_FVSLP 0x00002094 /* FMC VWLCT Trim */ #define FLASH_O_FVWLCT 0x00002098 /* FMC Sequential Pump Information */ #define FLASH_O_FSEQPMP 0x000020A8 /* FMC FSM Command */ #define FLASH_O_FSM_CMD 0x0000220C /* FMC FSM Program/Erase Operation Setup */ #define FLASH_O_FSM_PE_OSU 0x00002210 /* FMC FSM Voltage Status Setup */ #define FLASH_O_FSM_VSTAT 0x00002214 /* FMC FSM Program/Erase Verify Setup */ #define FLASH_O_FSM_PE_VSU 0x00002218 /* FMC FSM Compare Verify Setup */ #define FLASH_O_FSM_CMP_VSU 0x0000221C /* FMC FSM EXECUTEZ to Valid Data */ #define FLASH_O_FSM_EX_VAL 0x00002220 /* FMC FSM Read Mode Hold */ #define FLASH_O_FSM_RD_H 0x00002224 /* FMC FSM Program Hold */ #define FLASH_O_FSM_P_OH 0x00002228 /* FMC FSM Erase Operation Hold */ #define FLASH_O_FSM_ERA_OH 0x0000222C /* FMC FSM Program/Erase Verify Hold */ #define FLASH_O_FSM_PE_VH 0x00002234 /* FMC FSM Program Pulse Width */ #define FLASH_O_FSM_PRG_PW 0x00002240 /* FMC FSM Erase Pulse Width */ #define FLASH_O_FSM_ERA_PW 0x00002244 /* FMC FSM Maximum Programming Pulses */ #define FLASH_O_FSM_PRG_PUL 0x00002268 /* FMC FSM Maximum Erase Pulses */ #define FLASH_O_FSM_ERA_PUL 0x0000226C /* FMC FSM EC Step Size */ #define FLASH_O_FSM_STEP_SIZE 0x00002270 /* FMC FSM EC Step Height */ #define FLASH_O_FSM_EC_STEP_HEIGHT 0x00002278 /* FMC FSM_ST_MACHINE */ #define FLASH_O_FSM_ST_MACHINE 0x0000227C /* FMC FSM Register Write Enable */ #define FLASH_O_FSM_WR_ENA 0x00002288 /* FMC FSM Command Execute */ #define FLASH_O_FSM_EXECUTE 0x000022B4 /* FMC FSM Sector Erased 1 */ #define FLASH_O_FSM_SECTOR1 0x000022C0 /* FMC FSM Sector Erased 2 */ #define FLASH_O_FSM_SECTOR2 0x000022C4 /* FMC Flash Bank 0 Starting Address */ #define FLASH_O_FCFG_B0_START 0x00002410 /* FMC Flash Bank 0 Sector Size 0 */ #define FLASH_O_FCFG_B0_SSIZE0 0x00002430 /****************************************************************************** * * Register: FLASH_O_STAT * ******************************************************************************/ /* Field: [2] SAMHOLD_DIS * * Status indicator of flash sample and hold sequencing logic. This bit will go * to 1 some delay after CFG.DIS_IDLE is set to 1. * 0: Not disabled * 1: Sample and hold disabled and stable */ #define FLASH_STAT_SAMHOLD_DIS 0x00000004 /* Field: [1] BUSY * * Fast version of the FMC FMSTAT.BUSY bit. * This flag is valid immediately after the operation setting it (FMSTAT.BUSY * is delayed some cycles) * 0 : Not busy * 1 : Busy */ #define FLASH_STAT_BUSY 0x00000002 /****************************************************************************** * * Register: FLASH_O_CFG * ******************************************************************************/ /* Field: [8] STANDBY_MODE_SEL * * [Configured by boot firmware] * STANDBY mode selection control. This bit, in conjunction with * STANDBY_PW_SEL, determine which 1 of 4 sub-modes is selected for control of * the behavior and timing of the STANDBY input to the pump. * * 0 : Legacy PG1 behavior is selected when STANDBY_PW_SEL = 00. This is * referred to as sub-mode 1. When STANDBY_PW_SEL != 00, then sub-mode 2 * behavior is selected. STANDBY will be glitchy in these modes. * 1 : STANDBY pulse-width counter modes selected. In these two modes (referred * to as sub-mode 3 and sub-mode 4), the low time pulse width of the STANDBY * signal to the pump, is controlled by a programmable timer. STANDBY will not * be glitchy in these modes. */ #define FLASH_CFG_STANDBY_MODE_SEL_M 0x00000100 #define FLASH_CFG_STANDBY_MODE_SEL_S 8 /* Field: [7:6] STANDBY_PW_SEL * * [Configured by boot firmware] * STANDBY pulse width counter selection control. These bits, in conjunction * with STANDBY_MODE_SEL, determine which 1 of 4 sub-modes is selected for * control of the behavior and timing of the STANDBY input to the pump. * * 00 : Legacy PG1 behavior is selected when STANDBY_MODE_SEL=0. Sub-mode 4 is * selected when STANDBY_MODE_SEL=1. In sub-mode 4, STANDBY will be low for at * least 9 pump clock cycles. * 01 : Sub-mode 2 or 3 is selected, and STANDBY will be low for at least 9 * pump clock cycles. * 10: Sub-mode 2 or 3 is selected, and STANDBY will be low for at least 5 pump * clock cycles. * 11: Sub-mode 2 or 3 is selected, and STANDBY will be low for at least 13 * pump clock cycles. */ #define FLASH_CFG_STANDBY_PW_SEL_M 0x000000C0 #define FLASH_CFG_STANDBY_PW_SEL_S 6 /* Field: [1] DIS_STANDBY * * [Configured by boot firmware] * Disable standby functionality in read idle state */ #define FLASH_CFG_DIS_STANDBY 0x00000002 #define FLASH_CFG_DIS_STANDBY_BITN 1 #define FLASH_CFG_DIS_STANDBY_M 0x00000002 /* Field: [0] DIS_IDLE * * [Configured by boot firmware] * Disable sample and hold functionality in read idle state */ #define FLASH_CFG_DIS_IDLE 0x00000001 #define FLASH_CFG_DIS_IDLE_M 0x00000001 #define FLASH_CFG_DIS_IDLE_S 0 /****************************************************************************** * * Register: FLASH_O_FLASH_SIZE * ******************************************************************************/ /* Field: [7:0] SECTORS * * [Configured by boot firmware] * Flash size. The number of flash sectors in the configured device. Read * access to sectors equal to this number or higher will result in an error. * The CCFG area is the sector (SECTORS - 1) Writing to this register is * disabled by the CFG.CONFIGURED bit. */ #define FLASH_FLASH_SIZE_SECTORS_M 0x000000FF #define FLASH_FLASH_SIZE_SECTORS_S 0 /****************************************************************************** * * Register: FLASH_O_FRDCTL * ******************************************************************************/ /* Field: [11:8] RWAIT * * [Configured by boot firmware] * FMC Wait State. This field determines the FLCLK period during FMC controlled * flash accesses: * - During power up/ power down / low power mode * - During FSM operations like program, erase * - During software interface mode (see FLOCK , FBSTROBES registers) * FLCLK_period = HCLK_period X (RWAIT + 1), * FSM state machine operations are usually twice this amount. This value * should never be set less than 2. */ #define FLASH_FRDCTL_RWAIT_M 0x00000F00 #define FLASH_FRDCTL_RWAIT_S 8 /****************************************************************************** * * Register: FLASH_O_FBPROT * ******************************************************************************/ /* Field: [0] PROTL1DIS * * Level 1 Protection Disable bit. Setting this bit disables protection from * writing to the FBAC.OTPPROTDIS bits as well as the Sector Enable registers * FBSE for all banks. Clearing this bit enables protection and disables write * access to the FBAC.OTPPROTDIS register bits and FBSE register. */ #define FLASH_FBPROT_PROTL1DIS 0x00000001 /****************************************************************************** * * Register: FLASH_O_FMSTAT * ******************************************************************************/ /* Field: [4] CSTAT * * Command Status. Once the FSM starts any failure will set this bit. When set, * this bit informs the host that the program, erase, or validate sector * command failed and the command was stopped. This bit is cleared by the * Clear_Status command. For some errors, this will be the only indication of * an FSM error because the cause does not fall within the other error bit * types. */ #define FLASH_FMSTAT_CSTAT 0x00000010 /****************************************************************************** * * Register: FLASH_O_FVREADCT * ******************************************************************************/ /* Field: [3:0] VREADCT * * [Configured by boot firmware] * These bits control the voltage level for the specified pump voltage of * wordline power supply for read mode. */ #define FLASH_FVREADCT_VREADCT_M 0x0000000F #define FLASH_FVREADCT_VREADCT_S 0 /****************************************************************************** * * Register: FLASH_O_FVHVCT1 * ******************************************************************************/ /* Field: [23:20] TRIM13_E * * [Configured by boot firmware] * These bits control the voltage level for the specified pump voltage of high * voltage supply input during erase operation. */ #define FLASH_FVHVCT1_TRIM13_E_M 0x00F00000 #define FLASH_FVHVCT1_TRIM13_E_S 20 /* Field: [19:16] VHVCT_E * * [Configured by boot firmware] * These bits control the voltage level for the specified pump voltage of high * voltage supply input during erase operation. */ #define FLASH_FVHVCT1_VHVCT_E_M 0x000F0000 #define FLASH_FVHVCT1_VHVCT_E_S 16 /* Field: [7:4] TRIM13_PV * * [Configured by boot firmware] * These bits control the voltage level for the specified pump voltage of high * voltage supply input during program verify operation. */ #define FLASH_FVHVCT1_TRIM13_PV_M 0x000000F0 #define FLASH_FVHVCT1_TRIM13_PV_S 4 /* Field: [3:0] VHVCT_PV * * [Configured by boot firmware] * These bits control the voltage level for the specified pump voltage of high * voltage supply input during program verify operation. */ #define FLASH_FVHVCT1_VHVCT_PV_M 0x0000000F #define FLASH_FVHVCT1_VHVCT_PV_S 0 /****************************************************************************** * * Register: FLASH_O_FVHVCT2 * ******************************************************************************/ /* Field: [23:20] TRIM13_P * * [Configured by boot firmware] * These bits control the voltage level for the specified pump voltage of high * voltage supply input during program operation. */ #define FLASH_FVHVCT2_TRIM13_P_M 0x00F00000 #define FLASH_FVHVCT2_TRIM13_P_S 20 /* Field: [19:16] VHVCT_P * * [Configured by boot firmware] * These bits control the voltage level for the specified pump voltage of high * voltage supply input during program operation. */ #define FLASH_FVHVCT2_VHVCT_P_M 0x000F0000 #define FLASH_FVHVCT2_VHVCT_P_S 16 /****************************************************************************** * * Register: FLASH_O_FVNVCT * ******************************************************************************/ /* Field: [12:8] VCG2P5CT * * [Configured by boot firmware] * These bits control the voltage level for the VCG 2.5 CT pump voltage. */ #define FLASH_FVNVCT_VCG2P5CT_M 0x00001F00 #define FLASH_FVNVCT_VCG2P5CT_S 8 /****************************************************************************** * * Register: FLASH_O_FVSLP * ******************************************************************************/ /* Field: [15:12] VSL_P * * [Configured by boot firmware] * These bits control the voltage level for the specified pump voltage of high * current power input during program operation. */ #define FLASH_FVSLP_VSL_P_M 0x0000F000 #define FLASH_FVSLP_VSL_P_S 12 /****************************************************************************** * * Register: FLASH_O_FVWLCT * ******************************************************************************/ /* Field: [4:0] VWLCT_P * * [Configured by boot firmware] * These bits control the voltage level for the specified pump voltage of * wordline power supply during programming operations. */ #define FLASH_FVWLCT_VWLCT_P_M 0x0000001F #define FLASH_FVWLCT_VWLCT_P_S 0 /****************************************************************************** * * Register: FLASH_O_FSEQPMP * ******************************************************************************/ /* Field: [21:20] TRIM_1P7 * * [Configured by boot firmware] * This register goes directly to the pump's TRIM_1P7 port pins. */ #define FLASH_FSEQPMP_TRIM_1P7_M 0x00300000 #define FLASH_FSEQPMP_TRIM_1P7_S 20 /* Field: [14:12] VIN_AT_X * * This register controls to the pump's VIN_AT_XPX port pins with the following * encoding; * * If VIN_BY_PASS=0 then pump VIN_AT_XPX is equal to VIN_AT_XIN input ports * from the BATMON logic after clocking through synchronizers and the sequence * checker FSM logic contained in the flash wrapper. * * If VIN_BY_PASS=1 and VIN_AT_X=??? * * 0: then all pump VIN_AT_XPX signals are 0. * 1: then pump VIN_AT_1P7 is set. * 2: then pump VIN_AT_2P1 is also set. * 3: then pump VIN_AT_2P4 is also set. * 4-7: then pump VIN_AT_3P0 is also set (ie all VIN_AT_XPX signals are 1). */ #define FLASH_FSEQPMP_VIN_AT_X_M 0x00007000 #define FLASH_FSEQPMP_VIN_AT_X_S 12 /* Field: [8] VIN_BY_PASS * * [Configured by boot firmware] * * When this bit is a zero, the pump's VIN_AT_XPX ports comes from the FMC * input port VIN_AT_XIN. * * When this bit is a one, the pump's VIN_AT_XPX ports comes from the VIN_AT_X * bits in 14:12. */ #define FLASH_FSEQPMP_VIN_BY_PASS 0x00000100 #define FLASH_FSEQPMP_VIN_BY_PASS_M 0x00000100 /****************************************************************************** * * Register: FLASH_O_FSM_PE_OSU * ******************************************************************************/ /* Field: [15:8] PGM_OSU * * [Configured by boot firmware] * Program Operation Setup time. This determines the flash clocks from the mode * change to program, to the start of the program pulse. */ #define FLASH_FSM_PE_OSU_PGM_OSU_M 0x0000FF00 #define FLASH_FSM_PE_OSU_PGM_OSU_S 8 /* Field: [7:0] ERA_OSU * * [Configured by boot firmware] * Erase Operation Setup time. This determines the flash clocks from the mode * change to erase, to the start of the erase pulse. */ #define FLASH_FSM_PE_OSU_ERA_OSU_M 0x000000FF #define FLASH_FSM_PE_OSU_ERA_OSU_S 0 /****************************************************************************** * * Register: FLASH_O_FSM_VSTAT * ******************************************************************************/ /* Field: [15:12] VSTAT_CNT * * [Configured by boot firmware] * Voltage Status Count. Gives the number of consecutive HCLK pulses that must * be out of range before a voltage-out-of-range status error is given in * FMSTAT.VOLSTAT. One pulse in range will reset the counter. This is mainly a * glitch filter on the voltage status pump signal. */ #define FLASH_FSM_VSTAT_VSTAT_CNT_M 0x0000F000 #define FLASH_FSM_VSTAT_VSTAT_CNT_S 12 /****************************************************************************** * * Register: FLASH_O_FSM_PE_VSU * ******************************************************************************/ /* Field: [15:8] PGM_VSU * * [Configured by boot firmware] * Program Verify Setup time. This determines the flash clocks from the mode * change to program verify, to the change of address and the beginning of the * address setup time. */ #define FLASH_FSM_PE_VSU_PGM_VSU_M 0x0000FF00 #define FLASH_FSM_PE_VSU_PGM_VSU_S 8 /* Field: [7:0] ERA_VSU * * [Configured by boot firmware] * Erase Verify Setup time. This determines the flash clocks from the mode * change to erase verify, to the change of address and the beginning of the * address setup time. */ #define FLASH_FSM_PE_VSU_ERA_VSU_M 0x000000FF #define FLASH_FSM_PE_VSU_ERA_VSU_S 0 /****************************************************************************** * * Register: FLASH_O_FSM_CMP_VSU * ******************************************************************************/ /* Field: [15:12] ADD_EXZ * * [Configured by boot firmware] * Address to EXECUTEZ low setup time. This determines the flash clocks from * the row address change to the time EXECUTEZ goes low. All operations use * this value. */ #define FLASH_FSM_CMP_VSU_ADD_EXZ_M 0x0000F000 #define FLASH_FSM_CMP_VSU_ADD_EXZ_S 12 /****************************************************************************** * * Register: FLASH_O_FSM_EX_VAL * ******************************************************************************/ /* Field: [15:8] REP_VSU * * [Configured by boot firmware] * Repeat Verify action setup. If a program or erase operation advances to the * program_verify or erase_verify then this special shorter mode transition * time will be used in place of FSM_PE_VSU.PGM_VSU or FSM_PE_VSU.ERA_VSU * times. */ #define FLASH_FSM_EX_VAL_REP_VSU_M 0x0000FF00 #define FLASH_FSM_EX_VAL_REP_VSU_S 8 /* Field: [7:0] EXE_VALD * * [Configured by boot firmware] * EXECUTEZ low to valid Data. Determines the number of Flash clock cycles from * EXECUTEZ going low to the time the verify data can be read in the program * verify mode. Erase and compact verify is always a constant value which is * currently set at one flash clock. This value must be greater than 0. */ #define FLASH_FSM_EX_VAL_EXE_VALD_M 0x000000FF #define FLASH_FSM_EX_VAL_EXE_VALD_S 0 /****************************************************************************** * * Register: FLASH_O_FSM_RD_H * ******************************************************************************/ /* Field: [7:0] RD_H * * [Configured by boot firmware] * Read mode hold. This determines the number of flash clocks from the start of * the Read mode at the end of the operations until the FSM clears the * FMSTAT.BUSY. Writing a zero to this register will result in a value of 1. * The reset value of this register is 0x3Ah before FMC version 3.0.10.0 and * 0x5Ah after this version. */ #define FLASH_FSM_RD_H_RD_H_M 0x000000FF #define FLASH_FSM_RD_H_RD_H_S 0 /****************************************************************************** * * Register: FLASH_O_FSM_P_OH * ******************************************************************************/ /* Field: [15:8] PGM_OH * * [Configured by boot firmware] * EXECUTEZ high to mode change. This value determines the flash clocks from * the EXECUTEZ going high at the end of a program operation to the time the * mode can change. This value must be greater than or equal to one. */ #define FLASH_FSM_P_OH_PGM_OH_M 0x0000FF00 #define FLASH_FSM_P_OH_PGM_OH_S 8 /****************************************************************************** * * Register: FLASH_O_FSM_ERA_OH * ******************************************************************************/ /* Field: [15:0] ERA_OH * * [Configured by boot firmware] * EXECUTEZ high to mode change. Determines the flash clocks from EXECUTEZ * going high at the end of an erase operation to the time the mode can change. * If a bank erase is happening, then this is the time to when the TEZ and TCR * values for bank erase are released. The mode changes 10 flash clocks after * they are released. This value must be greater than or equal to one. */ #define FLASH_FSM_ERA_OH_ERA_OH_M 0x0000FFFF #define FLASH_FSM_ERA_OH_ERA_OH_S 0 /****************************************************************************** * * Register: FLASH_O_FSM_PE_VH * ******************************************************************************/ /* Field: [15:8] PGM_VH * * [Configured by boot firmware] * Program Verify Hold. This register determines the flash clocks from EXECUTEZ * going high after a program verify to a mode change. This value must be * greater than or equal to one */ #define FLASH_FSM_PE_VH_PGM_VH_M 0x0000FF00 #define FLASH_FSM_PE_VH_PGM_VH_S 8 /****************************************************************************** * * Register: FLASH_O_FSM_PRG_PW * ******************************************************************************/ /* Field: [15:0] PROG_PUL_WIDTH * * [Configured by boot firmware] * Program Pulse width.This register gives the number of flash clocks that the * EXECUTEZ signal is low in a program operation. */ #define FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_M 0x0000FFFF #define FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_S 0 /****************************************************************************** * * Register: FLASH_O_FSM_ERA_PW * ******************************************************************************/ /* Field: [31:0] FSM_ERA_PW * * [Configured by boot firmware] * Erase Pulse width. This register gives the number flash clocks that the * EXECUTEZ signal is low in an erase operation. */ #define FLASH_FSM_ERA_PW_FSM_ERA_PW_M 0xFFFFFFFF #define FLASH_FSM_ERA_PW_FSM_ERA_PW_S 0 /****************************************************************************** * * Register: FLASH_O_FSM_PRG_PUL * ******************************************************************************/ /* Field: [19:16] BEG_EC_LEVEL * * [Configured by boot firmware] * Beginning level for VHVCT. This determines the beginning level for VHVCT * that is used during erase modes. The pump voltage control registers supply * the other values that do not change during FSM operations. The reset value * is the same as FVHVCT1.VHVCT_E. */ #define FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_M 0x000F0000 #define FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_S 16 /* Field: [11:0] MAX_PRG_PUL * * [Configured by boot firmware] * Maximum Programming Pulses. This register contains the maximum number of * programming pulses allowed at one address. If it takes any more than this * amount during a programming operation then the FSM will exit with an error * and with the program violation, FMSTAT.PGV set, and the general error set, * FMSTAT.CSTAT. Setting FSM_ST_MACHINE.OVERRIDE to 0 will allow more than this * maximum value to occur without an error. During pre-conditioning for an * erase operation the FSM programs all the bits to zero. If the maximum number * of programming pulses is reached for an address, the FSM will continue with * the next address and set the FMSTAT.PCV and the general error FMSTAT.CSTAT. * If the FSM_ST_MACHINE.PREC_STOP_EN is set then the FSM will stop with errors * when more than the maximum number of pulses is needed. The * FSM_ST_MACHINE.OVERRIDE bit will take priority over the * FSM_ST_MACHINE.PREC_STOP_EN and continue doing pulses without setting the * error bits. Suspend operations will count a pulse if the program operation * began no matter how long the pulse lasted before is was suspended. Frequent * suspend or auto-suspend operations could result in max_pulse count error. */ #define FLASH_FSM_PRG_PUL_MAX_PRG_PUL_M 0x00000FFF #define FLASH_FSM_PRG_PUL_MAX_PRG_PUL_S 0 /****************************************************************************** * * Register: FLASH_O_FSM_ERA_PUL * ******************************************************************************/ /* Field: [19:16] MAX_EC_LEVEL * * [Configured by boot firmware] * Maximum VHVCT Level. This determines the maximum level for VHVCT that is * used during erase modes. The FSM will stop advancing VHVCT once it counts up * to the MAX_EC_LEVEL level from the beginning level. The MAX_EC_LEVEL + * FSM_EC_STEP_HEIGHT.EC_STEP_HEIGHT must be less than 0x200. The reset value * is the same as FVHVCT1.VHVCT_E. */ #define FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_M 0x000F0000 #define FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_S 16 /* Field: [11:0] MAX_ERA_PUL * * [Configured by boot firmware] * Maximum Erase Pulses. This register contains the maximum number of erase * pulses allowed at one address. If it takes any more than this amount the FSM * will exit with an error and with both the FMSTAT.EV and FMSTAT.CSTAT bits * set. Setting FSM_ST_MACHINE.OVERRIDE to 1 will allow more than this maximum * value to occur without an error. Suspend operations will count a pulse if * the erase operation began no matter how long the pulse lasted before is was * suspended. Frequent suspend or auto-suspend operations could result in * max_pulse count error. */ #define FLASH_FSM_ERA_PUL_MAX_ERA_PUL_M 0x00000FFF #define FLASH_FSM_ERA_PUL_MAX_ERA_PUL_S 0 /****************************************************************************** * * Register: FLASH_O_FSM_STEP_SIZE * ******************************************************************************/ /* Field: [24:16] EC_STEP_SIZE * * [Configured by boot firmware] * VHVCT Step Size. This is the number of erase pulses that must be completed * for each level before the FSM increments the FSM_PUL_CNTR.CUR_EC_LEVEL to * the next higher level. Actual erase pulses per level equals (EC_STEP_SIZE * +1). The stepping is only needed for the VHVCT voltage. */ #define FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_M 0x01FF0000 #define FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_S 16 /****************************************************************************** * * Register: FLASH_O_FSM_EC_STEP_HEIGHT * ******************************************************************************/ /* Field: [3:0] EC_STEP_HEIGHT * * [Configured by boot firmware] * Height of each EC step. This is the number of counts that the * FSM_PUL_CNTR.CUR_EC_LEVEL will increment when going to a new level. Actual * count size equals (EC_STEP_HEIGHT + 1). The stepping applies only to the * VHVCT voltage. If adding the height to the FSM_PUL_CNTR.CUR_EC_LEVEL results * in a value higher than the FSM_ERA_PUL.MAX_EC_LEVEL then the * FSM_PUL_CNTR.CUR_EC_LEVEL will be lowered to the MAX LEVEL before it is used * in the next erase pulse. */ #define FLASH_FSM_EC_STEP_HEIGHT_EC_STEP_HEIGHT_M 0x0000000F /****************************************************************************** * * Register: FLASH_O_FSM_ST_MACHINE * ******************************************************************************/ /* Field: [23] DO_PRECOND * * [Configured by boot firmware] * Do preconditioning. When this bit is a one, the FSM will precondition the * sector or bank before doing an erase operation. When zero, the FSM will just * begin with the erase verify and skip the preconditioning. */ #define FLASH_FSM_ST_MACHINE_DO_PRECOND 0x00800000 #define FLASH_FSM_ST_MACHINE_DO_PRECOND_M 0x00800000 #define FLASH_FSM_ST_MACHINE_DO_PRECOND_S 23 /* Field: [14] ONE_TIME_GOOD * * [Configured by boot firmware] * One Time Good function. If this bit is a one then the 'One Time Good' * function is enabled for all program operations. This includes operations * inside the erase functions and other functions. When zero, this function is * disabled for all modes. When doing the One Time Good function, the FSM will * attempt to program a location with data. If a desired zero bit reads back * from the flash one time as good then that bit is blocked from writing a zero * to the flash array again for this address. When the address changes, all * bits are unblocked. This prevents a bit from reading 0 in one programming * pulse and then 1 in the next programming pulse. On the second time the bit * would get a programming pulse even though it read 0 in an earlier read. If * this bit is a zero then the zero bits will be masked for each program verify * operation. It is recommended for this bit to be set to 1. */ #define FLASH_FSM_ST_MACHINE_ONE_TIME_GOOD 0x00004000 /****************************************************************************** * * Register: FLASH_O_FCFG_B0_SSIZE0 * ******************************************************************************/ /* Field: [3:0] B0_SECT_SIZE * * Size of sectors in Bank 0. Common sector size for all sectors in the bank in * 1K bytes multiples. * 0x0: 0K bytes * 0x1: 1K bytes(FLES) * 0x2: 2K bytes * 0x4: 4K bytes (FLEE) * ... * 0xF: 15K bytes */ #define FLASH_FCFG_B0_SSIZE0_B0_SECT_SIZE_M 0x0000000F #define FLASH_FCFG_B0_SSIZE0_B0_SECT_SIZE_S 0 /****************************************************************************** * * This section defines the register offsets of FCFG1 component * ******************************************************************************/ /* Flash Erase and Program Setup Time */ #define FCFG1_O_FLASH_E_P 0x00000170 /* Flash Compaction, Execute, Program and Read */ #define FCFG1_O_FLASH_C_E_P_R 0x00000174 /* Flash Program, Read, and Program Verify */ #define FCFG1_O_FLASH_P_R_PV 0x00000178 /* Flash Erase Hold and Sequence */ #define FCFG1_O_FLASH_EH_SEQ 0x0000017C /* Flash VHV Erase */ #define FCFG1_O_FLASH_VHV_E 0x00000180 /* Flash Program Pulse */ #define FCFG1_O_FLASH_PP 0x00000184 /* Flash Program and Erase Pulse */ #define FCFG1_O_FLASH_PROG_EP 0x00000188 /* Flash Erase Pulse Width */ #define FCFG1_O_FLASH_ERA_PW 0x0000018C /* Flash VHV */ #define FCFG1_O_FLASH_VHV 0x00000190 /* Flash VHV Program Verify */ #define FCFG1_O_FLASH_VHV_PV 0x00000194 /* Flash Voltages */ #define FCFG1_O_FLASH_V 0x00000198 /* Flash OTP Data 3 */ #define FCFG1_O_FLASH_OTP_DATA3 0x000002B0 /* Flash OTP Data 4 */ #define FCFG1_O_FLASH_OTP_DATA4 0x00000308 /****************************************************************************** * * Register: FCFG1_O_FLASH_E_P * ******************************************************************************/ /* Field: [31:24] PSU * * Program setup time in cycles. Value will be written to * FLASH:FSM_PE_OSU.PGM_OSU by the flash device driver when an erase/program * operation is initiated. */ #define FCFG1_FLASH_E_P_PSU_M 0xFF000000 #define FCFG1_FLASH_E_P_PSU_S 24 /* Field: [23:16] ESU * * Erase setup time in cycles. Value will be written to * FLASH:FSM_PE_OSU.ERA_OSU by the flash device driver when an erase/program * operation is initiated. */ #define FCFG1_FLASH_E_P_ESU_M 0x00FF0000 #define FCFG1_FLASH_E_P_ESU_S 16 /* Field: [15:8] PVSU * * Program verify setup time in cycles. Value will be written to * FLASH:FSM_PE_VSU.PGM_VSU by the flash device driver when an erase/program * operation is initiated. */ #define FCFG1_FLASH_E_P_PVSU_M 0x0000FF00 #define FCFG1_FLASH_E_P_PVSU_S 8 /* Field: [7:0] EVSU * * Erase verify setup time in cycles. Value will be written to * FLASH:FSM_PE_VSU.ERA_VSU by the flash device driver when an erase/program * operation is initiated. */ #define FCFG1_FLASH_E_P_EVSU_M 0x000000FF #define FCFG1_FLASH_E_P_EVSU_S 0 /****************************************************************************** * * Register: FCFG1_O_FLASH_C_E_P_R * ******************************************************************************/ /* Field: [31:24] RVSU * * Repeat verify setup time in cycles. Used for repeated verifies during * program and erase. Value will be written to FLASH:FSM_EX_VAL.REP_VSU by the * flash device driver when an erase/program operation is initiated. */ #define FCFG1_FLASH_C_E_P_R_RVSU_M 0xFF000000 #define FCFG1_FLASH_C_E_P_R_RVSU_S 24 /* Field: [23:16] PV_ACCESS * * Program verify EXECUTEZ->data valid time in half-microseconds. Value * will be converted to number of FCLK cycles by by flash device driver and the * converted value is written to FLASH:FSM_EX_VAL.EXE_VALD when an * erase/program operation is initiated. */ #define FCFG1_FLASH_C_E_P_R_PV_ACCESS_M 0x00FF0000 #define FCFG1_FLASH_C_E_P_R_PV_ACCESS_S 16 /* Field: [15:12] A_EXEZ_SETUP * * Address->EXECUTEZ setup time in cycles. Value will be written to * FLASH:FSM_CMP_VSU.ADD_EXZ by the flash device driver when an erase/program * operation is initiated. */ #define FCFG1_FLASH_C_E_P_R_A_EXEZ_SETUP_M 0x0000F000 #define FCFG1_FLASH_C_E_P_R_A_EXEZ_SETUP_S 12 /****************************************************************************** * * Register: FCFG1_O_FLASH_P_R_PV * ******************************************************************************/ /* Field: [31:24] PH * * Program hold time in half-microseconds after SAFELV goes high. Value will be * converted to number of FCLK cycles by the flash device driver and the * converted value is written to FLASH:FSM_P_OH.PGM_OH when an erase/program * operation is initiated. */ #define FCFG1_FLASH_P_R_PV_PH_M 0xFF000000 #define FCFG1_FLASH_P_R_PV_PH_S 24 /* Field: [23:16] RH * * Read hold/mode transition time in cycles. Value will be written to the RD_H * field bits[7:0] of the FSM_RD_H register in the flash module by the flash * device driver when an erase/program operation is initiated. */ #define FCFG1_FLASH_P_R_PV_RH_M 0x00FF0000 #define FCFG1_FLASH_P_R_PV_RH_S 16 /* Field: [15:8] PVH * * Program verify hold time in half-microseconds after SAFELV goes high. Value * will be converted to number of FCLK cycles by the flash device driver and * the converted value is written to FLASH:FSM_PE_VH.PGM_VH when an * erase/program operation is initiated. */ #define FCFG1_FLASH_P_R_PV_PVH_M 0x0000FF00 #define FCFG1_FLASH_P_R_PV_PVH_S 8 /****************************************************************************** * * Register: FCFG1_O_FLASH_EH_SEQ * ******************************************************************************/ /* Field: [31:24] EH * * Erase hold time in half-microseconds after SAFELV goes high. Value will be * converted to number of FCLK cycles by the flash device driver and the * converted value is written to FLASH:FSM_ERA_OH.ERA_OH when an erase/program * operation is initiated. */ #define FCFG1_FLASH_EH_SEQ_EH_M 0xFF000000 #define FCFG1_FLASH_EH_SEQ_EH_S 24 /* Field: [15:12] VSTAT * * Max number of HCLK cycles allowed for pump brown-out. Value will be written * to FLASH:FSM_VSTAT.VSTAT_CNT when an erase/program operation is initiated. */ #define FCFG1_FLASH_EH_SEQ_VSTAT_M 0x0000F000 #define FCFG1_FLASH_EH_SEQ_VSTAT_S 12 /****************************************************************************** * * Register: FCFG1_O_FLASH_VHV_E * ******************************************************************************/ /* Field: [31:16] VHV_E_START * * Starting VHV-Erase CT for stairstep erase. Value will be written to * FLASH:FSM_PRG_PUL.BEG_EC_LEVEL when erase/program operation is initiated. */ #define FCFG1_FLASH_VHV_E_VHV_E_START_M 0xFFFF0000 #define FCFG1_FLASH_VHV_E_VHV_E_START_S 16 /* Field: [15:0] VHV_E_STEP_HIGHT * * Number of VHV CTs to step after each erase pulse (up to the max). The actual * FMC register value should be one less than this since the FMC starts * counting from zero. Value will be written to * FLASH:FSM_EC_STEP_HEIGHT.EC_STEP_HEIGHT when an erase/program operation is * initiated. */ #define FCFG1_FLASH_VHV_E_VHV_E_STEP_HIGHT_M 0x0000FFFF #define FCFG1_FLASH_VHV_E_VHV_E_STEP_HIGHT_S 0 /****************************************************************************** * * Register: FCFG1_O_FLASH_PP * ******************************************************************************/ /* Field: [15:0] MAX_PP * * Max program pulse limit per program operation. Value will be written to * FLASH:FSM_PRG_PUL.MAX_PRG_PUL when an erase/program operation is initiated. */ #define FCFG1_FLASH_PP_MAX_PP_M 0x0000FFFF #define FCFG1_FLASH_PP_MAX_PP_S 0 /****************************************************************************** * * Register: FCFG1_O_FLASH_PROG_EP * ******************************************************************************/ /* Field: [31:16] MAX_EP * * Max erase pulse limit per erase operation. Value will be written to * FLASH:FSM_ERA_PUL.MAX_ERA_PUL when an erase/program operation is initiated. */ #define FCFG1_FLASH_PROG_EP_MAX_EP_M 0xFFFF0000 #define FCFG1_FLASH_PROG_EP_MAX_EP_S 16 /* Field: [15:0] PROGRAM_PW * * Program pulse width in half-microseconds. Value will be converted to number * of FCLK cycles by the flash device driver and the converted value is written * to FLASH:FSM_PRG_PW.PROG_PUL_WIDTH when a erase/program operation is * initiated. */ #define FCFG1_FLASH_PROG_EP_PROGRAM_PW_M 0x0000FFFF #define FCFG1_FLASH_PROG_EP_PROGRAM_PW_S 0 /****************************************************************************** * * Register: FCFG1_O_FLASH_ERA_PW * ******************************************************************************/ /* Field: [31:0] ERASE_PW * * Erase pulse width in half-microseconds. Value will be converted to number of * FCLK cycles by the flash device driver and the converted value is written to * FLASH:FSM_ERA_PW.FSM_ERA_PW when a erase/program operation is initiated. */ #define FCFG1_FLASH_ERA_PW_ERASE_PW_M 0xFFFFFFFF #define FCFG1_FLASH_ERA_PW_ERASE_PW_S 0 /****************************************************************************** * * Register: FCFG1_O_FLASH_VHV * ******************************************************************************/ /* Field: [27:24] TRIM13_P * * Value will be written to FLASH:FVHVCT2.TRIM13_P by the flash device driver * when an erase/program operation is initiated. */ #define FCFG1_FLASH_VHV_TRIM13_P_M 0x0F000000 #define FCFG1_FLASH_VHV_TRIM13_P_S 24 /* Field: [19:16] VHV_P * * Value will be written to FLASH:FVHVCT2.VHVCT_P by the flash device driver * when an erase/program operation is initiated. */ #define FCFG1_FLASH_VHV_VHV_P_M 0x000F0000 #define FCFG1_FLASH_VHV_VHV_P_S 16 /* Field: [11:8] TRIM13_E * * Value will be written to FLASH:FVHVCT1.TRIM13_E by the flash device driver * when an erase/program operation is initiated. */ #define FCFG1_FLASH_VHV_TRIM13_E_M 0x00000F00 #define FCFG1_FLASH_VHV_TRIM13_E_S 8 /* Field: [3:0] VHV_E * * Value will be written to FLASH:FVHVCT1.VHVCT_E by the flash device driver * when an erase/program operation is initiated */ #define FCFG1_FLASH_VHV_VHV_E_M 0x0000000F #define FCFG1_FLASH_VHV_VHV_E_S 0 /****************************************************************************** * * Register: FCFG1_O_FLASH_VHV_PV * ******************************************************************************/ /* Field: [27:24] TRIM13_PV * * Value will be written to FLASH:FVHVCT1.TRIM13_PV by the flash device driver * when an erase/program operation is initiated. */ #define FCFG1_FLASH_VHV_PV_TRIM13_PV_M 0x0F000000 #define FCFG1_FLASH_VHV_PV_TRIM13_PV_S 24 /* Field: [19:16] VHV_PV * * Value will be written to FLASH:FVHVCT1.VHVCT_PV by the flash device driver * when an erase/program operation is initiated. */ #define FCFG1_FLASH_VHV_PV_VHV_PV_M 0x000F0000 #define FCFG1_FLASH_VHV_PV_VHV_PV_S 16 /* Field: [15:8] VCG2P5 * * Control gate voltage during read, read margin, and erase verify. Value will * be written to FLASH:FVNVCT.VCG2P5CT by the flash device driver when an * erase/program operation is initiated. */ #define FCFG1_FLASH_VHV_PV_VCG2P5_M 0x0000FF00 #define FCFG1_FLASH_VHV_PV_VCG2P5_S 8 /****************************************************************************** * * Register: FCFG1_O_FLASH_V * ******************************************************************************/ /* Field: [31:24] VSL_P * * Sourceline voltage applied to the selected block during programming. Value * will be written to FLASH:FVSLP.VSL_P by the flash device driver when an * erase/program operation is initiated. */ #define FCFG1_FLASH_V_VSL_P_M 0xFF000000 #define FCFG1_FLASH_V_VSL_P_S 24 /* Field: [23:16] VWL_P * * Wordline voltage applied to the selected half-row during programming. Value * will be written to FLASH:FVWLCT.VWLCT_P by the flash device driver when an * erase/program operation is initiated. */ #define FCFG1_FLASH_V_VWL_P_M 0x00FF0000 #define FCFG1_FLASH_V_VWL_P_S 16 /* Field: [15:8] V_READ * * Wordline voltage applied to the selected block during reads and verifies. * Value will be written to FLASH:FVREADCT.VREADCT by the flash device driver * when an erase/program operation is initiated. */ #define FCFG1_FLASH_V_V_READ_M 0x0000FF00 #define FCFG1_FLASH_V_V_READ_S 8 /****************************************************************************** * * Register: FCFG1_O_FLASH_OTP_DATA3 * ******************************************************************************/ /* Field: [31:23] EC_STEP_SIZE * * Value will be written to FLASH:FSM_STEP_SIZE.EC_STEP_SIZE by the flash * device driver when a erase/program operation is initiated. */ #define FCFG1_FLASH_OTP_DATA3_EC_STEP_SIZE_M 0xFF800000 #define FCFG1_FLASH_OTP_DATA3_EC_STEP_SIZE_S 23 /* Field: [22] DO_PRECOND * * Value will be written to FLASH:FSM_ST_MACHINE.DO_PRECOND by the flash device * driver when a erase/program operation is initiated. * * Note that during a Total Erase operation the flash bank will always be * erased with Precondition enabled independent of the value of this FCFG1 bit * field. */ #define FCFG1_FLASH_OTP_DATA3_DO_PRECOND_M 0x00400000 #define FCFG1_FLASH_OTP_DATA3_DO_PRECOND_S 22 /* Field: [21:18] MAX_EC_LEVEL * * Value will be written to FLASH:FSM_ERA_PUL.MAX_EC_LEVEL by the flash device * driver when a erase/program operation is initiated. */ #define FCFG1_FLASH_OTP_DATA3_MAX_EC_LEVEL_M 0x003C0000 #define FCFG1_FLASH_OTP_DATA3_MAX_EC_LEVEL_S 18 /* Field: [17:16] TRIM_1P7 * * Value will be written to FLASH:FSEQPMP.TRIM_1P7 by the flash device driver * when a erase/program operation is initiated. */ #define FCFG1_FLASH_OTP_DATA3_TRIM_1P7_M 0x00030000 #define FCFG1_FLASH_OTP_DATA3_TRIM_1P7_S 16 /****************************************************************************** * * Register: FCFG1_O_FLASH_OTP_DATA4 * ******************************************************************************/ /* Field: [31] STANDBY_MODE_SEL_INT_WRT * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to * FLASH:CFG.STANDBY_MODE_SEL by flash device driver FW when a flash write * operation is initiated. */ #define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_WRT_M 0x80000000 #define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_WRT_S 31 /* Field: [30:29] STANDBY_PW_SEL_INT_WRT * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to * FLASH:CFG.STANDBY_PW_SEL by flash device driver FW when a flash write * operation is initiated. */ #define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_WRT_M 0x60000000 #define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_WRT_S 29 /* Field: [28] DIS_STANDBY_INT_WRT * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to * FLASH:CFG.DIS_STANDBY by flash device driver FW when a flash write operation * is initiated. */ #define FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_INT_WRT_M 0x10000000 /* Field: [27] DIS_IDLE_INT_WRT * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to * FLASH:CFG.DIS_IDLE by flash device driver FW when a flash write operation is * initiated. */ #define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_WRT_M 0x08000000 #define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_WRT_S 27 /* Field: [26:24] VIN_AT_X_INT_WRT * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to * FLASH:FSEQPMP.VIN_AT_X by flash device driver FW when a flash write * operation is initiated. */ #define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_WRT_M 0x07000000 #define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_WRT_S 24 /* Field: [23] STANDBY_MODE_SEL_EXT_WRT * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to * FLASH:CFG.STANDBY_MODE_SEL by flash device driver FW when a flash write * operation is initiated. */ #define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_WRT_M 0x00800000 #define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_WRT_S 23 /* Field: [22:21] STANDBY_PW_SEL_EXT_WRT * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to * FLASH:CFG.STANDBY_PW_SEL by flash device driver FW when a flash write * operation is initiated. */ #define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_WRT_M 0x00600000 #define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_WRT_S 21 /* Field: [20] DIS_STANDBY_EXT_WRT * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to * FLASH:CFG.DIS_STANDBY by flash device driver FW when a flash write operation * is initiated. */ #define FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_EXT_WRT_M 0x00100000 /* Field: [19] DIS_IDLE_EXT_WRT * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to * FLASH:CFG.DIS_IDLE by flash device driver FW when a flash write operation is * initiated. */ #define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_WRT_M 0x00080000 #define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_WRT_S 19 /* Field: [18:16] VIN_AT_X_EXT_WRT * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to * FLASH:FSEQPMP.VIN_AT_X by flash device driver FW when a flash write * operation is initiated. */ #define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_WRT_M 0x00070000 #define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_WRT_S 16 /* Field: [15] STANDBY_MODE_SEL_INT_RD * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to * FLASH:CFG.STANDBY_MODE_SEL both by boot FW while in safezone, and by flash * device driver FW after completion of a flash write operation. */ #define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_RD_M 0x00008000 #define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_RD_S 15 /* Field: [14:13] STANDBY_PW_SEL_INT_RD * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to * FLASH:CFG.STANDBY_PW_SEL both by boot FW while in safezone, and by flash * device driver FW after completion of a flash write operation. */ #define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_RD_M 0x00006000 #define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_RD_S 13 /* Field: [12] DIS_STANDBY_INT_RD * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to * FLASH:CFG.DIS_STANDBY both by boot FW while in safezone, and by flash device * driver FW after completion of a flash write operation. */ #define FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_INT_RD_M 0x00001000 /* Field: [11] DIS_IDLE_INT_RD * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to * FLASH:CFG.DIS_IDLE both by boot FW while in safezone, and by flash device * driver FW after completion of a flash write operation. */ #define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_RD_M 0x00000800 #define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_RD_S 11 /* Field: [10:8] VIN_AT_X_INT_RD * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 0, this value will be written to * FLASH:FSEQPMP.VIN_AT_X both by boot FW while in safezone, and by flash * device driver FW after completion of a flash write operation. */ #define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_RD_M 0x00000700 #define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_RD_S 8 /* Field: [7] STANDBY_MODE_SEL_EXT_RD * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to * FLASH:CFG.STANDBY_MODE_SEL both by boot FW while in safezone, and by flash * device driver FW after completion of a flash write operation. */ #define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_RD_M 0x00000080 #define FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_RD_S 7 /* Field: [6:5] STANDBY_PW_SEL_EXT_RD * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to * FLASH:CFG.STANDBY_PW_SEL both by boot FW while in safezone, and by flash * device driver FW after completion of a flash write operation. */ #define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_RD_M 0x00000060 #define FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_RD_S 5 /* Field: [4] DIS_STANDBY_EXT_RD * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to * FLASH:CFG.DIS_STANDBY both by boot FW while in safezone, and by flash device * driver FW after completion of a flash write operation. */ #define FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_EXT_RD_M 0x00000010 /* Field: [3] DIS_IDLE_EXT_RD * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to * FLASH:CFG.DIS_IDLE both by boot FW while in safezone, and by flash device * driver FW after completion of a flash write operation. */ #define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_RD_M 0x00000008 #define FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_RD_S 3 /* Field: [2:0] VIN_AT_X_EXT_RD * * If AON_PMCTL:PWRCTL.EXT_REG_MODE = 1, this value will be written to * FLASH:FSEQPMP.VIN_AT_X both by boot FW while in safezone, and by flash * device driver FW after completion of a flash write operation. */ #define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_RD_M 0x00000007 #define FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_RD_S 0 /****************************************************************************** * * This section defines the register offsets of AON_PMCTL component * ******************************************************************************/ /* Power Management Control */ #if defined(DEVICE_CC26X2) /* Agama (CC26x2) specific definition */ #define AON_PMCTL_O_PWRCTL 0x00000010 #elif defined(DEVICE_CC26X0) /* Chameleon (CC26x0) specific definition */ #define AON_PMCTL_O_PWRCTL 0x00000000 #endif /* Field: [1] EXT_REG_MODE * * Status of source for VDDRsupply: * * 0: DCDC or GLDO are generating VDDR * 1: DCDC and GLDO are bypassed and an external regulator supplies VDDR */ #define AON_PMCTL_PWRCTL_EXT_REG_MODE 0x00000002 #endif /* #ifndef OPENOCD_LOADERS_FLASH_CC26XX_HW_REGS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/cc26xx/main.c ================================================ // SPDX-License-Identifier: BSD-3-Clause /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #include #include #include "flashloader.h" /* Data buffers used by host to communicate with flashloader */ /* Flashloader parameter structure. */ __attribute__ ((section(".buffers.g_cfg"))) volatile struct flash_params g_cfg[2]; /* Data buffer 1. */ __attribute__ ((section(".buffers.g_buf1"))) uint8_t g_buf1[BUFFER_LEN]; /* Data buffer 2. */ __attribute__ ((section(".buffers.g_buf2"))) uint8_t g_buf2[BUFFER_LEN]; /* Buffer used for program with retain feature */ __attribute__ ((section(".buffers.g_retain_buf"))) uint8_t g_retain_buf[BUFFER_LEN]; uint32_t g_curr_buf; /* Current buffer used. */ uint32_t g_vims_ctl; /* Saved flash cache state. */ /****************************************************************************** * * This function stores the current VIMS configuration before * - disabling VIMS flash cache * - flushing the flash line buffers. * * Note Not using driverlib calls because it requires using "NO_ROM" define in * order to work for both Cha. R1 and R2 using the same code. Manually * doing the steps to minimize code footprint. * ******************************************************************************/ static void disable_flash_cache() { /* 1. Make sure VIMS is not currently changing mode (VIMS:STAT register) */ while ((HWREG(0x40034000) & 0x00000008) == 0x8) ; /* Save current VIMS:CTL state */ g_vims_ctl = HWREG(0x40034004); /* 2. Set VIMS mode to OFF and disable flash line buffers */ uint32_t new_vims_ctl = g_vims_ctl | 0x33; HWREG(0x40034004) = new_vims_ctl; /* 3. Wait for VIMS to have changed mode (VIMS:STAT register) */ while ((HWREG(0x40034000) & 0x00000008) == 0x8) ; } /****************************************************************************** * * This function restores the VIMS configuration saved off by * disable_flash_cache(). * * Note Not using driverlib calls because it requires using "NO_ROM" define in * order to work for both Cha. R1 and R2 using the same code. Manually * doing the steps to minimize code footprint. * ******************************************************************************/ static void restore_cache_state() { HWREG(0x40034004) = g_vims_ctl; /* Wait for VIMS to have changed mode (VIMS:STAT register) */ while ((HWREG(0x40034000) & 0x00000008) == 0x8) ; } /****************************************************************************** * * CC13xx/CC26xx flashloader main function. * ******************************************************************************/ int main(void) { flashloader_init((struct flash_params *)g_cfg, g_buf1, g_buf2); g_curr_buf = 0; /* start with the first buffer */ uint32_t status; while (1) { /* Wait for host to signal buffer is ready */ while (g_cfg[g_curr_buf].full == BUFFER_EMPTY) ; disable_flash_cache(); /* Perform requested task */ switch (g_cfg[g_curr_buf].cmd) { case CMD_ERASE_ALL: status = flashloader_erase_all(); break; case CMD_PROGRAM: status = flashloader_program( (uint8_t *)g_cfg[g_curr_buf].buf_addr, g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); break; case CMD_ERASE_AND_PROGRAM: status = flashloader_erase_and_program( (uint8_t *)g_cfg[g_curr_buf].buf_addr, g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); break; case CMD_ERASE_AND_PROGRAM_WITH_RETAIN: status = flashloader_program_with_retain( (uint8_t *)g_cfg[g_curr_buf].buf_addr, g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); break; case CMD_ERASE_SECTORS: status = flashloader_erase_sectors(g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); break; default: status = STATUS_FAILED_UNKNOWN_COMMAND; break; } restore_cache_state(); /* Enter infinite loop on error condition */ if (status != STATUS_OK) { g_cfg[g_curr_buf].full = status; while (1) ; } /* Mark current task complete, and begin looking at next buffer */ g_cfg[g_curr_buf].full = BUFFER_EMPTY; g_curr_buf ^= 1; } } void _exit(int status) { /* Enter infinite loop on hitting an exit condition */ (void)status; /* Unused parameter */ while (1) ; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/cc26xx/startup.c ================================================ // SPDX-License-Identifier: BSD-3-Clause /****************************************************************************** * * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #include /****************************************************************************** * * The entry point for the application startup code. * ******************************************************************************/ extern int main(void); /****************************************************************************** * * Reserve space for the system stack. * ******************************************************************************/ __attribute__ ((section(".stack"))) static uint32_t stack[100]; const uint32_t stack_pntr = (uint32_t)stack + sizeof(stack); /****************************************************************************** * * The following are constructs created by the linker indicating where * the "bss" and "ebss" segments reside in memory. * ******************************************************************************/ extern uint32_t _bss; extern uint32_t _ebss; /****************************************************************************** * * This is the entry point that handles setting the stack within the allowed * workspace, initializing the .bss segment, and then jumping to main. * ******************************************************************************/ __attribute__ ((section(".entry"))) void entry(void) { /* Workaround for ITT instructions. */ __asm(" NOP"); __asm(" NOP"); __asm(" NOP"); __asm(" NOP"); /* Initialize stack pointer */ __asm(" ldr sp, =stack_pntr"); /* Zero fill the bss segment. */ __asm(" ldr r0, =_bss\n" " ldr r1, =_ebss\n" " mov r2, #0\n" " .thumb_func\n" " zero_loop:\n" " cmp r0, r1\n" " it lt\n" " strlt r2, [r0], #4\n" " blt zero_loop"); /* Call the application's entry point. */ main(); /* If we ever return, enter an infinite loop */ while (1) ; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/cc3220sf/cc3220sf.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0xdf,0xf8,0x7c,0xa0,0xdf,0xf8,0x7c,0xb0,0xdf,0xf8,0x7c,0xc0,0x01,0xf0,0x7f,0x03, 0x00,0x2b,0x1e,0xd1,0x4f,0xf0,0x00,0x04,0xcc,0xf8,0x00,0x10,0x03,0x68,0xcb,0xf8, 0x00,0x30,0x0b,0xf1,0x04,0x0b,0x00,0xf1,0x04,0x00,0xa2,0xf1,0x01,0x02,0x04,0xf1, 0x01,0x04,0x01,0xf1,0x04,0x01,0x00,0x2a,0x01,0xd0,0x20,0x2c,0xee,0xd1,0xcc,0xf8, 0x20,0xa0,0xdc,0xf8,0x20,0x30,0x13,0xf0,0x01,0x0f,0xfa,0xd1,0x00,0x2a,0xd7,0xd1, 0x13,0xe0,0xcc,0xf8,0x00,0x10,0x03,0x68,0xcc,0xf8,0x04,0x30,0xcc,0xf8,0x08,0xa0, 0xdc,0xf8,0x08,0x30,0x13,0xf0,0x01,0x0f,0xfa,0xd1,0xa2,0xf1,0x01,0x02,0x00,0xf1, 0x04,0x00,0x01,0xf1,0x04,0x01,0x00,0x2a,0xc2,0xd1,0x00,0xbe,0x01,0xbe,0xfc,0xe7, 0x01,0x00,0x42,0xa4,0x00,0xd1,0x0f,0x40,0x00,0xd0,0x0f,0x40, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/cc3220sf/cc3220sf.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2017 by Texas Instruments, Inc. * ***************************************************************************/ /* Params: * r0 = buffer start address (in) * r1 = flash destination address (in) * r2 = number of words to write (in/out) */ .text .cpu cortex-m4 .code 16 .thumb .syntax unified .align 2 /* r3 = scratchpad * r4 = buffer word counter * r10 = flash programming key * r11 = base FWB address * r12 = base flash regs address */ start: ldr r10, =0xa4420001 /* flash programming key */ ldr r11, =0x400fd100 /* base of FWB */ ldr r12, =0x400fd000 /* base of flash regs */ and r3, r1, #0x7f /* is the dest address 32 word aligned? */ cmp r3, #0 bne program_word /* if not aligned do one word at a time */ /* program using the write buffers */ program_buffer: mov r4, #0 /* start the buffer word counter at 0 */ str r1, [r12] /* store the dest addr in FMA */ fill_buffer: ldr r3, [r0] /* get the word to write to FWB */ str r3, [r11] /* store the word in the FWB */ add r11, r11, #4 /* increment the FWB pointer */ add r0, r0, #4 /* increment the source pointer */ sub r2, r2, #1 /* decrement the total word counter */ add r4, r4, #1 /* increment the buffer word counter */ add r1, r1, #4 /* increment the dest pointer */ cmp r2, #0 /* is the total word counter now 0? */ beq buffer_ready /* go to end if total word counter is 0 */ cmp r4, #32 /* is the buffer word counter now 32? */ bne fill_buffer /* go to continue to fill buffer */ buffer_ready: str r10, [r12, #0x20] /* store the key and write bit to FMC2 */ wait_buffer_done: ldr r3, [r12, #0x20] /* read FMC2 */ tst r3, #1 /* see if the write bit is cleared */ bne wait_buffer_done /* go to read FMC2 if bit not cleared */ cmp r2, #0 /* is the total word counter now 0? */ bne start /* go if there is more to program */ b exit /* program just one word */ program_word: str r1, [r12] /* store the dest addr in FMA */ ldr r3, [r0] /* get the word to write to FMD */ str r3, [r12, #0x4] /* store the word in FMD */ str r10, [r12, #0x8] /* store the key and write bit to FMC */ wait_word_done: ldr r3, [r12, #0x8] /* read FMC */ tst r3, #1 /* see if the write bit is cleared */ bne wait_word_done /* go to read FMC if bit not cleared */ sub r2, r2, #1 /* decrement the total word counter */ add r0, r0, #4 /* increment the source pointer */ add r1, r1, #4 /* increment the dest pointer */ cmp r2, #0 /* is the total word counter now 0 */ bne start /* go if there is more to program */ /* end */ exit: bkpt #0 bkpt #1 b exit ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/cortex-m0.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2014 by Angus Gratton * * Derived from stm32f1x.S: * Copyright (C) 2011 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * * Copyright (C) 2013 by Roman Dmitrienko * * me@iamroman.org * ***************************************************************************/ .text .syntax unified .cpu cortex-m0 .thumb .thumb_func /* Written for NRF51822 (src/flash/nor/nrf51.c) however the NRF NVMC is * very generic (CPU blocks during flash writes), so this is actually * just a generic word-oriented copy routine for Cortex-M0 (also * suitable for Cortex-M0+/M3/M4.) * * To assemble: * arm-none-eabi-gcc -c cortex-m0.S * * To disassemble: * arm-none-eabi-objdump -o cortex-m0.o * * Thanks to Jens Bauer for providing advice on some of the tweaks. */ /* Params: * r0 - byte count (in) * r1 - workarea start * r2 - workarea end * r3 - target address * Clobbered: * r4 - rp * r5 - wp, tmp */ wait_fifo: ldr r5, [r1, #0] /* read wp */ cmp r5, #0 /* abort if wp == 0 */ beq exit ldr r4, [r1, #4] /* read rp */ cmp r4, r5 /* wait until rp != wp */ beq wait_fifo ldmia r4!, {r5} /* "*target_address++ = *rp++" */ stmia r3!, {r5} cmp r4, r2 /* wrap rp at end of work area buffer */ bcc no_wrap mov r4, r1 adds r4, #8 /* skip rp,wp at start of work area */ no_wrap: str r4, [r1, #4] /* write back rp */ subs r0, #4 /* decrement byte count */ bne wait_fifo /* loop if not done */ exit: bkpt #0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/efm32.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * * Copyright (C) 2013 by Roman Dmitrienko * * me@iamroman.org * ***************************************************************************/ .text .syntax unified .cpu cortex-m0 .thumb .thumb_func /* Params: * r0 - flash base (in), status (out) * r1 - count (word-32bit) * r2 - workarea start * r3 - workarea end * r4 - target address * Clobbered: * r5 - rp * r6 - wp, tmp * r7 - tmp */ /* offsets of registers from flash reg base */ #define EFM32_MSC_WRITECTRL_OFFSET 0x008 #define EFM32_MSC_WRITECMD_OFFSET 0x00c #define EFM32_MSC_ADDRB_OFFSET 0x010 #define EFM32_MSC_WDATA_OFFSET 0x018 #define EFM32_MSC_STATUS_OFFSET 0x01c /* set WREN to 1 */ movs r6, #1 str r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET] wait_fifo: ldr r6, [r2, #0] /* read wp */ cmp r6, #0 /* abort if wp == 0 */ beq exit ldr r5, [r2, #4] /* read rp */ cmp r5, r6 /* wait until rp != wp */ beq wait_fifo /* store address in MSC_ADDRB */ str r4, [r0, #EFM32_MSC_ADDRB_OFFSET] /* set LADDRIM bit */ movs r6, #1 str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET] /* check status for INVADDR and/or LOCKED */ ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] movs r7, #6 tst r6, r7 bne error /* wait for WDATAREADY */ wait_wdataready: ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] movs r7, #8 tst r6, r7 beq wait_wdataready /* load data to WDATA */ ldr r6, [r5] str r6, [r0, #EFM32_MSC_WDATA_OFFSET] /* set WRITEONCE bit */ movs r6, #8 str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET] adds r5, #4 /* rp++ */ adds r4, #4 /* target_address++ */ /* wait until BUSY flag is reset */ busy: ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] movs r7, #1 tst r6, r7 bne busy cmp r5, r3 /* wrap rp at end of buffer */ bcc no_wrap mov r5, r2 adds r5, #8 no_wrap: str r5, [r2, #4] /* store rp */ subs r1, r1, #1 /* decrement word count */ cmp r1, #0 beq exit /* loop if not done */ b wait_fifo error: movs r0, #0 str r0, [r2, #4] /* set rp = 0 on error */ exit: mov r0, r6 /* return status in r0 */ bkpt #0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/fespi/riscv.lds ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ OUTPUT_ARCH( "riscv" ) SECTIONS { . = 0x12340000; .text : { *(.text.entry) *(.text) } .data : { *(.data) } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/fespi/riscv32_fespi.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x17,0x01,0x00,0x00,0x13,0x01,0xc1,0x31,0xef,0x00,0x80,0x10,0x73,0x00,0x10,0x00, 0x93,0x07,0x90,0x3e,0x93,0x87,0xf7,0xff,0x63,0x96,0x07,0x00,0x13,0x05,0x10,0x00, 0x67,0x80,0x00,0x00,0x03,0x27,0x45,0x07,0x13,0x77,0x17,0x00,0xe3,0x04,0x07,0xfe, 0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00,0x93,0x07,0x90,0x3e,0x93,0x87,0xf7,0xff, 0x63,0x96,0x07,0x00,0x13,0x05,0x10,0x00,0x67,0x80,0x00,0x00,0x03,0x27,0x85,0x04, 0xe3,0x46,0x07,0xfe,0x23,0x24,0xb5,0x04,0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00, 0x83,0x27,0x05,0x04,0x13,0x01,0x41,0xff,0x23,0x22,0x81,0x00,0x23,0x24,0x11,0x00, 0x23,0x20,0x91,0x00,0x93,0xf7,0x77,0xff,0x23,0x20,0xf5,0x04,0x93,0x07,0x20,0x00, 0x23,0x2c,0xf5,0x00,0x93,0x05,0x50,0x00,0x13,0x04,0x05,0x00,0xef,0xf0,0xdf,0xfa, 0x93,0x07,0x90,0x3e,0x63,0x00,0x05,0x02,0x83,0x20,0x81,0x00,0x03,0x24,0x41,0x00, 0x83,0x24,0x01,0x00,0x13,0x01,0xc1,0x00,0x67,0x80,0x00,0x00,0x03,0x27,0xc4,0x04, 0x63,0x5a,0x07,0x00,0x93,0x87,0xf7,0xff,0xe3,0x9a,0x07,0xfe,0x13,0x05,0x10,0x00, 0x6f,0xf0,0x9f,0xfd,0x93,0x04,0x90,0x3e,0x93,0x84,0xf4,0xff,0xe3,0x88,0x04,0xfe, 0x93,0x05,0x00,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xf6,0xe3,0x1e,0x05,0xfa, 0x13,0x07,0x90,0x3e,0x13,0x07,0xf7,0xff,0xe3,0x0a,0x07,0xfc,0x83,0x27,0xc4,0x04, 0xe3,0xca,0x07,0xfe,0x93,0xf7,0x17,0x00,0xe3,0x98,0x07,0xfc,0x23,0x2c,0x04,0x00, 0x83,0x27,0x04,0x04,0x93,0xe7,0x87,0x00,0x23,0x20,0xf4,0x04,0x6f,0xf0,0xdf,0xf8, 0x13,0x01,0x41,0xfd,0x23,0x22,0x81,0x02,0x23,0x20,0x91,0x02,0x23,0x24,0x11,0x02, 0x13,0x04,0x05,0x00,0x23,0x26,0xb1,0x00,0x23,0x28,0xc1,0x00,0x23,0x20,0xd1,0x00, 0x23,0x22,0xe1,0x00,0x23,0x2a,0xf1,0x00,0xef,0xf0,0x9f,0xed,0x93,0x04,0x05,0x00, 0x63,0x16,0x05,0x04,0x83,0x27,0x04,0x06,0x13,0x05,0x04,0x00,0x93,0xf7,0xe7,0xff, 0x23,0x20,0xf4,0x06,0xef,0xf0,0xdf,0xf0,0x93,0x04,0x05,0x00,0x63,0x12,0x05,0x02, 0x83,0x27,0xc1,0x00,0x03,0x27,0x01,0x00,0x93,0x87,0xf7,0xff,0xb3,0xf7,0xe7,0x00, 0x03,0x47,0x41,0x01,0x23,0x2c,0xe1,0x00,0x03,0x27,0x41,0x00,0x63,0x14,0x07,0x02, 0x83,0x27,0x04,0x06,0x93,0xe7,0x17,0x00,0x23,0x20,0xf4,0x06,0x83,0x20,0x81,0x02, 0x03,0x24,0x41,0x02,0x13,0x85,0x04,0x00,0x83,0x24,0x01,0x02,0x13,0x01,0xc1,0x02, 0x67,0x80,0x00,0x00,0x83,0x26,0x41,0x00,0x03,0x27,0x41,0x00,0x23,0x24,0xd1,0x00, 0x83,0x26,0xc1,0x00,0x33,0x07,0xf7,0x00,0x63,0xf6,0xe6,0x00,0xb3,0x87,0xf6,0x40, 0x23,0x24,0xf1,0x00,0x93,0x05,0x60,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0xdf,0xe6, 0x63,0x1e,0x05,0x0c,0x13,0x05,0x04,0x00,0xef,0xf0,0x9f,0xe3,0x63,0x18,0x05,0x0c, 0x83,0x25,0x81,0x01,0x93,0x07,0x20,0x00,0x23,0x2c,0xf4,0x00,0x13,0x05,0x04,0x00, 0xef,0xf0,0x9f,0xe4,0x63,0x1c,0x05,0x0a,0x83,0x27,0x41,0x01,0x93,0xf7,0x07,0x10, 0x63,0x9c,0x07,0x08,0x83,0x27,0x01,0x00,0x13,0x05,0x04,0x00,0x93,0xd5,0x07,0x01, 0x93,0xf5,0xf5,0x0f,0xef,0xf0,0x5f,0xe2,0x63,0x1a,0x05,0x08,0x83,0x27,0x01,0x00, 0x13,0x05,0x04,0x00,0x93,0xd5,0x87,0x00,0x93,0xf5,0xf5,0x0f,0xef,0xf0,0xdf,0xe0, 0x63,0x1e,0x05,0x06,0x83,0x45,0x01,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0xdf,0xdf, 0x63,0x16,0x05,0x06,0x03,0x26,0x01,0x01,0x83,0x27,0x81,0x00,0xb3,0x07,0xf6,0x00, 0x63,0x12,0xf6,0x06,0x13,0x05,0x04,0x00,0x23,0x28,0xc1,0x00,0xef,0xf0,0x5f,0xdb, 0x63,0x16,0x05,0x04,0x23,0x2c,0x04,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x5f,0xdf, 0x63,0x1e,0x05,0x02,0x83,0x27,0x01,0x00,0x03,0x27,0x81,0x00,0xb3,0x87,0xe7,0x00, 0x23,0x20,0xf1,0x00,0x83,0x27,0x41,0x00,0xb3,0x87,0xe7,0x40,0x23,0x22,0xf1,0x00, 0x93,0x07,0x00,0x00,0x6f,0xf0,0x5f,0xee,0x83,0x27,0x01,0x00,0x13,0x05,0x04,0x00, 0x93,0xd5,0x87,0x01,0xef,0xf0,0x5f,0xd9,0xe3,0x0e,0x05,0xf4,0x93,0x04,0x05,0x00, 0x6f,0xf0,0x1f,0xed,0x83,0x45,0x06,0x00,0x13,0x05,0x04,0x00,0x23,0x2e,0xf1,0x00, 0x23,0x28,0xc1,0x00,0xef,0xf0,0x5f,0xd7,0x03,0x26,0x01,0x01,0x83,0x27,0xc1,0x01, 0x13,0x06,0x16,0x00,0xe3,0x0e,0x05,0xf6,0x6f,0xf0,0x5f,0xfd,0x09,0x53,0x67,0x08, 0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08, 0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08, 0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08, 0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/fespi/riscv64_fespi.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x17,0x01,0x00,0x00,0x13,0x01,0x81,0x38,0xef,0x00,0x40,0x12,0x73,0x00,0x10,0x00, 0x93,0x07,0x90,0x3e,0x9b,0x87,0xf7,0xff,0x63,0x96,0x07,0x00,0x13,0x05,0x10,0x00, 0x67,0x80,0x00,0x00,0x03,0x27,0x45,0x07,0x13,0x77,0x17,0x00,0xe3,0x04,0x07,0xfe, 0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00,0x93,0x07,0x90,0x3e,0x9b,0x87,0xf7,0xff, 0x63,0x96,0x07,0x00,0x13,0x05,0x10,0x00,0x67,0x80,0x00,0x00,0x03,0x27,0x85,0x04, 0x93,0x16,0x07,0x02,0xe3,0xc4,0x06,0xfe,0x9b,0x85,0x05,0x00,0x23,0x24,0xb5,0x04, 0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00,0x83,0x27,0x05,0x04,0x13,0x01,0x01,0xfe, 0x23,0x38,0x81,0x00,0x9b,0x87,0x07,0x00,0x23,0x3c,0x11,0x00,0x23,0x34,0x91,0x00, 0x93,0xf7,0x77,0xff,0x23,0x20,0xf5,0x04,0x93,0x07,0x20,0x00,0x23,0x2c,0xf5,0x00, 0x93,0x05,0x50,0x00,0x13,0x04,0x05,0x00,0xef,0xf0,0x1f,0xfa,0x93,0x07,0x90,0x3e, 0x63,0x02,0x05,0x02,0x83,0x30,0x81,0x01,0x03,0x34,0x01,0x01,0x83,0x34,0x81,0x00, 0x13,0x01,0x01,0x02,0x67,0x80,0x00,0x00,0x03,0x27,0xc4,0x04,0x93,0x16,0x07,0x02, 0x63,0xda,0x06,0x00,0x9b,0x87,0xf7,0xff,0xe3,0x98,0x07,0xfe,0x13,0x05,0x10,0x00, 0x6f,0xf0,0x5f,0xfd,0x93,0x04,0x90,0x3e,0x9b,0x84,0xf4,0xff,0xe3,0x88,0x04,0xfe, 0x93,0x05,0x00,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xf5,0xe3,0x1c,0x05,0xfa, 0x93,0x07,0x90,0x3e,0x9b,0x87,0xf7,0xff,0xe3,0x8a,0x07,0xfc,0x83,0x26,0xc4,0x04, 0x13,0x96,0x06,0x02,0x1b,0x87,0x06,0x00,0xe3,0x46,0x06,0xfe,0x93,0x77,0x17,0x00, 0xe3,0x94,0x07,0xfc,0x23,0x2c,0x04,0x00,0x83,0x27,0x04,0x04,0x9b,0x87,0x07,0x00, 0x93,0xe7,0x87,0x00,0x23,0x20,0xf4,0x04,0x6f,0xf0,0xdf,0xf7,0x13,0x01,0x01,0xfa, 0x23,0x38,0x81,0x04,0x23,0x34,0x91,0x04,0x23,0x30,0x21,0x05,0x23,0x3c,0x31,0x03, 0x23,0x38,0x41,0x03,0x23,0x34,0x51,0x03,0x23,0x30,0x61,0x03,0x23,0x3c,0x11,0x04, 0x23,0x3c,0x71,0x01,0x23,0x38,0x81,0x01,0x23,0x34,0x91,0x01,0x23,0x30,0xa1,0x01, 0x13,0x04,0x05,0x00,0x93,0x8a,0x05,0x00,0x13,0x0b,0x06,0x00,0x13,0x89,0x06,0x00, 0x13,0x0a,0x07,0x00,0x93,0x89,0x07,0x00,0xef,0xf0,0x9f,0xe9,0x93,0x04,0x05,0x00, 0x63,0x1a,0x05,0x04,0x83,0x27,0x04,0x06,0x13,0x05,0x04,0x00,0x9b,0x87,0x07,0x00, 0x93,0xf7,0xe7,0xff,0x23,0x20,0xf4,0x06,0xef,0xf0,0x1f,0xed,0x93,0x04,0x05,0x00, 0x63,0x12,0x05,0x02,0x9b,0x86,0xfa,0xff,0xb3,0x76,0xd9,0x00,0x93,0xfc,0xf9,0x0f, 0x93,0xf9,0x09,0x10,0x9b,0x86,0x06,0x00,0x13,0x0c,0x20,0x00,0x9b,0x89,0x09,0x00, 0x63,0x18,0x0a,0x04,0x83,0x27,0x04,0x06,0x9b,0x87,0x07,0x00,0x93,0xe7,0x17,0x00, 0x23,0x20,0xf4,0x06,0x83,0x30,0x81,0x05,0x03,0x34,0x01,0x05,0x03,0x39,0x01,0x04, 0x83,0x39,0x81,0x03,0x03,0x3a,0x01,0x03,0x83,0x3a,0x81,0x02,0x03,0x3b,0x01,0x02, 0x83,0x3b,0x81,0x01,0x03,0x3c,0x01,0x01,0x83,0x3c,0x81,0x00,0x03,0x3d,0x01,0x00, 0x13,0x85,0x04,0x00,0x83,0x34,0x81,0x04,0x13,0x01,0x01,0x06,0x67,0x80,0x00,0x00, 0xbb,0x07,0xda,0x00,0x93,0x0b,0x0a,0x00,0x63,0xf4,0xfa,0x00,0xbb,0x8b,0xda,0x40, 0x93,0x05,0x60,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xe1,0x63,0x1a,0x05,0x0a, 0x13,0x05,0x04,0x00,0xef,0xf0,0xdf,0xdd,0x63,0x14,0x05,0x0a,0x23,0x2c,0x84,0x01, 0x93,0x85,0x0c,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xdf,0x63,0x1a,0x05,0x08, 0x63,0x90,0x09,0x08,0x9b,0x55,0x09,0x01,0x93,0xf5,0xf5,0x0f,0x13,0x05,0x04,0x00, 0xef,0xf0,0x9f,0xdd,0x63,0x1e,0x05,0x06,0x9b,0x55,0x89,0x00,0x93,0xf5,0xf5,0x0f, 0x13,0x05,0x04,0x00,0xef,0xf0,0x5f,0xdc,0x63,0x14,0x05,0x06,0x93,0x75,0xf9,0x0f, 0x13,0x05,0x04,0x00,0xef,0xf0,0x5f,0xdb,0x63,0x1c,0x05,0x04,0x13,0x0d,0x00,0x00, 0x9b,0x07,0x0d,0x00,0x63,0xea,0x77,0x05,0x13,0x05,0x04,0x00,0xef,0xf0,0x5f,0xd7, 0x63,0x10,0x05,0x04,0x23,0x2c,0x04,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0xdf,0xdb, 0x63,0x18,0x05,0x02,0x93,0x97,0x0b,0x02,0x93,0xd7,0x07,0x02,0x33,0x0b,0xfb,0x00, 0x3b,0x09,0x79,0x01,0x3b,0x0a,0x7a,0x41,0x93,0x06,0x00,0x00,0x6f,0xf0,0x5f,0xef, 0x9b,0x55,0x89,0x01,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xd6,0xe3,0x0c,0x05,0xf6, 0x93,0x04,0x05,0x00,0x6f,0xf0,0x1f,0xee,0xb3,0x07,0xab,0x01,0x83,0xc5,0x07,0x00, 0x13,0x05,0x04,0x00,0x13,0x0d,0x1d,0x00,0xef,0xf0,0x1f,0xd4,0xe3,0x0a,0x05,0xf8, 0x6f,0xf0,0x1f,0xfe,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, 0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, 0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, 0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, 0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, 0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, 0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, 0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, 0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/fespi/riscv_fespi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include "../../../../src/flash/nor/spi.h" /* Register offsets */ #define FESPI_REG_SCKDIV 0x00 #define FESPI_REG_SCKMODE 0x04 #define FESPI_REG_CSID 0x10 #define FESPI_REG_CSDEF 0x14 #define FESPI_REG_CSMODE 0x18 #define FESPI_REG_DCSSCK 0x28 #define FESPI_REG_DSCKCS 0x2a #define FESPI_REG_DINTERCS 0x2c #define FESPI_REG_DINTERXFR 0x2e #define FESPI_REG_FMT 0x40 #define FESPI_REG_TXFIFO 0x48 #define FESPI_REG_RXFIFO 0x4c #define FESPI_REG_TXCTRL 0x50 #define FESPI_REG_RXCTRL 0x54 #define FESPI_REG_FCTRL 0x60 #define FESPI_REG_FFMT 0x64 #define FESPI_REG_IE 0x70 #define FESPI_REG_IP 0x74 /* Fields */ #define FESPI_SCK_POL 0x1 #define FESPI_SCK_PHA 0x2 #define FESPI_FMT_PROTO(x) ((x) & 0x3) #define FESPI_FMT_ENDIAN(x) (((x) & 0x1) << 2) #define FESPI_FMT_DIR(x) (((x) & 0x1) << 3) #define FESPI_FMT_LEN(x) (((x) & 0xf) << 16) /* TXCTRL register */ #define FESPI_TXWM(x) ((x) & 0xffff) /* RXCTRL register */ #define FESPI_RXWM(x) ((x) & 0xffff) #define FESPI_IP_TXWM 0x1 #define FESPI_IP_RXWM 0x2 #define FESPI_FCTRL_EN 0x1 #define FESPI_INSN_CMD_EN 0x1 #define FESPI_INSN_ADDR_LEN(x) (((x) & 0x7) << 1) #define FESPI_INSN_PAD_CNT(x) (((x) & 0xf) << 4) #define FESPI_INSN_CMD_PROTO(x) (((x) & 0x3) << 8) #define FESPI_INSN_ADDR_PROTO(x) (((x) & 0x3) << 10) #define FESPI_INSN_DATA_PROTO(x) (((x) & 0x3) << 12) #define FESPI_INSN_CMD_CODE(x) (((x) & 0xff) << 16) #define FESPI_INSN_PAD_CODE(x) (((x) & 0xff) << 24) /* Values */ #define FESPI_CSMODE_AUTO 0 #define FESPI_CSMODE_HOLD 2 #define FESPI_CSMODE_OFF 3 #define FESPI_DIR_RX 0 #define FESPI_DIR_TX 1 #define FESPI_PROTO_S 0 #define FESPI_PROTO_D 1 #define FESPI_PROTO_Q 2 #define FESPI_ENDIAN_MSB 0 #define FESPI_ENDIAN_LSB 1 /* Timeouts we use, in number of status checks. */ #define TIMEOUT 1000 /* #define DEBUG to make the return error codes provide enough information to * reconstruct the stack from where the error occurred. This is not enabled * usually to reduce the program size. */ #ifdef DEBUG #define ERROR_STACK(x) (x) #define ERROR_FESPI_TXWM_WAIT 0x10 #define ERROR_FESPI_TX 0x100 #define ERROR_FESPI_RX 0x1000 #define ERROR_FESPI_WIP 0x50000 #else #define ERROR_STACK(x) 0 #define ERROR_FESPI_TXWM_WAIT 1 #define ERROR_FESPI_TX 1 #define ERROR_FESPI_RX 1 #define ERROR_FESPI_WIP 1 #endif #define ERROR_OK 0 static int fespi_txwm_wait(volatile uint32_t *ctrl_base); static void fespi_disable_hw_mode(volatile uint32_t *ctrl_base); static void fespi_enable_hw_mode(volatile uint32_t *ctrl_base); static int fespi_wip(volatile uint32_t *ctrl_base); static int fespi_write_buffer(volatile uint32_t *ctrl_base, const uint8_t *buffer, unsigned offset, unsigned len, uint32_t flash_info); /* Can set bits 3:0 in result. */ /* flash_info contains: * bits 7:0 -- pprog_cmd * bit 8 -- 0 means send 3 bytes after pprog_cmd, 1 means send 4 bytes * after pprog_cmd */ int flash_fespi(volatile uint32_t *ctrl_base, uint32_t page_size, const uint8_t *buffer, unsigned offset, uint32_t count, uint32_t flash_info) { int result; result = fespi_txwm_wait(ctrl_base); if (result != ERROR_OK) return result | ERROR_STACK(0x1); /* Disable Hardware accesses*/ fespi_disable_hw_mode(ctrl_base); /* poll WIP */ result = fespi_wip(ctrl_base); if (result != ERROR_OK) { result |= ERROR_STACK(0x2); goto err; } /* Assume page_size is a power of two so we don't need the modulus code. */ uint32_t page_offset = offset & (page_size - 1); /* central part, aligned words */ while (count > 0) { uint32_t cur_count; /* clip block at page boundary */ if (page_offset + count > page_size) cur_count = page_size - page_offset; else cur_count = count; result = fespi_write_buffer(ctrl_base, buffer, offset, cur_count, flash_info); if (result != ERROR_OK) { result |= ERROR_STACK(0x3); goto err; } page_offset = 0; buffer += cur_count; offset += cur_count; count -= cur_count; } err: /* Switch to HW mode before return to prompt */ fespi_enable_hw_mode(ctrl_base); return result; } static uint32_t fespi_read_reg(volatile uint32_t *ctrl_base, unsigned address) { return ctrl_base[address / 4]; } static void fespi_write_reg(volatile uint32_t *ctrl_base, unsigned address, uint32_t value) { ctrl_base[address / 4] = value; } static void fespi_disable_hw_mode(volatile uint32_t *ctrl_base) { uint32_t fctrl = fespi_read_reg(ctrl_base, FESPI_REG_FCTRL); fespi_write_reg(ctrl_base, FESPI_REG_FCTRL, fctrl & ~FESPI_FCTRL_EN); } static void fespi_enable_hw_mode(volatile uint32_t *ctrl_base) { uint32_t fctrl = fespi_read_reg(ctrl_base, FESPI_REG_FCTRL); fespi_write_reg(ctrl_base, FESPI_REG_FCTRL, fctrl | FESPI_FCTRL_EN); } /* Can set bits 7:4 in result. */ static int fespi_txwm_wait(volatile uint32_t *ctrl_base) { unsigned timeout = TIMEOUT; while (timeout--) { uint32_t ip = fespi_read_reg(ctrl_base, FESPI_REG_IP); if (ip & FESPI_IP_TXWM) return ERROR_OK; } return ERROR_FESPI_TXWM_WAIT; } static void fespi_set_dir(volatile uint32_t *ctrl_base, bool dir) { uint32_t fmt = fespi_read_reg(ctrl_base, FESPI_REG_FMT); fespi_write_reg(ctrl_base, FESPI_REG_FMT, (fmt & ~(FESPI_FMT_DIR(0xFFFFFFFF))) | FESPI_FMT_DIR(dir)); } /* Can set bits 11:8 in result. */ static int fespi_tx(volatile uint32_t *ctrl_base, uint8_t in) { unsigned timeout = TIMEOUT; while (timeout--) { uint32_t txfifo = fespi_read_reg(ctrl_base, FESPI_REG_TXFIFO); if (!(txfifo >> 31)) { fespi_write_reg(ctrl_base, FESPI_REG_TXFIFO, in); return ERROR_OK; } } return ERROR_FESPI_TX; } /* Can set bits 15:12 in result. */ static int fespi_rx(volatile uint32_t *ctrl_base, uint8_t *out) { unsigned timeout = TIMEOUT; while (timeout--) { uint32_t value = fespi_read_reg(ctrl_base, FESPI_REG_RXFIFO); if (!(value >> 31)) { if (out) *out = value & 0xff; return ERROR_OK; } } return ERROR_FESPI_RX; } /* Can set bits 19:16 in result. */ static int fespi_wip(volatile uint32_t *ctrl_base) { fespi_set_dir(ctrl_base, FESPI_DIR_RX); fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD); int result = fespi_tx(ctrl_base, SPIFLASH_READ_STATUS); if (result != ERROR_OK) return result | ERROR_STACK(0x10000); result = fespi_rx(ctrl_base, NULL); if (result != ERROR_OK) return result | ERROR_STACK(0x20000); unsigned timeout = TIMEOUT; while (timeout--) { result = fespi_tx(ctrl_base, 0); if (result != ERROR_OK) return result | ERROR_STACK(0x30000); uint8_t rx; result = fespi_rx(ctrl_base, &rx); if (result != ERROR_OK) return result | ERROR_STACK(0x40000); if ((rx & SPIFLASH_BSY_BIT) == 0) { fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO); fespi_set_dir(ctrl_base, FESPI_DIR_TX); return ERROR_OK; } } return ERROR_FESPI_WIP; } /* Can set bits 23:20 in result. */ static int fespi_write_buffer(volatile uint32_t *ctrl_base, const uint8_t *buffer, unsigned offset, unsigned len, uint32_t flash_info) { int result = fespi_tx(ctrl_base, SPIFLASH_WRITE_ENABLE); if (result != ERROR_OK) return result | ERROR_STACK(0x100000); result = fespi_txwm_wait(ctrl_base); if (result != ERROR_OK) return result | ERROR_STACK(0x200000); fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD); result = fespi_tx(ctrl_base, flash_info & 0xff); if (result != ERROR_OK) return result | ERROR_STACK(0x300000); if (flash_info & 0x100) { result = fespi_tx(ctrl_base, offset >> 24); if (result != ERROR_OK) return result | ERROR_STACK(0x400000); } result = fespi_tx(ctrl_base, offset >> 16); if (result != ERROR_OK) return result | ERROR_STACK(0x400000); result = fespi_tx(ctrl_base, offset >> 8); if (result != ERROR_OK) return result | ERROR_STACK(0x500000); result = fespi_tx(ctrl_base, offset); if (result != ERROR_OK) return result | ERROR_STACK(0x600000); for (unsigned i = 0; i < len; i++) { result = fespi_tx(ctrl_base, buffer[i]); if (result != ERROR_OK) return result | ERROR_STACK(0x700000); } result = fespi_txwm_wait(ctrl_base); if (result != ERROR_OK) return result | ERROR_STACK(0x800000); fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO); result = fespi_wip(ctrl_base); if (result != ERROR_OK) return result | ERROR_STACK(0x900000); return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/fespi/riscv_wrapper.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #if __riscv_xlen == 64 # define LREG ld # define SREG sd # define REGBYTES 8 #else # define LREG lw # define SREG sw # define REGBYTES 4 #endif .section .text.entry .global _start _start: lla sp, stack_end jal flash_fespi ebreak .section .data .balign REGBYTES stack: .fill 16, REGBYTES, 0x8675309 stack_end: ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/fm4/erase.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Spansion FM4 flash sector erase algorithm * * Copyright (c) 2015 Andreas Färber * * Based on S6E2CC_MN709-00007 for S6E2CC/C5/C4/C3/C2/C1 series */ #include "fm4.h" #define RESULT_OKAY 0 #define RESULT_NONE 1 #define RESULT_TIMEOUT 2 .macro busy_wait, res, addr, tmp1, tmp2, tmp3 ldrb \tmp1, [\addr] /* ignore */ 1001: ldrb \tmp1, [\addr] ldrb \tmp2, [\addr] and \tmp3, \tmp1, #FLASH_TOGG and \tmp2, \tmp2, #FLASH_TOGG cmp \tmp3, \tmp2 beq 1010f and \tmp2, \tmp1, #FLASH_TLOV cmp \tmp2, #0 beq 1001b ldrb \tmp1, [\addr] ldrb \tmp2, [\addr] and \tmp3, \tmp1, #FLASH_TOGG and \tmp2, \tmp2, #FLASH_TOGG cmp \tmp3, \tmp2 beq 1010f mov \res, #RESULT_TIMEOUT bkpt #0 1010: mov \res, #RESULT_OKAY .endm .macro erase, cmdseqaddr1, cmdseqaddr2, sa, res, tmp1, tmp2, tmp3 mov \res, #RESULT_NONE mov \tmp1, #0xAA strh \tmp1, [\cmdseqaddr1] mov \tmp2, #0x55 strh \tmp2, [\cmdseqaddr2] mov \tmp3, #0x80 strh \tmp3, [\cmdseqaddr1] strh \tmp1, [\cmdseqaddr1] strh \tmp2, [\cmdseqaddr2] mov \tmp3, #0x30 strh \tmp3, [\sa] busy_wait \res, \sa, \tmp1, \tmp2, \tmp3 .endm /* r0 = 0xAA8 * r1 = 0x554 * r2 = SA * r3 = result */ erase: erase r0, r1, r2, r3, r4, r5, r6 bkpt #0 data: ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/fm4/erase.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x4f,0xf0,0x01,0x03,0x4f,0xf0,0xaa,0x04,0x04,0x80,0x4f,0xf0,0x55,0x05,0x0d,0x80, 0x4f,0xf0,0x80,0x06,0x06,0x80,0x04,0x80,0x0d,0x80,0x4f,0xf0,0x30,0x06,0x16,0x80, 0x14,0x78,0x14,0x78,0x15,0x78,0x04,0xf0,0x40,0x06,0x05,0xf0,0x40,0x05,0xae,0x42, 0x0e,0xd0,0x04,0xf0,0x20,0x05,0x00,0x2d,0xf3,0xd0,0x14,0x78,0x15,0x78,0x04,0xf0, 0x40,0x06,0x05,0xf0,0x40,0x05,0xae,0x42,0x02,0xd0,0x4f,0xf0,0x02,0x03,0x00,0xbe, 0x4f,0xf0,0x00,0x03,0x00,0xbe, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/fm4/fm4.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Spansion FM4 flash macros * * Copyright (c) 2015 Andreas Färber * * Based on S6E2CC_MN709-00007 for S6E2CC/C5/C4/C3/C2/C1 series */ .text .syntax unified .cpu cortex-m4 .thumb .thumb_func #define FLASH_DPOL (1 << 7) #define FLASH_TOGG (1 << 6) #define FLASH_TLOV (1 << 5) #define FLASH_TOGG2 (1 << 2) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/fm4/write.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Spansion FM4 flash write algorithm * * Copyright (c) 2015 Andreas Färber * * Based on S6E2CC_MN709-00007 for S6E2CC/C5/C4/C3/C2/C1 series */ #include "fm4.h" #define RESULT_OKAY 0 #define RESULT_NONE 1 #define RESULT_TIMEOUT 2 .macro busy_wait, res, addr, data, tmp1, tmp2, tmp3 ldrb \tmp1, [\addr] /* ignore */ and \tmp2, \data, #FLASH_DPOL 1001: ldrb \tmp1, [\addr] and \tmp3, \tmp1, #FLASH_DPOL cmp \tmp3, \tmp2 beq 1010f and \tmp3, \tmp1, #FLASH_TLOV cmp \tmp3, #0 beq 1001b ldrb \tmp1, [\addr] and \tmp3, \tmp1, #FLASH_DPOL cmp \tmp3, \tmp2 beq 1010f mov \res, #RESULT_TIMEOUT bkpt #0 1010: .endm .macro write_one, res, cmdseqaddr1, cmdseqaddr2, pa, pd, tmp1, tmp2, tmp3 mov \tmp1, #0xAA strh \tmp1, [\cmdseqaddr1] mov \tmp1, #0x55 strh \tmp1, [\cmdseqaddr2] mov \tmp1, #0xA0 strh \tmp1, [\cmdseqaddr1] strh \pd, [\pa] busy_wait \res, \pa, \pd, \tmp1, \tmp2, \tmp3 .endm .macro write, cmdseqaddr1, cmdseqaddr2, dest, src, cnt, res, tmp1, tmp2, tmp3, tmp4 mov \res, #RESULT_NONE 2001: cbz \cnt, 2010f ldrh \tmp1, [\src] write_one \res, \cmdseqaddr1, \cmdseqaddr2, \dest, \tmp1, \tmp2, \tmp3, \tmp4 sub \cnt, \cnt, #1 add \dest, \dest, #2 add \src, \src, #2 b 2001b 2010: mov \res, #RESULT_OKAY .endm /* r0 = 0xAA8 * r1 = 0x554 * r2 = dest * r3 = src * r4 = cnt * r5 = result */ write: write r0, r1, r2, r3, r4, r5, r6, r7, r8, r9 bkpt #0 data: ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/fm4/write.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x4f,0xf0,0x01,0x05,0x34,0xb3,0x1e,0x88,0x4f,0xf0,0xaa,0x07,0x07,0x80,0x4f,0xf0, 0x55,0x07,0x0f,0x80,0x4f,0xf0,0xa0,0x07,0x07,0x80,0x16,0x80,0x17,0x78,0x06,0xf0, 0x80,0x08,0x17,0x78,0x07,0xf0,0x80,0x09,0xc1,0x45,0x0c,0xd0,0x07,0xf0,0x20,0x09, 0xb9,0xf1,0x00,0x0f,0xf5,0xd0,0x17,0x78,0x07,0xf0,0x80,0x09,0xc1,0x45,0x02,0xd0, 0x4f,0xf0,0x02,0x05,0x00,0xbe,0xa4,0xf1,0x01,0x04,0x02,0xf1,0x02,0x02,0x03,0xf1, 0x02,0x03,0xd7,0xe7,0x4f,0xf0,0x00,0x05,0x00,0xbe, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/fpga/xilinx_bscan_spi.py ================================================ #!/usr/bin/python3 # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2015 Robert Jordens import unittest import migen as mg import migen.build.generic_platform as mb from migen.genlib import io from migen.build import xilinx """ This migen script produces proxy bitstreams to allow programming SPI flashes behind FPGAs. Bitstream binaries built with this script are available at: https://github.com/jordens/bscan_spi_bitstreams A JTAG2SPI transfer consists of: 1. an arbitrary number of 0 bits (from BYPASS registers in front of the JTAG2SPI DR) 2. a marker bit (1) indicating the start of the JTAG2SPI transaction 3. 32 bits (big endian) describing the length of the SPI transaction 4. a number of SPI clock cycles (corresponding to 3.) with CS_N asserted 5. an arbitrary number of cycles (to shift MISO/TDO data through subsequent BYPASS registers) Notes: * The JTAG2SPI DR is 1 bit long (due to different sampling edges of {MISO,MOSI}/{TDO,TDI}). * MOSI is TDI with half a cycle delay. * TDO is MISO with half a cycle delay. * CAPTURE-DR needs to be performed before SHIFT-DR on the BYPASSed TAPs in JTAG chain to clear the BYPASS registers to 0. https://github.com/m-labs/migen """ class JTAG2SPI(mg.Module): def __init__(self, spi=None, bits=32): self.jtag = mg.Record([ ("sel", 1), ("shift", 1), ("capture", 1), ("tck", 1), ("tdi", 1), ("tdo", 1), ]) self.cs_n = mg.TSTriple() self.clk = mg.TSTriple() self.mosi = mg.TSTriple() self.miso = mg.TSTriple() # # # self.cs_n.o.reset = mg.Constant(1) self.mosi.o.reset_less = True bits = mg.Signal(bits, reset_less=True) head = mg.Signal(max=len(bits), reset=len(bits) - 1) self.clock_domains.cd_sys = mg.ClockDomain() self.submodules.fsm = mg.FSM("IDLE") if spi is not None: self.specials += [ self.cs_n.get_tristate(spi.cs_n), self.mosi.get_tristate(spi.mosi), self.miso.get_tristate(spi.miso), ] if hasattr(spi, "clk"): # 7 Series drive it fixed self.specials += self.clk.get_tristate(spi.clk) # self.specials += io.DDROutput(1, 0, spi.clk, self.clk.o) self.comb += [ self.cd_sys.rst.eq(self.jtag.sel & self.jtag.capture), self.cd_sys.clk.eq(self.jtag.tck), self.cs_n.oe.eq(self.jtag.sel), self.clk.oe.eq(self.jtag.sel), self.mosi.oe.eq(self.jtag.sel), self.miso.oe.eq(0), # Do not suppress CLK toggles outside CS_N asserted. # Xilinx USRCCLK0 requires three dummy cycles to do anything # https://www.xilinx.com/support/answers/52626.html # This is fine since CS_N changes only on falling CLK. self.clk.o.eq(~self.jtag.tck), self.jtag.tdo.eq(self.miso.i), ] # Latency calculation (in half cycles): # 0 (falling TCK, rising CLK): # JTAG adapter: set TDI # 1 (rising TCK, falling CLK): # JTAG2SPI: sample TDI -> set MOSI # SPI: set MISO # 2 (falling TCK, rising CLK): # SPI: sample MOSI # JTAG2SPI (BSCAN primitive): sample MISO -> set TDO # 3 (rising TCK, falling CLK): # JTAG adapter: sample TDO self.fsm.act("IDLE", mg.If(self.jtag.tdi & self.jtag.sel & self.jtag.shift, mg.NextState("HEAD") ) ) self.fsm.act("HEAD", mg.If(head == 0, mg.NextState("XFER") ) ) self.fsm.act("XFER", mg.If(bits == 0, mg.NextState("IDLE") ), ) self.sync += [ self.mosi.o.eq(self.jtag.tdi), self.cs_n.o.eq(~self.fsm.ongoing("XFER")), mg.If(self.fsm.ongoing("HEAD"), bits.eq(mg.Cat(self.jtag.tdi, bits)), head.eq(head - 1) ), mg.If(self.fsm.ongoing("XFER"), bits.eq(bits - 1) ) ] class JTAG2SPITest(unittest.TestCase): def setUp(self): self.bits = 8 self.dut = JTAG2SPI(bits=self.bits) def test_instantiate(self): pass def test_initial_conditions(self): def check(): yield self.assertEqual((yield self.dut.cs_n.oe), 0) self.assertEqual((yield self.dut.mosi.oe), 0) self.assertEqual((yield self.dut.miso.oe), 0) self.assertEqual((yield self.dut.clk.oe), 0) mg.run_simulation(self.dut, check()) def test_enable(self): def check(): yield self.dut.jtag.sel.eq(1) yield self.dut.jtag.shift.eq(1) yield self.assertEqual((yield self.dut.cs_n.oe), 1) self.assertEqual((yield self.dut.mosi.oe), 1) self.assertEqual((yield self.dut.miso.oe), 0) self.assertEqual((yield self.dut.clk.oe), 1) mg.run_simulation(self.dut, check()) def run_seq(self, tdi, tdo, spi=None): yield self.dut.jtag.sel.eq(1) yield yield self.dut.jtag.shift.eq(1) for di in tdi: yield self.dut.jtag.tdi.eq(di) yield tdo.append((yield self.dut.jtag.tdo)) if spi is not None: v = [] for k in "cs_n clk mosi miso".split(): t = getattr(self.dut, k) v.append("{}>".format((yield t.o)) if (yield t.oe) else "<{}".format((yield t.i))) spi.append(" ".join(v)) yield self.dut.jtag.sel.eq(0) yield yield self.dut.jtag.shift.eq(0) yield def test_shift(self): bits = 8 data = 0x81 tdi = [0, 0, 1] # dummy from BYPASS TAPs and marker tdi += [((bits - 1) >> j) & 1 for j in range(self.bits - 1, -1, -1)] tdi += [(data >> j) & 1 for j in range(bits)] tdi += [0, 0, 0, 0] # dummy from BYPASS TAPs tdo = [] spi = [] mg.run_simulation(self.dut, self.run_seq(tdi, tdo, spi)) # print(tdo) for l in spi: print(l) class Spartan3(mg.Module): macro = "BSCAN_SPARTAN3" toolchain = "ise" def __init__(self, platform): platform.toolchain.bitgen_opt += " -g compress -g UnusedPin:Pullup" self.submodules.j2s = j2s = JTAG2SPI(platform.request("spiflash")) self.specials += [ mg.Instance( self.macro, o_SHIFT=j2s.jtag.shift, o_SEL1=j2s.jtag.sel, o_CAPTURE=j2s.jtag.capture, o_DRCK1=j2s.jtag.tck, o_TDI=j2s.jtag.tdi, i_TDO1=j2s.jtag.tdo, i_TDO2=0), ] platform.add_period_constraint(j2s.jtag.tck, 6) class Spartan3A(Spartan3): macro = "BSCAN_SPARTAN3A" class Spartan6(mg.Module): toolchain = "ise" def __init__(self, platform): platform.toolchain.bitgen_opt += " -g compress -g UnusedPin:Pullup" self.submodules.j2s = j2s = JTAG2SPI(platform.request("spiflash")) # clk = mg.Signal() self.specials += [ mg.Instance( "BSCAN_SPARTAN6", p_JTAG_CHAIN=1, o_SHIFT=j2s.jtag.shift, o_SEL=j2s.jtag.sel, o_CAPTURE=j2s.jtag.capture, o_DRCK=j2s.jtag.tck, o_TDI=j2s.jtag.tdi, i_TDO=j2s.jtag.tdo), # mg.Instance("BUFG", i_I=clk, o_O=j2s.jtag.tck) ] platform.add_period_constraint(j2s.jtag.tck, 6) class Series7(mg.Module): toolchain = "vivado" def __init__(self, platform): platform.toolchain.bitstream_commands.extend([ "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]", "set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design]" ]) self.submodules.j2s = j2s = JTAG2SPI(platform.request("spiflash")) # clk = mg.Signal() self.specials += [ mg.Instance( "BSCANE2", p_JTAG_CHAIN=1, o_SHIFT=j2s.jtag.shift, o_SEL=j2s.jtag.sel, o_CAPTURE=j2s.jtag.capture, o_DRCK=j2s.jtag.tck, o_TDI=j2s.jtag.tdi, i_TDO=j2s.jtag.tdo), mg.Instance( "STARTUPE2", i_CLK=0, i_GSR=0, i_GTS=0, i_KEYCLEARB=0, i_PACK=1, i_USRCCLKO=j2s.clk.o, i_USRCCLKTS=~j2s.clk.oe, i_USRDONEO=1, i_USRDONETS=1), # mg.Instance("BUFG", i_I=clk, o_O=j2s.jtag.tck) ] platform.add_period_constraint(j2s.jtag.tck, 6) try: self.comb += [ platform.request("user_sma_gpio_p").eq(j2s.cs_n.i), platform.request("user_sma_gpio_n").eq(j2s.clk.o), platform.request("user_sma_clock_p").eq(j2s.mosi.o), platform.request("user_sma_clock_n").eq(j2s.miso.i), ] except mb.ConstraintError: pass class Ultrascale(mg.Module): toolchain = "vivado" def __init__(self, platform): platform.toolchain.bitstream_commands.extend([ "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]", "set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design]", ]) self.submodules.j2s0 = j2s0 = JTAG2SPI() self.submodules.j2s1 = j2s1 = JTAG2SPI(platform.request("spiflash")) di = mg.Signal(4) self.comb += mg.Cat(j2s0.mosi.i, j2s0.miso.i).eq(di) self.specials += [ mg.Instance("BSCANE2", p_JTAG_CHAIN=1, o_SHIFT=j2s0.jtag.shift, o_SEL=j2s0.jtag.sel, o_CAPTURE=j2s0.jtag.capture, o_DRCK=j2s0.jtag.tck, o_TDI=j2s0.jtag.tdi, i_TDO=j2s0.jtag.tdo), mg.Instance("BSCANE2", p_JTAG_CHAIN=2, o_SHIFT=j2s1.jtag.shift, o_SEL=j2s1.jtag.sel, o_CAPTURE=j2s1.jtag.capture, o_DRCK=j2s1.jtag.tck, o_TDI=j2s1.jtag.tdi, i_TDO=j2s1.jtag.tdo), mg.Instance("STARTUPE3", i_GSR=0, i_GTS=0, i_KEYCLEARB=0, i_PACK=1, i_USRDONEO=1, i_USRDONETS=1, i_USRCCLKO=mg.Mux(j2s0.clk.oe, j2s0.clk.o, j2s1.clk.o), i_USRCCLKTS=~(j2s0.clk.oe | j2s1.clk.oe), i_FCSBO=j2s0.cs_n.o, i_FCSBTS=~j2s0.cs_n.oe, o_DI=di, i_DO=mg.Cat(j2s0.mosi.o, j2s0.miso.o, 0, 0), i_DTS=mg.Cat(~j2s0.mosi.oe, ~j2s0.miso.oe, 1, 1)) ] platform.add_period_constraint(j2s0.jtag.tck, 6) platform.add_period_constraint(j2s1.jtag.tck, 6) class XilinxBscanSpi(xilinx.XilinxPlatform): packages = { # (package-speedgrade, id): [cs_n, clk, mosi, miso, *pullups] ("cp132", 1): ["M2", "N12", "N2", "N8"], ("fg320", 1): ["U3", "U16", "T4", "N10"], ("fg320", 2): ["V3", "U16", "T11", "V16"], ("fg484", 1): ["Y4", "AA20", "AB14", "AB20"], ("fgg484", 1): ["Y4", "AA20", "AB14", "AB20"], ("fgg400", 1): ["Y2", "Y19", "W12", "W18"], ("ftg256", 1): ["T2", "R14", "P10", "T14"], ("ft256", 1): ["T2", "R14", "P10", "T14"], ("fg400", 1): ["Y2", "Y19", "W12", "W18"], ("cs484", 1): ["U7", "V17", "V13", "W17"], ("qg144-2", 1): ["P38", "P70", "P64", "P65", "P62", "P61"], ("cpg196-2", 1): ["P2", "N13", "P11", "N11", "N10", "P10"], ("cpg236-1", 1): ["K19", None, "D18", "D19", "G18", "F18"], ("csg484-2", 1): ["AB5", "W17", "AB17", "Y17", "V13", "W13"], ("csg324-2", 1): ["V3", "R15", "T13", "R13", "T14", "V14"], ("csg324-1", 1): ["L13", None, "K17", "K18", "L14", "M14"], ("fbg484-1", 1): ["T19", None, "P22", "R22", "P21", "R21"], ("fbg484-1", 2): ["L16", None, "H18", "H19", "G18", "F19"], ("fbg676-1", 1): ["C23", None, "B24", "A25", "B22", "A22"], ("ffg901-1", 1): ["V26", None, "R30", "T30", "R28", "T28"], ("ffg900-1", 1): ["U19", None, "P24", "R25", "R20", "R21"], ("ffg1156-1", 1): ["V30", None, "AA33", "AA34", "Y33", "Y34"], ("ffg1157-1", 1): ["AL33", None, "AN33", "AN34", "AK34", "AL34"], ("ffg1158-1", 1): ["C24", None, "A23", "A24", "B26", "A26"], ("ffg1926-1", 1): ["AK33", None, "AN34", "AN35", "AJ34", "AK34"], ("fhg1761-1", 1): ["AL36", None, "AM36", "AN36", "AJ36", "AJ37"], ("flg1155-1", 1): ["AL28", None, "AE28", "AF28", "AJ29", "AJ30"], ("flg1932-1", 1): ["V32", None, "T33", "R33", "U31", "T31"], ("flg1926-1", 1): ["AK33", None, "AN34", "AN35", "AJ34", "AK34"], ("ffva1156-2-e", 1): ["G26", None, "M20", "L20", "R21", "R22"], ("ffva1156-2-e", "sayma"): ["K21", None, "M20", "L20", "R21", "R22"], } pinouts = { # bitstreams are named by die, package does not matter, speed grade # should not matter. # # chip: (package, id, standard, class) "xc3s100e": ("cp132", 1, "LVCMOS33", Spartan3), "xc3s1200e": ("fg320", 1, "LVCMOS33", Spartan3), "xc3s1400a": ("fg484", 1, "LVCMOS33", Spartan3A), "xc3s1400an": ("fgg484", 1, "LVCMOS33", Spartan3A), "xc3s1600e": ("fg320", 1, "LVCMOS33", Spartan3), "xc3s200a": ("fg320", 2, "LVCMOS33", Spartan3A), "xc3s200an": ("ftg256", 1, "LVCMOS33", Spartan3A), "xc3s250e": ("cp132", 1, "LVCMOS33", Spartan3), "xc3s400a": ("fg320", 2, "LVCMOS33", Spartan3A), "xc3s400an": ("fgg400", 1, "LVCMOS33", Spartan3A), "xc3s500e": ("cp132", 1, "LVCMOS33", Spartan3), "xc3s50a": ("ft256", 1, "LVCMOS33", Spartan3A), "xc3s50an": ("ftg256", 1, "LVCMOS33", Spartan3A), "xc3s700a": ("fg400", 1, "LVCMOS33", Spartan3A), "xc3s700an": ("fgg484", 1, "LVCMOS33", Spartan3A), "xc3sd1800a": ("cs484", 1, "LVCMOS33", Spartan3A), "xc3sd3400a": ("cs484", 1, "LVCMOS33", Spartan3A), "xc6slx100": ("csg484-2", 1, "LVCMOS33", Spartan6), "xc6slx100t": ("csg484-2", 1, "LVCMOS33", Spartan6), "xc6slx150": ("csg484-2", 1, "LVCMOS33", Spartan6), "xc6slx150t": ("csg484-2", 1, "LVCMOS33", Spartan6), "xc6slx16": ("cpg196-2", 1, "LVCMOS33", Spartan6), "xc6slx25": ("csg324-2", 1, "LVCMOS33", Spartan6), "xc6slx25t": ("csg324-2", 1, "LVCMOS33", Spartan6), "xc6slx45": ("csg324-2", 1, "LVCMOS33", Spartan6), "xc6slx45t": ("csg324-2", 1, "LVCMOS33", Spartan6), "xc6slx4": ("cpg196-2", 1, "LVCMOS33", Spartan6), "xc6slx4t": ("qg144-2", 1, "LVCMOS33", Spartan6), "xc6slx75": ("csg484-2", 1, "LVCMOS33", Spartan6), "xc6slx75t": ("csg484-2", 1, "LVCMOS33", Spartan6), "xc6slx9": ("cpg196-2", 1, "LVCMOS33", Spartan6), "xc6slx9t": ("qg144-2", 1, "LVCMOS33", Spartan6), "xc7a100t": ("csg324-1", 1, "LVCMOS25", Series7), "xc7a15t": ("cpg236-1", 1, "LVCMOS25", Series7), "xc7a200t": ("fbg484-1", 1, "LVCMOS25", Series7), "xc7a35t": ("cpg236-1", 1, "LVCMOS25", Series7), "xc7a50t": ("cpg236-1", 1, "LVCMOS25", Series7), "xc7a75t": ("csg324-1", 1, "LVCMOS25", Series7), "xc7k160t": ("fbg484-1", 2, "LVCMOS25", Series7), "xc7k325t": ("fbg676-1", 1, "LVCMOS25", Series7), "xc7k325t-debug": ("ffg900-1", 1, "LVCMOS25", Series7), "xc7k355t": ("ffg901-1", 1, "LVCMOS25", Series7), "xc7k410t": ("fbg676-1", 1, "LVCMOS25", Series7), "xc7k420t": ("ffg1156-1", 1, "LVCMOS25", Series7), "xc7k480t": ("ffg1156-1", 1, "LVCMOS25", Series7), "xc7k70t": ("fbg484-1", 2, "LVCMOS25", Series7), "xc7v2000t": ("fhg1761-1", 1, "LVCMOS18", Series7), "xc7v585t": ("ffg1157-1", 1, "LVCMOS18", Series7), "xc7vh580t": ("flg1155-1", 1, "LVCMOS18", Series7), "xc7vh870t": ("flg1932-1", 1, "LVCMOS18", Series7), "xc7vx1140t": ("flg1926-1", 1, "LVCMOS18", Series7), "xc7vx330t": ("ffg1157-1", 1, "LVCMOS18", Series7), "xc7vx415t": ("ffg1157-1", 1, "LVCMOS18", Series7), "xc7vx485t": ("ffg1157-1", 1, "LVCMOS18", Series7), "xc7vx550t": ("ffg1158-1", 1, "LVCMOS18", Series7), "xc7vx690t": ("ffg1157-1", 1, "LVCMOS18", Series7), "xc7vx980t": ("ffg1926-1", 1, "LVCMOS18", Series7), "xcku040": ("ffva1156-2-e", 1, "LVCMOS18", Ultrascale), "xcku040-sayma": ("ffva1156-2-e", "sayma", "LVCMOS18", Ultrascale), } def __init__(self, device, pins, std, toolchain="ise"): ios = [self.make_spi(0, pins, std, toolchain)] if device == "xc7k325t-ffg900-1": # debug ios += [ ("user_sma_clock_p", 0, mb.Pins("L25"), mb.IOStandard("LVCMOS25")), ("user_sma_clock_n", 0, mb.Pins("K25"), mb.IOStandard("LVCMOS25")), ("user_sma_gpio_p", 0, mb.Pins("Y23"), mb.IOStandard("LVCMOS25")), ("user_sma_gpio_n", 0, mb.Pins("Y24"), mb.IOStandard("LVCMOS25")), ] xilinx.XilinxPlatform.__init__(self, device, ios, toolchain=toolchain) @staticmethod def make_spi(i, pins, std, toolchain): pu = "PULLUP" if toolchain == "ise" else "PULLUP TRUE" pd = "PULLDOWN" if toolchain == "ise" else "PULLDOWN TRUE" cs_n, clk, mosi, miso = pins[:4] io = ["spiflash", i, mb.Subsignal("cs_n", mb.Pins(cs_n), mb.Misc(pu)), mb.Subsignal("mosi", mb.Pins(mosi), mb.Misc(pu)), mb.Subsignal("miso", mb.Pins(miso), mb.Misc(pu)), mb.IOStandard(std), ] if clk: io.append(mb.Subsignal("clk", mb.Pins(clk), mb.Misc(pd))) for i, p in enumerate(pins[4:]): io.append(mb.Subsignal("pullup{}".format(i), mb.Pins(p), mb.Misc(pu))) return io @classmethod def make(cls, target, errors=False): pkg, id, std, Top = cls.pinouts[target] pins = cls.packages[(pkg, id)] device = target.split("-", 1)[0] platform = cls("{}-{}".format(device, pkg), pins, std, Top.toolchain) top = Top(platform) name = "bscan_spi_{}".format(target) try: platform.build(top, build_name=name) except Exception as e: print(("ERROR: xilinx_bscan_spi build failed " "for {}: {}").format(target, e)) if errors: raise if __name__ == "__main__": import argparse import multiprocessing p = argparse.ArgumentParser(description="build bscan_spi bitstreams " "for openocd jtagspi flash driver") p.add_argument("device", nargs="*", default=sorted(list(XilinxBscanSpi.pinouts)), help="build for these devices (default: %(default)s)") p.add_argument("-p", "--parallel", default=1, type=int, help="number of parallel builds (default: %(default)s)") args = p.parse_args() pool = multiprocessing.Pool(args.parallel) pool.map(XilinxBscanSpi.make, args.device, chunksize=1) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/gd32vf103/gd32vf103.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later #include #define FLASH_BSY (1 << 0) #define FLASH_PGERR (1 << 2) #define FLASH_WRPRTERR (1 << 4) void flash_write(volatile uint32_t *flash_sr, uint32_t hwords_count, uint16_t *buffer, uint16_t *target_addr) __attribute__((naked)); void flash_write(volatile uint32_t *flash_sr, uint32_t hwords_count, uint16_t *buffer, uint16_t *target_addr) { do { *target_addr = *buffer++; register uint32_t sr; do { sr = *flash_sr; } while (sr & FLASH_BSY); if (sr & (FLASH_PGERR | FLASH_WRPRTERR)) break; target_addr++; } while (--hwords_count); asm("ebreak"); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/gd32vf103/gd32vf103.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x83,0x57,0x06,0x00,0x13,0x06,0x26,0x00,0x23,0x90,0xf6,0x00,0x83,0x27,0x05,0x00, 0x13,0xf7,0x17,0x00,0xe3,0x1c,0x07,0xfe,0x93,0xf7,0x47,0x01,0x63,0x98,0x07,0x00, 0x93,0x85,0xf5,0xff,0x93,0x86,0x26,0x00,0xe3,0x9c,0x05,0xfc,0x73,0x00,0x10,0x00, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/k1921vk01t.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2015 by Bogdan Kolbov * * kolbov@niiet.ru * ***************************************************************************/ .text .syntax unified .cpu cortex-m4 .thumb .thumb_func /* K1921VK01T has 128-bitwidth flash, so it`s able to load 4x32-bit words at the time. * And only after all words loaded we can start write */ /* Registers addresses */ #define FLASH_FMA 0x00 /* Address reg */ #define FLASH_FMD1 0x04 /* Data1 reg */ #define FLASH_FMC 0x08 /* Command reg */ #define FLASH_FCIS 0x0C /* Operation Status reg */ #define FLASH_FCIC 0x14 /* Operation Status Clear reg */ #define FLASH_FMD2 0x50 /* Data2 reg */ #define FLASH_FMD3 0x54 /* Data3 reg */ #define FLASH_FMD4 0x58 /* Data4 reg*/ /* Params: * r0 - write cmd (in), status (out) * r1 - count * r2 - workarea start * r3 - workarea end * r4 - target address * Clobbered: * r5 - rp * r6 - wp, tmp * r7 - flash base */ ldr r7, =#0xA001C000 /* Flash reg base*/ wait_fifo: ldr r6, [r2, #0] /* read wp */ cmp r6, #0 /* abort if wp == 0 */ beq exit ldr r5, [r2, #4] /* read rp */ cmp r5, r6 /* wait until rp != wp */ beq wait_fifo load_data: ldr r6, [r5] /* read data1 */ str r6, [r7, #FLASH_FMD1] adds r5, #4 ldr r6, [r5] /* read data2 */ str r6, [r7, #FLASH_FMD2] adds r5, #4 ldr r6, [r5] /* read data3 */ str r6, [r7, #FLASH_FMD3] adds r5, #4 ldr r6, [r5] /* read data4 */ str r6, [r7, #FLASH_FMD4] adds r5, #4 start_write: str r4, [r7, #FLASH_FMA] /* set addr */ adds r4, #16 str r0, [r7, #FLASH_FMC] /* write cmd */ busy: ldr r6, [r7, #FLASH_FCIS] /* wait until flag set */ cmp r6, #0x0 beq busy cmp r6, #2 /* check the error bit */ beq error movs r6, #1 /* clear flags */ str r6, [r7, #FLASH_FCIC] cmp r5, r3 /* wrap rp at end of buffer */ bcc no_wrap mov r5, r2 adds r5, #8 no_wrap: str r5, [r2, #4] /* store rp */ subs r1, r1, #1 /* decrement 16-byte block count */ cmp r1, #0 beq exit /* loop if not done */ b wait_fifo error: movs r0, #0 str r0, [r2, #4] /* set rp = 0 on error */ exit: mov r0, r6 /* return status in r0 */ bkpt #0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/kinetis/kinetis_flash.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x16,0x68,0x00,0x2e,0x1f,0xd0,0x55,0x68,0xb5,0x42,0xf9,0xd0,0x60,0x60,0x06,0x27, 0xe7,0x71,0x2f,0x68,0xa7,0x60,0x80,0x27,0x27,0x70,0x04,0x35,0x9d,0x42,0x01,0xd3, 0x15,0x1c,0x08,0x35,0x55,0x60,0x16,0x68,0x00,0x2e,0x0c,0xd0,0x26,0x78,0x3e,0x42, 0xf9,0xd0,0x70,0x27,0x3e,0x42,0x04,0xd1,0x04,0x30,0x01,0x39,0x00,0x29,0xdf,0xd1, 0x01,0xe0,0x00,0x25,0x55,0x60,0x00,0xbe, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/kinetis/kinetis_flash.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2015 by Ivan Meleca * * ivan@artekit.eu * * * * Copyright (C) 2016 by Tomas Vanek * * vanekt@fbl.cz * ***************************************************************************/ /* Params: * r0 = flash destination address in/out * r1 = longword count * r2 = workarea start address * r3 = workarea end address * r4 = FTFx base */ .text .cpu cortex-m0plus .code 16 .thumb_func .align 2 /* r5 = rp * r6 = wp, tmp * r7 = tmp */ /* old longword algo: 6.680 KiB/s @ adapter_khz 2000 * this async algo: 19.808 KiB/s @ adapter_khz 2000 */ FTFx_FSTAT = 0 FTFx_FCCOB3 = 4 FTFx_FCCOB0 = 7 FTFx_FCCOB7 = 8 wait_fifo: ldr r6, [r2, #0] /* read wp */ cmp r6, #0 /* abort if wp == 0 */ beq exit ldr r5, [r2, #4] /* read rp */ cmp r5, r6 /* wait until rp != wp */ beq wait_fifo str r0, [r4, #FTFx_FCCOB3] /* set flash address */ mov r7, #6 strb r7, [r4, #FTFx_FCCOB0] /* flash command */ ldr r7, [r5] /* set longword data = *rp */ str r7, [r4, #FTFx_FCCOB7] mov r7, #128 strb r7, [r4, #FTFx_FSTAT] add r5, #4 /* rp += 4 */ cmp r5, r3 /* Wrap? */ bcc no_wrap mov r5, r2 add r5, #8 no_wrap: str r5, [r2, #4] /* Store rp */ wait_ccif: ldr r6, [r2, #0] /* read wp */ cmp r6, #0 /* abort if wp == 0 */ beq exit ldrb r6, [r4, #FTFx_FSTAT] tst r6, r7 beq wait_ccif mov r7, #0x70 tst r6, r7 bne error add r0, #4 /* flash address += 4, do not increment before err check */ sub r1, #1 /* word_count-- */ cmp r1, #0 bne wait_fifo b exit error: mov r5, #0 str r5, [r2, #4] /* set rp = 0 on error */ exit: bkpt #0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/kinetis_ke/kinetis_ke_flash.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x16,0x68,0x00,0x2e,0xfe,0xd0,0x55,0x68,0xb5,0x42,0xf9,0xd0,0x2f,0x4e,0x30,0x27, 0x37,0x70,0x2f,0x4e,0x00,0x27,0x37,0x70,0x2e,0x4e,0x06,0x27,0x37,0x70,0x07,0x0c, 0x2d,0x4e,0x37,0x70,0x2a,0x4e,0x01,0x27,0x37,0x70,0xc7,0xb2,0x2a,0x4e,0x37,0x70, 0x07,0x0a,0x28,0x4e,0x37,0x70,0x26,0x4e,0x02,0x27,0x37,0x70,0x6f,0x78,0x25,0x4e, 0x37,0x70,0x2f,0x78,0x24,0x4e,0x37,0x70,0x21,0x4e,0x03,0x27,0x37,0x70,0xef,0x78, 0x20,0x4e,0x37,0x70,0xaf,0x78,0x20,0x4e,0x37,0x70,0x01,0x39,0x04,0x30,0x04,0x35, 0x9d,0x42,0x01,0xd3,0x15,0x1c,0x08,0x35,0x00,0x29,0x1b,0xd0,0x16,0x68,0xae,0x42, 0x18,0xd0,0x17,0x4e,0x04,0x27,0x37,0x70,0x6f,0x78,0x16,0x4e,0x37,0x70,0x2f,0x78, 0x15,0x4e,0x37,0x70,0x12,0x4e,0x05,0x27,0x37,0x70,0xef,0x78,0x11,0x4e,0x37,0x70, 0xaf,0x78,0x11,0x4e,0x37,0x70,0x01,0x39,0x04,0x30,0x04,0x35,0x9d,0x42,0x01,0xd3, 0x15,0x1c,0x08,0x35,0x09,0x4e,0x80,0x27,0x37,0x70,0x08,0x4e,0x36,0x78,0x3e,0x42, 0xfb,0xd0,0x30,0x27,0x3e,0x42,0x04,0xd1,0x00,0x26,0x55,0x60,0x00,0x29,0x02,0xd0, 0x9e,0xe7,0x00,0x20,0x50,0x60,0x30,0x1c,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/kinetis_ke/kinetis_ke_flash.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2015 by Ivan Meleca * * ivan@artekit.eu * ***************************************************************************/ /* Params: * r0 = flash destination address, status * r1 = longword count * r2 = workarea start address * r3 = workarea end address */ .text .cpu cortex-m0plus .code 16 .thumb_func .align 2 /* r5 = rp * r6 = wp, tmp * r7 = tmp */ wait_fifo: ldr r6, [r2, #0] /* read wp */ cmp r6, #0 /* abort if wp == 0 */ beq exit ldr r5, [r2, #4] /* read rp */ cmp r5, r6 /* wait until rp != wp */ beq wait_fifo ldr r6, fstat /* Clear error flags */ mov r7, #48 strb r7, [r6] ldr r6, fccobix /* FCCOBIX = 0 */ mov r7, #0 strb r7, [r6] ldr r6, fccobhi /* Program FLASH command */ mov r7, #6 /* FCCOBHI = 6 */ strb r7, [r6] lsr r7, r0, #16 /* FCCOBLO = flash destination address >> 16 */ ldr r6, fccoblo strb r7, [r6] ldr r6, fccobix /* Index for lower byte address bits[15:0] */ mov r7, #1 strb r7, [r6] /* FCCOBIX = 1*/ uxtb r7, r0 /* Memory address bits[15:0] */ ldr r6, fccoblo strb r7, [r6] /* FCCOBLO = flash destination address */ lsr r7, r0, #8 ldr r6, fccobhi strb r7, [r6] /* FCCOBHI = flash destination address >> 8 */ ldr r6, fccobix /* FCCOBIX = 2 */ mov r7, #2 strb r7, [r6] ldrb r7, [r5, #1] /* FCCOBHI = rp >> 8 */ ldr r6, fccobhi strb r7, [r6] ldrb r7, [r5] /* FCCOBLO = rp */ ldr r6, fccoblo strb r7, [r6] ldr r6, fccobix /* FCCOBIX = 3 */ mov r7, #3 strb r7, [r6] ldrb r7, [r5, #3] /* FCCOBHI = rp >> 24 */ ldr r6, fccobhi strb r7, [r6] ldrb r7, [r5, #2] /* FCCOBLO = rp >> 16 */ ldr r6, fccoblo strb r7, [r6] sub r1, r1, #1 /* Two words (4 bytes) queued, decrement counter */ add r0, r0, #4 /* flash address += 4 */ add r5, r5, #4 /* rp += 4 */ cmp r5, r3 /* Wrap? */ bcc no_wrap mov r5, r2 add r5, r5, #8 no_wrap: cmp r1, #0 /* Done? */ beq execute ldr r6, [r2, #0] /* read wp */ cmp r6, r5 beq execute /* execute if rp == wp */ ldr r6, fccobix /* FCCOBIX = 4 */ mov r7, #4 strb r7, [r6] ldrb r7, [r5, #1] /* FCCOBHI = rp >> 8 */ ldr r6, fccobhi strb r7, [r6] ldrb r7, [r5] /* FCCOBLO = rp */ ldr r6, fccoblo strb r7, [r6] ldr r6, fccobix /* FCCOBIX = 5 */ mov r7, #5 strb r7, [r6] ldrb r7, [r5, #3] /* FCCOBHI = rp >> 24 */ ldr r6, fccobhi strb r7, [r6] ldrb r7, [r5, #2] /* FCCOBLO = rp >> 16 */ ldr r6, fccoblo strb r7, [r6] sub r1, r1, #1 /* Two words (4 bytes) queued, decrement counter */ add r0, r0, #4 /* flash address += 4 */ add r5, r5, #4 /* rp += 4 */ cmp r5, r3 /* Wrap? */ bcc execute mov r5, r2 add r5, r5, #8 execute: ldr r6, fstat /* Launch the command */ mov r7, #128 strb r7, [r6] wait_busy: ldr r6, fstat ldrb r6, [r6] /* Wait until finished */ tst r6, r7 beq wait_busy mov r7, #48 /* Check error */ tst r6, r7 bne error mov r6, #0 /* Clear error */ str r5, [r2, #4] /* Store rp */ cmp r1, #0 /* Done? */ beq done b wait_fifo error: mov r0, #0 str r0, [r2, #4] /* set rp = 0 on error */ done: mov r0, r6 /* Set result code */ bkpt #0 .align 2 fstat: .word 0 fccobix: .word 0 fccobhi: .word 0 fccoblo: .word 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/kinetis_ke/kinetis_ke_watchdog.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x07,0x4b,0x7f,0x22,0x1d,0x78,0x5c,0x78,0x2a,0x40,0x06,0x4d,0x98,0x88,0xd9,0x88, 0x5d,0x80,0x05,0x4d,0x5d,0x80,0x5c,0x70,0x98,0x80,0xd9,0x80,0x1a,0x70,0x00,0xbe, 0x00,0x20,0x05,0x40,0xc5,0x20,0x00,0x00,0xd9,0x28,0x00,0x00, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/kinetis_ke/kinetis_ke_watchdog.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2015 by Ivan Meleca * * ivan@artekit.eu * ***************************************************************************/ .text .cpu cortex-m0plus .code 16 .thumb_func .align 2 ldr r3, wdog_cs1 mov r2, #127 ldrb r5, [r3] ldrb r4, [r3, #1] and r2, r5 ldr r5, unlock1 ldrh r0, [r3, #4] ldrh r1, [r3, #6] strh r5, [r3, #2] ldr r5, unlock2 strh r5, [r3, #2] strb r4, [r3, #1] strh r0, [r3, #4] strh r1, [r3, #6] strb r2, [r3] bkpt #0 .align 2 wdog_cs1: .word 0x40052000 // Watchdog Control and Status Register 1 unlock1: .word 0x20C5 // 1st unlock word unlock2: .word 0x28D9 // 2nd unlock word ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/lpcspifi_erase.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * ***************************************************************************/ .text .syntax unified .cpu cortex-m3 .thumb .thumb_func /* * Params : * r0 = start address, status (out) * r1 = count * r2 = erase command * r3 = block size */ #define SSP_BASE_HIGH 0x4008 #define SSP_BASE_LOW 0x3000 #define SSP_CR0_OFFSET 0x00 #define SSP_CR1_OFFSET 0x04 #define SSP_DATA_OFFSET 0x08 #define SSP_CPSR_OFFSET 0x10 #define SSP_SR_OFFSET 0x0c #define SSP_CLOCK_BASE_HIGH 0x4005 #define SSP_CLOCK_BASE_LOW 0x0000 #define SSP_BRANCH_CLOCK_BASE_HIGH 0x4005 #define SSP_BRANCH_CLOCK_BASE_LOW 0x2000 #define SSP_BASE_CLOCK_OFFSET 0x94 #define SSP_BRANCH_CLOCK_OFFSET 0x700 #define IOCONFIG_BASE_HIGH 0x4008 #define IOCONFIG_BASE_LOW 0x6000 #define IOCONFIG_SCK_OFFSET 0x18c #define IOCONFIG_HOLD_OFFSET 0x190 #define IOCONFIG_WP_OFFSET 0x194 #define IOCONFIG_MISO_OFFSET 0x198 #define IOCONFIG_MOSI_OFFSET 0x19c #define IOCONFIG_CS_OFFSET 0x1a0 #define IO_BASE_HIGH 0x400f #define IO_BASE_LOW 0x4000 #define IO_CS_OFFSET 0xab #define IODIR_BASE_HIGH 0x400f #define IODIR_BASE_LOW 0x6000 #define IO_CS_DIR_OFFSET 0x14 setup: /* Initialize SSP pins and module */ mov.w r10, #IOCONFIG_BASE_LOW movt r10, #IOCONFIG_BASE_HIGH mov.w r8, #0xea str.w r8, [r10, #IOCONFIG_SCK_OFFSET] /* Configure SCK pin function */ mov.w r8, #0x40 str.w r8, [r10, #IOCONFIG_HOLD_OFFSET] /* Configure /HOLD pin function */ mov.w r8, #0x40 str.w r8, [r10, #IOCONFIG_WP_OFFSET] /* Configure /WP pin function */ mov.w r8, #0xed str.w r8, [r10, #IOCONFIG_MISO_OFFSET] /* Configure MISO pin function */ mov.w r8, #0xed str.w r8, [r10, #IOCONFIG_MOSI_OFFSET] /* Configure MOSI pin function */ mov.w r8, #0x44 str.w r8, [r10, #IOCONFIG_CS_OFFSET] /* Configure CS pin function */ mov.w r10, #IODIR_BASE_LOW movt r10, #IODIR_BASE_HIGH mov.w r8, #0x800 str r8, [r10, #IO_CS_DIR_OFFSET] /* Set CS as output */ mov.w r10, #IO_BASE_LOW movt r10, #IO_BASE_HIGH mov.w r8, #0xff str.w r8, [r10, #IO_CS_OFFSET] /* Set CS high */ mov.w r10, #SSP_CLOCK_BASE_LOW movt r10, #SSP_CLOCK_BASE_HIGH mov.w r8, #0x0000 movt r8, #0x0100 str.w r8, [r10, #SSP_BASE_CLOCK_OFFSET] /* Configure SSP0 base clock (use 12 MHz IRC) */ mov.w r10, #SSP_BRANCH_CLOCK_BASE_LOW movt r10, #SSP_BRANCH_CLOCK_BASE_HIGH mov.w r8, #0x01 str.w r8, [r10, #SSP_BRANCH_CLOCK_OFFSET] /* Configure (enable) SSP0 branch clock */ mov.w r10, #SSP_BASE_LOW movt r10, #SSP_BASE_HIGH mov.w r8, #0x07 str.w r8, [r10, #SSP_CR0_OFFSET] /* Set clock postscale */ mov.w r8, #0x02 str.w r8, [r10, #SSP_CPSR_OFFSET] /* Set clock prescale */ str.w r8, [r10, #SSP_CR1_OFFSET] /* Enable SSP in SPI mode */ write_enable: bl cs_down mov.w r9, #0x06 /* Send the write enable command */ bl write_data bl cs_up bl cs_down mov.w r9, #0x05 /* Get status register */ bl write_data mov.w r9, #0x00 /* Dummy data to clock in status */ bl write_data bl cs_up tst r9, #0x02 /* If the WE bit isn't set, we have a problem. */ beq error erase: bl cs_down mov.w r9, r2 /* Send the erase command */ bl write_data write_address: lsr r9, r0, #16 /* Send the current 24-bit write address, MSB first */ bl write_data lsr r9, r0, #8 bl write_data mov.w r9, r0 bl write_data bl cs_up wait_flash_busy: /* Wait for the flash to finish the previous erase */ bl cs_down mov.w r9, #0x05 /* Get status register */ bl write_data mov.w r9, #0x00 /* Dummy data to clock in status */ bl write_data bl cs_up tst r9, #0x01 /* If it isn't done, keep waiting */ bne wait_flash_busy subs r1, r1, #1 /* decrement count */ cbz r1, exit /* Exit if we have written everything */ add r0, r3 /* Move the address up by the block size */ b write_enable /* Start a new block erase */ write_data: /* Send/receive 1 byte of data over SSP */ mov.w r10, #SSP_BASE_LOW movt r10, #SSP_BASE_HIGH str.w r9, [r10, #SSP_DATA_OFFSET] /* Write supplied data to the SSP data reg */ wait_transmit: ldr r9, [r10, #SSP_SR_OFFSET] /* Check SSP status */ tst r9, #0x0010 /* Check if BSY bit is set */ bne wait_transmit /* If still transmitting, keep waiting */ ldr r9, [r10, #SSP_DATA_OFFSET] /* Load received data */ bx lr /* Exit subroutine */ cs_up: mov.w r8, #0xff b cs_write cs_down: mov.w r8, #0x0000 cs_write: mov.w r10, #IO_BASE_LOW movt r10, #IO_BASE_HIGH str.w r8, [r10, #IO_CS_OFFSET] bx lr error: movs r0, #0 exit: bkpt #0x00 .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/lpcspifi_init.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * ***************************************************************************/ /*************************************************************************** * This is an algorithm for the LPC43xx family (and probably the LPC18xx * * family as well, though they have not been tested) that will initialize * * memory-mapped SPI flash accesses. Unfortunately NXP has published * * neither the ROM source code that performs this initialization nor the * * register descriptions necessary to do so, so this code is necessary to * * call into the ROM SPIFI API. * ***************************************************************************/ .text .syntax unified .arch armv7-m .thumb .thumb_func .align 2 /* * Params : * r0 = spifi clock speed */ #define IOCONFIG_BASE_HIGH 0x4008 #define IOCONFIG_BASE_LOW 0x6000 #define IOCONFIG_SCK_OFFSET 0x18c #define IOCONFIG_HOLD_OFFSET 0x190 #define IOCONFIG_WP_OFFSET 0x194 #define IOCONFIG_MISO_OFFSET 0x198 #define IOCONFIG_MOSI_OFFSET 0x19c #define IOCONFIG_CS_OFFSET 0x1a0 #define SPIFI_ROM_TABLE_BASE_HIGH 0x1040 #define SPIFI_ROM_TABLE_BASE_LOW 0x0118 code: mov.w r8, r0 sub sp, #0x84 add r7, sp, #0x0 /* Initialize SPIFI pins */ mov.w r3, #IOCONFIG_BASE_LOW movt r3, #IOCONFIG_BASE_HIGH mov.w r2, #0xf3 str.w r2, [r3, #IOCONFIG_SCK_OFFSET] mov.w r3, #IOCONFIG_BASE_LOW movt r3, #IOCONFIG_BASE_HIGH mov.w r2, #IOCONFIG_BASE_LOW movt r2, #IOCONFIG_BASE_HIGH mov.w r1, #IOCONFIG_BASE_LOW movt r1, #IOCONFIG_BASE_HIGH mov.w r0, #IOCONFIG_BASE_LOW movt r0, #IOCONFIG_BASE_HIGH mov.w r4, #0xd3 str.w r4, [r0, #IOCONFIG_MOSI_OFFSET] mov r0, r4 str.w r0, [r1, #IOCONFIG_MISO_OFFSET] mov r1, r0 str.w r1, [r2, #IOCONFIG_WP_OFFSET] str.w r1, [r3, #IOCONFIG_HOLD_OFFSET] mov.w r3, #IOCONFIG_BASE_LOW movt r3, #IOCONFIG_BASE_HIGH mov.w r2, #0x13 str.w r2, [r3, #IOCONFIG_CS_OFFSET] /* Perform SPIFI init. See spifi_rom_api.h (in NXP lpc43xx driver package) for details */ /* on initialization arguments. */ movw r3, #SPIFI_ROM_TABLE_BASE_LOW /* The ROM API table is located @ 0x10400118, and */ movt r3, #SPIFI_ROM_TABLE_BASE_HIGH /* the first pointer in the struct is to the init function. */ ldr r3, [r3, #0x0] ldr r4, [r3, #0x0] /* Grab the init function pointer from the table */ /* Set up function arguments */ movw r0, #0x3b4 movt r0, #0x1000 /* Pointer to a SPIFI data struct that we don't care about */ mov.w r1, #0x3 /* "csHigh". Not 100% sure what this does. */ mov.w r2, #0xc0 /* The configuration word: S_RCVCLOCK | S_FULLCLK */ mov.w r3, r8 /* SPIFI clock speed (12MHz) */ blx r4 /* Call the init function */ b done done: bkpt #0 .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/lpcspifi_write.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * ***************************************************************************/ .text .syntax unified .cpu cortex-m3 .thumb .thumb_func /* * Params : * r0 = workarea start, status (out) * r1 = workarea end * r2 = target address (offset from flash base) * r3 = count (bytes) * r4 = page size * Clobbered: * r7 - rp * r8 - wp, tmp * r9 - send/receive data * r10 - temp * r11 - current page end address */ /* * This code is embedded within: src/flash/nor/lpcspifi.c as a "C" array. * * To rebuild: * arm-none-eabi-gcc -c lpcspifi_write.S * arm-none-eabi-objcopy -O binary lpcspifi_write.o lpcspifi_write.bin * xxd -c 8 -i lpcspifi_write.bin > lpcspifi_write.txt * * Then read and edit this result into the "C" source. */ #define SSP_BASE_HIGH 0x4008 #define SSP_BASE_LOW 0x3000 #define SSP_CR0_OFFSET 0x00 #define SSP_CR1_OFFSET 0x04 #define SSP_DATA_OFFSET 0x08 #define SSP_CPSR_OFFSET 0x10 #define SSP_SR_OFFSET 0x0c #define SSP_CLOCK_BASE_HIGH 0x4005 #define SSP_CLOCK_BASE_LOW 0x0000 #define SSP_BRANCH_CLOCK_BASE_HIGH 0x4005 #define SSP_BRANCH_CLOCK_BASE_LOW 0x2000 #define SSP_BASE_CLOCK_OFFSET 0x94 #define SSP_BRANCH_CLOCK_OFFSET 0x700 #define IOCONFIG_BASE_HIGH 0x4008 #define IOCONFIG_BASE_LOW 0x6000 #define IOCONFIG_SCK_OFFSET 0x18c #define IOCONFIG_HOLD_OFFSET 0x190 #define IOCONFIG_WP_OFFSET 0x194 #define IOCONFIG_MISO_OFFSET 0x198 #define IOCONFIG_MOSI_OFFSET 0x19c #define IOCONFIG_CS_OFFSET 0x1a0 #define IO_BASE_HIGH 0x400f #define IO_BASE_LOW 0x4000 #define IO_CS_OFFSET 0xab #define IODIR_BASE_HIGH 0x400f #define IODIR_BASE_LOW 0x6000 #define IO_CS_DIR_OFFSET 0x14 setup: /* Initialize SSP pins and module */ mov.w r10, #IOCONFIG_BASE_LOW movt r10, #IOCONFIG_BASE_HIGH mov.w r8, #0xea str.w r8, [r10, #IOCONFIG_SCK_OFFSET] /* Configure SCK pin function */ mov.w r8, #0x40 str.w r8, [r10, #IOCONFIG_HOLD_OFFSET] /* Configure /HOLD pin function */ mov.w r8, #0x40 str.w r8, [r10, #IOCONFIG_WP_OFFSET] /* Configure /WP pin function */ mov.w r8, #0xed str.w r8, [r10, #IOCONFIG_MISO_OFFSET] /* Configure MISO pin function */ mov.w r8, #0xed str.w r8, [r10, #IOCONFIG_MOSI_OFFSET] /* Configure MOSI pin function */ mov.w r8, #0x44 str.w r8, [r10, #IOCONFIG_CS_OFFSET] /* Configure CS pin function */ mov.w r10, #IODIR_BASE_LOW movt r10, #IODIR_BASE_HIGH mov.w r8, #0x800 str r8, [r10, #IO_CS_DIR_OFFSET] /* Set CS as output */ mov.w r10, #IO_BASE_LOW movt r10, #IO_BASE_HIGH mov.w r8, #0xff str.w r8, [r10, #IO_CS_OFFSET] /* Set CS high */ mov.w r10, #SSP_CLOCK_BASE_LOW movt r10, #SSP_CLOCK_BASE_HIGH mov.w r8, #0x0000 movt r8, #0x0100 str.w r8, [r10, #SSP_BASE_CLOCK_OFFSET] /* Configure SSP0 base clock (use 12 MHz IRC) */ mov.w r10, #SSP_BRANCH_CLOCK_BASE_LOW movt r10, #SSP_BRANCH_CLOCK_BASE_HIGH mov.w r8, #0x01 str.w r8, [r10, #SSP_BRANCH_CLOCK_OFFSET] /* Configure (enable) SSP0 branch clock */ mov.w r10, #SSP_BASE_LOW movt r10, #SSP_BASE_HIGH mov.w r8, #0x07 str.w r8, [r10, #SSP_CR0_OFFSET] /* Set clock postscale */ mov.w r8, #0x02 str.w r8, [r10, #SSP_CPSR_OFFSET] /* Set clock prescale */ str.w r8, [r10, #SSP_CR1_OFFSET] /* Enable SSP in SPI mode */ mov.w r11, #0x00 find_next_page_boundary: add r11, r4 /* Increment to the next page */ cmp r11, r2 /* If we have not reached the next page boundary after the target address, keep going */ bls find_next_page_boundary write_enable: bl cs_down mov.w r9, #0x06 /* Send the write enable command */ bl write_data bl cs_up bl cs_down mov.w r9, #0x05 /* Get status register */ bl write_data mov.w r9, #0x00 /* Dummy data to clock in status */ bl write_data bl cs_up tst r9, #0x02 /* If the WE bit isn't set, we have a problem. */ beq error page_program: bl cs_down mov.w r9, #0x02 /* Send the page program command */ bl write_data write_address: lsr r9, r2, #16 /* Send the current 24-bit write address, MSB first */ bl write_data lsr r9, r2, #8 bl write_data mov.w r9, r2 bl write_data wait_fifo: ldr r8, [r0] /* read the write pointer */ cmp r8, #0 /* if it's zero, we're gonzo */ beq exit ldr r7, [r0, #4] /* read the read pointer */ cmp r7, r8 /* wait until they are not equal */ beq wait_fifo write: ldrb r9, [r7], #0x01 /* Load one byte from the FIFO, increment the read pointer by 1 */ bl write_data /* send the byte to the flash chip */ cmp r7, r1 /* wrap the read pointer if it is at the end */ it cs addcs r7, r0, #8 /* skip loader args */ str r7, [r0, #4] /* store the new read pointer */ subs r3, r3, #1 /* decrement count */ cbz r3, exit /* Exit if we have written everything */ add r2, #1 /* Increment flash address by 1 */ cmp r11, r2 /* See if we have reached the end of a page */ bne wait_fifo /* If not, keep writing bytes */ bl cs_up /* Otherwise, end the command and keep going w/ the next page */ add r11, r4 /* Move up the end-of-page address by the page size*/ wait_flash_busy: /* Wait for the flash to finish the previous page write */ bl cs_down mov.w r9, #0x05 /* Get status register */ bl write_data mov.w r9, #0x00 /* Dummy data to clock in status */ bl write_data bl cs_up tst r9, #0x01 /* If it isn't done, keep waiting */ bne wait_flash_busy b write_enable /* If it is done, start a new page write */ write_data: /* Send/receive 1 byte of data over SSP */ mov.w r10, #SSP_BASE_LOW movt r10, #SSP_BASE_HIGH str.w r9, [r10, #SSP_DATA_OFFSET] /* Write supplied data to the SSP data reg */ wait_transmit: ldr r9, [r10, #SSP_SR_OFFSET] /* Check SSP status */ tst r9, #0x0010 /* Check if BSY bit is set */ bne wait_transmit /* If still transmitting, keep waiting */ ldr r9, [r10, #SSP_DATA_OFFSET] /* Load received data */ bx lr /* Exit subroutine */ cs_up: mov.w r8, #0xff b cs_write cs_down: mov.w r8, #0x0000 cs_write: mov.w r10, #IO_BASE_LOW movt r10, #IO_BASE_HIGH str.w r8, [r10, #IO_CS_OFFSET] bx lr error: movs r0, #0 str r0, [r2, #4] /* set rp = 0 on error */ exit: bl cs_up /* end the command before returning */ mov r0, r6 bkpt #0x00 .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/max32xxx/max32xxx.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0xdf,0xf8,0x44,0x40,0xd0,0xf8,0x00,0x80,0xb8,0xf1,0x00,0x0f,0x1a,0xd0,0x47,0x68, 0x47,0x45,0xf7,0xd0,0x22,0x60,0x02,0xf1,0x04,0x02,0x57,0xf8,0x04,0x8b,0xc4,0xf8, 0x30,0x80,0xa5,0x68,0x45,0xf0,0x01,0x05,0xa5,0x60,0xd4,0xf8,0x08,0x80,0x18,0xf0, 0x01,0x0f,0xfa,0xd1,0x8f,0x42,0x28,0xbf,0x00,0xf1,0x08,0x07,0x47,0x60,0x01,0x3b, 0x03,0xb1,0xdf,0xe7,0x00,0xbe,0x00,0xbf,0x00,0x00,0x00,0x40, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/max32xxx/max32xxx.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2016 by Maxim Integrated * * Kevin Gillespie * 11 tacts == 1.4us with 8MHz * every extra iteration will take 5 tacts == 0.6us */ delay: subs r6, r6, #1 cmp r6, #0 bne delay bx lr ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/mrvlqspi_write.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2014 by Mahavir Jain * * * * Adapted from (contrib/loaders/flash/lpcspifi_write.S): * * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * ***************************************************************************/ .text .syntax unified .cpu cortex-m3 .thumb .thumb_func /* * For compilation: * arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -c contrib/loaders/flash/mrvlqspi_write.S * arm-none-eabi-objcopy -O binary mrvlqspi_write.o code.bin * Copy code.bin into mrvlqspi flash driver */ /* * Params : * r0 = workarea start, status (out) * r1 = workarea end * r2 = target address (offset from flash base) * r3 = count (bytes) * r4 = page size * r5 = qspi base address * Clobbered: * r7 - rp * r8 - wp, tmp * r9 - send/receive data * r10 - current page end address */ #define CNTL 0x0 #define CONF 0x4 #define DOUT 0x8 #define DIN 0xc #define INSTR 0x10 #define ADDR 0x14 #define RDMODE 0x18 #define HDRCNT 0x1c #define DINCNT 0x20 #define SS_EN (1 << 0) #define XFER_RDY (1 << 1) #define RFIFO_EMPTY (1 << 4) #define WFIFO_EMPTY (1 << 6) #define WFIFO_FULL (1 << 7) #define FIFO_FLUSH (1 << 9) #define RW_EN (1 << 13) #define XFER_STOP (1 << 14) #define XFER_START (1 << 15) #define INS_WRITE_ENABLE 0x06 #define INS_READ_STATUS 0x05 #define INS_PAGE_PROGRAM 0x02 init: mov.w r10, #0x00 find_next_page_boundary: add r10, r4 /* Increment to the next page */ cmp r10, r2 /* If we have not reached the next page boundary after the target address, keep going */ bls find_next_page_boundary write_enable: /* Flush read/write fifos */ bl flush_fifo /* Instruction byte 1 */ movs r8, #0x1 str r8, [r5, #HDRCNT] /* Set write enable instruction */ movs r8, #INS_WRITE_ENABLE str r8, [r5, #INSTR] movs r9, #0x1 bl start_tx bl stop_tx page_program: /* Instruction byte 1, Addr byte 3 */ movs r8, #0x31 str r8, [r5, #HDRCNT] /* Todo: set addr and data pin to single */ write_address: mov r8, r2 str r8, [r5, #ADDR] /* Set page program instruction */ movs r8, #INS_PAGE_PROGRAM str r8, [r5, #INSTR] /* Start write transfer */ movs r9, #0x1 bl start_tx wait_fifo: ldr r8, [r0] /* read the write pointer */ cmp r8, #0 /* if it's zero, we're gonzo */ beq exit ldr r7, [r0, #4] /* read the read pointer */ cmp r7, r8 /* wait until they are not equal */ beq wait_fifo write: ldrb r9, [r7], #0x01 /* Load one byte from the FIFO, increment the read pointer by 1 */ bl write_data /* send the byte to the flash chip */ cmp r7, r1 /* wrap the read pointer if it is at the end */ it cs addcs r7, r0, #8 /* skip loader args */ str r7, [r0, #4] /* store the new read pointer */ subs r3, r3, #1 /* decrement count */ cmp r3, #0 /* Exit if we have written everything */ beq write_wait add r2, #1 /* Increment flash address by 1 */ cmp r10, r2 /* See if we have reached the end of a page */ bne wait_fifo /* If not, keep writing bytes */ write_wait: bl stop_tx /* Otherwise, end the command and keep going w/ the next page */ add r10, r4 /* Move up the end-of-page address by the page size*/ check_flash_busy: /* Wait for the flash to finish the previous page write */ /* Flush read/write fifos */ bl flush_fifo /* Instruction byte 1 */ movs r8, #0x1 str r8, [r5, #HDRCNT] /* Continuous data in of status register */ movs r8, #0x0 str r8, [r5, #DINCNT] /* Set write enable instruction */ movs r8, #INS_READ_STATUS str r8, [r5, #INSTR] /* Start read transfer */ movs r9, #0x0 bl start_tx wait_flash_busy: bl read_data and.w r9, r9, #0x1 cmp r9, #0x0 bne.n wait_flash_busy bl stop_tx cmp r3, #0 bne.n write_enable /* If it is done, start a new page write */ b exit /* All data written, exit */ write_data: /* Send/receive 1 byte of data over QSPI */ ldr r8, [r5, #CNTL] lsls r8, r8, #24 bmi.n write_data str r9, [r5, #DOUT] bx lr read_data: /* Read 1 byte of data over QSPI */ ldr r8, [r5, #CNTL] lsls r8, r8, #27 bmi.n read_data ldr r9, [r5, #DIN] bx lr flush_fifo: /* Flush read write fifos */ ldr r8, [r5, #CONF] orr.w r8, r8, #FIFO_FLUSH str r8, [r5, #CONF] flush_reset: ldr r8, [r5, #CONF] lsls r8, r8, #22 bmi.n flush_reset bx lr start_tx: ldr r8, [r5, #CNTL] orr.w r8, r8, #SS_EN str r8, [r5, #CNTL] xfer_rdy: ldr r8, [r5, #CNTL] lsls r8, r8, #30 bpl.n xfer_rdy ldr r8, [r5, #CONF] bfi r8, r9, #13, #1 orr.w r8, r8, #XFER_START str r8, [r5, #CONF] bx lr stop_tx: ldr r8, [r5, #CNTL] lsls r8, r8, #30 bpl.n stop_tx wfifo_wait: ldr r8, [r5, #CNTL] lsls r8, r8, #25 bpl.n wfifo_wait ldr r8, [r5, #CONF] orr.w r8, r8, #XFER_STOP str r8, [r5, #CONF] xfer_start: ldr r8, [r5, #CONF] lsls r8, r8, #16 bmi.n xfer_start ss_disable: # Disable SS_EN ldr r8, [r5, #CNTL] bic.w r8, r8, #SS_EN str r8, [r5, #CNTL] wait: ldr r8, [r5, #CNTL] lsls r8, r8, #30 bpl.n wait bx lr error: movs r0, #0 str r0, [r2, #4] /* set rp = 0 on error */ exit: mov r0, r6 bkpt #0x00 .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/MSP432E4_FlashLibIf.h ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2014-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432E4_FLASHLIBIF_H #define OPENOCD_LOADERS_FLASH_MSP432_MSP432E4_FLASHLIBIF_H #include #include /* RAM loader */ static const uint32_t RAM_LOADER_START = 0x20000000u; /* Code space */ static const uint32_t RAM_LOADER_MAIN = 0x20000110u; /* Code space */ static const uint32_t RAM_LOADER_BUFFER1 = 0x20002000u; /* SBUS data space */ static const uint32_t RAM_LOADER_BUFFER2 = 0x20003000u; /* SBUS data space */ static const uint32_t RAM_LOADER_STACK = 0x20002000u; /* SBUS data space */ /* Address for flash function to be executed */ static const uint32_t FLASH_FUNCTION_ADDRESS = 0x20000150u; enum flash_command { FLASH_NO_COMMAND = 0, FLASH_MASS_ERASE = 1, FLASH_SECTOR_ERASE = 2, FLASH_PROGRAM = 4, FLASH_INIT = 8, FLASH_EXIT = 16, FLASH_CONTINUOUS_PROGRAM = 32 }; /* Address for algorithm program and flash buffer */ static const uint32_t DST_ADDRESS = 0x2000015Cu; static const uint32_t SRC_LENGTH_ADDRESS = 0x20000160u; static const uint32_t BUFFER1_STATUS_REGISTER = 0x20000164u; static const uint32_t BUFFER2_STATUS_REGISTER = 0x20000168u; static const uint32_t BUFFER_INACTIVE = 0x00000000u; static const uint32_t BUFFER_ACTIVE = 0x00000001u; static const uint32_t BUFFER_DATA_READY = 0x00000010u; static const size_t SRC_LENGTH_MAX = 4096u; /* Erase options */ static const uint32_t ERASE_PARAM_ADDRESS = 0x2000016Cu; static const uint32_t ERASE_MAIN = 0x00000001u; static const uint32_t ERASE_INFO = 0x00000002u; /* Unlock BSL */ static const uint32_t UNLOCK_BSL_ADDRESS = 0x20000170u; static const uint32_t LOCK_BSL_KEY = 0x00000000u; static const uint32_t UNLOCK_BSL_KEY = 0x0000000Bu; /* Address for return code */ static const uint32_t RETURN_CODE_ADDRESS = 0x20000154u; /* Return codes */ static const uint32_t FLASH_BUSY = 0x00000001u; static const uint32_t FLASH_SUCCESS = 0x00000ACEu; static const uint32_t FLASH_ERROR = 0x0000DEADu; static const uint32_t FLASH_TIMEOUT_ERROR = 0xDEAD0000u; static const uint32_t FLASH_VERIFY_ERROR = 0xDEADDEADu; static const uint32_t FLASH_WRONG_COMMAND = 0x00000BADu; static const uint32_t FLASH_POWER_ERROR = 0x00DEAD00u; /* Device ID address */ static const uint32_t DEVICE_ID_ADDRESS = 0x0020100Cu; static const uint32_t PC_REGISTER = 15u; static const uint32_t SP_REGISTER = 13u; /* CS silicon and boot code revisions */ static const uint32_t SILICON_REV_ADDRESS = 0x00201010u; static const uint32_t SILICON_REV_A = 0x00000041u; static const uint32_t SILICON_REV_B = 0x00000042u; static const uint32_t SILICON_REV_C = 0x00000043u; static const uint32_t SILICON_REV_D = 0x00000044u; static const uint32_t SILICON_REV_E = 0x00000045u; static const uint32_t SILICON_REV_F = 0x00000046u; static const uint32_t SILICON_REV_G = 0x00000047u; static const uint32_t SILICON_REV_H = 0x00000048u; static const uint32_t SILICON_REV_I = 0x00000049u; static const uint32_t SILICON_REV_B_WRONG = 0x00004100u; struct flash_interface { volatile uint32_t FLASH_FUNCTION; volatile uint32_t RETURN_CODE; volatile uint32_t _RESERVED0; volatile uint32_t DST_ADDRESS; volatile uint32_t SRC_LENGTH; volatile uint32_t BUFFER1_STATUS_REGISTER; volatile uint32_t BUFFER2_STATUS_REGISTER; volatile uint32_t ERASE_PARAM; volatile uint32_t UNLOCK_BSL; }; #define FLASH_LOADER_BASE ((uint32_t)0x20000150u) #define FLASH_LOADER ((struct flash_interface *) FLASH_LOADER_BASE) #endif /* OPENOCD_LOADERS_FLASH_MSP432_MSP432E4_FLASHLIBIF_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/MSP432P4_FlashLibIf.h ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2014-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432P4_FLASHLIBIF_H #define OPENOCD_LOADERS_FLASH_MSP432_MSP432P4_FLASHLIBIF_H #include #include /* RAM loader */ static const uint32_t RAM_LOADER_START = 0x01000000u; /* Code space */ static const uint32_t RAM_LOADER_MAIN = 0x01000110u; /* Code space */ static const uint32_t RAM_LOADER_BUFFER1 = 0x20002000u; /* SBUS data space */ static const uint32_t RAM_LOADER_BUFFER2 = 0x20003000u; /* SBUS data space */ static const uint32_t RAM_LOADER_STACK = 0x20002000u; /* SBUS data space */ /* Address for flash function to be executed */ static const uint32_t FLASH_FUNCTION_ADDRESS = 0x20000150u; enum flash_command { FLASH_NO_COMMAND = 0, FLASH_MASS_ERASE = 1, FLASH_SECTOR_ERASE = 2, FLASH_PROGRAM = 4, FLASH_INIT = 8, FLASH_EXIT = 16, FLASH_CONTINUOUS_PROGRAM = 32 }; /* Address for algorithm program and flash buffer */ static const uint32_t DST_ADDRESS = 0x2000015Cu; static const uint32_t SRC_LENGTH_ADDRESS = 0x20000160u; static const uint32_t BUFFER1_STATUS_REGISTER = 0x20000164u; static const uint32_t BUFFER2_STATUS_REGISTER = 0x20000168u; static const uint32_t BUFFER_INACTIVE = 0x00000000u; static const uint32_t BUFFER_ACTIVE = 0x00000001u; static const uint32_t BUFFER_DATA_READY = 0x00000010u; static const size_t SRC_LENGTH_MAX = 4096u; /* erase options */ static const uint32_t ERASE_PARAM_ADDRESS = 0x2000016Cu; static const uint32_t ERASE_MAIN = 0x00000001u; static const uint32_t ERASE_INFO = 0x00000002u; /* Unlock BSL */ static const uint32_t UNLOCK_BSL_ADDRESS = 0x20000170u; static const uint32_t LOCK_BSL_KEY = 0x00000000u; static const uint32_t UNLOCK_BSL_KEY = 0x0000000Bu; /* Address for return code */ static const uint32_t RETURN_CODE_ADDRESS = 0x20000154u; /* Return codes */ static const uint32_t FLASH_BUSY = 0x00000001u; static const uint32_t FLASH_SUCCESS = 0x00000ACEu; static const uint32_t FLASH_ERROR = 0x0000DEADu; static const uint32_t FLASH_TIMEOUT_ERROR = 0xDEAD0000u; static const uint32_t FLASH_VERIFY_ERROR = 0xDEADDEADu; static const uint32_t FLASH_WRONG_COMMAND = 0x00000BADu; static const uint32_t FLASH_POWER_ERROR = 0x00DEAD00u; /* Device ID address */ static const uint32_t DEVICE_ID_ADDRESS = 0x0020100Cu; static const uint32_t PC_REGISTER = 15u; static const uint32_t SP_REGISTER = 13u; /* CS silicon and boot code revisions */ static const uint32_t SILICON_REV_ADDRESS = 0x00201010u; static const uint32_t SILICON_REV_A = 0x00000041u; static const uint32_t SILICON_REV_B = 0x00000042u; static const uint32_t SILICON_REV_C = 0x00000043u; static const uint32_t SILICON_REV_D = 0x00000044u; static const uint32_t SILICON_REV_E = 0x00000045u; static const uint32_t SILICON_REV_F = 0x00000046u; static const uint32_t SILICON_REV_G = 0x00000047u; static const uint32_t SILICON_REV_H = 0x00000048u; static const uint32_t SILICON_REV_I = 0x00000049u; static const uint32_t SILICON_REV_B_WRONG = 0x00004100u; struct flash_interface { volatile uint32_t FLASH_FUNCTION; volatile uint32_t RETURN_CODE; volatile uint32_t _RESERVED0; volatile uint32_t DST_ADDRESS; volatile uint32_t SRC_LENGTH; volatile uint32_t BUFFER1_STATUS_REGISTER; volatile uint32_t BUFFER2_STATUS_REGISTER; volatile uint32_t ERASE_PARAM; volatile uint32_t UNLOCK_BSL; }; #define FLASH_LOADER_BASE ((uint32_t)0x20000150u) #define FLASH_LOADER ((struct flash_interface *) FLASH_LOADER_BASE) #endif /* OPENOCD_LOADERS_FLASH_MSP432_MSP432P4_FLASHLIBIF_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/driverlib.c ================================================ // SPDX-License-Identifier: BSD-3-Clause /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #include #include #include "driverlib.h" /* * Wrapper function for the CPSID instruction. * Returns the state of PRIMASK on entry. */ uint32_t __attribute__((naked)) cpu_cpsid(void) { uint32_t ret; /* Read PRIMASK and disable interrupts. */ __asm(" mrs r0, PRIMASK\n" " cpsid i\n" " bx lr\n" : "=r" (ret)); /* * The return is handled in the inline assembly, but the compiler will * still complain if there is not an explicit return here (despite the fact * that this does not result in any code being produced because of the * naked attribute). */ return ret; } /* Wrapper function for the CPUWFI instruction. */ void __attribute__((naked)) cpu_wfi(void) { /* Wait for the next interrupt. */ __asm(" wfi\n" " bx lr\n"); } /* Power Control Module APIs */ #if defined(PCM) static bool __pcm_set_core_voltage_level_advanced(uint_fast8_t voltage_level, uint32_t time_out, bool blocking) { uint8_t power_mode; uint8_t current_voltage_level; uint32_t reg_value; bool bool_timeout; /* Getting current power mode and level */ power_mode = pcm_get_power_mode(); current_voltage_level = pcm_get_core_voltage_level(); bool_timeout = time_out > 0 ? true : false; /* If we are already at the power mode they requested, return */ if (current_voltage_level == voltage_level) return true; while (current_voltage_level != voltage_level) { reg_value = PCM->CTL0; switch (pcm_get_power_state()) { case PCM_AM_LF_VCORE1: case PCM_AM_DCDC_VCORE1: case PCM_AM_LDO_VCORE0: PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE1) | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); break; case PCM_AM_LF_VCORE0: case PCM_AM_DCDC_VCORE0: case PCM_AM_LDO_VCORE1: PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE0) | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); break; default: break; } if (blocking) { while (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS)) { if (bool_timeout && !(--time_out)) return false; } } else return true; current_voltage_level = pcm_get_core_voltage_level(); } /* Changing the power mode if we are stuck in LDO mode */ if (power_mode != pcm_get_power_mode()) { if (power_mode == PCM_DCDC_MODE) return pcm_set_power_mode(PCM_DCDC_MODE); else return pcm_set_power_mode(PCM_LF_MODE); } return true; } bool pcm_set_core_voltage_level(uint_fast8_t voltage_level) { return __pcm_set_core_voltage_level_advanced(voltage_level, 0, true); } uint8_t pcm_get_power_mode(void) { uint8_t current_power_state; current_power_state = pcm_get_power_state(); switch (current_power_state) { case PCM_AM_LDO_VCORE0: case PCM_AM_LDO_VCORE1: case PCM_LPM0_LDO_VCORE0: case PCM_LPM0_LDO_VCORE1: default: return PCM_LDO_MODE; case PCM_AM_DCDC_VCORE0: case PCM_AM_DCDC_VCORE1: case PCM_LPM0_DCDC_VCORE0: case PCM_LPM0_DCDC_VCORE1: return PCM_DCDC_MODE; case PCM_LPM0_LF_VCORE0: case PCM_LPM0_LF_VCORE1: case PCM_AM_LF_VCORE1: case PCM_AM_LF_VCORE0: return PCM_LF_MODE; } } uint8_t pcm_get_core_voltage_level(void) { uint8_t current_power_state = pcm_get_power_state(); switch (current_power_state) { case PCM_AM_LDO_VCORE0: case PCM_AM_DCDC_VCORE0: case PCM_AM_LF_VCORE0: case PCM_LPM0_LDO_VCORE0: case PCM_LPM0_DCDC_VCORE0: case PCM_LPM0_LF_VCORE0: default: return PCM_VCORE0; case PCM_AM_LDO_VCORE1: case PCM_AM_DCDC_VCORE1: case PCM_AM_LF_VCORE1: case PCM_LPM0_LDO_VCORE1: case PCM_LPM0_DCDC_VCORE1: case PCM_LPM0_LF_VCORE1: return PCM_VCORE1; case PCM_LPM3: return PCM_VCORELPM3; } } static bool __pcm_set_power_mode_advanced(uint_fast8_t power_mode, uint32_t time_out, bool blocking) { uint8_t current_power_mode; uint8_t current_power_state; uint32_t reg_value; bool bool_timeout; /* Getting Current Power Mode */ current_power_mode = pcm_get_power_mode(); /* If the power mode being set it the same as the current mode, return */ if (power_mode == current_power_mode) return true; current_power_state = pcm_get_power_state(); bool_timeout = time_out > 0 ? true : false; /* Go through the while loop while we haven't achieved the power mode */ while (current_power_mode != power_mode) { reg_value = PCM->CTL0; switch (current_power_state) { case PCM_AM_DCDC_VCORE0: case PCM_AM_LF_VCORE0: PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE0 | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); break; case PCM_AM_LF_VCORE1: case PCM_AM_DCDC_VCORE1: PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE1 | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); break; case PCM_AM_LDO_VCORE1: { if (power_mode == PCM_DCDC_MODE) { PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE1 | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); } else if (power_mode == PCM_LF_MODE) { PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE1 | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); } else return false; break; } case PCM_AM_LDO_VCORE0: { if (power_mode == PCM_DCDC_MODE) { PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE0 | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); } else if (power_mode == PCM_LF_MODE) { PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE0 | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); } else return false; break; } default: break; } if (blocking) { while (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS)) { if (bool_timeout && !(--time_out)) return false; } } else return true; current_power_mode = pcm_get_power_mode(); current_power_state = pcm_get_power_state(); } return true; } bool pcm_set_power_mode(uint_fast8_t power_mode) { return __pcm_set_power_mode_advanced(power_mode, 0, true); } static bool __pcm_set_power_state_advanced(uint_fast8_t power_state, uint32_t timeout, bool blocking) { uint8_t current_power_state; current_power_state = pcm_get_power_state(); if (current_power_state == power_state) return true; switch (power_state) { case PCM_AM_LDO_VCORE0: return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE, timeout, blocking); case PCM_AM_LDO_VCORE1: return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE, timeout, blocking); case PCM_AM_DCDC_VCORE0: return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE, timeout, blocking); case PCM_AM_DCDC_VCORE1: return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE, timeout, blocking); case PCM_AM_LF_VCORE0: return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE, timeout, blocking); case PCM_AM_LF_VCORE1: return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE, timeout, blocking); case PCM_LPM0_LDO_VCORE0: if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE, timeout, blocking)) break; return pcm_goto_lpm0(); case PCM_LPM0_LDO_VCORE1: if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE, timeout, blocking)) break; return pcm_goto_lpm0(); case PCM_LPM0_DCDC_VCORE0: if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE, timeout, blocking)) break; return pcm_goto_lpm0(); case PCM_LPM0_DCDC_VCORE1: if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE, timeout, blocking)) break; return pcm_goto_lpm0(); case PCM_LPM0_LF_VCORE0: if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE, timeout, blocking)) break; return pcm_goto_lpm0(); case PCM_LPM0_LF_VCORE1: if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE, timeout, blocking)) break; return pcm_goto_lpm0(); case PCM_LPM3: return pcm_goto_lpm3(); case PCM_LPM4: return pcm_goto_lpm4(); case PCM_LPM45: return pcm_shutdown_device(PCM_LPM45); case PCM_LPM35_VCORE0: return pcm_shutdown_device(PCM_LPM35_VCORE0); default: return false; } return false; } bool pcm_set_power_state(uint_fast8_t power_state) { return __pcm_set_power_state_advanced(power_state, 0, true); } bool pcm_shutdown_device(uint32_t shutdown_mode) { uint32_t shutdown_mode_bits = (shutdown_mode == PCM_LPM45) ? PCM_CTL0_LPMR_12 : PCM_CTL0_LPMR_10; /* If a power transition is occurring, return false */ if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS)) return false; /* Initiating the shutdown */ SCB->SCR |= SCB_SCR_SLEEPDEEP_MSK; PCM->CTL0 = (PCM_KEY | shutdown_mode_bits | (PCM->CTL0 & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_LPMR_MASK))); cpu_wfi(); return true; } bool pcm_goto_lpm4(void) { /* Disabling RTC_C and WDT_A */ wdt_a_hold_timer(); rtc_c_hold_clock(); /* LPM4 is just LPM3 with WDT_A/RTC_C disabled... */ return pcm_goto_lpm3(); } bool pcm_goto_lpm0(void) { /* If we are in the middle of a state transition, return false */ if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS)) return false; SCB->SCR &= ~SCB_SCR_SLEEPDEEP_MSK; cpu_wfi(); return true; } bool pcm_goto_lpm3(void) { uint_fast8_t current_power_state; uint_fast8_t current_power_mode; /* If we are in the middle of a state transition, return false */ if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS)) return false; /* If we are in the middle of a shutdown, return false */ if ((PCM->CTL0 & PCM_CTL0_LPMR_MASK) == PCM_CTL0_LPMR_10 || (PCM->CTL0 & PCM_CTL0_LPMR_MASK) == PCM_CTL0_LPMR_12) return false; current_power_mode = pcm_get_power_mode(); current_power_state = pcm_get_power_state(); if (current_power_mode == PCM_DCDC_MODE) pcm_set_power_mode(PCM_LDO_MODE); /* Clearing the SDR */ PCM->CTL0 = (PCM->CTL0 & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_LPMR_MASK)) | PCM_KEY; /* Setting the sleep deep bit */ SCB->SCR |= SCB_SCR_SLEEPDEEP_MSK; cpu_wfi(); SCB->SCR &= ~SCB_SCR_SLEEPDEEP_MSK; return pcm_set_power_state(current_power_state); } uint8_t pcm_get_power_state(void) { return (PCM->CTL0 & PCM_CTL0_CPM_MASK) >> PCM_CTL0_CPM_OFS; } #endif /* Real Time Clock APIs */ #if defined(RTC_C) void rtc_c_hold_clock(void) { RTC_C->CTL0 = (RTC_C->CTL0 & ~RTC_C_CTL0_KEY_MASK) | RTC_C_KEY; BITBAND_PERI(RTC_C->CTL13, RTC_C_CTL13_HOLD_OFS) = 1; BITBAND_PERI(RTC_C->CTL0, RTC_C_CTL0_KEY_OFS) = 0; } #endif /* Watch Dog Timer APIs */ #if defined(WDT_A) void wdt_a_hold_timer(void) { /* Set Hold bit */ uint8_t new_wdt_status = (WDT_A->CTL | WDT_A_CTL_HOLD); WDT_A->CTL = WDT_A_CTL_PW + new_wdt_status; } #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/driverlib.h ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_MSP432_DRIVERLIB_H #define OPENOCD_LOADERS_FLASH_MSP432_DRIVERLIB_H #include #include #ifdef __cplusplus extern "C" { #endif #if defined(__MSP432E4X__) #include "msp432e4x.h" #elif defined(__MSP432P401X__) #include "msp432p401x.h" #elif defined(__MSP432P411X__) #include "msp432p411x.h" #else #error "Failed to match a device specific include file" #endif /* Structure type to access the System Control Block (SCB). */ struct SCB_Type { volatile uint32_t CPUID; /* CPUID Base Register */ volatile uint32_t ICSR; /* Interrupt Control and State Register */ volatile uint32_t VTOR; /* Vector Table Offset Register */ volatile uint32_t AIRCR; /* Application Interrupt and Reset Control */ volatile uint32_t SCR; /* System Control Register */ volatile uint32_t CCR; /* Configuration Control Register */ volatile uint8_t SHP[12U]; /* System Handlers Priority Registers */ volatile uint32_t SHCSR; /* System Handler Control and State */ volatile uint32_t CFSR; /* Configurable Fault Status Register */ volatile uint32_t HFSR; /* HardFault Status Register */ volatile uint32_t DFSR; /* Debug Fault Status Register */ volatile uint32_t MMFAR; /* MemManage Fault Address Register */ volatile uint32_t BFAR; /* BusFault Address Register */ volatile uint32_t AFSR; /* Auxiliary Fault Status Register */ volatile uint32_t PFR[2U]; /* Processor Feature Register */ volatile uint32_t DFR; /* Debug Feature Register */ volatile uint32_t ADR; /* Auxiliary Feature Register */ volatile uint32_t MMFR[4U]; /* Memory Model Feature Register */ volatile uint32_t ISAR[5U]; /* Instruction Set Attributes Register */ uint32_t RESERVED0[5U]; volatile uint32_t CPACR; /* Coprocessor Access Control Register */ }; /* SCB:SCR register bits */ #define SCB_SCR_SLEEPDEEP_POS 2U #define SCB_SCR_SLEEPDEEP_MSK (1UL << SCB_SCR_SLEEPDEEP_POS) /* Memory mapping of Core Hardware */ #define SCS_BASE (0xE000E000UL) /* System Control Space Base Address */ #define SCB_BASE (SCS_BASE + 0x0D00UL) /* System Control Block Base Address */ #define SCB ((struct SCB_Type *)SCB_BASE) /* SCB configuration struct */ /* Definitions of standard bits */ #define BIT0 (uint16_t)(0x0001) #define BIT1 (uint16_t)(0x0002) #define BIT2 (uint16_t)(0x0004) #define BIT3 (uint16_t)(0x0008) #define BIT4 (uint16_t)(0x0010) #define BIT5 (uint16_t)(0x0020) #define BIT6 (uint16_t)(0x0040) #define BIT7 (uint16_t)(0x0080) #define BIT8 (uint16_t)(0x0100) #define BIT9 (uint16_t)(0x0200) #define BITA (uint16_t)(0x0400) #define BITB (uint16_t)(0x0800) #define BITC (uint16_t)(0x1000) #define BITD (uint16_t)(0x2000) #define BITE (uint16_t)(0x4000) #define BITF (uint16_t)(0x8000) #define BIT(x) ((uint16_t)1 << (x)) /* CPU Module prototypes */ extern uint32_t cpu_cpsid(void); extern void cpu_wfi(void); /* Clock Signal Module constants */ #define CS_DCO_FREQUENCY_3 CS_CTL0_DCORSEL_1 #define CS_DCO_FREQUENCY_24 CS_CTL0_DCORSEL_4 /* Power Control Module constants */ #define PCM_KEY 0x695A0000 #define PCM_AM_LDO_VCORE0 0x00 #define PCM_AM_LDO_VCORE1 0x01 #define PCM_AM_DCDC_VCORE0 0x04 #define PCM_AM_DCDC_VCORE1 0x05 #define PCM_AM_LF_VCORE0 0x08 #define PCM_AM_LF_VCORE1 0x09 #define PCM_LPM0_LDO_VCORE0 0x10 #define PCM_LPM0_LDO_VCORE1 0x11 #define PCM_LPM0_DCDC_VCORE0 0x14 #define PCM_LPM0_DCDC_VCORE1 0x15 #define PCM_LPM0_LF_VCORE0 0x18 #define PCM_LPM0_LF_VCORE1 0x19 #define PCM_LPM3 0x20 #define PCM_LPM4 0x21 #define PCM_LPM35_VCORE0 0xC0 #define PCM_LPM45 0xA0 #define PCM_VCORE0 0x00 #define PCM_VCORE1 0x01 #define PCM_VCORELPM3 0x02 #define PCM_LDO_MODE 0x00 #define PCM_DCDC_MODE 0x01 #define PCM_LF_MODE 0x02 /* Power Control Module prototypes */ extern bool pcm_set_core_voltage_level(uint_fast8_t voltage_level); extern uint8_t pcm_get_core_voltage_level(void); extern bool pcm_set_power_mode(uint_fast8_t power_mode); extern uint8_t pcm_get_power_mode(void); extern bool pcm_set_power_state(uint_fast8_t power_state); extern uint8_t pcm_get_power_state(void); extern bool pcm_shutdown_device(uint32_t shutdown_mode); extern bool pcm_goto_lpm0(void); extern bool pcm_goto_lpm3(void); extern bool pcm_goto_lpm4(void); /* ROM API Function Pointers */ #define ROM_API_TABLE ((unsigned long *)0x02000800) #define ROM_FLASH_CTL_TABLE ((unsigned long *)(ROM_API_TABLE[7])) #define ROM_PCM_TABLE ((unsigned long *)(ROM_API_TABLE[13])) #define ROM_WDT_TABLE ((unsigned long *)(ROM_API_TABLE[25])) #define ROM_SYS_CTL_A_TABLE ((unsigned long *)(ROM_API_TABLE[26])) #define ROM_FLASH_CTL_A_TABLE ((unsigned long *)(ROM_API_TABLE[27])) #if defined(__MSP432P401X__) #define ROM_FLASH_CTL_UNPROTECT_SECTOR \ ((bool (*)(uint_fast8_t memory_space, \ uint32_t sector_mask))ROM_FLASH_CTL_TABLE[4]) #endif #if defined(__MSP432P401X__) #define ROM_FLASH_CTL_PROTECT_SECTOR \ ((bool (*)(uint_fast8_t memory_space, \ uint32_t sector_mask))ROM_FLASH_CTL_TABLE[5]) #endif #if defined(__MSP432P401X__) #define ROM_FLASH_CTL_PERFORM_MASS_ERASE \ ((bool (*)(void))ROM_FLASH_CTL_TABLE[8]) #endif #if defined(__MSP432P401X__) #define ROM_FLASH_CTL_ERASE_SECTOR \ ((bool (*)(uint32_t addr))ROM_FLASH_CTL_TABLE[9]) #endif #if defined(__MSP432P401X__) #define ROM_FLASH_CTL_PROGRAM_MEMORY \ ((bool (*)(void *src, void *dest, uint32_t length))ROM_FLASH_CTL_TABLE[10]) #endif #if defined(__MSP432P401X__) #define ROM_FLASH_CTL_SET_WAIT_STATE \ ((void (*)(uint32_t bank, uint32_t wait_state))ROM_FLASH_CTL_TABLE[21]) #endif #if defined(__MSP432P401X__) #define ROM_FLASH_CTL_GET_WAIT_STATE \ ((uint32_t (*)(uint32_t bank))ROM_FLASH_CTL_TABLE[22]) #endif #if defined(__MSP432P401X__) #define ROM_PCM_SET_CORE_VOLTAGE_LEVEL \ ((bool (*)(uint_fast8_t voltage_level))ROM_PCM_TABLE[0]) #endif #if defined(__MSP432P401X__) #define ROM_PCM_GET_CORE_VOLTAGE_LEVEL \ ((uint8_t (*)(void))ROM_PCM_TABLE[1]) #endif #if defined(__MSP432P401X__) #define ROM_PCM_SET_POWER_STATE \ ((bool (*)(uint_fast8_t power_state))ROM_PCM_TABLE[6]) #endif #if defined(__MSP432P401X__) #define ROM_PCM_GET_POWER_STATE \ ((uint8_t (*)(void))ROM_PCM_TABLE[8]) #endif #if defined(__MSP432P401X__) || defined(__MSP432P411X__) #define ROM_WDT_A_HOLD_TIMER \ ((void (*)(void))ROM_WDT_TABLE[0]) #endif #if defined(__MSP432P411X__) #define ROM_SYS_CTL_A_GET_FLASH_SIZE \ ((uint_least32_t (*)(void))ROM_SYS_CTL_A_TABLE[1]) #endif #if defined(__MSP432P411X__) #define ROM_SYS_CTL_A_GET_INFO_FLASH_SIZE \ ((uint_least32_t (*)(void))ROM_SYS_CTL_A_TABLE[18]) #endif #if defined(__MSP432P411X__) #define ROM_FLASH_CTL_A_UNPROTECT_MEMORY \ ((bool (*)(uint32_t start_addr, uint32_t end_addr))ROM_FLASH_CTL_A_TABLE[4]) #endif #if defined(__MSP432P411X__) #define ROM_FLASH_CTL_A_PROTECT_MEMORY \ ((bool (*)(uint32_t start_addr, uint32_t end_addr))ROM_FLASH_CTL_A_TABLE[5]) #endif #if defined(__MSP432P411X__) #define ROM_FLASH_CTL_A_PERFORM_MASS_ERASE \ ((bool (*)(void))ROM_FLASH_CTL_A_TABLE[8]) #endif #if defined(__MSP432P411X__) #define ROM_FLASH_CTL_A_ERASE_SECTOR \ ((bool (*)(uint32_t addr))ROM_FLASH_CTL_A_TABLE[9]) #endif #if defined(__MSP432P411X__) #define ROM_FLASH_CTL_A_PROGRAM_MEMORY \ ((bool (*)(void *src, void *dest, uint32_t length)) \ ROM_FLASH_CTL_A_TABLE[10]) #endif #if defined(__MSP432P411X__) #define ROM_FLASH_CTL_A_SET_WAIT_STATE \ ((void (*)(uint32_t bank, uint32_t wait_state))ROM_FLASH_CTL_A_TABLE[21]) #endif #if defined(__MSP432P411X__) #define ROM_FLASH_CTL_A_GET_WAIT_STATE \ ((uint32_t (*)(uint32_t bank))ROM_FLASH_CTL_A_TABLE[22]) #endif /* Map API functions to ROM or locally built functions */ #ifdef ROM_FLASH_CTL_UNPROTECT_SECTOR #define MAP_FLASH_CTL_UNPROTECT_SECTOR ROM_FLASH_CTL_UNPROTECT_SECTOR #else #define MAP_FLASH_CTL_UNPROTECT_SECTOR flash_ctl_unprotect_sector #endif #ifdef ROM_FLASH_CTL_PROTECT_SECTOR #define MAP_FLASH_CTL_PROTECT_SECTOR ROM_FLASH_CTL_PROTECT_SECTOR #else #define MAP_FLASH_CTL_PROTECT_SECTOR flash_ctl_protect_sector #endif #ifdef ROM_FLASH_CTL_PERFORM_MASS_ERASE #define MAP_FLASH_CTL_PERFORM_MASS_ERASE ROM_FLASH_CTL_PERFORM_MASS_ERASE #else #define MAP_FLASH_CTL_PERFORM_MASS_ERASE flash_ctl_perform_mass_erase #endif #ifdef ROM_FLASH_CTL_ERASE_SECTOR #define MAP_FLASH_CTL_ERASE_SECTOR ROM_FLASH_CTL_ERASE_SECTOR #else #define MAP_FLASH_CTL_ERASE_SECTOR flash_ctl_erase_sector #endif #ifdef ROM_FLASH_CTL_PROGRAM_MEMORY #define MAP_FLASH_CTL_PROGRAM_MEMORY ROM_FLASH_CTL_PROGRAM_MEMORY #else #define MAP_FLASH_CTL_PROGRAM_MEMORY flash_ctl_program_memory #endif #ifdef ROM_FLASH_CTL_SET_WAIT_STATE #define MAP_FLASH_CTL_SET_WAIT_STATE ROM_FLASH_CTL_SET_WAIT_STATE #else #define MAP_FLASH_CTL_SET_WAIT_STATE flash_ctl_set_wait_state #endif #ifdef ROM_FLASH_CTL_GET_WAIT_STATE #define MAP_FLASH_CTL_GET_WAIT_STATE ROM_FLASH_CTL_GET_WAIT_STATE #else #define MAP_FLASH_CTL_GET_WAIT_STATE flash_ctl_get_wait_state #endif #ifdef ROM_PCM_SET_CORE_VOLTAGE_LEVEL #define MAP_PCM_SET_CORE_VOLTAGE_LEVEL ROM_PCM_SET_CORE_VOLTAGE_LEVEL #else #define MAP_PCM_SET_CORE_VOLTAGE_LEVEL pcm_set_core_voltage_level #endif #ifdef ROM_PCM_GET_CORE_VOLTAGE_LEVEL #define MAP_PCM_GET_CORE_VOLTAGE_LEVEL ROM_PCM_GET_CORE_VOLTAGE_LEVEL #else #define MAP_PCM_GET_CORE_VOLTAGE_LEVEL pcm_get_core_voltage_level #endif #ifdef ROM_PCM_SET_POWER_STATE #define MAP_PCM_SET_POWER_STATE ROM_PCM_SET_POWER_STATE #else #define MAP_PCM_SET_POWER_STATE pcm_set_power_state #endif #ifdef ROM_PCM_GET_POWER_STATE #define MAP_PCM_GET_POWER_STATE ROM_PCM_GET_POWER_STATE #else #define MAP_PCM_GET_POWER_STATE pcm_get_power_state #endif #ifdef ROM_WDT_A_HOLD_TIMER #define MAP_WDT_A_HOLD_TIMER ROM_WDT_A_HOLD_TIMER #else #define MAP_WDT_A_HOLD_TIMER wdt_a_hold_timer #endif #ifdef ROM_SYS_CTL_A_GET_FLASH_SIZE #define MAP_SYS_CTL_A_GET_FLASH_SIZE ROM_SYS_CTL_A_GET_FLASH_SIZE #else #define MAP_SYS_CTL_A_GET_FLASH_SIZE sys_ctl_a_get_flash_size #endif #ifdef ROM_SYS_CTL_A_GET_INFO_FLASH_SIZE #define MAP_SYS_CTL_A_GET_INFO_FLASH_SIZE ROM_SYS_CTL_A_GET_INFO_FLASH_SIZE #else #define MAP_SYS_CTL_A_GET_INFO_FLASH_SIZE sys_ctl_a_get_info_flash_size #endif #ifdef ROM_FLASH_CTL_A_UNPROTECT_MEMORY #define MAP_FLASH_CTL_A_UNPROTECT_MEMORY ROM_FLASH_CTL_A_UNPROTECT_MEMORY #else #define MAP_FLASH_CTL_A_UNPROTECT_MEMORY flash_ctl_a_unprotect_memory #endif #ifdef ROM_FLASH_CTL_A_PROTECT_MEMORY #define MAP_FLASH_CTL_A_PROTECT_MEMORY ROM_FLASH_CTL_A_PROTECT_MEMORY #else #define MAP_FLASH_CTL_A_PROTECT_MEMORY flash_ctl_a_protect_memory #endif #ifdef ROM_FLASH_CTL_A_PERFORM_MASS_ERASE #define MAP_FLASH_CTL_A_PERFORM_MASS_ERASE ROM_FLASH_CTL_A_PERFORM_MASS_ERASE #else #define MAP_FLASH_CTL_A_PERFORM_MASS_ERASE flash_ctl_a_perform_mass_erase #endif #ifdef ROM_FLASH_CTL_A_ERASE_SECTOR #define MAP_FLASH_CTL_A_ERASE_SECTOR ROM_FLASH_CTL_A_ERASE_SECTOR #else #define MAP_FLASH_CTL_A_ERASE_SECTOR flash_ctl_a_erase_sector #endif #ifdef ROM_FLASH_CTL_A_PROGRAM_MEMORY #define MAP_FLASH_CTL_A_PROGRAM_MEMORY ROM_FLASH_CTL_A_PROGRAM_MEMORY #else #define MAP_FLASH_CTL_A_PROGRAM_MEMORY flash_ctl_a_program_memory #endif #ifdef ROM_FLASH_CTL_A_SET_WAIT_STATE #define MAP_FLASH_CTL_A_SET_WAIT_STATE ROM_FLASH_CTL_A_SET_WAIT_STATE #else #define MAP_FLASH_CTL_A_SET_WAIT_STATE flash_ctl_a_set_wait_state #endif #ifdef ROM_FLASH_CTL_A_GET_WAIT_STATE #define MAP_FLASH_CTL_A_GET_WAIT_STATE ROM_FLASH_CTL_A_GET_WAIT_STATE #else #define MAP_FLASH_CTL_A_GET_WAIT_STATE flash_ctl_a_get_wait_state #endif /* Real Time Clock Module prototypes */ extern void rtc_c_hold_clock(void); /* Watchdog Timer Module prototypes */ extern void wdt_a_hold_timer(void); #if defined(__MCU_HAS_FLCTL_A__) #define FLASH_A_BANK0 0x00 #define FLASH_A_BANK1 0x01 #define __INFO_FLASH_A_TECH_START__ 0x00200000 #define __INFO_FLASH_A_TECH_MIDDLE__ 0x00204000 #endif #if defined(__MCU_HAS_FLCTL__) #define FLASH_BANK0 0x00 #define FLASH_BANK1 0x01 #define FLASH_MAIN_MEMORY_SPACE_BANK0 0x01 #define FLASH_MAIN_MEMORY_SPACE_BANK1 0x02 #define FLASH_INFO_MEMORY_SPACE_BANK0 0x03 #define FLASH_INFO_MEMORY_SPACE_BANK1 0x04 #define FLASH_SECTOR0 FLCTL_BANK0_MAIN_WEPROT_PROT0 #define FLASH_SECTOR1 FLCTL_BANK0_MAIN_WEPROT_PROT1 #endif #ifdef __cplusplus } #endif #endif /* OPENOCD_LOADERS_FLASH_MSP432_DRIVERLIB_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/main_msp432e4x.c ================================================ // SPDX-License-Identifier: BSD-3-Clause /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #include #include #include "driverlib.h" #include "MSP432E4_FlashLibIf.h" /* Local prototypes */ void msp432_flash_init(void); void msp432_flash_mass_erase(void); void msp432_flash_sector_erase(void); void msp432_flash_write(void); void msp432_flash_continous_write(void); void msp432_flash_exit(void); int main(void) { /* Disable interrupts */ __asm(" cpsid i"); /* Halt watchdog */ SYSCTL->RCGCWD &= ~(SYSCTL_RCGCWD_R1 + SYSCTL_RCGCWD_R0); while (1) { switch (FLASH_LOADER->FLASH_FUNCTION) { case FLASH_INIT: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_init(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_MASS_ERASE: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_mass_erase(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_SECTOR_ERASE: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_sector_erase(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_PROGRAM: case FLASH_CONTINUOUS_PROGRAM: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_continous_write(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_EXIT: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_exit(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_NO_COMMAND: break; default: FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; break; } } } /* Initialize flash */ void msp432_flash_init(void) { SCB->VTOR = 0x20000000; FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; } /* Erase entire flash */ void msp432_flash_mass_erase(void) { bool success = false; /* Clear the flash access and error interrupts. */ FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC | FLASH_FCMISC_ERMISC | FLASH_FCMISC_PMISC); /* Trigger mass erase */ FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_MERASE; while (FLASH_CTRL->FMC & FLASH_FMC_MERASE) ; /* Return an error if an access violation occurred. */ success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS | FLASH_FCRIS_ERRIS)); if (!success) FLASH_LOADER->RETURN_CODE = FLASH_VERIFY_ERROR; else FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; } /* Erase one flash sector */ void msp432_flash_sector_erase(void) { bool success = false; /* Clear the flash access and error interrupts. */ FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC | FLASH_FCMISC_ERMISC | FLASH_FCMISC_PMISC); /* Set 16kB aligned flash page address to be erased (16kB block) */ FLASH_CTRL->FMA = FLASH_LOADER->DST_ADDRESS; /* Trigger sector erase (erase flash page) */ FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_ERASE; while (FLASH_CTRL->FMC & FLASH_FMC_ERASE) ; /* Return an error if an access violation occurred. */ success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS | FLASH_FCRIS_ERRIS)); if (!success) FLASH_LOADER->RETURN_CODE = FLASH_ERROR; else FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; } /* Write data to flash */ void msp432_flash_continous_write(void) { bool buffer1_in_use = false; bool buffer2_in_use = false; uint32_t *src_address = NULL; bool success = true; uint32_t i = 0; uint32_t address = FLASH_LOADER->DST_ADDRESS; uint32_t data_to_write = FLASH_LOADER->SRC_LENGTH; int32_t write_package = 0; /* Clear the flash access and error interrupts. */ FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC | FLASH_FCMISC_INVDMISC | FLASH_FCMISC_PROGMISC | FLASH_FCMISC_PMISC); do { if (data_to_write > SRC_LENGTH_MAX) { write_package = SRC_LENGTH_MAX; data_to_write -= write_package; } else { write_package = data_to_write; data_to_write -= write_package; } while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) && !(FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY)) ; if (FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) { FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE; src_address = (uint32_t *) RAM_LOADER_BUFFER1; buffer1_in_use = true; } else if (FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY) { FLASH_LOADER->BUFFER2_STATUS_REGISTER |= BUFFER_ACTIVE; src_address = (uint32_t *) RAM_LOADER_BUFFER2; buffer2_in_use = true; } /* * The flash hardware can only write complete words to flash. If * an unaligned address is passed in, we must do a read-modify-write * on a word with enough bytes to align the rest of the buffer. And * if less than a whole word remains at the end, we must also do a * read-modify-write on a final word to finish up. */ if (0 != (address & 0x3)) { uint32_t head; uint8_t *ui8head = (uint8_t *)&head; uint8_t *buffer = (uint8_t *)src_address; /* Get starting offset for data to write (will be 1 to 3) */ uint32_t head_offset = address & 0x03; /* Get the aligned address to write this first word to */ uint32_t head_address = address & 0xfffffffc; /* Retrieve what is already in flash at the head address */ head = *(uint32_t *)head_address; /* Substitute in the new data to write */ while ((write_package > 0) && (head_offset < 4)) { ui8head[head_offset] = *buffer; head_offset++; address++; buffer++; write_package--; } src_address = (uint32_t *)buffer; FLASH_CTRL->FMD = head; FLASH_CTRL->FMA = head_address; FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE; /* Wait until the word has been programmed. */ while (FLASH_CTRL->FMC & FLASH_FMC_WRITE) ; /* Return an error if an access violation occurred. */ success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS)); } /* Program a word at a time until aligned on 32-word boundary */ while ((write_package >= 4) && ((address & 0x7f) != 0) && success) { FLASH_CTRL->FMD = *src_address++; FLASH_CTRL->FMA = address; FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE; /* Wait until the word has been programmed. */ while (FLASH_CTRL->FMC & FLASH_FMC_WRITE) ; /* Prepare for next word to write */ write_package -= 4; address += 4; /* Return an error if an access violation occurred. */ success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS)); } /* Program data in 32-word blocks */ while ((write_package >= 32) && success) { /* Loop over the words in this 32-word block. */ i = 0; do { FLASH_CTRL->FWBN[i] = *src_address++; write_package -= 4; i++; } while ((write_package > 0) && (i < 32)); FLASH_CTRL->FMA = address; FLASH_CTRL->FMC2 = FLASH_FMC_WRKEY | FLASH_FMC2_WRBUF; /* Wait until the write buffer has been programmed. */ while (FLASH_CTRL->FMC2 & FLASH_FMC2_WRBUF) ; /* Increment destination address by words written */ address += 128; /* Return an error if an access violation occurred. */ success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS)); } /* Program a word at a time on left over data */ while ((write_package >= 4) && success) { FLASH_CTRL->FMD = *src_address++; FLASH_CTRL->FMA = address; FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE; /* Wait until the word has been programmed. */ while (FLASH_CTRL->FMC & FLASH_FMC_WRITE) ; /* Prepare for next word to write */ write_package -= 4; address += 4; /* Return an error if an access violation occurred. */ success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS)); } if ((write_package > 0) && success) { uint32_t tail; uint8_t *ui8tail = (uint8_t *)&tail; uint8_t *buffer = (uint8_t *)src_address; /* Set starting offset for data to write */ uint32_t tail_offset = 0; /* Get the address to write this last word to */ uint32_t tail_address = address; /* Retrieve what is already in flash at the tail address */ tail = *(uint32_t *)address; /* Substitute in the new data to write */ while (write_package > 0) { ui8tail[tail_offset] = *buffer; tail_offset++; address++; buffer++; write_package--; } FLASH_CTRL->FMD = tail; FLASH_CTRL->FMA = tail_address; FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE; /* Wait until the word has been programmed. */ while (FLASH_CTRL->FMC & FLASH_FMC_WRITE) ; /* Return an error if an access violation occurred. */ success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS)); } if (buffer1_in_use) { FLASH_LOADER->BUFFER1_STATUS_REGISTER &= ~(BUFFER_ACTIVE | BUFFER_DATA_READY); buffer1_in_use = false; } else if (buffer2_in_use) { FLASH_LOADER->BUFFER2_STATUS_REGISTER &= ~(BUFFER_ACTIVE | BUFFER_DATA_READY); buffer2_in_use = false; } } while (success && data_to_write); if (!success) FLASH_LOADER->RETURN_CODE = FLASH_ERROR; else FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; } /* Exit flash programming */ void msp432_flash_exit(void) { SCB->VTOR = 0x00000000; FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/main_msp432p401x.c ================================================ // SPDX-License-Identifier: BSD-3-Clause /****************************************************************************** * * Copyright (C) 2013-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #include #include #include "driverlib.h" #include "MSP432P4_FlashLibIf.h" /* Number of erase repeats until timeout */ #define FLASH_MAX_REPEATS 5 /* Local prototypes */ void msp432_flash_init(void); void msp432_flash_mass_erase(void); void msp432_flash_sector_erase(void); void msp432_flash_write(void); void msp432_flash_continous_write(void); void msp432_flash_exit(void); void unlock_flash_sectors(void); void unlock_all_flash_sectors(void); void lock_all_flash_sectors(void); void __cs_set_dco_frequency_range(uint32_t dco_freq); static bool program_device(void *src, void *dest, uint32_t length); struct backup_params { uint32_t BANK0_WAIT_RESTORE; uint32_t BANK1_WAIT_RESTORE; uint32_t CS_DC0_FREQ_RESTORE; uint8_t VCORE_LEVEL_RESTORE; uint8_t PCM_VCORE_LEVEL_RESTORE; }; #define BACKUP_PARAMS ((struct backup_params *) 0x20000180) /* Main with trampoline */ int main(void) { /* Halt watchdog */ MAP_WDT_A_HOLD_TIMER(); /* Disable interrupts */ cpu_cpsid(); while (1) { switch (FLASH_LOADER->FLASH_FUNCTION) { case FLASH_INIT: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_init(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_MASS_ERASE: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_mass_erase(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_SECTOR_ERASE: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_sector_erase(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_PROGRAM: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_write(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_CONTINUOUS_PROGRAM: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_continous_write(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_EXIT: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_exit(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_NO_COMMAND: break; default: FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; break; } } } /* Initialize flash */ void msp432_flash_init(void) { bool success = false; /* Point to vector table in RAM */ SCB->VTOR = (uint32_t)0x01000000; /* backup system parameters */ BACKUP_PARAMS->BANK0_WAIT_RESTORE = MAP_FLASH_CTL_GET_WAIT_STATE(FLASH_BANK0); BACKUP_PARAMS->BANK1_WAIT_RESTORE = MAP_FLASH_CTL_GET_WAIT_STATE(FLASH_BANK1); BACKUP_PARAMS->VCORE_LEVEL_RESTORE = MAP_PCM_GET_CORE_VOLTAGE_LEVEL(); BACKUP_PARAMS->PCM_VCORE_LEVEL_RESTORE = MAP_PCM_GET_POWER_STATE(); BACKUP_PARAMS->CS_DC0_FREQ_RESTORE = CS->CTL0 & CS_CTL0_DCORSEL_MASK; /* set parameters for flashing */ success = MAP_PCM_SET_POWER_STATE(PCM_AM_LDO_VCORE0); /* Set Flash wait states to 2 */ MAP_FLASH_CTL_SET_WAIT_STATE(FLASH_BANK0, 2); MAP_FLASH_CTL_SET_WAIT_STATE(FLASH_BANK1, 2); /* Set CPU speed to 24MHz */ __cs_set_dco_frequency_range(CS_DCO_FREQUENCY_24); if (!success) { /* Indicate failed power switch */ FLASH_LOADER->RETURN_CODE = FLASH_POWER_ERROR; } else FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; } /* Erase entire flash */ void msp432_flash_mass_erase(void) { bool success = false; /* Allow flash writes */ unlock_flash_sectors(); /* Allow some mass erase repeats before timeout with error */ int erase_repeats = FLASH_MAX_REPEATS; while (!success && (erase_repeats > 0)) { /* Mass erase with post-verify */ success = MAP_FLASH_CTL_PERFORM_MASS_ERASE(); erase_repeats--; } if (erase_repeats == 0) FLASH_LOADER->RETURN_CODE = FLASH_VERIFY_ERROR; else FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; /* Block flash writes */ lock_all_flash_sectors(); } /* Erase one flash sector */ void msp432_flash_sector_erase(void) { bool success = false; /* Allow flash writes */ unlock_all_flash_sectors(); /* Allow some sector erase repeats before timeout with error */ int erase_repeats = FLASH_MAX_REPEATS; while (!success && (erase_repeats > 0)) { /* Sector erase with post-verify */ success = MAP_FLASH_CTL_ERASE_SECTOR(FLASH_LOADER->DST_ADDRESS); erase_repeats--; } if (erase_repeats == 0) FLASH_LOADER->RETURN_CODE = FLASH_ERROR; else FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; /* Block flash writes */ lock_all_flash_sectors(); } /* Write data to flash with the help of DriverLib */ void msp432_flash_write(void) { bool success = false; /* Allow flash writes */ unlock_all_flash_sectors(); while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY)) ; FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE; /* Program memory */ success = program_device((uint32_t *)RAM_LOADER_BUFFER1, (void *)FLASH_LOADER->DST_ADDRESS, FLASH_LOADER->SRC_LENGTH); FLASH_LOADER->BUFFER1_STATUS_REGISTER &= ~(BUFFER_ACTIVE | BUFFER_DATA_READY); /* Block flash writes */ lock_all_flash_sectors(); if (!success) FLASH_LOADER->RETURN_CODE = FLASH_ERROR; else FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; } /* Write data to flash with the help of DriverLib with auto-increment */ void msp432_flash_continous_write(void) { bool buffer1_in_use = false; bool buffer2_in_use = false; uint32_t *src_address = NULL; bool success = false; uint32_t bytes_to_write = FLASH_LOADER->SRC_LENGTH; uint32_t write_package = 0; uint32_t start_addr = FLASH_LOADER->DST_ADDRESS; while (bytes_to_write > 0) { if (bytes_to_write > SRC_LENGTH_MAX) { write_package = SRC_LENGTH_MAX; bytes_to_write -= write_package; } else { write_package = bytes_to_write; bytes_to_write -= write_package; } unlock_all_flash_sectors(); while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) && !(FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY)) ; if (FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) { FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE; src_address = (uint32_t *)RAM_LOADER_BUFFER1; buffer1_in_use = true; } else if (FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY) { FLASH_LOADER->BUFFER2_STATUS_REGISTER |= BUFFER_ACTIVE; src_address = (uint32_t *)RAM_LOADER_BUFFER2; buffer2_in_use = true; } if (buffer1_in_use || buffer2_in_use) { success = program_device(src_address, (void *)start_addr, write_package); if (buffer1_in_use) P6->OUT &= ~BIT4; /* Program from B1 */ else if (buffer2_in_use) P3->OUT &= ~BIT6; /* Program from B1 */ start_addr += write_package; } if (buffer1_in_use) { FLASH_LOADER->BUFFER1_STATUS_REGISTER &= ~(BUFFER_ACTIVE | BUFFER_DATA_READY); buffer1_in_use = false; } else if (buffer2_in_use) { FLASH_LOADER->BUFFER2_STATUS_REGISTER &= ~(BUFFER_ACTIVE | BUFFER_DATA_READY); buffer2_in_use = false; } /* Block flash writes */ lock_all_flash_sectors(); if (!success) { FLASH_LOADER->RETURN_CODE = FLASH_ERROR; break; } } if (success) FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; } /* Unlock Main/Info Flash sectors */ void unlock_flash_sectors(void) { if (FLASH_LOADER->ERASE_PARAM & ERASE_MAIN) { MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_MAIN_MEMORY_SPACE_BANK0, 0xFFFFFFFF); MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_MAIN_MEMORY_SPACE_BANK1, 0xFFFFFFFF); } if (FLASH_LOADER->ERASE_PARAM & ERASE_INFO) { MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_INFO_MEMORY_SPACE_BANK0, FLASH_SECTOR0 | FLASH_SECTOR1); if (FLASH_LOADER->UNLOCK_BSL == UNLOCK_BSL_KEY) MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_INFO_MEMORY_SPACE_BANK1, FLASH_SECTOR0 | FLASH_SECTOR1); } } /* Unlock All Flash sectors */ void unlock_all_flash_sectors(void) { MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_MAIN_MEMORY_SPACE_BANK0, 0xFFFFFFFF); MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_MAIN_MEMORY_SPACE_BANK1, 0xFFFFFFFF); MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_INFO_MEMORY_SPACE_BANK0, FLASH_SECTOR0 | FLASH_SECTOR1); if (FLASH_LOADER->UNLOCK_BSL == UNLOCK_BSL_KEY) MAP_FLASH_CTL_UNPROTECT_SECTOR(FLASH_INFO_MEMORY_SPACE_BANK1, FLASH_SECTOR0 | FLASH_SECTOR1); } /* Lock all Flash sectors */ void lock_all_flash_sectors(void) { MAP_FLASH_CTL_PROTECT_SECTOR(FLASH_MAIN_MEMORY_SPACE_BANK0, 0xFFFFFFFF); MAP_FLASH_CTL_PROTECT_SECTOR(FLASH_MAIN_MEMORY_SPACE_BANK1, 0xFFFFFFFF); MAP_FLASH_CTL_PROTECT_SECTOR(FLASH_INFO_MEMORY_SPACE_BANK0, FLASH_SECTOR0 | FLASH_SECTOR1); MAP_FLASH_CTL_PROTECT_SECTOR(FLASH_INFO_MEMORY_SPACE_BANK1, FLASH_SECTOR0 | FLASH_SECTOR1); } /* Force DCO frequency range */ void __cs_set_dco_frequency_range(uint32_t dco_freq) { /* Unlocking the CS Module */ CS->KEY = CS_KEY_VAL; /* Resetting Tuning Parameters and Setting the frequency */ CS->CTL0 = (CS->CTL0 & ~CS_CTL0_DCORSEL_MASK) | dco_freq; /* Locking the CS Module */ CS->KEY = 0; } /* Exit flash programming */ void msp432_flash_exit(void) { bool success = false; /* Restore modified registers, in reverse order */ __cs_set_dco_frequency_range(CS_DCO_FREQUENCY_3); MAP_FLASH_CTL_SET_WAIT_STATE(FLASH_BANK0, BACKUP_PARAMS->BANK0_WAIT_RESTORE); MAP_FLASH_CTL_SET_WAIT_STATE(FLASH_BANK1, BACKUP_PARAMS->BANK1_WAIT_RESTORE); success = MAP_PCM_SET_POWER_STATE(BACKUP_PARAMS->PCM_VCORE_LEVEL_RESTORE); success &= MAP_PCM_SET_CORE_VOLTAGE_LEVEL( BACKUP_PARAMS->VCORE_LEVEL_RESTORE); __cs_set_dco_frequency_range(BACKUP_PARAMS->CS_DC0_FREQ_RESTORE); /* Point to vector table in Flash */ SCB->VTOR = (uint32_t)0x00000000; if (!success) FLASH_LOADER->RETURN_CODE = FLASH_ERROR; else FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; } static bool program_device(void *src, void *dest, uint32_t length) { return MAP_FLASH_CTL_PROGRAM_MEMORY(src, dest, length); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/main_msp432p411x.c ================================================ // SPDX-License-Identifier: BSD-3-Clause /****************************************************************************** * * Copyright (C) 2013-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #include #include #include "driverlib.h" #include "MSP432P4_FlashLibIf.h" /* Number of erase repeats until timeout */ #define FLASH_MAX_REPEATS 5 /* Local prototypes */ void msp432_flash_init(void); void msp432_flash_mass_erase(void); void msp432_flash_sector_erase(void); void msp432_flash_write(void); void msp432_flash_continous_write(void); void msp432_flash_exit(void); void unlock_flash_sectors(void); void unlock_all_flash_sectors(void); void lock_all_flash_sectors(void); void __cs_set_dco_frequency_range(uint32_t dco_freq); static bool program_device(void *src, void *dest, uint32_t length); struct backup_params { uint32_t BANK0_WAIT_RESTORE; uint32_t BANK1_WAIT_RESTORE; uint32_t CS_DC0_FREQ_RESTORE; uint8_t VCORE_LEVEL_RESTORE; uint8_t PCM_VCORE_LEVEL_RESTORE; }; #define BACKUP_PARAMS ((struct backup_params *) 0x20000180) #define INFO_FLASH_START __INFO_FLASH_A_TECH_START__ #define INFO_FLASH_MIDDLE __INFO_FLASH_A_TECH_MIDDLE__ #define BSL_FLASH_START BSL_API_TABLE_ADDR /* Main with trampoline */ int main(void) { /* Halt watchdog */ MAP_WDT_A_HOLD_TIMER(); /* Disable interrupts */ cpu_cpsid(); while (1) { switch (FLASH_LOADER->FLASH_FUNCTION) { case FLASH_INIT: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_init(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_MASS_ERASE: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_mass_erase(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_SECTOR_ERASE: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_sector_erase(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_PROGRAM: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_write(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_CONTINUOUS_PROGRAM: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_continous_write(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_EXIT: FLASH_LOADER->RETURN_CODE = FLASH_BUSY; msp432_flash_exit(); FLASH_LOADER->FLASH_FUNCTION = 0; break; case FLASH_NO_COMMAND: break; default: FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; break; } } } /* Initialize flash */ void msp432_flash_init(void) { bool success = false; /* Point to vector table in RAM */ SCB->VTOR = (uint32_t)0x01000000; /* backup system parameters */ BACKUP_PARAMS->BANK0_WAIT_RESTORE = MAP_FLASH_CTL_A_GET_WAIT_STATE(FLASH_A_BANK0); BACKUP_PARAMS->BANK1_WAIT_RESTORE = MAP_FLASH_CTL_A_GET_WAIT_STATE(FLASH_A_BANK1); BACKUP_PARAMS->VCORE_LEVEL_RESTORE = MAP_PCM_GET_CORE_VOLTAGE_LEVEL(); BACKUP_PARAMS->PCM_VCORE_LEVEL_RESTORE = MAP_PCM_GET_POWER_STATE(); BACKUP_PARAMS->CS_DC0_FREQ_RESTORE = CS->CTL0 & CS_CTL0_DCORSEL_MASK; /* set parameters for flashing */ success = MAP_PCM_SET_POWER_STATE(PCM_AM_LDO_VCORE0); /* Set Flash wait states to 2 */ MAP_FLASH_CTL_A_SET_WAIT_STATE(FLASH_A_BANK0, 2); MAP_FLASH_CTL_A_SET_WAIT_STATE(FLASH_A_BANK1, 2); /* Set CPU speed to 24MHz */ __cs_set_dco_frequency_range(CS_DCO_FREQUENCY_24); if (!success) { /* Indicate failed power switch */ FLASH_LOADER->RETURN_CODE = FLASH_POWER_ERROR; } else FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; } /* Erase entire flash */ void msp432_flash_mass_erase(void) { bool success = false; /* Allow flash writes */ unlock_flash_sectors(); /* Allow some mass erase repeats before timeout with error */ int erase_repeats = FLASH_MAX_REPEATS; while (!success && (erase_repeats > 0)) { /* Mass erase with post-verify */ success = ROM_FLASH_CTL_A_PERFORM_MASS_ERASE(); erase_repeats--; } if (erase_repeats == 0) FLASH_LOADER->RETURN_CODE = FLASH_VERIFY_ERROR; else FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; /* Block flash writes */ lock_all_flash_sectors(); } /* Erase one flash sector */ void msp432_flash_sector_erase(void) { bool success = false; /* Allow flash writes */ unlock_all_flash_sectors(); /* Allow some sector erase repeats before timeout with error */ int erase_repeats = FLASH_MAX_REPEATS; while (!success && (erase_repeats > 0)) { /* Sector erase with post-verify */ success = MAP_FLASH_CTL_A_ERASE_SECTOR(FLASH_LOADER->DST_ADDRESS); erase_repeats--; } if (erase_repeats == 0) FLASH_LOADER->RETURN_CODE = FLASH_ERROR; else FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; /* Block flash writes */ lock_all_flash_sectors(); } /* Write data to flash with the help of DriverLib */ void msp432_flash_write(void) { bool success = false; /* Allow flash writes */ unlock_all_flash_sectors(); while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY)) ; FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE; /* Program memory */ success = program_device((uint32_t *)RAM_LOADER_BUFFER1, (void *)FLASH_LOADER->DST_ADDRESS, FLASH_LOADER->SRC_LENGTH); FLASH_LOADER->BUFFER1_STATUS_REGISTER &= ~(BUFFER_ACTIVE | BUFFER_DATA_READY); /* Block flash writes */ lock_all_flash_sectors(); if (!success) FLASH_LOADER->RETURN_CODE = FLASH_ERROR; else FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; } /* Write data to flash with the help of DriverLib with auto-increment */ void msp432_flash_continous_write(void) { bool buffer1_in_use = false; bool buffer2_in_use = false; uint32_t *src_address = NULL; bool success = false; uint32_t bytes_to_write = FLASH_LOADER->SRC_LENGTH; uint32_t write_package = 0; uint32_t start_addr = FLASH_LOADER->DST_ADDRESS; while (bytes_to_write > 0) { if (bytes_to_write > SRC_LENGTH_MAX) { write_package = SRC_LENGTH_MAX; bytes_to_write -= write_package; } else { write_package = bytes_to_write; bytes_to_write -= write_package; } unlock_all_flash_sectors(); while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) && !(FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY)) ; if (FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) { FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE; src_address = (uint32_t *) RAM_LOADER_BUFFER1; buffer1_in_use = true; } else if (FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY) { FLASH_LOADER->BUFFER2_STATUS_REGISTER |= BUFFER_ACTIVE; src_address = (uint32_t *) RAM_LOADER_BUFFER2; buffer2_in_use = true; } if (buffer1_in_use || buffer2_in_use) { success = program_device(src_address, (void *) start_addr, write_package); start_addr += write_package; } if (buffer1_in_use) { FLASH_LOADER->BUFFER1_STATUS_REGISTER &= ~(BUFFER_ACTIVE | BUFFER_DATA_READY); buffer1_in_use = false; } else if (buffer2_in_use) { FLASH_LOADER->BUFFER2_STATUS_REGISTER &= ~(BUFFER_ACTIVE | BUFFER_DATA_READY); buffer2_in_use = false; } /* Block flash writes */ lock_all_flash_sectors(); if (!success) { FLASH_LOADER->RETURN_CODE = FLASH_ERROR; break; } } if (success) FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; } /* Unlock Main/Info Flash sectors */ void unlock_flash_sectors(void) { if (FLASH_LOADER->ERASE_PARAM & ERASE_MAIN) MAP_FLASH_CTL_A_UNPROTECT_MEMORY(FLASH_BASE, FLASH_BASE + MAP_SYS_CTL_A_GET_FLASH_SIZE() - 1); if (FLASH_LOADER->ERASE_PARAM & ERASE_INFO) { MAP_FLASH_CTL_A_UNPROTECT_MEMORY(INFO_FLASH_START, TLV_BASE - 1); if (FLASH_LOADER->UNLOCK_BSL == UNLOCK_BSL_KEY) MAP_FLASH_CTL_A_UNPROTECT_MEMORY(BSL_FLASH_START, INFO_FLASH_MIDDLE - 1); MAP_FLASH_CTL_A_UNPROTECT_MEMORY(INFO_FLASH_MIDDLE, INFO_FLASH_MIDDLE + MAP_SYS_CTL_A_GET_INFO_FLASH_SIZE() - 1); } } /* Unlock All Flash sectors */ void unlock_all_flash_sectors(void) { MAP_FLASH_CTL_A_UNPROTECT_MEMORY(FLASH_BASE, FLASH_BASE + MAP_SYS_CTL_A_GET_FLASH_SIZE() - 1); MAP_FLASH_CTL_A_UNPROTECT_MEMORY(INFO_FLASH_START, TLV_BASE - 1); if (FLASH_LOADER->UNLOCK_BSL == UNLOCK_BSL_KEY) MAP_FLASH_CTL_A_UNPROTECT_MEMORY(BSL_FLASH_START, INFO_FLASH_MIDDLE - 1); MAP_FLASH_CTL_A_UNPROTECT_MEMORY(INFO_FLASH_MIDDLE, INFO_FLASH_MIDDLE + MAP_SYS_CTL_A_GET_INFO_FLASH_SIZE() - 1); } /* Lock all Flash sectors */ void lock_all_flash_sectors(void) { MAP_FLASH_CTL_A_PROTECT_MEMORY(FLASH_BASE, FLASH_BASE + MAP_SYS_CTL_A_GET_FLASH_SIZE() - 1); MAP_FLASH_CTL_A_PROTECT_MEMORY(INFO_FLASH_START, INFO_FLASH_START + MAP_SYS_CTL_A_GET_INFO_FLASH_SIZE() - 1); } /* Force DCO frequency range */ void __cs_set_dco_frequency_range(uint32_t dco_freq) { /* Unlocking the CS Module */ CS->KEY = CS_KEY_VAL; /* Resetting Tuning Parameters and Setting the frequency */ CS->CTL0 = (CS->CTL0 & ~CS_CTL0_DCORSEL_MASK) | dco_freq; /* Locking the CS Module */ CS->KEY = 0; } /* Exit flash programming */ void msp432_flash_exit(void) { bool success = false; /* Restore modified registers, in reverse order */ __cs_set_dco_frequency_range(CS_DCO_FREQUENCY_3); MAP_FLASH_CTL_A_SET_WAIT_STATE(FLASH_A_BANK0, BACKUP_PARAMS->BANK0_WAIT_RESTORE); MAP_FLASH_CTL_A_SET_WAIT_STATE(FLASH_A_BANK1, BACKUP_PARAMS->BANK1_WAIT_RESTORE); success = MAP_PCM_SET_POWER_STATE(BACKUP_PARAMS->PCM_VCORE_LEVEL_RESTORE); success &= MAP_PCM_SET_CORE_VOLTAGE_LEVEL( BACKUP_PARAMS->VCORE_LEVEL_RESTORE); __cs_set_dco_frequency_range(BACKUP_PARAMS->CS_DC0_FREQ_RESTORE); /* Point to vector table in Flash */ SCB->VTOR = (uint32_t)0x00000000; if (!success) FLASH_LOADER->RETURN_CODE = FLASH_ERROR; else FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS; } static bool program_device(void *src, void *dest, uint32_t length) { uint32_t dst_address = (uint32_t)dest; /* Flash main memory first, then information memory */ if ((dst_address < INFO_FLASH_START) && ((dst_address + length) > INFO_FLASH_START)) { uint32_t block_length = INFO_FLASH_START - dst_address; uint32_t src_address = (uint32_t)src; /* Main memory block */ bool success = MAP_FLASH_CTL_A_PROGRAM_MEMORY(src, dest, block_length); src_address = src_address + block_length; block_length = length - block_length; /* Information memory block */ success &= MAP_FLASH_CTL_A_PROGRAM_MEMORY((void *)src_address, (void *)INFO_FLASH_START, block_length); return success; } else return MAP_FLASH_CTL_A_PROGRAM_MEMORY(src, dest, length); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/msp432e4x/msp432e4x.lds ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ MEMORY { MAIN_FLASH (RX) : ORIGIN = 0x00000000, LENGTH = 0x00100000 SRAM_CODE_0(RWX): ORIGIN = 0x20000000, LENGTH = 0x00000110 SRAM_CODE_1(RWX): ORIGIN = 0x20000110, LENGTH = 0x00000030 SRAM_CODE_2(RWX): ORIGIN = 0x20000150, LENGTH = 0x00000040 SRAM_CODE_3(RWX): ORIGIN = 0x20000190, LENGTH = 0x00000F70 SRAM_CODE_4(RWX): ORIGIN = 0x20001170, LENGTH = 0x00000200 SRAM_DATA (RW) : ORIGIN = 0x20002000, LENGTH = 0x00001000 } REGION_ALIAS("REGION_INTVECT", SRAM_CODE_0); REGION_ALIAS("REGION_RESET", SRAM_CODE_1); REGION_ALIAS("REGION_DESCRIPTOR", SRAM_CODE_2); REGION_ALIAS("REGION_TEXT", SRAM_CODE_3); REGION_ALIAS("REGION_BSS", SRAM_CODE_3); REGION_ALIAS("REGION_DATA", SRAM_DATA); REGION_ALIAS("REGION_STACK", SRAM_CODE_4); REGION_ALIAS("REGION_HEAP", SRAM_DATA); REGION_ALIAS("REGION_ARM_EXIDX", SRAM_CODE_3); REGION_ALIAS("REGION_ARM_EXTAB", SRAM_CODE_3); SECTIONS { /* section for the interrupt vector area */ .intvecs : { KEEP (*(.intvecs)) } > REGION_INTVECT PROVIDE (_vtable_base_address = DEFINED(_vtable_base_address) ? _vtable_base_address : 0x20000000); .vtable (_vtable_base_address) : AT (_vtable_base_address) { KEEP (*(.vtable)) } > REGION_DATA .descriptor :{ FILL(0x00000000); . = ORIGIN(REGION_DESCRIPTOR) + LENGTH(REGION_DESCRIPTOR) - 1; BYTE(0x00); __ROM_AT = .; } > REGION_DESCRIPTOR .reset : { KEEP(*(.reset)) } > REGION_RESET AT> REGION_RESET .text : { CREATE_OBJECT_SYMBOLS KEEP (*(.text)) *(.text.*) . = ALIGN(0x4); KEEP (*(.ctors)) . = ALIGN(0x4); KEEP (*(.dtors)) . = ALIGN(0x4); __init_array_start = .; KEEP (*(.init_array*)) __init_array_end = .; KEEP (*(.init)) KEEP (*(.fini*)) } > REGION_TEXT AT> REGION_TEXT .rodata : { *(.rodata) *(.rodata.*) } > REGION_TEXT AT> REGION_TEXT .ARM.exidx : { __exidx_start = .; *(.ARM.exidx* .gnu.linkonce.armexidx.*) __exidx_end = .; } > REGION_ARM_EXIDX AT> REGION_ARM_EXIDX .ARM.extab : { KEEP (*(.ARM.extab* .gnu.linkonce.armextab.*)) } > REGION_ARM_EXTAB AT> REGION_ARM_EXTAB __etext = .; .data : { __data_load__ = LOADADDR (.data); __data_start__ = .; KEEP (*(.data)) KEEP (*(.data*)) . = ALIGN (4); __data_end__ = .; } > REGION_DATA AT> REGION_TEXT .bss : { __bss_start__ = .; *(.shbss) KEEP (*(.bss)) *(.bss.*) *(COMMON) . = ALIGN (4); __bss_end__ = .; } > REGION_BSS AT> REGION_BSS .heap : { __heap_start__ = .; end = __heap_start__; _end = end; __end = end; KEEP (*(.heap)) __heap_end__ = .; __HeapLimit = __heap_end__; } > REGION_HEAP AT> REGION_HEAP .stack (NOLOAD) : ALIGN(0x8) { _stack = .; KEEP(*(.stack)) } > REGION_STACK AT> REGION_STACK __stack_top = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK); PROVIDE(__stack = __stack_top); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/msp432e4x.h ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432E4X_H #define OPENOCD_LOADERS_FLASH_MSP432_MSP432E4X_H #include #ifdef __cplusplus extern "C" { #endif /* Register map for FLASH_CTRL peripheral (FLASH_CTRL) */ struct flash_ctrl { volatile uint32_t FMA; /* Flash Memory Address */ volatile uint32_t FMD; /* Flash Memory Data */ volatile uint32_t FMC; /* Flash Memory Control */ volatile uint32_t FCRIS; /* Flash Controller Raw Interrupt Status */ volatile uint32_t FCIM; /* Flash Controller Interrupt Mask */ volatile uint32_t FCMISC; /* Flash Cont. Masked Int. Status and Clear */ volatile uint32_t RESERVED0[2]; volatile uint32_t FMC2; /* Flash Memory Control 2 */ volatile uint32_t RESERVED1[3]; volatile uint32_t FWBVAL; /* Flash Write Buffer Valid */ volatile uint32_t RESERVED2[2]; volatile uint32_t FLPEKEY; /* Flash Program/Erase Key */ volatile uint32_t RESERVED3[48]; volatile uint32_t FWBN[32]; /* Flash Write Buffer n */ }; /* Register map for SYSCTL peripheral (SYSCTL) */ struct sys_ctrl { volatile uint32_t DID0; /* Device Identification 0 */ volatile uint32_t DID1; /* Device Identification 1 */ volatile uint32_t RESERVED0[12]; volatile uint32_t PTBOCTL; /* Power-Temp Brown Out Control */ volatile uint32_t RESERVED1[5]; volatile uint32_t RIS; /* Raw Interrupt Status */ volatile uint32_t IMC; /* Interrupt Mask Control */ volatile uint32_t MISC; /* Masked Interrupt Status and Clear */ volatile uint32_t RESC; /* Reset Cause */ volatile uint32_t PWRTC; /* Power-Temperature Cause */ volatile uint32_t NMIC; /* NMI Cause Register */ volatile uint32_t RESERVED2[5]; volatile uint32_t MOSCCTL; /* Main Oscillator Control */ volatile uint32_t RESERVED3[12]; volatile uint32_t RSCLKCFG; /* Run and Sleep Mode Configuration Register */ volatile uint32_t RESERVED4[3]; volatile uint32_t MEMTIM0; /* Memory Timing Register 0 for Main Flash */ volatile uint32_t RESERVED5[29]; volatile uint32_t ALTCLKCFG; /* Alternate Clock Configuration */ volatile uint32_t RESERVED6[2]; union { volatile uint32_t DSLPCLKCFG; /* Deep Sleep Clock Configuration */ volatile uint32_t DSCLKCFG; /* Deep Sleep Clock Register */ }; volatile uint32_t DIVSCLK; /* Divisor and Source Clock Configuration */ volatile uint32_t SYSPROP; /* System Properties */ volatile uint32_t PIOSCCAL; /* Precision Internal Oscillator Calibration */ volatile uint32_t PIOSCSTAT; /* Precision Internal Oscillator Statistics */ volatile uint32_t RESERVED7[2]; volatile uint32_t PLLFREQ0; /* PLL Frequency 0 */ volatile uint32_t PLLFREQ1; /* PLL Frequency 1 */ volatile uint32_t PLLSTAT; /* PLL Status */ volatile uint32_t RESERVED8[7]; volatile uint32_t SLPPWRCFG; /* Sleep Power Configuration */ volatile uint32_t DSLPPWRCFG; /* Deep-Sleep Power Configuration */ volatile uint32_t RESERVED9[4]; volatile uint32_t NVMSTAT; /* Non-Volatile Memory Information */ volatile uint32_t RESERVED10[4]; volatile uint32_t LDOSPCTL; /* LDO Sleep Power Control */ volatile uint32_t RESERVED11; volatile uint32_t LDODPCTL; /* LDO Deep-Sleep Power Control */ volatile uint32_t RESERVED12[6]; volatile uint32_t RESBEHAVCTL; /* Reset Behavior Control Register */ volatile uint32_t RESERVED13[6]; volatile uint32_t HSSR; /* Hardware System Service Request */ volatile uint32_t RESERVED14[34]; volatile uint32_t USBPDS; /* USB Power Domain Status */ volatile uint32_t USBMPC; /* USB Memory Power Control */ volatile uint32_t EMACPDS; /* Ethernet MAC Power Domain Status */ volatile uint32_t EMACMPC; /* Ethernet MAC Memory Power Control */ volatile uint32_t RESERVED15; volatile uint32_t LCDMPC; /* LCD Memory Power Control */ volatile uint32_t RESERVED16[26]; volatile uint32_t PPWD; /* Watchdog Timer Peripheral Present */ volatile uint32_t PPTIMER; /* General-Purpose Timer Peripheral Present */ volatile uint32_t PPGPIO; /* General-Purpose I/O Peripheral Present */ volatile uint32_t PPDMA; /* Micro DMA Peripheral Present */ volatile uint32_t PPEPI; /* EPI Peripheral Present */ volatile uint32_t PPHIB; /* Hibernation Peripheral Present */ volatile uint32_t PPUART; /* UART Peripheral Present */ volatile uint32_t PPSSI; /* Synchronous Serial Inter. Periph. Present */ volatile uint32_t PPI2C; /* Inter-Integrated Circuit Periph. Present */ volatile uint32_t RESERVED17; volatile uint32_t PPUSB; /* Universal Serial Bus Peripheral Present */ volatile uint32_t RESERVED18; volatile uint32_t PPEPHY; /* Ethernet PHY Peripheral Present */ volatile uint32_t PPCAN; /* Controller Area Network Periph. Present */ volatile uint32_t PPADC; /* Analog-to-Dig. Converter Periph. Present */ volatile uint32_t PPACMP; /* Analog Comparator Peripheral Present */ volatile uint32_t PPPWM; /* Pulse Width Modulator Peripheral Present */ volatile uint32_t PPQEI; /* Quadrature Encoder Inter. Periph. Present */ volatile uint32_t RESERVED19[4]; volatile uint32_t PPEEPROM; /* EEPROM Peripheral Present */ volatile uint32_t RESERVED20[6]; volatile uint32_t PPCCM; /* CRC/Cryptographic Modules Periph. Present */ volatile uint32_t RESERVED21[6]; volatile uint32_t PPLCD; /* LCD Peripheral Present */ volatile uint32_t RESERVED22; volatile uint32_t PPOWIRE; /* 1-Wire Peripheral Present */ volatile uint32_t PPEMAC; /* Ethernet MAC Peripheral Present */ volatile uint32_t RESERVED23[88]; volatile uint32_t SRWD; /* Watchdog Timer Software Reset */ volatile uint32_t SRTIMER; /* General-Purpose Timer Software Reset */ volatile uint32_t SRGPIO; /* General-Purpose I/O Software Reset */ volatile uint32_t SRDMA; /* Micro Direct Memory Access Software Reset */ volatile uint32_t SREPI; /* EPI Software Reset */ volatile uint32_t SRHIB; /* Hibernation Software Reset */ volatile uint32_t SRUART; /* UART Software Reset */ volatile uint32_t SRSSI; /* Synchronous Serial Inter. Software Reset */ volatile uint32_t SRI2C; /* Inter-Integrated Circuit Software Reset */ volatile uint32_t RESERVED24; volatile uint32_t SRUSB; /* Universal Serial Bus Software Reset */ volatile uint32_t RESERVED25; volatile uint32_t SREPHY; /* Ethernet PHY Software Reset */ volatile uint32_t SRCAN; /* Controller Area Network Software Reset */ volatile uint32_t SRADC; /* Analog-to-Dig. Converter Software Reset */ volatile uint32_t SRACMP; /* Analog Comparator Software Reset */ volatile uint32_t SRPWM; /* Pulse Width Modulator Software Reset */ volatile uint32_t SRQEI; /* Quadrature Encoder Inter. Software Reset */ volatile uint32_t RESERVED26[4]; volatile uint32_t SREEPROM; /* EEPROM Software Reset */ volatile uint32_t RESERVED27[6]; volatile uint32_t SRCCM; /* CRC/Cryptographic Modules Software Reset */ volatile uint32_t RESERVED28[6]; volatile uint32_t SRLCD; /* LCD Controller Software Reset */ volatile uint32_t RESERVED29; volatile uint32_t SROWIRE; /* 1-Wire Software Reset */ volatile uint32_t SREMAC; /* Ethernet MAC Software Reset */ volatile uint32_t RESERVED30[24]; volatile uint32_t RCGCWD; /* Watchdog Run Mode Clock Gating Control */ }; /* Peripheral Memory Map */ #define FLASH_CTRL_BASE 0x400FD000UL #define SYSCTL_BASE 0x400FE000UL /* Peripheral Declarations */ #define FLASH_CTRL ((struct flash_ctrl *) FLASH_CTRL_BASE) #define SYSCTL ((struct sys_ctrl *) SYSCTL_BASE) /* The following are defines for the bit fields in the FLASH_FMC register. */ #define FLASH_FMC_WRKEY 0xA4420000 /* FLASH write key */ #define FLASH_FMC_COMT 0x00000008 /* Commit Register Value */ #define FLASH_FMC_MERASE 0x00000004 /* Mass Erase Flash Memory */ #define FLASH_FMC_ERASE 0x00000002 /* Erase a Page of Flash Memory */ #define FLASH_FMC_WRITE 0x00000001 /* Write a Word into Flash Memory */ /* The following are defines for the bit fields in the FLASH_FCRIS register. */ #define FLASH_FCRIS_PROGRIS 0x00002000 /* Program Verify Raw Interrupt Status */ #define FLASH_FCRIS_ERRIS 0x00000800 /* Erase Verify Raw Interrupt Status */ #define FLASH_FCRIS_INVDRIS 0x00000400 /* Invalid Data Raw Interrupt Status */ #define FLASH_FCRIS_VOLTRIS 0x00000200 /* Pump Voltage Raw Interrupt Status */ #define FLASH_FCRIS_ERIS 0x00000004 /* EEPROM Raw Interrupt Status */ #define FLASH_FCRIS_PRIS 0x00000002 /* Programming Raw Interrupt Status */ #define FLASH_FCRIS_ARIS 0x00000001 /* Access Raw Interrupt Status */ /* The following are defines for the bit fields in the FLASH_FCIM register. */ #define FLASH_FCIM_PROGMASK 0x00002000 /* PROGVER Interrupt Mask */ #define FLASH_FCIM_ERMASK 0x00000800 /* ERVER Interrupt Mask */ #define FLASH_FCIM_INVDMASK 0x00000400 /* Invalid Data Interrupt Mask */ #define FLASH_FCIM_VOLTMASK 0x00000200 /* VOLT Interrupt Mask */ #define FLASH_FCIM_EMASK 0x00000004 /* EEPROM Interrupt Mask */ #define FLASH_FCIM_PMASK 0x00000002 /* Programming Interrupt Mask */ #define FLASH_FCIM_AMASK 0x00000001 /* Access Interrupt Mask */ /* The following are defines for the bit fields in the FLASH_FCMISC register. */ #define FLASH_FCMISC_PROGMISC 0x00002000 /* PROGVER Interrupt Status/Clear */ #define FLASH_FCMISC_ERMISC 0x00000800 /* ERVER Interrupt Status/Clear */ #define FLASH_FCMISC_INVDMISC 0x00000400 /* Invalid Data Int. Status/Clear */ #define FLASH_FCMISC_VOLTMISC 0x00000200 /* VOLT Interrupt Status/Clear */ #define FLASH_FCMISC_EMISC 0x00000004 /* EEPROM Interrupt Status/Clear */ #define FLASH_FCMISC_PMISC 0x00000002 /* Programming Int. Status/Clear */ #define FLASH_FCMISC_AMISC 0x00000001 /* Access Interrupt Status/Clear */ /* The following are defines for the bit fields in the FLASH_FMC2 register. */ #define FLASH_FMC2_WRBUF 0x00000001 /* Buffered Flash Memory Write */ /* The following are defines for the bit fields in the SYSCTL_RCGCWD reg. */ #define SYSCTL_RCGCWD_R1 0x00000002 /* Watchdog 1 Run Mode Clock Gating Cont. */ #define SYSCTL_RCGCWD_R0 0x00000001 /* Watchdog 0 Run Mode Clock Gating Cont. */ #ifdef __cplusplus } #endif #endif /* OPENOCD_LOADERS_FLASH_MSP432_MSP432E4X_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/msp432e4x_algo.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x70,0x13,0x00,0x20,0x11,0x01,0x00,0x20,0xc9,0x0a,0x00,0x20,0xc9,0x0a,0x00,0x20, 0xc9,0x0a,0x00,0x20,0xc9,0x0a,0x00,0x20,0xc9,0x0a,0x00,0x20,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0x0a,0x00,0x20, 0xc9,0x0a,0x00,0x20,0x00,0x00,0x00,0x00,0xc9,0x0a,0x00,0x20,0xc9,0x0a,0x00,0x20, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x41,0xf2,0x00,0x70,0xc2,0xf2,0x00,0x00,0x85,0x46,0x05,0x48,0x05,0x49,0x4f,0xf0, 0x00,0x02,0x88,0x42,0xb8,0xbf,0x40,0xf8,0x04,0x2b,0xfa,0xdb,0x00,0xf0,0x16,0xbc, 0x34,0x0f,0x00,0x20,0x50,0x0f,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x04,0x4b,0x05,0x48,0x1b,0x1a,0x06,0x2b,0x02,0xd9,0x04,0x4b,0x03,0xb1,0x18,0x47, 0x70,0x47,0x00,0xbf,0x37,0x24,0x00,0x20,0x34,0x24,0x00,0x20,0x00,0x00,0x00,0x00, 0x05,0x49,0x06,0x48,0x09,0x1a,0x89,0x10,0x01,0xeb,0xd1,0x71,0x49,0x10,0x02,0xd0, 0x03,0x4b,0x03,0xb1,0x18,0x47,0x70,0x47,0x34,0x24,0x00,0x20,0x34,0x24,0x00,0x20, 0x00,0x00,0x00,0x00,0x10,0xb5,0x06,0x4c,0x23,0x78,0x43,0xb9,0xff,0xf7,0xd8,0xff, 0x04,0x4b,0x13,0xb1,0x04,0x48,0xaf,0xf3,0x00,0x80,0x01,0x23,0x23,0x70,0x10,0xbd, 0x34,0x0f,0x00,0x20,0x00,0x00,0x00,0x00,0xf8,0x0a,0x00,0x20,0x08,0xb5,0x08,0x4b, 0x1b,0xb1,0x08,0x48,0x08,0x49,0xaf,0xf3,0x00,0x80,0x08,0x48,0x03,0x68,0x13,0xb9, 0xbd,0xe8,0x08,0x40,0xcc,0xe7,0x06,0x4b,0x00,0x2b,0xf9,0xd0,0x98,0x47,0xf7,0xe7, 0x00,0x00,0x00,0x00,0xf8,0x0a,0x00,0x20,0x38,0x0f,0x00,0x20,0x34,0x24,0x00,0x20, 0x00,0x00,0x00,0x00,0x13,0x4b,0x00,0x2b,0x08,0xbf,0x11,0x4b,0x9d,0x46,0xa3,0xf5, 0x80,0x3a,0x00,0x21,0x8b,0x46,0x0f,0x46,0x11,0x48,0x12,0x4a,0x12,0x1a,0x00,0xf0, 0x13,0xf9,0x0d,0x4b,0x00,0x2b,0x00,0xd0,0x98,0x47,0x0c,0x4b,0x00,0x2b,0x00,0xd0, 0x98,0x47,0x00,0x20,0x00,0x21,0x04,0x00,0x0d,0x00,0x0b,0x48,0x00,0xf0,0xb0,0xf8, 0x00,0xf0,0xda,0xf8,0x20,0x00,0x29,0x00,0x00,0xf0,0x70,0xfb,0x00,0xf0,0xae,0xf8, 0x00,0x00,0x08,0x00,0x70,0x13,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x34,0x0f,0x00,0x20,0x50,0x0f,0x00,0x20,0xfd,0x03,0x00,0x20,0x84,0x46,0x41,0xea, 0x00,0x03,0x13,0xf0,0x03,0x03,0x6d,0xd1,0x40,0x3a,0x41,0xd3,0x51,0xf8,0x04,0x3b, 0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, 0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, 0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, 0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, 0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, 0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, 0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, 0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x40,0x3a,0xbd,0xd2, 0x30,0x32,0x11,0xd3,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, 0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b,0x40,0xf8,0x04,0x3b,0x51,0xf8,0x04,0x3b, 0x40,0xf8,0x04,0x3b,0x10,0x3a,0xed,0xd2,0x0c,0x32,0x05,0xd3,0x51,0xf8,0x04,0x3b, 0x40,0xf8,0x04,0x3b,0x04,0x3a,0xf9,0xd2,0x04,0x32,0x08,0xd0,0xd2,0x07,0x1c,0xbf, 0x11,0xf8,0x01,0x3b,0x00,0xf8,0x01,0x3b,0x01,0xd3,0x0b,0x88,0x03,0x80,0x60,0x46, 0x70,0x47,0x00,0xbf,0x08,0x2a,0x13,0xd3,0x8b,0x07,0x8d,0xd0,0x10,0xf0,0x03,0x03, 0x8a,0xd0,0xc3,0xf1,0x04,0x03,0xd2,0x1a,0xdb,0x07,0x1c,0xbf,0x11,0xf8,0x01,0x3b, 0x00,0xf8,0x01,0x3b,0x80,0xd3,0x31,0xf8,0x02,0x3b,0x20,0xf8,0x02,0x3b,0x7b,0xe7, 0x04,0x3a,0xd9,0xd3,0x01,0x3a,0x11,0xf8,0x01,0x3b,0x00,0xf8,0x01,0x3b,0xf9,0xd2, 0x0b,0x78,0x03,0x70,0x4b,0x78,0x43,0x70,0x8b,0x78,0x83,0x70,0x60,0x46,0x70,0x47, 0x01,0x46,0x00,0x20,0x02,0x46,0x03,0x46,0x00,0xf0,0x9c,0xb8,0x08,0xb5,0x00,0x21, 0x04,0x46,0x00,0xf0,0xf3,0xf8,0x04,0x4b,0x18,0x68,0xc3,0x6b,0x03,0xb1,0x98,0x47, 0x20,0x46,0x00,0xf0,0x55,0xf9,0x00,0xbf,0xf4,0x0a,0x00,0x20,0x38,0xb5,0x08,0x4b, 0x08,0x4d,0xed,0x1a,0xac,0x10,0x18,0xbf,0xed,0x18,0x05,0xd0,0x01,0x3c,0x55,0xf8, 0x04,0x3d,0x98,0x47,0x00,0x2c,0xf9,0xd1,0xbd,0xe8,0x38,0x40,0x00,0xf0,0x60,0xbb, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0xb5,0x0f,0x4e,0x0f,0x4d,0x76,0x1b, 0xb6,0x10,0x18,0xbf,0x00,0x24,0x05,0xd0,0x01,0x34,0x55,0xf8,0x04,0x3b,0x98,0x47, 0xa6,0x42,0xf9,0xd1,0x0a,0x4e,0x0b,0x4d,0x76,0x1b,0x00,0xf0,0x43,0xfb,0xb6,0x10, 0x18,0xbf,0x00,0x24,0x06,0xd0,0x01,0x34,0x55,0xf8,0x04,0x3b,0x98,0x47,0xa6,0x42, 0xf9,0xd1,0x70,0xbd,0x70,0xbd,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xd4,0x0a,0x00,0x20,0xcc,0x0a,0x00,0x20,0x70,0xb4,0x84,0x07,0x46,0xd0,0x54,0x1e, 0x00,0x2a,0x41,0xd0,0xcd,0xb2,0x03,0x46,0x02,0xe0,0x62,0x1e,0xe4,0xb3,0x14,0x46, 0x03,0xf8,0x01,0x5b,0x9a,0x07,0xf8,0xd1,0x03,0x2c,0x2e,0xd9,0xcd,0xb2,0x45,0xea, 0x05,0x25,0x0f,0x2c,0x45,0xea,0x05,0x45,0x19,0xd9,0x03,0xf1,0x10,0x02,0x26,0x46, 0x10,0x3e,0x0f,0x2e,0x42,0xf8,0x10,0x5c,0x42,0xf8,0x0c,0x5c,0x42,0xf8,0x08,0x5c, 0x42,0xf8,0x04,0x5c,0x02,0xf1,0x10,0x02,0xf2,0xd8,0xa4,0xf1,0x10,0x02,0x22,0xf0, 0x0f,0x02,0x04,0xf0,0x0f,0x04,0x10,0x32,0x03,0x2c,0x13,0x44,0x0d,0xd9,0x1e,0x46, 0x22,0x46,0x04,0x3a,0x03,0x2a,0x46,0xf8,0x04,0x5b,0xfa,0xd8,0x22,0x1f,0x22,0xf0, 0x03,0x02,0x04,0x32,0x13,0x44,0x04,0xf0,0x03,0x04,0x2c,0xb1,0xc9,0xb2,0x1c,0x44, 0x03,0xf8,0x01,0x1b,0xa3,0x42,0xfb,0xd1,0x70,0xbc,0x70,0x47,0x14,0x46,0x03,0x46, 0xc2,0xe7,0x00,0xbf,0x2d,0xe9,0xf0,0x47,0x25,0x4c,0x25,0x68,0xd5,0xf8,0x48,0x41, 0x06,0x46,0x88,0x46,0x92,0x46,0x99,0x46,0xcc,0xb3,0x60,0x68,0x1f,0x28,0x18,0xdc, 0x43,0x1c,0x7e,0xb1,0x04,0xeb,0x80,0x05,0x01,0x21,0xc5,0xf8,0x88,0xa0,0xd4,0xf8, 0x88,0x71,0x01,0xfa,0x00,0xf2,0x17,0x43,0x02,0x2e,0xc4,0xf8,0x88,0x71,0xc5,0xf8, 0x08,0x91,0x1e,0xd0,0x02,0x30,0x63,0x60,0x44,0xf8,0x20,0x80,0x00,0x20,0xbd,0xe8, 0xf0,0x87,0x14,0x4b,0x03,0xb3,0x4f,0xf4,0xc8,0x70,0xaf,0xf3,0x00,0x80,0x04,0x46, 0xd0,0xb1,0xd5,0xf8,0x48,0x31,0x00,0x27,0x80,0xe8,0x88,0x00,0xc5,0xf8,0x48,0x41, 0x38,0x46,0x01,0x23,0xc4,0xf8,0x88,0x71,0xc4,0xf8,0x8c,0x71,0x00,0x2e,0xe1,0xd0, 0xd0,0xe7,0xd4,0xf8,0x8c,0x11,0x0a,0x43,0xc4,0xf8,0x8c,0x21,0xda,0xe7,0x05,0xf5, 0xa6,0x74,0xc5,0xf8,0x48,0x41,0xc0,0xe7,0x4f,0xf0,0xff,0x30,0xbd,0xe8,0xf0,0x87, 0xf4,0x0a,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x4b,0x13,0xb1,0x02,0x48,0xff,0xf7, 0x07,0xbf,0x70,0x47,0x00,0x00,0x00,0x00,0xfd,0x03,0x00,0x20,0x2d,0xe9,0xf0,0x4f, 0x31,0x4b,0x83,0xb0,0x1b,0x68,0x00,0x93,0x03,0xf5,0xa4,0x73,0x81,0x46,0x0e,0x46, 0x01,0x93,0x00,0x9b,0xd3,0xf8,0x48,0x71,0x27,0xb3,0xdd,0xf8,0x04,0xa0,0x7c,0x68, 0x65,0x1e,0x0e,0xd4,0x01,0x34,0x07,0xeb,0x84,0x04,0x4f,0xf0,0x00,0x08,0xe6,0xb1, 0xd4,0xf8,0x00,0x31,0xb3,0x42,0x18,0xd0,0x01,0x3d,0x6b,0x1c,0xa4,0xf1,0x04,0x04, 0xf5,0xd1,0x22,0x4b,0x73,0xb1,0x7b,0x68,0x00,0x2b,0x36,0xd1,0x3b,0x68,0x00,0x2b, 0x34,0xd0,0x38,0x46,0xca,0xf8,0x00,0x30,0xaf,0xf3,0x00,0x80,0xda,0xf8,0x00,0x70, 0x00,0x2f,0xdc,0xd1,0x03,0xb0,0xbd,0xe8,0xf0,0x8f,0x7b,0x68,0x22,0x68,0x01,0x3b, 0xab,0x42,0x0c,0xbf,0x7d,0x60,0xc4,0xf8,0x00,0x80,0x00,0x2a,0xdc,0xd0,0xd7,0xf8, 0x88,0x31,0xd7,0xf8,0x04,0xb0,0x01,0x21,0xa9,0x40,0x19,0x42,0x08,0xd1,0x90,0x47, 0x7b,0x68,0x5b,0x45,0xbd,0xd1,0xda,0xf8,0x00,0x30,0xbb,0x42,0xcc,0xd0,0xb8,0xe7, 0xd7,0xf8,0x8c,0x31,0x19,0x42,0x04,0xd1,0x48,0x46,0xd4,0xf8,0x80,0x10,0x90,0x47, 0xee,0xe7,0xd4,0xf8,0x80,0x00,0x90,0x47,0xea,0xe7,0x3b,0x68,0xba,0x46,0x1f,0x46, 0x00,0x2f,0xac,0xd1,0xce,0xe7,0x00,0xbf,0xf4,0x0a,0x00,0x20,0x00,0x00,0x00,0x00, 0xfe,0xe7,0x00,0xbf,0x2d,0xe9,0xf0,0x4f,0xa8,0x4b,0xa9,0x4a,0xde,0x68,0xd3,0xf8, 0x10,0xb0,0x85,0xb0,0x42,0xf2,0x03,0x61,0x00,0x24,0x99,0x46,0xa5,0x4b,0x51,0x61, 0x15,0x46,0x90,0x46,0x00,0x94,0xbb,0xf5,0x80,0x5f,0x93,0xbf,0x5f,0x46,0xab,0xf5, 0x80,0x5b,0x4f,0xf4,0x80,0x57,0x4f,0xf0,0x00,0x0b,0x03,0xe0,0xd9,0xf8,0x18,0x20, 0xd2,0x06,0x03,0xd4,0xd9,0xf8,0x14,0x20,0xd1,0x06,0xf7,0xd5,0xd9,0xf8,0x14,0x20, 0x12,0xf0,0x10,0x02,0x00,0xf0,0xb9,0x80,0xd9,0xf8,0x14,0x20,0x42,0xf0,0x01,0x02, 0xc9,0xf8,0x14,0x20,0x4f,0xf0,0x20,0x24,0x4f,0xf0,0x01,0x0a,0x16,0xf0,0x03,0x02, 0x00,0xf0,0xa9,0x80,0x26,0xf0,0x03,0x0c,0xdc,0xf8,0x00,0x10,0x03,0x91,0x47,0xb3, 0x21,0x46,0x78,0x1e,0x11,0xf8,0x01,0xeb,0x01,0x91,0x04,0xa9,0x11,0x44,0x01,0xf8, 0x04,0xec,0x02,0xf1,0x01,0x01,0x06,0xf1,0x01,0x0e,0x00,0xf0,0x01,0x81,0x04,0x29, 0x00,0xf0,0xfe,0x80,0x04,0xa8,0x01,0x44,0x60,0x78,0x01,0xf8,0x04,0x0c,0xb9,0x1e, 0x00,0x29,0x06,0xf1,0x02,0x00,0x04,0xf1,0x02,0x0e,0x40,0xf3,0xec,0x80,0x01,0x2a, 0x40,0xf0,0xe9,0x80,0xa2,0x78,0x8d,0xf8,0x0f,0x20,0x03,0x99,0x03,0x36,0x03,0x3f, 0x03,0x34,0x78,0x4a,0x69,0x60,0xc5,0xf8,0x00,0xc0,0xaa,0x60,0xaa,0x68,0xd0,0x07, 0xfc,0xd4,0xd8,0xf8,0x0c,0x10,0x42,0xf2,0x05,0x42,0x0a,0x40,0xb2,0xfa,0x82,0xf2, 0x52,0x09,0x03,0x2f,0x1a,0xdd,0x71,0x06,0x79,0xd0,0x00,0x2a,0x75,0xd0,0x54,0xf8, 0x04,0x2b,0x6a,0x60,0x2e,0x60,0xab,0x60,0xaa,0x68,0xd2,0x07,0xfc,0xd4,0xd8,0xf8, 0x0c,0x10,0x04,0x3f,0x42,0xf2,0x05,0x42,0x03,0x2f,0x02,0xea,0x01,0x02,0x06,0xf1, 0x04,0x06,0xb2,0xfa,0x82,0xf2,0x4f,0xea,0x52,0x12,0xe4,0xdc,0x00,0x2f,0x15,0xdc, 0xba,0xf1,0x00,0x0f,0x33,0xd0,0xd9,0xf8,0x14,0x10,0x21,0xf0,0x11,0x01,0xc9,0xf8, 0x14,0x10,0x00,0x2a,0x38,0xd0,0xbb,0xf1,0x00,0x0f,0x7f,0xf4,0x6c,0xaf,0x57,0x4b, 0x40,0xf6,0xce,0x22,0x5a,0x60,0x05,0xb0,0xbd,0xe8,0xf0,0x8f,0x00,0x2a,0xe7,0xd0, 0x04,0xa8,0x32,0x68,0x40,0xf8,0x04,0x2d,0x21,0x46,0x3a,0x46,0x01,0x93,0xff,0xf7, 0x45,0xfd,0x03,0x9a,0x4f,0x4b,0x6a,0x60,0x2e,0x60,0xab,0x60,0x01,0x9b,0x37,0x44, 0xaa,0x68,0xd2,0x07,0xfc,0xd4,0xd8,0xf8,0x0c,0x10,0x42,0xf2,0x05,0x42,0x0a,0x40, 0x3e,0x46,0xb2,0xfa,0x82,0xf2,0x52,0x09,0xba,0xf1,0x00,0x0f,0xcb,0xd1,0x00,0x99, 0x00,0x29,0xce,0xd0,0xd9,0xf8,0x18,0x10,0xcd,0xf8,0x00,0xa0,0x21,0xf0,0x11,0x01, 0xc9,0xf8,0x18,0x10,0x00,0x2a,0xc6,0xd1,0x3c,0x4b,0x4d,0xf6,0xad,0x62,0x5a,0x60, 0x05,0xb0,0xbd,0xe8,0xf0,0x8f,0x01,0x22,0x93,0xe7,0xd9,0xf8,0x18,0x10,0x11,0xf0, 0x10,0x01,0x5e,0xd0,0xd9,0xf8,0x18,0x10,0x37,0x4c,0x41,0xf0,0x01,0x01,0x92,0x46, 0x01,0x22,0xc9,0xf8,0x18,0x10,0x00,0x92,0x40,0xe7,0x00,0x22,0xa0,0xe7,0x1f,0x2f, 0x32,0xdd,0x00,0x2a,0xf9,0xd0,0x07,0xf1,0xff,0x3e,0x2e,0xf0,0x03,0x0e,0x0e,0xf1, 0x04,0x0e,0xa6,0x44,0x39,0x46,0x04,0xf1,0x80,0x0c,0x00,0x22,0x01,0xe0,0x64,0x45, 0x0b,0xd0,0x54,0xf8,0x04,0x7b,0x02,0xf1,0x40,0x00,0x74,0x45,0xa1,0xf1,0x04,0x01, 0x45,0xf8,0x20,0x70,0x02,0xf1,0x01,0x02,0xf1,0xd1,0x2e,0x60,0x0f,0x46,0x2b,0x62, 0x2a,0x6a,0xd0,0x07,0xfc,0xd4,0xd8,0xf8,0x0c,0x00,0x42,0xf2,0x05,0x42,0x1f,0x29, 0x02,0xea,0x00,0x02,0x06,0xf1,0x80,0x06,0xb2,0xfa,0x82,0xf2,0x4f,0xea,0x52,0x12, 0xcf,0xdc,0x03,0x29,0x7f,0xf7,0x6a,0xaf,0x00,0x2a,0xc6,0xd0,0x54,0xf8,0x04,0x2b, 0x6a,0x60,0x2e,0x60,0xab,0x60,0xaa,0x68,0xd1,0x07,0xfc,0xd4,0xd8,0xf8,0x0c,0x10, 0x04,0x3f,0x42,0xf2,0x05,0x42,0x03,0x2f,0x02,0xea,0x01,0x02,0x06,0xf1,0x04,0x06, 0xb2,0xfa,0x82,0xf2,0x4f,0xea,0x52,0x12,0xe6,0xdc,0x00,0x2f,0x7f,0xf7,0x50,0xaf, 0x64,0xe7,0x8a,0x46,0xea,0xe6,0x0f,0x46,0x74,0x46,0x06,0x46,0x03,0x99,0x18,0xe7, 0x01,0x9c,0x03,0x99,0x07,0x46,0x76,0x46,0x13,0xe7,0x00,0xbf,0x50,0x01,0x00,0x20, 0x00,0xd0,0x0f,0x40,0x01,0x00,0x42,0xa4,0x00,0x30,0x00,0x20,0x80,0xb5,0x72,0xb6, 0x52,0x4a,0x53,0x4c,0xd2,0xf8,0x00,0x36,0x52,0x4d,0x53,0x4f,0x53,0x4e,0x23,0xf0, 0x03,0x03,0xc2,0xf8,0x00,0x36,0xa0,0x46,0x2b,0x68,0x20,0x2b,0x00,0xf2,0x8d,0x80, 0x01,0xa2,0x52,0xf8,0x23,0xf0,0x00,0xbf,0x79,0x09,0x00,0x20,0x75,0x0a,0x00,0x20, 0x4b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x3d,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20, 0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x21,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20, 0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20, 0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x0d,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20, 0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20, 0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20, 0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20, 0x9b,0x0a,0x00,0x20,0x9b,0x0a,0x00,0x20,0x3d,0x0a,0x00,0x20,0x2c,0x49,0x00,0x23, 0x01,0x20,0x40,0xf6,0xce,0x22,0x68,0x60,0x8b,0x60,0x6a,0x60,0x2b,0x60,0xab,0xe7, 0x27,0x49,0x4f,0xf0,0x01,0x0e,0x4f,0xf0,0x00,0x50,0x40,0xf6,0xce,0x22,0x00,0x23, 0xc5,0xf8,0x04,0xe0,0x88,0x60,0x6a,0x60,0x2b,0x60,0x9d,0xe7,0x01,0x23,0x6b,0x60, 0xff,0xf7,0x30,0xfe,0x00,0x23,0x2b,0x60,0x96,0xe7,0x40,0xf6,0x03,0x23,0x01,0x22, 0x6a,0x60,0x63,0x61,0xeb,0x68,0x23,0x60,0xa7,0x60,0xa3,0x68,0x9b,0x07,0xfc,0xd4, 0xd8,0xf8,0x0c,0x20,0x40,0xf6,0x01,0x23,0x13,0x40,0xd3,0xb9,0x40,0xf6,0xce,0x23, 0x6b,0x60,0xe7,0xe7,0x01,0x22,0x40,0xf6,0x03,0x23,0x6a,0x60,0x63,0x61,0xa6,0x60, 0xa3,0x68,0x5a,0x07,0xfc,0xd4,0xd8,0xf8,0x0c,0x20,0x40,0xf6,0x01,0x23,0x13,0x40, 0x00,0x2b,0xeb,0xd0,0x0b,0x4b,0x6b,0x60,0xd4,0xe7,0x40,0xf6,0xad,0x33,0x6b,0x60, 0x6a,0xe7,0x4d,0xf6,0xad,0x63,0x6b,0x60,0xcc,0xe7,0x00,0xbf,0x00,0xe0,0x0f,0x40, 0x00,0xd0,0x0f,0x40,0x50,0x01,0x00,0x20,0x02,0x00,0x42,0xa4,0x04,0x00,0x42,0xa4, 0x00,0xed,0x00,0xe0,0xad,0xde,0xad,0xde,0xfe,0xe7,0x00,0xbf,0xfd,0x01,0x00,0x20, 0xb9,0x05,0x00,0x20,0xf8,0xb5,0x00,0xbf,0xf8,0xbc,0x08,0xbc,0x9e,0x46,0x70,0x47, 0xf8,0xb5,0x00,0xbf,0xd5,0x01,0x00,0x20,0xf8,0xbc,0x08,0xbc,0x9e,0x46,0x70,0x47, 0x43,0x00,0x00,0x00,0x08,0x20,0x00,0x20,0x3c,0xf7,0xff,0x7f,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf4,0x22,0x00,0x20, 0x5c,0x23,0x00,0x20,0xc4,0x23,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x0a,0x00,0x20, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x33,0xcd,0xab,0x34,0x12,0x6d,0xe6, 0xec,0xde,0x05,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x08,0x20,0x00,0x20, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/msp432p401x/msp432p401x.lds ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ MEMORY { MAIN_FLASH (RX) : ORIGIN = 0x00000000, LENGTH = 0x00040000 INFO_FLASH (RX) : ORIGIN = 0x00200000, LENGTH = 0x00004000 SRAM_CODE_0(RWX): ORIGIN = 0x01000000, LENGTH = 0x00000110 SRAM_CODE_1(RWX): ORIGIN = 0x01000110, LENGTH = 0x00000030 SRAM_CODE_2(RWX): ORIGIN = 0x01000150, LENGTH = 0x00000040 SRAM_CODE_3(RWX): ORIGIN = 0x01000190, LENGTH = 0x00000F70 SRAM_CODE_4(RWX): ORIGIN = 0x01001170, LENGTH = 0x00000200 SRAM_DATA (RW) : ORIGIN = 0x20002000, LENGTH = 0x00001000 } REGION_ALIAS("REGION_INTVECT", SRAM_CODE_0); REGION_ALIAS("REGION_RESET", SRAM_CODE_1); REGION_ALIAS("REGION_DESCRIPTOR", SRAM_CODE_2); REGION_ALIAS("REGION_TEXT", SRAM_CODE_3); REGION_ALIAS("REGION_BSS", SRAM_CODE_3); REGION_ALIAS("REGION_DATA", SRAM_DATA); REGION_ALIAS("REGION_STACK", SRAM_CODE_4); REGION_ALIAS("REGION_HEAP", SRAM_DATA); REGION_ALIAS("REGION_ARM_EXIDX", SRAM_CODE_3); REGION_ALIAS("REGION_ARM_EXTAB", SRAM_CODE_3); SECTIONS { /* section for the interrupt vector area */ .intvecs : { KEEP (*(.intvecs)) } > REGION_INTVECT PROVIDE (_vtable_base_address = DEFINED(_vtable_base_address) ? _vtable_base_address : 0x20000000); .vtable (_vtable_base_address) : AT (_vtable_base_address) { KEEP (*(.vtable)) } > REGION_DATA .descriptor :{ FILL(0x00000000); . = ORIGIN(REGION_DESCRIPTOR) + LENGTH(REGION_DESCRIPTOR) - 1; BYTE(0x00); __ROM_AT = .; } > REGION_DESCRIPTOR .reset : { KEEP(*(.reset)) } > REGION_RESET AT> REGION_RESET .text : { CREATE_OBJECT_SYMBOLS KEEP (*(.text)) *(.text.*) . = ALIGN(0x4); KEEP (*(.ctors)) . = ALIGN(0x4); KEEP (*(.dtors)) . = ALIGN(0x4); __init_array_start = .; KEEP (*(.init_array*)) __init_array_end = .; KEEP (*(.init)) KEEP (*(.fini*)) } > REGION_TEXT AT> REGION_TEXT .rodata : { *(.rodata) *(.rodata.*) } > REGION_TEXT AT> REGION_TEXT .ARM.exidx : { __exidx_start = .; *(.ARM.exidx* .gnu.linkonce.armexidx.*) __exidx_end = .; } > REGION_ARM_EXIDX AT> REGION_ARM_EXIDX .ARM.extab : { KEEP (*(.ARM.extab* .gnu.linkonce.armextab.*)) } > REGION_ARM_EXTAB AT> REGION_ARM_EXTAB __etext = .; .data : { __data_load__ = LOADADDR (.data); __data_start__ = .; KEEP (*(.data)) KEEP (*(.data*)) . = ALIGN (4); __data_end__ = .; } > REGION_DATA AT> REGION_TEXT .bss : { __bss_start__ = .; *(.shbss) KEEP (*(.bss)) *(.bss.*) *(COMMON) . = ALIGN (4); __bss_end__ = .; } > REGION_BSS AT> REGION_BSS .heap : { __heap_start__ = .; end = __heap_start__; _end = end; __end = end; KEEP (*(.heap)) __heap_end__ = .; __HeapLimit = __heap_end__; } > REGION_HEAP AT> REGION_HEAP .stack (NOLOAD) : ALIGN(0x8) { _stack = .; KEEP(*(.stack)) } > REGION_STACK AT> REGION_STACK __stack_top = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK); PROVIDE(__stack = __stack_top); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/msp432p401x.h ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432P401X_H #define OPENOCD_LOADERS_FLASH_MSP432_MSP432P401X_H #include #ifdef __cplusplus extern "C" { #endif #define __MCU_HAS_FLCTL__ /* Module FLCTL is available */ /* Device and peripheral memory map */ #define FLASH_BASE ((uint32_t)0x00000000) /* Flash memory start address */ #define SRAM_BASE ((uint32_t)0x20000000) /* SRAM memory start address */ #define PERIPH_BASE ((uint32_t)0x40000000) /* Peripherals start address */ #define CS_BASE (PERIPH_BASE + 0x00010400) /* Address of module CS regs. */ #define DIO_BASE (PERIPH_BASE + 0x00004C00) /* Address of module DIO regs. */ /* Register map for Clock Signal peripheral (CS) */ struct cs { volatile uint32_t KEY; /* Key Register */ volatile uint32_t CTL0; /* Control 0 Register */ volatile uint32_t CTL1; /* Control 1 Register */ volatile uint32_t CTL2; /* Control 2 Register */ volatile uint32_t CTL3; /* Control 3 Register */ }; /* Register map for DIO port (odd interrupt) */ struct dio_port_odd_int { volatile uint8_t IN; /* Port Input */ uint8_t RESERVED0; volatile uint8_t OUT; /* Port Output */ }; /* Register map for DIO port (even interrupt) */ struct dio_port_even_int { uint8_t RESERVED0; volatile uint8_t IN; /* Port Input */ uint8_t RESERVED1; volatile uint8_t OUT; /* Port Output */ }; /* Peripheral declarations */ #define CS ((struct cs *) CS_BASE) #define P3 ((struct dio_port_odd_int *) (DIO_BASE + 0x0020)) #define P6 ((struct dio_port_even_int *) (DIO_BASE + 0x0040)) /* Peripheral bit definitions */ /* DCORSEL Bit Mask */ #define CS_CTL0_DCORSEL_MASK ((uint32_t)0x00070000) /* Nominal DCO Frequency Range (MHz): 2 to 4 */ #define CS_CTL0_DCORSEL_1 ((uint32_t)0x00010000) /* Nominal DCO Frequency Range (MHz): 16 to 32 */ #define CS_CTL0_DCORSEL_4 ((uint32_t)0x00040000) /* CS control key value */ #define CS_KEY_VAL ((uint32_t)0x0000695A) /* Protects Sector 0 from program or erase */ #define FLCTL_BANK0_MAIN_WEPROT_PROT0 ((uint32_t)0x00000001) /* Protects Sector 1 from program or erase */ #define FLCTL_BANK0_MAIN_WEPROT_PROT1 ((uint32_t)0x00000002) #ifdef __cplusplus } #endif #endif /* OPENOCD_LOADERS_FLASH_MSP432_MSP432P401X_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/msp432p401x_algo.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x70,0x13,0x00,0x01,0x11,0x01,0x00,0x01,0xa1,0x0a,0x00,0x01,0xa1,0x0a,0x00,0x01, 0xa1,0x0a,0x00,0x01,0xa1,0x0a,0x00,0x01,0xa1,0x0a,0x00,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa1,0x0a,0x00,0x01, 0xa1,0x0a,0x00,0x01,0x00,0x00,0x00,0x00,0xa1,0x0a,0x00,0x01,0xa1,0x0a,0x00,0x01, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x41,0xf2,0x00,0x70,0xc0,0xf2,0x00,0x10,0x85,0x46,0x05,0x48,0x05,0x49,0x4f,0xf0, 0x00,0x02,0x88,0x42,0xb8,0xbf,0x40,0xf8,0x04,0x2b,0xfa,0xdb,0x00,0xf0,0x96,0xbb, 0x0c,0x0f,0x00,0x01,0x28,0x0f,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x04,0x4b,0x05,0x48,0x1b,0x1a,0x06,0x2b,0x02,0xd9,0x04,0x4b,0x03,0xb1,0x18,0x47, 0x70,0x47,0x00,0xbf,0x37,0x24,0x00,0x20,0x34,0x24,0x00,0x20,0x00,0x00,0x00,0x00, 0x05,0x49,0x06,0x48,0x09,0x1a,0x89,0x10,0x01,0xeb,0xd1,0x71,0x49,0x10,0x02,0xd0, 0x03,0x4b,0x03,0xb1,0x18,0x47,0x70,0x47,0x34,0x24,0x00,0x20,0x34,0x24,0x00,0x20, 0x00,0x00,0x00,0x00,0x10,0xb5,0x06,0x4c,0x23,0x78,0x43,0xb9,0xff,0xf7,0xd8,0xff, 0x04,0x4b,0x13,0xb1,0x04,0x48,0xaf,0xf3,0x00,0x80,0x01,0x23,0x23,0x70,0x10,0xbd, 0x0c,0x0f,0x00,0x01,0x00,0x00,0x00,0x00,0xd0,0x0a,0x00,0x01,0x08,0xb5,0x08,0x4b, 0x1b,0xb1,0x08,0x48,0x08,0x49,0xaf,0xf3,0x00,0x80,0x08,0x48,0x03,0x68,0x13,0xb9, 0xbd,0xe8,0x08,0x40,0xcc,0xe7,0x06,0x4b,0x00,0x2b,0xf9,0xd0,0x98,0x47,0xf7,0xe7, 0x00,0x00,0x00,0x00,0xd0,0x0a,0x00,0x01,0x10,0x0f,0x00,0x01,0x34,0x24,0x00,0x20, 0x00,0x00,0x00,0x00,0x13,0x4b,0x00,0x2b,0x08,0xbf,0x11,0x4b,0x9d,0x46,0xa3,0xf5, 0x80,0x3a,0x00,0x21,0x8b,0x46,0x0f,0x46,0x11,0x48,0x12,0x4a,0x12,0x1a,0x00,0xf0, 0x79,0xf8,0x0d,0x4b,0x00,0x2b,0x00,0xd0,0x98,0x47,0x0c,0x4b,0x00,0x2b,0x00,0xd0, 0x98,0x47,0x00,0x20,0x00,0x21,0x04,0x00,0x0d,0x00,0x0b,0x48,0x00,0xf0,0x16,0xf8, 0x00,0xf0,0x40,0xf8,0x20,0x00,0x29,0x00,0x00,0xf0,0xf0,0xfa,0x00,0xf0,0x14,0xf8, 0x00,0x00,0x08,0x00,0x70,0x13,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x0c,0x0f,0x00,0x01,0x28,0x0f,0x00,0x01,0xc9,0x02,0x00,0x01,0x01,0x46,0x00,0x20, 0x02,0x46,0x03,0x46,0x00,0xf0,0x9c,0xb8,0x08,0xb5,0x00,0x21,0x04,0x46,0x00,0xf0, 0xf3,0xf8,0x04,0x4b,0x18,0x68,0xc3,0x6b,0x03,0xb1,0x98,0x47,0x20,0x46,0x00,0xf0, 0x55,0xf9,0x00,0xbf,0xcc,0x0a,0x00,0x01,0x38,0xb5,0x08,0x4b,0x08,0x4d,0xed,0x1a, 0xac,0x10,0x18,0xbf,0xed,0x18,0x05,0xd0,0x01,0x3c,0x55,0xf8,0x04,0x3d,0x98,0x47, 0x00,0x2c,0xf9,0xd1,0xbd,0xe8,0x38,0x40,0x00,0xf0,0xe6,0xbb,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x70,0xb5,0x0f,0x4e,0x0f,0x4d,0x76,0x1b,0xb6,0x10,0x18,0xbf, 0x00,0x24,0x05,0xd0,0x01,0x34,0x55,0xf8,0x04,0x3b,0x98,0x47,0xa6,0x42,0xf9,0xd1, 0x0a,0x4e,0x0b,0x4d,0x76,0x1b,0x00,0xf0,0xc9,0xfb,0xb6,0x10,0x18,0xbf,0x00,0x24, 0x06,0xd0,0x01,0x34,0x55,0xf8,0x04,0x3b,0x98,0x47,0xa6,0x42,0xf9,0xd1,0x70,0xbd, 0x70,0xbd,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x0a,0x00,0x01, 0xa4,0x0a,0x00,0x01,0x70,0xb4,0x84,0x07,0x46,0xd0,0x54,0x1e,0x00,0x2a,0x41,0xd0, 0xcd,0xb2,0x03,0x46,0x02,0xe0,0x62,0x1e,0xe4,0xb3,0x14,0x46,0x03,0xf8,0x01,0x5b, 0x9a,0x07,0xf8,0xd1,0x03,0x2c,0x2e,0xd9,0xcd,0xb2,0x45,0xea,0x05,0x25,0x0f,0x2c, 0x45,0xea,0x05,0x45,0x19,0xd9,0x03,0xf1,0x10,0x02,0x26,0x46,0x10,0x3e,0x0f,0x2e, 0x42,0xf8,0x10,0x5c,0x42,0xf8,0x0c,0x5c,0x42,0xf8,0x08,0x5c,0x42,0xf8,0x04,0x5c, 0x02,0xf1,0x10,0x02,0xf2,0xd8,0xa4,0xf1,0x10,0x02,0x22,0xf0,0x0f,0x02,0x04,0xf0, 0x0f,0x04,0x10,0x32,0x03,0x2c,0x13,0x44,0x0d,0xd9,0x1e,0x46,0x22,0x46,0x04,0x3a, 0x03,0x2a,0x46,0xf8,0x04,0x5b,0xfa,0xd8,0x22,0x1f,0x22,0xf0,0x03,0x02,0x04,0x32, 0x13,0x44,0x04,0xf0,0x03,0x04,0x2c,0xb1,0xc9,0xb2,0x1c,0x44,0x03,0xf8,0x01,0x1b, 0xa3,0x42,0xfb,0xd1,0x70,0xbc,0x70,0x47,0x14,0x46,0x03,0x46,0xc2,0xe7,0x00,0xbf, 0x2d,0xe9,0xf0,0x47,0x25,0x4c,0x25,0x68,0xd5,0xf8,0x48,0x41,0x06,0x46,0x88,0x46, 0x92,0x46,0x99,0x46,0xcc,0xb3,0x60,0x68,0x1f,0x28,0x18,0xdc,0x43,0x1c,0x7e,0xb1, 0x04,0xeb,0x80,0x05,0x01,0x21,0xc5,0xf8,0x88,0xa0,0xd4,0xf8,0x88,0x71,0x01,0xfa, 0x00,0xf2,0x17,0x43,0x02,0x2e,0xc4,0xf8,0x88,0x71,0xc5,0xf8,0x08,0x91,0x1e,0xd0, 0x02,0x30,0x63,0x60,0x44,0xf8,0x20,0x80,0x00,0x20,0xbd,0xe8,0xf0,0x87,0x14,0x4b, 0x03,0xb3,0x4f,0xf4,0xc8,0x70,0xaf,0xf3,0x00,0x80,0x04,0x46,0xd0,0xb1,0xd5,0xf8, 0x48,0x31,0x00,0x27,0x80,0xe8,0x88,0x00,0xc5,0xf8,0x48,0x41,0x38,0x46,0x01,0x23, 0xc4,0xf8,0x88,0x71,0xc4,0xf8,0x8c,0x71,0x00,0x2e,0xe1,0xd0,0xd0,0xe7,0xd4,0xf8, 0x8c,0x11,0x0a,0x43,0xc4,0xf8,0x8c,0x21,0xda,0xe7,0x05,0xf5,0xa6,0x74,0xc5,0xf8, 0x48,0x41,0xc0,0xe7,0x4f,0xf0,0xff,0x30,0xbd,0xe8,0xf0,0x87,0xcc,0x0a,0x00,0x01, 0x00,0x00,0x00,0x00,0x02,0x4b,0x13,0xb1,0x02,0x48,0xff,0xf7,0x07,0xbf,0x70,0x47, 0x00,0x00,0x00,0x00,0xc9,0x02,0x00,0x01,0x2d,0xe9,0xf0,0x4f,0x31,0x4b,0x83,0xb0, 0x1b,0x68,0x00,0x93,0x03,0xf5,0xa4,0x73,0x81,0x46,0x0e,0x46,0x01,0x93,0x00,0x9b, 0xd3,0xf8,0x48,0x71,0x27,0xb3,0xdd,0xf8,0x04,0xa0,0x7c,0x68,0x65,0x1e,0x0e,0xd4, 0x01,0x34,0x07,0xeb,0x84,0x04,0x4f,0xf0,0x00,0x08,0xe6,0xb1,0xd4,0xf8,0x00,0x31, 0xb3,0x42,0x18,0xd0,0x01,0x3d,0x6b,0x1c,0xa4,0xf1,0x04,0x04,0xf5,0xd1,0x22,0x4b, 0x73,0xb1,0x7b,0x68,0x00,0x2b,0x36,0xd1,0x3b,0x68,0x00,0x2b,0x34,0xd0,0x38,0x46, 0xca,0xf8,0x00,0x30,0xaf,0xf3,0x00,0x80,0xda,0xf8,0x00,0x70,0x00,0x2f,0xdc,0xd1, 0x03,0xb0,0xbd,0xe8,0xf0,0x8f,0x7b,0x68,0x22,0x68,0x01,0x3b,0xab,0x42,0x0c,0xbf, 0x7d,0x60,0xc4,0xf8,0x00,0x80,0x00,0x2a,0xdc,0xd0,0xd7,0xf8,0x88,0x31,0xd7,0xf8, 0x04,0xb0,0x01,0x21,0xa9,0x40,0x19,0x42,0x08,0xd1,0x90,0x47,0x7b,0x68,0x5b,0x45, 0xbd,0xd1,0xda,0xf8,0x00,0x30,0xbb,0x42,0xcc,0xd0,0xb8,0xe7,0xd7,0xf8,0x8c,0x31, 0x19,0x42,0x04,0xd1,0x48,0x46,0xd4,0xf8,0x80,0x10,0x90,0x47,0xee,0xe7,0xd4,0xf8, 0x80,0x00,0x90,0x47,0xea,0xe7,0x3b,0x68,0xba,0x46,0x1f,0x46,0x00,0x2f,0xac,0xd1, 0xce,0xe7,0x00,0xbf,0xcc,0x0a,0x00,0x01,0x00,0x00,0x00,0x00,0xfe,0xe7,0x00,0xbf, 0xef,0xf3,0x10,0x80,0x72,0xb6,0x70,0x47,0xf8,0xb5,0x20,0x4e,0x20,0x4a,0x33,0x68, 0x20,0x4d,0x21,0x4f,0x21,0x4c,0x4f,0xf0,0x80,0x71,0x91,0x60,0x9b,0x6d,0x00,0x20, 0x98,0x47,0x33,0x68,0x28,0x60,0x9b,0x6d,0x01,0x20,0x98,0x47,0x3b,0x68,0x68,0x60, 0x5b,0x68,0x98,0x47,0x3b,0x68,0x28,0x73,0x1b,0x6a,0x98,0x47,0x63,0x68,0x3a,0x68, 0x68,0x73,0x03,0xf4,0xe0,0x23,0xab,0x60,0x93,0x69,0x00,0x20,0x98,0x47,0x33,0x68, 0x02,0x21,0x5b,0x6d,0x05,0x46,0x00,0x20,0x98,0x47,0x33,0x68,0x01,0x20,0x5b,0x6d, 0x02,0x21,0x98,0x47,0x46,0xf6,0x5a,0x13,0x23,0x60,0x63,0x68,0x23,0xf4,0xe0,0x23, 0x43,0xf4,0x80,0x23,0x00,0x22,0x63,0x60,0x22,0x60,0x09,0x4b,0x1d,0xb1,0x40,0xf6, 0xce,0x22,0x5a,0x60,0xf8,0xbd,0x07,0x4a,0x5a,0x60,0xf8,0xbd,0x1c,0x08,0x00,0x02, 0x00,0xed,0x00,0xe0,0x80,0x01,0x00,0x20,0x34,0x08,0x00,0x02,0x00,0x04,0x01,0x40, 0x50,0x01,0x00,0x20,0x00,0xad,0xde,0x00,0x2d,0xe9,0xf8,0x4f,0x4e,0x4c,0x25,0x69, 0xe7,0x68,0x00,0x2d,0x6d,0xd0,0xdf,0xf8,0x38,0xb1,0xdf,0xf8,0x38,0xa1,0xdf,0xf8, 0x38,0x91,0x4f,0xf0,0x00,0x08,0xdb,0xf8,0x00,0x30,0xb5,0xf5,0x80,0x5f,0x1b,0x69, 0x4f,0xf0,0xff,0x31,0x4f,0xf0,0x01,0x00,0x93,0xbf,0x2e,0x46,0xa5,0xf5,0x80,0x55, 0x4f,0xf4,0x80,0x56,0x00,0x25,0x98,0x47,0xdb,0xf8,0x00,0x30,0x4f,0xf0,0xff,0x31, 0x1b,0x69,0x02,0x20,0x98,0x47,0xdb,0xf8,0x00,0x30,0x03,0x20,0x1b,0x69,0x01,0x46, 0x98,0x47,0x23,0x6a,0x0b,0x2b,0x03,0xd1,0x60,0xe0,0xa3,0x69,0xd9,0x06,0x02,0xd4, 0x63,0x69,0xd8,0x06,0xf9,0xd5,0x63,0x69,0xda,0x06,0x3c,0xd5,0x63,0x69,0xdb,0xf8, 0x00,0x20,0x43,0xf0,0x01,0x03,0x63,0x61,0x93,0x6a,0x39,0x46,0x4f,0xf0,0x20,0x20, 0x32,0x46,0x98,0x47,0x99,0xf8,0x03,0x30,0x03,0xf0,0xef,0x03,0x89,0xf8,0x03,0x30, 0x63,0x69,0x23,0xf0,0x11,0x03,0x80,0x46,0x37,0x44,0x63,0x61,0xdb,0xf8,0x00,0x30, 0x4f,0xf0,0xff,0x31,0x5b,0x69,0x01,0x20,0x98,0x47,0xdb,0xf8,0x00,0x30,0x4f,0xf0, 0xff,0x31,0x5b,0x69,0x02,0x20,0x98,0x47,0xdb,0xf8,0x00,0x30,0x03,0x20,0x5b,0x69, 0x01,0x46,0x98,0x47,0xdb,0xf8,0x00,0x30,0x04,0x20,0x5b,0x69,0x03,0x21,0x98,0x47, 0xb8,0xf1,0x00,0x0f,0x29,0xd0,0x00,0x2d,0x9d,0xd1,0x17,0x4b,0x40,0xf6,0xce,0x22, 0x5a,0x60,0xbd,0xe8,0xf8,0x8f,0xa3,0x69,0xdb,0x06,0xd7,0xd5,0xa3,0x69,0xdb,0xf8, 0x00,0x20,0x12,0x48,0x43,0xf0,0x01,0x03,0xa3,0x61,0x93,0x6a,0x39,0x46,0x32,0x46, 0x98,0x47,0x9a,0xf8,0x02,0x30,0x03,0xf0,0xbf,0x03,0x8a,0xf8,0x02,0x30,0xa3,0x69, 0x23,0xf0,0x11,0x03,0x80,0x46,0x37,0x44,0xa3,0x61,0xbf,0xe7,0xdb,0xf8,0x00,0x30, 0x03,0x21,0x1b,0x69,0x04,0x20,0x98,0x47,0x9a,0xe7,0x03,0x4b,0x4d,0xf6,0xad,0x62, 0x5a,0x60,0xbd,0xe8,0xf8,0x8f,0x00,0xbf,0x50,0x01,0x00,0x20,0x00,0x30,0x00,0x20, 0x1c,0x08,0x00,0x02,0x20,0x4c,0x00,0x40,0x40,0x4c,0x00,0x40,0x13,0x4b,0xdb,0x69, 0xda,0x07,0x70,0xb5,0x14,0xd4,0x11,0x4c,0xe3,0x69,0x9b,0x07,0x00,0xd4,0x70,0xbd, 0x0f,0x4d,0x2b,0x68,0x03,0x20,0x1b,0x69,0x01,0x46,0x98,0x47,0x23,0x6a,0x0b,0x2b, 0xf5,0xd1,0x2b,0x68,0x04,0x20,0x1b,0x69,0x03,0x21,0xbd,0xe8,0x70,0x40,0x18,0x47, 0x07,0x4c,0x23,0x68,0x4f,0xf0,0xff,0x31,0x1b,0x69,0x01,0x20,0x98,0x47,0x23,0x68, 0x4f,0xf0,0xff,0x31,0x1b,0x69,0x02,0x20,0x98,0x47,0xdc,0xe7,0x50,0x01,0x00,0x20, 0x1c,0x08,0x00,0x02,0x2d,0xe9,0xf8,0x43,0x1e,0x4c,0x1f,0x4d,0x1f,0x4f,0x29,0x68, 0x3a,0x68,0xdf,0xf8,0x84,0x90,0x46,0xf6,0x5a,0x18,0xc4,0xf8,0x00,0x80,0x63,0x68, 0x23,0xf4,0xe0,0x23,0x00,0x26,0x43,0xf4,0x80,0x33,0x63,0x60,0x26,0x60,0x53,0x6d, 0x30,0x46,0x98,0x47,0x3b,0x68,0x69,0x68,0x5b,0x6d,0x01,0x20,0x98,0x47,0xd9,0xf8, 0x00,0x30,0x68,0x7b,0x9b,0x69,0x98,0x47,0xd9,0xf8,0x00,0x30,0x07,0x46,0x1b,0x68, 0x28,0x7b,0x98,0x47,0xc4,0xf8,0x00,0x80,0x63,0x68,0xaa,0x68,0x0c,0x49,0x23,0xf4, 0xe0,0x23,0x13,0x43,0x63,0x60,0x26,0x60,0x0a,0x4b,0x8e,0x60,0x28,0xb1,0x27,0xb1, 0x40,0xf6,0xce,0x22,0x5a,0x60,0xbd,0xe8,0xf8,0x83,0x4d,0xf6,0xad,0x62,0x5a,0x60, 0xbd,0xe8,0xf8,0x83,0x00,0x04,0x01,0x40,0x80,0x01,0x00,0x20,0x1c,0x08,0x00,0x02, 0x00,0xed,0x00,0xe0,0x50,0x01,0x00,0x20,0x34,0x08,0x00,0x02,0x8c,0x4b,0x8d,0x4c, 0x1b,0x68,0x8d,0x4d,0x1b,0x68,0x80,0xb5,0x98,0x47,0xff,0xf7,0x81,0xfe,0x27,0x46, 0x23,0x68,0x20,0x2b,0x00,0xf2,0xeb,0x80,0x01,0xa2,0x52,0xf8,0x23,0xf0,0x00,0xbf, 0x71,0x08,0x00,0x01,0xff,0x09,0x00,0x01,0xb9,0x09,0x00,0x01,0x4f,0x0a,0x00,0x01, 0x2f,0x09,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01, 0x21,0x09,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01, 0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01, 0x13,0x09,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01, 0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01, 0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01, 0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01,0x4f,0x0a,0x00,0x01, 0x05,0x09,0x00,0x01,0x01,0x23,0x63,0x60,0xff,0xf7,0x86,0xfe,0x00,0x23,0x23,0x60, 0xae,0xe7,0x01,0x23,0x63,0x60,0xff,0xf7,0x55,0xff,0x00,0x23,0x23,0x60,0xa7,0xe7, 0x01,0x23,0x63,0x60,0xff,0xf7,0x28,0xfe,0x00,0x23,0x23,0x60,0xa0,0xe7,0x2b,0x68, 0x01,0x20,0x60,0x60,0x1b,0x69,0x4f,0xf0,0xff,0x31,0x98,0x47,0x2b,0x68,0x4f,0xf0, 0xff,0x31,0x1b,0x69,0x02,0x20,0x98,0x47,0x2b,0x68,0x03,0x20,0x1b,0x69,0x01,0x46, 0x98,0x47,0x23,0x6a,0x0b,0x2b,0x00,0xf0,0x82,0x80,0x63,0x69,0xdb,0x06,0xfc,0xd5, 0x7b,0x69,0x28,0x68,0x43,0xf0,0x01,0x03,0x7b,0x61,0xf9,0x68,0x83,0x6a,0x3a,0x69, 0x4f,0xf0,0x20,0x20,0x98,0x47,0x7b,0x69,0x2a,0x68,0x23,0xf0,0x11,0x03,0x7b,0x61, 0x53,0x69,0x06,0x46,0x4f,0xf0,0xff,0x31,0x01,0x20,0x98,0x47,0x2b,0x68,0x4f,0xf0, 0xff,0x31,0x5b,0x69,0x02,0x20,0x98,0x47,0x2b,0x68,0x03,0x20,0x5b,0x69,0x01,0x46, 0x98,0x47,0x2b,0x68,0x04,0x20,0x5b,0x69,0x03,0x21,0x98,0x47,0x00,0x2e,0x52,0xd0, 0x40,0xf6,0xce,0x23,0x7b,0x60,0xb0,0xe7,0x2b,0x68,0x01,0x20,0x60,0x60,0x1b,0x69, 0x4f,0xf0,0xff,0x31,0x98,0x47,0x2b,0x68,0x4f,0xf0,0xff,0x31,0x1b,0x69,0x02,0x20, 0x98,0x47,0x2b,0x68,0x03,0x20,0x1b,0x69,0x01,0x46,0x98,0x47,0x23,0x6a,0x0b,0x2b, 0x43,0xd0,0x05,0x26,0x2b,0x68,0xe0,0x68,0x5b,0x6a,0x98,0x47,0x01,0x3e,0x00,0x28, 0x47,0xd1,0x00,0x2e,0xf6,0xd1,0x4d,0xf6,0xad,0x63,0x63,0x60,0x0e,0xe0,0x01,0x23, 0x63,0x60,0xff,0xf7,0xb3,0xfe,0x05,0x26,0x2b,0x68,0x1b,0x6a,0x98,0x47,0x01,0x3e, 0x00,0x28,0x30,0xd1,0x00,0x2e,0xf7,0xd1,0x20,0x4b,0x63,0x60,0x2b,0x68,0x4f,0xf0, 0xff,0x31,0x5b,0x69,0x01,0x20,0x98,0x47,0x2b,0x68,0x4f,0xf0,0xff,0x31,0x5b,0x69, 0x02,0x20,0x98,0x47,0x2b,0x68,0x03,0x20,0x5b,0x69,0x01,0x46,0x98,0x47,0x2b,0x68, 0x04,0x20,0x5b,0x69,0x03,0x21,0x98,0x47,0x00,0x23,0x23,0x60,0x10,0xe7,0x40,0xf6, 0xad,0x33,0x63,0x60,0x0c,0xe7,0x4d,0xf6,0xad,0x63,0x7b,0x60,0x5d,0xe7,0x2b,0x68, 0x03,0x21,0x1b,0x69,0x04,0x20,0x98,0x47,0x77,0xe7,0x2b,0x68,0x03,0x21,0x1b,0x69, 0x04,0x20,0x98,0x47,0xb5,0xe7,0x00,0x2e,0xce,0xd0,0x40,0xf6,0xce,0x23,0x63,0x60, 0xcc,0xe7,0x00,0x2e,0xb7,0xd0,0x40,0xf6,0xce,0x23,0x7b,0x60,0xc6,0xe7,0x00,0xbf, 0x64,0x08,0x00,0x02,0x50,0x01,0x00,0x20,0x1c,0x08,0x00,0x02,0xad,0xde,0xad,0xde, 0xfe,0xe7,0x00,0xbf,0xfd,0x01,0x00,0x01,0x85,0x04,0x00,0x01,0xf8,0xb5,0x00,0xbf, 0xf8,0xbc,0x08,0xbc,0x9e,0x46,0x70,0x47,0xf8,0xb5,0x00,0xbf,0xd5,0x01,0x00,0x01, 0xf8,0xbc,0x08,0xbc,0x9e,0x46,0x70,0x47,0x43,0x00,0x00,0x00,0x08,0x20,0x00,0x20, 0x64,0xf7,0xff,0x7f,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xf4,0x22,0x00,0x20,0x5c,0x23,0x00,0x20,0xc4,0x23,0x00,0x20, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xc8,0x0a,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x0e,0x33,0xcd,0xab,0x34,0x12,0x6d,0xe6,0xec,0xde,0x05,0x00,0x0b,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x20,0x00,0x20, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/msp432p411x/msp432p411x.lds ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ MEMORY { MAIN_FLASH (RX) : ORIGIN = 0x00000000, LENGTH = 0x00200000 INFO_FLASH (RX) : ORIGIN = 0x00200000, LENGTH = 0x00008000 SRAM_CODE_0(RWX): ORIGIN = 0x01000000, LENGTH = 0x00000110 SRAM_CODE_1(RWX): ORIGIN = 0x01000110, LENGTH = 0x00000030 SRAM_CODE_2(RWX): ORIGIN = 0x01000150, LENGTH = 0x00000040 SRAM_CODE_3(RWX): ORIGIN = 0x01000190, LENGTH = 0x00001E70 SRAM_CODE_4(RWX): ORIGIN = 0x01002000, LENGTH = 0x00000200 SRAM_DATA (RW) : ORIGIN = 0x20002000, LENGTH = 0x00001000 } REGION_ALIAS("REGION_INTVECT", SRAM_CODE_0); REGION_ALIAS("REGION_RESET", SRAM_CODE_1); REGION_ALIAS("REGION_DESCRIPTOR", SRAM_CODE_2); REGION_ALIAS("REGION_TEXT", SRAM_CODE_3); REGION_ALIAS("REGION_BSS", SRAM_CODE_3); REGION_ALIAS("REGION_DATA", SRAM_DATA); REGION_ALIAS("REGION_STACK", SRAM_CODE_4); REGION_ALIAS("REGION_HEAP", SRAM_DATA); REGION_ALIAS("REGION_ARM_EXIDX", SRAM_CODE_3); REGION_ALIAS("REGION_ARM_EXTAB", SRAM_CODE_3); SECTIONS { /* section for the interrupt vector area */ .intvecs : { KEEP (*(.intvecs)) } > REGION_INTVECT PROVIDE (_vtable_base_address = DEFINED(_vtable_base_address) ? _vtable_base_address : 0x20000000); .vtable (_vtable_base_address) : AT (_vtable_base_address) { KEEP (*(.vtable)) } > REGION_DATA .descriptor :{ FILL(0x00000000); . = ORIGIN(REGION_DESCRIPTOR) + LENGTH(REGION_DESCRIPTOR) - 1; BYTE(0x00); __ROM_AT = .; } > REGION_DESCRIPTOR .reset : { KEEP(*(.reset)) } > REGION_RESET AT> REGION_RESET .text : { CREATE_OBJECT_SYMBOLS KEEP (*(.text)) *(.text.*) . = ALIGN(0x4); KEEP (*(.ctors)) . = ALIGN(0x4); KEEP (*(.dtors)) . = ALIGN(0x4); __init_array_start = .; KEEP (*(.init_array*)) __init_array_end = .; KEEP (*(.init)) KEEP (*(.fini*)) } > REGION_TEXT AT> REGION_TEXT .rodata : { *(.rodata) *(.rodata.*) } > REGION_TEXT AT> REGION_TEXT .ARM.exidx : { __exidx_start = .; *(.ARM.exidx* .gnu.linkonce.armexidx.*) __exidx_end = .; } > REGION_ARM_EXIDX AT> REGION_ARM_EXIDX .ARM.extab : { KEEP (*(.ARM.extab* .gnu.linkonce.armextab.*)) } > REGION_ARM_EXTAB AT> REGION_ARM_EXTAB __etext = .; .data : { __data_load__ = LOADADDR (.data); __data_start__ = .; KEEP (*(.data)) KEEP (*(.data*)) . = ALIGN (4); __data_end__ = .; } > REGION_DATA AT> REGION_TEXT .bss : { __bss_start__ = .; *(.shbss) KEEP (*(.bss)) *(.bss.*) *(COMMON) . = ALIGN (4); __bss_end__ = .; } > REGION_BSS AT> REGION_BSS .heap : { __heap_start__ = .; end = __heap_start__; _end = end; __end = end; KEEP (*(.heap)) __heap_end__ = .; __HeapLimit = __heap_end__; } > REGION_HEAP AT> REGION_HEAP .stack (NOLOAD) : ALIGN(0x8) { _stack = .; KEEP(*(.stack)) } > REGION_STACK AT> REGION_STACK __stack_top = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK); PROVIDE(__stack = __stack_top); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/msp432p411x.h ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /****************************************************************************** * * Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432P411X_H #define OPENOCD_LOADERS_FLASH_MSP432_MSP432P411X_H #include #ifdef __cplusplus extern "C" { #endif /* Available Peripherals */ #define __MCU_HAS_FLCTL_A__ /* Module FLCTL_A is available */ #define __MCU_HAS_SYSCTL_A__ /* Module SYSCTL_A is available */ /* Device and Peripheral Memory Map */ #define FLASH_BASE ((uint32_t)0x00000000) /* Flash memory address */ #define PERIPH_BASE ((uint32_t)0x40000000) /* Peripherals address */ #define CS_BASE (PERIPH_BASE + 0x00010400) /* Address of CS regs. */ #define PCM_BASE (PERIPH_BASE + 0x00010000) /* Address of PCM regs. */ #define RTC_C_BASE (PERIPH_BASE + 0x00004400) /* Address of RTC_C regs */ #define TLV_BASE ((uint32_t)0x00201000) /* Address of TLV regs. */ #define WDT_A_BASE (PERIPH_BASE + 0x00004800) /* Address of WDT_A regs */ #define BITBAND_PERI_BASE ((uint32_t)(0x42000000)) /* * Peripherals with 8-bit or 16-bit register access allow only 8-bit or * 16-bit bit band access, so cast to 8 bit always */ #define BITBAND_PERI(x, b) (*((volatile uint8_t *) (BITBAND_PERI_BASE + \ (((uint32_t)(uint32_t *)&(x)) - PERIPH_BASE)*32 + (b)*4))) /* Register map for CLock Signal peripheral (CS) */ struct cs { volatile uint32_t KEY; /* Key Register */ volatile uint32_t CTL0; /* Control 0 Register */ volatile uint32_t CTL1; /* Control 1 Register */ volatile uint32_t CTL2; /* Control 2 Register */ volatile uint32_t CTL3; /* Control 3 Register */ }; /* Register map for Power Control Module peripheral (PCM) */ struct pcm { volatile uint32_t CTL0; /* Control 0 Register */ volatile uint32_t CTL1; /* Control 1 Register */ volatile uint32_t IE; /* Interrupt Enable Register */ volatile uint32_t IFG; /* Interrupt Flag Register */ volatile uint32_t CLRIFG; /* Clear Interrupt Flag Register */ }; /* Register map for Real-Time Clock peripheral (RTC_C) */ struct rtc_c { volatile uint16_t CTL0; /* RTCCTL0 Register */ volatile uint16_t CTL13; /* RTCCTL13 Register */ volatile uint16_t OCAL; /* RTCOCAL Register */ volatile uint16_t TCMP; /* RTCTCMP Register */ volatile uint16_t PS0CTL; /* RTC Prescale Timer 0 Control Register */ volatile uint16_t PS1CTL; /* RTC Prescale Timer 1 Control Register */ volatile uint16_t PS; /* Real-Time Clock Prescale Timer Register */ volatile uint16_t IV; /* Real-Time Clock Interrupt Vector Register */ volatile uint16_t TIM0; /* RTCTIM0 Register Hexadecimal Format */ volatile uint16_t TIM1; /* Real-Time Clock Hour, Day of Week */ volatile uint16_t DATE; /* RTCDATE - Hexadecimal Format */ volatile uint16_t YEAR; /* RTCYEAR Register - Hexadecimal Format */ volatile uint16_t AMINHR; /* RTCMINHR - Hexadecimal Format */ volatile uint16_t ADOWDAY; /* RTCADOWDAY - Hexadecimal Format */ volatile uint16_t BIN2BCD; /* Binary-to-BCD Conversion Register */ volatile uint16_t BCD2BIN; /* BCD-to-Binary Conversion Register */ }; /* Register map for Watchdog Timer peripheral (WDT_A) */ struct wdt_a { uint16_t RESERVED0[6]; volatile uint16_t CTL; /* Watchdog Timer Control Register */ }; /* Peripheral Declarations */ #define CS ((struct cs *) CS_BASE) #define PCM ((struct pcm *) PCM_BASE) #define RTC_C ((struct rtc_c *) RTC_C_BASE) #define WDT_A ((struct wdt_a *) WDT_A_BASE) /* Peripheral Register Bit Definitions */ /* DCORSEL Bit Mask */ #define CS_CTL0_DCORSEL_MASK ((uint32_t)0x00070000) /* Nominal DCO Frequency Range (MHz): 2 to 4 */ #define CS_CTL0_DCORSEL_1 ((uint32_t)0x00010000) /* Nominal DCO Frequency Range (MHz): 16 to 32 */ #define CS_CTL0_DCORSEL_4 ((uint32_t)0x00040000) /* CS control key value */ #define CS_KEY_VAL ((uint32_t)0x0000695A) /* AMR Bit Mask */ #define PCM_CTL0_AMR_MASK ((uint32_t)0x0000000F) /* LPMR Bit Mask */ #define PCM_CTL0_LPMR_MASK ((uint32_t)0x000000F0) /* LPM3.5. Core voltage setting 0. */ #define PCM_CTL0_LPMR_10 ((uint32_t)0x000000A0) /* LPM4.5 */ #define PCM_CTL0_LPMR_12 ((uint32_t)0x000000C0) /* CPM Bit Offset */ #define PCM_CTL0_CPM_OFS (8) /* CPM Bit Mask */ #define PCM_CTL0_CPM_MASK ((uint32_t)0x00003F00) /* PCMKEY Bit Mask */ #define PCM_CTL0_KEY_MASK ((uint32_t)0xFFFF0000) /* PMR_BUSY Bit Offset */ #define PCM_CTL1_PMR_BUSY_OFS (8) /* RTCKEY Bit Offset */ #define RTC_C_CTL0_KEY_OFS (8) /* RTCKEY Bit Mask */ #define RTC_C_CTL0_KEY_MASK ((uint16_t)0xFF00) /* RTCHOLD Bit Offset */ #define RTC_C_CTL13_HOLD_OFS (6) /* RTC_C Key Value for RTC_C write access */ #define RTC_C_KEY ((uint16_t)0xA500) /* Watchdog timer hold */ #define WDT_A_CTL_HOLD ((uint16_t)0x0080) /* WDT Key Value for WDT write access */ #define WDT_A_CTL_PW ((uint16_t)0x5A00) /* Address of BSL API table */ #define BSL_API_TABLE_ADDR ((uint32_t)0x00202000) #ifdef __cplusplus } #endif #endif /* OPENOCD_LOADERS_FLASH_MSP432_MSP432P411X_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/msp432p411x_algo.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x00,0x22,0x00,0x01,0x11,0x01,0x00,0x01,0x0d,0x12,0x00,0x01,0x0d,0x12,0x00,0x01, 0x0d,0x12,0x00,0x01,0x0d,0x12,0x00,0x01,0x0d,0x12,0x00,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x12,0x00,0x01, 0x0d,0x12,0x00,0x01,0x00,0x00,0x00,0x00,0x0d,0x12,0x00,0x01,0x0d,0x12,0x00,0x01, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x41,0xf2,0x00,0x70,0xc0,0xf2,0x00,0x10,0x85,0x46,0x05,0x48,0x05,0x49,0x4f,0xf0, 0x00,0x02,0x88,0x42,0xb8,0xbf,0x40,0xf8,0x04,0x2b,0xfa,0xdb,0x00,0xf0,0xaa,0xbf, 0x78,0x16,0x00,0x01,0x94,0x16,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x04,0x4b,0x05,0x48,0x1b,0x1a,0x06,0x2b,0x02,0xd9,0x04,0x4b,0x03,0xb1,0x18,0x47, 0x70,0x47,0x00,0xbf,0x37,0x24,0x00,0x20,0x34,0x24,0x00,0x20,0x00,0x00,0x00,0x00, 0x05,0x49,0x06,0x48,0x09,0x1a,0x89,0x10,0x01,0xeb,0xd1,0x71,0x49,0x10,0x02,0xd0, 0x03,0x4b,0x03,0xb1,0x18,0x47,0x70,0x47,0x34,0x24,0x00,0x20,0x34,0x24,0x00,0x20, 0x00,0x00,0x00,0x00,0x10,0xb5,0x06,0x4c,0x23,0x78,0x43,0xb9,0xff,0xf7,0xd8,0xff, 0x04,0x4b,0x13,0xb1,0x04,0x48,0xaf,0xf3,0x00,0x80,0x01,0x23,0x23,0x70,0x10,0xbd, 0x78,0x16,0x00,0x01,0x00,0x00,0x00,0x00,0x3c,0x12,0x00,0x01,0x08,0xb5,0x08,0x4b, 0x1b,0xb1,0x08,0x48,0x08,0x49,0xaf,0xf3,0x00,0x80,0x08,0x48,0x03,0x68,0x13,0xb9, 0xbd,0xe8,0x08,0x40,0xcc,0xe7,0x06,0x4b,0x00,0x2b,0xf9,0xd0,0x98,0x47,0xf7,0xe7, 0x00,0x00,0x00,0x00,0x3c,0x12,0x00,0x01,0x7c,0x16,0x00,0x01,0x34,0x24,0x00,0x20, 0x00,0x00,0x00,0x00,0x13,0x4b,0x00,0x2b,0x08,0xbf,0x11,0x4b,0x9d,0x46,0xa3,0xf5, 0x80,0x3a,0x00,0x21,0x8b,0x46,0x0f,0x46,0x11,0x48,0x12,0x4a,0x12,0x1a,0x00,0xf0, 0x79,0xf8,0x0d,0x4b,0x00,0x2b,0x00,0xd0,0x98,0x47,0x0c,0x4b,0x00,0x2b,0x00,0xd0, 0x98,0x47,0x00,0x20,0x00,0x21,0x04,0x00,0x0d,0x00,0x0b,0x48,0x00,0xf0,0x16,0xf8, 0x00,0xf0,0x40,0xf8,0x20,0x00,0x29,0x00,0x00,0xf0,0x04,0xff,0x00,0xf0,0x14,0xf8, 0x00,0x00,0x08,0x00,0x00,0x22,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x78,0x16,0x00,0x01,0x94,0x16,0x00,0x01,0xc9,0x02,0x00,0x01,0x01,0x46,0x00,0x20, 0x02,0x46,0x03,0x46,0x00,0xf0,0x9c,0xb8,0x08,0xb5,0x00,0x21,0x04,0x46,0x00,0xf0, 0xf3,0xf8,0x04,0x4b,0x18,0x68,0xc3,0x6b,0x03,0xb1,0x98,0x47,0x20,0x46,0x00,0xf0, 0x55,0xf9,0x00,0xbf,0x38,0x12,0x00,0x01,0x38,0xb5,0x08,0x4b,0x08,0x4d,0xed,0x1a, 0xac,0x10,0x18,0xbf,0xed,0x18,0x05,0xd0,0x01,0x3c,0x55,0xf8,0x04,0x3d,0x98,0x47, 0x00,0x2c,0xf9,0xd1,0xbd,0xe8,0x38,0x40,0x00,0xf0,0x9c,0xbf,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x70,0xb5,0x0f,0x4e,0x0f,0x4d,0x76,0x1b,0xb6,0x10,0x18,0xbf, 0x00,0x24,0x05,0xd0,0x01,0x34,0x55,0xf8,0x04,0x3b,0x98,0x47,0xa6,0x42,0xf9,0xd1, 0x0a,0x4e,0x0b,0x4d,0x76,0x1b,0x00,0xf0,0x7f,0xff,0xb6,0x10,0x18,0xbf,0x00,0x24, 0x06,0xd0,0x01,0x34,0x55,0xf8,0x04,0x3b,0x98,0x47,0xa6,0x42,0xf9,0xd1,0x70,0xbd, 0x70,0xbd,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x12,0x00,0x01, 0x10,0x12,0x00,0x01,0x70,0xb4,0x84,0x07,0x46,0xd0,0x54,0x1e,0x00,0x2a,0x41,0xd0, 0xcd,0xb2,0x03,0x46,0x02,0xe0,0x62,0x1e,0xe4,0xb3,0x14,0x46,0x03,0xf8,0x01,0x5b, 0x9a,0x07,0xf8,0xd1,0x03,0x2c,0x2e,0xd9,0xcd,0xb2,0x45,0xea,0x05,0x25,0x0f,0x2c, 0x45,0xea,0x05,0x45,0x19,0xd9,0x03,0xf1,0x10,0x02,0x26,0x46,0x10,0x3e,0x0f,0x2e, 0x42,0xf8,0x10,0x5c,0x42,0xf8,0x0c,0x5c,0x42,0xf8,0x08,0x5c,0x42,0xf8,0x04,0x5c, 0x02,0xf1,0x10,0x02,0xf2,0xd8,0xa4,0xf1,0x10,0x02,0x22,0xf0,0x0f,0x02,0x04,0xf0, 0x0f,0x04,0x10,0x32,0x03,0x2c,0x13,0x44,0x0d,0xd9,0x1e,0x46,0x22,0x46,0x04,0x3a, 0x03,0x2a,0x46,0xf8,0x04,0x5b,0xfa,0xd8,0x22,0x1f,0x22,0xf0,0x03,0x02,0x04,0x32, 0x13,0x44,0x04,0xf0,0x03,0x04,0x2c,0xb1,0xc9,0xb2,0x1c,0x44,0x03,0xf8,0x01,0x1b, 0xa3,0x42,0xfb,0xd1,0x70,0xbc,0x70,0x47,0x14,0x46,0x03,0x46,0xc2,0xe7,0x00,0xbf, 0x2d,0xe9,0xf0,0x47,0x25,0x4c,0x25,0x68,0xd5,0xf8,0x48,0x41,0x06,0x46,0x88,0x46, 0x92,0x46,0x99,0x46,0xcc,0xb3,0x60,0x68,0x1f,0x28,0x18,0xdc,0x43,0x1c,0x7e,0xb1, 0x04,0xeb,0x80,0x05,0x01,0x21,0xc5,0xf8,0x88,0xa0,0xd4,0xf8,0x88,0x71,0x01,0xfa, 0x00,0xf2,0x17,0x43,0x02,0x2e,0xc4,0xf8,0x88,0x71,0xc5,0xf8,0x08,0x91,0x1e,0xd0, 0x02,0x30,0x63,0x60,0x44,0xf8,0x20,0x80,0x00,0x20,0xbd,0xe8,0xf0,0x87,0x14,0x4b, 0x03,0xb3,0x4f,0xf4,0xc8,0x70,0xaf,0xf3,0x00,0x80,0x04,0x46,0xd0,0xb1,0xd5,0xf8, 0x48,0x31,0x00,0x27,0x80,0xe8,0x88,0x00,0xc5,0xf8,0x48,0x41,0x38,0x46,0x01,0x23, 0xc4,0xf8,0x88,0x71,0xc4,0xf8,0x8c,0x71,0x00,0x2e,0xe1,0xd0,0xd0,0xe7,0xd4,0xf8, 0x8c,0x11,0x0a,0x43,0xc4,0xf8,0x8c,0x21,0xda,0xe7,0x05,0xf5,0xa6,0x74,0xc5,0xf8, 0x48,0x41,0xc0,0xe7,0x4f,0xf0,0xff,0x30,0xbd,0xe8,0xf0,0x87,0x38,0x12,0x00,0x01, 0x00,0x00,0x00,0x00,0x02,0x4b,0x13,0xb1,0x02,0x48,0xff,0xf7,0x07,0xbf,0x70,0x47, 0x00,0x00,0x00,0x00,0xc9,0x02,0x00,0x01,0x2d,0xe9,0xf0,0x4f,0x31,0x4b,0x83,0xb0, 0x1b,0x68,0x00,0x93,0x03,0xf5,0xa4,0x73,0x81,0x46,0x0e,0x46,0x01,0x93,0x00,0x9b, 0xd3,0xf8,0x48,0x71,0x27,0xb3,0xdd,0xf8,0x04,0xa0,0x7c,0x68,0x65,0x1e,0x0e,0xd4, 0x01,0x34,0x07,0xeb,0x84,0x04,0x4f,0xf0,0x00,0x08,0xe6,0xb1,0xd4,0xf8,0x00,0x31, 0xb3,0x42,0x18,0xd0,0x01,0x3d,0x6b,0x1c,0xa4,0xf1,0x04,0x04,0xf5,0xd1,0x22,0x4b, 0x73,0xb1,0x7b,0x68,0x00,0x2b,0x36,0xd1,0x3b,0x68,0x00,0x2b,0x34,0xd0,0x38,0x46, 0xca,0xf8,0x00,0x30,0xaf,0xf3,0x00,0x80,0xda,0xf8,0x00,0x70,0x00,0x2f,0xdc,0xd1, 0x03,0xb0,0xbd,0xe8,0xf0,0x8f,0x7b,0x68,0x22,0x68,0x01,0x3b,0xab,0x42,0x0c,0xbf, 0x7d,0x60,0xc4,0xf8,0x00,0x80,0x00,0x2a,0xdc,0xd0,0xd7,0xf8,0x88,0x31,0xd7,0xf8, 0x04,0xb0,0x01,0x21,0xa9,0x40,0x19,0x42,0x08,0xd1,0x90,0x47,0x7b,0x68,0x5b,0x45, 0xbd,0xd1,0xda,0xf8,0x00,0x30,0xbb,0x42,0xcc,0xd0,0xb8,0xe7,0xd7,0xf8,0x8c,0x31, 0x19,0x42,0x04,0xd1,0x48,0x46,0xd4,0xf8,0x80,0x10,0x90,0x47,0xee,0xe7,0xd4,0xf8, 0x80,0x00,0x90,0x47,0xea,0xe7,0x3b,0x68,0xba,0x46,0x1f,0x46,0x00,0x2f,0xac,0xd1, 0xce,0xe7,0x00,0xbf,0x38,0x12,0x00,0x01,0x00,0x00,0x00,0x00,0xfe,0xe7,0x00,0xbf, 0x4f,0x4a,0x13,0x68,0xc3,0xf3,0x05,0x23,0x04,0x3b,0xdb,0xb2,0x15,0x2b,0x70,0xb4, 0x00,0xf2,0x8c,0x80,0x01,0x22,0x02,0xfa,0x03,0xf3,0x13,0xf0,0x30,0x1f,0x61,0xd0, 0x02,0x23,0x98,0x42,0x31,0xd0,0x46,0x4b,0x1b,0x68,0xc3,0xf3,0x05,0x23,0x44,0x4c, 0x44,0x49,0x01,0x25,0x22,0x68,0x09,0x2b,0x10,0xd8,0xdf,0xe8,0x03,0xf0,0x05,0x35, 0x0f,0x0f,0x45,0x29,0x0f,0x0f,0x45,0x29,0x01,0x28,0x63,0xd0,0x02,0x28,0x73,0xd1, 0x4f,0xf6,0xf0,0x76,0x3c,0x4b,0x16,0x40,0x33,0x43,0x23,0x60,0x0b,0x78,0x03,0xf0, 0xff,0x02,0x00,0x2b,0xfa,0xd1,0x23,0x68,0xc3,0xf3,0x05,0x23,0x04,0x3b,0xdb,0xb2, 0x15,0x2b,0x05,0xd8,0x05,0xfa,0x03,0xf3,0x13,0xf0,0x30,0x1f,0x38,0xd0,0x02,0x22, 0x23,0x68,0x90,0x42,0xc3,0xf3,0x05,0x23,0xd4,0xd1,0x01,0x20,0x70,0xbc,0x70,0x47, 0x4f,0xf6,0xf0,0x76,0x2d,0x4b,0x16,0x40,0x33,0x43,0x23,0x60,0x0b,0x78,0x03,0xf0, 0xff,0x02,0x00,0x2b,0xda,0xd1,0xde,0xe7,0x01,0x28,0x27,0xd0,0x02,0x28,0x43,0xd1, 0x4f,0xf6,0xf0,0x76,0x26,0x4b,0x16,0x40,0x33,0x43,0x23,0x60,0x0b,0x78,0x03,0xf0, 0xff,0x02,0x00,0x2b,0xca,0xd1,0xce,0xe7,0x4f,0xf6,0xf0,0x73,0x13,0x40,0x43,0xf0, 0xd2,0x43,0x43,0xf4,0xb4,0x03,0x23,0x60,0x0b,0x78,0x03,0xf0,0xff,0x02,0x00,0x2b, 0xbc,0xd1,0xc0,0xe7,0x13,0xf0,0x03,0x1f,0x14,0xbf,0x13,0x46,0x00,0x23,0x98,0xe7, 0x13,0xf0,0x03,0x1f,0x14,0xbf,0x01,0x22,0x00,0x22,0xc1,0xe7,0x4f,0xf6,0xf0,0x76, 0x14,0x4b,0x16,0x40,0x33,0x43,0x23,0x60,0x0b,0x78,0x03,0xf0,0xff,0x02,0x00,0x2b, 0xa4,0xd1,0xa8,0xe7,0x4f,0xf6,0xf0,0x76,0x0f,0x4b,0x16,0x40,0x33,0x43,0x23,0x60, 0x0b,0x78,0x03,0xf0,0xff,0x02,0x00,0x2b,0x98,0xd1,0x9c,0xe7,0x00,0x28,0xac,0xd0, 0x13,0x68,0xc3,0xf3,0x05,0x23,0x7a,0xe7,0x00,0x20,0x70,0xbc,0x70,0x47,0x00,0xbf, 0x00,0x00,0x01,0x40,0xa0,0x00,0x20,0x42,0x08,0x00,0x5a,0x69,0x01,0x00,0x5a,0x69, 0x09,0x00,0x5a,0x69,0x05,0x00,0x5a,0x69,0x04,0x00,0x5a,0x69,0x4a,0x4b,0x1b,0x68, 0xc3,0xf3,0x05,0x23,0x04,0x3b,0xdb,0xb2,0x15,0x2b,0xf0,0xb4,0x7e,0xd8,0x01,0x22, 0x02,0xfa,0x03,0xf3,0x13,0xf0,0x30,0x1f,0x5f,0xd0,0x02,0x26,0x42,0x4b,0x1b,0x68, 0xc3,0xf3,0x05,0x23,0x01,0x3b,0xdb,0xb2,0x1f,0x2b,0x69,0xd8,0x01,0x22,0x02,0xfa, 0x03,0xf3,0x03,0xf0,0x11,0x31,0x21,0xf0,0x10,0x21,0x00,0x29,0x68,0xd1,0x00,0x2b, 0xb4,0xbf,0x02,0x23,0x00,0x23,0x98,0x42,0x5d,0xd0,0x37,0x4c,0x37,0x49,0x01,0x25, 0x22,0x68,0x23,0x68,0xc3,0xf3,0x05,0x23,0x09,0x2b,0x0e,0xd8,0x05,0xfa,0x03,0xf3, 0x13,0xf4,0x89,0x7f,0x41,0xd1,0x40,0xf2,0x21,0x27,0x1f,0x40,0x2f,0xb1,0x4f,0xf6, 0xf0,0x77,0x2f,0x4b,0x17,0x40,0x3b,0x43,0x23,0x60,0x0b,0x78,0x03,0xf0,0xff,0x02, 0x00,0x2b,0xfa,0xd1,0x23,0x68,0xc3,0xf3,0x05,0x23,0x01,0x3b,0xdb,0xb2,0x1f,0x2b, 0x29,0xd8,0x05,0xfa,0x03,0xf3,0x03,0xf0,0x11,0x37,0x27,0xf0,0x10,0x27,0x6f,0xbb, 0x00,0x2b,0xb4,0xbf,0x02,0x23,0x00,0x23,0x98,0x42,0xd1,0xd1,0x1e,0x4b,0x1b,0x68, 0xc3,0xf3,0x05,0x23,0x04,0x3b,0xdb,0xb2,0x15,0x2b,0x06,0xd8,0x01,0x22,0x02,0xfa, 0x03,0xf3,0x13,0xf0,0x30,0x1f,0x25,0xd0,0x02,0x22,0x96,0x42,0x1b,0xd0,0x01,0x2e, 0x25,0xd0,0x02,0x20,0xf0,0xbc,0xff,0xf7,0xe3,0xbe,0x13,0xf0,0x03,0x1f,0x14,0xbf, 0x16,0x46,0x00,0x26,0x9a,0xe7,0x13,0x46,0xde,0xe7,0x4f,0xf6,0xf0,0x73,0x13,0x40, 0x43,0xf0,0xd2,0x43,0x43,0xf4,0xb4,0x03,0x23,0x60,0xbe,0xe7,0x01,0x23,0xd3,0xe7, 0x00,0x23,0x98,0x42,0xa1,0xd1,0x01,0x20,0xf0,0xbc,0x70,0x47,0x00,0x26,0x85,0xe7, 0x13,0x46,0x98,0xe7,0x13,0xf0,0x03,0x1f,0x08,0xbf,0x00,0x22,0xd5,0xe7,0x30,0x46, 0xf0,0xbc,0xff,0xf7,0xbd,0xbe,0x00,0xbf,0x00,0x00,0x01,0x40,0xa0,0x00,0x20,0x42, 0x01,0x00,0x5a,0x69,0xef,0xf3,0x10,0x80,0x72,0xb6,0x70,0x47,0x30,0xbf,0x70,0x47, 0x04,0x4a,0x08,0xb5,0x13,0x69,0x23,0xf0,0x04,0x03,0x13,0x61,0xff,0xf7,0xf6,0xff, 0x01,0x20,0x08,0xbd,0x00,0xed,0x00,0xe0,0xff,0xf7,0x50,0xbf,0x0b,0x4b,0x1b,0x68, 0xc3,0xf3,0x05,0x23,0x01,0x3b,0xdb,0xb2,0x1f,0x2b,0x0c,0xd8,0x01,0x20,0x00,0xfa, 0x03,0xf2,0x02,0xf0,0x11,0x33,0x23,0xf0,0x10,0x23,0x2b,0xb9,0x00,0x2a,0xb4,0xbf, 0x02,0x20,0x00,0x20,0x70,0x47,0x00,0x20,0x70,0x47,0x00,0xbf,0x00,0x00,0x01,0x40, 0x2d,0xe9,0xf8,0x43,0x7b,0x4e,0x7c,0x4c,0xdf,0xf8,0x00,0x82,0x7b,0x4f,0x7c,0x4d, 0x33,0x78,0x00,0x2b,0x43,0xd1,0x23,0x68,0x03,0xf0,0xf0,0x03,0xa0,0x2b,0x3e,0xd0, 0x23,0x68,0x03,0xf0,0xf0,0x03,0xc0,0x2b,0x39,0xd0,0x23,0x68,0xc3,0xf3,0x05,0x23, 0x04,0x3b,0xdb,0xb2,0x15,0x2b,0x08,0xd8,0x01,0x22,0x02,0xfa,0x03,0xf3,0x13,0xf0, 0x30,0x10,0x02,0xd1,0x13,0xf0,0x03,0x1f,0x55,0xd1,0x23,0x68,0xc3,0xf3,0x05,0x29, 0x22,0x68,0x4f,0xf6,0x0f,0x73,0x13,0x40,0x43,0xf0,0xd2,0x43,0x43,0xf4,0xb4,0x03, 0x23,0x60,0x2b,0x69,0x43,0xf0,0x04,0x03,0x2b,0x61,0xff,0xf7,0x9f,0xff,0x2b,0x69, 0x23,0xf0,0x04,0x03,0x2b,0x61,0x23,0x68,0xc3,0xf3,0x05,0x23,0x4b,0x45,0x29,0xd0, 0xb9,0xf1,0x11,0x0f,0x6b,0xd0,0x0d,0xd9,0xb9,0xf1,0x19,0x0f,0x72,0xd0,0x4b,0xd9, 0xb9,0xf1,0x21,0x0f,0x35,0xd0,0x02,0xd8,0xb9,0xf1,0x20,0x0f,0xb8,0xd0,0x00,0x20, 0xbd,0xe8,0xf8,0x83,0xb9,0xf1,0x05,0x0f,0x6f,0xd0,0x16,0xd9,0xb9,0xf1,0x09,0x0f, 0x00,0xf0,0x8c,0x80,0xb9,0xf1,0x10,0x0f,0x00,0xf0,0x81,0x80,0xb9,0xf1,0x08,0x0f, 0xed,0xd1,0x00,0x20,0xff,0xf7,0xd2,0xfe,0x98,0xb1,0x02,0x20,0xbd,0xe8,0xf8,0x43, 0xff,0xf7,0x1e,0xbe,0x01,0x20,0xbd,0xe8,0xf8,0x83,0xb9,0xf1,0x01,0x0f,0x68,0xd0, 0x5d,0xd3,0xb9,0xf1,0x04,0x0f,0xda,0xd1,0x00,0x20,0xff,0xf7,0xbf,0xfe,0x00,0x28, 0x50,0xd1,0xbd,0xe8,0xf8,0x83,0x23,0x68,0xc3,0xf3,0x05,0x29,0xff,0xf7,0x08,0xfe, 0xa6,0xe7,0x40,0x49,0x40,0x4a,0x8b,0x89,0x03,0xf0,0x7f,0x03,0x43,0xf4,0xb5,0x43, 0x8b,0x81,0x13,0x88,0xdb,0xb2,0x43,0xf4,0x25,0x43,0x01,0x20,0x00,0x21,0x13,0x80, 0x88,0xf8,0x00,0x00,0x39,0x70,0x72,0xe7,0xb9,0xf1,0x15,0x0f,0x5b,0xd0,0xb9,0xf1, 0x18,0x0f,0x51,0xd0,0xb9,0xf1,0x14,0x0f,0xb1,0xd1,0x00,0x20,0xff,0xf7,0x96,0xfe, 0x00,0x28,0xac,0xd0,0x01,0x20,0xff,0xf7,0xe3,0xfd,0x00,0x28,0xa7,0xd0,0x29,0x4b, 0x1b,0x78,0x00,0x2b,0xa3,0xd1,0xbd,0xe8,0xf8,0x43,0xff,0xf7,0x29,0xbf,0x01,0x20, 0xff,0xf7,0x84,0xfe,0x00,0x28,0x9a,0xd0,0x00,0x20,0xff,0xf7,0xd1,0xfd,0x00,0x28, 0xed,0xd1,0x94,0xe7,0x01,0x20,0xff,0xf7,0x79,0xfe,0x00,0x28,0x8f,0xd0,0x02,0x20, 0xff,0xf7,0xc6,0xfd,0x00,0x28,0xe2,0xd1,0x89,0xe7,0x01,0x20,0xff,0xf7,0x6e,0xfe, 0x00,0x28,0xae,0xd0,0x01,0x20,0xbd,0xe8,0xf8,0x43,0xff,0xf7,0xb9,0xbd,0x00,0x20, 0xff,0xf7,0x64,0xfe,0x00,0x28,0xa4,0xd0,0x00,0x20,0xbd,0xe8,0xf8,0x43,0xff,0xf7, 0xaf,0xbd,0x48,0x46,0xff,0xf7,0x5a,0xfe,0x00,0x28,0x9a,0xd0,0xf4,0xe7,0x00,0x20, 0xff,0xf7,0x54,0xfe,0x00,0x28,0x3f,0xf4,0x6a,0xaf,0xcd,0xe7,0x01,0x20,0xff,0xf7, 0x4d,0xfe,0x00,0x28,0x8d,0xd0,0x78,0xe7,0x00,0x20,0xff,0xf7,0x47,0xfe,0x00,0x28, 0x3f,0xf4,0x5d,0xaf,0xcb,0xe7,0x01,0x20,0xff,0xf7,0x40,0xfe,0x00,0x28,0x3f,0xf4, 0x56,0xaf,0xa7,0xe7,0xa0,0x00,0x20,0x42,0x00,0x00,0x01,0x40,0x20,0x80,0x08,0x42, 0x00,0xed,0x00,0xe0,0x00,0x48,0x00,0x40,0x00,0x44,0x00,0x40,0x58,0x80,0x08,0x42, 0x6b,0x49,0x30,0xb5,0x0a,0x68,0xc2,0xf3,0x05,0x22,0x90,0x42,0x83,0xb0,0x21,0xd0, 0x11,0x28,0x00,0xf0,0xbf,0x80,0x20,0xd9,0x19,0x28,0x00,0xf0,0x95,0x80,0x3a,0xd9, 0x21,0x28,0x5d,0xd0,0x55,0xd9,0xa0,0x28,0x00,0xf0,0x86,0x80,0xc0,0x28,0x1e,0xd1, 0x60,0x4b,0x1b,0x78,0xdb,0xb9,0x60,0x48,0x5d,0x49,0x02,0x69,0x5f,0x4b,0x42,0xf0, 0x04,0x02,0x02,0x61,0x08,0x68,0x4f,0xf6,0x0f,0x72,0x02,0x40,0x13,0x43,0x0b,0x60, 0xff,0xf7,0xa4,0xfe,0x01,0x20,0x03,0xb0,0x30,0xbd,0x05,0x28,0x00,0xf0,0xa1,0x80, 0x08,0xd9,0x09,0x28,0x62,0xd0,0x10,0x28,0x55,0xd0,0x08,0x28,0x4c,0xd0,0x00,0x20, 0x03,0xb0,0x30,0xbd,0x01,0x28,0x00,0xf0,0x87,0x80,0x7d,0xd3,0x04,0x28,0xf6,0xd1, 0x00,0x20,0xff,0xf7,0xeb,0xfd,0x00,0x28,0xe5,0xd0,0x01,0x20,0x03,0xb0,0xbd,0xe8, 0x30,0x40,0xff,0xf7,0x35,0xbd,0x15,0x28,0x67,0xd0,0x18,0x28,0x5f,0xd0,0x14,0x28, 0xe5,0xd1,0x00,0x20,0xff,0xf7,0xda,0xfd,0x00,0x28,0xe0,0xd0,0x01,0x20,0xff,0xf7, 0x27,0xfd,0x00,0x28,0xdb,0xd0,0x3f,0x4b,0x1b,0x78,0x00,0x2b,0xd7,0xd1,0x3e,0x4a, 0x01,0x90,0x13,0x69,0x23,0xf0,0x04,0x03,0x13,0x61,0xff,0xf7,0x67,0xfe,0x01,0x98, 0xc1,0xe7,0x20,0x28,0xcb,0xd1,0x03,0xb0,0xbd,0xe8,0x30,0x40,0xff,0xf7,0x88,0xbe, 0x37,0x49,0x38,0x4a,0x8b,0x89,0x38,0x4c,0x38,0x48,0x03,0xf0,0x7f,0x03,0x43,0xf4, 0xb5,0x43,0x8b,0x81,0x13,0x88,0xdb,0xb2,0x43,0xf4,0x25,0x43,0x01,0x25,0x00,0x21, 0x13,0x80,0x25,0x70,0x01,0x70,0xe6,0xe7,0x00,0x20,0xff,0xf7,0xa7,0xfd,0x00,0x28, 0xa1,0xd0,0x02,0x20,0xba,0xe7,0x00,0x20,0xff,0xf7,0xa0,0xfd,0x00,0x28,0xa6,0xd0, 0x00,0x20,0xff,0xf7,0xed,0xfc,0x00,0x28,0xc5,0xd1,0xa0,0xe7,0x01,0x20,0xff,0xf7, 0x95,0xfd,0x00,0x28,0x8f,0xd0,0xec,0xe7,0x1e,0x4b,0x1b,0x78,0x00,0x2b,0x96,0xd1, 0x1d,0x48,0x23,0x4b,0x02,0x69,0x7a,0xe7,0x01,0x20,0xff,0xf7,0x87,0xfd,0x00,0x28, 0x8d,0xd0,0x02,0x20,0xff,0xf7,0xd4,0xfc,0x00,0x28,0xac,0xd1,0x87,0xe7,0x00,0x20, 0xff,0xf7,0x7c,0xfd,0x00,0x28,0x82,0xd0,0xf3,0xe7,0x01,0x20,0xff,0xf7,0x76,0xfd, 0x00,0x28,0x3f,0xf4,0x7c,0xaf,0x99,0xe7,0x00,0x20,0xff,0xf7,0x6f,0xfd,0x00,0x28, 0x3f,0xf4,0x69,0xaf,0x00,0x20,0x81,0xe7,0xff,0xf7,0x68,0xfd,0x00,0x28,0x3f,0xf4, 0x62,0xaf,0xf7,0xe7,0x01,0x20,0xff,0xf7,0x61,0xfd,0x00,0x28,0x3f,0xf4,0x67,0xaf, 0xbe,0xe7,0x01,0x20,0xff,0xf7,0x5a,0xfd,0x00,0x28,0x3f,0xf4,0x54,0xaf,0x6c,0xe7, 0x00,0x00,0x01,0x40,0xa0,0x00,0x20,0x42,0x00,0xed,0x00,0xe0,0xa0,0x00,0x5a,0x69, 0x00,0x48,0x00,0x40,0x00,0x44,0x00,0x40,0x58,0x80,0x08,0x42,0x20,0x80,0x08,0x42, 0xc0,0x00,0x5a,0x69,0x02,0x4b,0x18,0x68,0xc0,0xf3,0x05,0x20,0x70,0x47,0x00,0xbf, 0x00,0x00,0x01,0x40,0x70,0xb5,0x1e,0x4e,0x1e,0x4a,0x33,0x68,0x1e,0x4d,0x1f,0x4c, 0x4f,0xf0,0x80,0x71,0x91,0x60,0x9b,0x6d,0x00,0x20,0x98,0x47,0x33,0x68,0x28,0x60, 0x9b,0x6d,0x01,0x20,0x98,0x47,0x68,0x60,0xff,0xf7,0xd8,0xfd,0x28,0x73,0xff,0xf7, 0xe1,0xff,0x63,0x68,0x68,0x73,0x03,0xf4,0xe0,0x23,0xab,0x60,0x00,0x20,0xff,0xf7, 0xef,0xfe,0x33,0x68,0x02,0x21,0x5b,0x6d,0x05,0x46,0x00,0x20,0x98,0x47,0x33,0x68, 0x01,0x20,0x5b,0x6d,0x02,0x21,0x98,0x47,0x46,0xf6,0x5a,0x13,0x23,0x60,0x63,0x68, 0x23,0xf4,0xe0,0x23,0x43,0xf4,0x80,0x23,0x00,0x22,0x63,0x60,0x22,0x60,0x08,0x4b, 0x1d,0xb1,0x40,0xf6,0xce,0x22,0x5a,0x60,0x70,0xbd,0x06,0x4a,0x5a,0x60,0x70,0xbd, 0x6c,0x08,0x00,0x02,0x00,0xed,0x00,0xe0,0x80,0x01,0x00,0x20,0x00,0x04,0x01,0x40, 0x50,0x01,0x00,0x20,0x00,0xad,0xde,0x00,0x19,0x4b,0xdb,0x69,0xda,0x07,0x70,0xb5, 0x1d,0xd4,0x17,0x4c,0xe3,0x69,0x9b,0x07,0x00,0xd4,0x70,0xbd,0x15,0x4d,0x16,0x49, 0x2b,0x68,0x4f,0xf4,0x00,0x10,0x1b,0x69,0x98,0x47,0x23,0x6a,0x0b,0x2b,0x19,0xd0, 0x12,0x4b,0x10,0x4a,0x1b,0x68,0x12,0x68,0x9b,0x6c,0x14,0x69,0x98,0x47,0x10,0x49, 0x23,0x46,0x01,0x44,0xbd,0xe8,0x70,0x40,0x4f,0xf4,0x01,0x10,0x18,0x47,0x0b,0x4b, 0x08,0x4a,0x1b,0x68,0x12,0x68,0x5b,0x68,0x14,0x69,0x98,0x47,0x41,0x1e,0x00,0x20, 0xa0,0x47,0xd6,0xe7,0x2b,0x68,0x06,0x49,0x1b,0x69,0x06,0x48,0x98,0x47,0xdf,0xe7, 0x50,0x01,0x00,0x20,0x6c,0x08,0x00,0x02,0xff,0x0f,0x20,0x00,0x68,0x08,0x00,0x02, 0xff,0x3f,0x20,0x00,0x00,0x20,0x20,0x00,0x14,0x4b,0x70,0xb5,0x14,0x4c,0x1b,0x68, 0x22,0x68,0x5b,0x68,0x15,0x69,0x98,0x47,0x41,0x1e,0x00,0x20,0xa8,0x47,0x23,0x68, 0x10,0x49,0x1b,0x69,0x4f,0xf4,0x00,0x10,0x98,0x47,0x0f,0x4b,0x1b,0x6a,0x0b,0x2b, 0x0e,0xd0,0x0a,0x4b,0x0a,0x4a,0x1b,0x68,0x12,0x68,0x9b,0x6c,0x14,0x69,0x98,0x47, 0x0a,0x49,0x23,0x46,0x01,0x44,0xbd,0xe8,0x70,0x40,0x4f,0xf4,0x01,0x10,0x18,0x47, 0x23,0x68,0x06,0x49,0x1b,0x69,0x06,0x48,0x98,0x47,0xea,0xe7,0x68,0x08,0x00,0x02, 0x6c,0x08,0x00,0x02,0xff,0x0f,0x20,0x00,0x50,0x01,0x00,0x20,0xff,0x3f,0x20,0x00, 0x00,0x20,0x20,0x00,0x2d,0xe9,0xf0,0x41,0xff,0xf7,0xc6,0xff,0x2d,0x49,0x4b,0x69, 0x2c,0x4a,0xdb,0x06,0xfb,0xd5,0x53,0x69,0x43,0xf0,0x01,0x03,0x53,0x61,0xd4,0x68, 0x15,0x69,0xb4,0xf5,0x00,0x1f,0x03,0xd2,0x2b,0x19,0xb3,0xf5,0x00,0x1f,0x2d,0xd8, 0x25,0x4b,0x1b,0x68,0x21,0x46,0x2a,0x46,0x9b,0x6a,0x4f,0xf0,0x20,0x20,0x98,0x47, 0x07,0x46,0x20,0x4c,0x21,0x4e,0x63,0x69,0x1f,0x4d,0x31,0x68,0x2a,0x68,0x23,0xf0, 0x11,0x03,0x63,0x61,0x4b,0x68,0xd2,0xf8,0x14,0x80,0x98,0x47,0x41,0x1e,0x00,0x20, 0xc0,0x47,0x33,0x68,0x2a,0x68,0x9b,0x6c,0x55,0x69,0x98,0x47,0x18,0x49,0x01,0x44, 0x4f,0xf4,0x00,0x10,0xa8,0x47,0x27,0xb1,0x40,0xf6,0xce,0x23,0x63,0x60,0xbd,0xe8, 0xf0,0x81,0x4d,0xf6,0xad,0x63,0x63,0x60,0xbd,0xe8,0xf0,0x81,0xdf,0xf8,0x38,0x80, 0xd8,0xf8,0x00,0x30,0xc4,0xf5,0x00,0x17,0x3a,0x46,0x9b,0x6a,0x21,0x46,0x4f,0xf0, 0x20,0x20,0x98,0x47,0xd8,0xf8,0x00,0x30,0x06,0x46,0xc4,0xf1,0x20,0x20,0xea,0x1b, 0x9b,0x6a,0x00,0xf5,0x00,0x10,0x4f,0xf4,0x00,0x11,0x98,0x47,0x30,0x40,0xc7,0xb2, 0xbf,0xe7,0x00,0xbf,0x50,0x01,0x00,0x20,0x6c,0x08,0x00,0x02,0x68,0x08,0x00,0x02, 0xff,0xff,0x1f,0x00,0x2d,0xe9,0xf0,0x4f,0x4f,0x4c,0x26,0x69,0xe7,0x68,0x83,0xb0, 0x00,0x2e,0x59,0xd0,0x4f,0xf0,0x00,0x09,0xca,0x46,0xcd,0xf8,0x00,0x90,0xb6,0xf5, 0x80,0x5f,0x93,0xbf,0xb0,0x46,0xa6,0xf5,0x80,0x56,0x4f,0xf4,0x80,0x58,0x00,0x26, 0xff,0xf7,0x4a,0xff,0x02,0xe0,0xa3,0x69,0xdb,0x06,0x02,0xd4,0x63,0x69,0xda,0x06, 0xf9,0xd5,0x65,0x69,0x15,0xf0,0x10,0x05,0x41,0xd0,0x63,0x69,0x43,0xf0,0x01,0x03, 0x63,0x61,0x4f,0xf0,0x20,0x2a,0x01,0x25,0x3c,0x4b,0x9f,0x42,0x08,0xeb,0x07,0x09, 0x3b,0x4b,0x02,0xd8,0xb9,0xf5,0x00,0x1f,0x4c,0xd8,0x1b,0x68,0x39,0x46,0x42,0x46, 0x9b,0x6a,0x50,0x46,0x98,0x47,0x4f,0x46,0x81,0x46,0x00,0x2d,0x39,0xd0,0x63,0x69, 0x23,0xf0,0x11,0x03,0x63,0x61,0xdf,0xf8,0xcc,0x80,0x31,0x4d,0xd8,0xf8,0x00,0x20, 0x2b,0x68,0x52,0x68,0xd3,0xf8,0x14,0xb0,0x90,0x47,0x41,0x1e,0x00,0x20,0xd8,0x47, 0xd8,0xf8,0x00,0x30,0x2a,0x68,0x9b,0x6c,0x55,0x69,0x98,0x47,0x27,0x49,0x01,0x44, 0x4f,0xf4,0x00,0x10,0xa8,0x47,0xb9,0xf1,0x00,0x0f,0x3e,0xd0,0x00,0x2e,0xae,0xd1, 0x21,0x4b,0x40,0xf6,0xce,0x22,0x5a,0x60,0x03,0xb0,0xbd,0xe8,0xf0,0x8f,0xa3,0x69, 0x13,0xf0,0x10,0x03,0x08,0xd0,0xa3,0x69,0xdf,0xf8,0x7c,0xa0,0x43,0xf0,0x01,0x03, 0xa3,0x61,0x01,0x23,0x00,0x93,0xb7,0xe7,0x00,0x9a,0x00,0x2a,0xcb,0xd0,0x1d,0x46, 0xb2,0xe7,0x00,0x9b,0x00,0x2b,0xc6,0xd0,0xa3,0x69,0x00,0x95,0x23,0xf0,0x11,0x03, 0xa3,0x61,0xc0,0xe7,0x1a,0x68,0x01,0x93,0xc7,0xf5,0x00,0x1b,0xd2,0xf8,0x28,0xc0, 0x39,0x46,0x5a,0x46,0x50,0x46,0xe0,0x47,0x01,0x9b,0x19,0x68,0x07,0x46,0xd1,0xf8, 0x28,0xc0,0xcb,0xeb,0x08,0x02,0x0a,0xeb,0x0b,0x00,0x4f,0xf4,0x00,0x11,0xe0,0x47, 0x38,0x40,0x4f,0x46,0x5f,0xfa,0x80,0xf9,0x9f,0xe7,0x03,0x4b,0x4d,0xf6,0xad,0x62, 0x5a,0x60,0x03,0xb0,0xbd,0xe8,0xf0,0x8f,0x50,0x01,0x00,0x20,0xff,0xff,0x1f,0x00, 0x6c,0x08,0x00,0x02,0x68,0x08,0x00,0x02,0x00,0x30,0x00,0x20,0x2d,0xe9,0xf0,0x41, 0x1b,0x4c,0x1c,0x4d,0x1c,0x4f,0x29,0x68,0x3a,0x68,0x46,0xf6,0x5a,0x18,0xc4,0xf8, 0x00,0x80,0x63,0x68,0x23,0xf4,0xe0,0x23,0x00,0x26,0x43,0xf4,0x80,0x33,0x63,0x60, 0x26,0x60,0x53,0x6d,0x30,0x46,0x98,0x47,0x3b,0x68,0x69,0x68,0x5b,0x6d,0x01,0x20, 0x98,0x47,0x68,0x7b,0xff,0xf7,0x1c,0xfd,0x07,0x46,0x28,0x7b,0xff,0xf7,0xf4,0xfb, 0xc4,0xf8,0x00,0x80,0x63,0x68,0xaa,0x68,0x0c,0x49,0x23,0xf4,0xe0,0x23,0x13,0x43, 0x63,0x60,0x26,0x60,0x0a,0x4b,0x8e,0x60,0x28,0xb1,0x27,0xb1,0x40,0xf6,0xce,0x22, 0x5a,0x60,0xbd,0xe8,0xf0,0x81,0x4d,0xf6,0xad,0x62,0x5a,0x60,0xbd,0xe8,0xf0,0x81, 0x00,0x04,0x01,0x40,0x80,0x01,0x00,0x20,0x6c,0x08,0x00,0x02,0x00,0xed,0x00,0xe0, 0x50,0x01,0x00,0x20,0x5b,0x4b,0x5c,0x4c,0x1b,0x68,0x5c,0x4e,0x1b,0x68,0x80,0xb5, 0x98,0x47,0xff,0xf7,0xb7,0xfb,0x27,0x46,0x23,0x68,0x20,0x2b,0x00,0xf2,0x99,0x80, 0x01,0xa2,0x52,0xf8,0x23,0xf0,0x00,0xbf,0x99,0x10,0x00,0x01,0x89,0x11,0x00,0x01, 0x65,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0x57,0x11,0x00,0x01,0xd3,0x11,0x00,0x01, 0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0x49,0x11,0x00,0x01,0xd3,0x11,0x00,0x01, 0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01, 0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0x3b,0x11,0x00,0x01,0xd3,0x11,0x00,0x01, 0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01, 0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01, 0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01, 0xd3,0x11,0x00,0x01,0xd3,0x11,0x00,0x01,0x2d,0x11,0x00,0x01,0x01,0x23,0x63,0x60, 0xff,0xf7,0xb8,0xfe,0x00,0x23,0x23,0x60,0xae,0xe7,0x01,0x23,0x63,0x60,0xff,0xf7, 0x5d,0xff,0x00,0x23,0x23,0x60,0xa7,0xe7,0x01,0x23,0x63,0x60,0xff,0xf7,0x82,0xfd, 0x00,0x23,0x23,0x60,0xa0,0xe7,0x01,0x23,0x63,0x60,0xff,0xf7,0x3b,0xfe,0x00,0x23, 0x23,0x60,0x99,0xe7,0x01,0x23,0x63,0x60,0xff,0xf7,0xfe,0xfd,0x05,0x25,0x33,0x68, 0xe0,0x68,0x5b,0x6a,0x98,0x47,0x01,0x3d,0x00,0x28,0x2e,0xd1,0x00,0x2d,0xf6,0xd1, 0x4d,0xf6,0xad,0x63,0x63,0x60,0x0d,0xe0,0x01,0x23,0x63,0x60,0xff,0xf7,0xac,0xfd, 0x05,0x25,0x33,0x68,0x1b,0x6a,0x98,0x47,0x01,0x3d,0x20,0xbb,0x00,0x2d,0xf8,0xd1, 0x17,0x4b,0x63,0x60,0x17,0x4d,0x32,0x68,0x2b,0x68,0xd2,0xf8,0x14,0x80,0x5b,0x68, 0x98,0x47,0x41,0x1e,0x00,0x20,0xc0,0x47,0x2b,0x68,0x32,0x68,0x9b,0x6c,0x55,0x69, 0x98,0x47,0x11,0x49,0x01,0x44,0x4f,0xf4,0x00,0x10,0xa8,0x47,0x00,0x23,0x23,0x60, 0x62,0xe7,0x40,0xf6,0xad,0x33,0x63,0x60,0x5e,0xe7,0x00,0x2d,0xd0,0xd0,0x40,0xf6, 0xce,0x23,0x7b,0x60,0xde,0xe7,0x00,0x2d,0xda,0xd0,0x40,0xf6,0xce,0x23,0x63,0x60, 0xd8,0xe7,0x00,0xbf,0x64,0x08,0x00,0x02,0x50,0x01,0x00,0x20,0x6c,0x08,0x00,0x02, 0xad,0xde,0xad,0xde,0x68,0x08,0x00,0x02,0xff,0xff,0x1f,0x00,0xfe,0xe7,0x00,0xbf, 0xfd,0x01,0x00,0x01,0x85,0x04,0x00,0x01,0xf8,0xb5,0x00,0xbf,0xf8,0xbc,0x08,0xbc, 0x9e,0x46,0x70,0x47,0xf8,0xb5,0x00,0xbf,0xd5,0x01,0x00,0x01,0xf8,0xbc,0x08,0xbc, 0x9e,0x46,0x70,0x47,0x43,0x00,0x00,0x00,0x08,0x20,0x00,0x20,0xf8,0xef,0xff,0x7f, 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xf4,0x22,0x00,0x20,0x5c,0x23,0x00,0x20,0xc4,0x23,0x00,0x20,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x34,0x12,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x33,0xcd,0xab, 0x34,0x12,0x6d,0xe6,0xec,0xde,0x05,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x08,0x20,0x00,0x20, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/startup_msp432e4.c ================================================ // SPDX-License-Identifier: BSD-3-Clause /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #include /* Entry point for the application. */ extern int main(); /* Reserve space for the system stack. */ extern uint32_t __stack_top; typedef void(*pFunc)(void); /* Interrupt handler prototypes */ void default_handler(void); void reset_handler(void); /* * The vector table. Note that the proper constructs must be placed on this to * ensure that it ends up at physical address 0x0000.0000 or at the start of * the program if located at a start address other than 0. */ void (* const intr_vectors[])(void) __attribute__((section(".intvecs"))) = { (pFunc)&__stack_top, /* The initial stack pointer */ reset_handler, /* The reset handler */ default_handler, /* The NMI handler */ default_handler, /* The hard fault handler */ default_handler, /* The MPU fault handler */ default_handler, /* The bus fault handler */ default_handler, /* The usage fault handler */ 0, /* Reserved */ 0, /* Reserved */ 0, /* Reserved */ 0, /* Reserved */ default_handler, /* SVCall handler */ default_handler, /* Debug monitor handler */ 0, /* Reserved */ default_handler, /* The PendSV handler */ default_handler /* The SysTick handler */ }; /* * The following are constructs created by the linker, indicating where * the "data" and "bss" segments reside in memory. The initializers for * the "data" segment resides immediately following the "text" segment. */ extern uint32_t __bss_start__; extern uint32_t __bss_end__; /* * This is the code that gets called when the processor first starts execution * following a reset event. Only the absolutely necessary set is performed, * after which the application supplied entry() routine is called. Any fancy * actions (such as making decisions based on the reset cause register, and * resetting the bits in that register) are left solely in the hands of the * application. */ __attribute__((section(".reset"))) __attribute__((naked)) void reset_handler(void) { /* Set stack pointer */ __asm(" MOVW.W r0, #0x1700\n" " MOVT.W r0, #0x2000\n" " mov sp, r0\n"); /* Zero fill the bss segment. */ __asm(" ldr r0, =__bss_start__\n" " ldr r1, =__bss_end__\n" " mov r2, #0\n" " .thumb_func\n" "zero_loop:\n" " cmp r0, r1\n" " it lt\n" " strlt r2, [r0], #4\n" " blt zero_loop"); /* Call the application's entry point. */ main(); } /* * This is the code that gets called when the processor receives an unexpected * interrupt. This simply enters an infinite loop, preserving the system state * for examination by a debugger. */ void default_handler(void) { /* Enter an infinite loop. */ while (1) ; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/msp432/startup_msp432p4.c ================================================ // SPDX-License-Identifier: BSD-3-Clause /****************************************************************************** * * Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************/ #include /* Entry point for the application. */ extern int main(); /* Reserve space for the system stack. */ extern uint32_t __stack_top; typedef void(*pFunc)(void); /* Interrupt handler prototypes */ void default_handler(void); void reset_handler(void); /* * The vector table. Note that the proper constructs must be placed on this to * ensure that it ends up at physical address 0x0000.0000 or at the start of * the program if located at a start address other than 0. */ void (* const intr_vectors[])(void) __attribute__((section(".intvecs"))) = { (pFunc)&__stack_top, /* The initial stack pointer */ reset_handler, /* The reset handler */ default_handler, /* The NMI handler */ default_handler, /* The hard fault handler */ default_handler, /* The MPU fault handler */ default_handler, /* The bus fault handler */ default_handler, /* The usage fault handler */ 0, /* Reserved */ 0, /* Reserved */ 0, /* Reserved */ 0, /* Reserved */ default_handler, /* SVCall handler */ default_handler, /* Debug monitor handler */ 0, /* Reserved */ default_handler, /* The PendSV handler */ default_handler /* The SysTick handler */ }; /* * The following are constructs created by the linker, indicating where * the "data" and "bss" segments reside in memory. The initializers for * the "data" segment resides immediately following the "text" segment. */ extern uint32_t __bss_start__; extern uint32_t __bss_end__; /* * This is the code that gets called when the processor first starts execution * following a reset event. Only the absolutely necessary set is performed, * after which the application supplied entry() routine is called. Any fancy * actions (such as making decisions based on the reset cause register, and * resetting the bits in that register) are left solely in the hands of the * application. */ __attribute__((section(".reset"))) __attribute__((naked)) void reset_handler(void) { /* Set stack pointer */ __asm(" MOVW.W r0, #0x1700\n" " MOVT.W r0, #0x0100\n" " mov sp, r0\n"); /* Zero fill the bss segment. */ __asm(" ldr r0, =__bss_start__\n" " ldr r1, =__bss_end__\n" " mov r2, #0\n" " .thumb_func\n" "zero_loop:\n" " cmp r0, r1\n" " it lt\n" " strlt r2, [r0], #4\n" " blt zero_loop"); /* Call the application's entry point. */ main(); } /* * This is the code that gets called when the processor receives an unexpected * interrupt. This simply enters an infinite loop, preserving the system state * for examination by a debugger. */ void default_handler(void) { /* Enter an infinite loop. */ while (1) ; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/npcx/npcx_algo.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x08,0xb5,0xdf,0xf8,0x08,0xd0,0x00,0xf0,0x2f,0xf9,0x00,0x00,0x48,0x15,0x0c,0x20, 0x03,0x4b,0x18,0x70,0x19,0x72,0x08,0x33,0x1a,0x78,0xd2,0x09,0xfc,0xd1,0x70,0x47, 0x16,0x00,0x02,0x40,0x70,0xb5,0x11,0x4c,0x23,0x78,0x03,0xf0,0xfd,0x03,0x23,0x70, 0xc0,0x21,0x05,0x20,0xff,0xf7,0xec,0xff,0x0d,0x4a,0x0e,0x49,0x6f,0xf0,0x7f,0x43, 0x6f,0xf0,0x2e,0x05,0x10,0x46,0x15,0x70,0x06,0x78,0xf6,0x09,0xfc,0xd1,0x0e,0x78, 0xf6,0x07,0x01,0xd5,0x01,0x3b,0xf6,0xd1,0x22,0x78,0x42,0xf0,0x02,0x02,0x00,0x2b, 0x22,0x70,0x0c,0xbf,0x03,0x20,0x00,0x20,0x70,0xbd,0x00,0xbf,0x1f,0x00,0x02,0x40, 0x1e,0x00,0x02,0x40,0x1a,0x00,0x02,0x40,0x08,0xb5,0xc0,0x21,0x06,0x20,0xff,0xf7, 0xc7,0xff,0xff,0xf7,0xcf,0xff,0x28,0xb9,0x03,0x4b,0x1b,0x78,0x13,0xf0,0x02,0x0f, 0x08,0xbf,0x02,0x20,0x08,0xbd,0x00,0xbf,0x1a,0x00,0x02,0x40,0xf8,0xb5,0x12,0x4c, 0x23,0x78,0x03,0xf0,0xfd,0x03,0x23,0x70,0x10,0x4b,0x17,0x46,0xc0,0xf3,0x07,0x42, 0x1a,0x70,0xc0,0xf3,0x07,0x22,0xc0,0xb2,0x03,0xf8,0x01,0x2c,0x0e,0x46,0x03,0xf8, 0x02,0x0c,0xe8,0x21,0x02,0x20,0xff,0xf7,0xa3,0xff,0x00,0x25,0xae,0x42,0x04,0xd8, 0x23,0x78,0x43,0xf0,0x02,0x03,0x23,0x70,0xf8,0xbd,0x78,0x5d,0xe0,0x21,0xff,0xf7, 0x97,0xff,0x01,0x35,0xf2,0xe7,0x00,0xbf,0x1f,0x00,0x02,0x40,0x19,0x00,0x02,0x40, 0x70,0x47,0x2d,0xe9,0xf0,0x41,0x00,0xf1,0xff,0x06,0x26,0xf0,0xff,0x06,0x34,0x1a, 0x8c,0x42,0x28,0xbf,0x0c,0x46,0x80,0x46,0x0d,0x46,0x17,0x46,0x5c,0xb1,0xff,0xf7, 0xb3,0xff,0x58,0xb9,0x3a,0x46,0xa1,0xb2,0x40,0x46,0xff,0xf7,0xbf,0xff,0xff,0xf7, 0x81,0xff,0x18,0xb9,0x27,0x44,0x2c,0x1b,0x14,0xb9,0x20,0x46,0xbd,0xe8,0xf0,0x81, 0xb4,0xf5,0x80,0x7f,0x25,0x46,0x28,0xbf,0x4f,0xf4,0x80,0x75,0xff,0xf7,0x9c,0xff, 0x00,0x28,0xf3,0xd1,0x3a,0x46,0xa9,0xb2,0x30,0x46,0xff,0xf7,0xa7,0xff,0xff,0xf7, 0x69,0xff,0x00,0x28,0xea,0xd1,0x2f,0x44,0x2e,0x44,0x64,0x1b,0xe4,0xe7,0x00,0x00, 0x2d,0xe9,0xf0,0x47,0x14,0x4e,0x15,0x4f,0xdf,0xf8,0x54,0x80,0x05,0x46,0x0c,0x46, 0x8a,0x46,0x05,0xeb,0x04,0x09,0xa9,0xeb,0x0a,0x09,0xba,0xf1,0x00,0x0f,0x02,0xd1, 0x50,0x46,0xbd,0xe8,0xf0,0x87,0xff,0xf7,0x77,0xff,0x00,0x28,0xf9,0xd1,0xc9,0xf3, 0x07,0x43,0x33,0x70,0xc9,0xf3,0x07,0x23,0x5f,0xfa,0x89,0xf9,0x3b,0x70,0xc8,0x21, 0x20,0x20,0x88,0xf8,0x00,0x90,0xff,0xf7,0x33,0xff,0xff,0xf7,0x3b,0xff,0x00,0x28, 0xe7,0xd1,0xaa,0xf5,0x80,0x5a,0xdc,0xe7,0x19,0x00,0x02,0x40,0x18,0x00,0x02,0x40, 0x17,0x00,0x02,0x40,0x08,0xb5,0xff,0xf7,0x57,0xff,0x38,0xb9,0xc0,0x21,0xc7,0x20, 0xff,0xf7,0x1e,0xff,0xbd,0xe8,0x08,0x40,0xff,0xf7,0x24,0xbf,0x08,0xbd,0x00,0x00, 0x38,0xb5,0xff,0xf7,0x49,0xff,0x04,0x46,0xc0,0xb9,0x0d,0x4b,0x0d,0x4d,0xf2,0x21, 0x28,0x70,0x18,0x70,0x01,0x20,0xff,0xf7,0x0b,0xff,0xff,0xf7,0x13,0xff,0x04,0x46, 0x60,0xb9,0xc1,0x21,0x05,0x20,0xff,0xf7,0x03,0xff,0x2b,0x78,0x2b,0xb9,0xc1,0x21, 0x35,0x20,0xff,0xf7,0xfd,0xfe,0x2b,0x78,0x03,0xb1,0x02,0x24,0x20,0x46,0x38,0xbd, 0x1b,0x00,0x02,0x40,0x1a,0x00,0x02,0x40,0x10,0xb5,0xc3,0x21,0x04,0x46,0x9f,0x20, 0xff,0xf7,0xee,0xfe,0x06,0x4b,0x07,0x4a,0x19,0x78,0x01,0x33,0x00,0x20,0x1b,0x78, 0x12,0x78,0x1b,0x02,0x43,0xea,0x01,0x43,0x13,0x43,0x23,0x60,0x10,0xbd,0x00,0xbf, 0x1a,0x00,0x02,0x40,0x1c,0x00,0x02,0x40,0x08,0xb5,0x10,0x22,0x00,0x21,0x00,0xf0, 0x4d,0xf8,0x00,0x20,0x08,0xbd,0x00,0x00,0x73,0xb5,0x21,0x48,0x20,0x4c,0xff,0xf7, 0xf3,0xff,0x20,0x4a,0x13,0x78,0x43,0xf0,0x80,0x03,0x13,0x70,0xff,0xf7,0xb0,0xff, 0x05,0x46,0x58,0xb9,0x1c,0x4e,0xe3,0x68,0x00,0x2b,0xfc,0xd0,0xa3,0x68,0x01,0x3b, 0x03,0x2b,0x2a,0xd8,0xdf,0xe8,0x03,0xf0,0x04,0x18,0x20,0x23,0xe5,0x60,0xfd,0xe7, 0x01,0xa8,0xff,0xf7,0xc1,0xff,0xa8,0xb9,0x01,0x9b,0x33,0x70,0x1a,0x0a,0x1b,0x0c, 0x72,0x70,0xb3,0x70,0xf0,0x70,0x23,0x7b,0x25,0x73,0x63,0x7b,0x65,0x73,0xa3,0x7b, 0xa5,0x73,0xe3,0x7b,0xe5,0x73,0xde,0xe7,0x20,0x68,0x61,0x68,0xff,0xf7,0x48,0xff, 0x00,0x28,0xf0,0xd0,0xe0,0x60,0xfe,0xe7,0xff,0xf7,0x74,0xff,0xf8,0xe7,0x20,0x68, 0x61,0x68,0x32,0x46,0xff,0xf7,0x05,0xff,0xf2,0xe7,0x01,0x20,0xf2,0xe7,0x00,0xbf, 0x00,0x00,0x0c,0x20,0x10,0x30,0x0c,0x40,0x10,0x00,0x0c,0x20,0xf0,0xb5,0x05,0x00, 0x83,0x07,0x4e,0xd0,0x54,0x1e,0x00,0x2a,0x46,0xd0,0x0a,0x06,0x12,0x0e,0x03,0x00, 0x03,0x26,0x02,0xe0,0x01,0x35,0x01,0x3c,0x3e,0xd3,0x01,0x33,0x2a,0x70,0x33,0x42, 0xf8,0xd1,0x03,0x2c,0x2f,0xd9,0xff,0x22,0x0a,0x40,0x15,0x02,0x15,0x43,0x2a,0x04, 0x15,0x43,0x0f,0x2c,0x38,0xd9,0x27,0x00,0x10,0x3f,0x3f,0x09,0x3e,0x01,0xb4,0x46, 0x1e,0x00,0x1a,0x00,0x10,0x36,0x66,0x44,0x15,0x60,0x55,0x60,0x95,0x60,0xd5,0x60, 0x10,0x32,0xb2,0x42,0xf8,0xd1,0x0f,0x26,0x0c,0x22,0x01,0x37,0x3f,0x01,0x26,0x40, 0xdb,0x19,0x37,0x00,0x22,0x42,0x1a,0xd0,0x3e,0x1f,0xb6,0x08,0xb4,0x00,0xa4,0x46, 0x1a,0x00,0x1c,0x1d,0x64,0x44,0x20,0xc2,0xa2,0x42,0xfc,0xd1,0x03,0x24,0x01,0x36, 0xb6,0x00,0x9b,0x19,0x3c,0x40,0x00,0x2c,0x06,0xd0,0x09,0x06,0x1c,0x19,0x09,0x0e, 0x19,0x70,0x01,0x33,0x9c,0x42,0xfb,0xd1,0xf0,0xbc,0x02,0xbc,0x08,0x47,0x34,0x00, 0xf1,0xe7,0x14,0x00,0x03,0x00,0xbc,0xe7,0x27,0x00,0xdd,0xe7, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/npcx/npcx_flash.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2020 by Nuvoton Technology Corporation * Mulin Chao * Wealian Liao */ #include #include #include "npcx_flash.h" /*---------------------------------------------------------------------------- * NPCX flash driver *----------------------------------------------------------------------------*/ static void flash_execute_cmd(uint8_t code, uint8_t cts) { /* Set UMA code */ NPCX_UMA_CODE = code; /* Execute UMA flash transaction by CTS setting */ NPCX_UMA_CTS = cts; /* Wait for transaction completed */ while (NPCX_IS_BIT_SET(NPCX_UMA_CTS, NPCX_UMA_CTS_EXEC_DONE)) ; } static void flash_cs_level(uint8_t level) { /* Program chip select pin to high/low level */ if (level) NPCX_SET_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_SW_CS1); else NPCX_CLEAR_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_SW_CS1); } static void flash_set_address(uint32_t dest_addr) { uint8_t *addr = (uint8_t *)&dest_addr; /* Set target flash address */ NPCX_UMA_AB2 = addr[2]; NPCX_UMA_AB1 = addr[1]; NPCX_UMA_AB0 = addr[0]; } void delay(uint32_t i) { while (i--) ; } static int flash_wait_ready(uint32_t timeout) { /* Chip Select down. -- Burst mode */ flash_cs_level(0); /* Command for Read status register */ flash_execute_cmd(NPCX_CMD_READ_STATUS_REG, NPCX_MASK_CMD_ONLY); while (timeout > 0) { /* Read status register */ NPCX_UMA_CTS = NPCX_MASK_RD_1BYTE; while (NPCX_IS_BIT_SET(NPCX_UMA_CTS, NPCX_UMA_CTS_EXEC_DONE)) ; if (!(NPCX_UMA_DB0 & NPCX_SPI_FLASH_SR1_BUSY)) break; if (--timeout > 0) delay(100); }; /* Wait for Busy clear */ /* Chip Select high. */ flash_cs_level(1); if (timeout == 0) return NPCX_FLASH_STATUS_FAILED_TIMEOUT; return NPCX_FLASH_STATUS_OK; } static int flash_write_enable(void) { /* Write enable command */ flash_execute_cmd(NPCX_CMD_WRITE_EN, NPCX_MASK_CMD_ONLY); /* Wait for flash is not busy */ int status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); if (status != NPCX_FLASH_STATUS_OK) return status; if (NPCX_UMA_DB0 & NPCX_SPI_FLASH_SR1_WEL) return NPCX_FLASH_STATUS_OK; else return NPCX_FLASH_STATUS_FAILED; } static void flash_burst_write(uint32_t dest_addr, uint16_t bytes, const uint8_t *data) { /* Chip Select down -- Burst mode */ flash_cs_level(0); /* Set write address */ flash_set_address(dest_addr); /* Start programming */ flash_execute_cmd(NPCX_CMD_FLASH_PROGRAM, NPCX_MASK_CMD_WR_ADR); for (uint32_t i = 0; i < bytes; i++) { flash_execute_cmd(*data, NPCX_MASK_CMD_WR_ONLY); data++; } /* Chip Select up */ flash_cs_level(1); } /* The data to write cannot cross 256 Bytes boundary */ static int flash_program_write(uint32_t addr, uint32_t size, const uint8_t *data) { int status = flash_write_enable(); if (status != NPCX_FLASH_STATUS_OK) return status; flash_burst_write(addr, size, data); return flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); } int flash_physical_write(uint32_t offset, uint32_t size, const uint8_t *data) { int status; uint32_t trunk_start = (offset + 0xff) & ~0xff; /* write head */ uint32_t dest_addr = offset; uint32_t write_len = ((trunk_start - offset) > size) ? size : (trunk_start - offset); if (write_len) { status = flash_program_write(dest_addr, write_len, data); if (status != NPCX_FLASH_STATUS_OK) return status; data += write_len; } dest_addr = trunk_start; size -= write_len; /* write remaining data*/ while (size > 0) { write_len = (size > NPCX_FLASH_WRITE_SIZE) ? NPCX_FLASH_WRITE_SIZE : size; status = flash_program_write(dest_addr, write_len, data); if (status != NPCX_FLASH_STATUS_OK) return status; data += write_len; dest_addr += write_len; size -= write_len; } return NPCX_FLASH_STATUS_OK; } int flash_physical_erase(uint32_t offset, uint32_t size) { /* Alignment has been checked in upper layer */ for (; size > 0; size -= NPCX_FLASH_ERASE_SIZE, offset += NPCX_FLASH_ERASE_SIZE) { /* Enable write */ int status = flash_write_enable(); if (status != NPCX_FLASH_STATUS_OK) return status; /* Set erase address */ flash_set_address(offset); /* Start erase */ flash_execute_cmd(NPCX_CMD_SECTOR_ERASE, NPCX_MASK_CMD_ADR); /* Wait erase completed */ status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); if (status != NPCX_FLASH_STATUS_OK) return status; } return NPCX_FLASH_STATUS_OK; } int flash_physical_erase_all(void) { /* Enable write */ int status = flash_write_enable(); if (status != NPCX_FLASH_STATUS_OK) return status; /* Start erase */ flash_execute_cmd(NPCX_CMD_CHIP_ERASE, NPCX_MASK_CMD_ONLY); /* Wait erase completed */ status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); if (status != NPCX_FLASH_STATUS_OK) return status; return NPCX_FLASH_STATUS_OK; } int flash_physical_clear_stsreg(void) { /* Enable write */ int status = flash_write_enable(); if (status != NPCX_FLASH_STATUS_OK) return status; NPCX_UMA_DB0 = 0x0; NPCX_UMA_DB1 = 0x0; /* Write status register 1/2 */ flash_execute_cmd(NPCX_CMD_WRITE_STATUS_REG, NPCX_MASK_CMD_WR_2BYTE); /* Wait writing completed */ status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); if (status != NPCX_FLASH_STATUS_OK) return status; /* Read status register 1/2 for checking */ flash_execute_cmd(NPCX_CMD_READ_STATUS_REG, NPCX_MASK_CMD_RD_1BYTE); if (NPCX_UMA_DB0 != 0x00) return NPCX_FLASH_STATUS_FAILED; flash_execute_cmd(NPCX_CMD_READ_STATUS_REG2, NPCX_MASK_CMD_RD_1BYTE); if (NPCX_UMA_DB0 != 0x00) return NPCX_FLASH_STATUS_FAILED; return NPCX_FLASH_STATUS_OK; } int flash_get_id(uint32_t *id) { flash_execute_cmd(NPCX_CMD_READ_ID, NPCX_MASK_CMD_RD_3BYTE); *id = NPCX_UMA_DB0 << 16 | NPCX_UMA_DB1 << 8 | NPCX_UMA_DB2; return NPCX_FLASH_STATUS_OK; } /*---------------------------------------------------------------------------- * flash loader function *----------------------------------------------------------------------------*/ uint32_t flashloader_init(struct npcx_flash_params *params) { /* Initialize params buffers */ memset(params, 0, sizeof(struct npcx_flash_params)); return NPCX_FLASH_STATUS_OK; } /*---------------------------------------------------------------------------- * Functions *----------------------------------------------------------------------------*/ /* flashloader parameter structure */ __attribute__ ((section(".buffers.g_cfg"))) volatile struct npcx_flash_params g_cfg; /* data buffer */ __attribute__ ((section(".buffers.g_buf"))) uint8_t g_buf[NPCX_FLASH_LOADER_BUFFER_SIZE]; int main(void) { uint32_t id; /* set buffer */ flashloader_init((struct npcx_flash_params *)&g_cfg); /* Avoid F_CS0 toggles while programming the internal flash. */ NPCX_SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_NO_F_SPI); /* clear flash status registers */ int status = flash_physical_clear_stsreg(); if (status != NPCX_FLASH_STATUS_OK) { while (1) g_cfg.sync = status; } while (1) { /* wait command*/ while (g_cfg.sync == NPCX_FLASH_LOADER_WAIT) ; /* command handler */ switch (g_cfg.cmd) { case NPCX_FLASH_CMD_GET_FLASH_ID: status = flash_get_id(&id); if (status == NPCX_FLASH_STATUS_OK) { g_buf[0] = id & 0xff; g_buf[1] = (id >> 8) & 0xff; g_buf[2] = (id >> 16) & 0xff; g_buf[3] = 0x00; } break; case NPCX_FLASH_CMD_ERASE_SECTORS: status = flash_physical_erase(g_cfg.addr, g_cfg.len); break; case NPCX_FLASH_CMD_ERASE_ALL: status = flash_physical_erase_all(); break; case NPCX_FLASH_CMD_PROGRAM: status = flash_physical_write(g_cfg.addr, g_cfg.len, g_buf); break; default: status = NPCX_FLASH_STATUS_FAILED_UNKNOWN_COMMAND; break; } /* clear & set result for next command */ if (status != NPCX_FLASH_STATUS_OK) { g_cfg.sync = status; while (1) ; } else { g_cfg.sync = NPCX_FLASH_LOADER_WAIT; } } return 0; } __attribute__ ((section(".stack"))) __attribute__ ((used)) static uint32_t stack[NPCX_FLASH_LOADER_STACK_SIZE / 4]; extern uint32_t _estack; extern uint32_t _bss; extern uint32_t _ebss; __attribute__ ((section(".entry"))) void entry(void) { /* set sp from end of stack */ __asm(" ldr sp, =_estack - 4"); main(); __asm(" bkpt #0x00"); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/npcx/npcx_flash.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2020 by Nuvoton Technology Corporation * Mulin Chao * Wealian Liao */ #ifndef OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_H #define OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_H #include "npcx_flash_config.h" /* Bit functions */ #define NPCX_SET_BIT(reg, bit) ((reg) |= (0x1 << (bit))) #define NPCX_CLEAR_BIT(reg, bit) ((reg) &= (~(0x1 << (bit)))) #define NPCX_IS_BIT_SET(reg, bit) (((reg) >> (bit)) & (0x1)) /* Field functions */ #define NPCX_GET_POS_FIELD(pos, size) (pos) #define NPCX_GET_SIZE_FIELD(pos, size) (size) #define NPCX_FIELD_POS(field) NPCX_GET_POS_##field #define NPCX_FIELD_SIZE(field) NPCX_GET_SIZE_##field /* Read field functions */ #define NPCX_GET_FIELD(reg, field) \ _NPCX_GET_FIELD_((reg), NPCX_FIELD_POS(field), NPCX_FIELD_SIZE(field)) #define _NPCX_GET_FIELD_(reg, f_pos, f_size) \ (((reg) >> (f_pos)) & ((1 << (f_size)) - 1)) /* Write field functions */ #define NPCX_SET_FIELD(reg, field, value) \ _NPCX_SET_FIELD_((reg), NPCX_FIELD_POS(field), NPCX_FIELD_SIZE(field), (value)) #define _NPCX_SET_FIELD_(reg, f_pos, f_size, value) \ ((reg) = ((reg) & (~(((1 << (f_size)) - 1) << (f_pos)))) | ((value) << (f_pos))) /* Register definitions */ #define NPCX_REG32_ADDR(addr) ((volatile uint32_t *)(addr)) #define NPCX_REG16_ADDR(addr) ((volatile uint16_t *)(addr)) #define NPCX_REG8_ADDR(addr) ((volatile uint8_t *)(addr)) #define NPCX_HW_BYTE(addr) (*NPCX_REG8_ADDR(addr)) #define NPCX_HW_WORD(addr) (*NPCX_REG16_ADDR(addr)) #define NPCX_HW_DWORD(addr) (*NPCX_REG32_ADDR(addr)) /* Devalt */ #define NPCX_SCFG_BASE_ADDR 0x400C3000 #define NPCX_DEVCNT NPCX_HW_BYTE(NPCX_SCFG_BASE_ADDR + 0x000) #define NPCX_DEVALT(n) NPCX_HW_BYTE(NPCX_SCFG_BASE_ADDR + 0x010 + (n)) #define NPCX_DEVCNT_HIF_TYP_SEL_FIELD FIELD(2, 2) #define NPCX_DEVCNT_JEN0_HEN 4 #define NPCX_DEVCNT_JEN1_HEN 5 #define NPCX_DEVCNT_F_SPI_TRIS 6 /* Pin-mux for SPI/FIU */ #define NPCX_DEVALT0_SPIP_SL 0 #define NPCX_DEVALT0_GPIO_NO_SPIP 3 #define NPCX_DEVALT0_F_SPI_CS1_2 4 #define NPCX_DEVALT0_F_SPI_CS1_1 5 #define NPCX_DEVALT0_F_SPI_QUAD 6 #define NPCX_DEVALT0_NO_F_SPI 7 /* Flash Interface Unit (FIU) registers */ #define NPCX_FIU_BASE_ADDR 0x40020000 #define NPCX_FIU_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x000) #define NPCX_BURST_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x001) #define NPCX_RESP_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x002) #define NPCX_SPI_FL_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x014) #define NPCX_UMA_CODE NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x016) #define NPCX_UMA_AB0 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x017) #define NPCX_UMA_AB1 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x018) #define NPCX_UMA_AB2 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x019) #define NPCX_UMA_DB0 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01A) #define NPCX_UMA_DB1 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01B) #define NPCX_UMA_DB2 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01C) #define NPCX_UMA_DB3 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01D) #define NPCX_UMA_CTS NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01E) #define NPCX_UMA_ECTS NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01F) #define NPCX_UMA_DB0_3 NPCX_HW_DWORD(NPCX_FIU_BASE_ADDR + 0x020) #define NPCX_FIU_RD_CMD NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x030) #define NPCX_FIU_DMM_CYC NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x032) #define NPCX_FIU_EXT_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x033) #define NPCX_FIU_UMA_AB0_3 NPCX_HW_DWORD(NPCX_FIU_BASE_ADDR + 0x034) /* FIU register fields */ #define NPCX_RESP_CFG_IAD_EN 0 #define NPCX_RESP_CFG_DEV_SIZE_EX 2 #define NPCX_UMA_CTS_A_SIZE 3 #define NPCX_UMA_CTS_C_SIZE 4 #define NPCX_UMA_CTS_RD_WR 5 #define NPCX_UMA_CTS_DEV_NUM 6 #define NPCX_UMA_CTS_EXEC_DONE 7 #define NPCX_UMA_ECTS_SW_CS0 0 #define NPCX_UMA_ECTS_SW_CS1 1 #define NPCX_UMA_ECTS_SEC_CS 2 #define NPCX_UMA_ECTS_UMA_LOCK 3 /* Flash UMA commands for npcx internal SPI flash */ #define NPCX_CMD_READ_ID 0x9F #define NPCX_CMD_READ_MAN_DEV_ID 0x90 #define NPCX_CMD_WRITE_EN 0x06 #define NPCX_CMD_WRITE_STATUS 0x50 #define NPCX_CMD_READ_STATUS_REG 0x05 #define NPCX_CMD_READ_STATUS_REG2 0x35 #define NPCX_CMD_WRITE_STATUS_REG 0x01 #define NPCX_CMD_FLASH_PROGRAM 0x02 #define NPCX_CMD_SECTOR_ERASE 0x20 #define NPCX_CMD_PROGRAM_UINT_SIZE 0x08 #define NPCX_CMD_PAGE_SIZE 0x00 #define NPCX_CMD_READ_ID_TYPE 0x47 #define NPCX_CMD_FAST_READ 0x0B #define NPCX_CMD_CHIP_ERASE 0xC7 /* * Status registers for SPI flash */ #define NPCX_SPI_FLASH_SR2_SUS (1 << 7) #define NPCX_SPI_FLASH_SR2_CMP (1 << 6) #define NPCX_SPI_FLASH_SR2_LB3 (1 << 5) #define NPCX_SPI_FLASH_SR2_LB2 (1 << 4) #define NPCX_SPI_FLASH_SR2_LB1 (1 << 3) #define NPCX_SPI_FLASH_SR2_QE (1 << 1) #define NPCX_SPI_FLASH_SR2_SRP1 (1 << 0) #define NPCX_SPI_FLASH_SR1_SRP0 (1 << 7) #define NPCX_SPI_FLASH_SR1_SEC (1 << 6) #define NPCX_SPI_FLASH_SR1_TB (1 << 5) #define NPCX_SPI_FLASH_SR1_BP2 (1 << 4) #define NPCX_SPI_FLASH_SR1_BP1 (1 << 3) #define NPCX_SPI_FLASH_SR1_BP0 (1 << 2) #define NPCX_SPI_FLASH_SR1_WEL (1 << 1) #define NPCX_SPI_FLASH_SR1_BUSY (1 << 0) #define NPCX_MASK_CMD_ONLY (0xC0) #define NPCX_MASK_CMD_ADR (0xC0 | 0x08) #define NPCX_MASK_CMD_ADR_WR (0xC0 | 0x20 | 0x08 | 0x01) #define NPCX_MASK_RD_1BYTE (0xC0 | 0x10 | 0x01) #define NPCX_MASK_RD_2BYTE (0xC0 | 0x10 | 0x02) #define NPCX_MASK_RD_3BYTE (0xC0 | 0x10 | 0x03) #define NPCX_MASK_RD_4BYTE (0xC0 | 0x10 | 0x04) #define NPCX_MASK_CMD_RD_1BYTE (0xC0 | 0x01) #define NPCX_MASK_CMD_RD_2BYTE (0xC0 | 0x02) #define NPCX_MASK_CMD_RD_3BYTE (0xC0 | 0x03) #define NPCX_MASK_CMD_RD_4BYTE (0xC0 | 0x04) #define NPCX_MASK_CMD_WR_ONLY (0xC0 | 0x20) #define NPCX_MASK_CMD_WR_1BYTE (0xC0 | 0x20 | 0x10 | 0x01) #define NPCX_MASK_CMD_WR_2BYTE (0xC0 | 0x20 | 0x10 | 0x02) #define NPCX_MASK_CMD_WR_ADR (0xC0 | 0x20 | 0x08) /* Flash loader parameters */ struct __attribute__((__packed__)) npcx_flash_params { uint32_t addr; /* Address in flash */ uint32_t len; /* Number of bytes */ uint32_t cmd; /* Command */ uint32_t sync; /* Handshake signal */ }; /* Flash trigger signal */ enum npcx_flash_handshake { NPCX_FLASH_LOADER_WAIT = 0x0, /* Idle */ NPCX_FLASH_LOADER_EXECUTE = 0xFFFFFFFF /* Execute Command */ }; /* Flash loader command */ enum npcx_flash_commands { NPCX_FLASH_CMD_NO_ACTION = 0, /* No action, default value */ NPCX_FLASH_CMD_GET_FLASH_ID, /* Get the internal flash ID */ NPCX_FLASH_CMD_ERASE_SECTORS, /* Erase unprotected sectors */ NPCX_FLASH_CMD_ERASE_ALL, /* Erase all */ NPCX_FLASH_CMD_PROGRAM, /* Program data */ }; /* Status */ enum npcx_flash_status { NPCX_FLASH_STATUS_OK = 0, NPCX_FLASH_STATUS_FAILED_UNKNOWN_COMMAND, NPCX_FLASH_STATUS_FAILED, NPCX_FLASH_STATUS_FAILED_TIMEOUT, }; #endif /* OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/npcx/npcx_flash.lds ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include "npcx_flash_config.h" /* Application memory map */ MEMORY { /* buffer + parameters */ BUFFER (RWX) : ORIGIN = NPCX_FLASH_LOADER_PARAMS_ADDR, LENGTH = NPCX_FLASH_LOADER_PARAMS_SIZE + NPCX_FLASH_LOADER_BUFFER_SIZE PROGRAM (RWX) : ORIGIN = NPCX_FLASH_LOADER_PROGRAM_ADDR, LENGTH = NPCX_FLASH_LOADER_PROGRAM_SIZE } /* Sections used for flashing */ SECTIONS { .buffers (NOLOAD) : { _buffers = .; *(.buffers.g_cfg) *(.buffers.g_buf) *(.buffers*) _ebuffers = .; } > BUFFER .text : { _text = .; *(.entry*) *(.text*) _etext = .; } > PROGRAM .data : { _data = .; *(.rodata*) *(.data*) _edata = .; } > PROGRAM .bss : { __bss_start__ = .; _bss = .; *(.bss*) *(COMMON) _ebss = .; __bss_end__ = .; } > PROGRAM .stack (NOLOAD) : { _stack = .; *(.stack*) _estack = .; } > PROGRAM } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/npcx/npcx_flash_config.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2021 by Nuvoton Technology Corporation * Mulin Chao * Wealian Liao */ #ifndef OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_CONFIG_H #define OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_CONFIG_H #define NPCX_FLASH_ABORT_TIMEOUT 0xFFFFFF /* NPCX chip information */ #define NPCX_FLASH_WRITE_SIZE 256L /* One page size for write */ #define NPCX_FLASH_ERASE_SIZE 0x1000 /* NPCX flash loader information */ #define NPCX_FLASH_LOADER_WORKING_ADDR 0x200C0000 #define NPCX_FLASH_LOADER_PARAMS_ADDR NPCX_FLASH_LOADER_WORKING_ADDR #define NPCX_FLASH_LOADER_PARAMS_SIZE 16 #define NPCX_FLASH_LOADER_BUFFER_ADDR (NPCX_FLASH_LOADER_PARAMS_ADDR + NPCX_FLASH_LOADER_PARAMS_SIZE) #define NPCX_FLASH_LOADER_BUFFER_SIZE NPCX_FLASH_ERASE_SIZE #define NPCX_FLASH_LOADER_PROGRAM_ADDR (NPCX_FLASH_LOADER_BUFFER_ADDR + NPCX_FLASH_LOADER_BUFFER_SIZE) #define NPCX_FLASH_LOADER_PROGRAM_SIZE 0x1000 /* Stack size in byte. 4 byte size alignment */ #define NPCX_FLASH_LOADER_STACK_SIZE 400 #endif /* OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_CONFIG_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/nrf5/nrf5.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2014 Angus Gratton * * gus@projectgus.com * ***************************************************************************/ .text .syntax unified .cpu cortex-m0 .thumb /* * Params : * r0 = byte count * r1 = buffer start * r2 = buffer end * r3 = target address * r6 = watchdog refresh value * r7 = watchdog refresh register address */ .thumb_func .global _start _start: wait_fifo: // Kick the watchdog str r6, [r7, #0] // Load write pointer ldr r5, [r1, #0] // Abort if it is NULL cmp r5, #0 beq.n exit // Load read pointer ldr r4, [r1, #4] // Continue waiting if it equals the write pointer cmp r4, r5 beq.n wait_fifo // Copy one word from buffer to target, and increment pointers ldmia r4!, {r5} stmia r3!, {r5} // If at end of buffer, wrap back to buffer start cmp r4, r2 bcc.n no_wrap mov r4, r1 adds r4, #8 no_wrap: // Update read pointer inside the buffer str r4, [r1, #4] // Deduce the word transferred from the byte count subs r0, #4 // Start again bne.n wait_fifo exit: // Wait for OpenOCD bkpt #0x00 .pool ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/nrf5/nrf5.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x3e,0x60,0x0d,0x68,0x00,0x2d,0x0b,0xd0,0x4c,0x68,0xac,0x42,0xf8,0xd0,0x20,0xcc, 0x20,0xc3,0x94,0x42,0x01,0xd3,0x0c,0x46,0x08,0x34,0x4c,0x60,0x04,0x38,0xef,0xd1, 0x00,0xbe, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/numicro/numicro_m0.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2015 Nemui Trinomius * * nemuisan_kawausogasuki@live.jp * * * * Copyright (C) 2017 Zale Yu * * CYYU@nuvoton.com * * * * Copyright (C) 2022 Jian-Hong Pan * * chienhung.pan@gmail.com * ***************************************************************************/ .text .cpu cortex-m0 .thumb /* Params: * r0 - workarea buffer / result * r1 - target address * r2 - wordcount * Clobbered: * r4 - tmp * r5 - tmp * r6 - tmp * r7 - tmp */ .L1: /* for(register uint32_t i=0;i */ #define BIT(n) (1UL << (n)) /* SH QSPI register bit masks _ */ #define SPCR_MSTR 0x08 #define SPCR_SPE 0x40 #define SPSR_SPRFF 0x80 #define SPSR_SPTEF 0x20 #define SPPCR_IO3FV 0x04 #define SPPCR_IO2FV 0x02 #define SPPCR_IO1FV 0x01 #define SPBDCR_RXBC0 BIT(0) #define SPCMD_SCKDEN BIT(15) #define SPCMD_SLNDEN BIT(14) #define SPCMD_SPNDEN BIT(13) #define SPCMD_SSLKP BIT(7) #define SPCMD_BRDV0 BIT(2) #define SPCMD_INIT1 SPCMD_SCKDEN | SPCMD_SLNDEN | \ SPCMD_SPNDEN | SPCMD_SSLKP | \ SPCMD_BRDV0 #define SPCMD_INIT2 SPCMD_SPNDEN | SPCMD_SSLKP | \ SPCMD_BRDV0 #define SPBFCR_TXRST BIT(7) #define SPBFCR_RXRST BIT(6) #define SPBFCR_TXTRG 0x30 #define SPBFCR_RXTRG 0x07 /* SH QSPI register set */ #define SH_QSPI_SPCR 0x00 #define SH_QSPI_SSLP 0x01 #define SH_QSPI_SPPCR 0x02 #define SH_QSPI_SPSR 0x03 #define SH_QSPI_SPDR 0x04 #define SH_QSPI_SPSCR 0x08 #define SH_QSPI_SPSSR 0x09 #define SH_QSPI_SPBR 0x0a #define SH_QSPI_SPDCR 0x0b #define SH_QSPI_SPCKD 0x0c #define SH_QSPI_SSLND 0x0d #define SH_QSPI_SPND 0x0e #define SH_QSPI_DUMMY0 0x0f #define SH_QSPI_SPCMD0 0x10 #define SH_QSPI_SPCMD1 0x12 #define SH_QSPI_SPCMD2 0x14 #define SH_QSPI_SPCMD3 0x16 #define SH_QSPI_SPBFCR 0x18 #define SH_QSPI_DUMMY1 0x19 #define SH_QSPI_SPBDCR 0x1a #define SH_QSPI_SPBMUL0 0x1c #define SH_QSPI_SPBMUL1 0x20 #define SH_QSPI_SPBMUL2 0x24 #define SH_QSPI_SPBMUL3 0x28 .syntax unified .arm .text .macro wait_for_spsr, spsrbit 1: ldrb r12, [r0, #SH_QSPI_SPSR] tst r12, \spsrbit beq 1b .endm .macro sh_qspi_xfer bl sh_qspi_cs_activate str r6, [r0, SH_QSPI_SPBMUL0] bl sh_qspi_xfer_common bl sh_qspi_cs_deactivate .endm .macro sh_qspi_write_enable ldr r4, =SPIFLASH_WRITE_ENABLE adr r5, _start add r4, r5 mov r5, #0x0 mov r6, #0x1 sh_qspi_xfer .endm .macro sh_qspi_wait_till_ready 1: ldr r4, =SPIFLASH_READ_STATUS adr r5, _start add r4, r5 mov r5, #0x0 mov r6, #0x2 sh_qspi_xfer and r13, #0x1 cmp r13, #0x1 beq 1b .endm /* * r0: controller base address * r1: data buffer base address * r2: BIT(31) -- page program (not read) * BIT(30) -- 4-byte address (not 3-byte) * BIT(29) -- 512-byte page (not 256-byte) * BIT(27:20) -- SF command * BIT(19:0) -- amount of data to read/write * r3: SF target address * * r7: data size * r8: page size * * r14: lr, link register * r15: pc, program counter * * Clobber: r4, r5, r6, r7, r8 */ .global _start _start: bic r7, r2, #0xff000000 bic r7, r7, #0x00f00000 and r8, r2, #(1 << 31) cmp r8, #(1 << 31) beq do_page_program /* fast read */ bl sh_qspi_cs_activate bl sh_qspi_setup_command add r8, r6, r7 str r8, [r0, SH_QSPI_SPBMUL0] bl sh_qspi_xfer_common mov r4, #0x0 mov r5, r1 mov r6, r7 bl sh_qspi_xfer_common bl sh_qspi_cs_deactivate b end do_page_program: mov r8, #0x100 tst r2, (1 << 29) movne r8, #0x200 do_pp_next_page: /* Check if less then page bytes left. */ cmp r7, r8 movlt r8, r7 sh_qspi_write_enable bl sh_qspi_cs_activate bl sh_qspi_setup_command str r6, [r0, SH_QSPI_SPBMUL0] bl sh_qspi_xfer_common mov r4, r1 mov r5, #0x0 mov r6, r8 bl sh_qspi_xfer_common bl sh_qspi_cs_deactivate sh_qspi_wait_till_ready add r1, r8 add r3, r8 sub r7, r8 cmp r7, #0 bne do_pp_next_page end: bkpt #0 sh_qspi_cs_activate: /* Set master mode only */ mov r12, #SPCR_MSTR strb r12, [r0, SH_QSPI_SPCR] /* Set command */ mov r12, #SPCMD_INIT1 strh r12, [r0, SH_QSPI_SPCMD0] /* Reset transfer and receive Buffer */ ldrb r12, [r0, SH_QSPI_SPSCR] orr r12, #(SPBFCR_TXRST | SPBFCR_RXRST) strb r12, [r0, SH_QSPI_SPBFCR] /* Clear transfer and receive Buffer control bit */ ldrb r12, [r0, SH_QSPI_SPBFCR] bic r12, #(SPBFCR_TXRST | SPBFCR_RXRST) strb r12, [r0, SH_QSPI_SPBFCR] /* Set sequence control method. Use sequence0 only */ mov r12, #0x00 strb r12, [r0, SH_QSPI_SPSCR] /* Enable SPI function */ ldrb r12, [r0, SH_QSPI_SPCR] orr r12, #SPCR_SPE strb r12, [r0, SH_QSPI_SPCR] mov pc, lr sh_qspi_cs_deactivate: /* Disable SPI function */ ldrb r12, [r0, SH_QSPI_SPCR] bic r12, #SPCR_SPE strb r12, [r0, SH_QSPI_SPCR] mov pc, lr /* * r0, controller base address * r4, tx buffer * r5, rx buffer * r6, xfer len, non-zero * * Upon exit, r13 contains the last byte in SPDR * * Clobber: r11, r12, r13 */ sh_qspi_xfer_common: prepcopy: ldr r13, [r0, #SH_QSPI_SPBFCR] orr r13, #(SPBFCR_TXTRG | SPBFCR_RXTRG) mov r11, #32 cmp r6, #32 biclt r13, #(SPBFCR_TXTRG | SPBFCR_RXTRG) movlt r11, #1 copy: str r13, [r0, #SH_QSPI_SPBFCR] wait_for_spsr SPSR_SPTEF mov r12, r11 mov r13, #0 cmp r4, #0 beq 3f 2: ldrb r13, [r4], #1 strb r13, [r0, #SH_QSPI_SPDR] subs r12, #1 bne 2b b 4f 3: strb r13, [r0, #SH_QSPI_SPDR] subs r12, #1 bne 3b 4: wait_for_spsr SPSR_SPRFF mov r12, r11 cmp r5, #0 beq 6f 5: ldrb r13, [r0, #SH_QSPI_SPDR] strb r13, [r5], #1 subs r12, #1 bne 5b b 7f 6: ldrb r13, [r0, #SH_QSPI_SPDR] subs r12, #1 bne 6b 7: subs r6, r11 bne prepcopy mov pc, lr sh_qspi_setup_command: ldr r4, =SPIFLASH_SCRATCH_DATA adr r5, _start add r4, r5 and r12, r2, #0x0ff00000 lsr r12, #20 strb r12, [r4] mov r12, r3 strb r12, [r4, #4] lsr r12, #8 strb r12, [r4, #3] lsr r12, #8 strb r12, [r4, #2] lsr r12, #8 strb r12, [r4, #1] lsr r12, #8 mov r5, #0x0 mov r6, #0x4 tst r2, (1 << 30) movne r6, #0x5 mov pc, lr SPIFLASH_READ_STATUS: .byte 0x05 /* Read Status Register */ SPIFLASH_WRITE_ENABLE: .byte 0x06 /* Write Enable */ SPIFLASH_NOOP: .byte 0x00 SPIFLASH_SCRATCH_DATA: .byte 0x00, 0x0, 0x0, 0x0, 0x0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/sh_qspi/sh_qspi.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0xff,0x74,0xc2,0xe3,0x0f,0x76,0xc7,0xe3,0x02,0x81,0x02,0xe2,0x02,0x01,0x58,0xe3, 0x0a,0x00,0x00,0x0a,0x32,0x00,0x00,0xeb,0x6c,0x00,0x00,0xeb,0x07,0x80,0x86,0xe0, 0x1c,0x80,0x80,0xe5,0x42,0x00,0x00,0xeb,0x00,0x40,0xa0,0xe3,0x01,0x50,0xa0,0xe1, 0x07,0x60,0xa0,0xe1,0x3e,0x00,0x00,0xeb,0x39,0x00,0x00,0xeb,0x27,0x00,0x00,0xea, 0x01,0x8c,0xa0,0xe3,0x02,0x02,0x12,0xe3,0x02,0x8c,0xa0,0x13,0x08,0x00,0x57,0xe1, 0x07,0x80,0xa0,0xb1,0xcc,0x41,0x9f,0xe5,0x60,0x50,0x4f,0xe2,0x05,0x40,0x84,0xe0, 0x00,0x50,0xa0,0xe3,0x01,0x60,0xa0,0xe3,0x1d,0x00,0x00,0xeb,0x1c,0x60,0x80,0xe5, 0x2f,0x00,0x00,0xeb,0x2a,0x00,0x00,0xeb,0x19,0x00,0x00,0xeb,0x53,0x00,0x00,0xeb, 0x1c,0x60,0x80,0xe5,0x2a,0x00,0x00,0xeb,0x01,0x40,0xa0,0xe1,0x00,0x50,0xa0,0xe3, 0x08,0x60,0xa0,0xe1,0x26,0x00,0x00,0xeb,0x21,0x00,0x00,0xeb,0x88,0x41,0x9f,0xe5, 0xa8,0x50,0x4f,0xe2,0x05,0x40,0x84,0xe0,0x00,0x50,0xa0,0xe3,0x02,0x60,0xa0,0xe3, 0x0b,0x00,0x00,0xeb,0x1c,0x60,0x80,0xe5,0x1d,0x00,0x00,0xeb,0x18,0x00,0x00,0xeb, 0x01,0xd0,0x0d,0xe2,0x01,0x00,0x5d,0xe3,0xf3,0xff,0xff,0x0a,0x08,0x10,0x81,0xe0, 0x08,0x30,0x83,0xe0,0x08,0x70,0x47,0xe0,0x00,0x00,0x57,0xe3,0xda,0xff,0xff,0x1a, 0x70,0x00,0x20,0xe1,0x08,0xc0,0xa0,0xe3,0x00,0xc0,0xc0,0xe5,0x84,0xc0,0x0e,0xe3, 0xb0,0xc1,0xc0,0xe1,0x08,0xc0,0xd0,0xe5,0xc0,0xc0,0x8c,0xe3,0x18,0xc0,0xc0,0xe5, 0x18,0xc0,0xd0,0xe5,0xc0,0xc0,0xcc,0xe3,0x18,0xc0,0xc0,0xe5,0x00,0xc0,0xa0,0xe3, 0x08,0xc0,0xc0,0xe5,0x00,0xc0,0xd0,0xe5,0x40,0xc0,0x8c,0xe3,0x00,0xc0,0xc0,0xe5, 0x0e,0xf0,0xa0,0xe1,0x00,0xc0,0xd0,0xe5,0x40,0xc0,0xcc,0xe3,0x00,0xc0,0xc0,0xe5, 0x0e,0xf0,0xa0,0xe1,0x18,0xd0,0x90,0xe5,0x37,0xd0,0x8d,0xe3,0x20,0xb0,0xa0,0xe3, 0x20,0x00,0x56,0xe3,0x37,0xd0,0xcd,0xb3,0x01,0xb0,0xa0,0xb3,0x18,0xd0,0x80,0xe5, 0x03,0xc0,0xd0,0xe5,0x20,0x00,0x1c,0xe3,0xfc,0xff,0xff,0x0a,0x0b,0xc0,0xa0,0xe1, 0x00,0xd0,0xa0,0xe3,0x00,0x00,0x54,0xe3,0x04,0x00,0x00,0x0a,0x01,0xd0,0xd4,0xe4, 0x04,0xd0,0xc0,0xe5,0x01,0xc0,0x5c,0xe2,0xfb,0xff,0xff,0x1a,0x02,0x00,0x00,0xea, 0x04,0xd0,0xc0,0xe5,0x01,0xc0,0x5c,0xe2,0xfc,0xff,0xff,0x1a,0x03,0xc0,0xd0,0xe5, 0x80,0x00,0x1c,0xe3,0xfc,0xff,0xff,0x0a,0x0b,0xc0,0xa0,0xe1,0x00,0x00,0x55,0xe3, 0x04,0x00,0x00,0x0a,0x04,0xd0,0xd0,0xe5,0x01,0xd0,0xc5,0xe4,0x01,0xc0,0x5c,0xe2, 0xfb,0xff,0xff,0x1a,0x02,0x00,0x00,0xea,0x04,0xd0,0xd0,0xe5,0x01,0xc0,0x5c,0xe2, 0xfc,0xff,0xff,0x1a,0x0b,0x60,0x56,0xe0,0xd9,0xff,0xff,0x1a,0x0e,0xf0,0xa0,0xe1, 0x58,0x40,0x9f,0xe5,0x77,0x5f,0x4f,0xe2,0x05,0x40,0x84,0xe0,0xff,0xc6,0x02,0xe2, 0x2c,0xca,0xa0,0xe1,0x00,0xc0,0xc4,0xe5,0x03,0xc0,0xa0,0xe1,0x04,0xc0,0xc4,0xe5, 0x2c,0xc4,0xa0,0xe1,0x03,0xc0,0xc4,0xe5,0x2c,0xc4,0xa0,0xe1,0x02,0xc0,0xc4,0xe5, 0x2c,0xc4,0xa0,0xe1,0x01,0xc0,0xc4,0xe5,0x2c,0xc4,0xa0,0xe1,0x00,0x50,0xa0,0xe3, 0x04,0x60,0xa0,0xe3,0x01,0x01,0x12,0xe3,0x05,0x60,0xa0,0x13,0x0e,0xf0,0xa0,0xe1, 0x05,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x02,0x00,0x00,0x20,0x02,0x00,0x00, 0x23,0x02,0x00,0x00, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/sh_qspi/sh_qspi.ld ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { . = 0x0; . = ALIGN(4); .text : { sh_qspi.o (.text*) *(.text*) } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/sim3x.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2014 by Ladislav Bábel * * ladababel@seznam.cz * ***************************************************************************/ #define INITIAL_UNLOCK 0x5A #define MULTIPLE_UNLOCK 0xF2 #define FLASHCTRL_KEY 0x4002E0C0 #define FLASHCTRL_CONFIG 0x4002E000 #define FLASHCTRL_WRADDR 0x4002E0A0 #define FLASHCTRL_WRDATA 0x4002E0B0 #define BUSYF 0x00100000 /* Write the initial unlock value to KEY (0xA5) */ movs r6, #INITIAL_UNLOCK str r6, [r0, #FLASHCTRL_KEY] /* Write the multiple unlock value to KEY (0xF2) */ movs r6, #MULTIPLE_UNLOCK str r6, [r0, #FLASHCTRL_KEY] wait_fifo: ldr r6, [r2, #0] cmp r6, #0 beq exit ldr r5, [r2, #4] cmp r5, r6 beq wait_fifo /* wait for BUSYF flag */ wait_busy1: ldr r6, [r0, #FLASHCTRL_CONFIG] tst r6, #BUSYF bne wait_busy1 /* Write the destination address to WRADDR */ str r4, [r0, #FLASHCTRL_WRADDR] /* Write the data half-word to WRDATA in right-justified format */ ldrh r6, [r5] str r6, [r0, #FLASHCTRL_WRDATA] adds r5, #2 adds r4, #2 /* wrap rp at end of buffer */ cmp r5, r3 bcc no_wrap mov r5, r2 adds r5, #8 no_wrap: str r5, [r2, #4] subs r1, r1, #1 cmp r1, #0 beq exit b wait_fifo exit: movs r6, #MULTIPLE_LOCK str r6, [r0, #FLASHCTRL_KEY] /* wait for BUSYF flag */ wait_busy2: ldr r6, [r0, #FLASHCTRL_CONFIG] tst r6, #BUSYF bne wait_busy2 bkpt #0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stellaris.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ .text .syntax unified .cpu cortex-m3 .thumb .thumb_func /* * Params : * r0 = workarea start * r1 = workarea end * r2 = target address * r3 = count (32bit words) * * Clobbered: * r4 = pFLASH_CTRL_BASE * r5 = FLASHWRITECMD * r7 - rp * r8 - wp, tmp */ write: ldr r4, pFLASH_CTRL_BASE ldr r5, FLASHWRITECMD wait_fifo: ldr r8, [r0, #0] /* read wp */ cmp r8, #0 /* abort if wp == 0 */ beq exit ldr r7, [r0, #4] /* read rp */ cmp r7, r8 /* wait until rp != wp */ beq wait_fifo mainloop: str r2, [r4, #0] /* FMA - write address */ add r2, r2, #4 /* increment target address */ ldr r8, [r7], #4 str r8, [r4, #4] /* FMD - write data */ str r5, [r4, #8] /* FMC - enable write */ busy: ldr r8, [r4, #8] tst r8, #1 bne busy cmp r7, r1 /* wrap rp at end of buffer */ it cs addcs r7, r0, #8 /* skip loader args */ str r7, [r0, #4] /* store rp */ subs r3, r3, #1 /* decrement word count */ cbz r3, exit /* loop if not done */ b wait_fifo exit: bkpt #0 pFLASH_CTRL_BASE: .word 0x400FD000 FLASHWRITECMD: .word 0xA4420001 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stm32/stm32f1x.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * ***************************************************************************/ .text .syntax unified .cpu cortex-m0 .thumb /* Params: * r0 - flash base (in), status (out) * r1 - count (halfword-16bit) * r2 - workarea start * r3 - workarea end * r4 - target address * Clobbered: * r5 - rp * r6 - wp, tmp * r7 - tmp */ #define STM32_FLASH_SR_OFFSET 0x0c /* offset of SR register from flash reg base */ .thumb_func .global _start _start: wait_fifo: ldr r6, [r2, #0] /* read wp */ cmp r6, #0 /* abort if wp == 0 */ beq exit ldr r5, [r2, #4] /* read rp */ cmp r5, r6 /* wait until rp != wp */ beq wait_fifo ldrh r6, [r5] /* "*target_address++ = *rp++" */ strh r6, [r4] adds r5, #2 adds r4, #2 busy: ldr r6, [r0, #STM32_FLASH_SR_OFFSET] /* wait until BSY flag is reset */ movs r7, #1 tst r6, r7 bne busy movs r7, #0x14 /* check the error bits */ tst r6, r7 bne error cmp r5, r3 /* wrap rp at end of buffer */ bcc no_wrap mov r5, r2 adds r5, #8 no_wrap: str r5, [r2, #4] /* store rp */ subs r1, r1, #1 /* decrement halfword count */ cmp r1, #0 beq exit /* loop if not done */ b wait_fifo error: movs r0, #0 str r0, [r2, #4] /* set rp = 0 on error */ exit: mov r0, r6 /* return status in r0 */ bkpt #0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stm32/stm32f1x.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x16,0x68,0x00,0x2e,0x18,0xd0,0x55,0x68,0xb5,0x42,0xf9,0xd0,0x2e,0x88,0x26,0x80, 0x02,0x35,0x02,0x34,0xc6,0x68,0x01,0x27,0x3e,0x42,0xfb,0xd1,0x14,0x27,0x3e,0x42, 0x08,0xd1,0x9d,0x42,0x01,0xd3,0x15,0x46,0x08,0x35,0x55,0x60,0x01,0x39,0x00,0x29, 0x02,0xd0,0xe5,0xe7,0x00,0x20,0x50,0x60,0x30,0x46,0x00,0xbe, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stm32/stm32f2x.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ .text .syntax unified .cpu cortex-m3 .thumb /* * Params : * r0 = workarea start, status (out) * r1 = workarea end * r2 = target address * r3 = count (16bit words) * r4 = flash base * * Clobbered: * r6 - temp * r7 - rp * r8 - wp, tmp */ #define STM32_FLASH_CR_OFFSET 0x10 /* offset of CR register in FLASH struct */ #define STM32_FLASH_SR_OFFSET 0x0c /* offset of SR register in FLASH struct */ #define STM32_PROG16 0x101 /* PG | PSIZE_16*/ .thumb_func .global _start _start: wait_fifo: ldr r8, [r0, #0] /* read wp */ cmp r8, #0 /* abort if wp == 0 */ beq exit ldr r7, [r0, #4] /* read rp */ cmp r7, r8 /* wait until rp != wp */ beq wait_fifo ldr r6, =STM32_PROG16 str r6, [r4, #STM32_FLASH_CR_OFFSET] ldrh r6, [r7], #0x02 /* read one half-word from src, increment ptr */ strh r6, [r2], #0x02 /* write one half-word from src, increment ptr */ dsb busy: ldr r6, [r4, #STM32_FLASH_SR_OFFSET] tst r6, #0x10000 /* BSY (bit16) == 1 => operation in progress */ bne busy /* wait more... */ tst r6, #0xf0 /* PGSERR | PGPERR | PGAERR | WRPERR */ bne error /* fail... */ cmp r7, r1 /* wrap rp at end of buffer */ it cs addcs r7, r0, #8 /* skip loader args */ str r7, [r0, #4] /* store rp */ subs r3, r3, #1 /* decrement halfword count */ cbz r3, exit /* loop if not done */ b wait_fifo error: movs r1, #0 str r1, [r0, #4] /* set rp = 0 on error */ exit: mov r0, r6 /* return status in r0 */ bkpt #0x00 .pool ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stm32/stm32f2x.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0xd0,0xf8,0x00,0x80,0xb8,0xf1,0x00,0x0f,0x1b,0xd0,0x47,0x68,0x47,0x45,0xf7,0xd0, 0x0d,0x4e,0x26,0x61,0x37,0xf8,0x02,0x6b,0x22,0xf8,0x02,0x6b,0xbf,0xf3,0x4f,0x8f, 0xe6,0x68,0x16,0xf4,0x80,0x3f,0xfb,0xd1,0x16,0xf0,0xf0,0x0f,0x07,0xd1,0x8f,0x42, 0x28,0xbf,0x00,0xf1,0x08,0x07,0x47,0x60,0x01,0x3b,0x13,0xb1,0xe0,0xe7,0x00,0x21, 0x41,0x60,0x30,0x46,0x00,0xbe,0x00,0x00,0x01,0x01,0x00,0x00, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stm32/stm32h7x.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2017 by STMicroelectronics * ***************************************************************************/ .text .syntax unified .cpu cortex-m4 .thumb /* * Code limitations: * The workarea must have size multiple of 4 bytes, since R/W * operations are all at 32 bits. * The workarea must be big enough to contain rp, wp and data, thus the minimum * workarea size is: min_wa_size = sizeof(rp, wp, data) = 4 + 4 + sizeof(data). * - for 0x450 devices: sizeof(data) = 32 bytes, thus min_wa_size = 40 bytes. * - for 0x480 devices: sizeof(data) = 16 bytes, thus min_wa_size = 24 bytes. * To benefit from concurrent host write-to-buffer and target * write-to-flash, the workarea must be way bigger than the minimum. * * To avoid confusions the write word size is got from .block_size member of * struct stm32h7x_part_info defined in stm32h7x.c */ /* * Params : * r0 = workarea start, status (out) * r1 = workarea end * r2 = target address * r3 = count (of write words) * r4 = size of write word * r5 = flash reg base * * Clobbered: * r6 - rp * r7 - wp, status, tmp * r8 - loop index, tmp */ #define STM32_FLASH_CR_OFFSET 0x0C /* offset of CR register in FLASH struct */ #define STM32_FLASH_SR_OFFSET 0x10 /* offset of SR register in FLASH struct */ #define STM32_CR_PROG 0x00000002 /* PG */ #define STM32_SR_QW_MASK 0x00000004 /* QW */ #define STM32_SR_ERROR_MASK 0x07ee0000 /* DBECCERR | SNECCERR | RDSERR | RDPERR | OPERR | INCERR | STRBERR | PGSERR | WRPERR */ .thumb_func .global _start _start: ldr r6, [r0, #4] /* read rp */ wait_fifo: ldr r7, [r0, #0] /* read wp */ cbz r7, exit /* abort if wp == 0, status = 0 */ subs r7, r7, r6 /* number of bytes available for read in r7 */ ittt mi /* if wrapped around */ addmi r7, r1 /* add size of buffer */ submi r7, r0 submi r7, #8 cmp r7, r4 /* wait until data buffer is full */ bcc wait_fifo mov r7, #STM32_CR_PROG str r7, [r5, #STM32_FLASH_CR_OFFSET] mov r8, #4 udiv r8, r4, r8 /* number of words is size of write word divided by 4*/ write_flash: dsb ldr r7, [r6], #0x04 /* read one word from src, increment ptr */ str r7, [r2], #0x04 /* write one word to dst, increment ptr */ dsb cmp r6, r1 /* if rp >= end of buffer ... */ it cs addcs r6, r0, #8 /* ... then wrap at buffer start */ subs r8, r8, #1 /* decrement loop index */ bne write_flash /* loop if not done */ busy: ldr r7, [r5, #STM32_FLASH_SR_OFFSET] tst r7, #STM32_SR_QW_MASK bne busy /* operation in progress, wait ... */ ldr r8, =STM32_SR_ERROR_MASK tst r7, r8 bne error /* fail... */ str r6, [r0, #4] /* store rp */ subs r3, r3, #1 /* decrement count */ bne wait_fifo /* loop if not done */ b exit error: movs r8, #0 str r8, [r0, #4] /* set rp = 0 on error */ exit: mov r0, r7 /* return status in r0 */ bkpt #0x00 .pool ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stm32/stm32h7x.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x46,0x68,0x07,0x68,0x6f,0xb3,0xbf,0x1b,0x42,0xbf,0x7f,0x18,0x3f,0x1a,0x08,0x3f, 0xa7,0x42,0xf6,0xd3,0x4f,0xf0,0x02,0x07,0xef,0x60,0x4f,0xf0,0x04,0x08,0xb4,0xfb, 0xf8,0xf8,0xbf,0xf3,0x4f,0x8f,0x56,0xf8,0x04,0x7b,0x42,0xf8,0x04,0x7b,0xbf,0xf3, 0x4f,0x8f,0x8e,0x42,0x28,0xbf,0x00,0xf1,0x08,0x06,0xb8,0xf1,0x01,0x08,0xf0,0xd1, 0x2f,0x69,0x17,0xf0,0x04,0x0f,0xfb,0xd1,0xdf,0xf8,0x1c,0x80,0x17,0xea,0x08,0x0f, 0x03,0xd1,0x46,0x60,0x01,0x3b,0xd4,0xd1,0x03,0xe0,0x5f,0xf0,0x00,0x08,0xc0,0xf8, 0x04,0x80,0x38,0x46,0x00,0xbe,0x00,0x00,0x00,0x00,0xee,0x07, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stm32/stm32l4x.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /** * Copyright (C) 2021 Tarek BOCHKATI * tarek.bouchkati@st.com */ #define OPENOCD_CONTRIB_LOADERS_FLASH_STM32_STM32L4X #include #include "../../../../src/flash/nor/stm32l4x.h" static inline __attribute__((always_inline)) void copy_buffer_u32(uint32_t *dst, uint32_t *src, int len) { for (int i = 0; i < len; i++) dst[i] = src[i]; } /* this function is assumes that fifo_size is multiple of flash_word_size * this condition is ensured by target_run_flash_async_algorithm */ void write(volatile struct stm32l4_work_area *work_area, uint8_t *fifo_end, uint8_t *target_address, uint32_t count) { volatile uint32_t *flash_sr = (uint32_t *) work_area->params.flash_sr_addr; volatile uint32_t *flash_cr = (uint32_t *) work_area->params.flash_cr_addr; /* optimization to avoid reading from memory each time */ uint8_t *rp_cache = work_area->fifo.rp; /* fifo_start is used to wrap when we reach fifo_end */ uint8_t *fifo_start = rp_cache; /* enable flash programming */ *flash_cr = FLASH_PG; while (count) { /* optimization to avoid reading from memory each time */ uint8_t *wp_cache = work_area->fifo.wp; if (wp_cache == 0) break; /* aborted by target_run_flash_async_algorithm */ int32_t fifo_size = wp_cache - rp_cache; if (fifo_size < 0) { /* consider the linear fifo, we will wrap later */ fifo_size = fifo_end - rp_cache; } /* wait for at least a flash word */ while (fifo_size >= work_area->params.flash_word_size) { copy_buffer_u32((uint32_t *)target_address, (uint32_t *)rp_cache, work_area->params.flash_word_size / 4); /* update target_address and rp_cache */ target_address += work_area->params.flash_word_size; rp_cache += work_area->params.flash_word_size; /* wait for the busy flag */ while (*flash_sr & work_area->params.flash_sr_bsy_mask) ; if (*flash_sr & FLASH_ERROR) { work_area->fifo.rp = 0; /* set rp to zero 0 on error */ goto write_end; } /* wrap if reach the fifo_end, and update rp in memory */ if (rp_cache >= fifo_end) rp_cache = fifo_start; /* flush the rp cache value, * so target_run_flash_async_algorithm can fill the circular fifo */ work_area->fifo.rp = rp_cache; /* update fifo_size and count */ fifo_size -= work_area->params.flash_word_size; count--; } } write_end: /* disable flash programming */ *flash_cr = 0; /* soft break the loader */ __asm("bkpt 0"); } /* by enabling this define 'DEBUG': * the main() function can help help debugging the loader algo * note: the application should be linked into RAM */ /* #define DEBUG */ #ifdef DEBUG /* device selector: STM32L5 | STM32U5 | STM32WB | STM32WL | STM32WL_CPU2 | STM32G0Bx | ... */ #define STM32U5 /* when using a secure device, and want to test the secure programming enable this define */ /* #define SECURE */ #if defined(STM32U5) # define FLASH_WORD_SIZE 16 #else # define FLASH_WORD_SIZE 8 #endif #if defined(STM32WB) || defined(STM32WL) # define FLASH_BASE 0x58004000 #else # define FLASH_BASE 0x40022000 #endif #if defined(STM32G0Bx) # define FLASH_BSY_MASK (FLASH_BSY | FLASH_BSY2) #else # define FLASH_BSY_MASK FLASH_BSY #endif #if defined(STM32L5) || defined(STM32U5) # ifdef SECURE # define FLASH_KEYR_OFFSET 0x0c # define FLASH_SR_OFFSET 0x24 # define FLASH_CR_OFFSET 0x2c # else # define FLASH_KEYR_OFFSET 0x08 # define FLASH_SR_OFFSET 0x20 # define FLASH_CR_OFFSET 0x28 # endif #elif defined(STM32WL_CPU2) # define FLASH_KEYR_OFFSET 0x08 # define FLASH_SR_OFFSET 0x60 # define FLASH_CR_OFFSET 0x64 #else # define FLASH_KEYR_OFFSET 0x08 # define FLASH_SR_OFFSET 0x10 # define FLASH_CR_OFFSET 0x14 #endif #define FLASH_KEYR (uint32_t *)((FLASH_BASE) + (FLASH_KEYR_OFFSET)) #define FLASH_SR (uint32_t *)((FLASH_BASE) + (FLASH_SR_OFFSET)) #define FLASH_CR (uint32_t *)((FLASH_BASE) + (FLASH_CR_OFFSET)) int main() { const uint32_t count = 2; const uint32_t buf_size = count * FLASH_WORD_SIZE; const uint32_t work_area_size = sizeof(struct stm32l4_work_area) + buf_size; uint8_t work_area_buf[work_area_size]; struct stm32l4_work_area *workarea = (struct stm32l4_work_area *)work_area_buf; /* fill the workarea struct */ workarea->params.flash_sr_addr = (uint32_t)(FLASH_SR); workarea->params.flash_cr_addr = (uint32_t)(FLASH_CR); workarea->params.flash_word_size = FLASH_WORD_SIZE; workarea->params.flash_sr_bsy_mask = FLASH_BSY_MASK; /* note: the workarea->stack is not used, in this configuration */ /* programming the existing memory raw content in workarea->fifo.buf */ /* feel free to fill the memory with magical values ... */ workarea->fifo.wp = (uint8_t *)(&workarea->fifo.buf + buf_size); workarea->fifo.rp = (uint8_t *)&workarea->fifo.buf; /* unlock the flash */ *FLASH_KEYR = KEY1; *FLASH_KEYR = KEY2; /* erase sector 0 */ *FLASH_CR = FLASH_PER | FLASH_STRT; while (*FLASH_SR & FLASH_BSY) ; /* flash address, should be aligned to FLASH_WORD_SIZE */ uint8_t *target_address = (uint8_t *) 0x8000000; write(workarea, (uint8_t *)(workarea + work_area_size), target_address, count); while (1) ; } #endif /* DEBUG */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stm32/stm32l4x.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0xf0,0xb5,0x87,0xb0,0x07,0x68,0x01,0x93,0x43,0x68,0x04,0x91,0x02,0x93,0x83,0x6f, 0x02,0x99,0x03,0x93,0x01,0x23,0x0b,0x60,0x03,0x9b,0x01,0x99,0x00,0x29,0x1f,0xd0, 0x41,0x6f,0x00,0x29,0x1c,0xd0,0xc9,0x1a,0x01,0xd5,0x04,0x99,0xc9,0x1a,0x84,0x68, 0x8c,0x42,0xf2,0xd8,0x85,0x68,0xac,0x08,0x05,0x94,0x00,0x24,0x05,0x9d,0xa5,0x42, 0x14,0xdc,0x84,0x68,0x12,0x19,0x84,0x68,0x1b,0x19,0x3c,0x68,0xc5,0x68,0x2e,0x00, 0x26,0x40,0x25,0x42,0xf9,0xd1,0xfa,0x25,0x3c,0x68,0x2c,0x42,0x0b,0xd0,0x86,0x67, 0x00,0x23,0x02,0x9a,0x13,0x60,0x00,0xbe,0x07,0xb0,0xf0,0xbd,0xa6,0x00,0x9d,0x59, 0x01,0x34,0x95,0x51,0xe2,0xe7,0x04,0x9c,0x9c,0x42,0x00,0xd8,0x03,0x9b,0x83,0x67, 0x84,0x68,0x09,0x1b,0x01,0x9c,0x01,0x3c,0x01,0x94,0xd0,0xe7, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stm32/stm32lx.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2011 Clement Burin des Roziers * * clement.burin-des-roziers@hikob.com * * * * Copyright (C) 2017 Armin van der Togt * * armin@otheruse.nl * ***************************************************************************/ .text .syntax unified .cpu cortex-m0 .thumb /* Parameters r0 - destination address r1 - source address r2 - half pages r3 - bytes per half page r4 - flash base Variables r0 - destination write pointer r1 - source read pointer r2 - source limit address r3 - bytes per half page r4 - flash base r5 - pages left in current half page r6 - temporary r/w */ /* offsets of registers from flash reg base */ #define STM32_FLASH_SR_OFFSET 0x18 .thumb_func .global _start _start: // r2 = source + half pages * bytes per half page muls r2, r2, r3 add r2, r1, r2 // Go to compare b test_done write_half_page: // initialize pages left in current half page mov r5, r3 write_word: // load word from address in r1 and increase r1 by 4 ldmia r1!, {r6} // store word to address in r0 and increase r0 by 4 stmia r0!, {r6} // check for end of half page subs r5, r5, #4 bne write_word wait_busy: // read status register into r6, loop while bottom bit is set ldr r6, [r4, #STM32_FLASH_SR_OFFSET] lsls r6, r6, #31 bne wait_busy test_done: // compare r1 and r2, loop if not equal cmp r1, r2 bne write_half_page // Set breakpoint to exit bkpt #0x00 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stm32/stm32lx.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x5a,0x43,0x0a,0x44,0x07,0xe0,0x1d,0x46,0x40,0xc9,0x40,0xc0,0x04,0x3d,0xfb,0xd1, 0xa6,0x69,0xf6,0x07,0xfc,0xd1,0x91,0x42,0xf5,0xd1,0x00,0xbe, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl ================================================ #!/usr/bin/perl # SPDX-License-Identifier: GPL-2.0-or-later # # Helper for generating GPIO setup for STM32F0, F4, F7, H7, L0, L1, L4, L4+ # and F1 (for 'stmqspi' and 'cmspi' drivers). # # Each pin is configured by "PortAndBit:Conf:Speed" # 'PortAndBit' specifies Port and bit number # 'Conf' is one of 'AFx' (alternate), 'P' (output), 'IN' (input), # (each optionally by 'P' (push-pull) or 'O' (open-drain)), # (all optionally followed by 'UP' (pull-up), or 'DO' (pull-down)) # 'Speed' is one of 'L' (low), 'M' (medium), 'H' (high), 'V' (very high) # # Port configuration can be given on command line as a single string (pins separated by commas) # or via CubeMX generated file. The latter must consist of the quadspi.c / octospi.c and the # corresponding header. The precise spelling in these files doesn't seem to be consistent, though ... # # Pins have to be ordered this way: # - I2C: SDA, SCL # - SPI (1 line): NCS, CLK, IO1/MISO, IO0/MOSI # - DPI (2 lines): NCS, CLK, IO1/MISO, IO0/MOSI # - QPI (4 lines): NCS, CLK, IO3/NHOLD, IO2/NWP, IO1/MISO, IO0/MOSI # For dual flash: BK_1 first, then BK_2. If single NCS for both, omit NCS in BK_2 # For octal flash: NCS, CLK, DQS, IO7 down to IO0 use strict; use Getopt::Std; my $GPIO_BASE; my $Conf; my $STM32F1 = 0; # "Blue-Pill stm32f103cbt6 board w/ cmspi #$STM32F1 = 1; #$GPIO_BASE = 0x40010800; #$Conf = "PB12:PP:M, PB13:PP:V, PB14:INUP:V, PB15:INUP:V"; #$Conf = "PB12:PP:M, PB13:PP:V, PB14:INUP:V, PB01:INUP:V"; #$STM32F1 = 1; #$GPIO_BASE = 0x40010800; #$Conf = "PB07:INUP:V, PB06:INUP:V"; # mini-stm32f030f4p6 board w/ cmspi #$GPIO_BASE = 0x48000000; #$Conf = "PB01:PP:V, PA05:PP:V, PA06:INUP:V, PA07:INUP:V"; # stm32f407vet6 board w/ cmspi #$GPIO_BASE = 0x40020000; #$Conf = "PB00:PP:M, PB03:PP:V, PB04:INUP:V, PB05:INUP:V"; # stm32f412g-disco quad #$GPIO_BASE = 0x40020000; #$Conf = "PB02:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V, PG06:AF10:V"; # stm32f413h-disco #$GPIO_BASE = 0x40020000; #$Conf = "PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PF09:AF10:V, PF08:AF10:V, PG06:AF10:V"; # stm32f469i-disco quad #$GPIO_BASE = 0x40020000; #$Conf = "PB06:AF10:V, PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V"; # w/ cmspi #$Conf = "PB06:PP:M, PF10:PP:V, PF06:INUP:V, PF07:INUP:V, PF09:INUP:V, PF08:INUP:V"; # stm32f723e-disco quad #$GPIO_BASE = 0x40020000; #$Conf = "PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V"; # stm32f746g-disco quad #$GPIO_BASE = 0x40020000; #Conf = "PB06:AF10:V, PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V"; # w/ cmspi #$Conf = "PB06:PP:M, PB02:PP:V, PD13:INUP:V, PE02:INUP:V, PD12:INUP:V, PD11:INUP:V"; # stm32f769i-disco quad #$GPIO_BASE = 0x40020000; #$Conf = "PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V"; # w/ cmspi #$Conf = "PB06:PP:M, PB02:PP:V, PD13:INUP:V, PE02:INUP:V, PC10:INUP:V, PC09:INUP:V, "; # b-l475e-iot01a quad #$GPIO_BASE = 0x48000000; #$Conf = "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V"; # stm32l476g-disco quad #$GPIO_BASE = 0x48000000; #$Conf = "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V"; # stm32l496g-disco quad #$GPIO_BASE = 0x48000000; #$Conf = "PA07:AF10:V, PA06:AF10:V, PA03:AF10:V, PB11:AF10:V, PB01:AF10:V, PB00:AF10:V"; # stm32l4r9i-disco octal #$GPIO_BASE = 0x48000000; #$Conf = "PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PH10:AF05:V, PH09:AF05:V, " # . "PH08:AF05:V, PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V"; # stm32l4p5g-disco octal/octal #$GPIO_BASE = 0x48000000; #$Conf = "PA07:AF10:V, PA06:AF10:V, PC03:AF10:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V, " # . "PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V, PG06:AF03:V"; #$Conf = "PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V, " # . "PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V"; # nucleo-f767zi dual quad #$GPIO_BASE = 0x40020000; #$Conf = "PB06:AF10:V, PB02:AF09:V, PC11:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, " # . "PD11:AF09:V, PE10:AF10:V, PE09:AF10:V, PE08:AF10:V, PE07:AF10:V"; # w/ cmspi #$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V"; #$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PE09:INPUP:V, PE08:INPUP:V, PE07:INPUP:V"; # nucleo-h743zi dual quad #$GPIO_BASE = 0x58020000; #$Conf = "PB10:AF09:V, PB02:AF09:V, PC11:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, " # . "PD11:AF09:V, PE10:AF10:V, PE09:AF10:V, PE08:AF10:V, PE07:AF10:V"; # w/ cmspi #$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V"; #$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PE09:INPUP:V, PE08:INPUP:V, PE07:INPUP:V"; # nucleo-h7a3zi dual quad #$GPIO_BASE = 0x58020000; #$Conf = "PB10:AF09:V, PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V, " # . "PC11:AF09:V, PE10:AF10:V, PD06:AF10:V, PE08:AF10:V, PE07:AF10:V"; # w/ cmspi #$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V"; #$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PD06:INPUP:V, PE08:INPUP:V, PE07:INPUP:V"; # nucleo-l4r5zi one dual quad single NCS #$GPIO_BASE = 0x48000000; #$Conf = "PA02:AF10:V, PE10:AF10:V, PD07:AF10:V, PD06:AF10:V, PD05:AF10:V, PD04:AF10:V, " # . "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V"; # w/ cmspi #$Conf = "PA02:PPUP:M, PE10:PPUP:V, PD07:INPDO:V, PD06:INPDO:V, PD05:INPDO:V, PD04:INPDO:V"; #$Conf = "PA02:PPUP:M, PE10:PPUP:V, PE15:INPDO:V, PE14:INPDO:V, PE13:INPDO:V, PE12:INPDO:V"; # nucleo-l552ze-q dual quad with single NCS #$GPIO_BASE = 0x42020000; #$Conf = "PA02:AF10:V, PE10:AF10:V, PD07:AF10:V, PD06:AF10:V, PD05:AF10:V, PD04:AF10:V, " # . "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V"; # w/ cmspi #$Conf = "PA02:PPUP:M, PE10:PPUP:V, PD07:INPDO:V, PD06:INPDO:V, PD05:INPDO:V, PD04:INPDO:V"; #$Conf = "PA02:PPUP:M, PE10:PPUP:V, PE15:INPDO:V, PE14:INPDO:V, PE13:INPDO:V, PE12:INPDO:V"; # nucleo-g071rb dual quad #$GPIO_BASE = 0x50000000; #$Conf = "PA00:PPUP:H, PA04:PPUP:V, PB03:INPUP:V, PA10:INPUP:V, PB11:INPUP:H, PB01:INPUP:H"; #$Conf = "PA01:PPUP:H, PA04:PPUP:V, PA08:INPUP:V, PB14:INPUP:V, PB04:INPUP:V, PB05:INPUP:V"; # nucleo-g474re dual quad with single NCS #$GPIO_BASE = 0x48000000; #$Conf = "PB11:AF10:H, PB10:AF10:V, PA06:AF10:V, PA07:AF10:V, PB00:AF10:V, PB01:AF10:V, " # . "PC04:AF10:V, PC03:AF10:V, PC02:AF10:V, PC01:AF10:V"; # w/ cmspi #$Conf = "PB11:PPUP:H, PB10:PPUP:V, PA06:INPUP:V, PA07:INPUP:V, PB00:INPUP:V, PB01:INPUP:V"; #$Conf = "PB11:PPUP:H, PB10:PPUP:V, PC04:INPUP:V, PC03:INPUP:V, PC02:INPUP:V, PC01:INPUP:V"; # stm32h745i-disco dual quad with single NCS #$GPIO_BASE = 0x58020000; #$Conf = "PG06:AF10:H, PF10:AF09:V, PF06:AF09:V, PF07:AF09:V, PF09:AF10:V, PD11:AF09:V, " # . "PG14:AF09:H, PG09:AF09:V, PH03:AF09:V, PH02:AF09:V"; # stm32h747i-disco dual quad with single NCS #GPIO_BASE = 0x58020000; #$Conf = "PG06:AF10:H, PB02:AF09:V, PF06:AF09:V, PF07:AF09:V, PF09:AF10:V, PD11:AF09:V, " # . "PG14:AF09:H, PG09:AF09:V, PH03:AF09:V, PH02:AF09:V"; # stm32h7b3i-disco octal #$GPIO_BASE = 0x58020000; #$Conf = "PG06:AF10:V, PB02:AF09:V, PC05:AF10:V, PD07:AF10:V, PG09:AF09:V, PH03:AF09:V, PC01:AF10:V, " # . "PF06:AF10:V, PF07:AF10:V, PF09:AF10:V, PD11:AF09:V"; # stm32h735g-disco octal #$GPIO_BASE = 0x58020000; #$Conf = "PG06:AF10:V, PF10:AF09:V, PB02:AF10:V, PD07:AF10:V, PG09:AF09:V, PD05:AF10:V, PD04:AF10:V, " # . "PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V"; # stm32l562e-disco octal #$GPIO_BASE = 0x42020000; #$Conf = "PA02:AF10:V, PA03:AF10:V, PB02:AF10:V, PC00:AF03:V, PC03:AF10:V, PC02:AF10:V, PC01:AF10:V, " # . "PA06:AF10:V, PA07:AF10:V, PB00:AF10:V, PB01:AF10:V"; &getopts('b:c:f:t'); if ($Getopt::Std::opt_b eq '') { if ($GPIO_BASE eq '') { die("usage: $0 [ -1 ] -b io_base [ -c port_configuration ] [ -f conf_file ]"); } } else { $GPIO_BASE = eval $Getopt::Std::opt_b; } if ($Getopt::Std::opt_c eq '') { if (($Conf eq '') && ($Getopt::Std::opt_f eq '')) { die("usage: $0 [ -b io_base ] ( -c port_configuration | -f conf_file )"); } }# else { $Conf = $Getopt::Std::opt_c . ','; } $STM32F1 = $Getopt::Std::opt_t; my $Sep = "\t"; my $Form = "${Sep}mmw 0x%08X 0x%08X 0x%08X\t;# "; my $GPIO_OFFS; my $GPIO_CRL; my $GPIO_CRH; my $GPIO_MODER; my $GPIO_OTYPER; my $GPIO_OSPEEDR; my $GPIO_PUPDR; my $GPIO_IDR; my $GPIO_ODR; my $GPIO_AFRL; my $GPIO_AFRH; if ($STM32F1) { # offsets for F1 devices $GPIO_OFFS = 0x400; $GPIO_CRL = 0x00; $GPIO_CRH = 0x04; $GPIO_IDR = 0x08; $GPIO_ODR = 0x0C; } else { # these offsets are identical on all F0, F4, F7, H7, L4, L4+ devices up to now $GPIO_OFFS = 0x400; $GPIO_MODER = 0x00; $GPIO_OTYPER = 0x04; $GPIO_OSPEEDR = 0x08; $GPIO_PUPDR = 0x0C; $GPIO_IDR = 0x10; $GPIO_ODR = 0x14; $GPIO_AFRL = 0x20; $GPIO_AFRH = 0x24; } my @Out = ( { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { } ); my @Port = ( ); my $Exor; my %Conf; my $Pins = "${Sep}#"; my $pins; my $altn; my %defs; if ($Getopt::Std::opt_f ne '') { open(CONF_FILE, '<', $Getopt::Std::opt_f) || die("can't open $Getopt::Std::opt_f"); while (my $line = ) { if ($line =~ /^\s*#define\s+.?(QSPI|QUAD_?SPI|OCTOSPI[^_]*)\w+_(Port|Pin)\s/) { if ($line =~ /#define\s+(\w+)\s+(\w+)/) { $defs{$1} = $2; } else { die($line); } } elsif ($line =~ /^\s*(P[A-Z])([0-9]+)\s*-+>\s+.?(QSPI|QUAD_?SPI|OCTO_?SPI[^_]*)_(\w+)/) { $Conf{$4} = sprintf("%s%02d", $1, $2); } elsif ($line =~ /^\s*GPIO_InitStruct.Pin\s*=\s*([^;]+\w)/) { $pins = $1; while ($line !~ /;/) { $line = ; $line =~ /^\s*([^;]+\w)/; $pins .= $1; } } elsif ($line =~ /^\s*GPIO_InitStruct.Alternate\s*=\s*GPIO_AF([0-9]+)/) { $altn = $1; } elsif ($line =~ /^\s*HAL_GPIO_Init\s*\(\s*(\w+)\s*,/) { my $port = $1; if ($port =~ /GPIO([A-Z])/) { $port = $1; } elsif (exists($defs{$port})) { $defs{$port} =~ /GPIO([A-Z])/; $port = $1; } else { printf("\n"); next; } my @pin = split(/\s*\|\s*/, $pins); foreach my $pin (@pin) { my $bit; if (exists($defs{$pin})) { $defs{$pin} =~ /GPIO_PIN_([0-9]+)/; $bit = $1; } else { $pin =~ /GPIO_PIN_([0-9]+)/; $bit = $1; } $Conf .= sprintf("P%s%02d:AF%02d:V, ", $port, $bit, $altn); } $pins = ''; $altn = 0; } } close(CONF_FILE); } else { my @names = ( ); my @conf = split(/\s*,\s*/, $Conf); if (@conf == 2) { push(@names, 'SDA', 'SCL'); } else { if (@conf == 3) { push(@names, 'NCS', 'CLK', 'IO0/DIO'); } elsif (@conf == 4) { push(@names, 'NCS', 'CLK','IO1/MISO', 'IO0/MOSI'); } elsif (@conf == 6) { push(@names, 'NCS', 'CLK', 'IO3/NHOLD', 'IO2/NWP', 'IO1/MISO', 'IO0/MOSI'); } elsif (@conf == 10) { push(@names, 'NCS', 'CLK', 'BK_1_IO3/NHOLD', 'BK1_IO2/NWP', 'BK1_IO1/MISO', 'BK1_IO0/MOSI'); push(@names, 'BK_2_IO3/NHOLD', 'BK2_IO2/NWP', 'BK2_IO1/MISO', 'BK2_IO0/MOSI'); } elsif (@conf == 11) { push(@names, 'BK_1_NCS', 'CLK', 'BK_1_IO3/NHOLD', 'BK1_IO2/NWP', 'BK1_IO1/MISO', 'BK1_IO0/MOSI'); push(@names, 'BK_2_NCS', 'BK_2_IO3/NHOLD', 'BK2_IO2/NWP', 'BK2_IO1/MISO', 'BK2_IO0/MOSI'); } else { die("invalid config"); } } for (my $index = 0; $index < @conf; $index++) { uc($conf[$index]) =~ /^P([A-K])([0-9]+):\s*([A-Z0-9]+):(L|M|H|V)$/; $Pins .= sprintf(" %s: P%s%02d,", $names[$index], $1, $2); } chop($Pins); } if (exists $Conf{'BK1_IO0'}) { # QuadSPI on F4, F7, H7 my $line; for my $i ('NCS', 'BK1_NCS', 'CLK', 'BK1_IO3', 'BK1_IO2', 'BK1_IO1', 'BK1_IO0') { (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i)); } } if (exists $Conf{'BK2_IO0'}) { # QuadSPI on F4, F7, H7 my $line; for my $i ('NCS', 'BK2_NCS', 'CLK', 'BK2_IO3', 'BK2_IO2', 'BK2_IO1', 'BK2_IO0') { (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i)); } } if (exists $Conf{'P1_IO0'}) { # OctoSPI on L4+, L5, H7 my $line; for my $i ('P1_NCS', 'P1_CLK', 'P1_DQS', 'P1_IO7', 'P1_IO6', 'P1_IO5', 'P1_IO4', 'P1_IO3', 'P1_IO2', 'P1_IO1', 'P1_IO0') { (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i)); } } if (exists $Conf{'P2_IO0'}) { # OctoSPI on L4+, H7 my $line; for my $i ('P2_NCS', 'P2_CLK', 'P2_DQS', 'P2_IO7', 'P2_IO6', 'P2_IO5', 'P2_IO4', 'P2_IO3', 'P2_IO2', 'P2_IO1', 'P2_IO0') { (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i)); } } my @Col = ( ); my @conf = split(/\s*,\s*/, $Conf); if (@conf == 3) { splice(@conf, 2, 0, 'NONE', 'NONE', 'NONE'); } elsif (@conf == 4) { splice(@conf, 2, 0, 'NONE', 'NONE'); } foreach my $line (@conf) { $line = uc($line); $line =~ /^P([A-K])([0-9]+):\s*([A-Z0-9]+):(L|M|H|V)$/; my $port = $1; my $pin = $2; my $conf = $3; my $speed = $4; my $MODER = 0x0; my $OTYPER = 0x0; my $OSPEEDR = 0x0; my $PUPDR = 0x0; my $AFR = 0x0; my $num = ord(${port}) - ord('A'); my $out = $Out[$num]; (exists $$out{'DEF'}) || ($$out{'DEF'} = 0); if ($conf eq '') { if ($line ne 'NONE') { printf(STDERR "invalid conf %s\n", $line); } next; } elsif ($conf =~ /^AF([0-9]+)(|P|O)(|UP|DO)$/) { if ($STM32F1) { printf(STDERR "no alternate %s for F1 family\n", $line); next; } if (($1 < 0) || ($1 > 15)) { printf(STDERR "invalid alternate %s\n", $line); next; } $MODER = 0x2; $AFR = $1; if ($pin <= 7) { $$out{'AFRL_H'} |= ($AFR << (${pin} << 2)); $$out{'AFRL_L'} |= (($AFR ^ 0xF) << (${pin} << 2)); } else { $$out{'AFRH_H'} |= ($AFR << ((${pin} - 8) << 2)); $$out{'AFRH_L'} |= (($AFR ^ 0xF) << ((${pin} - 8) << 2)); } if ($2 ne '') { $OTYPER = ($1 eq 'O') ? 0x1 : 0x0; $$out{'OTYPER_H'} |= ($OTYPER << $pin); $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin); } $PUPDR = ($3 eq 'UP') ? 0x1 : (($3 eq 'DO') ? 0x2 : 0x0); $$out{'PUPDR_H'} |= ($PUPDR << (${pin} << 1)); $$out{'PUPDR_L'} |= (($PUPDR ^0x3) << (${pin} << 1)); $conf = sprintf("AF%02d%s%s", $AFR, $2, $3); } elsif ($conf =~ /^IN(|P|O)(|UP|DO)$/) { if ($STM32F1) { $MODER = ($1 eq '') ? 0x4 : 0x8; ($2 eq 'UP') && ($$out{'PUPDR_H'} |= (1 << ${pin})); ($2 eq 'DO') && ($$out{'PUPDR_L'} |= (1 << ${pin})); } else { $MODER = 0x0; if ($1 ne '') { $OTYPER = ($1 eq 'O') ? 0x1 : 0x0; $$out{'OTYPER_H'} |= ($OTYPER << $pin); $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin); } $PUPDR = ($2 eq 'UP') ? 0x1 : (($2 eq 'DO') ? 0x2 : 0x0); $$out{'PUPDR_H'} |= ($PUPDR << (${pin} << 1)); $$out{'PUPDR_L'} |= (($PUPDR ^0x3) << (${pin} << 1)); } ($2 eq 'UP') && ($$out{'ODR_H'} |= (1 << ${pin})); ($2 eq 'DO') && ($$out{'ODR_L'} |= (1 << ${pin})); } elsif ($conf =~ /^P(P|O)(|UP|DO)$/) { if ($STM32F1) { $MODER = ($1 eq 'O') ? 0x4 : 0x0; $MODER |= (($speed eq 'V') ? 0x03 : (($speed eq 'L') ? 0x2 : 0x1)); if ($2 ne '') { printf(STDERR "WARNING: no output w/ pull-up/pull-down for F1 family %s\n", $line); } } else { $MODER = 0x1; $OTYPER = ($1 eq 'O') ? 0x1 : 0x0; $$out{'OTYPER_H'} |= ($OTYPER << $pin); $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin); $PUPDR = ($2 eq 'UP') ? 0x1 : (($2 eq 'DO') ? 0x2 : 0x0); $$out{'PUPDR_H'} |= ($PUPDR << ($pin << 1)); $$out{'PUPDR_L'} |= (($PUPDR ^ 0x3) << ($pin << 1)); } ($2 eq 'UP') && ($$out{'ODR_H'} |= (1 << ${pin})); ($2 eq 'DO') && ($$out{'ODR_L'} |= (1 << ${pin})); } else { printf(STDERR "invalid conf %s\n", $line); next; } if ($$out{'DEF'} & (1<< ${pin})) { printf(STDERR "redefinition: %s\n", $line); } if ($STM32F1) { if ($pin >= 8) { $$out{'CRH_H'} |= ($MODER << (($pin & 0x7) << 2)); $$out{'CRH_L'} |= (($MODER ^ 0xF) << (($pin & 0x7) << 2)); } else { $$out{'CRL_H'} |= ($MODER << (($pin & 0x7) << 2)); $$out{'CRL_L'} |= (($MODER ^ 0xF) << (($pin & 0x7) << 2)); } $Exor = sprintf("0x%08X %2d", ${GPIO_BASE} + (ord($port) - ord('A')) * ${GPIO_OFFS} + ${GPIO_ODR}, $pin); my $exor = 0xB << (($pin & 0x7) << 2); (($MODER & 0x3) == 0x0) && ($Exor .= sprintf(" 0x%03X 0x%03X 0x%08X", ((($pin >= 8) ? ${GPIO_CRH} : ${GPIO_CRL})-${GPIO_ODR}) & 0x3FF, ((($pin >= 8) ? ${GPIO_CRH} : ${GPIO_CRL})-${GPIO_ODR}) & 0x3FF, $exor)); } else { $$out{'DEF'} |= (1 << ${pin}); $$out{'MODER_H'} |= ($MODER << (${pin} << 1)); $$out{'MODER_L'} |= (($MODER ^ 0x3) << (${pin} << 1)); $OSPEEDR = (($speed eq 'V') ? 0x3 : (($speed eq 'H') ? 0x2 : (($speed eq 'M') ? 0x1 : 0x0))); $$out{'OSPEEDR_H'} |= ($OSPEEDR << (${pin} << 1)); $$out{'OSPEEDR_L'} |= (($OSPEEDR ^ 0x3) << (${pin} << 1)); $Exor = sprintf("0x%08X %2d", ${GPIO_BASE} + (ord($port) - ord('A')) * ${GPIO_OFFS} + ${GPIO_ODR}, $pin); my $exor = (0x1 << ($pin << 1)); ($MODER == 0x0) && ($Exor .= sprintf(" 0x%03X 0x%03X 0x%08X", (${GPIO_MODER}-${GPIO_ODR}) & 0x3FF, (${GPIO_MODER}-${GPIO_ODR}) & 0x3FF, $exor)); } push(@{$Port[$num]}, sprintf("P%s%02d:%s:%s", $port, $pin, $conf, $speed)); push(@Col, $Exor); } my $Col = sprintf("${Sep}0x%03X ", (${GPIO_IDR}-${GPIO_ODR}) & 0x3FF); for (my $i = 0; $i < @Col; $i++) { if (($i != 0) && (($i % 2) == 0)) { (($i + 1) < @Col) && ($Col .= "\\\n${Sep}"); } $Col .= sprintf("%s ", $Col[$i]); } printf("%s\n", $Col); my @Col = ( ); my $Set; for (my $i = 0; $i < @Out; $i++) { my $out = $Out[$i]; my $addr = ${GPIO_BASE} + $i * ${GPIO_OFFS}; my $count = 0; if ($STM32F1) { if (($$out{'CRH_H'} | $$out{'CRH_L'} | $$out{'CRL_H'} | $$out{'CRL_L'} | $$out{'PUPDR_H'} | $$out{'PUPDR_L'}) != 0) { push(@Col, sort({ $b cmp $a } @{$Port[$i]})); $Set .= sprintf("\n%s# Port %s: %s\n", ${Sep}, chr($i + ord('A')), join(", ", sort({ $b cmp $a } @{$Port[$i]}))); (($$out{'CRL_H'} | $$out{'CRL_L'}) != 0) && ($Set .= sprintf("${Form}CRL\n", $addr + ${GPIO_CRL}, $$out{'CRL_H'}, $$out{'CRL_L'})); (($$out{'CRH_H'} | $$out{'CRH_L'}) != 0) && ($Set .= sprintf("${Form}CRH\n", $addr + ${GPIO_CRH}, $$out{'CRH_H'}, $$out{'CRH_L'})); (($$out{'ODR_H'} | $$out{'ODR_L'}) != 0) && ($Set .= sprintf("${Form}ODR/PUPDR\n", $addr + ${GPIO_ODR}, $$out{'ODR_H'}, $$out{'ODR_L'})); } } else { if (($$out{'MODER_H'} | $$out{'MODER_L'} | $$out{'OTYPER_H'} | $$out{'OTYPER_L'} | $$out{'OSPEEDR_H'} | $$out{'OSPEEDR_L'} | $$out{'PUPDR_H'} | $$out{'PUPDR_L'} | $$out{'ODR_H'} | $$out{'ODR_L'} | $$out{'AFRL_H'} | $$out{'AFRL_L'} | $$out{'AFRH_H'} | $$out{'AFRH_L'}) != 0) { push(@Col, sort({ $b cmp $a } @{$Port[$i]})); $Set .= sprintf("%s# Port %s: %s\n", ${Sep}, chr($i + ord('A')), join(", ", sort({ $b cmp $a } @{$Port[$i]}))); (($$out{'MODER_H'} | $$out{'MODER_L'}) != 0) && ($Set .= sprintf("${Form}MODER\n", $addr + ${GPIO_MODER}, $$out{'MODER_H'}, $$out{'MODER_L'})); (($$out{'OTYPER_H'} | $$out{'OTYPER_L'}) != 0) && ($Set .= sprintf("${Form}OTYPER\n", $addr + ${GPIO_OTYPER}, $$out{'OTYPER_H'}, $$out{'OTYPER_L'})); (($$out{'OSPEEDR_H'} | $$out{'OSPEEDR_L'}) != 0) && ($Set .= sprintf("${Form}OSPEEDR\n", $addr + ${GPIO_OSPEEDR}, $$out{'OSPEEDR_H'}, $$out{'OSPEEDR_L'})); (($$out{'PUPDR_H'} | $$out{'PUPDR_L'}) != 0) && ($Set .= sprintf("${Form}PUPDR\n", $addr + ${GPIO_PUPDR}, $$out{'PUPDR_H'}, $$out{'PUPDR_L'})); (($$out{'ODR_H'} | $$out{'ODR_L'}) != 0) && ($Set .= sprintf("${Form}ODR\n", $addr + ${GPIO_ODR}, $$out{'ODR_H'}, $$out{'ODR_L'})); (($$out{'AFRL_H'} | $$out{'AFRL_L'}) != 0) && ($Set .= sprintf("${Form}AFRL\n", $addr + ${GPIO_AFRL}, $$out{'AFRL_H'}, $$out{'AFRL_L'})); (($$out{'AFRH_H'} | $$out{'AFRH_L'}) != 0) && ($Set .= sprintf("${Form}AFRH\n", $addr + ${GPIO_AFRH}, $$out{'AFRH_H'}, $$out{'AFRH_L'})); } } } my $Col = ''; for (my $i = 0; $i < @Col; $i++) { if (($i % 6) == 0) { chop($Col); (($i + 1) < @Col) && ($Col .= "\n${Sep}#"); } $Col .= sprintf(" %s,", $Col[$i]); } chop($Col); #printf("\n%s\n", $Pins); printf("%s\n", $Col); printf("%s\n", $Set); ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stmqspi/stmoctospi_crc32.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * ***************************************************************************/ .text .syntax unified .cpu cortex-m0 .thumb .thumb_func /* Params: * r0 - total count (bytes), crc32 (out) * r1 - flash page size * r2 - address offset into flash * r3 - OCTOSPI io_base * Clobbered: * r4 - tmp * r5 - address of OCTOSPI_DR * r6 - address of OCTOSPI_CCR * r7 - tmp */ #include "../../../../src/flash/nor/stmqspi.h" #define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR) #define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR) #define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR) .macro octospi_abort movs r5, #(1< CRC32XOR, pos. -> 0x0 */ lsls r4, r4, #1 /* shift result */ eors r4, r4, r7 /* eor by CRC32XOR or 0x0 */ .endr adds r2, r2, #1 /* increment address */ subs r0, r0, #1 /* decrement (count-1) */ bmi exit /* stop if no data left */ tst r2, r1 /* page end ? */ bne read_loop /* if not, then next byte */ page_end: bal start_read /* then next page */ .pool exit: mvns r0, r4 /* invert to get final result */ octospi_abort /* to idle state */ .align 2 /* align to word, bkpt is 4 words */ bkpt #0 /* before code end for exit_point */ .align 2 /* align to word */ cr_page_read: .space 4 /* OCTOSPI_CR value for read command */ ccr_page_read: .space 4 /* OCTOSPI_CCR value for read command */ tcr_page_read: .space 4 /* OCTOSPI_TCR value for read command */ ir_page_read: .space 4 /* OCTOSPI_IR value for read command */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x01,0x38,0x01,0x39,0x00,0x24,0xe4,0x43,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60, 0x50,0x25,0xed,0x18,0xb0,0x26,0x76,0x19,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27, 0x5f,0x62,0x22,0x4f,0x1f,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9, 0x07,0x46,0x1f,0x64,0x1e,0x4f,0x37,0x60,0x1e,0x4f,0xb7,0x60,0x1e,0x4f,0x37,0x61, 0x9a,0x64,0x15,0x4e,0x2f,0x78,0x3f,0x06,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00, 0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00, 0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00, 0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00, 0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0x01,0x32,0x01,0x38,0x05,0xd4, 0x0a,0x42,0xd7,0xd1,0xb8,0xe7,0x00,0x00,0xb7,0x1d,0xc1,0x04,0xe0,0x43,0x02,0x25, 0x1f,0x68,0x2f,0x43,0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * ***************************************************************************/ .text .syntax unified .cpu cortex-m0 .thumb .thumb_func /* Params: * r0 - sector count * r1 - QSPI io_base * Clobbered: * r2 - r7 tmp */ #include "../../../../src/flash/nor/stmqspi.h" #define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR) #define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR) #define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR) .macro octospi_abort movs r5, #(1< CRC32XOR, pos. -> 0x0 */ lsls r4, r4, #1 /* shift result */ eors r4, r4, r7 /* eor by CRC32XOR or 0x0 */ .endr adds r2, r2, #1 /* increment address */ subs r0, r0, #1 /* decrement (count-1) */ bmi exit /* stop if no data left */ tst r2, r1 /* page end ? */ bne read_loop /* if not, then next byte */ page_end: bal start_read /* then next page */ .pool exit: mvns r0, r4 /* invert to get final result */ qspi_abort /* to idle state */ .align 2 /* align to word, bkpt is 4 words */ bkpt #0 /* before code end for exit_point */ .align 2 /* align to word */ .space 4 /* not used */ ccr_page_read: .space 4 /* QSPI_CCR value for read command */ .space 4 /* not used */ .space 4 /* not used */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stmqspi/stmqspi_crc32.inc ================================================ /* Autogenerated with ../../../../src/helper/bin2char.sh */ 0x01,0x38,0x01,0x39,0x00,0x24,0xe4,0x43,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60, 0x20,0x25,0xed,0x18,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x17,0x46, 0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,0x1f,0x61,0x1c,0x4f,0x5f,0x61, 0x9a,0x61,0x9f,0x68,0x14,0x4e,0x2f,0x78,0x3f,0x06,0x7c,0x40,0xe7,0x17,0x37,0x40, 0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40, 0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40, 0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40, 0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0x01,0x32,0x01,0x38, 0x04,0xd4,0x0a,0x42,0xd7,0xd1,0xbf,0xe7,0xb7,0x1d,0xc1,0x04,0xe0,0x43,0x02,0x25, 0x1f,0x68,0x2f,0x43,0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/flash/stmqspi/stmqspi_erase_check.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * ***************************************************************************/ .text .syntax unified .cpu cortex-m0 .thumb .thumb_func /* Params: * r0 - sector count * r1 - QSPI io_base * Clobbered: * r2 - r7 tmp */ #include "../../../../src/flash/nor/stmqspi.h" .macro qspi_abort movs r4, #(1< $@" $(Q) $(CROSS)gcc -c $(CFLAGS) -o $@ $^ $(APP_CODE): $(APP_OBJ) @echo " CC $^ -> $@" $(Q) $(CROSS)objcopy -O binary -j.text $^ $(APP_BIN) $(Q) $(BIN2C) < $(APP_BIN) > $@ clean: $(Q) rm -rf $(BUILD_DIR) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/reset/espressif/esp32/cpu_reset_handler_code.inc ================================================ /* Autogenerated with ../../../../../src/helper/bin2char.sh */ 0x06,0x1e,0x00,0x00,0x06,0x14,0x00,0x00,0x34,0x80,0xf4,0x3f,0xb0,0x80,0xf4,0x3f, 0xb4,0x80,0xf4,0x3f,0x70,0x80,0xf4,0x3f,0x10,0x22,0x00,0x00,0x00,0x20,0x49,0x9c, 0x00,0x80,0xf4,0x3f,0xa1,0x3a,0xd8,0x50,0xa4,0x80,0xf4,0x3f,0x64,0xf0,0xf5,0x3f, 0x64,0x00,0xf6,0x3f,0x8c,0x80,0xf4,0x3f,0x48,0xf0,0xf5,0x3f,0x48,0x00,0xf6,0x3f, 0xfc,0xa1,0xf5,0x3f,0x38,0x00,0xf0,0x3f,0x30,0x00,0xf0,0x3f,0x2c,0x00,0xf0,0x3f, 0x34,0x80,0xf4,0x3f,0x00,0x30,0x00,0x00,0x50,0x55,0x30,0x41,0xeb,0xff,0x59,0x04, 0x41,0xeb,0xff,0x59,0x04,0x41,0xea,0xff,0x59,0x04,0x41,0xea,0xff,0x31,0xea,0xff, 0x39,0x04,0x31,0xea,0xff,0x41,0xea,0xff,0x39,0x04,0x00,0x00,0x60,0xeb,0x03,0x60, 0x61,0x04,0x56,0x66,0x04,0x50,0x55,0x30,0x31,0xe7,0xff,0x41,0xe7,0xff,0x39,0x04, 0x41,0xe7,0xff,0x39,0x04,0x41,0xe6,0xff,0x39,0x04,0x41,0xe6,0xff,0x59,0x04,0x41, 0xe6,0xff,0x59,0x04,0x41,0xe6,0xff,0x59,0x04,0x41,0xe5,0xff,0x59,0x04,0x41,0xe5, 0xff,0x59,0x04,0x41,0xe5,0xff,0x0c,0x13,0x39,0x04,0x41,0xe4,0xff,0x0c,0x13,0x39, 0x04,0x59,0x04,0x41,0xe3,0xff,0x31,0xe3,0xff,0x32,0x64,0x00,0x00,0x70,0x00,0x46, 0xfe,0xff, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/reset/espressif/esp32/esp32_cpu_reset_handler.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Reset stub used by esp32 target * * Copyright (C) 2017 Espressif Systems Ltd. * ***************************************************************************/ #define RTC_CNTL_RESET_STATE_REG 0x3ff48034 #define RTC_CNTL_RESET_STATE_DEF 0x3000 #define RTC_CNTL_CLK_CONF_REG 0x3ff48070 #define RTC_CNTL_CLK_CONF_DEF 0x2210 #define RTC_CNTL_STORE4_REG 0x3ff480b0 #define RTC_CNTL_STORE5_REG 0x3ff480b4 #define WDT_WKEY_VALUE 0x50D83AA1 #define TIMG0_WDTWPROTECT_REG 0x3ff5f064 #define TIMG0_WDTCONFIG0_REG 0x3ff5f048 #define TIMG1_WDTWPROTECT_REG 0x3FF60064 #define TIMG1_WDTCONFIG0_REG 0x3ff60048 #define RTC_CNTL_WDTCONFIG0_REG 0x3ff4808c #define RTC_CNTL_WDTWPROTECT_REG 0x3ff480a4 #define JTAG_ENABLE_REG 0x3ff5a1fc #define RTC_CNTL_OPTIONS0_REG 0x3ff48000 #define RTC_CNTL_OPTIONS0_DEF 0x1c492000 #define RTC_CNTL_SW_SYS_RST 0x80000000 #define DPORT_APPCPU_CTRL_A_REG 0x3ff0002c #define DPORT_APPCPU_RST_EN 0x1 #define DPORT_APPCPU_CTRL_B_REG 0x3ff00030 #define DPORT_APPCPU_CLKGATE_EN 0x1 #define DPORT_APPCPU_CTRL_C_REG 0x3ff00034 #define DPORT_APPCPU_CTRL_D_REG 0x3ff00038 /* This stub is copied to RTC_SLOW_MEM by OpenOCD, and the CPU starts executing * it instead of the ROM code (0x40000400). This stub disables watchdogs and * goes into a loop. * OpenOCD will then halt the target and perform CPU reset using OCD. */ /* Has to be at offset 0. This is the entry point of the CPU, once * RTC_CNTL_PROCPU_STAT_VECTOR_SEL is cleared. * CPU will come here after the system reset, triggered by RTC_CNTL_SW_SYS_RST. */ .global cpu_at_start_handler .type cpu_at_start_handler,@function .align 4 cpu_at_start_handler: j start /* Has to be at offset 4. Once the stub code has been uploaded into RTC Slow * memory, OpenOCD will set the PC to this address, and resume execution. * The stub will then jump to 'reset' label and perform the reset. */ .global cpu_reset_handler .type cpu_reset_handler,@function .align 4 cpu_reset_handler: j reset .align 4 .literal_position .align 4 reset: /* Use a5 as a zero register */ xor a5, a5, a5 /* Select static reset vector 0 (XCHAL_RESET_VECTOR0_VADDR, 0x50000000) */ movi a4, RTC_CNTL_RESET_STATE_REG s32i a5, a4, 0 /* Set some clock-related RTC registers to the default values */ movi a4, RTC_CNTL_STORE4_REG s32i a5, a4, 0 movi a4, RTC_CNTL_STORE5_REG s32i a5, a4, 0 movi a4, RTC_CNTL_CLK_CONF_REG movi a3, RTC_CNTL_CLK_CONF_DEF s32i a3, a4, 0 /* Reset the digital part of the chip (RTC controller doesn't get reset) */ movi a3, (RTC_CNTL_OPTIONS0_DEF | RTC_CNTL_SW_SYS_RST) movi a4, RTC_CNTL_OPTIONS0_REG s32i a3, a4, 0 /* Doesn't reach beyond this instruction */ .align 4 start: /* If running on the APP CPU, skip directly to the parking loop */ rsr.prid a6 extui a6, a6, 1, 1 bnez a6, parking_loop /* Use a5 as a zero register */ xor a5, a5, a5 /* Disable the watchdogs */ movi a3, WDT_WKEY_VALUE movi a4, RTC_CNTL_WDTWPROTECT_REG s32i.n a3, a4, 0 movi a4, TIMG0_WDTWPROTECT_REG s32i.n a3, a4, 0 movi a4, TIMG1_WDTWPROTECT_REG s32i.n a3, a4, 0 movi a4, RTC_CNTL_WDTCONFIG0_REG s32i.n a5, a4, 0 movi a4, TIMG0_WDTCONFIG0_REG s32i.n a5, a4, 0 movi a4, TIMG1_WDTCONFIG0_REG s32i.n a5, a4, 0 /* Enable JTAG (needed since rev. 3) */ movi a4, JTAG_ENABLE_REG s32i.n a5, a4, 0 /* Clear APP_CPU boot address */ movi a4, DPORT_APPCPU_CTRL_D_REG s32i.n a5, a4, 0 /* Clear APP_CPU clock gating */ movi a4, DPORT_APPCPU_CTRL_B_REG movi a3, DPORT_APPCPU_CLKGATE_EN s32i.n a3, a4, 0 /* Set and clear APP_CPU reset */ movi a4, DPORT_APPCPU_CTRL_A_REG movi a3, DPORT_APPCPU_RST_EN s32i.n a3, a4, 0 s32i.n a5, a4, 0 /* Restore the reset vector to ROM */ movi a4, RTC_CNTL_RESET_STATE_REG movi a3, RTC_CNTL_RESET_STATE_DEF s32i.n a3, a4, 0 parking_loop: /* PRO and APP CPU will be in this loop, until OpenOCD * finds the JTAG taps and puts the CPUs into debug mode. */ waiti 0 j parking_loop ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/reset/espressif/esp32s3/cpu_reset_handler_code.inc ================================================ /* Autogenerated with ../../../../../src/helper/bin2char.sh */ 0x06,0x23,0x00,0x00,0x06,0x18,0x00,0x00,0x38,0x80,0x00,0x60,0xc0,0x80,0x00,0x60, 0xc4,0x80,0x00,0x60,0x90,0x80,0x00,0x60,0x74,0x80,0x00,0x60,0x18,0x32,0x58,0x01, 0x00,0xa0,0x00,0x9c,0x00,0x80,0x00,0x60,0xa1,0x3a,0xd8,0x50,0xac,0x80,0x00,0x60, 0x64,0xf0,0x01,0x60,0x64,0x00,0x02,0x60,0x94,0x80,0x00,0x60,0x48,0xf0,0x01,0x60, 0x48,0x00,0x02,0x60,0xb4,0x80,0x00,0x60,0x2a,0x31,0x1d,0x8f,0xb0,0x80,0x00,0x60, 0x00,0x00,0xb0,0x84,0x04,0x00,0x0c,0x60,0x00,0x00,0x0c,0x60,0x00,0x00,0x0c,0x60, 0x38,0x80,0x00,0x60,0x00,0x30,0x00,0x00,0x50,0x55,0x30,0x41,0xe7,0xff,0x59,0x04, 0x41,0xe7,0xff,0x59,0x04,0x41,0xe6,0xff,0x59,0x04,0x41,0xe6,0xff,0x59,0x04,0x41, 0xe6,0xff,0x31,0xe6,0xff,0x39,0x04,0x31,0xe6,0xff,0x41,0xe6,0xff,0x39,0x04,0x00, 0x60,0xeb,0x03,0x60,0x61,0x04,0x56,0x26,0x05,0x50,0x55,0x30,0x31,0xe3,0xff,0x41, 0xe3,0xff,0x39,0x04,0x41,0xe3,0xff,0x39,0x04,0x41,0xe2,0xff,0x39,0x04,0x41,0xe2, 0xff,0x59,0x04,0x41,0xe2,0xff,0x59,0x04,0x41,0xe2,0xff,0x59,0x04,0x41,0xe1,0xff, 0x31,0xe2,0xff,0x39,0x04,0x41,0xe1,0xff,0x31,0xe2,0xff,0x39,0x04,0x41,0xe1,0xff, 0x59,0x04,0x41,0xe1,0xff,0x0c,0x23,0x39,0x04,0x41,0xe0,0xff,0x0c,0x43,0x39,0x04, 0x52,0x64,0x00,0x41,0xdf,0xff,0x31,0xdf,0xff,0x32,0x64,0x00,0x00,0x70,0x00,0x46, 0xfe,0xff, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/reset/espressif/esp32s3/esp32s3_cpu_reset_handler.S ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Reset stub used by esp32s3 target * * Copyright (C) 2020 Espressif Systems (Shanghai) Co. Ltd. * ***************************************************************************/ #define RTC_CNTL_RESET_STATE_REG 0x60008038 #define RTC_CNTL_RESET_STATE_DEF 0x3000 #define RTC_CNTL_CLK_CONF_REG 0x60008074 #define RTC_CNTL_CLK_CONF_DEF 0x1583218 #define RTC_CNTL_STORE4_REG 0x600080C0 #define RTC_CNTL_STORE5_REG 0x600080C4 #define WDT_WKEY_VALUE 0x50D83AA1 #define TIMG0_WDTWPROTECT_REG 0x6001F064 #define TIMG0_WDTCONFIG0_REG 0x6001F048 #define TIMG1_WDTWPROTECT_REG 0x60020064 #define TIMG1_WDTCONFIG0_REG 0x60020048 #define RTC_CNTL_WDTCONFIG0_REG 0x60008094 #define RTC_CNTL_WDTWPROTECT_REG 0x600080AC #define RTC_CNTL_OPTIONS0_REG 0x60008000 #define RTC_CNTL_OPTIONS0_DEF 0x1C00A000 #define RTC_CNTL_SW_SYS_RST 0x80000000 #define RTC_CNTL_DIG_PWC_REG 0x60008090 #define RTC_CNTL_SWD_CONF_REG 0x600080B0 #define RTC_CNTL_SWD_CONF_VAL 0x84B00000 #define RTC_CNTL_SWD_WPROTECT_REG 0x600080B4 #define RTC_CNTL_SWD_WKEY_VALUE 0x8F1D312A #define SYSTEM_CORE_1_CONTROL_0_REG 0x600C0000 #define SYSTEM_CONTROL_CORE_1_RESETING 0x4 #define SYSTEM_CONTROL_CORE_1_CLKGATE_EN 0x2 #define SYSTEM_CORE_1_CONTROL_1_REG 0x600C0004 /* This stub is copied to RTC_SLOW_MEM by OpenOCD, and the CPU starts executing * it instead of the ROM code (0x40000400). This stub disables watchdogs and * goes into a loop. * OpenOCD will then halt the target and perform CPU reset using OCD. */ /* Has to be at offset 0. This is the entry point of the CPU, once * RTC_CNTL_PROCPU_STAT_VECTOR_SEL is cleared. * CPU will come here after the system reset, triggered by RTC_CNTL_SW_SYS_RST. */ .global cpu_at_start_handler .type cpu_at_start_handler,@function .align 4 cpu_at_start_handler: j start /* Has to be at offset 4. Once the stub code has been uploaded into RTC Slow * memory, OpenOCD will set the PC to this address, and resume execution. * The stub will then jump to 'reset' label and perform the reset. */ .global cpu_reset_handler .type cpu_reset_handler,@function .align 4 cpu_reset_handler: j reset .align 4 .literal_position .align 4 reset: /* Use a5 as a zero register */ xor a5, a5, a5 /* Select static reset vector 0 (XCHAL_RESET_VECTOR0_VADDR, 0x50000000) */ movi a4, RTC_CNTL_RESET_STATE_REG s32i a5, a4, 0 /* Set some clock-related RTC registers to the default values */ movi a4, RTC_CNTL_STORE4_REG s32i a5, a4, 0 movi a4, RTC_CNTL_STORE5_REG s32i a5, a4, 0 movi a4, RTC_CNTL_DIG_PWC_REG s32i a5, a4, 0 movi a4, RTC_CNTL_CLK_CONF_REG movi a3, RTC_CNTL_CLK_CONF_DEF s32i a3, a4, 0 /* Reset the digital part of the chip (RTC controller doesn't get reset) */ movi a3, (RTC_CNTL_OPTIONS0_DEF | RTC_CNTL_SW_SYS_RST) movi a4, RTC_CNTL_OPTIONS0_REG s32i a3, a4, 0 /* Doesn't reach beyond this instruction */ .align 4 start: /* If running on the APP CPU, skip directly to the parking loop */ rsr.prid a6 extui a6, a6, 1, 1 bnez a6, parking_loop /* Use a5 as a zero register */ xor a5, a5, a5 /* Disable the watchdogs */ movi a3, WDT_WKEY_VALUE movi a4, RTC_CNTL_WDTWPROTECT_REG s32i.n a3, a4, 0 movi a4, TIMG0_WDTWPROTECT_REG s32i.n a3, a4, 0 movi a4, TIMG1_WDTWPROTECT_REG s32i.n a3, a4, 0 movi a4, RTC_CNTL_WDTCONFIG0_REG s32i.n a5, a4, 0 movi a4, TIMG0_WDTCONFIG0_REG s32i.n a5, a4, 0 movi a4, TIMG1_WDTCONFIG0_REG s32i.n a5, a4, 0 movi a4, RTC_CNTL_SWD_WPROTECT_REG movi a3, RTC_CNTL_SWD_WKEY_VALUE s32i.n a3, a4, 0 movi a4, RTC_CNTL_SWD_CONF_REG movi a3, RTC_CNTL_SWD_CONF_VAL s32i.n a3, a4, 0 /* Clear APP_CPU boot address */ movi a4, SYSTEM_CORE_1_CONTROL_1_REG s32i.n a5, a4, 0 /* Clear APP_CPU clock gating */ movi a4, SYSTEM_CORE_1_CONTROL_0_REG movi a3, SYSTEM_CONTROL_CORE_1_CLKGATE_EN s32i.n a3, a4, 0 /* Set and clear APP_CPU reset */ movi a4, SYSTEM_CORE_1_CONTROL_0_REG movi a3, SYSTEM_CONTROL_CORE_1_RESETING s32i.n a3, a4, 0 s32i.n a5, a4, 0 /* Restore the reset vector to ROM */ movi a4, RTC_CNTL_RESET_STATE_REG movi a3, RTC_CNTL_RESET_STATE_DEF s32i.n a3, a4, 0 parking_loop: /* PRO and APP CPU will be in this loop, until OpenOCD * finds the JTAG taps and puts the CPUs into debug mode. */ waiti 0 j parking_loop ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/watchdog/armv7m_kinetis_wdog.inc ================================================ /* Autogenerated with ../../../src/helper/bin2char.sh */ 0x04,0x4a,0xc2,0x81,0x04,0x4a,0xc2,0x81,0x01,0x24,0x02,0x88,0xa2,0x43,0x02,0x80, 0x05,0xe0,0x00,0x00,0x20,0xc5,0x00,0x00,0x28,0xd9,0x00,0x00,0x00,0x00,0x00,0xbe, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/watchdog/armv7m_kinetis_wdog.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2015 Tomas Vanek * * vanekt@fbl.cz * ***************************************************************************/ /* Disable watchdog for Kinetis Kx and KVx Parameters: r0 ... WDOG base (in) Used instruction set should work on both Cortex-M4 and M0+ */ .text .syntax unified .cpu cortex-m0 .thumb /* WDOG registers offsets */ WDOG_STCTRLH = 0 WDOG_UNLOCK = 0x0e WDOG_KEY1 = 0xc520 WDOG_KEY2 = 0xd928 .thumb_func start: /* WDOG_UNLOCK = 0xC520 */ ldr r2, =WDOG_KEY1 strh r2, [r0, WDOG_UNLOCK] /* WDOG_UNLOCK = 0xD928 */ ldr r2, =WDOG_KEY2 strh r2, [r0, WDOG_UNLOCK] /* WDOG_STCTRLH clear bit 0 */ movs r4, #1 ldrh r2, [r0, WDOG_STCTRLH] bics r2, r4 strh r2, [r0, WDOG_STCTRLH] /* OpenOCD checks exit point address. Jump to the very end. */ b done .pool /* Avoid padding at .text segment end. Otherwise exit point check fails. */ .skip ( . - start + 2) & 2, 0 done: bkpt #0 .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/watchdog/armv7m_kinetis_wdog32.inc ================================================ /* Autogenerated with ../../../src/helper/bin2char.sh */ 0x02,0x68,0x08,0x4b,0x1a,0x42,0x08,0x4b,0x01,0xd0,0x43,0x60,0x02,0xe0,0x83,0x80, 0x1b,0x0c,0x83,0x80,0x80,0x24,0xa2,0x43,0x20,0x24,0x22,0x43,0x02,0x60,0x03,0x4b, 0x83,0x60,0x06,0xe0,0x00,0x20,0x00,0x00,0x20,0xc5,0x28,0xd9,0x00,0x04,0x00,0x00, 0x00,0x00,0x00,0xbe, ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/loaders/watchdog/armv7m_kinetis_wdog32.s ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2017 Tomas Vanek * * vanekt@fbl.cz * ***************************************************************************/ /* Disable watchdog, 32-bit version for newer Kinetis Parameters: r0 ... WDOG32 base (in) Used instruction set should work on both Cortex-M4 and M0+ */ .text .syntax unified .cpu cortex-m0 .thumb /* WDOG registers offsets */ WDOG_CS = 0 WDOG_CNT = 4 WDOG_TOVAL = 8 WDOG_KEY = 0xd928c520 .thumb_func start: /* test WDOG_CS bit CMD32EN */ ldr r2, [r0, WDOG_CS] ldr r3, =0x2000 tst r2, r3 ldr r3, =WDOG_KEY beq cmd16 /* WDOG_CNT = key */ str r3, [r0, WDOG_CNT] b unlocked cmd16: /* WDOG_CNT = key, halfword by halfword */ strh r3, [r0, WDOG_CNT] lsrs r3, r3, #16 strh r3, [r0, WDOG_CNT] /* WDOG_CS: clear EN bit 7, set UPDATE bit 5 */ unlocked: movs r4, #0x80 bics r2, r4 movs r4, #0x20 orrs r2, r4 str r2, [r0, WDOG_CS] /* All active WDOG registers have to be updated, set dummy timeout */ /* WDOG_TOVAL = 0x400 */ ldr r3, =0x400 str r3, [r0, WDOG_TOVAL] /* OpenOCD checks exit point address. Jump to the very end. */ b done .pool /* Avoid padding at .text segment end. Otherwise exit point check fails. */ .skip ( . - start + 2) & 2, 0 done: bkpt #0 .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/remote_bitbang/remote_bitbang_sysfsgpio.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013 Paul Fertser * * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au * ***************************************************************************/ /* This is a test application to be used as a remote bitbang server for the OpenOCD remote_bitbang interface driver. To compile run: gcc -Wall -ansi -pedantic -std=c99 -o remote_bitbang_sysfsgpio remote_bitbang_sysfsgpio.c Usage example: On Raspberry Pi run: socat TCP6-LISTEN:7777,fork EXEC:"sudo ./remote_bitbang_sysfsgpio tck 11 tms 25 tdo 9 tdi 10" On host run: openocd -c "interface remote_bitbang; remote_bitbang host raspberrypi; remote_bitbang port 7777" \ -f target/stm32f1x.cfg Or if you want to test UNIX sockets, run both on Raspberry Pi: socat UNIX-LISTEN:/tmp/remotebitbang-socket,fork EXEC:"sudo ./remote_bitbang_sysfsgpio tck 11 tms 25 tdo 9 tdi 10" openocd -c "interface remote_bitbang; remote_bitbang host /tmp/remotebitbang-socket" -f target/stm32f1x.cfg */ #include #include #include #include #include #include #include #include #define LOG_ERROR(...) do { \ fprintf(stderr, __VA_ARGS__); \ fputc('\n', stderr); \ } while (0) #define LOG_WARNING(...) LOG_ERROR(__VA_ARGS__) #define ERROR_OK (-1) #define ERROR_FAIL (-2) #define ERROR_JTAG_INIT_FAILED ERROR_FAIL /* * Helper func to determine if gpio number valid * * Assume here that there will be less than 1000 gpios on a system */ static int is_gpio_valid(int gpio) { return gpio >= 0 && gpio < 1000; } /* * Helper func to open, write to and close a file * name and valstr must be null terminated. * * Returns negative on failure. */ static int open_write_close(const char *name, const char *valstr) { int ret; int fd = open(name, O_WRONLY); if (fd < 0) return fd; ret = write(fd, valstr, strlen(valstr)); close(fd); return ret; } /* * Helper func to unexport gpio from sysfs */ static void unexport_sysfs_gpio(int gpio) { char gpiostr[4]; if (!is_gpio_valid(gpio)) return; snprintf(gpiostr, sizeof(gpiostr), "%d", gpio); if (open_write_close("/sys/class/gpio/unexport", gpiostr) < 0) LOG_ERROR("Couldn't unexport gpio %d", gpio); return; } /* * Exports and sets up direction for gpio. * If the gpio is an output, it is initialized according to init_high, * otherwise it is ignored. * * If the gpio is already exported we just show a warning and continue; if * openocd happened to crash (or was killed by user) then the gpios will not * have been cleaned up. */ static int setup_sysfs_gpio(int gpio, int is_output, int init_high) { char buf[40]; char gpiostr[4]; int ret; if (!is_gpio_valid(gpio)) return ERROR_OK; snprintf(gpiostr, sizeof(gpiostr), "%d", gpio); ret = open_write_close("/sys/class/gpio/export", gpiostr); if (ret < 0) { if (errno == EBUSY) { LOG_WARNING("gpio %d is already exported", gpio); } else { LOG_ERROR("Couldn't export gpio %d", gpio); perror("sysfsgpio: "); return ERROR_FAIL; } } snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio); ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in"); if (ret < 0) { LOG_ERROR("Couldn't set direction for gpio %d", gpio); perror("sysfsgpio: "); unexport_sysfs_gpio(gpio); return ERROR_FAIL; } snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio); if (is_output) ret = open(buf, O_WRONLY | O_NONBLOCK | O_SYNC); else ret = open(buf, O_RDONLY | O_NONBLOCK | O_SYNC); if (ret < 0) unexport_sysfs_gpio(gpio); return ret; } /* * file descriptors for /sys/class/gpio/gpioXX/value * Set up during init. */ static int tck_fd = -1; static int tms_fd = -1; static int tdi_fd = -1; static int tdo_fd = -1; static int trst_fd = -1; static int srst_fd = -1; /* * Bitbang interface read of TDO * * The sysfs value will read back either '0' or '1'. The trick here is to call * lseek to bypass buffering in the sysfs kernel driver. */ static int sysfsgpio_read(void) { char buf[1]; /* important to seek to signal sysfs of new read */ lseek(tdo_fd, 0, SEEK_SET); int ret = read(tdo_fd, &buf, sizeof(buf)); if (ret < 0) { LOG_WARNING("reading tdo failed"); return 0; } return buf[0]; } /* * Bitbang interface write of TCK, TMS, TDI * * Seeing as this is the only function where the outputs are changed, * we can cache the old value to avoid needlessly writing it. */ static void sysfsgpio_write(int tck, int tms, int tdi) { const char one[] = "1"; const char zero[] = "0"; static int last_tck; static int last_tms; static int last_tdi; static int first_time; size_t bytes_written; if (!first_time) { last_tck = !tck; last_tms = !tms; last_tdi = !tdi; first_time = 1; } if (tdi != last_tdi) { bytes_written = write(tdi_fd, tdi ? &one : &zero, 1); if (bytes_written != 1) LOG_WARNING("writing tdi failed"); } if (tms != last_tms) { bytes_written = write(tms_fd, tms ? &one : &zero, 1); if (bytes_written != 1) LOG_WARNING("writing tms failed"); } /* write clk last */ if (tck != last_tck) { bytes_written = write(tck_fd, tck ? &one : &zero, 1); if (bytes_written != 1) LOG_WARNING("writing tck failed"); } last_tdi = tdi; last_tms = tms; last_tck = tck; } /* * Bitbang interface to manipulate reset lines SRST and TRST * * (1) assert or (0) deassert reset lines */ static void sysfsgpio_reset(int trst, int srst) { const char one[] = "1"; const char zero[] = "0"; size_t bytes_written; /* assume active low */ if (srst_fd >= 0) { bytes_written = write(srst_fd, srst ? &zero : &one, 1); if (bytes_written != 1) LOG_WARNING("writing srst failed"); } /* assume active low */ if (trst_fd >= 0) { bytes_written = write(trst_fd, trst ? &zero : &one, 1); if (bytes_written != 1) LOG_WARNING("writing trst failed"); } } /* gpio numbers for each gpio. Negative values are invalid */ static int tck_gpio = -1; static int tms_gpio = -1; static int tdi_gpio = -1; static int tdo_gpio = -1; static int trst_gpio = -1; static int srst_gpio = -1; /* helper func to close and cleanup files only if they were valid/ used */ static void cleanup_fd(int fd, int gpio) { if (gpio >= 0) { if (fd >= 0) close(fd); unexport_sysfs_gpio(gpio); } } static void cleanup_all_fds(void) { cleanup_fd(tck_fd, tck_gpio); cleanup_fd(tms_fd, tms_gpio); cleanup_fd(tdi_fd, tdi_gpio); cleanup_fd(tdo_fd, tdo_gpio); cleanup_fd(trst_fd, trst_gpio); cleanup_fd(srst_fd, srst_gpio); } static void process_remote_protocol(void) { int c; while (1) { c = getchar(); if (c == EOF || c == 'Q') /* Quit */ break; else if (c == 'b' || c == 'B') /* Blink */ continue; else if (c >= 'r' && c <= 'r' + 3) { /* Reset */ char d = c - 'r'; sysfsgpio_reset(!!(d & 2), (d & 1)); } else if (c >= '0' && c <= '0' + 7) {/* Write */ char d = c - '0'; sysfsgpio_write(!!(d & 4), !!(d & 2), (d & 1)); } else if (c == 'R') putchar(sysfsgpio_read()); else LOG_ERROR("Unknown command '%c' received", c); } } int main(int argc, char *argv[]) { LOG_WARNING("SysfsGPIO remote_bitbang JTAG driver\n"); for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "tck")) tck_gpio = atoi(argv[++i]); else if (!strcmp(argv[i], "tms")) tms_gpio = atoi(argv[++i]); else if (!strcmp(argv[i], "tdo")) tdo_gpio = atoi(argv[++i]); else if (!strcmp(argv[i], "tdi")) tdi_gpio = atoi(argv[++i]); else if (!strcmp(argv[i], "trst")) trst_gpio = atoi(argv[++i]); else if (!strcmp(argv[i], "srst")) srst_gpio = atoi(argv[++i]); else { LOG_ERROR("Usage:\n%s ((tck|tms|tdo|tdi|trst|srst) num)*", argv[0]); return -1; } } if (!(is_gpio_valid(tck_gpio) && is_gpio_valid(tms_gpio) && is_gpio_valid(tdi_gpio) && is_gpio_valid(tdo_gpio))) { if (!is_gpio_valid(tck_gpio)) LOG_ERROR("gpio num for tck is invalid"); if (!is_gpio_valid(tms_gpio)) LOG_ERROR("gpio num for tms is invalid"); if (!is_gpio_valid(tdo_gpio)) LOG_ERROR("gpio num for tdo is invalid"); if (!is_gpio_valid(tdi_gpio)) LOG_ERROR("gpio num for tdi is invalid"); LOG_ERROR("Require tck, tms, tdi and tdo gpios to all be specified"); return ERROR_JTAG_INIT_FAILED; } /* * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. */ tck_fd = setup_sysfs_gpio(tck_gpio, 1, 0); if (tck_fd < 0) goto out_error; tms_fd = setup_sysfs_gpio(tms_gpio, 1, 1); if (tms_fd < 0) goto out_error; tdi_fd = setup_sysfs_gpio(tdi_gpio, 1, 0); if (tdi_fd < 0) goto out_error; tdo_fd = setup_sysfs_gpio(tdo_gpio, 0, 0); if (tdo_fd < 0) goto out_error; /* assume active low */ if (trst_gpio > 0) { trst_fd = setup_sysfs_gpio(trst_gpio, 1, 1); if (trst_fd < 0) goto out_error; } /* assume active low */ if (srst_gpio > 0) { srst_fd = setup_sysfs_gpio(srst_gpio, 1, 1); if (srst_fd < 0) goto out_error; } LOG_WARNING("SysfsGPIO nums: tck = %d, tms = %d, tdi = %d, tdo = %d", tck_gpio, tms_gpio, tdi_gpio, tdo_gpio); LOG_WARNING("SysfsGPIO num: srst = %d", srst_gpio); LOG_WARNING("SysfsGPIO num: trst = %d", trst_gpio); setvbuf(stdout, NULL, _IONBF, 0); process_remote_protocol(); cleanup_all_fds(); return 0; out_error: cleanup_all_fds(); return ERROR_JTAG_INIT_FAILED; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/rpc_examples/ocd_rpc_example.py ================================================ #!/usr/bin/env python3 # SPDX-License-Identifier: GPL-3.0-or-later """ OpenOCD RPC example, covered by GNU GPLv3 or later Copyright (C) 2014 Andreas Ortmann (ortmann@finf.uni-hannover.de) Example output: ./ocd_rpc_example.py echo says hi! target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x00000188 msp: 0x10000fd8 variable @ 0x10000000: 0x01c9c380 variable @ 0x10000000: 0xdeadc0de memory (before): ['0xdeadc0de', '0x00000011', '0xaaaaaaaa', '0x00000023', '0x00000042', '0x0000ffff'] memory (after): ['0x00000001', '0x00000000', '0xaaaaaaaa', '0x00000023', '0x00000042', '0x0000ffff'] """ import socket import itertools def strToHex(data): return map(strToHex, data) if isinstance(data, list) else int(data, 16) def hexify(data): return "" if data is None else ("0x%08x" % data) def compareData(a, b): for i, j, num in zip(a, b, itertools.count(0)): if i != j: print("difference at %d: %s != %s" % (num, hexify(i), hexify(j))) class OpenOcd: COMMAND_TOKEN = '\x1a' def __init__(self, verbose=False): self.verbose = verbose self.tclRpcIp = "127.0.0.1" self.tclRpcPort = 6666 self.bufferSize = 4096 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) def __enter__(self): self.connect() return self def __exit__(self, type, value, traceback): self.disconnect() def connect(self): self.sock.connect((self.tclRpcIp, self.tclRpcPort)) def disconnect(self): try: self.send("exit") finally: self.sock.close() def send(self, cmd): """Send a command string to TCL RPC. Return the result that was read.""" data = (cmd + OpenOcd.COMMAND_TOKEN).encode("utf-8") if self.verbose: print("<- ", data) self.sock.send(data) return self._recv() def _recv(self): """Read from the stream until the token (\x1a) was received.""" data = bytes() while True: chunk = self.sock.recv(self.bufferSize) data += chunk if bytes(OpenOcd.COMMAND_TOKEN, encoding="utf-8") in chunk: break if self.verbose: print("-> ", data) data = data.decode("utf-8").strip() data = data[:-1] # strip trailing \x1a return data def readVariable(self, address): raw = self.send("mdw 0x%x" % address).split(": ") return None if (len(raw) < 2) else strToHex(raw[1]) def readMemory(self, wordLen, address, n): output = self.send("read_memory 0x%x %d %d" % (address, wordLen, n)) return [*map(lambda x: int(x, 16), output.split(" "))] def writeVariable(self, address, value): assert value is not None self.send("mww 0x%x 0x%x" % (address, value)) def writeMemory(self, wordLen, address, data): data = "{" + ' '.join(['0x%x' % x for x in data]) + "}" self.send("write_memory 0x%x %d %s" % (address, wordLen, data)) if __name__ == "__main__": def show(*args): print(*args, end="\n\n") with OpenOcd() as ocd: ocd.send("reset") show(ocd.send("capture { echo \"echo says hi!\" }")[:-1]) show(ocd.send("capture \"halt\"")[:-1]) # Read the first few words at the RAM region (put starting address of RAM # region into 'addr') addr = 0x10000000 value = ocd.readVariable(addr) show("variable @ %s: %s" % (hexify(addr), hexify(value))) ocd.writeVariable(addr, 0xdeadc0de) show("variable @ %s: %s" % (hexify(addr), hexify(ocd.readVariable(addr)))) data = [1, 0, 0xaaaaaaaa, 0x23, 0x42, 0xffff] wordlen = 32 n = len(data) read = ocd.readMemory(wordlen, addr, n) show("memory (before):", list(map(hexify, read))) ocd.writeMemory(wordlen, addr, n, data) read = ocd.readMemory(wordlen, addr, n) show("memory (after):", list(map(hexify, read))) compareData(read, data) ocd.send("resume") ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/rpc_examples/ocdrpc.hs ================================================ -- SPDX-License-Identifier: GPL-3.0-or-later -- OpenOCD RPC example -- Copyright (C) 2014 Paul Fertser -- -- Example output: -- $ ./ocdrpc -- Halting the target, full log output captured: -- target state: halted -- target halted due to debug-request, current mode: Thread -- xPSR: 0x21000000 pc: 0x00003352 msp: 0x20000fe8 -- -- Read memory, parse the result and show as a list of strings: -- ["0x20001000","0x0000334d","0x00002abb","0x0000118f","0x00002707","0x00002707","0x00002707","0x00000000","0x00000000","0x00000000","0x00000000","0x00002707","0x00002707","0x00000000","0x00002707","0x00002781"] -- Resuming {-# LANGUAGE OverloadedStrings #-} module Main where import Prelude import Network.Socket import System.IO.Streams.Core hiding (connect) import System.IO.Streams.Network import System.IO.Streams.Attoparsec import Data.Attoparsec.ByteString.Char8 import Data.ByteString.Char8 hiding (putStrLn, concat, map) import Text.Printf ocdReply = manyTill anyChar (char '\x1a') ocdExec (oistream, oostream) command = do write (Just $ pack $ command ++ "\x1a") oostream parseFromStream ocdReply oistream -- For each line: dispose of address, then match hex values mdwParser = (manyTill anyChar (string ": ") *> hexadecimal `sepBy` char ' ') `sepBy` string " \n" ocdMdw :: (InputStream ByteString, OutputStream ByteString) -> Integer -> Integer -> IO [Integer] ocdMdw s start qnt = do res <- ocdExec s $ "mdw " ++ show start ++ " " ++ show qnt case parseOnly mdwParser (pack res) of Right r -> return $ concat r main = do osock <- socket AF_INET Stream defaultProtocol connect osock (SockAddrInet 6666 $ tupleToHostAddress (127,0,0,1)) ostreams <- socketToStreams osock putStrLn "Halting the target, full log output captured:" ocdExec ostreams "capture \"halt\"" >>= putStrLn putStrLn "Read memory, parse the result and show as a list of strings:" ocdMdw ostreams 0 16 >>= putStrLn . (show :: [String] -> String) . map (printf "0x%08x") putStrLn "Resuming" ocdExec ostreams "resume" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/rtos-helpers/FreeRTOS-openocd.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer * present in the kernel, so it has to be supplied by other means for * OpenOCD's threads awareness. * * Add this file to your project, and, if you're using --gc-sections, * ``--undefined=uxTopUsedPriority'' (or * ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final * linking) to your LDFLAGS; same with all the other symbols you need. */ #include "FreeRTOS.h" #ifdef __GNUC__ #define USED __attribute__((used)) #else #define USED #endif const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/rtos-helpers/uCOS-III-openocd.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * uC/OS-III does not provide a fixed layout for OS_TCB, which makes it * impossible to determine the appropriate offsets within the structure * unaided. A priori knowledge of offsets based on os_dbg.c is tied to a * specific release and thusly, brittle. The constants defined below * provide the necessary information OpenOCD needs to provide support in * the most robust manner possible. * * This file should be linked along with the project to enable RTOS * support for uC/OS-III. */ #include #if OS_CFG_DBG_EN == 0 #error "OS_CFG_DBG_EN is required to enable RTOS support for OpenOCD" #endif #define OFFSET_OF(type, member) ((CPU_SIZE_T)&(((type *)0)->member)) #ifdef __GNUC__ #define USED __attribute__((used)) #else #define USED #endif const CPU_SIZE_T USED openocd_OS_TCB_StkPtr_offset = OFFSET_OF(OS_TCB, StkPtr); const CPU_SIZE_T USED openocd_OS_TCB_NamePtr_offset = OFFSET_OF(OS_TCB, NamePtr); const CPU_SIZE_T USED openocd_OS_TCB_TaskState_offset = OFFSET_OF(OS_TCB, TaskState); const CPU_SIZE_T USED openocd_OS_TCB_Prio_offset = OFFSET_OF(OS_TCB, Prio); const CPU_SIZE_T USED openocd_OS_TCB_DbgPrevPtr_offset = OFFSET_OF(OS_TCB, DbgPrevPtr); const CPU_SIZE_T USED openocd_OS_TCB_DbgNextPtr_offset = OFFSET_OF(OS_TCB, DbgNextPtr); ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/xsvf_tools/svf2xsvf.py ================================================ #!/usr/bin/python3.0 # SPDX-License-Identifier: GPL-2.0-or-later # Copyright 2008, SoftPLC Corporation http://softplc.com # Dick Hollenbeck dick@softplc.com # A python program to convert an SVF file to an XSVF file. There is an # option to include comments containing the source file line number from the origin # SVF file before each outputted XSVF statement. # # We deviate from the XSVF spec in that we introduce a new command called # XWAITSTATE which directly flows from the SVF RUNTEST command. Unfortunately # XRUNSTATE was ill conceived and is not used here. We also add support for the # three Lattice extensions to SVF: LCOUNT, LDELAY, and LSDR. The xsvf file # generated from this program is suitable for use with the xsvf player in # OpenOCD with my modifications to xsvf.c. # # This program is written for python 3.0, and it is not easy to change this # back to 2.x. You may find it easier to use python 3.x even if that means # building it. import re import sys import struct # There are both ------ and ------ sections to this program if len( sys.argv ) < 3: print("usage %s " % sys.argv[0]) exit(1) inputFilename = sys.argv[1] outputFilename = sys.argv[2] doCOMMENTs = True # Save XCOMMENTs in the output xsvf file #doCOMMENTs = False # Save XCOMMENTs in the output xsvf file # pick your file encoding file_encoding = 'ISO-8859-1' #file_encoding = 'utf-8' xrepeat = 0 # argument to XREPEAT, gives retry count for masked compares #-----< Lexer >--------------------------------------------------------------- StateBin = (RESET,IDLE, DRSELECT,DRCAPTURE,DRSHIFT,DREXIT1,DRPAUSE,DREXIT2,DRUPDATE, IRSELECT,IRCAPTURE,IRSHIFT,IREXIT1,IRPAUSE,IREXIT2,IRUPDATE) = range(16) # Any integer index into this tuple will be equal to its corresponding StateBin value StateTxt = ("RESET","IDLE", "DRSELECT","DRCAPTURE","DRSHIFT","DREXIT1","DRPAUSE","DREXIT2","DRUPDATE", "IRSELECT","IRCAPTURE","IRSHIFT","IREXIT1","IRPAUSE","IREXIT2","IRUPDATE") (XCOMPLETE,XTDOMASK,XSIR,XSDR,XRUNTEST,hole0,hole1,XREPEAT,XSDRSIZE,XSDRTDO, XSETSDRMASKS,XSDRINC,XSDRB,XSDRC,XSDRE,XSDRTDOB,XSDRTDOC, XSDRTDOE,XSTATE,XENDIR,XENDDR,XSIR2,XCOMMENT,XWAIT,XWAITSTATE, LCOUNT,LDELAY,LSDR,XTRST) = range(29) #Note: LCOUNT, LDELAY, and LSDR are Lattice extensions to SVF and provide a way to loop back # and check a completion status, essentially waiting on a part until it signals that it is done. # For example below: loop 25 times, each time through the loop do a LDELAY (same as a true RUNTEST) # and exit loop when LSDR compares match. """ LCOUNT 25; ! Step to DRPAUSE give 5 clocks and wait for 1.00e+000 SEC. LDELAY DRPAUSE 5 TCK 1.00E-003 SEC; ! Test for the completed status. Match means pass. ! Loop back to LDELAY line if not match and loop count less than 25. LSDR 1 TDI (0) TDO (1); """ #XTRST is an opcode Xilinx seemed to have missed and it comes from the SVF TRST statement. LineNumber = 1 def s_ident(scanner, token): return ("ident", token.upper(), LineNumber) def s_hex(scanner, token): global LineNumber LineNumber = LineNumber + token.count('\n') token = ''.join(token.split()) return ("hex", token[1:-1], LineNumber) def s_int(scanner, token): return ("int", int(token), LineNumber) def s_float(scanner, token): return ("float", float(token), LineNumber) #def s_comment(scanner, token): return ("comment", token, LineNumber) def s_semicolon(scanner, token): return ("semi", token, LineNumber) def s_nl(scanner,token): global LineNumber LineNumber = LineNumber + 1 #print( 'LineNumber=', LineNumber, file=sys.stderr ) return None #2.00E-002 scanner = re.Scanner([ (r"[a-zA-Z]\w*", s_ident), # (r"[-+]?[0-9]+[.]?[0-9]*([eE][-+]?[0-9]+)?", s_float), (r"[-+]?[0-9]+(([.][0-9eE+-]*)|([eE]+[-+]?[0-9]+))", s_float), (r"\d+", s_int), (r"\(([0-9a-fA-F]|\s)*\)", s_hex), (r"(!|//).*$", None), (r";", s_semicolon), (r"\n",s_nl), (r"\s*", None), ], re.MULTILINE ) # open the file using the given encoding file = open( sys.argv[1], encoding=file_encoding ) # read all svf file input into string "input" input = file.read() file.close() # Lexer: # create a list of tuples containing (tokenType, tokenValue, LineNumber) tokens = scanner.scan( input )[0] input = None # allow gc to reclaim memory holding file #for tokenType, tokenValue, ln in tokens: print( "line %d: %s" % (ln, tokenType), tokenValue ) #---------------------------------------------------------------------- tokVal = tokType = tokLn = None tup = iter( tokens ) def nextTok(): """ Function to read the next token from tup into tokType, tokVal, tokLn (linenumber) which are globals. """ global tokType, tokVal, tokLn, tup tokType, tokVal, tokLn = tup.__next__() class ParseError(Exception): """A class to hold a parsing error message""" def __init__(self, linenumber, token, message): self.linenumber = linenumber self.token = token self.message = message def __str__(self): global inputFilename return "Error in file \'%s\' at line %d near token %s\n %s" % ( inputFilename, self.linenumber, repr(self.token), self.message) class MASKSET(object): """ Class MASKSET holds a set of bit vectors, all of which are related, will all have the same length, and are associated with one of the seven shiftOps: HIR, HDR, TIR, TDR, SIR, SDR, LSDR. One of these holds a mask, smask, tdi, tdo, and a size. """ def __init__(self, name): self.empty() self.name = name def empty(self): self.mask = bytearray() self.smask = bytearray() self.tdi = bytearray() self.tdo = bytearray() self.size = 0 def syncLengths( self, sawTDI, sawTDO, sawMASK, sawSMASK, newSize ): """ Set all the lengths equal in the event some of the masks were not seen as part of the last change set. """ if self.size == newSize: return if newSize == 0: self.empty() return # If an SIR was given without a MASK(), then use a mask of all zeros. # this is not consistent with the SVF spec, but it makes sense because # it would be odd to be testing an instruction register read out of a # tap without giving a mask for it. Also, lattice seems to agree and is # generating SVF files that comply with this philosophy. if self.name == 'SIR' and not sawMASK: self.mask = bytearray( newSize ) if newSize != len(self.mask): self.mask = bytearray( newSize ) if self.name == 'SDR': # leave mask for HIR,HDR,TIR,TDR,SIR zeros for i in range( newSize ): self.mask[i] = 1 if newSize != len(self.tdo): self.tdo = bytearray( newSize ) if newSize != len(self.tdi): self.tdi = bytearray( newSize ) if newSize != len(self.smask): self.smask = bytearray( newSize ) self.size = newSize #---------- def makeBitArray( hexString, bitCount ): """ Converts a packed sequence of hex ascii characters into a bytearray where each element in the array holds exactly one bit. Only "bitCount" bits are scanned and these must be the least significant bits in the hex number. That is, it is legal to have some unused bits in the must significant hex nibble of the input "hexString". The string is scanned starting from the backend, then just before returning we reverse the array. This way the append() method can be used, which I assume is faster than an insert. """ global tokLn a = bytearray() length = bitCount hexString = list(hexString) hexString.reverse() #print(hexString) for c in hexString: if length <= 0: break; c = int(c, 16) for mask in [1,2,4,8]: if length <= 0: break; length = length - 1 a.append( (c & mask) != 0 ) if length > 0: raise ParseError( tokLn, hexString, "Insufficient hex characters for given length of %d" % bitCount ) a.reverse() #print(a) return a def makeXSVFbytes( bitarray ): """ Make a bytearray which is contains the XSVF bits which will be written directly to disk. The number of bytes needed is calculated from the size of the argument bitarray. """ bitCount = len(bitarray) byteCount = (bitCount+7)//8 ba = bytearray( byteCount ) firstBit = (bitCount % 8) - 1 if firstBit == -1: firstBit = 7 bitNdx = 0 for byteNdx in range(byteCount): mask = 1<> 1 bitNdx = bitNdx + 1 ba[byteNdx] = byte firstBit = 7 return ba def writeComment( outputFile, shiftOp_linenum, shiftOp ): """ Write an XCOMMENT record to outputFile """ comment = "%s @%d\0" % (shiftOp, shiftOp_linenum) # \0 is terminating nul ba = bytearray(1) ba[0] = XCOMMENT ba += comment.encode() outputFile.write( ba ) def combineBitVectors( trailer, meat, header ): """ Combine the 3 bit vectors comprizing a transmission. Since the least significant bits are sent first, the header is put onto the list last so they are sent first from that least significant position. """ ret = bytearray() ret.extend( trailer ) ret.extend( meat ) ret.extend( header ) return ret def writeRUNTEST( outputFile, run_state, end_state, run_count, min_time, tokenTxt ): """ Write the output for the SVF RUNTEST command. run_count - the number of clocks min_time - the number of seconds tokenTxt - either RUNTEST or LDELAY """ # convert from secs to usecs min_time = int( min_time * 1000000) # the SVF RUNTEST command does NOT map to the XSVF XRUNTEST command. Check the SVF spec, then # read the XSVF command. They are not the same. Use an XSVF XWAITSTATE to # implement the required behavior of the SVF RUNTEST command. if doCOMMENTs: writeComment( output, tokLn, tokenTxt ) if tokenTxt == 'RUNTEST': obuf = bytearray(11) obuf[0] = XWAITSTATE obuf[1] = run_state obuf[2] = end_state struct.pack_into(">i", obuf, 3, run_count ) # big endian 4 byte int to obuf struct.pack_into(">i", obuf, 7, min_time ) # big endian 4 byte int to obuf outputFile.write( obuf ) else: # == 'LDELAY' obuf = bytearray(10) obuf[0] = LDELAY obuf[1] = run_state # LDELAY has no end_state struct.pack_into(">i", obuf, 2, run_count ) # big endian 4 byte int to obuf struct.pack_into(">i", obuf, 6, min_time ) # big endian 4 byte int to obuf outputFile.write( obuf ) output = open( outputFilename, mode='wb' ) hir = MASKSET('HIR') hdr = MASKSET('HDR') tir = MASKSET('TIR') tdr = MASKSET('TDR') sir = MASKSET('SIR') sdr = MASKSET('SDR') expecting_eof = True # one of the commands that take the shiftParts after the length, the parse # template for all of these commands is identical shiftOps = ('SDR', 'SIR', 'LSDR', 'HDR', 'HIR', 'TDR', 'TIR') # the order must correspond to shiftOps, this holds the MASKSETS. 'LSDR' shares sdr with 'SDR' shiftSets = (sdr, sir, sdr, hdr, hir, tdr, tir ) # what to expect as parameters to a shiftOp, i.e. after a SDR length or SIR length shiftParts = ('TDI', 'TDO', 'MASK', 'SMASK') # the set of legal states which can trail the RUNTEST command run_state_allowed = ('IRPAUSE', 'DRPAUSE', 'RESET', 'IDLE') enddr_state_allowed = ('DRPAUSE', 'IDLE') endir_state_allowed = ('IRPAUSE', 'IDLE') trst_mode_allowed = ('ON', 'OFF', 'Z', 'ABSENT') enddr_state = IDLE endir_state = IDLE frequency = 1.00e+006 # HZ; # change detection for xsdrsize and xtdomask xsdrsize = -1 # the last one sent, send only on change xtdomask = bytearray() # the last one sent, send only on change # we use a number of single byte writes for the XSVF command below cmdbuf = bytearray(1) # Save the XREPEAT setting into the file as first thing. obuf = bytearray(2) obuf[0] = XREPEAT obuf[1] = xrepeat output.write( obuf ) try: while 1: expecting_eof = True nextTok() expecting_eof = False # print( tokType, tokVal, tokLn ) if tokVal in shiftOps: shiftOp_linenum = tokLn shiftOp = tokVal set = shiftSets[shiftOps.index(shiftOp)] # set flags false, if we see one later, set that one true later sawTDI = sawTDO = sawMASK = sawSMASK = False nextTok() if tokType != 'int': raise ParseError( tokLn, tokVal, "Expecting 'int' giving %s length, got '%s'" % (shiftOp, tokType) ) length = tokVal nextTok() while tokVal != ';': if tokVal not in shiftParts: raise ParseError( tokLn, tokVal, "Expecting TDI, TDO, MASK, SMASK, or ';'") shiftPart = tokVal nextTok() if tokType != 'hex': raise ParseError( tokLn, tokVal, "Expecting hex bits" ) bits = makeBitArray( tokVal, length ) if shiftPart == 'TDI': sawTDI = True set.tdi = bits elif shiftPart == 'TDO': sawTDO = True set.tdo = bits elif shiftPart == 'MASK': sawMASK = True set.mask = bits elif shiftPart == 'SMASK': sawSMASK = True set.smask = bits nextTok() set.syncLengths( sawTDI, sawTDO, sawMASK, sawSMASK, length ) # process all the gathered parameters and generate outputs here if shiftOp == 'SIR': if doCOMMENTs: writeComment( output, shiftOp_linenum, 'SIR' ) tdi = combineBitVectors( tir.tdi, sir.tdi, hir.tdi ) if len(tdi) > 255: obuf = bytearray(3) obuf[0] = XSIR2 struct.pack_into( ">h", obuf, 1, len(tdi) ) else: obuf = bytearray(2) obuf[0] = XSIR obuf[1] = len(tdi) output.write( obuf ) obuf = makeXSVFbytes( tdi ) output.write( obuf ) elif shiftOp == 'SDR': if doCOMMENTs: writeComment( output, shiftOp_linenum, shiftOp ) if not sawTDO: # pass a zero filled bit vector for the sdr.mask mask = combineBitVectors( tdr.mask, bytearray(sdr.size), hdr.mask ) tdi = combineBitVectors( tdr.tdi, sdr.tdi, hdr.tdi ) if xsdrsize != len(tdi): xsdrsize = len(tdi) cmdbuf[0] = XSDRSIZE output.write( cmdbuf ) obuf = bytearray(4) struct.pack_into( ">i", obuf, 0, xsdrsize ) # big endian 4 byte int to obuf output.write( obuf ) if xtdomask != mask: xtdomask = mask cmdbuf[0] = XTDOMASK output.write( cmdbuf ) obuf = makeXSVFbytes( mask ) output.write( obuf ) cmdbuf[0] = XSDR output.write( cmdbuf ) obuf = makeXSVFbytes( tdi ) output.write( obuf ) else: mask = combineBitVectors( tdr.mask, sdr.mask, hdr.mask ) tdi = combineBitVectors( tdr.tdi, sdr.tdi, hdr.tdi ) tdo = combineBitVectors( tdr.tdo, sdr.tdo, hdr.tdo ) if xsdrsize != len(tdi): xsdrsize = len(tdi) cmdbuf[0] = XSDRSIZE output.write( cmdbuf ) obuf = bytearray(4) struct.pack_into(">i", obuf, 0, xsdrsize ) # big endian 4 byte int to obuf output.write( obuf ) if xtdomask != mask: xtdomask = mask cmdbuf[0] = XTDOMASK output.write( cmdbuf ) obuf = makeXSVFbytes( mask ) output.write( obuf ) cmdbuf[0] = XSDRTDO output.write( cmdbuf ) obuf = makeXSVFbytes( tdi ) output.write( obuf ) obuf = makeXSVFbytes( tdo ) output.write( obuf ) #print( "len(tdo)=", len(tdo), "len(tdr.tdo)=", len(tdr.tdo), "len(sdr.tdo)=", len(sdr.tdo), "len(hdr.tdo)=", len(hdr.tdo) ) elif shiftOp == 'LSDR': if doCOMMENTs: writeComment( output, shiftOp_linenum, shiftOp ) mask = combineBitVectors( tdr.mask, sdr.mask, hdr.mask ) tdi = combineBitVectors( tdr.tdi, sdr.tdi, hdr.tdi ) tdo = combineBitVectors( tdr.tdo, sdr.tdo, hdr.tdo ) if xsdrsize != len(tdi): xsdrsize = len(tdi) cmdbuf[0] = XSDRSIZE output.write( cmdbuf ) obuf = bytearray(4) struct.pack_into(">i", obuf, 0, xsdrsize ) # big endian 4 byte int to obuf output.write( obuf ) if xtdomask != mask: xtdomask = mask cmdbuf[0] = XTDOMASK output.write( cmdbuf ) obuf = makeXSVFbytes( mask ) output.write( obuf ) cmdbuf[0] = LSDR output.write( cmdbuf ) obuf = makeXSVFbytes( tdi ) output.write( obuf ) obuf = makeXSVFbytes( tdo ) output.write( obuf ) #print( "len(tdo)=", len(tdo), "len(tdr.tdo)=", len(tdr.tdo), "len(sdr.tdo)=", len(sdr.tdo), "len(hdr.tdo)=", len(hdr.tdo) ) elif tokVal == 'RUNTEST' or tokVal == 'LDELAY': # e.g. from lattice tools: # "RUNTEST IDLE 5 TCK 1.00E-003 SEC;" saveTok = tokVal nextTok() min_time = 0 run_count = 0 max_time = 600 # ten minutes if tokVal in run_state_allowed: run_state = StateTxt.index(tokVal) end_state = run_state # bottom of page 17 of SVF spec nextTok() if tokType != 'int' and tokType != 'float': raise ParseError( tokLn, tokVal, "Expecting 'int' or 'float' after RUNTEST [run_state]") timeval = tokVal; nextTok() if tokVal != 'TCK' and tokVal != 'SEC' and tokVal != 'SCK': raise ParseError( tokLn, tokVal, "Expecting 'TCK' or 'SEC' or 'SCK' after RUNTEST [run_state] (run_count|min_time)") if tokVal == 'TCK' or tokVal == 'SCK': run_count = int( timeval ) else: min_time = timeval nextTok() if tokType == 'int' or tokType == 'float': min_time = tokVal nextTok() if tokVal != 'SEC': raise ParseError( tokLn, tokVal, "Expecting 'SEC' after RUNTEST [run_state] run_count min_time") nextTok() if tokVal == 'MAXIMUM': nextTok() if tokType != 'int' and tokType != 'float': raise ParseError( tokLn, tokVal, "Expecting 'max_time' after RUNTEST [run_state] min_time SEC MAXIMUM") max_time = tokVal nextTok() if tokVal != 'SEC': raise ParseError( tokLn, tokVal, "Expecting 'max_time' after RUNTEST [run_state] min_time SEC MAXIMUM max_time") nextTok() if tokVal == 'ENDSTATE': nextTok() if tokVal not in run_state_allowed: raise ParseError( tokLn, tokVal, "Expecting 'run_state' after RUNTEST .... ENDSTATE") end_state = StateTxt.index(tokVal) nextTok() if tokVal != ';': raise ParseError( tokLn, tokVal, "Expecting ';' after RUNTEST ....") # print( "run_count=", run_count, "min_time=", min_time, # "max_time=", max_time, "run_state=", State[run_state], "end_state=", State[end_state] ) writeRUNTEST( output, run_state, end_state, run_count, min_time, saveTok ) elif tokVal == 'LCOUNT': nextTok() if tokType != 'int': raise ParseError( tokLn, tokVal, "Expecting integer 'count' after LCOUNT") loopCount = tokVal nextTok() if tokVal != ';': raise ParseError( tokLn, tokVal, "Expecting ';' after LCOUNT count") if doCOMMENTs: writeComment( output, tokLn, 'LCOUNT' ) obuf = bytearray(5) obuf[0] = LCOUNT struct.pack_into(">i", obuf, 1, loopCount ) # big endian 4 byte int to obuf output.write( obuf ) elif tokVal == 'ENDDR': nextTok() if tokVal not in enddr_state_allowed: raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after ENDDR. (one of: DRPAUSE, IDLE)") enddr_state = StateTxt.index(tokVal) nextTok() if tokVal != ';': raise ParseError( tokLn, tokVal, "Expecting ';' after ENDDR stable_state") if doCOMMENTs: writeComment( output, tokLn, 'ENDDR' ) obuf = bytearray(2) obuf[0] = XENDDR # Page 10 of the March 1999 SVF spec shows that RESET is also allowed here. # Yet the XSVF spec has no provision for that, and uses a non-standard, i.e. # boolean argument to XENDDR which only handles two of the 3 intended states. obuf[1] = 1 if enddr_state == DRPAUSE else 0 output.write( obuf ) elif tokVal == 'ENDIR': nextTok() if tokVal not in endir_state_allowed: raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after ENDIR. (one of: IRPAUSE, IDLE)") endir_state = StateTxt.index(tokVal) nextTok() if tokVal != ';': raise ParseError( tokLn, tokVal, "Expecting ';' after ENDIR stable_state") if doCOMMENTs: writeComment( output, tokLn, 'ENDIR' ) obuf = bytearray(2) obuf[0] = XENDIR # Page 10 of the March 1999 SVF spec shows that RESET is also allowed here. # Yet the XSVF spec has no provision for that, and uses a non-standard, i.e. # boolean argument to XENDDR which only handles two of the 3 intended states. obuf[1] = 1 if endir_state == IRPAUSE else 0 output.write( obuf ) elif tokVal == 'STATE': nextTok() ln = tokLn while tokVal != ';': if tokVal not in StateTxt: raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after STATE") stable_state = StateTxt.index( tokVal ) if doCOMMENTs and ln != -1: writeComment( output, ln, 'STATE' ) ln = -1 # save comment only once obuf = bytearray(2) obuf[0] = XSTATE obuf[1] = stable_state output.write( obuf ) nextTok() elif tokVal == 'FREQUENCY': nextTok() if tokVal != ';': if tokType != 'int' and tokType != 'float': raise ParseError( tokLn, tokVal, "Expecting 'cycles HZ' after FREQUENCY") frequency = tokVal nextTok() if tokVal != 'HZ': raise ParseError( tokLn, tokVal, "Expecting 'HZ' after FREQUENCY cycles") nextTok() if tokVal != ';': raise ParseError( tokLn, tokVal, "Expecting ';' after FREQUENCY cycles HZ") elif tokVal == 'TRST': nextTok() if tokVal not in trst_mode_allowed: raise ParseError( tokLn, tokVal, "Expecting 'ON|OFF|Z|ABSENT' after TRST") trst_mode = tokVal nextTok() if tokVal != ';': raise ParseError( tokLn, tokVal, "Expecting ';' after TRST trst_mode") if doCOMMENTs: writeComment( output, tokLn, 'TRST %s' % trst_mode ) obuf = bytearray( 2 ) obuf[0] = XTRST obuf[1] = trst_mode_allowed.index( trst_mode ) # use the index as the binary argument to XTRST opcode output.write( obuf ) else: raise ParseError( tokLn, tokVal, "Unknown token '%s'" % tokVal) except StopIteration: if not expecting_eof: print( "Unexpected End of File at line ", tokLn ) except ParseError as pe: print( "\n", pe ) finally: # print( "closing file" ) cmdbuf[0] = XCOMPLETE output.write( cmdbuf ) output.close() ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/contrib/xsvf_tools/xsvfdump.py ================================================ #!/usr/bin/python3.0 # SPDX-License-Identifier: GPL-2.0-or-later # Copyright 2008, SoftPLC Corporation http://softplc.com # Dick Hollenbeck dick@softplc.com # Dump an Xilinx XSVF file to stdout # This program is written for python 3.0, and it is not easy to change this # back to 2.x. You may find it easier to use python 3.x even if that means # building it. import sys import struct LABEL = "A script to dump an XSVF file to stdout" Xsdrsize = 0 (XCOMPLETE,XTDOMASK,XSIR,XSDR,XRUNTEST,hole0,hole1,XREPEAT,XSDRSIZE,XSDRTDO, XSETSDRMASKS,XSDRINC,XSDRB,XSDRC,XSDRE,XSDRTDOB,XSDRTDOC, XSDRTDOE,XSTATE,XENDIR,XENDDR,XSIR2,XCOMMENT,XWAIT,XWAITSTATE, LCOUNT,LDELAY,LSDR,XTRST) = range(29) (RESET,IDLE, DRSELECT,DRCAPTURE,DRSHIFT,DREXIT1,DRPAUSE,DREXIT2,DRUPDATE, IRSELECT,IRCAPTURE,IRSHIFT,IREXIT1,IRPAUSE,IREXIT2,IRUPDATE) = range(16) State = ("RESET","IDLE", "DRSELECT","DRCAPTURE","DRSHIFT","DREXIT1","DRPAUSE","DREXIT2","DRUPDATE", "IRSELECT","IRCAPTURE","IRSHIFT","IREXIT1","IRPAUSE","IREXIT2","IRUPDATE") trst_mode_allowed = ('ON', 'OFF', 'Z', 'ABSENT') Setsdrmasks = 0 SetsdrmasksOnesCount = 0 def ReadSDRMASKS( f, len ): global Setsdrmasks, SetsdrmasksOnesCount byteCount = (len+7)//8 Setsdrmasks = f.read( byteCount ) ls = [] SetsdrmasksOnesCount = 0 for b in Setsdrmasks: ls.append( "%x" % ((b & 0xf0) >> 4) ) ls.append( "%x" % ( b & 0x0f ) ) for i in range(8): if b & (1<> 4) ) ls.append( "%x" % ( b & 0x0f ) ) return ''.join(ls) def ReadByte( f ): """Read a byte from a file and return it as an int in least significant 8 bits""" b = f.read(1) if b: return 0xff & b[0]; else: return -1 def ShowState( state ): """return the given state int as a state string""" #return "0x%02x" % state # comment this out to get textual state form global State if 0 <= state <= IRUPDATE: return State[state] else: return "Unknown state 0x%02x" % state def ShowOpcode( op, f ): """return the given byte as an opcode string""" global Xsdrsize if op == XCOMPLETE: print("XCOMPLETE") elif op == XTDOMASK: buf = bytes2hexString( f, Xsdrsize ) print("XTDOMASK 0x%s" % buf) elif op == XSIR: len = ReadByte( f ) buf = bytes2hexString( f, len ) print("XSIR 0x%02X 0x%s" % (len, buf)) elif op == XSDR: tdi = bytes2hexString( f, Xsdrsize ) print("XSDR 0x%s" % tdi) elif op == XRUNTEST: len = struct.unpack( '>i', f.read(4) )[0] print("XRUNTEST 0x%08X" % len) elif op == XREPEAT: len = ReadByte( f ) print("XREPEAT 0x%02X" % len) elif op == XSDRSIZE: Xsdrsize = struct.unpack( '>i', f.read(4) )[0] #print("XSDRSIZE 0x%08X" % Xsdrsize, file=sys.stderr ) print("XSDRSIZE 0x%08X %d" % (Xsdrsize, Xsdrsize) ) elif op == XSDRTDO: tdi = bytes2hexString( f, Xsdrsize ) tdo = bytes2hexString( f, Xsdrsize ) print("XSDRTDO 0x%s 0x%s" % (tdi, tdo) ) elif op == XSETSDRMASKS: addrmask = bytes2hexString( f, Xsdrsize ) datamask = ReadSDRMASKS( f, Xsdrsize ) print("XSETSDRMASKS 0x%s 0x%s" % (addrmask, datamask) ) elif op == XSDRINC: startaddr = bytes2hexString( f, Xsdrsize ) len = ReadByte(f) print("XSDRINC 0x%s 0x%02X" % (startaddr, len), end='' ) for numTimes in range(len): data = bytes2hexString( f, SetsdrmasksOnesCount) print(" 0x%s" % data ) print() # newline elif op == XSDRB: tdi = bytes2hexString( f, Xsdrsize ) print("XSDRB 0x%s" % tdi ) elif op == XSDRC: tdi = bytes2hexString( f, Xsdrsize ) print("XSDRC 0x%s" % tdi ) elif op == XSDRE: tdi = bytes2hexString( f, Xsdrsize ) print("XSDRE 0x%s" % tdi ) elif op == XSDRTDOB: tdo = bytes2hexString( f, Xsdrsize ) print("XSDRTDOB 0x%s" % tdo ) elif op == XSDRTDOC: tdi = bytes2hexString( f, Xsdrsize ) tdo = bytes2hexString( f, Xsdrsize ) print("XSDRTDOC 0x%s 0x%s" % (tdi, tdo) ) elif op == XSDRTDOE: tdi = bytes2hexString( f, Xsdrsize ) tdo = bytes2hexString( f, Xsdrsize ) print("XSDRTDOE 0x%s 0x%s" % (tdi, tdo) ) elif op == XSTATE: b = ReadByte(f) print("XSTATE %s" % ShowState(b)) elif op == XENDIR: b = ReadByte( f ) print("XENDIR %s" % 'IRPAUSE' if b==1 else 'IDLE') elif op == XENDDR: b = ReadByte( f ) print("XENDDR %s" % 'DRPAUSE' if b==1 else 'IDLE') elif op == XSIR2: len = struct.unpack( '>H', f.read(2) )[0] buf = bytes2hexString( f, len ) print("XSIR2 0x%04X 0x%s" % (len, buf)) elif op == XCOMMENT: cmt = [] while 1: b = ReadByte(f) if b == 0: # terminating nul break; cmt.append( chr(b) ) print("XCOMMENT \"%s\"" % ''.join(cmt) ) elif op == XWAIT: run_state = ReadByte(f) end_state = ReadByte(f) useconds = struct.unpack( '>i', f.read(4) )[0] print("XWAIT %s %s" % (ShowState(run_state), ShowState(end_state)), useconds) elif op == XWAITSTATE: run_state = ReadByte(f) end_state = ReadByte(f) clocks = struct.unpack( '>i', f.read(4) )[0] useconds = struct.unpack( '>i', f.read(4) )[0] print("XWAITSTATE %s %s CLOCKS=%d USECS=%d" % (ShowState(run_state), ShowState(end_state), clocks, useconds) ) elif op == LCOUNT: loop_count = struct.unpack( '>i', f.read(4) )[0] print("LCOUNT", loop_count ) elif op == LDELAY: run_state = ReadByte(f) clocks = struct.unpack( '>i', f.read(4) )[0] useconds = struct.unpack( '>i', f.read(4) )[0] print("LDELAY %s CLOCKS=%d USECS=%d" % (ShowState(run_state), clocks, useconds) ) elif op == LSDR: tdi = bytes2hexString( f, Xsdrsize ) tdo = bytes2hexString( f, Xsdrsize ) print("LSDR 0x%s 0x%s" % (tdi, tdo) ) elif op == XTRST: # the argument is a single byte and it is the index into "trst_mode_allowed" trst_mode = ReadByte(f) if trst_mode <= 3: print("TRST %s" % trst_mode_allowed[trst_mode] ) else: print("TRST 0x%02X" % trst_mode ); else: print("UNKNOWN op 0x%02X %d" % (op, op)) exit(1) def main(): if len( sys.argv ) < 2: print("usage %s " % sys.argv[0]) exit(1) f = open( sys.argv[1], 'rb' ) opcode = ReadByte( f ) while opcode != -1: # print the position within the file, then the command print( "%d: " % f.tell(), end='' ) ShowOpcode( opcode, f ) opcode = ReadByte(f) if __name__ == "__main__": main() ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/.gitattributes ================================================ # Avoid DOS conversion of texinfo files during git clone *.texi text eol=lf *.txt text eol=lf ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/Makefile.am ================================================ info_TEXINFOS += %D%/openocd.texi %C%_openocd_TEXINFOS = %D%/fdl.texi dist_man_MANS += %D%/openocd.1 EXTRA_DIST += %D%/manual MAINTAINERCLEANFILES += \ %D%/mdate-sh \ %D%/stamp-vti \ %D%/version.texi ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/checkpatch.rst ================================================ .. SPDX-License-Identifier: GPL-2.0-only ========== Checkpatch ========== Checkpatch (scripts/checkpatch.pl) is a perl script which checks for trivial style violations in patches and optionally corrects them. Checkpatch can also be run on file contexts and without the kernel tree. Checkpatch is not always right. Your judgement takes precedence over checkpatch messages. If your code looks better with the violations, then its probably best left alone. Options ======= This section will describe the options checkpatch can be run with. Usage:: ./scripts/checkpatch.pl [OPTION]... [FILE]... Available options: - -q, --quiet Enable quiet mode. - -v, --verbose Enable verbose mode. Additional verbose test descriptions are output so as to provide information on why that particular message is shown. - --no-tree Run checkpatch without the kernel tree. - --no-signoff Disable the 'Signed-off-by' line check. The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have the right to pass it on as an open-source patch. Example:: Signed-off-by: Random J Developer Setting this flag effectively stops a message for a missing signed-off-by line in a patch context. - --patch Treat FILE as a patch. This is the default option and need not be explicitly specified. - --emacs Set output to emacs compile window format. This allows emacs users to jump from the error in the compile window directly to the offending line in the patch. - --terse Output only one line per report. - --showfile Show the diffed file position instead of the input file position. - -g, --git Treat FILE as a single commit or a git revision range. Single commit with: - - ^ - ~n Multiple commits with: - .. - ... - - - -f, --file Treat FILE as a regular source file. This option must be used when running checkpatch on source files in the kernel. - --subjective, --strict Enable stricter tests in checkpatch. By default the tests emitted as CHECK do not activate by default. Use this flag to activate the CHECK tests. - --list-types Every message emitted by checkpatch has an associated TYPE. Add this flag to display all the types in checkpatch. Note that when this flag is active, checkpatch does not read the input FILE, and no message is emitted. Only a list of types in checkpatch is output. - --types TYPE(,TYPE2...) Only display messages with the given types. Example:: ./scripts/checkpatch.pl mypatch.patch --types EMAIL_SUBJECT,BRACES - --ignore TYPE(,TYPE2...) Checkpatch will not emit messages for the specified types. Example:: ./scripts/checkpatch.pl mypatch.patch --ignore EMAIL_SUBJECT,BRACES - --show-types By default checkpatch doesn't display the type associated with the messages. Set this flag to show the message type in the output. - --max-line-length=n Set the max line length (default 100). If a line exceeds the specified length, a LONG_LINE message is emitted. The message level is different for patch and file contexts. For patches, a WARNING is emitted. While a milder CHECK is emitted for files. So for file contexts, the --strict flag must also be enabled. - --min-conf-desc-length=n Set the Kconfig entry minimum description length, if shorter, warn. - --tab-size=n Set the number of spaces for tab (default 8). - --root=PATH PATH to the kernel tree root. This option must be specified when invoking checkpatch from outside the kernel root. - --no-summary Suppress the per file summary. - --mailback Only produce a report in case of Warnings or Errors. Milder Checks are excluded from this. - --summary-file Include the filename in summary. - --debug KEY=[0|1] Turn on/off debugging of KEY, where KEY is one of 'values', 'possible', 'type', and 'attr' (default is all off). - --fix This is an EXPERIMENTAL feature. If correctable errors exists, a file .EXPERIMENTAL-checkpatch-fixes is created which has the automatically fixable errors corrected. - --fix-inplace EXPERIMENTAL - Similar to --fix but input file is overwritten with fixes. DO NOT USE this flag unless you are absolutely sure and you have a backup in place. - --ignore-perl-version Override checking of perl version. Runtime errors maybe encountered after enabling this flag if the perl version does not meet the minimum specified. - --codespell Use the codespell dictionary for checking spelling errors. - --codespellfile Use the specified codespell file. Default is '/usr/share/codespell/dictionary.txt'. - --typedefsfile Read additional types from this file. - --color[=WHEN] Use colors 'always', 'never', or only when output is a terminal ('auto'). Default is 'auto'. - --kconfig-prefix=WORD Use WORD as a prefix for Kconfig symbols (default is `CONFIG_`). - -h, --help, --version Display the help text. Message Levels ============== Messages in checkpatch are divided into three levels. The levels of messages in checkpatch denote the severity of the error. They are: - ERROR This is the most strict level. Messages of type ERROR must be taken seriously as they denote things that are very likely to be wrong. - WARNING This is the next stricter level. Messages of type WARNING requires a more careful review. But it is milder than an ERROR. - CHECK This is the mildest level. These are things which may require some thought. Type Descriptions ================= This section contains a description of all the message types in checkpatch. .. Types in this section are also parsed by checkpatch. .. The types are grouped into subsections based on use. Allocation style ---------------- **ALLOC_ARRAY_ARGS** The first argument for kcalloc or kmalloc_array should be the number of elements. sizeof() as the first argument is generally wrong. See: https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html **ALLOC_SIZEOF_STRUCT** The allocation style is bad. In general for family of allocation functions using sizeof() to get memory size, constructs like:: p = alloc(sizeof(struct foo), ...) should be:: p = alloc(sizeof(*p), ...) See: https://www.kernel.org/doc/html/latest/process/coding-style.html#allocating-memory **ALLOC_WITH_MULTIPLY** Prefer kmalloc_array/kcalloc over kmalloc/kzalloc with a sizeof multiply. See: https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html API usage --------- **ARCH_DEFINES** Architecture specific defines should be avoided wherever possible. **ARCH_INCLUDE_LINUX** Whenever asm/file.h is included and linux/file.h exists, a conversion can be made when linux/file.h includes asm/file.h. However this is not always the case (See signal.h). This message type is emitted only for includes from arch/. **AVOID_BUG** BUG() or BUG_ON() should be avoided totally. Use WARN() and WARN_ON() instead, and handle the "impossible" error condition as gracefully as possible. See: https://www.kernel.org/doc/html/latest/process/deprecated.html#bug-and-bug-on **CONSIDER_KSTRTO** The simple_strtol(), simple_strtoll(), simple_strtoul(), and simple_strtoull() functions explicitly ignore overflows, which may lead to unexpected results in callers. The respective kstrtol(), kstrtoll(), kstrtoul(), and kstrtoull() functions tend to be the correct replacements. See: https://www.kernel.org/doc/html/latest/process/deprecated.html#simple-strtol-simple-strtoll-simple-strtoul-simple-strtoull **CONSTANT_CONVERSION** Use of __constant_ form is discouraged for the following functions:: __constant_cpu_to_be[x] __constant_cpu_to_le[x] __constant_be[x]_to_cpu __constant_le[x]_to_cpu __constant_htons __constant_ntohs Using any of these outside of include/uapi/ is not preferred as using the function without __constant_ is identical when the argument is a constant. In big endian systems, the macros like __constant_cpu_to_be32(x) and cpu_to_be32(x) expand to the same expression:: #define __constant_cpu_to_be32(x) ((__force __be32)(__u32)(x)) #define __cpu_to_be32(x) ((__force __be32)(__u32)(x)) In little endian systems, the macros __constant_cpu_to_be32(x) and cpu_to_be32(x) expand to __constant_swab32 and __swab32. __swab32 has a __builtin_constant_p check:: #define __swab32(x) \ (__builtin_constant_p((__u32)(x)) ? \ ___constant_swab32(x) : \ __fswab32(x)) So ultimately they have a special case for constants. Similar is the case with all of the macros in the list. Thus using the __constant_... forms are unnecessarily verbose and not preferred outside of include/uapi. See: https://lore.kernel.org/lkml/1400106425.12666.6.camel@joe-AO725/ **DEPRECATED_API** Usage of a deprecated RCU API is detected. It is recommended to replace old flavourful RCU APIs by their new vanilla-RCU counterparts. The full list of available RCU APIs can be viewed from the kernel docs. See: https://www.kernel.org/doc/html/latest/RCU/whatisRCU.html#full-list-of-rcu-apis **DEPRECATED_VARIABLE** EXTRA_{A,C,CPP,LD}FLAGS are deprecated and should be replaced by the new flags added via commit f77bf01425b1 ("kbuild: introduce ccflags-y, asflags-y and ldflags-y"). The following conversion scheme maybe used:: EXTRA_AFLAGS -> asflags-y EXTRA_CFLAGS -> ccflags-y EXTRA_CPPFLAGS -> cppflags-y EXTRA_LDFLAGS -> ldflags-y See: 1. https://lore.kernel.org/lkml/20070930191054.GA15876@uranus.ravnborg.org/ 2. https://lore.kernel.org/lkml/1313384834-24433-12-git-send-email-lacombar@gmail.com/ 3. https://www.kernel.org/doc/html/latest/kbuild/makefiles.html#compilation-flags **DEVICE_ATTR_FUNCTIONS** The function names used in DEVICE_ATTR is unusual. Typically, the store and show functions are used with _store and _show, where is a named attribute variable of the device. Consider the following examples:: static DEVICE_ATTR(type, 0444, type_show, NULL); static DEVICE_ATTR(power, 0644, power_show, power_store); The function names should preferably follow the above pattern. See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes **DEVICE_ATTR_RO** The DEVICE_ATTR_RO(name) helper macro can be used instead of DEVICE_ATTR(name, 0444, name_show, NULL); Note that the macro automatically appends _show to the named attribute variable of the device for the show method. See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes **DEVICE_ATTR_RW** The DEVICE_ATTR_RW(name) helper macro can be used instead of DEVICE_ATTR(name, 0644, name_show, name_store); Note that the macro automatically appends _show and _store to the named attribute variable of the device for the show and store methods. See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes **DEVICE_ATTR_WO** The DEVICE_AATR_WO(name) helper macro can be used instead of DEVICE_ATTR(name, 0200, NULL, name_store); Note that the macro automatically appends _store to the named attribute variable of the device for the store method. See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes **DUPLICATED_SYSCTL_CONST** Commit d91bff3011cf ("proc/sysctl: add shared variables for range check") added some shared const variables to be used instead of a local copy in each source file. Consider replacing the sysctl range checking value with the shared one in include/linux/sysctl.h. The following conversion scheme may be used:: &zero -> SYSCTL_ZERO &one -> SYSCTL_ONE &int_max -> SYSCTL_INT_MAX See: 1. https://lore.kernel.org/lkml/20190430180111.10688-1-mcroce@redhat.com/ 2. https://lore.kernel.org/lkml/20190531131422.14970-1-mcroce@redhat.com/ **ENOSYS** ENOSYS means that a nonexistent system call was called. Earlier, it was wrongly used for things like invalid operations on otherwise valid syscalls. This should be avoided in new code. See: https://lore.kernel.org/lkml/5eb299021dec23c1a48fa7d9f2c8b794e967766d.1408730669.git.luto@amacapital.net/ **ENOTSUPP** ENOTSUPP is not a standard error code and should be avoided in new patches. EOPNOTSUPP should be used instead. See: https://lore.kernel.org/netdev/20200510182252.GA411829@lunn.ch/ **EXPORT_SYMBOL** EXPORT_SYMBOL should immediately follow the symbol to be exported. **IN_ATOMIC** in_atomic() is not for driver use so any such use is reported as an ERROR. Also in_atomic() is often used to determine if sleeping is permitted, but it is not reliable in this use model. Therefore its use is strongly discouraged. However, in_atomic() is ok for core kernel use. See: https://lore.kernel.org/lkml/20080320201723.b87b3732.akpm@linux-foundation.org/ **LOCKDEP** The lockdep_no_validate class was added as a temporary measure to prevent warnings on conversion of device->sem to device->mutex. It should not be used for any other purpose. See: https://lore.kernel.org/lkml/1268959062.9440.467.camel@laptop/ **MALFORMED_INCLUDE** The #include statement has a malformed path. This has happened because the author has included a double slash "//" in the pathname accidentally. **USE_LOCKDEP** lockdep_assert_held() annotations should be preferred over assertions based on spin_is_locked() See: https://www.kernel.org/doc/html/latest/locking/lockdep-design.html#annotations **UAPI_INCLUDE** No #include statements in include/uapi should use a uapi/ path. **USLEEP_RANGE** usleep_range() should be preferred over udelay(). The proper way of using usleep_range() is mentioned in the kernel docs. See: https://www.kernel.org/doc/html/latest/timers/timers-howto.html#delays-information-on-the-various-kernel-delay-sleep-mechanisms Comments -------- **BLOCK_COMMENT_STYLE** The comment style is incorrect. The preferred style for multi- line comments is:: /* * This is the preferred style * for multi line comments. */ The networking comment style is a bit different, with the first line not empty like the former:: /* This is the preferred comment style * for files in net/ and drivers/net/ */ See: https://www.kernel.org/doc/html/latest/process/coding-style.html#commenting **C99_COMMENTS** C99 style single line comments (//) should not be used. Prefer the block comment style instead. See: https://www.kernel.org/doc/html/latest/process/coding-style.html#commenting **DATA_RACE** Applications of data_race() should have a comment so as to document the reasoning behind why it was deemed safe. See: https://lore.kernel.org/lkml/20200401101714.44781-1-elver@google.com/ **FSF_MAILING_ADDRESS** Kernel maintainers reject new instances of the GPL boilerplate paragraph directing people to write to the FSF for a copy of the GPL, since the FSF has moved in the past and may do so again. So do not write paragraphs about writing to the Free Software Foundation's mailing address. See: https://lore.kernel.org/lkml/20131006222342.GT19510@leaf/ Commit message -------------- **BAD_SIGN_OFF** The signed-off-by line does not fall in line with the standards specified by the community. See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#developer-s-certificate-of-origin-1-1 **BAD_STABLE_ADDRESS_STYLE** The email format for stable is incorrect. Some valid options for stable address are:: 1. stable@vger.kernel.org 2. stable@kernel.org For adding version info, the following comment style should be used:: stable@vger.kernel.org # version info **COMMIT_COMMENT_SYMBOL** Commit log lines starting with a '#' are ignored by git as comments. To solve this problem addition of a single space infront of the log line is enough. **COMMIT_MESSAGE** The patch is missing a commit description. A brief description of the changes made by the patch should be added. See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes **EMAIL_SUBJECT** Naming the tool that found the issue is not very useful in the subject line. A good subject line summarizes the change that the patch brings. See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes **FROM_SIGN_OFF_MISMATCH** The author's email does not match with that in the Signed-off-by: line(s). This can be sometimes caused due to an improperly configured email client. This message is emitted due to any of the following reasons:: - The email names do not match. - The email addresses do not match. - The email subaddresses do not match. - The email comments do not match. **MISSING_SIGN_OFF** The patch is missing a Signed-off-by line. A signed-off-by line should be added according to Developer's certificate of Origin. See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin **NO_AUTHOR_SIGN_OFF** The author of the patch has not signed off the patch. It is required that a simple sign off line should be present at the end of explanation of the patch to denote that the author has written it or otherwise has the rights to pass it on as an open source patch. See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin **DIFF_IN_COMMIT_MSG** Avoid having diff content in commit message. This causes problems when one tries to apply a file containing both the changelog and the diff because patch(1) tries to apply the diff which it found in the changelog. See: https://lore.kernel.org/lkml/20150611134006.9df79a893e3636019ad2759e@linux-foundation.org/ **GERRIT_CHANGE_ID** To be picked up by gerrit, the footer of the commit message might have a Change-Id like:: Change-Id: Ic8aaa0728a43936cd4c6e1ed590e01ba8f0fbf5b Signed-off-by: A. U. Thor The Change-Id line must be removed before submitting. **GIT_COMMIT_ID** The proper way to reference a commit id is: commit <12+ chars of sha1> ("") An example may be:: Commit e21d2170f36602ae2708 ("video: remove unnecessary platform_set_drvdata()") removed the unnecessary platform_set_drvdata(), but left the variable "dev" unused, delete it. See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes Comparison style ---------------- **ASSIGN_IN_IF** Do not use assignments in if condition. Example:: if ((foo = bar(...)) < BAZ) { should be written as:: foo = bar(...); if (foo < BAZ) { **BOOL_COMPARISON** Comparisons of A to true and false are better written as A and !A. See: https://lore.kernel.org/lkml/1365563834.27174.12.camel@joe-AO722/ **COMPARISON_TO_NULL** Comparisons to NULL in the form (foo == NULL) or (foo != NULL) are better written as (!foo) and (foo). **CONSTANT_COMPARISON** Comparisons with a constant or upper case identifier on the left side of the test should be avoided. Indentation and Line Breaks --------------------------- **CODE_INDENT** Code indent should use tabs instead of spaces. Outside of comments, documentation and Kconfig, spaces are never used for indentation. See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation **DEEP_INDENTATION** Indentation with 6 or more tabs usually indicate overly indented code. It is suggested to refactor excessive indentation of if/else/for/do/while/switch statements. See: https://lore.kernel.org/lkml/1328311239.21255.24.camel@joe2Laptop/ **SWITCH_CASE_INDENT_LEVEL** switch should be at the same indent as case. Example:: switch (suffix) { case 'G': case 'g': mem <<= 30; break; case 'M': case 'm': mem <<= 20; break; case 'K': case 'k': mem <<= 10; fallthrough; default: break; } See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation **LONG_LINE** The line has exceeded the specified maximum length. To use a different maximum line length, the --max-line-length=n option may be added while invoking checkpatch. Earlier, the default line length was 80 columns. Commit bdc48fa11e46 ("checkpatch/coding-style: deprecate 80-column warning") increased the limit to 100 columns. This is not a hard limit either and it's preferable to stay within 80 columns whenever possible. See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings **LONG_LINE_STRING** A string starts before but extends beyond the maximum line length. To use a different maximum line length, the --max-line-length=n option may be added while invoking checkpatch. See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings **LONG_LINE_COMMENT** A comment starts before but extends beyond the maximum line length. To use a different maximum line length, the --max-line-length=n option may be added while invoking checkpatch. See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings **SPLIT_STRING** Quoted strings that appear as messages in userspace and can be grepped, should not be split across multiple lines. See: https://lore.kernel.org/lkml/20120203052727.GA15035@leaf/ **MULTILINE_DEREFERENCE** A single dereferencing identifier spanned on multiple lines like:: struct_identifier->member[index]. member = <foo>; is generally hard to follow. It can easily lead to typos and so makes the code vulnerable to bugs. If fixing the multiple line dereferencing leads to an 80 column violation, then either rewrite the code in a more simple way or if the starting part of the dereferencing identifier is the same and used at multiple places then store it in a temporary variable, and use that temporary variable only at all the places. For example, if there are two dereferencing identifiers:: member1->member2->member3.foo1; member1->member2->member3.foo2; then store the member1->member2->member3 part in a temporary variable. It not only helps to avoid the 80 column violation but also reduces the program size by removing the unnecessary dereferences. But if none of the above methods work then ignore the 80 column violation because it is much easier to read a dereferencing identifier on a single line. **TRAILING_STATEMENTS** Trailing statements (for example after any conditional) should be on the next line. Statements, such as:: if (x == y) break; should be:: if (x == y) break; Macros, Attributes and Symbols ------------------------------ **ARRAY_SIZE** The ARRAY_SIZE(foo) macro should be preferred over sizeof(foo)/sizeof(foo[0]) for finding number of elements in an array. The macro is defined in include/linux/kernel.h:: #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) **AVOID_EXTERNS** Function prototypes don't need to be declared extern in .h files. It's assumed by the compiler and is unnecessary. **AVOID_L_PREFIX** Local symbol names that are prefixed with `.L` should be avoided, as this has special meaning for the assembler; a symbol entry will not be emitted into the symbol table. This can prevent `objtool` from generating correct unwind info. Symbols with STB_LOCAL binding may still be used, and `.L` prefixed local symbol names are still generally usable within a function, but `.L` prefixed local symbol names should not be used to denote the beginning or end of code regions via `SYM_CODE_START_LOCAL`/`SYM_CODE_END` **BIT_MACRO** Defines like: 1 << <digit> could be BIT(digit). The BIT() macro is defined via include/linux/bits.h:: #define BIT(nr) (1UL << (nr)) **CONST_READ_MOSTLY** When a variable is tagged with the __read_mostly annotation, it is a signal to the compiler that accesses to the variable will be mostly reads and rarely(but NOT never) a write. const __read_mostly does not make any sense as const data is already read-only. The __read_mostly annotation thus should be removed. **DATE_TIME** It is generally desirable that building the same source code with the same set of tools is reproducible, i.e. the output is always exactly the same. The kernel does *not* use the ``__DATE__`` and ``__TIME__`` macros, and enables warnings if they are used as they can lead to non-deterministic builds. See: https://www.kernel.org/doc/html/latest/kbuild/reproducible-builds.html#timestamps **DEFINE_ARCH_HAS** The ARCH_HAS_xyz and ARCH_HAVE_xyz patterns are wrong. For big conceptual features use Kconfig symbols instead. And for smaller things where we have compatibility fallback functions but want architectures able to override them with optimized ones, we should either use weak functions (appropriate for some cases), or the symbol that protects them should be the same symbol we use. See: https://lore.kernel.org/lkml/CA+55aFycQ9XJvEOsiM3txHL5bjUc8CeKWJNR_H+MiicaddB42Q@mail.gmail.com/ **DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON** do {} while(0) macros should not have a trailing semicolon. **INIT_ATTRIBUTE** Const init definitions should use __initconst instead of __initdata. Similarly init definitions without const require a separate use of const. **INLINE_LOCATION** The inline keyword should sit between storage class and type. For example, the following segment:: inline static int example_function(void) { ... } should be:: static inline int example_function(void) { ... } **MISPLACED_INIT** It is possible to use section markers on variables in a way which gcc doesn't understand (or at least not the way the developer intended):: static struct __initdata samsung_pll_clock exynos4_plls[nr_plls] = { does not put exynos4_plls in the .initdata section. The __initdata marker can be virtually anywhere on the line, except right after "struct". The preferred location is before the "=" sign if there is one, or before the trailing ";" otherwise. See: https://lore.kernel.org/lkml/1377655732.3619.19.camel@joe-AO722/ **MULTISTATEMENT_MACRO_USE_DO_WHILE** Macros with multiple statements should be enclosed in a do - while block. Same should also be the case for macros starting with `if` to avoid logic defects:: #define macrofun(a, b, c) \ do { \ if (a == 5) \ do_this(b, c); \ } while (0) See: https://www.kernel.org/doc/html/latest/process/coding-style.html#macros-enums-and-rtl **PREFER_FALLTHROUGH** Use the `fallthrough;` pseudo keyword instead of `/* fallthrough */` like comments. **TRAILING_SEMICOLON** Macro definition should not end with a semicolon. The macro invocation style should be consistent with function calls. This can prevent any unexpected code paths:: #define MAC do_something; If this macro is used within a if else statement, like:: if (some_condition) MAC; else do_something; Then there would be a compilation error, because when the macro is expanded there are two trailing semicolons, so the else branch gets orphaned. See: https://lore.kernel.org/lkml/1399671106.2912.21.camel@joe-AO725/ **SINGLE_STATEMENT_DO_WHILE_MACRO** For the multi-statement macros, it is necessary to use the do-while loop to avoid unpredictable code paths. The do-while loop helps to group the multiple statements into a single one so that a function-like macro can be used as a function only. But for the single statement macros, it is unnecessary to use the do-while loop. Although the code is syntactically correct but using the do-while loop is redundant. So remove the do-while loop for single statement macros. **WEAK_DECLARATION** Using weak declarations like __attribute__((weak)) or __weak can have unintended link defects. Avoid using them. Functions and Variables ----------------------- **CAMELCASE** Avoid CamelCase Identifiers. See: https://www.kernel.org/doc/html/latest/process/coding-style.html#naming **CONST_CONST** Using `const <type> const *` is generally meant to be written `const <type> * const`. **CONST_STRUCT** Using const is generally a good idea. Checkpatch reads a list of frequently used structs that are always or almost always constant. The existing structs list can be viewed from `scripts/const_structs.checkpatch`. See: https://lore.kernel.org/lkml/alpine.DEB.2.10.1608281509480.3321@hadrien/ **EMBEDDED_FUNCTION_NAME** Embedded function names are less appropriate to use as refactoring can cause function renaming. Prefer the use of "%s", __func__ to embedded function names. Note that this does not work with -f (--file) checkpatch option as it depends on patch context providing the function name. **FUNCTION_ARGUMENTS** This warning is emitted due to any of the following reasons: 1. Arguments for the function declaration do not follow the identifier name. Example:: void foo (int bar, int baz) This should be corrected to:: void foo(int bar, int baz) 2. Some arguments for the function definition do not have an identifier name. Example:: void foo(int) All arguments should have identifier names. **FUNCTION_WITHOUT_ARGS** Function declarations without arguments like:: int foo() should be:: int foo(void) **GLOBAL_INITIALISERS** Global variables should not be initialized explicitly to 0 (or NULL, false, etc.). Your compiler (or rather your loader, which is responsible for zeroing out the relevant sections) automatically does it for you. **INITIALISED_STATIC** Static variables should not be initialized explicitly to zero. Your compiler (or rather your loader) automatically does it for you. **MULTIPLE_ASSIGNMENTS** Multiple assignments on a single line makes the code unnecessarily complicated. So on a single line assign value to a single variable only, this makes the code more readable and helps avoid typos. **RETURN_PARENTHESES** return is not a function and as such doesn't need parentheses:: return (bar); can simply be:: return bar; Permissions ----------- **DEVICE_ATTR_PERMS** The permissions used in DEVICE_ATTR are unusual. Typically only three permissions are used - 0644 (RW), 0444 (RO) and 0200 (WO). See: https://www.kernel.org/doc/html/latest/filesystems/sysfs.html#attributes **EXECUTE_PERMISSIONS** There is no reason for source files to be executable. The executable bit can be removed safely. **EXPORTED_WORLD_WRITABLE** Exporting world writable sysfs/debugfs files is usually a bad thing. When done arbitrarily they can introduce serious security bugs. In the past, some of the debugfs vulnerabilities would seemingly allow any local user to write arbitrary values into device registers - a situation from which little good can be expected to emerge. See: https://lore.kernel.org/linux-arm-kernel/cover.1296818921.git.segoon@openwall.com/ **NON_OCTAL_PERMISSIONS** Permission bits should use 4 digit octal permissions (like 0700 or 0444). Avoid using any other base like decimal. **SYMBOLIC_PERMS** Permission bits in the octal form are more readable and easier to understand than their symbolic counterparts because many command-line tools use this notation. Experienced kernel developers have been using these traditional Unix permission bits for decades and so they find it easier to understand the octal notation than the symbolic macros. For example, it is harder to read S_IWUSR|S_IRUGO than 0644, which obscures the developer's intent rather than clarifying it. See: https://lore.kernel.org/lkml/CA+55aFw5v23T-zvDZp-MmD_EYxF8WbafwwB59934FV7g21uMGQ@mail.gmail.com/ Spacing and Brackets -------------------- **ASSIGNMENT_CONTINUATIONS** Assignment operators should not be written at the start of a line but should follow the operand at the previous line. **BRACES** The placement of braces is stylistically incorrect. The preferred way is to put the opening brace last on the line, and put the closing brace first:: if (x is true) { we do y } This applies for all non-functional blocks. However, there is one special case, namely functions: they have the opening brace at the beginning of the next line, thus:: int function(int x) { body of function } See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces **BRACKET_SPACE** Whitespace before opening bracket '[' is prohibited. There are some exceptions: 1. With a type on the left:: int [] a; 2. At the beginning of a line for slice initialisers:: [0...10] = 5, 3. Inside a curly brace:: = { [0...10] = 5 } **CONCATENATED_STRING** Concatenated elements should have a space in between. Example:: printk(KERN_INFO"bar"); should be:: printk(KERN_INFO "bar"); **ELSE_AFTER_BRACE** `else {` should follow the closing block `}` on the same line. See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces **LINE_SPACING** Vertical space is wasted given the limited number of lines an editor window can display when multiple blank lines are used. See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces **OPEN_BRACE** The opening brace should be following the function definitions on the next line. For any non-functional block it should be on the same line as the last construct. See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces **POINTER_LOCATION** When using pointer data or a function that returns a pointer type, the preferred use of * is adjacent to the data name or function name and not adjacent to the type name. Examples:: char *linux_banner; unsigned long long memparse(char *ptr, char **retptr); char *match_strdup(substring_t *s); See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces **SPACING** Whitespace style used in the kernel sources is described in kernel docs. See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces **TRAILING_WHITESPACE** Trailing whitespace should always be removed. Some editors highlight the trailing whitespace and cause visual distractions when editing files. See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces **UNNECESSARY_PARENTHESES** Parentheses are not required in the following cases: 1. Function pointer uses:: (foo->bar)(); could be:: foo->bar(); 2. Comparisons in if:: if ((foo->bar) && (foo->baz)) if ((foo == bar)) could be:: if (foo->bar && foo->baz) if (foo == bar) 3. addressof/dereference single Lvalues:: &(foo->bar) *(foo->bar) could be:: &foo->bar *foo->bar **WHILE_AFTER_BRACE** while should follow the closing bracket on the same line:: do { ... } while(something); See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces Others ------ **CONFIG_DESCRIPTION** Kconfig symbols should have a help text which fully describes it. **CORRUPTED_PATCH** The patch seems to be corrupted or lines are wrapped. Please regenerate the patch file before sending it to the maintainer. **CVS_KEYWORD** Since linux moved to git, the CVS markers are no longer used. So, CVS style keywords ($Id$, $Revision$, $Log$) should not be added. **DEFAULT_NO_BREAK** switch default case is sometimes written as "default:;". This can cause new cases added below default to be defective. A "break;" should be added after empty default statement to avoid unwanted fallthrough. **DOS_LINE_ENDINGS** For DOS-formatted patches, there are extra ^M symbols at the end of the line. These should be removed. **DT_SCHEMA_BINDING_PATCH** DT bindings moved to a json-schema based format instead of freeform text. See: https://www.kernel.org/doc/html/latest/devicetree/bindings/writing-schema.html **DT_SPLIT_BINDING_PATCH** Devicetree bindings should be their own patch. This is because bindings are logically independent from a driver implementation, they have a different maintainer (even though they often are applied via the same tree), and it makes for a cleaner history in the DT only tree created with git-filter-branch. See: https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters **EMBEDDED_FILENAME** Embedding the complete filename path inside the file isn't particularly useful as often the path is moved around and becomes incorrect. **FILE_PATH_CHANGES** Whenever files are added, moved, or deleted, the MAINTAINERS file patterns can be out of sync or outdated. So MAINTAINERS might need updating in these cases. **MEMSET** The memset use appears to be incorrect. This may be caused due to badly ordered parameters. Please recheck the usage. **NOT_UNIFIED_DIFF** The patch file does not appear to be in unified-diff format. Please regenerate the patch file before sending it to the maintainer. **PRINTF_0XDECIMAL** Prefixing 0x with decimal output is defective and should be corrected. **SPDX_LICENSE_TAG** The source file is missing or has an improper SPDX identifier tag. The Linux kernel requires the precise SPDX identifier in all source files, and it is thoroughly documented in the kernel docs. See: https://www.kernel.org/doc/html/latest/process/license-rules.html **TYPO_SPELLING** Some words may have been misspelled. Consider reviewing them. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/fdl.texi ================================================ @c -*-texinfo-*- @c The GNU Free Documentation License. @center Version 1.2, November 2002 @c This file is intended to be included within another document, @c hence no sectioning command or @node. @display Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @end display @enumerate 0 @item PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document @dfn{free} in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of ``copyleft'', which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. @item APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The ``Document'', below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as ``you''. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A ``Modified Version'' of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A ``Secondary Section'' is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The ``Invariant Sections'' are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The ``Cover Texts'' are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A ``Transparent'' copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not ``Transparent'' is called ``Opaque''. Examples of suitable formats for Transparent copies include plain @sc{ascii} without markup, Texinfo input format, La@TeX{} input format, @acronym{SGML} or @acronym{XML} using a publicly available @acronym{DTD}, and standard-conforming simple @acronym{HTML}, PostScript or @acronym{PDF} designed for human modification. Examples of transparent image formats include @acronym{PNG}, @acronym{XCF} and @acronym{JPG}. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, @acronym{SGML} or @acronym{XML} for which the @acronym{DTD} and/or processing tools are not generally available, and the machine-generated @acronym{HTML}, PostScript or @acronym{PDF} produced by some word processors for output purposes only. The ``Title Page'' means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, ``Title Page'' means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. A section ``Entitled XYZ'' means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as ``Acknowledgements'', ``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title'' of such a section when you modify the Document means that it remains a section ``Entitled XYZ'' according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. @item VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. @item COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. @item MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: @enumerate A @item Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. @item List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. @item State on the Title page the name of the publisher of the Modified Version, as the publisher. @item Preserve all the copyright notices of the Document. @item Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. @item Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. @item Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. @item Include an unaltered copy of this License. @item Preserve the section Entitled ``History'', Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled ``History'' in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. @item Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the ``History'' section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. @item For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. @item Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. @item Delete any section Entitled ``Endorsements''. Such a section may not be included in the Modified Version. @item Do not retitle any existing section to be Entitled ``Endorsements'' or to conflict in title with any Invariant Section. @item Preserve any Warranty Disclaimers. @end enumerate If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled ``Endorsements'', provided it contains nothing but endorsements of your Modified Version by various parties---for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. @item COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled ``History'' in the various original documents, forming one section Entitled ``History''; likewise combine any sections Entitled ``Acknowledgements'', and any sections Entitled ``Dedications''. You must delete all sections Entitled ``Endorsements.'' @item COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. @item AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an ``aggregate'' if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. @item TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled ``Acknowledgements'', ``Dedications'', or ``History'', the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. @item TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. @item FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See @uref{https://www.gnu.org/licenses/}. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License ``or any later version'' applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. @end enumerate @page @heading ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: @smallexample @group Copyright (C) @var{year} @var{your name}. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. @end group @end smallexample If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the ``with@dots{}Texts.'' line with this: @smallexample @group with the Invariant Sections being @var{list their titles}, with the Front-Cover Texts being @var{list}, and with the Back-Cover Texts being @var{list}. @end group @end smallexample If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. @c Local Variables: @c ispell-local-pdict: "ispell-dict" @c End: ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/app.txt ================================================ /** @page appdocs OpenOCD Application APIs The top-level APIs in the OpenOCD library allow applications to integrate all of the low-level functionality using a set of simple function calls. These function calls do not exist in a re-usable form, but contributions to create and document them will be welcome. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/endianness.txt ================================================ /** @page endianness About endianness OpenOCD has to potentially deal with different endianness between: - the host PC endianness; - the data endianness during communication between host and adapter; - the target CPU endianness. The whole OpenOCD code should be written to handle any endianness mismatch and should run on either little and big endian hosts. Big-endian host PC are becoming less and less common since Apple™ has switched away from big-endian PowerPC™ in favor of little-endian intel X86™. The lack of commercial big-endian hosts makes hard testing OpenOCD correctness on big-endian hosts. Running OpenOCD on low-cost commercial routers based on big-endian MIPS is possible, but it's tricky to properly setup the system and the cross-compiling environment. In next sections there are two example on how to compile and test OpenOCD in an emulated big-endian environment. @section endianness_helpers OpenOCD API for handling endianness Use the following OpenOCD API to handle endianness conversions: - host endianness to/from little endian: - le_to_h_u64(), le_to_h_u32(), le_to_h_u16(); - h_u64_to_le(), h_u32_to_le(), h_u16_to_le(); - buf_get_u32(), buf_get_u64(); - buf_set_u32(), buf_set_u64(); - host endianness to/from big endian: - be_to_h_u64(), be_to_h_u32(), be_to_h_u16(); - h_u64_to_be(), h_u32_to_be(), h_u16_to_be(); - host endianness to/from target endianness: - target_read_u64(), target_read_u32(), target_read_u16(); - target_write_u64(), target_write_u32(), target_write_u16(); - target_write_phys_u64(), target_write_phys_u32(), target_write_phys_u16(); - target_buffer_get_u64(), target_buffer_get_u32(), target_buffer_get_u24(), target_buffer_get_u16(); - target_buffer_set_u64(), target_buffer_set_u32(), target_buffer_set_u24(), target_buffer_set_u16(); - byte swap: - buf_bswap32(), buf_bswap16(). @section endianness_docker Use dockers to run different endianness Docker can run a full Linux image that includes the toolchain through QEMU emulator. By selecting a big-endian image, it's possible to compile and execute OpenOCD in big-endian. There are, so far, not many options for big-endian images; s390x is one of the few available. To be expanded. User should: - install docker; - download the big-endian image; - run the image in docker; - download, in the image, the OpenOCD code to test; - recompile OpenOCD code in the image; - run OpenOCD binary in the image. From https://github.com/multiarch/qemu-user-static @code{.unparsed} docker run --rm -t s390x/ubuntu bash @endcode @section endianness_qemu Use buildroot and QEMU to run different endianness QEMU User Mode Emulation is an efficient method to launch, on host's CPU, applications compiled for another CPU and/or for different endianness. It works either on Linux and BSD. More info available on https://www.qemu.org/docs/master/user/index.html With QEMU User Mode Emulation is thus possible running, on a commonly available little-endian X86 Linux host, OpenOCD compiled for a big-endian host. The following example will show how to use buildroot to: - build big-endian toolchain and libraries; - compile OpenOCD for big-endian; - run the big-endian OpenOCD on little-endian Linux PC. The example will use ARM Cortex-A7 big-endian only because I personally feel comfortable reading ARM assembly during debug. User can select other CPU architectures, as this does not impact the result. A similar method can be used to test OpenOCD compiled for 32 vs 64 bit host. @note - the version of autotools locally installer in your Linux host can be incompatible with the version of autotools used by buildroot. This can cause the build to fail if buildroot has to run its autotools on a partially configured OpenOCD folder. Use either a clean copy of OpenOCD code in 2., or run "./bootstrap" in OpenOCD folder to prevent buildroot from using its own autotools; - the configuration tool in 4. and 5. matches the version of OpenOCD used by buildroot. Some new driver could be not listed in. OpenOCD will build every driver that is not disabled and with satisfied dependencies. If the driver you plan to use is not listed, try a first build and check OpenOCD with command "adapter list", then try to hack the buildroot files Config.in and openocd.mk in folder package/openocd/ and use "make openocd-reconfigure" to rerun the build starting with configuration; - using pre-built toolchains, you need 2GB of disk space for buildroot build. To also rebuild the toolchains you will need ~5GB and much longer time for the first build (it takes ~2 hour on my crap 10+ years old laptop); - you need to install few tools for buildroot dependency, listed in https://buildroot.org/downloads/manual/manual.html#requirement ; - you need to install qemu-armeb. On Arch Linux it's in package qemu-arch-extra; on Ubuntu/debian it's packaged in qemu-user. Buildroot can also be configured to build qemu for the host, if you prefer, by enabling BR2_PACKAGE_HOST_QEMU_LINUX_USER_MODE, but this takes longer compile time; - don't use qemu-system-arm, as it emulates a complete system and requires a fully bootable ARM image; - while QEMU User Mode Emulation is available for both Linux and BSD, buildroot only builds binaries for Linux target. This example can only be used with Linux hosts emulating the Linux target. Steps to run big-endian OpenOCD on little-endian host Linux PC: 1. Get buildroot source. Today's latest version is "2022.02": @code{.unparsed} wget https://buildroot.org/downloads/buildroot-2022.02.tar.xz tar xf buildroot-2022.02.tar.xz cd buildroot-2022.02 @endcode 2. Override the source repo for OpenOCD in order to build your own code version in place of the default OpenOCD release version: @code{.unparsed} echo OPENOCD_OVERRIDE_SRCDIR=/home/me/openocd.git >> local.mk @endcode 3. Copy default config for OpenOCD big-endian. This used: - ARM Cortex-A7 big-endian target, - external Linaro armeb toolchain (to speed up first build), - OpenOCD all configure options enabled. @code{.unparsed} cp $OPENOCD_OVERRIDE_SRCDIR/contrib/buildroot/openocd_be_defconfig configs/ @endcode 4. Configure buildroot with default config for OpenOCD big-endian: @code{.unparsed} make openocd_be_defconfig @endcode 5. Optional, change buildroot configuration: @code{.unparsed} make menuconfig @endcode These are the options selected with default config for OpenOCD big-endian: @code{.unparsed} Target options ---> Target Architecture ---> ARM (big endian) Target Architecture Variant ---> cortex-A7 Toolchain ---> Toolchain type ---> External toolchain Toolchain ---> Linaro armeb 2018.05 Toolchain origin ---> Toolchain to be downloaded and installed Target packages ---> Hardware handling ---> openocd All adapters selected @endcode Save and exit 6. Build (and take a long coffee break ...): @code{.unparsed} make openocd @endcode 7. Execute big-endian OpenOCD: @code{.unparsed} cd output/target qemu-armeb -cpu cortex-a7 -L . usr/bin/openocd -s usr/share/openocd/scripts/ -f board/st_nucleo_f4.cfg @endcode 8. Optional, to rebuild after any source code modification in ${OPENOCD_OVERRIDE_SRCDIR}: @code{.unparsed} make openocd-rebuild @endcode */ /** @file This file contains the @ref endianness page. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/flash.txt ================================================ /** @page flashdocs OpenOCD Flash APIs OpenOCD provides its Flash APIs for developers to support different types of flash devices, some of which are built-in to target devices while others may be connected via standard memory interface (e.g. CFI, FMI, etc.). The Flash module provides the following APIs: - @subpage flashcfi - @subpage flashnand - @subpage flashtarget This section needs to be expanded. */ /** @page flashcfi OpenOCD CFI Flash API This section needs to be expanded to describe OpenOCD's CFI Flash API. */ /** @page flashnand OpenOCD NAND Flash API This section needs to be expanded to describe OpenOCD's NAND Flash API. */ /** @page flashtarget OpenOCD Target Flash API This section needs to be expanded to describe OpenOCD's Target Flash API. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/helper.txt ================================================ /** @page helperdocs OpenOCD Helper APIs OpenOCD uses several low-level APIs as the foundation for high-level APIs: - @subpage helperporting - @subpage helperjim - @subpage helpercommand - @subpage helperlogging - @subpage helperbuffers This section needs to be expanded. */ /** @page helperporting OpenOCD Types/Portability APIs This section needs to be expanded to describe OpenOCD's type and portability API. */ /** @page helperjim OpenOCD Jim API The Jim API provides access to a small-footprint TCL implementation. Visit http://jim.tcl.tk/ for more information on Jim. This section needs to be expanded to describe OpenOCD's Jim API. */ /** @page helpercommand OpenOCD Command API OpenOCD's command API allows modules to register callbacks that are then available to the scripting services. It provides the mechanism for these commands to be dispatched to the module using a standard interface. It provides macros for defining functions that use and extend this interface. @section helpercmdhandler Command Handlers Command handlers are functions with a particular signature, which can be extended by modules for passing additional parameters to helpers or another layer of handlers. @subsection helpercmdhandlerdef Defining and Calling Command Handlers These functions should be defined using the @c COMMAND_HANDLER macro. These methods must be defined as static, as their principal entry point should be the run_command dispatch mechanism. Command helper functions that require access to the full set of parameters should be defined using the @c COMMAND_HELPER. These must be declared static by you, as sometimes you might want to share a helper among several files (e.g. @c s3c24xx_nand.h). Both types of routines must be called using the @c CALL_COMMAND_HANDLER macro. Calls using this macro to normal handlers require the name of the command handler (which can be a name or function pointer). Calls to helpers and derived handlers must pass those extra parameters specified by their definitions; however, lexical capture is used for the core parameters. This dirty trick is being used as a stop-gap measure while the API is migrated to one that passes a pointer to a structure containing the same ingredients. At that point, this macro will be removed and callers will be able to use direct invocations. Thus, the following macros can be used to define and call command handlers or helpers: - @c COMMAND_HANDLER - declare or define a command handler. - @c COMMAND_HELPER - declare or define a derived command handler or helper. - @c CALL_COMMAND_HANDLER - call a command handler/helper. @subsection helpercmdhandlermacros Command Handler Macros In addition, the following macros may be used in the context of command handlers and helpers: - @c CMD_CTX - the current @c command_context - @c CMD_NAME - invoked command name - @c CMD_ARGC - the number of command arguments - @c CMD_ARGV - array of command argument strings @section helpercmdregister Command Registration In order to use a command handler, it must be registered with the command subsystem. All commands are registered with command_registration structures, specifying the name of the command, its handler, its allowed mode(s) of execution, and strings that provide usage and help text. A single handler may be registered using multiple names, but any name may have only one handler associated with it. The @c register_command() and @c register_commands() functions provide registration, while the @c unregister_command() and @c unregister_all_commands() functions will remove existing commands. These may be called at any time, allowing the command set to change in response to system actions. @subsection helpercmdjim Jim Command Registration The command_registration structure provides support for registering native Jim command handlers (@c jim_handler) too. For these handlers, the module can provide help and usage support; however, this mechanism allows Jim handlers to be called as sub-commands of other commands. These commands may be registered with a private data value (@c jim_handler_data) that will be available when called, as with low-level Jim command registration. A command may have a normal @c handler or a @c jim_handler, but not both. @subsection helpercmdregisterchains Command Chaining When using register_commands(), the array of commands may reference other arrays. When the @c chain field is filled in a command_registration record, the commands on in the chained list will added in one of two places. If the record defines a new command, then the chained commands are added under it; otherwise, the commands are added in the same context as the other commands in the array. @section helpercmdprimer Command Development Primer This @ref primercommand provides details about the @c hello module, showing how the pieces described on this page fit together. */ /** @page helperlogging OpenOCD Logging API This section needs to be expanded to describe OpenOCD's Logging API. */ /** @page helperbuffers OpenOCD Byte Buffer API This section needs to be expanded to describe OpenOCD's Byte Buffer API. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/jtag/drivers/remote_bitbang.txt ================================================ /** @remote_bitbangpage OpenOCD Developer's Guide The remote_bitbang JTAG driver is used to drive JTAG from a remote process. The remote_bitbang driver communicates via TCP or UNIX sockets with some remote process using an ASCII encoding of the bitbang interface. The remote process presumably then drives the JTAG however it pleases. The remote process should act as a server, listening for connections from the openocd remote_bitbang driver. The remote bitbang driver is useful for debugging software running on processors which are being simulated. The bitbang interface consists of the following functions. blink on Blink a light somewhere. The argument on is either 1 or 0. read Sample the value of tdo. write tck tms tdi Set the value of tck, tms, and tdi. reset trst srst Set the value of trst, srst. An additional function, quit, is added to the remote_bitbang interface to indicate there will be no more requests and the connection with the remote driver should be closed. These five functions are encoded in ASCII by assigning a single character to each possible request. The assignments are: B - Blink on b - Blink off R - Read request Q - Quit request 0 - Write 0 0 0 1 - Write 0 0 1 2 - Write 0 1 0 3 - Write 0 1 1 4 - Write 1 0 0 5 - Write 1 0 1 6 - Write 1 1 0 7 - Write 1 1 1 r - Reset 0 0 s - Reset 0 1 t - Reset 1 0 u - Reset 1 1 The read response is encoded in ASCII as either digit 0 or 1. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/jtag.txt ================================================ /** @page jtagdocs JTAG APIs For new developers unfamiliar with the technology, @ref primerjtag provides a brief introduction to the IEEE JTAG interface. The OpenOCD JTAG library API covers several functional areas. The jtag @b core communicates through the @b minidriver API with either its full @a driver implementation (src/jtag/jtag_driver.c) or a @a minidriver . Internally, the @b command API is used by the JTAG driver for managing asynchronous transactions. - @subpage jtagcore - @b public API routines - declared in @c src/jtag/jtag.h - used by other modules - @subpage jtagtcl - @b private TCL handling routines - defined in @c src/jtag/tcl.c - registers and handles Jim commands that configure and use the JTAG core - @subpage jtagcmd - @b private command queue API - declared in @c src/jtag/commands.h - provides routines used internally by the full JTAG drivers. - @subpage jtagiface - @b private interface driver API - declared in @c src/jtag/interface.h - used by the core, minidrivers, and the full interface device drivers. - allows implementing new interface device drivers. - includes the Cable/TAP API (commands starting with @c tap_) - @subpage jtagdriver - @b private minidriver API - declared in @c src/jtag/minidriver.h - used @a only by the core and minidriver implementations: - @c jtag_driver.c (in-tree OpenOCD drivers) - future implementations (on other embedded hosts) - interface device drivers do @b not need this API. */ /** @page jtagcore JTAG Core API This section needs to be expanded. */ /** @page jtagtcl JTAG TCL API This section needs to be expanded. */ /** @page jtagcmd JTAG Command API This section needs to be expanded. */ /** @page jtagiface JTAG Interface API This section needs to be expanded. */ /** @page jtagdriver JTAG Minidriver API This section needs to be expanded. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/main.txt ================================================ /** @mainpage OpenOCD Developer's Guide Welcome to the OpenOCD Developer's Guide -- the developer's resource for learning about the internal architecture of the OpenOCD project. @par In addition, this document contains the tactical and strategic plans and processes that have been developed by and for the OpenOCD community. Developers that want to contribute to OpenOCD should read the following sections before starting work: - @subpage thelist enumerates opportunities for improving or extending the OpenOCD platform. If your ideas are on The List, you might check the mailing list archives to find the status of your feature (or bug). - The @subpage styleguide provides rules that developers should follow when writing new code for OpenOCD. - The @subpage patchguide provides policies that developers should follow when submitting patches to the project. - The @subpage bugs page contains the content of the BUGS file, which provides instructions for submitting bug reports to the maintainers. - The @subpage releases page describes the project's release process. - The @subpage endianness provides hints about writing and testing endianness independent code for OpenOCD. @ref primer provide introductory materials for new developers on various specific topics. Finally, the @ref oocd pages explain how the code has been organized into layers of APIs, providing an overview of how they fit together. These pages attempt to give developers a high-level perspective of the various code modules provided by OpenOCD. */ /** @page primer OpenOCD Technical Primers This pages lists Technical Primers available for OpenOCD Developers. They seek to provide information to pull novices up the learning curves associated with the fundamental technologies used by OpenOCD. - @subpage primerdocs - @subpage primerautotools - @subpage primertcl - @subpage primerjtag The above documents should bridge any "ancillary" gaps in contributor knowledge, without having to learn the complete languages or technology. They should provide enough information for experienced developers to learn how to make "correct" changes when creating patches. Beyond the fundamentals, the following primers provide introductory tutorials for OpenOCD's sub-systems. These complement the @ref oocd pages that provide more high-level perspective on related topics. - @subpage primercommand In all cases, these Primers should use idiomatic conventions that the community has agreed are the "right way of doing things". In this respect, these documents typically assume some familiarity with the information contained in one or more @ref styleguide, or they will directly refer to specific style guides as supplemental reading. Contributions or suggestions for new Technical Primers are welcome. */ /** @page oocd OpenOCD Architecture The OpenOCD library consists of several APIs that build together to provide the support functionality. The following list shows how these modules are stacked in the current implementation (from bottom to top): - @subpage helperdocs - @ref helperporting - @ref helperjim - @ref helpercommand - @ref helperlogging - @subpage jtagdocs - @ref jtagcore - @ref jtagtcl - @ref jtagcmd - @ref jtagiface - @ref jtagdriver - @subpage targetdocs - @ref targetarm - @ref targetnotarm - @ref targetmips - @ref targetregister - @ref targetimage - @ref targettrace - @subpage flashdocs - @ref flashcfi - @ref flashnand - @ref flashtarget - @subpage serverdocs - @ref servergdb - @ref servertelnet - @ref serverhttp - @subpage appdocs Obviously, there are some nuances to the stack that are not shown by this linear list of layers. The List of @ref thelist enumerates opportunities for improving or extending the OpenOCD platform. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/primer/autotools.txt ================================================ /** @page primerautotools OpenOCD Autotools Primer This page provides an overview to OpenOCD's use of the GNU autotool suite: - @ref primerautoconf - @ref primerautomake - @ref primerlibtool Most developers do not need to concern themselves with these tools, as the @ref primerbootstrap script runs these tools in the required sequence. @section primerbootstrap Autotools Bootstrap The @c bootstrap script should be used by developers to run the autotools in the correct sequence. When run after a fresh checkout, this script generates the build files required to compile the project, producing the project configure script. @subsection primerbootstrapcures Problems Solved By Bootstrap For example, the build system can fail in unexpected ways after running <code>git pull</code>. Here, the <code>make maintainer-clean</code> should be used to remove all of the files generated by the @c bootstrap script and subsequent build processes. In this particular case, one may also need to remove stray files by hand after running this command to ensure everything is rebuilt properly. This step should be necessary only if the @c maintainer-clean was run @b after altering the build system files with git. If it is run @b before any updates, the build system should never leave artifacts in the tree. Without such precautions, changes can be introduced that leave the tree timestamps in an inconsistent state, producing strange compile errors that are resolve after such diligence. @subsection primermaintainerclean Autotools Cleaning Normally, all files generated by the bootstrap script, configure process, and build system should be removed after running <code>make maintainer-clean</code>. Automatically generated files that remain after this should be listed in @c MAINTAINERCLEANFILES, @c DISTCLEANFILES, or @c CLEANFILES, depending on which stage of the build process they are produced. @section primerautoconf Autoconf Configuration Script The @c autoconf program generates the @c configure script from @c configure.in, using serious Perl voodoo. The resulting script is included in the project distribution packages and run by users to configure the build process for their system. @section primerautomake Automake Makefiles The @c automake program generates @c Makefile.in files (from @c Makefile.am files). These files are later processed by the configure script produced by @c autoconf. @subsection primerautomakenewfiles Creating Makefile.am Files This section shows how to add a @c Makefile.am in a new directory (or one that lacks one). -# The new directory must be listed in the @c SUBDIRS variable in the parent directory's Makefile.am: @code $ echo 'SUBDIRS += directory' >>../Makefile.am @endcode -# Create an bare-bones Makefile.am file in directory that needs it: @code $ echo "MAINTAINERCLEANFILES = Makefile.in" >Makefile.am @endcode -# The @c configure.in script must be updated, so it generates the required Makefile when the @a configure script is run by the user: @verbatim AC_OUTPUT([ ... path/to/new/Makefile ]) @endverbatim Note: these instructions are @b not meant to be used literally, rather they are shown for demonstration purposes. The default MAINTAINERCLEANFILES rule ensures that the automake-generated @c Makefile.in file will be removed when developers run <code>make maintainer-clean</code>. Additional rules may be added after this; however, the project should bootstrap and tear down cleanly after taking these minimal steps, with the new directory being visited during the @c make sequence. @subsection primerautomaketweaks Updating Makefile.am Files Adding, removing, and renaming files from the project tree usually requires updating the autotools inputs. This section will help describe how to do this as questions arise. @section primerlibtool Libtool and Libraries The @c libtool program provides the means of generating libraries in a portable and painless manner (relatively speaking). This section will contain an answer to "what does libtool give OpenOCD?" and "what do developers need to consider in new code?" @section primerautotoolsmation Autotools Automation This section outlines three ways the autotools provides automation to assist with testing and distribution: - @ref primerautocheck -- automatic unit and smoke tests - @ref primerautodistcheck -- automatic distribution and packaging tests @subsection primerautocheck make check The <code>make check</code> command will run the OpenOCD test suite, once it has been integrated as such. This section will contain information about how to extend the testing build system components to implement new checks. @subsection primerautodistcheck make distcheck The <code>make distcheck</code> command produces an archive of the project deliverables (using <code>make dist</code>) and verifies its integrity for distribution by attempting to use the package in the same manner as a user. These checks includes the following steps: -# Unpack the project archive into its expected directory. -# Configure and build the project in a temporary out-of-tree directory. -# Run <code>make check</code> to ensure the distributed code passes all tests. -# Run <code>make install</code> into a temporary installation directory. -# Check that <code>make uninstall</code> removes all files that were installed. -# Check that <code>make distclean</code> removes all files created during all other steps (except the first). If all of these steps complete successfully, the @c make process will output a friendly message indicating the archive is ready to be distributed. */ /** @file This file contains the @ref primerautotools page. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/primer/commands.txt ================================================ /** @page primercommand Command Development Primer This page provides a primer for writing commands by introducing @c hello module. The full source code used in this example can be found in hello.c, and the @ref primercmdcode section shows how to use it. A summary of this information can be found in @ref helpercommand . @section primercmdhandler Command Handlers Defining new commands and their helpers is easy. The following code defines a simple command handler that delegates its argument parsing: @code COMMAND_HANDLER(handle_hello_command) { const char *sep, *name; int retval = CALL_COMMAND_HANDLER(handle_hello_args); if (ERROR_OK == retval) command_print(CMD, "Greetings%s%s!", sep, name); return retval; } @endcode Here, the @c COMMAND_HANDLER macro establishes the function signature, see in command.h by the @c __COMMAND_HANDLER macro. The COMMAND_HELPER macro function allows defining functions with an extended version of the base signature. These helper functions can be called (with the appropriate parameters), the @c CALL_COMMAND_HANDLER macro to pass any e as parameters to the following helper function: The subsequent blocks of code are a normal C function that can do anything, so only complex commands deserve should use command helper functions. In this respect, this example uses one to demonstrate how -- not when -- they should be used. @code static COMMAND_HELPER(handle_hello_args, const char **sep, const char **name) { if (argc > 1) { LOG_ERROR("%s: too many arguments", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; } if (1 == CMD_ARGC) { *sep = ", "; *name = CMD_ARGV[0]; } else *sep = *name = ""; return ERROR_OK; } @endcode Of course, you may also call other macros or functions, but that extends beyond the scope of this tutorial on writing commands. @section primercmdreg Command Registration Before this new function can be used, it must be registered somehow. For a new module, registering should be done in a new function for the purpose, which must be called from @c openocd.c: @code static const struct command_registration hello_command_handlers[] = { { .name = "hello", .mode = COMMAND_ANY, .handler = handle_hello_command, .help = "print a warm greeting", .usage = "[name]", }, { .chain = foo_command_handlers, } COMMAND_REGISTRATION_DONE }; int hello_register_commands(struct command_context_s *cmd_ctx) { return register_commands(cmd_ctx, NULL, handle_command_handlers); } @endcode Note that the "usage" text should use the same EBNF that's found in the User's Guide: literals in 'single quotes', sequences of optional parameters in [square brackets], and alternatives in (parentheses|with|vertical bars), and so forth. No angle brackets. That's it! The command should now be registered and available to scripts. @section primercmdchain Command Chaining This example also shows how to chain command handler registration, so your modules can "inherit" commands provided by other (sub)modules. Here, the hello module includes the foo commands in the same context that the 'hello' command will be registered. If the @c chain field had been put in the 'hello' command, then the @c foo module commands would be registered under it. Indeed, that technique is used to define the 'foo bar' and 'foo baz' commands, as well as for the example drivers that use these modules. The code for the 'foo' command handlers can be found in @c hello.c. @section primercmdcode Trying These Example Commands These commands have been inherited by the dummy interface, faux flash, and testee target drivers. The easiest way to test these is by using the dummy interface. Once OpenOCD has been built with this example code, the following command demonstrates the abilities that the @c hello module provides: @code openocd -c 'interface dummy' \ -c 'dummy hello' \ -c 'dummy hello World' \ -c 'dummy hello {John Doe}' \ -c 'dummy hello John Doe' # error: too many arguments @endcode If saved in @c hello.cfg, then running <code>openocd -f hello.cfg</code> should produce the following output before displaying the help text and exiting: @code Greetings! Greetings, World! Greetings, John Doe! Error: hello: too many arguments Runtime error, file "openocd.cfg", line 14: hello: too many arguments dummy hello [<name>] prints a warm welcome @endcode */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/primer/docs.txt ================================================ /** @page primerdocs OpenOCD Documentation Primers This page provides an introduction to OpenOCD's documentation processes. OpenOCD presently produces several kinds of documentation: - The User's Guide: - Focuses on using the OpenOCD software. - Details the installation, usage, and customization. - Provides descriptions of public Jim/TCL script commands. - Written using GNU texinfo. - Created with 'make pdf' or 'make html'. - See @subpage primertexinfo and @ref styletexinfo. - The References: (as proposed) - Focuses on using specific hardware with OpenOCD. - Details the supported interfaces, chips, boards, and targets. - Provides overview, usage, reference, and FAQ for each device. - Written using LaTeX language with custom macros. - Created with 'make references'. - See @subpage primerlatex and @ref stylelatex. - The Manual: - Focuses on developing the OpenOCD software. - Details the architecture, driver interfaces, and processes. - Provides "full" coverage of C source code (work-in-progress). - Written using Doxygen C language conventions (i.e. in comments). - Created with 'make doxygen'. - See @subpage primerdoxygen and @ref styledoxygen. The following sections provide more information for anyone that wants to contribute new or updated documentation to the OpenOCD project. */ /** @page primertexinfo Texinfo Primer The OpenOCD User's Guide presently exists entirely within the doc/openocd.texi document. That file contains documentation with mark-up suitable for being parsed by the GNU Texinfo utilities (http://www.gnu.org/software/texinfo/). When you add a new command, driver, or driver option, it needs to be documented in the User's Guide. Use the existing documentation for models, but feel free to make better use of Texinfo mechanisms. See the Texinfo web site for the Texinfo manual and more information. OpenOCD style guidelines for Texinfo documentation can be found on the @ref styletexinfo page. */ /** @page primerlatex LaTeX Primer The OpenOCD project provides a number of reference guides using the LaTeX typesetting language. - OpenOCD Quick Reference Sheets - OpenOCD Hardware Reference Guides These documents have not yet been produced, so this Primer serves as a placeholder to describe how they are created and can be extended. The same holds true for the @ref stylelatex page. */ /** @page primerdoxygen Doxygen Primer Doxygen-style comments are used to provide documentation in-line with the OpenOCD source code. These comments are used to document functions, variables, structs, enums, fields, and everything else that might need to be documented for developers. Additional files containing comments that supplement the code comments in order to provide complete developer documentation. Even if you already know Doxygen, please read this Primer to learn how OpenOCD developers already use Doxygen features in the project tree. For more information about OpenOCD's required style for using Doxygen, see the @ref styledoxygen page and look at existing documentation in the @c doc/manual tree. @section primerdoxytext Doxygen Input Files Doxygen has been configured parse all of the C source code files (*.c and *.h) in @c src/ in order to produce a complete reference of all OpenOCD project symbols. In addition to the source code files, other files will also be scanned for comment blocks; some are referenced explicitly by the @c INPUT variable in the Doxygen configuration file. By default, the Doxygen configuration enables a "full" set of features, including generation of dependency graphs (using the GraphViz package). These features may be disabled by editing the @c Doxyfile.in file at the top of the project tree; the configuration file includes comments that provide detailed documentation for each option. To support out-of-tree building of the documentation, the @c Doxyfile.in @c INPUT values will have all instances of the string @c "@srcdir@" replaced with the current value of the make variable <code>$(srcdir)</code>. The Makefile uses a rule to convert @c Doxyfile.in into the @c Doxyfile used by <code>make doxygen</code>. @section primerdoxyoocd OpenOCD Input Files OpenOCD uses the @c INPUT mechanism to include additional documentation to provide The Manual for OpenOCD Developers. These extra files contain high-level information intended to supplement the relatively low-level documentation that gets extracted from the source code comments. OpenOCD's Doxygen configuration file will search for all @c .txt files that can be found under the @c doc/manual directory in the project tree. New files containing valid Doxygen markup that are placed in or under that directory will be detected and included in The Manual automatically. @section primerdoxyman Doxygen Reference Manual The full documentation for Doxygen can be referenced on-line at the project home page: http://www.doxygen.org/index.html. In HTML versions of this document, an image with a link to this site appears in the page footer. */ /** @file This file contains the Doxygen source code for the @ref primerdocs. The @ref primerdocs page also contains the following sections: - @ref primertexinfo - @ref primerlatex - @ref primerdoxygen */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/primer/jtag.txt ================================================ /** @page primerjtag OpenOCD JTAG Primer JTAG is unnecessarily confusing, because JTAG is often confused with boundary scan, which is just one of its possible functions. JTAG is simply a communication interface designed to allow communication to functions contained on devices, for the designed purposes of initialisation, programming, testing, debugging, and anything else you want to use it for (as a chip designer). Think of JTAG as I2C for testing. It doesn't define what it can do, just a logical interface that allows a uniform channel for communication. See @par http://en.wikipedia.org/wiki/Joint_Test_Action_Group @image html jtag-state-machine-large.png The first page (among other things) shows a logical representation describing how multiple devices are wired up using JTAG. JTAG does not specify, data rates or interface levels (3.3V/1.8V, etc) each device can support different data rates/interface logic levels. How to wire them in a compatible way is an exercise for an engineer. Basically TMS controls which shift register is placed on the device, between TDI and TDO. The second diagram shows the state transitions on TMS which will select different shift registers. The first thing you need to do is reset the state machine, because when you connect to a chip you do not know what state the controller is in,you need to clock TMS as 1, at least 5 times. This will put you into "Test Logic Reset" State. Knowing this, you can, once reset, then track what each transition on TMS will do, and hence know what state the JTAG state machine is in. There are 2 "types" of shift registers. The Instruction shift register and the data shift register. The sizes of these are undefined, and can change from chip to chip. The Instruction register is used to select which Data register/data register function is used, and the data register is used to read data from that function or write data to it. Each of the states control what happens to either the data register or instruction register. For example, one of the data registers will be known as "bypass" this is (usually) a single bit which has no function and is used to bypass the chip. Assume we have 3 identical chips, wired up like the picture(wikipedia) and each has a 3 bits instruction register, and there are 2 known instructions (110 = bypass, 010 = "some other function") if we want to use "some other function", on the second chip in the line, and not change the other chips we would do the following transitions. From Test Logic Reset, TMS goes: 0 1 1 0 0 which puts every chip in the chain into the "Shift IR state" Then (while holding TMS as 0) TDI goes: 0 1 1 0 1 0 0 1 1 which puts the following values in the instruction shift register for each chip [110] [010] [110] The order is reversed, because we shift out the least significant bit first. Then we transition TMS: 1 1 1 0 0 which puts us in the "Shift DR state". Now when we clock data onto TDI (again while holding TMS to 0) , the data shifts through the data registers, and because of the instruction registers we selected ("some other function" has 8 bits in its data register), our total data register in the chain looks like this: 0 00000000 0 The first and last bit are in the "bypassed" chips, so values read from them are irrelevant and data written to them is ignored. But we need to write bits for those registers, because they are in the chain. If we wanted to write 0xF5 to the data register we would clock out of TDI (holding TMS to 0): 0 1 0 1 0 1 1 1 1 0 Again, we are clocking the least-significant bit first. Then we would clock TMS: 1 1 0 which updates the selected data register with the value 0xF5 and returns us to run test idle. If we needed to read the data register before over-writing it with F5, no sweat, that's already done, because the TDI/TDO are set up as a circular shift register, so if you write enough bits to fill the shift register, you will receive the "captured" contents of the data registers simultaneously on TDO. That's JTAG in a nutshell. On top of this, you need to get specs for target chips and work out what the various instruction registers/data registers do, so you can actually do something useful. That's where it gets interesting. But in and of itself, JTAG is actually very simple. @section primerjtagmore More Reading A separate primer contains information about @subpage primerjtagbs for developers that want to extend OpenOCD for such purposes. */ /** @page primerjtagbs JTAG Boundary Scan Primer The following page provides an introduction on JTAG that focuses on its boundary scan capabilities: @par http://www.engr.udayton.edu/faculty/jloomis/ece446/notes/jtag/jtag1.html OpenOCD does not presently have clear means of using JTAG for boundary scan testing purposes; however, some developers have explored the possibilities. The page contains information that may be useful to those wishing to implement boundary scan capabilities in OpenOCD. @section primerbsdl The BSDL Language For more information on the Boundary Scan Description Language (BSDL), the following page provides a good introduction: @par http://www.radio-electronics.com/info/t_and_m/boundaryscan/bsdl.php @section primerbsdlvendors Vendor BSDL Files NXP LPC: @par http://www.standardics.nxp.com/support/models/lpc2000/ Freescale PowerPC: @par http://www.freescale.com/webapp/sps/site/overview.jsp?code=DRPPCBSDLFLS Freescale i.MX1 (too old): @par http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=i.MX1&nodeId=0162468rH311432973ZrDR&fpsp=1&tab=Design_Tools_Tab Renesas R32C/117: @par http://sg.renesas.com/fmwk.jsp?cnt=r32c116_7_8_root.jsp&fp=/products/mpumcu/m16c_family/r32c100_series/r32c116_7_8_group/ - The device page does not come with BSDL file; you have to register to download them. @par http://www.corelis.com/support/BSDL.htm TI links theirs right off the generic page for each chip; this may be the case for other vendors as well. For example: - DaVinci DM355 -- http://www.ti.com/litv/zip/sprm262b - DaVinci DM6446 - 2.1 silicon -- http://www.ti.com/litv/zip/sprm325a - older silicon -- http://www.ti.com/litv/zip/sprm203 - OMAP 3530 - CBB package -- http://www.ti.com/litv/zip/sprm315b - 515 ball s-PGBA, POP, 0.4mm pitch - CUS package -- http://www.ti.com/litv/zip/sprm314a - 515 ball s-PGBA, POP, 0.5mm pitch - CBC package -- http://www.ti.com/litv/zip/sprm346 - 423 ball s-PGBA, 0.65mm pitch Many other files are available in the "Semiconductor Manufacturer's BSDL files" section of the following site: @par http://www.freelabs.com/~whitis/electronics/jtag/ */ /** @file This file contains the @ref primerjtag and @ref primerjtagbs page. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/primer/tcl.txt ================================================ /** @page primertcl OpenOCD TCL Primer The @subpage scripting page provides additional TCL Primer material. @verbatim **************************************** **************************************** This is a short introduction to 'un-scare' you about the language known as TCL. It is structured as a guided tour through the files written by me [Duane Ellis] - in early July 2008 for OpenOCD. Which uses the "JIM" embedded Tcl clone-ish language. Thing described here are *totally* TCL generic... not Jim specific. The goal of this document is to encourage you to add your own set of chips to the TCL package - and most importantly you should know where you should put them - so they end up in an organized way. --Duane Ellis. duane@duaneellis.com **************************************** **************************************** Adding "chip" support - Duane Ellis July 5 - 2008. The concept is this: In your "openocd.cfg" file add something like this: source [find tcl/chip/VENDOR/FAMILY/NAME.tcl] For example... source [find tcl/chip/atmel/at91/at91sam7x256.tcl] You'll notice that it makes use of: tcl/cpu/arm/<NAME>.tcl. Yes, that is where you should put "core" specific things. Be careful and learn the difference: THE "CORE" - is not the entire chip! Definition: That "file" listed above is called a "CHIP FILE". It may be standalone, or may need to "source" other "helper" files. The reference [7/5/2008] is the at91sam7x256.tcl file. **************************************** **************************************** === TCL TOUR === Open: at91sam7x256.tcl === TCL TOUR === A walk through --- For those who are new to TCL. Examine the file: at91sam7x256.tcl It starts with: source [find path/filename.tcl] In TCL - this is very important. Rule #1 Everything is a string. Rule #2 If you think other wise See #1. Reminds you of: Rule #1: The wife is correct. Rule #2: If you think otherwise, See #1 Any text contained inside of [square-brackets] is just like `back-ticks` in BASH. Hence, the [find FILENAME] executes the command find with a single parameter the filename. ======================================== Next you see a series of: set NAME VALUE It is mostly "obvious" what is going on. Exception: The arrays. You would *THINK* Tcl supports arrays. In fact, multi-dim arrays. That is false. For the index for"FLASH(0,CHIPSELECT)" is actually the string "0,CHIPSELECT". This is problematic. In the normal world, you think of array indexes as integers. For example these are different: set foo(0x0c) 123 set foo(12) 444 Why? Because 0x0c {lowercase} is a string. Don't forget UPPER CASE. You must be careful - always... always... use simple decimal numbers. When in doubt use 'expr' the evaluator. These are all the same. set x 0x0c set foo([expr $x]) "twelve" set x 12 set foo([expr $x]) "twelve" set x "2 * 6" set foo([expr $x]) "twelve" ************************************************** *************************************************** === TCL TOUR === Open the file: "bitsbytes.tcl" There is some tricky things going on. =============== First, there is a "for" loop - at level 0 {level 0 means: outside of a procedure/function} This means it is evaluated when the file is parsed. == SIDEBAR: About The FOR command == In TCL, "FOR" is a funny thing, it is not what you think it is. Syntactically - FOR is a just a command, it is not language construct like for(;;) in C... The "for" command takes 4 parameters. (1) The "initial command" to execute. (2) the test "expression" (3) the "next command" (4) the "body command" of the FOR loop. Notice I used the words "command" and "expression" above. The FOR command: 1) executes the "initial command" 2) evaluates the expression if 0 it stops. 3) executes the "body command" 4) executes the "next command" 5) Goto Step 2. As show, each of these items are in {curly-braces}. This means they are passed as they are - KEY-POINT: unevaluated to the FOR command. Think of it like escaping the backticks in Bash so that the "underlying" command can evaluate the contents. In this case, the FOR COMMAND. == END: SIDEBAR: About The FOR command == You'll see two lines: LINE1: set vn [format "BIT%d" $x] Format is like "sprintf". Because of the [brackets], it becomes what you think. But here's how: First - the line is parsed - for {braces}. In this case, there are none. Then, the parser looks for [brackets] and finds them. The parser then evaluates the contents of the [brackets], and replaces them. It is similar to this bash statement. EXPORT vn=`date` LINE 2 & 3 set $vn [expr {1024 * $x}] global $vn In line 1, we dynamically created a variable name. Here, we are assigning it a value. Lastly Line 3 we force the variable to be global, not "local" within the "for command body" =============== The PROCS proc create_mask { MSB LSB } { ... body .... } Like "for" - PROC is really just a command that takes 3 parameters. The (1) NAME of the function, a (2) LIST of parameters, and a (3) BODY Again, this is at "level 0" so it is a global function. (Yes, TCL supports local functions, you put them inside of a function} You'll see in some cases, I nest [brackets] a lot and in others I'm lazy or wanted it to be more clear... it is a matter of choice. =============== ************************************************** *************************************************** === TCL TOUR === Open the file: "memory.tcl" =============== Here is where I setup some 'memory definitions' that various targets can use. For example - there is an "unknown" memory region. All memory regions must have 2 things: (1) N_<name> (2) NAME( array ) And the array must have some specific names: ( <idx>, THING ) Where: THING is one of: CHIPSELECT BASE LEN HUMAN TYPE RWX - the access ability. WIDTH - the accessible width. i.e.: Some regions of memory are not 'word' accessible. The function "address_info" - given an address should tell you about the address. [as of this writing: 7/5/2008 I have done only a little bit with this -Duane] === MAJOR FUNCTION: == proc memread32 { ADDR } proc memread16 { ADDR } proc memread8 { ADDR } All read memory - and return the contents. [ FIXME: 7/5/2008 - I need to create "memwrite" functions] ************************************************** *************************************************** === TCL TOUR === Open the file: "mmr_helpers.tcl" =============== This file is used to display and work with "memory mapped registers" For example - 'show_mmr32_reg' is given the NAME of the register to display. The assumption is - the NAME is a global variable holding the address of that MMR. The code does some tricks. The [set [set NAME]] is the TCL way of doing double variable interpolation - like makefiles... In a makefile or shell script you may have seen this: FOO_linux = "Penguins rule" FOO_winXP = "Broken Glass" FOO_mac = "I like cat names" # Pick one BUILD = linux #BUILD = winXP #BUILD = mac FOO = ${FOO_${BUILD}} The "double [set] square bracket" thing is the TCL way, nothing more. ---- The IF statement - and "CATCH" . Notice this IF COMMAND - (not statement) is like this: [7/5/2008 it is this way] if ![catch { command } msg ] { ...something... } else { error [format string...] } The "IF" command expects either 2 or 4 parameters. === Sidebar: About "commands" === Take a look at the internals of "jim.c" Look for the function: Jim_IfCoreCommand() And all those other "CoreCommands" You'll notice - they all have "argc" and "argv" Yea, the entire thing is done that way. IF is a command. SO is "FOR" and "WHILE" and "DO" and the others. That is why I keep using the phase it is a "command" === END: Sidebar: About "commands" === Parameter 1 to the IF command is expected to be an expression. As such, I do not need to wrap it in {braces}. In this case, the "expression" is the result of the "CATCH" command. CATCH - is an error catcher. You give CATCH 1 or 2 parameters. The first 1st parameter is the "code to execute" The 2nd (optional) is where to put the error message. CATCH returns 0 on success, 1 for failure. The "![catch command]" is self explanatory. The 3rd parameter to IF must be exactly "else" or "elseif" [I lied above, the IF command can take many parameters they just have to be joined by exactly the words "else" or "elseif". The 4th parameter contains: "error [format STRING....]" This lets me modify the previous lower level error by tacking more text onto the end of it. In this case, i want to add the MMR register name to make my error message look better. --------- Back to something inside show_mmr32_reg{}. You'll see something 'set fn show_${NAME}_helper' Here I am constructing a 'function name' Then - I look it up to see if it exists. {the function: "proc_exists" does this} And - if it does - I call the function. In "C" it is a lot like using: 'sprintf()' to construct a function name string, then using "dlopen()" and "dlsym()" to look it up - and get a function pointer - and calling the function pointer. In this case - I execute a dynamic command. You can do some cool tricks with interpretors. ---------- Function: show_mmr32_bits() In this case, we use the special TCL command "upvar" which tcl's way of passing things by reference. In this case, we want to reach up into the callers lexical scope and find the array named "NAMES" The rest of the function is pretty straight forward. First - we figure out the longest name. Then print 4 rows of 8bits - with names. ************************************************** *************************************************** === TCL TOUR === Open the file: "chips/atmel/at91/usarts.tcl" =============== First - about the AT91SAM series - all of the usarts are basically identical... Second - there can be many of them. In this case - I do some more TCL tricks to dynamically create functions out of thin air. Some assumptions: The "CHIP" file has defined some variables in a proper form. i.e.: AT91C_BASE_US0 - for usart0, AT91C_BASE_US1 - for usart1 ... And so on ... Near the end of the file - look for a large "foreach" loop that looks like this: foreach WHO { US0 US1 US2 US3 US4 .... } { } In this case, I'm trying to figure out what USARTs exist. Step 1 - is to determine if the NAME has been defined. i.e.: Does AT91C_BASE_USx - where X is some number exist? The "info exists VARNAME" tells you if the variable exists. Then - inside the IF statement... There is another loop. This loop is the name of various "sub-registers" within the USART. Some more trick are played with the [set VAR] backtick evaluation stuff. And we create two variables We calculate and create the global variable name for every subregister in the USART. And - declare that variable as GLOBAL so the world can find it. Then - we dynamically create a function - based on the register name. Look carefully at how that is done. You'll notice the FUNCTION BODY is a string - not something in {braces}. Why? This is because we need TCL to evaluate the contents of that string "*NOW*" - when $vn exists not later, when the function "show_FOO" is invoked. Lastly - we build a "str" of commands - and create a single function - with the generated list of commands for the entire USART. With that little bit of code - I now have a bunch of functions like: show_US0, show_US1, show_US2, .... etc ... And show_US0_MR, show_US0_IMR ... etc... And - I have this for every USART... without having to create tons of boiler plate yucky code. **************************************** **************************************** END of the Tcl Intro and Walk Through **************************************** **************************************** FUTURE PLANS Some "GPIO" functions... @endverbatim */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/release.txt ================================================ /** @page releases Release Processes This page provides an introduction to the OpenOCD Release Processes: - @ref releasewhy - Explain the motivations for producing releases on a regular basis. - @ref releasewho - Describes the responsibilities and authority required to produce official OpenOCD releases. - @ref releasewhen - Provides guidelines for scheduling activities for each release cycle. - @ref releasehow - Outlines all of the steps for the processes used to produce and release the package source archives. - @ref releasescriptcmds - Introduces the automated @c release.sh script. @section releasewhy Why Produce Releases? The OpenOCD maintainers produce <i>releases</i> periodically for many reasons. This section provides the key reasons for making releases on a regular basis and why a set of <i>release processes</i> should be used to produce them. At any time, <i>source archives</i> can be produced by running <code>make dist</code> in the OpenOCD project tree. With the 0.2.0 release, this command will package the tree into several popular archive formats: <code>openocd-\<version\>.{tar.gz,tar.bz2,zip}</code>. If produced properly, these files are suitable for release to the public. When properly versioned and released for users, these archives present several important advantages compared to using the source repository (including snapshots downloaded from that repository using gitweb): -# They allow others to package and distribute the code using consistent version labels. Users won't normally need to care whose package they use, just the version of OpenOCD. -# They contain a working configure script and makefiles, which were produced as part of creating the archive. -# Because they have been formally released by the project, users don't need to try a random work-in-process revision. Releasing involves spending some time specifically on quality improvements, including bugfixing source code and documentation. -# They provide developers with the flexibility needed to address larger issues, which sometimes involves temporary breakage. Hopefully, this shows several good reasons to produce regular releases, but the release processes were developed with some additional design goals in mind. Specifically, the releases processes should have the following properties: -# Produce successive sets of archives cleanly and consistently. -# Implementable as a script that automates the critical steps. -# Prevent human operators from producing broken packages, when possible. -# Allow scheduling and automation of building and publishing milestones. The current release processes are documented in the following sections. They attempt to meet these design goals, but improvements may still need to be made. @subsection version_labels Version Labels Users can display the OpenOCD version string in at least two ways. The command line <code>openocd -v</code> invocation displays it; as does the Tcl <code>version</code> command. Labels for released versions look like <em>0.3.0</em>, or <em>0.3.0-rc1</em> for a preliminary release. Non-released (developer) versions look like <em>0.3.0-dev</em>, or <em>0.3.0-rc1-dev</em>. In all cases, additional tags may be appended to those base release version labels. The <code>tools/release/version.sh</code> script is used to manipulate version IDs found in the source tree. @subsubsection releaseversions Release Versions and Tags The OpenOCD version string is composed of three numeric components separated by two decimal points: @c x.y.z, where @c x is the @a major version number, @c y is the @a minor number, and @c z is the @a micro. For any <em>bug-fix</em> release, the micro version number will be non-zero (<code>z > 0</code>). For a <i>minor release</i>, the micro version number will be zero (<code>z = 0</code>). For a <i>major releases</i>, the minor version will @a also be zero (<code>y = 0, z = 0</code>). After these required numeric components, release version strings may contain tags such as <em>-rc1</em> or <em>-rc2</em>. These 'rc' tags indicate "release candidate" versions of the package. Like major/minor/micro numbers, these are updated as part of the release process. The release process includes version number manipulations to the tree being released, ensuring that all numbers are incremented (or rolled over) at the right time and in the proper locations of the repository. One of those manipulations creates a repository tag matching that release's version label. @subsubsection releaseversionsdist Packager Versions Distributors of patched versions of OpenOCD are encouraged to extend the version string with a unique version tag when producing external releases, as this helps to identify your particular distribution series. Knowing that a release has such patches can be essential to tracking down and fixing bugs. Packager version tags should always be suffixes to the version code from the OpenOCD project, signifying modifications to the original code base. Each packager release should have a unique version. For example, the following command will add a 'foo' tag to the configure.ac script of a local copy of the source tree, giving a version label like <em>0.3.0-foo</em>: @code tools/release/version.sh tag add foo @endcode This command will modify the configure.ac script in your working copy only. After running the @c bootstrap sequence, the tree can be patched and used to produce your own derived versions. You might check that change into a private branch of your git tree, along with the other patches you are providing. You can also "bump" those tags (so "foo1" becomes "foo2" etc) each time a derived package is released, incrementing the tag's version to facilitate tracking the changes you have distributed. @code tools/release/version.sh bump tag foo @endcode Of course, any patches in your branches must be provided to your customers, and be in conformance with the GPL. In most cases you should also work to merge your improvements to the mainline tree. @subsubsection version_tags Development Versions and Tags Everything except formal releases should have the tag <em>-dev</em> in their version number. This helps developers identify reports created from non-release versions, and it can be detected and manipulated by the release script. Specifically, this tag will be removed and re-added during the release process; it should never be manipulated by developers in submitted patches. Versions built from developer trees may have additional tags. Trees built from git snapshots have <em>snapshot</em> tags. When built from a "live" git tree, tags specify specific git revisions: 0.3.0-rc1-dev-00015-gf37c9b8-dirty indicates a development tree based on git revision f37c9b8 (a truncated version of a SHA1 hash) with some non-git patches applied (the <em>dirty</em> tag). This information can be useful when tracking down bugs. (Note that at this writing, the tags do not directly correspond to <code>git describe</code> output. The hash ID can be used with <code>git show</code>, but the relevant repository tag isn't <em>0.3.0-rc1-dev</em>; this might change in the future.) @section releasewho Release Manager OpenOCD archive releases will be produced by an individual filling the role of <i>Release Manager</i>, hereafter abbreviated as <i>RM</i>. This individual determines the schedule and executes the release processes for the community. @subsection releasewhohow RM Authority Each release requires one individual to fulfill the RM role; however, graceful transitions of this authority may take place at any time. The current RM may transfer their authority to another contributor in a post to the OpenOCD development mailing list. Such delegation of authority must be approved by the individual that will receive it and the community of maintainers. Initial arrangements with the new RM should be made off-list, as not every contributor wants these responsibilities. @subsection releasewhowhat RM Responsibilities In addition to the actual process of producing the releases, the RM is responsible for keeping the community informed of all progress through the release cycle(s) being managed. The RM is responsible for managing the changes to the package version, though the release tools should manage the tasks of adding or removing any required development branch tags and incrementing the version. These responsibilities matter most towards the end of the release cycle, when the RM creates the first RC and all contributors enter a quality-improvement mode. The RM works with other contributors to make sure everyone knows what kinds of fixes should merge, the status of major issues, and the release timetable. In particular, the RM has the final decision on whether a given bug should block the release. @section releasewhen Release Schedule The OpenOCD release process must be carried out on a periodic basis, so the project can realize the benefits presented in answer to the question, @ref releasewhy. Starting with the 0.2.0 release, the OpenOCD project expects to produce new releases every few months. Bug fix releases could be provided more frequently. These release schedule goals may be adjusted in the future, after the project maintainers and distributors receive feedback and experience. More importantly, the statements made in this section do not create an obligation by any member of the OpenOCD community to produce new releases on regular schedule, now or in the future. @subsection releasewhenexample Sample Schedule The RM must pro-actively communicate with the community from the beginning of the development cycle through the delivery of the new release. This section presents guidelines for scheduling key points where the community must be informed of changing conditions. If Tn is the time of release n, then the following schedule might describe some key T0-to-T1 release cycle milestones. - T0 ... End of T0 release cycle. T1 cycle starts, with merge window opening. Developers begin to merge queued work. - <em>... several weeks of merge window ...</em> - RC1 ... Close mainline to new work. Produce RC1 release, begin testing phase; developers are in "bugfix mode", all other work is queued; send out planned endgame schedule. - RC2 ... Produce RC2 and send schedule update to mailing list, listing priorities for remaining fixes - <em>... more RC milestones, until ready ...</em> - T1: End of T1 release cycle. T2 cycle starts, with merge window opening. Developers begin to merge queued work. Note that until it happens, any date for T1 is just a goal. Critical bugs prevent releases from happening. We are just beginning to use this window-plus-RCs process, so the lengths of the merge windows versus the RC phase is subject to change. Most projects have RC phases of a month or more. Some additional supplemental communication will be desirable. The above list omits the step-by-step instructions to daily release management. Individuals performing release management need to have the ability to interact proactively with the community as a whole, anticipating when such interaction will be required and giving ample notification. The next section explains why the OpenOCD project allows significant flexibility in the part of the development that precedes the release process. @subsection releasewhenflex Schedule Flexibility The Release Manager should attempt to follow the guidelines in this document, but the process of scheduling each release milestone should be community driven at the start. Features that don't complete before the merge window closes can be held (perhaps in some branch) until the next merge window opens, rather than delaying the release cycle. The Release Manager cannot schedule the work that will be done on the project, when it will be submitted, reviewed, and deemed suitable to be committed. That is, the RM cannot act as a priest in a cathedral; OpenOCD uses the bazaar development model. The release schedule must adapt continuously in response to changes in the rate of work. Fewer releases may be required if developers contribute less patches, and more releases may be desirable if the project continues to grow and experience high rates of community contribution. During each cycle, the RM should be tracking the situation and gathering feedback from the community. @section releasehow Release Process: Step-by-Step The release process is not final; it may need more iterations to work out bugs. While there are release scripts, key steps require community support; the Release Manager isn't the only participant. The following steps should be followed to produce each release: -# Produce final patches using a local clone of mainline. Nobody except the RM should be committing anything. <em>Everyone with commit privileges needs to know and agree to this in advance!</em> Even the RM only commits a handful of updates as part of the release process itself ... to files which are part of the version identification scheme or release process; and to create the version tag; and then to open the merge window for the next release cycle. -# Finalize @c the NEWS file to describe the changes in the release - This file is used to automatically post "blurbs" about the project. - This material should have been produced during the development cycle, by adding items for each @c NEWS-worthy contribution, when committed during the merge window. (One part of closing the merge window, by opening the RC phase of the release, is the commitment to hold all further such contributions until the next merge window opens.) - The RM should make sure nothing important was omitted, as part of the RC1 cycle. From then on, no more updates to NEWS content should be needed (except to seed the process for the next release, or maybe if a significant and longstanding bug is fixed late in the RC phase). -# Bump library version if our API changed (not yet required) -# Update and commit the final package version in @c configure.ac: (The <code>tools/release/version.sh</code> script might help ensure the versions are named properly.): -# Remove @c -dev tag. -# Update any @c -rc tag: - If producing the final release from an -rc series, remove it - If producing the first RC in a series, add rc1 - If producing the next RC in a series, bump the rc number -# Commit that version change, with a good descriptive comment. -# Create a git tag for the final commit, with a tag name matching the version string in <code>configure.ac</code> (including <em>-rcN</em> where relevant): @verbatim PACKAGE_VERSION="x.y.z" PACKAGE_TAG="v${PACKAGE_VERSION}" git tag -m "The openocd-${PACKAGE_VERSION} release." "${PACKAGE_TAG}" @endverbatim -# Do not push those changes to mainline yet; only builds using the source archives you will be creating should ever be labeled as official releases (with no "-dev" suffix). Since mainline is a development tree, these will be pushed later, as part of opening the merge window for the next release cycle (restoring the "-dev" suffix for that next release.) Those version and tag updates are the last ones to be included in the release being made. -# Produce the release files, using the local clone of the source tree which holds the release's tag and updated version in @c configure.ac ... this is used only to produce the release, and all files should already be properly checked out. -# Run <code>tools/release.sh package</code> to produce the source archives. This automatically bootstraps and configures the process. -# Run <code>tools/release.sh stage</code> to create an @c archives directory with the release data, including MD5 and SHA1 checksum files. -# Sanity check at least one of those archives, by extracting and configuring its contents, using them to build a copy of OpenOCD, and verifying that the result prints the correct release version in its startup banner. (For example, "configure --enable-parport" then "make" and run "src/openocd -v" as a sanity check.) -# Run <code>make docs</code> to create the documentation which will be published. -# Upload packages and post announcements of their availability: -# Release packages into files section of project sites: - SF.net: -# Under "Project Admin", use the "File Manager" -# Create a new folder under "openocd" named "${PACKAGE_VERSION}" -# Upload the @c NEWS file and mark it as the release notes. -# Upload the three source archive files, using the Web interface, into that folder. Verify the upload worked OK by checking the MD5 and SHA1 checksums computed by SourceForge against the versions created as part of staging the release. -# Also upload doc/openocd.pdf (the User's Guide) so the version matching each release will be easily available. -# Select each file in the release, and use the property panel to set its type and select the right release notes. - .tar.bz2: Linux, Mac - .tar.gz: BSD, Solaris, Others - .zip: Windows - For openocd.pdf just associate it with the right release notes. -# Create an SF.net project news update. -# Depending on how paranoid you're feeling today, verify the images by downloading them from the websites and making sure there are no differences between the downloaded copies and your originals. -# Publish User's and Developer's Guides to the project web sites: -# Use SCP to update the SF.net web site with PDF and HTML for the User's Guide, and HTML for the developer's guide ... you can instantiate a shell.sourceforge.net instance and set up symlinks from your home directory, to simplify this process. -# Post announcement e-mail to the openocd-development list. -# optionally: -# Post an update on the OpenOCD blog. -# Announce updates on freshmeat.net and other trackers. -# Submit updates to news feeds (e.g. Digg, Reddit, etc.). -# Resume normal development on mainline, by opening the merge window for the next major or minor release cycle. (You might want to do this before all the release bits are fully published.) - Update the version label in the @c configure.ac file: - Restore @c -dev version tag. - For a new minor release cycle, increment the release's minor number - For a new major release cycle, increment the release's major number and zero its minor number - Archive @c NEWS file as "<code>doc/news/NEWS-${PACKAGE_VERSION}</code>". - Create a new @c NEWS file for the next release - Commit those changes. - Push all the updates to mainline. - Last updates for the release, including the release tag (you will need to "git push --tags"). - Updates opening the merge window - At this point, it's OK for committers to start pushing changes which have been held off until the next release. (Any bugfixes to this release will be against a bug-fix release branch starting from the commit you tagged as this release, not mainline.) - Announce to the openocd-development list. Ideally, you will also be able to say who is managing the next release cycle. To start a bug-fix release branch: -# Create a new branch, starting from a major or minor release tag -# Restore @c -dev version tag. -# Bump micro version number in configure.ac -# Backport bugfix patches from mainline into that branch. (Always be sure mainline has the fix first, so it's hard to just lose a bugfix.) -# Commit and push those patches. -# When desired, release as above ... except note that the next release of a bugfix branch is never a new major or minor release @subsection releasescriptcmds Release Script Commands The @c release.sh script automates some of the steps involved in making releases, simplifying the Release Manager's work. The release script can be used for two tasks: - Creating releases and starting a new release cycle: @code git checkout master tools/release.sh --type=minor --final --start-rc release @endcode - Creating a development branch from a tagged release: @code git checkout 'v0.2.0' tools/release.sh --type=micro branch @endcode Both of these variations make automatic commits and tags in your repository, so you should be sure to run it on a cloned copy before proceeding with a live release. @subsection releasescriptopts Release Script Options The @c release.sh script recognizes some command-line options that affect its behavior: - The @c --start-rc indicates that the new development release cycle should start with @c -rc0. Without this, the @c -rc tag will be omitted, leading to non-monotonic versioning of the in-tree version numbers. - The @c --final indicates that the release should drop the @c -rc tag, to going from @c x.y.z-rcN-dev to x.y.z. @subsection releasescriptenv Release Script Environment The @c release.sh script recognizes some environment variables which affect its behavior: - @c CONFIG_OPTS : Passed as options to the configure script. - @c MAKE_OPTS : Passed as options to the 'make' processes. @section releasetutorial Release Tutorials This section should contain a brief tutorial for using the Release Script to perform release tasks, but the new script needs to be used for 0.3.0. @section releasetodo Release Script Shortcomings Improved automated packaging and distribution of OpenOCD requires more patching of the configure script. The final release script should be able to manage most steps of the processes. The steps requiring user input could be guided by an "assistant" that walks the Release Manager through the process from beginning to end, performing basic sanity checks on their various inputs (e.g. the @c NEWS blurb). */ /** @file This file contains the @ref releases page. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/scripting.txt ================================================ /** @page scripting Scripting Overview @section scriptingisnt What scripting will not do The scripting support is intended for developers of OpenOCD. It is not the intention that normal OpenOCD users will use tcl scripting extensively, write lots of clever scripts, or contribute back to OpenOCD. Target scripts can contain new procedures that end users may tinker to their needs without really understanding tcl. Since end users are not expected to mess with the scripting language, the choice of language is not terribly important to those same end users. Jim Tcl was chosen as it was easy to integrate, works great in an embedded environment and Øyvind Harboe had experience with it. @section scriptinguses Uses of scripting Default implementation of procedures in tcl/procedures.tcl. - Polymorphic commands for target scripts. - there will be added some commands in Tcl that the target scripts can replace. - produce \<productionfile\> \<serialnumber\>. Default implementation is to ignore serial number and write a raw binary file to beginning of first flash. Target script can dictate file format and structure of serialnumber. Tcl allows an argument to consist of e.g. a list so the structure of the serial number is not limited to a single string. - reset handling. Precise control of how srst, trst & tms is handled. - replace some parts of the current command line handler. This is only to simplify the implementation of OpenOCD and will have no externally visible consequences. Tcl has an advantage in that it's syntax is backwards compatible with the current OpenOCD syntax. - external scripting. Low level tcl functions will be defined that return machine readable output. These low level tcl functions constitute the tcl api. flash_banks is such a low level tcl proc. "flash banks" is an example of a command that has human readable output. The human readable output is expected to change in between versions of OpenOCD. The output from flash_banks may not be in the preferred form for the client. The client then has two choices a) parse the output from flash_banks or b) write a small piece of tcl to output the flash_banks output to a more suitable form. The latter may be simpler. @section scriptingexternal External scripting The embedded Jim Tcl interpreter in OpenOCD is very limited compared to any full scale PC hosted scripting language. The goal is to keep the internal Jim Tcl interpreter as small as possible and allow any advanced scripting, especially scripting that interacts with the host, run on the host and talk to OpenOCD via the TCP/IP scripting connection. Another problem with Jim Tcl is that there is no debugger for it. With a bit of trickery it should be possible to run Jim Tcl scripts under a Tcl interpreter on a PC. The advantage would be that the Jim Tcl scripts could be debugged using a standard PC Tcl debugger. The rough idea is to write an unknown proc that sends unknown commands to OpenOCD. Basically a PC version of startup.tcl. Patches most gratefully accepted! :-) */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/server.txt ================================================ /** @page serverdocs OpenOCD Server APIs OpenOCD provides support for implementing different types of servers. Presently, the following servers have APIs that can be used. - @subpage servergdb - @subpage servertelnet - @subpage serverhttp @section serverdocsoverview Overview What follows is a development history, and describes some of the intent of why certain features exist within OpenOCD along with the reasoning behind them. This roadmap section was written May 2009 - about 9 to 12 months after some of this work had started, it attempts to document some of the reasons why certain features exist within OpenOCD at that time. @section serverdocsbg Background In early 2008, Oyvind Harboe and Duane Ellis had talked about how to create a reasonable GUI for OpenOCD - something that is non-invasive, simple to use and maintain, and does not tie OpenOCD to many other packages. It would be wrong to "spider web" requirements into other external packages. That makes it difficult for developers to write new code and creates a support nightmare. In many ways, people had talked about the need for some type of high-level interface to OpenOCD, because they only had two choices: - the ability to script: via an external program the actions of OpenOCD. - the ability to write a complex internal commands: native 'commands' inside of OpenOCD was complicated. Fundamentally, the basic problem with both of those would be solved with a script language: -# <b>Internal</b>: simple, small, and self-contained. -# <b>Cross Language</b>: script friendly front-end -# <b>Cross Host</b>: GUI Host interface -# <b>Cross Debugger</b>: GUI-like interface What follows hopefully shows how the plans to solve these problems materialized and help to explain the grand roadmap plan. @subsection serverdocsjim Why JimTCL? The Internal Script Language At the time, the existing "command context schema" was proving itself insufficient. However, the problem was also considered from another direction: should OpenOCD be first class and the script second class? Which one rules? In the end, OpenOCD won, the conclusion was that simpler will be better. Let the script language be "good enough"; it would not need numerous features. Imagine debugging an embedded Perl module while debugging OpenOCD. Yuck. OpenOCD already has a complex enough build system, why make it worse? The goal was to add a simple language that would be moderately easy to work with and be self-contained. JimTCL is a single C and single H file, allowing OpenOCD to avoid the spider web of dependent packages. @section serverdocstcl TCL Server Port The TCL Server port was added in mid-2008. With embedded TCL, we can write scripts internally to help things, or we can write "C" code that interfaces well with TCL. From there, the developers wanted to create an external front-end that would be @a very usable and that @a any language could utilize, allowing simple front-ends to be (a) cross-platform (b) language agnostic, and (c) easy to develop and use. Simple ASCII protocols are easy. For example, HTTP, FTP (control), and SMTP are all text-based. All of these examples are widely and well-known, and they do not require high-speed or high-volume. They also support a high degree of interoperability with multiple systems. They are not human-centric protocols; more correctly, they are rigid, terse, simple ASCII protocols that are easily parsable by a script. Thus, the TCL server -- a 'machine' type socket interface -- was added with the hope was it would output simple "name-value" pair type data. At the time, simple name/value pairs seemed reasonably easier to do at the time, though Maybe it should output JSON; See here: http://www.mail-archive.com/openocd-development%40lists.berlios.de/msg00248.html The hope was that one could write a script in what ever language you want and do things with it! @section serverdocsgui GUI Like Interfaces A lot has been said about various "widigit-foo-gui-library is so wonderful". Please refer back to the domino and spider web problem of dependencies. Sure, you may well know the WhatEver-GUI library, but most others will not (including the next contributor to OpenOCD). How do we solve that problem? For example, Cygwin can be painful, Cygwin GUI packages want X11 to be present, crossing the barrier between MinGW and Cygwin is painful, let alone getting the GUI front end to work on MacOS, and Linux, yuck yuck yuck. Painful, very very painful. What works easier and is less work is what is already present in every platform? The answer: A web browser. In other words, OpenOCD could serve out embedded web pages via "localhost" to your browser. Long before OpenOCD had a TCL command line, Zylin AS built their ZY1000 device with a built-in HTTP server. Later, they were willing to both contribute and integrate most of that work into the main tree. @subsection serverdocsother Other Options Considered What if a web browser is not acceptable i.e.: You want to write your own front gadget in Eclipse, or KDevelop, or PerlTK, Ruby, or what ever the latest and greatest Script De Jour is. - Option 1: Can we transport this extra data through the GDB server protocol? In other words, can we extend the GDB server protocol? No, Eclipse wants to talk to GDB directly and control the GDB port. - Option 2: SWIG front end (libopenocd): Would that work? That's painful - unless you design your api to be very simplistic - every language has it's own set of wack-ness, parameter marshaling is painful. What about "callbacks" and structures, and other mess. Imagine debugging that system. When JimTCL was introduced Spencer Oliver had quite a few well-put concerns (Summer 2008) about the idea of "TCL" taking over OpenOCD. His concern is and was: how do you debug something written in 2 different languages? A "SWIG" front-end is unlikely to help that situation. @subsection serverdoccombined Combined: Socket & WebServer Benefits Seriously think about this question: What script language (or compiled language) today cannot talk directly to a socket? Every thing in the OpenOCD world can work a socket interface. Any host side tool can talk to Localhost or remote host, however one might want to make it work. A socket interface is very simple. One could write a Java application and serve it out via the embedded web server, could it - or something like it talk to the built in TCL server? Yes, absolutely! We are on to something here. @subsection serverdocplatforms Platform Permutations Look at some permutations where OpenOCD can run; these "just work" if the Socket Approach is used. - Linux/Cygwin/MinGW/MacOSX/FreeBSD development Host Locally - OpenOCD with some dongle on that host - Linux/Cygwin/MinGW/MacOS/FreeBSD development host - DONGLE: TCP/IP based ARM-Linux perhaps at91rm9200 or ep93xx.c, running openocd. - Windows Cygwin/X desktop environment. - Linux development host (via remote X11) - Dongle: "eb93xx.c" based Linux board @subsection serverdocfuture Development Scale Out During 2008, Duane Ellis created some TCL scripts to display peripheral register contents. For example, look at the sam7 TCL scripts, and the stm32 TCL scripts. The hope was others would create more. A good example of this is display/view the peripheral registers on your embedded target. Lots of commercial embedded debug tools have this, some can show the TIMER registers, the interrupt controller. What if the chip companies behind STM32, or PIC32, AT91SAM chips - wanted to write something that makes working with their chip better, easier, faster, etc. @a Question: How can we (the OpenOCD group) make that really fancy stuff across multiple different host platforms? Remember: OpenOCD runs on: -# Linux via USB, -# ARM Linux - bit-banging GPIO pins -# MacOSX -# FreeBSD -# Cygwin -# MinGW32 -# Ecos How can we get that to work? @subsection serverdocdebug What about Debugger Plugins? Really GDB is nice, it works, but it is not a good embedded debug tool. OpenOCD cannot work in a GUI when one cannot get to its command line. Some GDB front-end developers have pedantic designs that refuse any and all access to the GDB command line (e.g. http://www.kdbg.org/todo.php). The TELNET interface to OpenOCD works, but the intent of that interface is <b>human interaction</b>. It must remain available, developers depend upon it, sometimes that is the only scheme available. As a small group of developers, supporting all the platforms and targets in the debugger will be difficult, as there are enough problem with the plethora of Adapters, Chips, and different target boards. Yes, the TCL interface might be suitable, but it has not received much love or attention. Perhaps it will after you read and understand this. One reason might be, this adds one more host side requirement to make use of the feature. In other words, one could write a Python/TK front-end, but it is only useable if you have Python/TK installed. Maybe this can be done via Eclipse, but not all developers use Eclipse. Many developers use Emacs (possibly with GUD mode) or vim and will not accept such an interface. The next developer reading this might be using Insight (GDB-TK) - and somebody else - DDD.. There is no common host-side GDB front-end method. @section serverdocschallenge Front-End Scaling Maybe we are wrong - ie: OpenOCD + some TK tool Remember: OpenOCD is often (maybe 99.9%) of the time used with GDB-REMOTE. There is always some front-end package - be it command-line GDB under DDD, Eclipse, KDevelop, Emacs, or some other package (e.g. IAR tools can talk to GDB servers). How can the OpenOCD developers make that fancy target display GUI visible under 5 to 10 different host-side GDB.. Sure - a <em>man on a mission</em> can make that work. The GUI might be libopenocd + Perl/TK, or maybe an Eclipse Plug-in. That is a development support nightmare for reasons described above. We have enough support problems as it is with targets, adapters, etc. @section serverdocshttpbg HTTP Server Background OpenOCD includes an HTTP server because most development environments are likely contain a web browser. The web browser can talk to OpenOCD's HTTP server and provide a high-level interfaces to the program. Altogether, it provides a universally accessible GUI for OpenOCD. @section serverdocshtml Simple HTML Pages There is (or could be) a simple "Jim TCL" function to read a memory location. If that can be tied into a TCL script that can modify the HTTP text, then we have a simple script-based web server with a JTAG engine under the hood. Imagine a web page - served from a small board with two buttons: "LED_ON" and "LED_OFF", each click - turns the LED on or OFF, a very simplistic idea. Little boards with web servers are great examples of this: Ethernut is a good example and Contiki (not a board, an embedded OS) is another example. One could create a simple: <b>Click here to display memory</b> or maybe <b>click here to display the UART REGISTER BLOCK</b>; click again and see each register explained in exquisite detail. For an STM32, one could create a simple HTML page, with simple substitution text that the simple web server use to substitute the HTML text JIMTCL_PEEK32( 0x12345678 ) with the value read from memory. We end up with an HTML page that could list the contents of every peripheral register on the target platform. That also is transportable, regardless of the OpenOCD host platform: Linux/X86, Linux/ARM, FreeBSD, Cygwin, MinGW, or MacOSX. You could even port OpenOCD to an Android system and use it as a bit-banging JTAG Adapter serving web pages. @subsection serverdocshtmladv Advanced HTML Pages Java or JavaScript could be used to talk back to the TCL port. One could write a Java, AJAX, FLASH, or some other developer friendly toolbox and get a real cross-platform GUI interface. Sure, the interface is not native - but it is 100% cross-platform! OpenOCD current uses simple HTML pages; others might be an Adobe FLASH expert, or a Java Expert. These possibilities could allow the pages remain cross-platform but still provide a rich user-interface experience. Don't forget it can also be very simple, exactly what one developer can contribute, a set of very simple web pages. @subsection serverdocshtmlstatus HTTP/HTML Status As of May 2009, much of the HTML pages were contributed by Zylin AS, hence they continue to retain some resemblance to the ZY1000 interface. Patches would be welcome to move these parts of the system forward. */ /** @page servergdb OpenOCD GDB Server API This section needs to be expanded. */ /** @page servertelnet OpenOCD Telnet Server API This section needs to be expanded. */ /** @page serverhttp OpenOCD http Server API This section needs to be expanded. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/style.txt ================================================ /** @page styleguide Style Guides The goals for each of these guides are: - to produce correct code that appears clean, consistent, and readable, - to allow developers to create patches that conform to a standard, and - to eliminate these issues as points of future contention. Some of these rules may be ignored in the spirit of these stated goals; however, such exceptions should be fairly rare. The following style guides describe a formatting, naming, and other conventions that should be followed when writing or changing the OpenOCD code: - @subpage styletcl - @subpage stylec - @subpage styleperl - @subpage styleautotools In addition, the following style guides provide information for providing documentation, either as part of the C code or stand-alone. - @subpage styledoxygen - @subpage styletexinfo - @subpage stylelatex Feedback would be welcome to improve the OpenOCD guidelines. */ /** @page styletcl TCL Style Guide OpenOCD needs to expand its Jim/TCL Style Guide. Many of the guidelines listed on the @ref stylec page should apply to OpenOCD's Jim/TCL code as well. */ /** @page stylec C Style Guide This page contains guidelines for writing new C source code for the OpenOCD project. @section styleformat Formatting Guide - remove any trailing white space at the end of lines. - use TAB characters for indentation; do NOT use spaces. - displayed TAB width is 4 characters. - use Unix line endings ('\\n'); do NOT use DOS endings ('\\r\\n') - limit adjacent empty lines to at most two (2). - remove any trailing empty lines at the end of source files - do not "comment out" code from the tree nor put it within a block @code #if 0 ... #endif @endcode otherwise it would never be checked at compile time and when new patches get merged it could be not compilable anymore. Code that is not fully working nor ready for submission should instead be removed entirely (git can retrieve the old version). For exceptional cases that require keeping some unused code, let the compiler check it by putting it in a block @code if (false) { /* explain why this code should be kept here */ ... } @endcode - in a @c switch statement align the @c switch with the @c case label @code switch (dev_id) { case 0x0123: size = 0x10000; break; case 0x0412: size = 0x20000; break; default: size = 0x40000; break; } @endcode - in an <tt> if / then / else </tt> statement, if only one of the conditions require curly brackets due to multi-statement block, put the curly brackets also to the other condition @code if (x > 0) a = 12 + x; else a = 24; @endcode @code if (x > 0) { a = 12 + x; } else { a = 24; x = 0; } @endcode Finally, try to avoid lines of code that are longer than 72-80 columns: - long lines frequently indicate other style problems: - insufficient use of static functions, macros, or temporary variables - poor flow-control structure; "inverted" logical tests - a few lines may be wider than this limit (typically format strings), but: - all C compilers will concatenate series of string constants. - all long string constants should be split across multiple lines. - do never exceed 120 columns. @section stylenames Naming Rules - most identifiers must use lower-case letters (and digits) only. - macros must use upper-case letters (and digits) only. - OpenOCD identifiers should NEVER use @c MixedCaps. - @c typedef names must end with the '_t' suffix. - This should be reserved for types that should be passed by value. - Do @b not mix the typedef keyword with @c struct. - use underline characters between consecutive words in identifiers (e.g. @c more_than_one_word). @section style_include_guards Include Guards Every header file should have a unique include guard to prevent multiple inclusion. To guarantee uniqueness, an include guard should be based on the filename and the full path in the project source tree. For the header file src/helper/jim-nvp.h, the include guard would look like this: @code #ifndef OPENOCD_HELPER_JIM_NVP_H #define OPENOCD_HELPER_JIM_NVP_H /* Your code here. */ #endif /* OPENOCD_HELPER_JIM_NVP_H */ @endcode @section stylec99 C99 Rules - inline functions - @c // comments -- in new code, prefer these for single-line comments - trailing comma allowed in enum declarations - designated initializers ( .field = value ) - variables declarations should occur at the point of first use - new block scopes for selection and iteration statements - use malloc() to create dynamic arrays. Do @b not use @c alloca or variable length arrays on the stack. non-MMU hosts(uClinux) and pthreads require modest and predictable stack usage. @section styletypes Type Guidelines - use native types (@c int or <tt> unsigned int </tt>) if the type is not important - if size matters, use the types from \<stdint.h\> or \<inttypes.h\>: - @c int8_t, @c int16_t, @c int32_t, or @c int64_t: signed types of specified size - @c uint8_t, @c uint16_t, @c uint32_t, or @c uint64_t: unsigned types of specified size - use the associated @c printf and @c scanf formatting strings for these types (e.g. @c PRId8, PRIx16, SCNu8, ...) - do @b NOT redefine @c uN types from "types.h" - use type @c target_addr_t for target's address values - prefer type <tt> unsigned int </tt> to type @c unsigned @section stylefunc Functions - static inline functions should be preferred over macros: @code /* do NOT define macro-like functions like this... */ #define CUBE(x) ((x) * (x) * (x)) /* instead, define the same expression using a C99 inline function */ static inline int cube(int x) { return x * x * x; } @endcode - Functions should be declared static unless required by other modules - define static functions before first usage to avoid forward declarations. - Functions should have no space between its name and its parameter list: @code int f(int x1, int x2) { ... int y = f(x1, x2 - x1); ... } @endcode - Separate assignment and logical test statements. In other words, you should write statements like the following: @code // separate statements should be preferred result = foo(); if (result != ERROR_OK) ... @endcode More directly, do @b not combine these kinds of statements: @code // Combined statements should be avoided if ((result = foo()) != ERROR_OK) return result; @endcode - Do not compare @c bool values with @c true or @c false but use the value directly @code if (!is_enabled) ... @endcode - Avoid comparing pointers with @c NULL @code buf = malloc(buf_size); if (!buf) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @endcode */ /** @page styledoxygen Doxygen Style Guide The following sections provide guidelines for OpenOCD developers who wish to write Doxygen comments in the code or this manual. For an introduction to Doxygen documentation, see the @ref primerdoxygen. @section styledoxyblocks Doxygen Block Selection Several different types of Doxygen comments can be used; often, one style will be the most appropriate for a specific context. The following guidelines provide developers with heuristics for selecting an appropriate form and writing consistent documentation comments. -# use @c /// to for one-line documentation of instances. -# for documentation requiring multiple lines, use a "block" style: @verbatim /** * @brief First sentence is short description. Remaining text becomes * the full description block, where "empty" lines start new paragraphs. * * One can make text appear in @a italics, @b bold, @c monospace, or * in blocks such as the one in which this example appears in the Style * Guide. See the Doxygen Manual for the full list of commands. * * @param foo For a function, describe the parameters (e.g. @a foo). * @returns The value(s) returned, or possible error conditions. */ @endverbatim -# The block should start on the line following the opening @c /\**. -# The end of the block, @c *‍/, should also be on its own line. -# Every line in the block should have a @c '*' in-line with its start: - A leading space is required to align the @c '*' with the @c /\** line. - A single "empty" line should separate the function documentation from the block of parameter and return value descriptions. - Except to separate paragraphs of documentation, other extra "empty" lines should be removed from the block. -# Only single spaces should be used; do @b not add mid-line indentation. -# If the total line length will be less than 72-80 columns, then - The @c /\**< form can be used on the same line. - This style should be used sparingly; the best use is for fields: @verbatim int field; /**< field description */ @endverbatim @section styledoxyall Doxygen Style Guide The following guidelines apply to all Doxygen comment blocks: -# Use the @c '\@cmd' form for all doxygen commands (do @b not use @c '\\cmd'). -# Use symbol names such that Doxygen automatically creates links: -# @c function_name() can be used to reference functions (e.g. flash_set_dirty()). -# @c struct_name::member_name should be used to reference structure fields in the documentation (e.g. @c flash_driver::name). -# URLS get converted to markup automatically, without any extra effort. -# new pages can be linked into the hierarchy by using the @c \@subpage command somewhere the page(s) under which they should be linked: -# use @c \@ref in other contexts to create links to pages and sections. -# Use good Doxygen mark-up: -# '\@a' (italics) should be used to reference parameters (e.g. <i>foo</i>). -# '\@b' (bold) should be used to emphasizing <b>single</b> words. -# '\@c' (monospace) should be used with <code>file names</code> and <code>code symbols</code>, so they appear visually distinct from surrounding text. -# To mark-up multiple words, the HTML alternatives must be used. -# Two spaces should be used when nesting lists; do @b not use '\\t' in lists. -# Code examples provided in documentation must conform to the Style Guide. @section styledoxytext Doxygen Text Inputs In addition to the guidelines in the preceding sections, the following additional style guidelines should be considered when writing documentation as part of standalone text files: -# Text files must contain Doxygen at least one comment block: -# Documentation should begin in the first column (except for nested lists). -# Do NOT use the @c '*' convention that must be used in the source code. -# Each file should contain at least one @c \@page block. -# Each new page should be listed as a \@subpage in the \@page block of the page that should serve as its parent. -# Large pages should be structure in parts using meaningful \@section and \@subsection commands. -# Include a @c \@file block at the end of each Doxygen @c .txt file to document its contents: - Doxygen creates such pages for files automatically, but no content will appear on them for those that only contain manual pages. - The \@file block should provide useful meta-documentation to assist technical writers; typically, a list of the pages that it contains. - For example, the @ref styleguide exists in @c doc/manual/style.txt, which contains a reference back to itself. -# The \@file and \@page commands should begin on the same line as the start of the Doxygen comment: @verbatim /** @page pagename Page Title Documentation for the page. */ /** @file This file contains the @ref pagename page. */ @endverbatim For an example, the Doxygen source for this Style Guide can be found in @c doc/manual/style.txt, alongside other parts of The Manual. */ /** @page styletexinfo Texinfo Style Guide The User's Guide is there to provide two basic kinds of information. It is a guide for how and why to use each feature or mechanism of OpenOCD. It is also the reference manual for all commands and options involved in using them, including interface, flash, target, and other drivers. At this time, it is the only documentation for end users; everything else is addressing OpenOCD developers. There are two key audiences for the User's Guide, both developer based. The primary audience is developers using OpenOCD as a tool in their work, or who may be starting to use it that way. A secondary audience includes developers who are supporting those users by packaging or customizing it for their hardware, installing it as part of some software distribution, or by evolving OpenOCD itself. There is some crossover between those audiences. We encourage contributions from users as the fundamental way to evolve and improve OpenOCD. In particular, creating a board or target specific configuration file is something that many users will end up doing at some point, and we like to see such files become part of the mainline release. General documentation rules to remember include: - Be concise and clear. It's work to remove those extra words and sentences, but such "noise" doesn't help readers. - Make it easy to skim and browse. "Tell what you're going to say, then say it". Help readers decide whether to dig in now, or leave it for later. - Make sure the chapters flow well. Presentations should not jump around, and should move easily from overview down to details. - Avoid using the passive voice. - Address the reader to clarify roles ("your config file", "the board you are debugging", etc.); "the user" (etc) is artificial. - Use good English grammar and spelling. Remember also that English will not be the first language for many readers. Avoid complex or idiomatic usage that could create needless barriers. - Use examples to highlight fundamental ideas and common idioms. - Don't overuse list constructs. This is not a slide presentation; prefer paragraphs. When presenting features and mechanisms of OpenOCD: - Explain key concepts before presenting commands using them. - Tie examples to common developer tasks. - When giving instructions, you can \@enumerate each step both to clearly delineate the steps, and to highlight that this is not explanatory text. - When you provide "how to use it" advice or tutorials, keep it in separate sections from the reference material. - Good indexing is something of a black art. Use \@cindex for important concepts, but don't overuse it. In particular, rely on the \@deffn indexing, and use \@cindex primarily with significant blocks of text such as \@subsection. The \@dfn of a key term may merit indexing. - Use \@xref (and \@anchor) with care. Hardcopy versions, from the PDF, must make sense without clickable links (which don't work all that well with Texinfo in any case). If you find you're using many links, read that as a symptom that the presentation may be disjointed and confusing. - Avoid font tricks like \@b, but use \@option, \@file, \@dfn, \@emph and related mechanisms where appropriate. For technical reference material: - It's OK to start sections with explanations and end them with detailed lists of the relevant commands. - Use the \@deffn style declarations to define all commands and drivers. These will automatically appear in the relevant index, and those declarations help promote consistent presentation and style. - It's a "Command" if it can be used interactively. - Else it's a "Config Command" if it must be used before the configuration stage completes. - For a "Driver", list its name. - Use EBNF style regular expressions to define parameters: brackets around zero-or-one choices, parentheses around exactly-one choices. - Use \@option, \@file, \@var and other mechanisms where appropriate. - Say what output it displays, and what value it returns to callers. - Explain clearly what the command does. Sometimes you will find that it can't be explained clearly. That usually means the command is poorly designed; replace it with something better, if you can. - Be complete: document all commands, except as part of a strategy to phase something in or out. - Be correct: review the documentation against the code, and vice versa. - Alphabetize the \@defn declarations for all commands in each section. - Keep the per-command documentation focused on exactly what that command does, not motivation, advice, suggestions, or big examples. When commands deserve such expanded text, it belongs elsewhere. Solutions might be using a \@section explaining a cluster of related commands, or acting as a mini-tutorial. - Details for any given driver should be grouped together. The User's Guide is the first place most users will start reading, after they begin using OpenOCD. Make that investment of their time be as productive as possible. Needing to look at OpenOCD source code, to figure out how to use it is a bad sign, though it's OK to need to look at the User's guide to figure out what a config script is doing. */ /** @page stylelatex LaTeX Style Guide This page needs to provide style guidelines for using LaTeX, the typesetting language used by The References for OpenOCD Hardware. Likewise, the @ref primerlatex for using this guide needs to be completed. */ /** @page styleperl Perl Style Guide This page provides some style guidelines for using Perl, a scripting language used by several small tools in the tree: -# Ensure all Perl scripts use the proper suffix (@c .pl for scripts, and @c .pm for modules) -# Pass files as script parameters or piped as input: - Do NOT code paths to files in the tree, as this breaks out-of-tree builds. - If you must, then you must also use an automake rule to create the script. -# use @c '#!/usr/bin/perl' as the first line of Perl scripts. -# always <code>use strict</code> and <code>use warnings</code> -# invoke scripts indirectly in Makefiles or other scripts: @code perl script.pl @endcode Maintainers must also be sure to follow additional guidelines: -# Ensure that Perl scripts are committed as executables: Use "<code>chmod +x script.pl</code>" @a before using "<code>git add script.pl</code>" */ /** @page styleautotools Autotools Style Guide This page contains style guidelines for the OpenOCD autotools scripts. The following guidelines apply to the @c configure.ac file: - Better guidelines need to be developed, but until then... - Use good judgement. The following guidelines apply to @c Makefile.am files: -# When assigning variables with long lists of items: -# Separate the values on each line to make the files "patch friendly": @code VAR = \ value1 \ value2 \ ... value9 \ value10 @endcode */ /** @file This file contains the @ref styleguide pages. The @ref styleguide pages include the following Style Guides for their respective code and documentation languages: - @ref styletcl - @ref stylec - @ref styledoxygen - @ref styletexinfo - @ref stylelatex - @ref styleperl - @ref styleautotools */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/target/mips.txt ================================================ /** @page targetmips OpenOCD MIPS Targets @section ejatgmem EJTAG Memory Addresses An optional uncached and unmapped debug segment dseg (EJTAG area) appears in the address range 0xFFFF FFFF FF20 0000 to 0xFFFF FFFF FF3F FFFF. The dseg segment thereby appears in the kseg part of the compatibility segment, and access to kseg is possible with the dseg segment. The dseg segment is subdivided into dmseg (EJTAG memory) segment and the drseg (EJTAG registers) segment. The dmseg segment is used when the probe services the memory segment. The drseg segment is used when the memory-mapped debug registers are accessed. Table 5-2 shows the subdivision and attributes for the segments. dseg is divided in : - dmseg (0xFFFF FFFF FF20 0000 to 0xFFFF FFFF FF2F FFFF) - drseg (0xFFFF FFFF FF30 0000 to 0xFFFF FFFF FF3F FFFF) Because the dseg segment is serviced exclusively by the EJTAG features, there are no physical address per se. Instead the lower 21 bits of the virtual address select the appropriate reference in either EJTAG memory or registers. References are not mapped through the TLB, nor do the accesses appear on the external system memory interface. Both of this memory segments are Uncached. On debug exception (break) CPU jumps to the beginning of dmseg. This some kind of memory shared between CPU and EJTAG dongle. There CPU stops (correct terminology is : stalls, because it stops it's pipeline), and is waiting for some action of dongle. If the dongle gives it instruction, CPU executes it, augments it's PC to 0xFFFF FFFF FF20 0001 - but it again points to dmseg area, so it stops waiting for next instruction. This will all become clear later, after reading following prerequisite chapters. @section impflags Important flags @subsection pnnw PNnW Indicates read or write of a pending processor access: - 0 : Read processor access, for a fetch/load access - 1 : Write processor access, for a store access This value is defined only when a processor access is pending. Processor will do the action for us : it can for example read internal state (register values), and send us back the information via EJTAG memory (dmseg), or it can take some data from dmseg and write it into the registers or RAM. Every time when it sees address (i.e. when this address is the part of the opcode it is executing, whether it is instruction or data fetch) that falls into dmseg, processor stalls. That actually means that CPU stops it's pipeline and it is waiting for dongle to take some action. CPU is now either waiting for dongle to take some data from dmseg (if we requested for CPU do give us internal state, for example), or it will wait for some data from dongle (if it needs following instruction because it did previous, or if the operand address of the currently executed opcode falls somewhere (anywhere) in dmseg (0xff..ff20000 - 0xff..ff2fffff)). Bit PNnW describes character of CPU access to EJTAG memory (the memory where dongle puts/takes data) - CPU can either READ for it (PNnW == 0) or WRITE to it (PNnW == 1). By reading PNnW bit OpenOCD will know if it has to send (PNnW == 0) or to take (PNnW == 1) data (from dmseg, via dongle). @subsection pracc PrAcc Indicates a pending processor access and controls finishing of a pending processor access. When read: - 0 : No pending processor access - 1 : Pending processor access A write of 0 finishes a processor access if pending; otherwise operation of the processor is UNDEFINED if the bit is written to 0 when no processor access is pending. A write of 1 is ignored. A successful FASTDATA access will clear this bit. As noted above, on any access to dmseg, processor will stall. It waits for dongle to do some action - either to take or put some data. OpenOCD can figure out which action has to be taken by reading PrAcc bit. Once action from dongle has been done, i.e. after the data is taken/put, OpenOCD can signal to CPU to proceed with executing the instruction. This can be the next instruction (if previous was finished before pending), or the same instruction - if for example CPU was waiting on dongle to give it an operand, because it saw in the instruction opcode that operand address is somewhere in dmseg. That provoked the CPU to stall (it tried operand fetch to dmseg and stopped), and PNnW bit is 0 (CPU does read from dmseg), and PrAcc is 1 (CPU is pending on dmseg access). @subsection spracc SPrAcc Shifting in a zero value requests completion of the Fastdata access. The PrAcc bit in the EJTAG Control register is overwritten with zero when the access succeeds. (The access succeeds if PrAcc is one and the operation address is in the legal dmseg segment Fastdata area.) When successful, a one is shifted out. Shifting out a zero indicates a Fastdata access failure. Shifting in a one does not complete the Fastdata access and the PrAcc bit is unchanged. Shifting out a one indicates that the access would have been successful if allowed to complete and a zero indicates the access would not have successfully completed. @section fdreg Fastdata Register (TAP Instruction FASTDATA) The width of the Fastdata register is 1 bit. During a Fastdata access, the Fastdata register is written and read, i.e., a bit is shifted in and a bit is shifted out. Also during a Fastdata access, the Fastdata register value shifted in specifies whether the Fastdata access should be completed or not. The value shifted out is a flag that indicates whether the Fastdata access was successful or not (if completion was requested). @section ejtagacc EJTAG Access Implementation OpenOCD reads/writes data to JTAG via mips_m4k_read_memory() and mips_m4k_write_memory() functions defined in src/target/mips_m4k.c. Internally, these functions call mips32_pracc_read_mem() and mips32_pracc_write_mem() defined in src/target/mips32_pracc.c Let's take for example function mips32_pracc_read_mem32() which describes CPU reads (fetches) from dmseg (EJTAG memory) : @code static const uint32_t code[] = { /* start: */ MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */ MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */ MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)), MIPS32_SW(8,0,15), /* sw $8,($15) */ MIPS32_SW(9,0,15), /* sw $9,($15) */ MIPS32_SW(10,0,15), /* sw $10,($15) */ MIPS32_SW(11,0,15), /* sw $11,($15) */ MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */ MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)), MIPS32_LW(9,0,8), /* $9 = mem[$8]; read addr */ MIPS32_LW(10,4,8), /* $10 = mem[$8 + 4]; read count */ MIPS32_LUI(11,UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $11 = MIPS32_PRACC_PARAM_OUT */ MIPS32_ORI(11,11,LOWER16(MIPS32_PRACC_PARAM_OUT)), /* loop: */ MIPS32_BEQ(0,10,8), /* beq 0, $10, end */ MIPS32_NOP, MIPS32_LW(8,0,9), /* lw $8,0($9), Load $8 with the word @mem[$9] */ MIPS32_SW(8,0,11), /* sw $8,0($11) */ MIPS32_ADDI(10,10,NEG16(1)), /* $10-- */ MIPS32_ADDI(9,9,4), /* $1 += 4 */ MIPS32_ADDI(11,11,4), /* $11 += 4 */ MIPS32_B(NEG16(8)), /* b loop */ MIPS32_NOP, /* end: */ MIPS32_LW(11,0,15), /* lw $11,($15) */ MIPS32_LW(10,0,15), /* lw $10,($15) */ MIPS32_LW(9,0,15), /* lw $9,($15) */ MIPS32_LW(8,0,15), /* lw $8,($15) */ MIPS32_B(NEG16(27)), /* b start */ MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */ }; @endcode We have to pass this code to CPU via dongle via dmseg. After debug exception CPU will find itself stalling at the beginning of the dmseg. It waits for the first instruction from dongle. This is MIPS32_MTC0(15,31,0), so CPU saves C0 and continues to addr 0xFF20 0001, which falls also to dmseg, so it stalls. Dongle proceeds giving to CPU one by one instruction in this manner. However, things are not so simple. If you take a look at the program, you will see that some instructions take operands. If it has to take operand from the address in dmseg, CPU will stall waiting for the dongle to do the action of passing the operand and signal this by putting PrAcc to 0. If this operand is somewhere in RAM, CPU will not stall (it stalls only on dmseg), but it will just take it and proceed to next instruction. But since PC for next instruction points to dmseg, it will stall, so that dongle can pass next instruction. Some instructions are jumps (if these are jumps in dmseg addr, CPU will jump and then stall. If this is jump to some address in RAM, CPU will jump and just proceed - will not stall on addresses in RAM). To have information about CPU is currently (does it stalls wanting on operand or it jumped somewhere waiting for next instruction), OpenOCD has to call TAP ADDRESS instruction, which will ask CPU to give us his address within EJTAG memory : @code address = data = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &address); @endcode And then, upon the results, we can conclude where it is in our code so far, so we can give it what it wants next : @code if ((address >= MIPS32_PRACC_PARAM_IN) && (address <= MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4)) { offset = (address - MIPS32_PRACC_PARAM_IN) / 4; data = ctx->local_iparam[offset]; } else if ((address >= MIPS32_PRACC_PARAM_OUT) && (address <= MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4)) { offset = (address - MIPS32_PRACC_PARAM_OUT) / 4; data = ctx->local_oparam[offset]; } else if ((address >= MIPS32_PRACC_TEXT) && (address <= MIPS32_PRACC_TEXT + ctx->code_len * 4)) { offset = (address - MIPS32_PRACC_TEXT) / 4; data = ctx->code[offset]; } else if (address == MIPS32_PRACC_STACK) { /* save to our debug stack */ data = ctx->stack[--ctx->stack_offset]; } else { /* TODO: send JMP 0xFF200000 instruction. Hopefully processor jump back to start of debug vector */ data = 0; LOG_ERROR("Error reading unexpected address 0x%8.8" PRIx32 "", address); return ERROR_JTAG_DEVICE_ERROR; } @endcode i.e. if CPU is stalling on addresses in dmseg that are reserved for input parameters, we can conclude that it actually tried to take (read) parameter from there, and saw that address of parameter falls in dmseg, so it stopped. Obviously, now dongle have to give to it operand. Similarly, mips32_pracc_exec_write() describes CPU writes into EJTAG memory (dmseg). Obviously, code is RO, and CPU can change only parameters : @code mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32(ctx->ejtag_info, &data); /* Clear access pending bit */ ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL); mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl); //jtag_add_clocks(5); jtag_execute_queue(); if ((address >= MIPS32_PRACC_PARAM_IN) && (address <= MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4)) { offset = (address - MIPS32_PRACC_PARAM_IN) / 4; ctx->local_iparam[offset] = data; } else if ((address >= MIPS32_PRACC_PARAM_OUT) && (address <= MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4)) { offset = (address - MIPS32_PRACC_PARAM_OUT) / 4; ctx->local_oparam[offset] = data; } else if (address == MIPS32_PRACC_STACK) { /* save data onto our stack */ ctx->stack[ctx->stack_offset++] = data; } else { LOG_ERROR("Error writing unexpected address 0x%8.8" PRIx32 "", address); return ERROR_JTAG_DEVICE_ERROR; } @endcode CPU loops here : @code while (1) { if ((retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl)) != ERROR_OK) return retval; address = data = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &address); /* Check for read or write */ if (ejtag_ctrl & EJTAG_CTRL_PRNW) { if ((retval = mips32_pracc_exec_write(&ctx, address)) != ERROR_OK) return retval; } else { /* Check to see if its reading at the debug vector. The first pass through * the module is always read at the vector, so the first one we allow. When * the second read from the vector occurs we are done and just exit. */ if ((address == MIPS32_PRACC_TEXT) && (pass++)) { break; } if ((retval = mips32_pracc_exec_read(&ctx, address)) != ERROR_OK) return retval; } if (cycle == 0) break; } @endcode and using presented R (mips32_pracc_exec_read()) and W (mips32_pracc_exec_write()) functions it reads in the code (RO) and reads and writes operands (RW). @section fdimpl OpenOCD FASTDATA Implementation OpenOCD FASTDATA write function, mips32_pracc_fastdata_xfer() is called from bulk_write_memory callback, which writes a count items of 4 bytes to the memory of a target at the an address given. Because it operates only on whole words, this should be faster than target_write_memory(). In order to implement FASTDATA write, mips32_pracc_fastdata_xfer() uses the following handler : @code uint32_t handler_code[] = { /* caution when editing, table is modified below */ /* r15 points to the start of this code */ MIPS32_SW(8,MIPS32_FASTDATA_HANDLER_SIZE - 4,15), MIPS32_SW(9,MIPS32_FASTDATA_HANDLER_SIZE - 8,15), MIPS32_SW(10,MIPS32_FASTDATA_HANDLER_SIZE - 12,15), MIPS32_SW(11,MIPS32_FASTDATA_HANDLER_SIZE - 16,15), /* start of fastdata area in t0 */ MIPS32_LUI(8,UPPER16(MIPS32_PRACC_FASTDATA_AREA)), MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_FASTDATA_AREA)), MIPS32_LW(9,0,8), /* start addr in t1 */ MIPS32_LW(10,0,8), /* end addr to t2 */ /* loop: */ /* 8 */ MIPS32_LW(11,0,0), /* lw t3,[t8 | r9] */ /* 9 */ MIPS32_SW(11,0,0), /* sw t3,[r9 | r8] */ MIPS32_BNE(10,9,NEG16(3)), /* bne $t2,t1,loop */ MIPS32_ADDI(9,9,4), /* addi t1,t1,4 */ MIPS32_LW(8,MIPS32_FASTDATA_HANDLER_SIZE - 4,15), MIPS32_LW(9,MIPS32_FASTDATA_HANDLER_SIZE - 8,15), MIPS32_LW(10,MIPS32_FASTDATA_HANDLER_SIZE - 12,15), MIPS32_LW(11,MIPS32_FASTDATA_HANDLER_SIZE - 16,15), MIPS32_LUI(15,UPPER16(MIPS32_PRACC_TEXT)), MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_TEXT)), MIPS32_JR(15), /* jr start */ MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */ }; @endcode In the beginning and the end of the handler we have function prologue (save the regs that will be clobbered) and epilogue (restore regs), and in the very end, after all the xfer have been done, we do jump to the MIPS32_PRACC_TEXT address, i.e. Debug Exception Vector location. We will use this fact (that we came back to MIPS32_PRACC_TEXT) to verify later if all the handler is executed (because when in RAM, processor do not stall - it executes all instructions until one of them do not demand access to dmseg (if one of it's operands is there)). This handler is put into the RAM and executed from there, and not instruction by instruction, like in previous simple write (mips_m4k_write_memory()) and read (mips_m4k_read_memory()) functions. N.B. When it is executing this code in RAM, CPU will not stall on instructions, but execute all until it comes to the : @code MIPS32_LW(9,0,8) /* start addr in t1 */ @endcode and there it will stall - because it will see that one of the operands have to be fetched from dmseg (EJTAG memory, in this case FASTDATA memory segment). This handler is loaded in the RAM, at the reserved location "work_area". This work_area is configured in OpenOCD configuration script and should be selected in that way that it is not clobbered (overwritten) by data we want to write-in using FASTDATA. What is executed instruction by instruction which is passed by dongle (via EJATG memory) is small jump code, which jumps at the handler in RAM. CPU stalls on dmseg when receiving these jmp_code instructions, but once it jumps in RAM, CPU do not stall anymore and executes bunch of handler instructions. Until it comes to the first instruction which has an operand in FASTDATA area. There it stalls and waits on action from probe. It happens actually when CPU comes to this loop : @code MIPS32_LW(9,0,8), /* start addr in t1 */ MIPS32_LW(10,0,8), /* end addr to t2 */ /* loop: */ /* 8 */ MIPS32_LW(11,0,0), /* lw t3,[t8 | r9] */ /* 9 */ MIPS32_SW(11,0,0), /* sw t3,[r9 | r8] */ MIPS32_BNE(10,9,NEG16(3)), /* bne $t2,t1,loop */ @endcode and then it stalls because operand in r8 points to FASTDATA area. OpenOCD first verifies that CPU came to this place by : @code /* next fetch to dmseg should be in FASTDATA_AREA, check */ address = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &address); if (address != MIPS32_PRACC_FASTDATA_AREA) return ERROR_FAIL; @endcode and then passes to CPU start and end address of the loop region for handler in RAM. In the loop in handler, CPU sees that it has to take and operand from FSTDATA area (to write it to the dst in RAM after), and so it stalls, putting PrAcc to "1". OpenOCD fills the data via this loop : @code for (i = 0; i < count; i++) { /* Send the data out using fastdata (clears the access pending bit) */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); if ((retval = mips_ejtag_fastdata_scan(ejtag_info, write_t, buf++)) != ERROR_OK) return retval; } @endcode Each time when OpenOCD fills data to CPU (via dongle, via dmseg), CPU takes it and proceeds to execute the handler. However, since the handler is in an assembly loop, CPU comes to next instruction which also fetches data from FASTDATA area. So it stalls. Then OpenOCD fills the data again, from its (OpenOCD's) loop. And this game continues until all the data has been filled. After the last data has been given to CPU it sees that it reached the end address, so it proceeds with next instruction. However, this instruction do not point into dmseg, so CPU executes bunch of handler instructions (all prologue) and in the end jumps to MIPS32_PRACC_TEXT address. On its side, OpenOCD checks in CPU has jumped back to MIPS32_PRACC_TEXT, which is the confirmation that it correctly executed all the rest of the handler in RAM, and that is not stuck somewhere in the RAM, or stalling on some access in dmesg - that would be an error: @code address = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &address); if (address != MIPS32_PRACC_TEXT) LOG_ERROR("mini program did not return to start"); @endcode @section fdejtagspec EJTAG spec on FASTDATA access The width of the Fastdata register is 1 bit. During a Fastdata access, the Fastdata register is written and read, i.e., a bit is shifted in and a bit is shifted out. During a Fastdata access, the Fastdata register value shifted in specifies whether the Fastdata access should be completed or not. The value shifted out is a flag that indicates whether the Fastdata access was successful or not (if completion was requested). The FASTDATA access is used for efficient block transfers between dmseg (on the probe) and target memory (on the processor). An "upload" is defined as a sequence of processor loads from target memory and stores to dmseg. A "download" is a sequence of processor loads from dmseg and stores to target memory. The "Fastdata area" specifies the legal range of dmseg addresses (0xFF20.0000 - 0xFF20.000F) that can be used for uploads and downloads. The Data + Fastdata registers (selected with the FASTDATA instruction) allow efficient completion of pending Fastdata area accesses. During Fastdata uploads and downloads, the processor will stall on accesses to the Fastdata area. The PrAcc (processor access pending bit) will be 1 indicating the probe is required to complete the access. Both upload and download accesses are attempted by shifting in a zero SPrAcc value (to request access completion) and shifting out SPrAcc to see if the attempt will be successful (i.e., there was an access pending and a legal Fastdata area address was used). Downloads will also shift in the data to be used to satisfy the load from dmseg’s Fastdata area, while uploads will shift out the data being stored to dmseg’s Fastdata area. As noted above, two conditions must be true for the Fastdata access to succeed. These are: - PrAcc must be 1, i.e., there must be a pending processor access. - The Fastdata operation must use a valid Fastdata area address in dmseg (0xFF20.0000 to 0xFF20.000F). Basically, because FASTDATA area in dmseg is 16 bytes, we transfer (0xFF20.0000 - 0xFF20.000F) FASTDATA scan TAP instruction selects the Data and the Fastdata registers at once. They come in order : TDI -> | Data register| -> | Fastdata register | -> TDO FASTDATA register is 1-bit width register. It takes in SPrAcc bit which should be shifted first, followed by 32 bit of data. Scan width of FASTDTA is 33 bits in total : 33 bits are shifted in and 33 bits are shifted out. First bit that is shifted out is SPrAcc that comes out of Fastdata register and should give us status on FATSDATA write we want to do. @section fdcheck OpenOCD misses FASTDATA check Download flow (probe -> target block transfer) : 1) Probe transfer target execution to a loop in target memory doing a fixed number of "loads" to fastdata area of dmseg (and stores to the target download destination.) 2) Probe loops attempting to satisfy the loads "expected" from the target. On FASTDATA access "successful" move on to next "load". On FASTDATA access "failure" repeat until "successful" or timeout. (A "failure" is an attempt to satisfy an access when none are pending.) Note: A failure may have a recoverable (and even expected) cause like slow target execution of the load loop. Other failures may be due to unexpected more troublesome causes like an exception while in debug mode or a target hang on a bad target memory access. Shifted out SPrAcc bit inform us that there was CPU access pending and that it can be complete. Basically, we should do following procedure : - Download (dongle -> CPU) : You shift "download" DATA and FASTDATA[SPrAcc] = 0 (33 bit scan) into the target. If the value of FASTDATA[SPrAcc] shifted out is "1" then an access was pending when you started the scan and it is now complete. If SPrAcc is 0 then no access was pending to the fastdata area. (Repeat attempt to complete the access you expect for this data word. Timeout if you think the access is "long overdue" as something unexpected has happened.) - Upload (CPU -> dongle) : You shift "dummy" DATA and FASTDATA[SPrAcc] = 0 (33 bit scan) into the target. If the value of FASTDATA[SPrAcc] shifted out is "1" then an access was pending when you started the scan and it is now complete. The "upload" is the DATA shifted out of the target. If SPrAcc is 0 then no access was pending to the fastdata area. (Repeat attempt to complete the access you expect for this data word. Timeout if you think the access is "long overdue" as something unexpected has happened.) Basically, if checking first (before scan) if CPU is pending on FASTDATA access (PrAcc is "1"), like this @code wait(ready); do_scan(); @endcode which is inefficient, we should do it like this : @code BEGIN : do_scan(); if (!was_ready) goto BEGIN; @endcode by checking SPrAcc that we shifted out. If some FASTDATA write fails, OpenOCD will continue with it's loop (on the host side), but CPU will rest pending (on the target side) waiting for correct FASTDATA write. Since OpenOCD goes ahead, it will eventually finish it's loop, and proceed to check if CPU took all the data. But since CPU did not took all the data, it is still turns in handler's loop in RAM, stalling on Fastdata area so this check : @code address = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); retval = mips_ejtag_drscan_32(ejtag_info, &address); if (retval != ERROR_OK) return retval; if (address != MIPS32_PRACC_TEXT) LOG_ERROR("mini program did not return to start"); @endcode fails, and that gives us enough information of the failure. In this case, we can lower the JTAG frequency and try again, because most probable reason of this failure is that we tried FASTDATA upload before CPU arrived to rise PrAcc (i.e. before it was pending on access). However, the reasons for failure might be numerous : reset, exceptions which can occur in debug mode, bus hangs, etc. If lowering the JTAG freq does not work either, we can fall back to more robust solution with patch posted below. To summarize, FASTDATA communication goes as following : -# CPU jumps to Debug Exception Vector Location 0xFF200200 in dmseg and it stalls, pending and waiting for EJTAG to give it first debug instruction and signal it by putting PrAcc to "0" -# When PrAcc goes to "0" CPU execute one opcode sent by EJTAG via DATA reg. Then it pends on next access, waiting for PrAcc to be put to "0" again -# Following this game, OpenOCD first loads handler code in RAM, and then sends the jmp_code - instruction by instruction via DATA reg, which redirects CPU to handler previously set up in RAM -# Once in RAM CPU does not pend on any instruction, but it executes all handler instructions until first "fetch" to Fastdata area - then it stops and pends. -# So - when it comes to any instruction (opcode) in this handler in RAM which reads (or writes) to Fastdata area (0xF..F20.0000 to 0xF..F20.000F), CPU stops (i.e. stalls access). I.e. it stops on this lw opcode and waits to FASTDATA TAP command from the probe. -# CPU continues only if OpenOCD shifted in SPrAcc "0" (and if the PrAcc was "1"). It shifts-out "1" to tell us that it was OK (processor was stalled, so it can complete the access), and that it continued execution of the handler in RAM. -# If PrAcc was not "1" CPU will not continue (go to next instruction), but will shift-out "0" and keep stalling on the same instruction of my handler in RAM. -# When Fastdata loop is finished, CPU executes all following handler instructions in RAM (prologue). -# In the end of my handler in RAM, I jumps back to beginning of Debug Exception Vector Location 0xFF200200 in dmseg. -# When it jumps back to 0xFF200200 in dmseg processor stops and pends, waiting for OpenOCD to send it instruction via DATA reg and signal it by putting PrAcc to "0". */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/target/notarm.txt ================================================ /** @page targetnotarm OpenOCD Non-ARM Targets This page describes outstanding issues w.r.t. non-ARM targets. @section targetnotarmflash Flash drivers The flash drivers contain ARM32 code that is used to execute code on the target. This needs to be handled in some CPU independent manner. The ocl and ecos flash drivers compile the flash driver code to run on the target on the developer machine. The ocl and ecos flash drivers should be unified and instructions should be written on how to compile the target flash drivers. Perhaps using automake? eCos has CFI driver that could probably be compiled for all targets. The trick is to figure out a way to make the compiled flash drivers work on all target memory maps + sort out all the little details @section targetnotarm32v64 32 vs. 64 bit Currently OpenOCD only supports 32 bit targets. Adding 64 bit support would be nice but there hasn't been any call for it in the openocd development mailing list @section targetnotarmsupport Target Support target.h is relatively CPU agnostic and the intention is to move in the direction of less instruction set specific. Non-CPU targets are also supported, but there isn't a lot of activity on it in the mailing list currently. An example is FPGA programming support via JTAG, but also flash chips can be programmed directly using JTAG. @section targetnotarmphy non-JTAG physical layer JTAG is not the only physical protocol used to talk to CPUs. OpenOCD does not today have targets that use non-JTAG. The actual physical layer is a relatively modest part of the total OpenOCD system. @section targetnotarmppc PowerPC there exists open source implementations of PowerPC target manipulation, but there hasn't been a lot of activity in the mailing list. @section targetnotarmmips MIPS Currently OpenOCD has a MIPS target defined. This is the first non-ARM example of a CPU target */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/manual/target.txt ================================================ /** @page targetdocs OpenOCD Target APIs OpenOCD provides its Target APIs to allow developers to provide trace and debugging support for specific device targets. These primarily consist of ARM cores, but other types have been supported. New targets should be developed by following or using these APIs. The Target Support module contains APIs that cover several functional areas: - @subpage targetarm - @subpage targetnotarm - @subpage targetmips - @subpage targetregister - @subpage targetimage - @subpage targettrace This section needs to be expanded. */ /** @page targetarm OpenOCD ARM Targets This section needs to describe OpenOCD's ARM target support. */ /** @page targetregister OpenOCD Target Register API This section needs to describe OpenOCD's Target Register API, as provided by 'src/target/register.h'. */ /** @page targetimage OpenOCD Target Image API This section needs to describe OpenOCD's Target Image API, as provided by 'src/target/image.h'. */ /** @page targettrace OpenOCD Target Trace API This section needs to describe OpenOCD's Target Trace API, as provided by 'src/target/trace.h'. */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/openocd.1 ================================================ .TH "OPENOCD" "1" "November 24, 2009" .SH "NAME" openocd \- A free and open on\-chip debugging, in\-system programming and boundary\-scan testing tool for ARM and MIPS systems .SH "SYNOPSIS" .B openocd \fR[\fB\-fsdlcphv\fR] [\fB\-\-file\fR <filename>] [\fB\-\-search\fR <dirname>] [\fB\-\-debug\fR <debuglevel>] [\fB\-\-log_output\fR <filename>] [\fB\-\-command\fR <cmd>] [\fB\-\-pipe\fR] [\fB\-\-help\fR] [\fB\-\-version\fR] .SH "DESCRIPTION" .B OpenOCD is an on\-chip debugging, in\-system programming and boundary\-scan testing tool for various ARM and MIPS systems. .PP The debugger uses an IEEE 1149\-1 compliant JTAG TAP bus master to access on\-chip debug functionality available on ARM based microcontrollers or system-on-chip solutions. For MIPS systems the EJTAG interface is supported. .PP User interaction is realized through a telnet command line interface, a gdb (the GNU debugger) remote protocol server, and a simplified RPC connection that can be used to interface with OpenOCD's Jim Tcl engine. .PP OpenOCD supports various different types of JTAG interfaces/programmers, please check the \fIopenocd\fR info page for the complete list. .SH "OPTIONS" .TP .B "\-f, \-\-file <filename>" This is a shortcut for a \fB\-c "[script \fI<filename>\fB]"\fR command, using a search path to load the configuration file .IR <filename> . In order to specify multiple config files, you can use multiple .B \-\-file arguments. If no such \fB\-c\fR options are included, the first config file .B openocd.cfg in the search path will be used. .TP .B "\-s, \-\-search <dirname>" Add .I <dirname> to the search path used for config files and scripts. The search path begins with the current directory, then includes these additional directories before other components such as the standard OpenOCD script libraries. .TP .B "\-d, \-\-debug <debuglevel>" Set debug level. Possible values are: .br .RB " * " 0 " (errors)" .br .RB " * " 1 " (warnings)" .br .RB " * " 2 " (informational messages)" .br .RB " * " 3 " (debug messages)" .br The default level is .BR 2 . .TP .B "\-l, \-\-log_output <filename>" Redirect log output to the file .IR <filename> . Per default the log output is printed on .BR stderr . .TP .B "\-c, \-\-command <cmd>" Add the command .I <cmd> to a list of commands executed on server startup. Note that you will need to explicitly invoke .I init if the command requires access to a target or flash. .TP .B "\-p, \-\-pipe" Use pipes when talking to gdb. .TP .B "\-h, \-\-help" Show a help text and exit. .TP .B "\-v, \-\-version" Show version information and exit. .SH "BUGS" Please report any bugs on the mailing list at .BR openocd\-devel@lists.sourceforge.net . .SH "LICENCE" .B OpenOCD is covered by the GNU General Public License (GPL), version 2 or later. .SH "SEE ALSO" .BR jtag (1) .PP The full documentation for .B openocd is maintained as a Texinfo manual. If the .BR info (or .BR pinfo ) and .BR openocd programs are properly installed at your site, the command .B info openocd should give you access to the complete manual. .SH "AUTHORS" Please see the file AUTHORS. .PP This manual page was written by Uwe Hermann <uwe@hermann\-uwe.de>. It is licensed under the terms of the GNU GPL (version 2 or later). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/openocd.texi ================================================ \input texinfo @c -*-texinfo-*- @c %**start of header @setfilename openocd.info @settitle OpenOCD User's Guide @dircategory Development @direntry * OpenOCD: (openocd). OpenOCD User's Guide @end direntry @paragraphindent 0 @c %**end of header @include version.texi @copying This User's Guide documents release @value{VERSION}, dated @value{UPDATED}, of the Open On-Chip Debugger (OpenOCD). @itemize @bullet @item Copyright @copyright{} 2008-2022 The OpenOCD Project @item Copyright @copyright{} 2007-2008 Spencer Oliver @email{spen@@spen-soft.co.uk} @item Copyright @copyright{} 2008-2010 Oyvind Harboe @email{oyvind.harboe@@zylin.com} @item Copyright @copyright{} 2008 Duane Ellis @email{openocd@@duaneellis.com} @item Copyright @copyright{} 2009-2010 David Brownell @end itemize @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. @end quotation @end copying @titlepage @titlefont{@emph{Open On-Chip Debugger:}} @sp 1 @title OpenOCD User's Guide @subtitle for release @value{VERSION} @subtitle @value{UPDATED} @page @vskip 0pt plus 1filll @insertcopying @end titlepage @summarycontents @contents @ifnottex @node Top @top OpenOCD User's Guide @insertcopying @end ifnottex @menu * About:: About OpenOCD * Developers:: OpenOCD Developer Resources * Debug Adapter Hardware:: Debug Adapter Hardware * About Jim-Tcl:: About Jim-Tcl * Running:: Running OpenOCD * OpenOCD Project Setup:: OpenOCD Project Setup * Config File Guidelines:: Config File Guidelines * Server Configuration:: Server Configuration * Debug Adapter Configuration:: Debug Adapter Configuration * Reset Configuration:: Reset Configuration * TAP Declaration:: TAP Declaration * CPU Configuration:: CPU Configuration * Flash Commands:: Flash Commands * Flash Programming:: Flash Programming * PLD/FPGA Commands:: PLD/FPGA Commands * General Commands:: General Commands * Architecture and Core Commands:: Architecture and Core Commands * JTAG Commands:: JTAG Commands * Boundary Scan Commands:: Boundary Scan Commands * Utility Commands:: Utility Commands * GDB and OpenOCD:: Using GDB and OpenOCD * Tcl Scripting API:: Tcl Scripting API * FAQ:: Frequently Asked Questions * Tcl Crash Course:: Tcl Crash Course * License:: GNU Free Documentation License @comment DO NOT use the plain word ``Index'', reason: CYGWIN filename @comment case issue with ``Index.html'' and ``index.html'' @comment Occurs when creating ``--html --no-split'' output @comment This fix is based on: http://sourceware.org/ml/binutils/2006-05/msg00215.html * OpenOCD Concept Index:: Concept Index * Command and Driver Index:: Command and Driver Index @end menu @node About @unnumbered About @cindex about OpenOCD was created by Dominic Rath as part of a 2005 diploma thesis written at the University of Applied Sciences Augsburg (@uref{http://www.hs-augsburg.de}). Since that time, the project has grown into an active open-source project, supported by a diverse community of software and hardware developers from around the world. @section What is OpenOCD? @cindex TAP @cindex JTAG The Open On-Chip Debugger (OpenOCD) aims to provide debugging, in-system programming and boundary-scan testing for embedded target devices. It does so with the assistance of a @dfn{debug adapter}, which is a small hardware module which helps provide the right kind of electrical signaling to the target being debugged. These are required since the debug host (on which OpenOCD runs) won't usually have native support for such signaling, or the connector needed to hook up to the target. Such debug adapters support one or more @dfn{transport} protocols, each of which involves different electrical signaling (and uses different messaging protocols on top of that signaling). There are many types of debug adapter, and little uniformity in what they are called. (There are also product naming differences.) These adapters are sometimes packaged as discrete dongles, which may generically be called @dfn{hardware interface dongles}. Some development boards also integrate them directly, which may let the development board connect directly to the debug host over USB (and sometimes also to power it over USB). For example, a @dfn{JTAG Adapter} supports JTAG signaling, and is used to communicate with JTAG (IEEE 1149.1) compliant TAPs on your target board. A @dfn{TAP} is a ``Test Access Port'', a module which processes special instructions and data. TAPs are daisy-chained within and between chips and boards. JTAG supports debugging and boundary scan operations. There are also @dfn{SWD Adapters} that support Serial Wire Debug (SWD) signaling to communicate with some newer ARM cores, as well as debug adapters which support both JTAG and SWD transports. SWD supports only debugging, whereas JTAG also supports boundary scan operations. For some chips, there are also @dfn{Programming Adapters} supporting special transports used only to write code to flash memory, without support for on-chip debugging or boundary scan. (At this writing, OpenOCD does not support such non-debug adapters.) @b{Dongles:} OpenOCD currently supports many types of hardware dongles: USB-based, parallel port-based, and other standalone boxes that run OpenOCD internally. @xref{Debug Adapter Hardware}. @b{GDB Debug:} It allows ARM7 (ARM7TDMI and ARM720t), ARM9 (ARM920T, ARM922T, ARM926EJ--S, ARM966E--S), XScale (PXA25x, IXP42x), Cortex-M3 (Stellaris LM3, STMicroelectronics STM32 and Energy Micro EFM32) and Intel Quark (x10xx) based cores to be debugged via the GDB protocol. @b{Flash Programming:} Flash writing is supported for external CFI-compatible NOR flashes (Intel and AMD/Spansion command set) and several internal flashes (LPC1700, LPC1800, LPC2000, LPC4300, AT91SAM7, AT91SAM3U, STR7x, STR9x, LM3, STM32x and EFM32). Preliminary support for various NAND flash controllers (LPC3180, Orion, S3C24xx, more) is included. @section OpenOCD Web Site The OpenOCD web site provides the latest public news from the community: @uref{http://openocd.org/} @section Latest User's Guide: The user's guide you are now reading may not be the latest one available. A version for more recent code may be available. Its HTML form is published regularly at: @uref{http://openocd.org/doc/html/index.html} PDF form is likewise published at: @uref{http://openocd.org/doc/pdf/openocd.pdf} @section OpenOCD User's Forum There is an OpenOCD forum (phpBB) hosted by SparkFun, which might be helpful to you. Note that if you want anything to come to the attention of developers, you should post it to the OpenOCD Developer Mailing List instead of this forum. @uref{http://forum.sparkfun.com/viewforum.php?f=18} @section OpenOCD User's Mailing List The OpenOCD User Mailing List provides the primary means of communication between users: @uref{https://lists.sourceforge.net/mailman/listinfo/openocd-user} @section OpenOCD IRC Support can also be found on irc: @uref{irc://irc.libera.chat/openocd} @node Developers @chapter OpenOCD Developer Resources @cindex developers If you are interested in improving the state of OpenOCD's debugging and testing support, new contributions will be welcome. Motivated developers can produce new target, flash or interface drivers, improve the documentation, as well as more conventional bug fixes and enhancements. The resources in this chapter are available for developers wishing to explore or expand the OpenOCD source code. @section OpenOCD Git Repository During the 0.3.x release cycle, OpenOCD switched from Subversion to a Git repository hosted at SourceForge. The repository URL is: @uref{git://git.code.sf.net/p/openocd/code} or via http @uref{http://git.code.sf.net/p/openocd/code} You may prefer to use a mirror and the HTTP protocol: @uref{http://repo.or.cz/r/openocd.git} With standard Git tools, use @command{git clone} to initialize a local repository, and @command{git pull} to update it. There are also gitweb pages letting you browse the repository with a web browser, or download arbitrary snapshots without needing a Git client: @uref{http://repo.or.cz/w/openocd.git} The @file{README} file contains the instructions for building the project from the repository or a snapshot. Developers that want to contribute patches to the OpenOCD system are @b{strongly} encouraged to work against mainline. Patches created against older versions may require additional work from their submitter in order to be updated for newer releases. @section Doxygen Developer Manual During the 0.2.x release cycle, the OpenOCD project began providing a Doxygen reference manual. This document contains more technical information about the software internals, development processes, and similar documentation: @uref{http://openocd.org/doc/doxygen/html/index.html} This document is a work-in-progress, but contributions would be welcome to fill in the gaps. All of the source files are provided in-tree, listed in the Doxyfile configuration at the top of the source tree. @section Gerrit Review System All changes in the OpenOCD Git repository go through the web-based Gerrit Code Review System: @uref{https://review.openocd.org/} After a one-time registration and repository setup, anyone can push commits from their local Git repository directly into Gerrit. All users and developers are encouraged to review, test, discuss and vote for changes in Gerrit. The feedback provides the basis for a maintainer to eventually submit the change to the main Git repository. The @file{HACKING} file, also available as the Patch Guide in the Doxygen Developer Manual, contains basic information about how to connect a repository to Gerrit, prepare and push patches. Patch authors are expected to maintain their changes while they're in Gerrit, respond to feedback and if necessary rework and push improved versions of the change. @section OpenOCD Developer Mailing List The OpenOCD Developer Mailing List provides the primary means of communication between developers: @uref{https://lists.sourceforge.net/mailman/listinfo/openocd-devel} @section OpenOCD Bug Tracker The OpenOCD Bug Tracker is hosted on SourceForge: @uref{http://bugs.openocd.org/} @node Debug Adapter Hardware @chapter Debug Adapter Hardware @cindex dongles @cindex FTDI @cindex wiggler @cindex printer port @cindex USB Adapter @cindex RTCK Defined: @b{dongle}: A small device that plugs into a computer and serves as an adapter .... [snip] In the OpenOCD case, this generally refers to @b{a small adapter} that attaches to your computer via USB or the parallel port. @section Choosing a Dongle There are several things you should keep in mind when choosing a dongle. @enumerate @item @b{Transport} Does it support the kind of communication that you need? OpenOCD focuses mostly on JTAG. Your version may also support other ways to communicate with target devices. @item @b{Voltage} What voltage is your target - 1.8, 2.8, 3.3, or 5V? Does your dongle support it? You might need a level converter. @item @b{Pinout} What pinout does your target board use? Does your dongle support it? You may be able to use jumper wires, or an "octopus" connector, to convert pinouts. @item @b{Connection} Does your computer have the USB, parallel, or Ethernet port needed? @item @b{RTCK} Do you expect to use it with ARM chips and boards with RTCK support (also known as ``adaptive clocking'')? @end enumerate @section USB FT2232 Based There are many USB JTAG dongles on the market, many of them based on a chip from ``Future Technology Devices International'' (FTDI) known as the FTDI FT2232; this is a USB full speed (12 Mbps) chip. See: @url{http://www.ftdichip.com} for more information. In summer 2009, USB high speed (480 Mbps) versions of these FTDI chips started to become available in JTAG adapters. Around 2012, a new variant appeared - FT232H - this is a single-channel version of FT2232H. (Adapters using those high speed FT2232H or FT232H chips may support adaptive clocking.) The FT2232 chips are flexible enough to support some other transport options, such as SWD or the SPI variants used to program some chips. They have two communications channels, and one can be used for a UART adapter at the same time the other one is used to provide a debug adapter. Also, some development boards integrate an FT2232 chip to serve as a built-in low-cost debug adapter and USB-to-serial solution. @itemize @bullet @item @b{usbjtag} @* Link @url{http://elk.informatik.fh-augsburg.de/hhweb/doc/openocd/usbjtag/usbjtag.html} @item @b{jtagkey} @* See: @url{http://www.amontec.com/jtagkey.shtml} @item @b{jtagkey2} @* See: @url{http://www.amontec.com/jtagkey2.shtml} @item @b{oocdlink} @* See: @url{http://www.oocdlink.com} By Joern Kaipf @item @b{signalyzer} @* See: @url{http://www.signalyzer.com} @item @b{Stellaris Eval Boards} @* See: @url{http://www.ti.com} - The Stellaris eval boards bundle FT2232-based JTAG and SWD support, which can be used to debug the Stellaris chips. Using separate JTAG adapters is optional. These boards can also be used in a "pass through" mode as JTAG adapters to other target boards, disabling the Stellaris chip. @item @b{TI/Luminary ICDI} @* See: @url{http://www.ti.com} - TI/Luminary In-Circuit Debug Interface (ICDI) Boards are included in Stellaris LM3S9B9x Evaluation Kits. Like the non-detachable FT2232 support on the other Stellaris eval boards, they can be used to debug other target boards. @item @b{olimex-jtag} @* See: @url{http://www.olimex.com} @item @b{Flyswatter/Flyswatter2} @* See: @url{http://www.tincantools.com} @item @b{turtelizer2} @* See: @uref{http://www.ethernut.de/en/hardware/turtelizer/index.html, Turtelizer 2}, or @url{http://www.ethernut.de} @item @b{comstick} @* Link: @url{http://www.hitex.com/index.php?id=383} @item @b{stm32stick} @* Link @url{http://www.hitex.com/stm32-stick} @item @b{axm0432_jtag} @* Axiom AXM-0432 Link @url{http://www.axman.com} - NOTE: This JTAG does not appear to be available anymore as of April 2012. @item @b{cortino} @* Link @url{http://www.hitex.com/index.php?id=cortino} @item @b{dlp-usb1232h} @* Link @url{http://www.dlpdesign.com/usb/usb1232h.shtml} @item @b{digilent-hs1} @* Link @url{http://www.digilentinc.com/Products/Detail.cfm?Prod=JTAG-HS1} @item @b{opendous} @* Link @url{http://code.google.com/p/opendous/wiki/JTAG} FT2232H-based (OpenHardware). @item @b{JTAG-lock-pick Tiny 2} @* Link @url{http://www.distortec.com/jtag-lock-pick-tiny-2} FT232H-based @item @b{GW16042} @* Link: @url{http://shop.gateworks.com/index.php?route=product/product&path=70_80&product_id=64} FT2232H-based @end itemize @section USB-JTAG / Altera USB-Blaster compatibles These devices also show up as FTDI devices, but are not protocol-compatible with the FT2232 devices. They are, however, protocol-compatible among themselves. USB-JTAG devices typically consist of a FT245 followed by a CPLD that understands a particular protocol, or emulates this protocol using some other hardware. They may appear under different USB VID/PID depending on the particular product. The driver can be configured to search for any VID/PID pair (see the section on driver commands). @itemize @item @b{USB-JTAG} Kolja Waschk's USB Blaster-compatible adapter @* Link: @url{http://ixo-jtag.sourceforge.net/} @item @b{Altera USB-Blaster} @* Link: @url{http://www.altera.com/literature/ug/ug_usb_blstr.pdf} @end itemize @section USB J-Link based There are several OEM versions of the SEGGER @b{J-Link} adapter. It is an example of a microcontroller based JTAG adapter, it uses an AT91SAM764 internally. @itemize @bullet @item @b{SEGGER J-Link} @* Link: @url{http://www.segger.com/jlink.html} @item @b{Atmel SAM-ICE} (Only works with Atmel chips!) @* Link: @url{http://www.atmel.com/tools/atmelsam-ice.aspx} @item @b{IAR J-Link} @end itemize @section USB RLINK based Raisonance has an adapter called @b{RLink}. It exists in a stripped-down form on the STM32 Primer, permanently attached to the JTAG lines. It also exists on the STM32 Primer2, but that is wired for SWD and not JTAG, thus not supported. @itemize @bullet @item @b{Raisonance RLink} @* Link: @url{http://www.mcu-raisonance.com/~rlink-debugger-programmer__@/microcontrollers__tool~tool__T018:4cn9ziz4bnx6.html} @item @b{STM32 Primer} @* Link: @url{http://www.stm32circle.com/resources/stm32primer.php} @item @b{STM32 Primer2} @* Link: @url{http://www.stm32circle.com/resources/stm32primer2.php} @end itemize @section USB ST-LINK based STMicroelectronics has an adapter called @b{ST-LINK}. They only work with STMicroelectronics chips, notably STM32 and STM8. @itemize @bullet @item @b{ST-LINK} @* This is available standalone and as part of some kits, eg. STM32VLDISCOVERY. @* Link: @url{http://www.st.com/internet/evalboard/product/219866.jsp} @item @b{ST-LINK/V2} @* This is available standalone and as part of some kits, eg. STM32F4DISCOVERY. @* Link: @url{http://www.st.com/internet/evalboard/product/251168.jsp} @item @b{STLINK-V3} @* This is available standalone and as part of some kits. @* Link: @url{http://www.st.com/stlink-v3} @item @b{STLINK-V3PWR} @* This is available standalone. Beside the debugger functionality, the probe includes a SMU (source measurement unit) aimed at analyzing power consumption during code execution. The SMU is not supported by OpenOCD. @* Link: @url{http://www.st.com/stlink-v3pwr} @end itemize For info the original ST-LINK enumerates using the mass storage usb class; however, its implementation is completely broken. The result is this causes issues under Linux. The simplest solution is to get Linux to ignore the ST-LINK using one of the following methods: @itemize @bullet @item modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:i @item add "options usb-storage quirks=483:3744:i" to /etc/modprobe.conf @end itemize @section USB TI/Stellaris ICDI based Texas Instruments has an adapter called @b{ICDI}. It is not to be confused with the FTDI based adapters that were originally fitted to their evaluation boards. This is the adapter fitted to the Stellaris LaunchPad. @section USB Nuvoton Nu-Link Nuvoton has an adapter called @b{Nu-Link}. It is available either as stand-alone dongle and embedded on development boards. It supports SWD, serial port bridge and mass storage for firmware update. Both Nu-Link v1 and v2 are supported. @section USB CMSIS-DAP based ARM has released a interface standard called CMSIS-DAP that simplifies connecting debuggers to ARM Cortex based targets @url{http://www.keil.com/support/man/docs/dapdebug/dapdebug_introduction.htm}. @section USB Other @itemize @bullet @item @b{USBprog} @* Link: @url{http://shop.embedded-projects.net/} - which uses an Atmel MEGA32 and a UBN9604 @item @b{USB - Presto} @* Link: @url{http://tools.asix.net/prg_presto.htm} @item @b{Versaloon-Link} @* Link: @url{http://www.versaloon.com} @item @b{ARM-JTAG-EW} @* Link: @url{http://www.olimex.com/dev/arm-jtag-ew.html} @item @b{Buspirate} @* Link: @url{http://dangerousprototypes.com/bus-pirate-manual/} @item @b{opendous} @* Link: @url{http://code.google.com/p/opendous-jtag/} - which uses an AT90USB162 @item @b{estick} @* Link: @url{http://code.google.com/p/estick-jtag/} @item @b{Keil ULINK v1} @* Link: @url{http://www.keil.com/ulink1/} @item @b{TI XDS110 Debug Probe} @* Link: @url{https://software-dl.ti.com/ccs/esd/documents/xdsdebugprobes/emu_xds110.html} @* Link: @url{https://software-dl.ti.com/ccs/esd/documents/xdsdebugprobes/emu_xds_software_package_download.html#xds110-support-utilities} @end itemize @section IBM PC Parallel Printer Port Based The two well-known ``JTAG Parallel Ports'' cables are the Xilinx DLC5 and the Macraigor Wiggler. There are many clones and variations of these on the market. Note that parallel ports are becoming much less common, so if you have the choice you should probably avoid these adapters in favor of USB-based ones. @itemize @bullet @item @b{Wiggler} - There are many clones of this. @* Link: @url{http://www.macraigor.com/wiggler.htm} @item @b{DLC5} - From XILINX - There are many clones of this @* Link: Search the web for: ``XILINX DLC5'' - it is no longer produced, PDF schematics are easily found and it is easy to make. @item @b{Amontec - JTAG Accelerator} @* Link: @url{http://www.amontec.com/jtag_accelerator.shtml} @item @b{Wiggler2} @* Link: @url{http://www.ccac.rwth-aachen.de/~michaels/index.php/hardware/armjtag} @item @b{Wiggler_ntrst_inverted} @* Yet another variation - See the source code, src/jtag/parport.c @item @b{old_amt_wiggler} @* Unknown - probably not on the market today @item @b{arm-jtag} @* Link: Most likely @url{http://www.olimex.com/dev/arm-jtag.html} [another wiggler clone] @item @b{chameleon} @* Link: @url{http://www.amontec.com/chameleon.shtml} @item @b{Triton} @* Unknown. @item @b{Lattice} @* ispDownload from Lattice Semiconductor @url{http://www.latticesemi.com/lit/docs/@/devtools/dlcable.pdf} @item @b{flashlink} @* From STMicroelectronics; @* Link: @url{http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATA_BRIEF/DM00039500.pdf} @end itemize @section Other... @itemize @bullet @item @b{ep93xx} @* An EP93xx based Linux machine using the GPIO pins directly. @item @b{at91rm9200} @* Like the EP93xx - but an ATMEL AT91RM9200 based solution using the GPIO pins on the chip. @item @b{bcm2835gpio} @* A BCM2835-based board (e.g. Raspberry Pi) using the GPIO pins of the expansion header. @item @b{imx_gpio} @* A NXP i.MX-based board (e.g. Wandboard) using the GPIO pins (should work on any i.MX processor). @item @b{am335xgpio} @* A Texas Instruments AM335x-based board (e.g. BeagleBone Black) using the GPIO pins of the expansion headers. @item @b{jtag_vpi} @* A JTAG driver acting as a client for the JTAG VPI server interface. @* Link: @url{http://github.com/fjullien/jtag_vpi} @item @b{vdebug} @* A driver for Cadence virtual Debug Interface to emulated or simulated targets. It implements a client connecting to the vdebug server, which in turn communicates with the emulated or simulated RTL model through a transactor. The driver supports JTAG and DAP-level transports. @item @b{jtag_dpi} @* A JTAG driver acting as a client for the SystemVerilog Direct Programming Interface (DPI) for JTAG devices. DPI allows OpenOCD to connect to the JTAG interface of a hardware model written in SystemVerilog, for example, on an emulation model of target hardware. @item @b{xlnx_pcie_xvc} @* A JTAG driver exposing Xilinx Virtual Cable over PCI Express to OpenOCD as JTAG/SWD interface. @item @b{linuxgpiod} @* A bitbang JTAG driver using Linux GPIO through library libgpiod. @item @b{sysfsgpio} @* A bitbang JTAG driver using Linux legacy sysfs GPIO. This is deprecated from Linux v5.3; prefer using @b{linuxgpiod}. @item @b{esp_usb_jtag} @* A JTAG driver to communicate with builtin debug modules of Espressif ESP32-C3 and ESP32-S3 chips using OpenOCD. @end itemize @node About Jim-Tcl @chapter About Jim-Tcl @cindex Jim-Tcl @cindex tcl OpenOCD uses a small ``Tcl Interpreter'' known as Jim-Tcl. This programming language provides a simple and extensible command interpreter. All commands presented in this Guide are extensions to Jim-Tcl. You can use them as simple commands, without needing to learn much of anything about Tcl. Alternatively, you can write Tcl programs with them. You can learn more about Jim at its website, @url{http://jim.tcl.tk}. There is an active and responsive community, get on the mailing list if you have any questions. Jim-Tcl maintainers also lurk on the OpenOCD mailing list. @itemize @bullet @item @b{Jim vs. Tcl} @* Jim-Tcl is a stripped down version of the well known Tcl language, which can be found here: @url{http://www.tcl.tk}. Jim-Tcl has far fewer features. Jim-Tcl is several dozens of .C files and .H files and implements the basic Tcl command set. In contrast: Tcl 8.6 is a 4.2 MB .zip file containing 1540 files. @item @b{Missing Features} @* Our practice has been: Add/clone the real Tcl feature if/when needed. We welcome Jim-Tcl improvements, not bloat. Also there are a large number of optional Jim-Tcl features that are not enabled in OpenOCD. @item @b{Scripts} @* OpenOCD configuration scripts are Jim-Tcl Scripts. OpenOCD's command interpreter today is a mixture of (newer) Jim-Tcl commands, and the (older) original command interpreter. @item @b{Commands} @* At the OpenOCD telnet command line (or via the GDB monitor command) one can type a Tcl for() loop, set variables, etc. Some of the commands documented in this guide are implemented as Tcl scripts, from a @file{startup.tcl} file internal to the server. @item @b{Historical Note} @* Jim-Tcl was introduced to OpenOCD in spring 2008. Fall 2010, before OpenOCD 0.5 release, OpenOCD switched to using Jim-Tcl as a Git submodule, which greatly simplified upgrading Jim-Tcl to benefit from new features and bugfixes in Jim-Tcl. @item @b{Need a crash course in Tcl?} @*@xref{Tcl Crash Course}. @end itemize @node Running @chapter Running @cindex command line options @cindex logfile @cindex directory search Properly installing OpenOCD sets up your operating system to grant it access to the debug adapters. On Linux, this usually involves installing a file in @file{/etc/udev/rules.d,} so OpenOCD has permissions. An example rules file that works for many common adapters is shipped with OpenOCD in the @file{contrib} directory. MS-Windows needs complex and confusing driver configuration for every peripheral. Such issues are unique to each operating system, and are not detailed in this User's Guide. Then later you will invoke the OpenOCD server, with various options to tell it how each debug session should work. The @option{--help} option shows: @verbatim bash$ openocd --help --help | -h display this help --version | -v display OpenOCD version --file | -f use configuration file <name> --search | -s dir to search for config files and scripts --debug | -d set debug level to 3 | -d<n> set debug level to <level> --log_output | -l redirect log output to file <name> --command | -c run <command> @end verbatim If you don't give any @option{-f} or @option{-c} options, OpenOCD tries to read the configuration file @file{openocd.cfg}. To specify one or more different configuration files, use @option{-f} options. For example: @example openocd -f config1.cfg -f config2.cfg -f config3.cfg @end example Configuration files and scripts are searched for in @enumerate @item the current directory, @item any search dir specified on the command line using the @option{-s} option, @item any search dir specified using the @command{add_script_search_dir} command, @item a directory in the @env{OPENOCD_SCRIPTS} environment variable (if set), @item @file{%APPDATA%/OpenOCD} (only on Windows), @item @file{$HOME/Library/Preferences/org.openocd} (only on Darwin), @item @file{$XDG_CONFIG_HOME/openocd} (@env{$XDG_CONFIG_HOME} defaults to @file{$HOME/.config}), @item @file{$HOME/.openocd}, @item the site wide script library @file{$pkgdatadir/site} and @item the OpenOCD-supplied script library @file{$pkgdatadir/scripts}. @end enumerate The first found file with a matching file name will be used. @quotation Note Don't try to use configuration script names or paths which include the "#" character. That character begins Tcl comments. @end quotation @section Simple setup, no customization In the best case, you can use two scripts from one of the script libraries, hook up your JTAG adapter, and start the server ... and your JTAG setup will just work "out of the box". Always try to start by reusing those scripts, but assume you'll need more customization even if this works. @xref{OpenOCD Project Setup}. If you find a script for your JTAG adapter, and for your board or target, you may be able to hook up your JTAG adapter then start the server with some variation of one of the following: @example openocd -f interface/ADAPTER.cfg -f board/MYBOARD.cfg openocd -f interface/ftdi/ADAPTER.cfg -f board/MYBOARD.cfg @end example You might also need to configure which reset signals are present, using @option{-c 'reset_config trst_and_srst'} or something similar. If all goes well you'll see output something like @example Open On-Chip Debugger 0.4.0 (2010-01-14-15:06) For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : JTAG tap: lm3s.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3) @end example Seeing that "tap/device found" message, and no warnings, means the JTAG communication is working. That's a key milestone, but you'll probably need more project-specific setup. @section What OpenOCD does as it starts OpenOCD starts by processing the configuration commands provided on the command line or, if there were no @option{-c command} or @option{-f file.cfg} options given, in @file{openocd.cfg}. @xref{configurationstage,,Configuration Stage}. At the end of the configuration stage it verifies the JTAG scan chain defined using those commands; your configuration should ensure that this always succeeds. Normally, OpenOCD then starts running as a server. Alternatively, commands may be used to terminate the configuration stage early, perform work (such as updating some flash memory), and then shut down without acting as a server. Once OpenOCD starts running as a server, it waits for connections from clients (Telnet, GDB, RPC) and processes the commands issued through those channels. If you are having problems, you can enable internal debug messages via the @option{-d} option. Also it is possible to interleave Jim-Tcl commands w/config scripts using the @option{-c} command line switch. To enable debug output (when reporting problems or working on OpenOCD itself), use the @option{-d} command line switch. This sets the @option{debug_level} to "3", outputting the most information, including debug messages. The default setting is "2", outputting only informational messages, warnings and errors. You can also change this setting from within a telnet or gdb session using @command{debug_level<n>} (@pxref{debuglevel,,debug_level}). You can redirect all output from the server to a file using the @option{-l <logfile>} switch. Note! OpenOCD will launch the GDB & telnet server even if it can not establish a connection with the target. In general, it is possible for the JTAG controller to be unresponsive until the target is set up correctly via e.g. GDB monitor commands in a GDB init script. @node OpenOCD Project Setup @chapter OpenOCD Project Setup To use OpenOCD with your development projects, you need to do more than just connect the JTAG adapter hardware (dongle) to your development board and start the OpenOCD server. You also need to configure your OpenOCD server so that it knows about your adapter and board, and helps your work. You may also want to connect OpenOCD to GDB, possibly using Eclipse or some other GUI. @section Hooking up the JTAG Adapter Today's most common case is a dongle with a JTAG cable on one side (such as a ribbon cable with a 10-pin or 20-pin IDC connector) and a USB cable on the other. Instead of USB, some dongles use Ethernet; older ones may use a PC parallel port, or even a serial port. @enumerate @item @emph{Start with power to your target board turned off}, and nothing connected to your JTAG adapter. If you're particularly paranoid, unplug power to the board. It's important to have the ground signal properly set up, unless you are using a JTAG adapter which provides galvanic isolation between the target board and the debugging host. @item @emph{Be sure it's the right kind of JTAG connector.} If your dongle has a 20-pin ARM connector, you need some kind of adapter (or octopus, see below) to hook it up to boards using 14-pin or 10-pin connectors ... or to 20-pin connectors which don't use ARM's pinout. In the same vein, make sure the voltage levels are compatible. Not all JTAG adapters have the level shifters needed to work with 1.2 Volt boards. @item @emph{Be certain the cable is properly oriented} or you might damage your board. In most cases there are only two possible ways to connect the cable. Connect the JTAG cable from your adapter to the board. Be sure it's firmly connected. In the best case, the connector is keyed to physically prevent you from inserting it wrong. This is most often done using a slot on the board's male connector housing, which must match a key on the JTAG cable's female connector. If there's no housing, then you must look carefully and make sure pin 1 on the cable hooks up to pin 1 on the board. Ribbon cables are frequently all grey except for a wire on one edge, which is red. The red wire is pin 1. Sometimes dongles provide cables where one end is an ``octopus'' of color coded single-wire connectors, instead of a connector block. These are great when converting from one JTAG pinout to another, but are tedious to set up. Use these with connector pinout diagrams to help you match up the adapter signals to the right board pins. @item @emph{Connect the adapter's other end} once the JTAG cable is connected. A USB, parallel, or serial port connector will go to the host which you are using to run OpenOCD. For Ethernet, consult the documentation and your network administrator. For USB-based JTAG adapters you have an easy sanity check at this point: does the host operating system see the JTAG adapter? If you're running Linux, try the @command{lsusb} command. If that host is an MS-Windows host, you'll need to install a driver before OpenOCD works. @item @emph{Connect the adapter's power supply, if needed.} This step is primarily for non-USB adapters, but sometimes USB adapters need extra power. @item @emph{Power up the target board.} Unless you just let the magic smoke escape, you're now ready to set up the OpenOCD server so you can use JTAG to work with that board. @end enumerate Talk with the OpenOCD server using telnet (@code{telnet localhost 4444} on many systems) or GDB. @xref{GDB and OpenOCD}. @section Project Directory There are many ways you can configure OpenOCD and start it up. A simple way to organize them all involves keeping a single directory for your work with a given board. When you start OpenOCD from that directory, it searches there first for configuration files, scripts, files accessed through semihosting, and for code you upload to the target board. It is also the natural place to write files, such as log files and data you download from the board. @section Configuration Basics There are two basic ways of configuring OpenOCD, and a variety of ways you can mix them. Think of the difference as just being how you start the server: @itemize @item Many @option{-f file} or @option{-c command} options on the command line @item No options, but a @dfn{user config file} in the current directory named @file{openocd.cfg} @end itemize Here is an example @file{openocd.cfg} file for a setup using a Signalyzer FT2232-based JTAG adapter to talk to a board with an Atmel AT91SAM7X256 microcontroller: @example source [find interface/ftdi/signalyzer.cfg] # GDB can also flash my flash! gdb_memory_map enable gdb_flash_program enable source [find target/sam7x256.cfg] @end example Here is the command line equivalent of that configuration: @example openocd -f interface/ftdi/signalyzer.cfg \ -c "gdb_memory_map enable" \ -c "gdb_flash_program enable" \ -f target/sam7x256.cfg @end example You could wrap such long command lines in shell scripts, each supporting a different development task. One might re-flash the board with a specific firmware version. Another might set up a particular debugging or run-time environment. @quotation Important At this writing (October 2009) the command line method has problems with how it treats variables. For example, after @option{-c "set VAR value"}, or doing the same in a script, the variable @var{VAR} will have no value that can be tested in a later script. @end quotation Here we will focus on the simpler solution: one user config file, including basic configuration plus any TCL procedures to simplify your work. @section User Config Files @cindex config file, user @cindex user config file @cindex config file, overview A user configuration file ties together all the parts of a project in one place. One of the following will match your situation best: @itemize @item Ideally almost everything comes from configuration files provided by someone else. For example, OpenOCD distributes a @file{scripts} directory (probably in @file{/usr/share/openocd/scripts} on Linux). Board and tool vendors can provide these too, as can individual user sites; the @option{-s} command line option lets you say where to find these files. (@xref{Running}.) The AT91SAM7X256 example above works this way. Three main types of non-user configuration file each have their own subdirectory in the @file{scripts} directory: @enumerate @item @b{interface} -- one for each different debug adapter; @item @b{board} -- one for each different board @item @b{target} -- the chips which integrate CPUs and other JTAG TAPs @end enumerate Best case: include just two files, and they handle everything else. The first is an interface config file. The second is board-specific, and it sets up the JTAG TAPs and their GDB targets (by deferring to some @file{target.cfg} file), declares all flash memory, and leaves you nothing to do except meet your deadline: @example source [find interface/olimex-jtag-tiny.cfg] source [find board/csb337.cfg] @end example Boards with a single microcontroller often won't need more than the target config file, as in the AT91SAM7X256 example. That's because there is no external memory (flash, DDR RAM), and the board differences are encapsulated by application code. @item Maybe you don't know yet what your board looks like to JTAG. Once you know the @file{interface.cfg} file to use, you may need help from OpenOCD to discover what's on the board. Once you find the JTAG TAPs, you can just search for appropriate target and board configuration files ... or write your own, from the bottom up. @xref{autoprobing,,Autoprobing}. @item You can often reuse some standard config files but need to write a few new ones, probably a @file{board.cfg} file. You will be using commands described later in this User's Guide, and working with the guidelines in the next chapter. For example, there may be configuration files for your JTAG adapter and target chip, but you need a new board-specific config file giving access to your particular flash chips. Or you might need to write another target chip configuration file for a new chip built around the Cortex-M3 core. @quotation Note When you write new configuration files, please submit them for inclusion in the next OpenOCD release. For example, a @file{board/newboard.cfg} file will help the next users of that board, and a @file{target/newcpu.cfg} will help support users of any board using that chip. @end quotation @item You may need to write some C code. It may be as simple as supporting a new FT2232 or parport based adapter; a bit more involved, like a NAND or NOR flash controller driver; or a big piece of work like supporting a new chip architecture. @end itemize Reuse the existing config files when you can. Look first in the @file{scripts/boards} area, then @file{scripts/targets}. You may find a board configuration that's a good example to follow. When you write config files, separate the reusable parts (things every user of that interface, chip, or board needs) from ones specific to your environment and debugging approach. @itemize @item For example, a @code{gdb-attach} event handler that invokes the @command{reset init} command will interfere with debugging early boot code, which performs some of the same actions that the @code{reset-init} event handler does. @item Likewise, the @command{arm9 vector_catch} command (or @cindex vector_catch its siblings @command{xscale vector_catch} and @command{cortex_m vector_catch}) can be a time-saver during some debug sessions, but don't make everyone use that either. Keep those kinds of debugging aids in your user config file, along with messaging and tracing setup. (@xref{softwaredebugmessagesandtracing,,Software Debug Messages and Tracing}.) @item You might need to override some defaults. For example, you might need to move, shrink, or back up the target's work area if your application needs much SRAM. @item TCP/IP port configuration is another example of something which is environment-specific, and should only appear in a user config file. @xref{tcpipports,,TCP/IP Ports}. @end itemize @section Project-Specific Utilities A few project-specific utility routines may well speed up your work. Write them, and keep them in your project's user config file. For example, if you are making a boot loader work on a board, it's nice to be able to debug the ``after it's loaded to RAM'' parts separately from the finicky early code which sets up the DDR RAM controller and clocks. A script like this one, or a more GDB-aware sibling, may help: @example proc ramboot @{ @} @{ # Reset, running the target's "reset-init" scripts # to initialize clocks and the DDR RAM controller. # Leave the CPU halted. reset init # Load CONFIG_SKIP_LOWLEVEL_INIT version into DDR RAM. load_image u-boot.bin 0x20000000 # Start running. resume 0x20000000 @} @end example Then once that code is working you will need to make it boot from NOR flash; a different utility would help. Alternatively, some developers write to flash using GDB. (You might use a similar script if you're working with a flash based microcontroller application instead of a boot loader.) @example proc newboot @{ @} @{ # Reset, leaving the CPU halted. The "reset-init" event # proc gives faster access to the CPU and to NOR flash; # "reset halt" would be slower. reset init # Write standard version of U-Boot into the first two # sectors of NOR flash ... the standard version should # do the same lowlevel init as "reset-init". flash protect 0 0 1 off flash erase_sector 0 0 1 flash write_bank 0 u-boot.bin 0x0 flash protect 0 0 1 on # Reboot from scratch using that new boot loader. reset run @} @end example You may need more complicated utility procedures when booting from NAND. That often involves an extra bootloader stage, running from on-chip SRAM to perform DDR RAM setup so it can load the main bootloader code (which won't fit into that SRAM). Other helper scripts might be used to write production system images, involving considerably more than just a three stage bootloader. @section Target Software Changes Sometimes you may want to make some small changes to the software you're developing, to help make JTAG debugging work better. For example, in C or assembly language code you might use @code{#ifdef JTAG_DEBUG} (or its converse) around code handling issues like: @itemize @bullet @item @b{Watchdog Timers}... Watchdog timers are typically used to automatically reset systems if some application task doesn't periodically reset the timer. (The assumption is that the system has locked up if the task can't run.) When a JTAG debugger halts the system, that task won't be able to run and reset the timer ... potentially causing resets in the middle of your debug sessions. It's rarely a good idea to disable such watchdogs, since their usage needs to be debugged just like all other parts of your firmware. That might however be your only option. Look instead for chip-specific ways to stop the watchdog from counting while the system is in a debug halt state. It may be simplest to set that non-counting mode in your debugger startup scripts. You may however need a different approach when, for example, a motor could be physically damaged by firmware remaining inactive in a debug halt state. That might involve a type of firmware mode where that "non-counting" mode is disabled at the beginning then re-enabled at the end; a watchdog reset might fire and complicate the debug session, but hardware (or people) would be protected.@footnote{Note that many systems support a "monitor mode" debug that is a somewhat cleaner way to address such issues. You can think of it as only halting part of the system, maybe just one task, instead of the whole thing. At this writing, January 2010, OpenOCD based debugging does not support monitor mode debug, only "halt mode" debug.} @item @b{ARM Semihosting}... @cindex ARM semihosting When linked with a special runtime library provided with many toolchains@footnote{See chapter 8 "Semihosting" in @uref{http://infocenter.arm.com/help/topic/com.arm.doc.dui0203i/DUI0203I_rvct_developer_guide.pdf, ARM DUI 0203I}, the "RealView Compilation Tools Developer Guide". The CodeSourcery EABI toolchain also includes a semihosting library.}, your target code can use I/O facilities on the debug host. That library provides a small set of system calls which are handled by OpenOCD. It can let the debugger provide your system console and a file system, helping with early debugging or providing a more capable environment for sometimes-complex tasks like installing system firmware onto NAND or SPI flash. @item @b{ARM Wait-For-Interrupt}... Many ARM chips synchronize the JTAG clock using the core clock. Low power states which stop that core clock thus prevent JTAG access. Idle loops in tasking environments often enter those low power states via the @code{WFI} instruction (or its coprocessor equivalent, before ARMv7). You may want to @emph{disable that instruction} in source code, or otherwise prevent using that state, to ensure you can get JTAG access at any time.@footnote{As a more polite alternative, some processors have special debug-oriented registers which can be used to change various features including how the low power states are clocked while debugging. The STM32 DBGMCU_CR register is an example; at the cost of extra power consumption, JTAG can be used during low power states.} For example, the OpenOCD @command{halt} command may not work for an idle processor otherwise. @item @b{Delay after reset}... Not all chips have good support for debugger access right after reset; many LPC2xxx chips have issues here. Similarly, applications that reconfigure pins used for JTAG access as they start will also block debugger access. To work with boards like this, @emph{enable a short delay loop} the first thing after reset, before "real" startup activities. For example, one second's delay is usually more than enough time for a JTAG debugger to attach, so that early code execution can be debugged or firmware can be replaced. @item @b{Debug Communications Channel (DCC)}... Some processors include mechanisms to send messages over JTAG. Many ARM cores support these, as do some cores from other vendors. (OpenOCD may be able to use this DCC internally, speeding up some operations like writing to memory.) Your application may want to deliver various debugging messages over JTAG, by @emph{linking with a small library of code} provided with OpenOCD and using the utilities there to send various kinds of message. @xref{softwaredebugmessagesandtracing,,Software Debug Messages and Tracing}. @end itemize @section Target Hardware Setup Chip vendors often provide software development boards which are highly configurable, so that they can support all options that product boards may require. @emph{Make sure that any jumpers or switches match the system configuration you are working with.} Common issues include: @itemize @bullet @item @b{JTAG setup} ... Boards may support more than one JTAG configuration. Examples include jumpers controlling pullups versus pulldowns on the nTRST and/or nSRST signals, and choice of connectors (e.g. which of two headers on the base board, or one from a daughtercard). For some Texas Instruments boards, you may need to jumper the EMU0 and EMU1 signals (which OpenOCD won't currently control). @item @b{Boot Modes} ... Complex chips often support multiple boot modes, controlled by external jumpers. Make sure this is set up correctly. For example many i.MX boards from NXP need to be jumpered to "ATX mode" to start booting using the on-chip ROM, when using second stage bootloader code stored in a NAND flash chip. Such explicit configuration is common, and not limited to booting from NAND. You might also need to set jumpers to start booting using code loaded from an MMC/SD card; external SPI flash; Ethernet, UART, or USB links; NOR flash; OneNAND flash; some external host; or various other sources. @item @b{Memory Addressing} ... Boards which support multiple boot modes may also have jumpers to configure memory addressing. One board, for example, jumpers external chipselect 0 (used for booting) to address either a large SRAM (which must be pre-loaded via JTAG), NOR flash, or NAND flash. When it's jumpered to address NAND flash, that board must also be told to start booting from on-chip ROM. Your @file{board.cfg} file may also need to be told this jumper configuration, so that it can know whether to declare NOR flash using @command{flash bank} or instead declare NAND flash with @command{nand device}; and likewise which probe to perform in its @code{reset-init} handler. A closely related issue is bus width. Jumpers might need to distinguish between 8 bit or 16 bit bus access for the flash used to start booting. @item @b{Peripheral Access} ... Development boards generally provide access to every peripheral on the chip, sometimes in multiple modes (such as by providing multiple audio codec chips). This interacts with software configuration of pin multiplexing, where for example a given pin may be routed either to the MMC/SD controller or the GPIO controller. It also often interacts with configuration jumpers. One jumper may be used to route signals to an MMC/SD card slot or an expansion bus (which might in turn affect booting); others might control which audio or video codecs are used. @end itemize Plus you should of course have @code{reset-init} event handlers which set up the hardware to match that jumper configuration. That includes in particular any oscillator or PLL used to clock the CPU, and any memory controllers needed to access external memory and peripherals. Without such handlers, you won't be able to access those resources without working target firmware which can do that setup ... this can be awkward when you're trying to debug that target firmware. Even if there's a ROM bootloader which handles a few issues, it rarely provides full access to all board-specific capabilities. @node Config File Guidelines @chapter Config File Guidelines This chapter is aimed at any user who needs to write a config file, including developers and integrators of OpenOCD and any user who needs to get a new board working smoothly. It provides guidelines for creating those files. You should find the following directories under @t{$(INSTALLDIR)/scripts}, with config files maintained upstream. Use them as-is where you can; or as models for new files. @itemize @bullet @item @file{interface} ... These are for debug adapters. Files that specify configuration to use specific JTAG, SWD and other adapters go here. @item @file{board} ... Think Circuit Board, PWA, PCB, they go by many names. Board files contain initialization items that are specific to a board. They reuse target configuration files, since the same microprocessor chips are used on many boards, but support for external parts varies widely. For example, the SDRAM initialization sequence for the board, or the type of external flash and what address it uses. Any initialization sequence to enable that external flash or SDRAM should be found in the board file. Boards may also contain multiple targets: two CPUs; or a CPU and an FPGA. @item @file{target} ... Think chip. The ``target'' directory represents the JTAG TAPs on a chip which OpenOCD should control, not a board. Two common types of targets are ARM chips and FPGA or CPLD chips. When a chip has multiple TAPs (maybe it has both ARM and DSP cores), the target config file defines all of them. @item @emph{more} ... browse for other library files which may be useful. For example, there are various generic and CPU-specific utilities. @end itemize The @file{openocd.cfg} user config file may override features in any of the above files by setting variables before sourcing the target file, or by adding commands specific to their situation. @section Interface Config Files The user config file should be able to source one of these files with a command like this: @example source [find interface/FOOBAR.cfg] @end example A preconfigured interface file should exist for every debug adapter in use today with OpenOCD. That said, perhaps some of these config files have only been used by the developer who created it. A separate chapter gives information about how to set these up. @xref{Debug Adapter Configuration}. Read the OpenOCD source code (and Developer's Guide) if you have a new kind of hardware interface and need to provide a driver for it. @deffn {Command} {find} 'filename' Prints full path to @var{filename} according to OpenOCD search rules. @end deffn @deffn {Command} {ocd_find} 'filename' Prints full path to @var{filename} according to OpenOCD search rules. This is a low level function used by the @command{find}. Usually you want to use @command{find}, instead. @end deffn @section Board Config Files @cindex config file, board @cindex board config file The user config file should be able to source one of these files with a command like this: @example source [find board/FOOBAR.cfg] @end example The point of a board config file is to package everything about a given board that user config files need to know. In summary the board files should contain (if present) @enumerate @item One or more @command{source [find target/...cfg]} statements @item NOR flash configuration (@pxref{norconfiguration,,NOR Configuration}) @item NAND flash configuration (@pxref{nandconfiguration,,NAND Configuration}) @item Target @code{reset} handlers for SDRAM and I/O configuration @item JTAG adapter reset configuration (@pxref{Reset Configuration}) @item All things that are not ``inside a chip'' @end enumerate Generic things inside target chips belong in target config files, not board config files. So for example a @code{reset-init} event handler should know board-specific oscillator and PLL parameters, which it passes to target-specific utility code. The most complex task of a board config file is creating such a @code{reset-init} event handler. Define those handlers last, after you verify the rest of the board configuration works. @subsection Communication Between Config files In addition to target-specific utility code, another way that board and target config files communicate is by following a convention on how to use certain variables. The full Tcl/Tk language supports ``namespaces'', but Jim-Tcl does not. Thus the rule we follow in OpenOCD is this: Variables that begin with a leading underscore are temporary in nature, and can be modified and used at will within a target configuration file. Complex board config files can do the things like this, for a board with three chips: @example # Chip #1: PXA270 for network side, big endian set CHIPNAME network set ENDIAN big source [find target/pxa270.cfg] # on return: _TARGETNAME = network.cpu # other commands can refer to the "network.cpu" target. $_TARGETNAME configure .... events for this CPU.. # Chip #2: PXA270 for video side, little endian set CHIPNAME video set ENDIAN little source [find target/pxa270.cfg] # on return: _TARGETNAME = video.cpu # other commands can refer to the "video.cpu" target. $_TARGETNAME configure .... events for this CPU.. # Chip #3: Xilinx FPGA for glue logic set CHIPNAME xilinx unset ENDIAN source [find target/spartan3.cfg] @end example That example is oversimplified because it doesn't show any flash memory, or the @code{reset-init} event handlers to initialize external DRAM or (assuming it needs it) load a configuration into the FPGA. Such features are usually needed for low-level work with many boards, where ``low level'' implies that the board initialization software may not be working. (That's a common reason to need JTAG tools. Another is to enable working with microcontroller-based systems, which often have no debugging support except a JTAG connector.) Target config files may also export utility functions to board and user config files. Such functions should use name prefixes, to help avoid naming collisions. Board files could also accept input variables from user config files. For example, there might be a @code{J4_JUMPER} setting used to identify what kind of flash memory a development board is using, or how to set up other clocks and peripherals. @subsection Variable Naming Convention @cindex variable names Most boards have only one instance of a chip. However, it should be easy to create a board with more than one such chip (as shown above). Accordingly, we encourage these conventions for naming variables associated with different @file{target.cfg} files, to promote consistency and so that board files can override target defaults. Inputs to target config files include: @itemize @bullet @item @code{CHIPNAME} ... This gives a name to the overall chip, and is used as part of tap identifier dotted names. While the default is normally provided by the chip manufacturer, board files may need to distinguish between instances of a chip. @item @code{ENDIAN} ... By default @option{little} - although chips may hard-wire @option{big}. Chips that can't change endianness don't need to use this variable. @item @code{CPUTAPID} ... When OpenOCD examines the JTAG chain, it can be told verify the chips against the JTAG IDCODE register. The target file will hold one or more defaults, but sometimes the chip in a board will use a different ID (perhaps a newer revision). @end itemize Outputs from target config files include: @itemize @bullet @item @code{_TARGETNAME} ... By convention, this variable is created by the target configuration script. The board configuration file may make use of this variable to configure things like a ``reset init'' script, or other things specific to that board and that target. If the chip has 2 targets, the names are @code{_TARGETNAME0}, @code{_TARGETNAME1}, ... etc. @end itemize @subsection The reset-init Event Handler @cindex event, reset-init @cindex reset-init handler Board config files run in the OpenOCD configuration stage; they can't use TAPs or targets, since they haven't been fully set up yet. This means you can't write memory or access chip registers; you can't even verify that a flash chip is present. That's done later in event handlers, of which the target @code{reset-init} handler is one of the most important. Except on microcontrollers, the basic job of @code{reset-init} event handlers is setting up flash and DRAM, as normally handled by boot loaders. Microcontrollers rarely use boot loaders; they run right out of their on-chip flash and SRAM memory. But they may want to use one of these handlers too, if just for developer convenience. @quotation Note Because this is so very board-specific, and chip-specific, no examples are included here. Instead, look at the board config files distributed with OpenOCD. If you have a boot loader, its source code will help; so will configuration files for other JTAG tools (@pxref{translatingconfigurationfiles,,Translating Configuration Files}). @end quotation Some of this code could probably be shared between different boards. For example, setting up a DRAM controller often doesn't differ by much except the bus width (16 bits or 32?) and memory timings, so a reusable TCL procedure loaded by the @file{target.cfg} file might take those as parameters. Similarly with oscillator, PLL, and clock setup; and disabling the watchdog. Structure the code cleanly, and provide comments to help the next developer doing such work. (@emph{You might be that next person} trying to reuse init code!) The last thing normally done in a @code{reset-init} handler is probing whatever flash memory was configured. For most chips that needs to be done while the associated target is halted, either because JTAG memory access uses the CPU or to prevent conflicting CPU access. @subsection JTAG Clock Rate Before your @code{reset-init} handler has set up the PLLs and clocking, you may need to run with a low JTAG clock rate. @xref{jtagspeed,,JTAG Speed}. Then you'd increase that rate after your handler has made it possible to use the faster JTAG clock. When the initial low speed is board-specific, for example because it depends on a board-specific oscillator speed, then you should probably set it up in the board config file; if it's target-specific, it belongs in the target config file. For most ARM-based processors the fastest JTAG clock@footnote{A FAQ @uref{http://www.arm.com/support/faqdev/4170.html} gives details.} is one sixth of the CPU clock; or one eighth for ARM11 cores. Consult chip documentation to determine the peak JTAG clock rate, which might be less than that. @quotation Warning On most ARMs, JTAG clock detection is coupled to the core clock, so software using a @option{wait for interrupt} operation blocks JTAG access. Adaptive clocking provides a partial workaround, but a more complete solution just avoids using that instruction with JTAG debuggers. @end quotation If both the chip and the board support adaptive clocking, use the @command{jtag_rclk} command, in case your board is used with JTAG adapter which also supports it. Otherwise use @command{adapter speed}. Set the slow rate at the beginning of the reset sequence, and the faster rate as soon as the clocks are at full speed. @anchor{theinitboardprocedure} @subsection The init_board procedure @cindex init_board procedure The concept of @code{init_board} procedure is very similar to @code{init_targets} (@xref{theinittargetsprocedure,,The init_targets procedure}.) - it's a replacement of ``linear'' configuration scripts. This procedure is meant to be executed when OpenOCD enters run stage (@xref{enteringtherunstage,,Entering the Run Stage},) after @code{init_targets}. The idea to have separate @code{init_targets} and @code{init_board} procedures is to allow the first one to configure everything target specific (internal flash, internal RAM, etc.) and the second one to configure everything board specific (reset signals, chip frequency, reset-init event handler, external memory, etc.). Additionally ``linear'' board config file will most likely fail when target config file uses @code{init_targets} scheme (``linear'' script is executed before @code{init} and @code{init_targets} - after), so separating these two configuration stages is very convenient, as the easiest way to overcome this problem is to convert board config file to use @code{init_board} procedure. Board config scripts don't need to override @code{init_targets} defined in target config files when they only need to add some specifics. Just as @code{init_targets}, the @code{init_board} procedure can be overridden by ``next level'' script (which sources the original), allowing greater code reuse. @example ### board_file.cfg ### # source target file that does most of the config in init_targets source [find target/target.cfg] proc enable_fast_clock @{@} @{ # enables fast on-board clock source # configures the chip to use it @} # initialize only board specifics - reset, clock, adapter frequency proc init_board @{@} @{ reset_config trst_and_srst trst_pulls_srst $_TARGETNAME configure -event reset-start @{ adapter speed 100 @} $_TARGETNAME configure -event reset-init @{ enable_fast_clock adapter speed 10000 @} @} @end example @section Target Config Files @cindex config file, target @cindex target config file Board config files communicate with target config files using naming conventions as described above, and may source one or more target config files like this: @example source [find target/FOOBAR.cfg] @end example The point of a target config file is to package everything about a given chip that board config files need to know. In summary the target files should contain @enumerate @item Set defaults @item Add TAPs to the scan chain @item Add CPU targets (includes GDB support) @item CPU/Chip/CPU-Core specific features @item On-Chip flash @end enumerate As a rule of thumb, a target file sets up only one chip. For a microcontroller, that will often include a single TAP, which is a CPU needing a GDB target, and its on-chip flash. More complex chips may include multiple TAPs, and the target config file may need to define them all before OpenOCD can talk to the chip. For example, some phone chips have JTAG scan chains that include an ARM core for operating system use, a DSP, another ARM core embedded in an image processing engine, and other processing engines. @subsection Default Value Boiler Plate Code All target configuration files should start with code like this, letting board config files express environment-specific differences in how things should be set up. @example # Boards may override chip names, perhaps based on role, # but the default should match what the vendor uses if @{ [info exists CHIPNAME] @} @{ set _CHIPNAME $CHIPNAME @} else @{ set _CHIPNAME sam7x256 @} # ONLY use ENDIAN with targets that can change it. if @{ [info exists ENDIAN] @} @{ set _ENDIAN $ENDIAN @} else @{ set _ENDIAN little @} # TAP identifiers may change as chips mature, for example with # new revision fields (the "3" here). Pick a good default; you # can pass several such identifiers to the "jtag newtap" command. if @{ [info exists CPUTAPID ] @} @{ set _CPUTAPID $CPUTAPID @} else @{ set _CPUTAPID 0x3f0f0f0f @} @end example @c but 0x3f0f0f0f is for an str73x part ... @emph{Remember:} Board config files may include multiple target config files, or the same target file multiple times (changing at least @code{CHIPNAME}). Likewise, the target configuration file should define @code{_TARGETNAME} (or @code{_TARGETNAME0} etc) and use it later on when defining debug targets: @example set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME @end example @subsection Adding TAPs to the Scan Chain After the ``defaults'' are set up, add the TAPs on each chip to the JTAG scan chain. @xref{TAP Declaration}, and the naming convention for taps. In the simplest case the chip has only one TAP, probably for a CPU or FPGA. The config file for the Atmel AT91SAM7X256 looks (in part) like this: @example jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID @end example A board with two such at91sam7 chips would be able to source such a config file twice, with different values for @code{CHIPNAME}, so it adds a different TAP each time. If there are nonzero @option{-expected-id} values, OpenOCD attempts to verify the actual tap id against those values. It will issue error messages if there is mismatch, which can help to pinpoint problems in OpenOCD configurations. @example JTAG tap: sam7x256.cpu tap/device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3) ERROR: Tap: sam7x256.cpu - Expected id: 0x12345678, Got: 0x3f0f0f0f ERROR: expected: mfg: 0x33c, part: 0x2345, ver: 0x1 ERROR: got: mfg: 0x787, part: 0xf0f0, ver: 0x3 @end example There are more complex examples too, with chips that have multiple TAPs. Ones worth looking at include: @itemize @item @file{target/omap3530.cfg} -- with disabled ARM and DSP, plus a JRC to enable them @item @file{target/str912.cfg} -- with flash, CPU, and boundary scan @item @file{target/ti_dm355.cfg} -- with ETM, ARM, and JRC (this JRC is not currently used) @end itemize @subsection Add CPU targets After adding a TAP for a CPU, you should set it up so that GDB and other commands can use it. @xref{CPU Configuration}. For the at91sam7 example above, the command can look like this; note that @code{$_ENDIAN} is not needed, since OpenOCD defaults to little endian, and this chip doesn't support changing that. @example set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME @end example Work areas are small RAM areas associated with CPU targets. They are used by OpenOCD to speed up downloads, and to download small snippets of code to program flash chips. If the chip includes a form of ``on-chip-ram'' - and many do - define a work area if you can. Again using the at91sam7 as an example, this can look like: @example $_TARGETNAME configure -work-area-phys 0x00200000 \ -work-area-size 0x4000 -work-area-backup 0 @end example @subsection Define CPU targets working in SMP @cindex SMP After setting targets, you can define a list of targets working in SMP. @example set _TARGETNAME_1 $_CHIPNAME.cpu1 set _TARGETNAME_2 $_CHIPNAME.cpu2 target create $_TARGETNAME_1 cortex_a -chain-position $_CHIPNAME.dap \ -coreid 0 -dbgbase $_DAP_DBG1 target create $_TARGETNAME_2 cortex_a -chain-position $_CHIPNAME.dap \ -coreid 1 -dbgbase $_DAP_DBG2 #define 2 targets working in smp. target smp $_CHIPNAME.cpu2 $_CHIPNAME.cpu1 @end example In the above example on cortex_a, 2 cpus are working in SMP. In SMP only one GDB instance is created and : @itemize @bullet @item a set of hardware breakpoint sets the same breakpoint on all targets in the list. @item halt command triggers the halt of all targets in the list. @item resume command triggers the write context and the restart of all targets in the list. @item following a breakpoint: the target stopped by the breakpoint is displayed to the GDB session. @item dedicated GDB serial protocol packets are implemented for switching/retrieving the target displayed by the GDB session @pxref{usingopenocdsmpwithgdb,,Using OpenOCD SMP with GDB}. @end itemize The SMP behaviour can be disabled/enabled dynamically. On cortex_a following command have been implemented. @itemize @bullet @item cortex_a smp on : enable SMP mode, behaviour is as described above. @item cortex_a smp off : disable SMP mode, the current target is the one displayed in the GDB session, only this target is now controlled by GDB session. This behaviour is useful during system boot up. @item cortex_a smp : display current SMP mode. @item cortex_a smp_gdb : display/fix the core id displayed in GDB session see following example. @end itemize @example >cortex_a smp_gdb gdb coreid 0 -> -1 #0 : coreid 0 is displayed to GDB , #-> -1 : next resume triggers a real resume > cortex_a smp_gdb 1 gdb coreid 0 -> 1 #0 :coreid 0 is displayed to GDB , #->1 : next resume displays coreid 1 to GDB > resume > cortex_a smp_gdb gdb coreid 1 -> 1 #1 :coreid 1 is displayed to GDB , #->1 : next resume displays coreid 1 to GDB > cortex_a smp_gdb -1 gdb coreid 1 -> -1 #1 :coreid 1 is displayed to GDB, #->-1 : next resume triggers a real resume @end example @subsection Chip Reset Setup As a rule, you should put the @command{reset_config} command into the board file. Most things you think you know about a chip can be tweaked by the board. Some chips have specific ways the TRST and SRST signals are managed. In the unusual case that these are @emph{chip specific} and can never be changed by board wiring, they could go here. For example, some chips can't support JTAG debugging without both signals. Provide a @code{reset-assert} event handler if you can. Such a handler uses JTAG operations to reset the target, letting this target config be used in systems which don't provide the optional SRST signal, or on systems where you don't want to reset all targets at once. Such a handler might write to chip registers to force a reset, use a JRC to do that (preferable -- the target may be wedged!), or force a watchdog timer to trigger. (For Cortex-M targets, this is not necessary. The target driver knows how to use trigger an NVIC reset when SRST is not available.) Some chips need special attention during reset handling if they're going to be used with JTAG. An example might be needing to send some commands right after the target's TAP has been reset, providing a @code{reset-deassert-post} event handler that writes a chip register to report that JTAG debugging is being done. Another would be reconfiguring the watchdog so that it stops counting while the core is halted in the debugger. JTAG clocking constraints often change during reset, and in some cases target config files (rather than board config files) are the right places to handle some of those issues. For example, immediately after reset most chips run using a slower clock than they will use later. That means that after reset (and potentially, as OpenOCD first starts up) they must use a slower JTAG clock rate than they will use later. @xref{jtagspeed,,JTAG Speed}. @quotation Important When you are debugging code that runs right after chip reset, getting these issues right is critical. In particular, if you see intermittent failures when OpenOCD verifies the scan chain after reset, look at how you are setting up JTAG clocking. @end quotation @anchor{theinittargetsprocedure} @subsection The init_targets procedure @cindex init_targets procedure Target config files can either be ``linear'' (script executed line-by-line when parsed in configuration stage, @xref{configurationstage,,Configuration Stage},) or they can contain a special procedure called @code{init_targets}, which will be executed when entering run stage (after parsing all config files or after @code{init} command, @xref{enteringtherunstage,,Entering the Run Stage}.) Such procedure can be overridden by ``next level'' script (which sources the original). This concept facilitates code reuse when basic target config files provide generic configuration procedures and @code{init_targets} procedure, which can then be sourced and enhanced or changed in a ``more specific'' target config file. This is not possible with ``linear'' config scripts, because sourcing them executes every initialization commands they provide. @example ### generic_file.cfg ### proc setup_my_chip @{chip_name flash_size ram_size@} @{ # basic initialization procedure ... @} proc init_targets @{@} @{ # initializes generic chip with 4kB of flash and 1kB of RAM setup_my_chip MY_GENERIC_CHIP 4096 1024 @} ### specific_file.cfg ### source [find target/generic_file.cfg] proc init_targets @{@} @{ # initializes specific chip with 128kB of flash and 64kB of RAM setup_my_chip MY_CHIP_WITH_128K_FLASH_64KB_RAM 131072 65536 @} @end example The easiest way to convert ``linear'' config files to @code{init_targets} version is to enclose every line of ``code'' (i.e. not @code{source} commands, procedures, etc.) in this procedure. For an example of this scheme see LPC2000 target config files. The @code{init_boards} procedure is a similar concept concerning board config files (@xref{theinitboardprocedure,,The init_board procedure}.) @subsection The init_target_events procedure @cindex init_target_events procedure A special procedure called @code{init_target_events} is run just after @code{init_targets} (@xref{theinittargetsprocedure,,The init_targets procedure}.) and before @code{init_board} (@xref{theinitboardprocedure,,The init_board procedure}.) It is used to set up default target events for the targets that do not have those events already assigned. @subsection ARM Core Specific Hacks If the chip has a DCC, enable it. If the chip is an ARM9 with some special high speed download features - enable it. If present, the MMU, the MPU and the CACHE should be disabled. Some ARM cores are equipped with trace support, which permits examination of the instruction and data bus activity. Trace activity is controlled through an ``Embedded Trace Module'' (ETM) on one of the core's scan chains. The ETM emits voluminous data through a ``trace port''. (@xref{armhardwaretracing,,ARM Hardware Tracing}.) If you are using an external trace port, configure it in your board config file. If you are using an on-chip ``Embedded Trace Buffer'' (ETB), configure it in your target config file. @example etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb @end example @subsection Internal Flash Configuration This applies @b{ONLY TO MICROCONTROLLERS} that have flash built in. @b{Never ever} in the ``target configuration file'' define any type of flash that is external to the chip. (For example a BOOT flash on Chip Select 0.) Such flash information goes in a board file - not the TARGET (chip) file. Examples: @itemize @bullet @item at91sam7x256 - has 256K flash YES enable it. @item str912 - has flash internal YES enable it. @item imx27 - uses boot flash on CS0 - it goes in the board file. @item pxa270 - again - CS0 flash - it goes in the board file. @end itemize @anchor{translatingconfigurationfiles} @section Translating Configuration Files @cindex translation If you have a configuration file for another hardware debugger or toolset (Abatron, BDI2000, BDI3000, CCS, Lauterbach, SEGGER, Macraigor, etc.), translating it into OpenOCD syntax is often quite straightforward. The most tricky part of creating a configuration script is oftentimes the reset init sequence where e.g. PLLs, DRAM and the like is set up. One trick that you can use when translating is to write small Tcl procedures to translate the syntax into OpenOCD syntax. This can avoid manual translation errors and make it easier to convert other scripts later on. Example of transforming quirky arguments to a simple search and replace job: @example # Lauterbach syntax(?) # # Data.Set c15:0x042f %long 0x40000015 # # OpenOCD syntax when using procedure below. # # setc15 0x01 0x00050078 proc setc15 @{regs value@} @{ global TARGETNAME echo [format "set p15 0x%04x, 0x%08x" $regs $value] arm mcr 15 [expr @{($regs >> 12) & 0x7@}] \ [expr @{($regs >> 0) & 0xf@}] [expr @{($regs >> 4) & 0xf@}] \ [expr @{($regs >> 8) & 0x7@}] $value @} @end example @node Server Configuration @chapter Server Configuration @cindex initialization The commands here are commonly found in the openocd.cfg file and are used to specify what TCP/IP ports are used, and how GDB should be supported. @anchor{configurationstage} @section Configuration Stage @cindex configuration stage @cindex config command When the OpenOCD server process starts up, it enters a @emph{configuration stage} which is the only time that certain commands, @emph{configuration commands}, may be issued. Normally, configuration commands are only available inside startup scripts. In this manual, the definition of a configuration command is presented as a @emph{Config Command}, not as a @emph{Command} which may be issued interactively. The runtime @command{help} command also highlights configuration commands, and those which may be issued at any time. Those configuration commands include declaration of TAPs, flash banks, the interface used for JTAG communication, and other basic setup. The server must leave the configuration stage before it may access or activate TAPs. After it leaves this stage, configuration commands may no longer be issued. @deffn {Command} {command mode} [command_name] Returns the command modes allowed by a command: 'any', 'config', or 'exec'. If no command is specified, returns the current command mode. Returns 'unknown' if an unknown command is given. Command can be multiple tokens. (command valid any time) In this document, the modes are described as stages, 'config' and 'exec' mode correspond configuration stage and run stage. 'any' means the command can be executed in either stages. @xref{configurationstage,,Configuration Stage}, and @xref{enteringtherunstage,,Entering the Run Stage}. @end deffn @anchor{enteringtherunstage} @section Entering the Run Stage The first thing OpenOCD does after leaving the configuration stage is to verify that it can talk to the scan chain (list of TAPs) which has been configured. It will warn if it doesn't find TAPs it expects to find, or finds TAPs that aren't supposed to be there. You should see no errors at this point. If you see errors, resolve them by correcting the commands you used to configure the server. Common errors include using an initial JTAG speed that's too fast, and not providing the right IDCODE values for the TAPs on the scan chain. Once OpenOCD has entered the run stage, a number of commands become available. A number of these relate to the debug targets you may have declared. For example, the @command{mww} command will not be available until a target has been successfully instantiated. If you want to use those commands, you may need to force entry to the run stage. @deffn {Config Command} {init} This command terminates the configuration stage and enters the run stage. This helps when you need to have the startup scripts manage tasks such as resetting the target, programming flash, etc. To reset the CPU upon startup, add "init" and "reset" at the end of the config script or at the end of the OpenOCD command line using the @option{-c} command line switch. If this command does not appear in any startup/configuration file OpenOCD executes the command for you after processing all configuration files and/or command line options. @b{NOTE:} This command normally occurs near the end of your openocd.cfg file to force OpenOCD to ``initialize'' and make the targets ready. For example: If your openocd.cfg file needs to read/write memory on your target, @command{init} must occur before the memory read/write commands. This includes @command{nand probe}. @command{init} calls the following internal OpenOCD commands to initialize corresponding subsystems: @deffn {Config Command} {target init} @deffnx {Command} {transport init} @deffnx {Command} {dap init} @deffnx {Config Command} {flash init} @deffnx {Config Command} {nand init} @deffnx {Config Command} {pld init} @deffnx {Command} {tpiu init} @end deffn At last, @command{init} executes all the commands that are specified in the TCL list @var{post_init_commands}. The commands are executed in the same order they occupy in the list. If one of the commands fails, then the error is propagated and OpenOCD fails too. @example lappend post_init_commands @{echo "OpenOCD successfully initialized."@} lappend post_init_commands @{echo "Have fun with OpenOCD !"@} @end example @end deffn @deffn {Config Command} {noinit} Prevent OpenOCD from implicit @command{init} call at the end of startup. Allows issuing configuration commands over telnet or Tcl connection. When you are done with configuration use @command{init} to enter the run stage. @end deffn @deffn {Overridable Procedure} {jtag_init} This is invoked at server startup to verify that it can talk to the scan chain (list of TAPs) which has been configured. The default implementation first tries @command{jtag arp_init}, which uses only a lightweight JTAG reset before examining the scan chain. If that fails, it tries again, using a harder reset from the overridable procedure @command{init_reset}. Implementations must have verified the JTAG scan chain before they return. This is done by calling @command{jtag arp_init} (or @command{jtag arp_init-reset}). @end deffn @anchor{tcpipports} @section TCP/IP Ports @cindex TCP port @cindex server @cindex port @cindex security The OpenOCD server accepts remote commands in several syntaxes. Each syntax uses a different TCP/IP port, which you may specify only during configuration (before those ports are opened). For reasons including security, you may wish to prevent remote access using one or more of these ports. In such cases, just specify the relevant port number as "disabled". If you disable all access through TCP/IP, you will need to use the command line @option{-pipe} option. @anchor{gdb_port} @deffn {Config Command} {gdb_port} [number] @cindex GDB server Normally gdb listens to a TCP/IP port, but GDB can also communicate via pipes(stdin/out or named pipes). The name "gdb_port" stuck because it covers probably more than 90% of the normal use cases. No arguments reports GDB port. "pipe" means listen to stdin output to stdout, an integer is base port number, "disabled" disables the gdb server. When using "pipe", also use log_output to redirect the log output to a file so as not to flood the stdin/out pipes. Any other string is interpreted as named pipe to listen to. Output pipe is the same name as input pipe, but with 'o' appended, e.g. /var/gdb, /var/gdbo. The GDB port for the first target will be the base port, the second target will listen on gdb_port + 1, and so on. When not specified during the configuration stage, the port @var{number} defaults to 3333. When @var{number} is not a numeric value, incrementing it to compute the next port number does not work. In this case, specify the proper @var{number} for each target by using the option @code{-gdb-port} of the commands @command{target create} or @command{$target_name configure}. @xref{gdbportoverride,,option -gdb-port}. Note: when using "gdb_port pipe", increasing the default remote timeout in gdb (with 'set remotetimeout') is recommended. An insufficient timeout may cause initialization to fail with "Unknown remote qXfer reply: OK". @end deffn @deffn {Config Command} {tcl_port} [number] Specify or query the port used for a simplified RPC connection that can be used by clients to issue TCL commands and get the output from the Tcl engine. Intended as a machine interface. When not specified during the configuration stage, the port @var{number} defaults to 6666. When specified as "disabled", this service is not activated. @end deffn @deffn {Config Command} {telnet_port} [number] Specify or query the port on which to listen for incoming telnet connections. This port is intended for interaction with one human through TCL commands. When not specified during the configuration stage, the port @var{number} defaults to 4444. When specified as "disabled", this service is not activated. @end deffn @anchor{gdbconfiguration} @section GDB Configuration @cindex GDB @cindex GDB configuration You can reconfigure some GDB behaviors if needed. The ones listed here are static and global. @xref{targetconfiguration,,Target Configuration}, about configuring individual targets. @xref{targetevents,,Target Events}, about configuring target-specific event handling. @anchor{gdbbreakpointoverride} @deffn {Command} {gdb_breakpoint_override} [@option{hard}|@option{soft}|@option{disable}] Force breakpoint type for gdb @command{break} commands. This option supports GDB GUIs which don't distinguish hard versus soft breakpoints, if the default OpenOCD and GDB behaviour is not sufficient. GDB normally uses hardware breakpoints if the memory map has been set up for flash regions. @end deffn @anchor{gdbflashprogram} @deffn {Config Command} {gdb_flash_program} (@option{enable}|@option{disable}) Set to @option{enable} to cause OpenOCD to program the flash memory when a vFlash packet is received. The default behaviour is @option{enable}. @end deffn @deffn {Config Command} {gdb_memory_map} (@option{enable}|@option{disable}) Set to @option{enable} to cause OpenOCD to send the memory configuration to GDB when requested. GDB will then know when to set hardware breakpoints, and program flash using the GDB load command. @command{gdb_flash_program enable} must also be enabled for flash programming to work. Default behaviour is @option{enable}. @xref{gdbflashprogram,,gdb_flash_program}. @end deffn @deffn {Config Command} {gdb_report_data_abort} (@option{enable}|@option{disable}) Specifies whether data aborts cause an error to be reported by GDB memory read packets. The default behaviour is @option{disable}; use @option{enable} see these errors reported. @end deffn @deffn {Config Command} {gdb_report_register_access_error} (@option{enable}|@option{disable}) Specifies whether register accesses requested by GDB register read/write packets report errors or not. The default behaviour is @option{disable}; use @option{enable} see these errors reported. @end deffn @deffn {Config Command} {gdb_target_description} (@option{enable}|@option{disable}) Set to @option{enable} to cause OpenOCD to send the target descriptions to gdb via qXfer:features:read packet. The default behaviour is @option{enable}. @end deffn @deffn {Command} {gdb_save_tdesc} Saves the target description file to the local file system. The file name is @i{target_name}.xml. @end deffn @anchor{eventpolling} @section Event Polling Hardware debuggers are parts of asynchronous systems, where significant events can happen at any time. The OpenOCD server needs to detect some of these events, so it can report them to through TCL command line or to GDB. Examples of such events include: @itemize @item One of the targets can stop running ... maybe it triggers a code breakpoint or data watchpoint, or halts itself. @item Messages may be sent over ``debug message'' channels ... many targets support such messages sent over JTAG, for receipt by the person debugging or tools. @item Loss of power ... some adapters can detect these events. @item Resets not issued through JTAG ... such reset sources can include button presses or other system hardware, sometimes including the target itself (perhaps through a watchdog). @item Debug instrumentation sometimes supports event triggering such as ``trace buffer full'' (so it can quickly be emptied) or other signals (to correlate with code behavior). @end itemize None of those events are signaled through standard JTAG signals. However, most conventions for JTAG connectors include voltage level and system reset (SRST) signal detection. Some connectors also include instrumentation signals, which can imply events when those signals are inputs. In general, OpenOCD needs to periodically check for those events, either by looking at the status of signals on the JTAG connector or by sending synchronous ``tell me your status'' JTAG requests to the various active targets. There is a command to manage and monitor that polling, which is normally done in the background. @deffn {Command} {poll} [@option{on}|@option{off}] Poll the current target for its current state. (Also, @pxref{targetcurstate,,target curstate}.) If that target is in debug mode, architecture specific information about the current state is printed. An optional parameter allows background polling to be enabled and disabled. You could use this from the TCL command shell, or from GDB using @command{monitor poll} command. Leave background polling enabled while you're using GDB. @example > poll background polling: on target state: halted target halted in ARM state due to debug-request, \ current mode: Supervisor cpsr: 0x800000d3 pc: 0x11081bfc MMU: disabled, D-Cache: disabled, I-Cache: enabled > @end example @end deffn @node Debug Adapter Configuration @chapter Debug Adapter Configuration @cindex config file, interface @cindex interface config file Correctly installing OpenOCD includes making your operating system give OpenOCD access to debug adapters. Once that has been done, Tcl commands are used to select which one is used, and to configure how it is used. @quotation Note Because OpenOCD started out with a focus purely on JTAG, you may find places where it wrongly presumes JTAG is the only transport protocol in use. Be aware that recent versions of OpenOCD are removing that limitation. JTAG remains more functional than most other transports. Other transports do not support boundary scan operations, or may be specific to a given chip vendor. Some might be usable only for programming flash memory, instead of also for debugging. @end quotation Debug Adapters/Interfaces/Dongles are normally configured through commands in an interface configuration file which is sourced by your @file{openocd.cfg} file, or through a command line @option{-f interface/....cfg} option. @example source [find interface/olimex-jtag-tiny.cfg] @end example These commands tell OpenOCD what type of JTAG adapter you have, and how to talk to it. A few cases are so simple that you only need to say what driver to use: @example # jlink interface adapter driver jlink @end example Most adapters need a bit more configuration than that. @section Adapter Configuration The @command{adapter driver} command tells OpenOCD what type of debug adapter you are using. Depending on the type of adapter, you may need to use one or more additional commands to further identify or configure the adapter. @deffn {Config Command} {adapter driver} name Use the adapter driver @var{name} to connect to the target. @end deffn @deffn {Command} {adapter list} List the debug adapter drivers that have been built into the running copy of OpenOCD. @end deffn @deffn {Config Command} {adapter transports} transport_name+ Specifies the transports supported by this debug adapter. The adapter driver builds-in similar knowledge; use this only when external configuration (such as jumpering) changes what the hardware can support. @end deffn @anchor{adapter gpio} @deffn {Config Command} {adapter gpio [ @ @option{tdo} | @option{tdi} | @option{tms} | @option{tck} | @option{trst} | @ @option{swdio} | @option{swdio_dir} | @option{swclk} | @option{srst} | @ @option{led} @ [ @ gpio_number | @option{-chip} chip_number | @ @option{-active-high} | @option{-active-low} | @ @option{-push-pull} | @option{-open-drain} | @option{-open-source} | @ @option{-pull-none} | @option{-pull-up} | @option{-pull-down} | @ @option{-init-inactive} | @option{-init-active} | @option{-init-input} @ ] ]} Define the GPIO mapping that the adapter will use. The following signals can be defined: @itemize @minus @item @option{tdo}, @option{tdi}, @option{tms}, @option{tck}, @option{trst}: JTAG transport signals @item @option{swdio}, @option{swclk}: SWD transport signals @item @option{swdio_dir}: optional swdio buffer control signal @item @option{srst}: system reset signal @item @option{led}: optional activity led @end itemize Some adapters require that the GPIO chip number is set in addition to the GPIO number. The configuration options enable signals to be defined as active-high or active-low. The output drive mode can be set to push-pull, open-drain or open-source. Most adapters will have to emulate open-drain or open-source drive modes by switching between an input and output. Input and output signals can be instructed to use a pull-up or pull-down resistor, assuming it is supported by the adaptor driver and hardware. The initial state of outputs may also be set, "active" state means 1 for active-high outputs and 0 for active-low outputs. Bidirectional signals may also be initialized as an input. If the swdio signal is buffered the buffer direction can be controlled with the swdio_dir signal; the active state means that the buffer should be set as an output with respect to the adapter. The command options are cumulative with later commands able to override settings defined by earlier ones. The two commands @command{gpio led 7 -active-high} and @command{gpio led -chip 1 -active-low} sent sequentially are equivalent to issuing the single command @command{gpio led 7 -chip 1 -active-low}. It is not permissible to set the drive mode or initial state for signals which are inputs. The drive mode for the srst and trst signals must be set with the @command{adapter reset_config} command. It is not permissible to set the initial state of swdio_dir as it is derived from the initial state of swdio. The command @command{adapter gpio} prints the current configuration for all GPIOs while the command @command{adapter gpio gpio_name} prints the current configuration for gpio_name. Not all adapters support this generic GPIO mapping, some require their own commands to define the GPIOs used. Adapters that support the generic mapping may not support all of the listed options. @end deffn @deffn {Command} {adapter name} Returns the name of the debug adapter driver being used. @end deffn @deffn {Config Command} {adapter usb location} [<bus>-<port>[.<port>]...] Displays or specifies the physical USB port of the adapter to use. The path roots at @var{bus} and walks down the physical ports, with each @var{port} option specifying a deeper level in the bus topology, the last @var{port} denoting where the target adapter is actually plugged. The USB bus topology can be queried with the command @emph{lsusb -t} or @emph{dmesg}. This command is only available if your libusb1 is at least version 1.0.16. @end deffn @deffn {Config Command} {adapter serial} serial_string Specifies the @var{serial_string} of the adapter to use. If this command is not specified, serial strings are not checked. Only the following adapter drivers use the serial string from this command: arm-jtag-ew, cmsis_dap, esp_usb_jtag, ft232r, ftdi, hla (stlink, ti-icdi), jlink, kitprog, opendus, openjtag, osbdm, presto, rlink, st-link, usb_blaster (ublast2), usbprog, vsllink, xds110. @end deffn @section Interface Drivers Each of the interface drivers listed here must be explicitly enabled when OpenOCD is configured, in order to be made available at run time. @deffn {Interface Driver} {amt_jtagaccel} Amontec Chameleon in its JTAG Accelerator configuration, connected to a PC's EPP mode parallel port. This defines some driver-specific commands: @deffn {Config Command} {parport port} number Specifies either the address of the I/O port (default: 0x378 for LPT1) or the number of the @file{/dev/parport} device. @end deffn @deffn {Config Command} {rtck} [@option{enable}|@option{disable}] Displays status of RTCK option. Optionally sets that option first. @end deffn @end deffn @deffn {Interface Driver} {arm-jtag-ew} Olimex ARM-JTAG-EW USB adapter This has one driver-specific command: @deffn {Command} {armjtagew_info} Logs some status @end deffn @end deffn @deffn {Interface Driver} {at91rm9200} Supports bitbanged JTAG from the local system, presuming that system is an Atmel AT91rm9200 and a specific set of GPIOs is used. @c command: at91rm9200_device NAME @c chooses among list of bit configs ... only one option @end deffn @deffn {Interface Driver} {cmsis-dap} ARM CMSIS-DAP compliant based adapter v1 (USB HID based) or v2 (USB bulk). @deffn {Config Command} {cmsis_dap_vid_pid} [vid pid]+ The vendor ID and product ID of the CMSIS-DAP device. If not specified the driver will attempt to auto detect the CMSIS-DAP device. Currently, up to eight [@var{vid}, @var{pid}] pairs may be given, e.g. @example cmsis_dap_vid_pid 0xc251 0xf001 0x0d28 0x0204 @end example @end deffn @deffn {Config Command} {cmsis_dap_backend} [@option{auto}|@option{usb_bulk}|@option{hid}] Specifies how to communicate with the adapter: @itemize @minus @item @option{hid} Use HID generic reports - CMSIS-DAP v1 @item @option{usb_bulk} Use USB bulk - CMSIS-DAP v2 @item @option{auto} First try USB bulk CMSIS-DAP v2, if not found try HID CMSIS-DAP v1. This is the default if @command{cmsis_dap_backend} is not specified. @end itemize @end deffn @deffn {Config Command} {cmsis_dap_usb interface} [number] Specifies the @var{number} of the USB interface to use in v2 mode (USB bulk). In most cases need not to be specified and interfaces are searched by interface string or for user class interface. @end deffn @deffn {Command} {cmsis-dap info} Display various device information, like hardware version, firmware version, current bus status. @end deffn @deffn {Command} {cmsis-dap cmd} number number ... Execute an arbitrary CMSIS-DAP command. Use for adapter testing or for handling of an adapter vendor specific command from a Tcl script. Take given numbers as bytes, assemble a CMSIS-DAP protocol command packet from them and send it to the adapter. The first 4 bytes of the adapter response are logged. See @url{https://arm-software.github.io/CMSIS_5/DAP/html/group__DAP__Commands__gr.html} @end deffn @end deffn @deffn {Interface Driver} {dummy} A dummy software-only driver for debugging. @end deffn @deffn {Interface Driver} {ep93xx} Cirrus Logic EP93xx based single-board computer bit-banging (in development) @end deffn @deffn {Interface Driver} {ftdi} This driver is for adapters using the MPSSE (Multi-Protocol Synchronous Serial Engine) mode built into many FTDI chips, such as the FT2232, FT4232 and FT232H. The driver is using libusb-1.0 in asynchronous mode to talk to the FTDI device, bypassing intermediate libraries like libftdi. Support for new FTDI based adapters can be added completely through configuration files, without the need to patch and rebuild OpenOCD. The driver uses a signal abstraction to enable Tcl configuration files to define outputs for one or several FTDI GPIO. These outputs can then be controlled using the @command{ftdi set_signal} command. Special signal names are reserved for nTRST, nSRST and LED (for blink) so that they, if defined, will be used for their customary purpose. Inputs can be read using the @command{ftdi get_signal} command. To support SWD, a signal named SWD_EN must be defined. It is set to 1 when the SWD protocol is selected. When set, the adapter should route the SWDIO pin to the data input. An SWDIO_OE signal, if defined, will be set to 1 or 0 as required by the protocol, to tell the adapter to drive the data output onto the SWDIO pin or keep the SWDIO pin Hi-Z, respectively. Depending on the type of buffer attached to the FTDI GPIO, the outputs have to be controlled differently. In order to support tristateable signals such as nSRST, both a data GPIO and an output-enable GPIO can be specified for each signal. The following output buffer configurations are supported: @itemize @minus @item Push-pull with one FTDI output as (non-)inverted data line @item Open drain with one FTDI output as (non-)inverted output-enable @item Tristate with one FTDI output as (non-)inverted data line and another FTDI output as (non-)inverted output-enable @item Unbuffered, using the FTDI GPIO as a tristate output directly by switching data and direction as necessary @end itemize These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: @deffn {Config Command} {ftdi vid_pid} [vid pid]+ The vendor ID and product ID of the adapter. Up to eight [@var{vid}, @var{pid}] pairs may be given, e.g. @example ftdi vid_pid 0x0403 0xcff8 0x15ba 0x0003 @end example @end deffn @deffn {Config Command} {ftdi device_desc} description Provides the USB device description (the @emph{iProduct string}) of the adapter. If not specified, the device description is ignored during device selection. @end deffn @deffn {Config Command} {ftdi channel} channel Selects the channel of the FTDI device to use for MPSSE operations. Most adapters use the default, channel 0, but there are exceptions. @end deffn @deffn {Config Command} {ftdi layout_init} data direction Specifies the initial values of the FTDI GPIO data and direction registers. Each value is a 16-bit number corresponding to the concatenation of the high and low FTDI GPIO registers. The values should be selected based on the schematics of the adapter, such that all signals are set to safe levels with minimal impact on the target system. Avoid floating inputs, conflicting outputs and initially asserted reset signals. @end deffn @deffn {Command} {ftdi layout_signal} name [@option{-data}|@option{-ndata} data_mask] [@option{-input}|@option{-ninput} input_mask] [@option{-oe}|@option{-noe} oe_mask] [@option{-alias}|@option{-nalias} name] Creates a signal with the specified @var{name}, controlled by one or more FTDI GPIO pins via a range of possible buffer connections. The masks are FTDI GPIO register bitmasks to tell the driver the connection and type of the output buffer driving the respective signal. @var{data_mask} is the bitmask for the pin(s) connected to the data input of the output buffer. @option{-ndata} is used with inverting data inputs and @option{-data} with non-inverting inputs. The @option{-oe} (or @option{-noe}) option tells where the output-enable (or not-output-enable) input to the output buffer is connected. The options @option{-input} and @option{-ninput} specify the bitmask for pins to be read with the method @command{ftdi get_signal}. Both @var{data_mask} and @var{oe_mask} need not be specified. For example, a simple open-collector transistor driver would be specified with @option{-oe} only. In that case the signal can only be set to drive low or to Hi-Z and the driver will complain if the signal is set to drive high. Which means that if it's a reset signal, @command{reset_config} must be specified as @option{srst_open_drain}, not @option{srst_push_pull}. A special case is provided when @option{-data} and @option{-oe} is set to the same bitmask. Then the FTDI pin is considered being connected straight to the target without any buffer. The FTDI pin is then switched between output and input as necessary to provide the full set of low, high and Hi-Z characteristics. In all other cases, the pins specified in a signal definition are always driven by the FTDI. If @option{-alias} or @option{-nalias} is used, the signal is created identical (or with data inverted) to an already specified signal @var{name}. @end deffn @deffn {Command} {ftdi set_signal} name @option{0}|@option{1}|@option{z} Set a previously defined signal to the specified level. @itemize @minus @item @option{0}, drive low @item @option{1}, drive high @item @option{z}, set to high-impedance @end itemize @end deffn @deffn {Command} {ftdi get_signal} name Get the value of a previously defined signal. @end deffn @deffn {Command} {ftdi tdo_sample_edge} @option{rising}|@option{falling} Configure TCK edge at which the adapter samples the value of the TDO signal Due to signal propagation delays, sampling TDO on rising TCK can become quite peculiar at high JTAG clock speeds. However, FTDI chips offer a possibility to sample TDO on falling edge of TCK. With some board/adapter configurations, this may increase stability at higher JTAG clocks. @itemize @minus @item @option{rising}, sample TDO on rising edge of TCK - this is the default @item @option{falling}, sample TDO on falling edge of TCK @end itemize @end deffn For example adapter definitions, see the configuration files shipped in the @file{interface/ftdi} directory. @end deffn @deffn {Interface Driver} {ft232r} This driver is implementing synchronous bitbang mode of an FTDI FT232R, FT230X, FT231X and similar USB UART bridge ICs by reusing RS232 signals as GPIO. It currently doesn't support using CBUS pins as GPIO. List of connections (default physical pin numbers for FT232R in 28-pin SSOP package): @itemize @minus @item RXD(5) - TDI @item TXD(1) - TCK @item RTS(3) - TDO @item CTS(11) - TMS @item DTR(2) - TRST @item DCD(10) - SRST @end itemize User can change default pinout by supplying configuration commands with GPIO numbers or RS232 signal names. GPIO numbers correspond to bit numbers in FTDI GPIO register. They differ from physical pin numbers. For details see actual FTDI chip datasheets. Every JTAG line must be configured to unique GPIO number different than any other JTAG line, even those lines that are sometimes not used like TRST or SRST. FT232R @itemize @minus @item bit 7 - RI @item bit 6 - DCD @item bit 5 - DSR @item bit 4 - DTR @item bit 3 - CTS @item bit 2 - RTS @item bit 1 - RXD @item bit 0 - TXD @end itemize These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: @deffn {Config Command} {ft232r vid_pid} @var{vid} @var{pid} The vendor ID and product ID of the adapter. If not specified, default 0x0403:0x6001 is used. @end deffn @deffn {Config Command} {ft232r jtag_nums} @var{tck} @var{tms} @var{tdi} @var{tdo} Set four JTAG GPIO numbers at once. If not specified, default 0 3 1 2 or TXD CTS RXD RTS is used. @end deffn @deffn {Config Command} {ft232r tck_num} @var{tck} Set TCK GPIO number. If not specified, default 0 or TXD is used. @end deffn @deffn {Config Command} {ft232r tms_num} @var{tms} Set TMS GPIO number. If not specified, default 3 or CTS is used. @end deffn @deffn {Config Command} {ft232r tdi_num} @var{tdi} Set TDI GPIO number. If not specified, default 1 or RXD is used. @end deffn @deffn {Config Command} {ft232r tdo_num} @var{tdo} Set TDO GPIO number. If not specified, default 2 or RTS is used. @end deffn @deffn {Config Command} {ft232r trst_num} @var{trst} Set TRST GPIO number. If not specified, default 4 or DTR is used. @end deffn @deffn {Config Command} {ft232r srst_num} @var{srst} Set SRST GPIO number. If not specified, default 6 or DCD is used. @end deffn @deffn {Config Command} {ft232r restore_serial} @var{word} Restore serial port after JTAG. This USB bitmode control word (16-bit) will be sent before quit. Lower byte should set GPIO direction register to a "sane" state: 0x15 for TXD RTS DTR as outputs (1), others as inputs (0). Higher byte is usually 0 to disable bitbang mode. When kernel driver reattaches, serial port should continue to work. Value 0xFFFF disables sending control word and serial port, then kernel driver will not reattach. If not specified, default 0xFFFF is used. @end deffn @end deffn @deffn {Interface Driver} {remote_bitbang} Drive JTAG from a remote process. This sets up a UNIX or TCP socket connection with a remote process and sends ASCII encoded bitbang requests to that process instead of directly driving JTAG. The remote_bitbang driver is useful for debugging software running on processors which are being simulated. @deffn {Config Command} {remote_bitbang port} number Specifies the TCP port of the remote process to connect to or 0 to use UNIX sockets instead of TCP. @end deffn @deffn {Config Command} {remote_bitbang host} hostname Specifies the hostname of the remote process to connect to using TCP, or the name of the UNIX socket to use if remote_bitbang port is 0. @end deffn For example, to connect remotely via TCP to the host foobar you might have something like: @example adapter driver remote_bitbang remote_bitbang port 3335 remote_bitbang host foobar @end example To connect to another process running locally via UNIX sockets with socket named mysocket: @example adapter driver remote_bitbang remote_bitbang port 0 remote_bitbang host mysocket @end example @end deffn @deffn {Interface Driver} {usb_blaster} USB JTAG/USB-Blaster compatibles over one of the userspace libraries for FTDI chips. These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: @deffn {Config Command} {usb_blaster vid_pid} vid pid The vendor ID and product ID of the FTDI FT245 device. If not specified, default values are used. Currently, only one @var{vid}, @var{pid} pair may be given, e.g. for Altera USB-Blaster (default): @example usb_blaster vid_pid 0x09FB 0x6001 @end example The following VID/PID is for Kolja Waschk's USB JTAG: @example usb_blaster vid_pid 0x16C0 0x06AD @end example @end deffn @deffn {Command} {usb_blaster pin} (@option{pin6}|@option{pin8}) (@option{0}|@option{1}|@option{s}|@option{t}) Sets the state or function of the unused GPIO pins on USB-Blasters (pins 6 and 8 on the female JTAG header). These pins can be used as SRST and/or TRST provided the appropriate connections are made on the target board. For example, to use pin 6 as SRST: @example usb_blaster pin pin6 s reset_config srst_only @end example @end deffn @deffn {Config Command} {usb_blaster lowlevel_driver} (@option{ftdi}|@option{ublast2}) Chooses the low level access method for the adapter. If not specified, @option{ftdi} is selected unless it wasn't enabled during the configure stage. USB-Blaster II needs @option{ublast2}. @end deffn @deffn {Config Command} {usb_blaster firmware} @var{path} This command specifies @var{path} to access USB-Blaster II firmware image. To be used with USB-Blaster II only. @end deffn @end deffn @deffn {Interface Driver} {gw16012} Gateworks GW16012 JTAG programmer. This has one driver-specific command: @deffn {Config Command} {parport port} [port_number] Display either the address of the I/O port (default: 0x378 for LPT1) or the number of the @file{/dev/parport} device. If a parameter is provided, first switch to use that port. This is a write-once setting. @end deffn @end deffn @deffn {Interface Driver} {jlink} SEGGER J-Link family of USB adapters. It currently supports JTAG and SWD transports. @quotation Compatibility Note SEGGER released many firmware versions for the many hardware versions they produced. OpenOCD was extensively tested and intended to run on all of them, but some combinations were reported as incompatible. As a general recommendation, it is advisable to use the latest firmware version available for each hardware version. However the current V8 is a moving target, and SEGGER firmware versions released after the OpenOCD was released may not be compatible. In such cases it is recommended to revert to the last known functional version. For 0.5.0, this is from "Feb 8 2012 14:30:39", packed with 4.42c. For 0.6.0, the last known version is from "May 3 2012 18:36:22", packed with 4.46f. @end quotation @deffn {Command} {jlink hwstatus} Display various hardware related information, for example target voltage and pin states. @end deffn @deffn {Command} {jlink freemem} Display free device internal memory. @end deffn @deffn {Command} {jlink jtag} [@option{2}|@option{3}] Set the JTAG command version to be used. Without argument, show the actual JTAG command version. @end deffn @deffn {Command} {jlink config} Display the device configuration. @end deffn @deffn {Command} {jlink config targetpower} [@option{on}|@option{off}] Set the target power state on JTAG-pin 19. Without argument, show the target power state. @end deffn @deffn {Command} {jlink config mac} [@option{ff:ff:ff:ff:ff:ff}] Set the MAC address of the device. Without argument, show the MAC address. @end deffn @deffn {Command} {jlink config ip} [@option{A.B.C.D}(@option{/E}|@option{F.G.H.I})] Set the IP configuration of the device, where A.B.C.D is the IP address, E the bit of the subnet mask and F.G.H.I the subnet mask. Without arguments, show the IP configuration. @end deffn @deffn {Command} {jlink config usb} [@option{0} to @option{3}] Set the USB address of the device. This will also change the USB Product ID (PID) of the device. Without argument, show the USB address. @end deffn @deffn {Command} {jlink config reset} Reset the current configuration. @end deffn @deffn {Command} {jlink config write} Write the current configuration to the internal persistent storage. @end deffn @deffn {Command} {jlink emucom write} <channel> <data> Write data to an EMUCOM channel. The data needs to be encoded as hexadecimal pairs. The following example shows how to write the three bytes 0xaa, 0x0b and 0x23 to the EMUCOM channel 0x10: @example > jlink emucom write 0x10 aa0b23 @end example @end deffn @deffn {Command} {jlink emucom read} <channel> <length> Read data from an EMUCOM channel. The read data is encoded as hexadecimal pairs. The following example shows how to read 4 bytes from the EMUCOM channel 0x0: @example > jlink emucom read 0x0 4 77a90000 @end example @end deffn @deffn {Config Command} {jlink usb} <@option{0} to @option{3}> Set the USB address of the interface, in case more than one adapter is connected to the host. If not specified, USB addresses are not considered. Device selection via USB address is not always unambiguous. It is recommended to use the serial number instead, if possible. As a configuration command, it can be used only before 'init'. @end deffn @end deffn @deffn {Interface Driver} {kitprog} This driver is for Cypress Semiconductor's KitProg adapters. The KitProg is an SWD-only adapter that is designed to be used with Cypress's PSoC and PRoC device families, but it is possible to use it with some other devices. If you are using this adapter with a PSoC or a PRoC, you may need to add @command{kitprog_init_acquire_psoc} or @command{kitprog acquire_psoc} to your configuration script. Note that this driver is for the proprietary KitProg protocol, not the CMSIS-DAP mode introduced in firmware 2.14. If the KitProg is in CMSIS-DAP mode, it cannot be used with this driver, and must either be used with the cmsis-dap driver or switched back to KitProg mode. See the Cypress KitProg User Guide for instructions on how to switch KitProg modes. Known limitations: @itemize @bullet @item The frequency of SWCLK cannot be configured, and varies between 1.6 MHz and 2.7 MHz. @item For firmware versions below 2.14, "JTAG to SWD" sequences are replaced by "SWD line reset" in the driver. This is for two reasons. First, the KitProg does not support sending arbitrary SWD sequences, and only firmware 2.14 and later implement both "JTAG to SWD" and "SWD line reset" in firmware. Earlier firmware versions only implement "SWD line reset". Second, due to a firmware quirk, an SWD sequence must be sent after every target reset in order to re-establish communications with the target. @item Due in part to the limitation above, KitProg devices with firmware below version 2.14 will need to use @command{kitprog_init_acquire_psoc} in order to communicate with PSoC 5LP devices. This is because, assuming debug is not disabled on the PSoC, the PSoC 5LP needs its JTAG interface switched to SWD mode before communication can begin, but prior to firmware 2.14, "JTAG to SWD" could only be sent with an acquisition sequence. @end itemize @deffn {Config Command} {kitprog_init_acquire_psoc} Indicate that a PSoC acquisition sequence needs to be run during adapter init. Please be aware that the acquisition sequence hard-resets the target. @end deffn @deffn {Command} {kitprog acquire_psoc} Run a PSoC acquisition sequence immediately. Typically, this should not be used outside of the target-specific configuration scripts since it hard-resets the target as a side-effect. This is necessary for "reset halt" on some PSoC 4 series devices. @end deffn @deffn {Command} {kitprog info} Display various adapter information, such as the hardware version, firmware version, and target voltage. @end deffn @end deffn @deffn {Interface Driver} {parport} Supports PC parallel port bit-banging cables: Wigglers, PLD download cable, and more. These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: @deffn {Config Command} {parport cable} name Set the layout of the parallel port cable used to connect to the target. This is a write-once setting. Currently valid cable @var{name} values include: @itemize @minus @item @b{altium} Altium Universal JTAG cable. @item @b{arm-jtag} Same as original wiggler except SRST and TRST connections reversed and TRST is also inverted. @item @b{chameleon} The Amontec Chameleon's CPLD when operated in configuration mode. This is only used to program the Chameleon itself, not a connected target. @item @b{dlc5} The Xilinx Parallel cable III. @item @b{flashlink} The ST Parallel cable. @item @b{lattice} Lattice ispDOWNLOAD Cable @item @b{old_amt_wiggler} The Wiggler configuration that comes with some versions of Amontec's Chameleon Programmer. The new version available from the website uses the original Wiggler layout ('@var{wiggler}') @item @b{triton} The parallel port adapter found on the ``Karo Triton 1 Development Board''. This is also the layout used by the HollyGates design (see @uref{http://www.lartmaker.nl/projects/jtag/}). @item @b{wiggler} The original Wiggler layout, also supported by several clones, such as the Olimex ARM-JTAG @item @b{wiggler2} Same as original wiggler except an led is fitted on D5. @item @b{wiggler_ntrst_inverted} Same as original wiggler except TRST is inverted. @end itemize @end deffn @deffn {Config Command} {parport port} [port_number] Display either the address of the I/O port (default: 0x378 for LPT1) or the number of the @file{/dev/parport} device. If a parameter is provided, first switch to use that port. This is a write-once setting. When using PPDEV to access the parallel port, use the number of the parallel port: @option{parport port 0} (the default). If @option{parport port 0x378} is specified you may encounter a problem. @end deffn @deffn {Config Command} {parport toggling_time} [nanoseconds] Displays how many nanoseconds the hardware needs to toggle TCK; the parport driver uses this value to obey the @command{adapter speed} configuration. When the optional @var{nanoseconds} parameter is given, that setting is changed before displaying the current value. The default setting should work reasonably well on commodity PC hardware. However, you may want to calibrate for your specific hardware. @quotation Tip To measure the toggling time with a logic analyzer or a digital storage oscilloscope, follow the procedure below: @example > parport toggling_time 1000 > adapter speed 500 @end example This sets the maximum JTAG clock speed of the hardware, but the actual speed probably deviates from the requested 500 kHz. Now, measure the time between the two closest spaced TCK transitions. You can use @command{runtest 1000} or something similar to generate a large set of samples. Update the setting to match your measurement: @example > parport toggling_time <measured nanoseconds> @end example Now the clock speed will be a better match for @command{adapter speed} command given in OpenOCD scripts and event handlers. You can do something similar with many digital multimeters, but note that you'll probably need to run the clock continuously for several seconds before it decides what clock rate to show. Adjust the toggling time up or down until the measured clock rate is a good match with the rate you specified in the @command{adapter speed} command; be conservative. @end quotation @end deffn @deffn {Config Command} {parport write_on_exit} (@option{on}|@option{off}) This will configure the parallel driver to write a known cable-specific value to the parallel interface on exiting OpenOCD. @end deffn For example, the interface configuration file for a classic ``Wiggler'' cable on LPT2 might look something like this: @example adapter driver parport parport port 0x278 parport cable wiggler @end example @end deffn @deffn {Interface Driver} {presto} ASIX PRESTO USB JTAG programmer. @end deffn @deffn {Interface Driver} {rlink} Raisonance RLink USB adapter @end deffn @deffn {Interface Driver} {usbprog} usbprog is a freely programmable USB adapter. @end deffn @deffn {Interface Driver} {vsllink} vsllink is part of Versaloon which is a versatile USB programmer. @quotation Note This defines quite a few driver-specific commands, which are not currently documented here. @end quotation @end deffn @anchor{hla_interface} @deffn {Interface Driver} {hla} This is a driver that supports multiple High Level Adapters. This type of adapter does not expose some of the lower level api's that OpenOCD would normally use to access the target. Currently supported adapters include the STMicroelectronics ST-LINK, TI ICDI and Nuvoton Nu-Link. ST-LINK firmware version >= V2.J21.S4 recommended due to issues with earlier versions of firmware where serial number is reset after first use. Suggest using ST firmware update utility to upgrade ST-LINK firmware even if current version reported is V2.J21.S4. @deffn {Config Command} {hla_device_desc} description Currently Not Supported. @end deffn @deffn {Config Command} {hla_layout} (@option{stlink}|@option{icdi}|@option{nulink}) Specifies the adapter layout to use. @end deffn @deffn {Config Command} {hla_vid_pid} [vid pid]+ Pairs of vendor IDs and product IDs of the device. @end deffn @deffn {Config Command} {hla_stlink_backend} (usb | tcp [port]) @emph{ST-Link only:} Choose between 'exclusive' USB communication (the default backend) or 'shared' mode using ST-Link TCP server (the default port is 7184). @emph{Note:} ST-Link TCP server is a binary application provided by ST available from @url{https://www.st.com/en/development-tools/st-link-server.html, ST-LINK server software module}. @end deffn @deffn {Command} {hla_command} command Execute a custom adapter-specific command. The @var{command} string is passed as is to the underlying adapter layout handler. @end deffn @end deffn @anchor{st_link_dap_interface} @deffn {Interface Driver} {st-link} This is a driver that supports STMicroelectronics adapters ST-LINK/V2 (from firmware V2J24), STLINK-V3 and STLINK-V3PWR, thanks to a new API that provides directly access the arm ADIv5 DAP. The new API provide access to multiple AP on the same DAP, but the maximum number of the AP port is limited by the specific firmware version (e.g. firmware V2J29 has 3 as maximum AP number, while V2J32 has 8). An error is returned for any AP number above the maximum allowed value. @emph{Note:} Either these same adapters and their older versions are also supported by @ref{hla_interface, the hla interface driver}. @deffn {Config Command} {st-link backend} (usb | tcp [port]) Choose between 'exclusive' USB communication (the default backend) or 'shared' mode using ST-Link TCP server (the default port is 7184). @emph{Note:} ST-Link TCP server is a binary application provided by ST available from @url{https://www.st.com/en/development-tools/st-link-server.html, ST-LINK server software module}. @emph{Note:} ST-Link TCP server does not support the SWIM transport. @end deffn @deffn {Config Command} {st-link vid_pid} [vid pid]+ Pairs of vendor IDs and product IDs of the device. @end deffn @deffn {Command} {st-link cmd} rx_n (tx_byte)+ Sends an arbitrary command composed by the sequence of bytes @var{tx_byte} and receives @var{rx_n} bytes. For example, the command to read the target's supply voltage is one byte 0xf7 followed by 15 bytes zero. It returns 8 bytes, where the first 4 bytes represent the ADC sampling of the reference voltage 1.2V and the last 4 bytes represent the ADC sampling of half the target's supply voltage. @example > st-link cmd 8 0xf7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0xf1 0x05 0x00 0x00 0x0b 0x08 0x00 0x00 @end example The result can be converted to Volts (ignoring the most significant bytes, always zero) @example > set a [st-link cmd 8 0xf7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] > set n [expr @{[lindex $a 4] + 256 * [lindex $a 5]@}] > set d [expr @{[lindex $a 0] + 256 * [lindex $a 1]@}] > echo [expr @{2 * 1.2 * $n / $d@}] 3.24891518738 @end example @end deffn @end deffn @deffn {Interface Driver} {opendous} opendous-jtag is a freely programmable USB adapter. @end deffn @deffn {Interface Driver} {ulink} This is the Keil ULINK v1 JTAG debugger. @end deffn @deffn {Interface Driver} {xds110} The XDS110 is included as the embedded debug probe on many Texas Instruments LaunchPad evaluation boards. The XDS110 is also available as a stand-alone USB debug probe with the added capability to supply power to the target board. The following commands are supported by the XDS110 driver: @deffn {Config Command} {xds110 supply} voltage_in_millivolts Available only on the XDS110 stand-alone probe. Sets the voltage level of the XDS110 power supply. A value of 0 leaves the supply off. Otherwise, the supply can be set to any value in the range 1800 to 3600 millivolts. @end deffn @deffn {Command} {xds110 info} Displays information about the connected XDS110 debug probe (e.g. firmware version). @end deffn @end deffn @deffn {Interface Driver} {xlnx_pcie_xvc} This driver supports the Xilinx Virtual Cable (XVC) over PCI Express. It is commonly found in Xilinx based PCI Express designs. It allows debugging fabric based JTAG/SWD devices such as Cortex-M1/M3 microcontrollers. Access to this is exposed via extended capability registers in the PCI Express configuration space. For more information see Xilinx PG245 (Section on From_PCIE_to_JTAG mode). @deffn {Config Command} {xlnx_pcie_xvc config} device Specifies the PCI Express device via parameter @var{device} to use. The correct value for @var{device} can be obtained by looking at the output of lscpi -D (first column) for the corresponding device. The string will be of the format "DDDD:BB:SS.F" such as "0000:65:00.1". @end deffn @end deffn @deffn {Interface Driver} {bcm2835gpio} This SoC is present in Raspberry Pi which is a cheap single-board computer exposing some GPIOs on its expansion header. The driver accesses memory-mapped GPIO peripheral registers directly for maximum performance, but the only possible race condition is for the pins' modes/muxing (which is highly unlikely), so it should be able to coexist nicely with both sysfs bitbanging and various peripherals' kernel drivers. The driver restores the previous configuration on exit. GPIO numbers >= 32 can't be used for performance reasons. GPIO configuration is handled by the generic command @ref{adapter gpio, @command{adapter gpio}}. See @file{interface/raspberrypi-native.cfg} for a sample config and @file{interface/raspberrypi-gpio-connector.cfg} for pinout. @deffn {Config Command} {bcm2835gpio speed_coeffs} @var{speed_coeff} @var{speed_offset} Set SPEED_COEFF and SPEED_OFFSET for delay calculations. If unspecified, speed_coeff defaults to 113714, and speed_offset defaults to 28. @end deffn @deffn {Config Command} {bcm2835gpio peripheral_mem_dev} @var{device} Set the device path for access to the memory mapped GPIO control registers. Uses @file{/dev/gpiomem} by default, this is also the preferred option with respect to system security. If overridden to @file{/dev/mem}: @itemize @minus @item OpenOCD needs @code{cap_sys_rawio} or run as root to open @file{/dev/mem}. Please be aware of security issues imposed by running OpenOCD with elevated user rights and by @file{/dev/mem} itself. @item correct @command{peripheral_base} must be configured. @item GPIO 0-27 pads are set to the limited slew rate and drive strength is reduced to 4 mA (2 mA on RPi 4). @end itemize @end deffn @deffn {Config Command} {bcm2835gpio peripheral_base} @var{base} Set the peripheral base register address to access GPIOs. Ignored if @file{/dev/gpiomem} is used. For the RPi1, use 0x20000000. For RPi2 and RPi3, use 0x3F000000. For RPi4, use 0xFE000000. A full list can be found in the @uref{https://www.raspberrypi.org/documentation/hardware/raspberrypi/peripheral_addresses.md, official guide}. @end deffn @end deffn @deffn {Interface Driver} {imx_gpio} i.MX SoC is present in many community boards. Wandboard is an example of the one which is most popular. This driver is mostly the same as bcm2835gpio. See @file{interface/imx-native.cfg} for a sample config and pinout. @end deffn @deffn {Interface Driver} {am335xgpio} The AM335x SoC is present in BeagleBone Black and BeagleBone Green single-board computers which expose some of the GPIOs on the two expansion headers. For maximum performance the driver accesses memory-mapped GPIO peripheral registers directly. The memory mapping requires read and write permission to kernel memory; if /dev/gpiomem exists it will be used, otherwise /dev/mem will be used. The driver restores the GPIO state on exit. All four GPIO ports are available. GPIO configuration is handled by the generic command @ref{adapter gpio, @command{adapter gpio}}. @deffn {Config Command} {am335xgpio speed_coeffs} @var{speed_coeff} @var{speed_offset} Set SPEED_COEFF and SPEED_OFFSET for delay calculations. If unspecified speed_coeff defaults to 600000 and speed_offset defaults to 575. @end deffn See @file{interface/beaglebone-swd-native.cfg} for a sample configuration file. @end deffn @deffn {Interface Driver} {linuxgpiod} Linux provides userspace access to GPIO through libgpiod since Linux kernel version v4.6. The driver emulates either JTAG or SWD transport through bitbanging. There are no driver-specific commands, all GPIO configuration is handled by the generic command @ref{adapter gpio, @command{adapter gpio}}. This driver supports the resistor pull options provided by the @command{adapter gpio} command but the underlying hardware may not be able to support them. See @file{interface/dln-2-gpiod.cfg} for a sample configuration file. @end deffn @deffn {Interface Driver} {sysfsgpio} Linux legacy userspace access to GPIO through sysfs is deprecated from Linux kernel version v5.3. Prefer using @b{linuxgpiod}, instead. See @file{interface/sysfsgpio-raspberrypi.cfg} for a sample config. @end deffn @deffn {Interface Driver} {openjtag} OpenJTAG compatible USB adapter. This defines some driver-specific commands: @deffn {Config Command} {openjtag variant} variant Specifies the variant of the OpenJTAG adapter (see @uref{http://www.openjtag.org/}). Currently valid @var{variant} values include: @itemize @minus @item @b{standard} Standard variant (default). @item @b{cy7c65215} Cypress CY7C65215 Dual Channel USB-Serial Bridge Controller (see @uref{http://www.cypress.com/?rID=82870}). @end itemize @end deffn @deffn {Config Command} {openjtag device_desc} string The USB device description string of the adapter. This value is only used with the standard variant. @end deffn @end deffn @deffn {Interface Driver} {vdebug} Cadence Virtual Debug Interface driver. @deffn {Config Command} {vdebug server} host:port Specifies the host and TCP port number where the vdebug server runs. @end deffn @deffn {Config Command} {vdebug batching} value Specifies the batching method for the vdebug request. Possible values are 0 for no batching 1 or wr to batch write transactions together (default) 2 or rw to batch both read and write transactions @end deffn @deffn {Config Command} {vdebug polling} min max Takes two values, representing the polling interval in ms. Lower values mean faster debugger responsiveness, but lower emulation performance. The minimum should be around 10, maximum should not exceed 1000, which is the default gdb and keepalive timeout value. @end deffn @deffn {Config Command} {vdebug bfm_path} path clk_period Specifies the hierarchical path and input clk period of the vdebug BFM in the design. The hierarchical path uses Verilog notation top.inst.inst The clock period must include the unit, for instance 40ns. @end deffn @deffn {Config Command} {vdebug mem_path} path base size Specifies the hierarchical path to the design memory instance for backdoor access. Up to 4 memories can be specified. The hierarchical path uses Verilog notation. The base specifies start address in the design address space, size its size in bytes. Both values can use hexadecimal notation with prefix 0x. @end deffn @end deffn @deffn {Interface Driver} {jtag_dpi} SystemVerilog Direct Programming Interface (DPI) compatible driver for JTAG devices in emulation. The driver acts as a client for the SystemVerilog DPI server interface. @deffn {Config Command} {jtag_dpi set_port} port Specifies the TCP/IP port number of the SystemVerilog DPI server interface. @end deffn @deffn {Config Command} {jtag_dpi set_address} address Specifies the TCP/IP address of the SystemVerilog DPI server interface. @end deffn @end deffn @deffn {Interface Driver} {buspirate} This driver is for the Bus Pirate (see @url{http://dangerousprototypes.com/docs/Bus_Pirate}) and compatible devices. It uses a simple data protocol over a serial port connection. Most hardware development boards have a UART, a real serial port, or a virtual USB serial device, so this driver allows you to start building your own JTAG adapter without the complexity of a custom USB connection. @deffn {Config Command} {buspirate port} serial_port Specify the serial port's filename. For example: @example buspirate port /dev/ttyUSB0 @end example @end deffn @deffn {Config Command} {buspirate speed} (normal|fast) Set the communication speed to 115k (normal) or 1M (fast). For example: @example buspirate speed normal @end example @end deffn @deffn {Config Command} {buspirate mode} (normal|open-drain) Set the Bus Pirate output mode. @itemize @minus @item In normal mode (push/pull), do not enable the pull-ups, and do not connect I/O header pin VPU to JTAG VREF. @item In open drain mode, you will then need to enable the pull-ups. @end itemize For example: @example buspirate mode normal @end example @end deffn @deffn {Config Command} {buspirate pullup} (0|1) Whether to connect (1) or not (0) the I/O header pin VPU (JTAG VREF) to the pull-up/pull-down resistors on MOSI (JTAG TDI), CLK (JTAG TCK), MISO (JTAG TDO) and CS (JTAG TMS). For example: @example buspirate pullup 0 @end example @end deffn @deffn {Config Command} {buspirate vreg} (0|1) Whether to enable (1) or disable (0) the built-in voltage regulator, which can be used to supply power to a test circuit through I/O header pins +3V3 and +5V. For example: @example buspirate vreg 0 @end example @end deffn @deffn {Command} {buspirate led} (0|1) Turns the Bus Pirate's LED on (1) or off (0). For example: @end deffn @example buspirate led 1 @end example @end deffn @deffn {Interface Driver} {esp_usb_jtag} Espressif JTAG driver to communicate with ESP32-C3, ESP32-S3 chips and ESP USB Bridge board using OpenOCD. These chips have built-in JTAG circuitry and can be debugged without any additional hardware. Only an USB cable connected to the D+/D- pins is necessary. @deffn {Command} {espusbjtag tdo} Returns the current state of the TDO line @end deffn @deffn {Command} {espusbjtag setio} setio Manually set the status of the output lines with the order of (tdi tms tck trst srst) @example espusbjtag setio 0 1 0 1 0 @end example @end deffn @deffn {Config Command} {espusbjtag vid_pid} vid_pid Set vendor ID and product ID for the ESP usb jtag driver @example espusbjtag vid_pid 0x303a 0x1001 @end example @end deffn @deffn {Config Command} {espusbjtag caps_descriptor} caps_descriptor Set the jtag descriptor to read capabilities of ESP usb jtag driver @example espusbjtag caps_descriptor 0x2000 @end example @end deffn @deffn {Config Command} {espusbjtag chip_id} chip_id Set chip id to transfer to the ESP USB bridge board @example espusbjtag chip_id 1 @end example @end deffn @end deffn @section Transport Configuration @cindex Transport As noted earlier, depending on the version of OpenOCD you use, and the debug adapter you are using, several transports may be available to communicate with debug targets (or perhaps to program flash memory). @deffn {Command} {transport list} displays the names of the transports supported by this version of OpenOCD. @end deffn @deffn {Command} {transport select} @option{transport_name} Select which of the supported transports to use in this OpenOCD session. When invoked with @option{transport_name}, attempts to select the named transport. The transport must be supported by the debug adapter hardware and by the version of OpenOCD you are using (including the adapter's driver). If no transport has been selected and no @option{transport_name} is provided, @command{transport select} auto-selects the first transport supported by the debug adapter. @command{transport select} always returns the name of the session's selected transport, if any. @end deffn @subsection JTAG Transport @cindex JTAG JTAG is the original transport supported by OpenOCD, and most of the OpenOCD commands support it. JTAG transports expose a chain of one or more Test Access Points (TAPs), each of which must be explicitly declared. JTAG supports both debugging and boundary scan testing. Flash programming support is built on top of debug support. JTAG transport is selected with the command @command{transport select jtag}. Unless your adapter uses either @ref{hla_interface,the hla interface driver} (in which case the command is @command{transport select hla_jtag}) or @ref{st_link_dap_interface,the st-link interface driver} (in which case the command is @command{transport select dapdirect_jtag}). @subsection SWD Transport @cindex SWD @cindex Serial Wire Debug SWD (Serial Wire Debug) is an ARM-specific transport which exposes one Debug Access Point (DAP, which must be explicitly declared. (SWD uses fewer signal wires than JTAG.) SWD is debug-oriented, and does not support boundary scan testing. Flash programming support is built on top of debug support. (Some processors support both JTAG and SWD.) SWD transport is selected with the command @command{transport select swd}. Unless your adapter uses either @ref{hla_interface,the hla interface driver} (in which case the command is @command{transport select hla_swd}) or @ref{st_link_dap_interface,the st-link interface driver} (in which case the command is @command{transport select dapdirect_swd}). @deffn {Config Command} {swd newdap} ... Declares a single DAP which uses SWD transport. Parameters are currently the same as "jtag newtap" but this is expected to change. @end deffn @cindex SWD multi-drop The newer SWD devices (SW-DP v2 or SWJ-DP v2) support the multi-drop extension of SWD protocol: two or more devices can be connected to one SWD adapter. SWD transport works in multi-drop mode if @ref{dap_create,DAP} is configured with both @code{-dp-id} and @code{-instance-id} parameters regardless how many DAPs are created. Not all adapters and adapter drivers support SWD multi-drop. Only the following adapter drivers are SWD multi-drop capable: cmsis_dap (use an adapter with CMSIS-DAP version 2.0), ftdi, all bitbang based. @subsection SPI Transport @cindex SPI @cindex Serial Peripheral Interface The Serial Peripheral Interface (SPI) is a general purpose transport which uses four wire signaling. Some processors use it as part of a solution for flash programming. @anchor{swimtransport} @subsection SWIM Transport @cindex SWIM @cindex Single Wire Interface Module The Single Wire Interface Module (SWIM) is a low-pin-count debug protocol used by the STMicroelectronics MCU family STM8 and documented in the @uref{https://www.st.com/resource/en/user_manual/cd00173911.pdf, User Manual UM470}. SWIM does not support boundary scan testing nor multiple cores. The SWIM transport is selected with the command @command{transport select swim}. The concept of TAPs does not fit in the protocol since SWIM does not implement a scan chain. Nevertheless, the current SW model of OpenOCD requires defining a virtual SWIM TAP through the command @command{swim newtap basename tap_type}. The TAP definition must precede the target definition command @command{target create target_name stm8 -chain-position basename.tap_type}. @anchor{jtagspeed} @section JTAG Speed JTAG clock setup is part of system setup. It @emph{does not belong with interface setup} since any interface only knows a few of the constraints for the JTAG clock speed. Sometimes the JTAG speed is changed during the target initialization process: (1) slow at reset, (2) program the CPU clocks, (3) run fast. Both the "slow" and "fast" clock rates are functions of the oscillators used, the chip, the board design, and sometimes power management software that may be active. The speed used during reset, and the scan chain verification which follows reset, can be adjusted using a @code{reset-start} target event handler. It can then be reconfigured to a faster speed by a @code{reset-init} target event handler after it reprograms those CPU clocks, or manually (if something else, such as a boot loader, sets up those clocks). @xref{targetevents,,Target Events}. When the initial low JTAG speed is a chip characteristic, perhaps because of a required oscillator speed, provide such a handler in the target config file. When that speed is a function of a board-specific characteristic such as which speed oscillator is used, it belongs in the board config file instead. In both cases it's safest to also set the initial JTAG clock rate to that same slow speed, so that OpenOCD never starts up using a clock speed that's faster than the scan chain can support. @example jtag_rclk 3000 $_TARGET.cpu configure -event reset-start @{ jtag_rclk 3000 @} @end example If your system supports adaptive clocking (RTCK), configuring JTAG to use that is probably the most robust approach. However, it introduces delays to synchronize clocks; so it may not be the fastest solution. @b{NOTE:} Script writers should consider using @command{jtag_rclk} instead of @command{adapter speed}, but only for (ARM) cores and boards which support adaptive clocking. @deffn {Command} {adapter speed} max_speed_kHz A non-zero speed is in KHZ. Hence: 3000 is 3mhz. JTAG interfaces usually support a limited number of speeds. The speed actually used won't be faster than the speed specified. Chip data sheets generally include a top JTAG clock rate. The actual rate is often a function of a CPU core clock, and is normally less than that peak rate. For example, most ARM cores accept at most one sixth of the CPU clock. Speed 0 (khz) selects RTCK method. @xref{faqrtck,,FAQ RTCK}. If your system uses RTCK, you won't need to change the JTAG clocking after setup. Not all interfaces, boards, or targets support ``rtck''. If the interface device can not support it, an error is returned when you try to use RTCK. @end deffn @defun jtag_rclk fallback_speed_kHz @cindex adaptive clocking @cindex RTCK This Tcl proc (defined in @file{startup.tcl}) attempts to enable RTCK/RCLK. If that fails (maybe the interface, board, or target doesn't support it), falls back to the specified frequency. @example # Fall back to 3mhz if RTCK is not supported jtag_rclk 3000 @end example @end defun @node Reset Configuration @chapter Reset Configuration @cindex Reset Configuration Every system configuration may require a different reset configuration. This can also be quite confusing. Resets also interact with @var{reset-init} event handlers, which do things like setting up clocks and DRAM, and JTAG clock rates. (@xref{jtagspeed,,JTAG Speed}.) They can also interact with JTAG routers. Please see the various board files for examples. @quotation Note To maintainers and integrators: Reset configuration touches several things at once. Normally the board configuration file should define it and assume that the JTAG adapter supports everything that's wired up to the board's JTAG connector. However, the target configuration file could also make note of something the silicon vendor has done inside the chip, which will be true for most (or all) boards using that chip. And when the JTAG adapter doesn't support everything, the user configuration file will need to override parts of the reset configuration provided by other files. @end quotation @section Types of Reset There are many kinds of reset possible through JTAG, but they may not all work with a given board and adapter. That's part of why reset configuration can be error prone. @itemize @bullet @item @emph{System Reset} ... the @emph{SRST} hardware signal resets all chips connected to the JTAG adapter, such as processors, power management chips, and I/O controllers. Normally resets triggered with this signal behave exactly like pressing a RESET button. @item @emph{JTAG TAP Reset} ... the @emph{TRST} hardware signal resets just the TAP controllers connected to the JTAG adapter. Such resets should not be visible to the rest of the system; resetting a device's TAP controller just puts that controller into a known state. @item @emph{Emulation Reset} ... many devices can be reset through JTAG commands. These resets are often distinguishable from system resets, either explicitly (a "reset reason" register says so) or implicitly (not all parts of the chip get reset). @item @emph{Other Resets} ... system-on-chip devices often support several other types of reset. You may need to arrange that a watchdog timer stops while debugging, preventing a watchdog reset. There may be individual module resets. @end itemize In the best case, OpenOCD can hold SRST, then reset the TAPs via TRST and send commands through JTAG to halt the CPU at the reset vector before the 1st instruction is executed. Then when it finally releases the SRST signal, the system is halted under debugger control before any code has executed. This is the behavior required to support the @command{reset halt} and @command{reset init} commands; after @command{reset init} a board-specific script might do things like setting up DRAM. (@xref{resetcommand,,Reset Command}.) @anchor{srstandtrstissues} @section SRST and TRST Issues Because SRST and TRST are hardware signals, they can have a variety of system-specific constraints. Some of the most common issues are: @itemize @bullet @item @emph{Signal not available} ... Some boards don't wire SRST or TRST to the JTAG connector. Some JTAG adapters don't support such signals even if they are wired up. Use the @command{reset_config} @var{signals} options to say when either of those signals is not connected. When SRST is not available, your code might not be able to rely on controllers having been fully reset during code startup. Missing TRST is not a problem, since JTAG-level resets can be triggered using with TMS signaling. @item @emph{Signals shorted} ... Sometimes a chip, board, or adapter will connect SRST to TRST, instead of keeping them separate. Use the @command{reset_config} @var{combination} options to say when those signals aren't properly independent. @item @emph{Timing} ... Reset circuitry like a resistor/capacitor delay circuit, reset supervisor, or on-chip features can extend the effect of a JTAG adapter's reset for some time after the adapter stops issuing the reset. For example, there may be chip or board requirements that all reset pulses last for at least a certain amount of time; and reset buttons commonly have hardware debouncing. Use the @command{adapter srst delay} and @command{jtag_ntrst_delay} commands to say when extra delays are needed. @item @emph{Drive type} ... Reset lines often have a pullup resistor, letting the JTAG interface treat them as open-drain signals. But that's not a requirement, so the adapter may need to use push/pull output drivers. Also, with weak pullups it may be advisable to drive signals to both levels (push/pull) to minimize rise times. Use the @command{reset_config} @var{trst_type} and @var{srst_type} parameters to say how to drive reset signals. @item @emph{Special initialization} ... Targets sometimes need special JTAG initialization sequences to handle chip-specific issues (not limited to errata). For example, certain JTAG commands might need to be issued while the system as a whole is in a reset state (SRST active) but the JTAG scan chain is usable (TRST inactive). Many systems treat combined assertion of SRST and TRST as a trigger for a harder reset than SRST alone. Such custom reset handling is discussed later in this chapter. @end itemize There can also be other issues. Some devices don't fully conform to the JTAG specifications. Trivial system-specific differences are common, such as SRST and TRST using slightly different names. There are also vendors who distribute key JTAG documentation for their chips only to developers who have signed a Non-Disclosure Agreement (NDA). Sometimes there are chip-specific extensions like a requirement to use the normally-optional TRST signal (precluding use of JTAG adapters which don't pass TRST through), or needing extra steps to complete a TAP reset. In short, SRST and especially TRST handling may be very finicky, needing to cope with both architecture and board specific constraints. @section Commands for Handling Resets @deffn {Command} {adapter srst pulse_width} milliseconds Minimum amount of time (in milliseconds) OpenOCD should wait after asserting nSRST (active-low system reset) before allowing it to be deasserted. @end deffn @deffn {Command} {adapter srst delay} milliseconds How long (in milliseconds) OpenOCD should wait after deasserting nSRST (active-low system reset) before starting new JTAG operations. When a board has a reset button connected to SRST line it will probably have hardware debouncing, implying you should use this. @end deffn @deffn {Command} {jtag_ntrst_assert_width} milliseconds Minimum amount of time (in milliseconds) OpenOCD should wait after asserting nTRST (active-low JTAG TAP reset) before allowing it to be deasserted. @end deffn @deffn {Command} {jtag_ntrst_delay} milliseconds How long (in milliseconds) OpenOCD should wait after deasserting nTRST (active-low JTAG TAP reset) before starting new JTAG operations. @end deffn @anchor{reset_config} @deffn {Command} {reset_config} mode_flag ... This command displays or modifies the reset configuration of your combination of JTAG board and target in target configuration scripts. Information earlier in this section describes the kind of problems the command is intended to address (@pxref{srstandtrstissues,,SRST and TRST Issues}). As a rule this command belongs only in board config files, describing issues like @emph{board doesn't connect TRST}; or in user config files, addressing limitations derived from a particular combination of interface and board. (An unlikely example would be using a TRST-only adapter with a board that only wires up SRST.) The @var{mode_flag} options can be specified in any order, but only one of each type -- @var{signals}, @var{combination}, @var{gates}, @var{trst_type}, @var{srst_type} and @var{connect_type} -- may be specified at a time. If you don't provide a new value for a given type, its previous value (perhaps the default) is unchanged. For example, this means that you don't need to say anything at all about TRST just to declare that if the JTAG adapter should want to drive SRST, it must explicitly be driven high (@option{srst_push_pull}). @itemize @item @var{signals} can specify which of the reset signals are connected. For example, If the JTAG interface provides SRST, but the board doesn't connect that signal properly, then OpenOCD can't use it. Possible values are @option{none} (the default), @option{trst_only}, @option{srst_only} and @option{trst_and_srst}. @quotation Tip If your board provides SRST and/or TRST through the JTAG connector, you must declare that so those signals can be used. @end quotation @item The @var{combination} is an optional value specifying broken reset signal implementations. The default behaviour if no option given is @option{separate}, indicating everything behaves normally. @option{srst_pulls_trst} states that the test logic is reset together with the reset of the system (e.g. NXP LPC2000, "broken" board layout), @option{trst_pulls_srst} says that the system is reset together with the test logic (only hypothetical, I haven't seen hardware with such a bug, and can be worked around). @option{combined} implies both @option{srst_pulls_trst} and @option{trst_pulls_srst}. @item The @var{gates} tokens control flags that describe some cases where JTAG may be unavailable during reset. @option{srst_gates_jtag} (default) indicates that asserting SRST gates the JTAG clock. This means that no communication can happen on JTAG while SRST is asserted. Its converse is @option{srst_nogate}, indicating that JTAG commands can safely be issued while SRST is active. @item The @var{connect_type} tokens control flags that describe some cases where SRST is asserted while connecting to the target. @option{srst_nogate} is required to use this option. @option{connect_deassert_srst} (default) indicates that SRST will not be asserted while connecting to the target. Its converse is @option{connect_assert_srst}, indicating that SRST will be asserted before any target connection. Only some targets support this feature, STM32 and STR9 are examples. This feature is useful if you are unable to connect to your target due to incorrect options byte config or illegal program execution. @end itemize The optional @var{trst_type} and @var{srst_type} parameters allow the driver mode of each reset line to be specified. These values only affect JTAG interfaces with support for different driver modes, like the Amontec JTAGkey and JTAG Accelerator. Also, they are necessarily ignored if the relevant signal (TRST or SRST) is not connected. @itemize @item Possible @var{trst_type} driver modes for the test reset signal (TRST) are the default @option{trst_push_pull}, and @option{trst_open_drain}. Most boards connect this signal to a pulldown, so the JTAG TAPs never leave reset unless they are hooked up to a JTAG adapter. @item Possible @var{srst_type} driver modes for the system reset signal (SRST) are the default @option{srst_open_drain}, and @option{srst_push_pull}. Most boards connect this signal to a pullup, and allow the signal to be pulled low by various events including system power-up and pressing a reset button. @end itemize @end deffn @section Custom Reset Handling @cindex events OpenOCD has several ways to help support the various reset mechanisms provided by chip and board vendors. The commands shown in the previous section give standard parameters. There are also @emph{event handlers} associated with TAPs or Targets. Those handlers are Tcl procedures you can provide, which are invoked at particular points in the reset sequence. @emph{When SRST is not an option} you must set up a @code{reset-assert} event handler for your target. For example, some JTAG adapters don't include the SRST signal; and some boards have multiple targets, and you won't always want to reset everything at once. After configuring those mechanisms, you might still find your board doesn't start up or reset correctly. For example, maybe it needs a slightly different sequence of SRST and/or TRST manipulations, because of quirks that the @command{reset_config} mechanism doesn't address; or asserting both might trigger a stronger reset, which needs special attention. Experiment with lower level operations, such as @command{adapter assert}, @command{adapter deassert} and the @command{jtag arp_*} operations shown here, to find a sequence of operations that works. @xref{JTAG Commands}. When you find a working sequence, it can be used to override @command{jtag_init}, which fires during OpenOCD startup (@pxref{configurationstage,,Configuration Stage}); or @command{init_reset}, which fires during reset processing. You might also want to provide some project-specific reset schemes. For example, on a multi-target board the standard @command{reset} command would reset all targets, but you may need the ability to reset only one target at time and thus want to avoid using the board-wide SRST signal. @deffn {Overridable Procedure} {init_reset} mode This is invoked near the beginning of the @command{reset} command, usually to provide as much of a cold (power-up) reset as practical. By default it is also invoked from @command{jtag_init} if the scan chain does not respond to pure JTAG operations. The @var{mode} parameter is the parameter given to the low level reset command (@option{halt}, @option{init}, or @option{run}), @option{setup}, or potentially some other value. The default implementation just invokes @command{jtag arp_init-reset}. Replacements will normally build on low level JTAG operations such as @command{adapter assert} and @command{adapter deassert}. Operations here must not address individual TAPs (or their associated targets) until the JTAG scan chain has first been verified to work. Implementations must have verified the JTAG scan chain before they return. This is done by calling @command{jtag arp_init} (or @command{jtag arp_init-reset}). @end deffn @deffn {Command} {jtag arp_init} This validates the scan chain using just the four standard JTAG signals (TMS, TCK, TDI, TDO). It starts by issuing a JTAG-only reset. Then it performs checks to verify that the scan chain configuration matches the TAPs it can observe. Those checks include checking IDCODE values for each active TAP, and verifying the length of their instruction registers using TAP @code{-ircapture} and @code{-irmask} values. If these tests all pass, TAP @code{setup} events are issued to all TAPs with handlers for that event. @end deffn @deffn {Command} {jtag arp_init-reset} This uses TRST and SRST to try resetting everything on the JTAG scan chain (and anything else connected to SRST). It then invokes the logic of @command{jtag arp_init}. @end deffn @node TAP Declaration @chapter TAP Declaration @cindex TAP declaration @cindex TAP configuration @emph{Test Access Ports} (TAPs) are the core of JTAG. TAPs serve many roles, including: @itemize @bullet @item @b{Debug Target} A CPU TAP can be used as a GDB debug target. @item @b{Flash Programming} Some chips program the flash directly via JTAG. Others do it indirectly, making a CPU do it. @item @b{Program Download} Using the same CPU support GDB uses, you can initialize a DRAM controller, download code to DRAM, and then start running that code. @item @b{Boundary Scan} Most chips support boundary scan, which helps test for board assembly problems like solder bridges and missing connections. @end itemize OpenOCD must know about the active TAPs on your board(s). Setting up the TAPs is the core task of your configuration files. Once those TAPs are set up, you can pass their names to code which sets up CPUs and exports them as GDB targets, probes flash memory, performs low-level JTAG operations, and more. @section Scan Chains @cindex scan chain TAPs are part of a hardware @dfn{scan chain}, which is a daisy chain of TAPs. They also need to be added to OpenOCD's software mirror of that hardware list, giving each member a name and associating other data with it. Simple scan chains, with a single TAP, are common in systems with a single microcontroller or microprocessor. More complex chips may have several TAPs internally. Very complex scan chains might have a dozen or more TAPs: several in one chip, more in the next, and connecting to other boards with their own chips and TAPs. You can display the list with the @command{scan_chain} command. (Don't confuse this with the list displayed by the @command{targets} command, presented in the next chapter. That only displays TAPs for CPUs which are configured as debugging targets.) Here's what the scan chain might look like for a chip more than one TAP: @verbatim TapName Enabled IdCode Expected IrLen IrCap IrMask -- ------------------ ------- ---------- ---------- ----- ----- ------ 0 omap5912.dsp Y 0x03df1d81 0x03df1d81 38 0x01 0x03 1 omap5912.arm Y 0x0692602f 0x0692602f 4 0x01 0x0f 2 omap5912.unknown Y 0x00000000 0x00000000 8 0x01 0x03 @end verbatim OpenOCD can detect some of that information, but not all of it. @xref{autoprobing,,Autoprobing}. Unfortunately, those TAPs can't always be autoconfigured, because not all devices provide good support for that. JTAG doesn't require supporting IDCODE instructions, and chips with JTAG routers may not link TAPs into the chain until they are told to do so. The configuration mechanism currently supported by OpenOCD requires explicit configuration of all TAP devices using @command{jtag newtap} commands, as detailed later in this chapter. A command like this would declare one tap and name it @code{chip1.cpu}: @example jtag newtap chip1 cpu -irlen 4 -expected-id 0x3ba00477 @end example Each target configuration file lists the TAPs provided by a given chip. Board configuration files combine all the targets on a board, and so forth. Note that @emph{the order in which TAPs are declared is very important.} That declaration order must match the order in the JTAG scan chain, both inside a single chip and between them. @xref{faqtaporder,,FAQ TAP Order}. For example, the STMicroelectronics STR912 chip has three separate TAPs@footnote{See the ST document titled: @emph{STR91xFAxxx, Section 3.15 Jtag Interface, Page: 28/102, Figure 3: JTAG chaining inside the STR91xFA}. @url{http://eu.st.com/stonline/products/literature/ds/13495.pdf}}. To configure those taps, @file{target/str912.cfg} includes commands something like this: @example jtag newtap str912 flash ... params ... jtag newtap str912 cpu ... params ... jtag newtap str912 bs ... params ... @end example Actual config files typically use a variable such as @code{$_CHIPNAME} instead of literals like @option{str912}, to support more than one chip of each type. @xref{Config File Guidelines}. @deffn {Command} {jtag names} Returns the names of all current TAPs in the scan chain. Use @command{jtag cget} or @command{jtag tapisenabled} to examine attributes and state of each TAP. @example foreach t [jtag names] @{ puts [format "TAP: %s\n" $t] @} @end example @end deffn @deffn {Command} {scan_chain} Displays the TAPs in the scan chain configuration, and their status. The set of TAPs listed by this command is fixed by exiting the OpenOCD configuration stage, but systems with a JTAG router can enable or disable TAPs dynamically. @end deffn @c FIXME! "jtag cget" should be able to return all TAP @c attributes, like "$target_name cget" does for targets. @c Probably want "jtag eventlist", and a "tap-reset" event @c (on entry to RESET state). @section TAP Names @cindex dotted name When TAP objects are declared with @command{jtag newtap}, a @dfn{dotted.name} is created for the TAP, combining the name of a module (usually a chip) and a label for the TAP. For example: @code{xilinx.tap}, @code{str912.flash}, @code{omap3530.jrc}, @code{dm6446.dsp}, or @code{stm32.cpu}. Many other commands use that dotted.name to manipulate or refer to the TAP. For example, CPU configuration uses the name, as does declaration of NAND or NOR flash banks. The components of a dotted name should follow ``C'' symbol name rules: start with an alphabetic character, then numbers and underscores are OK; while others (including dots!) are not. @section TAP Declaration Commands @deffn {Config Command} {jtag newtap} chipname tapname configparams... Declares a new TAP with the dotted name @var{chipname}.@var{tapname}, and configured according to the various @var{configparams}. The @var{chipname} is a symbolic name for the chip. Conventionally target config files use @code{$_CHIPNAME}, defaulting to the model name given by the chip vendor but overridable. @cindex TAP naming convention The @var{tapname} reflects the role of that TAP, and should follow this convention: @itemize @bullet @item @code{bs} -- For boundary scan if this is a separate TAP; @item @code{cpu} -- The main CPU of the chip, alternatively @code{arm} and @code{dsp} on chips with both ARM and DSP CPUs, @code{arm1} and @code{arm2} on chips with two ARMs, and so forth; @item @code{etb} -- For an embedded trace buffer (example: an ARM ETB11); @item @code{flash} -- If the chip has a flash TAP, like the str912; @item @code{jrc} -- For JTAG route controller (example: the ICEPick modules on many Texas Instruments chips, like the OMAP3530 on Beagleboards); @item @code{tap} -- Should be used only for FPGA- or CPLD-like devices with a single TAP; @item @code{unknownN} -- If you have no idea what the TAP is for (N is a number); @item @emph{when in doubt} -- Use the chip maker's name in their data sheet. For example, the Freescale i.MX31 has a SDMA (Smart DMA) with a JTAG TAP; that TAP should be named @code{sdma}. @end itemize Every TAP requires at least the following @var{configparams}: @itemize @bullet @item @code{-irlen} @var{NUMBER} @*The length in bits of the instruction register, such as 4 or 5 bits. @end itemize A TAP may also provide optional @var{configparams}: @itemize @bullet @item @code{-disable} (or @code{-enable}) @*Use the @code{-disable} parameter to flag a TAP which is not linked into the scan chain after a reset using either TRST or the JTAG state machine's @sc{reset} state. You may use @code{-enable} to highlight the default state (the TAP is linked in). @xref{enablinganddisablingtaps,,Enabling and Disabling TAPs}. @item @code{-expected-id} @var{NUMBER} @*A non-zero @var{number} represents a 32-bit IDCODE which you expect to find when the scan chain is examined. These codes are not required by all JTAG devices. @emph{Repeat the option} as many times as required if more than one ID code could appear (for example, multiple versions). Specify @var{number} as zero to suppress warnings about IDCODE values that were found but not included in the list. Provide this value if at all possible, since it lets OpenOCD tell when the scan chain it sees isn't right. These values are provided in vendors' chip documentation, usually a technical reference manual. Sometimes you may need to probe the JTAG hardware to find these values. @xref{autoprobing,,Autoprobing}. @item @code{-ignore-version} @*Specify this to ignore the JTAG version field in the @code{-expected-id} option. When vendors put out multiple versions of a chip, or use the same JTAG-level ID for several largely-compatible chips, it may be more practical to ignore the version field than to update config files to handle all of the various chip IDs. The version field is defined as bit 28-31 of the IDCODE. @item @code{-ignore-bypass} @*Specify this to ignore the 'bypass' bit of the idcode. Some vendor put an invalid idcode regarding this bit. Specify this to ignore this bit and to not consider this tap in bypass mode. @item @code{-ircapture} @var{NUMBER} @*The bit pattern loaded by the TAP into the JTAG shift register on entry to the @sc{ircapture} state, such as 0x01. JTAG requires the two LSBs of this value to be 01. By default, @code{-ircapture} and @code{-irmask} are set up to verify that two-bit value. You may provide additional bits if you know them, or indicate that a TAP doesn't conform to the JTAG specification. @item @code{-irmask} @var{NUMBER} @*A mask used with @code{-ircapture} to verify that instruction scans work correctly. Such scans are not used by OpenOCD except to verify that there seems to be no problems with JTAG scan chain operations. @item @code{-ignore-syspwrupack} @*Specify this to ignore the CSYSPWRUPACK bit in the ARM DAP DP CTRL/STAT register during initial examination and when checking the sticky error bit. This bit is normally checked after setting the CSYSPWRUPREQ bit, but some devices do not set the ack bit until sometime later. @end itemize @end deffn @section Other TAP commands @deffn {Command} {jtag cget} dotted.name @option{-idcode} Get the value of the IDCODE found in hardware. @end deffn @deffn {Command} {jtag cget} dotted.name @option{-event} event_name @deffnx {Command} {jtag configure} dotted.name @option{-event} event_name handler At this writing this TAP attribute mechanism is limited and used mostly for event handling. (It is not a direct analogue of the @code{cget}/@code{configure} mechanism for debugger targets.) See the next section for information about the available events. The @code{configure} subcommand assigns an event handler, a TCL string which is evaluated when the event is triggered. The @code{cget} subcommand returns that handler. @end deffn @section TAP Events @cindex events @cindex TAP events OpenOCD includes two event mechanisms. The one presented here applies to all JTAG TAPs. The other applies to debugger targets, which are associated with certain TAPs. The TAP events currently defined are: @itemize @bullet @item @b{post-reset} @* The TAP has just completed a JTAG reset. The tap may still be in the JTAG @sc{reset} state. Handlers for these events might perform initialization sequences such as issuing TCK cycles, TMS sequences to ensure exit from the ARM SWD mode, and more. Because the scan chain has not yet been verified, handlers for these events @emph{should not issue commands which scan the JTAG IR or DR registers} of any particular target. @b{NOTE:} As this is written (September 2009), nothing prevents such access. @item @b{setup} @* The scan chain has been reset and verified. This handler may enable TAPs as needed. @item @b{tap-disable} @* The TAP needs to be disabled. This handler should implement @command{jtag tapdisable} by issuing the relevant JTAG commands. @item @b{tap-enable} @* The TAP needs to be enabled. This handler should implement @command{jtag tapenable} by issuing the relevant JTAG commands. @end itemize If you need some action after each JTAG reset which isn't actually specific to any TAP (since you can't yet trust the scan chain's contents to be accurate), you might: @example jtag configure CHIP.jrc -event post-reset @{ echo "JTAG Reset done" ... non-scan jtag operations to be done after reset @} @end example @anchor{enablinganddisablingtaps} @section Enabling and Disabling TAPs @cindex JTAG Route Controller @cindex jrc In some systems, a @dfn{JTAG Route Controller} (JRC) is used to enable and/or disable specific JTAG TAPs. Many ARM-based chips from Texas Instruments include an ``ICEPick'' module, which is a JRC. Such chips include DaVinci and OMAP3 processors. A given TAP may not be visible until the JRC has been told to link it into the scan chain; and if the JRC has been told to unlink that TAP, it will no longer be visible. Such routers address problems that JTAG ``bypass mode'' ignores, such as: @itemize @item The scan chain can only go as fast as its slowest TAP. @item Having many TAPs slows instruction scans, since all TAPs receive new instructions. @item TAPs in the scan chain must be powered up, which wastes power and prevents debugging some power management mechanisms. @end itemize The IEEE 1149.1 JTAG standard has no concept of a ``disabled'' tap, as implied by the existence of JTAG routers. However, the upcoming IEEE 1149.7 framework (layered on top of JTAG) does include a kind of JTAG router functionality. @c (a) currently the event handlers don't seem to be able to @c fail in a way that could lead to no-change-of-state. In OpenOCD, tap enabling/disabling is invoked by the Tcl commands shown below, and is implemented using TAP event handlers. So for example, when defining a TAP for a CPU connected to a JTAG router, your @file{target.cfg} file should define TAP event handlers using code that looks something like this: @example jtag configure CHIP.cpu -event tap-enable @{ ... jtag operations using CHIP.jrc @} jtag configure CHIP.cpu -event tap-disable @{ ... jtag operations using CHIP.jrc @} @end example Then you might want that CPU's TAP enabled almost all the time: @example jtag configure $CHIP.jrc -event setup "jtag tapenable $CHIP.cpu" @end example Note how that particular setup event handler declaration uses quotes to evaluate @code{$CHIP} when the event is configured. Using brackets @{ @} would cause it to be evaluated later, at runtime, when it might have a different value. @deffn {Command} {jtag tapdisable} dotted.name If necessary, disables the tap by sending it a @option{tap-disable} event. Returns the string "1" if the tap specified by @var{dotted.name} is enabled, and "0" if it is disabled. @end deffn @deffn {Command} {jtag tapenable} dotted.name If necessary, enables the tap by sending it a @option{tap-enable} event. Returns the string "1" if the tap specified by @var{dotted.name} is enabled, and "0" if it is disabled. @end deffn @deffn {Command} {jtag tapisenabled} dotted.name Returns the string "1" if the tap specified by @var{dotted.name} is enabled, and "0" if it is disabled. @quotation Note Humans will find the @command{scan_chain} command more helpful for querying the state of the JTAG taps. @end quotation @end deffn @anchor{autoprobing} @section Autoprobing @cindex autoprobe @cindex JTAG autoprobe TAP configuration is the first thing that needs to be done after interface and reset configuration. Sometimes it's hard finding out what TAPs exist, or how they are identified. Vendor documentation is not always easy to find and use. To help you get past such problems, OpenOCD has a limited @emph{autoprobing} ability to look at the scan chain, doing a @dfn{blind interrogation} and then reporting the TAPs it finds. To use this mechanism, start the OpenOCD server with only data that configures your JTAG interface, and arranges to come up with a slow clock (many devices don't support fast JTAG clocks right when they come out of reset). For example, your @file{openocd.cfg} file might have: @example source [find interface/olimex-arm-usb-tiny-h.cfg] reset_config trst_and_srst jtag_rclk 8 @end example When you start the server without any TAPs configured, it will attempt to autoconfigure the TAPs. There are two parts to this: @enumerate @item @emph{TAP discovery} ... After a JTAG reset (sometimes a system reset may be needed too), each TAP's data registers will hold the contents of either the IDCODE or BYPASS register. If JTAG communication is working, OpenOCD will see each TAP, and report what @option{-expected-id} to use with it. @item @emph{IR Length discovery} ... Unfortunately JTAG does not provide a reliable way to find out the value of the @option{-irlen} parameter to use with a TAP that is discovered. If OpenOCD can discover the length of a TAP's instruction register, it will report it. Otherwise you may need to consult vendor documentation, such as chip data sheets or BSDL files. @end enumerate In many cases your board will have a simple scan chain with just a single device. Here's what OpenOCD reported with one board that's a bit more complex: @example clock speed 8 kHz There are no enabled taps. AUTO PROBING MIGHT NOT WORK!! AUTO auto0.tap - use "jtag newtap auto0 tap -expected-id 0x2b900f0f ..." AUTO auto1.tap - use "jtag newtap auto1 tap -expected-id 0x07926001 ..." AUTO auto2.tap - use "jtag newtap auto2 tap -expected-id 0x0b73b02f ..." AUTO auto0.tap - use "... -irlen 4" AUTO auto1.tap - use "... -irlen 4" AUTO auto2.tap - use "... -irlen 6" no gdb ports allocated as no target has been specified @end example Given that information, you should be able to either find some existing config files to use, or create your own. If you create your own, you would configure from the bottom up: first a @file{target.cfg} file with these TAPs, any targets associated with them, and any on-chip resources; then a @file{board.cfg} with off-chip resources, clocking, and so forth. @anchor{dapdeclaration} @section DAP declaration (ARMv6-M, ARMv7 and ARMv8 targets) @cindex DAP declaration Since OpenOCD version 0.11.0, the Debug Access Port (DAP) is no longer implicitly created together with the target. It must be explicitly declared using the @command{dap create} command. For all ARMv6-M, ARMv7 and ARMv8 targets, the option "@option{-dap} @var{dap_name}" has to be used instead of "@option{-chain-position} @var{dotted.name}" when the target is created. The @command{dap} command group supports the following sub-commands: @anchor{dap_create} @deffn {Command} {dap create} dap_name @option{-chain-position} dotted.name configparams... Declare a DAP instance named @var{dap_name} linked to the JTAG tap @var{dotted.name}. This also creates a new command (@command{dap_name}) which is used for various purposes including additional configuration. There can only be one DAP for each JTAG tap in the system. A DAP may also provide optional @var{configparams}: @itemize @bullet @item @code{-adiv5} Specify that it's an ADIv5 DAP. This is the default if not specified. @item @code{-adiv6} Specify that it's an ADIv6 DAP. @item @code{-ignore-syspwrupack} Specify this to ignore the CSYSPWRUPACK bit in the ARM DAP DP CTRL/STAT register during initial examination and when checking the sticky error bit. This bit is normally checked after setting the CSYSPWRUPREQ bit, but some devices do not set the ack bit until sometime later. @item @code{-dp-id} @var{number} @*Debug port identification number for SWD DPv2 multidrop. The @var{number} is written to bits 0..27 of DP TARGETSEL during DP selection. To find the id number of a single connected device read DP TARGETID: @code{device.dap dpreg 0x24} Use bits 0..27 of TARGETID. @item @code{-instance-id} @var{number} @*Instance identification number for SWD DPv2 multidrop. The @var{number} is written to bits 28..31 of DP TARGETSEL during DP selection. To find the instance number of a single connected device read DP DLPIDR: @code{device.dap dpreg 0x34} The instance number is in bits 28..31 of DLPIDR value. @end itemize @end deffn @deffn {Command} {dap names} This command returns a list of all registered DAP objects. It it useful mainly for TCL scripting. @end deffn @deffn {Command} {dap info} [@var{num}|@option{root}] Displays the ROM table for MEM-AP @var{num}, defaulting to the currently selected AP of the currently selected target. On ADIv5 DAP @var{num} is the numeric index of the AP. On ADIv6 DAP @var{num} is the base address of the AP. With ADIv6 only, @option{root} specifies the root ROM table. @end deffn @deffn {Command} {dap init} Initialize all registered DAPs. This command is used internally during initialization. It can be issued at any time after the initialization, too. @end deffn The following commands exist as subcommands of DAP instances: @deffn {Command} {$dap_name info} [@var{num}|@option{root}] Displays the ROM table for MEM-AP @var{num}, defaulting to the currently selected AP. On ADIv5 DAP @var{num} is the numeric index of the AP. On ADIv6 DAP @var{num} is the base address of the AP. With ADIv6 only, @option{root} specifies the root ROM table. @end deffn @deffn {Command} {$dap_name apid} [num] Displays ID register from AP @var{num}, defaulting to the currently selected AP. On ADIv5 DAP @var{num} is the numeric index of the AP. On ADIv6 DAP @var{num} is the base address of the AP. @end deffn @anchor{DAP subcommand apreg} @deffn {Command} {$dap_name apreg} ap_num reg [value] Displays content of a register @var{reg} from AP @var{ap_num} or set a new value @var{value}. On ADIv5 DAP @var{ap_num} is the numeric index of the AP. On ADIv6 DAP @var{ap_num} is the base address of the AP. @var{reg} is byte address of a word register, 0, 4, 8 ... 0xfc. @end deffn @deffn {Command} {$dap_name apsel} [num] Select AP @var{num}, defaulting to 0. On ADIv5 DAP @var{num} is the numeric index of the AP. On ADIv6 DAP @var{num} is the base address of the AP. @end deffn @deffn {Command} {$dap_name dpreg} reg [value] Displays the content of DP register at address @var{reg}, or set it to a new value @var{value}. In case of SWD, @var{reg} is a value in packed format @math{dpbanksel << 4 | addr} and assumes values 0, 4, 8 ... 0xfc. In case of JTAG it only assumes values 0, 4, 8 and 0xc. @emph{Note:} Consider using @command{poll off} to avoid any disturbing background activity by OpenOCD while you are operating at such low-level. @end deffn @deffn {Command} {$dap_name baseaddr} [num] Displays debug base address from MEM-AP @var{num}, defaulting to the currently selected AP. On ADIv5 DAP @var{num} is the numeric index of the AP. On ADIv6 DAP @var{num} is the base address of the AP. @end deffn @deffn {Command} {$dap_name memaccess} [value] Displays the number of extra tck cycles in the JTAG idle to use for MEM-AP memory bus access [0-255], giving additional time to respond to reads. If @var{value} is defined, first assigns that. @end deffn @deffn {Command} {$dap_name apcsw} [value [mask]] Displays or changes CSW bit pattern for MEM-AP transfers. At the begin of each memory access the CSW pattern is extended (bitwise or-ed) by @dfn{Size} and @dfn{AddrInc} bit-fields according to transfer requirements and the result is written to the real CSW register. All bits except dynamically updated fields @dfn{Size} and @dfn{AddrInc} can be changed by changing the CSW pattern. Refer to ARM ADI v5 manual chapter 7.6.4 and appendix A for details. Use @var{value} only syntax if you want to set the new CSW pattern as a whole. The example sets HPROT1 bit (required by Cortex-M) and clears the rest of the pattern: @example kx.dap apcsw 0x2000000 @end example If @var{mask} is also used, the CSW pattern is changed only on bit positions where the mask bit is 1. The following example sets HPROT3 (cacheable) and leaves the rest of the pattern intact. It configures memory access through DCache on Cortex-M7. @example set CSW_HPROT3_CACHEABLE [expr @{1 << 27@}] samv.dap apcsw $CSW_HPROT3_CACHEABLE $CSW_HPROT3_CACHEABLE @end example Another example clears SPROT bit and leaves the rest of pattern intact: @example set CSW_SPROT [expr @{1 << 30@}] samv.dap apcsw 0 $CSW_SPROT @end example @emph{Note:} If you want to check the real value of CSW, not CSW pattern, use @code{xxx.dap apreg 0}. @xref{DAP subcommand apreg,,}. @emph{Warning:} Some of the CSW bits are vital for working memory transfer. If you set a wrong CSW pattern and MEM-AP stopped working, use the following example with a proper dap name: @example xxx.dap apcsw default @end example @end deffn @deffn {Config Command} {$dap_name ti_be_32_quirks} [@option{enable}] Set/get quirks mode for TI TMS450/TMS570 processors Disabled by default @end deffn @deffn {Config Command} {$dap_name nu_npcx_quirks} [@option{enable}] Set/get quirks mode for Nuvoton NPCX/NPCD MCU families Disabled by default @end deffn @node CPU Configuration @chapter CPU Configuration @cindex GDB target This chapter discusses how to set up GDB debug targets for CPUs. You can also access these targets without GDB (@pxref{Architecture and Core Commands}, and @ref{targetstatehandling,,Target State handling}) and through various kinds of NAND and NOR flash commands. If you have multiple CPUs you can have multiple such targets. We'll start by looking at how to examine the targets you have, then look at how to add one more target and how to configure it. @section Target List @cindex target, current @cindex target, list All targets that have been set up are part of a list, where each member has a name. That name should normally be the same as the TAP name. You can display the list with the @command{targets} (plural!) command. This display often has only one CPU; here's what it might look like with more than one: @verbatim TargetName Type Endian TapName State -- ------------------ ---------- ------ ------------------ ------------ 0* at91rm9200.cpu arm920t little at91rm9200.cpu running 1 MyTarget cortex_m little mychip.foo tap-disabled @end verbatim One member of that list is the @dfn{current target}, which is implicitly referenced by many commands. It's the one marked with a @code{*} near the target name. In particular, memory addresses often refer to the address space seen by that current target. Commands like @command{mdw} (memory display words) and @command{flash erase_address} (erase NOR flash blocks) are examples; and there are many more. Several commands let you examine the list of targets: @deffn {Command} {target current} Returns the name of the current target. @end deffn @deffn {Command} {target names} Lists the names of all current targets in the list. @example foreach t [target names] @{ puts [format "Target: %s\n" $t] @} @end example @end deffn @c yep, "target list" would have been better. @c plus maybe "target setdefault". @deffn {Command} {targets} [name] @emph{Note: the name of this command is plural. Other target command names are singular.} With no parameter, this command displays a table of all known targets in a user friendly form. With a parameter, this command sets the current target to the given target with the given @var{name}; this is only relevant on boards which have more than one target. @end deffn @section Target CPU Types @cindex target type @cindex CPU type Each target has a @dfn{CPU type}, as shown in the output of the @command{targets} command. You need to specify that type when calling @command{target create}. The CPU type indicates more than just the instruction set. It also indicates how that instruction set is implemented, what kind of debug support it integrates, whether it has an MMU (and if so, what kind), what core-specific commands may be available (@pxref{Architecture and Core Commands}), and more. It's easy to see what target types are supported, since there's a command to list them. @anchor{targettypes} @deffn {Command} {target types} Lists all supported target types. At this writing, the supported CPU types are: @itemize @bullet @item @code{aarch64} -- this is an ARMv8-A core with an MMU. @item @code{arm11} -- this is a generation of ARMv6 cores. @item @code{arm720t} -- this is an ARMv4 core with an MMU. @item @code{arm7tdmi} -- this is an ARMv4 core. @item @code{arm920t} -- this is an ARMv4 core with an MMU. @item @code{arm926ejs} -- this is an ARMv5 core with an MMU. @item @code{arm946e} -- this is an ARMv5 core with an MMU. @item @code{arm966e} -- this is an ARMv5 core. @item @code{arm9tdmi} -- this is an ARMv4 core. @item @code{avr} -- implements Atmel's 8-bit AVR instruction set. (Support for this is preliminary and incomplete.) @item @code{avr32_ap7k} -- this an AVR32 core. @item @code{cortex_a} -- this is an ARMv7-A core with an MMU. @item @code{cortex_m} -- this is an ARMv7-M core, supporting only the compact Thumb2 instruction set. Supports also ARMv6-M and ARMv8-M cores @item @code{cortex_r4} -- this is an ARMv7-R core. @item @code{dragonite} -- resembles arm966e. @item @code{dsp563xx} -- implements Freescale's 24-bit DSP. (Support for this is still incomplete.) @item @code{dsp5680xx} -- implements Freescale's 5680x DSP. @item @code{esirisc} -- this is an EnSilica eSi-RISC core. The current implementation supports eSi-32xx cores. @item @code{esp32} -- this is an Espressif SoC with dual Xtensa cores. @item @code{esp32s2} -- this is an Espressif SoC with single Xtensa core. @item @code{esp32s3} -- this is an Espressif SoC with dual Xtensa cores. @item @code{fa526} -- resembles arm920 (w/o Thumb). @item @code{feroceon} -- resembles arm926. @item @code{hla_target} -- a Cortex-M alternative to work with HL adapters like ST-Link. @item @code{ls1_sap} -- this is the SAP on NXP LS102x CPUs, allowing access to physical memory addresses independently of CPU cores. @item @code{mem_ap} -- this is an ARM debug infrastructure Access Port without a CPU, through which bus read and write cycles can be generated; it may be useful for working with non-CPU hardware behind an AP or during development of support for new CPUs. It's possible to connect a GDB client to this target (the GDB port has to be specified, @xref{gdbportoverride,,option -gdb-port}.), and a fake ARM core will be emulated to comply to GDB remote protocol. @item @code{mips_m4k} -- a MIPS core. @item @code{mips_mips64} -- a MIPS64 core. @item @code{or1k} -- this is an OpenRISC 1000 core. The current implementation supports three JTAG TAP cores: @itemize @minus @item @code{OpenCores TAP} (See: @url{http://opencores.org/project@comma{}jtag}) @item @code{Altera Virtual JTAG TAP} (See: @url{http://www.altera.com/literature/ug/ug_virtualjtag.pdf}) @item @code{Xilinx BSCAN_* virtual JTAG interface} (See: @url{http://www.xilinx.com/support/documentation/sw_manuals/xilinx14_2/spartan6_hdl.pdf}) @end itemize And two debug interfaces cores: @itemize @minus @item @code{Advanced debug interface} @*(See: @url{http://opencores.org/project@comma{}adv_debug_sys}) @item @code{SoC Debug Interface} @*(See: @url{http://opencores.org/project@comma{}dbg_interface}) @end itemize @item @code{quark_d20xx} -- an Intel Quark D20xx core. @item @code{quark_x10xx} -- an Intel Quark X10xx core. @item @code{riscv} -- a RISC-V core. @item @code{stm8} -- implements an STM8 core. @item @code{testee} -- a dummy target for cases without a real CPU, e.g. CPLD. @item @code{xscale} -- this is actually an architecture, not a CPU type. It is based on the ARMv5 architecture. @item @code{xtensa} -- this is a generic Cadence/Tensilica Xtensa core. @end itemize @end deffn To avoid being confused by the variety of ARM based cores, remember this key point: @emph{ARM is a technology licencing company}. (See: @url{http://www.arm.com}.) The CPU name used by OpenOCD will reflect the CPU design that was licensed, not a vendor brand which incorporates that design. Name prefixes like arm7, arm9, arm11, and cortex reflect design generations; while names like ARMv4, ARMv5, ARMv6, ARMv7 and ARMv8 reflect an architecture version implemented by a CPU design. @anchor{targetconfiguration} @section Target Configuration Before creating a ``target'', you must have added its TAP to the scan chain. When you've added that TAP, you will have a @code{dotted.name} which is used to set up the CPU support. The chip-specific configuration file will normally configure its CPU(s) right after it adds all of the chip's TAPs to the scan chain. Although you can set up a target in one step, it's often clearer if you use shorter commands and do it in two steps: create it, then configure optional parts. All operations on the target after it's created will use a new command, created as part of target creation. The two main things to configure after target creation are a work area, which usually has target-specific defaults even if the board setup code overrides them later; and event handlers (@pxref{targetevents,,Target Events}), which tend to be much more board-specific. The key steps you use might look something like this @example dap create mychip.dap -chain-position mychip.cpu target create MyTarget cortex_m -dap mychip.dap MyTarget configure -work-area-phys 0x08000 -work-area-size 8096 MyTarget configure -event reset-deassert-pre @{ jtag_rclk 5 @} MyTarget configure -event reset-init @{ myboard_reinit @} @end example You should specify a working area if you can; typically it uses some on-chip SRAM. Such a working area can speed up many things, including bulk writes to target memory; flash operations like checking to see if memory needs to be erased; GDB memory checksumming; and more. @quotation Warning On more complex chips, the work area can become inaccessible when application code (such as an operating system) enables or disables the MMU. For example, the particular MMU context used to access the virtual address will probably matter ... and that context might not have easy access to other addresses needed. At this writing, OpenOCD doesn't have much MMU intelligence. @end quotation It's often very useful to define a @code{reset-init} event handler. For systems that are normally used with a boot loader, common tasks include updating clocks and initializing memory controllers. That may be needed to let you write the boot loader into flash, in order to ``de-brick'' your board; or to load programs into external DDR memory without having run the boot loader. @deffn {Config Command} {target create} target_name type configparams... This command creates a GDB debug target that refers to a specific JTAG tap. It enters that target into a list, and creates a new command (@command{@var{target_name}}) which is used for various purposes including additional configuration. @itemize @bullet @item @var{target_name} ... is the name of the debug target. By convention this should be the same as the @emph{dotted.name} of the TAP associated with this target, which must be specified here using the @code{-chain-position @var{dotted.name}} configparam. This name is also used to create the target object command, referred to here as @command{$target_name}, and in other places the target needs to be identified. @item @var{type} ... specifies the target type. @xref{targettypes,,target types}. @item @var{configparams} ... all parameters accepted by @command{$target_name configure} are permitted. If the target is big-endian, set it here with @code{-endian big}. You @emph{must} set the @code{-chain-position @var{dotted.name}} or @code{-dap @var{dap_name}} here. @end itemize @end deffn @deffn {Command} {$target_name configure} configparams... The options accepted by this command may also be specified as parameters to @command{target create}. Their values can later be queried one at a time by using the @command{$target_name cget} command. @emph{Warning:} changing some of these after setup is dangerous. For example, moving a target from one TAP to another; and changing its endianness. @itemize @bullet @item @code{-chain-position} @var{dotted.name} -- names the TAP used to access this target. @item @code{-dap} @var{dap_name} -- names the DAP used to access this target. @xref{dapdeclaration,,DAP declaration}, on how to create and manage DAP instances. @item @code{-endian} (@option{big}|@option{little}) -- specifies whether the CPU uses big or little endian conventions @item @code{-event} @var{event_name} @var{event_body} -- @xref{targetevents,,Target Events}. Note that this updates a list of named event handlers. Calling this twice with two different event names assigns two different handlers, but calling it twice with the same event name assigns only one handler. Current target is temporarily overridden to the event issuing target before handler code starts and switched back after handler is done. @item @code{-work-area-backup} (@option{0}|@option{1}) -- says whether the work area gets backed up; by default, @emph{it is not backed up.} When possible, use a working_area that doesn't need to be backed up, since performing a backup slows down operations. For example, the beginning of an SRAM block is likely to be used by most build systems, but the end is often unused. @item @code{-work-area-size} @var{size} -- specify work are size, in bytes. The same size applies regardless of whether its physical or virtual address is being used. @item @code{-work-area-phys} @var{address} -- set the work area base @var{address} to be used when no MMU is active. @item @code{-work-area-virt} @var{address} -- set the work area base @var{address} to be used when an MMU is active. @emph{Do not specify a value for this except on targets with an MMU.} The value should normally correspond to a static mapping for the @code{-work-area-phys} address, set up by the current operating system. @anchor{rtostype} @item @code{-rtos} @var{rtos_type} -- enable rtos support for target, @var{rtos_type} can be one of @option{auto}, @option{none}, @option{eCos}, @option{ThreadX}, @option{FreeRTOS}, @option{linux}, @option{ChibiOS}, @option{embKernel}, @option{mqx}, @option{uCOS-III}, @option{nuttx}, @option{RIOT}, @option{Zephyr}, @option{rtkernel} @xref{gdbrtossupport,,RTOS Support}. @item @code{-defer-examine} -- skip target examination at initial JTAG chain scan and after a reset. A manual call to arp_examine is required to access the target for debugging. @item @code{-ap-num} @var{ap_number} -- set DAP access port for target. On ADIv5 DAP @var{ap_number} is the numeric index of the DAP AP the target is connected to. On ADIv6 DAP @var{ap_number} is the base address of the DAP AP the target is connected to. Use this option with systems where multiple, independent cores are connected to separate access ports of the same DAP. @item @code{-cti} @var{cti_name} -- set Cross-Trigger Interface (CTI) connected to the target. Currently, only the @code{aarch64} target makes use of this option, where it is a mandatory configuration for the target run control. @xref{armcrosstrigger,,ARM Cross-Trigger Interface}, for instruction on how to declare and control a CTI instance. @anchor{gdbportoverride} @item @code{-gdb-port} @var{number} -- see command @command{gdb_port} for the possible values of the parameter @var{number}, which are not only numeric values. Use this option to override, for this target only, the global parameter set with command @command{gdb_port}. @xref{gdb_port,,command gdb_port}. @item @code{-gdb-max-connections} @var{number} -- EXPERIMENTAL: set the maximum number of GDB connections that are allowed for the target. Default is 1. A negative value for @var{number} means unlimited connections. See @xref{gdbmeminspect,,Using GDB as a non-intrusive memory inspector}. @end itemize @end deffn @section Other $target_name Commands @cindex object command The Tcl/Tk language has the concept of object commands, and OpenOCD adopts that same model for targets. A good Tk example is a on screen button. Once a button is created a button has a name (a path in Tk terms) and that name is useable as a first class command. For example in Tk, one can create a button and later configure it like this: @example # Create button .foobar -background red -command @{ foo @} # Modify .foobar configure -foreground blue # Query set x [.foobar cget -background] # Report puts [format "The button is %s" $x] @end example In OpenOCD's terms, the ``target'' is an object just like a Tcl/Tk button, and its object commands are invoked the same way. @example str912.cpu mww 0x1234 0x42 omap3530.cpu mww 0x5555 123 @end example The commands supported by OpenOCD target objects are: @deffn {Command} {$target_name arp_examine} @option{allow-defer} @deffnx {Command} {$target_name arp_halt} @deffnx {Command} {$target_name arp_poll} @deffnx {Command} {$target_name arp_reset} @deffnx {Command} {$target_name arp_waitstate} Internal OpenOCD scripts (most notably @file{startup.tcl}) use these to deal with specific reset cases. They are not otherwise documented here. @end deffn @deffn {Command} {$target_name set_reg} dict Set register values of the target. @itemize @item @var{dict} ... Tcl dictionary with pairs of register names and values. @end itemize For example, the following command sets the value 0 to the program counter (pc) register and 0x1000 to the stack pointer (sp) register: @example set_reg @{pc 0 sp 0x1000@} @end example @end deffn @deffn {Command} {$target_name get_reg} [-force] list Get register values from the target and return them as Tcl dictionary with pairs of register names and values. If option "-force" is set, the register values are read directly from the target, bypassing any caching. @itemize @item @var{list} ... List of register names @end itemize For example, the following command retrieves the values from the program counter (pc) and stack pointer (sp) register: @example get_reg @{pc sp@} @end example @end deffn @deffn {Command} {$target_name write_memory} address width data ['phys'] This function provides an efficient way to write to the target memory from a Tcl script. @itemize @item @var{address} ... target memory address @item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 @item @var{data} ... Tcl list with the elements to write @item ['phys'] ... treat the memory address as physical instead of virtual address @end itemize For example, the following command writes two 32 bit words into the target memory at address 0x20000000: @example write_memory 0x20000000 32 @{0xdeadbeef 0x00230500@} @end example @end deffn @deffn {Command} {$target_name read_memory} address width count ['phys'] This function provides an efficient way to read the target memory from a Tcl script. A Tcl list containing the requested memory elements is returned by this function. @itemize @item @var{address} ... target memory address @item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 @item @var{count} ... number of elements to read @item ['phys'] ... treat the memory address as physical instead of virtual address @end itemize For example, the following command reads two 32 bit words from the target memory at address 0x20000000: @example read_memory 0x20000000 32 2 @end example @end deffn @deffn {Command} {$target_name cget} queryparm Each configuration parameter accepted by @command{$target_name configure} can be individually queried, to return its current value. The @var{queryparm} is a parameter name accepted by that command, such as @code{-work-area-phys}. There are a few special cases: @itemize @bullet @item @code{-event} @var{event_name} -- returns the handler for the event named @var{event_name}. This is a special case because setting a handler requires two parameters. @item @code{-type} -- returns the target type. This is a special case because this is set using @command{target create} and can't be changed using @command{$target_name configure}. @end itemize For example, if you wanted to summarize information about all the targets you might use something like this: @example foreach name [target names] @{ set y [$name cget -endian] set z [$name cget -type] puts [format "Chip %d is %s, Endian: %s, type: %s" \ $x $name $y $z] @} @end example @end deffn @anchor{targetcurstate} @deffn {Command} {$target_name curstate} Displays the current target state: @code{debug-running}, @code{halted}, @code{reset}, @code{running}, or @code{unknown}. (Also, @pxref{eventpolling,,Event Polling}.) @end deffn @deffn {Command} {$target_name eventlist} Displays a table listing all event handlers currently associated with this target. @xref{targetevents,,Target Events}. @end deffn @deffn {Command} {$target_name invoke-event} event_name Invokes the handler for the event named @var{event_name}. (This is primarily intended for use by OpenOCD framework code, for example by the reset code in @file{startup.tcl}.) @end deffn @deffn {Command} {$target_name mdd} [phys] addr [count] @deffnx {Command} {$target_name mdw} [phys] addr [count] @deffnx {Command} {$target_name mdh} [phys] addr [count] @deffnx {Command} {$target_name mdb} [phys] addr [count] Display contents of address @var{addr}, as 64-bit doublewords (@command{mdd}), 32-bit words (@command{mdw}), 16-bit halfwords (@command{mdh}), or 8-bit bytes (@command{mdb}). When the current target has an MMU which is present and active, @var{addr} is interpreted as a virtual address. Otherwise, or if the optional @var{phys} flag is specified, @var{addr} is interpreted as a physical address. If @var{count} is specified, displays that many units. (If you want to process the data instead of displaying it, see the @code{read_memory} primitives.) @end deffn @deffn {Command} {$target_name mwd} [phys] addr doubleword [count] @deffnx {Command} {$target_name mww} [phys] addr word [count] @deffnx {Command} {$target_name mwh} [phys] addr halfword [count] @deffnx {Command} {$target_name mwb} [phys] addr byte [count] Writes the specified @var{doubleword} (64 bits), @var{word} (32 bits), @var{halfword} (16 bits), or @var{byte} (8-bit) value, at the specified address @var{addr}. When the current target has an MMU which is present and active, @var{addr} is interpreted as a virtual address. Otherwise, or if the optional @var{phys} flag is specified, @var{addr} is interpreted as a physical address. If @var{count} is specified, fills that many units of consecutive address. @end deffn @anchor{targetevents} @section Target Events @cindex target events @cindex events At various times, certain things can happen, or you want them to happen. For example: @itemize @bullet @item What should happen when GDB connects? Should your target reset? @item When GDB tries to flash the target, do you need to enable the flash via a special command? @item Is using SRST appropriate (and possible) on your system? Or instead of that, do you need to issue JTAG commands to trigger reset? SRST usually resets everything on the scan chain, which can be inappropriate. @item During reset, do you need to write to certain memory locations to set up system clocks or to reconfigure the SDRAM? How about configuring the watchdog timer, or other peripherals, to stop running while you hold the core stopped for debugging? @end itemize All of the above items can be addressed by target event handlers. These are set up by @command{$target_name configure -event} or @command{target create ... -event}. The programmer's model matches the @code{-command} option used in Tcl/Tk buttons and events. The two examples below act the same, but one creates and invokes a small procedure while the other inlines it. @example proc my_init_proc @{ @} @{ echo "Disabling watchdog..." mww 0xfffffd44 0x00008000 @} mychip.cpu configure -event reset-init my_init_proc mychip.cpu configure -event reset-init @{ echo "Disabling watchdog..." mww 0xfffffd44 0x00008000 @} @end example The following target events are defined: @itemize @bullet @item @b{debug-halted} @* The target has halted for debug reasons (i.e.: breakpoint) @item @b{debug-resumed} @* The target has resumed (i.e.: GDB said run) @item @b{early-halted} @* Occurs early in the halt process @item @b{examine-start} @* Before target examine is called. @item @b{examine-end} @* After target examine is called with no errors. @item @b{examine-fail} @* After target examine fails. @item @b{gdb-attach} @* When GDB connects. Issued before any GDB communication with the target starts. GDB expects the target is halted during attachment. @xref{gdbmeminspect,,GDB as a non-intrusive memory inspector}, how to connect GDB to running target. The event can be also used to set up the target so it is possible to probe flash. Probing flash is necessary during GDB connect if you want to use @pxref{programmingusinggdb,,programming using GDB}. Another use of the flash memory map is for GDB to automatically choose hardware or software breakpoints depending on whether the breakpoint is in RAM or read only memory. Default is @code{halt} @item @b{gdb-detach} @* When GDB disconnects @item @b{gdb-end} @* When the target has halted and GDB is not doing anything (see early halt) @item @b{gdb-flash-erase-start} @* Before the GDB flash process tries to erase the flash (default is @code{reset init}) @item @b{gdb-flash-erase-end} @* After the GDB flash process has finished erasing the flash @item @b{gdb-flash-write-start} @* Before GDB writes to the flash @item @b{gdb-flash-write-end} @* After GDB writes to the flash (default is @code{reset halt}) @item @b{gdb-start} @* Before the target steps, GDB is trying to start/resume the target @item @b{halted} @* The target has halted @item @b{reset-assert-pre} @* Issued as part of @command{reset} processing after @command{reset-start} was triggered but before either SRST alone is asserted on the scan chain, or @code{reset-assert} is triggered. @item @b{reset-assert} @* Issued as part of @command{reset} processing after @command{reset-assert-pre} was triggered. When such a handler is present, cores which support this event will use it instead of asserting SRST. This support is essential for debugging with JTAG interfaces which don't include an SRST line (JTAG doesn't require SRST), and for selective reset on scan chains that have multiple targets. @item @b{reset-assert-post} @* Issued as part of @command{reset} processing after @code{reset-assert} has been triggered. or the target asserted SRST on the entire scan chain. @item @b{reset-deassert-pre} @* Issued as part of @command{reset} processing after @code{reset-assert-post} has been triggered. @item @b{reset-deassert-post} @* Issued as part of @command{reset} processing after @code{reset-deassert-pre} has been triggered and (if the target is using it) after SRST has been released on the scan chain. @item @b{reset-end} @* Issued as the final step in @command{reset} processing. @item @b{reset-init} @* Used by @b{reset init} command for board-specific initialization. This event fires after @emph{reset-deassert-post}. This is where you would configure PLLs and clocking, set up DRAM so you can download programs that don't fit in on-chip SRAM, set up pin multiplexing, and so on. (You may be able to switch to a fast JTAG clock rate here, after the target clocks are fully set up.) @item @b{reset-start} @* Issued as the first step in @command{reset} processing before @command{reset-assert-pre} is called. This is the most robust place to use @command{jtag_rclk} or @command{adapter speed} to switch to a low JTAG clock rate, when reset disables PLLs needed to use a fast clock. @item @b{resume-start} @* Before any target is resumed @item @b{resume-end} @* After all targets have resumed @item @b{resumed} @* Target has resumed @item @b{step-start} @* Before a target is single-stepped @item @b{step-end} @* After single-step has completed @item @b{trace-config} @* After target hardware trace configuration was changed @item @b{semihosting-user-cmd-0x100} @* The target made a semihosting call with user-defined operation number 0x100 @item @b{semihosting-user-cmd-0x101} @* The target made a semihosting call with user-defined operation number 0x101 @item @b{semihosting-user-cmd-0x102} @* The target made a semihosting call with user-defined operation number 0x102 @item @b{semihosting-user-cmd-0x103} @* The target made a semihosting call with user-defined operation number 0x103 @item @b{semihosting-user-cmd-0x104} @* The target made a semihosting call with user-defined operation number 0x104 @item @b{semihosting-user-cmd-0x105} @* The target made a semihosting call with user-defined operation number 0x105 @item @b{semihosting-user-cmd-0x106} @* The target made a semihosting call with user-defined operation number 0x106 @item @b{semihosting-user-cmd-0x107} @* The target made a semihosting call with user-defined operation number 0x107 @end itemize @quotation Note OpenOCD events are not supposed to be preempt by another event, but this is not enforced in current code. Only the target event @b{resumed} is executed with polling disabled; this avoids polling to trigger the event @b{halted}, reversing the logical order of execution of their handlers. Future versions of OpenOCD will prevent the event preemption and will disable the schedule of polling during the event execution. Do not rely on polling in any event handler; this means, don't expect the status of a core to change during the execution of the handler. The event handler will have to enable polling or use @command{$target_name arp_poll} to check if the core has changed status. @end quotation @node Flash Commands @chapter Flash Commands OpenOCD has different commands for NOR and NAND flash; the ``flash'' command works with NOR flash, while the ``nand'' command works with NAND flash. This partially reflects different hardware technologies: NOR flash usually supports direct CPU instruction and data bus access, while data from a NAND flash must be copied to memory before it can be used. (SPI flash must also be copied to memory before use.) However, the documentation also uses ``flash'' as a generic term; for example, ``Put flash configuration in board-specific files''. Flash Steps: @enumerate @item Configure via the command @command{flash bank} @* Do this in a board-specific configuration file, passing parameters as needed by the driver. @item Operate on the flash via @command{flash subcommand} @* Often commands to manipulate the flash are typed by a human, or run via a script in some automated way. Common tasks include writing a boot loader, operating system, or other data. @item GDB Flashing @* Flashing via GDB requires the flash be configured via ``flash bank'', and the GDB flash features be enabled. @xref{gdbconfiguration,,GDB Configuration}. @end enumerate Many CPUs have the ability to ``boot'' from the first flash bank. This means that misprogramming that bank can ``brick'' a system, so that it can't boot. JTAG tools, like OpenOCD, are often then used to ``de-brick'' the board by (re)installing working boot firmware. @anchor{norconfiguration} @section Flash Configuration Commands @cindex flash configuration @deffn {Config Command} {flash bank} name driver base size chip_width bus_width target [driver_options] Configures a flash bank which provides persistent storage for addresses from @math{base} to @math{base + size - 1}. These banks will often be visible to GDB through the target's memory map. In some cases, configuring a flash bank will activate extra commands; see the driver-specific documentation. @itemize @bullet @item @var{name} ... may be used to reference the flash bank in other flash commands. A number is also available. @item @var{driver} ... identifies the controller driver associated with the flash bank being declared. This is usually @code{cfi} for external flash, or else the name of a microcontroller with embedded flash memory. @xref{flashdriverlist,,Flash Driver List}. @item @var{base} ... Base address of the flash chip. @item @var{size} ... Size of the chip, in bytes. For some drivers, this value is detected from the hardware. @item @var{chip_width} ... Width of the flash chip, in bytes; ignored for most microcontroller drivers. @item @var{bus_width} ... Width of the data bus used to access the chip, in bytes; ignored for most microcontroller drivers. @item @var{target} ... Names the target used to issue commands to the flash controller. @comment Actually, it's currently a controller-specific parameter... @item @var{driver_options} ... drivers may support, or require, additional parameters. See the driver-specific documentation for more information. @end itemize @quotation Note This command is not available after OpenOCD initialization has completed. Use it in board specific configuration files, not interactively. @end quotation @end deffn @comment less confusing would be: "flash list" (like "nand list") @deffn {Command} {flash banks} Prints a one-line summary of each device that was declared using @command{flash bank}, numbered from zero. Note that this is the @emph{plural} form; the @emph{singular} form is a very different command. @end deffn @deffn {Command} {flash list} Retrieves a list of associative arrays for each device that was declared using @command{flash bank}, numbered from zero. This returned list can be manipulated easily from within scripts. @end deffn @deffn {Command} {flash probe} num Identify the flash, or validate the parameters of the configured flash. Operation depends on the flash type. The @var{num} parameter is a value shown by @command{flash banks}. Most flash commands will implicitly @emph{autoprobe} the bank; flash drivers can distinguish between probing and autoprobing, but most don't bother. @end deffn @section Preparing a Target before Flash Programming The target device should be in well defined state before the flash programming begins. @emph{Always issue} @command{reset init} before @ref{flashprogrammingcommands,,Flash Programming Commands}. Do not issue another @command{reset} or @command{reset halt} or @command{resume} until the programming session is finished. If you use @ref{programmingusinggdb,,Programming using GDB}, the target is prepared automatically in the event gdb-flash-erase-start The jimtcl script @command{program} calls @command{reset init} explicitly. @section Erasing, Reading, Writing to Flash @cindex flash erasing @cindex flash reading @cindex flash writing @cindex flash programming @anchor{flashprogrammingcommands} One feature distinguishing NOR flash from NAND or serial flash technologies is that for read access, it acts exactly like any other addressable memory. This means you can use normal memory read commands like @command{mdw} or @command{dump_image} with it, with no special @command{flash} subcommands. @xref{memoryaccess,,Memory access}, and @ref{imageaccess,,Image access}. Write access works differently. Flash memory normally needs to be erased before it's written. Erasing a sector turns all of its bits to ones, and writing can turn ones into zeroes. This is why there are special commands for interactive erasing and writing, and why GDB needs to know which parts of the address space hold NOR flash memory. @quotation Note Most of these erase and write commands leverage the fact that NOR flash chips consume target address space. They implicitly refer to the current JTAG target, and map from an address in that target's address space back to a flash bank. @comment In May 2009, those mappings may fail if any bank associated @comment with that target doesn't successfully autoprobe ... bug worth fixing? A few commands use abstract addressing based on bank and sector numbers, and don't depend on searching the current target and its address space. Avoid confusing the two command models. @end quotation Some flash chips implement software protection against accidental writes, since such buggy writes could in some cases ``brick'' a system. For such systems, erasing and writing may require sector protection to be disabled first. Examples include CFI flash such as ``Intel Advanced Bootblock flash'', and AT91SAM7 on-chip flash. @xref{flashprotect,,flash protect}. @deffn {Command} {flash erase_sector} num first last Erase sectors in bank @var{num}, starting at sector @var{first} up to and including @var{last}. Sector numbering starts at 0. Providing a @var{last} sector of @option{last} specifies "to the end of the flash bank". The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {flash erase_address} [@option{pad}] [@option{unlock}] address length Erase sectors starting at @var{address} for @var{length} bytes. Unless @option{pad} is specified, @math{address} must begin a flash sector, and @math{address + length - 1} must end a sector. Specifying @option{pad} erases extra data at the beginning and/or end of the specified region, as needed to erase only full sectors. The flash bank to use is inferred from the @var{address}, and the specified length must stay within that bank. As a special case, when @var{length} is zero and @var{address} is the start of the bank, the whole flash is erased. If @option{unlock} is specified, then the flash is unprotected before erase starts. @end deffn @deffn {Command} {flash filld} address double-word length @deffnx {Command} {flash fillw} address word length @deffnx {Command} {flash fillh} address halfword length @deffnx {Command} {flash fillb} address byte length Fills flash memory with the specified @var{double-word} (64 bits), @var{word} (32 bits), @var{halfword} (16 bits), or @var{byte} (8-bit) pattern, starting at @var{address} and continuing for @var{length} units (word/halfword/byte). No erasure is done before writing; when needed, that must be done before issuing this command. Writes are done in blocks of up to 1024 bytes, and each write is verified by reading back the data and comparing it to what was written. The flash bank to use is inferred from the @var{address} of each block, and the specified length must stay within that bank. @end deffn @comment no current checks for errors if fill blocks touch multiple banks! @deffn {Command} {flash mdw} addr [count] @deffnx {Command} {flash mdh} addr [count] @deffnx {Command} {flash mdb} addr [count] Display contents of address @var{addr}, as 32-bit words (@command{mdw}), 16-bit halfwords (@command{mdh}), or 8-bit bytes (@command{mdb}). If @var{count} is specified, displays that many units. Reads from flash using the flash driver, therefore it enables reading from a bank not mapped in target address space. The flash bank to use is inferred from the @var{address} of each block, and the specified length must stay within that bank. @end deffn @deffn {Command} {flash write_bank} num filename [offset] Write the binary @file{filename} to flash bank @var{num}, starting at @var{offset} bytes from the beginning of the bank. If @var{offset} is omitted, start at the beginning of the flash bank. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {flash read_bank} num filename [offset [length]] Read @var{length} bytes from the flash bank @var{num} starting at @var{offset} and write the contents to the binary @file{filename}. If @var{offset} is omitted, start at the beginning of the flash bank. If @var{length} is omitted, read the remaining bytes from the flash bank. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {flash verify_bank} num filename [offset] Compare the contents of the binary file @var{filename} with the contents of the flash bank @var{num} starting at @var{offset}. If @var{offset} is omitted, start at the beginning of the flash bank. Fail if the contents do not match. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {flash write_image} [erase] [unlock] filename [offset] [type] Write the image @file{filename} to the current target's flash bank(s). Only loadable sections from the image are written. A relocation @var{offset} may be specified, in which case it is added to the base address for each section in the image. The file [@var{type}] can be specified explicitly as @option{bin} (binary), @option{ihex} (Intel hex), @option{elf} (ELF file), @option{s19} (Motorola s19). @option{mem}, or @option{builder}. The relevant flash sectors will be erased prior to programming if the @option{erase} parameter is given. If @option{unlock} is provided, then the flash banks are unlocked before erase and program. The flash bank to use is inferred from the address of each image section. @quotation Warning Be careful using the @option{erase} flag when the flash is holding data you want to preserve. Portions of the flash outside those described in the image's sections might be erased with no notice. @itemize @item When a section of the image being written does not fill out all the sectors it uses, the unwritten parts of those sectors are necessarily also erased, because sectors can't be partially erased. @item Data stored in sector "holes" between image sections are also affected. For example, "@command{flash write_image erase ...}" of an image with one byte at the beginning of a flash bank and one byte at the end erases the entire bank -- not just the two sectors being written. @end itemize Also, when flash protection is important, you must re-apply it after it has been removed by the @option{unlock} flag. @end quotation @end deffn @deffn {Command} {flash verify_image} filename [offset] [type] Verify the image @file{filename} to the current target's flash bank(s). Parameters follow the description of 'flash write_image'. In contrast to the 'verify_image' command, for banks with specific verify method, that one is used instead of the usual target's read memory methods. This is necessary for flash banks not readable by ordinary memory reads. This command gives only an overall good/bad result for each bank, not addresses of individual failed bytes as it's intended only as quick check for successful programming. @end deffn @section Other Flash commands @cindex flash protection @deffn {Command} {flash erase_check} num Check erase state of sectors in flash bank @var{num}, and display that status. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {flash info} num [sectors] Print info about flash bank @var{num}, a list of protection blocks and their status. Use @option{sectors} to show a list of sectors instead. The @var{num} parameter is a value shown by @command{flash banks}. This command will first query the hardware, it does not print cached and possibly stale information. @end deffn @anchor{flashprotect} @deffn {Command} {flash protect} num first last (@option{on}|@option{off}) Enable (@option{on}) or disable (@option{off}) protection of flash blocks in flash bank @var{num}, starting at protection block @var{first} and continuing up to and including @var{last}. Providing a @var{last} block of @option{last} specifies "to the end of the flash bank". The @var{num} parameter is a value shown by @command{flash banks}. The protection block is usually identical to a flash sector. Some devices may utilize a protection block distinct from flash sector. See @command{flash info} for a list of protection blocks. @end deffn @deffn {Command} {flash padded_value} num value Sets the default value used for padding any image sections, This should normally match the flash bank erased value. If not specified by this command or the flash driver then it defaults to 0xff. @end deffn @anchor{program} @deffn {Command} {program} filename [preverify] [verify] [reset] [exit] [offset] This is a helper script that simplifies using OpenOCD as a standalone programmer. The only required parameter is @option{filename}, the others are optional. @xref{Flash Programming}. @end deffn @anchor{flashdriverlist} @section Flash Driver List As noted above, the @command{flash bank} command requires a driver name, and allows driver-specific options and behaviors. Some drivers also activate driver-specific commands. @deffn {Flash Driver} {virtual} This is a special driver that maps a previously defined bank to another address. All bank settings will be copied from the master physical bank. The @var{virtual} driver defines one mandatory parameters, @itemize @item @var{master_bank} The bank that this virtual address refers to. @end itemize So in the following example addresses 0xbfc00000 and 0x9fc00000 refer to the flash bank defined at address 0x1fc00000. Any command executed on the virtual banks is actually performed on the physical banks. @example flash bank $_FLASHNAME pic32mx 0x1fc00000 0 0 0 $_TARGETNAME flash bank vbank0 virtual 0xbfc00000 0 0 0 \ $_TARGETNAME $_FLASHNAME flash bank vbank1 virtual 0x9fc00000 0 0 0 \ $_TARGETNAME $_FLASHNAME @end example @end deffn @subsection External Flash @deffn {Flash Driver} {cfi} @cindex Common Flash Interface @cindex CFI The ``Common Flash Interface'' (CFI) is the main standard for external NOR flash chips, each of which connects to a specific external chip select on the CPU. Frequently the first such chip is used to boot the system. Your board's @code{reset-init} handler might need to configure additional chip selects using other commands (like: @command{mww} to configure a bus and its timings), or perhaps configure a GPIO pin that controls the ``write protect'' pin on the flash chip. The CFI driver can use a target-specific working area to significantly speed up operation. The CFI driver can accept the following optional parameters, in any order: @itemize @item @var{jedec_probe} ... is used to detect certain non-CFI flash ROMs, like AM29LV010 and similar types. @item @var{x16_as_x8} ... when a 16-bit flash is hooked up to an 8-bit bus. @item @var{bus_swap} ... when data bytes in a 16-bit flash needs to be swapped. @item @var{data_swap} ... when data bytes in a 16-bit flash needs to be swapped when writing data values (i.e. not CFI commands). @end itemize To configure two adjacent banks of 16 MBytes each, both sixteen bits (two bytes) wide on a sixteen bit bus: @example flash bank $_FLASHNAME cfi 0x00000000 0x01000000 2 2 $_TARGETNAME flash bank $_FLASHNAME cfi 0x01000000 0x01000000 2 2 $_TARGETNAME @end example To configure one bank of 32 MBytes built from two sixteen bit (two byte) wide parts wired in parallel to create a thirty-two bit (four byte) bus with doubled throughput: @example flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 $_TARGETNAME @end example @c "cfi part_id" disabled @end deffn @deffn {Flash Driver} {jtagspi} @cindex Generic JTAG2SPI driver @cindex SPI @cindex jtagspi @cindex bscan_spi Several FPGAs and CPLDs can retrieve their configuration (bitstream) from a SPI flash connected to them. To access this flash from the host, the device is first programmed with a special proxy bitstream that exposes the SPI flash on the device's JTAG interface. The flash can then be accessed through JTAG. Since signaling between JTAG and SPI is compatible, all that is required for a proxy bitstream is to connect TDI-MOSI, TDO-MISO, TCK-CLK and activate the flash chip select when the JTAG state machine is in SHIFT-DR. Such a bitstream for several Xilinx FPGAs can be found in @file{contrib/loaders/flash/fpga/xilinx_bscan_spi.py}. It requires @uref{https://github.com/m-labs/migen, migen} and a Xilinx toolchain to build. This flash bank driver requires a target on a JTAG tap and will access that tap directly. Since no support from the target is needed, the target can be a "testee" dummy. Since the target does not expose the flash memory mapping, target commands that would otherwise be expected to access the flash will not work. These include all @command{*_image} and @command{$target_name m*} commands as well as @command{program}. Equivalent functionality is available through the @command{flash write_bank}, @command{flash read_bank}, and @command{flash verify_bank} commands. According to device size, 1- to 4-byte addresses are sent. However, some flash chips additionally have to be switched to 4-byte addresses by an extra command, see below. @itemize @item @var{ir} ... is loaded into the JTAG IR to map the flash as the JTAG DR. For the bitstreams generated from @file{xilinx_bscan_spi.py} this is the @var{USER1} instruction. @end itemize @example target create $_TARGETNAME testee -chain-position $_CHIPNAME.fpga set _XILINX_USER1 0x02 flash bank $_FLASHNAME spi 0x0 0 0 0 \ $_TARGETNAME $_XILINX_USER1 @end example @deffn Command {jtagspi set} bank_id name total_size page_size read_cmd unused pprg_cmd mass_erase_cmd sector_size sector_erase_cmd Sets flash parameters: @var{name} human readable string, @var{total_size} size in bytes, @var{page_size} is write page size. @var{read_cmd} and @var{pprg_cmd} are commands for read and page program, respectively. @var{mass_erase_cmd}, @var{sector_size} and @var{sector_erase_cmd} are optional. @example jtagspi set 0 w25q128 0x1000000 0x100 0x03 0 0x02 0xC7 0x10000 0xD8 @end example @end deffn @deffn Command {jtagspi cmd} bank_id resp_num cmd_byte ... Sends command @var{cmd_byte} and at most 20 following bytes and reads @var{resp_num} bytes afterwards. E.g. for 'Enter 4-byte address mode' @example jtagspi cmd 0 0 0xB7 @end example @end deffn @deffn Command {jtagspi always_4byte} bank_id [ on | off ] Some devices use 4-byte addresses for all commands except the legacy 0x03 read regardless of device size. This command controls the corresponding hack. @end deffn @end deffn @deffn {Flash Driver} {xcf} @cindex Xilinx Platform flash driver @cindex xcf Xilinx FPGAs can be configured from specialized flash ICs named Platform Flash. It is (almost) regular NOR flash with erase sectors, program pages, etc. The only difference is special registers controlling its FPGA specific behavior. They must be properly configured for successful FPGA loading using additional @var{xcf} driver command: @deffn {Command} {xcf ccb} <bank_id> command accepts additional parameters: @itemize @item @var{external|internal} ... selects clock source. @item @var{serial|parallel} ... selects serial or parallel data bus mode. @item @var{slave|master} ... selects slave of master mode for flash device. @item @var{40|20} ... selects clock frequency in MHz for internal clock in master mode. @end itemize @example xcf ccb 0 external parallel slave 40 @end example All of them must be specified even if clock frequency is pointless in slave mode. If only bank id specified than command prints current CCB register value. Note: there is no need to write this register every time you erase/program data sectors because it stores in dedicated sector. @end deffn @deffn {Command} {xcf configure} <bank_id> Initiates FPGA loading procedure. Useful if your board has no "configure" button. @example xcf configure 0 @end example @end deffn Additional driver notes: @itemize @item Only single revision supported. @item Driver automatically detects need of bit reverse, but only "bin" (raw binary, do not confuse it with "bit") and "mcs" (Intel hex) file types supported. @item For additional info check xapp972.pdf and ug380.pdf. @end itemize @end deffn @deffn {Flash Driver} {lpcspifi} @cindex NXP SPI Flash Interface @cindex SPIFI @cindex lpcspifi NXP's LPC43xx and LPC18xx families include a proprietary SPI Flash Interface (SPIFI) peripheral that can drive and provide memory mapped access to external SPI flash devices. The lpcspifi driver initializes this interface and provides program and erase functionality for these serial flash devices. Use of this driver @b{requires} a working area of at least 1kB to be configured on the target device; more than this will significantly reduce flash programming times. The setup command only requires the @var{base} parameter. All other parameters are ignored, and the flash size and layout are configured by the driver. @example flash bank $_FLASHNAME lpcspifi 0x14000000 0 0 0 $_TARGETNAME @end example @end deffn @deffn {Flash Driver} {stmsmi} @cindex STMicroelectronics Serial Memory Interface @cindex SMI @cindex stmsmi Some devices from STMicroelectronics (e.g. STR75x MCU family, SPEAr MPU family) include a proprietary ``Serial Memory Interface'' (SMI) controller able to drive external SPI flash devices. Depending on specific device and board configuration, up to 4 external flash devices can be connected. SMI makes the flash content directly accessible in the CPU address space; each external device is mapped in a memory bank. CPU can directly read data, execute code and boot from SMI banks. Normal OpenOCD commands like @command{mdw} can be used to display the flash content. The setup command only requires the @var{base} parameter in order to identify the memory bank. All other parameters are ignored. Additional information, like flash size, are detected automatically. @example flash bank $_FLASHNAME stmsmi 0xf8000000 0 0 0 $_TARGETNAME @end example @end deffn @deffn {Flash Driver} {stmqspi} @cindex STMicroelectronics QuadSPI/OctoSPI Interface @cindex QuadSPI @cindex OctoSPI @cindex stmqspi Some devices from STMicroelectronics include a proprietary ``QuadSPI Interface'' (e.g. STM32F4, STM32F7, STM32L4) or ``OctoSPI Interface'' (e.g. STM32L4+) controller able to drive one or even two (dual mode) external SPI flash devices. The OctoSPI is a superset of QuadSPI, its presence is detected automatically. Currently only the regular command mode is supported, whereas the HyperFlash mode is not. QuadSPI/OctoSPI makes the flash contents directly accessible in the CPU address space; in case of dual mode both devices must be of the same type and are mapped in the same memory bank (even and odd addresses interleaved). CPU can directly read data, execute code (but not boot) from QuadSPI bank. The 'flash bank' command only requires the @var{base} parameter and the extra parameter @var{io_base} in order to identify the memory bank. Both are fixed by hardware, see datasheet or RM. All other parameters are ignored. The controller must be initialized after each reset and properly configured for memory-mapped read operation for the particular flash chip(s), for the full list of available register settings cf. the controller's RM. This setup is quite board specific (that's why booting from this memory is not possible). The flash driver infers all parameters from current controller register values when 'flash probe @var{bank_id}' is executed. Normal OpenOCD commands like @command{mdw} can be used to display the flash content, but only after proper controller initialization as described above. However, due to a silicon bug in some devices, attempting to access the very last word should be avoided. It is possible to use two (even different) flash chips alternatingly, if individual bank chip selects are available. For some package variants, this is not the case due to limited pin count. To switch from one to another, adjust FSEL bit accordingly and re-issue 'flash probe bank_id'. Note that the bank base address will @emph{not} change, so the address spaces of both devices will overlap. In dual flash mode both chips must be identical regarding size and most other properties. Block or sector protection internal to the flash chip is not handled by this driver at all, but can be dealt with manually by the 'cmd' command, see below. The sector protection via 'flash protect' command etc. is completely internal to openocd, intended only to prevent accidental erase or overwrite and it does not persist across openocd invocations. OpenOCD contains a hardcoded list of flash devices with their properties, these are auto-detected. If a device is not included in this list, SFDP discovery is attempted. If this fails or gives inappropriate results, manual setting is required (see 'set' command). @example flash bank $_FLASHNAME stmqspi 0x90000000 0 0 0 \ $_TARGETNAME 0xA0001000 flash bank $_FLASHNAME stmqspi 0x70000000 0 0 0 \ $_TARGETNAME 0xA0001400 @end example There are three specific commands @deffn {Command} {stmqspi mass_erase} bank_id Clears sector protections and performs a mass erase. Works only if there is no chip specific write protection engaged. @end deffn @deffn {Command} {stmqspi set} bank_id name total_size page_size read_cmd fread_cmd pprg_cmd mass_erase_cmd sector_size sector_erase_cmd Set flash parameters: @var{name} human readable string, @var{total_size} size in bytes, @var{page_size} is write page size. @var{read_cmd}, @var{fread_cmd} and @var{pprg_cmd} are commands for reading and page programming. @var{fread_cmd} is used in DPI and QPI modes, @var{read_cmd} in normal SPI (single line) mode. @var{mass_erase_cmd}, @var{sector_size} and @var{sector_erase_cmd} are optional. This command is required if chip id is not hardcoded yet and e.g. for EEPROMs or FRAMs which don't support an id command. In dual mode parameters of both chips are set identically. The parameters refer to a single chip, so the whole bank gets twice the specified capacity etc. @end deffn @deffn {Command} {stmqspi cmd} bank_id resp_num cmd_byte ... If @var{resp_num} is zero, sends command @var{cmd_byte} and following data bytes. In dual mode command byte is sent to @emph{both} chips but data bytes are sent @emph{alternatingly} to chip 1 and 2, first to flash 1, second to flash 2, etc., i.e. the total number of bytes (including cmd_byte) must be odd. If @var{resp_num} is not zero, cmd and at most four following data bytes are sent, in dual mode @emph{simultaneously} to both chips. Then @var{resp_num} bytes are read interleaved from both chips starting with chip 1. In this case @var{resp_num} must be even. Note the hardware dictated subtle difference of those two cases in dual-flash mode. To check basic communication settings, issue @example stmqspi cmd bank_id 0 0x04; stmqspi cmd bank_id 1 0x05 stmqspi cmd bank_id 0 0x06; stmqspi cmd bank_id 1 0x05 @end example for single flash mode or @example stmqspi cmd bank_id 0 0x04; stmqspi cmd bank_id 2 0x05 stmqspi cmd bank_id 0 0x06; stmqspi cmd bank_id 2 0x05 @end example for dual flash mode. This should return the status register contents. In 8-line mode, @var{cmd_byte} is sent twice - first time as given, second time complemented. Additionally, in 8-line mode only, some commands (e.g. Read Status) need a dummy address, e.g. @example stmqspi cmd bank_id 1 0x05 0x00 0x00 0x00 0x00 @end example should return the status register contents. @end deffn @end deffn @deffn {Flash Driver} {mrvlqspi} This driver supports QSPI flash controller of Marvell's Wireless Microcontroller platform. The flash size is autodetected based on the table of known JEDEC IDs hardcoded in the OpenOCD sources. @example flash bank $_FLASHNAME mrvlqspi 0x0 0 0 0 $_TARGETNAME 0x46010000 @end example @end deffn @deffn {Flash Driver} {ath79} @cindex Atheros ath79 SPI driver @cindex ath79 Members of ATH79 SoC family from Atheros include a SPI interface with 3 chip selects. On reset a SPI flash connected to the first chip select (CS0) is made directly read-accessible in the CPU address space (up to 16MBytes) and is usually used to store the bootloader and operating system. Normal OpenOCD commands like @command{mdw} can be used to display the flash content while it is in memory-mapped mode (only the first 4MBytes are accessible without additional configuration on reset). The setup command only requires the @var{base} parameter in order to identify the memory bank. The actual value for the base address is not otherwise used by the driver. However the mapping is passed to gdb. Thus for the memory mapped flash (chipselect CS0) the base address should be the actual memory mapped base address. For unmapped chipselects (CS1 and CS2) care should be taken to use a base address that does not overlap with real memory regions. Additional information, like flash size, are detected automatically. An optional additional parameter sets the chipselect for the bank, with the default CS0. CS1 and CS2 require additional GPIO setup before they can be used since the alternate function must be enabled on the GPIO pin CS1/CS2 is routed to on the given SoC. @example flash bank $_FLASHNAME ath79 0xbf000000 0 0 0 $_TARGETNAME # When using multiple chipselects the base should be different # for each, otherwise the write_image command is not able to # distinguish the banks. flash bank flash0 ath79 0xbf000000 0 0 0 $_TARGETNAME cs0 flash bank flash1 ath79 0x10000000 0 0 0 $_TARGETNAME cs1 flash bank flash2 ath79 0x20000000 0 0 0 $_TARGETNAME cs2 @end example @end deffn @deffn {Flash Driver} {fespi} @cindex Freedom E SPI @cindex fespi SiFive's Freedom E SPI controller, used in HiFive and other boards. @example flash bank $_FLASHNAME fespi 0x20000000 0 0 0 $_TARGETNAME @end example @end deffn @subsection Internal Flash (Microcontrollers) @deffn {Flash Driver} {aduc702x} The ADUC702x analog microcontrollers from Analog Devices include internal flash and use ARM7TDMI cores. The aduc702x flash driver works with models ADUC7019 through ADUC7028. The setup command only requires the @var{target} argument since all devices in this family have the same memory layout. @example flash bank $_FLASHNAME aduc702x 0 0 0 0 $_TARGETNAME @end example @end deffn @deffn {Flash Driver} {ambiqmicro} @cindex ambiqmicro @cindex apollo All members of the Apollo microcontroller family from Ambiq Micro include internal flash and use ARM's Cortex-M4 core. The host connects over USB to an FTDI interface that communicates with the target using SWD. The @var{ambiqmicro} driver reads the Chip Information Register detect the device class of the MCU. The Flash and SRAM sizes directly follow device class, and are used to set up the flash banks. If this fails, the driver will use default values set to the minimum sizes of an Apollo chip. All Apollo chips have two flash banks of the same size. In all cases the first flash bank starts at location 0, and the second bank starts after the first. @example # Flash bank 0 flash bank $_FLASHNAME ambiqmicro 0 0x00040000 0 0 $_TARGETNAME # Flash bank 1 - same size as bank0, starts after bank 0. flash bank $_FLASHNAME ambiqmicro 0x00040000 0x00040000 0 0 \ $_TARGETNAME @end example Flash is programmed using custom entry points into the bootloader. This is the only way to program the flash as no flash control registers are available to the user. The @var{ambiqmicro} driver adds some additional commands: @deffn {Command} {ambiqmicro mass_erase} <bank> Erase entire bank. @end deffn @deffn {Command} {ambiqmicro page_erase} <bank> <first> <last> Erase device pages. @end deffn @deffn {Command} {ambiqmicro program_otp} <bank> <offset> <count> Program OTP is a one time operation to create write protected flash. The user writes sectors to SRAM starting at 0x10000010. Program OTP will write these sectors from SRAM to flash, and write protect the flash. @end deffn @end deffn @deffn {Flash Driver} {at91samd} @cindex at91samd All members of the ATSAM D2x, D1x, D0x, ATSAMR, ATSAML and ATSAMC microcontroller families from Atmel include internal flash and use ARM's Cortex-M0+ core. Do not use for ATSAM D51 and E5x: use @xref{atsame5}. The devices have one flash bank: @example flash bank $_FLASHNAME at91samd 0x00000000 0 1 1 $_TARGETNAME @end example @deffn {Command} {at91samd chip-erase} Issues a complete Flash erase via the Device Service Unit (DSU). This can be used to erase a chip back to its factory state and does not require the processor to be halted. @end deffn @deffn {Command} {at91samd set-security} Secures the Flash via the Set Security Bit (SSB) command. This prevents access to the Flash and can only be undone by using the chip-erase command which erases the Flash contents and turns off the security bit. Warning: at this time, openocd will not be able to communicate with a secured chip and it is therefore not possible to chip-erase it without using another tool. @example at91samd set-security enable @end example @end deffn @deffn {Command} {at91samd eeprom} Shows or sets the EEPROM emulation size configuration, stored in the User Row of the Flash. When setting, the EEPROM size must be specified in bytes and it must be one of the permitted sizes according to the datasheet. Settings are written immediately but only take effect on MCU reset. EEPROM emulation requires additional firmware support and the minimum EEPROM size may not be the same as the minimum that the hardware supports. Set the EEPROM size to 0 in order to disable this feature. @example at91samd eeprom at91samd eeprom 1024 @end example @end deffn @deffn {Command} {at91samd bootloader} Shows or sets the bootloader size configuration, stored in the User Row of the Flash. This is called the BOOTPROT region. When setting, the bootloader size must be specified in bytes and it must be one of the permitted sizes according to the datasheet. Settings are written immediately but only take effect on MCU reset. Setting the bootloader size to 0 disables bootloader protection. @example at91samd bootloader at91samd bootloader 16384 @end example @end deffn @deffn {Command} {at91samd dsu_reset_deassert} This command releases internal reset held by DSU and prepares reset vector catch in case of reset halt. Command is used internally in event reset-deassert-post. @end deffn @deffn {Command} {at91samd nvmuserrow} Writes or reads the entire 64 bit wide NVM user row register which is located at 0x804000. This register includes various fuses lock-bits and factory calibration data. Reading the register is done by invoking this command without any arguments. Writing is possible by giving 1 or 2 hex values. The first argument is the register value to be written and the second one is an optional changemask. Every bit which value in changemask is 0 will stay unchanged. The lock- and reserved-bits are masked out and cannot be changed. @example # Read user row >at91samd nvmuserrow NVMUSERROW: 0xFFFFFC5DD8E0C788 # Write 0xFFFFFC5DD8E0C788 to user row >at91samd nvmuserrow 0xFFFFFC5DD8E0C788 # Write 0x12300 to user row but leave other bits and low # byte unchanged >at91samd nvmuserrow 0x12345 0xFFF00 @end example @end deffn @end deffn @anchor{at91sam3} @deffn {Flash Driver} {at91sam3} @cindex at91sam3 All members of the AT91SAM3 microcontroller family from Atmel include internal flash and use ARM's Cortex-M3 core. The driver currently (6/22/09) recognizes the AT91SAM3U[1/2/4][C/E] chips. Note that the driver was orginaly developed and tested using the AT91SAM3U4E, using a SAM3U-EK eval board. Support for other chips in the family was cribbed from the data sheet. @emph{Note to future readers/updaters: Please remove this worrisome comment after other chips are confirmed.} The AT91SAM3U4[E/C] (256K) chips have two flash banks; most other chips have one flash bank. In all cases the flash banks are at the following fixed locations: @example # Flash bank 0 - all chips flash bank $_FLASHNAME at91sam3 0x00080000 0 1 1 $_TARGETNAME # Flash bank 1 - only 256K chips flash bank $_FLASHNAME at91sam3 0x00100000 0 1 1 $_TARGETNAME @end example Internally, the AT91SAM3 flash memory is organized as follows. Unlike the AT91SAM7 chips, these are not used as parameters to the @command{flash bank} command: @itemize @item @emph{N-Banks:} 256K chips have 2 banks, others have 1 bank. @item @emph{Bank Size:} 128K/64K Per flash bank @item @emph{Sectors:} 16 or 8 per bank @item @emph{SectorSize:} 8K Per Sector @item @emph{PageSize:} 256 bytes per page. Note that OpenOCD operates on 'sector' sizes, not page sizes. @end itemize The AT91SAM3 driver adds some additional commands: @deffn {Command} {at91sam3 gpnvm} @deffnx {Command} {at91sam3 gpnvm clear} number @deffnx {Command} {at91sam3 gpnvm set} number @deffnx {Command} {at91sam3 gpnvm show} [@option{all}|number] With no parameters, @command{show} or @command{show all}, shows the status of all GPNVM bits. With @command{show} @var{number}, displays that bit. With @command{set} @var{number} or @command{clear} @var{number}, modifies that GPNVM bit. @end deffn @deffn {Command} {at91sam3 info} This command attempts to display information about the AT91SAM3 chip. @emph{First} it read the @code{CHIPID_CIDR} [address 0x400e0740, see Section 28.2.1, page 505 of the AT91SAM3U 29/may/2009 datasheet, document id: doc6430A] and decodes the values. @emph{Second} it reads the various clock configuration registers and attempts to display how it believes the chip is configured. By default, the SLOWCLK is assumed to be 32768 Hz, see the command @command{at91sam3 slowclk}. @end deffn @deffn {Command} {at91sam3 slowclk} [value] This command shows/sets the slow clock frequency used in the @command{at91sam3 info} command calculations above. @end deffn @end deffn @deffn {Flash Driver} {at91sam4} @cindex at91sam4 All members of the AT91SAM4 microcontroller family from Atmel include internal flash and use ARM's Cortex-M4 core. This driver uses the same command names/syntax as @xref{at91sam3}. @end deffn @deffn {Flash Driver} {at91sam4l} @cindex at91sam4l All members of the AT91SAM4L microcontroller family from Atmel include internal flash and use ARM's Cortex-M4 core. This driver uses the same command names/syntax as @xref{at91sam3}. The AT91SAM4L driver adds some additional commands: @deffn {Command} {at91sam4l smap_reset_deassert} This command releases internal reset held by SMAP and prepares reset vector catch in case of reset halt. Command is used internally in event reset-deassert-post. @end deffn @end deffn @anchor{atsame5} @deffn {Flash Driver} {atsame5} @cindex atsame5 All members of the SAM E54, E53, E51 and D51 microcontroller families from Microchip (former Atmel) include internal flash and use ARM's Cortex-M4 core. The devices have two ECC flash banks with a swapping feature. This driver handles both banks together as it were one. Bank swapping is not supported yet. @example flash bank $_FLASHNAME atsame5 0x00000000 0 1 1 $_TARGETNAME @end example @deffn {Command} {atsame5 bootloader} Shows or sets the bootloader size configuration, stored in the User Page of the Flash. This is called the BOOTPROT region. When setting, the bootloader size must be specified in bytes. The nearest bigger protection size is used. Settings are written immediately but only take effect on MCU reset. Setting the bootloader size to 0 disables bootloader protection. @example atsame5 bootloader atsame5 bootloader 16384 @end example @end deffn @deffn {Command} {atsame5 chip-erase} Issues a complete Flash erase via the Device Service Unit (DSU). This can be used to erase a chip back to its factory state and does not require the processor to be halted. @end deffn @deffn {Command} {atsame5 dsu_reset_deassert} This command releases internal reset held by DSU and prepares reset vector catch in case of reset halt. Command is used internally in event reset-deassert-post. @end deffn @deffn {Command} {atsame5 userpage} Writes or reads the first 64 bits of NVM User Page which is located at 0x804000. This field includes various fuses. Reading is done by invoking this command without any arguments. Writing is possible by giving 1 or 2 hex values. The first argument is the value to be written and the second one is an optional bit mask (a zero bit in the mask means the bit stays unchanged). The reserved fields are always masked out and cannot be changed. @example # Read >atsame5 userpage USER PAGE: 0xAEECFF80FE9A9239 # Write >atsame5 userpage 0xAEECFF80FE9A9239 # Write 2 to SEESBLK and 4 to SEEPSZ fields but leave other # bits unchanged (setup SmartEEPROM of virtual size 8192 # bytes) >atsame5 userpage 0x4200000000 0x7f00000000 @end example @end deffn @end deffn @deffn {Flash Driver} {atsamv} @cindex atsamv All members of the ATSAMV7x, ATSAMS70, and ATSAME70 families from Atmel include internal flash and use ARM's Cortex-M7 core. This driver uses the same command names/syntax as @xref{at91sam3}. @example flash bank $_FLASHNAME atsamv 0x00400000 0 0 0 $_TARGETNAME @end example @deffn {Command} {atsamv gpnvm} [@option{show} [@option{all}|number]] @deffnx {Command} {atsamv gpnvm} (@option{clr}|@option{set}) number With no parameters, @option{show} or @option{show all}, shows the status of all GPNVM bits. With @option{show} @var{number}, displays that bit. With @option{set} @var{number} or @option{clear} @var{number}, modifies that GPNVM bit. @end deffn @end deffn @deffn {Flash Driver} {at91sam7} All members of the AT91SAM7 microcontroller family from Atmel include internal flash and use ARM7TDMI cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @example flash bank $_FLASHNAME at91sam7 0 0 0 0 $_TARGETNAME @end example For chips which are not recognized by the controller driver, you must provide additional parameters in the following order: @itemize @item @var{chip_model} ... label used with @command{flash info} @item @var{banks} @item @var{sectors_per_bank} @item @var{pages_per_sector} @item @var{pages_size} @item @var{num_nvm_bits} @item @var{freq_khz} ... required if an external clock is provided, optional (but recommended) when the oscillator frequency is known @end itemize It is recommended that you provide zeroes for all of those values except the clock frequency, so that everything except that frequency will be autoconfigured. Knowing the frequency helps ensure correct timings for flash access. The flash controller handles erases automatically on a page (128/256 byte) basis, so explicit erase commands are not necessary for flash programming. However, there is an ``EraseAll`` command that can erase an entire flash plane (of up to 256KB), and it will be used automatically when you issue @command{flash erase_sector} or @command{flash erase_address} commands. @deffn {Command} {at91sam7 gpnvm} bitnum (@option{set}|@option{clear}) Set or clear a ``General Purpose Non-Volatile Memory'' (GPNVM) bit for the processor. Each processor has a number of such bits, used for controlling features such as brownout detection (so they are not truly general purpose). @quotation Note This assumes that the first flash bank (number 0) is associated with the appropriate at91sam7 target. @end quotation @end deffn @end deffn @deffn {Flash Driver} {avr} The AVR 8-bit microcontrollers from Atmel integrate flash memory. @emph{The current implementation is incomplete.} @comment - defines mass_erase ... pointless given flash_erase_address @end deffn @deffn {Flash Driver} {bluenrg-x} STMicroelectronics BlueNRG-1, BlueNRG-2 and BlueNRG-LP/LPS Bluetooth low energy wireless system-on-chip. They include ARM Cortex-M0/M0+ core and internal flash memory. The driver automatically recognizes these chips using the chip identification registers, and autoconfigures itself. @example flash bank $_FLASHNAME bluenrg-x 0 0 0 0 $_TARGETNAME @end example Note that when users ask to erase all the sectors of the flash, a mass erase command is used which is faster than erasing each single sector one by one. @example flash erase_sector 0 0 last # It will perform a mass erase @end example Triggering a mass erase is also useful when users want to disable readout protection. @end deffn @deffn {Flash Driver} {cc26xx} All versions of the SimpleLink CC13xx and CC26xx microcontrollers from Texas Instruments include internal flash. The cc26xx flash driver supports both the CC13xx and CC26xx family of devices. The driver automatically recognizes the specific version's flash parameters and autoconfigures itself. The flash bank starts at address 0. @example flash bank $_FLASHNAME cc26xx 0 0 0 0 $_TARGETNAME @end example @end deffn @deffn {Flash Driver} {cc3220sf} The CC3220SF version of the SimpleLink CC32xx microcontrollers from Texas Instruments includes 1MB of internal flash. The cc3220sf flash driver only supports the internal flash. The serial flash on SimpleLink boards is programmed via the bootloader over a UART connection. Security features of the CC3220SF may erase the internal flash during power on reset. Refer to documentation at @url{www.ti.com/cc3220sf} for details on security features and programming the serial flash. @example flash bank $_FLASHNAME cc3220sf 0 0 0 0 $_TARGETNAME @end example @end deffn @deffn {Flash Driver} {efm32} All members of the EFM32/EFR32 microcontroller family from Energy Micro (now Silicon Labs) include internal flash and use Arm Cortex-M3 or Cortex-M4 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @example flash bank $_FLASHNAME efm32 0 0 0 0 $_TARGETNAME @end example It supports writing to the user data page, as well as the portion of the lockbits page past 512 bytes on chips with larger page sizes. The latter is used by the SiLabs bootloader/AppLoader system for encryption keys. Setting protection on these pages is currently not supported. @example flash bank userdata.flash efm32 0x0FE00000 0 0 0 $_TARGETNAME flash bank lockbits.flash efm32 0x0FE04000 0 0 0 $_TARGETNAME @end example A special feature of efm32 controllers is that it is possible to completely disable the debug interface by writing the correct values to the 'Debug Lock Word'. OpenOCD supports this via the following command: @example efm32 debuglock num @end example The @var{num} parameter is a value shown by @command{flash banks}. Note that in order for this command to take effect, the target needs to be reset. @emph{The current implementation is incomplete. Unprotecting flash pages is not supported.} @end deffn @deffn {Flash Driver} {esirisc} Members of the eSi-RISC family may optionally include internal flash programmed via the eSi-TSMC Flash interface. Additional parameters are required to configure the driver: @option{cfg_address} is the base address of the configuration register interface, @option{clock_hz} is the expected clock frequency, and @option{wait_states} is the number of configured read wait states. @example flash bank $_FLASHNAME esirisc base_address size_bytes 0 0 \ $_TARGETNAME cfg_address clock_hz wait_states @end example @deffn {Command} {esirisc flash mass_erase} bank_id Erase all pages in data memory for the bank identified by @option{bank_id}. @end deffn @deffn {Command} {esirisc flash ref_erase} bank_id Erase the reference cell for the bank identified by @option{bank_id}. @emph{This is an uncommon operation.} @end deffn @end deffn @deffn {Flash Driver} {fm3} All members of the FM3 microcontroller family from Fujitsu include internal flash and use ARM Cortex-M3 cores. The @var{fm3} driver uses the @var{target} parameter to select the correct bank config, it can currently be one of the following: @code{mb9bfxx1.cpu}, @code{mb9bfxx2.cpu}, @code{mb9bfxx3.cpu}, @code{mb9bfxx4.cpu}, @code{mb9bfxx5.cpu} or @code{mb9bfxx6.cpu}. @example flash bank $_FLASHNAME fm3 0 0 0 0 $_TARGETNAME @end example @end deffn @deffn {Flash Driver} {fm4} All members of the FM4 microcontroller family from Spansion (formerly Fujitsu) include internal flash and use ARM Cortex-M4 cores. The @var{fm4} driver uses a @var{family} parameter to select the correct bank config, it can currently be one of the following: @code{MB9BFx64}, @code{MB9BFx65}, @code{MB9BFx66}, @code{MB9BFx67}, @code{MB9BFx68}, @code{S6E2Cx8}, @code{S6E2Cx9}, @code{S6E2CxA} or @code{S6E2Dx}, with @code{x} treated as wildcard and otherwise case (and any trailing characters) ignored. @example flash bank $@{_FLASHNAME@}0 fm4 0x00000000 0 0 0 \ $_TARGETNAME S6E2CCAJ0A flash bank $@{_FLASHNAME@}1 fm4 0x00100000 0 0 0 \ $_TARGETNAME S6E2CCAJ0A @end example @emph{The current implementation is incomplete. Protection is not supported, nor is Chip Erase (only Sector Erase is implemented).} @end deffn @deffn {Flash Driver} {kinetis} @cindex kinetis Kx, KLx, KVx and KE1x members of the Kinetis microcontroller family from NXP (former Freescale) include internal flash and use ARM Cortex-M0+ or M4 cores. The driver automatically recognizes flash size and a number of flash banks (1-4) using the chip identification register, and autoconfigures itself. Use kinetis_ke driver for KE0x and KEAx devices. The @var{kinetis} driver defines option: @itemize @item -sim-base @var{addr} ... base of System Integration Module where chip identification resides. Driver tries two known locations if option is omitted. @end itemize @example flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME @end example @deffn {Config Command} {kinetis create_banks} Configuration command enables automatic creation of additional flash banks based on real flash layout of device. Banks are created during device probe. Use 'flash probe 0' to force probe. @end deffn @deffn {Command} {kinetis fcf_source} [protection|write] Select what source is used when writing to a Flash Configuration Field. @option{protection} mode builds FCF content from protection bits previously set by 'flash protect' command. This mode is default. MCU is protected from unwanted locking by immediate writing FCF after erase of relevant sector. @option{write} mode enables direct write to FCF. Protection cannot be set by 'flash protect' command. FCF is written along with the rest of a flash image. @emph{BEWARE: Incorrect flash configuration may permanently lock the device!} @end deffn @deffn {Command} {kinetis fopt} [num] Set value to write to FOPT byte of Flash Configuration Field. Used in kinetis 'fcf_source protection' mode only. @end deffn @deffn {Command} {kinetis mdm check_security} Checks status of device security lock. Used internally in examine-end and examine-fail event. @end deffn @deffn {Command} {kinetis mdm halt} Issues a halt via the MDM-AP. This command can be used to break a watchdog reset loop when connecting to an unsecured target. @end deffn @deffn {Command} {kinetis mdm mass_erase} Issues a complete flash erase via the MDM-AP. This can be used to erase a chip back to its factory state, removing security. It does not require the processor to be halted, however the target will remain in a halted state after this command completes. @end deffn @deffn {Command} {kinetis nvm_partition} For FlexNVM devices only (KxxDX and KxxFX). Command shows or sets data flash or EEPROM backup size in kilobytes, sets two EEPROM blocks sizes in bytes and enables/disables loading of EEPROM contents to FlexRAM during reset. For details see device reference manual, Flash Memory Module, Program Partition command. Setting is possible only once after mass_erase. Reset the device after partition setting. Show partition size: @example kinetis nvm_partition info @end example Set 32 KB data flash, rest of FlexNVM is EEPROM backup. EEPROM has two blocks of 512 and 1536 bytes and its contents is loaded to FlexRAM during reset: @example kinetis nvm_partition dataflash 32 512 1536 on @end example Set 16 KB EEPROM backup, rest of FlexNVM is a data flash. EEPROM has two blocks of 1024 bytes and its contents is not loaded to FlexRAM during reset: @example kinetis nvm_partition eebkp 16 1024 1024 off @end example @end deffn @deffn {Command} {kinetis mdm reset} Issues a reset via the MDM-AP. This causes the MCU to output a low pulse on the RESET pin, which can be used to reset other hardware on board. @end deffn @deffn {Command} {kinetis disable_wdog} For Kx devices only (KLx has different COP watchdog, it is not supported). Command disables watchdog timer. @end deffn @end deffn @deffn {Flash Driver} {kinetis_ke} @cindex kinetis_ke KE0x and KEAx members of the Kinetis microcontroller family from NXP include internal flash and use ARM Cortex-M0+. The driver automatically recognizes the KE0x sub-family using the chip identification register, and autoconfigures itself. Use kinetis (not kinetis_ke) driver for KE1x devices. @example flash bank $_FLASHNAME kinetis_ke 0 0 0 0 $_TARGETNAME @end example @deffn {Command} {kinetis_ke mdm check_security} Checks status of device security lock. Used internally in examine-end event. @end deffn @deffn {Command} {kinetis_ke mdm mass_erase} Issues a complete Flash erase via the MDM-AP. This can be used to erase a chip back to its factory state. Command removes security lock from a device (use of SRST highly recommended). It does not require the processor to be halted. @end deffn @deffn {Command} {kinetis_ke disable_wdog} Command disables watchdog timer. @end deffn @end deffn @deffn {Flash Driver} {lpc2000} This is the driver to support internal flash of all members of the LPC11(x)00 and LPC1300 microcontroller families and most members of the LPC800, LPC1500, LPC1700, LPC1800, LPC2000, LPC4000, LPC54100, LPC8Nxx and NHS31xx microcontroller families from NXP. @quotation Note There are LPC2000 devices which are not supported by the @var{lpc2000} driver: The LPC2888 is supported by the @var{lpc288x} driver. The LPC29xx family is supported by the @var{lpc2900} driver. @end quotation The @var{lpc2000} driver defines two mandatory and two optional parameters, which must appear in the following order: @itemize @item @var{variant} ... required, may be @option{lpc2000_v1} (older LPC21xx and LPC22xx) @option{lpc2000_v2} (LPC213x, LPC214x, LPC210[123], LPC23xx and LPC24xx) @option{lpc1700} (LPC175x and LPC176x and LPC177x/8x) @option{lpc4300} - available also as @option{lpc1800} alias (LPC18x[2357] and LPC43x[2357]) @option{lpc800} (LPC8xx) @option{lpc1100} (LPC11(x)xx and LPC13xx) @option{lpc1500} (LPC15xx) @option{lpc54100} (LPC541xx) @option{lpc4000} (LPC40xx) or @option{auto} - automatically detects flash variant and size for LPC11(x)00, LPC8xx, LPC13xx, LPC17xx, LPC40xx, LPC8Nxx and NHS31xx @item @var{clock_kHz} ... the frequency, in kiloHertz, at which the core is running @item @option{calc_checksum} ... optional (but you probably want to provide this!), telling the driver to calculate a valid checksum for the exception vector table. @quotation Note If you don't provide @option{calc_checksum} when you're writing the vector table, the boot ROM will almost certainly ignore your flash image. However, if you do provide it, with most tool chains @command{verify_image} will fail. @end quotation @item @option{iap_entry} ... optional telling the driver to use a different ROM IAP entry point. @end itemize LPC flashes don't require the chip and bus width to be specified. @example flash bank $_FLASHNAME lpc2000 0x0 0x7d000 0 0 $_TARGETNAME \ lpc2000_v2 14765 calc_checksum @end example @deffn {Command} {lpc2000 part_id} bank Displays the four byte part identifier associated with the specified flash @var{bank}. @end deffn @end deffn @deffn {Flash Driver} {lpc288x} The LPC2888 microcontroller from NXP needs slightly different flash support from its lpc2000 siblings. The @var{lpc288x} driver defines one mandatory parameter, the programming clock rate in Hz. LPC flashes don't require the chip and bus width to be specified. @example flash bank $_FLASHNAME lpc288x 0 0 0 0 $_TARGETNAME 12000000 @end example @end deffn @deffn {Flash Driver} {lpc2900} This driver supports the LPC29xx ARM968E based microcontroller family from NXP. The predefined parameters @var{base}, @var{size}, @var{chip_width} and @var{bus_width} of the @code{flash bank} command are ignored. Flash size and sector layout are auto-configured by the driver. The driver has one additional mandatory parameter: The CPU clock rate (in kHz) at the time the flash operations will take place. Most of the time this will not be the crystal frequency, but a higher PLL frequency. The @code{reset-init} event handler in the board script is usually the place where you start the PLL. The driver rejects flashless devices (currently the LPC2930). The EEPROM in LPC2900 devices is not mapped directly into the address space. It must be handled much more like NAND flash memory, and will therefore be handled by a separate @code{lpc2900_eeprom} driver (not yet available). Sector protection in terms of the LPC2900 is handled transparently. Every time a sector needs to be erased or programmed, it is automatically unprotected. What is shown as protection status in the @code{flash info} command, is actually the LPC2900 @emph{sector security}. This is a mechanism to prevent a sector from ever being erased or programmed again. As this is an irreversible mechanism, it is handled by a special command (@code{lpc2900 secure_sector}), and not by the standard @code{flash protect} command. Example for a 125 MHz clock frequency: @example flash bank $_FLASHNAME lpc2900 0 0 0 0 $_TARGETNAME 125000 @end example Some @code{lpc2900}-specific commands are defined. In the following command list, the @var{bank} parameter is the bank number as obtained by the @code{flash banks} command. @deffn {Command} {lpc2900 signature} bank Calculates a 128-bit hash value, the @emph{signature}, from the whole flash content. This is a hardware feature of the flash block, hence the calculation is very fast. You may use this to verify the content of a programmed device against a known signature. Example: @example lpc2900 signature 0 signature: 0x5f40cdc8:0xc64e592e:0x10490f89:0x32a0f317 @end example @end deffn @deffn {Command} {lpc2900 read_custom} bank filename Reads the 912 bytes of customer information from the flash index sector, and saves it to a file in binary format. Example: @example lpc2900 read_custom 0 /path_to/customer_info.bin @end example @end deffn The index sector of the flash is a @emph{write-only} sector. It cannot be erased! In order to guard against unintentional write access, all following commands need to be preceded by a successful call to the @code{password} command: @deffn {Command} {lpc2900 password} bank password You need to use this command right before each of the following commands: @code{lpc2900 write_custom}, @code{lpc2900 secure_sector}, @code{lpc2900 secure_jtag}. The password string is fixed to "I_know_what_I_am_doing". Example: @example lpc2900 password 0 I_know_what_I_am_doing Potentially dangerous operation allowed in next command! @end example @end deffn @deffn {Command} {lpc2900 write_custom} bank filename type Writes the content of the file into the customer info space of the flash index sector. The filetype can be specified with the @var{type} field. Possible values for @var{type} are: @var{bin} (binary), @var{ihex} (Intel hex format), @var{elf} (ELF binary) or @var{s19} (Motorola S-records). The file must contain a single section, and the contained data length must be exactly 912 bytes. @quotation Attention This cannot be reverted! Be careful! @end quotation Example: @example lpc2900 write_custom 0 /path_to/customer_info.bin bin @end example @end deffn @deffn {Command} {lpc2900 secure_sector} bank first last Secures the sector range from @var{first} to @var{last} (including) against further program and erase operations. The sector security will be effective after the next power cycle. @quotation Attention This cannot be reverted! Be careful! @end quotation Secured sectors appear as @emph{protected} in the @code{flash info} command. Example: @example lpc2900 secure_sector 0 1 1 flash info 0 #0 : lpc2900 at 0x20000000, size 0x000c0000, (...) # 0: 0x00000000 (0x2000 8kB) not protected # 1: 0x00002000 (0x2000 8kB) protected # 2: 0x00004000 (0x2000 8kB) not protected @end example @end deffn @deffn {Command} {lpc2900 secure_jtag} bank Irreversibly disable the JTAG port. The new JTAG security setting will be effective after the next power cycle. @quotation Attention This cannot be reverted! Be careful! @end quotation Examples: @example lpc2900 secure_jtag 0 @end example @end deffn @end deffn @deffn {Flash Driver} {mdr} This drivers handles the integrated NOR flash on Milandr Cortex-M based controllers. A known limitation is that the Info memory can't be read or verified as it's not memory mapped. @example flash bank <name> mdr <base> <size> \ 0 0 <target#> @var{type} @var{page_count} @var{sec_count} @end example @itemize @bullet @item @var{type} - 0 for main memory, 1 for info memory @item @var{page_count} - total number of pages @item @var{sec_count} - number of sector per page count @end itemize Example usage: @example if @{ [info exists IMEMORY] && [string equal $IMEMORY true] @} @{ flash bank $@{_CHIPNAME@}_info.flash mdr 0x00000000 0x01000 \ 0 0 $_TARGETNAME 1 1 4 @} else @{ flash bank $_CHIPNAME.flash mdr 0x00000000 0x20000 \ 0 0 $_TARGETNAME 0 32 4 @} @end example @end deffn @deffn {Flash Driver} {msp432} All versions of the SimpleLink MSP432 microcontrollers from Texas Instruments include internal flash. The msp432 flash driver automatically recognizes the specific version's flash parameters and autoconfigures itself. Main program flash starts at address 0. The information flash region on MSP432P4 versions starts at address 0x200000. @example flash bank $_FLASHNAME msp432 0 0 0 0 $_TARGETNAME @end example @deffn {Command} {msp432 mass_erase} bank_id [main|all] Performs a complete erase of flash. By default, @command{mass_erase} will erase only the main program flash. On MSP432P4 versions, using @command{mass_erase all} will erase both the main program and information flash regions. To also erase the BSL in information flash, the user must first use the @command{bsl} command. @end deffn @deffn {Command} {msp432 bsl} bank_id [unlock|lock] On MSP432P4 versions, @command{bsl} unlocks and locks the bootstrap loader (BSL) region in information flash so that flash commands can erase or write the BSL. Leave the BSL locked to prevent accidentally corrupting the bootstrap loader. To erase and program the BSL: @example msp432 bsl unlock flash erase_address 0x202000 0x2000 flash write_image bsl.bin 0x202000 msp432 bsl lock @end example @end deffn @end deffn @deffn {Flash Driver} {niietcm4} This drivers handles the integrated NOR flash on NIIET Cortex-M4 based controllers. Flash size and sector layout are auto-configured by the driver. Main flash memory is called "Bootflash" and has main region and info region. Info region is NOT memory mapped by default, but it can replace first part of main region if needed. Full erase, single and block writes are supported for both main and info regions. There is additional not memory mapped flash called "Userflash", which also have division into regions: main and info. Purpose of userflash - to store system and user settings. Driver has special commands to perform operations with this memory. @example flash bank $_FLASHNAME niietcm4 0 0 0 0 $_TARGETNAME @end example Some niietcm4-specific commands are defined: @deffn {Command} {niietcm4 uflash_read_byte} bank ('main'|'info') address Read byte from main or info userflash region. @end deffn @deffn {Command} {niietcm4 uflash_write_byte} bank ('main'|'info') address value Write byte to main or info userflash region. @end deffn @deffn {Command} {niietcm4 uflash_full_erase} bank Erase all userflash including info region. @end deffn @deffn {Command} {niietcm4 uflash_erase} bank ('main'|'info') first_sector last_sector Erase sectors of main or info userflash region, starting at sector first up to and including last. @end deffn @deffn {Command} {niietcm4 uflash_protect_check} bank ('main'|'info') Check sectors protect. @end deffn @deffn {Command} {niietcm4 uflash_protect} bank ('main'|'info') first_sector last_sector ('on'|'off') Protect sectors of main or info userflash region, starting at sector first up to and including last. @end deffn @deffn {Command} {niietcm4 bflash_info_remap} bank ('on'|'off') Enable remapping bootflash info region to 0x00000000 (or 0x40000000 if external memory boot used). @end deffn @deffn {Command} {niietcm4 extmem_cfg} bank ('gpioa'|'gpiob'|'gpioc'|'gpiod'|'gpioe'|'gpiof'|'gpiog'|'gpioh') pin_num ('func1'|'func3') Configure external memory interface for boot. @end deffn @deffn {Command} {niietcm4 service_mode_erase} bank Perform emergency erase of all flash (bootflash and userflash). @end deffn @deffn {Command} {niietcm4 driver_info} bank Show information about flash driver. @end deffn @end deffn @deffn {Flash Driver} {npcx} All versions of the NPCX microcontroller families from Nuvoton include internal flash. The NPCX flash driver supports the NPCX family of devices. The driver automatically recognizes the specific version's flash parameters and autoconfigures itself. The flash bank starts at address 0x64000000. @example flash bank $_FLASHNAME npcx 0x64000000 0 0 0 $_TARGETNAME @end example @end deffn @deffn {Flash Driver} {nrf5} All members of the nRF51 microcontroller families from Nordic Semiconductor include internal flash and use ARM Cortex-M0 core. nRF52 family powered by ARM Cortex-M4 or M4F core is supported too. nRF52832 is fully supported including BPROT flash protection scheme. nRF52833 and nRF52840 devices are supported with the exception of security extensions (flash access control list - ACL). @example flash bank $_FLASHNAME nrf5 0 0x00000000 0 0 $_TARGETNAME @end example Some nrf5-specific commands are defined: @deffn {Command} {nrf5 mass_erase} Erases the contents of the code memory and user information configuration registers as well. It must be noted that this command works only for chips that do not have factory pre-programmed region 0 code. @end deffn @deffn {Command} {nrf5 info} Decodes and shows information from FICR and UICR registers. @end deffn @end deffn @deffn {Flash Driver} {ocl} This driver is an implementation of the ``on chip flash loader'' protocol proposed by Pavel Chromy. It is a minimalistic command-response protocol intended to be used over a DCC when communicating with an internal or external flash loader running from RAM. An example implementation for AT91SAM7x is available in @file{contrib/loaders/flash/at91sam7x/}. @example flash bank $_FLASHNAME ocl 0 0 0 0 $_TARGETNAME @end example @end deffn @deffn {Flash Driver} {pic32mx} The PIC32MX microcontrollers are based on the MIPS 4K cores, and integrate flash memory. @example flash bank $_FLASHNAME pix32mx 0x1fc00000 0 0 0 $_TARGETNAME flash bank $_FLASHNAME pix32mx 0x1d000000 0 0 0 $_TARGETNAME @end example @comment numerous *disabled* commands are defined: @comment - chip_erase ... pointless given flash_erase_address @comment - lock, unlock ... pointless given protect on/off (yes?) @comment - pgm_word ... shouldn't bank be deduced from address?? Some pic32mx-specific commands are defined: @deffn {Command} {pic32mx pgm_word} address value bank Programs the specified 32-bit @var{value} at the given @var{address} in the specified chip @var{bank}. @end deffn @deffn {Command} {pic32mx unlock} bank Unlock and erase specified chip @var{bank}. This will remove any Code Protection. @end deffn @end deffn @deffn {Flash Driver} {psoc4} All members of the PSoC 41xx/42xx microcontroller family from Cypress include internal flash and use ARM Cortex-M0 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. Note: Erased internal flash reads as 00. System ROM of PSoC 4 does not implement erase of a flash sector. @example flash bank $_FLASHNAME psoc4 0 0 0 0 $_TARGETNAME @end example psoc4-specific commands @deffn {Command} {psoc4 flash_autoerase} num (on|off) Enables or disables autoerase mode for a flash bank. If flash_autoerase is off, use mass_erase before flash programming. Flash erase command fails if region to erase is not whole flash memory. If flash_autoerase is on, a sector is both erased and programmed in one system ROM call. Flash erase command is ignored. This mode is suitable for gdb load. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {psoc4 mass_erase} num Erases the contents of the flash memory, protection and security lock. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn @deffn {Flash Driver} {psoc5lp} All members of the PSoC 5LP microcontroller family from Cypress include internal program flash and use ARM Cortex-M3 cores. The driver probes for a number of these chips and autoconfigures itself, apart from the base address. @example flash bank $_FLASHNAME psoc5lp 0x00000000 0 0 0 $_TARGETNAME @end example @b{Note:} PSoC 5LP chips can be configured to have ECC enabled or disabled. @quotation Attention If flash operations are performed in ECC-disabled mode, they will also affect the ECC flash region. Erasing a 16k flash sector in the 0x00000000 area will then also erase the corresponding 2k data bytes in the 0x48000000 area. Writing to the ECC data bytes in ECC-disabled mode is not implemented. @end quotation Commands defined in the @var{psoc5lp} driver: @deffn {Command} {psoc5lp mass_erase} Erases all flash data and ECC/configuration bytes, all flash protection rows, and all row latches in all flash arrays on the device. @end deffn @end deffn @deffn {Flash Driver} {psoc5lp_eeprom} All members of the PSoC 5LP microcontroller family from Cypress include internal EEPROM and use ARM Cortex-M3 cores. The driver probes for a number of these chips and autoconfigures itself, apart from the base address. @example flash bank $_CHIPNAME.eeprom psoc5lp_eeprom 0x40008000 0 0 0 \ $_TARGETNAME @end example @end deffn @deffn {Flash Driver} {psoc5lp_nvl} All members of the PSoC 5LP microcontroller family from Cypress include internal Nonvolatile Latches and use ARM Cortex-M3 cores. The driver probes for a number of these chips and autoconfigures itself. @example flash bank $_CHIPNAME.nvl psoc5lp_nvl 0 0 0 0 $_TARGETNAME @end example PSoC 5LP chips have multiple NV Latches: @itemize @item Device Configuration NV Latch - 4 bytes @item Write Once (WO) NV Latch - 4 bytes @end itemize @b{Note:} This driver only implements the Device Configuration NVL. The @var{psoc5lp} driver reads the ECC mode from Device Configuration NVL. @quotation Attention Switching ECC mode via write to Device Configuration NVL will require a reset after successful write. @end quotation @end deffn @deffn {Flash Driver} {psoc6} Supports PSoC6 (CY8C6xxx) family of Cypress microcontrollers. PSoC6 is a dual-core device with CM0+ and CM4 cores. Both cores share the same Flash/RAM/MMIO address space. Flash in PSoC6 is split into three regions: @itemize @bullet @item Main Flash - this is the main storage for user application. Total size varies among devices, sector size: 256 kBytes, row size: 512 bytes. Supports erase operation on individual rows. @item Work Flash - intended to be used as storage for user data (e.g. EEPROM emulation). Total size: 32 KBytes, sector size: 32 KBytes, row size: 512 bytes. @item Supervisory Flash - special region which contains device-specific service data. This region does not support erase operation. Only few rows can be programmed by the user, most of the rows are read only. Programming operation will erase row automatically. @end itemize All three flash regions are supported by the driver. Flash geometry is detected automatically by parsing data in SPCIF_GEOMETRY register. PSoC6 is equipped with NOR Flash so erased Flash reads as 0x00. @example flash bank main_flash_cm0 psoc6 0x10000000 0 0 0 \ $@{TARGET@}.cm0 flash bank work_flash_cm0 psoc6 0x14000000 0 0 0 \ $@{TARGET@}.cm0 flash bank super_flash_user_cm0 psoc6 0x16000800 0 0 0 \ $@{TARGET@}.cm0 flash bank super_flash_nar_cm0 psoc6 0x16001A00 0 0 0 \ $@{TARGET@}.cm0 flash bank super_flash_key_cm0 psoc6 0x16005A00 0 0 0 \ $@{TARGET@}.cm0 flash bank super_flash_toc2_cm0 psoc6 0x16007C00 0 0 0 \ $@{TARGET@}.cm0 flash bank main_flash_cm4 psoc6 0x10000000 0 0 0 \ $@{TARGET@}.cm4 flash bank work_flash_cm4 psoc6 0x14000000 0 0 0 \ $@{TARGET@}.cm4 flash bank super_flash_user_cm4 psoc6 0x16000800 0 0 0 \ $@{TARGET@}.cm4 flash bank super_flash_nar_cm4 psoc6 0x16001A00 0 0 0 \ $@{TARGET@}.cm4 flash bank super_flash_key_cm4 psoc6 0x16005A00 0 0 0 \ $@{TARGET@}.cm4 flash bank super_flash_toc2_cm4 psoc6 0x16007C00 0 0 0 \ $@{TARGET@}.cm4 @end example psoc6-specific commands @deffn {Command} {psoc6 reset_halt} Command can be used to simulate broken Vector Catch from gdbinit or tcl scripts. When invoked for CM0+ target, it will set break point at application entry point and issue SYSRESETREQ. This will reset both cores and all peripherals. CM0+ will reset CM4 during boot anyway so this is safe. On CM4 target, VECTRESET is used instead of SYSRESETREQ to avoid unwanted reset of CM0+; @end deffn @deffn {Command} {psoc6 mass_erase} num Erases the contents given flash bank. The @var{num} parameter is a value shown by @command{flash banks}. Note: only Main and Work flash regions support Erase operation. @end deffn @end deffn @deffn {Flash Driver} {qn908x} The NXP QN908x microcontrollers feature a Cortex-M4F with integrated Bluetooth LE 5 support and an internal flash of up to 512 KiB. These chips only support the SWD interface. The @var{qn908x} driver uses the internal "Flash Memory Controller" block via SWD to erase, program and read the internal flash. This driver does not support the ISP (In-System Programming) mode which is an alternate way to program the flash via UART, SPI or USB. The internal flash is 512 KiB in size in all released chips and it starts at the address 0x01000000, although it can be mapped to address 0 and it is aliased to other addresses. This driver only recognizes the bank starting at address 0x01000000. The internal bootloader stored in ROM is in charge of loading and verifying the image from flash, or enter ISP mode. The programmed image must start at the beginning of the flash and contain a valid header and a matching CRC32 checksum. Additionally, the image header contains a "Code Read Protection" (CRP) word which indicates whether SWD access is enabled, as well as whether ISP mode is enabled. Therefore, it is possible to program an image that disables SWD and ISP making it impossible to program another image in the future through these interfaces, or even debug the current image. While this is a valid use case for production deployments where the chips are locked down, by default this driver doesn't allow such images that disable the SWD interface. To program such images see the @command{qn908x allow_brick} command. Apart from the CRP field which is located in the image header, the last page of the flash memory contains a "Flash lock and protect" descriptor which allows to individually protect each 2 KiB page, as well as disabling SWD access to the flash and RAM. If this access is disabled it is not possible to read, erase or program individual pages from the SWD interface or even access the read-only "Flash information page" with information about the bootloader version and flash size. However when this protection is in place, it is still possible to mass erase the whole chip and then program a new image, for which you can use the @command{qn908x mass_erase}. Example: @example flash bank $FLASHNAME qn908x 0x01000000 0 0 0 $TARGETNAME calc_checksum @end example Parameters: @itemize @item @option{calc_checksum} optional parameter to compute the required checksum of the first bytes in the vector table. @quotation Note If the checksum in the header of your image is invalid and you don't provide the @option{calc_checksum} option the boot ROM will not boot your image and it may render the flash inaccessible. On the other hand, if you use this option to compute the checksum keep in mind that @command{verify_image} will fail on those four bytes of the checksum since those bytes in the flash will have the updated checksum. @end quotation @end itemize @deffn {Command} {qn908x allow_brick} Allow the qn908x driver to program images with a "Code Read Protection" byte that disables the SWD access. Programming such image will cause OpenOCD to not be able to reach the target over SWD anymore after the new image is programmed and its configuration takes effect, e.g. after a reboot. After executing @command{qn908x allow_brick} these images will be allowed to be programmed when writing to the flash. @end deffn @deffn {Command} {qn908x disable_wdog} Disable the watchdog timer (WDT) by resetting its CTRL field. The WDT starts enabled after a @command{reset halt} and it doesn't run while the target is halted. However, the verification process in this driver uses the generic Cortex-M verification process which executes a payload in RAM and thus requires the watchdog to be disabled before running @command{verify_image} after a reset halt or any other condition where the watchdog is running. Note that this is not done automatically and you must run this command in those scenarios. @end deffn @deffn {Command} {qn908x mass_erase} Erases the complete flash using the mass_erase method. Mass erase is only allowed if enabled in the Lock Status Register 8 (LOCK_STAT_8) which is read from the last sector of the flash on boot. However, this mass_erase lock protection can be bypassed and this command does so automatically. In the same LOCK_STAT_8 the flash and RAM access from SWD can be disabled by setting two bits in this register. After a mass_erase, all the bits of the flash would be set, making it the default to restrict SWD access to the flash and RAM regions. This new after erase LOCK_STAT_8 value only takes effect after being read from flash on the next reboot for example. After a mass_erase the LOCK_STAT_8 register is changed by the hardware to allow access to flash and RAM regardless of the value on flash, but only right after a mass_erase and until the next boot. Therefore it is possible to perform a mass_erase, program a new image, verify it and then reboot to a valid image that's locked from the SWD access. The @command{qn908x mass_erase} command clears the bits that would be loaded from the flash into LOCK_STAT_8 after erasing the whole chip to allow SWD access for debugging or re-flashing an image without a mass_erase by default. If the image being programmed also programs the last page of the flash with its own settings, this mass_erase behavior will interfere with that write since a new erase of at least the last page would need to be performed before writing to it again. For this reason the optional @option{keep_lock} argument can be used to leave the flash and RAM lock set. For development environments, the default behavior is desired. The mass erase locking mechanism is independent from the individual page locking bits, so it is possible that you can't erase a given page that is locked and you can't unprotect that page because the locking bits are also locked, but can still mass erase the whole flash. @end deffn @end deffn @deffn {Flash Driver} {rp2040} Supports RP2040 "Raspberry Pi Pico" microcontroller. RP2040 is a dual-core device with two CM0+ cores. Both cores share the same Flash/RAM/MMIO address space. Non-volatile storage is achieved with an external QSPI flash; a Boot ROM provides helper functions. @example flash bank $_FLASHNAME rp2040_flash $_FLASHBASE $_FLASHSIZE 1 32 $_TARGETNAME @end example @end deffn @deffn {Flash Driver} {rsl10} Supports Onsemi RSL10 microcontroller flash memory. Uses functions stored in ROM to control flash memory interface. @example flash bank $_FLASHNAME rsl10 $_FLASHBASE $_FLASHSIZE 0 0 $_TARGETNAME @end example @deffn {Command} {rsl10 lock} key1 key2 key3 key4 Writes @var{key1 key2 key3 key4} words to @var{0x81044 0x81048 0x8104c 0x8050}. Locks debug port by writing @var{0x4C6F634B} to @var{0x81040}. To unlock use the @command{rsl10 unlock key1 key2 key3 key4} command. @end deffn @deffn {Command} {rsl10 unlock} key1 key2 key3 key4 Unlocks debug port, by writing @var{key1 key2 key3 key4} words to registers through DAP, and clears @var{0x81040} address in flash to 0x1. @end deffn @deffn {Command} {rsl10 mass_erase} Erases all unprotected flash sectors. @end deffn @end deffn @deffn {Flash Driver} {sim3x} All members of the SiM3 microcontroller family from Silicon Laboratories include internal flash and use ARM Cortex-M3 cores. It supports both JTAG and SWD interface. The @var{sim3x} driver tries to probe the device to auto detect the MCU. If this fails, it will use the @var{size} parameter as the size of flash bank. @example flash bank $_FLASHNAME sim3x 0 $_CPUROMSIZE 0 0 $_TARGETNAME @end example There are 2 commands defined in the @var{sim3x} driver: @deffn {Command} {sim3x mass_erase} Erases the complete flash. This is used to unlock the flash. And this command is only possible when using the SWD interface. @end deffn @deffn {Command} {sim3x lock} Lock the flash. To unlock use the @command{sim3x mass_erase} command. @end deffn @end deffn @deffn {Flash Driver} {stellaris} All members of the Stellaris LM3Sxxx, LM4x and Tiva C microcontroller families from Texas Instruments include internal flash. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @example flash bank $_FLASHNAME stellaris 0 0 0 0 $_TARGETNAME @end example @deffn {Command} {stellaris recover} Performs the @emph{Recovering a "Locked" Device} procedure to restore the flash and its associated nonvolatile registers to their factory default values (erased). This is the only way to remove flash protection or re-enable debugging if that capability has been disabled. Note that the final "power cycle the chip" step in this procedure must be performed by hand, since OpenOCD can't do it. @quotation Warning if more than one Stellaris chip is connected, the procedure is applied to all of them. @end quotation @end deffn @end deffn @deffn {Flash Driver} {stm32f1x} All members of the STM32F0, STM32F1 and STM32F3 microcontroller families from STMicroelectronics and all members of the GD32F1x0, GD32F3x0 and GD32E23x microcontroller families from GigaDevice include internal flash and use ARM Cortex-M0/M3/M4/M23 cores. The driver also works with GD32VF103 powered by RISC-V core. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @example flash bank $_FLASHNAME stm32f1x 0 0 0 0 $_TARGETNAME @end example Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. @example flash bank $_FLASHNAME stm32f1x 0 0x20000 0 0 $_TARGETNAME @end example If you have a target with dual flash banks then define the second bank as per the following example. @example flash bank $_FLASHNAME stm32f1x 0x08080000 0 0 0 $_TARGETNAME @end example Some stm32f1x-specific commands are defined: @deffn {Command} {stm32f1x lock} num Locks the entire stm32 device against reading. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {stm32f1x unlock} num Unlocks the entire stm32 device for reading. This command will cause a mass erase of the entire stm32 device if previously locked. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {stm32f1x mass_erase} num Mass erases the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {stm32f1x options_read} num Reads and displays active stm32 option bytes loaded during POR or upon executing the @command{stm32f1x options_load} command. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {stm32f1x options_write} num (@option{SWWDG}|@option{HWWDG}) (@option{RSTSTNDBY}|@option{NORSTSTNDBY}) (@option{RSTSTOP}|@option{NORSTSTOP}) (@option{USEROPT} user_data) Writes the stm32 option byte with the specified values. The @var{num} parameter is a value shown by @command{flash banks}. The @var{user_data} parameter is content of higher 16 bits of the option byte register (Data0 and Data1 as one 16bit number). @end deffn @deffn {Command} {stm32f1x options_load} num Generates a special kind of reset to re-load the stm32 option bytes written by the @command{stm32f1x options_write} or @command{flash protect} commands without having to power cycle the target. Not applicable to stm32f1x devices. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn @deffn {Flash Driver} {stm32f2x} All members of the STM32F2, STM32F4 and STM32F7 microcontroller families from STMicroelectronics include internal flash and use ARM Cortex-M3/M4/M7 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @example flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME @end example If you use OTP (One-Time Programmable) memory define it as a second bank as per the following example. @example flash bank $_FLASHNAME stm32f2x 0x1FFF7800 0 0 0 $_TARGETNAME @end example @deffn {Command} {stm32f2x otp} num (@option{enable}|@option{disable}|@option{show}) Enables or disables OTP write commands for bank @var{num}. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. @example flash bank $_FLASHNAME stm32f2x 0 0x20000 0 0 $_TARGETNAME @end example Some stm32f2x-specific commands are defined: @deffn {Command} {stm32f2x lock} num Locks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {stm32f2x unlock} num Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {stm32f2x mass_erase} num Mass erases the entire stm32f2x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {stm32f2x options_read} num Reads and displays user options and (where implemented) boot_addr0, boot_addr1, optcr2. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {stm32f2x options_write} num user_options boot_addr0 boot_addr1 Writes user options and (where implemented) boot_addr0 and boot_addr1 in raw format. Warning: The meaning of the various bits depends on the device, always check datasheet! The @var{num} parameter is a value shown by @command{flash banks}, @var{user_options} a 12 bit value, consisting of bits 31-28 and 7-0 of FLASH_OPTCR, @var{boot_addr0} and @var{boot_addr1} two halfwords (of FLASH_OPTCR1). @end deffn @deffn {Command} {stm32f2x optcr2_write} num optcr2 Writes FLASH_OPTCR2 options. Warning: Clearing PCROPi bits requires a full mass erase! The @var{num} parameter is a value shown by @command{flash banks}, @var{optcr2} a 32-bit word. @end deffn @end deffn @deffn {Flash Driver} {stm32h7x} All members of the STM32H7 microcontroller families from STMicroelectronics include internal flash and use ARM Cortex-M7 core. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @example flash bank $_FLASHNAME stm32h7x 0 0 0 0 $_TARGETNAME @end example Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. @example flash bank $_FLASHNAME stm32h7x 0 0x20000 0 0 $_TARGETNAME @end example Some stm32h7x-specific commands are defined: @deffn {Command} {stm32h7x lock} num Locks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {stm32h7x unlock} num Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {stm32h7x mass_erase} num Mass erases the entire stm32h7x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {stm32h7x option_read} num reg_offset Reads an option byte register from the stm32h7x device. The @var{num} parameter is a value shown by @command{flash banks}, @var{reg_offset} is the register offset of the option byte to read from the used bank registers' base. For example: in STM32H74x/H75x the bank 1 registers' base is 0x52002000 and 0x52002100 for bank 2. Example usage: @example # read OPTSR_CUR stm32h7x option_read 0 0x1c # read WPSN_CUR1R stm32h7x option_read 0 0x38 # read WPSN_CUR2R stm32h7x option_read 1 0x38 @end example @end deffn @deffn {Command} {stm32h7x option_write} num reg_offset value [reg_mask] Writes an option byte register of the stm32h7x device. The @var{num} parameter is a value shown by @command{flash banks}, @var{reg_offset} is the register offset of the option byte to write from the used bank register base, and @var{reg_mask} is the mask to apply when writing the register (only bits with a '1' will be touched). Example usage: @example # swap bank 1 and bank 2 in dual bank devices # by setting SWAP_BANK_OPT bit in OPTSR_PRG stm32h7x option_write 0 0x20 0x8000000 0x8000000 @end example @end deffn @end deffn @deffn {Flash Driver} {stm32lx} All members of the STM32L0 and STM32L1 microcontroller families from STMicroelectronics include internal flash and use ARM Cortex-M3 and Cortex-M0+ cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @example flash bank $_FLASHNAME stm32lx 0 0 0 0 $_TARGETNAME @end example Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. If you use 0 as the bank base address, it tells the driver to autodetect the bank location assuming you're configuring the second bank. @example flash bank $_FLASHNAME stm32lx 0x08000000 0x20000 0 0 $_TARGETNAME @end example Some stm32lx-specific commands are defined: @deffn {Command} {stm32lx lock} num Locks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {stm32lx unlock} num Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {stm32lx mass_erase} num Mass erases the entire stm32lx device (all flash banks and EEPROM data). This is the only way to unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn @deffn {Flash Driver} {stm32l4x} All members of the STM32 G0, G4, L4, L4+, L5, U5, WB and WL microcontroller families from STMicroelectronics include internal flash and use ARM Cortex-M0+, M4 and M33 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @example flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME @end example If you use OTP (One-Time Programmable) memory define it as a second bank as per the following example. @example flash bank $_FLASHNAME stm32l4x 0x1FFF7000 0 0 0 $_TARGETNAME @end example @deffn {Command} {stm32l4x otp} num (@option{enable}|@option{disable}|@option{show}) Enables or disables OTP write commands for bank @var{num}. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. However, specifying a wrong value might lead to a completely wrong flash layout, so this feature must be used carefully. @example flash bank $_FLASHNAME stm32l4x 0x08000000 0x40000 0 0 $_TARGETNAME @end example Some stm32l4x-specific commands are defined: @deffn {Command} {stm32l4x lock} num Locks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @emph{Note:} To apply the protection change immediately, use @command{stm32l4x option_load}. @end deffn @deffn {Command} {stm32l4x unlock} num Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @emph{Note:} To apply the protection change immediately, use @command{stm32l4x option_load}. @end deffn @deffn {Command} {stm32l4x mass_erase} num Mass erases the entire stm32l4x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Command} {stm32l4x option_read} num reg_offset Reads an option byte register from the stm32l4x device. The @var{num} parameter is a value shown by @command{flash banks}, @var{reg_offset} is the register offset of the Option byte to read. For example to read the FLASH_OPTR register: @example stm32l4x option_read 0 0x20 # Option Register (for STM32L4x): <0x40022020> = 0xffeff8aa # Option Register (for STM32WBx): <0x58004020> = ... # The correct flash base address will be used automatically @end example The above example will read out the FLASH_OPTR register which contains the RDP option byte, Watchdog configuration, BOR level etc. @end deffn @deffn {Command} {stm32l4x option_write} num reg_offset reg_mask Write an option byte register of the stm32l4x device. The @var{num} parameter is a value shown by @command{flash banks}, @var{reg_offset} is the register offset of the Option byte to write, and @var{reg_mask} is the mask to apply when writing the register (only bits with a '1' will be touched). @emph{Note:} To apply the option bytes change immediately, use @command{stm32l4x option_load}. For example to write the WRP1AR option bytes: @example stm32l4x option_write 0 0x28 0x00FF0000 0x00FF00FF @end example The above example will write the WRP1AR option register configuring the Write protection Area A for bank 1. The above example set WRP1AR_END=255, WRP1AR_START=0. This will effectively write protect all sectors in flash bank 1. @end deffn @deffn {Command} {stm32l4x wrp_info} num [device_bank] List the protected areas using WRP. The @var{num} parameter is a value shown by @command{flash banks}. @var{device_bank} parameter is optional, possible values 'bank1' or 'bank2', if not specified, the command will display the whole flash protected areas. @b{Note:} @var{device_bank} is different from banks created using @code{flash bank}. Devices supported in this flash driver, can have main flash memory organized in single or dual-banks mode. Thus the usage of @var{device_bank} is meaningful only in dual-bank mode, to get write protected areas in a specific @var{device_bank} @end deffn @deffn {Command} {stm32l4x option_load} num Forces a re-load of the option byte registers. Will cause a system reset of the device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32l4x trustzone} num [@option{enable} | @option{disable}] Enables or disables Global TrustZone Security, using the TZEN option bit. If neither @option{enabled} nor @option{disable} are specified, the command will display the TrustZone status. @emph{Note:} This command works only with devices with TrustZone, eg. STM32L5. @emph{Note:} This command will perform an OBL_Launch after modifying the TZEN. @end deffn @end deffn @deffn {Flash Driver} {str7x} All members of the STR7 microcontroller family from STMicroelectronics include internal flash and use ARM7TDMI cores. The @var{str7x} driver defines one mandatory parameter, @var{variant}, which is either @code{STR71x}, @code{STR73x} or @code{STR75x}. @example flash bank $_FLASHNAME str7x \ 0x40000000 0x00040000 0 0 $_TARGETNAME STR71x @end example @deffn {Command} {str7x disable_jtag} bank Activate the Debug/Readout protection mechanism for the specified flash bank. @end deffn @end deffn @deffn {Flash Driver} {str9x} Most members of the STR9 microcontroller family from STMicroelectronics include internal flash and use ARM966E cores. The str9 needs the flash controller to be configured using the @command{str9x flash_config} command prior to Flash programming. @example flash bank $_FLASHNAME str9x 0x40000000 0x00040000 0 0 $_TARGETNAME str9x flash_config 0 4 2 0 0x80000 @end example @deffn {Command} {str9x flash_config} num bbsr nbbsr bbadr nbbadr Configures the str9 flash controller. The @var{num} parameter is a value shown by @command{flash banks}. @itemize @bullet @item @var{bbsr} - Boot Bank Size register @item @var{nbbsr} - Non Boot Bank Size register @item @var{bbadr} - Boot Bank Start Address register @item @var{nbbadr} - Boot Bank Start Address register @end itemize @end deffn @end deffn @deffn {Flash Driver} {str9xpec} @cindex str9xpec Only use this driver for locking/unlocking the device or configuring the option bytes. Use the standard str9 driver for programming. Before using the flash commands the turbo mode must be enabled using the @command{str9xpec enable_turbo} command. Here is some background info to help you better understand how this driver works. OpenOCD has two flash drivers for the str9: @enumerate @item Standard driver @option{str9x} programmed via the str9 core. Normally used for flash programming as it is faster than the @option{str9xpec} driver. @item Direct programming @option{str9xpec} using the flash controller. This is an ISC compliant (IEEE 1532) tap connected in series with the str9 core. The str9 core does not need to be running to program using this flash driver. Typical use for this driver is locking/unlocking the target and programming the option bytes. @end enumerate Before we run any commands using the @option{str9xpec} driver we must first disable the str9 core. This example assumes the @option{str9xpec} driver has been configured for flash bank 0. @example # assert srst, we do not want core running # while accessing str9xpec flash driver adapter assert srst # turn off target polling poll off # disable str9 core str9xpec enable_turbo 0 # read option bytes str9xpec options_read 0 # re-enable str9 core str9xpec disable_turbo 0 poll on reset halt @end example The above example will read the str9 option bytes. When performing a unlock remember that you will not be able to halt the str9 - it has been locked. Halting the core is not required for the @option{str9xpec} driver as mentioned above, just issue the commands above manually or from a telnet prompt. Several str9xpec-specific commands are defined: @deffn {Command} {str9xpec disable_turbo} num Restore the str9 into JTAG chain. @end deffn @deffn {Command} {str9xpec enable_turbo} num Enable turbo mode, will simply remove the str9 from the chain and talk directly to the embedded flash controller. @end deffn @deffn {Command} {str9xpec lock} num Lock str9 device. The str9 will only respond to an unlock command that will erase the device. @end deffn @deffn {Command} {str9xpec part_id} num Prints the part identifier for bank @var{num}. @end deffn @deffn {Command} {str9xpec options_cmap} num (@option{bank0}|@option{bank1}) Configure str9 boot bank. @end deffn @deffn {Command} {str9xpec options_lvdsel} num (@option{vdd}|@option{vdd_vddq}) Configure str9 lvd source. @end deffn @deffn {Command} {str9xpec options_lvdthd} num (@option{2.4v}|@option{2.7v}) Configure str9 lvd threshold. @end deffn @deffn {Command} {str9xpec options_lvdwarn} bank (@option{vdd}|@option{vdd_vddq}) Configure str9 lvd reset warning source. @end deffn @deffn {Command} {str9xpec options_read} num Read str9 option bytes. @end deffn @deffn {Command} {str9xpec options_write} num Write str9 option bytes. @end deffn @deffn {Command} {str9xpec unlock} num unlock str9 device. @end deffn @end deffn @deffn {Flash Driver} {swm050} @cindex swm050 All members of the swm050 microcontroller family from Foshan Synwit Tech. @example flash bank $_FLASHNAME swm050 0x0 0x2000 0 0 $_TARGETNAME @end example One swm050-specific command is defined: @deffn {Command} {swm050 mass_erase} bank_id Erases the entire flash bank. @end deffn @end deffn @deffn {Flash Driver} {tms470} Most members of the TMS470 microcontroller family from Texas Instruments include internal flash and use ARM7TDMI cores. This driver doesn't require the chip and bus width to be specified. Some tms470-specific commands are defined: @deffn {Command} {tms470 flash_keyset} key0 key1 key2 key3 Saves programming keys in a register, to enable flash erase and write commands. @end deffn @deffn {Command} {tms470 osc_megahertz} clock_mhz Reports the clock speed, which is used to calculate timings. @end deffn @deffn {Command} {tms470 plldis} (0|1) Disables (@var{1}) or enables (@var{0}) use of the PLL to speed up the flash clock. @end deffn @end deffn @deffn {Flash Driver} {w600} W60x series Wi-Fi SoC from WinnerMicro are designed with ARM Cortex-M3 and have 1M Byte QFLASH inside. The @var{w600} driver uses the @var{target} parameter to select the correct bank config. @example flash bank $_FLASHNAME w600 0x08000000 0 0 0 $_TARGETNAMEs @end example @end deffn @deffn {Flash Driver} {xmc1xxx} All members of the XMC1xxx microcontroller family from Infineon. This driver does not require the chip and bus width to be specified. @end deffn @deffn {Flash Driver} {xmc4xxx} All members of the XMC4xxx microcontroller family from Infineon. This driver does not require the chip and bus width to be specified. Some xmc4xxx-specific commands are defined: @deffn {Command} {xmc4xxx flash_password} bank_id passwd1 passwd2 Saves flash protection passwords which are used to lock the user flash @end deffn @deffn {Command} {xmc4xxx flash_unprotect} bank_id user_level[0-1] Removes Flash write protection from the selected user bank @end deffn @end deffn @section NAND Flash Commands @cindex NAND Compared to NOR or SPI flash, NAND devices are inexpensive and high density. Today's NAND chips, and multi-chip modules, commonly hold multiple GigaBytes of data. NAND chips consist of a number of ``erase blocks'' of a given size (such as 128 KBytes), each of which is divided into a number of pages (of perhaps 512 or 2048 bytes each). Each page of a NAND flash has an ``out of band'' (OOB) area to hold Error Correcting Code (ECC) and other metadata, usually 16 bytes of OOB for every 512 bytes of page data. One key characteristic of NAND flash is that its error rate is higher than that of NOR flash. In normal operation, that ECC is used to correct and detect errors. However, NAND blocks can also wear out and become unusable; those blocks are then marked "bad". NAND chips are even shipped from the manufacturer with a few bad blocks. The highest density chips use a technology (MLC) that wears out more quickly, so ECC support is increasingly important as a way to detect blocks that have begun to fail, and help to preserve data integrity with techniques such as wear leveling. Software is used to manage the ECC. Some controllers don't support ECC directly; in those cases, software ECC is used. Other controllers speed up the ECC calculations with hardware. Single-bit error correction hardware is routine. Controllers geared for newer MLC chips may correct 4 or more errors for every 512 bytes of data. You will need to make sure that any data you write using OpenOCD includes the appropriate kind of ECC. For example, that may mean passing the @code{oob_softecc} flag when writing NAND data, or ensuring that the correct hardware ECC mode is used. The basic steps for using NAND devices include: @enumerate @item Declare via the command @command{nand device} @* Do this in a board-specific configuration file, passing parameters as needed by the controller. @item Configure each device using @command{nand probe}. @* Do this only after the associated target is set up, such as in its reset-init script or in procures defined to access that device. @item Operate on the flash via @command{nand subcommand} @* Often commands to manipulate the flash are typed by a human, or run via a script in some automated way. Common task include writing a boot loader, operating system, or other data needed to initialize or de-brick a board. @end enumerate @b{NOTE:} At the time this text was written, the largest NAND flash fully supported by OpenOCD is 2 GiBytes (16 GiBits). This is because the variables used to hold offsets and lengths are only 32 bits wide. (Larger chips may work in some cases, unless an offset or length is larger than 0xffffffff, the largest 32-bit unsigned integer.) Some larger devices will work, since they are actually multi-chip modules with two smaller chips and individual chipselect lines. @anchor{nandconfiguration} @subsection NAND Configuration Commands @cindex NAND configuration NAND chips must be declared in configuration scripts, plus some additional configuration that's done after OpenOCD has initialized. @deffn {Config Command} {nand device} name driver target [configparams...] Declares a NAND device, which can be read and written to after it has been configured through @command{nand probe}. In OpenOCD, devices are single chips; this is unlike some operating systems, which may manage multiple chips as if they were a single (larger) device. In some cases, configuring a device will activate extra commands; see the controller-specific documentation. @b{NOTE:} This command is not available after OpenOCD initialization has completed. Use it in board specific configuration files, not interactively. @itemize @bullet @item @var{name} ... may be used to reference the NAND bank in most other NAND commands. A number is also available. @item @var{driver} ... identifies the NAND controller driver associated with the NAND device being declared. @xref{nanddriverlist,,NAND Driver List}. @item @var{target} ... names the target used when issuing commands to the NAND controller. @comment Actually, it's currently a controller-specific parameter... @item @var{configparams} ... controllers may support, or require, additional parameters. See the controller-specific documentation for more information. @end itemize @end deffn @deffn {Command} {nand list} Prints a summary of each device declared using @command{nand device}, numbered from zero. Note that un-probed devices show no details. @example > nand list #0: NAND 1GiB 3,3V 8-bit (Micron) pagesize: 2048, buswidth: 8, blocksize: 131072, blocks: 8192 #1: NAND 1GiB 3,3V 8-bit (Micron) pagesize: 2048, buswidth: 8, blocksize: 131072, blocks: 8192 > @end example @end deffn @deffn {Command} {nand probe} num Probes the specified device to determine key characteristics like its page and block sizes, and how many blocks it has. The @var{num} parameter is the value shown by @command{nand list}. You must (successfully) probe a device before you can use it with most other NAND commands. @end deffn @subsection Erasing, Reading, Writing to NAND Flash @deffn {Command} {nand dump} num filename offset length [oob_option] @cindex NAND reading Reads binary data from the NAND device and writes it to the file, starting at the specified offset. The @var{num} parameter is the value shown by @command{nand list}. Use a complete path name for @var{filename}, so you don't depend on the directory used to start the OpenOCD server. The @var{offset} and @var{length} must be exact multiples of the device's page size. They describe a data region; the OOB data associated with each such page may also be accessed. @b{NOTE:} At the time this text was written, no error correction was done on the data that's read, unless raw access was disabled and the underlying NAND controller driver had a @code{read_page} method which handled that error correction. By default, only page data is saved to the specified file. Use an @var{oob_option} parameter to save OOB data: @itemize @bullet @item no oob_* parameter @*Output file holds only page data; OOB is discarded. @item @code{oob_raw} @*Output file interleaves page data and OOB data; the file will be longer than "length" by the size of the spare areas associated with each data page. Note that this kind of "raw" access is different from what's implied by @command{nand raw_access}, which just controls whether a hardware-aware access method is used. @item @code{oob_only} @*Output file has only raw OOB data, and will be smaller than "length" since it will contain only the spare areas associated with each data page. @end itemize @end deffn @deffn {Command} {nand erase} num [offset length] @cindex NAND erasing @cindex NAND programming Erases blocks on the specified NAND device, starting at the specified @var{offset} and continuing for @var{length} bytes. Both of those values must be exact multiples of the device's block size, and the region they specify must fit entirely in the chip. If those parameters are not specified, the whole NAND chip will be erased. The @var{num} parameter is the value shown by @command{nand list}. @b{NOTE:} This command will try to erase bad blocks, when told to do so, which will probably invalidate the manufacturer's bad block marker. For the remainder of the current server session, @command{nand info} will still report that the block ``is'' bad. @end deffn @deffn {Command} {nand write} num filename offset [option...] @cindex NAND writing @cindex NAND programming Writes binary data from the file into the specified NAND device, starting at the specified offset. Those pages should already have been erased; you can't change zero bits to one bits. The @var{num} parameter is the value shown by @command{nand list}. Use a complete path name for @var{filename}, so you don't depend on the directory used to start the OpenOCD server. The @var{offset} must be an exact multiple of the device's page size. All data in the file will be written, assuming it doesn't run past the end of the device. Only full pages are written, and any extra space in the last page will be filled with 0xff bytes. (That includes OOB data, if that's being written.) @b{NOTE:} At the time this text was written, bad blocks are ignored. That is, this routine will not skip bad blocks, but will instead try to write them. This can cause problems. Provide at most one @var{option} parameter. With some NAND drivers, the meanings of these parameters may change if @command{nand raw_access} was used to disable hardware ECC. @itemize @bullet @item no oob_* parameter @*File has only page data, which is written. If raw access is in use, the OOB area will not be written. Otherwise, if the underlying NAND controller driver has a @code{write_page} routine, that routine may write the OOB with hardware-computed ECC data. @item @code{oob_only} @*File has only raw OOB data, which is written to the OOB area. Each page's data area stays untouched. @i{This can be a dangerous option}, since it can invalidate the ECC data. You may need to force raw access to use this mode. @item @code{oob_raw} @*File interleaves data and OOB data, both of which are written If raw access is enabled, the data is written first, then the un-altered OOB. Otherwise, if the underlying NAND controller driver has a @code{write_page} routine, that routine may modify the OOB before it's written, to include hardware-computed ECC data. @item @code{oob_softecc} @*File has only page data, which is written. The OOB area is filled with 0xff, except for a standard 1-bit software ECC code stored in conventional locations. You might need to force raw access to use this mode, to prevent the underlying driver from applying hardware ECC. @item @code{oob_softecc_kw} @*File has only page data, which is written. The OOB area is filled with 0xff, except for a 4-bit software ECC specific to the boot ROM in Marvell Kirkwood SoCs. You might need to force raw access to use this mode, to prevent the underlying driver from applying hardware ECC. @end itemize @end deffn @deffn {Command} {nand verify} num filename offset [option...] @cindex NAND verification @cindex NAND programming Verify the binary data in the file has been programmed to the specified NAND device, starting at the specified offset. The @var{num} parameter is the value shown by @command{nand list}. Use a complete path name for @var{filename}, so you don't depend on the directory used to start the OpenOCD server. The @var{offset} must be an exact multiple of the device's page size. All data in the file will be read and compared to the contents of the flash, assuming it doesn't run past the end of the device. As with @command{nand write}, only full pages are verified, so any extra space in the last page will be filled with 0xff bytes. The same @var{options} accepted by @command{nand write}, and the file will be processed similarly to produce the buffers that can be compared against the contents produced from @command{nand dump}. @b{NOTE:} This will not work when the underlying NAND controller driver's @code{write_page} routine must update the OOB with a hardware-computed ECC before the data is written. This limitation may be removed in a future release. @end deffn @subsection Other NAND commands @cindex NAND other commands @deffn {Command} {nand check_bad_blocks} num [offset length] Checks for manufacturer bad block markers on the specified NAND device. If no parameters are provided, checks the whole device; otherwise, starts at the specified @var{offset} and continues for @var{length} bytes. Both of those values must be exact multiples of the device's block size, and the region they specify must fit entirely in the chip. The @var{num} parameter is the value shown by @command{nand list}. @b{NOTE:} Before using this command you should force raw access with @command{nand raw_access enable} to ensure that the underlying driver will not try to apply hardware ECC. @end deffn @deffn {Command} {nand info} num The @var{num} parameter is the value shown by @command{nand list}. This prints the one-line summary from "nand list", plus for devices which have been probed this also prints any known status for each block. @end deffn @deffn {Command} {nand raw_access} num (@option{enable}|@option{disable}) Sets or clears an flag affecting how page I/O is done. The @var{num} parameter is the value shown by @command{nand list}. This flag is cleared (disabled) by default, but changing that value won't affect all NAND devices. The key factor is whether the underlying driver provides @code{read_page} or @code{write_page} methods. If it doesn't provide those methods, the setting of this flag is irrelevant; all access is effectively ``raw''. When those methods exist, they are normally used when reading data (@command{nand dump} or reading bad block markers) or writing it (@command{nand write}). However, enabling raw access (setting the flag) prevents use of those methods, bypassing hardware ECC logic. @i{This can be a dangerous option}, since writing blocks with the wrong ECC data can cause them to be marked as bad. @end deffn @anchor{nanddriverlist} @subsection NAND Driver List As noted above, the @command{nand device} command allows driver-specific options and behaviors. Some controllers also activate controller-specific commands. @deffn {NAND Driver} {at91sam9} This driver handles the NAND controllers found on AT91SAM9 family chips from Atmel. It takes two extra parameters: address of the NAND chip; address of the ECC controller. @example nand device $NANDFLASH at91sam9 $CHIPNAME 0x40000000 0xfffffe800 @end example AT91SAM9 chips support single-bit ECC hardware. The @code{write_page} and @code{read_page} methods are used to utilize the ECC hardware unless they are disabled by using the @command{nand raw_access} command. There are four additional commands that are needed to fully configure the AT91SAM9 NAND controller. Two are optional; most boards use the same wiring for ALE/CLE: @deffn {Config Command} {at91sam9 cle} num addr_line Configure the address line used for latching commands. The @var{num} parameter is the value shown by @command{nand list}. @end deffn @deffn {Config Command} {at91sam9 ale} num addr_line Configure the address line used for latching addresses. The @var{num} parameter is the value shown by @command{nand list}. @end deffn For the next two commands, it is assumed that the pins have already been properly configured for input or output. @deffn {Config Command} {at91sam9 rdy_busy} num pio_base_addr pin Configure the RDY/nBUSY input from the NAND device. The @var{num} parameter is the value shown by @command{nand list}. @var{pio_base_addr} is the base address of the PIO controller and @var{pin} is the pin number. @end deffn @deffn {Config Command} {at91sam9 ce} num pio_base_addr pin Configure the chip enable input to the NAND device. The @var{num} parameter is the value shown by @command{nand list}. @var{pio_base_addr} is the base address of the PIO controller and @var{pin} is the pin number. @end deffn @end deffn @deffn {NAND Driver} {davinci} This driver handles the NAND controllers found on DaVinci family chips from Texas Instruments. It takes three extra parameters: address of the NAND chip; hardware ECC mode to use (@option{hwecc1}, @option{hwecc4}, @option{hwecc4_infix}); address of the AEMIF controller on this processor. @example nand device davinci dm355.arm 0x02000000 hwecc4 0x01e10000 @end example All DaVinci processors support the single-bit ECC hardware, and newer ones also support the four-bit ECC hardware. The @code{write_page} and @code{read_page} methods are used to implement those ECC modes, unless they are disabled using the @command{nand raw_access} command. @end deffn @deffn {NAND Driver} {lpc3180} These controllers require an extra @command{nand device} parameter: the clock rate used by the controller. @deffn {Command} {lpc3180 select} num [mlc|slc] Configures use of the MLC or SLC controller mode. MLC implies use of hardware ECC. The @var{num} parameter is the value shown by @command{nand list}. @end deffn At this writing, this driver includes @code{write_page} and @code{read_page} methods. Using @command{nand raw_access} to disable those methods will prevent use of hardware ECC in the MLC controller mode, but won't change SLC behavior. @end deffn @comment current lpc3180 code won't issue 5-byte address cycles @deffn {NAND Driver} {mx3} This driver handles the NAND controller in i.MX31. The mxc driver should work for this chip as well. @end deffn @deffn {NAND Driver} {mxc} This driver handles the NAND controller found in Freescale i.MX chips. It has support for v1 (i.MX27 and i.MX31) and v2 (i.MX35). The driver takes 3 extra arguments, chip (@option{mx27}, @option{mx31}, @option{mx35}), ecc (@option{noecc}, @option{hwecc}) and optionally if bad block information should be swapped between main area and spare area (@option{biswap}), defaults to off. @example nand device mx35.nand mxc imx35.cpu mx35 hwecc biswap @end example @deffn {Command} {mxc biswap} bank_num [enable|disable] Turns on/off bad block information swapping from main area, without parameter query status. @end deffn @end deffn @deffn {NAND Driver} {orion} These controllers require an extra @command{nand device} parameter: the address of the controller. @example nand device orion 0xd8000000 @end example These controllers don't define any specialized commands. At this writing, their drivers don't include @code{write_page} or @code{read_page} methods, so @command{nand raw_access} won't change any behavior. @end deffn @deffn {NAND Driver} {s3c2410} @deffnx {NAND Driver} {s3c2412} @deffnx {NAND Driver} {s3c2440} @deffnx {NAND Driver} {s3c2443} @deffnx {NAND Driver} {s3c6400} These S3C family controllers don't have any special @command{nand device} options, and don't define any specialized commands. At this writing, their drivers don't include @code{write_page} or @code{read_page} methods, so @command{nand raw_access} won't change any behavior. @end deffn @node Flash Programming @chapter Flash Programming OpenOCD implements numerous ways to program the target flash, whether internal or external. Programming can be achieved by either using @ref{programmingusinggdb,,Programming using GDB}, or using the commands given in @ref{flashprogrammingcommands,,Flash Programming Commands}. @*To simplify using the flash commands directly a jimtcl script is available that handles the programming and verify stage. OpenOCD will program/verify/reset the target and optionally shutdown. The script is executed as follows and by default the following actions will be performed. @enumerate @item 'init' is executed. @item 'reset init' is called to reset and halt the target, any 'reset init' scripts are executed. @item @code{flash write_image} is called to erase and write any flash using the filename given. @item If the @option{preverify} parameter is given, the target is "verified" first and only flashed if this fails. @item @code{verify_image} is called if @option{verify} parameter is given. @item @code{reset run} is called if @option{reset} parameter is given. @item OpenOCD is shutdown if @option{exit} parameter is given. @end enumerate An example of usage is given below. @xref{program}. @example # program and verify using elf/hex/s19. verify and reset # are optional parameters openocd -f board/stm32f3discovery.cfg \ -c "program filename.elf verify reset exit" # binary files need the flash address passing openocd -f board/stm32f3discovery.cfg \ -c "program filename.bin exit 0x08000000" @end example @node PLD/FPGA Commands @chapter PLD/FPGA Commands @cindex PLD @cindex FPGA Programmable Logic Devices (PLDs) and the more flexible Field Programmable Gate Arrays (FPGAs) are both types of programmable hardware. OpenOCD can support programming them. Although PLDs are generally restrictive (cells are less functional, and there are no special purpose cells for memory or computational tasks), they share the same OpenOCD infrastructure. Accordingly, both are called PLDs here. @section PLD/FPGA Configuration and Commands As it does for JTAG TAPs, debug targets, and flash chips (both NOR and NAND), OpenOCD maintains a list of PLDs available for use in various commands. Also, each such PLD requires a driver. They are referenced by the name which was given when the pld was created or the number shown by the @command{pld devices} command. New PLDs are defined by @command{pld create pld_name driver_name -chain-position tap_name [driver_options]}. @deffn {Config Command} {pld create} pld_name driver_name -chain-position tap_name [driver_options] Creates a new PLD device, supported by driver @var{driver_name}, assigning @var{pld_name} for further reference. @code{-chain-position} @var{tap_name} names the TAP used to access this target. The driver may make use of any @var{driver_options} to configure its behavior. @end deffn @deffn {Command} {pld devices} List the known PLDs with their name. @end deffn @deffn {Command} {pld load} pld_name filename Loads the file @file{filename} into the PLD identified by @var{pld_name}. The file format must be inferred by the driver. @end deffn @section PLD/FPGA Drivers, Options, and Commands Drivers may support PLD-specific options to the @command{pld device} definition command, and may also define commands usable only with that particular type of PLD. @deffn {FPGA Driver} {virtex2} [@option{-no_jstart}] Virtex-II is a family of FPGAs sold by Xilinx. This driver can also be used to load Series3, Series6, Series7 and Zynq 7000 devices. It supports the IEEE 1532 standard for In-System Configuration (ISC). If @var{-no_jstart} is given, the JSTART instruction is not used after loading the bitstream. While required for Series2, Series3, and Series6, it breaks bitstream loading on Series7. @example openocd -f board/digilent_zedboard.cfg -c "init" \ -c "pld load 0 zedboard_bitstream.bit" @end example @deffn {Command} {virtex2 read_stat} pld_name Reads and displays the Virtex-II status register (STAT) for FPGA @var{pld_name}. @end deffn @deffn {Command} {virtex2 set_instr_codes} pld_name cfg_out cfg_in jprogb jstart jshutdown [user1 [user2 [user3 [user4]]]] Change values for boundary scan instructions. Default are values for Virtex 2, devices Virtex 4/5/6 and SSI devices are using different values. @var{pld_name} is the name of the pld device. @var{cfg_out} is the value used to select CFG_OUT instruction. @var{cfg_in} is the value used to select CFG_IN instruction. @var{jprogb} is the value used to select JPROGRAM instruction. @var{jstart} is the value used to select JSTART instruction. @var{jshutdown} is the value used to select JSHUTDOWN instruction. @var{user1} to @var{user4} are the intruction used to select the user registers USER1 to USER4. @end deffn @deffn {Command} {virtex2 set_user_codes} pld_name user1 [user2 [user3 [user4]]] Change values for boundary scan instructions selecting the registers USER1 to USER4. Description of the arguments can be found at command @command{virtex2 set_instr_codes}. @end deffn @deffn {Command} {virtex2 program} pld_name Load the bitstream from external memory for FPGA @var{pld_name}. A.k.a. refresh. @end deffn @end deffn @deffn {FPGA Driver} {lattice} [@option{-family} <name>] The FGPA families ECP2, ECP3, ECP5, Certus and CertusPro by Lattice are supported. This driver can be used to load the bitstream into the FPGA or read the status register and read/write the usercode register. For the option @option{-family} @var{name} is one of @var{ecp2 ecp3 ecp5 certus}. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices). @deffn {Command} {lattice read_status} pld_name Reads and displays the status register for FPGA @var{pld_name}. @end deffn @deffn {Command} {lattice read_user} pld_name Reads and displays the user register for FPGA @var{pld_name}. @end deffn @deffn {Command} {lattice write_user} pld_name val Writes the user register. for FPGA @var{pld_name} with value @var{val}. @end deffn @deffn {Command} {lattice set_preload} pld_name length Set the length of the register for the preload. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices). The load command for the FPGA @var{pld_name} will use a length for the preload of @var{length}. @end deffn @end deffn @deffn {FPGA Driver} {efinix} [@option{-family} <name>] Both families (Trion and Titanium) sold by Efinix are supported as both use the same protocol for In-System Configuration. This driver can be used to load the bitstream into the FPGA. For the option @option{-family} @var{name} is one of @var{trion|titanium}. @end deffn @deffn {FPGA Driver} {intel} [@option{-family} <name>] This driver can be used to load the bitstream into Intel (former Altera) FPGAs. The families Cyclone III, Cyclone IV, Cyclone V, Cyclone 10, Arria II are supported. @c Arria V and Arria 10, MAX II, MAX V, MAX10) For the option @option{-family} @var{name} is one of @var{cycloneiii cycloneiv cyclonev cyclone10 arriaii}. This is needed when the JTAG ID of the device is ambiguous (same ID is used for chips in different families). As input file format the driver supports a '.rbf' (raw bitstream file) file. The '.rbf' file can be generated from a '.sof' file with @verb{|quartus_cpf -c blinker.sof blinker.rbf|} Creates a new PLD device, an FPGA of the Cyclone III family, using the TAP named @verb{|cycloneiii.tap|}: @example pld create cycloneiii.pld intel -chain-position cycloneiii.tap -family cycloneiii @end example @deffn {Command} {intel set_bscan} pld_name len Set boundary scan register length of FPGA @var{pld_name} to @var{len}. This is needed because the length can vary between chips with the same JTAG ID. @end deffn @deffn {Command} {intel set_check_pos} pld_name pos Selects the position @var{pos} in the boundary-scan register. The bit at this position is checked after loading the bitstream and must be '1', which is the case when no error occurred. With a value of -1 for @var{pos} the check will be omitted. @end deffn @end deffn @deffn {FPGA Driver} {gowin} This driver can be used to load the bitstream into FPGAs from Gowin. It is possible to program the SRAM. Programming the flash is not supported. The files @verb{|.fs|} and @verb{|.bin|} generated by Gowin FPGA Designer are supported. @deffn {Command} {gowin read_status} pld_name Reads and displays the status register for FPGA @var{pld_name}. @end deffn @deffn {Command} {gowin read_user} pld_name Reads and displays the user register for FPGA @var{pld_name}. @end deffn @deffn {Command} {gowin reload} pld_name Load the bitstream from external memory for FPGA @var{pld_name}. A.k.a. refresh. @end deffn @end deffn @deffn {FPGA Driver} {gatemate} This driver can be used to load the bitstream into GateMate FPGAs form CologneChip. The files @verb{|.bit|} and @verb{|.cfg|} both generated by p_r tool from CologneChip are supported. @end deffn @node General Commands @chapter General Commands @cindex commands The commands documented in this chapter here are common commands that you, as a human, may want to type and see the output of. Configuration type commands are documented elsewhere. Intent: @itemize @bullet @item @b{Source Of Commands} @* OpenOCD commands can occur in a configuration script (discussed elsewhere) or typed manually by a human or supplied programmatically, or via one of several TCP/IP Ports. @item @b{From the human} @* A human should interact with the telnet interface (default port: 4444) or via GDB (default port 3333). To issue commands from within a GDB session, use the @option{monitor} command, e.g. use @option{monitor poll} to issue the @option{poll} command. All output is relayed through the GDB session. @item @b{Machine Interface} The Tcl interface's intent is to be a machine interface. The default Tcl port is 6666. @end itemize @section Server Commands @deffn {Command} {exit} Exits the current telnet session. @end deffn @deffn {Command} {help} [string] With no parameters, prints help text for all commands. Otherwise, prints each helptext containing @var{string}. Not every command provides helptext. Configuration commands, and commands valid at any time, are explicitly noted in parenthesis. In most cases, no such restriction is listed; this indicates commands which are only available after the configuration stage has completed. @end deffn @deffn {Command} {usage} [string] With no parameters, prints usage text for all commands. Otherwise, prints all usage text of which command, help text, and usage text containing @var{string}. Not every command provides helptext. @end deffn @deffn {Command} {sleep} msec [@option{busy}] Wait for at least @var{msec} milliseconds before resuming. If @option{busy} is passed, busy-wait instead of sleeping. (This option is strongly discouraged.) Useful in connection with script files (@command{script} command and @command{target_name} configuration). @end deffn @deffn {Command} {shutdown} [@option{error}] Close the OpenOCD server, disconnecting all clients (GDB, telnet, other). If option @option{error} is used, OpenOCD will return a non-zero exit code to the parent process. If user types CTRL-C or kills OpenOCD, the command @command{shutdown} will be automatically executed to cause OpenOCD to exit. It is possible to specify, in the TCL list @var{pre_shutdown_commands} , a set of commands to be automatically executed before @command{shutdown} , e.g.: @example lappend pre_shutdown_commands @{echo "Goodbye, my friend ..."@} lappend pre_shutdown_commands @{echo "see you soon !"@} @end example The commands in the list will be executed (in the same order they occupy in the list) before OpenOCD exits. If one of the commands in the list fails, then the remaining commands are not executed anymore while OpenOCD will proceed to quit. @end deffn @anchor{debuglevel} @deffn {Command} {debug_level} [n] @cindex message level Display debug level. If @var{n} (from 0..4) is provided, then set it to that level. This affects the kind of messages sent to the server log. Level 0 is error messages only; level 1 adds warnings; level 2 adds informational messages; level 3 adds debugging messages; and level 4 adds verbose low-level debug messages. The default is level 2, but that can be overridden on the command line along with the location of that log file (which is normally the server's standard output). @xref{Running}. @end deffn @deffn {Command} {echo} [-n] message Logs a message at "user" priority. Option "-n" suppresses trailing newline. @example echo "Downloading kernel -- please wait" @end example @end deffn @deffn {Command} {log_output} [filename | "default"] Redirect logging to @var{filename} or set it back to default output; the default log output channel is stderr. @end deffn @deffn {Command} {add_script_search_dir} [directory] Add @var{directory} to the file/script search path. @end deffn @deffn {Config Command} {bindto} [@var{name}] Specify hostname or IPv4 address on which to listen for incoming TCP/IP connections. By default, OpenOCD will listen on the loopback interface only. If your network environment is safe, @code{bindto 0.0.0.0} can be used to cover all available interfaces. @end deffn @anchor{targetstatehandling} @section Target State handling @cindex reset @cindex halt @cindex target initialization In this section ``target'' refers to a CPU configured as shown earlier (@pxref{CPU Configuration}). These commands, like many, implicitly refer to a current target which is used to perform the various operations. The current target may be changed by using @command{targets} command with the name of the target which should become current. @deffn {Command} {reg} [(number|name) [(value|'force')]] Access a single register by @var{number} or by its @var{name}. The target must generally be halted before access to CPU core registers is allowed. Depending on the hardware, some other registers may be accessible while the target is running. @emph{With no arguments}: list all available registers for the current target, showing number, name, size, value, and cache status. For valid entries, a value is shown; valid entries which are also dirty (and will be written back later) are flagged as such. @emph{With number/name}: display that register's value. Use @var{force} argument to read directly from the target, bypassing any internal cache. @emph{With both number/name and value}: set register's value. Writes may be held in a writeback cache internal to OpenOCD, so that setting the value marks the register as dirty instead of immediately flushing that value. Resuming CPU execution (including by single stepping) or otherwise activating the relevant module will flush such values. Cores may have surprisingly many registers in their Debug and trace infrastructure: @example > reg ===== ARM registers (0) r0 (/32): 0x0000D3C2 (dirty) (1) r1 (/32): 0xFD61F31C (2) r2 (/32) ... (164) ETM_contextid_comparator_mask (/32) > @end example @end deffn @deffn {Command} {set_reg} dict Set register values of the target. @itemize @item @var{dict} ... Tcl dictionary with pairs of register names and values. @end itemize For example, the following command sets the value 0 to the program counter (pc) register and 0x1000 to the stack pointer (sp) register: @example set_reg @{pc 0 sp 0x1000@} @end example @end deffn @deffn {Command} {get_reg} [-force] list Get register values from the target and return them as Tcl dictionary with pairs of register names and values. If option "-force" is set, the register values are read directly from the target, bypassing any caching. @itemize @item @var{list} ... List of register names @end itemize For example, the following command retrieves the values from the program counter (pc) and stack pointer (sp) register: @example get_reg @{pc sp@} @end example @end deffn @deffn {Command} {write_memory} address width data ['phys'] This function provides an efficient way to write to the target memory from a Tcl script. @itemize @item @var{address} ... target memory address @item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 @item @var{data} ... Tcl list with the elements to write @item ['phys'] ... treat the memory address as physical instead of virtual address @end itemize For example, the following command writes two 32 bit words into the target memory at address 0x20000000: @example write_memory 0x20000000 32 @{0xdeadbeef 0x00230500@} @end example @end deffn @deffn {Command} {read_memory} address width count ['phys'] This function provides an efficient way to read the target memory from a Tcl script. A Tcl list containing the requested memory elements is returned by this function. @itemize @item @var{address} ... target memory address @item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 @item @var{count} ... number of elements to read @item ['phys'] ... treat the memory address as physical instead of virtual address @end itemize For example, the following command reads two 32 bit words from the target memory at address 0x20000000: @example read_memory 0x20000000 32 2 @end example @end deffn @deffn {Command} {halt} [ms] @deffnx {Command} {wait_halt} [ms] The @command{halt} command first sends a halt request to the target, which @command{wait_halt} doesn't. Otherwise these behave the same: wait up to @var{ms} milliseconds, or 5 seconds if there is no parameter, for the target to halt (and enter debug mode). Using 0 as the @var{ms} parameter prevents OpenOCD from waiting. @quotation Warning On ARM cores, software using the @emph{wait for interrupt} operation often blocks the JTAG access needed by a @command{halt} command. This is because that operation also puts the core into a low power mode by gating the core clock; but the core clock is needed to detect JTAG clock transitions. One partial workaround uses adaptive clocking: when the core is interrupted the operation completes, then JTAG clocks are accepted at least until the interrupt handler completes. However, this workaround is often unusable since the processor, board, and JTAG adapter must all support adaptive JTAG clocking. Also, it can't work until an interrupt is issued. A more complete workaround is to not use that operation while you work with a JTAG debugger. Tasking environments generally have idle loops where the body is the @emph{wait for interrupt} operation. (On older cores, it is a coprocessor action; newer cores have a @option{wfi} instruction.) Such loops can just remove that operation, at the cost of higher power consumption (because the CPU is needlessly clocked). @end quotation @end deffn @deffn {Command} {resume} [address] Resume the target at its current code position, or the optional @var{address} if it is provided. @end deffn @deffn {Command} {step} [address] Single-step the target at its current code position, or the optional @var{address} if it is provided. @end deffn @anchor{resetcommand} @deffn {Command} {reset} @deffnx {Command} {reset run} @deffnx {Command} {reset halt} @deffnx {Command} {reset init} Perform as hard a reset as possible, using SRST if possible. @emph{All defined targets will be reset, and target events will fire during the reset sequence.} The optional parameter specifies what should happen after the reset. If there is no parameter, a @command{reset run} is executed. The other options will not work on all systems. @xref{Reset Configuration}. @itemize @minus @item @b{run} Let the target run @item @b{halt} Immediately halt the target @item @b{init} Immediately halt the target, and execute the reset-init script @end itemize @end deffn @deffn {Command} {soft_reset_halt} Requesting target halt and executing a soft reset. This is often used when a target cannot be reset and halted. The target, after reset is released begins to execute code. OpenOCD attempts to stop the CPU and then sets the program counter back to the reset vector. Unfortunately the code that was executed may have left the hardware in an unknown state. @end deffn @deffn {Command} {adapter assert} [signal [assert|deassert signal]] @deffnx {Command} {adapter deassert} [signal [assert|deassert signal]] Set values of reset signals. Without parameters returns current status of the signals. The @var{signal} parameter values may be @option{srst}, indicating that srst signal is to be asserted or deasserted, @option{trst}, indicating that trst signal is to be asserted or deasserted. The @command{reset_config} command should already have been used to configure how the board and the adapter treat these two signals, and to say if either signal is even present. @xref{Reset Configuration}. Trying to assert a signal that is not present triggers an error. If a signal is present on the adapter and not specified in the command, the signal will not be modified. @quotation Note TRST is specially handled. It actually signifies JTAG's @sc{reset} state. So if the board doesn't support the optional TRST signal, or it doesn't support it along with the specified SRST value, JTAG reset is triggered with TMS and TCK signals instead of the TRST signal. And no matter how that JTAG reset is triggered, once the scan chain enters @sc{reset} with TRST inactive, TAP @code{post-reset} events are delivered to all TAPs with handlers for that event. @end quotation @end deffn @anchor{memoryaccess} @section Memory access commands @cindex memory access These commands allow accesses of a specific size to the memory system. Often these are used to configure the current target in some special way. For example - one may need to write certain values to the SDRAM controller to enable SDRAM. @enumerate @item Use the @command{targets} (plural) command to change the current target. @item In system level scripts these commands are deprecated. Please use their TARGET object siblings to avoid making assumptions about what TAP is the current target, or about MMU configuration. @end enumerate @deffn {Command} {mdd} [phys] addr [count] @deffnx {Command} {mdw} [phys] addr [count] @deffnx {Command} {mdh} [phys] addr [count] @deffnx {Command} {mdb} [phys] addr [count] Display contents of address @var{addr}, as 64-bit doublewords (@command{mdd}), 32-bit words (@command{mdw}), 16-bit halfwords (@command{mdh}), or 8-bit bytes (@command{mdb}). When the current target has an MMU which is present and active, @var{addr} is interpreted as a virtual address. Otherwise, or if the optional @var{phys} flag is specified, @var{addr} is interpreted as a physical address. If @var{count} is specified, displays that many units. (If you want to process the data instead of displaying it, see the @code{read_memory} primitives.) @end deffn @deffn {Command} {mwd} [phys] addr doubleword [count] @deffnx {Command} {mww} [phys] addr word [count] @deffnx {Command} {mwh} [phys] addr halfword [count] @deffnx {Command} {mwb} [phys] addr byte [count] Writes the specified @var{doubleword} (64 bits), @var{word} (32 bits), @var{halfword} (16 bits), or @var{byte} (8-bit) value, at the specified address @var{addr}. When the current target has an MMU which is present and active, @var{addr} is interpreted as a virtual address. Otherwise, or if the optional @var{phys} flag is specified, @var{addr} is interpreted as a physical address. If @var{count} is specified, fills that many units of consecutive address. @end deffn @anchor{imageaccess} @section Image loading commands @cindex image loading @cindex image dumping @deffn {Command} {dump_image} filename address size Dump @var{size} bytes of target memory starting at @var{address} to the binary file named @var{filename}. @end deffn @deffn {Command} {fast_load} Loads an image stored in memory by @command{fast_load_image} to the current target. Must be preceded by fast_load_image. @end deffn @deffn {Command} {fast_load_image} filename address [@option{bin}|@option{ihex}|@option{elf}|@option{s19}] Normally you should be using @command{load_image} or GDB load. However, for testing purposes or when I/O overhead is significant(OpenOCD running on an embedded host), storing the image in memory and uploading the image to the target can be a way to upload e.g. multiple debug sessions when the binary does not change. Arguments are the same as @command{load_image}, but the image is stored in OpenOCD host memory, i.e. does not affect target. This approach is also useful when profiling target programming performance as I/O and target programming can easily be profiled separately. @end deffn @deffn {Command} {load_image} filename address [[@option{bin}|@option{ihex}|@option{elf}|@option{s19}] @option{min_addr} @option{max_length}] Load image from file @var{filename} to target memory offset by @var{address} from its load address. The file format may optionally be specified (@option{bin}, @option{ihex}, @option{elf}, or @option{s19}). In addition the following arguments may be specified: @var{min_addr} - ignore data below @var{min_addr} (this is w.r.t. to the target's load address + @var{address}) @var{max_length} - maximum number of bytes to load. @example proc load_image_bin @{fname foffset address length @} @{ # Load data from fname filename at foffset offset to # target at address. Load at most length bytes. load_image $fname [expr @{$address - $foffset@}] bin \ $address $length @} @end example @end deffn @deffn {Command} {test_image} filename [address [@option{bin}|@option{ihex}|@option{elf}]] Displays image section sizes and addresses as if @var{filename} were loaded into target memory starting at @var{address} (defaults to zero). The file format may optionally be specified (@option{bin}, @option{ihex}, or @option{elf}) @end deffn @deffn {Command} {verify_image} filename address [@option{bin}|@option{ihex}|@option{elf}] Verify @var{filename} against target memory starting at @var{address}. The file format may optionally be specified (@option{bin}, @option{ihex}, or @option{elf}) This will first attempt a comparison using a CRC checksum, if this fails it will try a binary compare. @end deffn @deffn {Command} {verify_image_checksum} filename address [@option{bin}|@option{ihex}|@option{elf}] Verify @var{filename} against target memory starting at @var{address}. The file format may optionally be specified (@option{bin}, @option{ihex}, or @option{elf}) This perform a comparison using a CRC checksum only @end deffn @section Breakpoint and Watchpoint commands @cindex breakpoint @cindex watchpoint CPUs often make debug modules accessible through JTAG, with hardware support for a handful of code breakpoints and data watchpoints. In addition, CPUs almost always support software breakpoints. @deffn {Command} {bp} [address len [@option{hw}]] With no parameters, lists all active breakpoints. Else sets a breakpoint on code execution starting at @var{address} for @var{length} bytes. This is a software breakpoint, unless @option{hw} is specified in which case it will be a hardware breakpoint. (@xref{arm9vectorcatch,,arm9 vector_catch}, or @pxref{xscalevectorcatch,,xscale vector_catch}, for similar mechanisms that do not consume hardware breakpoints.) @end deffn @deffn {Command} {rbp} @option{all} | address Remove the breakpoint at @var{address} or all breakpoints. @end deffn @deffn {Command} {rwp} address Remove data watchpoint on @var{address} @end deffn @deffn {Command} {wp} [address len [(@option{r}|@option{w}|@option{a}) [value [mask]]]] With no parameters, lists all active watchpoints. Else sets a data watchpoint on data from @var{address} for @var{length} bytes. The watch point is an "access" watchpoint unless the @option{r} or @option{w} parameter is provided, defining it as respectively a read or write watchpoint. If a @var{value} is provided, that value is used when determining if the watchpoint should trigger. The value may be first be masked using @var{mask} to mark ``don't care'' fields. @end deffn @section Real Time Transfer (RTT) Real Time Transfer (RTT) is an interface specified by SEGGER based on basic memory reads and writes to transfer data bidirectionally between target and host. The specification is independent of the target architecture. Every target that supports so called "background memory access", which means that the target memory can be accessed by the debugger while the target is running, can be used. This interface is especially of interest for targets without Serial Wire Output (SWO), such as ARM Cortex-M0, or where semihosting is not applicable because of real-time constraints. @quotation Note The current implementation supports only single target devices. @end quotation The data transfer between host and target device is organized through unidirectional up/down-channels for target-to-host and host-to-target communication, respectively. @quotation Note The current implementation does not respect channel buffer flags. They are used to determine what happens when writing to a full buffer, for example. @end quotation Channels are exposed via raw TCP/IP connections. One or more RTT servers can be assigned to each channel to make them accessible to an unlimited number of TCP/IP connections. @deffn {Command} {rtt setup} address size ID Configure RTT for the currently selected target. Once RTT is started, OpenOCD searches for a control block with the identifier @var{ID} starting at the memory address @var{address} within the next @var{size} bytes. @end deffn @deffn {Command} {rtt start} Start RTT. If the control block location is not known, OpenOCD starts searching for it. @end deffn @deffn {Command} {rtt stop} Stop RTT. @end deffn @deffn {Command} {rtt polling_interval} [interval] Display the polling interval. If @var{interval} is provided, set the polling interval. The polling interval determines (in milliseconds) how often the up-channels are checked for new data. @end deffn @deffn {Command} {rtt channels} Display a list of all channels and their properties. @end deffn @deffn {Command} {rtt channellist} Return a list of all channels and their properties as Tcl list. The list can be manipulated easily from within scripts. @end deffn @deffn {Command} {rtt server start} port channel Start a TCP server on @var{port} for the channel @var{channel}. @end deffn @deffn {Command} {rtt server stop} port Stop the TCP sever with port @var{port}. @end deffn The following example shows how to setup RTT using the SEGGER RTT implementation on the target device. @example resume rtt setup 0x20000000 2048 "SEGGER RTT" rtt start rtt server start 9090 0 @end example In this example, OpenOCD searches the control block with the ID "SEGGER RTT" starting at 0x20000000 for 2048 bytes. The RTT channel 0 is exposed through the TCP/IP port 9090. @section Misc Commands @cindex profiling @deffn {Command} {profile} seconds filename [start end] Profiling samples the CPU's program counter as quickly as possible, which is useful for non-intrusive stochastic profiling. Saves up to 10000 samples in @file{filename} using ``gmon.out'' format. Optional @option{start} and @option{end} parameters allow to limit the address range. @end deffn @deffn {Command} {version} [git] Returns a string identifying the version of this OpenOCD server. With option @option{git}, it returns the git version obtained at compile time through ``git describe''. @end deffn @deffn {Command} {virt2phys} virtual_address Requests the current target to map the specified @var{virtual_address} to its corresponding physical address, and displays the result. @end deffn @deffn {Command} {add_help_text} 'command_name' 'help-string' Add or replace help text on the given @var{command_name}. @end deffn @deffn {Command} {add_usage_text} 'command_name' 'help-string' Add or replace usage text on the given @var{command_name}. @end deffn @node Architecture and Core Commands @chapter Architecture and Core Commands @cindex Architecture Specific Commands @cindex Core Specific Commands Most CPUs have specialized JTAG operations to support debugging. OpenOCD packages most such operations in its standard command framework. Some of those operations don't fit well in that framework, so they are exposed here as architecture or implementation (core) specific commands. @anchor{armhardwaretracing} @section ARM Hardware Tracing @cindex tracing @cindex ETM @cindex ETB CPUs based on ARM cores may include standard tracing interfaces, based on an ``Embedded Trace Module'' (ETM) which sends voluminous address and data bus trace records to a ``Trace Port''. @itemize @item Development-oriented boards will sometimes provide a high speed trace connector for collecting that data, when the particular CPU supports such an interface. (The standard connector is a 38-pin Mictor, with both JTAG and trace port support.) Those trace connectors are supported by higher end JTAG adapters and some logic analyzer modules; frequently those modules can buffer several megabytes of trace data. Configuring an ETM coupled to such an external trace port belongs in the board-specific configuration file. @item If the CPU doesn't provide an external interface, it probably has an ``Embedded Trace Buffer'' (ETB) on the chip, which is a dedicated SRAM. 4KBytes is one common ETB size. Configuring an ETM coupled only to an ETB belongs in the CPU-specific (target) configuration file, since it works the same on all boards. @end itemize ETM support in OpenOCD doesn't seem to be widely used yet. @quotation Issues ETM support may be buggy, and at least some @command{etm config} parameters should be detected by asking the ETM for them. ETM trigger events could also implement a kind of complex hardware breakpoint, much more powerful than the simple watchpoint hardware exported by EmbeddedICE modules. @emph{Such breakpoints can be triggered even when using the dummy trace port driver}. It seems like a GDB hookup should be possible, as well as tracing only during specific states (perhaps @emph{handling IRQ 23} or @emph{calls foo()}). There should be GUI tools to manipulate saved trace data and help analyse it in conjunction with the source code. It's unclear how much of a common interface is shared with the current XScale trace support, or should be shared with eventual Nexus-style trace module support. At this writing (November 2009) only ARM7, ARM9, and ARM11 support for ETM modules is available. The code should be able to work with some newer cores; but not all of them support this original style of JTAG access. @end quotation @subsection ETM Configuration ETM setup is coupled with the trace port driver configuration. @deffn {Config Command} {etm config} target width mode clocking driver Declares the ETM associated with @var{target}, and associates it with a given trace port @var{driver}. @xref{traceportdrivers,,Trace Port Drivers}. Several of the parameters must reflect the trace port capabilities, which are a function of silicon capabilities (exposed later using @command{etm info}) and of what hardware is connected to that port (such as an external pod, or ETB). The @var{width} must be either 4, 8, or 16, except with ETMv3.0 and newer modules which may also support 1, 2, 24, 32, 48, and 64 bit widths. (With those versions, @command{etm info} also shows whether the selected port width and mode are supported.) The @var{mode} must be @option{normal}, @option{multiplexed}, or @option{demultiplexed}. The @var{clocking} must be @option{half} or @option{full}. @quotation Warning With ETMv3.0 and newer, the bits set with the @var{mode} and @var{clocking} parameters both control the mode. This modified mode does not map to the values supported by previous ETM modules, so this syntax is subject to change. @end quotation @quotation Note You can see the ETM registers using the @command{reg} command. Not all possible registers are present in every ETM. Most of the registers are write-only, and are used to configure what CPU activities are traced. @end quotation @end deffn @deffn {Command} {etm info} Displays information about the current target's ETM. This includes resource counts from the @code{ETM_CONFIG} register, as well as silicon capabilities (except on rather old modules). from the @code{ETM_SYS_CONFIG} register. @end deffn @deffn {Command} {etm status} Displays status of the current target's ETM and trace port driver: is the ETM idle, or is it collecting data? Did trace data overflow? Was it triggered? @end deffn @deffn {Command} {etm tracemode} [type context_id_bits cycle_accurate branch_output] Displays what data that ETM will collect. If arguments are provided, first configures that data. When the configuration changes, tracing is stopped and any buffered trace data is invalidated. @itemize @item @var{type} ... describing how data accesses are traced, when they pass any ViewData filtering that was set up. The value is one of @option{none} (save nothing), @option{data} (save data), @option{address} (save addresses), @option{all} (save data and addresses) @item @var{context_id_bits} ... 0, 8, 16, or 32 @item @var{cycle_accurate} ... @option{enable} or @option{disable} cycle-accurate instruction tracing. Before ETMv3, enabling this causes much extra data to be recorded. @item @var{branch_output} ... @option{enable} or @option{disable}. Disable this unless you need to try reconstructing the instruction trace stream without an image of the code. @end itemize @end deffn @deffn {Command} {etm trigger_debug} (@option{enable}|@option{disable}) Displays whether ETM triggering debug entry (like a breakpoint) is enabled or disabled, after optionally modifying that configuration. The default behaviour is @option{disable}. Any change takes effect after the next @command{etm start}. By using script commands to configure ETM registers, you can make the processor enter debug state automatically when certain conditions, more complex than supported by the breakpoint hardware, happen. @end deffn @subsection ETM Trace Operation After setting up the ETM, you can use it to collect data. That data can be exported to files for later analysis. It can also be parsed with OpenOCD, for basic sanity checking. To configure what is being traced, you will need to write various trace registers using @command{reg ETM_*} commands. For the definitions of these registers, read ARM publication @emph{IHI 0014, ``Embedded Trace Macrocell, Architecture Specification''}. Be aware that most of the relevant registers are write-only, and that ETM resources are limited. There are only a handful of address comparators, data comparators, counters, and so on. Examples of scenarios you might arrange to trace include: @itemize @item Code flow within a function, @emph{excluding} subroutines it calls. Use address range comparators to enable tracing for instruction access within that function's body. @item Code flow within a function, @emph{including} subroutines it calls. Use the sequencer and address comparators to activate tracing on an ``entered function'' state, then deactivate it by exiting that state when the function's exit code is invoked. @item Code flow starting at the fifth invocation of a function, combining one of the above models with a counter. @item CPU data accesses to the registers for a particular device, using address range comparators and the ViewData logic. @item Such data accesses only during IRQ handling, combining the above model with sequencer triggers which on entry and exit to the IRQ handler. @item @emph{... more} @end itemize At this writing, September 2009, there are no Tcl utility procedures to help set up any common tracing scenarios. @deffn {Command} {etm analyze} Reads trace data into memory, if it wasn't already present. Decodes and prints the data that was collected. @end deffn @deffn {Command} {etm dump} filename Stores the captured trace data in @file{filename}. @end deffn @deffn {Command} {etm image} filename [base_address] [type] Opens an image file. @end deffn @deffn {Command} {etm load} filename Loads captured trace data from @file{filename}. @end deffn @deffn {Command} {etm start} Starts trace data collection. @end deffn @deffn {Command} {etm stop} Stops trace data collection. @end deffn @anchor{traceportdrivers} @subsection Trace Port Drivers To use an ETM trace port it must be associated with a driver. @deffn {Trace Port Driver} {dummy} Use the @option{dummy} driver if you are configuring an ETM that's not connected to anything (on-chip ETB or off-chip trace connector). @emph{This driver lets OpenOCD talk to the ETM, but it does not expose any trace data collection.} @deffn {Config Command} {etm_dummy config} target Associates the ETM for @var{target} with a dummy driver. @end deffn @end deffn @deffn {Trace Port Driver} {etb} Use the @option{etb} driver if you are configuring an ETM to use on-chip ETB memory. @deffn {Config Command} {etb config} target etb_tap Associates the ETM for @var{target} with the ETB at @var{etb_tap}. You can see the ETB registers using the @command{reg} command. @end deffn @deffn {Command} {etb trigger_percent} [percent] This displays, or optionally changes, ETB behavior after the ETM's configured @emph{trigger} event fires. It controls how much more trace data is saved after the (single) trace trigger becomes active. @itemize @item The default corresponds to @emph{trace around} usage, recording 50 percent data before the event and the rest afterwards. @item The minimum value of @var{percent} is 2 percent, recording almost exclusively data before the trigger. Such extreme @emph{trace before} usage can help figure out what caused that event to happen. @item The maximum value of @var{percent} is 100 percent, recording data almost exclusively after the event. This extreme @emph{trace after} usage might help sort out how the event caused trouble. @end itemize @c REVISIT allow "break" too -- enter debug mode. @end deffn @end deffn @anchor{armcrosstrigger} @section ARM Cross-Trigger Interface @cindex CTI The ARM Cross-Trigger Interface (CTI) is a generic CoreSight component that connects event sources like tracing components or CPU cores with each other through a common trigger matrix (CTM). For ARMv8 architecture, a CTI is mandatory for core run control and each core has an individual CTI instance attached to it. OpenOCD has limited support for CTI using the @emph{cti} group of commands. @deffn {Command} {cti create} cti_name @option{-dap} dap_name @option{-ap-num} apn @option{-baseaddr} base_address Creates a CTI instance @var{cti_name} on the DAP instance @var{dap_name} on MEM-AP @var{apn}. On ADIv5 DAP @var{apn} is the numeric index of the DAP AP the CTI is connected to. On ADIv6 DAP @var{apn} is the base address of the DAP AP the CTI is connected to. The @var{base_address} must match the base address of the CTI on the respective MEM-AP. All arguments are mandatory. This creates a new command @command{$cti_name} which is used for various purposes including additional configuration. @end deffn @deffn {Command} {$cti_name enable} @option{on|off} Enable (@option{on}) or disable (@option{off}) the CTI. @end deffn @deffn {Command} {$cti_name dump} Displays a register dump of the CTI. @end deffn @deffn {Command} {$cti_name write} @var{reg_name} @var{value} Write @var{value} to the CTI register with the symbolic name @var{reg_name}. @end deffn @deffn {Command} {$cti_name read} @var{reg_name} Print the value read from the CTI register with the symbolic name @var{reg_name}. @end deffn @deffn {Command} {$cti_name ack} @var{event} Acknowledge a CTI @var{event}. @end deffn @deffn {Command} {$cti_name channel} @var{channel_number} @var{operation} Perform a specific channel operation, the possible operations are: gate, ungate, set, clear and pulse @end deffn @deffn {Command} {$cti_name testmode} @option{on|off} Enable (@option{on}) or disable (@option{off}) the integration test mode of the CTI. @end deffn @deffn {Command} {cti names} Prints a list of names of all CTI objects created. This command is mainly useful in TCL scripting. @end deffn @section Generic ARM @cindex ARM These commands should be available on all ARM processors. They are available in addition to other core-specific commands that may be available. @deffn {Command} {arm core_state} [@option{arm}|@option{thumb}] Displays the core_state, optionally changing it to process either @option{arm} or @option{thumb} instructions. The target may later be resumed in the currently set core_state. (Processors may also support the Jazelle state, but that is not currently supported in OpenOCD.) @end deffn @deffn {Command} {arm disassemble} address [count [@option{thumb}]] @cindex disassemble Disassembles @var{count} instructions starting at @var{address}. If @var{count} is not specified, a single instruction is disassembled. If @option{thumb} is specified, or the low bit of the address is set, Thumb2 (mixed 16/32-bit) instructions are used; else ARM (32-bit) instructions are used. (Processors may also support the Jazelle state, but those instructions are not currently understood by OpenOCD.) Note that all Thumb instructions are Thumb2 instructions, so older processors (without Thumb2 support) will still see correct disassembly of Thumb code. Also, ThumbEE opcodes are the same as Thumb2, with a handful of exceptions. ThumbEE disassembly currently has no explicit support. @end deffn @deffn {Command} {arm mcr} pX op1 CRn CRm op2 value Write @var{value} to a coprocessor @var{pX} register passing parameters @var{CRn}, @var{CRm}, opcodes @var{opc1} and @var{opc2}, and using the MCR instruction. (Parameter sequence matches the ARM instruction, but omits an ARM register.) @end deffn @deffn {Command} {arm mrc} pX coproc op1 CRn CRm op2 Read a coprocessor @var{pX} register passing parameters @var{CRn}, @var{CRm}, opcodes @var{opc1} and @var{opc2}, and the MRC instruction. Returns the result so it can be manipulated by Jim scripts. (Parameter sequence matches the ARM instruction, but omits an ARM register.) @end deffn @deffn {Command} {arm reg} Display a table of all banked core registers, fetching the current value from every core mode if necessary. @end deffn @deffn {Command} {arm semihosting} [@option{enable}|@option{disable}] @cindex ARM semihosting Display status of semihosting, after optionally changing that status. Semihosting allows for code executing on an ARM target to use the I/O facilities on the host computer i.e. the system where OpenOCD is running. The target application must be linked against a library implementing the ARM semihosting convention that forwards operation requests by using a special SVC instruction that is trapped at the Supervisor Call vector by OpenOCD. @end deffn @deffn {Command} {arm semihosting_redirect} (@option{disable} | @option{tcp} <port> [@option{debug}|@option{stdio}|@option{all}]) @cindex ARM semihosting Redirect semihosting messages to a specified TCP port. This command redirects debug (READC, WRITEC and WRITE0) and stdio (READ, WRITE) semihosting operations to the specified TCP port. The command allows to select which type of operations to redirect (debug, stdio, all (default)). Note: for stdio operations, only I/O from/to ':tt' file descriptors are redirected. @end deffn @deffn {Command} {arm semihosting_cmdline} [@option{enable}|@option{disable}] @cindex ARM semihosting Set the command line to be passed to the debugger. @example arm semihosting_cmdline argv0 argv1 argv2 ... @end example This option lets one set the command line arguments to be passed to the program. The first argument (argv0) is the program name in a standard C environment (argv[0]). Depending on the program (not much programs look at argv[0]), argv0 is ignored and can be any string. @end deffn @deffn {Command} {arm semihosting_fileio} [@option{enable}|@option{disable}] @cindex ARM semihosting Display status of semihosting fileio, after optionally changing that status. Enabling this option forwards semihosting I/O to GDB process using the File-I/O remote protocol extension. This is especially useful for interacting with remote files or displaying console messages in the debugger. @end deffn @deffn {Command} {arm semihosting_resexit} [@option{enable}|@option{disable}] @cindex ARM semihosting Enable resumable SEMIHOSTING_SYS_EXIT. When SEMIHOSTING_SYS_EXIT is called outside a debug session, things are simple, the openocd process calls exit() and passes the value returned by the target. When SEMIHOSTING_SYS_EXIT is called during a debug session, by default execution returns to the debugger, leaving the debugger in a HALT state, similar to the state entered when encountering a break. In some use cases, it is useful to have SEMIHOSTING_SYS_EXIT return normally, as any semihosting call, and do not break to the debugger. The standard allows this to happen, but the condition to trigger it is a bit obscure ("by performing an RDI_Execute request or equivalent"). To make the SEMIHOSTING_SYS_EXIT call return normally, enable this option (default: disabled). @end deffn @deffn {Command} {arm semihosting_read_user_param} @cindex ARM semihosting Read parameter of the semihosting call from the target. Usable in semihosting-user-cmd-0x10* event handlers, returning a string. When the target makes semihosting call with operation number from range 0x100- 0x107, an optional string parameter can be passed to the server. This parameter is valid during the run of the event handlers and is accessible with this command. @end deffn @deffn {Command} {arm semihosting_basedir} [dir] @cindex ARM semihosting Set the base directory for semihosting I/O, either an absolute path or a path relative to OpenOCD working directory. Use "." for the current directory. @end deffn @section ARMv4 and ARMv5 Architecture @cindex ARMv4 @cindex ARMv5 The ARMv4 and ARMv5 architectures are widely used in embedded systems, and introduced core parts of the instruction set in use today. That includes the Thumb instruction set, introduced in the ARMv4T variant. @subsection ARM7 and ARM9 specific commands @cindex ARM7 @cindex ARM9 These commands are specific to ARM7 and ARM9 cores, like ARM7TDMI, ARM720T, ARM9TDMI, ARM920T or ARM926EJ-S. They are available in addition to the ARM commands, and any other core-specific commands that may be available. @deffn {Command} {arm7_9 dbgrq} [@option{enable}|@option{disable}] Displays the value of the flag controlling use of the EmbeddedIce DBGRQ signal to force entry into debug mode, instead of breakpoints. If a boolean parameter is provided, first assigns that flag. This should be safe for all but ARM7TDMI-S cores (like NXP LPC). This feature is enabled by default on most ARM9 cores, including ARM9TDMI, ARM920T, and ARM926EJ-S. @end deffn @deffn {Command} {arm7_9 dcc_downloads} [@option{enable}|@option{disable}] @cindex DCC Displays the value of the flag controlling use of the debug communications channel (DCC) to write larger (>128 byte) amounts of memory. If a boolean parameter is provided, first assigns that flag. DCC downloads offer a huge speed increase, but might be unsafe, especially with targets running at very low speeds. This command was introduced with OpenOCD rev. 60, and requires a few bytes of working area. @end deffn @deffn {Command} {arm7_9 fast_memory_access} [@option{enable}|@option{disable}] Displays the value of the flag controlling use of memory writes and reads that don't check completion of the operation. If a boolean parameter is provided, first assigns that flag. This provides a huge speed increase, especially with USB JTAG cables (FT2232), but might be unsafe if used with targets running at very low speeds, like the 32kHz startup clock of an AT91RM9200. @end deffn @subsection ARM9 specific commands @cindex ARM9 ARM9-family cores are built around ARM9TDMI or ARM9E (including ARM9EJS) integer processors. Such cores include the ARM920T, ARM926EJ-S, and ARM966. @c 9-june-2009: tried this on arm920t, it didn't work. @c no-params always lists nothing caught, and that's how it acts. @c 23-oct-2009: doesn't work _consistently_ ... as if the ICE @c versions have different rules about when they commit writes. @anchor{arm9vectorcatch} @deffn {Command} {arm9 vector_catch} [@option{all}|@option{none}|list] @cindex vector_catch Vector Catch hardware provides a sort of dedicated breakpoint for hardware events such as reset, interrupt, and abort. You can use this to conserve normal breakpoint resources, so long as you're not concerned with code that branches directly to those hardware vectors. This always finishes by listing the current configuration. If parameters are provided, it first reconfigures the vector catch hardware to intercept @option{all} of the hardware vectors, @option{none} of them, or a list with one or more of the following: @option{reset} @option{undef} @option{swi} @option{pabt} @option{dabt} @option{irq} @option{fiq}. @end deffn @subsection ARM920T specific commands @cindex ARM920T These commands are available to ARM920T based CPUs, which are implementations of the ARMv4T architecture built using the ARM9TDMI integer core. They are available in addition to the ARM, ARM7/ARM9, and ARM9 commands. @deffn {Command} {arm920t cache_info} Print information about the caches found. This allows to see whether your target is an ARM920T (2x16kByte cache) or ARM922T (2x8kByte cache). @end deffn @deffn {Command} {arm920t cp15} regnum [value] Display cp15 register @var{regnum}; else if a @var{value} is provided, that value is written to that register. This uses "physical access" and the register number is as shown in bits 38..33 of table 9-9 in the ARM920T TRM. (Not all registers can be written.) @end deffn @deffn {Command} {arm920t read_cache} filename Dump the content of ICache and DCache to a file named @file{filename}. @end deffn @deffn {Command} {arm920t read_mmu} filename Dump the content of the ITLB and DTLB to a file named @file{filename}. @end deffn @subsection ARM926ej-s specific commands @cindex ARM926ej-s These commands are available to ARM926ej-s based CPUs, which are implementations of the ARMv5TEJ architecture based on the ARM9EJ-S integer core. They are available in addition to the ARM, ARM7/ARM9, and ARM9 commands. The Feroceon cores also support these commands, although they are not built from ARM926ej-s designs. @deffn {Command} {arm926ejs cache_info} Print information about the caches found. @end deffn @subsection ARM966E specific commands @cindex ARM966E These commands are available to ARM966 based CPUs, which are implementations of the ARMv5TE architecture. They are available in addition to the ARM, ARM7/ARM9, and ARM9 commands. @deffn {Command} {arm966e cp15} regnum [value] Display cp15 register @var{regnum}; else if a @var{value} is provided, that value is written to that register. The six bit @var{regnum} values are bits 37..32 from table 7-2 of the ARM966E-S TRM. There is no current control over bits 31..30 from that table, as required for BIST support. @end deffn @subsection XScale specific commands @cindex XScale Some notes about the debug implementation on the XScale CPUs: The XScale CPU provides a special debug-only mini-instruction cache (mini-IC) in which exception vectors and target-resident debug handler code are placed by OpenOCD. In order to get access to the CPU, OpenOCD must point vector 0 (the reset vector) to the entry of the debug handler. However, this means that the complete first cacheline in the mini-IC is marked valid, which makes the CPU fetch all exception handlers from the mini-IC, ignoring the code in RAM. To address this situation, OpenOCD provides the @code{xscale vector_table} command, which allows the user to explicitly write individual entries to either the high or low vector table stored in the mini-IC. It is recommended to place a pc-relative indirect branch in the vector table, and put the branch destination somewhere in memory. Doing so makes sure the code in the vector table stays constant regardless of code layout in memory: @example _vectors: ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] .org 0x100 .long real_reset_vector .long real_ui_handler .long real_swi_handler .long real_pf_abort .long real_data_abort .long 0 /* unused */ .long real_irq_handler .long real_fiq_handler @end example Alternatively, you may choose to keep some or all of the mini-IC vector table entries synced with those written to memory by your system software. The mini-IC can not be modified while the processor is executing, but for each vector table entry not previously defined using the @code{xscale vector_table} command, OpenOCD will copy the value from memory to the mini-IC every time execution resumes from a halt. This is done for both high and low vector tables (although the table not in use may not be mapped to valid memory, and in this case that copy operation will silently fail). This means that you will need to briefly halt execution at some strategic point during system start-up; e.g., after the software has initialized the vector table, but before exceptions are enabled. A breakpoint can be used to accomplish this once the appropriate location in the start-up code has been identified. A watchpoint over the vector table region is helpful in finding the location if you're not sure. Note that the same situation exists any time the vector table is modified by the system software. The debug handler must be placed somewhere in the address space using the @code{xscale debug_handler} command. The allowed locations for the debug handler are either (0x800 - 0x1fef800) or (0xfe000800 - 0xfffff800). The default value is 0xfe000800. XScale has resources to support two hardware breakpoints and two watchpoints. However, the following restrictions on watchpoint functionality apply: (1) the value and mask arguments to the @code{wp} command are not supported, (2) the watchpoint length must be a power of two and not less than four, and can not be greater than the watchpoint address, and (3) a watchpoint with a length greater than four consumes all the watchpoint hardware resources. This means that at any one time, you can have enabled either two watchpoints with a length of four, or one watchpoint with a length greater than four. These commands are available to XScale based CPUs, which are implementations of the ARMv5TE architecture. @deffn {Command} {xscale analyze_trace} Displays the contents of the trace buffer. @end deffn @deffn {Command} {xscale cache_clean_address} address Changes the address used when cleaning the data cache. @end deffn @deffn {Command} {xscale cache_info} Displays information about the CPU caches. @end deffn @deffn {Command} {xscale cp15} regnum [value] Display cp15 register @var{regnum}; else if a @var{value} is provided, that value is written to that register. @end deffn @deffn {Command} {xscale debug_handler} target address Changes the address used for the specified target's debug handler. @end deffn @deffn {Command} {xscale dcache} [@option{enable}|@option{disable}] Enables or disable the CPU's data cache. @end deffn @deffn {Command} {xscale dump_trace} filename Dumps the raw contents of the trace buffer to @file{filename}. @end deffn @deffn {Command} {xscale icache} [@option{enable}|@option{disable}] Enables or disable the CPU's instruction cache. @end deffn @deffn {Command} {xscale mmu} [@option{enable}|@option{disable}] Enables or disable the CPU's memory management unit. @end deffn @deffn {Command} {xscale trace_buffer} [@option{enable}|@option{disable} [@option{fill} [n] | @option{wrap}]] Displays the trace buffer status, after optionally enabling or disabling the trace buffer and modifying how it is emptied. @end deffn @deffn {Command} {xscale trace_image} filename [offset [type]] Opens a trace image from @file{filename}, optionally rebasing its segment addresses by @var{offset}. The image @var{type} may be one of @option{bin} (binary), @option{ihex} (Intel hex), @option{elf} (ELF file), @option{s19} (Motorola s19), @option{mem}, or @option{builder}. @end deffn @anchor{xscalevectorcatch} @deffn {Command} {xscale vector_catch} [mask] @cindex vector_catch Display a bitmask showing the hardware vectors to catch. If the optional parameter is provided, first set the bitmask to that value. The mask bits correspond with bit 16..23 in the DCSR: @example 0x01 Trap Reset 0x02 Trap Undefined Instructions 0x04 Trap Software Interrupt 0x08 Trap Prefetch Abort 0x10 Trap Data Abort 0x20 reserved 0x40 Trap IRQ 0x80 Trap FIQ @end example @end deffn @deffn {Command} {xscale vector_table} [(@option{low}|@option{high}) index value] @cindex vector_table Set an entry in the mini-IC vector table. There are two tables: one for low vectors (at 0x00000000), and one for high vectors (0xFFFF0000), each holding the 8 exception vectors. @var{index} can be 1-7, because vector 0 points to the debug handler entry and can not be overwritten. @var{value} holds the 32-bit opcode that is placed in the mini-IC. Without arguments, the current settings are displayed. @end deffn @section ARMv6 Architecture @cindex ARMv6 @subsection ARM11 specific commands @cindex ARM11 @deffn {Command} {arm11 memwrite burst} [@option{enable}|@option{disable}] Displays the value of the memwrite burst-enable flag, which is enabled by default. If a boolean parameter is provided, first assigns that flag. Burst writes are only used for memory writes larger than 1 word. They improve performance by assuming that the CPU has read each data word over JTAG and completed its write before the next word arrives, instead of polling for a status flag to verify that completion. This is usually safe, because JTAG runs much slower than the CPU. @end deffn @deffn {Command} {arm11 memwrite error_fatal} [@option{enable}|@option{disable}] Displays the value of the memwrite error_fatal flag, which is enabled by default. If a boolean parameter is provided, first assigns that flag. When set, certain memory write errors cause earlier transfer termination. @end deffn @deffn {Command} {arm11 step_irq_enable} [@option{enable}|@option{disable}] Displays the value of the flag controlling whether IRQs are enabled during single stepping; they are disabled by default. If a boolean parameter is provided, first assigns that. @end deffn @deffn {Command} {arm11 vcr} [value] @cindex vector_catch Displays the value of the @emph{Vector Catch Register (VCR)}, coprocessor 14 register 7. If @var{value} is defined, first assigns that. Vector Catch hardware provides dedicated breakpoints for certain hardware events. The specific bit values are core-specific (as in fact is using coprocessor 14 register 7 itself) but all current ARM11 cores @emph{except the ARM1176} use the same six bits. @end deffn @section ARMv7 and ARMv8 Architecture @cindex ARMv7 @cindex ARMv8 @subsection ARMv7-A specific commands @cindex Cortex-A @deffn {Command} {cortex_a cache_info} display information about target caches @end deffn @deffn {Command} {cortex_a dacrfixup} [@option{on}|@option{off}] Work around issues with software breakpoints when the program text is mapped read-only by the operating system. This option sets the CP15 DACR to "all-manager" to bypass MMU permission checks on memory access. Defaults to 'off'. @end deffn @deffn {Command} {cortex_a dbginit} Initialize core debug Enables debug by unlocking the Software Lock and clearing sticky powerdown indications @end deffn @deffn {Command} {cortex_a smp} [on|off] Display/set the current SMP mode @end deffn @deffn {Command} {cortex_a smp_gdb} [core_id] Display/set the current core displayed in GDB @end deffn @deffn {Command} {cortex_a maskisr} [@option{on}|@option{off}] Selects whether interrupts will be processed when single stepping @end deffn @deffn {Command} {cache_config l2x} [base way] configure l2x cache @end deffn @deffn {Command} {cortex_a mmu dump} [@option{0}|@option{1}|@option{addr} address [@option{num_entries}]] Dump the MMU translation table from TTB0 or TTB1 register, or from physical memory location @var{address}. When dumping the table from @var{address}, print at most @var{num_entries} page table entries. @var{num_entries} is optional, if omitted, the maximum possible (4096) entries are printed. @end deffn @subsection ARMv7-R specific commands @cindex Cortex-R @deffn {Command} {cortex_r4 dbginit} Initialize core debug Enables debug by unlocking the Software Lock and clearing sticky powerdown indications @end deffn @deffn {Command} {cortex_r4 maskisr} [@option{on}|@option{off}] Selects whether interrupts will be processed when single stepping @end deffn @subsection ARM CoreSight TPIU and SWO specific commands @cindex tracing @cindex SWO @cindex SWV @cindex TPIU ARM CoreSight provides several modules to generate debugging information internally (ITM, DWT and ETM). Their output is directed through TPIU or SWO modules to be captured externally either on an SWO pin (this configuration is called SWV) or on a synchronous parallel trace port. ARM CoreSight provides independent HW blocks named TPIU and SWO each with its own functionality. Embedded in Cortex-M3 and M4, ARM provides an optional HW block that includes both TPIU and SWO functionalities and is again named TPIU, which causes quite some confusion. The registers map of all the TPIU and SWO implementations allows using a single driver that detects at runtime the features available. The @command{tpiu} is used for either TPIU or SWO. A convenient alias @command{swo} is available to help distinguish, in scripts, the commands for SWO from the commands for TPIU. @deffn {Command} {swo} ... Alias of @command{tpiu ...}. Can be used in scripts to distinguish the commands for SWO from the commands for TPIU. @end deffn @deffn {Command} {tpiu create} tpiu_name configparams... Creates a TPIU or a SWO object. The two commands are equivalent. Add the object in a list and add new commands (@command{@var{tpiu_name}}) which are used for various purposes including additional configuration. @itemize @bullet @item @var{tpiu_name} -- the name of the TPIU or SWO object. This name is also used to create the object's command, referred to here as @command{$tpiu_name}, and in other places where the TPIU or SWO needs to be identified. @item @var{configparams} -- all parameters accepted by @command{$tpiu_name configure} are permitted. You @emph{must} set here the AP and MEM_AP base_address through @code{-dap @var{dap_name}}, @code{-ap-num @var{ap_number}} and @code{-baseaddr @var{base_address}}. @end itemize @end deffn @deffn {Command} {tpiu names} Lists all the TPIU or SWO objects created so far. The two commands are equivalent. @end deffn @deffn {Command} {tpiu init} Initialize all registered TPIU and SWO. The two commands are equivalent. These commands are used internally during initialization. They can be issued at any time after the initialization, too. @end deffn @deffn {Command} {$tpiu_name cget} queryparm Each configuration parameter accepted by @command{$tpiu_name configure} can be individually queried, to return its current value. The @var{queryparm} is a parameter name accepted by that command, such as @code{-dap}. @end deffn @deffn {Command} {$tpiu_name configure} configparams... The options accepted by this command may also be specified as parameters to @command{tpiu create}. Their values can later be queried one at a time by using the @command{$tpiu_name cget} command. @itemize @bullet @item @code{-dap} @var{dap_name} -- names the DAP used to access this TPIU. @xref{dapdeclaration,,DAP declaration}, on how to create and manage DAP instances. @item @code{-ap-num} @var{ap_number} -- sets DAP access port for TPIU. On ADIv5 DAP @var{ap_number} is the numeric index of the DAP AP the TPIU is connected to. On ADIv6 DAP @var{ap_number} is the base address of the DAP AP the TPIU is connected to. @item @code{-baseaddr} @var{base_address} -- sets the TPIU @var{base_address} where to access the TPIU in the DAP AP memory space. @item @code{-protocol} (@option{sync}|@option{uart}|@option{manchester}) -- sets the protocol used for trace data: @itemize @minus @item @option{sync} -- synchronous parallel trace output mode, using @var{port_width} data bits (default); @item @option{uart} -- use asynchronous SWO mode with NRZ (same as regular UART 8N1) coding; @item @option{manchester} -- use asynchronous SWO mode with Manchester coding. @end itemize @item @code{-event} @var{event_name} @var{event_body} -- assigns an event handler, a TCL string which is evaluated when the event is triggered. The events @code{pre-enable}, @code{post-enable}, @code{pre-disable} and @code{post-disable} are defined for TPIU/SWO. A typical use case for the event @code{pre-enable} is to enable the trace clock of the TPIU. @item @code{-output} (@option{external}|@option{:}@var{port}|@var{filename}|@option{-}) -- specifies the destination of the trace data: @itemize @minus @item @option{external} -- configure TPIU/SWO to let user capture trace output externally, either with an additional UART or with a logic analyzer (default); @item @option{-} -- configure TPIU/SWO and debug adapter to gather trace data and forward it to @command{tcl_trace} command; @item @option{:}@var{port} -- configure TPIU/SWO and debug adapter to gather trace data, open a TCP server at port @var{port} and send the trace data to each connected client; @item @var{filename} -- configure TPIU/SWO and debug adapter to gather trace data and append it to @var{filename}, which can be either a regular file or a named pipe. @end itemize @item @code{-traceclk} @var{TRACECLKIN_freq} -- mandatory parameter. Specifies the frequency in Hz of the trace clock. For the TPIU embedded in Cortex-M3 or M4, this is usually the same frequency as HCLK. For protocol @option{sync} this is twice the frequency of the pin data rate. @item @code{-pin-freq} @var{trace_freq} -- specifies the expected data rate in Hz of the SWO pin. Parameter used only on protocols @option{uart} and @option{manchester}. Can be omitted to let the adapter driver select the maximum supported rate automatically. @item @code{-port-width} @var{port_width} -- sets to @var{port_width} the width of the synchronous parallel port used for trace output. Parameter used only on protocol @option{sync}. If not specified, default value is @var{1}. @item @code{-formatter} (@option{0}|@option{1}) -- specifies if the formatter should be enabled. Parameter used only on protocol @option{sync}. If not specified, default value is @var{0}. @end itemize @end deffn @deffn {Command} {$tpiu_name enable} Uses the parameters specified by the previous @command{$tpiu_name configure} to configure and enable the TPIU or the SWO. If required, the adapter is also configured and enabled to receive the trace data. This command can be used before @command{init}, but it will take effect only after the @command{init}. @end deffn @deffn {Command} {$tpiu_name disable} Disable the TPIU or the SWO, terminating the receiving of the trace data. @end deffn Example usage: @enumerate @item STM32L152 board is programmed with an application that configures PLL to provide core clock with 24MHz frequency; to use ITM output it's enough to: @example #include <libopencm3/cm3/itm.h> ... ITM_STIM8(0) = c; ... @end example (the most obvious way is to use the first stimulus port for printf, for that this ITM_STIM8 assignment can be used inside _write(); to make it blocking to avoid data loss, add @code{while (!(ITM_STIM8(0) & ITM_STIM_FIFOREADY));}); @item An FT2232H UART is connected to the SWO pin of the board; @item Commands to configure UART for 12MHz baud rate: @example $ setserial /dev/ttyUSB1 spd_cust divisor 5 $ stty -F /dev/ttyUSB1 38400 @end example (FT2232H's base frequency is 60MHz, spd_cust allows to alias 38400 baud with our custom divisor to get 12MHz) @item @code{itmdump -f /dev/ttyUSB1 -d1} @item OpenOCD invocation line: @example openocd -f interface/stlink.cfg \ -c "transport select hla_swd" \ -f target/stm32l1.cfg \ -c "stm32l1.tpiu configure -protocol uart" \ -c "stm32l1.tpiu configure -traceclk 24000000 -pin-freq 12000000" \ -c "stm32l1.tpiu enable" @end example @end enumerate @subsection ARMv7-M specific commands @cindex tracing @cindex SWO @cindex SWV @cindex ITM @cindex ETM @deffn {Command} {itm port} @var{port} (@option{0}|@option{1}|@option{on}|@option{off}) Enable or disable trace output for ITM stimulus @var{port} (counting from 0). Port 0 is enabled on target creation automatically. @end deffn @deffn {Command} {itm ports} (@option{0}|@option{1}|@option{on}|@option{off}) Enable or disable trace output for all ITM stimulus ports. @end deffn @subsection Cortex-M specific commands @cindex Cortex-M @deffn {Command} {cortex_m maskisr} (@option{auto}|@option{on}|@option{off}|@option{steponly}) Control masking (disabling) interrupts during target step/resume. The @option{auto} option handles interrupts during stepping in a way that they get served but don't disturb the program flow. The step command first allows pending interrupt handlers to execute, then disables interrupts and steps over the next instruction where the core was halted. After the step interrupts are enabled again. If the interrupt handlers don't complete within 500ms, the step command leaves with the core running. The @option{steponly} option disables interrupts during single-stepping but enables them during normal execution. This can be used as a partial workaround for 702596 erratum in Cortex-M7 r0p1. See "Cortex-M7 (AT610) and Cortex-M7 with FPU (AT611) Software Developer Errata Notice" from ARM for further details. Note that a free hardware (FPB) breakpoint is required for the @option{auto} option. If no breakpoint is available at the time of the step, then the step is taken with interrupts enabled, i.e. the same way the @option{off} option does. Default is @option{auto}. @end deffn @deffn {Command} {cortex_m vector_catch} [@option{all}|@option{none}|list] @cindex vector_catch Vector Catch hardware provides dedicated breakpoints for certain hardware events. Parameters request interception of @option{all} of these hardware event vectors, @option{none} of them, or one or more of the following: @option{hard_err} for a HardFault exception; @option{mm_err} for a MemManage exception; @option{bus_err} for a BusFault exception; @option{irq_err}, @option{state_err}, @option{chk_err}, or @option{nocp_err} for various UsageFault exceptions; or @option{reset}. If NVIC setup code does not enable them, MemManage, BusFault, and UsageFault exceptions are mapped to HardFault. UsageFault checks for divide-by-zero and unaligned access must also be explicitly enabled. This finishes by listing the current vector catch configuration. @end deffn @deffn {Command} {cortex_m reset_config} (@option{sysresetreq}|@option{vectreset}) Control reset handling if hardware srst is not fitted @xref{reset_config,,reset_config}. @itemize @minus @item @option{sysresetreq} use AIRCR SYSRESETREQ to reset system. @item @option{vectreset} use AIRCR VECTRESET to reset system (default). @end itemize Using @option{vectreset} is a safe option for Cortex-M3, M4 and M7 cores. This however has the disadvantage of only resetting the core, all peripherals are unaffected. A solution would be to use a @code{reset-init} event handler to manually reset the peripherals. @xref{targetevents,,Target Events}. Cortex-M0, M0+ and M1 do not support @option{vectreset}, use @option{sysresetreq} instead. @end deffn @subsection ARMv8-A specific commands @cindex ARMv8-A @cindex aarch64 @deffn {Command} {aarch64 cache_info} Display information about target caches @end deffn @deffn {Command} {aarch64 dbginit} This command enables debugging by clearing the OS Lock and sticky power-down and reset indications. It also establishes the expected, basic cross-trigger configuration the aarch64 target code relies on. In a configuration file, the command would typically be called from a @code{reset-end} or @code{reset-deassert-post} handler, to re-enable debugging after a system reset. However, normally it is not necessary to use the command at all. @end deffn @deffn {Command} {aarch64 disassemble} address [count] @cindex disassemble Disassembles @var{count} instructions starting at @var{address}. If @var{count} is not specified, a single instruction is disassembled. @end deffn @deffn {Command} {aarch64 smp} [on|off] Display, enable or disable SMP handling mode. The state of SMP handling influences the way targets in an SMP group are handled by the run control. With SMP handling enabled, issuing halt or resume to one core will trigger halting or resuming of all cores in the group. The command @code{target smp} defines which targets are in the SMP group. With SMP handling disabled, all targets need to be treated individually. @end deffn @deffn {Command} {aarch64 maskisr} [@option{on}|@option{off}] Selects whether interrupts will be processed when single stepping. The default configuration is @option{on}. @end deffn @deffn {Command} {$target_name catch_exc} [@option{off}|@option{sec_el1}|@option{sec_el3}|@option{nsec_el1}|@option{nsec_el2}]+ Cause @command{$target_name} to halt when an exception is taken. Any combination of Secure (sec) EL1/EL3 or Non-Secure (nsec) EL1/EL2 is valid. The target @command{$target_name} will halt before taking the exception. In order to resume the target, the exception catch must be disabled again with @command{$target_name catch_exc off}. Issuing the command without options prints the current configuration. @end deffn @deffn {Command} {$target_name pauth} [@option{off}|@option{on}] Enable or disable pointer authentication features. When pointer authentication is used on ARM cores, GDB asks GDB servers for an 8-bytes mask to remove signature bits added by pointer authentication. If this feature is enabled, OpenOCD provides GDB with an 8-bytes mask. Pointer authentication feature is broken until gdb 12.1, going to be fixed. Consider using a newer version of gdb if you want to enable pauth feature. The default configuration is @option{off}. @end deffn @section EnSilica eSi-RISC Architecture eSi-RISC is a highly configurable microprocessor architecture for embedded systems provided by EnSilica. (See: @url{http://www.ensilica.com/risc-ip/}.) @subsection eSi-RISC Configuration @deffn {Command} {esirisc cache_arch} (@option{harvard}|@option{von_neumann}) Configure the caching architecture. Targets with the @code{UNIFIED_ADDRESS_SPACE} option disabled employ a Harvard architecture. By default, @option{von_neumann} is assumed. @end deffn @deffn {Command} {esirisc hwdc} (@option{all}|@option{none}|mask ...) Configure hardware debug control. The HWDC register controls which exceptions return control back to the debugger. Possible masks are @option{all}, @option{none}, @option{reset}, @option{interrupt}, @option{syscall}, @option{error}, and @option{debug}. By default, @option{reset}, @option{error}, and @option{debug} are enabled. @end deffn @subsection eSi-RISC Operation @deffn {Command} {esirisc flush_caches} Flush instruction and data caches. This command requires that the target is halted when the command is issued and configured with an instruction or data cache. @end deffn @subsection eSi-Trace Configuration eSi-RISC targets may be configured with support for instruction tracing. Trace data may be written to an in-memory buffer or FIFO. If a FIFO is configured, DMA is typically employed to move trace data off-device using a high-speed peripheral (eg. SPI). Collected trace data is encoded in one of three different formats. At a minimum, @command{esirisc trace buffer} or @command{esirisc trace fifo} must be issued along with @command{esirisc trace format} before trace data can be collected. OpenOCD provides rudimentary analysis of collected trace data. If more detail is needed, collected trace data can be dumped to a file and processed by external tooling. @quotation Issues OpenOCD is unable to process trace data sent to a FIFO. A potential workaround for this issue is to configure DMA to copy trace data to an in-memory buffer, which can then be passed to the @command{esirisc trace analyze} and @command{esirisc trace dump} commands. It is possible to corrupt trace data when using a FIFO if the peripheral responsible for draining data from the FIFO is not fast enough. This can be managed by enabling flow control, however this can impact timing-sensitive software operation on the CPU. @end quotation @deffn {Command} {esirisc trace buffer} address size [@option{wrap}] Configure trace buffer using the provided address and size. If the @option{wrap} option is specified, trace collection will continue once the end of the buffer is reached. By default, wrap is disabled. @end deffn @deffn {Command} {esirisc trace fifo} address Configure trace FIFO using the provided address. @end deffn @deffn {Command} {esirisc trace flow_control} (@option{enable}|@option{disable}) Enable or disable stalling the CPU to collect trace data. By default, flow control is disabled. @end deffn @deffn {Command} {esirisc trace format} (@option{full}|@option{branch}|@option{icache}) pc_bits Configure trace format and number of PC bits to be captured. @option{pc_bits} must be within 1 and 31 as the LSB is not collected. If external tooling is used to analyze collected trace data, these values must match. Supported trace formats: @itemize @item @option{full} capture full trace data, allowing execution history and timing to be determined. @item @option{branch} capture taken branch instructions and branch target addresses. @item @option{icache} capture instruction cache misses. @end itemize @end deffn @deffn {Command} {esirisc trace trigger start} (@option{condition}) [start_data start_mask] Configure trigger start condition using the provided start data and mask. A brief description of each condition is provided below; for more detail on how these values are used, see the eSi-RISC Architecture Manual. Supported conditions: @itemize @item @option{none} manual tracing (see @command{esirisc trace start}). @item @option{pc} start tracing if the PC matches start data and mask. @item @option{load} start tracing if the effective address of a load instruction matches start data and mask. @item @option{store} start tracing if the effective address of a store instruction matches start data and mask. @item @option{exception} start tracing if the EID of an exception matches start data and mask. @item @option{eret} start tracing when an @code{ERET} instruction is executed. @item @option{wait} start tracing when a @code{WAIT} instruction is executed. @item @option{stop} start tracing when a @code{STOP} instruction is executed. @item @option{high} start tracing when an external signal is a logical high. @item @option{low} start tracing when an external signal is a logical low. @end itemize @end deffn @deffn {Command} {esirisc trace trigger stop} (@option{condition}) [stop_data stop_mask] Configure trigger stop condition using the provided stop data and mask. A brief description of each condition is provided below; for more detail on how these values are used, see the eSi-RISC Architecture Manual. Supported conditions: @itemize @item @option{none} manual tracing (see @command{esirisc trace stop}). @item @option{pc} stop tracing if the PC matches stop data and mask. @item @option{load} stop tracing if the effective address of a load instruction matches stop data and mask. @item @option{store} stop tracing if the effective address of a store instruction matches stop data and mask. @item @option{exception} stop tracing if the EID of an exception matches stop data and mask. @item @option{eret} stop tracing when an @code{ERET} instruction is executed. @item @option{wait} stop tracing when a @code{WAIT} instruction is executed. @item @option{stop} stop tracing when a @code{STOP} instruction is executed. @end itemize @end deffn @deffn {Command} {esirisc trace trigger delay} (@option{trigger}) [cycles] Configure trigger start/stop delay in clock cycles. Supported triggers: @itemize @item @option{none} no delay to start or stop collection. @item @option{start} delay @option{cycles} after trigger to start collection. @item @option{stop} delay @option{cycles} after trigger to stop collection. @item @option{both} delay @option{cycles} after both triggers to start or stop collection. @end itemize @end deffn @subsection eSi-Trace Operation @deffn {Command} {esirisc trace init} Initialize trace collection. This command must be called any time the configuration changes. If a trace buffer has been configured, the contents will be overwritten when trace collection starts. @end deffn @deffn {Command} {esirisc trace info} Display trace configuration. @end deffn @deffn {Command} {esirisc trace status} Display trace collection status. @end deffn @deffn {Command} {esirisc trace start} Start manual trace collection. @end deffn @deffn {Command} {esirisc trace stop} Stop manual trace collection. @end deffn @deffn {Command} {esirisc trace analyze} [address size] Analyze collected trace data. This command may only be used if a trace buffer has been configured. If a trace FIFO has been configured, trace data must be copied to an in-memory buffer identified by the @option{address} and @option{size} options using DMA. @end deffn @deffn {Command} {esirisc trace dump} [address size] @file{filename} Dump collected trace data to file. This command may only be used if a trace buffer has been configured. If a trace FIFO has been configured, trace data must be copied to an in-memory buffer identified by the @option{address} and @option{size} options using DMA. @end deffn @section Intel Architecture Intel Quark X10xx is the first product in the Quark family of SoCs. It is an IA-32 (Pentium x86 ISA) compatible SoC. The core CPU in the X10xx is codenamed Lakemont. Lakemont version 1 (LMT1) is used in X10xx. The CPU TAP (Lakemont TAP) is used for software debug and the CLTAP is used for SoC level operations. Useful docs are here: https://communities.intel.com/community/makers/documentation @itemize @item Intel Quark SoC X1000 OpenOCD/GDB/Eclipse App Note (web search for doc num 330015) @item Intel Quark SoC X1000 Debug Operations User Guide (web search for doc num 329866) @item Intel Quark SoC X1000 Datasheet (web search for doc num 329676) @end itemize @subsection x86 32-bit specific commands The three main address spaces for x86 are memory, I/O and configuration space. These commands allow a user to read and write to the 64Kbyte I/O address space. @deffn {Command} {x86_32 idw} address Display the contents of a 32-bit I/O port from address range 0x0000 - 0xffff. @end deffn @deffn {Command} {x86_32 idh} address Display the contents of a 16-bit I/O port from address range 0x0000 - 0xffff. @end deffn @deffn {Command} {x86_32 idb} address Display the contents of a 8-bit I/O port from address range 0x0000 - 0xffff. @end deffn @deffn {Command} {x86_32 iww} address Write the contents of a 32-bit I/O port to address range 0x0000 - 0xffff. @end deffn @deffn {Command} {x86_32 iwh} address Write the contents of a 16-bit I/O port to address range 0x0000 - 0xffff. @end deffn @deffn {Command} {x86_32 iwb} address Write the contents of a 8-bit I/O port to address range 0x0000 - 0xffff. @end deffn @section OpenRISC Architecture The OpenRISC CPU is a soft core. It is used in a programmable SoC which can be configured with any of the TAP / Debug Unit available. @subsection TAP and Debug Unit selection commands @deffn {Command} {tap_select} (@option{vjtag}|@option{mohor}|@option{xilinx_bscan}) Select between the Altera Virtual JTAG , Xilinx Virtual JTAG and Mohor TAP. @end deffn @deffn {Command} {du_select} (@option{adv}|@option{mohor}) [option] Select between the Advanced Debug Interface and the classic one. An option can be passed as a second argument to the debug unit. When using the Advanced Debug Interface, option = 1 means the RTL core is configured with ADBG_USE_HISPEED = 1. This configuration skips status checking between bytes while doing read or write bursts. @end deffn @subsection Registers commands @deffn {Command} {addreg} [name] [address] [feature] [reg_group] Add a new register in the cpu register list. This register will be included in the generated target descriptor file. @strong{[feature]} must be "org.gnu.gdb.or1k.group[0..10]". @strong{[reg_group]} can be anything. The default register list defines "system", "dmmu", "immu", "dcache", "icache", "mac", "debug", "perf", "power", "pic" and "timer" groups. @emph{example:} @example addreg rtest 0x1234 org.gnu.gdb.or1k.group0 system @end example @end deffn @section RISC-V Architecture @uref{http://riscv.org/, RISC-V} is a free and open ISA. OpenOCD supports JTAG debug of RV32 and RV64 cores in heterogeneous multicore systems of up to 32 harts. (It's possible to increase this limit to 1024 by changing RISCV_MAX_HARTS in riscv.h.) OpenOCD primarily supports 0.13 of the RISC-V Debug Specification, but there is also support for legacy targets that implement version 0.11. @subsection RISC-V Terminology A @emph{hart} is a hardware thread. A hart may share resources (eg. FPU) with another hart, or may be a separate core. RISC-V treats those the same, and OpenOCD exposes each hart as a separate core. @subsection Vector Registers For harts that implement the vector extension, OpenOCD provides access to the relevant CSRs, as well as the vector registers (v0-v31). The size of each vector register is dependent on the value of vlenb. RISC-V allows each vector register to be divided into selected-width elements, and this division can be changed at run-time. Because OpenOCD cannot update register definitions at run-time, it exposes each vector register to gdb as a union of fields of vectors so that users can easily access individual bytes, shorts, words, longs, and quads inside each vector register. It is left to gdb or higher-level debuggers to present this data in a more intuitive format. In the XML register description, the vector registers (when vlenb=16) look as follows: @example <feature name="org.gnu.gdb.riscv.vector"> <vector id="bytes" type="uint8" count="16"/> <vector id="shorts" type="uint16" count="8"/> <vector id="words" type="uint32" count="4"/> <vector id="longs" type="uint64" count="2"/> <vector id="quads" type="uint128" count="1"/> <union id="riscv_vector"> <field name="b" type="bytes"/> <field name="s" type="shorts"/> <field name="w" type="words"/> <field name="l" type="longs"/> <field name="q" type="quads"/> </union> <reg name="v0" bitsize="128" regnum="4162" save-restore="no" type="riscv_vector" group="vector"/> ... <reg name="v31" bitsize="128" regnum="4193" save-restore="no" type="riscv_vector" group="vector"/> </feature> @end example @subsection RISC-V Debug Configuration Commands @deffn {Config Command} {riscv expose_csrs} n[-m|=name] [...] Configure which CSRs to expose in addition to the standard ones. The CSRs to expose can be specified as individual register numbers or register ranges (inclusive). For the individually listed CSRs, a human-readable name can optionally be set using the @code{n=name} syntax, which will get @code{csr_} prepended to it. If no name is provided, the register will be named @code{csr<n>}. By default OpenOCD attempts to expose only CSRs that are mentioned in a spec, and then only if the corresponding extension appears to be implemented. This command can be used if OpenOCD gets this wrong, or if the target implements custom CSRs. @example # Expose a single RISC-V CSR number 128 under the name "csr128": $_TARGETNAME expose_csrs 128 # Expose multiple RISC-V CSRs 128..132 under names "csr128" through "csr132": $_TARGETNAME expose_csrs 128-132 # Expose a single RISC-V CSR number 1996 under custom name "csr_myregister": $_TARGETNAME expose_csrs 1996=myregister @end example @end deffn @deffn {Config Command} {riscv expose_custom} n[-m|=name] [...] The RISC-V Debug Specification allows targets to expose custom registers through abstract commands. (See Section 3.5.1.1 in that document.) This command configures individual registers or register ranges (inclusive) that shall be exposed. Number 0 indicates the first custom register, whose abstract command number is 0xc000. For individually listed registers, a human-readable name can be optionally provided using the @code{n=name} syntax, which will get @code{custom_} prepended to it. If no name is provided, the register will be named @code{custom<n>}. @example # Expose one RISC-V custom register with number 0xc010 (0xc000 + 16) # under the name "custom16": $_TARGETNAME expose_custom 16 # Expose a range of RISC-V custom registers with numbers 0xc010 .. 0xc018 # (0xc000+16 .. 0xc000+24) under the names "custom16" through "custom24": $_TARGETNAME expose_custom 16-24 # Expose one RISC-V custom register with number 0xc020 (0xc000 + 32) under # user-defined name "custom_myregister": $_TARGETNAME expose_custom 32=myregister @end example @end deffn @deffn {Command} {riscv info} Displays some information OpenOCD detected about the target. @end deffn @deffn {Command} {riscv reset_delays} [wait] OpenOCD learns how many Run-Test/Idle cycles are required between scans to avoid encountering the target being busy. This command resets those learned values after `wait` scans. It's only useful for testing OpenOCD itself. @end deffn @deffn {Command} {riscv set_command_timeout_sec} [seconds] Set the wall-clock timeout (in seconds) for individual commands. The default should work fine for all but the slowest targets (eg. simulators). @end deffn @deffn {Command} {riscv set_reset_timeout_sec} [seconds] Set the maximum time to wait for a hart to come out of reset after reset is deasserted. @end deffn @deffn {Command} {riscv set_mem_access} method1 [method2] [method3] Specify which RISC-V memory access method(s) shall be used, and in which order of priority. At least one method must be specified. Available methods are: @itemize @item @code{progbuf} - Use RISC-V Debug Program Buffer to access memory. @item @code{sysbus} - Access memory via RISC-V Debug System Bus interface. @item @code{abstract} - Access memory via RISC-V Debug abstract commands. @end itemize By default, all memory access methods are enabled in the following order: @code{progbuf sysbus abstract}. This command can be used to change the memory access methods if the default behavior is not suitable for a particular target. @end deffn @deffn {Command} {riscv set_enable_virtual} on|off When on, memory accesses are performed on physical or virtual memory depending on the current system configuration. When off (default), all memory accessses are performed on physical memory. @end deffn @deffn {Command} {riscv set_enable_virt2phys} on|off When on (default), memory accesses are performed on physical or virtual memory depending on the current satp configuration. When off, all memory accessses are performed on physical memory. @end deffn @deffn {Command} {riscv resume_order} normal|reversed Some software assumes all harts are executing nearly continuously. Such software may be sensitive to the order that harts are resumed in. On harts that don't support hasel, this option allows the user to choose the order the harts are resumed in. If you are using this option, it's probably masking a race condition problem in your code. Normal order is from lowest hart index to highest. This is the default behavior. Reversed order is from highest hart index to lowest. @end deffn @deffn {Command} {riscv set_ir} (@option{idcode}|@option{dtmcs}|@option{dmi}) [value] Set the IR value for the specified JTAG register. This is useful, for example, when using the existing JTAG interface on a Xilinx FPGA by way of BSCANE2 primitives that only permit a limited selection of IR values. When utilizing version 0.11 of the RISC-V Debug Specification, @option{dtmcs} and @option{dmi} set the IR values for the DTMCONTROL and DBUS registers, respectively. @end deffn @deffn {Command} {riscv use_bscan_tunnel} value Enable or disable use of a BSCAN tunnel to reach DM. Supply the width of the DM transport TAP's instruction register to enable. Supply a value of 0 to disable. @end deffn @deffn {Command} {riscv set_ebreakm} on|off Control dcsr.ebreakm. When on (default), M-mode ebreak instructions trap to OpenOCD. When off, they generate a breakpoint exception handled internally. @end deffn @deffn {Command} {riscv set_ebreaks} on|off Control dcsr.ebreaks. When on (default), S-mode ebreak instructions trap to OpenOCD. When off, they generate a breakpoint exception handled internally. @end deffn @deffn {Command} {riscv set_ebreaku} on|off Control dcsr.ebreaku. When on (default), U-mode ebreak instructions trap to OpenOCD. When off, they generate a breakpoint exception handled internally. @end deffn @subsection RISC-V Authentication Commands The following commands can be used to authenticate to a RISC-V system. Eg. a trivial challenge-response protocol could be implemented as follows in a configuration file, immediately following @command{init}: @example set challenge [riscv authdata_read] riscv authdata_write [expr @{$challenge + 1@}] @end example @deffn {Command} {riscv authdata_read} Return the 32-bit value read from authdata. @end deffn @deffn {Command} {riscv authdata_write} value Write the 32-bit value to authdata. @end deffn @subsection RISC-V DMI Commands The following commands allow direct access to the Debug Module Interface, which can be used to interact with custom debug features. @deffn {Command} {riscv dmi_read} address Perform a 32-bit DMI read at address, returning the value. @end deffn @deffn {Command} {riscv dmi_write} address value Perform a 32-bit DMI write of value at address. @end deffn @section ARC Architecture @cindex ARC Synopsys DesignWare ARC Processors are a family of 32-bit CPUs that SoC designers can optimize for a wide range of uses, from deeply embedded to high-performance host applications in a variety of market segments. See more at: @url{http://www.synopsys.com/IP/ProcessorIP/ARCProcessors/Pages/default.aspx}. OpenOCD currently supports ARC EM processors. There is a set ARC-specific OpenOCD commands that allow low-level access to the core and provide necessary support for ARC extensibility and configurability capabilities. ARC processors has much more configuration capabilities than most of the other processors and in addition there is an extension interface that allows SoC designers to add custom registers and instructions. For the OpenOCD that mostly means that set of core and AUX registers in target will vary and is not fixed for a particular processor model. To enable extensibility several TCL commands are provided that allow to describe those optional registers in OpenOCD configuration files. Moreover those commands allow for a dynamic target features discovery. @subsection General ARC commands @deffn {Config Command} {arc add-reg} configparams Add a new register to processor target. By default newly created register is marked as not existing. @var{configparams} must have following required arguments: @itemize @bullet @item @code{-name} name @*Name of a register. @item @code{-num} number @*Architectural register number: core register number or AUX register number. @item @code{-feature} XML_feature @*Name of GDB XML target description feature. @end itemize @var{configparams} may have following optional arguments: @itemize @bullet @item @code{-gdbnum} number @*GDB register number. It is recommended to not assign GDB register number manually, because there would be a risk that two register will have same number. When register GDB number is not set with this option, then register will get a previous register number + 1. This option is required only for those registers that must be at particular address expected by GDB. @item @code{-core} @*This option specifies that register is a core registers. If not - this is an AUX register. AUX registers and core registers reside in different address spaces. @item @code{-bcr} @*This options specifies that register is a BCR register. BCR means Build Configuration Registers - this is a special type of AUX registers that are read only and non-volatile, that is - they never change their value. Therefore OpenOCD never invalidates values of those registers in internal caches. Because BCR is a type of AUX registers, this option cannot be used with @code{-core}. @item @code{-type} type_name @*Name of type of this register. This can be either one of the basic GDB types, or a custom types described with @command{arc add-reg-type-[flags|struct]}. @item @code{-g} @* If specified then this is a "general" register. General registers are always read by OpenOCD on context save (when core has just been halted) and is always transferred to GDB client in a response to g-packet. Contrary to this, non-general registers are read and sent to GDB client on-demand. In general it is not recommended to apply this option to custom registers. @end itemize @end deffn @deffn {Config Command} {arc add-reg-type-flags} -name name flags... Adds new register type of ``flags'' class. ``Flags'' types can contain only one-bit fields. Each flag definition looks like @code{-flag name bit-position}. @end deffn @anchor{add-reg-type-struct} @deffn {Config Command} {arc add-reg-type-struct} -name name structs... Adds new register type of ``struct'' class. ``Struct'' types can contain either bit-fields or fields of other types, however at the moment only bit fields are supported. Structure bit field definition looks like @code{-bitfield name startbit endbit}. @end deffn @deffn {Command} {arc get-reg-field} reg-name field-name Returns value of bit-field in a register. Register must be ``struct'' register type, @xref{add-reg-type-struct}. command definition. @end deffn @deffn {Command} {arc set-reg-exists} reg-names... Specify that some register exists. Any amount of names can be passed as an argument for a single command invocation. @end deffn @subsection ARC JTAG commands @deffn {Command} {arc jtag set-aux-reg} regnum value This command writes value to AUX register via its number. This command access register in target directly via JTAG, bypassing any OpenOCD internal caches, therefore it is unsafe to use if that register can be operated by other means. @end deffn @deffn {Command} {arc jtag set-core-reg} regnum value This command is similar to @command{arc jtag set-aux-reg} but is for core registers. @end deffn @deffn {Command} {arc jtag get-aux-reg} regnum This command returns the value storded in AUX register via its number. This commands access register in target directly via JTAG, bypassing any OpenOCD internal caches, therefore it is unsafe to use if that register can be operated by other means. @end deffn @deffn {Command} {arc jtag get-core-reg} regnum This command is similar to @command{arc jtag get-aux-reg} but is for core registers. @end deffn @section STM8 Architecture @uref{http://st.com/stm8/, STM8} is a 8-bit microcontroller platform from STMicroelectronics, based on a proprietary 8-bit core architecture. OpenOCD supports debugging STM8 through the STMicroelectronics debug protocol SWIM, @pxref{swimtransport,,SWIM}. @section Xtensa Architecture Xtensa is a highly-customizable, user-extensible microprocessor and DSP architecture for complex embedded systems provided by Cadence Design Systems, Inc. See the @uref{https://www.cadence.com/en_US/home/tools/ip/tensilica-ip.html, Tensilica IP} website for additional information and documentation. OpenOCD supports generic Xtensa processor implementations which can be customized by providing a core-specific configuration file which describes every enabled Xtensa architecture option, e.g. number of address registers, exceptions, reduced size instructions support, memory banks configuration etc. OpenOCD also supports SMP configurations for Xtensa processors with any number of cores and allows configuring their debug interconnect (termed "break/stall networks"), which control how debug signals are distributed among cores. Xtensa "break networks" are compatible with ARM's Cross Trigger Interface (CTI). OpenOCD implements both generic Xtensa targets as well as several Espressif Xtensa-based chips from the @uref{https://www.espressif.com/en/products/socs, ESP32 family}. OCD sessions for Xtensa processor and DSP targets are accessed via the Xtensa Debug Module (XDM), which provides external connectivity either through a traditional JTAG interface or an ARM DAP interface. If used, the DAP interface can control Xtensa targets through JTAG or SWD probes. @subsection Xtensa Core Configuration Due to the high level of configurability in Xtensa cores, the Xtensa target configuration comprises two categories: @enumerate @item Base Xtensa support common to all core configurations, and @item Core-specific support as configured for individual cores. @end enumerate All common Xtensa support is built into the OpenOCD Xtensa target layer and is enabled through a combination of TCL scripts: the target-specific @file{target/xtensa.cfg} and a board-specific @file{board/xtensa-*.cfg}, similar to other target architectures. Importantly, core-specific configuration information must be provided by the user, and takes the form of an @file{xtensa-core-XXX.cfg} TCL script that defines the core's configurable features through a series of Xtensa configuration commands (detailed below). This core-specific @file{xtensa-core-XXX.cfg} file is typically either: @itemize @bullet @item Located within the Xtensa core configuration build as @file{src/config/xtensa-core-openocd.cfg}, or @item Generated by running the command @code{xt-gdb --dump-oocd-config} from the Xtensa processor tool-chain's command-line tools. @end itemize NOTE: @file{xtensa-core-XXX.cfg} must match the target Xtensa hardware connected to OpenOCD. Some example Xtensa configurations are bundled with OpenOCD for reference: @itemize @bullet @item Cadence Palladium VDebug emulation target. The user can combine their @file{xtensa-core-XXX.cfg} with the provided @file{board/xtensa-palladium-vdebug.cfg} to debug an emulated Xtensa RTL design. @item NXP MIMXRT685-EVK evaluation kit. The relevant configuration files are @file{board/xtensa-rt685-jlink.cfg} and @file{board/xtensa-core-nxp_rt600.cfg}. Additional information is provided by @uref{https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt600-evaluation-kit:MIMXRT685-EVK, NXP}. @end itemize @subsection Xtensa Configuration Commands @deffn {Config Command} {xtensa xtdef} (@option{LX}|@option{NX}) Configure the Xtensa target architecture. Currently, Xtensa support is limited to LX6, LX7, and NX cores. @end deffn @deffn {Config Command} {xtensa xtopt} option value Configure Xtensa target options that are relevant to the debug subsystem. @var{option} is one of: @option{arnum}, @option{windowed}, @option{cpenable}, @option{exceptions}, @option{intnum}, @option{hipriints}, @option{excmlevel}, @option{intlevels}, @option{debuglevel}, @option{ibreaknum}, or @option{dbreaknum}. @var{value} is an integer with the exact range determined by each particular option. NOTE: Some options are specific to Xtensa LX or Xtensa NX architecture, while others may be common to both but have different valid ranges. @end deffn @deffn {Config Command} {xtensa xtmem} (@option{iram}|@option{dram}|@option{sram}|@option{irom}|@option{drom}|@option{srom}) baseaddr bytes Configure Xtensa target memory. Memory type determines access rights, where RAMs are read/write while ROMs are read-only. @var{baseaddr} and @var{bytes} are both integers, typically hexadecimal and decimal, respectively. @end deffn @deffn {Config Command} {xtensa xtmem} (@option{icache}|@option{dcache}) linebytes cachebytes ways [writeback] Configure Xtensa processor cache. All parameters are required except for the optional @option{writeback} parameter; all are integers. @end deffn @deffn {Config Command} {xtensa xtmpu} numfgseg minsegsz lockable execonly Configure an Xtensa Memory Protection Unit (MPU). MPUs can restrict access and/or control cacheability of specific address ranges, but are lighter-weight than a full traditional MMU. All parameters are required; all are integers. @end deffn @deffn {Config Command} {xtensa xtmmu} numirefillentries numdrefillentries (Xtensa-LX only) Configure an Xtensa Memory Management Unit (MMU). Both parameters are required; both are integers. @end deffn @deffn {Config Command} {xtensa xtregs} numregs Configure the total number of registers for the Xtensa core. Configuration logic expects to subsequently process this number of @code{xtensa xtreg} definitions. @var{numregs} is an integer. @end deffn @deffn {Config Command} {xtensa xtregfmt} (@option{sparse}|@option{contiguous}) [general] Configure the type of register map used by GDB to access the Xtensa core. Generic Xtensa tools (e.g. xt-gdb) require @option{sparse} mapping (default) while Espressif tools expect @option{contiguous} mapping. Contiguous mapping takes an additional, optional integer parameter @option{numgregs}, which specifies the number of general registers used in handling g/G packets. @end deffn @deffn {Config Command} {xtensa xtreg} name offset Configure an Xtensa core register. All core registers are 32 bits wide, while TIE and user registers may have variable widths. @var{name} is a character string identifier while @var{offset} is a hexadecimal integer. @end deffn @subsection Xtensa Operation Commands @deffn {Command} {xtensa maskisr} (@option{on}|@option{off}) (Xtensa-LX only) Mask or unmask Xtensa interrupts during instruction step. When masked, an interrupt that occurs during a step operation is handled and its ISR is executed, with the user's debug session returning after potentially executing many instructions. When unmasked, a triggered interrupt will result in execution progressing the requested number of instructions into the relevant vector/ISR code. @end deffn @deffn {Command} {xtensa set_permissive} (0|1) By default accessing memory beyond defined regions is forbidden. This commnd controls memory access address check. When set to (1), skips access controls and address range check before read/write memory. @end deffn @deffn {Command} {xtensa smpbreak} [none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut] Configures debug signals connection ("break network") for currently selected core. @itemize @bullet @item @code{none} - Core's "break/stall network" is disconnected. Core is not affected by any debug signal from other cores. @item @code{breakinout} - Core's "break network" is fully connected (break inputs and outputs are enabled). Core will receive debug break signals from other cores and send such signals to them. For example when another core is stopped due to breakpoint hit this core will be stopped too and vice versa. @item @code{runstall} - Core's "stall network" is fully connected (stall inputs and outputs are enabled). This feature is not well implemented and tested yet. @item @code{BreakIn} - Core's "break-in" signal is enabled. Core will receive debug break signals from other cores. For example when another core is stopped due to breakpoint hit this core will be stopped too. @item @code{BreakOut} - Core's "break-out" signal is enabled. Core will send debug break signal to other cores. For example when this core is stopped due to breakpoint hit other cores with enabled break-in signals will be stopped too. @item @code{RunStallIn} - Core's "runstall-in" signal is enabled. This feature is not well implemented and tested yet. @item @code{DebugModeOut} - Core's "debugmode-out" signal is enabled. This feature is not well implemented and tested yet. @end itemize @end deffn @deffn {Command} {xtensa exe} <ascii-encoded hexadecimal instruction bytes> Execute arbitrary instruction(s) provided as an ascii string. The string represents an integer number of instruction bytes, thus its length must be even. @end deffn @subsection Xtensa Performance Monitor Configuration @deffn {Command} {xtensa perfmon_enable} <counter_id> <select> [mask] [kernelcnt] [tracelevel] Enable and start performance counter. @itemize @bullet @item @code{counter_id} - Counter ID (0-1). @item @code{select} - Selects performance metric to be counted by the counter, e.g. 0 - CPU cycles, 2 - retired instructions. @item @code{mask} - Selects input subsets to be counted (counter will increment only once even if more than one condition corresponding to a mask bit occurs). @item @code{kernelcnt} - 0 - count events with "CINTLEVEL <= tracelevel", 1 - count events with "CINTLEVEL > tracelevel". @item @code{tracelevel} - Compares this value to "CINTLEVEL" when deciding whether to count. @end itemize @end deffn @deffn {Command} {xtensa perfmon_dump} (counter_id) Dump performance counter value. If no argument specified, dumps all counters. @end deffn @subsection Xtensa Trace Configuration @deffn {Command} {xtensa tracestart} [pc <pcval>/[<maskbitcount>]] [after <n> [ins|words]] Set up and start a HW trace. Optionally set PC address range to trigger tracing stop when reached during program execution. This command also allows to specify the amount of data to capture after stop trigger activation. @itemize @bullet @item @code{pcval} - PC value which will trigger trace data collection stop. @item @code{maskbitcount} - PC value mask. @item @code{n} - Maximum number of instructions/words to capture after trace stop trigger. @end itemize @end deffn @deffn {Command} {xtensa tracestop} Stop current trace as started by the tracestart command. @end deffn @deffn {Command} {xtensa tracedump} <outfile> Dump trace memory to a file. @end deffn @section Espressif Specific Commands @deffn {Command} {esp apptrace} (start <destination> [<poll_period> [<trace_size> [<stop_tmo> [<wait4halt> [<skip_size>]]]]]) Starts @uref{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#application-level-tracing-library, application level tracing}. Data will be stored to specified destination. Available destinations are: @itemize @bullet @item @code{file://<outfile>} - Save trace logs into file. @item @code{tcp://<host>:<port>} - Send trace logs to tcp port on specified host. OpenOCD will act as a tcp client. @item @code{con:} - Print trace logs to the stdout. @end itemize Other parameters will be same for each destination. @itemize @bullet @item @code{poll_period} - trace data polling period in ms. @item @code{trace_size} - maximum trace data size. Tracing will be stopped automatically when that amount is reached. Use "-1" to disable the limitation. @item @code{stop_tmo} - Data reception timeout in ms. Tracing will be stopped automatically when no data is received within that period. @item @code{wait4halt} - if non-zero then wait for target to be halted before tracing start. @item @code{skip_size} - amount of tracing data to be skipped before writing it to destination. @end itemize @end deffn @deffn {Command} {esp apptrace} (stop) Stops tracing started with above command. @end deffn @deffn {Command} {esp apptrace} (status) Requests ongoing tracing status. @end deffn @deffn {Command} {esp apptrace} (dump file://<outfile>) Dumps tracing data from target buffer. It can be useful to dump the latest data buffered on target for post-mortem analysis. For example when target starts tracing automatically w/o OpenOCD command and keeps only the latest data window which fit into the buffer. @uref{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#application-level-tracing-library, application level tracing}. Data will be stored to specified destination. @end deffn @deffn {Command} {esp sysview} (start file://<outfile1> [file://<outfile2>] [<poll_period> [<trace_size> [<stop_tmo> [<wait4halt> [<skip_size>]]]]]) Starts @uref{https://www.segger.com/products/development-tools/systemview/, SEGGER SystemView} compatible tracing. Data will be stored to specified destination. For dual-core chips traces from every core will be saved to separate files. Resulting files can be open in "SEGGER SystemView" application. @url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options} The meaning of the arguments is identical to @command{esp apptrace start}. @end deffn @deffn {Command} {esp sysview} (stop) Stops SystremView compatible tracing started with above command. @url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options} @end deffn @deffn {Command} {esp sysview} (status) Requests ongoing SystremView compatible tracing status. @url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options} @end deffn @deffn {Command} {esp sysview_mcore} (start file://<outfile> [<poll_period> [<trace_size> [<stop_tmo> [<wait4halt> [<skip_size>]]]]]) This command is identical to @command{esp sysview start}, but uses Espressif multi-core extension to @uref{https://www.segger.com/products/development-tools/systemview/, SEGGER SystemView} data format. Data will be stored to specified destination. Tracing data from all cores are saved in the same file. The meaning of the arguments is identical to @command{esp sysview start}. @end deffn @deffn {Command} {esp sysview_mcore} (stop) Stops Espressif multi-core SystremView tracing started with above command. @end deffn @deffn {Command} {esp sysview_mcore} (status) Requests ongoing Espressif multi-core SystremView tracing status. @end deffn @anchor{softwaredebugmessagesandtracing} @section Software Debug Messages and Tracing @cindex Linux-ARM DCC support @cindex tracing @cindex libdcc @cindex DCC OpenOCD can process certain requests from target software, when the target uses appropriate libraries. The most powerful mechanism is semihosting, but there is also a lighter weight mechanism using only the DCC channel. Currently @command{target_request debugmsgs} is supported only for @option{arm7_9} and @option{cortex_m} cores. These messages are received as part of target polling, so you need to have @command{poll on} active to receive them. They are intrusive in that they will affect program execution times. If that is a problem, @pxref{armhardwaretracing,,ARM Hardware Tracing}. See @file{libdcc} in the contrib dir for more details. In addition to sending strings, characters, and arrays of various size integers from the target, @file{libdcc} also exports a software trace point mechanism. The target being debugged may issue trace messages which include a 24-bit @dfn{trace point} number. Trace point support includes two distinct mechanisms, each supported by a command: @itemize @item @emph{History} ... A circular buffer of trace points can be set up, and then displayed at any time. This tracks where code has been, which can be invaluable in finding out how some fault was triggered. The buffer may overflow, since it collects records continuously. It may be useful to use some of the 24 bits to represent a particular event, and other bits to hold data. @item @emph{Counting} ... An array of counters can be set up, and then displayed at any time. This can help establish code coverage and identify hot spots. The array of counters is directly indexed by the trace point number, so trace points with higher numbers are not counted. @end itemize Linux-ARM kernels have a ``Kernel low-level debugging via EmbeddedICE DCC channel'' option (CONFIG_DEBUG_ICEDCC, depends on CONFIG_DEBUG_LL) which uses this mechanism to deliver messages before a serial console can be activated. This is not the same format used by @file{libdcc}. Other software, such as the U-Boot boot loader, sometimes does the same thing. @deffn {Command} {target_request debugmsgs} [@option{enable}|@option{disable}|@option{charmsg}] Displays current handling of target DCC message requests. These messages may be sent to the debugger while the target is running. The optional @option{enable} and @option{charmsg} parameters both enable the messages, while @option{disable} disables them. With @option{charmsg} the DCC words each contain one character, as used by Linux with CONFIG_DEBUG_ICEDCC; otherwise the libdcc format is used. @end deffn @deffn {Command} {trace history} [@option{clear}|count] With no parameter, displays all the trace points that have triggered in the order they triggered. With the parameter @option{clear}, erases all current trace history records. With a @var{count} parameter, allocates space for that many history records. @end deffn @deffn {Command} {trace point} [@option{clear}|identifier] With no parameter, displays all trace point identifiers and how many times they have been triggered. With the parameter @option{clear}, erases all current trace point counters. With a numeric @var{identifier} parameter, creates a new a trace point counter and associates it with that identifier. @emph{Important:} The identifier and the trace point number are not related except by this command. These trace point numbers always start at zero (from server startup, or after @command{trace point clear}) and count up from there. @end deffn @node JTAG Commands @chapter JTAG Commands @cindex JTAG Commands Most general purpose JTAG commands have been presented earlier. (@xref{jtagspeed,,JTAG Speed}, @ref{Reset Configuration}, and @ref{TAP Declaration}.) Lower level JTAG commands, as presented here, may be needed to work with targets which require special attention during operations such as reset or initialization. To use these commands you will need to understand some of the basics of JTAG, including: @itemize @bullet @item A JTAG scan chain consists of a sequence of individual TAP devices such as a CPUs. @item Control operations involve moving each TAP through the same standard state machine (in parallel) using their shared TMS and clock signals. @item Data transfer involves shifting data through the chain of instruction or data registers of each TAP, writing new register values while the reading previous ones. @item Data register sizes are a function of the instruction active in a given TAP, while instruction register sizes are fixed for each TAP. All TAPs support a BYPASS instruction with a single bit data register. @item The way OpenOCD differentiates between TAP devices is by shifting different instructions into (and out of) their instruction registers. @end itemize @section Low Level JTAG Commands These commands are used by developers who need to access JTAG instruction or data registers, possibly controlling the order of TAP state transitions. If you're not debugging OpenOCD internals, or bringing up a new JTAG adapter or a new type of TAP device (like a CPU or JTAG router), you probably won't need to use these commands. In a debug session that doesn't use JTAG for its transport protocol, these commands are not available. @deffn {Command} {drscan} tap [numbits value]+ [@option{-endstate} tap_state] Loads the data register of @var{tap} with a series of bit fields that specify the entire register. Each field is @var{numbits} bits long with a numeric @var{value} (hexadecimal encouraged). The return value holds the original value of each of those fields. For example, a 38 bit number might be specified as one field of 32 bits then one of 6 bits. @emph{For portability, never pass fields which are more than 32 bits long. Many OpenOCD implementations do not support 64-bit (or larger) integer values.} All TAPs other than @var{tap} must be in BYPASS mode. The single bit in their data registers does not matter. When @var{tap_state} is specified, the JTAG state machine is left in that state. For example @sc{drpause} might be specified, so that more instructions can be issued before re-entering the @sc{run/idle} state. If the end state is not specified, the @sc{run/idle} state is entered. @quotation Warning OpenOCD does not record information about data register lengths, so @emph{it is important that you get the bit field lengths right}. Remember that different JTAG instructions refer to different data registers, which may have different lengths. Moreover, those lengths may not be fixed; the SCAN_N instruction can change the length of the register accessed by the INTEST instruction (by connecting a different scan chain). @end quotation @end deffn @deffn {Command} {flush_count} Returns the number of times the JTAG queue has been flushed. This may be used for performance tuning. For example, flushing a queue over USB involves a minimum latency, often several milliseconds, which does not change with the amount of data which is written. You may be able to identify performance problems by finding tasks which waste bandwidth by flushing small transfers too often, instead of batching them into larger operations. @end deffn @deffn {Command} {irscan} [tap instruction]+ [@option{-endstate} tap_state] For each @var{tap} listed, loads the instruction register with its associated numeric @var{instruction}. (The number of bits in that instruction may be displayed using the @command{scan_chain} command.) For other TAPs, a BYPASS instruction is loaded. When @var{tap_state} is specified, the JTAG state machine is left in that state. For example @sc{irpause} might be specified, so the data register can be loaded before re-entering the @sc{run/idle} state. If the end state is not specified, the @sc{run/idle} state is entered. @quotation Note OpenOCD currently supports only a single field for instruction register values, unlike data register values. For TAPs where the instruction register length is more than 32 bits, portable scripts currently must issue only BYPASS instructions. @end quotation @end deffn @deffn {Command} {pathmove} start_state [next_state ...] Start by moving to @var{start_state}, which must be one of the @emph{stable} states. Unless it is the only state given, this will often be the current state, so that no TCK transitions are needed. Then, in a series of single state transitions (conforming to the JTAG state machine) shift to each @var{next_state} in sequence, one per TCK cycle. The final state must also be stable. @end deffn @deffn {Command} {runtest} @var{num_cycles} Move to the @sc{run/idle} state, and execute at least @var{num_cycles} of the JTAG clock (TCK). Instructions often need some time to execute before they take effect. @end deffn @c tms_sequence (short|long) @c ... temporary, debug-only, other than USBprog bug workaround... @deffn {Command} {verify_ircapture} (@option{enable}|@option{disable}) Verify values captured during @sc{ircapture} and returned during IR scans. Default is enabled, but this can be overridden by @command{verify_jtag}. This flag is ignored when validating JTAG chain configuration. @end deffn @deffn {Command} {verify_jtag} (@option{enable}|@option{disable}) Enables verification of DR and IR scans, to help detect programming errors. For IR scans, @command{verify_ircapture} must also be enabled. Default is enabled. @end deffn @section TAP state names @cindex TAP state names The @var{tap_state} names used by OpenOCD in the @command{drscan}, @command{irscan}, and @command{pathmove} commands are the same as those used in SVF boundary scan documents, except that SVF uses @sc{idle} instead of @sc{run/idle}. @itemize @bullet @item @b{RESET} ... @emph{stable} (with TMS high); acts as if TRST were pulsed @item @b{RUN/IDLE} ... @emph{stable}; don't assume this always means IDLE @item @b{DRSELECT} @item @b{DRCAPTURE} @item @b{DRSHIFT} ... @emph{stable}; TDI/TDO shifting through the data register @item @b{DREXIT1} @item @b{DRPAUSE} ... @emph{stable}; data register ready for update or more shifting @item @b{DREXIT2} @item @b{DRUPDATE} @item @b{IRSELECT} @item @b{IRCAPTURE} @item @b{IRSHIFT} ... @emph{stable}; TDI/TDO shifting through the instruction register @item @b{IREXIT1} @item @b{IRPAUSE} ... @emph{stable}; instruction register ready for update or more shifting @item @b{IREXIT2} @item @b{IRUPDATE} @end itemize Note that only six of those states are fully ``stable'' in the face of TMS fixed (low except for @sc{reset}) and a free-running JTAG clock. For all the others, the next TCK transition changes to a new state. @itemize @bullet @item From @sc{drshift} and @sc{irshift}, clock transitions will produce side effects by changing register contents. The values to be latched in upcoming @sc{drupdate} or @sc{irupdate} states may not be as expected. @item @sc{run/idle}, @sc{drpause}, and @sc{irpause} are reasonable choices after @command{drscan} or @command{irscan} commands, since they are free of JTAG side effects. @item @sc{run/idle} may have side effects that appear at non-JTAG levels, such as advancing the ARM9E-S instruction pipeline. Consult the documentation for the TAP(s) you are working with. @end itemize @node Boundary Scan Commands @chapter Boundary Scan Commands One of the original purposes of JTAG was to support boundary scan based hardware testing. Although its primary focus is to support On-Chip Debugging, OpenOCD also includes some boundary scan commands. @section SVF: Serial Vector Format @cindex Serial Vector Format @cindex SVF The Serial Vector Format, better known as @dfn{SVF}, is a way to represent JTAG test patterns in text files. In a debug session using JTAG for its transport protocol, OpenOCD supports running such test files. @deffn {Command} {svf} @file{filename} [@option{-tap @var{tapname}}] [@option{-quiet}] @ [@option{-nil}] [@option{-progress}] [@option{-ignore_error}] @ [@option{-noreset}] [@option{-addcycles @var{cyclecount}}] This issues a JTAG reset (Test-Logic-Reset) and then runs the SVF script from @file{filename}. Arguments can be specified in any order; the optional dash doesn't affect their semantics. Command options: @itemize @minus @item @option{-tap @var{tapname}} ignore IR and DR headers and footers specified by the SVF file with HIR, TIR, HDR and TDR commands; instead, calculate them automatically according to the current JTAG chain configuration, targeting @var{tapname}; @item @option{-quiet} do not log every command before execution; @item @option{-nil} ``dry run'', i.e., do not perform any operations on the real interface; @item @option{-progress} enable progress indication; @item @option{-ignore_error} continue execution despite TDO check errors. @item @option{-noreset} omit JTAG reset (Test-Logic-Reset) before executing content of the SVF file; @item @option{-addcycles @var{cyclecount}} inject @var{cyclecount} number of additional TCLK cycles after each SDR scan instruction; @end itemize @end deffn @section XSVF: Xilinx Serial Vector Format @cindex Xilinx Serial Vector Format @cindex XSVF The Xilinx Serial Vector Format, better known as @dfn{XSVF}, is a binary representation of SVF which is optimized for use with Xilinx devices. In a debug session using JTAG for its transport protocol, OpenOCD supports running such test files. @quotation Important Not all XSVF commands are supported. @end quotation @deffn {Command} {xsvf} (tapname|@option{plain}) filename [@option{virt2}] [@option{quiet}] This issues a JTAG reset (Test-Logic-Reset) and then runs the XSVF script from @file{filename}. When a @var{tapname} is specified, the commands are directed at that TAP. When @option{virt2} is specified, the @sc{xruntest} command counts are interpreted as TCK cycles instead of microseconds. Unless the @option{quiet} option is specified, messages are logged for comments and some retries. @end deffn The OpenOCD sources also include two utility scripts for working with XSVF; they are not currently installed after building the software. You may find them useful: @itemize @item @emph{svf2xsvf} ... converts SVF files into the extended XSVF syntax understood by the @command{xsvf} command; see notes below. @item @emph{xsvfdump} ... converts XSVF files into a text output format; understands the OpenOCD extensions. @end itemize The input format accepts a handful of non-standard extensions. These include three opcodes corresponding to SVF extensions from Lattice Semiconductor (LCOUNT, LDELAY, LDSR), and two opcodes supporting a more accurate translation of SVF (XTRST, XWAITSTATE). If @emph{xsvfdump} shows a file is using those opcodes, it probably will not be usable with other XSVF tools. @section IPDBG: JTAG-Host server @cindex IPDBG JTAG-Host server @cindex IPDBG IPDBG is a set of tools to debug IP-Cores. It comprises, among others, a logic analyzer and an arbitrary waveform generator. These are synthesize-able hardware descriptions of logic circuits in addition to software for control, visualization and further analysis. In a session using JTAG for its transport protocol, OpenOCD supports the function of a JTAG-Host. The JTAG-Host is needed to connect the circuit over JTAG to the control-software. For more details see @url{http://ipdbg.org}. @deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-tap @var{tapname}} @option{-hub @var{ir_value} [@var{dr_length}]} [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}] [@option{-port @var{number}}] [@option{-tool @var{number}}] Starts or stops a IPDBG JTAG-Host server. Arguments can be specified in any order. Command options: @itemize @bullet @item @option{-start|-stop} starts or stops a IPDBG JTAG-Host server (default: start). @item @option{-tap @var{tapname}} targeting the TAP @var{tapname}. @item @option{-hub @var{ir_value}} states that the JTAG hub is reachable with dr-scans while the JTAG instruction register has the value @var{ir_value}. @item @option{-port @var{number}} tcp port number where the JTAG-Host will listen. The default is 4242 which is used when the option is not given. @item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. The default is 1 which is used when the option is not given. @item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} On some devices, the user data-register is reachable if there is a specific value in a second dr. This second dr is called vir (virtual ir). With this parameter given, the IPDBG satisfies this condition prior an access to the IPDBG-Hub. The value shifted into the vir is given by the first parameter @var{vir_value} (default: 0x11). The second parameter @var{length} is the length of the vir data register (default: 5). With the @var{instr_code} (default: 0x00e) parameter the ir value to shift data through vir can be configured. @end itemize @end deffn or @deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-pld @var{name} [@var{user}]} [@option{-port @var{number}}] [@option{-tool @var{number}}] Also starts or stops a IPDBG JTAG-Host server. The pld drivers are able to provide the tap and hub/IR for the IPDBG JTAG-Host server. With the @option{-pld @var{name} [@var{user}]} the information from the pld-driver is used and the options @option{-tap} and @option{-hub} are not required. The defined driver for the pld @var{name} gets selected. (The pld devices names can be shown by the command @command{pld devices}). The @verb{|USERx|} instructions are vendor specific and don't change between families of the same vendor. So if there's a pld driver for your vendor it should work with your FPGA even when the driver is not compatible with your device for the remaining features. If your device/vendor is not supported you have to use the previous command. With [@var{user}] one can select a different @verb{|USERx|}-Instruction. If the IPDBG JTAG-Hub is used without modification the default value of 1 which selects the first @verb{|USERx|} instruction is adequate. The remaining options are described in the previous command. @end deffn Examples: @example ipdbg -start -tap xc6s.tap -hub 0x02 -port 4242 -tool 4 @end example Starts a server listening on tcp-port 4242 which connects to tool 4. The connection is through the TAP of a Xilinx Spartan 6 on USER1 instruction (tested with a papillion pro board). @example ipdbg -start -tap 10m50.tap -hub 0x00C -vir -port 60000 -tool 1 @end example Starts a server listening on tcp-port 60000 which connects to tool 1 (data_up_1/data_down_1). The connection is through the TAP of a Intel MAX10 virtual jtag component (sld_instance_index is 0; sld_ir_width is smaller than 5). @example ipdbg -start -pld xc7.pld -port 5555 -tool 0 @end example Starts a server listening on tcp-port 5555 which connects to tool 0 (data_up_0/data_down_0). The TAP and ir value used to reach the JTAG Hub is given by the pld driver. @node Utility Commands @chapter Utility Commands @cindex Utility Commands @section RAM testing @cindex RAM testing There is often a need to stress-test random access memory (RAM) for errors. OpenOCD comes with a Tcl implementation of well-known memory testing procedures allowing the detection of all sorts of issues with electrical wiring, defective chips, PCB layout and other common hardware problems. To use them, you usually need to initialise your RAM controller first; consult your SoC's documentation to get the recommended list of register operations and translate them to the corresponding @command{mww}/@command{mwb} commands. Load the memory testing functions with @example source [find tools/memtest.tcl] @end example to get access to the following facilities: @deffn {Command} {memTestDataBus} address Test the data bus wiring in a memory region by performing a walking 1's test at a fixed address within that region. @end deffn @deffn {Command} {memTestAddressBus} baseaddress size Perform a walking 1's test on the relevant bits of the address and check for aliasing. This test will find single-bit address failures such as stuck-high, stuck-low, and shorted pins. @end deffn @deffn {Command} {memTestDevice} baseaddress size Test the integrity of a physical memory device by performing an increment/decrement test over the entire region. In the process every storage bit in the device is tested as zero and as one. @end deffn @deffn {Command} {runAllMemTests} baseaddress size Run all of the above tests over a specified memory region. @end deffn @section Firmware recovery helpers @cindex Firmware recovery OpenOCD includes an easy-to-use script to facilitate mass-market devices recovery with JTAG. For quickstart instructions run: @example openocd -f tools/firmware-recovery.tcl -c firmware_help @end example @node GDB and OpenOCD @chapter GDB and OpenOCD @cindex GDB OpenOCD complies with the remote gdbserver protocol and, as such, can be used to debug remote targets. Setting up GDB to work with OpenOCD can involve several components: @itemize @item The OpenOCD server support for GDB may need to be configured. @xref{gdbconfiguration,,GDB Configuration}. @item GDB's support for OpenOCD may need configuration, as shown in this chapter. @item If you have a GUI environment like Eclipse, that also will probably need to be configured. @end itemize Of course, the version of GDB you use will need to be one which has been built to know about the target CPU you're using. It's probably part of the tool chain you're using. For example, if you are doing cross-development for ARM on an x86 PC, instead of using the native x86 @command{gdb} command you might use @command{arm-none-eabi-gdb} if that's the tool chain used to compile your code. @section Connecting to GDB @cindex Connecting to GDB Use GDB 6.7 or newer with OpenOCD if you run into trouble. For instance GDB 6.3 has a known bug that produces bogus memory access errors, which has since been fixed; see @url{http://osdir.com/ml/gdb.bugs.discuss/2004-12/msg00018.html} OpenOCD can communicate with GDB in two ways: @enumerate @item A socket (TCP/IP) connection is typically started as follows: @example target extended-remote localhost:3333 @end example This would cause GDB to connect to the gdbserver on the local pc using port 3333. The extended remote protocol is a super-set of the remote protocol and should be the preferred choice. More details are available in GDB documentation @url{https://sourceware.org/gdb/onlinedocs/gdb/Connecting.html} To speed-up typing, any GDB command can be abbreviated, including the extended remote command above that becomes: @example tar ext :3333 @end example @b{Note:} If any backward compatibility issue requires using the old remote protocol in place of the extended remote one, the former protocol is still available through the command: @example target remote localhost:3333 @end example @item A pipe connection is typically started as follows: @example target extended-remote | \ openocd -c "gdb_port pipe; log_output openocd.log" @end example This would cause GDB to run OpenOCD and communicate using pipes (stdin/stdout). Using this method has the advantage of GDB starting/stopping OpenOCD for the debug session. log_output sends the log output to a file to ensure that the pipe is not saturated when using higher debug level outputs. @end enumerate To list the available OpenOCD commands type @command{monitor help} on the GDB command line. @section Sample GDB session startup With the remote protocol, GDB sessions start a little differently than they do when you're debugging locally. Here's an example showing how to start a debug session with a small ARM program. In this case the program was linked to be loaded into SRAM on a Cortex-M3. Most programs would be written into flash (address 0) and run from there. @example $ arm-none-eabi-gdb example.elf (gdb) target extended-remote localhost:3333 Remote debugging using localhost:3333 ... (gdb) monitor reset halt ... (gdb) load Loading section .vectors, size 0x100 lma 0x20000000 Loading section .text, size 0x5a0 lma 0x20000100 Loading section .data, size 0x18 lma 0x200006a0 Start address 0x2000061c, load size 1720 Transfer rate: 22 KB/sec, 573 bytes/write. (gdb) continue Continuing. ... @end example You could then interrupt the GDB session to make the program break, type @command{where} to show the stack, @command{list} to show the code around the program counter, @command{step} through code, set breakpoints or watchpoints, and so on. @section Configuring GDB for OpenOCD OpenOCD supports the gdb @option{qSupported} packet, this enables information to be sent by the GDB remote server (i.e. OpenOCD) to GDB. Typical information includes packet size and the device's memory map. You do not need to configure the packet size by hand, and the relevant parts of the memory map should be automatically set up when you declare (NOR) flash banks. However, there are other things which GDB can't currently query. You may need to set those up by hand. As OpenOCD starts up, you will often see a line reporting something like: @example Info : lm3s.cpu: hardware has 6 breakpoints, 4 watchpoints @end example You can pass that information to GDB with these commands: @example set remote hardware-breakpoint-limit 6 set remote hardware-watchpoint-limit 4 @end example With that particular hardware (Cortex-M3) the hardware breakpoints only work for code running from flash memory. Most other ARM systems do not have such restrictions. Rather than typing such commands interactively, you may prefer to save them in a file and have GDB execute them as it starts, perhaps using a @file{.gdbinit} in your project directory or starting GDB using @command{gdb -x filename}. @section Programming using GDB @cindex Programming using GDB @anchor{programmingusinggdb} By default the target memory map is sent to GDB. This can be disabled by the following OpenOCD configuration option: @example gdb_memory_map disable @end example For this to function correctly a valid flash configuration must also be set in OpenOCD. For faster performance you should also configure a valid working area. Informing GDB of the memory map of the target will enable GDB to protect any flash areas of the target and use hardware breakpoints by default. This means that the OpenOCD option @command{gdb_breakpoint_override} is not required when using a memory map. @xref{gdbbreakpointoverride,,gdb_breakpoint_override}. To view the configured memory map in GDB, use the GDB command @option{info mem}. All other unassigned addresses within GDB are treated as RAM. GDB 6.8 and higher set any memory area not in the memory map as inaccessible. This can be changed to the old behaviour by using the following GDB command @example set mem inaccessible-by-default off @end example If @command{gdb_flash_program enable} is also used, GDB will be able to program any flash memory using the vFlash interface. GDB will look at the target memory map when a load command is given, if any areas to be programmed lie within the target flash area the vFlash packets will be used. If the target needs configuring before GDB programming, set target event gdb-flash-erase-start: @example $_TARGETNAME configure -event gdb-flash-erase-start BODY @end example @xref{targetevents,,Target Events}, for other GDB programming related events. To verify any flash programming the GDB command @option{compare-sections} can be used. @section Using GDB as a non-intrusive memory inspector @cindex Using GDB as a non-intrusive memory inspector @anchor{gdbmeminspect} If your project controls more than a blinking LED, let's say a heavy industrial robot or an experimental nuclear reactor, stopping the controlling process just because you want to attach GDB is not a good option. OpenOCD does not support GDB non-stop mode (might be implemented in the future). Though there is a possible setup where the target does not get stopped and GDB treats it as it were running. If the target supports background access to memory while it is running, you can use GDB in this mode to inspect memory (mainly global variables) without any intrusion of the target process. Remove default setting of gdb-attach event. @xref{targetevents,,Target Events}. Place following command after target configuration: @example $_TARGETNAME configure -event gdb-attach @{@} @end example If any of installed flash banks does not support probe on running target, switch off gdb_memory_map: @example gdb_memory_map disable @end example Ensure GDB is configured without interrupt-on-connect. Some GDB versions set it by default, some does not. @example set remote interrupt-on-connect off @end example If you switched gdb_memory_map off, you may want to setup GDB memory map manually or issue @command{set mem inaccessible-by-default off} Now you can issue GDB command @command{target extended-remote ...} and inspect memory of a running target. Do not use GDB commands @command{continue}, @command{step} or @command{next} as they synchronize GDB with your target and GDB would require stopping the target to get the prompt back. Do not use this mode under an IDE like Eclipse as it caches values of previously shown variables. It's also possible to connect more than one GDB to the same target by the target's configuration option @code{-gdb-max-connections}. This allows, for example, one GDB to run a script that continuously polls a set of variables while other GDB can be used interactively. Be extremely careful in this case, because the two GDB can easily get out-of-sync. @section RTOS Support @cindex RTOS Support @anchor{gdbrtossupport} OpenOCD includes RTOS support, this will however need enabling as it defaults to disabled. It can be enabled by passing @option{-rtos} arg to the target. @xref{rtostype,,RTOS Type}. @xref{Threads, Debugging Programs with Multiple Threads, Debugging Programs with Multiple Threads, gdb, GDB manual}, for details about relevant GDB commands. @* An example setup is below: @example $_TARGETNAME configure -rtos auto @end example This will attempt to auto detect the RTOS within your application. Currently supported rtos's include: @itemize @bullet @item @option{eCos} @item @option{ThreadX} @item @option{FreeRTOS} @item @option{linux} @item @option{ChibiOS} @item @option{embKernel} @item @option{mqx} @item @option{uCOS-III} @item @option{nuttx} @item @option{RIOT} @item @option{hwthread} (This is not an actual RTOS. @xref{usingopenocdsmpwithgdb,,Using OpenOCD SMP with GDB}.) @item @option{Zephyr} @item @option{rtkernel} @end itemize At any time, it's possible to drop the selected RTOS using: @example $_TARGETNAME configure -rtos none @end example Before an RTOS can be detected, it must export certain symbols; otherwise, it cannot be used by OpenOCD. Below is a list of the required symbols for each supported RTOS. @table @code @item eCos symbols Cyg_Thread::thread_list, Cyg_Scheduler_Base::current_thread. @item ThreadX symbols _tx_thread_current_ptr, _tx_thread_created_ptr, _tx_thread_created_count. @item FreeRTOS symbols @raggedright pxCurrentTCB, pxReadyTasksLists, xDelayedTaskList1, xDelayedTaskList2, pxDelayedTaskList, pxOverflowDelayedTaskList, xPendingReadyList, uxCurrentNumberOfTasks, uxTopUsedPriority, xSchedulerRunning. @end raggedright @item linux symbols init_task. @item ChibiOS symbols rlist, ch_debug, chSysInit. @item embKernel symbols Rtos::sCurrentTask, Rtos::sListReady, Rtos::sListSleep, Rtos::sListSuspended, Rtos::sMaxPriorities, Rtos::sCurrentTaskCount. @item mqx symbols _mqx_kernel_data, MQX_init_struct. @item uC/OS-III symbols OSRunning, OSTCBCurPtr, OSTaskDbgListPtr, OSTaskQty. @item nuttx symbols g_readytorun, g_tasklisttable. @item RIOT symbols @raggedright sched_threads, sched_num_threads, sched_active_pid, max_threads, _tcb_name_offset. @end raggedright @item Zephyr symbols _kernel, _kernel_openocd_offsets, _kernel_openocd_size_t_size @item rtkernel symbols Multiple struct offsets. @end table For most RTOS supported the above symbols will be exported by default. However for some, eg. FreeRTOS, uC/OS-III and Zephyr, extra steps must be taken. Zephyr must be compiled with the DEBUG_THREAD_INFO option. This will generate some symbols with information needed in order to build the list of threads. FreeRTOS and uC/OS-III RTOSes may require additional OpenOCD-specific file to be linked along with the project: @table @code @item FreeRTOS contrib/rtos-helpers/FreeRTOS-openocd.c @item uC/OS-III contrib/rtos-helpers/uCOS-III-openocd.c @end table @anchor{usingopenocdsmpwithgdb} @section Using OpenOCD SMP with GDB @cindex SMP @cindex RTOS @cindex hwthread OpenOCD includes a pseudo RTOS called @emph{hwthread} that presents CPU cores ("hardware threads") in an SMP system as threads to GDB. With this extension, GDB can be used to inspect the state of an SMP system in a natural way. After halting the system, using the GDB command @command{info threads} will list the context of each active CPU core in the system. GDB's @command{thread} command can be used to switch the view to a different CPU core. The @command{step} and @command{stepi} commands can be used to step a specific core while other cores are free-running or remain halted, depending on the scheduler-locking mode configured in GDB. @node Tcl Scripting API @chapter Tcl Scripting API @cindex Tcl Scripting API @cindex Tcl scripts @section API rules Tcl commands are stateless; e.g. the @command{telnet} command has a concept of currently active target, the Tcl API proc's take this sort of state information as an argument to each proc. There are three main types of return values: single value, name value pair list and lists. Name value pair. The proc 'foo' below returns a name/value pair list. @example > set foo(me) Duane > set foo(you) Oyvind > set foo(mouse) Micky > set foo(duck) Donald @end example If one does this: @example > set foo @end example The result is: @example me Duane you Oyvind mouse Micky duck Donald @end example Thus, to get the names of the associative array is easy: @verbatim foreach { name value } [set foo] { puts "Name: $name, Value: $value" } @end verbatim Lists returned should be relatively small. Otherwise, a range should be passed in to the proc in question. @section Internal low-level Commands By "low-level", we mean commands that a human would typically not invoke directly. @itemize @item @b{flash banks} <@var{driver}> <@var{base}> <@var{size}> <@var{chip_width}> <@var{bus_width}> <@var{target}> [@option{driver options} ...] Return information about the flash banks @item @b{capture} <@var{command}> Run <@var{command}> and return full log output that was produced during its execution. Example: @example > capture "reset init" @end example @end itemize OpenOCD commands can consist of two words, e.g. "flash banks". The @file{startup.tcl} "unknown" proc will translate this into a Tcl proc called "flash_banks". @section Tcl RPC server @cindex RPC OpenOCD provides a simple RPC server that allows to run arbitrary Tcl commands and receive the results. To access it, your application needs to connect to a configured TCP port (see @command{tcl_port}). Then it can pass any string to the interpreter terminating it with @code{0x1a} and wait for the return value (it will be terminated with @code{0x1a} as well). This can be repeated as many times as desired without reopening the connection. It is not needed anymore to prefix the OpenOCD commands with @code{ocd_} to get the results back. But sometimes you might need the @command{capture} command. See @file{contrib/rpc_examples/} for specific client implementations. @section Tcl RPC server notifications @cindex RPC Notifications Notifications are sent asynchronously to other commands being executed over the RPC server, so the port must be polled continuously. Target event, state and reset notifications are emitted as Tcl associative arrays in the following format. @verbatim type target_event event [event-name] type target_state state [state-name] type target_reset mode [reset-mode] @end verbatim @deffn {Command} {tcl_notifications} [on/off] Toggle output of target notifications to the current Tcl RPC server. Only available from the Tcl RPC server. Defaults to off. @end deffn @section Tcl RPC server trace output @cindex RPC trace output Trace data is sent asynchronously to other commands being executed over the RPC server, so the port must be polled continuously. Target trace data is emitted as a Tcl associative array in the following format. @verbatim type target_trace data [trace-data-hex-encoded] @end verbatim @deffn {Command} {tcl_trace} [on/off] Toggle output of target trace data to the current Tcl RPC server. Only available from the Tcl RPC server. Defaults to off. See an example application here: @url{https://github.com/apmorton/OpenOcdTraceUtil} [OpenOcdTraceUtil] @end deffn @node FAQ @chapter FAQ @cindex faq @enumerate @anchor{faqrtck} @item @b{RTCK, also known as: Adaptive Clocking - What is it?} @cindex RTCK @cindex adaptive clocking @* In digital circuit design it is often referred to as ``clock synchronisation'' the JTAG interface uses one clock (TCK or TCLK) operating at some speed, your CPU target is operating at another. The two clocks are not synchronised, they are ``asynchronous'' In order for the two to work together they must be synchronised well enough to work; JTAG can't go ten times faster than the CPU, for example. There are 2 basic options: @enumerate @item Use a special "adaptive clocking" circuit to change the JTAG clock rate to match what the CPU currently supports. @item The JTAG clock must be fixed at some speed that's enough slower than the CPU clock that all TMS and TDI transitions can be detected. @end enumerate @b{Does this really matter?} For some chips and some situations, this is a non-issue, like a 500MHz ARM926 with a 5 MHz JTAG link; the CPU has no difficulty keeping up with JTAG. Startup sequences are often problematic though, as are other situations where the CPU clock rate changes (perhaps to save power). For example, Atmel AT91SAM chips start operation from reset with a 32kHz system clock. Boot firmware may activate the main oscillator and PLL before switching to a faster clock (perhaps that 500 MHz ARM926 scenario). If you're using JTAG to debug that startup sequence, you must slow the JTAG clock to sometimes 1 to 4kHz. After startup completes, JTAG can use a faster clock. Consider also debugging a 500MHz ARM926 hand held battery powered device that enters a low power ``deep sleep'' mode, at 32kHz CPU clock, between keystrokes unless it has work to do. When would that 5 MHz JTAG clock be usable? @b{Solution #1 - A special circuit} In order to make use of this, your CPU, board, and JTAG adapter must all support the RTCK feature. Not all of them support this; keep reading! The RTCK ("Return TCK") signal in some ARM chips is used to help with this problem. ARM has a good description of the problem described at this link: @url{http://www.arm.com/support/faqdev/4170.html} [checked 28/nov/2008]. Link title: ``How does the JTAG synchronisation logic work? / how does adaptive clocking work?''. The nice thing about adaptive clocking is that ``battery powered hand held device example'' - the adaptiveness works perfectly all the time. One can set a break point or halt the system in the deep power down code, slow step out until the system speeds up. Note that adaptive clocking may also need to work at the board level, when a board-level scan chain has multiple chips. Parallel clock voting schemes are good way to implement this, both within and between chips, and can easily be implemented with a CPLD. It's not difficult to have logic fan a module's input TCK signal out to each TAP in the scan chain, and then wait until each TAP's RTCK comes back with the right polarity before changing the output RTCK signal. Texas Instruments makes some clock voting logic available for free (with no support) in VHDL form; see @url{http://tiexpressdsp.com/index.php/Adaptive_Clocking} @b{Solution #2 - Always works - but may be slower} Often this is a perfectly acceptable solution. In most simple terms: Often the JTAG clock must be 1/10 to 1/12 of the target clock speed. But what that ``magic division'' is varies depending on the chips on your board. @b{ARM rule of thumb} Most ARM based systems require an 6:1 division; ARM11 cores use an 8:1 division. @b{Xilinx rule of thumb} is 1/12 the clock speed. Note: most full speed FT2232 based JTAG adapters are limited to a maximum of 6MHz. The ones using USB high speed chips (FT2232H) often support faster clock rates (and adaptive clocking). You can still debug the 'low power' situations - you just need to either use a fixed and very slow JTAG clock rate ... or else manually adjust the clock speed at every step. (Adjusting is painful and tedious, and is not always practical.) It is however easy to ``code your way around it'' - i.e.: Cheat a little, have a special debug mode in your application that does a ``high power sleep''. If you are careful - 98% of your problems can be debugged this way. Note that on ARM you may need to avoid using the @emph{wait for interrupt} operation in your idle loops even if you don't otherwise change the CPU clock rate. That operation gates the CPU clock, and thus the JTAG clock; which prevents JTAG access. One consequence is not being able to @command{halt} cores which are executing that @emph{wait for interrupt} operation. To set the JTAG frequency use the command: @example # Example: 1.234MHz adapter speed 1234 @end example @item @b{Win32 Pathnames} Why don't backslashes work in Windows paths? OpenOCD uses Tcl and a backslash is an escape char. Use @{ and @} around Windows filenames. @example > echo \a > echo @{\a@} \a > echo "\a" > @end example @item @b{Missing: cygwin1.dll} OpenOCD complains about a missing cygwin1.dll. Make sure you have Cygwin installed, or at least a version of OpenOCD that claims to come with all the necessary DLLs. When using Cygwin, try launching OpenOCD from the Cygwin shell. @item @b{Breakpoint Issue} I'm trying to set a breakpoint using GDB (or a front-end like Insight or Eclipse), but OpenOCD complains that "Info: arm7_9_common.c:213 arm7_9_add_breakpoint(): sw breakpoint requested, but software breakpoints not enabled". GDB issues software breakpoints when a normal breakpoint is requested, or to implement source-line single-stepping. On ARMv4T systems, like ARM7TDMI, ARM720T or ARM920T, software breakpoints consume one of the two available hardware breakpoints. @item @b{LPC2000 Flash} When erasing or writing LPC2000 on-chip flash, the operation fails at random. Make sure the core frequency specified in the @option{flash lpc2000} line matches the clock at the time you're programming the flash. If you've specified the crystal's frequency, make sure the PLL is disabled. If you've specified the full core speed (e.g. 60MHz), make sure the PLL is enabled. @item @b{Amontec Chameleon} When debugging using an Amontec Chameleon in its JTAG Accelerator configuration, I keep getting "Error: amt_jtagaccel.c:184 amt_wait_scan_busy(): amt_jtagaccel timed out while waiting for end of scan, rtck was disabled". Make sure your PC's parallel port operates in EPP mode. You might have to try several settings in your PC BIOS (ECP, EPP, and different versions of those). @item @b{Data Aborts} When debugging with OpenOCD and GDB (plain GDB, Insight, or Eclipse), I get lots of "Error: arm7_9_common.c:1771 arm7_9_read_memory(): memory read caused data abort". The errors are non-fatal, and are the result of GDB trying to trace stack frames beyond the last valid frame. It might be possible to prevent this by setting up a proper "initial" stack frame, if you happen to know what exactly has to be done, feel free to add this here. @b{Simple:} In your startup code - push 8 registers of zeros onto the stack before calling main(). What GDB is doing is ``climbing'' the run time stack by reading various values on the stack using the standard call frame for the target. GDB keeps going - until one of 2 things happen @b{#1} an invalid frame is found, or @b{#2} some huge number of stackframes have been processed. By pushing zeros on the stack, GDB gracefully stops. @b{Debugging Interrupt Service Routines} - In your ISR before you call your C code, do the same - artificially push some zeros onto the stack, remember to pop them off when the ISR is done. @b{Also note:} If you have a multi-threaded operating system, they often do not @b{in the interest of saving memory} waste these few bytes. Painful... @item @b{JTAG Reset Config} I get the following message in the OpenOCD console (or log file): "Warning: arm7_9_common.c:679 arm7_9_assert_reset(): srst resets test logic, too". This warning doesn't indicate any serious problem, as long as you don't want to debug your core right out of reset. Your .cfg file specified @option{reset_config trst_and_srst srst_pulls_trst} to tell OpenOCD that either your board, your debugger or your target uC (e.g. LPC2000) can't assert the two reset signals independently. With this setup, it's not possible to halt the core right out of reset, everything else should work fine. @item @b{USB Power} When using OpenOCD in conjunction with Amontec JTAGkey and the Yagarto toolchain (Eclipse, arm-elf-gcc, arm-elf-gdb), the debugging seems to be unstable. When single-stepping over large blocks of code, GDB and OpenOCD quit with an error message. Is there a stability issue with OpenOCD? No, this is not a stability issue concerning OpenOCD. Most users have solved this issue by simply using a self-powered USB hub, which they connect their Amontec JTAGkey to. Apparently, some computers do not provide a USB power supply stable enough for the Amontec JTAGkey to be operated. @b{Laptops running on battery have this problem too...} @item @b{GDB Disconnects} When using the Amontec JTAGkey, sometimes OpenOCD crashes with the following error message: "Error: gdb_server.c:101 gdb_get_char(): read: 10054". What does that mean and what might be the reason for this? Error code 10054 corresponds to WSAECONNRESET, which means that the debugger (GDB) has closed the connection to OpenOCD. This might be a GDB issue. @item @b{LPC2000 Flash} In the configuration file in the section where flash device configurations are described, there is a parameter for specifying the clock frequency for LPC2000 internal flash devices (e.g. @option{flash bank $_FLASHNAME lpc2000 0x0 0x40000 0 0 $_TARGETNAME lpc2000_v1 14746 calc_checksum}), which must be specified in kilohertz. However, I do have a quartz crystal of a frequency that contains fractions of kilohertz (e.g. 14,745,600 Hz, i.e. 14,745.600 kHz). Is it possible to specify real numbers for the clock frequency? No. The clock frequency specified here must be given as an integral number. However, this clock frequency is used by the In-Application-Programming (IAP) routines of the LPC2000 family only, which seems to be very tolerant concerning the given clock frequency, so a slight difference between the specified clock frequency and the actual clock frequency will not cause any trouble. @item @b{Command Order} Do I have to keep a specific order for the commands in the configuration file? Well, yes and no. Commands can be given in arbitrary order, yet the devices listed for the JTAG scan chain must be given in the right order (jtag newdevice), with the device closest to the TDO-Pin being listed first. In general, whenever objects of the same type exist which require an index number, then these objects must be given in the right order (jtag newtap, targets and flash banks - a target references a jtag newtap and a flash bank references a target). You can use the ``scan_chain'' command to verify and display the tap order. Also, some commands can't execute until after @command{init} has been processed. Such commands include @command{nand probe} and everything else that needs to write to controller registers, perhaps for setting up DRAM and loading it with code. @anchor{faqtaporder} @item @b{JTAG TAP Order} Do I have to declare the TAPS in some particular order? Yes; whenever you have more than one, you must declare them in the same order used by the hardware. Many newer devices have multiple JTAG TAPs. For example: STMicroelectronics STM32 chips have two TAPs, a ``boundary scan TAP'' and ``Cortex-M3'' TAP. Example: The STM32 reference manual, Document ID: RM0008, Section 26.5, Figure 259, page 651/681, the ``TDI'' pin is connected to the boundary scan TAP, which then connects to the Cortex-M3 TAP, which then connects to the TDO pin. Thus, the proper order for the STM32 chip is: (1) The Cortex-M3, then (2) The boundary scan TAP. If your board includes an additional JTAG chip in the scan chain (for example a Xilinx CPLD or FPGA) you could place it before or after the STM32 chip in the chain. For example: @itemize @bullet @item OpenOCD_TDI(output) -> STM32 TDI Pin (BS Input) @item STM32 BS TDO (output) -> STM32 Cortex-M3 TDI (input) @item STM32 Cortex-M3 TDO (output) -> SM32 TDO Pin @item STM32 TDO Pin (output) -> Xilinx TDI Pin (input) @item Xilinx TDO Pin -> OpenOCD TDO (input) @end itemize The ``jtag device'' commands would thus be in the order shown below. Note: @itemize @bullet @item jtag newtap Xilinx tap -irlen ... @item jtag newtap stm32 cpu -irlen ... @item jtag newtap stm32 bs -irlen ... @item # Create the debug target and say where it is @item target create stm32.cpu -chain-position stm32.cpu ... @end itemize @item @b{SYSCOMP} Sometimes my debugging session terminates with an error. When I look into the log file, I can see these error messages: Error: arm7_9_common.c:561 arm7_9_execute_sys_speed(): timeout waiting for SYSCOMP TODO. @end enumerate @node Tcl Crash Course @chapter Tcl Crash Course @cindex Tcl Not everyone knows Tcl - this is not intended to be a replacement for learning Tcl, the intent of this chapter is to give you some idea of how the Tcl scripts work. This chapter is written with two audiences in mind. (1) OpenOCD users who need to understand a bit more of how Jim-Tcl works so they can do something useful, and (2) those that want to add a new command to OpenOCD. @section Tcl Rule #1 There is a famous joke, it goes like this: @enumerate @item Rule #1: The wife is always correct @item Rule #2: If you think otherwise, See Rule #1 @end enumerate The Tcl equal is this: @enumerate @item Rule #1: Everything is a string @item Rule #2: If you think otherwise, See Rule #1 @end enumerate As in the famous joke, the consequences of Rule #1 are profound. Once you understand Rule #1, you will understand Tcl. @section Tcl Rule #1b There is a second pair of rules. @enumerate @item Rule #1: Control flow does not exist. Only commands @* For example: the classic FOR loop or IF statement is not a control flow item, they are commands, there is no such thing as control flow in Tcl. @item Rule #2: If you think otherwise, See Rule #1 @* Actually what happens is this: There are commands that by convention, act like control flow key words in other languages. One of those commands is the word ``for'', another command is ``if''. @end enumerate @section Per Rule #1 - All Results are strings Every Tcl command results in a string. The word ``result'' is used deliberately. No result is just an empty string. Remember: @i{Rule #1 - Everything is a string} @section Tcl Quoting Operators In life of a Tcl script, there are two important periods of time, the difference is subtle. @enumerate @item Parse Time @item Evaluation Time @end enumerate The two key items here are how ``quoted things'' work in Tcl. Tcl has three primary quoting constructs, the [square-brackets] the @{curly-braces@} and ``double-quotes'' By now you should know $VARIABLES always start with a $DOLLAR sign. BTW: To set a variable, you actually use the command ``set'', as in ``set VARNAME VALUE'' much like the ancient BASIC language ``let x = 1'' statement, but without the equal sign. @itemize @bullet @item @b{[square-brackets]} @* @b{[square-brackets]} are command substitutions. It operates much like Unix Shell `back-ticks`. The result of a [square-bracket] operation is exactly 1 string. @i{Remember Rule #1 - Everything is a string}. These two statements are roughly identical: @example # bash example X=`date` echo "The Date is: $X" # Tcl example set X [date] puts "The Date is: $X" @end example @item @b{``double-quoted-things''} @* @b{``double-quoted-things''} are just simply quoted text. $VARIABLES and [square-brackets] are expanded in place - the result however is exactly 1 string. @i{Remember Rule #1 - Everything is a string} @example set x "Dinner" puts "It is now \"[date]\", $x is in 1 hour" @end example @item @b{@{Curly-Braces@}} @*@b{@{Curly-Braces@}} are magic: $VARIABLES and [square-brackets] are parsed, but are NOT expanded or executed. @{Curly-Braces@} are like 'single-quote' operators in BASH shell scripts, with the added feature: @{curly-braces@} can be nested, single quotes can not. @{@{@{this is nested 3 times@}@}@} NOTE: [date] is a bad example; at this writing, Jim/OpenOCD does not have a date command. @end itemize @section Consequences of Rule 1/2/3/4 The consequences of Rule 1 are profound. @subsection Tokenisation & Execution. Of course, whitespace, blank lines and #comment lines are handled in the normal way. As a script is parsed, each (multi) line in the script file is tokenised and according to the quoting rules. After tokenisation, that line is immediately executed. Multi line statements end with one or more ``still-open'' @{curly-braces@} which - eventually - closes a few lines later. @subsection Command Execution Remember earlier: There are no ``control flow'' statements in Tcl. Instead there are COMMANDS that simply act like control flow operators. Commands are executed like this: @enumerate @item Parse the next line into (argc) and (argv[]). @item Look up (argv[0]) in a table and call its function. @item Repeat until End Of File. @end enumerate It sort of works like this: @example for(;;)@{ ReadAndParse( &argc, &argv ); cmdPtr = LookupCommand( argv[0] ); (*cmdPtr->Execute)( argc, argv ); @} @end example When the command ``proc'' is parsed (which creates a procedure function) it gets 3 parameters on the command line. @b{1} the name of the proc (function), @b{2} the list of parameters, and @b{3} the body of the function. Note the choice of words: LIST and BODY. The PROC command stores these items in a table somewhere so it can be found by ``LookupCommand()'' @subsection The FOR command The most interesting command to look at is the FOR command. In Tcl, the FOR command is normally implemented in C. Remember, FOR is a command just like any other command. When the ascii text containing the FOR command is parsed, the parser produces 5 parameter strings, @i{(If in doubt: Refer to Rule #1)} they are: @enumerate 0 @item The ascii text 'for' @item The start text @item The test expression @item The next text @item The body text @end enumerate Sort of reminds you of ``main( int argc, char **argv )'' does it not? Remember @i{Rule #1 - Everything is a string.} The key point is this: Often many of those parameters are in @{curly-braces@} - thus the variables inside are not expanded or replaced until later. Remember that every Tcl command looks like the classic ``main( argc, argv )'' function in C. In JimTCL - they actually look like this: @example int MyCommand( Jim_Interp *interp, int *argc, Jim_Obj * const *argvs ); @end example Real Tcl is nearly identical. Although the newer versions have introduced a byte-code parser and interpreter, but at the core, it still operates in the same basic way. @subsection FOR command implementation To understand Tcl it is perhaps most helpful to see the FOR command. Remember, it is a COMMAND not a control flow structure. In Tcl there are two underlying C helper functions. Remember Rule #1 - You are a string. The @b{first} helper parses and executes commands found in an ascii string. Commands can be separated by semicolons, or newlines. While parsing, variables are expanded via the quoting rules. The @b{second} helper evaluates an ascii string as a numerical expression and returns a value. Here is an example of how the @b{FOR} command could be implemented. The pseudo code below does not show error handling. @example void Execute_AsciiString( void *interp, const char *string ); int Evaluate_AsciiExpression( void *interp, const char *string ); int MyForCommand( void *interp, int argc, char **argv ) @{ if( argc != 5 )@{ SetResult( interp, "WRONG number of parameters"); return ERROR; @} // argv[0] = the ascii string just like C // Execute the start statement. Execute_AsciiString( interp, argv[1] ); // Top of loop test for(;;)@{ i = Evaluate_AsciiExpression(interp, argv[2]); if( i == 0 ) break; // Execute the body Execute_AsciiString( interp, argv[3] ); // Execute the LOOP part Execute_AsciiString( interp, argv[4] ); @} // Return no error SetResult( interp, "" ); return SUCCESS; @} @end example Every other command IF, WHILE, FORMAT, PUTS, EXPR, everything works in the same basic way. @section OpenOCD Tcl Usage @subsection source and find commands @b{Where:} In many configuration files @* Example: @b{ source [find FILENAME] } @*Remember the parsing rules @enumerate @item The @command{find} command is in square brackets, and is executed with the parameter FILENAME. It should find and return the full path to a file with that name; it uses an internal search path. The RESULT is a string, which is substituted into the command line in place of the bracketed @command{find} command. (Don't try to use a FILENAME which includes the "#" character. That character begins Tcl comments.) @item The @command{source} command is executed with the resulting filename; it reads a file and executes as a script. @end enumerate @subsection format command @b{Where:} Generally occurs in numerous places. @* Tcl has no command like @b{printf()}, instead it has @b{format}, which is really more like @b{sprintf()}. @b{Example} @example set x 6 set y 7 puts [format "The answer: %d" [expr @{$x * $y@}]] @end example @enumerate @item The SET command creates 2 variables, X and Y. @item The double [nested] EXPR command performs math @* The EXPR command produces numerical result as a string. @* Refer to Rule #1 @item The format command is executed, producing a single string @* Refer to Rule #1. @item The PUTS command outputs the text. @end enumerate @subsection Body or Inlined Text @b{Where:} Various TARGET scripts. @example #1 Good proc someproc @{@} @{ ... multiple lines of stuff ... @} $_TARGETNAME configure -event FOO someproc #2 Good - no variables $_TARGETNAME configure -event foo "this ; that;" #3 Good Curly Braces $_TARGETNAME configure -event FOO @{ puts "Time: [date]" @} #4 DANGER DANGER DANGER $_TARGETNAME configure -event foo "puts \"Time: [date]\"" @end example @enumerate @item The $_TARGETNAME is an OpenOCD variable convention. @*@b{$_TARGETNAME} represents the last target created, the value changes each time a new target is created. Remember the parsing rules. When the ascii text is parsed, the @b{$_TARGETNAME} becomes a simple string, the name of the target which happens to be a TARGET (object) command. @item The 2nd parameter to the @option{-event} parameter is a TCBODY @*There are 4 examples: @enumerate @item The TCLBODY is a simple string that happens to be a proc name @item The TCLBODY is several simple commands separated by semicolons @item The TCLBODY is a multi-line @{curly-brace@} quoted string @item The TCLBODY is a string with variables that get expanded. @end enumerate In the end, when the target event FOO occurs the TCLBODY is evaluated. Method @b{#1} and @b{#2} are functionally identical. For Method @b{#3} and @b{#4} it is more interesting. What is the TCLBODY? Remember the parsing rules. In case #3, @{curly-braces@} mean the $VARS and [square-brackets] are expanded later, when the EVENT occurs, and the text is evaluated. In case #4, they are replaced before the ``Target Object Command'' is executed. This occurs at the same time $_TARGETNAME is replaced. In case #4 the date will never change. @{BTW: [date] is a bad example; at this writing, Jim/OpenOCD does not have a date command@} @end enumerate @subsection Global Variables @b{Where:} You might discover this when writing your own procs @* In simple terms: Inside a PROC, if you need to access a global variable you must say so. See also ``upvar''. Example: @example proc myproc @{ @} @{ set y 0 #Local variable Y global x #Global variable X puts [format "X=%d, Y=%d" $x $y] @} @end example @section Other Tcl Hacks @b{Dynamic variable creation} @example # Dynamically create a bunch of variables. for @{ set x 0 @} @{ $x < 32 @} @{ set x [expr @{$x + 1@}]@} @{ # Create var name set vn [format "BIT%d" $x] # Make it a global global $vn # Set it. set $vn [expr @{1 << $x@}] @} @end example @b{Dynamic proc/command creation} @example # One "X" function - 5 uart functions. foreach who @{A B C D E@} proc [format "show_uart%c" $who] @{ @} "show_UARTx $who" @} @end example @node License @appendix The GNU Free Documentation License. @include fdl.texi @node OpenOCD Concept Index @comment DO NOT use the plain word ``Index'', reason: CYGWIN filename @comment case issue with ``Index.html'' and ``index.html'' @comment Occurs when creating ``--html --no-split'' output @comment This fix is based on: http://sourceware.org/ml/binutils/2006-05/msg00215.html @unnumbered OpenOCD Concept Index @printindex cp @node Command and Driver Index @unnumbered Command and Driver Index @printindex fn @bye ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/cmsis_dap/04b4_f155_cypress_kitprog3.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # KitProg3 Firmware 1.01 # Has inconsistent class code 0 for CMSIS-DAP interface Bus 002 Device 017: ID 04b4:f155 Cypress Semiconductor Corp. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 ? bDeviceProtocol 1 Interface Association bMaxPacketSize0 8 idVendor 0x04b4 Cypress Semiconductor Corp. idProduct 0xf155 bcdDevice 1.01 iManufacturer 1 Cypress Semiconductor iProduct 6 KitProg3 CMSIS-DAP iSerial 128 102015B003137400 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 130 bNumInterfaces 4 bConfigurationValue 1 iConfiguration 11 KitProg3 CMSIS-DAP bmAttributes 0x80 (Bus Powered) MaxPower 400mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 0 (Defined at Interface level) bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 6 KitProg3 CMSIS-DAP Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 No Subclass bInterfaceProtocol 0 None iInterface 12 KitProg3 bridge HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.11 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 43 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x86 EP 6 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x07 EP 7 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 2 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 0 None iFunction 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 15 KitProg3 USBUART CDC Header: bcdCDC 1.10 CDC ACM: bmCapabilities 0x02 line coding and serial state CDC Union: bMasterInterface 2 bSlaveInterface 3 CDC Call Management: bmCapabilities 0x00 bDataInterface 3 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0008 1x 8 bytes bInterval 2 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 Unused bInterfaceProtocol 0 iInterface 4 KitProg3 USBUART Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x05 EP 5 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/cmsis_dap/0d28_0204_nxp_daplink.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Board: NXP FRDM-K64F Bus 001 Device 006: ID 0d28:0204 NXP ARM mbed Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x0d28 NXP idProduct 0x0204 ARM mbed bcdDevice 10.00 iManufacturer 1 ARM iProduct 2 DAPLink CMSIS-DAP iSerial 3 0240000031754e45002f00199485002b6461000097969900 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0082 bNumInterfaces 4 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 8 Mass Storage bInterfaceSubClass 6 SCSI bInterfaceProtocol 80 Bulk-Only iInterface 7 USB_MSC Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 6 CMSIS-DAP HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.00 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 33 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 1 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 4 mbed Serial Port Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 4 mbed Serial Port CDC Header: bcdCDC 1.10 CDC Call Management: bmCapabilities 0x03 call management use DataInterface bDataInterface 2 CDC ACM: bmCapabilities 0x06 sends break line coding and serial state CDC Union: bMasterInterface 1 bSlaveInterface 2 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0010 1x 16 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 5 mbed Serial Port Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/cmsis_dap/1a6a_2000_spansion_sk_fm4.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Reported in https://en.opensuse.org/User:A_faerber/SK-FM4-176L-S6E2CC Bus 002 Device 009: ID 1a6a:2000 Spansion Inc. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.01 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x1a6a Spansion Inc. idProduct 0x2000 bcdDevice 1.60 iManufacturer 1 Spansion iProduct 2 Spansion CMSIS-DAP + COM Port iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 107 bNumInterfaces 3 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x00 (Missing must-be-set bit!) (Bus Powered) MaxPower 62mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 No Subclass bInterfaceProtocol 0 None iInterface 4 Spansion CMSIS-DAP HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.11 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 29 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 1 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 5 Spansion USB Serial Port Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 0 CDC Header: bcdCDC 10.01 CDC ACM: bmCapabilities 0x00 CDC Union: bMasterInterface 1 bSlaveInterface 2 CDC Call Management: bmCapabilities 0x01 call management bDataInterface 2 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 255 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 Unused bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/cmsis_dap/2a86_8011_wch_link.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Reported in https://github.com/pyocd/pyOCD/issues/1395 Bus 003 Device 118: ID 2a86:8011 wch.cn WCH-Link Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 8 idVendor 0x2a86 idProduct 0x8011 bcdDevice 1.00 iManufacturer 1 wch.cn iProduct 2 WCH-Link iSerial 3 0001A0000001 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x006b bNumInterfaces 3 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 0 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 4 QYF CMSIS-DAP Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 0 iInterface 4 QYF CMSIS-DAP CDC Header: bcdCDC 1.10 CDC Call Management: bmCapabilities 0x01 call management bDataInterface 1 CDC ACM: bmCapabilities 0x02 line coding and serial state CDC Union: bMasterInterface 0 bSlaveInterface 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 2 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 5 (error) Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x03 EP 3 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 6 QYF CMSIS-DAP HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.00 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 33 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/cmsis_dap/c251_2722_keil_ulink2.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Standalone adapter Bus 001 Device 010: ID c251:2722 Keil Software, Inc. Keil ULINK2 CMSIS-DAP Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0xc251 Keil Software, Inc. idProduct 0x2722 bcdDevice 1.00 iManufacturer 1 Keil Software iProduct 2 Keil ULINK2 CMSIS-DAP iSerial 3 V0022U9E bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0029 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 4 CMSIS-DAP HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.00 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 33 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/cmsis_dap/c251_2723_keil_ulink_me.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Reported in https://stackoverflow.com/questions/27087281/jtag-adapter-ulink-me-and-openocd-on-archlinux Bus 005 Device 026: ID c251:2723 Keil Software, Inc. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0xc251 Keil Software, Inc. idProduct 0x2723 bcdDevice 1.00 iManufacturer 1 Keil Software iProduct 2 Keil ULINK-ME CMSIS-DAP iSerial 3 M0489MAE bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 41 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 No Subclass bInterfaceProtocol 0 None iInterface 4 CMSIS-DAP HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.00 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 33 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/cmsis_dap/c251_2750_keil_ulinkplus.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # firmware 2.0.11 Bus 001 Device 005: ID c251:2750 Keil Software, Inc. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0xc251 Keil Software, Inc. idProduct 0x2750 bcdDevice 1.00 iManufacturer 1 KEIL - Tools By ARM iProduct 2 Keil ULINKplus iSerial 3 L78440715A bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 101 bNumInterfaces 4 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 4 ULINKplus CMSIS-DAP Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 5 ULINKplus Digital I/O Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 6 ULINKplus Analog I/O Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x03 EP 3 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 7 ULINKplus Power Probe Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/cmsis_dap/c251_f001_jixin.pro.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Reported in https://sourceforge.net/p/openocd/tickets/368/ Bus 001 Device 008: ID c251:f001 Keil Software, Inc. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 ? bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0xc251 Keil Software, Inc. idProduct 0xf001 bcdDevice 1.00 iManufacturer 1 jixin.pro iProduct 2 CMSIS-DAP_LU iSerial 3 LU_2022_8888 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 107 bNumInterfaces 3 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 0 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 4 CMSIS-DAP CDC Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 0 None iInterface 4 CMSIS-DAP CDC CDC Header: bcdCDC 1.10 CDC Call Management: bmCapabilities 0x01 call management bDataInterface 1 CDC ACM: bmCapabilities 0x02 line coding and serial state CDC Union: bMasterInterface 0 bSlaveInterface 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 2 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 Unused bInterfaceProtocol 0 iInterface 5 CMSIS-DAP DCI Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 No Subclass bInterfaceProtocol 0 None iInterface 6 CMSIS-DAP_LU HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.00 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 33 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x03 EP 3 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/dump.sh ================================================ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later devs=$(lsusb -d $1:$2 | wc -l) case "$devs" in 0 ) echo "Error: USB device $1:$2 not found" > /dev/stderr exit 1 ;; 1 ) echo "Dumping $(lsusb -d $1:$2)" > /dev/stderr ;; * ) echo "Error: Multiple matches for 'lsusb -d $1:$2'" > /dev/stderr exit 1 ;; esac # break SPDX tag to hide it to checkpatch echo '# SPDX-''License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later' echo '' echo '# Optional comment' lsusb -v -d $1:$2 | sed 's/ *$//' ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/esp_usb_jtag/303a_1001_esp_usb_jtag.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Optional comment Bus 002 Device 035: ID 303a:1001 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x303a idProduct 0x1001 bcdDevice 1.01 iManufacturer 1 Espressif iProduct 2 USB JTAG/serial debug unit iSerial 3 7C:DF:A1:A2:8F:38 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0062 bNumInterfaces 3 bConfigurationValue 1 iConfiguration 0 bmAttributes 0xc0 Self Powered MaxPower 500mA Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 0 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 0 iFunction 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 0 iInterface 0 CDC Header: bcdCDC 1.10 CDC ACM: bmCapabilities 0x02 line coding and serial state CDC Union: bMasterInterface 0 bSlaveInterface 1 CDC Call Management: bmCapabilities 0x03 call management use DataInterface bDataInterface 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 2 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 1 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Device Status: 0x0001 Self Powered ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/ft232r/0403_6001_ft232r.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Board: FT232RL # Chip: FT232RL Bus 001 Device 005: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 8 idVendor 0x0403 Future Technology Devices International, Ltd idProduct 0x6001 FT232 Serial (UART) IC bcdDevice 6.00 iManufacturer 1 FTDI iProduct 2 FT232R USB UART iSerial 3 A50285BI bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0020 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0xa0 (Bus Powered) Remote Wakeup MaxPower 90mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 2 FT232R USB UART Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/ftdi/0403_6010_ft2232h.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Board: Steppenprobe # Link: https://github.com/diegoherranz/steppenprobe # Chip: FT2232HL Bus 001 Device 012: ID 0403:6010 Future Technology Devices International, Ltd FT2232C/D/H Dual UART/FIFO IC Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0403 Future Technology Devices International, Ltd idProduct 0x6010 FT2232C/D/H Dual UART/FIFO IC bcdDevice 7.00 iManufacturer 1 FTDI iProduct 2 Dual RS232-HS iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0037 bNumInterfaces 2 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 2 Dual RS232-HS Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 2 Dual RS232-HS Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/ftdi/0403_6014_digilent_hs2.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Reported in https://sourceforge.net/p/openocd/tickets/357/ Bus 001 Device 084: ID 0403:6014 Future Technology Devices International, Ltd FT232H Single HS USB-UART/FIFO IC Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0403 Future Technology Devices International, Ltd idProduct 0x6014 FT232H Single HS USB-UART/FIFO IC bcdDevice 9.00 iManufacturer 1 Digilent iProduct 2 Digilent USB Device iSerial 3 210249AFCD0B bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0020 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 2 Digilent USB Device Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/ftdi/0403_cff8_amontec_jtagkey2.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Link: http://www.amontec.com # Casing: Hi-Speed JTAGkey-2 (c) 2009, Amontec # PCB: Amontec JTAGkey2 v5.3 # Chip: FT2232HQ Bus 001 Device 017: ID 0403:cff8 Future Technology Devices International, Ltd Amontec JTAGkey Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0403 Future Technology Devices International, Ltd idProduct 0xcff8 Amontec JTAGkey bcdDevice 7.00 iManufacturer 1 Amontec iProduct 2 Amontec JTAGkey-2 iSerial 3 53U2ML49 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0037 bNumInterfaces 2 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 2 Amontec JTAGkey-2 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 2 Amontec JTAGkey-2 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/ftdi/09fb_6001_altera_blaster.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Clone www.terasic.com "USB Blaster" # PCB reports: "USB Blaster-B", "FOR ALTERA ONLY" # Chip: FT245BL Bus 001 Device 005: ID 09fb:6001 Altera Blaster Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 8 idVendor 0x09fb Altera idProduct 0x6001 Blaster bcdDevice 4.00 iManufacturer 1 Altera iProduct 2 USB-Blaster iSerial 3 91f28492 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0020 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 150mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 2 USB-Blaster Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/ftdi/9e88_9e8f_sheevaplug_jtagkey.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Reported in https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=837989 Bus 003 Device 002: ID 9e88:9e8f Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 8 idVendor 0x9e88 idProduct 0x9e8f bcdDevice 5.00 iManufacturer 1 FTDI iProduct 2 SheevaPlug JTAGKey FT2232D B iSerial 3 FTU85Z4Y bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 55 bNumInterfaces 2 bConfigurationValue 1 iConfiguration 0 bmAttributes 0xc0 Self Powered MaxPower 0mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 2 SheevaPlug JTAGKey FT2232D B Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 2 SheevaPlug JTAGKey FT2232D B Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/icdi/1cbe_00fd_ti_icdi.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Board: TI Tiva C Series TM4C1294 Connected LaunchPad # ICDI firmware update to add OpenOCD support Bus 001 Device 016: ID 1cbe:00fd Luminary Micro Inc. In-Circuit Debug Interface Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x1cbe Luminary Micro Inc. idProduct 0x00fd In-Circuit Debug Interface bcdDevice 1.00 iManufacturer 1 Texas Instruments iProduct 2 In-Circuit Debug Interface iSerial 3 0F00CAC2 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0074 bNumInterfaces 4 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 250mA Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 0 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 0 CDC Header: bcdCDC 1.10 CDC ACM: bmCapabilities 0x06 sends break line coding and serial state CDC Union: bMasterInterface 0 bSlaveInterface 1 CDC Call Management: bmCapabilities 0x01 call management bDataInterface 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0010 1x 16 bytes bInterval 1 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 0 bInterfaceClass 254 Application Specific Interface bInterfaceSubClass 1 Device Firmware Update bInterfaceProtocol 1 iInterface 0 Device Firmware Upgrade Interface Descriptor: bLength 9 bDescriptorType 33 bmAttributes 15 Will Detach Manifestation Tolerant Upload Supported Download Supported wDetachTimeout 65535 milliseconds wTransferSize 1024 bytes bcdDFUVersion 1.10 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/jlink/1366_0101_segger_jlink.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Reported in https://forums.gentoo.org/viewtopic-t-781442-start-0.html Bus 002 Device 002: ID 1366:0101 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 8 idVendor 0x1366 idProduct 0x0101 bcdDevice 0.01 iManufacturer 1 SEGGER iProduct 2 J-Link iSerial 3 123456 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 32 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0xc0 Self Powered MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Status: 0x0001 Self Powered ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/jlink/1366_0101_segger_jlink_plus_10_1.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Standalone adapter, original Segger, HW version 10.1 Bus 001 Device 005: ID 1366:0101 SEGGER J-Link PLUS Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x1366 SEGGER idProduct 0x0101 J-Link PLUS bcdDevice 1.00 iManufacturer 1 SEGGER iProduct 2 J-Link iSerial 3 123456 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0020 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 4 Configuration bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 5 BULK interface Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 1 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/kitprog/04b4_f139_cypress_kitprog.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Reported in http://false.ekta.is/tag/unboxing/ Bus 003 Device 011: ID 04b4:f139 Cypress Semiconductor Corp. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 ? bDeviceProtocol 1 Interface Association bMaxPacketSize0 8 idVendor 0x04b4 Cypress Semiconductor Corp. idProduct 0xf139 bcdDevice 2.0b iManufacturer 1 Cypress Semiconductor iProduct 2 Cypress KitProg iSerial 128 1C210338012E4400 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 130 bNumInterfaces 4 bConfigurationValue 1 iConfiguration 2 Cypress KitProg bmAttributes 0x80 (Bus Powered) MaxPower 400mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 No Subclass bInterfaceProtocol 0 None iInterface 3 KitBridge HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.11 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 43 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 5 KitProg Programmer Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 2 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 0 bFunctionProtocol 0 iFunction 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 0 None iInterface 4 KitProg USBUART CDC Header: bcdCDC 1.10 CDC ACM: bmCapabilities 0x02 line coding and serial state CDC Union: bMasterInterface 2 bSlaveInterface 1 CDC Call Management: bmCapabilities 0x00 bDataInterface 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0008 1x 8 bytes bInterval 2 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 Unused bInterfaceProtocol 0 iInterface 4 KitProg USBUART Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x86 EP 6 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x07 EP 7 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/nulink/0416_511d_nuvoton_nulink.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Board: nuvoTon NuMaker-PFM-M2351 # Adapter: ICE V3.0 Bus 001 Device 013: ID 0416:511d Winbond Electronics Corp. Nuvoton Nu-Link1 ICE/VCOM Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x0416 Winbond Electronics Corp. idProduct 0x511d Nuvoton Nu-Link1 ICE/VCOM bcdDevice 1.00 iManufacturer 1 Nuvoton iProduct 2 Nu-Link iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x006b bNumInterfaces 3 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.10 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 28 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 1 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 2 Nu-Link Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 0 CDC Header: bcdCDC 1.10 CDC Call Management: bmCapabilities 0x00 bDataInterface 1 CDC ACM: bmCapabilities 0x00 CDC Union: bMasterInterface 1 bSlaveInterface 2 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0008 1x 8 bytes bInterval 255 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/nulink/0416_5200_nuvoton_nulink.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Board: nuvoTon NuMaker-M483KG V1.1 # Adapter: Nu-Link2-Me V1.0 Bus 001 Device 014: ID 0416:5200 Winbond Electronics Corp. Nuvoton Nu-Link2-ME ICE/MSC/VCOM Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x0416 Winbond Electronics Corp. idProduct 0x5200 Nuvoton Nu-Link2-ME ICE/MSC/VCOM bcdDevice 0.00 iManufacturer 1 Nuvoton iProduct 2 Nu-Link2 Bulk iSerial 6 13010000AAAAAAAAAAAAAAAAAAAAAAAA bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0099 bNumInterfaces 5 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 1 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 3 Nu-Link2 VCOM CDC Header: bcdCDC 1.10 CDC Call Management: bmCapabilities 0x00 bDataInterface 1 CDC ACM: bmCapabilities 0x00 CDC Union: bMasterInterface 1 bSlaveInterface 2 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0100 1x 256 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0100 1x 256 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 4 Nu-Link2 HID HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.10 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 35 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x86 EP 6 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 4 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x07 EP 7 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 4 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 4 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 8 Mass Storage bInterfaceSubClass 6 SCSI bInterfaceProtocol 80 Bulk-Only iInterface 5 Nu-Link2 MSC Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x88 EP 8 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x09 EP 9 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/readme.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later This folder contains a collection of dumps of USB descriptors, obtained through Linux lsusb command, of several USB adapters supported by OpenOCD. This collection should help maintaining adapter drivers even if the developer doesn't have access to all the devices supported by the driver. To add a new file, run: ./doc/usb_adapters/dump.sh ${vid} ${pid} \ > doc/usb_adapters/${driver}/${vid}_${pid}_${short_description}.txt eventually edit the file to add some extra comment, then submit the file to OpenOCD gerrit, as explained in HACKING. The dumps are organized in subfolders corresponding to OpenOCD drivers: - cmsis_dap; - esp_usb_jtag; - ft232r; - ftdi; - icdi; - jlink; - kitprog; - nulink; - stlink; - xds110. The script above assumes the user has granted access permissions to the USB device file in /dev/bus/usb/<n>/<m> This is usually the case when the device is listed in contrib/60-openocd.rules and this udev rules file is properly installed in the host machine. If the user has no proper access permissions, the script has to be run as root or through 'sudo'. Old versions of 'lsusb -v' dump cryptic errors like: can't get device qualifier: Resource temporarily unavailable can't get debug descriptor: Resource temporarily unavailable when some optional descriptor is not present. This is fixed in usbutils v014. If you get such messages simply ignore them. They are printed on stderr, so will not be included in the generated file as the redirection '>' does only redirects stdout. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/stlink/0483_3744_stlinkv1.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Standalone adapter Bus 001 Device 009: ID 0483:3744 STMicroelectronics ST-LINK/V1 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0483 STMicroelectronics idProduct 0x3744 ST-LINK/V1 bcdDevice 1.00 iManufacturer 1 STMicroelectronics iProduct 2 STM32 STLink iSerial 3 0000001 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0020 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 8 Mass Storage bInterfaceSubClass 6 SCSI bInterfaceProtocol 80 Bulk-Only iInterface 4 ST Link Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/stlink/0483_3748_stlinkv2.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # ST-Link/V2 standalone or ST-Link/V2 in firmware update mode Bus 001 Device 006: ID 0483:3748 STMicroelectronics ST-LINK/V2 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0483 STMicroelectronics idProduct 0x3748 ST-LINK/V2 bcdDevice 1.00 iManufacturer 1 STMicroelectronics iProduct 2 STM32 STLink iSerial 3 0668FF323637414257071827 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0027 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 4 ST Link Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/stlink/0483_374b_stlinkv2.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Board: ST Nucleo F411 Bus 001 Device 007: ID 0483:374b STMicroelectronics ST-LINK/V2.1 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x0483 STMicroelectronics idProduct 0x374b ST-LINK/V2.1 bcdDevice 1.00 iManufacturer 1 STMicroelectronics iProduct 2 STM32 STLink iSerial 3 066EFF373535503457062922 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0080 bNumInterfaces 4 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 4 ST-Link Debug Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0020 1x 32 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 8 Mass Storage bInterfaceSubClass 6 SCSI bInterfaceProtocol 80 Bulk-Only iInterface 5 ST-Link mass storage Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x03 EP 3 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 2 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 6 ST-Link VCP Ctrl Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 6 ST-Link VCP Ctrl CDC Header: bcdCDC 1.10 CDC Call Management: bmCapabilities 0x00 bDataInterface 3 CDC ACM: bmCapabilities 0x06 sends break line coding and serial state CDC Union: bMasterInterface 2 bSlaveInterface 3 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0002 1x 2 bytes bInterval 255 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 7 ST-Link VCP Data Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x05 EP 5 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0008 1x 8 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0010 1x 16 bytes bInterval 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/stlink/0483_374d_stlinkv3.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # ST-Link/V3 in firmware update mode Bus 001 Device 009: ID 0483:374d STMicroelectronics STLINK-V3 Loader Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0483 STMicroelectronics idProduct 0x374d STLINK-V3 Loader bcdDevice 2.00 iManufacturer 1 STMicroelectronics iProduct 2 STM32 ST-LINK/V3 iSerial 3 003500463137510239383538 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0020 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 4 DFU Config bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 5 ST-LINK/V3 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0001 Self Powered ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/stlink/0483_374e_stlinkv3.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Board: ST Nucleo-H745AI-Q Bus 001 Device 008: ID 0483:374e STMicroelectronics STLINK-V3 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x0483 STMicroelectronics idProduct 0x374e STLINK-V3 bcdDevice 1.00 iManufacturer 1 STMicroelectronics iProduct 2 STLINK-V3 iSerial 3 005100313137511039383538 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0080 bNumInterfaces 4 bConfigurationValue 1 iConfiguration 4 Default Config bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 5 ST-Link Debug Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 8 Mass Storage bInterfaceSubClass 6 SCSI bInterfaceProtocol 80 Bulk-Only iInterface 6 ST-Link mass storage Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x03 EP 3 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 2 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 7 ST-Link VCP Ctrl Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 7 ST-Link VCP Ctrl CDC Header: bcdCDC 1.10 CDC Call Management: bmCapabilities 0x00 bDataInterface 3 CDC ACM: bmCapabilities 0x06 sends break line coding and serial state CDC Union: bMasterInterface 2 bSlaveInterface 3 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x000a 1x 10 bytes bInterval 16 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 8 ST-Link VCP Data Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x05 EP 5 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/stlink/0483_374f_stlinkv3.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Standalone adapter Bus 001 Device 008: ID 0483:374f STMicroelectronics STLINK-V3 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x0483 STMicroelectronics idProduct 0x374f STLINK-V3 bcdDevice 1.00 iManufacturer 1 STMicroelectronics iProduct 2 STLINK-V3 iSerial 3 003500463137510239383538 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0097 bNumInterfaces 5 bConfigurationValue 1 iConfiguration 4 Default Config bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 5 ST-Link Debug Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 8 Mass Storage bInterfaceSubClass 6 SCSI bInterfaceProtocol 80 Bulk-Only iInterface 6 ST-Link mass storage Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x03 EP 3 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 2 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 7 ST-Link VCP Ctrl Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 7 ST-Link VCP Ctrl CDC Header: bcdCDC 1.10 CDC Call Management: bmCapabilities 0x00 bDataInterface 3 CDC ACM: bmCapabilities 0x06 sends break line coding and serial state CDC Union: bMasterInterface 2 bSlaveInterface 3 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x000a 1x 10 bytes bInterval 16 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 8 ST-Link VCP Data Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x05 EP 5 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 4 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 9 ST-Link Bridge Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x86 EP 6 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x06 EP 6 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/stlink/0483_3752_stlinkv2.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Board: ST STM32MP157f-DK2 Bus 001 Device 005: ID 0483:3752 STMicroelectronics ST-LINK/V2.1 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x0483 STMicroelectronics idProduct 0x3752 ST-LINK/V2.1 bcdDevice 1.00 iManufacturer 1 STMicroelectronics iProduct 2 STM32 STLink iSerial 3 0668FF323637414257071827 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0069 bNumInterfaces 3 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 300mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 4 ST-Link Debug Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0020 1x 32 bytes bInterval 0 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 1 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 6 ST-Link VCP Ctrl Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 6 ST-Link VCP Ctrl CDC Header: bcdCDC 1.10 CDC Call Management: bmCapabilities 0x00 bDataInterface 2 CDC ACM: bmCapabilities 0x06 sends break line coding and serial state CDC Union: bMasterInterface 1 bSlaveInterface 2 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0008 1x 8 bytes bInterval 16 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 7 ST-Link VCP Data Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x05 EP 5 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/stlink/0483_3753_stlinkv3.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Board STM32MP135F-DK Bus 001 Device 011: ID 0483:3753 STMicroelectronics STLINK-V3 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x0483 STMicroelectronics idProduct 0x3753 STLINK-V3 bcdDevice 1.00 iManufacturer 1 STMicroelectronics iProduct 2 STLINK-V3 iSerial 3 001000294741500120383733 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x00c2 bNumInterfaces 6 bConfigurationValue 1 iConfiguration 4 Default Config bmAttributes 0x80 (Bus Powered) MaxPower 300mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 5 ST-Link Debug Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 1 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 7 ST-Link VCP Ctrl Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 7 ST-Link VCP Ctrl CDC Header: bcdCDC 1.10 CDC Call Management: bmCapabilities 0x00 bDataInterface 2 CDC ACM: bmCapabilities 0x06 sends break line coding and serial state CDC Union: bMasterInterface 1 bSlaveInterface 2 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x000a 1x 10 bytes bInterval 16 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 8 ST-Link VCP Data Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x05 EP 5 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 9 ST-Link Bridge Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x86 EP 6 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x06 EP 6 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 4 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 10 ST-Link VCP2 Ctrl Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 4 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 10 ST-Link VCP2 Ctrl CDC Header: bcdCDC 1.10 CDC Call Management: bmCapabilities 0x00 bDataInterface 5 CDC ACM: bmCapabilities 0x06 sends break line coding and serial state CDC Union: bMasterInterface 4 bSlaveInterface 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x000a 1x 10 bytes bInterval 16 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 5 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 11 ST-Link VCP2 Data Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x07 EP 7 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x87 EP 7 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/stlink/0483_3755_stlinkv3pwr.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # STLINK-V3PWR standalone in firmware update mode Bus 003 Device 054: ID 0483:3755 STMicroelectronics USB2.0 Hub Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0483 STMicroelectronics idProduct 0x3755 bcdDevice 1.00 iManufacturer 1 STMicroelectronics iProduct 2 STLINK-V3PWR iSerial 3 123456780000 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0020 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 4 DFU Config bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 5 ST-Link Usbloader Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/stlink/0483_3757_stlinkv3pwr.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # STLINK-V3PWR standalone Bus 003 Device 053: ID 0483:3757 STMicroelectronics USB2.0 Hub Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x0483 STMicroelectronics idProduct 0x3757 bcdDevice 1.00 iManufacturer 1 STMicroelectronics iProduct 2 STLINK-V3PWR iSerial 3 123456780000 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x00c2 bNumInterfaces 6 bConfigurationValue 1 iConfiguration 4 Default Config bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 5 ST-Link Debug Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 1 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 6 ST-Link VCP Ctrl Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 6 ST-Link VCP Ctrl CDC Header: bcdCDC 1.10 CDC Call Management: bmCapabilities 0x00 bDataInterface 2 CDC ACM: bmCapabilities 0x06 sends break line coding and serial state CDC Union: bMasterInterface 1 bSlaveInterface 2 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x000a 1x 10 bytes bInterval 16 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 7 ST-Link VCP Data Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x05 EP 5 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 8 ST-Link Bridge Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x86 EP 6 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x06 EP 6 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 4 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 9 ST-Link VCP-PWR Ctrl Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 4 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 9 ST-Link VCP-PWR Ctrl CDC Header: bcdCDC 1.10 CDC Call Management: bmCapabilities 0x00 bDataInterface 5 CDC ACM: bmCapabilities 0x06 sends break line coding and serial state CDC Union: bMasterInterface 4 bSlaveInterface 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x87 EP 7 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x000a 1x 10 bytes bInterval 16 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 5 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 10 ST-Link VCP-PWR Data Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x03 EP 3 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/doc/usb_adapters/xds110/0451_0451_ti_xds110.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later # Board: TI CC2650 LaunchPad Bus 001 Device 005: ID 0451:bef3 Texas Instruments, Inc. CC1352R1 Launchpad Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x0451 Texas Instruments, Inc. idProduct 0xbef3 CC1352R1 Launchpad bcdDevice 1.00 iManufacturer 1 Texas Instruments iProduct 2 XDS110 (03.00.00.13) Embed with CMSIS-DAP iSerial 3 L1002566 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x00db bNumInterfaces 7 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 0 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 0 CDC Header: bcdCDC 1.10 CDC ACM: bmCapabilities 0x06 sends break line coding and serial state CDC Union: bMasterInterface 0 bSlaveInterface 1 CDC Call Management: bmCapabilities 0x01 call management bDataInterface 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0010 1x 16 bytes bInterval 1 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 3 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 2 Abstract (modem) bFunctionProtocol 1 AT-commands (v.25ter) iFunction 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 0 CDC Header: bcdCDC 1.10 CDC ACM: bmCapabilities 0x06 sends break line coding and serial state CDC Union: bMasterInterface 3 bSlaveInterface 4 CDC Call Management: bmCapabilities 0x01 call management bDataInterface 4 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0010 1x 16 bytes bInterval 1 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 4 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x03 EP 3 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 5 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 6 XDS110 CMSIS-DAP HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.11 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 24 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x86 EP 6 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 6 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x05 EP 5 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x87 EP 7 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Status: 0x0000 (Bus Powered) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/guess-rev.sh ================================================ #!/bin/sh # # This scripts adds local version information from the version # control systems git, mercurial (hg) and subversion (svn). # # Copied from Linux 2.6.32 scripts/setlocalversion and modified # slightly to work better for OpenOCD. # usage() { echo "Usage: $0 [srctree]" >&2 exit 1 } cd "${1:-.}" || usage # Check for git and a git repo. if head=`git rev-parse --verify --short HEAD 2>/dev/null`; then # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore it, # because this version is defined in the top level Makefile. if [ -z "`git describe --exact-match 2>/dev/null`" ]; then # If we are past a tagged commit (like "v2.6.30-rc5-302-g72357d5"), # we pretty print it. if atag="`git describe 2>/dev/null`"; then echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}' # If we don't have a tag at all we print -g{commitish}. else printf '%s%s' -g $head fi fi # Is this git on svn? if git config --get svn-remote.svn.url >/dev/null; then printf -- '-svn%s' "`git svn find-rev $head`" fi # Update index only on r/w media [ -w . ] && git update-index --refresh --unmerged > /dev/null # Check for uncommitted changes if git diff-index --name-only HEAD | grep -v "^scripts/package" \ | read dummy; then printf '%s' -dirty fi # All done with git exit fi # Check for mercurial and a mercurial repo. if hgid=`hg id 2>/dev/null`; then tag=`printf '%s' "$hgid" | cut -d' ' -f2` # Do we have an untagged version? if [ -z "$tag" -o "$tag" = tip ]; then id=`printf '%s' "$hgid" | sed 's/[+ ].*//'` printf '%s%s' -hg "$id" fi # Are there uncommitted changes? # These are represented by + after the changeset id. case "$hgid" in *+|*+\ *) printf '%s' -dirty ;; esac # All done with mercurial exit fi # Check for svn and a svn repo. if rev=`svn info 2>/dev/null | grep '^Last Changed Rev'`; then rev=`echo $rev | awk '{print $NF}'` printf -- '-svn%s' "$rev" # All done with svn exit fi # There's no recognized repository; we must be a snapshot. printf -- '-snapshot' ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libopenocd.la bin_PROGRAMS += %D%/openocd %C%_openocd_SOURCES = \ %D%/main.c %C%_libopenocd_la_SOURCES = \ %D%/hello.c %D%/hello.h \ %D%/openocd.c %D%/openocd.h %C%_openocd_LDADD = %D%/libopenocd.la %C%_openocd_LDADD += $(MINGWLDADD) if INTERNAL_JIMTCL %C%_openocd_LDADD += $(top_builddir)/jimtcl/libjim.a else %C%_openocd_LDADD += -ljim endif %C%_libopenocd_la_CPPFLAGS = # banner output includes RELSTR appended to $VERSION from the configure script # guess-rev.sh returns either a repository version ID or "-snapshot" if RELEASE %C%_libopenocd_la_CPPFLAGS += -DRELSTR=\"\" %C%_libopenocd_la_CPPFLAGS += -DGITVERSION=\"\" else %C%_libopenocd_la_CPPFLAGS += -DRELSTR=\"`$(top_srcdir)/guess-rev.sh $(top_srcdir)`\" %C%_libopenocd_la_CPPFLAGS += -DGITVERSION=\"`cd $(top_srcdir) && git describe`\" %C%_libopenocd_la_CPPFLAGS += -DPKGBLDDATE=\"`date +%F-%R`\" endif # add default CPPFLAGS %C%_libopenocd_la_CPPFLAGS += $(AM_CPPFLAGS) $(CPPFLAGS) # the library search path. %C%_libopenocd_la_LDFLAGS = $(all_libraries) if IS_MINGW MINGWLDADD = -lws2_32 else MINGWLDADD = endif %C%_libopenocd_la_LIBADD = \ %D%/xsvf/libxsvf.la \ %D%/svf/libsvf.la \ %D%/pld/libpld.la \ %D%/jtag/libjtag.la \ %D%/transport/libtransport.la \ %D%/flash/libflash.la \ %D%/target/libtarget.la \ %D%/server/libserver.la \ %D%/rtos/librtos.la \ %D%/helper/libhelper.la \ %D%/rtt/librtt.la BIN2C = $(srcdir)/%D%/helper/bin2char.sh STARTUP_TCL_SRCS = EXTRA_DIST += $(STARTUP_TCL_SRCS) BUILT_SOURCES += %D%/startup_tcl.inc # Convert .tcl to c-array %D%/startup_tcl.inc: $(STARTUP_TCL_SRCS) mkdir -p %D% cat $^ | $(BIN2C) > $@ || { rm -f $@; false; } # add generated files to make clean list CLEANFILES += %D%/startup_tcl.inc # we do not want generated file in the dist #dist-hook: # rm -f $(distdir)/%D%/startup_tcl.inc include %D%/helper/Makefile.am include %D%/jtag/Makefile.am include %D%/transport/Makefile.am include %D%/xsvf/Makefile.am include %D%/svf/Makefile.am include %D%/target/Makefile.am include %D%/rtos/Makefile.am include %D%/server/Makefile.am include %D%/flash/Makefile.am include %D%/pld/Makefile.am include %D%/rtt/Makefile.am ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libflash.la %C%_libflash_la_SOURCES = \ %D%/common.c %D%/common.h %C%_libflash_la_LIBADD = \ %D%/nor/libocdflashnor.la \ %D%/nand/libocdflashnand.la STARTUP_TCL_SRCS += %D%/startup.tcl include %D%/nor/Makefile.am include %D%/nand/Makefile.am ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/common.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "common.h" #include <helper/log.h> unsigned get_flash_name_index(const char *name) { const char *name_index = strrchr(name, '.'); if (!name_index) return 0; if (name_index[1] < '0' || name_index[1] > '9') return ~0U; unsigned requested; int retval = parse_uint(name_index + 1, &requested); /* detect parsing error by forcing past end of bank list */ return (retval == ERROR_OK) ? requested : ~0U; } bool flash_driver_name_matches(const char *name, const char *expected) { unsigned blen = strlen(name); /* only match up to the length of the driver name... */ if (strncmp(name, expected, blen) != 0) return false; /* ...then check that name terminates at this spot. */ return expected[blen] == '.' || expected[blen] == '\0'; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/common.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifndef OPENOCD_FLASH_COMMON_H #define OPENOCD_FLASH_COMMON_H #include <helper/log.h> #include <helper/replacements.h> /** * Parses the optional '.index' portion of a flash bank identifier. * @param name The desired driver name, passed by the user. * @returns The parsed index request, or 0 if not present. If the * name provides a suffix but it does not parse as an unsigned integer, * the routine returns ~0U. This will prevent further matching. */ unsigned get_flash_name_index(const char *name); /** * Attempt to match the @c expected name with the @c name of a driver. * @param name The name of the driver (from the bank's device structure). * @param expected The expected driver name, passed by the user. */ bool flash_driver_name_matches(const char *name, const char *expected); #define ERROR_FLASH_BANK_INVALID (-900) #define ERROR_FLASH_SECTOR_INVALID (-901) #define ERROR_FLASH_OPERATION_FAILED (-902) #define ERROR_FLASH_DST_OUT_OF_BANK (-903) #define ERROR_FLASH_DST_BREAKS_ALIGNMENT (-904) #define ERROR_FLASH_BUSY (-905) #define ERROR_FLASH_SECTOR_NOT_ERASED (-906) #define ERROR_FLASH_BANK_NOT_PROBED (-907) #define ERROR_FLASH_OPER_UNSUPPORTED (-908) #define ERROR_FLASH_PROTECTED (-909) #endif /* OPENOCD_FLASH_COMMON_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libocdflashnand.la %C%_libocdflashnand_la_SOURCES = \ %D%/ecc.c \ %D%/ecc_kw.c \ %D%/core.c \ %D%/fileio.c \ %D%/tcl.c \ %D%/arm_io.c \ $(NAND_DRIVERS) \ %D%/driver.c \ $(NANDHEADERS) NAND_DRIVERS = \ %D%/nonce.c \ %D%/davinci.c \ %D%/lpc3180.c \ %D%/lpc32xx.c \ %D%/mxc.c \ %D%/mx3.c \ %D%/orion.c \ %D%/s3c24xx.c \ %D%/s3c2410.c \ %D%/s3c2412.c \ %D%/s3c2440.c \ %D%/s3c2443.c \ %D%/s3c6400.c \ %D%/at91sam9.c \ %D%/nuc910.c NANDHEADERS = \ %D%/arm_io.h \ %D%/core.h \ %D%/driver.h \ %D%/fileio.h \ %D%/imp.h \ %D%/lpc3180.h \ %D%/lpc32xx.h \ %D%/mxc.h \ %D%/mx3.h \ %D%/s3c24xx.h \ %D%/s3c24xx_regs.h \ %D%/nuc910.h ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/arm_io.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2009 by Marvell Semiconductors, Inc. * Written by Nicolas Pitre <nico at marvell.com> * * Copyright (C) 2009 by David Brownell */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "core.h" #include "arm_io.h" #include <helper/binarybuffer.h> #include <target/arm.h> #include <target/armv7m.h> #include <target/algorithm.h> /** * Copies code to a working area. This will allocate room for the code plus the * additional amount requested if the working area pointer is null. * * @param target Pointer to the target to copy code to * @param code Pointer to the code area to be copied * @param code_size Size of the code being copied * @param additional Size of the additional area to be allocated in addition to * code * @param area Pointer to a pointer to a working area to copy code to * @return Success or failure of the operation */ static int arm_code_to_working_area(struct target *target, const uint32_t *code, unsigned code_size, unsigned additional, struct working_area **area) { uint8_t code_buf[code_size]; int retval; unsigned size = code_size + additional; /* REVISIT this assumes size doesn't ever change. * That's usually correct; but there are boards with * both large and small page chips, where it won't be... */ /* make sure we have a working area */ if (!*area) { retval = target_alloc_working_area(target, size, area); if (retval != ERROR_OK) { LOG_DEBUG("%s: no %d byte buffer", __func__, (int) size); return ERROR_NAND_NO_BUFFER; } } /* buffer code in target endianness */ target_buffer_set_u32_array(target, code_buf, code_size / 4, code); /* copy code to work area */ retval = target_write_memory(target, (*area)->address, 4, code_size / 4, code_buf); return retval; } /** * ARM-specific bulk write from buffer to address of 8-bit wide NAND. * For now this supports ARMv4,ARMv5 and ARMv7-M cores. * * Enhancements to target_run_algorithm() could enable: * - ARMv6 and ARMv7 cores in ARM mode * * Different code fragments could handle: * - 16-bit wide data (needs different setup) * * @param nand Pointer to the arm_nand_data struct that defines the I/O * @param data Pointer to the data to be copied to flash * @param size Size of the data being copied * @return Success or failure of the operation */ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size) { struct target *target = nand->target; struct arm_algorithm armv4_5_algo; struct armv7m_algorithm armv7m_algo; void *arm_algo; struct arm *arm = target->arch_info; struct reg_param reg_params[3]; uint32_t target_buf; uint32_t exit_var = 0; int retval; /* Inputs: * r0 NAND data address (byte wide) * r1 buffer address * r2 buffer length */ static const uint32_t code_armv4_5[] = { 0xe4d13001, /* s: ldrb r3, [r1], #1 */ 0xe5c03000, /* strb r3, [r0] */ 0xe2522001, /* subs r2, r2, #1 */ 0x1afffffb, /* bne s */ /* exit: ARMv4 needs hardware breakpoint */ 0xe1200070, /* e: bkpt #0 */ }; /* Inputs: * r0 NAND data address (byte wide) * r1 buffer address * r2 buffer length * * see contrib/loaders/flash/armv7m_io.s for src */ static const uint32_t code_armv7m[] = { 0x3b01f811, 0x3a017003, 0xaffaf47f, 0xbf00be00, }; int target_code_size = 0; const uint32_t *target_code_src = NULL; /* set up algorithm */ if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */ armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC; armv7m_algo.core_mode = ARM_MODE_THREAD; arm_algo = &armv7m_algo; target_code_size = sizeof(code_armv7m); target_code_src = code_armv7m; } else { armv4_5_algo.common_magic = ARM_COMMON_MAGIC; armv4_5_algo.core_mode = ARM_MODE_SVC; armv4_5_algo.core_state = ARM_STATE_ARM; arm_algo = &armv4_5_algo; target_code_size = sizeof(code_armv4_5); target_code_src = code_armv4_5; } if (nand->op != ARM_NAND_WRITE || !nand->copy_area) { retval = arm_code_to_working_area(target, target_code_src, target_code_size, nand->chunk_size, &nand->copy_area); if (retval != ERROR_OK) return retval; } nand->op = ARM_NAND_WRITE; /* copy data to work area */ target_buf = nand->copy_area->address + target_code_size; retval = target_write_buffer(target, target_buf, size, data); if (retval != ERROR_OK) return retval; /* set up parameters */ init_reg_param(®_params[0], "r0", 32, PARAM_IN); init_reg_param(®_params[1], "r1", 32, PARAM_IN); init_reg_param(®_params[2], "r2", 32, PARAM_IN); buf_set_u32(reg_params[0].value, 0, 32, nand->data); buf_set_u32(reg_params[1].value, 0, 32, target_buf); buf_set_u32(reg_params[2].value, 0, 32, size); /* armv4 must exit using a hardware breakpoint */ if (arm->arch == ARM_ARCH_V4) exit_var = nand->copy_area->address + target_code_size - 4; /* use alg to write data from work area to NAND chip */ retval = target_run_algorithm(target, 0, NULL, 3, reg_params, nand->copy_area->address, exit_var, 1000, arm_algo); if (retval != ERROR_OK) LOG_ERROR("error executing hosted NAND write"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); return retval; } /** * Uses an on-chip algorithm for an ARM device to read from a NAND device and * store the data into the host machine's memory. * * @param nand Pointer to the arm_nand_data struct that defines the I/O * @param data Pointer to the data buffer to store the read data * @param size Amount of data to be stored to the buffer. * @return Success or failure of the operation */ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size) { struct target *target = nand->target; struct arm_algorithm armv4_5_algo; struct armv7m_algorithm armv7m_algo; void *arm_algo; struct arm *arm = target->arch_info; struct reg_param reg_params[3]; uint32_t target_buf; uint32_t exit_var = 0; int retval; /* Inputs: * r0 buffer address * r1 NAND data address (byte wide) * r2 buffer length */ static const uint32_t code_armv4_5[] = { 0xe5d13000, /* s: ldrb r3, [r1] */ 0xe4c03001, /* strb r3, [r0], #1 */ 0xe2522001, /* subs r2, r2, #1 */ 0x1afffffb, /* bne s */ /* exit: ARMv4 needs hardware breakpoint */ 0xe1200070, /* e: bkpt #0 */ }; /* Inputs: * r0 buffer address * r1 NAND data address (byte wide) * r2 buffer length * * see contrib/loaders/flash/armv7m_io.s for src */ static const uint32_t code_armv7m[] = { 0xf800780b, 0x3a013b01, 0xaffaf47f, 0xbf00be00, }; int target_code_size = 0; const uint32_t *target_code_src = NULL; /* set up algorithm */ if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */ armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC; armv7m_algo.core_mode = ARM_MODE_THREAD; arm_algo = &armv7m_algo; target_code_size = sizeof(code_armv7m); target_code_src = code_armv7m; } else { armv4_5_algo.common_magic = ARM_COMMON_MAGIC; armv4_5_algo.core_mode = ARM_MODE_SVC; armv4_5_algo.core_state = ARM_STATE_ARM; arm_algo = &armv4_5_algo; target_code_size = sizeof(code_armv4_5); target_code_src = code_armv4_5; } /* create the copy area if not yet available */ if (nand->op != ARM_NAND_READ || !nand->copy_area) { retval = arm_code_to_working_area(target, target_code_src, target_code_size, nand->chunk_size, &nand->copy_area); if (retval != ERROR_OK) return retval; } nand->op = ARM_NAND_READ; target_buf = nand->copy_area->address + target_code_size; /* set up parameters */ init_reg_param(®_params[0], "r0", 32, PARAM_IN); init_reg_param(®_params[1], "r1", 32, PARAM_IN); init_reg_param(®_params[2], "r2", 32, PARAM_IN); buf_set_u32(reg_params[0].value, 0, 32, target_buf); buf_set_u32(reg_params[1].value, 0, 32, nand->data); buf_set_u32(reg_params[2].value, 0, 32, size); /* armv4 must exit using a hardware breakpoint */ if (arm->arch == ARM_ARCH_V4) exit_var = nand->copy_area->address + target_code_size - 4; /* use alg to write data from NAND chip to work area */ retval = target_run_algorithm(target, 0, NULL, 3, reg_params, nand->copy_area->address, exit_var, 1000, arm_algo); if (retval != ERROR_OK) LOG_ERROR("error executing hosted NAND read"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); /* read from work area to the host's memory */ retval = target_read_buffer(target, target_buf, size, data); return retval; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/arm_io.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2009 by David Brownell */ #ifndef OPENOCD_FLASH_NAND_ARM_IO_H #define OPENOCD_FLASH_NAND_ARM_IO_H /** * Available operational states the arm_nand_data struct can be in. */ enum arm_nand_op { ARM_NAND_NONE, /**< No operation performed. */ ARM_NAND_READ, /**< Read operation performed. */ ARM_NAND_WRITE, /**< Write operation performed. */ }; /** * The arm_nand_data struct is used for defining NAND I/O operations on an ARM * core. */ struct arm_nand_data { /** Target is proxy for some ARM core. */ struct target *target; /** The copy area holds code loop and data for I/O operations. */ struct working_area *copy_area; /** The chunk size is the page size or ECC chunk. */ unsigned chunk_size; /** Where data is read from or written to. */ uint32_t data; /** Last operation executed using this struct. */ enum arm_nand_op op; /* currently implicit: data width == 8 bits (not 16) */ }; int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size); int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size); #endif /* OPENOCD_FLASH_NAND_ARM_IO_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/at91sam9.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2009 by Dean Glazeski * dnglaze@gmail.com */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <target/arm.h> #include <helper/log.h> #include "imp.h" #include "arm_io.h" #define AT91C_PIOX_SODR (0x30) /**< Offset to PIO SODR. */ #define AT91C_PIOX_CODR (0x34) /**< Offset to PIO CODR. */ #define AT91C_PIOX_PDSR (0x3C) /**< Offset to PIO PDSR. */ #define AT91C_ECCX_CR (0x00) /**< Offset to ECC CR. */ #define AT91C_ECCX_SR (0x08) /**< Offset to ECC SR. */ #define AT91C_ECCX_PR (0x0C) /**< Offset to ECC PR. */ #define AT91C_ECCX_NPR (0x10) /**< Offset to ECC NPR. */ /** * Representation of a pin on an AT91SAM9 chip. */ struct at91sam9_pin { /** Address of the PIO controller. */ uint32_t pioc; /** Pin number. */ uint32_t num; }; /** * Private data for the controller that is stored in the NAND device structure. */ struct at91sam9_nand { /** Address of the ECC controller for NAND. */ uint32_t ecc; /** Address data is written to. */ uint32_t data; /** Address commands are written to. */ uint32_t cmd; /** Address addresses are written to. */ uint32_t addr; /** I/O structure for hosted reads/writes. */ struct arm_nand_data io; /** Pin representing the ready/~busy line. */ struct at91sam9_pin busy; /** Pin representing the chip enable. */ struct at91sam9_pin ce; }; /** * Checks if the target is halted and prints an error message if it isn't. * * @param target Target to be checked. * @param label String label for where function is called from. * @return True if the target is halted. */ static int at91sam9_halted(struct target *target, const char *label) { if (target->state == TARGET_HALTED) return true; LOG_ERROR("Target must be halted to use NAND controller (%s)", label); return false; } /** * Initialize the AT91SAM9 NAND controller. * * @param nand NAND device the controller is attached to. * @return Success or failure of initialization. */ static int at91sam9_init(struct nand_device *nand) { struct target *target = nand->target; if (!at91sam9_halted(target, "init")) return ERROR_NAND_OPERATION_FAILED; return ERROR_OK; } /** * Enable NAND device attached to a controller. * * @param nand NAND controller information for controlling NAND device. * @return Success or failure of the enabling. */ static int at91sam9_enable(struct nand_device *nand) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; return target_write_u32(target, info->ce.pioc + AT91C_PIOX_CODR, 1 << info->ce.num); } /** * Disable NAND device attached to a controller. * * @param nand NAND controller information for controlling NAND device. * @return Success or failure of the disabling. */ static int at91sam9_disable(struct nand_device *nand) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; return target_write_u32(target, info->ce.pioc + AT91C_PIOX_SODR, 1 << info->ce.num); } /** * Send a command to the NAND device. * * @param nand NAND device to write the command to. * @param command Command to be written. * @return Success or failure of writing the command. */ static int at91sam9_command(struct nand_device *nand, uint8_t command) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; if (!at91sam9_halted(target, "command")) return ERROR_NAND_OPERATION_FAILED; at91sam9_enable(nand); return target_write_u8(target, info->cmd, command); } /** * Reset the AT91SAM9 NAND controller. * * @param nand NAND device to be reset. * @return Success or failure of reset. */ static int at91sam9_reset(struct nand_device *nand) { if (!at91sam9_halted(nand->target, "reset")) return ERROR_NAND_OPERATION_FAILED; return at91sam9_disable(nand); } /** * Send an address to the NAND device attached to an AT91SAM9 NAND controller. * * @param nand NAND device to send the address to. * @param address Address to be sent. * @return Success or failure of sending the address. */ static int at91sam9_address(struct nand_device *nand, uint8_t address) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; if (!at91sam9_halted(nand->target, "address")) return ERROR_NAND_OPERATION_FAILED; return target_write_u8(target, info->addr, address); } /** * Read data directly from the NAND device attached to an AT91SAM9 NAND * controller. * * @param nand NAND device to read from. * @param data Pointer to where the data should be put. * @return Success or failure of reading the data. */ static int at91sam9_read_data(struct nand_device *nand, void *data) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; if (!at91sam9_halted(nand->target, "read data")) return ERROR_NAND_OPERATION_FAILED; return target_read_u8(target, info->data, data); } /** * Write data directly to the NAND device attached to an AT91SAM9 NAND * controller. * * @param nand NAND device to be written to. * @param data Data to be written. * @return Success or failure of the data write. */ static int at91sam9_write_data(struct nand_device *nand, uint16_t data) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; if (!at91sam9_halted(target, "write data")) return ERROR_NAND_OPERATION_FAILED; return target_write_u8(target, info->data, data); } /** * Determine if the NAND device is ready by looking at the ready/~busy pin. * * @param nand NAND device to check. * @param timeout Time in milliseconds to wait for NAND to be ready. * @return True if the NAND is ready in the timeout period. */ static int at91sam9_nand_ready(struct nand_device *nand, int timeout) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; uint32_t status; if (!at91sam9_halted(target, "nand ready")) return 0; do { target_read_u32(target, info->busy.pioc + AT91C_PIOX_PDSR, &status); if (status & (1 << info->busy.num)) return 1; alive_sleep(1); } while (timeout-- > 0); return 0; } /** * Read a block of data from the NAND device attached to an AT91SAM9. This * utilizes the ARM hosted NAND read function. * * @param nand NAND device to read from. * @param data Pointer to where the read data should be placed. * @param size Size of the data being read. * @return Success or failure of the hosted read. */ static int at91sam9_read_block_data(struct nand_device *nand, uint8_t *data, int size) { struct at91sam9_nand *info = nand->controller_priv; struct arm_nand_data *io = &info->io; int status; if (!at91sam9_halted(nand->target, "read block")) return ERROR_NAND_OPERATION_FAILED; io->chunk_size = nand->page_size; status = arm_nandread(io, data, size); return status; } /** * Write a block of data to a NAND device attached to an AT91SAM9. This uses * the ARM hosted write function to write the data. * * @param nand NAND device to write to. * @param data Data to be written to device. * @param size Size of the data being written. * @return Success or failure of the hosted write. */ static int at91sam9_write_block_data(struct nand_device *nand, uint8_t *data, int size) { struct at91sam9_nand *info = nand->controller_priv; struct arm_nand_data *io = &info->io; int status; if (!at91sam9_halted(nand->target, "write block")) return ERROR_NAND_OPERATION_FAILED; io->chunk_size = nand->page_size; status = arm_nandwrite(io, data, size); return status; } /** * Initialize the ECC controller on the AT91SAM9. * * @param target Target to configure ECC on. * @param info NAND controller information for where the ECC is. * @return Success or failure of initialization. */ static int at91sam9_ecc_init(struct target *target, struct at91sam9_nand *info) { if (!info->ecc) { LOG_ERROR("ECC controller address must be set when not reading raw NAND data"); return ERROR_NAND_OPERATION_FAILED; } /* reset ECC parity registers */ return target_write_u32(target, info->ecc + AT91C_ECCX_CR, 1); } /** * Initialize an area for the OOB based on whether a user is requesting the OOB * data. This determines the size of the OOB and allocates the space in case * the user has not requested the OOB data. * * @param nand NAND device we are creating an OOB for. * @param oob Pointer to the user supplied OOB area. * @param size Size of the OOB. * @return Pointer to an area to store OOB data. */ static uint8_t *at91sam9_oob_init(struct nand_device *nand, uint8_t *oob, uint32_t *size) { if (!oob) { /* user doesn't want OOB, allocate it */ if (nand->page_size == 512) *size = 16; else if (nand->page_size == 2048) *size = 64; oob = malloc(*size); if (!oob) { LOG_ERROR("Unable to allocate space for OOB"); return NULL; } memset(oob, 0xFF, *size); } return oob; } /** * Reads a page from an AT91SAM9 NAND controller and verifies using 1-bit ECC * controller on chip. This makes an attempt to correct any errors that are * encountered while reading the page of data. * * @param nand NAND device to read from * @param page Page to be read. * @param data Pointer to where data should be read to. * @param data_size Size of the data to be read. * @param oob Pointer to where OOB data should be read to. * @param oob_size Size of the OOB data to be read. * @return Success or failure of reading the NAND page. */ static int at91sam9_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { int retval; struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; uint8_t *oob_data; uint32_t status; retval = at91sam9_ecc_init(target, info); if (retval != ERROR_OK) return retval; retval = nand_page_command(nand, page, NAND_CMD_READ0, !data); if (retval != ERROR_OK) return retval; if (data) { retval = nand_read_data_page(nand, data, data_size); if (retval != ERROR_OK) return retval; } oob_data = at91sam9_oob_init(nand, oob, &oob_size); retval = nand_read_data_page(nand, oob_data, oob_size); if (retval == ERROR_OK && data) { target_read_u32(target, info->ecc + AT91C_ECCX_SR, &status); if (status & 1) { LOG_ERROR("Error detected!"); if (status & 4) LOG_ERROR("Multiple errors encountered; unrecoverable!"); else { /* attempt recovery */ uint32_t parity; target_read_u32(target, info->ecc + AT91C_ECCX_PR, &parity); uint32_t word = (parity & 0x0000FFF0) >> 4; uint32_t bit = parity & 0x0F; data[word] ^= (0x1) << bit; LOG_INFO("Data word %d, bit %d corrected.", (unsigned) word, (unsigned) bit); } } if (status & 2) { /* we could write back correct ECC data */ LOG_ERROR("Error in ECC bytes detected"); } } if (!oob) { /* if it wasn't asked for, free it */ free(oob_data); } return retval; } /** * Write a page of data including 1-bit ECC information to a NAND device * attached to an AT91SAM9 controller. If there is OOB data to be written, * this will ignore the computed ECC from the ECC controller. * * @param nand NAND device to write to. * @param page Page to write. * @param data Pointer to data being written. * @param data_size Size of the data being written. * @param oob Pointer to OOB data being written. * @param oob_size Size of the OOB data. * @return Success or failure of the page write. */ static int at91sam9_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; int retval; uint8_t *oob_data = oob; uint32_t parity, nparity; retval = at91sam9_ecc_init(target, info); if (retval != ERROR_OK) return retval; retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); if (retval != ERROR_OK) return retval; if (data) { retval = nand_write_data_page(nand, data, data_size); if (retval != ERROR_OK) { LOG_ERROR("Unable to write data to NAND device"); return retval; } } oob_data = at91sam9_oob_init(nand, oob, &oob_size); if (!oob) { /* no OOB given, so read in the ECC parity from the ECC controller */ target_read_u32(target, info->ecc + AT91C_ECCX_PR, &parity); target_read_u32(target, info->ecc + AT91C_ECCX_NPR, &nparity); oob_data[0] = (uint8_t) parity; oob_data[1] = (uint8_t) (parity >> 8); oob_data[2] = (uint8_t) nparity; oob_data[3] = (uint8_t) (nparity >> 8); } retval = nand_write_data_page(nand, oob_data, oob_size); if (!oob) free(oob_data); if (retval != ERROR_OK) { LOG_ERROR("Unable to write OOB data to NAND"); return retval; } retval = nand_write_finish(nand); return retval; } /** * Handle the initial NAND device command for AT91SAM9 controllers. This * initializes much of the controller information struct to be ready for future * reads and writes. */ NAND_DEVICE_COMMAND_HANDLER(at91sam9_nand_device_command) { unsigned long chip = 0, ecc = 0; struct at91sam9_nand *info = NULL; LOG_DEBUG("AT91SAM9 NAND Device Command"); if (CMD_ARGC < 3 || CMD_ARGC > 4) { LOG_ERROR("parameters: %s target chip_addr", CMD_ARGV[0]); return ERROR_NAND_OPERATION_FAILED; } COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip); if (chip == 0) { LOG_ERROR("invalid NAND chip address: %s", CMD_ARGV[2]); return ERROR_NAND_OPERATION_FAILED; } if (CMD_ARGC == 4) { COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[3], ecc); if (ecc == 0) { LOG_ERROR("invalid ECC controller address: %s", CMD_ARGV[3]); return ERROR_NAND_OPERATION_FAILED; } } info = calloc(1, sizeof(*info)); if (!info) { LOG_ERROR("unable to allocate space for controller private data"); return ERROR_NAND_OPERATION_FAILED; } info->data = chip; info->cmd = chip | (1 << 22); info->addr = chip | (1 << 21); info->ecc = ecc; nand->controller_priv = info; info->io.target = nand->target; info->io.data = info->data; info->io.op = ARM_NAND_NONE; return ERROR_OK; } /** * Handle the AT91SAM9 CLE command for specifying the address line to use for * writing commands to a NAND device. */ COMMAND_HANDLER(handle_at91sam9_cle_command) { struct nand_device *nand = NULL; struct at91sam9_nand *info = NULL; unsigned num, address_line; if (CMD_ARGC != 2) { command_print(CMD, "incorrect number of arguments for 'at91sam9 cle' command"); return ERROR_OK; } COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); nand = get_nand_device_by_num(num); if (!nand) { command_print(CMD, "invalid nand device number: %s", CMD_ARGV[0]); return ERROR_OK; } info = nand->controller_priv; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], address_line); info->cmd = info->data | (1 << address_line); return ERROR_OK; } /** * Handle the AT91SAM9 ALE command for specifying the address line to use for * writing addresses to the NAND device. */ COMMAND_HANDLER(handle_at91sam9_ale_command) { struct nand_device *nand = NULL; struct at91sam9_nand *info = NULL; unsigned num, address_line; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); nand = get_nand_device_by_num(num); if (!nand) { command_print(CMD, "invalid nand device number: %s", CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } info = nand->controller_priv; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], address_line); info->addr = info->data | (1 << address_line); return ERROR_OK; } /** * Handle the AT91SAM9 RDY/~BUSY command for specifying the pin that watches the * RDY/~BUSY line from the NAND device. */ COMMAND_HANDLER(handle_at91sam9_rdy_busy_command) { struct nand_device *nand = NULL; struct at91sam9_nand *info = NULL; unsigned num, base_pioc, pin_num; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); nand = get_nand_device_by_num(num); if (!nand) { command_print(CMD, "invalid nand device number: %s", CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } info = nand->controller_priv; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], base_pioc); info->busy.pioc = base_pioc; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], pin_num); info->busy.num = pin_num; return ERROR_OK; } /** * Handle the AT91SAM9 CE command for specifying the pin that is used to enable * or disable the NAND device. */ COMMAND_HANDLER(handle_at91sam9_ce_command) { struct nand_device *nand = NULL; struct at91sam9_nand *info = NULL; unsigned num, base_pioc, pin_num; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); nand = get_nand_device_by_num(num); if (!nand) { command_print(CMD, "invalid nand device number: %s", CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } info = nand->controller_priv; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], base_pioc); info->ce.pioc = base_pioc; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], pin_num); info->ce.num = pin_num; return ERROR_OK; } static const struct command_registration at91sam9_sub_command_handlers[] = { { .name = "cle", .handler = handle_at91sam9_cle_command, .mode = COMMAND_CONFIG, .help = "set command latch enable address line (default is 22)", .usage = "bank_id address_line", }, { .name = "ale", .handler = handle_at91sam9_ale_command, .mode = COMMAND_CONFIG, .help = "set address latch enable address line (default is 21)", .usage = "bank_id address_line", }, { .name = "rdy_busy", .handler = handle_at91sam9_rdy_busy_command, .mode = COMMAND_CONFIG, .help = "set the GPIO input pin connected to " "the RDY/~BUSY signal (no default)", .usage = "bank_id pio_base_addr pin_num", }, { .name = "ce", .handler = handle_at91sam9_ce_command, .mode = COMMAND_CONFIG, .help = "set the GPIO output pin connected to " "the chip enable signal (no default)", .usage = "bank_id pio_base_addr pin_num", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration at91sam9_command_handler[] = { { .name = "at91sam9", .mode = COMMAND_ANY, .help = "AT91SAM9 NAND flash controller commands", .usage = "", .chain = at91sam9_sub_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** * Structure representing the AT91SAM9 NAND controller. */ struct nand_flash_controller at91sam9_nand_controller = { .name = "at91sam9", .nand_device_command = at91sam9_nand_device_command, .commands = at91sam9_command_handler, .init = at91sam9_init, .command = at91sam9_command, .reset = at91sam9_reset, .address = at91sam9_address, .read_data = at91sam9_read_data, .write_data = at91sam9_write_data, .nand_ready = at91sam9_nand_ready, .read_block_data = at91sam9_read_block_data, .write_block_data = at91sam9_write_block_data, .read_page = at91sam9_read_page, .write_page = at91sam9_write_page, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/core.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * * * Partially based on drivers/mtd/nand_ids.c from Linux. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" /* configured NAND devices and NAND Flash command handler */ struct nand_device *nand_devices; void nand_device_add(struct nand_device *c) { if (nand_devices) { struct nand_device *p = nand_devices; while (p && p->next) p = p->next; p->next = c; } else nand_devices = c; } /* Chip ID list * * Manufacturer, ID code, pagesize, chipsize in MegaByte, eraseblock size, * options, name * * Pagesize; 0, 256, 512 * 0 get this information from the extended chip ID * 256 256 Byte page size * 512 512 Byte page size */ static struct nand_info nand_flash_ids[] = { /* Vendor Specific Entries */ { NAND_MFR_SAMSUNG, 0xD5, 8192, 2048, 0x100000, LP_OPTIONS, "K9GAG08 2GB NAND 3.3V x8 MLC 2b/cell"}, { NAND_MFR_SAMSUNG, 0xD7, 8192, 4096, 0x100000, LP_OPTIONS, "K9LBG08 4GB NAND 3.3V x8 MLC 2b/cell"}, /* start "museum" IDs */ { 0x0, 0x6e, 256, 1, 0x1000, 0, "NAND 1MiB 5V 8-bit"}, { 0x0, 0x64, 256, 2, 0x1000, 0, "NAND 2MiB 5V 8-bit"}, { 0x0, 0x6b, 512, 4, 0x2000, 0, "NAND 4MiB 5V 8-bit"}, { 0x0, 0xe8, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"}, { 0x0, 0xec, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"}, { 0x0, 0xea, 256, 2, 0x1000, 0, "NAND 2MiB 3.3V 8-bit"}, { 0x0, 0xd5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"}, { 0x0, 0xe3, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"}, { 0x0, 0xe5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"}, { 0x0, 0xd6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"}, { 0x0, 0x39, 512, 8, 0x2000, 0, "NAND 8MiB 1.8V 8-bit"}, { 0x0, 0xe6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"}, { 0x0, 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 1.8V 16-bit"}, { 0x0, 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 3.3V 16-bit"}, /* end "museum" IDs */ { 0x0, 0x33, 512, 16, 0x4000, 0, "NAND 16MiB 1.8V 8-bit"}, { 0x0, 0x73, 512, 16, 0x4000, 0, "NAND 16MiB 3.3V 8-bit"}, { 0x0, 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16, "NAND 16MiB 1.8V 16-bit"}, { 0x0, 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16, "NAND 16MiB 3.3V 16-bit"}, { 0x0, 0x35, 512, 32, 0x4000, 0, "NAND 32MiB 1.8V 8-bit"}, { 0x0, 0x75, 512, 32, 0x4000, 0, "NAND 32MiB 3.3V 8-bit"}, { 0x0, 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16, "NAND 32MiB 1.8V 16-bit"}, { 0x0, 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16, "NAND 32MiB 3.3V 16-bit"}, { 0x0, 0x36, 512, 64, 0x4000, 0, "NAND 64MiB 1.8V 8-bit"}, { 0x0, 0x76, 512, 64, 0x4000, 0, "NAND 64MiB 3.3V 8-bit"}, { 0x0, 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16, "NAND 64MiB 1.8V 16-bit"}, { 0x0, 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16, "NAND 64MiB 3.3V 16-bit"}, { 0x0, 0x78, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"}, { 0x0, 0x39, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"}, { 0x0, 0x79, 512, 128, 0x4000, 0, "NAND 128MiB 3.3V 8-bit"}, { 0x0, 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 1.8V 16-bit"}, { 0x0, 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 1.8V 16-bit"}, { 0x0, 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 3.3V 16-bit"}, { 0x0, 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 3.3V 16-bit"}, { 0x0, 0x71, 512, 256, 0x4000, 0, "NAND 256MiB 3.3V 8-bit"}, { 0x0, 0xA2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 1.8V 8-bit"}, { 0x0, 0xF2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 3.3V 8-bit"}, { 0x0, 0xB2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 1.8V 16-bit"}, { 0x0, 0xC2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 3.3V 16-bit"}, { 0x0, 0xA1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 1.8V 8-bit"}, { 0x0, 0xF1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 3.3V 8-bit"}, { 0x0, 0xB1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 1.8V 16-bit"}, { 0x0, 0xC1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 3.3V 16-bit"}, { 0x0, 0xAA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 1.8V 8-bit"}, { 0x0, 0xDA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 3.3V 8-bit"}, { 0x0, 0xBA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 1.8V 16-bit"}, { 0x0, 0xCA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 3.3V 16-bit"}, { 0x0, 0xAC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 1.8V 8-bit"}, { 0x0, 0xDC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 3.3V 8-bit"}, { 0x0, 0xBC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 1.8V 16-bit"}, { 0x0, 0xCC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 3.3V 16-bit"}, { 0x0, 0xA3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 1.8V 8-bit"}, { 0x0, 0xD3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 3.3V 8-bit"}, { 0x0, 0xB3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 1.8V 16-bit"}, { 0x0, 0xC3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 3.3V 16-bit"}, { 0x0, 0xA5, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 1.8V 8-bit"}, { 0x0, 0xD5, 0, 8192, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"}, { 0x0, 0xB5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 1.8V 16-bit"}, { 0x0, 0xC5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 3.3V 16-bit"}, { 0x0, 0x48, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"}, {0, 0, 0, 0, 0, 0, NULL} }; /* Manufacturer ID list */ static struct nand_manufacturer nand_manuf_ids[] = { {0x0, "unknown"}, {NAND_MFR_TOSHIBA, "Toshiba"}, {NAND_MFR_SAMSUNG, "Samsung"}, {NAND_MFR_FUJITSU, "Fujitsu"}, {NAND_MFR_NATIONAL, "National"}, {NAND_MFR_RENESAS, "Renesas"}, {NAND_MFR_STMICRO, "ST Micro"}, {NAND_MFR_HYNIX, "Hynix"}, {NAND_MFR_MICRON, "Micron"}, {0x0, NULL}, }; /* * Define default oob placement schemes for large and small page devices */ #if 0 static struct nand_ecclayout nand_oob_8 = { .eccbytes = 3, .eccpos = {0, 1, 2}, .oobfree = { {.offset = 3, .length = 2}, {.offset = 6, .length = 2} } }; #endif /** * Returns the flash bank specified by @a name, which matches the * driver name and a suffix (option) specify the driver-specific * bank number. The suffix consists of the '.' and the driver-specific * bank number: when two davinci banks are defined, then 'davinci.1' refers * to the second (e.g. DM355EVM). */ static struct nand_device *get_nand_device_by_name(const char *name) { unsigned requested = get_flash_name_index(name); unsigned found = 0; struct nand_device *nand; for (nand = nand_devices; nand; nand = nand->next) { if (strcmp(nand->name, name) == 0) return nand; if (!flash_driver_name_matches(nand->controller->name, name)) continue; if (++found < requested) continue; return nand; } return NULL; } struct nand_device *get_nand_device_by_num(int num) { struct nand_device *p; int i = 0; for (p = nand_devices; p; p = p->next) { if (i++ == num) return p; } return NULL; } COMMAND_HELPER(nand_command_get_device, unsigned name_index, struct nand_device **nand) { const char *str = CMD_ARGV[name_index]; *nand = get_nand_device_by_name(str); if (*nand) return ERROR_OK; unsigned num; COMMAND_PARSE_NUMBER(uint, str, num); *nand = get_nand_device_by_num(num); if (!*nand) { command_print(CMD, "NAND flash device '%s' not found", str); return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } int nand_build_bbt(struct nand_device *nand, int first, int last) { uint32_t page; int i; int pages_per_block = (nand->erase_size / nand->page_size); uint8_t oob[6]; int ret; if ((first < 0) || (first >= nand->num_blocks)) first = 0; if ((last >= nand->num_blocks) || (last == -1)) last = nand->num_blocks - 1; page = first * pages_per_block; for (i = first; i <= last; i++) { ret = nand_read_page(nand, page, NULL, 0, oob, 6); if (ret != ERROR_OK) return ret; if (((nand->device->options & NAND_BUSWIDTH_16) && ((oob[0] & oob[1]) != 0xff)) || (((nand->page_size == 512) && (oob[5] != 0xff)) || ((nand->page_size == 2048) && (oob[0] != 0xff)))) { LOG_WARNING("bad block: %i", i); nand->blocks[i].is_bad = 1; } else nand->blocks[i].is_bad = 0; page += pages_per_block; } return ERROR_OK; } int nand_read_status(struct nand_device *nand, uint8_t *status) { if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; /* Send read status command */ /* FIXME: errors returned from nand->controller are mostly ignored! */ nand->controller->command(nand, NAND_CMD_STATUS); alive_sleep(1); /* read status */ if (nand->device->options & NAND_BUSWIDTH_16) { uint16_t data; nand->controller->read_data(nand, &data); *status = data & 0xff; } else nand->controller->read_data(nand, status); return ERROR_OK; } static int nand_poll_ready(struct nand_device *nand, int timeout) { uint8_t status; nand->controller->command(nand, NAND_CMD_STATUS); do { if (nand->device->options & NAND_BUSWIDTH_16) { uint16_t data; nand->controller->read_data(nand, &data); status = data & 0xff; } else nand->controller->read_data(nand, &status); if (status & NAND_STATUS_READY) break; alive_sleep(1); } while (timeout--); return (status & NAND_STATUS_READY) != 0; } int nand_probe(struct nand_device *nand) { uint8_t manufacturer_id, device_id; uint8_t id_buff[6] = { 0 }; /* zero buff to silence false warning * from clang static analyzer */ int retval; int i; /* clear device data */ nand->device = NULL; nand->manufacturer = NULL; /* clear device parameters */ nand->bus_width = 0; nand->address_cycles = 0; nand->page_size = 0; nand->erase_size = 0; /* initialize controller (device parameters are zero, use controller default) */ retval = nand->controller->init(nand); if (retval != ERROR_OK) { switch (retval) { case ERROR_NAND_OPERATION_FAILED: LOG_DEBUG("controller initialization failed"); return ERROR_NAND_OPERATION_FAILED; case ERROR_NAND_OPERATION_NOT_SUPPORTED: LOG_ERROR( "BUG: controller reported that it doesn't support default parameters"); return ERROR_NAND_OPERATION_FAILED; default: LOG_ERROR("BUG: unknown controller initialization failure"); return ERROR_NAND_OPERATION_FAILED; } } nand->controller->command(nand, NAND_CMD_RESET); nand->controller->reset(nand); nand->controller->command(nand, NAND_CMD_READID); nand->controller->address(nand, 0x0); if (nand->bus_width == 8) { nand->controller->read_data(nand, &manufacturer_id); nand->controller->read_data(nand, &device_id); } else { uint16_t data_buf; nand->controller->read_data(nand, &data_buf); manufacturer_id = data_buf & 0xff; nand->controller->read_data(nand, &data_buf); device_id = data_buf & 0xff; } for (i = 0; nand_flash_ids[i].name; i++) { if (nand_flash_ids[i].id == device_id && (nand_flash_ids[i].mfr_id == manufacturer_id || nand_flash_ids[i].mfr_id == 0)) { nand->device = &nand_flash_ids[i]; break; } } for (i = 0; nand_manuf_ids[i].name; i++) { if (nand_manuf_ids[i].id == manufacturer_id) { nand->manufacturer = &nand_manuf_ids[i]; break; } } if (!nand->manufacturer) { nand->manufacturer = &nand_manuf_ids[0]; nand->manufacturer->id = manufacturer_id; } if (!nand->device) { LOG_ERROR( "unknown NAND flash device found, manufacturer id: 0x%2.2x device id: 0x%2.2x", manufacturer_id, device_id); return ERROR_NAND_OPERATION_FAILED; } LOG_DEBUG("found %s (%s)", nand->device->name, nand->manufacturer->name); /* initialize device parameters */ /* bus width */ if (nand->device->options & NAND_BUSWIDTH_16) nand->bus_width = 16; else nand->bus_width = 8; /* Do we need extended device probe information? */ if (nand->device->page_size == 0 || nand->device->erase_size == 0) { if (nand->bus_width == 8) { retval = nand->controller->read_data(nand, id_buff + 3); if (retval != ERROR_OK) return retval; retval = nand->controller->read_data(nand, id_buff + 4); if (retval != ERROR_OK) return retval; retval = nand->controller->read_data(nand, id_buff + 5); if (retval != ERROR_OK) return retval; } else { uint16_t data_buf; retval = nand->controller->read_data(nand, &data_buf); if (retval != ERROR_OK) return retval; id_buff[3] = data_buf; retval = nand->controller->read_data(nand, &data_buf); if (retval != ERROR_OK) return retval; id_buff[4] = data_buf; retval = nand->controller->read_data(nand, &data_buf); if (retval != ERROR_OK) return retval; id_buff[5] = data_buf >> 8; } } /* page size */ if (nand->device->page_size == 0) nand->page_size = 1 << (10 + (id_buff[4] & 3)); else if (nand->device->page_size == 256) { LOG_ERROR("NAND flashes with 256 byte pagesize are not supported"); return ERROR_NAND_OPERATION_FAILED; } else nand->page_size = nand->device->page_size; /* number of address cycles */ if (nand->page_size <= 512) { /* small page devices */ if (nand->device->chip_size <= 32) nand->address_cycles = 3; else if (nand->device->chip_size <= 8*1024) nand->address_cycles = 4; else { LOG_ERROR("BUG: small page NAND device with more than 8 GiB encountered"); nand->address_cycles = 5; } } else { /* large page devices */ if (nand->device->chip_size <= 128) nand->address_cycles = 4; else if (nand->device->chip_size <= 32*1024) nand->address_cycles = 5; else { LOG_ERROR("BUG: large page NAND device with more than 32 GiB encountered"); nand->address_cycles = 6; } } /* erase size */ if (nand->device->erase_size == 0) { switch ((id_buff[4] >> 4) & 3) { case 0: nand->erase_size = 64 << 10; break; case 1: nand->erase_size = 128 << 10; break; case 2: nand->erase_size = 256 << 10; break; case 3: nand->erase_size = 512 << 10; break; } } else nand->erase_size = nand->device->erase_size; /* initialize controller, but leave parameters at the controllers default */ retval = nand->controller->init(nand); if (retval != ERROR_OK) { switch (retval) { case ERROR_NAND_OPERATION_FAILED: LOG_DEBUG("controller initialization failed"); return ERROR_NAND_OPERATION_FAILED; case ERROR_NAND_OPERATION_NOT_SUPPORTED: LOG_ERROR( "controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)", nand->bus_width, nand->address_cycles, nand->page_size); return ERROR_NAND_OPERATION_FAILED; default: LOG_ERROR("BUG: unknown controller initialization failure"); return ERROR_NAND_OPERATION_FAILED; } } nand->num_blocks = (nand->device->chip_size * 1024) / (nand->erase_size / 1024); nand->blocks = malloc(sizeof(struct nand_block) * nand->num_blocks); for (i = 0; i < nand->num_blocks; i++) { nand->blocks[i].size = nand->erase_size; nand->blocks[i].offset = i * nand->erase_size; nand->blocks[i].is_erased = -1; nand->blocks[i].is_bad = -1; } return ERROR_OK; } int nand_erase(struct nand_device *nand, int first_block, int last_block) { int i; uint32_t page; uint8_t status; int retval; if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; if ((first_block < 0) || (last_block >= nand->num_blocks)) return ERROR_COMMAND_SYNTAX_ERROR; /* make sure we know if a block is bad before erasing it */ for (i = first_block; i <= last_block; i++) { if (nand->blocks[i].is_bad == -1) { nand_build_bbt(nand, i, last_block); break; } } for (i = first_block; i <= last_block; i++) { /* Send erase setup command */ nand->controller->command(nand, NAND_CMD_ERASE1); page = i * (nand->erase_size / nand->page_size); /* Send page address */ if (nand->page_size <= 512) { /* row */ nand->controller->address(nand, page & 0xff); nand->controller->address(nand, (page >> 8) & 0xff); /* 3rd cycle only on devices with more than 32 MiB */ if (nand->address_cycles >= 4) nand->controller->address(nand, (page >> 16) & 0xff); /* 4th cycle only on devices with more than 8 GiB */ if (nand->address_cycles >= 5) nand->controller->address(nand, (page >> 24) & 0xff); } else { /* row */ nand->controller->address(nand, page & 0xff); nand->controller->address(nand, (page >> 8) & 0xff); /* 3rd cycle only on devices with more than 128 MiB */ if (nand->address_cycles >= 5) nand->controller->address(nand, (page >> 16) & 0xff); } /* Send erase confirm command */ nand->controller->command(nand, NAND_CMD_ERASE2); retval = nand->controller->nand_ready ? nand->controller->nand_ready(nand, 1000) : nand_poll_ready(nand, 1000); if (!retval) { LOG_ERROR("timeout waiting for NAND flash block erase to complete"); return ERROR_NAND_OPERATION_TIMEOUT; } retval = nand_read_status(nand, &status); if (retval != ERROR_OK) { LOG_ERROR("couldn't read status"); return ERROR_NAND_OPERATION_FAILED; } if (status & 0x1) { LOG_ERROR("didn't erase %sblock %d; status: 0x%2.2x", (nand->blocks[i].is_bad == 1) ? "bad " : "", i, status); /* continue; other blocks might still be erasable */ } nand->blocks[i].is_erased = 1; } return ERROR_OK; } #if 0 static int nand_read_plain(struct nand_device *nand, uint32_t address, uint8_t *data, uint32_t data_size) { uint8_t *page; if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; if (address % nand->page_size) { LOG_ERROR("reads need to be page aligned"); return ERROR_NAND_OPERATION_FAILED; } page = malloc(nand->page_size); while (data_size > 0) { uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size; uint32_t page_address; page_address = address / nand->page_size; nand_read_page(nand, page_address, page, nand->page_size, NULL, 0); memcpy(data, page, thisrun_size); address += thisrun_size; data += thisrun_size; data_size -= thisrun_size; } free(page); return ERROR_OK; } static int nand_write_plain(struct nand_device *nand, uint32_t address, uint8_t *data, uint32_t data_size) { uint8_t *page; if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; if (address % nand->page_size) { LOG_ERROR("writes need to be page aligned"); return ERROR_NAND_OPERATION_FAILED; } page = malloc(nand->page_size); while (data_size > 0) { uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size; uint32_t page_address; memset(page, 0xff, nand->page_size); memcpy(page, data, thisrun_size); page_address = address / nand->page_size; nand_write_page(nand, page_address, page, nand->page_size, NULL, 0); address += thisrun_size; data += thisrun_size; data_size -= thisrun_size; } free(page); return ERROR_OK; } #endif int nand_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { uint32_t block; if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; block = page / (nand->erase_size / nand->page_size); if (nand->blocks[block].is_erased == 1) nand->blocks[block].is_erased = 0; if (nand->use_raw || !nand->controller->write_page) return nand_write_page_raw(nand, page, data, data_size, oob, oob_size); else return nand->controller->write_page(nand, page, data, data_size, oob, oob_size); } int nand_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; if (nand->use_raw || !nand->controller->read_page) return nand_read_page_raw(nand, page, data, data_size, oob, oob_size); else return nand->controller->read_page(nand, page, data, data_size, oob, oob_size); } int nand_page_command(struct nand_device *nand, uint32_t page, uint8_t cmd, bool oob_only) { if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; if (oob_only && NAND_CMD_READ0 == cmd && nand->page_size <= 512) cmd = NAND_CMD_READOOB; nand->controller->command(nand, cmd); if (nand->page_size <= 512) { /* small page device */ /* column (always 0, we start at the beginning of a page/OOB area) */ nand->controller->address(nand, 0x0); /* row */ nand->controller->address(nand, page & 0xff); nand->controller->address(nand, (page >> 8) & 0xff); /* 4th cycle only on devices with more than 32 MiB */ if (nand->address_cycles >= 4) nand->controller->address(nand, (page >> 16) & 0xff); /* 5th cycle only on devices with more than 8 GiB */ if (nand->address_cycles >= 5) nand->controller->address(nand, (page >> 24) & 0xff); } else { /* large page device */ /* column (0 when we start at the beginning of a page, * or 2048 for the beginning of OOB area) */ nand->controller->address(nand, 0x0); if (oob_only) nand->controller->address(nand, 0x8); else nand->controller->address(nand, 0x0); /* row */ nand->controller->address(nand, page & 0xff); nand->controller->address(nand, (page >> 8) & 0xff); /* 5th cycle only on devices with more than 128 MiB */ if (nand->address_cycles >= 5) nand->controller->address(nand, (page >> 16) & 0xff); /* large page devices need a start command if reading */ if (cmd == NAND_CMD_READ0) nand->controller->command(nand, NAND_CMD_READSTART); } if (nand->controller->nand_ready) { if (!nand->controller->nand_ready(nand, 100)) return ERROR_NAND_OPERATION_TIMEOUT; } else { /* nand_poll_read() cannot be used during nand read */ alive_sleep(1); } return ERROR_OK; } int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size) { int retval = ERROR_NAND_NO_BUFFER; if (nand->controller->read_block_data) retval = (nand->controller->read_block_data)(nand, data, size); if (retval == ERROR_NAND_NO_BUFFER) { uint32_t i; int incr = (nand->device->options & NAND_BUSWIDTH_16) ? 2 : 1; retval = ERROR_OK; for (i = 0; retval == ERROR_OK && i < size; i += incr) { retval = nand->controller->read_data(nand, data); data += incr; } } return retval; } int nand_read_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { int retval; retval = nand_page_command(nand, page, NAND_CMD_READ0, !data); if (retval != ERROR_OK) return retval; if (data) nand_read_data_page(nand, data, data_size); if (oob) nand_read_data_page(nand, oob, oob_size); return ERROR_OK; } int nand_write_data_page(struct nand_device *nand, uint8_t *data, uint32_t size) { int retval = ERROR_NAND_NO_BUFFER; if (nand->controller->write_block_data) retval = (nand->controller->write_block_data)(nand, data, size); if (retval == ERROR_NAND_NO_BUFFER) { bool is16bit = nand->device->options & NAND_BUSWIDTH_16; uint32_t incr = is16bit ? 2 : 1; uint16_t write_data; uint32_t i; for (i = 0; i < size; i += incr) { if (is16bit) write_data = le_to_h_u16(data); else write_data = *data; retval = nand->controller->write_data(nand, write_data); if (retval != ERROR_OK) break; data += incr; } } return retval; } int nand_write_finish(struct nand_device *nand) { int retval; uint8_t status; nand->controller->command(nand, NAND_CMD_PAGEPROG); retval = nand->controller->nand_ready ? nand->controller->nand_ready(nand, 100) : nand_poll_ready(nand, 100); if (!retval) return ERROR_NAND_OPERATION_TIMEOUT; retval = nand_read_status(nand, &status); if (retval != ERROR_OK) { LOG_ERROR("couldn't read status"); return ERROR_NAND_OPERATION_FAILED; } if (status & NAND_STATUS_FAIL) { LOG_ERROR("write operation didn't pass, status: 0x%2.2x", status); return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } int nand_write_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { int retval; retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); if (retval != ERROR_OK) return retval; if (data) { retval = nand_write_data_page(nand, data, data_size); if (retval != ERROR_OK) { LOG_ERROR("Unable to write data to NAND device"); return retval; } } if (oob) { retval = nand_write_data_page(nand, oob, oob_size); if (retval != ERROR_OK) { LOG_ERROR("Unable to write OOB data to NAND device"); return retval; } } return nand_write_finish(nand); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/core.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * * * Partially based on linux/include/linux/mtd/nand.h * * Copyright (C) 2000 David Woodhouse <dwmw2@mvhi.com> * * Copyright (C) 2000 Steven J. Hill <sjhill@realitydiluted.com> * * Copyright (C) 2000 Thomas Gleixner <tglx@linutronix.de> * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_CORE_H #define OPENOCD_FLASH_NAND_CORE_H #include <flash/common.h> /** * Representation of a single NAND block in a NAND device. */ struct nand_block { /** Offset to the block. */ uint32_t offset; /** Size of the block. */ uint32_t size; /** True if the block has been erased. */ int is_erased; /** True if the block is bad. */ int is_bad; }; struct nand_oobfree { int offset; int length; }; struct nand_ecclayout { int eccbytes; int eccpos[64]; int oobavail; struct nand_oobfree oobfree[2]; }; struct nand_device { const char *name; struct target *target; struct nand_flash_controller *controller; void *controller_priv; struct nand_manufacturer *manufacturer; struct nand_info *device; int bus_width; int address_cycles; int page_size; int erase_size; bool use_raw; int num_blocks; struct nand_block *blocks; struct nand_device *next; }; /* NAND Flash Manufacturer ID Codes */ enum { NAND_MFR_TOSHIBA = 0x98, NAND_MFR_SAMSUNG = 0xec, NAND_MFR_FUJITSU = 0x04, NAND_MFR_NATIONAL = 0x8f, NAND_MFR_RENESAS = 0x07, NAND_MFR_STMICRO = 0x20, NAND_MFR_HYNIX = 0xad, NAND_MFR_MICRON = 0x2c, }; struct nand_manufacturer { int id; const char *name; }; struct nand_info { int mfr_id; int id; int page_size; int chip_size; int erase_size; int options; const char *name; }; /* Option constants for bizarre dysfunctionality and real features */ enum { /* Chip can not auto increment pages */ NAND_NO_AUTOINCR = 0x00000001, /* Buswitdh is 16 bit */ NAND_BUSWIDTH_16 = 0x00000002, /* Device supports partial programming without padding */ NAND_NO_PADDING = 0x00000004, /* Chip has cache program function */ NAND_CACHEPRG = 0x00000008, /* Chip has copy back function */ NAND_COPYBACK = 0x00000010, /* AND Chip which has 4 banks and a confusing page / block * assignment. See Renesas datasheet for further information */ NAND_IS_AND = 0x00000020, /* Chip has a array of 4 pages which can be read without * additional ready /busy waits */ NAND_4PAGE_ARRAY = 0x00000040, /* Chip requires that BBT is periodically rewritten to prevent * bits from adjacent blocks from 'leaking' in altering data. * This happens with the Renesas AG-AND chips, possibly others. */ BBT_AUTO_REFRESH = 0x00000080, /* Chip does not require ready check on read. True * for all large page devices, as they do not support * autoincrement.*/ NAND_NO_READRDY = 0x00000100, /* Options valid for Samsung large page devices */ NAND_SAMSUNG_LP_OPTIONS = (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK), /* Options for new chips with large page size. The pagesize and the * erasesize is determined from the extended id bytes */ LP_OPTIONS = (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR), LP_OPTIONS16 = (LP_OPTIONS | NAND_BUSWIDTH_16), }; enum { /* Standard NAND flash commands */ NAND_CMD_READ0 = 0x0, NAND_CMD_READ1 = 0x1, NAND_CMD_RNDOUT = 0x5, NAND_CMD_PAGEPROG = 0x10, NAND_CMD_READOOB = 0x50, NAND_CMD_ERASE1 = 0x60, NAND_CMD_STATUS = 0x70, NAND_CMD_STATUS_MULTI = 0x71, NAND_CMD_SEQIN = 0x80, NAND_CMD_RNDIN = 0x85, NAND_CMD_READID = 0x90, NAND_CMD_ERASE2 = 0xd0, NAND_CMD_RESET = 0xff, /* Extended commands for large page devices */ NAND_CMD_READSTART = 0x30, NAND_CMD_RNDOUTSTART = 0xE0, NAND_CMD_CACHEDPROG = 0x15, }; /* Status bits */ enum { NAND_STATUS_FAIL = 0x01, NAND_STATUS_FAIL_N1 = 0x02, NAND_STATUS_TRUE_READY = 0x20, NAND_STATUS_READY = 0x40, NAND_STATUS_WP = 0x80, }; /* OOB (spare) data formats */ enum oob_formats { NAND_OOB_NONE = 0x0, /* no OOB data at all */ NAND_OOB_RAW = 0x1, /* raw OOB data (16 bytes for 512b page sizes, 64 bytes for *2048b page sizes) */ NAND_OOB_ONLY = 0x2, /* only OOB data */ NAND_OOB_SW_ECC = 0x10, /* when writing, use SW ECC (as opposed to no ECC) */ NAND_OOB_HW_ECC = 0x20, /* when writing, use HW ECC (as opposed to no ECC) */ NAND_OOB_SW_ECC_KW = 0x40, /* when writing, use Marvell's Kirkwood bootrom format */ NAND_OOB_JFFS2 = 0x100, /* when writing, use JFFS2 OOB layout */ NAND_OOB_YAFFS2 = 0x100,/* when writing, use YAFFS2 OOB layout */ }; extern struct nand_device *nand_devices; struct nand_device *get_nand_device_by_num(int num); int nand_page_command(struct nand_device *nand, uint32_t page, uint8_t cmd, bool oob_only); int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size); int nand_write_data_page(struct nand_device *nand, uint8_t *data, uint32_t size); int nand_write_finish(struct nand_device *nand); int nand_read_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); int nand_write_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); int nand_read_status(struct nand_device *nand, uint8_t *status); int nand_calculate_ecc(struct nand_device *nand, const uint8_t *dat, uint8_t *ecc_code); int nand_calculate_ecc_kw(struct nand_device *nand, const uint8_t *dat, uint8_t *ecc_code); int nand_correct_data(struct nand_device *nand, u_char *dat, u_char *read_ecc, u_char *calc_ecc); int nand_register_commands(struct command_context *cmd_ctx); /** helper for parsing a nand device command argument string */ COMMAND_HELPER(nand_command_get_device, unsigned name_index, struct nand_device **nand); #define ERROR_NAND_DEVICE_INVALID (-1100) #define ERROR_NAND_OPERATION_FAILED (-1101) #define ERROR_NAND_OPERATION_TIMEOUT (-1102) #define ERROR_NAND_OPERATION_NOT_SUPPORTED (-1103) #define ERROR_NAND_DEVICE_NOT_PROBED (-1104) #define ERROR_NAND_ERROR_CORRECTION_FAILED (-1105) #define ERROR_NAND_NO_BUFFER (-1106) #endif /* OPENOCD_FLASH_NAND_CORE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/davinci.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by David Brownell * ***************************************************************************/ /* * DaVinci family NAND controller support for OpenOCD. * * This driver uses hardware ECC (1-bit or 4-bit) unless * the chip is accessed in "raw" mode. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "arm_io.h" #include <target/target.h> enum ecc { HWECC1, /* all controllers support 1-bit ECC */ HWECC4, /* newer chips also have 4-bit ECC hardware */ HWECC4_INFIX, /* avoid this layout, except maybe for boot code */ }; struct davinci_nand { uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */ uint8_t eccmode; /* Async EMIF controller base */ uint32_t aemif; /* NAND chip addresses */ uint32_t data; /* without CLE or ALE */ uint32_t cmd; /* with CLE */ uint32_t addr; /* with ALE */ /* write acceleration */ struct arm_nand_data io; /* page i/o for the relevant flavor of hardware ECC */ int (*read_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); int (*write_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); }; #define NANDFCR 0x60 /* flash control register */ #define NANDFSR 0x64 /* flash status register */ #define NANDFECC 0x70 /* 1-bit ECC data, CS0, 1st of 4 */ #define NAND4BITECCLOAD 0xbc /* 4-bit ECC, load saved values */ #define NAND4BITECC 0xc0 /* 4-bit ECC data, 1st of 4 */ #define NANDERRADDR 0xd0 /* 4-bit ECC err addr, 1st of 2 */ #define NANDERRVAL 0xd8 /* 4-bit ECC err value, 1st of 2 */ static int halted(struct target *target, const char *label) { if (target->state == TARGET_HALTED) return true; LOG_ERROR("Target must be halted to use NAND controller (%s)", label); return false; } static int davinci_init(struct nand_device *nand) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; uint32_t nandfcr; if (!halted(target, "init")) return ERROR_NAND_OPERATION_FAILED; /* We require something else to have configured AEMIF to talk * to NAND chip in this range (including timings and width). */ target_read_u32(target, info->aemif + NANDFCR, &nandfcr); if (!(nandfcr & (1 << info->chipsel))) { LOG_ERROR("chip address %08" PRIx32 " not NAND-enabled?", info->data); return ERROR_NAND_OPERATION_FAILED; } /* REVISIT verify: AxCR must be in 8-bit mode, since that's all we * tested. 16 bit support should work too; but not with 4-bit ECC. */ return ERROR_OK; } static int davinci_reset(struct nand_device *nand) { return ERROR_OK; } static int davinci_nand_ready(struct nand_device *nand, int timeout) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; uint32_t nandfsr; /* NOTE: return code is zero/error, else success; not ERROR_* */ if (!halted(target, "ready")) return 0; do { target_read_u32(target, info->aemif + NANDFSR, &nandfsr); if (nandfsr & 0x01) return 1; alive_sleep(1); } while (timeout-- > 0); return 0; } static int davinci_command(struct nand_device *nand, uint8_t command) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; if (!halted(target, "command")) return ERROR_NAND_OPERATION_FAILED; target_write_u8(target, info->cmd, command); return ERROR_OK; } static int davinci_address(struct nand_device *nand, uint8_t address) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; if (!halted(target, "address")) return ERROR_NAND_OPERATION_FAILED; target_write_u8(target, info->addr, address); return ERROR_OK; } static int davinci_write_data(struct nand_device *nand, uint16_t data) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; if (!halted(target, "write_data")) return ERROR_NAND_OPERATION_FAILED; target_write_u8(target, info->data, data); return ERROR_OK; } static int davinci_read_data(struct nand_device *nand, void *data) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; if (!halted(target, "read_data")) return ERROR_NAND_OPERATION_FAILED; target_read_u8(target, info->data, data); return ERROR_OK; } /* REVISIT a bit of native code should let block reads be MUCH faster */ static int davinci_read_block_data(struct nand_device *nand, uint8_t *data, int data_size) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; uint32_t nfdata = info->data; uint32_t tmp; if (!halted(target, "read_block")) return ERROR_NAND_OPERATION_FAILED; while (data_size >= 4) { target_read_u32(target, nfdata, &tmp); data[0] = tmp; data[1] = tmp >> 8; data[2] = tmp >> 16; data[3] = tmp >> 24; data_size -= 4; data += 4; } while (data_size > 0) { target_read_u8(target, nfdata, data); data_size -= 1; data += 1; } return ERROR_OK; } static int davinci_write_block_data(struct nand_device *nand, uint8_t *data, int data_size) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; uint32_t nfdata = info->data; uint32_t tmp; int status; if (!halted(target, "write_block")) return ERROR_NAND_OPERATION_FAILED; /* try the fast way first */ status = arm_nandwrite(&info->io, data, data_size); if (status != ERROR_NAND_NO_BUFFER) return status; /* else do it slowly */ while (data_size >= 4) { tmp = le_to_h_u32(data); target_write_u32(target, nfdata, tmp); data_size -= 4; data += 4; } while (data_size > 0) { target_write_u8(target, nfdata, *data); data_size -= 1; data += 1; } return ERROR_OK; } static int davinci_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct davinci_nand *info = nand->controller_priv; uint8_t *ooballoc = NULL; int status; if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; if (!halted(nand->target, "write_page")) return ERROR_NAND_OPERATION_FAILED; /* Always write both data and OOB ... we are not "raw" I/O! */ if (!data) { LOG_ERROR("Missing NAND data; try 'nand raw_access enable'"); return ERROR_NAND_OPERATION_FAILED; } /* If we're not given OOB, write 0xff where we don't write ECC codes. */ switch (nand->page_size) { case 512: oob_size = 16; break; case 2048: oob_size = 64; break; case 4096: oob_size = 128; break; default: return ERROR_NAND_OPERATION_FAILED; } if (!oob) { ooballoc = malloc(oob_size); if (!ooballoc) return ERROR_NAND_OPERATION_FAILED; oob = ooballoc; memset(oob, 0x0ff, oob_size); } /* REVISIT avoid wasting SRAM: unless nand->use_raw is set, * use 512 byte chunks. Read side support will often want * to include oob_size ... */ info->io.chunk_size = nand->page_size; status = info->write_page(nand, page, data, data_size, oob, oob_size); free(ooballoc); return status; } static int davinci_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct davinci_nand *info = nand->controller_priv; if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; if (!halted(nand->target, "read_page")) return ERROR_NAND_OPERATION_FAILED; return info->read_page(nand, page, data, data_size, oob, oob_size); } static void davinci_write_pagecmd(struct nand_device *nand, uint8_t cmd, uint32_t page) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; int page3 = nand->address_cycles - (nand->page_size == 512); /* write command ({page,otp}x{read,program} */ target_write_u8(target, info->cmd, cmd); /* column address (beginning-of-page) */ target_write_u8(target, info->addr, 0); if (nand->page_size > 512) target_write_u8(target, info->addr, 0); /* page address */ target_write_u8(target, info->addr, page); target_write_u8(target, info->addr, page >> 8); if (page3) target_write_u8(target, info->addr, page >> 16); if (page3 == 2) target_write_u8(target, info->addr, page >> 24); } static int davinci_seek_column(struct nand_device *nand, uint16_t column) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; /* Random read, we must have issued a page read already */ target_write_u8(target, info->cmd, NAND_CMD_RNDOUT); target_write_u8(target, info->addr, column); if (nand->page_size > 512) { target_write_u8(target, info->addr, column >> 8); target_write_u8(target, info->cmd, NAND_CMD_RNDOUTSTART); } if (!davinci_nand_ready(nand, 100)) return ERROR_NAND_OPERATION_TIMEOUT; return ERROR_OK; } static int davinci_writepage_tail(struct nand_device *nand, uint8_t *oob, uint32_t oob_size) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; uint8_t status; if (oob_size) davinci_write_block_data(nand, oob, oob_size); /* non-cachemode page program */ target_write_u8(target, info->cmd, NAND_CMD_PAGEPROG); if (!davinci_nand_ready(nand, 100)) return ERROR_NAND_OPERATION_TIMEOUT; if (nand_read_status(nand, &status) != ERROR_OK) { LOG_ERROR("couldn't read status"); return ERROR_NAND_OPERATION_FAILED; } if (status & NAND_STATUS_FAIL) { LOG_ERROR("write operation failed, status: 0x%02x", status); return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } /* * All DaVinci family chips support 1-bit ECC on a per-chipselect basis. */ static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { unsigned oob_offset; struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; const uint32_t fcr_addr = info->aemif + NANDFCR; const uint32_t ecc1_addr = info->aemif + NANDFECC + (4 * info->chipsel); uint32_t fcr, ecc1; /* Write contiguous ECC bytes starting at specified offset. * NOTE: Linux reserves twice as many bytes as we need; and * for 16-bit OOB, those extra bytes are discontiguous. */ switch (nand->page_size) { case 512: oob_offset = 0; break; case 2048: oob_offset = 40; break; default: oob_offset = 80; break; } davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page); /* scrub any old ECC state */ target_read_u32(target, ecc1_addr, &ecc1); target_read_u32(target, fcr_addr, &fcr); fcr |= 1 << (8 + info->chipsel); do { /* set "start csX 1bit ecc" bit */ target_write_u32(target, fcr_addr, fcr); /* write 512 bytes */ davinci_write_block_data(nand, data, 512); data += 512; data_size -= 512; /* read the ecc, pack to 3 bytes, and invert so the ecc * in an erased block is correct */ target_read_u32(target, ecc1_addr, &ecc1); ecc1 = (ecc1 & 0x0fff) | ((ecc1 & 0x0fff0000) >> 4); ecc1 = ~ecc1; /* save correct ECC code into oob data */ oob[oob_offset++] = (uint8_t)(ecc1); oob[oob_offset++] = (uint8_t)(ecc1 >> 8); oob[oob_offset++] = (uint8_t)(ecc1 >> 16); } while (data_size); /* write OOB into spare area */ return davinci_writepage_tail(nand, oob, oob_size); } /* * Preferred "new style" ECC layout for use with 4-bit ECC. This somewhat * slows down large page reads done with error correction (since the OOB * is read first, so its ECC data can be used incrementally), but the * manufacturer bad block markers are safe. Contrast: old "infix" style. */ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { static const uint8_t ecc512[] = { 0, 1, 2, 3, 4, /* 5== mfr badblock */ 6, 7, /* 8..12 for BBT or JFFS2 */ 13, 14, 15, }; static const uint8_t ecc2048[] = { 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, }; static const uint8_t ecc4096[] = { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, }; struct davinci_nand *info = nand->controller_priv; const uint8_t *l; struct target *target = nand->target; const uint32_t fcr_addr = info->aemif + NANDFCR; const uint32_t ecc4_addr = info->aemif + NAND4BITECC; uint32_t fcr, ecc4; /* Use the same ECC layout Linux uses. For small page chips * it's a bit cramped. * * NOTE: at this writing, 4KB pages have issues in Linux * because they need more than 64 bytes of ECC data, which * the standard ECC logic can't handle. */ switch (nand->page_size) { case 512: l = ecc512; break; case 2048: l = ecc2048; break; default: l = ecc4096; break; } davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page); /* scrub any old ECC state */ target_read_u32(target, info->aemif + NANDERRVAL, &ecc4); target_read_u32(target, fcr_addr, &fcr); fcr &= ~(0x03 << 4); fcr |= (1 << 12) | (info->chipsel << 4); do { uint32_t raw_ecc[4], *p; int i; /* start 4bit ecc on csX */ target_write_u32(target, fcr_addr, fcr); /* write 512 bytes */ davinci_write_block_data(nand, data, 512); data += 512; data_size -= 512; /* read the ecc, then save it into 10 bytes in the oob */ for (i = 0; i < 4; i++) { target_read_u32(target, ecc4_addr + 4 * i, &raw_ecc[i]); raw_ecc[i] &= 0x03ff03ff; } for (i = 0, p = raw_ecc; i < 2; i++, p += 2) { oob[*l++] = p[0] & 0xff; oob[*l++] = ((p[0] >> 8) & 0x03) | ((p[0] >> 14) & 0xfc); oob[*l++] = ((p[0] >> 22) & 0x0f) | ((p[1] << 4) & 0xf0); oob[*l++] = ((p[1] >> 4) & 0x3f) | ((p[1] >> 10) & 0xc0); oob[*l++] = (p[1] >> 18) & 0xff; } } while (data_size); /* write OOB into spare area */ return davinci_writepage_tail(nand, oob, oob_size); } /* * "Infix" OOB ... like Linux ECC_HW_SYNDROME. Avoided because it trashes * manufacturer bad block markers, except on small page chips. Once you * write to a page using this scheme, you need specialized code to update * it (code which ignores now-invalid bad block markers). * * This is needed *only* to support older firmware. Older ROM Boot Loaders * need it to read their second stage loader (UBL) into SRAM, but from then * on the whole system can use the cleaner non-infix layouts. Systems with * older second stage loaders (ABL/U-Boot, etc) or other system software * (MVL 4.x/5.x kernels, filesystems, etc) may need it more generally. */ static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; const uint32_t fcr_addr = info->aemif + NANDFCR; const uint32_t ecc4_addr = info->aemif + NAND4BITECC; uint32_t fcr, ecc4; davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page); /* scrub any old ECC state */ target_read_u32(target, info->aemif + NANDERRVAL, &ecc4); target_read_u32(target, fcr_addr, &fcr); fcr &= ~(0x03 << 4); fcr |= (1 << 12) | (info->chipsel << 4); do { uint32_t raw_ecc[4], *p; uint8_t *l; int i; /* start 4bit ecc on csX */ target_write_u32(target, fcr_addr, fcr); /* write 512 bytes */ davinci_write_block_data(nand, data, 512); data += 512; data_size -= 512; /* read the ecc */ for (i = 0; i < 4; i++) { target_read_u32(target, ecc4_addr + 4 * i, &raw_ecc[i]); raw_ecc[i] &= 0x03ff03ff; } /* skip 6 bytes of prepad, then pack 10 packed ecc bytes */ for (i = 0, l = oob + 6, p = raw_ecc; i < 2; i++, p += 2) { *l++ = p[0] & 0xff; *l++ = ((p[0] >> 8) & 0x03) | ((p[0] >> 14) & 0xfc); *l++ = ((p[0] >> 22) & 0x0f) | ((p[1] << 4) & 0xf0); *l++ = ((p[1] >> 4) & 0x3f) | ((p[1] >> 10) & 0xc0); *l++ = (p[1] >> 18) & 0xff; } /* write this "out-of-band" data -- infix */ davinci_write_block_data(nand, oob, 16); oob += 16; } while (data_size); /* the last data and OOB writes included the spare area */ return davinci_writepage_tail(nand, NULL, 0); } static int davinci_read_page_ecc4infix(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { int read_size; int want_col, at_col; int ret; davinci_write_pagecmd(nand, NAND_CMD_READ0, page); /* large page devices need a start command */ if (nand->page_size > 512) davinci_command(nand, NAND_CMD_READSTART); if (!davinci_nand_ready(nand, 100)) return ERROR_NAND_OPERATION_TIMEOUT; /* NOTE: not bothering to compute and use ECC data for now */ want_col = 0; at_col = 0; while ((data && data_size) || (oob && oob_size)) { if (data && data_size) { if (want_col != at_col) { /* Reads are slow, so seek past them when we can */ ret = davinci_seek_column(nand, want_col); if (ret != ERROR_OK) return ret; at_col = want_col; } /* read 512 bytes or data_size, whichever is smaller*/ read_size = data_size > 512 ? 512 : data_size; davinci_read_block_data(nand, data, read_size); data += read_size; data_size -= read_size; at_col += read_size; } want_col += 512; if (oob && oob_size) { if (want_col != at_col) { ret = davinci_seek_column(nand, want_col); if (ret != ERROR_OK) return ret; at_col = want_col; } /* read this "out-of-band" data -- infix */ read_size = oob_size > 16 ? 16 : oob_size; davinci_read_block_data(nand, oob, read_size); oob += read_size; oob_size -= read_size; at_col += read_size; } want_col += 16; } return ERROR_OK; } NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command) { struct davinci_nand *info; unsigned long chip, aemif; enum ecc eccmode; int chipsel; /* arguments: * - "davinci" * - target * - nand chip address * - ecc mode * - aemif address * Plus someday, optionally, ALE and CLE masks. */ if (CMD_ARGC < 5) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip); if (chip == 0) { LOG_ERROR("Invalid NAND chip address %s", CMD_ARGV[2]); goto fail; } if (strcmp(CMD_ARGV[3], "hwecc1") == 0) eccmode = HWECC1; else if (strcmp(CMD_ARGV[3], "hwecc4") == 0) eccmode = HWECC4; else if (strcmp(CMD_ARGV[3], "hwecc4_infix") == 0) eccmode = HWECC4_INFIX; else { LOG_ERROR("Invalid ecc mode %s", CMD_ARGV[3]); goto fail; } COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[4], aemif); if (aemif == 0) { LOG_ERROR("Invalid AEMIF controller address %s", CMD_ARGV[4]); goto fail; } /* REVISIT what we'd *like* to do is look up valid ranges using * target-specific declarations, and not even need to pass the * AEMIF controller address. */ if (aemif == 0x01e00000 /* dm6446, dm357 */ || aemif == 0x01e10000 /* dm335, dm355 */ || aemif == 0x01d10000 /* dm365 */ ) { if (chip < 0x02000000 || chip >= 0x0a000000) { LOG_ERROR("NAND address %08lx out of range?", chip); goto fail; } chipsel = (chip - 0x02000000) >> 25; } else { LOG_ERROR("unrecognized AEMIF controller address %08lx", aemif); goto fail; } info = calloc(1, sizeof(*info)); if (!info) goto fail; info->eccmode = eccmode; info->chipsel = chipsel; info->aemif = aemif; info->data = chip; info->cmd = chip | 0x10; info->addr = chip | 0x08; nand->controller_priv = info; info->io.target = nand->target; info->io.data = info->data; info->io.op = ARM_NAND_NONE; /* NOTE: for now we don't do any error correction on read. * Nothing else in OpenOCD currently corrects read errors, * and in any case it's *writing* that we care most about. */ info->read_page = nand_read_page_raw; switch (eccmode) { case HWECC1: /* ECC_HW, 1-bit corrections, 3 bytes ECC per 512 data bytes */ info->write_page = davinci_write_page_ecc1; break; case HWECC4: /* ECC_HW, 4-bit corrections, 10 bytes ECC per 512 data bytes */ info->write_page = davinci_write_page_ecc4; break; case HWECC4_INFIX: /* Same 4-bit ECC HW, with problematic page/ecc layout */ info->read_page = davinci_read_page_ecc4infix; info->write_page = davinci_write_page_ecc4infix; break; } return ERROR_OK; fail: return ERROR_NAND_OPERATION_FAILED; } struct nand_flash_controller davinci_nand_controller = { .name = "davinci", .usage = "chip_addr hwecc_mode aemif_addr", .nand_device_command = davinci_nand_device_command, .init = davinci_init, .reset = davinci_reset, .command = davinci_command, .address = davinci_address, .write_data = davinci_write_data, .read_data = davinci_read_data, .write_page = davinci_write_page, .read_page = davinci_read_page, .write_block_data = davinci_write_block_data, .read_block_data = davinci_read_block_data, .nand_ready = davinci_nand_ready, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/driver.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include "core.h" #include "driver.h" static struct nand_flash_controller *nand_flash_controllers[] = { &nonce_nand_controller, &davinci_nand_controller, &lpc3180_nand_controller, &lpc32xx_nand_controller, &orion_nand_controller, &s3c2410_nand_controller, &s3c2412_nand_controller, &s3c2440_nand_controller, &s3c2443_nand_controller, &s3c6400_nand_controller, &mxc_nand_flash_controller, &imx31_nand_flash_controller, &at91sam9_nand_controller, &nuc910_nand_controller, NULL }; struct nand_flash_controller *nand_driver_find_by_name(const char *name) { for (unsigned i = 0; nand_flash_controllers[i]; i++) { struct nand_flash_controller *controller = nand_flash_controllers[i]; if (strcmp(name, controller->name) == 0) return controller; } return NULL; } int nand_driver_walk(nand_driver_walker_t f, void *x) { for (unsigned i = 0; nand_flash_controllers[i]; i++) { int retval = (*f)(nand_flash_controllers[i], x); if (retval != ERROR_OK) return retval; } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/driver.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_DRIVER_H #define OPENOCD_FLASH_NAND_DRIVER_H struct nand_device; #define __NAND_DEVICE_COMMAND(name) \ COMMAND_HELPER(name, struct nand_device *nand) /** * Interface for NAND flash controllers. Not all of these functions are * required for full functionality of the NAND driver, but better performance * can be achieved by implementing each function. */ struct nand_flash_controller { /** Driver name that is used to select it from configuration files. */ const char *name; /** Usage of flash command registration. */ const char *usage; const struct command_registration *commands; /** NAND device command called when driver is instantiated during configuration. */ __NAND_DEVICE_COMMAND((*nand_device_command)); /** Initialize the NAND device. */ int (*init)(struct nand_device *nand); /** Reset the NAND device. */ int (*reset)(struct nand_device *nand); /** Issue a command to the NAND device. */ int (*command)(struct nand_device *nand, uint8_t command); /** Write an address to the NAND device. */ int (*address)(struct nand_device *nand, uint8_t address); /** Write word of data to the NAND device. */ int (*write_data)(struct nand_device *nand, uint16_t data); /** Read word of data from the NAND device. */ int (*read_data)(struct nand_device *nand, void *data); /** Write a block of data to the NAND device. */ int (*write_block_data)(struct nand_device *nand, uint8_t *data, int size); /** Read a block of data from the NAND device. */ int (*read_block_data)(struct nand_device *nand, uint8_t *data, int size); /** Write a page to the NAND device. */ int (*write_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); /** Read a page from the NAND device. */ int (*read_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); /** Check if the NAND device is ready for more instructions with timeout. */ int (*nand_ready)(struct nand_device *nand, int timeout); }; #define NAND_DEVICE_COMMAND_HANDLER(name) static __NAND_DEVICE_COMMAND(name) /** * Find a NAND flash controller by name. * @param name Identifies the NAND controller to find. * @returns The nand_flash_controller named @c name, or NULL if not found. */ struct nand_flash_controller *nand_driver_find_by_name(const char *name); /** Signature for callback functions passed to nand_driver_walk */ typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void *); /** * Walk the list of drivers, encapsulating the data structure type. * Application state/context can be passed through the @c x pointer. * @param f The callback function to invoke for each function. * @param x For use as private data storage, passed directly to @c f. * @returns ERROR_OK if successful, or the non-zero return value of @c f. * This allows a walker to terminate the loop early. */ int nand_driver_walk(nand_driver_walker_t f, void *x); extern struct nand_flash_controller at91sam9_nand_controller; extern struct nand_flash_controller davinci_nand_controller; extern struct nand_flash_controller imx31_nand_flash_controller; extern struct nand_flash_controller lpc3180_nand_controller; extern struct nand_flash_controller lpc32xx_nand_controller; extern struct nand_flash_controller mxc_nand_flash_controller; extern struct nand_flash_controller nonce_nand_controller; extern struct nand_flash_controller nuc910_nand_controller; extern struct nand_flash_controller orion_nand_controller; extern struct nand_flash_controller s3c2410_nand_controller; extern struct nand_flash_controller s3c2412_nand_controller; extern struct nand_flash_controller s3c2440_nand_controller; extern struct nand_flash_controller s3c2443_nand_controller; extern struct nand_flash_controller s3c6400_nand_controller; #endif /* OPENOCD_FLASH_NAND_DRIVER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/ecc.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later WITH eCos-exception-2.0 /* * This file contains an ECC algorithm from Toshiba that allows for detection * and correction of 1-bit errors in a 256 byte block of data. * * [ Extracted from the initial code found in some early Linux versions. * The current Linux code is bigger while being faster, but this is of * no real benefit when the bottleneck largely remains the JTAG link. ] * * Copyright (C) 2000-2004 Steven J. Hill (sjhill at realitydiluted.com) * Toshiba America Electronics Components, Inc. * * Copyright (C) 2006 Thomas Gleixner <tglx at linutronix.de> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "core.h" /* * Pre-calculated 256-way 1 byte column parity */ static const uint8_t nand_ecc_precalc_table[] = { 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 }; /* * nand_calculate_ecc - Calculate 3-byte ECC for 256-byte block */ int nand_calculate_ecc(struct nand_device *nand, const uint8_t *dat, uint8_t *ecc_code) { uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; int i; /* Initialize variables */ reg1 = reg2 = reg3 = 0; /* Build up column parity */ for (i = 0; i < 256; i++) { /* Get CP0 - CP5 from table */ idx = nand_ecc_precalc_table[*dat++]; reg1 ^= (idx & 0x3f); /* All bit XOR = 1 ? */ if (idx & 0x40) { reg3 ^= (uint8_t) i; reg2 ^= ~((uint8_t) i); } } /* Create non-inverted ECC code from line parity */ tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ /* Calculate final ECC code */ #ifdef NAND_ECC_SMC ecc_code[0] = ~tmp2; ecc_code[1] = ~tmp1; #else ecc_code[0] = ~tmp1; ecc_code[1] = ~tmp2; #endif ecc_code[2] = ((~reg1) << 2) | 0x03; return 0; } static inline int countbits(uint32_t b) { int res = 0; for (; b; b >>= 1) res += b & 0x01; return res; } /** * nand_correct_data - Detect and correct a 1 bit error for 256 byte block */ int nand_correct_data(struct nand_device *nand, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { uint8_t s0, s1, s2; #ifdef NAND_ECC_SMC s0 = calc_ecc[0] ^ read_ecc[0]; s1 = calc_ecc[1] ^ read_ecc[1]; s2 = calc_ecc[2] ^ read_ecc[2]; #else s1 = calc_ecc[0] ^ read_ecc[0]; s0 = calc_ecc[1] ^ read_ecc[1]; s2 = calc_ecc[2] ^ read_ecc[2]; #endif if ((s0 | s1 | s2) == 0) return 0; /* Check for a single bit error */ if (((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { uint32_t byteoffs, bitnum; byteoffs = (s1 << 0) & 0x80; byteoffs |= (s1 << 1) & 0x40; byteoffs |= (s1 << 2) & 0x20; byteoffs |= (s1 << 3) & 0x10; byteoffs |= (s0 >> 4) & 0x08; byteoffs |= (s0 >> 3) & 0x04; byteoffs |= (s0 >> 2) & 0x02; byteoffs |= (s0 >> 1) & 0x01; bitnum = (s2 >> 5) & 0x04; bitnum |= (s2 >> 4) & 0x02; bitnum |= (s2 >> 3) & 0x01; dat[byteoffs] ^= (1 << bitnum); return 1; } if (countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 << 16)) == 1) return 1; return -1; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/ecc_kw.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Reed-Solomon ECC handling for the Marvell Kirkwood SOC * Copyright (C) 2009 Marvell Semiconductor, Inc. * * Authors: Lennert Buytenhek <buytenh@wantstofly.org> * Nicolas Pitre <nico@fluxnic.net> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "core.h" /***************************************************************************** * Arithmetic in GF(2^10) ("F") modulo x^10 + x^3 + 1. * * For multiplication, a discrete log/exponent table is used, with * primitive element x (F is a primitive field, so x is primitive). */ #define MODPOLY 0x409 /* x^10 + x^3 + 1 in binary */ /* * Maps an integer a [0..1022] to a polynomial b = gf_exp[a] in * GF(2^10) mod x^10 + x^3 + 1 such that b = x ^ a. There's two * identical copies of this array back-to-back so that we can save * the mod 1023 operation when doing a GF multiplication. */ static uint16_t gf_exp[1023 + 1023]; /* * Maps a polynomial b in GF(2^10) mod x^10 + x^3 + 1 to an index * a = gf_log[b] in [0..1022] such that b = x ^ a. */ static uint16_t gf_log[1024]; static void gf_build_log_exp_table(void) { int i; int p_i; /* * p_i = x ^ i * * Initialise to 1 for i = 0. */ p_i = 1; for (i = 0; i < 1023; i++) { gf_exp[i] = p_i; gf_exp[i + 1023] = p_i; gf_log[p_i] = i; /* * p_i = p_i * x */ p_i <<= 1; if (p_i & (1 << 10)) p_i ^= MODPOLY; } } /***************************************************************************** * Reed-Solomon code * * This implements a (1023,1015) Reed-Solomon ECC code over GF(2^10) * mod x^10 + x^3 + 1, shortened to (520,512). The ECC data consists * of 8 10-bit symbols, or 10 8-bit bytes. * * Given 512 bytes of data, computes 10 bytes of ECC. * * This is done by converting the 512 bytes to 512 10-bit symbols * (elements of F), interpreting those symbols as a polynomial in F[X] * by taking symbol 0 as the coefficient of X^8 and symbol 511 as the * coefficient of X^519, and calculating the residue of that polynomial * divided by the generator polynomial, which gives us the 8 ECC symbols * as the remainder. Finally, we convert the 8 10-bit ECC symbols to 10 * 8-bit bytes. * * The generator polynomial is hardcoded, as that is faster, but it * can be computed by taking the primitive element a = x (in F), and * constructing a polynomial in F[X] with roots a, a^2, a^3, ..., a^8 * by multiplying the minimal polynomials for those roots (which are * just 'x - a^i' for each i). * * Note: due to unfortunate circumstances, the bootrom in the Kirkwood SOC * expects the ECC to be computed backward, i.e. from the last byte down * to the first one. */ int nand_calculate_ecc_kw(struct nand_device *nand, const uint8_t *data, uint8_t *ecc) { unsigned int r7, r6, r5, r4, r3, r2, r1, r0; int i; static int tables_initialized; if (!tables_initialized) { gf_build_log_exp_table(); tables_initialized = 1; } /* * Load bytes 504..511 of the data into r. */ r0 = data[504]; r1 = data[505]; r2 = data[506]; r3 = data[507]; r4 = data[508]; r5 = data[509]; r6 = data[510]; r7 = data[511]; /* * Shift bytes 503..0 (in that order) into r0, followed * by eight zero bytes, while reducing the polynomial by the * generator polynomial in every step. */ for (i = 503; i >= -8; i--) { unsigned int d; d = 0; if (i >= 0) d = data[i]; if (r7) { uint16_t *t = gf_exp + gf_log[r7]; r7 = r6 ^ t[0x21c]; r6 = r5 ^ t[0x181]; r5 = r4 ^ t[0x18e]; r4 = r3 ^ t[0x25f]; r3 = r2 ^ t[0x197]; r2 = r1 ^ t[0x193]; r1 = r0 ^ t[0x237]; r0 = d ^ t[0x024]; } else { r7 = r6; r6 = r5; r5 = r4; r4 = r3; r3 = r2; r2 = r1; r1 = r0; r0 = d; } } ecc[0] = r0; ecc[1] = (r0 >> 8) | (r1 << 2); ecc[2] = (r1 >> 6) | (r2 << 4); ecc[3] = (r2 >> 4) | (r3 << 6); ecc[4] = (r3 >> 2); ecc[5] = r4; ecc[6] = (r4 >> 8) | (r5 << 2); ecc[7] = (r5 >> 6) | (r6 << 4); ecc[8] = (r6 >> 4) | (r7 << 6); ecc[9] = (r7 >> 2); return 0; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/fileio.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * * * Partially based on drivers/mtd/nand_ids.c from Linux. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "core.h" #include "fileio.h" static struct nand_ecclayout nand_oob_16 = { .eccbytes = 6, .eccpos = {0, 1, 2, 3, 6, 7}, .oobfree = { {.offset = 8, .length = 8} } }; static struct nand_ecclayout nand_oob_64 = { .eccbytes = 24, .eccpos = { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 }, .oobfree = { {.offset = 2, .length = 38} } }; void nand_fileio_init(struct nand_fileio_state *state) { memset(state, 0, sizeof(*state)); state->oob_format = NAND_OOB_NONE; } int nand_fileio_start(struct command_invocation *cmd, struct nand_device *nand, const char *filename, int filemode, struct nand_fileio_state *state) { if (state->address % nand->page_size) { command_print(cmd, "only page-aligned addresses are supported"); return ERROR_COMMAND_SYNTAX_ERROR; } duration_start(&state->bench); if (filename) { int retval = fileio_open(&state->fileio, filename, filemode, FILEIO_BINARY); if (retval != ERROR_OK) { const char *msg = (filemode == FILEIO_READ) ? "read" : "write"; command_print(cmd, "failed to open '%s' for %s access", filename, msg); return retval; } state->file_opened = true; } if (!(state->oob_format & NAND_OOB_ONLY)) { state->page_size = nand->page_size; state->page = malloc(nand->page_size); } if (state->oob_format & (NAND_OOB_RAW | NAND_OOB_SW_ECC | NAND_OOB_SW_ECC_KW)) { if (nand->page_size == 512) { state->oob_size = 16; state->eccpos = nand_oob_16.eccpos; } else if (nand->page_size == 2048) { state->oob_size = 64; state->eccpos = nand_oob_64.eccpos; } state->oob = malloc(state->oob_size); } return ERROR_OK; } int nand_fileio_cleanup(struct nand_fileio_state *state) { if (state->file_opened) fileio_close(state->fileio); free(state->oob); state->oob = NULL; free(state->page); state->page = NULL; return ERROR_OK; } int nand_fileio_finish(struct nand_fileio_state *state) { nand_fileio_cleanup(state); return duration_measure(&state->bench); } COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state, struct nand_device **dev, enum fileio_access filemode, bool need_size, bool sw_ecc) { nand_fileio_init(state); unsigned minargs = need_size ? 4 : 3; if (minargs > CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; struct nand_device *nand; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &nand); if (retval != ERROR_OK) return retval; if (!nand->device) { command_print(CMD, "#%s: not probed", CMD_ARGV[0]); return ERROR_NAND_DEVICE_NOT_PROBED; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], state->address); if (need_size) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], state->size); if (state->size % nand->page_size) { command_print(CMD, "only page-aligned sizes are supported"); return ERROR_COMMAND_SYNTAX_ERROR; } } if (minargs < CMD_ARGC) { for (unsigned i = minargs; i < CMD_ARGC; i++) { if (!strcmp(CMD_ARGV[i], "oob_raw")) state->oob_format |= NAND_OOB_RAW; else if (!strcmp(CMD_ARGV[i], "oob_only")) state->oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY; else if (sw_ecc && !strcmp(CMD_ARGV[i], "oob_softecc")) state->oob_format |= NAND_OOB_SW_ECC; else if (sw_ecc && !strcmp(CMD_ARGV[i], "oob_softecc_kw")) state->oob_format |= NAND_OOB_SW_ECC_KW; else { command_print(CMD, "unknown option: %s", CMD_ARGV[i]); return ERROR_COMMAND_SYNTAX_ERROR; } } } retval = nand_fileio_start(CMD, nand, CMD_ARGV[1], filemode, state); if (retval != ERROR_OK) return retval; if (!need_size) { size_t filesize; retval = fileio_size(state->fileio, &filesize); if (retval != ERROR_OK) return retval; state->size = filesize; } *dev = nand; return ERROR_OK; } /** * @returns If no error occurred, returns number of bytes consumed; * otherwise, returns a negative error code.) */ int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s) { size_t total_read = 0; size_t one_read; if (s->page) { fileio_read(s->fileio, s->page_size, s->page, &one_read); if (one_read < s->page_size) memset(s->page + one_read, 0xff, s->page_size - one_read); total_read += one_read; } if (s->oob_format & NAND_OOB_SW_ECC) { uint8_t ecc[3]; memset(s->oob, 0xff, s->oob_size); for (uint32_t i = 0, j = 0; i < s->page_size; i += 256) { nand_calculate_ecc(nand, s->page + i, ecc); s->oob[s->eccpos[j++]] = ecc[0]; s->oob[s->eccpos[j++]] = ecc[1]; s->oob[s->eccpos[j++]] = ecc[2]; } } else if (s->oob_format & NAND_OOB_SW_ECC_KW) { /* * In this case eccpos is not used as * the ECC data is always stored contiguously * at the end of the OOB area. It consists * of 10 bytes per 512-byte data block. */ uint8_t *ecc = s->oob + s->oob_size - s->page_size / 512 * 10; memset(s->oob, 0xff, s->oob_size); for (uint32_t i = 0; i < s->page_size; i += 512) { nand_calculate_ecc_kw(nand, s->page + i, ecc); ecc += 10; } } else if (s->oob) { fileio_read(s->fileio, s->oob_size, s->oob, &one_read); if (one_read < s->oob_size) memset(s->oob + one_read, 0xff, s->oob_size - one_read); total_read += one_read; } return total_read; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/fileio.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_FILEIO_H #define OPENOCD_FLASH_NAND_FILEIO_H #include <helper/time_support.h> #include <helper/fileio.h> struct nand_fileio_state { uint32_t address; uint32_t size; uint8_t *page; uint32_t page_size; enum oob_formats oob_format; uint8_t *oob; uint32_t oob_size; const int *eccpos; bool file_opened; struct fileio *fileio; struct duration bench; }; void nand_fileio_init(struct nand_fileio_state *state); int nand_fileio_start(struct command_invocation *cmd, struct nand_device *nand, const char *filename, int filemode, struct nand_fileio_state *state); int nand_fileio_cleanup(struct nand_fileio_state *state); int nand_fileio_finish(struct nand_fileio_state *state); COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state, struct nand_device **dev, enum fileio_access filemode, bool need_size, bool sw_ecc); int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s); #endif /* OPENOCD_FLASH_NAND_FILEIO_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/imp.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_IMP_H #define OPENOCD_FLASH_NAND_IMP_H #include "core.h" #include "driver.h" void nand_device_add(struct nand_device *c); int nand_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); int nand_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); int nand_probe(struct nand_device *nand); int nand_erase(struct nand_device *nand, int first_block, int last_block); int nand_build_bbt(struct nand_device *nand, int first, int last); #endif /* OPENOCD_FLASH_NAND_IMP_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/lpc3180.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * Copyright (C) 2010 richard vegh <vegh.ricsi@gmail.com> * * Copyright (C) 2010 Oyvind Harboe <oyvind.harboe@zylin.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "lpc3180.h" #include <target/target.h> static int lpc3180_reset(struct nand_device *nand); static int lpc3180_controller_ready(struct nand_device *nand, int timeout); static int lpc3180_tc_ready(struct nand_device *nand, int timeout); #define ECC_OFFS 0x120 #define SPARE_OFFS 0x140 #define DATA_OFFS 0x200 /* nand device lpc3180 <target#> <oscillator_frequency> */ NAND_DEVICE_COMMAND_HANDLER(lpc3180_nand_device_command) { if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t osc_freq; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], osc_freq); struct lpc3180_nand_controller *lpc3180_info; lpc3180_info = malloc(sizeof(struct lpc3180_nand_controller)); nand->controller_priv = lpc3180_info; lpc3180_info->osc_freq = osc_freq; if ((lpc3180_info->osc_freq < 1000) || (lpc3180_info->osc_freq > 20000)) LOG_WARNING( "LPC3180 oscillator frequency should be between 1000 and 20000 kHz, was %i", lpc3180_info->osc_freq); lpc3180_info->selected_controller = LPC3180_NO_CONTROLLER; lpc3180_info->sw_write_protection = 0; lpc3180_info->sw_wp_lower_bound = 0x0; lpc3180_info->sw_wp_upper_bound = 0x0; return ERROR_OK; } static int lpc3180_pll(int fclkin, uint32_t pll_ctrl) { int bypass = (pll_ctrl & 0x8000) >> 15; int direct = (pll_ctrl & 0x4000) >> 14; int feedback = (pll_ctrl & 0x2000) >> 13; int p = (1 << ((pll_ctrl & 0x1800) >> 11) * 2); int n = ((pll_ctrl & 0x0600) >> 9) + 1; int m = ((pll_ctrl & 0x01fe) >> 1) + 1; int lock = (pll_ctrl & 0x1); if (!lock) LOG_WARNING("PLL is not locked"); if (!bypass && direct) /* direct mode */ return (m * fclkin) / n; if (bypass && !direct) /* bypass mode */ return fclkin / (2 * p); if (bypass & direct) /* direct bypass mode */ return fclkin; if (feedback) /* integer mode */ return m * (fclkin / n); else /* non-integer mode */ return (m / (2 * p)) * (fclkin / n); } static float lpc3180_cycle_time(struct nand_device *nand) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; uint32_t sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl; int sysclk; int hclk; int hclk_pll; float cycle; /* calculate timings */ /* determine current SYSCLK (13'MHz or main oscillator) */ target_read_u32(target, 0x40004050, &sysclk_ctrl); if ((sysclk_ctrl & 1) == 0) sysclk = lpc3180_info->osc_freq; else sysclk = 13000; /* determine selected HCLK source */ target_read_u32(target, 0x40004044, &pwr_ctrl); if ((pwr_ctrl & (1 << 2)) == 0) /* DIRECT RUN mode */ hclk = sysclk; else { target_read_u32(target, 0x40004058, &hclkpll_ctrl); hclk_pll = lpc3180_pll(sysclk, hclkpll_ctrl); target_read_u32(target, 0x40004040, &hclkdiv_ctrl); if (pwr_ctrl & (1 << 10)) /* ARM_CLK and HCLK use PERIPH_CLK */ hclk = hclk_pll / (((hclkdiv_ctrl & 0x7c) >> 2) + 1); else /* HCLK uses HCLK_PLL */ hclk = hclk_pll / (1 << (hclkdiv_ctrl & 0x3)); } LOG_DEBUG("LPC3180 HCLK currently clocked at %i kHz", hclk); cycle = (1.0 / hclk) * 1000000.0; return cycle; } static int lpc3180_init(struct nand_device *nand) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; int bus_width = nand->bus_width ? nand->bus_width : 8; int address_cycles = nand->address_cycles ? nand->address_cycles : 3; int page_size = nand->page_size ? nand->page_size : 512; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } /* sanitize arguments */ if ((bus_width != 8) && (bus_width != 16)) { LOG_ERROR("LPC3180 only supports 8 or 16 bit bus width, not %i", bus_width); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } /* The LPC3180 only brings out 8 bit NAND data bus, but the controller * would support 16 bit, too, so we just warn about this for now */ if (bus_width == 16) LOG_WARNING("LPC3180 only supports 8 bit bus width"); /* inform calling code about selected bus width */ nand->bus_width = bus_width; if ((address_cycles != 3) && (address_cycles != 4)) { LOG_ERROR("LPC3180 only supports 3 or 4 address cycles, not %i", address_cycles); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } if ((page_size != 512) && (page_size != 2048)) { LOG_ERROR("LPC3180 only supports 512 or 2048 byte pages, not %i", page_size); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } /* select MLC controller if none is currently selected */ if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_DEBUG("no LPC3180 NAND flash controller selected, using default 'mlc'"); lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER; } if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { uint32_t mlc_icr_value = 0x0; float cycle; int twp, twh, trp, treh, trhz, trbwb, tcea; /* FLASHCLK_CTRL = 0x22 (enable clock for MLC flash controller) */ target_write_u32(target, 0x400040c8, 0x22); /* MLC_CEH = 0x0 (Force nCE assert) */ target_write_u32(target, 0x200b804c, 0x0); /* MLC_LOCK = 0xa25e (unlock protected registers) */ target_write_u32(target, 0x200b8044, 0xa25e); /* MLC_ICR = configuration */ if (lpc3180_info->sw_write_protection) mlc_icr_value |= 0x8; if (page_size == 2048) mlc_icr_value |= 0x4; if (address_cycles == 4) mlc_icr_value |= 0x2; if (bus_width == 16) mlc_icr_value |= 0x1; target_write_u32(target, 0x200b8030, mlc_icr_value); /* calculate NAND controller timings */ cycle = lpc3180_cycle_time(nand); twp = ((40 / cycle) + 1); twh = ((20 / cycle) + 1); trp = ((30 / cycle) + 1); treh = ((15 / cycle) + 1); trhz = ((30 / cycle) + 1); trbwb = ((100 / cycle) + 1); tcea = ((45 / cycle) + 1); /* MLC_LOCK = 0xa25e (unlock protected registers) */ target_write_u32(target, 0x200b8044, 0xa25e); /* MLC_TIME_REG */ target_write_u32(target, 0x200b8034, (twp & 0xf) | ((twh & 0xf) << 4) | ((trp & 0xf) << 8) | ((treh & 0xf) << 12) | ((trhz & 0x7) << 16) | ((trbwb & 0x1f) << 19) | ((tcea & 0x3) << 24)); lpc3180_reset(nand); } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { float cycle; int r_setup, r_hold, r_width, r_rdy; int w_setup, w_hold, w_width, w_rdy; /* FLASHCLK_CTRL = 0x05 (enable clock for SLC flash controller) */ target_write_u32(target, 0x400040c8, 0x05); /* after reset set other registers of SLC so reset calling is here at the beginning */ lpc3180_reset(nand); /* SLC_CFG = 0x (Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst enabled, *DMA read from SLC, WIDTH = bus_width) */ target_write_u32(target, 0x20020014, 0x3e | ((bus_width == 16) ? 1 : 0)); /* SLC_IEN = 3 (INT_RDY_EN = 1) ,(INT_TC_STAT = 1) */ target_write_u32(target, 0x20020020, 0x03); /* DMA configuration * DMACLK_CTRL = 0x01 (enable clock for DMA controller) */ target_write_u32(target, 0x400040e8, 0x01); /* DMACConfig = DMA enabled*/ target_write_u32(target, 0x31000030, 0x01); /* calculate NAND controller timings */ cycle = lpc3180_cycle_time(nand); r_setup = w_setup = 0; r_hold = w_hold = 10 / cycle; r_width = 30 / cycle; w_width = 40 / cycle; r_rdy = w_rdy = 100 / cycle; /* SLC_TAC: SLC timing arcs register */ target_write_u32(target, 0x2002002c, (r_setup & 0xf) | ((r_hold & 0xf) << 4) | ((r_width & 0xf) << 8) | ((r_rdy & 0xf) << 12) | ((w_setup & 0xf) << 16) | ((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28)); } return ERROR_OK; } static int lpc3180_reset(struct nand_device *nand) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { /* MLC_CMD = 0xff (reset controller and NAND device) */ target_write_u32(target, 0x200b8000, 0xff); if (!lpc3180_controller_ready(nand, 100)) { LOG_ERROR("LPC3180 NAND controller timed out after reset"); return ERROR_NAND_OPERATION_TIMEOUT; } } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { /* SLC_CTRL = 0x6 (ECC_CLEAR, SW_RESET) */ target_write_u32(target, 0x20020010, 0x6); if (!lpc3180_controller_ready(nand, 100)) { LOG_ERROR("LPC3180 NAND controller timed out after reset"); return ERROR_NAND_OPERATION_TIMEOUT; } } return ERROR_OK; } static int lpc3180_command(struct nand_device *nand, uint8_t command) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { /* MLC_CMD = command */ target_write_u32(target, 0x200b8000, command); } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { /* SLC_CMD = command */ target_write_u32(target, 0x20020008, command); } return ERROR_OK; } static int lpc3180_address(struct nand_device *nand, uint8_t address) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { /* MLC_ADDR = address */ target_write_u32(target, 0x200b8004, address); } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { /* SLC_ADDR = address */ target_write_u32(target, 0x20020004, address); } return ERROR_OK; } static int lpc3180_write_data(struct nand_device *nand, uint16_t data) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { /* MLC_DATA = data */ target_write_u32(target, 0x200b0000, data); } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { /* SLC_DATA = data */ target_write_u32(target, 0x20020000, data); } return ERROR_OK; } static int lpc3180_read_data(struct nand_device *nand, void *data) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { /* data = MLC_DATA, use sized access */ if (nand->bus_width == 8) { uint8_t *data8 = data; target_read_u8(target, 0x200b0000, data8); } else if (nand->bus_width == 16) { uint16_t *data16 = data; target_read_u16(target, 0x200b0000, data16); } else { LOG_ERROR("BUG: bus_width neither 8 nor 16 bit"); return ERROR_NAND_OPERATION_FAILED; } } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { uint32_t data32; /* data = SLC_DATA, must use 32-bit access */ target_read_u32(target, 0x20020000, &data32); if (nand->bus_width == 8) { uint8_t *data8 = data; *data8 = data32 & 0xff; } else if (nand->bus_width == 16) { uint16_t *data16 = data; *data16 = data32 & 0xffff; } else { LOG_ERROR("BUG: bus_width neither 8 nor 16 bit"); return ERROR_NAND_OPERATION_FAILED; } } return ERROR_OK; } static int lpc3180_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; int retval; uint8_t status; uint8_t *page_buffer; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { uint8_t *oob_buffer; int quarter, num_quarters; if (!data && oob) { LOG_ERROR("LPC3180 MLC controller can't write OOB data only"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } if (oob && (oob_size > 24)) { LOG_ERROR("LPC3180 MLC controller can't write more " "than 6 bytes for each quarter's OOB data"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } if (data_size > (uint32_t)nand->page_size) { LOG_ERROR("data size exceeds page size"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } /* MLC_CMD = sequential input */ target_write_u32(target, 0x200b8000, NAND_CMD_SEQIN); page_buffer = malloc(512); oob_buffer = malloc(6); if (nand->page_size == 512) { /* MLC_ADDR = 0x0 (one column cycle) */ target_write_u32(target, 0x200b8004, 0x0); /* MLC_ADDR = row */ target_write_u32(target, 0x200b8004, page & 0xff); target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); if (nand->address_cycles == 4) target_write_u32(target, 0x200b8004, (page >> 16) & 0xff); } else { /* MLC_ADDR = 0x0 (two column cycles) */ target_write_u32(target, 0x200b8004, 0x0); target_write_u32(target, 0x200b8004, 0x0); /* MLC_ADDR = row */ target_write_u32(target, 0x200b8004, page & 0xff); target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); } /* when using the MLC controller, we have to treat a large page device * as being made out of four quarters, each the size of a small page device */ num_quarters = (nand->page_size == 2048) ? 4 : 1; for (quarter = 0; quarter < num_quarters; quarter++) { int thisrun_data_size = (data_size > 512) ? 512 : data_size; int thisrun_oob_size = (oob_size > 6) ? 6 : oob_size; memset(page_buffer, 0xff, 512); if (data) { memcpy(page_buffer, data, thisrun_data_size); data_size -= thisrun_data_size; data += thisrun_data_size; } memset(oob_buffer, 0xff, 6); if (oob) { memcpy(oob_buffer, oob, thisrun_oob_size); oob_size -= thisrun_oob_size; oob += thisrun_oob_size; } /* write MLC_ECC_ENC_REG to start encode cycle */ target_write_u32(target, 0x200b8008, 0x0); target_write_memory(target, 0x200a8000, 4, 128, page_buffer); target_write_memory(target, 0x200a8000, 1, 6, oob_buffer); /* write MLC_ECC_AUTO_ENC_REG to start auto encode */ target_write_u32(target, 0x200b8010, 0x0); if (!lpc3180_controller_ready(nand, 1000)) { LOG_ERROR("timeout while waiting for completion of auto encode cycle"); free(page_buffer); free(oob_buffer); return ERROR_NAND_OPERATION_FAILED; } } /* MLC_CMD = auto program command */ target_write_u32(target, 0x200b8000, NAND_CMD_PAGEPROG); retval = nand_read_status(nand, &status); if (retval != ERROR_OK) { LOG_ERROR("couldn't read status"); free(page_buffer); free(oob_buffer); return ERROR_NAND_OPERATION_FAILED; } if (status & NAND_STATUS_FAIL) { LOG_ERROR("write operation didn't pass, status: 0x%2.2x", status); free(page_buffer); free(oob_buffer); return ERROR_NAND_OPERATION_FAILED; } free(page_buffer); free(oob_buffer); } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { /********************************************************************** * Write both SLC NAND flash page main area and spare area. * Small page - * ------------------------------------------ * | 512 bytes main | 16 bytes spare | * ------------------------------------------ * Large page - * ------------------------------------------ * | 2048 bytes main | 64 bytes spare | * ------------------------------------------ * If DMA & ECC enabled, then the ECC generated for the 1st 256-byte * data is written to the 3rd word of the spare area. The ECC * generated for the 2nd 256-byte data is written to the 4th word * of the spare area. The ECC generated for the 3rd 256-byte data is * written to the 7th word of the spare area. The ECC generated * for the 4th 256-byte data is written to the 8th word of the * spare area and so on. * **********************************************************************/ int i = 0, target_mem_base; uint8_t *ecc_flash_buffer; struct working_area *pworking_area; if (lpc3180_info->is_bulk) { if (!data && oob) { /*if oob only mode is active original method is used as SLC *controller hangs during DMA interworking. Anyway the code supports *the oob only mode below. */ return nand_write_page_raw(nand, page, data, data_size, oob, oob_size); } retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); if (retval != ERROR_OK) return retval; /* allocate a working area */ if (target->working_area_size < (uint32_t) nand->page_size + 0x200) { LOG_ERROR("Reserve at least 0x%x physical target working area", nand->page_size + 0x200); return ERROR_FLASH_OPERATION_FAILED; } if (target->working_area_phys%4) { LOG_ERROR( "Reserve the physical target working area at word boundary"); return ERROR_FLASH_OPERATION_FAILED; } if (target_alloc_working_area(target, target->working_area_size, &pworking_area) != ERROR_OK) { LOG_ERROR("no working area specified, can't read LPC internal flash"); return ERROR_FLASH_OPERATION_FAILED; } target_mem_base = target->working_area_phys; if (nand->page_size == 2048) page_buffer = malloc(2048); else page_buffer = malloc(512); ecc_flash_buffer = malloc(64); /* SLC_CFG = 0x (Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst *enabled, DMA write to SLC, WIDTH = bus_width) */ target_write_u32(target, 0x20020014, 0x3c); if (data && !oob) { /* set DMA LLI-s in target memory and in DMA*/ for (i = 0; i < nand->page_size/0x100; i++) { int tmp; /* -------LLI for 256 byte block--------- * DMACC0SrcAddr = SRAM */ target_write_u32(target, target_mem_base+0+i*32, target_mem_base+DATA_OFFS+i*256); if (i == 0) target_write_u32(target, 0x31000100, target_mem_base+DATA_OFFS); /* DMACCxDestAddr = SLC_DMA_DATA */ target_write_u32(target, target_mem_base+4+i*32, 0x20020038); if (i == 0) target_write_u32(target, 0x31000104, 0x20020038); /* DMACCxLLI = next element */ tmp = (target_mem_base+(1+i*2)*16)&0xfffffffc; target_write_u32(target, target_mem_base+8+i*32, tmp); if (i == 0) target_write_u32(target, 0x31000108, tmp); /* DMACCxControl = TransferSize =64, Source burst size =16, * Destination burst size = 16, Source transfer width = 32 bit, * Destination transfer width = 32 bit, Source AHB master select = M0, * Destination AHB master select = M0, Source increment = 1, * Destination increment = 0, Terminal count interrupt enable bit = 0*/ target_write_u32(target, target_mem_base+12+i*32, 0x40 | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27 | 0<<31); if (i == 0) target_write_u32(target, 0x3100010c, 0x40 | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27 | 0<<31); /* -------LLI for 3 byte ECC--------- * DMACC0SrcAddr = SLC_ECC*/ target_write_u32(target, target_mem_base+16+i*32, 0x20020034); /* DMACCxDestAddr = SRAM */ target_write_u32(target, target_mem_base+20+i*32, target_mem_base+SPARE_OFFS+8+16*(i>>1)+(i%2)*4); /* DMACCxLLI = next element */ tmp = (target_mem_base+(2+i*2)*16)&0xfffffffc; target_write_u32(target, target_mem_base+24+i*32, tmp); /* DMACCxControl = TransferSize =1, Source burst size =4, * Destination burst size = 4, Source transfer width = 32 bit, * Destination transfer width = 32 bit, Source AHB master select = M0, * Destination AHB master select = M0, Source increment = 0, * Destination increment = 1, Terminal count interrupt enable bit = 0*/ target_write_u32(target, target_mem_base+28+i*32, 0x01 | 1<<12 | 1<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27 | 0<< 31); } } else if (data && oob) { /* -------LLI for 512 or 2048 bytes page--------- * DMACC0SrcAddr = SRAM */ target_write_u32(target, target_mem_base, target_mem_base+DATA_OFFS); target_write_u32(target, 0x31000100, target_mem_base+DATA_OFFS); /* DMACCxDestAddr = SLC_DMA_DATA */ target_write_u32(target, target_mem_base+4, 0x20020038); target_write_u32(target, 0x31000104, 0x20020038); /* DMACCxLLI = next element */ target_write_u32(target, target_mem_base+8, (target_mem_base+32)&0xfffffffc); target_write_u32(target, 0x31000108, (target_mem_base+32)&0xfffffffc); /* DMACCxControl = TransferSize =512 or 128, Source burst size =16, * Destination burst size = 16, Source transfer width = 32 bit, * Destination transfer width = 32 bit, Source AHB master select = M0, * Destination AHB master select = M0, Source increment = 1, * Destination increment = 0, Terminal count interrupt enable bit = 0*/ target_write_u32(target, target_mem_base+12, (nand->page_size == 2048 ? 512 : 128) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27 | 0<<31); target_write_u32(target, 0x3100010c, (nand->page_size == 2048 ? 512 : 128) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27 | 0<<31); i = 1; } else if (!data && oob) i = 0; /* -------LLI for spare area--------- * DMACC0SrcAddr = SRAM*/ target_write_u32(target, target_mem_base+0+i*32, target_mem_base+SPARE_OFFS); if (i == 0) target_write_u32(target, 0x31000100, target_mem_base+SPARE_OFFS); /* DMACCxDestAddr = SLC_DMA_DATA */ target_write_u32(target, target_mem_base+4+i*32, 0x20020038); if (i == 0) target_write_u32(target, 0x31000104, 0x20020038); /* DMACCxLLI = next element = NULL */ target_write_u32(target, target_mem_base+8+i*32, 0); if (i == 0) target_write_u32(target, 0x31000108, 0); /* DMACCxControl = TransferSize =16 for large page or 4 for small page, * Source burst size =16, Destination burst size = 16, Source transfer width = 32 bit, * Destination transfer width = 32 bit, Source AHB master select = M0, * Destination AHB master select = M0, Source increment = 1, * Destination increment = 0, Terminal count interrupt enable bit = 0*/ target_write_u32(target, target_mem_base+12+i*32, (nand->page_size == 2048 ? 0x10 : 0x04) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27 | 0<<31); if (i == 0) target_write_u32(target, 0x3100010c, (nand->page_size == 2048 ? 0x10 : 0x04) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27 | 0<<31); memset(ecc_flash_buffer, 0xff, 64); if (oob) memcpy(ecc_flash_buffer, oob, oob_size); target_write_memory(target, target_mem_base+SPARE_OFFS, 4, 16, ecc_flash_buffer); if (data) { memset(page_buffer, 0xff, nand->page_size == 2048 ? 2048 : 512); memcpy(page_buffer, data, data_size); target_write_memory(target, target_mem_base+DATA_OFFS, 4, nand->page_size == 2048 ? 512 : 128, page_buffer); } free(page_buffer); free(ecc_flash_buffer); /* Enable DMA after channel set up ! LLI only works when DMA is the flow controller! */ /* DMACCxConfig= E=1, SrcPeripheral = 1 (SLC), DestPeripheral = 1 (SLC), *FlowCntrl = 2 (Pher -> Mem, DMA), IE = 0, ITC = 0, L= 0, H=0*/ target_write_u32(target, 0x31000110, 1 | 1<<1 | 1<<6 | 2<<11 | 0<<14 | 0<<15 | 0<<16 | 0<<18); /* SLC_CTRL = 3 (START DMA), ECC_CLEAR */ target_write_u32(target, 0x20020010, 0x3); /* SLC_ICR = 2, INT_TC_CLR, clear pending TC*/ target_write_u32(target, 0x20020028, 2); /* SLC_TC */ if (!data && oob) target_write_u32(target, 0x20020030, (nand->page_size == 2048 ? 0x10 : 0x04)); else target_write_u32(target, 0x20020030, (nand->page_size == 2048 ? 0x840 : 0x210)); nand_write_finish(nand); if (!lpc3180_tc_ready(nand, 1000)) { LOG_ERROR("timeout while waiting for completion of DMA"); return ERROR_NAND_OPERATION_FAILED; } target_free_working_area(target, pworking_area); LOG_INFO("Page = 0x%" PRIx32 " was written.", page); } else return nand_write_page_raw(nand, page, data, data_size, oob, oob_size); } return ERROR_OK; } static int lpc3180_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; uint8_t *page_buffer; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { uint8_t *oob_buffer; uint32_t page_bytes_done = 0; uint32_t oob_bytes_done = 0; uint32_t mlc_isr; #if 0 if (oob && (oob_size > 6)) { LOG_ERROR("LPC3180 MLC controller can't read more than 6 bytes of OOB data"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } #endif if (data_size > (uint32_t)nand->page_size) { LOG_ERROR("data size exceeds page size"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } if (nand->page_size == 2048) { page_buffer = malloc(2048); oob_buffer = malloc(64); } else { page_buffer = malloc(512); oob_buffer = malloc(16); } if (!data && oob) { /* MLC_CMD = Read OOB * we can use the READOOB command on both small and large page devices, * as the controller translates the 0x50 command to a 0x0 with appropriate * positioning of the serial buffer read pointer */ target_write_u32(target, 0x200b8000, NAND_CMD_READOOB); } else { /* MLC_CMD = Read0 */ target_write_u32(target, 0x200b8000, NAND_CMD_READ0); } if (nand->page_size == 512) { /* small page device * MLC_ADDR = 0x0 (one column cycle) */ target_write_u32(target, 0x200b8004, 0x0); /* MLC_ADDR = row */ target_write_u32(target, 0x200b8004, page & 0xff); target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); if (nand->address_cycles == 4) target_write_u32(target, 0x200b8004, (page >> 16) & 0xff); } else { /* large page device * MLC_ADDR = 0x0 (two column cycles) */ target_write_u32(target, 0x200b8004, 0x0); target_write_u32(target, 0x200b8004, 0x0); /* MLC_ADDR = row */ target_write_u32(target, 0x200b8004, page & 0xff); target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); /* MLC_CMD = Read Start */ target_write_u32(target, 0x200b8000, NAND_CMD_READSTART); } while (page_bytes_done < (uint32_t)nand->page_size) { /* MLC_ECC_AUTO_DEC_REG = dummy */ target_write_u32(target, 0x200b8014, 0xaa55aa55); if (!lpc3180_controller_ready(nand, 1000)) { LOG_ERROR("timeout while waiting for completion of auto decode cycle"); free(page_buffer); free(oob_buffer); return ERROR_NAND_OPERATION_FAILED; } target_read_u32(target, 0x200b8048, &mlc_isr); if (mlc_isr & 0x8) { if (mlc_isr & 0x40) { LOG_ERROR("uncorrectable error detected: 0x%2.2x", (unsigned)mlc_isr); free(page_buffer); free(oob_buffer); return ERROR_NAND_OPERATION_FAILED; } LOG_WARNING("%i symbol error detected and corrected", ((int)(((mlc_isr & 0x30) >> 4) + 1))); } if (data) target_read_memory(target, 0x200a8000, 4, 128, page_buffer + page_bytes_done); if (oob) target_read_memory(target, 0x200a8000, 4, 4, oob_buffer + oob_bytes_done); page_bytes_done += 512; oob_bytes_done += 16; } if (data) memcpy(data, page_buffer, data_size); if (oob) memcpy(oob, oob_buffer, oob_size); free(page_buffer); free(oob_buffer); } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { /********************************************************************** * Read both SLC NAND flash page main area and spare area. * Small page - * ------------------------------------------ * | 512 bytes main | 16 bytes spare | * ------------------------------------------ * Large page - * ------------------------------------------ * | 2048 bytes main | 64 bytes spare | * ------------------------------------------ * If DMA & ECC enabled, then the ECC generated for the 1st 256-byte * data is compared with the 3rd word of the spare area. The ECC * generated for the 2nd 256-byte data is compared with the 4th word * of the spare area. The ECC generated for the 3rd 256-byte data is * compared with the 7th word of the spare area. The ECC generated * for the 4th 256-byte data is compared with the 8th word of the * spare area and so on. * **********************************************************************/ int retval, i, target_mem_base; uint8_t *ecc_hw_buffer; uint8_t *ecc_flash_buffer; struct working_area *pworking_area; if (lpc3180_info->is_bulk) { /* read always the data and also oob areas*/ retval = nand_page_command(nand, page, NAND_CMD_READ0, 0); if (retval != ERROR_OK) return retval; /* allocate a working area */ if (target->working_area_size < (uint32_t) nand->page_size + 0x200) { LOG_ERROR("Reserve at least 0x%x physical target working area", nand->page_size + 0x200); return ERROR_FLASH_OPERATION_FAILED; } if (target->working_area_phys%4) { LOG_ERROR( "Reserve the physical target working area at word boundary"); return ERROR_FLASH_OPERATION_FAILED; } if (target_alloc_working_area(target, target->working_area_size, &pworking_area) != ERROR_OK) { LOG_ERROR("no working area specified, can't read LPC internal flash"); return ERROR_FLASH_OPERATION_FAILED; } target_mem_base = target->working_area_phys; if (nand->page_size == 2048) page_buffer = malloc(2048); else page_buffer = malloc(512); ecc_hw_buffer = malloc(32); ecc_flash_buffer = malloc(64); /* SLC_CFG = 0x (Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst *enabled, DMA read from SLC, WIDTH = bus_width) */ target_write_u32(target, 0x20020014, 0x3e); /* set DMA LLI-s in target memory and in DMA*/ for (i = 0; i < nand->page_size/0x100; i++) { int tmp; /* -------LLI for 256 byte block--------- * DMACC0SrcAddr = SLC_DMA_DATA*/ target_write_u32(target, target_mem_base+0+i*32, 0x20020038); if (i == 0) target_write_u32(target, 0x31000100, 0x20020038); /* DMACCxDestAddr = SRAM */ target_write_u32(target, target_mem_base+4+i*32, target_mem_base+DATA_OFFS+i*256); if (i == 0) target_write_u32(target, 0x31000104, target_mem_base+DATA_OFFS); /* DMACCxLLI = next element */ tmp = (target_mem_base+(1+i*2)*16)&0xfffffffc; target_write_u32(target, target_mem_base+8+i*32, tmp); if (i == 0) target_write_u32(target, 0x31000108, tmp); /* DMACCxControl = TransferSize =64, Source burst size =16, * Destination burst size = 16, Source transfer width = 32 bit, * Destination transfer width = 32 bit, Source AHB master select = M0, * Destination AHB master select = M0, Source increment = 0, * Destination increment = 1, Terminal count interrupt enable bit = 0*/ target_write_u32(target, target_mem_base+12+i*32, 0x40 | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27 | 0<< 31); if (i == 0) target_write_u32(target, 0x3100010c, 0x40 | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27 | 0<< 31); /* -------LLI for 3 byte ECC--------- * DMACC0SrcAddr = SLC_ECC*/ target_write_u32(target, target_mem_base+16+i*32, 0x20020034); /* DMACCxDestAddr = SRAM */ target_write_u32(target, target_mem_base+20+i*32, target_mem_base+ECC_OFFS+i*4); /* DMACCxLLI = next element */ tmp = (target_mem_base+(2+i*2)*16)&0xfffffffc; target_write_u32(target, target_mem_base+24+i*32, tmp); /* DMACCxControl = TransferSize =1, Source burst size =4, * Destination burst size = 4, Source transfer width = 32 bit, * Destination transfer width = 32 bit, Source AHB master select = M0, * Destination AHB master select = M0, Source increment = 0, * Destination increment = 1, Terminal count interrupt enable bit = 0*/ target_write_u32(target, target_mem_base+28+i*32, 0x01 | 1<<12 | 1<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27 | 0<< 31); } /* -------LLI for spare area--------- * DMACC0SrcAddr = SLC_DMA_DATA*/ target_write_u32(target, target_mem_base+0+i*32, 0x20020038); /* DMACCxDestAddr = SRAM */ target_write_u32(target, target_mem_base+4+i*32, target_mem_base+SPARE_OFFS); /* DMACCxLLI = next element = NULL */ target_write_u32(target, target_mem_base+8+i*32, 0); /* DMACCxControl = TransferSize =16 for large page or 4 for small page, * Source burst size =16, Destination burst size = 16, Source transfer width = 32 bit, * Destination transfer width = 32 bit, Source AHB master select = M0, * Destination AHB master select = M0, Source increment = 0, * Destination increment = 1, Terminal count interrupt enable bit = 0*/ target_write_u32(target, target_mem_base + 12 + i * 32, (nand->page_size == 2048 ? 0x10 : 0x04) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27 | 0<<31); /* Enable DMA after channel set up ! LLI only works when DMA is the flow controller! */ /* DMACCxConfig= E=1, SrcPeripheral = 1 (SLC), DestPeripheral = 1 (SLC), *FlowCntrl = 2 (Pher-> Mem, DMA), IE = 0, ITC = 0, L= 0, H=0*/ target_write_u32(target, 0x31000110, 1 | 1<<1 | 1<<6 | 2<<11 | 0<<14 | 0<<15 | 0<<16 | 0<<18); /* SLC_CTRL = 3 (START DMA), ECC_CLEAR */ target_write_u32(target, 0x20020010, 0x3); /* SLC_ICR = 2, INT_TC_CLR, clear pending TC*/ target_write_u32(target, 0x20020028, 2); /* SLC_TC */ target_write_u32(target, 0x20020030, (nand->page_size == 2048 ? 0x840 : 0x210)); if (!lpc3180_tc_ready(nand, 1000)) { LOG_ERROR("timeout while waiting for completion of DMA"); free(page_buffer); free(ecc_hw_buffer); free(ecc_flash_buffer); target_free_working_area(target, pworking_area); return ERROR_NAND_OPERATION_FAILED; } if (data) { target_read_memory(target, target_mem_base+DATA_OFFS, 4, nand->page_size == 2048 ? 512 : 128, page_buffer); memcpy(data, page_buffer, data_size); LOG_INFO("Page = 0x%" PRIx32 " was read.", page); /* check hw generated ECC for each 256 bytes block with the saved *ECC in flash spare area*/ int idx = nand->page_size/0x200; target_read_memory(target, target_mem_base+SPARE_OFFS, 4, 16, ecc_flash_buffer); target_read_memory(target, target_mem_base+ECC_OFFS, 4, 8, ecc_hw_buffer); for (i = 0; i < idx; i++) { if ((0x00ffffff & *(uint32_t *)(void *)(ecc_hw_buffer+i*8)) != (0x00ffffff & *(uint32_t *)(void *)(ecc_flash_buffer+8+i*16))) LOG_WARNING( "ECC mismatch at 256 bytes size block= %d at page= 0x%" PRIx32, i * 2 + 1, page); if ((0x00ffffff & *(uint32_t *)(void *)(ecc_hw_buffer+4+i*8)) != (0x00ffffff & *(uint32_t *)(void *)(ecc_flash_buffer+12+i*16))) LOG_WARNING( "ECC mismatch at 256 bytes size block= %d at page= 0x%" PRIx32, i * 2 + 2, page); } } if (oob) memcpy(oob, ecc_flash_buffer, oob_size); free(page_buffer); free(ecc_hw_buffer); free(ecc_flash_buffer); target_free_working_area(target, pworking_area); } else return nand_read_page_raw(nand, page, data, data_size, oob, oob_size); } return ERROR_OK; } static int lpc3180_controller_ready(struct nand_device *nand, int timeout) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } LOG_DEBUG("lpc3180_controller_ready count start=%d", timeout); do { if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { uint8_t status; /* Read MLC_ISR, wait for controller to become ready */ target_read_u8(target, 0x200b8048, &status); if (status & 2) { LOG_DEBUG("lpc3180_controller_ready count=%d", timeout); return 1; } } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { uint32_t status; /* Read SLC_STAT and check READY bit */ target_read_u32(target, 0x20020018, &status); if (status & 1) { LOG_DEBUG("lpc3180_controller_ready count=%d", timeout); return 1; } } alive_sleep(1); } while (timeout-- > 0); return 0; } static int lpc3180_nand_ready(struct nand_device *nand, int timeout) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } LOG_DEBUG("lpc3180_nand_ready count start=%d", timeout); do { if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { uint8_t status = 0x0; /* Read MLC_ISR, wait for NAND flash device to become ready */ target_read_u8(target, 0x200b8048, &status); if (status & 1) { LOG_DEBUG("lpc3180_nand_ready count end=%d", timeout); return 1; } } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { uint32_t status = 0x0; /* Read SLC_STAT and check READY bit */ target_read_u32(target, 0x20020018, &status); if (status & 1) { LOG_DEBUG("lpc3180_nand_ready count end=%d", timeout); return 1; } } alive_sleep(1); } while (timeout-- > 0); return 0; } static int lpc3180_tc_ready(struct nand_device *nand, int timeout) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } LOG_DEBUG("lpc3180_tc_ready count start=%d", timeout); do { if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { uint32_t status = 0x0; /* Read SLC_INT_STAT and check INT_TC_STAT bit */ target_read_u32(target, 0x2002001c, &status); if (status & 2) { LOG_DEBUG("lpc3180_tc_ready count=%d", timeout); return 1; } } alive_sleep(1); } while (timeout-- > 0); return 0; } COMMAND_HANDLER(handle_lpc3180_select_command) { struct lpc3180_nand_controller *lpc3180_info = NULL; char *selected[] = { "no", "mlc", "slc" }; if ((CMD_ARGC < 1) || (CMD_ARGC > 3)) return ERROR_COMMAND_SYNTAX_ERROR; unsigned num; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); struct nand_device *nand = get_nand_device_by_num(num); if (!nand) { command_print(CMD, "nand device '#%s' is out of bounds", CMD_ARGV[0]); return ERROR_OK; } lpc3180_info = nand->controller_priv; if (CMD_ARGC >= 2) { if (strcmp(CMD_ARGV[1], "mlc") == 0) lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER; else if (strcmp(CMD_ARGV[1], "slc") == 0) { lpc3180_info->selected_controller = LPC3180_SLC_CONTROLLER; if (CMD_ARGC == 3 && strcmp(CMD_ARGV[2], "bulk") == 0) lpc3180_info->is_bulk = 1; else lpc3180_info->is_bulk = 0; } else return ERROR_COMMAND_SYNTAX_ERROR; } if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) command_print(CMD, "%s controller selected", selected[lpc3180_info->selected_controller]); else command_print(CMD, lpc3180_info->is_bulk ? "%s controller selected bulk mode is available" : "%s controller selected bulk mode is not available", selected[lpc3180_info->selected_controller]); return ERROR_OK; } static const struct command_registration lpc3180_exec_command_handlers[] = { { .name = "select", .handler = handle_lpc3180_select_command, .mode = COMMAND_EXEC, .help = "select MLC or SLC controller (default is MLC), SLC can be set to bulk mode", .usage = "bank_id ['mlc'|'slc' ['bulk'] ]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration lpc3180_command_handler[] = { { .name = "lpc3180", .mode = COMMAND_ANY, .help = "LPC3180 NAND flash controller commands", .usage = "", .chain = lpc3180_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct nand_flash_controller lpc3180_nand_controller = { .name = "lpc3180", .commands = lpc3180_command_handler, .nand_device_command = lpc3180_nand_device_command, .init = lpc3180_init, .reset = lpc3180_reset, .command = lpc3180_command, .address = lpc3180_address, .write_data = lpc3180_write_data, .read_data = lpc3180_read_data, .write_page = lpc3180_write_page, .read_page = lpc3180_read_page, .nand_ready = lpc3180_nand_ready, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/lpc3180.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_LPC3180_H #define OPENOCD_FLASH_NAND_LPC3180_H enum lpc3180_selected_controller { LPC3180_NO_CONTROLLER, LPC3180_MLC_CONTROLLER, LPC3180_SLC_CONTROLLER, }; struct lpc3180_nand_controller { int osc_freq; enum lpc3180_selected_controller selected_controller; int is_bulk; int sw_write_protection; uint32_t sw_wp_lower_bound; uint32_t sw_wp_upper_bound; }; #endif /* OPENOCD_FLASH_NAND_LPC3180_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/lpc32xx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2011 Bjarne Steinsbo <bsteinsbo@gmail.com> * * Copyright (C) 2010 richard vegh <vegh.ricsi@gmail.com> * * Copyright (C) 2010 Oyvind Harboe <oyvind.harboe@zylin.com> * * * * Based on a combination of the lpc3180 driver and code from * * uboot-2009.03-lpc32xx by Kevin Wells. * * Any bugs are mine. --BSt * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "lpc32xx.h" #include <target/target.h> static int lpc32xx_reset(struct nand_device *nand); static int lpc32xx_controller_ready(struct nand_device *nand, int timeout); static int lpc32xx_tc_ready(struct nand_device *nand, int timeout); /* These are offset with the working area in IRAM when using DMA to * read/write data to the SLC controller. * - DMA descriptors will be put at start of working area, * - Hardware generated ECC will be stored at ECC_OFFS * - OOB will be read/written from/to SPARE_OFFS * - Actual page data will be read from/to DATA_OFFS * There are unused holes between the used areas. */ #define ECC_OFFS 0x120 #define SPARE_OFFS 0x140 #define DATA_OFFS 0x200 static const int sp_ooblayout[] = { 10, 11, 12, 13, 14, 15 }; static const int lp_ooblayout[] = { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 }; struct dmac_ll { volatile uint32_t dma_src; volatile uint32_t dma_dest; volatile uint32_t next_lli; volatile uint32_t next_ctrl; }; static struct dmac_ll dmalist[(2048/256) * 2 + 1]; /* nand device lpc32xx <target#> <oscillator_frequency> */ NAND_DEVICE_COMMAND_HANDLER(lpc32xx_nand_device_command) { if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t osc_freq; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], osc_freq); struct lpc32xx_nand_controller *lpc32xx_info; lpc32xx_info = malloc(sizeof(struct lpc32xx_nand_controller)); nand->controller_priv = lpc32xx_info; lpc32xx_info->osc_freq = osc_freq; if ((lpc32xx_info->osc_freq < 1000) || (lpc32xx_info->osc_freq > 20000)) LOG_WARNING("LPC32xx oscillator frequency should be between " "1000 and 20000 kHz, was %i", lpc32xx_info->osc_freq); lpc32xx_info->selected_controller = LPC32XX_NO_CONTROLLER; lpc32xx_info->sw_write_protection = 0; lpc32xx_info->sw_wp_lower_bound = 0x0; lpc32xx_info->sw_wp_upper_bound = 0x0; return ERROR_OK; } static int lpc32xx_pll(int fclkin, uint32_t pll_ctrl) { int bypass = (pll_ctrl & 0x8000) >> 15; int direct = (pll_ctrl & 0x4000) >> 14; int feedback = (pll_ctrl & 0x2000) >> 13; int p = (1 << ((pll_ctrl & 0x1800) >> 11) * 2); int n = ((pll_ctrl & 0x0600) >> 9) + 1; int m = ((pll_ctrl & 0x01fe) >> 1) + 1; int lock = (pll_ctrl & 0x1); if (!lock) LOG_WARNING("PLL is not locked"); if (!bypass && direct) /* direct mode */ return (m * fclkin) / n; if (bypass && !direct) /* bypass mode */ return fclkin / (2 * p); if (bypass & direct) /* direct bypass mode */ return fclkin; if (feedback) /* integer mode */ return m * (fclkin / n); else /* non-integer mode */ return (m / (2 * p)) * (fclkin / n); } static float lpc32xx_cycle_time(struct nand_device *nand) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; uint32_t sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl; int sysclk; int hclk; int hclk_pll; float cycle; int retval; /* calculate timings */ /* determine current SYSCLK (13'MHz or main oscillator) */ retval = target_read_u32(target, 0x40004050, &sysclk_ctrl); if (retval != ERROR_OK) { LOG_ERROR("could not read SYSCLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } if ((sysclk_ctrl & 1) == 0) sysclk = lpc32xx_info->osc_freq; else sysclk = 13000; /* determine selected HCLK source */ retval = target_read_u32(target, 0x40004044, &pwr_ctrl); if (retval != ERROR_OK) { LOG_ERROR("could not read HCLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } if ((pwr_ctrl & (1 << 2)) == 0) /* DIRECT RUN mode */ hclk = sysclk; else { retval = target_read_u32(target, 0x40004058, &hclkpll_ctrl); if (retval != ERROR_OK) { LOG_ERROR("could not read HCLKPLL_CTRL"); return ERROR_NAND_OPERATION_FAILED; } hclk_pll = lpc32xx_pll(sysclk, hclkpll_ctrl); retval = target_read_u32(target, 0x40004040, &hclkdiv_ctrl); if (retval != ERROR_OK) { LOG_ERROR("could not read CLKDIV_CTRL"); return ERROR_NAND_OPERATION_FAILED; } if (pwr_ctrl & (1 << 10)) /* ARM_CLK and HCLK use PERIPH_CLK */ hclk = hclk_pll / (((hclkdiv_ctrl & 0x7c) >> 2) + 1); else /* HCLK uses HCLK_PLL */ hclk = hclk_pll / (1 << (hclkdiv_ctrl & 0x3)); } LOG_DEBUG("LPC32xx HCLK currently clocked at %i kHz", hclk); cycle = (1.0 / hclk) * 1000000.0; return cycle; } static int lpc32xx_init(struct nand_device *nand) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int bus_width = nand->bus_width ? nand->bus_width : 8; int address_cycles = nand->address_cycles ? nand->address_cycles : 3; int page_size = nand->page_size ? nand->page_size : 512; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC32xx " "NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } /* sanitize arguments */ if (bus_width != 8) { LOG_ERROR("LPC32xx doesn't support %i", bus_width); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } /* inform calling code about selected bus width */ nand->bus_width = bus_width; if ((address_cycles < 3) || (address_cycles > 5)) { LOG_ERROR("LPC32xx driver doesn't support %i address cycles", address_cycles); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } if ((page_size != 512) && (page_size != 2048)) { LOG_ERROR("LPC32xx doesn't support page size %i", page_size); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } /* select MLC controller if none is currently selected */ if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_DEBUG("no LPC32xx NAND flash controller selected, " "using default 'slc'"); lpc32xx_info->selected_controller = LPC32XX_SLC_CONTROLLER; } if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { uint32_t mlc_icr_value = 0x0; float cycle; int twp, twh, trp, treh, trhz, trbwb, tcea; /* FLASHCLK_CTRL = 0x22 (enable clk for MLC) */ retval = target_write_u32(target, 0x400040c8, 0x22); if (retval != ERROR_OK) { LOG_ERROR("could not set FLASHCLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_CEH = 0x0 (Force nCE assert) */ retval = target_write_u32(target, 0x200b804c, 0x0); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_CEH"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_LOCK = 0xa25e (unlock protected registers) */ retval = target_write_u32(target, 0x200b8044, 0xa25e); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_LOCK"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_ICR = configuration */ if (lpc32xx_info->sw_write_protection) mlc_icr_value |= 0x8; if (page_size == 2048) mlc_icr_value |= 0x4; if (address_cycles == 4) mlc_icr_value |= 0x2; if (bus_width == 16) mlc_icr_value |= 0x1; retval = target_write_u32(target, 0x200b8030, mlc_icr_value); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ICR"); return ERROR_NAND_OPERATION_FAILED; } /* calculate NAND controller timings */ cycle = lpc32xx_cycle_time(nand); twp = ((40 / cycle) + 1); twh = ((20 / cycle) + 1); trp = ((30 / cycle) + 1); treh = ((15 / cycle) + 1); trhz = ((30 / cycle) + 1); trbwb = ((100 / cycle) + 1); tcea = ((45 / cycle) + 1); /* MLC_LOCK = 0xa25e (unlock protected registers) */ retval = target_write_u32(target, 0x200b8044, 0xa25e); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_LOCK"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_TIME_REG */ retval = target_write_u32(target, 0x200b8034, (twp & 0xf) | ((twh & 0xf) << 4) | ((trp & 0xf) << 8) | ((treh & 0xf) << 12) | ((trhz & 0x7) << 16) | ((trbwb & 0x1f) << 19) | ((tcea & 0x3) << 24)); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_TIME_REG"); return ERROR_NAND_OPERATION_FAILED; } retval = lpc32xx_reset(nand); if (retval != ERROR_OK) return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { float cycle; int r_setup, r_hold, r_width, r_rdy; int w_setup, w_hold, w_width, w_rdy; /* FLASHCLK_CTRL = 0x05 (enable clk for SLC) */ retval = target_write_u32(target, 0x400040c8, 0x05); if (retval != ERROR_OK) { LOG_ERROR("could not set FLASHCLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } /* after reset set other registers of SLC, * so reset calling is here at the beginning */ retval = lpc32xx_reset(nand); if (retval != ERROR_OK) return ERROR_NAND_OPERATION_FAILED; /* SLC_CFG = Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst enabled, DMA read from SLC, WIDTH = bus_width) */ retval = target_write_u32(target, 0x20020014, 0x3e | ((bus_width == 16) ? 1 : 0)); if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_CFG"); return ERROR_NAND_OPERATION_FAILED; } /* SLC_IEN = 3 (INT_RDY_EN = 1) ,(INT_TC_STAT = 1) */ retval = target_write_u32(target, 0x20020020, 0x03); if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_IEN"); return ERROR_NAND_OPERATION_FAILED; } /* DMA configuration */ /* DMACLK_CTRL = 0x01 (enable clock for DMA controller) */ retval = target_write_u32(target, 0x400040e8, 0x01); if (retval != ERROR_OK) { LOG_ERROR("could not set DMACLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } /* DMACConfig = DMA enabled*/ retval = target_write_u32(target, 0x31000030, 0x01); if (retval != ERROR_OK) { LOG_ERROR("could not set DMACConfig"); return ERROR_NAND_OPERATION_FAILED; } /* calculate NAND controller timings */ cycle = lpc32xx_cycle_time(nand); r_setup = w_setup = 0; r_hold = w_hold = 10 / cycle; r_width = 30 / cycle; w_width = 40 / cycle; r_rdy = w_rdy = 100 / cycle; /* SLC_TAC: SLC timing arcs register */ retval = target_write_u32(target, 0x2002002c, (r_setup & 0xf) | ((r_hold & 0xf) << 4) | ((r_width & 0xf) << 8) | ((r_rdy & 0xf) << 12) | ((w_setup & 0xf) << 16) | ((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28)); if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_TAC"); return ERROR_NAND_OPERATION_FAILED; } } return ERROR_OK; } static int lpc32xx_reset(struct nand_device *nand) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use " "LPC32xx NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { /* MLC_CMD = 0xff (reset controller and NAND device) */ retval = target_write_u32(target, 0x200b8000, 0xff); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } if (!lpc32xx_controller_ready(nand, 100)) { LOG_ERROR("LPC32xx MLC NAND controller timed out " "after reset"); return ERROR_NAND_OPERATION_TIMEOUT; } } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { /* SLC_CTRL = 0x6 (ECC_CLEAR, SW_RESET) */ retval = target_write_u32(target, 0x20020010, 0x6); if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_CTRL"); return ERROR_NAND_OPERATION_FAILED; } if (!lpc32xx_controller_ready(nand, 100)) { LOG_ERROR("LPC32xx SLC NAND controller timed out " "after reset"); return ERROR_NAND_OPERATION_TIMEOUT; } } return ERROR_OK; } static int lpc32xx_command(struct nand_device *nand, uint8_t command) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use " "LPC32xx NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { /* MLC_CMD = command */ retval = target_write_u32(target, 0x200b8000, command); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { /* SLC_CMD = command */ retval = target_write_u32(target, 0x20020008, command); if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } } return ERROR_OK; } static int lpc32xx_address(struct nand_device *nand, uint8_t address) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use " "LPC32xx NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { /* MLC_ADDR = address */ retval = target_write_u32(target, 0x200b8004, address); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { /* SLC_ADDR = address */ retval = target_write_u32(target, 0x20020004, address); if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } } return ERROR_OK; } static int lpc32xx_write_data(struct nand_device *nand, uint16_t data) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use " "LPC32xx NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { /* MLC_DATA = data */ retval = target_write_u32(target, 0x200b0000, data); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_DATA"); return ERROR_NAND_OPERATION_FAILED; } } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { /* SLC_DATA = data */ retval = target_write_u32(target, 0x20020000, data); if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_DATA"); return ERROR_NAND_OPERATION_FAILED; } } return ERROR_OK; } static int lpc32xx_read_data(struct nand_device *nand, void *data) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC32xx " "NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { /* data = MLC_DATA, use sized access */ if (nand->bus_width == 8) { uint8_t *data8 = data; retval = target_read_u8(target, 0x200b0000, data8); } else { LOG_ERROR("BUG: bus_width neither 8 nor 16 bit"); return ERROR_NAND_OPERATION_FAILED; } if (retval != ERROR_OK) { LOG_ERROR("could not read MLC_DATA"); return ERROR_NAND_OPERATION_FAILED; } } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { uint32_t data32; /* data = SLC_DATA, must use 32-bit access */ retval = target_read_u32(target, 0x20020000, &data32); if (retval != ERROR_OK) { LOG_ERROR("could not read SLC_DATA"); return ERROR_NAND_OPERATION_FAILED; } if (nand->bus_width == 8) { uint8_t *data8 = data; *data8 = data32 & 0xff; } else { LOG_ERROR("BUG: bus_width neither 8 nor 16 bit"); return ERROR_NAND_OPERATION_FAILED; } } return ERROR_OK; } static int lpc32xx_write_page_mlc(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct target *target = nand->target; int retval; uint8_t status; static uint8_t page_buffer[512]; static uint8_t oob_buffer[6]; int quarter, num_quarters; /* MLC_CMD = sequential input */ retval = target_write_u32(target, 0x200b8000, NAND_CMD_SEQIN); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } if (nand->page_size == 512) { /* MLC_ADDR = 0x0 (one column cycle) */ retval = target_write_u32(target, 0x200b8004, 0x0); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_ADDR = row */ retval = target_write_u32(target, 0x200b8004, page & 0xff); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } if (nand->address_cycles == 4) { retval = target_write_u32(target, 0x200b8004, (page >> 16) & 0xff); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } } } else { /* MLC_ADDR = 0x0 (two column cycles) */ retval = target_write_u32(target, 0x200b8004, 0x0); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, 0x0); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_ADDR = row */ retval = target_write_u32(target, 0x200b8004, page & 0xff); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } } /* when using the MLC controller, we have to treat a large page device * as being made out of four quarters, each the size of a small page * device */ num_quarters = (nand->page_size == 2048) ? 4 : 1; for (quarter = 0; quarter < num_quarters; quarter++) { int thisrun_data_size = (data_size > 512) ? 512 : data_size; int thisrun_oob_size = (oob_size > 6) ? 6 : oob_size; memset(page_buffer, 0xff, 512); if (data) { memcpy(page_buffer, data, thisrun_data_size); data_size -= thisrun_data_size; data += thisrun_data_size; } memset(oob_buffer, 0xff, 6); if (oob) { memcpy(oob_buffer, oob, thisrun_oob_size); oob_size -= thisrun_oob_size; oob += thisrun_oob_size; } /* write MLC_ECC_ENC_REG to start encode cycle */ retval = target_write_u32(target, 0x200b8008, 0x0); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ECC_ENC_REG"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_memory(target, 0x200a8000, 4, 128, page_buffer); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_BUF (data)"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_memory(target, 0x200a8000, 1, 6, oob_buffer); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_BUF (oob)"); return ERROR_NAND_OPERATION_FAILED; } /* write MLC_ECC_AUTO_ENC_REG to start auto encode */ retval = target_write_u32(target, 0x200b8010, 0x0); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ECC_AUTO_ENC_REG"); return ERROR_NAND_OPERATION_FAILED; } if (!lpc32xx_controller_ready(nand, 1000)) { LOG_ERROR("timeout while waiting for " "completion of auto encode cycle"); return ERROR_NAND_OPERATION_FAILED; } } /* MLC_CMD = auto program command */ retval = target_write_u32(target, 0x200b8000, NAND_CMD_PAGEPROG); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } retval = nand_read_status(nand, &status); if (retval != ERROR_OK) { LOG_ERROR("couldn't read status"); return ERROR_NAND_OPERATION_FAILED; } if (status & NAND_STATUS_FAIL) { LOG_ERROR("write operation didn't pass, status: 0x%2.2x", status); return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } /* SLC controller in !raw mode will use target cpu to read/write nand from/to * target internal memory. The transfer to/from flash is done by DMA. This * function sets up the dma linked list in host memory for later transfer to * target. */ static int lpc32xx_make_dma_list(uint32_t target_mem_base, uint32_t page_size, int do_read) { uint32_t i, dmasrc, ctrl, ecc_ctrl, oob_ctrl, dmadst; /* DMACCxControl = TransferSize =64, Source burst size =16, Destination burst size = 16, Source transfer width = 32 bit, Destination transfer width = 32 bit, Source AHB master select = M0, Destination AHB master select = M0, Source increment = 0, // set later Destination increment = 0, // set later Terminal count interrupt enable bit = 0 // set on last */ /* * Write Operation Sequence for Small Block NAND * ---------------------------------------------------------- * 1. X'fer 256 bytes of data from Memory to Flash. * 2. Copy generated ECC data from Register to Spare Area * 3. X'fer next 256 bytes of data from Memory to Flash. * 4. Copy generated ECC data from Register to Spare Area. * 5. X'fer 16 bytes of Spare area from Memory to Flash. * Read Operation Sequence for Small Block NAND * ---------------------------------------------------------- * 1. X'fer 256 bytes of data from Flash to Memory. * 2. Copy generated ECC data from Register to ECC calc Buffer. * 3. X'fer next 256 bytes of data from Flash to Memory. * 4. Copy generated ECC data from Register to ECC calc Buffer. * 5. X'fer 16 bytes of Spare area from Flash to Memory. * Write Operation Sequence for Large Block NAND * ---------------------------------------------------------- * 1. Steps(1-4) of Write Operations repeated for four times * which generates 16 DMA descriptors to X'fer 2048 bytes of * data & 32 bytes of ECC data. * 2. X'fer 64 bytes of Spare area from Memory to Flash. * Read Operation Sequence for Large Block NAND * ---------------------------------------------------------- * 1. Steps(1-4) of Read Operations repeated for four times * which generates 16 DMA descriptors to X'fer 2048 bytes of * data & 32 bytes of ECC data. * 2. X'fer 64 bytes of Spare area from Flash to Memory. */ ctrl = (0x40 | 3 << 12 | 3 << 15 | 2 << 18 | 2 << 21 | 0 << 24 | 0 << 25 | 0 << 26 | 0 << 27 | 0 << 31); /* DMACCxControl = TransferSize =1, Source burst size =4, Destination burst size = 4, Source transfer width = 32 bit, Destination transfer width = 32 bit, Source AHB master select = M0, Destination AHB master select = M0, Source increment = 0, Destination increment = 1, Terminal count interrupt enable bit = 0 */ ecc_ctrl = 0x01 | 1 << 12 | 1 << 15 | 2 << 18 | 2 << 21 | 0 << 24 | 0 << 25 | 0 << 26 | 1 << 27 | 0 << 31; /* DMACCxControl = TransferSize =16 for lp or 4 for sp, Source burst size =16, Destination burst size = 16, Source transfer width = 32 bit, Destination transfer width = 32 bit, Source AHB master select = M0, Destination AHB master select = M0, Source increment = 0, // set later Destination increment = 0, // set later Terminal count interrupt enable bit = 1 // set on last */ oob_ctrl = (page_size == 2048 ? 0x10 : 0x04) | 3 << 12 | 3 << 15 | 2 << 18 | 2 << 21 | 0 << 24 | 0 << 25 | 0 << 26 | 0 << 27 | 1 << 31; if (do_read) { ctrl |= 1 << 27;/* Destination increment = 1 */ oob_ctrl |= 1 << 27; /* Destination increment = 1 */ dmasrc = 0x20020038; /* SLC_DMA_DATA */ dmadst = target_mem_base + DATA_OFFS; } else { ctrl |= 1 << 26;/* Source increment = 1 */ oob_ctrl |= 1 << 26; /* Source increment = 1 */ dmasrc = target_mem_base + DATA_OFFS; dmadst = 0x20020038; /* SLC_DMA_DATA */ } /* * Write Operation Sequence for Small Block NAND * ---------------------------------------------------------- * 1. X'fer 256 bytes of data from Memory to Flash. * 2. Copy generated ECC data from Register to Spare Area * 3. X'fer next 256 bytes of data from Memory to Flash. * 4. Copy generated ECC data from Register to Spare Area. * 5. X'fer 16 bytes of Spare area from Memory to Flash. * Read Operation Sequence for Small Block NAND * ---------------------------------------------------------- * 1. X'fer 256 bytes of data from Flash to Memory. * 2. Copy generated ECC data from Register to ECC calc Buffer. * 3. X'fer next 256 bytes of data from Flash to Memory. * 4. Copy generated ECC data from Register to ECC calc Buffer. * 5. X'fer 16 bytes of Spare area from Flash to Memory. * Write Operation Sequence for Large Block NAND * ---------------------------------------------------------- * 1. Steps(1-4) of Write Operations repeated for four times * which generates 16 DMA descriptors to X'fer 2048 bytes of * data & 32 bytes of ECC data. * 2. X'fer 64 bytes of Spare area from Memory to Flash. * Read Operation Sequence for Large Block NAND * ---------------------------------------------------------- * 1. Steps(1-4) of Read Operations repeated for four times * which generates 16 DMA descriptors to X'fer 2048 bytes of * data & 32 bytes of ECC data. * 2. X'fer 64 bytes of Spare area from Flash to Memory. */ for (i = 0; i < page_size/0x100; i++) { dmalist[i*2].dma_src = (do_read ? dmasrc : (dmasrc + i * 256)); dmalist[i*2].dma_dest = (do_read ? (dmadst + i * 256) : dmadst); dmalist[i*2].next_lli = target_mem_base + (i*2 + 1) * sizeof(struct dmac_ll); dmalist[i*2].next_ctrl = ctrl; dmalist[(i*2) + 1].dma_src = 0x20020034;/* SLC_ECC */ dmalist[(i*2) + 1].dma_dest = target_mem_base + ECC_OFFS + i * 4; dmalist[(i*2) + 1].next_lli = target_mem_base + (i*2 + 2) * sizeof(struct dmac_ll); dmalist[(i*2) + 1].next_ctrl = ecc_ctrl; } if (do_read) dmadst = target_mem_base + SPARE_OFFS; else { dmasrc = target_mem_base + SPARE_OFFS; dmalist[(i*2) - 1].next_lli = 0;/* last link = null on write */ dmalist[(i*2) - 1].next_ctrl |= (1 << 31); /* Set TC enable */ } dmalist[i*2].dma_src = dmasrc; dmalist[i*2].dma_dest = dmadst; dmalist[i*2].next_lli = 0; dmalist[i*2].next_ctrl = oob_ctrl; return i * 2 + 1; /* Number of descriptors */ } static int lpc32xx_start_slc_dma(struct nand_device *nand, uint32_t count, int do_wait) { struct target *target = nand->target; int retval; /* DMACIntTCClear = ch0 */ retval = target_write_u32(target, 0x31000008, 1); if (retval != ERROR_OK) { LOG_ERROR("Could not set DMACIntTCClear"); return retval; } /* DMACIntErrClear = ch0 */ retval = target_write_u32(target, 0x31000010, 1); if (retval != ERROR_OK) { LOG_ERROR("Could not set DMACIntErrClear"); return retval; } /* DMACCxConfig= E=1, SrcPeripheral = 1 (SLC), DestPeripheral = 1 (SLC), FlowCntrl = 2 (Pher -> Mem, DMA), IE = 0, ITC = 0, L= 0, H=0 */ retval = target_write_u32(target, 0x31000110, 1 | 1<<1 | 1<<6 | 2<<11 | 0<<14 | 0<<15 | 0<<16 | 0<<18); if (retval != ERROR_OK) { LOG_ERROR("Could not set DMACC0Config"); return retval; } /* SLC_CTRL = 3 (START DMA), ECC_CLEAR */ retval = target_write_u32(target, 0x20020010, 0x3); if (retval != ERROR_OK) { LOG_ERROR("Could not set SLC_CTRL"); return retval; } /* SLC_ICR = 2, INT_TC_CLR, clear pending TC*/ retval = target_write_u32(target, 0x20020028, 2); if (retval != ERROR_OK) { LOG_ERROR("Could not set SLC_ICR"); return retval; } /* SLC_TC */ retval = target_write_u32(target, 0x20020030, count); if (retval != ERROR_OK) { LOG_ERROR("lpc32xx_start_slc_dma: Could not set SLC_TC"); return retval; } /* Wait finish */ if (do_wait && !lpc32xx_tc_ready(nand, 100)) { LOG_ERROR("timeout while waiting for completion of DMA"); return ERROR_NAND_OPERATION_FAILED; } return retval; } static int lpc32xx_dma_ready(struct nand_device *nand, int timeout) { struct target *target = nand->target; LOG_DEBUG("lpc32xx_dma_ready count start=%d", timeout); do { uint32_t tc_stat; uint32_t err_stat; int retval; /* Read DMACRawIntTCStat */ retval = target_read_u32(target, 0x31000014, &tc_stat); if (retval != ERROR_OK) { LOG_ERROR("Could not read DMACRawIntTCStat"); return 0; } /* Read DMACRawIntErrStat */ retval = target_read_u32(target, 0x31000018, &err_stat); if (retval != ERROR_OK) { LOG_ERROR("Could not read DMACRawIntErrStat"); return 0; } if ((tc_stat | err_stat) & 1) { LOG_DEBUG("lpc32xx_dma_ready count=%d", timeout); if (err_stat & 1) { LOG_ERROR("lpc32xx_dma_ready " "DMA error, aborted"); return 0; } else return 1; } alive_sleep(1); } while (timeout-- > 0); return 0; } static uint32_t slc_ecc_copy_to_buffer(uint8_t *spare, const uint32_t *ecc, int count) { int i; for (i = 0; i < (count * 3); i += 3) { uint32_t ce = ecc[i/3]; ce = ~(ce << 2) & 0xFFFFFF; spare[i+2] = (uint8_t)(ce & 0xFF); ce >>= 8; spare[i+1] = (uint8_t)(ce & 0xFF); ce >>= 8; spare[i] = (uint8_t)(ce & 0xFF); } return 0; } static void lpc32xx_dump_oob(uint8_t *oob, uint32_t oob_size) { int addr = 0; while (oob_size > 0) { LOG_DEBUG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x", addr, oob[0], oob[1], oob[2], oob[3], oob[4], oob[5], oob[6], oob[7]); oob += 8; addr += 8; oob_size -= 8; } } static int lpc32xx_write_page_slc(struct nand_device *nand, struct working_area *pworking_area, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct target *target = nand->target; int retval; uint32_t target_mem_base; LOG_DEBUG("SLC write page %" PRIx32 " data=%d, oob=%d, " "data_size=%" PRIu32 ", oob_size=%" PRIu32, page, !!data, !!oob, data_size, oob_size); target_mem_base = pworking_area->address; /* * Skip writing page which has all 0xFF data as this will * generate 0x0 value. */ if (data && !oob) { uint32_t i, all_ff = 1; for (i = 0; i < data_size; i++) if (data[i] != 0xFF) { all_ff = 0; break; } if (all_ff) return ERROR_OK; } /* Make the dma descriptors in local memory */ int nll = lpc32xx_make_dma_list(target_mem_base, nand->page_size, 0); /* Write them to target. XXX: Assumes host and target have same byte sex. */ retval = target_write_memory(target, target_mem_base, 4, nll * sizeof(struct dmac_ll) / 4, (uint8_t *)dmalist); if (retval != ERROR_OK) { LOG_ERROR("Could not write DMA descriptors to IRAM"); return retval; } retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); if (retval != ERROR_OK) { LOG_ERROR("NAND_CMD_SEQIN failed"); return retval; } /* SLC_CFG = Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst enabled, DMA write to SLC, WIDTH = bus_width */ retval = target_write_u32(target, 0x20020014, 0x3c); if (retval != ERROR_OK) { LOG_ERROR("Could not set SLC_CFG"); return retval; } if (data) { /* Write data to target */ static uint8_t fdata[2048]; memset(fdata, 0xFF, nand->page_size); memcpy(fdata, data, data_size); retval = target_write_memory(target, target_mem_base + DATA_OFFS, 4, nand->page_size/4, fdata); if (retval != ERROR_OK) { LOG_ERROR("Could not write data to IRAM"); return retval; } /* Write first descriptor to DMA controller */ retval = target_write_memory(target, 0x31000100, 4, sizeof(struct dmac_ll) / 4, (uint8_t *)dmalist); if (retval != ERROR_OK) { LOG_ERROR("Could not write DMA descriptor to DMAC"); return retval; } /* Start xfer of data from iram to flash using DMA */ int tot_size = nand->page_size; tot_size += tot_size == 2048 ? 64 : 16; retval = lpc32xx_start_slc_dma(nand, tot_size, 0); if (retval != ERROR_OK) { LOG_ERROR("DMA failed"); return retval; } /* Wait for DMA to finish. SLC is not finished at this stage */ if (!lpc32xx_dma_ready(nand, 100)) { LOG_ERROR("Data DMA failed during write"); return ERROR_FLASH_OPERATION_FAILED; } } /* data xfer */ /* Copy OOB to iram */ static uint8_t foob[64]; int foob_size = nand->page_size == 2048 ? 64 : 16; memset(foob, 0xFF, foob_size); if (oob) /* Raw mode */ memcpy(foob, oob, oob_size); else { /* Get HW generated ECC, made while writing data */ int ecc_count = nand->page_size == 2048 ? 8 : 2; static uint32_t hw_ecc[8]; retval = target_read_memory(target, target_mem_base + ECC_OFFS, 4, ecc_count, (uint8_t *)hw_ecc); if (retval != ERROR_OK) { LOG_ERROR("Reading hw generated ECC from IRAM failed"); return retval; } /* Copy to oob, at correct offsets */ static uint8_t ecc[24]; slc_ecc_copy_to_buffer(ecc, hw_ecc, ecc_count); const int *layout = nand->page_size == 2048 ? lp_ooblayout : sp_ooblayout; int i; for (i = 0; i < ecc_count * 3; i++) foob[layout[i]] = ecc[i]; lpc32xx_dump_oob(foob, foob_size); } retval = target_write_memory(target, target_mem_base + SPARE_OFFS, 4, foob_size / 4, foob); if (retval != ERROR_OK) { LOG_ERROR("Writing OOB to IRAM failed"); return retval; } /* Write OOB descriptor to DMA controller */ retval = target_write_memory(target, 0x31000100, 4, sizeof(struct dmac_ll) / 4, (uint8_t *)(&dmalist[nll-1])); if (retval != ERROR_OK) { LOG_ERROR("Could not write OOB DMA descriptor to DMAC"); return retval; } if (data) { /* Only restart DMA with last descriptor, * don't setup SLC again */ /* DMACIntTCClear = ch0 */ retval = target_write_u32(target, 0x31000008, 1); if (retval != ERROR_OK) { LOG_ERROR("Could not set DMACIntTCClear"); return retval; } /* DMACCxConfig= * E=1, * SrcPeripheral = 1 (SLC), * DestPeripheral = 1 (SLC), * FlowCntrl = 2 (Pher -> Mem, DMA), * IE = 0, * ITC = 0, * L= 0, * H=0 */ retval = target_write_u32(target, 0x31000110, 1 | 1<<1 | 1<<6 | 2<<11 | 0<<14 | 0<<15 | 0<<16 | 0<<18); if (retval != ERROR_OK) { LOG_ERROR("Could not set DMACC0Config"); return retval; } /* Wait finish */ if (!lpc32xx_tc_ready(nand, 100)) { LOG_ERROR("timeout while waiting for " "completion of DMA"); return ERROR_NAND_OPERATION_FAILED; } } else { /* Start xfer of data from iram to flash using DMA */ retval = lpc32xx_start_slc_dma(nand, foob_size, 1); if (retval != ERROR_OK) { LOG_ERROR("DMA OOB failed"); return retval; } } /* Let NAND start actual writing */ retval = nand_write_finish(nand); if (retval != ERROR_OK) { LOG_ERROR("nand_write_finish failed"); return retval; } return ERROR_OK; } static int lpc32xx_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC32xx " "NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { if (!data && oob) { LOG_ERROR("LPC32xx MLC controller can't write " "OOB data only"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } if (oob && (oob_size > 24)) { LOG_ERROR("LPC32xx MLC controller can't write more " "than 6 bytes for each quarter's OOB data"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } if (data_size > (uint32_t)nand->page_size) { LOG_ERROR("data size exceeds page size"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } retval = lpc32xx_write_page_mlc(nand, page, data, data_size, oob, oob_size); } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { struct working_area *pworking_area; if (!data && oob) { /* * if oob only mode is active original method is used * as SLC controller hangs during DMA interworking. (?) * Anyway the code supports the oob only mode below. */ return nand_write_page_raw(nand, page, data, data_size, oob, oob_size); } retval = target_alloc_working_area(target, nand->page_size + DATA_OFFS, &pworking_area); if (retval != ERROR_OK) { LOG_ERROR("Can't allocate working area in " "LPC internal RAM"); return ERROR_FLASH_OPERATION_FAILED; } retval = lpc32xx_write_page_slc(nand, pworking_area, page, data, data_size, oob, oob_size); target_free_working_area(target, pworking_area); } return retval; } static int lpc32xx_read_page_mlc(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct target *target = nand->target; static uint8_t page_buffer[2048]; static uint8_t oob_buffer[64]; uint32_t page_bytes_done = 0; uint32_t oob_bytes_done = 0; uint32_t mlc_isr; int retval; if (!data && oob) { /* MLC_CMD = Read OOB * we can use the READOOB command on both small and large page * devices, as the controller translates the 0x50 command to * a 0x0 with appropriate positioning of the serial buffer * read pointer */ retval = target_write_u32(target, 0x200b8000, NAND_CMD_READOOB); } else { /* MLC_CMD = Read0 */ retval = target_write_u32(target, 0x200b8000, NAND_CMD_READ0); } if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } if (nand->page_size == 512) { /* small page device * MLC_ADDR = 0x0 (one column cycle) */ retval = target_write_u32(target, 0x200b8004, 0x0); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_ADDR = row */ retval = target_write_u32(target, 0x200b8004, page & 0xff); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } if (nand->address_cycles == 4) { retval = target_write_u32(target, 0x200b8004, (page >> 16) & 0xff); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } } } else { /* large page device * MLC_ADDR = 0x0 (two column cycles) */ retval = target_write_u32(target, 0x200b8004, 0x0); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, 0x0); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_ADDR = row */ retval = target_write_u32(target, 0x200b8004, page & 0xff); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_CMD = Read Start */ retval = target_write_u32(target, 0x200b8000, NAND_CMD_READSTART); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } } while (page_bytes_done < (uint32_t)nand->page_size) { /* MLC_ECC_AUTO_DEC_REG = dummy */ retval = target_write_u32(target, 0x200b8014, 0xaa55aa55); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ECC_AUTO_DEC_REG"); return ERROR_NAND_OPERATION_FAILED; } if (!lpc32xx_controller_ready(nand, 1000)) { LOG_ERROR("timeout while waiting for " "completion of auto decode cycle"); return ERROR_NAND_OPERATION_FAILED; } retval = target_read_u32(target, 0x200b8048, &mlc_isr); if (retval != ERROR_OK) { LOG_ERROR("could not read MLC_ISR"); return ERROR_NAND_OPERATION_FAILED; } if (mlc_isr & 0x8) { if (mlc_isr & 0x40) { LOG_ERROR("uncorrectable error detected: " "0x%2.2x", (unsigned)mlc_isr); return ERROR_NAND_OPERATION_FAILED; } LOG_WARNING("%i symbol error detected and corrected", ((int)(((mlc_isr & 0x30) >> 4) + 1))); } if (data) { retval = target_read_memory(target, 0x200a8000, 4, 128, page_buffer + page_bytes_done); if (retval != ERROR_OK) { LOG_ERROR("could not read MLC_BUF (data)"); return ERROR_NAND_OPERATION_FAILED; } } if (oob) { retval = target_read_memory(target, 0x200a8000, 4, 4, oob_buffer + oob_bytes_done); if (retval != ERROR_OK) { LOG_ERROR("could not read MLC_BUF (oob)"); return ERROR_NAND_OPERATION_FAILED; } } page_bytes_done += 512; oob_bytes_done += 16; } if (data) memcpy(data, page_buffer, data_size); if (oob) memcpy(oob, oob_buffer, oob_size); return ERROR_OK; } static int lpc32xx_read_page_slc(struct nand_device *nand, struct working_area *pworking_area, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct target *target = nand->target; int retval; uint32_t target_mem_base; LOG_DEBUG("SLC read page %" PRIx32 " data=%" PRIu32 ", oob=%" PRIu32, page, data_size, oob_size); target_mem_base = pworking_area->address; /* Make the dma descriptors in local memory */ int nll = lpc32xx_make_dma_list(target_mem_base, nand->page_size, 1); /* Write them to target. XXX: Assumes host and target have same byte sex. */ retval = target_write_memory(target, target_mem_base, 4, nll * sizeof(struct dmac_ll) / 4, (uint8_t *)dmalist); if (retval != ERROR_OK) { LOG_ERROR("Could not write DMA descriptors to IRAM"); return retval; } retval = nand_page_command(nand, page, NAND_CMD_READ0, 0); if (retval != ERROR_OK) { LOG_ERROR("lpc32xx_read_page_slc: NAND_CMD_READ0 failed"); return retval; } /* SLC_CFG = Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst enabled, DMA read from SLC, WIDTH = bus_width */ retval = target_write_u32(target, 0x20020014, 0x3e); if (retval != ERROR_OK) { LOG_ERROR("lpc32xx_read_page_slc: Could not set SLC_CFG"); return retval; } /* Write first descriptor to DMA controller */ retval = target_write_memory(target, 0x31000100, 4, sizeof(struct dmac_ll) / 4, (uint8_t *)dmalist); if (retval != ERROR_OK) { LOG_ERROR("Could not write DMA descriptor to DMAC"); return retval; } /* Start xfer of data from flash to iram using DMA */ int tot_size = nand->page_size; tot_size += nand->page_size == 2048 ? 64 : 16; retval = lpc32xx_start_slc_dma(nand, tot_size, 1); if (retval != ERROR_OK) { LOG_ERROR("lpc32xx_read_page_slc: DMA read failed"); return retval; } /* Copy data from iram */ if (data) { retval = target_read_memory(target, target_mem_base + DATA_OFFS, 4, data_size/4, data); if (retval != ERROR_OK) { LOG_ERROR("Could not read data from IRAM"); return retval; } } if (oob) { /* No error correction, just return data as read from flash */ retval = target_read_memory(target, target_mem_base + SPARE_OFFS, 4, oob_size/4, oob); if (retval != ERROR_OK) { LOG_ERROR("Could not read OOB from IRAM"); return retval; } return ERROR_OK; } /* Copy OOB from flash, stored in IRAM */ static uint8_t foob[64]; retval = target_read_memory(target, target_mem_base + SPARE_OFFS, 4, nand->page_size == 2048 ? 16 : 4, foob); lpc32xx_dump_oob(foob, nand->page_size == 2048 ? 64 : 16); if (retval != ERROR_OK) { LOG_ERROR("Could not read OOB from IRAM"); return retval; } /* Copy ECC from HW, generated while reading */ int ecc_count = nand->page_size == 2048 ? 8 : 2; static uint32_t hw_ecc[8]; /* max size */ retval = target_read_memory(target, target_mem_base + ECC_OFFS, 4, ecc_count, (uint8_t *)hw_ecc); if (retval != ERROR_OK) { LOG_ERROR("Could not read hw generated ECC from IRAM"); return retval; } static uint8_t ecc[24]; slc_ecc_copy_to_buffer(ecc, hw_ecc, ecc_count); /* Copy ECC from flash using correct layout */ static uint8_t fecc[24];/* max size */ const int *layout = nand->page_size == 2048 ? lp_ooblayout : sp_ooblayout; int i; for (i = 0; i < ecc_count * 3; i++) fecc[i] = foob[layout[i]]; /* Compare ECC and possibly correct data */ for (i = 0; i < ecc_count; i++) { retval = nand_correct_data(nand, data + 256*i, &fecc[i * 3], &ecc[i * 3]); if (retval > 0) LOG_WARNING("error detected and corrected: %" PRIu32 "/%d", page, i); if (retval < 0) break; } if (i == ecc_count) retval = ERROR_OK; else { LOG_ERROR("uncorrectable error detected: %" PRIu32 "/%d", page, i); retval = ERROR_NAND_OPERATION_FAILED; } return retval; } static int lpc32xx_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC32xx " "NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { if (data_size > (uint32_t)nand->page_size) { LOG_ERROR("data size exceeds page size"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } retval = lpc32xx_read_page_mlc(nand, page, data, data_size, oob, oob_size); } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { struct working_area *pworking_area; retval = target_alloc_working_area(target, nand->page_size + 0x200, &pworking_area); if (retval != ERROR_OK) { LOG_ERROR("Can't allocate working area in " "LPC internal RAM"); return ERROR_FLASH_OPERATION_FAILED; } retval = lpc32xx_read_page_slc(nand, pworking_area, page, data, data_size, oob, oob_size); target_free_working_area(target, pworking_area); } return retval; } static int lpc32xx_controller_ready(struct nand_device *nand, int timeout) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC32xx " "NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } LOG_DEBUG("lpc32xx_controller_ready count start=%d", timeout); do { if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { uint8_t status; /* Read MLC_ISR, wait for controller to become ready */ retval = target_read_u8(target, 0x200b8048, &status); if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_STAT"); return ERROR_NAND_OPERATION_FAILED; } if (status & 2) { LOG_DEBUG("lpc32xx_controller_ready count=%d", timeout); return 1; } } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { uint32_t status; /* Read SLC_STAT and check READY bit */ retval = target_read_u32(target, 0x20020018, &status); if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_STAT"); return ERROR_NAND_OPERATION_FAILED; } if (status & 1) { LOG_DEBUG("lpc32xx_controller_ready count=%d", timeout); return 1; } } alive_sleep(1); } while (timeout-- > 0); return 0; } static int lpc32xx_nand_ready(struct nand_device *nand, int timeout) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC32xx " "NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } LOG_DEBUG("lpc32xx_nand_ready count start=%d", timeout); do { if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { uint8_t status = 0x0; /* Read MLC_ISR, wait for NAND flash device to * become ready */ retval = target_read_u8(target, 0x200b8048, &status); if (retval != ERROR_OK) { LOG_ERROR("could not read MLC_ISR"); return ERROR_NAND_OPERATION_FAILED; } if (status & 1) { LOG_DEBUG("lpc32xx_nand_ready count end=%d", timeout); return 1; } } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { uint32_t status = 0x0; /* Read SLC_STAT and check READY bit */ retval = target_read_u32(target, 0x20020018, &status); if (retval != ERROR_OK) { LOG_ERROR("could not read SLC_STAT"); return ERROR_NAND_OPERATION_FAILED; } if (status & 1) { LOG_DEBUG("lpc32xx_nand_ready count end=%d", timeout); return 1; } } alive_sleep(1); } while (timeout-- > 0); return 0; } static int lpc32xx_tc_ready(struct nand_device *nand, int timeout) { struct target *target = nand->target; LOG_DEBUG("lpc32xx_tc_ready count start=%d", timeout); do { uint32_t status = 0x0; int retval; /* Read SLC_INT_STAT and check INT_TC_STAT bit */ retval = target_read_u32(target, 0x2002001c, &status); if (retval != ERROR_OK) { LOG_ERROR("Could not read SLC_INT_STAT"); return 0; } if (status & 2) { LOG_DEBUG("lpc32xx_tc_ready count=%d", timeout); return 1; } alive_sleep(1); } while (timeout-- > 0); return 0; } COMMAND_HANDLER(handle_lpc32xx_select_command) { struct lpc32xx_nand_controller *lpc32xx_info = NULL; char *selected[] = { "no", "mlc", "slc" }; if ((CMD_ARGC < 1) || (CMD_ARGC > 3)) return ERROR_COMMAND_SYNTAX_ERROR; unsigned num; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); struct nand_device *nand = get_nand_device_by_num(num); if (!nand) { command_print(CMD, "nand device '#%s' is out of bounds", CMD_ARGV[0]); return ERROR_OK; } lpc32xx_info = nand->controller_priv; if (CMD_ARGC >= 2) { if (strcmp(CMD_ARGV[1], "mlc") == 0) { lpc32xx_info->selected_controller = LPC32XX_MLC_CONTROLLER; } else if (strcmp(CMD_ARGV[1], "slc") == 0) { lpc32xx_info->selected_controller = LPC32XX_SLC_CONTROLLER; } else return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "%s controller selected", selected[lpc32xx_info->selected_controller]); return ERROR_OK; } static const struct command_registration lpc32xx_exec_command_handlers[] = { { .name = "select", .handler = handle_lpc32xx_select_command, .mode = COMMAND_EXEC, .help = "select MLC or SLC controller (default is MLC)", .usage = "bank_id ['mlc'|'slc' ]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration lpc32xx_command_handler[] = { { .name = "lpc32xx", .mode = COMMAND_ANY, .help = "LPC32xx NAND flash controller commands", .usage = "", .chain = lpc32xx_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct nand_flash_controller lpc32xx_nand_controller = { .name = "lpc32xx", .commands = lpc32xx_command_handler, .nand_device_command = lpc32xx_nand_device_command, .init = lpc32xx_init, .reset = lpc32xx_reset, .command = lpc32xx_command, .address = lpc32xx_address, .write_data = lpc32xx_write_data, .read_data = lpc32xx_read_data, .write_page = lpc32xx_write_page, .read_page = lpc32xx_read_page, .nand_ready = lpc32xx_nand_ready, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/lpc32xx.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_LPC32XX_H #define OPENOCD_FLASH_NAND_LPC32XX_H enum lpc32xx_selected_controller { LPC32XX_NO_CONTROLLER, LPC32XX_MLC_CONTROLLER, LPC32XX_SLC_CONTROLLER, }; struct lpc32xx_nand_controller { int osc_freq; enum lpc32xx_selected_controller selected_controller; int sw_write_protection; uint32_t sw_wp_lower_bound; uint32_t sw_wp_upper_bound; }; #endif /* OPENOCD_FLASH_NAND_LPC32XX_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/mx3.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by Alexei Babich * * Rezonans plc., Chelyabinsk, Russia * * impatt@mail.ru * ***************************************************************************/ /* * Freescale iMX3* OpenOCD NAND Flash controller support. * * Many thanks to Ben Dooks for writing s3c24xx driver. */ /* driver tested with STMicro NAND512W3A @imx31 tested "nand probe #", "nand erase # 0 #", "nand dump # file 0 #", "nand write # file 0" get_next_halfword_from_sram_buffer() not tested */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "mx3.h" #include <target/target.h> static const char target_not_halted_err_msg[] = "target must be halted to use mx3 NAND flash controller"; static const char data_block_size_err_msg[] = "minimal granularity is one half-word, %" PRIu32 " is incorrect"; static const char sram_buffer_bounds_err_msg[] = "trying to access out of SRAM buffer bound (addr=0x%" PRIx32 ")"; static const char get_status_register_err_msg[] = "can't get NAND status"; static uint32_t in_sram_address; static unsigned char sign_of_sequental_byte_read; static int test_iomux_settings(struct target *target, uint32_t value, uint32_t mask, const char *text); static int initialize_nf_controller(struct nand_device *nand); static int get_next_byte_from_sram_buffer(struct target *target, uint8_t *value); static int get_next_halfword_from_sram_buffer(struct target *target, uint16_t *value); static int poll_for_complete_op(struct target *target, const char *text); static int validate_target_state(struct nand_device *nand); static int do_data_output(struct nand_device *nand); static int imx31_command(struct nand_device *nand, uint8_t command); static int imx31_address(struct nand_device *nand, uint8_t address); NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command) { struct mx3_nf_controller *mx3_nf_info; mx3_nf_info = malloc(sizeof(struct mx3_nf_controller)); if (!mx3_nf_info) { LOG_ERROR("no memory for nand controller"); return ERROR_FAIL; } nand->controller_priv = mx3_nf_info; if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; /* * check hwecc requirements */ { int hwecc_needed; hwecc_needed = strcmp(CMD_ARGV[2], "hwecc"); if (hwecc_needed == 0) mx3_nf_info->flags.hw_ecc_enabled = 1; else mx3_nf_info->flags.hw_ecc_enabled = 0; } mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; mx3_nf_info->fin = MX3_NF_FIN_NONE; mx3_nf_info->flags.target_little_endian = (nand->target->endianness == TARGET_LITTLE_ENDIAN); return ERROR_OK; } static int imx31_init(struct nand_device *nand) { struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; struct target *target = nand->target; { /* * validate target state */ int validate_target_result; validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; } { uint16_t buffsize_register_content; target_read_u16(target, MX3_NF_BUFSIZ, &buffsize_register_content); mx3_nf_info->flags.one_kb_sram = !(buffsize_register_content & 0x000f); } { uint32_t pcsr_register_content; target_read_u32(target, MX3_PCSR, &pcsr_register_content); if (!nand->bus_width) { nand->bus_width = (pcsr_register_content & 0x80000000) ? 16 : 8; } else { pcsr_register_content |= ((nand->bus_width == 16) ? 0x80000000 : 0x00000000); target_write_u32(target, MX3_PCSR, pcsr_register_content); } if (!nand->page_size) { nand->page_size = (pcsr_register_content & 0x40000000) ? 2048 : 512; } else { pcsr_register_content |= ((nand->page_size == 2048) ? 0x40000000 : 0x00000000); target_write_u32(target, MX3_PCSR, pcsr_register_content); } if (mx3_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) { LOG_ERROR("NAND controller have only 1 kb SRAM, " "so pagesize 2048 is incompatible with it"); } } { uint32_t cgr_register_content; target_read_u32(target, MX3_CCM_CGR2, &cgr_register_content); if (!(cgr_register_content & 0x00000300)) { LOG_ERROR("clock gating to EMI disabled"); return ERROR_FAIL; } } { uint32_t gpr_register_content; target_read_u32(target, MX3_GPR, &gpr_register_content); if (gpr_register_content & 0x00000060) { LOG_ERROR("pins mode overridden by GPR"); return ERROR_FAIL; } } { /* * testing IOMUX settings; must be in "functional-mode output and * functional-mode input" mode */ int test_iomux; test_iomux = ERROR_OK; test_iomux |= test_iomux_settings(target, 0x43fac0c0, 0x7f7f7f00, "d0,d1,d2"); test_iomux |= test_iomux_settings(target, 0x43fac0c4, 0x7f7f7f7f, "d3,d4,d5,d6"); test_iomux |= test_iomux_settings(target, 0x43fac0c8, 0x0000007f, "d7"); if (nand->bus_width == 16) { test_iomux |= test_iomux_settings(target, 0x43fac0c8, 0x7f7f7f00, "d8,d9,d10"); test_iomux |= test_iomux_settings(target, 0x43fac0cc, 0x7f7f7f7f, "d11,d12,d13,d14"); test_iomux |= test_iomux_settings(target, 0x43fac0d0, 0x0000007f, "d15"); } test_iomux |= test_iomux_settings(target, 0x43fac0d0, 0x7f7f7f00, "nfwp,nfce,nfrb"); test_iomux |= test_iomux_settings(target, 0x43fac0d4, 0x7f7f7f7f, "nfwe,nfre,nfale,nfcle"); if (test_iomux != ERROR_OK) return ERROR_FAIL; } initialize_nf_controller(nand); { int retval; uint16_t nand_status_content; retval = ERROR_OK; retval |= imx31_command(nand, NAND_CMD_STATUS); retval |= imx31_address(nand, 0x00); retval |= do_data_output(nand); if (retval != ERROR_OK) { LOG_ERROR(get_status_register_err_msg); return ERROR_FAIL; } target_read_u16(target, MX3_NF_MAIN_BUFFER0, &nand_status_content); if (!(nand_status_content & 0x0080)) { /* * is host-big-endian correctly ?? */ LOG_INFO("NAND read-only"); mx3_nf_info->flags.nand_readonly = 1; } else mx3_nf_info->flags.nand_readonly = 0; } return ERROR_OK; } static int imx31_read_data(struct nand_device *nand, void *data) { struct target *target = nand->target; { /* * validate target state */ int validate_target_result; validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; } { /* * get data from nand chip */ int try_data_output_from_nand_chip; try_data_output_from_nand_chip = do_data_output(nand); if (try_data_output_from_nand_chip != ERROR_OK) return try_data_output_from_nand_chip; } if (nand->bus_width == 16) get_next_halfword_from_sram_buffer(target, data); else get_next_byte_from_sram_buffer(target, data); return ERROR_OK; } static int imx31_write_data(struct nand_device *nand, uint16_t data) { LOG_ERROR("write_data() not implemented"); return ERROR_NAND_OPERATION_FAILED; } static int imx31_reset(struct nand_device *nand) { /* * validate target state */ int validate_target_result; validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; initialize_nf_controller(nand); return ERROR_OK; } static int imx31_command(struct nand_device *nand, uint8_t command) { struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; struct target *target = nand->target; { /* * validate target state */ int validate_target_result; validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; } switch (command) { case NAND_CMD_READOOB: command = NAND_CMD_READ0; in_sram_address = MX3_NF_SPARE_BUFFER0; /* set read point for * data_read() and * read_block_data() to * spare area in SRAM * buffer */ break; case NAND_CMD_READ1: command = NAND_CMD_READ0; /* * offset == one half of page size */ in_sram_address = MX3_NF_MAIN_BUFFER0 + (nand->page_size >> 1); break; default: in_sram_address = MX3_NF_MAIN_BUFFER0; } target_write_u16(target, MX3_NF_FCMD, command); /* * start command input operation (set MX3_NF_BIT_OP_DONE==0) */ target_write_u16(target, MX3_NF_CFG2, MX3_NF_BIT_OP_FCI); { int poll_result; poll_result = poll_for_complete_op(target, "command"); if (poll_result != ERROR_OK) return poll_result; } /* * reset cursor to begin of the buffer */ sign_of_sequental_byte_read = 0; switch (command) { case NAND_CMD_READID: mx3_nf_info->optype = MX3_NF_DATAOUT_NANDID; mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; break; case NAND_CMD_STATUS: mx3_nf_info->optype = MX3_NF_DATAOUT_NANDSTATUS; mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; break; case NAND_CMD_READ0: mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; break; default: mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; } return ERROR_OK; } static int imx31_address(struct nand_device *nand, uint8_t address) { struct target *target = nand->target; { /* * validate target state */ int validate_target_result; validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; } target_write_u16(target, MX3_NF_FADDR, address); /* * start address input operation (set MX3_NF_BIT_OP_DONE==0) */ target_write_u16(target, MX3_NF_CFG2, MX3_NF_BIT_OP_FAI); { int poll_result; poll_result = poll_for_complete_op(target, "address"); if (poll_result != ERROR_OK) return poll_result; } return ERROR_OK; } static int imx31_nand_ready(struct nand_device *nand, int tout) { uint16_t poll_complete_status; struct target *target = nand->target; { /* * validate target state */ int validate_target_result; validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; } do { target_read_u16(target, MX3_NF_CFG2, &poll_complete_status); if (poll_complete_status & MX3_NF_BIT_OP_DONE) return tout; alive_sleep(1); } while (tout-- > 0); return tout; } static int imx31_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; struct target *target = nand->target; if (data_size % 2) { LOG_ERROR(data_block_size_err_msg, data_size); return ERROR_NAND_OPERATION_FAILED; } if (oob_size % 2) { LOG_ERROR(data_block_size_err_msg, oob_size); return ERROR_NAND_OPERATION_FAILED; } if (!data) { LOG_ERROR("nothing to program"); return ERROR_NAND_OPERATION_FAILED; } { /* * validate target state */ int retval; retval = validate_target_state(nand); if (retval != ERROR_OK) return retval; } { int retval = ERROR_OK; retval |= imx31_command(nand, NAND_CMD_SEQIN); retval |= imx31_address(nand, 0x00); retval |= imx31_address(nand, page & 0xff); retval |= imx31_address(nand, (page >> 8) & 0xff); if (nand->address_cycles >= 4) { retval |= imx31_address(nand, (page >> 16) & 0xff); if (nand->address_cycles >= 5) retval |= imx31_address(nand, (page >> 24) & 0xff); } target_write_buffer(target, MX3_NF_MAIN_BUFFER0, data_size, data); if (oob) { if (mx3_nf_info->flags.hw_ecc_enabled) { /* * part of spare block will be overridden by hardware * ECC generator */ LOG_DEBUG("part of spare block will be overridden by hardware ECC generator"); } target_write_buffer(target, MX3_NF_SPARE_BUFFER0, oob_size, oob); } /* * start data input operation (set MX3_NF_BIT_OP_DONE==0) */ target_write_u16(target, MX3_NF_CFG2, MX3_NF_BIT_OP_FDI); { int poll_result; poll_result = poll_for_complete_op(target, "data input"); if (poll_result != ERROR_OK) return poll_result; } retval |= imx31_command(nand, NAND_CMD_PAGEPROG); if (retval != ERROR_OK) return retval; /* * check status register */ { uint16_t nand_status_content; retval = ERROR_OK; retval |= imx31_command(nand, NAND_CMD_STATUS); retval |= imx31_address(nand, 0x00); retval |= do_data_output(nand); if (retval != ERROR_OK) { LOG_ERROR(get_status_register_err_msg); return retval; } target_read_u16(target, MX3_NF_MAIN_BUFFER0, &nand_status_content); if (nand_status_content & 0x0001) { /* * is host-big-endian correctly ?? */ return ERROR_NAND_OPERATION_FAILED; } } } return ERROR_OK; } static int imx31_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct target *target = nand->target; if (data_size % 2) { LOG_ERROR(data_block_size_err_msg, data_size); return ERROR_NAND_OPERATION_FAILED; } if (oob_size % 2) { LOG_ERROR(data_block_size_err_msg, oob_size); return ERROR_NAND_OPERATION_FAILED; } { /* * validate target state */ int retval; retval = validate_target_state(nand); if (retval != ERROR_OK) return retval; } { int retval = ERROR_OK; retval |= imx31_command(nand, NAND_CMD_READ0); retval |= imx31_address(nand, 0x00); retval |= imx31_address(nand, page & 0xff); retval |= imx31_address(nand, (page >> 8) & 0xff); if (nand->address_cycles >= 4) { retval |= imx31_address(nand, (page >> 16) & 0xff); if (nand->address_cycles >= 5) { retval |= imx31_address(nand, (page >> 24) & 0xff); retval |= imx31_command(nand, NAND_CMD_READSTART); } } retval |= do_data_output(nand); if (retval != ERROR_OK) return retval; if (data) { target_read_buffer(target, MX3_NF_MAIN_BUFFER0, data_size, data); } if (oob) { target_read_buffer(target, MX3_NF_SPARE_BUFFER0, oob_size, oob); } } return ERROR_OK; } static int test_iomux_settings(struct target *target, uint32_t address, uint32_t mask, const char *text) { uint32_t register_content; target_read_u32(target, address, ®ister_content); if ((register_content & mask) != (0x12121212 & mask)) { LOG_ERROR("IOMUX for {%s} is bad", text); return ERROR_FAIL; } return ERROR_OK; } static int initialize_nf_controller(struct nand_device *nand) { struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; struct target *target = nand->target; /* * resets NAND flash controller in zero time ? I don't know. */ target_write_u16(target, MX3_NF_CFG1, MX3_NF_BIT_RESET_EN); { uint16_t work_mode; work_mode = MX3_NF_BIT_INT_DIS; /* disable interrupt */ if (target->endianness == TARGET_BIG_ENDIAN) work_mode |= MX3_NF_BIT_BE_EN; if (mx3_nf_info->flags.hw_ecc_enabled) work_mode |= MX3_NF_BIT_ECC_EN; target_write_u16(target, MX3_NF_CFG1, work_mode); } /* * unlock SRAM buffer for write; 2 mean "Unlock", other values means "Lock" */ target_write_u16(target, MX3_NF_BUFCFG, 2); { uint16_t temp; target_read_u16(target, MX3_NF_FWP, &temp); if ((temp & 0x0007) == 1) { LOG_ERROR("NAND flash is tight-locked, reset needed"); return ERROR_FAIL; } } /* * unlock NAND flash for write */ target_write_u16(target, MX3_NF_FWP, 4); target_write_u16(target, MX3_NF_LOCKSTART, 0x0000); target_write_u16(target, MX3_NF_LOCKEND, 0xFFFF); /* * 0x0000 means that first SRAM buffer @0xB800_0000 will be used */ target_write_u16(target, MX3_NF_BUFADDR, 0x0000); /* * address of SRAM buffer */ in_sram_address = MX3_NF_MAIN_BUFFER0; sign_of_sequental_byte_read = 0; return ERROR_OK; } static int get_next_byte_from_sram_buffer(struct target *target, uint8_t *value) { static uint8_t even_byte; /* * host-big_endian ?? */ if (sign_of_sequental_byte_read == 0) even_byte = 0; if (in_sram_address > MX3_NF_LAST_BUFFER_ADDR) { LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address); *value = 0; sign_of_sequental_byte_read = 0; even_byte = 0; return ERROR_NAND_OPERATION_FAILED; } else { uint16_t temp; target_read_u16(target, in_sram_address, &temp); if (even_byte) { *value = temp >> 8; even_byte = 0; in_sram_address += 2; } else { *value = temp & 0xff; even_byte = 1; } } sign_of_sequental_byte_read = 1; return ERROR_OK; } static int get_next_halfword_from_sram_buffer(struct target *target, uint16_t *value) { if (in_sram_address > MX3_NF_LAST_BUFFER_ADDR) { LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address); *value = 0; return ERROR_NAND_OPERATION_FAILED; } else { target_read_u16(target, in_sram_address, value); in_sram_address += 2; } return ERROR_OK; } static int poll_for_complete_op(struct target *target, const char *text) { uint16_t poll_complete_status; for (int poll_cycle_count = 0; poll_cycle_count < 100; poll_cycle_count++) { usleep(25); target_read_u16(target, MX3_NF_CFG2, &poll_complete_status); if (poll_complete_status & MX3_NF_BIT_OP_DONE) break; } if (!(poll_complete_status & MX3_NF_BIT_OP_DONE)) { LOG_ERROR("%s sending timeout", text); return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } static int validate_target_state(struct nand_device *nand) { struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR(target_not_halted_err_msg); return ERROR_NAND_OPERATION_FAILED; } if (mx3_nf_info->flags.target_little_endian != (target->endianness == TARGET_LITTLE_ENDIAN)) { /* * endianness changed after NAND controller probed */ return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } static int do_data_output(struct nand_device *nand) { struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; struct target *target = nand->target; switch (mx3_nf_info->fin) { case MX3_NF_FIN_DATAOUT: /* * start data output operation (set MX3_NF_BIT_OP_DONE==0) */ target_write_u16 (target, MX3_NF_CFG2, MX3_NF_BIT_DATAOUT_TYPE(mx3_nf_info->optype)); { int poll_result; poll_result = poll_for_complete_op(target, "data output"); if (poll_result != ERROR_OK) return poll_result; } mx3_nf_info->fin = MX3_NF_FIN_NONE; /* * ECC stuff */ if ((mx3_nf_info->optype == MX3_NF_DATAOUT_PAGE) && mx3_nf_info->flags.hw_ecc_enabled) { uint16_t ecc_status; target_read_u16 (target, MX3_NF_ECCSTATUS, &ecc_status); switch (ecc_status & 0x000c) { case 1 << 2: LOG_DEBUG("main area read with 1 (correctable) error"); break; case 2 << 2: LOG_DEBUG("main area read with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; } switch (ecc_status & 0x0003) { case 1: LOG_DEBUG("spare area read with 1 (correctable) error"); break; case 2: LOG_DEBUG("main area read with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; } } break; case MX3_NF_FIN_NONE: break; } return ERROR_OK; } struct nand_flash_controller imx31_nand_flash_controller = { .name = "imx31", .usage = "nand device imx31 target noecc|hwecc", .nand_device_command = &imx31_nand_device_command, .init = &imx31_init, .reset = &imx31_reset, .command = &imx31_command, .address = &imx31_address, .write_data = &imx31_write_data, .read_data = &imx31_read_data, .write_page = &imx31_write_page, .read_page = &imx31_read_page, .nand_ready = &imx31_nand_ready, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/mx3.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 by Alexei Babich * * Rezonans plc., Chelyabinsk, Russia * * impatt@mail.ru * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_MX3_H #define OPENOCD_FLASH_NAND_MX3_H /* * Freescale iMX3* OpenOCD NAND Flash controller support. * * Many thanks to Ben Dooks for writing s3c24xx driver. */ #define MX3_NF_BASE_ADDR 0xb8000000 #define MX3_NF_BUFSIZ (MX3_NF_BASE_ADDR + 0xe00) #define MX3_NF_BUFADDR (MX3_NF_BASE_ADDR + 0xe04) #define MX3_NF_FADDR (MX3_NF_BASE_ADDR + 0xe06) #define MX3_NF_FCMD (MX3_NF_BASE_ADDR + 0xe08) #define MX3_NF_BUFCFG (MX3_NF_BASE_ADDR + 0xe0a) #define MX3_NF_ECCSTATUS (MX3_NF_BASE_ADDR + 0xe0c) #define MX3_NF_ECCMAINPOS (MX3_NF_BASE_ADDR + 0xe0e) #define MX3_NF_ECCSPAREPOS (MX3_NF_BASE_ADDR + 0xe10) #define MX3_NF_FWP (MX3_NF_BASE_ADDR + 0xe12) #define MX3_NF_LOCKSTART (MX3_NF_BASE_ADDR + 0xe14) #define MX3_NF_LOCKEND (MX3_NF_BASE_ADDR + 0xe16) #define MX3_NF_FWPSTATUS (MX3_NF_BASE_ADDR + 0xe18) /* * all bits not marked as self-clearing bit */ #define MX3_NF_CFG1 (MX3_NF_BASE_ADDR + 0xe1a) #define MX3_NF_CFG2 (MX3_NF_BASE_ADDR + 0xe1c) #define MX3_NF_MAIN_BUFFER0 (MX3_NF_BASE_ADDR + 0x0000) #define MX3_NF_MAIN_BUFFER1 (MX3_NF_BASE_ADDR + 0x0200) #define MX3_NF_MAIN_BUFFER2 (MX3_NF_BASE_ADDR + 0x0400) #define MX3_NF_MAIN_BUFFER3 (MX3_NF_BASE_ADDR + 0x0600) #define MX3_NF_SPARE_BUFFER0 (MX3_NF_BASE_ADDR + 0x0800) #define MX3_NF_SPARE_BUFFER1 (MX3_NF_BASE_ADDR + 0x0810) #define MX3_NF_SPARE_BUFFER2 (MX3_NF_BASE_ADDR + 0x0820) #define MX3_NF_SPARE_BUFFER3 (MX3_NF_BASE_ADDR + 0x0830) #define MX3_NF_MAIN_BUFFER_LEN 512 #define MX3_NF_SPARE_BUFFER_LEN 16 #define MX3_NF_LAST_BUFFER_ADDR ((MX3_NF_SPARE_BUFFER3) + MX3_NF_SPARE_BUFFER_LEN - 2) /* bits in MX3_NF_CFG1 register */ #define MX3_NF_BIT_SPARE_ONLY_EN (1<<2) #define MX3_NF_BIT_ECC_EN (1<<3) #define MX3_NF_BIT_INT_DIS (1<<4) #define MX3_NF_BIT_BE_EN (1<<5) #define MX3_NF_BIT_RESET_EN (1<<6) #define MX3_NF_BIT_FORCE_CE (1<<7) /* bits in MX3_NF_CFG2 register */ /*Flash Command Input*/ #define MX3_NF_BIT_OP_FCI (1<<0) /* * Flash Address Input */ #define MX3_NF_BIT_OP_FAI (1<<1) /* * Flash Data Input */ #define MX3_NF_BIT_OP_FDI (1<<2) /* see "enum mx_dataout_type" below */ #define MX3_NF_BIT_DATAOUT_TYPE(x) ((x)<<3) #define MX3_NF_BIT_OP_DONE (1<<15) #define MX3_CCM_CGR2 0x53f80028 #define MX3_GPR 0x43fac008 #define MX3_PCSR 0x53f8000c enum mx_dataout_type { MX3_NF_DATAOUT_PAGE = 1, MX3_NF_DATAOUT_NANDID = 2, MX3_NF_DATAOUT_NANDSTATUS = 4, }; enum mx_nf_finalize_action { MX3_NF_FIN_NONE, MX3_NF_FIN_DATAOUT, }; struct mx3_nf_flags { unsigned target_little_endian:1; unsigned nand_readonly:1; unsigned one_kb_sram:1; unsigned hw_ecc_enabled:1; }; struct mx3_nf_controller { enum mx_dataout_type optype; enum mx_nf_finalize_action fin; struct mx3_nf_flags flags; }; #endif /* OPENOCD_FLASH_NAND_MX3_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/mxc.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by Alexei Babich * * Rezonans plc., Chelyabinsk, Russia * * impatt@mail.ru * * * * Copyright (C) 2010 by Gaetan CARLIER * * Trump s.a., Belgium * * * * Copyright (C) 2011 by Erik Ahlen * * Avalon Innovation, Sweden * ***************************************************************************/ /* * Freescale iMX OpenOCD NAND Flash controller support. * based on Freescale iMX2* and iMX3* OpenOCD NAND Flash controller support. */ /* * driver tested with Samsung K9F2G08UXA and Numonyx/ST NAND02G-B2D @mxc * tested "nand probe #", "nand erase # 0 #", "nand dump # file 0 #", * "nand write # file 0", "nand verify" * * get_next_halfword_from_sram_buffer() not tested * !! all function only tested with 2k page nand device; mxc_write_page * writes the 4 MAIN_BUFFER's and is not compatible with < 2k page * !! oob must be be used due to NFS bug * !! oob must be 64 bytes per 2KiB page */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "mxc.h" #include <target/target.h> #define OOB_SIZE 64 #define nfc_is_v1() (mxc_nf_info->mxc_version == MXC_VERSION_MX27 || \ mxc_nf_info->mxc_version == MXC_VERSION_MX31) #define nfc_is_v2() (mxc_nf_info->mxc_version == MXC_VERSION_MX25 || \ mxc_nf_info->mxc_version == MXC_VERSION_MX35) /* This permits to print (in LOG_INFO) how much bytes * has been written after a page read or write. * This is useful when OpenOCD is used with a graphical * front-end to estimate progression of the global read/write */ #undef _MXC_PRINT_STAT /* #define _MXC_PRINT_STAT */ static const char target_not_halted_err_msg[] = "target must be halted to use mxc NAND flash controller"; static const char data_block_size_err_msg[] = "minimal granularity is one half-word, %" PRIu32 " is incorrect"; static const char sram_buffer_bounds_err_msg[] = "trying to access out of SRAM buffer bound (addr=0x%" PRIx32 ")"; static const char get_status_register_err_msg[] = "can't get NAND status"; static uint32_t in_sram_address; static unsigned char sign_of_sequental_byte_read; static uint32_t align_address_v2(struct nand_device *nand, uint32_t addr); static int initialize_nf_controller(struct nand_device *nand); static int get_next_byte_from_sram_buffer(struct nand_device *nand, uint8_t *value); static int get_next_halfword_from_sram_buffer(struct nand_device *nand, uint16_t *value); static int poll_for_complete_op(struct nand_device *nand, const char *text); static int validate_target_state(struct nand_device *nand); static int do_data_output(struct nand_device *nand); static int mxc_command(struct nand_device *nand, uint8_t command); static int mxc_address(struct nand_device *nand, uint8_t address); NAND_DEVICE_COMMAND_HANDLER(mxc_nand_device_command) { struct mxc_nf_controller *mxc_nf_info; int hwecc_needed; mxc_nf_info = malloc(sizeof(struct mxc_nf_controller)); if (!mxc_nf_info) { LOG_ERROR("no memory for nand controller"); return ERROR_FAIL; } nand->controller_priv = mxc_nf_info; if (CMD_ARGC < 4) { LOG_ERROR("use \"nand device mxc target mx25|mx27|mx31|mx35 noecc|hwecc [biswap]\""); return ERROR_FAIL; } /* * check board type */ if (strcmp(CMD_ARGV[2], "mx25") == 0) { mxc_nf_info->mxc_version = MXC_VERSION_MX25; mxc_nf_info->mxc_base_addr = 0xBB000000; mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x1E00; } else if (strcmp(CMD_ARGV[2], "mx27") == 0) { mxc_nf_info->mxc_version = MXC_VERSION_MX27; mxc_nf_info->mxc_base_addr = 0xD8000000; mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x0E00; } else if (strcmp(CMD_ARGV[2], "mx31") == 0) { mxc_nf_info->mxc_version = MXC_VERSION_MX31; mxc_nf_info->mxc_base_addr = 0xB8000000; mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x0E00; } else if (strcmp(CMD_ARGV[2], "mx35") == 0) { mxc_nf_info->mxc_version = MXC_VERSION_MX35; mxc_nf_info->mxc_base_addr = 0xBB000000; mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x1E00; } /* * check hwecc requirements */ hwecc_needed = strcmp(CMD_ARGV[3], "hwecc"); if (hwecc_needed == 0) mxc_nf_info->flags.hw_ecc_enabled = 1; else mxc_nf_info->flags.hw_ecc_enabled = 0; mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE; mxc_nf_info->fin = MXC_NF_FIN_NONE; mxc_nf_info->flags.target_little_endian = (nand->target->endianness == TARGET_LITTLE_ENDIAN); /* * should factory bad block indicator be swapped * as a workaround for how the nfc handles pages. */ if (CMD_ARGC > 4 && strcmp(CMD_ARGV[4], "biswap") == 0) { LOG_DEBUG("BI-swap enabled"); mxc_nf_info->flags.biswap_enabled = 1; } return ERROR_OK; } COMMAND_HANDLER(handle_mxc_biswap_command) { struct nand_device *nand = NULL; struct mxc_nf_controller *mxc_nf_info = NULL; if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &nand); if (retval != ERROR_OK) { command_print(CMD, "invalid nand device number or name: %s", CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } mxc_nf_info = nand->controller_priv; if (CMD_ARGC == 2) { if (strcmp(CMD_ARGV[1], "enable") == 0) mxc_nf_info->flags.biswap_enabled = true; else mxc_nf_info->flags.biswap_enabled = false; } if (mxc_nf_info->flags.biswap_enabled) command_print(CMD, "BI-swapping enabled on %s", nand->name); else command_print(CMD, "BI-swapping disabled on %s", nand->name); return ERROR_OK; } static const struct command_registration mxc_sub_command_handlers[] = { { .name = "biswap", .mode = COMMAND_EXEC, .handler = handle_mxc_biswap_command, .help = "Turns on/off bad block information swapping from main area, " "without parameter query status.", .usage = "bank_id ['enable'|'disable']", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration mxc_nand_command_handler[] = { { .name = "mxc", .mode = COMMAND_ANY, .help = "MXC NAND flash controller commands", .chain = mxc_sub_command_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static int mxc_init(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; int validate_target_result; uint16_t buffsize_register_content; uint32_t sreg_content; uint32_t sreg = MX2_FMCR; uint32_t sel_16bit = MX2_FMCR_NF_16BIT_SEL; uint32_t sel_fms = MX2_FMCR_NF_FMS; int retval; uint16_t nand_status_content; /* * validate target state */ validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; if (nfc_is_v1()) { target_read_u16(target, MXC_NF_BUFSIZ, &buffsize_register_content); mxc_nf_info->flags.one_kb_sram = !(buffsize_register_content & 0x000f); } else mxc_nf_info->flags.one_kb_sram = 0; if (mxc_nf_info->mxc_version == MXC_VERSION_MX31) { sreg = MX3_PCSR; sel_16bit = MX3_PCSR_NF_16BIT_SEL; sel_fms = MX3_PCSR_NF_FMS; } else if (mxc_nf_info->mxc_version == MXC_VERSION_MX25) { sreg = MX25_RCSR; sel_16bit = MX25_RCSR_NF_16BIT_SEL; sel_fms = MX25_RCSR_NF_FMS; } else if (mxc_nf_info->mxc_version == MXC_VERSION_MX35) { sreg = MX35_RCSR; sel_16bit = MX35_RCSR_NF_16BIT_SEL; sel_fms = MX35_RCSR_NF_FMS; } target_read_u32(target, sreg, &sreg_content); if (!nand->bus_width) { /* bus_width not yet defined. Read it from MXC_FMCR */ nand->bus_width = (sreg_content & sel_16bit) ? 16 : 8; } else { /* bus_width forced in soft. Sync it to MXC_FMCR */ sreg_content |= ((nand->bus_width == 16) ? sel_16bit : 0x00000000); target_write_u32(target, sreg, sreg_content); } if (nand->bus_width == 16) LOG_DEBUG("MXC_NF : bus is 16-bit width"); else LOG_DEBUG("MXC_NF : bus is 8-bit width"); if (!nand->page_size) nand->page_size = (sreg_content & sel_fms) ? 2048 : 512; else { sreg_content |= ((nand->page_size == 2048) ? sel_fms : 0x00000000); target_write_u32(target, sreg, sreg_content); } if (mxc_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) { LOG_ERROR("NAND controller have only 1 kb SRAM, so " "pagesize 2048 is incompatible with it"); } else LOG_DEBUG("MXC_NF : NAND controller can handle pagesize of 2048"); if (nfc_is_v2() && sreg_content & MX35_RCSR_NF_4K) LOG_ERROR("MXC driver does not have support for 4k pagesize."); initialize_nf_controller(nand); retval = ERROR_OK; retval |= mxc_command(nand, NAND_CMD_STATUS); retval |= mxc_address(nand, 0x00); retval |= do_data_output(nand); if (retval != ERROR_OK) { LOG_ERROR(get_status_register_err_msg); return ERROR_FAIL; } target_read_u16(target, MXC_NF_MAIN_BUFFER0, &nand_status_content); if (!(nand_status_content & 0x0080)) { LOG_INFO("NAND read-only"); mxc_nf_info->flags.nand_readonly = 1; } else mxc_nf_info->flags.nand_readonly = 0; return ERROR_OK; } static int mxc_read_data(struct nand_device *nand, void *data) { int validate_target_result; int try_data_output_from_nand_chip; /* * validate target state */ validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; /* * get data from nand chip */ try_data_output_from_nand_chip = do_data_output(nand); if (try_data_output_from_nand_chip != ERROR_OK) { LOG_ERROR("mxc_read_data : read data failed : '%x'", try_data_output_from_nand_chip); return try_data_output_from_nand_chip; } if (nand->bus_width == 16) get_next_halfword_from_sram_buffer(nand, data); else get_next_byte_from_sram_buffer(nand, data); return ERROR_OK; } static int mxc_write_data(struct nand_device *nand, uint16_t data) { LOG_ERROR("write_data() not implemented"); return ERROR_NAND_OPERATION_FAILED; } static int mxc_reset(struct nand_device *nand) { /* * validate target state */ int validate_target_result; validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; initialize_nf_controller(nand); return ERROR_OK; } static int mxc_command(struct nand_device *nand, uint8_t command) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; int validate_target_result; int poll_result; /* * validate target state */ validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; switch (command) { case NAND_CMD_READOOB: command = NAND_CMD_READ0; /* set read point for data_read() and read_block_data() to * spare area in SRAM buffer */ if (nfc_is_v1()) in_sram_address = MXC_NF_V1_SPARE_BUFFER0; else in_sram_address = MXC_NF_V2_SPARE_BUFFER0; break; case NAND_CMD_READ1: command = NAND_CMD_READ0; /* * offset == one half of page size */ in_sram_address = MXC_NF_MAIN_BUFFER0 + (nand->page_size >> 1); break; default: in_sram_address = MXC_NF_MAIN_BUFFER0; break; } target_write_u16(target, MXC_NF_FCMD, command); /* * start command input operation (set MXC_NF_BIT_OP_DONE==0) */ target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FCI); poll_result = poll_for_complete_op(nand, "command"); if (poll_result != ERROR_OK) return poll_result; /* * reset cursor to begin of the buffer */ sign_of_sequental_byte_read = 0; /* Handle special read command and adjust NF_CFG2(FDO) */ switch (command) { case NAND_CMD_READID: mxc_nf_info->optype = MXC_NF_DATAOUT_NANDID; mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; break; case NAND_CMD_STATUS: mxc_nf_info->optype = MXC_NF_DATAOUT_NANDSTATUS; mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; target_write_u16 (target, MXC_NF_BUFADDR, 0); in_sram_address = 0; break; case NAND_CMD_READ0: mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE; break; default: /* Other command use the default 'One page data out' FDO */ mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE; break; } return ERROR_OK; } static int mxc_address(struct nand_device *nand, uint8_t address) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; int validate_target_result; int poll_result; /* * validate target state */ validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; target_write_u16(target, MXC_NF_FADDR, address); /* * start address input operation (set MXC_NF_BIT_OP_DONE==0) */ target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FAI); poll_result = poll_for_complete_op(nand, "address"); if (poll_result != ERROR_OK) return poll_result; return ERROR_OK; } static int mxc_nand_ready(struct nand_device *nand, int tout) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; uint16_t poll_complete_status; int validate_target_result; /* * validate target state */ validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; do { target_read_u16(target, MXC_NF_CFG2, &poll_complete_status); if (poll_complete_status & MXC_NF_BIT_OP_DONE) return tout; alive_sleep(1); } while (tout-- > 0); return tout; } static int mxc_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; int retval; uint16_t nand_status_content; uint16_t swap1, swap2, new_swap1; uint8_t bufs; int poll_result; if (data_size % 2) { LOG_ERROR(data_block_size_err_msg, data_size); return ERROR_NAND_OPERATION_FAILED; } if (oob_size % 2) { LOG_ERROR(data_block_size_err_msg, oob_size); return ERROR_NAND_OPERATION_FAILED; } if (!data) { LOG_ERROR("nothing to program"); return ERROR_NAND_OPERATION_FAILED; } /* * validate target state */ retval = validate_target_state(nand); if (retval != ERROR_OK) return retval; in_sram_address = MXC_NF_MAIN_BUFFER0; sign_of_sequental_byte_read = 0; retval = ERROR_OK; retval |= mxc_command(nand, NAND_CMD_SEQIN); retval |= mxc_address(nand, 0); /* col */ retval |= mxc_address(nand, 0); /* col */ retval |= mxc_address(nand, page & 0xff); /* page address */ retval |= mxc_address(nand, (page >> 8) & 0xff);/* page address */ retval |= mxc_address(nand, (page >> 16) & 0xff); /* page address */ target_write_buffer(target, MXC_NF_MAIN_BUFFER0, data_size, data); if (oob) { if (mxc_nf_info->flags.hw_ecc_enabled) { /* * part of spare block will be overridden by hardware * ECC generator */ LOG_DEBUG("part of spare block will be overridden " "by hardware ECC generator"); } if (nfc_is_v1()) target_write_buffer(target, MXC_NF_V1_SPARE_BUFFER0, oob_size, oob); else { uint32_t addr = MXC_NF_V2_SPARE_BUFFER0; while (oob_size > 0) { uint8_t len = MIN(oob_size, MXC_NF_SPARE_BUFFER_LEN); target_write_buffer(target, addr, len, oob); addr = align_address_v2(nand, addr + len); oob += len; oob_size -= len; } } } if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) { /* BI-swap - work-around of i.MX NFC for NAND device with page == 2kb*/ target_read_u16(target, MXC_NF_MAIN_BUFFER3 + 464, &swap1); if (oob) { LOG_ERROR("Due to NFC Bug, oob is not correctly implemented in mxc driver"); return ERROR_NAND_OPERATION_FAILED; } swap2 = 0xffff; /* Spare buffer unused forced to 0xffff */ new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8); swap2 = (swap1 << 8) | (swap2 & 0xFF); target_write_u16(target, MXC_NF_MAIN_BUFFER3 + 464, new_swap1); if (nfc_is_v1()) target_write_u16(target, MXC_NF_V1_SPARE_BUFFER3 + 4, swap2); else target_write_u16(target, MXC_NF_V2_SPARE_BUFFER3, swap2); } /* * start data input operation (set MXC_NF_BIT_OP_DONE==0) */ if (nfc_is_v1() && nand->page_size > 512) bufs = 4; else bufs = 1; for (uint8_t i = 0; i < bufs; ++i) { target_write_u16(target, MXC_NF_BUFADDR, i); target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FDI); poll_result = poll_for_complete_op(nand, "data input"); if (poll_result != ERROR_OK) return poll_result; } retval |= mxc_command(nand, NAND_CMD_PAGEPROG); if (retval != ERROR_OK) return retval; /* * check status register */ retval = ERROR_OK; retval |= mxc_command(nand, NAND_CMD_STATUS); target_write_u16 (target, MXC_NF_BUFADDR, 0); mxc_nf_info->optype = MXC_NF_DATAOUT_NANDSTATUS; mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; retval |= do_data_output(nand); if (retval != ERROR_OK) { LOG_ERROR(get_status_register_err_msg); return retval; } target_read_u16(target, MXC_NF_MAIN_BUFFER0, &nand_status_content); if (nand_status_content & 0x0001) { /* * page not correctly written */ return ERROR_NAND_OPERATION_FAILED; } #ifdef _MXC_PRINT_STAT LOG_INFO("%d bytes newly written", data_size); #endif return ERROR_OK; } static int mxc_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; int retval; uint8_t bufs; uint16_t swap1, swap2, new_swap1; if (data_size % 2) { LOG_ERROR(data_block_size_err_msg, data_size); return ERROR_NAND_OPERATION_FAILED; } if (oob_size % 2) { LOG_ERROR(data_block_size_err_msg, oob_size); return ERROR_NAND_OPERATION_FAILED; } /* * validate target state */ retval = validate_target_state(nand); if (retval != ERROR_OK) return retval; /* Reset address_cycles before mxc_command ?? */ retval = mxc_command(nand, NAND_CMD_READ0); if (retval != ERROR_OK) return retval; retval = mxc_address(nand, 0); /* col */ if (retval != ERROR_OK) return retval; retval = mxc_address(nand, 0); /* col */ if (retval != ERROR_OK) return retval; retval = mxc_address(nand, page & 0xff);/* page address */ if (retval != ERROR_OK) return retval; retval = mxc_address(nand, (page >> 8) & 0xff); /* page address */ if (retval != ERROR_OK) return retval; retval = mxc_address(nand, (page >> 16) & 0xff);/* page address */ if (retval != ERROR_OK) return retval; retval = mxc_command(nand, NAND_CMD_READSTART); if (retval != ERROR_OK) return retval; if (nfc_is_v1() && nand->page_size > 512) bufs = 4; else bufs = 1; for (uint8_t i = 0; i < bufs; ++i) { target_write_u16(target, MXC_NF_BUFADDR, i); mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; retval = do_data_output(nand); if (retval != ERROR_OK) { LOG_ERROR("MXC_NF : Error reading page %d", i); return retval; } } if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) { uint32_t spare_buffer3; /* BI-swap - work-around of mxc NFC for NAND device with page == 2k */ target_read_u16(target, MXC_NF_MAIN_BUFFER3 + 464, &swap1); if (nfc_is_v1()) spare_buffer3 = MXC_NF_V1_SPARE_BUFFER3 + 4; else spare_buffer3 = MXC_NF_V2_SPARE_BUFFER3; target_read_u16(target, spare_buffer3, &swap2); new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8); swap2 = (swap1 << 8) | (swap2 & 0xFF); target_write_u16(target, MXC_NF_MAIN_BUFFER3 + 464, new_swap1); target_write_u16(target, spare_buffer3, swap2); } if (data) target_read_buffer(target, MXC_NF_MAIN_BUFFER0, data_size, data); if (oob) { if (nfc_is_v1()) target_read_buffer(target, MXC_NF_V1_SPARE_BUFFER0, oob_size, oob); else { uint32_t addr = MXC_NF_V2_SPARE_BUFFER0; while (oob_size > 0) { uint8_t len = MIN(oob_size, MXC_NF_SPARE_BUFFER_LEN); target_read_buffer(target, addr, len, oob); addr = align_address_v2(nand, addr + len); oob += len; oob_size -= len; } } } #ifdef _MXC_PRINT_STAT if (data_size > 0) { /* When Operation Status is read (when page is erased), * this function is used but data_size is null. */ LOG_INFO("%d bytes newly read", data_size); } #endif return ERROR_OK; } static uint32_t align_address_v2(struct nand_device *nand, uint32_t addr) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; uint32_t ret = addr; if (addr > MXC_NF_V2_SPARE_BUFFER0 && (addr & 0x1F) == MXC_NF_SPARE_BUFFER_LEN) ret += MXC_NF_SPARE_BUFFER_MAX - MXC_NF_SPARE_BUFFER_LEN; else if (addr >= (mxc_nf_info->mxc_base_addr + (uint32_t)nand->page_size)) ret = MXC_NF_V2_SPARE_BUFFER0; return ret; } static int initialize_nf_controller(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; uint16_t work_mode = 0; uint16_t temp; /* * resets NAND flash controller in zero time ? I don't know. */ target_write_u16(target, MXC_NF_CFG1, MXC_NF_BIT_RESET_EN); if (mxc_nf_info->mxc_version == MXC_VERSION_MX27) work_mode = MXC_NF_BIT_INT_DIS; /* disable interrupt */ if (target->endianness == TARGET_BIG_ENDIAN) { LOG_DEBUG("MXC_NF : work in Big Endian mode"); work_mode |= MXC_NF_BIT_BE_EN; } else LOG_DEBUG("MXC_NF : work in Little Endian mode"); if (mxc_nf_info->flags.hw_ecc_enabled) { LOG_DEBUG("MXC_NF : work with ECC mode"); work_mode |= MXC_NF_BIT_ECC_EN; } else LOG_DEBUG("MXC_NF : work without ECC mode"); if (nfc_is_v2()) { target_write_u16(target, MXC_NF_V2_SPAS, OOB_SIZE / 2); if (nand->page_size) { uint16_t pages_per_block = nand->erase_size / nand->page_size; work_mode |= MXC_NF_V2_CFG1_PPB(ffs(pages_per_block) - 6); } work_mode |= MXC_NF_BIT_ECC_4BIT; } target_write_u16(target, MXC_NF_CFG1, work_mode); /* * unlock SRAM buffer for write; 2 mean "Unlock", other values means "Lock" */ target_write_u16(target, MXC_NF_BUFCFG, 2); target_read_u16(target, MXC_NF_FWP, &temp); if ((temp & 0x0007) == 1) { LOG_ERROR("NAND flash is tight-locked, reset needed"); return ERROR_FAIL; } /* * unlock NAND flash for write */ if (nfc_is_v1()) { target_write_u16(target, MXC_NF_V1_UNLOCKSTART, 0x0000); target_write_u16(target, MXC_NF_V1_UNLOCKEND, 0xFFFF); } else { target_write_u16(target, MXC_NF_V2_UNLOCKSTART0, 0x0000); target_write_u16(target, MXC_NF_V2_UNLOCKSTART1, 0x0000); target_write_u16(target, MXC_NF_V2_UNLOCKSTART2, 0x0000); target_write_u16(target, MXC_NF_V2_UNLOCKSTART3, 0x0000); target_write_u16(target, MXC_NF_V2_UNLOCKEND0, 0xFFFF); target_write_u16(target, MXC_NF_V2_UNLOCKEND1, 0xFFFF); target_write_u16(target, MXC_NF_V2_UNLOCKEND2, 0xFFFF); target_write_u16(target, MXC_NF_V2_UNLOCKEND3, 0xFFFF); } target_write_u16(target, MXC_NF_FWP, 4); /* * 0x0000 means that first SRAM buffer @base_addr will be used */ target_write_u16(target, MXC_NF_BUFADDR, 0x0000); /* * address of SRAM buffer */ in_sram_address = MXC_NF_MAIN_BUFFER0; sign_of_sequental_byte_read = 0; return ERROR_OK; } static int get_next_byte_from_sram_buffer(struct nand_device *nand, uint8_t *value) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; static uint8_t even_byte; uint16_t temp; /* * host-big_endian ?? */ if (sign_of_sequental_byte_read == 0) even_byte = 0; if (in_sram_address > (nfc_is_v1() ? MXC_NF_V1_LAST_BUFFADDR : MXC_NF_V2_LAST_BUFFADDR)) { LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address); *value = 0; sign_of_sequental_byte_read = 0; even_byte = 0; return ERROR_NAND_OPERATION_FAILED; } else { if (nfc_is_v2()) in_sram_address = align_address_v2(nand, in_sram_address); target_read_u16(target, in_sram_address, &temp); if (even_byte) { *value = temp >> 8; even_byte = 0; in_sram_address += 2; } else { *value = temp & 0xff; even_byte = 1; } } sign_of_sequental_byte_read = 1; return ERROR_OK; } static int get_next_halfword_from_sram_buffer(struct nand_device *nand, uint16_t *value) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; if (in_sram_address > (nfc_is_v1() ? MXC_NF_V1_LAST_BUFFADDR : MXC_NF_V2_LAST_BUFFADDR)) { LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address); *value = 0; return ERROR_NAND_OPERATION_FAILED; } else { if (nfc_is_v2()) in_sram_address = align_address_v2(nand, in_sram_address); target_read_u16(target, in_sram_address, value); in_sram_address += 2; } return ERROR_OK; } static int poll_for_complete_op(struct nand_device *nand, const char *text) { if (mxc_nand_ready(nand, 1000) == -1) { LOG_ERROR("%s sending timeout", text); return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } static int validate_target_state(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR(target_not_halted_err_msg); return ERROR_NAND_OPERATION_FAILED; } if (mxc_nf_info->flags.target_little_endian != (target->endianness == TARGET_LITTLE_ENDIAN)) { /* * endianness changed after NAND controller probed */ return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } static int ecc_status_v1(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; uint16_t ecc_status; target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status); switch (ecc_status & 0x000c) { case 1 << 2: LOG_INFO("main area read with 1 (correctable) error"); break; case 2 << 2: LOG_INFO("main area read with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; } switch (ecc_status & 0x0003) { case 1: LOG_INFO("spare area read with 1 (correctable) error"); break; case 2: LOG_INFO("main area read with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } static int ecc_status_v2(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; uint16_t ecc_status; uint8_t no_subpages; uint8_t err; no_subpages = nand->page_size >> 9; target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status); do { err = ecc_status & 0xF; if (err > 4) { LOG_INFO("UnCorrectable RS-ECC Error"); return ERROR_NAND_OPERATION_FAILED; } else if (err > 0) LOG_INFO("%d Symbol Correctable RS-ECC Error", err); ecc_status >>= 4; } while (--no_subpages); return ERROR_OK; } static int do_data_output(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; int poll_result; switch (mxc_nf_info->fin) { case MXC_NF_FIN_DATAOUT: /* * start data output operation (set MXC_NF_BIT_OP_DONE==0) */ target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_DATAOUT_TYPE(mxc_nf_info->optype)); poll_result = poll_for_complete_op(nand, "data output"); if (poll_result != ERROR_OK) return poll_result; mxc_nf_info->fin = MXC_NF_FIN_NONE; /* * ECC stuff */ if (mxc_nf_info->optype == MXC_NF_DATAOUT_PAGE && mxc_nf_info->flags.hw_ecc_enabled) { int ecc_status; if (nfc_is_v1()) ecc_status = ecc_status_v1(nand); else ecc_status = ecc_status_v2(nand); if (ecc_status != ERROR_OK) return ecc_status; } break; case MXC_NF_FIN_NONE: break; } return ERROR_OK; } struct nand_flash_controller mxc_nand_flash_controller = { .name = "mxc", .nand_device_command = &mxc_nand_device_command, .commands = mxc_nand_command_handler, .init = &mxc_init, .reset = &mxc_reset, .command = &mxc_command, .address = &mxc_address, .write_data = &mxc_write_data, .read_data = &mxc_read_data, .write_page = &mxc_write_page, .read_page = &mxc_read_page, .nand_ready = &mxc_nand_ready, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/mxc.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 by Alexei Babich * * Rezonans plc., Chelyabinsk, Russia * * impatt@mail.ru * * * * Copyright (C) 2011 by Erik Ahlen * * Avalon Innovation, Sweden * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_MXC_H #define OPENOCD_FLASH_NAND_MXC_H /* * Freescale iMX OpenOCD NAND Flash controller support. * based on Freescale iMX2* and iMX3* OpenOCD NAND Flash controller support. * * Many thanks to Ben Dooks for writing s3c24xx driver. */ #define MXC_NF_BUFSIZ (mxc_nf_info->mxc_regs_addr + 0x00) #define MXC_NF_BUFADDR (mxc_nf_info->mxc_regs_addr + 0x04) #define MXC_NF_FADDR (mxc_nf_info->mxc_regs_addr + 0x06) #define MXC_NF_FCMD (mxc_nf_info->mxc_regs_addr + 0x08) #define MXC_NF_BUFCFG (mxc_nf_info->mxc_regs_addr + 0x0a) #define MXC_NF_ECCSTATUS (mxc_nf_info->mxc_regs_addr + 0x0c) #define MXC_NF_ECCMAINPOS (mxc_nf_info->mxc_regs_addr + 0x0e) #define MXC_NF_V1_ECCSPAREPOS (mxc_nf_info->mxc_regs_addr + 0x10) #define MXC_NF_V2_SPAS (mxc_nf_info->mxc_regs_addr + 0x10) #define MXC_NF_FWP (mxc_nf_info->mxc_regs_addr + 0x12) #define MXC_NF_V1_UNLOCKSTART (mxc_nf_info->mxc_regs_addr + 0x14) #define MXC_NF_V1_UNLOCKEND (mxc_nf_info->mxc_regs_addr + 0x16) #define MXC_NF_V2_UNLOCKSTART0 (mxc_nf_info->mxc_regs_addr + 0x20) #define MXC_NF_V2_UNLOCKSTART1 (mxc_nf_info->mxc_regs_addr + 0x24) #define MXC_NF_V2_UNLOCKSTART2 (mxc_nf_info->mxc_regs_addr + 0x28) #define MXC_NF_V2_UNLOCKSTART3 (mxc_nf_info->mxc_regs_addr + 0x2c) #define MXC_NF_V2_UNLOCKEND0 (mxc_nf_info->mxc_regs_addr + 0x22) #define MXC_NF_V2_UNLOCKEND1 (mxc_nf_info->mxc_regs_addr + 0x26) #define MXC_NF_V2_UNLOCKEND2 (mxc_nf_info->mxc_regs_addr + 0x2a) #define MXC_NF_V2_UNLOCKEND3 (mxc_nf_info->mxc_regs_addr + 0x2e) #define MXC_NF_FWPSTATUS (mxc_nf_info->mxc_regs_addr + 0x18) /* * all bits not marked as self-clearing bit */ #define MXC_NF_CFG1 (mxc_nf_info->mxc_regs_addr + 0x1a) #define MXC_NF_CFG2 (mxc_nf_info->mxc_regs_addr + 0x1c) #define MXC_NF_MAIN_BUFFER0 (mxc_nf_info->mxc_base_addr + 0x0000) #define MXC_NF_MAIN_BUFFER1 (mxc_nf_info->mxc_base_addr + 0x0200) #define MXC_NF_MAIN_BUFFER2 (mxc_nf_info->mxc_base_addr + 0x0400) #define MXC_NF_MAIN_BUFFER3 (mxc_nf_info->mxc_base_addr + 0x0600) #define MXC_NF_V1_SPARE_BUFFER0 (mxc_nf_info->mxc_base_addr + 0x0800) #define MXC_NF_V1_SPARE_BUFFER1 (mxc_nf_info->mxc_base_addr + 0x0810) #define MXC_NF_V1_SPARE_BUFFER2 (mxc_nf_info->mxc_base_addr + 0x0820) #define MXC_NF_V1_SPARE_BUFFER3 (mxc_nf_info->mxc_base_addr + 0x0830) #define MXC_NF_V2_MAIN_BUFFER4 (mxc_nf_info->mxc_base_addr + 0x0800) #define MXC_NF_V2_MAIN_BUFFER5 (mxc_nf_info->mxc_base_addr + 0x0a00) #define MXC_NF_V2_MAIN_BUFFER6 (mxc_nf_info->mxc_base_addr + 0x0c00) #define MXC_NF_V2_MAIN_BUFFER7 (mxc_nf_info->mxc_base_addr + 0x0e00) #define MXC_NF_V2_SPARE_BUFFER0 (mxc_nf_info->mxc_base_addr + 0x1000) #define MXC_NF_V2_SPARE_BUFFER1 (mxc_nf_info->mxc_base_addr + 0x1040) #define MXC_NF_V2_SPARE_BUFFER2 (mxc_nf_info->mxc_base_addr + 0x1080) #define MXC_NF_V2_SPARE_BUFFER3 (mxc_nf_info->mxc_base_addr + 0x10c0) #define MXC_NF_V2_SPARE_BUFFER4 (mxc_nf_info->mxc_base_addr + 0x1100) #define MXC_NF_V2_SPARE_BUFFER5 (mxc_nf_info->mxc_base_addr + 0x1140) #define MXC_NF_V2_SPARE_BUFFER6 (mxc_nf_info->mxc_base_addr + 0x1180) #define MXC_NF_V2_SPARE_BUFFER7 (mxc_nf_info->mxc_base_addr + 0x11c0) #define MXC_NF_MAIN_BUFFER_LEN 512 #define MXC_NF_SPARE_BUFFER_LEN 16 #define MXC_NF_SPARE_BUFFER_MAX 64 #define MXC_NF_V1_LAST_BUFFADDR ((MXC_NF_V1_SPARE_BUFFER3) + \ MXC_NF_SPARE_BUFFER_LEN - 2) #define MXC_NF_V2_LAST_BUFFADDR ((MXC_NF_V2_SPARE_BUFFER7) + \ MXC_NF_SPARE_BUFFER_LEN - 2) /* bits in MXC_NF_CFG1 register */ #define MXC_NF_BIT_ECC_4BIT (1<<0) #define MXC_NF_BIT_SPARE_ONLY_EN (1<<2) #define MXC_NF_BIT_ECC_EN (1<<3) #define MXC_NF_BIT_INT_DIS (1<<4) #define MXC_NF_BIT_BE_EN (1<<5) #define MXC_NF_BIT_RESET_EN (1<<6) #define MXC_NF_BIT_FORCE_CE (1<<7) #define MXC_NF_V2_CFG1_PPB(x) (((x) & 0x3) << 9) /* bits in MXC_NF_CFG2 register */ /*Flash Command Input*/ #define MXC_NF_BIT_OP_FCI (1<<0) /* * Flash Address Input */ #define MXC_NF_BIT_OP_FAI (1<<1) /* * Flash Data Input */ #define MXC_NF_BIT_OP_FDI (1<<2) /* see "enum mx_dataout_type" below */ #define MXC_NF_BIT_DATAOUT_TYPE(x) ((x)<<3) #define MXC_NF_BIT_OP_DONE (1<<15) #define MXC_CCM_CGR2 0x53f80028 #define MXC_GPR 0x43fac008 #define MX2_FMCR 0x10027814 #define MX2_FMCR_NF_16BIT_SEL (1<<4) #define MX2_FMCR_NF_FMS (1<<5) #define MX25_RCSR 0x53f80018 #define MX25_RCSR_NF_16BIT_SEL (1<<14) #define MX25_RCSR_NF_FMS (1<<8) #define MX25_RCSR_NF_4K (1<<9) #define MX3_PCSR 0x53f8000c #define MX3_PCSR_NF_16BIT_SEL (1<<31) #define MX3_PCSR_NF_FMS (1<<30) #define MX35_RCSR 0x53f80018 #define MX35_RCSR_NF_16BIT_SEL (1<<14) #define MX35_RCSR_NF_FMS (1<<8) #define MX35_RCSR_NF_4K (1<<9) enum mxc_version { MXC_VERSION_UKWN = 0, MXC_VERSION_MX25 = 1, MXC_VERSION_MX27 = 2, MXC_VERSION_MX31 = 3, MXC_VERSION_MX35 = 4 }; enum mxc_dataout_type { MXC_NF_DATAOUT_PAGE = 1, MXC_NF_DATAOUT_NANDID = 2, MXC_NF_DATAOUT_NANDSTATUS = 4, }; enum mxc_nf_finalize_action { MXC_NF_FIN_NONE, MXC_NF_FIN_DATAOUT, }; struct mxc_nf_flags { unsigned target_little_endian:1; unsigned nand_readonly:1; unsigned one_kb_sram:1; unsigned hw_ecc_enabled:1; unsigned biswap_enabled:1; }; struct mxc_nf_controller { enum mxc_version mxc_version; uint32_t mxc_base_addr; uint32_t mxc_regs_addr; enum mxc_dataout_type optype; enum mxc_nf_finalize_action fin; struct mxc_nf_flags flags; }; #endif /* OPENOCD_FLASH_NAND_MXC_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/nonce.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "hello.h" static int nonce_nand_command(struct nand_device *nand, uint8_t command) { return ERROR_OK; } static int nonce_nand_address(struct nand_device *nand, uint8_t address) { return ERROR_OK; } static int nonce_nand_read(struct nand_device *nand, void *data) { return ERROR_OK; } static int nonce_nand_write(struct nand_device *nand, uint16_t data) { return ERROR_OK; } static int nonce_nand_fast_block_write(struct nand_device *nand, uint8_t *data, int size) { return ERROR_OK; } static int nonce_nand_reset(struct nand_device *nand) { return nonce_nand_command(nand, NAND_CMD_RESET); } NAND_DEVICE_COMMAND_HANDLER(nonce_nand_device_command) { return ERROR_OK; } static int nonce_nand_init(struct nand_device *nand) { return ERROR_OK; } struct nand_flash_controller nonce_nand_controller = { .name = "nonce", .commands = hello_command_handlers, .nand_device_command = &nonce_nand_device_command, .init = &nonce_nand_init, .reset = &nonce_nand_reset, .command = &nonce_nand_command, .address = &nonce_nand_address, .read_data = &nonce_nand_read, .write_data = &nonce_nand_write, .write_block_data = &nonce_nand_fast_block_write, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/nuc910.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ /* * NAND controller interface for Nuvoton NUC910 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "nuc910.h" #include "arm_io.h" #include <target/arm.h> struct nuc910_nand_controller { struct arm_nand_data io; }; static int validate_target_state(struct nand_device *nand) { struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } static int nuc910_nand_command(struct nand_device *nand, uint8_t command) { struct target *target = nand->target; int result; result = validate_target_state(nand); if (result != ERROR_OK) return result; target_write_u8(target, NUC910_SMCMD, command); return ERROR_OK; } static int nuc910_nand_address(struct nand_device *nand, uint8_t address) { struct target *target = nand->target; int result; result = validate_target_state(nand); if (result != ERROR_OK) return result; target_write_u32(target, NUC910_SMADDR, ((address & 0xff) | NUC910_SMADDR_EOA)); return ERROR_OK; } static int nuc910_nand_read(struct nand_device *nand, void *data) { struct target *target = nand->target; int result; result = validate_target_state(nand); if (result != ERROR_OK) return result; target_read_u8(target, NUC910_SMDATA, data); return ERROR_OK; } static int nuc910_nand_write(struct nand_device *nand, uint16_t data) { struct target *target = nand->target; int result; result = validate_target_state(nand); if (result != ERROR_OK) return result; target_write_u8(target, NUC910_SMDATA, data); return ERROR_OK; } static int nuc910_nand_read_block_data(struct nand_device *nand, uint8_t *data, int data_size) { struct nuc910_nand_controller *nuc910_nand = nand->controller_priv; int result; result = validate_target_state(nand); if (result != ERROR_OK) return result; nuc910_nand->io.chunk_size = nand->page_size; /* try the fast way first */ result = arm_nandread(&nuc910_nand->io, data, data_size); if (result != ERROR_NAND_NO_BUFFER) return result; /* else do it slowly */ while (data_size--) nuc910_nand_read(nand, data++); return ERROR_OK; } static int nuc910_nand_write_block_data(struct nand_device *nand, uint8_t *data, int data_size) { struct nuc910_nand_controller *nuc910_nand = nand->controller_priv; int result; result = validate_target_state(nand); if (result != ERROR_OK) return result; nuc910_nand->io.chunk_size = nand->page_size; /* try the fast way first */ result = arm_nandwrite(&nuc910_nand->io, data, data_size); if (result != ERROR_NAND_NO_BUFFER) return result; /* else do it slowly */ while (data_size--) nuc910_nand_write(nand, *data++); return ERROR_OK; } static int nuc910_nand_reset(struct nand_device *nand) { return nuc910_nand_command(nand, NAND_CMD_RESET); } static int nuc910_nand_ready(struct nand_device *nand, int timeout) { struct target *target = nand->target; uint32_t status; do { target_read_u32(target, NUC910_SMISR, &status); if (status & NUC910_SMISR_RB_) return 1; alive_sleep(1); } while (timeout-- > 0); return 0; } NAND_DEVICE_COMMAND_HANDLER(nuc910_nand_device_command) { struct nuc910_nand_controller *nuc910_nand; nuc910_nand = calloc(1, sizeof(struct nuc910_nand_controller)); if (!nuc910_nand) { LOG_ERROR("no memory for nand controller"); return ERROR_NAND_DEVICE_INVALID; } nand->controller_priv = nuc910_nand; return ERROR_OK; } static int nuc910_nand_init(struct nand_device *nand) { struct nuc910_nand_controller *nuc910_nand = nand->controller_priv; struct target *target = nand->target; int bus_width = nand->bus_width ? nand->bus_width : 8; int result; result = validate_target_state(nand); if (result != ERROR_OK) return result; /* nuc910 only supports 8bit */ if (bus_width != 8) { LOG_ERROR("nuc910 only supports 8 bit bus width, not %i", bus_width); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } /* inform calling code about selected bus width */ nand->bus_width = bus_width; nuc910_nand->io.target = target; nuc910_nand->io.data = NUC910_SMDATA; nuc910_nand->io.op = ARM_NAND_NONE; /* configure nand controller */ target_write_u32(target, NUC910_FMICSR, NUC910_FMICSR_SM_EN); target_write_u32(target, NUC910_SMCSR, 0x010000a8); /* 2048 page size */ target_write_u32(target, NUC910_SMTCR, 0x00010204); target_write_u32(target, NUC910_SMIER, 0x00000000); return ERROR_OK; } struct nand_flash_controller nuc910_nand_controller = { .name = "nuc910", .command = nuc910_nand_command, .address = nuc910_nand_address, .read_data = nuc910_nand_read, .write_data = nuc910_nand_write, .write_block_data = nuc910_nand_write_block_data, .read_block_data = nuc910_nand_read_block_data, .nand_ready = nuc910_nand_ready, .reset = nuc910_nand_reset, .nand_device_command = nuc910_nand_device_command, .init = nuc910_nand_init, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/nuc910.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ /* * NAND controller interface for Nuvoton NUC910 */ #ifndef OPENOCD_FLASH_NAND_NUC910_H #define OPENOCD_FLASH_NAND_NUC910_H #define NUC910_FMICSR 0xB000D000 #define NUC910_SMCSR 0xB000D0A0 #define NUC910_SMTCR 0xB000D0A4 #define NUC910_SMIER 0xB000D0A8 #define NUC910_SMISR 0xB000D0AC #define NUC910_SMCMD 0xB000D0B0 #define NUC910_SMADDR 0xB000D0B4 #define NUC910_SMDATA 0xB000D0B8 #define NUC910_SMECC0 0xB000D0BC #define NUC910_SMECC1 0xB000D0C0 #define NUC910_SMECC2 0xB000D0C4 #define NUC910_SMECC3 0xB000D0C8 #define NUC910_ECC4ST 0xB000D114 /* Global Control and Status Register (FMICSR) */ #define NUC910_FMICSR_SM_EN (1<<3) /* NAND Flash Address Port Register (SMADDR) */ #define NUC910_SMADDR_EOA (1<<31) /* NAND Flash Control and Status Register (SMCSR) */ #define NUC910_SMCSR_PSIZE (1<<3) #define NUC910_SMCSR_DBW (1<<4) /* NAND Flash Interrupt Status Register (SMISR) */ #define NUC910_SMISR_ECC_IF (1<<2) #define NUC910_SMISR_RB_ (1<<18) /* ECC4 Correction Status (ECC4ST) */ #endif /* OPENOCD_FLASH_NAND_NUC910_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/orion.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by Marvell Semiconductors, Inc. * * Written by Nicolas Pitre <nico at marvell.com> * ***************************************************************************/ /* * NAND controller interface for Marvell Orion/Kirkwood SoCs. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "arm_io.h" #include <target/arm.h> struct orion_nand_controller { struct arm_nand_data io; uint32_t cmd; uint32_t addr; uint32_t data; }; #define CHECK_HALTED \ do { \ if (target->state != TARGET_HALTED) { \ LOG_ERROR("NAND flash access requires halted target"); \ return ERROR_NAND_OPERATION_FAILED; \ } \ } while (0) static int orion_nand_command(struct nand_device *nand, uint8_t command) { struct orion_nand_controller *hw = nand->controller_priv; struct target *target = nand->target; CHECK_HALTED; target_write_u8(target, hw->cmd, command); return ERROR_OK; } static int orion_nand_address(struct nand_device *nand, uint8_t address) { struct orion_nand_controller *hw = nand->controller_priv; struct target *target = nand->target; CHECK_HALTED; target_write_u8(target, hw->addr, address); return ERROR_OK; } static int orion_nand_read(struct nand_device *nand, void *data) { struct orion_nand_controller *hw = nand->controller_priv; struct target *target = nand->target; CHECK_HALTED; target_read_u8(target, hw->data, data); return ERROR_OK; } static int orion_nand_write(struct nand_device *nand, uint16_t data) { struct orion_nand_controller *hw = nand->controller_priv; struct target *target = nand->target; CHECK_HALTED; target_write_u8(target, hw->data, data); return ERROR_OK; } static int orion_nand_slow_block_write(struct nand_device *nand, uint8_t *data, int size) { while (size--) orion_nand_write(nand, *data++); return ERROR_OK; } static int orion_nand_fast_block_write(struct nand_device *nand, uint8_t *data, int size) { struct orion_nand_controller *hw = nand->controller_priv; int retval; hw->io.chunk_size = nand->page_size; retval = arm_nandwrite(&hw->io, data, size); if (retval == ERROR_NAND_NO_BUFFER) retval = orion_nand_slow_block_write(nand, data, size); return retval; } static int orion_nand_reset(struct nand_device *nand) { return orion_nand_command(nand, NAND_CMD_RESET); } NAND_DEVICE_COMMAND_HANDLER(orion_nand_device_command) { struct orion_nand_controller *hw; uint32_t base; uint8_t ale, cle; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; hw = calloc(1, sizeof(*hw)); if (!hw) { LOG_ERROR("no memory for nand controller"); return ERROR_NAND_DEVICE_INVALID; } nand->controller_priv = hw; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], base); cle = 0; ale = 1; hw->data = base; hw->cmd = base + (1 << cle); hw->addr = base + (1 << ale); hw->io.target = nand->target; hw->io.data = hw->data; hw->io.op = ARM_NAND_NONE; return ERROR_OK; } static int orion_nand_init(struct nand_device *nand) { return ERROR_OK; } struct nand_flash_controller orion_nand_controller = { .name = "orion", .usage = "<target_id> <NAND_address>", .command = orion_nand_command, .address = orion_nand_address, .read_data = orion_nand_read, .write_data = orion_nand_write, .write_block_data = orion_nand_fast_block_write, .reset = orion_nand_reset, .nand_device_command = orion_nand_device_command, .init = orion_nand_init, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/s3c2410.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * ***************************************************************************/ /* * S3C2410 OpenOCD NAND Flash controller support. * * Many thanks to Simtec Electronics for sponsoring this work. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "s3c24xx.h" NAND_DEVICE_COMMAND_HANDLER(s3c2410_nand_device_command) { struct s3c24xx_nand_controller *info; CALL_S3C24XX_DEVICE_COMMAND(nand, &info); /* fill in the address fields for the core device */ info->cmd = S3C2410_NFCMD; info->addr = S3C2410_NFADDR; info->data = S3C2410_NFDATA; info->nfstat = S3C2410_NFSTAT; return ERROR_OK; } static int s3c2410_init(struct nand_device *nand) { struct target *target = nand->target; target_write_u32(target, S3C2410_NFCONF, S3C2410_NFCONF_EN | S3C2410_NFCONF_TACLS(3) | S3C2410_NFCONF_TWRPH0(5) | S3C2410_NFCONF_TWRPH1(3)); return ERROR_OK; } static int s3c2410_write_data(struct nand_device *nand, uint16_t data) { struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } target_write_u32(target, S3C2410_NFDATA, data); return ERROR_OK; } static int s3c2410_read_data(struct nand_device *nand, void *data) { struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } target_read_u8(target, S3C2410_NFDATA, data); return ERROR_OK; } static int s3c2410_nand_ready(struct nand_device *nand, int timeout) { struct target *target = nand->target; uint8_t status; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } do { target_read_u8(target, S3C2410_NFSTAT, &status); if (status & S3C2410_NFSTAT_BUSY) return 1; alive_sleep(1); } while (timeout-- > 0); return 0; } struct nand_flash_controller s3c2410_nand_controller = { .name = "s3c2410", .nand_device_command = &s3c2410_nand_device_command, .init = &s3c2410_init, .reset = &s3c24xx_reset, .command = &s3c24xx_command, .address = &s3c24xx_address, .write_data = &s3c2410_write_data, .read_data = &s3c2410_read_data, .write_page = s3c24xx_write_page, .read_page = s3c24xx_read_page, .nand_ready = &s3c2410_nand_ready, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/s3c2412.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * ***************************************************************************/ /* * S3C2412 OpenOCD NAND Flash controller support. * * Many thanks to Simtec Electronics for sponsoring this work. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "s3c24xx.h" NAND_DEVICE_COMMAND_HANDLER(s3c2412_nand_device_command) { struct s3c24xx_nand_controller *info; CALL_S3C24XX_DEVICE_COMMAND(nand, &info); /* fill in the address fields for the core device */ info->cmd = S3C2440_NFCMD; info->addr = S3C2440_NFADDR; info->data = S3C2440_NFDATA; info->nfstat = S3C2412_NFSTAT; return ERROR_OK; } static int s3c2412_init(struct nand_device *nand) { struct target *target = nand->target; target_write_u32(target, S3C2410_NFCONF, S3C2440_NFCONF_TACLS(3) | S3C2440_NFCONF_TWRPH0(7) | S3C2440_NFCONF_TWRPH1(7)); target_write_u32(target, S3C2440_NFCONT, S3C2412_NFCONT_INIT_MAIN_ECC | S3C2440_NFCONT_ENABLE); return ERROR_OK; } struct nand_flash_controller s3c2412_nand_controller = { .name = "s3c2412", .nand_device_command = &s3c2412_nand_device_command, .init = &s3c2412_init, .reset = &s3c24xx_reset, .command = &s3c24xx_command, .address = &s3c24xx_address, .write_data = &s3c24xx_write_data, .read_data = &s3c24xx_read_data, .write_page = s3c24xx_write_page, .read_page = s3c24xx_read_page, .write_block_data = &s3c2440_write_block_data, .read_block_data = &s3c2440_read_block_data, .nand_ready = &s3c2440_nand_ready, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/s3c2440.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * ***************************************************************************/ /* * S3C2440 OpenOCD NAND Flash controller support. * * Many thanks to Simtec Electronics for sponsoring this work. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "s3c24xx.h" NAND_DEVICE_COMMAND_HANDLER(s3c2440_nand_device_command) { struct s3c24xx_nand_controller *info; CALL_S3C24XX_DEVICE_COMMAND(nand, &info); /* fill in the address fields for the core device */ info->cmd = S3C2440_NFCMD; info->addr = S3C2440_NFADDR; info->data = S3C2440_NFDATA; info->nfstat = S3C2440_NFSTAT; return ERROR_OK; } static int s3c2440_init(struct nand_device *nand) { struct target *target = nand->target; target_write_u32(target, S3C2410_NFCONF, S3C2440_NFCONF_TACLS(3) | S3C2440_NFCONF_TWRPH0(7) | S3C2440_NFCONF_TWRPH1(7)); target_write_u32(target, S3C2440_NFCONT, S3C2440_NFCONT_INITECC | S3C2440_NFCONT_ENABLE); return ERROR_OK; } int s3c2440_nand_ready(struct nand_device *nand, int timeout) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; uint8_t status; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } do { target_read_u8(target, s3c24xx_info->nfstat, &status); if (status & S3C2440_NFSTAT_READY) return 1; alive_sleep(1); } while (timeout-- > 0); return 0; } /* use the fact we can read/write 4 bytes in one go via a single 32bit op */ int s3c2440_read_block_data(struct nand_device *nand, uint8_t *data, int data_size) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; uint32_t nfdata = s3c24xx_info->data; uint32_t tmp; LOG_INFO("%s: reading data: %p, %p, %d", __func__, nand, data, data_size); if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } while (data_size >= 4) { target_read_u32(target, nfdata, &tmp); data[0] = tmp; data[1] = tmp >> 8; data[2] = tmp >> 16; data[3] = tmp >> 24; data_size -= 4; data += 4; } while (data_size > 0) { target_read_u8(target, nfdata, data); data_size -= 1; data += 1; } return ERROR_OK; } int s3c2440_write_block_data(struct nand_device *nand, uint8_t *data, int data_size) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; uint32_t nfdata = s3c24xx_info->data; uint32_t tmp; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } while (data_size >= 4) { tmp = le_to_h_u32(data); target_write_u32(target, nfdata, tmp); data_size -= 4; data += 4; } while (data_size > 0) { target_write_u8(target, nfdata, *data); data_size -= 1; data += 1; } return ERROR_OK; } struct nand_flash_controller s3c2440_nand_controller = { .name = "s3c2440", .nand_device_command = &s3c2440_nand_device_command, .init = &s3c2440_init, .reset = &s3c24xx_reset, .command = &s3c24xx_command, .address = &s3c24xx_address, .write_data = &s3c24xx_write_data, .read_data = &s3c24xx_read_data, .write_page = s3c24xx_write_page, .read_page = s3c24xx_read_page, .write_block_data = &s3c2440_write_block_data, .read_block_data = &s3c2440_read_block_data, .nand_ready = &s3c2440_nand_ready, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/s3c2443.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * ***************************************************************************/ /* * S3C2443 OpenOCD NAND Flash controller support. * * Many thanks to Simtec Electronics for sponsoring this work. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "s3c24xx.h" NAND_DEVICE_COMMAND_HANDLER(s3c2443_nand_device_command) { struct s3c24xx_nand_controller *info; CALL_S3C24XX_DEVICE_COMMAND(nand, &info); /* fill in the address fields for the core device */ info->cmd = S3C2440_NFCMD; info->addr = S3C2440_NFADDR; info->data = S3C2440_NFDATA; info->nfstat = S3C2412_NFSTAT; return ERROR_OK; } static int s3c2443_init(struct nand_device *nand) { struct target *target = nand->target; target_write_u32(target, S3C2410_NFCONF, S3C2440_NFCONF_TACLS(3) | S3C2440_NFCONF_TWRPH0(7) | S3C2440_NFCONF_TWRPH1(7)); target_write_u32(target, S3C2440_NFCONT, S3C2412_NFCONT_INIT_MAIN_ECC | S3C2440_NFCONT_ENABLE); return ERROR_OK; } struct nand_flash_controller s3c2443_nand_controller = { .name = "s3c2443", .nand_device_command = &s3c2443_nand_device_command, .init = &s3c2443_init, .reset = &s3c24xx_reset, .command = &s3c24xx_command, .address = &s3c24xx_address, .write_data = &s3c24xx_write_data, .read_data = &s3c24xx_read_data, .write_page = s3c24xx_write_page, .read_page = s3c24xx_read_page, .write_block_data = &s3c2440_write_block_data, .read_block_data = &s3c2440_read_block_data, .nand_ready = &s3c2440_nand_ready, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/s3c24xx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * ***************************************************************************/ /* * S3C24XX Series OpenOCD NAND Flash controller support. * * Many thanks to Simtec Electronics for sponsoring this work. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "s3c24xx.h" S3C24XX_DEVICE_COMMAND() { *info = NULL; struct s3c24xx_nand_controller *s3c24xx_info; s3c24xx_info = malloc(sizeof(struct s3c24xx_nand_controller)); if (!s3c24xx_info) { LOG_ERROR("no memory for nand controller"); return -ENOMEM; } nand->controller_priv = s3c24xx_info; *info = s3c24xx_info; return ERROR_OK; } int s3c24xx_reset(struct nand_device *nand) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } target_write_u32(target, s3c24xx_info->cmd, 0xff); return ERROR_OK; } int s3c24xx_command(struct nand_device *nand, uint8_t command) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } target_write_u16(target, s3c24xx_info->cmd, command); return ERROR_OK; } int s3c24xx_address(struct nand_device *nand, uint8_t address) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } target_write_u16(target, s3c24xx_info->addr, address); return ERROR_OK; } int s3c24xx_write_data(struct nand_device *nand, uint16_t data) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } target_write_u8(target, s3c24xx_info->data, data); return ERROR_OK; } int s3c24xx_read_data(struct nand_device *nand, void *data) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } target_read_u8(target, s3c24xx_info->data, data); return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/s3c24xx.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_S3C24XX_H #define OPENOCD_FLASH_NAND_S3C24XX_H /* * S3C24XX Series OpenOCD NAND Flash controller support. * * Many thanks to Simtec Electronics for sponsoring this work. */ #include "imp.h" #include "s3c24xx_regs.h" #include <target/target.h> struct s3c24xx_nand_controller { /* register addresses */ uint32_t cmd; uint32_t addr; uint32_t data; uint32_t nfstat; }; /* Default to using the un-translated NAND register based address */ #undef S3C2410_NFREG #define S3C2410_NFREG(x) ((x) + 0x4e000000) #define S3C24XX_DEVICE_COMMAND() \ COMMAND_HELPER(s3c24xx_nand_device_command, \ struct nand_device *nand, \ struct s3c24xx_nand_controller **info) S3C24XX_DEVICE_COMMAND(); #define CALL_S3C24XX_DEVICE_COMMAND(d, i) \ do { \ int retval = CALL_COMMAND_HANDLER(s3c24xx_nand_device_command, d, i); \ if (retval != ERROR_OK) \ return retval; \ } while (0) int s3c24xx_reset(struct nand_device *nand); int s3c24xx_command(struct nand_device *nand, uint8_t command); int s3c24xx_address(struct nand_device *nand, uint8_t address); int s3c24xx_write_data(struct nand_device *nand, uint16_t data); int s3c24xx_read_data(struct nand_device *nand, void *data); #define s3c24xx_write_page NULL #define s3c24xx_read_page NULL /* code shared between different controllers */ int s3c2440_nand_ready(struct nand_device *nand, int timeout); int s3c2440_read_block_data(struct nand_device *nand, uint8_t *data, int data_size); int s3c2440_write_block_data(struct nand_device *nand, uint8_t *data, int data_size); #endif /* OPENOCD_FLASH_NAND_S3C24XX_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/s3c24xx_regs.h ================================================ /* SPDX-License-Identifier: GPL-2.0-only */ /*************************************************************************** * Copyright (C) 2004, 2005 by Simtec Electronics * * linux@simtec.co.uk * * http://www.simtec.co.uk/products/SWLINUX/ * ***************************************************************************/ /* * S3C2410 NAND register definitions */ #ifndef OPENOCD_FLASH_NAND_S3C24XX_REGS_H #define OPENOCD_FLASH_NAND_S3C24XX_REGS_H #define S3C2410_NFREG(x) (x) #define S3C2410_NFCONF S3C2410_NFREG(0x00) #define S3C2410_NFCMD S3C2410_NFREG(0x04) #define S3C2410_NFADDR S3C2410_NFREG(0x08) #define S3C2410_NFDATA S3C2410_NFREG(0x0C) #define S3C2410_NFSTAT S3C2410_NFREG(0x10) #define S3C2410_NFECC S3C2410_NFREG(0x14) #define S3C2440_NFCONT S3C2410_NFREG(0x04) #define S3C2440_NFCMD S3C2410_NFREG(0x08) #define S3C2440_NFADDR S3C2410_NFREG(0x0C) #define S3C2440_NFDATA S3C2410_NFREG(0x10) #define S3C2440_NFECCD0 S3C2410_NFREG(0x14) #define S3C2440_NFECCD1 S3C2410_NFREG(0x18) #define S3C2440_NFECCD S3C2410_NFREG(0x1C) #define S3C2440_NFSTAT S3C2410_NFREG(0x20) #define S3C2440_NFESTAT0 S3C2410_NFREG(0x24) #define S3C2440_NFESTAT1 S3C2410_NFREG(0x28) #define S3C2440_NFMECC0 S3C2410_NFREG(0x2C) #define S3C2440_NFMECC1 S3C2410_NFREG(0x30) #define S3C2440_NFSECC S3C2410_NFREG(0x34) #define S3C2440_NFSBLK S3C2410_NFREG(0x38) #define S3C2440_NFEBLK S3C2410_NFREG(0x3C) #define S3C2412_NFSBLK S3C2410_NFREG(0x20) #define S3C2412_NFEBLK S3C2410_NFREG(0x24) #define S3C2412_NFSTAT S3C2410_NFREG(0x28) #define S3C2412_NFMECC_ERR0 S3C2410_NFREG(0x2C) #define S3C2412_NFMECC_ERR1 S3C2410_NFREG(0x30) #define S3C2412_NFMECC0 S3C2410_NFREG(0x34) #define S3C2412_NFMECC1 S3C2410_NFREG(0x38) #define S3C2412_NFSECC S3C2410_NFREG(0x3C) #define S3C2410_NFCONF_EN (1 << 15) #define S3C2410_NFCONF_512BYTE (1 << 14) #define S3C2410_NFCONF_4STEP (1 << 13) #define S3C2410_NFCONF_INITECC (1 << 12) #define S3C2410_NFCONF_NFCE (1 << 11) #define S3C2410_NFCONF_TACLS(x) ((x) << 8) #define S3C2410_NFCONF_TWRPH0(x) ((x) << 4) #define S3C2410_NFCONF_TWRPH1(x) ((x) << 0) #define S3C2410_NFSTAT_BUSY (1 << 0) #define S3C2440_NFCONF_BUSWIDTH_8 (0 << 0) #define S3C2440_NFCONF_BUSWIDTH_16 (1 << 0) #define S3C2440_NFCONF_ADVFLASH (1 << 3) #define S3C2440_NFCONF_TACLS(x) ((x) << 12) #define S3C2440_NFCONF_TWRPH0(x) ((x) << 8) #define S3C2440_NFCONF_TWRPH1(x) ((x) << 4) #define S3C2440_NFCONT_LOCKTIGHT (1 << 13) #define S3C2440_NFCONT_SOFTLOCK (1 << 12) #define S3C2440_NFCONT_ILLEGALACC_EN (1 << 10) #define S3C2440_NFCONT_RNBINT_EN (1 << 9) #define S3C2440_NFCONT_RN_FALLING (1 << 8) #define S3C2440_NFCONT_SPARE_ECCLOCK (1 << 6) #define S3C2440_NFCONT_MAIN_ECCLOCK (1 << 5) #define S3C2440_NFCONT_INITECC (1 << 4) #define S3C2440_NFCONT_NFCE (1 << 1) #define S3C2440_NFCONT_ENABLE (1 << 0) #define S3C2440_NFSTAT_READY (1 << 0) #define S3C2440_NFSTAT_NCE (1 << 1) #define S3C2440_NFSTAT_RNB_CHANGE (1 << 2) #define S3C2440_NFSTAT_ILLEGAL_ACCESS (1 << 3) #define S3C2412_NFCONF_NANDBOOT (1 << 31) #define S3C2412_NFCONF_ECCCLKCON (1 << 30) #define S3C2412_NFCONF_ECC_MLC (1 << 24) #define S3C2412_NFCONF_TACLS_MASK (7 << 12) /* 1 extra bit of Tacls */ #define S3C2412_NFCONT_ECC4_DIRWR (1 << 18) #define S3C2412_NFCONT_LOCKTIGHT (1 << 17) #define S3C2412_NFCONT_SOFTLOCK (1 << 16) #define S3C2412_NFCONT_ECC4_ENCINT (1 << 13) #define S3C2412_NFCONT_ECC4_DECINT (1 << 12) #define S3C2412_NFCONT_MAIN_ECC_LOCK (1 << 7) #define S3C2412_NFCONT_INIT_MAIN_ECC (1 << 5) #define S3C2412_NFCONT_NFCE1 (1 << 2) #define S3C2412_NFCONT_NFCE0 (1 << 1) #define S3C2412_NFSTAT_ECC_ENCDONE (1 << 7) #define S3C2412_NFSTAT_ECC_DECDONE (1 << 6) #define S3C2412_NFSTAT_ILLEGAL_ACCESS (1 << 5) #define S3C2412_NFSTAT_RNB_CHANGE (1 << 4) #define S3C2412_NFSTAT_NFCE1 (1 << 3) #define S3C2412_NFSTAT_NFCE0 (1 << 2) #define S3C2412_NFSTAT_RES1 (1 << 1) #define S3C2412_NFSTAT_READY (1 << 0) #define S3C2412_NFECCERR_SERRDATA(x) (((x) >> 21) & 0xf) #define S3C2412_NFECCERR_SERRBIT(x) (((x) >> 18) & 0x7) #define S3C2412_NFECCERR_MERRDATA(x) (((x) >> 7) & 0x3ff) #define S3C2412_NFECCERR_MERRBIT(x) (((x) >> 4) & 0x7) #define S3C2412_NFECCERR_SPARE_ERR(x) (((x) >> 2) & 0x3) #define S3C2412_NFECCERR_MAIN_ERR(x) (((x) >> 2) & 0x3) #define S3C2412_NFECCERR_NONE (0) #define S3C2412_NFECCERR_1BIT (1) #define S3C2412_NFECCERR_MULTIBIT (2) #define S3C2412_NFECCERR_ECCAREA (3) #endif /* OPENOCD_FLASH_NAND_S3C24XX_REGS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/s3c6400.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2010 by Peter Korsgaard <jacmet@sunsite.dk> * * Heavily based on s3c2412.c by Ben Dooks <ben@fluff.org> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "s3c24xx.h" /* s3c64xx uses another base address for the nand controller than 24xx */ #undef S3C2410_NFREG #define S3C2410_NFREG(x) ((x) + 0x70200000) NAND_DEVICE_COMMAND_HANDLER(s3c6400_nand_device_command) { struct s3c24xx_nand_controller *info; CALL_S3C24XX_DEVICE_COMMAND(nand, &info); /* fill in the address fields for the core device */ info->cmd = S3C2440_NFCMD; info->addr = S3C2440_NFADDR; info->data = S3C2440_NFDATA; info->nfstat = S3C2412_NFSTAT; return ERROR_OK; } static int s3c6400_init(struct nand_device *nand) { struct target *target = nand->target; target_write_u32(target, S3C2410_NFCONF, S3C2440_NFCONF_TACLS(3) | S3C2440_NFCONF_TWRPH0(7) | S3C2440_NFCONF_TWRPH1(7) | 4); target_write_u32(target, S3C2440_NFCONT, S3C2412_NFCONT_INIT_MAIN_ECC | S3C2440_NFCONT_ENABLE); return ERROR_OK; } struct nand_flash_controller s3c6400_nand_controller = { .name = "s3c6400", .nand_device_command = &s3c6400_nand_device_command, .init = &s3c6400_init, .reset = &s3c24xx_reset, .command = &s3c24xx_command, .address = &s3c24xx_address, .write_data = &s3c24xx_write_data, .read_data = &s3c24xx_read_data, .write_page = s3c24xx_write_page, .read_page = s3c24xx_read_page, .write_block_data = &s3c2440_write_block_data, .read_block_data = &s3c2440_read_block_data, .nand_ready = &s3c2440_nand_ready, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nand/tcl.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * * * Partially based on drivers/mtd/nand_ids.c from Linux. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "core.h" #include "imp.h" #include "fileio.h" #include <target/target.h> COMMAND_HANDLER(handle_nand_list_command) { struct nand_device *p; int i; if (!nand_devices) { command_print(CMD, "no NAND flash devices configured"); return ERROR_OK; } for (p = nand_devices, i = 0; p; p = p->next, i++) { if (p->device) command_print(CMD, "#%i: %s (%s) " "pagesize: %i, buswidth: %i,\n\t" "blocksize: %i, blocks: %i", i, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size, p->num_blocks); else command_print(CMD, "#%i: not probed", i); } return ERROR_OK; } COMMAND_HANDLER(handle_nand_info_command) { int i = 0; int j = 0; int first = -1; int last = -1; switch (CMD_ARGC) { default: return ERROR_COMMAND_SYNTAX_ERROR; case 1: first = 0; last = INT32_MAX; break; case 2: COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], i); first = last = i; i = 0; break; case 3: COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first); COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last); break; } struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); if (retval != ERROR_OK) return retval; if (!p->device) { command_print(CMD, "#%s: not probed", CMD_ARGV[0]); return ERROR_OK; } if (first >= p->num_blocks) first = p->num_blocks - 1; if (last >= p->num_blocks) last = p->num_blocks - 1; command_print(CMD, "#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i", i++, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size); for (j = first; j <= last; j++) { char *erase_state, *bad_state; if (p->blocks[j].is_erased == 0) erase_state = "not erased"; else if (p->blocks[j].is_erased == 1) erase_state = "erased"; else erase_state = "erase state unknown"; if (p->blocks[j].is_bad == 0) bad_state = ""; else if (p->blocks[j].is_bad == 1) bad_state = " (marked bad)"; else bad_state = " (block condition unknown)"; command_print(CMD, "\t#%i: 0x%8.8" PRIx32 " (%" PRIu32 "kB) %s%s", j, p->blocks[j].offset, p->blocks[j].size / 1024, erase_state, bad_state); } return ERROR_OK; } COMMAND_HANDLER(handle_nand_probe_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); if (retval != ERROR_OK) return retval; retval = nand_probe(p); if (retval == ERROR_OK) { command_print(CMD, "NAND flash device '%s (%s)' found", p->device->name, p->manufacturer->name); } return retval; } COMMAND_HANDLER(handle_nand_erase_command) { if (CMD_ARGC != 1 && CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); if (retval != ERROR_OK) return retval; unsigned long offset; unsigned long length; /* erase specified part of the chip; or else everything */ if (CMD_ARGC == 3) { unsigned long size = p->erase_size * p->num_blocks; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset); if ((offset % p->erase_size) != 0 || offset >= size) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length); if ((length == 0) || (length % p->erase_size) != 0 || (length + offset) > size) return ERROR_COMMAND_SYNTAX_ERROR; offset /= p->erase_size; length /= p->erase_size; } else { offset = 0; length = p->num_blocks; } retval = nand_erase(p, offset, offset + length - 1); if (retval == ERROR_OK) { command_print(CMD, "erased blocks %lu to %lu " "on NAND flash device #%s '%s'", offset, offset + length - 1, CMD_ARGV[0], p->device->name); } return retval; } COMMAND_HANDLER(handle_nand_check_bad_blocks_command) { int first = -1; int last = -1; if ((CMD_ARGC < 1) || (CMD_ARGC > 3) || (CMD_ARGC == 2)) return ERROR_COMMAND_SYNTAX_ERROR; struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); if (retval != ERROR_OK) return retval; if (CMD_ARGC == 3) { unsigned long offset; unsigned long length; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset); if (offset % p->erase_size) return ERROR_COMMAND_SYNTAX_ERROR; offset /= p->erase_size; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length); if (length % p->erase_size) return ERROR_COMMAND_SYNTAX_ERROR; length -= 1; length /= p->erase_size; first = offset; last = offset + length; } retval = nand_build_bbt(p, first, last); if (retval == ERROR_OK) { command_print(CMD, "checked NAND flash device for bad blocks, " "use \"nand info\" command to list blocks"); } return retval; } COMMAND_HANDLER(handle_nand_write_command) { struct nand_device *nand = NULL; struct nand_fileio_state s; int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args, &s, &nand, FILEIO_READ, false, true); if (retval != ERROR_OK) return retval; uint32_t total_bytes = s.size; while (s.size > 0) { int bytes_read = nand_fileio_read(nand, &s); if (bytes_read <= 0) { command_print(CMD, "error while reading file"); nand_fileio_cleanup(&s); return ERROR_FAIL; } s.size -= bytes_read; retval = nand_write_page(nand, s.address / nand->page_size, s.page, s.page_size, s.oob, s.oob_size); if (retval != ERROR_OK) { command_print(CMD, "failed writing file %s " "to NAND flash %s at offset 0x%8.8" PRIx32, CMD_ARGV[1], CMD_ARGV[0], s.address); nand_fileio_cleanup(&s); return retval; } s.address += s.page_size; } if (nand_fileio_finish(&s) == ERROR_OK) { command_print(CMD, "wrote file %s to NAND flash %s up to " "offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", CMD_ARGV[1], CMD_ARGV[0], s.address, duration_elapsed(&s.bench), duration_kbps(&s.bench, total_bytes)); } return ERROR_OK; } COMMAND_HANDLER(handle_nand_verify_command) { struct nand_device *nand = NULL; struct nand_fileio_state file; int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args, &file, &nand, FILEIO_READ, false, true); if (retval != ERROR_OK) return retval; struct nand_fileio_state dev; nand_fileio_init(&dev); dev.address = file.address; dev.size = file.size; dev.oob_format = file.oob_format; retval = nand_fileio_start(CMD, nand, NULL, FILEIO_NONE, &dev); if (retval != ERROR_OK) return retval; while (file.size > 0) { retval = nand_read_page(nand, dev.address / dev.page_size, dev.page, dev.page_size, dev.oob, dev.oob_size); if (retval != ERROR_OK) { command_print(CMD, "reading NAND flash page failed"); nand_fileio_cleanup(&dev); nand_fileio_cleanup(&file); return retval; } int bytes_read = nand_fileio_read(nand, &file); if (bytes_read <= 0) { command_print(CMD, "error while reading file"); nand_fileio_cleanup(&dev); nand_fileio_cleanup(&file); return ERROR_FAIL; } if ((dev.page && memcmp(dev.page, file.page, dev.page_size)) || (dev.oob && memcmp(dev.oob, file.oob, dev.oob_size))) { command_print(CMD, "NAND flash contents differ " "at 0x%8.8" PRIx32, dev.address); nand_fileio_cleanup(&dev); nand_fileio_cleanup(&file); return ERROR_FAIL; } file.size -= bytes_read; dev.address += nand->page_size; } if (nand_fileio_finish(&file) == ERROR_OK) { command_print(CMD, "verified file %s in NAND flash %s " "up to offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", CMD_ARGV[1], CMD_ARGV[0], dev.address, duration_elapsed(&file.bench), duration_kbps(&file.bench, dev.size)); } return nand_fileio_cleanup(&dev); } COMMAND_HANDLER(handle_nand_dump_command) { size_t filesize; struct nand_device *nand = NULL; struct nand_fileio_state s; int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args, &s, &nand, FILEIO_WRITE, true, false); if (retval != ERROR_OK) return retval; while (s.size > 0) { size_t size_written; retval = nand_read_page(nand, s.address / nand->page_size, s.page, s.page_size, s.oob, s.oob_size); if (retval != ERROR_OK) { command_print(CMD, "reading NAND flash page failed"); nand_fileio_cleanup(&s); return retval; } if (s.page) fileio_write(s.fileio, s.page_size, s.page, &size_written); if (s.oob) fileio_write(s.fileio, s.oob_size, s.oob, &size_written); s.size -= nand->page_size; s.address += nand->page_size; } retval = fileio_size(s.fileio, &filesize); if (retval != ERROR_OK) return retval; if (nand_fileio_finish(&s) == ERROR_OK) { command_print(CMD, "dumped %zu bytes in %fs (%0.3f KiB/s)", filesize, duration_elapsed(&s.bench), duration_kbps(&s.bench, filesize)); } return ERROR_OK; } COMMAND_HANDLER(handle_nand_raw_access_command) { if ((CMD_ARGC < 1) || (CMD_ARGC > 2)) return ERROR_COMMAND_SYNTAX_ERROR; struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); if (retval != ERROR_OK) return retval; if (!p->device) { command_print(CMD, "#%s: not probed", CMD_ARGV[0]); return ERROR_OK; } if (CMD_ARGC == 2) COMMAND_PARSE_ENABLE(CMD_ARGV[1], p->use_raw); const char *msg = p->use_raw ? "enabled" : "disabled"; command_print(CMD, "raw access is %s", msg); return ERROR_OK; } static const struct command_registration nand_exec_command_handlers[] = { { .name = "list", .handler = handle_nand_list_command, .mode = COMMAND_EXEC, .help = "list configured NAND flash devices", .usage = "", }, { .name = "info", .handler = handle_nand_info_command, .mode = COMMAND_EXEC, .usage = "[banknum | first_bank_num last_bank_num]", .help = "print info about one or more NAND flash devices", }, { .name = "probe", .handler = handle_nand_probe_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "identify NAND flash device", }, { .name = "check_bad_blocks", .handler = handle_nand_check_bad_blocks_command, .mode = COMMAND_EXEC, .usage = "bank_id [offset length]", .help = "check all or part of NAND flash device for bad blocks", }, { .name = "erase", .handler = handle_nand_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id [offset length]", .help = "erase all or subset of blocks on NAND flash device", }, { .name = "dump", .handler = handle_nand_dump_command, .mode = COMMAND_EXEC, .usage = "bank_id filename offset length " "['oob_raw'|'oob_only']", .help = "dump from NAND flash device", }, { .name = "verify", .handler = handle_nand_verify_command, .mode = COMMAND_EXEC, .usage = "bank_id filename offset " "['oob_raw'|'oob_only'|'oob_softecc'|'oob_softecc_kw']", .help = "verify NAND flash device", }, { .name = "write", .handler = handle_nand_write_command, .mode = COMMAND_EXEC, .usage = "bank_id filename offset " "['oob_raw'|'oob_only'|'oob_softecc'|'oob_softecc_kw']", .help = "write to NAND flash device", }, { .name = "raw_access", .handler = handle_nand_raw_access_command, .mode = COMMAND_EXEC, .usage = "bank_id ['enable'|'disable']", .help = "raw access to NAND flash device", }, COMMAND_REGISTRATION_DONE }; static int nand_init(struct command_context *cmd_ctx) { if (!nand_devices) return ERROR_OK; return register_commands(cmd_ctx, "nand", nand_exec_command_handlers); } COMMAND_HANDLER(handle_nand_init_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; static bool nand_initialized; if (nand_initialized) { LOG_INFO("'nand init' has already been called"); return ERROR_OK; } nand_initialized = true; LOG_DEBUG("Initializing NAND devices..."); return nand_init(CMD_CTX); } static int nand_list_walker(struct nand_flash_controller *c, void *x) { struct command_invocation *cmd = x; command_print(cmd, " %s", c->name); return ERROR_OK; } COMMAND_HANDLER(handle_nand_list_drivers) { command_print(CMD, "Available NAND flash controller drivers:"); return nand_driver_walk(&nand_list_walker, CMD); } static COMMAND_HELPER(create_nand_device, const char *bank_name, struct nand_flash_controller *controller) { struct nand_device *c; struct target *target; int retval; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; target = get_target(CMD_ARGV[1]); if (!target) { LOG_ERROR("invalid target %s", CMD_ARGV[1]); return ERROR_COMMAND_ARGUMENT_INVALID; } if (controller->commands) { retval = register_commands(CMD_CTX, NULL, controller->commands); if (retval != ERROR_OK) return retval; } c = malloc(sizeof(struct nand_device)); if (!c) { LOG_ERROR("End of memory"); return ERROR_FAIL; } c->name = strdup(bank_name); c->target = target; c->controller = controller; c->controller_priv = NULL; c->manufacturer = NULL; c->device = NULL; c->bus_width = 0; c->address_cycles = 0; c->page_size = 0; c->use_raw = false; c->next = NULL; retval = CALL_COMMAND_HANDLER(controller->nand_device_command, c); if (retval != ERROR_OK) { LOG_ERROR("'%s' driver rejected nand flash. Usage: %s", controller->name, controller->usage); free(c); return retval; } if (!controller->usage) LOG_DEBUG("'%s' driver usage field missing", controller->name); nand_device_add(c); return ERROR_OK; } COMMAND_HANDLER(handle_nand_device_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; /* save name and increment (for compatibility) with drivers */ const char *bank_name = *CMD_ARGV++; CMD_ARGC--; const char *driver_name = CMD_ARGV[0]; struct nand_flash_controller *controller; controller = nand_driver_find_by_name(CMD_ARGV[0]); if (!controller) { LOG_ERROR("No valid NAND flash driver found (%s)", driver_name); return CALL_COMMAND_HANDLER(handle_nand_list_drivers); } return CALL_COMMAND_HANDLER(create_nand_device, bank_name, controller); } static const struct command_registration nand_config_command_handlers[] = { { .name = "device", .handler = &handle_nand_device_command, .mode = COMMAND_CONFIG, .help = "defines a new NAND bank", .usage = "bank_id driver target [driver_options ...]", }, { .name = "drivers", .handler = &handle_nand_list_drivers, .mode = COMMAND_ANY, .help = "lists available NAND drivers", .usage = "" }, { .name = "init", .mode = COMMAND_CONFIG, .handler = &handle_nand_init_command, .help = "initialize NAND devices", .usage = "" }, COMMAND_REGISTRATION_DONE }; static const struct command_registration nand_command_handlers[] = { { .name = "nand", .mode = COMMAND_ANY, .help = "NAND flash command group", .usage = "", .chain = nand_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; int nand_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, nand_command_handlers); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libocdflashnor.la %C%_libocdflashnor_la_SOURCES = \ %D%/core.c \ %D%/tcl.c \ $(NOR_DRIVERS) \ %D%/drivers.c \ $(NORHEADERS) NOR_DRIVERS = \ %D%/aduc702x.c \ %D%/aducm360.c \ %D%/ambiqmicro.c \ %D%/at91sam4.c \ %D%/at91sam4l.c \ %D%/at91samd.c \ %D%/at91sam3.c \ %D%/at91sam7.c \ %D%/ath79.c \ %D%/atsamv.c \ %D%/atsame5.c \ %D%/avrf.c \ %D%/bluenrg-x.c \ %D%/cc3220sf.c \ %D%/cc26xx.c \ %D%/cfi.c \ %D%/dsp5680xx_flash.c \ %D%/efm32.c \ %D%/em357.c \ %D%/esirisc_flash.c \ %D%/faux.c \ %D%/fespi.c \ %D%/fm3.c \ %D%/fm4.c \ %D%/jtagspi.c \ %D%/kinetis.c \ %D%/kinetis_ke.c \ %D%/lpc2000.c \ %D%/lpc288x.c \ %D%/lpc2900.c \ %D%/lpcspifi.c \ %D%/max32xxx.c \ %D%/mdr.c \ %D%/msp432.c \ %D%/mrvlqspi.c \ %D%/niietcm4.c \ %D%/non_cfi.c \ %D%/npcx.c \ %D%/nrf5.c \ %D%/numicro.c \ %D%/ocl.c \ %D%/pic32mx.c \ %D%/psoc4.c \ %D%/psoc5lp.c \ %D%/psoc6.c \ %D%/qn908x.c \ %D%/renesas_rpchf.c \ %D%/rp2040.c \ %D%/rsl10.c \ %D%/sfdp.c \ %D%/sh_qspi.c \ %D%/sim3x.c \ %D%/spi.c \ %D%/stmsmi.c \ %D%/stmqspi.c \ %D%/stellaris.c \ %D%/stm32f1x.c \ %D%/stm32f2x.c \ %D%/stm32lx.c \ %D%/stm32l4x.c \ %D%/stm32h7x.c \ %D%/str7x.c \ %D%/str9x.c \ %D%/str9xpec.c \ %D%/swm050.c \ %D%/tms470.c \ %D%/virtual.c \ %D%/w600.c \ %D%/xcf.c \ %D%/xmc1xxx.c \ %D%/xmc4xxx.c NORHEADERS = \ %D%/core.h \ %D%/cc3220sf.h \ %D%/bluenrg-x.h \ %D%/cc26xx.h \ %D%/cfi.h \ %D%/driver.h \ %D%/imp.h \ %D%/non_cfi.h \ %D%/ocl.h \ %D%/sfdp.h \ %D%/spi.h \ %D%/stm32l4x.h \ %D%/stmqspi.h \ %D%/msp432.h ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/aduc702x.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2008 by Kevin McGuire * * Copyright (C) 2008 by Marcel Wijlaars * * Copyright (C) 2009 by Michael Ashton * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <helper/time_support.h> #include <target/algorithm.h> #include <target/arm.h> static int aduc702x_build_sector_list(struct flash_bank *bank); static int aduc702x_check_flash_completion(struct target *target, unsigned int timeout_ms); static int aduc702x_set_write_enable(struct target *target, int enable); #define ADUC702X_FLASH 0xfffff800 #define ADUC702X_FLASH_FEESTA (0*4) #define ADUC702X_FLASH_FEEMOD (1*4) #define ADUC702X_FLASH_FEECON (2*4) #define ADUC702X_FLASH_FEEDAT (3*4) #define ADUC702X_FLASH_FEEADR (4*4) #define ADUC702X_FLASH_FEESIGN (5*4) #define ADUC702X_FLASH_FEEPRO (6*4) #define ADUC702X_FLASH_FEEHIDE (7*4) /* flash bank aduc702x 0 0 0 0 <target#> * The ADC7019-28 devices all have the same flash layout */ FLASH_BANK_COMMAND_HANDLER(aduc702x_flash_bank_command) { bank->base = 0x80000; bank->size = 0xF800; /* top 4k not accessible */ aduc702x_build_sector_list(bank); return ERROR_OK; } static int aduc702x_build_sector_list(struct flash_bank *bank) { /* aduc7026_struct flash_bank *aduc7026_info = bank->driver_priv; */ uint32_t offset = 0; /* sector size is 512 */ bank->num_sectors = bank->size / 512; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; ++i) { bank->sectors[i].offset = offset; bank->sectors[i].size = 512; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } return ERROR_OK; } static int aduc702x_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { /* int res; */ int x; int count; /* uint32_t v; */ struct target *target = bank->target; aduc702x_set_write_enable(target, 1); /* mass erase */ if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) { LOG_DEBUG("performing mass erase."); target_write_u16(target, ADUC702X_FLASH + ADUC702X_FLASH_FEEDAT, 0x3cff); target_write_u16(target, ADUC702X_FLASH + ADUC702X_FLASH_FEEADR, 0xffc3); target_write_u8(target, ADUC702X_FLASH + ADUC702X_FLASH_FEECON, 0x06); if (aduc702x_check_flash_completion(target, 3500) != ERROR_OK) { LOG_ERROR("mass erase failed"); aduc702x_set_write_enable(target, 0); return ERROR_FLASH_OPERATION_FAILED; } LOG_DEBUG("mass erase successful."); return ERROR_OK; } else { unsigned long adr; count = last - first + 1; for (x = 0; x < count; ++x) { adr = bank->base + ((first + x) * 512); target_write_u16(target, ADUC702X_FLASH + ADUC702X_FLASH_FEEADR, adr); target_write_u8(target, ADUC702X_FLASH + ADUC702X_FLASH_FEECON, 0x05); if (aduc702x_check_flash_completion(target, 50) != ERROR_OK) { LOG_ERROR("failed to erase sector at address 0x%08lX", adr); aduc702x_set_write_enable(target, 0); return ERROR_FLASH_SECTOR_NOT_ERASED; } LOG_DEBUG("erased sector at address 0x%08lX", adr); } } aduc702x_set_write_enable(target, 0); return ERROR_OK; } /* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall * back to another mechanism that does not require onboard RAM * * Caller should not check for other return values specifically */ static int aduc702x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 7000; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[6]; struct arm_algorithm arm_algo; int retval = ERROR_OK; if (((count%2) != 0) || ((offset%2) != 0)) { LOG_ERROR("write block must be multiple of two bytes in offset & length"); return ERROR_FAIL; } /* parameters: r0 - address of source data (absolute) r1 - number of halfwords to be copied r2 - start address in flash (offset from beginning of flash memory) r3 - exit code r4 - base address of flash controller (0xFFFFF800) registers: r5 - scratch r6 - set to 2, used to write flash command */ static const uint32_t aduc702x_flash_write_code[] = { /* <_start>: */ 0xe3a05008, /* mov r5, #8 ; 0x8 */ 0xe5845004, /* str r5, [r4, #4] */ 0xe3a06002, /* mov r6, #2 ; 0x2 */ /* <next>: */ 0xe1c421b0, /* strh r2, [r4, #16] */ 0xe0d050b2, /* ldrh r5, [r0], #2 */ 0xe1c450bc, /* strh r5, [r4, #12] */ 0xe5c46008, /* strb r6, [r4, #8] */ /* <wait_complete>: */ 0xe1d430b0, /* ldrh r3, [r4] */ 0xe3130004, /* tst r3, #4 ; 0x4 */ 0x1afffffc, /* bne 1001c <wait_complete> */ 0xe2822002, /* add r2, r2, #2 ; 0x2 */ 0xe2511001, /* subs r1, r1, #1 ; 0x1 */ 0x0a000001, /* beq 1003c <done> */ 0xe3130001, /* tst r3, #1 ; 0x1 */ 0x1afffff3, /* bne 1000c <next> */ /* <done>: */ 0xeafffffe /* b 1003c <done> */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(aduc702x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } uint8_t code[sizeof(aduc702x_flash_write_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(aduc702x_flash_write_code), aduc702x_flash_write_code); retval = target_write_buffer(target, write_algorithm->address, sizeof(code), code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a buffer, *free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN); init_reg_param(®_params[4], "r4", 32, PARAM_OUT); while (count > 0) { uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count; retval = target_write_buffer(target, source->address, thisrun_count, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, thisrun_count/2); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[4].value, 0, 32, 0xFFFFF800); retval = target_run_algorithm(target, 0, NULL, 5, reg_params, write_algorithm->address, write_algorithm->address + sizeof(aduc702x_flash_write_code) - 4, 10000, &arm_algo); if (retval != ERROR_OK) { LOG_ERROR("error executing aduc702x flash write algorithm"); break; } if ((buf_get_u32(reg_params[3].value, 0, 32) & 1) != 1) { /* FIX!!!! what does this mean??? replace w/sensible error message */ LOG_ERROR("aduc702x detected error writing flash"); retval = ERROR_FAIL; break; } buffer += thisrun_count; address += thisrun_count; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; } /* All-JTAG, single-access method. Very slow. Used only if there is no * working area available. */ static int aduc702x_write_single(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { uint32_t x; uint8_t b; struct target *target = bank->target; aduc702x_set_write_enable(target, 1); for (x = 0; x < count; x += 2) { /* FEEADR = address */ target_write_u16(target, ADUC702X_FLASH + ADUC702X_FLASH_FEEADR, offset + x); /* set up data */ if ((x + 1) == count) { /* last byte */ target_read_u8(target, offset + x + 1, &b); } else b = buffer[x + 1]; target_write_u16(target, ADUC702X_FLASH + ADUC702X_FLASH_FEEDAT, buffer[x] | (b << 8)); /* do single-write command */ target_write_u8(target, ADUC702X_FLASH + ADUC702X_FLASH_FEECON, 0x02); if (aduc702x_check_flash_completion(target, 1) != ERROR_OK) { LOG_ERROR("single write failed for address 0x%08lX", (unsigned long)(offset + x)); aduc702x_set_write_enable(target, 0); return ERROR_FLASH_OPERATION_FAILED; } } LOG_DEBUG("wrote %d bytes at address 0x%08lX", (int)count, (unsigned long)(offset + x)); aduc702x_set_write_enable(target, 0); return ERROR_OK; } static int aduc702x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; /* try using a block write */ retval = aduc702x_write_block(bank, buffer, offset, count); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * use normal (slow) JTAG method */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); retval = aduc702x_write_single(bank, buffer, offset, count); if (retval != ERROR_OK) { LOG_ERROR("slow write failed"); return ERROR_FLASH_OPERATION_FAILED; } } } return retval; } static int aduc702x_probe(struct flash_bank *bank) { return ERROR_OK; } /* sets FEEMOD bit 3 * enable = 1 enables writes & erases, 0 disables them */ static int aduc702x_set_write_enable(struct target *target, int enable) { /* don't bother to preserve int enable bit here */ target_write_u16(target, ADUC702X_FLASH + ADUC702X_FLASH_FEEMOD, enable ? 8 : 0); return ERROR_OK; } /* wait up to timeout_ms for controller to not be busy, * then check whether the command passed or failed. * * this function sleeps 1ms between checks (after the first one), * so in some cases may slow things down without a usleep after the first read */ static int aduc702x_check_flash_completion(struct target *target, unsigned int timeout_ms) { uint8_t v = 4; int64_t endtime = timeval_ms() + timeout_ms; while (1) { target_read_u8(target, ADUC702X_FLASH + ADUC702X_FLASH_FEESTA, &v); if ((v & 4) == 0) break; alive_sleep(1); if (timeval_ms() >= endtime) break; } if (v & 2) return ERROR_FAIL; /* if a command is ignored, both the success and fail bits may be 0 */ else if ((v & 3) == 0) return ERROR_FAIL; else return ERROR_OK; } const struct flash_driver aduc702x_flash = { .name = "aduc702x", .flash_bank_command = aduc702x_flash_bank_command, .erase = aduc702x_erase, .write = aduc702x_write, .read = default_flash_read, .probe = aduc702x_probe, .auto_probe = aduc702x_probe, .erase_check = default_flash_blank_check, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/aducm360.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2015 by Ivan Buliev * * i.buliev@mikrosistemi.com * ***************************************************************************/ /*************************************************************************** * This version for ADuCM360 is largely based on the following flash * * drivers: * * - aduc702x.c * * Copyright (C) 2008 by Kevin McGuire * * Copyright (C) 2008 by Marcel Wijlaars * * Copyright (C) 2009 by Michael Ashton * * and * * - stm32f1x.c * * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <helper/time_support.h> #include <target/algorithm.h> #include <target/armv7m.h> static int aducm360_build_sector_list(struct flash_bank *bank); static int aducm360_check_flash_completion(struct target *target, unsigned int timeout_ms); static int aducm360_set_write_enable(struct target *target, int enable); #define ADUCM360_FLASH_BASE 0x40002800 #define ADUCM360_FLASH_FEESTA 0x0000 #define ADUCM360_FLASH_FEECON0 0x0004 #define ADUCM360_FLASH_FEECMD 0x0008 #define ADUCM360_FLASH_FEEADR0L 0x0010 #define ADUCM360_FLASH_FEEADR0H 0x0014 #define ADUCM360_FLASH_FEEADR1L 0x0018 #define ADUCM360_FLASH_FEEADR1H 0x001C #define ADUCM360_FLASH_FEEKEY 0x0020 #define ADUCM360_FLASH_FEEPROL 0x0028 #define ADUCM360_FLASH_FEEPROH 0x002C #define ADUCM360_FLASH_FEESIGL 0x0030 #define ADUCM360_FLASH_FEESIGH 0x0034 #define ADUCM360_FLASH_FEECON1 0x0038 #define ADUCM360_FLASH_FEEADRAL 0x0048 #define ADUCM360_FLASH_FEEADRAH 0x004C #define ADUCM360_FLASH_FEEAEN0 0x0078 #define ADUCM360_FLASH_FEEAEN1 0x007C #define ADUCM360_FLASH_FEEAEN2 0x0080 /* flash bank aducm360 0 0 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(aducm360_flash_bank_command) { bank->base = 0x00000000; bank->size = 0x00020000; aducm360_build_sector_list(bank); return ERROR_OK; } #define FLASH_SECTOR_SIZE 512 /* ----------------------------------------------------------------------- */ static int aducm360_build_sector_list(struct flash_bank *bank) { uint32_t offset = 0; /* sector size is 512 */ bank->num_sectors = bank->size / FLASH_SECTOR_SIZE; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned i = 0; i < bank->num_sectors; ++i) { bank->sectors[i].offset = offset; bank->sectors[i].size = FLASH_SECTOR_SIZE; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } return ERROR_OK; } /* ----------------------------------------------------------------------- */ static int aducm360_mass_erase(struct target *target) { uint32_t value; int res = ERROR_OK; /* Clear any old status */ target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value); /* Enable the writing to the flash*/ aducm360_set_write_enable(target, 1); /* Unlock for writing */ target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F456); target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F123); /* Issue the 'MASSERASE' command */ target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEECMD, 0x00000003); /* Check the result */ res = aducm360_check_flash_completion(target, 3500); if (res != ERROR_OK) { LOG_ERROR("mass erase failed."); aducm360_set_write_enable(target, 0); res = ERROR_FLASH_OPERATION_FAILED; } return res; } /* ----------------------------------------------------------------------- */ static int aducm360_page_erase(struct target *target, uint32_t padd) { uint32_t value; int res = ERROR_OK; /* Clear any old status */ target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value); /* Enable the writing to the flash*/ aducm360_set_write_enable(target, 1); /* Unlock for writing */ target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F456); target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEKEY, 0x0000F123); /* Write the sector address */ target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEADR0L, padd & 0xFFFF); target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEEADR0H, (padd>>16) & 0xFFFF); /* Issue the 'ERASEPAGE' command */ target_write_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEECMD, 0x00000001); /* Check the result */ res = aducm360_check_flash_completion(target, 50); if (res != ERROR_OK) { LOG_ERROR("page erase failed at 0x%08" PRIx32, padd); aducm360_set_write_enable(target, 0); res = ERROR_FLASH_OPERATION_FAILED; } return res; } /* ----------------------------------------------------------------------- */ static int aducm360_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int res = ERROR_OK; int i; int count; struct target *target = bank->target; uint32_t padd; if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) { res = aducm360_mass_erase(target); } else { count = last - first + 1; for (i = 0; i < count; ++i) { padd = bank->base + ((first+i)*FLASH_SECTOR_SIZE); res = aducm360_page_erase(target, padd); if (res != ERROR_OK) break; } } return res; } /* ----------------------------------------------------------------------- */ static int aducm360_write_block_sync( struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t target_buffer_size = 8192; struct working_area *helper; struct working_area *target_buffer; uint32_t address = bank->base + offset; struct reg_param reg_params[8]; int retval = ERROR_OK; uint32_t entry_point = 0, exit_point = 0; uint32_t res; struct armv7m_algorithm armv7m_algo; static const uint32_t aducm360_flash_write_code[] = { /* helper.code */ 0x88AF4D10, 0x0704F047, 0x682F80AF, 0x600E6806, 0xF017882F, 0xF43F0F08, 0xF851AFFB, 0x42B77B04, 0x800DF040, 0x0004F100, 0xF47F3A04, 0x686FAFEF, 0x0704F027, 0xF04F80AF, 0xF0000400, 0xF04FB802, 0xBE000480, 0x40002800, 0x00015000, 0x20000000, 0x00013000 }; LOG_DEBUG("'aducm360_write_block_sync' requested, dst:0x%08" PRIx32 ", count:0x%08" PRIx32 "bytes.", address, count); /* ----- Check the destination area for a Long Word alignment ----- */ if (((count%4) != 0) || ((offset%4) != 0)) { LOG_ERROR("write block must be multiple of four bytes in offset & length"); return ERROR_FAIL; } /* ----- Allocate space in the target's RAM for the helper code ----- */ if (target_alloc_working_area(target, sizeof(aducm360_flash_write_code), &helper) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* ----- Upload the helper code to the space in the target's RAM ----- */ uint8_t code[sizeof(aducm360_flash_write_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(aducm360_flash_write_code), aducm360_flash_write_code); retval = target_write_buffer(target, helper->address, sizeof(code), code); if (retval != ERROR_OK) return retval; entry_point = helper->address; /* ----- Allocate space in the target's RAM for the user application's object code ----- */ while (target_alloc_working_area_try(target, target_buffer_size, &target_buffer) != ERROR_OK) { LOG_WARNING("couldn't allocate a buffer space of 0x%08" PRIx32 "bytes in the target's SRAM.", target_buffer_size); target_buffer_size /= 2; if (target_buffer_size <= 256) { /* No room available */ LOG_WARNING("no large enough working area available, can't do block memory writes"); target_free_working_area(target, helper); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } /* ----- Prepare the target for the helper ----- */ armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC; armv7m_algo.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /*SRC */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /*DST */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /*COUNT */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /*not used */ init_reg_param(®_params[4], "r4", 32, PARAM_IN); /*RESULT */ /* ===== Execute the Main Programming Loop! ===== */ while (count > 0) { uint32_t thisrun_count = (count > target_buffer_size) ? target_buffer_size : count; /* ----- Upload the chunk ----- */ retval = target_write_buffer(target, target_buffer->address, thisrun_count, buffer); if (retval != ERROR_OK) break; /* Set the arguments for the helper */ buf_set_u32(reg_params[0].value, 0, 32, target_buffer->address); /*SRC */ buf_set_u32(reg_params[1].value, 0, 32, address); /*DST */ buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); /*COUNT */ buf_set_u32(reg_params[3].value, 0, 32, 0); /*NOT USED*/ retval = target_run_algorithm(target, 0, NULL, 5, reg_params, entry_point, exit_point, 10000, &armv7m_algo); if (retval != ERROR_OK) { LOG_ERROR("error executing aducm360 flash write algorithm"); break; } res = buf_get_u32(reg_params[4].value, 0, 32); if (res) { LOG_ERROR("aducm360 fast sync algorithm reports an error (%02" PRIX32 ")", res); retval = ERROR_FAIL; break; } buffer += thisrun_count; address += thisrun_count; count -= thisrun_count; } target_free_working_area(target, target_buffer); target_free_working_area(target, helper); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; } /* ----------------------------------------------------------------------- */ static int aducm360_write_block_async( struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t target_buffer_size = 1024; struct working_area *helper; struct working_area *target_buffer; uint32_t address = bank->base + offset; struct reg_param reg_params[9]; int retval = ERROR_OK; uint32_t entry_point = 0, exit_point = 0; uint32_t res; uint32_t wcount; struct armv7m_algorithm armv7m_algo; static const uint32_t aducm360_flash_write_code[] = { /* helper.code */ 0x4050F8DF, 0xF04588A5, 0x80A50504, 0x8000F8D0, 0x0F00F1B8, 0x8016F000, 0x45476847, 0xAFF6F43F, 0x6B04F857, 0x6B04F842, 0xF0158825, 0xF43F0F08, 0x428FAFFB, 0xF100BF28, 0x60470708, 0xB10B3B01, 0xBFE4F7FF, 0xF02588A5, 0x80A50504, 0x0900F04F, 0xBE00BF00, 0x40002800, 0x20000000, 0x20000100, 0x00013000 }; LOG_DEBUG("'aducm360_write_block_async' requested, dst:0x%08" PRIx32 ", count:0x%08" PRIx32 "bytes.", address, count); /* ----- Check the destination area for a Long Word alignment ----- */ if (((count%4) != 0) || ((offset%4) != 0)) { LOG_ERROR("write block must be multiple of four bytes in offset & length"); return ERROR_FAIL; } wcount = count/4; /* ----- Allocate space in the target's RAM for the helper code ----- */ if (target_alloc_working_area(target, sizeof(aducm360_flash_write_code), &helper) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* ----- Upload the helper code to the space in the target's RAM ----- */ uint8_t code[sizeof(aducm360_flash_write_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(aducm360_flash_write_code), aducm360_flash_write_code); retval = target_write_buffer(target, helper->address, sizeof(code), code); if (retval != ERROR_OK) return retval; entry_point = helper->address; /* ----- Allocate space in the target's RAM for the user application's object code ----- */ while (target_alloc_working_area_try(target, target_buffer_size, &target_buffer) != ERROR_OK) { LOG_WARNING("couldn't allocate a buffer space of 0x%08" PRIx32 "bytes in the target's SRAM.", target_buffer_size); target_buffer_size /= 2; if (target_buffer_size <= 256) { /* No room available */ LOG_WARNING("no large enough working area available, can't do block memory writes"); target_free_working_area(target, helper); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } /* ----- Prepare the target for the helper ----- */ armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC; armv7m_algo.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /*SRCBEG */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /*SRCEND */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /*DST */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /*COUNT (LWs)*/ init_reg_param(®_params[4], "r9", 32, PARAM_IN); /*RESULT */ buf_set_u32(reg_params[0].value, 0, 32, target_buffer->address); buf_set_u32(reg_params[1].value, 0, 32, target_buffer->address + target_buffer->size); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[3].value, 0, 32, wcount); retval = target_run_flash_async_algorithm(target, buffer, wcount, 4, 0, NULL, 5, reg_params, target_buffer->address, target_buffer->size, entry_point, exit_point, &armv7m_algo); if (retval != ERROR_OK) { LOG_ERROR("error executing aducm360 flash write algorithm"); } else { res = buf_get_u32(reg_params[4].value, 0, 32); /*RESULT*/ if (res) { LOG_ERROR("aducm360 fast async algorithm reports an error (%02" PRIX32 ")", res); retval = ERROR_FAIL; } } target_free_working_area(target, target_buffer); target_free_working_area(target, helper); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; } /* ----------------------------------------------------------------------- */ /* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall * back to another mechanism that does not require onboard RAM * * Caller should not check for other return values specifically */ static int aducm360_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int choice = 0; switch (choice) { case 0: return aducm360_write_block_sync(bank, buffer, offset, count); case 1: return aducm360_write_block_async(bank, buffer, offset, count); default: LOG_ERROR("aducm360_write_block was cancelled (no writing method was chosen)!"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } /* ----------------------------------------------------------------------- */ #define FEESTA_WRDONE 0x00000008 static int aducm360_write_modified(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { uint32_t value; int res = ERROR_OK; uint32_t i, j, a, d; struct target *target = bank->target; LOG_DEBUG("performing slow write (offset=0x%08" PRIx32 ", count=0x%08" PRIx32 ")...", offset, count); /* Enable the writing to the flash */ aducm360_set_write_enable(target, 1); /* Clear any old status */ target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value); for (i = 0; i < count; i += 4) { a = offset+i; for (j = 0; i < 4; i += 1) *((uint8_t *)(&d) + j) = buffer[i+j]; target_write_u32(target, a, d); do { target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEESTA, &value); } while (!(value & FEESTA_WRDONE)); } aducm360_set_write_enable(target, 0); return res; } /* ----------------------------------------------------------------------- */ static int aducm360_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; /* try using a block write */ retval = aducm360_write_block(bank, buffer, offset, count); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * use normal (slow) JTAG method */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); retval = aducm360_write_modified(bank, buffer, offset, count); if (retval != ERROR_OK) { LOG_ERROR("slow write failed"); return ERROR_FLASH_OPERATION_FAILED; } } } return retval; } /* ----------------------------------------------------------------------- */ static int aducm360_probe(struct flash_bank *bank) { return ERROR_OK; } /* ----------------------------------------------------------------------- */ /* sets FEECON0 bit 2 * enable = 1 enables writes & erases, 0 disables them */ static int aducm360_set_write_enable(struct target *target, int enable) { /* don't bother to preserve int enable bit here */ uint32_t value; target_read_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEECON0, &value); if (enable) value |= 0x00000004; else value &= ~0x00000004; target_write_u32(target, ADUCM360_FLASH_BASE + ADUCM360_FLASH_FEECON0, value); return ERROR_OK; } /* ----------------------------------------------------------------------- */ /* wait up to timeout_ms for controller to not be busy, * then check whether the command passed or failed. * * this function sleeps 1ms between checks (after the first one), * so in some cases may slow things down without a usleep after the first read */ static int aducm360_check_flash_completion(struct target *target, unsigned int timeout_ms) { uint32_t v = 1; int64_t endtime = timeval_ms() + timeout_ms; while (1) { target_read_u32(target, ADUCM360_FLASH_BASE+ADUCM360_FLASH_FEESTA, &v); if ((v & 0x00000001) == 0) break; alive_sleep(1); if (timeval_ms() >= endtime) break; } if (!(v & 0x00000004)) /* b2 */ return ERROR_FAIL; return ERROR_OK; } /* ----------------------------------------------------------------------- */ const struct flash_driver aducm360_flash = { .name = "aducm360", .flash_bank_command = aducm360_flash_bank_command, .erase = aducm360_erase, .write = aducm360_write, .read = default_flash_read, .probe = aducm360_probe, .auto_probe = aducm360_probe, .erase_check = default_flash_blank_check, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/ambiqmicro.c ================================================ // SPDX-License-Identifier: BSD-3-Clause /****************************************************************************** * * @file ambiqmicro.c * * @brief Ambiq Micro flash driver. * *****************************************************************************/ /****************************************************************************** * Copyright (c) 2015, David Racine <dracine at ambiqmicro.com> * * Copyright (c) 2016, Rick Foos <rfoos at solengtech.com> * * Copyright (c) 2015-2016, Ambiq Micro, Inc. * * All rights reserved. *****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/interface.h" #include "imp.h" #include "target/algorithm.h" #include "target/armv7m.h" #include "target/cortex_m.h" /** Check error, log error. */ #define CHECK_STATUS(rc, msg) { \ if (rc != ERROR_OK) { \ LOG_ERROR("status(%d):%s\n", rc, msg); } } /* * Address and Key defines. */ #define PROGRAM_KEY (0x12344321) #define OTP_PROGRAM_KEY (0x87655678) #define FLASH_PROGRAM_MAIN_FROM_SRAM 0x0800005d #define FLASH_PROGRAM_OTP_FROM_SRAM 0x08000061 #define FLASH_ERASE_LIST_MAIN_PAGES_FROM_SRAM 0x08000065 #define FLASH_MASS_ERASE_MAIN_PAGES_FROM_SRAM 0x08000069 static const uint32_t apollo_flash_size[] = { 1 << 15, 1 << 16, 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 21 }; static const uint32_t apollo_sram_size[] = { 1 << 15, 1 << 16, 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 21 }; struct ambiqmicro_flash_bank { /* chip id register */ bool probed; const char *target_name; uint8_t target_class; uint32_t sramsiz; uint32_t flshsiz; /* flash geometry */ uint32_t num_pages; uint32_t pagesize; uint32_t pages_in_lockregion; /* nv memory bits */ uint16_t num_lockbits; /* main clock status */ uint32_t rcc; uint32_t rcc2; uint8_t mck_valid; uint8_t xtal_mask; uint32_t iosc_freq; uint32_t mck_freq; const char *iosc_desc; const char *mck_desc; }; static struct { uint8_t class; uint8_t partno; const char *partname; } ambiqmicro_parts[6] = { {0xFF, 0x00, "Unknown"}, {0x01, 0x00, "Apollo"}, {0x02, 0x00, "Apollo2"}, {0x03, 0x00, "Unknown"}, {0x04, 0x00, "Unknown"}, {0x05, 0x00, "Apollo"}, }; static char *ambiqmicro_classname[6] = { "Unknown", "Apollo", "Apollo2", "Unknown", "Unknown", "Apollo" }; /*************************************************************************** * openocd command interface * ***************************************************************************/ /* flash_bank ambiqmicro <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(ambiqmicro_flash_bank_command) { struct ambiqmicro_flash_bank *ambiqmicro_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; ambiqmicro_info = calloc(sizeof(struct ambiqmicro_flash_bank), 1); bank->driver_priv = ambiqmicro_info; ambiqmicro_info->target_name = "Unknown target"; /* part wasn't probed yet */ ambiqmicro_info->probed = false; return ERROR_OK; } static int get_ambiqmicro_info(struct flash_bank *bank, struct command_invocation *cmd) { struct ambiqmicro_flash_bank *ambiqmicro_info = bank->driver_priv; char *classname; if (!ambiqmicro_info->probed) { LOG_ERROR("Target not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } /* Check class name in range. */ if (ambiqmicro_info->target_class < sizeof(ambiqmicro_classname)) classname = ambiqmicro_classname[ambiqmicro_info->target_class]; else classname = ambiqmicro_classname[0]; command_print_sameline(cmd, "\nAmbiq Micro information: Chip is " "class %d (%s) %s\n", ambiqmicro_info->target_class, classname, ambiqmicro_info->target_name); return ERROR_OK; } /*************************************************************************** * chip identification and status * ***************************************************************************/ /* Fill in driver info structure */ static int ambiqmicro_read_part_info(struct flash_bank *bank) { struct ambiqmicro_flash_bank *ambiqmicro_info = bank->driver_priv; struct target *target = bank->target; uint32_t part_num = 0; int retval; /* * Read Part Number. */ retval = target_read_u32(target, 0x40020000, &part_num); if (retval != ERROR_OK) { LOG_ERROR("status(0x%x):Could not read part_num.\n", retval); /* Set part_num to default device */ part_num = 0; } LOG_DEBUG("Part number: 0x%" PRIx32, part_num); /* * Determine device class. */ ambiqmicro_info->target_class = (part_num & 0xFF000000) >> 24; switch (ambiqmicro_info->target_class) { case 1: /* 1 - Apollo */ case 5: /* 5 - Apollo Bootloader */ bank->base = bank->bank_number * 0x40000; ambiqmicro_info->pagesize = 2048; ambiqmicro_info->flshsiz = apollo_flash_size[(part_num & 0x00F00000) >> 20]; ambiqmicro_info->sramsiz = apollo_sram_size[(part_num & 0x000F0000) >> 16]; ambiqmicro_info->num_pages = ambiqmicro_info->flshsiz / ambiqmicro_info->pagesize; if (ambiqmicro_info->num_pages > 128) { ambiqmicro_info->num_pages = 128; ambiqmicro_info->flshsiz = 1024 * 256; } break; default: LOG_INFO("Unknown Class. Using Apollo-64 as default."); bank->base = bank->bank_number * 0x40000; ambiqmicro_info->pagesize = 2048; ambiqmicro_info->flshsiz = apollo_flash_size[1]; ambiqmicro_info->sramsiz = apollo_sram_size[0]; ambiqmicro_info->num_pages = ambiqmicro_info->flshsiz / ambiqmicro_info->pagesize; if (ambiqmicro_info->num_pages > 128) { ambiqmicro_info->num_pages = 128; ambiqmicro_info->flshsiz = 1024 * 256; } break; } if (ambiqmicro_info->target_class < ARRAY_SIZE(ambiqmicro_parts)) ambiqmicro_info->target_name = ambiqmicro_parts[ambiqmicro_info->target_class].partname; else ambiqmicro_info->target_name = ambiqmicro_parts[0].partname; LOG_DEBUG("num_pages: %" PRIu32 ", pagesize: %" PRIu32 ", flash: %" PRIu32 ", sram: %" PRIu32, ambiqmicro_info->num_pages, ambiqmicro_info->pagesize, ambiqmicro_info->flshsiz, ambiqmicro_info->sramsiz); return ERROR_OK; } /*************************************************************************** * flash operations * ***************************************************************************/ static int ambiqmicro_protect_check(struct flash_bank *bank) { struct ambiqmicro_flash_bank *ambiqmicro = bank->driver_priv; int status = ERROR_OK; uint32_t i; if (!ambiqmicro->probed) { LOG_ERROR("Target not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } for (i = 0; i < (unsigned) bank->num_sectors; i++) bank->sectors[i].is_protected = -1; return status; } /** Read flash status from bootloader. */ static int check_flash_status(struct target *target, uint32_t address) { uint32_t retflash; int rc; rc = target_read_u32(target, address, &retflash); /* target connection failed. */ if (rc != ERROR_OK) { LOG_DEBUG("%s:%d:%s(): status(0x%x)\n", __FILE__, __LINE__, __func__, rc); return rc; } /* target flash failed, unknown cause. */ if (retflash != 0) { LOG_ERROR("Flash not happy: status(0x%" PRIx32 ")", retflash); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int ambiqmicro_exec_command(struct target *target, uint32_t command, uint32_t flash_return_address) { int retval, retflash; retval = target_resume( target, false, command, true, true); CHECK_STATUS(retval, "error executing ambiqmicro command"); /* * Wait for halt. */ for (;; ) { target_poll(target); if (target->state == TARGET_HALTED) break; else if (target->state == TARGET_RUNNING || target->state == TARGET_DEBUG_RUNNING) { /* * Keep polling until target halts. */ target_poll(target); alive_sleep(100); LOG_DEBUG("state = %d", target->state); } else { LOG_ERROR("Target not halted or running %d", target->state); break; } } /* * Read return value, flash error takes precedence. */ retflash = check_flash_status(target, flash_return_address); if (retflash != ERROR_OK) retval = retflash; /* Return code from target_resume OR flash. */ return retval; } static int ambiqmicro_mass_erase(struct flash_bank *bank) { struct target *target = NULL; struct ambiqmicro_flash_bank *ambiqmicro_info = NULL; int retval = ERROR_OK; ambiqmicro_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!ambiqmicro_info->probed) { LOG_ERROR("Target not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } /* * Clear Bootloader bit. */ retval = target_write_u32(target, 0x400201a0, 0x0); CHECK_STATUS(retval, "error clearing bootloader bit."); /* * Set up the SRAM. */ /* * Bank. */ retval = target_write_u32(target, 0x10000000, bank->bank_number); CHECK_STATUS(retval, "error writing target SRAM parameters."); /* * Write Key. */ retval = target_write_u32(target, 0x10000004, PROGRAM_KEY); CHECK_STATUS(retval, "error writing target SRAM parameters."); /* * Breakpoint. */ retval = target_write_u32(target, 0x10000008, 0xfffffffe); CHECK_STATUS(retval, "error writing target SRAM parameters."); /* * Erase the main array. */ LOG_INFO("Mass erase on bank %d.", bank->bank_number); /* * passed pc, addr = ROM function, handle breakpoints, not debugging. */ retval = ambiqmicro_exec_command(target, FLASH_MASS_ERASE_MAIN_PAGES_FROM_SRAM, 0x10000008); CHECK_STATUS(retval, "error executing ambiqmicro flash mass erase."); if (retval != ERROR_OK) return retval; /* * Set Bootloader bit, regardless of command execution. */ retval = target_write_u32(target, 0x400201a0, 0x1); CHECK_STATUS(retval, "error setting bootloader bit."); return retval; } static int ambiqmicro_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct ambiqmicro_flash_bank *ambiqmicro_info = bank->driver_priv; struct target *target = bank->target; int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!ambiqmicro_info->probed) { LOG_ERROR("Target not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } /* * Check pages. * Fix num_pages for the device. */ if ((last < first) || (last >= ambiqmicro_info->num_pages)) return ERROR_FLASH_SECTOR_INVALID; /* * Just Mass Erase if all pages are given. * TODO: Fix num_pages for the device */ if ((first == 0) && (last == (ambiqmicro_info->num_pages - 1))) return ambiqmicro_mass_erase(bank); /* * Clear Bootloader bit. */ retval = target_write_u32(target, 0x400201a0, 0x0); CHECK_STATUS(retval, "error clearing bootloader bit."); /* * Set up the SRAM. */ /* * Bank. */ retval = target_write_u32(target, 0x10000000, bank->bank_number); CHECK_STATUS(retval, "error writing target SRAM parameters."); /* * Number of pages to erase. */ retval = target_write_u32(target, 0x10000004, 1 + (last-first)); CHECK_STATUS(retval, "error writing target SRAM parameters."); /* * Write Key. */ retval = target_write_u32(target, 0x10000008, PROGRAM_KEY); CHECK_STATUS(retval, "error writing target SRAM parameters."); /* * Breakpoint. */ retval = target_write_u32(target, 0x1000000c, 0xfffffffe); CHECK_STATUS(retval, "error writing target SRAM parameters."); /* * Pointer to flash address. */ retval = target_write_u32(target, 0x10000010, first); CHECK_STATUS(retval, "error writing target SRAM parameters."); if (retval != ERROR_OK) return retval; /* * Erase the pages. */ LOG_INFO("Erasing pages %u to %u on bank %u", first, last, bank->bank_number); /* * passed pc, addr = ROM function, handle breakpoints, not debugging. */ retval = ambiqmicro_exec_command(target, FLASH_ERASE_LIST_MAIN_PAGES_FROM_SRAM, 0x1000000C); CHECK_STATUS(retval, "error executing flash page erase"); if (retval != ERROR_OK) return retval; LOG_INFO("%u pages erased!", 1+(last-first)); if (first == 0) { /* * Set Bootloader bit. */ retval = target_write_u32(target, 0x400201a0, 0x1); CHECK_STATUS(retval, "error setting bootloader bit."); if (retval != ERROR_OK) return retval; } return retval; } static int ambiqmicro_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { /* struct ambiqmicro_flash_bank *ambiqmicro_info = bank->driver_priv; * struct target *target = bank->target; */ /* * TODO */ LOG_INFO("Not yet implemented"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } return ERROR_OK; } static int ambiqmicro_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { /* struct ambiqmicro_flash_bank *ambiqmicro_info = bank->driver_priv; */ struct target *target = bank->target; uint32_t address = bank->base + offset; uint32_t buffer_pointer = 0x10000010; uint32_t maxbuffer; uint32_t thisrun_count; int retval = ERROR_OK; if (((count%4) != 0) || ((offset%4) != 0)) { LOG_ERROR("write block must be multiple of 4 bytes in offset & length"); return ERROR_FAIL; } /* * Max buffer size for this device. * Hard code 6kB for the buffer. */ maxbuffer = 0x1800; LOG_INFO("Flashing main array"); while (count > 0) { if (count > maxbuffer) thisrun_count = maxbuffer; else thisrun_count = count; /* * Set up the SRAM. */ /* * Pointer to flash. */ retval = target_write_u32(target, 0x10000000, address); CHECK_STATUS(retval, "error writing target SRAM parameters."); /* * Number of 32-bit words to program. */ retval = target_write_u32(target, 0x10000004, thisrun_count/4); CHECK_STATUS(retval, "error writing target SRAM parameters."); /* * Write Key. */ retval = target_write_u32(target, 0x10000008, PROGRAM_KEY); CHECK_STATUS(retval, "error writing target SRAM parameters."); /* * Breakpoint. */ retval = target_write_u32(target, 0x1000000c, 0xfffffffe); CHECK_STATUS(retval, "error writing target SRAM parameters."); /* * Write Buffer. */ retval = target_write_buffer(target, buffer_pointer, thisrun_count, buffer); if (retval != ERROR_OK) { CHECK_STATUS(retval, "error writing target SRAM parameters."); break; } LOG_DEBUG("address = 0x%08" PRIx32, address); retval = ambiqmicro_exec_command(target, FLASH_PROGRAM_MAIN_FROM_SRAM, 0x1000000c); CHECK_STATUS(retval, "error executing ambiqmicro flash write algorithm"); if (retval != ERROR_OK) break; buffer += thisrun_count; address += thisrun_count; count -= thisrun_count; } LOG_INFO("Main array flashed"); /* * Clear Bootloader bit. */ retval = target_write_u32(target, 0x400201a0, 0x0); CHECK_STATUS(retval, "error clearing bootloader bit"); return retval; } static int ambiqmicro_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; /* try using a block write */ retval = ambiqmicro_write_block(bank, buffer, offset, count); if (retval != ERROR_OK) LOG_ERROR("write failed"); return retval; } static int ambiqmicro_probe(struct flash_bank *bank) { struct ambiqmicro_flash_bank *ambiqmicro_info = bank->driver_priv; int retval; /* If this is a ambiqmicro chip, it has flash; probe() is just * to figure out how much is present. Only do it once. */ if (ambiqmicro_info->probed) { LOG_INFO("Target already probed"); return ERROR_OK; } /* ambiqmicro_read_part_info() already handled error checking and * reporting. Note that it doesn't write, so we don't care about * whether the target is halted or not. */ retval = ambiqmicro_read_part_info(bank); if (retval != ERROR_OK) return retval; free(bank->sectors); /* provide this for the benefit of the NOR flash framework */ bank->size = ambiqmicro_info->pagesize * ambiqmicro_info->num_pages; bank->num_sectors = ambiqmicro_info->num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = i * ambiqmicro_info->pagesize; bank->sectors[i].size = ambiqmicro_info->pagesize; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } /* * Part has been probed. */ ambiqmicro_info->probed = true; return retval; } static int ambiqmicro_otp_program(struct flash_bank *bank, uint32_t offset, uint32_t count) { struct target *target = NULL; struct ambiqmicro_flash_bank *ambiqmicro_info = NULL; int retval; ambiqmicro_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!ambiqmicro_info->probed) { LOG_ERROR("Target not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } if (count > 256) { LOG_ERROR("Count must be < 256"); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* * Clear Bootloader bit. */ retval = target_write_u32(target, 0x400201a0, 0x0); CHECK_STATUS(retval, "error clearing bootloader bit."); /* * Set up the SRAM. */ /* * Bank. */ retval = target_write_u32(target, 0x10000000, offset); CHECK_STATUS(retval, "error setting target SRAM parameters."); /* * Num of words to program. */ retval = target_write_u32(target, 0x10000004, count); CHECK_STATUS(retval, "error setting target SRAM parameters."); /* * Write Key. */ retval = target_write_u32(target, 0x10000008, OTP_PROGRAM_KEY); CHECK_STATUS(retval, "error setting target SRAM parameters."); /* * Breakpoint. */ retval = target_write_u32(target, 0x1000000c, 0xfffffffe); CHECK_STATUS(retval, "error setting target SRAM parameters."); if (retval != ERROR_OK) return retval; /* * Program OTP. */ LOG_INFO("Programming OTP offset 0x%08" PRIx32, offset); /* * passed pc, addr = ROM function, handle breakpoints, not debugging. */ retval = ambiqmicro_exec_command(target, FLASH_PROGRAM_OTP_FROM_SRAM, 0x1000000C); CHECK_STATUS(retval, "error executing ambiqmicro otp program algorithm"); LOG_INFO("Programming OTP finished."); return retval; } COMMAND_HANDLER(ambiqmicro_handle_mass_erase_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; if (ambiqmicro_mass_erase(bank) == ERROR_OK) command_print(CMD, "ambiqmicro mass erase complete"); else command_print(CMD, "ambiqmicro mass erase failed"); return ERROR_OK; } COMMAND_HANDLER(ambiqmicro_handle_page_erase_command) { struct flash_bank *bank; uint32_t first, last; int retval; if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], first); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last); retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; if (ambiqmicro_erase(bank, first, last) == ERROR_OK) command_print(CMD, "ambiqmicro page erase complete"); else command_print(CMD, "ambiqmicro page erase failed"); return ERROR_OK; } /** * Program the otp block. */ COMMAND_HANDLER(ambiqmicro_handle_program_otp_command) { struct flash_bank *bank; uint32_t offset, count; int retval; if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], offset); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count); command_print(CMD, "offset=0x%08" PRIx32 " count=%" PRIu32, offset, count); CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); retval = ambiqmicro_otp_program(bank, offset, count); if (retval != ERROR_OK) LOG_ERROR("error check log"); return ERROR_OK; } static const struct command_registration ambiqmicro_exec_command_handlers[] = { { .name = "mass_erase", .usage = "<bank>", .handler = ambiqmicro_handle_mass_erase_command, .mode = COMMAND_EXEC, .help = "Erase entire device", }, { .name = "page_erase", .usage = "<bank> <first> <last>", .handler = ambiqmicro_handle_page_erase_command, .mode = COMMAND_EXEC, .help = "Erase device pages", }, { .name = "program_otp", .handler = ambiqmicro_handle_program_otp_command, .mode = COMMAND_EXEC, .usage = "<bank> <offset> <count>", .help = "Program OTP (assumes you have already written array starting at 0x10000010)", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration ambiqmicro_command_handlers[] = { { .name = "ambiqmicro", .mode = COMMAND_EXEC, .help = "ambiqmicro flash command group", .usage = "Support for Ambiq Micro parts.", .chain = ambiqmicro_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver ambiqmicro_flash = { .name = "ambiqmicro", .commands = ambiqmicro_command_handlers, .flash_bank_command = ambiqmicro_flash_bank_command, .erase = ambiqmicro_erase, .protect = ambiqmicro_protect, .write = ambiqmicro_write, .read = default_flash_read, .probe = ambiqmicro_probe, .auto_probe = ambiqmicro_probe, .erase_check = default_flash_blank_check, .protect_check = ambiqmicro_protect_check, .info = get_ambiqmicro_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/at91sam3.c ================================================ // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-Source-Code) /* * Copyright (C) 2009 by Duane Ellis <openocd@duaneellis.com> * * at91sam3s* support * Copyright (C) 2010 by Olaf Lüke <olaf@uni-paderborn.de> * Copyright (C) 2011 by Olivier Schonken and Jim Norris * * Some of the lower level code was based on code supplied by * ATMEL under BSD-Source-Code License and this copyright. * ATMEL Microcontroller Software Support * Copyright (c) 2009, Atmel Corporation. All rights reserved. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/time_support.h> #define REG_NAME_WIDTH (12) /* at91sam3u series (has one or two flash banks) */ #define FLASH_BANK0_BASE_U 0x00080000 #define FLASH_BANK1_BASE_U 0x00100000 /* at91sam3s series (has always one flash bank) */ #define FLASH_BANK_BASE_S 0x00400000 /* at91sam3sd series (has always two flash banks) */ #define FLASH_BANK0_BASE_SD FLASH_BANK_BASE_S #define FLASH_BANK1_BASE_512K_SD (FLASH_BANK0_BASE_SD+(512*1024/2)) /* at91sam3n series (has always one flash bank) */ #define FLASH_BANK_BASE_N 0x00400000 /* at91sam3a/x series has two flash banks*/ #define FLASH_BANK0_BASE_AX 0x00080000 /*Bank 1 of the at91sam3a/x series starts at 0x00080000 + half flash size*/ #define FLASH_BANK1_BASE_256K_AX 0x000A0000 #define FLASH_BANK1_BASE_512K_AX 0x000C0000 #define AT91C_EFC_FCMD_GETD (0x0) /* (EFC) Get Flash Descriptor */ #define AT91C_EFC_FCMD_WP (0x1) /* (EFC) Write Page */ #define AT91C_EFC_FCMD_WPL (0x2) /* (EFC) Write Page and Lock */ #define AT91C_EFC_FCMD_EWP (0x3) /* (EFC) Erase Page and Write Page */ #define AT91C_EFC_FCMD_EWPL (0x4) /* (EFC) Erase Page and Write Page then Lock */ #define AT91C_EFC_FCMD_EA (0x5) /* (EFC) Erase All */ /* cmd6 is not present in the at91sam3u4/2/1 data sheet table 17-2 */ /* #define AT91C_EFC_FCMD_EPL (0x6) // (EFC) Erase plane? */ /* cmd7 is not present in the at91sam3u4/2/1 data sheet table 17-2 */ /* #define AT91C_EFC_FCMD_EPA (0x7) // (EFC) Erase pages? */ #define AT91C_EFC_FCMD_SLB (0x8) /* (EFC) Set Lock Bit */ #define AT91C_EFC_FCMD_CLB (0x9) /* (EFC) Clear Lock Bit */ #define AT91C_EFC_FCMD_GLB (0xA) /* (EFC) Get Lock Bit */ #define AT91C_EFC_FCMD_SFB (0xB) /* (EFC) Set Fuse Bit */ #define AT91C_EFC_FCMD_CFB (0xC) /* (EFC) Clear Fuse Bit */ #define AT91C_EFC_FCMD_GFB (0xD) /* (EFC) Get Fuse Bit */ #define AT91C_EFC_FCMD_STUI (0xE) /* (EFC) Start Read Unique ID */ #define AT91C_EFC_FCMD_SPUI (0xF) /* (EFC) Stop Read Unique ID */ #define OFFSET_EFC_FMR 0 #define OFFSET_EFC_FCR 4 #define OFFSET_EFC_FSR 8 #define OFFSET_EFC_FRR 12 static float _tomhz(uint32_t freq_hz) { float f; f = ((float)(freq_hz)) / 1000000.0; return f; } /* How the chip is configured. */ struct sam3_cfg { uint32_t unique_id[4]; uint32_t slow_freq; uint32_t rc_freq; uint32_t mainosc_freq; uint32_t plla_freq; uint32_t mclk_freq; uint32_t cpu_freq; uint32_t fclk_freq; uint32_t pclk0_freq; uint32_t pclk1_freq; uint32_t pclk2_freq; #define SAM3_CHIPID_CIDR (0x400E0740) uint32_t CHIPID_CIDR; #define SAM3_CHIPID_CIDR2 (0x400E0940) /*SAM3X and SAM3A cidr at this address*/ uint32_t CHIPID_CIDR2; #define SAM3_CHIPID_EXID (0x400E0744) uint32_t CHIPID_EXID; #define SAM3_CHIPID_EXID2 (0x400E0944) /*SAM3X and SAM3A cidr at this address*/ uint32_t CHIPID_EXID2; #define SAM3_PMC_BASE (0x400E0400) #define SAM3_PMC_SCSR (SAM3_PMC_BASE + 0x0008) uint32_t PMC_SCSR; #define SAM3_PMC_PCSR (SAM3_PMC_BASE + 0x0018) uint32_t PMC_PCSR; #define SAM3_CKGR_UCKR (SAM3_PMC_BASE + 0x001c) uint32_t CKGR_UCKR; #define SAM3_CKGR_MOR (SAM3_PMC_BASE + 0x0020) uint32_t CKGR_MOR; #define SAM3_CKGR_MCFR (SAM3_PMC_BASE + 0x0024) uint32_t CKGR_MCFR; #define SAM3_CKGR_PLLAR (SAM3_PMC_BASE + 0x0028) uint32_t CKGR_PLLAR; #define SAM3_PMC_MCKR (SAM3_PMC_BASE + 0x0030) uint32_t PMC_MCKR; #define SAM3_PMC_PCK0 (SAM3_PMC_BASE + 0x0040) uint32_t PMC_PCK0; #define SAM3_PMC_PCK1 (SAM3_PMC_BASE + 0x0044) uint32_t PMC_PCK1; #define SAM3_PMC_PCK2 (SAM3_PMC_BASE + 0x0048) uint32_t PMC_PCK2; #define SAM3_PMC_SR (SAM3_PMC_BASE + 0x0068) uint32_t PMC_SR; #define SAM3_PMC_IMR (SAM3_PMC_BASE + 0x006c) uint32_t PMC_IMR; #define SAM3_PMC_FSMR (SAM3_PMC_BASE + 0x0070) uint32_t PMC_FSMR; #define SAM3_PMC_FSPR (SAM3_PMC_BASE + 0x0074) uint32_t PMC_FSPR; }; /* * The AT91SAM3N data sheet 04-Oct-2010, AT91SAM3U data sheet 22-Aug-2011 * and AT91SAM3S data sheet 09-Feb-2011 state that for flash writes * the flash wait state (FWS) should be set to 6. It seems like that the * cause of the problem is not the flash itself, but the flash write * buffer. Ie the wait states have to be set before writing into the * buffer. * Tested and confirmed with SAM3N and SAM3U */ struct sam3_bank_private { bool probed; /* DANGER: THERE ARE DRAGONS HERE.. */ /* NOTE: If you add more 'ghost' pointers */ /* be aware that you must *manually* update */ /* these pointers in the function sam3_get_details() */ /* See the comment "Here there be dragons" */ /* so we can find the chip we belong to */ struct sam3_chip *chip; /* so we can find the original bank pointer */ struct flash_bank *bank; unsigned bank_number; uint32_t controller_address; uint32_t base_address; uint32_t flash_wait_states; bool present; unsigned size_bytes; unsigned nsectors; unsigned sector_size; unsigned page_size; }; struct sam3_chip_details { /* THERE ARE DRAGONS HERE.. */ /* note: If you add pointers here */ /* be careful about them as they */ /* may need to be updated inside */ /* the function: "sam3_get_details() */ /* which copy/overwrites the */ /* 'runtime' copy of this structure */ uint32_t chipid_cidr; const char *name; unsigned n_gpnvms; #define SAM3_N_NVM_BITS 3 unsigned gpnvm[SAM3_N_NVM_BITS]; unsigned total_flash_size; unsigned total_sram_size; unsigned n_banks; #define SAM3_MAX_FLASH_BANKS 2 /* these are "initialized" from the global const data */ struct sam3_bank_private bank[SAM3_MAX_FLASH_BANKS]; }; struct sam3_chip { struct sam3_chip *next; bool probed; /* this is "initialized" from the global const structure */ struct sam3_chip_details details; struct target *target; struct sam3_cfg cfg; }; struct sam3_reg_list { uint32_t address; size_t struct_offset; const char *name; void (*explain_func)(struct sam3_chip *chip); }; static struct sam3_chip *all_sam3_chips; static struct sam3_chip *get_current_sam3(struct command_invocation *cmd) { struct target *t; static struct sam3_chip *p; t = get_current_target(cmd->ctx); if (!t) { command_print_sameline(cmd, "No current target?\n"); return NULL; } p = all_sam3_chips; if (!p) { /* this should not happen */ /* the command is not registered until the chip is created? */ command_print_sameline(cmd, "No SAM3 chips exist?\n"); return NULL; } while (p) { if (p->target == t) return p; p = p->next; } command_print_sameline(cmd, "Cannot find SAM3 chip?\n"); return NULL; } /* these are used to *initialize* the "chip->details" structure. */ static const struct sam3_chip_details all_sam3_details[] = { /* Start at91sam3u* series */ { .chipid_cidr = 0x28100960, .name = "at91sam3u4e", .total_flash_size = 256 * 1024, .total_sram_size = 52 * 1024, .n_gpnvms = 3, .n_banks = 2, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 256, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_U, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 256, }, }, }, { .chipid_cidr = 0x281a0760, .name = "at91sam3u2e", .total_flash_size = 128 * 1024, .total_sram_size = 36 * 1024, .n_gpnvms = 2, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28190560, .name = "at91sam3u1e", .total_flash_size = 64 * 1024, .total_sram_size = 20 * 1024, .n_gpnvms = 2, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 8, .sector_size = 8192, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28000960, .name = "at91sam3u4c", .total_flash_size = 256 * 1024, .total_sram_size = 52 * 1024, .n_gpnvms = 3, .n_banks = 2, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ { { /* .bank[0] = { */ .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 256, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_U, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 256, }, }, }, { .chipid_cidr = 0x280a0760, .name = "at91sam3u2c", .total_flash_size = 128 * 1024, .total_sram_size = 36 * 1024, .n_gpnvms = 2, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28090560, .name = "at91sam3u1c", .total_flash_size = 64 * 1024, .total_sram_size = 20 * 1024, .n_gpnvms = 2, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 8, .sector_size = 8192, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, /* Start at91sam3s* series */ /* Note: The preliminary at91sam3s datasheet says on page 302 */ /* that the flash controller is at address 0x400E0800. */ /* This is _not_ the case, the controller resides at address 0x400e0a00. */ { .chipid_cidr = 0x28A00960, .name = "at91sam3s4c", .total_flash_size = 256 * 1024, .total_sram_size = 48 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28900960, .name = "at91sam3s4b", .total_flash_size = 256 * 1024, .total_sram_size = 48 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28800960, .name = "at91sam3s4a", .total_flash_size = 256 * 1024, .total_sram_size = 48 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28AA0760, .name = "at91sam3s2c", .total_flash_size = 128 * 1024, .total_sram_size = 32 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x289A0760, .name = "at91sam3s2b", .total_flash_size = 128 * 1024, .total_sram_size = 32 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x298B0A60, .name = "at91sam3sd8a", .total_flash_size = 512 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 32768, .page_size = 256, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_SD, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 32768, .page_size = 256, }, }, }, { .chipid_cidr = 0x299B0A60, .name = "at91sam3sd8b", .total_flash_size = 512 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 32768, .page_size = 256, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_SD, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 32768, .page_size = 256, }, }, }, { .chipid_cidr = 0x29ab0a60, .name = "at91sam3sd8c", .total_flash_size = 512 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 32768, .page_size = 256, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_SD, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 32768, .page_size = 256, }, }, }, { .chipid_cidr = 0x288A0760, .name = "at91sam3s2a", .total_flash_size = 128 * 1024, .total_sram_size = 32 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28A90560, .name = "at91sam3s1c", .total_flash_size = 64 * 1024, .total_sram_size = 16 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 4, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28990560, .name = "at91sam3s1b", .total_flash_size = 64 * 1024, .total_sram_size = 16 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 4, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28890560, .name = "at91sam3s1a", .total_flash_size = 64 * 1024, .total_sram_size = 16 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 4, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x288B0A60, .name = "at91sam3s8a", .total_flash_size = 256 * 2048, .total_sram_size = 64 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 2048, .nsectors = 16, .sector_size = 32768, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x289B0A60, .name = "at91sam3s8b", .total_flash_size = 256 * 2048, .total_sram_size = 64 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 2048, .nsectors = 16, .sector_size = 32768, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28AB0A60, .name = "at91sam3s8c", .total_flash_size = 256 * 2048, .total_sram_size = 64 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 2048, .nsectors = 16, .sector_size = 32768, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, /* Start at91sam3n* series */ { .chipid_cidr = 0x29540960, .name = "at91sam3n4c", .total_flash_size = 256 * 1024, .total_sram_size = 24 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29440960, .name = "at91sam3n4b", .total_flash_size = 256 * 1024, .total_sram_size = 24 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29340960, .name = "at91sam3n4a", .total_flash_size = 256 * 1024, .total_sram_size = 24 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29590760, .name = "at91sam3n2c", .total_flash_size = 128 * 1024, .total_sram_size = 16 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29490760, .name = "at91sam3n2b", .total_flash_size = 128 * 1024, .total_sram_size = 16 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29390760, .name = "at91sam3n2a", .total_flash_size = 128 * 1024, .total_sram_size = 16 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29580560, .name = "at91sam3n1c", .total_flash_size = 64 * 1024, .total_sram_size = 8 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 4, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29480560, .name = "at91sam3n1b", .total_flash_size = 64 * 1024, .total_sram_size = 8 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 4, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29380560, .name = "at91sam3n1a", .total_flash_size = 64 * 1024, .total_sram_size = 8 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 4, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29480360, .name = "at91sam3n0b", .total_flash_size = 32 * 1024, .total_sram_size = 8 * 1024, .n_gpnvms = 3, .n_banks = 1, /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 32 * 1024, .nsectors = 2, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29380360, .name = "at91sam3n0a", .total_flash_size = 32 * 1024, .total_sram_size = 8 * 1024, .n_gpnvms = 3, .n_banks = 1, /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 32 * 1024, .nsectors = 2, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29450260, .name = "at91sam3n00b", .total_flash_size = 16 * 1024, .total_sram_size = 4 * 1024, .n_gpnvms = 3, .n_banks = 1, /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 16 * 1024, .nsectors = 1, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29350260, .name = "at91sam3n00a", .total_flash_size = 16 * 1024, .total_sram_size = 4 * 1024, .n_gpnvms = 3, .n_banks = 1, /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 16 * 1024, .nsectors = 1, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = false, .bank_number = 1, }, }, }, /* Start at91sam3a series*/ /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ { .chipid_cidr = 0x283E0A60, .name = "at91sam3a8c", .total_flash_size = 512 * 1024, .total_sram_size = 96 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, }, }, { .chipid_cidr = 0x283B0960, .name = "at91sam3a4c", .total_flash_size = 256 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_256K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, }, }, /* Start at91sam3x* series */ /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /*at91sam3x8h - ES has an incorrect CIDR of 0x286E0A20*/ { .chipid_cidr = 0x286E0A20, .name = "at91sam3x8h - ES", .total_flash_size = 512 * 1024, .total_sram_size = 96 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, }, }, /*at91sam3x8h - ES2 and up uses the correct CIDR of 0x286E0A60*/ { .chipid_cidr = 0x286E0A60, .name = "at91sam3x8h", .total_flash_size = 512 * 1024, .total_sram_size = 96 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, }, }, { .chipid_cidr = 0x285E0A60, .name = "at91sam3x8e", .total_flash_size = 512 * 1024, .total_sram_size = 96 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, }, }, { .chipid_cidr = 0x284E0A60, .name = "at91sam3x8c", .total_flash_size = 512 * 1024, .total_sram_size = 96 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, }, }, { .chipid_cidr = 0x285B0960, .name = "at91sam3x4e", .total_flash_size = 256 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_256K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, }, }, { .chipid_cidr = 0x284B0960, .name = "at91sam3x4c", .total_flash_size = 256 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_256K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, }, }, /* terminate */ { .chipid_cidr = 0, .name = NULL, } }; /* Globals above */ /*********************************************************************** ********************************************************************** ********************************************************************** ********************************************************************** ********************************************************************** **********************************************************************/ /* *ATMEL* style code - from the SAM3 driver code */ /** * Get the current status of the EEFC and * the value of some status bits (LOCKE, PROGE). * @param private - info about the bank * @param v - result goes here */ static int efc_get_status(struct sam3_bank_private *private, uint32_t *v) { int r; r = target_read_u32(private->chip->target, private->controller_address + OFFSET_EFC_FSR, v); LOG_DEBUG("Status: 0x%08x (lockerror: %d, cmderror: %d, ready: %d)", (unsigned int)(*v), ((unsigned int)((*v >> 2) & 1)), ((unsigned int)((*v >> 1) & 1)), ((unsigned int)((*v >> 0) & 1))); return r; } /** * Get the result of the last executed command. * @param private - info about the bank * @param v - result goes here */ static int efc_get_result(struct sam3_bank_private *private, uint32_t *v) { int r; uint32_t rv; r = target_read_u32(private->chip->target, private->controller_address + OFFSET_EFC_FRR, &rv); if (v) *v = rv; LOG_DEBUG("Result: 0x%08x", ((unsigned int)(rv))); return r; } static int efc_start_command(struct sam3_bank_private *private, unsigned command, unsigned argument) { uint32_t n, v; int r; int retry; retry = 0; do_retry: /* Check command & argument */ switch (command) { case AT91C_EFC_FCMD_WP: case AT91C_EFC_FCMD_WPL: case AT91C_EFC_FCMD_EWP: case AT91C_EFC_FCMD_EWPL: /* case AT91C_EFC_FCMD_EPL: */ /* case AT91C_EFC_FCMD_EPA: */ case AT91C_EFC_FCMD_SLB: case AT91C_EFC_FCMD_CLB: n = (private->size_bytes / private->page_size); if (argument >= n) LOG_ERROR("*BUG*: Embedded flash has only %u pages", (unsigned)(n)); break; case AT91C_EFC_FCMD_SFB: case AT91C_EFC_FCMD_CFB: if (argument >= private->chip->details.n_gpnvms) { LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs", private->chip->details.n_gpnvms); } break; case AT91C_EFC_FCMD_GETD: case AT91C_EFC_FCMD_EA: case AT91C_EFC_FCMD_GLB: case AT91C_EFC_FCMD_GFB: case AT91C_EFC_FCMD_STUI: case AT91C_EFC_FCMD_SPUI: if (argument != 0) LOG_ERROR("Argument is meaningless for cmd: %d", command); break; default: LOG_ERROR("Unknown command %d", command); break; } if (command == AT91C_EFC_FCMD_SPUI) { /* this is a very special situation. */ /* Situation (1) - error/retry - see below */ /* And we are being called recursively */ /* Situation (2) - normal, finished reading unique id */ } else { /* it should be "ready" */ efc_get_status(private, &v); if (v & 1) { /* then it is ready */ /* we go on */ } else { if (retry) { /* we have done this before */ /* the controller is not responding. */ LOG_ERROR("flash controller(%d) is not ready! Error", private->bank_number); return ERROR_FAIL; } else { retry++; LOG_ERROR("Flash controller(%d) is not ready, attempting reset", private->bank_number); /* we do that by issuing the *STOP* command */ efc_start_command(private, AT91C_EFC_FCMD_SPUI, 0); /* above is recursive, and further recursion is blocked by */ /* if (command == AT91C_EFC_FCMD_SPUI) above */ goto do_retry; } } } v = (0x5A << 24) | (argument << 8) | command; LOG_DEBUG("Command: 0x%08x", ((unsigned int)(v))); r = target_write_u32(private->bank->target, private->controller_address + OFFSET_EFC_FCR, v); if (r != ERROR_OK) LOG_DEBUG("Error Write failed"); return r; } /** * Performs the given command and wait until its completion (or an error). * @param private - info about the bank * @param command - Command to perform. * @param argument - Optional command argument. * @param status - put command status bits here */ static int efc_perform_command(struct sam3_bank_private *private, unsigned command, unsigned argument, uint32_t *status) { int r; uint32_t v; int64_t ms_now, ms_end; /* default */ if (status) *status = 0; r = efc_start_command(private, command, argument); if (r != ERROR_OK) return r; ms_end = 500 + timeval_ms(); do { r = efc_get_status(private, &v); if (r != ERROR_OK) return r; ms_now = timeval_ms(); if (ms_now > ms_end) { /* error */ LOG_ERROR("Command timeout"); return ERROR_FAIL; } } while ((v & 1) == 0); /* error bits.. */ if (status) *status = (v & 0x6); return ERROR_OK; } /** * Read the unique ID. * @param private - info about the bank * The unique ID is stored in the 'private' structure. */ static int flashd_read_uid(struct sam3_bank_private *private) { int r; uint32_t v; int x; /* assume 0 */ private->chip->cfg.unique_id[0] = 0; private->chip->cfg.unique_id[1] = 0; private->chip->cfg.unique_id[2] = 0; private->chip->cfg.unique_id[3] = 0; LOG_DEBUG("Begin"); r = efc_start_command(private, AT91C_EFC_FCMD_STUI, 0); if (r < 0) return r; for (x = 0; x < 4; x++) { r = target_read_u32(private->chip->target, private->bank->base + (x * 4), &v); if (r < 0) return r; private->chip->cfg.unique_id[x] = v; } r = efc_perform_command(private, AT91C_EFC_FCMD_SPUI, 0, NULL); LOG_DEBUG("End: R=%d, id = 0x%08x, 0x%08x, 0x%08x, 0x%08x", r, (unsigned int)(private->chip->cfg.unique_id[0]), (unsigned int)(private->chip->cfg.unique_id[1]), (unsigned int)(private->chip->cfg.unique_id[2]), (unsigned int)(private->chip->cfg.unique_id[3])); return r; } /** * Erases the entire flash. * @param private - the info about the bank. */ static int flashd_erase_entire_bank(struct sam3_bank_private *private) { LOG_DEBUG("Here"); return efc_perform_command(private, AT91C_EFC_FCMD_EA, 0, NULL); } /** * Gets current GPNVM state. * @param private - info about the bank. * @param gpnvm - GPNVM bit index. * @param puthere - result stored here. */ /* ------------------------------------------------------------------------------ */ static int flashd_get_gpnvm(struct sam3_bank_private *private, unsigned gpnvm, unsigned *puthere) { uint32_t v; int r; LOG_DEBUG("Here"); if (private->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } if (gpnvm >= private->chip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", gpnvm, private->chip->details.n_gpnvms); return ERROR_FAIL; } /* Get GPNVMs status */ r = efc_perform_command(private, AT91C_EFC_FCMD_GFB, 0, NULL); if (r != ERROR_OK) { LOG_ERROR("Failed"); return r; } r = efc_get_result(private, &v); if (puthere) { /* Check if GPNVM is set */ /* get the bit and make it a 0/1 */ *puthere = (v >> gpnvm) & 1; } return r; } /** * Clears the selected GPNVM bit. * @param private info about the bank * @param gpnvm GPNVM index. * @returns 0 if successful; otherwise returns an error code. */ static int flashd_clr_gpnvm(struct sam3_bank_private *private, unsigned gpnvm) { int r; unsigned v; LOG_DEBUG("Here"); if (private->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } if (gpnvm >= private->chip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", gpnvm, private->chip->details.n_gpnvms); return ERROR_FAIL; } r = flashd_get_gpnvm(private, gpnvm, &v); if (r != ERROR_OK) { LOG_DEBUG("Failed: %d", r); return r; } r = efc_perform_command(private, AT91C_EFC_FCMD_CFB, gpnvm, NULL); LOG_DEBUG("End: %d", r); return r; } /** * Sets the selected GPNVM bit. * @param private info about the bank * @param gpnvm GPNVM index. */ static int flashd_set_gpnvm(struct sam3_bank_private *private, unsigned gpnvm) { int r; unsigned v; if (private->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } if (gpnvm >= private->chip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", gpnvm, private->chip->details.n_gpnvms); return ERROR_FAIL; } r = flashd_get_gpnvm(private, gpnvm, &v); if (r != ERROR_OK) return r; if (v) { /* already set */ r = ERROR_OK; } else { /* set it */ r = efc_perform_command(private, AT91C_EFC_FCMD_SFB, gpnvm, NULL); } return r; } /** * Returns a bit field (at most 64) of locked regions within a page. * @param private info about the bank * @param v where to store locked bits */ static int flashd_get_lock_bits(struct sam3_bank_private *private, uint32_t *v) { int r; LOG_DEBUG("Here"); r = efc_perform_command(private, AT91C_EFC_FCMD_GLB, 0, NULL); if (r == ERROR_OK) r = efc_get_result(private, v); LOG_DEBUG("End: %d", r); return r; } /** * Unlocks all the regions in the given address range. * @param private info about the bank * @param start_sector first sector to unlock * @param end_sector last (inclusive) to unlock */ static int flashd_unlock(struct sam3_bank_private *private, unsigned start_sector, unsigned end_sector) { int r; uint32_t status; uint32_t pg; uint32_t pages_per_sector; pages_per_sector = private->sector_size / private->page_size; /* Unlock all pages */ while (start_sector <= end_sector) { pg = start_sector * pages_per_sector; r = efc_perform_command(private, AT91C_EFC_FCMD_CLB, pg, &status); if (r != ERROR_OK) return r; start_sector++; } return ERROR_OK; } /** * Locks regions * @param private - info about the bank * @param start_sector - first sector to lock * @param end_sector - last sector (inclusive) to lock */ static int flashd_lock(struct sam3_bank_private *private, unsigned start_sector, unsigned end_sector) { uint32_t status; uint32_t pg; uint32_t pages_per_sector; int r; pages_per_sector = private->sector_size / private->page_size; /* Lock all pages */ while (start_sector <= end_sector) { pg = start_sector * pages_per_sector; r = efc_perform_command(private, AT91C_EFC_FCMD_SLB, pg, &status); if (r != ERROR_OK) return r; start_sector++; } return ERROR_OK; } /****** END SAM3 CODE ********/ /* begin helpful debug code */ /* print the fieldname, the field value, in dec & hex, and return field value */ static uint32_t sam3_reg_fieldname(struct sam3_chip *chip, const char *regname, uint32_t value, unsigned shift, unsigned width) { uint32_t v; int hwidth, dwidth; /* extract the field */ v = value >> shift; v = v & ((1 << width)-1); if (width <= 16) { hwidth = 4; dwidth = 5; } else { hwidth = 8; dwidth = 12; } /* show the basics */ LOG_USER_N("\t%*s: %*" PRIu32 " [0x%0*" PRIx32 "] ", REG_NAME_WIDTH, regname, dwidth, v, hwidth, v); return v; } static const char _unknown[] = "unknown"; static const char *const eproc_names[] = { _unknown, /* 0 */ "arm946es", /* 1 */ "arm7tdmi", /* 2 */ "Cortex-M3", /* 3 */ "arm920t", /* 4 */ "arm926ejs", /* 5 */ _unknown, /* 6 */ _unknown, /* 7 */ _unknown, /* 8 */ _unknown, /* 9 */ _unknown, /* 10 */ _unknown, /* 11 */ _unknown, /* 12 */ _unknown, /* 13 */ _unknown, /* 14 */ _unknown, /* 15 */ }; #define nvpsize2 nvpsize /* these two tables are identical */ static const char *const nvpsize[] = { "none", /* 0 */ "8K bytes", /* 1 */ "16K bytes", /* 2 */ "32K bytes", /* 3 */ _unknown, /* 4 */ "64K bytes", /* 5 */ _unknown, /* 6 */ "128K bytes", /* 7 */ _unknown, /* 8 */ "256K bytes", /* 9 */ "512K bytes", /* 10 */ _unknown, /* 11 */ "1024K bytes", /* 12 */ _unknown, /* 13 */ "2048K bytes", /* 14 */ _unknown, /* 15 */ }; static const char *const sramsize[] = { "48K Bytes", /* 0 */ "1K Bytes", /* 1 */ "2K Bytes", /* 2 */ "6K Bytes", /* 3 */ "112K Bytes", /* 4 */ "4K Bytes", /* 5 */ "80K Bytes", /* 6 */ "160K Bytes", /* 7 */ "8K Bytes", /* 8 */ "16K Bytes", /* 9 */ "32K Bytes", /* 10 */ "64K Bytes", /* 11 */ "128K Bytes", /* 12 */ "256K Bytes", /* 13 */ "96K Bytes", /* 14 */ "512K Bytes", /* 15 */ }; static const struct archnames { unsigned value; const char *name; } archnames[] = { { 0x19, "AT91SAM9xx Series" }, { 0x29, "AT91SAM9XExx Series" }, { 0x34, "AT91x34 Series" }, { 0x37, "CAP7 Series" }, { 0x39, "CAP9 Series" }, { 0x3B, "CAP11 Series" }, { 0x40, "AT91x40 Series" }, { 0x42, "AT91x42 Series" }, { 0x55, "AT91x55 Series" }, { 0x60, "AT91SAM7Axx Series" }, { 0x61, "AT91SAM7AQxx Series" }, { 0x63, "AT91x63 Series" }, { 0x70, "AT91SAM7Sxx Series" }, { 0x71, "AT91SAM7XCxx Series" }, { 0x72, "AT91SAM7SExx Series" }, { 0x73, "AT91SAM7Lxx Series" }, { 0x75, "AT91SAM7Xxx Series" }, { 0x76, "AT91SAM7SLxx Series" }, { 0x80, "ATSAM3UxC Series (100-pin version)" }, { 0x81, "ATSAM3UxE Series (144-pin version)" }, { 0x83, "ATSAM3AxC Series (100-pin version)" }, { 0x84, "ATSAM3XxC Series (100-pin version)" }, { 0x85, "ATSAM3XxE Series (144-pin version)" }, { 0x86, "ATSAM3XxG Series (208/217-pin version)" }, { 0x88, "ATSAM3SxA Series (48-pin version)" }, { 0x89, "ATSAM3SxB Series (64-pin version)" }, { 0x8A, "ATSAM3SxC Series (100-pin version)" }, { 0x92, "AT91x92 Series" }, { 0x93, "ATSAM3NxA Series (48-pin version)" }, { 0x94, "ATSAM3NxB Series (64-pin version)" }, { 0x95, "ATSAM3NxC Series (100-pin version)" }, { 0x98, "ATSAM3SDxA Series (48-pin version)" }, { 0x99, "ATSAM3SDxB Series (64-pin version)" }, { 0x9A, "ATSAM3SDxC Series (100-pin version)" }, { 0xA5, "ATSAM5A" }, { 0xF0, "AT75Cxx Series" }, { -1, NULL }, }; static const char *const nvptype[] = { "rom", /* 0 */ "romless or onchip flash", /* 1 */ "embedded flash memory",/* 2 */ "rom(nvpsiz) + embedded flash (nvpsiz2)", /* 3 */ "sram emulating flash", /* 4 */ _unknown, /* 5 */ _unknown, /* 6 */ _unknown, /* 7 */ }; static const char *_yes_or_no(uint32_t v) { if (v) return "YES"; else return "NO"; } static const char *const _rc_freq[] = { "4 MHz", "8 MHz", "12 MHz", "reserved" }; static void sam3_explain_ckgr_mor(struct sam3_chip *chip) { uint32_t v; uint32_t rcen; v = sam3_reg_fieldname(chip, "MOSCXTEN", chip->cfg.CKGR_MOR, 0, 1); LOG_USER("(main xtal enabled: %s)", _yes_or_no(v)); v = sam3_reg_fieldname(chip, "MOSCXTBY", chip->cfg.CKGR_MOR, 1, 1); LOG_USER("(main osc bypass: %s)", _yes_or_no(v)); rcen = sam3_reg_fieldname(chip, "MOSCRCEN", chip->cfg.CKGR_MOR, 3, 1); LOG_USER("(onchip RC-OSC enabled: %s)", _yes_or_no(rcen)); v = sam3_reg_fieldname(chip, "MOSCRCF", chip->cfg.CKGR_MOR, 4, 3); LOG_USER("(onchip RC-OSC freq: %s)", _rc_freq[v]); chip->cfg.rc_freq = 0; if (rcen) { switch (v) { default: chip->cfg.rc_freq = 0; break; case 0: chip->cfg.rc_freq = 4 * 1000 * 1000; break; case 1: chip->cfg.rc_freq = 8 * 1000 * 1000; break; case 2: chip->cfg.rc_freq = 12 * 1000 * 1000; break; } } v = sam3_reg_fieldname(chip, "MOSCXTST", chip->cfg.CKGR_MOR, 8, 8); LOG_USER("(startup clks, time= %f uSecs)", ((float)(v * 1000000)) / ((float)(chip->cfg.slow_freq))); v = sam3_reg_fieldname(chip, "MOSCSEL", chip->cfg.CKGR_MOR, 24, 1); LOG_USER("(mainosc source: %s)", v ? "external xtal" : "internal RC"); v = sam3_reg_fieldname(chip, "CFDEN", chip->cfg.CKGR_MOR, 25, 1); LOG_USER("(clock failure enabled: %s)", _yes_or_no(v)); } static void sam3_explain_chipid_cidr(struct sam3_chip *chip) { int x; uint32_t v; const char *cp; sam3_reg_fieldname(chip, "Version", chip->cfg.CHIPID_CIDR, 0, 5); LOG_USER_N("\n"); v = sam3_reg_fieldname(chip, "EPROC", chip->cfg.CHIPID_CIDR, 5, 3); LOG_USER("%s", eproc_names[v]); v = sam3_reg_fieldname(chip, "NVPSIZE", chip->cfg.CHIPID_CIDR, 8, 4); LOG_USER("%s", nvpsize[v]); v = sam3_reg_fieldname(chip, "NVPSIZE2", chip->cfg.CHIPID_CIDR, 12, 4); LOG_USER("%s", nvpsize2[v]); v = sam3_reg_fieldname(chip, "SRAMSIZE", chip->cfg.CHIPID_CIDR, 16, 4); LOG_USER("%s", sramsize[v]); v = sam3_reg_fieldname(chip, "ARCH", chip->cfg.CHIPID_CIDR, 20, 8); cp = _unknown; for (x = 0; archnames[x].name; x++) { if (v == archnames[x].value) { cp = archnames[x].name; break; } } LOG_USER("%s", cp); v = sam3_reg_fieldname(chip, "NVPTYP", chip->cfg.CHIPID_CIDR, 28, 3); LOG_USER("%s", nvptype[v]); v = sam3_reg_fieldname(chip, "EXTID", chip->cfg.CHIPID_CIDR, 31, 1); LOG_USER("(exists: %s)", _yes_or_no(v)); } static void sam3_explain_ckgr_mcfr(struct sam3_chip *chip) { uint32_t v; v = sam3_reg_fieldname(chip, "MAINFRDY", chip->cfg.CKGR_MCFR, 16, 1); LOG_USER("(main ready: %s)", _yes_or_no(v)); v = sam3_reg_fieldname(chip, "MAINF", chip->cfg.CKGR_MCFR, 0, 16); v = (v * chip->cfg.slow_freq) / 16; chip->cfg.mainosc_freq = v; LOG_USER("(%3.03f Mhz (%" PRIu32 ".%03" PRIu32 "khz slowclk)", _tomhz(v), (uint32_t)(chip->cfg.slow_freq / 1000), (uint32_t)(chip->cfg.slow_freq % 1000)); } static void sam3_explain_ckgr_plla(struct sam3_chip *chip) { uint32_t mula, diva; diva = sam3_reg_fieldname(chip, "DIVA", chip->cfg.CKGR_PLLAR, 0, 8); LOG_USER_N("\n"); mula = sam3_reg_fieldname(chip, "MULA", chip->cfg.CKGR_PLLAR, 16, 11); LOG_USER_N("\n"); chip->cfg.plla_freq = 0; if (mula == 0) LOG_USER("\tPLLA Freq: (Disabled,mula = 0)"); else if (diva == 0) LOG_USER("\tPLLA Freq: (Disabled,diva = 0)"); else if (diva >= 1) { chip->cfg.plla_freq = (chip->cfg.mainosc_freq * (mula + 1) / diva); LOG_USER("\tPLLA Freq: %3.03f MHz", _tomhz(chip->cfg.plla_freq)); } } static void sam3_explain_mckr(struct sam3_chip *chip) { uint32_t css, pres, fin = 0; int pdiv = 0; const char *cp = NULL; css = sam3_reg_fieldname(chip, "CSS", chip->cfg.PMC_MCKR, 0, 2); switch (css & 3) { case 0: fin = chip->cfg.slow_freq; cp = "slowclk"; break; case 1: fin = chip->cfg.mainosc_freq; cp = "mainosc"; break; case 2: fin = chip->cfg.plla_freq; cp = "plla"; break; case 3: if (chip->cfg.CKGR_UCKR & (1 << 16)) { fin = 480 * 1000 * 1000; cp = "upll"; } else { fin = 0; cp = "upll (*ERROR* UPLL is disabled)"; } break; default: assert(0); break; } LOG_USER("%s (%3.03f Mhz)", cp, _tomhz(fin)); pres = sam3_reg_fieldname(chip, "PRES", chip->cfg.PMC_MCKR, 4, 3); switch (pres & 0x07) { case 0: pdiv = 1; cp = "selected clock"; break; case 1: pdiv = 2; cp = "clock/2"; break; case 2: pdiv = 4; cp = "clock/4"; break; case 3: pdiv = 8; cp = "clock/8"; break; case 4: pdiv = 16; cp = "clock/16"; break; case 5: pdiv = 32; cp = "clock/32"; break; case 6: pdiv = 64; cp = "clock/64"; break; case 7: pdiv = 6; cp = "clock/6"; break; default: assert(0); break; } LOG_USER("(%s)", cp); fin = fin / pdiv; /* sam3 has a *SINGLE* clock - */ /* other at91 series parts have divisors for these. */ chip->cfg.cpu_freq = fin; chip->cfg.mclk_freq = fin; chip->cfg.fclk_freq = fin; LOG_USER("\t\tResult CPU Freq: %3.03f", _tomhz(fin)); } #if 0 static struct sam3_chip *target2sam3(struct target *target) { struct sam3_chip *chip; if (!target) return NULL; chip = all_sam3_chips; while (chip) { if (chip->target == target) break; /* return below */ else chip = chip->next; } return chip; } #endif static uint32_t *sam3_get_reg_ptr(struct sam3_cfg *cfg, const struct sam3_reg_list *list) { /* this function exists to help */ /* keep funky offsetof() errors */ /* and casting from causing bugs */ /* By using prototypes - we can detect what would */ /* be casting errors. */ return (uint32_t *)(void *)(((char *)(cfg)) + list->struct_offset); } #define SAM3_ENTRY(NAME, FUNC) { .address = SAM3_ ## NAME, .struct_offset = offsetof( \ struct sam3_cfg, \ NAME), # NAME, FUNC } static const struct sam3_reg_list sam3_all_regs[] = { SAM3_ENTRY(CKGR_MOR, sam3_explain_ckgr_mor), SAM3_ENTRY(CKGR_MCFR, sam3_explain_ckgr_mcfr), SAM3_ENTRY(CKGR_PLLAR, sam3_explain_ckgr_plla), SAM3_ENTRY(CKGR_UCKR, NULL), SAM3_ENTRY(PMC_FSMR, NULL), SAM3_ENTRY(PMC_FSPR, NULL), SAM3_ENTRY(PMC_IMR, NULL), SAM3_ENTRY(PMC_MCKR, sam3_explain_mckr), SAM3_ENTRY(PMC_PCK0, NULL), SAM3_ENTRY(PMC_PCK1, NULL), SAM3_ENTRY(PMC_PCK2, NULL), SAM3_ENTRY(PMC_PCSR, NULL), SAM3_ENTRY(PMC_SCSR, NULL), SAM3_ENTRY(PMC_SR, NULL), SAM3_ENTRY(CHIPID_CIDR, sam3_explain_chipid_cidr), SAM3_ENTRY(CHIPID_CIDR2, sam3_explain_chipid_cidr), SAM3_ENTRY(CHIPID_EXID, NULL), SAM3_ENTRY(CHIPID_EXID2, NULL), /* TERMINATE THE LIST */ { .name = NULL } }; #undef SAM3_ENTRY static struct sam3_bank_private *get_sam3_bank_private(struct flash_bank *bank) { return bank->driver_priv; } /** * Given a pointer to where it goes in the structure, * determine the register name, address from the all registers table. */ static const struct sam3_reg_list *sam3_get_reg(struct sam3_chip *chip, uint32_t *goes_here) { const struct sam3_reg_list *reg; reg = &(sam3_all_regs[0]); while (reg->name) { uint32_t *possible; /* calculate where this one go.. */ /* it is "possibly" this register. */ possible = ((uint32_t *)(void *)(((char *)(&(chip->cfg))) + reg->struct_offset)); /* well? Is it this register */ if (possible == goes_here) { /* Jump for joy! */ return reg; } /* next... */ reg++; } /* This is *TOTAL*PANIC* - we are totally screwed. */ LOG_ERROR("INVALID SAM3 REGISTER"); return NULL; } static int sam3_read_this_reg(struct sam3_chip *chip, uint32_t *goes_here) { const struct sam3_reg_list *reg; int r; reg = sam3_get_reg(chip, goes_here); if (!reg) return ERROR_FAIL; r = target_read_u32(chip->target, reg->address, goes_here); if (r != ERROR_OK) { LOG_ERROR("Cannot read SAM3 register: %s @ 0x%08x, Err: %d", reg->name, (unsigned)(reg->address), r); } return r; } static int sam3_read_all_regs(struct sam3_chip *chip) { int r; const struct sam3_reg_list *reg; reg = &(sam3_all_regs[0]); while (reg->name) { r = sam3_read_this_reg(chip, sam3_get_reg_ptr(&(chip->cfg), reg)); if (r != ERROR_OK) { LOG_ERROR("Cannot read SAM3 register: %s @ 0x%08x, Error: %d", reg->name, ((unsigned)(reg->address)), r); return r; } reg++; } /* Chip identification register * * Unfortunately, the chip identification register is not at * a constant address across all of the SAM3 series'. As a * consequence, a simple heuristic is used to find where it's * at... * * If the contents at the first address is zero, then we know * that the second address is where the chip id register is. * We can deduce this because for those SAM's that have the * chip id @ 0x400e0940, the first address, 0x400e0740, is * located in the memory map of the Power Management Controller * (PMC). Furthermore, the address is not used by the PMC. * So when read, the memory controller returns zero.*/ if (chip->cfg.CHIPID_CIDR == 0) { /*Put the correct CIDR and EXID values in the chip structure */ chip->cfg.CHIPID_CIDR = chip->cfg.CHIPID_CIDR2; chip->cfg.CHIPID_EXID = chip->cfg.CHIPID_EXID2; } return ERROR_OK; } static int sam3_get_info(struct sam3_chip *chip) { const struct sam3_reg_list *reg; uint32_t regval; reg = &(sam3_all_regs[0]); while (reg->name) { /* display all regs */ LOG_DEBUG("Start: %s", reg->name); regval = *sam3_get_reg_ptr(&(chip->cfg), reg); LOG_USER("%*s: [0x%08" PRIx32 "] -> 0x%08" PRIx32, REG_NAME_WIDTH, reg->name, reg->address, regval); if (reg->explain_func) (*(reg->explain_func))(chip); LOG_DEBUG("End: %s", reg->name); reg++; } LOG_USER(" rc-osc: %3.03f MHz", _tomhz(chip->cfg.rc_freq)); LOG_USER(" mainosc: %3.03f MHz", _tomhz(chip->cfg.mainosc_freq)); LOG_USER(" plla: %3.03f MHz", _tomhz(chip->cfg.plla_freq)); LOG_USER(" cpu-freq: %3.03f MHz", _tomhz(chip->cfg.cpu_freq)); LOG_USER("mclk-freq: %3.03f MHz", _tomhz(chip->cfg.mclk_freq)); LOG_USER(" UniqueId: 0x%08" PRIx32 " 0x%08" PRIx32 " 0x%08" PRIx32 " 0x%08" PRIx32, chip->cfg.unique_id[0], chip->cfg.unique_id[1], chip->cfg.unique_id[2], chip->cfg.unique_id[3]); return ERROR_OK; } static int sam3_protect_check(struct flash_bank *bank) { int r; uint32_t v = 0; unsigned x; struct sam3_bank_private *private; LOG_DEBUG("Begin"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } private = get_sam3_bank_private(bank); if (!private) { LOG_ERROR("no private for this bank?"); return ERROR_FAIL; } if (!(private->probed)) return ERROR_FLASH_BANK_NOT_PROBED; r = flashd_get_lock_bits(private, &v); if (r != ERROR_OK) { LOG_DEBUG("Failed: %d", r); return r; } for (x = 0; x < private->nsectors; x++) bank->sectors[x].is_protected = (!!(v & (1 << x))); LOG_DEBUG("Done"); return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command) { struct sam3_chip *chip; chip = all_sam3_chips; /* is this an existing chip? */ while (chip) { if (chip->target == bank->target) break; chip = chip->next; } if (!chip) { /* this is a *NEW* chip */ chip = calloc(1, sizeof(struct sam3_chip)); if (!chip) { LOG_ERROR("NO RAM!"); return ERROR_FAIL; } chip->target = bank->target; /* insert at head */ chip->next = all_sam3_chips; all_sam3_chips = chip; chip->target = bank->target; /* assumption is this runs at 32khz */ chip->cfg.slow_freq = 32768; chip->probed = false; } switch (bank->base) { default: LOG_ERROR("Address 0x%08x invalid bank address (try 0x%08x or 0x%08x " "[at91sam3u series] or 0x%08x [at91sam3s series] or " "0x%08x [at91sam3n series] or 0x%08x or 0x%08x or 0x%08x[at91sam3ax series] )", ((unsigned int)(bank->base)), ((unsigned int)(FLASH_BANK0_BASE_U)), ((unsigned int)(FLASH_BANK1_BASE_U)), ((unsigned int)(FLASH_BANK_BASE_S)), ((unsigned int)(FLASH_BANK_BASE_N)), ((unsigned int)(FLASH_BANK0_BASE_AX)), ((unsigned int)(FLASH_BANK1_BASE_256K_AX)), ((unsigned int)(FLASH_BANK1_BASE_512K_AX))); return ERROR_FAIL; /* at91sam3s and at91sam3n series only has bank 0*/ /* at91sam3u and at91sam3ax series has the same address for bank 0*/ case FLASH_BANK_BASE_S: case FLASH_BANK0_BASE_U: bank->driver_priv = &(chip->details.bank[0]); bank->bank_number = 0; chip->details.bank[0].chip = chip; chip->details.bank[0].bank = bank; break; /* Bank 1 of at91sam3u or at91sam3ax series */ case FLASH_BANK1_BASE_U: case FLASH_BANK1_BASE_256K_AX: case FLASH_BANK1_BASE_512K_AX: bank->driver_priv = &(chip->details.bank[1]); bank->bank_number = 1; chip->details.bank[1].chip = chip; chip->details.bank[1].bank = bank; break; } /* we initialize after probing. */ return ERROR_OK; } /** * Remove all chips from the internal list without distinguishing which one * is owned by this bank. This simplification works only for one shot * deallocation like current flash_free_all_banks() */ static void sam3_free_driver_priv(struct flash_bank *bank) { struct sam3_chip *chip = all_sam3_chips; while (chip) { struct sam3_chip *next = chip->next; free(chip); chip = next; } all_sam3_chips = NULL; } static int sam3_get_details(struct sam3_bank_private *private) { const struct sam3_chip_details *details; struct sam3_chip *chip; struct flash_bank *saved_banks[SAM3_MAX_FLASH_BANKS]; unsigned x; LOG_DEBUG("Begin"); details = all_sam3_details; while (details->name) { /* Compare cidr without version bits */ if (((details->chipid_cidr ^ private->chip->cfg.CHIPID_CIDR) & 0xFFFFFFE0) == 0) break; else details++; } if (!details->name) { LOG_ERROR("SAM3 ChipID 0x%08x not found in table (perhaps you can ID this chip?)", (unsigned int)(private->chip->cfg.CHIPID_CIDR)); /* Help the victim, print details about the chip */ LOG_INFO("SAM3 CHIPID_CIDR: 0x%08" PRIx32 " decodes as follows", private->chip->cfg.CHIPID_CIDR); sam3_explain_chipid_cidr(private->chip); return ERROR_FAIL; } /* DANGER: THERE ARE DRAGONS HERE */ /* get our chip - it is going */ /* to be over-written shortly */ chip = private->chip; /* Note that, in reality: */ /* */ /* private = &(chip->details.bank[0]) */ /* or private = &(chip->details.bank[1]) */ /* */ /* save the "bank" pointers */ for (x = 0; x < SAM3_MAX_FLASH_BANKS; x++) saved_banks[x] = chip->details.bank[x].bank; /* Overwrite the "details" structure. */ memcpy(&(private->chip->details), details, sizeof(private->chip->details)); /* now fix the ghosted pointers */ for (x = 0; x < SAM3_MAX_FLASH_BANKS; x++) { chip->details.bank[x].chip = chip; chip->details.bank[x].bank = saved_banks[x]; } /* update the *BANK*SIZE* */ LOG_DEBUG("End"); return ERROR_OK; } static int _sam3_probe(struct flash_bank *bank, int noise) { int r; struct sam3_bank_private *private; LOG_DEBUG("Begin: Bank: %u, Noise: %d", bank->bank_number, noise); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } private = get_sam3_bank_private(bank); if (!private) { LOG_ERROR("Invalid/unknown bank number"); return ERROR_FAIL; } r = sam3_read_all_regs(private->chip); if (r != ERROR_OK) return r; LOG_DEBUG("Here"); if (private->chip->probed) r = sam3_get_info(private->chip); else r = sam3_get_details(private); if (r != ERROR_OK) return r; /* update the flash bank size */ for (unsigned int x = 0; x < SAM3_MAX_FLASH_BANKS; x++) { if (bank->base == private->chip->details.bank[x].base_address) { bank->size = private->chip->details.bank[x].size_bytes; break; } } if (!bank->sectors) { bank->sectors = calloc(private->nsectors, (sizeof((bank->sectors)[0]))); if (!bank->sectors) { LOG_ERROR("No memory!"); return ERROR_FAIL; } bank->num_sectors = private->nsectors; for (unsigned int x = 0; x < bank->num_sectors; x++) { bank->sectors[x].size = private->sector_size; bank->sectors[x].offset = x * (private->sector_size); /* mark as unknown */ bank->sectors[x].is_erased = -1; bank->sectors[x].is_protected = -1; } } private->probed = true; r = sam3_protect_check(bank); if (r != ERROR_OK) return r; LOG_DEBUG("Bank = %d, nbanks = %d", private->bank_number, private->chip->details.n_banks); if ((private->bank_number + 1) == private->chip->details.n_banks) { /* read unique id, */ /* it appears to be associated with the *last* flash bank. */ flashd_read_uid(private); } return r; } static int sam3_probe(struct flash_bank *bank) { return _sam3_probe(bank, 1); } static int sam3_auto_probe(struct flash_bank *bank) { return _sam3_probe(bank, 0); } static int sam3_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct sam3_bank_private *private; int r; LOG_DEBUG("Here"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } r = sam3_auto_probe(bank); if (r != ERROR_OK) { LOG_DEBUG("Here,r=%d", r); return r; } private = get_sam3_bank_private(bank); if (!(private->probed)) return ERROR_FLASH_BANK_NOT_PROBED; if ((first == 0) && ((last + 1) == private->nsectors)) { /* whole chip */ LOG_DEBUG("Here"); return flashd_erase_entire_bank(private); } LOG_INFO("sam3 auto-erases while programming (request ignored)"); return ERROR_OK; } static int sam3_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct sam3_bank_private *private; int r; LOG_DEBUG("Here"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } private = get_sam3_bank_private(bank); if (!(private->probed)) return ERROR_FLASH_BANK_NOT_PROBED; if (set) r = flashd_lock(private, first, last); else r = flashd_unlock(private, first, last); LOG_DEBUG("End: r=%d", r); return r; } static int sam3_page_read(struct sam3_bank_private *private, unsigned pagenum, uint8_t *buf) { uint32_t adr; int r; adr = pagenum * private->page_size; adr += private->base_address; r = target_read_memory(private->chip->target, adr, 4, /* THIS*MUST*BE* in 32bit values */ private->page_size / 4, buf); if (r != ERROR_OK) LOG_ERROR("SAM3: Flash program failed to read page phys address: 0x%08x", (unsigned int)(adr)); return r; } static int sam3_page_write(struct sam3_bank_private *private, unsigned pagenum, const uint8_t *buf) { uint32_t adr; uint32_t status; uint32_t fmr; /* EEFC Flash Mode Register */ int r; adr = pagenum * private->page_size; adr += private->base_address; /* Get flash mode register value */ r = target_read_u32(private->chip->target, private->controller_address, &fmr); if (r != ERROR_OK) LOG_DEBUG("Error Read failed: read flash mode register"); /* Clear flash wait state field */ fmr &= 0xfffff0ff; /* set FWS (flash wait states) field in the FMR (flash mode register) */ fmr |= (private->flash_wait_states << 8); LOG_DEBUG("Flash Mode: 0x%08x", ((unsigned int)(fmr))); r = target_write_u32(private->bank->target, private->controller_address, fmr); if (r != ERROR_OK) LOG_DEBUG("Error Write failed: set flash mode register"); LOG_DEBUG("Wr Page %u @ phys address: 0x%08x", pagenum, (unsigned int)(adr)); r = target_write_memory(private->chip->target, adr, 4, /* THIS*MUST*BE* in 32bit values */ private->page_size / 4, buf); if (r != ERROR_OK) { LOG_ERROR("SAM3: Failed to write (buffer) page at phys address 0x%08x", (unsigned int)(adr)); return r; } r = efc_perform_command(private, /* send Erase & Write Page */ AT91C_EFC_FCMD_EWP, pagenum, &status); if (r != ERROR_OK) LOG_ERROR("SAM3: Error performing Erase & Write page @ phys address 0x%08x", (unsigned int)(adr)); if (status & (1 << 2)) { LOG_ERROR("SAM3: Page @ Phys address 0x%08x is locked", (unsigned int)(adr)); return ERROR_FAIL; } if (status & (1 << 1)) { LOG_ERROR("SAM3: Flash Command error @phys address 0x%08x", (unsigned int)(adr)); return ERROR_FAIL; } return ERROR_OK; } static int sam3_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int n; unsigned page_cur; unsigned page_end; int r; unsigned page_offset; struct sam3_bank_private *private; uint8_t *pagebuffer; /* in case we bail further below, set this to null */ pagebuffer = NULL; /* ignore dumb requests */ if (count == 0) { r = ERROR_OK; goto done; } if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); r = ERROR_TARGET_NOT_HALTED; goto done; } private = get_sam3_bank_private(bank); if (!(private->probed)) { r = ERROR_FLASH_BANK_NOT_PROBED; goto done; } if ((offset + count) > private->size_bytes) { LOG_ERROR("Flash write error - past end of bank"); LOG_ERROR(" offset: 0x%08x, count 0x%08x, BankEnd: 0x%08x", (unsigned int)(offset), (unsigned int)(count), (unsigned int)(private->size_bytes)); r = ERROR_FAIL; goto done; } pagebuffer = malloc(private->page_size); if (!pagebuffer) { LOG_ERROR("No memory for %d Byte page buffer", (int)(private->page_size)); r = ERROR_FAIL; goto done; } /* what page do we start & end in? */ page_cur = offset / private->page_size; page_end = (offset + count - 1) / private->page_size; LOG_DEBUG("Offset: 0x%08x, Count: 0x%08x", (unsigned int)(offset), (unsigned int)(count)); LOG_DEBUG("Page start: %d, Page End: %d", (int)(page_cur), (int)(page_end)); /* Special case: all one page */ /* */ /* Otherwise: */ /* (1) non-aligned start */ /* (2) body pages */ /* (3) non-aligned end. */ /* Handle special case - all one page. */ if (page_cur == page_end) { LOG_DEBUG("Special case, all in one page"); r = sam3_page_read(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; page_offset = (offset & (private->page_size-1)); memcpy(pagebuffer + page_offset, buffer, count); r = sam3_page_write(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; r = ERROR_OK; goto done; } /* non-aligned start */ page_offset = offset & (private->page_size - 1); if (page_offset) { LOG_DEBUG("Not-Aligned start"); /* read the partial */ r = sam3_page_read(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; /* over-write with new data */ n = (private->page_size - page_offset); memcpy(pagebuffer + page_offset, buffer, n); r = sam3_page_write(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; count -= n; offset += n; buffer += n; page_cur++; } /* By checking that offset is correct here, we also fix a clang warning */ assert(offset % private->page_size == 0); /* intermediate large pages */ /* also - the final *terminal* */ /* if that terminal page is a full page */ LOG_DEBUG("Full Page Loop: cur=%d, end=%d, count = 0x%08x", (int)page_cur, (int)page_end, (unsigned int)(count)); while ((page_cur < page_end) && (count >= private->page_size)) { r = sam3_page_write(private, page_cur, buffer); if (r != ERROR_OK) goto done; count -= private->page_size; buffer += private->page_size; page_cur += 1; } /* terminal partial page? */ if (count) { LOG_DEBUG("Terminal partial page, count = 0x%08x", (unsigned int)(count)); /* we have a partial page */ r = sam3_page_read(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; /* data goes at start */ memcpy(pagebuffer, buffer, count); r = sam3_page_write(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; } LOG_DEBUG("Done!"); r = ERROR_OK; done: free(pagebuffer); return r; } COMMAND_HANDLER(sam3_handle_info_command) { struct sam3_chip *chip; chip = get_current_sam3(CMD); if (!chip) return ERROR_OK; unsigned x; int r; /* bank0 must exist before we can do anything */ if (!chip->details.bank[0].bank) { x = 0; need_define: command_print(CMD, "Please define bank %d via command: flash bank %s ... ", x, at91sam3_flash.name); return ERROR_FAIL; } /* if bank 0 is not probed, then probe it */ if (!(chip->details.bank[0].probed)) { r = sam3_auto_probe(chip->details.bank[0].bank); if (r != ERROR_OK) return ERROR_FAIL; } /* above guarantees the "chip details" structure is valid */ /* and thus, bank private areas are valid */ /* and we have a SAM3 chip, what a concept! */ /* auto-probe other banks, 0 done above */ for (x = 1; x < SAM3_MAX_FLASH_BANKS; x++) { /* skip banks not present */ if (!(chip->details.bank[x].present)) continue; if (!chip->details.bank[x].bank) goto need_define; if (chip->details.bank[x].probed) continue; r = sam3_auto_probe(chip->details.bank[x].bank); if (r != ERROR_OK) return r; } r = sam3_get_info(chip); if (r != ERROR_OK) { LOG_DEBUG("Sam3Info, Failed %d", r); return r; } return ERROR_OK; } COMMAND_HANDLER(sam3_handle_gpnvm_command) { unsigned x, v; int r, who; struct sam3_chip *chip; chip = get_current_sam3(CMD); if (!chip) return ERROR_OK; if (chip->target->state != TARGET_HALTED) { LOG_ERROR("sam3 - target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!chip->details.bank[0].bank) { command_print(CMD, "Bank0 must be defined first via: flash bank %s ...", at91sam3_flash.name); return ERROR_FAIL; } if (!chip->details.bank[0].probed) { r = sam3_auto_probe(chip->details.bank[0].bank); if (r != ERROR_OK) return r; } switch (CMD_ARGC) { default: return ERROR_COMMAND_SYNTAX_ERROR; case 0: goto showall; case 1: who = -1; break; case 2: if ((strcmp(CMD_ARGV[0], "show") == 0) && (strcmp(CMD_ARGV[1], "all") == 0)) who = -1; else { uint32_t v32; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); who = v32; } break; } if (strcmp("show", CMD_ARGV[0]) == 0) { if (who == -1) { showall: r = ERROR_OK; for (x = 0; x < chip->details.n_gpnvms; x++) { r = flashd_get_gpnvm(&(chip->details.bank[0]), x, &v); if (r != ERROR_OK) break; command_print(CMD, "sam3-gpnvm%u: %u", x, v); } return r; } if ((who >= 0) && (((unsigned)(who)) < chip->details.n_gpnvms)) { r = flashd_get_gpnvm(&(chip->details.bank[0]), who, &v); if (r == ERROR_OK) command_print(CMD, "sam3-gpnvm%u: %u", who, v); return r; } else { command_print(CMD, "sam3-gpnvm invalid GPNVM: %u", who); return ERROR_COMMAND_SYNTAX_ERROR; } } if (who == -1) { command_print(CMD, "Missing GPNVM number"); return ERROR_COMMAND_SYNTAX_ERROR; } if (strcmp("set", CMD_ARGV[0]) == 0) r = flashd_set_gpnvm(&(chip->details.bank[0]), who); else if ((strcmp("clr", CMD_ARGV[0]) == 0) || (strcmp("clear", CMD_ARGV[0]) == 0)) /* quietly accept both */ r = flashd_clr_gpnvm(&(chip->details.bank[0]), who); else { command_print(CMD, "Unknown command: %s", CMD_ARGV[0]); r = ERROR_COMMAND_SYNTAX_ERROR; } return r; } COMMAND_HANDLER(sam3_handle_slowclk_command) { struct sam3_chip *chip; chip = get_current_sam3(CMD); if (!chip) return ERROR_OK; switch (CMD_ARGC) { case 0: /* show */ break; case 1: { /* set */ uint32_t v; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v); if (v > 200000) { /* absurd slow clock of 200Khz? */ command_print(CMD, "Absurd/illegal slow clock freq: %d\n", (int)(v)); return ERROR_COMMAND_SYNTAX_ERROR; } chip->cfg.slow_freq = v; break; } default: /* error */ command_print(CMD, "Too many parameters"); return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "Slowclk freq: %d.%03dkhz", (int)(chip->cfg.slow_freq / 1000), (int)(chip->cfg.slow_freq % 1000)); return ERROR_OK; } static const struct command_registration at91sam3_exec_command_handlers[] = { { .name = "gpnvm", .handler = sam3_handle_gpnvm_command, .mode = COMMAND_EXEC, .usage = "[('clr'|'set'|'show') bitnum]", .help = "Without arguments, shows all bits in the gpnvm " "register. Otherwise, clears, sets, or shows one " "General Purpose Non-Volatile Memory (gpnvm) bit.", }, { .name = "info", .handler = sam3_handle_info_command, .mode = COMMAND_EXEC, .help = "Print information about the current at91sam3 chip " "and its flash configuration.", .usage = "", }, { .name = "slowclk", .handler = sam3_handle_slowclk_command, .mode = COMMAND_EXEC, .usage = "[clock_hz]", .help = "Display or set the slowclock frequency " "(default 32768 Hz).", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration at91sam3_command_handlers[] = { { .name = "at91sam3", .mode = COMMAND_ANY, .help = "at91sam3 flash command group", .usage = "", .chain = at91sam3_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver at91sam3_flash = { .name = "at91sam3", .commands = at91sam3_command_handlers, .flash_bank_command = sam3_flash_bank_command, .erase = sam3_erase, .protect = sam3_protect, .write = sam3_write, .read = default_flash_read, .probe = sam3_probe, .auto_probe = sam3_auto_probe, .erase_check = default_flash_blank_check, .protect_check = sam3_protect_check, .free_driver_priv = sam3_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/at91sam4.c ================================================ // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-Source-Code) /* * Copyright (C) 2009 by Duane Ellis <openocd@duaneellis.com> * * at91sam3s* support * Copyright (C) 2010 by Olaf Lüke <olaf@uni-paderborn.de> * * at91sam3x* & at91sam4 support * Copyright (C) 2011 by Olivier Schonken, Jim Norris * * Some of the lower level code was based on code supplied by * ATMEL under BSD-Source-Code License and this copyright. * ATMEL Microcontroller Software Support * Copyright (c) 2009, Atmel Corporation. All rights reserved. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/time_support.h> #define REG_NAME_WIDTH (12) /* at91sam4s/at91sam4e/at91sam4c series (has always one flash bank)*/ #define FLASH_BANK_BASE_S 0x00400000 #define FLASH_BANK_BASE_C 0x01000000 /* at91sam4sd series (two one flash banks), first bank address */ #define FLASH_BANK0_BASE_SD FLASH_BANK_BASE_S /* at91sam4sd16x, second bank address */ #define FLASH_BANK1_BASE_1024K_SD (FLASH_BANK0_BASE_SD+(1024*1024/2)) /* at91sam4sd32x, second bank address */ #define FLASH_BANK1_BASE_2048K_SD (FLASH_BANK0_BASE_SD+(2048*1024/2)) /* at91sam4c32x, first and second bank address */ #define FLASH_BANK0_BASE_C32 FLASH_BANK_BASE_C #define FLASH_BANK1_BASE_C32 (FLASH_BANK_BASE_C+(2048*1024/2)) #define AT91C_EFC_FCMD_GETD (0x0) /* (EFC) Get Flash Descriptor */ #define AT91C_EFC_FCMD_WP (0x1) /* (EFC) Write Page */ #define AT91C_EFC_FCMD_WPL (0x2) /* (EFC) Write Page and Lock */ #define AT91C_EFC_FCMD_EWP (0x3) /* (EFC) Erase Page and Write Page */ #define AT91C_EFC_FCMD_EWPL (0x4) /* (EFC) Erase Page and Write Page then Lock */ #define AT91C_EFC_FCMD_EA (0x5) /* (EFC) Erase All */ /* cmd6 is not present in the at91sam4u4/2/1 data sheet table 19-2 */ /* #define AT91C_EFC_FCMD_EPL (0x6) // (EFC) Erase plane? */ #define AT91C_EFC_FCMD_EPA (0x7) /* (EFC) Erase pages */ #define AT91C_EFC_FCMD_SLB (0x8) /* (EFC) Set Lock Bit */ #define AT91C_EFC_FCMD_CLB (0x9) /* (EFC) Clear Lock Bit */ #define AT91C_EFC_FCMD_GLB (0xA) /* (EFC) Get Lock Bit */ #define AT91C_EFC_FCMD_SFB (0xB) /* (EFC) Set Fuse Bit */ #define AT91C_EFC_FCMD_CFB (0xC) /* (EFC) Clear Fuse Bit */ #define AT91C_EFC_FCMD_GFB (0xD) /* (EFC) Get Fuse Bit */ #define AT91C_EFC_FCMD_STUI (0xE) /* (EFC) Start Read Unique ID */ #define AT91C_EFC_FCMD_SPUI (0xF) /* (EFC) Stop Read Unique ID */ #define OFFSET_EFC_FMR 0 #define OFFSET_EFC_FCR 4 #define OFFSET_EFC_FSR 8 #define OFFSET_EFC_FRR 12 static float _tomhz(uint32_t freq_hz) { float f; f = ((float)(freq_hz)) / 1000000.0; return f; } /* How the chip is configured. */ struct sam4_cfg { uint32_t unique_id[4]; uint32_t slow_freq; uint32_t rc_freq; uint32_t mainosc_freq; uint32_t plla_freq; uint32_t mclk_freq; uint32_t cpu_freq; uint32_t fclk_freq; uint32_t pclk0_freq; uint32_t pclk1_freq; uint32_t pclk2_freq; #define SAM4_CHIPID_CIDR (0x400E0740) uint32_t CHIPID_CIDR; #define SAM4_CHIPID_EXID (0x400E0744) uint32_t CHIPID_EXID; #define SAM4_PMC_BASE (0x400E0400) #define SAM4_PMC_SCSR (SAM4_PMC_BASE + 0x0008) uint32_t PMC_SCSR; #define SAM4_PMC_PCSR (SAM4_PMC_BASE + 0x0018) uint32_t PMC_PCSR; #define SAM4_CKGR_UCKR (SAM4_PMC_BASE + 0x001c) uint32_t CKGR_UCKR; #define SAM4_CKGR_MOR (SAM4_PMC_BASE + 0x0020) uint32_t CKGR_MOR; #define SAM4_CKGR_MCFR (SAM4_PMC_BASE + 0x0024) uint32_t CKGR_MCFR; #define SAM4_CKGR_PLLAR (SAM4_PMC_BASE + 0x0028) uint32_t CKGR_PLLAR; #define SAM4_PMC_MCKR (SAM4_PMC_BASE + 0x0030) uint32_t PMC_MCKR; #define SAM4_PMC_PCK0 (SAM4_PMC_BASE + 0x0040) uint32_t PMC_PCK0; #define SAM4_PMC_PCK1 (SAM4_PMC_BASE + 0x0044) uint32_t PMC_PCK1; #define SAM4_PMC_PCK2 (SAM4_PMC_BASE + 0x0048) uint32_t PMC_PCK2; #define SAM4_PMC_SR (SAM4_PMC_BASE + 0x0068) uint32_t PMC_SR; #define SAM4_PMC_IMR (SAM4_PMC_BASE + 0x006c) uint32_t PMC_IMR; #define SAM4_PMC_FSMR (SAM4_PMC_BASE + 0x0070) uint32_t PMC_FSMR; #define SAM4_PMC_FSPR (SAM4_PMC_BASE + 0x0074) uint32_t PMC_FSPR; }; struct sam4_bank_private { bool probed; /* DANGER: THERE ARE DRAGONS HERE.. */ /* NOTE: If you add more 'ghost' pointers */ /* be aware that you must *manually* update */ /* these pointers in the function sam4_get_details() */ /* See the comment "Here there be dragons" */ /* so we can find the chip we belong to */ struct sam4_chip *chip; /* so we can find the original bank pointer */ struct flash_bank *bank; unsigned bank_number; uint32_t controller_address; uint32_t base_address; uint32_t flash_wait_states; bool present; unsigned size_bytes; unsigned nsectors; unsigned sector_size; unsigned page_size; }; struct sam4_chip_details { /* THERE ARE DRAGONS HERE.. */ /* note: If you add pointers here */ /* be careful about them as they */ /* may need to be updated inside */ /* the function: "sam4_get_details() */ /* which copy/overwrites the */ /* 'runtime' copy of this structure */ uint32_t chipid_cidr; const char *name; unsigned n_gpnvms; #define SAM4_N_NVM_BITS 3 unsigned gpnvm[SAM4_N_NVM_BITS]; unsigned total_flash_size; unsigned total_sram_size; unsigned n_banks; #define SAM4_MAX_FLASH_BANKS 2 /* these are "initialized" from the global const data */ struct sam4_bank_private bank[SAM4_MAX_FLASH_BANKS]; }; struct sam4_chip { struct sam4_chip *next; bool probed; /* this is "initialized" from the global const structure */ struct sam4_chip_details details; struct target *target; struct sam4_cfg cfg; }; struct sam4_reg_list { uint32_t address; size_t struct_offset; const char *name; void (*explain_func)(struct sam4_chip *chip); }; static struct sam4_chip *all_sam4_chips; static struct sam4_chip *get_current_sam4(struct command_invocation *cmd) { struct target *t; static struct sam4_chip *p; t = get_current_target(cmd->ctx); if (!t) { command_print_sameline(cmd, "No current target?\n"); return NULL; } p = all_sam4_chips; if (!p) { /* this should not happen */ /* the command is not registered until the chip is created? */ command_print_sameline(cmd, "No SAM4 chips exist?\n"); return NULL; } while (p) { if (p->target == t) return p; p = p->next; } command_print_sameline(cmd, "Cannot find SAM4 chip?\n"); return NULL; } /*The actual sector size of the SAM4S flash memory is 65536 bytes. 16 sectors for a 1024KB device*/ /*The lockregions are 8KB per lock region, with a 1024KB device having 128 lock regions. */ /*For the best results, nsectors are thus set to the amount of lock regions, and the sector_size*/ /*set to the lock region size. Page erases are used to erase 8KB sections when programming*/ /* these are used to *initialize* the "chip->details" structure. */ static const struct sam4_chip_details all_sam4_details[] = { /* Start at91sam4c* series */ /* at91sam4c32e - LQFP144 */ { .chipid_cidr = 0xA66D0EE0, .name = "at91sam4c32e", .total_flash_size = 2024 * 1024, .total_sram_size = 256 * 1024, .n_gpnvms = 3, .n_banks = 2, /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_C32, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_C32, .controller_address = 0x400e0c00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, }, }, /* at91sam4c32c - LQFP100 */ { .chipid_cidr = 0xA64D0EE0, .name = "at91sam4c32c", .total_flash_size = 2024 * 1024, .total_sram_size = 256 * 1024, .n_gpnvms = 3, .n_banks = 2, /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_C32, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_C32, .controller_address = 0x400e0c00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, }, }, /* at91sam4c16c - LQFP100 */ { .chipid_cidr = 0xA64C0CE0, .name = "at91sam4c16c", .total_flash_size = 1024 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_C, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /* at91sam4c8c - LQFP100 */ { .chipid_cidr = 0xA64C0AE0, .name = "at91sam4c8c", .total_flash_size = 512 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_C, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /* at91sam4c4c (rev B) - LQFP100 */ { .chipid_cidr = 0xA64C0CE5, .name = "at91sam4c4c", .total_flash_size = 256 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_C, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 256 * 1024, .nsectors = 32, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /* Start at91sam4e* series */ /*atsam4e16e - LQFP144/LFBGA144*/ { .chipid_cidr = 0xA3CC0CE0, .name = "at91sam4e16e", .total_flash_size = 1024 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /* Start at91sam4n* series */ /*atsam4n8a - LQFP48/QFN48*/ { .chipid_cidr = 0x293B0AE0, .name = "at91sam4n8a", .total_flash_size = 512 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4n8b - LQFP64/QFN64*/ { .chipid_cidr = 0x294B0AE0, .name = "at91sam4n8b", .total_flash_size = 512 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4n8c - LQFP100/TFBGA100/VFBGA100*/ { .chipid_cidr = 0x295B0AE0, .name = "at91sam4n8c", .total_flash_size = 512 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4n16b - LQFP64/QFN64*/ { .chipid_cidr = 0x29460CE0, .name = "at91sam4n16b", .total_flash_size = 1024 * 1024, .total_sram_size = 80 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4n16c - LQFP100/TFBGA100/VFBGA100*/ { .chipid_cidr = 0x29560CE0, .name = "at91sam4n16c", .total_flash_size = 1024 * 1024, .total_sram_size = 80 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /* Start at91sam4s* series */ /*atsam4s16c - LQFP100/BGA100*/ { .chipid_cidr = 0x28AC0CE0, .name = "at91sam4s16c", .total_flash_size = 1024 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*at91sam4sa16c - TFBGA100/VFBGA100/LQFP100*/ { .chipid_cidr = 0x28a70ce0, .name = "at91sam4sa16c", .total_flash_size = 1024 * 1024, .total_sram_size = 160 * 1024, .n_gpnvms = 2, .n_banks = 1, /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4s16b - LQFP64/QFN64/WLCSP64*/ { .chipid_cidr = 0x289C0CE0, .name = "at91sam4s16b", .total_flash_size = 1024 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4sa16b - LQFP64/QFN64*/ { .chipid_cidr = 0x28970CE0, .name = "at91sam4sa16b", .total_flash_size = 1024 * 1024, .total_sram_size = 160 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4s16a - LQFP48/QFN48*/ { .chipid_cidr = 0x288C0CE0, .name = "at91sam4s16a", .total_flash_size = 1024 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4s8c - LQFP100/BGA100*/ { .chipid_cidr = 0x28AC0AE0, .name = "at91sam4s8c", .total_flash_size = 512 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4s8b - LQFP64/QFN64/WLCSP64*/ { .chipid_cidr = 0x289C0AE0, .name = "at91sam4s8b", .total_flash_size = 512 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4s8a - LQFP48/BGA48*/ { .chipid_cidr = 0x288C0AE0, .name = "at91sam4s8a", .total_flash_size = 512 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4s4c - LQFP100/BGA100*/ { .chipid_cidr = 0x28ab09e0, .name = "at91sam4s4c", .total_flash_size = 256 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 256 * 1024, .nsectors = 32, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4s4b - LQFP64/QFN64/WLCSP64*/ { .chipid_cidr = 0x289b09e0, .name = "at91sam4s4b", .total_flash_size = 256 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 256 * 1024, .nsectors = 32, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4s4a - LQFP48/QFN48*/ { .chipid_cidr = 0x288b09e0, .name = "at91sam4s4a", .total_flash_size = 256 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 256 * 1024, .nsectors = 32, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4s2c - LQFP100/BGA100*/ { .chipid_cidr = 0x28ab07e0, .name = "at91sam4s2c", .total_flash_size = 128 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4s2b - LQPF64/QFN64/WLCSP64*/ { .chipid_cidr = 0x289b07e0, .name = "at91sam4s2b", .total_flash_size = 128 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*atsam4s2a - LQFP48/QFN48*/ { .chipid_cidr = 0x288b07e0, .name = "at91sam4s2a", .total_flash_size = 128 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, }, }, /*at91sam4sd32c - LQFP100/BGA100*/ { .chipid_cidr = 0x29a70ee0, .name = "at91sam4sd32c", .total_flash_size = 2048 * 1024, .total_sram_size = 160 * 1024, .n_gpnvms = 3, .n_banks = 2, /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_2048K_SD, .controller_address = 0x400e0c00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, }, }, /*at91sam4sd32b - LQFP64/BGA64*/ { .chipid_cidr = 0x29970ee0, .name = "at91sam4sd32b", .total_flash_size = 2048 * 1024, .total_sram_size = 160 * 1024, .n_gpnvms = 3, .n_banks = 2, /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_2048K_SD, .controller_address = 0x400e0c00, .flash_wait_states = 5, .present = true, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, }, }, /*at91sam4sd16c - LQFP100/BGA100*/ { .chipid_cidr = 0x29a70ce0, .name = "at91sam4sd16c", .total_flash_size = 1024 * 1024, .total_sram_size = 160 * 1024, .n_gpnvms = 3, .n_banks = 2, /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_1024K_SD, .controller_address = 0x400e0c00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, }, }, /*at91sam4sd16b - LQFP64/BGA64*/ { .chipid_cidr = 0x29970ce0, .name = "at91sam4sd16b", .total_flash_size = 1024 * 1024, .total_sram_size = 160 * 1024, .n_gpnvms = 3, .n_banks = 2, /* .bank[0] = { */ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = { */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_1024K_SD, .controller_address = 0x400e0c00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, }, }, /* atsamg53n19 */ { .chipid_cidr = 0x247e0ae0, .name = "atsamg53n19", .total_flash_size = 512 * 1024, .total_sram_size = 96 * 1024, .n_gpnvms = 2, .n_banks = 1, /* .bank[0] = {*/ { { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = false, .probed = false, .bank_number = 1, }, } }, /* atsamg55g19 Rev.A */ { .chipid_cidr = 0x24470ae0, .name = "atsamg55g19", .total_flash_size = 512 * 1024, .total_sram_size = 160 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = */ { .present = false, .probed = false, .bank_number = 1, }, } }, /* atsamg55g19 Rev.B */ { .chipid_cidr = 0x24470ae1, .name = "atsamg55g19b", .total_flash_size = 512 * 1024, .total_sram_size = 160 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = */ { .present = false, .probed = false, .bank_number = 1, }, } }, /* atsamg55j19 Rev.A */ { .chipid_cidr = 0x24570ae0, .name = "atsamg55j19", .total_flash_size = 512 * 1024, .total_sram_size = 160 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = */ { .present = false, .probed = false, .bank_number = 1, }, } }, /* atsamg55j19 Rev.B */ { .chipid_cidr = 0x24570ae1, .name = "atsamg55j19b", .total_flash_size = 512 * 1024, .total_sram_size = 160 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = */ { .probed = false, .chip = NULL, .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 5, .present = true, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = */ { .present = false, .probed = false, .bank_number = 1, }, } }, /* terminate */ { .chipid_cidr = 0, .name = NULL, } }; /* Globals above */ /*********************************************************************** ********************************************************************** ********************************************************************** ********************************************************************** ********************************************************************** **********************************************************************/ /* *ATMEL* style code - from the SAM4 driver code */ /** * Get the current status of the EEFC and * the value of some status bits (LOCKE, PROGE). * @param private - info about the bank * @param v - result goes here */ static int efc_get_status(struct sam4_bank_private *private, uint32_t *v) { int r; r = target_read_u32(private->chip->target, private->controller_address + OFFSET_EFC_FSR, v); LOG_DEBUG("Status: 0x%08x (lockerror: %d, cmderror: %d, ready: %d)", (unsigned int)(*v), ((unsigned int)((*v >> 2) & 1)), ((unsigned int)((*v >> 1) & 1)), ((unsigned int)((*v >> 0) & 1))); return r; } /** * Get the result of the last executed command. * @param private - info about the bank * @param v - result goes here */ static int efc_get_result(struct sam4_bank_private *private, uint32_t *v) { int r; uint32_t rv; r = target_read_u32(private->chip->target, private->controller_address + OFFSET_EFC_FRR, &rv); if (v) *v = rv; LOG_DEBUG("Result: 0x%08x", ((unsigned int)(rv))); return r; } static int efc_start_command(struct sam4_bank_private *private, unsigned command, unsigned argument) { uint32_t n, v; int r; int retry; retry = 0; do_retry: /* Check command & argument */ switch (command) { case AT91C_EFC_FCMD_WP: case AT91C_EFC_FCMD_WPL: case AT91C_EFC_FCMD_EWP: case AT91C_EFC_FCMD_EWPL: /* case AT91C_EFC_FCMD_EPL: */ case AT91C_EFC_FCMD_EPA: case AT91C_EFC_FCMD_SLB: case AT91C_EFC_FCMD_CLB: n = (private->size_bytes / private->page_size); if (argument >= n) LOG_ERROR("*BUG*: Embedded flash has only %u pages", (unsigned)(n)); break; case AT91C_EFC_FCMD_SFB: case AT91C_EFC_FCMD_CFB: if (argument >= private->chip->details.n_gpnvms) { LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs", private->chip->details.n_gpnvms); } break; case AT91C_EFC_FCMD_GETD: case AT91C_EFC_FCMD_EA: case AT91C_EFC_FCMD_GLB: case AT91C_EFC_FCMD_GFB: case AT91C_EFC_FCMD_STUI: case AT91C_EFC_FCMD_SPUI: if (argument != 0) LOG_ERROR("Argument is meaningless for cmd: %d", command); break; default: LOG_ERROR("Unknown command %d", command); break; } if (command == AT91C_EFC_FCMD_SPUI) { /* this is a very special situation. */ /* Situation (1) - error/retry - see below */ /* And we are being called recursively */ /* Situation (2) - normal, finished reading unique id */ } else { /* it should be "ready" */ efc_get_status(private, &v); if (v & 1) { /* then it is ready */ /* we go on */ } else { if (retry) { /* we have done this before */ /* the controller is not responding. */ LOG_ERROR("flash controller(%d) is not ready! Error", private->bank_number); return ERROR_FAIL; } else { retry++; LOG_ERROR("Flash controller(%d) is not ready, attempting reset", private->bank_number); /* we do that by issuing the *STOP* command */ efc_start_command(private, AT91C_EFC_FCMD_SPUI, 0); /* above is recursive, and further recursion is blocked by */ /* if (command == AT91C_EFC_FCMD_SPUI) above */ goto do_retry; } } } v = (0x5A << 24) | (argument << 8) | command; LOG_DEBUG("Command: 0x%08x", ((unsigned int)(v))); r = target_write_u32(private->bank->target, private->controller_address + OFFSET_EFC_FCR, v); if (r != ERROR_OK) LOG_DEBUG("Error Write failed"); return r; } /** * Performs the given command and wait until its completion (or an error). * @param private - info about the bank * @param command - Command to perform. * @param argument - Optional command argument. * @param status - put command status bits here */ static int efc_perform_command(struct sam4_bank_private *private, unsigned command, unsigned argument, uint32_t *status) { int r; uint32_t v; int64_t ms_now, ms_end; /* default */ if (status) *status = 0; r = efc_start_command(private, command, argument); if (r != ERROR_OK) return r; ms_end = 10000 + timeval_ms(); do { r = efc_get_status(private, &v); if (r != ERROR_OK) return r; ms_now = timeval_ms(); if (ms_now > ms_end) { /* error */ LOG_ERROR("Command timeout"); return ERROR_FAIL; } } while ((v & 1) == 0); /* error bits.. */ if (status) *status = (v & 0x6); return ERROR_OK; } /** * Read the unique ID. * @param private - info about the bank * The unique ID is stored in the 'private' structure. */ static int flashd_read_uid(struct sam4_bank_private *private) { int r; uint32_t v; int x; /* assume 0 */ private->chip->cfg.unique_id[0] = 0; private->chip->cfg.unique_id[1] = 0; private->chip->cfg.unique_id[2] = 0; private->chip->cfg.unique_id[3] = 0; LOG_DEBUG("Begin"); r = efc_start_command(private, AT91C_EFC_FCMD_STUI, 0); if (r < 0) return r; for (x = 0; x < 4; x++) { r = target_read_u32(private->chip->target, private->bank->base + (x * 4), &v); if (r < 0) return r; private->chip->cfg.unique_id[x] = v; } r = efc_perform_command(private, AT91C_EFC_FCMD_SPUI, 0, NULL); LOG_DEBUG("End: R=%d, id = 0x%08x, 0x%08x, 0x%08x, 0x%08x", r, (unsigned int)(private->chip->cfg.unique_id[0]), (unsigned int)(private->chip->cfg.unique_id[1]), (unsigned int)(private->chip->cfg.unique_id[2]), (unsigned int)(private->chip->cfg.unique_id[3])); return r; } /** * Erases the entire flash. * @param private - the info about the bank. */ static int flashd_erase_entire_bank(struct sam4_bank_private *private) { LOG_DEBUG("Here"); return efc_perform_command(private, AT91C_EFC_FCMD_EA, 0, NULL); } /** * Erases the entire flash. * @param private - the info about the bank. * @param first_page * @param num_pages * @param status */ static int flashd_erase_pages(struct sam4_bank_private *private, int first_page, int num_pages, uint32_t *status) { LOG_DEBUG("Here"); uint8_t erase_pages; switch (num_pages) { case 4: erase_pages = 0x00; break; case 8: erase_pages = 0x01; break; case 16: erase_pages = 0x02; break; case 32: erase_pages = 0x03; break; default: erase_pages = 0x00; break; } /* AT91C_EFC_FCMD_EPA * According to the datasheet FARG[15:2] defines the page from which * the erase will start.This page must be modulo 4, 8, 16 or 32 * according to the number of pages to erase. FARG[1:0] defines the * number of pages to be erased. Previously (firstpage << 2) was used * to conform to this, seems it should not be shifted... */ return efc_perform_command(private, /* send Erase Page */ AT91C_EFC_FCMD_EPA, (first_page) | erase_pages, status); } /** * Gets current GPNVM state. * @param private - info about the bank. * @param gpnvm - GPNVM bit index. * @param puthere - result stored here. */ /* ------------------------------------------------------------------------------ */ static int flashd_get_gpnvm(struct sam4_bank_private *private, unsigned gpnvm, unsigned *puthere) { uint32_t v; int r; LOG_DEBUG("Here"); if (private->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } if (gpnvm >= private->chip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", gpnvm, private->chip->details.n_gpnvms); return ERROR_FAIL; } /* Get GPNVMs status */ r = efc_perform_command(private, AT91C_EFC_FCMD_GFB, 0, NULL); if (r != ERROR_OK) { LOG_ERROR("Failed"); return r; } r = efc_get_result(private, &v); if (puthere) { /* Check if GPNVM is set */ /* get the bit and make it a 0/1 */ *puthere = (v >> gpnvm) & 1; } return r; } /** * Clears the selected GPNVM bit. * @param private info about the bank * @param gpnvm GPNVM index. * @returns 0 if successful; otherwise returns an error code. */ static int flashd_clr_gpnvm(struct sam4_bank_private *private, unsigned gpnvm) { int r; unsigned v; LOG_DEBUG("Here"); if (private->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } if (gpnvm >= private->chip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", gpnvm, private->chip->details.n_gpnvms); return ERROR_FAIL; } r = flashd_get_gpnvm(private, gpnvm, &v); if (r != ERROR_OK) { LOG_DEBUG("Failed: %d", r); return r; } r = efc_perform_command(private, AT91C_EFC_FCMD_CFB, gpnvm, NULL); LOG_DEBUG("End: %d", r); return r; } /** * Sets the selected GPNVM bit. * @param private info about the bank * @param gpnvm GPNVM index. */ static int flashd_set_gpnvm(struct sam4_bank_private *private, unsigned gpnvm) { int r; unsigned v; if (private->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } if (gpnvm >= private->chip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", gpnvm, private->chip->details.n_gpnvms); return ERROR_FAIL; } r = flashd_get_gpnvm(private, gpnvm, &v); if (r != ERROR_OK) return r; if (v) { /* already set */ r = ERROR_OK; } else { /* set it */ r = efc_perform_command(private, AT91C_EFC_FCMD_SFB, gpnvm, NULL); } return r; } /** * Returns a bit field (at most 64) of locked regions within a page. * @param private info about the bank * @param v where to store locked bits */ static int flashd_get_lock_bits(struct sam4_bank_private *private, uint32_t *v) { int r; LOG_DEBUG("Here"); r = efc_perform_command(private, AT91C_EFC_FCMD_GLB, 0, NULL); if (r == ERROR_OK) { efc_get_result(private, v); efc_get_result(private, v); efc_get_result(private, v); r = efc_get_result(private, v); } LOG_DEBUG("End: %d", r); return r; } /** * Unlocks all the regions in the given address range. * @param private info about the bank * @param start_sector first sector to unlock * @param end_sector last (inclusive) to unlock */ static int flashd_unlock(struct sam4_bank_private *private, unsigned start_sector, unsigned end_sector) { int r; uint32_t status; uint32_t pg; uint32_t pages_per_sector; pages_per_sector = private->sector_size / private->page_size; /* Unlock all pages */ while (start_sector <= end_sector) { pg = start_sector * pages_per_sector; r = efc_perform_command(private, AT91C_EFC_FCMD_CLB, pg, &status); if (r != ERROR_OK) return r; start_sector++; } return ERROR_OK; } /** * Locks regions * @param private - info about the bank * @param start_sector - first sector to lock * @param end_sector - last sector (inclusive) to lock */ static int flashd_lock(struct sam4_bank_private *private, unsigned start_sector, unsigned end_sector) { uint32_t status; uint32_t pg; uint32_t pages_per_sector; int r; pages_per_sector = private->sector_size / private->page_size; /* Lock all pages */ while (start_sector <= end_sector) { pg = start_sector * pages_per_sector; r = efc_perform_command(private, AT91C_EFC_FCMD_SLB, pg, &status); if (r != ERROR_OK) return r; start_sector++; } return ERROR_OK; } /****** END SAM4 CODE ********/ /* begin helpful debug code */ /* print the fieldname, the field value, in dec & hex, and return field value */ static uint32_t sam4_reg_fieldname(struct sam4_chip *chip, const char *regname, uint32_t value, unsigned shift, unsigned width) { uint32_t v; int hwidth, dwidth; /* extract the field */ v = value >> shift; v = v & ((1 << width)-1); if (width <= 16) { hwidth = 4; dwidth = 5; } else { hwidth = 8; dwidth = 12; } /* show the basics */ LOG_USER_N("\t%*s: %*" PRIu32 " [0x%0*" PRIx32 "] ", REG_NAME_WIDTH, regname, dwidth, v, hwidth, v); return v; } static const char _unknown[] = "unknown"; static const char *const eproc_names[] = { "Cortex-M7", /* 0 */ "arm946es", /* 1 */ "arm7tdmi", /* 2 */ "Cortex-M3", /* 3 */ "arm920t", /* 4 */ "arm926ejs", /* 5 */ "Cortex-A5", /* 6 */ "Cortex-M4", /* 7 */ _unknown, /* 8 */ _unknown, /* 9 */ _unknown, /* 10 */ _unknown, /* 11 */ _unknown, /* 12 */ _unknown, /* 13 */ _unknown, /* 14 */ _unknown, /* 15 */ }; #define nvpsize2 nvpsize /* these two tables are identical */ static const char *const nvpsize[] = { "none", /* 0 */ "8K bytes", /* 1 */ "16K bytes", /* 2 */ "32K bytes", /* 3 */ _unknown, /* 4 */ "64K bytes", /* 5 */ _unknown, /* 6 */ "128K bytes", /* 7 */ "160K bytes", /* 8 */ "256K bytes", /* 9 */ "512K bytes", /* 10 */ _unknown, /* 11 */ "1024K bytes", /* 12 */ _unknown, /* 13 */ "2048K bytes", /* 14 */ _unknown, /* 15 */ }; static const char *const sramsize[] = { "48K Bytes", /* 0 */ "1K Bytes", /* 1 */ "2K Bytes", /* 2 */ "6K Bytes", /* 3 */ "112K Bytes", /* 4 */ "4K Bytes", /* 5 */ "80K Bytes", /* 6 */ "160K Bytes", /* 7 */ "8K Bytes", /* 8 */ "16K Bytes", /* 9 */ "32K Bytes", /* 10 */ "64K Bytes", /* 11 */ "128K Bytes", /* 12 */ "256K Bytes", /* 13 */ "96K Bytes", /* 14 */ "512K Bytes", /* 15 */ }; static const struct archnames { unsigned value; const char *name; } archnames[] = { { 0x19, "AT91SAM9xx Series" }, { 0x29, "AT91SAM9XExx Series" }, { 0x34, "AT91x34 Series" }, { 0x37, "CAP7 Series" }, { 0x39, "CAP9 Series" }, { 0x3B, "CAP11 Series" }, { 0x3C, "ATSAM4E" }, { 0x40, "AT91x40 Series" }, { 0x42, "AT91x42 Series" }, { 0x43, "SAMG51 Series" }, { 0x44, "SAMG55 Series (49-pin WLCSP)" }, { 0x45, "SAMG55 Series (64-pin)" }, { 0x47, "SAMG53 Series" }, { 0x55, "AT91x55 Series" }, { 0x60, "AT91SAM7Axx Series" }, { 0x61, "AT91SAM7AQxx Series" }, { 0x63, "AT91x63 Series" }, { 0x64, "SAM4CxxC (100-pin version)" }, { 0x66, "SAM4CxxE (144-pin version)" }, { 0x70, "AT91SAM7Sxx Series" }, { 0x71, "AT91SAM7XCxx Series" }, { 0x72, "AT91SAM7SExx Series" }, { 0x73, "AT91SAM7Lxx Series" }, { 0x75, "AT91SAM7Xxx Series" }, { 0x76, "AT91SAM7SLxx Series" }, { 0x80, "ATSAM3UxC Series (100-pin version)" }, { 0x81, "ATSAM3UxE Series (144-pin version)" }, { 0x83, "ATSAM3A/SAM4A xC Series (100-pin version)"}, { 0x84, "ATSAM3X/SAM4X xC Series (100-pin version)"}, { 0x85, "ATSAM3X/SAM4X xE Series (144-pin version)"}, { 0x86, "ATSAM3X/SAM4X xG Series (208/217-pin version)" }, { 0x88, "ATSAM3S/SAM4S xA Series (48-pin version)" }, { 0x89, "ATSAM3S/SAM4S xB Series (64-pin version)" }, { 0x8A, "ATSAM3S/SAM4S xC Series (100-pin version)"}, { 0x92, "AT91x92 Series" }, { 0x93, "ATSAM3NxA Series (48-pin version)" }, { 0x94, "ATSAM3NxB Series (64-pin version)" }, { 0x95, "ATSAM3NxC Series (100-pin version)" }, { 0x98, "ATSAM3SDxA Series (48-pin version)" }, { 0x99, "ATSAM3SDxB Series (64-pin version)" }, { 0x9A, "ATSAM3SDxC Series (100-pin version)" }, { 0xA5, "ATSAM5A" }, { 0xF0, "AT75Cxx Series" }, { -1, NULL }, }; static const char *const nvptype[] = { "rom", /* 0 */ "romless or onchip flash", /* 1 */ "embedded flash memory",/* 2 */ "rom(nvpsiz) + embedded flash (nvpsiz2)", /* 3 */ "sram emulating flash", /* 4 */ _unknown, /* 5 */ _unknown, /* 6 */ _unknown, /* 7 */ }; static const char *_yes_or_no(uint32_t v) { if (v) return "YES"; else return "NO"; } static const char *const _rc_freq[] = { "4 MHz", "8 MHz", "12 MHz", "reserved" }; static void sam4_explain_ckgr_mor(struct sam4_chip *chip) { uint32_t v; uint32_t rcen; v = sam4_reg_fieldname(chip, "MOSCXTEN", chip->cfg.CKGR_MOR, 0, 1); LOG_USER("(main xtal enabled: %s)", _yes_or_no(v)); v = sam4_reg_fieldname(chip, "MOSCXTBY", chip->cfg.CKGR_MOR, 1, 1); LOG_USER("(main osc bypass: %s)", _yes_or_no(v)); rcen = sam4_reg_fieldname(chip, "MOSCRCEN", chip->cfg.CKGR_MOR, 3, 1); LOG_USER("(onchip RC-OSC enabled: %s)", _yes_or_no(rcen)); v = sam4_reg_fieldname(chip, "MOSCRCF", chip->cfg.CKGR_MOR, 4, 3); LOG_USER("(onchip RC-OSC freq: %s)", _rc_freq[v]); chip->cfg.rc_freq = 0; if (rcen) { switch (v) { default: chip->cfg.rc_freq = 0; break; case 0: chip->cfg.rc_freq = 4 * 1000 * 1000; break; case 1: chip->cfg.rc_freq = 8 * 1000 * 1000; break; case 2: chip->cfg.rc_freq = 12 * 1000 * 1000; break; } } v = sam4_reg_fieldname(chip, "MOSCXTST", chip->cfg.CKGR_MOR, 8, 8); LOG_USER("(startup clks, time= %f uSecs)", ((float)(v * 1000000)) / ((float)(chip->cfg.slow_freq))); v = sam4_reg_fieldname(chip, "MOSCSEL", chip->cfg.CKGR_MOR, 24, 1); LOG_USER("(mainosc source: %s)", v ? "external xtal" : "internal RC"); v = sam4_reg_fieldname(chip, "CFDEN", chip->cfg.CKGR_MOR, 25, 1); LOG_USER("(clock failure enabled: %s)", _yes_or_no(v)); } static void sam4_explain_chipid_cidr(struct sam4_chip *chip) { int x; uint32_t v; const char *cp; sam4_reg_fieldname(chip, "Version", chip->cfg.CHIPID_CIDR, 0, 5); LOG_USER_N("\n"); v = sam4_reg_fieldname(chip, "EPROC", chip->cfg.CHIPID_CIDR, 5, 3); LOG_USER("%s", eproc_names[v]); v = sam4_reg_fieldname(chip, "NVPSIZE", chip->cfg.CHIPID_CIDR, 8, 4); LOG_USER("%s", nvpsize[v]); v = sam4_reg_fieldname(chip, "NVPSIZE2", chip->cfg.CHIPID_CIDR, 12, 4); LOG_USER("%s", nvpsize2[v]); v = sam4_reg_fieldname(chip, "SRAMSIZE", chip->cfg.CHIPID_CIDR, 16, 4); LOG_USER("%s", sramsize[v]); v = sam4_reg_fieldname(chip, "ARCH", chip->cfg.CHIPID_CIDR, 20, 8); cp = _unknown; for (x = 0; archnames[x].name; x++) { if (v == archnames[x].value) { cp = archnames[x].name; break; } } LOG_USER("%s", cp); v = sam4_reg_fieldname(chip, "NVPTYP", chip->cfg.CHIPID_CIDR, 28, 3); LOG_USER("%s", nvptype[v]); v = sam4_reg_fieldname(chip, "EXTID", chip->cfg.CHIPID_CIDR, 31, 1); LOG_USER("(exists: %s)", _yes_or_no(v)); } static void sam4_explain_ckgr_mcfr(struct sam4_chip *chip) { uint32_t v; v = sam4_reg_fieldname(chip, "MAINFRDY", chip->cfg.CKGR_MCFR, 16, 1); LOG_USER("(main ready: %s)", _yes_or_no(v)); v = sam4_reg_fieldname(chip, "MAINF", chip->cfg.CKGR_MCFR, 0, 16); v = (v * chip->cfg.slow_freq) / 16; chip->cfg.mainosc_freq = v; LOG_USER("(%3.03f Mhz (%" PRIu32 ".%03" PRIu32 "khz slowclk)", _tomhz(v), (uint32_t)(chip->cfg.slow_freq / 1000), (uint32_t)(chip->cfg.slow_freq % 1000)); } static void sam4_explain_ckgr_plla(struct sam4_chip *chip) { uint32_t mula, diva; diva = sam4_reg_fieldname(chip, "DIVA", chip->cfg.CKGR_PLLAR, 0, 8); LOG_USER_N("\n"); mula = sam4_reg_fieldname(chip, "MULA", chip->cfg.CKGR_PLLAR, 16, 11); LOG_USER_N("\n"); chip->cfg.plla_freq = 0; if (mula == 0) LOG_USER("\tPLLA Freq: (Disabled,mula = 0)"); else if (diva == 0) LOG_USER("\tPLLA Freq: (Disabled,diva = 0)"); else if (diva >= 1) { chip->cfg.plla_freq = (chip->cfg.mainosc_freq * (mula + 1) / diva); LOG_USER("\tPLLA Freq: %3.03f MHz", _tomhz(chip->cfg.plla_freq)); } } static void sam4_explain_mckr(struct sam4_chip *chip) { uint32_t css, pres, fin = 0; int pdiv = 0; const char *cp = NULL; css = sam4_reg_fieldname(chip, "CSS", chip->cfg.PMC_MCKR, 0, 2); switch (css & 3) { case 0: fin = chip->cfg.slow_freq; cp = "slowclk"; break; case 1: fin = chip->cfg.mainosc_freq; cp = "mainosc"; break; case 2: fin = chip->cfg.plla_freq; cp = "plla"; break; case 3: if (chip->cfg.CKGR_UCKR & (1 << 16)) { fin = 480 * 1000 * 1000; cp = "upll"; } else { fin = 0; cp = "upll (*ERROR* UPLL is disabled)"; } break; default: assert(0); break; } LOG_USER("%s (%3.03f Mhz)", cp, _tomhz(fin)); pres = sam4_reg_fieldname(chip, "PRES", chip->cfg.PMC_MCKR, 4, 3); switch (pres & 0x07) { case 0: pdiv = 1; cp = "selected clock"; break; case 1: pdiv = 2; cp = "clock/2"; break; case 2: pdiv = 4; cp = "clock/4"; break; case 3: pdiv = 8; cp = "clock/8"; break; case 4: pdiv = 16; cp = "clock/16"; break; case 5: pdiv = 32; cp = "clock/32"; break; case 6: pdiv = 64; cp = "clock/64"; break; case 7: pdiv = 6; cp = "clock/6"; break; default: assert(0); break; } LOG_USER("(%s)", cp); fin = fin / pdiv; /* sam4 has a *SINGLE* clock - */ /* other at91 series parts have divisors for these. */ chip->cfg.cpu_freq = fin; chip->cfg.mclk_freq = fin; chip->cfg.fclk_freq = fin; LOG_USER("\t\tResult CPU Freq: %3.03f", _tomhz(fin)); } #if 0 static struct sam4_chip *target2sam4(struct target *target) { struct sam4_chip *chip; if (!target) return NULL; chip = all_sam4_chips; while (chip) { if (chip->target == target) break; /* return below */ else chip = chip->next; } return chip; } #endif static uint32_t *sam4_get_reg_ptr(struct sam4_cfg *cfg, const struct sam4_reg_list *list) { /* this function exists to help */ /* keep funky offsetof() errors */ /* and casting from causing bugs */ /* By using prototypes - we can detect what would */ /* be casting errors. */ return (uint32_t *)(void *)(((char *)(cfg)) + list->struct_offset); } #define SAM4_ENTRY(NAME, FUNC) { .address = SAM4_ ## NAME, .struct_offset = offsetof( \ struct sam4_cfg, \ NAME), # NAME, FUNC } static const struct sam4_reg_list sam4_all_regs[] = { SAM4_ENTRY(CKGR_MOR, sam4_explain_ckgr_mor), SAM4_ENTRY(CKGR_MCFR, sam4_explain_ckgr_mcfr), SAM4_ENTRY(CKGR_PLLAR, sam4_explain_ckgr_plla), SAM4_ENTRY(CKGR_UCKR, NULL), SAM4_ENTRY(PMC_FSMR, NULL), SAM4_ENTRY(PMC_FSPR, NULL), SAM4_ENTRY(PMC_IMR, NULL), SAM4_ENTRY(PMC_MCKR, sam4_explain_mckr), SAM4_ENTRY(PMC_PCK0, NULL), SAM4_ENTRY(PMC_PCK1, NULL), SAM4_ENTRY(PMC_PCK2, NULL), SAM4_ENTRY(PMC_PCSR, NULL), SAM4_ENTRY(PMC_SCSR, NULL), SAM4_ENTRY(PMC_SR, NULL), SAM4_ENTRY(CHIPID_CIDR, sam4_explain_chipid_cidr), SAM4_ENTRY(CHIPID_EXID, NULL), /* TERMINATE THE LIST */ { .name = NULL } }; #undef SAM4_ENTRY static struct sam4_bank_private *get_sam4_bank_private(struct flash_bank *bank) { return bank->driver_priv; } /** * Given a pointer to where it goes in the structure, * determine the register name, address from the all registers table. */ static const struct sam4_reg_list *sam4_get_reg(struct sam4_chip *chip, uint32_t *goes_here) { const struct sam4_reg_list *reg; reg = &(sam4_all_regs[0]); while (reg->name) { uint32_t *possible; /* calculate where this one go.. */ /* it is "possibly" this register. */ possible = ((uint32_t *)(void *)(((char *)(&(chip->cfg))) + reg->struct_offset)); /* well? Is it this register */ if (possible == goes_here) { /* Jump for joy! */ return reg; } /* next... */ reg++; } /* This is *TOTAL*PANIC* - we are totally screwed. */ LOG_ERROR("INVALID SAM4 REGISTER"); return NULL; } static int sam4_read_this_reg(struct sam4_chip *chip, uint32_t *goes_here) { const struct sam4_reg_list *reg; int r; reg = sam4_get_reg(chip, goes_here); if (!reg) return ERROR_FAIL; r = target_read_u32(chip->target, reg->address, goes_here); if (r != ERROR_OK) { LOG_ERROR("Cannot read SAM4 register: %s @ 0x%08x, Err: %d", reg->name, (unsigned)(reg->address), r); } return r; } static int sam4_read_all_regs(struct sam4_chip *chip) { int r; const struct sam4_reg_list *reg; reg = &(sam4_all_regs[0]); while (reg->name) { r = sam4_read_this_reg(chip, sam4_get_reg_ptr(&(chip->cfg), reg)); if (r != ERROR_OK) { LOG_ERROR("Cannot read SAM4 register: %s @ 0x%08x, Error: %d", reg->name, ((unsigned)(reg->address)), r); return r; } reg++; } return ERROR_OK; } static int sam4_get_info(struct sam4_chip *chip) { const struct sam4_reg_list *reg; uint32_t regval; int r; r = sam4_read_all_regs(chip); if (r != ERROR_OK) return r; reg = &(sam4_all_regs[0]); while (reg->name) { /* display all regs */ LOG_DEBUG("Start: %s", reg->name); regval = *sam4_get_reg_ptr(&(chip->cfg), reg); LOG_USER("%*s: [0x%08" PRIx32 "] -> 0x%08" PRIx32, REG_NAME_WIDTH, reg->name, reg->address, regval); if (reg->explain_func) (*(reg->explain_func))(chip); LOG_DEBUG("End: %s", reg->name); reg++; } LOG_USER(" rc-osc: %3.03f MHz", _tomhz(chip->cfg.rc_freq)); LOG_USER(" mainosc: %3.03f MHz", _tomhz(chip->cfg.mainosc_freq)); LOG_USER(" plla: %3.03f MHz", _tomhz(chip->cfg.plla_freq)); LOG_USER(" cpu-freq: %3.03f MHz", _tomhz(chip->cfg.cpu_freq)); LOG_USER("mclk-freq: %3.03f MHz", _tomhz(chip->cfg.mclk_freq)); LOG_USER(" UniqueId: 0x%08" PRIx32 " 0x%08" PRIx32 " 0x%08" PRIx32 " 0x%08"PRIx32, chip->cfg.unique_id[0], chip->cfg.unique_id[1], chip->cfg.unique_id[2], chip->cfg.unique_id[3]); return ERROR_OK; } static int sam4_protect_check(struct flash_bank *bank) { int r; uint32_t v[4] = {0}; unsigned x; struct sam4_bank_private *private; LOG_DEBUG("Begin"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } private = get_sam4_bank_private(bank); if (!private) { LOG_ERROR("no private for this bank?"); return ERROR_FAIL; } if (!(private->probed)) return ERROR_FLASH_BANK_NOT_PROBED; r = flashd_get_lock_bits(private, v); if (r != ERROR_OK) { LOG_DEBUG("Failed: %d", r); return r; } for (x = 0; x < private->nsectors; x++) bank->sectors[x].is_protected = (!!(v[x >> 5] & (1 << (x % 32)))); LOG_DEBUG("Done"); return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(sam4_flash_bank_command) { struct sam4_chip *chip; chip = all_sam4_chips; /* is this an existing chip? */ while (chip) { if (chip->target == bank->target) break; chip = chip->next; } if (!chip) { /* this is a *NEW* chip */ chip = calloc(1, sizeof(struct sam4_chip)); if (!chip) { LOG_ERROR("NO RAM!"); return ERROR_FAIL; } chip->target = bank->target; /* insert at head */ chip->next = all_sam4_chips; all_sam4_chips = chip; chip->target = bank->target; /* assumption is this runs at 32khz */ chip->cfg.slow_freq = 32768; chip->probed = false; } switch (bank->base) { default: LOG_ERROR("Address 0x%08x invalid bank address (try 0x%08x" "[at91sam4s series] )", ((unsigned int)(bank->base)), ((unsigned int)(FLASH_BANK_BASE_S))); return ERROR_FAIL; /* at91sam4s series only has bank 0*/ /* at91sam4sd series has the same address for bank 0 (FLASH_BANK0_BASE_SD)*/ case FLASH_BANK_BASE_S: case FLASH_BANK_BASE_C: bank->driver_priv = &(chip->details.bank[0]); bank->bank_number = 0; chip->details.bank[0].chip = chip; chip->details.bank[0].bank = bank; break; /* Bank 1 of at91sam4sd/at91sam4c32 series */ case FLASH_BANK1_BASE_1024K_SD: case FLASH_BANK1_BASE_2048K_SD: case FLASH_BANK1_BASE_C32: bank->driver_priv = &(chip->details.bank[1]); bank->bank_number = 1; chip->details.bank[1].chip = chip; chip->details.bank[1].bank = bank; break; } /* we initialize after probing. */ return ERROR_OK; } /** * Remove all chips from the internal list without distinguishing which one * is owned by this bank. This simplification works only for one shot * deallocation like current flash_free_all_banks() */ static void sam4_free_driver_priv(struct flash_bank *bank) { struct sam4_chip *chip = all_sam4_chips; while (chip) { struct sam4_chip *next = chip->next; free(chip); chip = next; } all_sam4_chips = NULL; } static int sam4_get_details(struct sam4_bank_private *private) { const struct sam4_chip_details *details; struct sam4_chip *chip; struct flash_bank *saved_banks[SAM4_MAX_FLASH_BANKS]; unsigned x; LOG_DEBUG("Begin"); details = all_sam4_details; while (details->name) { /* Compare cidr without version bits */ if (details->chipid_cidr == (private->chip->cfg.CHIPID_CIDR & 0xFFFFFFE0)) break; else details++; } if (!details->name) { LOG_ERROR("SAM4 ChipID 0x%08x not found in table (perhaps you can ID this chip?)", (unsigned int)(private->chip->cfg.CHIPID_CIDR)); /* Help the victim, print details about the chip */ LOG_INFO("SAM4 CHIPID_CIDR: 0x%08" PRIx32 " decodes as follows", private->chip->cfg.CHIPID_CIDR); sam4_explain_chipid_cidr(private->chip); return ERROR_FAIL; } else { LOG_DEBUG("SAM4 Found chip %s, CIDR 0x%08" PRIx32, details->name, details->chipid_cidr); } /* DANGER: THERE ARE DRAGONS HERE */ /* get our chip - it is going */ /* to be over-written shortly */ chip = private->chip; /* Note that, in reality: */ /* */ /* private = &(chip->details.bank[0]) */ /* or private = &(chip->details.bank[1]) */ /* */ /* save the "bank" pointers */ for (x = 0; x < SAM4_MAX_FLASH_BANKS; x++) saved_banks[x] = chip->details.bank[x].bank; /* Overwrite the "details" structure. */ memcpy(&(private->chip->details), details, sizeof(private->chip->details)); /* now fix the ghosted pointers */ for (x = 0; x < SAM4_MAX_FLASH_BANKS; x++) { chip->details.bank[x].chip = chip; chip->details.bank[x].bank = saved_banks[x]; } /* update the *BANK*SIZE* */ LOG_DEBUG("End"); return ERROR_OK; } static int sam4_info(struct flash_bank *bank, struct command_invocation *cmd) { struct sam4_bank_private *private; int k = bank->size / 1024; private = get_sam4_bank_private(bank); if (!private) return ERROR_FAIL; command_print_sameline(cmd, "%s bank %d: %d kB at " TARGET_ADDR_FMT, private->chip->details.name, private->bank_number, k, bank->base); return ERROR_OK; } static int sam4_probe(struct flash_bank *bank) { int r; struct sam4_bank_private *private; LOG_DEBUG("Begin: Bank: %u", bank->bank_number); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } private = get_sam4_bank_private(bank); if (!private) { LOG_ERROR("Invalid/unknown bank number"); return ERROR_FAIL; } r = sam4_read_all_regs(private->chip); if (r != ERROR_OK) return r; LOG_DEBUG("Here"); if (private->chip->probed) r = sam4_get_info(private->chip); else r = sam4_get_details(private); if (r != ERROR_OK) return r; /* update the flash bank size */ for (unsigned int x = 0; x < SAM4_MAX_FLASH_BANKS; x++) { if (bank->base == private->chip->details.bank[x].base_address) { bank->size = private->chip->details.bank[x].size_bytes; LOG_DEBUG("SAM4 Set flash bank to " TARGET_ADDR_FMT " - " TARGET_ADDR_FMT ", idx %d", bank->base, bank->base + bank->size, x); break; } } if (!bank->sectors) { bank->sectors = calloc(private->nsectors, (sizeof((bank->sectors)[0]))); if (!bank->sectors) { LOG_ERROR("No memory!"); return ERROR_FAIL; } bank->num_sectors = private->nsectors; for (unsigned int x = 0; x < bank->num_sectors; x++) { bank->sectors[x].size = private->sector_size; bank->sectors[x].offset = x * (private->sector_size); /* mark as unknown */ bank->sectors[x].is_erased = -1; bank->sectors[x].is_protected = -1; } } private->probed = true; r = sam4_protect_check(bank); if (r != ERROR_OK) return r; LOG_DEBUG("Bank = %d, nbanks = %d", private->bank_number, private->chip->details.n_banks); if ((private->bank_number + 1) == private->chip->details.n_banks) { /* read unique id, */ /* it appears to be associated with the *last* flash bank. */ flashd_read_uid(private); } return r; } static int sam4_auto_probe(struct flash_bank *bank) { struct sam4_bank_private *private; private = get_sam4_bank_private(bank); if (private && private->probed) return ERROR_OK; return sam4_probe(bank); } static int sam4_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct sam4_bank_private *private; int r; int page_count; /*16 pages equals 8KB - Same size as a lock region*/ page_count = 16; uint32_t status; LOG_DEBUG("Here"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } r = sam4_auto_probe(bank); if (r != ERROR_OK) { LOG_DEBUG("Here,r=%d", r); return r; } private = get_sam4_bank_private(bank); if (!(private->probed)) return ERROR_FLASH_BANK_NOT_PROBED; if ((first == 0) && ((last + 1) == private->nsectors)) { /* whole chip */ LOG_DEBUG("Here"); return flashd_erase_entire_bank(private); } LOG_INFO("sam4 does not auto-erase while programming (Erasing relevant sectors)"); LOG_INFO("sam4 First: 0x%08x Last: 0x%08x", first, last); for (unsigned int i = first; i <= last; i++) { /*16 pages equals 8KB - Same size as a lock region*/ r = flashd_erase_pages(private, (i * page_count), page_count, &status); LOG_INFO("Erasing sector: 0x%08x", i); if (r != ERROR_OK) LOG_ERROR("SAM4: Error performing Erase page @ lock region number %u", i); if (status & (1 << 2)) { LOG_ERROR("SAM4: Lock Region %u is locked", i); return ERROR_FAIL; } if (status & (1 << 1)) { LOG_ERROR("SAM4: Flash Command error @lock region %u", i); return ERROR_FAIL; } } return ERROR_OK; } static int sam4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct sam4_bank_private *private; int r; LOG_DEBUG("Here"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } private = get_sam4_bank_private(bank); if (!(private->probed)) return ERROR_FLASH_BANK_NOT_PROBED; if (set) r = flashd_lock(private, first, last); else r = flashd_unlock(private, first, last); LOG_DEBUG("End: r=%d", r); return r; } static int sam4_page_read(struct sam4_bank_private *private, unsigned pagenum, uint8_t *buf) { uint32_t adr; int r; adr = pagenum * private->page_size; adr = adr + private->base_address; r = target_read_memory(private->chip->target, adr, 4, /* THIS*MUST*BE* in 32bit values */ private->page_size / 4, buf); if (r != ERROR_OK) LOG_ERROR("SAM4: Flash program failed to read page phys address: 0x%08x", (unsigned int)(adr)); return r; } static int sam4_set_wait(struct sam4_bank_private *private) { uint32_t fmr; /* EEFC Flash Mode Register */ int r; /* Get flash mode register value */ r = target_read_u32(private->chip->target, private->controller_address, &fmr); if (r != ERROR_OK) { LOG_ERROR("Error Read failed: read flash mode register"); return r; } /* Clear flash wait state field */ fmr &= 0xfffff0ff; /* set FWS (flash wait states) field in the FMR (flash mode register) */ fmr |= (private->flash_wait_states << 8); LOG_DEBUG("Flash Mode: 0x%08x", ((unsigned int)(fmr))); r = target_write_u32(private->bank->target, private->controller_address, fmr); if (r != ERROR_OK) LOG_ERROR("Error Write failed: set flash mode register"); return r; } static int sam4_page_write(struct sam4_bank_private *private, unsigned pagenum, const uint8_t *buf) { uint32_t adr; uint32_t status; int r; adr = pagenum * private->page_size; adr = (adr + private->base_address); /* 1st sector 8kBytes - page 0 - 15*/ /* 2nd sector 8kBytes - page 16 - 30*/ /* 3rd sector 48kBytes - page 31 - 127*/ LOG_DEBUG("Wr Page %u @ phys address: 0x%08x", pagenum, (unsigned int)(adr)); r = target_write_memory(private->chip->target, adr, 4, /* THIS*MUST*BE* in 32bit values */ private->page_size / 4, buf); if (r != ERROR_OK) { LOG_ERROR("SAM4: Failed to write (buffer) page at phys address 0x%08x", (unsigned int)(adr)); return r; } r = efc_perform_command(private, /* send Erase & Write Page */ AT91C_EFC_FCMD_WP, /*AT91C_EFC_FCMD_EWP only works on first two 8kb sectors*/ pagenum, &status); if (r != ERROR_OK) LOG_ERROR("SAM4: Error performing Write page @ phys address 0x%08x", (unsigned int)(adr)); if (status & (1 << 2)) { LOG_ERROR("SAM4: Page @ Phys address 0x%08x is locked", (unsigned int)(adr)); return ERROR_FAIL; } if (status & (1 << 1)) { LOG_ERROR("SAM4: Flash Command error @phys address 0x%08x", (unsigned int)(adr)); return ERROR_FAIL; } return ERROR_OK; } static int sam4_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int n; unsigned page_cur; unsigned page_end; int r; unsigned page_offset; struct sam4_bank_private *private; uint8_t *pagebuffer; /* in case we bail further below, set this to null */ pagebuffer = NULL; /* ignore dumb requests */ if (count == 0) { r = ERROR_OK; goto done; } if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); r = ERROR_TARGET_NOT_HALTED; goto done; } private = get_sam4_bank_private(bank); if (!(private->probed)) { r = ERROR_FLASH_BANK_NOT_PROBED; goto done; } if ((offset + count) > private->size_bytes) { LOG_ERROR("Flash write error - past end of bank"); LOG_ERROR(" offset: 0x%08x, count 0x%08x, BankEnd: 0x%08x", (unsigned int)(offset), (unsigned int)(count), (unsigned int)(private->size_bytes)); r = ERROR_FAIL; goto done; } pagebuffer = malloc(private->page_size); if (!pagebuffer) { LOG_ERROR("No memory for %d Byte page buffer", (int)(private->page_size)); r = ERROR_FAIL; goto done; } r = sam4_set_wait(private); if (r != ERROR_OK) goto done; /* what page do we start & end in? */ page_cur = offset / private->page_size; page_end = (offset + count - 1) / private->page_size; LOG_DEBUG("Offset: 0x%08x, Count: 0x%08x", (unsigned int)(offset), (unsigned int)(count)); LOG_DEBUG("Page start: %d, Page End: %d", (int)(page_cur), (int)(page_end)); /* Special case: all one page */ /* */ /* Otherwise: */ /* (1) non-aligned start */ /* (2) body pages */ /* (3) non-aligned end. */ /* Handle special case - all one page. */ if (page_cur == page_end) { LOG_DEBUG("Special case, all in one page"); r = sam4_page_read(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; page_offset = (offset & (private->page_size-1)); memcpy(pagebuffer + page_offset, buffer, count); r = sam4_page_write(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; r = ERROR_OK; goto done; } /* non-aligned start */ page_offset = offset & (private->page_size - 1); if (page_offset) { LOG_DEBUG("Not-Aligned start"); /* read the partial */ r = sam4_page_read(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; /* over-write with new data */ n = (private->page_size - page_offset); memcpy(pagebuffer + page_offset, buffer, n); r = sam4_page_write(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; count -= n; offset += n; buffer += n; page_cur++; } /* By checking that offset is correct here, we also fix a clang warning */ assert(offset % private->page_size == 0); /* intermediate large pages */ /* also - the final *terminal* */ /* if that terminal page is a full page */ LOG_DEBUG("Full Page Loop: cur=%d, end=%d, count = 0x%08x", (int)page_cur, (int)page_end, (unsigned int)(count)); while ((page_cur < page_end) && (count >= private->page_size)) { r = sam4_page_write(private, page_cur, buffer); if (r != ERROR_OK) goto done; count -= private->page_size; buffer += private->page_size; page_cur += 1; } /* terminal partial page? */ if (count) { LOG_DEBUG("Terminal partial page, count = 0x%08x", (unsigned int)(count)); /* we have a partial page */ r = sam4_page_read(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; /* data goes at start */ memcpy(pagebuffer, buffer, count); r = sam4_page_write(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; } LOG_DEBUG("Done!"); r = ERROR_OK; done: free(pagebuffer); return r; } COMMAND_HANDLER(sam4_handle_info_command) { struct sam4_chip *chip; chip = get_current_sam4(CMD); if (!chip) return ERROR_OK; unsigned x; int r; /* bank0 must exist before we can do anything */ if (!chip->details.bank[0].bank) { x = 0; need_define: command_print(CMD, "Please define bank %d via command: flash bank %s ... ", x, at91sam4_flash.name); return ERROR_FAIL; } /* if bank 0 is not probed, then probe it */ if (!(chip->details.bank[0].probed)) { r = sam4_auto_probe(chip->details.bank[0].bank); if (r != ERROR_OK) return ERROR_FAIL; } /* above guarantees the "chip details" structure is valid */ /* and thus, bank private areas are valid */ /* and we have a SAM4 chip, what a concept! */ /* auto-probe other banks, 0 done above */ for (x = 1; x < SAM4_MAX_FLASH_BANKS; x++) { /* skip banks not present */ if (!(chip->details.bank[x].present)) continue; if (!chip->details.bank[x].bank) goto need_define; if (chip->details.bank[x].probed) continue; r = sam4_auto_probe(chip->details.bank[x].bank); if (r != ERROR_OK) return r; } r = sam4_get_info(chip); if (r != ERROR_OK) { LOG_DEBUG("Sam4Info, Failed %d", r); return r; } return ERROR_OK; } COMMAND_HANDLER(sam4_handle_gpnvm_command) { unsigned x, v; int r, who; struct sam4_chip *chip; chip = get_current_sam4(CMD); if (!chip) return ERROR_OK; if (chip->target->state != TARGET_HALTED) { LOG_ERROR("sam4 - target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!chip->details.bank[0].bank) { command_print(CMD, "Bank0 must be defined first via: flash bank %s ...", at91sam4_flash.name); return ERROR_FAIL; } if (!chip->details.bank[0].probed) { r = sam4_auto_probe(chip->details.bank[0].bank); if (r != ERROR_OK) return r; } switch (CMD_ARGC) { default: return ERROR_COMMAND_SYNTAX_ERROR; case 0: goto showall; case 1: who = -1; break; case 2: if ((strcmp(CMD_ARGV[0], "show") == 0) && (strcmp(CMD_ARGV[1], "all") == 0)) who = -1; else { uint32_t v32; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); who = v32; } break; } if (strcmp("show", CMD_ARGV[0]) == 0) { if (who == -1) { showall: r = ERROR_OK; for (x = 0; x < chip->details.n_gpnvms; x++) { r = flashd_get_gpnvm(&(chip->details.bank[0]), x, &v); if (r != ERROR_OK) break; command_print(CMD, "sam4-gpnvm%u: %u", x, v); } return r; } if ((who >= 0) && (((unsigned)(who)) < chip->details.n_gpnvms)) { r = flashd_get_gpnvm(&(chip->details.bank[0]), who, &v); if (r == ERROR_OK) command_print(CMD, "sam4-gpnvm%u: %u", who, v); return r; } else { command_print(CMD, "sam4-gpnvm invalid GPNVM: %u", who); return ERROR_COMMAND_SYNTAX_ERROR; } } if (who == -1) { command_print(CMD, "Missing GPNVM number"); return ERROR_COMMAND_SYNTAX_ERROR; } if (strcmp("set", CMD_ARGV[0]) == 0) r = flashd_set_gpnvm(&(chip->details.bank[0]), who); else if ((strcmp("clr", CMD_ARGV[0]) == 0) || (strcmp("clear", CMD_ARGV[0]) == 0)) /* quietly accept both */ r = flashd_clr_gpnvm(&(chip->details.bank[0]), who); else { command_print(CMD, "Unknown command: %s", CMD_ARGV[0]); r = ERROR_COMMAND_SYNTAX_ERROR; } return r; } COMMAND_HANDLER(sam4_handle_slowclk_command) { struct sam4_chip *chip; chip = get_current_sam4(CMD); if (!chip) return ERROR_OK; switch (CMD_ARGC) { case 0: /* show */ break; case 1: { /* set */ uint32_t v; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v); if (v > 200000) { /* absurd slow clock of 200Khz? */ command_print(CMD, "Absurd/illegal slow clock freq: %d\n", (int)(v)); return ERROR_COMMAND_SYNTAX_ERROR; } chip->cfg.slow_freq = v; break; } default: /* error */ command_print(CMD, "Too many parameters"); return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "Slowclk freq: %d.%03dkhz", (int)(chip->cfg.slow_freq / 1000), (int)(chip->cfg.slow_freq % 1000)); return ERROR_OK; } static const struct command_registration at91sam4_exec_command_handlers[] = { { .name = "gpnvm", .handler = sam4_handle_gpnvm_command, .mode = COMMAND_EXEC, .usage = "[('clr'|'set'|'show') bitnum]", .help = "Without arguments, shows all bits in the gpnvm " "register. Otherwise, clears, sets, or shows one " "General Purpose Non-Volatile Memory (gpnvm) bit.", }, { .name = "info", .handler = sam4_handle_info_command, .mode = COMMAND_EXEC, .help = "Print information about the current at91sam4 chip " "and its flash configuration.", .usage = "", }, { .name = "slowclk", .handler = sam4_handle_slowclk_command, .mode = COMMAND_EXEC, .usage = "[clock_hz]", .help = "Display or set the slowclock frequency " "(default 32768 Hz).", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration at91sam4_command_handlers[] = { { .name = "at91sam4", .mode = COMMAND_ANY, .help = "at91sam4 flash command group", .usage = "", .chain = at91sam4_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver at91sam4_flash = { .name = "at91sam4", .commands = at91sam4_command_handlers, .flash_bank_command = sam4_flash_bank_command, .erase = sam4_erase, .protect = sam4_protect, .write = sam4_write, .read = default_flash_read, .probe = sam4_probe, .auto_probe = sam4_auto_probe, .erase_check = default_flash_blank_check, .protect_check = sam4_protect_check, .info = sam4_info, .free_driver_priv = sam4_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/at91sam4l.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013 by Andrey Yurovsky * * Andrey Yurovsky <yurovsky@gmail.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <jtag/jtag.h> #include <target/cortex_m.h> /* At this time, the SAM4L Flash is available in these capacities: * ATSAM4Lx4xx: 256KB (512 pages) * ATSAM4Lx2xx: 128KB (256 pages) * ATSAM4Lx8xx: 512KB (1024 pages) */ /* There are 16 lockable regions regardless of overall capacity. The number * of pages per sector is therefore dependant on capacity. */ #define SAM4L_NUM_SECTORS 16 /* Locations in memory map */ #define SAM4L_FLASH ((uint32_t)0x00000000) /* Flash region */ #define SAM4L_FLASH_USER 0x00800000 /* Flash user page region */ #define SAM4L_FLASHCALW 0x400A0000 /* Flash controller */ #define SAM4L_CHIPID 0x400E0740 /* Chip Identification */ /* Offsets from SAM4L_FLASHCALW */ #define SAM4L_FCR 0x00 /* Flash Control Register (RW) */ #define SAM4L_FCMD 0x04 /* Flash Command Register (RW) */ #define SAM4L_FSR 0x08 /* Flash Status Register (RO) */ #define SAM4L_FPR 0x0C /* Flash Parameter Register (RO) */ #define SAM4L_FVR 0x10 /* Flash Version Register (RO) */ #define SAM4L_FGPFRHI 0x14 /* Flash General Purpose Register High (RO) */ #define SAM4L_FGPFRLO 0x18 /* Flash General Purpose Register Low (RO) */ /* Offsets from SAM4L_CHIPID */ #define SAM4L_CIDR 0x00 /* Chip ID Register (RO) */ #define SAM4L_EXID 0x04 /* Chip ID Extension Register (RO) */ /* Flash commands (for SAM4L_FCMD), see Table 14-5 */ #define SAM4L_FCMD_NOP 0 /* No Operation */ #define SAM4L_FCMD_WP 1 /* Write Page */ #define SAM4L_FCMD_EP 2 /* Erase Page */ #define SAM4L_FCMD_CPB 3 /* Clear Page Buffer */ #define SAM4L_FCMD_LP 4 /* Lock region containing given page */ #define SAM4L_FCMD_UP 5 /* Unlock region containing given page */ #define SAM4L_FCMD_EA 6 /* Erase All */ #define SAM4L_FCMD_WGPB 7 /* Write general-purpose fuse bit */ #define SAM4L_FCMD_EGPB 8 /* Erase general-purpose fuse bit */ #define SAM4L_FCMD_SSB 9 /* Set security fuses */ #define SAM4L_FCMD_PGPFB 10 /* Program general-purpose fuse byte */ #define SAM4L_FCMD_EAGPF 11 /* Erase all general-purpose fuse bits */ #define SAM4L_FCMD_QPR 12 /* Quick page read */ #define SAM4L_FCMD_WUP 13 /* Write user page */ #define SAM4L_FCMD_EUP 14 /* Erase user page */ #define SAM4L_FCMD_QPRUP 15 /* Quick page read (user page) */ #define SAM4L_FCMD_HSEN 16 /* High speed mode enable */ #define SAM4L_FCMD_HSDIS 17 /* High speed mode disable */ #define SAM4L_FMCD_CMDKEY 0xA5UL /* 'key' to issue commands, see 14.10.2 */ /* SMAP registers and bits */ #define SMAP_BASE 0x400A3000 #define SMAP_SCR (SMAP_BASE + 8) #define SMAP_SCR_HCR (1 << 1) struct sam4l_chip_info { uint32_t id; uint32_t exid; const char *name; }; /* These are taken from Table 9-1 in 42023E-SAM-07/2013 */ static const struct sam4l_chip_info sam4l_known_chips[] = { { 0xAB0B0AE0, 0x1400000F, "ATSAM4LC8C" }, { 0xAB0A09E0, 0x0400000F, "ATSAM4LC4C" }, { 0xAB0A07E0, 0x0400000F, "ATSAM4LC2C" }, { 0xAB0B0AE0, 0x1300000F, "ATSAM4LC8B" }, { 0xAB0A09E0, 0x0300000F, "ATSAM4LC4B" }, { 0xAB0A07E0, 0x0300000F, "ATSAM4LC2B" }, { 0xAB0B0AE0, 0x1200000F, "ATSAM4LC8A" }, { 0xAB0A09E0, 0x0200000F, "ATSAM4LC4A" }, { 0xAB0A07E0, 0x0200000F, "ATSAM4LC2A" }, { 0xAB0B0AE0, 0x14000002, "ATSAM4LS8C" }, { 0xAB0A09E0, 0x04000002, "ATSAM4LS4C" }, { 0xAB0A07E0, 0x04000002, "ATSAM4LS2C" }, { 0xAB0B0AE0, 0x13000002, "ATSAM4LS8B" }, { 0xAB0A09E0, 0x03000002, "ATSAM4LS4B" }, { 0xAB0A07E0, 0x03000002, "ATSAM4LS2B" }, { 0xAB0B0AE0, 0x12000002, "ATSAM4LS8A" }, { 0xAB0A09E0, 0x02000002, "ATSAM4LS4A" }, { 0xAB0A07E0, 0x02000002, "ATSAM4LS2A" }, }; /* Meaning of SRAMSIZ field in CHIPID, see 9.3.1 in 42023E-SAM-07/2013 */ static const uint16_t sam4l_ram_sizes[16] = { 48, 1, 2, 6, 24, 4, 80, 160, 8, 16, 32, 64, 128, 256, 96, 512 }; /* Meaning of PSZ field in FPR, see 14.10.4 in 42023E-SAM-07/2013 */ static const uint16_t sam4l_page_sizes[8] = { 32, 64, 128, 256, 512, 1024, 2048, 4096 }; struct sam4l_info { const struct sam4l_chip_info *details; uint32_t flash_kb; uint32_t ram_kb; uint32_t page_size; int num_pages; int sector_size; unsigned int pages_per_sector; bool probed; struct target *target; }; static int sam4l_flash_wait_until_ready(struct target *target) { volatile unsigned int t = 0; uint32_t st; int res; /* Poll the status register until the FRDY bit is set */ do { res = target_read_u32(target, SAM4L_FLASHCALW + SAM4L_FSR, &st); } while (res == ERROR_OK && !(st & (1<<0)) && ++t < 10); return res; } static int sam4l_flash_check_error(struct target *target, uint32_t *err) { uint32_t st; int res; res = target_read_u32(target, SAM4L_FLASHCALW + SAM4L_FSR, &st); if (res == ERROR_OK) *err = st & ((1<<3) | (1<<2)); /* grab PROGE and LOCKE bits */ return res; } static int sam4l_flash_command(struct target *target, uint8_t cmd, int page) { int res; uint32_t fcmd; uint32_t err; res = sam4l_flash_wait_until_ready(target); if (res != ERROR_OK) return res; if (page >= 0) { /* Set the page number. For some commands, the page number is just an * argument (ex: fuse bit number). */ fcmd = (SAM4L_FMCD_CMDKEY << 24) | ((page & 0xFFFF) << 8) | (cmd & 0x3F); } else { /* Reuse the page number that was read from the flash command register. */ res = target_read_u32(target, SAM4L_FLASHCALW + SAM4L_FCMD, &fcmd); if (res != ERROR_OK) return res; fcmd &= ~0x3F; /* clear out the command code */ fcmd |= (SAM4L_FMCD_CMDKEY << 24) | (cmd & 0x3F); } /* Send the command */ res = target_write_u32(target, SAM4L_FLASHCALW + SAM4L_FCMD, fcmd); if (res != ERROR_OK) return res; res = sam4l_flash_check_error(target, &err); if (res != ERROR_OK) return res; if (err != 0) LOG_ERROR("%s got error status 0x%08" PRIx32, __func__, err); res = sam4l_flash_wait_until_ready(target); return res; } FLASH_BANK_COMMAND_HANDLER(sam4l_flash_bank_command) { if (bank->base != SAM4L_FLASH) { LOG_ERROR("Address " TARGET_ADDR_FMT " invalid bank address (try 0x%08" PRIx32 "[at91sam4l series] )", bank->base, SAM4L_FLASH); return ERROR_FAIL; } struct sam4l_info *chip; chip = calloc(1, sizeof(*chip)); if (!chip) { LOG_ERROR("No memory for flash bank chip info"); return ERROR_FAIL; } chip->target = bank->target; chip->probed = false; bank->driver_priv = chip; return ERROR_OK; } static const struct sam4l_chip_info *sam4l_find_chip_name(uint32_t id, uint32_t exid) { unsigned int i; id &= ~0xF; for (i = 0; i < ARRAY_SIZE(sam4l_known_chips); i++) { if (sam4l_known_chips[i].id == id && sam4l_known_chips[i].exid == exid) return &sam4l_known_chips[i]; } return NULL; } static int sam4l_check_page_erased(struct flash_bank *bank, uint32_t pn, bool *is_erased_p) { int res; uint32_t st; /* Issue a quick page read to verify that we've erased this page */ res = sam4l_flash_command(bank->target, SAM4L_FCMD_QPR, pn); if (res != ERROR_OK) { LOG_ERROR("Quick page read %" PRIu32 " failed", pn); return res; } /* Retrieve the flash status */ res = target_read_u32(bank->target, SAM4L_FLASHCALW + SAM4L_FSR, &st); if (res != ERROR_OK) { LOG_ERROR("Couldn't read erase status"); return res; } /* Is the page in question really erased? */ *is_erased_p = !!(st & (1<<5)); return ERROR_OK; } static int sam4l_probe(struct flash_bank *bank) { uint32_t id, exid, param; int res; struct sam4l_info *chip = (struct sam4l_info *)bank->driver_priv; if (chip->probed) return ERROR_OK; res = target_read_u32(bank->target, SAM4L_CHIPID + SAM4L_CIDR, &id); if (res != ERROR_OK) { LOG_ERROR("Couldn't read chip ID"); return res; } res = target_read_u32(bank->target, SAM4L_CHIPID + SAM4L_EXID, &exid); if (res != ERROR_OK) { LOG_ERROR("Couldn't read extended chip ID"); return res; } chip->details = sam4l_find_chip_name(id, exid); /* The RAM capacity is in a lookup table. */ chip->ram_kb = sam4l_ram_sizes[0xF & (id >> 16)]; switch (0xF & (id >> 8)) { case 0x07: chip->flash_kb = 128; break; case 0x09: chip->flash_kb = 256; break; case 0x0A: chip->flash_kb = 512; break; default: LOG_ERROR("Unknown flash size (chip ID is %08" PRIx32 "), assuming 128K", id); chip->flash_kb = 128; break; } /* Retrieve the Flash parameters */ res = target_read_u32(bank->target, SAM4L_FLASHCALW + SAM4L_FPR, ¶m); if (res != ERROR_OK) { LOG_ERROR("Couldn't read Flash parameters"); return res; } /* Fetch the page size from the parameter register. Technically the flash * capacity is there too though the manual mentions that not all parts will * have it set so we use the Chip ID capacity information instead. */ chip->page_size = sam4l_page_sizes[0x7 & (param >> 8)]; assert(chip->page_size); chip->num_pages = chip->flash_kb * 1024 / chip->page_size; chip->sector_size = (chip->flash_kb * 1024) / SAM4L_NUM_SECTORS; chip->pages_per_sector = chip->sector_size / chip->page_size; /* Make sure the bank size is correct */ bank->size = chip->flash_kb * 1024; /* Allocate the sector table. */ bank->num_sectors = SAM4L_NUM_SECTORS; bank->sectors = calloc(bank->num_sectors, (sizeof((bank->sectors)[0]))); if (!bank->sectors) return ERROR_FAIL; /* Fill out the sector information: all SAM4L sectors are the same size and * there is always a fixed number of them. */ for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].size = chip->sector_size; bank->sectors[i].offset = i * chip->sector_size; /* mark as unknown */ bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } /* Done */ chip->probed = true; LOG_INFO("SAM4L MCU: %s (Rev %c) (%" PRIu32 "KB Flash with %d %" PRIu32 "B pages, %" PRIu32 "KB RAM)", chip->details ? chip->details->name : "unknown", (char)('A' + (id & 0xF)), chip->flash_kb, chip->num_pages, chip->page_size, chip->ram_kb); return ERROR_OK; } static int sam4l_protect_check(struct flash_bank *bank) { int res; uint32_t st; struct sam4l_info *chip = (struct sam4l_info *)bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!chip->probed) { if (sam4l_probe(bank) != ERROR_OK) return ERROR_FLASH_BANK_NOT_PROBED; } res = target_read_u32(bank->target, SAM4L_FLASHCALW + SAM4L_FSR, &st); if (res != ERROR_OK) return res; st >>= 16; /* There are 16 lock region bits in the upper half word */ for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = !!(st & (1<<i)); return ERROR_OK; } static int sam4l_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct sam4l_info *chip = (struct sam4l_info *)bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!chip->probed) { if (sam4l_probe(bank) != ERROR_OK) return ERROR_FLASH_BANK_NOT_PROBED; } /* Make sure the pages make sense. */ if (first >= bank->num_sectors || last >= bank->num_sectors) { LOG_ERROR("Protect range %u - %u not valid (%u sectors total)", first, last, bank->num_sectors); return ERROR_FAIL; } /* Try to lock or unlock each sector in the range. This is done by locking * a region containing one page in that sector, we arbitrarily choose the 0th * page in the sector. */ for (unsigned int i = first; i <= last; i++) { int res; res = sam4l_flash_command(bank->target, set ? SAM4L_FCMD_LP : SAM4L_FCMD_UP, i * chip->pages_per_sector); if (res != ERROR_OK) { LOG_ERROR("Can't %slock region containing page %d", set ? "" : "un", i); return res; } } return ERROR_OK; } static int sam4l_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int ret; struct sam4l_info *chip = (struct sam4l_info *)bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!chip->probed) { if (sam4l_probe(bank) != ERROR_OK) return ERROR_FLASH_BANK_NOT_PROBED; } /* Make sure the pages make sense. */ if (first >= bank->num_sectors || last >= bank->num_sectors) { LOG_ERROR("Erase range %u - %u not valid (%u sectors total)", first, last, bank->num_sectors); return ERROR_FAIL; } /* Erase */ if ((first == 0) && ((last + 1) == bank->num_sectors)) { LOG_DEBUG("Erasing the whole chip"); ret = sam4l_flash_command(bank->target, SAM4L_FCMD_EA, -1); if (ret != ERROR_OK) { LOG_ERROR("Erase All failed"); return ret; } } else { LOG_DEBUG("Erasing sectors %u through %u...\n", first, last); /* For each sector... */ for (unsigned int i = first; i <= last; i++) { /* For each page in that sector... */ for (unsigned int j = 0; j < chip->pages_per_sector; j++) { unsigned int pn = i * chip->pages_per_sector + j; bool is_erased = false; /* Issue the page erase */ ret = sam4l_flash_command(bank->target, SAM4L_FCMD_EP, pn); if (ret != ERROR_OK) { LOG_ERROR("Erasing page %u failed", pn); return ret; } ret = sam4l_check_page_erased(bank, pn, &is_erased); if (ret != ERROR_OK) return ret; if (!is_erased) { LOG_DEBUG("Page %u was not erased.", pn); return ERROR_FAIL; } } } } return ERROR_OK; } /* Write an entire page from host buffer 'buf' to page-aligned 'address' in the * Flash. */ static int sam4l_write_page(struct sam4l_info *chip, struct target *target, uint32_t address, const uint8_t *buf) { int res; LOG_DEBUG("sam4l_write_page address=%08" PRIx32, address); /* Clear the page buffer before we write to it */ res = sam4l_flash_command(target, SAM4L_FCMD_CPB, -1); if (res != ERROR_OK) { LOG_ERROR("%s: can't clear page buffer", __func__); return res; } /* Write the modified page back to the target's page buffer */ res = target_write_memory(target, address, 4, chip->page_size / 4, buf); if (res != ERROR_OK) { LOG_ERROR("%s: %d", __func__, __LINE__); return res; } /* Commit the page contents to Flash: erase the current page and then * write it out. */ res = sam4l_flash_command(target, SAM4L_FCMD_EP, -1); if (res != ERROR_OK) return res; res = sam4l_flash_command(target, SAM4L_FCMD_WP, -1); return res; } /* Write partial contents into page-aligned 'address' on the Flash from host * buffer 'buf' by writing 'nb' of 'buf' at 'offset' into the Flash page. */ static int sam4l_write_page_partial(struct sam4l_info *chip, struct flash_bank *bank, uint32_t address, const uint8_t *buf, uint32_t page_offset, uint32_t nb) { int res; uint8_t *pg = malloc(chip->page_size); if (!pg) return ERROR_FAIL; LOG_DEBUG("sam4l_write_page_partial address=%08" PRIx32 " nb=%08" PRIx32, address, nb); assert(page_offset + nb < chip->page_size); assert((address % chip->page_size) == 0); /* Retrieve the full page contents from Flash */ res = target_read_memory(bank->target, address, 4, chip->page_size / 4, pg); if (res != ERROR_OK) { free(pg); return res; } /* Insert our partial page over the data from Flash */ memcpy(pg + (page_offset % chip->page_size), buf, nb); /* Write the page back out */ res = sam4l_write_page(chip, bank->target, address, pg); free(pg); return res; } static int sam4l_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int res; uint32_t nb = 0; struct sam4l_info *chip = (struct sam4l_info *)bank->driver_priv; LOG_DEBUG("sam4l_write offset=%08" PRIx32 " count=%08" PRIx32, offset, count); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!chip->probed) { if (sam4l_probe(bank) != ERROR_OK) return ERROR_FLASH_BANK_NOT_PROBED; } if (offset % chip->page_size) { /* We're starting at an unaligned offset so we'll write a partial page * comprising that offset and up to the end of that page. */ nb = chip->page_size - (offset % chip->page_size); if (nb > count) nb = count; } else if (count < chip->page_size) { /* We're writing an aligned but partial page. */ nb = count; } if (nb > 0) { res = sam4l_write_page_partial(chip, bank, (offset / chip->page_size) * chip->page_size + bank->base, buffer, offset % chip->page_size, nb); if (res != ERROR_OK) return res; /* We're done with the page contents */ count -= nb; offset += nb; } /* There's at least one aligned page to write out. */ if (count >= chip->page_size) { assert(chip->page_size > 0); int np = count / chip->page_size + ((count % chip->page_size) ? 1 : 0); for (int i = 0; i < np; i++) { if (count >= chip->page_size) { res = sam4l_write_page(chip, bank->target, bank->base + offset, buffer + (i * chip->page_size)); /* Advance one page */ offset += chip->page_size; count -= chip->page_size; } else { res = sam4l_write_page_partial(chip, bank, bank->base + offset, buffer + (i * chip->page_size), 0, count); /* We're done after this. */ offset += count; count = 0; } if (res != ERROR_OK) return res; } } return ERROR_OK; } COMMAND_HANDLER(sam4l_handle_reset_deassert) { struct target *target = get_current_target(CMD_CTX); int retval = ERROR_OK; enum reset_types jtag_reset_config = jtag_get_reset_config(); /* If the target has been unresponsive before, try to re-establish * communication now - CPU is held in reset by DSU, DAP is working */ if (!target_was_examined(target)) target_examine_one(target); target_poll(target); /* In case of sysresetreq, debug retains state set in cortex_m_assert_reset() * so we just release reset held by SMAP * * n_RESET (srst) clears the DP, so reenable debug and set vector catch here * * After vectreset SMAP release is not needed however makes no harm */ if (target->reset_halt && (jtag_reset_config & RESET_HAS_SRST)) { retval = target_write_u32(target, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN); if (retval == ERROR_OK) retval = target_write_u32(target, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); /* do not return on error here, releasing SMAP reset is more important */ } int retval2 = target_write_u32(target, SMAP_SCR, SMAP_SCR_HCR); if (retval2 != ERROR_OK) return retval2; return retval; } static const struct command_registration at91sam4l_exec_command_handlers[] = { { .name = "smap_reset_deassert", .handler = sam4l_handle_reset_deassert, .mode = COMMAND_EXEC, .help = "deassert internal reset held by SMAP", .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration at91sam4l_command_handlers[] = { { .name = "at91sam4l", .mode = COMMAND_ANY, .help = "at91sam4l flash command group", .usage = "", .chain = at91sam4l_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver at91sam4l_flash = { .name = "at91sam4l", .commands = at91sam4l_command_handlers, .flash_bank_command = sam4l_flash_bank_command, .erase = sam4l_erase, .protect = sam4l_protect, .write = sam4l_write, .read = default_flash_read, .probe = sam4l_probe, .auto_probe = sam4l_probe, .erase_check = default_flash_blank_check, .protect_check = sam4l_protect_check, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/at91sam7.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Gheorghe Guran (atlas) * ****************************************************************************/ /*************************************************************************** * * New flash setup command: * * flash bank <driver> <base_addr> <size> <chip_width> <bus_width> <target_id> * [<chip_type> <banks> * <sectors_per_bank> <pages_per_sector> * <page_size> <num_nvmbits> * <ext_freq_khz>] * * <ext_freq_khz> - MUST be used if clock is from external source, * CAN be used if main oscillator frequency is known (recommended) * Examples: * ==== RECOMMENDED (covers clock speed) ============ * flash bank at91sam7 0x00100000 0 0 4 $_TARGETNAME AT91SAM7XC256 1 16 64 256 3 25000 * (if auto-detect fails; provides clock spec) * flash bank at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 25000 * (auto-detect everything except the clock) * ==== NOT RECOMMENDED !!! (clock speed is not configured) ==== * flash bank at91sam7 0x00100000 0 0 4 $_TARGETNAME AT91SAM7XC256 1 16 64 256 3 0 * (if auto-detect fails) * flash bank at91sam7 0 0 0 0 $_TARGETNAME * (old style, auto-detect everything) ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> /* AT91SAM7 control registers */ #define DBGU_CIDR 0xFFFFF240 #define CKGR_MCFR 0xFFFFFC24 #define CKGR_MOR 0xFFFFFC20 #define CKGR_MCFR_MAINRDY 0x10000 #define CKGR_PLLR 0xFFFFFC2c #define CKGR_PLLR_DIV 0xff #define CKGR_PLLR_MUL 0x07ff0000 #define PMC_MCKR 0xFFFFFC30 #define PMC_MCKR_CSS 0x03 #define PMC_MCKR_PRES 0x1c /* Flash Controller Commands */ #define WP 0x01 #define SLB 0x02 #define WPL 0x03 #define CLB 0x04 #define EA 0x08 #define SGPB 0x0B #define CGPB 0x0D #define SSB 0x0F /* MC_FSR bit definitions */ #define MC_FSR_FRDY 1 #define MC_FSR_EOL 2 /* AT91SAM7 constants */ #define RC_FREQ 32000 /* Flash timing modes */ #define FMR_TIMING_NONE 0 #define FMR_TIMING_NVBITS 1 #define FMR_TIMING_FLASH 2 /* Flash size constants */ #define FLASH_SIZE_8KB 1 #define FLASH_SIZE_16KB 2 #define FLASH_SIZE_32KB 3 #define FLASH_SIZE_64KB 5 #define FLASH_SIZE_128KB 7 #define FLASH_SIZE_256KB 9 #define FLASH_SIZE_512KB 10 #define FLASH_SIZE_1024KB 12 #define FLASH_SIZE_2048KB 14 static int at91sam7_protect_check(struct flash_bank *bank); static int at91sam7_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count); static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number); static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode); static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout); static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen); static const uint32_t mc_fmr[4] = { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 }; static const uint32_t mc_fcr[4] = { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 }; static const uint32_t mc_fsr[4] = { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 }; static const char *eproc[8] = { "Unknown", "ARM946-E", "ARM7TDMI", "Unknown", "ARM920T", "ARM926EJ-S", "Unknown", "Unknown" }; struct at91sam7_flash_bank { /* chip id register */ uint32_t cidr; uint16_t cidr_ext; uint16_t cidr_nvptyp; uint16_t cidr_arch; uint16_t cidr_sramsiz; uint16_t cidr_nvpsiz; uint16_t cidr_nvpsiz2; uint16_t cidr_eproc; uint16_t cidr_version; const char *target_name; /* flash auto-detection */ uint8_t flash_autodetection; /* flash geometry */ uint16_t pages_per_sector; uint16_t pagesize; uint16_t pages_in_lockregion; /* nv memory bits */ uint16_t num_lockbits_on; uint16_t lockbits; uint16_t num_nvmbits; uint16_t num_nvmbits_on; uint16_t nvmbits; uint8_t securitybit; /* 0: not init * 1: fmcn for nvbits (1uS) * 2: fmcn for flash (1.5uS) */ uint8_t flashmode; /* main clock status */ uint8_t mck_valid; uint32_t mck_freq; /* external clock frequency */ uint32_t ext_freq; }; #if 0 static long SRAMSIZ[16] = { -1, 0x0400, /* 1K */ 0x0800, /* 2K */ -1, 0x1c000, /* 112K */ 0x1000, /* 4K */ 0x14000, /* 80K */ 0x28000, /* 160K */ 0x2000, /* 8K */ 0x4000, /* 16K */ 0x8000, /* 32K */ 0x10000, /* 64K */ 0x20000, /* 128K */ 0x40000, /* 256K */ 0x18000, /* 96K */ 0x80000, /* 512K */ }; #endif static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number) { uint32_t fsr; target_read_u32(target, mc_fsr[bank_number], &fsr); return fsr; } /* Read clock configuration and set at91sam7_info->mck_freq */ static void at91sam7_read_clock_info(struct flash_bank *bank) { struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; struct target *target = bank->target; uint32_t mckr, mcfr, pllr, mor; unsigned long tmp = 0, mainfreq; /* Read Clock Generator Main Oscillator Register */ target_read_u32(target, CKGR_MOR, &mor); /* Read Clock Generator Main Clock Frequency Register */ target_read_u32(target, CKGR_MCFR, &mcfr); /* Read Master Clock Register*/ target_read_u32(target, PMC_MCKR, &mckr); /* Read Clock Generator PLL Register */ target_read_u32(target, CKGR_PLLR, &pllr); at91sam7_info->mck_valid = 0; at91sam7_info->mck_freq = 0; switch (mckr & PMC_MCKR_CSS) { case 0: /* Slow Clock */ at91sam7_info->mck_valid = 1; tmp = RC_FREQ; break; case 1: /* Main Clock */ if ((mcfr & CKGR_MCFR_MAINRDY) && (at91sam7_info->ext_freq == 0)) { at91sam7_info->mck_valid = 1; tmp = RC_FREQ / 16ul * (mcfr & 0xffff); } else if (at91sam7_info->ext_freq != 0) { at91sam7_info->mck_valid = 1; tmp = at91sam7_info->ext_freq; } break; case 2: /* Reserved */ break; case 3: /* PLL Clock */ if ((mcfr & CKGR_MCFR_MAINRDY) && (at91sam7_info->ext_freq == 0)) { target_read_u32(target, CKGR_PLLR, &pllr); if (!(pllr & CKGR_PLLR_DIV)) break; /* 0 Hz */ at91sam7_info->mck_valid = 1; mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff); /* Integer arithmetic should have sufficient precision * as long as PLL is properly configured. */ tmp = mainfreq / (pllr & CKGR_PLLR_DIV)* (((pllr & CKGR_PLLR_MUL) >> 16) + 1); } else if ((at91sam7_info->ext_freq != 0) && ((pllr&CKGR_PLLR_DIV) != 0)) { at91sam7_info->mck_valid = 1; tmp = at91sam7_info->ext_freq / (pllr&CKGR_PLLR_DIV)* (((pllr & CKGR_PLLR_MUL) >> 16) + 1); } break; } /* Prescaler adjust */ if ((((mckr & PMC_MCKR_PRES) >> 2) == 7) || (tmp == 0)) { at91sam7_info->mck_valid = 0; at91sam7_info->mck_freq = 0; } else if (((mckr & PMC_MCKR_PRES) >> 2) != 0) at91sam7_info->mck_freq = tmp >> ((mckr & PMC_MCKR_PRES) >> 2); else at91sam7_info->mck_freq = tmp; } /* Setup the timing registers for nvbits or normal flash */ static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode) { uint32_t fmr, fmcn = 0, fws = 0; struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; struct target *target = bank->target; if (mode && (mode != at91sam7_info->flashmode)) { /* Always round up (ceil) */ if (mode == FMR_TIMING_NVBITS) { if (at91sam7_info->cidr_arch == 0x60) { /* AT91SAM7A3 uses master clocks in 100 ns */ fmcn = (at91sam7_info->mck_freq/10000000ul) + 1; } else { /* master clocks in 1uS for ARCH 0x7 types */ fmcn = (at91sam7_info->mck_freq/1000000ul) + 1; } } else if (mode == FMR_TIMING_FLASH) { /* main clocks in 1.5uS */ fmcn = (at91sam7_info->mck_freq/1000000ul)+ (at91sam7_info->mck_freq/2000000ul) + 1; } /* hard overclocking */ if (fmcn > 0xFF) fmcn = 0xFF; /* Only allow fmcn = 0 if clock period is > 30 us = 33kHz. */ if (at91sam7_info->mck_freq <= 33333ul) fmcn = 0; /* Only allow fws = 0 if clock frequency is < 30 MHz. */ if (at91sam7_info->mck_freq > 30000000ul) fws = 1; LOG_DEBUG("fmcn[%i]: %i", bank->bank_number, (int)(fmcn)); fmr = fmcn << 16 | fws << 8; target_write_u32(target, mc_fmr[bank->bank_number], fmr); } at91sam7_info->flashmode = mode; } static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout) { uint32_t status; while ((!((status = at91sam7_get_flash_status(bank->target, bank->bank_number)) & waitbits)) && (timeout-- > 0)) { LOG_DEBUG("status[%i]: 0x%" PRIx32 "", (int)bank->bank_number, status); alive_sleep(1); } LOG_DEBUG("status[%i]: 0x%" PRIx32 "", bank->bank_number, status); if (status & 0x0C) { LOG_ERROR("status register: 0x%" PRIx32 "", status); if (status & 0x4) LOG_ERROR("Lock Error Bit Detected, Operation Abort"); if (status & 0x8) LOG_ERROR("Invalid command and/or bad keyword, Operation Abort"); if (status & 0x10) LOG_ERROR("Security Bit Set, Operation Abort"); } return status; } /* Send one command to the AT91SAM flash controller */ static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen) { uint32_t fcr; struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; struct target *target = bank->target; fcr = (0x5A << 24) | ((pagen&0x3FF) << 8) | cmd; target_write_u32(target, mc_fcr[bank->bank_number], fcr); LOG_DEBUG("Flash command: 0x%" PRIx32 ", flash bank: %i, page number: %u", fcr, bank->bank_number + 1, pagen); if ((at91sam7_info->cidr_arch == 0x60) && ((cmd == SLB) | (cmd == CLB))) { /* Lock bit manipulation on AT91SAM7A3 waits for FC_FSR bit 1, EOL */ if (at91sam7_wait_status_busy(bank, MC_FSR_EOL, 10)&0x0C) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } if (at91sam7_wait_status_busy(bank, MC_FSR_FRDY, 10)&0x0C) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } /* Read device id register, main clock frequency register and fill in driver info structure */ static int at91sam7_read_part_info(struct flash_bank *bank) { struct at91sam7_flash_bank *at91sam7_info; struct target *target = bank->target; uint16_t bnk, sec; uint16_t arch; uint32_t cidr; uint8_t banks_num = 0; uint16_t num_nvmbits = 0; uint16_t sectors_num = 0; uint16_t pages_per_sector = 0; uint16_t page_size = 0; uint32_t ext_freq; uint32_t bank_size; uint32_t base_address = 0; char *target_name_t = "Unknown"; at91sam7_info = bank->driver_priv; if (at91sam7_info->cidr != 0) { /* flash already configured, update clock and check for protected sectors */ for (struct flash_bank *t_bank = bank; t_bank; t_bank = t_bank->next) { if (t_bank->target != target) continue; /* re-calculate master clock frequency */ at91sam7_read_clock_info(t_bank); /* no timing */ at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE); /* check protect state */ at91sam7_protect_check(t_bank); } return ERROR_OK; } /* Read and parse chip identification register */ target_read_u32(target, DBGU_CIDR, &cidr); if (cidr == 0) { LOG_WARNING("Cannot identify target as an AT91SAM"); return ERROR_FLASH_OPERATION_FAILED; } if (at91sam7_info->flash_autodetection == 0) { /* banks and sectors are already created, based on data from input file */ for (struct flash_bank *t_bank = bank; t_bank; t_bank = t_bank->next) { if (t_bank->target != target) continue; at91sam7_info = t_bank->driver_priv; at91sam7_info->cidr = cidr; at91sam7_info->cidr_ext = (cidr >> 31)&0x0001; at91sam7_info->cidr_nvptyp = (cidr >> 28)&0x0007; at91sam7_info->cidr_arch = (cidr >> 20)&0x00FF; at91sam7_info->cidr_sramsiz = (cidr >> 16)&0x000F; at91sam7_info->cidr_nvpsiz2 = (cidr >> 12)&0x000F; at91sam7_info->cidr_nvpsiz = (cidr >> 8)&0x000F; at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007; at91sam7_info->cidr_version = cidr&0x001F; /* calculate master clock frequency */ at91sam7_read_clock_info(t_bank); /* no timing */ at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE); /* check protect state */ at91sam7_protect_check(t_bank); } return ERROR_OK; } arch = (cidr >> 20)&0x00FF; /* check flash size */ switch ((cidr >> 8)&0x000F) { case FLASH_SIZE_8KB: break; case FLASH_SIZE_16KB: banks_num = 1; sectors_num = 8; pages_per_sector = 32; page_size = 64; base_address = 0x00100000; if (arch == 0x70) { num_nvmbits = 2; target_name_t = "AT91SAM7S161/16"; } break; case FLASH_SIZE_32KB: banks_num = 1; sectors_num = 8; pages_per_sector = 32; page_size = 128; base_address = 0x00100000; if (arch == 0x70) { num_nvmbits = 2; target_name_t = "AT91SAM7S321/32"; } if (arch == 0x72) { num_nvmbits = 3; target_name_t = "AT91SAM7SE32"; } break; case FLASH_SIZE_64KB: banks_num = 1; sectors_num = 16; pages_per_sector = 32; page_size = 128; base_address = 0x00100000; if (arch == 0x70) { num_nvmbits = 2; target_name_t = "AT91SAM7S64"; } break; case FLASH_SIZE_128KB: banks_num = 1; sectors_num = 8; pages_per_sector = 64; page_size = 256; base_address = 0x00100000; if (arch == 0x70) { num_nvmbits = 2; target_name_t = "AT91SAM7S128"; } if (arch == 0x71) { num_nvmbits = 3; target_name_t = "AT91SAM7XC128"; } if (arch == 0x72) { num_nvmbits = 3; target_name_t = "AT91SAM7SE128"; } if (arch == 0x75) { num_nvmbits = 3; target_name_t = "AT91SAM7X128"; } break; case FLASH_SIZE_256KB: banks_num = 1; sectors_num = 16; pages_per_sector = 64; page_size = 256; base_address = 0x00100000; if (arch == 0x60) { num_nvmbits = 3; target_name_t = "AT91SAM7A3"; } if (arch == 0x70) { num_nvmbits = 2; target_name_t = "AT91SAM7S256"; } if (arch == 0x71) { num_nvmbits = 3; target_name_t = "AT91SAM7XC256"; } if (arch == 0x72) { num_nvmbits = 3; target_name_t = "AT91SAM7SE256"; } if (arch == 0x75) { num_nvmbits = 3; target_name_t = "AT91SAM7X256"; } break; case FLASH_SIZE_512KB: banks_num = 2; sectors_num = 16; pages_per_sector = 64; page_size = 256; base_address = 0x00100000; if (arch == 0x70) { num_nvmbits = 2; target_name_t = "AT91SAM7S512"; } if (arch == 0x71) { num_nvmbits = 3; target_name_t = "AT91SAM7XC512"; } if (arch == 0x72) { num_nvmbits = 3; target_name_t = "AT91SAM7SE512"; } if (arch == 0x75) { num_nvmbits = 3; target_name_t = "AT91SAM7X512"; } break; case FLASH_SIZE_1024KB: break; case FLASH_SIZE_2048KB: break; } if (strcmp(target_name_t, "Unknown") == 0) { LOG_ERROR( "Target autodetection failed! Please specify target parameters in configuration file"); return ERROR_FLASH_OPERATION_FAILED; } ext_freq = at91sam7_info->ext_freq; /* calculate bank size */ bank_size = sectors_num * pages_per_sector * page_size; for (bnk = 0; bnk < banks_num; bnk++) { struct flash_bank *t_bank = bank; if (bnk > 0) { if (!t_bank->next) { /* create a new flash bank element */ struct flash_bank *fb = malloc(sizeof(struct flash_bank)); fb->target = target; fb->driver = bank->driver; fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank)); fb->name = "sam7_probed"; fb->next = NULL; /* link created bank in 'flash_banks' list */ t_bank->next = fb; } t_bank = t_bank->next; } t_bank->bank_number = bnk; t_bank->base = base_address + bnk * bank_size; t_bank->size = bank_size; t_bank->num_sectors = sectors_num; /* allocate sectors */ t_bank->sectors = malloc(sectors_num * sizeof(struct flash_sector)); for (sec = 0; sec < sectors_num; sec++) { t_bank->sectors[sec].offset = sec * pages_per_sector * page_size; t_bank->sectors[sec].size = pages_per_sector * page_size; t_bank->sectors[sec].is_erased = -1; t_bank->sectors[sec].is_protected = -1; } at91sam7_info = t_bank->driver_priv; at91sam7_info->cidr = cidr; at91sam7_info->cidr_ext = (cidr >> 31)&0x0001; at91sam7_info->cidr_nvptyp = (cidr >> 28)&0x0007; at91sam7_info->cidr_arch = (cidr >> 20)&0x00FF; at91sam7_info->cidr_sramsiz = (cidr >> 16)&0x000F; at91sam7_info->cidr_nvpsiz2 = (cidr >> 12)&0x000F; at91sam7_info->cidr_nvpsiz = (cidr >> 8)&0x000F; at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007; at91sam7_info->cidr_version = cidr&0x001F; at91sam7_info->target_name = target_name_t; at91sam7_info->flashmode = 0; at91sam7_info->ext_freq = ext_freq; at91sam7_info->num_nvmbits = num_nvmbits; at91sam7_info->num_nvmbits_on = 0; at91sam7_info->pagesize = page_size; at91sam7_info->pages_per_sector = pages_per_sector; /* calculate master clock frequency */ at91sam7_read_clock_info(t_bank); /* no timing */ at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE); /* check protect state */ at91sam7_protect_check(t_bank); } LOG_DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x", at91sam7_info->cidr_nvptyp, at91sam7_info->cidr_arch); return ERROR_OK; } static int at91sam7_erase_check(struct flash_bank *bank) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Configure the flash controller timing */ at91sam7_read_clock_info(bank); at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH); return default_flash_blank_check(bank); } static int at91sam7_protect_check(struct flash_bank *bank) { uint8_t lock_pos, gpnvm_pos; uint32_t status; struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; if (at91sam7_info->cidr == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } status = at91sam7_get_flash_status(bank->target, bank->bank_number); at91sam7_info->lockbits = (status >> 16); at91sam7_info->num_lockbits_on = 0; for (lock_pos = 0; lock_pos < bank->num_sectors; lock_pos++) { if (((status >> (16 + lock_pos))&(0x0001)) == 1) { at91sam7_info->num_lockbits_on++; bank->sectors[lock_pos].is_protected = 1; } else bank->sectors[lock_pos].is_protected = 0; } /* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */ status = at91sam7_get_flash_status(bank->target, 0); at91sam7_info->securitybit = (status >> 4)&0x01; at91sam7_info->nvmbits = (status >> 8)&0xFF; at91sam7_info->num_nvmbits_on = 0; for (gpnvm_pos = 0; gpnvm_pos < at91sam7_info->num_nvmbits; gpnvm_pos++) { if (((status >> (8 + gpnvm_pos))&(0x01)) == 1) at91sam7_info->num_nvmbits_on++; } return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command) { struct flash_bank *t_bank = bank; struct at91sam7_flash_bank *at91sam7_info; struct target *target = t_bank->target; uint32_t base_address; uint32_t bank_size; uint32_t ext_freq = 0; unsigned int banks_num; unsigned int num_sectors; uint16_t pages_per_sector; uint16_t page_size; uint16_t num_nvmbits; at91sam7_info = malloc(sizeof(struct at91sam7_flash_bank)); t_bank->driver_priv = at91sam7_info; /* part wasn't probed for info yet */ at91sam7_info->cidr = 0; at91sam7_info->flashmode = 0; at91sam7_info->ext_freq = 0; at91sam7_info->flash_autodetection = 0; if (CMD_ARGC < 13) { at91sam7_info->flash_autodetection = 1; return ERROR_OK; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], base_address); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[8], banks_num); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[9], num_sectors); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[10], pages_per_sector); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[11], page_size); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[12], num_nvmbits); if (CMD_ARGC == 14) { unsigned long freq; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[13], freq); ext_freq = freq * 1000; at91sam7_info->ext_freq = ext_freq; } if ((banks_num == 0) || (num_sectors == 0) || (pages_per_sector == 0) || (page_size == 0) || (num_nvmbits == 0)) { at91sam7_info->flash_autodetection = 1; return ERROR_OK; } /* calculate bank size */ bank_size = num_sectors * pages_per_sector * page_size; for (unsigned int bnk = 0; bnk < banks_num; bnk++) { if (bnk > 0) { if (!t_bank->next) { /* create a new bank element */ struct flash_bank *fb = malloc(sizeof(struct flash_bank)); fb->target = target; fb->driver = bank->driver; fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank)); fb->name = "sam7_probed"; fb->next = NULL; /* link created bank in 'flash_banks' list */ t_bank->next = fb; } t_bank = t_bank->next; } t_bank->bank_number = bnk; t_bank->base = base_address + bnk * bank_size; t_bank->size = bank_size; t_bank->num_sectors = num_sectors; /* allocate sectors */ t_bank->sectors = malloc(num_sectors * sizeof(struct flash_sector)); for (unsigned int sec = 0; sec < num_sectors; sec++) { t_bank->sectors[sec].offset = sec * pages_per_sector * page_size; t_bank->sectors[sec].size = pages_per_sector * page_size; t_bank->sectors[sec].is_erased = -1; t_bank->sectors[sec].is_protected = -1; } at91sam7_info = t_bank->driver_priv; at91sam7_info->target_name = strdup(CMD_ARGV[7]); at91sam7_info->flashmode = 0; at91sam7_info->ext_freq = ext_freq; at91sam7_info->num_nvmbits = num_nvmbits; at91sam7_info->num_nvmbits_on = 0; at91sam7_info->pagesize = page_size; at91sam7_info->pages_per_sector = pages_per_sector; } return ERROR_OK; } static int at91sam7_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; uint32_t nbytes, pos; uint8_t *buffer; uint8_t erase_all; if (at91sam7_info->cidr == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((last < first) || (last >= bank->num_sectors)) return ERROR_FLASH_SECTOR_INVALID; erase_all = 0; if ((first == 0) && (last == (bank->num_sectors-1))) erase_all = 1; /* Configure the flash controller timing */ at91sam7_read_clock_info(bank); at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH); if (erase_all) { if (at91sam7_flash_command(bank, EA, 0) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; } else { /* allocate and clean buffer */ nbytes = (last - first + 1) * bank->sectors[first].size; buffer = malloc(nbytes * sizeof(uint8_t)); for (pos = 0; pos < nbytes; pos++) buffer[pos] = 0xFF; if (at91sam7_write(bank, buffer, bank->sectors[first].offset, nbytes) != ERROR_OK) { free(buffer); return ERROR_FLASH_OPERATION_FAILED; } free(buffer); } /* mark erased sectors */ for (unsigned int sec = first; sec <= last; sec++) bank->sectors[sec].is_erased = 1; return ERROR_OK; } static int at91sam7_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { uint32_t cmd; uint32_t pagen; struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; if (at91sam7_info->cidr == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((last < first) || (last >= bank->num_sectors)) return ERROR_FLASH_SECTOR_INVALID; /* Configure the flash controller timing */ at91sam7_read_clock_info(bank); at91sam7_set_flash_mode(bank, FMR_TIMING_NVBITS); for (unsigned int sector = first; sector <= last; sector++) { if (set) cmd = SLB; else cmd = CLB; /* if we lock a page from one sector then entire sector will be locked, also, * if we unlock a page from a locked sector, entire sector will be unlocked */ pagen = sector * at91sam7_info->pages_per_sector; if (at91sam7_flash_command(bank, cmd, pagen) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; } at91sam7_protect_check(bank); return ERROR_OK; } static int at91sam7_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; struct target *target = bank->target; uint32_t dst_min_alignment, wcount, bytes_remaining = count; uint32_t first_page, last_page, pagen, buffer_pos; if (at91sam7_info->cidr == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; dst_min_alignment = at91sam7_info->pagesize; if (offset % dst_min_alignment) { LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", offset, dst_min_alignment); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } if (at91sam7_info->cidr_arch == 0) return ERROR_FLASH_BANK_NOT_PROBED; first_page = offset/dst_min_alignment; last_page = DIV_ROUND_UP(offset + count, dst_min_alignment); LOG_DEBUG("first_page: %i, last_page: %i, count %i", (int)first_page, (int)last_page, (int)count); /* Configure the flash controller timing */ at91sam7_read_clock_info(bank); at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH); for (pagen = first_page; pagen < last_page; pagen++) { if (bytes_remaining < dst_min_alignment) count = bytes_remaining; else count = dst_min_alignment; bytes_remaining -= count; /* Write one block to the PageWriteBuffer */ buffer_pos = (pagen-first_page)*dst_min_alignment; wcount = DIV_ROUND_UP(count, 4); retval = target_write_memory(target, bank->base + pagen*dst_min_alignment, 4, wcount, buffer + buffer_pos); if (retval != ERROR_OK) return retval; /* Send Write Page command to Flash Controller */ if (at91sam7_flash_command(bank, WP, pagen) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; LOG_DEBUG("Write flash bank:%u page number:%" PRIu32, bank->bank_number, pagen); } return ERROR_OK; } static int at91sam7_probe(struct flash_bank *bank) { /* we can't probe on an at91sam7 * if this is an at91sam7, it has the configured flash */ int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = at91sam7_read_part_info(bank); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int get_at91sam7_info(struct flash_bank *bank, struct command_invocation *cmd) { struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; if (at91sam7_info->cidr == 0) return ERROR_FLASH_BANK_NOT_PROBED; command_print_sameline(cmd, "\n at91sam7 driver information: Chip is %s\n", at91sam7_info->target_name); command_print_sameline(cmd, " Cidr: 0x%8.8" PRIx32 " | Arch: 0x%4.4x | Eproc: %s | Version: 0x%3.3x | " "Flashsize: 0x%8.8" PRIx32 "\n", at91sam7_info->cidr, at91sam7_info->cidr_arch, eproc[at91sam7_info->cidr_eproc], at91sam7_info->cidr_version, bank->size); command_print_sameline(cmd, " Master clock (estimated): %u kHz | External clock: %u kHz\n", (unsigned)(at91sam7_info->mck_freq / 1000), (unsigned)(at91sam7_info->ext_freq / 1000)); command_print_sameline(cmd, " Pagesize: %i bytes | Lockbits(%u): %i 0x%4.4x | Pages in lock region: %i\n", at91sam7_info->pagesize, bank->num_sectors, at91sam7_info->num_lockbits_on, at91sam7_info->lockbits, at91sam7_info->pages_per_sector * at91sam7_info->num_lockbits_on); command_print_sameline(cmd, " Securitybit: %i | Nvmbits(%i): %i 0x%1.1x\n", at91sam7_info->securitybit, at91sam7_info->num_nvmbits, at91sam7_info->num_nvmbits_on, at91sam7_info->nvmbits); return ERROR_OK; } /* * On AT91SAM7S: When the gpnvm bits are set with * > at91sam7 gpnvm bitnr set * the changes are not visible in the flash controller status register MC_FSR * until the processor has been reset. * On the Olimex board this requires a power cycle. * Note that the AT91SAM7S has the following errata (doc6175.pdf sec 14.1.3): * The maximum number of write/erase cycles for Non volatile Memory bits is 100. this includes * Lock Bits (LOCKx), General Purpose NVM bits (GPNVMx) and the Security Bit. */ COMMAND_HANDLER(at91sam7_handle_gpnvm_command) { struct flash_bank *bank; int bit; uint8_t flashcmd; uint32_t status; struct at91sam7_flash_bank *at91sam7_info; int retval; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; bank = get_flash_bank_by_num_noprobe(0); if (!bank) return ERROR_FLASH_BANK_INVALID; if (strcmp(bank->driver->name, "at91sam7")) { command_print(CMD, "not an at91sam7 flash bank '%s'", CMD_ARGV[0]); return ERROR_FLASH_BANK_INVALID; } if (bank->target->state != TARGET_HALTED) { LOG_ERROR("target has to be halted to perform flash operation"); return ERROR_TARGET_NOT_HALTED; } if (strcmp(CMD_ARGV[1], "set") == 0) flashcmd = SGPB; else if (strcmp(CMD_ARGV[1], "clear") == 0) flashcmd = CGPB; else return ERROR_COMMAND_SYNTAX_ERROR; at91sam7_info = bank->driver_priv; if (at91sam7_info->cidr == 0) { retval = at91sam7_read_part_info(bank); if (retval != ERROR_OK) return retval; } COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], bit); if ((bit < 0) || (bit >= at91sam7_info->num_nvmbits)) { command_print(CMD, "gpnvm bit '#%s' is out of bounds for target %s", CMD_ARGV[0], at91sam7_info->target_name); return ERROR_OK; } /* Configure the flash controller timing */ at91sam7_read_clock_info(bank); at91sam7_set_flash_mode(bank, FMR_TIMING_NVBITS); if (at91sam7_flash_command(bank, flashcmd, bit) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; /* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */ status = at91sam7_get_flash_status(bank->target, 0); LOG_DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value %d, status 0x%" PRIx32, flashcmd, bit, status); /* check protect state */ at91sam7_protect_check(bank); return ERROR_OK; } static const struct command_registration at91sam7_exec_command_handlers[] = { { .name = "gpnvm", .handler = at91sam7_handle_gpnvm_command, .mode = COMMAND_EXEC, .help = "set or clear one General Purpose Non-Volatile Memory " "(gpnvm) bit", .usage = "bitnum ('set'|'clear')", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration at91sam7_command_handlers[] = { { .name = "at91sam7", .mode = COMMAND_ANY, .help = "at91sam7 flash command group", .usage = "", .chain = at91sam7_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver at91sam7_flash = { .name = "at91sam7", .usage = "gpnvm <bit> <set | clear>", .commands = at91sam7_command_handlers, .flash_bank_command = at91sam7_flash_bank_command, .erase = at91sam7_erase, .protect = at91sam7_protect, .write = at91sam7_write, .read = default_flash_read, .probe = at91sam7_probe, .auto_probe = at91sam7_probe, .erase_check = at91sam7_erase_check, .protect_check = at91sam7_protect_check, .info = get_at91sam7_info, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/at91samd.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013 by Andrey Yurovsky * * Andrey Yurovsky <yurovsky@gmail.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "helper/binarybuffer.h" #include <helper/time_support.h> #include <jtag/jtag.h> #include <target/cortex_m.h> #define SAMD_NUM_PROT_BLOCKS 16 #define SAMD_PAGE_SIZE_MAX 1024 #define SAMD_FLASH ((uint32_t)0x00000000) /* physical Flash memory */ #define SAMD_USER_ROW ((uint32_t)0x00804000) /* User Row of Flash */ #define SAMD_PAC1 0x41000000 /* Peripheral Access Control 1 */ #define SAMD_DSU 0x41002000 /* Device Service Unit */ #define SAMD_NVMCTRL 0x41004000 /* Non-volatile memory controller */ #define SAMD_DSU_STATUSA 1 /* DSU status register */ #define SAMD_DSU_DID 0x18 /* Device ID register */ #define SAMD_DSU_CTRL_EXT 0x100 /* CTRL register, external access */ #define SAMD_NVMCTRL_CTRLA 0x00 /* NVM control A register */ #define SAMD_NVMCTRL_CTRLB 0x04 /* NVM control B register */ #define SAMD_NVMCTRL_PARAM 0x08 /* NVM parameters register */ #define SAMD_NVMCTRL_INTFLAG 0x14 /* NVM Interrupt Flag Status & Clear */ #define SAMD_NVMCTRL_STATUS 0x18 /* NVM status register */ #define SAMD_NVMCTRL_ADDR 0x1C /* NVM address register */ #define SAMD_NVMCTRL_LOCK 0x20 /* NVM Lock section register */ #define SAMD_CMDEX_KEY 0xA5UL #define SAMD_NVM_CMD(n) ((SAMD_CMDEX_KEY << 8) | (n & 0x7F)) /* NVMCTRL commands. See Table 20-4 in 42129F–SAM–10/2013 */ #define SAMD_NVM_CMD_ER 0x02 /* Erase Row */ #define SAMD_NVM_CMD_WP 0x04 /* Write Page */ #define SAMD_NVM_CMD_EAR 0x05 /* Erase Auxiliary Row */ #define SAMD_NVM_CMD_WAP 0x06 /* Write Auxiliary Page */ #define SAMD_NVM_CMD_LR 0x40 /* Lock Region */ #define SAMD_NVM_CMD_UR 0x41 /* Unlock Region */ #define SAMD_NVM_CMD_SPRM 0x42 /* Set Power Reduction Mode */ #define SAMD_NVM_CMD_CPRM 0x43 /* Clear Power Reduction Mode */ #define SAMD_NVM_CMD_PBC 0x44 /* Page Buffer Clear */ #define SAMD_NVM_CMD_SSB 0x45 /* Set Security Bit */ #define SAMD_NVM_CMD_INVALL 0x46 /* Invalidate all caches */ /* NVMCTRL bits */ #define SAMD_NVM_CTRLB_MANW 0x80 /* NVMCTRL_INTFLAG bits */ #define SAMD_NVM_INTFLAG_READY 0x01 /* Known identifiers */ #define SAMD_PROCESSOR_M0 0x01 #define SAMD_FAMILY_D 0x00 #define SAMD_FAMILY_L 0x01 #define SAMD_FAMILY_C 0x02 #define SAMD_SERIES_20 0x00 #define SAMD_SERIES_21 0x01 #define SAMD_SERIES_22 0x02 #define SAMD_SERIES_10 0x02 #define SAMD_SERIES_11 0x03 #define SAMD_SERIES_09 0x04 /* Device ID macros */ #define SAMD_GET_PROCESSOR(id) (id >> 28) #define SAMD_GET_FAMILY(id) (((id >> 23) & 0x1F)) #define SAMD_GET_SERIES(id) (((id >> 16) & 0x3F)) #define SAMD_GET_DEVSEL(id) (id & 0xFF) /* Bits to mask out lockbits in user row */ #define NVMUSERROW_LOCKBIT_MASK 0x0000FFFFFFFFFFFFULL struct samd_part { uint8_t id; const char *name; uint32_t flash_kb; uint32_t ram_kb; }; /* Known SAMD09 parts. DID reset values missing in RM, see * https://github.com/avrxml/asf/blob/master/sam0/utils/cmsis/samd09/include/ */ static const struct samd_part samd09_parts[] = { { 0x0, "SAMD09D14A", 16, 4 }, { 0x7, "SAMD09C13A", 8, 4 }, }; /* Known SAMD10 parts */ static const struct samd_part samd10_parts[] = { { 0x0, "SAMD10D14AMU", 16, 4 }, { 0x1, "SAMD10D13AMU", 8, 4 }, { 0x2, "SAMD10D12AMU", 4, 4 }, { 0x3, "SAMD10D14ASU", 16, 4 }, { 0x4, "SAMD10D13ASU", 8, 4 }, { 0x5, "SAMD10D12ASU", 4, 4 }, { 0x6, "SAMD10C14A", 16, 4 }, { 0x7, "SAMD10C13A", 8, 4 }, { 0x8, "SAMD10C12A", 4, 4 }, }; /* Known SAMD11 parts */ static const struct samd_part samd11_parts[] = { { 0x0, "SAMD11D14AM", 16, 4 }, { 0x1, "SAMD11D13AMU", 8, 4 }, { 0x2, "SAMD11D12AMU", 4, 4 }, { 0x3, "SAMD11D14ASS", 16, 4 }, { 0x4, "SAMD11D13ASU", 8, 4 }, { 0x5, "SAMD11D12ASU", 4, 4 }, { 0x6, "SAMD11C14A", 16, 4 }, { 0x7, "SAMD11C13A", 8, 4 }, { 0x8, "SAMD11C12A", 4, 4 }, { 0x9, "SAMD11D14AU", 16, 4 }, }; /* Known SAMD20 parts. See Table 12-8 in 42129F–SAM–10/2013 */ static const struct samd_part samd20_parts[] = { { 0x0, "SAMD20J18A", 256, 32 }, { 0x1, "SAMD20J17A", 128, 16 }, { 0x2, "SAMD20J16A", 64, 8 }, { 0x3, "SAMD20J15A", 32, 4 }, { 0x4, "SAMD20J14A", 16, 2 }, { 0x5, "SAMD20G18A", 256, 32 }, { 0x6, "SAMD20G17A", 128, 16 }, { 0x7, "SAMD20G16A", 64, 8 }, { 0x8, "SAMD20G15A", 32, 4 }, { 0x9, "SAMD20G14A", 16, 2 }, { 0xA, "SAMD20E18A", 256, 32 }, { 0xB, "SAMD20E17A", 128, 16 }, { 0xC, "SAMD20E16A", 64, 8 }, { 0xD, "SAMD20E15A", 32, 4 }, { 0xE, "SAMD20E14A", 16, 2 }, }; /* Known SAMD21 parts. */ static const struct samd_part samd21_parts[] = { { 0x0, "SAMD21J18A", 256, 32 }, { 0x1, "SAMD21J17A", 128, 16 }, { 0x2, "SAMD21J16A", 64, 8 }, { 0x3, "SAMD21J15A", 32, 4 }, { 0x4, "SAMD21J14A", 16, 2 }, { 0x5, "SAMD21G18A", 256, 32 }, { 0x6, "SAMD21G17A", 128, 16 }, { 0x7, "SAMD21G16A", 64, 8 }, { 0x8, "SAMD21G15A", 32, 4 }, { 0x9, "SAMD21G14A", 16, 2 }, { 0xA, "SAMD21E18A", 256, 32 }, { 0xB, "SAMD21E17A", 128, 16 }, { 0xC, "SAMD21E16A", 64, 8 }, { 0xD, "SAMD21E15A", 32, 4 }, { 0xE, "SAMD21E14A", 16, 2 }, /* SAMR21 parts have integrated SAMD21 with a radio */ { 0x18, "SAMR21G19A", 256, 32 }, /* with 512k of serial flash */ { 0x19, "SAMR21G18A", 256, 32 }, { 0x1A, "SAMR21G17A", 128, 32 }, { 0x1B, "SAMR21G16A", 64, 16 }, { 0x1C, "SAMR21E18A", 256, 32 }, { 0x1D, "SAMR21E17A", 128, 32 }, { 0x1E, "SAMR21E16A", 64, 16 }, /* SAMD21 B Variants (Table 3-7 from rev I of datasheet) */ { 0x20, "SAMD21J16B", 64, 8 }, { 0x21, "SAMD21J15B", 32, 4 }, { 0x23, "SAMD21G16B", 64, 8 }, { 0x24, "SAMD21G15B", 32, 4 }, { 0x26, "SAMD21E16B", 64, 8 }, { 0x27, "SAMD21E15B", 32, 4 }, /* SAMD21 D and L Variants (from Errata) http://ww1.microchip.com/downloads/en/DeviceDoc/ SAM-D21-Family-Silicon-Errata-and-DataSheet-Clarification-DS80000760D.pdf */ { 0x55, "SAMD21E16BU", 64, 8 }, { 0x56, "SAMD21E15BU", 32, 4 }, { 0x57, "SAMD21G16L", 64, 8 }, { 0x3E, "SAMD21E16L", 64, 8 }, { 0x3F, "SAMD21E15L", 32, 4 }, { 0x62, "SAMD21E16CU", 64, 8 }, { 0x63, "SAMD21E15CU", 32, 4 }, { 0x92, "SAMD21J17D", 128, 16 }, { 0x93, "SAMD21G17D", 128, 16 }, { 0x94, "SAMD21E17D", 128, 16 }, { 0x95, "SAMD21E17DU", 128, 16 }, { 0x96, "SAMD21G17L", 128, 16 }, { 0x97, "SAMD21E17L", 128, 16 }, /* Known SAMDA1 parts. SAMD-A1 series uses the same series identifier like the SAMD21 taken from http://ww1.microchip.com/downloads/en/DeviceDoc/40001895A.pdf (pages 14-17) */ { 0x29, "SAMDA1J16A", 64, 8 }, { 0x2A, "SAMDA1J15A", 32, 4 }, { 0x2B, "SAMDA1J14A", 16, 4 }, { 0x2C, "SAMDA1G16A", 64, 8 }, { 0x2D, "SAMDA1G15A", 32, 4 }, { 0x2E, "SAMDA1G14A", 16, 4 }, { 0x2F, "SAMDA1E16A", 64, 8 }, { 0x30, "SAMDA1E15A", 32, 4 }, { 0x31, "SAMDA1E14A", 16, 4 }, { 0x64, "SAMDA1J16B", 64, 8 }, { 0x65, "SAMDA1J15B", 32, 4 }, { 0x66, "SAMDA1J14B", 16, 4 }, { 0x67, "SAMDA1G16B", 64, 8 }, { 0x68, "SAMDA1G15B", 32, 4 }, { 0x69, "SAMDA1G14B", 16, 4 }, { 0x6A, "SAMDA1E16B", 64, 8 }, { 0x6B, "SAMDA1E15B", 32, 4 }, { 0x6C, "SAMDA1E14B", 16, 4 }, }; /* Known SAML21 parts. */ static const struct samd_part saml21_parts[] = { { 0x00, "SAML21J18A", 256, 32 }, { 0x01, "SAML21J17A", 128, 16 }, { 0x02, "SAML21J16A", 64, 8 }, { 0x05, "SAML21G18A", 256, 32 }, { 0x06, "SAML21G17A", 128, 16 }, { 0x07, "SAML21G16A", 64, 8 }, { 0x0A, "SAML21E18A", 256, 32 }, { 0x0B, "SAML21E17A", 128, 16 }, { 0x0C, "SAML21E16A", 64, 8 }, { 0x0D, "SAML21E15A", 32, 4 }, { 0x0F, "SAML21J18B", 256, 32 }, { 0x10, "SAML21J17B", 128, 16 }, { 0x11, "SAML21J16B", 64, 8 }, { 0x14, "SAML21G18B", 256, 32 }, { 0x15, "SAML21G17B", 128, 16 }, { 0x16, "SAML21G16B", 64, 8 }, { 0x19, "SAML21E18B", 256, 32 }, { 0x1A, "SAML21E17B", 128, 16 }, { 0x1B, "SAML21E16B", 64, 8 }, { 0x1C, "SAML21E15B", 32, 4 }, /* SAMR30 parts have integrated SAML21 with a radio */ { 0x1E, "SAMR30G18A", 256, 32 }, { 0x1F, "SAMR30E18A", 256, 32 }, /* SAMR34/R35 parts have integrated SAML21 with a lora radio */ { 0x28, "SAMR34J18", 256, 40 }, { 0x29, "SAMR34J17", 128, 24 }, { 0x2A, "SAMR34J16", 64, 12 }, { 0x2B, "SAMR35J18", 256, 40 }, { 0x2C, "SAMR35J17", 128, 24 }, { 0x2D, "SAMR35J16", 64, 12 }, }; /* Known SAML22 parts. */ static const struct samd_part saml22_parts[] = { { 0x00, "SAML22N18A", 256, 32 }, { 0x01, "SAML22N17A", 128, 16 }, { 0x02, "SAML22N16A", 64, 8 }, { 0x05, "SAML22J18A", 256, 32 }, { 0x06, "SAML22J17A", 128, 16 }, { 0x07, "SAML22J16A", 64, 8 }, { 0x0A, "SAML22G18A", 256, 32 }, { 0x0B, "SAML22G17A", 128, 16 }, { 0x0C, "SAML22G16A", 64, 8 }, }; /* Known SAMC20 parts. */ static const struct samd_part samc20_parts[] = { { 0x00, "SAMC20J18A", 256, 32 }, { 0x01, "SAMC20J17A", 128, 16 }, { 0x02, "SAMC20J16A", 64, 8 }, { 0x03, "SAMC20J15A", 32, 4 }, { 0x05, "SAMC20G18A", 256, 32 }, { 0x06, "SAMC20G17A", 128, 16 }, { 0x07, "SAMC20G16A", 64, 8 }, { 0x08, "SAMC20G15A", 32, 4 }, { 0x0A, "SAMC20E18A", 256, 32 }, { 0x0B, "SAMC20E17A", 128, 16 }, { 0x0C, "SAMC20E16A", 64, 8 }, { 0x0D, "SAMC20E15A", 32, 4 }, { 0x20, "SAMC20N18A", 256, 32 }, { 0x21, "SAMC20N17A", 128, 16 }, }; /* Known SAMC21 parts. */ static const struct samd_part samc21_parts[] = { { 0x00, "SAMC21J18A", 256, 32 }, { 0x01, "SAMC21J17A", 128, 16 }, { 0x02, "SAMC21J16A", 64, 8 }, { 0x03, "SAMC21J15A", 32, 4 }, { 0x05, "SAMC21G18A", 256, 32 }, { 0x06, "SAMC21G17A", 128, 16 }, { 0x07, "SAMC21G16A", 64, 8 }, { 0x08, "SAMC21G15A", 32, 4 }, { 0x0A, "SAMC21E18A", 256, 32 }, { 0x0B, "SAMC21E17A", 128, 16 }, { 0x0C, "SAMC21E16A", 64, 8 }, { 0x0D, "SAMC21E15A", 32, 4 }, { 0x20, "SAMC21N18A", 256, 32 }, { 0x21, "SAMC21N17A", 128, 16 }, }; /* Each family of parts contains a parts table in the DEVSEL field of DID. The * processor ID, family ID, and series ID are used to determine which exact * family this is and then we can use the corresponding table. */ struct samd_family { uint8_t processor; uint8_t family; uint8_t series; const struct samd_part *parts; size_t num_parts; uint64_t nvm_userrow_res_mask; /* protect bits which are reserved, 0 -> protect */ }; /* Known SAMD families */ static const struct samd_family samd_families[] = { { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_20, samd20_parts, ARRAY_SIZE(samd20_parts), 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21, samd21_parts, ARRAY_SIZE(samd21_parts), 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_09, samd09_parts, ARRAY_SIZE(samd09_parts), 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_10, samd10_parts, ARRAY_SIZE(samd10_parts), 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_11, samd11_parts, ARRAY_SIZE(samd11_parts), 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_21, saml21_parts, ARRAY_SIZE(saml21_parts), 0xFFFF03FFFC01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_22, saml22_parts, ARRAY_SIZE(saml22_parts), 0xFFFF03FFFC01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_20, samc20_parts, ARRAY_SIZE(samc20_parts), 0xFFFF03FFFC01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_21, samc21_parts, ARRAY_SIZE(samc21_parts), 0xFFFF03FFFC01FF77ULL }, }; struct samd_info { uint32_t page_size; int num_pages; int sector_size; int prot_block_size; bool probed; struct target *target; }; /** * Gives the family structure to specific device id. * @param id The id of the device. * @return On failure NULL, otherwise a pointer to the structure. */ static const struct samd_family *samd_find_family(uint32_t id) { uint8_t processor = SAMD_GET_PROCESSOR(id); uint8_t family = SAMD_GET_FAMILY(id); uint8_t series = SAMD_GET_SERIES(id); for (unsigned i = 0; i < ARRAY_SIZE(samd_families); i++) { if (samd_families[i].processor == processor && samd_families[i].series == series && samd_families[i].family == family) return &samd_families[i]; } return NULL; } /** * Gives the part structure to specific device id. * @param id The id of the device. * @return On failure NULL, otherwise a pointer to the structure. */ static const struct samd_part *samd_find_part(uint32_t id) { uint8_t devsel = SAMD_GET_DEVSEL(id); const struct samd_family *family = samd_find_family(id); if (!family) return NULL; for (unsigned i = 0; i < family->num_parts; i++) { if (family->parts[i].id == devsel) return &family->parts[i]; } return NULL; } static int samd_protect_check(struct flash_bank *bank) { int res; uint16_t lock; res = target_read_u16(bank->target, SAMD_NVMCTRL + SAMD_NVMCTRL_LOCK, &lock); if (res != ERROR_OK) return res; /* Lock bits are active-low */ for (unsigned int prot_block = 0; prot_block < bank->num_prot_blocks; prot_block++) bank->prot_blocks[prot_block].is_protected = !(lock & (1u<<prot_block)); return ERROR_OK; } static int samd_get_flash_page_info(struct target *target, uint32_t *sizep, int *nump) { int res; uint32_t param; res = target_read_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_PARAM, ¶m); if (res == ERROR_OK) { /* The PSZ field (bits 18:16) indicate the page size bytes as 2^(3+n) * so 0 is 8KB and 7 is 1024KB. */ if (sizep) *sizep = (8 << ((param >> 16) & 0x7)); /* The NVMP field (bits 15:0) indicates the total number of pages */ if (nump) *nump = param & 0xFFFF; } else { LOG_ERROR("Couldn't read NVM Parameters register"); } return res; } static int samd_probe(struct flash_bank *bank) { uint32_t id; int res; struct samd_info *chip = (struct samd_info *)bank->driver_priv; const struct samd_part *part; if (chip->probed) return ERROR_OK; res = target_read_u32(bank->target, SAMD_DSU + SAMD_DSU_DID, &id); if (res != ERROR_OK) { LOG_ERROR("Couldn't read Device ID register"); return res; } part = samd_find_part(id); if (!part) { LOG_ERROR("Couldn't find part corresponding to DID %08" PRIx32, id); return ERROR_FAIL; } bank->size = part->flash_kb * 1024; res = samd_get_flash_page_info(bank->target, &chip->page_size, &chip->num_pages); if (res != ERROR_OK) { LOG_ERROR("Couldn't determine Flash page size"); return res; } /* Sanity check: the total flash size in the DSU should match the page size * multiplied by the number of pages. */ if (bank->size != chip->num_pages * chip->page_size) { LOG_WARNING("SAMD: bank size doesn't match NVM parameters. " "Identified %" PRIu32 "KB Flash but NVMCTRL reports %u %" PRIu32 "B pages", part->flash_kb, chip->num_pages, chip->page_size); } /* Erase granularity = 1 row = 4 pages */ chip->sector_size = chip->page_size * 4; /* Allocate the sector table */ bank->num_sectors = chip->num_pages / 4; bank->sectors = alloc_block_array(0, chip->sector_size, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; /* 16 protection blocks per device */ chip->prot_block_size = bank->size / SAMD_NUM_PROT_BLOCKS; /* Allocate the table of protection blocks */ bank->num_prot_blocks = SAMD_NUM_PROT_BLOCKS; bank->prot_blocks = alloc_block_array(0, chip->prot_block_size, bank->num_prot_blocks); if (!bank->prot_blocks) return ERROR_FAIL; samd_protect_check(bank); /* Done */ chip->probed = true; LOG_INFO("SAMD MCU: %s (%" PRIu32 "KB Flash, %" PRIu32 "KB RAM)", part->name, part->flash_kb, part->ram_kb); return ERROR_OK; } static int samd_check_error(struct target *target) { int ret, ret2; uint8_t intflag; uint16_t status; int timeout_ms = 1000; int64_t ts_start = timeval_ms(); do { ret = target_read_u8(target, SAMD_NVMCTRL + SAMD_NVMCTRL_INTFLAG, &intflag); if (ret != ERROR_OK) { LOG_ERROR("Can't read NVM intflag"); return ret; } if (intflag & SAMD_NVM_INTFLAG_READY) break; keep_alive(); } while (timeval_ms() - ts_start < timeout_ms); if (!(intflag & SAMD_NVM_INTFLAG_READY)) { LOG_ERROR("SAMD: NVM programming timed out"); return ERROR_FLASH_OPERATION_FAILED; } ret = target_read_u16(target, SAMD_NVMCTRL + SAMD_NVMCTRL_STATUS, &status); if (ret != ERROR_OK) { LOG_ERROR("Can't read NVM status"); return ret; } if ((status & 0x001C) == 0) return ERROR_OK; if (status & (1 << 4)) { /* NVME */ LOG_ERROR("SAMD: NVM Error"); ret = ERROR_FLASH_OPERATION_FAILED; } if (status & (1 << 3)) { /* LOCKE */ LOG_ERROR("SAMD: NVM lock error"); ret = ERROR_FLASH_PROTECTED; } if (status & (1 << 2)) { /* PROGE */ LOG_ERROR("SAMD: NVM programming error"); ret = ERROR_FLASH_OPER_UNSUPPORTED; } /* Clear the error conditions by writing a one to them */ ret2 = target_write_u16(target, SAMD_NVMCTRL + SAMD_NVMCTRL_STATUS, status); if (ret2 != ERROR_OK) LOG_ERROR("Can't clear NVM error conditions"); return ret; } static int samd_issue_nvmctrl_command(struct target *target, uint16_t cmd) { int res; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Issue the NVM command */ /* 32-bit write is used to ensure atomic operation on ST-Link */ res = target_write_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLA, SAMD_NVM_CMD(cmd)); if (res != ERROR_OK) return res; /* Check to see if the NVM command resulted in an error condition. */ return samd_check_error(target); } /** * Erases a flash-row at the given address. * @param target Pointer to the target structure. * @param address The address of the row. * @return On success ERROR_OK, on failure an errorcode. */ static int samd_erase_row(struct target *target, uint32_t address) { int res; /* Set an address contained in the row to be erased */ res = target_write_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR, address >> 1); /* Issue the Erase Row command to erase that row. */ if (res == ERROR_OK) res = samd_issue_nvmctrl_command(target, address == SAMD_USER_ROW ? SAMD_NVM_CMD_EAR : SAMD_NVM_CMD_ER); if (res != ERROR_OK) { LOG_ERROR("Failed to erase row containing %08" PRIx32, address); return ERROR_FAIL; } return ERROR_OK; } /** * Returns the bitmask of reserved bits in register. * @param target Pointer to the target structure. * @param mask Bitmask, 0 -> value stays untouched. * @return On success ERROR_OK, on failure an errorcode. */ static int samd_get_reservedmask(struct target *target, uint64_t *mask) { int res; /* Get the devicetype */ uint32_t id; res = target_read_u32(target, SAMD_DSU + SAMD_DSU_DID, &id); if (res != ERROR_OK) { LOG_ERROR("Couldn't read Device ID register"); return res; } const struct samd_family *family; family = samd_find_family(id); if (!family) { LOG_ERROR("Couldn't determine device family"); return ERROR_FAIL; } *mask = family->nvm_userrow_res_mask; return ERROR_OK; } static int read_userrow(struct target *target, uint64_t *userrow) { int res; uint8_t buffer[8]; res = target_read_memory(target, SAMD_USER_ROW, 4, 2, buffer); if (res != ERROR_OK) return res; *userrow = target_buffer_get_u64(target, buffer); return ERROR_OK; } /** * Modify the contents of the User Row in Flash. The User Row itself * has a size of one page and contains a combination of "fuses" and * calibration data. Bits which have a value of zero in the mask will * not be changed. Up to now devices only use the first 64 bits. * @param target Pointer to the target structure. * @param value_input The value to write. * @param value_mask Bitmask, 0 -> value stays untouched. * @return On success ERROR_OK, on failure an errorcode. */ static int samd_modify_user_row_masked(struct target *target, uint64_t value_input, uint64_t value_mask) { int res; uint32_t nvm_ctrlb; bool manual_wp = true; /* Retrieve the MCU's page size, in bytes. This is also the size of the * entire User Row. */ uint32_t page_size; res = samd_get_flash_page_info(target, &page_size, NULL); if (res != ERROR_OK) { LOG_ERROR("Couldn't determine Flash page size"); return res; } /* Make sure the size is sane. */ assert(page_size <= SAMD_PAGE_SIZE_MAX && page_size >= sizeof(value_input)); uint8_t buf[SAMD_PAGE_SIZE_MAX]; /* Read the user row (comprising one page) by words. */ res = target_read_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf); if (res != ERROR_OK) return res; uint64_t value_device; res = read_userrow(target, &value_device); if (res != ERROR_OK) return res; uint64_t value_new = (value_input & value_mask) | (value_device & ~value_mask); /* We will need to erase before writing if the new value needs a '1' in any * position for which the current value had a '0'. Otherwise we can avoid * erasing. */ if ((~value_device) & value_new) { res = samd_erase_row(target, SAMD_USER_ROW); if (res != ERROR_OK) { LOG_ERROR("Couldn't erase user row"); return res; } } /* Modify */ target_buffer_set_u64(target, buf, value_new); /* Write the page buffer back out to the target. */ res = target_write_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf); if (res != ERROR_OK) return res; /* Check if we need to do manual page write commands */ res = target_read_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB, &nvm_ctrlb); if (res == ERROR_OK) manual_wp = (nvm_ctrlb & SAMD_NVM_CTRLB_MANW) != 0; else { LOG_ERROR("Read of NVM register CTRKB failed."); return ERROR_FAIL; } if (manual_wp) { /* Trigger flash write */ res = samd_issue_nvmctrl_command(target, SAMD_NVM_CMD_WAP); } else { res = samd_check_error(target); } return res; } /** * Modifies the user row register to the given value. * @param target Pointer to the target structure. * @param value The value to write. * @param startb The bit-offset by which the given value is shifted. * @param endb The bit-offset of the last bit in value to write. * @return On success ERROR_OK, on failure an errorcode. */ static int samd_modify_user_row(struct target *target, uint64_t value, uint8_t startb, uint8_t endb) { uint64_t mask = 0; int i; for (i = startb ; i <= endb ; i++) mask |= ((uint64_t)1) << i; return samd_modify_user_row_masked(target, value << startb, mask); } static int samd_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int res = ERROR_OK; /* We can issue lock/unlock region commands with the target running but * the settings won't persist unless we're able to modify the LOCK regions * and that requires the target to be halted. */ if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } for (unsigned int prot_block = first; prot_block <= last; prot_block++) { if (set != bank->prot_blocks[prot_block].is_protected) { /* Load an address that is within this protection block (we use offset 0) */ res = target_write_u32(bank->target, SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR, bank->prot_blocks[prot_block].offset >> 1); if (res != ERROR_OK) goto exit; /* Tell the controller to lock that block */ res = samd_issue_nvmctrl_command(bank->target, set ? SAMD_NVM_CMD_LR : SAMD_NVM_CMD_UR); if (res != ERROR_OK) goto exit; } } /* We've now applied our changes, however they will be undone by the next * reset unless we also apply them to the LOCK bits in the User Page. The * LOCK bits start at bit 48, corresponding to Sector 0 and end with bit 63, * corresponding to Sector 15. A '1' means unlocked and a '0' means * locked. See Table 9-3 in the SAMD20 datasheet for more details. */ res = samd_modify_user_row(bank->target, set ? (uint64_t)0 : (uint64_t)UINT64_MAX, 48 + first, 48 + last); if (res != ERROR_OK) LOG_WARNING("SAMD: protect settings were not made persistent!"); res = ERROR_OK; exit: samd_protect_check(bank); return res; } static int samd_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int res; struct samd_info *chip = (struct samd_info *)bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!chip->probed) { if (samd_probe(bank) != ERROR_OK) return ERROR_FLASH_BANK_NOT_PROBED; } /* For each sector to be erased */ for (unsigned int s = first; s <= last; s++) { res = samd_erase_row(bank->target, bank->sectors[s].offset); if (res != ERROR_OK) { LOG_ERROR("SAMD: failed to erase sector %d at 0x%08" PRIx32, s, bank->sectors[s].offset); return res; } } return ERROR_OK; } static int samd_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int res; uint32_t nvm_ctrlb; uint32_t address; uint32_t pg_offset; uint32_t nb; uint32_t nw; struct samd_info *chip = (struct samd_info *)bank->driver_priv; uint8_t *pb = NULL; bool manual_wp; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!chip->probed) { if (samd_probe(bank) != ERROR_OK) return ERROR_FLASH_BANK_NOT_PROBED; } /* Check if we need to do manual page write commands */ res = target_read_u32(bank->target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB, &nvm_ctrlb); if (res != ERROR_OK) return res; if (nvm_ctrlb & SAMD_NVM_CTRLB_MANW) manual_wp = true; else manual_wp = false; res = samd_issue_nvmctrl_command(bank->target, SAMD_NVM_CMD_PBC); if (res != ERROR_OK) { LOG_ERROR("%s: %d", __func__, __LINE__); return res; } while (count) { nb = chip->page_size - offset % chip->page_size; if (count < nb) nb = count; address = bank->base + offset; pg_offset = offset % chip->page_size; if (offset % 4 || (offset + nb) % 4) { /* Either start or end of write is not word aligned */ if (!pb) { pb = malloc(chip->page_size); if (!pb) return ERROR_FAIL; } /* Set temporary page buffer to 0xff and overwrite the relevant part */ memset(pb, 0xff, chip->page_size); memcpy(pb + pg_offset, buffer, nb); /* Align start address to a word boundary */ address -= offset % 4; pg_offset -= offset % 4; assert(pg_offset % 4 == 0); /* Extend length to whole words */ nw = (nb + offset % 4 + 3) / 4; assert(pg_offset + 4 * nw <= chip->page_size); /* Now we have original data extended by 0xff bytes * to the nearest word boundary on both start and end */ res = target_write_memory(bank->target, address, 4, nw, pb + pg_offset); } else { assert(nb % 4 == 0); nw = nb / 4; assert(pg_offset + 4 * nw <= chip->page_size); /* Word aligned data, use direct write from buffer */ res = target_write_memory(bank->target, address, 4, nw, buffer); } if (res != ERROR_OK) { LOG_ERROR("%s: %d", __func__, __LINE__); goto free_pb; } /* Devices with errata 13134 have automatic page write enabled by default * For other devices issue a write page CMD to the NVM * If the page has not been written up to the last word * then issue CMD_WP always */ if (manual_wp || pg_offset + 4 * nw < chip->page_size) { res = samd_issue_nvmctrl_command(bank->target, SAMD_NVM_CMD_WP); } else { /* Access through AHB is stalled while flash is being programmed */ usleep(200); res = samd_check_error(bank->target); } if (res != ERROR_OK) { LOG_ERROR("%s: write failed at address 0x%08" PRIx32, __func__, address); goto free_pb; } /* We're done with the page contents */ count -= nb; offset += nb; buffer += nb; } free_pb: free(pb); return res; } FLASH_BANK_COMMAND_HANDLER(samd_flash_bank_command) { if (bank->base != SAMD_FLASH) { LOG_ERROR("Address " TARGET_ADDR_FMT " invalid bank address (try 0x%08" PRIx32 "[at91samd series] )", bank->base, SAMD_FLASH); return ERROR_FAIL; } struct samd_info *chip; chip = calloc(1, sizeof(*chip)); if (!chip) { LOG_ERROR("No memory for flash bank chip info"); return ERROR_FAIL; } chip->target = bank->target; chip->probed = false; bank->driver_priv = chip; return ERROR_OK; } COMMAND_HANDLER(samd_handle_chip_erase_command) { struct target *target = get_current_target(CMD_CTX); int res = ERROR_FAIL; if (target) { /* Enable access to the DSU by disabling the write protect bit */ target_write_u32(target, SAMD_PAC1, (1<<1)); /* intentionally without error checking - not accessible on secured chip */ /* Tell the DSU to perform a full chip erase. It takes about 240ms to * perform the erase. */ res = target_write_u8(target, SAMD_DSU + SAMD_DSU_CTRL_EXT, (1<<4)); if (res == ERROR_OK) command_print(CMD, "chip erase started"); else command_print(CMD, "write to DSU CTRL failed"); } return res; } COMMAND_HANDLER(samd_handle_set_security_command) { int res = ERROR_OK; struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC < 1 || (CMD_ARGC >= 1 && (strcmp(CMD_ARGV[0], "enable")))) { command_print(CMD, "supply the \"enable\" argument to proceed."); return ERROR_COMMAND_SYNTAX_ERROR; } if (target) { if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } res = samd_issue_nvmctrl_command(target, SAMD_NVM_CMD_SSB); /* Check (and clear) error conditions */ if (res == ERROR_OK) command_print(CMD, "chip secured on next power-cycle"); else command_print(CMD, "failed to secure chip"); } return res; } COMMAND_HANDLER(samd_handle_eeprom_command) { int res = ERROR_OK; struct target *target = get_current_target(CMD_CTX); if (target) { if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (CMD_ARGC >= 1) { int val = atoi(CMD_ARGV[0]); uint32_t code; if (val == 0) code = 7; else { /* Try to match size in bytes with corresponding size code */ for (code = 0; code <= 6; code++) { if (val == (2 << (13 - code))) break; } if (code > 6) { command_print(CMD, "Invalid EEPROM size. Please see " "datasheet for a list valid sizes."); return ERROR_COMMAND_SYNTAX_ERROR; } } res = samd_modify_user_row(target, code, 4, 6); } else { uint16_t val; res = target_read_u16(target, SAMD_USER_ROW, &val); if (res == ERROR_OK) { uint32_t size = ((val >> 4) & 0x7); /* grab size code */ if (size == 0x7) command_print(CMD, "EEPROM is disabled"); else { /* Otherwise, 6 is 256B, 0 is 16KB */ command_print(CMD, "EEPROM size is %u bytes", (2 << (13 - size))); } } } } return res; } COMMAND_HANDLER(samd_handle_nvmuserrow_command) { int res = ERROR_OK; struct target *target = get_current_target(CMD_CTX); if (target) { if (CMD_ARGC > 2) { command_print(CMD, "Too much Arguments given."); return ERROR_COMMAND_SYNTAX_ERROR; } if (CMD_ARGC > 0) { if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted."); return ERROR_TARGET_NOT_HALTED; } uint64_t mask; res = samd_get_reservedmask(target, &mask); if (res != ERROR_OK) { LOG_ERROR("Couldn't determine the mask for reserved bits."); return ERROR_FAIL; } mask &= NVMUSERROW_LOCKBIT_MASK; uint64_t value; COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], value); if (CMD_ARGC == 2) { uint64_t mask_temp; COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], mask_temp); mask &= mask_temp; } res = samd_modify_user_row_masked(target, value, mask); if (res != ERROR_OK) return res; } /* read register */ uint64_t value; res = read_userrow(target, &value); if (res == ERROR_OK) command_print(CMD, "NVMUSERROW: 0x%016"PRIX64, value); else LOG_ERROR("NVMUSERROW could not be read."); } return res; } COMMAND_HANDLER(samd_handle_bootloader_command) { int res = ERROR_OK; struct target *target = get_current_target(CMD_CTX); if (target) { if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Retrieve the MCU's page size, in bytes. */ uint32_t page_size; res = samd_get_flash_page_info(target, &page_size, NULL); if (res != ERROR_OK) { LOG_ERROR("Couldn't determine Flash page size"); return res; } if (CMD_ARGC >= 1) { int val = atoi(CMD_ARGV[0]); uint32_t code; if (val == 0) code = 7; else { /* Try to match size in bytes with corresponding size code */ for (code = 0; code <= 6; code++) { if ((unsigned int)val == (2UL << (8UL - code)) * page_size) break; } if (code > 6) { command_print(CMD, "Invalid bootloader size. Please " "see datasheet for a list valid sizes."); return ERROR_COMMAND_SYNTAX_ERROR; } } res = samd_modify_user_row(target, code, 0, 2); } else { uint16_t val; res = target_read_u16(target, SAMD_USER_ROW, &val); if (res == ERROR_OK) { uint32_t size = (val & 0x7); /* grab size code */ uint32_t nb; if (size == 0x7) nb = 0; else nb = (2 << (8 - size)) * page_size; /* There are 4 pages per row */ command_print(CMD, "Bootloader size is %" PRIu32 " bytes (%" PRIu32 " rows)", nb, (uint32_t)(nb / (page_size * 4))); } } } return res; } COMMAND_HANDLER(samd_handle_reset_deassert) { struct target *target = get_current_target(CMD_CTX); int retval = ERROR_OK; enum reset_types jtag_reset_config = jtag_get_reset_config(); /* If the target has been unresponsive before, try to re-establish * communication now - CPU is held in reset by DSU, DAP is working */ if (!target_was_examined(target)) target_examine_one(target); target_poll(target); /* In case of sysresetreq, debug retains state set in cortex_m_assert_reset() * so we just release reset held by DSU * * n_RESET (srst) clears the DP, so reenable debug and set vector catch here * * After vectreset DSU release is not needed however makes no harm */ if (target->reset_halt && (jtag_reset_config & RESET_HAS_SRST)) { retval = target_write_u32(target, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN); if (retval == ERROR_OK) retval = target_write_u32(target, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); /* do not return on error here, releasing DSU reset is more important */ } /* clear CPU Reset Phase Extension bit */ int retval2 = target_write_u8(target, SAMD_DSU + SAMD_DSU_STATUSA, (1<<1)); if (retval2 != ERROR_OK) return retval2; return retval; } static const struct command_registration at91samd_exec_command_handlers[] = { { .name = "dsu_reset_deassert", .handler = samd_handle_reset_deassert, .mode = COMMAND_EXEC, .help = "Deassert internal reset held by DSU.", .usage = "", }, { .name = "chip-erase", .handler = samd_handle_chip_erase_command, .mode = COMMAND_EXEC, .help = "Erase the entire Flash by using the Chip-" "Erase feature in the Device Service Unit (DSU).", .usage = "", }, { .name = "set-security", .handler = samd_handle_set_security_command, .mode = COMMAND_EXEC, .help = "Secure the chip's Flash by setting the Security Bit. " "This makes it impossible to read the Flash contents. " "The only way to undo this is to issue the chip-erase " "command.", .usage = "'enable'", }, { .name = "eeprom", .usage = "[size_in_bytes]", .handler = samd_handle_eeprom_command, .mode = COMMAND_EXEC, .help = "Show or set the EEPROM size setting, stored in the User Row. " "Please see Table 20-3 of the SAMD20 datasheet for allowed values. " "Changes are stored immediately but take affect after the MCU is " "reset.", }, { .name = "bootloader", .usage = "[size_in_bytes]", .handler = samd_handle_bootloader_command, .mode = COMMAND_EXEC, .help = "Show or set the bootloader size, stored in the User Row. " "Please see Table 20-2 of the SAMD20 datasheet for allowed values. " "Changes are stored immediately but take affect after the MCU is " "reset.", }, { .name = "nvmuserrow", .usage = "[value] [mask]", .handler = samd_handle_nvmuserrow_command, .mode = COMMAND_EXEC, .help = "Show or set the nvmuserrow register. It is 64 bit wide " "and located at address 0x804000. Use the optional mask argument " "to prevent changes at positions where the bitvalue is zero. " "For security reasons the lock- and reserved-bits are masked out " "in background and therefore cannot be changed.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration at91samd_command_handlers[] = { { .name = "at91samd", .mode = COMMAND_ANY, .help = "at91samd flash command group", .usage = "", .chain = at91samd_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver at91samd_flash = { .name = "at91samd", .commands = at91samd_command_handlers, .flash_bank_command = samd_flash_bank_command, .erase = samd_erase, .protect = samd_protect, .write = samd_write, .read = default_flash_read, .probe = samd_probe, .auto_probe = samd_probe, .erase_check = default_flash_blank_check, .protect_check = samd_protect_check, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/ath79.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2015 by Tobias Diedrich * * <ranma+openwrt@tdiedrich.de> * * * * based on the stmsmi code written by Antonio Borneo * * <borneo.antonio@gmail.com> * * * ***************************************************************************/ /* * Driver for the Atheros AR7xxx/AR9xxx SPI flash interface. * * Since no SPI mode register is present, presumably only * SPI "mode 3" (CPOL=1 and CPHA=1) is supported. * * The SPI interface supports up to 3 chip selects, however the SPI flash * used for booting the system must be connected to CS0. * * On boot, the first 4MiB of flash space are memory-mapped into the * area bf000000 - bfffffff (4 copies), so the MIPS bootstrap * vector bfc00000 is mapped to the beginning of the flash. * * By writing a 1 to the REMAP_DISABLE bit in the SPI_CONTROL register, * the full area of 16MiB is mapped. * * By writing a 0 to the SPI_FUNCTION_SELECT register (write-only dword * register @bf000000), memory mapping is disabled and the SPI registers * are exposed to the CPU instead: * bf000000 SPI_FUNCTION_SELECT * bf000004 SPI_CONTROL * bf000008 SPI_IO_CONTROL * bf00000c SPI_READ_DATA * * When not memory-mapped, the SPI interface is essentially bitbanged * using SPI_CONTROL and SPI_IO_CONTROL with the only hardware-assistance * being the 32bit read-only shift-register SPI_READ_DATA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "spi.h" #include <jtag/jtag.h> #include <helper/time_support.h> #include <helper/types.h> #include <target/mips32.h> #include <target/mips32_pracc.h> #include <target/target.h> #define BITS_PER_BYTE 8 #define ATH79_REG_FS 0 #define ATH79_REG_CLOCK 4 #define ATH79_REG_WRITE 8 #define ATH79_REG_DATA 12 #define ATH79_SPI_CS_ALLHI 0x70000 #define ATH79_SPI_CS0_HI 0x10000 #define ATH79_SPI_CS1_HI 0x20000 #define ATH79_SPI_CS2_HI 0x40000 #define ATH79_SPI_CE_HI 0x00100 #define ATH79_SPI_DO_HI 0x00001 #define ATH79_XFER_FINAL 0x00000001 #define ATH79_XFER_PARTIAL 0x00000000 /* Timeout in ms */ #define ATH79_MAX_TIMEOUT (3000) struct ath79_spi_ctx { uint8_t *page_buf; int pre_deselect; int post_deselect; }; struct ath79_flash_bank { bool probed; int chipselect; uint32_t io_base; const struct flash_device *dev; struct ath79_spi_ctx spi; }; struct ath79_target { char *name; uint32_t tap_idcode; uint32_t io_base; }; static const struct ath79_target target_devices[] = { /* name, tap_idcode, io_base */ { "ATH79", 0x00000001, 0xbf000000 }, { NULL, 0, 0 } }; static const uint32_t ath79_chipselects[] = { (~ATH79_SPI_CS0_HI & ATH79_SPI_CS_ALLHI), (~ATH79_SPI_CS1_HI & ATH79_SPI_CS_ALLHI), (~ATH79_SPI_CS2_HI & ATH79_SPI_CS_ALLHI), }; static void ath79_pracc_addn(struct pracc_queue_info *ctx, const uint32_t *instr, int n) { for (int i = 0; i < n; i++) pracc_add(ctx, 0, instr[i]); } static int ath79_spi_bitbang_codegen(struct ath79_flash_bank *ath79_info, struct pracc_queue_info *ctx, uint8_t *data, int len, int partial_xfer) { uint32_t cs_high = ATH79_SPI_CS_ALLHI; uint32_t cs_low = ath79_chipselects[ath79_info->chipselect]; uint32_t clock_high = cs_low | ATH79_SPI_CE_HI; uint32_t clock_low = cs_low; uint32_t pracc_out = 0; uint32_t io_base = ath79_info->io_base; const uint32_t preamble1[] = { /* $15 = MIPS32_PRACC_BASE_ADDR */ MIPS32_LUI(0, 15, PRACC_UPPER_BASE_ADDR), /* $1 = io_base */ MIPS32_LUI(0, 1, UPPER16(io_base)), }; ath79_pracc_addn(ctx, preamble1, ARRAY_SIZE(preamble1)); if (ath79_info->spi.pre_deselect) { /* Clear deselect flag so we don't deselect again if * this is a partial xfer. */ ath79_info->spi.pre_deselect = 0; const uint32_t pre_deselect[] = { /* [$1 + FS] = 1 (enable flash io register access) */ MIPS32_LUI(0, 2, UPPER16(1)), MIPS32_ORI(0, 2, 2, LOWER16(1)), MIPS32_SW(0, 2, ATH79_REG_FS, 1), /* deselect flash just in case */ /* $2 = SPI_CS_DIS */ MIPS32_LUI(0, 2, UPPER16(cs_high)), MIPS32_ORI(0, 2, 2, LOWER16(cs_high)), /* [$1 + WRITE] = $2 */ MIPS32_SW(0, 2, ATH79_REG_WRITE, 1), }; ath79_pracc_addn(ctx, pre_deselect, ARRAY_SIZE(pre_deselect)); } const uint32_t preamble2[] = { /* t0 = CLOCK_LOW + 0-bit */ MIPS32_LUI(0, 8, UPPER16((clock_low + 0))), MIPS32_ORI(0, 8, 8, LOWER16((clock_low + 0))), /* t1 = CLOCK_LOW + 1-bit */ MIPS32_LUI(0, 9, UPPER16((clock_low + 1))), MIPS32_ORI(0, 9, 9, LOWER16((clock_low + 1))), /* t2 = CLOCK_HIGH + 0-bit */ MIPS32_LUI(0, 10, UPPER16((clock_high + 0))), MIPS32_ORI(0, 10, 10, LOWER16((clock_high + 0))), /* t3 = CLOCK_HIGH + 1-bit */ MIPS32_LUI(0, 11, UPPER16((clock_high + 1))), MIPS32_ORI(0, 11, 11, LOWER16((clock_high + 1))), }; ath79_pracc_addn(ctx, preamble2, ARRAY_SIZE(preamble2)); for (int i = 0; i < len; i++) { uint8_t x = data[i]; /* Generate bitbang code for one byte, highest bit first .*/ for (int j = BITS_PER_BYTE - 1; j >= 0; j--) { int bit = ((x >> j) & 1); if (bit) { /* [$1 + WRITE] = t1 */ pracc_add(ctx, 0, MIPS32_SW(0, 9, ATH79_REG_WRITE, 1)); /* [$1 + WRITE] = t3 */ pracc_add(ctx, 0, MIPS32_SW(0, 11, ATH79_REG_WRITE, 1)); } else { /* [$1 + WRITE] = t0 */ pracc_add(ctx, 0, MIPS32_SW(0, 8, ATH79_REG_WRITE, 1)); /* [$1 + WRITE] = t2 */ pracc_add(ctx, 0, MIPS32_SW(0, 10, ATH79_REG_WRITE, 1)); } } if (i % 4 == 3) { /* $3 = [$1 + DATA] */ pracc_add(ctx, 0, MIPS32_LW(0, 3, ATH79_REG_DATA, 1)); /* [OUTi] = $3 */ pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + pracc_out, MIPS32_SW(0, 3, PRACC_OUT_OFFSET + pracc_out, 15)); pracc_out += 4; } } if (len & 3) { /* not a multiple of 4 bytes */ /* $3 = [$1 + DATA] */ pracc_add(ctx, 0, MIPS32_LW(0, 3, ATH79_REG_DATA, 1)); /* [OUTi] = $3 */ pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + pracc_out, MIPS32_SW(0, 3, PRACC_OUT_OFFSET + pracc_out, 15)); pracc_out += 4; } if (ath79_info->spi.post_deselect && !partial_xfer) { const uint32_t post_deselect[] = { /* $2 = SPI_CS_DIS */ MIPS32_LUI(0, 2, UPPER16(cs_high)), MIPS32_ORI(0, 2, 2, LOWER16(cs_high)), /* [$1 + WRITE] = $2 */ MIPS32_SW(0, 2, ATH79_REG_WRITE, 1), /* [$1 + FS] = 0 (disable flash io register access) */ MIPS32_XORI(0, 2, 2, 0), MIPS32_SW(0, 2, ATH79_REG_FS, 1), }; ath79_pracc_addn(ctx, post_deselect, ARRAY_SIZE(post_deselect)); } /* common pracc epilogue */ /* jump to start */ pracc_add(ctx, 0, MIPS32_B(0, NEG16(ctx->code_count + 1))); /* restore $15 from DeSave */ pracc_add(ctx, 0, MIPS32_MFC0(0, 15, 31, 0)); return pracc_out / 4; } static int ath79_spi_bitbang_chunk(struct flash_bank *bank, uint8_t *data, int len, int *transferred) { struct target *target = bank->target; struct ath79_flash_bank *ath79_info = bank->driver_priv; struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int pracc_words; /* * These constants must match the worst case in the above code * generator function ath79_spi_bitbang_codegen. */ const int pracc_pre_post = 26; const int pracc_loop_byte = 8 * 2 + 2; struct pracc_queue_info ctx = { .ejtag_info = ejtag_info }; int max_len = (PRACC_MAX_INSTRUCTIONS - pracc_pre_post) / pracc_loop_byte; int to_xfer = len > max_len ? max_len : len; int partial_xfer = len != to_xfer; int padded_len = (to_xfer + 3) & ~3; uint32_t *out = malloc(padded_len); if (!out) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } *transferred = 0; pracc_queue_init(&ctx); LOG_DEBUG("ath79_spi_bitbang_bytes(%p, %08" PRIx32 ", %p, %d)", target, ath79_info->io_base, data, len); LOG_DEBUG("max code %d => max len %d. to_xfer %d", PRACC_MAX_INSTRUCTIONS, max_len, to_xfer); pracc_words = ath79_spi_bitbang_codegen( ath79_info, &ctx, data, to_xfer, partial_xfer); LOG_DEBUG("Assembled %d instructions, %d stores", ctx.code_count, ctx.store_count); ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, out, 1); if (ctx.retval != ERROR_OK) goto exit; if (to_xfer & 3) { /* Not a multiple of 4 bytes. */ /* * Need to realign last word since we didn't shift the * full 32 bits. */ int missed_bytes = 4 - (to_xfer & 3); out[pracc_words - 1] <<= BITS_PER_BYTE * missed_bytes; } /* * pracc reads return uint32_t in host endianness, convert to * target endianness. * Since we know the ATH79 target is big endian and the SPI * shift register has the bytes in highest to lowest bit order, * this will ensure correct memory byte order regardless of host * endianness. */ target_buffer_set_u32_array(target, (uint8_t *)out, pracc_words, out); if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { for (int i = 0; i < to_xfer; i++) { LOG_DEBUG("bitbang %02x => %02x", data[i], ((uint8_t *)out)[i]); } } memcpy(data, out, to_xfer); *transferred = to_xfer; exit: pracc_queue_free(&ctx); free(out); return ctx.retval; } static void ath79_spi_bitbang_prepare(struct flash_bank *bank) { struct ath79_flash_bank *ath79_info = bank->driver_priv; ath79_info->spi.pre_deselect = 1; } static int ath79_spi_bitbang_bytes(struct flash_bank *bank, uint8_t *data, int len, uint32_t flags) { struct ath79_flash_bank *ath79_info = bank->driver_priv; int retval; int transferred; ath79_info->spi.post_deselect = !!(flags & ATH79_XFER_FINAL); do { transferred = 0; retval = ath79_spi_bitbang_chunk( bank, data, len, &transferred); if (retval != ERROR_OK) return retval; data += transferred; len -= transferred; } while (len > 0); return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(ath79_flash_bank_command) { struct ath79_flash_bank *ath79_info; int chipselect = 0; LOG_DEBUG("%s", __func__); if (CMD_ARGC < 6 || CMD_ARGC > 7) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 7) { if (strcmp(CMD_ARGV[6], "cs0") == 0) chipselect = 0; /* default */ else if (strcmp(CMD_ARGV[6], "cs1") == 0) chipselect = 1; else if (strcmp(CMD_ARGV[6], "cs2") == 0) chipselect = 2; else { LOG_ERROR("Unknown arg: %s", CMD_ARGV[6]); return ERROR_COMMAND_SYNTAX_ERROR; } } ath79_info = calloc(1, sizeof(struct ath79_flash_bank)); if (!ath79_info) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } ath79_info->chipselect = chipselect; bank->driver_priv = ath79_info; return ERROR_OK; } /* Read the status register of the external SPI flash chip. */ static int read_status_reg(struct flash_bank *bank, uint32_t *status) { uint8_t spi_bytes[] = {SPIFLASH_READ_STATUS, 0}; int retval; /* Send SPI command "read STATUS" */ ath79_spi_bitbang_prepare(bank); retval = ath79_spi_bitbang_bytes( bank, spi_bytes, sizeof(spi_bytes), ATH79_XFER_FINAL); *status = spi_bytes[1]; return retval; } /* check for WIP (write in progress) bit in status register */ /* timeout in ms */ static int wait_till_ready(struct flash_bank *bank, int timeout) { uint32_t status; int retval; long long endtime; endtime = timeval_ms() + timeout; do { /* read flash status register */ retval = read_status_reg(bank, &status); if (retval != ERROR_OK) return retval; if ((status & SPIFLASH_BSY_BIT) == 0) return ERROR_OK; alive_sleep(1); } while (timeval_ms() < endtime); LOG_ERROR("timeout"); return ERROR_FAIL; } /* Send "write enable" command to SPI flash chip. */ static int ath79_write_enable(struct flash_bank *bank) { uint32_t status; int retval; uint8_t spi_bytes[] = {SPIFLASH_WRITE_ENABLE}; /* Send SPI command "write enable" */ ath79_spi_bitbang_prepare(bank); retval = ath79_spi_bitbang_bytes( bank, spi_bytes, sizeof(spi_bytes), ATH79_XFER_FINAL); if (retval != ERROR_OK) return retval; /* read flash status register */ retval = read_status_reg(bank, &status); if (retval != ERROR_OK) return retval; /* Check write enabled */ if ((status & SPIFLASH_WE_BIT) == 0) { LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status); return ERROR_FAIL; } return ERROR_OK; } static int erase_command(struct flash_bank *bank, int sector) { struct ath79_flash_bank *ath79_info = bank->driver_priv; uint32_t offset = bank->sectors[sector].offset; uint8_t spi_bytes[] = { ath79_info->dev->erase_cmd, offset >> 16, offset >> 8, offset }; /* bitbang command */ ath79_spi_bitbang_prepare(bank); return ath79_spi_bitbang_bytes( bank, spi_bytes, sizeof(spi_bytes), ATH79_XFER_FINAL); } static int ath79_erase_sector(struct flash_bank *bank, int sector) { int retval = ath79_write_enable(bank); if (retval != ERROR_OK) return retval; /* send SPI command "block erase" */ retval = erase_command(bank, sector); if (retval != ERROR_OK) return retval; /* poll WIP for end of self timed Sector Erase cycle */ return wait_till_ready(bank, ATH79_MAX_TIMEOUT); } static int ath79_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct ath79_flash_bank *ath79_info = bank->driver_priv; int retval = ERROR_OK; LOG_DEBUG("%s: from sector %u to sector %u", __func__, first, last); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((last < first) || (last >= bank->num_sectors)) { LOG_ERROR("Flash sector invalid"); return ERROR_FLASH_SECTOR_INVALID; } if (!ath79_info->probed) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } if (ath79_info->dev->erase_cmd == 0x00) return ERROR_FLASH_OPER_UNSUPPORTED; for (unsigned sector = first; sector <= last; sector++) { if (bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FAIL; } } for (unsigned int sector = first; sector <= last; sector++) { retval = ath79_erase_sector(bank, sector); if (retval != ERROR_OK) break; keep_alive(); } return retval; } static int ath79_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { for (unsigned int sector = first; sector <= last; sector++) bank->sectors[sector].is_protected = set; return ERROR_OK; } static int ath79_write_page(struct flash_bank *bank, const uint8_t *buffer, uint32_t address, uint32_t len) { struct ath79_flash_bank *ath79_info = bank->driver_priv; uint8_t spi_bytes[] = { SPIFLASH_PAGE_PROGRAM, address >> 16, address >> 8, address, }; int retval; uint32_t i, pagesize; /* if no write pagesize, use reasonable default */ pagesize = ath79_info->dev->pagesize ? ath79_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE; if (address & 0xff) { LOG_ERROR("ath79_write_page: unaligned write address: %08" PRIx32, address); return ERROR_FAIL; } if (!ath79_info->spi.page_buf) { LOG_ERROR("ath79_write_page: page buffer not initialized"); return ERROR_FAIL; } if (len > ath79_info->dev->pagesize) { LOG_ERROR("ath79_write_page: len bigger than page size %" PRIu32 ": %" PRIu32, pagesize, len); return ERROR_FAIL; } for (i = 0; i < len; i++) { if (buffer[i] != 0xff) break; } if (i == len) /* all 0xff, no need to program. */ return ERROR_OK; LOG_INFO("writing %" PRIu32 " bytes to flash page @0x%08" PRIx32, len, address); memcpy(ath79_info->spi.page_buf, buffer, len); /* unlock writes */ retval = ath79_write_enable(bank); if (retval != ERROR_OK) return retval; /* bitbang command */ ath79_spi_bitbang_prepare(bank); retval = ath79_spi_bitbang_bytes( bank, spi_bytes, sizeof(spi_bytes), ATH79_XFER_PARTIAL); if (retval != ERROR_OK) return retval; /* write data */ return ath79_spi_bitbang_bytes( bank, ath79_info->spi.page_buf, len, ATH79_XFER_FINAL); } static int ath79_write_buffer(struct flash_bank *bank, const uint8_t *buffer, uint32_t address, uint32_t len) { struct ath79_flash_bank *ath79_info = bank->driver_priv; uint32_t page_size; int retval; LOG_DEBUG("%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, __func__, address, len); /* if no valid page_size, use reasonable default */ page_size = ath79_info->dev->pagesize ? ath79_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE; while (len > 0) { int page_len = len > page_size ? page_size : len; retval = ath79_write_page( bank, buffer, address, page_len); if (retval != ERROR_OK) return retval; buffer += page_size; address += page_size; len -= page_len; } return ERROR_OK; } static int ath79_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, __func__, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) { LOG_WARNING("Write pasts end of flash. Extra data discarded."); count = bank->size - offset; } /* Check sector protection */ for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { /* Start offset in or before this sector? */ /* End offset in or behind this sector? */ struct flash_sector *bs = &bank->sectors[sector]; if ((offset < (bs->offset + bs->size)) && ((offset + count - 1) >= bs->offset) && bs->is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FAIL; } } return ath79_write_buffer(bank, buffer, offset, count); } static int ath79_read_buffer(struct flash_bank *bank, uint8_t *buffer, uint32_t address, uint32_t len) { uint8_t spi_bytes[] = { SPIFLASH_READ, address >> 16, address >> 8, address, }; int retval; LOG_DEBUG("%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, __func__, address, len); if (address & 0xff) { LOG_ERROR("ath79_read_buffer: unaligned read address: %08" PRIx32, address); return ERROR_FAIL; } LOG_INFO("reading %" PRIu32 " bytes from flash @0x%08" PRIx32, len, address); /* bitbang command */ ath79_spi_bitbang_prepare(bank); retval = ath79_spi_bitbang_bytes( bank, spi_bytes, sizeof(spi_bytes), ATH79_XFER_PARTIAL); if (retval != ERROR_OK) return retval; /* read data */ return ath79_spi_bitbang_bytes( bank, buffer, len, ATH79_XFER_FINAL); } static int ath79_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, __func__, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) { LOG_WARNING("Reads past end of flash. Extra data discarded."); count = bank->size - offset; } return ath79_read_buffer(bank, buffer, offset, count); } /* Return ID of flash device */ static int read_flash_id(struct flash_bank *bank, uint32_t *id) { struct target *target = bank->target; int retval; uint8_t spi_bytes[] = {SPIFLASH_READ_ID, 0, 0, 0}; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Send SPI command "read ID" */ ath79_spi_bitbang_prepare(bank); retval = ath79_spi_bitbang_bytes( bank, spi_bytes, sizeof(spi_bytes), ATH79_XFER_FINAL); if (retval != ERROR_OK) return retval; *id = (spi_bytes[1] << 0) | (spi_bytes[2] << 8) | (spi_bytes[3] << 16); if (*id == 0xffffff) { LOG_ERROR("No SPI flash found"); return ERROR_FAIL; } return ERROR_OK; } static int ath79_probe(struct flash_bank *bank) { struct target *target = bank->target; struct ath79_flash_bank *ath79_info = bank->driver_priv; struct flash_sector *sectors; uint32_t id = 0; /* silence uninitialized warning */ uint32_t pagesize, sectorsize; const struct ath79_target *target_device; int retval; if (ath79_info->probed) { free(bank->sectors); free(ath79_info->spi.page_buf); } ath79_info->probed = false; for (target_device = target_devices; target_device->name; ++target_device) if (target_device->tap_idcode == target->tap->idcode) break; if (!target_device->name) { LOG_ERROR("Device ID 0x%" PRIx32 " is not known", target->tap->idcode); return ERROR_FAIL; } ath79_info->io_base = target_device->io_base; LOG_DEBUG("Found device %s at address " TARGET_ADDR_FMT, target_device->name, bank->base); retval = read_flash_id(bank, &id); if (retval != ERROR_OK) return retval; ath79_info->dev = NULL; for (const struct flash_device *p = flash_devices; p->name; p++) if (p->device_id == id) { ath79_info->dev = p; break; } if (!ath79_info->dev) { LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id); return ERROR_FAIL; } LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", ath79_info->dev->name, ath79_info->dev->device_id); /* Set correct size value */ bank->size = ath79_info->dev->size_in_bytes; if (bank->size <= (1UL << 16)) LOG_WARNING("device needs 2-byte addresses - not implemented"); if (bank->size > (1UL << 24)) LOG_WARNING("device needs paging or 4-byte addresses - not implemented"); /* if no sectors, treat whole bank as single sector */ sectorsize = ath79_info->dev->sectorsize ? ath79_info->dev->sectorsize : ath79_info->dev->size_in_bytes; /* create and fill sectors array */ bank->num_sectors = ath79_info->dev->size_in_bytes / sectorsize; sectors = calloc(1, sizeof(struct flash_sector) * bank->num_sectors); if (!sectors) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } /* if no write pagesize, use reasonable default */ pagesize = ath79_info->dev->pagesize ? ath79_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE; ath79_info->spi.page_buf = malloc(pagesize); if (!ath79_info->spi.page_buf) { LOG_ERROR("not enough memory"); free(sectors); return ERROR_FAIL; } for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { sectors[sector].offset = sector * sectorsize; sectors[sector].size = sectorsize; sectors[sector].is_erased = 0; sectors[sector].is_protected = 1; } bank->sectors = sectors; ath79_info->probed = true; return ERROR_OK; } static int ath79_auto_probe(struct flash_bank *bank) { struct ath79_flash_bank *ath79_info = bank->driver_priv; if (ath79_info->probed) return ERROR_OK; return ath79_probe(bank); } static int ath79_flash_blank_check(struct flash_bank *bank) { /* Not implemented */ return ERROR_OK; } static int ath79_protect_check(struct flash_bank *bank) { /* Not implemented */ return ERROR_OK; } static int get_ath79_info(struct flash_bank *bank, struct command_invocation *cmd) { struct ath79_flash_bank *ath79_info = bank->driver_priv; if (!ath79_info->probed) { command_print_sameline(cmd, "\nATH79 flash bank not probed yet\n"); return ERROR_OK; } command_print_sameline(cmd, "\nATH79 flash information:\n" " Device \'%s\' (ID 0x%08" PRIx32 ")\n", ath79_info->dev->name, ath79_info->dev->device_id); return ERROR_OK; } const struct flash_driver ath79_flash = { .name = "ath79", .flash_bank_command = ath79_flash_bank_command, .erase = ath79_erase, .protect = ath79_protect, .write = ath79_write, .read = ath79_read, .probe = ath79_probe, .auto_probe = ath79_auto_probe, .erase_check = ath79_flash_blank_check, .protect_check = ath79_protect_check, .info = get_ath79_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/atsame5.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2017 by Tomas Vanek * * vanekt@fbl.cz * * * * Based on at91samd.c * * Copyright (C) 2013 by Andrey Yurovsky * * Andrey Yurovsky <yurovsky@gmail.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "helper/binarybuffer.h" #include <helper/time_support.h> #include <jtag/jtag.h> #include <target/cortex_m.h> /* A note to prefixing. * Definitions and functions inherited from at91samd.c without * any change retained the original prefix samd_ so they eventually * may go to samd_common.h and .c * As currently there are only 3 short functions identical with * the original source, no common file was created. */ #define SAME5_PAGES_PER_BLOCK 16 #define SAME5_NUM_PROT_BLOCKS 32 #define SAMD_PAGE_SIZE_MAX 1024 #define SAMD_FLASH 0x00000000 /* physical Flash memory */ #define SAMD_USER_ROW 0x00804000 /* User Row of Flash */ #define SAME5_PAC 0x40000000 /* Peripheral Access Control */ #define SAMD_DSU 0x41002000 /* Device Service Unit */ #define SAMD_NVMCTRL 0x41004000 /* Non-volatile memory controller */ #define SAMD_DSU_STATUSA 1 /* DSU status register */ #define SAMD_DSU_DID 0x18 /* Device ID register */ #define SAMD_DSU_CTRL_EXT 0x100 /* CTRL register, external access */ #define SAME5_NVMCTRL_CTRLA 0x00 /* NVM control A register */ #define SAME5_NVMCTRL_CTRLB 0x04 /* NVM control B register */ #define SAMD_NVMCTRL_PARAM 0x08 /* NVM parameters register */ #define SAME5_NVMCTRL_INTFLAG 0x10 /* NVM interrupt flag register */ #define SAME5_NVMCTRL_STATUS 0x12 /* NVM status register */ #define SAME5_NVMCTRL_ADDR 0x14 /* NVM address register */ #define SAME5_NVMCTRL_LOCK 0x18 /* NVM Lock section register */ #define SAMD_CMDEX_KEY 0xA5UL #define SAMD_NVM_CMD(n) ((SAMD_CMDEX_KEY << 8) | (n & 0x7F)) /* NVMCTRL commands. */ #define SAME5_NVM_CMD_EP 0x00 /* Erase Page (User Page only) */ #define SAME5_NVM_CMD_EB 0x01 /* Erase Block */ #define SAME5_NVM_CMD_WP 0x03 /* Write Page */ #define SAME5_NVM_CMD_WQW 0x04 /* Write Quad Word */ #define SAME5_NVM_CMD_LR 0x11 /* Lock Region */ #define SAME5_NVM_CMD_UR 0x12 /* Unlock Region */ #define SAME5_NVM_CMD_PBC 0x15 /* Page Buffer Clear */ #define SAME5_NVM_CMD_SSB 0x16 /* Set Security Bit */ /* NVMCTRL bits */ #define SAME5_NVMCTRL_CTRLA_WMODE_MASK 0x30 #define SAME5_NVMCTRL_INTFLAG_DONE (1 << 0) #define SAME5_NVMCTRL_INTFLAG_ADDRE (1 << 1) #define SAME5_NVMCTRL_INTFLAG_PROGE (1 << 2) #define SAME5_NVMCTRL_INTFLAG_LOCKE (1 << 3) #define SAME5_NVMCTRL_INTFLAG_ECCSE (1 << 4) #define SAME5_NVMCTRL_INTFLAG_ECCDE (1 << 5) #define SAME5_NVMCTRL_INTFLAG_NVME (1 << 6) /* Known identifiers */ #define SAMD_PROCESSOR_M0 0x01 #define SAMD_PROCESSOR_M4 0x06 #define SAMD_FAMILY_D 0x00 #define SAMD_FAMILY_E 0x03 #define SAMD_SERIES_51 0x06 #define SAME_SERIES_51 0x01 #define SAME_SERIES_53 0x03 #define SAME_SERIES_54 0x04 /* Device ID macros */ #define SAMD_GET_PROCESSOR(id) (id >> 28) #define SAMD_GET_FAMILY(id) (((id >> 23) & 0x1F)) #define SAMD_GET_SERIES(id) (((id >> 16) & 0x3F)) #define SAMD_GET_DEVSEL(id) (id & 0xFF) /* Bits to mask user row */ #define NVMUSERROW_SAM_E5_D5_MASK 0x7FFF00FF3C007FFFULL struct samd_part { uint8_t id; const char *name; uint32_t flash_kb; uint32_t ram_kb; }; /* See SAM D5x/E5x Family Silicon Errata and Data Sheet Clarification * DS80000748K */ /* Known SAMD51 parts. */ static const struct samd_part samd51_parts[] = { { 0x00, "SAMD51P20A", 1024, 256 }, { 0x01, "SAMD51P19A", 512, 192 }, { 0x02, "SAMD51N20A", 1024, 256 }, { 0x03, "SAMD51N19A", 512, 192 }, { 0x04, "SAMD51J20A", 1024, 256 }, { 0x05, "SAMD51J19A", 512, 192 }, { 0x06, "SAMD51J18A", 256, 128 }, { 0x07, "SAMD51G19A", 512, 192 }, { 0x08, "SAMD51G18A", 256, 128 }, }; /* Known SAME51 parts. */ static const struct samd_part same51_parts[] = { { 0x00, "SAME51N20A", 1024, 256 }, { 0x01, "SAME51N19A", 512, 192 }, { 0x02, "SAME51J19A", 512, 192 }, { 0x03, "SAME51J18A", 256, 128 }, { 0x04, "SAME51J20A", 1024, 256 }, { 0x05, "SAME51G19A", 512, 192 }, /* New in rev D */ { 0x06, "SAME51G18A", 256, 128 }, /* New in rev D */ }; /* Known SAME53 parts. */ static const struct samd_part same53_parts[] = { { 0x02, "SAME53N20A", 1024, 256 }, { 0x03, "SAME53N19A", 512, 192 }, { 0x04, "SAME53J20A", 1024, 256 }, { 0x05, "SAME53J19A", 512, 192 }, { 0x06, "SAME53J18A", 256, 128 }, { 0x55, "LAN9255/ZMX020", 1024, 256 }, { 0x56, "LAN9255/ZMX019", 512, 192 }, { 0x57, "LAN9255/ZMX018", 256, 128 }, }; /* Known SAME54 parts. */ static const struct samd_part same54_parts[] = { { 0x00, "SAME54P20A", 1024, 256 }, { 0x01, "SAME54P19A", 512, 192 }, { 0x02, "SAME54N20A", 1024, 256 }, { 0x03, "SAME54N19A", 512, 192 }, }; /* Each family of parts contains a parts table in the DEVSEL field of DID. The * processor ID, family ID, and series ID are used to determine which exact * family this is and then we can use the corresponding table. */ struct samd_family { uint8_t processor; uint8_t family; uint8_t series; const struct samd_part *parts; size_t num_parts; }; /* Known SAMD families */ static const struct samd_family samd_families[] = { { SAMD_PROCESSOR_M4, SAMD_FAMILY_D, SAMD_SERIES_51, samd51_parts, ARRAY_SIZE(samd51_parts) }, { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, SAME_SERIES_51, same51_parts, ARRAY_SIZE(same51_parts) }, { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, SAME_SERIES_53, same53_parts, ARRAY_SIZE(same53_parts) }, { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, SAME_SERIES_54, same54_parts, ARRAY_SIZE(same54_parts) }, }; struct samd_info { const struct samd_params *par; uint32_t page_size; int num_pages; int sector_size; int prot_block_size; bool probed; struct target *target; }; /** * Gives the family structure to specific device id. * @param id The id of the device. * @return On failure NULL, otherwise a pointer to the structure. */ static const struct samd_family *samd_find_family(uint32_t id) { uint8_t processor = SAMD_GET_PROCESSOR(id); uint8_t family = SAMD_GET_FAMILY(id); uint8_t series = SAMD_GET_SERIES(id); for (unsigned i = 0; i < ARRAY_SIZE(samd_families); i++) { if (samd_families[i].processor == processor && samd_families[i].series == series && samd_families[i].family == family) return &samd_families[i]; } return NULL; } /** * Gives the part structure to specific device id. * @param id The id of the device. * @return On failure NULL, otherwise a pointer to the structure. */ static const struct samd_part *samd_find_part(uint32_t id) { uint8_t devsel = SAMD_GET_DEVSEL(id); const struct samd_family *family = samd_find_family(id); if (!family) return NULL; for (unsigned i = 0; i < family->num_parts; i++) { if (family->parts[i].id == devsel) return &family->parts[i]; } return NULL; } static int same5_protect_check(struct flash_bank *bank) { int res; uint32_t lock; res = target_read_u32(bank->target, SAMD_NVMCTRL + SAME5_NVMCTRL_LOCK, &lock); if (res != ERROR_OK) return res; /* Lock bits are active-low */ for (unsigned int prot_block = 0; prot_block < bank->num_prot_blocks; prot_block++) bank->prot_blocks[prot_block].is_protected = !(lock & (1u<<prot_block)); return ERROR_OK; } static int samd_get_flash_page_info(struct target *target, uint32_t *sizep, int *nump) { int res; uint32_t param; res = target_read_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_PARAM, ¶m); if (res == ERROR_OK) { /* The PSZ field (bits 18:16) indicate the page size bytes as 2^(3+n) * so 0 is 8KB and 7 is 1024KB. */ if (sizep) *sizep = (8 << ((param >> 16) & 0x7)); /* The NVMP field (bits 15:0) indicates the total number of pages */ if (nump) *nump = param & 0xFFFF; } else { LOG_ERROR("Couldn't read NVM Parameters register"); } return res; } static int same5_probe(struct flash_bank *bank) { uint32_t id; int res; struct samd_info *chip = (struct samd_info *)bank->driver_priv; const struct samd_part *part; if (chip->probed) return ERROR_OK; res = target_read_u32(bank->target, SAMD_DSU + SAMD_DSU_DID, &id); if (res != ERROR_OK) { LOG_ERROR("Couldn't read Device ID register"); return res; } part = samd_find_part(id); if (!part) { LOG_ERROR("Couldn't find part corresponding to DID %08" PRIx32, id); return ERROR_FAIL; } bank->size = part->flash_kb * 1024; res = samd_get_flash_page_info(bank->target, &chip->page_size, &chip->num_pages); if (res != ERROR_OK) { LOG_ERROR("Couldn't determine Flash page size"); return res; } /* Sanity check: the total flash size in the DSU should match the page size * multiplied by the number of pages. */ if (bank->size != chip->num_pages * chip->page_size) { LOG_WARNING("SAM: bank size doesn't match NVM parameters. " "Identified %" PRIu32 "KB Flash but NVMCTRL reports %u %" PRIu32 "B pages", part->flash_kb, chip->num_pages, chip->page_size); } /* Erase granularity = 1 block = 16 pages */ chip->sector_size = chip->page_size * SAME5_PAGES_PER_BLOCK; /* Allocate the sector table */ bank->num_sectors = chip->num_pages / SAME5_PAGES_PER_BLOCK; bank->sectors = alloc_block_array(0, chip->sector_size, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; /* 16 protection blocks per device */ chip->prot_block_size = bank->size / SAME5_NUM_PROT_BLOCKS; /* Allocate the table of protection blocks */ bank->num_prot_blocks = SAME5_NUM_PROT_BLOCKS; bank->prot_blocks = alloc_block_array(0, chip->prot_block_size, bank->num_prot_blocks); if (!bank->prot_blocks) return ERROR_FAIL; same5_protect_check(bank); /* Done */ chip->probed = true; LOG_INFO("SAM MCU: %s (%" PRIu32 "KB Flash, %" PRIu32 "KB RAM)", part->name, part->flash_kb, part->ram_kb); return ERROR_OK; } static int same5_wait_and_check_error(struct target *target) { int ret, ret2; /* Table 54-40 lists the maximum erase block time as 200 ms. * Include some margin. */ int timeout_ms = 200 * 5; int64_t ts_start = timeval_ms(); uint16_t intflag; do { ret = target_read_u16(target, SAMD_NVMCTRL + SAME5_NVMCTRL_INTFLAG, &intflag); if (ret != ERROR_OK) { LOG_ERROR("SAM: error reading the NVMCTRL_INTFLAG register"); return ret; } if (intflag & SAME5_NVMCTRL_INTFLAG_DONE) break; keep_alive(); } while (timeval_ms() - ts_start < timeout_ms); if (!(intflag & SAME5_NVMCTRL_INTFLAG_DONE)) { LOG_ERROR("SAM: NVM programming timed out"); ret = ERROR_FLASH_OPERATION_FAILED; } #if 0 if (intflag & SAME5_NVMCTRL_INTFLAG_ECCSE) LOG_ERROR("SAM: ECC Single Error"); if (intflag & SAME5_NVMCTRL_INTFLAG_ECCDE) { LOG_ERROR("SAM: ECC Double Error"); ret = ERROR_FLASH_OPERATION_FAILED; } #endif if (intflag & SAME5_NVMCTRL_INTFLAG_ADDRE) { LOG_ERROR("SAM: Addr Error"); ret = ERROR_FLASH_OPERATION_FAILED; } if (intflag & SAME5_NVMCTRL_INTFLAG_NVME) { LOG_ERROR("SAM: NVM Error"); ret = ERROR_FLASH_OPERATION_FAILED; } if (intflag & SAME5_NVMCTRL_INTFLAG_LOCKE) { LOG_ERROR("SAM: NVM lock error"); ret = ERROR_FLASH_PROTECTED; } if (intflag & SAME5_NVMCTRL_INTFLAG_PROGE) { LOG_ERROR("SAM: NVM programming error"); ret = ERROR_FLASH_OPER_UNSUPPORTED; } /* Clear the error conditions by writing a one to them */ ret2 = target_write_u16(target, SAMD_NVMCTRL + SAME5_NVMCTRL_INTFLAG, intflag); if (ret2 != ERROR_OK) LOG_ERROR("Can't clear NVM error conditions"); return ret; } static int same5_issue_nvmctrl_command(struct target *target, uint16_t cmd) { int res; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Issue the NVM command */ /* 32-bit write is used to ensure atomic operation on ST-Link */ res = target_write_u32(target, SAMD_NVMCTRL + SAME5_NVMCTRL_CTRLB, SAMD_NVM_CMD(cmd)); if (res != ERROR_OK) return res; /* Check to see if the NVM command resulted in an error condition. */ return same5_wait_and_check_error(target); } /** * Erases a flash block or page at the given address. * @param target Pointer to the target structure. * @param address The address of the row. * @return On success ERROR_OK, on failure an errorcode. */ static int same5_erase_block(struct target *target, uint32_t address) { int res; /* Set an address contained in the block to be erased */ res = target_write_u32(target, SAMD_NVMCTRL + SAME5_NVMCTRL_ADDR, address); /* Issue the Erase Block command. */ if (res == ERROR_OK) res = same5_issue_nvmctrl_command(target, address == SAMD_USER_ROW ? SAME5_NVM_CMD_EP : SAME5_NVM_CMD_EB); if (res != ERROR_OK) { LOG_ERROR("Failed to erase block containing %08" PRIx32, address); return ERROR_FAIL; } return ERROR_OK; } static int same5_pre_write_check(struct target *target) { int res; uint32_t nvm_ctrla; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Check if manual write mode is set */ res = target_read_u32(target, SAMD_NVMCTRL + SAME5_NVMCTRL_CTRLA, &nvm_ctrla); if (res != ERROR_OK) return res; if (nvm_ctrla & SAME5_NVMCTRL_CTRLA_WMODE_MASK) { LOG_ERROR("The flash controller must be in manual write mode. Issue 'reset init' and retry."); return ERROR_FAIL; } return res; } /** * Modify the contents of the User Row in Flash. The User Row itself * has a size of one page and contains a combination of "fuses" and * calibration data. Bits which have a value of zero in the mask will * not be changed. * @param target Pointer to the target structure. * @param data Pointer to the value to write. * @param mask Pointer to bitmask, 0 -> value stays untouched. * @param offset Offset in user row where new data will be applied. * @param count Size of buffer and mask in bytes. * @return On success ERROR_OK, on failure an errorcode. */ static int same5_modify_user_row_masked(struct target *target, const uint8_t *data, const uint8_t *mask, uint32_t offset, uint32_t count) { int res; /* Retrieve the MCU's flash page size, in bytes. */ uint32_t page_size; res = samd_get_flash_page_info(target, &page_size, NULL); if (res != ERROR_OK) { LOG_ERROR("Couldn't determine Flash page size"); return res; } /* Make sure the size is sane. */ assert(page_size <= SAMD_PAGE_SIZE_MAX && page_size >= offset + count); uint8_t buf[SAMD_PAGE_SIZE_MAX]; /* Read the user row (comprising one page) by words. */ res = target_read_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf); if (res != ERROR_OK) return res; /* Modify buffer and check if really changed */ bool changed = false; uint32_t i; for (i = 0; i < count; i++) { uint8_t old_b = buf[offset+i]; uint8_t new_b = (old_b & ~mask[i]) | (data[i] & mask[i]); buf[offset+i] = new_b; if (old_b != new_b) changed = true; } if (!changed) return ERROR_OK; res = same5_pre_write_check(target); if (res != ERROR_OK) return res; res = same5_erase_block(target, SAMD_USER_ROW); if (res != ERROR_OK) { LOG_ERROR("Couldn't erase user row"); return res; } /* Write the page buffer back out to the target using Write Quad Word */ for (i = 0; i < page_size; i += 4 * 4) { res = target_write_memory(target, SAMD_USER_ROW + i, 4, 4, buf + i); if (res != ERROR_OK) return res; /* Trigger flash write */ res = same5_issue_nvmctrl_command(target, SAME5_NVM_CMD_WQW); if (res != ERROR_OK) return res; } return res; } /** * Modifies the user row register to the given value. * @param target Pointer to the target structure. * @param value The value to write. * @param startb The bit-offset by which the given value is shifted. * @param endb The bit-offset of the last bit in value to write. * @return On success ERROR_OK, on failure an errorcode. */ static int same5_modify_user_row(struct target *target, uint32_t value, uint8_t startb, uint8_t endb) { uint8_t buf_val[8] = { 0 }; uint8_t buf_mask[8] = { 0 }; assert(startb <= endb && endb < 64); buf_set_u32(buf_val, startb, endb + 1 - startb, value); buf_set_u32(buf_mask, startb, endb + 1 - startb, 0xffffffff); return same5_modify_user_row_masked(target, buf_val, buf_mask, 0, 8); } static int same5_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int res = ERROR_OK; /* We can issue lock/unlock region commands with the target running but * the settings won't persist unless we're able to modify the LOCK regions * and that requires the target to be halted. */ if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } for (unsigned int prot_block = first; prot_block <= last; prot_block++) { if (set != bank->prot_blocks[prot_block].is_protected) { /* Load an address that is within this protection block (we use offset 0) */ res = target_write_u32(bank->target, SAMD_NVMCTRL + SAME5_NVMCTRL_ADDR, bank->prot_blocks[prot_block].offset); if (res != ERROR_OK) goto exit; /* Tell the controller to lock that block */ res = same5_issue_nvmctrl_command(bank->target, set ? SAME5_NVM_CMD_LR : SAME5_NVM_CMD_UR); if (res != ERROR_OK) goto exit; } } /* We've now applied our changes, however they will be undone by the next * reset unless we also apply them to the LOCK bits in the User Page. * A '1' means unlocked and a '0' means locked. */ const uint8_t lock[4] = { 0, 0, 0, 0 }; const uint8_t unlock[4] = { 0xff, 0xff, 0xff, 0xff }; uint8_t mask[4] = { 0, 0, 0, 0 }; buf_set_u32(mask, first, last + 1 - first, 0xffffffff); res = same5_modify_user_row_masked(bank->target, set ? lock : unlock, mask, 8, 4); if (res != ERROR_OK) LOG_WARNING("SAM: protect settings were not made persistent!"); res = ERROR_OK; exit: same5_protect_check(bank); return res; } static int same5_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int res; struct samd_info *chip = (struct samd_info *)bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!chip->probed) return ERROR_FLASH_BANK_NOT_PROBED; /* For each sector to be erased */ for (unsigned int s = first; s <= last; s++) { res = same5_erase_block(bank->target, bank->sectors[s].offset); if (res != ERROR_OK) { LOG_ERROR("SAM: failed to erase sector %d at 0x%08" PRIx32, s, bank->sectors[s].offset); return res; } } return ERROR_OK; } static int same5_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int res; uint32_t address; uint32_t pg_offset; uint32_t nb; uint32_t nw; struct samd_info *chip = (struct samd_info *)bank->driver_priv; uint8_t *pb = NULL; res = same5_pre_write_check(bank->target); if (res != ERROR_OK) return res; if (!chip->probed) return ERROR_FLASH_BANK_NOT_PROBED; res = same5_issue_nvmctrl_command(bank->target, SAME5_NVM_CMD_PBC); if (res != ERROR_OK) { LOG_ERROR("%s: %d", __func__, __LINE__); return res; } while (count) { nb = chip->page_size - offset % chip->page_size; if (count < nb) nb = count; address = bank->base + offset; pg_offset = offset % chip->page_size; if (offset % 4 || (offset + nb) % 4) { /* Either start or end of write is not word aligned */ if (!pb) { pb = malloc(chip->page_size); if (!pb) return ERROR_FAIL; } /* Set temporary page buffer to 0xff and overwrite the relevant part */ memset(pb, 0xff, chip->page_size); memcpy(pb + pg_offset, buffer, nb); /* Align start address to a word boundary */ address -= offset % 4; pg_offset -= offset % 4; assert(pg_offset % 4 == 0); /* Extend length to whole words */ nw = (nb + offset % 4 + 3) / 4; assert(pg_offset + 4 * nw <= chip->page_size); /* Now we have original data extended by 0xff bytes * to the nearest word boundary on both start and end */ res = target_write_memory(bank->target, address, 4, nw, pb + pg_offset); } else { assert(nb % 4 == 0); nw = nb / 4; assert(pg_offset + 4 * nw <= chip->page_size); /* Word aligned data, use direct write from buffer */ res = target_write_memory(bank->target, address, 4, nw, buffer); } if (res != ERROR_OK) { LOG_ERROR("%s: %d", __func__, __LINE__); goto free_pb; } res = same5_issue_nvmctrl_command(bank->target, SAME5_NVM_CMD_WP); if (res != ERROR_OK) { LOG_ERROR("%s: write failed at address 0x%08" PRIx32, __func__, address); goto free_pb; } /* We're done with the page contents */ count -= nb; offset += nb; buffer += nb; } free_pb: free(pb); return res; } FLASH_BANK_COMMAND_HANDLER(same5_flash_bank_command) { if (bank->base != SAMD_FLASH) { LOG_ERROR("Address " TARGET_ADDR_FMT " invalid bank address (try " "0x%08x[same5] )", bank->base, SAMD_FLASH); return ERROR_FAIL; } struct samd_info *chip; chip = calloc(1, sizeof(*chip)); if (!chip) { LOG_ERROR("No memory for flash bank chip info"); return ERROR_FAIL; } chip->target = bank->target; chip->probed = false; bank->driver_priv = chip; return ERROR_OK; } COMMAND_HANDLER(same5_handle_chip_erase_command) { struct target *target = get_current_target(CMD_CTX); if (!target) return ERROR_FAIL; /* Enable access to the DSU by disabling the write protect bit */ target_write_u32(target, SAME5_PAC, (1<<16) | (1<<5) | (1<<1)); /* intentionally without error checking - not accessible on secured chip */ /* Tell the DSU to perform a full chip erase. It takes about 240ms to * perform the erase. */ int res = target_write_u8(target, SAMD_DSU + SAMD_DSU_CTRL_EXT, (1<<4)); if (res == ERROR_OK) command_print(CMD, "chip erase started"); else command_print(CMD, "write to DSU CTRL failed"); return res; } COMMAND_HANDLER(same5_handle_userpage_command) { int res = ERROR_OK; struct target *target = get_current_target(CMD_CTX); if (!target) return ERROR_FAIL; if (CMD_ARGC > 2) { command_print(CMD, "Too much Arguments given."); return ERROR_COMMAND_SYNTAX_ERROR; } if (CMD_ARGC >= 1) { uint64_t value, mask = NVMUSERROW_SAM_E5_D5_MASK; COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], value); if (CMD_ARGC == 2) { uint64_t mask_temp; COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], mask_temp); mask &= mask_temp; } uint8_t val_buf[8], mask_buf[8]; target_buffer_set_u64(target, val_buf, value); target_buffer_set_u64(target, mask_buf, mask); res = same5_modify_user_row_masked(target, val_buf, mask_buf, 0, sizeof(val_buf)); } uint8_t buffer[8]; int res2 = target_read_memory(target, SAMD_USER_ROW, 4, 2, buffer); if (res2 == ERROR_OK) { uint64_t value = target_buffer_get_u64(target, buffer); command_print(CMD, "USER PAGE: 0x%016"PRIX64, value); } else { LOG_ERROR("USER PAGE could not be read."); } if (CMD_ARGC >= 1) return res; else return res2; } COMMAND_HANDLER(same5_handle_bootloader_command) { int res = ERROR_OK; struct target *target = get_current_target(CMD_CTX); if (!target) return ERROR_FAIL; if (CMD_ARGC >= 1) { unsigned long size; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[0], size); uint32_t code = (size + 8191) / 8192; if (code > 15) { command_print(CMD, "Invalid bootloader size. Please " "see datasheet for a list valid sizes."); return ERROR_COMMAND_SYNTAX_ERROR; } res = same5_modify_user_row(target, 15 - code, 26, 29); } uint32_t val; int res2 = target_read_u32(target, SAMD_USER_ROW, &val); if (res2 == ERROR_OK) { uint32_t code = (val >> 26) & 0xf; /* grab size code */ uint32_t size = (15 - code) * 8192; command_print(CMD, "Bootloader protected in the first %" PRIu32 " bytes", size); } if (CMD_ARGC >= 1) return res; else return res2; } COMMAND_HANDLER(samd_handle_reset_deassert) { struct target *target = get_current_target(CMD_CTX); int res = ERROR_OK; enum reset_types jtag_reset_config = jtag_get_reset_config(); if (!target) return ERROR_FAIL; /* If the target has been unresponsive before, try to re-establish * communication now - CPU is held in reset by DSU, DAP is working */ if (!target_was_examined(target)) target_examine_one(target); target_poll(target); /* In case of sysresetreq, debug retains state set in cortex_m_assert_reset() * so we just release reset held by DSU * * n_RESET (srst) clears the DP, so reenable debug and set vector catch here * * After vectreset DSU release is not needed however makes no harm */ if (target->reset_halt && (jtag_reset_config & RESET_HAS_SRST)) { res = target_write_u32(target, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN); if (res == ERROR_OK) res = target_write_u32(target, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); /* do not return on error here, releasing DSU reset is more important */ } /* clear CPU Reset Phase Extension bit */ int res2 = target_write_u8(target, SAMD_DSU + SAMD_DSU_STATUSA, (1<<1)); if (res2 != ERROR_OK) return res2; return res; } static const struct command_registration same5_exec_command_handlers[] = { { .name = "dsu_reset_deassert", .usage = "", .handler = samd_handle_reset_deassert, .mode = COMMAND_EXEC, .help = "Deassert internal reset held by DSU." }, { .name = "chip-erase", .usage = "", .handler = same5_handle_chip_erase_command, .mode = COMMAND_EXEC, .help = "Erase the entire Flash by using the Chip-" "Erase feature in the Device Service Unit (DSU).", }, { .name = "bootloader", .usage = "[size_in_bytes]", .handler = same5_handle_bootloader_command, .mode = COMMAND_EXEC, .help = "Show or set the bootloader protection size, stored in the User Row. " "Changes are stored immediately but take affect after the MCU is " "reset.", }, { .name = "userpage", .usage = "[value] [mask]", .handler = same5_handle_userpage_command, .mode = COMMAND_EXEC, .help = "Show or set the first 64-bit part of user page " "located at address 0x804000. Use the optional mask argument " "to prevent changes at positions where the bitvalue is zero. " "For security reasons the reserved-bits are masked out " "in background and therefore cannot be changed.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration same5_command_handlers[] = { { .name = "atsame5", .mode = COMMAND_ANY, .help = "atsame5 flash command group", .usage = "", .chain = same5_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver atsame5_flash = { .name = "atsame5", .commands = same5_command_handlers, .flash_bank_command = same5_flash_bank_command, .erase = same5_erase, .protect = same5_protect, .write = same5_write, .read = default_flash_read, .probe = same5_probe, .auto_probe = same5_probe, .erase_check = default_flash_blank_check, .protect_check = same5_protect_check, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/atsamv.c ================================================ // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-Source-Code) /* * Copyright (C) 2009 by Duane Ellis <openocd@duaneellis.com> * * at91sam3s* support * Copyright (C) 2010 by Olaf Lüke <olaf@uni-paderborn.de> * * at91sam3x* & at91sam4 support * Copyright (C) 2011 by Olivier Schonken and Jim Norris * * atsamv, atsams, and atsame support * Copyright (C) 2015 Morgan Quigley * * Some of the lower level code was based on code supplied by * ATMEL under BSD-Source-Code License and this copyright. * ATMEL Microcontroller Software Support * Copyright (c) 2009, Atmel Corporation. All rights reserved. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/time_support.h> #define REG_NAME_WIDTH (12) #define SAMV_EFC_FCMD_GETD (0x0) /* (EFC) Get Flash Descriptor */ #define SAMV_EFC_FCMD_WP (0x1) /* (EFC) Write Page */ #define SAMV_EFC_FCMD_WPL (0x2) /* (EFC) Write Page and Lock */ #define SAMV_EFC_FCMD_EWP (0x3) /* (EFC) Erase Page and Write Page */ #define SAMV_EFC_FCMD_EWPL (0x4) /* (EFC) Erase Page, Write Page then Lock*/ #define SAMV_EFC_FCMD_EA (0x5) /* (EFC) Erase All */ #define SAMV_EFC_FCMD_EPA (0x7) /* (EFC) Erase pages */ #define SAMV_EFC_FCMD_SLB (0x8) /* (EFC) Set Lock Bit */ #define SAMV_EFC_FCMD_CLB (0x9) /* (EFC) Clear Lock Bit */ #define SAMV_EFC_FCMD_GLB (0xA) /* (EFC) Get Lock Bit */ #define SAMV_EFC_FCMD_SFB (0xB) /* (EFC) Set Fuse Bit */ #define SAMV_EFC_FCMD_CFB (0xC) /* (EFC) Clear Fuse Bit */ #define SAMV_EFC_FCMD_GFB (0xD) /* (EFC) Get Fuse Bit */ #define OFFSET_EFC_FMR 0 #define OFFSET_EFC_FCR 4 #define OFFSET_EFC_FSR 8 #define OFFSET_EFC_FRR 12 #define SAMV_CHIPID_CIDR (0x400E0940) #define SAMV_NUM_GPNVM_BITS 9 #define SAMV_CONTROLLER_ADDR (0x400e0c00) #define SAMV_SECTOR_SIZE 16384 #define SAMV_PAGE_SIZE 512 #define SAMV_FLASH_BASE 0x00400000 struct samv_flash_bank { bool probed; unsigned size_bytes; unsigned gpnvm[SAMV_NUM_GPNVM_BITS]; }; /* The actual sector size of the SAMV7 flash memory is 128K bytes. * 16 sectors for a 2048KB device. The lock regions are 16KB per lock * region, with a 2048KB device having 128 lock regions. * For the best results, num_sectors is thus set to the number of lock * regions, and the sector_size set to the lock region size. Page * erases are used to erase 16KB sections when programming */ static int samv_efc_get_status(struct target *target, uint32_t *v) { int r = target_read_u32(target, SAMV_CONTROLLER_ADDR + OFFSET_EFC_FSR, v); return r; } static int samv_efc_get_result(struct target *target, uint32_t *v) { uint32_t rv; int r = target_read_u32(target, SAMV_CONTROLLER_ADDR + OFFSET_EFC_FRR, &rv); if (v) *v = rv; return r; } static int samv_efc_start_command(struct target *target, unsigned command, unsigned argument) { uint32_t v; samv_efc_get_status(target, &v); if (!(v & 1)) { LOG_ERROR("flash controller is not ready"); return ERROR_FAIL; } v = (0x5A << 24) | (argument << 8) | command; LOG_DEBUG("starting flash command: 0x%08x", (unsigned int)(v)); int r = target_write_u32(target, SAMV_CONTROLLER_ADDR + OFFSET_EFC_FCR, v); if (r != ERROR_OK) LOG_DEBUG("write failed"); return r; } static int samv_efc_perform_command(struct target *target, unsigned command, unsigned argument, uint32_t *status) { int r; uint32_t v; int64_t ms_now, ms_end; if (status) *status = 0; r = samv_efc_start_command(target, command, argument); if (r != ERROR_OK) return r; ms_end = 10000 + timeval_ms(); do { r = samv_efc_get_status(target, &v); if (r != ERROR_OK) return r; ms_now = timeval_ms(); if (ms_now > ms_end) { /* error */ LOG_ERROR("Command timeout"); return ERROR_FAIL; } } while ((v & 1) == 0); /* if requested, copy the flash controller error bits back to the caller */ if (status) *status = (v & 0x6); return ERROR_OK; } static int samv_erase_pages(struct target *target, int first_page, int num_pages, uint32_t *status) { uint8_t erase_pages; switch (num_pages) { case 4: erase_pages = 0x00; break; case 8: erase_pages = 0x01; break; case 16: erase_pages = 0x02; break; case 32: erase_pages = 0x03; break; default: erase_pages = 0x00; break; } /* SAMV_EFC_FCMD_EPA * According to the datasheet FARG[15:2] defines the page from which * the erase will start.This page must be modulo 4, 8, 16 or 32 * according to the number of pages to erase. FARG[1:0] defines the * number of pages to be erased. Previously (firstpage << 2) was used * to conform to this, seems it should not be shifted... */ return samv_efc_perform_command(target, SAMV_EFC_FCMD_EPA, first_page | erase_pages, status); } static int samv_get_gpnvm(struct target *target, unsigned gpnvm, unsigned *out) { uint32_t v; int r; if (gpnvm >= SAMV_NUM_GPNVM_BITS) { LOG_ERROR("invalid gpnvm %d, max: %d", gpnvm, SAMV_NUM_GPNVM_BITS); return ERROR_FAIL; } r = samv_efc_perform_command(target, SAMV_EFC_FCMD_GFB, 0, NULL); if (r != ERROR_OK) { LOG_ERROR("samv_get_gpnvm failed"); return r; } r = samv_efc_get_result(target, &v); if (out) *out = (v >> gpnvm) & 1; return r; } static int samv_clear_gpnvm(struct target *target, unsigned gpnvm) { int r; unsigned v; if (gpnvm >= SAMV_NUM_GPNVM_BITS) { LOG_ERROR("invalid gpnvm %d, max: %d", gpnvm, SAMV_NUM_GPNVM_BITS); return ERROR_FAIL; } r = samv_get_gpnvm(target, gpnvm, &v); if (r != ERROR_OK) { LOG_DEBUG("get gpnvm failed: %d", r); return r; } r = samv_efc_perform_command(target, SAMV_EFC_FCMD_CFB, gpnvm, NULL); LOG_DEBUG("clear gpnvm result: %d", r); return r; } static int samv_set_gpnvm(struct target *target, unsigned gpnvm) { int r; unsigned v; if (gpnvm >= SAMV_NUM_GPNVM_BITS) { LOG_ERROR("invalid gpnvm %d, max: %d", gpnvm, SAMV_NUM_GPNVM_BITS); return ERROR_FAIL; } r = samv_get_gpnvm(target, gpnvm, &v); if (r != ERROR_OK) return r; if (v) { r = ERROR_OK; /* the gpnvm bit is already set */ } else { /* we need to set it */ r = samv_efc_perform_command(target, SAMV_EFC_FCMD_SFB, gpnvm, NULL); } return r; } static int samv_flash_unlock(struct target *target, unsigned start_sector, unsigned end_sector) { int r; uint32_t status; uint32_t pg; uint32_t pages_per_sector; /* todo: look into this... i think this should be done on lock regions */ pages_per_sector = SAMV_SECTOR_SIZE / SAMV_PAGE_SIZE; while (start_sector <= end_sector) { pg = start_sector * pages_per_sector; r = samv_efc_perform_command(target, SAMV_EFC_FCMD_CLB, pg, &status); if (r != ERROR_OK) return r; start_sector++; } return ERROR_OK; } static int samv_flash_lock(struct target *target, unsigned start_sector, unsigned end_sector) { uint32_t status; uint32_t pg; uint32_t pages_per_sector; int r; /* todo: look into this... i think this should be done on lock regions */ pages_per_sector = SAMV_SECTOR_SIZE / SAMV_PAGE_SIZE; while (start_sector <= end_sector) { pg = start_sector * pages_per_sector; r = samv_efc_perform_command(target, SAMV_EFC_FCMD_SLB, pg, &status); if (r != ERROR_OK) return r; start_sector++; } return ERROR_OK; } static int samv_protect_check(struct flash_bank *bank) { int r; uint32_t v[4] = {0}; r = samv_efc_perform_command(bank->target, SAMV_EFC_FCMD_GLB, 0, NULL); if (r == ERROR_OK) { samv_efc_get_result(bank->target, &v[0]); samv_efc_get_result(bank->target, &v[1]); samv_efc_get_result(bank->target, &v[2]); r = samv_efc_get_result(bank->target, &v[3]); } if (r != ERROR_OK) return r; for (unsigned int x = 0; x < bank->num_sectors; x++) bank->sectors[x].is_protected = (!!(v[x >> 5] & (1 << (x % 32)))); return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(samv_flash_bank_command) { LOG_INFO("flash bank command"); struct samv_flash_bank *samv_info; samv_info = calloc(1, sizeof(struct samv_flash_bank)); bank->driver_priv = samv_info; return ERROR_OK; } static int samv_get_device_id(struct flash_bank *bank, uint32_t *device_id) { return target_read_u32(bank->target, SAMV_CHIPID_CIDR, device_id); } static int samv_probe(struct flash_bank *bank) { uint32_t device_id; int r = samv_get_device_id(bank, &device_id); if (r != ERROR_OK) return r; LOG_INFO("device id = 0x%08" PRIx32 "", device_id); uint8_t eproc = (device_id >> 5) & 0x7; if (eproc != 0) { LOG_ERROR("unexpected eproc code: %d was expecting 0 (Cortex-M7)", eproc); return ERROR_FAIL; } uint8_t nvm_size_code = (device_id >> 8) & 0xf; switch (nvm_size_code) { case 10: bank->size = 512 * 1024; break; case 12: bank->size = 1024 * 1024; break; case 14: bank->size = 2048 * 1024; break; default: LOG_ERROR("unrecognized flash size code: %d", nvm_size_code); return ERROR_FAIL; } struct samv_flash_bank *samv_info = bank->driver_priv; samv_info->size_bytes = bank->size; samv_info->probed = true; bank->base = SAMV_FLASH_BASE; bank->num_sectors = bank->size / SAMV_SECTOR_SIZE; bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); for (unsigned int s = 0; s < bank->num_sectors; s++) { bank->sectors[s].size = SAMV_SECTOR_SIZE; bank->sectors[s].offset = s * SAMV_SECTOR_SIZE; bank->sectors[s].is_erased = -1; bank->sectors[s].is_protected = -1; } r = samv_protect_check(bank); if (r != ERROR_OK) return r; return ERROR_OK; } static int samv_auto_probe(struct flash_bank *bank) { struct samv_flash_bank *samv_info = bank->driver_priv; if (samv_info->probed) return ERROR_OK; return samv_probe(bank); } static int samv_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { const int page_count = 32; /* 32 pages equals 16 KB lock region */ if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } int r = samv_auto_probe(bank); if (r != ERROR_OK) return r; /* easy case: we've been requested to erase the entire flash */ if ((first == 0) && ((last + 1) == bank->num_sectors)) return samv_efc_perform_command(bank->target, SAMV_EFC_FCMD_EA, 0, NULL); LOG_INFO("erasing lock regions %u-%u...", first, last); for (unsigned int i = first; i <= last; i++) { uint32_t status; r = samv_erase_pages(bank->target, (i * page_count), page_count, &status); LOG_INFO("erasing lock region %u", i); if (r != ERROR_OK) LOG_ERROR("error performing erase page @ lock region number %u", i); if (status & (1 << 2)) { LOG_ERROR("lock region %u is locked", i); return ERROR_FAIL; } if (status & (1 << 1)) { LOG_ERROR("flash command error @lock region %u", i); return ERROR_FAIL; } } return ERROR_OK; } static int samv_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } int r; if (set) r = samv_flash_lock(bank->target, first, last); else r = samv_flash_unlock(bank->target, first, last); return r; } static int samv_page_read(struct target *target, unsigned page_num, uint8_t *buf) { uint32_t addr = SAMV_FLASH_BASE + page_num * SAMV_PAGE_SIZE; int r = target_read_memory(target, addr, 4, SAMV_PAGE_SIZE / 4, buf); if (r != ERROR_OK) LOG_ERROR("flash program failed to read page @ 0x%08x", (unsigned int)(addr)); return r; } static int samv_page_write(struct target *target, unsigned pagenum, const uint8_t *buf) { uint32_t status; const uint32_t addr = SAMV_FLASH_BASE + pagenum * SAMV_PAGE_SIZE; int r; LOG_DEBUG("write page %u at address 0x%08x", pagenum, (unsigned int)addr); r = target_write_memory(target, addr, 4, SAMV_PAGE_SIZE / 4, buf); if (r != ERROR_OK) { LOG_ERROR("failed to buffer page at 0x%08x", (unsigned int)addr); return r; } r = samv_efc_perform_command(target, SAMV_EFC_FCMD_WP, pagenum, &status); if (r != ERROR_OK) LOG_ERROR("error performing write page at 0x%08x", (unsigned int)addr); if (status & (1 << 2)) { LOG_ERROR("page at 0x%08x is locked", (unsigned int)addr); return ERROR_FAIL; } if (status & (1 << 1)) { LOG_ERROR("flash command error at 0x%08x", (unsigned int)addr); return ERROR_FAIL; } return ERROR_OK; } static int samv_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (count == 0) return ERROR_OK; if ((offset + count) > bank->size) { LOG_ERROR("flash write error - past end of bank"); LOG_ERROR(" offset: 0x%08x, count 0x%08x, bank end: 0x%08x", (unsigned int)(offset), (unsigned int)(count), (unsigned int)(bank->size)); return ERROR_FAIL; } uint8_t pagebuffer[SAMV_PAGE_SIZE] = {0}; uint32_t page_cur = offset / SAMV_PAGE_SIZE; uint32_t page_end = (offset + count - 1) / SAMV_PAGE_SIZE; LOG_DEBUG("offset: 0x%08x, count: 0x%08x", (unsigned int)(offset), (unsigned int)(count)); LOG_DEBUG("page start: %d, page end: %d", (int)(page_cur), (int)(page_end)); /* Special case: all one page */ /* Otherwise: */ /* (1) non-aligned start */ /* (2) body pages */ /* (3) non-aligned end. */ int r; uint32_t page_offset; /* handle special case - all one page. */ if (page_cur == page_end) { LOG_DEBUG("special case, all in one page"); r = samv_page_read(bank->target, page_cur, pagebuffer); if (r != ERROR_OK) return r; page_offset = offset & (SAMV_PAGE_SIZE-1); memcpy(pagebuffer + page_offset, buffer, count); r = samv_page_write(bank->target, page_cur, pagebuffer); if (r != ERROR_OK) return r; return ERROR_OK; } /* step 1) handle the non-aligned starting address */ page_offset = offset & (SAMV_PAGE_SIZE - 1); if (page_offset) { LOG_DEBUG("non-aligned start"); /* read the partial page */ r = samv_page_read(bank->target, page_cur, pagebuffer); if (r != ERROR_OK) return r; /* over-write with new data */ uint32_t n = SAMV_PAGE_SIZE - page_offset; memcpy(pagebuffer + page_offset, buffer, n); r = samv_page_write(bank->target, page_cur, pagebuffer); if (r != ERROR_OK) return r; count -= n; offset += n; buffer += n; page_cur++; } /* By checking that offset is correct here, we also fix a clang warning */ assert(offset % SAMV_PAGE_SIZE == 0); /* step 2) handle the full pages */ LOG_DEBUG("full page loop: cur=%d, end=%d, count = 0x%08x", (int)page_cur, (int)page_end, (unsigned int)(count)); while ((page_cur < page_end) && (count >= SAMV_PAGE_SIZE)) { r = samv_page_write(bank->target, page_cur, buffer); if (r != ERROR_OK) return r; count -= SAMV_PAGE_SIZE; buffer += SAMV_PAGE_SIZE; page_cur += 1; } /* step 3) write final page, if it's partial (otherwise it's already done) */ if (count) { LOG_DEBUG("final partial page, count = 0x%08x", (unsigned int)(count)); /* we have a partial page */ r = samv_page_read(bank->target, page_cur, pagebuffer); if (r != ERROR_OK) return r; memcpy(pagebuffer, buffer, count); /* data goes at start of page */ r = samv_page_write(bank->target, page_cur, pagebuffer); if (r != ERROR_OK) return r; } return ERROR_OK; } static int samv_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct samv_flash_bank *samv_info = bank->driver_priv; if (!samv_info->probed) { int r = samv_probe(bank); if (r != ERROR_OK) return r; } command_print_sameline(cmd, "Cortex-M7 detected with %" PRIu32 " kB flash\n", bank->size / 1024); return ERROR_OK; } COMMAND_HANDLER(samv_handle_gpnvm_command) { struct flash_bank *bank = get_flash_bank_by_num_noprobe(0); if (!bank) return ERROR_FAIL; struct samv_flash_bank *samv_info = bank->driver_priv; struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target not halted"); return ERROR_TARGET_NOT_HALTED; } int r; if (!samv_info->probed) { r = samv_auto_probe(bank); if (r != ERROR_OK) return r; } int who = 0; switch (CMD_ARGC) { case 0: goto showall; case 1: who = -1; break; case 2: if (!strcmp(CMD_ARGV[0], "show") && !strcmp(CMD_ARGV[1], "all")) who = -1; else { uint32_t v32; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); who = v32; } break; default: return ERROR_COMMAND_SYNTAX_ERROR; } unsigned v = 0; if (!strcmp("show", CMD_ARGV[0])) { if (who == -1) { showall: r = ERROR_OK; for (int x = 0; x < SAMV_NUM_GPNVM_BITS; x++) { r = samv_get_gpnvm(target, x, &v); if (r != ERROR_OK) break; command_print(CMD, "samv-gpnvm%u: %u", x, v); } return r; } if ((who >= 0) && (((unsigned)who) < SAMV_NUM_GPNVM_BITS)) { r = samv_get_gpnvm(target, who, &v); if (r != ERROR_OK) return r; command_print(CMD, "samv-gpnvm%u: %u", who, v); return r; } else { command_print(CMD, "invalid gpnvm: %u", who); return ERROR_COMMAND_SYNTAX_ERROR; } } if (who == -1) { command_print(CMD, "missing gpnvm number"); return ERROR_COMMAND_SYNTAX_ERROR; } if (!strcmp("set", CMD_ARGV[0])) r = samv_set_gpnvm(target, who); else if (!strcmp("clr", CMD_ARGV[0]) || !strcmp("clear", CMD_ARGV[0])) r = samv_clear_gpnvm(target, who); else { command_print(CMD, "unknown command: %s", CMD_ARGV[0]); r = ERROR_COMMAND_SYNTAX_ERROR; } return r; } static const struct command_registration atsamv_exec_command_handlers[] = { { .name = "gpnvm", .handler = samv_handle_gpnvm_command, .mode = COMMAND_EXEC, .usage = "[('clr'|'set'|'show') bitnum]", .help = "Without arguments, shows all bits in the gpnvm " "register. Otherwise, clears, sets, or shows one " "General Purpose Non-Volatile Memory (gpnvm) bit.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration atsamv_command_handlers[] = { { .name = "atsamv", .mode = COMMAND_ANY, .help = "atsamv flash command group", .usage = "", .chain = atsamv_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver atsamv_flash = { .name = "atsamv", .commands = atsamv_command_handlers, .flash_bank_command = samv_flash_bank_command, .erase = samv_erase, .protect = samv_protect, .write = samv_write, .read = default_flash_read, .probe = samv_probe, .auto_probe = samv_auto_probe, .erase_check = default_flash_blank_check, .protect_check = samv_protect_check, .info = samv_get_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/avrf.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <target/avrt.h> /* AVR_JTAG_Instructions */ #define AVR_JTAG_INS_LEN 4 /* Public Instructions: */ #define AVR_JTAG_INS_EXTEST 0x00 #define AVR_JTAG_INS_IDCODE 0x01 #define AVR_JTAG_INS_SAMPLE_PRELOAD 0x02 #define AVR_JTAG_INS_BYPASS 0x0F /* AVR Specified Public Instructions: */ #define AVR_JTAG_INS_AVR_RESET 0x0C #define AVR_JTAG_INS_PROG_ENABLE 0x04 #define AVR_JTAG_INS_PROG_COMMANDS 0x05 #define AVR_JTAG_INS_PROG_PAGELOAD 0x06 #define AVR_JTAG_INS_PROG_PAGEREAD 0x07 /* Data Registers: */ #define AVR_JTAG_REG_BYPASS_LEN 1 #define AVR_JTAG_REG_DEVICEID_LEN 32 #define AVR_JTAG_REG_RESET_LEN 1 #define AVR_JTAG_REG_JTAGID_LEN 32 #define AVR_JTAG_REG_PROGRAMMING_ENABLE_LEN 16 #define AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN 15 #define AVR_JTAG_REG_FLASH_DATA_BYTE_LEN 16 struct avrf_type { char name[15]; uint16_t chip_id; int flash_page_size; int flash_page_num; int eeprom_page_size; int eeprom_page_num; }; struct avrf_flash_bank { int ppage_size; bool probed; }; static const struct avrf_type avft_chips_info[] = { /* name, chip_id, flash_page_size, flash_page_num, * eeprom_page_size, eeprom_page_num */ {"atmega128", 0x9702, 256, 512, 8, 512}, {"atmega128rfa1", 0xa701, 128, 512, 8, 512}, {"atmega256rfr2", 0xa802, 256, 1024, 8, 1024}, {"at90can128", 0x9781, 256, 512, 8, 512}, {"at90usb128", 0x9782, 256, 512, 8, 512}, {"atmega164p", 0x940a, 128, 128, 4, 128}, {"atmega324p", 0x9508, 128, 256, 4, 256}, {"atmega324pa", 0x9511, 128, 256, 4, 256}, {"atmega644p", 0x960a, 256, 256, 8, 256}, {"atmega1284p", 0x9705, 256, 512, 8, 512}, {"atmega32u4", 0x9587, 128, 256, 4, 256}, }; /* avr program functions */ static int avr_jtag_reset(struct avr_common *avr, uint32_t reset) { avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_AVR_RESET); avr_jtag_senddat(avr->jtag_info.tap, NULL, reset, AVR_JTAG_REG_RESET_LEN); return ERROR_OK; } static int avr_jtag_read_jtagid(struct avr_common *avr, uint32_t *id) { avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_IDCODE); avr_jtag_senddat(avr->jtag_info.tap, id, 0, AVR_JTAG_REG_JTAGID_LEN); return ERROR_OK; } static int avr_jtagprg_enterprogmode(struct avr_common *avr) { avr_jtag_reset(avr, 1); avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_ENABLE); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xA370, AVR_JTAG_REG_PROGRAMMING_ENABLE_LEN); return ERROR_OK; } static int avr_jtagprg_leaveprogmode(struct avr_common *avr) { avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2300, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3300, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_ENABLE); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0, AVR_JTAG_REG_PROGRAMMING_ENABLE_LEN); avr_jtag_reset(avr, 0); return ERROR_OK; } static int avr_jtagprg_chiperase(struct avr_common *avr) { uint32_t poll_value; avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2380, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3180, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3380, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3380, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); do { poll_value = 0; avr_jtag_senddat(avr->jtag_info.tap, &poll_value, 0x3380, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value); } while (!(poll_value & 0x0200)); return ERROR_OK; } static int avr_jtagprg_writeflashpage(struct avr_common *avr, const bool ext_addressing, const uint8_t *page_buf, uint32_t buf_size, uint32_t addr, uint32_t page_size) { uint32_t poll_value; avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2310, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); /* load extended high byte */ if (ext_addressing) avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0b00 | ((addr >> 17) & 0xFF), AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); /* load addr high byte */ avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0700 | ((addr >> 9) & 0xFF), AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); /* load addr low byte */ avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0300 | ((addr >> 1) & 0xFF), AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_PAGELOAD); for (uint32_t i = 0; i < page_size; i++) { if (i < buf_size) avr_jtag_senddat(avr->jtag_info.tap, NULL, page_buf[i], 8); else avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xFF, 8); } avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3500, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); do { poll_value = 0; avr_jtag_senddat(avr->jtag_info.tap, &poll_value, 0x3700, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value); } while (!(poll_value & 0x0200)); return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command) { struct avrf_flash_bank *avrf_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; avrf_info = malloc(sizeof(struct avrf_flash_bank)); bank->driver_priv = avrf_info; avrf_info->probed = false; return ERROR_OK; } static int avrf_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct avr_common *avr = target->arch_info; int status; LOG_DEBUG("%s", __func__); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } status = avr_jtagprg_enterprogmode(avr); if (status != ERROR_OK) return status; status = avr_jtagprg_chiperase(avr); if (status != ERROR_OK) return status; return avr_jtagprg_leaveprogmode(avr); } static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct avr_common *avr = target->arch_info; uint32_t cur_size, cur_buffer_size, page_size; bool ext_addressing; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } page_size = bank->sectors[0].size; if ((offset % page_size) != 0) { LOG_WARNING("offset 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment", offset, page_size); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } LOG_DEBUG("offset is 0x%08" PRIx32 "", offset); LOG_DEBUG("count is %" PRIu32 "", count); if (avr_jtagprg_enterprogmode(avr) != ERROR_OK) return ERROR_FAIL; if (bank->size > 0x20000) ext_addressing = true; else ext_addressing = false; cur_size = 0; while (count > 0) { if (count > page_size) cur_buffer_size = page_size; else cur_buffer_size = count; avr_jtagprg_writeflashpage(avr, ext_addressing, buffer + cur_size, cur_buffer_size, offset + cur_size, page_size); count -= cur_buffer_size; cur_size += cur_buffer_size; keep_alive(); } return avr_jtagprg_leaveprogmode(avr); } #define EXTRACT_MFG(X) (((X) & 0xffe) >> 1) #define EXTRACT_PART(X) (((X) & 0xffff000) >> 12) #define EXTRACT_VER(X) (((X) & 0xf0000000) >> 28) static int avrf_probe(struct flash_bank *bank) { struct target *target = bank->target; struct avrf_flash_bank *avrf_info = bank->driver_priv; struct avr_common *avr = target->arch_info; const struct avrf_type *avr_info = NULL; uint32_t device_id; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } avrf_info->probed = false; avr_jtag_read_jtagid(avr, &device_id); if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; LOG_INFO("device id = 0x%08" PRIx32 "", device_id); if (EXTRACT_MFG(device_id) != 0x1F) LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F); for (size_t i = 0; i < ARRAY_SIZE(avft_chips_info); i++) { if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) { avr_info = &avft_chips_info[i]; LOG_INFO("target device is %s", avr_info->name); break; } } if (avr_info) { free(bank->sectors); /* chip found */ bank->base = 0x00000000; bank->size = (avr_info->flash_page_size * avr_info->flash_page_num); bank->num_sectors = avr_info->flash_page_num; bank->sectors = malloc(sizeof(struct flash_sector) * avr_info->flash_page_num); for (int i = 0; i < avr_info->flash_page_num; i++) { bank->sectors[i].offset = i * avr_info->flash_page_size; bank->sectors[i].size = avr_info->flash_page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } avrf_info->probed = true; return ERROR_OK; } else { /* chip not supported */ LOG_ERROR("0x%" PRIx32 " is not support for avr", EXTRACT_PART(device_id)); avrf_info->probed = true; return ERROR_FAIL; } } static int avrf_auto_probe(struct flash_bank *bank) { struct avrf_flash_bank *avrf_info = bank->driver_priv; if (avrf_info->probed) return ERROR_OK; return avrf_probe(bank); } static int avrf_info(struct flash_bank *bank, struct command_invocation *cmd) { struct target *target = bank->target; struct avr_common *avr = target->arch_info; const struct avrf_type *avr_info = NULL; uint32_t device_id; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } avr_jtag_read_jtagid(avr, &device_id); if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; LOG_INFO("device id = 0x%08" PRIx32 "", device_id); if (EXTRACT_MFG(device_id) != 0x1F) LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F); for (size_t i = 0; i < ARRAY_SIZE(avft_chips_info); i++) { if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) { avr_info = &avft_chips_info[i]; LOG_INFO("target device is %s", avr_info->name); break; } } if (avr_info) { /* chip found */ command_print_sameline(cmd, "%s - Rev: 0x%" PRIx32 "", avr_info->name, EXTRACT_VER(device_id)); return ERROR_OK; } else { /* chip not supported */ command_print_sameline(cmd, "Cannot identify target as a avr\n"); return ERROR_FLASH_OPERATION_FAILED; } } static int avrf_mass_erase(struct flash_bank *bank) { struct target *target = bank->target; struct avr_common *avr = target->arch_info; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((avr_jtagprg_enterprogmode(avr) != ERROR_OK) || (avr_jtagprg_chiperase(avr) != ERROR_OK) || (avr_jtagprg_leaveprogmode(avr) != ERROR_OK)) return ERROR_FAIL; return ERROR_OK; } COMMAND_HANDLER(avrf_handle_mass_erase_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; if (avrf_mass_erase(bank) == ERROR_OK) command_print(CMD, "avr mass erase complete"); else command_print(CMD, "avr mass erase failed"); LOG_DEBUG("%s", __func__); return ERROR_OK; } static const struct command_registration avrf_exec_command_handlers[] = { { .name = "mass_erase", .usage = "<bank>", .handler = avrf_handle_mass_erase_command, .mode = COMMAND_EXEC, .help = "erase entire device", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration avrf_command_handlers[] = { { .name = "avrf", .mode = COMMAND_ANY, .help = "AVR flash command group", .usage = "", .chain = avrf_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver avr_flash = { .name = "avr", .commands = avrf_command_handlers, .flash_bank_command = avrf_flash_bank_command, .erase = avrf_erase, .write = avrf_write, .read = default_flash_read, .probe = avrf_probe, .auto_probe = avrf_auto_probe, .erase_check = default_flash_blank_check, .info = avrf_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/bluenrg-x.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2017 by Michele Sardo * * msmttchr@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/binarybuffer.h> #include "helper/types.h" #include <target/algorithm.h> #include <target/armv7m.h> #include <target/cortex_m.h> #include "imp.h" #include "bluenrg-x.h" #define BLUENRG2_JTAG_REG (flash_priv_data_2.jtag_idcode_reg) #define BLUENRGLP_JTAG_REG (flash_priv_data_lp.jtag_idcode_reg) #define DIE_ID_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->die_id_reg) #define JTAG_IDCODE_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->jtag_idcode_reg) #define FLASH_PAGE_SIZE(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_page_size) #define FLASH_SIZE_REG_MASK (0xFFFF) struct flash_ctrl_priv_data { uint32_t die_id_reg; uint32_t jtag_idcode_reg; uint32_t flash_base; uint32_t flash_regs_base; uint32_t flash_page_size; uint32_t jtag_idcode; char *part_name; }; static const struct flash_ctrl_priv_data flash_priv_data_1 = { .die_id_reg = 0x4090001C, .jtag_idcode_reg = 0x40900028, .flash_base = 0x10040000, .flash_regs_base = 0x40100000, .flash_page_size = 2048, .jtag_idcode = 0x00000000, .part_name = "BLUENRG-1", }; static const struct flash_ctrl_priv_data flash_priv_data_2 = { .die_id_reg = 0x4090001C, .jtag_idcode_reg = 0x40900028, .flash_base = 0x10040000, .flash_regs_base = 0x40100000, .flash_page_size = 2048, .jtag_idcode = 0x0200A041, .part_name = "BLUENRG-2", }; static const struct flash_ctrl_priv_data flash_priv_data_lp = { .die_id_reg = 0x40000000, .jtag_idcode_reg = 0x40000004, .flash_base = 0x10040000, .flash_regs_base = 0x40001000, .flash_page_size = 2048, .jtag_idcode = 0x0201E041, .part_name = "BLUENRG-LP", }; static const struct flash_ctrl_priv_data flash_priv_data_lps = { .die_id_reg = 0x40000000, .jtag_idcode_reg = 0x40000004, .flash_base = 0x10040000, .flash_regs_base = 0x40001000, .flash_page_size = 2048, .jtag_idcode = 0x02028041, .part_name = "BLUENRG-LPS", }; struct bluenrgx_flash_bank { bool probed; uint32_t die_id; const struct flash_ctrl_priv_data *flash_ptr; }; static const struct flash_ctrl_priv_data *flash_ctrl[] = { &flash_priv_data_1, &flash_priv_data_2, &flash_priv_data_lp, &flash_priv_data_lps}; /* flash_bank bluenrg-x 0 0 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) { struct bluenrgx_flash_bank *bluenrgx_info; /* Create the bank structure */ bluenrgx_info = calloc(1, sizeof(*bluenrgx_info)); /* Check allocation */ if (!bluenrgx_info) { LOG_ERROR("failed to allocate bank structure"); return ERROR_FAIL; } bank->write_start_alignment = 16; bank->write_end_alignment = 16; bank->driver_priv = bluenrgx_info; bluenrgx_info->probed = false; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } static inline uint32_t bluenrgx_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; return bluenrgx_info->flash_ptr->flash_regs_base + reg_offset; } static inline int bluenrgx_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value) { return target_read_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value); } static inline int bluenrgx_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) { return target_write_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value); } static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int retval = ERROR_OK; struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; unsigned int num_sectors = (last - first + 1); const bool mass_erase = (num_sectors == bank->num_sectors); struct target *target = bank->target; uint32_t address, command; /* check preconditions */ if (!bluenrgx_info->probed) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Disable blue module */ if (target_write_u32(target, 0x200000c0, 0) != ERROR_OK) { LOG_ERROR("Blue disable failed"); return ERROR_FAIL; } if (mass_erase) { command = FLASH_CMD_MASSERASE; address = bank->base; if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS, (address - bank->base) >> 2) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, command) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } for (unsigned int i = 0; i < 100; i++) { uint32_t value; if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } if (value & FLASH_INT_CMDDONE) break; if (i == 99) { LOG_ERROR("Mass erase command failed (timeout)"); retval = ERROR_FAIL; } } } else { command = FLASH_CMD_ERASE_PAGE; for (unsigned int i = first; i <= last; i++) { address = bank->base+i*FLASH_PAGE_SIZE(bluenrgx_info); LOG_DEBUG("address = %08" PRIx32 ", index = %u", address, i); if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS, (address - bank->base) >> 2) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, command) != ERROR_OK) { LOG_ERROR("Failed"); return ERROR_FAIL; } for (unsigned int j = 0; j < 100; j++) { uint32_t value; if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } if (value & FLASH_INT_CMDDONE) break; if (j == 99) { LOG_ERROR("Erase command failed (timeout)"); retval = ERROR_FAIL; } } } } return retval; } static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 16384 + 8; struct working_area *write_algorithm; struct working_area *write_algorithm_stack; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct mem_param mem_params[1]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* See contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c for source and * hints how to generate the data! */ static const uint8_t bluenrgx_flash_write_code[] = { #include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc" }; /* check preconditions */ if (!bluenrgx_info->probed) return ERROR_FLASH_BANK_NOT_PROBED; if ((offset + count) > bank->size) { LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %" PRIu32 ", size=%" PRIu32, (offset + count), bank->size); return ERROR_FLASH_DST_OUT_OF_BANK; } if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(bluenrgx_flash_write_code), bluenrgx_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ if (target_alloc_working_area(target, buffer_size, &source)) { LOG_WARNING("no large enough working area available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* Stack area */ if (target_alloc_working_area(target, 128, &write_algorithm_stack) != ERROR_OK) { LOG_DEBUG("no working area for target algorithm stack"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "sp", 32, PARAM_OUT); /* Put the 4th parameter at the location in the stack frame of target write() function. * See contrib/loaders/flash/bluenrg-x/bluenrg-x_write.lst * 34 ldr r6, [sp, #80] * ^^^ offset */ init_mem_param(&mem_params[0], write_algorithm_stack->address + 80, 32, PARAM_OUT); /* Stack for target write algorithm - target write() function has * __attribute__((naked)) so it does not setup the new stack frame. * Therefore the stack frame uses the area from SP upwards! * Interrupts are disabled and no subroutines are called from write() * so no need to allocate stack below SP. * TODO: remove __attribute__((naked)) and use similar parameter passing as stm32l4x */ buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_stack->address); /* FIFO start address (first two words used for write and read pointers) */ buf_set_u32(reg_params[0].value, 0, 32, source->address); /* FIFO end address (first two words used for write and read pointers) */ buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); /* Flash memory address */ buf_set_u32(reg_params[2].value, 0, 32, address); /* Number of bytes */ buf_set_u32(reg_params[3].value, 0, 32, count); /* Flash register base address */ buf_set_u32(mem_params[0].value, 0, 32, bluenrgx_info->flash_ptr->flash_regs_base); LOG_DEBUG("source->address = " TARGET_ADDR_FMT, source->address); LOG_DEBUG("source->address+ source->size = " TARGET_ADDR_FMT, source->address+source->size); LOG_DEBUG("write_algorithm_stack->address = " TARGET_ADDR_FMT, write_algorithm_stack->address); LOG_DEBUG("address = %08" PRIx32, address); LOG_DEBUG("count = %08" PRIx32, count); retval = target_run_flash_async_algorithm(target, buffer, count/16, 16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */ 1, mem_params, 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("error executing bluenrg-x flash write algorithm"); uint32_t error = buf_get_u32(reg_params[0].value, 0, 32); if (error != 0) LOG_ERROR("flash write failed = %08" PRIx32, error); } if (retval == ERROR_OK) { uint32_t rp; /* Read back rp and check that is valid */ retval = target_read_u32(target, source->address+4, &rp); if (retval == ERROR_OK) { if ((rp < source->address+8) || (rp > (source->address + source->size))) { LOG_ERROR("flash write failed = %08" PRIx32, rp); retval = ERROR_FLASH_OPERATION_FAILED; } } } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); target_free_working_area(target, write_algorithm_stack); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_mem_param(&mem_params[0]); return retval; } static int bluenrgx_probe(struct flash_bank *bank) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; uint32_t idcode, size_info, die_id; int retval = target_read_u32(bank->target, BLUENRGLP_JTAG_REG, &idcode); if (retval != ERROR_OK) return retval; if ((idcode != flash_priv_data_lp.jtag_idcode) && (idcode != flash_priv_data_lps.jtag_idcode)) { retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode); if (retval != ERROR_OK) return retval; } /* Default device is BlueNRG-1 */ bluenrgx_info->flash_ptr = &flash_priv_data_1; bank->base = flash_priv_data_1.flash_base; for (size_t i = 0; i < ARRAY_SIZE(flash_ctrl); i++) { if (idcode == (*flash_ctrl[i]).jtag_idcode) { bluenrgx_info->flash_ptr = flash_ctrl[i]; bank->base = (*flash_ctrl[i]).flash_base; break; } } retval = bluenrgx_read_flash_reg(bank, FLASH_SIZE_REG, &size_info); size_info = size_info & FLASH_SIZE_REG_MASK; if (retval != ERROR_OK) return retval; retval = target_read_u32(bank->target, DIE_ID_REG(bluenrgx_info), &die_id); if (retval != ERROR_OK) return retval; bank->size = (size_info + 1) * FLASH_WORD_LEN; bank->num_sectors = bank->size/FLASH_PAGE_SIZE(bluenrgx_info); bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = i * FLASH_PAGE_SIZE(bluenrgx_info); bank->sectors[i].size = FLASH_PAGE_SIZE(bluenrgx_info); bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } bluenrgx_info->probed = true; bluenrgx_info->die_id = die_id; return ERROR_OK; } static int bluenrgx_auto_probe(struct flash_bank *bank) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; if (bluenrgx_info->probed) return ERROR_OK; return bluenrgx_probe(bank); } /* This method must return a string displaying information about the bank */ static int bluenrgx_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; int mask_number, cut_number; if (!bluenrgx_info->probed) { int retval = bluenrgx_probe(bank); if (retval != ERROR_OK) { command_print_sameline(cmd, "Unable to find bank information."); return retval; } } mask_number = (bluenrgx_info->die_id >> 4) & 0xF; cut_number = bluenrgx_info->die_id & 0xF; command_print_sameline(cmd, "%s - Rev: %d.%d", bluenrgx_info->flash_ptr->part_name, mask_number, cut_number); return ERROR_OK; } const struct flash_driver bluenrgx_flash = { .name = "bluenrg-x", .flash_bank_command = bluenrgx_flash_bank_command, .erase = bluenrgx_erase, .protect = NULL, .write = bluenrgx_write, .read = default_flash_read, .probe = bluenrgx_probe, .erase_check = default_flash_blank_check, .protect_check = NULL, .auto_probe = bluenrgx_auto_probe, .info = bluenrgx_get_info, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/bluenrg-x.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2019 by STMicroelectronics. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_BLUENRGX_H #define OPENOCD_FLASH_NOR_BLUENRGX_H /* Flash Controller registers offsets */ #define FLASH_REG_COMMAND 0x00 #define FLASH_REG_CONFIG 0x04 #define FLASH_REG_IRQSTAT 0x08 #define FLASH_REG_IRQMASK 0x0C #define FLASH_REG_IRQRAW 0x10 #define FLASH_REG_ADDRESS 0x18 #define FLASH_REG_UNLOCKM 0x1C #define FLASH_REG_UNLOCKL 0x20 #define FLASH_REG_DATA0 0x40 #define FLASH_REG_DATA1 0x44 #define FLASH_REG_DATA2 0x48 #define FLASH_REG_DATA3 0x4C #define FLASH_SIZE_REG 0x14 /* Flash Controller commands */ #define FLASH_CMD_ERASE_PAGE 0x11 #define FLASH_CMD_MASSERASE 0x22 #define FLASH_CMD_WRITE 0x33 #define FLASH_CMD_BURSTWRITE 0xCC #define FLASH_INT_CMDDONE 0x01 #define FLASH_WORD_LEN 4 #endif /* OPENOCD_FLASH_NOR_BLUENRGX_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/cc26xx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2017 by Texas Instruments, Inc. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "cc26xx.h" #include <helper/binarybuffer.h> #include <helper/time_support.h> #include <target/algorithm.h> #include <target/armv7m.h> #include <target/image.h> #define FLASH_TIMEOUT 8000 struct cc26xx_bank { const char *family_name; uint32_t icepick_id; uint32_t user_id; uint32_t device_type; uint32_t sector_length; bool probed; struct working_area *working_area; struct armv7m_algorithm armv7m_info; const uint8_t *algo_code; uint32_t algo_size; uint32_t algo_working_size; uint32_t buffer_addr[2]; uint32_t params_addr[2]; }; /* Flash helper algorithm for CC26x0 Chameleon targets */ static const uint8_t cc26x0_algo[] = { #include "../../../contrib/loaders/flash/cc26xx/cc26x0_algo.inc" }; /* Flash helper algorithm for CC26x2 Agama targets */ static const uint8_t cc26x2_algo[] = { #include "../../../contrib/loaders/flash/cc26xx/cc26x2_algo.inc" }; static int cc26xx_auto_probe(struct flash_bank *bank); static uint32_t cc26xx_device_type(uint32_t icepick_id, uint32_t user_id) { uint32_t device_type = 0; switch (icepick_id & ICEPICK_ID_MASK) { case CC26X0_ICEPICK_ID: device_type = CC26X0_TYPE; break; case CC26X1_ICEPICK_ID: device_type = CC26X1_TYPE; break; case CC13X0_ICEPICK_ID: device_type = CC13X0_TYPE; break; case CC13X2_CC26X2_ICEPICK_ID: default: if ((user_id & USER_ID_CC13_MASK) != 0) device_type = CC13X2_TYPE; else device_type = CC26X2_TYPE; break; } return device_type; } static uint32_t cc26xx_sector_length(uint32_t icepick_id) { uint32_t sector_length; switch (icepick_id & ICEPICK_ID_MASK) { case CC26X0_ICEPICK_ID: case CC26X1_ICEPICK_ID: case CC13X0_ICEPICK_ID: /* Chameleon family device */ sector_length = CC26X0_SECTOR_LENGTH; break; case CC13X2_CC26X2_ICEPICK_ID: default: /* Agama family device */ sector_length = CC26X2_SECTOR_LENGTH; break; } return sector_length; } static int cc26xx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr) { struct target *target = bank->target; struct cc26xx_bank *cc26xx_bank = bank->driver_priv; uint32_t status_addr = params_addr + CC26XX_STATUS_OFFSET; uint32_t status = CC26XX_BUFFER_FULL; long long start_ms; long long elapsed_ms; int retval = ERROR_OK; start_ms = timeval_ms(); while (status == CC26XX_BUFFER_FULL) { retval = target_read_u32(target, status_addr, &status); if (retval != ERROR_OK) return retval; elapsed_ms = timeval_ms() - start_ms; if (elapsed_ms > 500) keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; }; if (status != CC26XX_BUFFER_EMPTY) { LOG_ERROR("%s: Flash operation failed", cc26xx_bank->family_name); return ERROR_FAIL; } return ERROR_OK; } static int cc26xx_init(struct flash_bank *bank) { struct target *target = bank->target; struct cc26xx_bank *cc26xx_bank = bank->driver_priv; int retval; /* Make sure we've probed the flash to get the device and size */ retval = cc26xx_auto_probe(bank); if (retval != ERROR_OK) return retval; /* Check for working area to use for flash helper algorithm */ target_free_working_area(target, cc26xx_bank->working_area); cc26xx_bank->working_area = NULL; retval = target_alloc_working_area(target, cc26xx_bank->algo_working_size, &cc26xx_bank->working_area); if (retval != ERROR_OK) return retval; /* Confirm the defined working address is the area we need to use */ if (cc26xx_bank->working_area->address != CC26XX_ALGO_BASE_ADDRESS) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* Write flash helper algorithm into target memory */ retval = target_write_buffer(target, CC26XX_ALGO_BASE_ADDRESS, cc26xx_bank->algo_size, cc26xx_bank->algo_code); if (retval != ERROR_OK) { LOG_ERROR("%s: Failed to load flash helper algorithm", cc26xx_bank->family_name); target_free_working_area(target, cc26xx_bank->working_area); cc26xx_bank->working_area = NULL; return retval; } /* Initialize the ARMv7 specific info to run the algorithm */ cc26xx_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; cc26xx_bank->armv7m_info.core_mode = ARM_MODE_THREAD; /* Begin executing the flash helper algorithm */ retval = target_start_algorithm(target, 0, NULL, 0, NULL, CC26XX_ALGO_BASE_ADDRESS, 0, &cc26xx_bank->armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("%s: Failed to start flash helper algorithm", cc26xx_bank->family_name); target_free_working_area(target, cc26xx_bank->working_area); cc26xx_bank->working_area = NULL; return retval; } /* * At this point, the algorithm is running on the target and * ready to receive commands and data to flash the target */ return retval; } static int cc26xx_quit(struct flash_bank *bank) { struct target *target = bank->target; struct cc26xx_bank *cc26xx_bank = bank->driver_priv; int retval; /* Regardless of the algo's status, attempt to halt the target */ (void)target_halt(target); /* Now confirm target halted and clean up from flash helper algorithm */ retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, FLASH_TIMEOUT, &cc26xx_bank->armv7m_info); target_free_working_area(target, cc26xx_bank->working_area); cc26xx_bank->working_area = NULL; return retval; } static int cc26xx_mass_erase(struct flash_bank *bank) { struct target *target = bank->target; struct cc26xx_bank *cc26xx_bank = bank->driver_priv; struct cc26xx_algo_params algo_params; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = cc26xx_init(bank); if (retval != ERROR_OK) return retval; /* Initialize algorithm parameters */ buf_set_u32(algo_params.address, 0, 32, 0); buf_set_u32(algo_params.length, 0, 32, 4); buf_set_u32(algo_params.command, 0, 32, CC26XX_CMD_ERASE_ALL); buf_set_u32(algo_params.status, 0, 32, CC26XX_BUFFER_FULL); /* Issue flash helper algorithm parameters for mass erase */ retval = target_write_buffer(target, cc26xx_bank->params_addr[0], sizeof(algo_params), (uint8_t *)&algo_params); /* Wait for command to complete */ if (retval == ERROR_OK) retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[0]); /* Regardless of errors, try to close down algo */ (void)cc26xx_quit(bank); return retval; } FLASH_BANK_COMMAND_HANDLER(cc26xx_flash_bank_command) { struct cc26xx_bank *cc26xx_bank; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; cc26xx_bank = malloc(sizeof(struct cc26xx_bank)); if (!cc26xx_bank) return ERROR_FAIL; /* Initialize private flash information */ memset((void *)cc26xx_bank, 0x00, sizeof(struct cc26xx_bank)); cc26xx_bank->family_name = "cc26xx"; cc26xx_bank->device_type = CC26XX_NO_TYPE; cc26xx_bank->sector_length = 0x1000; /* Finish initialization of bank */ bank->driver_priv = cc26xx_bank; bank->next = NULL; return ERROR_OK; } static int cc26xx_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct cc26xx_bank *cc26xx_bank = bank->driver_priv; struct cc26xx_algo_params algo_params; uint32_t address; uint32_t length; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Do a mass erase if user requested all sectors of flash */ if ((first == 0) && (last == (bank->num_sectors - 1))) { /* Request mass erase of flash */ return cc26xx_mass_erase(bank); } address = first * cc26xx_bank->sector_length; length = (last - first + 1) * cc26xx_bank->sector_length; retval = cc26xx_init(bank); if (retval != ERROR_OK) return retval; /* Set up algorithm parameters for erase command */ buf_set_u32(algo_params.address, 0, 32, address); buf_set_u32(algo_params.length, 0, 32, length); buf_set_u32(algo_params.command, 0, 32, CC26XX_CMD_ERASE_SECTORS); buf_set_u32(algo_params.status, 0, 32, CC26XX_BUFFER_FULL); /* Issue flash helper algorithm parameters for erase */ retval = target_write_buffer(target, cc26xx_bank->params_addr[0], sizeof(algo_params), (uint8_t *)&algo_params); /* If no error, wait for erase to finish */ if (retval == ERROR_OK) retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[0]); /* Regardless of errors, try to close down algo */ (void)cc26xx_quit(bank); return retval; } static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct cc26xx_bank *cc26xx_bank = bank->driver_priv; struct cc26xx_algo_params algo_params[2]; uint32_t size = 0; long long start_ms; long long elapsed_ms; uint32_t address; uint32_t index; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = cc26xx_init(bank); if (retval != ERROR_OK) return retval; /* Initialize algorithm parameters to default values */ buf_set_u32(algo_params[0].command, 0, 32, CC26XX_CMD_PROGRAM); buf_set_u32(algo_params[1].command, 0, 32, CC26XX_CMD_PROGRAM); /* Write requested data, ping-ponging between two buffers */ index = 0; start_ms = timeval_ms(); address = bank->base + offset; while (count > 0) { if (count > cc26xx_bank->sector_length) size = cc26xx_bank->sector_length; else size = count; /* Put next block of data to flash into buffer */ retval = target_write_buffer(target, cc26xx_bank->buffer_addr[index], size, buffer); if (retval != ERROR_OK) { LOG_ERROR("Unable to write data to target memory"); break; } /* Update algo parameters for next block */ buf_set_u32(algo_params[index].address, 0, 32, address); buf_set_u32(algo_params[index].length, 0, 32, size); buf_set_u32(algo_params[index].status, 0, 32, CC26XX_BUFFER_FULL); /* Issue flash helper algorithm parameters for block write */ retval = target_write_buffer(target, cc26xx_bank->params_addr[index], sizeof(algo_params[index]), (uint8_t *)&algo_params[index]); if (retval != ERROR_OK) break; /* Wait for next ping pong buffer to be ready */ index ^= 1; retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[index]); if (retval != ERROR_OK) break; count -= size; buffer += size; address += size; elapsed_ms = timeval_ms() - start_ms; if (elapsed_ms > 500) keep_alive(); } /* If no error yet, wait for last buffer to finish */ if (retval == ERROR_OK) { index ^= 1; retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[index]); } /* Regardless of errors, try to close down algo */ (void)cc26xx_quit(bank); return retval; } static int cc26xx_probe(struct flash_bank *bank) { struct target *target = bank->target; struct cc26xx_bank *cc26xx_bank = bank->driver_priv; uint32_t sector_length; uint32_t value; int num_sectors; int max_sectors; int retval; retval = target_read_u32(target, FCFG1_ICEPICK_ID, &value); if (retval != ERROR_OK) return retval; cc26xx_bank->icepick_id = value; retval = target_read_u32(target, FCFG1_USER_ID, &value); if (retval != ERROR_OK) return retval; cc26xx_bank->user_id = value; cc26xx_bank->device_type = cc26xx_device_type(cc26xx_bank->icepick_id, cc26xx_bank->user_id); sector_length = cc26xx_sector_length(cc26xx_bank->icepick_id); /* Set up appropriate flash helper algorithm */ switch (cc26xx_bank->icepick_id & ICEPICK_ID_MASK) { case CC26X0_ICEPICK_ID: case CC26X1_ICEPICK_ID: case CC13X0_ICEPICK_ID: /* Chameleon family device */ cc26xx_bank->algo_code = cc26x0_algo; cc26xx_bank->algo_size = sizeof(cc26x0_algo); cc26xx_bank->algo_working_size = CC26X0_WORKING_SIZE; cc26xx_bank->buffer_addr[0] = CC26X0_ALGO_BUFFER_0; cc26xx_bank->buffer_addr[1] = CC26X0_ALGO_BUFFER_1; cc26xx_bank->params_addr[0] = CC26X0_ALGO_PARAMS_0; cc26xx_bank->params_addr[1] = CC26X0_ALGO_PARAMS_1; max_sectors = CC26X0_MAX_SECTORS; break; case CC13X2_CC26X2_ICEPICK_ID: default: /* Agama family device */ cc26xx_bank->algo_code = cc26x2_algo; cc26xx_bank->algo_size = sizeof(cc26x2_algo); cc26xx_bank->algo_working_size = CC26X2_WORKING_SIZE; cc26xx_bank->buffer_addr[0] = CC26X2_ALGO_BUFFER_0; cc26xx_bank->buffer_addr[1] = CC26X2_ALGO_BUFFER_1; cc26xx_bank->params_addr[0] = CC26X2_ALGO_PARAMS_0; cc26xx_bank->params_addr[1] = CC26X2_ALGO_PARAMS_1; max_sectors = CC26X2_MAX_SECTORS; break; } retval = target_read_u32(target, CC26XX_FLASH_SIZE_INFO, &value); if (retval != ERROR_OK) return retval; num_sectors = value & 0xff; if (num_sectors > max_sectors) num_sectors = max_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); if (!bank->sectors) return ERROR_FAIL; bank->base = CC26XX_FLASH_BASE_ADDR; bank->num_sectors = num_sectors; bank->size = num_sectors * sector_length; bank->write_start_alignment = 0; bank->write_end_alignment = 0; cc26xx_bank->sector_length = sector_length; for (int i = 0; i < num_sectors; i++) { bank->sectors[i].offset = i * sector_length; bank->sectors[i].size = sector_length; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } /* We've successfully determined the stats on the flash bank */ cc26xx_bank->probed = true; /* If we fall through to here, then all went well */ return ERROR_OK; } static int cc26xx_auto_probe(struct flash_bank *bank) { struct cc26xx_bank *cc26xx_bank = bank->driver_priv; int retval = ERROR_OK; if (!cc26xx_bank->probed) retval = cc26xx_probe(bank); return retval; } static int cc26xx_info(struct flash_bank *bank, struct command_invocation *cmd) { struct cc26xx_bank *cc26xx_bank = bank->driver_priv; const char *device; switch (cc26xx_bank->device_type) { case CC26X0_TYPE: device = "CC26x0"; break; case CC26X1_TYPE: device = "CC26x1"; break; case CC13X0_TYPE: device = "CC13x0"; break; case CC13X2_TYPE: device = "CC13x2"; break; case CC26X2_TYPE: device = "CC26x2"; break; case CC26XX_NO_TYPE: default: device = "Unrecognized"; break; } command_print_sameline(cmd, "%s device: ICEPick ID 0x%08" PRIx32 ", USER ID 0x%08" PRIx32 "\n", device, cc26xx_bank->icepick_id, cc26xx_bank->user_id); return ERROR_OK; } const struct flash_driver cc26xx_flash = { .name = "cc26xx", .flash_bank_command = cc26xx_flash_bank_command, .erase = cc26xx_erase, .write = cc26xx_write, .read = default_flash_read, .probe = cc26xx_probe, .auto_probe = cc26xx_auto_probe, .erase_check = default_flash_blank_check, .info = cc26xx_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/cc26xx.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2017 by Texas Instruments, Inc. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_CC26XX_H #define OPENOCD_FLASH_NOR_CC26XX_H /* Addresses of FCFG1 registers to access ICEPick Device ID and User ID */ #define FCFG1_ICEPICK_ID 0x50001318 #define FCFG1_USER_ID 0x50001294 /* ICEPick device ID mask and values */ #define ICEPICK_ID_MASK 0x0fffffff #define ICEPICK_REV_MASK 0xf0000000 #define CC26X0_ICEPICK_ID 0x0b99a02f #define CC26X1_ICEPICK_ID 0x0b9bd02f #define CC13X0_ICEPICK_ID 0x0b9be02f #define CC13X2_CC26X2_ICEPICK_ID 0x0bb4102f /* User ID mask for Agama CC13x2 vs CC26x2 */ #define USER_ID_CC13_MASK 0x00800000 /* Common CC26xx/CC13xx flash and memory parameters */ #define CC26XX_FLASH_BASE_ADDR 0x00000000 #define CC26XX_FLASH_SIZE_INFO 0x4003002c #define CC26XX_SRAM_SIZE_INFO 0x40082250 #define CC26XX_ALGO_BASE_ADDRESS 0x20000000 /* Chameleon CC26x0/CC13x0 specific parameters */ #define CC26X0_MAX_SECTORS 32 #define CC26X0_SECTOR_LENGTH 0x1000 #define CC26X0_ALGO_BUFFER_0 0x20001c00 #define CC26X0_ALGO_BUFFER_1 0x20002c00 #define CC26X0_ALGO_PARAMS_0 0x20001bd8 #define CC26X0_ALGO_PARAMS_1 0x20001bec #define CC26X0_WORKING_SIZE (CC26X0_ALGO_BUFFER_1 + CC26X0_SECTOR_LENGTH - \ CC26XX_ALGO_BASE_ADDRESS) /* Agama CC26x2/CC13x2 specific parameters */ #define CC26X2_MAX_SECTORS 128 #define CC26X2_SECTOR_LENGTH 0x2000 #define CC26X2_ALGO_BUFFER_0 0x20002000 #define CC26X2_ALGO_BUFFER_1 0x20004000 #define CC26X2_ALGO_PARAMS_0 0x20001fd8 #define CC26X2_ALGO_PARAMS_1 0x20001fec #define CC26X2_WORKING_SIZE (CC26X2_ALGO_BUFFER_1 + CC26X2_SECTOR_LENGTH - \ CC26XX_ALGO_BASE_ADDRESS) /* CC26xx flash helper algorithm buffer flags */ #define CC26XX_BUFFER_EMPTY 0x00000000 #define CC26XX_BUFFER_FULL 0xffffffff /* CC26XX flash helper algorithm commands */ #define CC26XX_CMD_NO_ACTION 0 #define CC26XX_CMD_ERASE_ALL 1 #define CC26XX_CMD_PROGRAM 2 #define CC26XX_CMD_ERASE_AND_PROGRAM 3 #define CC26XX_CMD_ERASE_AND_PROGRAM_WITH_RETAIN 4 #define CC26XX_CMD_ERASE_SECTORS 5 /* CC26xx and CC13xx device types */ #define CC26XX_NO_TYPE 0 /* Device type not determined yet */ #define CC26X0_TYPE 1 /* CC26x0 Chameleon device */ #define CC26X1_TYPE 2 /* CC26x1 Chameleon device */ #define CC26X2_TYPE 3 /* CC26x2 Agama device */ #define CC13X0_TYPE 4 /* CC13x0 Chameleon device */ #define CC13X2_TYPE 5 /* CC13x2 Agama device */ /* Flash helper algorithm parameter block struct */ #define CC26XX_STATUS_OFFSET 0x0c struct cc26xx_algo_params { uint8_t address[4]; uint8_t length[4]; uint8_t command[4]; uint8_t status[4]; }; #endif /* OPENOCD_FLASH_NOR_CC26XX_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/cc3220sf.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2017 by Texas Instruments, Inc. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "cc3220sf.h" #include <helper/binarybuffer.h> #include <helper/time_support.h> #include <target/algorithm.h> #include <target/armv7m.h> #define FLASH_TIMEOUT 5000 struct cc3220sf_bank { bool probed; struct armv7m_algorithm armv7m_info; }; /* Flash helper algorithm for CC3220SF */ static const uint8_t cc3220sf_algo[] = { #include "../../../contrib/loaders/flash/cc3220sf/cc3220sf.inc" }; static int cc3220sf_mass_erase(struct flash_bank *bank) { struct target *target = bank->target; bool done; long long start_ms; long long elapsed_ms; uint32_t value; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Set starting address to erase to zero */ retval = target_write_u32(target, FMA_REGISTER_ADDR, 0); if (retval != ERROR_OK) return retval; /* Write the MERASE bit of the FMC register */ retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_MERASE_VALUE); if (retval != ERROR_OK) return retval; /* Poll the MERASE bit until the mass erase is complete */ done = false; start_ms = timeval_ms(); while (!done) { retval = target_read_u32(target, FMC_REGISTER_ADDR, &value); if (retval != ERROR_OK) return retval; if ((value & FMC_MERASE_BIT) == 0) { /* Bit clears when mass erase is finished */ done = true; } else { elapsed_ms = timeval_ms() - start_ms; if (elapsed_ms > 500) keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; } } if (!done) { /* Mass erase timed out waiting for confirmation */ return ERROR_FAIL; } return retval; } FLASH_BANK_COMMAND_HANDLER(cc3220sf_flash_bank_command) { struct cc3220sf_bank *cc3220sf_bank; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; cc3220sf_bank = malloc(sizeof(struct cc3220sf_bank)); if (!cc3220sf_bank) return ERROR_FAIL; /* Initialize private flash information */ cc3220sf_bank->probed = false; /* Finish initialization of flash bank */ bank->driver_priv = cc3220sf_bank; bank->next = NULL; return ERROR_OK; } static int cc3220sf_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; bool done; long long start_ms; long long elapsed_ms; uint32_t address; uint32_t value; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Do a mass erase if user requested all sectors of flash */ if ((first == 0) && (last == (bank->num_sectors - 1))) { /* Request mass erase of flash */ return cc3220sf_mass_erase(bank); } /* Erase requested sectors one by one */ for (unsigned int i = first; i <= last; i++) { /* Determine address of sector to erase */ address = FLASH_BASE_ADDR + i * FLASH_SECTOR_SIZE; /* Set starting address to erase */ retval = target_write_u32(target, FMA_REGISTER_ADDR, address); if (retval != ERROR_OK) return retval; /* Write the ERASE bit of the FMC register */ retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_ERASE_VALUE); if (retval != ERROR_OK) return retval; /* Poll the ERASE bit until the erase is complete */ done = false; start_ms = timeval_ms(); while (!done) { retval = target_read_u32(target, FMC_REGISTER_ADDR, &value); if (retval != ERROR_OK) return retval; if ((value & FMC_ERASE_BIT) == 0) { /* Bit clears when mass erase is finished */ done = true; } else { elapsed_ms = timeval_ms() - start_ms; if (elapsed_ms > 500) keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; } } if (!done) { /* Sector erase timed out waiting for confirmation */ return ERROR_FAIL; } } return retval; } static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv; struct working_area *algo_working_area; struct working_area *buffer_working_area; struct reg_param reg_params[3]; uint32_t algo_base_address; uint32_t algo_buffer_address; uint32_t algo_buffer_size; uint32_t address; uint32_t remaining; uint32_t words; uint32_t result; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Obtain working area to use for flash helper algorithm */ retval = target_alloc_working_area(target, sizeof(cc3220sf_algo), &algo_working_area); if (retval != ERROR_OK) return retval; /* Obtain working area to use for flash buffer */ retval = target_alloc_working_area(target, target_get_working_area_avail(target), &buffer_working_area); if (retval != ERROR_OK) { target_free_working_area(target, algo_working_area); return retval; } algo_base_address = algo_working_area->address; algo_buffer_address = buffer_working_area->address; algo_buffer_size = buffer_working_area->size; /* Make sure buffer size is a multiple of 32 word (0x80 byte) chunks */ /* (algo runs more efficiently if it operates on 32 words at a time) */ if (algo_buffer_size > 0x80) algo_buffer_size &= ~0x7f; /* Write flash helper algorithm into target memory */ retval = target_write_buffer(target, algo_base_address, sizeof(cc3220sf_algo), cc3220sf_algo); if (retval != ERROR_OK) { target_free_working_area(target, algo_working_area); target_free_working_area(target, buffer_working_area); return retval; } /* Initialize the ARMv7m specific info to run the algorithm */ cc3220sf_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; cc3220sf_bank->armv7m_info.core_mode = ARM_MODE_THREAD; /* Initialize register params for flash helper algorithm */ init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); /* Prepare to write to flash */ address = FLASH_BASE_ADDR + offset; remaining = count; /* The flash hardware can only write complete words to flash. If * an unaligned address is passed in, we must do a read-modify-write * on a word with enough bytes to align the rest of the buffer. And * if less than a whole word remains at the end, we must also do a * read-modify-write on a final word to finish up. */ /* Do one word write to align address on 32-bit boundary if needed */ if (0 != (address & 0x3)) { uint8_t head[4]; /* Get starting offset for data to write (will be 1 to 3) */ uint32_t head_offset = address & 0x03; /* Get the aligned address to write this first word to */ uint32_t head_address = address & 0xfffffffc; /* Retrieve what is already in flash at the head address */ retval = target_read_buffer(target, head_address, sizeof(head), head); if (retval == ERROR_OK) { /* Substitute in the new data to write */ while ((remaining > 0) && (head_offset < 4)) { head[head_offset] = *buffer; head_offset++; address++; buffer++; remaining--; } } if (retval == ERROR_OK) { /* Helper parameters are passed in registers R0-R2 */ /* Set start of data buffer, address to write to, and word count */ buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address); buf_set_u32(reg_params[1].value, 0, 32, head_address); buf_set_u32(reg_params[2].value, 0, 32, 1); /* Write head value into buffer to flash */ retval = target_write_buffer(target, algo_buffer_address, sizeof(head), head); } if (retval == ERROR_OK) { /* Execute the flash helper algorithm */ retval = target_run_algorithm(target, 0, NULL, 3, reg_params, algo_base_address, 0, FLASH_TIMEOUT, &cc3220sf_bank->armv7m_info); if (retval != ERROR_OK) LOG_ERROR("cc3220sf: Flash algorithm failed to run"); /* Check that the head value was written to flash */ result = buf_get_u32(reg_params[2].value, 0, 32); if (result != 0) { retval = ERROR_FAIL; LOG_ERROR("cc3220sf: Flash operation failed"); } } } /* Check if there's data at end of buffer that isn't a full word */ uint32_t tail_count = remaining & 0x03; /* Adjust remaining so it is a multiple of whole words */ remaining -= tail_count; while ((retval == ERROR_OK) && (remaining > 0)) { /* Set start of data buffer and address to write to */ buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address); buf_set_u32(reg_params[1].value, 0, 32, address); /* Download data to write into memory buffer */ if (remaining >= algo_buffer_size) { /* Fill up buffer with data to flash */ retval = target_write_buffer(target, algo_buffer_address, algo_buffer_size, buffer); if (retval != ERROR_OK) break; /* Count to write is in 32-bit words */ words = algo_buffer_size / 4; /* Bump variables to next data */ address += algo_buffer_size; buffer += algo_buffer_size; remaining -= algo_buffer_size; } else { /* Fill buffer with what's left of the data */ retval = target_write_buffer(target, algo_buffer_address, remaining, buffer); if (retval != ERROR_OK) break; /* Calculate the final word count to write */ words = remaining / 4; if (0 != (remaining % 4)) words++; /* Bump variables to any final data */ address += remaining; buffer += remaining; remaining = 0; } /* Set number of words to write */ buf_set_u32(reg_params[2].value, 0, 32, words); /* Execute the flash helper algorithm */ retval = target_run_algorithm(target, 0, NULL, 3, reg_params, algo_base_address, 0, FLASH_TIMEOUT, &cc3220sf_bank->armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("cc3220sf: Flash algorithm failed to run"); break; } /* Check that all words were written to flash */ result = buf_get_u32(reg_params[2].value, 0, 32); if (result != 0) { retval = ERROR_FAIL; LOG_ERROR("cc3220sf: Flash operation failed"); break; } keep_alive(); } /* Do one word write for any final bytes less than a full word */ if ((retval == ERROR_OK) && (tail_count != 0)) { uint8_t tail[4]; /* Set starting byte offset for data to write */ uint32_t tail_offset = 0; /* Retrieve what is already in flash at the tail address */ retval = target_read_buffer(target, address, sizeof(tail), tail); if (retval == ERROR_OK) { /* Substitute in the new data to write */ while (tail_count > 0) { tail[tail_offset] = *buffer; tail_offset++; buffer++; tail_count--; } } if (retval == ERROR_OK) { /* Set start of data buffer, address to write to, and word count */ buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, 1); /* Write tail value into buffer to flash */ retval = target_write_buffer(target, algo_buffer_address, sizeof(tail), tail); } if (retval == ERROR_OK) { /* Execute the flash helper algorithm */ retval = target_run_algorithm(target, 0, NULL, 3, reg_params, algo_base_address, 0, FLASH_TIMEOUT, &cc3220sf_bank->armv7m_info); if (retval != ERROR_OK) LOG_ERROR("cc3220sf: Flash algorithm failed to run"); /* Check that the tail was written to flash */ result = buf_get_u32(reg_params[2].value, 0, 32); if (result != 0) { retval = ERROR_FAIL; LOG_ERROR("cc3220sf: Flash operation failed"); } } } /* Free resources */ destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, algo_working_area); target_free_working_area(target, buffer_working_area); return retval; } static int cc3220sf_probe(struct flash_bank *bank) { struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv; uint32_t base; uint32_t size; unsigned int num_sectors; base = FLASH_BASE_ADDR; size = FLASH_NUM_SECTORS * FLASH_SECTOR_SIZE; num_sectors = FLASH_NUM_SECTORS; free(bank->sectors); bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); if (!bank->sectors) return ERROR_FAIL; bank->base = base; bank->size = size; bank->write_start_alignment = 0; bank->write_end_alignment = 0; bank->num_sectors = num_sectors; for (unsigned int i = 0; i < num_sectors; i++) { bank->sectors[i].offset = i * FLASH_SECTOR_SIZE; bank->sectors[i].size = FLASH_SECTOR_SIZE; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } /* We've successfully recorded the stats on this flash bank */ cc3220sf_bank->probed = true; /* If we fall through to here, then all went well */ return ERROR_OK; } static int cc3220sf_auto_probe(struct flash_bank *bank) { struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv; int retval = ERROR_OK; if (!cc3220sf_bank->probed) retval = cc3220sf_probe(bank); return retval; } static int cc3220sf_info(struct flash_bank *bank, struct command_invocation *cmd) { command_print_sameline(cmd, "CC3220SF with 1MB internal flash\n"); return ERROR_OK; } const struct flash_driver cc3220sf_flash = { .name = "cc3220sf", .flash_bank_command = cc3220sf_flash_bank_command, .erase = cc3220sf_erase, .write = cc3220sf_write, .read = default_flash_read, .probe = cc3220sf_probe, .auto_probe = cc3220sf_auto_probe, .erase_check = default_flash_blank_check, .info = cc3220sf_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/cc3220sf.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2017 by Texas Instruments, Inc. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_CC3220SF_H #define OPENOCD_FLASH_NOR_CC3220SF_H /* CC3220SF device types */ #define CC3220_NO_TYPE 0 /* Device type not determined yet */ #define CC3220_OTHER 1 /* CC3220 variant without flash */ #define CC3220SF 2 /* CC3220SF variant with flash */ /* Flash parameters */ #define FLASH_BASE_ADDR 0x01000000 #define FLASH_SECTOR_SIZE 2048 #define FLASH_NUM_SECTORS 512 /* CC2200SF flash registers */ #define FMA_REGISTER_ADDR 0x400FD000 #define FMC_REGISTER_ADDR 0x400FD008 #define FMC_DEFAULT_VALUE 0xA4420000 #define FMC_ERASE_BIT 0x00000002 #define FMC_MERASE_BIT 0x00000004 #define FMC_ERASE_VALUE (FMC_DEFAULT_VALUE | FMC_ERASE_BIT) #define FMC_MERASE_VALUE (FMC_DEFAULT_VALUE | FMC_MERASE_BIT) #endif /* OPENOCD_FLASH_NOR_CC3220SF_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/cfi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2009 Michael Schwingen * * michael@schwingen.org * * Copyright (C) 2010 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "cfi.h" #include "non_cfi.h" #include <target/arm.h> #include <target/arm7_9_common.h> #include <target/armv7m.h> #include <target/mips32.h> #include <helper/binarybuffer.h> #include <target/algorithm.h> /* defines internal maximum size for code fragment in cfi_intel_write_block() */ #define CFI_MAX_INTEL_CODESIZE 256 /* some id-types with specific handling */ #define AT49BV6416 0x00d6 #define AT49BV6416T 0x00d2 static const struct cfi_unlock_addresses cfi_unlock_addresses[] = { [CFI_UNLOCK_555_2AA] = { .unlock1 = 0x555, .unlock2 = 0x2aa }, [CFI_UNLOCK_5555_2AAA] = { .unlock1 = 0x5555, .unlock2 = 0x2aaa }, }; static const int cfi_status_poll_mask_dq6_dq7 = CFI_STATUS_POLL_MASK_DQ6_DQ7; /* CFI fixups forward declarations */ static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, const void *param); static void cfi_fixup_0002_unlock_addresses(struct flash_bank *bank, const void *param); static void cfi_fixup_reversed_erase_regions(struct flash_bank *bank, const void *param); static void cfi_fixup_0002_write_buffer(struct flash_bank *bank, const void *param); static void cfi_fixup_0002_polling_bits(struct flash_bank *bank, const void *param); /* fixup after reading cmdset 0002 primary query table */ static const struct cfi_fixup cfi_0002_fixups[] = { {CFI_MFR_SST, 0x00D4, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_SST, 0x00D5, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_SST, 0x00D6, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_SST, 0x00D7, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_SST, 0x2780, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_SST, 0x274b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_SST, 0x235f, cfi_fixup_0002_polling_bits, /* 39VF3201C */ &cfi_status_poll_mask_dq6_dq7}, {CFI_MFR_SST, 0x236d, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]}, {CFI_MFR_ATMEL, 0x00C8, cfi_fixup_reversed_erase_regions, NULL}, {CFI_MFR_ST, 0x22C4, cfi_fixup_reversed_erase_regions, NULL}, /* M29W160ET */ {CFI_MFR_FUJITSU, 0x22ea, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]}, {CFI_MFR_FUJITSU, 0x226b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_AMIC, 0xb31a, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]}, {CFI_MFR_MX, 0x225b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]}, {CFI_MFR_EON, 0x225b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]}, {CFI_MFR_AMD, 0x225b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]}, {CFI_MFR_ANY, CFI_ID_ANY, cfi_fixup_0002_erase_regions, NULL}, {CFI_MFR_ST, 0x227E, cfi_fixup_0002_write_buffer, NULL},/* M29W128G */ {0, 0, NULL, NULL} }; /* fixup after reading cmdset 0001 primary query table */ static const struct cfi_fixup cfi_0001_fixups[] = { {0, 0, NULL, NULL} }; static void cfi_fixup(struct flash_bank *bank, const struct cfi_fixup *fixups) { struct cfi_flash_bank *cfi_info = bank->driver_priv; for (const struct cfi_fixup *f = fixups; f->fixup; f++) { if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi_info->manufacturer)) && ((f->id == CFI_ID_ANY) || (f->id == cfi_info->device_id))) f->fixup(bank, f->param); } } uint32_t cfi_flash_address(struct flash_bank *bank, int sector, uint32_t offset) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->x16_as_x8) offset *= 2; /* while the sector list isn't built, only accesses to sector 0 work */ if (sector == 0) return bank->base + offset * bank->bus_width; else { if (!bank->sectors) { LOG_ERROR("BUG: sector list not yet built"); exit(-1); } return bank->base + bank->sectors[sector].offset + offset * bank->bus_width; } } static int cfi_target_write_memory(struct flash_bank *bank, target_addr_t addr, uint32_t count, const uint8_t *buffer) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->write_mem) { return cfi_info->write_mem(bank, addr, count, buffer); } else { return target_write_memory(bank->target, addr, bank->bus_width, count, buffer); } } int cfi_target_read_memory(struct flash_bank *bank, target_addr_t addr, uint32_t count, uint8_t *buffer) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->read_mem) { return cfi_info->read_mem(bank, addr, count, buffer); } else { return target_read_memory(bank->target, addr, bank->bus_width, count, buffer); } } static void cfi_command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf) { struct cfi_flash_bank *cfi_info = bank->driver_priv; /* clear whole buffer, to ensure bits that exceed the bus_width * are set to zero */ for (size_t i = 0; i < CFI_MAX_BUS_WIDTH; i++) cmd_buf[i] = 0; if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) { for (unsigned int i = bank->bus_width; i > 0; i--) *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd; } else { for (unsigned int i = 1; i <= bank->bus_width; i++) *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd; } } int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address) { uint8_t command[CFI_MAX_BUS_WIDTH]; cfi_command(bank, cmd, command); return cfi_target_write_memory(bank, address, 1, command); } /* read unsigned 8-bit value from the bank * flash banks are expected to be made of similar chips * the query result should be the same for all */ static int cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset, uint8_t *val) { struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH]; int retval; retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset), 1, data); if (retval != ERROR_OK) return retval; if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) *val = data[0]; else *val = data[bank->bus_width - 1]; return ERROR_OK; } /* read unsigned 8-bit value from the bank * in case of a bank made of multiple chips, * the individual values are ORed */ static int cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset, uint8_t *val) { struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH]; int retval; retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset), 1, data); if (retval != ERROR_OK) return retval; if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) { for (unsigned int i = 0; i < bank->bus_width / bank->chip_width; i++) data[0] |= data[i]; *val = data[0]; } else { uint8_t value = 0; for (unsigned int i = 0; i < bank->bus_width / bank->chip_width; i++) value |= data[bank->bus_width - 1 - i]; *val = value; } return ERROR_OK; } static int cfi_query_u16(struct flash_bank *bank, int sector, uint32_t offset, uint16_t *val) { struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH * 2]; int retval; if (cfi_info->x16_as_x8) { for (uint8_t i = 0; i < 2; i++) { retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset + i), 1, &data[i * bank->bus_width]); if (retval != ERROR_OK) return retval; } } else { retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset), 2, data); if (retval != ERROR_OK) return retval; } if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) *val = data[0] | data[bank->bus_width] << 8; else *val = data[bank->bus_width - 1] | data[(2 * bank->bus_width) - 1] << 8; return ERROR_OK; } static int cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offset, uint32_t *val) { struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH * 4]; int retval; if (cfi_info->x16_as_x8) { for (uint8_t i = 0; i < 4; i++) { retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset + i), 1, &data[i * bank->bus_width]); if (retval != ERROR_OK) return retval; } } else { retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset), 4, data); if (retval != ERROR_OK) return retval; } if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) *val = data[0] | data[bank->bus_width] << 8 | data[bank->bus_width * 2] << 16 | data[bank->bus_width * 3] << 24; else *val = data[bank->bus_width - 1] | data[(2 * bank->bus_width) - 1] << 8 | data[(3 * bank->bus_width) - 1] << 16 | data[(4 * bank->bus_width) - 1] << 24; return ERROR_OK; } int cfi_reset(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; int retval = ERROR_OK; retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; if (cfi_info->manufacturer == 0x20 && (cfi_info->device_id == 0x227E || cfi_info->device_id == 0x7E)) { /* Numonix M29W128G is cmd 0xFF intolerant - causes internal undefined state * so we send an extra 0xF0 reset to fix the bug */ retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x00)); if (retval != ERROR_OK) return retval; } return retval; } static void cfi_intel_clear_status_register(struct flash_bank *bank) { cfi_send_command(bank, 0x50, cfi_flash_address(bank, 0, 0x0)); } static int cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout, uint8_t *val) { uint8_t status; int retval = ERROR_OK; for (;; ) { if (timeout-- < 0) { LOG_ERROR("timeout while waiting for WSM to become ready"); return ERROR_FAIL; } retval = cfi_get_u8(bank, 0, 0x0, &status); if (retval != ERROR_OK) return retval; if (status & 0x80) break; alive_sleep(1); } /* mask out bit 0 (reserved) */ status = status & 0xfe; LOG_DEBUG("status: 0x%x", status); if (status != 0x80) { LOG_ERROR("status register: 0x%x", status); if (status & 0x2) LOG_ERROR("Block Lock-Bit Detected, Operation Abort"); if (status & 0x4) LOG_ERROR("Program suspended"); if (status & 0x8) LOG_ERROR("Low Programming Voltage Detected, Operation Aborted"); if (status & 0x10) LOG_ERROR("Program Error / Error in Setting Lock-Bit"); if (status & 0x20) LOG_ERROR("Error in Block Erasure or Clear Lock-Bits"); if (status & 0x40) LOG_ERROR("Block Erase Suspended"); cfi_intel_clear_status_register(bank); retval = ERROR_FAIL; } *val = status; return retval; } int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout) { uint8_t status, oldstatus; struct cfi_flash_bank *cfi_info = bank->driver_priv; int retval; retval = cfi_get_u8(bank, 0, 0x0, &oldstatus); if (retval != ERROR_OK) return retval; do { retval = cfi_get_u8(bank, 0, 0x0, &status); if (retval != ERROR_OK) return retval; if ((status ^ oldstatus) & 0x40) { if (status & cfi_info->status_poll_mask & 0x20) { retval = cfi_get_u8(bank, 0, 0x0, &oldstatus); if (retval != ERROR_OK) return retval; retval = cfi_get_u8(bank, 0, 0x0, &status); if (retval != ERROR_OK) return retval; if ((status ^ oldstatus) & 0x40) { LOG_ERROR("dq5 timeout, status: 0x%x", status); return ERROR_FLASH_OPERATION_FAILED; } else { LOG_DEBUG("status: 0x%x", status); return ERROR_OK; } } } else {/* no toggle: finished, OK */ LOG_DEBUG("status: 0x%x", status); return ERROR_OK; } oldstatus = status; alive_sleep(1); } while (timeout-- > 0); LOG_ERROR("timeout, status: 0x%x", status); return ERROR_FLASH_BUSY; } static int cfi_read_intel_pri_ext(struct flash_bank *bank) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_intel_pri_ext *pri_ext; free(cfi_info->pri_ext); pri_ext = malloc(sizeof(struct cfi_intel_pri_ext)); if (!pri_ext) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } cfi_info->pri_ext = pri_ext; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0, &pri_ext->pri[0]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1, &pri_ext->pri[1]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2, &pri_ext->pri[2]); if (retval != ERROR_OK) return retval; if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I')) { retval = cfi_reset(bank); if (retval != ERROR_OK) return retval; LOG_ERROR("Could not read bank flash bank information"); return ERROR_FLASH_BANK_INVALID; } retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3, &pri_ext->major_version); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4, &pri_ext->minor_version); if (retval != ERROR_OK) return retval; LOG_DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); retval = cfi_query_u32(bank, 0, cfi_info->pri_addr + 5, &pri_ext->feature_support); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9, &pri_ext->suspend_cmd_support); if (retval != ERROR_OK) return retval; retval = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xa, &pri_ext->blk_status_reg_mask); if (retval != ERROR_OK) return retval; LOG_DEBUG("feature_support: 0x%" PRIx32 ", suspend_cmd_support: " "0x%x, blk_status_reg_mask: 0x%x", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask); retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xc, &pri_ext->vcc_optimal); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xd, &pri_ext->vpp_optimal); if (retval != ERROR_OK) return retval; LOG_DEBUG("Vcc opt: %x.%x, Vpp opt: %u.%x", (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f, (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f); retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xe, &pri_ext->num_protection_fields); if (retval != ERROR_OK) return retval; if (pri_ext->num_protection_fields != 1) { LOG_WARNING("expected one protection register field, but found %i", pri_ext->num_protection_fields); } retval = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xf, &pri_ext->prot_reg_addr); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x11, &pri_ext->fact_prot_reg_size); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x12, &pri_ext->user_prot_reg_size); if (retval != ERROR_OK) return retval; LOG_DEBUG("protection_fields: %i, prot_reg_addr: 0x%x, " "factory pre-programmed: %i, user programmable: %i", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size); return ERROR_OK; } static int cfi_read_spansion_pri_ext(struct flash_bank *bank) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext; free(cfi_info->pri_ext); pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext)); if (!pri_ext) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } cfi_info->pri_ext = pri_ext; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0, &pri_ext->pri[0]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1, &pri_ext->pri[1]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2, &pri_ext->pri[2]); if (retval != ERROR_OK) return retval; /* default values for implementation specific workarounds */ pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1; pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2; pri_ext->_reversed_geometry = 0; if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I')) { retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("Could not read spansion bank information"); return ERROR_FLASH_BANK_INVALID; } retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3, &pri_ext->major_version); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4, &pri_ext->minor_version); if (retval != ERROR_OK) return retval; LOG_DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5, &pri_ext->silicon_revision); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6, &pri_ext->erase_suspend); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7, &pri_ext->blk_prot); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 8, &pri_ext->tmp_blk_unprotected); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9, &pri_ext->blk_prot_unprot); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 10, &pri_ext->simultaneous_ops); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 11, &pri_ext->burst_mode); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 12, &pri_ext->page_mode); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 13, &pri_ext->vpp_min); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 14, &pri_ext->vpp_max); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 15, &pri_ext->top_bottom); if (retval != ERROR_OK) return retval; LOG_DEBUG("Silicon Revision: 0x%x, Erase Suspend: 0x%x, Block protect: 0x%x", pri_ext->silicon_revision, pri_ext->erase_suspend, pri_ext->blk_prot); LOG_DEBUG("Temporary Unprotect: 0x%x, Block Protect Scheme: 0x%x, " "Simultaneous Ops: 0x%x", pri_ext->tmp_blk_unprotected, pri_ext->blk_prot_unprot, pri_ext->simultaneous_ops); LOG_DEBUG("Burst Mode: 0x%x, Page Mode: 0x%x, ", pri_ext->burst_mode, pri_ext->page_mode); LOG_DEBUG("Vpp min: %u.%x, Vpp max: %u.%x", (pri_ext->vpp_min & 0xf0) >> 4, pri_ext->vpp_min & 0x0f, (pri_ext->vpp_max & 0xf0) >> 4, pri_ext->vpp_max & 0x0f); LOG_DEBUG("WP# protection 0x%x", pri_ext->top_bottom); return ERROR_OK; } static int cfi_read_atmel_pri_ext(struct flash_bank *bank) { int retval; struct cfi_atmel_pri_ext atmel_pri_ext; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext; free(cfi_info->pri_ext); pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext)); if (!pri_ext) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } /* ATMEL devices use the same CFI primary command set (0x2) as AMD/Spansion, * but a different primary extended query table. * We read the atmel table, and prepare a valid AMD/Spansion query table. */ memset(pri_ext, 0, sizeof(struct cfi_spansion_pri_ext)); cfi_info->pri_ext = pri_ext; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0, &atmel_pri_ext.pri[0]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1, &atmel_pri_ext.pri[1]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2, &atmel_pri_ext.pri[2]); if (retval != ERROR_OK) return retval; if ((atmel_pri_ext.pri[0] != 'P') || (atmel_pri_ext.pri[1] != 'R') || (atmel_pri_ext.pri[2] != 'I')) { retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("Could not read atmel bank information"); return ERROR_FLASH_BANK_INVALID; } pri_ext->pri[0] = atmel_pri_ext.pri[0]; pri_ext->pri[1] = atmel_pri_ext.pri[1]; pri_ext->pri[2] = atmel_pri_ext.pri[2]; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3, &atmel_pri_ext.major_version); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4, &atmel_pri_ext.minor_version); if (retval != ERROR_OK) return retval; LOG_DEBUG("pri: '%c%c%c', version: %c.%c", atmel_pri_ext.pri[0], atmel_pri_ext.pri[1], atmel_pri_ext.pri[2], atmel_pri_ext.major_version, atmel_pri_ext.minor_version); pri_ext->major_version = atmel_pri_ext.major_version; pri_ext->minor_version = atmel_pri_ext.minor_version; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5, &atmel_pri_ext.features); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6, &atmel_pri_ext.bottom_boot); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7, &atmel_pri_ext.burst_mode); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 8, &atmel_pri_ext.page_mode); if (retval != ERROR_OK) return retval; LOG_DEBUG( "features: 0x%2.2x, bottom_boot: 0x%2.2x, burst_mode: 0x%2.2x, page_mode: 0x%2.2x", atmel_pri_ext.features, atmel_pri_ext.bottom_boot, atmel_pri_ext.burst_mode, atmel_pri_ext.page_mode); if (atmel_pri_ext.features & 0x02) pri_ext->erase_suspend = 2; /* some chips got it backwards... */ if (cfi_info->device_id == AT49BV6416 || cfi_info->device_id == AT49BV6416T) { if (atmel_pri_ext.bottom_boot) pri_ext->top_bottom = 3; else pri_ext->top_bottom = 2; } else { if (atmel_pri_ext.bottom_boot) pri_ext->top_bottom = 2; else pri_ext->top_bottom = 3; } pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1; pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2; return ERROR_OK; } static int cfi_read_0002_pri_ext(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->manufacturer == CFI_MFR_ATMEL) return cfi_read_atmel_pri_ext(bank); else return cfi_read_spansion_pri_ext(bank); } static int cfi_spansion_info(struct flash_bank *bank, struct command_invocation *cmd) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; command_print_sameline(cmd, "\nSpansion primary algorithm extend information:\n"); command_print_sameline(cmd, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); command_print_sameline(cmd, "Silicon Rev.: 0x%x, Address Sensitive unlock: 0x%x\n", (pri_ext->silicon_revision) >> 2, (pri_ext->silicon_revision) & 0x03); command_print_sameline(cmd, "Erase Suspend: 0x%x, Sector Protect: 0x%x\n", pri_ext->erase_suspend, pri_ext->blk_prot); command_print_sameline(cmd, "VppMin: %u.%x, VppMax: %u.%x\n", (pri_ext->vpp_min & 0xf0) >> 4, pri_ext->vpp_min & 0x0f, (pri_ext->vpp_max & 0xf0) >> 4, pri_ext->vpp_max & 0x0f); return ERROR_OK; } static int cfi_intel_info(struct flash_bank *bank, struct command_invocation *cmd) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext; command_print_sameline(cmd, "\nintel primary algorithm extend information:\n"); command_print_sameline(cmd, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); command_print_sameline(cmd, "feature_support: 0x%" PRIx32 ", " "suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x\n", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask); command_print_sameline(cmd, "Vcc opt: %x.%x, Vpp opt: %u.%x\n", (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f, (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f); command_print_sameline(cmd, "protection_fields: %i, prot_reg_addr: 0x%x, " "factory pre-programmed: %i, user programmable: %i\n", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size); return ERROR_OK; } int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char **argv) { struct cfi_flash_bank *cfi_info; bool bus_swap = false; if (argc < 6) return ERROR_COMMAND_SYNTAX_ERROR; /* both widths must: * - not exceed max value; * - not be null; * - be equal to a power of 2. * bus must be wide enough to hold one chip */ if ((bank->chip_width > CFI_MAX_CHIP_WIDTH) || (bank->bus_width > CFI_MAX_BUS_WIDTH) || (bank->chip_width == 0) || (bank->bus_width == 0) || (bank->chip_width & (bank->chip_width - 1)) || (bank->bus_width & (bank->bus_width - 1)) || (bank->chip_width > bank->bus_width)) { LOG_ERROR("chip and bus width have to specified in bytes"); return ERROR_FLASH_BANK_INVALID; } cfi_info = calloc(1, sizeof(struct cfi_flash_bank)); if (!cfi_info) { LOG_ERROR("No memory for flash bank info"); return ERROR_FAIL; } bank->driver_priv = cfi_info; for (unsigned i = 6; i < argc; i++) { if (strcmp(argv[i], "x16_as_x8") == 0) cfi_info->x16_as_x8 = true; else if (strcmp(argv[i], "data_swap") == 0) cfi_info->data_swap = true; else if (strcmp(argv[i], "bus_swap") == 0) bus_swap = true; else if (strcmp(argv[i], "jedec_probe") == 0) cfi_info->jedec_probe = true; } if (bus_swap) cfi_info->endianness = bank->target->endianness == TARGET_LITTLE_ENDIAN ? TARGET_BIG_ENDIAN : TARGET_LITTLE_ENDIAN; else cfi_info->endianness = bank->target->endianness; /* bank wasn't probed yet */ cfi_info->qry[0] = 0xff; return ERROR_OK; } /* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#> [options] */ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command) { return cfi_flash_bank_cmd(bank, CMD_ARGC, CMD_ARGV); } static int cfi_intel_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; cfi_intel_clear_status_register(bank); for (unsigned int i = first; i <= last; i++) { retval = cfi_send_command(bank, 0x20, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0xd0, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; uint8_t status; retval = cfi_intel_wait_status_busy(bank, cfi_info->block_erase_timeout, &status); if (retval != ERROR_OK) return retval; if (status != 0x80) { retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("couldn't erase block %u of flash bank at base " TARGET_ADDR_FMT, i, bank->base); return ERROR_FLASH_OPERATION_FAILED; } } return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); } int cfi_spansion_unlock_seq(struct flash_bank *bank) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; retval = cfi_send_command(bank, 0xaa, cfi_flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x55, cfi_flash_address(bank, 0, pri_ext->_unlock2)); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int cfi_spansion_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; for (unsigned int i = first; i <= last; i++) { retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x80, cfi_flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x30, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; if (cfi_spansion_wait_status_busy(bank, cfi_info->block_erase_timeout) != ERROR_OK) { retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("couldn't erase block %i of flash bank at base " TARGET_ADDR_FMT, i, bank->base); return ERROR_FLASH_OPERATION_FAILED; } } return cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); } int cfi_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((last < first) || (last >= bank->num_sectors)) return ERROR_FLASH_SECTOR_INVALID; if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; switch (cfi_info->pri_id) { case 1: case 3: return cfi_intel_erase(bank, first, last); case 2: return cfi_spansion_erase(bank, first, last); default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } return ERROR_OK; } static int cfi_intel_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext; int retry = 0; /* if the device supports neither legacy lock/unlock (bit 3) nor * instant individual block locking (bit 5). */ if (!(pri_ext->feature_support & 0x28)) { LOG_ERROR("lock/unlock not supported on flash"); return ERROR_FLASH_OPERATION_FAILED; } cfi_intel_clear_status_register(bank); for (unsigned int i = first; i <= last; i++) { retval = cfi_send_command(bank, 0x60, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; if (set) { retval = cfi_send_command(bank, 0x01, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; bank->sectors[i].is_protected = 1; } else { retval = cfi_send_command(bank, 0xd0, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; bank->sectors[i].is_protected = 0; } /* instant individual block locking doesn't require reading of the status register **/ if (!(pri_ext->feature_support & 0x20)) { /* Clear lock bits operation may take up to 1.4s */ uint8_t status; retval = cfi_intel_wait_status_busy(bank, 1400, &status); if (retval != ERROR_OK) return retval; } else { uint8_t block_status; /* read block lock bit, to verify status */ retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, 0x55)); if (retval != ERROR_OK) return retval; retval = cfi_get_u8(bank, i, 0x2, &block_status); if (retval != ERROR_OK) return retval; if ((block_status & 0x1) != set) { LOG_ERROR( "couldn't change block lock status (set = %i, block_status = 0x%2.2x)", set, block_status); retval = cfi_send_command(bank, 0x70, cfi_flash_address(bank, 0, 0x55)); if (retval != ERROR_OK) return retval; uint8_t status; retval = cfi_intel_wait_status_busy(bank, 10, &status); if (retval != ERROR_OK) return retval; if (retry > 10) return ERROR_FLASH_OPERATION_FAILED; else { i--; retry++; } } } } /* if the device doesn't support individual block lock bits set/clear, * all blocks have been unlocked in parallel, so we set those that should be protected */ if ((!set) && (!(pri_ext->feature_support & 0x20))) { /* FIX!!! this code path is broken!!! * * The correct approach is: * * 1. read out current protection status * * 2. override read out protection status w/unprotected. * * 3. re-protect what should be protected. * */ for (unsigned int i = 0; i < bank->num_sectors; i++) { if (bank->sectors[i].is_protected == 1) { cfi_intel_clear_status_register(bank); retval = cfi_send_command(bank, 0x60, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x01, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; uint8_t status; retval = cfi_intel_wait_status_busy(bank, 100, &status); if (retval != ERROR_OK) return retval; } } } return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); } int cfi_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; switch (cfi_info->pri_id) { case 1: case 3: return cfi_intel_protect(bank, set, first, last); default: LOG_WARNING("protect: cfi primary command set %i unsupported", cfi_info->pri_id); return ERROR_OK; } } static uint32_t cfi_command_val(struct flash_bank *bank, uint8_t cmd) { struct target *target = bank->target; uint8_t buf[CFI_MAX_BUS_WIDTH]; cfi_command(bank, cmd, buf); switch (bank->bus_width) { case 1: return buf[0]; case 2: return target_buffer_get_u16(target, buf); case 4: return target_buffer_get_u32(target, buf); default: LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", bank->bus_width); return 0; } } static int cfi_intel_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t address, uint32_t count) { struct target *target = bank->target; struct reg_param reg_params[7]; struct arm_algorithm arm_algo; struct working_area *write_algorithm; struct working_area *source = NULL; uint32_t buffer_size = 32768; uint32_t write_command_val, busy_pattern_val, error_pattern_val; /* algorithm register usage: * r0: source address (in RAM) * r1: target address (in Flash) * r2: count * r3: flash write command * r4: status byte (returned to host) * r5: busy test pattern * r6: error test pattern */ /* see contrib/loaders/flash/armv4_5_cfi_intel_32.s for src */ static const uint32_t word_32_code[] = { 0xe4904004, /* loop: ldr r4, [r0], #4 */ 0xe5813000, /* str r3, [r1] */ 0xe5814000, /* str r4, [r1] */ 0xe5914000, /* busy: ldr r4, [r1] */ 0xe0047005, /* and r7, r4, r5 */ 0xe1570005, /* cmp r7, r5 */ 0x1afffffb, /* bne busy */ 0xe1140006, /* tst r4, r6 */ 0x1a000003, /* bne done */ 0xe2522001, /* subs r2, r2, #1 */ 0x0a000001, /* beq done */ 0xe2811004, /* add r1, r1 #4 */ 0xeafffff2, /* b loop */ 0xeafffffe /* done: b -2 */ }; /* see contrib/loaders/flash/armv4_5_cfi_intel_16.s for src */ static const uint32_t word_16_code[] = { 0xe0d040b2, /* loop: ldrh r4, [r0], #2 */ 0xe1c130b0, /* strh r3, [r1] */ 0xe1c140b0, /* strh r4, [r1] */ 0xe1d140b0, /* busy ldrh r4, [r1] */ 0xe0047005, /* and r7, r4, r5 */ 0xe1570005, /* cmp r7, r5 */ 0x1afffffb, /* bne busy */ 0xe1140006, /* tst r4, r6 */ 0x1a000003, /* bne done */ 0xe2522001, /* subs r2, r2, #1 */ 0x0a000001, /* beq done */ 0xe2811002, /* add r1, r1 #2 */ 0xeafffff2, /* b loop */ 0xeafffffe /* done: b -2 */ }; /* see contrib/loaders/flash/armv4_5_cfi_intel_8.s for src */ static const uint32_t word_8_code[] = { 0xe4d04001, /* loop: ldrb r4, [r0], #1 */ 0xe5c13000, /* strb r3, [r1] */ 0xe5c14000, /* strb r4, [r1] */ 0xe5d14000, /* busy ldrb r4, [r1] */ 0xe0047005, /* and r7, r4, r5 */ 0xe1570005, /* cmp r7, r5 */ 0x1afffffb, /* bne busy */ 0xe1140006, /* tst r4, r6 */ 0x1a000003, /* bne done */ 0xe2522001, /* subs r2, r2, #1 */ 0x0a000001, /* beq done */ 0xe2811001, /* add r1, r1 #1 */ 0xeafffff2, /* b loop */ 0xeafffffe /* done: b -2 */ }; uint8_t target_code[4*CFI_MAX_INTEL_CODESIZE]; const uint32_t *target_code_src; uint32_t target_code_size; int retval = ERROR_OK; /* check we have a supported arch */ if (is_arm(target_to_arm(target))) { /* All other ARM CPUs have 32 bit instructions */ arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; } else { LOG_ERROR("Unknown architecture"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } cfi_intel_clear_status_register(bank); /* If we are setting up the write_algorithm, we need target_code_src * if not we only need target_code_size. */ /* However, we don't want to create multiple code paths, so we * do the unnecessary evaluation of target_code_src, which the * compiler will probably nicely optimize away if not needed */ /* prepare algorithm code for target endian */ switch (bank->bus_width) { case 1: target_code_src = word_8_code; target_code_size = sizeof(word_8_code); break; case 2: target_code_src = word_16_code; target_code_size = sizeof(word_16_code); break; case 4: target_code_src = word_32_code; target_code_size = sizeof(word_32_code); break; default: LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", bank->bus_width); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* flash write code */ if (target_code_size > sizeof(target_code)) { LOG_WARNING("Internal error - target code buffer to small. " "Increase CFI_MAX_INTEL_CODESIZE and recompile."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } target_buffer_set_u32_array(target, target_code, target_code_size / 4, target_code_src); /* Get memory for block write handler */ retval = target_alloc_working_area(target, target_code_size, &write_algorithm); if (retval != ERROR_OK) { LOG_WARNING("No working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* write algorithm code to working area */ retval = target_write_buffer(target, write_algorithm->address, target_code_size, target_code); if (retval != ERROR_OK) { LOG_ERROR("Unable to write block write code to target"); goto cleanup; } /* Get a workspace buffer for the data to flash starting with 32k size. * Half size until buffer would be smaller 256 Bytes then fail back */ /* FIXME Why 256 bytes, why not 32 bytes (smallest flash write page */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { LOG_WARNING( "no large enough working area available, can't do block memory writes"); retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; goto cleanup; } } /* setup algo registers */ init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_IN); init_reg_param(®_params[5], "r5", 32, PARAM_OUT); init_reg_param(®_params[6], "r6", 32, PARAM_OUT); /* prepare command and status register patterns */ write_command_val = cfi_command_val(bank, 0x40); busy_pattern_val = cfi_command_val(bank, 0x80); error_pattern_val = cfi_command_val(bank, 0x7e); LOG_DEBUG("Using target buffer at " TARGET_ADDR_FMT " and of size 0x%04" PRIx32, source->address, buffer_size); /* Programming main loop */ while (count > 0) { uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count; uint32_t wsm_error; retval = target_write_buffer(target, source->address, thisrun_count, buffer); if (retval != ERROR_OK) goto cleanup; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width); buf_set_u32(reg_params[3].value, 0, 32, write_command_val); buf_set_u32(reg_params[5].value, 0, 32, busy_pattern_val); buf_set_u32(reg_params[6].value, 0, 32, error_pattern_val); LOG_DEBUG("Write 0x%04" PRIx32 " bytes to flash at 0x%08" PRIx32, thisrun_count, address); /* Execute algorithm, assume breakpoint for last instruction */ retval = target_run_algorithm(target, 0, NULL, 7, reg_params, write_algorithm->address, write_algorithm->address + target_code_size - sizeof(uint32_t), 10000, /* 10s should be enough for max. 32k of data */ &arm_algo); /* On failure try a fall back to direct word writes */ if (retval != ERROR_OK) { cfi_intel_clear_status_register(bank); LOG_ERROR( "Execution of flash algorithm failed. Can't fall back. Please report."); retval = ERROR_FLASH_OPERATION_FAILED; /* retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; */ /* FIXME To allow fall back or recovery, we must save the actual status * somewhere, so that a higher level code can start recovery. */ goto cleanup; } /* Check return value from algo code */ wsm_error = buf_get_u32(reg_params[4].value, 0, 32) & error_pattern_val; if (wsm_error) { /* read status register (outputs debug information) */ uint8_t status; cfi_intel_wait_status_busy(bank, 100, &status); cfi_intel_clear_status_register(bank); retval = ERROR_FLASH_OPERATION_FAILED; goto cleanup; } buffer += thisrun_count; address += thisrun_count; count -= thisrun_count; keep_alive(); } /* free up resources */ cleanup: target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); destroy_reg_param(®_params[6]); return retval; } static int cfi_spansion_write_block_mips(struct flash_bank *bank, const uint8_t *buffer, uint32_t address, uint32_t count) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; struct target *target = bank->target; struct reg_param reg_params[10]; struct mips32_algorithm mips32_info; struct working_area *write_algorithm; struct working_area *source; uint32_t buffer_size = 32768; uint32_t status; int retval = ERROR_OK; /* input parameters - * 4 A0 = source address * 5 A1 = destination address * 6 A2 = number of writes * 7 A3 = flash write command * 8 T0 = constant to mask DQ7 bits (also used for Dq5 with shift) * output parameters - * 9 T1 = 0x80 ok 0x00 bad * temp registers - * 10 T2 = value read from flash to test status * 11 T3 = holding register * unlock registers - * 12 T4 = unlock1_addr * 13 T5 = unlock1_cmd * 14 T6 = unlock2_addr * 15 T7 = unlock2_cmd */ static const uint32_t mips_word_16_code[] = { /* start: */ MIPS32_LHU(0, 9, 0, 4), /* lhu $t1, ($a0) ; out = &saddr */ MIPS32_ADDI(0, 4, 4, 2), /* addi $a0, $a0, 2 ; saddr += 2 */ MIPS32_SH(0, 13, 0, 12), /* sh $t5, ($t4) ; *fl_unl_addr1 = fl_unl_cmd1 */ MIPS32_SH(0, 15, 0, 14), /* sh $t7, ($t6) ; *fl_unl_addr2 = fl_unl_cmd2 */ MIPS32_SH(0, 7, 0, 12), /* sh $a3, ($t4) ; *fl_unl_addr1 = fl_write_cmd */ MIPS32_SH(0, 9, 0, 5), /* sh $t1, ($a1) ; *daddr = out */ MIPS32_NOP, /* nop */ /* busy: */ MIPS32_LHU(0, 10, 0, 5), /* lhu $t2, ($a1) ; temp1 = *daddr */ MIPS32_XOR(0, 11, 9, 10), /* xor $t3, $a0, $t2 ; temp2 = out ^ temp1; */ MIPS32_AND(0, 11, 8, 11), /* and $t3, $t0, $t3 ; temp2 = temp2 & DQ7mask */ MIPS32_BNE(0, 11, 8, 13), /* bne $t3, $t0, cont ; if (temp2 != DQ7mask) goto cont */ MIPS32_NOP, /* nop */ MIPS32_SRL(0, 10, 8, 2), /* srl $t2,$t0,2 ; temp1 = DQ7mask >> 2 */ MIPS32_AND(0, 11, 10, 11), /* and $t3, $t2, $t3 ; temp2 = temp2 & temp1 */ MIPS32_BNE(0, 11, 10, NEG16(8)), /* bne $t3, $t2, busy ; if (temp2 != temp1) goto busy */ MIPS32_NOP, /* nop */ MIPS32_LHU(0, 10, 0, 5), /* lhu $t2, ($a1) ; temp1 = *daddr */ MIPS32_XOR(0, 11, 9, 10), /* xor $t3, $a0, $t2 ; temp2 = out ^ temp1; */ MIPS32_AND(0, 11, 8, 11), /* and $t3, $t0, $t3 ; temp2 = temp2 & DQ7mask */ MIPS32_BNE(0, 11, 8, 4), /* bne $t3, $t0, cont ; if (temp2 != DQ7mask) goto cont */ MIPS32_NOP, /* nop */ MIPS32_XOR(0, 9, 9, 9), /* xor $t1, $t1, $t1 ; out = 0 */ MIPS32_BEQ(0, 9, 0, 11), /* beq $t1, $zero, done ; if (out == 0) goto done */ MIPS32_NOP, /* nop */ /* cont: */ MIPS32_ADDI(0, 6, 6, NEG16(1)), /* addi, $a2, $a2, -1 ; numwrites-- */ MIPS32_BNE(0, 6, 0, 5), /* bne $a2, $zero, cont2 ; if (numwrite != 0) goto cont2 */ MIPS32_NOP, /* nop */ MIPS32_LUI(0, 9, 0), /* lui $t1, 0 */ MIPS32_ORI(0, 9, 9, 0x80), /* ori $t1, $t1, 0x80 ; out = 0x80 */ MIPS32_B(0, 4), /* b done ; goto done */ MIPS32_NOP, /* nop */ /* cont2: */ MIPS32_ADDI(0, 5, 5, 2), /* addi $a0, $a0, 2 ; daddr += 2 */ MIPS32_B(0, NEG16(33)), /* b start ; goto start */ MIPS32_NOP, /* nop */ /* done: */ MIPS32_SDBBP(0), /* sdbbp ; break(); */ }; mips32_info.common_magic = MIPS32_COMMON_MAGIC; mips32_info.isa_mode = MIPS32_ISA_MIPS32; int target_code_size = 0; const uint32_t *target_code_src = NULL; switch (bank->bus_width) { case 2: /* Check for DQ5 support */ if (cfi_info->status_poll_mask & (1 << 5)) { target_code_src = mips_word_16_code; target_code_size = sizeof(mips_word_16_code); } else { LOG_ERROR("Need DQ5 support"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* target_code_src = mips_word_16_code_dq7only; */ /* target_code_size = sizeof(mips_word_16_code_dq7only); */ } break; default: LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", bank->bus_width); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* flash write code */ uint8_t *target_code; /* convert bus-width dependent algorithm code to correct endianness */ target_code = malloc(target_code_size); if (!target_code) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } target_buffer_set_u32_array(target, target_code, target_code_size / 4, target_code_src); /* allocate working area */ retval = target_alloc_working_area(target, target_code_size, &write_algorithm); if (retval != ERROR_OK) { free(target_code); return retval; } /* write algorithm code to working area */ retval = target_write_buffer(target, write_algorithm->address, target_code_size, target_code); if (retval != ERROR_OK) { free(target_code); return retval; } free(target_code); /* the following code still assumes target code is fixed 24*4 bytes */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING( "not enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } init_reg_param(®_params[0], "r4", 32, PARAM_OUT); init_reg_param(®_params[1], "r5", 32, PARAM_OUT); init_reg_param(®_params[2], "r6", 32, PARAM_OUT); init_reg_param(®_params[3], "r7", 32, PARAM_OUT); init_reg_param(®_params[4], "r8", 32, PARAM_OUT); init_reg_param(®_params[5], "r9", 32, PARAM_IN); init_reg_param(®_params[6], "r12", 32, PARAM_OUT); init_reg_param(®_params[7], "r13", 32, PARAM_OUT); init_reg_param(®_params[8], "r14", 32, PARAM_OUT); init_reg_param(®_params[9], "r15", 32, PARAM_OUT); while (count > 0) { uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count; retval = target_write_buffer(target, source->address, thisrun_count, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width); buf_set_u32(reg_params[3].value, 0, 32, cfi_command_val(bank, 0xA0)); buf_set_u32(reg_params[4].value, 0, 32, cfi_command_val(bank, 0x80)); buf_set_u32(reg_params[6].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock1)); buf_set_u32(reg_params[7].value, 0, 32, 0xaaaaaaaa); buf_set_u32(reg_params[8].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock2)); buf_set_u32(reg_params[9].value, 0, 32, 0x55555555); retval = target_run_algorithm(target, 0, NULL, 10, reg_params, write_algorithm->address, write_algorithm->address + ((target_code_size) - 4), 10000, &mips32_info); if (retval != ERROR_OK) break; status = buf_get_u32(reg_params[5].value, 0, 32); if (status != 0x80) { LOG_ERROR("flash write block failed status: 0x%" PRIx32, status); retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count; address += thisrun_count; count -= thisrun_count; } target_free_all_working_areas(target); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); destroy_reg_param(®_params[6]); destroy_reg_param(®_params[7]); destroy_reg_param(®_params[8]); destroy_reg_param(®_params[9]); return retval; } static int cfi_spansion_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t address, uint32_t count) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; struct target *target = bank->target; struct reg_param reg_params[10]; void *arm_algo; struct arm_algorithm armv4_5_algo; struct armv7m_algorithm armv7m_algo; struct working_area *write_algorithm; struct working_area *source; uint32_t buffer_size = 32768; uint32_t status; int retval = ERROR_OK; /* input parameters - * R0 = source address * R1 = destination address * R2 = number of writes * R3 = flash write command * R4 = constant to mask DQ7 bits (also used for Dq5 with shift) * output parameters - * R5 = 0x80 ok 0x00 bad * temp registers - * R6 = value read from flash to test status * R7 = holding register * unlock registers - * R8 = unlock1_addr * R9 = unlock1_cmd * R10 = unlock2_addr * R11 = unlock2_cmd */ /* see contrib/loaders/flash/armv4_5_cfi_span_32.s for src */ static const uint32_t armv4_5_word_32_code[] = { /* 00008100 <sp_32_code>: */ 0xe4905004, /* ldr r5, [r0], #4 */ 0xe5889000, /* str r9, [r8] */ 0xe58ab000, /* str r11, [r10] */ 0xe5883000, /* str r3, [r8] */ 0xe5815000, /* str r5, [r1] */ 0xe1a00000, /* nop */ /* 00008110 <sp_32_busy>: */ 0xe5916000, /* ldr r6, [r1] */ 0xe0257006, /* eor r7, r5, r6 */ 0xe0147007, /* ands r7, r4, r7 */ 0x0a000007, /* beq 8140 <sp_32_cont> ; b if DQ7 == Data7 */ 0xe0166124, /* ands r6, r6, r4, lsr #2 */ 0x0afffff9, /* beq 8110 <sp_32_busy> ; b if DQ5 low */ 0xe5916000, /* ldr r6, [r1] */ 0xe0257006, /* eor r7, r5, r6 */ 0xe0147007, /* ands r7, r4, r7 */ 0x0a000001, /* beq 8140 <sp_32_cont> ; b if DQ7 == Data7 */ 0xe3a05000, /* mov r5, #0 ; 0x0 - return 0x00, error */ 0x1a000004, /* bne 8154 <sp_32_done> */ /* 00008140 <sp_32_cont>: */ 0xe2522001, /* subs r2, r2, #1 ; 0x1 */ 0x03a05080, /* moveq r5, #128 ; 0x80 */ 0x0a000001, /* beq 8154 <sp_32_done> */ 0xe2811004, /* add r1, r1, #4 ; 0x4 */ 0xeaffffe8, /* b 8100 <sp_32_code> */ /* 00008154 <sp_32_done>: */ 0xeafffffe /* b 8154 <sp_32_done> */ }; /* see contrib/loaders/flash/armv4_5_cfi_span_16.s for src */ static const uint32_t armv4_5_word_16_code[] = { /* 00008158 <sp_16_code>: */ 0xe0d050b2, /* ldrh r5, [r0], #2 */ 0xe1c890b0, /* strh r9, [r8] */ 0xe1cab0b0, /* strh r11, [r10] */ 0xe1c830b0, /* strh r3, [r8] */ 0xe1c150b0, /* strh r5, [r1] */ 0xe1a00000, /* nop (mov r0,r0) */ /* 00008168 <sp_16_busy>: */ 0xe1d160b0, /* ldrh r6, [r1] */ 0xe0257006, /* eor r7, r5, r6 */ 0xe0147007, /* ands r7, r4, r7 */ 0x0a000007, /* beq 8198 <sp_16_cont> */ 0xe0166124, /* ands r6, r6, r4, lsr #2 */ 0x0afffff9, /* beq 8168 <sp_16_busy> */ 0xe1d160b0, /* ldrh r6, [r1] */ 0xe0257006, /* eor r7, r5, r6 */ 0xe0147007, /* ands r7, r4, r7 */ 0x0a000001, /* beq 8198 <sp_16_cont> */ 0xe3a05000, /* mov r5, #0 ; 0x0 */ 0x1a000004, /* bne 81ac <sp_16_done> */ /* 00008198 <sp_16_cont>: */ 0xe2522001, /* subs r2, r2, #1 ; 0x1 */ 0x03a05080, /* moveq r5, #128 ; 0x80 */ 0x0a000001, /* beq 81ac <sp_16_done> */ 0xe2811002, /* add r1, r1, #2 ; 0x2 */ 0xeaffffe8, /* b 8158 <sp_16_code> */ /* 000081ac <sp_16_done>: */ 0xeafffffe /* b 81ac <sp_16_done> */ }; /* see contrib/loaders/flash/armv7m_cfi_span_16.s for src */ static const uint32_t armv7m_word_16_code[] = { 0x5B02F830, 0x9000F8A8, 0xB000F8AA, 0x3000F8A8, 0xBF00800D, 0xEA85880E, 0x40270706, 0xEA16D00A, 0xD0F70694, 0xEA85880E, 0x40270706, 0xF04FD002, 0xD1070500, 0xD0023A01, 0x0102F101, 0xF04FE7E0, 0xE7FF0580, 0x0000BE00 }; /* see contrib/loaders/flash/armv7m_cfi_span_16_dq7.s for src */ static const uint32_t armv7m_word_16_code_dq7only[] = { /* 00000000 <code>: */ 0x5B02F830, /* ldrh.w r5, [r0], #2 */ 0x9000F8A8, /* strh.w r9, [r8] */ 0xB000F8AA, /* strh.w fp, [sl] */ 0x3000F8A8, /* strh.w r3, [r8] */ 0xBF00800D, /* strh r5, [r1, #0] */ /* nop */ /* 00000014 <busy>: */ 0xEA85880E, /* ldrh r6, [r1, #0] */ /* eor.w r7, r5, r6 */ 0x40270706, /* ands r7, r4 */ 0x3A01D1FA, /* bne.n 14 <busy> */ /* subs r2, #1 */ 0xF101D002, /* beq.n 28 <success> */ 0xE7EB0102, /* add.w r1, r1, #2 */ /* b.n 0 <code> */ /* 00000028 <success>: */ 0x0580F04F, /* mov.w r5, #128 */ 0xBF00E7FF, /* b.n 30 <done> */ /* nop (for alignment purposes) */ /* 00000030 <done>: */ 0x0000BE00 /* bkpt 0x0000 */ }; /* see contrib/loaders/flash/armv4_5_cfi_span_16_dq7.s for src */ static const uint32_t armv4_5_word_16_code_dq7only[] = { /* <sp_16_code>: */ 0xe0d050b2, /* ldrh r5, [r0], #2 */ 0xe1c890b0, /* strh r9, [r8] */ 0xe1cab0b0, /* strh r11, [r10] */ 0xe1c830b0, /* strh r3, [r8] */ 0xe1c150b0, /* strh r5, [r1] */ 0xe1a00000, /* nop (mov r0,r0) */ /* <sp_16_busy>: */ 0xe1d160b0, /* ldrh r6, [r1] */ 0xe0257006, /* eor r7, r5, r6 */ 0xe2177080, /* ands r7, #0x80 */ 0x1afffffb, /* bne 8168 <sp_16_busy> */ /* */ 0xe2522001, /* subs r2, r2, #1 ; 0x1 */ 0x03a05080, /* moveq r5, #128 ; 0x80 */ 0x0a000001, /* beq 81ac <sp_16_done> */ 0xe2811002, /* add r1, r1, #2 ; 0x2 */ 0xeafffff0, /* b 8158 <sp_16_code> */ /* 000081ac <sp_16_done>: */ 0xeafffffe /* b 81ac <sp_16_done> */ }; /* see contrib/loaders/flash/armv4_5_cfi_span_8.s for src */ static const uint32_t armv4_5_word_8_code[] = { /* 000081b0 <sp_16_code_end>: */ 0xe4d05001, /* ldrb r5, [r0], #1 */ 0xe5c89000, /* strb r9, [r8] */ 0xe5cab000, /* strb r11, [r10] */ 0xe5c83000, /* strb r3, [r8] */ 0xe5c15000, /* strb r5, [r1] */ 0xe1a00000, /* nop (mov r0,r0) */ /* 000081c0 <sp_8_busy>: */ 0xe5d16000, /* ldrb r6, [r1] */ 0xe0257006, /* eor r7, r5, r6 */ 0xe0147007, /* ands r7, r4, r7 */ 0x0a000007, /* beq 81f0 <sp_8_cont> */ 0xe0166124, /* ands r6, r6, r4, lsr #2 */ 0x0afffff9, /* beq 81c0 <sp_8_busy> */ 0xe5d16000, /* ldrb r6, [r1] */ 0xe0257006, /* eor r7, r5, r6 */ 0xe0147007, /* ands r7, r4, r7 */ 0x0a000001, /* beq 81f0 <sp_8_cont> */ 0xe3a05000, /* mov r5, #0 ; 0x0 */ 0x1a000004, /* bne 8204 <sp_8_done> */ /* 000081f0 <sp_8_cont>: */ 0xe2522001, /* subs r2, r2, #1 ; 0x1 */ 0x03a05080, /* moveq r5, #128 ; 0x80 */ 0x0a000001, /* beq 8204 <sp_8_done> */ 0xe2811001, /* add r1, r1, #1 ; 0x1 */ 0xeaffffe8, /* b 81b0 <sp_16_code_end> */ /* 00008204 <sp_8_done>: */ 0xeafffffe /* b 8204 <sp_8_done> */ }; if (strncmp(target_type_name(target), "mips_m4k", 8) == 0) return cfi_spansion_write_block_mips(bank, buffer, address, count); if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */ armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC; armv7m_algo.core_mode = ARM_MODE_THREAD; arm_algo = &armv7m_algo; } else if (is_arm(target_to_arm(target))) { /* All other ARM CPUs have 32 bit instructions */ armv4_5_algo.common_magic = ARM_COMMON_MAGIC; armv4_5_algo.core_mode = ARM_MODE_SVC; armv4_5_algo.core_state = ARM_STATE_ARM; arm_algo = &armv4_5_algo; } else { LOG_ERROR("Unknown architecture"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } int target_code_size = 0; const uint32_t *target_code_src = NULL; switch (bank->bus_width) { case 1: if (is_armv7m(target_to_armv7m(target))) { LOG_ERROR("Unknown ARM architecture"); return ERROR_FAIL; } target_code_src = armv4_5_word_8_code; target_code_size = sizeof(armv4_5_word_8_code); break; case 2: /* Check for DQ5 support */ if (cfi_info->status_poll_mask & (1 << 5)) { if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */ target_code_src = armv7m_word_16_code; target_code_size = sizeof(armv7m_word_16_code); } else { /* armv4_5 target */ target_code_src = armv4_5_word_16_code; target_code_size = sizeof(armv4_5_word_16_code); } } else { /* No DQ5 support. Use DQ7 DATA# polling only. */ if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */ target_code_src = armv7m_word_16_code_dq7only; target_code_size = sizeof(armv7m_word_16_code_dq7only); } else { /* armv4_5 target */ target_code_src = armv4_5_word_16_code_dq7only; target_code_size = sizeof(armv4_5_word_16_code_dq7only); } } break; case 4: if (is_armv7m(target_to_armv7m(target))) { LOG_ERROR("Unknown ARM architecture"); return ERROR_FAIL; } target_code_src = armv4_5_word_32_code; target_code_size = sizeof(armv4_5_word_32_code); break; default: LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", bank->bus_width); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* flash write code */ uint8_t *target_code; /* convert bus-width dependent algorithm code to correct endianness */ target_code = malloc(target_code_size); if (!target_code) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } target_buffer_set_u32_array(target, target_code, target_code_size / 4, target_code_src); /* allocate working area */ retval = target_alloc_working_area(target, target_code_size, &write_algorithm); if (retval != ERROR_OK) { free(target_code); return retval; } /* write algorithm code to working area */ retval = target_write_buffer(target, write_algorithm->address, target_code_size, target_code); if (retval != ERROR_OK) { free(target_code); return retval; } free(target_code); /* the following code still assumes target code is fixed 24*4 bytes */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING( "not enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_OUT); init_reg_param(®_params[5], "r5", 32, PARAM_IN); init_reg_param(®_params[6], "r8", 32, PARAM_OUT); init_reg_param(®_params[7], "r9", 32, PARAM_OUT); init_reg_param(®_params[8], "r10", 32, PARAM_OUT); init_reg_param(®_params[9], "r11", 32, PARAM_OUT); while (count > 0) { uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count; retval = target_write_buffer(target, source->address, thisrun_count, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width); buf_set_u32(reg_params[3].value, 0, 32, cfi_command_val(bank, 0xA0)); buf_set_u32(reg_params[4].value, 0, 32, cfi_command_val(bank, 0x80)); buf_set_u32(reg_params[6].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock1)); buf_set_u32(reg_params[7].value, 0, 32, 0xaaaaaaaa); buf_set_u32(reg_params[8].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock2)); buf_set_u32(reg_params[9].value, 0, 32, 0x55555555); retval = target_run_algorithm(target, 0, NULL, 10, reg_params, write_algorithm->address, write_algorithm->address + ((target_code_size) - 4), 10000, arm_algo); if (retval != ERROR_OK) break; status = buf_get_u32(reg_params[5].value, 0, 32); if (status != 0x80) { LOG_ERROR("flash write block failed status: 0x%" PRIx32, status); retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count; address += thisrun_count; count -= thisrun_count; } target_free_all_working_areas(target); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); destroy_reg_param(®_params[6]); destroy_reg_param(®_params[7]); destroy_reg_param(®_params[8]); destroy_reg_param(®_params[9]); return retval; } static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; cfi_intel_clear_status_register(bank); retval = cfi_send_command(bank, 0x40, address); if (retval != ERROR_OK) return retval; retval = cfi_target_write_memory(bank, address, 1, word); if (retval != ERROR_OK) return retval; uint8_t status; retval = cfi_intel_wait_status_busy(bank, cfi_info->word_write_timeout, &status); if (retval != ERROR_OK) return retval; if (status != 0x80) { retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("couldn't write word at base " TARGET_ADDR_FMT ", address 0x%" PRIx32, bank->base, address); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word, uint32_t wordcount, uint32_t address) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; /* Calculate buffer size and boundary mask * buffersize is (buffer size per chip) * (number of chips) * bufferwsize is buffersize in words */ uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width); uint32_t buffermask = buffersize-1; uint32_t bufferwsize = buffersize / bank->bus_width; /* Check for valid range */ if (address & buffermask) { LOG_ERROR("Write address at base " TARGET_ADDR_FMT ", address 0x%" PRIx32 " not aligned to 2^%d boundary", bank->base, address, cfi_info->max_buf_write_size); return ERROR_FLASH_OPERATION_FAILED; } /* Check for valid size */ if (wordcount > bufferwsize) { LOG_ERROR("Number of data words %" PRIu32 " exceeds available buffersize %" PRIu32, wordcount, buffersize); return ERROR_FLASH_OPERATION_FAILED; } /* Write to flash buffer */ cfi_intel_clear_status_register(bank); /* Initiate buffer operation _*/ retval = cfi_send_command(bank, 0xe8, address); if (retval != ERROR_OK) return retval; uint8_t status; retval = cfi_intel_wait_status_busy(bank, cfi_info->buf_write_timeout, &status); if (retval != ERROR_OK) return retval; if (status != 0x80) { retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR( "couldn't start buffer write operation at base " TARGET_ADDR_FMT ", address 0x%" PRIx32, bank->base, address); return ERROR_FLASH_OPERATION_FAILED; } /* Write buffer wordcount-1 and data words */ retval = cfi_send_command(bank, bufferwsize-1, address); if (retval != ERROR_OK) return retval; retval = cfi_target_write_memory(bank, address, bufferwsize, word); if (retval != ERROR_OK) return retval; /* Commit write operation */ retval = cfi_send_command(bank, 0xd0, address); if (retval != ERROR_OK) return retval; retval = cfi_intel_wait_status_busy(bank, cfi_info->buf_write_timeout, &status); if (retval != ERROR_OK) return retval; if (status != 0x80) { retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("Buffer write at base " TARGET_ADDR_FMT ", address 0x%" PRIx32 " failed.", bank->base, address); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int cfi_spansion_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0xa0, cfi_flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; retval = cfi_target_write_memory(bank, address, 1, word); if (retval != ERROR_OK) return retval; if (cfi_spansion_wait_status_busy(bank, cfi_info->word_write_timeout) != ERROR_OK) { retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("couldn't write word at base " TARGET_ADDR_FMT ", address 0x%" PRIx32, bank->base, address); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word, uint32_t wordcount, uint32_t address) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; /* Calculate buffer size and boundary mask * buffersize is (buffer size per chip) * (number of chips) * bufferwsize is buffersize in words */ uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width); uint32_t buffermask = buffersize-1; uint32_t bufferwsize = buffersize / bank->bus_width; /* Check for valid range */ if (address & buffermask) { LOG_ERROR("Write address at base " TARGET_ADDR_FMT ", address 0x%" PRIx32 " not aligned to 2^%d boundary", bank->base, address, cfi_info->max_buf_write_size); return ERROR_FLASH_OPERATION_FAILED; } /* Check for valid size */ if (wordcount > bufferwsize) { LOG_ERROR("Number of data words %" PRIu32 " exceeds available buffersize %" PRIu32, wordcount, buffersize); return ERROR_FLASH_OPERATION_FAILED; } /* Unlock */ retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; /* Buffer load command */ retval = cfi_send_command(bank, 0x25, address); if (retval != ERROR_OK) return retval; /* Write buffer wordcount-1 and data words */ retval = cfi_send_command(bank, bufferwsize-1, address); if (retval != ERROR_OK) return retval; retval = cfi_target_write_memory(bank, address, bufferwsize, word); if (retval != ERROR_OK) return retval; /* Commit write operation */ retval = cfi_send_command(bank, 0x29, address); if (retval != ERROR_OK) return retval; if (cfi_spansion_wait_status_busy(bank, cfi_info->buf_write_timeout) != ERROR_OK) { retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("couldn't write block at base " TARGET_ADDR_FMT ", address 0x%" PRIx32 ", size 0x%" PRIx32, bank->base, address, bufferwsize); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address) { struct cfi_flash_bank *cfi_info = bank->driver_priv; switch (cfi_info->pri_id) { case 1: case 3: return cfi_intel_write_word(bank, word, address); case 2: return cfi_spansion_write_word(bank, word, address); default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } return ERROR_FLASH_OPERATION_FAILED; } static int cfi_write_words(struct flash_bank *bank, const uint8_t *word, uint32_t wordcount, uint32_t address) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->buf_write_timeout_typ == 0) { /* buffer writes are not supported */ LOG_DEBUG("Buffer Writes Not Supported"); return ERROR_FLASH_OPER_UNSUPPORTED; } switch (cfi_info->pri_id) { case 1: case 3: return cfi_intel_write_words(bank, word, wordcount, address); case 2: return cfi_spansion_write_words(bank, word, wordcount, address); default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } return ERROR_FLASH_OPERATION_FAILED; } static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct cfi_flash_bank *cfi_info = bank->driver_priv; uint32_t address = bank->base + offset; uint32_t read_p; int align; /* number of unaligned bytes */ uint8_t current_word[CFI_MAX_BUS_WIDTH]; int retval; LOG_DEBUG("reading buffer of %i byte at 0x%8.8x", (int)count, (unsigned)offset); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; /* start at the first byte of the first word (bus_width size) */ read_p = address & ~(bank->bus_width - 1); align = address - read_p; if (align != 0) { LOG_INFO("Fixup %d unaligned read head bytes", align); /* read a complete word from flash */ retval = cfi_target_read_memory(bank, read_p, 1, current_word); if (retval != ERROR_OK) return retval; /* take only bytes we need */ for (unsigned int i = align; (i < bank->bus_width) && (count > 0); i++, count--) *buffer++ = current_word[i]; read_p += bank->bus_width; } align = count / bank->bus_width; if (align) { retval = cfi_target_read_memory(bank, read_p, align, buffer); if (retval != ERROR_OK) return retval; read_p += align * bank->bus_width; buffer += align * bank->bus_width; count -= align * bank->bus_width; } if (count) { LOG_INFO("Fixup %" PRIu32 " unaligned read tail bytes", count); /* read a complete word from flash */ retval = cfi_target_read_memory(bank, read_p, 1, current_word); if (retval != ERROR_OK) return retval; /* take only bytes we need */ for (unsigned int i = 0; (i < bank->bus_width) && (count > 0); i++, count--) *buffer++ = current_word[i]; } return ERROR_OK; } static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct cfi_flash_bank *cfi_info = bank->driver_priv; uint32_t address = bank->base + offset; /* address of first byte to be programmed */ uint32_t write_p; int align; /* number of unaligned bytes */ int blk_count; /* number of bus_width bytes for block copy */ uint8_t current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being *programmed */ uint8_t *swapped_buffer = NULL; const uint8_t *real_buffer = NULL; int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; /* start at the first byte of the first word (bus_width size) */ write_p = address & ~(bank->bus_width - 1); align = address - write_p; if (align != 0) { LOG_INFO("Fixup %d unaligned head bytes", align); /* read a complete word from flash */ retval = cfi_target_read_memory(bank, write_p, 1, current_word); if (retval != ERROR_OK) return retval; /* replace only bytes that must be written */ for (unsigned int i = align; (i < bank->bus_width) && (count > 0); i++, count--) if (cfi_info->data_swap) /* data bytes are swapped (reverse endianness) */ current_word[bank->bus_width - i] = *buffer++; else current_word[i] = *buffer++; retval = cfi_write_word(bank, current_word, write_p); if (retval != ERROR_OK) return retval; write_p += bank->bus_width; } if (cfi_info->data_swap && count) { swapped_buffer = malloc(count & ~(bank->bus_width - 1)); switch (bank->bus_width) { case 2: buf_bswap16(swapped_buffer, buffer, count & ~(bank->bus_width - 1)); break; case 4: buf_bswap32(swapped_buffer, buffer, count & ~(bank->bus_width - 1)); break; } real_buffer = buffer; buffer = swapped_buffer; } /* handle blocks of bus_size aligned bytes */ blk_count = count & ~(bank->bus_width - 1); /* round down, leave tail bytes */ switch (cfi_info->pri_id) { /* try block writes (fails without working area) */ case 1: case 3: retval = cfi_intel_write_block(bank, buffer, write_p, blk_count); break; case 2: retval = cfi_spansion_write_block(bank, buffer, write_p, blk_count); break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (retval == ERROR_OK) { /* Increment pointers and decrease count on successful block write */ buffer += blk_count; write_p += blk_count; count -= blk_count; } else { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* Calculate buffer size and boundary mask * buffersize is (buffer size per chip) * (number of chips) * bufferwsize is buffersize in words */ uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width); uint32_t buffermask = buffersize-1; uint32_t bufferwsize = buffersize / bank->bus_width; /* fall back to memory writes */ while (count >= (uint32_t)bank->bus_width) { bool fallback; if ((write_p & 0xff) == 0) { LOG_INFO("Programming at 0x%08" PRIx32 ", count 0x%08" PRIx32 " bytes remaining", write_p, count); } fallback = true; if ((bufferwsize > 0) && (count >= buffersize) && !(write_p & buffermask)) { retval = cfi_write_words(bank, buffer, bufferwsize, write_p); if (retval == ERROR_OK) { buffer += buffersize; write_p += buffersize; count -= buffersize; fallback = false; } else if (retval != ERROR_FLASH_OPER_UNSUPPORTED) return retval; } /* try the slow way? */ if (fallback) { for (unsigned int i = 0; i < bank->bus_width; i++) current_word[i] = *buffer++; retval = cfi_write_word(bank, current_word, write_p); if (retval != ERROR_OK) return retval; write_p += bank->bus_width; count -= bank->bus_width; } } } else return retval; } if (swapped_buffer) { buffer = real_buffer + (buffer - swapped_buffer); free(swapped_buffer); } /* return to read array mode, so we can read from flash again for padding */ retval = cfi_reset(bank); if (retval != ERROR_OK) return retval; /* handle unaligned tail bytes */ if (count > 0) { LOG_INFO("Fixup %" PRIu32 " unaligned tail bytes", count); /* read a complete word from flash */ retval = cfi_target_read_memory(bank, write_p, 1, current_word); if (retval != ERROR_OK) return retval; /* replace only bytes that must be written */ for (unsigned int i = 0; (i < bank->bus_width) && (count > 0); i++, count--) if (cfi_info->data_swap) /* data bytes are swapped (reverse endianness) */ current_word[bank->bus_width - i] = *buffer++; else current_word[i] = *buffer++; retval = cfi_write_word(bank, current_word, write_p); if (retval != ERROR_OK) return retval; } /* return to read array mode */ return cfi_reset(bank); } static void cfi_fixup_reversed_erase_regions(struct flash_bank *bank, const void *param) { (void) param; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; pri_ext->_reversed_geometry = 1; } static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, const void *param) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; (void) param; if ((pri_ext->_reversed_geometry) || (pri_ext->top_bottom == 3)) { LOG_DEBUG("swapping reversed erase region information on cmdset 0002 device"); for (unsigned int i = 0; i < cfi_info->num_erase_regions / 2; i++) { int j = (cfi_info->num_erase_regions - 1) - i; uint32_t swap; swap = cfi_info->erase_region_info[i]; cfi_info->erase_region_info[i] = cfi_info->erase_region_info[j]; cfi_info->erase_region_info[j] = swap; } } } static void cfi_fixup_0002_unlock_addresses(struct flash_bank *bank, const void *param) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; const struct cfi_unlock_addresses *unlock_addresses = param; pri_ext->_unlock1 = unlock_addresses->unlock1; pri_ext->_unlock2 = unlock_addresses->unlock2; } static void cfi_fixup_0002_polling_bits(struct flash_bank *bank, const void *param) { struct cfi_flash_bank *cfi_info = bank->driver_priv; const int *status_poll_mask = param; cfi_info->status_poll_mask = *status_poll_mask; } static int cfi_query_string(struct flash_bank *bank, int address) { struct cfi_flash_bank *cfi_info = bank->driver_priv; int retval; retval = cfi_send_command(bank, 0x98, cfi_flash_address(bank, 0, address)); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x10, &cfi_info->qry[0]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x11, &cfi_info->qry[1]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x12, &cfi_info->qry[2]); if (retval != ERROR_OK) return retval; LOG_DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]); if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y')) { retval = cfi_reset(bank); if (retval != ERROR_OK) return retval; LOG_ERROR("Could not probe bank: no QRY"); return ERROR_FLASH_BANK_INVALID; } return ERROR_OK; } int cfi_probe(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct target *target = bank->target; unsigned int num_sectors = 0; int sector = 0; uint32_t unlock1 = 0x555; uint32_t unlock2 = 0x2aa; int retval; uint8_t value_buf0[CFI_MAX_BUS_WIDTH], value_buf1[CFI_MAX_BUS_WIDTH]; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } cfi_info->probed = false; cfi_info->num_erase_regions = 0; free(bank->sectors); bank->sectors = NULL; free(cfi_info->erase_region_info); cfi_info->erase_region_info = NULL; /* JEDEC standard JESD21C uses 0x5555 and 0x2aaa as unlock addresses, * while CFI compatible AMD/Spansion flashes use 0x555 and 0x2aa */ if (cfi_info->jedec_probe) { unlock1 = 0x5555; unlock2 = 0x2aaa; } /* switch to read identifier codes mode ("AUTOSELECT") */ retval = cfi_send_command(bank, 0xaa, cfi_flash_address(bank, 0, unlock1)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x55, cfi_flash_address(bank, 0, unlock2)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, unlock1)); if (retval != ERROR_OK) return retval; retval = cfi_target_read_memory(bank, cfi_flash_address(bank, 0, 0x00), 1, value_buf0); if (retval != ERROR_OK) return retval; retval = cfi_target_read_memory(bank, cfi_flash_address(bank, 0, 0x01), 1, value_buf1); if (retval != ERROR_OK) return retval; switch (bank->chip_width) { case 1: cfi_info->manufacturer = *value_buf0; cfi_info->device_id = *value_buf1; break; case 2: cfi_info->manufacturer = target_buffer_get_u16(target, value_buf0); cfi_info->device_id = target_buffer_get_u16(target, value_buf1); break; case 4: cfi_info->manufacturer = target_buffer_get_u32(target, value_buf0); cfi_info->device_id = target_buffer_get_u32(target, value_buf1); break; default: LOG_ERROR("Unsupported bank chipwidth %u, can't probe memory", bank->chip_width); return ERROR_FLASH_OPERATION_FAILED; } LOG_INFO("Flash Manufacturer/Device: 0x%04x 0x%04x", cfi_info->manufacturer, cfi_info->device_id); /* switch back to read array mode */ retval = cfi_reset(bank); if (retval != ERROR_OK) return retval; /* check device/manufacturer ID for known non-CFI flashes. */ cfi_fixup_non_cfi(bank); /* query only if this is a CFI compatible flash, * otherwise the relevant info has already been filled in */ if (!cfi_info->not_cfi) { /* enter CFI query mode * according to JEDEC Standard No. 68.01, * a single bus sequence with address = 0x55, data = 0x98 should put * the device into CFI query mode. * * SST flashes clearly violate this, and we will consider them incompatible for now */ retval = cfi_query_string(bank, 0x55); if (retval != ERROR_OK) { /* * Spansion S29WS-N CFI query fix is to try 0x555 if 0x55 fails. Should * be harmless enough: * * http://www.infradead.org/pipermail/linux-mtd/2005-September/013618.html */ LOG_USER("Try workaround w/0x555 instead of 0x55 to get QRY."); retval = cfi_query_string(bank, 0x555); } if (retval != ERROR_OK) return retval; retval = cfi_query_u16(bank, 0, 0x13, &cfi_info->pri_id); if (retval != ERROR_OK) return retval; retval = cfi_query_u16(bank, 0, 0x15, &cfi_info->pri_addr); if (retval != ERROR_OK) return retval; retval = cfi_query_u16(bank, 0, 0x17, &cfi_info->alt_id); if (retval != ERROR_OK) return retval; retval = cfi_query_u16(bank, 0, 0x19, &cfi_info->alt_addr); if (retval != ERROR_OK) return retval; LOG_DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: " "0x%4.4x, alt_addr: 0x%4.4x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr); retval = cfi_query_u8(bank, 0, 0x1b, &cfi_info->vcc_min); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x1c, &cfi_info->vcc_max); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x1d, &cfi_info->vpp_min); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x1e, &cfi_info->vpp_max); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x1f, &cfi_info->word_write_timeout_typ); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x20, &cfi_info->buf_write_timeout_typ); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x21, &cfi_info->block_erase_timeout_typ); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x22, &cfi_info->chip_erase_timeout_typ); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x23, &cfi_info->word_write_timeout_max); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x24, &cfi_info->buf_write_timeout_max); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x25, &cfi_info->block_erase_timeout_max); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x26, &cfi_info->chip_erase_timeout_max); if (retval != ERROR_OK) return retval; uint8_t data; retval = cfi_query_u8(bank, 0, 0x27, &data); if (retval != ERROR_OK) return retval; cfi_info->dev_size = 1 << data; retval = cfi_query_u16(bank, 0, 0x28, &cfi_info->interface_desc); if (retval != ERROR_OK) return retval; retval = cfi_query_u16(bank, 0, 0x2a, &cfi_info->max_buf_write_size); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x2c, &cfi_info->num_erase_regions); if (retval != ERROR_OK) return retval; LOG_DEBUG("size: 0x%" PRIx32 ", interface desc: %i, max buffer write size: 0x%x", cfi_info->dev_size, cfi_info->interface_desc, (1 << cfi_info->max_buf_write_size)); if (cfi_info->num_erase_regions) { cfi_info->erase_region_info = malloc(sizeof(*cfi_info->erase_region_info) * cfi_info->num_erase_regions); for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++) { retval = cfi_query_u32(bank, 0, 0x2d + (4 * i), &cfi_info->erase_region_info[i]); if (retval != ERROR_OK) return retval; LOG_DEBUG( "erase region[%i]: %" PRIu32 " blocks of size 0x%" PRIx32 "", i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256); } } else cfi_info->erase_region_info = NULL; /* We need to read the primary algorithm extended query table before calculating * the sector layout to be able to apply fixups */ switch (cfi_info->pri_id) { /* Intel command set (standard and extended) */ case 0x0001: case 0x0003: cfi_read_intel_pri_ext(bank); break; /* AMD/Spansion, Atmel, ... command set */ case 0x0002: cfi_info->status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7; /* *default *for *all *CFI *flashes **/ cfi_read_0002_pri_ext(bank); break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } /* return to read array mode * we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command */ retval = cfi_reset(bank); if (retval != ERROR_OK) return retval; } /* end CFI case */ LOG_DEBUG("Vcc min: %x.%x, Vcc max: %x.%x, Vpp min: %u.%x, Vpp max: %u.%x", (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f, (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f, (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f, (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f); LOG_DEBUG("typ. word write timeout: %u us, typ. buf write timeout: %u us, " "typ. block erase timeout: %u ms, typ. chip erase timeout: %u ms", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ, 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ); LOG_DEBUG("max. word write timeout: %u us, max. buf write timeout: %u us, " "max. block erase timeout: %u ms, max. chip erase timeout: %u ms", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ), (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ), (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ), (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ)); /* convert timeouts to real values in ms */ cfi_info->word_write_timeout = DIV_ROUND_UP((1L << cfi_info->word_write_timeout_typ) * (1L << cfi_info->word_write_timeout_max), 1000); cfi_info->buf_write_timeout = DIV_ROUND_UP((1L << cfi_info->buf_write_timeout_typ) * (1L << cfi_info->buf_write_timeout_max), 1000); cfi_info->block_erase_timeout = (1L << cfi_info->block_erase_timeout_typ) * (1L << cfi_info->block_erase_timeout_max); cfi_info->chip_erase_timeout = (1L << cfi_info->chip_erase_timeout_typ) * (1L << cfi_info->chip_erase_timeout_max); LOG_DEBUG("calculated word write timeout: %u ms, buf write timeout: %u ms, " "block erase timeout: %u ms, chip erase timeout: %u ms", cfi_info->word_write_timeout, cfi_info->buf_write_timeout, cfi_info->block_erase_timeout, cfi_info->chip_erase_timeout); /* apply fixups depending on the primary command set */ switch (cfi_info->pri_id) { /* Intel command set (standard and extended) */ case 0x0001: case 0x0003: cfi_fixup(bank, cfi_0001_fixups); break; /* AMD/Spansion, Atmel, ... command set */ case 0x0002: cfi_fixup(bank, cfi_0002_fixups); break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } if ((cfi_info->dev_size * bank->bus_width / bank->chip_width) != bank->size) { LOG_WARNING("configuration specifies 0x%" PRIx32 " size, but a 0x%" PRIx32 " size flash was found", bank->size, cfi_info->dev_size); } if (cfi_info->num_erase_regions == 0) { /* a device might have only one erase block, spanning the whole device */ bank->num_sectors = 1; bank->sectors = malloc(sizeof(struct flash_sector)); bank->sectors[sector].offset = 0x0; bank->sectors[sector].size = bank->size; bank->sectors[sector].is_erased = -1; bank->sectors[sector].is_protected = -1; } else { uint32_t offset = 0; for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++) num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1; bank->num_sectors = num_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++) { for (uint32_t j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++) { bank->sectors[sector].offset = offset; bank->sectors[sector].size = ((cfi_info->erase_region_info[i] >> 16) * 256) * bank->bus_width / bank->chip_width; offset += bank->sectors[sector].size; bank->sectors[sector].is_erased = -1; bank->sectors[sector].is_protected = -1; sector++; } } if (offset != (cfi_info->dev_size * bank->bus_width / bank->chip_width)) { LOG_WARNING( "CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", (cfi_info->dev_size * bank->bus_width / bank->chip_width), offset); } } cfi_info->probed = true; return ERROR_OK; } int cfi_auto_probe(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->probed) return ERROR_OK; return cfi_probe(bank); } static int cfi_intel_protect_check(struct flash_bank *bank) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext; /* check if block lock bits are supported on this device */ if (!(pri_ext->blk_status_reg_mask & 0x1)) return ERROR_FLASH_OPERATION_FAILED; retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, 0x55)); if (retval != ERROR_OK) return retval; for (unsigned int i = 0; i < bank->num_sectors; i++) { uint8_t block_status; retval = cfi_get_u8(bank, i, 0x2, &block_status); if (retval != ERROR_OK) return retval; if (block_status & 1) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; } return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); } static int cfi_spansion_protect_check(struct flash_bank *bank) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; for (unsigned int i = 0; i < bank->num_sectors; i++) { uint8_t block_status; retval = cfi_get_u8(bank, i, 0x2, &block_status); if (retval != ERROR_OK) return retval; if (block_status & 1) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; } return cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); } int cfi_protect_check(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; switch (cfi_info->pri_id) { case 1: case 3: return cfi_intel_protect_check(bank); case 2: return cfi_spansion_protect_check(bank); default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } return ERROR_OK; } int cfi_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->qry[0] == 0xff) { command_print_sameline(cmd, "\ncfi flash bank not probed yet\n"); return ERROR_OK; } if (!cfi_info->not_cfi) command_print_sameline(cmd, "\nCFI flash: "); else command_print_sameline(cmd, "\nnon-CFI flash: "); command_print_sameline(cmd, "mfr: 0x%4.4x, id:0x%4.4x\n", cfi_info->manufacturer, cfi_info->device_id); command_print_sameline(cmd, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: " "0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x\n", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr); command_print_sameline(cmd, "Vcc min: %x.%x, Vcc max: %x.%x, " "Vpp min: %u.%x, Vpp max: %u.%x\n", (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f, (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f, (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f, (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f); command_print_sameline(cmd, "typ. word write timeout: %u us, " "typ. buf write timeout: %u us, " "typ. block erase timeout: %u ms, " "typ. chip erase timeout: %u ms\n", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ, 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ); command_print_sameline(cmd, "max. word write timeout: %u us, " "max. buf write timeout: %u us, max. " "block erase timeout: %u ms, max. chip erase timeout: %u ms\n", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ), (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ), (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ), (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ)); command_print_sameline(cmd, "size: 0x%" PRIx32 ", interface desc: %i, " "max buffer write size: 0x%x\n", cfi_info->dev_size, cfi_info->interface_desc, 1 << cfi_info->max_buf_write_size); switch (cfi_info->pri_id) { case 1: case 3: cfi_intel_info(bank, cmd); break; case 2: cfi_spansion_info(bank, cmd); break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } return ERROR_OK; } static void cfi_fixup_0002_write_buffer(struct flash_bank *bank, const void *param) { struct cfi_flash_bank *cfi_info = bank->driver_priv; /* disable write buffer for M29W128G */ cfi_info->buf_write_timeout_typ = 0; } const struct flash_driver cfi_flash = { .name = "cfi", .flash_bank_command = cfi_flash_bank_command, .erase = cfi_erase, .protect = cfi_protect, .write = cfi_write, .read = cfi_read, .probe = cfi_probe, .auto_probe = cfi_auto_probe, /* FIXME: access flash at bus_width size */ .erase_check = default_flash_blank_check, .protect_check = cfi_protect_check, .info = cfi_get_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/cfi.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_CFI_H #define OPENOCD_FLASH_NOR_CFI_H #define CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7 0xE0 /* DQ5..DQ7 */ #define CFI_STATUS_POLL_MASK_DQ6_DQ7 0xC0 /* DQ6..DQ7 */ struct cfi_flash_bank { bool x16_as_x8; bool jedec_probe; bool not_cfi; bool probed; enum target_endianness endianness; bool data_swap; uint16_t manufacturer; uint16_t device_id; uint8_t qry[3]; /* identification string */ uint16_t pri_id; uint16_t pri_addr; uint16_t alt_id; uint16_t alt_addr; /* device-system interface */ uint8_t vcc_min; uint8_t vcc_max; uint8_t vpp_min; uint8_t vpp_max; uint8_t word_write_timeout_typ; uint8_t buf_write_timeout_typ; uint8_t block_erase_timeout_typ; uint8_t chip_erase_timeout_typ; uint8_t word_write_timeout_max; uint8_t buf_write_timeout_max; uint8_t block_erase_timeout_max; uint8_t chip_erase_timeout_max; uint8_t status_poll_mask; /* flash geometry */ uint32_t dev_size; uint16_t interface_desc; uint16_t max_buf_write_size; uint8_t num_erase_regions; uint32_t *erase_region_info; void *pri_ext; void *alt_ext; /* calculated timeouts */ unsigned word_write_timeout; unsigned buf_write_timeout; unsigned block_erase_timeout; unsigned chip_erase_timeout; /* memory accessors */ int (*write_mem)(struct flash_bank *bank, target_addr_t addr, uint32_t count, const uint8_t *buffer); int (*read_mem)(struct flash_bank *bank, target_addr_t addr, uint32_t count, uint8_t *buffer); }; /* Intel primary extended query table * as defined for the Advanced+ Boot Block Flash Memory (C3) * and used by the linux kernel cfi driver (as of 2.6.14) */ struct cfi_intel_pri_ext { uint8_t pri[3]; uint8_t major_version; uint8_t minor_version; uint32_t feature_support; uint8_t suspend_cmd_support; uint16_t blk_status_reg_mask; uint8_t vcc_optimal; uint8_t vpp_optimal; uint8_t num_protection_fields; uint16_t prot_reg_addr; uint8_t fact_prot_reg_size; uint8_t user_prot_reg_size; uint8_t extra[0]; }; /* Spansion primary extended query table as defined for and used by * the linux kernel cfi driver (as of 2.6.15) */ struct cfi_spansion_pri_ext { uint8_t pri[3]; uint8_t major_version; uint8_t minor_version; uint8_t silicon_revision; /* bits 1-0: Address Sensitive Unlock */ uint8_t erase_suspend; uint8_t blk_prot; uint8_t tmp_blk_unprotected; uint8_t blk_prot_unprot; uint8_t simultaneous_ops; uint8_t burst_mode; uint8_t page_mode; uint8_t vpp_min; uint8_t vpp_max; uint8_t top_bottom; int _reversed_geometry; uint32_t _unlock1; uint32_t _unlock2; }; /* Atmel primary extended query table as defined for and used by * the linux kernel cfi driver (as of 2.6.20+) */ struct cfi_atmel_pri_ext { uint8_t pri[3]; uint8_t major_version; uint8_t minor_version; uint8_t features; uint8_t bottom_boot; uint8_t burst_mode; uint8_t page_mode; }; enum { CFI_UNLOCK_555_2AA, CFI_UNLOCK_5555_2AAA, }; struct cfi_unlock_addresses { uint32_t unlock1; uint32_t unlock2; }; struct cfi_fixup { uint16_t mfr; uint16_t id; void (*fixup)(struct flash_bank *bank, const void *param); const void *param; }; int cfi_erase(struct flash_bank *bank, unsigned int first, unsigned int last); int cfi_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last); int cfi_probe(struct flash_bank *bank); int cfi_auto_probe(struct flash_bank *bank); int cfi_protect_check(struct flash_bank *bank); int cfi_get_info(struct flash_bank *bank, struct command_invocation *cmd); int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char **argv); uint32_t cfi_flash_address(struct flash_bank *bank, int sector, uint32_t offset); int cfi_spansion_unlock_seq(struct flash_bank *bank); int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address); int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address); int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout); int cfi_reset(struct flash_bank *bank); int cfi_target_read_memory(struct flash_bank *bank, target_addr_t addr, uint32_t count, uint8_t *buffer); #define CFI_MFR_AMD 0x0001 #define CFI_MFR_FUJITSU 0x0004 #define CFI_MFR_ATMEL 0x001F #define CFI_MFR_ST 0x0020 /* STMicroelectronics */ #define CFI_MFR_AMIC 0x0037 #define CFI_MFR_SST 0x00BF #define CFI_MFR_MX 0x00C2 #define CFI_MFR_EON 0x007F #define CFI_MFR_ANY 0xffff #define CFI_ID_ANY 0xffff #define CFI_MAX_BUS_WIDTH 4 #define CFI_MAX_CHIP_WIDTH 4 #endif /* OPENOCD_FLASH_NOR_CFI_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/core.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007-2010 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> * * Copyright (C) 2017-2018 Tomas Vanek <vanekt@fbl.cz> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <flash/common.h> #include <flash/nor/core.h> #include <flash/nor/imp.h> #include <target/image.h> /** * @file * Upper level of NOR flash framework. * The lower level interfaces are to drivers. These upper level ones * primarily support access from Tcl scripts or from GDB. */ static struct flash_bank *flash_banks; int flash_driver_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int retval; retval = bank->driver->erase(bank, first, last); if (retval != ERROR_OK) LOG_ERROR("failed erasing sectors %u to %u", first, last); return retval; } int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int retval; unsigned int num_blocks; if (bank->num_prot_blocks) num_blocks = bank->num_prot_blocks; else num_blocks = bank->num_sectors; /* callers may not supply illegal parameters ... */ if (first > last || last >= num_blocks) { LOG_ERROR("illegal protection block range"); return ERROR_FAIL; } /* force "set" to 0/1 */ set = !!set; if (!bank->driver->protect) { LOG_ERROR("Flash protection is not supported."); return ERROR_FLASH_OPER_UNSUPPORTED; } /* DANGER! * * We must not use any cached information about protection state!!!! * * There are a million things that could change the protect state: * * the target could have reset, power cycled, been hot plugged, * the application could have run, etc. * * Drivers only receive valid protection block range. */ retval = bank->driver->protect(bank, set, first, last); if (retval != ERROR_OK) LOG_ERROR("failed setting protection for blocks %u to %u", first, last); return retval; } int flash_driver_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; retval = bank->driver->write(bank, buffer, offset, count); if (retval != ERROR_OK) { LOG_ERROR( "error writing to flash at address " TARGET_ADDR_FMT " at offset 0x%8.8" PRIx32, bank->base, offset); } return retval; } int flash_driver_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; LOG_DEBUG("call flash_driver_read()"); retval = bank->driver->read(bank, buffer, offset, count); if (retval != ERROR_OK) { LOG_ERROR( "error reading to flash at address " TARGET_ADDR_FMT " at offset 0x%8.8" PRIx32, bank->base, offset); } return retval; } int default_flash_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { return target_read_buffer(bank->target, offset + bank->base, count, buffer); } int flash_driver_verify(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; retval = bank->driver->verify ? bank->driver->verify(bank, buffer, offset, count) : default_flash_verify(bank, buffer, offset, count); if (retval != ERROR_OK) { LOG_ERROR("verify failed in bank at " TARGET_ADDR_FMT " starting at 0x%8.8" PRIx32, bank->base, offset); } return retval; } int default_flash_verify(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { uint32_t target_crc, image_crc; int retval; retval = image_calculate_checksum(buffer, count, &image_crc); if (retval != ERROR_OK) return retval; retval = target_checksum_memory(bank->target, offset + bank->base, count, &target_crc); if (retval != ERROR_OK) return retval; LOG_DEBUG("addr " TARGET_ADDR_FMT ", len 0x%08" PRIx32 ", crc 0x%08" PRIx32 " 0x%08" PRIx32, offset + bank->base, count, ~image_crc, ~target_crc); if (target_crc == image_crc) return ERROR_OK; else return ERROR_FAIL; } void flash_bank_add(struct flash_bank *bank) { /* put flash bank in linked list */ unsigned bank_num = 0; if (flash_banks) { /* find last flash bank */ struct flash_bank *p = flash_banks; while (p->next) { bank_num += 1; p = p->next; } p->next = bank; bank_num += 1; } else flash_banks = bank; bank->bank_number = bank_num; } struct flash_bank *flash_bank_list(void) { return flash_banks; } struct flash_bank *get_flash_bank_by_num_noprobe(unsigned int num) { struct flash_bank *p; unsigned int i = 0; for (p = flash_banks; p; p = p->next) { if (i++ == num) return p; } LOG_ERROR("flash bank %d does not exist", num); return NULL; } unsigned int flash_get_bank_count(void) { struct flash_bank *p; unsigned int i = 0; for (p = flash_banks; p; p = p->next) i++; return i; } void default_flash_free_driver_priv(struct flash_bank *bank) { free(bank->driver_priv); bank->driver_priv = NULL; } void flash_free_all_banks(void) { struct flash_bank *bank = flash_banks; while (bank) { struct flash_bank *next = bank->next; if (bank->driver->free_driver_priv) bank->driver->free_driver_priv(bank); else LOG_WARNING("Flash driver of %s does not support free_driver_priv()", bank->name); /* For 'virtual' flash driver bank->sectors and bank->prot_blocks pointers are copied from * master flash_bank structure. They point to memory locations allocated by master flash driver * so master driver is responsible for releasing them. * Avoid UB caused by double-free memory corruption if flash bank is 'virtual'. */ if (strcmp(bank->driver->name, "virtual") != 0) { free(bank->sectors); free(bank->prot_blocks); } free(bank->name); free(bank); bank = next; } flash_banks = NULL; } struct flash_bank *get_flash_bank_by_name_noprobe(const char *name) { unsigned requested = get_flash_name_index(name); unsigned found = 0; struct flash_bank *bank; for (bank = flash_banks; bank; bank = bank->next) { if (strcmp(bank->name, name) == 0) return bank; if (!flash_driver_name_matches(bank->driver->name, name)) continue; if (++found < requested) continue; return bank; } return NULL; } int get_flash_bank_by_name(const char *name, struct flash_bank **bank_result) { struct flash_bank *bank; int retval; bank = get_flash_bank_by_name_noprobe(name); if (bank) { retval = bank->driver->auto_probe(bank); if (retval != ERROR_OK) { LOG_ERROR("auto_probe failed"); return retval; } } *bank_result = bank; return ERROR_OK; } int get_flash_bank_by_num(unsigned int num, struct flash_bank **bank) { struct flash_bank *p = get_flash_bank_by_num_noprobe(num); int retval; if (!p) return ERROR_FAIL; retval = p->driver->auto_probe(p); if (retval != ERROR_OK) { LOG_ERROR("auto_probe failed"); return retval; } *bank = p; return ERROR_OK; } /* lookup flash bank by address, bank not found is success, but * result_bank is set to NULL. */ int get_flash_bank_by_addr(struct target *target, target_addr_t addr, bool check, struct flash_bank **result_bank) { struct flash_bank *c; /* cycle through bank list */ for (c = flash_banks; c; c = c->next) { if (c->target != target) continue; int retval; retval = c->driver->auto_probe(c); if (retval != ERROR_OK) { LOG_ERROR("auto_probe failed"); return retval; } /* check whether address belongs to this flash bank */ if ((addr >= c->base) && (addr <= c->base + (c->size - 1))) { *result_bank = c; return ERROR_OK; } } *result_bank = NULL; if (check) { LOG_ERROR("No flash at address " TARGET_ADDR_FMT, addr); return ERROR_FAIL; } return ERROR_OK; } static int default_flash_mem_blank_check(struct flash_bank *bank) { struct target *target = bank->target; const int buffer_size = 1024; uint32_t n_bytes; int retval = ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } uint8_t *buffer = malloc(buffer_size); for (unsigned int i = 0; i < bank->num_sectors; i++) { uint32_t j; bank->sectors[i].is_erased = 1; for (j = 0; j < bank->sectors[i].size; j += buffer_size) { uint32_t chunk; chunk = buffer_size; if (chunk > (bank->sectors[i].size - j)) chunk = (bank->sectors[i].size - j); retval = target_read_memory(target, bank->base + bank->sectors[i].offset + j, 4, chunk/4, buffer); if (retval != ERROR_OK) goto done; for (n_bytes = 0; n_bytes < chunk; n_bytes++) { if (buffer[n_bytes] != bank->erased_value) { bank->sectors[i].is_erased = 0; break; } } } } done: free(buffer); return retval; } int default_flash_blank_check(struct flash_bank *bank) { struct target *target = bank->target; int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } struct target_memory_check_block *block_array; block_array = malloc(bank->num_sectors * sizeof(struct target_memory_check_block)); if (!block_array) return default_flash_mem_blank_check(bank); for (unsigned int i = 0; i < bank->num_sectors; i++) { block_array[i].address = bank->base + bank->sectors[i].offset; block_array[i].size = bank->sectors[i].size; block_array[i].result = UINT32_MAX; /* erase state unknown */ } bool fast_check = true; for (unsigned int i = 0; i < bank->num_sectors; ) { retval = target_blank_check_memory(target, block_array + i, bank->num_sectors - i, bank->erased_value); if (retval < 1) { /* Run slow fallback if the first run gives no result * otherwise use possibly incomplete results */ if (i == 0) fast_check = false; break; } i += retval; /* add number of blocks done this round */ } if (fast_check) { for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = block_array[i].result; retval = ERROR_OK; } else { if (retval == ERROR_NOT_IMPLEMENTED) LOG_USER("Running slow fallback erase check"); else LOG_USER("Running slow fallback erase check - add working memory"); retval = default_flash_mem_blank_check(bank); } free(block_array); return retval; } /* Manipulate given flash region, selecting the bank according to target * and address. Maps an address range to a set of sectors, and issues * the callback() on that set ... e.g. to erase or unprotect its members. * * Parameter iterate_protect_blocks switches iteration of protect block * instead of erase sectors. If there is no protect blocks array, sectors * are used in iteration, so compatibility for old flash drivers is retained. * * The "pad_reason" parameter is a kind of boolean: when it's NULL, the * range must fit those sectors exactly. This is clearly safe; it can't * erase data which the caller said to leave alone, for example. If it's * non-NULL, rather than failing, extra data in the first and/or last * sectors will be added to the range, and that reason string is used when * warning about those additions. */ static int flash_iterate_address_range_inner(struct target *target, char *pad_reason, target_addr_t addr, uint32_t length, bool iterate_protect_blocks, int (*callback)(struct flash_bank *bank, unsigned int first, unsigned int last)) { struct flash_bank *c; struct flash_sector *block_array; target_addr_t last_addr = addr + length - 1; /* the last address of range */ int first = -1; int last = -1; int i; int num_blocks; int retval = get_flash_bank_by_addr(target, addr, true, &c); if (retval != ERROR_OK) return retval; if (c->size == 0 || c->num_sectors == 0) { LOG_ERROR("Bank is invalid"); return ERROR_FLASH_BANK_INVALID; } if (length == 0) { /* special case, erase whole bank when length is zero */ if (addr != c->base) { LOG_ERROR("Whole bank access must start at beginning of bank."); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } return callback(c, 0, c->num_sectors - 1); } /* check whether it all fits in this bank */ if (last_addr > c->base + c->size - 1) { LOG_ERROR("Flash access does not fit into bank."); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } if (!c->prot_blocks || c->num_prot_blocks == 0) { /* flash driver does not define protect blocks, use sectors instead */ iterate_protect_blocks = false; } if (iterate_protect_blocks) { block_array = c->prot_blocks; num_blocks = c->num_prot_blocks; } else { block_array = c->sectors; num_blocks = c->num_sectors; } for (i = 0; i < num_blocks; i++) { struct flash_sector *f = &block_array[i]; target_addr_t sector_addr = c->base + f->offset; target_addr_t sector_last_addr = sector_addr + f->size - 1; /* start only on a sector boundary */ if (first < 0) { /* scanned past the first sector? */ if (addr < sector_addr) break; /* is this the first sector? */ if (addr == sector_addr) first = i; /* Does this need head-padding? If so, pad and warn; * or else force an error. * * Such padding can make trouble, since *WE* can't * ever know if that data was in use. The warning * should help users sort out messes later. */ else if (addr <= sector_last_addr && pad_reason) { /* FIXME say how many bytes (e.g. 80 KB) */ LOG_WARNING("Adding extra %s range, " TARGET_ADDR_FMT " .. " TARGET_ADDR_FMT, pad_reason, sector_addr, addr - 1); first = i; } else continue; } /* is this (also?) the last sector? */ if (last_addr == sector_last_addr) { last = i; break; } /* Does this need tail-padding? If so, pad and warn; * or else force an error. */ if (last_addr < sector_last_addr && pad_reason) { /* FIXME say how many bytes (e.g. 80 KB) */ LOG_WARNING("Adding extra %s range, " TARGET_ADDR_FMT " .. " TARGET_ADDR_FMT, pad_reason, last_addr + 1, sector_last_addr); last = i; break; } /* MUST finish on a sector boundary */ if (last_addr < sector_addr) break; } /* invalid start or end address? */ if (first == -1 || last == -1) { LOG_ERROR("address range " TARGET_ADDR_FMT " .. " TARGET_ADDR_FMT " is not sector-aligned", addr, last_addr); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* The NOR driver may trim this range down, based on what * sectors are already erased/unprotected. GDB currently * blocks such optimizations. */ return callback(c, first, last); } /* The inner fn only handles a single bank, we could be spanning * multiple chips. */ static int flash_iterate_address_range(struct target *target, char *pad_reason, target_addr_t addr, uint32_t length, bool iterate_protect_blocks, int (*callback)(struct flash_bank *bank, unsigned int first, unsigned int last)) { struct flash_bank *c; int retval = ERROR_OK; /* Danger! zero-length iterations means entire bank! */ do { retval = get_flash_bank_by_addr(target, addr, true, &c); if (retval != ERROR_OK) return retval; uint32_t cur_length = length; /* check whether it all fits in this bank */ if (addr + length - 1 > c->base + c->size - 1) { LOG_DEBUG("iterating over more than one flash bank."); cur_length = c->base + c->size - addr; } retval = flash_iterate_address_range_inner(target, pad_reason, addr, cur_length, iterate_protect_blocks, callback); if (retval != ERROR_OK) break; length -= cur_length; addr += cur_length; } while (length > 0); return retval; } int flash_erase_address_range(struct target *target, bool pad, target_addr_t addr, uint32_t length) { return flash_iterate_address_range(target, pad ? "erase" : NULL, addr, length, false, &flash_driver_erase); } static int flash_driver_unprotect(struct flash_bank *bank, unsigned int first, unsigned int last) { return flash_driver_protect(bank, 0, first, last); } int flash_unlock_address_range(struct target *target, target_addr_t addr, uint32_t length) { /* By default, pad to sector boundaries ... the real issue here * is that our (only) caller *permanently* removes protection, * and doesn't restore it. */ return flash_iterate_address_range(target, "unprotect", addr, length, true, &flash_driver_unprotect); } static int compare_section(const void *a, const void *b) { struct imagesection *b1, *b2; b1 = *((struct imagesection **)a); b2 = *((struct imagesection **)b); if (b1->base_address == b2->base_address) return 0; else if (b1->base_address > b2->base_address) return 1; else return -1; } /** * Get aligned start address of a flash write region */ target_addr_t flash_write_align_start(struct flash_bank *bank, target_addr_t addr) { if (addr < bank->base || addr >= bank->base + bank->size || bank->write_start_alignment <= 1) return addr; if (bank->write_start_alignment == FLASH_WRITE_ALIGN_SECTOR) { uint32_t offset = addr - bank->base; uint32_t aligned = 0; for (unsigned int sect = 0; sect < bank->num_sectors; sect++) { if (bank->sectors[sect].offset > offset) break; aligned = bank->sectors[sect].offset; } return bank->base + aligned; } return addr & ~(bank->write_start_alignment - 1); } /** * Get aligned end address of a flash write region */ target_addr_t flash_write_align_end(struct flash_bank *bank, target_addr_t addr) { if (addr < bank->base || addr >= bank->base + bank->size || bank->write_end_alignment <= 1) return addr; if (bank->write_end_alignment == FLASH_WRITE_ALIGN_SECTOR) { uint32_t offset = addr - bank->base; uint32_t aligned = 0; for (unsigned int sect = 0; sect < bank->num_sectors; sect++) { aligned = bank->sectors[sect].offset + bank->sectors[sect].size - 1; if (aligned >= offset) break; } return bank->base + aligned; } return addr | (bank->write_end_alignment - 1); } /** * Check if gap between sections is bigger than minimum required to discontinue flash write */ static bool flash_write_check_gap(struct flash_bank *bank, target_addr_t addr1, target_addr_t addr2) { if (bank->minimal_write_gap == FLASH_WRITE_CONTINUOUS || addr1 < bank->base || addr1 >= bank->base + bank->size || addr2 < bank->base || addr2 >= bank->base + bank->size) return false; if (bank->minimal_write_gap == FLASH_WRITE_GAP_SECTOR) { unsigned int sect; uint32_t offset1 = addr1 - bank->base; /* find the sector following the one containing addr1 */ for (sect = 0; sect < bank->num_sectors; sect++) { if (bank->sectors[sect].offset > offset1) break; } if (sect >= bank->num_sectors) return false; uint32_t offset2 = addr2 - bank->base; return bank->sectors[sect].offset + bank->sectors[sect].size <= offset2; } target_addr_t aligned1 = flash_write_align_end(bank, addr1); target_addr_t aligned2 = flash_write_align_start(bank, addr2); return aligned1 + bank->minimal_write_gap < aligned2; } int flash_write_unlock_verify(struct target *target, struct image *image, uint32_t *written, bool erase, bool unlock, bool write, bool verify) { int retval = ERROR_OK; unsigned int section; uint32_t section_offset; struct flash_bank *c; int *padding; section = 0; section_offset = 0; if (written) *written = 0; if (erase) { /* assume all sectors need erasing - stops any problems * when flash_write is called multiple times */ flash_set_dirty(); } /* allocate padding array */ padding = calloc(image->num_sections, sizeof(*padding)); /* This fn requires all sections to be in ascending order of addresses, * whereas an image can have sections out of order. */ struct imagesection **sections = malloc(sizeof(struct imagesection *) * image->num_sections); for (unsigned int i = 0; i < image->num_sections; i++) sections[i] = &image->sections[i]; qsort(sections, image->num_sections, sizeof(struct imagesection *), compare_section); /* loop until we reach end of the image */ while (section < image->num_sections) { uint32_t buffer_idx; uint8_t *buffer; unsigned int section_last; target_addr_t run_address = sections[section]->base_address + section_offset; uint32_t run_size = sections[section]->size - section_offset; int pad_bytes = 0; if (sections[section]->size == 0) { LOG_WARNING("empty section %d", section); section++; section_offset = 0; continue; } /* find the corresponding flash bank */ retval = get_flash_bank_by_addr(target, run_address, false, &c); if (retval != ERROR_OK) goto done; if (!c) { LOG_WARNING("no flash bank found for address " TARGET_ADDR_FMT, run_address); section++; /* and skip it */ section_offset = 0; continue; } /* collect consecutive sections which fall into the same bank */ section_last = section; padding[section] = 0; while ((run_address + run_size - 1 < c->base + c->size - 1) && (section_last + 1 < image->num_sections)) { /* sections are sorted */ assert(sections[section_last + 1]->base_address >= c->base); if (sections[section_last + 1]->base_address >= (c->base + c->size)) { /* Done with this bank */ break; } /* if we have multiple sections within our image, * flash programming could fail due to alignment issues * attempt to rebuild a consecutive buffer for the flash loader */ target_addr_t run_next_addr = run_address + run_size; target_addr_t next_section_base = sections[section_last + 1]->base_address; if (next_section_base < run_next_addr) { LOG_ERROR("Section at " TARGET_ADDR_FMT " overlaps section ending at " TARGET_ADDR_FMT, next_section_base, run_next_addr); LOG_ERROR("Flash write aborted."); retval = ERROR_FAIL; goto done; } pad_bytes = next_section_base - run_next_addr; if (pad_bytes) { if (flash_write_check_gap(c, run_next_addr - 1, next_section_base)) { LOG_INFO("Flash write discontinued at " TARGET_ADDR_FMT ", next section at " TARGET_ADDR_FMT, run_next_addr, next_section_base); break; } } if (pad_bytes > 0) LOG_INFO("Padding image section %d at " TARGET_ADDR_FMT " with %d bytes", section_last, run_next_addr, pad_bytes); padding[section_last] = pad_bytes; run_size += pad_bytes; run_size += sections[++section_last]->size; } if (run_address + run_size - 1 > c->base + c->size - 1) { /* If we have more than one flash chip back to back, then we limit * the current write operation to the current chip. */ LOG_DEBUG("Truncate flash run size to the current flash chip."); run_size = c->base + c->size - run_address; assert(run_size > 0); } uint32_t padding_at_start = 0; if (c->write_start_alignment || c->write_end_alignment) { /* align write region according to bank requirements */ target_addr_t aligned_start = flash_write_align_start(c, run_address); padding_at_start = run_address - aligned_start; if (padding_at_start > 0) { LOG_WARNING("Section start address " TARGET_ADDR_FMT " breaks the required alignment of flash bank %s", run_address, c->name); LOG_WARNING("Padding %" PRIu32 " bytes from " TARGET_ADDR_FMT, padding_at_start, aligned_start); run_address -= padding_at_start; run_size += padding_at_start; } target_addr_t run_end = run_address + run_size - 1; target_addr_t aligned_end = flash_write_align_end(c, run_end); pad_bytes = aligned_end - run_end; if (pad_bytes > 0) { LOG_INFO("Padding image section %d at " TARGET_ADDR_FMT " with %d bytes (bank write end alignment)", section_last, run_end + 1, pad_bytes); padding[section_last] += pad_bytes; run_size += pad_bytes; } } else if (unlock || erase) { /* If we're applying any sector automagic, then pad this * (maybe-combined) segment to the end of its last sector. */ uint32_t offset_start = run_address - c->base; uint32_t offset_end = offset_start + run_size; uint32_t end = offset_end, delta; for (unsigned int sector = 0; sector < c->num_sectors; sector++) { end = c->sectors[sector].offset + c->sectors[sector].size; if (offset_end <= end) break; } delta = end - offset_end; padding[section_last] += delta; run_size += delta; } /* allocate buffer */ buffer = malloc(run_size); if (!buffer) { LOG_ERROR("Out of memory for flash bank buffer"); retval = ERROR_FAIL; goto done; } if (padding_at_start) memset(buffer, c->default_padded_value, padding_at_start); buffer_idx = padding_at_start; /* read sections to the buffer */ while (buffer_idx < run_size) { size_t size_read; size_read = run_size - buffer_idx; if (size_read > sections[section]->size - section_offset) size_read = sections[section]->size - section_offset; /* KLUDGE! * * #¤%#"%¤% we have to figure out the section # from the sorted * list of pointers to sections to invoke image_read_section()... */ intptr_t diff = (intptr_t)sections[section] - (intptr_t)image->sections; int t_section_num = diff / sizeof(struct imagesection); LOG_DEBUG("image_read_section: section = %d, t_section_num = %d, " "section_offset = %"PRIu32", buffer_idx = %"PRIu32", size_read = %zu", section, t_section_num, section_offset, buffer_idx, size_read); retval = image_read_section(image, t_section_num, section_offset, size_read, buffer + buffer_idx, &size_read); if (retval != ERROR_OK || size_read == 0) { free(buffer); goto done; } buffer_idx += size_read; section_offset += size_read; /* see if we need to pad the section */ if (padding[section]) { memset(buffer + buffer_idx, c->default_padded_value, padding[section]); buffer_idx += padding[section]; } if (section_offset >= sections[section]->size) { section++; section_offset = 0; } } retval = ERROR_OK; if (unlock) retval = flash_unlock_address_range(target, run_address, run_size); if (retval == ERROR_OK) { if (erase) { /* calculate and erase sectors */ retval = flash_erase_address_range(target, true, run_address, run_size); } } if (retval == ERROR_OK) { if (write) { /* write flash sectors */ retval = flash_driver_write(c, buffer, run_address - c->base, run_size); } } if (retval == ERROR_OK) { if (verify) { /* verify flash sectors */ retval = flash_driver_verify(c, buffer, run_address - c->base, run_size); } } free(buffer); if (retval != ERROR_OK) { /* abort operation */ goto done; } if (written) *written += run_size; /* add run size to total written counter */ } done: free(sections); free(padding); return retval; } int flash_write(struct target *target, struct image *image, uint32_t *written, bool erase) { return flash_write_unlock_verify(target, image, written, erase, false, true, false); } struct flash_sector *alloc_block_array(uint32_t offset, uint32_t size, unsigned int num_blocks) { struct flash_sector *array = calloc(num_blocks, sizeof(struct flash_sector)); if (!array) return NULL; for (unsigned int i = 0; i < num_blocks; i++) { array[i].offset = offset; array[i].size = size; array[i].is_erased = -1; array[i].is_protected = -1; offset += size; } return array; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/core.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_CORE_H #define OPENOCD_FLASH_NOR_CORE_H #include <flash/common.h> /** * @file * Upper level NOR flash interfaces. */ struct image; /** * Describes the geometry and status of a single flash sector * within a flash bank. A single bank typically consists of multiple * sectors, each of which can be erased and protected independently. */ struct flash_sector { /** Bus offset from start of the flash chip (in bytes). */ uint32_t offset; /** Number of bytes in this flash sector. */ uint32_t size; /** * Indication of erasure status: 0 = not erased, 1 = erased, * other = unknown. Set by @c flash_driver_s::erase_check only. * * This information must be considered stale immediately. * Don't set it in flash_driver_s::erase or a device mass_erase * Don't clear it in flash_driver_s::write * The flag is not used in a protection block */ int is_erased; /** * Indication of protection status: 0 = unprotected/unlocked, * 1 = protected/locked, other = unknown. Set by * @c flash_driver_s::protect_check. * * This information must be considered stale immediately. * A million things could make it stale: power cycle, * reset of target, code running on target, etc. * * If a flash_bank uses an extra array of protection blocks, * protection flag is not valid in sector array */ int is_protected; }; /** Special value for write_start_alignment and write_end_alignment field */ #define FLASH_WRITE_ALIGN_SECTOR UINT32_MAX /** Special values for minimal_write_gap field */ #define FLASH_WRITE_CONTINUOUS 0 #define FLASH_WRITE_GAP_SECTOR UINT32_MAX /** * Provides details of a flash bank, available either on-chip or through * a major interface. * * This structure will be passed as a parameter to the callbacks in the * flash_driver_s structure, some of which may modify the contents of * this structure of the area of flash that it defines. Driver writers * may use the @c driver_priv member to store additional data on a * per-bank basis, if required. */ struct flash_bank { char *name; struct target *target; /**< Target to which this bank belongs. */ const struct flash_driver *driver; /**< Driver for this bank. */ void *driver_priv; /**< Private driver storage pointer */ unsigned int bank_number; /**< The 'bank' (or chip number) of this instance. */ target_addr_t base; /**< The base address of this bank */ uint32_t size; /**< The size of this chip bank, in bytes */ unsigned int chip_width; /**< Width of the chip in bytes (1,2,4 bytes) */ unsigned int bus_width; /**< Maximum bus width, in bytes (1,2,4 bytes) */ /** Erased value. Defaults to 0xFF. */ uint8_t erased_value; /** Default padded value used, normally this matches the flash * erased value. Defaults to 0xFF. */ uint8_t default_padded_value; /** Required alignment of flash write start address. * Default 0, no alignment. Can be any power of two or FLASH_WRITE_ALIGN_SECTOR */ uint32_t write_start_alignment; /** Required alignment of flash write end address. * Default 0, no alignment. Can be any power of two or FLASH_WRITE_ALIGN_SECTOR */ uint32_t write_end_alignment; /** Minimal gap between sections to discontinue flash write * Default FLASH_WRITE_GAP_SECTOR splits the write if one or more untouched * sectors in between. * Can be size in bytes or FLASH_WRITE_CONTINUOUS */ uint32_t minimal_write_gap; /** * The number of sectors on this chip. This value will * be set initially to 0, and the flash driver must set this to * some non-zero value during "probe()" or "auto_probe()". */ unsigned int num_sectors; /** Array of sectors, allocated and initialized by the flash driver */ struct flash_sector *sectors; /** * The number of protection blocks in this bank. This value * is set initially to 0 and sectors are used as protection blocks. * Driver probe can set protection blocks array to work with * protection granularity different than sector size. */ unsigned int num_prot_blocks; /** Array of protection blocks, allocated and initialized by the flash driver */ struct flash_sector *prot_blocks; struct flash_bank *next; /**< The next flash bank on this chip */ }; /** Registers the 'flash' subsystem commands */ int flash_register_commands(struct command_context *cmd_ctx); /** * Erases @a length bytes in the @a target flash, starting at @a addr. * The range @a addr to @a addr + @a length - 1 must be strictly * sector aligned, unless @a pad is true. Setting @a pad true extends * the range, at beginning and/or end, if needed for sector alignment. * @returns ERROR_OK if successful; otherwise, an error code. */ int flash_erase_address_range(struct target *target, bool pad, target_addr_t addr, uint32_t length); int flash_unlock_address_range(struct target *target, target_addr_t addr, uint32_t length); /** * Align start address of a flash write region according to bank requirements. * @param bank Pointer to bank descriptor structure * @param addr Address to align * @returns Aligned address */ target_addr_t flash_write_align_start(struct flash_bank *bank, target_addr_t addr); /** * Align end address of a flash write region according to bank requirements. * Note: Use address of the last byte to write, not the next after the region. * @param bank Pointer to bank descriptor structure * @param addr Address to align (address of the last byte to write) * @returns Aligned address (address of the last byte of padded region) */ target_addr_t flash_write_align_end(struct flash_bank *bank, target_addr_t addr); /** * Writes @a image into the @a target flash. The @a written parameter * will contain the * @param target The target with the flash to be programmed. * @param image The image that will be programmed to flash. * @param written On return, contains the number of bytes written. * @param erase Indicates whether the flash driver should first * erase the corresponding banks or sectors before programming. * @returns ERROR_OK if successful; otherwise, an error code. */ int flash_write(struct target *target, struct image *image, uint32_t *written, bool erase); /** * Forces targets to re-examine their erase/protection state. * This routine must be called when the system may modify the status. */ void flash_set_dirty(void); /** @returns The number of flash banks currently defined. */ unsigned int flash_get_bank_count(void); /** Deallocates bank->driver_priv */ void default_flash_free_driver_priv(struct flash_bank *bank); /** Deallocates all flash banks */ void flash_free_all_banks(void); /** * Provides default read implementation for flash memory. * @param bank The bank to read. * @param buffer The data bytes read. * @param offset The offset into the chip to read. * @param count The number of bytes to read. * @returns ERROR_OK if successful; otherwise, an error code. */ int default_flash_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); /** * Provides default verify implementation for flash memory. * @param bank The bank to verify. * @param buffer The data bytes to verify. * @param offset The offset into the chip to verify. * @param count The number of bytes to verify. * @returns ERROR_OK if successful; otherwise, an error code. */ int default_flash_verify(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count); /** * Provides default erased-bank check handling. Checks to see if * the flash driver knows they are erased; if things look uncertain, * this routine will call default_flash_mem_blank_check() to confirm. * @returns ERROR_OK if successful; otherwise, an error code. */ int default_flash_blank_check(struct flash_bank *bank); /** * Returns the flash bank specified by @a name, which matches the * driver name and a suffix (option) specify the driver-specific * bank number. The suffix consists of the '.' and the driver-specific * bank number: when two str9x banks are defined, then 'str9x.1' refers * to the second. */ int get_flash_bank_by_name(const char *name, struct flash_bank **bank_result); /** * Returns the flash bank specified by @a name, which matches the * driver name and a suffix (option) specify the driver-specific * bank number. The suffix consists of the '.' and the driver-specific * bank number: when two str9x banks are defined, then 'str9x.1' refers * to the second. */ struct flash_bank *get_flash_bank_by_name_noprobe(const char *name); /** * Returns the flash bank like get_flash_bank_by_name(), without probing. * @param num The flash bank number. * @param bank returned bank if fn returns ERROR_OK * @returns ERROR_OK if successful */ int get_flash_bank_by_num(unsigned int num, struct flash_bank **bank); /** * Retrieves @a bank from a command argument, reporting errors parsing * the bank identifier or retrieving the specified bank. The bank * may be identified by its bank number or by @c name.instance, where * @a instance is driver-specific. * @param name_index The index to the string in args containing the * bank identifier. * @param bank On output, contains a pointer to the bank or NULL. * @returns ERROR_OK on success, or an error indicating the problem. */ COMMAND_HELPER(flash_command_get_bank, unsigned name_index, struct flash_bank **bank); /** * Retrieves @a bank from a command argument, reporting errors parsing * the bank identifier or retrieving the specified bank. The bank * may be identified by its bank number or by @c name.instance, where * @a instance is driver-specific. * @param name_index The index to the string in args containing the * bank identifier. * @param bank On output, contains a pointer to the bank or NULL. * @param do_probe Does auto-probing when set, otherwise without probing. * @returns ERROR_OK on success, or an error indicating the problem. */ COMMAND_HELPER(flash_command_get_bank_probe_optional, unsigned int name_index, struct flash_bank **bank, bool do_probe); /** * Returns the flash bank like get_flash_bank_by_num(), without probing. * @param num The flash bank number. * @returns A struct flash_bank for flash bank @a num, or NULL. */ struct flash_bank *get_flash_bank_by_num_noprobe(unsigned int num); /** * Returns the flash bank located at a specified address. * @param target The target, presumed to contain one or more banks. * @param addr An address that is within the range of the bank. * @param check return ERROR_OK and result_bank NULL if the bank does not exist * @param result_bank The struct flash_bank located at @a addr, or NULL. * @returns ERROR_OK on success, or an error indicating the problem. */ int get_flash_bank_by_addr(struct target *target, target_addr_t addr, bool check, struct flash_bank **result_bank); /** * Allocate and fill an array of sectors or protection blocks. * @param offset Offset of first block. * @param size Size of each block. * @param num_blocks Number of blocks in array. * @returns A struct flash_sector pointer or NULL when allocation failed. */ struct flash_sector *alloc_block_array(uint32_t offset, uint32_t size, unsigned int num_blocks); #endif /* OPENOCD_FLASH_NOR_CORE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/driver.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_DRIVER_H #define OPENOCD_FLASH_NOR_DRIVER_H struct flash_bank; #define __FLASH_BANK_COMMAND(name) \ COMMAND_HELPER(name, struct flash_bank *bank) /** * @brief Provides the implementation-independent structure that defines * all of the callbacks required by OpenOCD flash drivers. * * Driver authors must implement the routines defined here, providing an * instance with the fields filled out. After that, the instance must * be registered in flash.c, so it can be used by the driver lookup system. * * Specifically, the user can issue the command: @par * @code * flash bank DRIVERNAME ...parameters... * @endcode * * OpenOCD will search for the driver with a @c flash_driver_s::name * that matches @c DRIVERNAME. * * The flash subsystem calls some of the other drivers routines a using * corresponding static <code>flash_driver_<i>callback</i>()</code> * routine in flash.c. */ struct flash_driver { /** * Gives a human-readable name of this flash driver, * This field is used to select and initialize the driver. */ const char *name; /** * Gives a human-readable description of arguments. */ const char *usage; /** * An array of driver-specific commands to register. When called * during the "flash bank" command, the driver can register addition * commands to support new flash chip functions. */ const struct command_registration *commands; /** * Finish the "flash bank" command for @a bank. The * @a bank parameter will have been filled in by the core flash * layer when this routine is called, and the driver can store * additional information in its struct flash_bank::driver_priv field. * * The CMD_ARGV are: @par * @code * CMD_ARGV[0] = bank * CMD_ARGV[1] = drivername {name above} * CMD_ARGV[2] = baseaddress * CMD_ARGV[3] = lengthbytes * CMD_ARGV[4] = chip_width_in bytes * CMD_ARGV[5] = bus_width_in_bytes * CMD_ARGV[6] = driver-specific parameters * @endcode * * For example, CMD_ARGV[4] = 2 (for 16 bit flash), * CMD_ARGV[5] = 4 (for 32 bit bus). * * If extra arguments are provided (@a CMD_ARGC > 6), they will * start in @a CMD_ARGV[6]. These can be used to implement * driver-specific extensions. * * @returns ERROR_OK if successful; otherwise, an error code. */ __FLASH_BANK_COMMAND((*flash_bank_command)); /** * Bank/sector erase routine (target-specific). When * called, the flash driver should erase the specified sectors * using whatever means are at its disposal. * * @param bank The bank of flash to be erased. * @param first The number of the first sector to erase, typically 0. * @param last The number of the last sector to erase, typically N-1. * @returns ERROR_OK if successful; otherwise, an error code. */ int (*erase)(struct flash_bank *bank, unsigned int first, unsigned int last); /** * Bank/sector protection routine (target-specific). * * If protection is not implemented, set method to NULL * * When called, the driver should enable/disable protection * for MINIMUM the range covered by first..last sectors * inclusive. Some chips have alignment requirements will * cause the actual range to be protected / unprotected to * be larger than the first..last range. * * @param bank The bank to protect or unprotect. * @param set If non-zero, enable protection; if 0, disable it. * @param first The first sector to (un)protect, typically 0. * @param last The last sector to (un)project, typically N-1. * @returns ERROR_OK if successful; otherwise, an error code. */ int (*protect)(struct flash_bank *bank, int set, unsigned int first, unsigned int last); /** * Program data into the flash. Note CPU address will be * "bank->base + offset", while the physical address is * dependent upon current target MMU mappings. * * @param bank The bank to program * @param buffer The data bytes to write. * @param offset The offset into the chip to program. * @param count The number of bytes to write. * @returns ERROR_OK if successful; otherwise, an error code. */ int (*write)(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count); /** * Read data from the flash. Note CPU address will be * "bank->base + offset", while the physical address is * dependent upon current target MMU mappings. * * @param bank The bank to read. * @param buffer The data bytes read. * @param offset The offset into the chip to read. * @param count The number of bytes to read. * @returns ERROR_OK if successful; otherwise, an error code. */ int (*read)(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); /** * Verify data in flash. Note CPU address will be * "bank->base + offset", while the physical address is * dependent upon current target MMU mappings. * * @param bank The bank to verify * @param buffer The data bytes to verify against. * @param offset The offset into the chip to verify. * @param count The number of bytes to verify. * @returns ERROR_OK if successful; otherwise, an error code. */ int (*verify)(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count); /** * Probe to determine what kind of flash is present. * This is invoked by the "probe" script command. * * @param bank The bank to probe * @returns ERROR_OK if successful; otherwise, an error code. */ int (*probe)(struct flash_bank *bank); /** * Check the erasure status of a flash bank. * When called, the driver routine must perform the required * checks and then set the @c flash_sector_s::is_erased field * for each of the flash banks's sectors. * * @param bank The bank to check * @returns ERROR_OK if successful; otherwise, an error code. */ int (*erase_check)(struct flash_bank *bank); /** * Determine if the specific bank is "protected" or not. * When called, the driver routine must must perform the * required protection check(s) and then set the @c * flash_sector_s::is_protected field for each of the flash * bank's sectors. * * If protection is not implemented, set method to NULL * * @param bank - the bank to check * @returns ERROR_OK if successful; otherwise, an error code. */ int (*protect_check)(struct flash_bank *bank); /** * Display human-readable information about the flash * bank. * * @param bank - the bank to get info about * @param cmd - command invocation instance for which to generate * the textual output * @returns ERROR_OK if successful; otherwise, an error code. */ int (*info)(struct flash_bank *bank, struct command_invocation *cmd); /** * A more gentle flavor of flash_driver_s::probe, performing * setup with less noise. Generally, driver routines should test * to see if the bank has already been probed; if it has, the * driver probably should not perform its probe a second time. * * This callback is often called from the inside of other * routines (e.g. GDB flash downloads) to autoprobe the flash as * it is programming the flash. * * @param bank - the bank to probe * @returns ERROR_OK if successful; otherwise, an error code. */ int (*auto_probe)(struct flash_bank *bank); /** * Deallocates private driver structures. * Use default_flash_free_driver_priv() to simply free(bank->driver_priv) * * @param bank - the bank being destroyed */ void (*free_driver_priv)(struct flash_bank *bank); }; #define FLASH_BANK_COMMAND_HANDLER(name) \ static __FLASH_BANK_COMMAND(name) /** * Find a NOR flash driver by its name. * @param name The name of the requested driver. * @returns The flash_driver called @c name, or NULL if not found. */ const struct flash_driver *flash_driver_find_by_name(const char *name); extern const struct flash_driver aduc702x_flash; extern const struct flash_driver aducm360_flash; extern const struct flash_driver ambiqmicro_flash; extern const struct flash_driver at91sam3_flash; extern const struct flash_driver at91sam4_flash; extern const struct flash_driver at91sam4l_flash; extern const struct flash_driver at91sam7_flash; extern const struct flash_driver at91samd_flash; extern const struct flash_driver ath79_flash; extern const struct flash_driver atsame5_flash; extern const struct flash_driver atsamv_flash; extern const struct flash_driver avr_flash; extern const struct flash_driver bluenrgx_flash; extern const struct flash_driver cc26xx_flash; extern const struct flash_driver cc3220sf_flash; extern const struct flash_driver cfi_flash; extern const struct flash_driver dsp5680xx_flash; extern const struct flash_driver efm32_flash; extern const struct flash_driver em357_flash; extern const struct flash_driver esirisc_flash; extern const struct flash_driver faux_flash; extern const struct flash_driver fespi_flash; extern const struct flash_driver fm3_flash; extern const struct flash_driver fm4_flash; extern const struct flash_driver jtagspi_flash; extern const struct flash_driver kinetis_flash; extern const struct flash_driver kinetis_ke_flash; extern const struct flash_driver lpc2000_flash; extern const struct flash_driver lpc288x_flash; extern const struct flash_driver lpc2900_flash; extern const struct flash_driver lpcspifi_flash; extern const struct flash_driver max32xxx_flash; extern const struct flash_driver mdr_flash; extern const struct flash_driver mrvlqspi_flash; extern const struct flash_driver msp432_flash; extern const struct flash_driver niietcm4_flash; extern const struct flash_driver npcx_flash; extern const struct flash_driver nrf51_flash; extern const struct flash_driver nrf5_flash; extern const struct flash_driver numicro_flash; extern const struct flash_driver ocl_flash; extern const struct flash_driver pic32mx_flash; extern const struct flash_driver psoc4_flash; extern const struct flash_driver psoc5lp_eeprom_flash; extern const struct flash_driver psoc5lp_flash; extern const struct flash_driver psoc5lp_nvl_flash; extern const struct flash_driver psoc6_flash; extern const struct flash_driver qn908x_flash; extern const struct flash_driver renesas_rpchf_flash; extern const struct flash_driver rp2040_flash; extern const struct flash_driver rsl10_flash; extern const struct flash_driver sh_qspi_flash; extern const struct flash_driver sim3x_flash; extern const struct flash_driver stellaris_flash; extern const struct flash_driver stm32f1x_flash; extern const struct flash_driver stm32f2x_flash; extern const struct flash_driver stm32h7x_flash; extern const struct flash_driver stm32l4x_flash; extern const struct flash_driver stm32lx_flash; extern const struct flash_driver stmqspi_flash; extern const struct flash_driver stmsmi_flash; extern const struct flash_driver str7x_flash; extern const struct flash_driver str9x_flash; extern const struct flash_driver str9xpec_flash; extern const struct flash_driver swm050_flash; extern const struct flash_driver tms470_flash; extern const struct flash_driver virtual_flash; extern const struct flash_driver w600_flash; extern const struct flash_driver xcf_flash; extern const struct flash_driver xmc1xxx_flash; extern const struct flash_driver xmc4xxx_flash; #endif /* OPENOCD_FLASH_NOR_DRIVER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/drivers.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" /** * The list of built-in flash drivers. * @todo Make this dynamically extendable with loadable modules. */ static const struct flash_driver * const flash_drivers[] = { &aduc702x_flash, &aducm360_flash, &ambiqmicro_flash, &at91sam3_flash, &at91sam4_flash, &at91sam4l_flash, &at91sam7_flash, &at91samd_flash, &ath79_flash, &atsame5_flash, &atsamv_flash, &avr_flash, &bluenrgx_flash, &cc3220sf_flash, &cc26xx_flash, &cfi_flash, &dsp5680xx_flash, &efm32_flash, &em357_flash, &esirisc_flash, &faux_flash, &fm3_flash, &fm4_flash, &fespi_flash, &jtagspi_flash, &kinetis_flash, &kinetis_ke_flash, &lpc2000_flash, &lpc288x_flash, &lpc2900_flash, &lpcspifi_flash, &max32xxx_flash, &mdr_flash, &mrvlqspi_flash, &msp432_flash, &niietcm4_flash, &npcx_flash, &nrf5_flash, &nrf51_flash, &numicro_flash, &ocl_flash, &pic32mx_flash, &psoc4_flash, &psoc5lp_flash, &psoc5lp_eeprom_flash, &psoc5lp_nvl_flash, &psoc6_flash, &qn908x_flash, &renesas_rpchf_flash, &rp2040_flash, &sh_qspi_flash, &sim3x_flash, &stellaris_flash, &stm32f1x_flash, &stm32f2x_flash, &stm32lx_flash, &stm32l4x_flash, &stm32h7x_flash, &stmsmi_flash, &stmqspi_flash, &str7x_flash, &str9x_flash, &str9xpec_flash, &swm050_flash, &tms470_flash, &virtual_flash, &xcf_flash, &xmc1xxx_flash, &xmc4xxx_flash, &w600_flash, &rsl10_flash, NULL, }; const struct flash_driver *flash_driver_find_by_name(const char *name) { for (unsigned i = 0; flash_drivers[i]; i++) { if (strcmp(name, flash_drivers[i]->name) == 0) return flash_drivers[i]; } return NULL; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/dsp5680xx_flash.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Rodrigo L. Rosa * * rodrigorosa.LG@gmail.com * * * * Based on a file written by: * * Kevin McGuire * * Marcel Wijlaars * * Michael Ashton * ***************************************************************************/ /** * @file dsp5680xx_flash.c * @author Rodrigo L. Rosa <rodrigorosa.LG@gmail.com> * @date Thu Jun 9 18:21:58 2011 * * @brief This file implements the basic functions to run flashing commands * from the TCL interface. * It allows the user to flash the Freescale 5680xx DSP. * * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <helper/time_support.h> #include <target/algorithm.h> #include <target/dsp5680xx.h> static int dsp5680xx_build_sector_list(struct flash_bank *bank) { bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; ++i) { bank->sectors[i].offset = i * HFM_SECTOR_SIZE; bank->sectors[i].size = HFM_SECTOR_SIZE; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } LOG_USER("%s not tested yet.", __func__); return ERROR_OK; } /* flash bank dsp5680xx 0 0 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(dsp5680xx_flash_bank_command) { bank->base = HFM_FLASH_BASE_ADDR; bank->size = HFM_SIZE_BYTES; /* top 4k not accessible */ bank->num_sectors = HFM_SECTOR_COUNT; dsp5680xx_build_sector_list(bank); return ERROR_OK; } /** * A memory mapped register (PROT) holds information regarding sector protection. * Protection refers to undesired core access. * The value in this register is loaded from flash upon reset. * * @param bank * * @return */ static int dsp5680xx_flash_protect_check(struct flash_bank *bank) { int retval = ERROR_OK; uint16_t protected = 0; retval = dsp5680xx_f_protect_check(bank->target, &protected); if (retval != ERROR_OK) { for (int i = 0; i < HFM_SECTOR_COUNT; i++) bank->sectors[i].is_protected = -1; return ERROR_OK; } for (int i = 0; i < HFM_SECTOR_COUNT / 2; i++) { if (protected & 1) { bank->sectors[2 * i].is_protected = 1; bank->sectors[2 * i + 1].is_protected = 1; } else { bank->sectors[2 * i].is_protected = 0; bank->sectors[2 * i + 1].is_protected = 0; } protected = (protected >> 1); } return retval; } /** * Protection functionality is not implemented. * The current implementation applies/removes security on the chip. * The chip is effectively secured/unsecured after the first reset * following the execution of this function. * * @param bank * @param set Apply or remove security on the chip. * @param first This parameter is ignored. * @param last This parameter is ignored. * * @return */ static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { /** * This applies security to flash module after next reset, it does * not actually apply protection (protection refers to undesired access from the core) */ int retval; if (set) retval = dsp5680xx_f_lock(bank->target); else retval = dsp5680xx_f_unlock(bank->target); return retval; } /** * The dsp5680xx use word addressing. The "/2" that appear in the following code * are a workaround for the fact that OpenOCD uses byte addressing. * * @param bank * @param buffer Data to write to flash. * @param offset * @param count In bytes (2 bytes per address). * * @return */ static int dsp5680xx_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { if ((offset + count / 2) > bank->size) { LOG_ERROR("%s: Flash bank cannot fit data.", __func__); return ERROR_FAIL; } if (offset % 2) { /** * Writing to odd addresses not supported. * This chip uses word addressing, Openocd only supports byte addressing. * The workaround results in disabling writing to odd byte addresses */ LOG_ERROR("%s: Writing to odd addresses not supported for this target", __func__); return ERROR_FAIL; } return dsp5680xx_f_wr(bank->target, buffer, bank->base + offset / 2, count, 0); } static int dsp5680xx_probe(struct flash_bank *bank) { LOG_DEBUG("%s not implemented", __func__); return ERROR_OK; } /** * The flash module (FM) on the dsp5680xx supports both individual sector * and mass erase of the flash memory. * If this function is called with @a first == @a last == 0 or if @a first is the * first sector (#0) and @a last is the last sector then the mass erase command * is executed (much faster than erasing each sector individually). * * @param bank * @param first * @param last * * @return */ static int dsp5680xx_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { return dsp5680xx_f_erase(bank->target, (uint32_t) first, (uint32_t) last); } /** * The flash module (FM) on the dsp5680xx support a blank check function. * This function executes the FM's blank check functionality on each and every sector. * * @param bank * * @return */ static int dsp5680xx_flash_erase_check(struct flash_bank *bank) { int retval = ERROR_OK; uint8_t erased = 0; uint32_t i; for (i = 0; i < HFM_SECTOR_COUNT; i++) { retval = dsp5680xx_f_erase_check(bank->target, &erased, i); if (retval != ERROR_OK) { bank->sectors[i].is_erased = -1; } else { if (erased) bank->sectors[i].is_erased = 1; else bank->sectors[i].is_erased = 0; } } return retval; } const struct flash_driver dsp5680xx_flash = { .name = "dsp5680xx_flash", .flash_bank_command = dsp5680xx_flash_bank_command, .erase = dsp5680xx_flash_erase, .protect = dsp5680xx_flash_protect, .write = dsp5680xx_flash_write, /* .read = default_flash_read, */ .probe = dsp5680xx_probe, .auto_probe = dsp5680xx_probe, .erase_check = dsp5680xx_flash_erase_check, .protect_check = dsp5680xx_flash_protect_check, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/efm32.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * * * * Copyright (C) 2013 by Roman Dmitrienko * * me@iamroman.org * * * * Copyright (C) 2014 Nemui Trinomius * * nemuisan_kawausogasuki@live.jp * * * * Copyright (C) 2021 Doug Brunner * * doug.a.brunner@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> #include <target/cortex_m.h> #define EFM_FAMILY_ID_GIANT_GECKO 72 #define EFM_FAMILY_ID_LEOPARD_GECKO 74 #define EFM32_FLASH_ERASE_TMO 100 #define EFM32_FLASH_WDATAREADY_TMO 100 #define EFM32_FLASH_WRITE_TMO 100 #define EFM32_FLASH_BASE 0 /* size in bytes, not words; must fit all Gecko devices */ #define LOCKWORDS_SZ 512 #define EFM32_MSC_INFO_BASE 0x0fe00000 #define EFM32_MSC_USER_DATA EFM32_MSC_INFO_BASE #define EFM32_MSC_LOCK_BITS (EFM32_MSC_INFO_BASE+0x4000) #define EFM32_MSC_LOCK_BITS_EXTRA (EFM32_MSC_LOCK_BITS+LOCKWORDS_SZ) #define EFM32_MSC_DEV_INFO (EFM32_MSC_INFO_BASE+0x8000) /* PAGE_SIZE is not present in Zero, Happy and the original Gecko MCU */ #define EFM32_MSC_DI_PAGE_SIZE (EFM32_MSC_DEV_INFO+0x1e7) #define EFM32_MSC_DI_FLASH_SZ (EFM32_MSC_DEV_INFO+0x1f8) #define EFM32_MSC_DI_RAM_SZ (EFM32_MSC_DEV_INFO+0x1fa) #define EFM32_MSC_DI_PART_NUM (EFM32_MSC_DEV_INFO+0x1fc) #define EFM32_MSC_DI_PART_FAMILY (EFM32_MSC_DEV_INFO+0x1fe) #define EFM32_MSC_DI_PROD_REV (EFM32_MSC_DEV_INFO+0x1ff) #define EFM32_MSC_REGBASE 0x400c0000 #define EFM32_MSC_REGBASE_SERIES1 0x400e0000 #define EFM32_MSC_REG_WRITECTRL 0x008 #define EFM32_MSC_WRITECTRL_WREN_MASK 0x1 #define EFM32_MSC_REG_WRITECMD 0x00c #define EFM32_MSC_WRITECMD_LADDRIM_MASK 0x1 #define EFM32_MSC_WRITECMD_ERASEPAGE_MASK 0x2 #define EFM32_MSC_WRITECMD_WRITEONCE_MASK 0x8 #define EFM32_MSC_REG_ADDRB 0x010 #define EFM32_MSC_REG_WDATA 0x018 #define EFM32_MSC_REG_STATUS 0x01c #define EFM32_MSC_STATUS_BUSY_MASK 0x1 #define EFM32_MSC_STATUS_LOCKED_MASK 0x2 #define EFM32_MSC_STATUS_INVADDR_MASK 0x4 #define EFM32_MSC_STATUS_WDATAREADY_MASK 0x8 #define EFM32_MSC_STATUS_WORDTIMEOUT_MASK 0x10 #define EFM32_MSC_STATUS_ERASEABORTED_MASK 0x20 #define EFM32_MSC_REG_LOCK 0x03c #define EFM32_MSC_REG_LOCK_SERIES1 0x040 #define EFM32_MSC_LOCK_LOCKKEY 0x1b71 enum efm32_bank_index { EFM32_BANK_INDEX_MAIN, EFM32_BANK_INDEX_USER_DATA, EFM32_BANK_INDEX_LOCK_BITS, EFM32_N_BANKS }; static int efm32x_get_bank_index(target_addr_t base) { switch (base) { case EFM32_FLASH_BASE: return EFM32_BANK_INDEX_MAIN; case EFM32_MSC_USER_DATA: return EFM32_BANK_INDEX_USER_DATA; case EFM32_MSC_LOCK_BITS: return EFM32_BANK_INDEX_LOCK_BITS; default: return ERROR_FAIL; } } struct efm32_family_data { int family_id; const char *name; /* EFM32 series (EFM32LG995F is the "old" series 0, while EFR32MG12P132 is the "new" series 1). Determines location of MSC registers. */ int series; /* Page size in bytes, or 0 to read from EFM32_MSC_DI_PAGE_SIZE */ int page_size; /* MSC register base address, or 0 to use default */ uint32_t msc_regbase; }; struct efm32_info { const struct efm32_family_data *family_data; uint16_t flash_sz_kib; uint16_t ram_sz_kib; uint16_t part_num; uint8_t part_family; uint8_t prod_rev; uint16_t page_size; }; struct efm32x_flash_chip { struct efm32_info info; bool probed[EFM32_N_BANKS]; uint32_t lb_page[LOCKWORDS_SZ/4]; uint32_t reg_base; uint32_t reg_lock; uint32_t refcount; }; static const struct efm32_family_data efm32_families[] = { { 16, "EFR32MG1P Mighty", .series = 1 }, { 17, "EFR32MG1B Mighty", .series = 1 }, { 18, "EFR32MG1V Mighty", .series = 1 }, { 19, "EFR32BG1P Blue", .series = 1 }, { 20, "EFR32BG1B Blue", .series = 1 }, { 21, "EFR32BG1V Blue", .series = 1 }, { 25, "EFR32FG1P Flex", .series = 1 }, { 26, "EFR32FG1B Flex", .series = 1 }, { 27, "EFR32FG1V Flex", .series = 1 }, { 28, "EFR32MG2P Mighty", .series = 1 }, { 29, "EFR32MG2B Mighty", .series = 1 }, { 30, "EFR32MG2V Mighty", .series = 1 }, { 31, "EFR32BG12P Blue", .series = 1 }, { 32, "EFR32BG12B Blue", .series = 1 }, { 33, "EFR32BG12V Blue", .series = 1 }, { 37, "EFR32FG12P Flex", .series = 1 }, { 38, "EFR32FG12B Flex", .series = 1 }, { 39, "EFR32FG12V Flex", .series = 1 }, { 40, "EFR32MG13P Mighty", .series = 1 }, { 41, "EFR32MG13B Mighty", .series = 1 }, { 42, "EFR32MG13V Mighty", .series = 1 }, { 43, "EFR32BG13P Blue", .series = 1 }, { 44, "EFR32BG13B Blue", .series = 1 }, { 45, "EFR32BG13V Blue", .series = 1 }, { 46, "EFR32ZG13P Zen", .series = 1 }, { 49, "EFR32FG13P Flex", .series = 1 }, { 50, "EFR32FG13B Flex", .series = 1 }, { 51, "EFR32FG13V Flex", .series = 1 }, { 52, "EFR32MG14P Mighty", .series = 1 }, { 53, "EFR32MG14B Mighty", .series = 1 }, { 54, "EFR32MG14V Mighty", .series = 1 }, { 55, "EFR32BG14P Blue", .series = 1 }, { 56, "EFR32BG14B Blue", .series = 1 }, { 57, "EFR32BG14V Blue", .series = 1 }, { 58, "EFR32ZG14P Zen", .series = 1 }, { 61, "EFR32FG14P Flex", .series = 1 }, { 62, "EFR32FG14B Flex", .series = 1 }, { 63, "EFR32FG14V Flex", .series = 1 }, { 71, "EFM32G", .series = 0, .page_size = 512 }, { 72, "EFM32GG Giant", .series = 0 }, { 73, "EFM32TG Tiny", .series = 0, .page_size = 512 }, { 74, "EFM32LG Leopard", .series = 0 }, { 75, "EFM32WG Wonder", .series = 0 }, { 76, "EFM32ZG Zero", .series = 0, .page_size = 1024 }, { 77, "EFM32HG Happy", .series = 0, .page_size = 1024 }, { 81, "EFM32PG1B Pearl", .series = 1 }, { 83, "EFM32JG1B Jade", .series = 1 }, { 85, "EFM32PG12B Pearl", .series = 1 }, { 87, "EFM32JG12B Jade", .series = 1 }, { 89, "EFM32PG13B Pearl", .series = 1 }, { 91, "EFM32JG13B Jade", .series = 1 }, { 100, "EFM32GG11B Giant", .series = 1, .msc_regbase = 0x40000000 }, { 103, "EFM32TG11B Tiny", .series = 1, .msc_regbase = 0x40000000 }, { 106, "EFM32GG12B Giant", .series = 1, .msc_regbase = 0x40000000 }, { 120, "EZR32WG Wonder", .series = 0 }, { 121, "EZR32LG Leopard", .series = 0 }, { 122, "EZR32HG Happy", .series = 0, .page_size = 1024 }, }; const struct flash_driver efm32_flash; static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t addr, uint32_t count); static int efm32x_write_only_lockbits(struct flash_bank *bank); static int efm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_sz) { return target_read_u16(bank->target, EFM32_MSC_DI_FLASH_SZ, flash_sz); } static int efm32x_get_ram_size(struct flash_bank *bank, uint16_t *ram_sz) { return target_read_u16(bank->target, EFM32_MSC_DI_RAM_SZ, ram_sz); } static int efm32x_get_part_num(struct flash_bank *bank, uint16_t *pnum) { return target_read_u16(bank->target, EFM32_MSC_DI_PART_NUM, pnum); } static int efm32x_get_part_family(struct flash_bank *bank, uint8_t *pfamily) { return target_read_u8(bank->target, EFM32_MSC_DI_PART_FAMILY, pfamily); } static int efm32x_get_prod_rev(struct flash_bank *bank, uint8_t *prev) { return target_read_u8(bank->target, EFM32_MSC_DI_PROD_REV, prev); } static int efm32x_read_reg_u32(struct flash_bank *bank, target_addr_t offset, uint32_t *value) { struct efm32x_flash_chip *efm32x_info = bank->driver_priv; uint32_t base = efm32x_info->reg_base; return target_read_u32(bank->target, base + offset, value); } static int efm32x_write_reg_u32(struct flash_bank *bank, target_addr_t offset, uint32_t value) { struct efm32x_flash_chip *efm32x_info = bank->driver_priv; uint32_t base = efm32x_info->reg_base; return target_write_u32(bank->target, base + offset, value); } static int efm32x_read_info(struct flash_bank *bank) { int ret; struct efm32x_flash_chip *efm32x_info = bank->driver_priv; struct efm32_info *efm32_info = &(efm32x_info->info); memset(efm32_info, 0, sizeof(struct efm32_info)); const struct cortex_m_common *cortex_m = target_to_cm(bank->target); switch (cortex_m->core_info->partno) { case CORTEX_M3_PARTNO: case CORTEX_M4_PARTNO: case CORTEX_M0P_PARTNO: break; default: LOG_ERROR("Target is not Cortex-Mx Device"); return ERROR_FAIL; } ret = efm32x_get_flash_size(bank, &(efm32_info->flash_sz_kib)); if (ret != ERROR_OK) return ret; ret = efm32x_get_ram_size(bank, &(efm32_info->ram_sz_kib)); if (ret != ERROR_OK) return ret; ret = efm32x_get_part_num(bank, &(efm32_info->part_num)); if (ret != ERROR_OK) return ret; ret = efm32x_get_part_family(bank, &(efm32_info->part_family)); if (ret != ERROR_OK) return ret; ret = efm32x_get_prod_rev(bank, &(efm32_info->prod_rev)); if (ret != ERROR_OK) return ret; for (size_t i = 0; i < ARRAY_SIZE(efm32_families); i++) { if (efm32_families[i].family_id == efm32_info->part_family) efm32_info->family_data = &efm32_families[i]; } if (!efm32_info->family_data) { LOG_ERROR("Unknown MCU family %d", efm32_info->part_family); return ERROR_FAIL; } switch (efm32_info->family_data->series) { case 0: efm32x_info->reg_base = EFM32_MSC_REGBASE; efm32x_info->reg_lock = EFM32_MSC_REG_LOCK; break; case 1: efm32x_info->reg_base = EFM32_MSC_REGBASE_SERIES1; efm32x_info->reg_lock = EFM32_MSC_REG_LOCK_SERIES1; break; } if (efm32_info->family_data->msc_regbase != 0) efm32x_info->reg_base = efm32_info->family_data->msc_regbase; if (efm32_info->family_data->page_size != 0) { efm32_info->page_size = efm32_info->family_data->page_size; } else { uint8_t pg_size = 0; ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE, &pg_size); if (ret != ERROR_OK) return ret; efm32_info->page_size = (1 << ((pg_size+10) & 0xff)); if (efm32_info->part_family == EFM_FAMILY_ID_GIANT_GECKO || efm32_info->part_family == EFM_FAMILY_ID_LEOPARD_GECKO) { /* Giant or Leopard Gecko */ if (efm32_info->prod_rev < 18) { /* EFM32 GG/LG errata: MEM_INFO_PAGE_SIZE is invalid for MCUs with PROD_REV < 18 */ if (efm32_info->flash_sz_kib < 512) efm32_info->page_size = 2048; else efm32_info->page_size = 4096; } } if ((efm32_info->page_size != 2048) && (efm32_info->page_size != 4096)) { LOG_ERROR("Invalid page size %u", efm32_info->page_size); return ERROR_FAIL; } } return ERROR_OK; } /* flash bank efm32 <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(efm32x_flash_bank_command) { struct efm32x_flash_chip *efm32x_info = NULL; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; int bank_index = efm32x_get_bank_index(bank->base); if (bank_index < 0) { LOG_ERROR("Flash bank with base address %" PRIx32 " is not supported", (uint32_t) bank->base); return ERROR_FAIL; } /* look for an existing flash structure matching target */ for (struct flash_bank *bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) { if (bank_iter->driver == &efm32_flash && bank_iter->target == bank->target && bank->driver_priv) { efm32x_info = bank->driver_priv; break; } } if (!efm32x_info) { /* target not matched, make a new one */ efm32x_info = calloc(1, sizeof(struct efm32x_flash_chip)); memset(efm32x_info->lb_page, 0xff, LOCKWORDS_SZ); } ++efm32x_info->refcount; bank->driver_priv = efm32x_info; return ERROR_OK; } /** * Remove flash structure corresponding to this bank, * if and only if it's not used by any others */ static void efm32x_free_driver_priv(struct flash_bank *bank) { struct efm32x_flash_chip *efm32x_info = bank->driver_priv; if (efm32x_info) { /* Use ref count to determine if it can be freed; scanning bank list doesn't work, * because this function can be called after some banks in the list have been * already destroyed */ --efm32x_info->refcount; if (efm32x_info->refcount == 0) { free(efm32x_info); bank->driver_priv = NULL; } } } /* set or reset given bits in a register */ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg, uint32_t bitmask, int set) { int ret = 0; uint32_t reg_val = 0; ret = efm32x_read_reg_u32(bank, reg, ®_val); if (ret != ERROR_OK) return ret; if (set) reg_val |= bitmask; else reg_val &= ~bitmask; return efm32x_write_reg_u32(bank, reg, reg_val); } static int efm32x_set_wren(struct flash_bank *bank, int write_enable) { return efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECTRL, EFM32_MSC_WRITECTRL_WREN_MASK, write_enable); } static int efm32x_msc_lock(struct flash_bank *bank, int lock) { struct efm32x_flash_chip *efm32x_info = bank->driver_priv; return efm32x_write_reg_u32(bank, efm32x_info->reg_lock, (lock ? 0 : EFM32_MSC_LOCK_LOCKKEY)); } static int efm32x_wait_status(struct flash_bank *bank, int timeout, uint32_t wait_mask, int wait_for_set) { int ret = 0; uint32_t status = 0; while (1) { ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); if (ret != ERROR_OK) break; LOG_DEBUG("status: 0x%" PRIx32 "", status); if (((status & wait_mask) == 0) && (wait_for_set == 0)) break; else if (((status & wait_mask) != 0) && wait_for_set) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for MSC status"); return ERROR_FAIL; } alive_sleep(1); } if (status & EFM32_MSC_STATUS_ERASEABORTED_MASK) LOG_WARNING("page erase was aborted"); return ret; } static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) { /* this function DOES NOT set WREN; must be set already */ /* 1. write address to ADDRB 2. write LADDRIM 3. check status (INVADDR, LOCKED) 4. write ERASEPAGE 5. wait until !STATUS_BUSY */ int ret = 0; uint32_t status = 0; LOG_DEBUG("erasing flash page at 0x%08" PRIx32, addr); ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr); if (ret != ERROR_OK) return ret; ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); if (ret != ERROR_OK) return ret; ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); if (ret != ERROR_OK) return ret; LOG_DEBUG("status 0x%" PRIx32, status); if (status & EFM32_MSC_STATUS_LOCKED_MASK) { LOG_ERROR("Page is locked"); return ERROR_FAIL; } else if (status & EFM32_MSC_STATUS_INVADDR_MASK) { LOG_ERROR("Invalid address 0x%" PRIx32, addr); return ERROR_FAIL; } ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_ERASEPAGE_MASK, 1); if (ret != ERROR_OK) return ret; return efm32x_wait_status(bank, EFM32_FLASH_ERASE_TMO, EFM32_MSC_STATUS_BUSY_MASK, 0); } static int efm32x_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; int ret = 0; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } efm32x_msc_lock(bank, 0); ret = efm32x_set_wren(bank, 1); if (ret != ERROR_OK) { LOG_ERROR("Failed to enable MSC write"); return ret; } for (unsigned int i = first; i <= last; i++) { ret = efm32x_erase_page(bank, bank->base + bank->sectors[i].offset); if (ret != ERROR_OK) LOG_ERROR("Failed to erase page %d", i); } ret = efm32x_set_wren(bank, 0); efm32x_msc_lock(bank, 1); if (ret != ERROR_OK) return ret; if (bank->base == EFM32_MSC_LOCK_BITS) { ret = efm32x_write_only_lockbits(bank); if (ret != ERROR_OK) LOG_ERROR("Failed to restore lockbits after erase"); } return ret; } static int efm32x_read_lock_data(struct flash_bank *bank) { struct efm32x_flash_chip *efm32x_info = bank->driver_priv; struct target *target = bank->target; int data_size = 0; uint32_t *ptr = NULL; int ret = 0; assert(bank->num_sectors > 0); /* calculate the number of 32-bit words to read (one lock bit per sector) */ data_size = (bank->num_sectors + 31) / 32; ptr = efm32x_info->lb_page; for (int i = 0; i < data_size; i++, ptr++) { ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+i*4, ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read PLW %d", i); return ret; } } /* also, read ULW, DLW, MLW, ALW and CLW words */ /* ULW, word 126 */ ptr = efm32x_info->lb_page + 126; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+126*4, ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read ULW"); return ret; } /* DLW, word 127 */ ptr = efm32x_info->lb_page + 127; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+127*4, ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read DLW"); return ret; } /* MLW, word 125, present in GG, LG, PG, JG, EFR32 */ ptr = efm32x_info->lb_page + 125; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+125*4, ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read MLW"); return ret; } /* ALW, word 124, present in GG, LG, PG, JG, EFR32 */ ptr = efm32x_info->lb_page + 124; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+124*4, ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read ALW"); return ret; } /* CLW1, word 123, present in EFR32 */ ptr = efm32x_info->lb_page + 123; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+123*4, ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read CLW1"); return ret; } /* CLW0, word 122, present in GG, LG, PG, JG, EFR32 */ ptr = efm32x_info->lb_page + 122; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+122*4, ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read CLW0"); return ret; } return ERROR_OK; } static int efm32x_write_only_lockbits(struct flash_bank *bank) { struct efm32x_flash_chip *efm32x_info = bank->driver_priv; return efm32x_priv_write(bank, (uint8_t *)efm32x_info->lb_page, EFM32_MSC_LOCK_BITS, LOCKWORDS_SZ); } static int efm32x_write_lock_data(struct flash_bank *bank) { struct efm32x_flash_chip *efm32x_info = bank->driver_priv; int ret = 0; /* Preserve any data written to the high portion of the lockbits page */ assert(efm32x_info->info.page_size >= LOCKWORDS_SZ); uint32_t extra_bytes = efm32x_info->info.page_size - LOCKWORDS_SZ; uint8_t *extra_data = NULL; if (extra_bytes) { extra_data = malloc(extra_bytes); ret = target_read_buffer(bank->target, EFM32_MSC_LOCK_BITS_EXTRA, extra_bytes, extra_data); if (ret != ERROR_OK) { LOG_ERROR("Failed to read extra contents of LB page"); free(extra_data); return ret; } } ret = efm32x_erase_page(bank, EFM32_MSC_LOCK_BITS); if (ret != ERROR_OK) { LOG_ERROR("Failed to erase LB page"); if (extra_data) free(extra_data); return ret; } if (extra_data) { ret = efm32x_priv_write(bank, extra_data, EFM32_MSC_LOCK_BITS_EXTRA, extra_bytes); free(extra_data); if (ret != ERROR_OK) { LOG_ERROR("Failed to restore extra contents of LB page"); return ret; } } return efm32x_write_only_lockbits(bank); } static int efm32x_get_page_lock(struct flash_bank *bank, size_t page) { struct efm32x_flash_chip *efm32x_info = bank->driver_priv; uint32_t dw = 0; uint32_t mask = 0; switch (bank->base) { case EFM32_FLASH_BASE: dw = efm32x_info->lb_page[page >> 5]; mask = 1 << (page & 0x1f); break; case EFM32_MSC_USER_DATA: dw = efm32x_info->lb_page[126]; mask = 0x1; break; case EFM32_MSC_LOCK_BITS: dw = efm32x_info->lb_page[126]; mask = 0x2; break; } return (dw & mask) ? 0 : 1; } static int efm32x_set_page_lock(struct flash_bank *bank, size_t page, int set) { struct efm32x_flash_chip *efm32x_info = bank->driver_priv; if (bank->base != EFM32_FLASH_BASE) { LOG_ERROR("Locking user and lockbits pages is not supported yet"); return ERROR_FAIL; } uint32_t *dw = &efm32x_info->lb_page[page >> 5]; uint32_t mask = 0; mask = 1 << (page & 0x1f); if (!set) *dw |= mask; else *dw &= ~mask; return ERROR_OK; } static int efm32x_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct target *target = bank->target; int ret = 0; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } for (unsigned int i = first; i <= last; i++) { ret = efm32x_set_page_lock(bank, i, set); if (ret != ERROR_OK) { LOG_ERROR("Failed to set lock on page %d", i); return ret; } } ret = efm32x_write_lock_data(bank); if (ret != ERROR_OK) { LOG_ERROR("Failed to write LB page"); return ret; } return ERROR_OK; } static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, uint32_t address, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; struct efm32x_flash_chip *efm32x_info = bank->driver_priv; int ret = ERROR_OK; /* see contrib/loaders/flash/efm32.S for src */ static const uint8_t efm32x_flash_write_code[] = { /* #define EFM32_MSC_WRITECTRL_OFFSET 0x008 */ /* #define EFM32_MSC_WRITECMD_OFFSET 0x00c */ /* #define EFM32_MSC_ADDRB_OFFSET 0x010 */ /* #define EFM32_MSC_WDATA_OFFSET 0x018 */ /* #define EFM32_MSC_STATUS_OFFSET 0x01c */ 0x01, 0x26, /* movs r6, #1 */ 0x86, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET] */ /* wait_fifo: */ 0x16, 0x68, /* ldr r6, [r2, #0] */ 0x00, 0x2e, /* cmp r6, #0 */ 0x22, 0xd0, /* beq exit */ 0x55, 0x68, /* ldr r5, [r2, #4] */ 0xb5, 0x42, /* cmp r5, r6 */ 0xf9, 0xd0, /* beq wait_fifo */ 0x04, 0x61, /* str r4, [r0, #EFM32_MSC_ADDRB_OFFSET] */ 0x01, 0x26, /* movs r6, #1 */ 0xc6, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET] */ 0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */ 0x06, 0x27, /* movs r7, #6 */ 0x3e, 0x42, /* tst r6, r7 */ 0x16, 0xd1, /* bne error */ /* wait_wdataready: */ 0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */ 0x08, 0x27, /* movs r7, #8 */ 0x3e, 0x42, /* tst r6, r7 */ 0xfb, 0xd0, /* beq wait_wdataready */ 0x2e, 0x68, /* ldr r6, [r5] */ 0x86, 0x61, /* str r6, [r0, #EFM32_MSC_WDATA_OFFSET] */ 0x08, 0x26, /* movs r6, #8 */ 0xc6, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET] */ 0x04, 0x35, /* adds r5, #4 */ 0x04, 0x34, /* adds r4, #4 */ /* busy: */ 0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */ 0x01, 0x27, /* movs r7, #1 */ 0x3e, 0x42, /* tst r6, r7 */ 0xfb, 0xd1, /* bne busy */ 0x9d, 0x42, /* cmp r5, r3 */ 0x01, 0xd3, /* bcc no_wrap */ 0x15, 0x46, /* mov r5, r2 */ 0x08, 0x35, /* adds r5, #8 */ /* no_wrap: */ 0x55, 0x60, /* str r5, [r2, #4] */ 0x01, 0x39, /* subs r1, r1, #1 */ 0x00, 0x29, /* cmp r1, #0 */ 0x02, 0xd0, /* beq exit */ 0xdb, 0xe7, /* b wait_fifo */ /* error: */ 0x00, 0x20, /* movs r0, #0 */ 0x50, 0x60, /* str r0, [r2, #4] */ /* exit: */ 0x30, 0x46, /* mov r0, r6 */ 0x00, 0xbe, /* bkpt #0 */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(efm32x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } ret = target_write_buffer(target, write_algorithm->address, sizeof(efm32x_flash_write_code), efm32x_flash_write_code); if (ret != ERROR_OK) return ret; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */ if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (word-32bit) */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ buf_set_u32(reg_params[0].value, 0, 32, efm32x_info->reg_base); buf_set_u32(reg_params[1].value, 0, 32, count); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[4].value, 0, 32, address); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; ret = target_run_flash_async_algorithm(target, buf, count, 4, 0, NULL, 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (ret == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("flash write failed at address 0x%"PRIx32, buf_get_u32(reg_params[4].value, 0, 32)); if (buf_get_u32(reg_params[0].value, 0, 32) & EFM32_MSC_STATUS_LOCKED_MASK) { LOG_ERROR("flash memory write protected"); } if (buf_get_u32(reg_params[0].value, 0, 32) & EFM32_MSC_STATUS_INVADDR_MASK) { LOG_ERROR("invalid flash memory write address"); } } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return ret; } static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, uint32_t val) { /* this function DOES NOT set WREN; must be set already */ /* 1. write address to ADDRB 2. write LADDRIM 3. check status (INVADDR, LOCKED) 4. wait for WDATAREADY 5. write data to WDATA 6. write WRITECMD_WRITEONCE to WRITECMD 7. wait until !STATUS_BUSY */ /* FIXME: EFM32G ref states (7.3.2) that writes should be * performed twice per dword */ int ret = 0; uint32_t status = 0; /* if not called, GDB errors will be reported during large writes */ keep_alive(); ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr); if (ret != ERROR_OK) return ret; ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); if (ret != ERROR_OK) return ret; ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); if (ret != ERROR_OK) return ret; LOG_DEBUG("status 0x%" PRIx32, status); if (status & EFM32_MSC_STATUS_LOCKED_MASK) { LOG_ERROR("Page is locked"); return ERROR_FAIL; } else if (status & EFM32_MSC_STATUS_INVADDR_MASK) { LOG_ERROR("Invalid address 0x%" PRIx32, addr); return ERROR_FAIL; } ret = efm32x_wait_status(bank, EFM32_FLASH_WDATAREADY_TMO, EFM32_MSC_STATUS_WDATAREADY_MASK, 1); if (ret != ERROR_OK) { LOG_ERROR("Wait for WDATAREADY failed"); return ret; } ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WDATA, val); if (ret != ERROR_OK) { LOG_ERROR("WDATA write failed"); return ret; } ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_WRITEONCE_MASK); if (ret != ERROR_OK) { LOG_ERROR("WRITECMD write failed"); return ret; } ret = efm32x_wait_status(bank, EFM32_FLASH_WRITE_TMO, EFM32_MSC_STATUS_BUSY_MASK, 0); if (ret != ERROR_OK) { LOG_ERROR("Wait for BUSY failed"); return ret; } return ERROR_OK; } static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t addr, uint32_t count) { struct target *target = bank->target; uint8_t *new_buffer = NULL; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (addr & 0x3) { LOG_ERROR("addr 0x%" PRIx32 " breaks required 4-byte " "alignment", addr); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } if (count & 0x3) { uint32_t old_count = count; count = (old_count | 3) + 1; new_buffer = malloc(count); if (!new_buffer) { LOG_ERROR("odd number of bytes to write and no memory " "for padding buffer"); return ERROR_FAIL; } LOG_INFO("odd number of bytes to write (%" PRIu32 "), extending to %" PRIu32 " " "and padding with 0xff", old_count, count); memset(new_buffer, 0xff, count); buffer = memcpy(new_buffer, buffer, old_count); } uint32_t words_remaining = count / 4; int retval, retval2; /* unlock flash registers */ efm32x_msc_lock(bank, 0); retval = efm32x_set_wren(bank, 1); if (retval != ERROR_OK) goto cleanup; /* try using a block write */ retval = efm32x_write_block(bank, buffer, addr, words_remaining); if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single word accesses */ LOG_WARNING("couldn't use block writes, falling back to single " "memory accesses"); while (words_remaining > 0) { uint32_t value; memcpy(&value, buffer, sizeof(uint32_t)); retval = efm32x_write_word(bank, addr, value); if (retval != ERROR_OK) goto reset_pg_and_lock; words_remaining--; buffer += 4; addr += 4; } } reset_pg_and_lock: retval2 = efm32x_set_wren(bank, 0); efm32x_msc_lock(bank, 1); if (retval == ERROR_OK) retval = retval2; cleanup: free(new_buffer); return retval; } static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { if (bank->base == EFM32_MSC_LOCK_BITS && offset < LOCKWORDS_SZ) { LOG_ERROR("Cannot write to lock words"); return ERROR_FAIL; } return efm32x_priv_write(bank, buffer, bank->base + offset, count); } static int efm32x_probe(struct flash_bank *bank) { struct efm32x_flash_chip *efm32x_info = bank->driver_priv; struct efm32_info *efm32_mcu_info = &(efm32x_info->info); int ret; int bank_index = efm32x_get_bank_index(bank->base); assert(bank_index >= 0); efm32x_info->probed[bank_index] = false; memset(efm32x_info->lb_page, 0xff, LOCKWORDS_SZ); ret = efm32x_read_info(bank); if (ret != ERROR_OK) return ret; LOG_INFO("detected part: %s Gecko, rev %d", efm32_mcu_info->family_data->name, efm32_mcu_info->prod_rev); LOG_INFO("flash size = %d KiB", efm32_mcu_info->flash_sz_kib); LOG_INFO("flash page size = %d B", efm32_mcu_info->page_size); assert(efm32_mcu_info->page_size != 0); free(bank->sectors); bank->sectors = NULL; if (bank->base == EFM32_FLASH_BASE) { bank->num_sectors = efm32_mcu_info->flash_sz_kib * 1024 / efm32_mcu_info->page_size; assert(bank->num_sectors > 0); ret = efm32x_read_lock_data(bank); if (ret != ERROR_OK) { LOG_ERROR("Failed to read LB data"); return ret; } } else bank->num_sectors = 1; bank->size = bank->num_sectors * efm32_mcu_info->page_size; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (uint32_t i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = i * efm32_mcu_info->page_size; bank->sectors[i].size = efm32_mcu_info->page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } efm32x_info->probed[bank_index] = true; return ERROR_OK; } static int efm32x_auto_probe(struct flash_bank *bank) { struct efm32x_flash_chip *efm32x_info = bank->driver_priv; int bank_index = efm32x_get_bank_index(bank->base); assert(bank_index >= 0); if (efm32x_info->probed[bank_index]) return ERROR_OK; return efm32x_probe(bank); } static int efm32x_protect_check(struct flash_bank *bank) { struct target *target = bank->target; int ret = 0; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } ret = efm32x_read_lock_data(bank); if (ret != ERROR_OK) { LOG_ERROR("Failed to read LB data"); return ret; } assert(bank->sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = efm32x_get_page_lock(bank, i); return ERROR_OK; } static int get_efm32x_info(struct flash_bank *bank, struct command_invocation *cmd) { struct efm32x_flash_chip *efm32x_info = bank->driver_priv; int ret; ret = efm32x_read_info(bank); if (ret != ERROR_OK) { LOG_ERROR("Failed to read EFM32 info"); return ret; } command_print_sameline(cmd, "%s Gecko, rev %d", efm32x_info->info.family_data->name, efm32x_info->info.prod_rev); return ERROR_OK; } COMMAND_HANDLER(efm32x_handle_debuglock_command) { struct target *target = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct efm32x_flash_chip *efm32x_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } uint32_t *ptr; ptr = efm32x_info->lb_page + 127; *ptr = 0; retval = efm32x_write_lock_data(bank); if (retval != ERROR_OK) { LOG_ERROR("Failed to write LB page"); return retval; } command_print(CMD, "efm32x debug interface locked, reset the device to apply"); return ERROR_OK; } static const struct command_registration efm32x_exec_command_handlers[] = { { .name = "debuglock", .handler = efm32x_handle_debuglock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Lock the debug interface of the device.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration efm32x_command_handlers[] = { { .name = "efm32", .mode = COMMAND_ANY, .help = "efm32 flash command group", .usage = "", .chain = efm32x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver efm32_flash = { .name = "efm32", .commands = efm32x_command_handlers, .flash_bank_command = efm32x_flash_bank_command, .erase = efm32x_erase, .protect = efm32x_protect, .write = efm32x_write, .read = default_flash_read, .probe = efm32x_probe, .auto_probe = efm32x_auto_probe, .erase_check = default_flash_blank_check, .protect_check = efm32x_protect_check, .info = get_efm32x_info, .free_driver_priv = efm32x_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/em357.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * Copyright (C) 2011 by Erik Botö * erik.boto@pelagicore.com ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> /* em357 register locations */ #define EM357_FLASH_ACR 0x40008000 #define EM357_FLASH_KEYR 0x40008004 #define EM357_FLASH_OPTKEYR 0x40008008 #define EM357_FLASH_SR 0x4000800C #define EM357_FLASH_CR 0x40008010 #define EM357_FLASH_AR 0x40008014 #define EM357_FLASH_OBR 0x4000801C #define EM357_FLASH_WRPR 0x40008020 #define EM357_FPEC_CLK 0x4000402c /* option byte location */ #define EM357_OB_RDP 0x08040800 #define EM357_OB_WRP0 0x08040808 #define EM357_OB_WRP1 0x0804080A #define EM357_OB_WRP2 0x0804080C /* FLASH_CR register bits */ #define FLASH_PG (1 << 0) #define FLASH_PER (1 << 1) #define FLASH_MER (1 << 2) #define FLASH_OPTPG (1 << 4) #define FLASH_OPTER (1 << 5) #define FLASH_STRT (1 << 6) #define FLASH_LOCK (1 << 7) #define FLASH_OPTWRE (1 << 9) /* FLASH_SR register bits */ #define FLASH_BSY (1 << 0) #define FLASH_PGERR (1 << 2) #define FLASH_WRPRTERR (1 << 4) #define FLASH_EOP (1 << 5) /* EM357_FLASH_OBR bit definitions (reading) */ #define OPT_ERROR 0 #define OPT_READOUT 1 /* register unlock keys */ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB struct em357_options { uint16_t RDP; uint16_t user_options; uint16_t protection[3]; }; struct em357_flash_bank { struct em357_options option_bytes; int ppage_size; bool probed; }; static int em357_mass_erase(struct flash_bank *bank); /* flash bank em357 <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(em357_flash_bank_command) { struct em357_flash_bank *em357_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; em357_info = malloc(sizeof(struct em357_flash_bank)); bank->driver_priv = em357_info; em357_info->probed = false; return ERROR_OK; } static inline int em357_get_flash_status(struct flash_bank *bank, uint32_t *status) { struct target *target = bank->target; return target_read_u32(target, EM357_FLASH_SR, status); } static int em357_wait_status_busy(struct flash_bank *bank, int timeout) { struct target *target = bank->target; uint32_t status; int retval = ERROR_OK; /* wait for busy to clear */ for (;; ) { retval = em357_get_flash_status(bank, &status); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%" PRIx32 "", status); if ((status & FLASH_BSY) == 0) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FAIL; } alive_sleep(1); } if (status & FLASH_WRPRTERR) { LOG_ERROR("em357 device protected"); retval = ERROR_FAIL; } if (status & FLASH_PGERR) { LOG_ERROR("em357 device programming failed"); retval = ERROR_FAIL; } /* Clear but report errors */ if (status & (FLASH_WRPRTERR | FLASH_PGERR)) { /* If this operation fails, we ignore it and report the original * retval */ target_write_u32(target, EM357_FLASH_SR, FLASH_WRPRTERR | FLASH_PGERR); } return retval; } static int em357_read_options(struct flash_bank *bank) { uint32_t optiondata; struct em357_flash_bank *em357_info = NULL; struct target *target = bank->target; em357_info = bank->driver_priv; /* read current option bytes */ int retval = target_read_u32(target, EM357_FLASH_OBR, &optiondata); if (retval != ERROR_OK) return retval; em357_info->option_bytes.user_options = (uint16_t)0xFFFC | ((optiondata >> 2) & 0x03); em357_info->option_bytes.RDP = (optiondata & (1 << OPT_READOUT)) ? 0xFFFF : 0x5AA5; if (optiondata & (1 << OPT_READOUT)) LOG_INFO("Device Security Bit Set"); /* each bit refers to a 4bank protection */ retval = target_read_u32(target, EM357_FLASH_WRPR, &optiondata); if (retval != ERROR_OK) return retval; em357_info->option_bytes.protection[0] = (uint16_t)optiondata; em357_info->option_bytes.protection[1] = (uint16_t)(optiondata >> 8); em357_info->option_bytes.protection[2] = (uint16_t)(optiondata >> 16); return ERROR_OK; } static int em357_erase_options(struct flash_bank *bank) { struct em357_flash_bank *em357_info = NULL; struct target *target = bank->target; em357_info = bank->driver_priv; /* read current options */ em357_read_options(bank); /* unlock flash registers */ int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; /* unlock option flash registers */ retval = target_write_u32(target, EM357_FLASH_OPTKEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_OPTKEYR, KEY2); if (retval != ERROR_OK) return retval; /* erase option bytes */ retval = target_write_u32(target, EM357_FLASH_CR, FLASH_OPTER | FLASH_OPTWRE); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_CR, FLASH_OPTER | FLASH_STRT | FLASH_OPTWRE); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 10); if (retval != ERROR_OK) return retval; /* clear readout protection and complementary option bytes * this will also force a device unlock if set */ em357_info->option_bytes.RDP = 0x5AA5; return ERROR_OK; } static int em357_write_options(struct flash_bank *bank) { struct em357_flash_bank *em357_info = NULL; struct target *target = bank->target; em357_info = bank->driver_priv; /* unlock flash registers */ int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; /* unlock option flash registers */ retval = target_write_u32(target, EM357_FLASH_OPTKEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_OPTKEYR, KEY2); if (retval != ERROR_OK) return retval; /* program option bytes */ retval = target_write_u32(target, EM357_FLASH_CR, FLASH_OPTPG | FLASH_OPTWRE); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 10); if (retval != ERROR_OK) return retval; /* write protection byte 1 */ retval = target_write_u16(target, EM357_OB_WRP0, em357_info->option_bytes.protection[0]); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 10); if (retval != ERROR_OK) return retval; /* write protection byte 2 */ retval = target_write_u16(target, EM357_OB_WRP1, em357_info->option_bytes.protection[1]); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 10); if (retval != ERROR_OK) return retval; /* write protection byte 3 */ retval = target_write_u16(target, EM357_OB_WRP2, em357_info->option_bytes.protection[2]); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 10); if (retval != ERROR_OK) return retval; /* write readout protection bit */ retval = target_write_u16(target, EM357_OB_RDP, em357_info->option_bytes.RDP); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 10); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_CR, FLASH_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int em357_protect_check(struct flash_bank *bank) { struct target *target = bank->target; struct em357_flash_bank *em357_info = bank->driver_priv; uint32_t protection; int i, s; int num_bits; int set; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* each bit refers to a 4bank protection (bit 0-23) */ int retval = target_read_u32(target, EM357_FLASH_WRPR, &protection); if (retval != ERROR_OK) return retval; /* each protection bit is for 4 * 2K pages */ num_bits = (bank->num_sectors / em357_info->ppage_size); for (i = 0; i < num_bits; i++) { set = 1; if (protection & (1 << i)) set = 0; for (s = 0; s < em357_info->ppage_size; s++) bank->sectors[(i * em357_info->ppage_size) + s].is_protected = set; } return ERROR_OK; } static int em357_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first == 0) && (last == (bank->num_sectors - 1))) return em357_mass_erase(bank); /* Enable FPEC clock */ target_write_u32(target, EM357_FPEC_CLK, 0x00000001); /* unlock flash registers */ int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; for (unsigned int i = first; i <= last; i++) { retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PER); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_AR, bank->base + bank->sectors[i].offset); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PER | FLASH_STRT); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 100); if (retval != ERROR_OK) return retval; } retval = target_write_u32(target, EM357_FLASH_CR, FLASH_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int em357_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct em357_flash_bank *em357_info = NULL; struct target *target = bank->target; uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; int reg, bit; int status; uint32_t protection; em357_info = bank->driver_priv; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first % em357_info->ppage_size) != 0) { LOG_WARNING("aligned start protect sector to a %d sector boundary", em357_info->ppage_size); first = first - (first % em357_info->ppage_size); } if (((last + 1) % em357_info->ppage_size) != 0) { LOG_WARNING("aligned end protect sector to a %d sector boundary", em357_info->ppage_size); last++; last = last - (last % em357_info->ppage_size); last--; } /* each bit refers to a 4bank protection */ int retval = target_read_u32(target, EM357_FLASH_WRPR, &protection); if (retval != ERROR_OK) return retval; prot_reg[0] = (uint16_t)protection; prot_reg[1] = (uint16_t)(protection >> 8); prot_reg[2] = (uint16_t)(protection >> 16); for (unsigned int i = first; i <= last; i++) { reg = (i / em357_info->ppage_size) / 8; bit = (i / em357_info->ppage_size) - (reg * 8); LOG_WARNING("reg, bit: %d, %d", reg, bit); if (set) prot_reg[reg] &= ~(1 << bit); else prot_reg[reg] |= (1 << bit); } status = em357_erase_options(bank); if (retval != ERROR_OK) return status; em357_info->option_bytes.protection[0] = prot_reg[0]; em357_info->option_bytes.protection[1] = prot_reg[1]; em357_info->option_bytes.protection[2] = prot_reg[2]; return em357_write_options(bank); } static int em357_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* see contrib/loaders/flash/stm32x.s for src, the same is used here except for * a modified *_FLASH_BASE */ static const uint8_t em357_flash_write_code[] = { /* #define EM357_FLASH_CR_OFFSET 0x10 * #define EM357_FLASH_SR_OFFSET 0x0C * write: */ 0x08, 0x4c, /* ldr r4, EM357_FLASH_BASE */ 0x1c, 0x44, /* add r4, r3 */ /* write_half_word: */ 0x01, 0x23, /* movs r3, #0x01 */ 0x23, 0x61, /* str r3, [r4, *#EM357_FLASH_CR_OFFSET] */ 0x30, 0xf8, 0x02, 0x3b, /* ldrh r3, [r0], #0x02 */ 0x21, 0xf8, 0x02, 0x3b, /* strh r3, [r1], #0x02 */ /* busy: */ 0xe3, 0x68, /* ldr r3, [r4, *#EM357_FLASH_SR_OFFSET] */ 0x13, 0xf0, 0x01, 0x0f, /* tst r3, #0x01 */ 0xfb, 0xd0, /* beq busy */ 0x13, 0xf0, 0x14, 0x0f, /* tst r3, #0x14 */ 0x01, 0xd1, /* bne exit */ 0x01, 0x3a, /* subs r2, r2, #0x01 */ 0xf0, 0xd1, /* bne write_half_word */ /* exit: */ 0x00, 0xbe, /* bkpt #0x00 */ 0x00, 0x80, 0x00, 0x40, /* EM357_FLASH_BASE: .word 0x40008000 */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(em357_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(em357_flash_write_code), em357_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING( "no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT); while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count; retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); buf_set_u32(reg_params[3].value, 0, 32, 0); retval = target_run_algorithm(target, 0, NULL, 4, reg_params, write_algorithm->address, 0, 10000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("error executing em357 flash write algorithm"); break; } if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_PGERR) { LOG_ERROR("flash memory not erased before writing"); /* Clear but report errors */ target_write_u32(target, EM357_FLASH_SR, FLASH_PGERR); retval = ERROR_FAIL; break; } if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_WRPRTERR) { LOG_ERROR("flash memory write protected"); /* Clear but report errors */ target_write_u32(target, EM357_FLASH_SR, FLASH_WRPRTERR); retval = ERROR_FAIL; break; } buffer += thisrun_count * 2; address += thisrun_count * 2; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; } static int em357_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t words_remaining = (count / 2); uint32_t bytes_remaining = (count & 0x00000001); uint32_t address = bank->base + offset; uint32_t bytes_written = 0; int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x1) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* unlock flash registers */ retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; target_write_u32(target, EM357_FPEC_CLK, 0x00000001); /* multiple half words (2-byte) to be programmed? */ if (words_remaining > 0) { /* try using a block write */ retval = em357_write_block(bank, buffer, offset, words_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single dword accesses */ LOG_WARNING( "couldn't use block writes, falling back to single memory accesses"); } } else { buffer += words_remaining * 2; address += words_remaining * 2; words_remaining = 0; } } if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)) return retval; while (words_remaining > 0) { uint16_t value; memcpy(&value, buffer + bytes_written, sizeof(uint16_t)); retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PG); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, address, value); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 5); if (retval != ERROR_OK) return retval; bytes_written += 2; words_remaining--; address += 2; } if (bytes_remaining) { uint16_t value = 0xffff; memcpy(&value, buffer + bytes_written, bytes_remaining); retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PG); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, address, value); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 5); if (retval != ERROR_OK) return retval; } return target_write_u32(target, EM357_FLASH_CR, FLASH_LOCK); } static int em357_probe(struct flash_bank *bank) { struct target *target = bank->target; struct em357_flash_bank *em357_info = bank->driver_priv; int i; uint16_t num_pages; int page_size; uint32_t base_address = 0x08000000; em357_info->probed = false; switch (bank->size) { case 0x10000: /* 64k -- 64 1k pages */ num_pages = 64; page_size = 1024; break; case 0x20000: /* 128k -- 128 1k pages */ num_pages = 128; page_size = 1024; break; case 0x30000: /* 192k -- 96 2k pages */ num_pages = 96; page_size = 2048; break; case 0x40000: /* 256k -- 128 2k pages */ num_pages = 128; page_size = 2048; break; case 0x80000: /* 512k -- 256 2k pages */ num_pages = 256; page_size = 2048; break; default: LOG_WARNING("No size specified for em357 flash driver, assuming 192k!"); num_pages = 96; page_size = 2048; break; } /* Enable FPEC CLK */ int retval = target_write_u32(target, EM357_FPEC_CLK, 0x00000001); if (retval != ERROR_OK) return retval; em357_info->ppage_size = 4; LOG_INFO("flash size = %d KiB", num_pages*page_size/1024); free(bank->sectors); bank->base = base_address; bank->size = (num_pages * page_size); bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); for (i = 0; i < num_pages; i++) { bank->sectors[i].offset = i * page_size; bank->sectors[i].size = page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } em357_info->probed = true; return ERROR_OK; } static int em357_auto_probe(struct flash_bank *bank) { struct em357_flash_bank *em357_info = bank->driver_priv; if (em357_info->probed) return ERROR_OK; return em357_probe(bank); } COMMAND_HANDLER(em357_handle_lock_command) { struct target *target = NULL; struct em357_flash_bank *em357_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; em357_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (em357_erase_options(bank) != ERROR_OK) { command_print(CMD, "em357 failed to erase options"); return ERROR_OK; } /* set readout protection */ em357_info->option_bytes.RDP = 0; if (em357_write_options(bank) != ERROR_OK) { command_print(CMD, "em357 failed to lock device"); return ERROR_OK; } command_print(CMD, "em357 locked"); return ERROR_OK; } COMMAND_HANDLER(em357_handle_unlock_command) { struct target *target = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (em357_erase_options(bank) != ERROR_OK) { command_print(CMD, "em357 failed to unlock device"); return ERROR_OK; } if (em357_write_options(bank) != ERROR_OK) { command_print(CMD, "em357 failed to lock device"); return ERROR_OK; } command_print(CMD, "em357 unlocked.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect."); return ERROR_OK; } static int em357_mass_erase(struct flash_bank *bank) { struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Make sure the flash clock is on */ target_write_u32(target, EM357_FPEC_CLK, 0x00000001); /* unlock option flash registers */ int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; /* mass erase flash memory */ retval = target_write_u32(target, EM357_FLASH_CR, FLASH_MER); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_CR, FLASH_MER | FLASH_STRT); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 100); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_CR, FLASH_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } COMMAND_HANDLER(em357_handle_mass_erase_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = em357_mass_erase(bank); if (retval == ERROR_OK) command_print(CMD, "em357 mass erase complete"); else command_print(CMD, "em357 mass erase failed"); return retval; } static const struct command_registration em357_exec_command_handlers[] = { { .name = "lock", .usage = "<bank>", .handler = em357_handle_lock_command, .mode = COMMAND_EXEC, .help = "Lock entire flash device.", }, { .name = "unlock", .usage = "<bank>", .handler = em357_handle_unlock_command, .mode = COMMAND_EXEC, .help = "Unlock entire protected flash device.", }, { .name = "mass_erase", .usage = "<bank>", .handler = em357_handle_mass_erase_command, .mode = COMMAND_EXEC, .help = "Erase entire flash device.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration em357_command_handlers[] = { { .name = "em357", .mode = COMMAND_ANY, .help = "em357 flash command group", .usage = "", .chain = em357_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver em357_flash = { .name = "em357", .commands = em357_command_handlers, .flash_bank_command = em357_flash_bank_command, .erase = em357_erase, .protect = em357_protect, .write = em357_write, .read = default_flash_read, .probe = em357_probe, .auto_probe = em357_auto_probe, .erase_check = default_flash_blank_check, .protect_check = em357_protect_check, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/esirisc_flash.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * * James Zhao <hjz@squareup.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <flash/common.h> #include <flash/nor/imp.h> #include <helper/command.h> #include <helper/log.h> #include <helper/time_support.h> #include <helper/types.h> #include <target/esirisc.h> #include <target/target.h> /* eSi-TSMC Flash Registers */ #define CONTROL 0x00 /* Control Register */ #define TIMING0 0x04 /* Timing Register 0 */ #define TIMING1 0x08 /* Timing Register 1 */ #define TIMING2 0x0c /* Timing Register 2 */ #define UNLOCK1 0x18 /* Unlock 1 */ #define UNLOCK2 0x1c /* Unlock 2 */ #define ADDRESS 0x20 /* Erase/Program Address */ #define PB_DATA 0x24 /* Program Buffer Data */ #define PB_INDEX 0x28 /* Program Buffer Index */ #define STATUS 0x2c /* Status Register */ #define REDUN_0 0x30 /* Redundant Address 0 */ #define REDUN_1 0x34 /* Redundant Address 1 */ /* Control Fields */ #define CONTROL_SLM (1<<0) /* Sleep Mode */ #define CONTROL_WP (1<<1) /* Register Write Protect */ #define CONTROL_E (1<<3) /* Erase */ #define CONTROL_EP (1<<4) /* Erase Page */ #define CONTROL_P (1<<5) /* Program Flash */ #define CONTROL_ERC (1<<6) /* Erase Reference Cell */ #define CONTROL_R (1<<7) /* Recall Trim Code */ #define CONTROL_AP (1<<8) /* Auto-Program */ /* Timing Fields */ #define TIMING0_R(x) (((x) << 0) & 0x3f) /* Read Wait States */ #define TIMING0_F(x) (((x) << 16) & 0xffff0000) /* Tnvh Clock Cycles */ #define TIMING1_E(x) (((x) << 0) & 0xffffff) /* Tme/Terase/Tre Clock Cycles */ #define TIMING2_P(x) (((x) << 0) & 0xffff) /* Tprog Clock Cycles */ #define TIMING2_H(x) (((x) << 16) & 0xff0000) /* Clock Cycles in 100ns */ #define TIMING2_T(x) (((x) << 24) & 0xf000000) /* Clock Cycles in 10ns */ /* Status Fields */ #define STATUS_BUSY (1<<0) /* Busy (Erase/Program) */ #define STATUS_WER (1<<1) /* Write Protect Error */ #define STATUS_DR (1<<2) /* Disable Redundancy */ #define STATUS_DIS (1<<3) /* Discharged */ #define STATUS_BO (1<<4) /* Brown Out */ /* Redundant Address Fields */ #define REDUN_R (1<<0) /* Used */ #define REDUN_P(x) (((x) << 12) & 0x7f000) /* Redundant Page Address */ /* * The eSi-TSMC Flash manual provides two sets of timings based on the * underlying flash process. By default, 90nm is assumed. */ #if 0 /* 55nm */ #define TNVH 5000 /* 5us */ #define TME 80000000 /* 80ms */ #define TERASE 160000000 /* 160ms */ #define TRE 100000000 /* 100ms */ #define TPROG 8000 /* 8us */ #else /* 90nm */ #define TNVH 5000 /* 5us */ #define TME 20000000 /* 20ms */ #define TERASE 40000000 /* 40ms */ #define TRE 40000000 /* 40ms */ #define TPROG 40000 /* 40us */ #endif #define CONTROL_TIMEOUT 5000 /* 5s */ #define FLASH_PAGE_SIZE 4096 #define PB_MAX 32 #define NUM_NS_PER_S 1000000000ULL struct esirisc_flash_bank { bool probed; uint32_t cfg; uint32_t clock; uint32_t wait_states; }; static const struct command_registration esirisc_flash_command_handlers[]; FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command) { struct esirisc_flash_bank *esirisc_info; if (CMD_ARGC < 9) return ERROR_COMMAND_SYNTAX_ERROR; esirisc_info = calloc(1, sizeof(struct esirisc_flash_bank)); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], esirisc_info->cfg); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], esirisc_info->clock); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[8], esirisc_info->wait_states); bank->driver_priv = esirisc_info; /* register commands using existing esirisc context */ register_commands(CMD_CTX, "esirisc", esirisc_flash_command_handlers); return ERROR_OK; } /* * Register writes are ignored if the control.WP flag is set; the * following sequence is required to modify this flag even when * protection is disabled. */ static int esirisc_flash_unlock(struct flash_bank *bank) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; struct target *target = bank->target; target_write_u32(target, esirisc_info->cfg + UNLOCK1, 0x7123); target_write_u32(target, esirisc_info->cfg + UNLOCK2, 0x812a); target_write_u32(target, esirisc_info->cfg + UNLOCK1, 0xbee1); return ERROR_OK; } static int esirisc_flash_disable_protect(struct flash_bank *bank) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; struct target *target = bank->target; uint32_t control; target_read_u32(target, esirisc_info->cfg + CONTROL, &control); if (!(control & CONTROL_WP)) return ERROR_OK; (void)esirisc_flash_unlock(bank); control &= ~CONTROL_WP; target_write_u32(target, esirisc_info->cfg + CONTROL, control); return ERROR_OK; } static int esirisc_flash_enable_protect(struct flash_bank *bank) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; struct target *target = bank->target; uint32_t control; target_read_u32(target, esirisc_info->cfg + CONTROL, &control); if (control & CONTROL_WP) return ERROR_OK; (void)esirisc_flash_unlock(bank); control |= CONTROL_WP; target_write_u32(target, esirisc_info->cfg + CONTROL, control); return ERROR_OK; } static int esirisc_flash_check_status(struct flash_bank *bank) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; struct target *target = bank->target; uint32_t status; target_read_u32(target, esirisc_info->cfg + STATUS, &status); if (status & STATUS_WER) { LOG_ERROR("%s: bad status: 0x%" PRIx32, bank->name, status); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int esirisc_flash_clear_status(struct flash_bank *bank) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; struct target *target = bank->target; target_write_u32(target, esirisc_info->cfg + STATUS, STATUS_WER); return ERROR_OK; } static int esirisc_flash_wait(struct flash_bank *bank, int ms) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; struct target *target = bank->target; uint32_t status; int64_t t; t = timeval_ms(); for (;;) { target_read_u32(target, esirisc_info->cfg + STATUS, &status); if (!(status & STATUS_BUSY)) return ERROR_OK; if ((timeval_ms() - t) > ms) return ERROR_TARGET_TIMEOUT; keep_alive(); } } static int esirisc_flash_control(struct flash_bank *bank, uint32_t control) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; struct target *target = bank->target; esirisc_flash_clear_status(bank); target_write_u32(target, esirisc_info->cfg + CONTROL, control); int retval = esirisc_flash_wait(bank, CONTROL_TIMEOUT); if (retval != ERROR_OK) { LOG_ERROR("%s: control timed out: 0x%" PRIx32, bank->name, control); return retval; } return esirisc_flash_check_status(bank); } static int esirisc_flash_recall(struct flash_bank *bank) { return esirisc_flash_control(bank, CONTROL_R); } static int esirisc_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; struct target *target = bank->target; int retval = ERROR_OK; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; (void)esirisc_flash_disable_protect(bank); for (unsigned int page = first; page < last; ++page) { uint32_t address = page * FLASH_PAGE_SIZE; target_write_u32(target, esirisc_info->cfg + ADDRESS, address); retval = esirisc_flash_control(bank, CONTROL_EP); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to erase address: 0x%" PRIx32, bank->name, address); break; } } (void)esirisc_flash_enable_protect(bank); return retval; } static int esirisc_flash_mass_erase(struct flash_bank *bank) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; struct target *target = bank->target; int retval; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; (void)esirisc_flash_disable_protect(bank); target_write_u32(target, esirisc_info->cfg + ADDRESS, 0); retval = esirisc_flash_control(bank, CONTROL_E); if (retval != ERROR_OK) LOG_ERROR("%s: failed to mass erase", bank->name); (void)esirisc_flash_enable_protect(bank); return retval; } /* * Per TSMC, the reference cell should be erased once per sample. This * is typically done during wafer sort, however we include support for * those that may need to calibrate flash at a later time. */ static int esirisc_flash_ref_erase(struct flash_bank *bank) { struct target *target = bank->target; int retval; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; (void)esirisc_flash_disable_protect(bank); retval = esirisc_flash_control(bank, CONTROL_ERC); if (retval != ERROR_OK) LOG_ERROR("%s: failed to erase reference cell", bank->name); (void)esirisc_flash_enable_protect(bank); return retval; } static int esirisc_flash_fill_pb(struct flash_bank *bank, const uint8_t *buffer, uint32_t count) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; struct target *target = bank->target; struct esirisc_common *esirisc = target_to_esirisc(target); /* * The pb_index register is auto-incremented when pb_data is written * and should be cleared before each operation. */ target_write_u32(target, esirisc_info->cfg + PB_INDEX, 0); /* * The width of the pb_data register depends on the underlying * target; writing one byte at a time incurs a significant * performance penalty and should be avoided. */ while (count > 0) { uint32_t max_bytes = DIV_ROUND_UP(esirisc->num_bits, 8); uint32_t num_bytes = MIN(count, max_bytes); target_write_buffer(target, esirisc_info->cfg + PB_DATA, num_bytes, buffer); buffer += num_bytes; count -= num_bytes; } return ERROR_OK; } static int esirisc_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; struct target *target = bank->target; int retval = ERROR_OK; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; (void)esirisc_flash_disable_protect(bank); /* * The address register is auto-incremented based on the contents of * the pb_index register after each operation completes. It can be * set once provided pb_index is cleared before each operation. */ target_write_u32(target, esirisc_info->cfg + ADDRESS, offset); /* * Care must be taken when filling the program buffer; a maximum of * 32 bytes may be written at a time and may not cross a 32-byte * boundary based on the current offset. */ while (count > 0) { uint32_t max_bytes = PB_MAX - (offset & 0x1f); uint32_t num_bytes = MIN(count, max_bytes); esirisc_flash_fill_pb(bank, buffer, num_bytes); retval = esirisc_flash_control(bank, CONTROL_P); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to program address: 0x%" PRIx32, bank->name, offset); break; } buffer += num_bytes; offset += num_bytes; count -= num_bytes; } (void)esirisc_flash_enable_protect(bank); return retval; } static uint32_t esirisc_flash_num_cycles(struct flash_bank *bank, uint64_t ns) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; /* apply scaling factor to avoid truncation */ uint64_t hz = (uint64_t)esirisc_info->clock * 1000; uint64_t num_cycles = ((hz / NUM_NS_PER_S) * ns) / 1000; if (hz % NUM_NS_PER_S > 0) num_cycles++; return num_cycles; } static int esirisc_flash_init(struct flash_bank *bank) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; struct target *target = bank->target; uint32_t value; int retval; (void)esirisc_flash_disable_protect(bank); /* initialize timing registers */ value = TIMING0_F(esirisc_flash_num_cycles(bank, TNVH)) | TIMING0_R(esirisc_info->wait_states); LOG_DEBUG("TIMING0: 0x%" PRIx32, value); target_write_u32(target, esirisc_info->cfg + TIMING0, value); value = TIMING1_E(esirisc_flash_num_cycles(bank, TERASE)); LOG_DEBUG("TIMING1: 0x%" PRIx32, value); target_write_u32(target, esirisc_info->cfg + TIMING1, value); value = TIMING2_T(esirisc_flash_num_cycles(bank, 10)) | TIMING2_H(esirisc_flash_num_cycles(bank, 100)) | TIMING2_P(esirisc_flash_num_cycles(bank, TPROG)); LOG_DEBUG("TIMING2: 0x%" PRIx32, value); target_write_u32(target, esirisc_info->cfg + TIMING2, value); /* recall trim code */ retval = esirisc_flash_recall(bank); if (retval != ERROR_OK) LOG_ERROR("%s: failed to recall trim code", bank->name); (void)esirisc_flash_enable_protect(bank); return retval; } static int esirisc_flash_probe(struct flash_bank *bank) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; struct target *target = bank->target; int retval; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; bank->num_sectors = bank->size / FLASH_PAGE_SIZE; bank->sectors = alloc_block_array(0, FLASH_PAGE_SIZE, bank->num_sectors); retval = esirisc_flash_init(bank); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to initialize bank", bank->name); return retval; } esirisc_info->probed = true; return ERROR_OK; } static int esirisc_flash_auto_probe(struct flash_bank *bank) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; if (esirisc_info->probed) return ERROR_OK; return esirisc_flash_probe(bank); } static int esirisc_flash_info(struct flash_bank *bank, struct command_invocation *cmd) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; command_print_sameline(cmd, "%4s cfg at 0x%" PRIx32 ", clock %" PRIu32 ", wait_states %" PRIu32, "", /* align with first line */ esirisc_info->cfg, esirisc_info->clock, esirisc_info->wait_states); return ERROR_OK; } COMMAND_HANDLER(handle_esirisc_flash_mass_erase_command) { struct flash_bank *bank; int retval; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = esirisc_flash_mass_erase(bank); command_print(CMD, "mass erase %s", (retval == ERROR_OK) ? "successful" : "failed"); return retval; } COMMAND_HANDLER(handle_esirisc_flash_ref_erase_command) { struct flash_bank *bank; int retval; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = esirisc_flash_ref_erase(bank); command_print(CMD, "erase reference cell %s", (retval == ERROR_OK) ? "successful" : "failed"); return retval; } static const struct command_registration esirisc_flash_exec_command_handlers[] = { { .name = "mass_erase", .handler = handle_esirisc_flash_mass_erase_command, .mode = COMMAND_EXEC, .help = "erase all pages in data memory", .usage = "bank_id", }, { .name = "ref_erase", .handler = handle_esirisc_flash_ref_erase_command, .mode = COMMAND_EXEC, .help = "erase reference cell (uncommon)", .usage = "bank_id", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration esirisc_flash_command_handlers[] = { { .name = "flash", .mode = COMMAND_EXEC, .help = "eSi-TSMC Flash command group", .usage = "", .chain = esirisc_flash_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver esirisc_flash = { .name = "esirisc", .usage = "flash bank bank_id 'esirisc' base_address size_bytes 0 0 target " "cfg_address clock_hz wait_states", .flash_bank_command = esirisc_flash_bank_command, .erase = esirisc_flash_erase, .write = esirisc_flash_write, .read = default_flash_read, .probe = esirisc_flash_probe, .auto_probe = esirisc_flash_auto_probe, .erase_check = default_flash_blank_check, .info = esirisc_flash_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/faux.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <target/image.h> #include "hello.h" struct faux_flash_bank { struct target *target; uint8_t *memory; uint32_t start_address; }; static const int sector_size = 0x10000; /* flash bank faux <base> <size> <chip_width> <bus_width> <target#> <driverPath> */ FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command) { struct faux_flash_bank *info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; info = malloc(sizeof(struct faux_flash_bank)); if (!info) { LOG_ERROR("no memory for flash bank info"); return ERROR_FAIL; } info->memory = malloc(bank->size); if (!info->memory) { free(info); LOG_ERROR("no memory for flash bank info"); return ERROR_FAIL; } bank->driver_priv = info; /* Use 0x10000 as a fixed sector size. */ uint32_t offset = 0; bank->num_sectors = bank->size/sector_size; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = sector_size; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } info->target = get_target(CMD_ARGV[5]); if (!info->target) { LOG_ERROR("target '%s' not defined", CMD_ARGV[5]); free(info->memory); free(info); return ERROR_FAIL; } return ERROR_OK; } static int faux_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct faux_flash_bank *info = bank->driver_priv; memset(info->memory + first*sector_size, 0xff, sector_size*(last-first + 1)); return ERROR_OK; } static int faux_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct faux_flash_bank *info = bank->driver_priv; memcpy(info->memory + offset, buffer, count); return ERROR_OK; } static int faux_info(struct flash_bank *bank, struct command_invocation *cmd) { command_print_sameline(cmd, "faux flash driver"); return ERROR_OK; } static int faux_probe(struct flash_bank *bank) { return ERROR_OK; } static const struct command_registration faux_command_handlers[] = { { .name = "faux", .mode = COMMAND_ANY, .help = "faux flash command group", .chain = hello_command_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; const struct flash_driver faux_flash = { .name = "faux", .commands = faux_command_handlers, .flash_bank_command = faux_flash_bank_command, .erase = faux_erase, .write = faux_write, .read = default_flash_read, .probe = faux_probe, .auto_probe = faux_probe, .erase_check = default_flash_blank_check, .info = faux_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/fespi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> * * Modified by Megan Wachs <megan@sifive.com> from the original stmsmi.c * ***************************************************************************/ /* The Freedom E SPI controller is a SPI bus controller * specifically designed for SPI Flash Memories on Freedom E platforms. * * Two working modes are available: * - SW mode: the SPI is controlled by SW. Any custom commands can be sent * on the bus. Writes are only possible in this mode. * - HW mode: Memory content is directly * accessible in CPU memory space. CPU can read and execute memory content. */ /* ATTENTION: * To have flash memory mapped in CPU memory space, the controller * must have "HW mode" enabled. * 1) The command "reset init" has to initialize the controller and put * it in HW mode (this is actually the default out of reset for Freedom E systems). * 2) every command in this file have to return to prompt in HW mode. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "spi.h" #include <jtag/jtag.h> #include <helper/time_support.h> #include <target/algorithm.h> #include "target/riscv/riscv.h" /* Register offsets */ #define FESPI_REG_SCKDIV 0x00 #define FESPI_REG_SCKMODE 0x04 #define FESPI_REG_CSID 0x10 #define FESPI_REG_CSDEF 0x14 #define FESPI_REG_CSMODE 0x18 #define FESPI_REG_DCSSCK 0x28 #define FESPI_REG_DSCKCS 0x2a #define FESPI_REG_DINTERCS 0x2c #define FESPI_REG_DINTERXFR 0x2e #define FESPI_REG_FMT 0x40 #define FESPI_REG_TXFIFO 0x48 #define FESPI_REG_RXFIFO 0x4c #define FESPI_REG_TXCTRL 0x50 #define FESPI_REG_RXCTRL 0x54 #define FESPI_REG_FCTRL 0x60 #define FESPI_REG_FFMT 0x64 #define FESPI_REG_IE 0x70 #define FESPI_REG_IP 0x74 /* Fields */ #define FESPI_SCK_POL 0x1 #define FESPI_SCK_PHA 0x2 #define FESPI_FMT_PROTO(x) ((x) & 0x3) #define FESPI_FMT_ENDIAN(x) (((x) & 0x1) << 2) #define FESPI_FMT_DIR(x) (((x) & 0x1) << 3) #define FESPI_FMT_LEN(x) (((x) & 0xf) << 16) /* TXCTRL register */ #define FESPI_TXWM(x) ((x) & 0xffff) /* RXCTRL register */ #define FESPI_RXWM(x) ((x) & 0xffff) #define FESPI_IP_TXWM 0x1 #define FESPI_IP_RXWM 0x2 #define FESPI_FCTRL_EN 0x1 #define FESPI_INSN_CMD_EN 0x1 #define FESPI_INSN_ADDR_LEN(x) (((x) & 0x7) << 1) #define FESPI_INSN_PAD_CNT(x) (((x) & 0xf) << 4) #define FESPI_INSN_CMD_PROTO(x) (((x) & 0x3) << 8) #define FESPI_INSN_ADDR_PROTO(x) (((x) & 0x3) << 10) #define FESPI_INSN_DATA_PROTO(x) (((x) & 0x3) << 12) #define FESPI_INSN_CMD_CODE(x) (((x) & 0xff) << 16) #define FESPI_INSN_PAD_CODE(x) (((x) & 0xff) << 24) /* Values */ #define FESPI_CSMODE_AUTO 0 #define FESPI_CSMODE_HOLD 2 #define FESPI_CSMODE_OFF 3 #define FESPI_DIR_RX 0 #define FESPI_DIR_TX 1 #define FESPI_PROTO_S 0 #define FESPI_PROTO_D 1 #define FESPI_PROTO_Q 2 #define FESPI_ENDIAN_MSB 0 #define FESPI_ENDIAN_LSB 1 /* Timeout in ms */ #define FESPI_CMD_TIMEOUT (100) #define FESPI_PROBE_TIMEOUT (100) #define FESPI_MAX_TIMEOUT (3000) struct fespi_flash_bank { bool probed; target_addr_t ctrl_base; const struct flash_device *dev; }; struct fespi_target { char *name; uint32_t tap_idcode; uint32_t ctrl_base; }; /* TODO !!! What is the right naming convention here? */ static const struct fespi_target target_devices[] = { /* name, tap_idcode, ctrl_base */ { "Freedom E310-G000 SPI Flash", 0x10e31913, 0x10014000 }, { "Freedom E310-G002 SPI Flash", 0x20000913, 0x10014000 }, { NULL, 0, 0 } }; FLASH_BANK_COMMAND_HANDLER(fespi_flash_bank_command) { struct fespi_flash_bank *fespi_info; LOG_DEBUG("%s", __func__); if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; fespi_info = malloc(sizeof(struct fespi_flash_bank)); if (!fespi_info) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } bank->driver_priv = fespi_info; fespi_info->probed = false; fespi_info->ctrl_base = 0; if (CMD_ARGC >= 7) { COMMAND_PARSE_ADDRESS(CMD_ARGV[6], fespi_info->ctrl_base); LOG_DEBUG("ASSUMING FESPI device at ctrl_base = " TARGET_ADDR_FMT, fespi_info->ctrl_base); } return ERROR_OK; } static int fespi_read_reg(struct flash_bank *bank, uint32_t *value, target_addr_t address) { struct target *target = bank->target; struct fespi_flash_bank *fespi_info = bank->driver_priv; int result = target_read_u32(target, fespi_info->ctrl_base + address, value); if (result != ERROR_OK) { LOG_ERROR("fespi_read_reg() error at " TARGET_ADDR_FMT, fespi_info->ctrl_base + address); return result; } return ERROR_OK; } static int fespi_write_reg(struct flash_bank *bank, target_addr_t address, uint32_t value) { struct target *target = bank->target; struct fespi_flash_bank *fespi_info = bank->driver_priv; int result = target_write_u32(target, fespi_info->ctrl_base + address, value); if (result != ERROR_OK) { LOG_ERROR("fespi_write_reg() error writing 0x%" PRIx32 " to " TARGET_ADDR_FMT, value, fespi_info->ctrl_base + address); return result; } return ERROR_OK; } static int fespi_disable_hw_mode(struct flash_bank *bank) { uint32_t fctrl; if (fespi_read_reg(bank, &fctrl, FESPI_REG_FCTRL) != ERROR_OK) return ERROR_FAIL; return fespi_write_reg(bank, FESPI_REG_FCTRL, fctrl & ~FESPI_FCTRL_EN); } static int fespi_enable_hw_mode(struct flash_bank *bank) { uint32_t fctrl; if (fespi_read_reg(bank, &fctrl, FESPI_REG_FCTRL) != ERROR_OK) return ERROR_FAIL; return fespi_write_reg(bank, FESPI_REG_FCTRL, fctrl | FESPI_FCTRL_EN); } static int fespi_set_dir(struct flash_bank *bank, bool dir) { uint32_t fmt; if (fespi_read_reg(bank, &fmt, FESPI_REG_FMT) != ERROR_OK) return ERROR_FAIL; return fespi_write_reg(bank, FESPI_REG_FMT, (fmt & ~(FESPI_FMT_DIR(0xFFFFFFFF))) | FESPI_FMT_DIR(dir)); } static int fespi_txwm_wait(struct flash_bank *bank) { int64_t start = timeval_ms(); while (1) { uint32_t ip; if (fespi_read_reg(bank, &ip, FESPI_REG_IP) != ERROR_OK) return ERROR_FAIL; if (ip & FESPI_IP_TXWM) break; int64_t now = timeval_ms(); if (now - start > 1000) { LOG_ERROR("ip.txwm didn't get set."); return ERROR_TARGET_TIMEOUT; } } return ERROR_OK; } static int fespi_tx(struct flash_bank *bank, uint8_t in) { int64_t start = timeval_ms(); while (1) { uint32_t txfifo; if (fespi_read_reg(bank, &txfifo, FESPI_REG_TXFIFO) != ERROR_OK) return ERROR_FAIL; if (!(txfifo >> 31)) break; int64_t now = timeval_ms(); if (now - start > 1000) { LOG_ERROR("txfifo stayed negative."); return ERROR_TARGET_TIMEOUT; } } return fespi_write_reg(bank, FESPI_REG_TXFIFO, in); } static int fespi_rx(struct flash_bank *bank, uint8_t *out) { int64_t start = timeval_ms(); uint32_t value; while (1) { if (fespi_read_reg(bank, &value, FESPI_REG_RXFIFO) != ERROR_OK) return ERROR_FAIL; if (!(value >> 31)) break; int64_t now = timeval_ms(); if (now - start > 1000) { LOG_ERROR("rxfifo didn't go positive (value=0x%" PRIx32 ").", value); return ERROR_TARGET_TIMEOUT; } } if (out) *out = value & 0xff; return ERROR_OK; } /* TODO!!! Why don't we need to call this after writing? */ static int fespi_wip(struct flash_bank *bank, int timeout) { int64_t endtime; fespi_set_dir(bank, FESPI_DIR_RX); if (fespi_write_reg(bank, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD) != ERROR_OK) return ERROR_FAIL; endtime = timeval_ms() + timeout; fespi_tx(bank, SPIFLASH_READ_STATUS); if (fespi_rx(bank, NULL) != ERROR_OK) return ERROR_FAIL; do { alive_sleep(1); fespi_tx(bank, 0); uint8_t rx; if (fespi_rx(bank, &rx) != ERROR_OK) return ERROR_FAIL; if ((rx & SPIFLASH_BSY_BIT) == 0) { if (fespi_write_reg(bank, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO) != ERROR_OK) return ERROR_FAIL; fespi_set_dir(bank, FESPI_DIR_TX); return ERROR_OK; } } while (timeval_ms() < endtime); LOG_ERROR("timeout"); return ERROR_FAIL; } static int fespi_erase_sector(struct flash_bank *bank, int sector) { struct fespi_flash_bank *fespi_info = bank->driver_priv; int retval; retval = fespi_tx(bank, SPIFLASH_WRITE_ENABLE); if (retval != ERROR_OK) return retval; retval = fespi_txwm_wait(bank); if (retval != ERROR_OK) return retval; if (fespi_write_reg(bank, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD) != ERROR_OK) return ERROR_FAIL; retval = fespi_tx(bank, fespi_info->dev->erase_cmd); if (retval != ERROR_OK) return retval; sector = bank->sectors[sector].offset; if (bank->size > 0x1000000) { retval = fespi_tx(bank, sector >> 24); if (retval != ERROR_OK) return retval; } retval = fespi_tx(bank, sector >> 16); if (retval != ERROR_OK) return retval; retval = fespi_tx(bank, sector >> 8); if (retval != ERROR_OK) return retval; retval = fespi_tx(bank, sector); if (retval != ERROR_OK) return retval; retval = fespi_txwm_wait(bank); if (retval != ERROR_OK) return retval; if (fespi_write_reg(bank, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO) != ERROR_OK) return ERROR_FAIL; retval = fespi_wip(bank, FESPI_MAX_TIMEOUT); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int fespi_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct fespi_flash_bank *fespi_info = bank->driver_priv; int retval = ERROR_OK; LOG_DEBUG("%s: from sector %u to sector %u", __func__, first, last); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((last < first) || (last >= bank->num_sectors)) { LOG_ERROR("Flash sector invalid"); return ERROR_FLASH_SECTOR_INVALID; } if (!(fespi_info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } for (unsigned int sector = first; sector <= last; sector++) { if (bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FAIL; } } if (fespi_info->dev->erase_cmd == 0x00) return ERROR_FLASH_OPER_UNSUPPORTED; if (fespi_write_reg(bank, FESPI_REG_TXCTRL, FESPI_TXWM(1)) != ERROR_OK) return ERROR_FAIL; retval = fespi_txwm_wait(bank); if (retval != ERROR_OK) { LOG_ERROR("WM Didn't go high before attempting."); return retval; } /* Disable Hardware accesses*/ if (fespi_disable_hw_mode(bank) != ERROR_OK) return ERROR_FAIL; /* poll WIP */ retval = fespi_wip(bank, FESPI_PROBE_TIMEOUT); if (retval != ERROR_OK) goto done; for (unsigned int sector = first; sector <= last; sector++) { retval = fespi_erase_sector(bank, sector); if (retval != ERROR_OK) goto done; keep_alive(); } /* Switch to HW mode before return to prompt */ done: if (fespi_enable_hw_mode(bank) != ERROR_OK) return ERROR_FAIL; return retval; } static int fespi_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { for (unsigned int sector = first; sector <= last; sector++) bank->sectors[sector].is_protected = set; return ERROR_OK; } static int slow_fespi_write_buffer(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t len) { struct fespi_flash_bank *fespi_info = bank->driver_priv; uint32_t ii; /* TODO!!! assert that len < page size */ if (fespi_tx(bank, SPIFLASH_WRITE_ENABLE) != ERROR_OK) return ERROR_FAIL; if (fespi_txwm_wait(bank) != ERROR_OK) return ERROR_FAIL; if (fespi_write_reg(bank, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD) != ERROR_OK) return ERROR_FAIL; if (fespi_tx(bank, fespi_info->dev->pprog_cmd) != ERROR_OK) return ERROR_FAIL; if (bank->size > 0x1000000 && fespi_tx(bank, offset >> 24) != ERROR_OK) return ERROR_FAIL; if (fespi_tx(bank, offset >> 16) != ERROR_OK) return ERROR_FAIL; if (fespi_tx(bank, offset >> 8) != ERROR_OK) return ERROR_FAIL; if (fespi_tx(bank, offset) != ERROR_OK) return ERROR_FAIL; for (ii = 0; ii < len; ii++) { if (fespi_tx(bank, buffer[ii]) != ERROR_OK) return ERROR_FAIL; } if (fespi_txwm_wait(bank) != ERROR_OK) return ERROR_FAIL; if (fespi_write_reg(bank, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO) != ERROR_OK) return ERROR_FAIL; keep_alive(); return ERROR_OK; } static const uint8_t riscv32_bin[] = { #include "../../../contrib/loaders/flash/fespi/riscv32_fespi.inc" }; static const uint8_t riscv64_bin[] = { #include "../../../contrib/loaders/flash/fespi/riscv64_fespi.inc" }; static int fespi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct fespi_flash_bank *fespi_info = bank->driver_priv; uint32_t cur_count, page_size; int retval = ERROR_OK; LOG_DEBUG("bank->size=0x%x offset=0x%08" PRIx32 " count=0x%08" PRIx32, bank->size, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > fespi_info->dev->size_in_bytes) { LOG_WARNING("Write past end of flash. Extra data discarded."); count = fespi_info->dev->size_in_bytes - offset; } /* Check sector protection */ for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { /* Start offset in or before this sector? */ /* End offset in or behind this sector? */ if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) && ((offset + count - 1) >= bank->sectors[sector].offset) && bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FAIL; } } struct riscv_info *riscv = riscv_info(target); if (!is_riscv(riscv)) { LOG_ERROR("Unexpected target type"); return ERROR_FAIL; } unsigned int xlen = riscv_xlen(target); struct working_area *algorithm_wa = NULL; struct working_area *data_wa = NULL; const uint8_t *bin; size_t bin_size; if (xlen == 32) { bin = riscv32_bin; bin_size = sizeof(riscv32_bin); } else { bin = riscv64_bin; bin_size = sizeof(riscv64_bin); } unsigned data_wa_size = 0; if (target_alloc_working_area(target, bin_size, &algorithm_wa) == ERROR_OK) { retval = target_write_buffer(target, algorithm_wa->address, bin_size, bin); if (retval != ERROR_OK) { LOG_ERROR("Failed to write code to " TARGET_ADDR_FMT ": %d", algorithm_wa->address, retval); target_free_working_area(target, algorithm_wa); algorithm_wa = NULL; } else { data_wa_size = MIN(target_get_working_area_avail(target), count); if (data_wa_size < 128) { LOG_WARNING("Couldn't allocate data working area."); target_free_working_area(target, algorithm_wa); algorithm_wa = NULL; } else if (target_alloc_working_area(target, data_wa_size, &data_wa) != ERROR_OK) { target_free_working_area(target, algorithm_wa); algorithm_wa = NULL; } } } else { LOG_WARNING("Couldn't allocate %zd-byte working area.", bin_size); algorithm_wa = NULL; } /* If no valid page_size, use reasonable default. */ page_size = fespi_info->dev->pagesize ? fespi_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE; if (algorithm_wa) { struct reg_param reg_params[6]; init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); init_reg_param(®_params[2], "a2", xlen, PARAM_OUT); init_reg_param(®_params[3], "a3", xlen, PARAM_OUT); init_reg_param(®_params[4], "a4", xlen, PARAM_OUT); init_reg_param(®_params[5], "a5", xlen, PARAM_OUT); while (count > 0) { cur_count = MIN(count, data_wa_size); buf_set_u64(reg_params[0].value, 0, xlen, fespi_info->ctrl_base); buf_set_u64(reg_params[1].value, 0, xlen, page_size); buf_set_u64(reg_params[2].value, 0, xlen, data_wa->address); buf_set_u64(reg_params[3].value, 0, xlen, offset); buf_set_u64(reg_params[4].value, 0, xlen, cur_count); buf_set_u64(reg_params[5].value, 0, xlen, fespi_info->dev->pprog_cmd | (bank->size > 0x1000000 ? 0x100 : 0)); retval = target_write_buffer(target, data_wa->address, cur_count, buffer); if (retval != ERROR_OK) { LOG_DEBUG("Failed to write %d bytes to " TARGET_ADDR_FMT ": %d", cur_count, data_wa->address, retval); goto err; } LOG_DEBUG("write(ctrl_base=0x%" TARGET_PRIxADDR ", page_size=0x%x, " "address=0x%" TARGET_PRIxADDR ", offset=0x%" PRIx32 ", count=0x%" PRIx32 "), buffer=%02x %02x %02x %02x %02x %02x ..." PRIx32, fespi_info->ctrl_base, page_size, data_wa->address, offset, cur_count, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, algorithm_wa->address, 0, cur_count * 2, NULL); if (retval != ERROR_OK) { LOG_ERROR("Failed to execute algorithm at " TARGET_ADDR_FMT ": %d", algorithm_wa->address, retval); goto err; } uint64_t algorithm_result = buf_get_u64(reg_params[0].value, 0, xlen); if (algorithm_result != 0) { LOG_ERROR("Algorithm returned error %" PRId64, algorithm_result); retval = ERROR_FAIL; goto err; } buffer += cur_count; offset += cur_count; count -= cur_count; } target_free_working_area(target, data_wa); target_free_working_area(target, algorithm_wa); } else { fespi_txwm_wait(bank); /* Disable Hardware accesses*/ if (fespi_disable_hw_mode(bank) != ERROR_OK) return ERROR_FAIL; /* poll WIP */ retval = fespi_wip(bank, FESPI_PROBE_TIMEOUT); if (retval != ERROR_OK) goto err; uint32_t page_offset = offset % page_size; /* central part, aligned words */ while (count > 0) { /* clip block at page boundary */ if (page_offset + count > page_size) cur_count = page_size - page_offset; else cur_count = count; retval = slow_fespi_write_buffer(bank, buffer, offset, cur_count); if (retval != ERROR_OK) goto err; page_offset = 0; buffer += cur_count; offset += cur_count; count -= cur_count; } /* Switch to HW mode before return to prompt */ if (fespi_enable_hw_mode(bank) != ERROR_OK) return ERROR_FAIL; } return ERROR_OK; err: target_free_working_area(target, data_wa); target_free_working_area(target, algorithm_wa); /* Switch to HW mode before return to prompt */ if (fespi_enable_hw_mode(bank) != ERROR_OK) return ERROR_FAIL; return retval; } /* Return ID of flash device */ /* On exit, SW mode is kept */ static int fespi_read_flash_id(struct flash_bank *bank, uint32_t *id) { struct target *target = bank->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } fespi_txwm_wait(bank); /* poll WIP */ retval = fespi_wip(bank, FESPI_PROBE_TIMEOUT); if (retval != ERROR_OK) return retval; fespi_set_dir(bank, FESPI_DIR_RX); /* Send SPI command "read ID" */ if (fespi_write_reg(bank, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD) != ERROR_OK) return ERROR_FAIL; fespi_tx(bank, SPIFLASH_READ_ID); /* Send dummy bytes to actually read the ID.*/ fespi_tx(bank, 0); fespi_tx(bank, 0); fespi_tx(bank, 0); /* read ID from Receive Register */ *id = 0; if (fespi_rx(bank, NULL) != ERROR_OK) return ERROR_FAIL; uint8_t rx; if (fespi_rx(bank, &rx) != ERROR_OK) return ERROR_FAIL; *id = rx; if (fespi_rx(bank, &rx) != ERROR_OK) return ERROR_FAIL; *id |= (rx << 8); if (fespi_rx(bank, &rx) != ERROR_OK) return ERROR_FAIL; *id |= (rx << 16); if (fespi_write_reg(bank, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO) != ERROR_OK) return ERROR_FAIL; fespi_set_dir(bank, FESPI_DIR_TX); return ERROR_OK; } static int fespi_probe(struct flash_bank *bank) { struct target *target = bank->target; struct fespi_flash_bank *fespi_info = bank->driver_priv; struct flash_sector *sectors; uint32_t id = 0; /* silence uninitialized warning */ const struct fespi_target *target_device; int retval; uint32_t sectorsize; if (fespi_info->probed) free(bank->sectors); fespi_info->probed = false; if (fespi_info->ctrl_base == 0) { for (target_device = target_devices ; target_device->name ; ++target_device) if (target_device->tap_idcode == target->tap->idcode) break; if (!target_device->name) { LOG_ERROR("Device ID 0x%" PRIx32 " is not known as FESPI capable", target->tap->idcode); return ERROR_FAIL; } fespi_info->ctrl_base = target_device->ctrl_base; LOG_DEBUG("Valid FESPI on device %s at address " TARGET_ADDR_FMT, target_device->name, bank->base); } else { LOG_DEBUG("Assuming FESPI as specified at address " TARGET_ADDR_FMT " with ctrl at " TARGET_ADDR_FMT, fespi_info->ctrl_base, bank->base); } /* read and decode flash ID; returns in SW mode */ if (fespi_write_reg(bank, FESPI_REG_TXCTRL, FESPI_TXWM(1)) != ERROR_OK) return ERROR_FAIL; fespi_set_dir(bank, FESPI_DIR_TX); /* Disable Hardware accesses*/ if (fespi_disable_hw_mode(bank) != ERROR_OK) return ERROR_FAIL; retval = fespi_read_flash_id(bank, &id); if (fespi_enable_hw_mode(bank) != ERROR_OK) return ERROR_FAIL; if (retval != ERROR_OK) return retval; fespi_info->dev = NULL; for (const struct flash_device *p = flash_devices; p->name ; p++) if (p->device_id == id) { fespi_info->dev = p; break; } if (!fespi_info->dev) { LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id); return ERROR_FAIL; } LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", fespi_info->dev->name, fespi_info->dev->device_id); /* Set correct size value */ bank->size = fespi_info->dev->size_in_bytes; if (bank->size <= (1UL << 16)) LOG_WARNING("device needs 2-byte addresses - not implemented"); /* if no sectors, treat whole bank as single sector */ sectorsize = fespi_info->dev->sectorsize ? fespi_info->dev->sectorsize : fespi_info->dev->size_in_bytes; /* create and fill sectors array */ bank->num_sectors = fespi_info->dev->size_in_bytes / sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); if (!sectors) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { sectors[sector].offset = sector * sectorsize; sectors[sector].size = sectorsize; sectors[sector].is_erased = -1; sectors[sector].is_protected = 0; } bank->sectors = sectors; fespi_info->probed = true; return ERROR_OK; } static int fespi_auto_probe(struct flash_bank *bank) { struct fespi_flash_bank *fespi_info = bank->driver_priv; if (fespi_info->probed) return ERROR_OK; return fespi_probe(bank); } static int fespi_protect_check(struct flash_bank *bank) { /* Nothing to do. Protection is only handled in SW. */ return ERROR_OK; } static int get_fespi_info(struct flash_bank *bank, struct command_invocation *cmd) { struct fespi_flash_bank *fespi_info = bank->driver_priv; if (!(fespi_info->probed)) { command_print_sameline(cmd, "\nFESPI flash bank not probed yet\n"); return ERROR_OK; } command_print_sameline(cmd, "\nFESPI flash information:\n" " Device \'%s\' (ID 0x%08" PRIx32 ")\n", fespi_info->dev->name, fespi_info->dev->device_id); return ERROR_OK; } const struct flash_driver fespi_flash = { .name = "fespi", .flash_bank_command = fespi_flash_bank_command, .erase = fespi_erase, .protect = fespi_protect, .write = fespi_write, .read = default_flash_read, .probe = fespi_probe, .auto_probe = fespi_auto_probe, .erase_check = default_flash_blank_check, .protect_check = fespi_protect_check, .info = get_fespi_info, .free_driver_priv = default_flash_free_driver_priv }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/fm3.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Marc Willam, Holger Wech * * openOCD.fseu(AT)de.fujitsu.com * * Copyright (C) 2011 Ronny Strutz * * * * Copyright (C) 2013 Nemui Trinomius * * nemuisan_kawausogasuki@live.jp * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> #define FLASH_DQ6 0x40 /* Data toggle flag bit (TOGG) position */ #define FLASH_DQ5 0x20 /* Time limit exceeding flag bit (TLOV) position */ enum fm3_variant { MB9BFXX1, /* Flash Type '1' */ MB9BFXX2, MB9BFXX3, MB9BFXX4, MB9BFXX5, MB9BFXX6, MB9BFXX7, MB9BFXX8, MB9AFXX1, /* Flash Type '2' */ MB9AFXX2, MB9AFXX3, MB9AFXX4, MB9AFXX5, MB9AFXX6, MB9AFXX7, MB9AFXX8, }; enum fm3_flash_type { FM3_NO_FLASH_TYPE = 0, FM3_FLASH_TYPE1 = 1, FM3_FLASH_TYPE2 = 2 }; struct fm3_flash_bank { enum fm3_variant variant; enum fm3_flash_type flashtype; bool probed; }; FLASH_BANK_COMMAND_HANDLER(fm3_flash_bank_command) { struct fm3_flash_bank *fm3_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; fm3_info = malloc(sizeof(struct fm3_flash_bank)); bank->driver_priv = fm3_info; /* Flash type '1' */ if (strcmp(CMD_ARGV[5], "mb9bfxx1.cpu") == 0) { fm3_info->variant = MB9BFXX1; fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx2.cpu") == 0) { fm3_info->variant = MB9BFXX2; fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx3.cpu") == 0) { fm3_info->variant = MB9BFXX3; fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx4.cpu") == 0) { fm3_info->variant = MB9BFXX4; fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx5.cpu") == 0) { fm3_info->variant = MB9BFXX5; fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx6.cpu") == 0) { fm3_info->variant = MB9BFXX6; fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx7.cpu") == 0) { fm3_info->variant = MB9BFXX7; fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx8.cpu") == 0) { fm3_info->variant = MB9BFXX8; fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9afxx1.cpu") == 0) { /* Flash type '2' */ fm3_info->variant = MB9AFXX1; fm3_info->flashtype = FM3_FLASH_TYPE2; } else if (strcmp(CMD_ARGV[5], "mb9afxx2.cpu") == 0) { fm3_info->variant = MB9AFXX2; fm3_info->flashtype = FM3_FLASH_TYPE2; } else if (strcmp(CMD_ARGV[5], "mb9afxx3.cpu") == 0) { fm3_info->variant = MB9AFXX3; fm3_info->flashtype = FM3_FLASH_TYPE2; } else if (strcmp(CMD_ARGV[5], "mb9afxx4.cpu") == 0) { fm3_info->variant = MB9AFXX4; fm3_info->flashtype = FM3_FLASH_TYPE2; } else if (strcmp(CMD_ARGV[5], "mb9afxx5.cpu") == 0) { fm3_info->variant = MB9AFXX5; fm3_info->flashtype = FM3_FLASH_TYPE2; } else if (strcmp(CMD_ARGV[5], "mb9afxx6.cpu") == 0) { fm3_info->variant = MB9AFXX6; fm3_info->flashtype = FM3_FLASH_TYPE2; } else if (strcmp(CMD_ARGV[5], "mb9afxx7.cpu") == 0) { fm3_info->variant = MB9AFXX7; fm3_info->flashtype = FM3_FLASH_TYPE2; } else if (strcmp(CMD_ARGV[5], "mb9afxx8.cpu") == 0) { fm3_info->variant = MB9AFXX8; fm3_info->flashtype = FM3_FLASH_TYPE2; } /* unknown Flash type */ else { LOG_ERROR("unknown fm3 variant: %s", CMD_ARGV[5]); free(fm3_info); return ERROR_FLASH_BANK_INVALID; } fm3_info->probed = false; return ERROR_OK; } /* Data polling algorithm */ static int fm3_busy_wait(struct target *target, uint32_t offset, int timeout_ms) { int retval = ERROR_OK; uint8_t state1, state2; int ms = 0; /* While(1) loop exit via "break" and "return" on error */ while (1) { /* dummy-read - see flash manual */ retval = target_read_u8(target, offset, &state1); if (retval != ERROR_OK) return retval; /* Data polling 1 */ retval = target_read_u8(target, offset, &state1); if (retval != ERROR_OK) return retval; /* Data polling 2 */ retval = target_read_u8(target, offset, &state2); if (retval != ERROR_OK) return retval; /* Flash command finished via polled data equal? */ if ((state1 & FLASH_DQ6) == (state2 & FLASH_DQ6)) break; /* Timeout Flag? */ else if (state1 & FLASH_DQ5) { /* Retry data polling */ /* Data polling 1 */ retval = target_read_u8(target, offset, &state1); if (retval != ERROR_OK) return retval; /* Data polling 2 */ retval = target_read_u8(target, offset, &state2); if (retval != ERROR_OK) return retval; /* Flash command finished via polled data equal? */ if ((state1 & FLASH_DQ6) != (state2 & FLASH_DQ6)) return ERROR_FLASH_OPERATION_FAILED; /* finish anyway */ break; } usleep(1000); ++ms; /* Polling time exceeded? */ if (ms > timeout_ms) { LOG_ERROR("Polling data reading timed out!"); return ERROR_FLASH_OPERATION_FAILED; } } if (retval == ERROR_OK) LOG_DEBUG("fm3_busy_wait(%" PRIx32 ") needs about %d ms", offset, ms); return retval; } static int fm3_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct fm3_flash_bank *fm3_info = bank->driver_priv; struct target *target = bank->target; int retval = ERROR_OK; uint32_t u32_dummy_read; int odd; uint32_t u32_flash_type; uint32_t u32_flash_seq_address1; uint32_t u32_flash_seq_address2; struct working_area *write_algorithm; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; u32_flash_type = (uint32_t) fm3_info->flashtype; if (u32_flash_type == FM3_FLASH_TYPE1) { u32_flash_seq_address1 = 0x00001550; u32_flash_seq_address2 = 0x00000AA8; } else if (u32_flash_type == FM3_FLASH_TYPE2) { u32_flash_seq_address1 = 0x00000AA8; u32_flash_seq_address2 = 0x00000554; } else { LOG_ERROR("Flash/Device type unknown!"); return ERROR_FLASH_OPERATION_FAILED; } if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* RAMCODE used for fm3 Flash sector erase: */ /* R0 keeps Flash Sequence address 1 (u32FlashSeq1) */ /* R1 keeps Flash Sequence address 2 (u32FlashSeq2) */ /* R2 keeps Flash Offset address (ofs) */ static const uint8_t fm3_flash_erase_sector_code[] = { /* *(uint16_t*)u32FlashSeq1 = 0xAA; */ 0xAA, 0x24, /* MOVS R4, #0xAA */ 0x04, 0x80, /* STRH R4, [R0, #0] */ /* *(uint16_t*)u32FlashSeq2 = 0x55; */ 0x55, 0x23, /* MOVS R3, #0x55 */ 0x0B, 0x80, /* STRH R3, [R1, #0] */ /* *(uint16_t*)u32FlashSeq1 = 0x80; */ 0x80, 0x25, /* MOVS R5, #0x80 */ 0x05, 0x80, /* STRH R5, [R0, #0] */ /* *(uint16_t*)u32FlashSeq1 = 0xAA; */ 0x04, 0x80, /* STRH R4, [R0, #0] */ /* *(uint16_t*)u32FlashSeq2 = 0x55; */ 0x0B, 0x80, /* STRH R3, [R1, #0] */ /* Sector_Erase Command (0x30) */ /* *(uint16_t*)ofs = 0x30; */ 0x30, 0x20, /* MOVS R0, #0x30 */ 0x10, 0x80, /* STRH R0, [R2, #0] */ /* End Code */ 0x00, 0xBE, /* BKPT #0 */ }; LOG_INFO("Fujitsu MB9[A/B]FXXX: Sector Erase ... (%u to %u)", first, last); /* disable HW watchdog */ retval = target_write_u32(target, 0x40011C00, 0x1ACCE551); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, 0x40011C00, 0xE5331AAE); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, 0x40011008, 0x00000000); if (retval != ERROR_OK) return retval; /* FASZR = 0x01, Enables CPU Programming Mode (16-bit Flash access) */ retval = target_write_u32(target, 0x40000000, 0x0001); if (retval != ERROR_OK) return retval; /* dummy read of FASZR */ retval = target_read_u32(target, 0x40000000, &u32_dummy_read); if (retval != ERROR_OK) return retval; /* allocate working area with flash sector erase code */ if (target_alloc_working_area(target, sizeof(fm3_flash_erase_sector_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(fm3_flash_erase_sector_code), fm3_flash_erase_sector_code); if (retval != ERROR_OK) return retval; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* u32_flash_seq_address1 */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* u32_flash_seq_address2 */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* offset */ /* write code buffer and use Flash sector erase code within fm3 */ for (unsigned int sector = first ; sector <= last ; sector++) { uint32_t offset = bank->sectors[sector].offset; for (odd = 0; odd < 2 ; odd++) { if (odd) offset += 4; buf_set_u32(reg_params[0].value, 0, 32, u32_flash_seq_address1); buf_set_u32(reg_params[1].value, 0, 32, u32_flash_seq_address2); buf_set_u32(reg_params[2].value, 0, 32, offset); retval = target_run_algorithm(target, 0, NULL, 3, reg_params, write_algorithm->address, 0, 100000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("Error executing flash erase programming algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; return retval; } retval = fm3_busy_wait(target, offset, 500); if (retval != ERROR_OK) return retval; } } target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); /* FASZR = 0x02, Enables CPU Run Mode (32-bit Flash access) */ retval = target_write_u32(target, 0x40000000, 0x0002); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, 0x40000000, &u32_dummy_read); /* dummy read of FASZR */ return retval; } static int fm3_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct fm3_flash_bank *fm3_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 2048; /* Default minimum value */ struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; uint32_t u32_flash_type; uint32_t u32_flash_seq_address1; uint32_t u32_flash_seq_address2; /* Increase buffer_size if needed */ if (buffer_size < (target->working_area_size / 2)) buffer_size = (target->working_area_size / 2); u32_flash_type = (uint32_t) fm3_info->flashtype; if (u32_flash_type == FM3_FLASH_TYPE1) { u32_flash_seq_address1 = 0x00001550; u32_flash_seq_address2 = 0x00000AA8; } else if (u32_flash_type == FM3_FLASH_TYPE2) { u32_flash_seq_address1 = 0x00000AA8; u32_flash_seq_address2 = 0x00000554; } else { LOG_ERROR("Flash/Device type unknown!"); return ERROR_FLASH_OPERATION_FAILED; } /* RAMCODE used for fm3 Flash programming: */ /* R0 keeps source start address (u32Source) */ /* R1 keeps target start address (u32Target) */ /* R2 keeps number of halfwords to write (u32Count) */ /* R3 keeps Flash Sequence address 1 (u32FlashSeq1) */ /* R4 keeps Flash Sequence address 2 (u32FlashSeq2) */ /* R5 returns result value (u32FlashResult) */ static const uint8_t fm3_flash_write_code[] = { /* fm3_FLASH_IF->FASZ &= 0xFFFD; */ 0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x4F, 0xF6, 0xFD, 0x76, /* MOVW R6, #0xFFFD */ 0x35, 0x40, /* ANDS R5, R5, R6 */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x35, 0x60, /* STR R5, [R6] */ /* fm3_FLASH_IF->FASZ |= 1; */ 0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */ 0x2D, 0x68, /* LDR R5, [R3] */ 0x55, 0xF0, 0x01, 0x05, /* ORRS.W R5, R5, #1 */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x35, 0x60, /* STR R5, [R6] */ /* u32_dummy_read = fm3_FLASH_IF->FASZ; */ 0x28, 0x4D, /* LDR.N R5, ??u32_dummy_read */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x36, 0x68, /* LDR R6, [R6] */ 0x2E, 0x60, /* STR R6, [R5] */ /* u32FlashResult = FLASH_WRITE_NO_RESULT */ 0x26, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x00, 0x26, /* MOVS R6, #0 */ 0x2E, 0x60, /* STR R6, [R5] */ /* while ((u32Count > 0 ) */ /* && (u32FlashResult */ /* == FLASH_WRITE_NO_RESULT)) */ 0x01, 0x2A, /* L0: CMP R2, #1 */ 0x2C, 0xDB, /* BLT.N L1 */ 0x24, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x00, 0x2D, /* CMP R5, #0 */ 0x28, 0xD1, /* BNE.N L1 */ /* *u32FlashSeq1 = FLASH_WRITE_1; */ 0xAA, 0x25, /* MOVS R5, #0xAA */ 0x1D, 0x60, /* STR R5, [R3] */ /* *u32FlashSeq2 = FLASH_WRITE_2; */ 0x55, 0x25, /* MOVS R5, #0x55 */ 0x25, 0x60, /* STR R5, [R4] */ /* *u32FlashSeq1 = FLASH_WRITE_3; */ 0xA0, 0x25, /* MOVS R5, #0xA0 */ 0x1D, 0x60, /* STRH R5, [R3] */ /* *(volatile uint16_t*)u32Target */ /* = *(volatile uint16_t*)u32Source; */ 0x05, 0x88, /* LDRH R5, [R0] */ 0x0D, 0x80, /* STRH R5, [R1] */ /* while (u32FlashResult */ /* == FLASH_WRITE_NO_RESTULT) */ 0x1E, 0x4D, /* L2: LDR.N R5, ??u32FlashResult */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x00, 0x2D, /* CMP R5, #0 */ 0x11, 0xD1, /* BNE.N L3 */ /* if ((*(volatile uint16_t*)u32Target */ /* & FLASH_DQ5) == FLASH_DQ5) */ 0x0D, 0x88, /* LDRH R5, [R1] */ 0xAD, 0x06, /* LSLS R5, R5, #0x1A */ 0x02, 0xD5, /* BPL.N L4 */ /* u32FlashResult = FLASH_WRITE_TIMEOUT */ 0x1A, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x02, 0x26, /* MOVS R6, #2 */ 0x2E, 0x60, /* STR R6, [R5] */ /* if ((*(volatile uint16_t *)u32Target */ /* & FLASH_DQ7) */ /* == (*(volatile uint16_t*)u32Source */ /* & FLASH_DQ7)) */ 0x0D, 0x88, /* L4: LDRH R5, [R1] */ 0x15, 0xF0, 0x80, 0x05, /* ANDS.W R5, R5, #0x80 */ 0x06, 0x88, /* LDRH R6, [R0] */ 0x16, 0xF0, 0x80, 0x06, /* ANDS.W R6, R6, #0x80 */ 0xB5, 0x42, /* CMP R5, R6 */ 0xED, 0xD1, /* BNE.N L2 */ /* u32FlashResult = FLASH_WRITE_OKAY */ 0x15, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x01, 0x26, /* MOVS R6, #1 */ 0x2E, 0x60, /* STR R6, [R5] */ 0xE9, 0xE7, /* B.N L2 */ /* if (u32FlashResult */ /* != FLASH_WRITE_TIMEOUT) */ 0x13, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x02, 0x2D, /* CMP R5, #2 */ 0x02, 0xD0, /* BEQ.N L5 */ /* u32FlashResult = FLASH_WRITE_NO_RESULT */ 0x11, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x00, 0x26, /* MOVS R6, #0 */ 0x2E, 0x60, /* STR R6, [R5] */ /* u32Count--; */ 0x52, 0x1E, /* L5: SUBS R2, R2, #1 */ /* u32Source += 2; */ 0x80, 0x1C, /* ADDS R0, R0, #2 */ /* u32Target += 2; */ 0x89, 0x1C, /* ADDS R1, R1, #2 */ 0xD0, 0xE7, /* B.N L0 */ /* fm3_FLASH_IF->FASZ &= 0xFFFE; */ 0x5F, 0xF0, 0x80, 0x45, /* L1: MOVS.W R5, #(fm3_FLASH_IF->FASZ) */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x4F, 0xF6, 0xFE, 0x76, /* MOVW R6, #0xFFFE */ 0x35, 0x40, /* ANDS R5, R5, R6 */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x35, 0x60, /* STR R5, [R6] */ /* fm3_FLASH_IF->FASZ |= 2; */ 0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x55, 0xF0, 0x02, 0x05, /* ORRS.W R5, R5, #2 */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x35, 0x60, /* STR R5, [R6] */ /* u32_dummy_read = fm3_FLASH_IF->FASZ; */ 0x04, 0x4D, /* LDR.N R5, ??u32_dummy_read */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x36, 0x68, /* LDR R6, [R6] */ 0x2E, 0x60, /* STR R6, [R5] */ /* copy u32FlashResult to R3 for return */ /* value */ 0xDF, 0xF8, 0x08, 0x50, /* LDR.W R5, ??u32FlashResult */ 0x2D, 0x68, /* LDR R5, [R5] */ /* Breakpoint here */ 0x00, 0xBE, /* BKPT #0 */ /* The following address pointers assume, that the code is running from */ /* SRAM basic-address + 8.These address pointers will be patched, if a */ /* different start address in RAM is used (e.g. for Flash type 2)! */ /* Default SRAM basic-address is 0x20000000. */ 0x00, 0x00, 0x00, 0x20, /* u32_dummy_read address in RAM (0x20000000) */ 0x04, 0x00, 0x00, 0x20 /* u32FlashResult address in RAM (0x20000004) */ }; LOG_INFO("Fujitsu MB9[A/B]FXXX: FLASH Write ..."); /* disable HW watchdog */ retval = target_write_u32(target, 0x40011C00, 0x1ACCE551); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, 0x40011C00, 0xE5331AAE); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, 0x40011008, 0x00000000); if (retval != ERROR_OK) return retval; count = count / 2; /* number bytes -> number halfwords */ /* check code alignment */ if (offset & 0x1) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* allocate working area and variables with flash programming code */ if (target_alloc_working_area(target, sizeof(fm3_flash_write_code) + 8, &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address + 8, sizeof(fm3_flash_write_code), fm3_flash_write_code); if (retval != ERROR_OK) return retval; /* Patching 'local variable address' */ /* Algorithm: u32_dummy_read: */ retval = target_write_u32(target, (write_algorithm->address + 8) + sizeof(fm3_flash_write_code) - 8, (write_algorithm->address)); if (retval != ERROR_OK) return retval; /* Algorithm: u32FlashResult: */ retval = target_write_u32(target, (write_algorithm->address + 8) + sizeof(fm3_flash_write_code) - 4, (write_algorithm->address) + 4); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* free working area, write algorithm already allocated */ target_free_working_area(target, write_algorithm); LOG_WARNING("No large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* source start address */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* target start address */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* number of halfwords to program */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* Flash Sequence address 1 */ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* Flash Sequence address 1 */ init_reg_param(®_params[5], "r5", 32, PARAM_IN); /* result */ /* write code buffer and use Flash programming code within fm3 */ /* Set breakpoint to 0 with time-out of 1000 ms */ while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count; retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); buf_set_u32(reg_params[3].value, 0, 32, u32_flash_seq_address1); buf_set_u32(reg_params[4].value, 0, 32, u32_flash_seq_address2); retval = target_run_algorithm(target, 0, NULL, 6, reg_params, (write_algorithm->address + 8), 0, 1000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("Error executing fm3 Flash programming algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (buf_get_u32(reg_params[5].value, 0, 32) != ERROR_OK) { LOG_ERROR("Fujitsu MB9[A/B]FXXX: Flash programming ERROR (Timeout) -> Reg R3: %" PRIx32, buf_get_u32(reg_params[5].value, 0, 32)); retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count * 2; address += thisrun_count * 2; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); return retval; } static int fm3_probe(struct flash_bank *bank) { struct fm3_flash_bank *fm3_info = bank->driver_priv; uint16_t num_pages; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* -- page-- start -- blocksize - mpu - totalFlash -- page0 0x00000 16k page1 0x04000 16k page2 0x08000 96k ___ fxx3 128k Flash page3 0x20000 128k ___ fxx4 256k Flash page4 0x40000 128k ___ fxx5 384k Flash page5 0x60000 128k ___ fxx6 512k Flash ----------------------- page6 0x80000 128k page7 0xa0000 128k ___ fxx7 256k Flash page8 0xc0000 128k page9 0xe0000 128k ___ fxx8 256k Flash */ num_pages = 10; /* max number of Flash pages for malloc */ fm3_info->probed = false; bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); bank->base = 0x00000000; bank->size = 32 * 1024; /* bytes */ bank->sectors[0].offset = 0; bank->sectors[0].size = 16 * 1024; bank->sectors[0].is_erased = -1; bank->sectors[0].is_protected = -1; bank->sectors[1].offset = 0x4000; bank->sectors[1].size = 16 * 1024; bank->sectors[1].is_erased = -1; bank->sectors[1].is_protected = -1; if ((fm3_info->variant == MB9BFXX1) || (fm3_info->variant == MB9AFXX1)) { num_pages = 3; bank->size = 64 * 1024; /* bytes */ bank->num_sectors = num_pages; bank->sectors[2].offset = 0x8000; bank->sectors[2].size = 32 * 1024; bank->sectors[2].is_erased = -1; bank->sectors[2].is_protected = -1; } if ((fm3_info->variant == MB9BFXX2) || (fm3_info->variant == MB9BFXX4) || (fm3_info->variant == MB9BFXX5) || (fm3_info->variant == MB9BFXX6) || (fm3_info->variant == MB9BFXX7) || (fm3_info->variant == MB9BFXX8) || (fm3_info->variant == MB9AFXX2) || (fm3_info->variant == MB9AFXX4) || (fm3_info->variant == MB9AFXX5) || (fm3_info->variant == MB9AFXX6) || (fm3_info->variant == MB9AFXX7) || (fm3_info->variant == MB9AFXX8)) { num_pages = 3; bank->size = 128 * 1024; /* bytes */ bank->num_sectors = num_pages; bank->sectors[2].offset = 0x8000; bank->sectors[2].size = 96 * 1024; bank->sectors[2].is_erased = -1; bank->sectors[2].is_protected = -1; } if ((fm3_info->variant == MB9BFXX4) || (fm3_info->variant == MB9BFXX5) || (fm3_info->variant == MB9BFXX6) || (fm3_info->variant == MB9BFXX7) || (fm3_info->variant == MB9BFXX8) || (fm3_info->variant == MB9AFXX4) || (fm3_info->variant == MB9AFXX5) || (fm3_info->variant == MB9AFXX6) || (fm3_info->variant == MB9AFXX7) || (fm3_info->variant == MB9AFXX8)) { num_pages = 4; bank->size = 256 * 1024; /* bytes */ bank->num_sectors = num_pages; bank->sectors[3].offset = 0x20000; bank->sectors[3].size = 128 * 1024; bank->sectors[3].is_erased = -1; bank->sectors[3].is_protected = -1; } if ((fm3_info->variant == MB9BFXX5) || (fm3_info->variant == MB9BFXX6) || (fm3_info->variant == MB9BFXX7) || (fm3_info->variant == MB9BFXX8) || (fm3_info->variant == MB9AFXX5) || (fm3_info->variant == MB9AFXX6) || (fm3_info->variant == MB9AFXX7) || (fm3_info->variant == MB9AFXX8)) { num_pages = 5; bank->size = 384 * 1024; /* bytes */ bank->num_sectors = num_pages; bank->sectors[4].offset = 0x40000; bank->sectors[4].size = 128 * 1024; bank->sectors[4].is_erased = -1; bank->sectors[4].is_protected = -1; } if ((fm3_info->variant == MB9BFXX6) || (fm3_info->variant == MB9BFXX7) || (fm3_info->variant == MB9BFXX8) || (fm3_info->variant == MB9AFXX6) || (fm3_info->variant == MB9AFXX7) || (fm3_info->variant == MB9AFXX8)) { num_pages = 6; bank->size = 512 * 1024; /* bytes */ bank->num_sectors = num_pages; bank->sectors[5].offset = 0x60000; bank->sectors[5].size = 128 * 1024; bank->sectors[5].is_erased = -1; bank->sectors[5].is_protected = -1; } if ((fm3_info->variant == MB9BFXX7) || (fm3_info->variant == MB9BFXX8) || (fm3_info->variant == MB9AFXX7) || (fm3_info->variant == MB9AFXX8)) { num_pages = 8; bank->size = 768 * 1024; /* bytes */ bank->num_sectors = num_pages; bank->sectors[6].offset = 0x80000; bank->sectors[6].size = 128 * 1024; bank->sectors[6].is_erased = -1; bank->sectors[6].is_protected = -1; bank->sectors[7].offset = 0xa0000; bank->sectors[7].size = 128 * 1024; bank->sectors[7].is_erased = -1; bank->sectors[7].is_protected = -1; } if ((fm3_info->variant == MB9BFXX8) || (fm3_info->variant == MB9AFXX8)) { num_pages = 10; bank->size = 1024 * 1024; /* bytes */ bank->num_sectors = num_pages; bank->sectors[8].offset = 0xc0000; bank->sectors[8].size = 128 * 1024; bank->sectors[8].is_erased = -1; bank->sectors[8].is_protected = -1; bank->sectors[9].offset = 0xe0000; bank->sectors[9].size = 128 * 1024; bank->sectors[9].is_erased = -1; bank->sectors[9].is_protected = -1; } fm3_info->probed = true; return ERROR_OK; } static int fm3_auto_probe(struct flash_bank *bank) { struct fm3_flash_bank *fm3_info = bank->driver_priv; if (fm3_info->probed) return ERROR_OK; return fm3_probe(bank); } /* Chip erase */ static int fm3_chip_erase(struct flash_bank *bank) { struct target *target = bank->target; struct fm3_flash_bank *fm3_info2 = bank->driver_priv; int retval = ERROR_OK; uint32_t u32_dummy_read; uint32_t u32_flash_type; uint32_t u32_flash_seq_address1; uint32_t u32_flash_seq_address2; struct working_area *write_algorithm; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; u32_flash_type = (uint32_t) fm3_info2->flashtype; if (u32_flash_type == FM3_FLASH_TYPE1) { LOG_INFO("*** Erasing mb9bfxxx type"); u32_flash_seq_address1 = 0x00001550; u32_flash_seq_address2 = 0x00000AA8; } else if (u32_flash_type == FM3_FLASH_TYPE2) { LOG_INFO("*** Erasing mb9afxxx type"); u32_flash_seq_address1 = 0x00000AA8; u32_flash_seq_address2 = 0x00000554; } else { LOG_ERROR("Flash/Device type unknown!"); return ERROR_FLASH_OPERATION_FAILED; } if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* RAMCODE used for fm3 Flash chip erase: */ /* R0 keeps Flash Sequence address 1 (u32FlashSeq1) */ /* R1 keeps Flash Sequence address 2 (u32FlashSeq2) */ static const uint8_t fm3_flash_erase_chip_code[] = { /* *(uint16_t*)u32FlashSeq1 = 0xAA; */ 0xAA, 0x22, /* MOVS R2, #0xAA */ 0x02, 0x80, /* STRH R2, [R0, #0] */ /* *(uint16_t*)u32FlashSeq2 = 0x55; */ 0x55, 0x23, /* MOVS R3, #0x55 */ 0x0B, 0x80, /* STRH R3, [R1, #0] */ /* *(uint16_t*)u32FlashSeq1 = 0x80; */ 0x80, 0x24, /* MOVS R4, #0x80 */ 0x04, 0x80, /* STRH R4, [R0, #0] */ /* *(uint16_t*)u32FlashSeq1 = 0xAA; */ 0x02, 0x80, /* STRH R2, [R0, #0] */ /* *(uint16_t*)u32FlashSeq2 = 0x55; */ 0x0B, 0x80, /* STRH R3, [R1, #0] */ /* Chip_Erase Command 0x10 */ /* *(uint16_t*)u32FlashSeq1 = 0x10; */ 0x10, 0x21, /* MOVS R1, #0x10 */ 0x01, 0x80, /* STRH R1, [R0, #0] */ /* End Code */ 0x00, 0xBE, /* BKPT #0 */ }; LOG_INFO("Fujitsu MB9[A/B]xxx: Chip Erase ... (may take several seconds)"); /* disable HW watchdog */ retval = target_write_u32(target, 0x40011C00, 0x1ACCE551); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, 0x40011C00, 0xE5331AAE); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, 0x40011008, 0x00000000); if (retval != ERROR_OK) return retval; /* FASZR = 0x01, Enables CPU Programming Mode (16-bit Flash access) */ retval = target_write_u32(target, 0x40000000, 0x0001); if (retval != ERROR_OK) return retval; /* dummy read of FASZR */ retval = target_read_u32(target, 0x40000000, &u32_dummy_read); if (retval != ERROR_OK) return retval; /* allocate working area with flash chip erase code */ if (target_alloc_working_area(target, sizeof(fm3_flash_erase_chip_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(fm3_flash_erase_chip_code), fm3_flash_erase_chip_code); if (retval != ERROR_OK) return retval; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* u32_flash_seq_address1 */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* u32_flash_seq_address2 */ buf_set_u32(reg_params[0].value, 0, 32, u32_flash_seq_address1); buf_set_u32(reg_params[1].value, 0, 32, u32_flash_seq_address2); retval = target_run_algorithm(target, 0, NULL, 2, reg_params, write_algorithm->address, 0, 100000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("Error executing flash erase programming algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; return retval; } target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); retval = fm3_busy_wait(target, u32_flash_seq_address2, 20000); /* 20s timeout */ if (retval != ERROR_OK) return retval; /* FASZR = 0x02, Re-enables CPU Run Mode (32-bit Flash access) */ retval = target_write_u32(target, 0x40000000, 0x0002); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, 0x40000000, &u32_dummy_read); /* dummy read of FASZR */ return retval; } COMMAND_HANDLER(fm3_handle_chip_erase_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; if (fm3_chip_erase(bank) == ERROR_OK) { command_print(CMD, "fm3 chip erase complete"); } else { command_print(CMD, "fm3 chip erase failed"); } return ERROR_OK; } static const struct command_registration fm3_exec_command_handlers[] = { { .name = "chip_erase", .usage = "<bank>", .handler = fm3_handle_chip_erase_command, .mode = COMMAND_EXEC, .help = "Erase entire Flash device.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration fm3_command_handlers[] = { { .name = "fm3", .mode = COMMAND_ANY, .help = "fm3 Flash command group", .usage = "", .chain = fm3_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver fm3_flash = { .name = "fm3", .commands = fm3_command_handlers, .flash_bank_command = fm3_flash_bank_command, .erase = fm3_erase, .write = fm3_write_block, .probe = fm3_probe, .auto_probe = fm3_auto_probe, .erase_check = default_flash_blank_check, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/fm4.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Spansion FM4 flash * * Copyright (c) 2015 Andreas Färber * * Based on S6E2DH_MN709-00013 for S6E2DH/DF/D5/D3 series * Based on S6E2CC_MN709-00007 for S6E2CC/C5/C4/C3/C2/C1 series * Based on MB9B560R_MN709-00005 for MB9BFx66/x67/x68 series * Based on MB9B560L_MN709-00006 for MB9BFx64/x65/x66 series */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> #define FLASH_BASE 0x40000000 #define FASZR (FLASH_BASE + 0x000) #define DFCTRLR (FLASH_BASE + 0x030) #define DFCTRLR_DFE (1UL << 0) #define WDG_BASE 0x40011000 #define WDG_CTL (WDG_BASE + 0x008) #define WDG_LCK (WDG_BASE + 0xC00) enum fm4_variant { MB9BFX64, MB9BFX65, MB9BFX66, MB9BFX67, MB9BFX68, S6E2CX8, S6E2CX9, S6E2CXA, S6E2DX, }; struct fm4_flash_bank { enum fm4_variant variant; int macro_nr; bool probed; }; static int fm4_disable_hw_watchdog(struct target *target) { int retval; retval = target_write_u32(target, WDG_LCK, 0x1ACCE551); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, WDG_LCK, 0xE5331AAE); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, WDG_CTL, 0); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int fm4_enter_flash_cpu_programming_mode(struct target *target) { uint32_t u32_value; int retval; /* FASZR ASZ = CPU programming mode */ retval = target_write_u32(target, FASZR, 0x00000001); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, FASZR, &u32_value); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int fm4_enter_flash_cpu_rom_mode(struct target *target) { uint32_t u32_value; int retval; /* FASZR ASZ = CPU ROM mode */ retval = target_write_u32(target, FASZR, 0x00000002); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, FASZR, &u32_value); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int fm4_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct working_area *workarea; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_algo; unsigned i; int retval; const uint8_t erase_sector_code[] = { #include "../../../contrib/loaders/flash/fm4/erase.inc" }; if (target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } LOG_DEBUG("Spansion FM4 erase sectors %u to %u", first, last); retval = fm4_disable_hw_watchdog(target); if (retval != ERROR_OK) return retval; retval = fm4_enter_flash_cpu_programming_mode(target); if (retval != ERROR_OK) return retval; retval = target_alloc_working_area(target, sizeof(erase_sector_code), &workarea); if (retval != ERROR_OK) { LOG_ERROR("No working area available."); retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; goto err_alloc_code; } retval = target_write_buffer(target, workarea->address, sizeof(erase_sector_code), erase_sector_code); if (retval != ERROR_OK) goto err_write_code; armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC; armv7m_algo.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN); for (unsigned int sector = first; sector <= last; sector++) { uint32_t addr = bank->base + bank->sectors[sector].offset; uint32_t result; buf_set_u32(reg_params[0].value, 0, 32, (addr & ~0xffff) | 0xAA8); buf_set_u32(reg_params[1].value, 0, 32, (addr & ~0xffff) | 0x554); buf_set_u32(reg_params[2].value, 0, 32, addr); retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, workarea->address, 0, 1000, &armv7m_algo); if (retval != ERROR_OK) { LOG_ERROR("Error executing flash sector erase " "programming algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; goto err_run; } result = buf_get_u32(reg_params[3].value, 0, 32); if (result == 2) { LOG_ERROR("Timeout error from flash sector erase programming algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; goto err_run_ret; } else if (result != 0) { LOG_ERROR("Unexpected error %" PRIu32 " from flash sector erase programming algorithm", result); retval = ERROR_FLASH_OPERATION_FAILED; goto err_run_ret; } else retval = ERROR_OK; } err_run_ret: err_run: for (i = 0; i < ARRAY_SIZE(reg_params); i++) destroy_reg_param(®_params[i]); err_write_code: target_free_working_area(target, workarea); err_alloc_code: if (retval != ERROR_OK) fm4_enter_flash_cpu_rom_mode(target); else retval = fm4_enter_flash_cpu_rom_mode(target); return retval; } static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t byte_count) { struct target *target = bank->target; struct working_area *code_workarea, *data_workarea; struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_algo; uint32_t halfword_count = DIV_ROUND_UP(byte_count, 2); uint32_t result; unsigned i; int retval, retval2 = ERROR_OK; const uint8_t write_block_code[] = { #include "../../../contrib/loaders/flash/fm4/write.inc" }; LOG_DEBUG("Spansion FM4 write at 0x%08" PRIx32 " (%" PRIu32 " bytes)", offset, byte_count); if (offset & 0x1) { LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } if (byte_count & 0x1) { LOG_WARNING("length %" PRIu32 " is not 2-byte aligned, rounding up", byte_count); } if (target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } retval = fm4_disable_hw_watchdog(target); if (retval != ERROR_OK) return retval; retval = target_alloc_working_area(target, sizeof(write_block_code), &code_workarea); if (retval != ERROR_OK) { LOG_ERROR("No working area available for write code."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, code_workarea->address, sizeof(write_block_code), write_block_code); if (retval != ERROR_OK) goto err_write_code; retval = target_alloc_working_area(target, MIN(halfword_count * 2, target_get_working_area_avail(target)), &data_workarea); if (retval != ERROR_OK) { LOG_ERROR("No working area available for write data."); retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; goto err_alloc_data; } armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC; armv7m_algo.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_OUT); init_reg_param(®_params[5], "r5", 32, PARAM_IN); retval = fm4_enter_flash_cpu_programming_mode(target); if (retval != ERROR_OK) goto err_flash_mode; while (byte_count > 0) { uint32_t halfwords = MIN(halfword_count, data_workarea->size / 2); uint32_t addr = bank->base + offset; LOG_DEBUG("copying %" PRIu32 " bytes to SRAM " TARGET_ADDR_FMT, MIN(halfwords * 2, byte_count), data_workarea->address); retval = target_write_buffer(target, data_workarea->address, MIN(halfwords * 2, byte_count), buffer); if (retval != ERROR_OK) { LOG_ERROR("Error writing data buffer"); retval = ERROR_FLASH_OPERATION_FAILED; goto err_write_data; } LOG_DEBUG("writing 0x%08" PRIx32 "-0x%08" PRIx32 " (%" PRIu32 "x)", addr, addr + halfwords * 2 - 1, halfwords); buf_set_u32(reg_params[0].value, 0, 32, (addr & ~0xffff) | 0xAA8); buf_set_u32(reg_params[1].value, 0, 32, (addr & ~0xffff) | 0x554); buf_set_u32(reg_params[2].value, 0, 32, addr); buf_set_u32(reg_params[3].value, 0, 32, data_workarea->address); buf_set_u32(reg_params[4].value, 0, 32, halfwords); retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, code_workarea->address, 0, 5 * 60 * 1000, &armv7m_algo); if (retval != ERROR_OK) { LOG_ERROR("Error executing flash sector erase " "programming algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; goto err_run; } result = buf_get_u32(reg_params[5].value, 0, 32); if (result == 2) { LOG_ERROR("Timeout error from flash write " "programming algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; goto err_run_ret; } else if (result != 0) { LOG_ERROR("Unexpected error %" PRIu32 " from flash write " "programming algorithm", result); retval = ERROR_FLASH_OPERATION_FAILED; goto err_run_ret; } else retval = ERROR_OK; halfword_count -= halfwords; offset += halfwords * 2; buffer += halfwords * 2; byte_count -= MIN(halfwords * 2, byte_count); } err_run_ret: err_run: err_write_data: retval2 = fm4_enter_flash_cpu_rom_mode(target); err_flash_mode: for (i = 0; i < ARRAY_SIZE(reg_params); i++) destroy_reg_param(®_params[i]); target_free_working_area(target, data_workarea); err_alloc_data: err_write_code: target_free_working_area(target, code_workarea); if (retval != ERROR_OK) return retval; return retval2; } static int mb9bf_probe(struct flash_bank *bank) { struct fm4_flash_bank *fm4_bank = bank->driver_priv; uint32_t flash_addr = bank->base; switch (fm4_bank->variant) { case MB9BFX64: bank->num_sectors = 8; break; case MB9BFX65: bank->num_sectors = 10; break; case MB9BFX66: bank->num_sectors = 12; break; case MB9BFX67: bank->num_sectors = 16; break; case MB9BFX68: bank->num_sectors = 20; break; default: return ERROR_FLASH_OPER_UNSUPPORTED; } LOG_DEBUG("%u sectors", bank->num_sectors); bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); for (unsigned int i = 0; i < bank->num_sectors; i++) { if (i < 4) bank->sectors[i].size = 8 * 1024; else if (i == 4) bank->sectors[i].size = 32 * 1024; else bank->sectors[i].size = 64 * 1024; bank->sectors[i].offset = flash_addr - bank->base; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; bank->size += bank->sectors[i].size; flash_addr += bank->sectors[i].size; } return ERROR_OK; } static void s6e2cc_init_sector(struct flash_sector *sector, int sa) { if (sa < 8) sector->size = 8 * 1024; else if (sa == 8) sector->size = 32 * 1024; else sector->size = 64 * 1024; sector->is_erased = -1; sector->is_protected = -1; } static int s6e2cc_probe(struct flash_bank *bank) { struct target *target = bank->target; struct fm4_flash_bank *fm4_bank = bank->driver_priv; uint32_t u32_value; uint32_t flash_addr = bank->base; int retval; unsigned int i, num_extra_sectors, num_sectors; retval = target_read_u32(target, DFCTRLR, &u32_value); if (retval != ERROR_OK) return retval; if (u32_value & DFCTRLR_DFE) { LOG_WARNING("Dual Flash mode is not implemented."); return ERROR_FLASH_OPER_UNSUPPORTED; } switch (fm4_bank->variant) { case S6E2CX8: num_sectors = (fm4_bank->macro_nr == 0) ? 20 : 0; break; case S6E2CX9: num_sectors = (fm4_bank->macro_nr == 0) ? 20 : 12; break; case S6E2CXA: num_sectors = 20; break; default: return ERROR_FLASH_OPER_UNSUPPORTED; } num_extra_sectors = (fm4_bank->macro_nr == 0) ? 1 : 4; bank->num_sectors = num_sectors + num_extra_sectors; LOG_DEBUG("%u sectors", bank->num_sectors); bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); for (i = 0; i < num_sectors; i++) { int sa = 4 + i; bank->sectors[i].offset = flash_addr - bank->base; s6e2cc_init_sector(&bank->sectors[i], sa); bank->size += bank->sectors[i].size; flash_addr += bank->sectors[i].size; } flash_addr = (fm4_bank->macro_nr == 0) ? 0x00406000 : 0x00408000; for (; i < bank->num_sectors; i++) { int sa = 4 - num_extra_sectors + (i - num_sectors); bank->sectors[i].offset = flash_addr - bank->base; s6e2cc_init_sector(&bank->sectors[i], sa); /* * Don't increase bank->size for these sectors * to avoid an overlap between Flash Macros #0 and #1. */ flash_addr += bank->sectors[i].size; } return ERROR_OK; } static int s6e2dh_probe(struct flash_bank *bank) { uint32_t flash_addr = bank->base; bank->num_sectors = 10; bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); for (unsigned int i = 0; i < bank->num_sectors; i++) { if (i < 4) bank->sectors[i].size = 8 * 1024; else if (i == 4) bank->sectors[i].size = 32 * 1024; else bank->sectors[i].size = 64 * 1024; bank->sectors[i].offset = flash_addr - bank->base; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; bank->size += bank->sectors[i].size; flash_addr += bank->sectors[i].size; } return ERROR_OK; } static int fm4_probe(struct flash_bank *bank) { struct fm4_flash_bank *fm4_bank = bank->driver_priv; int retval; if (fm4_bank->probed) return ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } switch (fm4_bank->variant) { case MB9BFX64: case MB9BFX65: case MB9BFX66: case MB9BFX67: case MB9BFX68: retval = mb9bf_probe(bank); break; case S6E2CX8: case S6E2CX9: case S6E2CXA: retval = s6e2cc_probe(bank); break; case S6E2DX: retval = s6e2dh_probe(bank); break; default: return ERROR_FLASH_OPER_UNSUPPORTED; } if (retval != ERROR_OK) return retval; fm4_bank->probed = true; return ERROR_OK; } static int fm4_auto_probe(struct flash_bank *bank) { struct fm4_flash_bank *fm4_bank = bank->driver_priv; if (fm4_bank->probed) return ERROR_OK; return fm4_probe(bank); } static int fm4_get_info_command(struct flash_bank *bank, struct command_invocation *cmd) { struct fm4_flash_bank *fm4_bank = bank->driver_priv; const char *name; if (bank->target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } switch (fm4_bank->variant) { case MB9BFX64: name = "MB9BFx64"; break; case MB9BFX65: name = "MB9BFx65"; break; case MB9BFX66: name = "MB9BFx66"; break; case MB9BFX67: name = "MB9BFx67"; break; case MB9BFX68: name = "MB9BFx68"; break; case S6E2CX8: name = "S6E2Cx8"; break; case S6E2CX9: name = "S6E2Cx9"; break; case S6E2CXA: name = "S6E2CxA"; break; case S6E2DX: name = "S6E2Dx"; break; default: name = "unknown"; break; } switch (fm4_bank->variant) { case S6E2CX8: case S6E2CX9: case S6E2CXA: command_print_sameline(cmd, "%s MainFlash Macro #%i", name, fm4_bank->macro_nr); break; default: command_print_sameline(cmd, "%s MainFlash", name); break; } return ERROR_OK; } static bool fm4_name_match(const char *s, const char *pattern) { int i = 0; while (s[i]) { /* If the match string is shorter, ignore excess */ if (!pattern[i]) return true; /* Use x as wildcard */ if (pattern[i] != 'x' && tolower(s[i]) != tolower(pattern[i])) return false; i++; } return true; } static int mb9bf_bank_setup(struct flash_bank *bank, const char *variant) { struct fm4_flash_bank *fm4_bank = bank->driver_priv; if (fm4_name_match(variant, "MB9BFx64")) { fm4_bank->variant = MB9BFX64; } else if (fm4_name_match(variant, "MB9BFx65")) { fm4_bank->variant = MB9BFX65; } else if (fm4_name_match(variant, "MB9BFx66")) { fm4_bank->variant = MB9BFX66; } else if (fm4_name_match(variant, "MB9BFx67")) { fm4_bank->variant = MB9BFX67; } else if (fm4_name_match(variant, "MB9BFx68")) { fm4_bank->variant = MB9BFX68; } else { LOG_WARNING("MB9BF variant %s not recognized.", variant); return ERROR_FLASH_OPER_UNSUPPORTED; } return ERROR_OK; } static int s6e2cc_bank_setup(struct flash_bank *bank, const char *variant) { struct fm4_flash_bank *fm4_bank = bank->driver_priv; if (fm4_name_match(variant, "S6E2Cx8")) { fm4_bank->variant = S6E2CX8; } else if (fm4_name_match(variant, "S6E2Cx9")) { fm4_bank->variant = S6E2CX9; } else if (fm4_name_match(variant, "S6E2CxA")) { fm4_bank->variant = S6E2CXA; } else { LOG_WARNING("S6E2CC variant %s not recognized.", variant); return ERROR_FLASH_OPER_UNSUPPORTED; } return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(fm4_flash_bank_command) { struct fm4_flash_bank *fm4_bank; const char *variant; int ret; if (CMD_ARGC < 7) return ERROR_COMMAND_SYNTAX_ERROR; variant = CMD_ARGV[6]; fm4_bank = malloc(sizeof(struct fm4_flash_bank)); if (!fm4_bank) return ERROR_FLASH_OPERATION_FAILED; fm4_bank->probed = false; fm4_bank->macro_nr = (bank->base == 0x00000000) ? 0 : 1; bank->driver_priv = fm4_bank; if (fm4_name_match(variant, "MB9BF")) ret = mb9bf_bank_setup(bank, variant); else if (fm4_name_match(variant, "S6E2Cx")) ret = s6e2cc_bank_setup(bank, variant); else if (fm4_name_match(variant, "S6E2Dx")) { fm4_bank->variant = S6E2DX; ret = ERROR_OK; } else { LOG_WARNING("Family %s not recognized.", variant); ret = ERROR_FLASH_OPER_UNSUPPORTED; } if (ret != ERROR_OK) free(fm4_bank); return ret; } const struct flash_driver fm4_flash = { .name = "fm4", .flash_bank_command = fm4_flash_bank_command, .info = fm4_get_info_command, .probe = fm4_probe, .auto_probe = fm4_auto_probe, .read = default_flash_read, .erase = fm4_flash_erase, .erase_check = default_flash_blank_check, .write = fm4_flash_write, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/imp.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_IMP_H #define OPENOCD_FLASH_NOR_IMP_H #include <stdbool.h> /* this is an internal header */ #include "core.h" #include "driver.h" /* almost all drivers will need this file */ #include <target/target.h> /** * Adds a new NOR bank to the global list of banks. * @param bank The bank that should be added. */ void flash_bank_add(struct flash_bank *bank); /** * @return The first bank in the global list. */ struct flash_bank *flash_bank_list(void); int flash_driver_erase(struct flash_bank *bank, unsigned int first, unsigned int last); int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last); int flash_driver_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count); int flash_driver_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); int flash_driver_verify(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count); /* write (optional verify) an image to flash memory of the given target */ int flash_write_unlock_verify(struct target *target, struct image *image, uint32_t *written, bool erase, bool unlock, bool write, bool verify); #endif /* OPENOCD_FLASH_NOR_IMP_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/jtagspi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2015 Robert Jordens <jordens@gmail.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <jtag/jtag.h> #include <flash/nor/spi.h> #include <helper/time_support.h> #define JTAGSPI_MAX_TIMEOUT 3000 struct jtagspi_flash_bank { struct jtag_tap *tap; struct flash_device dev; char devname[32]; bool probed; bool always_4byte; /* use always 4-byte address except for basic read 0x03 */ uint32_t ir; unsigned int addr_len; /* address length in bytes */ }; FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command) { struct jtagspi_flash_bank *info; if (CMD_ARGC < 7) return ERROR_COMMAND_SYNTAX_ERROR; info = malloc(sizeof(struct jtagspi_flash_bank)); if (!info) { LOG_ERROR("no memory for flash bank info"); return ERROR_FAIL; } bank->sectors = NULL; bank->driver_priv = info; if (!bank->target->tap) { LOG_ERROR("Target has no JTAG tap"); return ERROR_FAIL; } info->tap = bank->target->tap; info->probed = false; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->ir); return ERROR_OK; } static void jtagspi_set_ir(struct flash_bank *bank) { struct jtagspi_flash_bank *info = bank->driver_priv; struct scan_field field; uint8_t buf[4] = { 0 }; LOG_DEBUG("loading jtagspi ir"); buf_set_u32(buf, 0, info->tap->ir_length, info->ir); field.num_bits = info->tap->ir_length; field.out_value = buf; field.in_value = NULL; jtag_add_ir_scan(info->tap, &field, TAP_IDLE); } static void flip_u8(const uint8_t *in, uint8_t *out, unsigned int len) { for (unsigned int i = 0; i < len; i++) out[i] = flip_u32(in[i], 8); } static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd, uint8_t *write_buffer, unsigned int write_len, uint8_t *data_buffer, int data_len) { assert(write_buffer || write_len == 0); assert(data_buffer || data_len == 0); struct scan_field fields[6]; LOG_DEBUG("cmd=0x%02x write_len=%d data_len=%d", cmd, write_len, data_len); /* negative data_len == read operation */ const bool is_read = (data_len < 0); if (is_read) data_len = -data_len; int n = 0; const uint8_t marker = 1; fields[n].num_bits = 1; fields[n].out_value = ▮ fields[n].in_value = NULL; n++; /* transfer length = cmd + address + read/write, * -1 due to the counter implementation */ uint8_t xfer_bits[4]; h_u32_to_be(xfer_bits, ((sizeof(cmd) + write_len + data_len) * CHAR_BIT) - 1); flip_u8(xfer_bits, xfer_bits, sizeof(xfer_bits)); fields[n].num_bits = sizeof(xfer_bits) * CHAR_BIT; fields[n].out_value = xfer_bits; fields[n].in_value = NULL; n++; flip_u8(&cmd, &cmd, sizeof(cmd)); fields[n].num_bits = sizeof(cmd) * CHAR_BIT; fields[n].out_value = &cmd; fields[n].in_value = NULL; n++; if (write_len) { flip_u8(write_buffer, write_buffer, write_len); fields[n].num_bits = write_len * CHAR_BIT; fields[n].out_value = write_buffer; fields[n].in_value = NULL; n++; } if (data_len > 0) { if (is_read) { fields[n].num_bits = jtag_tap_count_enabled(); fields[n].out_value = NULL; fields[n].in_value = NULL; n++; fields[n].out_value = NULL; fields[n].in_value = data_buffer; } else { flip_u8(data_buffer, data_buffer, data_len); fields[n].out_value = data_buffer; fields[n].in_value = NULL; } fields[n].num_bits = data_len * CHAR_BIT; n++; } jtagspi_set_ir(bank); /* passing from an IR scan to SHIFT-DR clears BYPASS registers */ struct jtagspi_flash_bank *info = bank->driver_priv; jtag_add_dr_scan(info->tap, n, fields, TAP_IDLE); int retval = jtag_execute_queue(); if (is_read) flip_u8(data_buffer, data_buffer, data_len); return retval; } COMMAND_HANDLER(jtagspi_handle_set) { struct flash_bank *bank = NULL; struct jtagspi_flash_bank *info = NULL; struct flash_sector *sectors = NULL; uint32_t temp; unsigned int index = 1; int retval; LOG_DEBUG("%s", __func__); /* there are 6 mandatory arguments: * devname, size_in_bytes, pagesize, read_cmd, unused, pprog_cmd */ if (index + 6 > CMD_ARGC) { command_print(CMD, "jtagspi: not enough arguments"); return ERROR_COMMAND_SYNTAX_ERROR; } /* calling flash_command_get_bank without probing because handle_set is used to set device parameters if not autodetected. So probing would fail anyhow. */ retval = CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional, 0, &bank, false); if (ERROR_OK != retval) return retval; info = bank->driver_priv; /* invalidate all old info */ if (info->probed) { bank->size = 0; bank->num_sectors = 0; if (bank->sectors) free(bank->sectors); bank->sectors = NULL; info->always_4byte = false; info->probed = false; } memset(&info->dev, 0, sizeof(info->dev)); strncpy(info->devname, CMD_ARGV[index++], sizeof(info->devname) - 1); info->devname[sizeof(info->devname) - 1] = '\0'; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], temp); info->dev.size_in_bytes = temp; if ((temp & (temp - 1)) || (temp < (1UL << 8))) { command_print(CMD, "jtagspi: device size must be 2^n with n >= 8"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], temp); info->dev.pagesize = temp; if (info->dev.pagesize == 0) info->dev.pagesize = SPIFLASH_DEF_PAGESIZE; if ((temp & (temp - 1)) || (temp > info->dev.size_in_bytes)) { command_print(CMD, "jtagspi: page size must be 2^n and <= device size"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.read_cmd); if ((info->dev.read_cmd != 0x03) && (info->dev.read_cmd != 0x13)) { command_print(CMD, "jtagspi: only 0x03/0x13 READ allowed"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.qread_cmd); COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.pprog_cmd); if ((info->dev.pprog_cmd != 0x02) && (info->dev.pprog_cmd != 0x12)) { command_print(CMD, "jtagspi: only 0x02/0x12 PPRG allowed"); return ERROR_COMMAND_SYNTAX_ERROR; } /* remaining params are optional */ if (index < CMD_ARGC) COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.chip_erase_cmd); else info->dev.chip_erase_cmd = 0x00; if (index < CMD_ARGC) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], temp); info->dev.sectorsize = temp; if ((info->dev.sectorsize > info->dev.size_in_bytes) || (info->dev.sectorsize < info->dev.pagesize) || (temp & (temp - 1))) { command_print(CMD, "jtagspi: sector size must be 2^n and <= device size"); return ERROR_COMMAND_SYNTAX_ERROR; } if (index < CMD_ARGC) COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.erase_cmd); else { command_print(CMD, "jtagspi: erase command missing"); return ERROR_COMMAND_SYNTAX_ERROR; } } else { /* no sector size / sector erase cmd given, treat whole bank as a single sector */ info->dev.erase_cmd = 0x00; info->dev.sectorsize = info->dev.size_in_bytes; } if (index < CMD_ARGC) { command_print(CMD, "jtagspi: extra arguments"); return ERROR_COMMAND_SYNTAX_ERROR; } /* set correct size value */ bank->size = info->dev.size_in_bytes; /* calculate address length in bytes */ if (bank->size <= (1UL << 8)) info->addr_len = 1; else if (bank->size <= (1UL << 16)) info->addr_len = 2; else if (bank->size <= (1UL << 24)) info->addr_len = 3; else { info->addr_len = 4; LOG_WARNING("4-byte addresses needed, might need extra command to enable"); } /* create and fill sectors array */ bank->num_sectors = info->dev.size_in_bytes / info->dev.sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); if (!sectors) { LOG_ERROR("Not enough memory"); return ERROR_FAIL; } for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { sectors[sector].offset = sector * (info->dev.sectorsize); sectors[sector].size = info->dev.sectorsize; sectors[sector].is_erased = -1; sectors[sector].is_protected = 0; } bank->sectors = sectors; info->dev.name = info->devname; if (info->dev.size_in_bytes / 4096) LOG_INFO("flash \'%s\' id = unknown\nflash size = %" PRIu32 " kbytes", info->dev.name, info->dev.size_in_bytes / 1024); else LOG_INFO("flash \'%s\' id = unknown\nflash size = %" PRIu32 " bytes", info->dev.name, info->dev.size_in_bytes); info->probed = true; return ERROR_OK; } COMMAND_HANDLER(jtagspi_handle_cmd) { struct flash_bank *bank; const unsigned int max = 20; uint8_t cmd_byte, num_read, write_buffer[max], read_buffer[1 << CHAR_BIT]; LOG_DEBUG("%s", __func__); if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; uint8_t num_write = CMD_ARGC - 3; if (num_write > max) { command_print(CMD, "at most %d bytes may be send", max); return ERROR_COMMAND_ARGUMENT_INVALID; } /* calling flash_command_get_bank without probing because we like to be able to send commands before auto-probing occurred. For example sending "release from power down" is needed before probing when flash is in power down mode. */ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional, 0, &bank, false); if (retval != ERROR_OK) return retval; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], num_read); COMMAND_PARSE_NUMBER(u8, CMD_ARGV[2], cmd_byte); for (unsigned int i = 0; i < num_write; i++) COMMAND_PARSE_NUMBER(u8, CMD_ARGV[i + 3], write_buffer[i]); /* process command */ retval = jtagspi_cmd(bank, cmd_byte, write_buffer, num_write, read_buffer, -num_read); if (retval != ERROR_OK) return retval; command_print_sameline(CMD, "spi: %02" PRIx8, cmd_byte); for (unsigned int i = 0; i < num_write; i++) command_print_sameline(CMD, " %02" PRIx8, write_buffer[i]); command_print_sameline(CMD, " ->"); for (unsigned int i = 0; i < num_read; i++) command_print_sameline(CMD, " %02" PRIx8, read_buffer[i]); return ERROR_OK; } COMMAND_HANDLER(jtagspi_handle_always_4byte) { struct flash_bank *bank; struct jtagspi_flash_bank *jtagspi_info; int retval; LOG_DEBUG("%s", __func__); if ((CMD_ARGC != 1) && (CMD_ARGC != 2)) return ERROR_COMMAND_SYNTAX_ERROR; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; jtagspi_info = bank->driver_priv; if (CMD_ARGC == 1) command_print(CMD, jtagspi_info->always_4byte ? "on" : "off"); else COMMAND_PARSE_BOOL(CMD_ARGV[1], jtagspi_info->always_4byte, "on", "off"); return ERROR_OK; } static int jtagspi_probe(struct flash_bank *bank) { struct jtagspi_flash_bank *info = bank->driver_priv; struct flash_sector *sectors; const struct flash_device *p; uint8_t in_buf[3]; uint32_t id, sectorsize; if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } info->probed = false; jtagspi_cmd(bank, SPIFLASH_READ_ID, NULL, 0, in_buf, -3); /* the table in spi.c has the manufacturer byte (first) as the lsb */ id = le_to_h_u24(in_buf); memset(&info->dev, 0, sizeof(info->dev)); for (p = flash_devices; p->name ; p++) if (p->device_id == id) { memcpy(&info->dev, p, sizeof(info->dev)); break; } if (!(p->name)) { LOG_ERROR("Unknown flash device (ID 0x%06" PRIx32 ")", id & 0xFFFFFF); return ERROR_FAIL; } LOG_INFO("Found flash device \'%s\' (ID 0x%06" PRIx32 ")", info->dev.name, info->dev.device_id & 0xFFFFFF); /* Set correct size value */ bank->size = info->dev.size_in_bytes; /* calculate address length in bytes */ if (bank->size <= (1UL << 8)) info->addr_len = 1; else if (bank->size <= (1UL << 16)) info->addr_len = 2; else if (bank->size <= (1UL << 24)) info->addr_len = 3; else { info->addr_len = 4; LOG_WARNING("4-byte addresses needed, might need extra command to enable"); } /* if no sectors, treat whole bank as single sector */ sectorsize = info->dev.sectorsize ? info->dev.sectorsize : info->dev.size_in_bytes; /* create and fill sectors array */ bank->num_sectors = info->dev.size_in_bytes / sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); if (!sectors) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { sectors[sector].offset = sector * sectorsize; sectors[sector].size = sectorsize; sectors[sector].is_erased = -1; sectors[sector].is_protected = 0; } bank->sectors = sectors; info->probed = true; return ERROR_OK; } static int jtagspi_auto_probe(struct flash_bank *bank) { struct jtagspi_flash_bank *info = bank->driver_priv; if (info->probed) return ERROR_OK; return jtagspi_probe(bank); } static int jtagspi_read_status(struct flash_bank *bank, uint32_t *status) { uint8_t buf; int err = jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, 0, &buf, -1); if (err == ERROR_OK) { *status = buf; LOG_DEBUG("status=0x%02" PRIx32, *status); } return err; } static int jtagspi_wait(struct flash_bank *bank, int timeout_ms) { int64_t t0 = timeval_ms(); int64_t dt; do { dt = timeval_ms() - t0; uint32_t status = (uint32_t)-1; int retval = jtagspi_read_status(bank, &status); if (retval != ERROR_OK) return retval; if ((status & SPIFLASH_BSY_BIT) == 0) { LOG_DEBUG("waited %" PRId64 " ms", dt); return ERROR_OK; } alive_sleep(1); } while (dt <= timeout_ms); LOG_ERROR("timeout, device still busy"); return ERROR_FAIL; } static int jtagspi_write_enable(struct flash_bank *bank) { jtagspi_cmd(bank, SPIFLASH_WRITE_ENABLE, NULL, 0, NULL, 0); uint32_t status = (uint32_t)-1; int retval = jtagspi_read_status(bank, &status); if (retval != ERROR_OK) return retval; if ((status & SPIFLASH_WE_BIT) == 0) { LOG_ERROR("Cannot enable write to flash. Status=0x%02" PRIx32, status); return ERROR_FAIL; } return ERROR_OK; } static int jtagspi_bulk_erase(struct flash_bank *bank) { struct jtagspi_flash_bank *info = bank->driver_priv; int retval; int64_t t0 = timeval_ms(); if (info->dev.chip_erase_cmd == 0x00) return ERROR_FLASH_OPER_UNSUPPORTED; retval = jtagspi_write_enable(bank); if (retval != ERROR_OK) return retval; retval = jtagspi_cmd(bank, info->dev.chip_erase_cmd, NULL, 0, NULL, 0); if (retval != ERROR_OK) return retval; retval = jtagspi_wait(bank, bank->num_sectors * JTAGSPI_MAX_TIMEOUT); LOG_INFO("took %" PRId64 " ms", timeval_ms() - t0); return retval; } static uint8_t *fill_addr(uint32_t addr, unsigned int addr_len, uint8_t *buffer) { for (buffer += addr_len; addr_len > 0; --addr_len) { *--buffer = addr; addr >>= 8; } return buffer; } static int jtagspi_sector_erase(struct flash_bank *bank, unsigned int sector) { struct jtagspi_flash_bank *info = bank->driver_priv; int retval; uint8_t addr[sizeof(uint32_t)]; int64_t t0 = timeval_ms(); retval = jtagspi_write_enable(bank); if (retval != ERROR_OK) return retval; /* ATXP032/064/128 use always 4-byte addresses except for 0x03 read */ unsigned int addr_len = info->always_4byte ? 4 : info->addr_len; retval = jtagspi_cmd(bank, info->dev.erase_cmd, fill_addr(bank->sectors[sector].offset, addr_len, addr), addr_len, NULL, 0); if (retval != ERROR_OK) return retval; retval = jtagspi_wait(bank, JTAGSPI_MAX_TIMEOUT); LOG_INFO("sector %u took %" PRId64 " ms", sector, timeval_ms() - t0); return retval; } static int jtagspi_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct jtagspi_flash_bank *info = bank->driver_priv; int retval = ERROR_OK; LOG_DEBUG("erase from sector %u to sector %u", first, last); if ((last < first) || (last >= bank->num_sectors)) { LOG_ERROR("Flash sector invalid"); return ERROR_FLASH_SECTOR_INVALID; } if (!(info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } for (unsigned int sector = first; sector <= last; sector++) { if (bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FAIL; } } if (first == 0 && last == (bank->num_sectors - 1) && info->dev.chip_erase_cmd != 0x00 && info->dev.chip_erase_cmd != info->dev.erase_cmd) { LOG_DEBUG("Trying bulk erase."); retval = jtagspi_bulk_erase(bank); if (retval == ERROR_OK) return retval; else LOG_WARNING("Bulk flash erase failed. Falling back to sector erase."); } if (info->dev.erase_cmd == 0x00) return ERROR_FLASH_OPER_UNSUPPORTED; for (unsigned int sector = first; sector <= last; sector++) { retval = jtagspi_sector_erase(bank, sector); if (retval != ERROR_OK) { LOG_ERROR("Sector erase failed."); break; } } return retval; } static int jtagspi_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { for (unsigned int sector = first; sector <= last; sector++) bank->sectors[sector].is_protected = set; return ERROR_OK; } static int jtagspi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct jtagspi_flash_bank *info = bank->driver_priv; uint32_t pagesize, currsize; uint8_t addr[sizeof(uint32_t)]; int retval; if (!(info->probed)) { LOG_ERROR("Flash bank not probed."); return ERROR_FLASH_BANK_NOT_PROBED; } /* if no sectorsize, use reasonable default */ pagesize = info->dev.sectorsize ? info->dev.sectorsize : info->dev.pagesize; if (pagesize == 0) pagesize = (info->dev.size_in_bytes <= SPIFLASH_DEF_PAGESIZE) ? info->dev.size_in_bytes : SPIFLASH_DEF_PAGESIZE; /* ATXP032/064/128 use always 4-byte addresses except for 0x03 read */ unsigned int addr_len = ((info->dev.read_cmd != 0x03) && info->always_4byte) ? 4 : info->addr_len; while (count > 0) { /* length up to end of current page */ currsize = ((offset + pagesize) & ~(pagesize - 1)) - offset; /* but no more than remaining size */ currsize = (count < currsize) ? count : currsize; retval = jtagspi_cmd(bank, info->dev.read_cmd, fill_addr(offset, addr_len, addr), addr_len, buffer, -currsize); if (retval != ERROR_OK) { LOG_ERROR("page read error"); return retval; } LOG_DEBUG("read page at 0x%08" PRIx32, offset); offset += currsize; buffer += currsize; count -= currsize; } return ERROR_OK; } static int jtagspi_page_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct jtagspi_flash_bank *info = bank->driver_priv; uint8_t addr[sizeof(uint32_t)]; int retval; retval = jtagspi_write_enable(bank); if (retval != ERROR_OK) return retval; /* ATXP032/064/128 use always 4-byte addresses except for 0x03 read */ unsigned int addr_len = ((info->dev.read_cmd != 0x03) && info->always_4byte) ? 4 : info->addr_len; retval = jtagspi_cmd(bank, info->dev.pprog_cmd, fill_addr(offset, addr_len, addr), addr_len, (uint8_t *) buffer, count); if (retval != ERROR_OK) return retval; return jtagspi_wait(bank, JTAGSPI_MAX_TIMEOUT); } static int jtagspi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct jtagspi_flash_bank *info = bank->driver_priv; uint32_t pagesize, currsize; int retval; if (!(info->probed)) { LOG_ERROR("Flash bank not probed."); return ERROR_FLASH_BANK_NOT_PROBED; } /* if no write pagesize, use reasonable default */ pagesize = info->dev.pagesize ? info->dev.pagesize : SPIFLASH_DEF_PAGESIZE; while (count > 0) { /* length up to end of current page */ currsize = ((offset + pagesize) & ~(pagesize - 1)) - offset; /* but no more than remaining size */ currsize = (count < currsize) ? count : currsize; retval = jtagspi_page_write(bank, buffer, offset, currsize); if (retval != ERROR_OK) { LOG_ERROR("page write error"); return retval; } LOG_DEBUG("wrote page at 0x%08" PRIx32, offset); offset += currsize; buffer += currsize; count -= currsize; } return ERROR_OK; } static int jtagspi_info(struct flash_bank *bank, struct command_invocation *cmd) { struct jtagspi_flash_bank *info = bank->driver_priv; if (!(info->probed)) { command_print_sameline(cmd, "\nJTAGSPI flash bank not probed yet\n"); return ERROR_OK; } command_print_sameline(cmd, "flash \'%s\', device id = 0x%06" PRIx32 ", flash size = %" PRIu32 " %sbytes\n(page size = %" PRIu32 ", read = 0x%02" PRIx8 ", qread = 0x%02" PRIx8 ", pprog = 0x%02" PRIx8 ", mass_erase = 0x%02" PRIx8 ", sector size = %" PRIu32 " %sbytes, sector_erase = 0x%02" PRIx8 ")", info->dev.name, info->dev.device_id & 0xFFFFFF, bank->size / 4096 ? bank->size / 1024 : bank->size, bank->size / 4096 ? "k" : "", info->dev.pagesize, info->dev.read_cmd, info->dev.qread_cmd, info->dev.pprog_cmd, info->dev.chip_erase_cmd, info->dev.sectorsize / 4096 ? info->dev.sectorsize / 1024 : info->dev.sectorsize, info->dev.sectorsize / 4096 ? "k" : "", info->dev.erase_cmd); return ERROR_OK; } static const struct command_registration jtagspi_exec_command_handlers[] = { { .name = "set", .handler = jtagspi_handle_set, .mode = COMMAND_EXEC, .usage = "bank_id name chip_size page_size read_cmd unused pprg_cmd " "[ mass_erase_cmd ] [ sector_size sector_erase_cmd ]", .help = "Set device parameters if not autodetected.", }, { .name = "cmd", .handler = jtagspi_handle_cmd, .mode = COMMAND_EXEC, .usage = "bank_id num_resp cmd_byte ...", .help = "Send low-level command cmd_byte and following bytes, read num_bytes.", }, { .name = "always_4byte", .handler = jtagspi_handle_always_4byte, .mode = COMMAND_EXEC, .usage = "bank_id [ on | off ]", .help = "Use always 4-byte address except for basic 0x03.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration jtagspi_command_handlers[] = { { .name = "jtagspi", .mode = COMMAND_ANY, .help = "jtagspi command group", .usage = "", .chain = jtagspi_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver jtagspi_flash = { .name = "jtagspi", .commands = jtagspi_command_handlers, .flash_bank_command = jtagspi_flash_bank_command, .erase = jtagspi_erase, .protect = jtagspi_protect, .write = jtagspi_write, .read = jtagspi_read, .probe = jtagspi_probe, .auto_probe = jtagspi_auto_probe, .erase_check = default_flash_blank_check, .info = jtagspi_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/kinetis.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * kesmtp@freenet.de * * * * Copyright (C) 2011 sleep(5) ltd * * tomas@sleepfive.com * * * * Copyright (C) 2012 by Christopher D. Kilgour * * techie at whiterocker.com * * * * Copyright (C) 2013 Nemui Trinomius * * nemuisan_kawausogasuki@live.jp * * * * Copyright (C) 2015 Tomas Vanek * * vanekt@fbl.cz * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/interface.h" #include "imp.h" #include <helper/binarybuffer.h> #include <helper/time_support.h> #include <target/target_type.h> #include <target/algorithm.h> #include <target/arm_adi_v5.h> #include <target/armv7m.h> #include <target/cortex_m.h> /* * Implementation Notes * * The persistent memories in the Kinetis chip families K10 through * K70 are all manipulated with the Flash Memory Module. Some * variants call this module the FTFE, others call it the FTFL. To * indicate that both are considered here, we use FTFX. * * Within the module, according to the chip variant, the persistent * memory is divided into what Freescale terms Program Flash, FlexNVM, * and FlexRAM. All chip variants have Program Flash. Some chip * variants also have FlexNVM and FlexRAM, which always appear * together. * * A given Kinetis chip may have 1, 2 or 4 blocks of flash. Here we map * each block to a separate bank. Each block size varies by chip and * may be determined by the read-only SIM_FCFG1 register. The sector * size within each bank/block varies by chip, and may be 1, 2 or 4k. * The sector size may be different for flash and FlexNVM. * * The first half of the flash (1 or 2 blocks) is always Program Flash * and always starts at address 0x00000000. The "PFLSH" flag, bit 23 * of the read-only SIM_FCFG2 register, determines whether the second * half of the flash is also Program Flash or FlexNVM+FlexRAM. When * PFLSH is set, the second from the first half. When PFLSH is clear, * the second half of flash is FlexNVM and always starts at address * 0x10000000. FlexRAM, which is also present when PFLSH is clear, * always starts at address 0x14000000. * * The Flash Memory Module provides a register set where flash * commands are loaded to perform flash operations like erase and * program. Different commands are available depending on whether * Program Flash or FlexNVM/FlexRAM is being manipulated. Although * the commands used are quite consistent between flash blocks, the * parameters they accept differ according to the flash sector size. * */ /* Addresses */ #define FCF_ADDRESS 0x00000400 #define FCF_FPROT 0x8 #define FCF_FSEC 0xc #define FCF_FOPT 0xd #define FCF_FDPROT 0xf #define FCF_SIZE 0x10 #define FLEXRAM 0x14000000 #define MSCM_OCMDR0 0x40001400 #define FMC_PFB01CR 0x4001f004 #define FTFX_FSTAT 0x40020000 #define FTFX_FCNFG 0x40020001 #define FTFX_FCCOB3 0x40020004 #define FTFX_FPROT3 0x40020010 #define FTFX_FDPROT 0x40020017 #define SIM_BASE 0x40047000 #define SIM_BASE_KL28 0x40074000 #define SIM_COPC 0x40048100 /* SIM_COPC does not exist on devices with changed SIM_BASE */ #define WDOG_BASE 0x40052000 #define WDOG32_KE1X 0x40052000 #define WDOG32_KL28 0x40076000 #define SMC_PMCTRL 0x4007E001 #define SMC_PMSTAT 0x4007E003 #define SMC32_PMCTRL 0x4007E00C #define SMC32_PMSTAT 0x4007E014 #define PMC_REGSC 0x4007D002 #define MC_PMCTRL 0x4007E003 #define MCM_PLACR 0xF000300C /* Offsets */ #define SIM_SOPT1_OFFSET 0x0000 #define SIM_SDID_OFFSET 0x1024 #define SIM_FCFG1_OFFSET 0x104c #define SIM_FCFG2_OFFSET 0x1050 #define WDOG_STCTRLH_OFFSET 0 #define WDOG32_CS_OFFSET 0 /* Values */ #define PM_STAT_RUN 0x01 #define PM_STAT_VLPR 0x04 #define PM_CTRL_RUNM_RUN 0x00 /* Commands */ #define FTFX_CMD_BLOCKSTAT 0x00 #define FTFX_CMD_SECTSTAT 0x01 #define FTFX_CMD_LWORDPROG 0x06 #define FTFX_CMD_SECTERASE 0x09 #define FTFX_CMD_SECTWRITE 0x0b #define FTFX_CMD_MASSERASE 0x44 #define FTFX_CMD_PGMPART 0x80 #define FTFX_CMD_SETFLEXRAM 0x81 /* The older Kinetis K series uses the following SDID layout : * Bit 31-16 : 0 * Bit 15-12 : REVID * Bit 11-7 : DIEID * Bit 6-4 : FAMID * Bit 3-0 : PINID * * The newer Kinetis series uses the following SDID layout : * Bit 31-28 : FAMID * Bit 27-24 : SUBFAMID * Bit 23-20 : SERIESID * Bit 19-16 : SRAMSIZE * Bit 15-12 : REVID * Bit 6-4 : Reserved (0) * Bit 3-0 : PINID * * We assume that if bits 31-16 are 0 then it's an older * K-series MCU. */ #define KINETIS_SOPT1_RAMSIZE_MASK 0x0000F000 #define KINETIS_SOPT1_RAMSIZE_K24FN1M 0x0000B000 #define KINETIS_SDID_K_SERIES_MASK 0x0000FFFF #define KINETIS_SDID_DIEID_MASK 0x00000F80 #define KINETIS_SDID_DIEID_K22FN128 0x00000680 /* smaller pflash with FTFA */ #define KINETIS_SDID_DIEID_K22FN256 0x00000A80 #define KINETIS_SDID_DIEID_K22FN512 0x00000E80 #define KINETIS_SDID_DIEID_K24FN256 0x00000700 #define KINETIS_SDID_DIEID_K24FN1M 0x00000300 /* Detect Errata 7534 */ /* We can't rely solely on the FAMID field to determine the MCU * type since some FAMID values identify multiple MCUs with * different flash sector sizes (K20 and K22 for instance). * Therefore we combine it with the DIEID bits which may possibly * break if Freescale bumps the DIEID for a particular MCU. */ #define KINETIS_K_SDID_TYPE_MASK 0x00000FF0 #define KINETIS_K_SDID_K10_M50 0x00000000 #define KINETIS_K_SDID_K10_M72 0x00000080 #define KINETIS_K_SDID_K10_M100 0x00000100 #define KINETIS_K_SDID_K10_M120 0x00000180 #define KINETIS_K_SDID_K11 0x00000220 #define KINETIS_K_SDID_K12 0x00000200 #define KINETIS_K_SDID_K20_M50 0x00000010 #define KINETIS_K_SDID_K20_M72 0x00000090 #define KINETIS_K_SDID_K20_M100 0x00000110 #define KINETIS_K_SDID_K20_M120 0x00000190 #define KINETIS_K_SDID_K21_M50 0x00000230 #define KINETIS_K_SDID_K21_M120 0x00000330 #define KINETIS_K_SDID_K22_M50 0x00000210 #define KINETIS_K_SDID_K22_M120 0x00000310 #define KINETIS_K_SDID_K30_M72 0x000000A0 #define KINETIS_K_SDID_K30_M100 0x00000120 #define KINETIS_K_SDID_K40_M72 0x000000B0 #define KINETIS_K_SDID_K40_M100 0x00000130 #define KINETIS_K_SDID_K50_M72 0x000000E0 #define KINETIS_K_SDID_K51_M72 0x000000F0 #define KINETIS_K_SDID_K53 0x00000170 #define KINETIS_K_SDID_K60_M100 0x00000140 #define KINETIS_K_SDID_K60_M150 0x000001C0 #define KINETIS_K_SDID_K70_M150 0x000001D0 #define KINETIS_K_REVID_MASK 0x0000F000 #define KINETIS_K_REVID_SHIFT 12 #define KINETIS_SDID_SERIESID_MASK 0x00F00000 #define KINETIS_SDID_SERIESID_K 0x00000000 #define KINETIS_SDID_SERIESID_KL 0x00100000 #define KINETIS_SDID_SERIESID_KE 0x00200000 #define KINETIS_SDID_SERIESID_KW 0x00500000 #define KINETIS_SDID_SERIESID_KV 0x00600000 #define KINETIS_SDID_SUBFAMID_SHIFT 24 #define KINETIS_SDID_SUBFAMID_MASK 0x0F000000 #define KINETIS_SDID_SUBFAMID_KX0 0x00000000 #define KINETIS_SDID_SUBFAMID_KX1 0x01000000 #define KINETIS_SDID_SUBFAMID_KX2 0x02000000 #define KINETIS_SDID_SUBFAMID_KX3 0x03000000 #define KINETIS_SDID_SUBFAMID_KX4 0x04000000 #define KINETIS_SDID_SUBFAMID_KX5 0x05000000 #define KINETIS_SDID_SUBFAMID_KX6 0x06000000 #define KINETIS_SDID_SUBFAMID_KX7 0x07000000 #define KINETIS_SDID_SUBFAMID_KX8 0x08000000 #define KINETIS_SDID_FAMILYID_SHIFT 28 #define KINETIS_SDID_FAMILYID_MASK 0xF0000000 #define KINETIS_SDID_FAMILYID_K0X 0x00000000 #define KINETIS_SDID_FAMILYID_K1X 0x10000000 #define KINETIS_SDID_FAMILYID_K2X 0x20000000 #define KINETIS_SDID_FAMILYID_K3X 0x30000000 #define KINETIS_SDID_FAMILYID_K4X 0x40000000 #define KINETIS_SDID_FAMILYID_K5X 0x50000000 #define KINETIS_SDID_FAMILYID_K6X 0x60000000 #define KINETIS_SDID_FAMILYID_K7X 0x70000000 #define KINETIS_SDID_FAMILYID_K8X 0x80000000 #define KINETIS_SDID_FAMILYID_KL8X 0x90000000 /* The field originally named DIEID has new name/meaning on KE1x */ #define KINETIS_SDID_PROJECTID_MASK KINETIS_SDID_DIEID_MASK #define KINETIS_SDID_PROJECTID_KE1XF 0x00000080 #define KINETIS_SDID_PROJECTID_KE1XZ 0x00000100 struct kinetis_flash_bank { struct kinetis_chip *k_chip; bool probed; unsigned bank_number; /* bank number in particular chip */ struct flash_bank *bank; uint32_t sector_size; uint32_t protection_size; uint32_t prog_base; /* base address for FTFx operations */ /* usually same as bank->base for pflash, differs for FlexNVM */ uint32_t protection_block; /* number of first protection block in this bank */ enum { FC_AUTO = 0, FC_PFLASH, FC_FLEX_NVM, FC_FLEX_RAM, } flash_class; }; #define KINETIS_MAX_BANKS 4u struct kinetis_chip { struct target *target; bool probed; uint32_t sim_sdid; uint32_t sim_fcfg1; uint32_t sim_fcfg2; uint32_t fcfg2_maxaddr0_shifted; uint32_t fcfg2_maxaddr1_shifted; unsigned num_pflash_blocks, num_nvm_blocks; unsigned pflash_sector_size, nvm_sector_size; unsigned max_flash_prog_size; uint32_t pflash_base; uint32_t pflash_size; uint32_t nvm_base; uint32_t nvm_size; /* whole FlexNVM */ uint32_t dflash_size; /* accessible rest of FlexNVM if EEPROM backup uses part of FlexNVM */ uint32_t progr_accel_ram; uint32_t sim_base; enum { FS_PROGRAM_SECTOR = 1, FS_PROGRAM_LONGWORD = 2, FS_PROGRAM_PHRASE = 4, /* Unsupported */ FS_NO_CMD_BLOCKSTAT = 0x40, FS_WIDTH_256BIT = 0x80, FS_ECC = 0x100, } flash_support; enum { KINETIS_CACHE_NONE, KINETIS_CACHE_K, /* invalidate using FMC->PFB0CR/PFB01CR */ KINETIS_CACHE_L, /* invalidate using MCM->PLACR */ KINETIS_CACHE_MSCM, /* devices like KE1xF, invalidate MSCM->OCMDR0 */ } cache_type; enum { KINETIS_WDOG_NONE, KINETIS_WDOG_K, KINETIS_WDOG_COP, KINETIS_WDOG32_KE1X, KINETIS_WDOG32_KL28, } watchdog_type; enum { KINETIS_SMC, KINETIS_SMC32, KINETIS_MC, } sysmodectrlr_type; char name[40]; unsigned num_banks; struct kinetis_flash_bank banks[KINETIS_MAX_BANKS]; }; struct kinetis_type { uint32_t sdid; char *name; }; static const struct kinetis_type kinetis_types_old[] = { { KINETIS_K_SDID_K10_M50, "MK10D%s5" }, { KINETIS_K_SDID_K10_M72, "MK10D%s7" }, { KINETIS_K_SDID_K10_M100, "MK10D%s10" }, { KINETIS_K_SDID_K10_M120, "MK10F%s12" }, { KINETIS_K_SDID_K11, "MK11D%s5" }, { KINETIS_K_SDID_K12, "MK12D%s5" }, { KINETIS_K_SDID_K20_M50, "MK20D%s5" }, { KINETIS_K_SDID_K20_M72, "MK20D%s7" }, { KINETIS_K_SDID_K20_M100, "MK20D%s10" }, { KINETIS_K_SDID_K20_M120, "MK20F%s12" }, { KINETIS_K_SDID_K21_M50, "MK21D%s5" }, { KINETIS_K_SDID_K21_M120, "MK21F%s12" }, { KINETIS_K_SDID_K22_M50, "MK22D%s5" }, { KINETIS_K_SDID_K22_M120, "MK22F%s12" }, { KINETIS_K_SDID_K30_M72, "MK30D%s7" }, { KINETIS_K_SDID_K30_M100, "MK30D%s10" }, { KINETIS_K_SDID_K40_M72, "MK40D%s7" }, { KINETIS_K_SDID_K40_M100, "MK40D%s10" }, { KINETIS_K_SDID_K50_M72, "MK50D%s7" }, { KINETIS_K_SDID_K51_M72, "MK51D%s7" }, { KINETIS_K_SDID_K53, "MK53D%s10" }, { KINETIS_K_SDID_K60_M100, "MK60D%s10" }, { KINETIS_K_SDID_K60_M150, "MK60F%s15" }, { KINETIS_K_SDID_K70_M150, "MK70F%s15" }, }; #define MDM_AP 1 #define MDM_REG_STAT 0x00 #define MDM_REG_CTRL 0x04 #define MDM_REG_ID 0xfc #define MDM_STAT_FMEACK (1<<0) #define MDM_STAT_FREADY (1<<1) #define MDM_STAT_SYSSEC (1<<2) #define MDM_STAT_SYSRES (1<<3) #define MDM_STAT_FMEEN (1<<5) #define MDM_STAT_BACKDOOREN (1<<6) #define MDM_STAT_LPEN (1<<7) #define MDM_STAT_VLPEN (1<<8) #define MDM_STAT_LLSMODEXIT (1<<9) #define MDM_STAT_VLLSXMODEXIT (1<<10) #define MDM_STAT_CORE_HALTED (1<<16) #define MDM_STAT_CORE_SLEEPDEEP (1<<17) #define MDM_STAT_CORESLEEPING (1<<18) #define MDM_CTRL_FMEIP (1<<0) #define MDM_CTRL_DBG_DIS (1<<1) #define MDM_CTRL_DBG_REQ (1<<2) #define MDM_CTRL_SYS_RES_REQ (1<<3) #define MDM_CTRL_CORE_HOLD_RES (1<<4) #define MDM_CTRL_VLLSX_DBG_REQ (1<<5) #define MDM_CTRL_VLLSX_DBG_ACK (1<<6) #define MDM_CTRL_VLLSX_STAT_ACK (1<<7) #define MDM_ACCESS_TIMEOUT 500 /* msec */ static bool allow_fcf_writes; static uint8_t fcf_fopt = 0xff; static bool create_banks; const struct flash_driver kinetis_flash; static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count); static int kinetis_probe_chip(struct kinetis_chip *k_chip); static int kinetis_auto_probe(struct flash_bank *bank); static int kinetis_mdm_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value) { LOG_DEBUG("MDM_REG[0x%02x] <- %08" PRIX32, reg, value); struct adiv5_ap *ap = dap_get_ap(dap, MDM_AP); if (!ap) { LOG_DEBUG("MDM: failed to get AP"); return ERROR_FAIL; } int retval = dap_queue_ap_write(ap, reg, value); if (retval != ERROR_OK) { LOG_DEBUG("MDM: failed to queue a write request"); dap_put_ap(ap); return retval; } retval = dap_run(dap); dap_put_ap(ap); if (retval != ERROR_OK) { LOG_DEBUG("MDM: dap_run failed"); return retval; } return ERROR_OK; } static int kinetis_mdm_read_register(struct adiv5_dap *dap, unsigned reg, uint32_t *result) { struct adiv5_ap *ap = dap_get_ap(dap, MDM_AP); if (!ap) { LOG_DEBUG("MDM: failed to get AP"); return ERROR_FAIL; } int retval = dap_queue_ap_read(ap, reg, result); if (retval != ERROR_OK) { LOG_DEBUG("MDM: failed to queue a read request"); dap_put_ap(ap); return retval; } retval = dap_run(dap); dap_put_ap(ap); if (retval != ERROR_OK) { LOG_DEBUG("MDM: dap_run failed"); return retval; } LOG_DEBUG("MDM_REG[0x%02x]: %08" PRIX32, reg, *result); return ERROR_OK; } static int kinetis_mdm_poll_register(struct adiv5_dap *dap, unsigned reg, uint32_t mask, uint32_t value, uint32_t timeout_ms) { uint32_t val; int retval; int64_t ms_timeout = timeval_ms() + timeout_ms; do { retval = kinetis_mdm_read_register(dap, reg, &val); if (retval != ERROR_OK || (val & mask) == value) return retval; alive_sleep(1); } while (timeval_ms() < ms_timeout); LOG_DEBUG("MDM: polling timed out"); return ERROR_FAIL; } /* * This command can be used to break a watchdog reset loop when * connecting to an unsecured target. Unlike other commands, halt will * automatically retry as it does not know how far into the boot process * it is when the command is called. */ COMMAND_HANDLER(kinetis_mdm_halt) { struct target *target = get_current_target(CMD_CTX); struct cortex_m_common *cortex_m = target_to_cm(target); struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; int retval; int tries = 0; uint32_t stat; int64_t ms_timeout = timeval_ms() + MDM_ACCESS_TIMEOUT; if (!dap) { LOG_ERROR("Cannot perform halt with a high-level adapter"); return ERROR_FAIL; } while (true) { tries++; kinetis_mdm_write_register(dap, MDM_REG_CTRL, MDM_CTRL_CORE_HOLD_RES); alive_sleep(1); retval = kinetis_mdm_read_register(dap, MDM_REG_STAT, &stat); if (retval != ERROR_OK) { LOG_DEBUG("MDM: failed to read MDM_REG_STAT"); continue; } /* Repeat setting MDM_CTRL_CORE_HOLD_RES until system is out of * reset with flash ready and without security */ if ((stat & (MDM_STAT_FREADY | MDM_STAT_SYSSEC | MDM_STAT_SYSRES)) == (MDM_STAT_FREADY | MDM_STAT_SYSRES)) break; if (timeval_ms() >= ms_timeout) { LOG_ERROR("MDM: halt timed out"); return ERROR_FAIL; } } LOG_DEBUG("MDM: halt succeeded after %d attempts.", tries); target_poll(target); /* enable polling in case kinetis_check_flash_security_status disabled it */ jtag_poll_set_enabled(true); alive_sleep(100); target->reset_halt = true; target->type->assert_reset(target); retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, 0); if (retval != ERROR_OK) { LOG_ERROR("MDM: failed to clear MDM_REG_CTRL"); return retval; } target->type->deassert_reset(target); return ERROR_OK; } COMMAND_HANDLER(kinetis_mdm_reset) { struct target *target = get_current_target(CMD_CTX); struct cortex_m_common *cortex_m = target_to_cm(target); struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; int retval; if (!dap) { LOG_ERROR("Cannot perform reset with a high-level adapter"); return ERROR_FAIL; } retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, MDM_CTRL_SYS_RES_REQ); if (retval != ERROR_OK) { LOG_ERROR("MDM: failed to write MDM_REG_CTRL"); return retval; } retval = kinetis_mdm_poll_register(dap, MDM_REG_STAT, MDM_STAT_SYSRES, 0, 500); if (retval != ERROR_OK) { LOG_ERROR("MDM: failed to assert reset"); return retval; } retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, 0); if (retval != ERROR_OK) { LOG_ERROR("MDM: failed to clear MDM_REG_CTRL"); return retval; } return ERROR_OK; } /* * This function implements the procedure to mass erase the flash via * SWD/JTAG on Kinetis K and L series of devices as it is described in * AN4835 "Production Flash Programming Best Practices for Kinetis K- * and L-series MCUs" Section 4.2.1. To prevent a watchdog reset loop, * the core remains halted after this function completes as suggested * by the application note. */ COMMAND_HANDLER(kinetis_mdm_mass_erase) { struct target *target = get_current_target(CMD_CTX); struct cortex_m_common *cortex_m = target_to_cm(target); struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; if (!dap) { LOG_ERROR("Cannot perform mass erase with a high-level adapter"); return ERROR_FAIL; } int retval; /* * ... Power on the processor, or if power has already been * applied, assert the RESET pin to reset the processor. For * devices that do not have a RESET pin, write the System * Reset Request bit in the MDM-AP control register after * establishing communication... */ /* assert SRST if configured */ bool has_srst = jtag_get_reset_config() & RESET_HAS_SRST; if (has_srst) adapter_assert_reset(); retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, MDM_CTRL_SYS_RES_REQ); if (retval != ERROR_OK && !has_srst) { LOG_ERROR("MDM: failed to assert reset"); goto deassert_reset_and_exit; } /* * ... Read the MDM-AP status register repeatedly and wait for * stable conditions suitable for mass erase: * - mass erase is enabled * - flash is ready * - reset is finished * * Mass erase is started as soon as all conditions are met in 32 * subsequent status reads. * * In case of not stable conditions (RESET/WDOG loop in secured device) * the user is asked for manual pressing of RESET button * as a last resort. */ int cnt_mass_erase_disabled = 0; int cnt_ready = 0; int64_t ms_start = timeval_ms(); bool man_reset_requested = false; do { uint32_t stat = 0; int64_t ms_elapsed = timeval_ms() - ms_start; if (!man_reset_requested && ms_elapsed > 100) { LOG_INFO("MDM: Press RESET button now if possible."); man_reset_requested = true; } if (ms_elapsed > 3000) { LOG_ERROR("MDM: waiting for mass erase conditions timed out."); LOG_INFO("Mass erase of a secured MCU is not possible without hardware reset."); LOG_INFO("Connect SRST, use 'reset_config srst_only' and retry."); goto deassert_reset_and_exit; } retval = kinetis_mdm_read_register(dap, MDM_REG_STAT, &stat); if (retval != ERROR_OK) { cnt_ready = 0; continue; } if (!(stat & MDM_STAT_FMEEN)) { cnt_ready = 0; cnt_mass_erase_disabled++; if (cnt_mass_erase_disabled > 10) { LOG_ERROR("MDM: mass erase is disabled"); goto deassert_reset_and_exit; } continue; } if ((stat & (MDM_STAT_FREADY | MDM_STAT_SYSRES)) == MDM_STAT_FREADY) cnt_ready++; else cnt_ready = 0; } while (cnt_ready < 32); /* * ... Write the MDM-AP control register to set the Flash Mass * Erase in Progress bit. This will start the mass erase * process... */ retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, MDM_CTRL_SYS_RES_REQ | MDM_CTRL_FMEIP); if (retval != ERROR_OK) { LOG_ERROR("MDM: failed to start mass erase"); goto deassert_reset_and_exit; } /* * ... Read the MDM-AP control register until the Flash Mass * Erase in Progress bit clears... * Data sheed defines erase time <3.6 sec/512kB flash block. * The biggest device has 4 pflash blocks => timeout 16 sec. */ retval = kinetis_mdm_poll_register(dap, MDM_REG_CTRL, MDM_CTRL_FMEIP, 0, 16000); if (retval != ERROR_OK) { LOG_ERROR("MDM: mass erase timeout"); goto deassert_reset_and_exit; } target_poll(target); /* enable polling in case kinetis_check_flash_security_status disabled it */ jtag_poll_set_enabled(true); alive_sleep(100); target->reset_halt = true; target->type->assert_reset(target); /* * ... Negate the RESET signal or clear the System Reset Request * bit in the MDM-AP control register. */ retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, 0); if (retval != ERROR_OK) LOG_ERROR("MDM: failed to clear MDM_REG_CTRL"); target->type->deassert_reset(target); return retval; deassert_reset_and_exit: kinetis_mdm_write_register(dap, MDM_REG_CTRL, 0); if (has_srst) adapter_deassert_reset(); return retval; } static const uint32_t kinetis_known_mdm_ids[] = { 0x001C0000, /* Kinetis-K Series */ 0x001C0020, /* Kinetis-L/M/V/E Series */ 0x001C0030, /* Kinetis with a Cortex-M7, in time of writing KV58 */ }; /* * This function implements the procedure to connect to * SWD/JTAG on Kinetis K and L series of devices as it is described in * AN4835 "Production Flash Programming Best Practices for Kinetis K- * and L-series MCUs" Section 4.1.1 */ COMMAND_HANDLER(kinetis_check_flash_security_status) { struct target *target = get_current_target(CMD_CTX); struct cortex_m_common *cortex_m = target_to_cm(target); struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; if (!dap) { LOG_WARNING("Cannot check flash security status with a high-level adapter"); return ERROR_OK; } if (!dap->ops) return ERROR_OK; /* too early to check, in JTAG mode ops may not be initialised */ uint32_t val; int retval; /* * ... The MDM-AP ID register can be read to verify that the * connection is working correctly... */ retval = kinetis_mdm_read_register(dap, MDM_REG_ID, &val); if (retval != ERROR_OK) { LOG_ERROR("MDM: failed to read ID register"); return ERROR_OK; } if (val == 0) return ERROR_OK; /* dap not yet initialised */ bool found = false; for (size_t i = 0; i < ARRAY_SIZE(kinetis_known_mdm_ids); i++) { if (val == kinetis_known_mdm_ids[i]) { found = true; break; } } if (!found) LOG_WARNING("MDM: unknown ID %08" PRIX32, val); /* * ... Read the System Security bit to determine if security is enabled. * If System Security = 0, then proceed. If System Security = 1, then * communication with the internals of the processor, including the * flash, will not be possible without issuing a mass erase command or * unsecuring the part through other means (backdoor key unlock)... */ retval = kinetis_mdm_read_register(dap, MDM_REG_STAT, &val); if (retval != ERROR_OK) { LOG_ERROR("MDM: failed to read MDM_REG_STAT"); return ERROR_OK; } /* * System Security bit is also active for short time during reset. * If a MCU has blank flash and runs in RESET/WDOG loop, * System Security bit is active most of time! * We should observe Flash Ready bit and read status several times * to avoid false detection of secured MCU */ int secured_score = 0, flash_not_ready_score = 0; if ((val & (MDM_STAT_SYSSEC | MDM_STAT_FREADY)) != MDM_STAT_FREADY) { uint32_t stats[32]; struct adiv5_ap *ap = dap_get_ap(dap, MDM_AP); if (!ap) { LOG_ERROR("MDM: failed to get AP"); return ERROR_OK; } for (unsigned int i = 0; i < 32; i++) { stats[i] = MDM_STAT_FREADY; dap_queue_ap_read(ap, MDM_REG_STAT, &stats[i]); } retval = dap_run(dap); dap_put_ap(ap); if (retval != ERROR_OK) { LOG_DEBUG("MDM: dap_run failed when validating secured state"); return ERROR_OK; } for (unsigned int i = 0; i < 32; i++) { if (stats[i] & MDM_STAT_SYSSEC) secured_score++; if (!(stats[i] & MDM_STAT_FREADY)) flash_not_ready_score++; } } if (flash_not_ready_score <= 8 && secured_score > 24) { jtag_poll_set_enabled(false); LOG_WARNING("*********** ATTENTION! ATTENTION! ATTENTION! ATTENTION! **********"); LOG_WARNING("**** ****"); LOG_WARNING("**** Your Kinetis MCU is in secured state, which means that, ****"); LOG_WARNING("**** with exception for very basic communication, JTAG/SWD ****"); LOG_WARNING("**** interface will NOT work. In order to restore its ****"); LOG_WARNING("**** functionality please issue 'kinetis mdm mass_erase' ****"); LOG_WARNING("**** command, power cycle the MCU and restart OpenOCD. ****"); LOG_WARNING("**** ****"); LOG_WARNING("*********** ATTENTION! ATTENTION! ATTENTION! ATTENTION! **********"); } else if (flash_not_ready_score > 24) { jtag_poll_set_enabled(false); LOG_WARNING("**** Your Kinetis MCU is probably locked-up in RESET/WDOG loop. ****"); LOG_WARNING("**** Common reason is a blank flash (at least a reset vector). ****"); LOG_WARNING("**** Issue 'kinetis mdm halt' command or if SRST is connected ****"); LOG_WARNING("**** and configured, use 'reset halt' ****"); LOG_WARNING("**** If MCU cannot be halted, it is likely secured and running ****"); LOG_WARNING("**** in RESET/WDOG loop. Issue 'kinetis mdm mass_erase' ****"); } else { LOG_INFO("MDM: Chip is unsecured. Continuing."); jtag_poll_set_enabled(true); } return ERROR_OK; } static struct kinetis_chip *kinetis_get_chip(struct target *target) { struct flash_bank *bank_iter; struct kinetis_flash_bank *k_bank; /* iterate over all kinetis banks */ for (bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) { if (bank_iter->driver != &kinetis_flash || bank_iter->target != target) continue; k_bank = bank_iter->driver_priv; if (!k_bank) continue; if (k_bank->k_chip) return k_bank->k_chip; } return NULL; } static int kinetis_chip_options(struct kinetis_chip *k_chip, int argc, const char *argv[]) { for (int i = 0; i < argc; i++) { if (strcmp(argv[i], "-sim-base") == 0) { if (i + 1 < argc) k_chip->sim_base = strtoul(argv[++i], NULL, 0); } else LOG_ERROR("Unsupported flash bank option %s", argv[i]); } return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command) { struct target *target = bank->target; struct kinetis_chip *k_chip; struct kinetis_flash_bank *k_bank; int retval; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; LOG_INFO("add flash_bank kinetis %s", bank->name); k_chip = kinetis_get_chip(target); if (!k_chip) { k_chip = calloc(sizeof(struct kinetis_chip), 1); if (!k_chip) { LOG_ERROR("No memory"); return ERROR_FAIL; } k_chip->target = target; /* only the first defined bank can define chip options */ retval = kinetis_chip_options(k_chip, CMD_ARGC - 6, CMD_ARGV + 6); if (retval != ERROR_OK) return retval; } if (k_chip->num_banks >= KINETIS_MAX_BANKS) { LOG_ERROR("Only %u Kinetis flash banks are supported", KINETIS_MAX_BANKS); return ERROR_FAIL; } bank->driver_priv = k_bank = &(k_chip->banks[k_chip->num_banks]); k_bank->k_chip = k_chip; k_bank->bank_number = k_chip->num_banks; k_bank->bank = bank; k_chip->num_banks++; return ERROR_OK; } static void kinetis_free_driver_priv(struct flash_bank *bank) { struct kinetis_flash_bank *k_bank = bank->driver_priv; if (!k_bank) return; struct kinetis_chip *k_chip = k_bank->k_chip; if (!k_chip) return; k_chip->num_banks--; if (k_chip->num_banks == 0) free(k_chip); } static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) { unsigned num_blocks; struct kinetis_flash_bank *k_bank; struct flash_bank *bank; char base_name[69], name[87], num[11]; char *class, *p; num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks; if (num_blocks > KINETIS_MAX_BANKS) { LOG_ERROR("Only %u Kinetis flash banks are supported", KINETIS_MAX_BANKS); return ERROR_FAIL; } bank = k_chip->banks[0].bank; if (bank && bank->name) { strncpy(base_name, bank->name, sizeof(base_name) - 1); base_name[sizeof(base_name) - 1] = '\0'; p = strstr(base_name, ".pflash"); if (p) { *p = '\0'; if (k_chip->num_pflash_blocks > 1) { /* rename first bank if numbering is needed */ snprintf(name, sizeof(name), "%s.pflash0", base_name); free(bank->name); bank->name = strdup(name); } } } else { strncpy(base_name, target_name(k_chip->target), sizeof(base_name) - 1); base_name[sizeof(base_name) - 1] = '\0'; p = strstr(base_name, ".cpu"); if (p) *p = '\0'; } for (unsigned int bank_idx = 1; bank_idx < num_blocks; bank_idx++) { k_bank = &(k_chip->banks[bank_idx]); bank = k_bank->bank; if (bank) continue; num[0] = '\0'; if (bank_idx < k_chip->num_pflash_blocks) { class = "pflash"; if (k_chip->num_pflash_blocks > 1) snprintf(num, sizeof(num), "%u", bank_idx); } else { class = "flexnvm"; if (k_chip->num_nvm_blocks > 1) snprintf(num, sizeof(num), "%u", bank_idx - k_chip->num_pflash_blocks); } bank = calloc(sizeof(struct flash_bank), 1); if (!bank) return ERROR_FAIL; bank->target = k_chip->target; bank->driver = &kinetis_flash; bank->default_padded_value = bank->erased_value = 0xff; snprintf(name, sizeof(name), "%s.%s%s", base_name, class, num); bank->name = strdup(name); bank->driver_priv = k_bank = &(k_chip->banks[k_chip->num_banks]); k_bank->k_chip = k_chip; k_bank->bank_number = bank_idx; k_bank->bank = bank; if (k_chip->num_banks <= bank_idx) k_chip->num_banks = bank_idx + 1; flash_bank_add(bank); } return ERROR_OK; } static int kinetis_disable_wdog_algo(struct target *target, size_t code_size, const uint8_t *code, uint32_t wdog_base) { struct working_area *wdog_algorithm; struct armv7m_algorithm armv7m_info; struct reg_param reg_params[1]; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = target_alloc_working_area(target, code_size, &wdog_algorithm); if (retval != ERROR_OK) return retval; retval = target_write_buffer(target, wdog_algorithm->address, code_size, code); if (retval == ERROR_OK) { armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, wdog_base); retval = target_run_algorithm(target, 0, NULL, 1, reg_params, wdog_algorithm->address, wdog_algorithm->address + code_size - 2, 500, &armv7m_info); destroy_reg_param(®_params[0]); if (retval != ERROR_OK) LOG_ERROR("Error executing Kinetis WDOG unlock algorithm"); } target_free_working_area(target, wdog_algorithm); return retval; } /* Disable the watchdog on Kinetis devices * Standard Kx WDOG peripheral checks timing and therefore requires to run algo. */ static int kinetis_disable_wdog_kx(struct target *target) { const uint32_t wdog_base = WDOG_BASE; uint16_t wdog; int retval; static const uint8_t kinetis_unlock_wdog_code[] = { #include "../../../contrib/loaders/watchdog/armv7m_kinetis_wdog.inc" }; retval = target_read_u16(target, wdog_base + WDOG_STCTRLH_OFFSET, &wdog); if (retval != ERROR_OK) return retval; if ((wdog & 0x1) == 0) { /* watchdog already disabled */ return ERROR_OK; } LOG_INFO("Disabling Kinetis watchdog (initial WDOG_STCTRLH = 0x%04" PRIx16 ")", wdog); retval = kinetis_disable_wdog_algo(target, sizeof(kinetis_unlock_wdog_code), kinetis_unlock_wdog_code, wdog_base); if (retval != ERROR_OK) return retval; retval = target_read_u16(target, wdog_base + WDOG_STCTRLH_OFFSET, &wdog); if (retval != ERROR_OK) return retval; LOG_INFO("WDOG_STCTRLH = 0x%04" PRIx16, wdog); return (wdog & 0x1) ? ERROR_FAIL : ERROR_OK; } static int kinetis_disable_wdog32(struct target *target, uint32_t wdog_base) { uint32_t wdog_cs; int retval; static const uint8_t kinetis_unlock_wdog_code[] = { #include "../../../contrib/loaders/watchdog/armv7m_kinetis_wdog32.inc" }; retval = target_read_u32(target, wdog_base + WDOG32_CS_OFFSET, &wdog_cs); if (retval != ERROR_OK) return retval; if ((wdog_cs & 0x80) == 0) return ERROR_OK; /* watchdog already disabled */ LOG_INFO("Disabling Kinetis watchdog (initial WDOG_CS 0x%08" PRIx32 ")", wdog_cs); retval = kinetis_disable_wdog_algo(target, sizeof(kinetis_unlock_wdog_code), kinetis_unlock_wdog_code, wdog_base); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, wdog_base + WDOG32_CS_OFFSET, &wdog_cs); if (retval != ERROR_OK) return retval; if ((wdog_cs & 0x80) == 0) return ERROR_OK; /* watchdog disabled successfully */ LOG_ERROR("Cannot disable Kinetis watchdog (WDOG_CS 0x%08" PRIx32 "), issue 'reset init'", wdog_cs); return ERROR_FAIL; } static int kinetis_disable_wdog(struct kinetis_chip *k_chip) { struct target *target = k_chip->target; uint8_t sim_copc; int retval; if (!k_chip->probed) { retval = kinetis_probe_chip(k_chip); if (retval != ERROR_OK) return retval; } switch (k_chip->watchdog_type) { case KINETIS_WDOG_K: return kinetis_disable_wdog_kx(target); case KINETIS_WDOG_COP: retval = target_read_u8(target, SIM_COPC, &sim_copc); if (retval != ERROR_OK) return retval; if ((sim_copc & 0xc) == 0) return ERROR_OK; /* watchdog already disabled */ LOG_INFO("Disabling Kinetis watchdog (initial SIM_COPC 0x%02" PRIx8 ")", sim_copc); retval = target_write_u8(target, SIM_COPC, sim_copc & ~0xc); if (retval != ERROR_OK) return retval; retval = target_read_u8(target, SIM_COPC, &sim_copc); if (retval != ERROR_OK) return retval; if ((sim_copc & 0xc) == 0) return ERROR_OK; /* watchdog disabled successfully */ LOG_ERROR("Cannot disable Kinetis watchdog (SIM_COPC 0x%02" PRIx8 "), issue 'reset init'", sim_copc); return ERROR_FAIL; case KINETIS_WDOG32_KE1X: return kinetis_disable_wdog32(target, WDOG32_KE1X); case KINETIS_WDOG32_KL28: return kinetis_disable_wdog32(target, WDOG32_KL28); default: return ERROR_OK; } } COMMAND_HANDLER(kinetis_disable_wdog_handler) { int result; struct target *target = get_current_target(CMD_CTX); struct kinetis_chip *k_chip = kinetis_get_chip(target); if (!k_chip) return ERROR_FAIL; if (CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; result = kinetis_disable_wdog(k_chip); return result; } static int kinetis_ftfx_decode_error(uint8_t fstat) { if (fstat & 0x20) { LOG_ERROR("Flash operation failed, illegal command"); return ERROR_FLASH_OPER_UNSUPPORTED; } else if (fstat & 0x10) LOG_ERROR("Flash operation failed, protection violated"); else if (fstat & 0x40) LOG_ERROR("Flash operation failed, read collision"); else if (fstat & 0x80) return ERROR_OK; else LOG_ERROR("Flash operation timed out"); return ERROR_FLASH_OPERATION_FAILED; } static int kinetis_ftfx_clear_error(struct target *target) { /* reset error flags */ return target_write_u8(target, FTFX_FSTAT, 0x70); } static int kinetis_ftfx_prepare(struct target *target) { int result; uint8_t fstat; /* wait until busy */ for (unsigned int i = 0; i < 50; i++) { result = target_read_u8(target, FTFX_FSTAT, &fstat); if (result != ERROR_OK) return result; if (fstat & 0x80) break; } if ((fstat & 0x80) == 0) { LOG_ERROR("Flash controller is busy"); return ERROR_FLASH_OPERATION_FAILED; } if (fstat != 0x80) { /* reset error flags */ result = kinetis_ftfx_clear_error(target); } return result; } /* Kinetis Program-LongWord Microcodes */ static const uint8_t kinetis_flash_write_code[] = { #include "../../../contrib/loaders/flash/kinetis/kinetis_flash.inc" }; /* Program LongWord Block Write */ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t wcount) { struct target *target = bank->target; uint32_t buffer_size; struct working_area *write_algorithm; struct working_area *source; struct kinetis_flash_bank *k_bank = bank->driver_priv; uint32_t address = k_bank->prog_base + offset; uint32_t end_address; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval; uint8_t fstat; /* allocate working area with flash programming code */ if (target_alloc_working_area(target, sizeof(kinetis_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(kinetis_flash_write_code), kinetis_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer, size *must* be multiple of word */ buffer_size = target_get_working_area_avail(target) & ~(sizeof(uint32_t) - 1); if (buffer_size < 256) { LOG_WARNING("large enough working area not available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } else if (buffer_size > 16384) { /* probably won't benefit from more than 16k ... */ buffer_size = 16384; } if (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { LOG_ERROR("allocating working area failed"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* address */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* word count */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, wcount); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[4].value, 0, 32, FTFX_FSTAT); retval = target_run_flash_async_algorithm(target, buffer, wcount, 4, 0, NULL, 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { end_address = buf_get_u32(reg_params[0].value, 0, 32); LOG_ERROR("Error writing flash at %08" PRIx32, end_address); retval = target_read_u8(target, FTFX_FSTAT, &fstat); if (retval == ERROR_OK) { retval = kinetis_ftfx_decode_error(fstat); /* reset error flags */ target_write_u8(target, FTFX_FSTAT, 0x70); } } else if (retval != ERROR_OK) LOG_ERROR("Error executing kinetis Flash programming algorithm"); target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; } static int kinetis_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { if (allow_fcf_writes) { LOG_ERROR("Protection setting is possible with 'kinetis fcf_source protection' only!"); return ERROR_FAIL; } if (!bank->prot_blocks || bank->num_prot_blocks == 0) { LOG_ERROR("No protection possible for current bank!"); return ERROR_FLASH_BANK_INVALID; } for (unsigned int i = first; i < bank->num_prot_blocks && i <= last; i++) bank->prot_blocks[i].is_protected = set; LOG_INFO("Protection bits will be written at the next FCF sector erase or write."); LOG_INFO("Do not issue 'flash info' command until protection is written,"); LOG_INFO("doing so would re-read protection status from MCU."); return ERROR_OK; } static int kinetis_protect_check(struct flash_bank *bank) { struct kinetis_flash_bank *k_bank = bank->driver_priv; int result; int b; uint32_t fprot; if (k_bank->flash_class == FC_PFLASH) { /* read protection register */ result = target_read_u32(bank->target, FTFX_FPROT3, &fprot); if (result != ERROR_OK) return result; /* Every bit protects 1/32 of the full flash (not necessarily just this bank) */ } else if (k_bank->flash_class == FC_FLEX_NVM) { uint8_t fdprot; /* read protection register */ result = target_read_u8(bank->target, FTFX_FDPROT, &fdprot); if (result != ERROR_OK) return result; fprot = fdprot; } else { LOG_ERROR("Protection checks for FlexRAM not supported"); return ERROR_FLASH_BANK_INVALID; } b = k_bank->protection_block; for (unsigned int i = 0; i < bank->num_prot_blocks; i++) { if ((fprot >> b) & 1) bank->prot_blocks[i].is_protected = 0; else bank->prot_blocks[i].is_protected = 1; b++; } return ERROR_OK; } static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) { uint32_t fprot = 0xffffffff; uint8_t fsec = 0xfe; /* set MCU unsecure */ uint8_t fdprot = 0xff; unsigned num_blocks; uint32_t pflash_bit; uint8_t dflash_bit; struct flash_bank *bank_iter; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; memset(fcf, 0xff, FCF_SIZE); pflash_bit = 1; dflash_bit = 1; /* iterate over all kinetis banks */ /* current bank is bank 0, it contains FCF */ num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks; for (unsigned int bank_idx = 0; bank_idx < num_blocks; bank_idx++) { k_bank = &(k_chip->banks[bank_idx]); bank_iter = k_bank->bank; if (!bank_iter) { LOG_WARNING("Missing bank %u configuration, FCF protection flags may be incomplete", bank_idx); continue; } kinetis_auto_probe(bank_iter); assert(bank_iter->prot_blocks); if (k_bank->flash_class == FC_PFLASH) { for (unsigned int i = 0; i < bank_iter->num_prot_blocks; i++) { if (bank_iter->prot_blocks[i].is_protected == 1) fprot &= ~pflash_bit; pflash_bit <<= 1; } } else if (k_bank->flash_class == FC_FLEX_NVM) { for (unsigned int i = 0; i < bank_iter->num_prot_blocks; i++) { if (bank_iter->prot_blocks[i].is_protected == 1) fdprot &= ~dflash_bit; dflash_bit <<= 1; } } } target_buffer_set_u32(bank->target, fcf + FCF_FPROT, fprot); fcf[FCF_FSEC] = fsec; fcf[FCF_FOPT] = fcf_fopt; fcf[FCF_FDPROT] = fdprot; return ERROR_OK; } static int kinetis_ftfx_command(struct target *target, uint8_t fcmd, uint32_t faddr, uint8_t fccob4, uint8_t fccob5, uint8_t fccob6, uint8_t fccob7, uint8_t fccob8, uint8_t fccob9, uint8_t fccoba, uint8_t fccobb, uint8_t *ftfx_fstat) { uint8_t command[12] = {faddr & 0xff, (faddr >> 8) & 0xff, (faddr >> 16) & 0xff, fcmd, fccob7, fccob6, fccob5, fccob4, fccobb, fccoba, fccob9, fccob8}; int result; uint8_t fstat; int64_t ms_timeout = timeval_ms() + 250; result = target_write_memory(target, FTFX_FCCOB3, 4, 3, command); if (result != ERROR_OK) return result; /* start command */ result = target_write_u8(target, FTFX_FSTAT, 0x80); if (result != ERROR_OK) return result; /* wait for done */ do { result = target_read_u8(target, FTFX_FSTAT, &fstat); if (result != ERROR_OK) return result; if (fstat & 0x80) break; } while (timeval_ms() < ms_timeout); if (ftfx_fstat) *ftfx_fstat = fstat; if ((fstat & 0xf0) != 0x80) { LOG_DEBUG("ftfx command failed FSTAT: %02X FCCOB: %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X", fstat, command[3], command[2], command[1], command[0], command[7], command[6], command[5], command[4], command[11], command[10], command[9], command[8]); return kinetis_ftfx_decode_error(fstat); } return ERROR_OK; } static int kinetis_read_pmstat(struct kinetis_chip *k_chip, uint8_t *pmstat) { int result; uint32_t stat32; struct target *target = k_chip->target; switch (k_chip->sysmodectrlr_type) { case KINETIS_SMC: result = target_read_u8(target, SMC_PMSTAT, pmstat); return result; case KINETIS_SMC32: result = target_read_u32(target, SMC32_PMSTAT, &stat32); if (result == ERROR_OK) *pmstat = stat32 & 0xff; return result; case KINETIS_MC: /* emulate SMC by reading PMC_REGSC bit 3 (VLPRS) */ result = target_read_u8(target, PMC_REGSC, pmstat); if (result == ERROR_OK) { if (*pmstat & 0x08) *pmstat = PM_STAT_VLPR; else *pmstat = PM_STAT_RUN; } return result; } return ERROR_FAIL; } static int kinetis_check_run_mode(struct kinetis_chip *k_chip) { int result; uint8_t pmstat; struct target *target; if (!k_chip) { LOG_ERROR("Chip not probed."); return ERROR_FAIL; } target = k_chip->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } result = kinetis_read_pmstat(k_chip, &pmstat); if (result != ERROR_OK) return result; if (pmstat == PM_STAT_RUN) return ERROR_OK; if (pmstat == PM_STAT_VLPR) { /* It is safe to switch from VLPR to RUN mode without changing clock */ LOG_INFO("Switching from VLPR to RUN mode."); switch (k_chip->sysmodectrlr_type) { case KINETIS_SMC: result = target_write_u8(target, SMC_PMCTRL, PM_CTRL_RUNM_RUN); break; case KINETIS_SMC32: result = target_write_u32(target, SMC32_PMCTRL, PM_CTRL_RUNM_RUN); break; case KINETIS_MC: result = target_write_u32(target, MC_PMCTRL, PM_CTRL_RUNM_RUN); break; } if (result != ERROR_OK) return result; for (unsigned int i = 100; i > 0; i--) { result = kinetis_read_pmstat(k_chip, &pmstat); if (result != ERROR_OK) return result; if (pmstat == PM_STAT_RUN) return ERROR_OK; } } LOG_ERROR("Flash operation not possible in current run mode: SMC_PMSTAT: 0x%x", pmstat); LOG_ERROR("Issue a 'reset init' command."); return ERROR_TARGET_NOT_HALTED; } static void kinetis_invalidate_flash_cache(struct kinetis_chip *k_chip) { struct target *target = k_chip->target; switch (k_chip->cache_type) { case KINETIS_CACHE_K: target_write_u8(target, FMC_PFB01CR + 2, 0xf0); /* Set CINV_WAY bits - request invalidate of all cache ways */ /* FMC_PFB0CR has same address and CINV_WAY bits as FMC_PFB01CR */ break; case KINETIS_CACHE_L: target_write_u8(target, MCM_PLACR + 1, 0x04); /* set bit CFCC - Clear Flash Controller Cache */ break; case KINETIS_CACHE_MSCM: target_write_u32(target, MSCM_OCMDR0, 0x30); /* disable data prefetch and flash speculate */ break; default: break; } } static int kinetis_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int result; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; result = kinetis_check_run_mode(k_chip); if (result != ERROR_OK) return result; /* reset error flags */ result = kinetis_ftfx_prepare(bank->target); if (result != ERROR_OK) return result; if ((first > bank->num_sectors) || (last > bank->num_sectors)) return ERROR_FLASH_OPERATION_FAILED; /* * FIXME: TODO: use the 'Erase Flash Block' command if the * requested erase is PFlash or NVM and encompasses the entire * block. Should be quicker. */ for (unsigned int i = first; i <= last; i++) { /* set command and sector address */ result = kinetis_ftfx_command(bank->target, FTFX_CMD_SECTERASE, k_bank->prog_base + bank->sectors[i].offset, 0, 0, 0, 0, 0, 0, 0, 0, NULL); if (result != ERROR_OK) { LOG_WARNING("erase sector %u failed", i); return ERROR_FLASH_OPERATION_FAILED; } if (k_bank->prog_base == 0 && bank->sectors[i].offset <= FCF_ADDRESS && bank->sectors[i].offset + bank->sectors[i].size > FCF_ADDRESS + FCF_SIZE) { if (allow_fcf_writes) { LOG_WARNING("Flash Configuration Field erased, DO NOT reset or power off the device"); LOG_WARNING("until correct FCF is programmed or MCU gets security lock."); } else { uint8_t fcf_buffer[FCF_SIZE]; kinetis_fill_fcf(bank, fcf_buffer); result = kinetis_write_inner(bank, fcf_buffer, FCF_ADDRESS, FCF_SIZE); if (result != ERROR_OK) LOG_WARNING("Flash Configuration Field write failed"); else LOG_DEBUG("Generated FCF written"); } } } kinetis_invalidate_flash_cache(k_bank->k_chip); return ERROR_OK; } static int kinetis_make_ram_ready(struct target *target) { int result; uint8_t ftfx_fcnfg; /* check if ram ready */ result = target_read_u8(target, FTFX_FCNFG, &ftfx_fcnfg); if (result != ERROR_OK) return result; if (ftfx_fcnfg & (1 << 1)) return ERROR_OK; /* ram ready */ /* make flex ram available */ result = kinetis_ftfx_command(target, FTFX_CMD_SETFLEXRAM, 0x00ff0000, 0, 0, 0, 0, 0, 0, 0, 0, NULL); if (result != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; /* check again */ result = target_read_u8(target, FTFX_FCNFG, &ftfx_fcnfg); if (result != ERROR_OK) return result; if (ftfx_fcnfg & (1 << 1)) return ERROR_OK; /* ram ready */ return ERROR_FLASH_OPERATION_FAILED; } static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int result = ERROR_OK; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; uint8_t *buffer_aligned = NULL; /* * Kinetis uses different terms for the granularity of * sector writes, e.g. "phrase" or "128 bits". We use * the generic term "chunk". The largest possible * Kinetis "chunk" is 16 bytes (128 bits). */ uint32_t prog_section_chunk_bytes = k_bank->sector_size >> 8; uint32_t prog_size_bytes = k_chip->max_flash_prog_size; while (count > 0) { uint32_t size = prog_size_bytes - offset % prog_size_bytes; uint32_t align_begin = offset % prog_section_chunk_bytes; uint32_t align_end; uint32_t size_aligned; uint16_t chunk_count; uint8_t ftfx_fstat; if (size > count) size = count; align_end = (align_begin + size) % prog_section_chunk_bytes; if (align_end) align_end = prog_section_chunk_bytes - align_end; size_aligned = align_begin + size + align_end; chunk_count = size_aligned / prog_section_chunk_bytes; if (size != size_aligned) { /* aligned section: the first, the last or the only */ if (!buffer_aligned) buffer_aligned = malloc(prog_size_bytes); memset(buffer_aligned, 0xff, size_aligned); memcpy(buffer_aligned + align_begin, buffer, size); result = target_write_memory(bank->target, k_chip->progr_accel_ram, 4, size_aligned / 4, buffer_aligned); LOG_DEBUG("section @ " TARGET_ADDR_FMT " aligned begin %" PRIu32 ", end %" PRIu32, bank->base + offset, align_begin, align_end); } else result = target_write_memory(bank->target, k_chip->progr_accel_ram, 4, size_aligned / 4, buffer); LOG_DEBUG("write section @ " TARGET_ADDR_FMT " with length %" PRIu32 " bytes", bank->base + offset, size); if (result != ERROR_OK) { LOG_ERROR("target_write_memory failed"); break; } /* execute section-write command */ result = kinetis_ftfx_command(bank->target, FTFX_CMD_SECTWRITE, k_bank->prog_base + offset - align_begin, chunk_count>>8, chunk_count, 0, 0, 0, 0, 0, 0, &ftfx_fstat); if (result != ERROR_OK) { LOG_ERROR("Error writing section at " TARGET_ADDR_FMT, bank->base + offset); break; } if (ftfx_fstat & 0x01) { LOG_ERROR("Flash write error at " TARGET_ADDR_FMT, bank->base + offset); if (k_bank->prog_base == 0 && offset == FCF_ADDRESS + FCF_SIZE && (k_chip->flash_support & FS_WIDTH_256BIT)) { LOG_ERROR("Flash write immediately after the end of Flash Config Field shows error"); LOG_ERROR("because the flash memory is 256 bits wide (data were written correctly)."); LOG_ERROR("Either change the linker script to add a gap of 16 bytes after FCF"); LOG_ERROR("or set 'kinetis fcf_source write'"); } } buffer += size; offset += size; count -= size; keep_alive(); } free(buffer_aligned); return result; } static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int result; bool fallback = false; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; if (!(k_chip->flash_support & FS_PROGRAM_SECTOR)) { /* fallback to longword write */ fallback = true; LOG_INFO("This device supports Program Longword execution only."); } else { result = kinetis_make_ram_ready(bank->target); if (result != ERROR_OK) { fallback = true; LOG_WARNING("FlexRAM not ready, fallback to slow longword write."); } } LOG_DEBUG("flash write @ " TARGET_ADDR_FMT, bank->base + offset); if (!fallback) { /* program section command */ kinetis_write_sections(bank, buffer, offset, count); } else if (k_chip->flash_support & FS_PROGRAM_LONGWORD) { /* program longword command, not supported in FTFE */ uint8_t *new_buffer = NULL; /* check word alignment */ if (offset & 0x3) { LOG_ERROR("offset 0x%" PRIx32 " breaks the required alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } if (count & 0x3) { uint32_t old_count = count; count = (old_count | 3) + 1; new_buffer = malloc(count); if (!new_buffer) { LOG_ERROR("odd number of bytes to write and no memory " "for padding buffer"); return ERROR_FAIL; } LOG_INFO("odd number of bytes to write (%" PRIu32 "), extending to %" PRIu32 " " "and padding with 0xff", old_count, count); memset(new_buffer + old_count, 0xff, count - old_count); buffer = memcpy(new_buffer, buffer, old_count); } uint32_t words_remaining = count / 4; kinetis_disable_wdog(k_chip); /* try using a block write */ result = kinetis_write_block(bank, buffer, offset, words_remaining); if (result == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single word accesses */ LOG_WARNING("couldn't use block writes, falling back to single " "memory accesses"); while (words_remaining) { uint8_t ftfx_fstat; LOG_DEBUG("write longword @ %08" PRIx32, (uint32_t)(bank->base + offset)); result = kinetis_ftfx_command(bank->target, FTFX_CMD_LWORDPROG, k_bank->prog_base + offset, buffer[3], buffer[2], buffer[1], buffer[0], 0, 0, 0, 0, &ftfx_fstat); if (result != ERROR_OK) { LOG_ERROR("Error writing longword at " TARGET_ADDR_FMT, bank->base + offset); break; } if (ftfx_fstat & 0x01) LOG_ERROR("Flash write error at " TARGET_ADDR_FMT, bank->base + offset); buffer += 4; offset += 4; words_remaining--; keep_alive(); } } free(new_buffer); } else { LOG_ERROR("Flash write strategy not implemented"); return ERROR_FLASH_OPERATION_FAILED; } kinetis_invalidate_flash_cache(k_chip); return result; } static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int result; bool set_fcf = false; bool fcf_in_data_valid = false; bool fcf_differs = false; int sect = 0; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; uint8_t fcf_buffer[FCF_SIZE]; uint8_t fcf_current[FCF_SIZE]; uint8_t fcf_in_data[FCF_SIZE]; result = kinetis_check_run_mode(k_chip); if (result != ERROR_OK) return result; /* reset error flags */ result = kinetis_ftfx_prepare(bank->target); if (result != ERROR_OK) return result; if (k_bank->prog_base == 0 && !allow_fcf_writes) { if (bank->sectors[1].offset <= FCF_ADDRESS) sect = 1; /* 1kb sector, FCF in 2nd sector */ if (offset < bank->sectors[sect].offset + bank->sectors[sect].size && offset + count > bank->sectors[sect].offset) set_fcf = true; /* write to any part of sector with FCF */ } if (set_fcf) { kinetis_fill_fcf(bank, fcf_buffer); fcf_in_data_valid = offset <= FCF_ADDRESS && offset + count >= FCF_ADDRESS + FCF_SIZE; if (fcf_in_data_valid) { memcpy(fcf_in_data, buffer + FCF_ADDRESS - offset, FCF_SIZE); if (memcmp(fcf_in_data, fcf_buffer, 8)) { fcf_differs = true; LOG_INFO("Setting of backdoor key is not supported in mode 'kinetis fcf_source protection'."); } if (memcmp(fcf_in_data + FCF_FPROT, fcf_buffer + FCF_FPROT, 4)) { fcf_differs = true; LOG_INFO("Flash protection requested in the programmed file differs from current setting."); } if (fcf_in_data[FCF_FDPROT] != fcf_buffer[FCF_FDPROT]) { fcf_differs = true; LOG_INFO("Data flash protection requested in the programmed file differs from current setting."); } if ((fcf_in_data[FCF_FSEC] & 3) != 2) { fcf_in_data_valid = false; LOG_INFO("Device security requested in the programmed file! Write denied."); } else if (fcf_in_data[FCF_FSEC] != fcf_buffer[FCF_FSEC]) { fcf_differs = true; LOG_INFO("Strange unsecure mode 0x%02" PRIx8 " requested in the programmed file, set FSEC = 0x%02" PRIx8 " in the startup code!", fcf_in_data[FCF_FSEC], fcf_buffer[FCF_FSEC]); } if (fcf_in_data[FCF_FOPT] != fcf_buffer[FCF_FOPT]) { fcf_differs = true; LOG_INFO("FOPT requested in the programmed file differs from current setting, set 'kinetis fopt 0x%02" PRIx8 "'.", fcf_in_data[FCF_FOPT]); } /* If the device has ECC flash, then we cannot re-program FCF */ if (fcf_differs) { if (k_chip->flash_support & FS_ECC) { fcf_in_data_valid = false; LOG_INFO("Cannot re-program FCF. Expect verify errors at FCF (0x400-0x40f)."); } else { LOG_INFO("Trying to re-program FCF."); if (!(k_chip->flash_support & FS_PROGRAM_LONGWORD)) LOG_INFO("Flash re-programming may fail on this device!"); } } } } if (set_fcf && !fcf_in_data_valid) { if (offset < FCF_ADDRESS) { /* write part preceding FCF */ result = kinetis_write_inner(bank, buffer, offset, FCF_ADDRESS - offset); if (result != ERROR_OK) return result; } result = target_read_memory(bank->target, bank->base + FCF_ADDRESS, 4, FCF_SIZE / 4, fcf_current); if (result == ERROR_OK && memcmp(fcf_current, fcf_buffer, FCF_SIZE) == 0) set_fcf = false; if (set_fcf) { /* write FCF if differs from flash - eliminate multiple writes */ result = kinetis_write_inner(bank, fcf_buffer, FCF_ADDRESS, FCF_SIZE); if (result != ERROR_OK) return result; } LOG_WARNING("Flash Configuration Field written."); LOG_WARNING("Reset or power off the device to make settings effective."); if (offset + count > FCF_ADDRESS + FCF_SIZE) { uint32_t delta = FCF_ADDRESS + FCF_SIZE - offset; /* write part after FCF */ result = kinetis_write_inner(bank, buffer + delta, FCF_ADDRESS + FCF_SIZE, count - delta); } return result; } else { /* no FCF fiddling, normal write */ return kinetis_write_inner(bank, buffer, offset, count); } } static int kinetis_probe_chip(struct kinetis_chip *k_chip) { int result; uint8_t fcfg1_nvmsize, fcfg1_pfsize, fcfg1_eesize, fcfg1_depart; uint8_t fcfg2_pflsh; uint32_t ee_size = 0; uint32_t pflash_size_k, nvm_size_k, dflash_size_k; uint32_t pflash_size_m; unsigned num_blocks = 0; unsigned maxaddr_shift = 13; struct target *target = k_chip->target; unsigned familyid = 0, subfamid = 0; unsigned cpu_mhz = 120; bool use_nvm_marking = false; char flash_marking[12], nvm_marking[2]; char name[40]; k_chip->probed = false; k_chip->pflash_sector_size = 0; k_chip->pflash_base = 0; k_chip->nvm_base = 0x10000000; k_chip->progr_accel_ram = FLEXRAM; name[0] = '\0'; if (k_chip->sim_base) result = target_read_u32(target, k_chip->sim_base + SIM_SDID_OFFSET, &k_chip->sim_sdid); else { result = target_read_u32(target, SIM_BASE + SIM_SDID_OFFSET, &k_chip->sim_sdid); if (result == ERROR_OK) k_chip->sim_base = SIM_BASE; else { result = target_read_u32(target, SIM_BASE_KL28 + SIM_SDID_OFFSET, &k_chip->sim_sdid); if (result == ERROR_OK) k_chip->sim_base = SIM_BASE_KL28; } } if (result != ERROR_OK) return result; if ((k_chip->sim_sdid & (~KINETIS_SDID_K_SERIES_MASK)) == 0) { /* older K-series MCU */ uint32_t mcu_type = k_chip->sim_sdid & KINETIS_K_SDID_TYPE_MASK; k_chip->cache_type = KINETIS_CACHE_K; k_chip->watchdog_type = KINETIS_WDOG_K; switch (mcu_type) { case KINETIS_K_SDID_K10_M50: case KINETIS_K_SDID_K20_M50: /* 1kB sectors */ k_chip->pflash_sector_size = 1<<10; k_chip->nvm_sector_size = 1<<10; num_blocks = 2; k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR; break; case KINETIS_K_SDID_K10_M72: case KINETIS_K_SDID_K20_M72: case KINETIS_K_SDID_K30_M72: case KINETIS_K_SDID_K30_M100: case KINETIS_K_SDID_K40_M72: case KINETIS_K_SDID_K40_M100: case KINETIS_K_SDID_K50_M72: /* 2kB sectors, 1kB FlexNVM sectors */ k_chip->pflash_sector_size = 2<<10; k_chip->nvm_sector_size = 1<<10; num_blocks = 2; k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR; k_chip->max_flash_prog_size = 1<<10; break; case KINETIS_K_SDID_K10_M100: case KINETIS_K_SDID_K20_M100: case KINETIS_K_SDID_K11: case KINETIS_K_SDID_K12: case KINETIS_K_SDID_K21_M50: case KINETIS_K_SDID_K22_M50: case KINETIS_K_SDID_K51_M72: case KINETIS_K_SDID_K53: case KINETIS_K_SDID_K60_M100: /* 2kB sectors */ k_chip->pflash_sector_size = 2<<10; k_chip->nvm_sector_size = 2<<10; num_blocks = 2; k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR; break; case KINETIS_K_SDID_K21_M120: case KINETIS_K_SDID_K22_M120: /* 4kB sectors (MK21FN1M0, MK21FX512, MK22FN1M0, MK22FX512) */ k_chip->pflash_sector_size = 4<<10; k_chip->max_flash_prog_size = 1<<10; k_chip->nvm_sector_size = 4<<10; num_blocks = 2; k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; break; case KINETIS_K_SDID_K10_M120: case KINETIS_K_SDID_K20_M120: case KINETIS_K_SDID_K60_M150: case KINETIS_K_SDID_K70_M150: /* 4kB sectors */ k_chip->pflash_sector_size = 4<<10; k_chip->nvm_sector_size = 4<<10; num_blocks = 4; k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; break; default: LOG_ERROR("Unsupported K-family FAMID"); } for (size_t idx = 0; idx < ARRAY_SIZE(kinetis_types_old); idx++) { if (kinetis_types_old[idx].sdid == mcu_type) { strcpy(name, kinetis_types_old[idx].name); use_nvm_marking = true; break; } } /* first revision of some devices has no SMC */ switch (mcu_type) { case KINETIS_K_SDID_K10_M100: case KINETIS_K_SDID_K20_M100: case KINETIS_K_SDID_K30_M100: case KINETIS_K_SDID_K40_M100: case KINETIS_K_SDID_K60_M100: { uint32_t revid = (k_chip->sim_sdid & KINETIS_K_REVID_MASK) >> KINETIS_K_REVID_SHIFT; /* highest bit set corresponds to rev 2.x */ if (revid <= 7) { k_chip->sysmodectrlr_type = KINETIS_MC; strcat(name, " Rev 1.x"); } } break; } } else { /* Newer K-series or KL series MCU */ familyid = (k_chip->sim_sdid & KINETIS_SDID_FAMILYID_MASK) >> KINETIS_SDID_FAMILYID_SHIFT; subfamid = (k_chip->sim_sdid & KINETIS_SDID_SUBFAMID_MASK) >> KINETIS_SDID_SUBFAMID_SHIFT; switch (k_chip->sim_sdid & KINETIS_SDID_SERIESID_MASK) { case KINETIS_SDID_SERIESID_K: use_nvm_marking = true; k_chip->cache_type = KINETIS_CACHE_K; k_chip->watchdog_type = KINETIS_WDOG_K; switch (k_chip->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK)) { case KINETIS_SDID_FAMILYID_K0X | KINETIS_SDID_SUBFAMID_KX2: /* K02FN64, K02FN128: FTFA, 2kB sectors */ k_chip->pflash_sector_size = 2<<10; num_blocks = 1; k_chip->flash_support = FS_PROGRAM_LONGWORD; cpu_mhz = 100; break; case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX2: { /* MK24FN1M reports as K22, this should detect it (according to errata note 1N83J) */ uint32_t sopt1; result = target_read_u32(target, k_chip->sim_base + SIM_SOPT1_OFFSET, &sopt1); if (result != ERROR_OK) return result; if (((k_chip->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K24FN1M) && ((sopt1 & KINETIS_SOPT1_RAMSIZE_MASK) == KINETIS_SOPT1_RAMSIZE_K24FN1M)) { /* MK24FN1M */ k_chip->pflash_sector_size = 4<<10; num_blocks = 2; k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; k_chip->max_flash_prog_size = 1<<10; subfamid = 4; /* errata 1N83J fix */ break; } if ((k_chip->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K22FN128 || (k_chip->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K22FN256 || (k_chip->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K22FN512) { /* K22 with new-style SDID - smaller pflash with FTFA, 2kB sectors */ k_chip->pflash_sector_size = 2<<10; /* autodetect 1 or 2 blocks */ k_chip->flash_support = FS_PROGRAM_LONGWORD; break; } LOG_ERROR("Unsupported Kinetis K22 DIEID"); break; } case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX4: k_chip->pflash_sector_size = 4<<10; if ((k_chip->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K24FN256) { /* K24FN256 - smaller pflash with FTFA */ num_blocks = 1; k_chip->flash_support = FS_PROGRAM_LONGWORD; break; } /* K24FN1M without errata 7534 */ num_blocks = 2; k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; k_chip->max_flash_prog_size = 1<<10; break; case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX1: /* errata 7534 - should be K63 */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX2: /* errata 7534 - should be K64 */ subfamid += 2; /* errata 7534 fix */ /* fallthrough */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX3: /* K63FN1M0 */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX4: /* K64FN1M0, K64FX512 */ k_chip->pflash_sector_size = 4<<10; k_chip->nvm_sector_size = 4<<10; k_chip->max_flash_prog_size = 1<<10; num_blocks = 2; k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; break; case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX6: /* K26FN2M0 */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX6: /* K66FN2M0, K66FX1M0 */ k_chip->pflash_sector_size = 4<<10; k_chip->nvm_sector_size = 4<<10; k_chip->max_flash_prog_size = 1<<10; num_blocks = 4; k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_ECC; cpu_mhz = 180; break; case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX7: /* K27FN2M0 */ case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX8: /* K28FN2M0 */ k_chip->pflash_sector_size = 4<<10; k_chip->max_flash_prog_size = 1<<10; num_blocks = 4; k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_ECC; cpu_mhz = 150; break; case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX0: case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX1: case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX2: /* K80FN256, K81FN256, K82FN256 */ k_chip->pflash_sector_size = 4<<10; num_blocks = 1; k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_NO_CMD_BLOCKSTAT; cpu_mhz = 150; break; case KINETIS_SDID_FAMILYID_KL8X | KINETIS_SDID_SUBFAMID_KX1: case KINETIS_SDID_FAMILYID_KL8X | KINETIS_SDID_SUBFAMID_KX2: /* KL81Z128, KL82Z128 */ k_chip->pflash_sector_size = 2<<10; num_blocks = 1; k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_NO_CMD_BLOCKSTAT; k_chip->cache_type = KINETIS_CACHE_L; use_nvm_marking = false; snprintf(name, sizeof(name), "MKL8%uZ%%s7", subfamid); break; default: LOG_ERROR("Unsupported Kinetis FAMILYID SUBFAMID"); } if (name[0] == '\0') snprintf(name, sizeof(name), "MK%u%uF%%s%u", familyid, subfamid, cpu_mhz / 10); break; case KINETIS_SDID_SERIESID_KL: /* KL-series */ k_chip->pflash_sector_size = 1<<10; k_chip->nvm_sector_size = 1<<10; /* autodetect 1 or 2 blocks */ k_chip->flash_support = FS_PROGRAM_LONGWORD; k_chip->cache_type = KINETIS_CACHE_L; k_chip->watchdog_type = KINETIS_WDOG_COP; cpu_mhz = 48; switch (k_chip->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK)) { case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX3: case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX3: subfamid = 7; break; case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX8: cpu_mhz = 72; k_chip->pflash_sector_size = 2<<10; num_blocks = 2; k_chip->watchdog_type = KINETIS_WDOG32_KL28; k_chip->sysmodectrlr_type = KINETIS_SMC32; break; } snprintf(name, sizeof(name), "MKL%u%uZ%%s%u", familyid, subfamid, cpu_mhz / 10); break; case KINETIS_SDID_SERIESID_KW: /* Newer KW-series (all KW series except KW2xD, KW01Z) */ cpu_mhz = 48; switch (k_chip->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK)) { case KINETIS_SDID_FAMILYID_K4X | KINETIS_SDID_SUBFAMID_KX0: /* KW40Z */ case KINETIS_SDID_FAMILYID_K3X | KINETIS_SDID_SUBFAMID_KX0: /* KW30Z */ case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX0: /* KW20Z */ /* FTFA, 1kB sectors */ k_chip->pflash_sector_size = 1<<10; k_chip->nvm_sector_size = 1<<10; /* autodetect 1 or 2 blocks */ k_chip->flash_support = FS_PROGRAM_LONGWORD; k_chip->cache_type = KINETIS_CACHE_L; k_chip->watchdog_type = KINETIS_WDOG_COP; break; case KINETIS_SDID_FAMILYID_K4X | KINETIS_SDID_SUBFAMID_KX1: /* KW41Z */ case KINETIS_SDID_FAMILYID_K3X | KINETIS_SDID_SUBFAMID_KX1: /* KW31Z */ case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX1: /* KW21Z */ /* FTFA, 2kB sectors */ k_chip->pflash_sector_size = 2<<10; k_chip->nvm_sector_size = 2<<10; /* autodetect 1 or 2 blocks */ k_chip->flash_support = FS_PROGRAM_LONGWORD; k_chip->cache_type = KINETIS_CACHE_L; k_chip->watchdog_type = KINETIS_WDOG_COP; break; default: LOG_ERROR("Unsupported KW FAMILYID SUBFAMID"); } snprintf(name, sizeof(name), "MKW%u%uZ%%s%u", familyid, subfamid, cpu_mhz / 10); break; case KINETIS_SDID_SERIESID_KV: /* KV-series */ k_chip->watchdog_type = KINETIS_WDOG_K; switch (k_chip->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK)) { case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX0: /* KV10: FTFA, 1kB sectors */ k_chip->pflash_sector_size = 1<<10; num_blocks = 1; k_chip->flash_support = FS_PROGRAM_LONGWORD; k_chip->cache_type = KINETIS_CACHE_L; strcpy(name, "MKV10Z%s7"); break; case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX1: /* KV11: FTFA, 2kB sectors */ k_chip->pflash_sector_size = 2<<10; num_blocks = 1; k_chip->flash_support = FS_PROGRAM_LONGWORD; k_chip->cache_type = KINETIS_CACHE_L; strcpy(name, "MKV11Z%s7"); break; case KINETIS_SDID_FAMILYID_K3X | KINETIS_SDID_SUBFAMID_KX0: /* KV30: FTFA, 2kB sectors, 1 block */ case KINETIS_SDID_FAMILYID_K3X | KINETIS_SDID_SUBFAMID_KX1: /* KV31: FTFA, 2kB sectors, 2 blocks */ k_chip->pflash_sector_size = 2<<10; /* autodetect 1 or 2 blocks */ k_chip->flash_support = FS_PROGRAM_LONGWORD; k_chip->cache_type = KINETIS_CACHE_K; break; case KINETIS_SDID_FAMILYID_K4X | KINETIS_SDID_SUBFAMID_KX2: case KINETIS_SDID_FAMILYID_K4X | KINETIS_SDID_SUBFAMID_KX4: case KINETIS_SDID_FAMILYID_K4X | KINETIS_SDID_SUBFAMID_KX6: /* KV4x: FTFA, 4kB sectors */ k_chip->pflash_sector_size = 4<<10; num_blocks = 1; k_chip->flash_support = FS_PROGRAM_LONGWORD; k_chip->cache_type = KINETIS_CACHE_K; cpu_mhz = 168; break; case KINETIS_SDID_FAMILYID_K5X | KINETIS_SDID_SUBFAMID_KX6: case KINETIS_SDID_FAMILYID_K5X | KINETIS_SDID_SUBFAMID_KX8: /* KV5x: FTFE, 8kB sectors */ k_chip->pflash_sector_size = 8<<10; k_chip->max_flash_prog_size = 1<<10; num_blocks = 1; maxaddr_shift = 14; k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_WIDTH_256BIT | FS_ECC; k_chip->pflash_base = 0x10000000; k_chip->progr_accel_ram = 0x18000000; cpu_mhz = 240; break; default: LOG_ERROR("Unsupported KV FAMILYID SUBFAMID"); } if (name[0] == '\0') snprintf(name, sizeof(name), "MKV%u%uF%%s%u", familyid, subfamid, cpu_mhz / 10); break; case KINETIS_SDID_SERIESID_KE: /* KE1x-series */ k_chip->watchdog_type = KINETIS_WDOG32_KE1X; switch (k_chip->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK | KINETIS_SDID_PROJECTID_MASK)) { case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX4 | KINETIS_SDID_PROJECTID_KE1XZ: case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX5 | KINETIS_SDID_PROJECTID_KE1XZ: /* KE1xZ: FTFE, 2kB sectors */ k_chip->pflash_sector_size = 2<<10; k_chip->nvm_sector_size = 2<<10; k_chip->max_flash_prog_size = 1<<9; num_blocks = 2; k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; k_chip->cache_type = KINETIS_CACHE_L; cpu_mhz = 72; snprintf(name, sizeof(name), "MKE%u%uZ%%s%u", familyid, subfamid, cpu_mhz / 10); break; case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX4 | KINETIS_SDID_PROJECTID_KE1XF: case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX6 | KINETIS_SDID_PROJECTID_KE1XF: case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX8 | KINETIS_SDID_PROJECTID_KE1XF: /* KE1xF: FTFE, 4kB sectors */ k_chip->pflash_sector_size = 4<<10; k_chip->nvm_sector_size = 2<<10; k_chip->max_flash_prog_size = 1<<10; num_blocks = 2; k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; k_chip->cache_type = KINETIS_CACHE_MSCM; cpu_mhz = 168; snprintf(name, sizeof(name), "MKE%u%uF%%s%u", familyid, subfamid, cpu_mhz / 10); break; default: LOG_ERROR("Unsupported KE FAMILYID SUBFAMID"); } break; default: LOG_ERROR("Unsupported K-series"); } } if (k_chip->pflash_sector_size == 0) { LOG_ERROR("MCU is unsupported, SDID 0x%08" PRIx32, k_chip->sim_sdid); return ERROR_FLASH_OPER_UNSUPPORTED; } result = target_read_u32(target, k_chip->sim_base + SIM_FCFG1_OFFSET, &k_chip->sim_fcfg1); if (result != ERROR_OK) return result; result = target_read_u32(target, k_chip->sim_base + SIM_FCFG2_OFFSET, &k_chip->sim_fcfg2); if (result != ERROR_OK) return result; LOG_DEBUG("SDID: 0x%08" PRIX32 " FCFG1: 0x%08" PRIX32 " FCFG2: 0x%08" PRIX32, k_chip->sim_sdid, k_chip->sim_fcfg1, k_chip->sim_fcfg2); fcfg1_nvmsize = (uint8_t)((k_chip->sim_fcfg1 >> 28) & 0x0f); fcfg1_pfsize = (uint8_t)((k_chip->sim_fcfg1 >> 24) & 0x0f); fcfg1_eesize = (uint8_t)((k_chip->sim_fcfg1 >> 16) & 0x0f); fcfg1_depart = (uint8_t)((k_chip->sim_fcfg1 >> 8) & 0x0f); fcfg2_pflsh = (uint8_t)((k_chip->sim_fcfg2 >> 23) & 0x01); k_chip->fcfg2_maxaddr0_shifted = ((k_chip->sim_fcfg2 >> 24) & 0x7f) << maxaddr_shift; k_chip->fcfg2_maxaddr1_shifted = ((k_chip->sim_fcfg2 >> 16) & 0x7f) << maxaddr_shift; if (num_blocks == 0) num_blocks = k_chip->fcfg2_maxaddr1_shifted ? 2 : 1; else if (k_chip->fcfg2_maxaddr1_shifted == 0 && num_blocks >= 2 && fcfg2_pflsh) { /* fcfg2_maxaddr1 may be zero due to partitioning whole NVM as EEPROM backup * Do not adjust block count in this case! */ num_blocks = 1; LOG_WARNING("MAXADDR1 is zero, number of flash banks adjusted to 1"); } else if (k_chip->fcfg2_maxaddr1_shifted != 0 && num_blocks == 1) { num_blocks = 2; LOG_WARNING("MAXADDR1 is non zero, number of flash banks adjusted to 2"); } /* when the PFLSH bit is set, there is no FlexNVM/FlexRAM */ if (!fcfg2_pflsh) { switch (fcfg1_nvmsize) { case 0x03: case 0x05: case 0x07: case 0x09: case 0x0b: k_chip->nvm_size = 1 << (14 + (fcfg1_nvmsize >> 1)); break; case 0x0f: if (k_chip->pflash_sector_size >= 4<<10) k_chip->nvm_size = 512<<10; else /* K20_100 */ k_chip->nvm_size = 256<<10; break; default: k_chip->nvm_size = 0; break; } switch (fcfg1_eesize) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: ee_size = (16 << (10 - fcfg1_eesize)); break; default: ee_size = 0; break; } switch (fcfg1_depart) { case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: k_chip->dflash_size = k_chip->nvm_size - (4096 << fcfg1_depart); break; case 0x07: case 0x08: k_chip->dflash_size = 0; break; case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: k_chip->dflash_size = 4096 << (fcfg1_depart & 0x7); break; default: k_chip->dflash_size = k_chip->nvm_size; break; } } switch (fcfg1_pfsize) { case 0x00: k_chip->pflash_size = 8192; break; case 0x01: case 0x03: case 0x05: case 0x07: case 0x09: case 0x0b: case 0x0d: k_chip->pflash_size = 1 << (14 + (fcfg1_pfsize >> 1)); break; case 0x0f: /* a peculiar case: Freescale states different sizes for 0xf * KL03P24M48SF0RM 32 KB .... duplicate of code 0x3 * K02P64M100SFARM 128 KB ... duplicate of code 0x7 * K22P121M120SF8RM 256 KB ... duplicate of code 0x9 * K22P121M120SF7RM 512 KB ... duplicate of code 0xb * K22P100M120SF5RM 1024 KB ... duplicate of code 0xd * K26P169M180SF5RM 2048 KB ... the only unique value * fcfg2_maxaddr0 seems to be the only clue to pflash_size * Checking fcfg2_maxaddr0 in bank probe is pointless then */ if (fcfg2_pflsh) k_chip->pflash_size = k_chip->fcfg2_maxaddr0_shifted * num_blocks; else k_chip->pflash_size = k_chip->fcfg2_maxaddr0_shifted * num_blocks / 2; if (k_chip->pflash_size != 2048<<10) LOG_WARNING("SIM_FCFG1 PFSIZE = 0xf: please check if pflash is %" PRIu32 " KB", k_chip->pflash_size>>10); break; default: k_chip->pflash_size = 0; break; } if (k_chip->flash_support & FS_PROGRAM_SECTOR && k_chip->max_flash_prog_size == 0) { k_chip->max_flash_prog_size = k_chip->pflash_sector_size; /* Program section size is equal to sector size by default */ } if (fcfg2_pflsh) { k_chip->num_pflash_blocks = num_blocks; k_chip->num_nvm_blocks = 0; } else { k_chip->num_pflash_blocks = (num_blocks + 1) / 2; k_chip->num_nvm_blocks = num_blocks - k_chip->num_pflash_blocks; } if (use_nvm_marking) { nvm_marking[0] = k_chip->num_nvm_blocks ? 'X' : 'N'; nvm_marking[1] = '\0'; } else nvm_marking[0] = '\0'; pflash_size_k = k_chip->pflash_size / 1024; pflash_size_m = pflash_size_k / 1024; if (pflash_size_m) snprintf(flash_marking, sizeof(flash_marking), "%s%" PRIu32 "M0xxx", nvm_marking, pflash_size_m); else snprintf(flash_marking, sizeof(flash_marking), "%s%" PRIu32 "xxx", nvm_marking, pflash_size_k); snprintf(k_chip->name, sizeof(k_chip->name), name, flash_marking); LOG_INFO("Kinetis %s detected: %u flash blocks", k_chip->name, num_blocks); LOG_INFO("%u PFlash banks: %" PRIu32 " KiB total", k_chip->num_pflash_blocks, pflash_size_k); if (k_chip->num_nvm_blocks) { nvm_size_k = k_chip->nvm_size / 1024; dflash_size_k = k_chip->dflash_size / 1024; LOG_INFO("%u FlexNVM banks: %" PRIu32 " KiB total, %" PRIu32 " KiB available as data flash, %" PRIu32 " bytes FlexRAM", k_chip->num_nvm_blocks, nvm_size_k, dflash_size_k, ee_size); } k_chip->probed = true; if (create_banks) kinetis_create_missing_banks(k_chip); return ERROR_OK; } static int kinetis_probe(struct flash_bank *bank) { int result; uint8_t fcfg2_maxaddr0, fcfg2_pflsh, fcfg2_maxaddr1; unsigned num_blocks, first_nvm_bank; uint32_t size_k; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip; assert(k_bank); k_chip = k_bank->k_chip; k_bank->probed = false; if (!k_chip->probed) { result = kinetis_probe_chip(k_chip); if (result != ERROR_OK) return result; } num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks; first_nvm_bank = k_chip->num_pflash_blocks; if (k_bank->bank_number < k_chip->num_pflash_blocks) { /* pflash, banks start at address zero */ k_bank->flash_class = FC_PFLASH; bank->size = (k_chip->pflash_size / k_chip->num_pflash_blocks); bank->base = k_chip->pflash_base + bank->size * k_bank->bank_number; k_bank->prog_base = 0x00000000 + bank->size * k_bank->bank_number; k_bank->sector_size = k_chip->pflash_sector_size; /* pflash is divided into 32 protection areas for * parts with more than 32K of PFlash. For parts with * less the protection unit is set to 1024 bytes */ k_bank->protection_size = MAX(k_chip->pflash_size / 32, 1024); bank->num_prot_blocks = bank->size / k_bank->protection_size; k_bank->protection_block = bank->num_prot_blocks * k_bank->bank_number; size_k = bank->size / 1024; LOG_DEBUG("Kinetis bank %u: %" PRIu32 "k PFlash, FTFx base 0x%08" PRIx32 ", sect %" PRIu32, k_bank->bank_number, size_k, k_bank->prog_base, k_bank->sector_size); } else if (k_bank->bank_number < num_blocks) { /* nvm, banks start at address 0x10000000 */ unsigned nvm_ord = k_bank->bank_number - first_nvm_bank; uint32_t limit; k_bank->flash_class = FC_FLEX_NVM; bank->size = k_chip->nvm_size / k_chip->num_nvm_blocks; bank->base = k_chip->nvm_base + bank->size * nvm_ord; k_bank->prog_base = 0x00800000 + bank->size * nvm_ord; k_bank->sector_size = k_chip->nvm_sector_size; if (k_chip->dflash_size == 0) { k_bank->protection_size = 0; } else { int i; for (i = k_chip->dflash_size; ~i & 1; i >>= 1) ; if (i == 1) k_bank->protection_size = k_chip->dflash_size / 8; /* data flash size = 2^^n */ else k_bank->protection_size = k_chip->nvm_size / 8; /* TODO: verify on SF1, not documented in RM */ } bank->num_prot_blocks = 8 / k_chip->num_nvm_blocks; k_bank->protection_block = bank->num_prot_blocks * nvm_ord; /* EEPROM backup part of FlexNVM is not accessible, use dflash_size as a limit */ if (k_chip->dflash_size > bank->size * nvm_ord) limit = k_chip->dflash_size - bank->size * nvm_ord; else limit = 0; if (bank->size > limit) { bank->size = limit; LOG_DEBUG("FlexNVM bank %u limited to 0x%08" PRIx32 " due to active EEPROM backup", k_bank->bank_number, limit); } size_k = bank->size / 1024; LOG_DEBUG("Kinetis bank %u: %" PRIu32 "k FlexNVM, FTFx base 0x%08" PRIx32 ", sect %" PRIu32, k_bank->bank_number, size_k, k_bank->prog_base, k_bank->sector_size); } else { LOG_ERROR("Cannot determine parameters for bank %u, only %u banks on device", k_bank->bank_number, num_blocks); return ERROR_FLASH_BANK_INVALID; } fcfg2_pflsh = (uint8_t)((k_chip->sim_fcfg2 >> 23) & 0x01); fcfg2_maxaddr0 = (uint8_t)((k_chip->sim_fcfg2 >> 24) & 0x7f); fcfg2_maxaddr1 = (uint8_t)((k_chip->sim_fcfg2 >> 16) & 0x7f); if (k_bank->bank_number == 0 && k_chip->fcfg2_maxaddr0_shifted != bank->size) LOG_WARNING("MAXADDR0 0x%02" PRIx8 " check failed," " please report to OpenOCD mailing list", fcfg2_maxaddr0); if (fcfg2_pflsh) { if (k_bank->bank_number == 1 && k_chip->fcfg2_maxaddr1_shifted != bank->size) LOG_WARNING("MAXADDR1 0x%02" PRIx8 " check failed," " please report to OpenOCD mailing list", fcfg2_maxaddr1); } else { if (k_bank->bank_number == first_nvm_bank && k_chip->fcfg2_maxaddr1_shifted != k_chip->dflash_size) LOG_WARNING("FlexNVM MAXADDR1 0x%02" PRIx8 " check failed," " please report to OpenOCD mailing list", fcfg2_maxaddr1); } free(bank->sectors); bank->sectors = NULL; free(bank->prot_blocks); bank->prot_blocks = NULL; if (k_bank->sector_size == 0) { LOG_ERROR("Unknown sector size for bank %u", bank->bank_number); return ERROR_FLASH_BANK_INVALID; } bank->num_sectors = bank->size / k_bank->sector_size; if (bank->num_sectors > 0) { /* FlexNVM bank can be used for EEPROM backup therefore zero sized */ bank->sectors = alloc_block_array(0, k_bank->sector_size, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; bank->prot_blocks = alloc_block_array(0, k_bank->protection_size, bank->num_prot_blocks); if (!bank->prot_blocks) return ERROR_FAIL; } else { bank->num_prot_blocks = 0; } k_bank->probed = true; return ERROR_OK; } static int kinetis_auto_probe(struct flash_bank *bank) { struct kinetis_flash_bank *k_bank = bank->driver_priv; if (k_bank && k_bank->probed) return ERROR_OK; return kinetis_probe(bank); } static int kinetis_info(struct flash_bank *bank, struct command_invocation *cmd) { const char *bank_class_names[] = { "(ANY)", "PFlash", "FlexNVM", "FlexRAM" }; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; uint32_t size_k = bank->size / 1024; command_print_sameline(cmd, "%s %s: %" PRIu32 "k %s bank %s at " TARGET_ADDR_FMT, bank->driver->name, k_chip->name, size_k, bank_class_names[k_bank->flash_class], bank->name, bank->base); return ERROR_OK; } static int kinetis_blank_check(struct flash_bank *bank) { struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; int result; /* surprisingly blank check does not work in VLPR and HSRUN modes */ result = kinetis_check_run_mode(k_chip); if (result != ERROR_OK) return result; /* reset error flags */ result = kinetis_ftfx_prepare(bank->target); if (result != ERROR_OK) return result; if (k_bank->flash_class == FC_PFLASH || k_bank->flash_class == FC_FLEX_NVM) { bool block_dirty = true; bool use_block_cmd = !(k_chip->flash_support & FS_NO_CMD_BLOCKSTAT); uint8_t ftfx_fstat; if (use_block_cmd && k_bank->flash_class == FC_FLEX_NVM) { uint8_t fcfg1_depart = (uint8_t)((k_chip->sim_fcfg1 >> 8) & 0x0f); /* block operation cannot be used on FlexNVM when EEPROM backup partition is set */ if (fcfg1_depart != 0xf && fcfg1_depart != 0) use_block_cmd = false; } if (use_block_cmd) { /* check if whole bank is blank */ result = kinetis_ftfx_command(bank->target, FTFX_CMD_BLOCKSTAT, k_bank->prog_base, 0, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat); if (result != ERROR_OK) kinetis_ftfx_clear_error(bank->target); else if ((ftfx_fstat & 0x01) == 0) block_dirty = false; } if (block_dirty) { /* the whole bank is not erased, check sector-by-sector */ for (unsigned int i = 0; i < bank->num_sectors; i++) { /* normal margin */ result = kinetis_ftfx_command(bank->target, FTFX_CMD_SECTSTAT, k_bank->prog_base + bank->sectors[i].offset, 1, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat); if (result == ERROR_OK) { bank->sectors[i].is_erased = !(ftfx_fstat & 0x01); } else { LOG_DEBUG("Ignoring error on PFlash sector blank-check"); kinetis_ftfx_clear_error(bank->target); bank->sectors[i].is_erased = -1; } } } else { /* the whole bank is erased, update all sectors */ for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; } } else { LOG_WARNING("kinetis_blank_check not supported yet for FlexRAM"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } COMMAND_HANDLER(kinetis_nvm_partition) { int result; unsigned bank_idx; unsigned num_blocks, first_nvm_bank; unsigned long par, log2 = 0, ee1 = 0, ee2 = 0; enum { SHOW_INFO, DF_SIZE, EEBKP_SIZE } sz_type = SHOW_INFO; bool enable; uint8_t load_flex_ram = 1; uint8_t ee_size_code = 0x3f; uint8_t flex_nvm_partition_code = 0; uint8_t ee_split = 3; struct target *target = get_current_target(CMD_CTX); struct kinetis_chip *k_chip; uint32_t sim_fcfg1; k_chip = kinetis_get_chip(target); if (CMD_ARGC >= 2) { if (strcmp(CMD_ARGV[0], "dataflash") == 0) sz_type = DF_SIZE; else if (strcmp(CMD_ARGV[0], "eebkp") == 0) sz_type = EEBKP_SIZE; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], par); while (par >> (log2 + 3)) log2++; } switch (sz_type) { case SHOW_INFO: if (!k_chip) { LOG_ERROR("Chip not probed."); return ERROR_FAIL; } result = target_read_u32(target, k_chip->sim_base + SIM_FCFG1_OFFSET, &sim_fcfg1); if (result != ERROR_OK) return result; flex_nvm_partition_code = (uint8_t)((sim_fcfg1 >> 8) & 0x0f); switch (flex_nvm_partition_code) { case 0: command_print(CMD, "No EEPROM backup, data flash only"); break; case 1: case 2: case 3: case 4: case 5: case 6: command_print(CMD, "EEPROM backup %d KB", 4 << flex_nvm_partition_code); break; case 8: command_print(CMD, "No data flash, EEPROM backup only"); break; case 0x9: case 0xA: case 0xB: case 0xC: case 0xD: case 0xE: command_print(CMD, "data flash %d KB", 4 << (flex_nvm_partition_code & 7)); break; case 0xf: command_print(CMD, "No EEPROM backup, data flash only (DEPART not set)"); break; default: command_print(CMD, "Unsupported EEPROM backup size code 0x%02" PRIx8, flex_nvm_partition_code); } return ERROR_OK; case DF_SIZE: flex_nvm_partition_code = 0x8 | log2; break; case EEBKP_SIZE: flex_nvm_partition_code = log2; break; } if (CMD_ARGC == 3) { unsigned long eex; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], eex); ee1 = ee2 = eex / 2; } else if (CMD_ARGC >= 4) { COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], ee1); COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[3], ee2); } enable = ee1 + ee2 > 0; if (enable) { for (log2 = 2; ; log2++) { if (ee1 + ee2 == (16u << 10) >> log2) break; if (ee1 + ee2 > (16u << 10) >> log2 || log2 >= 9) { LOG_ERROR("Unsupported EEPROM size"); return ERROR_FLASH_OPERATION_FAILED; } } if (ee1 * 3 == ee2) ee_split = 1; else if (ee1 * 7 == ee2) ee_split = 0; else if (ee1 != ee2) { LOG_ERROR("Unsupported EEPROM sizes ratio"); return ERROR_FLASH_OPERATION_FAILED; } ee_size_code = log2 | ee_split << 4; } if (CMD_ARGC >= 5) COMMAND_PARSE_ON_OFF(CMD_ARGV[4], enable); if (enable) load_flex_ram = 0; LOG_INFO("DEPART 0x%" PRIx8 ", EEPROM size code 0x%" PRIx8, flex_nvm_partition_code, ee_size_code); result = kinetis_check_run_mode(k_chip); if (result != ERROR_OK) return result; /* reset error flags */ result = kinetis_ftfx_prepare(target); if (result != ERROR_OK) return result; result = kinetis_ftfx_command(target, FTFX_CMD_PGMPART, load_flex_ram, ee_size_code, flex_nvm_partition_code, 0, 0, 0, 0, 0, 0, NULL); if (result != ERROR_OK) return result; command_print(CMD, "FlexNVM partition set. Please reset MCU."); if (k_chip) { first_nvm_bank = k_chip->num_pflash_blocks; num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks; for (bank_idx = first_nvm_bank; bank_idx < num_blocks; bank_idx++) k_chip->banks[bank_idx].probed = false; /* re-probe before next use */ k_chip->probed = false; } command_print(CMD, "FlexNVM banks will be re-probed to set new data flash size."); return ERROR_OK; } COMMAND_HANDLER(kinetis_fcf_source_handler) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { if (strcmp(CMD_ARGV[0], "write") == 0) allow_fcf_writes = true; else if (strcmp(CMD_ARGV[0], "protection") == 0) allow_fcf_writes = false; else return ERROR_COMMAND_SYNTAX_ERROR; } if (allow_fcf_writes) { command_print(CMD, "Arbitrary Flash Configuration Field writes enabled."); command_print(CMD, "Protection info writes to FCF disabled."); LOG_WARNING("BEWARE: incorrect flash configuration may permanently lock the device."); } else { command_print(CMD, "Protection info writes to Flash Configuration Field enabled."); command_print(CMD, "Arbitrary FCF writes disabled. Mode safe from unwanted locking of the device."); } return ERROR_OK; } COMMAND_HANDLER(kinetis_fopt_handler) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], fcf_fopt); } else { command_print(CMD, "FCF_FOPT 0x%02" PRIx8, fcf_fopt); } return ERROR_OK; } COMMAND_HANDLER(kinetis_create_banks_handler) { if (CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; create_banks = true; return ERROR_OK; } static const struct command_registration kinetis_security_command_handlers[] = { { .name = "check_security", .mode = COMMAND_EXEC, .help = "Check status of device security lock", .usage = "", .handler = kinetis_check_flash_security_status, }, { .name = "halt", .mode = COMMAND_EXEC, .help = "Issue a halt via the MDM-AP", .usage = "", .handler = kinetis_mdm_halt, }, { .name = "mass_erase", .mode = COMMAND_EXEC, .help = "Issue a complete flash erase via the MDM-AP", .usage = "", .handler = kinetis_mdm_mass_erase, }, { .name = "reset", .mode = COMMAND_EXEC, .help = "Issue a reset via the MDM-AP", .usage = "", .handler = kinetis_mdm_reset, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration kinetis_exec_command_handlers[] = { { .name = "mdm", .mode = COMMAND_ANY, .help = "MDM-AP command group", .usage = "", .chain = kinetis_security_command_handlers, }, { .name = "disable_wdog", .mode = COMMAND_EXEC, .help = "Disable the watchdog timer", .usage = "", .handler = kinetis_disable_wdog_handler, }, { .name = "nvm_partition", .mode = COMMAND_EXEC, .help = "Show/set data flash or EEPROM backup size in kilobytes," " set two EEPROM sizes in bytes and FlexRAM loading during reset", .usage = "('info'|'dataflash' size|'eebkp' size) [eesize1 eesize2] ['on'|'off']", .handler = kinetis_nvm_partition, }, { .name = "fcf_source", .mode = COMMAND_EXEC, .help = "Use protection as a source for Flash Configuration Field or allow writing arbitrary values to the FCF" " Mode 'protection' is safe from unwanted locking of the device.", .usage = "['protection'|'write']", .handler = kinetis_fcf_source_handler, }, { .name = "fopt", .mode = COMMAND_EXEC, .help = "FCF_FOPT value source in 'kinetis fcf_source protection' mode", .usage = "[num]", .handler = kinetis_fopt_handler, }, { .name = "create_banks", .mode = COMMAND_CONFIG, .help = "Driver creates additional banks if device with two/four flash blocks is probed", .handler = kinetis_create_banks_handler, .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration kinetis_command_handler[] = { { .name = "kinetis", .mode = COMMAND_ANY, .help = "Kinetis flash controller commands", .usage = "", .chain = kinetis_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver kinetis_flash = { .name = "kinetis", .commands = kinetis_command_handler, .flash_bank_command = kinetis_flash_bank_command, .erase = kinetis_erase, .protect = kinetis_protect, .write = kinetis_write, .read = default_flash_read, .probe = kinetis_probe, .auto_probe = kinetis_auto_probe, .erase_check = kinetis_blank_check, .protect_check = kinetis_protect_check, .info = kinetis_info, .free_driver_priv = kinetis_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/kinetis_ke.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2015 by Ivan Meleca * * ivan@artekit.eu * * * * Modified from kinetis.c * * * * Copyright (C) 2011 by Mathias Kuester * * kesmtp@freenet.de * * * * Copyright (C) 2011 sleep(5) ltd * * tomas@sleepfive.com * * * * Copyright (C) 2012 by Christopher D. Kilgour * * techie at whiterocker.com * * * * Copyright (C) 2013 Nemui Trinomius * * nemuisan_kawausogasuki@live.jp * * * * Copyright (C) 2015 Tomas Vanek * * vanekt@fbl.cz * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/interface.h" #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/arm_adi_v5.h> #include <target/armv7m.h> #include <target/cortex_m.h> /* Addresses */ #define SIM_SRSID 0x40048000 #define ICS_C1 0x40064000 #define ICS_C2 0x40064001 #define ICS_C3 0x40064002 #define ICS_C4 0x40064003 #define ICS_S 0x40064004 #define SIM_BUSDIV 0x40048018 #define SIM_CLKDIV_KE06 0x40048024 #define SIM_CLKDIV_KE04_44_64_80 0x40048024 #define SIM_CLKDIV_KE04_16_20_24 0x4004801C #define WDOG_CS1 0x40052000 #define ICS_C2_BDIV_MASK 0xE0 #define ICS_C2_BDIV_SHIFT 5 #define ICS_C2_BDIV(x) (((uint8_t)(((uint8_t)(x))<<ICS_C2_BDIV_SHIFT))&ICS_C2_BDIV_MASK) #define ICS_S_LOCK_MASK 0x40 #define ICS_C4_SCFTRIM_MASK 0x1 #define SIM_CLKDIV_OUTDIV2_MASK 0x1000000 #define FTMRX_FCLKDIV_FDIV_MASK 0x3F #define FTMRX_FCLKDIV_FDIV_SHIFT 0 #define FTMRX_FCLKDIV_FDIV(x) (((uint8_t)(((uint8_t)(x))<<FTMRX_FCLKDIV_FDIV_SHIFT))&FTMRX_FCLKDIV_FDIV_MASK) #define FTMRX_FCLKDIV_FDIVLCK_MASK 0x40 #define FTMRX_FCLKDIV_FDIVLCK_SHIFT 6 #define FTMRX_FCLKDIV_FDIVLD_MASK 0x80 #define FTMRX_FCLKDIV_FDIVLD_SHIFT 7 #define FTMRX_FSTAT_CCIF_MASK 0x80 #define FTMRX_FSTAT_MGSTAT0_MASK 0x01 #define FTMRX_FSTAT_MGSTAT1_MASK 0x02 /* Commands */ #define FTMRX_CMD_ALLERASED 0x01 #define FTMRX_CMD_BLOCKERASED 0x02 #define FTMRX_CMD_SECTIONERASED 0x03 #define FTMRX_CMD_READONCE 0x04 #define FTMRX_CMD_PROGFLASH 0x06 #define FTMRX_CMD_PROGONCE 0x07 #define FTMRX_CMD_ERASEALL 0x08 #define FTMRX_CMD_ERASEBLOCK 0x09 #define FTMRX_CMD_ERASESECTOR 0x0A #define FTMRX_CMD_UNSECURE 0x0B #define FTMRX_CMD_VERIFYACCESS 0x0C #define FTMRX_CMD_SETMARGINLVL 0x0D #define FTMRX_CMD_SETFACTORYLVL 0x0E #define FTMRX_CMD_CONFIGNVM 0x0F /* Error codes */ #define FTMRX_ERROR_ACCERR 0x20 #define FTMRX_ERROR_FPVIOL 0x10 #define KINETIS_KE_SRSID_FAMID(x) ((x >> 28) & 0x0F) #define KINETIS_KE_SRSID_SUBFAMID(x) ((x >> 24) & 0x0F) #define KINETIS_KE_SRSID_PINCOUNT(x) ((x >> 16) & 0x0F) #define KINETIS_KE_SRSID_KEX2 0x02 #define KINETIS_KE_SRSID_KEX4 0x04 #define KINETIS_KE_SRSID_KEX6 0x06 struct kinetis_ke_flash_bank { uint32_t sector_size; uint32_t protection_size; uint32_t sim_srsid; uint32_t ftmrx_fclkdiv_addr; uint32_t ftmrx_fccobix_addr; uint32_t ftmrx_fstat_addr; uint32_t ftmrx_fprot_addr; uint32_t ftmrx_fccobhi_addr; uint32_t ftmrx_fccoblo_addr; }; #define MDM_REG_STAT 0x00 #define MDM_REG_CTRL 0x04 #define MDM_REG_ID 0xfc #define MDM_STAT_FMEACK (1<<0) #define MDM_STAT_FREADY (1<<1) #define MDM_STAT_SYSSEC (1<<2) #define MDM_STAT_SYSRES (1<<3) #define MDM_STAT_FMEEN (1<<5) #define MDM_STAT_BACKDOOREN (1<<6) #define MDM_STAT_LPEN (1<<7) #define MDM_STAT_VLPEN (1<<8) #define MDM_STAT_LLSMODEXIT (1<<9) #define MDM_STAT_VLLSXMODEXIT (1<<10) #define MDM_STAT_CORE_HALTED (1<<16) #define MDM_STAT_CORE_SLEEPDEEP (1<<17) #define MDM_STAT_CORESLEEPING (1<<18) #define MEM_CTRL_FMEIP (1<<0) #define MEM_CTRL_DBG_DIS (1<<1) #define MEM_CTRL_DBG_REQ (1<<2) #define MEM_CTRL_SYS_RES_REQ (1<<3) #define MEM_CTRL_CORE_HOLD_RES (1<<4) #define MEM_CTRL_VLLSX_DBG_REQ (1<<5) #define MEM_CTRL_VLLSX_DBG_ACK (1<<6) #define MEM_CTRL_VLLSX_STAT_ACK (1<<7) #define MDM_ACCESS_TIMEOUT 3000 /* iterations */ static int kinetis_ke_mdm_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value) { LOG_DEBUG("MDM_REG[0x%02x] <- %08" PRIX32, reg, value); struct adiv5_ap *ap = dap_get_ap(dap, 1); if (!ap) { LOG_DEBUG("MDM: failed to get AP"); return ERROR_FAIL; } int retval = dap_queue_ap_write(ap, reg, value); if (retval != ERROR_OK) { LOG_DEBUG("MDM: failed to queue a write request"); dap_put_ap(ap); return retval; } retval = dap_run(dap); dap_put_ap(ap); if (retval != ERROR_OK) { LOG_DEBUG("MDM: dap_run failed"); return retval; } return ERROR_OK; } static int kinetis_ke_mdm_read_register(struct adiv5_dap *dap, unsigned reg, uint32_t *result) { struct adiv5_ap *ap = dap_get_ap(dap, 1); if (!ap) { LOG_DEBUG("MDM: failed to get AP"); return ERROR_FAIL; } int retval = dap_queue_ap_read(ap, reg, result); if (retval != ERROR_OK) { LOG_DEBUG("MDM: failed to queue a read request"); dap_put_ap(ap); return retval; } retval = dap_run(dap); dap_put_ap(ap); if (retval != ERROR_OK) { LOG_DEBUG("MDM: dap_run failed"); return retval; } LOG_DEBUG("MDM_REG[0x%02x]: %08" PRIX32, reg, *result); return ERROR_OK; } static int kinetis_ke_mdm_poll_register(struct adiv5_dap *dap, unsigned reg, uint32_t mask, uint32_t value) { uint32_t val; int retval; int timeout = MDM_ACCESS_TIMEOUT; do { retval = kinetis_ke_mdm_read_register(dap, reg, &val); if (retval != ERROR_OK || (val & mask) == value) return retval; alive_sleep(1); } while (timeout--); LOG_DEBUG("MDM: polling timed out"); return ERROR_FAIL; } static int kinetis_ke_prepare_flash(struct flash_bank *bank) { struct target *target = bank->target; struct kinetis_ke_flash_bank *kinfo = bank->driver_priv; uint8_t c2, c3, c4, s = 0; uint16_t trim_value = 0; uint16_t timeout = 0; uint32_t bus_clock = 0; uint32_t bus_reg_val = 0; uint32_t bus_reg_addr = 0; uint32_t flash_clk_div; uint8_t fclkdiv; int result; /* * The RM states that the flash clock has to be set to 1MHz for writing and * erasing operations (otherwise it can damage the flash). * This function configures the entire clock tree to make sure we * run at the specified clock. We'll set FEI mode running from the ~32KHz * internal clock. So we need to: * - Trim internal clock. * - Configure the divider for ICSOUTCLK (ICS module). * - Configure the divider to get a bus clock (SIM module). * - Configure the flash clock that depends on the bus clock. * * For MKE02_40 and MKE02_20 we set ICSOUTCLK = 20MHz and bus clock = 20MHz. * For MKE04 and MKE06 we run at ICSOUTCLK = 48MHz and bus clock = 24MHz. */ /* * Trim internal clock */ switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { case KINETIS_KE_SRSID_KEX2: /* Both KE02_20 and KE02_40 should get the same trim value */ trim_value = 0x4C; break; case KINETIS_KE_SRSID_KEX4: trim_value = 0x54; break; case KINETIS_KE_SRSID_KEX6: trim_value = 0x58; break; } result = target_read_u8(target, ICS_C4, &c4); if (result != ERROR_OK) return result; c3 = trim_value; c4 = (c4 & ~(ICS_C4_SCFTRIM_MASK)) | ((trim_value >> 8) & 0x01); result = target_write_u8(target, ICS_C3, c3); if (result != ERROR_OK) return result; result = target_write_u8(target, ICS_C4, c4); if (result != ERROR_OK) return result; result = target_read_u8(target, ICS_S, &s); if (result != ERROR_OK) return result; /* Wait */ while (!(s & ICS_S_LOCK_MASK)) { if (timeout <= 1000) { timeout++; alive_sleep(1); } else { return ERROR_FAIL; } result = target_read_u8(target, ICS_S, &s); if (result != ERROR_OK) return result; } /* ... trim done ... */ /* * Configure SIM (bus clock) */ switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { /* KE02 sub-family operates on SIM_BUSDIV */ case KINETIS_KE_SRSID_KEX2: bus_reg_val = 0; bus_reg_addr = SIM_BUSDIV; bus_clock = 20000000; break; /* KE04 and KE06 sub-family operates on SIM_CLKDIV * Clocks are divided by: * DIV1 = core clock = 48MHz * DIV2 = bus clock = 24Mhz * DIV3 = timer clocks * So we need to configure SIM_CLKDIV, DIV1 and DIV2 value */ case KINETIS_KE_SRSID_KEX4: /* KE04 devices have the SIM_CLKDIV register at a different offset * depending on the pin count. */ switch (KINETIS_KE_SRSID_PINCOUNT(kinfo->sim_srsid)) { /* 16, 20 and 24 pins */ case 1: case 2: case 3: bus_reg_addr = SIM_CLKDIV_KE04_16_20_24; break; /* 44, 64 and 80 pins */ case 5: case 7: case 8: bus_reg_addr = SIM_CLKDIV_KE04_44_64_80; break; default: LOG_ERROR("KE04 - Unknown pin count"); return ERROR_FAIL; } bus_reg_val = SIM_CLKDIV_OUTDIV2_MASK; bus_clock = 24000000; break; case KINETIS_KE_SRSID_KEX6: bus_reg_val = SIM_CLKDIV_OUTDIV2_MASK; bus_reg_addr = SIM_CLKDIV_KE06; bus_clock = 24000000; break; } result = target_write_u32(target, bus_reg_addr, bus_reg_val); if (result != ERROR_OK) return result; /* * Configure ICS to FEI (internal source) */ result = target_read_u8(target, ICS_C2, &c2); if (result != ERROR_OK) return result; c2 &= ~ICS_C2_BDIV_MASK; switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { case KINETIS_KE_SRSID_KEX2: /* Note: since there are two KE02 types, the KE02_40 @ 40MHz and the * KE02_20 @ 20MHz, we divide here the ~40MHz ICSFLLCLK down to 20MHz, * for compatibility. */ c2 |= ICS_C2_BDIV(1); break; case KINETIS_KE_SRSID_KEX4: case KINETIS_KE_SRSID_KEX6: /* For KE04 and KE06, the ICSFLLCLK can be 48MHz. */ c2 |= ICS_C2_BDIV(0); break; } result = target_write_u8(target, ICS_C2, c2); if (result != ERROR_OK) return result; /* Internal clock as reference (IREFS = 1) */ result = target_write_u8(target, ICS_C1, 4); if (result != ERROR_OK) return result; /* Wait for FLL to lock */ result = target_read_u8(target, ICS_S, &s); if (result != ERROR_OK) return result; while (!(s & ICS_S_LOCK_MASK)) { if (timeout <= 1000) { timeout++; alive_sleep(1); } else { return ERROR_FLASH_OPERATION_FAILED; } result = target_read_u8(target, ICS_S, &s); if (result != ERROR_OK) return result; } /* * Configure flash clock to 1MHz. */ flash_clk_div = bus_clock / 1000000L - 1; /* Check if the FCLKDIV register is locked */ result = target_read_u8(target, kinfo->ftmrx_fclkdiv_addr, &fclkdiv); if (result != ERROR_OK) return result; if (!(fclkdiv & FTMRX_FCLKDIV_FDIVLCK_MASK)) { /* Unlocked. Check if the register was configured, and if so, if it has the right value */ if ((fclkdiv & FTMRX_FCLKDIV_FDIVLD_MASK) && ((fclkdiv & FTMRX_FCLKDIV_FDIV_MASK) != FTMRX_FCLKDIV_FDIV(flash_clk_div))) { LOG_WARNING("Flash clock was already set and contains an invalid value."); LOG_WARNING("Please reset the target."); return ERROR_FAIL; } /* Finally, configure the flash clock */ fclkdiv = (fclkdiv & ~(FTMRX_FCLKDIV_FDIV_MASK)) | FTMRX_FCLKDIV_FDIV(flash_clk_div); result = target_write_u8(target, kinfo->ftmrx_fclkdiv_addr, fclkdiv); if (result != ERROR_OK) return result; } else { /* Locked. Check if the current value is correct. */ if ((fclkdiv & FTMRX_FCLKDIV_FDIV_MASK) != FTMRX_FCLKDIV_FDIV(flash_clk_div)) { LOG_WARNING("Flash clock register is locked and contains an invalid value."); LOG_WARNING("Please reset the target."); return ERROR_FAIL; } } LOG_INFO("Flash clock ready"); return ERROR_OK; } static int kinetis_ke_stop_watchdog(struct target *target) { struct working_area *watchdog_algorithm; struct armv7m_algorithm armv7m_info; int retval; uint8_t cs1; static const uint8_t watchdog_code[] = { #include "../../../contrib/loaders/flash/kinetis_ke/kinetis_ke_watchdog.inc" }; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Check if the watchdog is enabled */ retval = target_read_u8(target, WDOG_CS1, &cs1); if (retval != ERROR_OK) return retval; if (!(cs1 & 0x80)) { /* Already stopped */ return ERROR_OK; } /* allocate working area with watchdog code */ if (target_alloc_working_area(target, sizeof(watchdog_code), &watchdog_algorithm) != ERROR_OK) { LOG_WARNING("No working area available for watchdog algorithm"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, watchdog_algorithm->address, sizeof(watchdog_code), watchdog_code); if (retval != ERROR_OK) return retval; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; retval = target_run_algorithm(target, 0, NULL, 0, NULL, watchdog_algorithm->address, 0, 100000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("Error executing Kinetis KE watchdog algorithm"); } else { LOG_INFO("Watchdog stopped"); } target_free_working_area(target, watchdog_algorithm); return retval; } COMMAND_HANDLER(kinetis_ke_disable_wdog_handler) { struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; return kinetis_ke_stop_watchdog(target); } COMMAND_HANDLER(kinetis_ke_mdm_mass_erase) { struct target *target = get_current_target(CMD_CTX); struct cortex_m_common *cortex_m = target_to_cm(target); struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; if (!dap) { LOG_ERROR("Cannot perform mass erase with a high-level adapter"); return ERROR_FAIL; } int retval; /* According to chapter 18.3.7.2 of the KE02 reference manual */ /* assert SRST */ if (jtag_get_reset_config() & RESET_HAS_SRST) adapter_assert_reset(); /* * 1. Reset the device by asserting RESET pin or DAP_CTRL[3] */ retval = kinetis_ke_mdm_write_register(dap, MDM_REG_CTRL, MEM_CTRL_SYS_RES_REQ); if (retval != ERROR_OK) return retval; /* * ... Read the MDM-AP status register until the Flash Ready bit sets... */ retval = kinetis_ke_mdm_poll_register(dap, MDM_REG_STAT, MDM_STAT_FREADY | MDM_STAT_SYSRES, MDM_STAT_FREADY); if (retval != ERROR_OK) { LOG_ERROR("MDM : flash ready timeout"); return retval; } /* * 2. Set DAP_CTRL[0] bit to invoke debug mass erase via SWD * 3. Release reset by deasserting RESET pin or DAP_CTRL[3] bit via SWD. */ retval = kinetis_ke_mdm_write_register(dap, MDM_REG_CTRL, MEM_CTRL_FMEIP); if (retval != ERROR_OK) return retval; /* As a sanity check make sure that device started mass erase procedure */ retval = kinetis_ke_mdm_poll_register(dap, MDM_REG_STAT, MDM_STAT_FMEACK, MDM_STAT_FMEACK); if (retval != ERROR_OK) return retval; /* * 4. Wait till DAP_CTRL[0] bit is cleared (after mass erase completes, * DAP_CTRL[0] bit is cleared automatically). */ retval = kinetis_ke_mdm_poll_register(dap, MDM_REG_CTRL, MEM_CTRL_FMEIP, 0); if (retval != ERROR_OK) return retval; if (jtag_get_reset_config() & RESET_HAS_SRST) adapter_deassert_reset(); return ERROR_OK; } static const uint32_t kinetis_ke_known_mdm_ids[] = { 0x001C0020, /* Kinetis-L/M/V/E/KE Series */ }; /* * This function implements the procedure to connect to * SWD/JTAG on Kinetis K and L series of devices as it is described in * AN4835 "Production Flash Programming Best Practices for Kinetis K- * and L-series MCUs" Section 4.1.1 */ COMMAND_HANDLER(kinetis_ke_check_flash_security_status) { struct target *target = get_current_target(CMD_CTX); struct cortex_m_common *cortex_m = target_to_cm(target); struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; if (!dap) { LOG_WARNING("Cannot check flash security status with a high-level adapter"); return ERROR_OK; } uint32_t val; int retval; /* * ... The MDM-AP ID register can be read to verify that the * connection is working correctly... */ retval = kinetis_ke_mdm_read_register(dap, MDM_REG_ID, &val); if (retval != ERROR_OK) { LOG_ERROR("MDM: failed to read ID register"); goto fail; } bool found = false; for (size_t i = 0; i < ARRAY_SIZE(kinetis_ke_known_mdm_ids); i++) { if (val == kinetis_ke_known_mdm_ids[i]) { found = true; break; } } if (!found) LOG_WARNING("MDM: unknown ID %08" PRIX32, val); /* * ... Read the MDM-AP status register until the Flash Ready bit sets... */ retval = kinetis_ke_mdm_poll_register(dap, MDM_REG_STAT, MDM_STAT_FREADY, MDM_STAT_FREADY); if (retval != ERROR_OK) { LOG_ERROR("MDM: flash ready timeout"); goto fail; } /* * ... Read the System Security bit to determine if security is enabled. * If System Security = 0, then proceed. If System Security = 1, then * communication with the internals of the processor, including the * flash, will not be possible without issuing a mass erase command or * unsecuring the part through other means (backdoor key unlock)... */ retval = kinetis_ke_mdm_read_register(dap, MDM_REG_STAT, &val); if (retval != ERROR_OK) { LOG_ERROR("MDM: failed to read MDM_REG_STAT"); goto fail; } if (val & MDM_STAT_SYSSEC) { jtag_poll_set_enabled(false); LOG_WARNING("*********** ATTENTION! ATTENTION! ATTENTION! ATTENTION! **********"); LOG_WARNING("**** ****"); LOG_WARNING("**** Your Kinetis MCU is in secured state, which means that, ****"); LOG_WARNING("**** with exception for very basic communication, JTAG/SWD ****"); LOG_WARNING("**** interface will NOT work. In order to restore its ****"); LOG_WARNING("**** functionality please issue 'kinetis_ke mdm mass_erase' ****"); LOG_WARNING("**** command, power cycle the MCU and restart OpenOCD. ****"); LOG_WARNING("**** ****"); LOG_WARNING("*********** ATTENTION! ATTENTION! ATTENTION! ATTENTION! **********"); } else { LOG_INFO("MDM: Chip is unsecured. Continuing."); jtag_poll_set_enabled(true); } return ERROR_OK; fail: LOG_ERROR("MDM: Failed to check security status of the MCU. Cannot proceed further"); jtag_poll_set_enabled(false); return retval; } FLASH_BANK_COMMAND_HANDLER(kinetis_ke_flash_bank_command) { struct kinetis_ke_flash_bank *bank_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; LOG_INFO("add flash_bank kinetis_ke %s", bank->name); bank_info = malloc(sizeof(struct kinetis_ke_flash_bank)); memset(bank_info, 0, sizeof(struct kinetis_ke_flash_bank)); bank->driver_priv = bank_info; return ERROR_OK; } /* Kinetis Program-LongWord Microcodes */ static uint8_t kinetis_ke_flash_write_code[] = { #include "../../../contrib/loaders/flash/kinetis_ke/kinetis_ke_flash.inc" }; static int kinetis_ke_write_words(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t words) { struct kinetis_ke_flash_bank *kinfo = bank->driver_priv; struct target *target = bank->target; uint32_t ram_buffer_size = 512 + 16; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; uint32_t flash_code_size; LOG_INFO("Kinetis KE: FLASH Write ..."); /* allocate working area with flash programming code */ if (target_alloc_working_area(target, sizeof(kinetis_ke_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* Patch the FTMRx registers addresses */ flash_code_size = sizeof(kinetis_ke_flash_write_code); buf_set_u32(&kinetis_ke_flash_write_code[flash_code_size-16], 0, 32, kinfo->ftmrx_fstat_addr); buf_set_u32(&kinetis_ke_flash_write_code[flash_code_size-12], 0, 32, kinfo->ftmrx_fccobix_addr); buf_set_u32(&kinetis_ke_flash_write_code[flash_code_size-8], 0, 32, kinfo->ftmrx_fccobhi_addr); buf_set_u32(&kinetis_ke_flash_write_code[flash_code_size-4], 0, 32, kinfo->ftmrx_fccoblo_addr); retval = target_write_buffer(target, write_algorithm->address, sizeof(kinetis_ke_flash_write_code), kinetis_ke_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ if (target_alloc_working_area(target, ram_buffer_size, &source) != ERROR_OK) { /* free working area, write algorithm already allocated */ target_free_working_area(target, write_algorithm); LOG_WARNING("No large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, words); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); retval = target_run_flash_async_algorithm(target, buffer, words, 4, 0, NULL, 4, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { if (buf_get_u32(reg_params[0].value, 0, 32) & FTMRX_ERROR_ACCERR) LOG_ERROR("flash access error"); if (buf_get_u32(reg_params[0].value, 0, 32) & FTMRX_ERROR_FPVIOL) LOG_ERROR("flash protection violation"); } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; } static int kinetis_ke_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { LOG_WARNING("kinetis_ke_protect not supported yet"); /* FIXME: TODO */ if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } return ERROR_FLASH_BANK_INVALID; } static int kinetis_ke_protect_check(struct flash_bank *bank) { struct kinetis_ke_flash_bank *kinfo = bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } int result; uint8_t fprot; uint8_t fpopen, fpldis, fphdis; uint8_t fphs, fpls; uint32_t lprot_size = 0, hprot_size = 0; uint32_t lprot_to = 0, hprot_from = 0; /* read protection register */ result = target_read_u8(bank->target, kinfo->ftmrx_fprot_addr, &fprot); if (result != ERROR_OK) return result; fpopen = fprot & 0x80; fpldis = fprot & 0x04; fphdis = fprot & 0x20; fphs = (fprot >> 3) & 0x03; fpls = fprot & 0x03; /* Fully unprotected? */ if (fpopen && fpldis && fphdis) { LOG_WARNING("No flash protection found."); for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = 0; kinfo->protection_size = 0; } else { LOG_WARNING("Flash protected. FPOPEN=%i FPLDIS=%i FPHDIS=%i FPLS=%i FPHS=%i", fpopen ? 1 : 0, fpldis ? 1 : 0, fphdis ? 1 : 0, fpls, fphs); /* Retrieve which region is protected and how much */ if (fpopen) { if (fpldis == 0) lprot_size = (kinfo->sector_size * 4) << fpls; if (fphdis == 0) hprot_size = (kinfo->sector_size * 2) << fphs; } else { if (fpldis == 1) lprot_size = (kinfo->sector_size * 4) << fpls; if (fphdis == 1) hprot_size = (kinfo->sector_size * 2) << fphs; } kinfo->protection_size = lprot_size + hprot_size; /* lprot_to indicates up to where the lower region is protected */ lprot_to = lprot_size / kinfo->sector_size; /* hprot_from indicates from where the upper region is protected */ hprot_from = (0x8000 - hprot_size) / kinfo->sector_size; for (unsigned int i = 0; i < bank->num_sectors; i++) { /* Check if the sector is in the lower region */ if (bank->sectors[i].offset < 0x4000) { /* Compare the sector start address against lprot_to */ if (lprot_to && (i < lprot_to)) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; /* Check if the sector is between the lower and upper region * OR after the upper region */ } else if (bank->sectors[i].offset < 0x6000 || bank->sectors[i].offset >= 0x8000) { /* If fpopen is 1 then these regions are protected */ if (fpopen) bank->sectors[i].is_protected = 0; else bank->sectors[i].is_protected = 1; /* Check if the sector is in the upper region */ } else if (bank->sectors[i].offset < 0x8000) { if (hprot_from && (i > hprot_from)) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; } } } return ERROR_OK; } static int kinetis_ke_ftmrx_command(struct flash_bank *bank, uint8_t count, uint8_t *FCCOBIX, uint8_t *FCCOBHI, uint8_t *FCCOBLO, uint8_t *fstat) { uint8_t i; int result; struct target *target = bank->target; struct kinetis_ke_flash_bank *kinfo = bank->driver_priv; uint32_t timeout = 0; /* Clear error flags */ result = target_write_u8(target, kinfo->ftmrx_fstat_addr, 0x30); if (result != ERROR_OK) return result; for (i = 0; i < count; i++) { /* Write index */ result = target_write_u8(target, kinfo->ftmrx_fccobix_addr, FCCOBIX[i]); if (result != ERROR_OK) return result; /* Write high part */ result = target_write_u8(target, kinfo->ftmrx_fccobhi_addr, FCCOBHI[i]); if (result != ERROR_OK) return result; /* Write low part (that is not always required) */ if (FCCOBLO) { result = target_write_u8(target, kinfo->ftmrx_fccoblo_addr, FCCOBLO[i]); if (result != ERROR_OK) return result; } } /* Launch the command */ result = target_write_u8(target, kinfo->ftmrx_fstat_addr, 0x80); if (result != ERROR_OK) return result; /* Wait for it to finish */ result = target_read_u8(target, kinfo->ftmrx_fstat_addr, fstat); if (result != ERROR_OK) return result; while (!(*fstat & FTMRX_FSTAT_CCIF_MASK)) { if (timeout <= 1000) { timeout++; alive_sleep(1); } else { return ERROR_FLASH_OPERATION_FAILED; } result = target_read_u8(target, kinfo->ftmrx_fstat_addr, fstat); if (result != ERROR_OK) return result; } return ERROR_OK; } static int kinetis_ke_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int result; uint8_t FCCOBIX[2], FCCOBHI[2], FCCOBLO[2], fstat; bool fcf_erased = false; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first > bank->num_sectors) || (last > bank->num_sectors)) return ERROR_FLASH_OPERATION_FAILED; result = kinetis_ke_prepare_flash(bank); if (result != ERROR_OK) return result; for (unsigned int i = first; i <= last; i++) { FCCOBIX[0] = 0; FCCOBHI[0] = FTMRX_CMD_ERASESECTOR; FCCOBLO[0] = (bank->base + bank->sectors[i].offset) >> 16; FCCOBIX[1] = 1; FCCOBHI[1] = (bank->base + bank->sectors[i].offset) >> 8; FCCOBLO[1] = (bank->base + bank->sectors[i].offset); result = kinetis_ke_ftmrx_command(bank, 2, FCCOBIX, FCCOBHI, FCCOBLO, &fstat); if (result != ERROR_OK) { LOG_WARNING("erase sector %u failed", i); return ERROR_FLASH_OPERATION_FAILED; } if (i == 2) fcf_erased = true; } if (fcf_erased) { LOG_WARNING ("flash configuration field erased, please reset the device"); } return ERROR_OK; } static int kinetis_ke_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int result; uint8_t *new_buffer = NULL; uint32_t words = count / 4; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset > bank->size) return ERROR_FLASH_BANK_INVALID; if (offset & 0x3) { LOG_WARNING("offset 0x%" PRIx32 " breaks the required alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } result = kinetis_ke_stop_watchdog(bank->target); if (result != ERROR_OK) return result; result = kinetis_ke_prepare_flash(bank); if (result != ERROR_OK) return result; if (count & 0x3) { uint32_t old_count = count; count = (old_count | 3) + 1; new_buffer = malloc(count); if (!new_buffer) { LOG_ERROR("odd number of bytes to write and no memory " "for padding buffer"); return ERROR_FAIL; } LOG_INFO("odd number of bytes to write (%" PRIu32 "), extending to %" PRIu32 " " "and padding with 0xff", old_count, count); memset(new_buffer, 0xff, count); buffer = memcpy(new_buffer, buffer, old_count); words++; } result = kinetis_ke_write_words(bank, buffer, offset, words); free(new_buffer); return result; } static int kinetis_ke_probe(struct flash_bank *bank) { int result; uint32_t offset = 0; struct target *target = bank->target; struct kinetis_ke_flash_bank *kinfo = bank->driver_priv; result = target_read_u32(target, SIM_SRSID, &kinfo->sim_srsid); if (result != ERROR_OK) return result; if (KINETIS_KE_SRSID_FAMID(kinfo->sim_srsid) != 0x00) { LOG_ERROR("Unsupported KE family"); return ERROR_FLASH_OPER_UNSUPPORTED; } switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { case KINETIS_KE_SRSID_KEX2: LOG_INFO("KE02 sub-family"); break; case KINETIS_KE_SRSID_KEX4: LOG_INFO("KE04 sub-family"); break; case KINETIS_KE_SRSID_KEX6: LOG_INFO("KE06 sub-family"); break; default: LOG_ERROR("Unsupported KE sub-family"); return ERROR_FLASH_OPER_UNSUPPORTED; } /* We can only retrieve the ke0x part, but there is no way to know * the flash size, so assume the maximum flash size for the entire * sub family. */ bank->base = 0x00000000; kinfo->sector_size = 512; switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { case KINETIS_KE_SRSID_KEX2: /* Max. 64KB */ bank->size = 0x00010000; bank->num_sectors = 128; /* KE02 uses the FTMRH flash controller, * and registers have a different offset from the * FTMRE flash controller. Sort this out here. */ kinfo->ftmrx_fclkdiv_addr = 0x40020000; kinfo->ftmrx_fccobix_addr = 0x40020002; kinfo->ftmrx_fstat_addr = 0x40020006; kinfo->ftmrx_fprot_addr = 0x40020008; kinfo->ftmrx_fccobhi_addr = 0x4002000A; kinfo->ftmrx_fccoblo_addr = 0x4002000B; break; case KINETIS_KE_SRSID_KEX6: case KINETIS_KE_SRSID_KEX4: /* Max. 128KB */ bank->size = 0x00020000; bank->num_sectors = 256; /* KE04 and KE06 use the FTMRE flash controller, * and registers have a different offset from the * FTMRH flash controller. Sort this out here. */ kinfo->ftmrx_fclkdiv_addr = 0x40020003; kinfo->ftmrx_fccobix_addr = 0x40020001; kinfo->ftmrx_fstat_addr = 0x40020005; kinfo->ftmrx_fprot_addr = 0x4002000B; kinfo->ftmrx_fccobhi_addr = 0x40020009; kinfo->ftmrx_fccoblo_addr = 0x40020008; break; } free(bank->sectors); assert(bank->num_sectors > 0); bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = kinfo->sector_size; offset += kinfo->sector_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } return ERROR_OK; } static int kinetis_ke_auto_probe(struct flash_bank *bank) { struct kinetis_ke_flash_bank *kinfo = bank->driver_priv; if (kinfo->sim_srsid) return ERROR_OK; return kinetis_ke_probe(bank); } static int kinetis_ke_info(struct flash_bank *bank, struct command_invocation *cmd) { command_print_sameline(cmd, "%s driver for flash bank %s at " TARGET_ADDR_FMT, bank->driver->name, bank->name, bank->base); return ERROR_OK; } static int kinetis_ke_blank_check(struct flash_bank *bank) { uint8_t FCCOBIX[3], FCCOBHI[3], FCCOBLO[3], fstat; uint16_t longwords = 0; int result; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } result = kinetis_ke_prepare_flash(bank); if (result != ERROR_OK) return result; /* check if whole bank is blank */ FCCOBIX[0] = 0; FCCOBHI[0] = FTMRX_CMD_ALLERASED; result = kinetis_ke_ftmrx_command(bank, 1, FCCOBIX, FCCOBHI, NULL, &fstat); if (result != ERROR_OK) return result; if (fstat & (FTMRX_FSTAT_MGSTAT0_MASK | FTMRX_FSTAT_MGSTAT1_MASK)) { /* the whole bank is not erased, check sector-by-sector */ for (unsigned int i = 0; i < bank->num_sectors; i++) { FCCOBIX[0] = 0; FCCOBHI[0] = FTMRX_CMD_SECTIONERASED; FCCOBLO[0] = (bank->base + bank->sectors[i].offset) >> 16; FCCOBIX[1] = 1; FCCOBHI[1] = (bank->base + bank->sectors[i].offset) >> 8; FCCOBLO[1] = (bank->base + bank->sectors[i].offset); longwords = 128; FCCOBIX[2] = 2; FCCOBHI[2] = longwords >> 8; FCCOBLO[2] = longwords; result = kinetis_ke_ftmrx_command(bank, 3, FCCOBIX, FCCOBHI, FCCOBLO, &fstat); if (result == ERROR_OK) { bank->sectors[i].is_erased = !(fstat & (FTMRX_FSTAT_MGSTAT0_MASK | FTMRX_FSTAT_MGSTAT1_MASK)); } else { LOG_DEBUG("Ignoring error on PFlash sector blank-check"); bank->sectors[i].is_erased = -1; } } } else { /* the whole bank is erased, update all sectors */ for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; } return ERROR_OK; } static const struct command_registration kinetis_ke_security_command_handlers[] = { { .name = "check_security", .mode = COMMAND_EXEC, .help = "Check status of device security lock", .usage = "", .handler = kinetis_ke_check_flash_security_status, }, { .name = "mass_erase", .mode = COMMAND_EXEC, .help = "Issue a complete flash erase via the MDM-AP", .usage = "", .handler = kinetis_ke_mdm_mass_erase, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration kinetis_ke_exec_command_handlers[] = { { .name = "mdm", .mode = COMMAND_ANY, .help = "MDM-AP command group", .usage = "", .chain = kinetis_ke_security_command_handlers, }, { .name = "disable_wdog", .mode = COMMAND_EXEC, .help = "Disable the watchdog timer", .usage = "", .handler = kinetis_ke_disable_wdog_handler, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration kinetis_ke_command_handler[] = { { .name = "kinetis_ke", .mode = COMMAND_ANY, .help = "Kinetis KE flash controller commands", .usage = "", .chain = kinetis_ke_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver kinetis_ke_flash = { .name = "kinetis_ke", .commands = kinetis_ke_command_handler, .flash_bank_command = kinetis_ke_flash_bank_command, .erase = kinetis_ke_erase, .protect = kinetis_ke_protect, .write = kinetis_ke_write, .read = default_flash_read, .probe = kinetis_ke_probe, .auto_probe = kinetis_ke_auto_probe, .erase_check = kinetis_ke_blank_check, .protect_check = kinetis_ke_protect_check, .info = kinetis_ke_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/lpc2000.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * LPC1700 support Copyright (C) 2009 by Audrius Urmanavicius * * didele.deze@gmail.com * * * * LPC1100 variant and auto-probing support Copyright (C) 2014 * * by Cosmin Gorgovan cosmin [at] linux-geek [dot] org * * * * LPC800/LPC1500/LPC54100 support Copyright (C) 2013/2014 * * by Nemui Trinomius * * nemuisan_kawausogasuki@live.jp * * * * LPC8N04/HNS31xx support Copyright (C) 2018 * * by Jean-Christian de Rivaz jcdr [at] innodelec [dot] ch * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/arm_opcodes.h> #include <target/armv7m.h> /** * @file * flash programming support for NXP LPC8xx,LPC1xxx,LPC4xxx,LP5410x,LPC2xxx and NHS31xx devices. * * @todo Provide a way to update CCLK after declaring the flash bank. The value which is correct after chip reset will * rarely still work right after the clocks switch to use the PLL (e.g. 4MHz --> 100 MHz). */ /* * currently supported devices: * variant 1 (lpc2000_v1): * - 2104 | 5 | 6 * - 2114 | 9 * - 2124 | 9 * - 2194 * - 2212 | 4 * - 2292 | 4 * * variant 2 (lpc2000_v2): * - 213x * - 214x * - 2101 | 2 | 3 * - 2364 | 6 | 8 * - 2378 * * lpc1700: * - 175x * - 176x (tested with LPC1768) * - 177x * - 178x (tested with LPC1788) * * lpc4000: (lpc1700's alias) * - 407x * - 408x (tested with LPC4088) * * lpc4300: (also available as lpc1800 - alias) * - 43x2 | 3 | 5 | 7 (tested with LPC4337/LPC4357) * - 18x2 | 3 | 5 | 7 * * lpc800: * - 810 | 1 | 2 (tested with LPC810/LPC811/LPC812) * - 822 | 4 (tested with LPC824) * - 8N04 * - NHS31xx (tested with NHS3100) * - 844 | 5 (tested with LPC845) * * lpc1100: * - 11xx * - 11Axx * - 11Cxx * - 11Dxx * - 11Exx * - 11Uxx (tested with LPC11U34) * - 131x * - 134x * * lpc1500: * - 15x7 | 8 | 9 (tested with LPC1549) * * lpc54100: * - 54101 | 2 (tested with LPC54102) * * The auto variant auto-detects parts from the following series: * - 11xx * - 11Axx * - 11Cxx * - 11Dxx * - 11Exx * - 11Uxx * - 131x * - 134x * - 175x * - 176x * - 177x * - 178x * - 407x * - 408x * - 81x * - 82x * - 8N04 * - NHS31xx */ /* Part IDs for autodetection */ /* A script which can automatically extract part ids from user manuals is available here: * https://github.com/lgeek/lpc_part_ids */ #define LPC1110_1 0x0A07102B #define LPC1110_2 0x1A07102B #define LPC1111_002_1 0x0A16D02B #define LPC1111_002_2 0x1A16D02B #define LPC1111_101_1 0x041E502B #define LPC1111_101_2 0x2516D02B #define LPC1111_103_1 0x00010013 #define LPC1111_201_1 0x0416502B #define LPC1111_201_2 0x2516902B #define LPC1111_203_1 0x00010012 #define LPC1112_101_1 0x042D502B #define LPC1112_101_2 0x2524D02B #define LPC1112_102_1 0x0A24902B #define LPC1112_102_2 0x1A24902B #define LPC1112_103_1 0x00020023 #define LPC1112_201_1 0x0425502B #define LPC1112_201_2 0x2524902B #define LPC1112_203_1 0x00020022 #define LPC1113_201_1 0x0434502B #define LPC1113_201_2 0x2532902B #define LPC1113_203_1 0x00030032 #define LPC1113_301_1 0x0434102B #define LPC1113_301_2 0x2532102B #define LPC1113_303_1 0x00030030 #define LPC1114_102_1 0x0A40902B #define LPC1114_102_2 0x1A40902B #define LPC1114_201_1 0x0444502B #define LPC1114_201_2 0x2540902B #define LPC1114_203_1 0x00040042 #define LPC1114_301_1 0x0444102B #define LPC1114_301_2 0x2540102B #define LPC1114_303_1 0x00040040 #define LPC1114_323_1 0x00040060 #define LPC1114_333_1 0x00040070 #define LPC1115_303_1 0x00050080 #define LPC11A02_1 0x4D4C802B #define LPC11A04_1 0x4D80002B #define LPC11A11_001_1 0x455EC02B #define LPC11A12_101_1 0x4574802B #define LPC11A13_201_1 0x458A402B #define LPC11A14_301_1 0x35A0002B #define LPC11A14_301_2 0x45A0002B #define LPC11C12_301_1 0x1421102B #define LPC11C14_301_1 0x1440102B #define LPC11C22_301_1 0x1431102B #define LPC11C24_301_1 0x1430102B #define LPC11E11_101 0x293E902B #define LPC11E12_201 0x2954502B #define LPC11E13_301 0x296A102B #define LPC11E14_401 0x2980102B #define LPC11E36_501 0x00009C41 #define LPC11E37_401 0x00007C45 #define LPC11E37_501 0x00007C41 #define LPC11U12_201_1 0x095C802B #define LPC11U12_201_2 0x295C802B #define LPC11U13_201_1 0x097A802B #define LPC11U13_201_2 0x297A802B #define LPC11U14_201_1 0x0998802B #define LPC11U14_201_2 0x2998802B #define LPC11U23_301 0x2972402B #define LPC11U24_301 0x2988402B #define LPC11U24_401 0x2980002B #define LPC11U34_311 0x0003D440 #define LPC11U34_421 0x0001CC40 #define LPC11U35_401 0x0001BC40 #define LPC11U35_501 0x0000BC40 #define LPC11U36_401 0x00019C40 #define LPC11U37_401 0x00017C40 #define LPC11U37H_401 0x00007C44 #define LPC11U37_501 0x00007C40 #define LPC11E66 0x0000DCC1 #define LPC11E67 0x0000BC81 #define LPC11E68 0x00007C01 #define LPC11U66 0x0000DCC8 #define LPC11U67_1 0x0000BC88 #define LPC11U67_2 0x0000BC80 #define LPC11U68_1 0x00007C08 #define LPC11U68_2 0x00007C00 #define LPC1311 0x2C42502B #define LPC1311_1 0x1816902B #define LPC1313 0x2C40102B #define LPC1313_1 0x1830102B #define LPC1315 0x3A010523 #define LPC1316 0x1A018524 #define LPC1317 0x1A020525 #define LPC1342 0x3D01402B #define LPC1343 0x3D00002B #define LPC1343_1 0x3000002B #define LPC1345 0x28010541 #define LPC1346 0x08018542 #define LPC1347 0x08020543 #define LPC1751_1 0x25001110 #define LPC1751_2 0x25001118 #define LPC1752 0x25001121 #define LPC1754 0x25011722 #define LPC1756 0x25011723 #define LPC1758 0x25013F37 #define LPC1759 0x25113737 #define LPC1763 0x26012033 #define LPC1764 0x26011922 #define LPC1765 0x26013733 #define LPC1766 0x26013F33 #define LPC1767 0x26012837 #define LPC1768 0x26013F37 #define LPC1769 0x26113F37 #define LPC1774 0x27011132 #define LPC1776 0x27191F43 #define LPC1777 0x27193747 #define LPC1778 0x27193F47 #define LPC1785 0x281D1743 #define LPC1786 0x281D1F43 #define LPC1787 0x281D3747 #define LPC1788 0x281D3F47 #define LPC4072 0x47011121 #define LPC4074 0x47011132 #define LPC4076 0x47191F43 #define LPC4078 0x47193F47 #define LPC4088 0x481D3F47 #define LPC810_021 0x00008100 #define LPC811_001 0x00008110 #define LPC812_101 0x00008120 #define LPC812_101_1 0x00008121 #define LPC812_101_2 0x00008122 #define LPC812_101_3 0x00008123 #define LPC822_101 0x00008221 #define LPC822_101_1 0x00008222 #define LPC824_201 0x00008241 #define LPC824_201_1 0x00008242 #define LPC8N04 0x00008A04 #define NHS3100 0x4e310020 #define NHS3152 0x4e315220 #define NHS3153 0x4e315320 /* Only specified in Rev.1 of the datasheet */ #define LPC844_201 0x00008441 #define LPC844_201_1 0x00008442 #define LPC844_201_2 0x00008444 #define LPC845_301 0x00008451 #define LPC845_301_1 0x00008452 #define LPC845_301_2 0x00008453 #define LPC845_301_3 0x00008454 #define IAP_CODE_LEN 0x34 #define LPC11XX_REG_SECTORS 24 typedef enum { LPC2000_V1, LPC2000_V2, LPC1700, LPC4300, LPC800, LPC1100, LPC1500, LPC54100, LPC_AUTO, } lpc2000_variant; struct lpc2000_flash_bank { lpc2000_variant variant; uint32_t cclk; int cmd51_dst_boundary; int calc_checksum; uint32_t cmd51_max_buffer; int checksum_vector; uint32_t iap_max_stack; uint32_t lpc4300_bank; uint32_t iap_entry_alternative; bool probed; }; enum lpc2000_status_codes { LPC2000_CMD_SUCCESS = 0, LPC2000_INVALID_COMMAND = 1, LPC2000_SRC_ADDR_ERROR = 2, LPC2000_DST_ADDR_ERROR = 3, LPC2000_SRC_ADDR_NOT_MAPPED = 4, LPC2000_DST_ADDR_NOT_MAPPED = 5, LPC2000_COUNT_ERROR = 6, LPC2000_INVALID_SECTOR = 7, LPC2000_SECTOR_NOT_BLANK = 8, LPC2000_SECTOR_NOT_PREPARED = 9, LPC2000_COMPARE_ERROR = 10, LPC2000_BUSY = 11, LPC2000_PARAM_ERROR = 12, LPC2000_ADDR_ERROR = 13, LPC2000_ADDR_NOT_MAPPED = 14, LPC2000_CMD_NOT_LOCKED = 15, LPC2000_INVALID_CODE = 16, LPC2000_INVALID_BAUD_RATE = 17, LPC2000_INVALID_STOP_BIT = 18, LPC2000_CRP_ENABLED = 19, LPC2000_INVALID_FLASH_UNIT = 20, LPC2000_USER_CODE_CHECKSUM = 21, LCP2000_ERROR_SETTING_ACTIVE_PARTITION = 22, }; static int lpc2000_build_sector_list(struct flash_bank *bank) { struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; uint32_t offset = 0; /* default to a 4096 write buffer */ lpc2000_info->cmd51_max_buffer = 4096; if (lpc2000_info->variant == LPC2000_V1) { lpc2000_info->cmd51_dst_boundary = 512; lpc2000_info->checksum_vector = 5; lpc2000_info->iap_max_stack = 128; /* variant 1 has different layout for 128kb and 256kb flashes */ if (bank->size == 128 * 1024) { bank->num_sectors = 16; bank->sectors = malloc(sizeof(struct flash_sector) * 16); for (int i = 0; i < 16; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = 8 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } } else if (bank->size == 256 * 1024) { bank->num_sectors = 18; bank->sectors = malloc(sizeof(struct flash_sector) * 18); for (int i = 0; i < 8; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = 8 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } for (int i = 8; i < 10; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = 64 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } for (int i = 10; i < 18; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = 8 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } } else { LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } } else if (lpc2000_info->variant == LPC2000_V2) { lpc2000_info->cmd51_dst_boundary = 256; lpc2000_info->checksum_vector = 5; lpc2000_info->iap_max_stack = 128; /* variant 2 has a uniform layout, only number of sectors differs */ switch (bank->size) { case 4 * 1024: lpc2000_info->cmd51_max_buffer = 1024; bank->num_sectors = 1; break; case 8 * 1024: lpc2000_info->cmd51_max_buffer = 1024; bank->num_sectors = 2; break; case 16 * 1024: bank->num_sectors = 4; break; case 32 * 1024: bank->num_sectors = 8; break; case 64 * 1024: bank->num_sectors = 9; break; case 128 * 1024: bank->num_sectors = 11; break; case 256 * 1024: bank->num_sectors = 15; break; case 500 * 1024: bank->num_sectors = 27; break; case 512 * 1024: case 504 * 1024: bank->num_sectors = 28; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); break; } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { if (i < 8) { bank->sectors[i].offset = offset; bank->sectors[i].size = 4 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } else if (i < 22) { bank->sectors[i].offset = offset; bank->sectors[i].size = 32 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } else if (i < 28) { bank->sectors[i].offset = offset; bank->sectors[i].size = 4 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } } } else if (lpc2000_info->variant == LPC1700) { lpc2000_info->cmd51_dst_boundary = 256; lpc2000_info->checksum_vector = 7; lpc2000_info->iap_max_stack = 128; switch (bank->size) { case 4 * 1024: lpc2000_info->cmd51_max_buffer = 256; bank->num_sectors = 1; break; case 8 * 1024: lpc2000_info->cmd51_max_buffer = 512; bank->num_sectors = 2; break; case 16 * 1024: lpc2000_info->cmd51_max_buffer = 512; bank->num_sectors = 4; break; case 32 * 1024: lpc2000_info->cmd51_max_buffer = 1024; bank->num_sectors = 8; break; case 64 * 1024: bank->num_sectors = 16; break; case 128 * 1024: bank->num_sectors = 18; break; case 256 * 1024: bank->num_sectors = 22; break; case 512 * 1024: bank->num_sectors = 30; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; /* sectors 0-15 are 4kB-sized, 16 and above are 32kB-sized for LPC17xx/LPC40xx devices */ bank->sectors[i].size = (i < 16) ? 4 * 1024 : 32 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } } else if (lpc2000_info->variant == LPC4300) { lpc2000_info->cmd51_dst_boundary = 512; lpc2000_info->checksum_vector = 7; lpc2000_info->iap_max_stack = 208; switch (bank->size) { case 256 * 1024: bank->num_sectors = 11; break; case 384 * 1024: bank->num_sectors = 13; break; case 512 * 1024: bank->num_sectors = 15; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; /* sectors 0-7 are 8kB-sized, 8 and above are 64kB-sized for LPC43xx devices */ bank->sectors[i].size = (i < 8) ? 8 * 1024 : 64 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } } else if (lpc2000_info->variant == LPC800) { lpc2000_info->cmd51_dst_boundary = 64; lpc2000_info->checksum_vector = 7; lpc2000_info->iap_max_stack = 208; /* 148byte for LPC81x,208byte for LPC82x. */ lpc2000_info->cmd51_max_buffer = 256; /* smallest MCU in the series, LPC810, has 1 kB of SRAM */ switch (bank->size) { case 4 * 1024: bank->num_sectors = 4; break; case 8 * 1024: bank->num_sectors = 8; break; case 16 * 1024: bank->num_sectors = 16; break; case 30 * 1024: lpc2000_info->cmd51_max_buffer = 1024; /* For LPC8N04 and NHS31xx, have 8kB of SRAM */ bank->num_sectors = 30; /* There have only 30kB of writable Flash out of 32kB */ break; case 32 * 1024: lpc2000_info->cmd51_max_buffer = 1024; /* For LPC824, has 8kB of SRAM */ bank->num_sectors = 32; break; case 64 * 1024: lpc2000_info->cmd51_max_buffer = 1024; /* For LPC844, has 8kB of SRAM */ bank->num_sectors = 64; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; /* all sectors are 1kB-sized for LPC8xx devices */ bank->sectors[i].size = 1 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } } else if (lpc2000_info->variant == LPC1100) { lpc2000_info->cmd51_dst_boundary = 256; lpc2000_info->checksum_vector = 7; lpc2000_info->iap_max_stack = 128; if ((bank->size % (4 * 1024)) != 0) { LOG_ERROR("BUG: unknown bank->size encountered,\nLPC1100 flash size must be a multiple of 4096"); exit(-1); } lpc2000_info->cmd51_max_buffer = 512; /* smallest MCU in the series, LPC1110, has 1 kB of SRAM */ unsigned int large_sectors = 0; unsigned int normal_sectors = bank->size / 4096; if (normal_sectors > LPC11XX_REG_SECTORS) { large_sectors = (normal_sectors - LPC11XX_REG_SECTORS) / 8; normal_sectors = LPC11XX_REG_SECTORS; } bank->num_sectors = normal_sectors + large_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = (i < LPC11XX_REG_SECTORS ? 4 : 32) * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } } else if (lpc2000_info->variant == LPC1500) { lpc2000_info->cmd51_dst_boundary = 256; lpc2000_info->checksum_vector = 7; lpc2000_info->iap_max_stack = 128; switch (bank->size) { case 64 * 1024: bank->num_sectors = 16; break; case 128 * 1024: bank->num_sectors = 32; break; case 256 * 1024: bank->num_sectors = 64; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; /* all sectors are 4kB-sized */ bank->sectors[i].size = 4 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } } else if (lpc2000_info->variant == LPC54100) { lpc2000_info->cmd51_dst_boundary = 256; lpc2000_info->checksum_vector = 7; lpc2000_info->iap_max_stack = 128; switch (bank->size) { case 256 * 1024: bank->num_sectors = 8; break; case 512 * 1024: bank->num_sectors = 16; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; /* all sectors are 32kB-sized */ bank->sectors[i].size = 32 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } } else { LOG_ERROR("BUG: unknown lpc2000_info->variant encountered"); exit(-1); } return ERROR_OK; } /* this function allocates and initializes working area used for IAP algorithm * uses 52 + max IAP stack bytes working area * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait) * 0x8 to 0x1f: command parameter table (1+5 words) * 0x20 to 0x33: command result table (1+4 words) * 0x34 to 0xb3|0x104: stack * (128b needed for lpc1xxx/2000/5410x, 208b for lpc43xx/lpc82x and 148b for lpc81x) */ static int lpc2000_iap_working_area_init(struct flash_bank *bank, struct working_area **iap_working_area) { struct target *target = bank->target; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; if (target_alloc_working_area(target, IAP_CODE_LEN + lpc2000_info->iap_max_stack, iap_working_area) != ERROR_OK) { LOG_ERROR("no working area specified, can't write LPC2000 internal flash"); return ERROR_FLASH_OPERATION_FAILED; } uint8_t jump_gate[8]; /* write IAP code to working area */ switch (lpc2000_info->variant) { case LPC800: case LPC1100: case LPC1500: case LPC1700: case LPC4300: case LPC54100: case LPC_AUTO: target_buffer_set_u32(target, jump_gate, ARMV4_5_T_BX(12)); target_buffer_set_u32(target, jump_gate + 4, ARMV5_T_BKPT(0)); break; case LPC2000_V1: case LPC2000_V2: target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12)); target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0)); break; default: LOG_ERROR("BUG: unknown lpc2000_info->variant encountered"); exit(-1); } int retval = target_write_memory(target, (*iap_working_area)->address, 4, 2, jump_gate); if (retval != ERROR_OK) { LOG_ERROR("Write memory at address " TARGET_ADDR_FMT " failed (check work_area definition)", (*iap_working_area)->address); target_free_working_area(target, *iap_working_area); } return retval; } /* call LPC8xx/LPC1xxx/LPC4xxx/LPC5410x/LPC2000 IAP function */ static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_working_area, int code, uint32_t param_table[5], uint32_t result_table[4]) { struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; struct target *target = bank->target; struct arm_algorithm arm_algo; /* for LPC2000 */ struct armv7m_algorithm armv7m_info; /* for LPC8xx/LPC1xxx/LPC4xxx/LPC5410x */ uint32_t iap_entry_point = 0; /* to make compiler happier */ switch (lpc2000_info->variant) { case LPC800: case LPC1100: case LPC1700: case LPC_AUTO: armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; iap_entry_point = 0x1fff1ff1; break; case LPC1500: case LPC54100: armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; iap_entry_point = 0x03000205; break; case LPC2000_V1: case LPC2000_V2: arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; iap_entry_point = 0x7ffffff1; break; case LPC4300: armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; /* read out IAP entry point from ROM driver table at 0x10400100 */ target_read_u32(target, 0x10400100, &iap_entry_point); break; default: LOG_ERROR("BUG: unknown lpc2000->variant encountered"); exit(-1); } if (lpc2000_info->iap_entry_alternative != 0x0) iap_entry_point = lpc2000_info->iap_entry_alternative; struct mem_param mem_params[2]; /* command parameter table */ init_mem_param(&mem_params[0], iap_working_area->address + 8, 6 * 4, PARAM_OUT); target_buffer_set_u32(target, mem_params[0].value, code); target_buffer_set_u32(target, mem_params[0].value + 0x04, param_table[0]); target_buffer_set_u32(target, mem_params[0].value + 0x08, param_table[1]); target_buffer_set_u32(target, mem_params[0].value + 0x0c, param_table[2]); target_buffer_set_u32(target, mem_params[0].value + 0x10, param_table[3]); target_buffer_set_u32(target, mem_params[0].value + 0x14, param_table[4]); struct reg_param reg_params[5]; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, iap_working_area->address + 0x08); /* command result table */ init_mem_param(&mem_params[1], iap_working_area->address + 0x20, 5 * 4, PARAM_IN); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, iap_working_area->address + 0x20); /* IAP entry point */ init_reg_param(®_params[2], "r12", 32, PARAM_OUT); buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point); switch (lpc2000_info->variant) { case LPC800: case LPC1100: case LPC1500: case LPC1700: case LPC4300: case LPC54100: case LPC_AUTO: /* IAP stack */ init_reg_param(®_params[3], "sp", 32, PARAM_OUT); buf_set_u32(reg_params[3].value, 0, 32, iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack); /* return address */ init_reg_param(®_params[4], "lr", 32, PARAM_OUT); buf_set_u32(reg_params[4].value, 0, 32, (iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */ target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address, 0, 10000, &armv7m_info); break; case LPC2000_V1: case LPC2000_V2: /* IAP stack */ init_reg_param(®_params[3], "sp_svc", 32, PARAM_OUT); buf_set_u32(reg_params[3].value, 0, 32, iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack); /* return address */ init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT); buf_set_u32(reg_params[4].value, 0, 32, iap_working_area->address + 0x04); target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address, iap_working_area->address + 0x4, 10000, &arm_algo); break; default: LOG_ERROR("BUG: unknown lpc2000->variant encountered"); exit(-1); } int status_code = target_buffer_get_u32(target, mem_params[1].value); result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04); result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08); result_table[2] = target_buffer_get_u32(target, mem_params[1].value + 0x0c); result_table[3] = target_buffer_get_u32(target, mem_params[1].value + 0x10); LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ") completed with result = %8.8x", code, param_table[0], param_table[1], param_table[2], param_table[3], param_table[4], status_code); destroy_mem_param(&mem_params[0]); destroy_mem_param(&mem_params[1]); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return status_code; } static int lpc2000_iap_blank_check(struct flash_bank *bank, unsigned int first, unsigned int last) { if (last >= bank->num_sectors) return ERROR_FLASH_SECTOR_INVALID; uint32_t param_table[5] = {0}; uint32_t result_table[4]; struct working_area *iap_working_area; int retval = lpc2000_iap_working_area_init(bank, &iap_working_area); if (retval != ERROR_OK) return retval; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; if (lpc2000_info->variant == LPC4300) param_table[2] = lpc2000_info->lpc4300_bank; for (unsigned int i = first; i <= last && retval == ERROR_OK; i++) { /* check single sector */ param_table[0] = param_table[1] = i; int status_code = lpc2000_iap_call(bank, iap_working_area, 53, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: bank->sectors[i].is_erased = 1; break; case LPC2000_SECTOR_NOT_BLANK: bank->sectors[i].is_erased = 0; break; case LPC2000_INVALID_SECTOR: bank->sectors[i].is_erased = 0; break; case LPC2000_BUSY: retval = ERROR_FLASH_BUSY; break; default: LOG_ERROR("BUG: unknown LPC2000 status code %i", status_code); exit(-1); } } struct target *target = bank->target; target_free_working_area(target, iap_working_area); return retval; } /* * flash bank lpc2000 <base> <size> 0 0 <target#> <lpc_variant> <cclk> [calc_checksum] */ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command) { if (CMD_ARGC < 8) return ERROR_COMMAND_SYNTAX_ERROR; struct lpc2000_flash_bank *lpc2000_info = calloc(1, sizeof(*lpc2000_info)); lpc2000_info->probed = false; bank->driver_priv = lpc2000_info; if (strcmp(CMD_ARGV[6], "lpc2000_v1") == 0) { lpc2000_info->variant = LPC2000_V1; } else if (strcmp(CMD_ARGV[6], "lpc2000_v2") == 0) { lpc2000_info->variant = LPC2000_V2; } else if (strcmp(CMD_ARGV[6], "lpc1700") == 0 || strcmp(CMD_ARGV[6], "lpc4000") == 0) { lpc2000_info->variant = LPC1700; } else if (strcmp(CMD_ARGV[6], "lpc1800") == 0 || strcmp(CMD_ARGV[6], "lpc4300") == 0) { lpc2000_info->variant = LPC4300; } else if (strcmp(CMD_ARGV[6], "lpc800") == 0) { lpc2000_info->variant = LPC800; } else if (strcmp(CMD_ARGV[6], "lpc1100") == 0) { lpc2000_info->variant = LPC1100; } else if (strcmp(CMD_ARGV[6], "lpc1500") == 0) { lpc2000_info->variant = LPC1500; } else if (strcmp(CMD_ARGV[6], "lpc54100") == 0) { lpc2000_info->variant = LPC54100; } else if (strcmp(CMD_ARGV[6], "auto") == 0) { lpc2000_info->variant = LPC_AUTO; } else { LOG_ERROR("unknown LPC2000 variant: %s", CMD_ARGV[6]); free(lpc2000_info); return ERROR_FLASH_BANK_INVALID; } /* Maximum size required for the IAP stack. This value only gets used when probing, only for auto, lpc1100 and lpc1700. We use the maximum size for any part supported by the driver(!) to be safe in case the auto variant is mistakenly used on a MCU from one of the series for which we don't support auto-probing. */ lpc2000_info->iap_max_stack = 208; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], lpc2000_info->cclk); lpc2000_info->calc_checksum = 0; uint32_t temp_base = 0; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], temp_base); if (temp_base >= 0x1B000000) lpc2000_info->lpc4300_bank = 1; /* bank B */ else lpc2000_info->lpc4300_bank = 0; /* bank A */ if (CMD_ARGC >= 9) { if (strcmp(CMD_ARGV[8], "calc_checksum") == 0) lpc2000_info->calc_checksum = 1; } if (CMD_ARGC >= 10 && !lpc2000_info->iap_entry_alternative) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[9], lpc2000_info->iap_entry_alternative); return ERROR_OK; } static int lpc2000_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; uint32_t param_table[5] = {0}; param_table[0] = first; param_table[1] = last; if (lpc2000_info->variant == LPC4300) param_table[2] = lpc2000_info->lpc4300_bank; else param_table[2] = lpc2000_info->cclk; uint32_t result_table[4]; struct working_area *iap_working_area; int retval = lpc2000_iap_working_area_init(bank, &iap_working_area); if (retval != ERROR_OK) return retval; if (lpc2000_info->variant == LPC4300) /* Init IAP Anyway */ lpc2000_iap_call(bank, iap_working_area, 49, param_table, result_table); /* Prepare sectors */ int status_code = lpc2000_iap_call(bank, iap_working_area, 50, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: retval = ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (retval == ERROR_OK) { /* Erase sectors */ param_table[2] = lpc2000_info->cclk; if (lpc2000_info->variant == LPC4300) param_table[3] = lpc2000_info->lpc4300_bank; status_code = lpc2000_iap_call(bank, iap_working_area, 52, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: retval = ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 erase sectors returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; } } struct target *target = bank->target; target_free_working_area(target, iap_working_area); return retval; } static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; uint32_t dst_min_alignment = lpc2000_info->cmd51_dst_boundary; if (offset % dst_min_alignment) { LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32, offset, dst_min_alignment); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } int first_sector = 0; int last_sector = 0; for (unsigned int i = 0; i < bank->num_sectors; i++) { if (offset >= bank->sectors[i].offset) first_sector = i; if (offset + DIV_ROUND_UP(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset) last_sector = i; } LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector); /* check if exception vectors should be flashed */ if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum) { assert(lpc2000_info->checksum_vector < 8); uint32_t checksum = 0; for (int i = 0; i < 8; i++) { LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4, buf_get_u32(buffer + (i * 4), 0, 32)); if (i != lpc2000_info->checksum_vector) checksum += buf_get_u32(buffer + (i * 4), 0, 32); } checksum = 0 - checksum; LOG_DEBUG("checksum: 0x%8.8" PRIx32, checksum); uint32_t original_value = buf_get_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32); if (original_value != checksum) { LOG_WARNING("Boot verification checksum in image (0x%8.8" PRIx32 ") to be written to flash is " "different from calculated vector checksum (0x%8.8" PRIx32 ").", original_value, checksum); LOG_WARNING("OpenOCD will write the correct checksum. To remove this warning modify build tools on developer PC to inject correct LPC vector " "checksum."); } /* FIXME: WARNING! This code is broken because it modifies the callers buffer in place. */ buf_set_u32((uint8_t *)buffer + (lpc2000_info->checksum_vector * 4), 0, 32, checksum); } struct working_area *iap_working_area; int retval = lpc2000_iap_working_area_init(bank, &iap_working_area); if (retval != ERROR_OK) return retval; struct working_area *download_area; /* allocate a working area */ if (target_alloc_working_area(target, lpc2000_info->cmd51_max_buffer, &download_area) != ERROR_OK) { LOG_ERROR("no working area specified, can't write LPC2000 internal flash"); target_free_working_area(target, iap_working_area); return ERROR_FLASH_OPERATION_FAILED; } uint32_t bytes_remaining = count; uint32_t bytes_written = 0; uint32_t param_table[5] = {0}; uint32_t result_table[4]; if (lpc2000_info->variant == LPC4300) /* Init IAP Anyway */ lpc2000_iap_call(bank, iap_working_area, 49, param_table, result_table); while (bytes_remaining > 0) { uint32_t thisrun_bytes; if (bytes_remaining >= lpc2000_info->cmd51_max_buffer) thisrun_bytes = lpc2000_info->cmd51_max_buffer; else thisrun_bytes = lpc2000_info->cmd51_dst_boundary; /* Prepare sectors */ param_table[0] = first_sector; param_table[1] = last_sector; if (lpc2000_info->variant == LPC4300) param_table[2] = lpc2000_info->lpc4300_bank; else param_table[2] = lpc2000_info->cclk; int status_code = lpc2000_iap_call(bank, iap_working_area, 50, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: retval = ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; } /* Exit if error occurred */ if (retval != ERROR_OK) break; if (bytes_remaining >= thisrun_bytes) { retval = target_write_buffer(bank->target, download_area->address, thisrun_bytes, buffer + bytes_written); if (retval != ERROR_OK) { retval = ERROR_FLASH_OPERATION_FAILED; break; } } else { uint8_t *last_buffer = malloc(thisrun_bytes); memcpy(last_buffer, buffer + bytes_written, bytes_remaining); memset(last_buffer + bytes_remaining, 0xff, thisrun_bytes - bytes_remaining); target_write_buffer(bank->target, download_area->address, thisrun_bytes, last_buffer); free(last_buffer); } LOG_DEBUG("writing 0x%" PRIx32 " bytes to address " TARGET_ADDR_FMT, thisrun_bytes, bank->base + offset + bytes_written); /* Write data */ param_table[0] = bank->base + offset + bytes_written; param_table[1] = download_area->address; param_table[2] = thisrun_bytes; param_table[3] = lpc2000_info->cclk; status_code = lpc2000_iap_call(bank, iap_working_area, 51, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: retval = ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; } /* Exit if error occurred */ if (retval != ERROR_OK) break; if (bytes_remaining > thisrun_bytes) bytes_remaining -= thisrun_bytes; else bytes_remaining = 0; bytes_written += thisrun_bytes; } target_free_working_area(target, iap_working_area); target_free_working_area(target, download_area); return retval; } static int get_lpc2000_part_id(struct flash_bank *bank, uint32_t *part_id) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } uint32_t param_table[5] = {0}; uint32_t result_table[4]; struct working_area *iap_working_area; int retval = lpc2000_iap_working_area_init(bank, &iap_working_area); if (retval != ERROR_OK) return retval; /* The status seems to be bogus with the part ID command on some IAP firmwares, so ignore it. */ lpc2000_iap_call(bank, iap_working_area, 54, param_table, result_table); struct target *target = bank->target; target_free_working_area(target, iap_working_area); /* If the result is zero, the command probably didn't work out. */ if (result_table[0] == 0) return LPC2000_INVALID_COMMAND; *part_id = result_table[0]; return LPC2000_CMD_SUCCESS; } static int lpc2000_auto_probe_flash(struct flash_bank *bank) { uint32_t part_id; int retval; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = get_lpc2000_part_id(bank, &part_id); if (retval != LPC2000_CMD_SUCCESS) { LOG_ERROR("Could not get part ID"); return retval; } switch (part_id) { case LPC1110_1: case LPC1110_2: lpc2000_info->variant = LPC1100; bank->size = 4 * 1024; break; case LPC1111_002_1: case LPC1111_002_2: case LPC1111_101_1: case LPC1111_101_2: case LPC1111_103_1: case LPC1111_201_1: case LPC1111_201_2: case LPC1111_203_1: case LPC11A11_001_1: case LPC11E11_101: case LPC1311: case LPC1311_1: lpc2000_info->variant = LPC1100; bank->size = 8 * 1024; break; case LPC1112_101_1: case LPC1112_101_2: case LPC1112_102_1: case LPC1112_102_2: case LPC1112_103_1: case LPC1112_201_1: case LPC1112_201_2: case LPC1112_203_1: case LPC11A02_1: case LPC11C12_301_1: case LPC11C22_301_1: case LPC11A12_101_1: case LPC11E12_201: case LPC11U12_201_1: case LPC11U12_201_2: case LPC1342: lpc2000_info->variant = LPC1100; bank->size = 16 * 1024; break; case LPC1113_201_1: case LPC1113_201_2: case LPC1113_203_1: case LPC1113_301_1: case LPC1113_301_2: case LPC1113_303_1: case LPC11A13_201_1: case LPC11E13_301: case LPC11U13_201_1: case LPC11U13_201_2: case LPC11U23_301: lpc2000_info->variant = LPC1100; bank->size = 24 * 1024; break; case LPC1114_102_1: case LPC1114_102_2: case LPC1114_201_1: case LPC1114_201_2: case LPC1114_203_1: case LPC1114_301_1: case LPC1114_301_2: case LPC1114_303_1: case LPC11A04_1: case LPC11A14_301_1: case LPC11A14_301_2: case LPC11C14_301_1: case LPC11C24_301_1: case LPC11E14_401: case LPC11U14_201_1: case LPC11U14_201_2: case LPC11U24_301: case LPC11U24_401: case LPC1313: case LPC1313_1: case LPC1315: case LPC1343: case LPC1343_1: case LPC1345: lpc2000_info->variant = LPC1100; bank->size = 32 * 1024; break; case LPC1751_1: case LPC1751_2: lpc2000_info->variant = LPC1700; bank->size = 32 * 1024; break; case LPC11U34_311: lpc2000_info->variant = LPC1100; bank->size = 40 * 1024; break; case LPC1114_323_1: case LPC11U34_421: case LPC1316: case LPC1346: lpc2000_info->variant = LPC1100; bank->size = 48 * 1024; break; case LPC1114_333_1: lpc2000_info->variant = LPC1100; bank->size = 56 * 1024; break; case LPC1115_303_1: case LPC11U35_401: case LPC11U35_501: case LPC11E66: case LPC11U66: case LPC1317: case LPC1347: lpc2000_info->variant = LPC1100; bank->size = 64 * 1024; break; case LPC1752: case LPC4072: lpc2000_info->variant = LPC1700; bank->size = 64 * 1024; break; case LPC11E36_501: case LPC11U36_401: lpc2000_info->variant = LPC1100; bank->size = 96 * 1024; break; case LPC11E37_401: case LPC11E37_501: case LPC11U37_401: case LPC11U37H_401: case LPC11U37_501: case LPC11E67: case LPC11E68: case LPC11U67_1: case LPC11U67_2: lpc2000_info->variant = LPC1100; bank->size = 128 * 1024; break; case LPC1754: case LPC1764: case LPC1774: case LPC4074: lpc2000_info->variant = LPC1700; bank->size = 128 * 1024; break; case LPC11U68_1: case LPC11U68_2: lpc2000_info->variant = LPC1100; bank->size = 256 * 1024; break; case LPC1756: case LPC1763: case LPC1765: case LPC1766: case LPC1776: case LPC1785: case LPC1786: case LPC4076: lpc2000_info->variant = LPC1700; bank->size = 256 * 1024; break; case LPC1758: case LPC1759: case LPC1767: case LPC1768: case LPC1769: case LPC1777: case LPC1778: case LPC1787: case LPC1788: case LPC4078: case LPC4088: lpc2000_info->variant = LPC1700; bank->size = 512 * 1024; break; case LPC810_021: lpc2000_info->variant = LPC800; bank->size = 4 * 1024; break; case LPC811_001: lpc2000_info->variant = LPC800; bank->size = 8 * 1024; break; case LPC812_101: case LPC812_101_1: case LPC812_101_2: case LPC812_101_3: case LPC822_101: case LPC822_101_1: lpc2000_info->variant = LPC800; bank->size = 16 * 1024; break; case LPC824_201: case LPC824_201_1: lpc2000_info->variant = LPC800; bank->size = 32 * 1024; break; case LPC8N04: case NHS3100: case NHS3152: case NHS3153: lpc2000_info->variant = LPC800; bank->size = 30 * 1024; break; case LPC844_201: case LPC844_201_1: case LPC844_201_2: case LPC845_301: case LPC845_301_1: case LPC845_301_2: case LPC845_301_3: lpc2000_info->variant = LPC800; bank->size = 64 * 1024; break; default: LOG_ERROR("BUG: unknown Part ID encountered: 0x%" PRIx32, part_id); exit(-1); } return ERROR_OK; } static int lpc2000_probe(struct flash_bank *bank) { int status; uint32_t part_id; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; if (!lpc2000_info->probed) { if (lpc2000_info->variant == LPC_AUTO) { status = lpc2000_auto_probe_flash(bank); if (status != ERROR_OK) return status; } else if (lpc2000_info->variant == LPC1100 || lpc2000_info->variant == LPC1700) { status = get_lpc2000_part_id(bank, &part_id); if (status == LPC2000_CMD_SUCCESS) LOG_INFO("If auto-detection fails for this part, please email " "openocd-devel@lists.sourceforge.net, citing part id 0x%" PRIx32 ".\n", part_id); } lpc2000_build_sector_list(bank); lpc2000_info->probed = true; } return ERROR_OK; } static int lpc2000_erase_check(struct flash_bank *bank) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1); } static int get_lpc2000_info(struct flash_bank *bank, struct command_invocation *cmd) { struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; command_print_sameline(cmd, "lpc2000 flash driver variant: %i, clk: %" PRIu32 "kHz", lpc2000_info->variant, lpc2000_info->cclk); return ERROR_OK; } COMMAND_HANDLER(lpc2000_handle_part_id_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } uint32_t part_id; int status_code = get_lpc2000_part_id(bank, &part_id); if (status_code != 0x0) { if (status_code == ERROR_FLASH_OPERATION_FAILED) { command_print(CMD, "no sufficient working area specified, can't access LPC2000 IAP interface"); } else command_print(CMD, "lpc2000 IAP returned status code %i", status_code); } else command_print(CMD, "lpc2000 part id: 0x%8.8" PRIx32, part_id); return retval; } static const struct command_registration lpc2000_exec_command_handlers[] = { { .name = "part_id", .handler = lpc2000_handle_part_id_command, .mode = COMMAND_EXEC, .help = "print part id of lpc2000 flash bank <num>", .usage = "<bank>", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration lpc2000_command_handlers[] = { { .name = "lpc2000", .mode = COMMAND_ANY, .help = "lpc2000 flash command group", .usage = "", .chain = lpc2000_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver lpc2000_flash = { .name = "lpc2000", .commands = lpc2000_command_handlers, .flash_bank_command = lpc2000_flash_bank_command, .erase = lpc2000_erase, .write = lpc2000_write, .read = default_flash_read, .probe = lpc2000_probe, .auto_probe = lpc2000_probe, .erase_check = lpc2000_erase_check, .info = get_lpc2000_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/lpc288x.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2008 by * * Karl RobinSod <karl.robinsod@gmail.com> * ***************************************************************************/ /*************************************************************************** * There are some things to notice * * You need to unprotect flash sectors each time you connect the OpenOCD * Dumping 1MB takes about 60 Seconds * Full erase (sectors 0-22 inclusive) takes 2-4 seconds * Writing 1MB takes 88 seconds * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #define LOAD_TIMER_ERASE 0 #define LOAD_TIMER_WRITE 1 #define FLASH_PAGE_SIZE 512 /* LPC288X control registers */ #define DBGU_CIDR 0x8000507C /* LPC288X flash registers */ #define F_CTRL 0x80102000 /* Flash control register R/W 0x5 */ #define F_STAT 0x80102004 /* Flash status register RO 0x45 */ #define F_PROG_TIME 0x80102008 /* Flash program time register R/W 0 */ #define F_WAIT 0x80102010 /* Flash read wait state register R/W 0xC004 */ #define F_CLK_TIME 0x8010201C /* Flash clock divider for 66 kHz generation R/W 0 **/ #define F_INTEN_CLR 0x80102FD8 /* Clear interrupt enable bits WO - */ #define F_INTEN_SET 0x80102FDC /* Set interrupt enable bits WO - */ #define F_INT_STAT 0x80102FE0 /* Interrupt status bits RO 0 */ #define F_INTEN 0x80102FE4 /* Interrupt enable bits RO 0 */ #define F_INT_CLR 0x80102FE8 /* Clear interrupt status bits WO */ #define F_INT_SET 0x80102FEC /* Set interrupt status bits WO - */ #define FLASH_PD 0x80005030 /* Allows turning off the Flash memory for power *savings. R/W 1*/ #define FLASH_INIT 0x80005034 /* Monitors Flash readiness, such as recovery from *Power Down mode. R/W -*/ /* F_CTRL bits */ #define FC_CS 0x0001 #define FC_FUNC 0x0002 #define FC_WEN 0x0004 #define FC_RD_LATCH 0x0020 #define FC_PROTECT 0x0080 #define FC_SET_DATA 0x0400 #define FC_RSSL 0x0800 #define FC_PROG_REQ 0x1000 #define FC_CLR_BUF 0x4000 #define FC_LOAD_REQ 0x8000 /* F_STAT bits */ #define FS_DONE 0x0001 #define FS_PROGGNT 0x0002 #define FS_RDY 0x0004 #define FS_ERR 0x0020 /* F_PROG_TIME */ #define FPT_TIME_MASK 0x7FFF #define FPT_ENABLE 0x8000 /* F_WAIT */ #define FW_WAIT_STATES_MASK 0x00FF #define FW_SET_MASK 0xC000 /* F_CLK_TIME */ #define FCT_CLK_DIV_MASK 0x0FFF struct lpc288x_flash_bank { uint32_t working_area; uint32_t working_area_size; /* chip id register */ uint32_t cidr; const char *target_name; uint32_t cclk; uint32_t sector_size_break; }; static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout); static void lpc288x_load_timer(int erase, struct target *target); static void lpc288x_set_flash_clk(struct flash_bank *bank); static uint32_t lpc288x_system_ready(struct flash_bank *bank); static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout) { uint32_t status; struct target *target = bank->target; do { alive_sleep(1); timeout--; target_read_u32(target, F_STAT, &status); } while (((status & FS_DONE) == 0) && timeout); if (timeout == 0) { LOG_DEBUG("Timedout!"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } /* Read device id register and fill in driver info structure */ static int lpc288x_read_part_info(struct flash_bank *bank) { struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv; struct target *target = bank->target; uint32_t cidr; int i = 0; uint32_t offset; if (lpc288x_info->cidr == 0x0102100A) return ERROR_OK;/* already probed, multiple probes may cause memory leak, not *allowed */ /* Read and parse chip identification register */ target_read_u32(target, DBGU_CIDR, &cidr); if (cidr != 0x0102100A) { LOG_WARNING("Cannot identify target as an LPC288X (%08" PRIx32 ")", cidr); return ERROR_FLASH_OPERATION_FAILED; } lpc288x_info->cidr = cidr; lpc288x_info->sector_size_break = 0x000F0000; lpc288x_info->target_name = "LPC288x"; /* setup the sector info... */ offset = bank->base; bank->num_sectors = 23; bank->sectors = malloc(sizeof(struct flash_sector) * 23); for (i = 0; i < 15; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = 64 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } for (i = 15; i < 23; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = 8 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } return ERROR_OK; } /* TODO: Revisit! Is it impossible to read protection status? */ static int lpc288x_protect_check(struct flash_bank *bank) { return ERROR_OK; } /* flash_bank LPC288x 0 0 0 0 <target#> <cclk> */ FLASH_BANK_COMMAND_HANDLER(lpc288x_flash_bank_command) { struct lpc288x_flash_bank *lpc288x_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; lpc288x_info = malloc(sizeof(struct lpc288x_flash_bank)); bank->driver_priv = lpc288x_info; /* part wasn't probed for info yet */ lpc288x_info->cidr = 0; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], lpc288x_info->cclk); return ERROR_OK; } /* The frequency is the AHB clock frequency divided by (CLK_DIV ×3) + 1. * This must be programmed such that the Flash Programming clock frequency is 66 kHz ± 20%. * AHB = 12 MHz ? * 12000000/66000 = 182 * CLK_DIV = 60 ? */ static void lpc288x_set_flash_clk(struct flash_bank *bank) { uint32_t clk_time; struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv; clk_time = (lpc288x_info->cclk / 66000) / 3; target_write_u32(bank->target, F_CTRL, FC_CS | FC_WEN); target_write_u32(bank->target, F_CLK_TIME, clk_time); } /* AHB tcyc (in ns) 83 ns * LOAD_TIMER_ERASE FPT_TIME = ((400,000,000 / AHB tcyc (in ns)) - 2) / 512 * = 9412 (9500) (AN10548 9375) * LOAD_TIMER_WRITE FPT_TIME = ((1,000,000 / AHB tcyc (in ns)) - 2) / 512 * = 23 (75) (AN10548 72 - is this wrong?) * TODO: Sort out timing calcs ;) */ static void lpc288x_load_timer(int erase, struct target *target) { if (erase == LOAD_TIMER_ERASE) target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 9500); else target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 75); } static uint32_t lpc288x_system_ready(struct flash_bank *bank) { struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv; if (lpc288x_info->cidr == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } return ERROR_OK; } static int lpc288x_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { uint32_t status; struct target *target = bank->target; status = lpc288x_system_ready(bank); /* probed? halted? */ if (status != ERROR_OK) return status; if ((last < first) || (last >= bank->num_sectors)) { LOG_INFO("Bad sector range"); return ERROR_FLASH_SECTOR_INVALID; } /* Configure the flash controller timing */ lpc288x_set_flash_clk(bank); for (unsigned int sector = first; sector <= last; sector++) { if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; lpc288x_load_timer(LOAD_TIMER_ERASE, target); target_write_u32(target, bank->sectors[sector].offset, 0x00); target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_CS); } if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } static int lpc288x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { uint8_t page_buffer[FLASH_PAGE_SIZE]; uint32_t status, source_offset, dest_offset; struct target *target = bank->target; uint32_t bytes_remaining = count; uint32_t first_sector, last_sector, sector, page; /* probed? halted? */ status = lpc288x_system_ready(bank); if (status != ERROR_OK) return status; /* Initialise search indices */ first_sector = last_sector = 0xffffffff; /* validate the write range... */ for (unsigned int i = 0; i < bank->num_sectors; i++) { if ((offset >= bank->sectors[i].offset) && (offset < (bank->sectors[i].offset + bank->sectors[i].size)) && (first_sector == 0xffffffff)) { first_sector = i; /* all writes must start on a sector boundary... */ if (offset % bank->sectors[i].size) { LOG_INFO( "offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", offset, bank->sectors[i].size); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } } if (((offset + count) > bank->sectors[i].offset) && ((offset + count) <= (bank->sectors[i].offset + bank->sectors[i].size)) && (last_sector == 0xffffffff)) last_sector = i; } /* Range check... */ if (first_sector == 0xffffffff || last_sector == 0xffffffff) { LOG_INFO("Range check failed %" PRIx32 " %" PRIx32 "", offset, count); return ERROR_FLASH_DST_OUT_OF_BANK; } /* Configure the flash controller timing */ lpc288x_set_flash_clk(bank); /* initialise the offsets */ source_offset = 0; dest_offset = 0; for (sector = first_sector; sector <= last_sector; sector++) { for (page = 0; page < bank->sectors[sector].size / FLASH_PAGE_SIZE; page++) { if (bytes_remaining == 0) { count = 0; memset(page_buffer, 0xFF, FLASH_PAGE_SIZE); } else if (bytes_remaining < FLASH_PAGE_SIZE) { count = bytes_remaining; memset(page_buffer, 0xFF, FLASH_PAGE_SIZE); memcpy(page_buffer, &buffer[source_offset], count); } else { count = FLASH_PAGE_SIZE; memcpy(page_buffer, &buffer[source_offset], count); } /* Wait for flash to become ready */ if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; /* fill flash data latches with 1's */ target_write_u32(target, F_CTRL, FC_CS | FC_SET_DATA | FC_WEN | FC_FUNC); target_write_u32(target, F_CTRL, FC_CS | FC_WEN | FC_FUNC); if (target_write_buffer(target, offset + dest_offset, FLASH_PAGE_SIZE, page_buffer) != ERROR_OK) { LOG_INFO("Write to flash buffer failed"); return ERROR_FLASH_OPERATION_FAILED; } dest_offset += FLASH_PAGE_SIZE; source_offset += count; bytes_remaining -= count; lpc288x_load_timer(LOAD_TIMER_WRITE, target); target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_FUNC | FC_CS); } } return ERROR_OK; } static int lpc288x_probe(struct flash_bank *bank) { /* we only deal with LPC2888 so flash config is fixed */ struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv; int retval; if (lpc288x_info->cidr != 0) return ERROR_OK;/* already probed */ if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = lpc288x_read_part_info(bank); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int lpc288x_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int status; uint32_t value; struct target *target = bank->target; /* probed? halted? */ status = lpc288x_system_ready(bank); if (status != ERROR_OK) return status; if ((last < first) || (last >= bank->num_sectors)) return ERROR_FLASH_SECTOR_INVALID; /* Configure the flash controller timing */ lpc288x_set_flash_clk(bank); for (unsigned int lockregion = first; lockregion <= last; lockregion++) { if (set) { /* write an odd value to base address to protect... */ value = 0x01; } else { /* write an even value to base address to unprotect... */ value = 0x00; } target_write_u32(target, bank->sectors[lockregion].offset, value); target_write_u32(target, F_CTRL, FC_LOAD_REQ | FC_PROTECT | FC_WEN | FC_FUNC | FC_CS); } return ERROR_OK; } const struct flash_driver lpc288x_flash = { .name = "lpc288x", .flash_bank_command = lpc288x_flash_bank_command, .erase = lpc288x_erase, .protect = lpc288x_protect, .write = lpc288x_write, .read = default_flash_read, .probe = lpc288x_probe, .auto_probe = lpc288x_probe, .erase_check = default_flash_blank_check, .protect_check = lpc288x_protect_check, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/lpc2900.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by * * Rolf Meeser <rolfm_9dq@yahoo.de> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/arm.h> #include <target/image.h> /* 1024 bytes */ #define KiB 1024 /* Some flash constants */ #define FLASH_PAGE_SIZE 512 /* bytes */ #define FLASH_ERASE_TIME 100000 /* microseconds */ #define FLASH_PROGRAM_TIME 1000 /* microseconds */ /* Chip ID / Feature Registers */ #define CHIPID 0xE0000000 /* Chip ID */ #define FEAT0 0xE0000100 /* Chip feature 0 */ #define FEAT1 0xE0000104 /* Chip feature 1 */ #define FEAT2 0xE0000108 /* Chip feature 2 (contains flash size indicator) */ #define FEAT3 0xE000010C /* Chip feature 3 */ #define EXPECTED_CHIPID 0x209CE02B /* Chip ID of all LPC2900 devices */ /* Flash/EEPROM Control Registers */ #define FCTR 0x20200000 /* Flash control */ #define FPTR 0x20200008 /* Flash program-time */ #define FTCTR 0x2020000C /* Flash test control */ #define FBWST 0x20200010 /* Flash bridge wait-state */ #define FCRA 0x2020001C /* Flash clock divider */ #define FMSSTART 0x20200020 /* Flash Built-In Self Test start address */ #define FMSSTOP 0x20200024 /* Flash Built-In Self Test stop address */ #define FMS16 0x20200028 /* Flash 16-bit signature */ #define FMSW0 0x2020002C /* Flash 128-bit signature Word 0 */ #define FMSW1 0x20200030 /* Flash 128-bit signature Word 1 */ #define FMSW2 0x20200034 /* Flash 128-bit signature Word 2 */ #define FMSW3 0x20200038 /* Flash 128-bit signature Word 3 */ #define EECMD 0x20200080 /* EEPROM command */ #define EEADDR 0x20200084 /* EEPROM address */ #define EEWDATA 0x20200088 /* EEPROM write data */ #define EERDATA 0x2020008C /* EEPROM read data */ #define EEWSTATE 0x20200090 /* EEPROM wait state */ #define EECLKDIV 0x20200094 /* EEPROM clock divider */ #define EEPWRDWN 0x20200098 /* EEPROM power-down/start */ #define EEMSSTART 0x2020009C /* EEPROM BIST start address */ #define EEMSSTOP 0x202000A0 /* EEPROM BIST stop address */ #define EEMSSIG 0x202000A4 /* EEPROM 24-bit BIST signature */ #define INT_CLR_ENABLE 0x20200FD8 /* Flash/EEPROM interrupt clear enable */ #define INT_SET_ENABLE 0x20200FDC /* Flash/EEPROM interrupt set enable */ #define INT_STATUS 0x20200FE0 /* Flash/EEPROM interrupt status */ #define INT_ENABLE 0x20200FE4 /* Flash/EEPROM interrupt enable */ #define INT_CLR_STATUS 0x20200FE8 /* Flash/EEPROM interrupt clear status */ #define INT_SET_STATUS 0x20200FEC /* Flash/EEPROM interrupt set status */ /* Interrupt sources */ #define INTSRC_END_OF_PROG (1 << 28) #define INTSRC_END_OF_BIST (1 << 27) #define INTSRC_END_OF_RDWR (1 << 26) #define INTSRC_END_OF_MISR (1 << 2) #define INTSRC_END_OF_BURN (1 << 1) #define INTSRC_END_OF_ERASE (1 << 0) /* FCTR bits */ #define FCTR_FS_LOADREQ (1 << 15) #define FCTR_FS_CACHECLR (1 << 14) #define FCTR_FS_CACHEBYP (1 << 13) #define FCTR_FS_PROGREQ (1 << 12) #define FCTR_FS_RLS (1 << 11) #define FCTR_FS_PDL (1 << 10) #define FCTR_FS_PD (1 << 9) #define FCTR_FS_WPB (1 << 7) #define FCTR_FS_ISS (1 << 6) #define FCTR_FS_RLD (1 << 5) #define FCTR_FS_DCR (1 << 4) #define FCTR_FS_WEB (1 << 2) #define FCTR_FS_WRE (1 << 1) #define FCTR_FS_CS (1 << 0) /* FPTR bits */ #define FPTR_EN_T (1 << 15) /* FTCTR bits */ #define FTCTR_FS_BYPASS_R (1 << 29) #define FTCTR_FS_BYPASS_W (1 << 28) /* FMSSTOP bits */ #define FMSSTOP_MISR_START (1 << 17) /* EEMSSTOP bits */ #define EEMSSTOP_STRTBIST (1 << 31) /* Index sector */ #define ISS_CUSTOMER_START1 (0x830) #define ISS_CUSTOMER_END1 (0xA00) #define ISS_CUSTOMER_SIZE1 (ISS_CUSTOMER_END1 - ISS_CUSTOMER_START1) #define ISS_CUSTOMER_NWORDS1 (ISS_CUSTOMER_SIZE1 / 4) #define ISS_CUSTOMER_START2 (0xA40) #define ISS_CUSTOMER_END2 (0xC00) #define ISS_CUSTOMER_SIZE2 (ISS_CUSTOMER_END2 - ISS_CUSTOMER_START2) #define ISS_CUSTOMER_NWORDS2 (ISS_CUSTOMER_SIZE2 / 4) #define ISS_CUSTOMER_SIZE (ISS_CUSTOMER_SIZE1 + ISS_CUSTOMER_SIZE2) /** * Private data for \c lpc2900 flash driver. */ struct lpc2900_flash_bank { /** * This flag is set when the device has been successfully probed. */ bool is_probed; /** * Holds the value read from CHIPID register. * The driver will not load if the chipid doesn't match the expected * value of 0x209CE02B of the LPC2900 family. A probe will only be done * if the chipid does not yet contain the expected value. */ uint32_t chipid; /** * String holding device name. * This string is set by the probe function to the type number of the * device. It takes the form "LPC29xx". */ char *target_name; /** * System clock frequency. * Holds the clock frequency in Hz, as passed by the configuration file * to the <tt>flash bank</tt> command. */ uint32_t clk_sys_fmc; /** * Flag to indicate that dangerous operations are possible. * This flag can be set by passing the correct password to the * <tt>lpc2900 password</tt> command. If set, other dangerous commands, * which operate on the index sector, can be executed. */ uint32_t risky; /** * Maximum contiguous block of internal SRAM (bytes). * Autodetected by the driver. Not the total amount of SRAM, only * the largest \em contiguous block! */ uint32_t max_ram_block; }; static uint32_t lpc2900_wait_status(struct flash_bank *bank, uint32_t mask, int timeout); static void lpc2900_setup(struct flash_bank *bank); static uint32_t lpc2900_is_ready(struct flash_bank *bank); static uint32_t lpc2900_read_security_status(struct flash_bank *bank); static uint32_t lpc2900_run_bist128(struct flash_bank *bank, uint32_t addr_from, uint32_t addr_to, uint32_t signature[4]); static unsigned int lpc2900_address2sector(struct flash_bank *bank, uint32_t offset); static uint32_t lpc2900_calc_tr(uint32_t clock_var, uint32_t time_var); /*********************** Helper functions **************************/ /** * Wait for an event in mask to occur in INT_STATUS. * * Return when an event occurs, or after a timeout. * * @param[in] bank Pointer to the flash bank descriptor * @param[in] mask Mask to be used for INT_STATUS * @param[in] timeout Timeout in ms */ static uint32_t lpc2900_wait_status(struct flash_bank *bank, uint32_t mask, int timeout) { uint32_t int_status; struct target *target = bank->target; do { alive_sleep(1); timeout--; target_read_u32(target, INT_STATUS, &int_status); } while (((int_status & mask) == 0) && (timeout != 0)); if (timeout == 0) { LOG_DEBUG("Timeout!"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } /** * Set up the flash for erase/program operations. * * Enable the flash, and set the correct CRA clock of 66 kHz. * * @param bank Pointer to the flash bank descriptor */ static void lpc2900_setup(struct flash_bank *bank) { uint32_t fcra; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; /* Power up the flash block */ target_write_u32(bank->target, FCTR, FCTR_FS_WEB | FCTR_FS_CS); fcra = (lpc2900_info->clk_sys_fmc / (3 * 66000)) - 1; target_write_u32(bank->target, FCRA, fcra); } /** * Check if device is ready. * * Check if device is ready for flash operation: * Must have been successfully probed. * Must be halted. */ static uint32_t lpc2900_is_ready(struct flash_bank *bank) { struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; if (!lpc2900_info->is_probed) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } return ERROR_OK; } /** * Read the status of sector security from the index sector. * * @param bank Pointer to the flash bank descriptor */ static uint32_t lpc2900_read_security_status(struct flash_bank *bank) { uint32_t status = lpc2900_is_ready(bank); if (status != ERROR_OK) return status; struct target *target = bank->target; /* Enable ISS access */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB | FCTR_FS_ISS); /* Read the relevant block of memory from the ISS sector */ uint32_t iss_secured_field[0x230/16][4]; target_read_memory(target, bank->base + 0xC00, 4, 0x230/4, (uint8_t *)iss_secured_field); /* Disable ISS access */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); /* Check status of each sector. Note that the sector numbering in the LPC2900 * is different from the logical sector numbers used in OpenOCD! * Refer to the user manual for details. * * All zeros (16x 0x00) are treated as a secured sector (is_protected = 1) * All ones (16x 0xFF) are treated as a non-secured sector (is_protected = 0) * Anything else is undefined (is_protected = -1). This is treated as * a protected sector! */ for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { unsigned int index_t; /* Convert logical sector number to physical sector number */ if (sector <= 4) index_t = sector + 11; else if (sector <= 7) index_t = sector + 27; else index_t = sector - 8; bank->sectors[sector].is_protected = -1; if ((iss_secured_field[index_t][0] == 0x00000000) && (iss_secured_field[index_t][1] == 0x00000000) && (iss_secured_field[index_t][2] == 0x00000000) && (iss_secured_field[index_t][3] == 0x00000000)) bank->sectors[sector].is_protected = 1; if ((iss_secured_field[index_t][0] == 0xFFFFFFFF) && (iss_secured_field[index_t][1] == 0xFFFFFFFF) && (iss_secured_field[index_t][2] == 0xFFFFFFFF) && (iss_secured_field[index_t][3] == 0xFFFFFFFF)) bank->sectors[sector].is_protected = 0; } return ERROR_OK; } /** * Use BIST to calculate a 128-bit hash value over a range of flash. * * @param bank Pointer to the flash bank descriptor * @param addr_from * @param addr_to * @param signature */ static uint32_t lpc2900_run_bist128(struct flash_bank *bank, uint32_t addr_from, uint32_t addr_to, uint32_t signature[4]) { struct target *target = bank->target; /* Clear END_OF_MISR interrupt status */ target_write_u32(target, INT_CLR_STATUS, INTSRC_END_OF_MISR); /* Start address */ target_write_u32(target, FMSSTART, addr_from >> 4); /* End address, and issue start command */ target_write_u32(target, FMSSTOP, (addr_to >> 4) | FMSSTOP_MISR_START); /* Poll for end of operation. Calculate a reasonable timeout. */ if (lpc2900_wait_status(bank, INTSRC_END_OF_MISR, 1000) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; /* Return the signature */ uint8_t sig_buf[4 * 4]; target_read_memory(target, FMSW0, 4, 4, sig_buf); target_buffer_get_u32_array(target, sig_buf, 4, signature); return ERROR_OK; } /** * Return sector number for given address. * * Return the (logical) sector number for a given relative address. * No sanity check is done. It assumed that the address is valid. * * @param bank Pointer to the flash bank descriptor * @param offset Offset address relative to bank start */ static unsigned int lpc2900_address2sector(struct flash_bank *bank, uint32_t offset) { uint32_t address = bank->base + offset; /* Run through all sectors of this bank */ for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { /* Return immediately if address is within the current sector */ if (address < (bank->sectors[sector].offset + bank->sectors[sector].size)) return sector; } /* We should never come here. If we do, return an arbitrary sector number. */ return 0; } /** * Write one page to the index sector. * * @param bank Pointer to the flash bank descriptor * @param pagenum Page number (0...7) * @param page Page array (FLASH_PAGE_SIZE bytes) */ static int lpc2900_write_index_page(struct flash_bank *bank, int pagenum, uint8_t page[FLASH_PAGE_SIZE]) { /* Only pages 4...7 are user writable */ if ((pagenum < 4) || (pagenum > 7)) { LOG_ERROR("Refuse to burn index sector page %d", pagenum); return ERROR_COMMAND_ARGUMENT_INVALID; } /* Get target, and check if it's halted */ struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Private info */ struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; /* Enable flash block and set the correct CRA clock of 66 kHz */ lpc2900_setup(bank); /* Un-protect the index sector */ target_write_u32(target, bank->base, 0); target_write_u32(target, FCTR, FCTR_FS_LOADREQ | FCTR_FS_WPB | FCTR_FS_ISS | FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS); /* Set latch load mode */ target_write_u32(target, FCTR, FCTR_FS_ISS | FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS); /* Write whole page to flash data latches */ if (target_write_memory(target, bank->base + pagenum * FLASH_PAGE_SIZE, 4, FLASH_PAGE_SIZE / 4, page) != ERROR_OK) { LOG_ERROR("Index sector write failed @ page %d", pagenum); target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); return ERROR_FLASH_OPERATION_FAILED; } /* Clear END_OF_BURN interrupt status */ target_write_u32(target, INT_CLR_STATUS, INTSRC_END_OF_BURN); /* Set the program/erase time to FLASH_PROGRAM_TIME */ target_write_u32(target, FPTR, FPTR_EN_T | lpc2900_calc_tr(lpc2900_info->clk_sys_fmc, FLASH_PROGRAM_TIME)); /* Trigger flash write */ target_write_u32(target, FCTR, FCTR_FS_PROGREQ | FCTR_FS_ISS | FCTR_FS_WPB | FCTR_FS_WRE | FCTR_FS_CS); /* Wait for the end of the write operation. If it's not over after one * second, something went dreadfully wrong... :-( */ if (lpc2900_wait_status(bank, INTSRC_END_OF_BURN, 1000) != ERROR_OK) { LOG_ERROR("Index sector write failed @ page %d", pagenum); target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); return ERROR_FLASH_OPERATION_FAILED; } target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); return ERROR_OK; } /** * Calculate FPTR.TR register value for desired program/erase time. * * @param clock_var System clock in Hz * @param time_var Program/erase time in µs */ static uint32_t lpc2900_calc_tr(uint32_t clock_var, uint32_t time_var) { /* ((time[µs]/1e6) * f[Hz]) + 511 * FPTR.TR = ------------------------------- * 512 */ uint32_t tr_val = (uint32_t)((((time_var / 1e6) * clock_var) + 511.0) / 512.0); return tr_val; } /*********************** Private flash commands **************************/ /** * Command to determine the signature of the whole flash. * * Uses the Built-In-Self-Test (BIST) to generate a 128-bit hash value * of the flash content. */ COMMAND_HANDLER(lpc2900_handle_signature_command) { uint32_t status; uint32_t signature[4]; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Run BIST over whole flash range */ status = lpc2900_run_bist128(bank, bank->base, bank->base + (bank->size - 1), signature); if (status != ERROR_OK) return status; command_print(CMD, "signature: 0x%8.8" PRIx32 ":0x%8.8" PRIx32 ":0x%8.8" PRIx32 ":0x%8.8" PRIx32, signature[3], signature[2], signature[1], signature[0]); return ERROR_OK; } /** * Store customer info in file. * * Read customer info from index sector, and store that block of data into * a disk file. The format is binary. */ COMMAND_HANDLER(lpc2900_handle_read_custom_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; lpc2900_info->risky = 0; /* Get target, and check if it's halted */ struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Storage for customer info. Read in two parts */ uint8_t customer[4 * (ISS_CUSTOMER_NWORDS1 + ISS_CUSTOMER_NWORDS2)]; /* Enable access to index sector */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB | FCTR_FS_ISS); /* Read two parts */ target_read_memory(target, bank->base+ISS_CUSTOMER_START1, 4, ISS_CUSTOMER_NWORDS1, &customer[0]); target_read_memory(target, bank->base+ISS_CUSTOMER_START2, 4, ISS_CUSTOMER_NWORDS2, &customer[4 * ISS_CUSTOMER_NWORDS1]); /* Deactivate access to index sector */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); /* Try and open the file */ struct fileio *fileio; const char *filename = CMD_ARGV[1]; int ret = fileio_open(&fileio, filename, FILEIO_WRITE, FILEIO_BINARY); if (ret != ERROR_OK) { LOG_WARNING("Could not open file %s", filename); return ret; } size_t nwritten; ret = fileio_write(fileio, sizeof(customer), customer, &nwritten); if (ret != ERROR_OK) { LOG_ERROR("Write operation to file %s failed", filename); fileio_close(fileio); return ret; } fileio_close(fileio); return ERROR_OK; } /** * Enter password to enable potentially dangerous options. */ COMMAND_HANDLER(lpc2900_handle_password_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; #define ISS_PASSWORD "I_know_what_I_am_doing" lpc2900_info->risky = !strcmp(CMD_ARGV[1], ISS_PASSWORD); if (!lpc2900_info->risky) { command_print(CMD, "Wrong password (use '%s')", ISS_PASSWORD); return ERROR_COMMAND_ARGUMENT_INVALID; } command_print(CMD, "Potentially dangerous operation allowed in next command!"); return ERROR_OK; } /** * Write customer info from file to the index sector. */ COMMAND_HANDLER(lpc2900_handle_write_custom_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; /* Check if command execution is allowed. */ if (!lpc2900_info->risky) { command_print(CMD, "Command execution not allowed!"); return ERROR_COMMAND_ARGUMENT_INVALID; } lpc2900_info->risky = 0; /* Get target, and check if it's halted */ struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* The image will always start at offset 0 */ struct image image; image.base_address_set = true; image.base_address = 0; image.start_address_set = false; const char *filename = CMD_ARGV[1]; const char *type = (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL; retval = image_open(&image, filename, type); if (retval != ERROR_OK) return retval; /* Do a sanity check: The image must be exactly the size of the customer programmable area. Any other size is rejected. */ if (image.num_sections != 1) { LOG_ERROR("Only one section allowed in image file."); return ERROR_COMMAND_SYNTAX_ERROR; } if ((image.sections[0].base_address != 0) || (image.sections[0].size != ISS_CUSTOMER_SIZE)) { LOG_ERROR("Incorrect image file size. Expected %d, " "got %" PRIu32, ISS_CUSTOMER_SIZE, image.sections[0].size); return ERROR_COMMAND_SYNTAX_ERROR; } /* Well boys, I reckon this is it... */ /* Customer info is split into two blocks in pages 4 and 5. */ uint8_t page[FLASH_PAGE_SIZE]; /* Page 4 */ uint32_t offset = ISS_CUSTOMER_START1 % FLASH_PAGE_SIZE; memset(page, 0xff, FLASH_PAGE_SIZE); size_t size_read; retval = image_read_section(&image, 0, 0, ISS_CUSTOMER_SIZE1, &page[offset], &size_read); if (retval != ERROR_OK) { LOG_ERROR("couldn't read from file '%s'", filename); image_close(&image); return retval; } retval = lpc2900_write_index_page(bank, 4, page); if (retval != ERROR_OK) { image_close(&image); return retval; } /* Page 5 */ offset = ISS_CUSTOMER_START2 % FLASH_PAGE_SIZE; memset(page, 0xff, FLASH_PAGE_SIZE); retval = image_read_section(&image, 0, ISS_CUSTOMER_SIZE1, ISS_CUSTOMER_SIZE2, &page[offset], &size_read); if (retval != ERROR_OK) { LOG_ERROR("couldn't read from file '%s'", filename); image_close(&image); return retval; } retval = lpc2900_write_index_page(bank, 5, page); if (retval != ERROR_OK) { image_close(&image); return retval; } image_close(&image); return ERROR_OK; } /** * Activate 'sector security' for a range of sectors. */ COMMAND_HANDLER(lpc2900_handle_secure_sector_command) { if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; /* Get the bank descriptor */ struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; /* Check if command execution is allowed. */ if (!lpc2900_info->risky) { command_print(CMD, "Command execution not allowed! " "(use 'password' command first)"); return ERROR_COMMAND_ARGUMENT_INVALID; } lpc2900_info->risky = 0; /* Read sector range, and do a sanity check. */ unsigned int first, last; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], first); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], last); if ((first >= bank->num_sectors) || (last >= bank->num_sectors) || (first > last)) { command_print(CMD, "Illegal sector range"); return ERROR_COMMAND_ARGUMENT_INVALID; } uint8_t page[FLASH_PAGE_SIZE]; /* Sectors in page 6 */ if ((first <= 4) || (last >= 8)) { memset(&page, 0xff, FLASH_PAGE_SIZE); for (unsigned int sector = first; sector <= last; sector++) { if (sector <= 4) memset(&page[0xB0 + 16*sector], 0, 16); else if (sector >= 8) memset(&page[0x00 + 16*(sector - 8)], 0, 16); } retval = lpc2900_write_index_page(bank, 6, page); if (retval != ERROR_OK) { LOG_ERROR("failed to update index sector page 6"); return retval; } } /* Sectors in page 7 */ if ((first <= 7) && (last >= 5)) { memset(&page, 0xff, FLASH_PAGE_SIZE); for (unsigned int sector = first; sector <= last; sector++) { if ((sector >= 5) && (sector <= 7)) memset(&page[0x00 + 16*(sector - 5)], 0, 16); } retval = lpc2900_write_index_page(bank, 7, page); if (retval != ERROR_OK) { LOG_ERROR("failed to update index sector page 7"); return retval; } } command_print(CMD, "Sectors security will become effective after next power cycle"); /* Update the sector security status */ if (lpc2900_read_security_status(bank) != ERROR_OK) { LOG_ERROR("Cannot determine sector security status"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } /** * Activate JTAG protection. */ COMMAND_HANDLER(lpc2900_handle_secure_jtag_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; /* Get the bank descriptor */ struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; /* Check if command execution is allowed. */ if (!lpc2900_info->risky) { command_print(CMD, "Command execution not allowed! " "(use 'password' command first)"); return ERROR_COMMAND_ARGUMENT_INVALID; } lpc2900_info->risky = 0; /* Prepare page */ uint8_t page[FLASH_PAGE_SIZE]; memset(&page, 0xff, FLASH_PAGE_SIZE); /* Insert "soft" protection word */ page[0x30 + 15] = 0x7F; page[0x30 + 11] = 0x7F; page[0x30 + 7] = 0x7F; page[0x30 + 3] = 0x7F; /* Write to page 5 */ retval = lpc2900_write_index_page(bank, 5, page); if (retval != ERROR_OK) { LOG_ERROR("failed to update index sector page 5"); return retval; } LOG_INFO("JTAG security set. Good bye!"); return ERROR_OK; } /*********************** Flash interface functions **************************/ static const struct command_registration lpc2900_exec_command_handlers[] = { { .name = "signature", .usage = "<bank>", .handler = lpc2900_handle_signature_command, .mode = COMMAND_EXEC, .help = "Calculate and display signature of flash bank.", }, { .name = "read_custom", .handler = lpc2900_handle_read_custom_command, .mode = COMMAND_EXEC, .usage = "bank_id filename", .help = "Copies 912 bytes of customer information " "from index sector into file.", }, { .name = "password", .handler = lpc2900_handle_password_command, .mode = COMMAND_EXEC, .usage = "bank_id password", .help = "Enter fixed password to enable 'dangerous' options.", }, { .name = "write_custom", .handler = lpc2900_handle_write_custom_command, .mode = COMMAND_EXEC, .usage = "bank_id filename ('bin'|'ihex'|'elf'|'s19')", .help = "Copies 912 bytes of customer info from file " "to index sector.", }, { .name = "secure_sector", .handler = lpc2900_handle_secure_sector_command, .mode = COMMAND_EXEC, .usage = "bank_id first_sector last_sector", .help = "Activate sector security for a range of sectors. " "It will be effective after a power cycle.", }, { .name = "secure_jtag", .handler = lpc2900_handle_secure_jtag_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Disable the JTAG port. " "It will be effective after a power cycle.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration lpc2900_command_handlers[] = { { .name = "lpc2900", .mode = COMMAND_ANY, .help = "LPC2900 flash command group", .usage = "", .chain = lpc2900_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Evaluate flash bank command. */ FLASH_BANK_COMMAND_HANDLER(lpc2900_flash_bank_command) { struct lpc2900_flash_bank *lpc2900_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; lpc2900_info = malloc(sizeof(struct lpc2900_flash_bank)); bank->driver_priv = lpc2900_info; /* Get flash clock. * Reject it if we can't meet the requirements for program time * (if clock too slow), or for erase time (clock too fast). */ uint32_t clk_sys_fmc; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], clk_sys_fmc); lpc2900_info->clk_sys_fmc = clk_sys_fmc * 1000; uint32_t clock_limit; /* Check program time limit */ clock_limit = 512000000l / FLASH_PROGRAM_TIME; if (lpc2900_info->clk_sys_fmc < clock_limit) { LOG_WARNING("flash clock must be at least %" PRIu32 " kHz", (clock_limit / 1000)); return ERROR_FLASH_BANK_INVALID; } /* Check erase time limit */ clock_limit = (uint32_t)((32767.0 * 512.0 * 1e6) / FLASH_ERASE_TIME); if (lpc2900_info->clk_sys_fmc > clock_limit) { LOG_WARNING("flash clock must be a maximum of %" PRIu32 " kHz", (clock_limit / 1000)); return ERROR_FLASH_BANK_INVALID; } /* Chip ID will be obtained by probing the device later */ lpc2900_info->chipid = 0; lpc2900_info->is_probed = false; return ERROR_OK; } /** * Erase sector(s). * * @param bank Pointer to the flash bank descriptor * @param first First sector to be erased * @param last Last sector (including) to be erased */ static int lpc2900_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { uint32_t status; unsigned int last_unsecured_sector; bool has_unsecured_sector; struct target *target = bank->target; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; status = lpc2900_is_ready(bank); if (status != ERROR_OK) return status; /* Sanity check on sector range */ if ((last < first) || (last >= bank->num_sectors)) { LOG_INFO("Bad sector range"); return ERROR_FLASH_SECTOR_INVALID; } /* Update the info about secured sectors */ lpc2900_read_security_status(bank); /* The selected sector range might include secured sectors. An attempt * to erase such a sector will cause the erase to fail also for unsecured * sectors. It is necessary to determine the last unsecured sector now, * because we have to treat the last relevant sector in the list in * a special way. */ last_unsecured_sector = -1; has_unsecured_sector = false; for (unsigned int sector = first; sector <= last; sector++) { if (!bank->sectors[sector].is_protected) { last_unsecured_sector = sector; has_unsecured_sector = true; } } /* Exit now, in case of the rare constellation where all sectors in range * are secured. This is regarded a success, since erasing/programming of * secured sectors shall be handled transparently. */ if (!has_unsecured_sector) return ERROR_OK; /* Enable flash block and set the correct CRA clock of 66 kHz */ lpc2900_setup(bank); /* Clear END_OF_ERASE interrupt status */ target_write_u32(target, INT_CLR_STATUS, INTSRC_END_OF_ERASE); /* Set the program/erase timer to FLASH_ERASE_TIME */ target_write_u32(target, FPTR, FPTR_EN_T | lpc2900_calc_tr(lpc2900_info->clk_sys_fmc, FLASH_ERASE_TIME)); /* Sectors are marked for erasure, then erased all together */ for (unsigned int sector = first; sector <= last_unsecured_sector; sector++) { /* Only mark sectors that aren't secured. Any attempt to erase a group * of sectors will fail if any single one of them is secured! */ if (!bank->sectors[sector].is_protected) { /* Unprotect the sector */ target_write_u32(target, bank->sectors[sector].offset, 0); target_write_u32(target, FCTR, FCTR_FS_LOADREQ | FCTR_FS_WPB | FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS); /* Mark the sector for erasure. The last sector in the list triggers the erasure. */ target_write_u32(target, bank->sectors[sector].offset, 0); if (sector == last_unsecured_sector) { target_write_u32(target, FCTR, FCTR_FS_PROGREQ | FCTR_FS_WPB | FCTR_FS_CS); } else { target_write_u32(target, FCTR, FCTR_FS_LOADREQ | FCTR_FS_WPB | FCTR_FS_WEB | FCTR_FS_CS); } } } /* Wait for the end of the erase operation. If it's not over after two seconds, * something went dreadfully wrong... :-( */ if (lpc2900_wait_status(bank, INTSRC_END_OF_ERASE, 2000) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; /* Normal flash operating mode */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); return ERROR_OK; } /* lpc2900_protect command is not supported. * "Protection" in LPC2900 terms is handled transparently. Sectors will * automatically be unprotected as needed. * Instead we use the concept of sector security. A secured sector is shown * as "protected" in OpenOCD. Sector security is a permanent feature, and * cannot be disabled once activated. */ /** * Write data to flash. * * @param bank Pointer to the flash bank descriptor * @param buffer Buffer with data * @param offset Start address (relative to bank start) * @param count Number of bytes to be programmed */ static int lpc2900_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { uint8_t page[FLASH_PAGE_SIZE]; uint32_t status; uint32_t num_bytes; struct target *target = bank->target; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; int retval; static const uint32_t write_target_code[] = { /* Set auto latch mode: FCTR=CS|WRE|WEB */ 0xe3a0a007, /* loop mov r10, #0x007 */ 0xe583a000, /* str r10,[r3,#0] */ /* Load complete page into latches */ 0xe3a06020, /* mov r6,#(512/16) */ 0xe8b00f00, /* next ldmia r0!,{r8-r11} */ 0xe8a10f00, /* stmia r1!,{r8-r11} */ 0xe2566001, /* subs r6,#1 */ 0x1afffffb, /* bne next */ /* Clear END_OF_BURN interrupt status */ 0xe3a0a002, /* mov r10,#(1 << 1) */ 0xe583afe8, /* str r10,[r3,#0xfe8] */ /* Set the erase time to FLASH_PROGRAM_TIME */ 0xe5834008, /* str r4,[r3,#8] */ /* Trigger flash write * FCTR = CS | WRE | WPB | PROGREQ */ 0xe3a0a083, /* mov r10,#0x83 */ 0xe38aaa01, /* orr r10,#0x1000 */ 0xe583a000, /* str r10,[r3,#0] */ /* Wait for end of burn */ 0xe593afe0, /* wait ldr r10,[r3,#0xfe0] */ 0xe21aa002, /* ands r10,#(1 << 1) */ 0x0afffffc, /* beq wait */ /* End? */ 0xe2522001, /* subs r2,#1 */ 0x1affffed, /* bne loop */ 0xeafffffe /* done b done */ }; status = lpc2900_is_ready(bank); if (status != ERROR_OK) return status; /* Enable flash block and set the correct CRA clock of 66 kHz */ lpc2900_setup(bank); /* Update the info about secured sectors */ lpc2900_read_security_status(bank); /* Unprotect all involved sectors */ for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { /* Start address in or before this sector? * End address in or behind this sector? */ if (((bank->base + offset) < (bank->sectors[sector].offset + bank->sectors[sector].size)) && ((bank->base + (offset + count - 1)) >= bank->sectors[sector].offset)) { /* This sector is involved and needs to be unprotected. * Don't do it for secured sectors. */ if (!bank->sectors[sector].is_protected) { target_write_u32(target, bank->sectors[sector].offset, 0); target_write_u32(target, FCTR, FCTR_FS_LOADREQ | FCTR_FS_WPB | FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS); } } } /* Set the program/erase time to FLASH_PROGRAM_TIME */ uint32_t prog_time = FPTR_EN_T | lpc2900_calc_tr(lpc2900_info->clk_sys_fmc, FLASH_PROGRAM_TIME); /* If there is a working area of reasonable size, use it to program via * a target algorithm. If not, fall back to host programming. */ /* We need some room for target code. */ const uint32_t target_code_size = sizeof(write_target_code); /* Try working area allocation. Start with a large buffer, and try with * reduced size if that fails. */ struct working_area *warea; uint32_t buffer_size = lpc2900_info->max_ram_block - 1 * KiB; while (target_alloc_working_area_try(target, buffer_size + target_code_size, &warea) != ERROR_OK) { /* Try a smaller buffer now, and stop if it's too small. */ buffer_size -= 1 * KiB; if (buffer_size < 2 * KiB) { LOG_INFO("no (large enough) working area, falling back to host mode"); warea = NULL; break; } } if (warea) { struct reg_param reg_params[5]; struct arm_algorithm arm_algo; /* We can use target mode. Download the algorithm. */ uint8_t code[sizeof(write_target_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(write_target_code), write_target_code); retval = target_write_buffer(target, (warea->address) + buffer_size, sizeof(code), code); if (retval != ERROR_OK) { LOG_ERROR("Unable to write block write code to target"); target_free_all_working_areas(target); return ERROR_FLASH_OPERATION_FAILED; } init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* Write to flash in large blocks */ while (count != 0) { uint32_t this_npages; const uint8_t *this_buffer; unsigned int start_sector = lpc2900_address2sector(bank, offset); /* First page / last page / rest */ if (offset % FLASH_PAGE_SIZE) { /* Block doesn't start on page boundary. * Burn first partial page separately. */ memset(&page, 0xff, sizeof(page)); memcpy(&page[offset % FLASH_PAGE_SIZE], buffer, FLASH_PAGE_SIZE - (offset % FLASH_PAGE_SIZE)); this_npages = 1; this_buffer = &page[0]; count = count + (offset % FLASH_PAGE_SIZE); offset = offset - (offset % FLASH_PAGE_SIZE); } else if (count < FLASH_PAGE_SIZE) { /* Download last incomplete page separately. */ memset(&page, 0xff, sizeof(page)); memcpy(&page, buffer, count); this_npages = 1; this_buffer = &page[0]; count = FLASH_PAGE_SIZE; } else { /* Download as many full pages as possible */ this_npages = (count < buffer_size) ? count / FLASH_PAGE_SIZE : buffer_size / FLASH_PAGE_SIZE; this_buffer = buffer; /* Make sure we stop at the next secured sector */ unsigned int sector = start_sector + 1; while (sector < bank->num_sectors) { /* Secured? */ if (bank->sectors[sector].is_protected) { /* Is that next sector within the current block? */ if ((bank->sectors[sector].offset - bank->base) < (offset + (this_npages * FLASH_PAGE_SIZE))) { /* Yes! Split the block */ this_npages = (bank->sectors[sector].offset - bank->base - offset) / FLASH_PAGE_SIZE; break; } } sector++; } } /* Skip the current sector if it is secured */ if (bank->sectors[start_sector].is_protected) { LOG_DEBUG("Skip secured sector %u", start_sector); /* Stop if this is the last sector */ if (start_sector == bank->num_sectors - 1) break; /* Skip */ uint32_t nskip = bank->sectors[start_sector].size - (offset % bank->sectors[start_sector].size); offset += nskip; buffer += nskip; count = (count >= nskip) ? (count - nskip) : 0; continue; } /* Execute buffer download */ retval = target_write_buffer(target, warea->address, this_npages * FLASH_PAGE_SIZE, this_buffer); if (retval != ERROR_OK) { LOG_ERROR("Unable to write data to target"); target_free_all_working_areas(target); return ERROR_FLASH_OPERATION_FAILED; } /* Prepare registers */ buf_set_u32(reg_params[0].value, 0, 32, warea->address); buf_set_u32(reg_params[1].value, 0, 32, offset); buf_set_u32(reg_params[2].value, 0, 32, this_npages); buf_set_u32(reg_params[3].value, 0, 32, FCTR); buf_set_u32(reg_params[4].value, 0, 32, FPTR_EN_T | prog_time); /* Execute algorithm, assume breakpoint for last instruction */ arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; retval = target_run_algorithm(target, 0, NULL, 5, reg_params, (warea->address) + buffer_size, (warea->address) + buffer_size + target_code_size - 4, 10000, /* 10s should be enough for max. 16 KiB of data */ &arm_algo); if (retval != ERROR_OK) { LOG_ERROR("Execution of flash algorithm failed."); target_free_all_working_areas(target); retval = ERROR_FLASH_OPERATION_FAILED; break; } count -= this_npages * FLASH_PAGE_SIZE; buffer += this_npages * FLASH_PAGE_SIZE; offset += this_npages * FLASH_PAGE_SIZE; } /* Free all resources */ destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); target_free_all_working_areas(target); } else { /* Write to flash memory page-wise */ while (count != 0) { /* How many bytes do we copy this time? */ num_bytes = (count >= FLASH_PAGE_SIZE) ? FLASH_PAGE_SIZE - (offset % FLASH_PAGE_SIZE) : count; /* Don't do anything with it if the page is in a secured sector. */ if (!bank->sectors[lpc2900_address2sector(bank, offset)].is_protected) { /* Set latch load mode */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WRE | FCTR_FS_WEB); /* Always clear the buffer (a little overhead, but who cares) */ memset(page, 0xFF, FLASH_PAGE_SIZE); /* Copy them to the buffer */ memcpy(&page[offset % FLASH_PAGE_SIZE], &buffer[offset % FLASH_PAGE_SIZE], num_bytes); /* Write whole page to flash data latches */ if (target_write_memory(target, bank->base + (offset - (offset % FLASH_PAGE_SIZE)), 4, FLASH_PAGE_SIZE / 4, page) != ERROR_OK) { LOG_ERROR("Write failed @ 0x%8.8" PRIx32, offset); target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); return ERROR_FLASH_OPERATION_FAILED; } /* Clear END_OF_BURN interrupt status */ target_write_u32(target, INT_CLR_STATUS, INTSRC_END_OF_BURN); /* Set the programming time */ target_write_u32(target, FPTR, FPTR_EN_T | prog_time); /* Trigger flash write */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WRE | FCTR_FS_WPB | FCTR_FS_PROGREQ); /* Wait for the end of the write operation. If it's not over * after one second, something went dreadfully wrong... :-( */ if (lpc2900_wait_status(bank, INTSRC_END_OF_BURN, 1000) != ERROR_OK) { LOG_ERROR("Write failed @ 0x%8.8" PRIx32, offset); target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); return ERROR_FLASH_OPERATION_FAILED; } } /* Update pointers and counters */ offset += num_bytes; buffer += num_bytes; count -= num_bytes; } retval = ERROR_OK; } /* Normal flash operating mode */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); return retval; } /** * Try and identify the device. * * Determine type number and its memory layout. * * @param bank Pointer to the flash bank descriptor */ static int lpc2900_probe(struct flash_bank *bank) { struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; struct target *target = bank->target; uint32_t offset; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* We want to do this only once. */ if (lpc2900_info->is_probed) return ERROR_OK; /* Probing starts with reading the CHIPID register. We will continue only * if this identifies as an LPC2900 device. */ target_read_u32(target, CHIPID, &lpc2900_info->chipid); if (lpc2900_info->chipid != EXPECTED_CHIPID) { LOG_WARNING("Device is not an LPC29xx"); return ERROR_FLASH_OPERATION_FAILED; } /* It's an LPC29xx device. Now read the feature register FEAT0...FEAT3. */ uint32_t feat0, feat1, feat2, feat3; target_read_u32(target, FEAT0, &feat0); target_read_u32(target, FEAT1, &feat1); target_read_u32(target, FEAT2, &feat2); target_read_u32(target, FEAT3, &feat3); /* Base address */ bank->base = 0x20000000; /* Determine flash layout from FEAT2 register */ uint32_t num_64k_sectors = (feat2 >> 16) & 0xFF; uint32_t num_8k_sectors = (feat2 >> 0) & 0xFF; bank->num_sectors = num_64k_sectors + num_8k_sectors; bank->size = KiB * (64 * num_64k_sectors + 8 * num_8k_sectors); /* Determine maximum contiguous RAM block */ lpc2900_info->max_ram_block = 16 * KiB; if ((feat1 & 0x30) == 0x30) { lpc2900_info->max_ram_block = 32 * KiB; if ((feat1 & 0x0C) == 0x0C) lpc2900_info->max_ram_block = 48 * KiB; } /* Determine package code and ITCM size */ uint32_t package_code = feat0 & 0x0F; uint32_t itcm_code = (feat1 >> 16) & 0x1F; /* Determine the exact type number. */ uint32_t found = 1; if ((package_code == 4) && (itcm_code == 5)) { /* Old LPC2917 or LPC2919 (non-/01 devices) */ lpc2900_info->target_name = (bank->size == 768*KiB) ? "LPC2919" : "LPC2917"; } else { if (package_code == 2) { /* 100-pin package */ if (bank->size == 128*KiB) lpc2900_info->target_name = "LPC2921"; else if (bank->size == 256*KiB) lpc2900_info->target_name = "LPC2923"; else if (bank->size == 512*KiB) lpc2900_info->target_name = "LPC2925"; else found = 0; } else if (package_code == 4) { /* 144-pin package */ if ((bank->size == 256*KiB) && (feat3 == 0xFFFFFFE9)) lpc2900_info->target_name = "LPC2926"; else if ((bank->size == 512*KiB) && (feat3 == 0xFFFFFCF0)) lpc2900_info->target_name = "LPC2917/01"; else if ((bank->size == 512*KiB) && (feat3 == 0xFFFFFFF1)) lpc2900_info->target_name = "LPC2927"; else if ((bank->size == 768*KiB) && (feat3 == 0xFFFFFCF8)) lpc2900_info->target_name = "LPC2919/01"; else if ((bank->size == 768*KiB) && (feat3 == 0xFFFFFFF9)) lpc2900_info->target_name = "LPC2929"; else found = 0; } else if (package_code == 5) { /* 208-pin package */ lpc2900_info->target_name = (bank->size == 0) ? "LPC2930" : "LPC2939"; } else found = 0; } if (!found) { LOG_WARNING("Unknown LPC29xx derivative (FEATx=" "%08" PRIx32 ":%08" PRIx32 ":%08" PRIx32 ":%08" PRIx32 ")", feat0, feat1, feat2, feat3); return ERROR_FLASH_OPERATION_FAILED; } /* Show detected device */ LOG_INFO("Flash bank %u: Device %s, %" PRIu32 " KiB in %u sectors", bank->bank_number, lpc2900_info->target_name, bank->size / KiB, bank->num_sectors); /* Flashless devices cannot be handled */ if (bank->num_sectors == 0) { LOG_WARNING("Flashless device cannot be handled"); return ERROR_FLASH_OPERATION_FAILED; } /* Sector layout. * These are logical sector numbers. When doing real flash operations, * the logical flash number are translated into the physical flash numbers * of the device. */ bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); offset = 0; for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; if (i <= 7) bank->sectors[i].size = 8 * KiB; else if (i <= 18) bank->sectors[i].size = 64 * KiB; else { /* We shouldn't come here. But there might be a new part out there * that has more than 19 sectors. Politely ask for a fix then. */ bank->sectors[i].size = 0; LOG_ERROR("Never heard about sector %u", i); } offset += bank->sectors[i].size; } lpc2900_info->is_probed = true; /* Read sector security status */ if (lpc2900_read_security_status(bank) != ERROR_OK) { LOG_ERROR("Cannot determine sector security status"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } /** * Run a blank check for each sector. * * For speed reasons, the device isn't read word by word. * A hash value is calculated by the hardware ("BIST") for each sector. * This value is then compared against the known hash of an empty sector. * * @param bank Pointer to the flash bank descriptor */ static int lpc2900_erase_check(struct flash_bank *bank) { uint32_t status = lpc2900_is_ready(bank); if (status != ERROR_OK) { LOG_INFO("Processor not halted/not probed"); return status; } /* Use the BIST (Built-In Self Test) to generate a signature of each flash * sector. Compare against the expected signature of an empty sector. */ for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { uint32_t signature[4]; status = lpc2900_run_bist128(bank, bank->sectors[sector].offset, bank->sectors[sector].offset + (bank->sectors[sector].size - 1), signature); if (status != ERROR_OK) return status; /* The expected signatures for an empty sector are different * for 8 KiB and 64 KiB sectors. */ if (bank->sectors[sector].size == 8*KiB) { bank->sectors[sector].is_erased = (signature[3] == 0x01ABAAAA) && (signature[2] == 0xAAAAAAAA) && (signature[1] == 0xAAAAAAAA) && (signature[0] == 0xAAA00AAA); } if (bank->sectors[sector].size == 64*KiB) { bank->sectors[sector].is_erased = (signature[3] == 0x11801222) && (signature[2] == 0xB88844FF) && (signature[1] == 0x11A22008) && (signature[0] == 0x2B1BFE44); } } return ERROR_OK; } /** * Get protection (sector security) status. * * Determine the status of "sector security" for each sector. * A secured sector is one that can never be erased/programmed again. * * @param bank Pointer to the flash bank descriptor */ static int lpc2900_protect_check(struct flash_bank *bank) { return lpc2900_read_security_status(bank); } const struct flash_driver lpc2900_flash = { .name = "lpc2900", .commands = lpc2900_command_handlers, .flash_bank_command = lpc2900_flash_bank_command, .erase = lpc2900_erase, .write = lpc2900_write, .read = default_flash_read, .probe = lpc2900_probe, .auto_probe = lpc2900_probe, .erase_check = lpc2900_erase_check, .protect_check = lpc2900_protect_check, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/lpcspifi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "spi.h" #include <jtag/jtag.h> #include <helper/time_support.h> #include <target/algorithm.h> #include <target/armv7m.h> /* Offsets from ssp_base into config & data registers */ #define SSP_CR0 (0x00) /* Control register 0 */ #define SSP_CR1 (0x04) /* Control register 1 */ #define SSP_DATA (0x08) /* Data register (TX and RX) */ #define SSP_SR (0x0C) /* Status register */ #define SSP_CPSR (0x10) /* Clock prescale register */ /* Status register fields */ #define SSP_BSY (0x00000010) /* Timeout in ms */ #define SSP_CMD_TIMEOUT (100) #define SSP_PROBE_TIMEOUT (100) #define SSP_MAX_TIMEOUT (3000) /* Size of the stack to alloc in the working area for the execution of * the ROM spifi_init() function */ #define SPIFI_INIT_STACK_SIZE 512 struct lpcspifi_flash_bank { bool probed; uint32_t ssp_base; uint32_t io_base; uint32_t ioconfig_base; uint32_t bank_num; uint32_t max_spi_clock_mhz; const struct flash_device *dev; }; /* flash_bank lpcspifi <base> <size> <chip_width> <bus_width> <target> */ FLASH_BANK_COMMAND_HANDLER(lpcspifi_flash_bank_command) { struct lpcspifi_flash_bank *lpcspifi_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; lpcspifi_info = malloc(sizeof(struct lpcspifi_flash_bank)); if (!lpcspifi_info) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } bank->driver_priv = lpcspifi_info; lpcspifi_info->probed = false; return ERROR_OK; } static inline int ioconfig_write_reg(struct target *target, uint32_t ioconfig_base, uint32_t offset, uint32_t value) { return target_write_u32(target, ioconfig_base + offset, value); } static inline int ssp_write_reg(struct target *target, uint32_t ssp_base, uint32_t offset, uint32_t value) { return target_write_u32(target, ssp_base + offset, value); } static inline int io_write_reg(struct target *target, uint32_t io_base, uint32_t offset, uint32_t value) { return target_write_u32(target, io_base + offset, value); } static inline int ssp_read_reg(struct target *target, uint32_t ssp_base, uint32_t offset, uint32_t *value) { return target_read_u32(target, ssp_base + offset, value); } static int ssp_setcs(struct target *target, uint32_t io_base, unsigned int value) { return io_write_reg(target, io_base, 0x12ac, value ? 0xffffffff : 0x00000000); } /* Poll the SSP busy flag. When this comes back as 0, the transfer is complete * and the controller is idle. */ static int poll_ssp_busy(struct target *target, uint32_t ssp_base, int timeout) { int64_t endtime; uint32_t value; int retval; retval = ssp_read_reg(target, ssp_base, SSP_SR, &value); if ((retval == ERROR_OK) && (value & SSP_BSY) == 0) return ERROR_OK; else if (retval != ERROR_OK) return retval; endtime = timeval_ms() + timeout; do { alive_sleep(1); retval = ssp_read_reg(target, ssp_base, SSP_SR, &value); if ((retval == ERROR_OK) && (value & SSP_BSY) == 0) return ERROR_OK; else if (retval != ERROR_OK) return retval; } while (timeval_ms() < endtime); LOG_ERROR("Timeout while polling BSY"); return ERROR_FLASH_OPERATION_FAILED; } /* Un-initialize the ssp module and initialize the SPIFI module */ static int lpcspifi_set_hw_mode(struct flash_bank *bank) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t ssp_base = lpcspifi_info->ssp_base; struct armv7m_algorithm armv7m_info; struct working_area *spifi_init_algorithm; struct reg_param reg_params[2]; int retval = ERROR_OK; LOG_DEBUG("Uninitializing LPC43xx SSP"); /* Turn off the SSP module */ retval = ssp_write_reg(target, ssp_base, SSP_CR1, 0x00000000); if (retval != ERROR_OK) return retval; /* see contrib/loaders/flash/lpcspifi_init.S for src */ static const uint8_t spifi_init_code[] = { 0x4f, 0xea, 0x00, 0x08, 0xa1, 0xb0, 0x00, 0xaf, 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03, 0x4f, 0xf0, 0xf3, 0x02, 0xc3, 0xf8, 0x8c, 0x21, 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03, 0x4f, 0xf4, 0xc0, 0x42, 0xc4, 0xf2, 0x08, 0x02, 0x4f, 0xf4, 0xc0, 0x41, 0xc4, 0xf2, 0x08, 0x01, 0x4f, 0xf4, 0xc0, 0x40, 0xc4, 0xf2, 0x08, 0x00, 0x4f, 0xf0, 0xd3, 0x04, 0xc0, 0xf8, 0x9c, 0x41, 0x20, 0x46, 0xc1, 0xf8, 0x98, 0x01, 0x01, 0x46, 0xc2, 0xf8, 0x94, 0x11, 0xc3, 0xf8, 0x90, 0x11, 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03, 0x4f, 0xf0, 0x13, 0x02, 0xc3, 0xf8, 0xa0, 0x21, 0x40, 0xf2, 0x18, 0x13, 0xc1, 0xf2, 0x40, 0x03, 0x1b, 0x68, 0x1c, 0x68, 0x40, 0xf2, 0xb4, 0x30, 0xc1, 0xf2, 0x00, 0x00, 0x4f, 0xf0, 0x03, 0x01, 0x4f, 0xf0, 0xc0, 0x02, 0x4f, 0xea, 0x08, 0x03, 0xa0, 0x47, 0x00, 0xf0, 0x00, 0xb8, 0x00, 0xbe }; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; LOG_DEBUG("Allocating working area for SPIFI init algorithm"); /* Get memory for spifi initialization algorithm */ retval = target_alloc_working_area(target, sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE, &spifi_init_algorithm); if (retval != ERROR_OK) { LOG_ERROR("Insufficient working area to initialize SPIFI " "module. You must allocate at least %zdB of working " "area in order to use this driver.", sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE ); return retval; } LOG_DEBUG("Writing algorithm to working area at " TARGET_ADDR_FMT, spifi_init_algorithm->address); /* Write algorithm to working area */ retval = target_write_buffer(target, spifi_init_algorithm->address, sizeof(spifi_init_code), spifi_init_code ); if (retval != ERROR_OK) { target_free_working_area(target, spifi_init_algorithm); return retval; } init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* spifi clk speed */ /* the spifi_init() rom API makes use of the stack */ init_reg_param(®_params[1], "sp", 32, PARAM_OUT); /* For now, the algorithm will set up the SPIFI module * @ the IRC clock speed. In the future, it could be made * a bit smarter to use other clock sources if the user has * already configured them in order to speed up memory- * mapped reads. */ buf_set_u32(reg_params[0].value, 0, 32, 12); /* valid stack pointer */ buf_set_u32(reg_params[1].value, 0, 32, (spifi_init_algorithm->address + sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE) & ~7UL); /* Run the algorithm */ LOG_DEBUG("Running SPIFI init algorithm"); retval = target_run_algorithm(target, 0, NULL, 2, reg_params, spifi_init_algorithm->address, spifi_init_algorithm->address + sizeof(spifi_init_code) - 2, 1000, &armv7m_info); if (retval != ERROR_OK) LOG_ERROR("Error executing SPIFI init algorithm"); target_free_working_area(target, spifi_init_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); return retval; } /* Initialize the ssp module */ static int lpcspifi_set_sw_mode(struct flash_bank *bank) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t ssp_base = lpcspifi_info->ssp_base; uint32_t io_base = lpcspifi_info->io_base; uint32_t ioconfig_base = lpcspifi_info->ioconfig_base; int retval = ERROR_OK; /* Re-initialize SPIFI. There are a couple of errata on this, so this makes sure that nothing's in an unhappy state. */ retval = lpcspifi_set_hw_mode(bank); /* If we couldn't initialize hardware mode, don't even bother continuing */ if (retval != ERROR_OK) return retval; /* Initialize the pins */ retval = ioconfig_write_reg(target, ioconfig_base, 0x194, 0x00000040); if (retval == ERROR_OK) retval = ioconfig_write_reg(target, ioconfig_base, 0x1a0, 0x00000044); if (retval == ERROR_OK) retval = ioconfig_write_reg(target, ioconfig_base, 0x190, 0x00000040); if (retval == ERROR_OK) retval = ioconfig_write_reg(target, ioconfig_base, 0x19c, 0x000000ed); if (retval == ERROR_OK) retval = ioconfig_write_reg(target, ioconfig_base, 0x198, 0x000000ed); if (retval == ERROR_OK) retval = ioconfig_write_reg(target, ioconfig_base, 0x18c, 0x000000ea); /* Set CS high & as an output */ if (retval == ERROR_OK) retval = io_write_reg(target, io_base, 0x12ac, 0xffffffff); if (retval == ERROR_OK) retval = io_write_reg(target, io_base, 0x2014, 0x00000800); /* Initialize the module */ if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_CR0, 0x00000007); if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_CR1, 0x00000000); if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_CPSR, 0x00000008); if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_CR1, 0x00000002); /* If something didn't work out, attempt to return SPIFI to HW mode */ if (retval != ERROR_OK) lpcspifi_set_hw_mode(bank); return retval; } /* Read the status register of the external SPI flash chip. */ static int read_status_reg(struct flash_bank *bank, uint32_t *status) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t ssp_base = lpcspifi_info->ssp_base; uint32_t io_base = lpcspifi_info->io_base; uint32_t value; int retval = ERROR_OK; retval = ssp_setcs(target, io_base, 0); if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, SPIFLASH_READ_STATUS); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); /* Dummy write to clock in the register */ if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_setcs(target, io_base, 1); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); if (retval == ERROR_OK) *status = value; return retval; } /* check for BSY bit in flash status register */ /* timeout in ms */ static int wait_till_ready(struct flash_bank *bank, int timeout) { uint32_t status; int retval; int64_t endtime; endtime = timeval_ms() + timeout; do { /* read flash status register */ retval = read_status_reg(bank, &status); if (retval != ERROR_OK) return retval; if ((status & SPIFLASH_BSY_BIT) == 0) return ERROR_OK; alive_sleep(1); } while (timeval_ms() < endtime); LOG_ERROR("timeout waiting for flash to finish write/erase operation"); return ERROR_FAIL; } /* Send "write enable" command to SPI flash chip. */ static int lpcspifi_write_enable(struct flash_bank *bank) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t ssp_base = lpcspifi_info->ssp_base; uint32_t io_base = lpcspifi_info->io_base; uint32_t status, value; int retval = ERROR_OK; retval = ssp_setcs(target, io_base, 0); if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, SPIFLASH_WRITE_ENABLE); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); if (retval == ERROR_OK) retval = ssp_setcs(target, io_base, 1); /* read flash status register */ if (retval == ERROR_OK) retval = read_status_reg(bank, &status); if (retval != ERROR_OK) return retval; /* Check write enabled */ if ((status & SPIFLASH_WE_BIT) == 0) { LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status); return ERROR_FAIL; } return retval; } static int lpcspifi_bulk_erase(struct flash_bank *bank) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t ssp_base = lpcspifi_info->ssp_base; uint32_t io_base = lpcspifi_info->io_base; uint32_t value; int retval = ERROR_OK; if (lpcspifi_info->dev->chip_erase_cmd == 0x00) return ERROR_FLASH_OPER_UNSUPPORTED; retval = lpcspifi_set_sw_mode(bank); if (retval == ERROR_OK) retval = lpcspifi_write_enable(bank); /* send SPI command "bulk erase" */ if (retval == ERROR_OK) ssp_setcs(target, io_base, 0); if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, lpcspifi_info->dev->chip_erase_cmd); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); if (retval == ERROR_OK) retval = ssp_setcs(target, io_base, 1); /* poll flash BSY for self-timed bulk erase */ if (retval == ERROR_OK) retval = wait_till_ready(bank, bank->num_sectors*SSP_MAX_TIMEOUT); return retval; } static int lpcspifi_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; struct working_area *erase_algorithm; int retval = ERROR_OK; LOG_DEBUG("erase from sector %u to sector %u", first, last); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((last < first) || (last >= bank->num_sectors)) { LOG_ERROR("Flash sector invalid"); return ERROR_FLASH_SECTOR_INVALID; } if (!(lpcspifi_info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } for (unsigned int sector = first; sector <= last; sector++) { if (bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FAIL; } } /* If we're erasing the entire chip and the flash supports * it, use a bulk erase instead of going sector-by-sector. */ if (first == 0 && last == (bank->num_sectors - 1) && lpcspifi_info->dev->chip_erase_cmd != lpcspifi_info->dev->erase_cmd) { LOG_DEBUG("Chip supports the bulk erase command." " Will use bulk erase instead of sector-by-sector erase."); retval = lpcspifi_bulk_erase(bank); if (retval == ERROR_OK) { retval = lpcspifi_set_hw_mode(bank); return retval; } else LOG_WARNING("Bulk flash erase failed. Falling back to sector-by-sector erase."); } if (lpcspifi_info->dev->erase_cmd == 0x00) return ERROR_FLASH_OPER_UNSUPPORTED; retval = lpcspifi_set_hw_mode(bank); if (retval != ERROR_OK) return retval; /* see contrib/loaders/flash/lpcspifi_erase.S for src */ static const uint8_t lpcspifi_flash_erase_code[] = { 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0xea, 0x08, 0xca, 0xf8, 0x8c, 0x81, 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x90, 0x81, 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x94, 0x81, 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x98, 0x81, 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x9c, 0x81, 0x4f, 0xf0, 0x44, 0x08, 0xca, 0xf8, 0xa0, 0x81, 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0x4f, 0xf4, 0x00, 0x68, 0xca, 0xf8, 0x14, 0x80, 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0x4f, 0xf0, 0xff, 0x08, 0xca, 0xf8, 0xab, 0x80, 0x4f, 0xf0, 0x00, 0x0a, 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x00, 0x08, 0xc0, 0xf2, 0x00, 0x18, 0xca, 0xf8, 0x94, 0x80, 0x4f, 0xf4, 0x00, 0x5a, 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x01, 0x08, 0xca, 0xf8, 0x00, 0x87, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0x07, 0x08, 0xca, 0xf8, 0x00, 0x80, 0x4f, 0xf0, 0x02, 0x08, 0xca, 0xf8, 0x10, 0x80, 0xca, 0xf8, 0x04, 0x80, 0x00, 0xf0, 0x52, 0xf8, 0x4f, 0xf0, 0x06, 0x09, 0x00, 0xf0, 0x3b, 0xf8, 0x00, 0xf0, 0x48, 0xf8, 0x00, 0xf0, 0x4a, 0xf8, 0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x33, 0xf8, 0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x2f, 0xf8, 0x00, 0xf0, 0x3c, 0xf8, 0x19, 0xf0, 0x02, 0x0f, 0x00, 0xf0, 0x45, 0x80, 0x00, 0xf0, 0x3a, 0xf8, 0x4f, 0xea, 0x02, 0x09, 0x00, 0xf0, 0x23, 0xf8, 0x4f, 0xea, 0x10, 0x49, 0x00, 0xf0, 0x1f, 0xf8, 0x4f, 0xea, 0x10, 0x29, 0x00, 0xf0, 0x1b, 0xf8, 0x4f, 0xea, 0x00, 0x09, 0x00, 0xf0, 0x17, 0xf8, 0x00, 0xf0, 0x24, 0xf8, 0x00, 0xf0, 0x26, 0xf8, 0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x0f, 0xf8, 0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x0b, 0xf8, 0x00, 0xf0, 0x18, 0xf8, 0x19, 0xf0, 0x01, 0x0f, 0x7f, 0xf4, 0xf0, 0xaf, 0x01, 0x39, 0xf9, 0xb1, 0x18, 0x44, 0xff, 0xf7, 0xbf, 0xbf, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0xca, 0xf8, 0x08, 0x90, 0xda, 0xf8, 0x0c, 0x90, 0x19, 0xf0, 0x10, 0x0f, 0x7f, 0xf4, 0xfa, 0xaf, 0xda, 0xf8, 0x08, 0x90, 0x70, 0x47, 0x4f, 0xf0, 0xff, 0x08, 0x00, 0xf0, 0x02, 0xb8, 0x4f, 0xf0, 0x00, 0x08, 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0xca, 0xf8, 0xab, 0x80, 0x70, 0x47, 0x00, 0x20, 0x00, 0xbe, 0xff, 0xff }; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; /* Get memory for spifi initialization algorithm */ retval = target_alloc_working_area(target, sizeof(lpcspifi_flash_erase_code), &erase_algorithm); if (retval != ERROR_OK) { LOG_ERROR("Insufficient working area. You must configure a working" " area of at least %zdB in order to erase SPIFI flash.", sizeof(lpcspifi_flash_erase_code)); return retval; } /* Write algorithm to working area */ retval = target_write_buffer(target, erase_algorithm->address, sizeof(lpcspifi_flash_erase_code), lpcspifi_flash_erase_code); if (retval != ERROR_OK) { target_free_working_area(target, erase_algorithm); return retval; } init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* Start address */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* Sector count */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* Erase command */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* Sector size */ buf_set_u32(reg_params[0].value, 0, 32, bank->sectors[first].offset); buf_set_u32(reg_params[1].value, 0, 32, last - first + 1); buf_set_u32(reg_params[2].value, 0, 32, lpcspifi_info->dev->erase_cmd); buf_set_u32(reg_params[3].value, 0, 32, bank->sectors[first].size); /* Run the algorithm */ retval = target_run_algorithm(target, 0, NULL, 4, reg_params, erase_algorithm->address, erase_algorithm->address + sizeof(lpcspifi_flash_erase_code) - 4, 3000*(last - first + 1), &armv7m_info); if (retval != ERROR_OK) LOG_ERROR("Error executing flash erase algorithm"); target_free_working_area(target, erase_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); retval = lpcspifi_set_hw_mode(bank); return retval; } static int lpcspifi_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { for (unsigned int sector = first; sector <= last; sector++) bank->sectors[sector].is_protected = set; return ERROR_OK; } static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t page_size, fifo_size; struct working_area *fifo; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; struct working_area *write_algorithm; int retval = ERROR_OK; LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > lpcspifi_info->dev->size_in_bytes) { LOG_WARNING("Writes past end of flash. Extra data discarded."); count = lpcspifi_info->dev->size_in_bytes - offset; } /* Check sector protection */ for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { /* Start offset in or before this sector? */ /* End offset in or behind this sector? */ if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) && ((offset + count - 1) >= bank->sectors[sector].offset) && bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FAIL; } } /* if no valid page_size, use reasonable default */ page_size = lpcspifi_info->dev->pagesize ? lpcspifi_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE; retval = lpcspifi_set_hw_mode(bank); if (retval != ERROR_OK) return retval; /* see contrib/loaders/flash/lpcspifi_write.S for src */ static const uint8_t lpcspifi_flash_write_code[] = { 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0xea, 0x08, 0xca, 0xf8, 0x8c, 0x81, 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x90, 0x81, 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x94, 0x81, 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x98, 0x81, 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x9c, 0x81, 0x4f, 0xf0, 0x44, 0x08, 0xca, 0xf8, 0xa0, 0x81, 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0x4f, 0xf4, 0x00, 0x68, 0xca, 0xf8, 0x14, 0x80, 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0x4f, 0xf0, 0xff, 0x08, 0xca, 0xf8, 0xab, 0x80, 0x4f, 0xf0, 0x00, 0x0a, 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x00, 0x08, 0xc0, 0xf2, 0x00, 0x18, 0xca, 0xf8, 0x94, 0x80, 0x4f, 0xf4, 0x00, 0x5a, 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x01, 0x08, 0xca, 0xf8, 0x00, 0x87, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0x07, 0x08, 0xca, 0xf8, 0x00, 0x80, 0x4f, 0xf0, 0x02, 0x08, 0xca, 0xf8, 0x10, 0x80, 0xca, 0xf8, 0x04, 0x80, 0x4f, 0xf0, 0x00, 0x0b, 0xa3, 0x44, 0x93, 0x45, 0x7f, 0xf6, 0xfc, 0xaf, 0x00, 0xf0, 0x6a, 0xf8, 0x4f, 0xf0, 0x06, 0x09, 0x00, 0xf0, 0x53, 0xf8, 0x00, 0xf0, 0x60, 0xf8, 0x00, 0xf0, 0x62, 0xf8, 0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x4b, 0xf8, 0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x47, 0xf8, 0x00, 0xf0, 0x54, 0xf8, 0x19, 0xf0, 0x02, 0x0f, 0x00, 0xf0, 0x5d, 0x80, 0x00, 0xf0, 0x52, 0xf8, 0x4f, 0xf0, 0x02, 0x09, 0x00, 0xf0, 0x3b, 0xf8, 0x4f, 0xea, 0x12, 0x49, 0x00, 0xf0, 0x37, 0xf8, 0x4f, 0xea, 0x12, 0x29, 0x00, 0xf0, 0x33, 0xf8, 0x4f, 0xea, 0x02, 0x09, 0x00, 0xf0, 0x2f, 0xf8, 0xd0, 0xf8, 0x00, 0x80, 0xb8, 0xf1, 0x00, 0x0f, 0x00, 0xf0, 0x47, 0x80, 0x47, 0x68, 0x47, 0x45, 0x3f, 0xf4, 0xf6, 0xaf, 0x17, 0xf8, 0x01, 0x9b, 0x00, 0xf0, 0x21, 0xf8, 0x8f, 0x42, 0x28, 0xbf, 0x00, 0xf1, 0x08, 0x07, 0x47, 0x60, 0x01, 0x3b, 0xbb, 0xb3, 0x02, 0xf1, 0x01, 0x02, 0x93, 0x45, 0x7f, 0xf4, 0xe6, 0xaf, 0x00, 0xf0, 0x22, 0xf8, 0xa3, 0x44, 0x00, 0xf0, 0x23, 0xf8, 0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x0c, 0xf8, 0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x08, 0xf8, 0x00, 0xf0, 0x15, 0xf8, 0x19, 0xf0, 0x01, 0x0f, 0x7f, 0xf4, 0xf0, 0xaf, 0xff, 0xf7, 0xa7, 0xbf, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0xca, 0xf8, 0x08, 0x90, 0xda, 0xf8, 0x0c, 0x90, 0x19, 0xf0, 0x10, 0x0f, 0x7f, 0xf4, 0xfa, 0xaf, 0xda, 0xf8, 0x08, 0x90, 0x70, 0x47, 0x4f, 0xf0, 0xff, 0x08, 0x00, 0xf0, 0x02, 0xb8, 0x4f, 0xf0, 0x00, 0x08, 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0xca, 0xf8, 0xab, 0x80, 0x70, 0x47, 0x00, 0x20, 0x50, 0x60, 0xff, 0xf7, 0xef, 0xff, 0x30, 0x46, 0x00, 0xbe, 0xff, 0xff }; if (target_alloc_working_area(target, sizeof(lpcspifi_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_ERROR("Insufficient working area. You must configure" " a working area > %zdB in order to write to SPIFI flash.", sizeof(lpcspifi_flash_write_code)); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(lpcspifi_flash_write_code), lpcspifi_flash_write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } /* FIFO allocation */ fifo_size = target_get_working_area_avail(target); if (fifo_size == 0) { /* if we already allocated the writing code but failed to get fifo * space, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_ERROR("Insufficient working area. Please allocate at least" " %zdB of working area to enable flash writes.", sizeof(lpcspifi_flash_write_code) + 1 ); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } else if (fifo_size < page_size) LOG_WARNING("Working area size is limited; flash writes may be" " slow. Increase working area size to at least %zdB" " to reduce write times.", (size_t)(sizeof(lpcspifi_flash_write_code) + page_size) ); else if (fifo_size > 0x2000) /* Beyond this point, we start to get diminishing returns */ fifo_size = 0x2000; if (target_alloc_working_area(target, fifo_size, &fifo) != ERROR_OK) { target_free_working_area(target, write_algorithm); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* page size */ buf_set_u32(reg_params[0].value, 0, 32, fifo->address); buf_set_u32(reg_params[1].value, 0, 32, fifo->address + fifo->size); buf_set_u32(reg_params[2].value, 0, 32, offset); buf_set_u32(reg_params[3].value, 0, 32, count); buf_set_u32(reg_params[4].value, 0, 32, page_size); retval = target_run_flash_async_algorithm(target, buffer, count, 1, 0, NULL, 5, reg_params, fifo->address, fifo->size, write_algorithm->address, 0, &armv7m_info ); if (retval != ERROR_OK) LOG_ERROR("Error executing flash write algorithm"); target_free_working_area(target, fifo); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); /* Switch to HW mode before return to prompt */ retval = lpcspifi_set_hw_mode(bank); return retval; } /* Return ID of flash device */ /* On exit, SW mode is kept */ static int lpcspifi_read_flash_id(struct flash_bank *bank, uint32_t *id) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t ssp_base = lpcspifi_info->ssp_base; uint32_t io_base = lpcspifi_info->io_base; uint32_t value; uint8_t id_buf[3] = {0, 0, 0}; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_DEBUG("Getting ID"); retval = lpcspifi_set_sw_mode(bank); if (retval != ERROR_OK) return retval; /* poll WIP */ if (retval == ERROR_OK) retval = wait_till_ready(bank, SSP_PROBE_TIMEOUT); /* Send SPI command "read ID" */ if (retval == ERROR_OK) retval = ssp_setcs(target, io_base, 0); if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, SPIFLASH_READ_ID); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); /* Dummy write to clock in data */ if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); if (retval == ERROR_OK) id_buf[0] = value; /* Dummy write to clock in data */ if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); if (retval == ERROR_OK) id_buf[1] = value; /* Dummy write to clock in data */ if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); if (retval == ERROR_OK) id_buf[2] = value; if (retval == ERROR_OK) retval = ssp_setcs(target, io_base, 1); if (retval == ERROR_OK) *id = id_buf[2] << 16 | id_buf[1] << 8 | id_buf[0]; return retval; } static int lpcspifi_probe(struct flash_bank *bank) { struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; struct flash_sector *sectors; uint32_t id = 0; /* silence uninitialized warning */ int retval; uint32_t sectorsize; /* If we've already probed, we should be fine to skip this time. */ if (lpcspifi_info->probed) return ERROR_OK; lpcspifi_info->probed = false; lpcspifi_info->ssp_base = 0x40083000; lpcspifi_info->io_base = 0x400F4000; lpcspifi_info->ioconfig_base = 0x40086000; lpcspifi_info->bank_num = bank->bank_number; /* read and decode flash ID; returns in SW mode */ retval = lpcspifi_read_flash_id(bank, &id); if (retval != ERROR_OK) return retval; retval = lpcspifi_set_hw_mode(bank); if (retval != ERROR_OK) return retval; lpcspifi_info->dev = NULL; for (const struct flash_device *p = flash_devices; p->name ; p++) if (p->device_id == id) { lpcspifi_info->dev = p; break; } if (!lpcspifi_info->dev) { LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id); return ERROR_FAIL; } LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", lpcspifi_info->dev->name, lpcspifi_info->dev->device_id); /* Set correct size value */ bank->size = lpcspifi_info->dev->size_in_bytes; if (bank->size <= (1UL << 16)) LOG_WARNING("device needs 2-byte addresses - not implemented"); if (bank->size > (1UL << 24)) LOG_WARNING("device needs paging or 4-byte addresses - not implemented"); /* if no sectors, treat whole bank as single sector */ sectorsize = lpcspifi_info->dev->sectorsize ? lpcspifi_info->dev->sectorsize : lpcspifi_info->dev->size_in_bytes; /* create and fill sectors array */ bank->num_sectors = lpcspifi_info->dev->size_in_bytes / sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); if (!sectors) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { sectors[sector].offset = sector * sectorsize; sectors[sector].size = sectorsize; sectors[sector].is_erased = -1; sectors[sector].is_protected = 0; } bank->sectors = sectors; lpcspifi_info->probed = true; return ERROR_OK; } static int lpcspifi_auto_probe(struct flash_bank *bank) { struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; if (lpcspifi_info->probed) return ERROR_OK; return lpcspifi_probe(bank); } static int lpcspifi_protect_check(struct flash_bank *bank) { /* Nothing to do. Protection is only handled in SW. */ return ERROR_OK; } static int get_lpcspifi_info(struct flash_bank *bank, struct command_invocation *cmd) { struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; if (!(lpcspifi_info->probed)) { command_print_sameline(cmd, "\nSPIFI flash bank not probed yet\n"); return ERROR_OK; } command_print_sameline(cmd, "\nSPIFI flash information:\n" " Device \'%s\' (ID 0x%08" PRIx32 ")\n", lpcspifi_info->dev->name, lpcspifi_info->dev->device_id); return ERROR_OK; } const struct flash_driver lpcspifi_flash = { .name = "lpcspifi", .flash_bank_command = lpcspifi_flash_bank_command, .erase = lpcspifi_erase, .protect = lpcspifi_protect, .write = lpcspifi_write, .read = default_flash_read, .probe = lpcspifi_probe, .auto_probe = lpcspifi_auto_probe, .erase_check = default_flash_blank_check, .protect_check = lpcspifi_protect_check, .info = get_lpcspifi_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/max32xxx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2016 by Maxim Integrated * * Kevin Gillespie <kevin.gillespie@maximintegrated.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> /* Register Addresses */ #define FLSH_ADDR 0x000 #define FLSH_CLKDIV 0x004 #define FLSH_CN 0x008 #define PR1E_ADDR 0x00C #define PR2S_ADDR 0x010 #define PR2E_ADDR 0x014 #define PR3S_ADDR 0x018 #define PR3E_ADDR 0x01C #define FLSH_MD 0x020 #define FLSH_INT 0x024 #define FLSH_DATA0 0x030 #define FLSH_DATA1 0x034 #define FLSH_DATA2 0x038 #define FLSH_DATA3 0x03C #define FLSH_BL_CTRL 0x170 #define FLSH_PROT 0x300 #define ARM_PID_REG 0xE00FFFE0 #define MAX326XX_ID_REG 0x40000838 /* Register settings */ #define FLSH_INT_AF 0x00000002 #define FLSH_CN_UNLOCK_MASK 0xF0000000 #define FLSH_CN_UNLOCK_VALUE 0x20000000 #define FLSH_CN_PEND 0x01000000 #define FLSH_CN_ERASE_CODE_MASK 0x0000FF00 #define FLSH_CN_ERASE_CODE_PGE 0x00005500 #define FLSH_CN_ERASE_CODE_ME 0x0000AA00 #define FLSH_CN_PGE 0x00000004 #define FLSH_CN_ME 0x00000002 #define FLSH_CN_WR 0x00000001 #define FLASH_BL_CTRL_23 0x00020000 #define FLASH_BL_CTRL_IFREN 0x00000001 #define ARM_PID_DEFAULT_CM3 0xB4C3 #define ARM_PID_DEFAULT_CM4 0xB4C4 #define MAX326XX_ID 0x4D static int max32xxx_mass_erase(struct flash_bank *bank); struct max32xxx_flash_bank { bool probed; int max326xx; unsigned int flash_size; unsigned int flc_base; unsigned int sector_size; unsigned int clkdiv_value; uint32_t int_state; unsigned int burst_size_bits; }; /* see contrib/loaders/flash/max32xxx/max32xxx.s for src */ static const uint8_t write_code[] = { #include "../../../contrib/loaders/flash/max32xxx/max32xxx.inc" }; /* Config Command: flash bank name driver base size chip_width bus_width target [driver_option] flash bank max32xxx <base> <size> 0 0 <target> <FLC base> <sector size> <clkdiv> [burst_bits] */ FLASH_BANK_COMMAND_HANDLER(max32xxx_flash_bank_command) { struct max32xxx_flash_bank *info; if (CMD_ARGC < 9) { LOG_WARNING("incomplete flash bank max32xxx configuration: <base> <size> 0 0 <target> <FLC base> <sector size> <clkdiv> [burst_bits]"); return ERROR_FLASH_BANK_INVALID; } info = calloc(sizeof(struct max32xxx_flash_bank), 1); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], info->flash_size); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[6], info->flc_base); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[7], info->sector_size); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[8], info->clkdiv_value); if (CMD_ARGC > 9) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[9], info->burst_size_bits); else info->burst_size_bits = 32; info->int_state = 0; bank->driver_priv = info; return ERROR_OK; } static int get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct max32xxx_flash_bank *info = bank->driver_priv; if (!info->probed) return ERROR_FLASH_BANK_NOT_PROBED; command_print_sameline(cmd, "\nMaxim Integrated max32xxx flash driver\n"); return ERROR_OK; } /*************************************************************************** * flash operations ***************************************************************************/ static int max32xxx_flash_op_pre(struct flash_bank *bank) { struct target *target = bank->target; struct max32xxx_flash_bank *info = bank->driver_priv; uint32_t flsh_cn; uint32_t bootloader; /* Check if the flash controller is busy */ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); if (flsh_cn & (FLSH_CN_PEND | FLSH_CN_ERASE_CODE_MASK | FLSH_CN_PGE | FLSH_CN_ME | FLSH_CN_WR)) return ERROR_FLASH_BUSY; /* Refresh flash controller timing */ target_write_u32(target, info->flc_base + FLSH_CLKDIV, info->clkdiv_value); /* Clear and disable flash programming interrupts */ target_read_u32(target, info->flc_base + FLSH_INT, &info->int_state); target_write_u32(target, info->flc_base + FLSH_INT, 0x00000000); /* Clear the lower bit in the bootloader configuration register in case flash page 0 has been replaced */ if (target_read_u32(target, info->flc_base + FLSH_BL_CTRL, &bootloader) != ERROR_OK) { LOG_ERROR("Read failure on FLSH_BL_CTRL"); return ERROR_FAIL; } if (bootloader & FLASH_BL_CTRL_23) { LOG_WARNING("FLSH_BL_CTRL indicates BL mode 2 or mode 3."); if (bootloader & FLASH_BL_CTRL_IFREN) { LOG_WARNING("Flash page 0 swapped out, attempting to swap back in for programming"); bootloader &= ~(FLASH_BL_CTRL_IFREN); if (target_write_u32(target, info->flc_base + FLSH_BL_CTRL, bootloader) != ERROR_OK) { LOG_ERROR("Write failure on FLSH_BL_CTRL"); return ERROR_FAIL; } if (target_read_u32(target, info->flc_base + FLSH_BL_CTRL, &bootloader) != ERROR_OK) { LOG_ERROR("Read failure on FLSH_BL_CTRL"); return ERROR_FAIL; } if (bootloader & FLASH_BL_CTRL_IFREN) { /* Bummer */ LOG_ERROR("Unable to swap flash page 0 back in. Writes to page 0 will fail."); } } } /* Unlock flash */ flsh_cn &= ~FLSH_CN_UNLOCK_MASK; flsh_cn |= FLSH_CN_UNLOCK_VALUE; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); /* Confirm flash is unlocked */ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); if ((flsh_cn & FLSH_CN_UNLOCK_VALUE) != FLSH_CN_UNLOCK_VALUE) return ERROR_FAIL; return ERROR_OK; } static int max32xxx_flash_op_post(struct flash_bank *bank) { struct target *target = bank->target; struct max32xxx_flash_bank *info = bank->driver_priv; uint32_t flsh_cn; /* Restore flash programming interrupts */ target_write_u32(target, info->flc_base + FLSH_INT, info->int_state); /* Lock flash */ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); flsh_cn &= ~FLSH_CN_UNLOCK_MASK; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); return ERROR_OK; } static int max32xxx_protect_check(struct flash_bank *bank) { struct max32xxx_flash_bank *info = bank->driver_priv; struct target *target = bank->target; uint32_t temp_reg; if (!info->probed) return ERROR_FLASH_BANK_NOT_PROBED; if (!info->max326xx) { for (unsigned i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = -1; return ERROR_FLASH_OPER_UNSUPPORTED; } /* Check the protection */ for (unsigned i = 0; i < bank->num_sectors; i++) { if (i%32 == 0) target_read_u32(target, info->flc_base + FLSH_PROT + ((i/32)*4), &temp_reg); if (temp_reg & (0x1 << i%32)) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; } return ERROR_OK; } static int max32xxx_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { uint32_t flsh_cn, flsh_int; struct max32xxx_flash_bank *info = bank->driver_priv; struct target *target = bank->target; int retval; int retry; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!info->probed) return ERROR_FLASH_BANK_NOT_PROBED; if ((last < first) || (last >= bank->num_sectors)) return ERROR_FLASH_SECTOR_INVALID; if ((first == 0) && (last == (bank->num_sectors - 1))) return max32xxx_mass_erase(bank); /* Prepare to issue flash operation */ retval = max32xxx_flash_op_pre(bank); if (retval != ERROR_OK) return retval; int erased = 0; for (unsigned int banknr = first; banknr <= last; banknr++) { /* Check the protection */ if (bank->sectors[banknr].is_protected == 1) { LOG_WARNING("Flash sector %u is protected", banknr); continue; } else erased = 1; /* Address is first word in page */ target_write_u32(target, info->flc_base + FLSH_ADDR, banknr * info->sector_size); /* Write page erase code */ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); flsh_cn |= FLSH_CN_ERASE_CODE_PGE; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); /* Issue page erase command */ flsh_cn |= 0x4; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); /* Wait until erase complete */ retry = 1000; do { target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); if (retry <= 0) { LOG_ERROR("Timed out waiting for flash page erase @ 0x%08x", banknr * info->sector_size); return ERROR_FLASH_OPERATION_FAILED; } /* Check access violations */ target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int); if (flsh_int & FLSH_INT_AF) { LOG_ERROR("Error erasing flash page %i", banknr); target_write_u32(target, info->flc_base + FLSH_INT, 0); max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; } } if (!erased) { LOG_ERROR("All pages protected %u to %u", first, last); max32xxx_flash_op_post(bank); return ERROR_FAIL; } if (max32xxx_flash_op_post(bank) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int max32xxx_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct max32xxx_flash_bank *info = bank->driver_priv; struct target *target = bank->target; uint32_t temp_reg; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!info->probed) return ERROR_FLASH_BANK_NOT_PROBED; if (!info->max326xx) return ERROR_FLASH_OPER_UNSUPPORTED; if ((last < first) || (last >= bank->num_sectors)) return ERROR_FLASH_SECTOR_INVALID; /* Setup the protection on the pages given */ for (unsigned int page = first; page <= last; page++) { if (set) { /* Set the write/erase bit for this page */ target_read_u32(target, info->flc_base + FLSH_PROT + (page/32), &temp_reg); temp_reg |= (0x1 << page%32); target_write_u32(target, info->flc_base + FLSH_PROT + (page/32), temp_reg); bank->sectors[page].is_protected = 1; } else { /* Clear the write/erase bit for this page */ target_read_u32(target, info->flc_base + FLSH_PROT + (page/32), &temp_reg); temp_reg &= ~(0x1 << page%32); target_write_u32(target, info->flc_base + FLSH_PROT + (page/32), temp_reg); bank->sectors[page].is_protected = 0; } } return ERROR_OK; } static int max32xxx_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t wcount) { struct max32xxx_flash_bank *info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *source; struct working_area *write_algorithm; uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* power of two, and multiple of word size */ static const unsigned buf_min = 128; /* for small buffers it's faster not to download an algorithm */ if (wcount * 4 < buf_min) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "", bank, buffer, offset, wcount); /* flash write code */ if (target_alloc_working_area(target, sizeof(write_code), &write_algorithm) != ERROR_OK) { LOG_DEBUG("no working area for block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* plus a buffer big enough for this data */ if (wcount * 4 < buffer_size) buffer_size = wcount * 4; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= buf_min) { target_free_working_area(target, write_algorithm); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } LOG_DEBUG("retry target_alloc_working_area(%s, size=%u)", target_name(target), (unsigned) buffer_size); } target_write_buffer(target, write_algorithm->address, sizeof(write_code), write_code); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[3].value, 0, 32, wcount); buf_set_u32(reg_params[4].value, 0, 32, info->flc_base); retval = target_run_flash_async_algorithm(target, buffer, wcount, 4, 0, NULL, 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) LOG_ERROR("error %d executing max32xxx flash write algorithm", retval); target_free_working_area(target, write_algorithm); target_free_working_area(target, source); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; } static int max32xxx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct max32xxx_flash_bank *info = bank->driver_priv; struct target *target = bank->target; uint32_t flsh_cn, flsh_int; uint32_t address = offset; uint32_t remaining = count; uint32_t words_remaining; int retval; int retry; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_DEBUG("bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32 "", bank, buffer, offset, count); if (!info->probed) return ERROR_FLASH_BANK_NOT_PROBED; if (offset & 0x3) { LOG_WARNING("offset size must be word aligned"); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; /* Prepare to issue flash operation */ retval = max32xxx_flash_op_pre(bank); if (retval != ERROR_OK) return retval; if (remaining >= 4) { /* write in 32-bit units */ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); flsh_cn &= 0xF7FFFFFF; flsh_cn |= 0x00000010; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); /* try using a block write */ words_remaining = remaining / 4; retval = max32xxx_write_block(bank, buffer, offset, words_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) LOG_DEBUG("writing flash word-at-a-time"); else { max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; } } else { /* all 32-bit words have been written */ buffer += words_remaining * 4; address += words_remaining * 4; remaining -= words_remaining * 4; } } if ((remaining >= 4) && ((address & 0x1F) != 0)) { /* write in 32-bit units until we are 128-bit aligned */ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); flsh_cn &= 0xF7FFFFFF; flsh_cn |= 0x00000010; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); while ((remaining >= 4) && ((address & 0x1F) != 0)) { target_write_u32(target, info->flc_base + FLSH_ADDR, address); target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, buffer); flsh_cn |= 0x00000001; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); /* Wait until flash operation is complete */ retry = 10; do { target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); if (retry <= 0) { LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, address); return ERROR_FLASH_OPERATION_FAILED; } buffer += 4; address += 4; remaining -= 4; } } if ((info->burst_size_bits == 128) && (remaining >= 16)) { /* write in 128-bit bursts while we can */ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); flsh_cn &= 0xFFFFFFEF; flsh_cn |= 0x08000000; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); target_write_u32(target, info->flc_base + FLSH_ADDR, address); while (remaining >= 16) { if ((address & 0xFFF) == 0) LOG_DEBUG("Writing @ 0x%08" PRIx32, address); target_write_buffer(target, info->flc_base + FLSH_DATA0, 16, buffer); flsh_cn |= 0x00000001; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); /* Wait until flash operation is complete */ retry = 10; do { target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); if (retry <= 0) { LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, address); return ERROR_FLASH_OPERATION_FAILED; } buffer += 16; address += 16; remaining -= 16; } } if (remaining >= 4) { /* write in 32-bit units while we can */ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); flsh_cn &= 0xF7FFFFFF; flsh_cn |= 0x00000010; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); while (remaining >= 4) { target_write_u32(target, info->flc_base + FLSH_ADDR, address); target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, buffer); flsh_cn |= 0x00000001; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); /* Wait until flash operation is complete */ retry = 10; do { target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); if (retry <= 0) { LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, address); return ERROR_FLASH_OPERATION_FAILED; } buffer += 4; address += 4; remaining -= 4; } } if (remaining > 0) { /* write remaining bytes in a 32-bit unit */ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); flsh_cn &= 0xF7FFFFFF; flsh_cn |= 0x00000010; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); uint8_t last_word[4] = {0xff, 0xff, 0xff, 0xff}; int i = 0; while (remaining > 0) { last_word[i++] = *buffer; buffer++; remaining--; } target_write_u32(target, info->flc_base + FLSH_ADDR, address); target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, last_word); flsh_cn |= 0x00000001; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); /* Wait until flash operation is complete */ retry = 10; do { target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); if (retry <= 0) { LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, address); return ERROR_FLASH_OPERATION_FAILED; } } /* Check access violations */ target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int); if (flsh_int & FLSH_INT_AF) { LOG_ERROR("Flash Error writing 0x%" PRIx32 " bytes at 0x%08" PRIx32, count, offset); max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; } if (max32xxx_flash_op_post(bank) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int max32xxx_probe(struct flash_bank *bank) { struct max32xxx_flash_bank *info = bank->driver_priv; struct target *target = bank->target; uint32_t arm_id[2]; uint16_t arm_pid; free(bank->sectors); /* provide this for the benefit of the NOR flash framework */ bank->size = info->flash_size; bank->num_sectors = info->flash_size / info->sector_size; bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = i * info->sector_size; bank->sectors[i].size = info->sector_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } /* Probe to determine if this part is in the max326xx family */ info->max326xx = 0; target_read_u32(target, ARM_PID_REG, &arm_id[0]); target_read_u32(target, ARM_PID_REG+4, &arm_id[1]); arm_pid = (arm_id[1] << 8) + arm_id[0]; LOG_DEBUG("arm_pid = 0x%x", arm_pid); if ((arm_pid == ARM_PID_DEFAULT_CM3) || arm_pid == ARM_PID_DEFAULT_CM4) { uint32_t max326xx_id; target_read_u32(target, MAX326XX_ID_REG, &max326xx_id); LOG_DEBUG("max326xx_id = 0x%" PRIx32, max326xx_id); max326xx_id = ((max326xx_id & 0xFF000000) >> 24); if (max326xx_id == MAX326XX_ID) info->max326xx = 1; } LOG_DEBUG("info->max326xx = %d", info->max326xx); /* Initialize the protection bits for each flash page */ if (max32xxx_protect_check(bank) == ERROR_FLASH_OPER_UNSUPPORTED) LOG_WARNING("Flash protection not supported on this device"); info->probed = true; return ERROR_OK; } static int max32xxx_mass_erase(struct flash_bank *bank) { struct target *target = NULL; struct max32xxx_flash_bank *info = NULL; uint32_t flsh_cn, flsh_int; int retval; int retry; info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!info->probed) return ERROR_FLASH_BANK_NOT_PROBED; int not_protected = 0; for (unsigned int i = 0; i < bank->num_sectors; i++) { if (bank->sectors[i].is_protected == 1) LOG_WARNING("Flash sector %u is protected", i); else not_protected = 1; } if (!not_protected) { LOG_ERROR("All pages protected"); return ERROR_FAIL; } /* Prepare to issue flash operation */ retval = max32xxx_flash_op_pre(bank); if (retval != ERROR_OK) return retval; /* Write mass erase code */ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); flsh_cn |= FLSH_CN_ERASE_CODE_ME; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); /* Issue mass erase command */ flsh_cn |= 0x2; target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); /* Wait until erase complete */ retry = 1000; do { target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); if (retry <= 0) { LOG_ERROR("Timed out waiting for flash mass erase"); return ERROR_FLASH_OPERATION_FAILED; } /* Check access violations */ target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int); if (flsh_int & FLSH_INT_AF) { LOG_ERROR("Error mass erasing"); target_write_u32(target, info->flc_base + FLSH_INT, 0); return ERROR_FLASH_OPERATION_FAILED; } if (max32xxx_flash_op_post(bank) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } COMMAND_HANDLER(max32xxx_handle_mass_erase_command) { struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (CMD_ARGC < 1) { command_print(CMD, "max32xxx mass_erase <bank>"); return ERROR_OK; } if (retval != ERROR_OK) return retval; if (max32xxx_mass_erase(bank) == ERROR_OK) command_print(CMD, "max32xxx mass erase complete"); else command_print(CMD, "max32xxx mass erase failed"); return ERROR_OK; } COMMAND_HANDLER(max32xxx_handle_protection_set_command) { struct flash_bank *bank; int retval; struct max32xxx_flash_bank *info; uint32_t addr, len; if (CMD_ARGC != 3) { command_print(CMD, "max32xxx protection_set <bank> <addr> <size>"); return ERROR_OK; } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; info = bank->driver_priv; /* Convert the range to the page numbers */ if (sscanf(CMD_ARGV[1], "0x%"SCNx32, &addr) != 1) { LOG_WARNING("Error parsing address"); command_print(CMD, "max32xxx protection_set <bank> <addr> <size>"); return ERROR_FAIL; } /* Mask off the top portion on the address */ addr = (addr & 0x0FFFFFFF); if (sscanf(CMD_ARGV[2], "0x%"SCNx32, &len) != 1) { LOG_WARNING("Error parsing length"); command_print(CMD, "max32xxx protection_set <bank> <addr> <size>"); return ERROR_FAIL; } /* Check the address is in the range of the flash */ if ((addr+len) >= info->flash_size) return ERROR_FLASH_SECTOR_INVALID; if (len == 0) return ERROR_OK; /* Convert the address and length to the page boundaries */ addr = addr - (addr % info->sector_size); if (len % info->sector_size) len = len + info->sector_size - (len % info->sector_size); /* Convert the address and length to page numbers */ addr = (addr / info->sector_size); len = addr + (len / info->sector_size) - 1; if (max32xxx_protect(bank, 1, addr, len) == ERROR_OK) command_print(CMD, "max32xxx protection set complete"); else command_print(CMD, "max32xxx protection set failed"); return ERROR_OK; } COMMAND_HANDLER(max32xxx_handle_protection_clr_command) { struct flash_bank *bank; int retval; struct max32xxx_flash_bank *info; uint32_t addr, len; if (CMD_ARGC != 3) { command_print(CMD, "max32xxx protection_clr <bank> <addr> <size>"); return ERROR_OK; } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; info = bank->driver_priv; /* Convert the range to the page numbers */ if (sscanf(CMD_ARGV[1], "0x%"SCNx32, &addr) != 1) { LOG_WARNING("Error parsing address"); command_print(CMD, "max32xxx protection_clr <bank> <addr> <size>"); return ERROR_FAIL; } /* Mask off the top portion on the address */ addr = (addr & 0x0FFFFFFF); if (sscanf(CMD_ARGV[2], "0x%"SCNx32, &len) != 1) { LOG_WARNING("Error parsing length"); command_print(CMD, "max32xxx protection_clr <bank> <addr> <size>"); return ERROR_FAIL; } /* Check the address is in the range of the flash */ if ((addr+len) >= info->flash_size) return ERROR_FLASH_SECTOR_INVALID; if (len == 0) return ERROR_OK; /* Convert the address and length to the page boundaries */ addr = addr - (addr % info->sector_size); if (len % info->sector_size) len = len + info->sector_size - (len % info->sector_size); /* Convert the address and length to page numbers */ addr = (addr / info->sector_size); len = addr + (len / info->sector_size) - 1; if (max32xxx_protect(bank, 0, addr, len) == ERROR_OK) command_print(CMD, "max32xxx protection clear complete"); else command_print(CMD, "max32xxx protection clear failed"); return ERROR_OK; } COMMAND_HANDLER(max32xxx_handle_protection_check_command) { struct flash_bank *bank; int retval; struct max32xxx_flash_bank *info; if (CMD_ARGC < 1) { command_print(CMD, "max32xxx protection_check <bank>"); return ERROR_OK; } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; info = bank->driver_priv; /* Update the protection array */ retval = max32xxx_protect_check(bank); if (retval != ERROR_OK) { LOG_WARNING("Error updating the protection array"); return retval; } LOG_WARNING("s:<sector number> a:<address> p:<protection bit>"); for (unsigned i = 0; i < bank->num_sectors; i += 4) { LOG_WARNING("s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d", (i+0), (i+0)*info->sector_size, bank->sectors[(i+0)].is_protected, (i+1), (i+1)*info->sector_size, bank->sectors[(i+1)].is_protected, (i+2), (i+2)*info->sector_size, bank->sectors[(i+2)].is_protected, (i+3), (i+3)*info->sector_size, bank->sectors[(i+3)].is_protected); } return ERROR_OK; } static const struct command_registration max32xxx_exec_command_handlers[] = { { .name = "mass_erase", .handler = max32xxx_handle_mass_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "mass erase flash", }, { .name = "protection_set", .handler = max32xxx_handle_protection_set_command, .mode = COMMAND_EXEC, .usage = "bank_id addr size", .help = "set flash protection for address range", }, { .name = "protection_clr", .handler = max32xxx_handle_protection_clr_command, .mode = COMMAND_EXEC, .usage = "bank_id addr size", .help = "clear flash protection for address range", }, { .name = "protection_check", .handler = max32xxx_handle_protection_check_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "check flash protection", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration max32xxx_command_handlers[] = { { .name = "max32xxx", .mode = COMMAND_EXEC, .help = "max32xxx flash command group", .chain = max32xxx_exec_command_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; const struct flash_driver max32xxx_flash = { .name = "max32xxx", .commands = max32xxx_command_handlers, .flash_bank_command = max32xxx_flash_bank_command, .erase = max32xxx_erase, .protect = max32xxx_protect, .write = max32xxx_write, .read = default_flash_read, .probe = max32xxx_probe, .auto_probe = max32xxx_probe, .erase_check = default_flash_blank_check, .protect_check = max32xxx_protect_check, .info = get_info, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/mdr.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * * * * Copyright (C) 2013 by Paul Fertser * * fercerpav@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> #define MD_RST_CLK 0x40020000 #define MD_PER_CLOCK (MD_RST_CLK + 0x1C) #define MD_PER_CLOCK_EEPROM (1 << 3) #define MD_PER_CLOCK_RST_CLK (1 << 4) #define FLASH_REG_BASE 0x40018000 #define FLASH_CMD (FLASH_REG_BASE + 0x00) #define FLASH_ADR (FLASH_REG_BASE + 0x04) #define FLASH_DI (FLASH_REG_BASE + 0x08) #define FLASH_DO (FLASH_REG_BASE + 0x0C) #define FLASH_KEY (FLASH_REG_BASE + 0x10) #define FLASH_NVSTR (1 << 13) #define FLASH_PROG (1 << 12) #define FLASH_MAS1 (1 << 11) #define FLASH_ERASE (1 << 10) #define FLASH_IFREN (1 << 9) #define FLASH_SE (1 << 8) #define FLASH_YE (1 << 7) #define FLASH_XE (1 << 6) #define FLASH_RD (1 << 2) #define FLASH_WR (1 << 1) #define FLASH_CON (1 << 0) #define FLASH_DELAY_MASK (7 << 3) #define KEY 0x8AAA5551 struct mdr_flash_bank { bool probed; unsigned int mem_type; unsigned int page_count; unsigned int sec_count; }; /* flash bank <name> mdr <base> <size> 0 0 <target#> <type> <page_count> <sec_count> */ FLASH_BANK_COMMAND_HANDLER(mdr_flash_bank_command) { struct mdr_flash_bank *mdr_info; if (CMD_ARGC < 9) return ERROR_COMMAND_SYNTAX_ERROR; mdr_info = malloc(sizeof(struct mdr_flash_bank)); bank->driver_priv = mdr_info; mdr_info->probed = false; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[6], mdr_info->mem_type); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[7], mdr_info->page_count); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[8], mdr_info->sec_count); return ERROR_OK; } static int mdr_mass_erase(struct flash_bank *bank) { struct target *target = bank->target; struct mdr_flash_bank *mdr_info = bank->driver_priv; uint32_t flash_cmd; int retval; unsigned int i; retval = target_read_u32(target, FLASH_CMD, &flash_cmd); if (retval != ERROR_OK) return retval; for (i = 0; i < mdr_info->sec_count; i++) { retval = target_write_u32(target, FLASH_ADR, i << 2); if (retval != ERROR_OK) return retval; flash_cmd |= FLASH_XE | FLASH_MAS1 | FLASH_ERASE; retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) return retval; flash_cmd |= FLASH_NVSTR; retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) return retval; flash_cmd &= ~FLASH_ERASE; retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) return retval; flash_cmd &= ~(FLASH_XE | FLASH_MAS1 | FLASH_NVSTR); retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) return retval; } return retval; } static int mdr_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct mdr_flash_bank *mdr_info = bank->driver_priv; int retval, retval2; unsigned int j; uint32_t flash_cmd, cur_per_clock; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = target_read_u32(target, MD_PER_CLOCK, &cur_per_clock); if (retval != ERROR_OK) return retval; if (!(cur_per_clock & 0x10)) { LOG_ERROR("Target needs reset before flash operations"); return ERROR_FLASH_OPERATION_FAILED; } retval = target_write_u32(target, MD_PER_CLOCK, cur_per_clock | MD_PER_CLOCK_EEPROM); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, FLASH_KEY, KEY); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, FLASH_CMD, &flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; /* Switch on register access */ flash_cmd = (flash_cmd & FLASH_DELAY_MASK) | FLASH_CON; if (mdr_info->mem_type) flash_cmd |= FLASH_IFREN; retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; if ((first == 0) && (last == (bank->num_sectors - 1)) && !mdr_info->mem_type) { retval = mdr_mass_erase(bank); goto reset_pg_and_lock; } unsigned int page_size = bank->size / mdr_info->page_count; for (unsigned int i = first; i <= last; i++) { for (j = 0; j < mdr_info->sec_count; j++) { retval = target_write_u32(target, FLASH_ADR, (i * page_size) | (j << 2)); if (retval != ERROR_OK) goto reset_pg_and_lock; flash_cmd |= FLASH_XE | FLASH_ERASE; retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; flash_cmd |= FLASH_NVSTR; retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; flash_cmd &= ~FLASH_ERASE; retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; flash_cmd &= ~(FLASH_XE | FLASH_NVSTR); retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; } } reset_pg_and_lock: flash_cmd &= FLASH_DELAY_MASK; retval2 = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval == ERROR_OK) retval = retval2; retval2 = target_write_u32(target, FLASH_KEY, 0); if (retval == ERROR_OK) retval = retval2; return retval; } static int mdr_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* see contrib/loaders/flash/mdr32fx.S for src */ static const uint8_t mdr32fx_flash_write_code[] = { 0x07, 0x68, 0x16, 0x68, 0x00, 0x2e, 0x2e, 0xd0, 0x55, 0x68, 0xb5, 0x42, 0xf9, 0xd0, 0x2e, 0x68, 0x44, 0x60, 0x86, 0x60, 0x17, 0x4e, 0x37, 0x43, 0x07, 0x60, 0x05, 0x26, 0x00, 0xf0, 0x25, 0xf8, 0x15, 0x4e, 0x37, 0x43, 0x07, 0x60, 0x0d, 0x26, 0x00, 0xf0, 0x1f, 0xf8, 0x80, 0x26, 0x37, 0x43, 0x07, 0x60, 0x3d, 0x26, 0x00, 0xf0, 0x19, 0xf8, 0x80, 0x26, 0xb7, 0x43, 0x07, 0x60, 0x0f, 0x4e, 0xb7, 0x43, 0x07, 0x60, 0x05, 0x26, 0x00, 0xf0, 0x10, 0xf8, 0x0d, 0x4e, 0xb7, 0x43, 0x07, 0x60, 0x04, 0x35, 0x04, 0x34, 0x9d, 0x42, 0x01, 0xd3, 0x15, 0x46, 0x08, 0x35, 0x55, 0x60, 0x01, 0x39, 0x00, 0x29, 0x00, 0xd0, 0xcd, 0xe7, 0x30, 0x46, 0x00, 0xbe, 0x01, 0x3e, 0x00, 0x2e, 0xfc, 0xd1, 0x70, 0x47, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x40, 0x20, 0x00, 0x00 }; /* flash write code */ if (target_alloc_working_area(target, sizeof(mdr32fx_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(mdr32fx_flash_write_code), mdr32fx_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */ if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (32bit) */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ buf_set_u32(reg_params[0].value, 0, 32, FLASH_REG_BASE); buf_set_u32(reg_params[1].value, 0, 32, count); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[4].value, 0, 32, address); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; retval = target_run_flash_async_algorithm(target, buffer, count, 4, 0, NULL, 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) LOG_ERROR("flash write failed at address 0x%"PRIx32, buf_get_u32(reg_params[4].value, 0, 32)); target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; } static int mdr_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct mdr_flash_bank *mdr_info = bank->driver_priv; uint8_t *new_buffer = NULL; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x3) { LOG_ERROR("offset 0x%" PRIx32 " breaks required 4-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* If there's an odd number of bytes, the data has to be padded. Duplicate * the buffer and use the normal code path with a single block write since * it's probably cheaper than to special case the last odd write using * discrete accesses. */ int rem = count % 4; if (rem) { new_buffer = malloc(count + rem); if (!new_buffer) { LOG_ERROR("odd number of bytes to write and no memory for padding buffer"); return ERROR_FAIL; } LOG_INFO("odd number of bytes to write, padding with 0xff"); buffer = memcpy(new_buffer, buffer, count); while (rem--) new_buffer[count++] = 0xff; } uint32_t flash_cmd, cur_per_clock; int retval, retval2; retval = target_read_u32(target, MD_PER_CLOCK, &cur_per_clock); if (retval != ERROR_OK) goto free_buffer; if (!(cur_per_clock & MD_PER_CLOCK_RST_CLK)) { /* Something's very wrong if the RST_CLK module is not clocked */ LOG_ERROR("Target needs reset before flash operations"); retval = ERROR_FLASH_OPERATION_FAILED; goto free_buffer; } retval = target_write_u32(target, MD_PER_CLOCK, cur_per_clock | MD_PER_CLOCK_EEPROM); if (retval != ERROR_OK) goto free_buffer; retval = target_write_u32(target, FLASH_KEY, KEY); if (retval != ERROR_OK) goto free_buffer; retval = target_read_u32(target, FLASH_CMD, &flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; /* Switch on register access */ flash_cmd = (flash_cmd & FLASH_DELAY_MASK) | FLASH_CON; if (mdr_info->mem_type) flash_cmd |= FLASH_IFREN; retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; /* try using block write */ retval = mdr_write_block(bank, buffer, offset, count/4); if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single halfword accesses */ LOG_WARNING("Can't use block writes, falling back to single memory accesses"); unsigned int page_size = bank->size / mdr_info->page_count; unsigned int page_mask = page_size - 1; while (count > 0) { unsigned int i, j; unsigned int cur_page = offset & ~page_mask; unsigned int bytes_to_write = cur_page + page_size - offset; if (count < bytes_to_write) bytes_to_write = count; /*LOG_INFO("Selecting next page: %08x", cur_page);*/ for (i = 0; i < mdr_info->sec_count; i++) { retval = target_write_u32(target, FLASH_ADR, offset + i*4); if (retval != ERROR_OK) goto reset_pg_and_lock; /*LOG_INFO("Selecting page/sector: %08x", offset + i*4);*/ flash_cmd |= FLASH_XE | FLASH_PROG; retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; flash_cmd |= FLASH_NVSTR; retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; for (j = 0; (((offset + j + i*4) & ~page_mask) == cur_page) && (j + i*4 < count); j += mdr_info->sec_count*4) { uint32_t value; memcpy(&value, buffer + j + i*4, sizeof(uint32_t)); retval = target_write_u32(target, FLASH_DI, value); if (retval != ERROR_OK) goto reset_pg_and_lock; /*LOG_INFO("Writing to addr %08x", offset + j + i*4);*/ retval = target_write_u32(target, FLASH_ADR, offset + j + i*4); if (retval != ERROR_OK) goto reset_pg_and_lock; flash_cmd |= FLASH_YE; retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; flash_cmd &= ~FLASH_YE; retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; } flash_cmd &= ~FLASH_NVSTR; retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; flash_cmd &= ~(FLASH_XE | FLASH_PROG); retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; } buffer += bytes_to_write; offset += bytes_to_write; count -= bytes_to_write; } } reset_pg_and_lock: flash_cmd &= FLASH_DELAY_MASK; retval2 = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval == ERROR_OK) retval = retval2; retval2 = target_write_u32(target, FLASH_KEY, 0); if (retval == ERROR_OK) retval = retval2; free_buffer: free(new_buffer); /* read some bytes bytes to flush buffer in flash accelerator. * See errata for 1986VE1T and 1986VE3. Error 0007 */ if ((retval == ERROR_OK) && (!mdr_info->mem_type)) { uint32_t tmp; target_checksum_memory(bank->target, bank->base, 64, &tmp); } return retval; } static int mdr_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct mdr_flash_bank *mdr_info = bank->driver_priv; int retval, retval2; if (!mdr_info->mem_type) return default_flash_read(bank, buffer, offset, count); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x3) { LOG_ERROR("offset 0x%" PRIx32 " breaks required 4-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } if (count & 0x3) { LOG_ERROR("count 0x%" PRIx32 " breaks required 4-byte alignment", count); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } uint32_t flash_cmd, cur_per_clock; retval = target_read_u32(target, MD_PER_CLOCK, &cur_per_clock); if (retval != ERROR_OK) goto err; if (!(cur_per_clock & MD_PER_CLOCK_RST_CLK)) { /* Something's very wrong if the RST_CLK module is not clocked */ LOG_ERROR("Target needs reset before flash operations"); retval = ERROR_FLASH_OPERATION_FAILED; goto err; } retval = target_write_u32(target, MD_PER_CLOCK, cur_per_clock | MD_PER_CLOCK_EEPROM); if (retval != ERROR_OK) goto err; retval = target_write_u32(target, FLASH_KEY, KEY); if (retval != ERROR_OK) goto err; retval = target_read_u32(target, FLASH_CMD, &flash_cmd); if (retval != ERROR_OK) goto err_lock; /* Switch on register access */ flash_cmd = (flash_cmd & FLASH_DELAY_MASK) | FLASH_CON | FLASH_IFREN; retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; for (uint32_t i = 0; i < count; i += 4) { retval = target_write_u32(target, FLASH_ADR, offset + i); if (retval != ERROR_OK) goto reset_pg_and_lock; retval = target_write_u32(target, FLASH_CMD, flash_cmd | FLASH_XE | FLASH_YE | FLASH_SE); if (retval != ERROR_OK) goto reset_pg_and_lock; uint32_t buf; retval = target_read_u32(target, FLASH_DO, &buf); if (retval != ERROR_OK) goto reset_pg_and_lock; buf_set_u32(buffer, i * 8, 32, buf); retval = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval != ERROR_OK) goto reset_pg_and_lock; } reset_pg_and_lock: flash_cmd &= FLASH_DELAY_MASK; retval2 = target_write_u32(target, FLASH_CMD, flash_cmd); if (retval == ERROR_OK) retval = retval2; err_lock: retval2 = target_write_u32(target, FLASH_KEY, 0); if (retval == ERROR_OK) retval = retval2; err: return retval; } static int mdr_probe(struct flash_bank *bank) { struct mdr_flash_bank *mdr_info = bank->driver_priv; unsigned int page_count, page_size, i; page_count = mdr_info->page_count; page_size = bank->size / page_count; free(bank->sectors); bank->num_sectors = page_count; bank->sectors = malloc(sizeof(struct flash_sector) * page_count); for (i = 0; i < page_count; i++) { bank->sectors[i].offset = i * page_size; bank->sectors[i].size = page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } mdr_info->probed = true; return ERROR_OK; } static int mdr_auto_probe(struct flash_bank *bank) { struct mdr_flash_bank *mdr_info = bank->driver_priv; if (mdr_info->probed) return ERROR_OK; return mdr_probe(bank); } static int get_mdr_info(struct flash_bank *bank, struct command_invocation *cmd) { struct mdr_flash_bank *mdr_info = bank->driver_priv; command_print_sameline(cmd, "MDR32Fx - %s", mdr_info->mem_type ? "info memory" : "main memory"); return ERROR_OK; } const struct flash_driver mdr_flash = { .name = "mdr", .usage = "flash bank <name> mdr <base> <size> 0 0 <target#> <type> <page_count> <sec_count>\n" "<type>: 0 for main memory, 1 for info memory", .flash_bank_command = mdr_flash_bank_command, .erase = mdr_erase, .write = mdr_write, .read = mdr_read, .probe = mdr_probe, .auto_probe = mdr_auto_probe, .erase_check = default_flash_blank_check, .info = get_mdr_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/mrvlqspi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2014 by Mahavir Jain <mjain@marvell.com> * ***************************************************************************/ /* * This is QSPI flash controller driver for Marvell's Wireless * Microcontroller platform. * * For more information please refer, * https://origin-www.marvell.com/microcontrollers/wi-fi-microcontroller-platform/ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "spi.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> #define QSPI_R_EN (0x0) #define QSPI_W_EN (0x1) #define QSPI_SS_DISABLE (0x0) #define QSPI_SS_ENABLE (0x1) #define WRITE_DISABLE (0x0) #define WRITE_ENABLE (0x1) #define QSPI_TIMEOUT (1000) #define FIFO_FLUSH_TIMEOUT (1000) #define BLOCK_ERASE_TIMEOUT (1000) #define CHIP_ERASE_TIMEOUT (10000) #define SS_EN (1 << 0) #define XFER_RDY (1 << 1) #define RFIFO_EMPTY (1 << 4) #define WFIFO_EMPTY (1 << 6) #define WFIFO_FULL (1 << 7) #define FIFO_FLUSH (1 << 9) #define RW_EN (1 << 13) #define XFER_STOP (1 << 14) #define XFER_START (1 << 15) #define CONF_MASK (0x7) #define CONF_OFFSET (10) #define INS_WRITE_ENABLE 0x06 #define INS_WRITE_DISABLE 0x04 #define INS_READ_STATUS 0x05 #define INS_PAGE_PROGRAM 0x02 #define CNTL 0x0 /* QSPI_BASE + 0x0 */ #define CONF 0x4 #define DOUT 0x8 #define DIN 0xc #define INSTR 0x10 #define ADDR 0x14 #define RDMODE 0x18 #define HDRCNT 0x1c #define DINCNT 0x20 struct mrvlqspi_flash_bank { bool probed; uint32_t reg_base; uint32_t bank_num; const struct flash_device *dev; }; static inline uint32_t mrvlqspi_get_reg(struct flash_bank *bank, uint32_t reg) { struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv; return reg + mrvlqspi_info->reg_base; } static inline int mrvlqspi_set_din_cnt(struct flash_bank *bank, uint32_t count) { struct target *target = bank->target; return target_write_u32(target, mrvlqspi_get_reg(bank, DINCNT), count); } static inline int mrvlqspi_set_addr(struct flash_bank *bank, uint32_t addr) { struct target *target = bank->target; return target_write_u32(target, mrvlqspi_get_reg(bank, ADDR), addr); } static inline int mrvlqspi_set_instr(struct flash_bank *bank, uint32_t instr) { struct target *target = bank->target; return target_write_u32(target, mrvlqspi_get_reg(bank, INSTR), instr); } static inline int mrvlqspi_set_hdr_cnt(struct flash_bank *bank, uint32_t hdr_cnt) { struct target *target = bank->target; return target_write_u32(target, mrvlqspi_get_reg(bank, HDRCNT), hdr_cnt); } static int mrvlqspi_set_conf(struct flash_bank *bank, uint32_t conf_val) { int retval; uint32_t regval; struct target *target = bank->target; retval = target_read_u32(target, mrvlqspi_get_reg(bank, CONF), ®val); if (retval != ERROR_OK) return retval; regval &= ~(CONF_MASK << CONF_OFFSET); regval |= (conf_val << CONF_OFFSET); return target_write_u32(target, mrvlqspi_get_reg(bank, CONF), regval); } static int mrvlqspi_set_ss_state(struct flash_bank *bank, bool state, int timeout) { int retval; uint32_t regval; struct target *target = bank->target; retval = target_read_u32(target, mrvlqspi_get_reg(bank, CNTL), ®val); if (retval != ERROR_OK) return retval; if (state) regval |= SS_EN; else regval &= ~(SS_EN); retval = target_write_u32(target, mrvlqspi_get_reg(bank, CNTL), regval); if (retval != ERROR_OK) return retval; /* wait for xfer_ready to set */ for (;;) { retval = target_read_u32(target, mrvlqspi_get_reg(bank, CNTL), ®val); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%08" PRIx32, regval); if ((regval & XFER_RDY) == XFER_RDY) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FAIL; } alive_sleep(1); } return ERROR_OK; } static int mrvlqspi_start_transfer(struct flash_bank *bank, bool rw_mode) { int retval; uint32_t regval; struct target *target = bank->target; retval = mrvlqspi_set_ss_state(bank, QSPI_SS_ENABLE, QSPI_TIMEOUT); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, mrvlqspi_get_reg(bank, CONF), ®val); if (retval != ERROR_OK) return retval; if (rw_mode) regval |= RW_EN; else regval &= ~(RW_EN); regval |= XFER_START; retval = target_write_u32(target, mrvlqspi_get_reg(bank, CONF), regval); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int mrvlqspi_stop_transfer(struct flash_bank *bank) { int retval; uint32_t regval; struct target *target = bank->target; int timeout = QSPI_TIMEOUT; /* wait for xfer_ready and wfifo_empty to set */ for (;;) { retval = target_read_u32(target, mrvlqspi_get_reg(bank, CNTL), ®val); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%08" PRIx32, regval); if ((regval & (XFER_RDY | WFIFO_EMPTY)) == (XFER_RDY | WFIFO_EMPTY)) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FAIL; } alive_sleep(1); } retval = target_read_u32(target, mrvlqspi_get_reg(bank, CONF), ®val); if (retval != ERROR_OK) return retval; regval |= XFER_STOP; retval = target_write_u32(target, mrvlqspi_get_reg(bank, CONF), regval); if (retval != ERROR_OK) return retval; /* wait for xfer_start to reset */ for (;;) { retval = target_read_u32(target, mrvlqspi_get_reg(bank, CONF), ®val); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%08" PRIx32, regval); if ((regval & XFER_START) == 0) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FAIL; } alive_sleep(1); } retval = mrvlqspi_set_ss_state(bank, QSPI_SS_DISABLE, QSPI_TIMEOUT); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int mrvlqspi_fifo_flush(struct flash_bank *bank, int timeout) { int retval; uint32_t val; struct target *target = bank->target; retval = target_read_u32(target, mrvlqspi_get_reg(bank, CONF), &val); if (retval != ERROR_OK) return retval; val |= FIFO_FLUSH; retval = target_write_u32(target, mrvlqspi_get_reg(bank, CONF), val); if (retval != ERROR_OK) return retval; /* wait for fifo_flush to clear */ for (;;) { retval = target_read_u32(target, mrvlqspi_get_reg(bank, CONF), &val); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%08" PRIX32, val); if ((val & FIFO_FLUSH) == 0) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FAIL; } alive_sleep(1); } return ERROR_OK; } static int mrvlqspi_read_byte(struct flash_bank *bank, uint8_t *data) { int retval; uint32_t val; struct target *target = bank->target; /* wait for rfifo_empty to reset */ for (;;) { retval = target_read_u32(target, mrvlqspi_get_reg(bank, CNTL), &val); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%08" PRIx32, val); if ((val & RFIFO_EMPTY) == 0) break; usleep(10); } retval = target_read_u32(target, mrvlqspi_get_reg(bank, DIN), &val); if (retval != ERROR_OK) return retval; *data = val & 0xFF; return ERROR_OK; } static int mrvlqspi_flash_busy_status(struct flash_bank *bank, int timeout) { uint8_t val; int retval; /* Flush read/write fifos */ retval = mrvlqspi_fifo_flush(bank, FIFO_FLUSH_TIMEOUT); if (retval != ERROR_OK) return retval; /* Set instruction/addr count value */ retval = mrvlqspi_set_hdr_cnt(bank, 0x1); if (retval != ERROR_OK) return retval; /* Read flash status register in continuous manner */ retval = mrvlqspi_set_din_cnt(bank, 0x0); if (retval != ERROR_OK) return retval; /* Set instruction */ retval = mrvlqspi_set_instr(bank, INS_READ_STATUS); if (retval != ERROR_OK) return retval; /* Set data and addr pin length */ retval = mrvlqspi_set_conf(bank, 0x0); if (retval != ERROR_OK) return retval; /* Enable read mode transfer */ retval = mrvlqspi_start_transfer(bank, QSPI_R_EN); if (retval != ERROR_OK) return retval; for (;;) { retval = mrvlqspi_read_byte(bank, &val); if (retval != ERROR_OK) return retval; if (!(val & 0x1)) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FAIL; } alive_sleep(1); } return mrvlqspi_stop_transfer(bank); } static int mrvlqspi_set_write_status(struct flash_bank *bank, bool mode) { int retval; uint32_t instr; /* Flush read/write fifos */ retval = mrvlqspi_fifo_flush(bank, FIFO_FLUSH_TIMEOUT); if (retval != ERROR_OK) return retval; /* Set instruction/addr count value */ retval = mrvlqspi_set_hdr_cnt(bank, 0x1); if (retval != ERROR_OK) return retval; if (mode) instr = INS_WRITE_ENABLE; else instr = INS_WRITE_DISABLE; /* Set instruction */ retval = mrvlqspi_set_instr(bank, instr); if (retval != ERROR_OK) return retval; retval = mrvlqspi_start_transfer(bank, QSPI_W_EN); if (retval != ERROR_OK) return retval; retval = mrvlqspi_stop_transfer(bank); if (retval != ERROR_OK) return retval; return retval; } static int mrvlqspi_read_id(struct flash_bank *bank, uint32_t *id) { uint8_t id_buf[3] = {0, 0, 0}; int retval, i; LOG_DEBUG("Getting ID"); /* Flush read/write fifos */ retval = mrvlqspi_fifo_flush(bank, FIFO_FLUSH_TIMEOUT); if (retval != ERROR_OK) return retval; /* Set instruction/addr count value */ retval = mrvlqspi_set_hdr_cnt(bank, 0x1); if (retval != ERROR_OK) return retval; /* Set count for number of bytes to read */ retval = mrvlqspi_set_din_cnt(bank, 0x3); if (retval != ERROR_OK) return retval; /* Set instruction */ retval = mrvlqspi_set_instr(bank, SPIFLASH_READ_ID); if (retval != ERROR_OK) return retval; /* Set data and addr pin length */ retval = mrvlqspi_set_conf(bank, 0x0); if (retval != ERROR_OK) return retval; retval = mrvlqspi_start_transfer(bank, QSPI_R_EN); if (retval != ERROR_OK) return retval; for (i = 0; i < 3; i++) { retval = mrvlqspi_read_byte(bank, &id_buf[i]); if (retval != ERROR_OK) return retval; } LOG_DEBUG("ID is 0x%02" PRIx8 " 0x%02" PRIx8 " 0x%02" PRIx8, id_buf[0], id_buf[1], id_buf[2]); retval = mrvlqspi_set_ss_state(bank, QSPI_SS_DISABLE, QSPI_TIMEOUT); if (retval != ERROR_OK) return retval; *id = id_buf[2] << 16 | id_buf[1] << 8 | id_buf[0]; return ERROR_OK; } static int mrvlqspi_block_erase(struct flash_bank *bank, uint32_t offset) { int retval; struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv; /* Set flash write enable */ retval = mrvlqspi_set_write_status(bank, WRITE_ENABLE); if (retval != ERROR_OK) return retval; /* Set instruction/addr count value */ retval = mrvlqspi_set_hdr_cnt(bank, (0x1 | (0x3 << 4))); if (retval != ERROR_OK) return retval; /* Set read offset address */ retval = mrvlqspi_set_addr(bank, offset); if (retval != ERROR_OK) return retval; /* Set instruction */ retval = mrvlqspi_set_instr(bank, mrvlqspi_info->dev->erase_cmd); if (retval != ERROR_OK) return retval; retval = mrvlqspi_start_transfer(bank, QSPI_W_EN); if (retval != ERROR_OK) return retval; retval = mrvlqspi_stop_transfer(bank); if (retval != ERROR_OK) return retval; return mrvlqspi_flash_busy_status(bank, BLOCK_ERASE_TIMEOUT); } static int mrvlqspi_bulk_erase(struct flash_bank *bank) { int retval; struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv; if (mrvlqspi_info->dev->chip_erase_cmd == 0x00) return ERROR_FLASH_OPER_UNSUPPORTED; /* Set flash write enable */ retval = mrvlqspi_set_write_status(bank, WRITE_ENABLE); if (retval != ERROR_OK) return retval; /* Set instruction */ retval = mrvlqspi_set_instr(bank, mrvlqspi_info->dev->chip_erase_cmd); if (retval != ERROR_OK) return retval; retval = mrvlqspi_start_transfer(bank, QSPI_W_EN); if (retval != ERROR_OK) return retval; retval = mrvlqspi_stop_transfer(bank); if (retval != ERROR_OK) return retval; return mrvlqspi_flash_busy_status(bank, CHIP_ERASE_TIMEOUT); } static int mrvlqspi_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv; int retval = ERROR_OK; LOG_DEBUG("erase from sector %u to sector %u", first, last); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((last < first) || (last >= bank->num_sectors)) { LOG_ERROR("Flash sector invalid"); return ERROR_FLASH_SECTOR_INVALID; } if (!(mrvlqspi_info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } for (unsigned int sector = first; sector <= last; sector++) { if (bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FAIL; } } /* If we're erasing the entire chip and the flash supports * it, use a bulk erase instead of going sector-by-sector. */ if (first == 0 && last == (bank->num_sectors - 1) && mrvlqspi_info->dev->chip_erase_cmd != mrvlqspi_info->dev->erase_cmd) { LOG_DEBUG("Chip supports the bulk erase command." " Will use bulk erase instead of sector-by-sector erase."); retval = mrvlqspi_bulk_erase(bank); if (retval == ERROR_OK) { return retval; } else LOG_WARNING("Bulk flash erase failed." " Falling back to sector-by-sector erase."); } if (mrvlqspi_info->dev->erase_cmd == 0x00) return ERROR_FLASH_OPER_UNSUPPORTED; for (unsigned int sector = first; sector <= last; sector++) { retval = mrvlqspi_block_erase(bank, sector * mrvlqspi_info->dev->sectorsize); if (retval != ERROR_OK) return retval; } return retval; } static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv; int retval = ERROR_OK; uint32_t page_size, fifo_size; struct working_area *fifo; struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; struct working_area *write_algorithm; LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > mrvlqspi_info->dev->size_in_bytes) { LOG_WARNING("Writes past end of flash. Extra data discarded."); count = mrvlqspi_info->dev->size_in_bytes - offset; } /* Check sector protection */ for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { /* Start offset in or before this sector? */ /* End offset in or behind this sector? */ if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) && ((offset + count - 1) >= bank->sectors[sector].offset) && bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FAIL; } } /* if no valid page_size, use reasonable default */ page_size = mrvlqspi_info->dev->pagesize ? mrvlqspi_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE; /* See contrib/loaders/flash/mrvlqspi.S for src */ static const uint8_t mrvlqspi_flash_write_code[] = { 0x4f, 0xf0, 0x00, 0x0a, 0xa2, 0x44, 0x92, 0x45, 0x7f, 0xf6, 0xfc, 0xaf, 0x00, 0xf0, 0x6b, 0xf8, 0x5f, 0xf0, 0x01, 0x08, 0xc5, 0xf8, 0x1c, 0x80, 0x5f, 0xf0, 0x06, 0x08, 0xc5, 0xf8, 0x10, 0x80, 0x5f, 0xf0, 0x01, 0x09, 0x00, 0xf0, 0x6b, 0xf8, 0x00, 0xf0, 0x7d, 0xf8, 0x5f, 0xf0, 0x31, 0x08, 0xc5, 0xf8, 0x1c, 0x80, 0x90, 0x46, 0xc5, 0xf8, 0x14, 0x80, 0x5f, 0xf0, 0x02, 0x08, 0xc5, 0xf8, 0x10, 0x80, 0x5f, 0xf0, 0x01, 0x09, 0x00, 0xf0, 0x5a, 0xf8, 0xd0, 0xf8, 0x00, 0x80, 0xb8, 0xf1, 0x00, 0x0f, 0x00, 0xf0, 0x8b, 0x80, 0x47, 0x68, 0x47, 0x45, 0x3f, 0xf4, 0xf6, 0xaf, 0x17, 0xf8, 0x01, 0x9b, 0x00, 0xf0, 0x30, 0xf8, 0x8f, 0x42, 0x28, 0xbf, 0x00, 0xf1, 0x08, 0x07, 0x47, 0x60, 0x01, 0x3b, 0x00, 0x2b, 0x00, 0xf0, 0x05, 0x80, 0x02, 0xf1, 0x01, 0x02, 0x92, 0x45, 0x7f, 0xf4, 0xe4, 0xaf, 0x00, 0xf0, 0x50, 0xf8, 0xa2, 0x44, 0x00, 0xf0, 0x2d, 0xf8, 0x5f, 0xf0, 0x01, 0x08, 0xc5, 0xf8, 0x1c, 0x80, 0x5f, 0xf0, 0x00, 0x08, 0xc5, 0xf8, 0x20, 0x80, 0x5f, 0xf0, 0x05, 0x08, 0xc5, 0xf8, 0x10, 0x80, 0x5f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x29, 0xf8, 0x00, 0xf0, 0x13, 0xf8, 0x09, 0xf0, 0x01, 0x09, 0xb9, 0xf1, 0x00, 0x0f, 0xf8, 0xd1, 0x00, 0xf0, 0x34, 0xf8, 0x00, 0x2b, 0xa4, 0xd1, 0x00, 0xf0, 0x53, 0xb8, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0x08, 0x68, 0xfa, 0xd4, 0xc5, 0xf8, 0x08, 0x90, 0x70, 0x47, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0xc8, 0x68, 0xfa, 0xd4, 0xd5, 0xf8, 0x0c, 0x90, 0x70, 0x47, 0xd5, 0xf8, 0x04, 0x80, 0x48, 0xf4, 0x00, 0x78, 0xc5, 0xf8, 0x04, 0x80, 0xd5, 0xf8, 0x04, 0x80, 0x5f, 0xea, 0x88, 0x58, 0xfa, 0xd4, 0x70, 0x47, 0xd5, 0xf8, 0x00, 0x80, 0x48, 0xf0, 0x01, 0x08, 0xc5, 0xf8, 0x00, 0x80, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0x88, 0x78, 0xfa, 0xd5, 0xd5, 0xf8, 0x04, 0x80, 0x69, 0xf3, 0x4d, 0x38, 0x48, 0xf4, 0x00, 0x48, 0xc5, 0xf8, 0x04, 0x80, 0x70, 0x47, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0x88, 0x78, 0xfa, 0xd5, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0x48, 0x68, 0xfa, 0xd5, 0xd5, 0xf8, 0x04, 0x80, 0x48, 0xf4, 0x80, 0x48, 0xc5, 0xf8, 0x04, 0x80, 0xd5, 0xf8, 0x04, 0x80, 0x5f, 0xea, 0x08, 0x48, 0xfa, 0xd4, 0xd5, 0xf8, 0x00, 0x80, 0x28, 0xf0, 0x01, 0x08, 0xc5, 0xf8, 0x00, 0x80, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0x88, 0x78, 0xfa, 0xd5, 0x70, 0x47, 0x00, 0x20, 0x50, 0x60, 0x30, 0x46, 0x00, 0xbe }; if (target_alloc_working_area(target, sizeof(mrvlqspi_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_ERROR("Insufficient working area. You must configure" " a working area > %zdB in order to write to SPIFI flash.", sizeof(mrvlqspi_flash_write_code)); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(mrvlqspi_flash_write_code), mrvlqspi_flash_write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } /* FIFO allocation */ fifo_size = target_get_working_area_avail(target); if (fifo_size == 0) { /* if we already allocated the writing code but failed to get fifo * space, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_ERROR("Insufficient working area. Please allocate at least" " %zdB of working area to enable flash writes.", sizeof(mrvlqspi_flash_write_code) + 1 ); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } else if (fifo_size < page_size) LOG_WARNING("Working area size is limited; flash writes may be" " slow. Increase working area size to at least %zdB" " to reduce write times.", (size_t)(sizeof(mrvlqspi_flash_write_code) + page_size) ); if (target_alloc_working_area(target, fifo_size, &fifo) != ERROR_OK) { target_free_working_area(target, write_algorithm); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* page size */ init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* qspi base address */ buf_set_u32(reg_params[0].value, 0, 32, fifo->address); buf_set_u32(reg_params[1].value, 0, 32, fifo->address + fifo->size); buf_set_u32(reg_params[2].value, 0, 32, offset); buf_set_u32(reg_params[3].value, 0, 32, count); buf_set_u32(reg_params[4].value, 0, 32, page_size); buf_set_u32(reg_params[5].value, 0, 32, (uint32_t) mrvlqspi_info->reg_base); retval = target_run_flash_async_algorithm(target, buffer, count, 1, 0, NULL, 6, reg_params, fifo->address, fifo->size, write_algorithm->address, 0, &armv7m_info ); if (retval != ERROR_OK) LOG_ERROR("Error executing flash write algorithm"); target_free_working_area(target, fifo); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); return retval; } static int mrvlqspi_flash_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv; int retval; uint32_t i; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!(mrvlqspi_info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } /* Flush read/write fifos */ retval = mrvlqspi_fifo_flush(bank, FIFO_FLUSH_TIMEOUT); if (retval != ERROR_OK) return retval; /* Set instruction/addr count value */ retval = mrvlqspi_set_hdr_cnt(bank, (0x1 | (0x3 << 4))); if (retval != ERROR_OK) return retval; /* Set count for number of bytes to read */ retval = mrvlqspi_set_din_cnt(bank, count); if (retval != ERROR_OK) return retval; /* Set read address */ retval = mrvlqspi_set_addr(bank, offset); if (retval != ERROR_OK) return retval; /* Set instruction */ retval = mrvlqspi_set_instr(bank, SPIFLASH_READ); if (retval != ERROR_OK) return retval; /* Set data and addr pin length */ retval = mrvlqspi_set_conf(bank, 0x0); if (retval != ERROR_OK) return retval; retval = mrvlqspi_start_transfer(bank, QSPI_R_EN); if (retval != ERROR_OK) return retval; for (i = 0; i < count; i++) { retval = mrvlqspi_read_byte(bank, &buffer[i]); if (retval != ERROR_OK) return retval; } retval = mrvlqspi_set_ss_state(bank, QSPI_SS_DISABLE, QSPI_TIMEOUT); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int mrvlqspi_probe(struct flash_bank *bank) { struct target *target = bank->target; struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv; uint32_t id = 0; int retval; struct flash_sector *sectors; uint32_t sectorsize; /* If we've already probed, we should be fine to skip this time. */ if (mrvlqspi_info->probed) return ERROR_OK; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } mrvlqspi_info->probed = false; mrvlqspi_info->bank_num = bank->bank_number; /* Read flash JEDEC ID */ retval = mrvlqspi_read_id(bank, &id); if (retval != ERROR_OK) return retval; mrvlqspi_info->dev = NULL; for (const struct flash_device *p = flash_devices; p->name ; p++) if (p->device_id == id) { mrvlqspi_info->dev = p; break; } if (!mrvlqspi_info->dev) { LOG_ERROR("Unknown flash device ID 0x%08" PRIx32, id); return ERROR_FAIL; } LOG_INFO("Found flash device \'%s\' ID 0x%08" PRIx32, mrvlqspi_info->dev->name, mrvlqspi_info->dev->device_id); /* Set correct size value */ bank->size = mrvlqspi_info->dev->size_in_bytes; if (bank->size <= (1UL << 16)) LOG_WARNING("device needs 2-byte addresses - not implemented"); if (bank->size > (1UL << 24)) LOG_WARNING("device needs paging or 4-byte addresses - not implemented"); /* if no sectors, treat whole bank as single sector */ sectorsize = mrvlqspi_info->dev->sectorsize ? mrvlqspi_info->dev->sectorsize : mrvlqspi_info->dev->size_in_bytes; /* create and fill sectors array */ bank->num_sectors = mrvlqspi_info->dev->size_in_bytes / sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); if (!sectors) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { sectors[sector].offset = sector * sectorsize; sectors[sector].size = sectorsize; sectors[sector].is_erased = -1; sectors[sector].is_protected = 0; } bank->sectors = sectors; mrvlqspi_info->probed = true; return ERROR_OK; } static int mrvlqspi_auto_probe(struct flash_bank *bank) { struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv; if (mrvlqspi_info->probed) return ERROR_OK; return mrvlqspi_probe(bank); } static int mrvlqspi_flash_erase_check(struct flash_bank *bank) { /* Not implemented yet */ return ERROR_OK; } static int mrvlqspi_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv; if (!(mrvlqspi_info->probed)) { command_print_sameline(cmd, "\nQSPI flash bank not probed yet\n"); return ERROR_OK; } command_print_sameline(cmd, "\nQSPI flash information:\n" " Device \'%s\' ID 0x%08" PRIx32 "\n", mrvlqspi_info->dev->name, mrvlqspi_info->dev->device_id); return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(mrvlqspi_flash_bank_command) { struct mrvlqspi_flash_bank *mrvlqspi_info; if (CMD_ARGC < 7) return ERROR_COMMAND_SYNTAX_ERROR; mrvlqspi_info = malloc(sizeof(struct mrvlqspi_flash_bank)); if (!mrvlqspi_info) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } /* Get QSPI controller register map base address */ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], mrvlqspi_info->reg_base); bank->driver_priv = mrvlqspi_info; mrvlqspi_info->probed = false; return ERROR_OK; } const struct flash_driver mrvlqspi_flash = { .name = "mrvlqspi", .flash_bank_command = mrvlqspi_flash_bank_command, .erase = mrvlqspi_flash_erase, .write = mrvlqspi_flash_write, .read = mrvlqspi_flash_read, .probe = mrvlqspi_probe, .auto_probe = mrvlqspi_auto_probe, .erase_check = mrvlqspi_flash_erase_check, .info = mrvlqspi_get_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/msp432.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2018 by Texas Instruments, Inc. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "msp432.h" #include <helper/binarybuffer.h> #include <helper/time_support.h> #include <target/algorithm.h> #include <target/armv7m.h> #include <target/image.h> /* MSP432P4 hardware registers */ #define P4_FLASH_MAIN_SIZE_REG 0xE0043020 #define P4_FLASH_INFO_SIZE_REG 0xE0043024 #define P4_DEVICE_ID_REG 0x0020100C #define P4_HARDWARE_REV_REG 0x00201010 /* MSP432E4 hardware registers */ #define E4_DID0_REG 0x400FE000 #define E4_DID1_REG 0x400FE004 #define FLASH_TIMEOUT 8000 #define SUPPORT_MESSAGE \ "Your pre-production MSP432P401x silicon is not fully supported\n" \ "You can find more information at www.ti.com/product/MSP432P401R" struct msp432_bank { uint32_t device_id; uint32_t hardware_rev; int family_type; int device_type; uint32_t sector_length; bool probed_main; bool probed_info; bool unlock_bsl; struct working_area *working_area; struct armv7m_algorithm armv7m_info; }; /* Flash helper algorithm for MSP432P401x targets */ static const uint8_t msp432p401x_algo[] = { #include "../../../contrib/loaders/flash/msp432/msp432p401x_algo.inc" }; /* Flash helper algorithm for MSP432P411x targets */ static const uint8_t msp432p411x_algo[] = { #include "../../../contrib/loaders/flash/msp432/msp432p411x_algo.inc" }; /* Flash helper algorithm for MSP432E4x targets */ static const uint8_t msp432e4x_algo[] = { #include "../../../contrib/loaders/flash/msp432/msp432e4x_algo.inc" }; static int msp432_auto_probe(struct flash_bank *bank); static int msp432_device_type(uint32_t family_type, uint32_t device_id, uint32_t hardware_rev) { int device_type = MSP432_NO_TYPE; if (family_type == MSP432E4) { /* MSP432E4 device family */ if (device_id == 0x180C0002) { if (hardware_rev == 0x102DC06E) { /* The 01Y variant */ device_type = MSP432E401Y; } else if (hardware_rev == 0x1032E076) { /* The 11Y variant */ device_type = MSP432E411Y; } else { /* Reasonable guess that this is a new variant */ device_type = MSP432E4X_GUESS; } } else { /* Wild guess that this is an MSP432E4 */ device_type = MSP432E4X_GUESS; } } else { /* MSP432P4 device family */ /* Examine the device ID and hardware revision to get the device type */ switch (device_id) { case 0xA000: case 0xA001: case 0xA002: case 0xA003: case 0xA004: case 0xA005: /* Device is definitely MSP432P401x, check hardware revision */ if (hardware_rev == 0x41 || hardware_rev == 0x42) { /* Rev A or B of the silicon has been deprecated */ device_type = MSP432P401X_DEPR; } else if (hardware_rev >= 0x43 && hardware_rev <= 0x49) { /* Current and future revisions of the MSP432P401x device */ device_type = MSP432P401X; } else { /* Unknown or unanticipated hardware revision */ device_type = MSP432P401X_GUESS; } break; case 0xA010: case 0xA012: case 0xA016: case 0xA019: case 0xA01F: case 0xA020: case 0xA022: case 0xA026: case 0xA029: case 0xA02F: /* Device is definitely MSP432P411x, check hardware revision */ if (hardware_rev >= 0x41 && hardware_rev <= 0x49) { /* Current and future revisions of the MSP432P411x device */ device_type = MSP432P411X; } else { /* Unknown or unanticipated hardware revision */ device_type = MSP432P411X_GUESS; } break; case 0xFFFF: /* Device is very early silicon that has been deprecated */ device_type = MSP432P401X_DEPR; break; default: if (device_id < 0xA010) { /* Wild guess that this is an MSP432P401x */ device_type = MSP432P401X_GUESS; } else { /* Reasonable guess that this is a new variant */ device_type = MSP432P411X_GUESS; } break; } } return device_type; } static const char *msp432_return_text(uint32_t return_code) { switch (return_code) { case FLASH_BUSY: return "FLASH_BUSY"; case FLASH_SUCCESS: return "FLASH_SUCCESS"; case FLASH_ERROR: return "FLASH_ERROR"; case FLASH_TIMEOUT_ERROR: return "FLASH_TIMEOUT_ERROR"; case FLASH_VERIFY_ERROR: return "FLASH_VERIFY_WRONG"; case FLASH_WRONG_COMMAND: return "FLASH_WRONG_COMMAND"; case FLASH_POWER_ERROR: return "FLASH_POWER_ERROR"; default: return "UNDEFINED_RETURN_CODE"; } } static void msp432_init_params(struct msp432_algo_params *algo_params) { buf_set_u32(algo_params->flash_command, 0, 32, FLASH_NO_COMMAND); buf_set_u32(algo_params->return_code, 0, 32, 0); buf_set_u32(algo_params->_reserved0, 0, 32, 0); buf_set_u32(algo_params->address, 0, 32, 0); buf_set_u32(algo_params->length, 0, 32, 0); buf_set_u32(algo_params->buffer1_status, 0, 32, BUFFER_INACTIVE); buf_set_u32(algo_params->buffer2_status, 0, 32, BUFFER_INACTIVE); buf_set_u32(algo_params->erase_param, 0, 32, FLASH_ERASE_MAIN); buf_set_u32(algo_params->unlock_bsl, 0, 32, FLASH_LOCK_BSL); } static int msp432_exec_cmd(struct target *target, struct msp432_algo_params *algo_params, uint32_t command) { int retval; /* Make sure the given params do not include the command */ buf_set_u32(algo_params->flash_command, 0, 32, FLASH_NO_COMMAND); buf_set_u32(algo_params->return_code, 0, 32, 0); buf_set_u32(algo_params->buffer1_status, 0, 32, BUFFER_INACTIVE); buf_set_u32(algo_params->buffer2_status, 0, 32, BUFFER_INACTIVE); /* Write out parameters to target memory */ retval = target_write_buffer(target, ALGO_PARAMS_BASE_ADDR, sizeof(struct msp432_algo_params), (uint8_t *)algo_params); if (retval != ERROR_OK) return retval; /* Write out command to target memory */ retval = target_write_u32(target, ALGO_FLASH_COMMAND_ADDR, command); return retval; } static int msp432_wait_return_code(struct target *target) { uint32_t return_code = 0; long long start_ms; long long elapsed_ms; int retval = ERROR_OK; start_ms = timeval_ms(); while ((return_code == 0) || (return_code == FLASH_BUSY)) { retval = target_read_u32(target, ALGO_RETURN_CODE_ADDR, &return_code); if (retval != ERROR_OK) return retval; elapsed_ms = timeval_ms() - start_ms; if (elapsed_ms > 500) keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; }; if (return_code != FLASH_SUCCESS) { LOG_ERROR("msp432: Flash operation failed: %s", msp432_return_text(return_code)); return ERROR_FAIL; } return ERROR_OK; } static int msp432_wait_inactive(struct target *target, uint32_t buffer) { uint32_t status_code = BUFFER_ACTIVE; uint32_t status_addr; long long start_ms; long long elapsed_ms; int retval; switch (buffer) { case 1: /* Buffer 1 */ status_addr = ALGO_BUFFER1_STATUS_ADDR; break; case 2: /* Buffer 2 */ status_addr = ALGO_BUFFER2_STATUS_ADDR; break; default: return ERROR_FAIL; } start_ms = timeval_ms(); while (status_code != BUFFER_INACTIVE) { retval = target_read_u32(target, status_addr, &status_code); if (retval != ERROR_OK) return retval; elapsed_ms = timeval_ms() - start_ms; if (elapsed_ms > 500) keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; }; if (status_code != BUFFER_INACTIVE) { LOG_ERROR( "msp432: Flash operation failed: buffer not written to flash"); return ERROR_FAIL; } return ERROR_OK; } static int msp432_init(struct flash_bank *bank) { struct target *target = bank->target; struct msp432_bank *msp432_bank = bank->driver_priv; struct msp432_algo_params algo_params; struct reg_param reg_params[1]; const uint8_t *loader_code; uint32_t loader_size; uint32_t algo_entry_addr; int retval; /* Make sure we've probed the flash to get the device and size */ retval = msp432_auto_probe(bank); if (retval != ERROR_OK) return retval; /* Choose appropriate flash helper algorithm */ switch (msp432_bank->device_type) { case MSP432P401X: case MSP432P401X_DEPR: case MSP432P401X_GUESS: default: loader_code = msp432p401x_algo; loader_size = sizeof(msp432p401x_algo); algo_entry_addr = P4_ALGO_ENTRY_ADDR; break; case MSP432P411X: case MSP432P411X_GUESS: loader_code = msp432p411x_algo; loader_size = sizeof(msp432p411x_algo); algo_entry_addr = P4_ALGO_ENTRY_ADDR; break; case MSP432E401Y: case MSP432E411Y: case MSP432E4X_GUESS: loader_code = msp432e4x_algo; loader_size = sizeof(msp432e4x_algo); algo_entry_addr = E4_ALGO_ENTRY_ADDR; break; } /* Issue warnings if this is a device we may not be able to flash */ if (msp432_bank->device_type == MSP432P401X_GUESS || msp432_bank->device_type == MSP432P411X_GUESS) { /* Explicit device type check failed. Report this. */ LOG_WARNING( "msp432: Unrecognized MSP432P4 Device ID and Hardware " "Rev (%04" PRIX32 ", %02" PRIX32 ")", msp432_bank->device_id, msp432_bank->hardware_rev); } else if (msp432_bank->device_type == MSP432P401X_DEPR) { LOG_WARNING( "msp432: MSP432P401x pre-production device (deprecated " "silicon)\n" SUPPORT_MESSAGE); } else if (msp432_bank->device_type == MSP432E4X_GUESS) { /* Explicit device type check failed. Report this. */ LOG_WARNING( "msp432: Unrecognized MSP432E4 DID0 and DID1 values " "(%08" PRIX32 ", %08" PRIX32 ")", msp432_bank->device_id, msp432_bank->hardware_rev); } /* Check for working area to use for flash helper algorithm */ target_free_working_area(target, msp432_bank->working_area); msp432_bank->working_area = NULL; retval = target_alloc_working_area(target, ALGO_WORKING_SIZE, &msp432_bank->working_area); if (retval != ERROR_OK) return retval; /* Confirm the defined working address is the area we need to use */ if (msp432_bank->working_area->address != ALGO_BASE_ADDR) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* Write flash helper algorithm into target memory */ retval = target_write_buffer(target, ALGO_BASE_ADDR, loader_size, loader_code); if (retval != ERROR_OK) return retval; /* Initialize the ARMv7 specific info to run the algorithm */ msp432_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; msp432_bank->armv7m_info.core_mode = ARM_MODE_THREAD; /* Initialize algorithm parameters to default values */ msp432_init_params(&algo_params); /* Write out parameters to target memory */ retval = target_write_buffer(target, ALGO_PARAMS_BASE_ADDR, sizeof(algo_params), (uint8_t *)&algo_params); if (retval != ERROR_OK) return retval; /* Initialize stack pointer for flash helper algorithm */ init_reg_param(®_params[0], "sp", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, ALGO_STACK_POINTER_ADDR); /* Begin executing the flash helper algorithm */ retval = target_start_algorithm(target, 0, NULL, 1, reg_params, algo_entry_addr, 0, &msp432_bank->armv7m_info); destroy_reg_param(®_params[0]); if (retval != ERROR_OK) { LOG_ERROR("msp432: Failed to start flash helper algorithm"); return retval; } /* * At this point, the algorithm is running on the target and * ready to receive commands and data to flash the target */ /* Issue the init command to the flash helper algorithm */ retval = msp432_exec_cmd(target, &algo_params, FLASH_INIT); if (retval != ERROR_OK) return retval; retval = msp432_wait_return_code(target); return retval; } static int msp432_quit(struct flash_bank *bank) { struct target *target = bank->target; struct msp432_bank *msp432_bank = bank->driver_priv; struct msp432_algo_params algo_params; int retval; /* Initialize algorithm parameters to default values */ msp432_init_params(&algo_params); /* Issue the exit command to the flash helper algorithm */ retval = msp432_exec_cmd(target, &algo_params, FLASH_EXIT); if (retval != ERROR_OK) return retval; (void)msp432_wait_return_code(target); /* Regardless of the return code, attempt to halt the target */ (void)target_halt(target); /* Now confirm target halted and clean up from flash helper algorithm */ retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, FLASH_TIMEOUT, &msp432_bank->armv7m_info); target_free_working_area(target, msp432_bank->working_area); msp432_bank->working_area = NULL; return retval; } static int msp432_mass_erase(struct flash_bank *bank, bool all) { struct target *target = bank->target; struct msp432_bank *msp432_bank = bank->driver_priv; struct msp432_algo_params algo_params; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = msp432_init(bank); if (retval != ERROR_OK) return retval; /* Initialize algorithm parameters to default values */ msp432_init_params(&algo_params); if (all) { buf_set_u32(algo_params.erase_param, 0, 32, FLASH_ERASE_MAIN | FLASH_ERASE_INFO); if (msp432_bank->unlock_bsl) buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL); } /* Issue the mass erase command to the flash helper algorithm */ retval = msp432_exec_cmd(target, &algo_params, FLASH_MASS_ERASE); if (retval != ERROR_OK) { (void)msp432_quit(bank); return retval; } retval = msp432_wait_return_code(target); if (retval != ERROR_OK) { (void)msp432_quit(bank); return retval; } retval = msp432_quit(bank); if (retval != ERROR_OK) return retval; return retval; } COMMAND_HANDLER(msp432_mass_erase_command) { struct flash_bank *bank; struct msp432_bank *msp432_bank; bool all; int retval; if (1 > CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; if (1 == CMD_ARGC) { all = false; } else if (2 == CMD_ARGC) { /* Check argument for how much to erase */ if (strcmp(CMD_ARGV[1], "main") == 0) all = false; else if (strcmp(CMD_ARGV[1], "all") == 0) all = true; else return ERROR_COMMAND_SYNTAX_ERROR; } else { return ERROR_COMMAND_SYNTAX_ERROR; } msp432_bank = bank->driver_priv; if (msp432_bank->family_type == MSP432E4) { /* MSP432E4 does not have main vs info regions, ignore "all" */ all = false; } retval = msp432_mass_erase(bank, all); if (retval != ERROR_OK) return retval; if (msp432_bank->family_type == MSP432E4) { /* MSP432E4 does not have main vs info regions */ LOG_INFO("msp432: Mass erase of flash is complete"); } else { LOG_INFO("msp432: Mass erase of %s is complete", all ? "main + information flash" : "main flash"); } return ERROR_OK; } COMMAND_HANDLER(msp432_bsl_command) { struct flash_bank *bank; struct msp432_bank *msp432_bank; int retval; if (1 > CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; msp432_bank = bank->driver_priv; if (msp432_bank->family_type == MSP432E4) { LOG_WARNING("msp432: MSP432E4 does not have a BSL region"); return ERROR_OK; } if (2 == CMD_ARGC) { if (strcmp(CMD_ARGV[1], "lock") == 0) msp432_bank->unlock_bsl = false; else if (strcmp(CMD_ARGV[1], "unlock") == 0) msp432_bank->unlock_bsl = true; else return ERROR_COMMAND_SYNTAX_ERROR; } else if (1 != CMD_ARGC) { /* Extra, unknown argument passed in */ return ERROR_COMMAND_SYNTAX_ERROR; } LOG_INFO("msp432: BSL flash region is currently %slocked", msp432_bank->unlock_bsl ? "un" : ""); return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command) { struct msp432_bank *msp432_bank; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; /* Create shared private struct for flash banks */ msp432_bank = malloc(sizeof(struct msp432_bank)); if (!msp432_bank) return ERROR_FAIL; /* Initialize private flash information */ msp432_bank->device_id = 0; msp432_bank->hardware_rev = 0; msp432_bank->family_type = MSP432_NO_FAMILY; msp432_bank->device_type = MSP432_NO_TYPE; msp432_bank->sector_length = 0x1000; msp432_bank->probed_main = false; msp432_bank->probed_info = false; msp432_bank->unlock_bsl = false; msp432_bank->working_area = NULL; /* Finish up initial settings here */ bank->driver_priv = msp432_bank; bank->base = FLASH_BASE; return ERROR_OK; } static int msp432_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct msp432_bank *msp432_bank = bank->driver_priv; struct msp432_algo_params algo_params; bool is_main = bank->base == FLASH_BASE; bool is_info = bank->base == P4_FLASH_INFO_BASE; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Do a mass erase if user requested all sectors of main flash */ if (is_main && (first == 0) && (last == (bank->num_sectors - 1))) { /* Request mass erase of main flash */ return msp432_mass_erase(bank, false); } retval = msp432_init(bank); if (retval != ERROR_OK) return retval; /* Initialize algorithm parameters to default values */ msp432_init_params(&algo_params); /* Adjust params if this is the info bank */ if (is_info) { buf_set_u32(algo_params.erase_param, 0, 32, FLASH_ERASE_INFO); /* And flag if BSL is unlocked */ if (msp432_bank->unlock_bsl) buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL); } /* Erase requested sectors one by one */ for (unsigned int i = first; i <= last; i++) { /* Skip TVL (read-only) sector of the info bank */ if (is_info && 1 == i) continue; /* Skip BSL sectors of info bank if locked */ if (is_info && (2 == i || 3 == i) && !msp432_bank->unlock_bsl) continue; /* Convert sector number to starting address of sector */ buf_set_u32(algo_params.address, 0, 32, bank->base + (i * msp432_bank->sector_length)); /* Issue the sector erase command to the flash helper algorithm */ retval = msp432_exec_cmd(target, &algo_params, FLASH_SECTOR_ERASE); if (retval != ERROR_OK) { (void)msp432_quit(bank); return retval; } retval = msp432_wait_return_code(target); if (retval != ERROR_OK) { (void)msp432_quit(bank); return retval; } } retval = msp432_quit(bank); if (retval != ERROR_OK) return retval; return retval; } static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct msp432_bank *msp432_bank = bank->driver_priv; struct msp432_algo_params algo_params; uint32_t size; uint32_t data_ready = BUFFER_DATA_READY; long long start_ms; long long elapsed_ms; bool is_info = bank->base == P4_FLASH_INFO_BASE; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* * Block attempts to write to read-only sectors of flash * The TVL region in sector 1 of the info flash is always read-only * The BSL region in sectors 2 and 3 of the info flash may be unlocked * The helper algorithm will hang on attempts to write to TVL */ if (is_info) { /* Set read-only start to TVL sector */ uint32_t start = 0x1000; /* Set read-only end after BSL region if locked */ uint32_t end = (msp432_bank->unlock_bsl) ? 0x2000 : 0x4000; /* Check if request includes anything in read-only sectors */ if ((offset + count - 1) < start || offset >= end) { /* The request includes no bytes in read-only sectors */ /* Fall out and process the request normally */ } else { /* Send a request for anything before read-only sectors */ if (offset < start) { uint32_t start_count = MIN(start - offset, count); retval = msp432_write(bank, buffer, offset, start_count); if (retval != ERROR_OK) return retval; } /* Send a request for anything after read-only sectors */ if ((offset + count - 1) >= end) { uint32_t skip = end - offset; count -= skip; offset += skip; buffer += skip; return msp432_write(bank, buffer, offset, count); } else { /* Request is entirely in read-only sectors */ return ERROR_OK; } } } retval = msp432_init(bank); if (retval != ERROR_OK) return retval; /* Initialize algorithm parameters to default values */ msp432_init_params(&algo_params); /* Set up parameters for requested flash write operation */ buf_set_u32(algo_params.address, 0, 32, bank->base + offset); buf_set_u32(algo_params.length, 0, 32, count); /* Check if this is the info bank */ if (is_info) { /* And flag if BSL is unlocked */ if (msp432_bank->unlock_bsl) buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL); } /* Set up flash helper algorithm to continuous flash mode */ retval = msp432_exec_cmd(target, &algo_params, FLASH_CONTINUOUS); if (retval != ERROR_OK) { (void)msp432_quit(bank); return retval; } /* Write requested data, one buffer at a time */ start_ms = timeval_ms(); while (count > 0) { if (count > ALGO_BUFFER_SIZE) size = ALGO_BUFFER_SIZE; else size = count; /* Put next block of data to flash into buffer */ retval = target_write_buffer(target, ALGO_BUFFER1_ADDR, size, buffer); if (retval != ERROR_OK) { LOG_ERROR("Unable to write data to target memory"); (void)msp432_quit(bank); return ERROR_FLASH_OPERATION_FAILED; } /* Signal the flash helper algorithm that data is ready to flash */ retval = target_write_u32(target, ALGO_BUFFER1_STATUS_ADDR, data_ready); if (retval != ERROR_OK) { (void)msp432_quit(bank); return ERROR_FLASH_OPERATION_FAILED; } retval = msp432_wait_inactive(target, 1); if (retval != ERROR_OK) { (void)msp432_quit(bank); return retval; } count -= size; buffer += size; elapsed_ms = timeval_ms() - start_ms; if (elapsed_ms > 500) keep_alive(); } /* Confirm that the flash helper algorithm is finished */ retval = msp432_wait_return_code(target); if (retval != ERROR_OK) { (void)msp432_quit(bank); return retval; } retval = msp432_quit(bank); if (retval != ERROR_OK) return retval; return retval; } static int msp432_probe(struct flash_bank *bank) { struct target *target = bank->target; struct msp432_bank *msp432_bank = bank->driver_priv; uint32_t device_id; uint32_t hardware_rev; uint32_t sector_length; uint32_t size; unsigned int num_sectors; bool is_main = bank->base == FLASH_BASE; bool is_info = bank->base == P4_FLASH_INFO_BASE; int retval; /* Check if this bank has already been successfully probed */ if (is_main && msp432_bank->probed_main) return ERROR_OK; if (is_info && msp432_bank->probed_info) return ERROR_OK; /* Read the flash size register to determine this is a P4 or not */ /* MSP432P4s will return the size of flash. MSP432E4s will return zero */ retval = target_read_u32(target, P4_FLASH_MAIN_SIZE_REG, &size); if (retval != ERROR_OK) return retval; if (size == 0) { /* This is likely an MSP432E4 */ msp432_bank->family_type = MSP432E4; retval = target_read_u32(target, E4_DID0_REG, &device_id); if (retval != ERROR_OK) return retval; msp432_bank->device_id = device_id; retval = target_read_u32(target, E4_DID1_REG, &hardware_rev); if (retval != ERROR_OK) return retval; msp432_bank->hardware_rev = hardware_rev; } else { /* This is likely an MSP432P4 */ msp432_bank->family_type = MSP432P4; retval = target_read_u32(target, P4_DEVICE_ID_REG, &device_id); if (retval != ERROR_OK) return retval; msp432_bank->device_id = device_id & 0xFFFF; retval = target_read_u32(target, P4_HARDWARE_REV_REG, &hardware_rev); if (retval != ERROR_OK) return retval; msp432_bank->hardware_rev = hardware_rev & 0xFF; } msp432_bank->device_type = msp432_device_type(msp432_bank->family_type, msp432_bank->device_id, msp432_bank->hardware_rev); if (msp432_bank->family_type == MSP432P4) { /* Set up MSP432P4 specific flash parameters */ if (is_main) { retval = target_read_u32(target, P4_FLASH_MAIN_SIZE_REG, &size); if (retval != ERROR_OK) return retval; sector_length = P4_SECTOR_LENGTH; num_sectors = size / sector_length; } else if (is_info) { if (msp432_bank->device_type == MSP432P411X || msp432_bank->device_type == MSP432P411X_GUESS) { /* MSP432P411x has an info size register, use that for size */ retval = target_read_u32(target, P4_FLASH_INFO_SIZE_REG, &size); if (retval != ERROR_OK) return retval; } else { /* All other MSP432P401x devices have fixed info region size */ size = 0x4000; /* 16 KB info region */ } sector_length = P4_SECTOR_LENGTH; num_sectors = size / sector_length; } else { /* Invalid bank somehow */ return ERROR_FAIL; } } else { /* Set up MSP432E4 specific flash parameters */ if (is_main) { size = E4_FLASH_SIZE; sector_length = E4_SECTOR_LENGTH; num_sectors = size / sector_length; } else { /* Invalid bank somehow */ return ERROR_FAIL; } } free(bank->sectors); bank->sectors = NULL; if (num_sectors > 0) { bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); if (!bank->sectors) return ERROR_FAIL; } bank->size = size; bank->write_start_alignment = 0; bank->write_end_alignment = 0; bank->num_sectors = num_sectors; msp432_bank->sector_length = sector_length; for (unsigned int i = 0; i < num_sectors; i++) { bank->sectors[i].offset = i * sector_length; bank->sectors[i].size = sector_length; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } /* We've successfully determined the stats on this flash bank */ if (is_main) msp432_bank->probed_main = true; if (is_info) msp432_bank->probed_info = true; if (is_main && MSP432P4 == msp432_bank->family_type) { /* Create the info flash bank needed by MSP432P4 variants */ struct flash_bank *info = calloc(sizeof(struct flash_bank), 1); if (!info) return ERROR_FAIL; /* Create a name for the info bank, append "_1" to main name */ char *name = malloc(strlen(bank->name) + 3); strcpy(name, bank->name); strcat(name, "_1"); /* Initialize info bank */ info->name = name; info->target = bank->target; info->driver = bank->driver; info->driver_priv = msp432_bank; info->base = P4_FLASH_INFO_BASE; flash_bank_add(info); } /* If we fall through to here, then all went well */ return ERROR_OK; } static int msp432_auto_probe(struct flash_bank *bank) { struct msp432_bank *msp432_bank = bank->driver_priv; bool is_main = bank->base == FLASH_BASE; bool is_info = bank->base == P4_FLASH_INFO_BASE; int retval = ERROR_OK; if (is_main) if (!msp432_bank->probed_main) retval = msp432_probe(bank); if (is_info) if (!msp432_bank->probed_info) retval = msp432_probe(bank); return retval; } static int msp432_info(struct flash_bank *bank, struct command_invocation *cmd) { struct msp432_bank *msp432_bank = bank->driver_priv; switch (msp432_bank->device_type) { case MSP432P401X_DEPR: if (msp432_bank->device_id == 0xFFFF) { /* Very early pre-production silicon currently deprecated */ command_print_sameline(cmd, "MSP432P401x pre-production device (deprecated silicon)\n" SUPPORT_MESSAGE); } else { /* Revision A or B silicon, also deprecated */ command_print_sameline(cmd, "MSP432P401x Device Rev %c (deprecated silicon)\n" SUPPORT_MESSAGE, (char)msp432_bank->hardware_rev); } break; case MSP432P401X: command_print_sameline(cmd, "MSP432P401x Device Rev %c\n", (char)msp432_bank->hardware_rev); break; case MSP432P411X: command_print_sameline(cmd, "MSP432P411x Device Rev %c\n", (char)msp432_bank->hardware_rev); break; case MSP432E401Y: command_print_sameline(cmd, "MSP432E401Y Device\n"); break; case MSP432E411Y: command_print_sameline(cmd, "MSP432E411Y Device\n"); break; case MSP432E4X_GUESS: command_print_sameline(cmd, "Unrecognized MSP432E4 DID0 and DID1 IDs (%08" PRIX32 ", %08" PRIX32 ")", msp432_bank->device_id, msp432_bank->hardware_rev); break; case MSP432P401X_GUESS: case MSP432P411X_GUESS: default: command_print_sameline(cmd, "Unrecognized MSP432P4 Device ID and Hardware Rev (%04" PRIX32 ", %02" PRIX32 ")", msp432_bank->device_id, msp432_bank->hardware_rev); break; } return ERROR_OK; } static int msp432_protect_check(struct flash_bank *bank) { /* Added to suppress warning, not needed for MSP432 flash */ return ERROR_OK; } static void msp432_flash_free_driver_priv(struct flash_bank *bank) { bool is_main = bank->base == FLASH_BASE; /* A single private struct is shared between main and info banks */ /* Only free it on the call for main bank */ if (is_main) free(bank->driver_priv); /* Forget about the private struct on both main and info banks */ bank->driver_priv = NULL; } static const struct command_registration msp432_exec_command_handlers[] = { { .name = "mass_erase", .handler = msp432_mass_erase_command, .mode = COMMAND_EXEC, .help = "Erase entire flash memory on device.", .usage = "bank_id ['main' | 'all']", }, { .name = "bsl", .handler = msp432_bsl_command, .mode = COMMAND_EXEC, .help = "Allow BSL to be erased or written by flash commands.", .usage = "bank_id ['unlock' | 'lock']", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration msp432_command_handlers[] = { { .name = "msp432", .mode = COMMAND_EXEC, .help = "MSP432 flash command group", .usage = "", .chain = msp432_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver msp432_flash = { .name = "msp432", .commands = msp432_command_handlers, .flash_bank_command = msp432_flash_bank_command, .erase = msp432_erase, .write = msp432_write, .read = default_flash_read, .probe = msp432_probe, .auto_probe = msp432_auto_probe, .erase_check = default_flash_blank_check, .protect_check = msp432_protect_check, .info = msp432_info, .free_driver_priv = msp432_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/msp432.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2018 by Texas Instruments, Inc. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_MSP432_H #define OPENOCD_FLASH_NOR_MSP432_H /* MSP432 family types */ #define MSP432_NO_FAMILY 0 /* Family type not determined yet */ #define MSP432E4 1 /* MSP432E4 family of devices */ #define MSP432P4 2 /* MSP432P4 family of devices */ /* MSP432 device types */ #define MSP432_NO_TYPE 0 /* Device type not determined yet */ #define MSP432P401X_DEPR 1 /* Early MSP432P401x offerings, now deprecated */ #define MSP432P401X 2 /* MSP432P401x device, revision C or higher */ #define MSP432P411X 3 /* MSP432P411x device, revision A or higher */ #define MSP432P401X_GUESS 4 /* Assuming it's an MSP432P401x device */ #define MSP432P411X_GUESS 5 /* Assuming it's an MSP432P411x device */ #define MSP432E401Y 6 /* MSP432E401Y device */ #define MSP432E411Y 7 /* MSP432E401Y device */ #define MSP432E4X_GUESS 8 /* Assuming it's an MSP432E4x device */ /* Common MSP432 flash parameters */ #define FLASH_BASE 0x00000000 /* MSP432P4 flash parameters */ #define P4_FLASH_MAIN_BASE FLASH_BASE #define P4_FLASH_INFO_BASE 0x00200000 #define P4_SECTOR_LENGTH 0x1000 #define P4_ALGO_ENTRY_ADDR 0x01000110 /* MSP432E4 flash parameters */ #define E4_FLASH_BASE FLASH_BASE #define E4_FLASH_SIZE 0x100000 #define E4_SECTOR_LENGTH 0x4000 #define E4_ALGO_ENTRY_ADDR 0x20000110 /* Flash helper algorithm key addresses */ #define ALGO_BASE_ADDR 0x20000000 #define ALGO_BUFFER1_ADDR 0x20002000 #define ALGO_BUFFER2_ADDR 0x20003000 #define ALGO_PARAMS_BASE_ADDR 0x20000150 #define ALGO_FLASH_COMMAND_ADDR 0x20000150 #define ALGO_RETURN_CODE_ADDR 0x20000154 #define ALGO_FLASH_DEST_ADDR 0x2000015c #define ALGO_FLASH_LENGTH_ADDR 0x20000160 #define ALGO_BUFFER1_STATUS_ADDR 0x20000164 #define ALGO_BUFFER2_STATUS_ADDR 0x20000168 #define ALGO_ERASE_PARAM_ADDR 0x2000016c #define ALGO_UNLOCK_BSL_ADDR 0x20000170 #define ALGO_STACK_POINTER_ADDR 0x20002000 /* Flash helper algorithm key sizes */ #define ALGO_BUFFER_SIZE 0x1000 #define ALGO_WORKING_SIZE (ALGO_BUFFER2_ADDR + 0x1000 - ALGO_BASE_ADDR) /* Flash helper algorithm flash commands */ #define FLASH_NO_COMMAND 0 #define FLASH_MASS_ERASE 1 #define FLASH_SECTOR_ERASE 2 #define FLASH_PROGRAM 4 #define FLASH_INIT 8 #define FLASH_EXIT 16 #define FLASH_CONTINUOUS 32 /* Flash helper algorithm return codes */ #define FLASH_BUSY 0x00000001 #define FLASH_SUCCESS 0x00000ACE #define FLASH_ERROR 0x0000DEAD #define FLASH_TIMEOUT_ERROR 0xDEAD0000 #define FLASH_VERIFY_ERROR 0xDEADDEAD #define FLASH_WRONG_COMMAND 0x00000BAD #define FLASH_POWER_ERROR 0x00DEAD00 /* Flash helper algorithm buffer status values */ #define BUFFER_INACTIVE 0x00 #define BUFFER_ACTIVE 0x01 #define BUFFER_DATA_READY 0x10 /* Flash helper algorithm erase parameters */ #define FLASH_ERASE_MAIN 0x01 #define FLASH_ERASE_INFO 0x02 /* Flash helper algorithm lock/unlock BSL options */ #define FLASH_LOCK_BSL 0x00 #define FLASH_UNLOCK_BSL 0x0b /* Flash helper algorithm parameter block struct */ struct msp432_algo_params { uint8_t flash_command[4]; uint8_t return_code[4]; uint8_t _reserved0[4]; uint8_t address[4]; uint8_t length[4]; uint8_t buffer1_status[4]; uint8_t buffer2_status[4]; uint8_t erase_param[4]; uint8_t unlock_bsl[4]; }; #endif /* OPENOCD_FLASH_NOR_MSP432_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/niietcm4.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2015 by Bogdan Kolbov * * kolbov@niiet.ru * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> #define FLASH_DRIVER_VER 0x00010000 #define CHIPID_ADDR 0xF0000000 #define K1921VK01T_ID 0x00000000 /*============================================================================== * FLASH CONTROL REGS *============================================================================== */ #define MAIN_MEM_TYPE 0 #define INFO_MEM_TYPE 1 #define SERVICE_MODE_ERASE_ADDR 0x80030164 #define MAGIC_KEY 0xA442 /*-- BOOTFLASH ---------------------------------------------------------------*/ #define BOOTFLASH_BASE 0xA001C000 #define FMA (BOOTFLASH_BASE + 0x00) #define FMD1 (BOOTFLASH_BASE + 0x04) #define FMC (BOOTFLASH_BASE + 0x08) #define FCIS (BOOTFLASH_BASE + 0x0C) #define FCIM (BOOTFLASH_BASE + 0x10) #define FCIC (BOOTFLASH_BASE + 0x14) #define FMD2 (BOOTFLASH_BASE + 0x50) #define FMD3 (BOOTFLASH_BASE + 0x54) #define FMD4 (BOOTFLASH_BASE + 0x58) /*---- FMC: Command register */ #define FMC_WRITE (1<<0) /* Writing in main region */ #define FMC_PAGE_ERASE (1<<1) /* Page erase the main region */ #define FMC_FULL_ERASE (1<<2) /* Erase full flash */ #define FMC_WRITE_IFB (1<<4) /* Writing in info region */ #define FMC_PAGEERASE_IFB (1<<5) /* Erase page of info region */ #define FMC_MAGIC_KEY (MAGIC_KEY<<16) /* Operation run command */ /*---- FCIS: Status register */ #define FCIS_OP_CMLT (1<<0) /* Completion flag operation */ #define FCIS_OP_ERROR (1<<1) /* Flag operation error */ /*---- FCIC: CLear status register */ #define FCIC_CLR_OPCMLT (1<<0) /* Clear completion flag in register FCIS */ #define FCIC_CLR_OPERROR (1<<1) /* Clear error flag in register FCIS */ /*-- USERFLASH ---------------------------------------------------------------*/ #define USERFLASH_PAGE_SIZE 256 #define USERFLASH_PAGE_TOTALNUM 256 #define USERFLASH_BASE 0xA0022000 #define UFMA (USERFLASH_BASE + 0x00) #define UFMD (USERFLASH_BASE + 0x04) #define UFMC (USERFLASH_BASE + 0x08) #define UFCIS (USERFLASH_BASE + 0x0C) #define UFCIM (USERFLASH_BASE + 0x10) #define UFCIC (USERFLASH_BASE + 0x14) /*---- UFMC: Command register */ #define UFMC_WRITE (1<<0) /* Writing in main region */ #define UFMC_PAGE_ERASE (1<<1) /* Paged erase the main region */ #define UFMC_FULL_ERASE (1<<2) /* Erase full flash */ #define UFMC_READ (1<<3) /* Reading from main region */ #define UFMC_WRITE_IFB (1<<4) /* Writing in info region */ #define UFMC_PAGEERASE_IFB (1<<5) /* Erase page of info region */ #define UFMC_READ_IFB (1<<6) /* Reading from info region */ #define UFMC_MAGIC_KEY (MAGIC_KEY<<16) /* Operation run command */ /*---- UFCIS: Status register */ #define UFCIS_OP_CMLT (1<<0) /* Completion flag operation */ #define UFCIS_OP_ERROR (1<<1) /* Flag operation error */ /*---- UFCIC: CLear status register */ #define UFCIC_CLR_OPCMLT (1<<0) /* Clear completion flag in register FCIS */ #define UFCIC_CLR_OPERROR (1<<1) /* Clear error flag in register FCIS */ /*---- In info userflash address space */ #define INFOWORD0_ADDR 0x00 #define INFOWORD0_BOOTFROM_IFB (1<<0) /* Boot from bootflash or bootflash_ifb */ #define INFOWORD0_EN_GPIO (1<<1) /* Remap to 0x00000000 extmem or bootflash */ #define INFOWORD0_BOOTFROM_IFB_POS 0 #define INFOWORD0_EN_GPIO_POS 1 #define INFOWORD0_EXTMEM_SEL_POS 3 /* Choose altfunc of gpio to work with extmem */ #define INFOWORD1_ADDR 0x01 #define INFOWORD1_PINNUM_POS 0 /* Choose gpio pin number to control extmem boot */ #define INFOWORD1_PORTNUM_POS 4 /* Choose gpio port to control extmem boot */ #define INFOWORD2_ADDR 0x02 #define INFOWORD2_LOCK_IFB_BF (1<<0) /* Protect info part of bootflash */ #define INFOWORD3_ADDR 0x03 #define INFOWORD3_LOCK_IFB_UF (1<<0) /* Protect info part of userflash */ #define BF_LOCK_ADDR 0x40 #define UF_LOCK_ADDR 0x80 /** * Private data for flash driver. */ struct niietcm4_flash_bank { /* target params */ bool probed; uint32_t chipid; char *chip_name; char chip_brief[4096]; /* not mapped userflash params */ uint32_t uflash_width; uint32_t uflash_size; uint32_t uflash_pagetotal; uint32_t uflash_info_size; uint32_t uflash_info_pagetotal; /* boot params */ bool bflash_info_remap; char *extmem_boot_port; uint32_t extmem_boot_pin; uint32_t extmem_boot_altfunc; bool extmem_boot; }; /*============================================================================== * HELPER FUNCTIONS *============================================================================== */ /** * Wait while operation with bootflash being performed and check result status */ static int niietcm4_opstatus_check(struct flash_bank *bank) { struct target *target = bank->target; int retval; int timeout = 5000; uint32_t flash_status; retval = target_read_u32(target, FCIS, &flash_status); if (retval != ERROR_OK) return retval; while (flash_status == 0x00) { retval = target_read_u32(target, FCIS, &flash_status); if (retval != ERROR_OK) return retval; if (timeout-- <= 0) { LOG_ERROR("Bootflash operation timeout"); return ERROR_FLASH_OPERATION_FAILED; } busy_sleep(1); /* can use busy sleep for short times. */ } if (flash_status == FCIS_OP_ERROR) { LOG_ERROR("Bootflash operation error"); return ERROR_FLASH_OPERATION_FAILED; } /* clear status */ uint32_t flash_cmd = FCIC_CLR_OPCMLT | FCIC_CLR_OPERROR; retval = target_write_u32(target, FCIC, flash_cmd); if (retval != ERROR_OK) return retval; return retval; } /** * Wait while operation with userflash being performed and check result status */ static int niietcm4_uopstatus_check(struct flash_bank *bank) { struct target *target = bank->target; int retval; int timeout = 5000; uint32_t uflash_status; retval = target_read_u32(target, UFCIS, &uflash_status); if (retval != ERROR_OK) return retval; while (uflash_status == 0x00) { retval = target_read_u32(target, UFCIS, &uflash_status); if (retval != ERROR_OK) return retval; if (timeout-- <= 0) { LOG_ERROR("Userflash operation timeout"); return ERROR_FLASH_OPERATION_FAILED; } busy_sleep(1); /* can use busy sleep for short times. */ } if (uflash_status == UFCIS_OP_ERROR) { LOG_ERROR("Userflash operation error"); return ERROR_FLASH_OPERATION_FAILED; } /* clear status */ uint32_t uflash_cmd = UFCIC_CLR_OPCMLT | UFCIC_CLR_OPERROR; retval = target_write_u32(target, UFCIC, uflash_cmd); if (retval != ERROR_OK) return retval; return retval; } /** * Dump page of userflash region. * If we want to change some settings, we have to dump it full, because userflash is flash(not EEPROM). * And correct write to flash can be performed only after erase. * So without dump, changing one registers will clear others. */ static int niietcm4_dump_uflash_page(struct flash_bank *bank, uint32_t *dump, int page_num, int mem_type) { struct target *target = bank->target; int i; int retval = ERROR_OK; uint32_t uflash_cmd; if (mem_type == INFO_MEM_TYPE) uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ_IFB; else uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ; int first = page_num*USERFLASH_PAGE_SIZE; int last = first + USERFLASH_PAGE_SIZE; for (i = first; i < last; i++) { retval = target_write_u32(target, UFMA, i); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, UFMC, uflash_cmd); if (retval != ERROR_OK) return retval; retval = niietcm4_uopstatus_check(bank); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, UFMD, &dump[i]); if (retval != ERROR_OK) return retval; } return retval; } /** * Load modified page dump to userflash region page. */ static int niietcm4_load_uflash_page(struct flash_bank *bank, uint32_t *dump, int page_num, int mem_type) { struct target *target = bank->target; int i; int retval = ERROR_OK; uint32_t uflash_cmd; if (mem_type == INFO_MEM_TYPE) uflash_cmd = UFMC_MAGIC_KEY | UFMC_WRITE_IFB; else uflash_cmd = UFMC_MAGIC_KEY | UFMC_WRITE; int first = page_num*USERFLASH_PAGE_SIZE; int last = first + USERFLASH_PAGE_SIZE; for (i = first; i < last; i++) { retval = target_write_u32(target, UFMA, i); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, UFMD, dump[i]); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, UFMC, uflash_cmd); if (retval != ERROR_OK) return retval; retval = niietcm4_uopstatus_check(bank); if (retval != ERROR_OK) return retval; } return retval; } /** * Erase one page of userflash info or main region */ static int niietcm4_uflash_page_erase(struct flash_bank *bank, int page_num, int mem_type) { struct target *target = bank->target; int retval; uint32_t uflash_cmd; if (mem_type == INFO_MEM_TYPE) uflash_cmd = UFMC_MAGIC_KEY | UFMC_PAGEERASE_IFB; else uflash_cmd = UFMC_MAGIC_KEY | UFMC_PAGE_ERASE; retval = target_write_u32(target, UFMA, page_num*USERFLASH_PAGE_SIZE); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, UFMD, 0xFF); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, UFMC, uflash_cmd); if (retval != ERROR_OK) return retval; /* status check */ retval = niietcm4_uopstatus_check(bank); if (retval != ERROR_OK) return retval; return retval; } /** * Enable or disable protection of userflash pages */ static int niietcm4_uflash_protect(struct flash_bank *bank, int mem_type, int set, unsigned int first, unsigned int last) { int retval; if (mem_type == INFO_MEM_TYPE) { /* read dump */ uint32_t uflash_dump[USERFLASH_PAGE_SIZE]; retval = niietcm4_dump_uflash_page(bank, uflash_dump, 0, 1); if (retval != ERROR_OK) return retval; /* modify dump */ if (set) uflash_dump[INFOWORD2_ADDR] &= ~INFOWORD3_LOCK_IFB_UF; else uflash_dump[INFOWORD2_ADDR] |= INFOWORD3_LOCK_IFB_UF; /* erase page 0 userflash */ retval = niietcm4_uflash_page_erase(bank, 0, 1); if (retval != ERROR_OK) return retval; /* write dump to userflash */ retval = niietcm4_load_uflash_page(bank, uflash_dump, 0, 1); if (retval != ERROR_OK) return retval; } else { /* read dump */ uint32_t uflash_dump[USERFLASH_PAGE_SIZE]; retval = niietcm4_dump_uflash_page(bank, uflash_dump, 0, 1); if (retval != ERROR_OK) return retval; /* modify dump */ for (unsigned int i = first; i <= last; i++) { uint32_t reg_num = i/8; uint32_t bit_num = i%8; if (set) uflash_dump[UF_LOCK_ADDR+reg_num] &= ~(1<<bit_num); else uflash_dump[UF_LOCK_ADDR+reg_num] |= (1<<bit_num); } /* erase page 0 info userflash */ retval = niietcm4_uflash_page_erase(bank, 0, 1); if (retval != ERROR_OK) return retval; /* write dump to userflash */ retval = niietcm4_load_uflash_page(bank, uflash_dump, 0, 1); if (retval != ERROR_OK) return retval; } return retval; } /*============================================================================== * FLASH COMMANDS *============================================================================== */ COMMAND_HANDLER(niietcm4_handle_uflash_read_byte_command) { if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct target *target = bank->target; /* skip over flash bank */ CMD_ARGC--; CMD_ARGV++; uint32_t uflash_addr; uint32_t uflash_cmd; uint32_t uflash_data; if (strcmp("info", CMD_ARGV[0]) == 0) uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ_IFB; else if (strcmp("main", CMD_ARGV[0]) == 0) uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ; else return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], uflash_addr); retval = target_write_u32(target, UFMA, uflash_addr); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, UFMC, uflash_cmd); if (retval != ERROR_OK) return retval; /* status check */ retval = niietcm4_uopstatus_check(bank); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, UFMD, &uflash_data); if (retval != ERROR_OK) return retval; command_print(CMD, "Read userflash %s region:\n" "address = 0x%04" PRIx32 ",\n" "value = 0x%02" PRIx32 ".", CMD_ARGV[0], uflash_addr, uflash_data); return retval; } COMMAND_HANDLER(niietcm4_handle_uflash_write_byte_command) { if (CMD_ARGC < 4) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* skip over flash bank */ CMD_ARGC--; CMD_ARGV++; uint32_t uflash_addr; uint32_t uflash_data; int mem_type; if (strcmp("info", CMD_ARGV[0]) == 0) mem_type = 1; else if (strcmp("main", CMD_ARGV[0]) == 0) mem_type = 0; else return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], uflash_addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], uflash_data); int page_num = uflash_addr/USERFLASH_PAGE_SIZE; command_print(CMD, "Write userflash %s region:\n" "address = 0x%04" PRIx32 ",\n" "value = 0x%02" PRIx32 ".\n" "Please wait ... ", CMD_ARGV[0], uflash_addr, uflash_data); /* dump */ uint32_t uflash_dump[USERFLASH_PAGE_SIZE]; niietcm4_dump_uflash_page(bank, uflash_dump, page_num, mem_type); /* modify dump */ uflash_dump[uflash_addr%USERFLASH_PAGE_SIZE] = uflash_data; /* erase page userflash */ niietcm4_uflash_page_erase(bank, page_num, mem_type); /* write dump to userflash */ niietcm4_load_uflash_page(bank, uflash_dump, page_num, mem_type); command_print(CMD, "done!"); return retval; } COMMAND_HANDLER(niietcm4_handle_uflash_full_erase_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } uint32_t uflash_addr = 0; uint32_t uflash_data = 0xFF; uint32_t uflash_cmd = UFMC_MAGIC_KEY | UFMC_FULL_ERASE; retval = target_write_u32(target, UFMA, uflash_addr); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, UFMD, uflash_data); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, UFMC, uflash_cmd); if (retval != ERROR_OK) return retval; /* status check */ retval = niietcm4_uopstatus_check(bank); if (retval != ERROR_OK) return retval; command_print(CMD, "Userflash full erase done!"); return retval; } COMMAND_HANDLER(niietcm4_handle_uflash_erase_command) { if (CMD_ARGC < 4) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* skip over flash bank */ CMD_ARGC--; CMD_ARGV++; unsigned int first, last; int mem_type; if (strcmp("info", CMD_ARGV[0]) == 0) mem_type = 1; else if (strcmp("main", CMD_ARGV[0]) == 0) mem_type = 0; else return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], first); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], last); for (unsigned int i = first; i <= last; i++) { retval = niietcm4_uflash_page_erase(bank, i, mem_type); if (retval != ERROR_OK) return retval; } command_print(CMD, "Erase %s userflash pages %u through %u done!", CMD_ARGV[0], first, last); return retval; } COMMAND_HANDLER(niietcm4_handle_uflash_protect_check_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* skip over flash bank */ CMD_ARGC--; CMD_ARGV++; int mem_type; if (strcmp("info", CMD_ARGV[0]) == 0) mem_type = 1; else if (strcmp("main", CMD_ARGV[0]) == 0) mem_type = 0; else return ERROR_COMMAND_SYNTAX_ERROR; int i, j; uint32_t uflash_addr; uint32_t uflash_cmd; uint32_t uflash_data; /* chose between main userflash and info userflash */ if (mem_type == INFO_MEM_TYPE) { uflash_addr = INFOWORD3_ADDR; uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ_IFB; retval = target_write_u32(target, UFMA, uflash_addr); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, UFMC, uflash_cmd); if (retval != ERROR_OK) return retval; /* status check */ retval = niietcm4_uopstatus_check(bank); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, UFMD, &uflash_data); if (retval != ERROR_OK) return retval; if (uflash_data & INFOWORD3_LOCK_IFB_UF) command_print(CMD, "All sectors of info userflash are not protected!"); else command_print(CMD, "All sectors of info userflash are protected!"); } else { uflash_addr = UF_LOCK_ADDR; uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ_IFB; for (i = 0; i < USERFLASH_PAGE_TOTALNUM/8; i++) { retval = target_write_u32(target, UFMA, uflash_addr); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, UFMC, uflash_cmd); if (retval != ERROR_OK) return retval; /* status check */ retval = niietcm4_uopstatus_check(bank); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, UFMD, &uflash_data); if (retval != ERROR_OK) return retval; for (j = 0; j < 8; j++) { if (uflash_data & 0x1) command_print(CMD, "Userflash sector #%03d: 0x%04x (0x100) is not protected!", i*8+j, (i*8+j)*USERFLASH_PAGE_SIZE); else command_print(CMD, "Userflash sector #%03d: 0x%04x (0x100) is protected!", i*8+j, (i*8+j)*USERFLASH_PAGE_SIZE); uflash_data = uflash_data >> 1; } uflash_addr++; } } return retval; } COMMAND_HANDLER(niietcm4_handle_uflash_protect_command) { if (CMD_ARGC < 5) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* skip over flash bank */ CMD_ARGC--; CMD_ARGV++; int mem_type; if (strcmp("info", CMD_ARGV[0]) == 0) mem_type = 1; else if (strcmp("main", CMD_ARGV[0]) == 0) mem_type = 0; else return ERROR_COMMAND_SYNTAX_ERROR; unsigned int first, last; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], first); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], last); int set; if (strcmp("on", CMD_ARGV[3]) == 0) { command_print(CMD, "Try to enable %s userflash sectors %u through %u protection. Please wait ... ", CMD_ARGV[0], first, last); set = 1; } else if (strcmp("off", CMD_ARGV[3]) == 0) { command_print(CMD, "Try to disable %s userflash sectors %u through %u protection. Please wait ... ", CMD_ARGV[0], first, last); set = 0; } else return ERROR_COMMAND_SYNTAX_ERROR; retval = niietcm4_uflash_protect(bank, mem_type, set, first, last); if (retval != ERROR_OK) return retval; command_print(CMD, "done!"); return retval; } COMMAND_HANDLER(niietcm4_handle_bflash_info_remap_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* skip over flash bank */ CMD_ARGC--; CMD_ARGV++; int set; if (strcmp("on", CMD_ARGV[0]) == 0) { command_print(CMD, "Try to enable bootflash info region remap. Please wait ..."); set = 1; } else if (strcmp("off", CMD_ARGV[0]) == 0) { command_print(CMD, "Try to disable bootflash info region remap. Please wait ..."); set = 0; } else return ERROR_COMMAND_SYNTAX_ERROR; /* dump */ uint32_t uflash_dump[USERFLASH_PAGE_SIZE]; niietcm4_dump_uflash_page(bank, uflash_dump, 0, 1); /* modify dump */ if (set) uflash_dump[INFOWORD0_ADDR] &= ~INFOWORD0_BOOTFROM_IFB; else uflash_dump[INFOWORD0_ADDR] |= INFOWORD0_BOOTFROM_IFB; /* erase page userflash */ niietcm4_uflash_page_erase(bank, 0, 1); /* write dump to userflash */ niietcm4_load_uflash_page(bank, uflash_dump, 0, 1); command_print(CMD, "done!"); return retval; } COMMAND_HANDLER(niietcm4_handle_extmem_cfg_command) { if (CMD_ARGC < 4) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* skip over flash bank */ CMD_ARGC--; CMD_ARGV++; uint32_t port; if (strcmp("gpioa", CMD_ARGV[0]) == 0) port = 8; else if (strcmp("gpiob", CMD_ARGV[0]) == 0) port = 9; else if (strcmp("gpioc", CMD_ARGV[0]) == 0) port = 10; else if (strcmp("gpiod", CMD_ARGV[0]) == 0) port = 11; else if (strcmp("gpioe", CMD_ARGV[0]) == 0) port = 12; else if (strcmp("gpiof", CMD_ARGV[0]) == 0) port = 13; else if (strcmp("gpiog", CMD_ARGV[0]) == 0) port = 14; else if (strcmp("gpioh", CMD_ARGV[0]) == 0) port = 15; else return ERROR_COMMAND_SYNTAX_ERROR; uint32_t pin; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], pin); if (pin > 15) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t func; if (strcmp("func1", CMD_ARGV[2]) == 0) func = 0; else if (strcmp("func3", CMD_ARGV[2]) == 0) func = 3; else return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "Try to configure external memory boot interface:\n" "port = %s\n" "pin = %s\n" "func = %s\n" "Please wait ...", CMD_ARGV[0], CMD_ARGV[1], CMD_ARGV[2]); /* dump */ uint32_t uflash_dump[USERFLASH_PAGE_SIZE]; niietcm4_dump_uflash_page(bank, uflash_dump, 0, 1); /* modify dump */ uflash_dump[INFOWORD0_ADDR] &= ~(3<<INFOWORD0_EXTMEM_SEL_POS); uflash_dump[INFOWORD0_ADDR] |= func<<INFOWORD0_EXTMEM_SEL_POS; uflash_dump[INFOWORD1_ADDR] = (port<<INFOWORD1_PORTNUM_POS) | (pin<<INFOWORD1_PINNUM_POS); /* erase page userflash */ niietcm4_uflash_page_erase(bank, 0, 1); /* write dump to userflash */ niietcm4_load_uflash_page(bank, uflash_dump, 0, 1); command_print(CMD, "done!"); return retval; } COMMAND_HANDLER(niietcm4_handle_extmem_boot_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* skip over flash bank */ CMD_ARGC--; CMD_ARGV++; int set; if (strcmp("on", CMD_ARGV[0]) == 0) { command_print(CMD, "Try to enable boot from external memory. Please wait ..."); set = 1; } else if (strcmp("off", CMD_ARGV[0]) == 0) { command_print(CMD, "Try to disable boot from external memory. Please wait ..."); set = 0; } else return ERROR_COMMAND_SYNTAX_ERROR; /* dump */ uint32_t uflash_dump[USERFLASH_PAGE_SIZE]; niietcm4_dump_uflash_page(bank, uflash_dump, 0, 1); /* modify dump */ if (set) uflash_dump[INFOWORD0_ADDR] &= ~INFOWORD0_EN_GPIO; else uflash_dump[INFOWORD0_ADDR] |= INFOWORD0_EN_GPIO; /* erase page userflash */ niietcm4_uflash_page_erase(bank, 0, 1); /* write dump to userflash */ niietcm4_load_uflash_page(bank, uflash_dump, 0, 1); command_print(CMD, "done!"); return retval; } COMMAND_HANDLER(niietcm4_handle_service_mode_erase_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct target *target = bank->target; command_print(CMD, "Try to perform service mode erase. Please wait ..."); retval = target_write_u32(target, SERVICE_MODE_ERASE_ADDR, 1); if (retval != ERROR_OK) return retval; int timeout = 500; uint32_t status; retval = target_read_u32(target, SERVICE_MODE_ERASE_ADDR, &status); if (retval != ERROR_OK) return retval; while (status != 0x03) { retval = target_read_u32(target, SERVICE_MODE_ERASE_ADDR, &status); if (retval != ERROR_OK) return retval; if (timeout-- <= 0) { LOG_ERROR("Service mode erase timeout"); return ERROR_FLASH_OPERATION_FAILED; } busy_sleep(1); /* can use busy sleep for short times. */ } command_print(CMD, "done! All data erased."); return retval; } COMMAND_HANDLER(niietcm4_handle_driver_info_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; command_print(CMD, "niietcm4 flash driver\n" "version: %d.%d\n" "author: Bogdan Kolbov\n" "mail: kolbov@niiet.ru", FLASH_DRIVER_VER>>16, FLASH_DRIVER_VER&0xFFFF); return retval; } static const struct command_registration niietcm4_exec_command_handlers[] = { { .name = "uflash_read_byte", .handler = niietcm4_handle_uflash_read_byte_command, .mode = COMMAND_EXEC, .usage = "bank_id ('main'|'info') address", .help = "Read byte from main or info userflash region", }, { .name = "uflash_write_byte", .handler = niietcm4_handle_uflash_write_byte_command, .mode = COMMAND_EXEC, .usage = "bank_id ('main'|'info') address value", .help = "Write byte to main or info userflash region", }, { .name = "uflash_full_erase", .handler = niietcm4_handle_uflash_full_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Erase all userflash including info region", }, { .name = "uflash_erase", .handler = niietcm4_handle_uflash_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id ('main'|'info') first_sector_num last_sector_num", .help = "Erase sectors of main or info userflash region, starting at sector first up to and including last.", }, { .name = "uflash_protect_check", .handler = niietcm4_handle_uflash_protect_check_command, .mode = COMMAND_EXEC, .usage = "bank_id ('main'|'info')", .help = "Check sectors protect.", }, { .name = "uflash_protect", .handler = niietcm4_handle_uflash_protect_command, .mode = COMMAND_EXEC, .usage = "bank_id ('main'|'info') first_sector_num last_sector_num ('on'|'off')", .help = "Protect sectors of main or info userflash region, starting at sector first up to and including last.", }, { .name = "bflash_info_remap", .handler = niietcm4_handle_bflash_info_remap_command, .mode = COMMAND_EXEC, .usage = "bank_id ('on'|'off')", .help = "Enable remapping bootflash info region to 0x00000000 (or 0x40000000 if external memory boot used).", }, { .name = "extmem_cfg", .handler = niietcm4_handle_extmem_cfg_command, .mode = COMMAND_EXEC, .usage = "bank_id ('gpioa'|'gpiob'|'gpioc'|'gpiod'|'gpioe'|'gpiof'|'gpiog'|'gpioh') pin_num ('func1'|'func3')", .help = "Configure external memory interface for boot.", }, { .name = "extmem_boot", .handler = niietcm4_handle_extmem_boot_command, .mode = COMMAND_EXEC, .usage = "bank_id ('on'|'off')", .help = "Enable boot from external memory.", }, { .name = "service_mode_erase", .handler = niietcm4_handle_service_mode_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Perform emergency erase of all flash (bootflash and userflash).", }, { .name = "driver_info", .handler = niietcm4_handle_driver_info_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Show information about flash driver.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration niietcm4_command_handlers[] = { { .name = "niietcm4", .mode = COMMAND_ANY, .help = "niietcm4 flash command group", .usage = "", .chain = niietcm4_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /*============================================================================== * FLASH INTERFACE *============================================================================== */ FLASH_BANK_COMMAND_HANDLER(niietcm4_flash_bank_command) { struct niietcm4_flash_bank *niietcm4_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; niietcm4_info = malloc(sizeof(struct niietcm4_flash_bank)); bank->driver_priv = niietcm4_info; /* information will be updated by probing */ niietcm4_info->probed = false; niietcm4_info->chipid = 0; niietcm4_info->chip_name = NULL; niietcm4_info->uflash_width = 0; niietcm4_info->uflash_size = 0; niietcm4_info->uflash_pagetotal = 0; niietcm4_info->uflash_info_size = 0; niietcm4_info->uflash_info_pagetotal = 0; niietcm4_info->bflash_info_remap = false; niietcm4_info->extmem_boot_port = NULL; niietcm4_info->extmem_boot_pin = 0; niietcm4_info->extmem_boot_altfunc = 0; niietcm4_info->extmem_boot = false; return ERROR_OK; } static int niietcm4_protect_check(struct flash_bank *bank) { struct target *target = bank->target; struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv; int retval = ERROR_FLASH_OPERATION_FAILED; int set; uint32_t uflash_addr; uint32_t uflash_cmd; uint32_t uflash_data; /* chose between main bootflash and info bootflash */ if (niietcm4_info->bflash_info_remap) { uflash_addr = INFOWORD2_ADDR; uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ_IFB; retval = target_write_u32(target, UFMA, uflash_addr); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, UFMC, uflash_cmd); if (retval != ERROR_OK) return retval; /* status check */ retval = niietcm4_uopstatus_check(bank); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, UFMD, &uflash_data); if (retval != ERROR_OK) return retval; if (uflash_data & INFOWORD2_LOCK_IFB_BF) set = 0; else set = 1; bank->sectors[0].is_protected = set; } else { uflash_addr = BF_LOCK_ADDR; uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ_IFB; for (unsigned int i = 0; i < bank->num_sectors/8; i++) { retval = target_write_u32(target, UFMA, uflash_addr); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, UFMC, uflash_cmd); if (retval != ERROR_OK) return retval; /* status check */ retval = niietcm4_uopstatus_check(bank); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, UFMD, &uflash_data); if (retval != ERROR_OK) return retval; for (int j = 0; j < 8; j++) { if (uflash_data & 0x1) set = 0; else set = 1; bank->sectors[i*8+j].is_protected = set; uflash_data = uflash_data >> 1; } uflash_addr++; } } return retval; } static int niietcm4_mass_erase(struct flash_bank *bank) { struct target *target = bank->target; int retval; uint32_t flash_cmd; /* start mass erase */ flash_cmd = FMC_MAGIC_KEY | FMC_FULL_ERASE; retval = target_write_u32(target, FMC, flash_cmd); if (retval != ERROR_OK) return retval; /* status check */ retval = niietcm4_opstatus_check(bank); if (retval != ERROR_OK) return retval; return retval; } static int niietcm4_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv; int retval = ERROR_FLASH_OPERATION_FAILED; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first == 0) && (last == (bank->num_sectors - 1))) { retval = niietcm4_mass_erase(bank); return retval; } /* chose between main bootflash and info bootflash */ uint32_t flash_cmd, flash_addr; if (niietcm4_info->bflash_info_remap) flash_cmd = FMC_MAGIC_KEY | FMC_PAGEERASE_IFB; else flash_cmd = FMC_MAGIC_KEY | FMC_PAGE_ERASE; /* erasing pages */ unsigned int page_size = bank->size / bank->num_sectors; for (unsigned int i = first; i <= last; i++) { /* current page addr */ flash_addr = i*page_size; retval = target_write_u32(target, FMA, flash_addr); if (retval != ERROR_OK) return retval; /* start erase */ retval = target_write_u32(target, FMC, flash_cmd); if (retval != ERROR_OK) return retval; /* status check */ retval = niietcm4_opstatus_check(bank); if (retval != ERROR_OK) return retval; } return retval; } static int niietcm4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct target *target = bank->target; struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_INFO("Please wait ..."); /* it`s quite a long process */ /* chose between main bootflash and info bootflash */ if (niietcm4_info->bflash_info_remap) { /* dump */ uint32_t uflash_dump[USERFLASH_PAGE_SIZE]; retval = niietcm4_dump_uflash_page(bank, uflash_dump, 0, 1); if (retval != ERROR_OK) return retval; /* modify dump */ if (set) uflash_dump[INFOWORD2_ADDR] &= ~INFOWORD2_LOCK_IFB_BF; else uflash_dump[INFOWORD2_ADDR] |= INFOWORD2_LOCK_IFB_BF; /* erase page 0 userflash */ retval = niietcm4_uflash_page_erase(bank, 0, 1); if (retval != ERROR_OK) return retval; /* write dump to userflash */ retval = niietcm4_load_uflash_page(bank, uflash_dump, 0, 1); if (retval != ERROR_OK) return retval; } else { /* read dump*/ uint32_t uflash_dump[USERFLASH_PAGE_SIZE]; retval = niietcm4_dump_uflash_page(bank, uflash_dump, 0, 1); if (retval != ERROR_OK) return retval; /* modify dump */ for (unsigned int i = first; i <= last; i++) { uint32_t reg_num = i/8; uint32_t bit_num = i%8; if (set) uflash_dump[BF_LOCK_ADDR+reg_num] &= ~(1<<bit_num); else uflash_dump[BF_LOCK_ADDR+reg_num] |= (1<<bit_num); } /* erase page 0 info userflash */ retval = niietcm4_uflash_page_erase(bank, 0, 1); if (retval != ERROR_OK) return retval; /* write dump to userflash */ retval = niietcm4_load_uflash_page(bank, uflash_dump, 0, 1); if (retval != ERROR_OK) return retval; } return retval; } static int niietcm4_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv; uint32_t buffer_size = 32768 + 8; /* 8 bytes for rp and wp */ struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* see contrib/loaders/flash/k1921vk01t.S for src */ static const uint8_t niietcm4_flash_write_code[] = { 0x14, 0x4f, 0x16, 0x68, 0x00, 0x2e, 0x23, 0xd0, 0x55, 0x68, 0xb5, 0x42, 0xf9, 0xd0, 0x2e, 0x68, 0x7e, 0x60, 0x04, 0x35, 0x2e, 0x68, 0x3e, 0x65, 0x04, 0x35, 0x2e, 0x68, 0x7e, 0x65, 0x04, 0x35, 0x2e, 0x68, 0xbe, 0x65, 0x04, 0x35, 0x3c, 0x60, 0x10, 0x34, 0xb8, 0x60, 0xfe, 0x68, 0x00, 0x2e, 0xfc, 0xd0, 0x02, 0x2e, 0x0a, 0xd0, 0x01, 0x26, 0x7e, 0x61, 0x9d, 0x42, 0x01, 0xd3, 0x15, 0x46, 0x08, 0x35, 0x55, 0x60, 0x01, 0x39, 0x00, 0x29, 0x02, 0xd0, 0xda, 0xe7, 0x00, 0x20, 0x50, 0x60, 0x30, 0x46, 0x00, 0xbe, 0x00, 0xc0, 0x01, 0xa0 }; /* flash write code */ if (target_alloc_working_area(target, sizeof(niietcm4_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(niietcm4_flash_write_code), niietcm4_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; buffer_size &= ~15UL; /* Make sure it's 16 byte aligned */ buffer_size += 8; /* And 8 bytes for WP and RP */ if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* write_cmd base (in), status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (128bit) */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ uint32_t flash_cmd; if (niietcm4_info->bflash_info_remap) flash_cmd = FMC_MAGIC_KEY | FMC_WRITE_IFB; else flash_cmd = FMC_MAGIC_KEY | FMC_WRITE; buf_set_u32(reg_params[0].value, 0, 32, flash_cmd); buf_set_u32(reg_params[1].value, 0, 32, count); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[4].value, 0, 32, address); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; retval = target_run_flash_async_algorithm(target, buffer, count, 16, 0, NULL, 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) LOG_ERROR("flash write failed at address 0x%"PRIx32, buf_get_u32(reg_params[4].value, 0, 32)); target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; } static int niietcm4_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv; uint8_t *new_buffer = NULL; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0xF) { LOG_ERROR("offset 0x%" PRIx32 " breaks required 4-word alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* If there's an odd number of words, the data has to be padded. Duplicate * the buffer and use the normal code path with a single block write since * it's probably cheaper than to special case the last odd write using * discrete accesses. */ int rem = count % 16; if (rem) { new_buffer = malloc(count + 16 - rem); if (!new_buffer) { LOG_ERROR("Odd number of words to write and no memory for padding buffer"); return ERROR_FAIL; } LOG_INFO("Odd number of words to write, padding with 0xFFFFFFFF"); buffer = memcpy(new_buffer, buffer, count); while (rem < 16) { new_buffer[count++] = 0xff; rem++; } } int retval; /* try using block write */ retval = niietcm4_write_block(bank, buffer, offset, count/16); uint32_t flash_addr, flash_cmd, flash_data; if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single halfword accesses */ LOG_WARNING("Can't use block writes, falling back to single memory accesses"); LOG_INFO("Please wait ..."); /* it`s quite a long process */ /* chose between main bootflash and info bootflash */ if (niietcm4_info->bflash_info_remap) flash_cmd = FMC_MAGIC_KEY | FMC_WRITE_IFB; else flash_cmd = FMC_MAGIC_KEY | FMC_WRITE; /* write 16 bytes per try */ for (unsigned int i = 0; i < count; i += 16) { /* current addr */ LOG_INFO("%u byte of %" PRIu32, i, count); flash_addr = offset + i; retval = target_write_u32(target, FMA, flash_addr); if (retval != ERROR_OK) goto free_buffer; /* Prepare data (4 words) */ uint32_t value[4]; memcpy(&value, buffer + i*16, 4*sizeof(uint32_t)); /* place in reg 16 bytes of data */ flash_data = value[0]; retval = target_write_u32(target, FMD1, flash_data); if (retval != ERROR_OK) goto free_buffer; flash_data = value[1]; retval = target_write_u32(target, FMD2, flash_data); if (retval != ERROR_OK) goto free_buffer; flash_data = value[2]; retval = target_write_u32(target, FMD3, flash_data); if (retval != ERROR_OK) goto free_buffer; flash_data = value[3]; retval = target_write_u32(target, FMD4, flash_data); if (retval != ERROR_OK) goto free_buffer; /* write start */ retval = target_write_u32(target, FMC, flash_cmd); if (retval != ERROR_OK) goto free_buffer; /* status check */ retval = niietcm4_opstatus_check(bank); if (retval != ERROR_OK) goto free_buffer; } } free_buffer: free(new_buffer); return retval; } static int niietcm4_probe_k1921vk01t(struct flash_bank *bank) { struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv; struct target *target = bank->target; int retval; niietcm4_info->chip_name = "K1921VK01T"; /* check if we in service mode */ uint32_t service_mode; retval = target_read_u32(target, 0x80017000, &service_mode); if (retval != ERROR_OK) return retval; service_mode = (service_mode>>2) & 0x1; if (!service_mode) { niietcm4_info->uflash_width = 8; niietcm4_info->uflash_size = 0x10000; niietcm4_info->uflash_pagetotal = 256; niietcm4_info->uflash_info_size = 0x200; niietcm4_info->uflash_info_pagetotal = 2; uint32_t uflash_data[2]; uint32_t uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ_IFB; for (int i = 0; i < 2; i++) { retval = target_write_u32(target, UFMA, i); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, UFMC, uflash_cmd); if (retval != ERROR_OK) return retval; /* status check */ retval = niietcm4_uopstatus_check(bank); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, UFMD, &uflash_data[i]); if (retval != ERROR_OK) return retval; } int boot_from_ifb = (uflash_data[0]>>INFOWORD0_BOOTFROM_IFB_POS) & 0x1; int en_gpio = (uflash_data[0]>>INFOWORD0_EN_GPIO_POS) & 0x1; int extmem_sel = (uflash_data[0]>>INFOWORD0_EXTMEM_SEL_POS) & 0x3; int pinnum = (uflash_data[1]>>INFOWORD1_PINNUM_POS) & 0xF; int portnum = (uflash_data[1]>>INFOWORD1_PORTNUM_POS) & 0x7; if (boot_from_ifb) niietcm4_info->bflash_info_remap = false; else niietcm4_info->bflash_info_remap = true; if (extmem_sel == 0x2) niietcm4_info->extmem_boot_altfunc = 3; else niietcm4_info->extmem_boot_altfunc = 1; if (portnum == 0x0) niietcm4_info->extmem_boot_port = "GPIOA"; else if (portnum == 0x1) niietcm4_info->extmem_boot_port = "GPIOB"; else if (portnum == 0x2) niietcm4_info->extmem_boot_port = "GPIOC"; else if (portnum == 0x3) niietcm4_info->extmem_boot_port = "GPIOD"; else if (portnum == 0x4) niietcm4_info->extmem_boot_port = "GPIOE"; else if (portnum == 0x5) niietcm4_info->extmem_boot_port = "GPIOF"; else if (portnum == 0x6) niietcm4_info->extmem_boot_port = "GPIOG"; else if (portnum == 0x7) niietcm4_info->extmem_boot_port = "GPIOH"; else niietcm4_info->extmem_boot_port = "not defined"; if (en_gpio) niietcm4_info->extmem_boot = false; else niietcm4_info->extmem_boot = true; niietcm4_info->extmem_boot_pin = pinnum; /* check state of extmem boot en pin, if "high", extmem remapped to 0x00000000 */ uint32_t extmem_boot_port_data; retval = target_read_u32(target, 0x80010000 + 0x1000*portnum, &extmem_boot_port_data); if (retval != ERROR_OK) return retval; int extmem_boot_pin_data = (extmem_boot_port_data>>pinnum) & 0x1; uint32_t extmem_base; uint32_t bflash_base; if (extmem_boot_pin_data && niietcm4_info->extmem_boot) { extmem_base = 0x00000000; bflash_base = 0x40000000; } else { extmem_base = 0x40000000; bflash_base = 0x00000000; } uint32_t bflash_size = 0x100000; uint32_t bflash_pages = 128; uint32_t bflash_info_size = 0x2000; uint32_t bflash_info_pages = 1; if (niietcm4_info->bflash_info_remap) { bflash_base += 0x2000; bflash_size -= 0x2000; bflash_pages--; bank->size = bflash_info_size; bank->num_sectors = bflash_info_pages; } else { bank->size = bflash_size; bank->num_sectors = bflash_pages; } char info_bootflash_addr_str[64]; if (niietcm4_info->bflash_info_remap) snprintf(info_bootflash_addr_str, sizeof(info_bootflash_addr_str), TARGET_ADDR_FMT " base address", bank->base); else snprintf(info_bootflash_addr_str, sizeof(info_bootflash_addr_str), "not mapped to global address space"); snprintf(niietcm4_info->chip_brief, sizeof(niietcm4_info->chip_brief), "\n" "MEMORY CONFIGURATION\n" "Bootflash :\n" " %" PRIu32 " kB total\n" " %" PRIu32 " pages %" PRIu32 " kB each\n" " 0x%08" PRIx32 " base address\n" "%s" "Info bootflash :\n" " %" PRIu32 " kB total\n" " %" PRIu32 " pages %" PRIu32 " kB each\n" " %s\n" "%s" "Userflash :\n" " %" PRIu32 " kB total\n" " %" PRIu32 " pages %" PRIu32 " B each\n" " %" PRIu32 " bit cells\n" " not mapped to global address space\n" "Info userflash :\n" " %" PRIu32 " B total\n" " %" PRIu32 " pages of %" PRIu32 " B each\n" " %" PRIu32 " bit cells\n" " not mapped to global address space\n" "RAM :\n" " 192 kB total\n" " 0x20000000 base address\n" "External memory :\n" " 8/16 bit address space\n" " 0x%08" PRIx32 " base address\n" "\n" "INFOWORD STATUS\n" "Bootflash info region remap :\n" " %s\n" "External memory boot port :\n" " %s\n" "External memory boot pin :\n" " %" PRIu32 "\n" "External memory interface alternative function :\n" " %" PRIu32 "\n" "Option boot from external memory :\n" " %s\n", bflash_size/1024, bflash_pages, (bflash_size/bflash_pages)/1024, bflash_base, niietcm4_info->bflash_info_remap ? "" : " this flash will be used for debugging, writing and etc\n", bflash_info_size/1024, bflash_info_pages, (bflash_info_size/bflash_info_pages)/1024, info_bootflash_addr_str, niietcm4_info->bflash_info_remap ? " this flash will be used for debugging, writing and etc\n" : "", niietcm4_info->uflash_size/1024, niietcm4_info->uflash_pagetotal, niietcm4_info->uflash_size/niietcm4_info->uflash_pagetotal, niietcm4_info->uflash_width, niietcm4_info->uflash_info_size, niietcm4_info->uflash_info_pagetotal, niietcm4_info->uflash_info_size/niietcm4_info->uflash_info_pagetotal, niietcm4_info->uflash_width, extmem_base, niietcm4_info->bflash_info_remap ? "enable" : "disable", niietcm4_info->extmem_boot_port, niietcm4_info->extmem_boot_pin, niietcm4_info->extmem_boot_altfunc, niietcm4_info->extmem_boot ? "enable" : "disable"); } else { bank->size = 0x100000; bank->num_sectors = 128; sprintf(niietcm4_info->chip_brief, "\n" "H[2] was HIGH while startup. Device entered service mode.\n" "All flashes were locked.\n" "If you want to perform emergency erase (erase all flashes),\n" "please use \"service_mode_erase\" command and reset device.\n" "Do not forget to pull H[2] down while reset for returning to normal operation mode.\n" ); } return retval; } static int niietcm4_probe(struct flash_bank *bank) { struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv; struct target *target = bank->target; free(bank->sectors); bank->sectors = NULL; uint32_t retval; uint32_t chipid; retval = target_read_u32(target, CHIPID_ADDR, &chipid); if (retval != ERROR_OK) { chipid = K1921VK01T_ID; LOG_INFO("unknown chipid, assuming K1921VK01T"); } if (chipid == K1921VK01T_ID) niietcm4_probe_k1921vk01t(bank); int page_total = bank->num_sectors; int page_size = bank->size / page_total; bank->sectors = malloc(sizeof(struct flash_sector) * page_total); for (int i = 0; i < page_total; i++) { bank->sectors[i].offset = i * page_size; bank->sectors[i].size = page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } niietcm4_info->probed = true; return ERROR_OK; } static int niietcm4_auto_probe(struct flash_bank *bank) { struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv; if (niietcm4_info->probed) return ERROR_OK; return niietcm4_probe(bank); } static int get_niietcm4_info(struct flash_bank *bank, struct command_invocation *cmd) { struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv; command_print_sameline(cmd, "\nNIIET Cortex-M4F %s\n%s", niietcm4_info->chip_name, niietcm4_info->chip_brief); return ERROR_OK; } const struct flash_driver niietcm4_flash = { .name = "niietcm4", .usage = "flash bank <name> niietcm4 <base> <size> 0 0 <target#>", .commands = niietcm4_command_handlers, .flash_bank_command = niietcm4_flash_bank_command, .erase = niietcm4_erase, .protect = niietcm4_protect, .write = niietcm4_write, .read = default_flash_read, .probe = niietcm4_probe, .auto_probe = niietcm4_auto_probe, .erase_check = default_flash_blank_check, .protect_check = niietcm4_protect_check, .info = get_niietcm4_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/non_cfi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2009 Michael Schwingen * * michael@schwingen.org * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "cfi.h" #include "non_cfi.h" #define KB 1024 #define MB (1024*1024) #define ERASE_REGION(num, size) (((size/256) << 16) | (num-1)) /* non-CFI compatible flashes */ static const struct non_cfi non_cfi_flashes[] = { { .mfr = CFI_MFR_SST, .id = 0xd4, .pri_id = 0x02, .dev_size = 64*KB, .interface_desc = 0x0, /* x8 only device */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(16, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0xd5, .pri_id = 0x02, .dev_size = 128*KB, .interface_desc = 0x0, /* x8 only device */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(32, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0xd6, .pri_id = 0x02, .dev_size = 256*KB, .interface_desc = 0x0, /* x8 only device */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(64, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0xd7, .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x0, /* x8 only device */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(128, 4*KB) } }, { .mfr = CFI_MFR_AMD, /* Spansion AM29LV040B */ .id = 0x4f, .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x0, /* x8 only device */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(8, 64*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x2780, .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x2, /* x8 or x16 device */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(128, 4*KB) } }, { .mfr = CFI_MFR_ST, .id = 0xd6, /* ST29F400BB */ .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(7, 64*KB) } }, { .mfr = CFI_MFR_ST, .id = 0xd5, /* ST29F400BT */ .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(7, 64*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 16*KB) } }, /* SST 39VF* do not support DQ5 status polling - this currently is only supported by the host algorithm, not by the target code using the work area. Only true for 8-bit and 32-bit wide memories. 16-bit wide memories without DQ5 status polling are supported by the target code. */ { .mfr = CFI_MFR_SST, .id = 0x2782, /* SST39xF160 */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(512, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x2783, /* SST39VF320 */ .pri_id = 0x02, .dev_size = 4*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(1024, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x234b, /* SST39VF1601 */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(512, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x274b, /* SST39WF1601 */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(512, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x234a, /* SST39VF1602 */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(512, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x235b, /* SST39VF3201 */ .pri_id = 0x02, .dev_size = 4*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(1024, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x235a, /* SST39VF3202 */ .pri_id = 0x02, .dev_size = 4*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(1024, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x236d, /* SST39VF6401B */ .pri_id = 0x02, .dev_size = 8*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(2048, 4*KB) } }, { .mfr = CFI_MFR_AMD, .id = 0x22ab, /* AM29F400BB */ .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(7, 64*KB) } }, { .mfr = CFI_MFR_AMD, .id = 0x2223, /* AM29F400BT */ .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(7, 64*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 16*KB) } }, { .mfr = CFI_MFR_FUJITSU, .id = 0x226b, /* AM29SL800DB */ .pri_id = 0x02, .dev_size = 1*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(15, 64*KB) } }, { .mfr = CFI_MFR_FUJITSU, .id = 0x22ea, /* MBM29SL800TE */ .pri_id = 0x02, .dev_size = 1*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(15, 64*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 16*KB) } }, { .mfr = CFI_MFR_FUJITSU, .id = 0xba, /* 29LV400BC */ .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x1, /* x8 or x16 device w/ nBYTE */ .max_buf_write_size = 0x00, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(7, 64*KB) } }, { .mfr = CFI_MFR_AMIC, .id = 0xb31a, /* A29L800A */ .pri_id = 0x02, .dev_size = 1*MB, .interface_desc = 0x2, .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(15, 64*KB) } }, { .mfr = CFI_MFR_MX, .id = 0x225b, /* MX29LV800B */ .pri_id = 0x02, .dev_size = 1*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(15, 64*KB) } }, { .mfr = CFI_MFR_MX, .id = 0x2249, /* MX29LV160AB: 2MB */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(31, 64*KB) } }, { .mfr = CFI_MFR_MX, .id = 0x22C4, /* MX29LV160AT: 2MB */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(31, 64*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 16*KB) } }, { .mfr = CFI_MFR_EON, .id = 0x225b, /* EN29LV800BB */ .pri_id = 0x02, .dev_size = 1*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(15, 64*KB) } }, { .mfr = CFI_MFR_ATMEL, .id = 0x00c0, /* Atmel 49BV1614 */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 3, .erase_region_info = { ERASE_REGION(8, 8*KB), ERASE_REGION(2, 32*KB), ERASE_REGION(30, 64*KB) } }, { .mfr = CFI_MFR_ATMEL, .id = 0xC2, /* Atmel 49BV1614T */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 3, .erase_region_info = { ERASE_REGION(30, 64*KB), ERASE_REGION(2, 32*KB), ERASE_REGION(8, 8*KB) } }, { .mfr = CFI_MFR_AMD, .id = 0x225b, /* S29AL008D */ .pri_id = 0x02, .dev_size = 1*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(15, 64*KB) } }, { .mfr = 0, .id = 0, } }; void cfi_fixup_non_cfi(struct flash_bank *bank) { unsigned int mask; struct cfi_flash_bank *cfi_info = bank->driver_priv; const struct non_cfi *non_cfi = non_cfi_flashes; if (cfi_info->x16_as_x8) mask = 0xFF; else mask = 0xFFFF; for (non_cfi = non_cfi_flashes; non_cfi->mfr; non_cfi++) { if ((cfi_info->manufacturer == non_cfi->mfr) && (cfi_info->device_id == (non_cfi->id & mask))) break; } /* only fixup jedec flashes found in table */ if (!non_cfi->mfr) return; cfi_info->not_cfi = true; /* fill in defaults for non-critical data */ cfi_info->vcc_min = 0x0; cfi_info->vcc_max = 0x0; cfi_info->vpp_min = 0x0; cfi_info->vpp_max = 0x0; /* these are used for timeouts - use vales that should be long enough for normal operation. */ cfi_info->word_write_timeout_typ = 0x0a; cfi_info->buf_write_timeout_typ = 0x0d; cfi_info->block_erase_timeout_typ = 0x0d; cfi_info->chip_erase_timeout_typ = 0x10; cfi_info->word_write_timeout_max = 0x0; cfi_info->buf_write_timeout_max = 0x0; cfi_info->block_erase_timeout_max = 0x0; cfi_info->chip_erase_timeout_max = 0x0; cfi_info->qry[0] = 'Q'; cfi_info->qry[1] = 'R'; cfi_info->qry[2] = 'Y'; cfi_info->pri_id = non_cfi->pri_id; cfi_info->pri_addr = 0x0; cfi_info->alt_id = 0x0; cfi_info->alt_addr = 0x0; cfi_info->alt_ext = NULL; cfi_info->interface_desc = non_cfi->interface_desc; cfi_info->max_buf_write_size = non_cfi->max_buf_write_size; cfi_info->status_poll_mask = non_cfi->status_poll_mask; cfi_info->num_erase_regions = non_cfi->num_erase_regions; size_t erase_region_info_size = sizeof(*cfi_info->erase_region_info) * cfi_info->num_erase_regions; cfi_info->erase_region_info = malloc(erase_region_info_size); memcpy(cfi_info->erase_region_info, non_cfi->erase_region_info, erase_region_info_size); cfi_info->dev_size = non_cfi->dev_size; if (cfi_info->pri_id == 0x2) { struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext)); pri_ext->pri[0] = 'P'; pri_ext->pri[1] = 'R'; pri_ext->pri[2] = 'I'; pri_ext->major_version = '1'; pri_ext->minor_version = '0'; pri_ext->silicon_revision = 0x0; pri_ext->erase_suspend = 0x0; pri_ext->blk_prot = 0x0; pri_ext->tmp_blk_unprotected = 0x0; pri_ext->blk_prot_unprot = 0x0; pri_ext->simultaneous_ops = 0x0; pri_ext->burst_mode = 0x0; pri_ext->page_mode = 0x0; pri_ext->vpp_min = 0x0; pri_ext->vpp_max = 0x0; pri_ext->top_bottom = 0x0; pri_ext->_unlock1 = 0x5555; pri_ext->_unlock2 = 0x2AAA; pri_ext->_reversed_geometry = 0; cfi_info->pri_ext = pri_ext; } else if ((cfi_info->pri_id == 0x1) || (cfi_info->pri_id == 0x3)) { LOG_ERROR("BUG: non-CFI flashes using the Intel commandset are not yet supported"); exit(-1); } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/non_cfi.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_NON_CFI_H #define OPENOCD_FLASH_NOR_NON_CFI_H struct non_cfi { uint16_t mfr; uint16_t id; uint16_t pri_id; uint32_t dev_size; uint16_t interface_desc; uint16_t max_buf_write_size; uint8_t num_erase_regions; uint32_t erase_region_info[6]; uint8_t status_poll_mask; }; void cfi_fixup_non_cfi(struct flash_bank *bank); #endif /* OPENOCD_FLASH_NOR_NON_CFI_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/npcx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2020 by Nuvoton Technology Corporation * Mulin Chao <mlchao@nuvoton.com> * Wealian Liao <WHLIAO@nuvoton.com> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <helper/time_support.h> #include <target/armv7m.h> #include "../../../contrib/loaders/flash/npcx/npcx_flash.h" /* NPCX flash loader */ static const uint8_t npcx_algo[] = { #include "../../../contrib/loaders/flash/npcx/npcx_algo.inc" }; #define NPCX_FLASH_TIMEOUT_MS 8000 #define NPCX_FLASH_BASE_ADDR 0x64000000 /* flash list */ enum npcx_flash_device_index { NPCX_FLASH_256KB = 0, NPCX_FLASH_512KB = 1, NPCX_FLASH_1MB = 2, NPCX_FLASH_UNKNOWN, }; struct npcx_flash_bank { const char *family_name; uint32_t sector_length; bool probed; enum npcx_flash_device_index flash; struct working_area *working_area; struct armv7m_algorithm armv7m_info; const uint8_t *algo_code; uint32_t algo_size; uint32_t algo_working_size; uint32_t buffer_addr; uint32_t params_addr; }; struct npcx_flash_info { char *name; uint32_t id; uint32_t size; }; static const struct npcx_flash_info flash_info[] = { [NPCX_FLASH_256KB] = { .name = "256KB Flash", .id = 0xEF4012, .size = 256 * 1024, }, [NPCX_FLASH_512KB] = { .name = "512KB Flash", .id = 0xEF4013, .size = 512 * 1024, }, [NPCX_FLASH_1MB] = { .name = "1MB Flash", .id = 0xEF4014, .size = 1024 * 1024, }, [NPCX_FLASH_UNKNOWN] = { .name = "Unknown Flash", .size = 0xFFFFFFFF, }, }; static int npcx_init(struct flash_bank *bank) { struct target *target = bank->target; struct npcx_flash_bank *npcx_bank = bank->driver_priv; /* Check for working area to use for flash helper algorithm */ target_free_working_area(target, npcx_bank->working_area); npcx_bank->working_area = NULL; int retval = target_alloc_working_area(target, npcx_bank->algo_working_size, &npcx_bank->working_area); if (retval != ERROR_OK) return retval; /* Confirm the defined working address is the area we need to use */ if (npcx_bank->working_area->address != NPCX_FLASH_LOADER_WORKING_ADDR) { LOG_ERROR("%s: Invalid working address", npcx_bank->family_name); LOG_INFO("Hint: Use '-work-area-phys 0x%" PRIx32 "' in your target configuration", NPCX_FLASH_LOADER_WORKING_ADDR); target_free_working_area(target, npcx_bank->working_area); npcx_bank->working_area = NULL; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* Write flash helper algorithm into target memory */ retval = target_write_buffer(target, NPCX_FLASH_LOADER_PROGRAM_ADDR, npcx_bank->algo_size, npcx_bank->algo_code); if (retval != ERROR_OK) { LOG_ERROR("%s: Failed to load flash helper algorithm", npcx_bank->family_name); target_free_working_area(target, npcx_bank->working_area); npcx_bank->working_area = NULL; return retval; } /* Initialize the ARMv7 specific info to run the algorithm */ npcx_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; npcx_bank->armv7m_info.core_mode = ARM_MODE_THREAD; /* Begin executing the flash helper algorithm */ retval = target_start_algorithm(target, 0, NULL, 0, NULL, NPCX_FLASH_LOADER_PROGRAM_ADDR, 0, &npcx_bank->armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("%s: Failed to start flash helper algorithm", npcx_bank->family_name); target_free_working_area(target, npcx_bank->working_area); npcx_bank->working_area = NULL; return retval; } /* * At this point, the algorithm is running on the target and * ready to receive commands and data to flash the target */ return retval; } static int npcx_quit(struct flash_bank *bank) { struct target *target = bank->target; struct npcx_flash_bank *npcx_bank = bank->driver_priv; /* Regardless of the algo's status, attempt to halt the target */ (void)target_halt(target); /* Now confirm target halted and clean up from flash helper algorithm */ int retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, NPCX_FLASH_TIMEOUT_MS, &npcx_bank->armv7m_info); target_free_working_area(target, npcx_bank->working_area); npcx_bank->working_area = NULL; return retval; } static int npcx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr) { struct target *target = bank->target; struct npcx_flash_bank *npcx_bank = bank->driver_priv; uint32_t status_addr = params_addr + offsetof(struct npcx_flash_params, sync); uint32_t status; int64_t start_ms = timeval_ms(); do { int retval = target_read_u32(target, status_addr, &status); if (retval != ERROR_OK) return retval; keep_alive(); int64_t elapsed_ms = timeval_ms() - start_ms; if (elapsed_ms > NPCX_FLASH_TIMEOUT_MS) break; } while (status == NPCX_FLASH_LOADER_EXECUTE); if (status != NPCX_FLASH_LOADER_WAIT) { LOG_ERROR("%s: Flash operation failed, status=0x%" PRIx32, npcx_bank->family_name, status); return ERROR_FAIL; } return ERROR_OK; } static enum npcx_flash_device_index npcx_get_flash_id(struct flash_bank *bank, uint32_t *flash_id) { struct target *target = bank->target; struct npcx_flash_bank *npcx_bank = bank->driver_priv; struct npcx_flash_params algo_params; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } int retval = npcx_init(bank); if (retval != ERROR_OK) return retval; /* Set up algorithm parameters for get flash ID command */ target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_GET_FLASH_ID); target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT); /* Issue flash helper algorithm parameters for get flash ID */ retval = target_write_buffer(target, npcx_bank->params_addr, sizeof(algo_params), (uint8_t *)&algo_params); if (retval != ERROR_OK) { (void)npcx_quit(bank); return retval; } target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE); retval = target_write_buffer(target, npcx_bank->params_addr, sizeof(algo_params), (uint8_t *)&algo_params); /* If no error, wait for finishing */ if (retval == ERROR_OK) { retval = npcx_wait_algo_done(bank, npcx_bank->params_addr); if (retval == ERROR_OK) target_read_u32(target, NPCX_FLASH_LOADER_BUFFER_ADDR, flash_id); } /* Regardless of errors, try to close down algo */ (void)npcx_quit(bank); return retval; } static int npcx_get_flash(uint32_t flash_id) { for (uint32_t i = 0; i < ARRAY_SIZE(flash_info) - 1; i++) { if (flash_info[i].id == flash_id) return i; } return NPCX_FLASH_UNKNOWN; } static int npcx_probe(struct flash_bank *bank) { struct npcx_flash_bank *npcx_bank = bank->driver_priv; uint32_t sector_length = NPCX_FLASH_ERASE_SIZE; uint32_t flash_id; /* Set up appropriate flash helper algorithm */ npcx_bank->algo_code = npcx_algo; npcx_bank->algo_size = sizeof(npcx_algo); npcx_bank->algo_working_size = NPCX_FLASH_LOADER_PARAMS_SIZE + NPCX_FLASH_LOADER_BUFFER_SIZE + NPCX_FLASH_LOADER_PROGRAM_SIZE; npcx_bank->buffer_addr = NPCX_FLASH_LOADER_BUFFER_ADDR; npcx_bank->params_addr = NPCX_FLASH_LOADER_PARAMS_ADDR; int retval = npcx_get_flash_id(bank, &flash_id); if (retval != ERROR_OK) return retval; npcx_bank->flash = npcx_get_flash(flash_id); unsigned int num_sectors = flash_info[npcx_bank->flash].size / sector_length; bank->sectors = calloc(num_sectors, sizeof(struct flash_sector)); if (!bank->sectors) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } bank->base = NPCX_FLASH_BASE_ADDR; bank->num_sectors = num_sectors; bank->size = num_sectors * sector_length; bank->write_start_alignment = 0; bank->write_end_alignment = 0; npcx_bank->sector_length = sector_length; for (unsigned int i = 0; i < num_sectors; i++) { bank->sectors[i].offset = i * sector_length; bank->sectors[i].size = sector_length; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } /* We've successfully determined the stats on the flash bank */ npcx_bank->probed = true; /* If we fall through to here, then all went well */ return ERROR_OK; } static int npcx_auto_probe(struct flash_bank *bank) { struct npcx_flash_bank *npcx_bank = bank->driver_priv; int retval = ERROR_OK; if (!npcx_bank->probed) retval = npcx_probe(bank); return retval; } FLASH_BANK_COMMAND_HANDLER(npcx_flash_bank_command) { struct npcx_flash_bank *npcx_bank; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; npcx_bank = calloc(1, sizeof(struct npcx_flash_bank)); if (!npcx_bank) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } /* Initialize private flash information */ npcx_bank->family_name = "npcx"; npcx_bank->sector_length = NPCX_FLASH_ERASE_SIZE; /* Finish initialization of bank */ bank->driver_priv = npcx_bank; bank->next = NULL; return ERROR_OK; } static int npcx_chip_erase(struct flash_bank *bank) { struct target *target = bank->target; struct npcx_flash_bank *npcx_bank = bank->driver_priv; struct npcx_flash_params algo_params; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Make sure we've probed the flash to get the device and size */ int retval = npcx_auto_probe(bank); if (retval != ERROR_OK) return retval; retval = npcx_init(bank); if (retval != ERROR_OK) return retval; /* Set up algorithm parameters for chip erase command */ target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_ERASE_ALL); target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT); /* Set algorithm parameters */ retval = target_write_buffer(target, npcx_bank->params_addr, sizeof(algo_params), (uint8_t *)&algo_params); if (retval != ERROR_OK) { (void)npcx_quit(bank); return retval; } /* Issue flash helper algorithm parameters for chip erase */ target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE); retval = target_write_buffer(target, npcx_bank->params_addr, sizeof(algo_params), (uint8_t *)&algo_params); /* If no error, wait for chip erase finish */ if (retval == ERROR_OK) retval = npcx_wait_algo_done(bank, npcx_bank->params_addr); /* Regardless of errors, try to close down algo */ (void)npcx_quit(bank); return retval; } static int npcx_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct npcx_flash_bank *npcx_bank = bank->driver_priv; struct npcx_flash_params algo_params; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first == 0) && (last == (bank->num_sectors - 1))) { /* Request chip erase */ return npcx_chip_erase(bank); } uint32_t address = first * npcx_bank->sector_length; uint32_t length = (last - first + 1) * npcx_bank->sector_length; /* Make sure we've probed the flash to get the device and size */ int retval = npcx_auto_probe(bank); if (retval != ERROR_OK) return retval; retval = npcx_init(bank); if (retval != ERROR_OK) return retval; /* Set up algorithm parameters for erase command */ target_buffer_set_u32(target, (uint8_t *)&algo_params.addr, address); target_buffer_set_u32(target, (uint8_t *)&algo_params.len, length); target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_ERASE_SECTORS); target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT); /* Set algorithm parameters */ retval = target_write_buffer(target, npcx_bank->params_addr, sizeof(algo_params), (uint8_t *)&algo_params); if (retval != ERROR_OK) { (void)npcx_quit(bank); return retval; } /* Issue flash helper algorithm parameters for erase */ target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE); retval = target_write_buffer(target, npcx_bank->params_addr, sizeof(algo_params), (uint8_t *)&algo_params); /* If no error, wait for erase to finish */ if (retval == ERROR_OK) retval = npcx_wait_algo_done(bank, npcx_bank->params_addr); /* Regardless of errors, try to close down algo */ (void)npcx_quit(bank); return retval; } static int npcx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct npcx_flash_bank *npcx_bank = bank->driver_priv; struct npcx_flash_params algo_params; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Make sure we've probed the flash to get the device and size */ int retval = npcx_auto_probe(bank); if (retval != ERROR_OK) return retval; retval = npcx_init(bank); if (retval != ERROR_OK) return retval; /* Initialize algorithm parameters to default values */ target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_PROGRAM); uint32_t address = offset; while (count > 0) { uint32_t size = (count > NPCX_FLASH_LOADER_BUFFER_SIZE) ? NPCX_FLASH_LOADER_BUFFER_SIZE : count; /* Put the data into buffer */ retval = target_write_buffer(target, npcx_bank->buffer_addr, size, buffer); if (retval != ERROR_OK) { LOG_ERROR("Unable to write data to target memory"); break; } /* Update algo parameters for flash write */ target_buffer_set_u32(target, (uint8_t *)&algo_params.addr, address); target_buffer_set_u32(target, (uint8_t *)&algo_params.len, size); target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT); /* Set algorithm parameters */ retval = target_write_buffer(target, npcx_bank->params_addr, sizeof(algo_params), (uint8_t *)&algo_params); if (retval != ERROR_OK) break; /* Issue flash helper algorithm parameters for flash write */ target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE); retval = target_write_buffer(target, npcx_bank->params_addr, sizeof(algo_params), (uint8_t *)&algo_params); if (retval != ERROR_OK) break; /* Wait for flash write finish */ retval = npcx_wait_algo_done(bank, npcx_bank->params_addr); if (retval != ERROR_OK) break; count -= size; buffer += size; address += size; } /* Regardless of errors, try to close down algo */ (void)npcx_quit(bank); return retval; } static int npcx_info(struct flash_bank *bank, struct command_invocation *cmd) { struct npcx_flash_bank *npcx_bank = bank->driver_priv; command_print_sameline(cmd, "%s flash: %s\n", npcx_bank->family_name, flash_info[npcx_bank->flash].name); return ERROR_OK; } const struct flash_driver npcx_flash = { .name = "npcx", .flash_bank_command = npcx_flash_bank_command, .erase = npcx_erase, .write = npcx_write, .read = default_flash_read, .probe = npcx_probe, .auto_probe = npcx_auto_probe, .erase_check = default_flash_blank_check, .info = npcx_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/nrf5.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013 Synapse Product Development * * Andrey Smirnov <andrew.smironv@gmail.com> * * Angus Gratton <gus@projectgus.com> * * Erdem U. Altunyurt <spamjunkeater@gmail.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> #include <helper/types.h> #include <helper/time_support.h> /* Both those values are constant across the current spectrum ofr nRF5 devices */ #define WATCHDOG_REFRESH_REGISTER 0x40010600 #define WATCHDOG_REFRESH_VALUE 0x6e524635 enum { NRF5_FLASH_BASE = 0x00000000, }; enum nrf5_ficr_registers { NRF5_FICR_BASE = 0x10000000, /* Factory Information Configuration Registers */ #define NRF5_FICR_REG(offset) (NRF5_FICR_BASE + offset) NRF5_FICR_CODEPAGESIZE = NRF5_FICR_REG(0x010), NRF5_FICR_CODESIZE = NRF5_FICR_REG(0x014), NRF51_FICR_CLENR0 = NRF5_FICR_REG(0x028), NRF51_FICR_PPFC = NRF5_FICR_REG(0x02C), NRF51_FICR_NUMRAMBLOCK = NRF5_FICR_REG(0x034), NRF51_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG(0x038), NRF51_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C), NRF51_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040), NRF51_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044), NRF5_FICR_CONFIGID = NRF5_FICR_REG(0x05C), NRF5_FICR_DEVICEID0 = NRF5_FICR_REG(0x060), NRF5_FICR_DEVICEID1 = NRF5_FICR_REG(0x064), NRF5_FICR_ER0 = NRF5_FICR_REG(0x080), NRF5_FICR_ER1 = NRF5_FICR_REG(0x084), NRF5_FICR_ER2 = NRF5_FICR_REG(0x088), NRF5_FICR_ER3 = NRF5_FICR_REG(0x08C), NRF5_FICR_IR0 = NRF5_FICR_REG(0x090), NRF5_FICR_IR1 = NRF5_FICR_REG(0x094), NRF5_FICR_IR2 = NRF5_FICR_REG(0x098), NRF5_FICR_IR3 = NRF5_FICR_REG(0x09C), NRF5_FICR_DEVICEADDRTYPE = NRF5_FICR_REG(0x0A0), NRF5_FICR_DEVICEADDR0 = NRF5_FICR_REG(0x0A4), NRF5_FICR_DEVICEADDR1 = NRF5_FICR_REG(0x0A8), NRF51_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC), NRF51_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0), NRF51_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4), NRF51_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8), NRF51_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC), NRF51_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0), NRF51_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC), NRF51_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0), NRF51_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4), NRF51_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8), NRF51_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC), /* Following registers are available on nRF52 and on nRF51 since rev 3 */ NRF5_FICR_INFO_PART = NRF5_FICR_REG(0x100), NRF5_FICR_INFO_VARIANT = NRF5_FICR_REG(0x104), NRF5_FICR_INFO_PACKAGE = NRF5_FICR_REG(0x108), NRF5_FICR_INFO_RAM = NRF5_FICR_REG(0x10C), NRF5_FICR_INFO_FLASH = NRF5_FICR_REG(0x110), }; enum nrf5_uicr_registers { NRF5_UICR_BASE = 0x10001000, /* User Information * Configuration Registers */ #define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset) NRF51_UICR_CLENR0 = NRF5_UICR_REG(0x000), NRF51_UICR_RBPCONF = NRF5_UICR_REG(0x004), NRF51_UICR_XTALFREQ = NRF5_UICR_REG(0x008), NRF51_UICR_FWID = NRF5_UICR_REG(0x010), }; enum nrf5_nvmc_registers { NRF5_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory * Controller Registers */ #define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + offset) NRF5_NVMC_READY = NRF5_NVMC_REG(0x400), NRF5_NVMC_CONFIG = NRF5_NVMC_REG(0x504), NRF5_NVMC_ERASEPAGE = NRF5_NVMC_REG(0x508), NRF5_NVMC_ERASEALL = NRF5_NVMC_REG(0x50C), NRF5_NVMC_ERASEUICR = NRF5_NVMC_REG(0x514), NRF5_BPROT_BASE = 0x40000000, }; enum nrf5_nvmc_config_bits { NRF5_NVMC_CONFIG_REN = 0x00, NRF5_NVMC_CONFIG_WEN = 0x01, NRF5_NVMC_CONFIG_EEN = 0x02, }; struct nrf52_ficr_info { uint32_t part; uint32_t variant; uint32_t package; uint32_t ram; uint32_t flash; }; enum nrf5_features { NRF5_FEATURE_SERIES_51 = 1 << 0, NRF5_FEATURE_SERIES_52 = 1 << 1, NRF5_FEATURE_BPROT = 1 << 2, NRF5_FEATURE_ACL_PROT = 1 << 3, }; struct nrf5_device_spec { uint16_t hwid; const char *part; const char *variant; const char *build_code; unsigned int flash_size_kb; enum nrf5_features features; }; struct nrf5_info { unsigned int refcount; struct nrf5_bank { struct nrf5_info *chip; bool probed; } bank[2]; struct target *target; /* chip identification stored in nrf5_probe() for use in nrf5_info() */ bool ficr_info_valid; struct nrf52_ficr_info ficr_info; const struct nrf5_device_spec *spec; uint16_t hwid; enum nrf5_features features; unsigned int flash_size_kb; unsigned int ram_size_kb; }; #define NRF51_DEVICE_DEF(id, pt, var, bcode, fsize) \ { \ .hwid = (id), \ .part = pt, \ .variant = var, \ .build_code = bcode, \ .flash_size_kb = (fsize), \ .features = NRF5_FEATURE_SERIES_51, \ } #define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize, features) \ { \ .hwid = (id), \ .part = pt, \ .variant = var, \ .build_code = bcode, \ .flash_size_kb = (fsize), \ .features = features, \ } /* The known devices table below is derived from the "nRF5x series * compatibility matrix" documents, which can be found in the "DocLib" of * nordic: * * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51422_ic_revision_overview * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51822_ic_revision_overview * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51824_ic_revision_overview * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52810/latest/COMP/nrf52810/nRF52810_ic_revision_overview * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52832/latest/COMP/nrf52832/ic_revision_overview * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52840/latest/COMP/nrf52840/nRF52840_ic_revision_overview * * Up to date with Matrix v2.0, plus some additional HWIDs. * * The additional HWIDs apply where the build code in the matrix is * shown as Gx0, Bx0, etc. In these cases the HWID in the matrix is * for x==0, x!=0 means different (unspecified) HWIDs. */ static const struct nrf5_device_spec nrf5_known_devices_table[] = { /* nRF51822 Devices (IC rev 1). */ NRF51_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256), NRF51_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128), NRF51_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128), NRF51_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256), NRF51_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256), /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards with built-in jlink seem to use engineering samples not listed in the nRF51 Series Compatibility Matrix V1.0. */ NRF51_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), /* nRF51822 Devices (IC rev 2). */ NRF51_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256), NRF51_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256), NRF51_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256), NRF51_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256), NRF51_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256), NRF51_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128), NRF51_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256), NRF51_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256), NRF51_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256), /* nRF51822 Devices (IC rev 3). */ NRF51_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256), NRF51_DEVICE_DEF(0x00D1, "51822", "QFAA", "H2", 256), NRF51_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128), NRF51_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256), NRF51_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256), NRF51_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128), NRF51_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256), NRF51_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256), NRF51_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256), /* nRF51422 Devices (IC rev 1). */ NRF51_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), NRF51_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256), NRF51_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256), /* nRF51422 Devices (IC rev 2). */ NRF51_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256), NRF51_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256), NRF51_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128), NRF51_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256), /* nRF51422 Devices (IC rev 3). */ NRF51_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256), NRF51_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128), NRF51_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256), NRF51_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256), NRF51_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128), NRF51_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), NRF51_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), /* The driver fully autodetects nRF52 series devices by FICR INFO, * no need for nRF52xxx HWIDs in this table */ #if 0 /* nRF52810 Devices */ NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), /* nRF52832 Devices */ NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), /* nRF52840 Devices */ NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_ACL_PROT), #endif }; struct nrf5_device_package { uint32_t package; const char *code; }; /* Newer devices have FICR INFO.PACKAGE. * This table converts its value to two character code */ static const struct nrf5_device_package nrf5_packages_table[] = { { 0x2000, "QF" }, { 0x2001, "CH" }, { 0x2002, "CI" }, { 0x2005, "CK" }, }; const struct flash_driver nrf5_flash, nrf51_flash; static bool nrf5_bank_is_probed(const struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; assert(nbank); return nbank->probed; } static int nrf5_probe(struct flash_bank *bank); static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_info **chip) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } struct nrf5_bank *nbank = bank->driver_priv; *chip = nbank->chip; if (nrf5_bank_is_probed(bank)) return ERROR_OK; return nrf5_probe(bank); } static int nrf5_wait_for_nvmc(struct nrf5_info *chip) { uint32_t ready; int res; int timeout_ms = 340; int64_t ts_start = timeval_ms(); do { res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready); if (res != ERROR_OK) { LOG_ERROR("Error waiting NVMC_READY: generic flash write/erase error (check protection etc...)"); return res; } if (ready == 0x00000001) return ERROR_OK; keep_alive(); } while ((timeval_ms()-ts_start) < timeout_ms); LOG_DEBUG("Timed out waiting for NVMC_READY"); return ERROR_FLASH_BUSY; } static int nrf5_nvmc_erase_enable(struct nrf5_info *chip) { int res; res = target_write_u32(chip->target, NRF5_NVMC_CONFIG, NRF5_NVMC_CONFIG_EEN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable erase operation"); return res; } /* According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) LOG_ERROR("Erase enable did not complete"); return res; } static int nrf5_nvmc_write_enable(struct nrf5_info *chip) { int res; res = target_write_u32(chip->target, NRF5_NVMC_CONFIG, NRF5_NVMC_CONFIG_WEN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable write operation"); return res; } /* According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) LOG_ERROR("Write enable did not complete"); return res; } static int nrf5_nvmc_read_only(struct nrf5_info *chip) { int res; res = target_write_u32(chip->target, NRF5_NVMC_CONFIG, NRF5_NVMC_CONFIG_REN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable read-only operation"); return res; } /* According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) LOG_ERROR("Read only enable did not complete"); return res; } static int nrf5_nvmc_generic_erase(struct nrf5_info *chip, uint32_t erase_register, uint32_t erase_value) { int res; res = nrf5_nvmc_erase_enable(chip); if (res != ERROR_OK) goto error; res = target_write_u32(chip->target, erase_register, erase_value); if (res != ERROR_OK) goto set_read_only; res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) goto set_read_only; return nrf5_nvmc_read_only(chip); set_read_only: nrf5_nvmc_read_only(chip); error: LOG_ERROR("Failed to erase reg: 0x%08"PRIx32" val: 0x%08"PRIx32, erase_register, erase_value); return ERROR_FAIL; } static int nrf5_protect_check_clenr0(struct flash_bank *bank) { int res; uint32_t clenr0; struct nrf5_bank *nbank = bank->driver_priv; struct nrf5_info *chip = nbank->chip; assert(chip); res = target_read_u32(chip->target, NRF51_FICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[FICR]"); return res; } if (clenr0 == 0xFFFFFFFF) { res = target_read_u32(chip->target, NRF51_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[UICR]"); return res; } } for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = clenr0 != 0xFFFFFFFF && bank->sectors[i].offset < clenr0; return ERROR_OK; } static int nrf5_protect_check_bprot(struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; struct nrf5_info *chip = nbank->chip; assert(chip); static uint32_t nrf5_bprot_offsets[4] = { 0x600, 0x604, 0x610, 0x614 }; uint32_t bprot_reg = 0; int res; for (unsigned int i = 0; i < bank->num_sectors; i++) { unsigned int bit = i % 32; if (bit == 0) { unsigned int n_reg = i / 32; if (n_reg >= ARRAY_SIZE(nrf5_bprot_offsets)) break; res = target_read_u32(chip->target, NRF5_BPROT_BASE + nrf5_bprot_offsets[n_reg], &bprot_reg); if (res != ERROR_OK) return res; } bank->sectors[i].is_protected = (bprot_reg & (1 << bit)) ? 1 : 0; } return ERROR_OK; } static int nrf5_protect_check(struct flash_bank *bank) { /* UICR cannot be write protected so just return early */ if (bank->base == NRF5_UICR_BASE) return ERROR_OK; struct nrf5_bank *nbank = bank->driver_priv; struct nrf5_info *chip = nbank->chip; assert(chip); if (chip->features & NRF5_FEATURE_BPROT) return nrf5_protect_check_bprot(bank); if (chip->features & NRF5_FEATURE_SERIES_51) return nrf5_protect_check_clenr0(bank); LOG_WARNING("Flash protection of this nRF device is not supported"); return ERROR_FLASH_OPER_UNSUPPORTED; } static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int res; uint32_t clenr0, ppfc; struct nrf5_bank *nbank = bank->driver_priv; struct nrf5_info *chip = nbank->chip; if (first != 0) { LOG_ERROR("Code region 0 must start at the beginning of the bank"); return ERROR_FAIL; } res = target_read_u32(chip->target, NRF51_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); return res; } if ((ppfc & 0xFF) == 0x00) { LOG_ERROR("Code region 0 size was pre-programmed at the factory, can't change flash protection settings"); return ERROR_FAIL; } res = target_read_u32(chip->target, NRF51_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size from UICR"); return res; } if (!set || clenr0 != 0xFFFFFFFF) { LOG_ERROR("You need to perform chip erase before changing the protection settings"); return ERROR_FAIL; } res = nrf5_nvmc_write_enable(chip); if (res != ERROR_OK) goto error; clenr0 = bank->sectors[last].offset + bank->sectors[last].size; res = target_write_u32(chip->target, NRF51_UICR_CLENR0, clenr0); int res2 = nrf5_wait_for_nvmc(chip); if (res == ERROR_OK) res = res2; if (res == ERROR_OK) LOG_INFO("A reset or power cycle is required for the new protection settings to take effect."); else LOG_ERROR("Couldn't write code region 0 size to UICR"); error: nrf5_nvmc_read_only(chip); return res; } static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int res; struct nrf5_info *chip; /* UICR cannot be write protected so just bail out early */ if (bank->base == NRF5_UICR_BASE) { LOG_ERROR("UICR page does not support protection"); return ERROR_FLASH_OPER_UNSUPPORTED; } res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; if (chip->features & NRF5_FEATURE_SERIES_51) return nrf5_protect_clenr0(bank, set, first, last); LOG_ERROR("Flash protection setting is not supported on this nRF5 device"); return ERROR_FLASH_OPER_UNSUPPORTED; } static bool nrf5_info_variant_to_str(uint32_t variant, char *bf) { uint8_t b[4]; h_u32_to_be(b, variant); if (isalnum(b[0]) && isalnum(b[1]) && isalnum(b[2]) && isalnum(b[3])) { memcpy(bf, b, 4); bf[4] = 0; return true; } strcpy(bf, "xxxx"); return false; } static const char *nrf5_decode_info_package(uint32_t package) { for (size_t i = 0; i < ARRAY_SIZE(nrf5_packages_table); i++) { if (nrf5_packages_table[i].package == package) return nrf5_packages_table[i].code; } return "xx"; } static int get_nrf5_chip_type_str(const struct nrf5_info *chip, char *buf, unsigned int buf_size) { int res; if (chip->spec) { res = snprintf(buf, buf_size, "nRF%s-%s(build code: %s)", chip->spec->part, chip->spec->variant, chip->spec->build_code); } else if (chip->ficr_info_valid) { char variant[5]; nrf5_info_variant_to_str(chip->ficr_info.variant, variant); res = snprintf(buf, buf_size, "nRF%" PRIx32 "-%s%.2s(build code: %s)", chip->ficr_info.part, nrf5_decode_info_package(chip->ficr_info.package), variant, &variant[2]); } else { res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%04" PRIx16 ")", chip->hwid); } /* safety: */ if (res <= 0 || (unsigned int)res >= buf_size) { LOG_ERROR("BUG: buffer problem in %s", __func__); return ERROR_FAIL; } return ERROR_OK; } static int nrf5_info(struct flash_bank *bank, struct command_invocation *cmd) { struct nrf5_bank *nbank = bank->driver_priv; struct nrf5_info *chip = nbank->chip; char chip_type_str[256]; if (get_nrf5_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) return ERROR_FAIL; command_print_sameline(cmd, "%s %ukB Flash, %ukB RAM", chip_type_str, chip->flash_size_kb, chip->ram_size_kb); return ERROR_OK; } static int nrf5_read_ficr_info(struct nrf5_info *chip) { int res; struct target *target = chip->target; chip->ficr_info_valid = false; res = target_read_u32(target, NRF5_FICR_INFO_PART, &chip->ficr_info.part); if (res != ERROR_OK) { LOG_DEBUG("Couldn't read FICR INFO.PART register"); return res; } uint32_t series = chip->ficr_info.part & 0xfffff000; switch (series) { case 0x51000: chip->features = NRF5_FEATURE_SERIES_51; break; case 0x52000: chip->features = NRF5_FEATURE_SERIES_52; switch (chip->ficr_info.part) { case 0x52810: case 0x52832: chip->features |= NRF5_FEATURE_BPROT; break; case 0x52840: chip->features |= NRF5_FEATURE_ACL_PROT; break; } break; default: LOG_DEBUG("FICR INFO likely not implemented. Invalid PART value 0x%08" PRIx32, chip->ficr_info.part); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* Now we know the device has FICR INFO filled by something relevant: * Although it is not documented, the tested nRF51 rev 3 devices * have FICR INFO.PART, RAM and FLASH of the same format as nRF52. * VARIANT and PACKAGE coding is unknown for a nRF51 device. * nRF52 devices have FICR INFO documented and always filled. */ res = target_read_u32(target, NRF5_FICR_INFO_VARIANT, &chip->ficr_info.variant); if (res != ERROR_OK) return res; res = target_read_u32(target, NRF5_FICR_INFO_PACKAGE, &chip->ficr_info.package); if (res != ERROR_OK) return res; res = target_read_u32(target, NRF5_FICR_INFO_RAM, &chip->ficr_info.ram); if (res != ERROR_OK) return res; res = target_read_u32(target, NRF5_FICR_INFO_FLASH, &chip->ficr_info.flash); if (res != ERROR_OK) return res; chip->ficr_info_valid = true; return ERROR_OK; } static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size) { int res; *ram_size = 0; uint32_t numramblock; res = target_read_u32(target, NRF51_FICR_NUMRAMBLOCK, &numramblock); if (res != ERROR_OK) { LOG_DEBUG("Couldn't read FICR NUMRAMBLOCK register"); return res; } if (numramblock < 1 || numramblock > 4) { LOG_DEBUG("FICR NUMRAMBLOCK strange value %" PRIx32, numramblock); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } for (unsigned int i = 0; i < numramblock; i++) { uint32_t sizeramblock; res = target_read_u32(target, NRF51_FICR_SIZERAMBLOCK0 + sizeof(uint32_t)*i, &sizeramblock); if (res != ERROR_OK) { LOG_DEBUG("Couldn't read FICR NUMRAMBLOCK register"); return res; } if (sizeramblock < 1024 || sizeramblock > 65536) LOG_DEBUG("FICR SIZERAMBLOCK strange value %" PRIx32, sizeramblock); else *ram_size += sizeramblock; } return res; } static int nrf5_probe(struct flash_bank *bank) { int res; struct nrf5_bank *nbank = bank->driver_priv; struct nrf5_info *chip = nbank->chip; struct target *target = chip->target; uint32_t configid; res = target_read_u32(target, NRF5_FICR_CONFIGID, &configid); if (res != ERROR_OK) { LOG_ERROR("Couldn't read CONFIGID register"); return res; } /* HWID is stored in the lower two bytes of the CONFIGID register */ chip->hwid = configid & 0xFFFF; /* guess a nRF51 series if the device has no FICR INFO and we don't know HWID */ chip->features = NRF5_FEATURE_SERIES_51; /* Don't bail out on error for the case that some old engineering * sample has FICR INFO registers unreadable. We can proceed anyway. */ (void)nrf5_read_ficr_info(chip); chip->spec = NULL; for (size_t i = 0; i < ARRAY_SIZE(nrf5_known_devices_table); i++) { if (chip->hwid == nrf5_known_devices_table[i].hwid) { chip->spec = &nrf5_known_devices_table[i]; chip->features = chip->spec->features; break; } } if (chip->spec && chip->ficr_info_valid) { /* check if HWID table gives the same part as FICR INFO */ if (chip->ficr_info.part != strtoul(chip->spec->part, NULL, 16)) LOG_WARNING("HWID 0x%04" PRIx32 " mismatch: FICR INFO.PART %" PRIx32, chip->hwid, chip->ficr_info.part); } if (chip->ficr_info_valid) { chip->ram_size_kb = chip->ficr_info.ram; } else { uint32_t ram_size; nrf5_get_ram_size(target, &ram_size); chip->ram_size_kb = ram_size / 1024; } /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */ uint32_t flash_page_size; res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE, &flash_page_size); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code page size"); return res; } /* Note the register name is misleading, * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */ uint32_t num_sectors; res = target_read_u32(chip->target, NRF5_FICR_CODESIZE, &num_sectors); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code memory size"); return res; } chip->flash_size_kb = num_sectors * flash_page_size / 1024; if (!chip->bank[0].probed && !chip->bank[1].probed) { char chip_type_str[256]; if (get_nrf5_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) return ERROR_FAIL; const bool device_is_unknown = (!chip->spec && !chip->ficr_info_valid); LOG_INFO("%s%s %ukB Flash, %ukB RAM", device_is_unknown ? "Unknown device: " : "", chip_type_str, chip->flash_size_kb, chip->ram_size_kb); } free(bank->sectors); if (bank->base == NRF5_FLASH_BASE) { /* Sanity check */ if (chip->spec && chip->flash_size_kb != chip->spec->flash_size_kb) LOG_WARNING("Chip's reported Flash capacity does not match expected one"); if (chip->ficr_info_valid && chip->flash_size_kb != chip->ficr_info.flash) LOG_WARNING("Chip's reported Flash capacity does not match FICR INFO.FLASH"); bank->num_sectors = num_sectors; bank->size = num_sectors * flash_page_size; bank->sectors = alloc_block_array(0, flash_page_size, num_sectors); if (!bank->sectors) return ERROR_FAIL; chip->bank[0].probed = true; } else { bank->num_sectors = 1; bank->size = flash_page_size; bank->sectors = alloc_block_array(0, flash_page_size, num_sectors); if (!bank->sectors) return ERROR_FAIL; bank->sectors[0].is_protected = 0; chip->bank[1].probed = true; } return ERROR_OK; } static int nrf5_auto_probe(struct flash_bank *bank) { if (nrf5_bank_is_probed(bank)) return ERROR_OK; return nrf5_probe(bank); } static int nrf5_erase_all(struct nrf5_info *chip) { LOG_DEBUG("Erasing all non-volatile memory"); return nrf5_nvmc_generic_erase(chip, NRF5_NVMC_ERASEALL, 0x00000001); } static int nrf5_erase_page(struct flash_bank *bank, struct nrf5_info *chip, struct flash_sector *sector) { int res; LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset); if (bank->base == NRF5_UICR_BASE) { if (chip->features & NRF5_FEATURE_SERIES_51) { uint32_t ppfc; res = target_read_u32(chip->target, NRF51_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); return res; } if ((ppfc & 0xFF) == 0xFF) { /* We can't erase the UICR. Double-check to see if it's already erased before complaining. */ default_flash_blank_check(bank); if (sector->is_erased == 1) return ERROR_OK; LOG_ERROR("The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region"); return ERROR_FAIL; } } res = nrf5_nvmc_generic_erase(chip, NRF5_NVMC_ERASEUICR, 0x00000001); } else { res = nrf5_nvmc_generic_erase(chip, NRF5_NVMC_ERASEPAGE, sector->offset); } return res; } /* Start a low level flash write for the specified region */ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const uint8_t *buffer, uint32_t bytes) { struct target *target = chip->target; uint32_t buffer_size = 8192; struct working_area *write_algorithm; struct working_area *source; struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; static const uint8_t nrf5_flash_write_code[] = { #include "../../../contrib/loaders/flash/nrf5/nrf5.inc" }; LOG_DEBUG("Writing buffer to flash address=0x%"PRIx32" bytes=0x%"PRIx32, address, bytes); assert(bytes % 4 == 0); /* allocate working area with flash programming code */ if (target_alloc_working_area(target, sizeof(nrf5_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, falling back to slow memory writes"); for (; bytes > 0; bytes -= 4) { retval = target_write_memory(target, address, 4, 1, buffer); if (retval != ERROR_OK) return retval; retval = nrf5_wait_for_nvmc(chip); if (retval != ERROR_OK) return retval; address += 4; buffer += 4; } return ERROR_OK; } retval = target_write_buffer(target, write_algorithm->address, sizeof(nrf5_flash_write_code), nrf5_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */ if (buffer_size <= 256) { /* free working area, write algorithm already allocated */ target_free_working_area(target, write_algorithm); LOG_WARNING("No large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* byte count */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer start */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT); /* target address */ init_reg_param(®_params[4], "r6", 32, PARAM_OUT); /* watchdog refresh value */ init_reg_param(®_params[5], "r7", 32, PARAM_OUT); /* watchdog refresh register address */ buf_set_u32(reg_params[0].value, 0, 32, bytes); buf_set_u32(reg_params[1].value, 0, 32, source->address); buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[3].value, 0, 32, address); buf_set_u32(reg_params[4].value, 0, 32, WATCHDOG_REFRESH_VALUE); buf_set_u32(reg_params[5].value, 0, 32, WATCHDOG_REFRESH_REGISTER); retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4, 0, NULL, ARRAY_SIZE(reg_params), reg_params, source->address, source->size, write_algorithm->address, write_algorithm->address + sizeof(nrf5_flash_write_code) - 2, &armv7m_info); target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); return retval; } static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct nrf5_info *chip; int res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; assert(offset % 4 == 0); assert(count % 4 == 0); /* UICR CLENR0 based protection used on nRF51 is somewhat clumsy: * RM reads: Code running from code region 1 will not be able to write * to code region 0. * Unfortunately the flash loader running from RAM can write to both * code regions without any hint the protection is violated. * * Update protection state and check if any flash sector to be written * is protected. */ if (chip->features & NRF5_FEATURE_SERIES_51) { res = nrf5_protect_check_clenr0(bank); if (res != ERROR_OK) return res; for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { struct flash_sector *bs = &bank->sectors[sector]; /* Start offset in or before this sector? */ /* End offset in or behind this sector? */ if ((offset < (bs->offset + bs->size)) && ((offset + count - 1) >= bs->offset) && bs->is_protected == 1) { LOG_ERROR("Write refused, sector %d is protected", sector); return ERROR_FLASH_PROTECTED; } } } res = nrf5_nvmc_write_enable(chip); if (res != ERROR_OK) goto error; res = nrf5_ll_flash_write(chip, bank->base + offset, buffer, count); if (res != ERROR_OK) goto error; return nrf5_nvmc_read_only(chip); error: nrf5_nvmc_read_only(chip); LOG_ERROR("Failed to write to nrf5 flash"); return res; } static int nrf5_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int res; struct nrf5_info *chip; res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; /* UICR CLENR0 based protection used on nRF51 prevents erase * absolutely silently. NVMC has no flag to indicate the protection * was violated. * * Update protection state and check if any flash sector to be erased * is protected. */ if (chip->features & NRF5_FEATURE_SERIES_51) { res = nrf5_protect_check_clenr0(bank); if (res != ERROR_OK) return res; } /* For each sector to be erased */ for (unsigned int s = first; s <= last && res == ERROR_OK; s++) { if (chip->features & NRF5_FEATURE_SERIES_51 && bank->sectors[s].is_protected == 1) { LOG_ERROR("Flash sector %d is protected", s); return ERROR_FLASH_PROTECTED; } res = nrf5_erase_page(bank, chip, &bank->sectors[s]); if (res != ERROR_OK) { LOG_ERROR("Error erasing sector %d", s); return res; } } return ERROR_OK; } static void nrf5_free_driver_priv(struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; struct nrf5_info *chip = nbank->chip; if (!chip) return; chip->refcount--; if (chip->refcount == 0) { free(chip); bank->driver_priv = NULL; } } static struct nrf5_info *nrf5_get_chip(struct target *target) { struct flash_bank *bank_iter; /* iterate over nrf5 banks of same target */ for (bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) { if (bank_iter->driver != &nrf5_flash && bank_iter->driver != &nrf51_flash) continue; if (bank_iter->target != target) continue; struct nrf5_bank *nbank = bank_iter->driver_priv; if (!nbank) continue; if (nbank->chip) return nbank->chip; } return NULL; } FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) { struct nrf5_info *chip; struct nrf5_bank *nbank = NULL; switch (bank->base) { case NRF5_FLASH_BASE: case NRF5_UICR_BASE: break; default: LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base); return ERROR_FAIL; } chip = nrf5_get_chip(bank->target); if (!chip) { /* Create a new chip */ chip = calloc(1, sizeof(*chip)); if (!chip) return ERROR_FAIL; chip->target = bank->target; } switch (bank->base) { case NRF5_FLASH_BASE: nbank = &chip->bank[0]; break; case NRF5_UICR_BASE: nbank = &chip->bank[1]; break; } assert(nbank); chip->refcount++; nbank->chip = chip; nbank->probed = false; bank->driver_priv = nbank; bank->write_start_alignment = bank->write_end_alignment = 4; return ERROR_OK; } COMMAND_HANDLER(nrf5_handle_mass_erase_command) { int res; struct flash_bank *bank = NULL; struct target *target = get_current_target(CMD_CTX); res = get_flash_bank_by_addr(target, NRF5_FLASH_BASE, true, &bank); if (res != ERROR_OK) return res; assert(bank); struct nrf5_info *chip; res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; if (chip->features & NRF5_FEATURE_SERIES_51) { uint32_t ppfc; res = target_read_u32(target, NRF51_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); return res; } if ((ppfc & 0xFF) == 0x00) { LOG_ERROR("Code region 0 size was pre-programmed at the factory, " "mass erase command won't work."); return ERROR_FAIL; } } res = nrf5_erase_all(chip); if (res == ERROR_OK) { LOG_INFO("Mass erase completed."); if (chip->features & NRF5_FEATURE_SERIES_51) LOG_INFO("A reset or power cycle is required if the flash was protected before."); } else { LOG_ERROR("Failed to erase the chip"); } return res; } COMMAND_HANDLER(nrf5_handle_info_command) { int res; struct flash_bank *bank = NULL; struct target *target = get_current_target(CMD_CTX); res = get_flash_bank_by_addr(target, NRF5_FLASH_BASE, true, &bank); if (res != ERROR_OK) return res; assert(bank); struct nrf5_info *chip; res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; static struct { const uint32_t address; uint32_t value; } ficr[] = { { .address = NRF5_FICR_CODEPAGESIZE }, { .address = NRF5_FICR_CODESIZE }, { .address = NRF51_FICR_CLENR0 }, { .address = NRF51_FICR_PPFC }, { .address = NRF51_FICR_NUMRAMBLOCK }, { .address = NRF51_FICR_SIZERAMBLOCK0 }, { .address = NRF51_FICR_SIZERAMBLOCK1 }, { .address = NRF51_FICR_SIZERAMBLOCK2 }, { .address = NRF51_FICR_SIZERAMBLOCK3 }, { .address = NRF5_FICR_CONFIGID }, { .address = NRF5_FICR_DEVICEID0 }, { .address = NRF5_FICR_DEVICEID1 }, { .address = NRF5_FICR_ER0 }, { .address = NRF5_FICR_ER1 }, { .address = NRF5_FICR_ER2 }, { .address = NRF5_FICR_ER3 }, { .address = NRF5_FICR_IR0 }, { .address = NRF5_FICR_IR1 }, { .address = NRF5_FICR_IR2 }, { .address = NRF5_FICR_IR3 }, { .address = NRF5_FICR_DEVICEADDRTYPE }, { .address = NRF5_FICR_DEVICEADDR0 }, { .address = NRF5_FICR_DEVICEADDR1 }, { .address = NRF51_FICR_OVERRIDEN }, { .address = NRF51_FICR_NRF_1MBIT0 }, { .address = NRF51_FICR_NRF_1MBIT1 }, { .address = NRF51_FICR_NRF_1MBIT2 }, { .address = NRF51_FICR_NRF_1MBIT3 }, { .address = NRF51_FICR_NRF_1MBIT4 }, { .address = NRF51_FICR_BLE_1MBIT0 }, { .address = NRF51_FICR_BLE_1MBIT1 }, { .address = NRF51_FICR_BLE_1MBIT2 }, { .address = NRF51_FICR_BLE_1MBIT3 }, { .address = NRF51_FICR_BLE_1MBIT4 }, }, uicr[] = { { .address = NRF51_UICR_CLENR0, }, { .address = NRF51_UICR_RBPCONF }, { .address = NRF51_UICR_XTALFREQ }, { .address = NRF51_UICR_FWID }, }; for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) { res = target_read_u32(chip->target, ficr[i].address, &ficr[i].value); if (res != ERROR_OK) { LOG_ERROR("Couldn't read %" PRIx32, ficr[i].address); return res; } } for (size_t i = 0; i < ARRAY_SIZE(uicr); i++) { res = target_read_u32(chip->target, uicr[i].address, &uicr[i].value); if (res != ERROR_OK) { LOG_ERROR("Couldn't read %" PRIx32, uicr[i].address); return res; } } command_print(CMD, "\n[factory information control block]\n\n" "code page size: %"PRIu32"B\n" "code memory size: %"PRIu32"kB\n" "code region 0 size: %"PRIu32"kB\n" "pre-programmed code: %s\n" "number of ram blocks: %"PRIu32"\n" "ram block 0 size: %"PRIu32"B\n" "ram block 1 size: %"PRIu32"B\n" "ram block 2 size: %"PRIu32"B\n" "ram block 3 size: %"PRIu32 "B\n" "config id: %" PRIx32 "\n" "device id: 0x%"PRIx32"%08"PRIx32"\n" "encryption root: 0x%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32"\n" "identity root: 0x%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32"\n" "device address type: 0x%"PRIx32"\n" "device address: 0x%"PRIx32"%08"PRIx32"\n" "override enable: %"PRIx32"\n" "NRF_1MBIT values: %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32"\n" "BLE_1MBIT values: %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32"\n" "\n[user information control block]\n\n" "code region 0 size: %"PRIu32"kB\n" "read back protection configuration: %"PRIx32"\n" "reset value for XTALFREQ: %"PRIx32"\n" "firmware id: 0x%04"PRIx32, ficr[0].value, (ficr[1].value * ficr[0].value) / 1024, (ficr[2].value == 0xFFFFFFFF) ? 0 : ficr[2].value / 1024, ((ficr[3].value & 0xFF) == 0x00) ? "present" : "not present", ficr[4].value, ficr[5].value, (ficr[6].value == 0xFFFFFFFF) ? 0 : ficr[6].value, (ficr[7].value == 0xFFFFFFFF) ? 0 : ficr[7].value, (ficr[8].value == 0xFFFFFFFF) ? 0 : ficr[8].value, ficr[9].value, ficr[10].value, ficr[11].value, ficr[12].value, ficr[13].value, ficr[14].value, ficr[15].value, ficr[16].value, ficr[17].value, ficr[18].value, ficr[19].value, ficr[20].value, ficr[21].value, ficr[22].value, ficr[23].value, ficr[24].value, ficr[25].value, ficr[26].value, ficr[27].value, ficr[28].value, ficr[29].value, ficr[30].value, ficr[31].value, ficr[32].value, ficr[33].value, (uicr[0].value == 0xFFFFFFFF) ? 0 : uicr[0].value / 1024, uicr[1].value & 0xFFFF, uicr[2].value & 0xFF, uicr[3].value & 0xFFFF); return ERROR_OK; } static const struct command_registration nrf5_exec_command_handlers[] = { { .name = "mass_erase", .handler = nrf5_handle_mass_erase_command, .mode = COMMAND_EXEC, .help = "Erase all flash contents of the chip.", .usage = "", }, { .name = "info", .handler = nrf5_handle_info_command, .mode = COMMAND_EXEC, .help = "Show FICR and UICR info.", .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration nrf5_command_handlers[] = { { .name = "nrf5", .mode = COMMAND_ANY, .help = "nrf5 flash command group", .usage = "", .chain = nrf5_exec_command_handlers, }, { .name = "nrf51", .mode = COMMAND_ANY, .help = "nrf51 flash command group", .usage = "", .chain = nrf5_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver nrf5_flash = { .name = "nrf5", .commands = nrf5_command_handlers, .flash_bank_command = nrf5_flash_bank_command, .info = nrf5_info, .erase = nrf5_erase, .protect = nrf5_protect, .write = nrf5_write, .read = default_flash_read, .probe = nrf5_probe, .auto_probe = nrf5_auto_probe, .erase_check = default_flash_blank_check, .protect_check = nrf5_protect_check, .free_driver_priv = nrf5_free_driver_priv, }; /* We need to retain the flash-driver name as well as the commands * for backwards compatibility */ const struct flash_driver nrf51_flash = { .name = "nrf51", .commands = nrf5_command_handlers, .flash_bank_command = nrf5_flash_bank_command, .info = nrf5_info, .erase = nrf5_erase, .protect = nrf5_protect, .write = nrf5_write, .read = default_flash_read, .probe = nrf5_probe, .auto_probe = nrf5_auto_probe, .erase_check = default_flash_blank_check, .protect_check = nrf5_protect_check, .free_driver_priv = nrf5_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/numicro.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by James K. Larson * * jlarson@pacifier.com * * * * Copyright (C) 2013 Cosmin Gorgovan * * cosmin [at] linux-geek [dot] org * * * * Copyright (C) 2014 Pawel Si * * stawel+openocd@gmail.com * * * * Copyright (C) 2015 Nemui Trinomius * * nemuisan_kawausogasuki@live.jp * * * * Copyright (C) 2017 Zale Yu * * CYYU@nuvoton.com * * * * Copyright (C) 2022 Jian-Hong Pan * * chienhung.pan@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> #include <target/cortex_m.h> /* Nuvoton NuMicro register locations */ #define NUMICRO_SYS_BASE 0x50000000 #define NUMICRO_SYS_WRPROT 0x50000100 #define NUMICRO_SYS_IPRSTC1 0x50000008 #define NUMICRO_SYSCLK_BASE 0x50000200 #define NUMICRO_SYSCLK_PWRCON 0x50000200 #define NUMICRO_SYSCLK_CLKSEL0 0x50000210 #define NUMICRO_SYSCLK_CLKDIV 0x50000218 #define NUMICRO_SYSCLK_AHBCLK 0x50000204 #define NUMICRO_FLASH_BASE 0x5000C000 #define NUMICRO_FLASH_ISPCON 0x5000C000 #define NUMICRO_FLASH_ISPADR 0x5000C004 #define NUMICRO_FLASH_ISPDAT 0x5000C008 #define NUMICRO_FLASH_ISPCMD 0x5000C00C #define NUMICRO_FLASH_ISPTRG 0x5000C010 #define NUMICRO_FLASH_CHEAT 0x5000C01C /* Undocumented isp register(may be cheat register) */ #define NUMICRO_SCS_BASE 0xE000E000 #define NUMICRO_SCS_AIRCR 0xE000ED0C #define NUMICRO_SCS_DHCSR 0xE000EDF0 #define NUMICRO_SCS_DEMCR 0xE000EDFC #define NUMICRO_APROM_BASE 0x00000000 #define NUMICRO_DATA_BASE 0x0001F000 #define NUMICRO_LDROM_BASE 0x00100000 #define NUMICRO_CONFIG_BASE 0x00300000 #define NUMICRO_CONFIG0 0x5000C000 #define NUMICRO_CONFIG1 0x5000C004 /* Command register bits */ #define PWRCON_OSC22M (1 << 2) #define PWRCON_XTL12M (1 << 0) #define IPRSTC1_CPU_RST (1 << 1) #define IPRSTC1_CHIP_RST (1 << 0) #define AHBCLK_ISP_EN (1 << 2) #define AHBCLK_SRAM_EN (1 << 4) #define AHBCLK_TICK_EN (1 << 5) #define ISPCON_ISPEN (1 << 0) #define ISPCON_BS_AP (0 << 1) #define ISPCON_BS_LP (1 << 1) #define ISPCON_BS_MASK (1 << 1) #define ISPCON_APUEN (1 << 3) #define ISPCON_CFGUEN (1 << 4) #define ISPCON_LDUEN (1 << 5) #define ISPCON_ISPFF (1 << 6) #define CONFIG0_LOCK_MASK (1 << 1) /* isp commands */ #define ISPCMD_READ 0x00 #define ISPCMD_WRITE 0x21 #define ISPCMD_ERASE 0x22 #define ISPCMD_CHIPERASE 0x26 /* Undocumented isp "Chip-Erase" command */ #define ISPCMD_READ_CID 0x0B #define ISPCMD_READ_DID 0x0C #define ISPCMD_READ_UID 0x04 #define ISPCMD_VECMAP 0x2E #define ISPTRG_ISPGO (1 << 0) /* access unlock keys */ #define REG_KEY1 0x59 #define REG_KEY2 0x16 #define REG_KEY3 0x88 #define REG_LOCK 0x00 /* flash pagesizes */ #define NUMICRO_PAGESIZE 512 /* flash MAX banks */ #define NUMICRO_MAX_FLASH_BANKS 4 /* flash bank structs */ struct numicro_flash_bank_type { uint32_t base; uint32_t size; }; /* part structs */ struct numicro_cpu_type { char *partname; uint32_t partid; unsigned int n_banks; struct numicro_flash_bank_type bank[NUMICRO_MAX_FLASH_BANKS]; }; /* If DataFlash size equals zero, it means the actual size depends on config settings. */ #define NUMICRO_BANKS_GENERAL(aprom_size, data_size, ldrom_size, config_size) \ .n_banks = 4, \ {{NUMICRO_APROM_BASE, (aprom_size)}, \ {NUMICRO_DATA_BASE, (data_size)}, \ {NUMICRO_LDROM_BASE, (ldrom_size)}, \ {NUMICRO_CONFIG_BASE, (config_size)}} static const struct numicro_cpu_type numicro_parts[] = { /*PART NO*/ /*PART ID*/ /*Banks*/ /* M051AN */ {"M052LAN", 0x00005200, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M054LAN", 0x00005400, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M058LAN", 0x00005800, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M0516LAN", 0x00005A00, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M052ZAN", 0x00005203, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M054ZAN", 0x00005403, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M058ZAN", 0x00005803, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M0516ZAN", 0x00005A03, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, /* M051BN */ {"M052LBN", 0x10005200, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M054LBN", 0x10005400, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M058LBN", 0x10005800, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M0516LBN", 0x10005A00, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M052ZBN", 0x10005203, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M054ZBN", 0x10005403, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M058ZBN", 0x10005803, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M0516ZBN", 0x10005A03, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, /* M051DN */ {"M0516LDN", 0x20005A00, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M0516ZDN", 0x20005A03, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M052LDN", 0x20005200, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M052ZDN", 0x20005203, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M054LDN", 0x20005400, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M054ZDN", 0x20005403, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M058LDN", 0x20005800, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M058ZDN", 0x20005803, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, /* M051DE */ {"M0516LDE", 0x30005A00, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M0516ZDE", 0x30005A03, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M052LDE", 0x30005200, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M052ZDE", 0x30005203, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M054LDE", 0x30005400, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M054ZDE", 0x30005403, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M058LDE", 0x30005800, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, {"M058ZDE", 0x30005803, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, /* M0518 */ {"M0518LC2AE", 0x10051803, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"M0518LD2AE", 0x10051800, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"M0518SC2AE", 0x10051813, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"M0518SD2AE", 0x10051810, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, /* M0519 */ {"M0519LD3AE", 0x00051902, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 8 * 1024, 8)}, {"M0519LE3AE", 0x00051900, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, {"M0519SD3AE", 0x00051922, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 8 * 1024, 8)}, {"M0519SE3AE", 0x00051920, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, {"M0519VE3AE", 0x00051930, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, /* M058S */ {"M058SFAN", 0x00005818, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"M058SLAN", 0x00005810, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"M058SSAN", 0x00005816, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"M058SZAN", 0x00005813, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, /* MINI51AN */ {"MINI51LAN", 0x00205100, NUMICRO_BANKS_GENERAL(4 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI51TAN", 0x00205104, NUMICRO_BANKS_GENERAL(4 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI51ZAN", 0x00205103, NUMICRO_BANKS_GENERAL(4 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI52LAN", 0x00205200, NUMICRO_BANKS_GENERAL(8 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI52TAN", 0x00205204, NUMICRO_BANKS_GENERAL(8 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI52ZAN", 0x00205203, NUMICRO_BANKS_GENERAL(8 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI54LAN", 0x00205400, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI54TAN", 0x00205404, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI54ZAN", 0x00205403, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, /* MINI51DE */ {"MINI51FDE", 0x20205105, NUMICRO_BANKS_GENERAL(4 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI51LDE", 0x20205100, NUMICRO_BANKS_GENERAL(4 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI51TDE", 0x20205104, NUMICRO_BANKS_GENERAL(4 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI51ZDE", 0x20205103, NUMICRO_BANKS_GENERAL(4 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI52FDE", 0x20205205, NUMICRO_BANKS_GENERAL(8 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI52LDE", 0x20205200, NUMICRO_BANKS_GENERAL(8 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI52TDE", 0x20205204, NUMICRO_BANKS_GENERAL(8 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI52ZDE", 0x20205203, NUMICRO_BANKS_GENERAL(8 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI54FDE", 0x20205405, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI54LDE", 0x20205400, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI54TDE", 0x20205404, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, {"MINI54ZDE", 0x20205403, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, /* MINI55 */ {"MINI55LDE", 0x00505500, NUMICRO_BANKS_GENERAL(35 * 512, 0 * 1024, 2 * 1024, 8)}, {"MINI55ZDE", 0x00505503, NUMICRO_BANKS_GENERAL(35 * 512, 0 * 1024, 2 * 1024, 8)}, /* MINI58 */ {"MINI58FDE", 0x00A05805, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 5 * 512, 8)}, {"MINI58LDE", 0x00A05800, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 5 * 512, 8)}, {"MINI58TDE", 0x00A05804, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 5 * 512, 8)}, {"MINI58ZDE", 0x00A05803, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 5 * 512, 8)}, /* NANO100AN */ {"NANO100LC2AN", 0x00110025, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100LD2AN", 0x00110019, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100LD3AN", 0x00110018, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100SC2AN", 0x00110023, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100SD2AN", 0x00110016, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100SD3AN", 0x00110015, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100VD2AN", 0x00110013, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100VD3AN", 0x00110012, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100ZC2AN", 0x00110029, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100ZD2AN", 0x00110028, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100ZD3AN", 0x00110027, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120LC2AN", 0x00112025, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120LD2AN", 0x00112019, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120LD3AN", 0x00112018, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120SC2AN", 0x00112023, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120SD2AN", 0x00112016, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120SD3AN", 0x00112015, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120VD2AN", 0x00112013, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120VD3AN", 0x00112012, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120ZC2AN", 0x00112029, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120ZD2AN", 0x00112028, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120ZD3AN", 0x00112027, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, /* NANO100BN */ {"NANO100KC2BN", 0x00110040, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100KD2BN", 0x00110039, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100KD3BN", 0x00110038, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100KE3BN", 0x00110030, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100LC2BN", 0x00110043, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100LD2BN", 0x0011003F, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100LD3BN", 0x0011003E, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100LE3BN", 0x00110036, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100ND2BN", 0x00110046, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100ND3BN", 0x00110045, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100NE3BN", 0x00110044, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100SC2BN", 0x00110042, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100SD2BN", 0x0011003D, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100SD3BN", 0x0011003C, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO100SE3BN", 0x00110034, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO110KC2BN", 0x00111040, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO110KD2BN", 0x00111039, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO110KD3BN", 0x00111038, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO110KE3BN", 0x00111030, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO110RC2BN", 0x00111043, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO110RD2BN", 0x00111044, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO110RD3BN", 0x00111045, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO110SC2BN", 0x00111042, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO110SD2BN", 0x0011103D, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO110SD3BN", 0x0011103C, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO110SE3BN", 0x00111034, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120KC2BN", 0x00112040, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120KD2BN", 0x00112039, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120KD3BN", 0x00112038, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120KE3BN", 0x00112030, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120LC2BN", 0x00112043, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120LD2BN", 0x0011203F, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120LD3BN", 0x0011203E, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120LE3BN", 0x00112036, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120SC2BN", 0x00112042, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120SD2BN", 0x0011203D, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120SD3BN", 0x0011203C, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO120SE3BN", 0x00112034, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO130KC2BN", 0x00113040, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO130KD2BN", 0x00113039, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO130KD3BN", 0x00113038, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO130KE3BN", 0x00113030, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO130SC2BN", 0x00113042, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO130SD2BN", 0x0011303D, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO130SD3BN", 0x0011303C, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO130SE3BN", 0x00113034, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, /* NANO103 */ {"NANO103SD3AE", 0x00110301, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO103LD3AE", 0x00110304, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO103ZD3AE", 0x00110307, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, /* NANO112AN */ {"NANO102LB1AN", 0x00110206, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO102LC2AN", 0x00110208, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO102SC2AN", 0x00110212, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO102ZB1AN", 0x00110202, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO102ZC2AN", 0x00110204, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO112LB1AN", 0x00111202, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO112LC2AN", 0x00111204, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO112RB1AN", 0x00111210, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO112RC2AN", 0x00111212, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO112SB1AN", 0x00111206, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO112SC2AN", 0x00111208, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NANO112VC2AN", 0x00111216, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, /* NUC029AN */ {"NUC029LAN", 0x00295A00, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, {"NUC029TAN", 0x00295804, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, /* NUC029AE */ {"NUC029FAE", 0x00295415, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, /* NUC100AN */ {"NUC100LD3AN", 0x00010003, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100LE3AN", 0x00010000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC100RD3AN", 0x00010012, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100RE3AN", 0x00010009, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC100VD2AN", 0x00010022, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100VD3AN", 0x00010021, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100VE3AN", 0x00100018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC120LD3AN", 0x00012003, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120LE3AN", 0x00120000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC120RD3AN", 0x00012012, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120RE3AN", 0x00012009, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC120VD2AN", 0x00012022, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120VD3AN", 0x00012021, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120VE3AN", 0x00012018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, /* NUC100BN */ {"NUC100LC1BN", 0x10010008, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100LD1BN", 0x10010005, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100LD2BN", 0x10010004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100RC1BN", 0x10010017, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100RD1BN", 0x10010014, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100RD2BN", 0x10010013, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120LC1BN", 0x10012008, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120LD1BN", 0x10012005, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120LD2BN", 0x10012004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120RC1BN", 0x10012017, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120RD1BN", 0x10012014, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120RD2BN", 0x10012013, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, /* NUC100CN */ {"NUC130LC1CN", 0x20013008, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC130LD2CN", 0x20013004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC130LE3CN", 0x20013000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC130RC1CN", 0x20013017, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC130RD2CN", 0x20013013, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC130RE3CN", 0x20013009, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC130VE3CN", 0x20013018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC140LC1CN", 0x20014008, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC140LD2CN", 0x20014004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC140LE3CN", 0x20014000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC140RC1CN", 0x20014017, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC140RD2CN", 0x20014013, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC140RE3CN", 0x20014009, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC140VE3CN", 0x20014018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, /* NUC100DN */ {"NUC100LC1DN", 0x30010008, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100LD1DN", 0x30010005, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100LD2DN", 0x30010004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100LD3DN", 0x30010003, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100LE3DN", 0x30010000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC100RC1DN", 0x30010017, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100RD1DN", 0x30010014, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100RD2DN", 0x30010013, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100RD3DN", 0x30010012, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100RE3DN", 0x30010009, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC100VD2DN", 0x30010022, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100VD3DN", 0x30010021, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC100VE3DN", 0x30010018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC120LC1DN", 0x30012008, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120LD1DN", 0x30012005, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120LD2DN", 0x30012004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120LD3DN", 0x30012003, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120LE3DN", 0x30012000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC120RC1DN", 0x30012035, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120RD1DN", 0x30012032, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120RD2DN", 0x30012031, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120RD3DN", 0x30012030, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120RE3DN", 0x30012027, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC120VD2DN", 0x30012022, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120VD3DN", 0x30012021, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC120VE3DN", 0x30012018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, /* NUC121 */ {"NUC121SC2AE", 0x00012105, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 9 * 512, 8)}, {"NUC121LC2AE", 0x00012125, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 9 * 512, 8)}, {"NUC121ZC2AE", 0x00012145, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 9 * 512, 8)}, {"NUC125SC2AE", 0x00012505, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 9 * 512, 8)}, {"NUC125LC2AE", 0x00012525, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 9 * 512, 8)}, {"NUC125ZC2AE", 0x00012545, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 9 * 512, 8)}, /* NUC122 */ {"NUC122LC1AN", 0x00012208, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC122LD2AN", 0x00012204, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC122SC1AN", 0x00012226, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC122SD2AN", 0x00012222, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC122ZC1AN", 0x00012235, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC122ZD2AN", 0x00012231, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, /* NUC123AN */ {"NUC123LC2AN1", 0x00012325, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC123LD4AN0", 0x00012335, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC123SC2AN1", 0x00012305, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC123SD4AN0", 0x00012315, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC123ZC2AN1", 0x00012345, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC123ZD4AN0", 0x00012355, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, /* NUC123AE */ {"NUC123LC2AE1", 0x10012325, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC123LD4AE0", 0x10012335, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC123SC2AE1", 0x10012305, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC123SD4AE0", 0x10012315, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC123ZC2AE1", 0x10012345, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC123ZD4AE0", 0x10012355, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, /* NUC131AE */ {"NUC131LC2AE", 0x10013103, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC131LD2AE", 0x10013100, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC131SC2AE", 0x10013113, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC131SD2AE", 0x10013110, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, /* NUC200/220AN */ {"NUC200LC2AN", 0x00020007, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC200LD2AN", 0x00020004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC200LE3AN", 0x00020000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC200SC2AN", 0x00020034, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC200SD2AN", 0x00020031, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC200SE3AN", 0x00020027, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC200VE3AN", 0x00020018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC220LC2AN", 0x00022007, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC220LD2AN", 0x00022004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC220LE3AN", 0x00022000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC220SC2AN", 0x00022034, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC220SD2AN", 0x00022031, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, {"NUC220SE3AN", 0x00022027, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"NUC220VE3AN", 0x00022018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, /* NUC230/240AE */ {"NUC230LC2AE", 0x10023007, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 8 * 1024, 8)}, {"NUC230LD2AE", 0x10023004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 8 * 1024, 8)}, {"NUC230LE3AE", 0x10023000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, {"NUC230SC2AE", 0x10023034, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 8 * 1024, 8)}, {"NUC230SD2AE", 0x10023031, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 8 * 1024, 8)}, {"NUC230SE3AE", 0x10023027, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, {"NUC230VE3AE", 0x10023018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, {"NUC240LC2AE", 0x10024007, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 8 * 1024, 8)}, {"NUC240LD2AE", 0x10024004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 8 * 1024, 8)}, {"NUC240LE3AE", 0x10024000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, {"NUC240SC2AE", 0x10024034, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 8 * 1024, 8)}, {"NUC240SD2AE", 0x10024031, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 8 * 1024, 8)}, {"NUC240SE3AE", 0x10024027, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, {"NUC240VE3AE", 0x10024018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, /* M451 */ {"M451LC3AE", 0x00945101, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451LD3AE", 0x00945100, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451LE6AE", 0x00845101, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451LG6AE", 0x00845100, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451MLC3AE", 0x00945001, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451MLD3AE", 0x00945000, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451MLE6AE", 0x00845001, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451MLG6AE", 0x00845000, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451MSC3AE", 0x00945011, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451MSD3AE", 0x00945010, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451RC3AE", 0x00945121, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451RD3AE", 0x00945120, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451RE6AE", 0x00845121, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451RG6AE", 0x00845120, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451VE6AE", 0x00845131, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M451VG6AE", 0x00845130, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M452LC3AE", 0x00945201, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M452LD3AE", 0x00945200, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M452LE6AE", 0x00845201, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M452LG6AE", 0x00845200, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M452RD3AE", 0x00945220, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M452RE6AE", 0x00845221, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M452RG6AE", 0x00845220, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M453LC3AE", 0x00945301, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M453LD3AE", 0x00945300, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M453LE6AE", 0x00845301, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M453LG6AE", 0x00845300, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M453RD3AE", 0x00945320, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M453RE6AE", 0x00845321, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M453RG6AE", 0x00845320, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M453VD3AE", 0x00945330, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M453VE6AE", 0x00845331, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M453VG6AE", 0x00845330, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M4TKVG6AE", 0x00845430, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M4TKVE6AE", 0x00845431, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M4TKRG6AE", 0x00845420, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M4TKRE6AE", 0x00845421, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M4TKLG6AE", 0x00845400, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, {"M4TKLE6AE", 0x00845401, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, /* NUC442_472 */ {"NUC442JG8AE", 0x00044203, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC442JI8AE", 0x00044201, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC442KG8AE", 0x00044206, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC442KI8AE", 0x00044204, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC442RG8AE", 0x00044212, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC442RI8AE", 0x00044210, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC442VG8AE", 0x00044209, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC442VI8AE", 0x00044207, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC472HG8AE", 0x00047203, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC472HI8AE", 0x00047201, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC472JG8AE", 0x00047206, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC472JI8AE", 0x00047204, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC472KG8AE", 0x00047209, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC472KI8AE", 0x00047207, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC472VG8AE", 0x00047212, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, {"NUC472VI8AE", 0x00047210, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, {"UNKNOWN", 0x00000000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 16 * 1024, 8)}, }; /* Private bank information for NuMicro. */ struct numicro_flash_bank { struct working_area *write_algorithm; bool probed; const struct numicro_cpu_type *cpu; }; /* Private variables */ static uint32_t m_page_size = NUMICRO_PAGESIZE; static uint32_t m_address_bias_offset; /* Private methods */ static int numicro_get_arm_arch(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); if (armv7m->arm.arch != ARM_ARCH_V6M) { LOG_DEBUG("NuMicro arm architecture: armv7m\n"); m_page_size = NUMICRO_PAGESIZE * 4; m_address_bias_offset = 0x10000000; } else { LOG_DEBUG("NuMicro arm architecture: armv6m\n"); m_page_size = NUMICRO_PAGESIZE; m_address_bias_offset = 0x0; } return ERROR_OK; } static int numicro_reg_unlock(struct target *target) { uint32_t is_protected; int retval = ERROR_OK; /* Check to see if NUC is register unlocked or not */ retval = target_read_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, &is_protected); if (retval != ERROR_OK) return retval; LOG_DEBUG("protected = 0x%08" PRIx32 "", is_protected); if (is_protected == 0) { /* means protected - so unlock it */ /* unlock flash registers */ retval = target_write_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, REG_KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, REG_KEY2); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, REG_KEY3); if (retval != ERROR_OK) return retval; } /* Check that unlock worked */ retval = target_read_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, &is_protected); if (retval != ERROR_OK) return retval; if (is_protected == 1) { /* means unprotected */ LOG_DEBUG("protection removed"); } else { LOG_DEBUG("still protected!!"); } return ERROR_OK; } static int numicro_init_isp(struct target *target) { uint32_t reg_stat; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = numicro_reg_unlock(target); if (retval != ERROR_OK) return retval; /* Enable ISP/SRAM/TICK Clock */ retval = target_read_u32(target, NUMICRO_SYSCLK_AHBCLK - m_address_bias_offset, ®_stat); if (retval != ERROR_OK) return retval; reg_stat |= AHBCLK_ISP_EN | AHBCLK_SRAM_EN | AHBCLK_TICK_EN; retval = target_write_u32(target, NUMICRO_SYSCLK_AHBCLK - m_address_bias_offset, reg_stat); if (retval != ERROR_OK) return retval; /* Enable ISP */ retval = target_read_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, ®_stat); if (retval != ERROR_OK) return retval; reg_stat |= ISPCON_ISPFF | ISPCON_LDUEN | ISPCON_APUEN | ISPCON_CFGUEN | ISPCON_ISPEN; retval = target_write_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, reg_stat); if (retval != ERROR_OK) return retval; /* Write one to undocumented flash control register */ retval = target_write_u32(target, NUMICRO_FLASH_CHEAT - m_address_bias_offset, 1); if (retval != ERROR_OK) return retval; return ERROR_OK; } static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t addr, uint32_t wdata, uint32_t *rdata) { uint32_t timeout, status; int retval = ERROR_OK; retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD - m_address_bias_offset, cmd); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, NUMICRO_FLASH_ISPDAT - m_address_bias_offset, wdata); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, NUMICRO_FLASH_ISPADR - m_address_bias_offset, addr); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG - m_address_bias_offset, ISPTRG_ISPGO); if (retval != ERROR_OK) return retval; /* Wait for busy to clear - check the GO flag */ timeout = 100; for (;;) { retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG - m_address_bias_offset, &status); if (retval != ERROR_OK) return retval; if ((status & (ISPTRG_ISPGO)) == 0) break; if (timeout-- <= 0) { LOG_DEBUG("timed out waiting for flash"); return ERROR_FAIL; } busy_sleep(1); /* can use busy sleep for short times. */ } retval = target_read_u32(target, NUMICRO_FLASH_ISPDAT - m_address_bias_offset, rdata); if (retval != ERROR_OK) return retval; return ERROR_OK; } /* NuMicro Program-LongWord Microcodes */ static const uint8_t numicro_flash_write_code[] = { #include "../../../contrib/loaders/flash/numicro/numicro_m0.inc" }; static const uint8_t numicro_m4_flash_write_code[] = { #include "../../../contrib/loaders/flash/numicro/numicro_m4.inc" }; /* Program LongWord Block Write */ static int numicro_writeblock(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 1024; /* Default minimum value */ struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* Params: * r0 - workarea buffer / result * r1 - target address * r2 - wordcount * Clobbered: * r4 - tmp * r5 - tmp * r6 - tmp * r7 - tmp */ /* Increase buffer_size if needed */ if (buffer_size < (target->working_area_size/2)) buffer_size = (target->working_area_size/2); /* check code alignment */ if (offset & 0x1) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* Difference between M0 and M4 */ if (m_page_size == NUMICRO_PAGESIZE) { /* allocate working area with flash programming code */ if (target_alloc_working_area(target, sizeof(numicro_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(numicro_flash_write_code), numicro_flash_write_code); if (retval != ERROR_OK) return retval; } else { /* for M4 */ /* allocate working area with flash programming code */ if (target_alloc_working_area(target, sizeof(numicro_m4_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(numicro_m4_flash_write_code), numicro_m4_flash_write_code); if (retval != ERROR_OK) return retval; buffer_size = m_page_size; } /* memory buffer */ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 4; if (buffer_size <= 256) { /* free working area, write algorithm already allocated */ target_free_working_area(target, write_algorithm); LOG_WARNING("No large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* *pLW (*buffer) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* faddr */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* number of words to program */ /* write code buffer and use Flash programming code within NuMicro */ /* Set breakpoint to 0 with time-out of 1000 ms */ while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 4)) ? (buffer_size / 4) : count; retval = target_write_buffer(target, source->address, thisrun_count * 4, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); retval = target_run_algorithm(target, 0, NULL, 3, reg_params, write_algorithm->address, 0, 100000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("Error executing NuMicro Flash programming algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count * 4; address += thisrun_count * 4; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); return retval; } /* Flash Lock checking - examines the lock bit. */ static int numicro_protect_check(struct flash_bank *bank) { struct target *target = bank->target; uint32_t set, config[2]; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_INFO("Nuvoton NuMicro: Flash Lock Check..."); numicro_get_arm_arch(target); retval = numicro_init_isp(target); if (retval != ERROR_OK) return retval; /* Read CONFIG0,CONFIG1 */ numicro_fmc_cmd(target, ISPCMD_READ, NUMICRO_CONFIG0 - m_address_bias_offset, 0, &config[0]); numicro_fmc_cmd(target, ISPCMD_READ, NUMICRO_CONFIG1 - m_address_bias_offset, 0, &config[1]); LOG_DEBUG("CONFIG0: 0x%" PRIx32 ",CONFIG1: 0x%" PRIx32 "", config[0], config[1]); if ((config[0] & (1<<7)) == 0) LOG_INFO("CBS=0: Boot From LPROM"); else LOG_INFO("CBS=1: Boot From APROM"); if ((config[0] & CONFIG0_LOCK_MASK) == 0) { LOG_INFO("Flash is secure locked!"); LOG_INFO("TO UNLOCK FLASH,EXECUTE chip_erase COMMAND!!"); set = 1; } else { LOG_INFO("Flash is not locked!"); set = 0; } for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = set; return ERROR_OK; } static int numicro_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; uint32_t timeout, status; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_INFO("Nuvoton NuMicro: Sector Erase ... (%u to %u)", first, last); numicro_get_arm_arch(target); retval = numicro_init_isp(target); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD - m_address_bias_offset, ISPCMD_ERASE); if (retval != ERROR_OK) return retval; for (unsigned int i = first; i <= last; i++) { LOG_DEBUG("erasing sector %u at address " TARGET_ADDR_FMT, i, bank->base + bank->sectors[i].offset); retval = target_write_u32(target, NUMICRO_FLASH_ISPADR - m_address_bias_offset, bank->base + bank->sectors[i].offset); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG - m_address_bias_offset, ISPTRG_ISPGO); /* This is the only bit available */ if (retval != ERROR_OK) return retval; /* wait for busy to clear - check the GO flag */ timeout = 100; for (;;) { retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG - m_address_bias_offset, &status); if (retval != ERROR_OK) return retval; if (status == 0) break; if (timeout-- <= 0) { LOG_DEBUG("timed out waiting for flash"); return ERROR_FAIL; } busy_sleep(1); /* can use busy sleep for short times. */ } /* check for failure */ retval = target_read_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, &status); if (retval != ERROR_OK) return retval; if ((status & ISPCON_ISPFF) != 0) { LOG_DEBUG("failure: 0x%" PRIx32 "", status); /* if bit is set, then must write to it to clear it. */ retval = target_write_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, (status | ISPCON_ISPFF)); if (retval != ERROR_OK) return retval; } } /* done, */ LOG_DEBUG("Erase done."); return ERROR_OK; } /* The write routine stub. */ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t timeout, status; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_INFO("Nuvoton NuMicro: Flash Write ..."); numicro_get_arm_arch(target); retval = numicro_init_isp(target); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD - m_address_bias_offset, ISPCMD_WRITE); if (retval != ERROR_OK) return retval; assert(offset % 4 == 0); assert(count % 4 == 0); uint32_t words_remaining = count / 4; /* try using a block write */ retval = numicro_writeblock(bank, buffer, offset, words_remaining); if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single word accesses */ LOG_WARNING("couldn't use block writes, falling back to single " "memory accesses"); /* program command */ for (uint32_t i = 0; i < count; i += 4) { /* write 4 bytes each time with 0xff padding to avoid unaligned case */ uint8_t padding[4] = {0xff, 0xff, 0xff, 0xff}; memcpy(padding, buffer + i, MIN(4, count - i)); retval = target_write_u32(target, NUMICRO_FLASH_ISPADR - m_address_bias_offset, bank->base + offset + i); if (retval != ERROR_OK) return retval; retval = target_write_memory(target, NUMICRO_FLASH_ISPDAT - m_address_bias_offset, 4, 1, padding); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG - m_address_bias_offset, ISPTRG_ISPGO); if (retval != ERROR_OK) return retval; /* wait for busy to clear - check the GO flag */ timeout = 100; for (;;) { retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG - m_address_bias_offset, &status); if (retval != ERROR_OK) return retval; if (status == 0) break; if (timeout-- <= 0) { LOG_DEBUG("timed out waiting for flash"); return ERROR_FAIL; } busy_sleep(1); /* can use busy sleep for short times. */ } } } /* check for failure */ retval = target_read_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, &status); if (retval != ERROR_OK) return retval; if ((status & ISPCON_ISPFF) != 0) { LOG_DEBUG("failure: 0x%" PRIx32 "", status); /* if bit is set, then must write to it to clear it. */ retval = target_write_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, (status | ISPCON_ISPFF)); if (retval != ERROR_OK) return retval; } else { LOG_DEBUG("Write OK"); } /* done. */ LOG_DEBUG("Write done."); return ERROR_OK; } static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_type **cpu) { uint32_t part_id; int retval = ERROR_OK; numicro_get_arm_arch(target); /* Read NuMicro PartID */ retval = target_read_u32(target, NUMICRO_SYS_BASE - m_address_bias_offset, &part_id); if (retval != ERROR_OK) { LOG_WARNING("NuMicro flash driver: Failed to Get PartID\n"); return ERROR_FLASH_OPERATION_FAILED; } LOG_INFO("Device ID: 0x%08" PRIx32 "", part_id); /* search part numbers */ for (size_t i = 0; i < ARRAY_SIZE(numicro_parts); i++) { if (part_id == numicro_parts[i].partid) { *cpu = &numicro_parts[i]; LOG_INFO("Device Name: %s", (*cpu)->partname); return ERROR_OK; } } return ERROR_FAIL; } static int numicro_get_flash_size(struct flash_bank *bank, const struct numicro_cpu_type *cpu, uint32_t *flash_size) { for (size_t i = 0; i < cpu->n_banks; i++) { if (bank->base == cpu->bank[i].base) { *flash_size = cpu->bank[i].size; LOG_INFO("bank base = " TARGET_ADDR_FMT ", size = 0x%08" PRIx32, bank->base, *flash_size); return ERROR_OK; } } return ERROR_FLASH_OPERATION_FAILED; } static int numicro_probe(struct flash_bank *bank) { uint32_t flash_size, offset = 0; int num_pages; const struct numicro_cpu_type *cpu; struct target *target = bank->target; int retval = ERROR_OK; retval = numicro_get_cpu_type(target, &cpu); if (retval != ERROR_OK) { LOG_WARNING("NuMicro flash driver: Failed to detect a known part\n"); return ERROR_FLASH_OPERATION_FAILED; } retval = numicro_get_flash_size(bank, cpu, &flash_size); if (retval != ERROR_OK) { LOG_WARNING("NuMicro flash driver: Failed to detect flash size\n"); return ERROR_FLASH_OPERATION_FAILED; } num_pages = flash_size / m_page_size; bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); bank->size = flash_size; for (int i = 0; i < num_pages; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = m_page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; offset += m_page_size; } struct numicro_flash_bank *numicro_info = bank->driver_priv; numicro_info->probed = true; numicro_info->cpu = cpu; LOG_DEBUG("Nuvoton NuMicro: Probed ..."); return ERROR_OK; } /* Standard approach to autoprobing. */ static int numicro_auto_probe(struct flash_bank *bank) { struct numicro_flash_bank *numicro_info = bank->driver_priv; if (numicro_info->probed) return ERROR_OK; return numicro_probe(bank); } /* This is the function called in the config file. */ FLASH_BANK_COMMAND_HANDLER(numicro_flash_bank_command) { struct numicro_flash_bank *bank_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; LOG_DEBUG("add flash_bank numicro %s", bank->name); bank_info = malloc(sizeof(struct numicro_flash_bank)); memset(bank_info, 0, sizeof(struct numicro_flash_bank)); bank->driver_priv = bank_info; bank->write_start_alignment = bank->write_end_alignment = 4; return ERROR_OK; } COMMAND_HANDLER(numicro_handle_read_isp_command) { uint32_t address; uint32_t ispdat; int retval = ERROR_OK; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); struct target *target = get_current_target(CMD_CTX); numicro_get_arm_arch(target); retval = numicro_init_isp(target); if (retval != ERROR_OK) return retval; retval = numicro_fmc_cmd(target, ISPCMD_READ, address, 0, &ispdat); if (retval != ERROR_OK) return retval; LOG_INFO("0x%08" PRIx32 ": 0x%08" PRIx32, address, ispdat); return ERROR_OK; } COMMAND_HANDLER(numicro_handle_write_isp_command) { uint32_t address; uint32_t ispdat, rdat; int retval = ERROR_OK; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], ispdat); struct target *target = get_current_target(CMD_CTX); numicro_get_arm_arch(target); retval = numicro_init_isp(target); if (retval != ERROR_OK) return retval; retval = numicro_fmc_cmd(target, ISPCMD_WRITE, address, ispdat, &rdat); if (retval != ERROR_OK) return retval; LOG_INFO("0x%08" PRIx32 ": 0x%08" PRIx32, address, ispdat); return ERROR_OK; } COMMAND_HANDLER(numicro_handle_chip_erase_command) { int retval = ERROR_OK; uint32_t rdat; if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); numicro_get_arm_arch(target); retval = numicro_init_isp(target); if (retval != ERROR_OK) return retval; retval = numicro_fmc_cmd(target, ISPCMD_CHIPERASE, 0, 0, &rdat); if (retval != ERROR_OK) { command_print(CMD, "numicro chip_erase failed"); return retval; } command_print(CMD, "numicro chip_erase complete"); return ERROR_OK; } static const struct command_registration numicro_exec_command_handlers[] = { { .name = "read_isp", .handler = numicro_handle_read_isp_command, .usage = "address", .mode = COMMAND_EXEC, .help = "read flash through ISP.", }, { .name = "write_isp", .handler = numicro_handle_write_isp_command, .usage = "address value", .mode = COMMAND_EXEC, .help = "write flash through ISP.", }, { .name = "chip_erase", .handler = numicro_handle_chip_erase_command, .mode = COMMAND_EXEC, .help = "chip erase through ISP.", .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration numicro_command_handlers[] = { { .name = "numicro", .mode = COMMAND_ANY, .help = "numicro flash command group", .usage = "", .chain = numicro_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver numicro_flash = { .name = "numicro", .commands = numicro_command_handlers, .flash_bank_command = numicro_flash_bank_command, .erase = numicro_erase, .write = numicro_write, .read = default_flash_read, .probe = numicro_probe, .auto_probe = numicro_auto_probe, .erase_check = default_flash_blank_check, .protect_check = numicro_protect_check, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/ocl.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "ocl.h" #include <target/embeddedice.h> struct ocl_priv { struct arm_jtag *jtag_info; unsigned int buflen; unsigned int bufalign; }; /* flash_bank ocl 0 0 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(ocl_flash_bank_command) { struct arm7_9_common *arm7_9; struct ocl_priv *ocl; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; arm7_9 = target_to_arm7_9(bank->target); if (!is_arm7_9(arm7_9)) return ERROR_TARGET_INVALID; ocl = bank->driver_priv = malloc(sizeof(struct ocl_priv)); ocl->jtag_info = &arm7_9->jtag_info; ocl->buflen = 0; ocl->bufalign = 1; return ERROR_OK; } static int ocl_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct ocl_priv *ocl = bank->driver_priv; int retval; uint32_t dcc_buffer[3]; /* check preconditions */ if (bank->num_sectors == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_RUNNING) { LOG_ERROR("target has to be running to communicate with the loader"); return ERROR_TARGET_NOT_RUNNING; } if ((first == 0) && (last == bank->num_sectors - 1)) { dcc_buffer[0] = OCL_ERASE_ALL; retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) return retval; } else { dcc_buffer[0] = OCL_ERASE_BLOCK; dcc_buffer[1] = first; dcc_buffer[2] = last; retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 3); if (retval != ERROR_OK) return retval; } /* wait for response, fixed timeout of 1 s */ retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000); if (retval != ERROR_OK) return retval; /* receive response */ retval = embeddedice_receive(ocl->jtag_info, dcc_buffer + 1, 1); if (retval != ERROR_OK) return retval; if (dcc_buffer[1] != OCL_CMD_DONE) { if (dcc_buffer[0] == OCL_ERASE_ALL) LOG_ERROR("loader response to OCL_ERASE_ALL 0x%08" PRIx32 "", dcc_buffer[1]); else LOG_ERROR("loader response to OCL_ERASE_BLOCK 0x%08" PRIx32 "", dcc_buffer[1]); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int ocl_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct ocl_priv *ocl = bank->driver_priv; int retval; uint32_t *dcc_buffer; uint32_t *dcc_bufptr; int byteofs; int runlen; uint32_t chksum; int i; /* check preconditions */ if (ocl->buflen == 0 || ocl->bufalign == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_RUNNING) { LOG_ERROR("target has to be running to communicate with the loader"); return ERROR_TARGET_NOT_RUNNING; } /* allocate buffer for max. ocl buffer + overhead */ dcc_buffer = malloc(sizeof(uint32_t)*(ocl->buflen/4 + 3)); while (count) { if (count + (offset % ocl->bufalign) > ocl->buflen) runlen = ocl->buflen - (offset % ocl->bufalign); else runlen = count; dcc_buffer[0] = OCL_FLASH_BLOCK | runlen; dcc_buffer[1] = offset; dcc_bufptr = &dcc_buffer[2]; *dcc_bufptr = 0xffffffff; byteofs = (offset % ocl->bufalign) % 4; chksum = OCL_CHKS_INIT; /* copy data to DCC buffer in proper byte order and properly aligned */ for (i = 0; i < runlen; i++) { switch (byteofs++) { case 0: *dcc_bufptr &= *(buffer++) | 0xffffff00; break; case 1: *dcc_bufptr &= ((*(buffer++)) << 8) | 0xffff00ff; break; case 2: *dcc_bufptr &= ((*(buffer++)) << 16) | 0xff00ffff; break; case 3: *dcc_bufptr &= ((*(buffer++)) << 24) | 0x00ffffff; chksum ^= *(dcc_bufptr++); *dcc_bufptr = 0xffffffff; byteofs = 0; break; } } /* add the remaining word to checksum */ if (byteofs) chksum ^= *(dcc_bufptr++); *(dcc_bufptr++) = chksum; /* send the data */ retval = embeddedice_send(ocl->jtag_info, dcc_buffer, dcc_bufptr-dcc_buffer); if (retval != ERROR_OK) { free(dcc_buffer); return retval; } /* wait for response, fixed timeout of 1 s */ retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000); if (retval != ERROR_OK) { free(dcc_buffer); return retval; } /* receive response */ retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) { free(dcc_buffer); return retval; } if (dcc_buffer[0] != OCL_CMD_DONE) { LOG_ERROR("loader response to OCL_FLASH_BLOCK 0x%08" PRIx32 "", dcc_buffer[0]); free(dcc_buffer); return ERROR_FLASH_OPERATION_FAILED; } count -= runlen; offset += runlen; } free(dcc_buffer); return ERROR_OK; } static int ocl_probe(struct flash_bank *bank) { struct ocl_priv *ocl = bank->driver_priv; int retval; uint32_t dcc_buffer[1]; int sectsize; /* purge pending data in DCC */ embeddedice_receive(ocl->jtag_info, dcc_buffer, 1); dcc_buffer[0] = OCL_PROBE; retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) return retval; /* wait for response, fixed timeout of 1 s */ retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000); if (retval != ERROR_OK) return retval; /* receive response */ retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) return retval; if (dcc_buffer[0] != OCL_CMD_DONE) { LOG_ERROR("loader response to OCL_PROBE 0x%08" PRIx32 "", dcc_buffer[0]); return ERROR_FLASH_OPERATION_FAILED; } /* receive and fill in parameters, detection of loader is important, receive it one by one */ retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0); if (retval != ERROR_OK) return retval; retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) return retval; bank->base = dcc_buffer[0]; retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0); if (retval != ERROR_OK) return retval; retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) return retval; bank->size = dcc_buffer[0]; retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0); if (retval != ERROR_OK) return retval; retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) return retval; bank->num_sectors = dcc_buffer[0]; retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0); if (retval != ERROR_OK) return retval; retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) return retval; ocl->buflen = dcc_buffer[0] & 0xffff; ocl->bufalign = dcc_buffer[0] >> 16; bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector)*bank->num_sectors); if (bank->num_sectors == 0) { LOG_ERROR("number of sectors shall be non zero value"); return ERROR_FLASH_BANK_INVALID; } if (bank->size % bank->num_sectors) { LOG_ERROR("bank size not divisible by number of sectors"); return ERROR_FLASH_BANK_INVALID; } sectsize = bank->size / bank->num_sectors; for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = i * sectsize; bank->sectors[i].size = sectsize; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } if (ocl->bufalign == 0) ocl->bufalign = 1; if (ocl->buflen == 0) { LOG_ERROR("buflen shall be non zero value"); return ERROR_FLASH_BANK_INVALID; } if ((ocl->bufalign > ocl->buflen) || (ocl->buflen % ocl->bufalign)) { LOG_ERROR("buflen is not multiple of bufalign"); return ERROR_FLASH_BANK_INVALID; } if (ocl->buflen % 4) { LOG_ERROR("buflen shall be divisible by 4"); return ERROR_FLASH_BANK_INVALID; } return ERROR_OK; } static int ocl_auto_probe(struct flash_bank *bank) { struct ocl_priv *ocl = bank->driver_priv; if (ocl->buflen == 0 || ocl->bufalign == 0) return ERROR_FLASH_BANK_NOT_PROBED; return ERROR_OK; } const struct flash_driver ocl_flash = { .name = "ocl", .flash_bank_command = ocl_flash_bank_command, .erase = ocl_erase, .write = ocl_write, .read = default_flash_read, .probe = ocl_probe, .erase_check = default_flash_blank_check, .auto_probe = ocl_auto_probe, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/ocl.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_OCL_H #define OPENOCD_FLASH_NOR_OCL_H /* command/response mask */ #define OCL_CMD_MASK 0xFFFF0000L /* commands */ #define OCL_FLASH_BLOCK 0x0CFB0000L #define OCL_ERASE_BLOCK 0x0CEB0000L #define OCL_ERASE_ALL 0x0CEA0000L #define OCL_PROBE 0x0CBE0000L /* responses */ #define OCL_CMD_DONE 0x0ACD0000L #define OCL_CMD_ERR 0x0ACE0000L #define OCL_CHKS_FAIL 0x0ACF0000L #define OCL_BUFF_OVER 0x0AB00000L #define OCL_CHKS_INIT 0xC100CD0CL #endif /* OPENOCD_FLASH_NOR_OCL_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/pic32mx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by John McCarthy * * jgmcc@magma.ca * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/jtag.h> #include "imp.h" #include <target/algorithm.h> #include <target/mips32.h> #include <target/mips_m4k.h> #define PIC32MX_MANUF_ID 0x029 /* pic32mx memory locations */ #define PIC32MX_PHYS_RAM 0x00000000 #define PIC32MX_PHYS_PGM_FLASH 0x1D000000 #define PIC32MX_PHYS_PERIPHERALS 0x1F800000 #define PIC32MX_PHYS_BOOT_FLASH 0x1FC00000 /* * Translate Virtual and Physical addresses. * Note: These macros only work for KSEG0/KSEG1 addresses. */ #define virt2phys(v) ((v) & 0x1FFFFFFF) /* pic32mx configuration register locations */ #define PIC32MX_DEVCFG0_1XX_2XX 0xBFC00BFC #define PIC32MX_DEVCFG0 0xBFC02FFC #define PIC32MX_DEVCFG1 0xBFC02FF8 #define PIC32MX_DEVCFG2 0xBFC02FF4 #define PIC32MX_DEVCFG3 0xBFC02FF0 #define PIC32MX_DEVID 0xBF80F220 #define PIC32MX_BMXPFMSZ 0xBF882060 #define PIC32MX_BMXBOOTSZ 0xBF882070 #define PIC32MX_BMXDRMSZ 0xBF882040 /* pic32mx flash controller register locations */ #define PIC32MX_NVMCON 0xBF80F400 #define PIC32MX_NVMCONCLR 0xBF80F404 #define PIC32MX_NVMCONSET 0xBF80F408 #define PIC32MX_NVMCONINV 0xBF80F40C #define NVMCON_NVMWR (1 << 15) #define NVMCON_NVMWREN (1 << 14) #define NVMCON_NVMERR (1 << 13) #define NVMCON_LVDERR (1 << 12) #define NVMCON_LVDSTAT (1 << 11) #define NVMCON_OP_PFM_ERASE 0x5 #define NVMCON_OP_PAGE_ERASE 0x4 #define NVMCON_OP_ROW_PROG 0x3 #define NVMCON_OP_WORD_PROG 0x1 #define NVMCON_OP_NOP 0x0 #define PIC32MX_NVMKEY 0xBF80F410 #define PIC32MX_NVMADDR 0xBF80F420 #define PIC32MX_NVMADDRCLR 0xBF80F424 #define PIC32MX_NVMADDRSET 0xBF80F428 #define PIC32MX_NVMADDRINV 0xBF80F42C #define PIC32MX_NVMDATA 0xBF80F430 #define PIC32MX_NVMSRCADDR 0xBF80F440 /* flash unlock keys */ #define NVMKEY1 0xAA996655 #define NVMKEY2 0x556699AA #define MX_1XX_2XX 1 /* PIC32mx1xx/2xx */ #define MX_17X_27X 2 /* PIC32mx17x/27x */ struct pic32mx_flash_bank { bool probed; int dev_type; /* Default 0. 1 for Pic32MX1XX/2XX variant */ }; /* * DEVID values as per PIC32MX Flash Programming Specification Rev N */ static const struct pic32mx_devs_s { uint32_t devid; const char *name; } pic32mx_devs[] = { {0x04A07053, "110F016B"}, {0x04A09053, "110F016C"}, {0x04A0B053, "110F016D"}, {0x04A06053, "120F032B"}, {0x04A08053, "120F032C"}, {0x04A0A053, "120F032D"}, {0x04D07053, "130F064B"}, {0x04D09053, "130F064C"}, {0x04D0B053, "130F064D"}, {0x04D06053, "150F128B"}, {0x04D08053, "150F128C"}, {0x04D0A053, "150F128D"}, {0x06610053, "170F256B"}, {0x0661A053, "170F256D"}, {0x04A01053, "210F016B"}, {0x04A03053, "210F016C"}, {0x04A05053, "210F016D"}, {0x04A00053, "220F032B"}, {0x04A02053, "220F032C"}, {0x04A04053, "220F032D"}, {0x04D01053, "230F064B"}, {0x04D03053, "230F064C"}, {0x04D05053, "230F064D"}, {0x04D00053, "250F128B"}, {0x04D02053, "250F128C"}, {0x04D04053, "250F128D"}, {0x06600053, "270F256B"}, {0x0660A053, "270F256D"}, {0x05600053, "330F064H"}, {0x05601053, "330F064L"}, {0x05602053, "430F064H"}, {0x05603053, "430F064L"}, {0x0570C053, "350F128H"}, {0x0570D053, "350F128L"}, {0x0570E053, "450F128H"}, {0x0570F053, "450F128L"}, {0x05704053, "350F256H"}, {0x05705053, "350F256L"}, {0x05706053, "450F256H"}, {0x05707053, "450F256L"}, {0x05808053, "370F512H"}, {0x05809053, "370F512L"}, {0x0580A053, "470F512H"}, {0x0580B053, "470F512L"}, {0x00938053, "360F512L"}, {0x00934053, "360F256L"}, {0x0092D053, "340F128L"}, {0x0092A053, "320F128L"}, {0x00916053, "340F512H"}, {0x00912053, "340F256H"}, {0x0090D053, "340F128H"}, {0x0090A053, "320F128H"}, {0x00906053, "320F064H"}, {0x00902053, "320F032H"}, {0x00978053, "460F512L"}, {0x00974053, "460F256L"}, {0x0096D053, "440F128L"}, {0x00952053, "440F256H"}, {0x00956053, "440F512H"}, {0x0094D053, "440F128H"}, {0x00942053, "420F032H"}, {0x04307053, "795F512L"}, {0x0430E053, "795F512H"}, {0x04306053, "775F512L"}, {0x0430D053, "775F512H"}, {0x04312053, "775F256L"}, {0x04303053, "775F256H"}, {0x04417053, "764F128L"}, {0x0440B053, "764F128H"}, {0x04341053, "695F512L"}, {0x04325053, "695F512H"}, {0x04311053, "675F512L"}, {0x0430C053, "675F512H"}, {0x04305053, "675F256L"}, {0x0430B053, "675F256H"}, {0x04413053, "664F128L"}, {0x04407053, "664F128H"}, {0x04411053, "664F064L"}, {0x04405053, "664F064H"}, {0x0430F053, "575F512L"}, {0x04309053, "575F512H"}, {0x04333053, "575F256L"}, {0x04317053, "575F256H"}, {0x0440F053, "564F128L"}, {0x04403053, "564F128H"}, {0x0440D053, "564F064L"}, {0x04401053, "564F064H"}, {0x04400053, "534F064H"}, {0x0440C053, "534F064L"}, {0x00000000, NULL} }; /* flash bank pic32mx <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(pic32mx_flash_bank_command) { struct pic32mx_flash_bank *pic32mx_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; pic32mx_info = malloc(sizeof(struct pic32mx_flash_bank)); bank->driver_priv = pic32mx_info; pic32mx_info->probed = false; pic32mx_info->dev_type = 0; return ERROR_OK; } static uint32_t pic32mx_get_flash_status(struct flash_bank *bank) { struct target *target = bank->target; uint32_t status; target_read_u32(target, PIC32MX_NVMCON, &status); return status; } static uint32_t pic32mx_wait_status_busy(struct flash_bank *bank, int timeout) { uint32_t status; /* wait for busy to clear */ while (((status = pic32mx_get_flash_status(bank)) & NVMCON_NVMWR) && (timeout-- > 0)) { LOG_DEBUG("status: 0x%" PRIx32, status); alive_sleep(1); } if (timeout <= 0) LOG_DEBUG("timeout: status: 0x%" PRIx32, status); return status; } static int pic32mx_nvm_exec(struct flash_bank *bank, uint32_t op, uint32_t timeout) { struct target *target = bank->target; uint32_t status; target_write_u32(target, PIC32MX_NVMCON, NVMCON_NVMWREN | op); /* unlock flash registers */ target_write_u32(target, PIC32MX_NVMKEY, NVMKEY1); target_write_u32(target, PIC32MX_NVMKEY, NVMKEY2); /* start operation */ target_write_u32(target, PIC32MX_NVMCONSET, NVMCON_NVMWR); status = pic32mx_wait_status_busy(bank, timeout); /* lock flash registers */ target_write_u32(target, PIC32MX_NVMCONCLR, NVMCON_NVMWREN); return status; } static int pic32mx_protect_check(struct flash_bank *bank) { struct target *target = bank->target; struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv; uint32_t config0_address; uint32_t devcfg0; unsigned int s, num_pages; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } switch (pic32mx_info->dev_type) { case MX_1XX_2XX: case MX_17X_27X: config0_address = PIC32MX_DEVCFG0_1XX_2XX; break; default: config0_address = PIC32MX_DEVCFG0; break; } target_read_u32(target, config0_address, &devcfg0); if ((devcfg0 & (1 << 28)) == 0) /* code protect bit */ num_pages = 0xffff; /* All pages protected */ else if (virt2phys(bank->base) == PIC32MX_PHYS_BOOT_FLASH) { if (devcfg0 & (1 << 24)) num_pages = 0; /* All pages unprotected */ else num_pages = 0xffff; /* All pages protected */ } else { /* pgm flash */ switch (pic32mx_info->dev_type) { case MX_1XX_2XX: num_pages = (~devcfg0 >> 10) & 0x7f; break; case MX_17X_27X: num_pages = (~devcfg0 >> 10) & 0x1ff; break; default: num_pages = (~devcfg0 >> 12) & 0xff; break; } } for (s = 0; s < bank->num_sectors && s < num_pages; s++) bank->sectors[s].is_protected = 1; for (; s < bank->num_sectors; s++) bank->sectors[s].is_protected = 0; return ERROR_OK; } static int pic32mx_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; uint32_t status; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first == 0) && (last == (bank->num_sectors - 1)) && (virt2phys(bank->base) == PIC32MX_PHYS_PGM_FLASH)) { /* this will only erase the Program Flash (PFM), not the Boot Flash (BFM) * we need to use the MTAP to perform a full erase */ LOG_DEBUG("Erasing entire program flash"); status = pic32mx_nvm_exec(bank, NVMCON_OP_PFM_ERASE, 50); if (status & NVMCON_NVMERR) return ERROR_FLASH_OPERATION_FAILED; if (status & NVMCON_LVDERR) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } for (unsigned int i = first; i <= last; i++) { target_write_u32(target, PIC32MX_NVMADDR, virt2phys(bank->base + bank->sectors[i].offset)); status = pic32mx_nvm_exec(bank, NVMCON_OP_PAGE_ERASE, 10); if (status & NVMCON_NVMERR) return ERROR_FLASH_OPERATION_FAILED; if (status & NVMCON_LVDERR) return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int pic32mx_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } return ERROR_OK; } /* see contrib/loaders/flash/pic32mx.s for src */ static uint32_t pic32mx_flash_write_code[] = { /* write: */ 0x3C08AA99, /* lui $t0, 0xaa99 */ 0x35086655, /* ori $t0, 0x6655 */ 0x3C095566, /* lui $t1, 0x5566 */ 0x352999AA, /* ori $t1, 0x99aa */ 0x3C0ABF80, /* lui $t2, 0xbf80 */ 0x354AF400, /* ori $t2, 0xf400 */ 0x340B4003, /* ori $t3, $zero, 0x4003 */ 0x340C8000, /* ori $t4, $zero, 0x8000 */ /* write_row: */ 0x2CD30080, /* sltiu $s3, $a2, 128 */ 0x16600008, /* bne $s3, $zero, write_word */ 0x340D4000, /* ori $t5, $zero, 0x4000 */ 0xAD450020, /* sw $a1, 32($t2) */ 0xAD440040, /* sw $a0, 64($t2) */ 0x04110016, /* bal progflash */ 0x24840200, /* addiu $a0, $a0, 512 */ 0x24A50200, /* addiu $a1, $a1, 512 */ 0x1000FFF7, /* beq $zero, $zero, write_row */ 0x24C6FF80, /* addiu $a2, $a2, -128 */ /* write_word: */ 0x3C15A000, /* lui $s5, 0xa000 */ 0x36B50000, /* ori $s5, $s5, 0x0 */ 0x00952025, /* or $a0, $a0, $s5 */ 0x10000008, /* beq $zero, $zero, next_word */ 0x340B4001, /* ori $t3, $zero, 0x4001 */ /* prog_word: */ 0x8C940000, /* lw $s4, 0($a0) */ 0xAD540030, /* sw $s4, 48($t2) */ 0xAD450020, /* sw $a1, 32($t2) */ 0x04110009, /* bal progflash */ 0x24840004, /* addiu $a0, $a0, 4 */ 0x24A50004, /* addiu $a1, $a1, 4 */ 0x24C6FFFF, /* addiu $a2, $a2, -1 */ /* next_word: */ 0x14C0FFF8, /* bne $a2, $zero, prog_word */ 0x00000000, /* nop */ /* done: */ 0x10000002, /* beq $zero, $zero, exit */ 0x24040000, /* addiu $a0, $zero, 0 */ /* error: */ 0x26240000, /* addiu $a0, $s1, 0 */ /* exit: */ 0x7000003F, /* sdbbp */ /* progflash: */ 0xAD4B0000, /* sw $t3, 0($t2) */ 0xAD480010, /* sw $t0, 16($t2) */ 0xAD490010, /* sw $t1, 16($t2) */ 0xAD4C0008, /* sw $t4, 8($t2) */ /* waitflash: */ 0x8D500000, /* lw $s0, 0($t2) */ 0x020C8024, /* and $s0, $s0, $t4 */ 0x1600FFFD, /* bne $s0, $zero, waitflash */ 0x00000000, /* nop */ 0x00000000, /* nop */ 0x00000000, /* nop */ 0x00000000, /* nop */ 0x00000000, /* nop */ 0x8D510000, /* lw $s1, 0($t2) */ 0x30113000, /* andi $s1, $zero, 0x3000 */ 0x1620FFEF, /* bne $s1, $zero, error */ 0xAD4D0004, /* sw $t5, 4($t2) */ 0x03E00008, /* jr $ra */ 0x00000000 /* nop */ }; static int pic32mx_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[3]; uint32_t row_size; int retval = ERROR_OK; struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv; struct mips32_algorithm mips32_info; /* flash write code */ if (target_alloc_working_area(target, sizeof(pic32mx_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* Change values for counters and row size, depending on variant */ switch (pic32mx_info->dev_type) { case MX_1XX_2XX: case MX_17X_27X: /* 128 byte row */ pic32mx_flash_write_code[8] = 0x2CD30020; pic32mx_flash_write_code[14] = 0x24840080; pic32mx_flash_write_code[15] = 0x24A50080; pic32mx_flash_write_code[17] = 0x24C6FFE0; row_size = 128; break; default: /* 512 byte row */ pic32mx_flash_write_code[8] = 0x2CD30080; pic32mx_flash_write_code[14] = 0x24840200; pic32mx_flash_write_code[15] = 0x24A50200; pic32mx_flash_write_code[17] = 0x24C6FF80; row_size = 512; break; } uint8_t code[sizeof(pic32mx_flash_write_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(pic32mx_flash_write_code), pic32mx_flash_write_code); retval = target_write_buffer(target, write_algorithm->address, sizeof(code), code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } mips32_info.common_magic = MIPS32_COMMON_MAGIC; mips32_info.isa_mode = MIPS32_ISA_MIPS32; init_reg_param(®_params[0], "r4", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r5", 32, PARAM_OUT); init_reg_param(®_params[2], "r6", 32, PARAM_OUT); int row_offset = offset % row_size; uint8_t *new_buffer = NULL; if (row_offset && (count >= (row_size / 4))) { new_buffer = malloc(buffer_size); if (!new_buffer) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } memset(new_buffer, 0xff, row_offset); address -= row_offset; } else row_offset = 0; while (count > 0) { uint32_t status; uint32_t thisrun_count; if (row_offset) { thisrun_count = (count > ((buffer_size - row_offset) / 4)) ? ((buffer_size - row_offset) / 4) : count; memcpy(new_buffer + row_offset, buffer, thisrun_count * 4); retval = target_write_buffer(target, source->address, row_offset + thisrun_count * 4, new_buffer); if (retval != ERROR_OK) break; } else { thisrun_count = (count > (buffer_size / 4)) ? (buffer_size / 4) : count; retval = target_write_buffer(target, source->address, thisrun_count * 4, buffer); if (retval != ERROR_OK) break; } buf_set_u32(reg_params[0].value, 0, 32, virt2phys(source->address)); buf_set_u32(reg_params[1].value, 0, 32, virt2phys(address)); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count + row_offset / 4); retval = target_run_algorithm(target, 0, NULL, 3, reg_params, write_algorithm->address, 0, 10000, &mips32_info); if (retval != ERROR_OK) { LOG_ERROR("error executing pic32mx flash write algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; break; } status = buf_get_u32(reg_params[0].value, 0, 32); if (status & NVMCON_NVMERR) { LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (status & NVMCON_LVDERR) { LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status); retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count * 4; address += thisrun_count * 4; count -= thisrun_count; if (row_offset) { address += row_offset; row_offset = 0; } } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); free(new_buffer); return retval; } static int pic32mx_write_word(struct flash_bank *bank, uint32_t address, uint32_t word) { struct target *target = bank->target; target_write_u32(target, PIC32MX_NVMADDR, virt2phys(address)); target_write_u32(target, PIC32MX_NVMDATA, word); return pic32mx_nvm_exec(bank, NVMCON_OP_WORD_PROG, 5); } static int pic32mx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { uint32_t words_remaining = (count / 4); uint32_t bytes_remaining = (count & 0x00000003); uint32_t address = bank->base + offset; uint32_t bytes_written = 0; uint32_t status; int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_DEBUG("writing to flash at address " TARGET_ADDR_FMT " at offset 0x%8.8" PRIx32 " count: 0x%8.8" PRIx32 "", bank->base, offset, count); if (offset & 0x3) { LOG_WARNING("offset 0x%" PRIx32 "breaks required 4-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* multiple words (4-byte) to be programmed? */ if (words_remaining > 0) { /* try using a block write */ retval = pic32mx_write_block(bank, buffer, offset, words_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single dword accesses */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); } else if (retval == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("flash writing failed"); return retval; } } else { buffer += words_remaining * 4; address += words_remaining * 4; words_remaining = 0; } } while (words_remaining > 0) { uint32_t value; memcpy(&value, buffer + bytes_written, sizeof(uint32_t)); status = pic32mx_write_word(bank, address, value); if (status & NVMCON_NVMERR) { LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status); return ERROR_FLASH_OPERATION_FAILED; } if (status & NVMCON_LVDERR) { LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status); return ERROR_FLASH_OPERATION_FAILED; } bytes_written += 4; words_remaining--; address += 4; } if (bytes_remaining) { uint32_t value = 0xffffffff; memcpy(&value, buffer + bytes_written, bytes_remaining); status = pic32mx_write_word(bank, address, value); if (status & NVMCON_NVMERR) { LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status); return ERROR_FLASH_OPERATION_FAILED; } if (status & NVMCON_LVDERR) { LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status); return ERROR_FLASH_OPERATION_FAILED; } } return ERROR_OK; } static int pic32mx_probe(struct flash_bank *bank) { struct target *target = bank->target; struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv; struct mips32_common *mips32 = target->arch_info; struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int i; uint32_t num_pages = 0; uint32_t device_id; int page_size; pic32mx_info->probed = false; device_id = ejtag_info->idcode; LOG_INFO("device id = 0x%08" PRIx32 " (manuf 0x%03x dev 0x%04x, ver 0x%02x)", device_id, (unsigned)((device_id >> 1) & 0x7ff), (unsigned)((device_id >> 12) & 0xffff), (unsigned)((device_id >> 28) & 0xf)); if (((device_id >> 1) & 0x7ff) != PIC32MX_MANUF_ID) { LOG_WARNING("Cannot identify target as a PIC32MX family."); return ERROR_FLASH_OPERATION_FAILED; } /* Check for PIC32mx1xx/2xx */ for (i = 0; pic32mx_devs[i].name; i++) { if (pic32mx_devs[i].devid == (device_id & 0x0fffffff)) { if ((pic32mx_devs[i].name[0] == '1') || (pic32mx_devs[i].name[0] == '2')) pic32mx_info->dev_type = (pic32mx_devs[i].name[1] == '7') ? MX_17X_27X : MX_1XX_2XX; break; } } switch (pic32mx_info->dev_type) { case MX_1XX_2XX: case MX_17X_27X: page_size = 1024; break; default: page_size = 4096; break; } if (virt2phys(bank->base) == PIC32MX_PHYS_BOOT_FLASH) { /* 0x1FC00000: Boot flash size */ #if 0 /* for some reason this register returns 8k for the boot bank size * this does not match the docs, so for now set the boot bank at a * fixed 12k */ if (target_read_u32(target, PIC32MX_BMXBOOTSZ, &num_pages) != ERROR_OK) { LOG_WARNING("PIC32MX flash size failed, probe inaccurate - assuming 12k flash"); num_pages = (12 * 1024); } #else /* fixed 12k boot bank - see comments above */ switch (pic32mx_info->dev_type) { case MX_1XX_2XX: case MX_17X_27X: num_pages = (3 * 1024); break; default: num_pages = (12 * 1024); break; } #endif } else { /* read the flash size from the device */ if (target_read_u32(target, PIC32MX_BMXPFMSZ, &num_pages) != ERROR_OK) { switch (pic32mx_info->dev_type) { case MX_1XX_2XX: case MX_17X_27X: LOG_WARNING("PIC32MX flash size failed, probe inaccurate - assuming 32k flash"); num_pages = (32 * 1024); break; default: LOG_WARNING("PIC32MX flash size failed, probe inaccurate - assuming 512k flash"); num_pages = (512 * 1024); break; } } } LOG_INFO("flash size = %" PRIu32 " KiB", num_pages / 1024); free(bank->sectors); /* calculate numbers of pages */ num_pages /= page_size; bank->size = (num_pages * page_size); bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); for (i = 0; i < (int)num_pages; i++) { bank->sectors[i].offset = i * page_size; bank->sectors[i].size = page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } pic32mx_info->probed = true; return ERROR_OK; } static int pic32mx_auto_probe(struct flash_bank *bank) { struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv; if (pic32mx_info->probed) return ERROR_OK; return pic32mx_probe(bank); } static int pic32mx_info(struct flash_bank *bank, struct command_invocation *cmd) { struct target *target = bank->target; struct mips32_common *mips32 = target->arch_info; struct mips_ejtag *ejtag_info = &mips32->ejtag_info; uint32_t device_id; device_id = ejtag_info->idcode; if (((device_id >> 1) & 0x7ff) != PIC32MX_MANUF_ID) { command_print_sameline(cmd, "Cannot identify target as a PIC32MX family (manufacturer 0x%03x != 0x%03x)\n", (unsigned)((device_id >> 1) & 0x7ff), PIC32MX_MANUF_ID); return ERROR_FLASH_OPERATION_FAILED; } int i; for (i = 0; pic32mx_devs[i].name; i++) { if (pic32mx_devs[i].devid == (device_id & 0x0fffffff)) { command_print_sameline(cmd, "PIC32MX%s", pic32mx_devs[i].name); break; } } if (!pic32mx_devs[i].name) command_print_sameline(cmd, "Unknown"); command_print_sameline(cmd, " Ver: 0x%02x", (unsigned)((device_id >> 28) & 0xf)); return ERROR_OK; } COMMAND_HANDLER(pic32mx_handle_pgm_word_command) { uint32_t address, value; int status, res; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 2, &bank); if (retval != ERROR_OK) return retval; if (address < bank->base || address >= (bank->base + bank->size)) { command_print(CMD, "flash address '%s' is out of bounds", CMD_ARGV[0]); return ERROR_OK; } res = ERROR_OK; status = pic32mx_write_word(bank, address, value); if (status & NVMCON_NVMERR) res = ERROR_FLASH_OPERATION_FAILED; if (status & NVMCON_LVDERR) res = ERROR_FLASH_OPERATION_FAILED; if (res == ERROR_OK) command_print(CMD, "pic32mx pgm word complete"); else command_print(CMD, "pic32mx pgm word failed (status = 0x%x)", status); return ERROR_OK; } COMMAND_HANDLER(pic32mx_handle_unlock_command) { struct target *target = NULL; struct mips_m4k_common *mips_m4k; struct mips_ejtag *ejtag_info; int timeout = 10; if (CMD_ARGC < 1) { command_print(CMD, "pic32mx unlock <bank>"); return ERROR_COMMAND_SYNTAX_ERROR; } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; target = bank->target; mips_m4k = target_to_m4k(target); ejtag_info = &mips_m4k->mips32.ejtag_info; /* we have to use the MTAP to perform a full erase */ mips_ejtag_set_instr(ejtag_info, MTAP_SW_MTAP); mips_ejtag_set_instr(ejtag_info, MTAP_COMMAND); /* first check status of device */ uint8_t mchip_cmd = MCHP_STATUS; mips_ejtag_drscan_8(ejtag_info, &mchip_cmd); if (mchip_cmd & (1 << 7)) { /* device is not locked */ command_print(CMD, "pic32mx is already unlocked, erasing anyway"); } /* unlock/erase device */ mips_ejtag_drscan_8_out(ejtag_info, MCHP_ASERT_RST); jtag_add_sleep(200); mips_ejtag_drscan_8_out(ejtag_info, MCHP_ERASE); do { mchip_cmd = MCHP_STATUS; mips_ejtag_drscan_8(ejtag_info, &mchip_cmd); if (timeout-- == 0) { LOG_DEBUG("timeout waiting for unlock: 0x%" PRIx8 "", mchip_cmd); break; } alive_sleep(1); } while ((mchip_cmd & (1 << 2)) || (!(mchip_cmd & (1 << 3)))); mips_ejtag_drscan_8_out(ejtag_info, MCHP_DE_ASSERT_RST); /* select ejtag tap */ mips_ejtag_set_instr(ejtag_info, MTAP_SW_ETAP); command_print(CMD, "pic32mx unlocked.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect."); return ERROR_OK; } static const struct command_registration pic32mx_exec_command_handlers[] = { { .name = "pgm_word", .usage = "<addr> <value> <bank>", .handler = pic32mx_handle_pgm_word_command, .mode = COMMAND_EXEC, .help = "program a word", }, { .name = "unlock", .handler = pic32mx_handle_unlock_command, .mode = COMMAND_EXEC, .usage = "[bank_id]", .help = "Unlock/Erase entire device.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration pic32mx_command_handlers[] = { { .name = "pic32mx", .mode = COMMAND_ANY, .help = "pic32mx flash command group", .usage = "", .chain = pic32mx_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver pic32mx_flash = { .name = "pic32mx", .commands = pic32mx_command_handlers, .flash_bank_command = pic32mx_flash_bank_command, .erase = pic32mx_erase, .protect = pic32mx_protect, .write = pic32mx_write, .read = default_flash_read, .probe = pic32mx_probe, .auto_probe = pic32mx_auto_probe, .erase_check = default_flash_blank_check, .protect_check = pic32mx_protect_check, .info = pic32mx_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/psoc4.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * * * * Copyright (C) 2014 by Tomas Vanek (PSoC 4 support derived from STM32) * * vanekt@fbl.cz * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <jtag/jtag.h> #include <target/algorithm.h> #include <target/armv7m.h> /* device documents: PSoC(R) 4: PSoC 4200 Family Datasheet Document Number: 001-87197 Rev. *B Revised August 29, 2013 PSoC 4100/4200 Family PSoC(R) 4 Architecture TRM Document No. 001-85634 Rev. *E June 28, 2016 PSoC(R) 4 Registers TRM Spec. Document No. 001-85847 Rev. *A June 25, 2013 PSoC 4000 Family PSoC(R) 4 Technical Reference Manual Document No. 001-89309 Rev. *B May 9, 2016 PSoC 41XX_BLE/42XX_BLE Family PSoC 4 BLE Architecture TRM Document No. 001-92738 Rev. *C February 12, 2016 PSoC 4200L Family PSoC 4 Architecture TRM Document No. 001-97952 Rev. *A December 15, 2015 PSoC 4200L Family PSoC 4 Registers TRM Document No. 001-98126 Rev. *A December 16, 2015 PSoC 4100M/4200M Family PSoC 4 Architecture TRM Document No. 001-95223 Rev. *B July 29, 2015 PSoC 4100S Family PSoC 4 Architecture TRM Document No. 002-10621 Rev. *A July 29, 2016 PSoC 4100S Family PSoC 4 Registers TRM Document No. 002-10523 Rev. *A July 20, 2016 PSoC Analog Coprocessor Architecture TRM Document No. 002-10404 Rev. ** December 18, 2015 CY8C4Axx PSoC Analog Coprocessor Registers TRM Document No. 002-10405 Rev. ** December 18, 2015 CY8C41xx, CY8C42xx Programming Specifications Document No. 001-81799 Rev. *C March 4, 2014 CYBL10x6x, CY8C4127_BL, CY8C4247_BL Programming Specifications Document No. 001-91508 Rev. *B September 22, 2014 http://dmitry.gr/index.php?r=05.Projects&proj=24.%20PSoC4%20confidential */ /* register locations */ #define PSOC4_SFLASH_MACRO0 0x0FFFF000 #define PSOC4_CPUSS_SYSREQ_LEGACY 0x40000004 #define PSOC4_CPUSS_SYSARG_LEGACY 0x40000008 #define PSOC4_SPCIF_GEOMETRY_LEGACY 0x400E0000 #define PSOC4_CPUSS_SYSREQ_NEW 0x40100004 #define PSOC4_CPUSS_SYSARG_NEW 0x40100008 #define PSOC4_SPCIF_GEOMETRY_NEW 0x40110000 #define PSOC4_TEST_MODE 0x40030014 #define PSOC4_ROMTABLE_PID0 0xF0000FE0 /* constants */ #define PSOC4_SFLASH_MACRO_SIZE 0x800 #define PSOC4_ROWS_PER_MACRO 512 #define PSOC4_SROM_KEY1 0xb6 #define PSOC4_SROM_KEY2 0xd3 #define PSOC4_SROM_SYSREQ_BIT (1<<31) #define PSOC4_SROM_HMASTER_BIT (1<<30) #define PSOC4_SROM_PRIVILEGED_BIT (1<<28) #define PSOC4_SROM_STATUS_SUCCEEDED 0xa0000000 #define PSOC4_SROM_STATUS_FAILED 0xf0000000 #define PSOC4_SROM_STATUS_MASK 0xf0000000 /* not documented in any TRM */ #define PSOC4_SROM_ERR_IMO_NOT_IMPLEM 0xf0000013 #define PSOC4_CMD_GET_SILICON_ID 0 #define PSOC4_CMD_LOAD_LATCH 4 #define PSOC4_CMD_WRITE_ROW 5 #define PSOC4_CMD_PROGRAM_ROW 6 #define PSOC4_CMD_ERASE_ALL 0xa #define PSOC4_CMD_CHECKSUM 0xb #define PSOC4_CMD_WRITE_PROTECTION 0xd #define PSOC4_CMD_SET_IMO48 0x15 #define PSOC4_CMD_WRITE_SFLASH_ROW 0x18 #define PSOC4_CHIP_PROT_VIRGIN 0x0 #define PSOC4_CHIP_PROT_OPEN 0x1 #define PSOC4_CHIP_PROT_PROTECTED 0x2 #define PSOC4_CHIP_PROT_KILL 0x4 #define PSOC4_ROMTABLE_DESIGNER_CHECK 0xb4 #define PSOC4_FAMILY_FLAG_LEGACY 1 struct psoc4_chip_family { uint16_t id; const char *name; uint32_t flags; }; static const struct psoc4_chip_family psoc4_families[] = { { 0x93, "PSoC4100/4200", .flags = PSOC4_FAMILY_FLAG_LEGACY }, { 0x9A, "PSoC4000", .flags = 0 }, { 0x9E, "PSoC/PRoC BLE (119E)", .flags = 0 }, { 0xA0, "PSoC4200L", .flags = 0 }, { 0xA1, "PSoC4100M/4200M", .flags = 0 }, { 0xA3, "PSoC/PRoC BLE (11A3)", .flags = 0 }, { 0xA9, "PSoC4000S", .flags = 0 }, { 0xAA, "PSoC/PRoC BLE (11AA)", .flags = 0 }, { 0xAB, "PSoC4100S", .flags = 0 }, { 0xAC, "PSoC Analog Coprocessor", .flags = 0 }, { 0, "Unknown", .flags = 0 } }; struct psoc4_flash_bank { uint32_t row_size; uint32_t user_bank_size; unsigned int num_macros; bool probed; uint8_t cmd_program_row; uint16_t family_id; bool legacy_family; uint32_t cpuss_sysreq_addr; uint32_t cpuss_sysarg_addr; uint32_t spcif_geometry_addr; }; static const struct psoc4_chip_family *psoc4_family_by_id(uint16_t family_id) { const struct psoc4_chip_family *p = psoc4_families; while (p->id && p->id != family_id) p++; return p; } static const char *psoc4_decode_chip_protection(uint8_t protection) { switch (protection) { case PSOC4_CHIP_PROT_VIRGIN: return "protection VIRGIN"; case PSOC4_CHIP_PROT_OPEN: return "protection open"; case PSOC4_CHIP_PROT_PROTECTED: return "PROTECTED"; case PSOC4_CHIP_PROT_KILL: return "protection KILL"; default: LOG_WARNING("Unknown protection state 0x%02" PRIx8 "", protection); return ""; } } /* flash bank <name> psoc <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(psoc4_flash_bank_command) { struct psoc4_flash_bank *psoc4_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; psoc4_info = calloc(1, sizeof(struct psoc4_flash_bank)); bank->driver_priv = psoc4_info; bank->default_padded_value = bank->erased_value = 0x00; psoc4_info->user_bank_size = bank->size; psoc4_info->cmd_program_row = PSOC4_CMD_WRITE_ROW; return ERROR_OK; } /* PSoC 4 system ROM request * Setting SROM_SYSREQ_BIT in CPUSS_SYSREQ register runs NMI service * in sysrem ROM. Algorithm just waits for NMI to finish. * When sysreq_params_size == 0 only one parameter is passed in CPUSS_SYSARG register. * Otherwise address of memory parameter block is set in CPUSS_SYSARG * and the first parameter is written to the first word of parameter block */ static int psoc4_sysreq(struct flash_bank *bank, uint8_t cmd, uint16_t cmd_param, uint32_t *sysreq_params, uint32_t sysreq_params_size, uint32_t *sysarg_out) { struct target *target = bank->target; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; struct working_area *sysreq_wait_algorithm; struct working_area *sysreq_mem; struct reg_param reg_params[1]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; uint32_t param1 = PSOC4_SROM_KEY1 | ((PSOC4_SROM_KEY2 + cmd) << 8) | (cmd_param << 16); static uint8_t psoc4_sysreq_wait_code[] = { /* system request NMI is served immediately after algo run now we are done: break */ 0x00, 0xbe, /* bkpt 0 */ }; const int code_words = (sizeof(psoc4_sysreq_wait_code) + 3) / 4; /* stack must be aligned */ const int stack_size = 256; /* tested stack sizes on PSoC4200: ERASE_ALL 144 PROGRAM_ROW 112 other sysreq 68 */ /* allocate area for sysreq wait code and stack */ if (target_alloc_working_area(target, code_words * 4 + stack_size, &sysreq_wait_algorithm) != ERROR_OK) { LOG_DEBUG("no working area for sysreq code"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* Write the code */ retval = target_write_buffer(target, sysreq_wait_algorithm->address, sizeof(psoc4_sysreq_wait_code), psoc4_sysreq_wait_code); if (retval != ERROR_OK) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ goto cleanup_algo; } if (sysreq_params_size) { LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32 " size %" PRIu32, cmd, cmd_param, param1, sysreq_params_size); /* Allocate memory for sysreq_params */ retval = target_alloc_working_area(target, sysreq_params_size, &sysreq_mem); if (retval != ERROR_OK) { LOG_WARNING("no working area for sysreq parameters"); /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; goto cleanup_algo; } /* Write sysreq_params */ target_buffer_set_u32(target, (uint8_t *)sysreq_params, param1); retval = target_write_buffer(target, sysreq_mem->address, sysreq_params_size, (uint8_t *)sysreq_params); if (retval != ERROR_OK) goto cleanup_mem; /* Set address of sysreq parameters block */ retval = target_write_u32(target, psoc4_info->cpuss_sysarg_addr, sysreq_mem->address); if (retval != ERROR_OK) goto cleanup_mem; } else { /* Sysreq without memory block of parameters */ LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32, cmd, cmd_param, param1); /* Set register parameter */ retval = target_write_u32(target, psoc4_info->cpuss_sysarg_addr, param1); if (retval != ERROR_OK) goto cleanup_mem; } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; /* sysreq stack */ init_reg_param(®_params[0], "sp", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, sysreq_wait_algorithm->address + sysreq_wait_algorithm->size); struct armv7m_common *armv7m = target_to_armv7m(target); if (!armv7m) { /* something is very wrong if armv7m is NULL */ LOG_ERROR("unable to get armv7m target"); retval = ERROR_FAIL; goto cleanup; } /* Set SROM request */ retval = target_write_u32(target, psoc4_info->cpuss_sysreq_addr, PSOC4_SROM_SYSREQ_BIT | PSOC4_SROM_HMASTER_BIT | cmd); if (retval != ERROR_OK) goto cleanup; /* Execute wait code */ retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, sysreq_wait_algorithm->address, 0, 1000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("sysreq wait code execution failed"); goto cleanup; } uint32_t sysarg_out_tmp; retval = target_read_u32(target, psoc4_info->cpuss_sysarg_addr, &sysarg_out_tmp); if (retval != ERROR_OK) goto cleanup; if (sysarg_out) { *sysarg_out = sysarg_out_tmp; /* If result is an error, do not show now, let caller to decide */ } else if ((sysarg_out_tmp & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) { LOG_ERROR("sysreq error 0x%" PRIx32, sysarg_out_tmp); retval = ERROR_FAIL; } cleanup: destroy_reg_param(®_params[0]); cleanup_mem: if (sysreq_params_size) target_free_working_area(target, sysreq_mem); cleanup_algo: target_free_working_area(target, sysreq_wait_algorithm); return retval; } /* helper routine to get silicon ID from a PSoC 4 chip */ static int psoc4_get_silicon_id(struct flash_bank *bank, uint32_t *silicon_id, uint16_t *family_id, uint8_t *protection) { struct target *target = bank->target; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; uint32_t part0, part1; int retval = psoc4_sysreq(bank, PSOC4_CMD_GET_SILICON_ID, 0, NULL, 0, &part0); if (retval != ERROR_OK) return retval; if ((part0 & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) { LOG_ERROR("sysreq error 0x%" PRIx32, part0); return ERROR_FAIL; } retval = target_read_u32(target, psoc4_info->cpuss_sysreq_addr, &part1); if (retval != ERROR_OK) return retval; /* build ID as Cypress sw does: * bit 31..16 silicon ID * bit 15..8 revision ID (so far 0x11 for all devices) * bit 7..0 family ID (lowest 8 bits) */ if (silicon_id) *silicon_id = ((part0 & 0x0000ffff) << 16) | ((part0 & 0x00ff0000) >> 8) | (part1 & 0x000000ff); if (family_id) *family_id = part1 & 0x0fff; if (protection) *protection = (part1 >> 12) & 0x0f; return ERROR_OK; } static int psoc4_get_family(struct target *target, uint16_t *family_id) { int retval, i; uint32_t pidbf[3]; uint8_t pid[3]; retval = target_read_memory(target, PSOC4_ROMTABLE_PID0, 4, 3, (uint8_t *)pidbf); if (retval != ERROR_OK) return retval; for (i = 0; i < 3; i++) { uint32_t tmp = target_buffer_get_u32(target, (uint8_t *)(pidbf + i)); if (tmp & 0xffffff00) { LOG_ERROR("Unexpected data in ROMTABLE"); return ERROR_FAIL; } pid[i] = tmp & 0xff; } uint16_t family = pid[0] | ((pid[1] & 0xf) << 8); uint32_t designer = ((pid[1] & 0xf0) >> 4) | ((pid[2] & 0xf) << 4); if (designer != PSOC4_ROMTABLE_DESIGNER_CHECK) { LOG_ERROR("ROMTABLE designer is not Cypress"); return ERROR_FAIL; } *family_id = family; return ERROR_OK; } static int psoc4_flash_prepare(struct flash_bank *bank) { struct target *target = bank->target; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } uint16_t family_id; int retval; /* get family ID from SROM call */ retval = psoc4_get_silicon_id(bank, NULL, &family_id, NULL); if (retval != ERROR_OK) return retval; /* and check with family ID from ROMTABLE */ if (family_id != psoc4_info->family_id) { LOG_ERROR("Family mismatch"); return ERROR_FAIL; } if (!psoc4_info->legacy_family) { uint32_t sysreq_status; retval = psoc4_sysreq(bank, PSOC4_CMD_SET_IMO48, 0, NULL, 0, &sysreq_status); if (retval != ERROR_OK) return retval; if ((sysreq_status & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) { /* This undocumented error code is returned probably when * PSOC4_CMD_SET_IMO48 command is not implemented. * Can be safely ignored, programming works. */ if (sysreq_status == PSOC4_SROM_ERR_IMO_NOT_IMPLEM) LOG_INFO("PSOC4_CMD_SET_IMO48 is not implemented on this device."); else { LOG_ERROR("sysreq error 0x%" PRIx32, sysreq_status); return ERROR_FAIL; } } } return ERROR_OK; } static int psoc4_protect_check(struct flash_bank *bank) { struct target *target = bank->target; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; uint32_t prot_addr = PSOC4_SFLASH_MACRO0; int retval; uint8_t bf[PSOC4_ROWS_PER_MACRO/8]; unsigned int s = 0; for (unsigned int m = 0; m < psoc4_info->num_macros; m++, prot_addr += PSOC4_SFLASH_MACRO_SIZE) { retval = target_read_memory(target, prot_addr, 4, PSOC4_ROWS_PER_MACRO/32, bf); if (retval != ERROR_OK) return retval; for (unsigned int i = 0; i < PSOC4_ROWS_PER_MACRO && s < bank->num_sectors; i++, s++) bank->sectors[s].is_protected = bf[i/8] & (1 << (i%8)) ? 1 : 0; } return ERROR_OK; } static int psoc4_mass_erase(struct flash_bank *bank) { int retval = psoc4_flash_prepare(bank); if (retval != ERROR_OK) return retval; /* Call "Erase All" system ROM API */ uint32_t param = 0; return psoc4_sysreq(bank, PSOC4_CMD_ERASE_ALL, 0, ¶m, sizeof(param), NULL); } static int psoc4_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct psoc4_flash_bank *psoc4_info = bank->driver_priv; if (psoc4_info->cmd_program_row == PSOC4_CMD_WRITE_ROW) { LOG_INFO("Autoerase enabled, erase command ignored"); return ERROR_OK; } if ((first == 0) && (last == (bank->num_sectors - 1))) return psoc4_mass_erase(bank); LOG_ERROR("Only mass erase available! Consider using 'psoc4 flash_autoerase 0 on'"); return ERROR_FAIL; } static int psoc4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct target *target = bank->target; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; if (!psoc4_info->probed) return ERROR_FAIL; int retval = psoc4_flash_prepare(bank); if (retval != ERROR_OK) return retval; uint32_t *sysrq_buffer = NULL; const int param_sz = 8; int chip_prot = PSOC4_CHIP_PROT_OPEN; unsigned int i; unsigned int num_bits = bank->num_sectors; if (num_bits > PSOC4_ROWS_PER_MACRO) num_bits = PSOC4_ROWS_PER_MACRO; int prot_sz = num_bits / 8; sysrq_buffer = malloc(param_sz + prot_sz); if (!sysrq_buffer) { LOG_ERROR("no memory for row buffer"); return ERROR_FAIL; } for (i = first; i <= last && i < bank->num_sectors; i++) bank->sectors[i].is_protected = set; for (unsigned int m = 0, sect = 0; m < psoc4_info->num_macros; m++) { uint8_t *p = (uint8_t *)(sysrq_buffer + 2); memset(p, 0, prot_sz); for (i = 0; i < num_bits && sect < bank->num_sectors; i++, sect++) { if (bank->sectors[sect].is_protected) p[i/8] |= 1 << (i%8); } /* Call "Load Latch" system ROM API */ target_buffer_set_u32(target, (uint8_t *)(sysrq_buffer + 1), prot_sz - 1); retval = psoc4_sysreq(bank, PSOC4_CMD_LOAD_LATCH, 0 /* Byte number in latch from what to write */ | (m << 8), /* flash macro index */ sysrq_buffer, param_sz + prot_sz, NULL); if (retval != ERROR_OK) break; /* Call "Write Protection" system ROM API */ retval = psoc4_sysreq(bank, PSOC4_CMD_WRITE_PROTECTION, chip_prot | (m << 8), NULL, 0, NULL); if (retval != ERROR_OK) break; } free(sysrq_buffer); psoc4_protect_check(bank); return retval; } COMMAND_HANDLER(psoc4_handle_flash_autoerase_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; bool enable = psoc4_info->cmd_program_row == PSOC4_CMD_WRITE_ROW; if (CMD_ARGC >= 2) COMMAND_PARSE_ON_OFF(CMD_ARGV[1], enable); if (enable) { psoc4_info->cmd_program_row = PSOC4_CMD_WRITE_ROW; LOG_INFO("Flash auto-erase enabled, non mass erase commands will be ignored."); } else { psoc4_info->cmd_program_row = PSOC4_CMD_PROGRAM_ROW; LOG_INFO("Flash auto-erase disabled. Use psoc mass_erase before flash programming."); } return retval; } static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; uint32_t *sysrq_buffer = NULL; const int param_sz = 8; int retval = psoc4_flash_prepare(bank); if (retval != ERROR_OK) return retval; sysrq_buffer = malloc(param_sz + psoc4_info->row_size); if (!sysrq_buffer) { LOG_ERROR("no memory for row buffer"); return ERROR_FAIL; } uint8_t *row_buffer = (uint8_t *)sysrq_buffer + param_sz; uint32_t row_num = offset / psoc4_info->row_size; uint32_t row_offset = offset - row_num * psoc4_info->row_size; if (row_offset) memset(row_buffer, bank->default_padded_value, row_offset); while (count) { uint32_t chunk_size = psoc4_info->row_size - row_offset; if (chunk_size > count) { chunk_size = count; memset(row_buffer + chunk_size, bank->default_padded_value, psoc4_info->row_size - chunk_size); } memcpy(row_buffer + row_offset, buffer, chunk_size); LOG_DEBUG("offset / row: 0x%08" PRIx32 " / %" PRIu32 ", size %" PRIu32 "", offset, row_offset, chunk_size); uint32_t macro_idx = row_num / PSOC4_ROWS_PER_MACRO; /* Call "Load Latch" system ROM API */ target_buffer_set_u32(target, (uint8_t *)(sysrq_buffer + 1), psoc4_info->row_size - 1); retval = psoc4_sysreq(bank, PSOC4_CMD_LOAD_LATCH, 0 /* Byte number in latch from what to write */ | (macro_idx << 8), sysrq_buffer, param_sz + psoc4_info->row_size, NULL); if (retval != ERROR_OK) goto cleanup; /* Call "Program Row" or "Write Row" system ROM API */ uint32_t sysrq_param; retval = psoc4_sysreq(bank, psoc4_info->cmd_program_row, row_num & 0xffff, &sysrq_param, sizeof(sysrq_param), NULL); if (retval != ERROR_OK) goto cleanup; buffer += chunk_size; row_num++; row_offset = 0; count -= chunk_size; } cleanup: free(sysrq_buffer); return retval; } /* Due to Cypress's method of market segmentation some devices * have accessible only 1/2, 1/4 or 1/8 of SPCIF described flash */ static int psoc4_test_flash_wounding(struct target *target, uint32_t flash_size) { int retval, i; for (i = 3; i >= 1; i--) { uint32_t addr = flash_size >> i; uint32_t dummy; retval = target_read_u32(target, addr, &dummy); if (retval != ERROR_OK) return i; } return 0; } static int psoc4_probe(struct flash_bank *bank) { struct psoc4_flash_bank *psoc4_info = bank->driver_priv; struct target *target = bank->target; int retval; uint16_t family_id; psoc4_info->probed = false; retval = psoc4_get_family(target, &family_id); if (retval != ERROR_OK) return retval; const struct psoc4_chip_family *family = psoc4_family_by_id(family_id); if (family->id == 0) { LOG_ERROR("Cannot identify PSoC 4 family."); return ERROR_FAIL; } if (family->flags & PSOC4_FAMILY_FLAG_LEGACY) { LOG_INFO("%s legacy family detected.", family->name); psoc4_info->legacy_family = true; psoc4_info->cpuss_sysreq_addr = PSOC4_CPUSS_SYSREQ_LEGACY; psoc4_info->cpuss_sysarg_addr = PSOC4_CPUSS_SYSARG_LEGACY; psoc4_info->spcif_geometry_addr = PSOC4_SPCIF_GEOMETRY_LEGACY; } else { LOG_INFO("%s family detected.", family->name); psoc4_info->legacy_family = false; psoc4_info->cpuss_sysreq_addr = PSOC4_CPUSS_SYSREQ_NEW; psoc4_info->cpuss_sysarg_addr = PSOC4_CPUSS_SYSARG_NEW; psoc4_info->spcif_geometry_addr = PSOC4_SPCIF_GEOMETRY_NEW; } uint32_t spcif_geometry; retval = target_read_u32(target, psoc4_info->spcif_geometry_addr, &spcif_geometry); if (retval != ERROR_OK) return retval; uint32_t flash_size_in_kb = spcif_geometry & 0x3fff; /* TRM of legacy, M and L version describes FLASH field as 16-bit. * S-series and PSoC Analog Coprocessor changes spec to 14-bit only. * Impose PSoC Analog Coprocessor limit to all devices as it * does not make any harm: flash size is safely below 4 MByte limit */ uint32_t row_size = (spcif_geometry >> 22) & 3; uint32_t num_macros = (spcif_geometry >> 20) & 3; if (psoc4_info->legacy_family) { flash_size_in_kb = flash_size_in_kb * 256 / 1024; row_size *= 128; } else { flash_size_in_kb = (flash_size_in_kb + 1) * 256 / 1024; row_size = 64 * (row_size + 1); num_macros++; } LOG_DEBUG("SPCIF geometry: %" PRIu32 " KiB flash, row %" PRIu32 " bytes.", flash_size_in_kb, row_size); /* if the user sets the size manually then ignore the probed value * this allows us to work around devices that have a invalid flash size register value */ if (psoc4_info->user_bank_size) { LOG_INFO("ignoring flash probed value, using configured bank size"); flash_size_in_kb = psoc4_info->user_bank_size / 1024; } char macros_txt[22] = ""; if (num_macros > 1) snprintf(macros_txt, sizeof(macros_txt), " in %" PRIu32 " macros", num_macros); LOG_INFO("flash size = %" PRIu32 " KiB%s", flash_size_in_kb, macros_txt); /* calculate number of pages */ uint32_t num_rows = flash_size_in_kb * 1024 / row_size; /* check number of flash macros */ if (num_macros != (num_rows + PSOC4_ROWS_PER_MACRO - 1) / PSOC4_ROWS_PER_MACRO) LOG_WARNING("Number of macros does not correspond with flash size!"); if (!psoc4_info->legacy_family) { int wounding = psoc4_test_flash_wounding(target, num_rows * row_size); if (wounding > 0) { flash_size_in_kb = flash_size_in_kb >> wounding; num_rows = num_rows >> wounding; LOG_INFO("WOUNDING detected: accessible flash size %" PRIu32 " kbytes", flash_size_in_kb); } } free(bank->sectors); psoc4_info->family_id = family_id; psoc4_info->num_macros = num_macros; psoc4_info->row_size = row_size; bank->base = 0x00000000; bank->size = num_rows * row_size; bank->num_sectors = num_rows; bank->sectors = alloc_block_array(0, row_size, num_rows); if (!bank->sectors) return ERROR_FAIL; LOG_DEBUG("flash bank set %" PRIu32 " rows", num_rows); psoc4_info->probed = true; return ERROR_OK; } static int psoc4_auto_probe(struct flash_bank *bank) { struct psoc4_flash_bank *psoc4_info = bank->driver_priv; if (psoc4_info->probed) return ERROR_OK; return psoc4_probe(bank); } static int get_psoc4_info(struct flash_bank *bank, struct command_invocation *cmd) { struct target *target = bank->target; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; if (!psoc4_info->probed) return ERROR_FAIL; const struct psoc4_chip_family *family = psoc4_family_by_id(psoc4_info->family_id); uint32_t size_in_kb = bank->size / 1024; if (target->state != TARGET_HALTED) { command_print_sameline(cmd, "%s, flash %" PRIu32 " kb" " (halt target to see details)", family->name, size_in_kb); return ERROR_OK; } uint32_t silicon_id; uint16_t family_id; uint8_t protection; int retval = psoc4_get_silicon_id(bank, &silicon_id, &family_id, &protection); if (retval != ERROR_OK) return retval; if (family_id != psoc4_info->family_id) command_print_sameline(cmd, "Family id mismatch 0x%02" PRIx16 "/0x%02" PRIx16 ", silicon id 0x%08" PRIx32, psoc4_info->family_id, family_id, silicon_id); else { command_print_sameline(cmd, "%s silicon id 0x%08" PRIx32 "", family->name, silicon_id); } const char *prot_txt = psoc4_decode_chip_protection(protection); command_print_sameline(cmd, ", flash %" PRIu32 " kb %s", size_in_kb, prot_txt); return ERROR_OK; } COMMAND_HANDLER(psoc4_handle_mass_erase_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = psoc4_mass_erase(bank); if (retval == ERROR_OK) command_print(CMD, "psoc mass erase complete"); else command_print(CMD, "psoc mass erase failed"); return retval; } static const struct command_registration psoc4_exec_command_handlers[] = { { .name = "mass_erase", .handler = psoc4_handle_mass_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Erase entire flash device.", }, { .name = "flash_autoerase", .handler = psoc4_handle_flash_autoerase_command, .mode = COMMAND_EXEC, .usage = "bank_id on|off", .help = "Set autoerase mode for flash bank.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration psoc4_command_handlers[] = { { .name = "psoc4", .mode = COMMAND_ANY, .help = "PSoC 4 flash command group", .usage = "", .chain = psoc4_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver psoc4_flash = { .name = "psoc4", .commands = psoc4_command_handlers, .flash_bank_command = psoc4_flash_bank_command, .erase = psoc4_erase, .protect = psoc4_protect, .write = psoc4_write, .read = default_flash_read, .probe = psoc4_probe, .auto_probe = psoc4_auto_probe, .erase_check = default_flash_blank_check, .protect_check = psoc4_protect_check, .info = get_psoc4_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/psoc5lp.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * PSoC 5LP flash driver * * Copyright (c) 2016 Andreas Färber */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/time_support.h> #include <target/armv7m.h> #define PM_ACT_CFG0 0x400043A0 #define PM_ACT_CFG12 0x400043AC #define SPC_CPU_DATA 0x40004720 #define SPC_SR 0x40004722 #define PRT1_PC2 0x4000500A #define PHUB_CH0_BASIC_CFG 0x40007010 #define PHUB_CH0_ACTION 0x40007014 #define PHUB_CH0_BASIC_STATUS 0x40007018 #define PHUB_CH1_BASIC_CFG 0x40007020 #define PHUB_CH1_ACTION 0x40007024 #define PHUB_CH1_BASIC_STATUS 0x40007028 #define PHUB_CFGMEM0_CFG0 0x40007600 #define PHUB_CFGMEM0_CFG1 0x40007604 #define PHUB_CFGMEM1_CFG0 0x40007608 #define PHUB_CFGMEM1_CFG1 0x4000760C #define PHUB_TDMEM0_ORIG_TD0 0x40007800 #define PHUB_TDMEM0_ORIG_TD1 0x40007804 #define PHUB_TDMEM1_ORIG_TD0 0x40007808 #define PHUB_TDMEM1_ORIG_TD1 0x4000780C #define PANTHER_DEVICE_ID 0x4008001C /* NVL is not actually mapped to the Cortex-M address space * As we need a base address different from other banks in the device * we use the address of NVL programming data in Cypress images */ #define NVL_META_BASE 0x90000000 #define PM_ACT_CFG12_EN_EE (1 << 4) #define SPC_KEY1 0xB6 #define SPC_KEY2 0xD3 #define SPC_LOAD_BYTE 0x00 #define SPC_LOAD_MULTI_BYTE 0x01 #define SPC_LOAD_ROW 0x02 #define SPC_READ_BYTE 0x03 #define SPC_READ_MULTI_BYTE 0x04 #define SPC_WRITE_ROW 0x05 #define SPC_WRITE_USER_NVL 0x06 #define SPC_PRG_ROW 0x07 #define SPC_ERASE_SECTOR 0x08 #define SPC_ERASE_ALL 0x09 #define SPC_READ_HIDDEN_ROW 0x0A #define SPC_PROGRAM_PROTECT_ROW 0x0B #define SPC_GET_CHECKSUM 0x0C #define SPC_GET_TEMP 0x0E #define SPC_READ_VOLATILE_BYTE 0x10 #define SPC_ARRAY_ALL 0x3F #define SPC_ARRAY_EEPROM 0x40 #define SPC_ARRAY_NVL_USER 0x80 #define SPC_ARRAY_NVL_WO 0xF8 #define SPC_ROW_PROTECTION 0 #define SPC_OPCODE_LEN 3 #define SPC_SR_DATA_READY (1 << 0) #define SPC_SR_IDLE (1 << 1) #define PM_ACT_CFG0_EN_CLK_SPC (1 << 3) #define PHUB_CHX_BASIC_CFG_EN (1 << 0) #define PHUB_CHX_BASIC_CFG_WORK_SEP (1 << 5) #define PHUB_CHX_ACTION_CPU_REQ (1 << 0) #define PHUB_CFGMEMX_CFG0 (1 << 7) #define PHUB_TDMEMX_ORIG_TD0_NEXT_TD_PTR_LAST (0xff << 16) #define PHUB_TDMEMX_ORIG_TD0_INC_SRC_ADDR (1 << 24) #define NVL_3_ECCEN (1 << 3) #define ROW_SIZE 256 #define ROW_ECC_SIZE 32 #define ROWS_PER_SECTOR 64 #define SECTOR_SIZE (ROWS_PER_SECTOR * ROW_SIZE) #define ROWS_PER_BLOCK 256 #define BLOCK_SIZE (ROWS_PER_BLOCK * ROW_SIZE) #define SECTORS_PER_BLOCK (BLOCK_SIZE / SECTOR_SIZE) #define EEPROM_ROW_SIZE 16 #define EEPROM_SECTOR_SIZE (ROWS_PER_SECTOR * EEPROM_ROW_SIZE) #define EEPROM_BLOCK_SIZE (ROWS_PER_BLOCK * EEPROM_ROW_SIZE) #define PART_NUMBER_LEN (17 + 1) struct psoc5lp_device { uint32_t id; unsigned fam; unsigned speed_mhz; unsigned flash_kb; unsigned eeprom_kb; }; /* * Device information collected from datasheets. * Different temperature ranges (C/I/Q/A) may share IDs, not differing otherwise. */ static const struct psoc5lp_device psoc5lp_devices[] = { /* CY8C58LP Family Datasheet */ { .id = 0x2E11F069, .fam = 8, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E120069, .fam = 8, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E123069, .fam = 8, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E124069, .fam = 8, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E126069, .fam = 8, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E127069, .fam = 8, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E117069, .fam = 8, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 }, { .id = 0x2E118069, .fam = 8, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 }, { .id = 0x2E119069, .fam = 8, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 }, { .id = 0x2E11C069, .fam = 8, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 }, { .id = 0x2E114069, .fam = 8, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 }, { .id = 0x2E115069, .fam = 8, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 }, { .id = 0x2E116069, .fam = 8, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 }, { .id = 0x2E160069, .fam = 8, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 }, /* '' */ { .id = 0x2E161069, .fam = 8, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 }, /* '' */ { .id = 0x2E1D2069, .fam = 8, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E1D6069, .fam = 8, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 }, /* CY8C56LP Family Datasheet */ { .id = 0x2E10A069, .fam = 6, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E10D069, .fam = 6, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E10E069, .fam = 6, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E106069, .fam = 6, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 }, { .id = 0x2E108069, .fam = 6, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 }, { .id = 0x2E109069, .fam = 6, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 }, { .id = 0x2E101069, .fam = 6, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 }, { .id = 0x2E104069, .fam = 6, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 }, /* '' */ { .id = 0x2E105069, .fam = 6, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 }, { .id = 0x2E128069, .fam = 6, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 }, /* '' */ { .id = 0x2E122069, .fam = 6, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E129069, .fam = 6, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 }, { .id = 0x2E163069, .fam = 6, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E156069, .fam = 6, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E1D3069, .fam = 6, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 }, /* CY8C54LP Family Datasheet */ { .id = 0x2E11A069, .fam = 4, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E16A069, .fam = 4, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E12A069, .fam = 4, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E103069, .fam = 4, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 }, { .id = 0x2E16C069, .fam = 4, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 }, { .id = 0x2E102069, .fam = 4, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 }, { .id = 0x2E148069, .fam = 4, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 }, { .id = 0x2E155069, .fam = 4, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 }, { .id = 0x2E16B069, .fam = 4, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 }, { .id = 0x2E12B069, .fam = 4, .speed_mhz = 67, .flash_kb = 32, .eeprom_kb = 2 }, { .id = 0x2E168069, .fam = 4, .speed_mhz = 67, .flash_kb = 32, .eeprom_kb = 2 }, { .id = 0x2E178069, .fam = 4, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E15D069, .fam = 4, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E1D4069, .fam = 4, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 }, /* CY8C52LP Family Datasheet */ { .id = 0x2E11E069, .fam = 2, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E12F069, .fam = 2, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E133069, .fam = 2, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 }, { .id = 0x2E159069, .fam = 2, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 }, { .id = 0x2E11D069, .fam = 2, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 }, { .id = 0x2E121069, .fam = 2, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 }, { .id = 0x2E184069, .fam = 2, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 }, { .id = 0x2E196069, .fam = 2, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 }, { .id = 0x2E132069, .fam = 2, .speed_mhz = 67, .flash_kb = 32, .eeprom_kb = 2 }, { .id = 0x2E138069, .fam = 2, .speed_mhz = 67, .flash_kb = 32, .eeprom_kb = 2 }, { .id = 0x2E13A069, .fam = 2, .speed_mhz = 67, .flash_kb = 32, .eeprom_kb = 2 }, { .id = 0x2E152069, .fam = 2, .speed_mhz = 67, .flash_kb = 32, .eeprom_kb = 2 }, { .id = 0x2E15F069, .fam = 2, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E15A069, .fam = 2, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 }, { .id = 0x2E1D5069, .fam = 2, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 }, }; static void psoc5lp_get_part_number(const struct psoc5lp_device *dev, char *str) { strcpy(str, "CY8Cabcdefg-LPxxx"); str[4] = '5'; str[5] = '0' + dev->fam; switch (dev->speed_mhz) { case 67: str[6] = '6'; break; case 80: str[6] = '8'; break; default: str[6] = '?'; } switch (dev->flash_kb) { case 32: str[7] = '5'; break; case 64: str[7] = '6'; break; case 128: str[7] = '7'; break; case 256: str[7] = '8'; break; default: str[7] = '?'; } /* Package does not matter. */ str[8] = 'x'; str[9] = 'x'; /* Temperate range cannot uniquely be identified. */ str[10] = 'x'; } static int psoc5lp_get_device_id(struct target *target, uint32_t *id) { int retval; retval = target_read_u32(target, PANTHER_DEVICE_ID, id); /* dummy read */ if (retval != ERROR_OK) return retval; retval = target_read_u32(target, PANTHER_DEVICE_ID, id); return retval; } static int psoc5lp_find_device(struct target *target, const struct psoc5lp_device **device) { uint32_t device_id; unsigned i; int retval; *device = NULL; retval = psoc5lp_get_device_id(target, &device_id); if (retval != ERROR_OK) return retval; LOG_DEBUG("PANTHER_DEVICE_ID = 0x%08" PRIX32, device_id); for (i = 0; i < ARRAY_SIZE(psoc5lp_devices); i++) { if (psoc5lp_devices[i].id == device_id) { *device = &psoc5lp_devices[i]; return ERROR_OK; } } LOG_ERROR("Device 0x%08" PRIX32 " not supported", device_id); return ERROR_FLASH_OPER_UNSUPPORTED; } static int psoc5lp_spc_enable_clock(struct target *target) { int retval; uint8_t pm_act_cfg0; retval = target_read_u8(target, PM_ACT_CFG0, &pm_act_cfg0); if (retval != ERROR_OK) { LOG_ERROR("Cannot read PM_ACT_CFG0"); return retval; } if (pm_act_cfg0 & PM_ACT_CFG0_EN_CLK_SPC) return ERROR_OK; /* clock already enabled */ retval = target_write_u8(target, PM_ACT_CFG0, pm_act_cfg0 | PM_ACT_CFG0_EN_CLK_SPC); if (retval != ERROR_OK) LOG_ERROR("Cannot enable SPC clock"); return retval; } static int psoc5lp_spc_write_opcode(struct target *target, uint8_t opcode) { int retval; retval = target_write_u8(target, SPC_CPU_DATA, SPC_KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, SPC_KEY2 + opcode); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, opcode); return retval; } static void psoc5lp_spc_write_opcode_buffer(struct target *target, uint8_t *buf, uint8_t opcode) { buf[0] = SPC_KEY1; buf[1] = SPC_KEY2 + opcode; buf[2] = opcode; } static int psoc5lp_spc_busy_wait_data(struct target *target) { int64_t endtime; uint8_t sr; int retval; retval = target_read_u8(target, SPC_SR, &sr); /* dummy read */ if (retval != ERROR_OK) return retval; endtime = timeval_ms() + 1000; /* 1 second timeout */ do { alive_sleep(1); retval = target_read_u8(target, SPC_SR, &sr); if (retval != ERROR_OK) return retval; if (sr == SPC_SR_DATA_READY) return ERROR_OK; } while (timeval_ms() < endtime); return ERROR_FLASH_OPERATION_FAILED; } static int psoc5lp_spc_busy_wait_idle(struct target *target) { int64_t endtime; uint8_t sr; int retval; retval = target_read_u8(target, SPC_SR, &sr); /* dummy read */ if (retval != ERROR_OK) return retval; endtime = timeval_ms() + 1000; /* 1 second timeout */ do { alive_sleep(1); retval = target_read_u8(target, SPC_SR, &sr); if (retval != ERROR_OK) return retval; if (sr == SPC_SR_IDLE) return ERROR_OK; } while (timeval_ms() < endtime); return ERROR_FLASH_OPERATION_FAILED; } static int psoc5lp_spc_load_byte(struct target *target, uint8_t array_id, uint8_t offset, uint8_t value) { int retval; retval = psoc5lp_spc_write_opcode(target, SPC_LOAD_BYTE); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, array_id); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, offset); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, value); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_busy_wait_idle(target); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int psoc5lp_spc_load_row(struct target *target, uint8_t array_id, const uint8_t *data, unsigned row_size) { unsigned i; int retval; retval = psoc5lp_spc_write_opcode(target, SPC_LOAD_ROW); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, array_id); if (retval != ERROR_OK) return retval; for (i = 0; i < row_size; i++) { retval = target_write_u8(target, SPC_CPU_DATA, data[i]); if (retval != ERROR_OK) return retval; } retval = psoc5lp_spc_busy_wait_idle(target); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int psoc5lp_spc_read_byte(struct target *target, uint8_t array_id, uint8_t offset, uint8_t *data) { int retval; retval = psoc5lp_spc_write_opcode(target, SPC_READ_BYTE); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, array_id); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, offset); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_busy_wait_data(target); if (retval != ERROR_OK) return retval; retval = target_read_u8(target, SPC_CPU_DATA, data); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_busy_wait_idle(target); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int psoc5lp_spc_write_row(struct target *target, uint8_t array_id, uint16_t row_id, const uint8_t *temp) { int retval; retval = psoc5lp_spc_write_opcode(target, SPC_WRITE_ROW); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, array_id); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, row_id >> 8); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, row_id & 0xff); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, temp[0]); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, temp[1]); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_busy_wait_idle(target); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int psoc5lp_spc_write_user_nvl(struct target *target, uint8_t array_id) { int retval; retval = psoc5lp_spc_write_opcode(target, SPC_WRITE_USER_NVL); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, array_id); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_busy_wait_idle(target); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int psoc5lp_spc_erase_sector(struct target *target, uint8_t array_id, uint8_t row_id) { int retval; retval = psoc5lp_spc_write_opcode(target, SPC_ERASE_SECTOR); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, array_id); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, row_id); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_busy_wait_idle(target); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int psoc5lp_spc_erase_all(struct target *target) { int retval; retval = psoc5lp_spc_write_opcode(target, SPC_ERASE_ALL); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_busy_wait_idle(target); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int psoc5lp_spc_read_hidden_row(struct target *target, uint8_t array_id, uint8_t row_id, uint8_t *data) { int i, retval; retval = psoc5lp_spc_write_opcode(target, SPC_READ_HIDDEN_ROW); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, array_id); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, row_id); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_busy_wait_data(target); if (retval != ERROR_OK) return retval; for (i = 0; i < ROW_SIZE; i++) { retval = target_read_u8(target, SPC_CPU_DATA, &data[i]); if (retval != ERROR_OK) return retval; } retval = psoc5lp_spc_busy_wait_idle(target); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int psoc5lp_spc_get_temp(struct target *target, uint8_t samples, uint8_t *data) { int retval; retval = psoc5lp_spc_write_opcode(target, SPC_GET_TEMP); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, samples); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_busy_wait_data(target); if (retval != ERROR_OK) return retval; retval = target_read_u8(target, SPC_CPU_DATA, &data[0]); if (retval != ERROR_OK) return retval; retval = target_read_u8(target, SPC_CPU_DATA, &data[1]); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_busy_wait_idle(target); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int psoc5lp_spc_read_volatile_byte(struct target *target, uint8_t array_id, uint8_t offset, uint8_t *data) { int retval; retval = psoc5lp_spc_write_opcode(target, SPC_READ_VOLATILE_BYTE); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, array_id); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, SPC_CPU_DATA, offset); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_busy_wait_data(target); if (retval != ERROR_OK) return retval; retval = target_read_u8(target, SPC_CPU_DATA, data); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_busy_wait_idle(target); if (retval != ERROR_OK) return retval; return ERROR_OK; } /* * NV Latch */ struct psoc5lp_nvl_flash_bank { bool probed; const struct psoc5lp_device *device; }; static int psoc5lp_nvl_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; retval = psoc5lp_spc_enable_clock(bank->target); if (retval != ERROR_OK) return retval; while (count > 0) { retval = psoc5lp_spc_read_byte(bank->target, SPC_ARRAY_NVL_USER, offset, buffer); if (retval != ERROR_OK) return retval; buffer++; offset++; count--; } return ERROR_OK; } static int psoc5lp_nvl_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { LOG_WARNING("There is no erase operation for NV Latches"); return ERROR_FLASH_OPER_UNSUPPORTED; } static int psoc5lp_nvl_erase_check(struct flash_bank *bank) { for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 0; return ERROR_OK; } static int psoc5lp_nvl_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t byte_count) { struct target *target = bank->target; uint8_t *current_data, val; bool write_required = false, pullup_needed = false, ecc_changed = false; uint32_t i; int retval; if (offset != 0 || byte_count != bank->size) { LOG_ERROR("NVL can only be written in whole"); return ERROR_FLASH_OPER_UNSUPPORTED; } current_data = calloc(1, bank->size); if (!current_data) return ERROR_FAIL; retval = psoc5lp_nvl_read(bank, current_data, offset, byte_count); if (retval != ERROR_OK) { free(current_data); return retval; } for (i = offset; i < byte_count; i++) { if (current_data[i] != buffer[i]) { write_required = true; break; } } if (((buffer[2] & 0x80) == 0x80) && ((current_data[0] & 0x0C) != 0x08)) pullup_needed = true; if (((buffer[3] ^ current_data[3]) & 0x08) == 0x08) ecc_changed = true; free(current_data); if (!write_required) { LOG_INFO("Unchanged, skipping NVL write"); return ERROR_OK; } if (pullup_needed) { retval = target_read_u8(target, PRT1_PC2, &val); if (retval != ERROR_OK) return retval; val &= 0xF0; val |= 0x05; retval = target_write_u8(target, PRT1_PC2, val); if (retval != ERROR_OK) return retval; } for (i = offset; i < byte_count; i++) { retval = psoc5lp_spc_load_byte(target, SPC_ARRAY_NVL_USER, i, buffer[i]); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_read_volatile_byte(target, SPC_ARRAY_NVL_USER, i, &val); if (retval != ERROR_OK) return retval; if (val != buffer[i]) { LOG_ERROR("Failed to load NVL byte %" PRIu32 ": " "expected 0x%02" PRIx8 ", read 0x%02" PRIx8, i, buffer[i], val); return ERROR_FLASH_OPERATION_FAILED; } } retval = psoc5lp_spc_write_user_nvl(target, SPC_ARRAY_NVL_USER); if (retval != ERROR_OK) return retval; if (ecc_changed) { retval = target_call_reset_callbacks(target, RESET_INIT); if (retval != ERROR_OK) LOG_WARNING("Reset failed after enabling or disabling ECC"); } return ERROR_OK; } static int psoc5lp_nvl_get_info_command(struct flash_bank *bank, struct command_invocation *cmd) { struct psoc5lp_nvl_flash_bank *psoc_nvl_bank = bank->driver_priv; char part_number[PART_NUMBER_LEN]; psoc5lp_get_part_number(psoc_nvl_bank->device, part_number); command_print_sameline(cmd, "%s", part_number); return ERROR_OK; } static int psoc5lp_nvl_probe(struct flash_bank *bank) { struct psoc5lp_nvl_flash_bank *psoc_nvl_bank = bank->driver_priv; int retval; if (psoc_nvl_bank->probed) return ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = psoc5lp_find_device(bank->target, &psoc_nvl_bank->device); if (retval != ERROR_OK) return retval; bank->base = NVL_META_BASE; bank->size = 4; bank->num_sectors = 1; bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); bank->sectors[0].offset = 0; bank->sectors[0].size = 4; bank->sectors[0].is_erased = -1; bank->sectors[0].is_protected = -1; psoc_nvl_bank->probed = true; return ERROR_OK; } static int psoc5lp_nvl_auto_probe(struct flash_bank *bank) { struct psoc5lp_nvl_flash_bank *psoc_nvl_bank = bank->driver_priv; if (psoc_nvl_bank->probed) return ERROR_OK; return psoc5lp_nvl_probe(bank); } FLASH_BANK_COMMAND_HANDLER(psoc5lp_nvl_flash_bank_command) { struct psoc5lp_nvl_flash_bank *psoc_nvl_bank; psoc_nvl_bank = malloc(sizeof(struct psoc5lp_nvl_flash_bank)); if (!psoc_nvl_bank) return ERROR_FLASH_OPERATION_FAILED; psoc_nvl_bank->probed = false; bank->driver_priv = psoc_nvl_bank; return ERROR_OK; } const struct flash_driver psoc5lp_nvl_flash = { .name = "psoc5lp_nvl", .flash_bank_command = psoc5lp_nvl_flash_bank_command, .info = psoc5lp_nvl_get_info_command, .probe = psoc5lp_nvl_probe, .auto_probe = psoc5lp_nvl_auto_probe, .read = psoc5lp_nvl_read, .erase = psoc5lp_nvl_erase, .erase_check = psoc5lp_nvl_erase_check, .write = psoc5lp_nvl_write, .free_driver_priv = default_flash_free_driver_priv, }; /* * EEPROM */ struct psoc5lp_eeprom_flash_bank { bool probed; const struct psoc5lp_device *device; }; static int psoc5lp_eeprom_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int retval; for (unsigned int i = first; i <= last; i++) { retval = psoc5lp_spc_erase_sector(bank->target, SPC_ARRAY_EEPROM, i); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int psoc5lp_eeprom_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t byte_count) { struct target *target = bank->target; uint8_t temp[2]; unsigned row; int retval; if (offset % EEPROM_ROW_SIZE != 0) { LOG_ERROR("Writes must be row-aligned, got offset 0x%08" PRIx32, offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } retval = psoc5lp_spc_get_temp(target, 3, temp); if (retval != ERROR_OK) { LOG_ERROR("Unable to read Die temperature"); return retval; } LOG_DEBUG("Get_Temp: sign 0x%02" PRIx8 ", magnitude 0x%02" PRIx8, temp[0], temp[1]); for (row = offset / EEPROM_ROW_SIZE; byte_count >= EEPROM_ROW_SIZE; row++) { retval = psoc5lp_spc_load_row(target, SPC_ARRAY_EEPROM, buffer, EEPROM_ROW_SIZE); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_write_row(target, SPC_ARRAY_EEPROM, row, temp); if (retval != ERROR_OK) return retval; buffer += EEPROM_ROW_SIZE; byte_count -= EEPROM_ROW_SIZE; offset += EEPROM_ROW_SIZE; } if (byte_count > 0) { uint8_t buf[EEPROM_ROW_SIZE]; memcpy(buf, buffer, byte_count); memset(buf + byte_count, bank->default_padded_value, EEPROM_ROW_SIZE - byte_count); LOG_DEBUG("Padding %" PRIu32 " bytes", EEPROM_ROW_SIZE - byte_count); retval = psoc5lp_spc_load_row(target, SPC_ARRAY_EEPROM, buf, EEPROM_ROW_SIZE); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_write_row(target, SPC_ARRAY_EEPROM, row, temp); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int psoc5lp_eeprom_get_info_command(struct flash_bank *bank, struct command_invocation *cmd) { struct psoc5lp_eeprom_flash_bank *psoc_eeprom_bank = bank->driver_priv; char part_number[PART_NUMBER_LEN]; psoc5lp_get_part_number(psoc_eeprom_bank->device, part_number); command_print_sameline(cmd, "%s", part_number); return ERROR_OK; } static int psoc5lp_eeprom_probe(struct flash_bank *bank) { struct psoc5lp_eeprom_flash_bank *psoc_eeprom_bank = bank->driver_priv; uint32_t flash_addr = bank->base; uint32_t val; int retval; if (psoc_eeprom_bank->probed) return ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = psoc5lp_find_device(bank->target, &psoc_eeprom_bank->device); if (retval != ERROR_OK) return retval; retval = target_read_u32(bank->target, PM_ACT_CFG12, &val); if (retval != ERROR_OK) return retval; if (!(val & PM_ACT_CFG12_EN_EE)) { val |= PM_ACT_CFG12_EN_EE; retval = target_write_u32(bank->target, PM_ACT_CFG12, val); if (retval != ERROR_OK) return retval; } bank->size = psoc_eeprom_bank->device->eeprom_kb * 1024; bank->num_sectors = DIV_ROUND_UP(bank->size, EEPROM_SECTOR_SIZE); bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].size = EEPROM_SECTOR_SIZE; bank->sectors[i].offset = flash_addr - bank->base; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; flash_addr += bank->sectors[i].size; } bank->default_padded_value = bank->erased_value = 0x00; psoc_eeprom_bank->probed = true; return ERROR_OK; } static int psoc5lp_eeprom_auto_probe(struct flash_bank *bank) { struct psoc5lp_eeprom_flash_bank *psoc_eeprom_bank = bank->driver_priv; if (psoc_eeprom_bank->probed) return ERROR_OK; return psoc5lp_eeprom_probe(bank); } FLASH_BANK_COMMAND_HANDLER(psoc5lp_eeprom_flash_bank_command) { struct psoc5lp_eeprom_flash_bank *psoc_eeprom_bank; psoc_eeprom_bank = malloc(sizeof(struct psoc5lp_eeprom_flash_bank)); if (!psoc_eeprom_bank) return ERROR_FLASH_OPERATION_FAILED; psoc_eeprom_bank->probed = false; psoc_eeprom_bank->device = NULL; bank->driver_priv = psoc_eeprom_bank; return ERROR_OK; } const struct flash_driver psoc5lp_eeprom_flash = { .name = "psoc5lp_eeprom", .flash_bank_command = psoc5lp_eeprom_flash_bank_command, .info = psoc5lp_eeprom_get_info_command, .probe = psoc5lp_eeprom_probe, .auto_probe = psoc5lp_eeprom_auto_probe, .read = default_flash_read, .erase = psoc5lp_eeprom_erase, .erase_check = default_flash_blank_check, .write = psoc5lp_eeprom_write, .free_driver_priv = default_flash_free_driver_priv, }; /* * Program Flash */ struct psoc5lp_flash_bank { bool probed; const struct psoc5lp_device *device; bool ecc_enabled; /* If ecc is disabled, num_sectors counts both std and ecc sectors. * If ecc is enabled, num_sectors indicates just the number of std sectors. * However ecc sector descriptors bank->sector[num_sectors..2*num_sectors-1] * are used for driver private flash operations */ }; static int psoc5lp_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct psoc5lp_flash_bank *psoc_bank = bank->driver_priv; int retval; if (!psoc_bank->ecc_enabled) { /* Silently avoid erasing sectors twice */ if (last >= first + bank->num_sectors / 2) { LOG_DEBUG("Skipping duplicate erase of sectors %u to %u", first + bank->num_sectors / 2, last); last = first + (bank->num_sectors / 2) - 1; } /* Check for any remaining ECC sectors */ if (last >= bank->num_sectors / 2) { LOG_WARNING("Skipping erase of ECC region sectors %u to %u", bank->num_sectors / 2, last); last = (bank->num_sectors / 2) - 1; } } for (unsigned int i = first; i <= last; i++) { retval = psoc5lp_spc_erase_sector(bank->target, i / SECTORS_PER_BLOCK, i % SECTORS_PER_BLOCK); if (retval != ERROR_OK) return retval; } return ERROR_OK; } /* Derived from core.c:default_flash_blank_check() */ static int psoc5lp_erase_check(struct flash_bank *bank) { struct psoc5lp_flash_bank *psoc_bank = bank->driver_priv; struct target *target = bank->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } unsigned int num_sectors = bank->num_sectors; if (psoc_bank->ecc_enabled) num_sectors *= 2; /* count both std and ecc sector always */ struct target_memory_check_block *block_array; block_array = malloc(num_sectors * sizeof(struct target_memory_check_block)); if (!block_array) return ERROR_FAIL; for (unsigned int i = 0; i < num_sectors; i++) { block_array[i].address = bank->base + bank->sectors[i].offset; block_array[i].size = bank->sectors[i].size; block_array[i].result = UINT32_MAX; /* erase state unknown */ } bool fast_check = true; for (unsigned int i = 0; i < num_sectors; ) { retval = armv7m_blank_check_memory(target, block_array + i, num_sectors - i, bank->erased_value); if (retval < 1) { /* Run slow fallback if the first run gives no result * otherwise use possibly incomplete results */ if (i == 0) fast_check = false; break; } i += retval; /* add number of blocks done this round */ } if (fast_check) { if (psoc_bank->ecc_enabled) { for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = (block_array[i].result != 1) ? block_array[i].result : block_array[i + bank->num_sectors].result; /* if std sector is erased, use status of ecc sector */ } else { for (unsigned int i = 0; i < num_sectors; i++) bank->sectors[i].is_erased = block_array[i].result; } retval = ERROR_OK; } else { LOG_ERROR("Can't run erase check - add working memory"); retval = ERROR_FAIL; } free(block_array); return retval; } static int psoc5lp_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t byte_count) { struct psoc5lp_flash_bank *psoc_bank = bank->driver_priv; struct target *target = bank->target; struct working_area *code_area, *even_row_area, *odd_row_area; uint32_t row_size; uint8_t temp[2], buf[12], ecc_bytes[ROW_ECC_SIZE]; unsigned array_id, row; int i, retval; if (offset + byte_count > bank->size) { LOG_ERROR("Writing to ECC not supported"); return ERROR_FLASH_DST_OUT_OF_BANK; } if (offset % ROW_SIZE != 0) { LOG_ERROR("Writes must be row-aligned, got offset 0x%08" PRIx32, offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } row_size = ROW_SIZE; if (!psoc_bank->ecc_enabled) { row_size += ROW_ECC_SIZE; memset(ecc_bytes, bank->default_padded_value, ROW_ECC_SIZE); } retval = psoc5lp_spc_get_temp(target, 3, temp); if (retval != ERROR_OK) { LOG_ERROR("Unable to read Die temperature"); return retval; } LOG_DEBUG("Get_Temp: sign 0x%02" PRIx8 ", magnitude 0x%02" PRIx8, temp[0], temp[1]); assert(target_get_working_area_avail(target) == target->working_area_size); retval = target_alloc_working_area(target, target_get_working_area_avail(target) / 2, &code_area); if (retval != ERROR_OK) { LOG_ERROR("Could not allocate working area for program SRAM"); return retval; } assert(code_area->address < 0x20000000); retval = target_alloc_working_area(target, SPC_OPCODE_LEN + 1 + row_size + 3 + SPC_OPCODE_LEN + 6, &even_row_area); if (retval != ERROR_OK) { LOG_ERROR("Could not allocate working area for even row"); goto err_alloc_even; } assert(even_row_area->address >= 0x20000000); retval = target_alloc_working_area(target, even_row_area->size, &odd_row_area); if (retval != ERROR_OK) { LOG_ERROR("Could not allocate working area for odd row"); goto err_alloc_odd; } assert(odd_row_area->address >= 0x20000000); for (array_id = offset / BLOCK_SIZE; byte_count > 0; array_id++) { for (row = (offset / ROW_SIZE) % ROWS_PER_BLOCK; row < ROWS_PER_BLOCK && byte_count > 0; row++) { bool even_row = (row % 2 == 0); struct working_area *data_area = even_row ? even_row_area : odd_row_area; unsigned len = MIN(ROW_SIZE, byte_count); LOG_DEBUG("Writing load command for array %u row %u at " TARGET_ADDR_FMT, array_id, row, data_area->address); psoc5lp_spc_write_opcode_buffer(target, buf, SPC_LOAD_ROW); buf[SPC_OPCODE_LEN] = array_id; retval = target_write_buffer(target, data_area->address, 4, buf); if (retval != ERROR_OK) goto err_write; retval = target_write_buffer(target, data_area->address + SPC_OPCODE_LEN + 1, len, buffer); if (retval != ERROR_OK) goto err_write; buffer += len; byte_count -= len; offset += len; if (len < ROW_SIZE) { uint8_t padding[ROW_SIZE]; memset(padding, bank->default_padded_value, ROW_SIZE); LOG_DEBUG("Padding %d bytes", ROW_SIZE - len); retval = target_write_buffer(target, data_area->address + SPC_OPCODE_LEN + 1 + len, ROW_SIZE - len, padding); if (retval != ERROR_OK) goto err_write; } if (!psoc_bank->ecc_enabled) { retval = target_write_buffer(target, data_area->address + SPC_OPCODE_LEN + 1 + ROW_SIZE, sizeof(ecc_bytes), ecc_bytes); if (retval != ERROR_OK) goto err_write; } for (i = 0; i < 3; i++) buf[i] = 0x00; /* 3 NOPs for short delay */ psoc5lp_spc_write_opcode_buffer(target, buf + 3, SPC_PRG_ROW); buf[3 + SPC_OPCODE_LEN] = array_id; buf[3 + SPC_OPCODE_LEN + 1] = row >> 8; buf[3 + SPC_OPCODE_LEN + 2] = row & 0xff; memcpy(buf + 3 + SPC_OPCODE_LEN + 3, temp, 2); buf[3 + SPC_OPCODE_LEN + 5] = 0x00; /* padding */ retval = target_write_buffer(target, data_area->address + SPC_OPCODE_LEN + 1 + row_size, 12, buf); if (retval != ERROR_OK) goto err_write; retval = target_write_u32(target, even_row ? PHUB_CH0_BASIC_STATUS : PHUB_CH1_BASIC_STATUS, (even_row ? 0 : 1) << 8); if (retval != ERROR_OK) goto err_dma; retval = target_write_u32(target, even_row ? PHUB_CH0_BASIC_CFG : PHUB_CH1_BASIC_CFG, PHUB_CHX_BASIC_CFG_WORK_SEP | PHUB_CHX_BASIC_CFG_EN); if (retval != ERROR_OK) goto err_dma; retval = target_write_u32(target, even_row ? PHUB_CFGMEM0_CFG0 : PHUB_CFGMEM1_CFG0, PHUB_CFGMEMX_CFG0); if (retval != ERROR_OK) goto err_dma; retval = target_write_u32(target, even_row ? PHUB_CFGMEM0_CFG1 : PHUB_CFGMEM1_CFG1, ((SPC_CPU_DATA >> 16) << 16) | (data_area->address >> 16)); if (retval != ERROR_OK) goto err_dma; retval = target_write_u32(target, even_row ? PHUB_TDMEM0_ORIG_TD0 : PHUB_TDMEM1_ORIG_TD0, PHUB_TDMEMX_ORIG_TD0_INC_SRC_ADDR | PHUB_TDMEMX_ORIG_TD0_NEXT_TD_PTR_LAST | ((SPC_OPCODE_LEN + 1 + row_size + 3 + SPC_OPCODE_LEN + 5) & 0xfff)); if (retval != ERROR_OK) goto err_dma; retval = target_write_u32(target, even_row ? PHUB_TDMEM0_ORIG_TD1 : PHUB_TDMEM1_ORIG_TD1, ((SPC_CPU_DATA & 0xffff) << 16) | (data_area->address & 0xffff)); if (retval != ERROR_OK) goto err_dma; retval = psoc5lp_spc_busy_wait_idle(target); if (retval != ERROR_OK) goto err_idle; retval = target_write_u32(target, even_row ? PHUB_CH0_ACTION : PHUB_CH1_ACTION, PHUB_CHX_ACTION_CPU_REQ); if (retval != ERROR_OK) goto err_dma_action; } } retval = psoc5lp_spc_busy_wait_idle(target); err_dma_action: err_idle: err_dma: err_write: target_free_working_area(target, odd_row_area); err_alloc_odd: target_free_working_area(target, even_row_area); err_alloc_even: target_free_working_area(target, code_area); return retval; } static int psoc5lp_protect_check(struct flash_bank *bank) { struct psoc5lp_flash_bank *psoc_bank = bank->driver_priv; uint8_t row_data[ROW_SIZE]; const unsigned protection_bytes_per_sector = ROWS_PER_SECTOR * 2 / 8; unsigned i, k, num_sectors; int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } for (i = 0; i < DIV_ROUND_UP(bank->size, BLOCK_SIZE); i++) { retval = psoc5lp_spc_read_hidden_row(bank->target, i, SPC_ROW_PROTECTION, row_data); if (retval != ERROR_OK) return retval; /* Last flash array may have less rows, but in practice full sectors. */ if (i == bank->size / BLOCK_SIZE) num_sectors = (bank->size % BLOCK_SIZE) / SECTOR_SIZE; else num_sectors = SECTORS_PER_BLOCK; for (unsigned int j = 0; j < num_sectors; j++) { int sector_nr = i * SECTORS_PER_BLOCK + j; struct flash_sector *sector = &bank->sectors[sector_nr]; struct flash_sector *ecc_sector; if (psoc_bank->ecc_enabled) ecc_sector = &bank->sectors[bank->num_sectors + sector_nr]; else ecc_sector = &bank->sectors[bank->num_sectors / 2 + sector_nr]; sector->is_protected = ecc_sector->is_protected = 0; for (k = protection_bytes_per_sector * j; k < protection_bytes_per_sector * (j + 1); k++) { assert(k < protection_bytes_per_sector * SECTORS_PER_BLOCK); LOG_DEBUG("row[%u][%02u] = 0x%02" PRIx8, i, k, row_data[k]); if (row_data[k] != 0x00) { sector->is_protected = ecc_sector->is_protected = 1; break; } } } } return ERROR_OK; } static int psoc5lp_get_info_command(struct flash_bank *bank, struct command_invocation *cmd) { struct psoc5lp_flash_bank *psoc_bank = bank->driver_priv; char part_number[PART_NUMBER_LEN]; const char *ecc; psoc5lp_get_part_number(psoc_bank->device, part_number); ecc = psoc_bank->ecc_enabled ? "ECC enabled" : "ECC disabled"; command_print_sameline(cmd, "%s %s", part_number, ecc); return ERROR_OK; } static int psoc5lp_probe(struct flash_bank *bank) { struct target *target = bank->target; struct psoc5lp_flash_bank *psoc_bank = bank->driver_priv; uint32_t flash_addr = bank->base; uint8_t nvl[4], temp[2]; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!psoc_bank->device) { retval = psoc5lp_find_device(target, &psoc_bank->device); if (retval != ERROR_OK) return retval; bank->size = psoc_bank->device->flash_kb * 1024; } bank->num_sectors = DIV_ROUND_UP(bank->size, SECTOR_SIZE); if (!psoc_bank->probed) { retval = psoc5lp_spc_enable_clock(target); if (retval != ERROR_OK) return retval; /* First values read are inaccurate, so do it once now. */ retval = psoc5lp_spc_get_temp(target, 3, temp); if (retval != ERROR_OK) { LOG_ERROR("Unable to read Die temperature"); return retval; } bank->sectors = calloc(bank->num_sectors * 2, sizeof(struct flash_sector)); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].size = SECTOR_SIZE; bank->sectors[i].offset = flash_addr - bank->base; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; flash_addr += bank->sectors[i].size; } flash_addr = 0x48000000; for (unsigned int i = bank->num_sectors; i < bank->num_sectors * 2; i++) { bank->sectors[i].size = ROWS_PER_SECTOR * ROW_ECC_SIZE; bank->sectors[i].offset = flash_addr - bank->base; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; flash_addr += bank->sectors[i].size; } bank->default_padded_value = bank->erased_value = 0x00; psoc_bank->probed = true; } retval = psoc5lp_spc_read_byte(target, SPC_ARRAY_NVL_USER, 3, &nvl[3]); if (retval != ERROR_OK) return retval; LOG_DEBUG("NVL[%d] = 0x%02" PRIx8, 3, nvl[3]); psoc_bank->ecc_enabled = nvl[3] & NVL_3_ECCEN; if (!psoc_bank->ecc_enabled) bank->num_sectors *= 2; return ERROR_OK; } static int psoc5lp_auto_probe(struct flash_bank *bank) { return psoc5lp_probe(bank); } COMMAND_HANDLER(psoc5lp_handle_mass_erase_command) { struct flash_bank *bank; int retval; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = psoc5lp_spc_erase_all(bank->target); if (retval == ERROR_OK) command_print(CMD, "PSoC 5LP erase succeeded"); else command_print(CMD, "PSoC 5LP erase failed"); return retval; } FLASH_BANK_COMMAND_HANDLER(psoc5lp_flash_bank_command) { struct psoc5lp_flash_bank *psoc_bank; psoc_bank = malloc(sizeof(struct psoc5lp_flash_bank)); if (!psoc_bank) return ERROR_FLASH_OPERATION_FAILED; psoc_bank->probed = false; psoc_bank->device = NULL; bank->driver_priv = psoc_bank; return ERROR_OK; } static const struct command_registration psoc5lp_exec_command_handlers[] = { { .name = "mass_erase", .handler = psoc5lp_handle_mass_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Erase all flash data and ECC/configuration bytes, " "all flash protection rows, " "and all row latches in all flash arrays on the device.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration psoc5lp_command_handlers[] = { { .name = "psoc5lp", .mode = COMMAND_ANY, .help = "PSoC 5LP flash command group", .usage = "", .chain = psoc5lp_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver psoc5lp_flash = { .name = "psoc5lp", .commands = psoc5lp_command_handlers, .flash_bank_command = psoc5lp_flash_bank_command, .info = psoc5lp_get_info_command, .probe = psoc5lp_probe, .auto_probe = psoc5lp_auto_probe, .protect_check = psoc5lp_protect_check, .read = default_flash_read, .erase = psoc5lp_erase, .erase_check = psoc5lp_erase_check, .write = psoc5lp_write, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/psoc6.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * * * Copyright (C) 2018 by Bohdan Tymkiv * * bohdan.tymkiv@cypress.com bohdan200@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <time.h> #include "imp.h" #include "helper/time_support.h" #include "target/arm_adi_v5.h" #include "target/target.h" #include "target/cortex_m.h" #include "target/breakpoints.h" #include "target/target_type.h" #include "target/algorithm.h" /************************************************************************************************** * PSoC6 device definitions *************************************************************************************************/ #define MFLASH_SECTOR_SIZE (256u * 1024u) #define WFLASH_SECTOR_SIZE (32u * 1024u) #define MEM_BASE_MFLASH 0x10000000u #define MEM_BASE_WFLASH 0x14000000u #define MEM_WFLASH_SIZE 32768u #define MEM_BASE_SFLASH 0x16000000u #define RAM_STACK_WA_SIZE 2048u #define PSOC6_SPCIF_GEOMETRY 0x4025F00Cu #define PROTECTION_UNKNOWN 0x00u #define PROTECTION_VIRGIN 0x01u #define PROTECTION_NORMAL 0x02u #define PROTECTION_SECURE 0x03u #define PROTECTION_DEAD 0x04u #define MEM_BASE_IPC 0x40230000u #define IPC_STRUCT_SIZE 0x20u #define MEM_IPC(n) (MEM_BASE_IPC + (n) * IPC_STRUCT_SIZE) #define MEM_IPC_ACQUIRE(n) (MEM_IPC(n) + 0x00u) #define MEM_IPC_NOTIFY(n) (MEM_IPC(n) + 0x08u) #define MEM_IPC_DATA(n) (MEM_IPC(n) + 0x0Cu) #define MEM_IPC_LOCK_STATUS(n) (MEM_IPC(n) + 0x10u) #define MEM_BASE_IPC_INTR 0x40231000u #define IPC_INTR_STRUCT_SIZE 0x20u #define MEM_IPC_INTR(n) (MEM_BASE_IPC_INTR + (n) * IPC_INTR_STRUCT_SIZE) #define MEM_IPC_INTR_MASK(n) (MEM_IPC_INTR(n) + 0x08u) #define IPC_ACQUIRE_SUCCESS_MSK 0x80000000u #define IPC_LOCK_ACQUIRED_MSK 0x80000000u #define IPC_ID 2u #define IPC_INTR_ID 0u #define IPC_TIMEOUT_MS 1000 #define SROMAPI_SIID_REQ 0x00000001u #define SROMAPI_SIID_REQ_FAMILY_REVISION (SROMAPI_SIID_REQ | 0x000u) #define SROMAPI_SIID_REQ_SIID_PROTECTION (SROMAPI_SIID_REQ | 0x100u) #define SROMAPI_WRITEROW_REQ 0x05000100u #define SROMAPI_PROGRAMROW_REQ 0x06000100u #define SROMAPI_ERASESECTOR_REQ 0x14000100u #define SROMAPI_ERASEALL_REQ 0x0A000100u #define SROMAPI_ERASEROW_REQ 0x1C000100u #define SROMAPI_STATUS_MSK 0xF0000000u #define SROMAPI_STAT_SUCCESS 0xA0000000u #define SROMAPI_DATA_LOCATION_MSK 0x00000001u #define SROMAPI_CALL_TIMEOUT_MS 1500 struct psoc6_target_info { uint32_t silicon_id; uint8_t protection; uint32_t main_flash_sz; uint32_t row_sz; bool is_probed; }; struct timeout { int64_t start_time; long timeout_ms; }; struct row_region { uint32_t addr; size_t size; }; static const struct row_region safe_sflash_regions[] = { {0x16000800, 0x800}, /* SFLASH: User Data */ {0x16001A00, 0x200}, /* SFLASH: NAR */ {0x16005A00, 0xC00}, /* SFLASH: Public Key */ {0x16007C00, 0x400}, /* SFLASH: TOC2 */ }; #define SFLASH_NUM_REGIONS ARRAY_SIZE(safe_sflash_regions) static struct working_area *g_stack_area; static struct armv7m_algorithm g_armv7m_info; /** *********************************************************************************************** * @brief Initializes `struct timeout` structure with given timeout value * @param to pointer to `struct timeout` structure * @param timeout_ms timeout, in milliseconds *************************************************************************************************/ static void timeout_init(struct timeout *to, long timeout_ms) { to->start_time = timeval_ms(); to->timeout_ms = timeout_ms; } /** *********************************************************************************************** * @brief Returns true if given `struct timeout` structure has expired * @param to pointer to `struct timeout` structure * @return true if timeout expired *************************************************************************************************/ static bool timeout_expired(struct timeout *to) { return (timeval_ms() - to->start_time) > to->timeout_ms; } /** *********************************************************************************************** * @brief Starts pseudo flash algorithm and leaves it running. Function allocates working area for * algorithm code and CPU stack, adjusts stack pointer, uploads and starts the algorithm. * Algorithm (a basic infinite loop) runs asynchronously while driver performs Flash operations. * * @param target target for the algorithm * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int sromalgo_prepare(struct target *target) { int hr; /* Initialize Vector Table Offset register (in case FW modified it) */ hr = target_write_u32(target, 0xE000ED08, 0x00000000); if (hr != ERROR_OK) return hr; /* Allocate Working Area for Stack and Flash algorithm */ hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &g_stack_area); if (hr != ERROR_OK) return hr; g_armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; g_armv7m_info.core_mode = ARM_MODE_THREAD; struct reg_param reg_params; init_reg_param(®_params, "sp", 32, PARAM_OUT); buf_set_u32(reg_params.value, 0, 32, g_stack_area->address + g_stack_area->size); /* Write basic infinite loop algorithm to target RAM */ hr = target_write_u32(target, g_stack_area->address, 0xFEE7FEE7); if (hr != ERROR_OK) goto destroy_rp_free_wa; hr = target_start_algorithm(target, 0, NULL, 1, ®_params, g_stack_area->address, 0, &g_armv7m_info); if (hr != ERROR_OK) goto destroy_rp_free_wa; destroy_reg_param(®_params); return hr; destroy_rp_free_wa: /* Something went wrong, do some cleanup */ destroy_reg_param(®_params); target_free_working_area(target, g_stack_area); g_stack_area = NULL; return hr; } /** *********************************************************************************************** * @brief Stops running flash algorithm and releases associated resources. * This function is also used for cleanup in case of errors so g_stack_area may be NULL. * These cases have to be handled gracefully. * * @param target current target *************************************************************************************************/ static void sromalgo_release(struct target *target) { int hr = ERROR_OK; if (g_stack_area) { /* Stop flash algorithm if it is running */ if (target->running_alg) { hr = target_halt(target); if (hr != ERROR_OK) goto exit_free_wa; hr = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, IPC_TIMEOUT_MS, &g_armv7m_info); if (hr != ERROR_OK) goto exit_free_wa; } exit_free_wa: /* Free Stack/Flash algorithm working area */ target_free_working_area(target, g_stack_area); g_stack_area = NULL; } } /** *********************************************************************************************** * @brief Waits for expected IPC lock status. PSoC6 uses IPC structures for inter-core * communication. Same IPCs are used to invoke SROM API. IPC structure must be locked prior to * invoking any SROM API. This ensures nothing else in the system will use same IPC thus corrupting * our data. Locking is performed by ipc_acquire(), this function ensures that IPC is actually * in expected state * * @param target current target * @param ipc_id IPC index to poll. IPC #2 is dedicated for DAP access * @param lock_expected expected lock status * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_expected) { int hr; uint32_t reg_val; struct timeout to; timeout_init(&to, IPC_TIMEOUT_MS); while (!timeout_expired(&to)) { /* Process any server requests */ keep_alive(); /* Read IPC Lock status */ hr = target_read_u32(target, MEM_IPC_LOCK_STATUS(ipc_id), ®_val); if (hr != ERROR_OK) { LOG_ERROR("Unable to read IPC Lock Status register"); return hr; } bool is_locked = (reg_val & IPC_LOCK_ACQUIRED_MSK) != 0; if (lock_expected == is_locked) return ERROR_OK; } if (target->coreid) { LOG_WARNING("SROM API calls via CM4 target are supported on single-core PSoC6 devices only. " "Please perform all Flash-related operations via CM0+ target on dual-core devices."); } LOG_ERROR("Timeout polling IPC Lock Status"); return ERROR_TARGET_TIMEOUT; } /** *********************************************************************************************** * @brief Acquires IPC structure. PSoC6 uses IPC structures for inter-core communication. * Same IPCs are used to invoke SROM API. IPC structure must be locked prior to invoking any SROM API. * This ensures nothing else in the system will use same IPC thus corrupting our data. * This function locks the IPC. * * @param target current target * @param ipc_id ipc_id IPC index to acquire. IPC #2 is dedicated for DAP access * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int ipc_acquire(struct target *target, char ipc_id) { int hr = ERROR_OK; bool is_acquired = false; uint32_t reg_val; struct timeout to; timeout_init(&to, IPC_TIMEOUT_MS); while (!timeout_expired(&to)) { keep_alive(); hr = target_write_u32(target, MEM_IPC_ACQUIRE(ipc_id), IPC_ACQUIRE_SUCCESS_MSK); if (hr != ERROR_OK) { LOG_ERROR("Unable to write to IPC Acquire register"); return hr; } /* Check if data is written on first step */ hr = target_read_u32(target, MEM_IPC_ACQUIRE(ipc_id), ®_val); if (hr != ERROR_OK) { LOG_ERROR("Unable to read IPC Acquire register"); return hr; } is_acquired = (reg_val & IPC_ACQUIRE_SUCCESS_MSK) != 0; if (is_acquired) { /* If IPC structure is acquired, the lock status should be set */ hr = ipc_poll_lock_stat(target, ipc_id, true); break; } } if (!is_acquired) LOG_ERROR("Timeout acquiring IPC structure"); return hr; } /** *********************************************************************************************** * @brief Invokes SROM API functions which are responsible for Flash operations * * @param target current target * @param req_and_params request id of the function to invoke * @param working_area address of memory buffer in target's memory space for SROM API parameters * @param data_out pointer to variable which will be populated with execution status * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int call_sromapi(struct target *target, uint32_t req_and_params, uint32_t working_area, uint32_t *data_out) { int hr; bool is_data_in_ram = (req_and_params & SROMAPI_DATA_LOCATION_MSK) == 0; hr = ipc_acquire(target, IPC_ID); if (hr != ERROR_OK) return hr; if (is_data_in_ram) hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), working_area); else hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), req_and_params); if (hr != ERROR_OK) return hr; /* Enable notification interrupt of IPC_INTR_STRUCT0(CM0+) for IPC_STRUCT2 */ hr = target_write_u32(target, MEM_IPC_INTR_MASK(IPC_INTR_ID), 1u << (16 + IPC_ID)); if (hr != ERROR_OK) return hr; hr = target_write_u32(target, MEM_IPC_NOTIFY(IPC_ID), 1); if (hr != ERROR_OK) return hr; /* Poll lock status */ hr = ipc_poll_lock_stat(target, IPC_ID, false); if (hr != ERROR_OK) return hr; /* Poll Data byte */ if (is_data_in_ram) hr = target_read_u32(target, working_area, data_out); else hr = target_read_u32(target, MEM_IPC_DATA(IPC_ID), data_out); if (hr != ERROR_OK) { LOG_ERROR("Error reading SROM API Status location"); return hr; } bool is_success = (*data_out & SROMAPI_STATUS_MSK) == SROMAPI_STAT_SUCCESS; if (!is_success) { LOG_ERROR("SROM API execution failed. Status: 0x%08" PRIX32, *data_out); return ERROR_TARGET_FAILURE; } return ERROR_OK; } /** *********************************************************************************************** * @brief Retrieves SiliconID and Protection status of the target device * @param target current target * @param si_id pointer to variable, will be populated with SiliconID * @param protection pointer to variable, will be populated with protection status * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int get_silicon_id(struct target *target, uint32_t *si_id, uint8_t *protection) { int hr; uint32_t family_rev, siid_prot; hr = sromalgo_prepare(target); if (hr != ERROR_OK) goto exit; /* Read FamilyID and Revision */ hr = call_sromapi(target, SROMAPI_SIID_REQ_FAMILY_REVISION, 0, &family_rev); if (hr != ERROR_OK) goto exit; /* Read SiliconID and Protection */ hr = call_sromapi(target, SROMAPI_SIID_REQ_SIID_PROTECTION, 0, &siid_prot); if (hr != ERROR_OK) goto exit; *si_id = (siid_prot & 0x0000FFFF) << 16; *si_id |= (family_rev & 0x00FF0000) >> 8; *si_id |= (family_rev & 0x000000FF) >> 0; *protection = (siid_prot & 0x000F0000) >> 0x10; exit: sromalgo_release(target); return ERROR_OK; } /** *********************************************************************************************** * @brief Translates Protection status to openocd-friendly boolean value * @param bank current flash bank * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_protect_check(struct flash_bank *bank) { int is_protected; struct psoc6_target_info *psoc6_info = bank->driver_priv; int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection); if (hr != ERROR_OK) return hr; switch (psoc6_info->protection) { case PROTECTION_VIRGIN: case PROTECTION_NORMAL: is_protected = 0; break; case PROTECTION_UNKNOWN: case PROTECTION_SECURE: case PROTECTION_DEAD: default: is_protected = 1; break; } for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = is_protected; return ERROR_OK; } /** *********************************************************************************************** * @brief Dummy function, Life Cycle transition is not currently supported * @return ERROR_OK always *************************************************************************************************/ static int psoc6_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { (void)bank; (void)set; (void)first; (void)last; LOG_WARNING("Life Cycle transition for PSoC6 is not supported"); return ERROR_OK; } /** *********************************************************************************************** * @brief Translates Protection status to string * @param protection protection value * @return pointer to const string describing protection status *************************************************************************************************/ static const char *protection_to_str(uint8_t protection) { switch (protection) { case PROTECTION_VIRGIN: return "VIRGIN"; case PROTECTION_NORMAL: return "NORMAL"; case PROTECTION_SECURE: return "SECURE"; case PROTECTION_DEAD: return "DEAD"; case PROTECTION_UNKNOWN: default: return "UNKNOWN"; } } /** *********************************************************************************************** * @brief psoc6_get_info Displays human-readable information about acquired device * @param bank current flash bank * @param cmd pointer to command invocation instance * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct psoc6_target_info *psoc6_info = bank->driver_priv; if (psoc6_info->is_probed == false) return ERROR_FAIL; int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection); if (hr != ERROR_OK) return hr; command_print_sameline(cmd, "PSoC6 Silicon ID: 0x%08" PRIX32 "\n" "Protection: %s\n" "Main Flash size: %" PRIu32 " kB\n" "Work Flash size: 32 kB\n", psoc6_info->silicon_id, protection_to_str(psoc6_info->protection), psoc6_info->main_flash_sz / 1024); return ERROR_OK; } /** *********************************************************************************************** * @brief Checks if given flash bank belongs to Supervisory Flash * @param bank current flash bank * @return true if flash bank belongs to Supervisory Flash *************************************************************************************************/ static bool is_sflash_bank(struct flash_bank *bank) { for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) { if (bank->base == safe_sflash_regions[i].addr) return true; } return false; } /** *********************************************************************************************** * @brief Checks if given flash bank belongs to Work Flash * @param bank current flash bank * @return true if flash bank belongs to Work Flash *************************************************************************************************/ static inline bool is_wflash_bank(struct flash_bank *bank) { return (bank->base == MEM_BASE_WFLASH); } /** *********************************************************************************************** * @brief Checks if given flash bank belongs to Main Flash * @param bank current flash bank * @return true if flash bank belongs to Main Flash *************************************************************************************************/ static inline bool is_mflash_bank(struct flash_bank *bank) { return (bank->base == MEM_BASE_MFLASH); } /** *********************************************************************************************** * @brief Probes the device and populates related data structures with target flash geometry data. * This is done in non-intrusive way, no SROM API calls are involved so GDB can safely attach to a * running target. Function assumes that size of Work Flash is 32kB (true for all current part numbers) * * @param bank current flash bank * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_probe(struct flash_bank *bank) { struct target *target = bank->target; struct psoc6_target_info *psoc6_info = bank->driver_priv; int hr = ERROR_OK; /* Retrieve data from SPCIF_GEOMETRY */ uint32_t geom; target_read_u32(target, PSOC6_SPCIF_GEOMETRY, &geom); uint32_t row_sz_lg2 = (geom & 0xF0) >> 4; uint32_t row_sz = (0x01 << row_sz_lg2); uint32_t row_cnt = 1 + ((geom & 0x00FFFF00) >> 8); uint32_t bank_cnt = 1 + ((geom & 0xFF000000) >> 24); /* Calculate size of Main Flash*/ uint32_t flash_sz_bytes = bank_cnt * row_cnt * row_sz; free(bank->sectors); bank->sectors = NULL; size_t bank_size = 0; if (is_mflash_bank(bank)) bank_size = flash_sz_bytes; else if (is_wflash_bank(bank)) bank_size = MEM_WFLASH_SIZE; else if (is_sflash_bank(bank)) { for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) { if (safe_sflash_regions[i].addr == bank->base) { bank_size = safe_sflash_regions[i].size; break; } } } if (bank_size == 0) { LOG_ERROR("Invalid Flash Bank base address in config file"); return ERROR_FLASH_BANK_INVALID; } unsigned int num_sectors = bank_size / row_sz; bank->size = bank_size; bank->erased_value = 0; bank->default_padded_value = 0; bank->num_sectors = num_sectors; bank->sectors = calloc(num_sectors, sizeof(struct flash_sector)); for (unsigned int i = 0; i < num_sectors; i++) { bank->sectors[i].size = row_sz; bank->sectors[i].offset = i * row_sz; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } psoc6_info->is_probed = true; psoc6_info->main_flash_sz = flash_sz_bytes; psoc6_info->row_sz = row_sz; return hr; } /** *********************************************************************************************** * @brief Probes target device only if it hasn't been probed yet * @param bank current flash bank * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_auto_probe(struct flash_bank *bank) { struct psoc6_target_info *psoc6_info = bank->driver_priv; int hr; if (psoc6_info->is_probed) hr = ERROR_OK; else hr = psoc6_probe(bank); return hr; } /** *********************************************************************************************** * @brief Erases single sector (256k) on target device * @param bank current flash bank * @param wa working area for SROM API parameters * @param addr starting address of the sector * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_erase_sector(struct flash_bank *bank, struct working_area *wa, uint32_t addr) { struct target *target = bank->target; LOG_DEBUG("Erasing SECTOR @%08" PRIX32, addr); int hr = target_write_u32(target, wa->address, SROMAPI_ERASESECTOR_REQ); if (hr != ERROR_OK) return hr; hr = target_write_u32(target, wa->address + 0x04, addr); if (hr != ERROR_OK) return hr; uint32_t data_out; hr = call_sromapi(target, SROMAPI_ERASESECTOR_REQ, wa->address, &data_out); if (hr != ERROR_OK) LOG_ERROR("SECTOR @%08" PRIX32 " not erased!", addr); return hr; } /** *********************************************************************************************** * @brief Erases single row (512b) on target device * @param bank current flash bank * @param wa working area for SROM API parameters * @param addr starting address of the flash row * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_erase_row(struct flash_bank *bank, struct working_area *wa, uint32_t addr) { struct target *target = bank->target; LOG_DEBUG("Erasing ROW @%08" PRIX32, addr); int hr = target_write_u32(target, wa->address, SROMAPI_ERASEROW_REQ); if (hr != ERROR_OK) return hr; hr = target_write_u32(target, wa->address + 0x04, addr); if (hr != ERROR_OK) return hr; uint32_t data_out; hr = call_sromapi(target, SROMAPI_ERASEROW_REQ, wa->address, &data_out); if (hr != ERROR_OK) LOG_ERROR("ROW @%08" PRIX32 " not erased!", addr); return hr; } /** *********************************************************************************************** * @brief Performs Erase operation. Function will try to use biggest erase block possible to * speedup the operation. * * @param bank current flash bank * @param first first sector to erase * @param last last sector to erase * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct psoc6_target_info *psoc6_info = bank->driver_priv; const uint32_t sector_size = is_wflash_bank(bank) ? WFLASH_SECTOR_SIZE : MFLASH_SECTOR_SIZE; int hr; struct working_area *wa; if (is_sflash_bank(bank)) { LOG_INFO("Erase operation on Supervisory Flash is not required, skipping"); return ERROR_OK; } hr = sromalgo_prepare(target); if (hr != ERROR_OK) goto exit; hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa); if (hr != ERROR_OK) goto exit; /* Number of rows in single sector */ const unsigned int rows_in_sector = sector_size / psoc6_info->row_sz; while (last >= first) { /* Erase Sector if we are on sector boundary and erase size covers whole sector */ if ((first % rows_in_sector) == 0 && (last - first + 1) >= rows_in_sector) { hr = psoc6_erase_sector(bank, wa, bank->base + first * psoc6_info->row_sz); if (hr != ERROR_OK) goto exit_free_wa; first += rows_in_sector; } else { /* Perform Row Erase otherwise */ hr = psoc6_erase_row(bank, wa, bank->base + first * psoc6_info->row_sz); if (hr != ERROR_OK) goto exit_free_wa; first += 1; } } exit_free_wa: target_free_working_area(target, wa); exit: sromalgo_release(target); return hr; } /** *********************************************************************************************** * @brief Programs single Flash Row * @param bank current flash bank * @param addr address of the flash row * @param buffer pointer to the buffer with data * @param is_sflash true if current flash bank belongs to Supervisory Flash * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_program_row(struct flash_bank *bank, uint32_t addr, const uint8_t *buffer, bool is_sflash) { struct target *target = bank->target; struct psoc6_target_info *psoc6_info = bank->driver_priv; struct working_area *wa; const uint32_t sromapi_req = is_sflash ? SROMAPI_WRITEROW_REQ : SROMAPI_PROGRAMROW_REQ; uint32_t data_out; int hr = ERROR_OK; LOG_DEBUG("Programming ROW @%08" PRIX32, addr); hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa); if (hr != ERROR_OK) goto exit; hr = target_write_u32(target, wa->address, sromapi_req); if (hr != ERROR_OK) goto exit_free_wa; hr = target_write_u32(target, wa->address + 0x04, 0x106); if (hr != ERROR_OK) goto exit_free_wa; hr = target_write_u32(target, wa->address + 0x08, addr); if (hr != ERROR_OK) goto exit_free_wa; hr = target_write_u32(target, wa->address + 0x0C, wa->address + 0x10); if (hr != ERROR_OK) goto exit_free_wa; hr = target_write_buffer(target, wa->address + 0x10, psoc6_info->row_sz, buffer); if (hr != ERROR_OK) goto exit_free_wa; hr = call_sromapi(target, sromapi_req, wa->address, &data_out); exit_free_wa: target_free_working_area(target, wa); exit: return hr; } /** *********************************************************************************************** * @brief Performs Program operation * @param bank current flash bank * @param buffer pointer to the buffer with data * @param offset starting offset in flash bank * @param count number of bytes in buffer * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_program(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct psoc6_target_info *psoc6_info = bank->driver_priv; const bool is_sflash = is_sflash_bank(bank); int hr; uint8_t page_buf[psoc6_info->row_sz]; hr = sromalgo_prepare(target); if (hr != ERROR_OK) goto exit; while (count) { uint32_t row_offset = offset % psoc6_info->row_sz; uint32_t aligned_addr = bank->base + offset - row_offset; uint32_t row_bytes = MIN(psoc6_info->row_sz - row_offset, count); memset(page_buf, 0, sizeof(page_buf)); memcpy(&page_buf[row_offset], buffer, row_bytes); hr = psoc6_program_row(bank, aligned_addr, page_buf, is_sflash); if (hr != ERROR_OK) { LOG_ERROR("Failed to program Flash at address 0x%08" PRIX32, aligned_addr); goto exit; } buffer += row_bytes; offset += row_bytes; count -= row_bytes; } exit: sromalgo_release(target); return hr; } /** *********************************************************************************************** * @brief Performs Mass Erase operation * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ COMMAND_HANDLER(psoc6_handle_mass_erase_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int hr = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (hr != ERROR_OK) return hr; hr = psoc6_erase(bank, 0, bank->num_sectors - 1); return hr; } /** *********************************************************************************************** * @brief Simulates broken Vector Catch * Function will try to determine entry point of user application. If it succeeds it will set HW * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards. * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will * reset CM4 anyway, so using SYSRESETREQ is safe here. * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core. * * @param target current target * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int handle_reset_halt(struct target *target) { int hr; uint32_t reset_addr; bool is_cm0 = (target->coreid == 0); /* Halt target device */ if (target->state != TARGET_HALTED) { hr = target_halt(target); if (hr != ERROR_OK) return hr; target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS); if (hr != ERROR_OK) return hr; } /* Read Vector Offset register */ uint32_t vt_base; const uint32_t vt_offset_reg = is_cm0 ? 0x402102B0 : 0x402102C0; hr = target_read_u32(target, vt_offset_reg, &vt_base); if (hr != ERROR_OK) return ERROR_OK; /* Invalid value means flash is empty */ vt_base &= 0xFFFFFF00; if ((vt_base == 0) || (vt_base == 0xFFFFFF00)) return ERROR_OK; /* Read Reset Vector value*/ hr = target_read_u32(target, vt_base + 4, &reset_addr); if (hr != ERROR_OK) return hr; /* Invalid value means flash is empty */ if ((reset_addr == 0) || (reset_addr == 0xFFFFFF00)) return ERROR_OK; /* Set breakpoint at User Application entry point */ hr = breakpoint_add(target, reset_addr, 2, BKPT_HARD); if (hr != ERROR_OK) return hr; const struct armv7m_common *cm = target_to_armv7m(target); /* PSoC6 reboots immediately after issuing SYSRESETREQ / VECTRESET * this disables SWD/JTAG pins momentarily and may break communication * Ignoring return value of mem_ap_write_atomic_u32 seems to be ok here */ if (is_cm0) { /* Reset the CM0 by asserting SYSRESETREQ. This will also reset CM4 */ LOG_INFO("psoc6.cm0: bkpt @0x%08" PRIX32 ", issuing SYSRESETREQ", reset_addr); mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR, AIRCR_VECTKEY | AIRCR_SYSRESETREQ); } else { LOG_INFO("psoc6.cm4: bkpt @0x%08" PRIX32 ", issuing VECTRESET", reset_addr); mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR, AIRCR_VECTKEY | AIRCR_VECTRESET); } /* Wait 100ms for bootcode and reinitialize DAP */ usleep(100000); dap_dp_init(cm->debug_ap->dap); target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS); /* Remove the break point */ breakpoint_remove(target, reset_addr); return ERROR_OK; } /** *********************************************************************************************** * @brief Simulates broken Vector Catch * Function will try to determine entry point of user application. If it succeeds it will set HW * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards. * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will * reset CM4 anyway, so using SYSRESETREQ is safe here. * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core. * * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ COMMAND_HANDLER(psoc6_handle_reset_halt) { if (CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); return handle_reset_halt(target); } FLASH_BANK_COMMAND_HANDLER(psoc6_flash_bank_command) { struct psoc6_target_info *psoc6_info; int hr = ERROR_OK; if (CMD_ARGC < 6) hr = ERROR_COMMAND_SYNTAX_ERROR; else { psoc6_info = calloc(1, sizeof(struct psoc6_target_info)); psoc6_info->is_probed = false; bank->driver_priv = psoc6_info; } return hr; } static const struct command_registration psoc6_exec_command_handlers[] = { { .name = "mass_erase", .handler = psoc6_handle_mass_erase_command, .mode = COMMAND_EXEC, .usage = "bank", .help = "Erases entire Main Flash", }, { .name = "reset_halt", .handler = psoc6_handle_reset_halt, .mode = COMMAND_EXEC, .usage = "", .help = "Tries to simulate broken Vector Catch", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration psoc6_command_handlers[] = { { .name = "psoc6", .mode = COMMAND_ANY, .help = "PSoC 6 flash command group", .usage = "", .chain = psoc6_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver psoc6_flash = { .name = "psoc6", .commands = psoc6_command_handlers, .flash_bank_command = psoc6_flash_bank_command, .erase = psoc6_erase, .protect = psoc6_protect, .write = psoc6_program, .read = default_flash_read, .probe = psoc6_probe, .auto_probe = psoc6_auto_probe, .erase_check = default_flash_blank_check, .protect_check = psoc6_protect_check, .info = psoc6_get_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/qn908x.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2020 iosabi * * iosabi <iosabi@protonmail.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <helper/bits.h> #include <helper/crc32.h> #include <helper/time_support.h> #include <helper/types.h> /* The QN908x has two flash regions, one is the main flash region holding the * user code and the second one is a small (0x800 bytes) "Flash information * page" that can't be written to by the user. This page contains information * programmed at the factory. * * The main flash region is normally 512 KiB, there's a field in the "Flash * information page" that allows to specify for 256 KiB size chips. However, at * the time of writing, none of the variants in the market have 256 KiB. * * The flash is divided into blocks of 256 KiB each, therefore containing two * blocks. A block is subdivided into pages, of 2048 bytes. A page is the * smallest region that can be erased or protected independently, although it * is also possible to erase a whole block or both blocks. A page is subdivided * into 8 rows of 64 words (32-bit words). The word subdivision is only * relevant because DMA can write multiple words in the same row in the same * flash program operation. * * For the Flash information page we are only interested in the last * 0x100 bytes which contain a CRC-32 checksum of that 0x100 bytes long region * and a field stating the size of the flash. This is also a good check that * we are dealing with the right chip/flash configuration and is used in the * probe() function. */ #define QN908X_FLASH_BASE 0x01000000 #define QN908X_FLASH_PAGE_SIZE 2048 #define QN908X_FLASH_PAGES_PER_BLOCK 128 #define QN908X_FLASH_MAX_BLOCKS 2 #define QN908X_FLASH_BLOCK_SIZE \ (QN908X_FLASH_PAGES_PER_BLOCK * QN908X_FLASH_PAGE_SIZE) #define QN908X_FLASH_IRQ_VECTOR_CHECKSUM_POS 0x1c #define QN908X_FLASH_IRQ_VECTOR_CHECKSUM_SIZE 4 #define QN908X_FLASH_IRQ_VECTOR_CHECKSUM_END \ (QN908X_FLASH_IRQ_VECTOR_CHECKSUM_POS + QN908X_FLASH_IRQ_VECTOR_CHECKSUM_SIZE) /* Flash information page memory fields. */ #define QN908X_INFO_PAGE_BASE 0x210b0000u #define QN908X_INFO_PAGE_CRC32 (QN908X_INFO_PAGE_BASE + 0x700) #define QN908X_INFO_PAGE_CRC_START (QN908X_INFO_PAGE_BASE + 0x704) #define QN908X_INFO_PAGE_BOOTLOADER_VER (QN908X_INFO_PAGE_BASE + 0x704) #define QN908X_INFO_PAGE_FLASH_SIZE (QN908X_INFO_PAGE_BASE + 0x708) #define QN908X_INFO_PAGE_BLUETOOTH_ADDR (QN908X_INFO_PAGE_BASE + 0x7fa) #define QN908X_INFO_PAGE_CRC_END (QN908X_INFO_PAGE_BASE + 0x800) /* Possible values of the QN908X_INFO_PAGE_FLASH_SIZE field. */ enum qn908x_info_page_flash_size { QN908X_FLASH_SIZE_512K = 0xfffff0ff, QN908X_FLASH_SIZE_256K = 0xffffe0ff, }; /* QN908x "Flash memory controller", described in section 28 of the user * manual. In the NXP SDK this peripheral is called "FLASH", however we use the * name "FMC" (Flash Memory Controller) here when referring to the controller * to avoid confusion with other "flash" terms in OpenOCD. */ #define QN908X_FMC_BASE 0x40081000u #define QN908X_FMC_INI_RD_EN (QN908X_FMC_BASE + 0x00) #define QN908X_FMC_ERASE_CTRL (QN908X_FMC_BASE + 0x04) #define QN908X_FMC_ERASE_TIME (QN908X_FMC_BASE + 0x08) #define QN908X_FMC_TIME_CTRL (QN908X_FMC_BASE + 0x0c) #define QN908X_FMC_SMART_CTRL (QN908X_FMC_BASE + 0x10) #define QN908X_FMC_INT_STAT (QN908X_FMC_BASE + 0x18) #define QN908X_FMC_LOCK_STAT_0 (QN908X_FMC_BASE + 0x20) #define QN908X_FMC_LOCK_STAT_1 (QN908X_FMC_BASE + 0x24) #define QN908X_FMC_LOCK_STAT_2 (QN908X_FMC_BASE + 0x28) #define QN908X_FMC_LOCK_STAT_3 (QN908X_FMC_BASE + 0x2c) #define QN908X_FMC_LOCK_STAT_4 (QN908X_FMC_BASE + 0x30) #define QN908X_FMC_LOCK_STAT_5 (QN908X_FMC_BASE + 0x34) #define QN908X_FMC_LOCK_STAT_6 (QN908X_FMC_BASE + 0x38) #define QN908X_FMC_LOCK_STAT_7 (QN908X_FMC_BASE + 0x3c) #define QN908X_FMC_LOCK_STAT_8 (QN908X_FMC_BASE + 0x40) #define QN908X_FMC_STATUS1 (QN908X_FMC_BASE + 0x48) #define QN908X_FMC_DEBUG_PASSWORD (QN908X_FMC_BASE + 0xa8) #define QN908X_FMC_ERASE_PASSWORD (QN908X_FMC_BASE + 0xac) #define QN908X_FMC_INI_RD_EN_INI_RD_EN_MASK BIT(0) #define QN908X_FMC_STATUS1_FSH_ERA_BUSY_L_MASK BIT(9) #define QN908X_FMC_STATUS1_FSH_WR_BUSY_L_MASK BIT(10) #define QN908X_FMC_STATUS1_FSH_ERA_BUSY_H_MASK BIT(12) #define QN908X_FMC_STATUS1_FSH_WR_BUSY_H_MASK BIT(13) #define QN908X_FMC_STATUS1_INI_RD_DONE_MASK BIT(15) #define QN908X_FMC_STATUS1_FSH_STA_MASK BIT(26) #define QN908X_FMC_ERASE_CTRL_PAGE_IDXL_SHIFT 0 #define QN908X_FMC_ERASE_CTRL_PAGE_IDXH_SHIFT 8 #define QN908X_FMC_ERASE_CTRL_HALF_ERASEL_EN_SHIFT 28 #define QN908X_FMC_ERASE_CTRL_HALF_ERASEH_EN_SHIFT 29 #define QN908X_FMC_ERASE_CTRL_PAGE_ERASEL_EN_SHIFT 30 #define QN908X_FMC_ERASE_CTRL_PAGE_ERASEH_EN_SHIFT 31 #define QN908X_FMC_INT_STAT_AHBL_INT_MASK BIT(0) #define QN908X_FMC_INT_STAT_LOCKL_INT_MASK BIT(1) #define QN908X_FMC_INT_STAT_ERASEL_INT_MASK BIT(2) #define QN908X_FMC_INT_STAT_WRITEL_INT_MASK BIT(3) #define QN908X_FMC_INT_STAT_WR_BUFL_INT_MASK BIT(4) #define QN908X_FMC_INT_STAT_WRITE_FAIL_L_INT_MASK BIT(5) #define QN908X_FMC_INT_STAT_ERASE_FAIL_L_INT_MASK BIT(6) #define QN908X_FMC_INT_STAT_AHBH_INT_MASK BIT(8) #define QN908X_FMC_INT_STAT_LOCKH_INT_MASK BIT(9) #define QN908X_FMC_INT_STAT_ERASEH_INT_MASK BIT(10) #define QN908X_FMC_INT_STAT_WRITEH_INT_MASK BIT(11) #define QN908X_FMC_INT_STAT_WR_BUFH_INT_MASK BIT(12) #define QN908X_FMC_INT_STAT_WRITE_FAIL_H_INT_MASK BIT(13) #define QN908X_FMC_INT_STAT_ERASE_FAIL_H_INT_MASK BIT(14) #define QN908X_FMC_SMART_CTRL_PRGML_EN_MASK BIT(0) #define QN908X_FMC_SMART_CTRL_PRGMH_EN_MASK BIT(1) #define QN908X_FMC_SMART_CTRL_SMART_WRITEL_EN_MASK BIT(2) #define QN908X_FMC_SMART_CTRL_SMART_WRITEH_EN_MASK BIT(3) #define QN908X_FMC_SMART_CTRL_SMART_ERASEL_EN_MASK BIT(4) #define QN908X_FMC_SMART_CTRL_SMART_ERASEH_EN_MASK BIT(5) #define QN908X_FMC_SMART_CTRL_MAX_WRITE_MASK 0xf00u #define QN908X_FMC_SMART_CTRL_MAX_WRITE_SHIFT 8u #define QN908X_FMC_SMART_CTRL_MAX_WRITE(x) \ (((uint32_t)(((uint32_t)(x)) << QN908X_FMC_SMART_CTRL_MAX_WRITE_SHIFT)) \ & QN908X_FMC_SMART_CTRL_MAX_WRITE_MASK) #define QN908X_FMC_SMART_CTRL_MAX_ERASE_MASK 0x3f000u #define QN908X_FMC_SMART_CTRL_MAX_ERASE_SHIFT 12u #define QN908X_FMC_SMART_CTRL_MAX_ERASE(x) \ (((uint32_t)(((uint32_t)(x)) << QN908X_FMC_SMART_CTRL_MAX_ERASE_SHIFT)) \ & QN908X_FMC_SMART_CTRL_MAX_ERASE_MASK) #define QN908X_FMC_SMART_CTRL_MAX_ERASE_RETRIES 9 #define QN908X_FMC_SMART_CTRL_MAX_WRITE_RETRIES 9 #define QN908X_FMC_TIME_CTRL_PRGM_CYCLE_MASK 0xfffu #define QN908X_FMC_TIME_CTRL_PRGM_CYCLE_SHIFT 0u #define QN908X_FMC_TIME_CTRL_PRGM_CYCLE(x) \ (((uint32_t)(((uint32_t)(x)) << QN908X_FMC_TIME_CTRL_PRGM_CYCLE_SHIFT)) \ & QN908X_FMC_TIME_CTRL_PRGM_CYCLE_MASK) #define QN908X_FMC_TIME_CTRL_TIME_BASE_MASK 0xff000u #define QN908X_FMC_TIME_CTRL_TIME_BASE_SHIFT 12u #define QN908X_FMC_TIME_CTRL_TIME_BASE(x) \ (((uint32_t)(((uint32_t)(x)) << QN908X_FMC_TIME_CTRL_TIME_BASE_SHIFT)) \ & QN908X_FMC_TIME_CTRL_TIME_BASE_MASK) #define QN908X_FMC_LOCK_STAT_8_MASS_ERASE_LOCK_EN BIT(0) #define QN908X_FMC_LOCK_STAT_8_FSH_PROTECT_EN BIT(1) #define QN908X_FMC_LOCK_STAT_8_MEM_PROTECT_EN BIT(2) #define QN908X_FMC_LOCK_STAT_8_PROTECT_ANY (BIT(1) | BIT(2)) /* See Table 418 "Flash lock and protect description" in the user manual */ #define QN908X_FLASH_LOCK_ADDR (QN908X_FLASH_BASE + 0x7f820) /* Allow mass erase */ #define QN908X_FLASH_LOCK_ENABLE_MASS_ERASE BIT(0) /* disallow flash access from SWD */ #define QN908X_FLASH_LOCK_ENABLE_FLASH_PROTECTION BIT(1) /* disallow SRAM access from SWD */ #define QN908X_FLASH_LOCK_ENABLE_MEMORY_PROTECTION BIT(2) /* Page lock information located at the beginning of the last page. */ struct qn908x_flash_page_lock { uint8_t bits[QN908X_FLASH_MAX_BLOCKS * QN908X_FLASH_PAGES_PER_BLOCK / 8]; uint8_t protection; uint8_t _reserved[3]; /* nvds_size is unused here, but we need to preserve it across erases * when locking and unlocking pages. */ uint8_t nvds_size[4]; } __attribute__ ((packed)); /* Clock configuration is stored in the SYSCON. */ #define QN908X_SYSCON_BASE 0x40000000u #define QN908X_SYSCON_CLK_EN (QN908X_SYSCON_BASE + 0x00cu) #define QN908X_SYSCON_CLK_CTRL (QN908X_SYSCON_BASE + 0x010u) #define QN908X_SYSCON_CHIP_ID (QN908X_SYSCON_BASE + 0x108u) #define QN908X_SYSCON_XTAL_CTRL (QN908X_SYSCON_BASE + 0x180u) /* Internal 16MHz / 8MHz clock used by the erase operation. */ #define QN908X_SYSCON_CLK_EN_CLK_DP_EN_MASK BIT(21) #define SYSCON_XTAL_CTRL_XTAL_DIV_MASK BIT(31) #define SYSCON_CLK_CTRL_AHB_DIV_MASK 0x1FFF0u #define SYSCON_CLK_CTRL_AHB_DIV_SHIFT 4u #define SYSCON_CLK_CTRL_CLK_XTAL_SEL_MASK BIT(19) #define SYSCON_CLK_CTRL_CLK_OSC32M_DIV_MASK BIT(20) #define SYSCON_CLK_CTRL_SYS_CLK_SEL_MASK 0xC0000000u #define SYSCON_CLK_CTRL_SYS_CLK_SEL_SHIFT 30u #define CLOCK_16MHZ 16000000u #define CLOCK_32MHZ 32000000u #define CLOCK_32KHZ 32000u /* Watchdog block registers */ #define QN908X_WDT_BASE 0x40001000u #define QN908X_WDT_CTRL (QN908X_WDT_BASE + 0x08u) #define QN908X_WDT_LOCK (QN908X_WDT_BASE + 0x20u) struct qn908x_flash_bank { /* The number of flash blocks. Initially set to zero until the flash * is probed. This determines the size of the flash. */ unsigned int num_blocks; unsigned int user_bank_size; bool calc_checksum; /* Whether we allow to flash an image that disables SWD access, potentially * bricking the device since the image can't be reflashed from SWD. */ bool allow_swd_disabled; bool page_lock_loaded; struct qn908x_flash_page_lock page_lock; }; /* 500 ms timeout. */ #define QN908X_DEFAULT_TIMEOUT_MS 500 /* Forward declaration of commands. */ static int qn908x_probe(struct flash_bank *bank); static int qn908x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count); /* Update the value of a register with a mask. This helper allows to read a * register, modify a subset of the bits and write back the value, which is a * common operation when modifying only a bit filed in a register. */ static int qn908x_update_reg(struct target *target, target_addr_t reg, uint32_t mask, uint32_t value) { uint32_t orig_value = 0; uint32_t new_value; int retval; if (mask != 0xffffffff) { /* No need to read the old value if we request a mask of 32 bits. */ retval = target_read_u32(target, reg, &orig_value); if (retval != ERROR_OK) { LOG_DEBUG("Error reading reg at " TARGET_ADDR_FMT ": %d", reg, retval); return retval; } } new_value = (orig_value & ~mask) | (value & mask); retval = target_write_u32(target, reg, new_value); if (retval != ERROR_OK) { LOG_DEBUG("Error writing reg at " TARGET_ADDR_FMT " with 0x%08" PRIx32 ": %d", reg, new_value, retval); return retval; } if (mask == 0xffffffff) { LOG_DEBUG("Updated reg at " TARGET_ADDR_FMT ": ?? -> 0x%.08" PRIx32 "", reg, new_value); } else { LOG_DEBUG("Updated reg at " TARGET_ADDR_FMT ": 0x%.08" PRIx32 " -> 0x%.08" PRIx32, reg, orig_value, new_value); } return ERROR_OK; } /* Load lock bit and protection bit and load redundancy page info. * This populates the LOCK_STAT_n registers with the values from the lock page, * making protection bit changes to the last page effective. */ static int qn908x_load_lock_stat(struct target *target) { int retval = target_write_u32(target, QN908X_FMC_INI_RD_EN, QN908X_FMC_INI_RD_EN_INI_RD_EN_MASK); if (retval != ERROR_OK) return retval; uint32_t status1; const uint32_t status_mask = QN908X_FMC_STATUS1_FSH_STA_MASK | QN908X_FMC_STATUS1_INI_RD_DONE_MASK; do { retval = target_read_u32(target, QN908X_FMC_STATUS1, &status1); if (retval != ERROR_OK) return retval; } while ((status1 & status_mask) != QN908X_FMC_STATUS1_INI_RD_DONE_MASK); for (int i = 0; i <= 8; i++) { uint32_t addr = QN908X_FMC_LOCK_STAT_0 + i * 4; uint32_t lock_stat; if (target_read_u32(target, addr, &lock_stat) == ERROR_OK) LOG_DEBUG("LOCK_STAT_%d = 0x%08" PRIx32, i, lock_stat); } return ERROR_OK; } /* Initializes the FMC controller registers for allowing writing. */ static int qn908x_init_flash(struct target *target) { /* Determine the current clock configuration. */ uint32_t clk_ctrl; int retval = target_read_u32(target, QN908X_SYSCON_CLK_CTRL, &clk_ctrl); if (retval != ERROR_OK) return retval; uint32_t clk_sel = (clk_ctrl & SYSCON_CLK_CTRL_SYS_CLK_SEL_MASK) >> SYSCON_CLK_CTRL_SYS_CLK_SEL_SHIFT; LOG_DEBUG("Clock clk_sel=0x%08" PRIu32, clk_sel); /* Core clock frequency. */ uint32_t core_freq = 0; switch (clk_sel) { case 0: /* RCO 32 MHz */ core_freq = (clk_ctrl & SYSCON_CLK_CTRL_CLK_OSC32M_DIV_MASK) ? CLOCK_16MHZ : CLOCK_32MHZ; break; case 1: /* Xin frequency */ { uint32_t clk_xtal; retval = target_read_u32(target, QN908X_SYSCON_XTAL_CTRL, &clk_xtal); if (retval != ERROR_OK) return retval; core_freq = (clk_ctrl & SYSCON_CLK_CTRL_CLK_XTAL_SEL_MASK) && (clk_xtal & SYSCON_XTAL_CTRL_XTAL_DIV_MASK) ? CLOCK_32MHZ : CLOCK_16MHZ; } break; case 2: /* 32 Kz */ core_freq = CLOCK_32KHZ; break; default: return ERROR_FAIL; } uint32_t ahb_div = (clk_ctrl & SYSCON_CLK_CTRL_AHB_DIV_MASK) >> SYSCON_CLK_CTRL_AHB_DIV_SHIFT; uint32_t ahb_freq = core_freq / (ahb_div + 1); LOG_DEBUG("Core freq: %" PRIu32 " Hz | AHB freq: %" PRIu32 " Hz", core_freq, ahb_freq); /* TIME_BASE is 2uS at the current AHB clock speed. */ retval = target_write_u32(target, QN908X_FMC_TIME_CTRL, QN908X_FMC_TIME_CTRL_TIME_BASE(2 * ahb_freq / 1000000) | QN908X_FMC_TIME_CTRL_PRGM_CYCLE(30)); if (retval != ERROR_OK) return retval; return qn908x_load_lock_stat(target); } /* flash bank qn908x <base> <size> 0 0 <target#> [calc_checksum] */ FLASH_BANK_COMMAND_HANDLER(qn908x_flash_bank_command) { struct qn908x_flash_bank *qn908x_info; if (CMD_ARGC < 6 || CMD_ARGC > 7) return ERROR_COMMAND_SYNTAX_ERROR; if (bank->base != QN908X_FLASH_BASE) { LOG_ERROR("Address " TARGET_ADDR_FMT " is an invalid bank address (try 0x%08" PRIx32 ")", bank->base, QN908X_FLASH_BASE); return ERROR_COMMAND_ARGUMENT_INVALID; } qn908x_info = malloc(sizeof(struct qn908x_flash_bank)); if (!qn908x_info) return ERROR_FAIL; bank->driver_priv = qn908x_info; qn908x_info->num_blocks = 0; qn908x_info->user_bank_size = bank->size; qn908x_info->page_lock_loaded = false; qn908x_info->allow_swd_disabled = false; qn908x_info->calc_checksum = false; if (CMD_ARGC == 7) { if (strcmp(CMD_ARGV[6], "calc_checksum")) { free(qn908x_info); return ERROR_COMMAND_ARGUMENT_INVALID; } qn908x_info->calc_checksum = true; } return ERROR_OK; } static int qn908x_read_page_lock(struct flash_bank *bank) { struct qn908x_flash_bank *qn908x_info = bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* The last page of the flash contains the "Flash lock and protect" * information. It is not clear where this is located on chips with only * one block. */ uint32_t prot_offset = qn908x_info->num_blocks * QN908X_FLASH_BLOCK_SIZE - QN908X_FLASH_PAGE_SIZE; int retval = target_read_memory(bank->target, bank->base + prot_offset, 4, sizeof(qn908x_info->page_lock) / 4, (void *)(&qn908x_info->page_lock)); if (retval != ERROR_OK) return retval; LOG_DEBUG("Flash protection = 0x%02" PRIx8, qn908x_info->page_lock.protection); qn908x_info->page_lock_loaded = true; return ERROR_OK; } static int qn908x_busy_check(struct target *target) { uint32_t status1; int retval = target_read_u32(target, QN908X_FMC_STATUS1, &status1); if (retval != ERROR_OK) return retval; if ((status1 & (QN908X_FMC_STATUS1_FSH_ERA_BUSY_L_MASK | QN908X_FMC_STATUS1_FSH_WR_BUSY_L_MASK | QN908X_FMC_STATUS1_FSH_ERA_BUSY_H_MASK | QN908X_FMC_STATUS1_FSH_WR_BUSY_H_MASK))) return ERROR_FLASH_BUSY; return ERROR_OK; } static int qn908x_status_check(struct target *target) { uint32_t int_stat; int retval = target_read_u32(target, QN908X_FMC_INT_STAT, &int_stat); if (retval != ERROR_OK) return retval; /* The error bits for block 0 and block 1 have the exact same layout, only * that block 1 error bits are shifted by 8 bits. We use this fact to * loop over the blocks */ for (unsigned int block = 0; block <= 1; block++) { unsigned int shift = (block) ? 8 : 0; if (int_stat & (QN908X_FMC_INT_STAT_AHBL_INT_MASK << shift)) { LOG_ERROR("AHB error on block %u", block); return ERROR_FAIL; } if (int_stat & (QN908X_FMC_INT_STAT_LOCKL_INT_MASK << shift)) { LOG_ERROR("Locked page being accessed error on block %u", block); return ERROR_FAIL; } if (int_stat & (QN908X_FMC_INT_STAT_WRITE_FAIL_L_INT_MASK << shift)) { LOG_ERROR("Smart write on block %u failed", block); return ERROR_FAIL; } if ((int_stat & (QN908X_FMC_INT_STAT_ERASE_FAIL_L_INT_MASK << shift)) || (int_stat & (QN908X_FMC_INT_STAT_ERASE_FAIL_H_INT_MASK << shift))) { LOG_ERROR("Smart erase on block %u failed", block); return ERROR_FAIL; } } return ERROR_OK; } static int qn908x_wait_for_idle(struct target *target, int64_t timeout_ms) { int64_t ms_start = timeval_ms(); int busy = ERROR_FLASH_BUSY; while (busy != ERROR_OK) { busy = qn908x_busy_check(target); if (busy != ERROR_OK && busy != ERROR_FLASH_BUSY) return busy; if (timeval_ms() - ms_start > timeout_ms) { LOG_ERROR("Timeout waiting to be idle."); return ERROR_TIMEOUT_REACHED; } } return ERROR_OK; } /* Set up the chip to perform an erase (page or block) operation. */ static int qn908x_setup_erase(struct target *target) { int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Enable 8MHz clock. */ retval = qn908x_update_reg(target, QN908X_SYSCON_CLK_EN, QN908X_SYSCON_CLK_EN_CLK_DP_EN_MASK, QN908X_SYSCON_CLK_EN_CLK_DP_EN_MASK); if (retval != ERROR_OK) return retval; /* Set ERASE_TIME to 2ms for smart erase. */ retval = qn908x_update_reg(target, QN908X_FMC_ERASE_TIME, (1u << 20) - 1, 2000 * 8); /* 2000 uS * 8 MHz = x cycles */ if (retval != ERROR_OK) return retval; /* Set up smart erase. SWD can only perform smart erase. */ uint32_t ctrl_val = QN908X_FMC_SMART_CTRL_SMART_ERASEH_EN_MASK | QN908X_FMC_SMART_CTRL_SMART_ERASEL_EN_MASK | QN908X_FMC_SMART_CTRL_MAX_ERASE(QN908X_FMC_SMART_CTRL_MAX_ERASE_RETRIES) | QN908X_FMC_SMART_CTRL_MAX_WRITE(QN908X_FMC_SMART_CTRL_MAX_WRITE_RETRIES); retval = target_write_u32(target, QN908X_FMC_SMART_CTRL, ctrl_val); if (retval != ERROR_OK) return retval; retval = qn908x_wait_for_idle(target, QN908X_DEFAULT_TIMEOUT_MS); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int qn908x_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct qn908x_flash_bank *qn908x_info = bank->driver_priv; int retval = ERROR_OK; if (!qn908x_info->num_blocks) { if (qn908x_probe(bank) != ERROR_OK) return ERROR_FLASH_BANK_NOT_PROBED; } retval = qn908x_setup_erase(bank->target); if (retval != ERROR_OK) return retval; for (unsigned int i = first; i <= last; i++) { if (i >= bank->num_sectors) return ERROR_FLASH_SECTOR_INVALID; uint32_t block_idx = i / QN908X_FLASH_PAGES_PER_BLOCK; uint32_t page_idx = i % QN908X_FLASH_PAGES_PER_BLOCK; if (block_idx >= qn908x_info->num_blocks) return ERROR_FLASH_SECTOR_INVALID; LOG_DEBUG("Erasing page %" PRIu32 " of block %" PRIu32, page_idx, block_idx); /* Depending on the block the page we are erasing is located we * need to use a different set of bits in the registers. */ uint32_t ctrl_page_idx_shift = block_idx ? QN908X_FMC_ERASE_CTRL_PAGE_IDXH_SHIFT : QN908X_FMC_ERASE_CTRL_PAGE_IDXL_SHIFT; uint32_t ctrl_erase_en_shift = block_idx ? QN908X_FMC_ERASE_CTRL_PAGE_ERASEH_EN_SHIFT : QN908X_FMC_ERASE_CTRL_PAGE_ERASEL_EN_SHIFT; retval = target_write_u32(bank->target, QN908X_FMC_ERASE_CTRL, BIT(ctrl_erase_en_shift) | (page_idx << ctrl_page_idx_shift)); if (retval != ERROR_OK) return retval; retval = qn908x_wait_for_idle(bank->target, QN908X_DEFAULT_TIMEOUT_MS); if (retval != ERROR_OK) return retval; retval = qn908x_status_check(bank->target); if (retval != ERROR_OK) return retval; } return retval; } static int qn908x_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct qn908x_flash_bank *qn908x_info = bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!qn908x_info->page_lock_loaded) { int retval = qn908x_read_page_lock(bank); if (retval != ERROR_OK) return retval; } /* Use [first, last) interval open on the right side from now on. */ last++; /* We use sectors as prot_blocks. */ bool needs_update = false; for (unsigned int i = first; i < last; i++) { if (set != (((qn908x_info->page_lock.bits[i / 8] >> (i % 8)) & 1) ^ 1)) needs_update = true; } /* Check that flash protection still allows SWD access to flash and RAM, * otherwise we won't be able to re-flash this chip from SWD unless we do a * mass erase. */ if (qn908x_info->page_lock.protection & QN908X_FMC_LOCK_STAT_8_PROTECT_ANY) { LOG_WARNING("SWD flash/RAM access disabled in the Flash lock and " "protect descriptor. You might need to issue a mass_erase to " "regain SWD access to this chip after reboot."); } if (!needs_update) return ERROR_OK; int last_page = qn908x_info->num_blocks * QN908X_FLASH_PAGES_PER_BLOCK - 1; int retval; if (qn908x_info->page_lock.bits[sizeof(qn908x_info->page_lock.bits) - 1] & 0x80) { /* A bit 1 in the MSB in the page_lock.bits array means that the last * page is unlocked, so we can just erase it. */ retval = qn908x_erase(bank, last_page, last_page); if (retval != ERROR_OK) return retval; } else { /* TODO: The last page is locked and we can't erase unless we use the * ERASE_PASSWORD from code running on the device. For this we need to * copy a little program to RAM and execute the erase command from * there since there's no way to override the page protection from * SWD. */ LOG_ERROR("Unprotecting the last page is not supported. Issue a " "\"qn908x mass_erase\" command to erase the whole flash, " "including the last page and its protection."); return ERROR_FAIL; } for (unsigned int i = first / 8; i < (last + 7) / 8; i++) { /* first_mask contains a bit set if the bit corresponds to a block id * that is larger or equal than first. This is basically 0xff in all * cases except potentially the first iteration. */ uint8_t first_mask = (first <= i * 8) ? 0xff : 0xff ^ ((1u << (first - i * 8)) - 1); /* Similar to first_mask, this contains a bit set if the corresponding * is smaller than last. */ uint8_t last_mask = (i * 8 + 8 <= last) ? 0xff : ((1u << (last - i * 8)) - 1); uint8_t mask = first_mask & last_mask; LOG_DEBUG("protect set=%d bits[%d] with mask=0x%02x", set, i, mask); /* To "set" the protection bit means to clear the bit in the page_lock * bit array. */ if (set) qn908x_info->page_lock.bits[i] &= ~mask; else qn908x_info->page_lock.bits[i] |= mask; } retval = qn908x_write(bank, (void *)(&qn908x_info->page_lock), last_page * QN908X_FLASH_PAGE_SIZE, sizeof(qn908x_info->page_lock)); if (retval != ERROR_OK) return retval; /* Reload the lock_stat to make the changes effective. */ retval = qn908x_load_lock_stat(bank->target); if (retval != ERROR_OK) return retval; for (unsigned int i = first; i < last; i++) bank->sectors[i].is_protected = set; return ERROR_OK; } static int qn908x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct qn908x_flash_bank *qn908x_info = bank->driver_priv; int retval = ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* The flash infrastructure was requested to align writes to 32 bit */ assert(((offset % 4) == 0) && ((count % 4) == 0)); /* Compute the calc_checksum even if it wasn't requested. */ uint32_t checksum = 0; if (offset == 0 && count >= 0x20) { for (int i = 0; i < 7; i++) checksum += buf_get_u32(buffer + (i * 4), 0, 32); checksum = 0 - checksum; LOG_DEBUG("computed image checksum: 0x%8.8" PRIx32, checksum); uint32_t stored_checksum = buf_get_u32(buffer + 7 * 4, 0, 32); if (checksum != stored_checksum) { LOG_WARNING("Image vector table checksum mismatch: expected 0x%08" PRIx32 " but found 0x%08" PRIx32, checksum, stored_checksum); if (!qn908x_info->calc_checksum) LOG_WARNING("This device will not boot, use calc_checksum in " "the flash bank."); else LOG_WARNING("Updating checksum, verification will fail."); } } /* Check the Code Read Protection (CRP) word for invalid values or not * allowed ones. */ if (offset <= 0x20 && offset + count >= 0x24) { uint32_t crp = buf_get_u32(buffer + 0x20 - offset, 0, 32); /* 2-bit fields at bits 10, 12, 14, 16 and 18 must not be 00 or 11. */ for (int i = 10; i <= 18; i += 2) { uint32_t field = (crp >> i) & 3; if (field == 0 || field == 3) { LOG_DEBUG("Code Read Protection = 0x%08" PRIx32, crp); LOG_ERROR("The Code Read Protection (CRP) field at bit %d is " "invalid (%" PRIu32 "). An invalid value could make " "the flash inaccessible.", i, field); return ERROR_FAIL; } } uint32_t swd_allowed = (crp >> 18) & 3; if (swd_allowed != 2) { LOG_WARNING("The Code Read Protection (CRP) in this image " "(0x%08" PRIx32 ") is disabling the SWD access, which is " "currently used by OpenOCD to flash this device. After " "reboot, this device will not be accessible to OpenOCD " "anymore.", crp); if (!qn908x_info->allow_swd_disabled) { LOG_ERROR("Disabling SWD is not allowed, run " "\"qn908x allow_brick\" before if you really want to " "disable SWD. You won't be able to access this chip " "anymore from OpenOCD."); return ERROR_FAIL; } } } retval = qn908x_wait_for_idle(bank->target, QN908X_DEFAULT_TIMEOUT_MS); if (retval != ERROR_OK) return retval; uint32_t smart_ctrl = QN908X_FMC_SMART_CTRL_SMART_WRITEL_EN_MASK | QN908X_FMC_SMART_CTRL_PRGML_EN_MASK | QN908X_FMC_SMART_CTRL_MAX_WRITE(QN908X_FMC_SMART_CTRL_MAX_WRITE_RETRIES); if (qn908x_info->num_blocks > 1) { smart_ctrl |= QN908X_FMC_SMART_CTRL_SMART_WRITEH_EN_MASK | QN908X_FMC_SMART_CTRL_PRGMH_EN_MASK; } retval = target_write_u32(bank->target, QN908X_FMC_SMART_CTRL, smart_ctrl); if (retval != ERROR_OK) return retval; /* Write data page-wise, as suggested in the examples in section * 28.5.2 "Flash write" of user manual UM11023 in revision 1.1 * (February 2018). */ while (count > 0) { uint32_t next_offset = (offset & ~(QN908X_FLASH_PAGE_SIZE - 1)) + QN908X_FLASH_PAGE_SIZE; uint32_t chunk_len = next_offset - offset; if (chunk_len > count) chunk_len = count; if (offset == 0 && chunk_len >= QN908X_FLASH_IRQ_VECTOR_CHECKSUM_END && qn908x_info->calc_checksum) { /* write data prior to checksum */ retval = target_write_buffer(bank->target, bank->base, QN908X_FLASH_IRQ_VECTOR_CHECKSUM_POS, buffer); if (retval != ERROR_OK) return retval; /* write computed crc checksum instead of provided data */ retval = target_write_u32(bank->target, bank->base + QN908X_FLASH_IRQ_VECTOR_CHECKSUM_POS, checksum); if (retval != ERROR_OK) return retval; retval = target_write_buffer(bank->target, bank->base + QN908X_FLASH_IRQ_VECTOR_CHECKSUM_END, chunk_len - QN908X_FLASH_IRQ_VECTOR_CHECKSUM_END, buffer + QN908X_FLASH_IRQ_VECTOR_CHECKSUM_END); } else { retval = target_write_buffer(bank->target, bank->base + offset, chunk_len, buffer); } if (retval != ERROR_OK) return retval; keep_alive(); buffer += chunk_len; count -= chunk_len; offset = next_offset; /* Wait for FMC to complete write */ retval = qn908x_wait_for_idle(bank->target, QN908X_DEFAULT_TIMEOUT_MS); if (retval != ERROR_OK) return retval; /* Check if FMC reported any errors */ retval = qn908x_status_check(bank->target); if (retval != ERROR_OK) return retval; } return retval; } static int is_flash_protected(struct flash_bank *bank, bool *is_protected) { int retval; uint32_t lock_stat; retval = target_read_u32(bank->target, QN908X_FMC_LOCK_STAT_8, &lock_stat); if (retval) return retval; *is_protected = false; if (lock_stat & QN908X_FMC_LOCK_STAT_8_PROTECT_ANY) *is_protected = true; return ERROR_OK; } static int qn908x_probe(struct flash_bank *bank) { int retval; struct qn908x_flash_bank *qn908x_info = bank->driver_priv; uint8_t info_page[QN908X_INFO_PAGE_CRC_END - QN908X_INFO_PAGE_CRC_START]; qn908x_info->num_blocks = 0; /* When the SWD access to the RAM is locked by the LOCK_STAT_8 register we * can't access the info page to verify the chip/bank version and it will * read all zeros. This situation prevents the bank from being initialized * at all so no other operation can be performed. The only option to * re-flash the chip is to perform a mass_erase from SWD, which can be * performed even if the mass_erase operation is locked as well. * We attempt to read the info page and redirect the user to perform a * mass_erase if we detect this situation. */ retval = target_read_memory(bank->target, QN908X_INFO_PAGE_CRC_START, sizeof(uint32_t), sizeof(info_page) / sizeof(uint32_t), info_page); if (retval != ERROR_OK) return retval; const uint32_t crc_seed = 0xffffffff; /* The QN908x uses the standard little endian CRC32 polynomial and all ones * as seed. The CRC32 is however finalized by one last xor operation that * is not part of the common CRC32 implementation, so we do that by hand */ uint32_t computed_crc = crc32_le(CRC32_POLY_LE, crc_seed, info_page, sizeof(info_page)); computed_crc ^= crc_seed; uint32_t read_crc; retval = target_read_u32(bank->target, QN908X_INFO_PAGE_CRC32, &read_crc); if (retval != ERROR_OK) return retval; if (computed_crc != read_crc) { uint32_t info_page_or = 0; for (unsigned int i = 0; i < sizeof(info_page); i++) info_page_or |= info_page[i]; bool is_protected; retval = is_flash_protected(bank, &is_protected); if (retval != ERROR_OK) return retval; if (info_page_or == 0 && is_protected) { LOG_ERROR("The flash or memory in this chip is protected and " "cannot be accessed from the SWD interface. However, a " "\"qn908x mass_erase\" can erase the device and lift this " "protection."); return ERROR_FAIL; } LOG_ERROR("Flash information page CRC32 mismatch, found 0x%08" PRIx32 " but computed 0x%08" PRIx32 ". Flash size unknown", read_crc, computed_crc); return ERROR_FAIL; } uint32_t flash_size_fld = target_buffer_get_u32(bank->target, info_page + (QN908X_INFO_PAGE_FLASH_SIZE - QN908X_INFO_PAGE_CRC_START)); switch (flash_size_fld) { case QN908X_FLASH_SIZE_512K: qn908x_info->num_blocks = 2; break; case QN908X_FLASH_SIZE_256K: qn908x_info->num_blocks = 1; break; default: LOG_ERROR("Unknown Flash size field: 0x%08" PRIx32, flash_size_fld); return ERROR_FAIL; } bank->size = qn908x_info->num_blocks * QN908X_FLASH_BLOCK_SIZE; bank->write_start_alignment = 4; bank->write_end_alignment = 4; /* The flash supports erasing and protecting individual pages. */ bank->num_sectors = qn908x_info->num_blocks * QN908X_FLASH_PAGES_PER_BLOCK; bank->sectors = alloc_block_array(0, QN908X_FLASH_PAGE_SIZE, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; retval = qn908x_init_flash(bank->target); if (retval != ERROR_OK) return retval; LOG_INFO("Detected flash size: %d KiB", bank->size / 1024); return ERROR_OK; } static int qn908x_auto_probe(struct flash_bank *bank) { struct qn908x_flash_bank *qn908x_info = bank->driver_priv; if (qn908x_info->num_blocks != 0) return ERROR_OK; LOG_DEBUG("auto_probe"); return qn908x_probe(bank); } static int qn908x_protect_check(struct flash_bank *bank) { struct qn908x_flash_bank *qn908x_info = bank->driver_priv; int retval = qn908x_read_page_lock(bank); if (retval != ERROR_OK) return retval; for (uint32_t i = 0; i < qn908x_info->num_blocks * QN908X_FLASH_PAGES_PER_BLOCK; i++) { /* A bit 0 in page_lock means page is locked. */ bank->sectors[i].is_protected = ((qn908x_info->page_lock.bits[i / 8] >> (i % 8)) & 1) ^ 1; } return ERROR_OK; } static int qn908x_get_info(struct flash_bank *bank, struct command_invocation *cmd) { uint32_t bootloader_version; uint32_t chip_id; uint8_t bluetooth[6]; int retval; struct qn908x_flash_bank *qn908x_info = bank->driver_priv; retval = target_read_u32(bank->target, QN908X_SYSCON_CHIP_ID, &chip_id); if (retval != ERROR_OK) { command_print_sameline(cmd, "Cannot read QN908x chip ID."); return retval; } retval = target_read_u32(bank->target, QN908X_INFO_PAGE_BOOTLOADER_VER, &bootloader_version); if (retval != ERROR_OK) { command_print_sameline(cmd, "Cannot read from QN908x info page."); return retval; } retval = target_read_memory(bank->target, QN908X_INFO_PAGE_BLUETOOTH_ADDR, 1, sizeof(bluetooth), bluetooth); if (retval != ERROR_OK) { command_print_sameline(cmd, "Cannot read QN908x bluetooth L2 address."); return retval; } command_print_sameline(cmd, "qn908x: chip id: 0x%" PRIx32, chip_id); command_print_sameline(cmd, " bdaddr: " "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8, bluetooth[0], bluetooth[1], bluetooth[2], bluetooth[3], bluetooth[4], bluetooth[5]); command_print_sameline(cmd, " bootloader: %08" PRIx32, bootloader_version); command_print_sameline(cmd, " blocks: %" PRIu32, qn908x_info->num_blocks); return ERROR_OK; } COMMAND_HANDLER(qn908x_handle_allow_brick_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct flash_bank *bank = NULL; if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; retval = get_flash_bank_by_addr(target, QN908X_FLASH_BASE, true, &bank); if (retval != ERROR_OK) return retval; /* If get_flash_bank_by_addr() did not find the flash bank, it should have * returned and error code instead of ERROR_OK */ assert(bank); struct qn908x_flash_bank *qn908x_info = bank->driver_priv; LOG_WARNING("Flashing images that disable SWD in qn908x is now allowed."); qn908x_info->allow_swd_disabled = true; return ERROR_OK; } COMMAND_HANDLER(qn908x_handle_disable_wdog_command) { int retval; struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (target->state != TARGET_HALTED) { command_print(CMD, "Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* To change any value in the watchdog block (WDT) we need to first write * 0x1ACCE551 to the LOCK register, and we can then set it back to any other * value to prevent accidental changes to the watchdog. */ retval = target_write_u32(target, QN908X_WDT_LOCK, 0x1ACCE551); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, QN908X_WDT_CTRL, 0); if (retval != ERROR_OK) return retval; return target_write_u32(target, QN908X_WDT_LOCK, 0); } COMMAND_HANDLER(qn908x_handle_mass_erase_command) { int retval; bool keep_lock = false; if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { if (strcmp("keep_lock", CMD_ARGV[0])) return ERROR_COMMAND_ARGUMENT_INVALID; keep_lock = true; } /* This operation can be performed without probing the bank since it is the * only way to unlock a chip when the flash and ram have been locked. */ struct target *target = get_current_target(CMD_CTX); retval = qn908x_setup_erase(target); if (retval != ERROR_OK) return retval; /* Check the mass-erase locking status for information purposes only. This * lock applies to both the SWD and the code running in the core but can be * bypassed in either case. */ uint32_t lock_stat_8; retval = target_read_u32(target, QN908X_FMC_LOCK_STAT_8, &lock_stat_8); LOG_DEBUG("LOCK_STAT_8 before erasing: 0x%" PRIx32, lock_stat_8); if (retval != ERROR_OK) return retval; if ((lock_stat_8 & QN908X_FMC_LOCK_STAT_8_MASS_ERASE_LOCK_EN) == 0) { LOG_INFO("mass_erase disabled by Flash lock and protection, forcing " "mass_erase."); } /* Set the DEBUG_PASSWORD so we can force the mass erase from the SWD. We do * this regardless of the lock status. */ retval = target_write_u32(target, QN908X_FMC_DEBUG_PASSWORD, 0xCA1E093F); if (retval != ERROR_OK) return retval; /* Erase both halves of the flash at the same time. These are actually done * sequentially but we need to send the command to erase both blocks since * doing so in a locked flash will change the LOCK_STAT_8 register to 0x01, * allowing us to access the (now erase) flash an memory. Erasing only one * block at a time does not reset the LOCK_STAT_8 register and therefore * will not grant access to program the chip. */ uint32_t erase_cmd = (1u << QN908X_FMC_ERASE_CTRL_HALF_ERASEH_EN_SHIFT) | (1u << QN908X_FMC_ERASE_CTRL_HALF_ERASEL_EN_SHIFT); LOG_DEBUG("Erasing both blocks with command 0x%" PRIx32, erase_cmd); retval = target_write_u32(target, QN908X_FMC_ERASE_CTRL, erase_cmd); if (retval != ERROR_OK) return retval; retval = qn908x_wait_for_idle(target, QN908X_DEFAULT_TIMEOUT_MS); if (retval != ERROR_OK) return retval; retval = qn908x_status_check(target); if (retval != ERROR_OK) return retval; /* Set the debug password back to 0 to avoid accidental mass_erase. */ retval = target_write_u32(target, QN908X_FMC_DEBUG_PASSWORD, 0); if (retval != ERROR_OK) return retval; /* At this point the flash is erased and we are able to write to the flash * since the LOCK_STAT_8 gets updated to 0x01 after the mass_erase. However, * after a hard reboot this value will be realoaded from flash which after * an erase is 0xff. This means that after flashing an image that doesn't * set the protection bits we end up with a chip that we can't debug. We * update this value to 0x01 unless "keep_lock" is passed to allow the SWD * interface to debug the flash and RAM after a hard reset. */ if (keep_lock) return retval; retval = qn908x_init_flash(target); if (retval != ERROR_OK) return retval; /* Unlock access to RAM and FLASH in the last page of the flash and * reloading */ retval = qn908x_wait_for_idle(target, QN908X_DEFAULT_TIMEOUT_MS); if (retval != ERROR_OK) return retval; uint32_t smart_ctrl = QN908X_FMC_SMART_CTRL_SMART_WRITEH_EN_MASK | QN908X_FMC_SMART_CTRL_PRGMH_EN_MASK; retval = target_write_u32(target, QN908X_FMC_SMART_CTRL, smart_ctrl); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, QN908X_FLASH_LOCK_ADDR, QN908X_FLASH_LOCK_ENABLE_MASS_ERASE); if (retval != ERROR_OK) return retval; retval = qn908x_wait_for_idle(target, QN908X_DEFAULT_TIMEOUT_MS); if (retval != ERROR_OK) return retval; /* Force a page_lock reload after the mass_erase . */ retval = qn908x_load_lock_stat(target); if (retval != ERROR_OK) return retval; return retval; } static const struct command_registration qn908x_exec_command_handlers[] = { { .name = "allow_brick", .handler = qn908x_handle_allow_brick_command, .mode = COMMAND_EXEC, .help = "Allow writing images that disable SWD access in their " "Code Read Protection (CRP) word. Warning: This can make your " "chip inaccessible from OpenOCD or any other SWD debugger.", .usage = "", }, { .name = "disable_wdog", .handler = qn908x_handle_disable_wdog_command, .mode = COMMAND_EXEC, .help = "Disabled the watchdog (WDT).", .usage = "", }, { .name = "mass_erase", .handler = qn908x_handle_mass_erase_command, .mode = COMMAND_EXEC, .help = "Erase the whole flash chip.", .usage = "[keep_lock]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration qn908x_command_handlers[] = { { .name = "qn908x", .mode = COMMAND_ANY, .help = "qn908x flash controller commands", .usage = "", .chain = qn908x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver qn908x_flash = { .name = "qn908x", .commands = qn908x_command_handlers, .flash_bank_command = qn908x_flash_bank_command, .info = qn908x_get_info, .erase = qn908x_erase, .protect = qn908x_protect, .write = qn908x_write, .read = default_flash_read, .probe = qn908x_probe, .auto_probe = qn908x_auto_probe, .erase_check = default_flash_blank_check, .protect_check = qn908x_protect_check, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/renesas_rpchf.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Renesas RCar Gen3 RPC Hyperflash driver * Based on U-Boot RPC Hyperflash driver * * Copyright (C) 2016 Renesas Electronics Corporation * Copyright (C) 2016 Cogent Embedded, Inc. * Copyright (C) 2017-2019 Marek Vasut <marek.vasut@gmail.com> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "cfi.h" #include "non_cfi.h" #include <helper/binarybuffer.h> #include <helper/bits.h> #include <helper/time_support.h> #define RPC_CMNCR 0x0000 /* R/W */ #define RPC_CMNCR_MD BIT(31) #define RPC_CMNCR_MOIIO0(val) (((val) & 0x3) << 16) #define RPC_CMNCR_MOIIO1(val) (((val) & 0x3) << 18) #define RPC_CMNCR_MOIIO2(val) (((val) & 0x3) << 20) #define RPC_CMNCR_MOIIO3(val) (((val) & 0x3) << 22) #define RPC_CMNCR_MOIIO_HIZ (RPC_CMNCR_MOIIO0(3) | RPC_CMNCR_MOIIO1(3) | \ RPC_CMNCR_MOIIO2(3) | RPC_CMNCR_MOIIO3(3)) #define RPC_CMNCR_IO0FV(val) (((val) & 0x3) << 8) #define RPC_CMNCR_IO2FV(val) (((val) & 0x3) << 12) #define RPC_CMNCR_IO3FV(val) (((val) & 0x3) << 14) #define RPC_CMNCR_IOFV_HIZ (RPC_CMNCR_IO0FV(3) | RPC_CMNCR_IO2FV(3) | \ RPC_CMNCR_IO3FV(3)) #define RPC_CMNCR_BSZ(val) (((val) & 0x3) << 0) #define RPC_SSLDR 0x0004 /* R/W */ #define RPC_SSLDR_SPNDL(d) (((d) & 0x7) << 16) #define RPC_SSLDR_SLNDL(d) (((d) & 0x7) << 8) #define RPC_SSLDR_SCKDL(d) (((d) & 0x7) << 0) #define RPC_DRCR 0x000C /* R/W */ #define RPC_DRCR_SSLN BIT(24) #define RPC_DRCR_RBURST(v) (((v) & 0x1F) << 16) #define RPC_DRCR_RCF BIT(9) #define RPC_DRCR_RBE BIT(8) #define RPC_DRCR_SSLE BIT(0) #define RPC_DRCMR 0x0010 /* R/W */ #define RPC_DRCMR_CMD(c) (((c) & 0xFF) << 16) #define RPC_DRCMR_OCMD(c) (((c) & 0xFF) << 0) #define RPC_DREAR 0x0014 /* R/W */ #define RPC_DREAR_EAV(v) (((v) & 0xFF) << 16) #define RPC_DREAR_EAC(v) (((v) & 0x7) << 0) #define RPC_DROPR 0x0018 /* R/W */ #define RPC_DROPR_OPD3(o) (((o) & 0xFF) << 24) #define RPC_DROPR_OPD2(o) (((o) & 0xFF) << 16) #define RPC_DROPR_OPD1(o) (((o) & 0xFF) << 8) #define RPC_DROPR_OPD0(o) (((o) & 0xFF) << 0) #define RPC_DRENR 0x001C /* R/W */ #define RPC_DRENR_CDB(o) (uint32_t)((((o) & 0x3) << 30)) #define RPC_DRENR_OCDB(o) (((o) & 0x3) << 28) #define RPC_DRENR_ADB(o) (((o) & 0x3) << 24) #define RPC_DRENR_OPDB(o) (((o) & 0x3) << 20) #define RPC_DRENR_SPIDB(o) (((o) & 0x3) << 16) #define RPC_DRENR_DME BIT(15) #define RPC_DRENR_CDE BIT(14) #define RPC_DRENR_OCDE BIT(12) #define RPC_DRENR_ADE(v) (((v) & 0xF) << 8) #define RPC_DRENR_OPDE(v) (((v) & 0xF) << 4) #define RPC_SMCR 0x0020 /* R/W */ #define RPC_SMCR_SSLKP BIT(8) #define RPC_SMCR_SPIRE BIT(2) #define RPC_SMCR_SPIWE BIT(1) #define RPC_SMCR_SPIE BIT(0) #define RPC_SMCMR 0x0024 /* R/W */ #define RPC_SMCMR_CMD(c) (((c) & 0xFF) << 16) #define RPC_SMCMR_OCMD(c) (((c) & 0xFF) << 0) #define RPC_SMADR 0x0028 /* R/W */ #define RPC_SMOPR 0x002C /* R/W */ #define RPC_SMOPR_OPD0(o) (((o) & 0xFF) << 0) #define RPC_SMOPR_OPD1(o) (((o) & 0xFF) << 8) #define RPC_SMOPR_OPD2(o) (((o) & 0xFF) << 16) #define RPC_SMOPR_OPD3(o) (((o) & 0xFF) << 24) #define RPC_SMENR 0x0030 /* R/W */ #define RPC_SMENR_CDB(o) (((o) & 0x3) << 30) #define RPC_SMENR_OCDB(o) (((o) & 0x3) << 28) #define RPC_SMENR_ADB(o) (((o) & 0x3) << 24) #define RPC_SMENR_OPDB(o) (((o) & 0x3) << 20) #define RPC_SMENR_SPIDB(o) (((o) & 0x3) << 16) #define RPC_SMENR_DME BIT(15) #define RPC_SMENR_CDE BIT(14) #define RPC_SMENR_OCDE BIT(12) #define RPC_SMENR_ADE(v) (((v) & 0xF) << 8) #define RPC_SMENR_OPDE(v) (((v) & 0xF) << 4) #define RPC_SMENR_SPIDE(v) (((v) & 0xF) << 0) #define RPC_SMRDR0 0x0038 /* R */ #define RPC_SMRDR1 0x003C /* R */ #define RPC_SMWDR0 0x0040 /* R/W */ #define RPC_SMWDR1 0x0044 /* R/W */ #define RPC_CMNSR 0x0048 /* R */ #define RPC_CMNSR_SSLF BIT(1) #define RPC_CMNSR_TEND BIT(0) #define RPC_DRDMCR 0x0058 /* R/W */ #define RPC_DRDMCR_DMCYC(v) (((v) & 0xF) << 0) #define RPC_DRDRENR 0x005C /* R/W */ #define RPC_DRDRENR_HYPE (0x5 << 12) #define RPC_DRDRENR_ADDRE BIT(8) #define RPC_DRDRENR_OPDRE BIT(4) #define RPC_DRDRENR_DRDRE BIT(0) #define RPC_SMDMCR 0x0060 /* R/W */ #define RPC_SMDMCR_DMCYC(v) (((v) & 0xF) << 0) #define RPC_SMDRENR 0x0064 /* R/W */ #define RPC_SMDRENR_HYPE (0x5 << 12) #define RPC_SMDRENR_ADDRE BIT(8) #define RPC_SMDRENR_OPDRE BIT(4) #define RPC_SMDRENR_SPIDRE BIT(0) #define RPC_PHYCNT 0x007C /* R/W */ #define RPC_PHYCNT_CAL BIT(31) #define PRC_PHYCNT_OCTA_AA BIT(22) #define PRC_PHYCNT_OCTA_SA BIT(23) #define PRC_PHYCNT_EXDS BIT(21) #define RPC_PHYCNT_OCT BIT(20) #define RPC_PHYCNT_WBUF2 BIT(4) #define RPC_PHYCNT_WBUF BIT(2) #define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0) #define RPC_PHYINT 0x0088 /* R/W */ #define RPC_PHYINT_RSTEN BIT(18) #define RPC_PHYINT_WPEN BIT(17) #define RPC_PHYINT_INTEN BIT(16) #define RPC_PHYINT_RST BIT(2) #define RPC_PHYINT_WP BIT(1) #define RPC_PHYINT_INT BIT(0) #define RPC_WBUF 0x8000 /* R/W size=4/8/16/32/64Bytes */ #define RPC_WBUF_SIZE 0x100 static uint32_t rpc_base = 0xee200000; static uint32_t mem_base = 0x08000000; enum rpc_hf_size { RPC_HF_SIZE_16BIT = RPC_SMENR_SPIDE(0x8), RPC_HF_SIZE_32BIT = RPC_SMENR_SPIDE(0xC), RPC_HF_SIZE_64BIT = RPC_SMENR_SPIDE(0xF), }; static int rpc_hf_wait_tend(struct target *target) { uint32_t reg = rpc_base + RPC_CMNSR; uint32_t val; unsigned long timeout = 1000; long long endtime; int ret; endtime = timeval_ms() + timeout; do { ret = target_read_u32(target, reg, &val); if (ret != ERROR_OK) return ERROR_FAIL; if (val & RPC_CMNSR_TEND) return ERROR_OK; alive_sleep(1); } while (timeval_ms() < endtime); LOG_ERROR("timeout"); return ERROR_TIMEOUT_REACHED; } static int clrsetbits_u32(struct target *target, uint32_t reg, uint32_t clr, uint32_t set) { uint32_t val; int ret; ret = target_read_u32(target, reg, &val); if (ret != ERROR_OK) return ret; val &= ~clr; val |= set; return target_write_u32(target, reg, val); } static int rpc_hf_mode(struct target *target, bool manual) { uint32_t val; int ret; ret = rpc_hf_wait_tend(target); if (ret != ERROR_OK) { LOG_ERROR("Mode TEND timeout"); return ret; } ret = clrsetbits_u32(target, rpc_base + RPC_PHYCNT, RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 | RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3), RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)); if (ret != ERROR_OK) return ret; ret = clrsetbits_u32(target, rpc_base + RPC_CMNCR, RPC_CMNCR_MD | RPC_CMNCR_BSZ(3), RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | (manual ? RPC_CMNCR_MD : 0) | RPC_CMNCR_BSZ(1)); if (ret != ERROR_OK) return ret; if (manual) return ERROR_OK; ret = target_write_u32(target, rpc_base + RPC_DRCR, RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF | RPC_DRCR_RBE); if (ret != ERROR_OK) return ret; ret = target_write_u32(target, rpc_base + RPC_DRCMR, RPC_DRCMR_CMD(0xA0)); if (ret != ERROR_OK) return ret; ret = target_write_u32(target, rpc_base + RPC_DRENR, RPC_DRENR_CDB(2) | RPC_DRENR_OCDB(2) | RPC_DRENR_ADB(2) | RPC_DRENR_SPIDB(2) | RPC_DRENR_CDE | RPC_DRENR_OCDE | RPC_DRENR_ADE(4)); if (ret != ERROR_OK) return ret; ret = target_write_u32(target, rpc_base + RPC_DRDMCR, RPC_DRDMCR_DMCYC(0xE)); if (ret != ERROR_OK) return ret; ret = target_write_u32(target, rpc_base + RPC_DRDRENR, RPC_DRDRENR_HYPE | RPC_DRDRENR_ADDRE | RPC_DRDRENR_DRDRE); if (ret != ERROR_OK) return ret; /* Dummy read */ return target_read_u32(target, rpc_base + RPC_DRCR, &val); } static int rpc_hf_xfer(struct target *target, target_addr_t addr, uint32_t wdata, uint32_t *rdata, enum rpc_hf_size size, bool write, const uint8_t *wbuf, unsigned int wbuf_size) { int ret; uint32_t val; if (wbuf_size != 0) { ret = rpc_hf_wait_tend(target); if (ret != ERROR_OK) { LOG_ERROR("Xfer TEND timeout"); return ret; } /* Write calibration magic */ ret = target_write_u32(target, rpc_base + RPC_DRCR, 0x01FF0301); if (ret != ERROR_OK) return ret; ret = target_write_u32(target, rpc_base + RPC_PHYCNT, 0x80030277); if (ret != ERROR_OK) return ret; ret = target_write_memory(target, rpc_base | RPC_WBUF, 4, wbuf_size / 4, wbuf); if (ret != ERROR_OK) return ret; ret = clrsetbits_u32(target, rpc_base + RPC_CMNCR, RPC_CMNCR_MD | RPC_CMNCR_BSZ(3), RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | RPC_CMNCR_MD | RPC_CMNCR_BSZ(1)); if (ret != ERROR_OK) return ret; } else { ret = rpc_hf_mode(target, 1); if (ret != ERROR_OK) return ret; } /* Submit HF address, SMCMR CMD[7] ~= CA Bit# 47 (R/nW) */ ret = target_write_u32(target, rpc_base + RPC_SMCMR, write ? 0 : RPC_SMCMR_CMD(0x80)); if (ret != ERROR_OK) return ret; ret = target_write_u32(target, rpc_base + RPC_SMADR, addr >> 1); if (ret != ERROR_OK) return ret; ret = target_write_u32(target, rpc_base + RPC_SMOPR, 0x0); if (ret != ERROR_OK) return ret; ret = target_write_u32(target, rpc_base + RPC_SMDRENR, RPC_SMDRENR_HYPE | RPC_SMDRENR_ADDRE | RPC_SMDRENR_SPIDRE); if (ret != ERROR_OK) return ret; val = RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) | RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) | (wbuf_size ? RPC_SMENR_OPDB(2) : 0) | RPC_SMENR_CDE | RPC_SMENR_OCDE | RPC_SMENR_ADE(4) | size; if (write) { ret = target_write_u32(target, rpc_base + RPC_SMENR, val); if (ret != ERROR_OK) return ret; if (wbuf_size == 0) { buf_bswap32((uint8_t *)&wdata, (uint8_t *)&wdata, 4); ret = target_write_u32(target, rpc_base + RPC_SMWDR0, wdata); if (ret != ERROR_OK) return ret; } ret = target_write_u32(target, rpc_base + RPC_SMCR, RPC_SMCR_SPIWE | RPC_SMCR_SPIE); if (ret != ERROR_OK) return ret; } else { val |= RPC_SMENR_DME; ret = target_write_u32(target, rpc_base + RPC_SMDMCR, RPC_SMDMCR_DMCYC(0xE)); if (ret != ERROR_OK) return ret; ret = target_write_u32(target, rpc_base + RPC_SMENR, val); if (ret != ERROR_OK) return ret; ret = target_write_u32(target, rpc_base + RPC_SMCR, RPC_SMCR_SPIRE | RPC_SMCR_SPIE); if (ret != ERROR_OK) return ret; ret = rpc_hf_wait_tend(target); if (ret != ERROR_OK) return ret; uint32_t val32; ret = target_read_u32(target, rpc_base + RPC_SMRDR0, &val32); if (ret != ERROR_OK) return ret; buf_bswap32((uint8_t *)&val32, (uint8_t *)&val32, 4); *rdata = val32; } ret = rpc_hf_mode(target, 0); if (ret != ERROR_OK) LOG_ERROR("Xfer done TEND timeout"); return ret; } static int rpchf_target_write_memory(struct flash_bank *bank, target_addr_t addr, uint32_t count, const uint8_t *buffer) { struct target *target = bank->target; uint32_t wdata; if (count != 2) return ERROR_FAIL; wdata = buffer[0] | (buffer[1] << 8); return rpc_hf_xfer(target, addr, wdata, NULL, RPC_HF_SIZE_16BIT, true, NULL, 0); } static int rpchf_target_read_memory(struct flash_bank *bank, target_addr_t addr, uint32_t count, uint8_t *buffer) { struct target *target = bank->target; uint32_t i, rdata; int ret; for (i = 0; i < count; i++) { ret = rpc_hf_xfer(target, addr + (2 * i), 0, &rdata, RPC_HF_SIZE_16BIT, false, NULL, 0); if (ret != ERROR_OK) return ret; buffer[(2 * i) + 0] = rdata & 0xff; buffer[(2 * i) + 1] = (rdata >> 8) & 0xff; } return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(rpchf_flash_bank_command) { struct cfi_flash_bank *cfi_info; int ret; ret = cfi_flash_bank_cmd(bank, CMD_ARGC, CMD_ARGV); if (ret != ERROR_OK) return ret; cfi_info = bank->driver_priv; cfi_info->read_mem = rpchf_target_read_memory; cfi_info->write_mem = rpchf_target_write_memory; return ERROR_OK; } static int rpchf_spansion_write_words(struct flash_bank *bank, const uint8_t *word, uint32_t wordcount, uint32_t address) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; /* Calculate buffer size and boundary mask * buffersize is (buffer size per chip) * (number of chips) * bufferwsize is buffersize in words */ uint32_t buffersize = RPC_WBUF_SIZE; uint32_t buffermask = buffersize - 1; uint32_t bufferwsize = buffersize / 2; /* Check for valid range */ if (address & buffermask) { LOG_ERROR("Write address at base " TARGET_ADDR_FMT ", address 0x%" PRIx32 " not aligned to 2^%d boundary", bank->base, address, cfi_info->max_buf_write_size); return ERROR_FLASH_OPERATION_FAILED; } /* Check for valid size */ if (wordcount > bufferwsize) { LOG_ERROR("Number of data words %" PRIu32 " exceeds available buffersize %" PRIu32, wordcount, buffersize); return ERROR_FLASH_OPERATION_FAILED; } /* Unlock */ retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0xa0, cfi_flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; retval = rpc_hf_xfer(bank->target, address, 0, NULL, RPC_HF_SIZE_64BIT, true, word, wordcount * 2); if (retval != ERROR_OK) return retval; if (cfi_spansion_wait_status_busy(bank, cfi_info->word_write_timeout) != ERROR_OK) { retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("couldn't write block at base " TARGET_ADDR_FMT ", address 0x%" PRIx32 ", size 0x%" PRIx32, bank->base, address, bufferwsize); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int rpchf_write_words(struct flash_bank *bank, const uint8_t *word, uint32_t wordcount, uint32_t address) { return rpchf_spansion_write_words(bank, word, wordcount, address); } static int rpchf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct cfi_flash_bank *cfi_info = bank->driver_priv; uint32_t address = bank->base + offset; /* address of first byte to be programmed */ uint32_t write_p; int align; /* number of unaligned bytes */ uint8_t current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being *programmed */ int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; /* start at the first byte of the first word (bus_width size) */ write_p = address & ~(bank->bus_width - 1); align = address - write_p; if (align != 0) { LOG_INFO("Fixup %d unaligned head bytes", align); /* read a complete word from flash */ retval = cfi_target_read_memory(bank, write_p, 1, current_word); if (retval != ERROR_OK) return retval; /* replace only bytes that must be written */ for (unsigned int i = align; (i < bank->bus_width) && (count > 0); i++, count--) { if (cfi_info->data_swap) /* data bytes are swapped (reverse endianness) */ current_word[bank->bus_width - i] = *buffer++; else current_word[i] = *buffer++; } retval = cfi_write_word(bank, current_word, write_p); if (retval != ERROR_OK) return retval; write_p += bank->bus_width; } /* Calculate buffer size and boundary mask * buffersize is (buffer size per chip) * (number of chips) * bufferwsize is buffersize in words */ uint32_t buffersize = RPC_WBUF_SIZE; uint32_t buffermask = buffersize-1; uint32_t bufferwsize = buffersize / bank->bus_width; /* fall back to memory writes */ while (count >= (uint32_t)bank->bus_width) { bool fallback; if ((write_p & 0xff) == 0) { LOG_INFO("Programming at 0x%08" PRIx32 ", count 0x%08" PRIx32 " bytes remaining", write_p, count); } fallback = true; if ((bufferwsize > 0) && (count >= buffersize) && !(write_p & buffermask)) { retval = rpchf_write_words(bank, buffer, bufferwsize, write_p); if (retval == ERROR_OK) { buffer += buffersize; write_p += buffersize; count -= buffersize; fallback = false; } else if (retval != ERROR_FLASH_OPER_UNSUPPORTED) return retval; } /* try the slow way? */ if (fallback) { for (unsigned int i = 0; i < bank->bus_width; i++) current_word[i] = *buffer++; retval = cfi_write_word(bank, current_word, write_p); if (retval != ERROR_OK) return retval; write_p += bank->bus_width; count -= bank->bus_width; } } /* return to read array mode, so we can read from flash again for padding */ retval = cfi_reset(bank); if (retval != ERROR_OK) return retval; /* handle unaligned tail bytes */ if (count > 0) { LOG_INFO("Fixup %" PRIu32 " unaligned tail bytes", count); /* read a complete word from flash */ retval = cfi_target_read_memory(bank, write_p, 1, current_word); if (retval != ERROR_OK) return retval; /* replace only bytes that must be written */ for (unsigned int i = 0; (i < bank->bus_width) && (count > 0); i++, count--) if (cfi_info->data_swap) /* data bytes are swapped (reverse endianness) */ current_word[bank->bus_width - i] = *buffer++; else current_word[i] = *buffer++; retval = cfi_write_word(bank, current_word, write_p); if (retval != ERROR_OK) return retval; } /* return to read array mode */ return cfi_reset(bank); } static int rpchf_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct target *target = bank->target; LOG_DEBUG("reading buffer of %" PRIu32 " byte at 0x%8.8" PRIx32, count, offset); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; return target_read_memory(target, offset | mem_base, 4, count / 4, buffer); } const struct flash_driver renesas_rpchf_flash = { .name = "rpchf", .flash_bank_command = rpchf_flash_bank_command, .erase = cfi_erase, .protect = cfi_protect, .write = rpchf_write, .read = rpchf_read, .probe = cfi_probe, .auto_probe = cfi_auto_probe, .erase_check = default_flash_blank_check, .protect_check = cfi_protect_check, .info = cfi_get_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/rp2040.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> #include "spi.h" /* NOTE THAT THIS CODE REQUIRES FLASH ROUTINES in BOOTROM WITH FUNCTION TABLE PTR AT 0x00000010 Your gdbinit should load the bootrom.elf if appropriate */ /* this is 'M' 'u', 1 (version) */ #define BOOTROM_MAGIC 0x01754d #define BOOTROM_MAGIC_ADDR 0x00000010 /* Call a ROM function via the debug trampoline Up to four arguments passed in r0...r3 as per ABI Function address is passed in r7 the trampoline is needed because OpenOCD "algorithm" code insists on sw breakpoints. */ #define MAKE_TAG(a, b) (((b)<<8) | a) #define FUNC_DEBUG_TRAMPOLINE MAKE_TAG('D', 'T') #define FUNC_DEBUG_TRAMPOLINE_END MAKE_TAG('D', 'E') #define FUNC_FLASH_EXIT_XIP MAKE_TAG('E', 'X') #define FUNC_CONNECT_INTERNAL_FLASH MAKE_TAG('I', 'F') #define FUNC_FLASH_RANGE_ERASE MAKE_TAG('R', 'E') #define FUNC_FLASH_RANGE_PROGRAM MAKE_TAG('R', 'P') #define FUNC_FLASH_FLUSH_CACHE MAKE_TAG('F', 'C') #define FUNC_FLASH_ENTER_CMD_XIP MAKE_TAG('C', 'X') struct rp2040_flash_bank { /* flag indicating successful flash probe */ bool probed; /* stack used by Boot ROM calls */ struct working_area *stack; /* function jump table populated by rp2040_flash_probe() */ uint16_t jump_debug_trampoline; uint16_t jump_debug_trampoline_end; uint16_t jump_flash_exit_xip; uint16_t jump_connect_internal_flash; uint16_t jump_flash_range_erase; uint16_t jump_flash_range_program; uint16_t jump_flush_cache; uint16_t jump_enter_cmd_xip; /* detected model of SPI flash */ const struct flash_device *dev; }; /* guessed SPI flash description if autodetection disabled (same as win w25q16jv) */ static const struct flash_device rp2040_default_spi_device = FLASH_ID("autodetect disabled", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0, 0x100, 0x10000, 0); static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16_t *symbol) { uint32_t magic; int err = target_read_u32(target, BOOTROM_MAGIC_ADDR, &magic); if (err != ERROR_OK) return err; magic &= 0xffffff; /* ignore bootrom version */ if (magic != BOOTROM_MAGIC) { if (!((magic ^ BOOTROM_MAGIC)&0xffff)) LOG_ERROR("Incorrect RP2040 BOOT ROM version"); else LOG_ERROR("RP2040 BOOT ROM not found"); return ERROR_FAIL; } /* dereference the table pointer */ uint16_t table_entry; err = target_read_u16(target, BOOTROM_MAGIC_ADDR + 4, &table_entry); if (err != ERROR_OK) return err; uint16_t entry_tag; do { err = target_read_u16(target, table_entry, &entry_tag); if (err != ERROR_OK) return err; if (entry_tag == tag) { /* 16 bit symbol is next */ return target_read_u16(target, table_entry + 2, symbol); } table_entry += 4; } while (entry_tag); return ERROR_FAIL; } static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank *priv, uint16_t func_offset, uint32_t argdata[], unsigned int n_args, unsigned int timeout_ms) { char *regnames[4] = { "r0", "r1", "r2", "r3" }; assert(n_args <= ARRAY_SIZE(regnames)); /* only allow register arguments */ if (!priv->stack) { LOG_ERROR("no stack for flash programming code"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } target_addr_t stacktop = priv->stack->address + priv->stack->size; LOG_TARGET_DEBUG(target, "Calling ROM func @0x%" PRIx16 " with %u arguments", func_offset, n_args); struct reg_param args[ARRAY_SIZE(regnames) + 2]; struct armv7m_algorithm alg_info; for (unsigned int i = 0; i < n_args; ++i) { init_reg_param(&args[i], regnames[i], 32, PARAM_OUT); buf_set_u32(args[i].value, 0, 32, argdata[i]); } /* Pass function pointer in r7 */ init_reg_param(&args[n_args], "r7", 32, PARAM_OUT); buf_set_u32(args[n_args].value, 0, 32, func_offset); /* Setup stack */ init_reg_param(&args[n_args + 1], "sp", 32, PARAM_OUT); buf_set_u32(args[n_args + 1].value, 0, 32, stacktop); unsigned int n_reg_params = n_args + 2; /* User arguments + r7 + sp */ for (unsigned int i = 0; i < n_reg_params; ++i) LOG_DEBUG("Set %s = 0x%" PRIx32, args[i].reg_name, buf_get_u32(args[i].value, 0, 32)); /* Actually call the function */ alg_info.common_magic = ARMV7M_COMMON_MAGIC; alg_info.core_mode = ARM_MODE_THREAD; int err = target_run_algorithm( target, 0, NULL, /* No memory arguments */ n_reg_params, args, /* User arguments + r7 + sp */ priv->jump_debug_trampoline, priv->jump_debug_trampoline_end, timeout_ms, &alg_info ); for (unsigned int i = 0; i < n_reg_params; ++i) destroy_reg_param(&args[i]); if (err != ERROR_OK) LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16, func_offset); return err; } /* Finalize flash write/erase/read ID * - flush cache * - enters memory-mapped (XIP) mode to make flash data visible * - deallocates target ROM func stack if previously allocated */ static int rp2040_finalize_stack_free(struct flash_bank *bank) { struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; /* Always flush before returning to execute-in-place, to invalidate stale * cache contents. The flush call also restores regular hardware-controlled * chip select following a rp2040_flash_exit_xip(). */ LOG_DEBUG("Flushing flash cache after write behind"); int err = rp2040_call_rom_func(target, priv, priv->jump_flush_cache, NULL, 0, 1000); if (err != ERROR_OK) { LOG_ERROR("Failed to flush flash cache"); /* Intentionally continue after error and try to setup xip anyway */ } LOG_DEBUG("Configuring SSI for execute-in-place"); err = rp2040_call_rom_func(target, priv, priv->jump_enter_cmd_xip, NULL, 0, 1000); if (err != ERROR_OK) LOG_ERROR("Failed to set SSI to XIP mode"); target_free_working_area(target, priv->stack); priv->stack = NULL; return err; } /* Prepare flash write/erase/read ID * - allocates a stack for target ROM func * - switches the SPI interface from memory-mapped mode to direct command mode * Always pair with a call of rp2040_finalize_stack_free() * after flash operation finishes or fails. */ static int rp2040_stack_grab_and_prep(struct flash_bank *bank) { struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; /* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */ const int STACK_SIZE = 256; int err = target_alloc_working_area(target, STACK_SIZE, &priv->stack); if (err != ERROR_OK) { LOG_ERROR("Could not allocate stack for flash programming code"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } LOG_DEBUG("Connecting internal flash"); err = rp2040_call_rom_func(target, priv, priv->jump_connect_internal_flash, NULL, 0, 1000); if (err != ERROR_OK) { LOG_ERROR("Failed to connect internal flash"); return err; } LOG_DEBUG("Kicking flash out of XIP mode"); err = rp2040_call_rom_func(target, priv, priv->jump_flash_exit_xip, NULL, 0, 1000); if (err != ERROR_OK) { LOG_ERROR("Failed to exit flash XIP mode"); return err; } return ERROR_OK; } static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { LOG_DEBUG("Writing %d bytes starting at 0x%" PRIx32, count, offset); struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } struct working_area *bounce = NULL; int err = rp2040_stack_grab_and_prep(bank); if (err != ERROR_OK) goto cleanup; unsigned int avail_pages = target_get_working_area_avail(target) / priv->dev->pagesize; /* We try to allocate working area rounded down to device page size, * al least 1 page, at most the write data size */ unsigned int chunk_size = MIN(MAX(avail_pages, 1) * priv->dev->pagesize, count); err = target_alloc_working_area(target, chunk_size, &bounce); if (err != ERROR_OK) { LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue"); goto cleanup; } LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address); while (count > 0) { uint32_t write_size = count > chunk_size ? chunk_size : count; LOG_DEBUG("Writing %d bytes to offset 0x%" PRIx32, write_size, offset); err = target_write_buffer(target, bounce->address, write_size, buffer); if (err != ERROR_OK) { LOG_ERROR("Could not load data into target bounce buffer"); break; } uint32_t args[3] = { offset, /* addr */ bounce->address, /* data */ write_size /* count */ }; err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program, args, ARRAY_SIZE(args), 3000); if (err != ERROR_OK) { LOG_ERROR("Failed to invoke flash programming code on target"); break; } buffer += write_size; offset += write_size; count -= write_size; } cleanup: target_free_working_area(target, bounce); rp2040_finalize_stack_free(bank); return err; } static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } uint32_t start_addr = bank->sectors[first].offset; uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr; LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr); int err = rp2040_stack_grab_and_prep(bank); if (err != ERROR_OK) goto cleanup; LOG_DEBUG("Remote call flash_range_erase"); uint32_t args[4] = { bank->sectors[first].offset, /* addr */ bank->sectors[last].offset + bank->sectors[last].size - bank->sectors[first].offset, /* count */ priv->dev->sectorsize, /* block_size */ priv->dev->erase_cmd /* block_cmd */ }; /* The RP2040 Boot ROM provides a _flash_range_erase() API call documented in Section 2.8.3.1.3: https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf and the particular source code for said Boot ROM function can be found here: https://github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c In theory, the function algorithm provides for erasing both a smaller "sector" (4096 bytes) and an optional larger "block" (size and command provided in args). */ unsigned int timeout_ms = 2000 * (last - first) + 1000; err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args), timeout_ms); cleanup: rp2040_finalize_stack_free(bank); return err; } /* ----------------------------------------------------------------------------- Driver probing etc */ static int rp2040_ssel_active(struct target *target, bool active) { const target_addr_t qspi_ctrl_addr = 0x4001800c; const uint32_t qspi_ctrl_outover_low = 2UL << 8; const uint32_t qspi_ctrl_outover_high = 3UL << 8; uint32_t state = (active) ? qspi_ctrl_outover_low : qspi_ctrl_outover_high; uint32_t val; int err = target_read_u32(target, qspi_ctrl_addr, &val); if (err != ERROR_OK) return err; val = (val & ~qspi_ctrl_outover_high) | state; err = target_write_u32(target, qspi_ctrl_addr, val); if (err != ERROR_OK) return err; return ERROR_OK; } static int rp2040_spi_read_flash_id(struct target *target, uint32_t *devid) { uint32_t device_id = 0; const target_addr_t ssi_dr0 = 0x18000060; int err = rp2040_ssel_active(target, true); /* write RDID request into SPI peripheral's FIFO */ for (int count = 0; (count < 4) && (err == ERROR_OK); count++) err = target_write_u32(target, ssi_dr0, SPIFLASH_READ_ID); /* by this time, there is a receive FIFO entry for every write */ for (int count = 0; (count < 4) && (err == ERROR_OK); count++) { uint32_t status; err = target_read_u32(target, ssi_dr0, &status); device_id >>= 8; device_id |= (status & 0xFF) << 24; } if (err == ERROR_OK) *devid = device_id >> 8; int err2 = rp2040_ssel_active(target, false); if (err2 != ERROR_OK) LOG_ERROR("SSEL inactive failed"); return err; } static int rp2040_flash_probe(struct flash_bank *bank) { struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } int err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE, &priv->jump_debug_trampoline); if (err != ERROR_OK) { LOG_ERROR("Debug trampoline not found in RP2040 ROM."); return err; } priv->jump_debug_trampoline &= ~1u; /* mask off thumb bit */ err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE_END, &priv->jump_debug_trampoline_end); if (err != ERROR_OK) { LOG_ERROR("Debug trampoline end not found in RP2040 ROM."); return err; } priv->jump_debug_trampoline_end &= ~1u; /* mask off thumb bit */ err = rp2040_lookup_symbol(target, FUNC_FLASH_EXIT_XIP, &priv->jump_flash_exit_xip); if (err != ERROR_OK) { LOG_ERROR("Function FUNC_FLASH_EXIT_XIP not found in RP2040 ROM."); return err; } err = rp2040_lookup_symbol(target, FUNC_CONNECT_INTERNAL_FLASH, &priv->jump_connect_internal_flash); if (err != ERROR_OK) { LOG_ERROR("Function FUNC_CONNECT_INTERNAL_FLASH not found in RP2040 ROM."); return err; } err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_ERASE, &priv->jump_flash_range_erase); if (err != ERROR_OK) { LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2040 ROM."); return err; } err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_PROGRAM, &priv->jump_flash_range_program); if (err != ERROR_OK) { LOG_ERROR("Function FUNC_FLASH_RANGE_PROGRAM not found in RP2040 ROM."); return err; } err = rp2040_lookup_symbol(target, FUNC_FLASH_FLUSH_CACHE, &priv->jump_flush_cache); if (err != ERROR_OK) { LOG_ERROR("Function FUNC_FLASH_FLUSH_CACHE not found in RP2040 ROM."); return err; } err = rp2040_lookup_symbol(target, FUNC_FLASH_ENTER_CMD_XIP, &priv->jump_enter_cmd_xip); if (err != ERROR_OK) { LOG_ERROR("Function FUNC_FLASH_ENTER_CMD_XIP not found in RP2040 ROM."); return err; } if (bank->size) { /* size overridden, suppress reading SPI flash ID */ priv->dev = &rp2040_default_spi_device; LOG_DEBUG("SPI flash autodetection disabled, using configured size"); } else { /* zero bank size in cfg, read SPI flash ID and autodetect */ err = rp2040_stack_grab_and_prep(bank); uint32_t device_id = 0; if (err == ERROR_OK) err = rp2040_spi_read_flash_id(target, &device_id); rp2040_finalize_stack_free(bank); if (err != ERROR_OK) return err; /* search for a SPI flash Device ID match */ priv->dev = NULL; for (const struct flash_device *p = flash_devices; p->name ; p++) if (p->device_id == device_id) { priv->dev = p; break; } if (!priv->dev) { LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", device_id); return ERROR_FAIL; } LOG_INFO("Found flash device '%s' (ID 0x%08" PRIx32 ")", priv->dev->name, priv->dev->device_id); bank->size = priv->dev->size_in_bytes; } /* the Boot ROM flash_range_program() routine requires page alignment */ bank->write_start_alignment = priv->dev->pagesize; bank->write_end_alignment = priv->dev->pagesize; bank->num_sectors = bank->size / priv->dev->sectorsize; LOG_INFO("RP2040 B0 Flash Probe: %" PRIu32 " bytes @" TARGET_ADDR_FMT ", in %u sectors\n", bank->size, bank->base, bank->num_sectors); bank->sectors = alloc_block_array(0, priv->dev->sectorsize, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; if (err == ERROR_OK) priv->probed = true; return err; } static int rp2040_flash_auto_probe(struct flash_bank *bank) { struct rp2040_flash_bank *priv = bank->driver_priv; if (priv->probed) return ERROR_OK; return rp2040_flash_probe(bank); } static void rp2040_flash_free_driver_priv(struct flash_bank *bank) { free(bank->driver_priv); bank->driver_priv = NULL; } /* ----------------------------------------------------------------------------- Driver boilerplate */ FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command) { struct rp2040_flash_bank *priv; priv = malloc(sizeof(struct rp2040_flash_bank)); priv->probed = false; /* Set up driver_priv */ bank->driver_priv = priv; return ERROR_OK; } const struct flash_driver rp2040_flash = { .name = "rp2040_flash", .flash_bank_command = rp2040_flash_bank_command, .erase = rp2040_flash_erase, .write = rp2040_flash_write, .read = default_flash_read, .probe = rp2040_flash_probe, .auto_probe = rp2040_flash_auto_probe, .erase_check = default_flash_blank_check, .free_driver_priv = rp2040_flash_free_driver_priv }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/rsl10.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2022 by Toms Stūrmanis * * toms.sturmanis@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdint.h> #include <helper/binarybuffer.h> #include <helper/bits.h> #include <target/algorithm.h> #include <target/arm_adi_v5.h> #include <target/armv7m.h> #include <target/cortex_m.h> #include "imp.h" #define RSL10_FLASH_ADDRESS_MAIN 0x00100000 #define RSL10_FLASH_ADDRESS_NVR1 0x00080000 #define RSL10_FLASH_ADDRESS_NVR2 0x00080800 #define RSL10_FLASH_ADDRESS_NVR3 0x00081000 #define RSL10_FLASH_ADDRESS_NVR4 0x00081800 #define RSL10_FLASH_ADDRESS_LOCK_INFO_SETTING 0x00081040 #define RSL10_REG_ID 0x1FFFFFFC #define RSL10_FLASH_REG_MAIN_WRITE_UNLOCK 0x40000504 #define RSL10_FLASH_REG_MAIN_CTRL 0x40000508 #define RSL10_FLASH_REG_IF_STATUS 0x40000538 #define RSL10_FLASH_REG_NVR_WRITE_UNLOCK 0x40000548 #define RSL10_FLASH_REG_NVR_CTRL 0x4000054C #define RSL10_FLASH_REG_DEBUG_UNLOCK_KEY1 0x400000F0 #define RSL10_FLASH_REG_DEBUG_UNLOCK_KEY2 0x400000F4 #define RSL10_FLASH_REG_DEBUG_UNLOCK_KEY3 0x400000F8 #define RSL10_FLASH_REG_DEBUG_UNLOCK_KEY4 0x400000FC #define RSL10_NVR3_USER_KEY_OFFSET 0x40 #define RSL10_ID 0x09010106 #define RSL10_FLASH_KEY_MAIN 0xDBC8264E #define RSL10_FLASH_KEY_NVR 0x71B371F5 #define RSL10_KEY_DEBUG_LOCK 0x4C6F634B #define RSL10_FLASH_REG_MAIN_CTRL_LOW_W_ENABLE BIT(0) #define RSL10_FLASH_REG_MAIN_CTRL_MIDDLE_W_ENABLE BIT(1) #define RSL10_FLASH_REG_MAIN_CTRL_HIGH_W_ENABLE BIT(2) #define RSL10_FLASH_REG_NVR_CTRL_NVR1_W_ENABLE BIT(1) #define RSL10_FLASH_REG_NVR_CTRL_NVR2_W_ENABLE BIT(2) #define RSL10_FLASH_REG_NVR_CTRL_NVR3_W_ENABLE BIT(3) #define RSL10_FLASH_REG_STATUS_LOW_W_UNLOCKED BIT(0) #define RSL10_FLASH_REG_STATUS_MIDDLE_W_UNLOCKED BIT(1) #define RSL10_FLASH_REG_STATUS_HIGH_W_UNLOCKED BIT(2) #define RSL10_FLASH_REG_STATUS_NVR1_W_UNLOCKED BIT(4) #define RSL10_FLASH_REG_STATUS_NVR2_W_UNLOCKED BIT(5) #define RSL10_FLASH_REG_STATUS_NVR3_W_UNLOCKED BIT(6) #define RSL10_ROM_CMD_WRITE_WORD_PAIR 0x3C #define RSL10_ROM_CMD_WRITE_BUFFER 0x40 #define RSL10_ROM_CMD_ERASE_SECTOR 0x44 #define RSL10_ROM_CMD_ERASE_ALL 0x48 #define FLASH_SECTOR_SIZE 0x2000 #define RSL10_ROM_CMD_WRITE_BUFFER_MAX_SIZE FLASH_SECTOR_SIZE #define ALGO_STACK_POINTER_ADDR 0x20002000 /* Used to launch flash related functions from ROM * Params : * r0-r2 = arguments * r3 = target address in rom */ static const uint8_t rsl10_rom_launcher_code[] = { #include "../../../contrib/loaders/flash/rsl10/rom_launcher.inc" }; enum rsl10_flash_status { RSL10_FLASH_ERR_NONE = 0x0, RSL10_FLASH_ERR_GENERAL_FAILURE = 0x1, RSL10_FLASH_ERR_WRITE_NOT_ENABLED = 0x2, RSL10_FLASH_ERR_BAD_ADDRESS = 0x3, RSL10_FLASH_ERR_ERASE_FAILED = 0x4, RSL10_FLASH_ERR_BAD_LENGTH = 0x5, RSL10_FLASH_ERR_INACCESSIBLE = 0x6, RSL10_FLASH_ERR_COPIER_BUSY = 0x7, RSL10_FLASH_ERR_PROG_FAILED = 0x8, RSL10_FLASH_MAX_ERR_CODES /* must be the last one */ }; static const char *const rsl10_error_list[] = { [RSL10_FLASH_ERR_GENERAL_FAILURE] = "general failure", [RSL10_FLASH_ERR_WRITE_NOT_ENABLED] = "write not enabled, protected", [RSL10_FLASH_ERR_BAD_ADDRESS] = "bad address", [RSL10_FLASH_ERR_ERASE_FAILED] = "erase failed", [RSL10_FLASH_ERR_BAD_LENGTH] = "bad length", [RSL10_FLASH_ERR_INACCESSIBLE] = "inaccessible: not powered up, or isolated", [RSL10_FLASH_ERR_COPIER_BUSY] = "copier busy", [RSL10_FLASH_ERR_PROG_FAILED] = "prog failed", }; static const char *rsl10_error(enum rsl10_flash_status x) { if (x >= RSL10_FLASH_MAX_ERR_CODES || !rsl10_error_list[x]) return "unknown"; return rsl10_error_list[x]; } const struct flash_driver rsl10_flash; struct rsl10_info { unsigned int refcount; struct rsl10_bank { struct rsl10_info *chip; bool probed; } bank[5]; struct target *target; unsigned int flash_size_kb; }; static bool rsl10_bank_is_probed(const struct flash_bank *bank) { struct rsl10_bank *nbank = bank->driver_priv; assert(nbank); return nbank->probed; } static int rsl10_probe(struct flash_bank *bank); static int rsl10_get_probed_chip_if_halted(struct flash_bank *bank, struct rsl10_info **chip) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } struct rsl10_bank *nbank = bank->driver_priv; *chip = nbank->chip; if (rsl10_bank_is_probed(bank)) return ERROR_OK; return rsl10_probe(bank); } static int rsl10_protect_check(struct flash_bank *bank) { struct rsl10_bank *nbank = bank->driver_priv; struct rsl10_info *chip = nbank->chip; assert(chip); uint32_t status; int retval = target_read_u32(bank->target, RSL10_FLASH_REG_IF_STATUS, &status); if (retval != ERROR_OK) return retval; if (bank->base == RSL10_FLASH_ADDRESS_MAIN) { for (unsigned int i = 0; i < bank->num_prot_blocks; i++) bank->prot_blocks[i].is_protected = (status & (1 << i)) ? 0 : 1; } else { uint32_t test_bit = 0; switch (bank->base) { case RSL10_FLASH_ADDRESS_NVR1: test_bit = RSL10_FLASH_REG_STATUS_NVR1_W_UNLOCKED; break; case RSL10_FLASH_ADDRESS_NVR2: test_bit = RSL10_FLASH_REG_STATUS_NVR2_W_UNLOCKED; break; case RSL10_FLASH_ADDRESS_NVR3: test_bit = RSL10_FLASH_REG_STATUS_NVR3_W_UNLOCKED; break; default: break; } bank->sectors[0].is_protected = (status & test_bit) ? 0 : 1; } return ERROR_OK; } static int rsl10_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct rsl10_info *chip; int retval = rsl10_get_probed_chip_if_halted(bank, &chip); if (retval != ERROR_OK) return retval; if (bank->base == RSL10_FLASH_ADDRESS_MAIN) { uint32_t status; retval = target_read_u32(bank->target, RSL10_FLASH_REG_MAIN_CTRL, &status); if (retval != ERROR_OK) return retval; for (unsigned int i = first; i <= last; i++) { if (set) status &= ~(1 << i); else status |= (1 << i); } retval = target_write_u32(bank->target, RSL10_FLASH_REG_MAIN_CTRL, status); if (retval != ERROR_OK) return retval; retval = target_write_u32(bank->target, RSL10_FLASH_REG_MAIN_WRITE_UNLOCK, RSL10_FLASH_KEY_MAIN); if (retval != ERROR_OK) return retval; } else { uint32_t bit = 0; switch (bank->base) { case RSL10_FLASH_ADDRESS_NVR1: bit = RSL10_FLASH_REG_NVR_CTRL_NVR1_W_ENABLE; break; case RSL10_FLASH_ADDRESS_NVR2: bit = RSL10_FLASH_REG_NVR_CTRL_NVR2_W_ENABLE; break; case RSL10_FLASH_ADDRESS_NVR3: bit = RSL10_FLASH_REG_NVR_CTRL_NVR3_W_ENABLE; break; default: break; } uint32_t status; retval = target_read_u32(bank->target, RSL10_FLASH_REG_NVR_CTRL, &status); if (retval != ERROR_OK) return retval; if (set) status &= ~bit; else status |= bit; retval = target_write_u32(bank->target, RSL10_FLASH_REG_NVR_CTRL, status); if (retval != ERROR_OK) return retval; retval = target_write_u32(bank->target, RSL10_FLASH_REG_NVR_WRITE_UNLOCK, RSL10_FLASH_KEY_NVR); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int rsl10_check_device(struct flash_bank *bank) { uint32_t configid; int retval = target_read_u32(bank->target, RSL10_REG_ID, &configid); if (retval != ERROR_OK) return retval; if (configid != RSL10_ID) { LOG_ERROR("This is not supported (RSL10) device, use other flash driver!!!"); return ERROR_TARGET_INVALID; } return ERROR_OK; } static int rsl10_probe(struct flash_bank *bank) { struct rsl10_bank *nbank = bank->driver_priv; struct rsl10_info *chip = nbank->chip; int retval = rsl10_check_device(bank); if (retval != ERROR_OK) return retval; unsigned int bank_id; unsigned int num_prot_blocks = 0; switch (bank->base) { case RSL10_FLASH_ADDRESS_MAIN: bank_id = 0; num_prot_blocks = 3; break; case RSL10_FLASH_ADDRESS_NVR1: bank_id = 1; break; case RSL10_FLASH_ADDRESS_NVR2: bank_id = 2; break; case RSL10_FLASH_ADDRESS_NVR3: bank_id = 3; break; default: return ERROR_FAIL; } uint32_t flash_page_size = 2048; bank->write_start_alignment = 8; bank->write_end_alignment = 8; bank->num_sectors = bank->size / flash_page_size; chip->flash_size_kb = bank->size / 1024; free(bank->sectors); bank->sectors = NULL; bank->sectors = alloc_block_array(0, flash_page_size, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; free(bank->prot_blocks); bank->prot_blocks = NULL; if (num_prot_blocks > 0) { bank->num_prot_blocks = num_prot_blocks; bank->prot_blocks = alloc_block_array(0, bank->num_sectors / 3 * flash_page_size, bank->num_prot_blocks); if (!bank->prot_blocks) return ERROR_FAIL; } chip->bank[bank_id].probed = true; return ERROR_OK; } static int rsl10_auto_probe(struct flash_bank *bank) { if (rsl10_bank_is_probed(bank)) return ERROR_OK; return rsl10_probe(bank); } static int rsl10_ll_flash_erase(struct rsl10_info *chip, uint32_t address) { struct target *target = chip->target; struct working_area *write_algorithm; LOG_DEBUG("erasing buffer flash address=0x%" PRIx32, address); int retval = target_alloc_working_area(target, sizeof(rsl10_rom_launcher_code), &write_algorithm); if (retval != ERROR_OK) { LOG_ERROR("Current working area 0x%x is too small! Increase working area size!", target->working_area_size); return ERROR_FAIL; } retval = target_write_buffer(target, write_algorithm->address, sizeof(rsl10_rom_launcher_code), rsl10_rom_launcher_code); if (retval != ERROR_OK) goto free_algorithm; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* address */ init_reg_param(®_params[1], "r3", 32, PARAM_OUT); /* cmd */ init_reg_param(®_params[2], "sp", 32, PARAM_OUT); /* stack pointer */ buf_set_u32(reg_params[0].value, 0, 32, address); uint32_t cmd; retval = target_read_u32(target, RSL10_ROM_CMD_ERASE_SECTOR, &cmd); if (retval != ERROR_OK) goto free_reg_params; buf_set_u32(reg_params[1].value, 0, 32, cmd); buf_set_u32(reg_params[2].value, 0, 32, ALGO_STACK_POINTER_ADDR); retval = target_run_algorithm( target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, write_algorithm->address, write_algorithm->address + sizeof(rsl10_rom_launcher_code) - 2, 1000, &armv7m_info ); if (retval != ERROR_OK) goto free_reg_params; int algo_ret = buf_get_u32(reg_params[0].value, 0, 32); if (algo_ret != RSL10_FLASH_ERR_NONE) { LOG_ERROR("RSL10 ERASE ERROR: '%s' (%d)", rsl10_error(algo_ret), algo_ret); retval = ERROR_FLASH_SECTOR_NOT_ERASED; } free_reg_params: for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) destroy_reg_param(®_params[i]); free_algorithm: target_free_working_area(target, write_algorithm); return retval; } static int rsl10_ll_flash_write(struct rsl10_info *chip, uint32_t address, const uint8_t *buffer, uint32_t bytes) { struct target *target = chip->target; struct working_area *write_algorithm; if (bytes == 8) { uint32_t data; data = buf_get_u32(buffer, 0, 32); LOG_DEBUG("Writing 0x%" PRIx32 " to flash address=0x%" PRIx32 " bytes=0x%" PRIx32, data, address, bytes); } else LOG_DEBUG("Writing buffer to flash address=0x%" PRIx32 " bytes=0x%" PRIx32, address, bytes); /* allocate working area with flash programming code */ int retval = target_alloc_working_area(target, sizeof(rsl10_rom_launcher_code), &write_algorithm); if (retval != ERROR_OK) { LOG_ERROR("Current working area 0x%x is too small! Increase working area size!", target->working_area_size); return ERROR_FAIL; } retval = target_write_buffer(target, write_algorithm->address, sizeof(rsl10_rom_launcher_code), rsl10_rom_launcher_code); if (retval != ERROR_OK) goto free_algorithm; /* memory buffer, rounded down, to be multiple of 8 */ uint32_t buffer_avail = target_get_working_area_avail(target) & ~7; uint32_t buffer_size = MIN(RSL10_ROM_CMD_WRITE_BUFFER_MAX_SIZE, buffer_avail); struct working_area *source; retval = target_alloc_working_area(target, buffer_size, &source); if (retval != ERROR_OK) { LOG_ERROR("Current working area 0x%x is too small! Increase working area size!", target->working_area_size); goto free_algorithm; } struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* start addr, return value */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* length */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* data */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* cmd */ init_reg_param(®_params[4], "sp", 32, PARAM_OUT); /* stack pointer */ buf_set_u32(reg_params[4].value, 0, 32, ALGO_STACK_POINTER_ADDR); uint32_t cmd = 0; uint32_t sent_bytes = 0; uint32_t write_address = 0; uint32_t bytes_to_send = 0; uint32_t remaining_bytes = 0; retval = target_read_u32(target, RSL10_ROM_CMD_WRITE_BUFFER, &cmd); if (retval != ERROR_OK) goto free_everything; while (sent_bytes < bytes) { remaining_bytes = bytes - sent_bytes; bytes_to_send = remaining_bytes >= buffer_size ? buffer_size : remaining_bytes; retval = target_write_buffer(target, source->address, bytes_to_send, buffer + sent_bytes); if (retval != ERROR_OK) goto free_everything; write_address = address + sent_bytes; LOG_DEBUG( "write_address: 0x%" PRIx32 ", words: 0x%" PRIx32 ", source: 0x%" PRIx64 ", cmd: 0x%" PRIx32, write_address, bytes_to_send / 4, source->address, cmd ); buf_set_u32(reg_params[0].value, 0, 32, write_address); buf_set_u32(reg_params[1].value, 0, 32, bytes_to_send / 4); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, cmd); retval = target_run_algorithm( target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, write_algorithm->address, write_algorithm->address + sizeof(rsl10_rom_launcher_code) - 2, 1000, &armv7m_info ); if (retval != ERROR_OK) goto free_everything; int algo_ret = buf_get_u32(reg_params[0].value, 0, 32); if (algo_ret != RSL10_FLASH_ERR_NONE) { LOG_ERROR("RSL10 WRITE ERROR: '%s' (%d)", rsl10_error(algo_ret), algo_ret); retval = ERROR_FLASH_OPERATION_FAILED; goto free_everything; } sent_bytes += bytes_to_send; } free_everything: target_free_working_area(target, source); for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) destroy_reg_param(®_params[i]); free_algorithm: target_free_working_area(target, write_algorithm); return retval; } static int rsl10_mass_erase(struct target *target) { struct working_area *write_algorithm; int retval = target_alloc_working_area(target, sizeof(rsl10_rom_launcher_code), &write_algorithm); if (retval != ERROR_OK) { LOG_ERROR("Current working area 0x%x is too small! Increase working area size!", target->working_area_size); return ERROR_FAIL; } retval = target_write_buffer(target, write_algorithm->address, sizeof(rsl10_rom_launcher_code), rsl10_rom_launcher_code); if (retval != ERROR_OK) goto free_algorithm; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* return value */ init_reg_param(®_params[1], "r3", 32, PARAM_OUT); /* cmd */ init_reg_param(®_params[2], "sp", 32, PARAM_OUT); /* stack pointer */ uint32_t cmd; retval = target_read_u32(target, RSL10_ROM_CMD_ERASE_ALL, &cmd); if (retval != ERROR_OK) goto free_reg_params; buf_set_u32(reg_params[1].value, 0, 32, cmd); buf_set_u32(reg_params[2].value, 0, 32, ALGO_STACK_POINTER_ADDR); retval = target_run_algorithm( target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, write_algorithm->address, write_algorithm->address + sizeof(rsl10_rom_launcher_code) - 2, 1000, &armv7m_info ); if (retval != ERROR_OK) goto free_reg_params; int algo_ret = buf_get_u32(reg_params[0].value, 0, 32); if (algo_ret != RSL10_FLASH_ERR_NONE) { LOG_ERROR("RSL10 MASS ERASE ERROR: '%s' (%d)", rsl10_error(algo_ret), algo_ret); retval = ERROR_FLASH_OPERATION_FAILED; } free_reg_params: for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) destroy_reg_param(®_params[i]); free_algorithm: target_free_working_area(target, write_algorithm); return retval; } static int rsl10_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct rsl10_info *chip; int retval = rsl10_get_probed_chip_if_halted(bank, &chip); if (retval != ERROR_OK) return retval; return rsl10_ll_flash_write(chip, bank->base + offset, buffer, count); } static int rsl10_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { LOG_INFO("erase bank: %x, %x", first, last); int retval; struct rsl10_info *chip; retval = rsl10_get_probed_chip_if_halted(bank, &chip); if (retval != ERROR_OK) return retval; for (unsigned int i = first; i <= last; i++) { retval = rsl10_ll_flash_erase(chip, bank->base + i * 0x800); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static void rsl10_free_driver_priv(struct flash_bank *bank) { struct rsl10_bank *nbank = bank->driver_priv; struct rsl10_info *chip = nbank->chip; if (!chip) return; chip->refcount--; if (chip->refcount == 0) { free(chip); bank->driver_priv = NULL; } } static struct rsl10_info *rsl10_get_chip(struct target *target) { struct flash_bank *bank_iter; /* iterate over rsl10 banks of same target */ for (bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) { if (bank_iter->driver != &rsl10_flash) continue; if (bank_iter->target != target) continue; struct rsl10_bank *nbank = bank_iter->driver_priv; if (!nbank) continue; if (nbank->chip) return nbank->chip; } return NULL; } FLASH_BANK_COMMAND_HANDLER(rsl10_flash_bank_command) { struct rsl10_info *chip = NULL; struct rsl10_bank *nbank = NULL; LOG_INFO("Creating flash @ " TARGET_ADDR_FMT, bank->base); switch (bank->base) { case RSL10_FLASH_ADDRESS_MAIN: case RSL10_FLASH_ADDRESS_NVR1: case RSL10_FLASH_ADDRESS_NVR2: case RSL10_FLASH_ADDRESS_NVR3: case RSL10_FLASH_ADDRESS_NVR4: break; default: LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base); return ERROR_FAIL; } chip = rsl10_get_chip(bank->target); if (!chip) { chip = calloc(1, sizeof(*chip)); if (!chip) return ERROR_FAIL; chip->target = bank->target; } switch (bank->base) { case RSL10_FLASH_ADDRESS_MAIN: nbank = &chip->bank[0]; break; case RSL10_FLASH_ADDRESS_NVR1: nbank = &chip->bank[1]; break; case RSL10_FLASH_ADDRESS_NVR2: nbank = &chip->bank[2]; break; case RSL10_FLASH_ADDRESS_NVR3: nbank = &chip->bank[3]; break; case RSL10_FLASH_ADDRESS_NVR4: nbank = &chip->bank[4]; break; } assert(nbank); chip->refcount++; nbank->chip = chip; nbank->probed = false; bank->driver_priv = nbank; return ERROR_OK; } COMMAND_HANDLER(rsl10_lock_command) { struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC != 4) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = get_flash_bank_by_addr(target, RSL10_FLASH_ADDRESS_NVR3, true, &bank); if (retval != ERROR_OK) return retval; LOG_INFO("Keys used: %s %s %s %s", CMD_ARGV[0], CMD_ARGV[1], CMD_ARGV[2], CMD_ARGV[3]); uint32_t user_key[4]; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], user_key[0]); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], user_key[1]); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], user_key[2]); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], user_key[3]); uint8_t write_buffer[6 * 4]; target_buffer_set_u32(target, write_buffer, RSL10_KEY_DEBUG_LOCK); target_buffer_set_u32_array(target, &write_buffer[4], 4, user_key); /* pad the end to 64-bit word boundary */ memset(&write_buffer[5 * 4], bank->default_padded_value, 4); retval = rsl10_erase(bank, 0, 0); if (retval != ERROR_OK) return retval; retval = rsl10_write(bank, write_buffer, RSL10_NVR3_USER_KEY_OFFSET, sizeof(write_buffer)); if (retval != ERROR_OK) { /* erase sector, if write fails, otherwise it can lock debug with wrong keys */ return rsl10_erase(bank, 0, 0); } command_print( CMD, "****** WARNING ******\n" "rsl10 device has been successfully prepared to lock.\n" "Debug port is locked after restart.\n" "Unlock with 'rsl10_unlock key0 key1 key2 key3'\n" "****** ....... ******\n" ); return rsl10_protect(bank, true, 0, 0); } COMMAND_HANDLER(rsl10_unlock_command) { if (CMD_ARGC != 4) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); struct cortex_m_common *cortex_m = target_to_cm(target); struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; struct adiv5_ap *ap = dap_get_ap(dap, 0); uint32_t user_key[4]; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], user_key[0]); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], user_key[1]); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], user_key[2]); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], user_key[3]); uint8_t write_buffer1[4 * 4]; target_buffer_set_u32_array(target, write_buffer1, 4, user_key); int retval = mem_ap_write_buf(ap, write_buffer1, 4, 4, RSL10_FLASH_REG_DEBUG_UNLOCK_KEY1); if (retval != ERROR_OK) { dap_put_ap(ap); return retval; } dap_put_ap(ap); uint32_t key; retval = mem_ap_read_atomic_u32(ap, RSL10_FLASH_ADDRESS_LOCK_INFO_SETTING, &key); if (retval != ERROR_OK) return retval; LOG_INFO("mem read: 0x%08" PRIx32, key); if (key == RSL10_KEY_DEBUG_LOCK) { retval = command_run_line(CMD_CTX, "reset init"); if (retval != ERROR_OK) return retval; struct flash_bank *bank; retval = get_flash_bank_by_addr(target, RSL10_FLASH_ADDRESS_NVR3, true, &bank); if (retval != ERROR_OK) return retval; retval = rsl10_protect(bank, false, 0, 0); if (retval != ERROR_OK) return retval; uint8_t write_buffer2[4 * 2]; target_buffer_set_u32(target, write_buffer2, 0x1); /* pad the end to 64-bit word boundary */ memset(&write_buffer2[4], bank->default_padded_value, 4); /* let it fail, because sector is not erased, maybe just erase all? */ (void)rsl10_write(bank, write_buffer2, RSL10_NVR3_USER_KEY_OFFSET, sizeof(write_buffer2)); command_print(CMD, "Debug port is unlocked!"); } return ERROR_OK; } COMMAND_HANDLER(rsl10_mass_erase_command) { if (CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); int retval = rsl10_mass_erase(target); if (retval != ERROR_OK) return retval; command_print(CMD, "Mass erase was succesfull!"); return ERROR_OK; } static const struct command_registration rsl10_exec_command_handlers[] = { { .name = "lock", .handler = rsl10_lock_command, .mode = COMMAND_EXEC, .help = "Lock rsl10 debug, with passed keys", .usage = "key1 key2 key3 key4", }, { .name = "unlock", .handler = rsl10_unlock_command, .mode = COMMAND_EXEC, .help = "Unlock rsl10 debug, with passed keys", .usage = "key1 key2 key3 key4", }, { .name = "mass_erase", .handler = rsl10_mass_erase_command, .mode = COMMAND_EXEC, .help = "Mass erase all unprotected flash areas", .usage = "", }, COMMAND_REGISTRATION_DONE}; static const struct command_registration rsl10_command_handlers[] = { { .name = "rsl10", .mode = COMMAND_ANY, .help = "rsl10 flash command group", .usage = "", .chain = rsl10_exec_command_handlers, }, COMMAND_REGISTRATION_DONE}; const struct flash_driver rsl10_flash = { .name = "rsl10", .commands = rsl10_command_handlers, .flash_bank_command = rsl10_flash_bank_command, .erase = rsl10_erase, .protect = rsl10_protect, .write = rsl10_write, .read = default_flash_read, .probe = rsl10_probe, .auto_probe = rsl10_auto_probe, .erase_check = default_flash_blank_check, .protect_check = rsl10_protect_check, .free_driver_priv = rsl10_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/sfdp.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2019 by Andreas Bolsch <andreas.bolsch@mni.thm.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "spi.h" #include "sfdp.h" #define SFDP_MAGIC 0x50444653 #define SFDP_ACCESS_PROT 0xFF #define SFDP_BASIC_FLASH 0xFF00 #define SFDP_4BYTE_ADDR 0xFF84 static const char *sfdp_name = "sfdp"; struct sfdp_hdr { uint32_t signature; uint32_t revision; }; struct sfdp_phdr { uint32_t revision; uint32_t ptr; }; struct sfdp_basic_flash_param { uint32_t fast_addr; /* 01: fast read and 3/4 address bytes */ uint32_t density; /* 02: memory density */ uint32_t fast_1x4; /* 03: 1-1-4 and 1-4-4 fast read */ uint32_t fast_1x2; /* 04: 1-2-2 and 1-1-2 fast read */ uint32_t fast_444; /* 05: 4-4-4 and 2-2-2 fast read */ uint32_t read_222; /* 06: 2-2-2 fast read instr and dummy */ uint32_t read_444; /* 07: 4-4-4 fast read instr and dummy */ uint32_t erase_t12; /* 08: erase types 1, 2 */ uint32_t erase_t34; /* 09: erase types 3, 4 */ uint32_t erase_time; /* 10: erase times for types 1 - 4 */ uint32_t chip_byte; /* 11: chip erase time, byte prog time, page prog */ uint32_t susp_time; /* 12: suspend and resume times */ uint32_t susp_instr; /* 13: suspend and resume instr */ uint32_t pwrd_instr; /* 14: powerdown instr */ uint32_t quad_req; /* 15: quad enable requirements */ uint32_t addr_reset; /* 16: 3-/4-byte addressing and reset */ uint32_t read_1x8; /* 17: 1-1-8 and 1-8-8 fast read instr and dummy */ uint32_t dtr_drive; /* 18: dtr modes and drive strength */ uint32_t octal_req; /* 19: octal enable requirements */ uint32_t speed_888; /* 20: speed in 8-8-8 modes */ }; struct sfdp_4byte_addr_param { uint32_t flags; /* 01: various flags */ uint32_t erase_t1234; /* 02: erase commands */ }; /* Try to get parameters from flash via SFDP */ int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, read_sfdp_block_t read_sfdp_block) { struct sfdp_hdr header; struct sfdp_phdr *pheaders = NULL; uint32_t *ptable = NULL; unsigned int j, k, nph; int retval, erase_type = 0; memset(dev, 0, sizeof(struct flash_device)); /* retrieve SFDP header */ memset(&header, 0, sizeof(header)); retval = read_sfdp_block(bank, 0x0, sizeof(header) >> 2, (uint32_t *)&header); if (retval != ERROR_OK) return retval; LOG_DEBUG("header 0x%08" PRIx32 " 0x%08" PRIx32, header.signature, header.revision); if (header.signature != SFDP_MAGIC) { LOG_INFO("no SDFP found"); return ERROR_FLASH_BANK_NOT_PROBED; } if (((header.revision >> 24) & 0xFF) != SFDP_ACCESS_PROT) { LOG_ERROR("access protocol 0x%02x not implemented", (header.revision >> 24) & 0xFFU); return ERROR_FLASH_BANK_NOT_PROBED; } /* retrieve table of parameter headers */ nph = ((header.revision >> 16) & 0xFF) + 1; LOG_DEBUG("parameter headers: %d", nph); pheaders = malloc(sizeof(struct sfdp_phdr) * nph); if (!pheaders) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } memset(pheaders, 0, sizeof(struct sfdp_phdr) * nph); retval = read_sfdp_block(bank, sizeof(header), (sizeof(struct sfdp_phdr) >> 2) * nph, (uint32_t *)pheaders); if (retval != ERROR_OK) goto err; for (k = 0; k < nph; k++) { uint8_t words = (pheaders[k].revision >> 24) & 0xFF; uint16_t id = (((pheaders[k].ptr) >> 16) & 0xFF00) | (pheaders[k].revision & 0xFF); uint32_t ptr = pheaders[k].ptr & 0xFFFFFF; LOG_DEBUG("pheader %d len=0x%02" PRIx8 " id=0x%04" PRIx16 " ptr=0x%06" PRIx32, k, words, id, ptr); /* retrieve parameter table */ ptable = malloc(words << 2); if (!ptable) { LOG_ERROR("not enough memory"); retval = ERROR_FAIL; goto err; } retval = read_sfdp_block(bank, ptr, words, ptable); if (retval != ERROR_OK) goto err; for (j = 0; j < words; j++) LOG_DEBUG("word %02d 0x%08X", j + 1, ptable[j]); if (id == SFDP_BASIC_FLASH) { struct sfdp_basic_flash_param *table = (struct sfdp_basic_flash_param *)ptable; uint16_t erase; if (words < 9) { LOG_ERROR("id=0x%04" PRIx16 " invalid length %d", id, words); retval = ERROR_FLASH_BANK_NOT_PROBED; goto err; } LOG_DEBUG("basic flash parameter table"); /* dummy device name */ dev->name = sfdp_name; /* default instructions */ dev->read_cmd = SPIFLASH_READ; dev->pprog_cmd = SPIFLASH_PAGE_PROGRAM; dev->chip_erase_cmd = SPIFLASH_MASS_ERASE; /* get device size */ if (table->density & (1UL << 31)) dev->size_in_bytes = 1UL << ((table->density & ~(1UL << 31)) - 3); else dev->size_in_bytes = (table->density + 1) >> 3; /* 2-2-2 read instruction, not used */ if (table->fast_444 & (1UL << 0)) dev->qread_cmd = (table->read_222 >> 24) & 0xFF; /* 4-4-4 read instruction */ if (table->fast_444 & (1UL << 4)) dev->qread_cmd = (table->read_444 >> 24) & 0xFF; /* find the largest erase block size and instruction */ erase = (table->erase_t12 >> 0) & 0xFFFF; erase_type = 1; if (((table->erase_t12 >> 16) & 0xFF) > (erase & 0xFF)) { erase = (table->erase_t12 >> 16) & 0xFFFF; erase_type = 2; } if (((table->erase_t34 >> 0) & 0xFF) > (erase & 0xFF)) { erase = (table->erase_t34 >> 0) & 0xFFFF; erase_type = 3; } if (((table->erase_t34 >> 16) & 0xFF) > (erase & 0xFF)) { erase = (table->erase_t34 >> 16) & 0xFFFF; erase_type = 4; } dev->erase_cmd = (erase >> 8) & 0xFF; dev->sectorsize = 1UL << (erase & 0xFF); if ((offsetof(struct sfdp_basic_flash_param, chip_byte) >> 2) < words) { /* get Program Page Size, if chip_byte present, that's optional */ dev->pagesize = 1UL << ((table->chip_byte >> 4) & 0x0F); } else { /* no explicit page size specified ... */ if (table->fast_addr & (1UL << 2)) { /* Write Granularity = 1, use 64 bytes */ dev->pagesize = 1UL << 6; } else { /* Write Granularity = 0, use 16 bytes */ dev->pagesize = 1UL << 4; } } if (dev->size_in_bytes > (1UL << 24)) { if (((table->fast_addr >> 17) & 0x3) == 0x0) LOG_ERROR("device needs paging - not implemented"); /* 4-byte addresses needed if more than 16 MBytes */ if (((offsetof(struct sfdp_basic_flash_param, addr_reset) >> 2) < words) && (table->addr_reset & (1UL << 29))) { /* dedicated 4-byte-address instructions, hopefully these ... * this entry is unfortunately optional as well * a subsequent 4-byte address table may overwrite this */ dev->read_cmd = 0x13; dev->pprog_cmd = 0x12; dev->erase_cmd = 0xDC; if (dev->qread_cmd != 0) dev->qread_cmd = 0xEC; } else if (((table->fast_addr >> 17) & 0x3) == 0x1) LOG_INFO("device has to be switched to 4-byte addresses"); } } else if (id == SFDP_4BYTE_ADDR) { struct sfdp_4byte_addr_param *table = (struct sfdp_4byte_addr_param *)ptable; if (words >= (offsetof(struct sfdp_4byte_addr_param, erase_t1234) + sizeof(table->erase_t1234)) >> 2) { LOG_INFO("4-byte address parameter table"); /* read and page program instructions */ if (table->flags & (1UL << 0)) dev->read_cmd = 0x13; if (table->flags & (1UL << 5)) dev->qread_cmd = 0xEC; if (table->flags & (1UL << 6)) dev->pprog_cmd = 0x12; /* erase instructions */ if ((erase_type == 1) && (table->flags & (1UL << 9))) dev->erase_cmd = (table->erase_t1234 >> 0) & 0xFF; else if ((erase_type == 2) && (table->flags & (1UL << 10))) dev->erase_cmd = (table->erase_t1234 >> 8) & 0xFF; else if ((erase_type == 3) && (table->flags & (1UL << 11))) dev->erase_cmd = (table->erase_t1234 >> 16) & 0xFF; else if ((erase_type == 4) && (table->flags & (1UL << 12))) dev->erase_cmd = (table->erase_t1234 >> 24) & 0xFF; } else LOG_ERROR("parameter table id=0x%04" PRIx16 " invalid length %d", id, words); } else LOG_DEBUG("unimplemented parameter table id=0x%04" PRIx16, id); free(ptable); ptable = NULL; } if (erase_type != 0) { LOG_INFO("valid SFDP detected"); retval = ERROR_OK; } else { LOG_ERROR("incomplete/invalid SFDP"); retval = ERROR_FLASH_BANK_NOT_PROBED; } err: free(pheaders); free(ptable); return retval; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/sfdp.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2019 by Andreas Bolsch <andreas.bolsch@mni.thm.de * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_SFDP_H #define OPENOCD_FLASH_NOR_SFDP_H /* per JESD216D 'addr' is *byte* based but must be word aligned, * 'buffer' is word based, word aligned and always little-endian encoded, * in the flash, 'addr_len' is 3 or 4, 'dummy' ***usually*** 8 * * the actual number of dummy clocks should be worked out by this function * dynamically, i.e. by scanning the first few bytes for the SFDP signature * * buffer contents is supposed to be returned in ***host*** endianness */ typedef int (*read_sfdp_block_t)(struct flash_bank *bank, uint32_t addr, uint32_t words, uint32_t *buffer); extern int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, read_sfdp_block_t read_sfdp_block); #endif /* OPENOCD_FLASH_NOR_SFDP_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/sh_qspi.c ================================================ // SPDX-License-Identifier: GPL-2.0-only /* * SH QSPI (Quad SPI) driver * Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com> * * Based on U-Boot SH QSPI driver * Copyright (C) 2013 Renesas Electronics Corporation * Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "spi.h" #include <helper/binarybuffer.h> #include <helper/bits.h> #include <helper/time_support.h> #include <helper/types.h> #include <jtag/jtag.h> #include <target/algorithm.h> #include <target/arm.h> #include <target/arm_opcodes.h> #include <target/target.h> /* SH QSPI register bit masks <REG>_<BIT> */ #define SPCR_MSTR 0x08 #define SPCR_SPE 0x40 #define SPSR_SPRFF 0x80 #define SPSR_SPTEF 0x20 #define SPPCR_IO3FV 0x04 #define SPPCR_IO2FV 0x02 #define SPPCR_IO1FV 0x01 #define SPBDCR_RXBC0 BIT(0) #define SPCMD_SCKDEN BIT(15) #define SPCMD_SLNDEN BIT(14) #define SPCMD_SPNDEN BIT(13) #define SPCMD_SSLKP BIT(7) #define SPCMD_BRDV0 BIT(2) #define SPCMD_INIT1 (SPCMD_SCKDEN | SPCMD_SLNDEN | \ SPCMD_SPNDEN | SPCMD_SSLKP | \ SPCMD_BRDV0) #define SPCMD_INIT2 (SPCMD_SPNDEN | SPCMD_SSLKP | \ SPCMD_BRDV0) #define SPBFCR_TXRST BIT(7) #define SPBFCR_RXRST BIT(6) #define SPBFCR_TXTRG 0x30 #define SPBFCR_RXTRG 0x07 /* SH QSPI register set */ #define SH_QSPI_SPCR 0x00 #define SH_QSPI_SSLP 0x01 #define SH_QSPI_SPPCR 0x02 #define SH_QSPI_SPSR 0x03 #define SH_QSPI_SPDR 0x04 #define SH_QSPI_SPSCR 0x08 #define SH_QSPI_SPSSR 0x09 #define SH_QSPI_SPBR 0x0a #define SH_QSPI_SPDCR 0x0b #define SH_QSPI_SPCKD 0x0c #define SH_QSPI_SSLND 0x0d #define SH_QSPI_SPND 0x0e #define SH_QSPI_DUMMY0 0x0f #define SH_QSPI_SPCMD0 0x10 #define SH_QSPI_SPCMD1 0x12 #define SH_QSPI_SPCMD2 0x14 #define SH_QSPI_SPCMD3 0x16 #define SH_QSPI_SPBFCR 0x18 #define SH_QSPI_DUMMY1 0x19 #define SH_QSPI_SPBDCR 0x1a #define SH_QSPI_SPBMUL0 0x1c #define SH_QSPI_SPBMUL1 0x20 #define SH_QSPI_SPBMUL2 0x24 #define SH_QSPI_SPBMUL3 0x28 struct sh_qspi_flash_bank { const struct flash_device *dev; uint32_t io_base; bool probed; struct working_area *io_algorithm; struct working_area *source; unsigned int buffer_size; }; struct sh_qspi_target { char *name; uint32_t tap_idcode; uint32_t io_base; }; static const struct sh_qspi_target target_devices[] = { /* name, tap_idcode, io_base */ { "SH QSPI", 0x4ba00477, 0xe6b10000 }, { NULL, 0, 0 } }; static int sh_qspi_init(struct flash_bank *bank) { struct target *target = bank->target; struct sh_qspi_flash_bank *info = bank->driver_priv; uint8_t val; int ret; /* QSPI initialize */ /* Set master mode only */ ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR); if (ret != ERROR_OK) return ret; /* Set SSL signal level */ ret = target_write_u8(target, info->io_base + SH_QSPI_SSLP, 0x00); if (ret != ERROR_OK) return ret; /* Set MOSI signal value when transfer is in idle state */ ret = target_write_u8(target, info->io_base + SH_QSPI_SPPCR, SPPCR_IO3FV | SPPCR_IO2FV); if (ret != ERROR_OK) return ret; /* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */ ret = target_write_u8(target, info->io_base + SH_QSPI_SPBR, 0x01); if (ret != ERROR_OK) return ret; /* Disable Dummy Data Transmission */ ret = target_write_u8(target, info->io_base + SH_QSPI_SPDCR, 0x00); if (ret != ERROR_OK) return ret; /* Set clock delay value */ ret = target_write_u8(target, info->io_base + SH_QSPI_SPCKD, 0x00); if (ret != ERROR_OK) return ret; /* Set SSL negation delay value */ ret = target_write_u8(target, info->io_base + SH_QSPI_SSLND, 0x00); if (ret != ERROR_OK) return ret; /* Set next-access delay value */ ret = target_write_u8(target, info->io_base + SH_QSPI_SPND, 0x00); if (ret != ERROR_OK) return ret; /* Set equence command */ ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0, SPCMD_INIT2); if (ret != ERROR_OK) return ret; /* Reset transfer and receive Buffer */ ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val); if (ret != ERROR_OK) return ret; val |= SPBFCR_TXRST | SPBFCR_RXRST; ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val); if (ret != ERROR_OK) return ret; /* Clear transfer and receive Buffer control bit */ ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val); if (ret != ERROR_OK) return ret; val &= ~(SPBFCR_TXRST | SPBFCR_RXRST); ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val); if (ret != ERROR_OK) return ret; /* Set equence control method. Use equence0 only */ ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00); if (ret != ERROR_OK) return ret; /* Enable SPI function */ ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val); if (ret != ERROR_OK) return ret; val |= SPCR_SPE; return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val); } static int sh_qspi_cs_activate(struct flash_bank *bank) { struct target *target = bank->target; struct sh_qspi_flash_bank *info = bank->driver_priv; uint8_t val; int ret; /* Set master mode only */ ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR); if (ret != ERROR_OK) return ret; /* Set command */ ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0, SPCMD_INIT1); if (ret != ERROR_OK) return ret; /* Reset transfer and receive Buffer */ ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val); if (ret != ERROR_OK) return ret; val |= SPBFCR_TXRST | SPBFCR_RXRST; ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val); if (ret != ERROR_OK) return ret; /* Clear transfer and receive Buffer control bit */ ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val); if (ret != ERROR_OK) return ret; val &= ~(SPBFCR_TXRST | SPBFCR_RXRST); ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val); if (ret != ERROR_OK) return ret; /* Set equence control method. Use equence0 only */ ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00); if (ret != ERROR_OK) return ret; /* Enable SPI function */ ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val); if (ret != ERROR_OK) return ret; val |= SPCR_SPE; return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val); } static int sh_qspi_cs_deactivate(struct flash_bank *bank) { struct target *target = bank->target; struct sh_qspi_flash_bank *info = bank->driver_priv; uint8_t val; int ret; /* Disable SPI Function */ ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val); if (ret != ERROR_OK) return ret; val &= ~SPCR_SPE; return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val); } static int sh_qspi_wait_for_bit(struct flash_bank *bank, uint8_t reg, uint32_t mask, bool set, unsigned long timeout) { struct target *target = bank->target; struct sh_qspi_flash_bank *info = bank->driver_priv; long long endtime; uint8_t val; int ret; endtime = timeval_ms() + timeout; do { ret = target_read_u8(target, info->io_base + reg, &val); if (ret != ERROR_OK) return ret; if (!set) val = ~val; if ((val & mask) == mask) return ERROR_OK; alive_sleep(1); } while (timeval_ms() < endtime); LOG_ERROR("timeout"); return ERROR_TIMEOUT_REACHED; } static int sh_qspi_xfer_common(struct flash_bank *bank, const uint8_t *dout, unsigned int outlen, uint8_t *din, unsigned int inlen, bool xfer_start, bool xfer_end) { struct target *target = bank->target; struct sh_qspi_flash_bank *info = bank->driver_priv; uint8_t tdata, rdata; uint8_t val; unsigned int nbyte = outlen + inlen; int ret = 0; if (xfer_start) { ret = sh_qspi_cs_activate(bank); if (ret != ERROR_OK) return ret; ret = target_write_u32(target, info->io_base + SH_QSPI_SPBMUL0, nbyte); if (ret != ERROR_OK) return ret; ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val); if (ret != ERROR_OK) return ret; val &= ~(SPBFCR_TXTRG | SPBFCR_RXTRG); ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val); if (ret != ERROR_OK) return ret; } while (nbyte > 0) { ret = sh_qspi_wait_for_bit(bank, SH_QSPI_SPSR, SPSR_SPTEF, true, 1000); if (ret != ERROR_OK) return ret; tdata = outlen ? *dout++ : 0; ret = target_write_u8(target, info->io_base + SH_QSPI_SPDR, tdata); if (ret != ERROR_OK) return ret; ret = sh_qspi_wait_for_bit(bank, SH_QSPI_SPSR, SPSR_SPRFF, true, 1000); if (ret != ERROR_OK) return ret; ret = target_read_u8(target, info->io_base + SH_QSPI_SPDR, &rdata); if (ret != ERROR_OK) return ret; if (!outlen && inlen) { *din++ = rdata; inlen--; } if (outlen) outlen--; nbyte--; } if (xfer_end) return sh_qspi_cs_deactivate(bank); else return ERROR_OK; } /* Send "write enable" command to SPI flash chip. */ static int sh_qspi_write_enable(struct flash_bank *bank) { uint8_t dout = SPIFLASH_WRITE_ENABLE; return sh_qspi_xfer_common(bank, &dout, 1, NULL, 0, 1, 1); } /* Read the status register of the external SPI flash chip. */ static int read_status_reg(struct flash_bank *bank, uint32_t *status) { uint8_t dout = SPIFLASH_READ_STATUS; uint8_t din; int ret; ret = sh_qspi_xfer_common(bank, &dout, 1, &din, 1, 1, 1); if (ret != ERROR_OK) return ret; *status = din & 0xff; return ERROR_OK; } /* check for WIP (write in progress) bit in status register */ /* timeout in ms */ static int wait_till_ready(struct flash_bank *bank, int timeout) { long long endtime; uint32_t status; int ret; endtime = timeval_ms() + timeout; do { /* read flash status register */ ret = read_status_reg(bank, &status); if (ret != ERROR_OK) return ret; if ((status & SPIFLASH_BSY_BIT) == 0) return ERROR_OK; alive_sleep(1); } while (timeval_ms() < endtime); LOG_ERROR("timeout"); return ERROR_TIMEOUT_REACHED; } static int sh_qspi_erase_sector(struct flash_bank *bank, int sector) { struct sh_qspi_flash_bank *info = bank->driver_priv; bool addr4b = info->dev->size_in_bytes > (1UL << 24); uint32_t address = (sector * info->dev->sectorsize) << (addr4b ? 0 : 8); uint8_t dout[5] = { info->dev->erase_cmd, (address >> 24) & 0xff, (address >> 16) & 0xff, (address >> 8) & 0xff, (address >> 0) & 0xff }; unsigned int doutlen = addr4b ? 5 : 4; int ret; /* Write Enable */ ret = sh_qspi_write_enable(bank); if (ret != ERROR_OK) return ret; /* Erase */ ret = sh_qspi_xfer_common(bank, dout, doutlen, NULL, 0, 1, 1); if (ret != ERROR_OK) return ret; /* Poll status register */ return wait_till_ready(bank, 3000); } static int sh_qspi_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct sh_qspi_flash_bank *info = bank->driver_priv; int retval = ERROR_OK; LOG_DEBUG("%s: from sector %u to sector %u", __func__, first, last); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((last < first) || (last >= bank->num_sectors)) { LOG_ERROR("Flash sector invalid"); return ERROR_FLASH_SECTOR_INVALID; } if (!info->probed) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } if (info->dev->erase_cmd == 0x00) return ERROR_FLASH_OPER_UNSUPPORTED; for (unsigned int sector = first; sector <= last; sector++) { if (bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FAIL; } } for (unsigned int sector = first; sector <= last; sector++) { retval = sh_qspi_erase_sector(bank, sector); if (retval != ERROR_OK) break; keep_alive(); } return retval; } static int sh_qspi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct sh_qspi_flash_bank *info = bank->driver_priv; struct reg_param reg_params[4]; struct arm_algorithm arm_algo; uint32_t io_base = (uint32_t)(info->io_base); uint32_t src_base = (uint32_t)(info->source->address); uint32_t chunk; bool addr4b = !!(info->dev->size_in_bytes > (1UL << 24)); int ret = ERROR_OK; LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, __func__, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) { LOG_WARNING("Write pasts end of flash. Extra data discarded."); count = bank->size - offset; } if (offset & 0xff) { LOG_ERROR("sh_qspi_write_page: unaligned write address: %08" PRIx32, offset); return ERROR_FAIL; } /* Check sector protection */ for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { /* Start offset in or before this sector? */ /* End offset in or behind this sector? */ struct flash_sector *bs = &bank->sectors[sector]; if ((offset < (bs->offset + bs->size)) && ((offset + count - 1) >= bs->offset) && bs->is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FAIL; } } LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, __func__, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) { LOG_WARNING("Reads past end of flash. Extra data discarded."); count = bank->size - offset; } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); while (count > 0) { chunk = (count > info->buffer_size) ? info->buffer_size : count; target_write_buffer(target, info->source->address, chunk, buffer); buf_set_u32(reg_params[0].value, 0, 32, io_base); buf_set_u32(reg_params[1].value, 0, 32, src_base); buf_set_u32(reg_params[2].value, 0, 32, (1 << 31) | (addr4b << 30) | (info->dev->pprog_cmd << 20) | chunk); buf_set_u32(reg_params[3].value, 0, 32, offset); ret = target_run_algorithm(target, 0, NULL, 4, reg_params, info->io_algorithm->address, 0, 10000, &arm_algo); if (ret != ERROR_OK) { LOG_ERROR("error executing SH QSPI flash IO algorithm"); ret = ERROR_FLASH_OPERATION_FAILED; break; } buffer += chunk; offset += chunk; count -= chunk; } destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return ret; } static int sh_qspi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct sh_qspi_flash_bank *info = bank->driver_priv; struct reg_param reg_params[4]; struct arm_algorithm arm_algo; uint32_t io_base = (uint32_t)(info->io_base); uint32_t src_base = (uint32_t)(info->source->address); uint32_t chunk; bool addr4b = !!(info->dev->size_in_bytes > (1UL << 24)); int ret = ERROR_OK; LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, __func__, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) { LOG_WARNING("Reads past end of flash. Extra data discarded."); count = bank->size - offset; } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); while (count > 0) { chunk = (count > info->buffer_size) ? info->buffer_size : count; buf_set_u32(reg_params[0].value, 0, 32, io_base); buf_set_u32(reg_params[1].value, 0, 32, src_base); buf_set_u32(reg_params[2].value, 0, 32, (addr4b << 30) | (info->dev->read_cmd << 20) | chunk); buf_set_u32(reg_params[3].value, 0, 32, offset); ret = target_run_algorithm(target, 0, NULL, 4, reg_params, info->io_algorithm->address, 0, 10000, &arm_algo); if (ret != ERROR_OK) { LOG_ERROR("error executing SH QSPI flash IO algorithm"); ret = ERROR_FLASH_OPERATION_FAILED; break; } target_read_buffer(target, info->source->address, chunk, buffer); buffer += chunk; offset += chunk; count -= chunk; } destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return ret; } /* Return ID of flash device */ static int read_flash_id(struct flash_bank *bank, uint32_t *id) { struct target *target = bank->target; uint8_t dout = SPIFLASH_READ_ID; uint8_t din[3] = { 0, 0, 0 }; int ret; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } ret = sh_qspi_xfer_common(bank, &dout, 1, din, 3, 1, 1); if (ret != ERROR_OK) return ret; *id = (din[0] << 0) | (din[1] << 8) | (din[2] << 16); if (*id == 0xffffff) { LOG_ERROR("No SPI flash found"); return ERROR_FAIL; } return ERROR_OK; } static int sh_qspi_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { for (unsigned int sector = first; sector <= last; sector++) bank->sectors[sector].is_protected = set; return ERROR_OK; } static int sh_qspi_upload_helper(struct flash_bank *bank) { struct target *target = bank->target; struct sh_qspi_flash_bank *info = bank->driver_priv; /* see contrib/loaders/flash/sh_qspi.s for src */ static const uint8_t sh_qspi_io_code[] = { #include "../../../contrib/loaders/flash/sh_qspi/sh_qspi.inc" }; int ret; target_free_working_area(target, info->source); target_free_working_area(target, info->io_algorithm); /* FIXME: Working areas are allocated during flash probe * and eventual target_free_all_working_areas() called in case * of target reset or run is not handled at all. * Not a big problem if area backp is off. */ /* flash write code */ if (target_alloc_working_area(target, sizeof(sh_qspi_io_code), &info->io_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } target_write_buffer(target, info->io_algorithm->address, sizeof(sh_qspi_io_code), sh_qspi_io_code); /* * Try to allocate as big work area buffer as possible, start * with 32 kiB and count down. If there is less than 256 Bytes * of work area available, abort. */ info->buffer_size = 32768; while (true) { ret = target_alloc_working_area_try(target, info->buffer_size, &info->source); if (ret == ERROR_OK) return ret; info->buffer_size /= 2; if (info->buffer_size <= 256) { target_free_working_area(target, info->io_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } return ERROR_OK; } static int sh_qspi_probe(struct flash_bank *bank) { struct target *target = bank->target; struct sh_qspi_flash_bank *info = bank->driver_priv; struct flash_sector *sectors; uint32_t id = 0; /* silence uninitialized warning */ uint32_t sectorsize; const struct sh_qspi_target *target_device; int ret; if (info->probed) free(bank->sectors); info->probed = false; for (target_device = target_devices; target_device->name; ++target_device) if (target_device->tap_idcode == target->tap->idcode) break; if (!target_device->name) { LOG_ERROR("Device ID 0x%" PRIx32 " is not known", target->tap->idcode); return ERROR_FAIL; } info->io_base = target_device->io_base; LOG_DEBUG("Found device %s at address " TARGET_ADDR_FMT, target_device->name, bank->base); ret = sh_qspi_upload_helper(bank); if (ret != ERROR_OK) return ret; ret = sh_qspi_init(bank); if (ret != ERROR_OK) return ret; ret = read_flash_id(bank, &id); if (ret != ERROR_OK) return ret; info->dev = NULL; for (const struct flash_device *p = flash_devices; p->name; p++) if (p->device_id == id) { info->dev = p; break; } if (!info->dev) { LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id); return ERROR_FAIL; } LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", info->dev->name, info->dev->device_id); /* Set correct size value */ bank->size = info->dev->size_in_bytes; if (bank->size <= (1UL << 16)) LOG_WARNING("device needs 2-byte addresses - not implemented"); /* if no sectors, treat whole bank as single sector */ sectorsize = info->dev->sectorsize ? info->dev->sectorsize : info->dev->size_in_bytes; /* create and fill sectors array */ bank->num_sectors = info->dev->size_in_bytes / sectorsize; sectors = calloc(1, sizeof(*sectors) * bank->num_sectors); if (!sectors) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { sectors[sector].offset = sector * sectorsize; sectors[sector].size = sectorsize; sectors[sector].is_erased = 0; sectors[sector].is_protected = 0; } bank->sectors = sectors; info->probed = true; return ERROR_OK; } static int sh_qspi_auto_probe(struct flash_bank *bank) { struct sh_qspi_flash_bank *info = bank->driver_priv; if (info->probed) return ERROR_OK; return sh_qspi_probe(bank); } static int sh_qspi_flash_blank_check(struct flash_bank *bank) { /* Not implemented */ return ERROR_OK; } static int sh_qspi_protect_check(struct flash_bank *bank) { /* Not implemented */ return ERROR_OK; } static int sh_qspi_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct sh_qspi_flash_bank *info = bank->driver_priv; if (!info->probed) { command_print_sameline(cmd, "\nSH QSPI flash bank not probed yet\n"); return ERROR_OK; } command_print_sameline(cmd, "\nSH QSPI flash information:\n" " Device \'%s\' (ID 0x%08" PRIx32 ")\n", info->dev->name, info->dev->device_id); return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(sh_qspi_flash_bank_command) { struct sh_qspi_flash_bank *info; LOG_DEBUG("%s", __func__); if (CMD_ARGC < 6 || CMD_ARGC > 7) return ERROR_COMMAND_SYNTAX_ERROR; if ((CMD_ARGC == 7) && strcmp(CMD_ARGV[6], "cs0")) { LOG_ERROR("Unknown arg: %s", CMD_ARGV[6]); return ERROR_COMMAND_SYNTAX_ERROR; } info = calloc(1, sizeof(struct sh_qspi_flash_bank)); if (!info) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } bank->driver_priv = info; return ERROR_OK; } const struct flash_driver sh_qspi_flash = { .name = "sh_qspi", .flash_bank_command = sh_qspi_flash_bank_command, .erase = sh_qspi_erase, .protect = sh_qspi_protect, .write = sh_qspi_write, .read = sh_qspi_read, .probe = sh_qspi_probe, .auto_probe = sh_qspi_auto_probe, .erase_check = sh_qspi_flash_blank_check, .protect_check = sh_qspi_protect_check, .info = sh_qspi_get_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/sim3x.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2014 by Ladislav Bábel * * ladababel@seznam.cz * * * * Copyright (C) 2015 by Andreas Bomholtz * * andreas@seluxit.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <helper/time_support.h> #include <target/algorithm.h> #include <target/arm_adi_v5.h> #include <target/cortex_m.h> /* SI32_DEVICEID0 */ #define DEVICEID0_DEVICEID0 (0x400490C0) #define DEVICEID0_DEVICEID1 (0x400490D0) #define DEVICEID0_DEVICEID2 (0x400490E0) #define DEVICEID0_DEVICEID3 (0x400490F0) /* cortex_m CPUID */ #define CPUID_CHECK_VALUE (0x410FC230) #define CPUID_CHECK_VALUE_MASK (0xFF0FFFF0) /* Flash */ #define FLASH_BASE_ADDRESS (0x00000000) #define LOCK_WORD_ADDRESS (0x0003FFFC) #define LOCK_WORD_MCU_UNLOCKED (0xFFFFFFFF) /* Can't by locked again without erase, because LOCK_WORD is in FLASH */ #define LOCK_WORD_MCU_UNLOCKED_BY_FIRMWARE (0x00000000) /* SI32_FLASHCTRL_0 */ #define FLASHCTRL0_CONFIG_ALL (0x4002E000) #define FLASHCTRL0_CONFIG_SET (0x4002E004) #define FLASHCTRL0_CONFIG_CLR (0x4002E008) #define FLASHCTRL0_CONFIG_ERASEEN_MASK (0x00040000) #define FLASHCTRL0_CONFIG_BUSYF_MASK (0x00100000) #define FLASHCTRL0_WRADDR (0x4002E0A0) #define FLASHCTRL0_WRDATA (0x4002E0B0) #define FLASHCTRL0_KEY (0x4002E0C0) #define FLASHCTRL0_KEY_INITIAL_UNLOCK (0x000000A5) #define FLASHCTRL0_KEY_SINGLE_UNLOCK (0x000000F1) #define FLASHCTRL0_KEY_MULTIPLE_UNLOCK (0x000000F2) #define FLASHCTRL0_KEY_MULTIPLE_LOCK (0x0000005A) #define FLASH_BUSY_TIMEOUT (100) /* SI32_RSTSRC_0 */ #define RSTSRC0_RESETEN_ALL (0x4002D060) #define RSTSRC0_RESETEN_SET (0x4002D064) #define RSTSRC0_RESETEN_CLR (0x4002D068) #define RSTSRC0_RESETEN_VMONREN_MASK (0x00000004) #define RSTSRC0_RESETEN_SWREN_MASK (0x00000040) /* SI32_VMON_0 */ #define VMON0_CONTROL_ALL (0x4002F000) #define VMON0_CONTROL_SET (0x4002F004) #define VMON0_CONTROL_CLR (0x4002F008) #define VMON0_CONTROL_VMONEN_MASK (0x80000000) /* SI32_CLKCTRL_0 */ #define CLKCTRL0_APBCLKG0_ALL (0x4002D020) #define CLKCTRL0_APBCLKG0_SET (0x4002D024) #define CLKCTRL0_APBCLKG0_CLR (0x4002D028) #define CLKCTRL0_APBCLKG0_FLCTRLCEN_MASK (0x40000000) /* SI32_WDTIMER_0 */ #define WDTIMER0_CONTROL_ALL (0x40030000) #define WDTIMER0_CONTROL_SET (0x40030004) #define WDTIMER0_CONTROL_CLR (0x40030008) #define WDTIMER0_CONTROL_DBGMD_MASK (0x00000002) #define WDTIMER0_STATUS_ALL (0x40030010) #define WDTIMER0_STATUS_SET (0x40030014) #define WDTIMER0_STATUS_CLR (0x40030018) #define WDTIMER0_STATUS_KEYSTS_MASK (0x00000001) #define WDTIMER0_STATUS_PRIVSTS_MASK (0x00000002) #define WDTIMER0_THRESHOLD (0x40030020) #define WDTIMER0_WDTKEY (0x40030030) #define WDTIMER0_KEY_ATTN (0x000000A5) #define WDTIMER0_KEY_WRITE (0x000000F1) #define WDTIMER0_KEY_RESET (0x000000CC) #define WDTIMER0_KEY_DISABLE (0x000000DD) #define WDTIMER0_KEY_START (0x000000EE) #define WDTIMER0_KEY_LOCK (0x000000FF) /* DAP */ #define SIM3X_AP (0x0A) #define SIM3X_AP_CTRL1 (0x00) #define SIM3X_AP_CTRL2 (0x04) #define SIM3X_AP_LOCK (0x08) #define SIM3X_AP_CRC (0x0C) #define SIM3X_AP_INIT_STAT (0x10) #define SIM3X_AP_DAP_IN (0x14) #define SIM3X_AP_DAP_OUT (0x18) #define SIM3X_AP_ID (0xFC) /* DAP register values */ #define SIM3X_AP_CTRL1_MASS_ERASE_REQ (0x00000001) #define SIM3X_AP_CTRL1_RESET_REQ (0x00000008) /* this bit is set if MCU is locked */ #define SIM3X_AP_INIT_STAT_LOCK (0x00000004) /* expected value inside SIM3X_AP_ID */ #define SIM3X_AP_ID_VALUE (0x2430002) #define SIM3X_FLASH_PAGE_SIZE 1024 struct sim3x_info { uint16_t flash_size_kb; uint16_t part_number; char part_family; uint8_t device_revision; char device_package[4]; bool probed; bool need_init; bool flash_locked; }; /* flash bank sim3x 0 0 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(sim3x_flash_bank_command) { struct sim3x_info *sim3x_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; /* Init sim3x_info struct */ sim3x_info = malloc(sizeof(struct sim3x_info)); sim3x_info->probed = false; sim3x_info->need_init = true; sim3x_info->device_revision = 0; memset(sim3x_info->device_package, 0, 4); bank->driver_priv = sim3x_info; return ERROR_OK; } static int sim3x_init(struct flash_bank *bank) { int ret; struct target *target; struct sim3x_info *sim3x_info; target = bank->target; /* Disable watchdog timer */ ret = target_write_u32(target, WDTIMER0_WDTKEY, WDTIMER0_KEY_ATTN); if (ret != ERROR_OK) return ret; ret = target_write_u32(target, WDTIMER0_WDTKEY, WDTIMER0_KEY_DISABLE); if (ret != ERROR_OK) return ret; /* Enable one write command */ ret = target_write_u32(target, WDTIMER0_WDTKEY, WDTIMER0_KEY_ATTN); if (ret != ERROR_OK) return ret; ret = target_write_u32(target, WDTIMER0_WDTKEY, WDTIMER0_KEY_WRITE); if (ret != ERROR_OK) return ret; /* Watchdog Timer Debug Mode */ ret = target_write_u32(target, WDTIMER0_CONTROL_SET, WDTIMER0_CONTROL_DBGMD_MASK); if (ret != ERROR_OK) return ret; /* Enable VDD Supply Monitor */ ret = target_write_u32(target, VMON0_CONTROL_SET, VMON0_CONTROL_VMONEN_MASK); if (ret != ERROR_OK) return ret; /* Set VDD Supply Monitor as a reset source */ ret = target_write_u32(target, RSTSRC0_RESETEN_SET, RSTSRC0_RESETEN_VMONREN_MASK); if (ret != ERROR_OK) return ret; /* Flash Controller Clock Enable */ ret = target_write_u32(target, CLKCTRL0_APBCLKG0_SET, CLKCTRL0_APBCLKG0_FLCTRLCEN_MASK); if (ret != ERROR_OK) return ret; /* Disable Flash Erase Mode */ ret = target_write_u32(target, FLASHCTRL0_CONFIG_CLR, FLASHCTRL0_CONFIG_ERASEEN_MASK); if (ret != ERROR_OK) return ret; sim3x_info = bank->driver_priv; sim3x_info->need_init = 0; return ERROR_OK; } static int sim3x_erase_page(struct flash_bank *bank, uint32_t addr) { int ret, i; uint32_t temp; struct target *target; target = bank->target; for (i = 0; i < FLASH_BUSY_TIMEOUT; i++) { ret = target_read_u32(target, FLASHCTRL0_CONFIG_ALL, &temp); if (ret != ERROR_OK) return ret; /* If is not busy */ if ((temp & FLASHCTRL0_CONFIG_BUSYF_MASK) == 0) { /* If erase is not enabled */ if ((temp & FLASHCTRL0_CONFIG_ERASEEN_MASK) == 0) { /* Enter Flash Erase Mode */ ret = target_write_u32(target, FLASHCTRL0_CONFIG_SET, FLASHCTRL0_CONFIG_ERASEEN_MASK); if (ret != ERROR_OK) return ret; } /* Write the address of the Flash page to WRADDR */ ret = target_write_u32(target, FLASHCTRL0_WRADDR, addr); if (ret != ERROR_OK) return ret; /* Write the initial unlock value to KEY */ ret = target_write_u32(target, FLASHCTRL0_KEY, FLASHCTRL0_KEY_INITIAL_UNLOCK); if (ret != ERROR_OK) return ret; /* Write the single unlock value to KEY */ ret = target_write_u32(target, FLASHCTRL0_KEY, FLASHCTRL0_KEY_SINGLE_UNLOCK); if (ret != ERROR_OK) return ret; /* Write any value to WRDATA to initiate the page erase */ ret = target_write_u32(target, FLASHCTRL0_WRDATA, 0); if (ret != ERROR_OK) return ret; return ERROR_OK; } alive_sleep(1); } LOG_ERROR("timed out waiting for FLASHCTRL0_CONFIG_BUSYF"); return ERROR_FAIL; } static int sim3x_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int ret; uint32_t temp; struct sim3x_info *sim3x_info; struct target *target; /* Check if target is halted */ if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } sim3x_info = bank->driver_priv; /* Init MCU after reset */ if (sim3x_info->need_init) { ret = sim3x_init(bank); if (ret != ERROR_OK) { LOG_ERROR("Failed to init MCU"); return ret; } } /* erase pages */ for (unsigned int i = first; i <= last; i++) { ret = sim3x_erase_page(bank, bank->sectors[i].offset); if (ret != ERROR_OK) return ret; } target = bank->target; /* Wait until busy */ for (unsigned int i = 0; i < FLASH_BUSY_TIMEOUT; i++) { ret = target_read_u32(target, FLASHCTRL0_CONFIG_ALL, &temp); if (ret != ERROR_OK) return ret; if ((temp & FLASHCTRL0_CONFIG_BUSYF_MASK) == 0) { /* If is not busy */ if ((temp & FLASHCTRL0_CONFIG_ERASEEN_MASK) != 0) { /* If erase is enabled */ /* Disable Flash Erase Mode */ ret = target_write_u32(target, FLASHCTRL0_CONFIG_CLR, FLASHCTRL0_CONFIG_ERASEEN_MASK); if (ret != ERROR_OK) return ret; } return ERROR_OK; } alive_sleep(1); } LOG_ERROR("timed out waiting for FLASHCTRL0_CONFIG_BUSYF"); return ERROR_FAIL; } static int sim3x_write_block(struct flash_bank *bank, const uint8_t *buf, uint32_t offset, uint32_t count) /* count is count of half words (2 bytes)! */ { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int ret = ERROR_OK; /* see contrib/loaders/flash/sim3x.s for src */ static const uint8_t sim3x_flash_write_code[] = { /* Write the initial unlock value to KEY (0xA5) */ 0xA5, 0x26, /* movs r6, #INITIAL_UNLOCK */ 0xC0, 0xF8, 0xC0, 0x60, /* str r6, [r0, #FLASHCTRL_KEY] */ /* Write the multiple unlock value to KEY (0xF2) */ 0xF2, 0x26, /* movs r6, #MULTIPLE_UNLOCK */ 0xC0, 0xF8, 0xC0, 0x60, /* str r6, [r0, #FLASHCTRL_KEY] */ /* wait_fifo: */ 0x16, 0x68, /* ldr r6, [r2, #0] */ 0x00, 0x2E, /* cmp r6, #0 */ 0x16, 0xD0, /* beq exit */ 0x55, 0x68, /* ldr r5, [r2, #4] */ 0xB5, 0x42, /* cmp r5, r6 */ 0xF9, 0xD0, /* beq wait_fifo */ /* wait for BUSYF flag */ /* wait_busy1: */ 0x06, 0x68, /* ldr r6, [r0, #FLASHCTRL_CONFIG] */ 0x16, 0xF4, 0x80, 0x1F, /* tst r6, #BUSYF */ 0xFB, 0xD1, /* bne wait_busy1 */ /* Write the destination address to WRADDR */ 0xC0, 0xF8, 0xA0, 0x40, /* str r4, [r0, #FLASHCTRL_WRADDR] */ /* Write the data half-word to WRDATA in right-justified format */ 0x2E, 0x88, /* ldrh r6, [r5] */ 0xC0, 0xF8, 0xB0, 0x60, /* str r6, [r0, #FLASHCTRL_WRDATA] */ 0x02, 0x35, /* adds r5, #2 */ 0x02, 0x34, /* adds r4, #2 */ /* wrap rp at end of buffer */ 0x9D, 0x42, /* cmp r5, r3 */ 0x01, 0xD3, /* bcc no_wrap */ 0x15, 0x46, /* mov r5, r2 */ 0x08, 0x35, /* adds r5, #8 */ /* no_wrap: */ 0x55, 0x60, /* str r5, [r2, #4] */ 0x49, 0x1E, /* subs r1, r1, #1 */ 0x00, 0x29, /* cmp r1, #0 */ 0x00, 0xD0, /* beq exit */ 0xE5, 0xE7, /* b wait_fifo */ /* exit: */ 0x5A, 0x26, /* movs r6, #MULTIPLE_LOCK */ 0xC0, 0xF8, 0xC0, 0x60, /* str r6, [r0, #FLASHCTRL_KEY] */ /* wait for BUSYF flag */ /* wait_busy2: */ 0x06, 0x68, /* ldr r6, [r0, #FLASHCTRL_CONFIG] */ 0x16, 0xF4, 0x80, 0x1F, /* tst r6, #BUSYF */ 0xFB, 0xD1, /* bne wait_busy2 */ 0x00, 0xBE /* bkpt #0 */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(sim3x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } ret = target_write_buffer(target, write_algorithm->address, sizeof(sim3x_flash_write_code), sim3x_flash_write_code); if (ret != ERROR_OK) return ret; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; buffer_size &= ~1UL; /* Make sure it's 2 byte aligned */ if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* flash base */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ buf_set_u32(reg_params[0].value, 0, 32, FLASHCTRL0_CONFIG_ALL); buf_set_u32(reg_params[1].value, 0, 32, count); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[4].value, 0, 32, address); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; ret = target_run_flash_async_algorithm(target, buf, count, 2, 0, NULL, 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (ret == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("flash write failed at address 0x%"PRIx32, buf_get_u32(reg_params[4].value, 0, 32)); } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return ret; } static int sim3x_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int ret; struct target *target; struct sim3x_info *sim3x_info; uint8_t *new_buffer = NULL; target = bank->target; /* Check if target is halted */ if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } sim3x_info = bank->driver_priv; if (sim3x_info->flash_locked) { LOG_ERROR("Flash is locked"); return ERROR_FAIL; } /* Init MCU after reset */ if (sim3x_info->need_init) { ret = sim3x_init(bank); if (ret != ERROR_OK) return ret; } if (offset & 0x1) { LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } if (count & 0x1) { uint32_t old_count = count; count++; new_buffer = malloc(count); if (!new_buffer) { LOG_ERROR("odd number of bytes to write and no memory " "for padding buffer"); return ERROR_FAIL; } LOG_INFO("odd number of bytes to write (%" PRIu32 "), extending to %" PRIu32 " and padding with 0xff", old_count, count); new_buffer[count - 1] = 0xff; buffer = memcpy(new_buffer, buffer, old_count); } ret = sim3x_write_block(bank, buffer, offset, count / 2); free(new_buffer); return ret; } static int sim3x_flash_lock_check(struct flash_bank *bank) { int ret; uint32_t lock_word; struct sim3x_info *sim3x_info; ret = target_read_u32(bank->target, LOCK_WORD_ADDRESS, &lock_word); if (ret != ERROR_OK) { LOG_ERROR("Can not read Lock Word"); return ret; } sim3x_info = bank->driver_priv; sim3x_info->flash_locked = (lock_word != 0xFFFFFFFF); return ERROR_OK; } static int sim3x_flash_protect_check(struct flash_bank *bank) { int ret; struct sim3x_info *sim3x_info; /* Check if target is halted */ if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } ret = sim3x_flash_lock_check(bank); if (ret != ERROR_OK) return ret; sim3x_info = bank->driver_priv; for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = sim3x_info->flash_locked; return ERROR_OK; } static int sim3x_flash_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int ret; uint8_t lock_word[4]; struct sim3x_info *sim3x_info; struct target *target; target = bank->target; /* Check if target is halted */ if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (first != 0 || last != bank->num_sectors - 1) { LOG_ERROR("Flash does not support finer granularity"); return ERROR_FAIL; } sim3x_info = bank->driver_priv; if (set) { if (sim3x_info->flash_locked) { LOG_INFO("Flash is already locked"); return ERROR_OK; } /* Lock Flash */ target_buffer_set_u32(target, lock_word, 0xFFFFFFFE); ret = sim3x_flash_write(bank, lock_word, LOCK_WORD_ADDRESS, 4); if (ret != ERROR_OK) return ret; } else { /* Flash is unlocked by an erase operation */ ret = sim3x_flash_erase(bank, 0, 0); if (ret != ERROR_OK) return ret; } ret = sim3x_flash_protect_check(bank); if (ret != ERROR_OK) return ret; if (set) { if (sim3x_info->flash_locked) { LOG_INFO("Flash locked"); return ERROR_OK; } else { LOG_ERROR("Flash lock error"); return ERROR_FAIL; } } else { if (sim3x_info->flash_locked) { LOG_ERROR("Flash unlock error"); return ERROR_FAIL; } else { LOG_INFO("Flash unlocked"); return ERROR_OK; } } } static int sim3x_read_deviceid(struct flash_bank *bank) { int ret; struct sim3x_info *sim3x_info; uint32_t device_id; int part_number; char part_num_string[4]; sim3x_info = bank->driver_priv; /* MCU check */ ret = target_read_u32(bank->target, DEVICEID0_DEVICEID2, &device_id); if (ret != ERROR_OK) return ret; /* Device ID should be 'M3' */ if (device_id != 0x00004D33) return ERROR_FAIL; /* Family and Part number */ ret = target_read_u32(bank->target, DEVICEID0_DEVICEID1, &device_id); if (ret != ERROR_OK) return ret; part_num_string[0] = device_id >> 16; part_num_string[1] = device_id >> 8; part_num_string[2] = device_id; part_num_string[3] = 0; part_number = atoi(part_num_string); /* Part Number should be between 100 and 999 */ if (!isalpha(device_id >> 24) || part_number < 100 || part_number > 999) return ERROR_FAIL; sim3x_info->part_family = device_id >> 24; sim3x_info->part_number = part_number; /* Package and Revision */ ret = target_read_u32(bank->target, DEVICEID0_DEVICEID0, &device_id); if (ret != ERROR_OK) return ret; sim3x_info->device_package[0] = device_id >> 24; sim3x_info->device_package[1] = device_id >> 16; sim3x_info->device_package[2] = device_id >> 8; sim3x_info->device_package[3] = 0; sim3x_info->device_revision = device_id; return ERROR_OK; } static int sim3x_parse_part_info(struct sim3x_info *sim3x_info) { switch (sim3x_info->part_number) { case 134: case 136: sim3x_info->flash_size_kb = 32; break; case 144: case 146: sim3x_info->flash_size_kb = 64; break; case 154: case 156: case 157: sim3x_info->flash_size_kb = 128; break; case 164: case 166: case 167: sim3x_info->flash_size_kb = 256; break; default: LOG_ERROR("Unknown Part number %d", sim3x_info->part_number); sim3x_info->part_number = 0; return ERROR_FAIL; } switch (sim3x_info->part_family) { case 'c': case 'C': LOG_INFO("SiM3C%d detected", sim3x_info->part_number); break; case 'u': case 'U': LOG_INFO("SiM3U%d detected", sim3x_info->part_number); break; case 'l': case 'L': LOG_INFO("SiM3L%d detected", sim3x_info->part_number); break; default: LOG_ERROR("Unsupported MCU family %c", sim3x_info->part_family); sim3x_info->part_family = 0; return ERROR_FAIL; } return ERROR_OK; } static int sim3x_read_info(struct flash_bank *bank) { int ret; struct sim3x_info *sim3x_info; uint32_t cpuid; sim3x_info = bank->driver_priv; /* Core check */ ret = target_read_u32(bank->target, CPUID, &cpuid); if (ret != ERROR_OK) { LOG_ERROR("Failed to read CPU ID"); return ret; } if (((cpuid >> 4) & 0xfff) != 0xc23) { LOG_ERROR("Target is not Cortex-M3"); return ERROR_FAIL; } /* Read info from chip */ ret = sim3x_read_deviceid(bank); if (ret == ERROR_OK) { ret = sim3x_parse_part_info(sim3x_info); if (ret != ERROR_OK) { LOG_ERROR("Failed to parse info from MCU"); return ERROR_FAIL; } } else { LOG_WARNING("Failed to read info from MCU, using info from flash bank parameters"); /* Check if flash size is given in flash bank command */ if (!bank->size) { LOG_ERROR("Flash size not set in the flash bank command"); return ERROR_FAIL; } /* Convert bank size to kb */ sim3x_info->flash_size_kb = bank->size / 1024; } LOG_INFO("Flash size = %dKB", sim3x_info->flash_size_kb); return ERROR_OK; } static int sim3x_probe(struct flash_bank *bank) { int ret, i; struct sim3x_info *sim3x_info; sim3x_info = bank->driver_priv; sim3x_info->probed = false; sim3x_info->need_init = true; /* Read info from chip */ ret = sim3x_read_info(bank); if (ret != ERROR_OK) return ret; ret = sim3x_flash_lock_check(bank); if (ret != ERROR_OK) return ret; free(bank->sectors); bank->base = FLASH_BASE_ADDRESS; bank->size = sim3x_info->flash_size_kb * SIM3X_FLASH_PAGE_SIZE; bank->num_sectors = SIM3X_FLASH_PAGE_SIZE; bank->sectors = malloc(sizeof(struct flash_sector) * sim3x_info->flash_size_kb); for (i = 0; i < sim3x_info->flash_size_kb; i++) { bank->sectors[i].offset = i * SIM3X_FLASH_PAGE_SIZE; bank->sectors[i].size = SIM3X_FLASH_PAGE_SIZE; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = sim3x_info->flash_locked; } sim3x_info->probed = true; return ERROR_OK; } static int sim3x_auto_probe(struct flash_bank *bank) { struct sim3x_info *sim3x_info; sim3x_info = bank->driver_priv; if (sim3x_info->probed) { sim3x_info->need_init = true; return ERROR_OK; } else { return sim3x_probe(bank); } } static int sim3x_flash_info(struct flash_bank *bank, struct command_invocation *cmd) { struct sim3x_info *sim3x_info; sim3x_info = bank->driver_priv; /* Read info about chip */ int ret = sim3x_read_info(bank); if (ret != ERROR_OK) return ret; /* Part */ if (sim3x_info->part_family && sim3x_info->part_number) { command_print_sameline(cmd, "SiM3%c%d", sim3x_info->part_family, sim3x_info->part_number); /* Revision */ if (sim3x_info->device_revision && sim3x_info->device_revision <= 'Z' - 'A') { command_print_sameline(cmd, "-%c", sim3x_info->device_revision + 'A'); /* Package */ command_print_sameline(cmd, "-G%s", sim3x_info->device_package); } } /* Print flash size */ command_print_sameline(cmd, " flash_size = %dKB", sim3x_info->flash_size_kb); return ERROR_OK; } /** * reg 31:8 - no effect * reg 7:4 - bank * reg 3:2 - register * reg 1:0 - no effect */ static int ap_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value) { LOG_DEBUG("DAP_REG[0x%02x] <- %08" PRIX32, reg, value); struct adiv5_ap *ap = dap_get_ap(dap, SIM3X_AP); if (!ap) { LOG_DEBUG("DAP: failed to get AP"); return ERROR_FAIL; } int retval = dap_queue_ap_write(ap, reg, value); if (retval != ERROR_OK) { LOG_DEBUG("DAP: failed to queue a write request"); dap_put_ap(ap); return retval; } retval = dap_run(dap); dap_put_ap(ap); if (retval != ERROR_OK) { LOG_DEBUG("DAP: dap_run failed"); return retval; } return ERROR_OK; } static int ap_read_register(struct adiv5_dap *dap, unsigned reg, uint32_t *result) { struct adiv5_ap *ap = dap_get_ap(dap, SIM3X_AP); if (!ap) { LOG_DEBUG("DAP: failed to get AP"); return ERROR_FAIL; } int retval = dap_queue_ap_read(ap, reg, result); if (retval != ERROR_OK) { LOG_DEBUG("DAP: failed to queue a read request"); dap_put_ap(ap); return retval; } retval = dap_run(dap); dap_put_ap(ap); if (retval != ERROR_OK) { LOG_DEBUG("DAP: dap_run failed"); return retval; } LOG_DEBUG("DAP_REG[0x%02x]: %08" PRIX32, reg, *result); return ERROR_OK; } static int ap_poll_register(struct adiv5_dap *dap, unsigned reg, uint32_t mask, uint32_t value, int timeout) { uint32_t val; int retval; do { retval = ap_read_register(dap, reg, &val); if (retval != ERROR_OK || (val & mask) == value) return retval; alive_sleep(1); } while (timeout--); LOG_DEBUG("DAP: polling timed out"); return ERROR_FAIL; } COMMAND_HANDLER(sim3x_mass_erase) { uint32_t val; int ret; struct target *target = get_current_target(CMD_CTX); struct cortex_m_common *cortex_m = target_to_cm(target); struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; if (!dap) { /* Used debug interface doesn't support direct DAP access */ LOG_ERROR("mass_erase can't be used by this debug interface"); return ERROR_FAIL; } ret = ap_read_register(dap, SIM3X_AP_ID, &val); if (ret != ERROR_OK) return ret; if (val != SIM3X_AP_ID_VALUE) { LOG_ERROR("Wrong SIM3X_AP_ID"); return ERROR_FAIL; } /* Mass erase sequence */ ret = ap_write_register(dap, SIM3X_AP_CTRL1, SIM3X_AP_CTRL1_RESET_REQ); if (ret != ERROR_OK) return ret; ret = ap_write_register(dap, SIM3X_AP_CTRL1, SIM3X_AP_CTRL1_RESET_REQ | SIM3X_AP_CTRL1_MASS_ERASE_REQ); if (ret != ERROR_OK) return ret; ret = ap_poll_register(dap, SIM3X_AP_CTRL1, SIM3X_AP_CTRL1_MASS_ERASE_REQ, 0x00000000, FLASH_BUSY_TIMEOUT); if (ret != ERROR_OK) return ret; ret = ap_write_register(dap, SIM3X_AP_CTRL1, 0x00000000); /* clear SIM3X_AP_CTRL1_RESET_REQ */ if (ret != ERROR_OK) return ret; LOG_INFO("Mass erase success"); return ERROR_OK; } COMMAND_HANDLER(sim3x_lock) { uint32_t val; int ret; struct target *target = get_current_target(CMD_CTX); struct cortex_m_common *cortex_m = target_to_cm(target); struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; if (!dap) { /* Used debug interface doesn't support direct DAP access */ LOG_INFO("Target can't be unlocked by this debug interface"); /* Core check */ ret = target_read_u32(target, CPUID, &val); if (ret != ERROR_OK) return ret; if ((val & CPUID_CHECK_VALUE_MASK) != CPUID_CHECK_VALUE) { LOG_ERROR("Target is not ARM Cortex-M3 or is already locked"); return ERROR_FAIL; } } else { /* check SIM3X_AP_ID */ ret = ap_read_register(dap, SIM3X_AP_ID, &val); if (ret != ERROR_OK) return ret; if (val != SIM3X_AP_ID_VALUE) { LOG_ERROR("Wrong SIM3X_AP_ID"); return ERROR_FAIL; } /* check if locked */ ret = target_read_u32(target, CPUID, &val); /* if correct value is read, then it will continue */ if (ret != ERROR_OK || (val & CPUID_CHECK_VALUE_MASK) != CPUID_CHECK_VALUE) { /* if correct value isn't read, then it will check SIM3X_AP_INIT_STAT register */ ret = ap_read_register(dap, SIM3X_AP_INIT_STAT, &val); if (ret != ERROR_OK) return ret; if (val & SIM3X_AP_INIT_STAT_LOCK) { LOG_INFO("Target is already locked"); return ERROR_OK; } else { LOG_ERROR("Target doesn't seem to be locked but memory was not read correct"); return ERROR_FAIL; } } } ret = target_read_u32(target, LOCK_WORD_ADDRESS, &val); if (ret != ERROR_OK) return ret; if (val == LOCK_WORD_MCU_UNLOCKED) { /* Lock Flash */ uint8_t lock_word[4]; target_buffer_set_u32(target, lock_word, 0xFFFFFFFE); /* Get Flash Bank */ struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; ret = sim3x_flash_write(bank, lock_word, LOCK_WORD_ADDRESS, 4); if (ret != ERROR_OK) return ret; LOG_INFO("Target is successfully locked"); return ERROR_OK; } else if (val == LOCK_WORD_MCU_UNLOCKED_BY_FIRMWARE) { /* Can't by locked again without erase, because LOCK_WORD is in FLASH */ LOG_ERROR("Target is unlocked by firmware and can't by locked again without the lock page erase or mass erase"); return ERROR_FAIL; } else { LOG_ERROR("Unexpected lock word value"); /* SIM3X_AP_ID_VALUE is not checked */ if (!dap) LOG_INFO("Maybe this isn't a SiM3x MCU"); return ERROR_FAIL; } } static const struct command_registration sim3x_exec_command_handlers[] = { { .name = "mass_erase", .mode = COMMAND_EXEC, .help = "Erase the complete flash", .usage = "", .handler = sim3x_mass_erase, }, { .name = "lock", .mode = COMMAND_EXEC, .help = "Locks the flash. Unlock by mass erase", .usage = "", .handler = sim3x_lock, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration sim3x_command_handlers[] = { { .name = "sim3x", .mode = COMMAND_ANY, .help = "sim3x flash command group", .usage = "", .chain = sim3x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver sim3x_flash = { .name = "sim3x", .commands = sim3x_command_handlers, .flash_bank_command = sim3x_flash_bank_command, .erase = sim3x_flash_erase, .protect = sim3x_flash_protect, .write = sim3x_flash_write, .read = default_flash_read, .probe = sim3x_probe, .auto_probe = sim3x_auto_probe, .erase_check = default_flash_blank_check, .protect_check = sim3x_flash_protect_check, .info = sim3x_flash_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/spi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2018 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * * * * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * * * * Copyright (C) 2010 by Antonio Borneo * * borneo.antonio@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "spi.h" #include <jtag/jtag.h> /* Shared table of known SPI flash devices for SPI-based flash drivers. Taken * from device datasheets and Linux SPI flash drivers. */ const struct flash_device flash_devices[] = { /* name, read_cmd, qread_cmd, pprog_cmd, erase_cmd, chip_erase_cmd, device_id, * pagesize, sectorsize, size_in_bytes * note: device id is usually 3 bytes long, however the unused highest byte counts * continuation codes for manufacturer id as per JEP106xx */ FLASH_ID("st m25pe10", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00118020, 0x100, 0x10000, 0x20000), FLASH_ID("st m25pe20", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00128020, 0x100, 0x10000, 0x40000), FLASH_ID("st m25pe40", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00138020, 0x100, 0x10000, 0x80000), FLASH_ID("st m25pe80", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00148020, 0x100, 0x10000, 0x100000), FLASH_ID("st m25pe16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00158020, 0x100, 0x10000, 0x200000), FLASH_ID("st m25p05", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000), FLASH_ID("st m25p10", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000), FLASH_ID("st m25p20", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000), FLASH_ID("st m25p40", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00132020, 0x100, 0x10000, 0x80000), FLASH_ID("st m25p80", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00142020, 0x100, 0x10000, 0x100000), FLASH_ID("st m25p16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00152020, 0x100, 0x10000, 0x200000), FLASH_ID("st m25p32", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00162020, 0x100, 0x10000, 0x400000), FLASH_ID("st m25p64", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00172020, 0x100, 0x10000, 0x800000), FLASH_ID("st m25p128", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00182020, 0x100, 0x40000, 0x1000000), FLASH_ID("st m45pe10", 0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00114020, 0x100, 0x10000, 0x20000), FLASH_ID("st m45pe20", 0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00124020, 0x100, 0x10000, 0x40000), FLASH_ID("st m45pe40", 0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00134020, 0x100, 0x10000, 0x80000), FLASH_ID("st m45pe80", 0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00144020, 0x100, 0x10000, 0x100000), FLASH_ID("sp s25fl004", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00120201, 0x100, 0x10000, 0x80000), FLASH_ID("sp s25fl008", 0x03, 0x08, 0x02, 0xd8, 0xc7, 0x00130201, 0x100, 0x10000, 0x100000), FLASH_ID("sp s25fl016", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00140201, 0x100, 0x10000, 0x200000), FLASH_ID("sp s25fl116k", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00154001, 0x100, 0x10000, 0x200000), FLASH_ID("sp s25fl032", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00150201, 0x100, 0x10000, 0x400000), FLASH_ID("sp s25fl132k", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00164001, 0x100, 0x10000, 0x400000), FLASH_ID("sp s25fl064", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00160201, 0x100, 0x10000, 0x800000), FLASH_ID("sp s25fl164k", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 0x800000), FLASH_ID("sp s25fl128s", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 0x1000000), FLASH_ID("sp s25fl256s", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00190201, 0x100, 0x10000, 0x2000000), FLASH_ID("sp s25fl512s", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00200201, 0x200, 0x40000, 0x4000000), FLASH_ID("cyp s25fl064l", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00176001, 0x100, 0x10000, 0x800000), FLASH_ID("cyp s25fl128l", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00186001, 0x100, 0x10000, 0x1000000), FLASH_ID("cyp s25fl256l", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00196001, 0x100, 0x10000, 0x2000000), FLASH_ID("cyp s28hl256t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x00195a34, 0x100, 0x40000, 0x2000000), /* page! */ FLASH_ID("cyp s28hs256t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x00195b34, 0x100, 0x40000, 0x2000000), /* page! */ FLASH_ID("cyp s28hl512t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a5a34, 0x100, 0x40000, 0x4000000), /* page! */ FLASH_ID("cyp s28hs512t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a5b34, 0x100, 0x40000, 0x4000000), /* page! */ FLASH_ID("cyp s28hl01gt", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b5a34, 0x100, 0x40000, 0x8000000), /* page! */ FLASH_ID("cyp s28hs01gt", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b5b34, 0x100, 0x40000, 0x8000000), /* page! */ FLASH_ID("atmel 25f512", 0x03, 0x00, 0x02, 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000), FLASH_ID("atmel 25f1024", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000), FLASH_ID("atmel 25f2048", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000), FLASH_ID("atmel 25f4096", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000), FLASH_ID("atmel 25fs040", 0x03, 0x00, 0x02, 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000), FLASH_ID("adesto 25sf041b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001841f, 0x100, 0x10000, 0x80000), FLASH_ID("adesto 25df081a", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001451f, 0x100, 0x10000, 0x100000), FLASH_ID("adesto 25sf081b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001851f, 0x100, 0x10000, 0x100000), FLASH_ID("adesto 25sf161b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001861f, 0x100, 0x10000, 0x200000), FLASH_ID("adesto 25df321b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001471f, 0x100, 0x10000, 0x400000), FLASH_ID("adesto 25sf321b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001871f, 0x100, 0x10000, 0x400000), FLASH_ID("adesto 25xf641b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001881f, 0x100, 0x10000, 0x800000), /* sf/qf */ FLASH_ID("adesto 25xf128a", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001891f, 0x100, 0x10000, 0x1000000), /* sf/qf */ FLASH_ID("adesto xp032", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0700a743, 0x100, 0x10000, 0x400000), /* 4-byte */ FLASH_ID("adesto xp064b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0001a81f, 0x100, 0x10000, 0x800000), /* 4-byte */ FLASH_ID("adesto xp128", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0000a91f, 0x100, 0x10000, 0x1000000), /* 4-byte */ FLASH_ID("mac 25l512", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000), FLASH_ID("mac 25l1005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000), FLASH_ID("mac 25l2005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000), FLASH_ID("mac 25l4005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001320c2, 0x010, 0x10000, 0x80000), FLASH_ID("mac 25l8005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001420c2, 0x010, 0x10000, 0x100000), FLASH_ID("mac 25l1605", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001520c2, 0x100, 0x10000, 0x200000), FLASH_ID("mac 25l3205", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001620c2, 0x100, 0x10000, 0x400000), FLASH_ID("mac 25l6405", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000), FLASH_ID("mac 25l12845", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001820c2, 0x100, 0x10000, 0x1000000), FLASH_ID("mac 25l25645", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001920c2, 0x100, 0x10000, 0x2000000), FLASH_ID("mac 25l51245", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a20c2, 0x100, 0x10000, 0x4000000), FLASH_ID("mac 25lm51245", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x003a85c2, 0x100, 0x10000, 0x4000000), FLASH_ID("mac 25r512f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001028c2, 0x100, 0x10000, 0x10000), FLASH_ID("mac 25r1035f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001128c2, 0x100, 0x10000, 0x20000), FLASH_ID("mac 25r2035f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001228c2, 0x100, 0x10000, 0x40000), FLASH_ID("mac 25r4035f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001328c2, 0x100, 0x10000, 0x80000), FLASH_ID("mac 25r8035f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001428c2, 0x100, 0x10000, 0x100000), FLASH_ID("mac 25r1635f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001528c2, 0x100, 0x10000, 0x200000), FLASH_ID("mac 25r3235f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001628c2, 0x100, 0x10000, 0x400000), FLASH_ID("mac 25r6435f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001728c2, 0x100, 0x10000, 0x800000), FLASH_ID("mac 25u1635e", 0x03, 0xeb, 0x02, 0x20, 0xc7, 0x003525c2, 0x100, 0x1000, 0x100000), FLASH_ID("mac 66l1g45g", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b20c2, 0x100, 0x10000, 0x8000000), FLASH_ID("mac 66um1g45g", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x003b80c2, 0x100, 0x10000, 0x8000000), FLASH_ID("mac 66lm1g45g", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x003b85c2, 0x100, 0x10000, 0x8000000), FLASH_ID("micron n25q032", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0016ba20, 0x100, 0x10000, 0x400000), FLASH_ID("micron n25q064", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000), FLASH_ID("micron n25q128", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000), FLASH_ID("micron n25q256 3v", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019ba20, 0x100, 0x10000, 0x2000000), FLASH_ID("micron n25q256 1.8v", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019bb20, 0x100, 0x10000, 0x2000000), FLASH_ID("micron mt25ql512", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0020ba20, 0x100, 0x10000, 0x4000000), FLASH_ID("micron mt25ql01", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0021ba20, 0x100, 0x10000, 0x8000000), FLASH_ID("micron mt25qu01", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0021bb20, 0x100, 0x10000, 0x8000000), FLASH_ID("micron mt25ql02", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0022ba20, 0x100, 0x10000, 0x10000000), FLASH_ID("win w25q80bv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), FLASH_ID("win w25q16jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540ef, 0x100, 0x10000, 0x200000), FLASH_ID("win w25q16jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001570ef, 0x100, 0x10000, 0x200000), /* QPI / DTR */ FLASH_ID("win w25q32fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000), FLASH_ID("win w25q32fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000), /* QPI mode */ FLASH_ID("win w25q32jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001670ef, 0x100, 0x10000, 0x400000), FLASH_ID("win w25q64fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000), FLASH_ID("win w25q64fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001760ef, 0x100, 0x10000, 0x800000), /* QPI mode */ FLASH_ID("win w25q64jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001770ef, 0x100, 0x10000, 0x800000), FLASH_ID("win w25q128fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000), FLASH_ID("win w25q128fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001860ef, 0x100, 0x10000, 0x1000000), /* QPI mode */ FLASH_ID("win w25q128jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001870ef, 0x100, 0x10000, 0x1000000), FLASH_ID("win w25q256fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001940ef, 0x100, 0x10000, 0x2000000), FLASH_ID("win w25q256fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001960ef, 0x100, 0x10000, 0x2000000), /* QPI mode */ FLASH_ID("win w25q256jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001970ef, 0x100, 0x10000, 0x2000000), FLASH_ID("win w25q512jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x002040ef, 0x100, 0x10000, 0x4000000), FLASH_ID("win w25q01jv", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002140ef, 0x100, 0x10000, 0x8000000), FLASH_ID("win w25q01jv-dtr", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x002170ef, 0x100, 0x10000, 0x8000000), FLASH_ID("win w25q02jv-dtr", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x002270ef, 0x100, 0x10000, 0x10000000), FLASH_ID("gd gd25q512", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001040c8, 0x100, 0x1000, 0x10000), FLASH_ID("gd gd25q10", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001140c8, 0x100, 0x1000, 0x20000), FLASH_ID("gd gd25q20", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001240c8, 0x100, 0x1000, 0x40000), FLASH_ID("gd gd25q40", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001340c8, 0x100, 0x1000, 0x80000), FLASH_ID("gd gd25q16c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000), FLASH_ID("gd gd25q32c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000), FLASH_ID("gd gd25q64c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001740c8, 0x100, 0x10000, 0x800000), FLASH_ID("gd gd25q128c", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000), FLASH_ID("gd gd25q256c", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x001940c8, 0x100, 0x10000, 0x2000000), FLASH_ID("gd gd25q512mc", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002040c8, 0x100, 0x10000, 0x4000000), FLASH_ID("gd gd25lx256e", 0x13, 0x0c, 0x12, 0xdc, 0xc7, 0x001968c8, 0x100, 0x10000, 0x2000000), FLASH_ID("zbit zb25vq16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0015605e, 0x100, 0x10000, 0x200000), FLASH_ID("zbit zb25vq32", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016405e, 0x100, 0x10000, 0x400000), FLASH_ID("zbit zb25vq32", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016605e, 0x100, 0x10000, 0x400000), /* QPI mode */ FLASH_ID("zbit zb25vq64", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017405e, 0x100, 0x10000, 0x800000), FLASH_ID("zbit zb25vq64", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017605e, 0x100, 0x10000, 0x800000), /* QPI mode */ FLASH_ID("zbit zb25vq128", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018405e, 0x100, 0x10000, 0x1000000), FLASH_ID("zbit zb25vq128", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018605e, 0x100, 0x10000, 0x1000000), /* QPI mode */ FLASH_ID("issi is25lq040b", 0x03, 0xeb, 0x02, 0x20, 0xc7, 0x0013409d, 0x100, 0x1000, 0x80000), FLASH_ID("issi is25lp032", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0016609d, 0x100, 0x10000, 0x400000), FLASH_ID("issi is25lp064", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0017609d, 0x100, 0x10000, 0x800000), FLASH_ID("issi is25lp128d", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018609d, 0x100, 0x10000, 0x1000000), FLASH_ID("issi is25wp128d", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018709d, 0x100, 0x10000, 0x1000000), FLASH_ID("issi is25lp256d", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019609d, 0x100, 0x10000, 0x2000000), FLASH_ID("issi is25wp256d", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019709d, 0x100, 0x10000, 0x2000000), FLASH_ID("issi is25lp512m", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a609d, 0x100, 0x10000, 0x4000000), FLASH_ID("issi is25wp512m", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a709d, 0x100, 0x10000, 0x4000000), FLASH_ID("xtx xt25f02e", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0012400b, 0x100, 0x10000, 0x40000), FLASH_ID("xtx xt25f04d", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0013400b, 0x100, 0x10000, 0x80000), FLASH_ID("xtx xt25f08b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0014400b, 0x100, 0x10000, 0x100000), FLASH_ID("xtx xt25f16b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0015400b, 0x100, 0x10000, 0x200000), FLASH_ID("xtx xt25f32b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016400b, 0x100, 0x10000, 0x200000), FLASH_ID("xtx xt25f64b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017400b, 0x100, 0x10000, 0x400000), FLASH_ID("xtx xt25f128b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018400b, 0x100, 0x10000, 0x800000), FLASH_ID("xtx xt25q08d", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0014600b, 0x100, 0x10000, 0x100000), FLASH_ID("xtx xt25q16b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0015600b, 0x100, 0x10000, 0x200000), FLASH_ID("xtx xt25q32b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016600b, 0x100, 0x10000, 0x400000), /* exists ? */ FLASH_ID("xtx xt25q64b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017600b, 0x100, 0x10000, 0x800000), FLASH_ID("xtx xt25q128b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018600b, 0x100, 0x10000, 0x1000000), /* FRAM, no erase commands, no write page or sectors */ FRAM_ID("fu mb85rs16n", 0x03, 0, 0x02, 0x00010104, 0x800), FRAM_ID("fu mb85rs32v", 0x03, 0, 0x02, 0x00010204, 0x1000), /* exists ? */ FRAM_ID("fu mb85rs64v", 0x03, 0, 0x02, 0x00020304, 0x2000), FRAM_ID("fu mb85rs128b", 0x03, 0, 0x02, 0x00090404, 0x4000), FRAM_ID("fu mb85rs256b", 0x03, 0, 0x02, 0x00090504, 0x8000), FRAM_ID("fu mb85rs512t", 0x03, 0, 0x02, 0x00032604, 0x10000), FRAM_ID("fu mb85rs1mt", 0x03, 0, 0x02, 0x00032704, 0x20000), FRAM_ID("fu mb85rs2mta", 0x03, 0, 0x02, 0x00034804, 0x40000), FRAM_ID("cyp fm25v01a", 0x03, 0, 0x02, 0x060821c2, 0x4000), FRAM_ID("cyp fm25v02", 0x03, 0, 0x02, 0x060022c2, 0x8000), FRAM_ID("cyp fm25v02a", 0x03, 0, 0x02, 0x060822c2, 0x8000), FRAM_ID("cyp fm25v05", 0x03, 0, 0x02, 0x060023c2, 0x10000), FRAM_ID("cyp fm25v10", 0x03, 0, 0x02, 0x060024c2, 0x20000), FRAM_ID("cyp fm25v20a", 0x03, 0, 0x02, 0x060825c2, 0x40000), FRAM_ID("cyp fm25v40", 0x03, 0, 0x02, 0x064026c2, 0x80000), FRAM_ID("cyp cy15b102qn", 0x03, 0, 0x02, 0x06002ac2, 0x40000), FRAM_ID("cyp cy15v102qn", 0x03, 0, 0x02, 0x06042ac2, 0x40000), FRAM_ID("cyp cy15b104qi", 0x03, 0, 0x02, 0x06012dc2, 0x80000), FRAM_ID("cyp cy15b104qi", 0x03, 0, 0x02, 0x06a12dc2, 0x80000), FRAM_ID("cyp cy15v104qi", 0x03, 0, 0x02, 0x06052dc2, 0x80000), FRAM_ID("cyp cy15v104qi", 0x03, 0, 0x02, 0x06a52dc2, 0x80000), FRAM_ID("cyp cy15b104qn", 0x03, 0, 0x02, 0x06402cc2, 0x80000), FRAM_ID("cyp cy15b108qi", 0x03, 0, 0x02, 0x06012fc2, 0x100000), FRAM_ID("cyp cy15b108qi", 0x03, 0, 0x02, 0x06a12fc2, 0x100000), FRAM_ID("cyp cy15v108qi", 0x03, 0, 0x02, 0x06052fc2, 0x100000), FRAM_ID("cyp cy15v108qi", 0x03, 0, 0x02, 0x06a52fc2, 0x100000), FRAM_ID("cyp cy15b108qn", 0x03, 0, 0x02, 0x06012ec2, 0x100000), FRAM_ID("cyp cy15b108qn", 0x03, 0, 0x02, 0x06032ec2, 0x100000), FRAM_ID("cyp cy15b108qn", 0x03, 0, 0x02, 0x06a12ec2, 0x100000), FRAM_ID("cyp cy15v108qn", 0x03, 0, 0x02, 0x06052ec2, 0x100000), FRAM_ID("cyp cy15v108qn", 0x03, 0, 0x02, 0x06072ec2, 0x100000), FRAM_ID("cyp cy15v108qn", 0x03, 0, 0x02, 0x06a52ec2, 0x100000), FLASH_ID(NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0) }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/spi.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2018-2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * * * * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * * * * Copyright (C) 2010 by Antonio Borneo * * borneo.antonio@gmail.com * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_SPI_H #define OPENOCD_FLASH_NOR_SPI_H #ifndef __ASSEMBLER__ /* data structure to maintain flash ids from different vendors */ struct flash_device { const char *name; uint8_t read_cmd; uint8_t qread_cmd; uint8_t pprog_cmd; uint8_t erase_cmd; uint8_t chip_erase_cmd; uint32_t device_id; uint32_t pagesize; uint32_t sectorsize; uint32_t size_in_bytes; }; #define FLASH_ID(n, re, qr, pp, es, ces, id, psize, ssize, size) \ { \ .name = n, \ .read_cmd = re, \ .qread_cmd = qr, \ .pprog_cmd = pp, \ .erase_cmd = es, \ .chip_erase_cmd = ces, \ .device_id = id, \ .pagesize = psize, \ .sectorsize = ssize, \ .size_in_bytes = size, \ } #define FRAM_ID(n, re, qr, pp, id, size) \ { \ .name = n, \ .read_cmd = re, \ .qread_cmd = qr, \ .pprog_cmd = pp, \ .erase_cmd = 0x00, \ .chip_erase_cmd = 0x00, \ .device_id = id, \ .pagesize = 0, \ .sectorsize = 0, \ .size_in_bytes = size, \ } extern const struct flash_device flash_devices[]; #endif /* fields in SPI flash status register */ #define SPIFLASH_BSY 0 #define SPIFLASH_BSY_BIT (1 << SPIFLASH_BSY) /* WIP Bit of SPI SR */ #define SPIFLASH_WE 1 #define SPIFLASH_WE_BIT (1 << SPIFLASH_WE) /* WEL Bit of SPI SR */ /* SPI Flash Commands */ #define SPIFLASH_READ_ID 0x9F /* Read Flash Identification */ #define SPIFLASH_READ_MID 0xAF /* Read Flash Identification, multi-io */ #define SPIFLASH_READ_STATUS 0x05 /* Read Status Register */ #define SPIFLASH_WRITE_ENABLE 0x06 /* Write Enable */ #define SPIFLASH_PAGE_PROGRAM 0x02 /* Page Program */ #define SPIFLASH_FAST_READ 0x0B /* Fast Read */ #define SPIFLASH_READ 0x03 /* Normal Read */ #define SPIFLASH_MASS_ERASE 0xC7 /* Mass Erase */ #define SPIFLASH_READ_SFDP 0x5A /* Read Serial Flash Discoverable Parameters */ #define SPIFLASH_DEF_PAGESIZE 256 /* default for non-page-oriented devices (FRAMs) */ #endif /* OPENOCD_FLASH_NOR_SPI_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/stellaris.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ /*************************************************************************** * STELLARIS flash is tested on LM3S811, LM3S6965, LM3s3748, more. ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/interface.h" #include "imp.h" #include <target/algorithm.h> #include <target/arm_adi_v5.h> #include <target/armv7m.h> #define DID0_VER(did0) ((did0 >> 28)&0x07) /* STELLARIS control registers */ #define SCB_BASE 0x400FE000 #define DID0 0x000 #define DID1 0x004 #define DC0 0x008 #define DC1 0x010 #define DC2 0x014 #define DC3 0x018 #define DC4 0x01C #define RIS 0x050 #define RCC 0x060 #define PLLCFG 0x064 #define RCC2 0x070 #define NVMSTAT 0x1a0 /* "legacy" flash memory protection registers (64KB max) */ #define FMPRE 0x130 #define FMPPE 0x134 /* new flash memory protection registers (for more than 64KB) */ #define FMPRE0 0x200 /* PRE1 = PRE0 + 4, etc */ #define FMPPE0 0x400 /* PPE1 = PPE0 + 4, etc */ #define USECRL 0x140 #define FLASH_CONTROL_BASE 0x400FD000 #define FLASH_FMA (FLASH_CONTROL_BASE | 0x000) #define FLASH_FMD (FLASH_CONTROL_BASE | 0x004) #define FLASH_FMC (FLASH_CONTROL_BASE | 0x008) #define FLASH_CRIS (FLASH_CONTROL_BASE | 0x00C) #define FLASH_CIM (FLASH_CONTROL_BASE | 0x010) #define FLASH_MISC (FLASH_CONTROL_BASE | 0x014) #define FLASH_FSIZE (FLASH_CONTROL_BASE | 0xFC0) #define FLASH_SSIZE (FLASH_CONTROL_BASE | 0xFC4) #define AMISC 1 #define PMISC 2 #define AMASK 1 #define PMASK 2 /* Flash Controller Command bits */ #define FMC_WRKEY (0xA442 << 16) #define FMC_COMT (1 << 3) #define FMC_MERASE (1 << 2) #define FMC_ERASE (1 << 1) #define FMC_WRITE (1 << 0) /* STELLARIS constants */ /* values to write in FMA to commit write-"once" values */ #define FLASH_FMA_PRE(x) (2 * (x)) /* for FMPPREx */ #define FLASH_FMA_PPE(x) (2 * (x) + 1) /* for FMPPPEx */ static void stellaris_read_clock_info(struct flash_bank *bank); static int stellaris_mass_erase(struct flash_bank *bank); struct stellaris_flash_bank { /* chip id register */ uint32_t did0; uint32_t did1; uint32_t dc0; uint32_t dc1; uint32_t fsize; uint32_t ssize; const char *target_name; uint8_t target_class; uint32_t sramsiz; /* flash geometry */ uint32_t num_pages; uint32_t pagesize; /* main clock status */ uint32_t rcc; uint32_t rcc2; uint8_t mck_valid; uint8_t xtal_mask; uint32_t iosc_freq; uint32_t mck_freq; const char *iosc_desc; const char *mck_desc; }; /* Autogenerated by contrib/gen-stellaris-part-header.pl */ /* From Stellaris Firmware Development Package revision 9453 */ static const struct { uint8_t class; uint8_t partno; const char *partname; } stellaris_parts[] = { {0x00, 0x01, "LM3S101"}, {0x00, 0x02, "LM3S102"}, {0x01, 0xBF, "LM3S1110"}, {0x01, 0xC3, "LM3S1133"}, {0x01, 0xC5, "LM3S1138"}, {0x01, 0xC1, "LM3S1150"}, {0x01, 0xC4, "LM3S1162"}, {0x01, 0xC2, "LM3S1165"}, {0x01, 0xEC, "LM3S1166"}, {0x01, 0xC6, "LM3S1332"}, {0x01, 0xBC, "LM3S1435"}, {0x01, 0xBA, "LM3S1439"}, {0x01, 0xBB, "LM3S1512"}, {0x01, 0xC7, "LM3S1538"}, {0x01, 0xDB, "LM3S1601"}, {0x03, 0x06, "LM3S1607"}, {0x01, 0xDA, "LM3S1608"}, {0x01, 0xC0, "LM3S1620"}, {0x04, 0xCD, "LM3S1621"}, {0x03, 0x03, "LM3S1625"}, {0x03, 0x04, "LM3S1626"}, {0x03, 0x05, "LM3S1627"}, {0x01, 0xB3, "LM3S1635"}, {0x01, 0xEB, "LM3S1636"}, {0x01, 0xBD, "LM3S1637"}, {0x04, 0xB1, "LM3S1651"}, {0x01, 0xB9, "LM3S1751"}, {0x03, 0x10, "LM3S1776"}, {0x04, 0x16, "LM3S1811"}, {0x04, 0x3D, "LM3S1816"}, {0x01, 0xB4, "LM3S1850"}, {0x01, 0xDD, "LM3S1911"}, {0x01, 0xDC, "LM3S1918"}, {0x01, 0xB7, "LM3S1937"}, {0x01, 0xBE, "LM3S1958"}, {0x01, 0xB5, "LM3S1960"}, {0x01, 0xB8, "LM3S1968"}, {0x01, 0xEA, "LM3S1969"}, {0x04, 0xCE, "LM3S1B21"}, {0x06, 0xCA, "LM3S1C21"}, {0x06, 0xCB, "LM3S1C26"}, {0x06, 0x98, "LM3S1C58"}, {0x06, 0xB0, "LM3S1D21"}, {0x06, 0xCC, "LM3S1D26"}, {0x06, 0x1D, "LM3S1F11"}, {0x06, 0x1B, "LM3S1F16"}, {0x06, 0xAF, "LM3S1G21"}, {0x06, 0x95, "LM3S1G58"}, {0x06, 0x1E, "LM3S1H11"}, {0x06, 0x1C, "LM3S1H16"}, {0x04, 0x0F, "LM3S1J11"}, {0x04, 0x3C, "LM3S1J16"}, {0x04, 0x0E, "LM3S1N11"}, {0x04, 0x3B, "LM3S1N16"}, {0x04, 0xB2, "LM3S1P51"}, {0x04, 0x9E, "LM3S1R21"}, {0x04, 0xC9, "LM3S1R26"}, {0x04, 0x30, "LM3S1W16"}, {0x04, 0x2F, "LM3S1Z16"}, {0x01, 0x51, "LM3S2110"}, {0x01, 0x84, "LM3S2139"}, {0x03, 0x39, "LM3S2276"}, {0x01, 0xA2, "LM3S2410"}, {0x01, 0x59, "LM3S2412"}, {0x01, 0x56, "LM3S2432"}, {0x01, 0x5A, "LM3S2533"}, {0x01, 0xE1, "LM3S2601"}, {0x01, 0xE0, "LM3S2608"}, {0x03, 0x33, "LM3S2616"}, {0x01, 0x57, "LM3S2620"}, {0x01, 0x85, "LM3S2637"}, {0x01, 0x53, "LM3S2651"}, {0x03, 0x80, "LM3S2671"}, {0x03, 0x50, "LM3S2678"}, {0x01, 0xA4, "LM3S2730"}, {0x01, 0x52, "LM3S2739"}, {0x03, 0x3A, "LM3S2776"}, {0x04, 0x6D, "LM3S2793"}, {0x01, 0xE3, "LM3S2911"}, {0x01, 0xE2, "LM3S2918"}, {0x01, 0xED, "LM3S2919"}, {0x01, 0x54, "LM3S2939"}, {0x01, 0x8F, "LM3S2948"}, {0x01, 0x58, "LM3S2950"}, {0x01, 0x55, "LM3S2965"}, {0x04, 0x6C, "LM3S2B93"}, {0x06, 0x94, "LM3S2D93"}, {0x06, 0x93, "LM3S2U93"}, {0x00, 0x19, "LM3S300"}, {0x00, 0x11, "LM3S301"}, {0x00, 0x1A, "LM3S308"}, {0x00, 0x12, "LM3S310"}, {0x00, 0x13, "LM3S315"}, {0x00, 0x14, "LM3S316"}, {0x00, 0x17, "LM3S317"}, {0x00, 0x15, "LM3S328"}, {0x03, 0x08, "LM3S3634"}, {0x03, 0x43, "LM3S3651"}, {0x04, 0xC8, "LM3S3654"}, {0x03, 0x44, "LM3S3739"}, {0x03, 0x49, "LM3S3748"}, {0x03, 0x45, "LM3S3749"}, {0x04, 0x42, "LM3S3826"}, {0x04, 0x41, "LM3S3J26"}, {0x04, 0x40, "LM3S3N26"}, {0x04, 0x3F, "LM3S3W26"}, {0x04, 0x3E, "LM3S3Z26"}, {0x03, 0x81, "LM3S5632"}, {0x04, 0x0C, "LM3S5651"}, {0x03, 0x8A, "LM3S5652"}, {0x04, 0x4D, "LM3S5656"}, {0x03, 0x91, "LM3S5662"}, {0x03, 0x96, "LM3S5732"}, {0x03, 0x97, "LM3S5737"}, {0x03, 0xA0, "LM3S5739"}, {0x03, 0x99, "LM3S5747"}, {0x03, 0xA7, "LM3S5749"}, {0x03, 0x9A, "LM3S5752"}, {0x03, 0x9C, "LM3S5762"}, {0x04, 0x69, "LM3S5791"}, {0x04, 0x0B, "LM3S5951"}, {0x04, 0x4E, "LM3S5956"}, {0x04, 0x68, "LM3S5B91"}, {0x06, 0x2E, "LM3S5C31"}, {0x06, 0x2C, "LM3S5C36"}, {0x06, 0x5E, "LM3S5C51"}, {0x06, 0x5B, "LM3S5C56"}, {0x06, 0x5F, "LM3S5D51"}, {0x06, 0x5C, "LM3S5D56"}, {0x06, 0x87, "LM3S5D91"}, {0x06, 0x2D, "LM3S5G31"}, {0x06, 0x1F, "LM3S5G36"}, {0x06, 0x5D, "LM3S5G51"}, {0x06, 0x4F, "LM3S5G56"}, {0x04, 0x09, "LM3S5K31"}, {0x04, 0x4A, "LM3S5K36"}, {0x04, 0x0A, "LM3S5P31"}, {0x04, 0x48, "LM3S5P36"}, {0x04, 0xB6, "LM3S5P3B"}, {0x04, 0x0D, "LM3S5P51"}, {0x04, 0x4C, "LM3S5P56"}, {0x04, 0x07, "LM3S5R31"}, {0x04, 0x4B, "LM3S5R36"}, {0x04, 0x47, "LM3S5T36"}, {0x06, 0x7F, "LM3S5U91"}, {0x04, 0x46, "LM3S5Y36"}, {0x00, 0x2A, "LM3S600"}, {0x00, 0x21, "LM3S601"}, {0x00, 0x2B, "LM3S608"}, {0x00, 0x22, "LM3S610"}, {0x01, 0xA1, "LM3S6100"}, {0x00, 0x23, "LM3S611"}, {0x01, 0x74, "LM3S6110"}, {0x00, 0x24, "LM3S612"}, {0x00, 0x25, "LM3S613"}, {0x00, 0x26, "LM3S615"}, {0x00, 0x28, "LM3S617"}, {0x00, 0x29, "LM3S618"}, {0x00, 0x27, "LM3S628"}, {0x01, 0xA5, "LM3S6420"}, {0x01, 0x82, "LM3S6422"}, {0x01, 0x75, "LM3S6432"}, {0x01, 0x76, "LM3S6537"}, {0x01, 0x71, "LM3S6610"}, {0x01, 0xE7, "LM3S6611"}, {0x01, 0xE6, "LM3S6618"}, {0x01, 0x83, "LM3S6633"}, {0x01, 0x8B, "LM3S6637"}, {0x01, 0xA3, "LM3S6730"}, {0x01, 0x77, "LM3S6753"}, {0x01, 0xE9, "LM3S6911"}, {0x01, 0xE8, "LM3S6918"}, {0x01, 0x89, "LM3S6938"}, {0x01, 0x72, "LM3S6950"}, {0x01, 0x78, "LM3S6952"}, {0x01, 0x73, "LM3S6965"}, {0x06, 0xAA, "LM3S6C11"}, {0x06, 0xAC, "LM3S6C65"}, {0x06, 0x9F, "LM3S6G11"}, {0x06, 0xAB, "LM3S6G65"}, {0x00, 0x38, "LM3S800"}, {0x00, 0x31, "LM3S801"}, {0x00, 0x39, "LM3S808"}, {0x00, 0x32, "LM3S811"}, {0x00, 0x33, "LM3S812"}, {0x00, 0x34, "LM3S815"}, {0x00, 0x36, "LM3S817"}, {0x00, 0x37, "LM3S818"}, {0x00, 0x35, "LM3S828"}, {0x01, 0x64, "LM3S8530"}, {0x01, 0x8E, "LM3S8538"}, {0x01, 0x61, "LM3S8630"}, {0x01, 0x63, "LM3S8730"}, {0x01, 0x8D, "LM3S8733"}, {0x01, 0x86, "LM3S8738"}, {0x01, 0x65, "LM3S8930"}, {0x01, 0x8C, "LM3S8933"}, {0x01, 0x88, "LM3S8938"}, {0x01, 0xA6, "LM3S8962"}, {0x01, 0x62, "LM3S8970"}, {0x01, 0xD7, "LM3S8971"}, {0x06, 0xAE, "LM3S8C62"}, {0x06, 0xAD, "LM3S8G62"}, {0x04, 0xCF, "LM3S9781"}, {0x04, 0x67, "LM3S9790"}, {0x04, 0x6B, "LM3S9792"}, {0x04, 0x2D, "LM3S9971"}, {0x04, 0x20, "LM3S9997"}, {0x04, 0xD0, "LM3S9B81"}, {0x04, 0x66, "LM3S9B90"}, {0x04, 0x6A, "LM3S9B92"}, {0x04, 0x6E, "LM3S9B95"}, {0x04, 0x6F, "LM3S9B96"}, {0x04, 0x1D, "LM3S9BN2"}, {0x04, 0x1E, "LM3S9BN5"}, {0x04, 0x1F, "LM3S9BN6"}, {0x06, 0x70, "LM3S9C97"}, {0x06, 0xA9, "LM3S9D81"}, {0x06, 0x7E, "LM3S9D90"}, {0x06, 0x92, "LM3S9D92"}, {0x06, 0x9D, "LM3S9D96"}, {0x06, 0x7B, "LM3S9DN5"}, {0x06, 0x7C, "LM3S9DN6"}, {0x06, 0x60, "LM3S9G97"}, {0x06, 0x79, "LM3S9GN5"}, {0x04, 0x1B, "LM3S9L71"}, {0x04, 0x18, "LM3S9L97"}, {0x06, 0xA8, "LM3S9U81"}, {0x06, 0x7D, "LM3S9U90"}, {0x06, 0x90, "LM3S9U92"}, {0x06, 0x9B, "LM3S9U96"}, {0x05, 0x01, "LM4F120B2QR/TM4C1233C3PM"}, {0x05, 0x02, "LM4F120C4QR/TM4C1233D5PM"}, {0x05, 0x03, "LM4F120E5QR/TM4C1233E6PM"}, {0x05, 0x04, "LM4F120H5QR/TM4C1233H6PM"}, {0x05, 0x08, "LM4F121B2QR/TM4C1232C3PM"}, {0x05, 0x09, "LM4F121C4QR/TM4C1232D5PM"}, {0x05, 0x0A, "LM4F121E5QR/TM4C1232E6PM"}, {0x05, 0x0B, "LM4F121H5QR/TM4C1232H6PM"}, {0x05, 0x10, "LM4F110E5QR/TM4C1231E6PM"}, {0x05, 0x11, "LM4F110H5QR/TM4C1231H6PM"}, {0x05, 0x18, "LM4F110B2QR/TM4C1231C3PM"}, {0x05, 0x19, "LM4F110C4QR/TM4C1231D5PM"}, {0x05, 0x20, "LM4F111E5QR/TM4C1230E6PM"}, {0x05, 0x21, "LM4F111H5QR/TM4C1230H6PM"}, {0x05, 0x22, "LM4F111B2QR/TM4C1230C3PM"}, {0x05, 0x23, "LM4F111C4QR/TM4C1230D5PM"}, {0x05, 0x30, "LM4F112E5QC/TM4C1231E6PZ"}, {0x05, 0x31, "LM4F112H5QC/TM4C1231H6PZ"}, {0x05, 0x35, "LM4F112H5QD/TM4C1231H6PGE"}, {0x05, 0x36, "LM4F112C4QC/TM4C1231D5PZ"}, {0x05, 0x40, "LM4F130E5QR/TM4C1237E6PM"}, {0x05, 0x41, "LM4F130H5QR/TM4C1237H6PM"}, {0x05, 0x48, "LM4F130C4QR/TM4C1237D5PM"}, {0x05, 0x50, "LM4F131E5QR/TM4C1236E6PM"}, {0x05, 0x51, "LM4F131H5QR/TM4C1236H6PM"}, {0x05, 0x52, "LM4F131C4QR/TM4C1236D5PM"}, {0x05, 0x60, "LM4F132E5QC/TM4C1237E6PZ"}, {0x05, 0x61, "LM4F132H5QC/TM4C1237H6PZ"}, {0x05, 0x65, "LM4F132H5QD/TM4C1237H6PGE"}, {0x05, 0x66, "LM4F132C4QC/TM4C1237D5PZ"}, {0x05, 0x70, "LM4F210E5QR/TM4C123BE6PM"}, {0x05, 0x73, "LM4F210H5QR/TM4C123BH6PM"}, {0x05, 0x80, "LM4F211E5QR/TM4C123AE6PM"}, {0x05, 0x83, "LM4F211H5QR/TM4C123AH6PM"}, {0x05, 0xA0, "LM4F230E5QR/TM4C123GE6PM"}, {0x05, 0xA1, "LM4F230H5QR/TM4C123GH6PM"}, {0x05, 0xB0, "LM4F231E5QR/TM4C123FE6PM"}, {0x05, 0xB1, "LM4F231H5QR/TM4C123FH6PM"}, {0x05, 0xC0, "LM4F232E5QC/TM4C123GE6PZ"}, {0x05, 0xC1, "LM4F232H5QC/TM4C123GH6PZ"}, {0x05, 0xC3, "LM4F212E5QC/TM4C123BE6PZ"}, {0x05, 0xC4, "LM4F212H5QC/TM4C123BH6PZ"}, {0x05, 0xC5, "LM4F232H5QD/TM4C123GH6PGE"}, {0x05, 0xC6, "LM4F212H5QD/TM4C123BH6PGE"}, {0x05, 0xD0, "LM4F122C4QC/TM4C1233D5PZ"}, {0x05, 0xD1, "LM4F122E5QC/TM4C1233E6PZ"}, {0x05, 0xD2, "LM4F122H5QC/TM4C1233H6PZ"}, {0x05, 0xD6, "LM4F122H5QD/TM4C1233H6PGE"}, {0x05, 0xE1, "LM4FSXLH5BB"}, {0x05, 0xE3, "LM4F232H5BB/TM4C123GH6ZRB"}, {0x05, 0xE4, "LM4FS99H5BB"}, {0x05, 0xE5, "LM4FS1AH5BB"}, {0x05, 0xE9, "LM4F212H5BB/TM4C123BH6ZRB"}, {0x05, 0xEA, "LM4FS1GH5BB"}, {0x05, 0xF0, "TM4C123GH6ZXR"}, {0x0A, 0x19, "TM4C1290NCPDT"}, {0x0A, 0x1B, "TM4C1290NCZAD"}, {0x0A, 0x1C, "TM4C1292NCPDT"}, {0x0A, 0x1E, "TM4C1292NCZAD"}, {0x0A, 0x1F, "TM4C1294NCPDT"}, {0x0A, 0x21, "TM4C1294NCZAD"}, {0x0A, 0x22, "TM4C1297NCZAD"}, {0x0A, 0x23, "TM4C1299NCZAD"}, {0x0A, 0x24, "TM4C129CNCPDT"}, {0x0A, 0x26, "TM4C129CNCZAD"}, {0x0A, 0x27, "TM4C129DNCPDT"}, {0x0A, 0x29, "TM4C129DNCZAD"}, {0x0A, 0x2D, "TM4C129ENCPDT"}, {0x0A, 0x2F, "TM4C129ENCZAD"}, {0x0A, 0x30, "TM4C129LNCZAD"}, {0x0A, 0x32, "TM4C129XNCZAD"}, {0x0A, 0x34, "TM4C1294KCPDT"}, {0x0A, 0x35, "TM4C129EKCPDT"}, {0x0A, 0x36, "TM4C1299KCZAD"}, {0x0A, 0x37, "TM4C129XKCZAD"}, {0xFF, 0x00, "Unknown Part"} }; static const char * const stellaris_classname[] = { "Sandstorm", "Fury", "Unknown", "DustDevil", "Tempest", "Blizzard/TM4C123x", "Firestorm", "", "", "", "Snowflake", }; /*************************************************************************** * openocd command interface * ***************************************************************************/ /* flash_bank stellaris <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(stellaris_flash_bank_command) { struct stellaris_flash_bank *stellaris_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; stellaris_info = calloc(sizeof(struct stellaris_flash_bank), 1); bank->base = 0x0; bank->driver_priv = stellaris_info; stellaris_info->target_name = "Unknown target"; /* part wasn't probed for info yet */ stellaris_info->did1 = 0; /* TODO Specify the main crystal speed in kHz using an optional * argument; ditto, the speed of an external oscillator used * instead of a crystal. Avoid programming flash using IOSC. */ return ERROR_OK; } static int get_stellaris_info(struct flash_bank *bank, struct command_invocation *cmd) { struct stellaris_flash_bank *stellaris_info = bank->driver_priv; if (stellaris_info->did1 == 0) return ERROR_FLASH_BANK_NOT_PROBED; /* Read main and master clock frequency register */ stellaris_read_clock_info(bank); command_print_sameline(cmd, "\nTI/LMI Stellaris information: Chip is " "class %i (%s) %s rev %c%i\n", stellaris_info->target_class, stellaris_classname[stellaris_info->target_class], stellaris_info->target_name, (int)('A' + ((stellaris_info->did0 >> 8) & 0xFF)), (int)((stellaris_info->did0) & 0xFF)); command_print_sameline(cmd, "did1: 0x%8.8" PRIx32 ", arch: 0x%4.4" PRIx32 ", eproc: %s, ramsize: %" PRIu32 "k, flashsize: %" PRIu32 "k\n", stellaris_info->did1, stellaris_info->did1, "ARMv7M", stellaris_info->sramsiz, (uint32_t)(stellaris_info->num_pages * stellaris_info->pagesize / 1024)); command_print_sameline(cmd, "master clock: %ikHz%s, " "rcc is 0x%" PRIx32 ", rcc2 is 0x%" PRIx32 ", " "pagesize: %" PRIu32 ", pages: %" PRIu32, (int)(stellaris_info->mck_freq / 1000), stellaris_info->mck_desc, stellaris_info->rcc, stellaris_info->rcc2, stellaris_info->pagesize, stellaris_info->num_pages); return ERROR_OK; } /*************************************************************************** * chip identification and status * ***************************************************************************/ /* Set the flash timing register to match current clocking */ static void stellaris_set_flash_timing(struct flash_bank *bank) { struct stellaris_flash_bank *stellaris_info = bank->driver_priv; struct target *target = bank->target; uint32_t usecrl = (stellaris_info->mck_freq/1000000ul-1); /* only valid for Sandstorm and Fury class devices */ if (stellaris_info->target_class > 1) return; LOG_DEBUG("usecrl = %i", (int)(usecrl)); target_write_u32(target, SCB_BASE | USECRL, usecrl); } static const unsigned rcc_xtal[32] = { [0x00] = 1000000, /* no pll */ [0x01] = 1843200, /* no pll */ [0x02] = 2000000, /* no pll */ [0x03] = 2457600, /* no pll */ [0x04] = 3579545, [0x05] = 3686400, [0x06] = 4000000, /* usb */ [0x07] = 4096000, [0x08] = 4915200, [0x09] = 5000000, /* usb */ [0x0a] = 5120000, [0x0b] = 6000000, /* (reset) usb */ [0x0c] = 6144000, [0x0d] = 7372800, [0x0e] = 8000000, /* usb */ [0x0f] = 8192000, /* parts before DustDevil use just 4 bits for xtal spec */ [0x10] = 10000000, /* usb */ [0x11] = 12000000, /* usb */ [0x12] = 12288000, [0x13] = 13560000, [0x14] = 14318180, [0x15] = 16000000, /* usb */ [0x16] = 16384000, }; /** Read clock configuration and set stellaris_info->usec_clocks. */ static void stellaris_read_clock_info(struct flash_bank *bank) { struct stellaris_flash_bank *stellaris_info = bank->driver_priv; struct target *target = bank->target; uint32_t rcc, rcc2, pllcfg, sysdiv, usesysdiv, bypass, oscsrc; unsigned xtal; unsigned long mainfreq; target_read_u32(target, SCB_BASE | RCC, &rcc); LOG_DEBUG("Stellaris RCC %" PRIx32 "", rcc); target_read_u32(target, SCB_BASE | RCC2, &rcc2); LOG_DEBUG("Stellaris RCC2 %" PRIx32 "", rcc); target_read_u32(target, SCB_BASE | PLLCFG, &pllcfg); LOG_DEBUG("Stellaris PLLCFG %" PRIx32 "", pllcfg); stellaris_info->rcc = rcc; stellaris_info->rcc2 = rcc2; sysdiv = (rcc >> 23) & 0xF; usesysdiv = (rcc >> 22) & 0x1; bypass = (rcc >> 11) & 0x1; oscsrc = (rcc >> 4) & 0x3; xtal = (rcc >> 6) & stellaris_info->xtal_mask; /* NOTE: post-Sandstorm parts have RCC2 which may override * parts of RCC ... with more sysdiv options, option for * 32768 Hz mainfreq, PLL controls. On Sandstorm it reads * as zero, so the "use RCC2" flag is always clear. */ if (rcc2 & (1 << 31)) { sysdiv = (rcc2 >> 23) & 0x3F; bypass = (rcc2 >> 11) & 0x1; oscsrc = (rcc2 >> 4) & 0x7; /* FIXME Tempest parts have an additional lsb for * fractional sysdiv (200 MHz / 2.5 == 80 MHz) */ } stellaris_info->mck_desc = ""; switch (oscsrc) { case 0: /* MOSC */ mainfreq = rcc_xtal[xtal]; break; case 1: /* IOSC */ mainfreq = stellaris_info->iosc_freq; stellaris_info->mck_desc = stellaris_info->iosc_desc; break; case 2: /* IOSC/4 */ mainfreq = stellaris_info->iosc_freq / 4; stellaris_info->mck_desc = stellaris_info->iosc_desc; break; case 3: /* lowspeed */ /* Sandstorm doesn't have this 30K +/- 30% osc */ mainfreq = 30000; stellaris_info->mck_desc = " (±30%)"; break; case 8: /* hibernation osc */ /* not all parts support hibernation */ mainfreq = 32768; break; default: /* NOTREACHED */ mainfreq = 0; break; } /* PLL is used if it's not bypassed; its output is 200 MHz * even when it runs at 400 MHz (adds divide-by-two stage). */ if (!bypass) mainfreq = 200000000; if (usesysdiv) stellaris_info->mck_freq = mainfreq/(1 + sysdiv); else stellaris_info->mck_freq = mainfreq; } /* Read device id register, main clock frequency register and fill in driver info structure */ static int stellaris_read_part_info(struct flash_bank *bank) { struct stellaris_flash_bank *stellaris_info = bank->driver_priv; struct target *target = bank->target; uint32_t did0, did1, ver, fam; int i; /* Read and parse chip identification register */ target_read_u32(target, SCB_BASE | DID0, &did0); target_read_u32(target, SCB_BASE | DID1, &did1); target_read_u32(target, SCB_BASE | DC0, &stellaris_info->dc0); target_read_u32(target, SCB_BASE | DC1, &stellaris_info->dc1); LOG_DEBUG("did0 0x%" PRIx32 ", did1 0x%" PRIx32 ", dc0 0x%" PRIx32 ", dc1 0x%" PRIx32 "", did0, did1, stellaris_info->dc0, stellaris_info->dc1); ver = DID0_VER(did0); if ((ver != 0) && (ver != 1)) { LOG_WARNING("Unknown did0 version, cannot identify target"); return ERROR_FLASH_OPERATION_FAILED; } if (did1 == 0) { LOG_WARNING("Cannot identify target as a Stellaris"); return ERROR_FLASH_OPERATION_FAILED; } ver = did1 >> 28; fam = (did1 >> 24) & 0xF; if (((ver != 0) && (ver != 1)) || (fam != 0)) { LOG_WARNING("Unknown did1 version/family."); return ERROR_FLASH_OPERATION_FAILED; } /* For Sandstorm, Fury, DustDevil: current data sheets say IOSC * is 12 MHz, but some older parts have 15 MHz. A few data sheets * even give _both_ numbers! We'll use current numbers; IOSC is * always approximate. * * For Tempest: IOSC is calibrated, 16 MHz * For Blizzard: IOSC is calibrated, 16 MHz * For Firestorm: IOSC is calibrated, 16 MHz */ stellaris_info->iosc_freq = 12000000; stellaris_info->iosc_desc = " (±30%)"; stellaris_info->xtal_mask = 0x0f; /* get device class */ if (DID0_VER(did0) > 0) { stellaris_info->target_class = (did0 >> 16) & 0xFF; } else { /* Sandstorm class */ stellaris_info->target_class = 0; } switch (stellaris_info->target_class) { case 0: /* Sandstorm */ /* * Current (2009-August) parts seem to be rev C2 and use 12 MHz. * Parts before rev C0 used 15 MHz; some C0 parts use 15 MHz * (LM3S618), but some other C0 parts are 12 MHz (LM3S811). */ if (((did0 >> 8) & 0xff) < 2) { stellaris_info->iosc_freq = 15000000; stellaris_info->iosc_desc = " (±50%)"; } break; case 1: /* Fury */ break; case 4: /* Tempest */ case 5: /* Blizzard */ case 6: /* Firestorm */ case 0xa: /* Snowflake */ stellaris_info->iosc_freq = 16000000; /* +/- 1% */ stellaris_info->iosc_desc = " (±1%)"; /* FALL THROUGH */ case 3: /* DustDevil */ stellaris_info->xtal_mask = 0x1f; break; default: LOG_WARNING("Unknown did0 class"); } for (i = 0; stellaris_parts[i].partno; i++) { if ((stellaris_parts[i].partno == ((did1 >> 16) & 0xFF)) && (stellaris_parts[i].class == stellaris_info->target_class)) break; } stellaris_info->target_name = stellaris_parts[i].partname; stellaris_info->did0 = did0; stellaris_info->did1 = did1; if (stellaris_info->target_class == 5) { /* Blizzard */ target_read_u32(target, FLASH_FSIZE, &stellaris_info->fsize); target_read_u32(target, FLASH_SSIZE, &stellaris_info->ssize); stellaris_info->num_pages = 2 * (1 + (stellaris_info->fsize & 0xFFFF)); stellaris_info->sramsiz = (1 + (stellaris_info->ssize & 0xFFFF)) / 4; stellaris_info->pagesize = 1024; } else if (stellaris_info->target_class == 0xa) { /* Snowflake */ target_read_u32(target, FLASH_FSIZE, &stellaris_info->fsize); target_read_u32(target, FLASH_SSIZE, &stellaris_info->ssize); stellaris_info->pagesize = (1 << ((stellaris_info->fsize >> 16) & 7)) * 1024; stellaris_info->num_pages = 2048 * (1 + (stellaris_info->fsize & 0xFFFF)) / stellaris_info->pagesize; stellaris_info->sramsiz = (1 + (stellaris_info->ssize & 0xFFFF)) / 4; } else { stellaris_info->num_pages = 2 * (1 + (stellaris_info->dc0 & 0xFFFF)); stellaris_info->sramsiz = (1 + ((stellaris_info->dc0 >> 16) & 0xFFFF)) / 4; stellaris_info->pagesize = 1024; } /* REVISIT for at least Tempest parts, read NVMSTAT.FWB too. * That exposes a 32-word Flash Write Buffer ... enabling * writes of more than one word at a time. */ return ERROR_OK; } /*************************************************************************** * flash operations * ***************************************************************************/ static int stellaris_protect_check(struct flash_bank *bank) { struct stellaris_flash_bank *stellaris = bank->driver_priv; struct target *target = bank->target; uint32_t flash_sizek = stellaris->pagesize / 1024 * stellaris->num_pages; uint32_t fmppe_addr; int status = ERROR_OK; if (stellaris->did1 == 0) return ERROR_FLASH_BANK_NOT_PROBED; for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = -1; /* Read each Flash Memory Protection Program Enable (FMPPE) register * to report any pages that we can't write. Ignore the Read Enable * register (FMPRE). */ if (stellaris->target_class >= 0x0a || flash_sizek > 64) fmppe_addr = SCB_BASE | FMPPE0; else fmppe_addr = SCB_BASE | FMPPE; unsigned int page = 0, lockbitnum, lockbitcnt = flash_sizek / 2; unsigned int bits_per_page = stellaris->pagesize / 2048; /* Every lock bit always corresponds to a 2k region */ for (lockbitnum = 0; lockbitnum < lockbitcnt; lockbitnum += 32) { uint32_t fmppe; target_read_u32(target, fmppe_addr, &fmppe); for (unsigned int i = 0; i < 32 && lockbitnum + i < lockbitcnt; i++) { bool protect = !(fmppe & (1 << i)); if (bits_per_page) { bank->sectors[page++].is_protected = protect; i += bits_per_page - 1; } else { /* 1024k pages, every lockbit covers 2 pages */ bank->sectors[page++].is_protected = protect; bank->sectors[page++].is_protected = protect; } } fmppe_addr += 4; } return status; } static int stellaris_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { uint32_t flash_fmc, flash_cris; struct stellaris_flash_bank *stellaris_info = bank->driver_priv; struct target *target = bank->target; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (stellaris_info->did1 == 0) return ERROR_FLASH_BANK_NOT_PROBED; if ((last < first) || (last >= stellaris_info->num_pages)) return ERROR_FLASH_SECTOR_INVALID; if ((first == 0) && (last == (stellaris_info->num_pages - 1))) return stellaris_mass_erase(bank); /* Refresh flash controller timing */ stellaris_read_clock_info(bank); stellaris_set_flash_timing(bank); /* Clear and disable flash programming interrupts */ target_write_u32(target, FLASH_CIM, 0); target_write_u32(target, FLASH_MISC, PMISC | AMISC); /* REVISIT this clobbers state set by any halted firmware ... * it might want to process those IRQs. */ for (unsigned int banknr = first; banknr <= last; banknr++) { /* Address is first word in page */ target_write_u32(target, FLASH_FMA, banknr * stellaris_info->pagesize); /* Write erase command */ target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_ERASE); /* Wait until erase complete */ do { target_read_u32(target, FLASH_FMC, &flash_fmc); } while (flash_fmc & FMC_ERASE); /* Check access violations */ target_read_u32(target, FLASH_CRIS, &flash_cris); if (flash_cris & (AMASK)) { LOG_WARNING("Error erasing flash page %i, flash_cris 0x%" PRIx32 "", banknr, flash_cris); target_write_u32(target, FLASH_CRIS, 0); return ERROR_FLASH_OPERATION_FAILED; } } return ERROR_OK; } static int stellaris_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct stellaris_flash_bank *stellaris = bank->driver_priv; struct target *target = bank->target; uint32_t flash_fmc, flash_cris; unsigned int bits_per_page = stellaris->pagesize / 2048; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!set) { LOG_ERROR("Hardware doesn't support page-level unprotect. " "Try the 'recover' command."); return ERROR_COMMAND_SYNTAX_ERROR; } if (stellaris->did1 == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (stellaris->target_class == 0x03 && !((stellaris->did0 >> 8) & 0xFF) && !((stellaris->did0) & 0xFF)) { LOG_ERROR("DustDevil A0 parts can't be unprotected, see errata; refusing to proceed"); return ERROR_FLASH_OPERATION_FAILED; } if (!bits_per_page && (first % 2 || !(last % 2))) { LOG_ERROR("Can't protect unaligned pages"); return ERROR_FLASH_SECTOR_INVALID; } /* Refresh flash controller timing */ stellaris_read_clock_info(bank); stellaris_set_flash_timing(bank); /* Clear and disable flash programming interrupts */ target_write_u32(target, FLASH_CIM, 0); target_write_u32(target, FLASH_MISC, PMISC | AMISC); uint32_t flash_sizek = stellaris->pagesize / 1024 * stellaris->num_pages; uint32_t fmppe_addr; if (stellaris->target_class >= 0x0a || flash_sizek > 64) fmppe_addr = SCB_BASE | FMPPE0; else fmppe_addr = SCB_BASE | FMPPE; unsigned int page = 0; unsigned int lockbitnum, lockbitcnt = flash_sizek / 2; /* Every lock bit always corresponds to a 2k region */ for (lockbitnum = 0; lockbitnum < lockbitcnt; lockbitnum += 32) { uint32_t fmppe; target_read_u32(target, fmppe_addr, &fmppe); for (unsigned int i = 0; i < 32 && lockbitnum + i < lockbitcnt; i++) { if (page >= first && page <= last) fmppe &= ~(1 << i); if (bits_per_page) { if (!((i + 1) % bits_per_page)) page++; } else { /* 1024k pages, every lockbit covers 2 pages */ page += 2; } } target_write_u32(target, fmppe_addr, fmppe); /* Commit FMPPE* */ target_write_u32(target, FLASH_FMA, 1 + lockbitnum / 16); /* Write commit command */ target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); /* Wait until commit complete */ do { target_read_u32(target, FLASH_FMC, &flash_fmc); } while (flash_fmc & FMC_COMT); /* Check access violations */ target_read_u32(target, FLASH_CRIS, &flash_cris); if (flash_cris & (AMASK)) { LOG_WARNING("Error setting flash page protection, flash_cris 0x%" PRIx32 "", flash_cris); target_write_u32(target, FLASH_CRIS, 0); return ERROR_FLASH_OPERATION_FAILED; } fmppe_addr += 4; } return ERROR_OK; } /* see contrib/loaders/flash/stellaris.s for src */ static const uint8_t stellaris_write_code[] = { /* write: */ 0xDF, 0xF8, 0x40, 0x40, /* ldr r4, pFLASH_CTRL_BASE */ 0xDF, 0xF8, 0x40, 0x50, /* ldr r5, FLASHWRITECMD */ /* wait_fifo: */ 0xD0, 0xF8, 0x00, 0x80, /* ldr r8, [r0, #0] */ 0xB8, 0xF1, 0x00, 0x0F, /* cmp r8, #0 */ 0x17, 0xD0, /* beq exit */ 0x47, 0x68, /* ldr r7, [r0, #4] */ 0x47, 0x45, /* cmp r7, r8 */ 0xF7, 0xD0, /* beq wait_fifo */ /* mainloop: */ 0x22, 0x60, /* str r2, [r4, #0] */ 0x02, 0xF1, 0x04, 0x02, /* add r2, r2, #4 */ 0x57, 0xF8, 0x04, 0x8B, /* ldr r8, [r7], #4 */ 0xC4, 0xF8, 0x04, 0x80, /* str r8, [r4, #4] */ 0xA5, 0x60, /* str r5, [r4, #8] */ /* busy: */ 0xD4, 0xF8, 0x08, 0x80, /* ldr r8, [r4, #8] */ 0x18, 0xF0, 0x01, 0x0F, /* tst r8, #1 */ 0xFA, 0xD1, /* bne busy */ 0x8F, 0x42, /* cmp r7, r1 */ 0x28, 0xBF, /* it cs */ 0x00, 0xF1, 0x08, 0x07, /* addcs r7, r0, #8 */ 0x47, 0x60, /* str r7, [r0, #4] */ 0x01, 0x3B, /* subs r3, r3, #1 */ 0x03, 0xB1, /* cbz r3, exit */ 0xE2, 0xE7, /* b wait_fifo */ /* exit: */ 0x00, 0xBE, /* bkpt #0 */ /* pFLASH_CTRL_BASE: */ 0x00, 0xD0, 0x0F, 0x40, /* .word 0x400FD000 */ /* FLASHWRITECMD: */ 0x01, 0x00, 0x42, 0xA4 /* .word 0xA4420001 */ }; static int stellaris_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t wcount) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *source; struct working_area *write_algorithm; uint32_t address = bank->base + offset; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* power of two, and multiple of word size */ static const unsigned buf_min = 128; /* for small buffers it's faster not to download an algorithm */ if (wcount * 4 < buf_min) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "", bank, buffer, offset, wcount); /* flash write code */ if (target_alloc_working_area(target, sizeof(stellaris_write_code), &write_algorithm) != ERROR_OK) { LOG_DEBUG("no working area for block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* plus a buffer big enough for this data */ if (wcount * 4 < buffer_size) buffer_size = wcount * 4; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= buf_min) { target_free_working_area(target, write_algorithm); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } LOG_DEBUG("retry target_alloc_working_area(%s, size=%u)", target_name(target), (unsigned) buffer_size); } target_write_buffer(target, write_algorithm->address, sizeof(stellaris_write_code), stellaris_write_code); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[3].value, 0, 32, wcount); retval = target_run_flash_async_algorithm(target, buffer, wcount, 4, 0, NULL, 4, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) LOG_ERROR("error %d executing stellaris flash write algorithm", retval); target_free_working_area(target, write_algorithm); target_free_working_area(target, source); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; } static int stellaris_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct stellaris_flash_bank *stellaris_info = bank->driver_priv; struct target *target = bank->target; uint32_t address = offset; uint32_t flash_cris, flash_fmc; uint32_t words_remaining = (count / 4); uint32_t bytes_remaining = (count & 0x00000003); uint32_t bytes_written = 0; int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32 "", bank, buffer, offset, count); if (stellaris_info->did1 == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (offset & 0x3) { LOG_WARNING("offset size must be word aligned"); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; /* Refresh flash controller timing */ stellaris_read_clock_info(bank); stellaris_set_flash_timing(bank); /* Clear and disable flash programming interrupts */ target_write_u32(target, FLASH_CIM, 0); target_write_u32(target, FLASH_MISC, PMISC | AMISC); /* REVISIT this clobbers state set by any halted firmware ... * it might want to process those IRQs. */ /* multiple words to be programmed? */ if (words_remaining > 0) { /* try using a block write */ retval = stellaris_write_block(bank, buffer, offset, words_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { LOG_DEBUG("writing flash word-at-a-time"); } else if (retval == ERROR_FLASH_OPERATION_FAILED) { /* if an error occurred, we examine the reason, and quit */ target_read_u32(target, FLASH_CRIS, &flash_cris); LOG_ERROR("flash writing failed with CRIS: 0x%" PRIx32 "", flash_cris); return ERROR_FLASH_OPERATION_FAILED; } } else { buffer += words_remaining * 4; address += words_remaining * 4; words_remaining = 0; } } while (words_remaining > 0) { if (!(address & 0xff)) LOG_DEBUG("0x%" PRIx32 "", address); /* Program one word */ target_write_u32(target, FLASH_FMA, address); target_write_buffer(target, FLASH_FMD, 4, buffer); target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE); /* LOG_DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE); */ /* Wait until write complete */ do { target_read_u32(target, FLASH_FMC, &flash_fmc); } while (flash_fmc & FMC_WRITE); buffer += 4; address += 4; words_remaining--; } if (bytes_remaining) { uint8_t last_word[4] = {0xff, 0xff, 0xff, 0xff}; /* copy the last remaining bytes into the write buffer */ memcpy(last_word, buffer+bytes_written, bytes_remaining); if (!(address & 0xff)) LOG_DEBUG("0x%" PRIx32 "", address); /* Program one word */ target_write_u32(target, FLASH_FMA, address); target_write_buffer(target, FLASH_FMD, 4, last_word); target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE); /* LOG_DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE); */ /* Wait until write complete */ do { target_read_u32(target, FLASH_FMC, &flash_fmc); } while (flash_fmc & FMC_WRITE); } /* Check access violations */ target_read_u32(target, FLASH_CRIS, &flash_cris); if (flash_cris & (AMASK)) { LOG_DEBUG("flash_cris 0x%" PRIx32 "", flash_cris); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int stellaris_probe(struct flash_bank *bank) { struct stellaris_flash_bank *stellaris_info = bank->driver_priv; int retval; /* If this is a stellaris chip, it has flash; probe() is just * to figure out how much is present. Only do it once. */ if (stellaris_info->did1 != 0) return ERROR_OK; /* stellaris_read_part_info() already handled error checking and * reporting. Note that it doesn't write, so we don't care about * whether the target is halted or not. */ retval = stellaris_read_part_info(bank); if (retval != ERROR_OK) return retval; free(bank->sectors); /* provide this for the benefit of the NOR flash framework */ bank->size = stellaris_info->num_pages * stellaris_info->pagesize; bank->num_sectors = stellaris_info->num_pages; bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = i * stellaris_info->pagesize; bank->sectors[i].size = stellaris_info->pagesize; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } return retval; } static int stellaris_mass_erase(struct flash_bank *bank) { struct target *target = NULL; struct stellaris_flash_bank *stellaris_info = NULL; uint32_t flash_fmc; stellaris_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (stellaris_info->did1 == 0) return ERROR_FLASH_BANK_NOT_PROBED; /* Refresh flash controller timing */ stellaris_read_clock_info(bank); stellaris_set_flash_timing(bank); /* Clear and disable flash programming interrupts */ target_write_u32(target, FLASH_CIM, 0); target_write_u32(target, FLASH_MISC, PMISC | AMISC); /* REVISIT this clobbers state set by any halted firmware ... * it might want to process those IRQs. */ target_write_u32(target, FLASH_FMA, 0); target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE); /* Wait until erase complete */ do { target_read_u32(target, FLASH_FMC, &flash_fmc); } while (flash_fmc & FMC_MERASE); /* if device has > 128k, then second erase cycle is needed * this is only valid for older devices, but will not hurt */ if (stellaris_info->num_pages * stellaris_info->pagesize > 0x20000) { target_write_u32(target, FLASH_FMA, 0x20000); target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE); /* Wait until erase complete */ do { target_read_u32(target, FLASH_FMC, &flash_fmc); } while (flash_fmc & FMC_MERASE); } return ERROR_OK; } COMMAND_HANDLER(stellaris_handle_mass_erase_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; if (stellaris_mass_erase(bank) == ERROR_OK) command_print(CMD, "stellaris mass erase complete"); else command_print(CMD, "stellaris mass erase failed"); return ERROR_OK; } /** * Perform the Stellaris "Recovering a 'Locked' Device procedure. * This performs a mass erase and then restores all nonvolatile registers * (including USER_* registers and flash lock bits) to their defaults. * Accordingly, flash can be reprogrammed, and JTAG can be used. * * NOTE that DustDevil parts (at least rev A0 silicon) have errata which * can affect this operation if flash protection has been enabled. */ COMMAND_HANDLER(stellaris_handle_recover_command) { struct flash_bank *bank; struct arm *arm; int retval; if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; bank = get_flash_bank_by_num_noprobe(0); if (!bank) return ERROR_FAIL; /* REVISIT ... it may be worth sanity checking that the AP is * inactive before we start. ARM documents that switching a DP's * mode while it's active can cause fault modes that need a power * cycle to recover. */ Jim_Eval_Named(CMD_CTX->interp, "catch { hla_command \"debug unlock\" }", NULL, 0); if (!strcmp(Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL), "0")) { retval = ERROR_OK; goto user_action; } /* assert SRST */ if (!(jtag_get_reset_config() & RESET_HAS_SRST)) { LOG_ERROR("Can't recover Stellaris flash without SRST"); return ERROR_FAIL; } adapter_assert_reset(); arm = target_to_arm(bank->target); for (int i = 0; i < 5; i++) { retval = dap_to_swd(arm->dap); if (retval != ERROR_OK) goto done; retval = dap_to_jtag(arm->dap); if (retval != ERROR_OK) goto done; } /* de-assert SRST */ adapter_deassert_reset(); retval = jtag_execute_queue(); /* wait 400+ msec ... OK, "1+ second" is simpler */ usleep(1000); user_action: /* USER INTERVENTION required for the power cycle * Restarting OpenOCD is likely needed because of mode switching. */ LOG_INFO("USER ACTION: " "power cycle Stellaris chip, then restart OpenOCD."); done: return retval; } static const struct command_registration stellaris_exec_command_handlers[] = { { .name = "mass_erase", .usage = "<bank>", .handler = stellaris_handle_mass_erase_command, .mode = COMMAND_EXEC, .help = "erase entire device", }, { .name = "recover", .handler = stellaris_handle_recover_command, .mode = COMMAND_EXEC, .usage = "", .help = "recover (and erase) locked device", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration stellaris_command_handlers[] = { { .name = "stellaris", .mode = COMMAND_EXEC, .help = "Stellaris flash command group", .usage = "", .chain = stellaris_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver stellaris_flash = { .name = "stellaris", .commands = stellaris_command_handlers, .flash_bank_command = stellaris_flash_bank_command, .erase = stellaris_erase, .protect = stellaris_protect, .write = stellaris_write, .read = default_flash_read, .probe = stellaris_probe, .auto_probe = stellaris_probe, .erase_check = default_flash_blank_check, .protect_check = stellaris_protect_check, .info = get_stellaris_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/stm32f1x.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <string.h> #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/cortex_m.h> /* stm32x register locations */ #define FLASH_REG_BASE_B0 0x40022000 #define FLASH_REG_BASE_B1 0x40022040 #define STM32_FLASH_ACR 0x00 #define STM32_FLASH_KEYR 0x04 #define STM32_FLASH_OPTKEYR 0x08 #define STM32_FLASH_SR 0x0C #define STM32_FLASH_CR 0x10 #define STM32_FLASH_AR 0x14 #define STM32_FLASH_OBR 0x1C #define STM32_FLASH_WRPR 0x20 /* TODO: Check if code using these really should be hard coded to bank 0. * There are valid cases, on dual flash devices the protection of the * second bank is done on the bank0 reg's. */ #define STM32_FLASH_ACR_B0 0x40022000 #define STM32_FLASH_KEYR_B0 0x40022004 #define STM32_FLASH_OPTKEYR_B0 0x40022008 #define STM32_FLASH_SR_B0 0x4002200C #define STM32_FLASH_CR_B0 0x40022010 #define STM32_FLASH_AR_B0 0x40022014 #define STM32_FLASH_OBR_B0 0x4002201C #define STM32_FLASH_WRPR_B0 0x40022020 /* option byte location */ #define STM32_OB_RDP 0x1FFFF800 #define STM32_OB_USER 0x1FFFF802 #define STM32_OB_DATA0 0x1FFFF804 #define STM32_OB_DATA1 0x1FFFF806 #define STM32_OB_WRP0 0x1FFFF808 #define STM32_OB_WRP1 0x1FFFF80A #define STM32_OB_WRP2 0x1FFFF80C #define STM32_OB_WRP3 0x1FFFF80E /* FLASH_CR register bits */ #define FLASH_PG (1 << 0) #define FLASH_PER (1 << 1) #define FLASH_MER (1 << 2) #define FLASH_OPTPG (1 << 4) #define FLASH_OPTER (1 << 5) #define FLASH_STRT (1 << 6) #define FLASH_LOCK (1 << 7) #define FLASH_OPTWRE (1 << 9) #define FLASH_OBL_LAUNCH (1 << 13) /* except stm32f1x series */ /* FLASH_SR register bits */ #define FLASH_BSY (1 << 0) #define FLASH_PGERR (1 << 2) #define FLASH_WRPRTERR (1 << 4) #define FLASH_EOP (1 << 5) /* STM32_FLASH_OBR bit definitions (reading) */ #define OPT_ERROR 0 #define OPT_READOUT 1 #define OPT_RDWDGSW 2 #define OPT_RDRSTSTOP 3 #define OPT_RDRSTSTDBY 4 #define OPT_BFB2 5 /* dual flash bank only */ /* register unlock keys */ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB /* timeout values */ #define FLASH_WRITE_TIMEOUT 10 #define FLASH_ERASE_TIMEOUT 100 struct stm32x_options { uint8_t rdp; uint8_t user; uint16_t data; uint32_t protection; }; struct stm32x_flash_bank { struct stm32x_options option_bytes; int ppage_size; bool probed; bool has_dual_banks; /* used to access dual flash bank stm32xl */ bool can_load_options; uint32_t register_base; uint8_t default_rdp; int user_data_offset; int option_offset; uint32_t user_bank_size; }; static int stm32x_mass_erase(struct flash_bank *bank); static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t address, uint32_t hwords_count); /* flash bank stm32x <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) { struct stm32x_flash_bank *stm32x_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; stm32x_info = malloc(sizeof(struct stm32x_flash_bank)); bank->driver_priv = stm32x_info; stm32x_info->probed = false; stm32x_info->has_dual_banks = false; stm32x_info->can_load_options = false; stm32x_info->register_base = FLASH_REG_BASE_B0; stm32x_info->user_bank_size = bank->size; /* The flash write must be aligned to a halfword boundary */ bank->write_start_alignment = bank->write_end_alignment = 2; return ERROR_OK; } static inline int stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; return reg + stm32x_info->register_base; } static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status) { struct target *target = bank->target; return target_read_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), status); } static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) { struct target *target = bank->target; uint32_t status; int retval = ERROR_OK; /* wait for busy to clear */ for (;;) { retval = stm32x_get_flash_status(bank, &status); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%" PRIx32 "", status); if ((status & FLASH_BSY) == 0) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FLASH_BUSY; } alive_sleep(1); } if (status & FLASH_WRPRTERR) { LOG_ERROR("stm32x device protected"); retval = ERROR_FLASH_PROTECTED; } if (status & FLASH_PGERR) { LOG_ERROR("stm32x device programming failed / flash not erased"); retval = ERROR_FLASH_OPERATION_FAILED; } /* Clear but report errors */ if (status & (FLASH_WRPRTERR | FLASH_PGERR)) { /* If this operation fails, we ignore it and report the original * retval */ target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), FLASH_WRPRTERR | FLASH_PGERR); } return retval; } static int stm32x_check_operation_supported(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; /* if we have a dual flash bank device then * we need to perform option byte stuff on bank0 only */ if (stm32x_info->register_base != FLASH_REG_BASE_B0) { LOG_ERROR("Option byte operations must use bank 0"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int stm32x_read_options(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; uint32_t option_bytes; int retval; /* read user and read protection option bytes, user data option bytes */ retval = target_read_u32(target, STM32_FLASH_OBR_B0, &option_bytes); if (retval != ERROR_OK) return retval; stm32x_info->option_bytes.rdp = (option_bytes & (1 << OPT_READOUT)) ? 0 : stm32x_info->default_rdp; stm32x_info->option_bytes.user = (option_bytes >> stm32x_info->option_offset >> 2) & 0xff; stm32x_info->option_bytes.data = (option_bytes >> stm32x_info->user_data_offset) & 0xffff; /* read write protection option bytes */ retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &stm32x_info->option_bytes.protection); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32x_erase_options(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; /* read current options */ stm32x_read_options(bank); /* unlock flash registers */ int retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY2); if (retval != ERROR_OK) goto flash_lock; /* unlock option flash registers */ retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY1); if (retval != ERROR_OK) goto flash_lock; retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY2); if (retval != ERROR_OK) goto flash_lock; /* erase option bytes */ retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTER | FLASH_OPTWRE); if (retval != ERROR_OK) goto flash_lock; retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTER | FLASH_STRT | FLASH_OPTWRE); if (retval != ERROR_OK) goto flash_lock; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) goto flash_lock; /* clear read protection option byte * this will also force a device unlock if set */ stm32x_info->option_bytes.rdp = stm32x_info->default_rdp; return ERROR_OK; flash_lock: target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); return retval; } static int stm32x_write_options(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = NULL; struct target *target = bank->target; stm32x_info = bank->driver_priv; /* unlock flash registers */ int retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY2); if (retval != ERROR_OK) goto flash_lock; /* unlock option flash registers */ retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY1); if (retval != ERROR_OK) goto flash_lock; retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY2); if (retval != ERROR_OK) goto flash_lock; /* program option bytes */ retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTPG | FLASH_OPTWRE); if (retval != ERROR_OK) goto flash_lock; uint8_t opt_bytes[16]; target_buffer_set_u16(target, opt_bytes, stm32x_info->option_bytes.rdp); target_buffer_set_u16(target, opt_bytes + 2, stm32x_info->option_bytes.user); target_buffer_set_u16(target, opt_bytes + 4, stm32x_info->option_bytes.data & 0xff); target_buffer_set_u16(target, opt_bytes + 6, (stm32x_info->option_bytes.data >> 8) & 0xff); target_buffer_set_u16(target, opt_bytes + 8, stm32x_info->option_bytes.protection & 0xff); target_buffer_set_u16(target, opt_bytes + 10, (stm32x_info->option_bytes.protection >> 8) & 0xff); target_buffer_set_u16(target, opt_bytes + 12, (stm32x_info->option_bytes.protection >> 16) & 0xff); target_buffer_set_u16(target, opt_bytes + 14, (stm32x_info->option_bytes.protection >> 24) & 0xff); /* Block write is preferred in favour of operation with ancient ST-Link * firmwares without 16-bit memory access. See * 480: flash: stm32f1x: write option bytes using the loader * https://review.openocd.org/c/openocd/+/480 */ retval = stm32x_write_block(bank, opt_bytes, STM32_OB_RDP, sizeof(opt_bytes) / 2); flash_lock: { int retval2 = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); if (retval == ERROR_OK) retval = retval2; } return retval; } static int stm32x_protect_check(struct flash_bank *bank) { struct target *target = bank->target; uint32_t protection; int retval = stm32x_check_operation_supported(bank); if (retval != ERROR_OK) return retval; /* medium density - each bit refers to a 4 sector protection block * high density - each bit refers to a 2 sector protection block * bit 31 refers to all remaining sectors in a bank */ retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &protection); if (retval != ERROR_OK) return retval; for (unsigned int i = 0; i < bank->num_prot_blocks; i++) bank->prot_blocks[i].is_protected = (protection & (1 << i)) ? 0 : 1; return ERROR_OK; } static int stm32x_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first == 0) && (last == (bank->num_sectors - 1))) return stm32x_mass_erase(bank); /* unlock flash registers */ int retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) goto flash_lock; for (unsigned int i = first; i <= last; i++) { retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER); if (retval != ERROR_OK) goto flash_lock; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_AR), bank->base + bank->sectors[i].offset); if (retval != ERROR_OK) goto flash_lock; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER | FLASH_STRT); if (retval != ERROR_OK) goto flash_lock; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) goto flash_lock; } flash_lock: { int retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval == ERROR_OK) retval = retval2; } return retval; } static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct target *target = bank->target; struct stm32x_flash_bank *stm32x_info = bank->driver_priv; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } int retval = stm32x_check_operation_supported(bank); if (retval != ERROR_OK) return retval; retval = stm32x_erase_options(bank); if (retval != ERROR_OK) { LOG_ERROR("stm32x failed to erase options"); return retval; } for (unsigned int i = first; i <= last; i++) { if (set) stm32x_info->option_bytes.protection &= ~(1 << i); else stm32x_info->option_bytes.protection |= (1 << i); } return stm32x_write_options(bank); } static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buffer, uint32_t address, uint32_t hwords_count) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size; struct working_area *write_algorithm; struct working_area *source; struct armv7m_algorithm armv7m_info; int retval; static const uint8_t stm32x_flash_write_code[] = { #include "../../../contrib/loaders/flash/stm32/stm32f1x.inc" }; /* flash write code */ if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } /* memory buffer */ buffer_size = target_get_working_area_avail(target); buffer_size = MIN(hwords_count * 2 + 8, MAX(buffer_size, 256)); /* Normally we allocate all available working area. * MIN shrinks buffer_size if the size of the written block is smaller. * MAX prevents using async algo if the available working area is smaller * than 256, the following allocation fails with * ERROR_TARGET_RESOURCE_NOT_AVAILABLE and slow flashing takes place. */ retval = target_alloc_working_area(target, buffer_size, &source); /* Allocated size is always 32-bit word aligned */ if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); /* target_alloc_working_area() may return ERROR_FAIL if area backup fails: * convert any error to ERROR_TARGET_RESOURCE_NOT_AVAILABLE */ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } struct reg_param reg_params[5]; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ buf_set_u32(reg_params[0].value, 0, 32, stm32x_info->register_base); buf_set_u32(reg_params[1].value, 0, 32, hwords_count); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[4].value, 0, 32, address); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; retval = target_run_flash_async_algorithm(target, buffer, hwords_count, 2, 0, NULL, ARRAY_SIZE(reg_params), reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { /* Actually we just need to check for programming errors * stm32x_wait_status_busy also reports error and clears status bits. * * Target algo returns flash status in r0 only if properly finished. * It is safer to re-read status register. */ int retval2 = stm32x_wait_status_busy(bank, 5); if (retval2 != ERROR_OK) retval = retval2; LOG_ERROR("flash write failed just before address 0x%"PRIx32, buf_get_u32(reg_params[4].value, 0, 32)); } for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) destroy_reg_param(®_params[i]); target_free_working_area(target, source); target_free_working_area(target, write_algorithm); return retval; } static int stm32x_write_block_riscv(struct flash_bank *bank, const uint8_t *buffer, uint32_t address, uint32_t hwords_count) { struct target *target = bank->target; uint32_t buffer_size; struct working_area *write_algorithm; struct working_area *source; static const uint8_t gd32vf103_flash_write_code[] = { #include "../../../contrib/loaders/flash/gd32vf103/gd32vf103.inc" }; /* flash write code */ if (target_alloc_working_area(target, sizeof(gd32vf103_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } int retval = target_write_buffer(target, write_algorithm->address, sizeof(gd32vf103_flash_write_code), gd32vf103_flash_write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } /* memory buffer */ buffer_size = target_get_working_area_avail(target); buffer_size = MIN(hwords_count * 2, MAX(buffer_size, 256)); retval = target_alloc_working_area(target, buffer_size, &source); /* Allocated size is always word aligned */ if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); /* target_alloc_working_area() may return ERROR_FAIL if area backup fails: * convert any error to ERROR_TARGET_RESOURCE_NOT_AVAILABLE */ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } struct reg_param reg_params[4]; init_reg_param(®_params[0], "a0", 32, PARAM_OUT); /* poiner to FLASH_SR */ init_reg_param(®_params[1], "a1", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_params[2], "a2", 32, PARAM_OUT); /* buffer start */ init_reg_param(®_params[3], "a3", 32, PARAM_IN_OUT); /* target address */ while (hwords_count > 0) { uint32_t thisrun_hwords = source->size / 2; /* Limit to the amount of data we actually want to write */ if (thisrun_hwords > hwords_count) thisrun_hwords = hwords_count; /* Write data to buffer */ retval = target_write_buffer(target, source->address, thisrun_hwords * 2, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, stm32x_get_flash_reg(bank, STM32_FLASH_SR)); buf_set_u32(reg_params[1].value, 0, 32, thisrun_hwords); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, address); retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, write_algorithm->address, write_algorithm->address + sizeof(gd32vf103_flash_write_code) - 4, 10000, NULL); if (retval != ERROR_OK) { LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", write_algorithm->address, retval); break; } /* Actually we just need to check for programming errors * stm32x_wait_status_busy also reports error and clears status bits */ retval = stm32x_wait_status_busy(bank, 5); if (retval != ERROR_OK) { LOG_ERROR("flash write failed at address 0x%"PRIx32, buf_get_u32(reg_params[3].value, 0, 32)); break; } /* Update counters */ buffer += thisrun_hwords * 2; address += thisrun_hwords * 2; hwords_count -= thisrun_hwords; } for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) destroy_reg_param(®_params[i]); target_free_working_area(target, source); target_free_working_area(target, write_algorithm); return retval; } /** Writes a block to flash either using target algorithm * or use fallback, host controlled halfword-by-halfword access. * Flash controller must be unlocked before this call. */ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t address, uint32_t hwords_count) { struct target *target = bank->target; /* The flash write must be aligned to a halfword boundary. * The flash infrastructure ensures it, do just a security check */ assert(address % 2 == 0); int retval; struct arm *arm = target_to_arm(target); if (is_arm(arm)) { /* try using a block write - on ARM architecture or... */ retval = stm32x_write_block_async(bank, buffer, address, hwords_count); } else { /* ... RISC-V architecture */ retval = stm32x_write_block_riscv(bank, buffer, address, hwords_count); } if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single halfword accesses */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); while (hwords_count > 0) { retval = target_write_memory(target, address, 2, 1, buffer); if (retval != ERROR_OK) return retval; retval = stm32x_wait_status_busy(bank, 5); if (retval != ERROR_OK) return retval; hwords_count--; buffer += 2; address += 2; } } return retval; } static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* The flash write must be aligned to a halfword boundary. * The flash infrastructure ensures it, do just a security check */ assert(offset % 2 == 0); assert(count % 2 == 0); int retval, retval2; /* unlock flash registers */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) goto reset_pg_and_lock; /* enable flash programming */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG); if (retval != ERROR_OK) goto reset_pg_and_lock; /* write to flash */ retval = stm32x_write_block(bank, buffer, bank->base + offset, count / 2); reset_pg_and_lock: retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval == ERROR_OK) retval = retval2; return retval; } struct stm32x_property_addr { uint32_t device_id; uint32_t flash_size; }; static int stm32x_get_property_addr(struct target *target, struct stm32x_property_addr *addr) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_TARGET_NOT_EXAMINED; } switch (cortex_m_get_partno_safe(target)) { case CORTEX_M0_PARTNO: /* STM32F0x devices */ addr->device_id = 0x40015800; addr->flash_size = 0x1FFFF7CC; return ERROR_OK; case CORTEX_M3_PARTNO: /* STM32F1x devices */ addr->device_id = 0xE0042000; addr->flash_size = 0x1FFFF7E0; return ERROR_OK; case CORTEX_M4_PARTNO: /* STM32F3x devices */ addr->device_id = 0xE0042000; addr->flash_size = 0x1FFFF7CC; return ERROR_OK; case CORTEX_M23_PARTNO: /* GD32E23x devices */ addr->device_id = 0x40015800; addr->flash_size = 0x1FFFF7E0; return ERROR_OK; case CORTEX_M_PARTNO_INVALID: /* Check for GD32VF103 with RISC-V CPU */ if (strcmp(target_type_name(target), "riscv") == 0 && target_address_bits(target) == 32) { /* There is nothing like arm common_magic in riscv_info_t * check text name of target and if target is 32-bit */ addr->device_id = 0xE0042000; addr->flash_size = 0x1FFFF7E0; return ERROR_OK; } /* fallthrough */ default: LOG_ERROR("Cannot identify target as a stm32x"); return ERROR_FAIL; } } static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) { struct target *target = bank->target; struct stm32x_property_addr addr; int retval = stm32x_get_property_addr(target, &addr); if (retval != ERROR_OK) return retval; return target_read_u32(target, addr.device_id, device_id); } static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb) { struct target *target = bank->target; struct stm32x_property_addr addr; int retval = stm32x_get_property_addr(target, &addr); if (retval != ERROR_OK) return retval; return target_read_u16(target, addr.flash_size, flash_size_in_kb); } static int stm32x_probe(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; uint16_t flash_size_in_kb; uint16_t max_flash_size_in_kb; uint32_t dbgmcu_idcode; int page_size; uint32_t base_address = 0x08000000; stm32x_info->probed = false; stm32x_info->register_base = FLASH_REG_BASE_B0; stm32x_info->user_data_offset = 10; stm32x_info->option_offset = 0; /* default factory read protection level 0 */ stm32x_info->default_rdp = 0xA5; /* read stm32 device id register */ int retval = stm32x_get_device_id(bank, &dbgmcu_idcode); if (retval != ERROR_OK) return retval; LOG_INFO("device id = 0x%08" PRIx32 "", dbgmcu_idcode); uint16_t device_id = dbgmcu_idcode & 0xfff; uint16_t rev_id = dbgmcu_idcode >> 16; /* set page size, protection granularity and max flash size depending on family */ switch (device_id) { case 0x440: /* stm32f05x */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 64; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; stm32x_info->default_rdp = 0xAA; stm32x_info->can_load_options = true; break; case 0x444: /* stm32f03x */ case 0x445: /* stm32f04x */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 32; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; stm32x_info->default_rdp = 0xAA; stm32x_info->can_load_options = true; break; case 0x448: /* stm32f07x */ page_size = 2048; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 128; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; stm32x_info->default_rdp = 0xAA; stm32x_info->can_load_options = true; break; case 0x442: /* stm32f09x */ page_size = 2048; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 256; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; stm32x_info->default_rdp = 0xAA; stm32x_info->can_load_options = true; break; case 0x410: /* stm32f1x medium-density */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 128; /* GigaDevice GD32F1x0 & GD32F3x0 & GD32E23x series devices share DEV_ID with STM32F101/2/3 medium-density line, however they use a REV_ID different from any STM32 device. The main difference is another offset of user option bits (like WDG_SW, nRST_STOP, nRST_STDBY) in option byte register (FLASH_OBR/FMC_OBSTAT 0x4002201C). This caused problems e.g. during flash block programming because of unexpected active hardware watchog. */ switch (rev_id) { case 0x1303: /* gd32f1x0 */ stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; max_flash_size_in_kb = 64; stm32x_info->can_load_options = true; break; case 0x1704: /* gd32f3x0 */ stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; stm32x_info->can_load_options = true; break; case 0x1906: /* gd32vf103 */ break; case 0x1909: /* gd32e23x */ stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; max_flash_size_in_kb = 64; stm32x_info->can_load_options = true; break; } break; case 0x412: /* stm32f1x low-density */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 32; break; case 0x414: /* stm32f1x high-density */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 512; break; case 0x418: /* stm32f1x connectivity */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 256; break; case 0x430: /* stm32f1 XL-density (dual flash banks) */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 1024; stm32x_info->has_dual_banks = true; break; case 0x420: /* stm32f100xx low- and medium-density value line */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 128; break; case 0x428: /* stm32f100xx high-density value line */ page_size = 2048; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 512; break; case 0x422: /* stm32f302/3xb/c */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 256; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; stm32x_info->default_rdp = 0xAA; stm32x_info->can_load_options = true; break; case 0x446: /* stm32f303xD/E */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 512; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; stm32x_info->default_rdp = 0xAA; stm32x_info->can_load_options = true; break; case 0x432: /* stm32f37x */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 256; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; stm32x_info->default_rdp = 0xAA; stm32x_info->can_load_options = true; break; case 0x438: /* stm32f33x */ case 0x439: /* stm32f302x6/8 */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 64; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; stm32x_info->default_rdp = 0xAA; stm32x_info->can_load_options = true; break; default: LOG_WARNING("Cannot identify target as a STM32 family."); return ERROR_FAIL; } /* get flash size from target. */ retval = stm32x_get_flash_size(bank, &flash_size_in_kb); /* failed reading flash size or flash size invalid (early silicon), * default to max target family */ if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming %dk flash", max_flash_size_in_kb); flash_size_in_kb = max_flash_size_in_kb; } if (stm32x_info->has_dual_banks) { /* split reported size into matching bank */ if (bank->base != 0x08080000) { /* bank 0 will be fixed 512k */ flash_size_in_kb = 512; } else { flash_size_in_kb -= 512; /* bank1 also uses a register offset */ stm32x_info->register_base = FLASH_REG_BASE_B1; base_address = 0x08080000; } } /* if the user sets the size manually then ignore the probed value * this allows us to work around devices that have a invalid flash size register value */ if (stm32x_info->user_bank_size) { LOG_INFO("ignoring flash probed value, using configured bank size"); flash_size_in_kb = stm32x_info->user_bank_size / 1024; } LOG_INFO("flash size = %d KiB", flash_size_in_kb); /* did we assign flash size? */ assert(flash_size_in_kb != 0xffff); /* calculate numbers of pages */ int num_pages = flash_size_in_kb * 1024 / page_size; /* check that calculation result makes sense */ assert(num_pages > 0); free(bank->sectors); bank->sectors = NULL; free(bank->prot_blocks); bank->prot_blocks = NULL; bank->base = base_address; bank->size = (num_pages * page_size); bank->num_sectors = num_pages; bank->sectors = alloc_block_array(0, page_size, num_pages); if (!bank->sectors) return ERROR_FAIL; /* calculate number of write protection blocks */ int num_prot_blocks = num_pages / stm32x_info->ppage_size; if (num_prot_blocks > 32) num_prot_blocks = 32; bank->num_prot_blocks = num_prot_blocks; bank->prot_blocks = alloc_block_array(0, stm32x_info->ppage_size * page_size, num_prot_blocks); if (!bank->prot_blocks) return ERROR_FAIL; if (num_prot_blocks == 32) bank->prot_blocks[31].size = (num_pages - (31 * stm32x_info->ppage_size)) * page_size; stm32x_info->probed = true; return ERROR_OK; } static int stm32x_auto_probe(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; if (stm32x_info->probed) return ERROR_OK; return stm32x_probe(bank); } #if 0 COMMAND_HANDLER(stm32x_handle_part_id_command) { return ERROR_OK; } #endif static const char *get_stm32f0_revision(uint16_t rev_id) { const char *rev_str = NULL; switch (rev_id) { case 0x1000: rev_str = "1.0"; break; case 0x2000: rev_str = "2.0"; break; } return rev_str; } static int get_stm32x_info(struct flash_bank *bank, struct command_invocation *cmd) { uint32_t dbgmcu_idcode; /* read stm32 device id register */ int retval = stm32x_get_device_id(bank, &dbgmcu_idcode); if (retval != ERROR_OK) return retval; uint16_t device_id = dbgmcu_idcode & 0xfff; uint16_t rev_id = dbgmcu_idcode >> 16; const char *device_str; const char *rev_str = NULL; switch (device_id) { case 0x410: device_str = "STM32F10x (Medium Density)"; switch (rev_id) { case 0x0000: rev_str = "A"; break; case 0x1303: /* gd32f1x0 */ device_str = "GD32F1x0"; break; case 0x1704: /* gd32f3x0 */ device_str = "GD32F3x0"; break; case 0x1906: device_str = "GD32VF103"; break; case 0x1909: /* gd32e23x */ device_str = "GD32E23x"; break; case 0x2000: rev_str = "B"; break; case 0x2001: rev_str = "Z"; break; case 0x2003: rev_str = "Y"; break; } break; case 0x412: device_str = "STM32F10x (Low Density)"; switch (rev_id) { case 0x1000: rev_str = "A"; break; } break; case 0x414: device_str = "STM32F10x (High Density)"; switch (rev_id) { case 0x1000: rev_str = "A"; break; case 0x1001: rev_str = "Z"; break; case 0x1003: rev_str = "Y"; break; } break; case 0x418: device_str = "STM32F10x (Connectivity)"; switch (rev_id) { case 0x1000: rev_str = "A"; break; case 0x1001: rev_str = "Z"; break; } break; case 0x420: device_str = "STM32F100 (Low/Medium Density)"; switch (rev_id) { case 0x1000: rev_str = "A"; break; case 0x1001: rev_str = "Z"; break; } break; case 0x422: device_str = "STM32F302xB/C"; switch (rev_id) { case 0x1000: rev_str = "A"; break; case 0x1001: rev_str = "Z"; break; case 0x1003: rev_str = "Y"; break; case 0x2000: rev_str = "B"; break; } break; case 0x428: device_str = "STM32F100 (High Density)"; switch (rev_id) { case 0x1000: rev_str = "A"; break; case 0x1001: rev_str = "Z"; break; } break; case 0x430: device_str = "STM32F10x (XL Density)"; switch (rev_id) { case 0x1000: rev_str = "A"; break; } break; case 0x432: device_str = "STM32F37x"; switch (rev_id) { case 0x1000: rev_str = "A"; break; case 0x2000: rev_str = "B"; break; } break; case 0x438: device_str = "STM32F33x"; switch (rev_id) { case 0x1000: rev_str = "A"; break; } break; case 0x439: device_str = "STM32F302x6/8"; switch (rev_id) { case 0x1000: rev_str = "A"; break; case 0x1001: rev_str = "Z"; break; } break; case 0x444: device_str = "STM32F03x"; rev_str = get_stm32f0_revision(rev_id); break; case 0x440: device_str = "STM32F05x"; rev_str = get_stm32f0_revision(rev_id); break; case 0x445: device_str = "STM32F04x"; rev_str = get_stm32f0_revision(rev_id); break; case 0x446: device_str = "STM32F303xD/E"; switch (rev_id) { case 0x1000: rev_str = "A"; break; } break; case 0x448: device_str = "STM32F07x"; rev_str = get_stm32f0_revision(rev_id); break; case 0x442: device_str = "STM32F09x"; rev_str = get_stm32f0_revision(rev_id); break; default: command_print_sameline(cmd, "Cannot identify target as a STM32F0/1/3\n"); return ERROR_FAIL; } if (rev_str) command_print_sameline(cmd, "%s - Rev: %s", device_str, rev_str); else command_print_sameline(cmd, "%s - Rev: unknown (0x%04x)", device_str, rev_id); return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_lock_command) { struct target *target = NULL; struct stm32x_flash_bank *stm32x_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = stm32x_check_operation_supported(bank); if (retval != ERROR_OK) return retval; if (stm32x_erase_options(bank) != ERROR_OK) { command_print(CMD, "stm32x failed to erase options"); return ERROR_OK; } /* set readout protection */ stm32x_info->option_bytes.rdp = 0; if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD, "stm32x failed to lock device"); return ERROR_OK; } command_print(CMD, "stm32x locked"); return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_unlock_command) { struct target *target = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = stm32x_check_operation_supported(bank); if (retval != ERROR_OK) return retval; if (stm32x_erase_options(bank) != ERROR_OK) { command_print(CMD, "stm32x failed to erase options"); return ERROR_OK; } if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD, "stm32x failed to unlock device"); return ERROR_OK; } command_print(CMD, "stm32x unlocked.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect."); return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_options_read_command) { uint32_t optionbyte, protection; struct target *target = NULL; struct stm32x_flash_bank *stm32x_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = stm32x_check_operation_supported(bank); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, STM32_FLASH_OBR_B0, &optionbyte); if (retval != ERROR_OK) return retval; uint16_t user_data = optionbyte >> stm32x_info->user_data_offset; retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &protection); if (retval != ERROR_OK) return retval; if (optionbyte & (1 << OPT_ERROR)) command_print(CMD, "option byte complement error"); command_print(CMD, "option byte register = 0x%" PRIx32 "", optionbyte); command_print(CMD, "write protection register = 0x%" PRIx32 "", protection); command_print(CMD, "read protection: %s", (optionbyte & (1 << OPT_READOUT)) ? "on" : "off"); /* user option bytes are offset depending on variant */ optionbyte >>= stm32x_info->option_offset; command_print(CMD, "watchdog: %sware", (optionbyte & (1 << OPT_RDWDGSW)) ? "soft" : "hard"); command_print(CMD, "stop mode: %sreset generated upon entry", (optionbyte & (1 << OPT_RDRSTSTOP)) ? "no " : ""); command_print(CMD, "standby mode: %sreset generated upon entry", (optionbyte & (1 << OPT_RDRSTSTDBY)) ? "no " : ""); if (stm32x_info->has_dual_banks) command_print(CMD, "boot: bank %d", (optionbyte & (1 << OPT_BFB2)) ? 0 : 1); command_print(CMD, "user data = 0x%02" PRIx16 "", user_data); return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_options_write_command) { struct target *target = NULL; struct stm32x_flash_bank *stm32x_info = NULL; uint8_t optionbyte; uint16_t useropt; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = stm32x_check_operation_supported(bank); if (retval != ERROR_OK) return retval; retval = stm32x_read_options(bank); if (retval != ERROR_OK) return retval; /* start with current options */ optionbyte = stm32x_info->option_bytes.user; useropt = stm32x_info->option_bytes.data; /* skip over flash bank */ CMD_ARGC--; CMD_ARGV++; while (CMD_ARGC) { if (strcmp("SWWDG", CMD_ARGV[0]) == 0) optionbyte |= (1 << 0); else if (strcmp("HWWDG", CMD_ARGV[0]) == 0) optionbyte &= ~(1 << 0); else if (strcmp("NORSTSTOP", CMD_ARGV[0]) == 0) optionbyte |= (1 << 1); else if (strcmp("RSTSTOP", CMD_ARGV[0]) == 0) optionbyte &= ~(1 << 1); else if (strcmp("NORSTSTNDBY", CMD_ARGV[0]) == 0) optionbyte |= (1 << 2); else if (strcmp("RSTSTNDBY", CMD_ARGV[0]) == 0) optionbyte &= ~(1 << 2); else if (strcmp("USEROPT", CMD_ARGV[0]) == 0) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], useropt); CMD_ARGC--; CMD_ARGV++; } else if (stm32x_info->has_dual_banks) { if (strcmp("BOOT0", CMD_ARGV[0]) == 0) optionbyte |= (1 << 3); else if (strcmp("BOOT1", CMD_ARGV[0]) == 0) optionbyte &= ~(1 << 3); else return ERROR_COMMAND_SYNTAX_ERROR; } else return ERROR_COMMAND_SYNTAX_ERROR; CMD_ARGC--; CMD_ARGV++; } if (stm32x_erase_options(bank) != ERROR_OK) { command_print(CMD, "stm32x failed to erase options"); return ERROR_OK; } stm32x_info->option_bytes.user = optionbyte; stm32x_info->option_bytes.data = useropt; if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD, "stm32x failed to write options"); return ERROR_OK; } command_print(CMD, "stm32x write options complete.\n" "INFO: %spower cycle is required " "for the new settings to take effect.", stm32x_info->can_load_options ? "'stm32f1x options_load' command or " : ""); return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_options_load_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct stm32x_flash_bank *stm32x_info = bank->driver_priv; if (!stm32x_info->can_load_options) { LOG_ERROR("Command not applicable to stm32f1x devices - power cycle is " "required instead."); return ERROR_FAIL; } struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = stm32x_check_operation_supported(bank); if (retval != ERROR_OK) return retval; /* unlock option flash registers */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) { (void)target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); return retval; } /* force re-load of option bytes - generates software reset */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OBL_LAUNCH); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32x_mass_erase(struct flash_bank *bank) { struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* unlock option flash registers */ int retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) goto flash_lock; /* mass erase flash memory */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER); if (retval != ERROR_OK) goto flash_lock; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER | FLASH_STRT); if (retval != ERROR_OK) goto flash_lock; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); flash_lock: { int retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval == ERROR_OK) retval = retval2; } return retval; } COMMAND_HANDLER(stm32x_handle_mass_erase_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = stm32x_mass_erase(bank); if (retval == ERROR_OK) command_print(CMD, "stm32x mass erase complete"); else command_print(CMD, "stm32x mass erase failed"); return retval; } static const struct command_registration stm32f1x_exec_command_handlers[] = { { .name = "lock", .handler = stm32x_handle_lock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Lock entire flash device.", }, { .name = "unlock", .handler = stm32x_handle_unlock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Unlock entire protected flash device.", }, { .name = "mass_erase", .handler = stm32x_handle_mass_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Erase entire flash device.", }, { .name = "options_read", .handler = stm32x_handle_options_read_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Read and display device option bytes.", }, { .name = "options_write", .handler = stm32x_handle_options_write_command, .mode = COMMAND_EXEC, .usage = "bank_id ('SWWDG'|'HWWDG') " "('RSTSTNDBY'|'NORSTSTNDBY') " "('RSTSTOP'|'NORSTSTOP') ('USEROPT' user_data)", .help = "Replace bits in device option bytes.", }, { .name = "options_load", .handler = stm32x_handle_options_load_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Force re-load of device option bytes.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration stm32f1x_command_handlers[] = { { .name = "stm32f1x", .mode = COMMAND_ANY, .help = "stm32f1x flash command group", .usage = "", .chain = stm32f1x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver stm32f1x_flash = { .name = "stm32f1x", .commands = stm32f1x_command_handlers, .flash_bank_command = stm32x_flash_bank_command, .erase = stm32x_erase, .protect = stm32x_protect, .write = stm32x_write, .read = default_flash_read, .probe = stm32x_probe, .auto_probe = stm32x_auto_probe, .erase_check = default_flash_blank_check, .protect_check = stm32x_protect_check, .info = get_stm32x_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/stm32f2x.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/cortex_m.h> /* Regarding performance: * * Short story - it might be best to leave the performance at * current levels. * * You may see a jump in speed if you change to using * 32bit words for the block programming. * * Its a shame you cannot use the double word as its * even faster - but you require external VPP for that mode. * * Having said all that 16bit writes give us the widest vdd * operating range, so may be worth adding a note to that effect. * */ /* Danger!!!! The STM32F1x and STM32F2x series actually have * quite different flash controllers. * * What's more scary is that the names of the registers and their * addresses are the same, but the actual bits and what they do are * can be very different. * * To reduce testing complexity and dangers of regressions, * a separate file is used for stm32fx2x. * * Sector sizes in kiBytes: * 1 MiByte part with 4 x 16, 1 x 64, 7 x 128. * 1.5 MiByte part with 4 x 16, 1 x 64, 11 x 128. * 2 MiByte part with 4 x 16, 1 x 64, 7 x 128, 4 x 16, 1 x 64, 7 x 128. * 1 MiByte STM32F42x/43x part with DB1M Option set: * 4 x 16, 1 x 64, 3 x 128, 4 x 16, 1 x 64, 3 x 128. * * STM32F7[2|3] * 512 kiByte part with 4 x 16, 1 x 64, 3 x 128. * * STM32F7[4|5] * 1 MiByte part with 4 x 32, 1 x 128, 3 x 256. * * STM32F7[6|7] * 1 MiByte part in single bank mode with 4 x 32, 1 x 128, 3 x 256. * 1 MiByte part in dual-bank mode two banks with 4 x 16, 1 x 64, 3 x 128 each. * 2 MiByte part in single-bank mode with 4 x 32, 1 x 128, 7 x 256. * 2 MiByte part in dual-bank mode two banks with 4 x 16, 1 x 64, 7 x 128 each. * * Protection size is sector size. * * Tested with STM3220F-EVAL board. * * STM32F4xx series for reference. * * RM0090 * http://www.st.com/web/en/resource/technical/document/reference_manual/DM00031020.pdf * * PM0059 * www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/ * PROGRAMMING_MANUAL/CD00233952.pdf * * STM32F7xx series for reference. * * RM0385 * http://www.st.com/web/en/resource/technical/document/reference_manual/DM00124865.pdf * * RM0410 * http://www.st.com/resource/en/reference_manual/dm00224583.pdf * * RM0430 * http://www.st.com/resource/en/reference_manual/dm00305666.pdf * * RM0431 * http://www.st.com/resource/en/reference_manual/dm00305990.pdf * * STM32F1x series - notice that this code was copy, pasted and knocked * into a stm32f2x driver, so in case something has been converted or * bugs haven't been fixed, here are the original manuals: * * RM0008 - Reference manual * * RM0042, the Flash programming manual for low-, medium- high-density and * connectivity line STM32F10x devices * * PM0068, the Flash programming manual for XL-density STM32F10x devices. * */ /* Erase time can be as high as 1000ms, 10x this and it's toast... */ #define FLASH_ERASE_TIMEOUT 10000 #define FLASH_WRITE_TIMEOUT 5 /* Mass erase time can be as high as 32 s in x8 mode. */ #define FLASH_MASS_ERASE_TIMEOUT 33000 #define FLASH_BANK_BASE 0x80000000 #define STM32F2_OTP_SIZE 512 #define STM32F2_OTP_SECTOR_SIZE 32 #define STM32F2_OTP_BANK_BASE 0x1fff7800 #define STM32F2_OTP_LOCK_BASE ((STM32F2_OTP_BANK_BASE) + (STM32F2_OTP_SIZE)) /* see RM0410 section 3.6 "One-time programmable bytes" */ #define STM32F7_OTP_SECTOR_SIZE 64 #define STM32F7_OTP_SIZE 1024 #define STM32F7_OTP_BANK_BASE 0x1ff0f000 #define STM32F7_OTP_LOCK_BASE ((STM32F7_OTP_BANK_BASE) + (STM32F7_OTP_SIZE)) #define STM32_FLASH_BASE 0x40023c00 #define STM32_FLASH_ACR 0x40023c00 #define STM32_FLASH_KEYR 0x40023c04 #define STM32_FLASH_OPTKEYR 0x40023c08 #define STM32_FLASH_SR 0x40023c0C #define STM32_FLASH_CR 0x40023c10 #define STM32_FLASH_OPTCR 0x40023c14 #define STM32_FLASH_OPTCR1 0x40023c18 #define STM32_FLASH_OPTCR2 0x40023c1c /* FLASH_CR register bits */ #define FLASH_PG (1 << 0) #define FLASH_SER (1 << 1) #define FLASH_MER (1 << 2) /* MER/MER1 for f76x/77x */ #define FLASH_MER1 (1 << 15) /* MER2 for f76x/77x, confusing ... */ #define FLASH_STRT (1 << 16) #define FLASH_PSIZE_8 (0 << 8) #define FLASH_PSIZE_16 (1 << 8) #define FLASH_PSIZE_32 (2 << 8) #define FLASH_PSIZE_64 (3 << 8) /* The sector number encoding is not straight binary for dual bank flash. */ #define FLASH_SNB(a) ((a) << 3) #define FLASH_LOCK (1 << 31) /* FLASH_SR register bits */ #define FLASH_BSY (1 << 16) #define FLASH_PGSERR (1 << 7) /* Programming sequence error */ #define FLASH_PGPERR (1 << 6) /* Programming parallelism error */ #define FLASH_PGAERR (1 << 5) /* Programming alignment error */ #define FLASH_WRPERR (1 << 4) /* Write protection error */ #define FLASH_OPERR (1 << 1) /* Operation error */ #define FLASH_ERROR (FLASH_PGSERR | FLASH_PGPERR | FLASH_PGAERR | FLASH_WRPERR | FLASH_OPERR) /* STM32_FLASH_OPTCR register bits */ #define OPTCR_LOCK (1 << 0) #define OPTCR_START (1 << 1) #define OPTCR_NDBANK (1 << 29) /* not dual bank mode */ #define OPTCR_DB1M (1 << 30) /* 1 MiB devices dual flash bank option */ #define OPTCR_SPRMOD (1 << 31) /* switches PCROPi/nWPRi interpretation */ /* STM32_FLASH_OPTCR2 register bits */ #define OPTCR2_PCROP_RDP (1 << 31) /* erase PCROP zone when decreasing RDP */ /* register unlock keys */ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB /* option register unlock key */ #define OPTKEY1 0x08192A3B #define OPTKEY2 0x4C5D6E7F struct stm32x_options { uint8_t RDP; uint16_t user_options; /* bit 0-7 usual options, bit 8-11 extra options */ uint32_t protection; uint32_t boot_addr; uint32_t optcr2_pcrop; }; struct stm32x_flash_bank { struct stm32x_options option_bytes; bool probed; bool otp_unlocked; bool has_large_mem; /* F42x/43x/469/479/7xx in dual bank mode */ bool has_extra_options; /* F42x/43x/469/479/7xx */ bool has_boot_addr; /* F7xx */ bool has_optcr2_pcrop; /* F72x/73x */ unsigned int protection_bits; /* F413/423 */ uint32_t user_bank_size; }; static bool stm32x_is_otp(struct flash_bank *bank) { return bank->base == STM32F2_OTP_BANK_BASE || bank->base == STM32F7_OTP_BANK_BASE; } static bool stm32x_otp_is_f7(struct flash_bank *bank) { return bank->base == STM32F7_OTP_BANK_BASE; } static int stm32x_is_otp_unlocked(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; return stm32x_info->otp_unlocked; } static int stm32x_otp_disable(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; LOG_INFO("OTP memory bank #%u is disabled for write commands.", bank->bank_number); stm32x_info->otp_unlocked = false; return ERROR_OK; } static int stm32x_otp_enable(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; if (!stm32x_info->otp_unlocked) { LOG_INFO("OTP memory bank #%u is enabled for write commands.", bank->bank_number); stm32x_info->otp_unlocked = true; } else { LOG_WARNING("OTP memory bank #%u is already enabled for write commands.", bank->bank_number); } return ERROR_OK; } /* flash bank stm32x <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) { struct stm32x_flash_bank *stm32x_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; stm32x_info = malloc(sizeof(struct stm32x_flash_bank)); bank->driver_priv = stm32x_info; stm32x_info->probed = false; stm32x_info->otp_unlocked = false; stm32x_info->user_bank_size = bank->size; return ERROR_OK; } static inline int stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg) { return reg; } static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status) { struct target *target = bank->target; return target_read_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), status); } static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) { struct target *target = bank->target; uint32_t status; int retval = ERROR_OK; /* wait for busy to clear */ for (;;) { retval = stm32x_get_flash_status(bank, &status); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%" PRIx32, status); if ((status & FLASH_BSY) == 0) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FAIL; } alive_sleep(1); } if (status & FLASH_WRPERR) { LOG_ERROR("stm32x device protected"); retval = ERROR_FAIL; } /* Clear but report errors */ if (status & FLASH_ERROR) { if (retval == ERROR_OK) retval = ERROR_FAIL; /* If this operation fails, we ignore it and report the original * retval */ target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), status & FLASH_ERROR); } return retval; } static int stm32x_unlock_reg(struct target *target) { uint32_t ctrl; /* first check if not already unlocked * otherwise writing on STM32_FLASH_KEYR will fail */ int retval = target_read_u32(target, STM32_FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; if ((ctrl & FLASH_LOCK) == 0) return ERROR_OK; /* unlock flash registers */ retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, STM32_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, STM32_FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; if (ctrl & FLASH_LOCK) { LOG_ERROR("flash not unlocked STM32_FLASH_CR: 0x%" PRIx32, ctrl); return ERROR_TARGET_FAILURE; } return ERROR_OK; } static int stm32x_unlock_option_reg(struct target *target) { uint32_t ctrl; int retval = target_read_u32(target, STM32_FLASH_OPTCR, &ctrl); if (retval != ERROR_OK) return retval; if ((ctrl & OPTCR_LOCK) == 0) return ERROR_OK; /* unlock option registers */ retval = target_write_u32(target, STM32_FLASH_OPTKEYR, OPTKEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, STM32_FLASH_OPTKEYR, OPTKEY2); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, STM32_FLASH_OPTCR, &ctrl); if (retval != ERROR_OK) return retval; if (ctrl & OPTCR_LOCK) { LOG_ERROR("options not unlocked STM32_FLASH_OPTCR: 0x%" PRIx32, ctrl); return ERROR_TARGET_FAILURE; } return ERROR_OK; } static int stm32x_read_options(struct flash_bank *bank) { uint32_t optiondata; struct stm32x_flash_bank *stm32x_info = NULL; struct target *target = bank->target; stm32x_info = bank->driver_priv; /* read current option bytes */ int retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata); if (retval != ERROR_OK) return retval; /* caution: F2 implements 5 bits (WDG_SW only) * whereas F7 6 bits (IWDG_SW and WWDG_SW) in user_options */ stm32x_info->option_bytes.user_options = optiondata & 0xfc; stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff; stm32x_info->option_bytes.protection = (optiondata >> 16) & (~(0xffff << stm32x_info->protection_bits) & 0xffff); if (stm32x_info->has_extra_options) { /* F42x/43x/469/479 and 7xx have up to 4 bits of extra options */ stm32x_info->option_bytes.user_options |= (optiondata >> 20) & ((0xf00 << (stm32x_info->protection_bits - 12)) & 0xf00); } if (stm32x_info->has_large_mem || stm32x_info->has_boot_addr) { retval = target_read_u32(target, STM32_FLASH_OPTCR1, &optiondata); if (retval != ERROR_OK) return retval; /* FLASH_OPTCR1 has quite different meanings ... */ if (stm32x_info->has_boot_addr) { /* for F7xx it contains boot0 and boot1 */ stm32x_info->option_bytes.boot_addr = optiondata; } else { /* for F42x/43x/469/479 it contains 12 additional protection bits */ stm32x_info->option_bytes.protection |= (optiondata >> 4) & 0x00fff000; } } if (stm32x_info->has_optcr2_pcrop) { retval = target_read_u32(target, STM32_FLASH_OPTCR2, &optiondata); if (retval != ERROR_OK) return retval; stm32x_info->option_bytes.optcr2_pcrop = optiondata; if (stm32x_info->has_optcr2_pcrop && (stm32x_info->option_bytes.optcr2_pcrop & ~OPTCR2_PCROP_RDP)) { LOG_INFO("PCROP Engaged"); } } else { stm32x_info->option_bytes.optcr2_pcrop = 0x0; } if (stm32x_info->option_bytes.RDP != 0xAA) LOG_INFO("Device Security Bit Set"); return ERROR_OK; } static int stm32x_write_options(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = NULL; struct target *target = bank->target; uint32_t optiondata, optiondata2; stm32x_info = bank->driver_priv; int retval = stm32x_unlock_option_reg(target); if (retval != ERROR_OK) return retval; /* rebuild option data */ optiondata = stm32x_info->option_bytes.user_options & 0xfc; optiondata |= stm32x_info->option_bytes.RDP << 8; optiondata |= (stm32x_info->option_bytes.protection & (~(0xffff << stm32x_info->protection_bits))) << 16; if (stm32x_info->has_extra_options) { /* F42x/43x/469/479 and 7xx have up to 4 bits of extra options */ optiondata |= (stm32x_info->option_bytes.user_options & ((0xf00 << (stm32x_info->protection_bits - 12)) & 0xf00)) << 20; } if (stm32x_info->has_large_mem || stm32x_info->has_boot_addr) { if (stm32x_info->has_boot_addr) { /* F7xx uses FLASH_OPTCR1 for boot0 and boot1 ... */ optiondata2 = stm32x_info->option_bytes.boot_addr; } else { /* F42x/43x/469/479 uses FLASH_OPTCR1 for additional protection bits */ optiondata2 = (stm32x_info->option_bytes.protection & 0x00fff000) << 4; } retval = target_write_u32(target, STM32_FLASH_OPTCR1, optiondata2); if (retval != ERROR_OK) return retval; } /* program extra pcrop register */ if (stm32x_info->has_optcr2_pcrop) { retval = target_write_u32(target, STM32_FLASH_OPTCR2, stm32x_info->option_bytes.optcr2_pcrop); if (retval != ERROR_OK) return retval; } /* program options */ retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata); if (retval != ERROR_OK) return retval; /* start programming cycle */ retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata | OPTCR_START); if (retval != ERROR_OK) return retval; /* wait for completion, this might trigger a security erase and take a while */ retval = stm32x_wait_status_busy(bank, FLASH_MASS_ERASE_TIMEOUT); if (retval != ERROR_OK) return retval; /* relock registers */ retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata | OPTCR_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32x_otp_read_protect(struct flash_bank *bank) { struct target *target = bank->target; uint32_t lock_base; int retval; uint8_t lock; lock_base = stm32x_otp_is_f7(bank) ? STM32F7_OTP_LOCK_BASE : STM32F2_OTP_LOCK_BASE; for (unsigned int i = 0; i < bank->num_sectors; i++) { retval = target_read_u8(target, lock_base + i, &lock); if (retval != ERROR_OK) return retval; bank->sectors[i].is_protected = !lock; } return ERROR_OK; } static int stm32x_otp_protect(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; uint32_t lock_base; int i, retval; uint8_t lock; assert((first <= last) && (last < bank->num_sectors)); lock_base = stm32x_otp_is_f7(bank) ? STM32F7_OTP_LOCK_BASE : STM32F2_OTP_LOCK_BASE; for (i = first; first <= last; i++) { retval = target_read_u8(target, lock_base + i, &lock); if (retval != ERROR_OK) return retval; if (lock) continue; lock = 0xff; retval = target_write_u8(target, lock_base + i, lock); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int stm32x_protect_check(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct flash_sector *prot_blocks; unsigned int num_prot_blocks; int retval; /* if it's the OTP bank, look at the lock bits there */ if (stm32x_is_otp(bank)) return stm32x_otp_read_protect(bank); /* read write protection settings */ retval = stm32x_read_options(bank); if (retval != ERROR_OK) { LOG_DEBUG("unable to read option bytes"); return retval; } if (bank->prot_blocks) { num_prot_blocks = bank->num_prot_blocks; prot_blocks = bank->prot_blocks; } else { num_prot_blocks = bank->num_sectors; prot_blocks = bank->sectors; } for (unsigned int i = 0; i < num_prot_blocks; i++) prot_blocks[i].is_protected = ~(stm32x_info->option_bytes.protection >> i) & 1; return ERROR_OK; } static int stm32x_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; if (stm32x_is_otp(bank)) { LOG_ERROR("Cannot erase OTP memory"); return ERROR_FAIL; } assert((first <= last) && (last < bank->num_sectors)); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } int retval; retval = stm32x_unlock_reg(target); if (retval != ERROR_OK) return retval; /* Sector Erase To erase a sector, follow the procedure below: 1. Check that no Flash memory operation is ongoing by checking the BSY bit in the FLASH_SR register 2. Set the SER bit and select the sector you wish to erase (SNB) in the FLASH_CR register 3. Set the STRT bit in the FLASH_CR register 4. Wait for the BSY bit to be cleared */ for (unsigned int i = first; i <= last; i++) { unsigned int snb; if (stm32x_info->has_large_mem && i >= (bank->num_sectors / 2)) snb = (i - (bank->num_sectors / 2)) | 0x10; else snb = i; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_SER | FLASH_SNB(snb) | FLASH_STRT); if (retval != ERROR_OK) return retval; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) return retval; } retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct target *target = bank->target; struct stm32x_flash_bank *stm32x_info = bank->driver_priv; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (stm32x_is_otp(bank)) { if (!set) { LOG_ERROR("OTP protection can only be enabled"); return ERROR_COMMAND_ARGUMENT_INVALID; } return stm32x_otp_protect(bank, first, last); } /* read protection settings */ int retval = stm32x_read_options(bank); if (retval != ERROR_OK) { LOG_DEBUG("unable to read option bytes"); return retval; } for (unsigned int i = first; i <= last; i++) { if (set) stm32x_info->option_bytes.protection &= ~(1 << i); else stm32x_info->option_bytes.protection |= (1 << i); } retval = stm32x_write_options(bank); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; static const uint8_t stm32x_flash_write_code[] = { #include "../../../contrib/loaders/flash/stm32/stm32f2x.inc" }; if (stm32x_is_otp(bank) && !stm32x_is_otp_unlocked(bank)) { LOG_ERROR("OTP memory bank is disabled for write commands."); return ERROR_FAIL; } if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash base */ buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[3].value, 0, 32, count); buf_set_u32(reg_params[4].value, 0, 32, STM32_FLASH_BASE); retval = target_run_flash_async_algorithm(target, buffer, count, 2, 0, NULL, 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("error executing stm32x flash write algorithm"); uint32_t error = buf_get_u32(reg_params[0].value, 0, 32) & FLASH_ERROR; if (error & FLASH_WRPERR) LOG_ERROR("flash memory write protected"); if (error != 0) { LOG_ERROR("flash write failed = 0x%08" PRIx32, error); /* Clear but report errors */ target_write_u32(target, STM32_FLASH_SR, error); retval = ERROR_FAIL; } } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; } static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t words_remaining = (count / 2); uint32_t bytes_remaining = (count & 0x00000001); uint32_t address = bank->base + offset; uint32_t bytes_written = 0; int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x1) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } retval = stm32x_unlock_reg(target); if (retval != ERROR_OK) return retval; /* multiple half words (2-byte) to be programmed? */ if (words_remaining > 0) { /* try using a block write */ retval = stm32x_write_block(bank, buffer, offset, words_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single dword accesses */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); } } else { buffer += words_remaining * 2; address += words_remaining * 2; words_remaining = 0; } } if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)) return retval; /* Standard programming The Flash memory programming sequence is as follows: 1. Check that no main Flash memory operation is ongoing by checking the BSY bit in the FLASH_SR register. 2. Set the PG bit in the FLASH_CR register 3. Perform the data write operation(s) to the desired memory address (inside main memory block or OTP area): – – Half-word access in case of x16 parallelism – Word access in case of x32 parallelism – 4. Byte access in case of x8 parallelism Double word access in case of x64 parallelism Wait for the BSY bit to be cleared */ while (words_remaining > 0) { retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG | FLASH_PSIZE_16); if (retval != ERROR_OK) return retval; retval = target_write_memory(target, address, 2, 1, buffer + bytes_written); if (retval != ERROR_OK) return retval; retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) return retval; bytes_written += 2; words_remaining--; address += 2; } if (bytes_remaining) { retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG | FLASH_PSIZE_8); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, address, buffer[bytes_written]); if (retval != ERROR_OK) return retval; retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) return retval; } return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK); } static void setup_sector(struct flash_bank *bank, unsigned int i, unsigned int size) { assert(i < bank->num_sectors); bank->sectors[i].offset = bank->size; bank->sectors[i].size = size; bank->size += bank->sectors[i].size; LOG_DEBUG("sector %u: %ukBytes", i, size >> 10); } static uint16_t sector_size_in_kb(unsigned int i, uint16_t max_sector_size_in_kb) { if (i < 4) return max_sector_size_in_kb / 8; if (i == 4) return max_sector_size_in_kb / 2; return max_sector_size_in_kb; } static unsigned int calculate_number_of_sectors(struct flash_bank *bank, uint16_t flash_size_in_kb, uint16_t max_sector_size_in_kb) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; uint16_t remaining_flash_size_in_kb = flash_size_in_kb; unsigned int nr_sectors; /* Dual Bank Flash has two identically-arranged banks of sectors. */ if (stm32x_info->has_large_mem) remaining_flash_size_in_kb /= 2; for (nr_sectors = 0; remaining_flash_size_in_kb > 0; nr_sectors++) { uint16_t size_in_kb = sector_size_in_kb(nr_sectors, max_sector_size_in_kb); if (size_in_kb > remaining_flash_size_in_kb) { LOG_INFO("%s Bank %" PRIu16 " kiB final sector clipped to %" PRIu16 " kiB", stm32x_info->has_large_mem ? "Dual" : "Single", flash_size_in_kb, remaining_flash_size_in_kb); remaining_flash_size_in_kb = 0; } else { remaining_flash_size_in_kb -= size_in_kb; } } return stm32x_info->has_large_mem ? nr_sectors*2 : nr_sectors; } static void setup_bank(struct flash_bank *bank, unsigned int start, uint16_t flash_size_in_kb, uint16_t max_sector_size_in_kb) { uint16_t remaining_flash_size_in_kb = flash_size_in_kb; unsigned int sector_index = 0; while (remaining_flash_size_in_kb > 0) { uint16_t size_in_kb = sector_size_in_kb(sector_index, max_sector_size_in_kb); if (size_in_kb > remaining_flash_size_in_kb) { /* Clip last sector. Already warned in * calculate_number_of_sectors. */ size_in_kb = remaining_flash_size_in_kb; } setup_sector(bank, start + sector_index, size_in_kb * 1024); remaining_flash_size_in_kb -= size_in_kb; sector_index++; } } static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) { /* this checks for a stm32f4x errata issue where a * stm32f2x DBGMCU_IDCODE is incorrectly returned. * If the issue is detected target is forced to stm32f4x Rev A. * Only effects Rev A silicon */ struct target *target = bank->target; /* read stm32 device id register */ int retval = target_read_u32(target, 0xE0042000, device_id); if (retval != ERROR_OK) return retval; if ((*device_id & 0xfff) == 0x411 && cortex_m_get_partno_safe(target) == CORTEX_M4_PARTNO) { *device_id &= ~((0xFFFF << 16) | 0xfff); *device_id |= (0x1000 << 16) | 0x413; LOG_INFO("stm32f4x errata detected - fixing incorrect MCU_IDCODE"); } return retval; } static int stm32x_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stm32x_flash_bank *stm32x_info = bank->driver_priv; unsigned int num_prot_blocks, num_sectors; uint16_t flash_size_in_kb; uint16_t otp_size_in_b; uint16_t otp_sector_size; uint32_t flash_size_reg = 0x1FFF7A22; uint16_t max_sector_size_in_kb = 128; uint16_t max_flash_size_in_kb; uint32_t device_id; uint32_t base_address = 0x08000000; stm32x_info->probed = false; stm32x_info->has_large_mem = false; stm32x_info->has_boot_addr = false; stm32x_info->has_extra_options = false; stm32x_info->has_optcr2_pcrop = false; stm32x_info->protection_bits = 12; /* max. number of nWRPi bits (in FLASH_OPTCR !!!) */ num_prot_blocks = 0; free(bank->sectors); bank->num_sectors = 0; bank->sectors = NULL; free(bank->prot_blocks); bank->num_prot_blocks = 0; bank->prot_blocks = NULL; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_TARGET_NOT_EXAMINED; } /* if explicitly called out as OTP bank, short circuit probe */ if (stm32x_is_otp(bank)) { if (stm32x_otp_is_f7(bank)) { otp_size_in_b = STM32F7_OTP_SIZE; otp_sector_size = STM32F7_OTP_SECTOR_SIZE; } else { otp_size_in_b = STM32F2_OTP_SIZE; otp_sector_size = STM32F2_OTP_SECTOR_SIZE; } num_sectors = otp_size_in_b / otp_sector_size; LOG_INFO("flash size = %" PRIu16 " bytes", otp_size_in_b); assert(num_sectors > 0); bank->num_sectors = num_sectors; bank->sectors = calloc(sizeof(struct flash_sector), num_sectors); if (stm32x_otp_is_f7(bank)) bank->size = STM32F7_OTP_SIZE; else bank->size = STM32F2_OTP_SIZE; for (unsigned int i = 0; i < num_sectors; i++) { bank->sectors[i].offset = i * otp_sector_size; bank->sectors[i].size = otp_sector_size; bank->sectors[i].is_erased = 1; bank->sectors[i].is_protected = 0; } stm32x_info->probed = true; return ERROR_OK; } /* read stm32 device id register */ int retval = stm32x_get_device_id(bank, &device_id); if (retval != ERROR_OK) return retval; LOG_INFO("device id = 0x%08" PRIx32, device_id); device_id &= 0xfff; /* only bits 0-11 are used further on */ /* set max flash size depending on family, id taken from AN2606 */ switch (device_id) { case 0x411: /* F20x/21x */ case 0x413: /* F40x/41x */ max_flash_size_in_kb = 1024; break; case 0x419: /* F42x/43x */ case 0x434: /* F469/479 */ stm32x_info->has_extra_options = true; max_flash_size_in_kb = 2048; break; case 0x423: /* F401xB/C */ max_flash_size_in_kb = 256; break; case 0x421: /* F446 */ case 0x431: /* F411 */ case 0x433: /* F401xD/E */ case 0x441: /* F412 */ max_flash_size_in_kb = 512; break; case 0x458: /* F410 */ max_flash_size_in_kb = 128; break; case 0x449: /* F74x/75x */ max_flash_size_in_kb = 1024; max_sector_size_in_kb = 256; flash_size_reg = 0x1FF0F442; stm32x_info->has_extra_options = true; stm32x_info->has_boot_addr = true; break; case 0x451: /* F76x/77x */ max_flash_size_in_kb = 2048; max_sector_size_in_kb = 256; flash_size_reg = 0x1FF0F442; stm32x_info->has_extra_options = true; stm32x_info->has_boot_addr = true; break; case 0x452: /* F72x/73x */ max_flash_size_in_kb = 512; flash_size_reg = 0x1FF07A22; /* yes, 0x1FF*0*7A22, not 0x1FF*F*7A22 */ stm32x_info->has_extra_options = true; stm32x_info->has_boot_addr = true; stm32x_info->has_optcr2_pcrop = true; break; case 0x463: /* F413x/423x */ max_flash_size_in_kb = 1536; stm32x_info->has_extra_options = true; stm32x_info->protection_bits = 15; num_prot_blocks = 15; break; default: LOG_WARNING("Cannot identify target as a STM32 family."); return ERROR_FAIL; } /* get flash size from target. */ retval = target_read_u16(target, flash_size_reg, &flash_size_in_kb); /* failed reading flash size or flash size invalid (early silicon), * default to max target family */ if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming %" PRIu16 "k flash", max_flash_size_in_kb); flash_size_in_kb = max_flash_size_in_kb; } /* if the user sets the size manually then ignore the probed value * this allows us to work around devices that have a invalid flash size register value */ if (stm32x_info->user_bank_size) { LOG_INFO("ignoring flash probed value, using configured bank size"); flash_size_in_kb = stm32x_info->user_bank_size / 1024; } LOG_INFO("flash size = %" PRIu16 " KiB", flash_size_in_kb); /* did we assign flash size? */ assert(flash_size_in_kb != 0xffff); /* F42x/43x/469/479 1024 kiByte devices have a dual bank option */ if ((device_id == 0x419) || (device_id == 0x434)) { uint32_t optiondata; retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata); if (retval != ERROR_OK) { LOG_DEBUG("unable to read option bytes"); return retval; } if ((flash_size_in_kb > 1024) || (optiondata & OPTCR_DB1M)) { stm32x_info->has_large_mem = true; LOG_INFO("Dual Bank %" PRIu16 " kiB STM32F42x/43x/469/479 found", flash_size_in_kb); } else { stm32x_info->has_large_mem = false; LOG_INFO("Single Bank %" PRIu16 " kiB STM32F42x/43x/469/479 found", flash_size_in_kb); } } /* F76x/77x devices have a dual bank option */ if (device_id == 0x451) { uint32_t optiondata; retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata); if (retval != ERROR_OK) { LOG_DEBUG("unable to read option bytes"); return retval; } if (optiondata & OPTCR_NDBANK) { stm32x_info->has_large_mem = false; LOG_INFO("Single Bank %" PRIu16 " kiB STM32F76x/77x found", flash_size_in_kb); } else { stm32x_info->has_large_mem = true; max_sector_size_in_kb >>= 1; /* sector size divided by 2 in dual-bank mode */ LOG_INFO("Dual Bank %" PRIu16 " kiB STM32F76x/77x found", flash_size_in_kb); } } /* calculate numbers of pages */ unsigned int num_pages = calculate_number_of_sectors( bank, flash_size_in_kb, max_sector_size_in_kb); bank->base = base_address; bank->num_sectors = num_pages; bank->sectors = calloc(num_pages, sizeof(struct flash_sector)); for (unsigned int i = 0; i < num_pages; i++) { bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } bank->size = 0; LOG_DEBUG("allocated %u sectors", num_pages); /* F76x/77x in dual bank mode */ if ((device_id == 0x451) && stm32x_info->has_large_mem) num_prot_blocks = num_pages >> 1; if (num_prot_blocks) { bank->prot_blocks = malloc(sizeof(struct flash_sector) * num_prot_blocks); for (unsigned int i = 0; i < num_prot_blocks; i++) bank->prot_blocks[i].is_protected = 0; LOG_DEBUG("allocated %u prot blocks", num_prot_blocks); } if (stm32x_info->has_large_mem) { /* dual-bank */ setup_bank(bank, 0, flash_size_in_kb >> 1, max_sector_size_in_kb); setup_bank(bank, num_pages >> 1, flash_size_in_kb >> 1, max_sector_size_in_kb); /* F767x/F77x in dual mode, one protection bit refers to two adjacent sectors */ if (device_id == 0x451) { for (unsigned int i = 0; i < num_prot_blocks; i++) { bank->prot_blocks[i].offset = bank->sectors[i << 1].offset; bank->prot_blocks[i].size = bank->sectors[i << 1].size + bank->sectors[(i << 1) + 1].size; } } } else { /* single-bank */ setup_bank(bank, 0, flash_size_in_kb, max_sector_size_in_kb); /* F413/F423, sectors 14 and 15 share one common protection bit */ if (device_id == 0x463) { for (unsigned int i = 0; i < num_prot_blocks; i++) { bank->prot_blocks[i].offset = bank->sectors[i].offset; bank->prot_blocks[i].size = bank->sectors[i].size; } bank->prot_blocks[num_prot_blocks - 1].size <<= 1; } } bank->num_prot_blocks = num_prot_blocks; assert((bank->size >> 10) == flash_size_in_kb); stm32x_info->probed = true; return ERROR_OK; } static int stm32x_auto_probe(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; if (stm32x_info->probed) return ERROR_OK; return stm32x_probe(bank); } static int get_stm32x_info(struct flash_bank *bank, struct command_invocation *cmd) { uint32_t dbgmcu_idcode; /* read stm32 device id register */ int retval = stm32x_get_device_id(bank, &dbgmcu_idcode); if (retval != ERROR_OK) return retval; uint16_t device_id = dbgmcu_idcode & 0xfff; uint16_t rev_id = dbgmcu_idcode >> 16; const char *device_str; const char *rev_str = NULL; switch (device_id) { case 0x411: device_str = "STM32F2xx"; switch (rev_id) { case 0x1000: rev_str = "A"; break; case 0x2000: rev_str = "B"; break; case 0x1001: rev_str = "Z"; break; case 0x2001: rev_str = "Y"; break; case 0x2003: rev_str = "X"; break; case 0x2007: rev_str = "1"; break; case 0x200F: rev_str = "V"; break; case 0x201F: rev_str = "2"; break; } break; case 0x413: case 0x419: case 0x434: device_str = "STM32F4xx"; switch (rev_id) { case 0x1000: rev_str = "A"; break; case 0x1001: rev_str = "Z"; break; case 0x1003: rev_str = "Y"; break; case 0x1007: rev_str = "1"; break; case 0x2001: rev_str = "3"; break; } break; case 0x421: device_str = "STM32F446"; switch (rev_id) { case 0x1000: rev_str = "A"; break; } break; case 0x423: case 0x431: case 0x433: case 0x458: case 0x441: device_str = "STM32F4xx (Low Power)"; switch (rev_id) { case 0x1000: rev_str = "A"; break; case 0x1001: rev_str = "Z"; break; case 0x2000: rev_str = "B"; break; case 0x3000: rev_str = "C"; break; } break; case 0x449: device_str = "STM32F7[4|5]x"; switch (rev_id) { case 0x1000: rev_str = "A"; break; case 0x1001: rev_str = "Z"; break; } break; case 0x451: device_str = "STM32F7[6|7]x"; switch (rev_id) { case 0x1000: rev_str = "A"; break; case 0x1001: rev_str = "Z"; break; } break; case 0x452: device_str = "STM32F7[2|3]x"; switch (rev_id) { case 0x1000: rev_str = "A"; break; } break; case 0x463: device_str = "STM32F4[1|2]3"; switch (rev_id) { case 0x1000: rev_str = "A"; break; } break; default: command_print_sameline(cmd, "Cannot identify target as a STM32F2/4/7\n"); return ERROR_FAIL; } if (rev_str) command_print_sameline(cmd, "%s - Rev: %s", device_str, rev_str); else command_print_sameline(cmd, "%s - Rev: unknown (0x%04" PRIx16 ")", device_str, rev_id); return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_lock_command) { struct target *target = NULL; struct stm32x_flash_bank *stm32x_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_INFO("Target not halted"); /* return ERROR_TARGET_NOT_HALTED; */ } if (stm32x_read_options(bank) != ERROR_OK) { command_print(CMD, "%s failed to read options", bank->driver->name); return ERROR_OK; } /* set readout protection */ stm32x_info->option_bytes.RDP = 0; if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD, "%s failed to lock device", bank->driver->name); return ERROR_OK; } command_print(CMD, "%s locked", bank->driver->name); return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_unlock_command) { struct target *target = NULL; struct stm32x_flash_bank *stm32x_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_INFO("Target not halted"); /* return ERROR_TARGET_NOT_HALTED; */ } if (stm32x_read_options(bank) != ERROR_OK) { command_print(CMD, "%s failed to read options", bank->driver->name); return ERROR_OK; } /* clear readout protection and complementary option bytes * this will also force a device unlock if set */ stm32x_info->option_bytes.RDP = 0xAA; if (stm32x_info->has_optcr2_pcrop) { stm32x_info->option_bytes.optcr2_pcrop = OPTCR2_PCROP_RDP | (~1U << bank->num_sectors); } if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD, "%s failed to unlock device", bank->driver->name); return ERROR_OK; } command_print(CMD, "%s unlocked.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect.", bank->driver->name); return ERROR_OK; } static int stm32x_mass_erase(struct flash_bank *bank) { int retval; uint32_t flash_mer; struct target *target = bank->target; struct stm32x_flash_bank *stm32x_info = NULL; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } stm32x_info = bank->driver_priv; retval = stm32x_unlock_reg(target); if (retval != ERROR_OK) return retval; /* mass erase flash memory */ if (stm32x_info->has_large_mem) flash_mer = FLASH_MER | FLASH_MER1; else flash_mer = FLASH_MER; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), flash_mer); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), flash_mer | FLASH_STRT); if (retval != ERROR_OK) return retval; retval = stm32x_wait_status_busy(bank, FLASH_MASS_ERASE_TIMEOUT); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_mass_erase_command) { if (CMD_ARGC < 1) { command_print(CMD, "stm32x mass_erase <bank>"); return ERROR_COMMAND_SYNTAX_ERROR; } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = stm32x_mass_erase(bank); if (retval == ERROR_OK) { command_print(CMD, "stm32x mass erase complete"); } else { command_print(CMD, "stm32x mass erase failed"); } return retval; } COMMAND_HANDLER(stm32f2x_handle_options_read_command) { int retval; struct flash_bank *bank; struct stm32x_flash_bank *stm32x_info = NULL; if (CMD_ARGC != 1) { command_print(CMD, "stm32f2x options_read <bank>"); return ERROR_COMMAND_SYNTAX_ERROR; } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = stm32x_read_options(bank); if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; if (stm32x_info->has_extra_options) { if (stm32x_info->has_boot_addr) { uint32_t boot_addr = stm32x_info->option_bytes.boot_addr; command_print(CMD, "stm32f2x user_options 0x%03" PRIX16 "," " boot_add0 0x%04" PRIX32 ", boot_add1 0x%04" PRIX32, stm32x_info->option_bytes.user_options, boot_addr & 0xffff, (boot_addr & 0xffff0000) >> 16); if (stm32x_info->has_optcr2_pcrop) { command_print(CMD, "stm32f2x optcr2_pcrop 0x%08" PRIX32, stm32x_info->option_bytes.optcr2_pcrop); } } else { command_print(CMD, "stm32f2x user_options 0x%03" PRIX16, stm32x_info->option_bytes.user_options); } } else { command_print(CMD, "stm32f2x user_options 0x%02" PRIX16, stm32x_info->option_bytes.user_options); } return retval; } COMMAND_HANDLER(stm32f2x_handle_options_write_command) { int retval; struct flash_bank *bank; struct stm32x_flash_bank *stm32x_info = NULL; uint16_t user_options, boot_addr0, boot_addr1, options_mask; if (CMD_ARGC < 1) { command_print(CMD, "stm32f2x options_write <bank> ..."); return ERROR_COMMAND_SYNTAX_ERROR; } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = stm32x_read_options(bank); if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; if (stm32x_info->has_boot_addr) { if (CMD_ARGC != 4) { command_print(CMD, "stm32f2x options_write <bank> <user_options>" " <boot_addr0> <boot_addr1>"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_NUMBER(u16, CMD_ARGV[2], boot_addr0); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], boot_addr1); stm32x_info->option_bytes.boot_addr = boot_addr0 | (((uint32_t) boot_addr1) << 16); } else { if (CMD_ARGC != 2) { command_print(CMD, "stm32f2x options_write <bank> <user_options>"); return ERROR_COMMAND_SYNTAX_ERROR; } } COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], user_options); options_mask = !stm32x_info->has_extra_options ? ~0xfc : ~(((0xf00 << (stm32x_info->protection_bits - 12)) | 0xff) & 0xffc); if (user_options & options_mask) { command_print(CMD, "stm32f2x invalid user_options"); return ERROR_COMMAND_ARGUMENT_INVALID; } stm32x_info->option_bytes.user_options = user_options; if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD, "stm32f2x failed to write options"); return ERROR_OK; } /* switching between single- and dual-bank modes requires re-probe */ /* ... and reprogramming of whole flash */ stm32x_info->probed = false; command_print(CMD, "stm32f2x write options complete.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect."); return retval; } COMMAND_HANDLER(stm32f2x_handle_optcr2_write_command) { int retval; struct flash_bank *bank; struct stm32x_flash_bank *stm32x_info = NULL; uint32_t optcr2_pcrop; if (CMD_ARGC != 2) { command_print(CMD, "stm32f2x optcr2_write <bank> <optcr2_value>"); return ERROR_COMMAND_SYNTAX_ERROR; } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; if (!stm32x_info->has_optcr2_pcrop) { command_print(CMD, "no optcr2 register"); return ERROR_COMMAND_ARGUMENT_INVALID; } command_print(CMD, "INFO: To disable PCROP, set PCROP_RDP" " with PCROPi bits STILL SET, then\nlock device and" " finally unlock it. Clears PCROP and mass erases flash."); retval = stm32x_read_options(bank); if (retval != ERROR_OK) return retval; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], optcr2_pcrop); stm32x_info->option_bytes.optcr2_pcrop = optcr2_pcrop; if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD, "stm32f2x failed to write options"); return ERROR_OK; } command_print(CMD, "stm32f2x optcr2_write complete."); return retval; } COMMAND_HANDLER(stm32x_handle_otp_command) { if (CMD_ARGC < 2) { command_print(CMD, "stm32x otp <bank> (enable|disable|show)"); return ERROR_COMMAND_SYNTAX_ERROR; } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; if (stm32x_is_otp(bank)) { if (strcmp(CMD_ARGV[1], "enable") == 0) { stm32x_otp_enable(bank); } else if (strcmp(CMD_ARGV[1], "disable") == 0) { stm32x_otp_disable(bank); } else if (strcmp(CMD_ARGV[1], "show") == 0) { command_print(CMD, "OTP memory bank #%u is %s for write commands.", bank->bank_number, stm32x_is_otp_unlocked(bank) ? "enabled" : "disabled"); } else { return ERROR_COMMAND_SYNTAX_ERROR; } } else { command_print(CMD, "Failed: not an OTP bank."); } return retval; } static const struct command_registration stm32f2x_exec_command_handlers[] = { { .name = "lock", .handler = stm32x_handle_lock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Lock entire flash device.", }, { .name = "unlock", .handler = stm32x_handle_unlock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Unlock entire protected flash device.", }, { .name = "mass_erase", .handler = stm32x_handle_mass_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Erase entire flash device.", }, { .name = "options_read", .handler = stm32f2x_handle_options_read_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Read and display device option bytes.", }, { .name = "options_write", .handler = stm32f2x_handle_options_write_command, .mode = COMMAND_EXEC, .usage = "bank_id user_options [ boot_add0 boot_add1 ]", .help = "Write option bytes", }, { .name = "optcr2_write", .handler = stm32f2x_handle_optcr2_write_command, .mode = COMMAND_EXEC, .usage = "bank_id optcr2", .help = "Write optcr2 word", }, { .name = "otp", .handler = stm32x_handle_otp_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "OTP (One Time Programmable) memory write enable/disable.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration stm32f2x_command_handlers[] = { { .name = "stm32f2x", .mode = COMMAND_ANY, .help = "stm32f2x flash command group", .usage = "", .chain = stm32f2x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver stm32f2x_flash = { .name = "stm32f2x", .commands = stm32f2x_command_handlers, .flash_bank_command = stm32x_flash_bank_command, .erase = stm32x_erase, .protect = stm32x_protect, .write = stm32x_write, .read = default_flash_read, .probe = stm32x_probe, .auto_probe = stm32x_auto_probe, .erase_check = default_flash_blank_check, .protect_check = stm32x_protect_check, .info = get_stm32x_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/stm32h7x.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2017 by STMicroelectronics * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/cortex_m.h> /* Erase time can be as high as 1000ms, 10x this and it's toast... */ #define FLASH_ERASE_TIMEOUT 10000 #define FLASH_WRITE_TIMEOUT 5 /* RM 433 */ /* Same Flash registers for both banks, */ /* access depends on Flash Base address */ #define FLASH_ACR 0x00 #define FLASH_KEYR 0x04 #define FLASH_OPTKEYR 0x08 #define FLASH_CR 0x0C #define FLASH_SR 0x10 #define FLASH_CCR 0x14 #define FLASH_OPTCR 0x18 #define FLASH_OPTSR_CUR 0x1C #define FLASH_OPTSR_PRG 0x20 #define FLASH_OPTCCR 0x24 #define FLASH_WPSN_CUR 0x38 #define FLASH_WPSN_PRG 0x3C /* FLASH_CR register bits */ #define FLASH_LOCK (1 << 0) #define FLASH_PG (1 << 1) #define FLASH_SER (1 << 2) #define FLASH_BER (1 << 3) #define FLASH_PSIZE_8 (0 << 4) #define FLASH_PSIZE_16 (1 << 4) #define FLASH_PSIZE_32 (2 << 4) #define FLASH_PSIZE_64 (3 << 4) #define FLASH_FW (1 << 6) #define FLASH_START (1 << 7) /* FLASH_SR register bits */ #define FLASH_BSY (1 << 0) /* Operation in progress */ #define FLASH_QW (1 << 2) /* Operation queue in progress */ #define FLASH_WRPERR (1 << 17) /* Write protection error */ #define FLASH_PGSERR (1 << 18) /* Programming sequence error */ #define FLASH_STRBERR (1 << 19) /* Strobe error */ #define FLASH_INCERR (1 << 21) /* Inconsistency error */ #define FLASH_OPERR (1 << 22) /* Operation error */ #define FLASH_RDPERR (1 << 23) /* Read Protection error */ #define FLASH_RDSERR (1 << 24) /* Secure Protection error */ #define FLASH_SNECCERR (1 << 25) /* Single ECC error */ #define FLASH_DBECCERR (1 << 26) /* Double ECC error */ #define FLASH_ERROR (FLASH_WRPERR | FLASH_PGSERR | FLASH_STRBERR | FLASH_INCERR | FLASH_OPERR | \ FLASH_RDPERR | FLASH_RDSERR | FLASH_SNECCERR | FLASH_DBECCERR) /* FLASH_OPTCR register bits */ #define OPT_LOCK (1 << 0) #define OPT_START (1 << 1) /* FLASH_OPTSR register bits */ #define OPT_BSY (1 << 0) #define OPT_RDP_POS 8 #define OPT_RDP_MASK (0xff << OPT_RDP_POS) #define OPT_OPTCHANGEERR (1 << 30) /* FLASH_OPTCCR register bits */ #define OPT_CLR_OPTCHANGEERR (1 << 30) /* register unlock keys */ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB /* option register unlock key */ #define OPTKEY1 0x08192A3B #define OPTKEY2 0x4C5D6E7F #define DBGMCU_IDCODE_REGISTER 0x5C001000 #define FLASH_BANK0_ADDRESS 0x08000000 #define FLASH_BANK1_ADDRESS 0x08100000 #define FLASH_REG_BASE_B0 0x52002000 #define FLASH_REG_BASE_B1 0x52002100 /* Supported device IDs */ #define DEVID_STM32H74_H75XX 0x450 #define DEVID_STM32H7A_H7BXX 0x480 #define DEVID_STM32H72_H73XX 0x483 struct stm32h7x_rev { uint16_t rev; const char *str; }; /* stm32h7x_part_info permits the store each device information and specificities. * the default unit is byte unless the suffix '_kb' is used. */ struct stm32h7x_part_info { uint16_t id; const char *device_str; const struct stm32h7x_rev *revs; size_t num_revs; unsigned int page_size_kb; unsigned int block_size; /* flash write word size in bytes */ uint16_t max_flash_size_kb; bool has_dual_bank; uint16_t max_bank_size_kb; /* Used when has_dual_bank is true */ uint32_t fsize_addr; /* Location of FSIZE register */ uint32_t wps_group_size; /* write protection group sectors' count */ uint32_t wps_mask; /* function to compute flash_cr register values */ uint32_t (*compute_flash_cr)(uint32_t cmd, int snb); }; struct stm32h7x_flash_bank { bool probed; uint32_t idcode; uint32_t user_bank_size; uint32_t flash_regs_base; /* Address of flash reg controller */ const struct stm32h7x_part_info *part_info; }; enum stm32h7x_opt_rdp { OPT_RDP_L0 = 0xaa, OPT_RDP_L1 = 0x00, OPT_RDP_L2 = 0xcc }; static const struct stm32h7x_rev stm32h74_h75xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2001, "X" }, { 0x2003, "V" }, }; static const struct stm32h7x_rev stm32h7a_h7bxx_revs[] = { { 0x1000, "A"}, }; static const struct stm32h7x_rev stm32h72_h73xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, }; static uint32_t stm32h74_h75xx_compute_flash_cr(uint32_t cmd, int snb) { return cmd | (snb << 8); } static uint32_t stm32h7a_h7bxx_compute_flash_cr(uint32_t cmd, int snb) { /* save FW and START bits, to be right shifted by 2 bits later */ const uint32_t tmp = cmd & (FLASH_FW | FLASH_START); /* mask parallelism (ignored), FW and START bits */ cmd &= ~(FLASH_PSIZE_64 | FLASH_FW | FLASH_START); return cmd | (tmp >> 2) | (snb << 6); } static const struct stm32h7x_part_info stm32h7x_parts[] = { { .id = DEVID_STM32H74_H75XX, .revs = stm32h74_h75xx_revs, .num_revs = ARRAY_SIZE(stm32h74_h75xx_revs), .device_str = "STM32H74x/75x", .page_size_kb = 128, .block_size = 32, .max_flash_size_kb = 2048, .max_bank_size_kb = 1024, .has_dual_bank = true, .fsize_addr = 0x1FF1E880, .wps_group_size = 1, .wps_mask = 0xFF, .compute_flash_cr = stm32h74_h75xx_compute_flash_cr, }, { .id = DEVID_STM32H7A_H7BXX, .revs = stm32h7a_h7bxx_revs, .num_revs = ARRAY_SIZE(stm32h7a_h7bxx_revs), .device_str = "STM32H7Ax/7Bx", .page_size_kb = 8, .block_size = 16, .max_flash_size_kb = 2048, .max_bank_size_kb = 1024, .has_dual_bank = true, .fsize_addr = 0x08FFF80C, .wps_group_size = 4, .wps_mask = 0xFFFFFFFF, .compute_flash_cr = stm32h7a_h7bxx_compute_flash_cr, }, { .id = DEVID_STM32H72_H73XX, .revs = stm32h72_h73xx_revs, .num_revs = ARRAY_SIZE(stm32h72_h73xx_revs), .device_str = "STM32H72x/73x", .page_size_kb = 128, .block_size = 32, .max_flash_size_kb = 1024, .max_bank_size_kb = 1024, .has_dual_bank = false, .fsize_addr = 0x1FF1E880, .wps_group_size = 1, .wps_mask = 0xFF, .compute_flash_cr = stm32h74_h75xx_compute_flash_cr, }, }; /* flash bank stm32x <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) { struct stm32h7x_flash_bank *stm32x_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; stm32x_info = malloc(sizeof(struct stm32h7x_flash_bank)); bank->driver_priv = stm32x_info; stm32x_info->probed = false; stm32x_info->user_bank_size = bank->size; return ERROR_OK; } static inline uint32_t stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset) { struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; return reg_offset + stm32x_info->flash_regs_base; } static inline int stm32x_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value) { uint32_t reg_addr = stm32x_get_flash_reg(bank, reg_offset); int retval = target_read_u32(bank->target, reg_addr, value); if (retval != ERROR_OK) LOG_ERROR("error while reading from address 0x%" PRIx32, reg_addr); return retval; } static inline int stm32x_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) { uint32_t reg_addr = stm32x_get_flash_reg(bank, reg_offset); int retval = target_write_u32(bank->target, reg_addr, value); if (retval != ERROR_OK) LOG_ERROR("error while writing to address 0x%" PRIx32, reg_addr); return retval; } static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status) { return stm32x_read_flash_reg(bank, FLASH_SR, status); } static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout) { uint32_t status; int retval; /* wait for flash operations completion */ for (;;) { retval = stm32x_get_flash_status(bank, &status); if (retval != ERROR_OK) return retval; if ((status & FLASH_QW) == 0) break; if (timeout-- <= 0) { LOG_ERROR("wait_flash_op_queue, time out expired, status: 0x%" PRIx32, status); return ERROR_FAIL; } alive_sleep(1); } if (status & FLASH_WRPERR) { LOG_ERROR("wait_flash_op_queue, WRPERR detected"); retval = ERROR_FAIL; } /* Clear error + EOP flags but report errors */ if (status & FLASH_ERROR) { if (retval == ERROR_OK) retval = ERROR_FAIL; /* If this operation fails, we ignore it and report the original retval */ stm32x_write_flash_reg(bank, FLASH_CCR, status); } return retval; } static int stm32x_unlock_reg(struct flash_bank *bank) { uint32_t ctrl; /* first check if not already unlocked * otherwise writing on FLASH_KEYR will fail */ int retval = stm32x_read_flash_reg(bank, FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; if ((ctrl & FLASH_LOCK) == 0) return ERROR_OK; /* unlock flash registers for bank */ retval = stm32x_write_flash_reg(bank, FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; retval = stm32x_write_flash_reg(bank, FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; retval = stm32x_read_flash_reg(bank, FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; if (ctrl & FLASH_LOCK) { LOG_ERROR("flash not unlocked STM32_FLASH_CRx: 0x%" PRIx32, ctrl); return ERROR_TARGET_FAILURE; } return ERROR_OK; } static int stm32x_unlock_option_reg(struct flash_bank *bank) { uint32_t ctrl; int retval = stm32x_read_flash_reg(bank, FLASH_OPTCR, &ctrl); if (retval != ERROR_OK) return retval; if ((ctrl & OPT_LOCK) == 0) return ERROR_OK; /* unlock option registers */ retval = stm32x_write_flash_reg(bank, FLASH_OPTKEYR, OPTKEY1); if (retval != ERROR_OK) return retval; retval = stm32x_write_flash_reg(bank, FLASH_OPTKEYR, OPTKEY2); if (retval != ERROR_OK) return retval; retval = stm32x_read_flash_reg(bank, FLASH_OPTCR, &ctrl); if (retval != ERROR_OK) return retval; if (ctrl & OPT_LOCK) { LOG_ERROR("options not unlocked STM32_FLASH_OPTCR: 0x%" PRIx32, ctrl); return ERROR_TARGET_FAILURE; } return ERROR_OK; } static inline int stm32x_lock_reg(struct flash_bank *bank) { return stm32x_write_flash_reg(bank, FLASH_CR, FLASH_LOCK); } static inline int stm32x_lock_option_reg(struct flash_bank *bank) { return stm32x_write_flash_reg(bank, FLASH_OPTCR, OPT_LOCK); } static int stm32x_write_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) { int retval, retval2; /* unlock option bytes for modification */ retval = stm32x_unlock_option_reg(bank); if (retval != ERROR_OK) goto flash_options_lock; /* write option bytes */ retval = stm32x_write_flash_reg(bank, reg_offset, value); if (retval != ERROR_OK) goto flash_options_lock; /* Remove OPT error flag before programming */ retval = stm32x_write_flash_reg(bank, FLASH_OPTCCR, OPT_CLR_OPTCHANGEERR); if (retval != ERROR_OK) goto flash_options_lock; /* start programming cycle */ retval = stm32x_write_flash_reg(bank, FLASH_OPTCR, OPT_START); if (retval != ERROR_OK) goto flash_options_lock; /* wait for completion */ int timeout = FLASH_ERASE_TIMEOUT; uint32_t status; for (;;) { retval = stm32x_read_flash_reg(bank, FLASH_OPTSR_CUR, &status); if (retval != ERROR_OK) { LOG_ERROR("stm32x_options_program: failed to read FLASH_OPTSR_CUR"); goto flash_options_lock; } if ((status & OPT_BSY) == 0) break; if (timeout-- <= 0) { LOG_ERROR("waiting for OBL launch, time out expired, OPTSR: 0x%" PRIx32, status); retval = ERROR_FAIL; goto flash_options_lock; } alive_sleep(1); } /* check for failure */ if (status & OPT_OPTCHANGEERR) { LOG_ERROR("error changing option bytes (OPTCHANGEERR=1)"); retval = ERROR_FLASH_OPERATION_FAILED; } flash_options_lock: retval2 = stm32x_lock_option_reg(bank); if (retval2 != ERROR_OK) LOG_ERROR("error during the lock of flash options"); return (retval == ERROR_OK) ? retval2 : retval; } static int stm32x_modify_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value, uint32_t mask) { uint32_t data; int retval = stm32x_read_flash_reg(bank, reg_offset, &data); if (retval != ERROR_OK) return retval; data = (data & ~mask) | (value & mask); return stm32x_write_option(bank, reg_offset, data); } static int stm32x_protect_check(struct flash_bank *bank) { uint32_t protection; /* read 'write protection' settings */ int retval = stm32x_read_flash_reg(bank, FLASH_WPSN_CUR, &protection); if (retval != ERROR_OK) { LOG_DEBUG("unable to read WPSN_CUR register"); return retval; } for (unsigned int i = 0; i < bank->num_prot_blocks; i++) bank->prot_blocks[i].is_protected = protection & (1 << i) ? 0 : 1; return ERROR_OK; } static int stm32x_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; int retval, retval2; assert(first < bank->num_sectors); assert(last < bank->num_sectors); if (bank->target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = stm32x_unlock_reg(bank); if (retval != ERROR_OK) goto flash_lock; /* Sector Erase To erase a sector, follow the procedure below: 1. Check that no Flash memory operation is ongoing by checking the QW bit in the FLASH_SR register 2. Set the SER bit and select the sector you wish to erase (SNB) in the FLASH_CR register 3. Set the STRT bit in the FLASH_CR register 4. Wait for flash operations completion */ for (unsigned int i = first; i <= last; i++) { LOG_DEBUG("erase sector %u", i); retval = stm32x_write_flash_reg(bank, FLASH_CR, stm32x_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64, i)); if (retval != ERROR_OK) { LOG_ERROR("Error erase sector %u", i); goto flash_lock; } retval = stm32x_write_flash_reg(bank, FLASH_CR, stm32x_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64 | FLASH_START, i)); if (retval != ERROR_OK) { LOG_ERROR("Error erase sector %u", i); goto flash_lock; } retval = stm32x_wait_flash_op_queue(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) { LOG_ERROR("erase time-out or operation error sector %u", i); goto flash_lock; } } flash_lock: retval2 = stm32x_lock_reg(bank); if (retval2 != ERROR_OK) LOG_ERROR("error during the lock of flash"); return (retval == ERROR_OK) ? retval2 : retval; } static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct target *target = bank->target; struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; uint32_t protection; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* read 'write protection' settings */ int retval = stm32x_read_flash_reg(bank, FLASH_WPSN_CUR, &protection); if (retval != ERROR_OK) { LOG_DEBUG("unable to read WPSN_CUR register"); return retval; } for (unsigned int i = first; i <= last; i++) { if (set) protection &= ~(1 << i); else protection |= (1 << i); } /* apply WRPSN mask */ protection &= stm32x_info->part_info->wps_mask; LOG_DEBUG("stm32x_protect, option_bytes written WPSN 0x%" PRIx32, protection); /* apply new option value */ return stm32x_write_option(bank, FLASH_WPSN_PRG, protection); } static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; /* * If the size of the data part of the buffer is not a multiple of .block_size, we get * "corrupted fifo read" pointer in target_run_flash_async_algorithm() */ uint32_t data_size = 512 * stm32x_info->part_info->block_size; uint32_t buffer_size = 8 + data_size; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; static const uint8_t stm32x_flash_write_code[] = { #include "../../../contrib/loaders/flash/stm32/stm32h7x.inc" }; if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { data_size /= 2; buffer_size = 8 + data_size; if (data_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } LOG_DEBUG("target_alloc_working_area_try : buffer_size -> 0x%" PRIx32, buffer_size); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count of words (word size = .block_size (bytes) */ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* word size in bytes */ init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* flash reg base */ buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[3].value, 0, 32, count); buf_set_u32(reg_params[4].value, 0, 32, stm32x_info->part_info->block_size); buf_set_u32(reg_params[5].value, 0, 32, stm32x_info->flash_regs_base); retval = target_run_flash_async_algorithm(target, buffer, count, stm32x_info->part_info->block_size, 0, NULL, ARRAY_SIZE(reg_params), reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("error executing stm32h7x flash write algorithm"); uint32_t flash_sr = buf_get_u32(reg_params[0].value, 0, 32); if (flash_sr & FLASH_WRPERR) LOG_ERROR("flash memory write protected"); if ((flash_sr & FLASH_ERROR) != 0) { LOG_ERROR("flash write failed, FLASH_SR = 0x%08" PRIx32, flash_sr); /* Clear error + EOP flags but report errors */ stm32x_write_flash_reg(bank, FLASH_CCR, flash_sr); retval = ERROR_FAIL; } } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); return retval; } static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; uint32_t address = bank->base + offset; int retval, retval2; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* should be enforced via bank->write_start_alignment */ assert(!(offset % stm32x_info->part_info->block_size)); /* should be enforced via bank->write_end_alignment */ assert(!(count % stm32x_info->part_info->block_size)); retval = stm32x_unlock_reg(bank); if (retval != ERROR_OK) goto flash_lock; uint32_t blocks_remaining = count / stm32x_info->part_info->block_size; /* multiple words (n * .block_size) to be programmed in block */ if (blocks_remaining) { retval = stm32x_write_block(bank, buffer, offset, blocks_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) dword accesses */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); } } else { buffer += blocks_remaining * stm32x_info->part_info->block_size; address += blocks_remaining * stm32x_info->part_info->block_size; blocks_remaining = 0; } if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)) goto flash_lock; } /* Standard programming The Flash memory programming sequence is as follows: 1. Check that no main Flash memory operation is ongoing by checking the QW bit in the FLASH_SR register. 2. Set the PG bit in the FLASH_CR register 3. 8 x Word access (or Force Write FW) 4. Wait for flash operations completion */ while (blocks_remaining > 0) { retval = stm32x_write_flash_reg(bank, FLASH_CR, stm32x_info->part_info->compute_flash_cr(FLASH_PG | FLASH_PSIZE_64, 0)); if (retval != ERROR_OK) goto flash_lock; retval = target_write_buffer(target, address, stm32x_info->part_info->block_size, buffer); if (retval != ERROR_OK) goto flash_lock; retval = stm32x_wait_flash_op_queue(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) goto flash_lock; buffer += stm32x_info->part_info->block_size; address += stm32x_info->part_info->block_size; blocks_remaining--; } flash_lock: retval2 = stm32x_lock_reg(bank); if (retval2 != ERROR_OK) LOG_ERROR("error during the lock of flash"); return (retval == ERROR_OK) ? retval2 : retval; } static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id) { /* read stm32 device id register */ int retval = target_read_u32(bank->target, DBGMCU_IDCODE_REGISTER, id); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32x_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; uint16_t flash_size_in_kb; uint32_t device_id; stm32x_info->probed = false; stm32x_info->part_info = NULL; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_TARGET_NOT_EXAMINED; } int retval = stm32x_read_id_code(bank, &stm32x_info->idcode); if (retval != ERROR_OK) return retval; LOG_DEBUG("device id = 0x%08" PRIx32, stm32x_info->idcode); device_id = stm32x_info->idcode & 0xfff; for (unsigned int n = 0; n < ARRAY_SIZE(stm32h7x_parts); n++) { if (device_id == stm32h7x_parts[n].id) stm32x_info->part_info = &stm32h7x_parts[n]; } if (!stm32x_info->part_info) { LOG_WARNING("Cannot identify target as a STM32H7xx family."); return ERROR_FAIL; } else { LOG_INFO("Device: %s", stm32x_info->part_info->device_str); } /* update the address of controller */ if (bank->base == FLASH_BANK0_ADDRESS) stm32x_info->flash_regs_base = FLASH_REG_BASE_B0; else if (bank->base == FLASH_BANK1_ADDRESS) stm32x_info->flash_regs_base = FLASH_REG_BASE_B1; else { LOG_WARNING("Flash register base not defined for bank %u", bank->bank_number); return ERROR_FAIL; } LOG_DEBUG("flash_regs_base: 0x%" PRIx32, stm32x_info->flash_regs_base); /* get flash size from target */ /* STM32H74x/H75x, the second core (Cortex-M4) cannot read the flash size */ retval = ERROR_FAIL; if (device_id == DEVID_STM32H74_H75XX && cortex_m_get_partno_safe(target) == CORTEX_M4_PARTNO) LOG_WARNING("%s cannot read the flash size register", target_name(target)); else retval = target_read_u16(target, stm32x_info->part_info->fsize_addr, &flash_size_in_kb); if (retval != ERROR_OK) { /* read error when device has invalid value, set max flash size */ flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb; LOG_INFO("assuming %" PRIu16 "k flash", flash_size_in_kb); } else LOG_INFO("flash size probed value %" PRIu16 "k", flash_size_in_kb); /* setup bank size */ const uint32_t bank1_base = FLASH_BANK0_ADDRESS; const uint32_t bank2_base = bank1_base + stm32x_info->part_info->max_bank_size_kb * 1024; bool has_dual_bank = stm32x_info->part_info->has_dual_bank; switch (device_id) { case DEVID_STM32H74_H75XX: case DEVID_STM32H7A_H7BXX: /* For STM32H74x/75x and STM32H7Ax/Bx * - STM32H7xxxI devices contains dual bank, 1 Mbyte each * - STM32H7xxxG devices contains dual bank, 512 Kbyte each * - STM32H7xxxB devices contains single bank, 128 Kbyte * - the second bank starts always from 0x08100000 */ if (flash_size_in_kb == 128) has_dual_bank = false; else /* flash size is 2M or 1M */ flash_size_in_kb /= 2; break; case DEVID_STM32H72_H73XX: break; default: LOG_ERROR("unsupported device"); return ERROR_FAIL; } if (has_dual_bank) { LOG_INFO("STM32H7 flash has dual banks"); if (bank->base != bank1_base && bank->base != bank2_base) { LOG_ERROR("STM32H7 flash bank base address config is incorrect. " TARGET_ADDR_FMT " but should rather be 0x%" PRIx32 " or 0x%" PRIx32, bank->base, bank1_base, bank2_base); return ERROR_FAIL; } } else { LOG_INFO("STM32H7 flash has a single bank"); if (bank->base == bank2_base) { LOG_ERROR("this device has a single bank only"); return ERROR_FAIL; } else if (bank->base != bank1_base) { LOG_ERROR("STM32H7 flash bank base address config is incorrect. " TARGET_ADDR_FMT " but should be 0x%" PRIx32, bank->base, bank1_base); return ERROR_FAIL; } } LOG_INFO("Bank (%u) size is %" PRIu16 " kb, base address is " TARGET_ADDR_FMT, bank->bank_number, flash_size_in_kb, bank->base); /* if the user sets the size manually then ignore the probed value * this allows us to work around devices that have an invalid flash size register value */ if (stm32x_info->user_bank_size) { LOG_INFO("ignoring flash probed value, using configured bank size"); flash_size_in_kb = stm32x_info->user_bank_size / 1024; } else if (flash_size_in_kb == 0xffff) { /* die flash size */ flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb; } /* did we assign flash size? */ assert(flash_size_in_kb != 0xffff); bank->size = flash_size_in_kb * 1024; bank->write_start_alignment = stm32x_info->part_info->block_size; bank->write_end_alignment = stm32x_info->part_info->block_size; /* setup sectors */ bank->num_sectors = flash_size_in_kb / stm32x_info->part_info->page_size_kb; assert(bank->num_sectors > 0); free(bank->sectors); bank->sectors = alloc_block_array(0, stm32x_info->part_info->page_size_kb * 1024, bank->num_sectors); if (!bank->sectors) { LOG_ERROR("failed to allocate bank sectors"); return ERROR_FAIL; } /* setup protection blocks */ const uint32_t wpsn = stm32x_info->part_info->wps_group_size; assert(bank->num_sectors % wpsn == 0); bank->num_prot_blocks = bank->num_sectors / wpsn; assert(bank->num_prot_blocks > 0); free(bank->prot_blocks); bank->prot_blocks = alloc_block_array(0, stm32x_info->part_info->page_size_kb * wpsn * 1024, bank->num_prot_blocks); if (!bank->prot_blocks) { LOG_ERROR("failed to allocate bank prot_block"); return ERROR_FAIL; } stm32x_info->probed = true; return ERROR_OK; } static int stm32x_auto_probe(struct flash_bank *bank) { struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; if (stm32x_info->probed) return ERROR_OK; return stm32x_probe(bank); } /* This method must return a string displaying information about the bank */ static int stm32x_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; const struct stm32h7x_part_info *info = stm32x_info->part_info; if (!stm32x_info->probed) { int retval = stm32x_probe(bank); if (retval != ERROR_OK) { command_print_sameline(cmd, "Unable to find bank information."); return retval; } } if (info) { const char *rev_str = NULL; uint16_t rev_id = stm32x_info->idcode >> 16; for (unsigned int i = 0; i < info->num_revs; i++) if (rev_id == info->revs[i].rev) rev_str = info->revs[i].str; if (rev_str) { command_print_sameline(cmd, "%s - Rev: %s", stm32x_info->part_info->device_str, rev_str); } else { command_print_sameline(cmd, "%s - Rev: unknown (0x%04" PRIx16 ")", stm32x_info->part_info->device_str, rev_id); } } else { command_print_sameline(cmd, "Cannot identify target as a STM32H7x"); return ERROR_FAIL; } return ERROR_OK; } static int stm32x_set_rdp(struct flash_bank *bank, enum stm32h7x_opt_rdp new_rdp) { struct target *target = bank->target; uint32_t optsr, cur_rdp; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = stm32x_read_flash_reg(bank, FLASH_OPTSR_PRG, &optsr); if (retval != ERROR_OK) { LOG_DEBUG("unable to read FLASH_OPTSR_PRG register"); return retval; } /* get current RDP, and check if there is a change */ cur_rdp = (optsr & OPT_RDP_MASK) >> OPT_RDP_POS; if (new_rdp == cur_rdp) { LOG_INFO("the requested RDP value is already programmed"); return ERROR_OK; } switch (new_rdp) { case OPT_RDP_L0: LOG_WARNING("unlocking the entire flash device"); break; case OPT_RDP_L1: LOG_WARNING("locking the entire flash device"); break; case OPT_RDP_L2: LOG_WARNING("locking the entire flash device, irreversible"); break; } /* apply new RDP */ optsr = (optsr & ~OPT_RDP_MASK) | (new_rdp << OPT_RDP_POS); /* apply new option value */ return stm32x_write_option(bank, FLASH_OPTSR_PRG, optsr); } COMMAND_HANDLER(stm32x_handle_lock_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = stm32x_set_rdp(bank, OPT_RDP_L1); if (retval != ERROR_OK) command_print(CMD, "%s failed to lock device", bank->driver->name); else command_print(CMD, "%s locked", bank->driver->name); return retval; } COMMAND_HANDLER(stm32x_handle_unlock_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = stm32x_set_rdp(bank, OPT_RDP_L0); if (retval != ERROR_OK) command_print(CMD, "%s failed to unlock device", bank->driver->name); else command_print(CMD, "%s unlocked", bank->driver->name); return retval; } static int stm32x_mass_erase(struct flash_bank *bank) { int retval, retval2; struct target *target = bank->target; struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = stm32x_unlock_reg(bank); if (retval != ERROR_OK) goto flash_lock; /* mass erase flash memory bank */ retval = stm32x_write_flash_reg(bank, FLASH_CR, stm32x_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64, 0)); if (retval != ERROR_OK) goto flash_lock; retval = stm32x_write_flash_reg(bank, FLASH_CR, stm32x_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64 | FLASH_START, 0)); if (retval != ERROR_OK) goto flash_lock; retval = stm32x_wait_flash_op_queue(bank, 30000); if (retval != ERROR_OK) goto flash_lock; flash_lock: retval2 = stm32x_lock_reg(bank); if (retval2 != ERROR_OK) LOG_ERROR("error during the lock of flash"); return (retval == ERROR_OK) ? retval2 : retval; } COMMAND_HANDLER(stm32x_handle_mass_erase_command) { if (CMD_ARGC < 1) { command_print(CMD, "stm32h7x mass_erase <bank>"); return ERROR_COMMAND_SYNTAX_ERROR; } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = stm32x_mass_erase(bank); if (retval == ERROR_OK) command_print(CMD, "stm32h7x mass erase complete"); else command_print(CMD, "stm32h7x mass erase failed"); return retval; } COMMAND_HANDLER(stm32x_handle_option_read_command) { if (CMD_ARGC < 2) { command_print(CMD, "stm32h7x option_read <bank> <option_reg offset>"); return ERROR_COMMAND_SYNTAX_ERROR; } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; uint32_t reg_offset, value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset); retval = stm32x_read_flash_reg(bank, reg_offset, &value); if (retval != ERROR_OK) return retval; command_print(CMD, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32, stm32x_get_flash_reg(bank, reg_offset), value); return retval; } COMMAND_HANDLER(stm32x_handle_option_write_command) { if (CMD_ARGC < 3) { command_print(CMD, "stm32h7x option_write <bank> <option_reg offset> <value> [mask]"); return ERROR_COMMAND_SYNTAX_ERROR; } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; uint32_t reg_offset, value, mask = 0xffffffff; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); if (CMD_ARGC > 3) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], mask); return stm32x_modify_option(bank, reg_offset, value, mask); } static const struct command_registration stm32h7x_exec_command_handlers[] = { { .name = "lock", .handler = stm32x_handle_lock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Lock entire flash device.", }, { .name = "unlock", .handler = stm32x_handle_unlock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Unlock entire protected flash device.", }, { .name = "mass_erase", .handler = stm32x_handle_mass_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Erase entire flash device.", }, { .name = "option_read", .handler = stm32x_handle_option_read_command, .mode = COMMAND_EXEC, .usage = "bank_id reg_offset", .help = "Read and display device option bytes.", }, { .name = "option_write", .handler = stm32x_handle_option_write_command, .mode = COMMAND_EXEC, .usage = "bank_id reg_offset value [mask]", .help = "Write device option bit fields with provided value.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration stm32h7x_command_handlers[] = { { .name = "stm32h7x", .mode = COMMAND_ANY, .help = "stm32h7x flash command group", .usage = "", .chain = stm32h7x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver stm32h7x_flash = { .name = "stm32h7x", .commands = stm32h7x_command_handlers, .flash_bank_command = stm32x_flash_bank_command, .erase = stm32x_erase, .protect = stm32x_protect, .write = stm32x_write, .read = default_flash_read, .probe = stm32x_probe, .auto_probe = stm32x_auto_probe, .erase_check = default_flash_blank_check, .protect_check = stm32x_protect_check, .info = stm32x_get_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/stm32l4x.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2015 by Uwe Bonnes * * bon@elektron.ikp.physik.tu-darmstadt.de * * * * Copyright (C) 2019 by Tarek Bochkati for STMicroelectronics * * tarek.bouchkati@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/align.h> #include <helper/binarybuffer.h> #include <helper/bits.h> #include <target/algorithm.h> #include <target/arm_adi_v5.h> #include <target/cortex_m.h> #include "stm32l4x.h" /* STM32L4xxx series for reference. * * RM0351 (STM32L4x5/STM32L4x6) * http://www.st.com/resource/en/reference_manual/dm00083560.pdf * * RM0394 (STM32L43x/44x/45x/46x) * http://www.st.com/resource/en/reference_manual/dm00151940.pdf * * RM0432 (STM32L4R/4Sxx) * http://www.st.com/resource/en/reference_manual/dm00310109.pdf * * STM32L476RG Datasheet (for erase timing) * http://www.st.com/resource/en/datasheet/stm32l476rg.pdf * * The RM0351 devices have normally two banks, but on 512 and 256 kiB devices * an option byte is available to map all sectors to the first bank. * Both STM32 banks are treated as one OpenOCD bank, as other STM32 devices * handlers do! * * RM0394 devices have a single bank only. * * RM0432 devices have single and dual bank operating modes. * - for STM32L4R/Sxx the FLASH size is 2Mbyte or 1Mbyte. * - for STM32L4P/Q5x the FLASH size is 1Mbyte or 512Kbyte. * Bank page (sector) size is 4Kbyte (dual mode) or 8Kbyte (single mode). * * Bank mode is controlled by two different bits in option bytes register. * - for STM32L4R/Sxx * In 2M FLASH devices bit 22 (DBANK) controls Dual Bank mode. * In 1M FLASH devices bit 21 (DB1M) controls Dual Bank mode. * - for STM32L4P5/Q5x * In 1M FLASH devices bit 22 (DBANK) controls Dual Bank mode. * In 512K FLASH devices bit 21 (DB512K) controls Dual Bank mode. */ /* STM32WBxxx series for reference. * * RM0434 (STM32WB55/WB35x) * http://www.st.com/resource/en/reference_manual/dm00318631.pdf * * RM0471 (STM32WB50/WB30x) * http://www.st.com/resource/en/reference_manual/dm00622834.pdf * * RM0473 (STM32WB15x) * http://www.st.com/resource/en/reference_manual/dm00649196.pdf * * RM0478 (STM32WB10x) * http://www.st.com/resource/en/reference_manual/dm00689203.pdf */ /* STM32WLxxx series for reference. * * RM0461 (STM32WLEx) * http://www.st.com/resource/en/reference_manual/dm00530369.pdf * * RM0453 (STM32WL5x) * http://www.st.com/resource/en/reference_manual/dm00451556.pdf */ /* STM32C0xxx series for reference. * * RM0490 (STM32C0x1) * http://www.st.com/resource/en/reference_manual/dm00781702.pdf */ /* STM32G0xxx series for reference. * * RM0444 (STM32G0x1) * http://www.st.com/resource/en/reference_manual/dm00371828.pdf * * RM0454 (STM32G0x0) * http://www.st.com/resource/en/reference_manual/dm00463896.pdf */ /* STM32G4xxx series for reference. * * RM0440 (STM32G43x/44x/47x/48x/49x/4Ax) * http://www.st.com/resource/en/reference_manual/dm00355726.pdf * * Cat. 2 devices have single bank only, page size is 2kByte. * * Cat. 3 devices have single and dual bank operating modes, * Page size is 2kByte (dual mode) or 4kByte (single mode). * * Bank mode is controlled by bit 22 (DBANK) in option bytes register. * Both banks are treated as a single OpenOCD bank. * * Cat. 4 devices have single bank only, page size is 2kByte. */ /* STM32L5xxx series for reference. * * RM0428 (STM32L552xx/STM32L562xx) * http://www.st.com/resource/en/reference_manual/dm00346336.pdf */ /* Erase time can be as high as 25ms, 10x this and assume it's toast... */ #define FLASH_ERASE_TIMEOUT 250 #define FLASH_WRITE_TIMEOUT 50 /* relevant STM32L4 flags ****************************************************/ #define F_NONE 0 /* this flag indicates if the device flash is with dual bank architecture */ #define F_HAS_DUAL_BANK BIT(0) /* this flags is used for dual bank devices only, it indicates if the * 4 WRPxx are usable if the device is configured in single-bank mode */ #define F_USE_ALL_WRPXX BIT(1) /* this flag indicates if the device embeds a TrustZone security feature */ #define F_HAS_TZ BIT(2) /* this flag indicates if the device has the same flash registers as STM32L5 */ #define F_HAS_L5_FLASH_REGS BIT(3) /* this flag indicates that programming should be done in quad-word * the default programming word size is double-word */ #define F_QUAD_WORD_PROG BIT(4) /* end of STM32L4 flags ******************************************************/ enum stm32l4_flash_reg_index { STM32_FLASH_ACR_INDEX, STM32_FLASH_KEYR_INDEX, STM32_FLASH_OPTKEYR_INDEX, STM32_FLASH_SR_INDEX, STM32_FLASH_CR_INDEX, /* for some devices like STM32WL5x, the CPU2 have a dedicated C2CR register w/o LOCKs, * so it uses the C2CR for flash operations and CR for checking locks and locking */ STM32_FLASH_CR_WLK_INDEX, /* FLASH_CR_WITH_LOCK */ STM32_FLASH_OPTR_INDEX, STM32_FLASH_WRP1AR_INDEX, STM32_FLASH_WRP1BR_INDEX, STM32_FLASH_WRP2AR_INDEX, STM32_FLASH_WRP2BR_INDEX, STM32_FLASH_REG_INDEX_NUM, }; enum stm32l4_rdp { RDP_LEVEL_0 = 0xAA, RDP_LEVEL_0_5 = 0x55, /* for devices with TrustZone enabled */ RDP_LEVEL_1 = 0x00, RDP_LEVEL_2 = 0xCC }; static const uint32_t stm32l4_flash_regs[STM32_FLASH_REG_INDEX_NUM] = { [STM32_FLASH_ACR_INDEX] = 0x000, [STM32_FLASH_KEYR_INDEX] = 0x008, [STM32_FLASH_OPTKEYR_INDEX] = 0x00C, [STM32_FLASH_SR_INDEX] = 0x010, [STM32_FLASH_CR_INDEX] = 0x014, [STM32_FLASH_OPTR_INDEX] = 0x020, [STM32_FLASH_WRP1AR_INDEX] = 0x02C, [STM32_FLASH_WRP1BR_INDEX] = 0x030, [STM32_FLASH_WRP2AR_INDEX] = 0x04C, [STM32_FLASH_WRP2BR_INDEX] = 0x050, }; static const uint32_t stm32wl_cpu2_flash_regs[STM32_FLASH_REG_INDEX_NUM] = { [STM32_FLASH_ACR_INDEX] = 0x000, [STM32_FLASH_KEYR_INDEX] = 0x008, [STM32_FLASH_OPTKEYR_INDEX] = 0x010, [STM32_FLASH_SR_INDEX] = 0x060, [STM32_FLASH_CR_INDEX] = 0x064, [STM32_FLASH_CR_WLK_INDEX] = 0x014, [STM32_FLASH_OPTR_INDEX] = 0x020, [STM32_FLASH_WRP1AR_INDEX] = 0x02C, [STM32_FLASH_WRP1BR_INDEX] = 0x030, }; static const uint32_t stm32l5_ns_flash_regs[STM32_FLASH_REG_INDEX_NUM] = { [STM32_FLASH_ACR_INDEX] = 0x000, [STM32_FLASH_KEYR_INDEX] = 0x008, /* NSKEYR */ [STM32_FLASH_OPTKEYR_INDEX] = 0x010, [STM32_FLASH_SR_INDEX] = 0x020, /* NSSR */ [STM32_FLASH_CR_INDEX] = 0x028, /* NSCR */ [STM32_FLASH_OPTR_INDEX] = 0x040, [STM32_FLASH_WRP1AR_INDEX] = 0x058, [STM32_FLASH_WRP1BR_INDEX] = 0x05C, [STM32_FLASH_WRP2AR_INDEX] = 0x068, [STM32_FLASH_WRP2BR_INDEX] = 0x06C, }; static const uint32_t stm32l5_s_flash_regs[STM32_FLASH_REG_INDEX_NUM] = { [STM32_FLASH_ACR_INDEX] = 0x000, [STM32_FLASH_KEYR_INDEX] = 0x00C, /* SECKEYR */ [STM32_FLASH_OPTKEYR_INDEX] = 0x010, [STM32_FLASH_SR_INDEX] = 0x024, /* SECSR */ [STM32_FLASH_CR_INDEX] = 0x02C, /* SECCR */ [STM32_FLASH_OPTR_INDEX] = 0x040, [STM32_FLASH_WRP1AR_INDEX] = 0x058, [STM32_FLASH_WRP1BR_INDEX] = 0x05C, [STM32_FLASH_WRP2AR_INDEX] = 0x068, [STM32_FLASH_WRP2BR_INDEX] = 0x06C, }; struct stm32l4_rev { const uint16_t rev; const char *str; }; struct stm32l4_part_info { uint16_t id; const char *device_str; const struct stm32l4_rev *revs; const size_t num_revs; const uint16_t max_flash_size_kb; const uint32_t flags; /* one bit per feature, see STM32L4 flags: macros F_XXX */ const uint32_t flash_regs_base; const uint32_t fsize_addr; const uint32_t otp_base; const uint32_t otp_size; }; struct stm32l4_flash_bank { bool probed; uint32_t idcode; unsigned int bank1_sectors; bool dual_bank_mode; int hole_sectors; uint32_t user_bank_size; uint32_t data_width; uint32_t cr_bker_mask; uint32_t sr_bsy_mask; uint32_t wrpxxr_mask; const struct stm32l4_part_info *part_info; uint32_t flash_regs_base; const uint32_t *flash_regs; bool otp_enabled; enum stm32l4_rdp rdp; bool tzen; uint32_t optr; }; enum stm32_bank_id { STM32_BANK1, STM32_BANK2, STM32_ALL_BANKS }; struct stm32l4_wrp { enum stm32l4_flash_reg_index reg_idx; uint32_t value; bool used; int first; int last; int offset; }; /* human readable list of families this drivers supports (sorted alphabetically) */ static const char *device_families = "STM32C0/G0/G4/L4/L4+/L5/U5/WB/WL"; static const struct stm32l4_rev stm32l47_l48xx_revs[] = { { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" } }; static const struct stm32l4_rev stm32l43_l44xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; static const struct stm32l4_rev stm32c01xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, }; static const struct stm32l4_rev stm32c03xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, }; static const struct stm32l4_rev stm32g05_g06xx_revs[] = { { 0x1000, "A" }, }; static const struct stm32l4_rev stm32_g07_g08xx_revs[] = { { 0x1000, "A/Z" } /* A and Z, no typo in RM! */, { 0x2000, "B" }, }; static const struct stm32l4_rev stm32l49_l4axx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, }; static const struct stm32l4_rev stm32l45_l46xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; static const struct stm32l4_rev stm32l41_l42xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; static const struct stm32l4_rev stm32g03_g04xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2000, "B" }, }; static const struct stm32l4_rev stm32g0b_g0cxx_revs[] = { { 0x1000, "A" }, }; static const struct stm32l4_rev stm32g43_g44xx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, }; static const struct stm32l4_rev stm32g47_g48xx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, }; static const struct stm32l4_rev stm32l4r_l4sxx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x100F, "W" }, { 0x101F, "V" }, }; static const struct stm32l4_rev stm32l4p_l4qxx_revs[] = { { 0x1001, "Z" }, }; static const struct stm32l4_rev stm32l55_l56xx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, }; static const struct stm32l4_rev stm32g49_g4axx_revs[] = { { 0x1000, "A" }, }; static const struct stm32l4_rev stm32u57_u58xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2000, "B" }, { 0x2001, "X" }, { 0x3000, "C" }, }; static const struct stm32l4_rev stm32wb1xx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, }; static const struct stm32l4_rev stm32wb5xx_revs[] = { { 0x2001, "2.1" }, }; static const struct stm32l4_rev stm32wb3xx_revs[] = { { 0x1000, "A" }, }; static const struct stm32l4_rev stm32wle_wl5xx_revs[] = { { 0x1000, "1.0" }, }; static const struct stm32l4_part_info stm32l4_parts[] = { { .id = DEVID_STM32L47_L48XX, .revs = stm32l47_l48xx_revs, .num_revs = ARRAY_SIZE(stm32l47_l48xx_revs), .device_str = "STM32L47/L48xx", .max_flash_size_kb = 1024, .flags = F_HAS_DUAL_BANK, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32L43_L44XX, .revs = stm32l43_l44xx_revs, .num_revs = ARRAY_SIZE(stm32l43_l44xx_revs), .device_str = "STM32L43/L44xx", .max_flash_size_kb = 256, .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32C01XX, .revs = stm32c01xx_revs, .num_revs = ARRAY_SIZE(stm32c01xx_revs), .device_str = "STM32C01xx", .max_flash_size_kb = 32, .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75A0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32C03XX, .revs = stm32c03xx_revs, .num_revs = ARRAY_SIZE(stm32c03xx_revs), .device_str = "STM32C03xx", .max_flash_size_kb = 32, .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75A0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32G05_G06XX, .revs = stm32g05_g06xx_revs, .num_revs = ARRAY_SIZE(stm32g05_g06xx_revs), .device_str = "STM32G05/G06xx", .max_flash_size_kb = 64, .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32G07_G08XX, .revs = stm32_g07_g08xx_revs, .num_revs = ARRAY_SIZE(stm32_g07_g08xx_revs), .device_str = "STM32G07/G08xx", .max_flash_size_kb = 128, .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32L49_L4AXX, .revs = stm32l49_l4axx_revs, .num_revs = ARRAY_SIZE(stm32l49_l4axx_revs), .device_str = "STM32L49/L4Axx", .max_flash_size_kb = 1024, .flags = F_HAS_DUAL_BANK, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32L45_L46XX, .revs = stm32l45_l46xx_revs, .num_revs = ARRAY_SIZE(stm32l45_l46xx_revs), .device_str = "STM32L45/L46xx", .max_flash_size_kb = 512, .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32L41_L42XX, .revs = stm32l41_l42xx_revs, .num_revs = ARRAY_SIZE(stm32l41_l42xx_revs), .device_str = "STM32L41/L42xx", .max_flash_size_kb = 128, .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32G03_G04XX, .revs = stm32g03_g04xx_revs, .num_revs = ARRAY_SIZE(stm32g03_g04xx_revs), .device_str = "STM32G03x/G04xx", .max_flash_size_kb = 64, .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32G0B_G0CXX, .revs = stm32g0b_g0cxx_revs, .num_revs = ARRAY_SIZE(stm32g0b_g0cxx_revs), .device_str = "STM32G0B/G0Cx", .max_flash_size_kb = 512, .flags = F_HAS_DUAL_BANK, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32G43_G44XX, .revs = stm32g43_g44xx_revs, .num_revs = ARRAY_SIZE(stm32g43_g44xx_revs), .device_str = "STM32G43/G44xx", .max_flash_size_kb = 128, .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32G47_G48XX, .revs = stm32g47_g48xx_revs, .num_revs = ARRAY_SIZE(stm32g47_g48xx_revs), .device_str = "STM32G47/G48xx", .max_flash_size_kb = 512, .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32L4R_L4SXX, .revs = stm32l4r_l4sxx_revs, .num_revs = ARRAY_SIZE(stm32l4r_l4sxx_revs), .device_str = "STM32L4R/L4Sxx", .max_flash_size_kb = 2048, .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32L4P_L4QXX, .revs = stm32l4p_l4qxx_revs, .num_revs = ARRAY_SIZE(stm32l4p_l4qxx_revs), .device_str = "STM32L4P/L4Qxx", .max_flash_size_kb = 1024, .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32L55_L56XX, .revs = stm32l55_l56xx_revs, .num_revs = ARRAY_SIZE(stm32l55_l56xx_revs), .device_str = "STM32L55/L56xx", .max_flash_size_kb = 512, .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX | F_HAS_TZ | F_HAS_L5_FLASH_REGS, .flash_regs_base = 0x40022000, .fsize_addr = 0x0BFA05E0, .otp_base = 0x0BFA0000, .otp_size = 512, }, { .id = DEVID_STM32G49_G4AXX, .revs = stm32g49_g4axx_revs, .num_revs = ARRAY_SIZE(stm32g49_g4axx_revs), .device_str = "STM32G49/G4Axx", .max_flash_size_kb = 512, .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32U57_U58XX, .revs = stm32u57_u58xx_revs, .num_revs = ARRAY_SIZE(stm32u57_u58xx_revs), .device_str = "STM32U57/U58xx", .max_flash_size_kb = 2048, .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, .flash_regs_base = 0x40022000, .fsize_addr = 0x0BFA07A0, .otp_base = 0x0BFA0000, .otp_size = 512, }, { .id = DEVID_STM32WB1XX, .revs = stm32wb1xx_revs, .num_revs = ARRAY_SIZE(stm32wb1xx_revs), .device_str = "STM32WB1x", .max_flash_size_kb = 320, .flags = F_NONE, .flash_regs_base = 0x58004000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32WB5XX, .revs = stm32wb5xx_revs, .num_revs = ARRAY_SIZE(stm32wb5xx_revs), .device_str = "STM32WB5x", .max_flash_size_kb = 1024, .flags = F_NONE, .flash_regs_base = 0x58004000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32WB3XX, .revs = stm32wb3xx_revs, .num_revs = ARRAY_SIZE(stm32wb3xx_revs), .device_str = "STM32WB3x", .max_flash_size_kb = 512, .flags = F_NONE, .flash_regs_base = 0x58004000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, { .id = DEVID_STM32WLE_WL5XX, .revs = stm32wle_wl5xx_revs, .num_revs = ARRAY_SIZE(stm32wle_wl5xx_revs), .device_str = "STM32WLE/WL5x", .max_flash_size_kb = 256, .flags = F_NONE, .flash_regs_base = 0x58004000, .fsize_addr = 0x1FFF75E0, .otp_base = 0x1FFF7000, .otp_size = 1024, }, }; /* flash bank stm32l4x <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command) { struct stm32l4_flash_bank *stm32l4_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; /* fix-up bank base address: 0 is used for normal flash memory */ if (bank->base == 0) bank->base = STM32_FLASH_BANK_BASE; stm32l4_info = calloc(1, sizeof(struct stm32l4_flash_bank)); if (!stm32l4_info) return ERROR_FAIL; /* Checkme: What better error to use?*/ bank->driver_priv = stm32l4_info; stm32l4_info->probed = false; stm32l4_info->otp_enabled = false; stm32l4_info->user_bank_size = bank->size; return ERROR_OK; } /* bitmap helper extension */ struct range { unsigned int start; unsigned int end; }; static void bitmap_to_ranges(unsigned long *bitmap, unsigned int nbits, struct range *ranges, unsigned int *ranges_count) { *ranges_count = 0; bool last_bit = 0, cur_bit; for (unsigned int i = 0; i < nbits; i++) { cur_bit = test_bit(i, bitmap); if (cur_bit && !last_bit) { (*ranges_count)++; ranges[*ranges_count - 1].start = i; ranges[*ranges_count - 1].end = i; } else if (cur_bit && last_bit) { /* update (increment) the end this range */ ranges[*ranges_count - 1].end = i; } last_bit = cur_bit; } } static inline int range_print_one(struct range *range, char *str) { if (range->start == range->end) return sprintf(str, "[%d]", range->start); return sprintf(str, "[%d,%d]", range->start, range->end); } static char *range_print_alloc(struct range *ranges, unsigned int ranges_count) { /* each range will be printed like the following: [start,end] * start and end, both are unsigned int, an unsigned int takes 10 characters max * plus 3 characters for '[', ',' and ']' * thus means each range can take maximum 23 character * after each range we add a ' ' as separator and finally we need the '\0' * if the ranges_count is zero we reserve one char for '\0' to return an empty string */ char *str = calloc(1, ranges_count * (24 * sizeof(char)) + 1); char *ptr = str; for (unsigned int i = 0; i < ranges_count; i++) { ptr += range_print_one(&(ranges[i]), ptr); if (i < ranges_count - 1) *(ptr++) = ' '; } return str; } /* end of bitmap helper extension */ static inline bool stm32l4_is_otp(struct flash_bank *bank) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; return bank->base == stm32l4_info->part_info->otp_base; } static int stm32l4_otp_enable(struct flash_bank *bank, bool enable) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; if (!stm32l4_is_otp(bank)) return ERROR_FAIL; char *op_str = enable ? "enabled" : "disabled"; LOG_INFO("OTP memory (bank #%d) is %s%s for write commands", bank->bank_number, stm32l4_info->otp_enabled == enable ? "already " : "", op_str); stm32l4_info->otp_enabled = enable; return ERROR_OK; } static inline bool stm32l4_otp_is_enabled(struct flash_bank *bank) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; return stm32l4_info->otp_enabled; } static void stm32l4_sync_rdp_tzen(struct flash_bank *bank) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; bool tzen = false; if (stm32l4_info->part_info->flags & F_HAS_TZ) tzen = (stm32l4_info->optr & FLASH_TZEN) != 0; uint32_t rdp = stm32l4_info->optr & FLASH_RDP_MASK; /* for devices without TrustZone: * RDP level 0 and 2 values are to 0xAA and 0xCC * Any other value corresponds to RDP level 1 * for devices with TrusZone: * RDP level 0 and 2 values are 0xAA and 0xCC * RDP level 0.5 value is 0x55 only if TZEN = 1 * Any other value corresponds to RDP level 1, including 0x55 if TZEN = 0 */ if (rdp != RDP_LEVEL_0 && rdp != RDP_LEVEL_2) { if (!tzen || (tzen && rdp != RDP_LEVEL_0_5)) rdp = RDP_LEVEL_1; } stm32l4_info->tzen = tzen; stm32l4_info->rdp = rdp; } static inline uint32_t stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; return stm32l4_info->flash_regs_base + reg_offset; } static inline uint32_t stm32l4_get_flash_reg_by_index(struct flash_bank *bank, enum stm32l4_flash_reg_index reg_index) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; return stm32l4_get_flash_reg(bank, stm32l4_info->flash_regs[reg_index]); } static inline int stm32l4_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value) { return target_read_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value); } static inline int stm32l4_read_flash_reg_by_index(struct flash_bank *bank, enum stm32l4_flash_reg_index reg_index, uint32_t *value) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; return stm32l4_read_flash_reg(bank, stm32l4_info->flash_regs[reg_index], value); } static inline int stm32l4_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) { return target_write_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value); } static inline int stm32l4_write_flash_reg_by_index(struct flash_bank *bank, enum stm32l4_flash_reg_index reg_index, uint32_t value) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; return stm32l4_write_flash_reg(bank, stm32l4_info->flash_regs[reg_index], value); } static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; uint32_t status; int retval = ERROR_OK; /* wait for busy to clear */ for (;;) { retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, &status); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%" PRIx32 "", status); if ((status & stm32l4_info->sr_bsy_mask) == 0) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FAIL; } alive_sleep(1); } if (status & FLASH_WRPERR) { LOG_ERROR("stm32x device protected"); retval = ERROR_FAIL; } /* Clear but report errors */ if (status & FLASH_ERROR) { if (retval == ERROR_OK) retval = ERROR_FAIL; /* If this operation fails, we ignore it and report the original * retval */ stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, status & FLASH_ERROR); } return retval; } /** set all FLASH_SECBB registers to the same value */ static int stm32l4_set_secbb(struct flash_bank *bank, uint32_t value) { /* This function should be used only with device with TrustZone, do just a security check */ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; assert(stm32l4_info->part_info->flags & F_HAS_TZ); /* based on RM0438 Rev6 for STM32L5x devices: * to modify a page block-based security attribution, it is recommended to * 1- check that no flash operation is ongoing on the related page * 2- add ISB instruction after modifying the page security attribute in SECBBxRy * this step is not need in case of JTAG direct access */ int retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) return retval; /* write SECBBxRy registers */ LOG_DEBUG("setting secure block-based areas registers (SECBBxRy) to 0x%08x", value); const uint8_t secbb_regs[] = { FLASH_SECBB1(1), FLASH_SECBB1(2), FLASH_SECBB1(3), FLASH_SECBB1(4), /* bank 1 SECBB register offsets */ FLASH_SECBB2(1), FLASH_SECBB2(2), FLASH_SECBB2(3), FLASH_SECBB2(4) /* bank 2 SECBB register offsets */ }; unsigned int num_secbb_regs = ARRAY_SIZE(secbb_regs); /* in single bank mode, it's useless to modify FLASH_SECBB2Rx registers * then consider only the first half of secbb_regs */ if (!stm32l4_info->dual_bank_mode) num_secbb_regs /= 2; for (unsigned int i = 0; i < num_secbb_regs; i++) { retval = stm32l4_write_flash_reg(bank, secbb_regs[i], value); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static inline int stm32l4_get_flash_cr_with_lock_index(struct flash_bank *bank) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; return (stm32l4_info->flash_regs[STM32_FLASH_CR_WLK_INDEX]) ? STM32_FLASH_CR_WLK_INDEX : STM32_FLASH_CR_INDEX; } static int stm32l4_unlock_reg(struct flash_bank *bank) { const uint32_t flash_cr_index = stm32l4_get_flash_cr_with_lock_index(bank); uint32_t ctrl; /* first check if not already unlocked * otherwise writing on STM32_FLASH_KEYR will fail */ int retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl); if (retval != ERROR_OK) return retval; if ((ctrl & FLASH_LOCK) == 0) return ERROR_OK; /* unlock flash registers */ retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_KEYR_INDEX, KEY1); if (retval != ERROR_OK) return retval; retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_KEYR_INDEX, KEY2); if (retval != ERROR_OK) return retval; retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl); if (retval != ERROR_OK) return retval; if (ctrl & FLASH_LOCK) { LOG_ERROR("flash not unlocked STM32_FLASH_CR: %" PRIx32, ctrl); return ERROR_TARGET_FAILURE; } return ERROR_OK; } static int stm32l4_unlock_option_reg(struct flash_bank *bank) { const uint32_t flash_cr_index = stm32l4_get_flash_cr_with_lock_index(bank); uint32_t ctrl; int retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl); if (retval != ERROR_OK) return retval; if ((ctrl & FLASH_OPTLOCK) == 0) return ERROR_OK; /* unlock option registers */ retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_OPTKEYR_INDEX, OPTKEY1); if (retval != ERROR_OK) return retval; retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_OPTKEYR_INDEX, OPTKEY2); if (retval != ERROR_OK) return retval; retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl); if (retval != ERROR_OK) return retval; if (ctrl & FLASH_OPTLOCK) { LOG_ERROR("options not unlocked STM32_FLASH_CR: %" PRIx32, ctrl); return ERROR_TARGET_FAILURE; } return ERROR_OK; } static int stm32l4_perform_obl_launch(struct flash_bank *bank) { int retval, retval2; retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) goto err_lock; retval = stm32l4_unlock_option_reg(bank); if (retval != ERROR_OK) goto err_lock; /* Set OBL_LAUNCH bit in CR -> system reset and option bytes reload, * but the RMs explicitly do *NOT* list this as power-on reset cause, and: * "Note: If the read protection is set while the debugger is still * connected through JTAG/SWD, apply a POR (power-on reset) instead of a system reset." */ /* "Setting OBL_LAUNCH generates a reset so the option byte loading is performed under system reset" */ /* Due to this reset ST-Link reports an SWD_DP_ERROR, despite the write was successful, * then just ignore the returned value */ stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_OBL_LAUNCH); /* Need to re-probe after change */ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; stm32l4_info->probed = false; err_lock: retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK | FLASH_OPTLOCK); if (retval != ERROR_OK) return retval; return retval2; } static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value, uint32_t mask) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; uint32_t optiondata; int retval, retval2; retval = stm32l4_read_flash_reg(bank, reg_offset, &optiondata); if (retval != ERROR_OK) return retval; /* for STM32L5 and similar devices, use always non-secure * registers for option bytes programming */ const uint32_t *saved_flash_regs = stm32l4_info->flash_regs; if (stm32l4_info->part_info->flags & F_HAS_L5_FLASH_REGS) stm32l4_info->flash_regs = stm32l5_ns_flash_regs; retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) goto err_lock; retval = stm32l4_unlock_option_reg(bank); if (retval != ERROR_OK) goto err_lock; optiondata = (optiondata & ~mask) | (value & mask); retval = stm32l4_write_flash_reg(bank, reg_offset, optiondata); if (retval != ERROR_OK) goto err_lock; retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_OPTSTRT); if (retval != ERROR_OK) goto err_lock; retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); err_lock: retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK | FLASH_OPTLOCK); stm32l4_info->flash_regs = saved_flash_regs; if (retval != ERROR_OK) return retval; return retval2; } static int stm32l4_get_one_wrpxy(struct flash_bank *bank, struct stm32l4_wrp *wrpxy, enum stm32l4_flash_reg_index reg_idx, int offset) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; int ret; wrpxy->reg_idx = reg_idx; wrpxy->offset = offset; ret = stm32l4_read_flash_reg_by_index(bank, wrpxy->reg_idx , &wrpxy->value); if (ret != ERROR_OK) return ret; wrpxy->first = (wrpxy->value & stm32l4_info->wrpxxr_mask) + wrpxy->offset; wrpxy->last = ((wrpxy->value >> 16) & stm32l4_info->wrpxxr_mask) + wrpxy->offset; wrpxy->used = wrpxy->first <= wrpxy->last; return ERROR_OK; } static int stm32l4_get_all_wrpxy(struct flash_bank *bank, enum stm32_bank_id dev_bank_id, struct stm32l4_wrp *wrpxy, unsigned int *n_wrp) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; int ret; *n_wrp = 0; /* for single bank devices there is 2 WRP regions. * for dual bank devices there is 2 WRP regions per bank, * if configured as single bank only 2 WRP are usable * except for STM32L4R/S/P/Q, G4 cat3, L5 ... all 4 WRP are usable * note: this should be revised, if a device will have the SWAP banks option */ int wrp2y_sectors_offset = -1; /* -1 : unused */ /* if bank_id is BANK1 or ALL_BANKS */ if (dev_bank_id != STM32_BANK2) { /* get FLASH_WRP1AR */ ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP1AR_INDEX, 0); if (ret != ERROR_OK) return ret; /* get WRP1BR */ ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP1BR_INDEX, 0); if (ret != ERROR_OK) return ret; /* for some devices (like STM32L4R/S) in single-bank mode, the 4 WRPxx are usable */ if ((stm32l4_info->part_info->flags & F_USE_ALL_WRPXX) && !stm32l4_info->dual_bank_mode) wrp2y_sectors_offset = 0; } /* if bank_id is BANK2 or ALL_BANKS */ if (dev_bank_id != STM32_BANK1 && stm32l4_info->dual_bank_mode) wrp2y_sectors_offset = stm32l4_info->bank1_sectors; if (wrp2y_sectors_offset >= 0) { /* get WRP2AR */ ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP2AR_INDEX, wrp2y_sectors_offset); if (ret != ERROR_OK) return ret; /* get WRP2BR */ ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP2BR_INDEX, wrp2y_sectors_offset); if (ret != ERROR_OK) return ret; } return ERROR_OK; } static int stm32l4_write_one_wrpxy(struct flash_bank *bank, struct stm32l4_wrp *wrpxy) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; int wrp_start = wrpxy->first - wrpxy->offset; int wrp_end = wrpxy->last - wrpxy->offset; uint32_t wrp_value = (wrp_start & stm32l4_info->wrpxxr_mask) | ((wrp_end & stm32l4_info->wrpxxr_mask) << 16); return stm32l4_write_option(bank, stm32l4_info->flash_regs[wrpxy->reg_idx], wrp_value, 0xffffffff); } static int stm32l4_write_all_wrpxy(struct flash_bank *bank, struct stm32l4_wrp *wrpxy, unsigned int n_wrp) { int ret; for (unsigned int i = 0; i < n_wrp; i++) { ret = stm32l4_write_one_wrpxy(bank, &wrpxy[i]); if (ret != ERROR_OK) return ret; } return ERROR_OK; } static int stm32l4_protect_check(struct flash_bank *bank) { unsigned int n_wrp; struct stm32l4_wrp wrpxy[4]; int ret = stm32l4_get_all_wrpxy(bank, STM32_ALL_BANKS, wrpxy, &n_wrp); if (ret != ERROR_OK) return ret; /* initialize all sectors as unprotected */ for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = 0; /* now check WRPxy and mark the protected sectors */ for (unsigned int i = 0; i < n_wrp; i++) { if (wrpxy[i].used) { for (int s = wrpxy[i].first; s <= wrpxy[i].last; s++) bank->sectors[s].is_protected = 1; } } return ERROR_OK; } static int stm32l4_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; int retval, retval2; assert((first <= last) && (last < bank->num_sectors)); if (stm32l4_is_otp(bank)) { LOG_ERROR("cannot erase OTP memory"); return ERROR_FLASH_OPER_UNSUPPORTED; } if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { /* set all FLASH pages as secure */ retval = stm32l4_set_secbb(bank, FLASH_SECBB_SECURE); if (retval != ERROR_OK) { /* restore all FLASH pages as non-secure */ stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); /* ignore the return value */ return retval; } } retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) goto err_lock; /* Sector Erase To erase a sector, follow the procedure below: 1. Check that no Flash memory operation is ongoing by checking the BSY bit in the FLASH_SR register 2. Set the PER bit and select the page and bank you wish to erase in the FLASH_CR register 3. Set the STRT bit in the FLASH_CR register 4. Wait for the BSY bit to be cleared */ for (unsigned int i = first; i <= last; i++) { uint32_t erase_flags; erase_flags = FLASH_PER | FLASH_STRT; if (i >= stm32l4_info->bank1_sectors) { uint8_t snb; snb = i - stm32l4_info->bank1_sectors; erase_flags |= snb << FLASH_PAGE_SHIFT | stm32l4_info->cr_bker_mask; } else erase_flags |= i << FLASH_PAGE_SHIFT; retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, erase_flags); if (retval != ERROR_OK) break; retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) break; } err_lock: retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK); if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { /* restore all FLASH pages as non-secure */ int retval3 = stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); if (retval3 != ERROR_OK) return retval3; } if (retval != ERROR_OK) return retval; return retval2; } static int stm32l4_protect_same_bank(struct flash_bank *bank, enum stm32_bank_id bank_id, int set, unsigned int first, unsigned int last) { unsigned int i; /* check if the desired protection is already configured */ for (i = first; i <= last; i++) { if (bank->sectors[i].is_protected != set) break; else if (i == last) { LOG_INFO("The specified sectors are already %s", set ? "protected" : "unprotected"); return ERROR_OK; } } /* all sectors from first to last (or part of them) could have different * protection other than the requested */ unsigned int n_wrp; struct stm32l4_wrp wrpxy[4]; int ret = stm32l4_get_all_wrpxy(bank, bank_id, wrpxy, &n_wrp); if (ret != ERROR_OK) return ret; /* use bitmap and range helpers to optimize the WRP usage */ DECLARE_BITMAP(pages, bank->num_sectors); bitmap_zero(pages, bank->num_sectors); for (i = 0; i < n_wrp; i++) { if (wrpxy[i].used) { for (int p = wrpxy[i].first; p <= wrpxy[i].last; p++) set_bit(p, pages); } } /* we have at most 'n_wrp' WRP areas * add one range if the user is trying to protect a fifth range */ struct range ranges[n_wrp + 1]; unsigned int ranges_count = 0; bitmap_to_ranges(pages, bank->num_sectors, ranges, &ranges_count); /* pretty-print the currently protected ranges */ if (ranges_count > 0) { char *ranges_str = range_print_alloc(ranges, ranges_count); LOG_DEBUG("current protected areas: %s", ranges_str); free(ranges_str); } else LOG_DEBUG("current protected areas: none"); if (set) { /* flash protect */ for (i = first; i <= last; i++) set_bit(i, pages); } else { /* flash unprotect */ for (i = first; i <= last; i++) clear_bit(i, pages); } /* check the ranges_count after the user request */ bitmap_to_ranges(pages, bank->num_sectors, ranges, &ranges_count); /* pretty-print the requested areas for protection */ if (ranges_count > 0) { char *ranges_str = range_print_alloc(ranges, ranges_count); LOG_DEBUG("requested areas for protection: %s", ranges_str); free(ranges_str); } else LOG_DEBUG("requested areas for protection: none"); if (ranges_count > n_wrp) { LOG_ERROR("cannot set the requested protection " "(only %u write protection areas are available)" , n_wrp); return ERROR_FAIL; } /* re-init all WRPxy as disabled (first > last)*/ for (i = 0; i < n_wrp; i++) { wrpxy[i].first = wrpxy[i].offset + 1; wrpxy[i].last = wrpxy[i].offset; } /* then configure WRPxy areas */ for (i = 0; i < ranges_count; i++) { wrpxy[i].first = ranges[i].start; wrpxy[i].last = ranges[i].end; } /* finally write WRPxy registers */ return stm32l4_write_all_wrpxy(bank, wrpxy, n_wrp); } static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct target *target = bank->target; struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; if (stm32l4_is_otp(bank)) { LOG_ERROR("cannot protect/unprotect OTP memory"); return ERROR_FLASH_OPER_UNSUPPORTED; } if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* refresh the sectors' protection */ int ret = stm32l4_protect_check(bank); if (ret != ERROR_OK) return ret; /* the requested sectors could be located into bank1 and/or bank2 */ if (last < stm32l4_info->bank1_sectors) { return stm32l4_protect_same_bank(bank, STM32_BANK1, set, first, last); } else if (first >= stm32l4_info->bank1_sectors) { return stm32l4_protect_same_bank(bank, STM32_BANK2, set, first, last); } else { ret = stm32l4_protect_same_bank(bank, STM32_BANK1, set, first, stm32l4_info->bank1_sectors - 1); if (ret != ERROR_OK) return ret; return stm32l4_protect_same_bank(bank, STM32_BANK2, set, stm32l4_info->bank1_sectors, last); } } /* count is the size divided by stm32l4_info->data_width */ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; static const uint8_t stm32l4_flash_write_code[] = { #include "../../../contrib/loaders/flash/stm32/stm32l4x.inc" }; if (target_alloc_working_area(target, sizeof(stm32l4_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32l4_flash_write_code), stm32l4_flash_write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } /* data_width should be multiple of double-word */ assert(stm32l4_info->data_width % 8 == 0); const size_t extra_size = sizeof(struct stm32l4_work_area); uint32_t buffer_size = target_get_working_area_avail(target) - extra_size; /* buffer_size should be multiple of stm32l4_info->data_width */ buffer_size &= ~(stm32l4_info->data_width - 1); if (buffer_size < 256) { LOG_WARNING("large enough working area not available, can't do block memory writes"); target_free_working_area(target, write_algorithm); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } else if (buffer_size > 16384) { /* probably won't benefit from more than 16k ... */ buffer_size = 16384; } if (target_alloc_working_area_try(target, buffer_size + extra_size, &source) != ERROR_OK) { LOG_ERROR("allocating working area failed"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; /* contrib/loaders/flash/stm32/stm32l4x.c:write() arguments */ init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* stm32l4_work_area ptr , status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (of stm32l4_info->data_width) */ buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[3].value, 0, 32, count); /* write algo stack pointer */ init_reg_param(®_params[4], "sp", 32, PARAM_OUT); buf_set_u32(reg_params[4].value, 0, 32, source->address + offsetof(struct stm32l4_work_area, stack) + LDR_STACK_SIZE); struct stm32l4_loader_params loader_extra_params; target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_sr_addr, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX)); target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_cr_addr, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX)); target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_word_size, stm32l4_info->data_width); target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_sr_bsy_mask, stm32l4_info->sr_bsy_mask); retval = target_write_buffer(target, source->address, sizeof(loader_extra_params), (uint8_t *) &loader_extra_params); if (retval != ERROR_OK) return retval; retval = target_run_flash_async_algorithm(target, buffer, count, stm32l4_info->data_width, 0, NULL, ARRAY_SIZE(reg_params), reg_params, source->address + offsetof(struct stm32l4_work_area, fifo), source->size - offsetof(struct stm32l4_work_area, fifo), write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("error executing stm32l4 flash write algorithm"); uint32_t error; stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, &error); error &= FLASH_ERROR; if (error & FLASH_WRPERR) LOG_ERROR("flash memory write protected"); if (error != 0) { LOG_ERROR("flash write failed = %08" PRIx32, error); /* Clear but report errors */ stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, error); retval = ERROR_FAIL; } } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; } /* count is the size divided by stm32l4_info->data_width */ static int stm32l4_write_block_without_loader(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; struct target *target = bank->target; uint32_t address = bank->base + offset; int retval = ERROR_OK; /* wait for BSY bit */ retval = stm32l4_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) return retval; /* set PG in FLASH_CR */ retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_PG); if (retval != ERROR_OK) return retval; /* write directly to flash memory */ const uint8_t *src = buffer; const uint32_t data_width_in_words = stm32l4_info->data_width / 4; while (count--) { retval = target_write_memory(target, address, 4, data_width_in_words, src); if (retval != ERROR_OK) return retval; /* wait for BSY bit */ retval = stm32l4_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) return retval; src += stm32l4_info->data_width; address += stm32l4_info->data_width; } /* reset PG in FLASH_CR */ retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, 0); if (retval != ERROR_OK) return retval; return retval; } static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; int retval = ERROR_OK, retval2; if (stm32l4_is_otp(bank) && !stm32l4_otp_is_enabled(bank)) { LOG_ERROR("OTP memory is disabled for write commands"); return ERROR_FAIL; } if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* ensure that stm32l4_info->data_width is 'at least' a multiple of dword */ assert(stm32l4_info->data_width % 8 == 0); /* The flash write must be aligned to the 'stm32l4_info->data_width' boundary. * The flash infrastructure ensures it, do just a security check */ assert(offset % stm32l4_info->data_width == 0); assert(count % stm32l4_info->data_width == 0); /* STM32G4xxx Cat. 3 devices may have gaps between banks, check whether * data to be written does not go into a gap: * suppose buffer is fully contained in bank from sector 0 to sector * num->sectors - 1 and sectors are ordered according to offset */ struct flash_sector *head = &bank->sectors[0]; struct flash_sector *tail = &bank->sectors[bank->num_sectors - 1]; while ((head < tail) && (offset >= (head + 1)->offset)) { /* buffer does not intersect head nor gap behind head */ head++; } while ((head < tail) && (offset + count <= (tail - 1)->offset + (tail - 1)->size)) { /* buffer does not intersect tail nor gap before tail */ --tail; } LOG_DEBUG("data: 0x%08" PRIx32 " - 0x%08" PRIx32 ", sectors: 0x%08" PRIx32 " - 0x%08" PRIx32, offset, offset + count - 1, head->offset, tail->offset + tail->size - 1); /* Now check that there is no gap from head to tail, this should work * even for multiple or non-symmetric gaps */ while (head < tail) { if (head->offset + head->size != (head + 1)->offset) { LOG_ERROR("write into gap from " TARGET_ADDR_FMT " to " TARGET_ADDR_FMT, bank->base + head->offset + head->size, bank->base + (head + 1)->offset - 1); retval = ERROR_FLASH_DST_OUT_OF_BANK; } head++; } if (retval != ERROR_OK) return retval; if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { /* set all FLASH pages as secure */ retval = stm32l4_set_secbb(bank, FLASH_SECBB_SECURE); if (retval != ERROR_OK) { /* restore all FLASH pages as non-secure */ stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); /* ignore the return value */ return retval; } } retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) goto err_lock; /* For TrustZone enabled devices, when TZEN is set and RDP level is 0.5, * the debug is possible only in non-secure state. * Thus means the flashloader will run in non-secure mode, * and the workarea need to be in non-secure RAM */ if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0_5)) LOG_WARNING("RDP = 0x55, the work-area should be in non-secure RAM (check SAU partitioning)"); /* first try to write using the loader, for better performance */ retval = stm32l4_write_block(bank, buffer, offset, count / stm32l4_info->data_width); /* if resources are not available write without a loader */ if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { LOG_WARNING("falling back to programming without a flash loader (slower)"); retval = stm32l4_write_block_without_loader(bank, buffer, offset, count / stm32l4_info->data_width); } err_lock: retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK); if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { /* restore all FLASH pages as non-secure */ int retval3 = stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); if (retval3 != ERROR_OK) return retval3; } if (retval != ERROR_OK) { LOG_ERROR("block write failed"); return retval; } return retval2; } static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) { int retval = ERROR_OK; struct target *target = bank->target; /* try reading possible IDCODE registers, in the following order */ uint32_t dbgmcu_idcode[] = {DBGMCU_IDCODE_L4_G4, DBGMCU_IDCODE_G0, DBGMCU_IDCODE_L5}; for (unsigned int i = 0; i < ARRAY_SIZE(dbgmcu_idcode); i++) { retval = target_read_u32(target, dbgmcu_idcode[i], id); if ((retval == ERROR_OK) && ((*id & 0xfff) != 0) && ((*id & 0xfff) != 0xfff)) return ERROR_OK; } /* Workaround for STM32WL5x devices: * DBGMCU_IDCODE cannot be read using CPU1 (Cortex-M0+) at AP1, * to solve this read the UID64 (IEEE 64-bit unique device ID register) */ struct armv7m_common *armv7m = target_to_armv7m_safe(target); if (!armv7m) { LOG_ERROR("Flash requires Cortex-M target"); return ERROR_TARGET_INVALID; } /* CPU2 (Cortex-M0+) is supported only with non-hla adapters because it is on AP1. * Using HLA adapters armv7m.debug_ap is null, and checking ap_num triggers a segfault */ if (cortex_m_get_partno_safe(target) == CORTEX_M0P_PARTNO && armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) { uint32_t uid64_ids; /* UID64 is contains * - Bits 63:32 : DEVNUM (unique device number, different for each individual device) * - Bits 31:08 : STID (company ID) = 0x0080E1 * - Bits 07:00 : DEVID (device ID) = 0x15 * * read only the fixed values {STID,DEVID} from UID64_IDS to identify the device as STM32WLx */ retval = target_read_u32(target, UID64_IDS, &uid64_ids); if (retval == ERROR_OK && uid64_ids == UID64_IDS_STM32WL) { /* force the DEV_ID to DEVID_STM32WLE_WL5XX and the REV_ID to unknown */ *id = DEVID_STM32WLE_WL5XX; return ERROR_OK; } } LOG_ERROR("can't get the device id"); return (retval == ERROR_OK) ? ERROR_FAIL : retval; } static const char *get_stm32l4_rev_str(struct flash_bank *bank) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; const struct stm32l4_part_info *part_info = stm32l4_info->part_info; assert(part_info); const uint16_t rev_id = stm32l4_info->idcode >> 16; for (unsigned int i = 0; i < part_info->num_revs; i++) { if (rev_id == part_info->revs[i].rev) return part_info->revs[i].str; } return "'unknown'"; } static const char *get_stm32l4_bank_type_str(struct flash_bank *bank) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; assert(stm32l4_info->part_info); return stm32l4_is_otp(bank) ? "OTP" : stm32l4_info->dual_bank_mode ? "Flash dual" : "Flash single"; } static int stm32l4_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; const struct stm32l4_part_info *part_info; uint16_t flash_size_kb = 0xffff; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_TARGET_NOT_EXAMINED; } struct armv7m_common *armv7m = target_to_armv7m_safe(target); if (!armv7m) { LOG_ERROR("Flash requires Cortex-M target"); return ERROR_TARGET_INVALID; } stm32l4_info->probed = false; /* read stm32 device id registers */ int retval = stm32l4_read_idcode(bank, &stm32l4_info->idcode); if (retval != ERROR_OK) return retval; const uint32_t device_id = stm32l4_info->idcode & 0xFFF; for (unsigned int n = 0; n < ARRAY_SIZE(stm32l4_parts); n++) { if (device_id == stm32l4_parts[n].id) { stm32l4_info->part_info = &stm32l4_parts[n]; break; } } if (!stm32l4_info->part_info) { LOG_WARNING("Cannot identify target as an %s family device.", device_families); return ERROR_FAIL; } part_info = stm32l4_info->part_info; const char *rev_str = get_stm32l4_rev_str(bank); const uint16_t rev_id = stm32l4_info->idcode >> 16; LOG_INFO("device idcode = 0x%08" PRIx32 " (%s - Rev %s : 0x%04x)", stm32l4_info->idcode, part_info->device_str, rev_str, rev_id); stm32l4_info->flash_regs_base = stm32l4_info->part_info->flash_regs_base; stm32l4_info->data_width = (part_info->flags & F_QUAD_WORD_PROG) ? 16 : 8; stm32l4_info->cr_bker_mask = FLASH_BKER; stm32l4_info->sr_bsy_mask = FLASH_BSY; /* Set flash write alignment boundaries. * Ask the flash infrastructure to ensure required alignment */ bank->write_start_alignment = stm32l4_info->data_width; bank->write_end_alignment = stm32l4_info->data_width; /* Initialize the flash registers layout */ if (part_info->flags & F_HAS_L5_FLASH_REGS) stm32l4_info->flash_regs = stm32l5_ns_flash_regs; else stm32l4_info->flash_regs = stm32l4_flash_regs; /* read flash option register */ retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &stm32l4_info->optr); if (retval != ERROR_OK) return retval; stm32l4_sync_rdp_tzen(bank); /* for devices with TrustZone, use flash secure registers when TZEN=1 and RDP is LEVEL_0 */ if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { if (part_info->flags & F_HAS_L5_FLASH_REGS) { stm32l4_info->flash_regs_base |= STM32L5_REGS_SEC_OFFSET; stm32l4_info->flash_regs = stm32l5_s_flash_regs; } else { LOG_ERROR("BUG: device supported incomplete"); return ERROR_NOT_IMPLEMENTED; } } if (part_info->flags & F_HAS_TZ) LOG_INFO("TZEN = %d : TrustZone %s by option bytes", stm32l4_info->tzen, stm32l4_info->tzen ? "enabled" : "disabled"); LOG_INFO("RDP level %s (0x%02X)", stm32l4_info->rdp == RDP_LEVEL_0 ? "0" : stm32l4_info->rdp == RDP_LEVEL_0_5 ? "0.5" : "1", stm32l4_info->rdp); if (stm32l4_is_otp(bank)) { bank->size = part_info->otp_size; LOG_INFO("OTP size is %d bytes, base address is " TARGET_ADDR_FMT, bank->size, bank->base); /* OTP memory is considered as one sector */ free(bank->sectors); bank->num_sectors = 1; bank->sectors = alloc_block_array(0, part_info->otp_size, 1); if (!bank->sectors) { LOG_ERROR("failed to allocate bank sectors"); return ERROR_FAIL; } stm32l4_info->probed = true; return ERROR_OK; } else if (bank->base != STM32_FLASH_BANK_BASE && bank->base != STM32_FLASH_S_BANK_BASE) { LOG_ERROR("invalid bank base address"); return ERROR_FAIL; } /* get flash size from target. */ retval = target_read_u16(target, part_info->fsize_addr, &flash_size_kb); /* failed reading flash size or flash size invalid (early silicon), * default to max target family */ if (retval != ERROR_OK || flash_size_kb == 0xffff || flash_size_kb == 0 || flash_size_kb > part_info->max_flash_size_kb) { LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming %dk flash", part_info->max_flash_size_kb); flash_size_kb = part_info->max_flash_size_kb; } /* if the user sets the size manually then ignore the probed value * this allows us to work around devices that have a invalid flash size register value */ if (stm32l4_info->user_bank_size) { LOG_WARNING("overriding size register by configured bank size - MAY CAUSE TROUBLE"); flash_size_kb = stm32l4_info->user_bank_size / 1024; } LOG_INFO("flash size = %d KiB", flash_size_kb); /* did we assign a flash size? */ assert((flash_size_kb != 0xffff) && flash_size_kb); const bool is_max_flash_size = flash_size_kb == stm32l4_info->part_info->max_flash_size_kb; stm32l4_info->bank1_sectors = 0; stm32l4_info->hole_sectors = 0; int num_pages = 0; int page_size_kb = 0; stm32l4_info->dual_bank_mode = false; switch (device_id) { case DEVID_STM32L47_L48XX: case DEVID_STM32L49_L4AXX: /* if flash size is max (1M) the device is always dual bank * STM32L47/L48xx: has variants with 512K * STM32L49/L4Axx: has variants with 512 and 256 * for these variants: * if DUAL_BANK = 0 -> single bank * else -> dual bank without gap * note: the page size is invariant */ page_size_kb = 2; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; /* check DUAL_BANK option bit if the flash is less than 1M */ if (is_max_flash_size || (stm32l4_info->optr & FLASH_L4_DUAL_BANK)) { stm32l4_info->dual_bank_mode = true; stm32l4_info->bank1_sectors = num_pages / 2; } break; case DEVID_STM32L43_L44XX: case DEVID_STM32C01XX: case DEVID_STM32C03XX: case DEVID_STM32G05_G06XX: case DEVID_STM32G07_G08XX: case DEVID_STM32L45_L46XX: case DEVID_STM32L41_L42XX: case DEVID_STM32G03_G04XX: case DEVID_STM32G43_G44XX: case DEVID_STM32G49_G4AXX: case DEVID_STM32WB1XX: /* single bank flash */ page_size_kb = 2; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; break; case DEVID_STM32G0B_G0CXX: /* single/dual bank depending on DUAL_BANK option bit */ page_size_kb = 2; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; stm32l4_info->cr_bker_mask = FLASH_BKER_G0; /* check DUAL_BANK bit */ if (stm32l4_info->optr & FLASH_G0_DUAL_BANK) { stm32l4_info->sr_bsy_mask = FLASH_BSY | FLASH_BSY2; stm32l4_info->dual_bank_mode = true; stm32l4_info->bank1_sectors = num_pages / 2; } break; case DEVID_STM32G47_G48XX: /* STM32G47/8 can be single/dual bank: * if DUAL_BANK = 0 -> single bank * else -> dual bank WITH gap */ page_size_kb = 4; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; if (stm32l4_info->optr & FLASH_G4_DUAL_BANK) { stm32l4_info->dual_bank_mode = true; page_size_kb = 2; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages / 2; /* for devices with trimmed flash, there is a gap between both banks */ stm32l4_info->hole_sectors = (part_info->max_flash_size_kb - flash_size_kb) / (2 * page_size_kb); } break; case DEVID_STM32L4R_L4SXX: case DEVID_STM32L4P_L4QXX: /* STM32L4R/S can be single/dual bank: * if size = 2M check DBANK bit * if size = 1M check DB1M bit * STM32L4P/Q can be single/dual bank * if size = 1M check DBANK bit * if size = 512K check DB512K bit (same as DB1M bit) */ page_size_kb = 8; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; if ((is_max_flash_size && (stm32l4_info->optr & FLASH_L4R_DBANK)) || (!is_max_flash_size && (stm32l4_info->optr & FLASH_LRR_DB1M))) { stm32l4_info->dual_bank_mode = true; page_size_kb = 4; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages / 2; } break; case DEVID_STM32L55_L56XX: /* STM32L55/L56xx can be single/dual bank: * if size = 512K check DBANK bit * if size = 256K check DB256K bit * * default page size is 4kb, if DBANK = 1, the page size is 2kb. */ page_size_kb = (stm32l4_info->optr & FLASH_L5_DBANK) ? 2 : 4; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; if ((is_max_flash_size && (stm32l4_info->optr & FLASH_L5_DBANK)) || (!is_max_flash_size && (stm32l4_info->optr & FLASH_L5_DB256))) { stm32l4_info->dual_bank_mode = true; stm32l4_info->bank1_sectors = num_pages / 2; } break; case DEVID_STM32U57_U58XX: /* if flash size is max (2M) the device is always dual bank * otherwise check DUALBANK */ page_size_kb = 8; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; if (is_max_flash_size || (stm32l4_info->optr & FLASH_U5_DUALBANK)) { stm32l4_info->dual_bank_mode = true; stm32l4_info->bank1_sectors = num_pages / 2; } break; case DEVID_STM32WB5XX: case DEVID_STM32WB3XX: /* single bank flash */ page_size_kb = 4; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; break; case DEVID_STM32WLE_WL5XX: /* single bank flash */ page_size_kb = 2; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; /* CPU2 (Cortex-M0+) is supported only with non-hla adapters because it is on AP1. * Using HLA adapters armv7m->debug_ap is null, and checking ap_num triggers a segfault */ if (armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) stm32l4_info->flash_regs = stm32wl_cpu2_flash_regs; break; default: LOG_ERROR("unsupported device"); return ERROR_FAIL; } /* ensure that at least there is 1 flash sector / page */ if (num_pages == 0) { if (stm32l4_info->user_bank_size) LOG_ERROR("The specified flash size is less than page size"); LOG_ERROR("Flash pages count cannot be zero"); return ERROR_FAIL; } LOG_INFO("flash mode : %s-bank", stm32l4_info->dual_bank_mode ? "dual" : "single"); const int gap_size_kb = stm32l4_info->hole_sectors * page_size_kb; if (gap_size_kb != 0) { LOG_INFO("gap detected from 0x%08x to 0x%08x", STM32_FLASH_BANK_BASE + stm32l4_info->bank1_sectors * page_size_kb * 1024, STM32_FLASH_BANK_BASE + (stm32l4_info->bank1_sectors * page_size_kb + gap_size_kb) * 1024 - 1); } /* number of significant bits in WRPxxR differs per device, * always right adjusted, on some devices non-implemented * bits read as '0', on others as '1' ... * notably G4 Cat. 2 implement only 6 bits, contradicting the RM */ /* use *max_flash_size* instead of actual size as the trimmed versions * certainly use the same number of bits */ uint32_t max_pages = stm32l4_info->part_info->max_flash_size_kb / page_size_kb; /* in dual bank mode number of pages is doubled, but extra bit is bank selection */ stm32l4_info->wrpxxr_mask = ((max_pages >> (stm32l4_info->dual_bank_mode ? 1 : 0)) - 1); assert((stm32l4_info->wrpxxr_mask & 0xFFFF0000) == 0); LOG_DEBUG("WRPxxR mask 0x%04" PRIx16, (uint16_t)stm32l4_info->wrpxxr_mask); free(bank->sectors); bank->size = (flash_size_kb + gap_size_kb) * 1024; bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); if (!bank->sectors) { LOG_ERROR("failed to allocate bank sectors"); return ERROR_FAIL; } for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = i * page_size_kb * 1024; /* in dual bank configuration, if there is a gap between banks * we fix up the sector offset to consider this gap */ if (i >= stm32l4_info->bank1_sectors && stm32l4_info->hole_sectors) bank->sectors[i].offset += gap_size_kb * 1024; bank->sectors[i].size = page_size_kb * 1024; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } stm32l4_info->probed = true; return ERROR_OK; } static int stm32l4_auto_probe(struct flash_bank *bank) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; if (stm32l4_info->probed) { uint32_t optr_cur; /* save flash_regs_base */ uint32_t saved_flash_regs_base = stm32l4_info->flash_regs_base; /* for devices with TrustZone, use NS flash registers to read OPTR */ if (stm32l4_info->part_info->flags & F_HAS_L5_FLASH_REGS) stm32l4_info->flash_regs_base &= ~STM32L5_REGS_SEC_OFFSET; /* read flash option register and re-probe if optr value is changed */ int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &optr_cur); /* restore saved flash_regs_base */ stm32l4_info->flash_regs_base = saved_flash_regs_base; if (retval != ERROR_OK) return retval; if (stm32l4_info->optr == optr_cur) return ERROR_OK; } return stm32l4_probe(bank); } static int get_stm32l4_info(struct flash_bank *bank, struct command_invocation *cmd) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; const struct stm32l4_part_info *part_info = stm32l4_info->part_info; if (part_info) { const uint16_t rev_id = stm32l4_info->idcode >> 16; command_print_sameline(cmd, "%s - Rev %s : 0x%04x", part_info->device_str, get_stm32l4_rev_str(bank), rev_id); if (stm32l4_info->probed) command_print_sameline(cmd, " - %s-bank", get_stm32l4_bank_type_str(bank)); } else { command_print_sameline(cmd, "Cannot identify target as an %s device", device_families); } return ERROR_OK; } static int stm32l4_mass_erase(struct flash_bank *bank) { int retval, retval2; struct target *target = bank->target; struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; if (stm32l4_is_otp(bank)) { LOG_ERROR("cannot erase OTP memory"); return ERROR_FLASH_OPER_UNSUPPORTED; } uint32_t action = FLASH_MER1; if (stm32l4_info->part_info->flags & F_HAS_DUAL_BANK) action |= FLASH_MER2; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { /* set all FLASH pages as secure */ retval = stm32l4_set_secbb(bank, FLASH_SECBB_SECURE); if (retval != ERROR_OK) { /* restore all FLASH pages as non-secure */ stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); /* ignore the return value */ return retval; } } retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) goto err_lock; /* mass erase flash memory */ retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT / 10); if (retval != ERROR_OK) goto err_lock; retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, action); if (retval != ERROR_OK) goto err_lock; retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, action | FLASH_STRT); if (retval != ERROR_OK) goto err_lock; retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); err_lock: retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK); if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { /* restore all FLASH pages as non-secure */ int retval3 = stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); if (retval3 != ERROR_OK) return retval3; } if (retval != ERROR_OK) return retval; return retval2; } COMMAND_HANDLER(stm32l4_handle_mass_erase_command) { if (CMD_ARGC < 1) { command_print(CMD, "stm32l4x mass_erase <STM32L4 bank>"); return ERROR_COMMAND_SYNTAX_ERROR; } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = stm32l4_mass_erase(bank); if (retval == ERROR_OK) command_print(CMD, "stm32l4x mass erase complete"); else command_print(CMD, "stm32l4x mass erase failed"); return retval; } COMMAND_HANDLER(stm32l4_handle_option_read_command) { if (CMD_ARGC < 2) { command_print(CMD, "stm32l4x option_read <STM32L4 bank> <option_reg offset>"); return ERROR_COMMAND_SYNTAX_ERROR; } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; uint32_t reg_offset, reg_addr; uint32_t value = 0; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset); reg_addr = stm32l4_get_flash_reg(bank, reg_offset); retval = stm32l4_read_flash_reg(bank, reg_offset, &value); if (retval != ERROR_OK) return retval; command_print(CMD, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32 "", reg_addr, value); return retval; } COMMAND_HANDLER(stm32l4_handle_option_write_command) { if (CMD_ARGC < 3) { command_print(CMD, "stm32l4x option_write <STM32L4 bank> <option_reg offset> <value> [mask]"); return ERROR_COMMAND_SYNTAX_ERROR; } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; uint32_t reg_offset; uint32_t value = 0; uint32_t mask = 0xFFFFFFFF; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); if (CMD_ARGC > 3) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], mask); command_print(CMD, "%s Option written.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect.", bank->driver->name); retval = stm32l4_write_option(bank, reg_offset, value, mask); return retval; } COMMAND_HANDLER(stm32l4_handle_trustzone_command) { if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; if (!(stm32l4_info->part_info->flags & F_HAS_TZ)) { LOG_ERROR("This device does not have a TrustZone"); return ERROR_FAIL; } retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &stm32l4_info->optr); if (retval != ERROR_OK) return retval; stm32l4_sync_rdp_tzen(bank); if (CMD_ARGC == 1) { /* only display the TZEN value */ LOG_INFO("Global TrustZone Security is %s", stm32l4_info->tzen ? "enabled" : "disabled"); return ERROR_OK; } bool new_tzen; COMMAND_PARSE_ENABLE(CMD_ARGV[1], new_tzen); if (new_tzen == stm32l4_info->tzen) { LOG_INFO("The requested TZEN is already programmed"); return ERROR_OK; } if (new_tzen) { if (stm32l4_info->rdp != RDP_LEVEL_0) { LOG_ERROR("TZEN can be set only when RDP level is 0"); return ERROR_FAIL; } retval = stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], FLASH_TZEN, FLASH_TZEN); } else { /* Deactivation of TZEN (from 1 to 0) is only possible when the RDP is * changing to level 0 (from level 1 to level 0 or from level 0.5 to level 0). */ if (stm32l4_info->rdp != RDP_LEVEL_1 && stm32l4_info->rdp != RDP_LEVEL_0_5) { LOG_ERROR("Deactivation of TZEN is only possible when the RDP is changing to level 0"); return ERROR_FAIL; } retval = stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], RDP_LEVEL_0, FLASH_RDP_MASK | FLASH_TZEN); } if (retval != ERROR_OK) return retval; return stm32l4_perform_obl_launch(bank); } COMMAND_HANDLER(stm32l4_handle_option_load_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = stm32l4_perform_obl_launch(bank); if (retval != ERROR_OK) { command_print(CMD, "stm32l4x option load failed"); return retval; } command_print(CMD, "stm32l4x option load completed. Power-on reset might be required"); return ERROR_OK; } COMMAND_HANDLER(stm32l4_handle_lock_command) { struct target *target = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; if (stm32l4_is_otp(bank)) { LOG_ERROR("cannot lock/unlock OTP memory"); return ERROR_FLASH_OPER_UNSUPPORTED; } target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* set readout protection level 1 by erasing the RDP option byte */ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; if (stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], RDP_LEVEL_1, FLASH_RDP_MASK) != ERROR_OK) { command_print(CMD, "%s failed to lock device", bank->driver->name); return ERROR_OK; } return ERROR_OK; } COMMAND_HANDLER(stm32l4_handle_unlock_command) { struct target *target = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; if (stm32l4_is_otp(bank)) { LOG_ERROR("cannot lock/unlock OTP memory"); return ERROR_FLASH_OPER_UNSUPPORTED; } target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; if (stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], RDP_LEVEL_0, FLASH_RDP_MASK) != ERROR_OK) { command_print(CMD, "%s failed to unlock device", bank->driver->name); return ERROR_OK; } return ERROR_OK; } COMMAND_HANDLER(stm32l4_handle_wrp_info_command) { if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; if (stm32l4_is_otp(bank)) { LOG_ERROR("OTP memory does not have write protection areas"); return ERROR_FLASH_OPER_UNSUPPORTED; } struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; enum stm32_bank_id dev_bank_id = STM32_ALL_BANKS; if (CMD_ARGC == 2) { if (strcmp(CMD_ARGV[1], "bank1") == 0) dev_bank_id = STM32_BANK1; else if (strcmp(CMD_ARGV[1], "bank2") == 0) dev_bank_id = STM32_BANK2; else return ERROR_COMMAND_ARGUMENT_INVALID; } if (dev_bank_id == STM32_BANK2) { if (!(stm32l4_info->part_info->flags & F_HAS_DUAL_BANK)) { LOG_ERROR("this device has no second bank"); return ERROR_FAIL; } else if (!stm32l4_info->dual_bank_mode) { LOG_ERROR("this device is configured in single bank mode"); return ERROR_FAIL; } } int ret; unsigned int n_wrp, i; struct stm32l4_wrp wrpxy[4]; ret = stm32l4_get_all_wrpxy(bank, dev_bank_id, wrpxy, &n_wrp); if (ret != ERROR_OK) return ret; /* use bitmap and range helpers to better describe protected areas */ DECLARE_BITMAP(pages, bank->num_sectors); bitmap_zero(pages, bank->num_sectors); for (i = 0; i < n_wrp; i++) { if (wrpxy[i].used) { for (int p = wrpxy[i].first; p <= wrpxy[i].last; p++) set_bit(p, pages); } } /* we have at most 'n_wrp' WRP areas */ struct range ranges[n_wrp]; unsigned int ranges_count = 0; bitmap_to_ranges(pages, bank->num_sectors, ranges, &ranges_count); if (ranges_count > 0) { /* pretty-print the protected ranges */ char *ranges_str = range_print_alloc(ranges, ranges_count); command_print(CMD, "protected areas: %s", ranges_str); free(ranges_str); } else command_print(CMD, "no protected areas"); return ERROR_OK; } COMMAND_HANDLER(stm32l4_handle_otp_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; if (!stm32l4_is_otp(bank)) { command_print(CMD, "the specified bank is not an OTP memory"); return ERROR_FAIL; } if (strcmp(CMD_ARGV[1], "enable") == 0) stm32l4_otp_enable(bank, true); else if (strcmp(CMD_ARGV[1], "disable") == 0) stm32l4_otp_enable(bank, false); else if (strcmp(CMD_ARGV[1], "show") == 0) command_print(CMD, "OTP memory bank #%d is %s for write commands.", bank->bank_number, stm32l4_otp_is_enabled(bank) ? "enabled" : "disabled"); else return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } static const struct command_registration stm32l4_exec_command_handlers[] = { { .name = "lock", .handler = stm32l4_handle_lock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Lock entire flash device.", }, { .name = "unlock", .handler = stm32l4_handle_unlock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Unlock entire protected flash device.", }, { .name = "mass_erase", .handler = stm32l4_handle_mass_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Erase entire flash device.", }, { .name = "option_read", .handler = stm32l4_handle_option_read_command, .mode = COMMAND_EXEC, .usage = "bank_id reg_offset", .help = "Read & Display device option bytes.", }, { .name = "option_write", .handler = stm32l4_handle_option_write_command, .mode = COMMAND_EXEC, .usage = "bank_id reg_offset value mask", .help = "Write device option bit fields with provided value.", }, { .name = "trustzone", .handler = stm32l4_handle_trustzone_command, .mode = COMMAND_EXEC, .usage = "<bank_id> [enable|disable]", .help = "Configure TrustZone security", }, { .name = "wrp_info", .handler = stm32l4_handle_wrp_info_command, .mode = COMMAND_EXEC, .usage = "bank_id [bank1|bank2]", .help = "list the protected areas using WRP", }, { .name = "option_load", .handler = stm32l4_handle_option_load_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Force re-load of device options (will cause device reset).", }, { .name = "otp", .handler = stm32l4_handle_otp_command, .mode = COMMAND_EXEC, .usage = "<bank_id> <enable|disable|show>", .help = "OTP (One Time Programmable) memory write enable/disable", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration stm32l4_command_handlers[] = { { .name = "stm32l4x", .mode = COMMAND_ANY, .help = "stm32l4x flash command group", .usage = "", .chain = stm32l4_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver stm32l4x_flash = { .name = "stm32l4x", .commands = stm32l4_command_handlers, .flash_bank_command = stm32l4_flash_bank_command, .erase = stm32l4_erase, .protect = stm32l4_protect, .write = stm32l4_write, .read = default_flash_read, .probe = stm32l4_probe, .auto_probe = stm32l4_auto_probe, .erase_check = default_flash_blank_check, .protect_check = stm32l4_protect_check, .info = get_stm32l4_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/stm32l4x.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2015 by Uwe Bonnes * * bon@elektron.ikp.physik.tu-darmstadt.de * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_STM32L4X #define OPENOCD_FLASH_NOR_STM32L4X /* IMPORTANT: this file is included by stm32l4x driver and flashloader, * so please when changing this file, do not forget to check the flashloader */ /* FIXME: #include "helper/bits.h" cause build errors when compiling * the flashloader, for now just redefine the needed 'BIT 'macro */ #ifndef BIT #define BIT(nr) (1UL << (nr)) #endif /* FLASH_CR register bits */ #define FLASH_PG BIT(0) #define FLASH_PER BIT(1) #define FLASH_MER1 BIT(2) #define FLASH_PAGE_SHIFT 3 #define FLASH_BKER BIT(11) #define FLASH_BKER_G0 BIT(13) #define FLASH_MER2 BIT(15) #define FLASH_STRT BIT(16) #define FLASH_OPTSTRT BIT(17) #define FLASH_EOPIE BIT(24) #define FLASH_ERRIE BIT(25) #define FLASH_OBL_LAUNCH BIT(27) #define FLASH_OPTLOCK BIT(30) #define FLASH_LOCK BIT(31) /* FLASH_SR register bits */ #define FLASH_BSY BIT(16) #define FLASH_BSY2 BIT(17) /* Fast programming not used => related errors not used*/ #define FLASH_PGSERR BIT(7) /* Programming sequence error */ #define FLASH_SIZERR BIT(6) /* Size error */ #define FLASH_PGAERR BIT(5) /* Programming alignment error */ #define FLASH_WRPERR BIT(4) /* Write protection error */ #define FLASH_PROGERR BIT(3) /* Programming error */ #define FLASH_OPERR BIT(1) /* Operation error */ #define FLASH_EOP BIT(0) /* End of operation */ #define FLASH_ERROR (FLASH_PGSERR | FLASH_SIZERR | FLASH_PGAERR | \ FLASH_WRPERR | FLASH_PROGERR | FLASH_OPERR) /* register unlock keys */ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB /* option register unlock key */ #define OPTKEY1 0x08192A3B #define OPTKEY2 0x4C5D6E7F /* FLASH_OPTR register bits */ #define FLASH_RDP_MASK 0xFF #define FLASH_G0_DUAL_BANK BIT(21) #define FLASH_G4_DUAL_BANK BIT(22) #define FLASH_L4_DUAL_BANK BIT(21) #define FLASH_L4R_DBANK BIT(22) #define FLASH_LRR_DB1M BIT(21) #define FLASH_L5_DBANK BIT(22) #define FLASH_L5_DB256 BIT(21) #define FLASH_U5_DUALBANK BIT(21) #define FLASH_TZEN BIT(31) /* FLASH secure block based bank 1/2 register offsets */ #define FLASH_SECBB1(X) (0x80 + 4 * (X - 1)) #define FLASH_SECBB2(X) (0xA0 + 4 * (X - 1)) #define FLASH_SECBB_SECURE 0xFFFFFFFF #define FLASH_SECBB_NON_SECURE 0 /* IDCODE register possible addresses */ #define DBGMCU_IDCODE_G0 0x40015800 #define DBGMCU_IDCODE_L4_G4 0xE0042000 #define DBGMCU_IDCODE_L5 0xE0044000 #define UID64_DEVNUM 0x1FFF7580 #define UID64_IDS 0x1FFF7584 #define UID64_IDS_STM32WL 0x0080E115 /* Supported device IDs */ #define DEVID_STM32L47_L48XX 0x415 #define DEVID_STM32L43_L44XX 0x435 #define DEVID_STM32C01XX 0x443 #define DEVID_STM32C03XX 0x453 #define DEVID_STM32G05_G06XX 0x456 #define DEVID_STM32G07_G08XX 0x460 #define DEVID_STM32L49_L4AXX 0x461 #define DEVID_STM32L45_L46XX 0x462 #define DEVID_STM32L41_L42XX 0x464 #define DEVID_STM32G03_G04XX 0x466 #define DEVID_STM32G0B_G0CXX 0x467 #define DEVID_STM32G43_G44XX 0x468 #define DEVID_STM32G47_G48XX 0x469 #define DEVID_STM32L4R_L4SXX 0x470 #define DEVID_STM32L4P_L4QXX 0x471 #define DEVID_STM32L55_L56XX 0x472 #define DEVID_STM32G49_G4AXX 0x479 #define DEVID_STM32U57_U58XX 0x482 #define DEVID_STM32WB1XX 0x494 #define DEVID_STM32WB5XX 0x495 #define DEVID_STM32WB3XX 0x496 #define DEVID_STM32WLE_WL5XX 0x497 /* known Flash base addresses */ #define STM32_FLASH_BANK_BASE 0x08000000 #define STM32_FLASH_S_BANK_BASE 0x0C000000 /* offset between non-secure and secure flash registers */ #define STM32L5_REGS_SEC_OFFSET 0x10000000 /* 100 bytes as loader stack should be large enough for the loader to operate */ #define LDR_STACK_SIZE 100 struct stm32l4_work_area { struct stm32l4_loader_params { uint32_t flash_sr_addr; uint32_t flash_cr_addr; uint32_t flash_word_size; uint32_t flash_sr_bsy_mask; } params; uint8_t stack[LDR_STACK_SIZE]; struct flash_async_algorithm_circbuf { /* note: stm32l4_work_area struct is shared between the loader * and stm32l4x flash driver. * * '*wp' and '*rp' pointers' size is 4 bytes each since stm32l4x * devices have 32-bit processors. * however when used in openocd code, their size depends on the host * if the host is 32-bit, then the size is 4 bytes each. * if the host is 64-bit, then the size is 8 bytes each. * to avoid this size difference, change their types depending on the * usage (pointers for the loader, and 32-bit integers in openocd code). */ #ifdef OPENOCD_CONTRIB_LOADERS_FLASH_STM32_STM32L4X uint8_t *wp; uint8_t *rp; #else uint32_t wp; uint32_t rp; #endif /* OPENOCD_CONTRIB_LOADERS_FLASH_STM32_STM32L4X */ } fifo; }; #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/stm32lx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Clement Burin des Roziers * * clement.burin-des-roziers@hikob.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> #include <target/cortex_m.h> /* stm32lx flash register locations */ #define FLASH_ACR 0x00 #define FLASH_PECR 0x04 #define FLASH_PDKEYR 0x08 #define FLASH_PEKEYR 0x0C #define FLASH_PRGKEYR 0x10 #define FLASH_OPTKEYR 0x14 #define FLASH_SR 0x18 #define FLASH_OBR 0x1C #define FLASH_WRPR 0x20 /* FLASH_ACR bites */ #define FLASH_ACR__LATENCY (1<<0) #define FLASH_ACR__PRFTEN (1<<1) #define FLASH_ACR__ACC64 (1<<2) #define FLASH_ACR__SLEEP_PD (1<<3) #define FLASH_ACR__RUN_PD (1<<4) /* FLASH_PECR bits */ #define FLASH_PECR__PELOCK (1<<0) #define FLASH_PECR__PRGLOCK (1<<1) #define FLASH_PECR__OPTLOCK (1<<2) #define FLASH_PECR__PROG (1<<3) #define FLASH_PECR__DATA (1<<4) #define FLASH_PECR__FTDW (1<<8) #define FLASH_PECR__ERASE (1<<9) #define FLASH_PECR__FPRG (1<<10) #define FLASH_PECR__EOPIE (1<<16) #define FLASH_PECR__ERRIE (1<<17) #define FLASH_PECR__OBL_LAUNCH (1<<18) /* FLASH_SR bits */ #define FLASH_SR__BSY (1<<0) #define FLASH_SR__EOP (1<<1) #define FLASH_SR__ENDHV (1<<2) #define FLASH_SR__READY (1<<3) #define FLASH_SR__WRPERR (1<<8) #define FLASH_SR__PGAERR (1<<9) #define FLASH_SR__SIZERR (1<<10) #define FLASH_SR__OPTVERR (1<<11) /* Unlock keys */ #define PEKEY1 0x89ABCDEF #define PEKEY2 0x02030405 #define PRGKEY1 0x8C9DAEBF #define PRGKEY2 0x13141516 #define OPTKEY1 0xFBEAD9C8 #define OPTKEY2 0x24252627 /* other registers */ #define DBGMCU_IDCODE 0xE0042000 #define DBGMCU_IDCODE_L0 0x40015800 /* Constants */ #define FLASH_SECTOR_SIZE 4096 #define FLASH_BANK0_ADDRESS 0x08000000 /* option bytes */ #define OPTION_BYTES_ADDRESS 0x1FF80000 #define OPTION_BYTE_0_PR1 0xFFFF0000 #define OPTION_BYTE_0_PR0 0xFF5500AA static int stm32lx_unlock_program_memory(struct flash_bank *bank); static int stm32lx_lock_program_memory(struct flash_bank *bank); static int stm32lx_enable_write_half_page(struct flash_bank *bank); static int stm32lx_erase_sector(struct flash_bank *bank, int sector); static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank); static int stm32lx_lock(struct flash_bank *bank); static int stm32lx_unlock(struct flash_bank *bank); static int stm32lx_mass_erase(struct flash_bank *bank); static int stm32lx_wait_until_bsy_clear_timeout(struct flash_bank *bank, int timeout); static int stm32lx_update_part_info(struct flash_bank *bank, uint16_t flash_size_in_kb); struct stm32lx_rev { uint16_t rev; const char *str; }; struct stm32lx_part_info { uint16_t id; const char *device_str; const struct stm32lx_rev *revs; size_t num_revs; unsigned int page_size; unsigned int pages_per_sector; uint16_t max_flash_size_kb; uint16_t first_bank_size_kb; /* used when has_dual_banks is true */ bool has_dual_banks; uint32_t flash_base; /* Flash controller registers location */ uint32_t fsize_base; /* Location of FSIZE register */ }; struct stm32lx_flash_bank { bool probed; uint32_t idcode; uint32_t user_bank_size; uint32_t flash_base; struct stm32lx_part_info part_info; }; static const struct stm32lx_rev stm32_416_revs[] = { { 0x1000, "A" }, { 0x1008, "Y" }, { 0x1038, "W" }, { 0x1078, "V" }, }; static const struct stm32lx_rev stm32_417_revs[] = { { 0x1000, "A" }, { 0x1008, "Z" }, { 0x1018, "Y" }, { 0x1038, "X" } }; static const struct stm32lx_rev stm32_425_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, { 0x2008, "Y" }, { 0x2018, "1, X" }, }; static const struct stm32lx_rev stm32_427_revs[] = { { 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" }, { 0x10f8, "V" }, }; static const struct stm32lx_rev stm32_429_revs[] = { { 0x1000, "A" }, { 0x1018, "Z" }, }; static const struct stm32lx_rev stm32_436_revs[] = { { 0x1000, "A" }, { 0x1008, "Z" }, { 0x1018, "Y" }, { 0x1038, "X" }, }; static const struct stm32lx_rev stm32_437_revs[] = { { 0x1000, "A" }, }; static const struct stm32lx_rev stm32_447_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, { 0x2008, "Z" }, }; static const struct stm32lx_rev stm32_457_revs[] = { { 0x1000, "A" }, { 0x1008, "Z" }, }; static const struct stm32lx_part_info stm32lx_parts[] = { { .id = 0x416, .revs = stm32_416_revs, .num_revs = ARRAY_SIZE(stm32_416_revs), .device_str = "STM32L1xx (Cat.1 - Low/Medium Density)", .page_size = 256, .pages_per_sector = 16, .max_flash_size_kb = 128, .has_dual_banks = false, .flash_base = 0x40023C00, .fsize_base = 0x1FF8004C, }, { .id = 0x417, .revs = stm32_417_revs, .num_revs = ARRAY_SIZE(stm32_417_revs), .device_str = "STM32L0xx (Cat. 3)", .page_size = 128, .pages_per_sector = 32, .max_flash_size_kb = 64, .has_dual_banks = false, .flash_base = 0x40022000, .fsize_base = 0x1FF8007C, }, { .id = 0x425, .revs = stm32_425_revs, .num_revs = ARRAY_SIZE(stm32_425_revs), .device_str = "STM32L0xx (Cat. 2)", .page_size = 128, .pages_per_sector = 32, .max_flash_size_kb = 32, .has_dual_banks = false, .flash_base = 0x40022000, .fsize_base = 0x1FF8007C, }, { .id = 0x427, .revs = stm32_427_revs, .num_revs = ARRAY_SIZE(stm32_427_revs), .device_str = "STM32L1xx (Cat.3 - Medium+ Density)", .page_size = 256, .pages_per_sector = 16, .max_flash_size_kb = 256, .has_dual_banks = false, .flash_base = 0x40023C00, .fsize_base = 0x1FF800CC, }, { .id = 0x429, .revs = stm32_429_revs, .num_revs = ARRAY_SIZE(stm32_429_revs), .device_str = "STM32L1xx (Cat.2)", .page_size = 256, .pages_per_sector = 16, .max_flash_size_kb = 128, .has_dual_banks = false, .flash_base = 0x40023C00, .fsize_base = 0x1FF8004C, }, { .id = 0x436, .revs = stm32_436_revs, .num_revs = ARRAY_SIZE(stm32_436_revs), .device_str = "STM32L1xx (Cat.4/Cat.3 - Medium+/High Density)", .page_size = 256, .pages_per_sector = 16, .max_flash_size_kb = 384, .first_bank_size_kb = 192, .has_dual_banks = true, .flash_base = 0x40023C00, .fsize_base = 0x1FF800CC, }, { .id = 0x437, .revs = stm32_437_revs, .num_revs = ARRAY_SIZE(stm32_437_revs), .device_str = "STM32L1xx (Cat.5/Cat.6)", .page_size = 256, .pages_per_sector = 16, .max_flash_size_kb = 512, .first_bank_size_kb = 0, /* determined in runtime */ .has_dual_banks = true, .flash_base = 0x40023C00, .fsize_base = 0x1FF800CC, }, { .id = 0x447, .revs = stm32_447_revs, .num_revs = ARRAY_SIZE(stm32_447_revs), .device_str = "STM32L0xx (Cat.5)", .page_size = 128, .pages_per_sector = 32, .max_flash_size_kb = 192, .first_bank_size_kb = 0, /* determined in runtime */ .has_dual_banks = false, /* determined in runtime */ .flash_base = 0x40022000, .fsize_base = 0x1FF8007C, }, { .id = 0x457, .revs = stm32_457_revs, .num_revs = ARRAY_SIZE(stm32_457_revs), .device_str = "STM32L0xx (Cat.1)", .page_size = 128, .pages_per_sector = 32, .max_flash_size_kb = 16, .has_dual_banks = false, .flash_base = 0x40022000, .fsize_base = 0x1FF8007C, }, }; /* flash bank stm32lx <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command) { struct stm32lx_flash_bank *stm32lx_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; /* Create the bank structure */ stm32lx_info = calloc(1, sizeof(*stm32lx_info)); /* Check allocation */ if (!stm32lx_info) { LOG_ERROR("failed to allocate bank structure"); return ERROR_FAIL; } bank->driver_priv = stm32lx_info; stm32lx_info->probed = false; stm32lx_info->user_bank_size = bank->size; /* the stm32l erased value is 0x00 */ bank->default_padded_value = bank->erased_value = 0x00; return ERROR_OK; } COMMAND_HANDLER(stm32lx_handle_mass_erase_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = stm32lx_mass_erase(bank); if (retval == ERROR_OK) command_print(CMD, "stm32lx mass erase complete"); else command_print(CMD, "stm32lx mass erase failed"); return retval; } COMMAND_HANDLER(stm32lx_handle_lock_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = stm32lx_lock(bank); if (retval == ERROR_OK) command_print(CMD, "STM32Lx locked, takes effect after power cycle."); else command_print(CMD, "STM32Lx lock failed"); return retval; } COMMAND_HANDLER(stm32lx_handle_unlock_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = stm32lx_unlock(bank); if (retval == ERROR_OK) command_print(CMD, "STM32Lx unlocked, takes effect after power cycle."); else command_print(CMD, "STM32Lx unlock failed"); return retval; } static int stm32lx_protect_check(struct flash_bank *bank) { int retval; struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; uint32_t wrpr; /* * Read the WRPR word, and check each bit (corresponding to each * flash sector */ retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_WRPR, &wrpr); if (retval != ERROR_OK) return retval; for (unsigned int i = 0; i < bank->num_sectors; i++) { if (wrpr & (1 << i)) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; } return ERROR_OK; } static int stm32lx_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int retval; /* * It could be possible to do a mass erase if all sectors must be * erased, but it is not implemented yet. */ if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* * Loop over the selected sectors and erase them */ for (unsigned int i = first; i <= last; i++) { retval = stm32lx_erase_sector(bank, i); if (retval != ERROR_OK) return retval; bank->sectors[i].is_erased = 1; } return ERROR_OK; } static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; uint32_t hp_nb = stm32lx_info->part_info.page_size / 2; uint32_t buffer_size = (16384 / hp_nb) * hp_nb; /* must be multiple of hp_nb */ struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; static const uint8_t stm32lx_flash_write_code[] = { #include "../../../contrib/loaders/flash/stm32/stm32lx.inc" }; /* Make sure we're performing a half-page aligned write. */ if (offset % hp_nb) { LOG_ERROR("The offset must be %" PRIu32 "B-aligned but it is %" PRIi32 "B)", hp_nb, offset); return ERROR_FAIL; } if (count % hp_nb) { LOG_ERROR("The byte count must be %" PRIu32 "B-aligned but count is %" PRIu32 "B)", hp_nb, count); return ERROR_FAIL; } /* flash write code */ if (target_alloc_working_area(target, sizeof(stm32lx_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_DEBUG("no working area for block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* Write the flashing code */ retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32lx_flash_write_code), stm32lx_flash_write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } /* Allocate half pages memory */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { if (buffer_size > 1024) buffer_size -= 1024; else buffer_size /= 2; if (buffer_size <= stm32lx_info->part_info.page_size) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } else { /* Make sure we're still asking for an integral number of half-pages */ buffer_size -= buffer_size % hp_nb; } } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* Enable half-page write */ retval = stm32lx_enable_write_half_page(bank); if (retval != ERROR_OK) { target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; } struct armv7m_common *armv7m = target_to_armv7m(target); if (!armv7m) { /* something is very wrong if armv7m is NULL */ LOG_ERROR("unable to get armv7m target"); return retval; } /* save any DEMCR flags and configure target to catch any Hard Faults */ uint32_t demcr_save = armv7m->demcr; armv7m->demcr = VC_HARDERR; /* Loop while there are bytes to write */ while (count > 0) { uint32_t this_count; this_count = (count > buffer_size) ? buffer_size : count; /* Write the next half pages */ retval = target_write_buffer(target, source->address, this_count, buffer); if (retval != ERROR_OK) break; /* 4: Store useful information in the registers */ /* the destination address of the copy (R0) */ buf_set_u32(reg_params[0].value, 0, 32, address); /* The source address of the copy (R1) */ buf_set_u32(reg_params[1].value, 0, 32, source->address); /* The number of half pages to copy (R2) */ buf_set_u32(reg_params[2].value, 0, 32, this_count / hp_nb); /* The size in byes of a half page (R3) */ buf_set_u32(reg_params[3].value, 0, 32, hp_nb); /* The flash base address (R4) */ buf_set_u32(reg_params[4].value, 0, 32, stm32lx_info->flash_base); /* 5: Execute the bunch of code */ retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, write_algorithm->address, 0, 10000, &armv7m_info); if (retval != ERROR_OK) break; /* check for Hard Fault */ if (armv7m->exception_number == 3) break; /* 6: Wait while busy */ retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) break; buffer += this_count; address += this_count; count -= this_count; } /* restore previous flags */ armv7m->demcr = demcr_save; if (armv7m->exception_number == 3) { /* the stm32l15x devices seem to have an issue when blank. * if a ram loader is executed on a blank device it will * Hard Fault, this issue does not happen for a already programmed device. * A related issue is described in the stm32l151xx errata (Doc ID 17721 Rev 6 - 2.1.3). * The workaround of handling the Hard Fault exception does work, but makes the * loader more complicated, as a compromise we manually write the pages, programming time * is reduced by 50% using this slower method. */ LOG_WARNING("Couldn't use loader, falling back to page memory writes"); while (count > 0) { uint32_t this_count; this_count = (count > hp_nb) ? hp_nb : count; /* Write the next half pages */ retval = target_write_buffer(target, address, this_count, buffer); if (retval != ERROR_OK) break; /* Wait while busy */ retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) break; buffer += this_count; address += this_count; count -= this_count; } } if (retval == ERROR_OK) retval = stm32lx_lock_program_memory(bank); target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; } static int stm32lx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; uint32_t hp_nb = stm32lx_info->part_info.page_size / 2; uint32_t halfpages_number; uint32_t bytes_remaining = 0; uint32_t address = bank->base + offset; uint32_t bytes_written = 0; int retval, retval2; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x3) { LOG_ERROR("offset 0x%" PRIx32 " breaks required 4-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } retval = stm32lx_unlock_program_memory(bank); if (retval != ERROR_OK) return retval; /* first we need to write any unaligned head bytes up to * the next 128 byte page */ if (offset % hp_nb) bytes_remaining = MIN(count, hp_nb - (offset % hp_nb)); while (bytes_remaining > 0) { uint8_t value[4] = {0xff, 0xff, 0xff, 0xff}; /* copy remaining bytes into the write buffer */ uint32_t bytes_to_write = MIN(4, bytes_remaining); memcpy(value, buffer + bytes_written, bytes_to_write); retval = target_write_buffer(target, address, 4, value); if (retval != ERROR_OK) goto reset_pg_and_lock; bytes_written += bytes_to_write; bytes_remaining -= bytes_to_write; address += 4; retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) goto reset_pg_and_lock; } offset += bytes_written; count -= bytes_written; /* this should always pass this check here */ assert((offset % hp_nb) == 0); /* calculate half pages */ halfpages_number = count / hp_nb; if (halfpages_number) { retval = stm32lx_write_half_pages(bank, buffer + bytes_written, offset, hp_nb * halfpages_number); if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* attempt slow memory writes */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); halfpages_number = 0; } else { if (retval != ERROR_OK) return ERROR_FAIL; } } /* write any remaining bytes */ uint32_t page_bytes_written = hp_nb * halfpages_number; bytes_written += page_bytes_written; address += page_bytes_written; bytes_remaining = count - page_bytes_written; retval = stm32lx_unlock_program_memory(bank); if (retval != ERROR_OK) return retval; while (bytes_remaining > 0) { uint8_t value[4] = {0xff, 0xff, 0xff, 0xff}; /* copy remaining bytes into the write buffer */ uint32_t bytes_to_write = MIN(4, bytes_remaining); memcpy(value, buffer + bytes_written, bytes_to_write); retval = target_write_buffer(target, address, 4, value); if (retval != ERROR_OK) goto reset_pg_and_lock; bytes_written += bytes_to_write; bytes_remaining -= bytes_to_write; address += 4; retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) goto reset_pg_and_lock; } reset_pg_and_lock: retval2 = stm32lx_lock_program_memory(bank); if (retval == ERROR_OK) retval = retval2; return retval; } static int stm32lx_read_id_code(struct target *target, uint32_t *id) { struct armv7m_common *armv7m = target_to_armv7m(target); int retval; if (armv7m->arm.arch == ARM_ARCH_V6M) retval = target_read_u32(target, DBGMCU_IDCODE_L0, id); else /* read stm32 device id register */ retval = target_read_u32(target, DBGMCU_IDCODE, id); return retval; } static int stm32lx_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; uint16_t flash_size_in_kb; uint32_t device_id; uint32_t base_address = FLASH_BANK0_ADDRESS; uint32_t second_bank_base; unsigned int n; stm32lx_info->probed = false; int retval = stm32lx_read_id_code(bank->target, &device_id); if (retval != ERROR_OK) return retval; stm32lx_info->idcode = device_id; LOG_DEBUG("device id = 0x%08" PRIx32 "", device_id); for (n = 0; n < ARRAY_SIZE(stm32lx_parts); n++) { if ((device_id & 0xfff) == stm32lx_parts[n].id) { stm32lx_info->part_info = stm32lx_parts[n]; break; } } if (n == ARRAY_SIZE(stm32lx_parts)) { LOG_ERROR("Cannot identify target as an STM32 L0 or L1 family device."); return ERROR_FAIL; } else { LOG_INFO("Device: %s", stm32lx_info->part_info.device_str); } stm32lx_info->flash_base = stm32lx_info->part_info.flash_base; /* Get the flash size from target. */ retval = target_read_u16(target, stm32lx_info->part_info.fsize_base, &flash_size_in_kb); /* 0x436 devices report their flash size as a 0 or 1 code indicating 384K * or 256K, respectively. Please see RM0038 r8 or newer and refer to * section 30.1.1. */ if (retval == ERROR_OK && (device_id & 0xfff) == 0x436) { if (flash_size_in_kb == 0) flash_size_in_kb = 384; else if (flash_size_in_kb == 1) flash_size_in_kb = 256; } /* 0x429 devices only use the lowest 8 bits of the flash size register */ if (retval == ERROR_OK && (device_id & 0xfff) == 0x429) { flash_size_in_kb &= 0xff; } /* Failed reading flash size or flash size invalid (early silicon), * default to max target family */ if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { LOG_WARNING("STM32L flash size failed, probe inaccurate - assuming %dk flash", stm32lx_info->part_info.max_flash_size_kb); flash_size_in_kb = stm32lx_info->part_info.max_flash_size_kb; } else if (flash_size_in_kb > stm32lx_info->part_info.max_flash_size_kb) { LOG_WARNING("STM32L probed flash size assumed incorrect since FLASH_SIZE=%dk > %dk, - assuming %dk flash", flash_size_in_kb, stm32lx_info->part_info.max_flash_size_kb, stm32lx_info->part_info.max_flash_size_kb); flash_size_in_kb = stm32lx_info->part_info.max_flash_size_kb; } /* Overwrite default dual-bank configuration */ retval = stm32lx_update_part_info(bank, flash_size_in_kb); if (retval != ERROR_OK) return ERROR_FAIL; if (stm32lx_info->part_info.has_dual_banks) { /* Use the configured base address to determine if this is the first or second flash bank. * Verify that the base address is reasonably correct and determine the flash bank size */ second_bank_base = base_address + stm32lx_info->part_info.first_bank_size_kb * 1024; if (bank->base == second_bank_base || !bank->base) { /* This is the second bank */ base_address = second_bank_base; flash_size_in_kb = flash_size_in_kb - stm32lx_info->part_info.first_bank_size_kb; } else if (bank->base == base_address) { /* This is the first bank */ flash_size_in_kb = stm32lx_info->part_info.first_bank_size_kb; } else { LOG_WARNING("STM32L flash bank base address config is incorrect. " TARGET_ADDR_FMT " but should rather be 0x%" PRIx32 " or 0x%" PRIx32, bank->base, base_address, second_bank_base); return ERROR_FAIL; } LOG_INFO("STM32L flash has dual banks. Bank (%u) size is %dkb, base address is 0x%" PRIx32, bank->bank_number, flash_size_in_kb, base_address); } else { LOG_INFO("STM32L flash size is %dkb, base address is 0x%" PRIx32, flash_size_in_kb, base_address); } /* if the user sets the size manually then ignore the probed value * this allows us to work around devices that have a invalid flash size register value */ if (stm32lx_info->user_bank_size) { flash_size_in_kb = stm32lx_info->user_bank_size / 1024; LOG_INFO("ignoring flash probed value, using configured bank size: %dkbytes", flash_size_in_kb); } /* calculate numbers of sectors (4kB per sector) */ unsigned int num_sectors = (flash_size_in_kb * 1024) / FLASH_SECTOR_SIZE; free(bank->sectors); bank->size = flash_size_in_kb * 1024; bank->base = base_address; bank->num_sectors = num_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); if (!bank->sectors) { LOG_ERROR("failed to allocate bank sectors"); return ERROR_FAIL; } for (unsigned int i = 0; i < num_sectors; i++) { bank->sectors[i].offset = i * FLASH_SECTOR_SIZE; bank->sectors[i].size = FLASH_SECTOR_SIZE; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } stm32lx_info->probed = true; return ERROR_OK; } static int stm32lx_auto_probe(struct flash_bank *bank) { struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; if (stm32lx_info->probed) return ERROR_OK; return stm32lx_probe(bank); } /* This method must return a string displaying information about the bank */ static int stm32lx_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; const struct stm32lx_part_info *info = &stm32lx_info->part_info; uint16_t rev_id = stm32lx_info->idcode >> 16; const char *rev_str = NULL; if (!stm32lx_info->probed) { int retval = stm32lx_probe(bank); if (retval != ERROR_OK) { command_print_sameline(cmd, "Unable to find bank information."); return retval; } } for (unsigned int i = 0; i < info->num_revs; i++) if (rev_id == info->revs[i].rev) rev_str = info->revs[i].str; if (rev_str) { command_print_sameline(cmd, "%s - Rev: %s", info->device_str, rev_str); } else { command_print_sameline(cmd, "%s - Rev: unknown (0x%04x)", info->device_str, rev_id); } return ERROR_OK; } static const struct command_registration stm32lx_exec_command_handlers[] = { { .name = "mass_erase", .handler = stm32lx_handle_mass_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Erase entire flash device. including available EEPROM", }, { .name = "lock", .handler = stm32lx_handle_lock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Increase the readout protection to Level 1.", }, { .name = "unlock", .handler = stm32lx_handle_unlock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Lower the readout protection from Level 1 to 0.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration stm32lx_command_handlers[] = { { .name = "stm32lx", .mode = COMMAND_ANY, .help = "stm32lx flash command group", .usage = "", .chain = stm32lx_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver stm32lx_flash = { .name = "stm32lx", .commands = stm32lx_command_handlers, .flash_bank_command = stm32lx_flash_bank_command, .erase = stm32lx_erase, .write = stm32lx_write, .read = default_flash_read, .probe = stm32lx_probe, .auto_probe = stm32lx_auto_probe, .erase_check = default_flash_blank_check, .protect_check = stm32lx_protect_check, .info = stm32lx_get_info, .free_driver_priv = default_flash_free_driver_priv, }; /* Static methods implementation */ static int stm32lx_unlock_program_memory(struct flash_bank *bank) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; int retval; uint32_t reg32; /* * Unlocking the program memory is done by unlocking the PECR, * then by writing the 2 PRGKEY to the PRGKEYR register */ /* check flash is not already unlocked */ retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; if ((reg32 & FLASH_PECR__PRGLOCK) == 0) return ERROR_OK; /* To unlock the PECR write the 2 PEKEY to the PEKEYR register */ retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PEKEYR, PEKEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PEKEYR, PEKEY2); if (retval != ERROR_OK) return retval; /* Make sure it worked */ retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; if (reg32 & FLASH_PECR__PELOCK) { LOG_ERROR("PELOCK is not cleared :("); return ERROR_FLASH_OPERATION_FAILED; } retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PRGKEYR, PRGKEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PRGKEYR, PRGKEY2); if (retval != ERROR_OK) return retval; /* Make sure it worked */ retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; if (reg32 & FLASH_PECR__PRGLOCK) { LOG_ERROR("PRGLOCK is not cleared :("); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int stm32lx_enable_write_half_page(struct flash_bank *bank) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; int retval; uint32_t reg32; /** * Unlock the program memory, then set the FPRG bit in the PECR register. */ retval = stm32lx_unlock_program_memory(bank); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; reg32 |= FLASH_PECR__FPRG; retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR, reg32); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; reg32 |= FLASH_PECR__PROG; retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR, reg32); return retval; } static int stm32lx_lock_program_memory(struct flash_bank *bank) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; int retval; uint32_t reg32; /* To lock the program memory, simply set the lock bit and lock PECR */ retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; reg32 |= FLASH_PECR__PRGLOCK; retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR, reg32); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; reg32 |= FLASH_PECR__PELOCK; retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR, reg32); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32lx_erase_sector(struct flash_bank *bank, int sector) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; int retval; uint32_t reg32; /* * To erase a sector (i.e. stm32lx_info->part_info.pages_per_sector pages), * first unlock the memory, loop over the pages of this sector * and write 0x0 to its first word. */ retval = stm32lx_unlock_program_memory(bank); if (retval != ERROR_OK) return retval; for (int page = 0; page < (int)stm32lx_info->part_info.pages_per_sector; page++) { reg32 = FLASH_PECR__PROG | FLASH_PECR__ERASE; retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR, reg32); if (retval != ERROR_OK) return retval; retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) return retval; uint32_t addr = bank->base + bank->sectors[sector].offset + (page * stm32lx_info->part_info.page_size); retval = target_write_u32(target, addr, 0x0); if (retval != ERROR_OK) return retval; retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) return retval; } retval = stm32lx_lock_program_memory(bank); if (retval != ERROR_OK) return retval; return ERROR_OK; } static inline int stm32lx_get_flash_status(struct flash_bank *bank, uint32_t *status) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; return target_read_u32(target, stm32lx_info->flash_base + FLASH_SR, status); } static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank) { return stm32lx_wait_until_bsy_clear_timeout(bank, 100); } static int stm32lx_unlock_options_bytes(struct flash_bank *bank) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; int retval; uint32_t reg32; /* * Unlocking the options bytes is done by unlocking the PECR, * then by writing the 2 FLASH_PEKEYR to the FLASH_OPTKEYR register */ /* check flash is not already unlocked */ retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; if ((reg32 & FLASH_PECR__OPTLOCK) == 0) return ERROR_OK; if ((reg32 & FLASH_PECR__PELOCK) != 0) { retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PEKEYR, PEKEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PEKEYR, PEKEY2); if (retval != ERROR_OK) return retval; } /* To unlock the PECR write the 2 OPTKEY to the FLASH_OPTKEYR register */ retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_OPTKEYR, OPTKEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_OPTKEYR, OPTKEY2); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32lx_wait_until_bsy_clear_timeout(struct flash_bank *bank, int timeout) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; uint32_t status; int retval = ERROR_OK; /* wait for busy to clear */ for (;;) { retval = stm32lx_get_flash_status(bank, &status); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%" PRIx32 "", status); if ((status & FLASH_SR__BSY) == 0) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FAIL; } alive_sleep(1); } if (status & FLASH_SR__WRPERR) { LOG_ERROR("access denied / write protected"); retval = ERROR_FAIL; } if (status & FLASH_SR__PGAERR) { LOG_ERROR("invalid program address"); retval = ERROR_FAIL; } /* Clear but report errors */ if (status & FLASH_SR__OPTVERR) { /* If this operation fails, we ignore it and report the original retval */ target_write_u32(target, stm32lx_info->flash_base + FLASH_SR, status & FLASH_SR__OPTVERR); } return retval; } static int stm32lx_obl_launch(struct flash_bank *bank) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; int retval; /* This will fail as the target gets immediately rebooted */ target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR, FLASH_PECR__OBL_LAUNCH); size_t tries = 10; do { target_halt(target); retval = target_poll(target); } while (--tries > 0 && (retval != ERROR_OK || target->state != TARGET_HALTED)); return tries ? ERROR_OK : ERROR_FAIL; } static int stm32lx_lock(struct flash_bank *bank) { int retval; struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = stm32lx_unlock_options_bytes(bank); if (retval != ERROR_OK) return retval; /* set the RDP protection level to 1 */ retval = target_write_u32(target, OPTION_BYTES_ADDRESS, OPTION_BYTE_0_PR1); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32lx_unlock(struct flash_bank *bank) { int retval; struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = stm32lx_unlock_options_bytes(bank); if (retval != ERROR_OK) return retval; /* set the RDP protection level to 0 */ retval = target_write_u32(target, OPTION_BYTES_ADDRESS, OPTION_BYTE_0_PR0); if (retval != ERROR_OK) return retval; retval = stm32lx_wait_until_bsy_clear_timeout(bank, 30000); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32lx_mass_erase(struct flash_bank *bank) { int retval; struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = NULL; uint32_t reg32; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } stm32lx_info = bank->driver_priv; retval = stm32lx_lock(bank); if (retval != ERROR_OK) return retval; retval = stm32lx_obl_launch(bank); if (retval != ERROR_OK) return retval; retval = stm32lx_unlock(bank); if (retval != ERROR_OK) return retval; retval = stm32lx_obl_launch(bank); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR, reg32 | FLASH_PECR__OPTLOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32lx_update_part_info(struct flash_bank *bank, uint16_t flash_size_in_kb) { struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; switch (stm32lx_info->part_info.id) { case 0x447: /* STM32L0xx (Cat.5) devices */ if (flash_size_in_kb == 192 || flash_size_in_kb == 128) { stm32lx_info->part_info.first_bank_size_kb = flash_size_in_kb / 2; stm32lx_info->part_info.has_dual_banks = true; } break; case 0x437: /* STM32L1xx (Cat.5/Cat.6) */ stm32lx_info->part_info.first_bank_size_kb = flash_size_in_kb / 2; break; } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/stmqspi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2016 - 2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * * * * Copyright (C) 2010 by Antonio Borneo * * borneo.antonio@gmail.com * ***************************************************************************/ /* STM QuadSPI (QSPI) and OctoSPI (OCTOSPI) controller are SPI bus controllers * specifically designed for SPI memories. * Two working modes are available: * - indirect mode: the SPI is controlled by SW. Any custom commands can be sent * on the bus. * - memory mapped mode: the SPI is under QSPI/OCTOSPI control. Memory content * is directly accessible in CPU memory space. CPU can read and execute from * memory (but not write to) */ /* ATTENTION: * To have flash mapped in CPU memory space, the QSPI/OCTOSPI controller * has to be in "memory mapped mode". This requires following constraints: * 1) The command "reset init" has to initialize QSPI/OCTOSPI controller and put * it in memory mapped mode; * 2) every command in this file has to return to prompt in memory mapped mode. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <helper/bits.h> #include <helper/time_support.h> #include <target/algorithm.h> #include <target/armv7m.h> #include <target/image.h> #include "stmqspi.h" #include "sfdp.h" /* deprecated */ #undef SPIFLASH_READ #undef SPIFLASH_PAGE_PROGRAM /* saved mode settings */ #define QSPI_MODE (stmqspi_info->saved_ccr & \ (0xF0000000U | QSPI_DCYC_MASK | QSPI_4LINE_MODE | QSPI_ALTB_MODE | QSPI_ADDR4)) /* saved read mode settings but indirect read instead of memory mapped * in particular, use the dummy cycle setting from this saved setting */ #define QSPI_CCR_READ (QSPI_READ_MODE | (stmqspi_info->saved_ccr & \ (0xF0000000U | QSPI_DCYC_MASK | QSPI_4LINE_MODE | QSPI_ALTB_MODE | QSPI_ADDR4 | 0xFF))) /* QSPI_CCR for various other commands, these never use dummy cycles nor alternate bytes */ #define QSPI_CCR_READ_STATUS \ ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB) | \ (QSPI_READ_MODE | SPIFLASH_READ_STATUS)) #define QSPI_CCR_READ_ID \ ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB) | \ (QSPI_READ_MODE | SPIFLASH_READ_ID)) #define QSPI_CCR_READ_MID \ ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB) | \ (QSPI_READ_MODE | SPIFLASH_READ_MID)) /* always use 3-byte addresses for read SFDP */ #define QSPI_CCR_READ_SFDP \ ((QSPI_MODE & ~QSPI_DCYC_MASK & ~QSPI_ADDR4 & QSPI_NO_ALTB) | \ (QSPI_READ_MODE | QSPI_ADDR3 | SPIFLASH_READ_SFDP)) #define QSPI_CCR_WRITE_ENABLE \ ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB & QSPI_NO_DATA) | \ (QSPI_WRITE_MODE | SPIFLASH_WRITE_ENABLE)) #define QSPI_CCR_SECTOR_ERASE \ ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ALTB & QSPI_NO_DATA) | \ (QSPI_WRITE_MODE | stmqspi_info->dev.erase_cmd)) #define QSPI_CCR_MASS_ERASE \ ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB & QSPI_NO_DATA) | \ (QSPI_WRITE_MODE | stmqspi_info->dev.chip_erase_cmd)) #define QSPI_CCR_PAGE_PROG \ ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ALTB) | \ (QSPI_WRITE_MODE | stmqspi_info->dev.pprog_cmd)) /* saved mode settings */ #define OCTOSPI_MODE (stmqspi_info->saved_cr & 0xCFFFFFFF) #define OPI_MODE ((stmqspi_info->saved_ccr & OCTOSPI_ISIZE_MASK) != 0) #define OCTOSPI_MODE_CCR (stmqspi_info->saved_ccr & \ (0xF0000000U | OCTOSPI_8LINE_MODE | OCTOSPI_ALTB_MODE | OCTOSPI_ADDR4)) /* use saved ccr for read */ #define OCTOSPI_CCR_READ OCTOSPI_MODE_CCR /* OCTOSPI_CCR for various other commands, these never use alternate bytes * * for READ_STATUS and READ_ID, 4-byte address 0 * * 4 dummy cycles must sent in OPI mode when DQS is disabled. However, when * * DQS is enabled, some STM32 devices need at least 6 dummy cycles for * * proper operation, but otherwise the actual number has no effect! * * E.g. RM0432 Rev. 7 is incorrect regarding this: L4R9 works well with 4 * * dummy clocks whereas L4P5 not at all. * */ #define OPI_DUMMY \ ((stmqspi_info->saved_ccr & OCTOSPI_DQSEN) ? 6U : 4U) #define OCTOSPI_CCR_READ_STATUS \ ((OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & \ (OPI_MODE ? ~0U : OCTOSPI_NO_ADDR) & OCTOSPI_NO_ALTB)) #define OCTOSPI_CCR_READ_ID \ ((OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & \ (OPI_MODE ? ~0U : OCTOSPI_NO_ADDR) & OCTOSPI_NO_ALTB)) #define OCTOSPI_CCR_READ_MID OCTOSPI_CCR_READ_ID /* 4-byte address in octo mode, else 3-byte address for read SFDP */ #define OCTOSPI_CCR_READ_SFDP(len) \ ((OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & ~OCTOSPI_ADDR4 & OCTOSPI_NO_ALTB) | \ (((len) < 4) ? OCTOSPI_ADDR3 : OCTOSPI_ADDR4)) #define OCTOSPI_CCR_WRITE_ENABLE \ ((OCTOSPI_MODE_CCR & OCTOSPI_NO_ADDR & OCTOSPI_NO_ALTB & OCTOSPI_NO_DATA)) #define OCTOSPI_CCR_SECTOR_ERASE \ ((OCTOSPI_MODE_CCR & OCTOSPI_NO_ALTB & OCTOSPI_NO_DATA)) #define OCTOSPI_CCR_MASS_ERASE \ ((OCTOSPI_MODE_CCR & OCTOSPI_NO_ADDR & OCTOSPI_NO_ALTB & OCTOSPI_NO_DATA)) #define OCTOSPI_CCR_PAGE_PROG \ ((OCTOSPI_MODE_CCR & QSPI_NO_ALTB)) #define SPI_ADSIZE (((stmqspi_info->saved_ccr >> SPI_ADSIZE_POS) & 0x3) + 1) #define OPI_CMD(cmd) ((OPI_MODE ? ((((uint16_t)(cmd)) << 8) | (~(cmd) & 0xFFU)) : (cmd))) /* convert uint32_t into 4 uint8_t in little endian byte order */ static inline uint32_t h_to_le_32(uint32_t val) { uint32_t result; h_u32_to_le((uint8_t *)&result, val); return result; } /* Timeout in ms */ #define SPI_CMD_TIMEOUT (100) #define SPI_PROBE_TIMEOUT (100) #define SPI_MAX_TIMEOUT (2000) #define SPI_MASS_ERASE_TIMEOUT (400000) struct sector_info { uint32_t offset; uint32_t size; uint32_t result; }; struct stmqspi_flash_bank { bool probed; char devname[32]; bool octo; struct flash_device dev; uint32_t io_base; uint32_t saved_cr; /* in particular FSEL, DFM bit mask in QUADSPI_CR *AND* OCTOSPI_CR */ uint32_t saved_ccr; /* different meaning for QUADSPI and OCTOSPI */ uint32_t saved_tcr; /* only for OCTOSPI */ uint32_t saved_ir; /* only for OCTOSPI */ unsigned int sfdp_dummy1; /* number of dummy bytes for SFDP read for flash1 and octo */ unsigned int sfdp_dummy2; /* number of dummy bytes for SFDP read for flash2 */ }; static inline int octospi_cmd(struct flash_bank *bank, uint32_t mode, uint32_t ccr, uint32_t ir) { struct target *target = bank->target; const struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; const uint32_t io_base = stmqspi_info->io_base; int retval = target_write_u32(target, io_base + OCTOSPI_CR, OCTOSPI_MODE | mode); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, io_base + OCTOSPI_TCR, (stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK) | ((OPI_MODE && (mode == OCTOSPI_READ_MODE)) ? (OPI_DUMMY << OCTOSPI_DCYC_POS) : 0)); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, io_base + OCTOSPI_CCR, ccr); if (retval != ERROR_OK) return retval; return target_write_u32(target, io_base + OCTOSPI_IR, OPI_CMD(ir)); } FLASH_BANK_COMMAND_HANDLER(stmqspi_flash_bank_command) { struct stmqspi_flash_bank *stmqspi_info; uint32_t io_base; LOG_DEBUG("%s", __func__); if (CMD_ARGC < 7) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], io_base); stmqspi_info = malloc(sizeof(struct stmqspi_flash_bank)); if (!stmqspi_info) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } bank->driver_priv = stmqspi_info; stmqspi_info->sfdp_dummy1 = 0; stmqspi_info->sfdp_dummy2 = 0; stmqspi_info->probed = false; stmqspi_info->io_base = io_base; return ERROR_OK; } /* Poll busy flag */ /* timeout in ms */ static int poll_busy(struct flash_bank *bank, int timeout) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; uint32_t io_base = stmqspi_info->io_base; long long endtime; endtime = timeval_ms() + timeout; do { uint32_t spi_sr; int retval = target_read_u32(target, io_base + SPI_SR, &spi_sr); if (retval != ERROR_OK) return retval; if ((spi_sr & BIT(SPI_BUSY)) == 0) { /* Clear transmit finished flag */ return target_write_u32(target, io_base + SPI_FCR, BIT(SPI_TCF)); } else LOG_DEBUG("busy: 0x%08X", spi_sr); alive_sleep(1); } while (timeval_ms() < endtime); LOG_ERROR("Timeout while polling BUSY"); return ERROR_FLASH_OPERATION_FAILED; } static int stmqspi_abort(struct flash_bank *bank) { struct target *target = bank->target; const struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; const uint32_t io_base = stmqspi_info->io_base; uint32_t cr; int retval = target_read_u32(target, io_base + SPI_CR, &cr); if (retval != ERROR_OK) cr = 0; return target_write_u32(target, io_base + SPI_CR, cr | BIT(SPI_ABORT)); } /* Set to memory-mapped mode, e.g. after an error */ static int set_mm_mode(struct flash_bank *bank) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; uint32_t io_base = stmqspi_info->io_base; int retval; /* Reset Address register bits 0 and 1, see various errata sheets */ retval = target_write_u32(target, io_base + SPI_AR, 0x0); if (retval != ERROR_OK) return retval; /* Abort any previous operation */ retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; /* Wait for busy to be cleared */ retval = poll_busy(bank, SPI_PROBE_TIMEOUT); if (retval != ERROR_OK) return retval; /* Finally switch to memory mapped mode */ if (IS_OCTOSPI) { retval = target_write_u32(target, io_base + OCTOSPI_CR, OCTOSPI_MODE | OCTOSPI_MM_MODE); if (retval == ERROR_OK) retval = target_write_u32(target, io_base + OCTOSPI_CCR, stmqspi_info->saved_ccr); if (retval == ERROR_OK) retval = target_write_u32(target, io_base + OCTOSPI_TCR, stmqspi_info->saved_tcr); if (retval == ERROR_OK) retval = target_write_u32(target, io_base + OCTOSPI_IR, stmqspi_info->saved_ir); } else { retval = target_write_u32(target, io_base + QSPI_CR, stmqspi_info->saved_cr); if (retval == ERROR_OK) retval = target_write_u32(target, io_base + QSPI_CCR, stmqspi_info->saved_ccr); } return retval; } /* Read the status register of the external SPI flash chip(s). */ static int read_status_reg(struct flash_bank *bank, uint16_t *status) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; uint32_t io_base = stmqspi_info->io_base; uint8_t data; int count, retval; /* Abort any previous operation */ retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; /* Wait for busy to be cleared */ retval = poll_busy(bank, SPI_PROBE_TIMEOUT); if (retval != ERROR_OK) goto err; /* Read always two (for DTR mode) bytes per chip */ count = 2; retval = target_write_u32(target, io_base + SPI_DLR, ((stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 2 * count : count) - 1); if (retval != ERROR_OK) goto err; /* Read status */ if (IS_OCTOSPI) { retval = octospi_cmd(bank, OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_STATUS, SPIFLASH_READ_STATUS); if (OPI_MODE) { /* Dummy address 0, only required for 8-line mode */ retval = target_write_u32(target, io_base + SPI_AR, 0); if (retval != ERROR_OK) goto err; } } else retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_STATUS); if (retval != ERROR_OK) goto err; *status = 0; /* for debugging only */ uint32_t dummy; (void)target_read_u32(target, io_base + SPI_SR, &dummy); for ( ; count > 0; --count) { if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) { /* get status of flash 1 in dual mode or flash 1 only mode */ retval = target_read_u8(target, io_base + SPI_DR, &data); if (retval != ERROR_OK) goto err; *status |= data; } if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) { /* get status of flash 2 in dual mode or flash 2 only mode */ retval = target_read_u8(target, io_base + SPI_DR, &data); if (retval != ERROR_OK) goto err; *status |= ((uint16_t)data) << 8; } } LOG_DEBUG("flash status regs: 0x%04" PRIx16, *status); err: return retval; } /* check for WIP (write in progress) bit(s) in status register(s) */ /* timeout in ms */ static int wait_till_ready(struct flash_bank *bank, int timeout) { uint16_t status; int retval; long long endtime; endtime = timeval_ms() + timeout; do { /* Read flash status register(s) */ retval = read_status_reg(bank, &status); if (retval != ERROR_OK) return retval; if ((status & ((SPIFLASH_BSY_BIT << 8) | SPIFLASH_BSY_BIT)) == 0) return retval; alive_sleep(25); } while (timeval_ms() < endtime); LOG_ERROR("timeout"); return ERROR_FLASH_OPERATION_FAILED; } /* Send "write enable" command to SPI flash chip(s). */ static int qspi_write_enable(struct flash_bank *bank) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; uint32_t io_base = stmqspi_info->io_base; uint16_t status; int retval; /* Abort any previous operation */ retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; /* Wait for busy to be cleared */ retval = poll_busy(bank, SPI_PROBE_TIMEOUT); if (retval != ERROR_OK) goto err; /* Send write enable command */ if (IS_OCTOSPI) { retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, OCTOSPI_CCR_WRITE_ENABLE, SPIFLASH_WRITE_ENABLE); if (OPI_MODE) { /* Dummy address 0, only required for 8-line mode */ retval = target_write_u32(target, io_base + SPI_AR, 0); if (retval != ERROR_OK) goto err; } } else retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_WRITE_ENABLE); if (retval != ERROR_OK) goto err; /* Wait for transmit of command completed */ poll_busy(bank, SPI_CMD_TIMEOUT); if (retval != ERROR_OK) goto err; /* Read flash status register */ retval = read_status_reg(bank, &status); if (retval != ERROR_OK) goto err; /* Check write enabled for flash 1 */ if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) if ((status & (SPIFLASH_WE_BIT | SPIFLASH_BSY_BIT)) != SPIFLASH_WE_BIT) { LOG_ERROR("Cannot write enable flash1. Status=0x%02x", status & 0xFFU); return ERROR_FLASH_OPERATION_FAILED; } /* Check write enabled for flash 2 */ status >>= 8; if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) if ((status & (SPIFLASH_WE_BIT | SPIFLASH_BSY_BIT)) != SPIFLASH_WE_BIT) { LOG_ERROR("Cannot write enable flash2. Status=0x%02x", status & 0xFFU); return ERROR_FLASH_OPERATION_FAILED; } err: return retval; } COMMAND_HANDLER(stmqspi_handle_mass_erase_command) { struct target *target = NULL; struct flash_bank *bank; struct stmqspi_flash_bank *stmqspi_info; struct duration bench; uint32_t io_base; uint16_t status; unsigned int sector; int retval; LOG_DEBUG("%s", __func__); if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; stmqspi_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!(stmqspi_info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } if (stmqspi_info->dev.chip_erase_cmd == 0x00) { LOG_ERROR("Mass erase not available for this device"); return ERROR_FLASH_OPER_UNSUPPORTED; } for (sector = 0; sector < bank->num_sectors; sector++) { if (bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FLASH_PROTECTED; } } io_base = stmqspi_info->io_base; duration_start(&bench); retval = qspi_write_enable(bank); if (retval != ERROR_OK) goto err; /* Send Mass Erase command */ if (IS_OCTOSPI) retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, OCTOSPI_CCR_MASS_ERASE, stmqspi_info->dev.chip_erase_cmd); else retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_MASS_ERASE); if (retval != ERROR_OK) goto err; /* Wait for transmit of command completed */ poll_busy(bank, SPI_CMD_TIMEOUT); if (retval != ERROR_OK) goto err; /* Read flash status register(s) */ retval = read_status_reg(bank, &status); if (retval != ERROR_OK) goto err; /* Check for command in progress for flash 1 */ if (((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) && ((status & SPIFLASH_BSY_BIT) == 0) && ((status & SPIFLASH_WE_BIT) != 0)) { LOG_ERROR("Mass erase command not accepted by flash1. Status=0x%02x", status & 0xFFU); retval = ERROR_FLASH_OPERATION_FAILED; goto err; } /* Check for command in progress for flash 2 */ status >>= 8; if (((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) && ((status & SPIFLASH_BSY_BIT) == 0) && ((status & SPIFLASH_WE_BIT) != 0)) { LOG_ERROR("Mass erase command not accepted by flash2. Status=0x%02x", status & 0xFFU); retval = ERROR_FLASH_OPERATION_FAILED; goto err; } /* Poll WIP for end of self timed Sector Erase cycle */ retval = wait_till_ready(bank, SPI_MASS_ERASE_TIMEOUT); duration_measure(&bench); if (retval == ERROR_OK) command_print(CMD, "stmqspi mass erase completed in %fs (%0.3f KiB/s)", duration_elapsed(&bench), duration_kbps(&bench, bank->size)); else command_print(CMD, "stmqspi mass erase not completed even after %fs", duration_elapsed(&bench)); err: /* Switch to memory mapped mode before return to prompt */ set_mm_mode(bank); return retval; } static int log2u(uint32_t word) { int result; for (result = 0; (unsigned int) result < sizeof(uint32_t) * CHAR_BIT; result++) if (word == BIT(result)) return result; return -1; } COMMAND_HANDLER(stmqspi_handle_set) { struct flash_bank *bank = NULL; struct target *target = NULL; struct stmqspi_flash_bank *stmqspi_info = NULL; struct flash_sector *sectors = NULL; uint32_t io_base; unsigned int index = 0, dual, fsize; int retval; LOG_DEBUG("%s", __func__); /* chip_erase_cmd, sectorsize and erase_cmd are optional */ if ((CMD_ARGC < 7) || (CMD_ARGC > 10)) return ERROR_COMMAND_SYNTAX_ERROR; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, index++, &bank); if (retval != ERROR_OK) return retval; target = bank->target; stmqspi_info = bank->driver_priv; dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; /* invalidate all flash device info */ if (stmqspi_info->probed) free(bank->sectors); bank->size = 0; bank->num_sectors = 0; bank->sectors = NULL; stmqspi_info->sfdp_dummy1 = 0; stmqspi_info->sfdp_dummy2 = 0; stmqspi_info->probed = false; memset(&stmqspi_info->dev, 0, sizeof(stmqspi_info->dev)); stmqspi_info->dev.name = "unknown"; strncpy(stmqspi_info->devname, CMD_ARGV[index++], sizeof(stmqspi_info->devname) - 1); stmqspi_info->devname[sizeof(stmqspi_info->devname) - 1] = '\0'; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], stmqspi_info->dev.size_in_bytes); if (log2u(stmqspi_info->dev.size_in_bytes) < 8) { command_print(CMD, "stmqspi: device size must be 2^n with n >= 8"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], stmqspi_info->dev.pagesize); if (stmqspi_info->dev.pagesize > stmqspi_info->dev.size_in_bytes || (log2u(stmqspi_info->dev.pagesize) < 0)) { command_print(CMD, "stmqspi: page size must be 2^n and <= device size"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.read_cmd); if ((stmqspi_info->dev.read_cmd != 0x03) && (stmqspi_info->dev.read_cmd != 0x13)) { command_print(CMD, "stmqspi: only 0x03/0x13 READ cmd allowed"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.qread_cmd); if ((stmqspi_info->dev.qread_cmd != 0x00) && (stmqspi_info->dev.qread_cmd != 0x0B) && (stmqspi_info->dev.qread_cmd != 0x0C) && (stmqspi_info->dev.qread_cmd != 0x3B) && (stmqspi_info->dev.qread_cmd != 0x3C) && (stmqspi_info->dev.qread_cmd != 0x6B) && (stmqspi_info->dev.qread_cmd != 0x6C) && (stmqspi_info->dev.qread_cmd != 0xBB) && (stmqspi_info->dev.qread_cmd != 0xBC) && (stmqspi_info->dev.qread_cmd != 0xEB) && (stmqspi_info->dev.qread_cmd != 0xEC) && (stmqspi_info->dev.qread_cmd != 0xEE)) { command_print(CMD, "stmqspi: only 0x0B/0x0C/0x3B/0x3C/" "0x6B/0x6C/0xBB/0xBC/0xEB/0xEC/0xEE QREAD allowed"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.pprog_cmd); if ((stmqspi_info->dev.pprog_cmd != 0x02) && (stmqspi_info->dev.pprog_cmd != 0x12) && (stmqspi_info->dev.pprog_cmd != 0x32)) { command_print(CMD, "stmqspi: only 0x02/0x12/0x32 PPRG cmd allowed"); return ERROR_COMMAND_SYNTAX_ERROR; } if (index < CMD_ARGC) COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.chip_erase_cmd); else stmqspi_info->dev.chip_erase_cmd = 0x00; if (index < CMD_ARGC) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], stmqspi_info->dev.sectorsize); if ((stmqspi_info->dev.sectorsize > stmqspi_info->dev.size_in_bytes) || (stmqspi_info->dev.sectorsize < stmqspi_info->dev.pagesize) || (log2u(stmqspi_info->dev.sectorsize) < 0)) { command_print(CMD, "stmqspi: sector size must be 2^n and <= device size"); return ERROR_COMMAND_SYNTAX_ERROR; } if (index < CMD_ARGC) COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.erase_cmd); else return ERROR_COMMAND_SYNTAX_ERROR; } else { /* no sector size / sector erase cmd given, treat whole bank as a single sector */ stmqspi_info->dev.erase_cmd = 0x00; stmqspi_info->dev.sectorsize = stmqspi_info->dev.size_in_bytes; } /* set correct size value */ bank->size = stmqspi_info->dev.size_in_bytes << dual; io_base = stmqspi_info->io_base; uint32_t dcr; retval = target_read_u32(target, io_base + SPI_DCR, &dcr); if (retval != ERROR_OK) return retval; fsize = (dcr >> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1); LOG_DEBUG("FSIZE = 0x%04x", fsize); if (bank->size == BIT(fsize + 1)) LOG_DEBUG("FSIZE in DCR(1) matches actual capacity. Beware of silicon bug in H7, L4+, MP1."); else if (bank->size == BIT(fsize + 0)) LOG_DEBUG("FSIZE in DCR(1) is off by one regarding actual capacity. Fix for silicon bug?"); else LOG_ERROR("FSIZE in DCR(1) doesn't match actual capacity."); /* create and fill sectors array */ bank->num_sectors = stmqspi_info->dev.size_in_bytes / stmqspi_info->dev.sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); if (!sectors) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { sectors[sector].offset = sector * (stmqspi_info->dev.sectorsize << dual); sectors[sector].size = (stmqspi_info->dev.sectorsize << dual); sectors[sector].is_erased = -1; sectors[sector].is_protected = 0; } bank->sectors = sectors; stmqspi_info->dev.name = stmqspi_info->devname; if (stmqspi_info->dev.size_in_bytes / 4096) LOG_INFO("flash \'%s\' id = unknown\nchip size = %" PRIu32 " KiB," " bank size = %" PRIu32 " KiB", stmqspi_info->dev.name, stmqspi_info->dev.size_in_bytes / 1024, (stmqspi_info->dev.size_in_bytes / 1024) << dual); else LOG_INFO("flash \'%s\' id = unknown\nchip size = %" PRIu32 " B," " bank size = %" PRIu32 " B", stmqspi_info->dev.name, stmqspi_info->dev.size_in_bytes, stmqspi_info->dev.size_in_bytes << dual); stmqspi_info->probed = true; return ERROR_OK; } COMMAND_HANDLER(stmqspi_handle_cmd) { struct target *target = NULL; struct flash_bank *bank; struct stmqspi_flash_bank *stmqspi_info = NULL; uint32_t io_base, addr; uint8_t num_write, num_read, cmd_byte, data; unsigned int count; const int max = 21; char temp[4], output[(2 + max + 256) * 3 + 8]; int retval; LOG_DEBUG("%s", __func__); if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; num_write = CMD_ARGC - 2; if (num_write > max) { LOG_ERROR("at most %d bytes may be sent", max); return ERROR_COMMAND_SYNTAX_ERROR; } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; target = bank->target; stmqspi_info = bank->driver_priv; io_base = stmqspi_info->io_base; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], num_read); COMMAND_PARSE_NUMBER(u8, CMD_ARGV[2], cmd_byte); if (num_read == 0) { /* nothing to read, then one command byte and for dual flash * an *even* number of data bytes to follow */ if (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) { if ((num_write & 1) == 0) { LOG_ERROR("number of data bytes to write must be even in dual mode"); return ERROR_COMMAND_SYNTAX_ERROR; } } } else { /* read mode, one command byte and up to four following address bytes */ if (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) { if ((num_read & 1) != 0) { LOG_ERROR("number of bytes to read must be even in dual mode"); return ERROR_COMMAND_SYNTAX_ERROR; } } if ((num_write < 1) || (num_write > 5)) { LOG_ERROR("one cmd and up to four addr bytes must be send when reading"); return ERROR_COMMAND_SYNTAX_ERROR; } } /* Abort any previous operation */ retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; /* Wait for busy to be cleared */ retval = poll_busy(bank, SPI_PROBE_TIMEOUT); if (retval != ERROR_OK) return retval; /* send command byte */ snprintf(output, sizeof(output), "spi: %02x ", cmd_byte); if (num_read == 0) { /* write, send cmd byte */ retval = target_write_u32(target, io_base + SPI_DLR, ((uint32_t)num_write) - 2); if (retval != ERROR_OK) goto err; if (IS_OCTOSPI) retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, (OCTOSPI_MODE_CCR & OCTOSPI_NO_ALTB & OCTOSPI_NO_ADDR & ((num_write == 1) ? OCTOSPI_NO_DATA : ~0U)), cmd_byte); else retval = target_write_u32(target, io_base + QSPI_CCR, (QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ALTB & QSPI_NO_ADDR & ((num_write == 1) ? QSPI_NO_DATA : ~0U)) | (QSPI_WRITE_MODE | cmd_byte)); if (retval != ERROR_OK) goto err; /* send additional data bytes */ for (count = 3; count < CMD_ARGC; count++) { COMMAND_PARSE_NUMBER(u8, CMD_ARGV[count], data); snprintf(temp, sizeof(temp), "%02" PRIx8 " ", data); retval = target_write_u8(target, io_base + SPI_DR, data); if (retval != ERROR_OK) goto err; strncat(output, temp, sizeof(output) - strlen(output) - 1); } strncat(output, "-> ", sizeof(output) - strlen(output) - 1); } else { /* read, pack additional bytes into address */ addr = 0; for (count = 3; count < CMD_ARGC; count++) { COMMAND_PARSE_NUMBER(u8, CMD_ARGV[count], data); snprintf(temp, sizeof(temp), "%02" PRIx8 " ", data); addr = (addr << 8) | data; strncat(output, temp, sizeof(output) - strlen(output) - 1); } strncat(output, "-> ", sizeof(output) - strlen(output) - 1); /* send cmd byte, if ADMODE indicates no address, this already triggers command */ retval = target_write_u32(target, io_base + SPI_DLR, ((uint32_t)num_read) - 1); if (retval != ERROR_OK) goto err; if (IS_OCTOSPI) retval = octospi_cmd(bank, OCTOSPI_READ_MODE, (OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & OCTOSPI_NO_ALTB & ~OCTOSPI_ADDR4 & ((num_write == 1) ? OCTOSPI_NO_ADDR : ~0U)) | (((num_write - 2) & 0x3U) << SPI_ADSIZE_POS), cmd_byte); else retval = target_write_u32(target, io_base + QSPI_CCR, (QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ALTB & ~QSPI_ADDR4 & ((num_write == 1) ? QSPI_NO_ADDR : ~0U)) | ((QSPI_READ_MODE | (((num_write - 2) & 0x3U) << SPI_ADSIZE_POS) | cmd_byte))); if (retval != ERROR_OK) goto err; if (num_write > 1) { /* if ADMODE indicates address required, only the write to AR triggers command */ retval = target_write_u32(target, io_base + SPI_AR, addr); if (retval != ERROR_OK) goto err; } /* read response bytes */ for ( ; num_read > 0; num_read--) { retval = target_read_u8(target, io_base + SPI_DR, &data); if (retval != ERROR_OK) goto err; snprintf(temp, sizeof(temp), "%02" PRIx8 " ", data); strncat(output, temp, sizeof(output) - strlen(output) - 1); } } command_print(CMD, "%s", output); err: /* Switch to memory mapped mode before return to prompt */ set_mm_mode(bank); return retval; } static int qspi_erase_sector(struct flash_bank *bank, unsigned int sector) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; uint32_t io_base = stmqspi_info->io_base; uint16_t status; int retval; retval = qspi_write_enable(bank); if (retval != ERROR_OK) goto err; /* Send Sector Erase command */ if (IS_OCTOSPI) retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, OCTOSPI_CCR_SECTOR_ERASE, stmqspi_info->dev.erase_cmd); else retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_SECTOR_ERASE); if (retval != ERROR_OK) goto err; /* Address is sector offset, this write initiates command transmission */ retval = target_write_u32(target, io_base + SPI_AR, bank->sectors[sector].offset); if (retval != ERROR_OK) goto err; /* Wait for transmit of command completed */ poll_busy(bank, SPI_CMD_TIMEOUT); if (retval != ERROR_OK) goto err; /* Read flash status register(s) */ retval = read_status_reg(bank, &status); if (retval != ERROR_OK) goto err; LOG_DEBUG("erase status regs: 0x%04" PRIx16, status); /* Check for command in progress for flash 1 */ /* If BSY and WE are already cleared the erase did probably complete already */ if (((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) && ((status & SPIFLASH_BSY_BIT) == 0) && ((status & SPIFLASH_WE_BIT) != 0)) { LOG_ERROR("Sector erase command not accepted by flash1. Status=0x%02x", status & 0xFFU); retval = ERROR_FLASH_OPERATION_FAILED; goto err; } /* Check for command in progress for flash 2 */ /* If BSY and WE are already cleared the erase did probably complete already */ status >>= 8; if (((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) && ((status & SPIFLASH_BSY_BIT) == 0) && ((status & SPIFLASH_WE_BIT) != 0)) { LOG_ERROR("Sector erase command not accepted by flash2. Status=0x%02x", status & 0xFFU); retval = ERROR_FLASH_OPERATION_FAILED; goto err; } /* Erase takes a long time, so some sort of progress message is a good idea */ LOG_DEBUG("erasing sector %4u", sector); /* Poll WIP for end of self timed Sector Erase cycle */ retval = wait_till_ready(bank, SPI_MAX_TIMEOUT); err: return retval; } static int stmqspi_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; unsigned int sector; int retval = ERROR_OK; LOG_DEBUG("%s: from sector %u to sector %u", __func__, first, last); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!(stmqspi_info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } if (stmqspi_info->dev.erase_cmd == 0x00) { LOG_ERROR("Sector erase not available for this device"); return ERROR_FLASH_OPER_UNSUPPORTED; } if ((last < first) || (last >= bank->num_sectors)) { LOG_ERROR("Flash sector invalid"); return ERROR_FLASH_SECTOR_INVALID; } for (sector = first; sector <= last; sector++) { if (bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FLASH_PROTECTED; } } for (sector = first; sector <= last; sector++) { retval = qspi_erase_sector(bank, sector); if (retval != ERROR_OK) break; alive_sleep(10); keep_alive(); } if (retval != ERROR_OK) LOG_ERROR("Flash sector_erase failed on sector %u", sector); /* Switch to memory mapped mode before return to prompt */ set_mm_mode(bank); return retval; } static int stmqspi_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { unsigned int sector; for (sector = first; sector <= last; sector++) bank->sectors[sector].is_protected = set; if (set) LOG_WARNING("setting soft protection only, not related to flash's hardware write protection"); return ERROR_OK; } /* Check whether flash is blank */ static int stmqspi_blank_check(struct flash_bank *bank) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; struct duration bench; struct reg_param reg_params[2]; struct armv7m_algorithm armv7m_info; struct working_area *algorithm; const uint8_t *code; struct sector_info erase_check_info; uint32_t codesize, maxsize, result, exit_point; unsigned int count, index, num_sectors, sector; int retval; const uint32_t erased = 0x00FF; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!(stmqspi_info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } /* Abort any previous operation */ retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; /* Wait for busy to be cleared */ retval = poll_busy(bank, SPI_PROBE_TIMEOUT); if (retval != ERROR_OK) return retval; /* see contrib/loaders/flash/stmqspi/stmqspi_erase_check.S for src */ static const uint8_t stmqspi_erase_check_code[] = { #include "../../../contrib/loaders/flash/stmqspi/stmqspi_erase_check.inc" }; /* see contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S for src */ static const uint8_t stmoctospi_erase_check_code[] = { #include "../../../contrib/loaders/flash/stmqspi/stmoctospi_erase_check.inc" }; if (IS_OCTOSPI) { code = stmoctospi_erase_check_code; codesize = sizeof(stmoctospi_erase_check_code); } else { code = stmqspi_erase_check_code; codesize = sizeof(stmqspi_erase_check_code); } /* This will overlay the last 4 words of stmqspi/stmoctospi_erase_check_code in target */ /* for read use the saved settings (memory mapped mode) but indirect read mode */ uint32_t ccr_buffer[][4] = { /* cr (not used for QSPI) * * ccr (for both QSPI and OCTOSPI) * * tcr (not used for QSPI) * * ir (not used for QSPI) */ { h_to_le_32(OCTOSPI_MODE | OCTOSPI_READ_MODE), h_to_le_32(IS_OCTOSPI ? OCTOSPI_CCR_READ : QSPI_CCR_READ), h_to_le_32(stmqspi_info->saved_tcr), h_to_le_32(stmqspi_info->saved_ir), }, }; maxsize = target_get_working_area_avail(target); if (maxsize < codesize + sizeof(erase_check_info)) { LOG_ERROR("Not enough working area, can't do QSPI blank check"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } num_sectors = (maxsize - codesize) / sizeof(erase_check_info); num_sectors = (bank->num_sectors < num_sectors) ? bank->num_sectors : num_sectors; if (target_alloc_working_area_try(target, codesize + num_sectors * sizeof(erase_check_info), &algorithm) != ERROR_OK) { LOG_ERROR("allocating working area failed"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; /* prepare blank check code, excluding ccr_buffer */ retval = target_write_buffer(target, algorithm->address, codesize - sizeof(ccr_buffer), code); if (retval != ERROR_OK) goto err; /* prepare QSPI/OCTOSPI_CCR register values */ retval = target_write_buffer(target, algorithm->address + codesize - sizeof(ccr_buffer), sizeof(ccr_buffer), (uint8_t *)ccr_buffer); if (retval != ERROR_OK) goto err; duration_start(&bench); /* after breakpoint instruction (halfword), one nop (halfword) and * port_buffer till end of code */ exit_point = algorithm->address + codesize - sizeof(uint32_t) - sizeof(ccr_buffer); init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* sector count */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* QSPI/OCTOSPI io_base */ sector = 0; while (sector < bank->num_sectors) { /* at most num_sectors sectors to handle in one run */ count = bank->num_sectors - sector; if (count > num_sectors) count = num_sectors; for (index = 0; index < count; index++) { erase_check_info.offset = h_to_le_32(bank->sectors[sector + index].offset); erase_check_info.size = h_to_le_32(bank->sectors[sector + index].size); erase_check_info.result = h_to_le_32(erased); retval = target_write_buffer(target, algorithm->address + codesize + index * sizeof(erase_check_info), sizeof(erase_check_info), (uint8_t *)&erase_check_info); if (retval != ERROR_OK) goto err; } buf_set_u32(reg_params[0].value, 0, 32, count); buf_set_u32(reg_params[1].value, 0, 32, stmqspi_info->io_base); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; LOG_DEBUG("checking sectors %u to %u", sector, sector + count - 1); /* check a block of sectors */ retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, algorithm->address, exit_point, count * ((bank->sectors[sector].size >> 6) + 1) + 1000, &armv7m_info); if (retval != ERROR_OK) break; for (index = 0; index < count; index++) { retval = target_read_buffer(target, algorithm->address + codesize + index * sizeof(erase_check_info), sizeof(erase_check_info), (uint8_t *)&erase_check_info); if (retval != ERROR_OK) goto err; if ((erase_check_info.offset != h_to_le_32(bank->sectors[sector + index].offset)) || (erase_check_info.size != 0)) { LOG_ERROR("corrupted blank check info"); goto err; } /* we need le_32_to_h, but that's the same as h_to_le_32 */ result = h_to_le_32(erase_check_info.result); bank->sectors[sector + index].is_erased = ((result & 0xFF) == 0xFF); LOG_DEBUG("Flash sector %u checked: 0x%04x", sector + index, result & 0xFFFFU); } keep_alive(); sector += count; } destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); duration_measure(&bench); LOG_INFO("stmqspi blank checked in %fs (%0.3f KiB/s)", duration_elapsed(&bench), duration_kbps(&bench, bank->size)); err: target_free_working_area(target, algorithm); /* Switch to memory mapped mode before return to prompt */ set_mm_mode(bank); return retval; } /* Verify checksum */ static int qspi_verify(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; struct working_area *algorithm; const uint8_t *code; uint32_t pagesize, codesize, crc32, result, exit_point; int retval; /* see contrib/loaders/flash/stmqspi/stmqspi_crc32.S for src */ static const uint8_t stmqspi_crc32_code[] = { #include "../../../contrib/loaders/flash/stmqspi/stmqspi_crc32.inc" }; /* see contrib/loaders/flash/stmqspi/stmoctospi_crc32.S for src */ static const uint8_t stmoctospi_crc32_code[] = { #include "../../../contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc" }; if (IS_OCTOSPI) { code = stmoctospi_crc32_code; codesize = sizeof(stmoctospi_crc32_code); } else { code = stmqspi_crc32_code; codesize = sizeof(stmqspi_crc32_code); } /* block size doesn't matter that much here */ pagesize = stmqspi_info->dev.sectorsize; if (pagesize == 0) pagesize = stmqspi_info->dev.pagesize; if (pagesize == 0) pagesize = SPIFLASH_DEF_PAGESIZE; /* adjust size according to dual flash mode */ pagesize = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? pagesize << 1 : pagesize; /* This will overlay the last 4 words of stmqspi/stmoctospi_crc32_code in target */ /* for read use the saved settings (memory mapped mode) but indirect read mode */ uint32_t ccr_buffer[][4] = { /* cr (not used for QSPI) * * ccr (for both QSPI and OCTOSPI) * * tcr (not used for QSPI) * * ir (not used for QSPI) */ { h_to_le_32(OCTOSPI_MODE | OCTOSPI_READ_MODE), h_to_le_32(IS_OCTOSPI ? OCTOSPI_CCR_READ : QSPI_CCR_READ), h_to_le_32(stmqspi_info->saved_tcr), h_to_le_32(stmqspi_info->saved_ir), }, }; if (target_alloc_working_area_try(target, codesize, &algorithm) != ERROR_OK) { LOG_ERROR("Not enough working area, can't do QSPI verify"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; /* prepare verify code, excluding ccr_buffer */ retval = target_write_buffer(target, algorithm->address, codesize - sizeof(ccr_buffer), code); if (retval != ERROR_OK) goto err; /* prepare QSPI/OCTOSPI_CCR register values */ retval = target_write_buffer(target, algorithm->address + codesize - sizeof(ccr_buffer), sizeof(ccr_buffer), (uint8_t *)ccr_buffer); if (retval != ERROR_OK) goto err; /* after breakpoint instruction (halfword), one nop (halfword) and * port_buffer till end of code */ exit_point = algorithm->address + codesize - sizeof(uint32_t) - sizeof(ccr_buffer); init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* count (in), crc32 (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* pagesize */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* offset into flash address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* QSPI/OCTOSPI io_base */ buf_set_u32(reg_params[0].value, 0, 32, count); buf_set_u32(reg_params[1].value, 0, 32, pagesize); buf_set_u32(reg_params[2].value, 0, 32, offset); buf_set_u32(reg_params[3].value, 0, 32, stmqspi_info->io_base); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, algorithm->address, exit_point, (count >> 5) + 1000, &armv7m_info); keep_alive(); image_calculate_checksum(buffer, count, &crc32); if (retval == ERROR_OK) { result = buf_get_u32(reg_params[0].value, 0, 32); LOG_DEBUG("addr " TARGET_ADDR_FMT ", len 0x%08" PRIx32 ", crc 0x%08" PRIx32 " 0x%08" PRIx32, offset + bank->base, count, ~crc32, result); if (~crc32 != result) retval = ERROR_FAIL; } destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); err: target_free_working_area(target, algorithm); /* Switch to memory mapped mode before return to prompt */ set_mm_mode(bank); return retval; } static int qspi_read_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count, bool write) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; uint32_t io_base = stmqspi_info->io_base; struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; struct working_area *algorithm; uint32_t pagesize, fifo_start, fifosize, remaining; uint32_t maxsize, codesize, exit_point; const uint8_t *code = NULL; unsigned int dual; int retval; LOG_DEBUG("%s: offset=0x%08" PRIx32 " len=0x%08" PRIx32, __func__, offset, count); dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; /* see contrib/loaders/flash/stmqspi/stmqspi_read.S for src */ static const uint8_t stmqspi_read_code[] = { #include "../../../contrib/loaders/flash/stmqspi/stmqspi_read.inc" }; /* see contrib/loaders/flash/stmqspi/stmoctospi_read.S for src */ static const uint8_t stmoctospi_read_code[] = { #include "../../../contrib/loaders/flash/stmqspi/stmoctospi_read.inc" }; /* see contrib/loaders/flash/stmqspi/stmqspi_write.S for src */ static const uint8_t stmqspi_write_code[] = { #include "../../../contrib/loaders/flash/stmqspi/stmqspi_write.inc" }; /* see contrib/loaders/flash/stmqspi/stmoctospi_write.S for src */ static const uint8_t stmoctospi_write_code[] = { #include "../../../contrib/loaders/flash/stmqspi/stmoctospi_write.inc" }; /* This will overlay the last 12 words of stmqspi/stmoctospi_read/write_code in target */ /* for read use the saved settings (memory mapped mode) but indirect read mode */ uint32_t ccr_buffer[][4] = { /* cr (not used for QSPI) * * ccr (for both QSPI and OCTOSPI) * * tcr (not used for QSPI) * * ir (not used for QSPI) */ { h_to_le_32(OCTOSPI_MODE | OCTOSPI_READ_MODE), h_to_le_32(IS_OCTOSPI ? OCTOSPI_CCR_READ_STATUS : QSPI_CCR_READ_STATUS), h_to_le_32((stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK) | (OPI_MODE ? (OPI_DUMMY << OCTOSPI_DCYC_POS) : 0)), h_to_le_32(OPI_CMD(SPIFLASH_READ_STATUS)), }, { h_to_le_32(OCTOSPI_MODE | OCTOSPI_WRITE_MODE), h_to_le_32(IS_OCTOSPI ? OCTOSPI_CCR_WRITE_ENABLE : QSPI_CCR_WRITE_ENABLE), h_to_le_32(stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK), h_to_le_32(OPI_CMD(SPIFLASH_WRITE_ENABLE)), }, { h_to_le_32(OCTOSPI_MODE | (write ? OCTOSPI_WRITE_MODE : OCTOSPI_READ_MODE)), h_to_le_32(write ? (IS_OCTOSPI ? OCTOSPI_CCR_PAGE_PROG : QSPI_CCR_PAGE_PROG) : (IS_OCTOSPI ? OCTOSPI_CCR_READ : QSPI_CCR_READ)), h_to_le_32(write ? (stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK) : stmqspi_info->saved_tcr), h_to_le_32(write ? OPI_CMD(stmqspi_info->dev.pprog_cmd) : stmqspi_info->saved_ir), }, }; /* force reasonable defaults */ fifosize = stmqspi_info->dev.sectorsize ? stmqspi_info->dev.sectorsize : stmqspi_info->dev.size_in_bytes; if (write) { if (IS_OCTOSPI) { code = stmoctospi_write_code; codesize = sizeof(stmoctospi_write_code); } else { code = stmqspi_write_code; codesize = sizeof(stmqspi_write_code); } } else { if (IS_OCTOSPI) { code = stmoctospi_read_code; codesize = sizeof(stmoctospi_read_code); } else { code = stmqspi_read_code; codesize = sizeof(stmqspi_read_code); } } /* for write, pagesize must be taken into account */ /* for read, the page size doesn't matter that much */ pagesize = stmqspi_info->dev.pagesize; if (pagesize == 0) pagesize = (fifosize <= SPIFLASH_DEF_PAGESIZE) ? fifosize : SPIFLASH_DEF_PAGESIZE; /* adjust sizes according to dual flash mode */ pagesize <<= dual; fifosize <<= dual; /* memory buffer, we assume sectorsize to be a power of 2 times pagesize */ maxsize = target_get_working_area_avail(target); if (maxsize < codesize + 2 * sizeof(uint32_t) + pagesize) { LOG_ERROR("not enough working area, can't do QSPI page reads/writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* fifo size at most sector size, and multiple of page size */ maxsize -= (codesize + 2 * sizeof(uint32_t)); fifosize = ((maxsize < fifosize) ? maxsize : fifosize) & ~(pagesize - 1); if (target_alloc_working_area_try(target, codesize + 2 * sizeof(uint32_t) + fifosize, &algorithm) != ERROR_OK) { LOG_ERROR("allocating working area failed"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; /* prepare flash write code, excluding ccr_buffer */ retval = target_write_buffer(target, algorithm->address, codesize - sizeof(ccr_buffer), code); if (retval != ERROR_OK) goto err; /* prepare QSPI/OCTOSPI_CCR register values */ retval = target_write_buffer(target, algorithm->address + codesize - sizeof(ccr_buffer), sizeof(ccr_buffer), (uint8_t *)ccr_buffer); if (retval != ERROR_OK) goto err; /* target buffer starts right after flash_write_code, i.e. * wp and rp are implicitly included in buffer!!! */ fifo_start = algorithm->address + codesize + 2 * sizeof(uint32_t); init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* count (in), status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* pagesize */ init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); /* offset into flash address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* QSPI/OCTOSPI io_base */ init_reg_param(®_params[4], "r8", 32, PARAM_OUT); /* fifo start */ init_reg_param(®_params[5], "r9", 32, PARAM_OUT); /* fifo end + 1 */ buf_set_u32(reg_params[0].value, 0, 32, count); buf_set_u32(reg_params[1].value, 0, 32, pagesize); buf_set_u32(reg_params[2].value, 0, 32, offset); buf_set_u32(reg_params[3].value, 0, 32, io_base); buf_set_u32(reg_params[4].value, 0, 32, fifo_start); buf_set_u32(reg_params[5].value, 0, 32, fifo_start + fifosize); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; /* after breakpoint instruction (halfword), one nop (halfword) and * ccr_buffer follow till end of code */ exit_point = algorithm->address + codesize - (sizeof(ccr_buffer) + sizeof(uint32_t)); if (write) { retval = target_run_flash_async_algorithm(target, buffer, count, 1, 0, NULL, ARRAY_SIZE(reg_params), reg_params, algorithm->address + codesize, fifosize + 2 * sizeof(uint32_t), algorithm->address, exit_point, &armv7m_info); } else { retval = target_run_read_async_algorithm(target, buffer, count, 1, 0, NULL, ARRAY_SIZE(reg_params), reg_params, algorithm->address + codesize, fifosize + 2 * sizeof(uint32_t), algorithm->address, exit_point, &armv7m_info); } remaining = buf_get_u32(reg_params[0].value, 0, 32); if ((retval == ERROR_OK) && remaining) retval = ERROR_FLASH_OPERATION_FAILED; if (retval != ERROR_OK) { offset = buf_get_u32(reg_params[2].value, 0, 32); LOG_ERROR("flash %s failed at address 0x%" PRIx32 ", remaining 0x%" PRIx32, write ? "write" : "read", offset, remaining); } destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); err: target_free_working_area(target, algorithm); /* Switch to memory mapped mode before return to prompt */ set_mm_mode(bank); return retval; } static int stmqspi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; int retval; LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, __func__, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!(stmqspi_info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } if (offset + count > bank->size) { LOG_WARNING("Read beyond end of flash. Extra data to be ignored."); count = bank->size - offset; } /* Abort any previous operation */ retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; /* Wait for busy to be cleared */ retval = poll_busy(bank, SPI_PROBE_TIMEOUT); if (retval != ERROR_OK) return retval; return qspi_read_write_block(bank, buffer, offset, count, false); } static int stmqspi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; unsigned int dual, sector; bool octal_dtr; int retval; LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, __func__, offset, count); dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; octal_dtr = IS_OCTOSPI && (stmqspi_info->saved_ccr & BIT(OCTOSPI_DDTR)); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!(stmqspi_info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } if (offset + count > bank->size) { LOG_WARNING("Write beyond end of flash. Extra data discarded."); count = bank->size - offset; } /* Check sector protection */ for (sector = 0; sector < bank->num_sectors; sector++) { /* Start offset in or before this sector? */ /* End offset in or behind this sector? */ if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) && ((offset + count - 1) >= bank->sectors[sector].offset) && bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FLASH_PROTECTED; } } if ((dual || octal_dtr) && ((offset & 1) != 0 || (count & 1) != 0)) { LOG_ERROR("In dual-QSPI and octal-DTR modes writes must be two byte aligned: " "%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, __func__, offset, count); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* Abort any previous operation */ retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; /* Wait for busy to be cleared */ retval = poll_busy(bank, SPI_PROBE_TIMEOUT); if (retval != ERROR_OK) return retval; return qspi_read_write_block(bank, (uint8_t *)buffer, offset, count, true); } static int stmqspi_verify(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; unsigned int dual; bool octal_dtr; int retval; LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, __func__, offset, count); dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; octal_dtr = IS_OCTOSPI && (stmqspi_info->saved_ccr & BIT(OCTOSPI_DDTR)); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!(stmqspi_info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } if (offset + count > bank->size) { LOG_WARNING("Verify beyond end of flash. Extra data ignored."); count = bank->size - offset; } if ((dual || octal_dtr) && ((offset & 1) != 0 || (count & 1) != 0)) { LOG_ERROR("In dual-QSPI and octal-DTR modes reads must be two byte aligned: " "%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, __func__, offset, count); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* Abort any previous operation */ retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; /* Wait for busy to be cleared */ retval = poll_busy(bank, SPI_PROBE_TIMEOUT); if (retval != ERROR_OK) return retval; return qspi_verify(bank, (uint8_t *)buffer, offset, count); } /* Find appropriate dummy setting, in particular octo mode */ static int find_sfdp_dummy(struct flash_bank *bank, int len) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; uint32_t io_base = stmqspi_info->io_base; uint8_t data; unsigned int dual, count; bool flash1 = !(stmqspi_info->saved_cr & BIT(SPI_FSEL_FLASH)); int retval; const unsigned int max_bytes = 64; dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; LOG_DEBUG("%s: len=%d, dual=%u, flash1=%d", __func__, len, dual, flash1); /* Abort any previous operation */ retval = target_write_u32(target, io_base + SPI_CR, stmqspi_info->saved_cr | BIT(SPI_ABORT)); if (retval != ERROR_OK) goto err; /* Wait for busy to be cleared */ retval = poll_busy(bank, SPI_PROBE_TIMEOUT); if (retval != ERROR_OK) goto err; /* Switch to saved_cr (had to be set accordingly before this call) */ retval = target_write_u32(target, io_base + SPI_CR, stmqspi_info->saved_cr); if (retval != ERROR_OK) goto err; /* Read at most that many bytes */ retval = target_write_u32(target, io_base + SPI_DLR, (max_bytes << dual) - 1); if (retval != ERROR_OK) return retval; /* Read SFDP block */ if (IS_OCTOSPI) retval = octospi_cmd(bank, OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_SFDP(len), SPIFLASH_READ_SFDP); else retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_SFDP); if (retval != ERROR_OK) goto err; /* Read from start of sfdp block */ retval = target_write_u32(target, io_base + SPI_AR, 0); if (retval != ERROR_OK) goto err; for (count = 0 ; count < max_bytes; count++) { if ((dual != 0) && !flash1) { /* discard even byte in dual flash-mode if flash2 */ retval = target_read_u8(target, io_base + SPI_DR, &data); if (retval != ERROR_OK) goto err; } retval = target_read_u8(target, io_base + SPI_DR, &data); if (retval != ERROR_OK) goto err; if (data == 0x53) { LOG_DEBUG("start of SFDP header for flash%c after %u dummy bytes", flash1 ? '1' : '2', count); if (flash1) stmqspi_info->sfdp_dummy1 = count; else stmqspi_info->sfdp_dummy2 = count; return ERROR_OK; } if ((dual != 0) && flash1) { /* discard odd byte in dual flash-mode if flash1 */ retval = target_read_u8(target, io_base + SPI_DR, &data); if (retval != ERROR_OK) goto err; } } LOG_DEBUG("no start of SFDP header even after %u dummy bytes", count); err: /* Abort operation */ retval = stmqspi_abort(bank); return retval; } /* Read SFDP parameter block */ static int read_sfdp_block(struct flash_bank *bank, uint32_t addr, uint32_t words, uint32_t *buffer) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; uint32_t io_base = stmqspi_info->io_base; bool flash1 = !(stmqspi_info->saved_cr & BIT(SPI_FSEL_FLASH)); unsigned int dual, count, len, *dummy; int retval; dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; if (IS_OCTOSPI && (((stmqspi_info->saved_ccr >> SPI_DMODE_POS) & 0x7) > 3)) { /* in OCTO mode 4-byte address and (yet) unknown number of dummy clocks */ len = 4; /* in octo mode, use sfdp_dummy1 only */ dummy = &stmqspi_info->sfdp_dummy1; if (*dummy == 0) { retval = find_sfdp_dummy(bank, len); if (retval != ERROR_OK) return retval; } } else { /* in all other modes 3-byte-address and 8(?) dummy clocks */ len = 3; /* use sfdp_dummy1/2 according to currently selected flash */ dummy = (stmqspi_info->saved_cr & BIT(SPI_FSEL_FLASH)) ? &stmqspi_info->sfdp_dummy2 : &stmqspi_info->sfdp_dummy1; /* according to SFDP standard, there should always be 8 dummy *CLOCKS* * giving 1, 2 or 4 dummy *BYTES*, however, this is apparently not * always implemented correctly, so determine the number of dummy bytes * dynamically */ if (*dummy == 0) { retval = find_sfdp_dummy(bank, len); if (retval != ERROR_OK) return retval; } } LOG_DEBUG("%s: addr=0x%08" PRIx32 " words=0x%08" PRIx32 " dummy=%u", __func__, addr, words, *dummy); /* Abort any previous operation */ retval = target_write_u32(target, io_base + SPI_CR, stmqspi_info->saved_cr | BIT(SPI_ABORT)); if (retval != ERROR_OK) goto err; /* Wait for busy to be cleared */ retval = poll_busy(bank, SPI_PROBE_TIMEOUT); if (retval != ERROR_OK) goto err; /* Switch to one flash only */ retval = target_write_u32(target, io_base + SPI_CR, stmqspi_info->saved_cr); if (retval != ERROR_OK) goto err; /* Read that many words plus dummy bytes */ retval = target_write_u32(target, io_base + SPI_DLR, ((*dummy + words * sizeof(uint32_t)) << dual) - 1); if (retval != ERROR_OK) goto err; /* Read SFDP block */ if (IS_OCTOSPI) retval = octospi_cmd(bank, OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_SFDP(len), SPIFLASH_READ_SFDP); else retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_SFDP); if (retval != ERROR_OK) goto err; retval = target_write_u32(target, io_base + SPI_AR, addr << dual); if (retval != ERROR_OK) goto err; /* dummy clocks */ for (count = *dummy << dual; count > 0; --count) { retval = target_read_u8(target, io_base + SPI_DR, (uint8_t *)buffer); if (retval != ERROR_OK) goto err; } for ( ; words > 0; words--) { if (dual != 0) { uint32_t word1, word2; retval = target_read_u32(target, io_base + SPI_DR, &word1); if (retval != ERROR_OK) goto err; retval = target_read_u32(target, io_base + SPI_DR, &word2); if (retval != ERROR_OK) goto err; if (!flash1) { /* shift odd numbered bytes into even numbered ones */ word1 >>= 8; word2 >>= 8; } /* pack even numbered bytes into one word */ *buffer = (word1 & 0xFFU) | ((word1 & 0xFF0000U) >> 8) | ((word2 & 0xFFU) << 16) | ((word2 & 0xFF0000U) << 8); } else { retval = target_read_u32(target, io_base + SPI_DR, buffer); if (retval != ERROR_OK) goto err; } LOG_DEBUG("raw SFDP data 0x%08" PRIx32, *buffer); /* endian correction, sfdp data is always le uint32_t based */ *buffer = le_to_h_u32((uint8_t *)buffer); buffer++; } err: return retval; } /* Return ID of flash device(s) */ /* On exit, indirect mode is kept */ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; uint32_t io_base = stmqspi_info->io_base; uint8_t byte; unsigned int type, count, len1, len2; int retval = ERROR_OK; /* invalidate both ids */ *id1 = 0; *id2 = 0; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* SPIFLASH_READ_MID causes device in octal mode to go berserk, so don't use in this case */ for (type = (IS_OCTOSPI && OPI_MODE) ? 1 : 0; type < 2 ; type++) { /* Abort any previous operation */ retval = stmqspi_abort(bank); if (retval != ERROR_OK) goto err; /* Poll WIP */ retval = wait_till_ready(bank, SPI_PROBE_TIMEOUT); if (retval != ERROR_OK) goto err; /* Wait for busy to be cleared */ retval = poll_busy(bank, SPI_PROBE_TIMEOUT); if (retval != ERROR_OK) goto err; /* Read at most 16 bytes per chip */ count = 16; retval = target_write_u32(target, io_base + SPI_DLR, (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH) ? count * 2 : count) - 1); if (retval != ERROR_OK) goto err; /* Read id: one particular flash chip (N25Q128) switches back to SPI mode when receiving * SPI_FLASH_READ_ID in QPI mode, hence try SPIFLASH_READ_MID first */ switch (type) { case 0: if (IS_OCTOSPI) retval = octospi_cmd(bank, OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_MID, SPIFLASH_READ_MID); else retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_MID); break; case 1: if (IS_OCTOSPI) retval = octospi_cmd(bank, OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_ID, SPIFLASH_READ_ID); else retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_ID); break; default: return ERROR_FAIL; } if (retval != ERROR_OK) goto err; /* Dummy address 0, only required for 8-line mode */ if (IS_OCTOSPI && OPI_MODE) { retval = target_write_u32(target, io_base + SPI_AR, 0); if (retval != ERROR_OK) goto err; } /* for debugging only */ uint32_t dummy; (void)target_read_u32(target, io_base + SPI_SR, &dummy); /* Read ID from Data Register */ for (len1 = 0, len2 = 0; count > 0; --count) { if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) { retval = target_read_u8(target, io_base + SPI_DR, &byte); if (retval != ERROR_OK) goto err; /* collect 3 bytes without continuation codes */ if ((byte != 0x7F) && (len1 < 3)) { *id1 = (*id1 >> 8) | ((uint32_t)byte) << 16; len1++; } } if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) { retval = target_read_u8(target, io_base + SPI_DR, &byte); if (retval != ERROR_OK) goto err; /* collect 3 bytes without continuation codes */ if ((byte != 0x7F) && (len2 < 3)) { *id2 = (*id2 >> 8) | ((uint32_t)byte) << 16; len2++; } } } if (((*id1 != 0x000000) && (*id1 != 0xFFFFFF)) || ((*id2 != 0x000000) && (*id2 != 0xFFFFFF))) break; } if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) { if ((*id1 == 0x000000) || (*id1 == 0xFFFFFF)) { /* no id retrieved, so id must be set manually */ LOG_INFO("No id from flash1"); retval = ERROR_FLASH_BANK_NOT_PROBED; } } if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) { if ((*id2 == 0x000000) || (*id2 == 0xFFFFFF)) { /* no id retrieved, so id must be set manually */ LOG_INFO("No id from flash2"); retval = ERROR_FLASH_BANK_NOT_PROBED; } } err: return retval; } static int stmqspi_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; struct flash_sector *sectors = NULL; uint32_t io_base = stmqspi_info->io_base; uint32_t id1 = 0, id2 = 0, data = 0; const struct flash_device *p; const uint32_t magic = 0xAEF1510E; unsigned int dual, fsize; bool octal_dtr; int retval; /* invalidate all flash device info */ if (stmqspi_info->probed) free(bank->sectors); bank->size = 0; bank->num_sectors = 0; bank->sectors = NULL; stmqspi_info->sfdp_dummy1 = 0; stmqspi_info->sfdp_dummy2 = 0; stmqspi_info->probed = false; memset(&stmqspi_info->dev, 0, sizeof(stmqspi_info->dev)); stmqspi_info->dev.name = "unknown"; /* Abort any previous operation */ retval = stmqspi_abort(bank); if (retval != ERROR_OK) return retval; /* Wait for busy to be cleared */ retval = poll_busy(bank, SPI_PROBE_TIMEOUT); if (retval != ERROR_OK) return retval; /* check whether QSPI_ABR is writeable and readback returns the value written */ retval = target_write_u32(target, io_base + QSPI_ABR, magic); if (retval == ERROR_OK) { (void)target_read_u32(target, io_base + QSPI_ABR, &data); (void)target_write_u32(target, io_base + QSPI_ABR, 0); } if (data == magic) { LOG_DEBUG("QSPI_ABR register present"); stmqspi_info->octo = false; } else { uint32_t magic_id; retval = target_read_u32(target, io_base + OCTOSPI_MAGIC, &magic_id); if (retval == ERROR_OK && magic_id == OCTO_MAGIC_ID) { LOG_DEBUG("OCTOSPI_MAGIC present"); stmqspi_info->octo = true; } else { LOG_ERROR("No QSPI, no OCTOSPI at 0x%08" PRIx32, io_base); stmqspi_info->probed = false; stmqspi_info->dev.name = "none"; return ERROR_FAIL; } } /* save current FSEL and DFM bits in QSPI/OCTOSPI_CR, current QSPI/OCTOSPI_CCR value */ retval = target_read_u32(target, io_base + SPI_CR, &stmqspi_info->saved_cr); if (retval == ERROR_OK) retval = target_read_u32(target, io_base + SPI_CCR, &stmqspi_info->saved_ccr); if (IS_OCTOSPI) { uint32_t dcr1; retval = target_read_u32(target, io_base + OCTOSPI_DCR1, &dcr1); if (retval == ERROR_OK) retval = target_read_u32(target, io_base + OCTOSPI_TCR, &stmqspi_info->saved_tcr); if (retval == ERROR_OK) retval = target_read_u32(target, io_base + OCTOSPI_IR, &stmqspi_info->saved_ir); if (retval != ERROR_OK) { LOG_ERROR("No OCTOSPI at io_base 0x%08" PRIx32, io_base); stmqspi_info->probed = false; stmqspi_info->dev.name = "none"; return ERROR_FAIL; } const uint32_t mtyp = (dcr1 & OCTOSPI_MTYP_MASK) >> OCTOSPI_MTYP_POS; if ((mtyp != 0x0) && (mtyp != 0x1)) { LOG_ERROR("Only regular SPI protocol supported in OCTOSPI"); stmqspi_info->probed = false; stmqspi_info->dev.name = "none"; return ERROR_FAIL; } LOG_DEBUG("OCTOSPI at 0x%08" PRIx64 ", io_base at 0x%08" PRIx32 ", OCTOSPI_CR 0x%08" PRIx32 ", OCTOSPI_CCR 0x%08" PRIx32 ", %d-byte addr", bank->base, io_base, stmqspi_info->saved_cr, stmqspi_info->saved_ccr, SPI_ADSIZE); } else { if (retval == ERROR_OK) { LOG_DEBUG("QSPI at 0x%08" PRIx64 ", io_base at 0x%08" PRIx32 ", QSPI_CR 0x%08" PRIx32 ", QSPI_CCR 0x%08" PRIx32 ", %d-byte addr", bank->base, io_base, stmqspi_info->saved_cr, stmqspi_info->saved_ccr, SPI_ADSIZE); if (stmqspi_info->saved_ccr & (1U << QSPI_DDRM)) LOG_WARNING("DDR mode is untested and suffers from some silicon bugs"); } else { LOG_ERROR("No QSPI at io_base 0x%08" PRIx32, io_base); stmqspi_info->probed = false; stmqspi_info->dev.name = "none"; return ERROR_FAIL; } } dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; octal_dtr = IS_OCTOSPI && (stmqspi_info->saved_ccr & BIT(OCTOSPI_DDTR)); if (dual || octal_dtr) bank->write_start_alignment = bank->write_end_alignment = 2; else bank->write_start_alignment = bank->write_end_alignment = 1; /* read and decode flash ID; returns in indirect mode */ retval = read_flash_id(bank, &id1, &id2); LOG_DEBUG("id1 0x%06" PRIx32 ", id2 0x%06" PRIx32, id1, id2); if (retval == ERROR_FLASH_BANK_NOT_PROBED) { /* no id retrieved, so id must be set manually */ LOG_INFO("No id - set flash parameters manually"); retval = ERROR_OK; goto err; } if (retval != ERROR_OK) goto err; /* identify flash1 */ for (p = flash_devices; id1 && p->name ; p++) { if (p->device_id == id1) { memcpy(&stmqspi_info->dev, p, sizeof(stmqspi_info->dev)); if (p->size_in_bytes / 4096) LOG_INFO("flash1 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 " KiB", p->name, id1, p->size_in_bytes / 1024); else LOG_INFO("flash1 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 " B", p->name, id1, p->size_in_bytes); break; } } if (id1 && !p->name) { /* chip not been identified by id, then try SFDP */ struct flash_device temp; uint32_t saved_cr = stmqspi_info->saved_cr; /* select flash1 */ stmqspi_info->saved_cr = stmqspi_info->saved_cr & ~BIT(SPI_FSEL_FLASH); retval = spi_sfdp(bank, &temp, &read_sfdp_block); /* restore saved_cr */ stmqspi_info->saved_cr = saved_cr; if (retval == ERROR_OK) { LOG_INFO("flash1 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 " KiB", temp.name, id1, temp.size_in_bytes / 1024); /* save info and retrieved *good* id as spi_sfdp clears all info */ memcpy(&stmqspi_info->dev, &temp, sizeof(stmqspi_info->dev)); stmqspi_info->dev.device_id = id1; } else { /* even not identified by SFDP, then give up */ LOG_WARNING("Unknown flash1 device id = 0x%06" PRIx32 " - set flash parameters manually", id1); retval = ERROR_OK; goto err; } } /* identify flash2 */ for (p = flash_devices; id2 && p->name ; p++) { if (p->device_id == id2) { if (p->size_in_bytes / 4096) LOG_INFO("flash2 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 " KiB", p->name, id2, p->size_in_bytes / 1024); else LOG_INFO("flash2 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 " B", p->name, id2, p->size_in_bytes); if (!id1) memcpy(&stmqspi_info->dev, p, sizeof(stmqspi_info->dev)); else { if ((stmqspi_info->dev.read_cmd != p->read_cmd) || (stmqspi_info->dev.qread_cmd != p->qread_cmd) || (stmqspi_info->dev.pprog_cmd != p->pprog_cmd) || (stmqspi_info->dev.erase_cmd != p->erase_cmd) || (stmqspi_info->dev.chip_erase_cmd != p->chip_erase_cmd) || (stmqspi_info->dev.sectorsize != p->sectorsize) || (stmqspi_info->dev.size_in_bytes != p->size_in_bytes)) { LOG_ERROR("Incompatible flash1/flash2 devices"); goto err; } /* page size is optional in SFDP, so accept smallest value */ if (p->pagesize < stmqspi_info->dev.pagesize) stmqspi_info->dev.pagesize = p->pagesize; } break; } } if (id2 && !p->name) { /* chip not been identified by id, then try SFDP */ struct flash_device temp; uint32_t saved_cr = stmqspi_info->saved_cr; /* select flash2 */ stmqspi_info->saved_cr = stmqspi_info->saved_cr | BIT(SPI_FSEL_FLASH); retval = spi_sfdp(bank, &temp, &read_sfdp_block); /* restore saved_cr */ stmqspi_info->saved_cr = saved_cr; if (retval == ERROR_OK) LOG_INFO("flash2 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 " KiB", temp.name, id2, temp.size_in_bytes / 1024); else { /* even not identified by SFDP, then give up */ LOG_WARNING("Unknown flash2 device id = 0x%06" PRIx32 " - set flash parameters manually", id2); retval = ERROR_OK; goto err; } if (!id1) memcpy(&stmqspi_info->dev, &temp, sizeof(stmqspi_info->dev)); else { if ((stmqspi_info->dev.read_cmd != temp.read_cmd) || (stmqspi_info->dev.qread_cmd != temp.qread_cmd) || (stmqspi_info->dev.pprog_cmd != temp.pprog_cmd) || (stmqspi_info->dev.erase_cmd != temp.erase_cmd) || (stmqspi_info->dev.chip_erase_cmd != temp.chip_erase_cmd) || (stmqspi_info->dev.sectorsize != temp.sectorsize) || (stmqspi_info->dev.size_in_bytes != temp.size_in_bytes)) { LOG_ERROR("Incompatible flash1/flash2 devices"); goto err; } /* page size is optional in SFDP, so accept smallest value */ if (temp.pagesize < stmqspi_info->dev.pagesize) stmqspi_info->dev.pagesize = temp.pagesize; } } /* Set correct size value */ bank->size = stmqspi_info->dev.size_in_bytes << dual; uint32_t dcr; retval = target_read_u32(target, io_base + SPI_DCR, &dcr); if (retval != ERROR_OK) goto err; fsize = (dcr >> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1); LOG_DEBUG("FSIZE = 0x%04x", fsize); if (bank->size == BIT((fsize + 1))) LOG_DEBUG("FSIZE in DCR(1) matches actual capacity. Beware of silicon bug in H7, L4+, MP1."); else if (bank->size == BIT((fsize + 0))) LOG_DEBUG("FSIZE in DCR(1) is off by one regarding actual capacity. Fix for silicon bug?"); else LOG_ERROR("FSIZE in DCR(1) doesn't match actual capacity."); /* if no sectors, then treat whole flash as single sector */ if (stmqspi_info->dev.sectorsize == 0) stmqspi_info->dev.sectorsize = stmqspi_info->dev.size_in_bytes; /* if no page_size, then use sectorsize as page_size */ if (stmqspi_info->dev.pagesize == 0) stmqspi_info->dev.pagesize = stmqspi_info->dev.sectorsize; /* create and fill sectors array */ bank->num_sectors = stmqspi_info->dev.size_in_bytes / stmqspi_info->dev.sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); if (!sectors) { LOG_ERROR("not enough memory"); retval = ERROR_FAIL; goto err; } for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { sectors[sector].offset = sector * (stmqspi_info->dev.sectorsize << dual); sectors[sector].size = (stmqspi_info->dev.sectorsize << dual); sectors[sector].is_erased = -1; sectors[sector].is_protected = 0; } bank->sectors = sectors; stmqspi_info->probed = true; err: /* Switch to memory mapped mode before return to prompt */ set_mm_mode(bank); return retval; } static int stmqspi_auto_probe(struct flash_bank *bank) { struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; if (stmqspi_info->probed) return ERROR_OK; stmqspi_probe(bank); return ERROR_OK; } static int stmqspi_protect_check(struct flash_bank *bank) { /* Nothing to do. Protection is only handled in SW. */ return ERROR_OK; } static int get_stmqspi_info(struct flash_bank *bank, struct command_invocation *cmd) { struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; if (!(stmqspi_info->probed)) { command_print_sameline(cmd, "\nQSPI flash bank not probed yet\n"); return ERROR_FLASH_BANK_NOT_PROBED; } command_print_sameline(cmd, "flash%s%s \'%s\', device id = 0x%06" PRIx32 ", flash size = %" PRIu32 "%s B\n(page size = %" PRIu32 ", read = 0x%02" PRIx8 ", qread = 0x%02" PRIx8 ", pprog = 0x%02" PRIx8 ", mass_erase = 0x%02" PRIx8 ", sector size = %" PRIu32 " %sB, sector_erase = 0x%02" PRIx8 ")", ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) ? "1" : "", ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) ? "2" : "", stmqspi_info->dev.name, stmqspi_info->dev.device_id, bank->size / 4096 ? bank->size / 1024 : bank->size, bank->size / 4096 ? "Ki" : "", stmqspi_info->dev.pagesize, stmqspi_info->dev.read_cmd, stmqspi_info->dev.qread_cmd, stmqspi_info->dev.pprog_cmd, stmqspi_info->dev.chip_erase_cmd, stmqspi_info->dev.sectorsize / 4096 ? stmqspi_info->dev.sectorsize / 1024 : stmqspi_info->dev.sectorsize, stmqspi_info->dev.sectorsize / 4096 ? "Ki" : "", stmqspi_info->dev.erase_cmd); return ERROR_OK; } static const struct command_registration stmqspi_exec_command_handlers[] = { { .name = "mass_erase", .handler = stmqspi_handle_mass_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Mass erase entire flash device.", }, { .name = "set", .handler = stmqspi_handle_set, .mode = COMMAND_EXEC, .usage = "bank_id name chip_size page_size read_cmd qread_cmd pprg_cmd " "[ mass_erase_cmd ] [ sector_size sector_erase_cmd ]", .help = "Set params of single flash chip", }, { .name = "cmd", .handler = stmqspi_handle_cmd, .mode = COMMAND_EXEC, .usage = "bank_id num_resp cmd_byte ...", .help = "Send low-level command cmd_byte and following bytes or read num_resp.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration stmqspi_command_handlers[] = { { .name = "stmqspi", .mode = COMMAND_ANY, .help = "stmqspi flash command group", .usage = "", .chain = stmqspi_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver stmqspi_flash = { .name = "stmqspi", .commands = stmqspi_command_handlers, .flash_bank_command = stmqspi_flash_bank_command, .erase = stmqspi_erase, .protect = stmqspi_protect, .write = stmqspi_write, .read = stmqspi_read, .verify = stmqspi_verify, .probe = stmqspi_probe, .auto_probe = stmqspi_auto_probe, .erase_check = stmqspi_blank_check, .protect_check = stmqspi_protect_check, .info = get_stmqspi_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/stmqspi.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2016 - 2018 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_STMQSPI_H #define OPENOCD_FLASH_NOR_STMQSPI_H #include "spi.h" /* QSPI register offsets */ #define QSPI_CR (0x00) /* Control register */ #define QSPI_DCR (0x04) /* Device configuration register */ #define QSPI_SR (0x08) /* Status register */ #define QSPI_FCR (0x0C) /* Flag clear register */ #define QSPI_DLR (0x10) /* Data length register */ #define QSPI_CCR (0x14) /* Communication configuration register */ #define QSPI_AR (0x18) /* Address register */ #define QSPI_ABR (0x1C) /* Alternate bytes register */ #define QSPI_DR (0x20) /* Data register */ /* common bits in QSPI_CR and OCTOSPI_CR */ #define SPI_FSEL_FLASH 7 /* Select flash 2 */ #define SPI_DUAL_FLASH 6 /* Dual flash mode */ #define SPI_ABORT 1 /* Abort bit */ /* common bits in QSPI_DCR and OCTOSPI_DCR1 */ #define SPI_FSIZE_POS 16 /* bit position of FSIZE */ #define SPI_FSIZE_LEN 5 /* width of FSIZE field */ /* common bits in QSPI_SR/FCR and OCTOSPI_SR/FCR */ #define SPI_BUSY 5 /* Busy flag */ #define SPI_FTF 2 /* FIFO threshold flag */ #define SPI_TCF 1 /* Transfer complete flag */ /* fields in QSPI_CCR */ #define QSPI_DDRM 31 /* position of DDRM bit */ #define SPI_DMODE_POS 24 /* bit position of DMODE */ #define QSPI_DCYC_POS 18 /* bit position of DCYC */ #define QSPI_DCYC_LEN 5 /* width of DCYC field */ #define QSPI_DCYC_MASK ((BIT(QSPI_DCYC_LEN) - 1) << QSPI_DCYC_POS) #define SPI_ADSIZE_POS 12 /* bit position of ADSIZE */ #define QSPI_WRITE_MODE 0x00000000U /* indirect write mode */ #define QSPI_READ_MODE 0x04000000U /* indirect read mode */ #define QSPI_MM_MODE 0x0C000000U /* memory mapped mode */ #define QSPI_ALTB_MODE 0x0003C000U /* alternate byte mode */ #define QSPI_4LINE_MODE 0x03000F00U /* 4 lines for data, addr, instr */ #define QSPI_NO_DATA (~0x03000000U) /* no data */ #define QSPI_NO_ALTB (~QSPI_ALTB_MODE) /* no alternate */ #define QSPI_NO_ADDR (~0x00000C00U) /* no address */ #define QSPI_ADDR3 (0x2U << SPI_ADSIZE_POS) /* 3 byte address */ #define QSPI_ADDR4 (0x3U << SPI_ADSIZE_POS) /* 4 byte address */ /* OCTOSPI register offsets */ #define OCTOSPI_CR (0x000) /* Control register */ #define OCTOSPI_DCR1 (0x008) /* Device configuration register 1 */ #define OCTOSPI_DCR2 (0x00C) /* Device configuration register 2 */ #define OCTOSPI_DCR3 (0x010) /* Device configuration register 3 */ #define OCTOSPI_SR (0x020) /* Status register */ #define OCTOSPI_FCR (0x024) /* Flag clear register */ #define OCTOSPI_DLR (0x040) /* Data length register */ #define OCTOSPI_AR (0x048) /* Address register */ #define OCTOSPI_DR (0x050) /* Data register */ #define OCTOSPI_CCR (0x100) /* Communication configuration register */ #define OCTOSPI_TCR (0x108) /* Timing configuration register */ #define OCTOSPI_IR (0x110) /* Instruction register */ #define OCTOSPI_WCCR (0x180) /* Write communication configuration register */ #define OCTOSPI_WIR (0x190) /* Write instruction register */ #define OCTOSPI_MAGIC (0x3FC) /* Magic ID register, deleted from RM, why? */ #define OCTO_MAGIC_ID 0xA3C5DD01 /* Magic ID, deleted from RM, why? */ /* additional bits in OCTOSPI_CR */ #define OCTOSPI_WRITE_MODE 0x00000000U /* indirect write mode */ #define OCTOSPI_READ_MODE 0x10000000U /* indirect read mode */ #define OCTOSPI_MM_MODE 0x30000000U /* memory mapped mode */ /* additional fields in OCTOSPI_DCR1 */ #define OCTOSPI_MTYP_POS (24) /* bit position of MTYP */ #define OCTOSPI_MTYP_LEN (3) /* width of MTYP field */ #define OCTOSPI_MTYP_MASK ((BIT(OCTOSPI_MTYP_LEN) - 1) << OCTOSPI_MTYP_POS) /* fields in OCTOSPI_CCR */ #define OCTOSPI_ALTB_MODE 0x001F0000U /* alternate byte mode */ #define OCTOSPI_8LINE_MODE 0x0F003F3FU /* 8 lines DTR for data, addr, instr */ #define OCTOSPI_NO_DATA (~0x0F000000U) /* no data */ #define OCTOSPI_NO_ALTB (~OCTOSPI_ALTB_MODE) /* no alternate */ #define OCTOSPI_NO_ADDR (~0x00000F00U) /* no address */ #define OCTOSPI_ADDR3 (0x2U << SPI_ADSIZE_POS) /* 3 byte address */ #define OCTOSPI_ADDR4 (0x3U << SPI_ADSIZE_POS) /* 4 byte address */ #define OCTOSPI_DQSEN 29 /* DQS enable */ #define OCTOSPI_DDTR 27 /* DTR for data */ #define OCTOSPI_NO_DDTR (~BIT(OCTOSPI_DDTR)) /* no DTR for data, but maybe still DQS */ #define OCTOSPI_ISIZE_MASK (0x30) /* ISIZE field */ /* fields in OCTOSPI_TCR */ #define OCTOSPI_DCYC_POS 0 /* bit position of DCYC */ #define OCTOSPI_DCYC_LEN 5 /* width of DCYC field */ #define OCTOSPI_DCYC_MASK ((BIT(OCTOSPI_DCYC_LEN) - 1) << OCTOSPI_DCYC_POS) #define IS_OCTOSPI (stmqspi_info->octo) #define SPI_CR (IS_OCTOSPI ? OCTOSPI_CR : QSPI_CR) #define SPI_DCR (IS_OCTOSPI ? OCTOSPI_DCR1 : QSPI_DCR) #define SPI_SR (IS_OCTOSPI ? OCTOSPI_SR : QSPI_SR) #define SPI_FCR (IS_OCTOSPI ? OCTOSPI_FCR : QSPI_FCR) #define SPI_DLR (IS_OCTOSPI ? OCTOSPI_DLR : QSPI_DLR) #define SPI_AR (IS_OCTOSPI ? OCTOSPI_AR : QSPI_AR) #define SPI_DR (IS_OCTOSPI ? OCTOSPI_DR : QSPI_DR) #define SPI_CCR (IS_OCTOSPI ? OCTOSPI_CCR : QSPI_CCR) #endif /* OPENOCD_FLASH_NOR_STMQSPI_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/stmsmi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> * ***************************************************************************/ /* STM Serial Memory Interface (SMI) controller is a SPI bus controller * specifically designed for SPI memories. * Only SPI "mode 3" (CPOL=1 and CPHA=1) is supported. * Two working modes are available: * - SW mode: the SPI is controlled by SW. Any custom commands can be sent * on the bus. * - HW mode: the SPI but is under SMI control. Memory content is directly * accessible in CPU memory space. CPU can read, write and execute memory * content. */ /* ATTENTION: * To have flash memory mapped in CPU memory space, the SMI controller * have to be in "HW mode". This requires following constraints: * 1) The command "reset init" have to initialize SMI controller and put * it in HW mode; * 2) every command in this file have to return to prompt in HW mode. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "spi.h" #include <jtag/jtag.h> #include <helper/time_support.h> #define SMI_READ_REG(a) \ ({ \ int _ret; \ uint32_t _value; \ \ _ret = target_read_u32(target, io_base + (a), &_value); \ if (_ret != ERROR_OK) \ return _ret; \ _value; \ }) #define SMI_WRITE_REG(a, v) \ { \ int _retval; \ \ _retval = target_write_u32(target, io_base + (a), (v)); \ if (_retval != ERROR_OK) \ return _retval; \ } #define SMI_POLL_TFF(timeout) \ { \ int _retval; \ \ _retval = poll_tff(target, io_base, timeout); \ if (_retval != ERROR_OK) \ return _retval; \ } #define SMI_SET_SW_MODE() SMI_WRITE_REG(SMI_CR1, \ SMI_READ_REG(SMI_CR1) | SMI_SW_MODE) #define SMI_SET_HWWB_MODE() SMI_WRITE_REG(SMI_CR1, \ (SMI_READ_REG(SMI_CR1) | SMI_WB_MODE) & ~SMI_SW_MODE) #define SMI_SET_HW_MODE() SMI_WRITE_REG(SMI_CR1, \ SMI_READ_REG(SMI_CR1) & ~(SMI_SW_MODE | SMI_WB_MODE)) #define SMI_CLEAR_TFF() SMI_WRITE_REG(SMI_SR, ~SMI_TFF) #define SMI_BANK_SIZE (0x01000000) #define SMI_CR1 (0x00) /* Control register 1 */ #define SMI_CR2 (0x04) /* Control register 2 */ #define SMI_SR (0x08) /* Status register */ #define SMI_TR (0x0c) /* TX */ #define SMI_RR (0x10) /* RX */ /* fields in SMI_CR1 */ #define SMI_SW_MODE 0x10000000 /* set to enable SW Mode */ #define SMI_WB_MODE 0x20000000 /* Write Burst Mode */ /* fields in SMI_CR2 */ #define SMI_TX_LEN_1 0x00000001 /* data length = 1 byte */ #define SMI_TX_LEN_4 0x00000004 /* data length = 4 byte */ #define SMI_RX_LEN_3 0x00000030 /* data length = 3 byte */ #define SMI_SEND 0x00000080 /* Send data */ #define SMI_RSR 0x00000400 /* reads status reg */ #define SMI_WE 0x00000800 /* Write Enable */ #define SMI_SEL_BANK0 0x00000000 /* Select Bank0 */ #define SMI_SEL_BANK1 0x00001000 /* Select Bank1 */ #define SMI_SEL_BANK2 0x00002000 /* Select Bank2 */ #define SMI_SEL_BANK3 0x00003000 /* Select Bank3 */ /* fields in SMI_SR */ #define SMI_TFF 0x00000100 /* Transfer Finished Flag */ /* Commands */ #define SMI_READ_ID 0x0000009F /* Read Flash Identification */ /* Timeout in ms */ #define SMI_CMD_TIMEOUT (100) #define SMI_PROBE_TIMEOUT (100) #define SMI_MAX_TIMEOUT (3000) struct stmsmi_flash_bank { bool probed; uint32_t io_base; uint32_t bank_num; const struct flash_device *dev; }; struct stmsmi_target { char *name; uint32_t tap_idcode; uint32_t smi_base; uint32_t io_base; }; static const struct stmsmi_target target_devices[] = { /* name, tap_idcode, smi_base, io_base */ { "SPEAr3xx/6xx", 0x07926041, 0xf8000000, 0xfc000000 }, { "STR75x", 0x4f1f0041, 0x80000000, 0x90000000 }, { NULL, 0, 0, 0 } }; FLASH_BANK_COMMAND_HANDLER(stmsmi_flash_bank_command) { struct stmsmi_flash_bank *stmsmi_info; LOG_DEBUG("%s", __func__); if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; stmsmi_info = malloc(sizeof(struct stmsmi_flash_bank)); if (!stmsmi_info) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } bank->driver_priv = stmsmi_info; stmsmi_info->probed = false; return ERROR_OK; } /* Poll transmit finished flag */ /* timeout in ms */ static int poll_tff(struct target *target, uint32_t io_base, int timeout) { int64_t endtime; if (SMI_READ_REG(SMI_SR) & SMI_TFF) return ERROR_OK; endtime = timeval_ms() + timeout; do { alive_sleep(1); if (SMI_READ_REG(SMI_SR) & SMI_TFF) return ERROR_OK; } while (timeval_ms() < endtime); LOG_ERROR("Timeout while polling TFF"); return ERROR_FLASH_OPERATION_FAILED; } /* Read the status register of the external SPI flash chip. * The operation is triggered by setting SMI_RSR bit. * SMI sends the proper SPI command (0x05) and returns value in SMI_SR */ static int read_status_reg(struct flash_bank *bank, uint32_t *status) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; /* clear transmit finished flag */ SMI_CLEAR_TFF(); /* Read status */ SMI_WRITE_REG(SMI_CR2, stmsmi_info->bank_num | SMI_RSR); /* Poll transmit finished flag */ SMI_POLL_TFF(SMI_CMD_TIMEOUT); /* clear transmit finished flag */ SMI_CLEAR_TFF(); *status = SMI_READ_REG(SMI_SR) & 0x0000ffff; /* clean-up SMI_CR2 */ SMI_WRITE_REG(SMI_CR2, 0); /* AB: Required ? */ return ERROR_OK; } /* check for WIP (write in progress) bit in status register */ /* timeout in ms */ static int wait_till_ready(struct flash_bank *bank, int timeout) { uint32_t status; int retval; int64_t endtime; endtime = timeval_ms() + timeout; do { /* read flash status register */ retval = read_status_reg(bank, &status); if (retval != ERROR_OK) return retval; if ((status & SPIFLASH_BSY_BIT) == 0) return ERROR_OK; alive_sleep(1); } while (timeval_ms() < endtime); LOG_ERROR("timeout"); return ERROR_FAIL; } /* Send "write enable" command to SPI flash chip. * The operation is triggered by setting SMI_WE bit, and SMI sends * the proper SPI command (0x06) */ static int smi_write_enable(struct flash_bank *bank) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; uint32_t status; int retval; /* Enter in HW mode */ SMI_SET_HW_MODE(); /* AB: is this correct ?*/ /* clear transmit finished flag */ SMI_CLEAR_TFF(); /* Send write enable command */ SMI_WRITE_REG(SMI_CR2, stmsmi_info->bank_num | SMI_WE); /* Poll transmit finished flag */ SMI_POLL_TFF(SMI_CMD_TIMEOUT); /* read flash status register */ retval = read_status_reg(bank, &status); if (retval != ERROR_OK) return retval; /* Check write enabled */ if ((status & SPIFLASH_WE_BIT) == 0) { LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status); return ERROR_FAIL; } return ERROR_OK; } static uint32_t erase_command(struct stmsmi_flash_bank *stmsmi_info, uint32_t offset) { uint8_t cmd_bytes[] = { stmsmi_info->dev->erase_cmd, offset >> 16, offset >> 8, offset }; return le_to_h_u32(cmd_bytes); } static int smi_erase_sector(struct flash_bank *bank, int sector) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; uint32_t cmd; int retval; retval = smi_write_enable(bank); if (retval != ERROR_OK) return retval; /* Switch to SW mode to send sector erase command */ SMI_SET_SW_MODE(); /* clear transmit finished flag */ SMI_CLEAR_TFF(); /* send SPI command "block erase" */ cmd = erase_command(stmsmi_info, bank->sectors[sector].offset); SMI_WRITE_REG(SMI_TR, cmd); SMI_WRITE_REG(SMI_CR2, stmsmi_info->bank_num | SMI_SEND | SMI_TX_LEN_4); /* Poll transmit finished flag */ SMI_POLL_TFF(SMI_CMD_TIMEOUT); /* poll WIP for end of self timed Sector Erase cycle */ retval = wait_till_ready(bank, SMI_MAX_TIMEOUT); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stmsmi_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; int retval = ERROR_OK; LOG_DEBUG("%s: from sector %u to sector %u", __func__, first, last); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((last < first) || (last >= bank->num_sectors)) { LOG_ERROR("Flash sector invalid"); return ERROR_FLASH_SECTOR_INVALID; } if (!(stmsmi_info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } for (unsigned int sector = first; sector <= last; sector++) { if (bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FAIL; } } if (stmsmi_info->dev->erase_cmd == 0x00) return ERROR_FLASH_OPER_UNSUPPORTED; for (unsigned int sector = first; sector <= last; sector++) { retval = smi_erase_sector(bank, sector); if (retval != ERROR_OK) break; keep_alive(); } /* Switch to HW mode before return to prompt */ SMI_SET_HW_MODE(); return retval; } static int stmsmi_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { for (unsigned int sector = first; sector <= last; sector++) bank->sectors[sector].is_protected = set; return ERROR_OK; } static int smi_write_buffer(struct flash_bank *bank, const uint8_t *buffer, uint32_t address, uint32_t len) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; int retval; LOG_DEBUG("%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, __func__, address, len); retval = smi_write_enable(bank); if (retval != ERROR_OK) return retval; /* HW mode, write burst mode */ SMI_SET_HWWB_MODE(); retval = target_write_buffer(target, address, len, buffer); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stmsmi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; uint32_t cur_count, page_size, page_offset; int retval = ERROR_OK; LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, __func__, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > stmsmi_info->dev->size_in_bytes) { LOG_WARNING("Write pasts end of flash. Extra data discarded."); count = stmsmi_info->dev->size_in_bytes - offset; } /* Check sector protection */ for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { /* Start offset in or before this sector? */ /* End offset in or behind this sector? */ if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) && ((offset + count - 1) >= bank->sectors[sector].offset) && bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FAIL; } } /* if no valid page_size, use reasonable default */ page_size = stmsmi_info->dev->pagesize ? stmsmi_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE; /* unaligned buffer head */ if (count > 0 && (offset & 3) != 0) { cur_count = 4 - (offset & 3); if (cur_count > count) cur_count = count; retval = smi_write_buffer(bank, buffer, bank->base + offset, cur_count); if (retval != ERROR_OK) goto err; offset += cur_count; buffer += cur_count; count -= cur_count; } page_offset = offset % page_size; /* central part, aligned words */ while (count >= 4) { /* clip block at page boundary */ if (page_offset + count > page_size) cur_count = page_size - page_offset; else cur_count = count & ~3; retval = smi_write_buffer(bank, buffer, bank->base + offset, cur_count); if (retval != ERROR_OK) goto err; page_offset = 0; buffer += cur_count; offset += cur_count; count -= cur_count; keep_alive(); } /* buffer tail */ if (count > 0) retval = smi_write_buffer(bank, buffer, bank->base + offset, count); err: /* Switch to HW mode before return to prompt */ SMI_SET_HW_MODE(); return retval; } /* Return ID of flash device */ /* On exit, SW mode is kept */ static int read_flash_id(struct flash_bank *bank, uint32_t *id) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* poll WIP */ retval = wait_till_ready(bank, SMI_PROBE_TIMEOUT); if (retval != ERROR_OK) return retval; /* enter in SW mode */ SMI_SET_SW_MODE(); /* clear transmit finished flag */ SMI_CLEAR_TFF(); /* Send SPI command "read ID" */ SMI_WRITE_REG(SMI_TR, SMI_READ_ID); SMI_WRITE_REG(SMI_CR2, stmsmi_info->bank_num | SMI_SEND | SMI_RX_LEN_3 | SMI_TX_LEN_1); /* Poll transmit finished flag */ SMI_POLL_TFF(SMI_CMD_TIMEOUT); /* clear transmit finished flag */ SMI_CLEAR_TFF(); /* read ID from Receive Register */ *id = SMI_READ_REG(SMI_RR) & 0x00ffffff; return ERROR_OK; } static int stmsmi_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base, sectorsize; struct flash_sector *sectors; uint32_t id = 0; /* silence uninitialized warning */ const struct stmsmi_target *target_device; int retval; if (stmsmi_info->probed) free(bank->sectors); stmsmi_info->probed = false; for (target_device = target_devices ; target_device->name ; ++target_device) if (target_device->tap_idcode == target->tap->idcode) break; if (!target_device->name) { LOG_ERROR("Device ID 0x%" PRIx32 " is not known as SMI capable", target->tap->idcode); return ERROR_FAIL; } switch (bank->base - target_device->smi_base) { case 0: stmsmi_info->bank_num = SMI_SEL_BANK0; break; case SMI_BANK_SIZE: stmsmi_info->bank_num = SMI_SEL_BANK1; break; case 2*SMI_BANK_SIZE: stmsmi_info->bank_num = SMI_SEL_BANK2; break; case 3*SMI_BANK_SIZE: stmsmi_info->bank_num = SMI_SEL_BANK3; break; default: LOG_ERROR("Invalid SMI base address " TARGET_ADDR_FMT, bank->base); return ERROR_FAIL; } io_base = target_device->io_base; stmsmi_info->io_base = io_base; LOG_DEBUG("Valid SMI on device %s at address " TARGET_ADDR_FMT, target_device->name, bank->base); /* read and decode flash ID; returns in SW mode */ retval = read_flash_id(bank, &id); SMI_SET_HW_MODE(); if (retval != ERROR_OK) return retval; stmsmi_info->dev = NULL; for (const struct flash_device *p = flash_devices; p->name ; p++) if (p->device_id == id) { stmsmi_info->dev = p; break; } if (!stmsmi_info->dev) { LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id); return ERROR_FAIL; } LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", stmsmi_info->dev->name, stmsmi_info->dev->device_id); /* Set correct size value */ bank->size = stmsmi_info->dev->size_in_bytes; if (bank->size <= (1UL << 16)) LOG_WARNING("device needs 2-byte addresses - not implemented"); if (bank->size > (1UL << 24)) LOG_WARNING("device needs paging or 4-byte addresses - not implemented"); /* if no sectors, treat whole bank as single sector */ sectorsize = stmsmi_info->dev->sectorsize ? stmsmi_info->dev->sectorsize : stmsmi_info->dev->size_in_bytes; /* create and fill sectors array */ bank->num_sectors = stmsmi_info->dev->size_in_bytes / sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); if (!sectors) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { sectors[sector].offset = sector * sectorsize; sectors[sector].size = sectorsize; sectors[sector].is_erased = -1; sectors[sector].is_protected = 1; } bank->sectors = sectors; stmsmi_info->probed = true; return ERROR_OK; } static int stmsmi_auto_probe(struct flash_bank *bank) { struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; if (stmsmi_info->probed) return ERROR_OK; return stmsmi_probe(bank); } static int stmsmi_protect_check(struct flash_bank *bank) { /* Nothing to do. Protection is only handled in SW. */ return ERROR_OK; } static int get_stmsmi_info(struct flash_bank *bank, struct command_invocation *cmd) { struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; if (!(stmsmi_info->probed)) { command_print_sameline(cmd, "\nSMI flash bank not probed yet\n"); return ERROR_OK; } command_print_sameline(cmd, "\nSMI flash information:\n" " Device \'%s\' (ID 0x%08" PRIx32 ")\n", stmsmi_info->dev->name, stmsmi_info->dev->device_id); return ERROR_OK; } const struct flash_driver stmsmi_flash = { .name = "stmsmi", .flash_bank_command = stmsmi_flash_bank_command, .erase = stmsmi_erase, .protect = stmsmi_protect, .write = stmsmi_write, .read = default_flash_read, .probe = stmsmi_probe, .auto_probe = stmsmi_auto_probe, .erase_check = default_flash_blank_check, .protect_check = stmsmi_protect_check, .info = get_stmsmi_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/str7x.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2010 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <target/arm.h> #include <helper/binarybuffer.h> #include <target/algorithm.h> /* Flash registers */ #define FLASH_CR0 0x00000000 #define FLASH_CR1 0x00000004 #define FLASH_DR0 0x00000008 #define FLASH_DR1 0x0000000C #define FLASH_AR 0x00000010 #define FLASH_ER 0x00000014 #define FLASH_NVWPAR 0x0000DFB0 #define FLASH_NVAPR0 0x0000DFB8 #define FLASH_NVAPR1 0x0000DFBC /* FLASH_CR0 register bits */ #define FLASH_WMS 0x80000000 #define FLASH_SUSP 0x40000000 #define FLASH_WPG 0x20000000 #define FLASH_DWPG 0x10000000 #define FLASH_SER 0x08000000 #define FLASH_SPR 0x01000000 #define FLASH_BER 0x04000000 #define FLASH_MER 0x02000000 #define FLASH_LOCK 0x00000010 #define FLASH_BSYA1 0x00000004 #define FLASH_BSYA0 0x00000002 /* FLASH_CR1 register bits */ #define FLASH_B1S 0x02000000 #define FLASH_B0S 0x01000000 #define FLASH_B1F1 0x00020000 #define FLASH_B1F0 0x00010000 #define FLASH_B0F7 0x00000080 #define FLASH_B0F6 0x00000040 #define FLASH_B0F5 0x00000020 #define FLASH_B0F4 0x00000010 #define FLASH_B0F3 0x00000008 #define FLASH_B0F2 0x00000004 #define FLASH_B0F1 0x00000002 #define FLASH_B0F0 0x00000001 /* FLASH_ER register bits */ #define FLASH_WPF 0x00000100 #define FLASH_RESER 0x00000080 #define FLASH_SEQER 0x00000040 #define FLASH_10ER 0x00000008 #define FLASH_PGER 0x00000004 #define FLASH_ERER 0x00000002 #define FLASH_ERR 0x00000001 struct str7x_flash_bank { uint32_t *sector_bits; uint32_t disable_bit; uint32_t busy_bits; uint32_t register_base; }; struct str7x_mem_layout { uint32_t sector_start; uint32_t sector_size; uint32_t sector_bit; }; enum str7x_status_codes { STR7X_CMD_SUCCESS = 0, STR7X_INVALID_COMMAND = 1, STR7X_SRC_ADDR_ERROR = 2, STR7X_DST_ADDR_ERROR = 3, STR7X_SRC_ADDR_NOT_MAPPED = 4, STR7X_DST_ADDR_NOT_MAPPED = 5, STR7X_COUNT_ERROR = 6, STR7X_INVALID_SECTOR = 7, STR7X_SECTOR_NOT_BLANK = 8, STR7X_SECTOR_NOT_PREPARED = 9, STR7X_COMPARE_ERROR = 10, STR7X_BUSY = 11 }; static const struct str7x_mem_layout mem_layout_str7bank0[] = { {0x00000000, 0x02000, 0x01}, {0x00002000, 0x02000, 0x02}, {0x00004000, 0x02000, 0x04}, {0x00006000, 0x02000, 0x08}, {0x00008000, 0x08000, 0x10}, {0x00010000, 0x10000, 0x20}, {0x00020000, 0x10000, 0x40}, {0x00030000, 0x10000, 0x80} }; static const struct str7x_mem_layout mem_layout_str7bank1[] = { {0x00000000, 0x02000, 0x10000}, {0x00002000, 0x02000, 0x20000} }; static int str7x_get_flash_adr(struct flash_bank *bank, uint32_t reg) { struct str7x_flash_bank *str7x_info = bank->driver_priv; return str7x_info->register_base | reg; } static int str7x_build_block_list(struct flash_bank *bank) { struct str7x_flash_bank *str7x_info = bank->driver_priv; int i; unsigned int num_sectors; int b0_sectors = 0, b1_sectors = 0; switch (bank->size) { case 16 * 1024: b1_sectors = 2; break; case 64 * 1024: b0_sectors = 5; break; case 128 * 1024: b0_sectors = 6; break; case 256 * 1024: b0_sectors = 8; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } num_sectors = b0_sectors + b1_sectors; bank->num_sectors = num_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); str7x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors); num_sectors = 0; for (i = 0; i < b0_sectors; i++) { bank->sectors[num_sectors].offset = mem_layout_str7bank0[i].sector_start; bank->sectors[num_sectors].size = mem_layout_str7bank0[i].sector_size; bank->sectors[num_sectors].is_erased = -1; /* the reset_init handler marks all the sectors unprotected, * matching hardware after reset; keep the driver in sync */ bank->sectors[num_sectors].is_protected = 0; str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank0[i].sector_bit; } for (i = 0; i < b1_sectors; i++) { bank->sectors[num_sectors].offset = mem_layout_str7bank1[i].sector_start; bank->sectors[num_sectors].size = mem_layout_str7bank1[i].sector_size; bank->sectors[num_sectors].is_erased = -1; /* the reset_init handler marks all the sectors unprotected, * matching hardware after reset; keep the driver in sync */ bank->sectors[num_sectors].is_protected = 0; str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank1[i].sector_bit; } return ERROR_OK; } /* flash bank str7x <base> <size> 0 0 <target#> <str71_variant> */ FLASH_BANK_COMMAND_HANDLER(str7x_flash_bank_command) { struct str7x_flash_bank *str7x_info; if (CMD_ARGC < 7) return ERROR_COMMAND_SYNTAX_ERROR; str7x_info = malloc(sizeof(struct str7x_flash_bank)); bank->driver_priv = str7x_info; /* set default bits for str71x flash */ str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA1 | FLASH_BSYA0); str7x_info->disable_bit = (1 << 1); if (strcmp(CMD_ARGV[6], "STR71x") == 0) str7x_info->register_base = 0x40100000; else if (strcmp(CMD_ARGV[6], "STR73x") == 0) { str7x_info->register_base = 0x80100000; str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA0); } else if (strcmp(CMD_ARGV[6], "STR75x") == 0) { str7x_info->register_base = 0x20100000; str7x_info->disable_bit = (1 << 0); } else { LOG_ERROR("unknown STR7x variant: '%s'", CMD_ARGV[6]); free(str7x_info); return ERROR_FLASH_BANK_INVALID; } str7x_build_block_list(bank); return ERROR_OK; } /* wait for flash to become idle or report errors. FIX!!! what's the maximum timeout??? The documentation doesn't state any maximum time.... by inspection it seems > 1000ms is to be expected. 10000ms is long enough that it should cover anything, yet not quite be equivalent to an infinite loop. */ static int str7x_waitbusy(struct flash_bank *bank) { int err; int i; struct target *target = bank->target; struct str7x_flash_bank *str7x_info = bank->driver_priv; for (i = 0 ; i < 10000; i++) { uint32_t retval; err = target_read_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), &retval); if (err != ERROR_OK) return err; if ((retval & str7x_info->busy_bits) == 0) return ERROR_OK; alive_sleep(1); } LOG_ERROR("Timed out waiting for str7x flash"); return ERROR_FAIL; } static int str7x_result(struct flash_bank *bank) { struct target *target = bank->target; uint32_t flash_flags; int retval; retval = target_read_u32(target, str7x_get_flash_adr(bank, FLASH_ER), &flash_flags); if (retval != ERROR_OK) return retval; if (flash_flags & FLASH_WPF) { LOG_ERROR("str7x hw write protection set"); retval = ERROR_FAIL; } if (flash_flags & FLASH_RESER) { LOG_ERROR("str7x suspended program erase not resumed"); retval = ERROR_FAIL; } if (flash_flags & FLASH_10ER) { LOG_ERROR("str7x trying to set bit to 1 when it is already 0"); retval = ERROR_FAIL; } if (flash_flags & FLASH_PGER) { LOG_ERROR("str7x program error"); retval = ERROR_FAIL; } if (flash_flags & FLASH_ERER) { LOG_ERROR("str7x erase error"); retval = ERROR_FAIL; } if (retval == ERROR_OK) { if (flash_flags & FLASH_ERR) { /* this should always be set if one of the others are set... */ LOG_ERROR("str7x write operation failed / bad setup"); retval = ERROR_FAIL; } } return retval; } static int str7x_protect_check(struct flash_bank *bank) { struct str7x_flash_bank *str7x_info = bank->driver_priv; struct target *target = bank->target; uint32_t flash_flags; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } int retval; retval = target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), &flash_flags); if (retval != ERROR_OK) return retval; for (unsigned int i = 0; i < bank->num_sectors; i++) { if (flash_flags & str7x_info->sector_bits[i]) bank->sectors[i].is_protected = 0; else bank->sectors[i].is_protected = 1; } return ERROR_OK; } static int str7x_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct str7x_flash_bank *str7x_info = bank->driver_priv; struct target *target = bank->target; uint32_t cmd; uint32_t sectors = 0; int err; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } for (unsigned int i = first; i <= last; i++) sectors |= str7x_info->sector_bits[i]; LOG_DEBUG("sectors: 0x%" PRIx32 "", sectors); /* clear FLASH_ER register */ err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0); if (err != ERROR_OK) return err; cmd = FLASH_SER; err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); if (err != ERROR_OK) return err; cmd = sectors; err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR1), cmd); if (err != ERROR_OK) return err; cmd = FLASH_SER | FLASH_WMS; err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); if (err != ERROR_OK) return err; err = str7x_waitbusy(bank); if (err != ERROR_OK) return err; err = str7x_result(bank); if (err != ERROR_OK) return err; return ERROR_OK; } static int str7x_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct str7x_flash_bank *str7x_info = bank->driver_priv; struct target *target = bank->target; uint32_t cmd; uint32_t protect_blocks; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } protect_blocks = 0xFFFFFFFF; if (set) { for (unsigned int i = first; i <= last; i++) protect_blocks &= ~(str7x_info->sector_bits[i]); } /* clear FLASH_ER register */ int err; err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0); if (err != ERROR_OK) return err; cmd = FLASH_SPR; err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); if (err != ERROR_OK) return err; cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR); err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), cmd); if (err != ERROR_OK) return err; cmd = protect_blocks; err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), cmd); if (err != ERROR_OK) return err; cmd = FLASH_SPR | FLASH_WMS; err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); if (err != ERROR_OK) return err; err = str7x_waitbusy(bank); if (err != ERROR_OK) return err; err = str7x_result(bank); if (err != ERROR_OK) return err; return ERROR_OK; } static int str7x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct str7x_flash_bank *str7x_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 32768; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[6]; struct arm_algorithm arm_algo; int retval = ERROR_OK; /* see contrib/loaders/flash/str7x.s for src */ static const uint32_t str7x_flash_write_code[] = { /* write: */ 0xe3a04201, /* mov r4, #0x10000000 */ 0xe5824000, /* str r4, [r2, #0x0] */ 0xe5821010, /* str r1, [r2, #0x10] */ 0xe4904004, /* ldr r4, [r0], #4 */ 0xe5824008, /* str r4, [r2, #0x8] */ 0xe4904004, /* ldr r4, [r0], #4 */ 0xe582400c, /* str r4, [r2, #0xc] */ 0xe3a04209, /* mov r4, #0x90000000 */ 0xe5824000, /* str r4, [r2, #0x0] */ /* busy: */ 0xe5924000, /* ldr r4, [r2, #0x0] */ 0xe1140005, /* tst r4, r5 */ 0x1afffffc, /* bne busy */ 0xe5924014, /* ldr r4, [r2, #0x14] */ 0xe31400ff, /* tst r4, #0xff */ 0x03140c01, /* tsteq r4, #0x100 */ 0x1a000002, /* bne exit */ 0xe2811008, /* add r1, r1, #0x8 */ 0xe2533001, /* subs r3, r3, #1 */ 0x1affffec, /* bne write */ /* exit: */ 0xeafffffe, /* b exit */ }; /* flash write code */ if (target_alloc_working_area_try(target, sizeof(str7x_flash_write_code), &write_algorithm) != ERROR_OK) { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } uint8_t code[sizeof(str7x_flash_write_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(str7x_flash_write_code), str7x_flash_write_code); target_write_buffer(target, write_algorithm->address, sizeof(code), code); /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_IN); init_reg_param(®_params[5], "r5", 32, PARAM_OUT); while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count; target_write_buffer(target, source->address, thisrun_count * 8, buffer); buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, str7x_get_flash_adr(bank, FLASH_CR0)); buf_set_u32(reg_params[3].value, 0, 32, thisrun_count); buf_set_u32(reg_params[5].value, 0, 32, str7x_info->busy_bits); retval = target_run_algorithm(target, 0, NULL, 6, reg_params, write_algorithm->address, write_algorithm->address + (sizeof(str7x_flash_write_code) - 4), 10000, &arm_algo); if (retval != ERROR_OK) break; if (buf_get_u32(reg_params[4].value, 0, 32) != 0x00) { retval = str7x_result(bank); break; } buffer += thisrun_count * 8; address += thisrun_count * 8; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); return retval; } static int str7x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t dwords_remaining = (count / 8); uint32_t bytes_remaining = (count & 0x00000007); uint32_t address = bank->base + offset; uint32_t bytes_written = 0; uint32_t cmd; int retval; uint32_t check_address = offset; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x7) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } for (unsigned int i = 0; i < bank->num_sectors; i++) { uint32_t sec_start = bank->sectors[i].offset; uint32_t sec_end = sec_start + bank->sectors[i].size; /* check if destination falls within the current sector */ if ((check_address >= sec_start) && (check_address < sec_end)) { /* check if destination ends in the current sector */ if (offset + count < sec_end) check_address = offset + count; else check_address = sec_end; } } if (check_address != offset + count) return ERROR_FLASH_DST_OUT_OF_BANK; /* clear FLASH_ER register */ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0); /* multiple dwords (8-byte) to be programmed? */ if (dwords_remaining > 0) { /* try using a block write */ retval = str7x_write_block(bank, buffer, offset, dwords_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single dword accesses */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); } else { return retval; } } else { buffer += dwords_remaining * 8; address += dwords_remaining * 8; dwords_remaining = 0; } } while (dwords_remaining > 0) { /* command */ cmd = FLASH_DWPG; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); /* address */ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address); /* data word 1 */ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, buffer + bytes_written); bytes_written += 4; /* data word 2 */ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, buffer + bytes_written); bytes_written += 4; /* start programming cycle */ cmd = FLASH_DWPG | FLASH_WMS; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); int err; err = str7x_waitbusy(bank); if (err != ERROR_OK) return err; err = str7x_result(bank); if (err != ERROR_OK) return err; dwords_remaining--; address += 8; } if (bytes_remaining) { uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; /* copy the last remaining bytes into the write buffer */ memcpy(last_dword, buffer+bytes_written, bytes_remaining); /* command */ cmd = FLASH_DWPG; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); /* address */ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address); /* data word 1 */ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, last_dword); /* data word 2 */ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, last_dword + 4); /* start programming cycle */ cmd = FLASH_DWPG | FLASH_WMS; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); int err; err = str7x_waitbusy(bank); if (err != ERROR_OK) return err; err = str7x_result(bank); if (err != ERROR_OK) return err; } return ERROR_OK; } static int str7x_probe(struct flash_bank *bank) { return ERROR_OK; } #if 0 COMMAND_HANDLER(str7x_handle_part_id_command) { return ERROR_OK; } #endif static int get_str7x_info(struct flash_bank *bank, struct command_invocation *cmd) { /* Setting the write protection on a sector is a permanent change but it * can be disabled temporarily. FLASH_NVWPAR reflects the permanent * protection state of the sectors, not the temporary. */ command_print_sameline(cmd, "STR7x flash protection info is only valid after a power cycle, " "clearing the protection is only temporary and may not be reflected in the current " "info returned."); return ERROR_OK; } COMMAND_HANDLER(str7x_handle_disable_jtag_command) { struct target *target = NULL; struct str7x_flash_bank *str7x_info = NULL; uint32_t flash_cmd; uint16_t protection_level = 0; uint16_t protection_regs; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; str7x_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* first we get protection status */ uint32_t reg; target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR0), ®); if (!(reg & str7x_info->disable_bit)) protection_level = 1; target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR1), ®); protection_regs = ~(reg >> 16); while (((protection_regs) != 0) && (protection_level < 16)) { protection_regs >>= 1; protection_level++; } if (protection_level == 0) { flash_cmd = FLASH_SPR; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd); target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFB8); target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), 0xFFFFFFFD); flash_cmd = FLASH_SPR | FLASH_WMS; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd); } else { flash_cmd = FLASH_SPR; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd); target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFBC); target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), ~(1 << (15 + protection_level))); flash_cmd = FLASH_SPR | FLASH_WMS; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd); } return ERROR_OK; } static const struct command_registration str7x_exec_command_handlers[] = { { .name = "disable_jtag", .usage = "<bank>", .handler = str7x_handle_disable_jtag_command, .mode = COMMAND_EXEC, .help = "disable jtag access", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration str7x_command_handlers[] = { { .name = "str7x", .mode = COMMAND_ANY, .help = "str7x flash command group", .usage = "", .chain = str7x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver str7x_flash = { .name = "str7x", .commands = str7x_command_handlers, .flash_bank_command = str7x_flash_bank_command, .erase = str7x_erase, .protect = str7x_protect, .write = str7x_write, .read = default_flash_read, .probe = str7x_probe, .auto_probe = str7x_probe, .erase_check = default_flash_blank_check, .protect_check = str7x_protect_check, .info = get_str7x_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/str9x.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * Copyright (C) 2008 by Oyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <target/arm966e.h> #include <target/algorithm.h> /* Flash registers */ #define FLASH_BBSR 0x54000000 /* Boot Bank Size Register */ #define FLASH_NBBSR 0x54000004 /* Non-Boot Bank Size Register */ #define FLASH_BBADR 0x5400000C /* Boot Bank Base Address Register */ #define FLASH_NBBADR 0x54000010 /* Non-Boot Bank Base Address Register */ #define FLASH_CR 0x54000018 /* Control Register */ #define FLASH_SR 0x5400001C /* Status Register */ #define FLASH_BCE5ADDR 0x54000020 /* BC Fifth Entry Target Address Register */ struct str9x_flash_bank { uint32_t *sector_bits; int variant; int bank1; }; enum str9x_status_codes { STR9X_CMD_SUCCESS = 0, STR9X_INVALID_COMMAND = 1, STR9X_SRC_ADDR_ERROR = 2, STR9X_DST_ADDR_ERROR = 3, STR9X_SRC_ADDR_NOT_MAPPED = 4, STR9X_DST_ADDR_NOT_MAPPED = 5, STR9X_COUNT_ERROR = 6, STR9X_INVALID_SECTOR = 7, STR9X_SECTOR_NOT_BLANK = 8, STR9X_SECTOR_NOT_PREPARED = 9, STR9X_COMPARE_ERROR = 10, STR9X_BUSY = 11 }; static uint32_t bank1start = 0x00080000; static int str9x_build_block_list(struct flash_bank *bank) { struct str9x_flash_bank *str9x_info = bank->driver_priv; int i; unsigned int num_sectors; int b0_sectors = 0, b1_sectors = 0; uint32_t offset = 0; /* set if we have large flash str9 */ str9x_info->variant = 0; str9x_info->bank1 = 0; switch (bank->size) { case (256 * 1024): b0_sectors = 4; break; case (512 * 1024): b0_sectors = 8; break; case (1024 * 1024): bank1start = 0x00100000; str9x_info->variant = 1; b0_sectors = 16; break; case (2048 * 1024): bank1start = 0x00200000; str9x_info->variant = 1; b0_sectors = 32; break; case (128 * 1024): str9x_info->variant = 1; str9x_info->bank1 = 1; b1_sectors = 8; bank1start = bank->base; break; case (32 * 1024): str9x_info->bank1 = 1; b1_sectors = 4; bank1start = bank->base; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } num_sectors = b0_sectors + b1_sectors; bank->num_sectors = num_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); str9x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors); num_sectors = 0; for (i = 0; i < b0_sectors; i++) { bank->sectors[num_sectors].offset = offset; bank->sectors[num_sectors].size = 0x10000; offset += bank->sectors[i].size; bank->sectors[num_sectors].is_erased = -1; bank->sectors[num_sectors].is_protected = 1; str9x_info->sector_bits[num_sectors++] = (1 << i); } for (i = 0; i < b1_sectors; i++) { bank->sectors[num_sectors].offset = offset; bank->sectors[num_sectors].size = str9x_info->variant == 0 ? 0x2000 : 0x4000; offset += bank->sectors[i].size; bank->sectors[num_sectors].is_erased = -1; bank->sectors[num_sectors].is_protected = 1; if (str9x_info->variant) str9x_info->sector_bits[num_sectors++] = (1 << i); else str9x_info->sector_bits[num_sectors++] = (1 << (i + 8)); } return ERROR_OK; } /* flash bank str9x <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(str9x_flash_bank_command) { struct str9x_flash_bank *str9x_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; str9x_info = malloc(sizeof(struct str9x_flash_bank)); bank->driver_priv = str9x_info; str9x_build_block_list(bank); return ERROR_OK; } static int str9x_protect_check(struct flash_bank *bank) { int retval; struct str9x_flash_bank *str9x_info = bank->driver_priv; struct target *target = bank->target; uint32_t adr; uint32_t status = 0; uint16_t hstatus = 0; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* read level one protection */ if (str9x_info->variant) { if (str9x_info->bank1) { adr = bank1start + 0x18; retval = target_write_u16(target, adr, 0x90); if (retval != ERROR_OK) return retval; retval = target_read_u16(target, adr, &hstatus); if (retval != ERROR_OK) return retval; status = hstatus; } else { adr = bank1start + 0x14; retval = target_write_u16(target, adr, 0x90); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, adr, &status); if (retval != ERROR_OK) return retval; } } else { adr = bank1start + 0x10; retval = target_write_u16(target, adr, 0x90); if (retval != ERROR_OK) return retval; retval = target_read_u16(target, adr, &hstatus); if (retval != ERROR_OK) return retval; status = hstatus; } /* read array command */ retval = target_write_u16(target, adr, 0xFF); if (retval != ERROR_OK) return retval; for (unsigned int i = 0; i < bank->num_sectors; i++) { if (status & str9x_info->sector_bits[i]) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; } return ERROR_OK; } static int str9x_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; uint32_t adr; uint8_t status; uint8_t erase_cmd; int total_timeout; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Check if we can erase whole bank */ if ((first == 0) && (last == (bank->num_sectors - 1))) { /* Optimize to run erase bank command instead of sector */ erase_cmd = 0x80; /* Add timeout duration since erase bank takes more time */ total_timeout = 1000 * bank->num_sectors; } else { /* Erase sector command */ erase_cmd = 0x20; total_timeout = 1000; } /* this is so the compiler can *know* */ assert(total_timeout > 0); for (unsigned int i = first; i <= last; i++) { int retval; adr = bank->base + bank->sectors[i].offset; /* erase sectors or block */ retval = target_write_u16(target, adr, erase_cmd); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, adr, 0xD0); if (retval != ERROR_OK) return retval; /* get status */ retval = target_write_u16(target, adr, 0x70); if (retval != ERROR_OK) return retval; int timeout; for (timeout = 0; timeout < total_timeout; timeout++) { retval = target_read_u8(target, adr, &status); if (retval != ERROR_OK) return retval; if (status & 0x80) break; alive_sleep(1); } if (timeout == total_timeout) { LOG_ERROR("erase timed out"); return ERROR_FAIL; } /* clear status, also clear read array */ retval = target_write_u16(target, adr, 0x50); if (retval != ERROR_OK) return retval; /* read array command */ retval = target_write_u16(target, adr, 0xFF); if (retval != ERROR_OK) return retval; if (status & 0x22) { LOG_ERROR("error erasing flash bank, status: 0x%x", status); return ERROR_FLASH_OPERATION_FAILED; } /* If we ran erase bank command, we are finished */ if (erase_cmd == 0x80) break; } return ERROR_OK; } static int str9x_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct target *target = bank->target; uint32_t adr; uint8_t status; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } for (unsigned int i = first; i <= last; i++) { /* Level One Protection */ adr = bank->base + bank->sectors[i].offset; target_write_u16(target, adr, 0x60); if (set) target_write_u16(target, adr, 0x01); else target_write_u16(target, adr, 0xD0); /* query status */ target_read_u8(target, adr, &status); /* clear status, also clear read array */ target_write_u16(target, adr, 0x50); /* read array command */ target_write_u16(target, adr, 0xFF); } return ERROR_OK; } static int str9x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 32768; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[4]; struct arm_algorithm arm_algo; int retval = ERROR_OK; /* see contrib/loaders/flash/str9x.s for src */ static const uint32_t str9x_flash_write_code[] = { /* write: */ 0xe3c14003, /* bic r4, r1, #3 */ 0xe3a03040, /* mov r3, #0x40 */ 0xe1c430b0, /* strh r3, [r4, #0] */ 0xe0d030b2, /* ldrh r3, [r0], #2 */ 0xe0c130b2, /* strh r3, [r1], #2 */ 0xe3a03070, /* mov r3, #0x70 */ 0xe1c430b0, /* strh r3, [r4, #0] */ /* busy: */ 0xe5d43000, /* ldrb r3, [r4, #0] */ 0xe3130080, /* tst r3, #0x80 */ 0x0afffffc, /* beq busy */ 0xe3a05050, /* mov r5, #0x50 */ 0xe1c450b0, /* strh r5, [r4, #0] */ 0xe3a050ff, /* mov r5, #0xFF */ 0xe1c450b0, /* strh r5, [r4, #0] */ 0xe3130012, /* tst r3, #0x12 */ 0x1a000001, /* bne exit */ 0xe2522001, /* subs r2, r2, #1 */ 0x1affffed, /* bne write */ /* exit: */ 0xe1200070, /* bkpt #0 */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(str9x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } uint8_t code[sizeof(str9x_flash_write_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(str9x_flash_write_code), str9x_flash_write_code); target_write_buffer(target, write_algorithm->address, sizeof(code), code); /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN); while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count; target_write_buffer(target, source->address, thisrun_count * 2, buffer); buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); retval = target_run_algorithm(target, 0, NULL, 4, reg_params, write_algorithm->address, 0, 10000, &arm_algo); if (retval != ERROR_OK) { LOG_ERROR("error executing str9x flash write algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80) { retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count * 2; address += thisrun_count * 2; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; } static int str9x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t words_remaining = (count / 2); uint32_t bytes_remaining = (count & 0x00000001); uint32_t address = bank->base + offset; uint32_t bytes_written = 0; uint8_t status; int retval; uint32_t check_address = offset; uint32_t bank_adr; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x1) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } for (unsigned int i = 0; i < bank->num_sectors; i++) { uint32_t sec_start = bank->sectors[i].offset; uint32_t sec_end = sec_start + bank->sectors[i].size; /* check if destination falls within the current sector */ if ((check_address >= sec_start) && (check_address < sec_end)) { /* check if destination ends in the current sector */ if (offset + count < sec_end) check_address = offset + count; else check_address = sec_end; } } if (check_address != offset + count) return ERROR_FLASH_DST_OUT_OF_BANK; /* multiple half words (2-byte) to be programmed? */ if (words_remaining > 0) { /* try using a block write */ retval = str9x_write_block(bank, buffer, offset, words_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single dword accesses */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); } else if (retval == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("flash writing failed"); return ERROR_FLASH_OPERATION_FAILED; } } else { buffer += words_remaining * 2; address += words_remaining * 2; words_remaining = 0; } } while (words_remaining > 0) { bank_adr = address & ~0x03; /* write data command */ target_write_u16(target, bank_adr, 0x40); target_write_memory(target, address, 2, 1, buffer + bytes_written); /* get status command */ target_write_u16(target, bank_adr, 0x70); int timeout; for (timeout = 0; timeout < 1000; timeout++) { target_read_u8(target, bank_adr, &status); if (status & 0x80) break; alive_sleep(1); } if (timeout == 1000) { LOG_ERROR("write timed out"); return ERROR_FAIL; } /* clear status reg and read array */ target_write_u16(target, bank_adr, 0x50); target_write_u16(target, bank_adr, 0xFF); if (status & 0x10) return ERROR_FLASH_OPERATION_FAILED; else if (status & 0x02) return ERROR_FLASH_OPERATION_FAILED; bytes_written += 2; words_remaining--; address += 2; } if (bytes_remaining) { uint8_t last_halfword[2] = {0xff, 0xff}; /* copy the last remaining bytes into the write buffer */ memcpy(last_halfword, buffer+bytes_written, bytes_remaining); bank_adr = address & ~0x03; /* write data command */ target_write_u16(target, bank_adr, 0x40); target_write_memory(target, address, 2, 1, last_halfword); /* query status command */ target_write_u16(target, bank_adr, 0x70); int timeout; for (timeout = 0; timeout < 1000; timeout++) { target_read_u8(target, bank_adr, &status); if (status & 0x80) break; alive_sleep(1); } if (timeout == 1000) { LOG_ERROR("write timed out"); return ERROR_FAIL; } /* clear status reg and read array */ target_write_u16(target, bank_adr, 0x50); target_write_u16(target, bank_adr, 0xFF); if (status & 0x10) return ERROR_FLASH_OPERATION_FAILED; else if (status & 0x02) return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int str9x_probe(struct flash_bank *bank) { return ERROR_OK; } #if 0 COMMAND_HANDLER(str9x_handle_part_id_command) { return ERROR_OK; } #endif COMMAND_HANDLER(str9x_handle_flash_config_command) { struct target *target = NULL; if (CMD_ARGC < 5) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; uint32_t bbsr, nbbsr, bbadr, nbbadr; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], bbsr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], nbbsr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], bbadr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], nbbadr); target = bank->target; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* config flash controller */ target_write_u32(target, FLASH_BBSR, bbsr); target_write_u32(target, FLASH_NBBSR, nbbsr); target_write_u32(target, FLASH_BBADR, bbadr >> 2); target_write_u32(target, FLASH_NBBADR, nbbadr >> 2); /* set bit 18 instruction TCM order as per flash programming manual */ arm966e_write_cp15(target, 62, 0x40000); /* enable flash bank 1 */ target_write_u32(target, FLASH_CR, 0x18); return ERROR_OK; } static const struct command_registration str9x_config_command_handlers[] = { { .name = "flash_config", .handler = str9x_handle_flash_config_command, .mode = COMMAND_EXEC, .help = "Configure str9x flash controller, prior to " "programming the flash.", .usage = "bank_id BBSR NBBSR BBADR NBBADR", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration str9x_command_handlers[] = { { .name = "str9x", .mode = COMMAND_ANY, .help = "str9x flash command group", .usage = "", .chain = str9x_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver str9x_flash = { .name = "str9x", .commands = str9x_command_handlers, .flash_bank_command = str9x_flash_bank_command, .erase = str9x_erase, .protect = str9x_protect, .write = str9x_write, .read = default_flash_read, .probe = str9x_probe, .auto_probe = str9x_probe, .erase_check = default_flash_blank_check, .protect_check = str9x_protect_check, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/str9xpec.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <target/arm7_9_common.h> /* ISC commands */ #define ISC_IDCODE 0xFE #define ISC_MFG_READ 0x4C #define ISC_CONFIGURATION 0x07 #define ISC_ENABLE 0x0C #define ISC_DISABLE 0x0F #define ISC_NOOP 0x10 #define ISC_ADDRESS_SHIFT 0x11 #define ISC_CLR_STATUS 0x13 #define ISC_PROGRAM 0x20 #define ISC_PROGRAM_SECURITY 0x22 #define ISC_PROGRAM_UC 0x23 #define ISC_ERASE 0x30 #define ISC_READ 0x50 #define ISC_BLANK_CHECK 0x60 /* ISC_DEFAULT bit definitions */ #define ISC_STATUS_SECURITY 0x40 #define ISC_STATUS_INT_ERROR 0x30 #define ISC_STATUS_MODE 0x08 #define ISC_STATUS_BUSY 0x04 #define ISC_STATUS_ERROR 0x03 /* Option bytes definitions */ #define STR9XPEC_OPT_CSMAPBIT 48 #define STR9XPEC_OPT_LVDTHRESBIT 49 #define STR9XPEC_OPT_LVDSELBIT 50 #define STR9XPEC_OPT_LVDWARNBIT 51 #define STR9XPEC_OPT_OTPBIT 63 enum str9xpec_status_codes { STR9XPEC_INVALID_COMMAND = 1, STR9XPEC_ISC_SUCCESS = 2, STR9XPEC_ISC_DISABLED = 3, STR9XPEC_ISC_INTFAIL = 32, }; struct str9xpec_flash_controller { struct jtag_tap *tap; uint32_t *sector_bits; int chain_pos; int isc_enable; uint8_t options[8]; }; static int str9xpec_erase_area(struct flash_bank *bank, unsigned int first, unsigned int last); static int str9xpec_set_address(struct flash_bank *bank, uint8_t sector); static int str9xpec_write_options(struct flash_bank *bank); static int str9xpec_set_instr(struct jtag_tap *tap, uint32_t new_instr, tap_state_t end_state) { if (!tap) return ERROR_TARGET_INVALID; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; field.num_bits = tap->ir_length; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, end_state); free(t); } return ERROR_OK; } static uint8_t str9xpec_isc_status(struct jtag_tap *tap) { struct scan_field field; uint8_t status; if (str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE) != ERROR_OK) return ISC_STATUS_ERROR; field.num_bits = 8; field.out_value = NULL; field.in_value = &status; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); LOG_DEBUG("status: 0x%2.2x", status); if (status & ISC_STATUS_SECURITY) LOG_INFO("Device Security Bit Set"); return status; } static int str9xpec_isc_enable(struct flash_bank *bank) { uint8_t status; struct jtag_tap *tap; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; if (str9xpec_info->isc_enable) return ERROR_OK; /* enter isc mode */ if (str9xpec_set_instr(tap, ISC_ENABLE, TAP_IDLE) != ERROR_OK) return ERROR_TARGET_INVALID; /* check ISC status */ status = str9xpec_isc_status(tap); if (status & ISC_STATUS_MODE) { /* we have entered isc mode */ str9xpec_info->isc_enable = 1; LOG_DEBUG("ISC_MODE Enabled"); } return ERROR_OK; } static int str9xpec_isc_disable(struct flash_bank *bank) { uint8_t status; struct jtag_tap *tap; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; if (!str9xpec_info->isc_enable) return ERROR_OK; if (str9xpec_set_instr(tap, ISC_DISABLE, TAP_IDLE) != ERROR_OK) return ERROR_TARGET_INVALID; /* delay to handle aborts */ jtag_add_sleep(50); /* check ISC status */ status = str9xpec_isc_status(tap); if (!(status & ISC_STATUS_MODE)) { /* we have left isc mode */ str9xpec_info->isc_enable = 0; LOG_DEBUG("ISC_MODE Disabled"); } return ERROR_OK; } static int str9xpec_read_config(struct flash_bank *bank) { struct scan_field field; uint8_t status; struct jtag_tap *tap; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; LOG_DEBUG("ISC_CONFIGURATION"); /* execute ISC_CONFIGURATION command */ str9xpec_set_instr(tap, ISC_CONFIGURATION, TAP_IRPAUSE); field.num_bits = 64; field.out_value = NULL; field.in_value = str9xpec_info->options; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); status = str9xpec_isc_status(tap); return status; } static int str9xpec_build_block_list(struct flash_bank *bank) { struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; int i; unsigned int num_sectors; int b0_sectors = 0, b1_sectors = 0; uint32_t offset = 0; int b1_size = 0x2000; switch (bank->size) { case (256 * 1024): b0_sectors = 4; break; case (512 * 1024): b0_sectors = 8; break; case (1024 * 1024): b0_sectors = 16; break; case (2048 * 1024): b0_sectors = 32; break; case (128 * 1024): b1_size = 0x4000; b1_sectors = 8; break; case (32 * 1024): b1_sectors = 4; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } num_sectors = b0_sectors + b1_sectors; bank->num_sectors = num_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); str9xpec_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors); num_sectors = 0; for (i = 0; i < b0_sectors; i++) { bank->sectors[num_sectors].offset = offset; bank->sectors[num_sectors].size = 0x10000; offset += bank->sectors[i].size; bank->sectors[num_sectors].is_erased = -1; bank->sectors[num_sectors].is_protected = 1; str9xpec_info->sector_bits[num_sectors++] = i; } for (i = 0; i < b1_sectors; i++) { bank->sectors[num_sectors].offset = offset; bank->sectors[num_sectors].size = b1_size; offset += bank->sectors[i].size; bank->sectors[num_sectors].is_erased = -1; bank->sectors[num_sectors].is_protected = 1; str9xpec_info->sector_bits[num_sectors++] = i + 32; } return ERROR_OK; } /* flash bank str9x <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(str9xpec_flash_bank_command) { struct str9xpec_flash_controller *str9xpec_info; struct arm *arm = NULL; struct arm7_9_common *arm7_9 = NULL; struct arm_jtag *jtag_info = NULL; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; str9xpec_info = malloc(sizeof(struct str9xpec_flash_controller)); bank->driver_priv = str9xpec_info; /* REVISIT verify that the jtag position of flash controller is * right after *THIS* core, which must be a STR9xx core ... */ arm = bank->target->arch_info; arm7_9 = arm->arch_info; jtag_info = &arm7_9->jtag_info; /* The core is the next tap after the flash controller in the chain */ str9xpec_info->tap = jtag_tap_by_position(jtag_info->tap->abs_chain_position - 1); str9xpec_info->isc_enable = 0; str9xpec_build_block_list(bank); /* clear option byte register */ buf_set_u32(str9xpec_info->options, 0, 64, 0); return ERROR_OK; } static int str9xpec_blank_check(struct flash_bank *bank, unsigned int first, unsigned int last) { struct scan_field field; uint8_t status; struct jtag_tap *tap; uint8_t *buffer = NULL; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; if (!str9xpec_info->isc_enable) str9xpec_isc_enable(bank); if (!str9xpec_info->isc_enable) return ERROR_FLASH_OPERATION_FAILED; buffer = calloc(DIV_ROUND_UP(64, 8), 1); LOG_DEBUG("blank check: first_bank: %u, last_bank: %u", first, last); for (unsigned int i = first; i <= last; i++) buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1); /* execute ISC_BLANK_CHECK command */ str9xpec_set_instr(tap, ISC_BLANK_CHECK, TAP_IRPAUSE); field.num_bits = 64; field.out_value = buffer; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_sleep(40000); /* read blank check result */ field.num_bits = 64; field.out_value = NULL; field.in_value = buffer; jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE); jtag_execute_queue(); status = str9xpec_isc_status(tap); for (unsigned int i = first; i <= last; i++) { if (buf_get_u32(buffer, str9xpec_info->sector_bits[i], 1)) bank->sectors[i].is_erased = 0; else bank->sectors[i].is_erased = 1; } free(buffer); str9xpec_isc_disable(bank); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } static int str9xpec_protect_check(struct flash_bank *bank) { uint8_t status; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; status = str9xpec_read_config(bank); for (unsigned int i = 0; i < bank->num_sectors; i++) { if (buf_get_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1)) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; } if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } static int str9xpec_erase_area(struct flash_bank *bank, unsigned int first, unsigned int last) { struct scan_field field; uint8_t status; struct jtag_tap *tap; uint8_t *buffer = NULL; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; if (!str9xpec_info->isc_enable) str9xpec_isc_enable(bank); if (!str9xpec_info->isc_enable) return ISC_STATUS_ERROR; buffer = calloc(DIV_ROUND_UP(64, 8), 1); LOG_DEBUG("erase: first_bank: %u, last_bank: %u", first, last); /* last bank: 0xFF signals a full erase (unlock complete device) */ /* last bank: 0xFE signals a option byte erase */ if (last == 0xFF) { for (unsigned int i = 0; i < 64; i++) buf_set_u32(buffer, i, 1, 1); } else if (last == 0xFE) buf_set_u32(buffer, 49, 1, 1); else { for (unsigned int i = first; i <= last; i++) buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1); } LOG_DEBUG("ISC_ERASE"); /* execute ISC_ERASE command */ str9xpec_set_instr(tap, ISC_ERASE, TAP_IRPAUSE); field.num_bits = 64; field.out_value = buffer; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); jtag_add_sleep(10); /* wait for erase completion */ while (!((status = str9xpec_isc_status(tap)) & ISC_STATUS_BUSY)) alive_sleep(1); free(buffer); str9xpec_isc_disable(bank); return status; } static int str9xpec_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int status; status = str9xpec_erase_area(bank, first, last); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } static int str9xpec_lock_device(struct flash_bank *bank) { struct scan_field field; uint8_t status; struct jtag_tap *tap; struct str9xpec_flash_controller *str9xpec_info = NULL; str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; if (!str9xpec_info->isc_enable) str9xpec_isc_enable(bank); if (!str9xpec_info->isc_enable) return ISC_STATUS_ERROR; /* set security address */ str9xpec_set_address(bank, 0x80); /* execute ISC_PROGRAM command */ str9xpec_set_instr(tap, ISC_PROGRAM_SECURITY, TAP_IDLE); str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE); do { field.num_bits = 8; field.out_value = NULL; field.in_value = &status; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); } while (!(status & ISC_STATUS_BUSY)); str9xpec_isc_disable(bank); return status; } static int str9xpec_unlock_device(struct flash_bank *bank) { uint8_t status; status = str9xpec_erase_area(bank, 0, 255); return status; } static int str9xpec_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { uint8_t status; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; status = str9xpec_read_config(bank); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; LOG_DEBUG("protect: first_bank: %u, last_bank: %u", first, last); /* last bank: 0xFF signals a full device protect */ if (last == 0xFF) { if (set) status = str9xpec_lock_device(bank); else { /* perform full erase to unlock device */ status = str9xpec_unlock_device(bank); } } else { for (unsigned int i = first; i <= last; i++) { if (set) buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 1); else buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 0); } status = str9xpec_write_options(bank); } if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } static int str9xpec_set_address(struct flash_bank *bank, uint8_t sector) { struct jtag_tap *tap; struct scan_field field; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; /* set flash controller address */ str9xpec_set_instr(tap, ISC_ADDRESS_SHIFT, TAP_IRPAUSE); field.num_bits = 8; field.out_value = §or; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE); return ERROR_OK; } static int str9xpec_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; uint32_t dwords_remaining = (count / 8); uint32_t bytes_remaining = (count & 0x00000007); uint32_t bytes_written = 0; uint8_t status; uint32_t check_address = offset; struct jtag_tap *tap; struct scan_field field; uint8_t *scanbuf; unsigned int first_sector = 0; unsigned int last_sector = 0; tap = str9xpec_info->tap; if (!str9xpec_info->isc_enable) str9xpec_isc_enable(bank); if (!str9xpec_info->isc_enable) return ERROR_FLASH_OPERATION_FAILED; if (offset & 0x7) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } for (unsigned int i = 0; i < bank->num_sectors; i++) { uint32_t sec_start = bank->sectors[i].offset; uint32_t sec_end = sec_start + bank->sectors[i].size; /* check if destination falls within the current sector */ if ((check_address >= sec_start) && (check_address < sec_end)) { /* check if destination ends in the current sector */ if (offset + count < sec_end) check_address = offset + count; else check_address = sec_end; } if ((offset >= sec_start) && (offset < sec_end)) first_sector = i; if ((offset + count >= sec_start) && (offset + count < sec_end)) last_sector = i; } if (check_address != offset + count) return ERROR_FLASH_DST_OUT_OF_BANK; LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector); scanbuf = calloc(DIV_ROUND_UP(64, 8), 1); LOG_DEBUG("ISC_PROGRAM"); for (unsigned int i = first_sector; i <= last_sector; i++) { str9xpec_set_address(bank, str9xpec_info->sector_bits[i]); dwords_remaining = dwords_remaining < (bank->sectors[i].size/8) ? dwords_remaining : (bank->sectors[i].size/8); while (dwords_remaining > 0) { str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE); field.num_bits = 64; field.out_value = (buffer + bytes_written); field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); /* small delay before polling */ jtag_add_sleep(50); str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE); do { field.num_bits = 8; field.out_value = NULL; field.in_value = scanbuf; jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE); jtag_execute_queue(); status = buf_get_u32(scanbuf, 0, 8); } while (!(status & ISC_STATUS_BUSY)); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; /* if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL) return ERROR_FLASH_OPERATION_FAILED; */ dwords_remaining--; bytes_written += 8; } } if (bytes_remaining) { uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; /* copy the last remaining bytes into the write buffer */ memcpy(last_dword, buffer+bytes_written, bytes_remaining); str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE); field.num_bits = 64; field.out_value = last_dword; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); /* small delay before polling */ jtag_add_sleep(50); str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE); do { field.num_bits = 8; field.out_value = NULL; field.in_value = scanbuf; jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE); jtag_execute_queue(); status = buf_get_u32(scanbuf, 0, 8); } while (!(status & ISC_STATUS_BUSY)); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; /* if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL) return ERROR_FLASH_OPERATION_FAILED; */ } free(scanbuf); str9xpec_isc_disable(bank); return ERROR_OK; } static int str9xpec_probe(struct flash_bank *bank) { return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_part_id_command) { struct scan_field field; uint8_t *buffer = NULL; struct jtag_tap *tap; uint32_t idcode; struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; buffer = calloc(DIV_ROUND_UP(32, 8), 1); str9xpec_set_instr(tap, ISC_IDCODE, TAP_IRPAUSE); field.num_bits = 32; field.out_value = NULL; field.in_value = buffer; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); idcode = buf_get_u32(buffer, 0, 32); command_print(CMD, "str9xpec part id: 0x%8.8" PRIx32 "", idcode); free(buffer); return ERROR_OK; } static int str9xpec_erase_check(struct flash_bank *bank) { return str9xpec_blank_check(bank, 0, bank->num_sectors - 1); } COMMAND_HANDLER(str9xpec_handle_flash_options_read_command) { uint8_t status; struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; status = str9xpec_read_config(bank); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; /* boot bank */ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1)) command_print(CMD, "CS Map: bank1"); else command_print(CMD, "CS Map: bank0"); /* OTP lock */ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_OTPBIT, 1)) command_print(CMD, "OTP Lock: OTP Locked"); else command_print(CMD, "OTP Lock: OTP Unlocked"); /* LVD Threshold */ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1)) command_print(CMD, "LVD Threshold: 2.7v"); else command_print(CMD, "LVD Threshold: 2.4v"); /* LVD reset warning */ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1)) command_print(CMD, "LVD Reset Warning: VDD or VDDQ Inputs"); else command_print(CMD, "LVD Reset Warning: VDD Input Only"); /* LVD reset select */ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1)) command_print(CMD, "LVD Reset Selection: VDD or VDDQ Inputs"); else command_print(CMD, "LVD Reset Selection: VDD Input Only"); return ERROR_OK; } static int str9xpec_write_options(struct flash_bank *bank) { struct scan_field field; uint8_t status; struct jtag_tap *tap; struct str9xpec_flash_controller *str9xpec_info = NULL; str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; /* erase config options first */ status = str9xpec_erase_area(bank, 0xFE, 0xFE); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return status; if (!str9xpec_info->isc_enable) str9xpec_isc_enable(bank); if (!str9xpec_info->isc_enable) return ISC_STATUS_ERROR; /* according to data 64th bit has to be set */ buf_set_u32(str9xpec_info->options, 63, 1, 1); /* set option byte address */ str9xpec_set_address(bank, 0x50); /* execute ISC_PROGRAM command */ str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE); field.num_bits = 64; field.out_value = str9xpec_info->options; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); /* small delay before polling */ jtag_add_sleep(50); str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE); do { field.num_bits = 8; field.out_value = NULL; field.in_value = &status; jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE); jtag_execute_queue(); } while (!(status & ISC_STATUS_BUSY)); str9xpec_isc_disable(bank); return status; } COMMAND_HANDLER(str9xpec_handle_flash_options_write_command) { uint8_t status; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; status = str9xpec_write_options(bank); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; command_print(CMD, "str9xpec write options complete.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect."); return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_options_cmap_command) { struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; if (strcmp(CMD_ARGV[1], "bank1") == 0) buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 1); else buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 0); return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_options_lvdthd_command) { struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; if (strcmp(CMD_ARGV[1], "2.7v") == 0) buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 1); else buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 0); return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_options_lvdsel_command) { struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; if (strcmp(CMD_ARGV[1], "vdd_vddq") == 0) buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 1); else buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 0); return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_options_lvdwarn_command) { struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; if (strcmp(CMD_ARGV[1], "vdd_vddq") == 0) buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 1); else buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 0); return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_lock_command) { uint8_t status; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; status = str9xpec_lock_device(bank); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_unlock_command) { uint8_t status; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; status = str9xpec_unlock_device(bank); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; command_print(CMD, "str9xpec unlocked.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect."); return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_enable_turbo_command) { struct jtag_tap *tap0; struct jtag_tap *tap1; struct jtag_tap *tap2; struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; /* remove arm core from chain - enter turbo mode */ tap0 = str9xpec_info->tap; if (!tap0) { /* things are *WRONG* */ command_print(CMD, "**STR9FLASH** (tap0) invalid chain?"); return ERROR_FAIL; } tap1 = tap0->next_tap; if (!tap1) { /* things are *WRONG* */ command_print(CMD, "**STR9FLASH** (tap1) invalid chain?"); return ERROR_FAIL; } tap2 = tap1->next_tap; if (!tap2) { /* things are *WRONG* */ command_print(CMD, "**STR9FLASH** (tap2) invalid chain?"); return ERROR_FAIL; } /* enable turbo mode - TURBO-PROG-ENABLE */ str9xpec_set_instr(tap2, 0xD, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* modify scan chain - str9 core has been removed */ tap1->enabled = 0; return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_disable_turbo_command) { struct jtag_tap *tap; struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; if (!tap) return ERROR_FAIL; /* exit turbo mode via RESET */ str9xpec_set_instr(tap, ISC_NOOP, TAP_IDLE); jtag_add_tlr(); jtag_execute_queue(); /* restore previous scan chain */ if (tap->next_tap) tap->next_tap->enabled = 1; return ERROR_OK; } static const struct command_registration str9xpec_config_command_handlers[] = { { .name = "enable_turbo", .usage = "<bank>", .handler = str9xpec_handle_flash_enable_turbo_command, .mode = COMMAND_EXEC, .help = "enable str9xpec turbo mode", }, { .name = "disable_turbo", .usage = "<bank>", .handler = str9xpec_handle_flash_disable_turbo_command, .mode = COMMAND_EXEC, .help = "disable str9xpec turbo mode", }, { .name = "options_cmap", .usage = "<bank> <bank0 | bank1>", .handler = str9xpec_handle_flash_options_cmap_command, .mode = COMMAND_EXEC, .help = "configure str9xpec boot sector", }, { .name = "options_lvdthd", .usage = "<bank> <2.4v | 2.7v>", .handler = str9xpec_handle_flash_options_lvdthd_command, .mode = COMMAND_EXEC, .help = "configure str9xpec lvd threshold", }, { .name = "options_lvdsel", .usage = "<bank> <vdd | vdd_vddq>", .handler = str9xpec_handle_flash_options_lvdsel_command, .mode = COMMAND_EXEC, .help = "configure str9xpec lvd selection", }, { .name = "options_lvdwarn", .usage = "<bank> <vdd | vdd_vddq>", .handler = str9xpec_handle_flash_options_lvdwarn_command, .mode = COMMAND_EXEC, .help = "configure str9xpec lvd warning", }, { .name = "options_read", .usage = "<bank>", .handler = str9xpec_handle_flash_options_read_command, .mode = COMMAND_EXEC, .help = "read str9xpec options", }, { .name = "options_write", .usage = "<bank>", .handler = str9xpec_handle_flash_options_write_command, .mode = COMMAND_EXEC, .help = "write str9xpec options", }, { .name = "lock", .usage = "<bank>", .handler = str9xpec_handle_flash_lock_command, .mode = COMMAND_EXEC, .help = "lock str9xpec device", }, { .name = "unlock", .usage = "<bank>", .handler = str9xpec_handle_flash_unlock_command, .mode = COMMAND_EXEC, .help = "unlock str9xpec device", }, { .name = "part_id", .usage = "<bank>", .handler = str9xpec_handle_part_id_command, .mode = COMMAND_EXEC, .help = "print part id of str9xpec flash bank", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration str9xpec_command_handlers[] = { { .name = "str9xpec", .mode = COMMAND_ANY, .help = "str9xpec flash command group", .usage = "", .chain = str9xpec_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver str9xpec_flash = { .name = "str9xpec", .commands = str9xpec_command_handlers, .flash_bank_command = str9xpec_flash_bank_command, .erase = str9xpec_erase, .protect = str9xpec_protect, .write = str9xpec_write, .read = default_flash_read, .probe = str9xpec_probe, .auto_probe = str9xpec_probe, .erase_check = str9xpec_erase_check, .protect_check = str9xpec_protect_check, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/swm050.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2019 Icenowy Zheng <icenowy@aosc.io> * * Copyright (C) 2019 Caleb Szalacinski <contact@skiboy.net> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <target/image.h> #define SWM050_DELAY 100 #define SWM050_FLASH_PAGE_SIZE 0x200 #define SWM050_FLASH_PAGES 16 #define SWM050_CPU_ID 0xE000ED00 #define SWM050_CPU_ID_VAL 0x410CC200 #define SWM050_FLASH_REG1 0x1F000000 #define SWM050_FLASH_REG2 0x1F000038 #define SWM050_FLASH_KEY 0xAAAAAAAA #define SWM050_SYSCTL_CFG_0 0x400F0000 #define SWM050_SYSCTL_DBLF 0x400F0008 static int swm050_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Perform erase */ retval = target_write_u32(target, SWM050_FLASH_REG1, 0x4); if (retval != ERROR_OK) return retval; for (unsigned int curr_page = first; curr_page <= last; curr_page++) { uint32_t curr_addr = bank->base + (SWM050_FLASH_PAGE_SIZE * curr_page); /* Perform write */ retval = target_write_u32(target, curr_addr, SWM050_FLASH_KEY); if (retval != ERROR_OK) return retval; alive_sleep(SWM050_DELAY); } /* Close flash interface */ retval = target_write_u32(target, SWM050_FLASH_REG1, 0x0); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int swm050_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); retval = ERROR_TARGET_NOT_HALTED; return retval; } /* Perform write */ retval = target_write_u32(target, SWM050_FLASH_REG1, 0x1); if (retval != ERROR_OK) return retval; retval = target_write_memory(target, bank->base + offset, 4, count/4, buffer); if (retval != ERROR_OK) return retval; /* Close flash interface */ retval = target_write_u32(target, SWM050_FLASH_REG1, 0x0); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int swm050_probe(struct flash_bank *bank) { return ERROR_OK; } static int swm050_mass_erase(struct flash_bank *bank) { struct target *target = bank->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Perform mass erase */ retval = target_write_u32(target, SWM050_FLASH_REG1, 0x6); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, SWM050_FLASH_REG2, 0x1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, 0x0, SWM050_FLASH_KEY); if (retval != ERROR_OK) return retval; alive_sleep(SWM050_DELAY); /* Close flash interface */ retval = target_write_u32(target, SWM050_FLASH_REG1, 0x0); if (retval != ERROR_OK) return retval; return ERROR_OK; } COMMAND_HANDLER(swm050_handle_mass_erase_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; retval = swm050_mass_erase(bank); if (retval == ERROR_OK) command_print(CMD, "swm050 mass erase complete"); else command_print(CMD, "swm050 mass erase failed"); return retval; } FLASH_BANK_COMMAND_HANDLER(swm050_flash_bank_command) { free(bank->sectors); bank->write_start_alignment = 4; bank->write_end_alignment = 4; bank->size = SWM050_FLASH_PAGE_SIZE * SWM050_FLASH_PAGES; bank->num_sectors = SWM050_FLASH_PAGES; bank->sectors = alloc_block_array(0, SWM050_FLASH_PAGE_SIZE, SWM050_FLASH_PAGES); if (!bank->sectors) return ERROR_FAIL; for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = 0; return ERROR_OK; } static const struct command_registration swm050_exec_command_handlers[] = { { .name = "mass_erase", .handler = swm050_handle_mass_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Erase entire flash device.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration swm050_command_handlers[] = { { .name = "swm050", .mode = COMMAND_ANY, .help = "swm050 flash command group", .usage = "", .chain = swm050_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver swm050_flash = { .name = "swm050", .commands = swm050_command_handlers, .flash_bank_command = swm050_flash_bank_command, .erase = swm050_erase, .write = swm050_write, .read = default_flash_read, .probe = swm050_probe, .auto_probe = swm050_probe, .erase_check = default_flash_blank_check, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/tcl.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * Copyright (C) 2017-2018 Tomas Vanek <vanekt@fbl.cz> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/time_support.h> #include <target/image.h> /** * @file * Implements Tcl commands used to access NOR flash facilities. */ COMMAND_HELPER(flash_command_get_bank_probe_optional, unsigned int name_index, struct flash_bank **bank, bool do_probe) { const char *name = CMD_ARGV[name_index]; int retval; if (do_probe) { retval = get_flash_bank_by_name(name, bank); } else { *bank = get_flash_bank_by_name_noprobe(name); retval = ERROR_OK; } if (retval != ERROR_OK) return retval; if (*bank) return ERROR_OK; unsigned bank_num; COMMAND_PARSE_NUMBER(uint, name, bank_num); if (do_probe) { return get_flash_bank_by_num(bank_num, bank); } else { *bank = get_flash_bank_by_num_noprobe(bank_num); retval = (bank) ? ERROR_OK : ERROR_FAIL; return retval; } } COMMAND_HELPER(flash_command_get_bank, unsigned name_index, struct flash_bank **bank) { return CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional, name_index, bank, true); } COMMAND_HANDLER(handle_flash_info_command) { struct flash_bank *p; int j = 0; int retval; bool show_sectors = false; bool prot_block_available; if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 2) { if (strcmp("sectors", CMD_ARGV[1]) == 0) show_sectors = true; else return ERROR_COMMAND_SYNTAX_ERROR; } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (retval != ERROR_OK) return retval; if (p) { int num_blocks; struct flash_sector *block_array; /* attempt auto probe */ retval = p->driver->auto_probe(p); if (retval != ERROR_OK) return retval; /* If the driver does not implement protection, we show the default * state of is_protected array - usually protection state unknown */ if (!p->driver->protect_check) { retval = ERROR_FLASH_OPER_UNSUPPORTED; } else { /* We must query the hardware to avoid printing stale information! */ retval = p->driver->protect_check(p); if (retval != ERROR_OK && retval != ERROR_FLASH_OPER_UNSUPPORTED) return retval; } if (retval == ERROR_FLASH_OPER_UNSUPPORTED) LOG_INFO("Flash protection check is not implemented."); command_print(CMD, "#%u : %s at " TARGET_ADDR_FMT ", size 0x%8.8" PRIx32 ", buswidth %u, chipwidth %u", p->bank_number, p->driver->name, p->base, p->size, p->bus_width, p->chip_width); prot_block_available = p->num_prot_blocks && p->prot_blocks; if (!show_sectors && prot_block_available) { block_array = p->prot_blocks; num_blocks = p->num_prot_blocks; } else { block_array = p->sectors; num_blocks = p->num_sectors; } for (j = 0; j < num_blocks; j++) { char *protect_state = ""; if (block_array[j].is_protected == 0) protect_state = "not protected"; else if (block_array[j].is_protected == 1) protect_state = "protected"; else if (!show_sectors || !prot_block_available) protect_state = "protection state unknown"; command_print(CMD, "\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIu32 "kB) %s", j, block_array[j].offset, block_array[j].size, block_array[j].size >> 10, protect_state); } if (p->driver->info) { /* Let the flash driver print extra custom info */ retval = p->driver->info(p, CMD); command_print_sameline(CMD, "\n"); if (retval != ERROR_OK) LOG_ERROR("error retrieving flash info"); } } return retval; } COMMAND_HANDLER(handle_flash_probe_command) { struct flash_bank *p; int retval; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; retval = CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional, 0, &p, false); if (retval != ERROR_OK) return retval; if (p) { retval = p->driver->probe(p); if (retval == ERROR_OK) command_print(CMD, "flash '%s' found at " TARGET_ADDR_FMT, p->driver->name, p->base); } else { command_print(CMD, "flash bank '#%s' is out of bounds", CMD_ARGV[0]); retval = ERROR_FAIL; } return retval; } COMMAND_HANDLER(handle_flash_erase_check_command) { bool blank = true; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *p; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (retval != ERROR_OK) return retval; retval = p->driver->erase_check(p); if (retval == ERROR_OK) command_print(CMD, "successfully checked erase state"); else { command_print(CMD, "unknown error when checking erase state of flash bank #%s at " TARGET_ADDR_FMT, CMD_ARGV[0], p->base); } for (unsigned int j = 0; j < p->num_sectors; j++) { char *erase_state; if (p->sectors[j].is_erased == 0) erase_state = "not erased"; else if (p->sectors[j].is_erased == 1) continue; else erase_state = "erase state unknown"; blank = false; command_print(CMD, "\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIu32 "kB) %s", j, p->sectors[j].offset, p->sectors[j].size, p->sectors[j].size >> 10, erase_state); } if (blank) command_print(CMD, "\tBank is erased"); return retval; } COMMAND_HANDLER(handle_flash_erase_address_command) { struct flash_bank *p; int retval = ERROR_OK; target_addr_t address; uint32_t length; bool do_pad = false; bool do_unlock = false; struct target *target = get_current_target(CMD_CTX); while (CMD_ARGC >= 3) { /* Optionally pad out the address range to block/sector * boundaries. We can't know if there's data in that part * of the flash; only do padding if we're told to. */ if (strcmp("pad", CMD_ARGV[0]) == 0) do_pad = true; else if (strcmp("unlock", CMD_ARGV[0]) == 0) do_unlock = true; else return ERROR_COMMAND_SYNTAX_ERROR; CMD_ARGC--; CMD_ARGV++; } if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); if (length <= 0) { command_print(CMD, "Length must be >0"); return ERROR_COMMAND_SYNTAX_ERROR; } retval = get_flash_bank_by_addr(target, address, true, &p); if (retval != ERROR_OK) return retval; /* We can't know if we did a resume + halt, in which case we no longer know the erased state **/ flash_set_dirty(); struct duration bench; duration_start(&bench); if (do_unlock) retval = flash_unlock_address_range(target, address, length); if (retval == ERROR_OK) retval = flash_erase_address_range(target, do_pad, address, length); if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "erased address " TARGET_ADDR_FMT " (length %" PRIu32 ")" " in %fs (%0.3f KiB/s)", address, length, duration_elapsed(&bench), duration_kbps(&bench, length)); } return retval; } COMMAND_HANDLER(handle_flash_erase_command) { if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t first; uint32_t last; struct flash_bank *p; int retval; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (retval != ERROR_OK) return retval; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], first); if (strcmp(CMD_ARGV[2], "last") == 0) last = p->num_sectors - 1; else COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last); if (!(first <= last)) { command_print(CMD, "ERROR: " "first sector must be <= last"); return ERROR_FAIL; } if (!(last <= (p->num_sectors - 1))) { command_print(CMD, "ERROR: " "last sector must be <= %u", p->num_sectors - 1); return ERROR_FAIL; } struct duration bench; duration_start(&bench); retval = flash_driver_erase(p, first, last); if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "erased sectors %" PRIu32 " " "through %" PRIu32 " on flash bank %u " "in %fs", first, last, p->bank_number, duration_elapsed(&bench)); } return retval; } COMMAND_HANDLER(handle_flash_protect_command) { if (CMD_ARGC != 4) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t first; uint32_t last; struct flash_bank *p; int retval; int num_blocks; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (retval != ERROR_OK) return retval; if (p->num_prot_blocks) num_blocks = p->num_prot_blocks; else num_blocks = p->num_sectors; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], first); if (strcmp(CMD_ARGV[2], "last") == 0) last = num_blocks - 1; else COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last); bool set; COMMAND_PARSE_ON_OFF(CMD_ARGV[3], set); if (!(first <= last)) { command_print(CMD, "ERROR: " "first %s must be <= last", (p->num_prot_blocks) ? "block" : "sector"); return ERROR_FAIL; } if (!(last <= (uint32_t)(num_blocks - 1))) { command_print(CMD, "ERROR: " "last %s must be <= %d", (p->num_prot_blocks) ? "block" : "sector", num_blocks - 1); return ERROR_FAIL; } retval = flash_driver_protect(p, set, first, last); if (retval == ERROR_OK) { command_print(CMD, "%s protection for %s %" PRIu32 " through %" PRIu32 " on flash bank %d", (set) ? "set" : "cleared", (p->num_prot_blocks) ? "blocks" : "sectors", first, last, p->bank_number); } return retval; } COMMAND_HANDLER(handle_flash_write_image_command) { struct target *target = get_current_target(CMD_CTX); struct image image; uint32_t written; int retval; /* flash auto-erase is disabled by default*/ int auto_erase = 0; bool auto_unlock = false; while (CMD_ARGC) { if (strcmp(CMD_ARGV[0], "erase") == 0) { auto_erase = 1; CMD_ARGV++; CMD_ARGC--; command_print(CMD, "auto erase enabled"); } else if (strcmp(CMD_ARGV[0], "unlock") == 0) { auto_unlock = true; CMD_ARGV++; CMD_ARGC--; command_print(CMD, "auto unlock enabled"); } else break; } if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (!target) { LOG_ERROR("no target selected"); return ERROR_FAIL; } struct duration bench; duration_start(&bench); if (CMD_ARGC >= 2) { image.base_address_set = true; COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], image.base_address); } else { image.base_address_set = false; image.base_address = 0x0; } image.start_address_set = false; retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL); if (retval != ERROR_OK) return retval; retval = flash_write_unlock_verify(target, &image, &written, auto_erase, auto_unlock, true, false); if (retval != ERROR_OK) { image_close(&image); return retval; } if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "wrote %" PRIu32 " bytes from file %s " "in %fs (%0.3f KiB/s)", written, CMD_ARGV[0], duration_elapsed(&bench), duration_kbps(&bench, written)); } image_close(&image); return retval; } COMMAND_HANDLER(handle_flash_verify_image_command) { struct target *target = get_current_target(CMD_CTX); struct image image; uint32_t verified; int retval; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (!target) { LOG_ERROR("no target selected"); return ERROR_FAIL; } struct duration bench; duration_start(&bench); if (CMD_ARGC >= 2) { image.base_address_set = 1; COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], image.base_address); } else { image.base_address_set = 0; image.base_address = 0x0; } image.start_address_set = 0; retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL); if (retval != ERROR_OK) return retval; retval = flash_write_unlock_verify(target, &image, &verified, false, false, false, true); if (retval != ERROR_OK) { image_close(&image); return retval; } if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "verified %" PRIu32 " bytes from file %s " "in %fs (%0.3f KiB/s)", verified, CMD_ARGV[0], duration_elapsed(&bench), duration_kbps(&bench, verified)); } image_close(&image); return retval; } COMMAND_HANDLER(handle_flash_fill_command) { target_addr_t address; uint64_t pattern; uint32_t count; struct target *target = get_current_target(CMD_CTX); unsigned i; uint32_t wordsize; int retval; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], pattern); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count); struct flash_bank *bank; retval = get_flash_bank_by_addr(target, address, true, &bank); if (retval != ERROR_OK) return retval; switch (CMD_NAME[4]) { case 'd': wordsize = 8; break; case 'w': wordsize = 4; break; case 'h': wordsize = 2; break; case 'b': wordsize = 1; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } if ((wordsize < sizeof(pattern)) && (pattern >> (8 * wordsize) != 0)) { command_print(CMD, "Fill pattern 0x%" PRIx64 " does not fit within %" PRIu32 "-byte word", pattern, wordsize); return ERROR_FAIL; } if (count == 0) return ERROR_OK; if (address + count * wordsize > bank->base + bank->size) { LOG_ERROR("Cannot cross flash bank borders"); return ERROR_FAIL; } uint32_t size_bytes = count * wordsize; target_addr_t aligned_start = flash_write_align_start(bank, address); target_addr_t end_addr = address + size_bytes - 1; target_addr_t aligned_end = flash_write_align_end(bank, end_addr); uint32_t aligned_size = aligned_end + 1 - aligned_start; uint32_t padding_at_start = address - aligned_start; uint32_t padding_at_end = aligned_end - end_addr; uint8_t *buffer = malloc(aligned_size); if (!buffer) return ERROR_FAIL; if (padding_at_start) { memset(buffer, bank->default_padded_value, padding_at_start); LOG_WARNING("Start address " TARGET_ADDR_FMT " breaks the required alignment of flash bank %s", address, bank->name); LOG_WARNING("Padding %" PRIu32 " bytes from " TARGET_ADDR_FMT, padding_at_start, aligned_start); } uint8_t *ptr = buffer + padding_at_start; switch (wordsize) { case 8: for (i = 0; i < count; i++, ptr += wordsize) target_buffer_set_u64(target, ptr, pattern); break; case 4: for (i = 0; i < count; i++, ptr += wordsize) target_buffer_set_u32(target, ptr, pattern); break; case 2: for (i = 0; i < count; i++, ptr += wordsize) target_buffer_set_u16(target, ptr, pattern); break; case 1: memset(ptr, pattern, count); ptr += count; break; default: LOG_ERROR("BUG: can't happen"); exit(-1); } if (padding_at_end) { memset(ptr, bank->default_padded_value, padding_at_end); LOG_INFO("Padding at " TARGET_ADDR_FMT " with %" PRIu32 " bytes (bank write end alignment)", end_addr + 1, padding_at_end); } struct duration bench; duration_start(&bench); retval = flash_driver_write(bank, buffer, aligned_start - bank->base, aligned_size); if (retval != ERROR_OK) goto done; retval = flash_driver_read(bank, buffer, address - bank->base, size_bytes); if (retval != ERROR_OK) goto done; for (i = 0, ptr = buffer; i < count; i++) { uint64_t readback = 0; switch (wordsize) { case 8: readback = target_buffer_get_u64(target, ptr); break; case 4: readback = target_buffer_get_u32(target, ptr); break; case 2: readback = target_buffer_get_u16(target, ptr); break; case 1: readback = *ptr; break; } if (readback != pattern) { LOG_ERROR( "Verification error address " TARGET_ADDR_FMT ", read back 0x%02" PRIx64 ", expected 0x%02" PRIx64, address + i * wordsize, readback, pattern); retval = ERROR_FAIL; goto done; } ptr += wordsize; } if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "wrote %" PRIu32 " bytes to " TARGET_ADDR_FMT " in %fs (%0.3f KiB/s)", size_bytes, address, duration_elapsed(&bench), duration_kbps(&bench, size_bytes)); } done: free(buffer); return retval; } COMMAND_HANDLER(handle_flash_md_command) { int retval; if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; target_addr_t address; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); uint32_t count = 1; if (CMD_ARGC == 2) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], count); unsigned int wordsize; switch (CMD_NAME[2]) { case 'w': wordsize = 4; break; case 'h': wordsize = 2; break; case 'b': wordsize = 1; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } if (count == 0) return ERROR_OK; struct target *target = get_current_target(CMD_CTX); struct flash_bank *bank; retval = get_flash_bank_by_addr(target, address, true, &bank); if (retval != ERROR_OK) return retval; uint32_t offset = address - bank->base; uint32_t sizebytes = count * wordsize; if (offset + sizebytes > bank->size) { command_print(CMD, "Cannot cross flash bank borders"); return ERROR_FAIL; } uint8_t *buffer = calloc(count, wordsize); if (!buffer) { command_print(CMD, "No memory for flash read buffer"); return ERROR_FAIL; } retval = flash_driver_read(bank, buffer, offset, sizebytes); if (retval == ERROR_OK) target_handle_md_output(CMD, target, address, wordsize, count, buffer); free(buffer); return retval; } COMMAND_HANDLER(handle_flash_write_bank_command) { uint32_t offset; uint8_t *buffer; size_t length; struct fileio *fileio; if (CMD_ARGC < 2 || CMD_ARGC > 3) return ERROR_COMMAND_SYNTAX_ERROR; struct duration bench; duration_start(&bench); struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; offset = 0; if (CMD_ARGC > 2) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset); if (offset > bank->size) { LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank", offset); return ERROR_COMMAND_ARGUMENT_INVALID; } if (fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) return ERROR_FAIL; size_t filesize; retval = fileio_size(fileio, &filesize); if (retval != ERROR_OK) { fileio_close(fileio); return retval; } length = MIN(filesize, bank->size - offset); if (!length) { LOG_INFO("Nothing to write to flash bank"); fileio_close(fileio); return ERROR_OK; } if (length != filesize) LOG_INFO("File content exceeds flash bank size. Only writing the " "first %zu bytes of the file", length); target_addr_t start_addr = bank->base + offset; target_addr_t aligned_start = flash_write_align_start(bank, start_addr); target_addr_t end_addr = start_addr + length - 1; target_addr_t aligned_end = flash_write_align_end(bank, end_addr); uint32_t aligned_size = aligned_end + 1 - aligned_start; uint32_t padding_at_start = start_addr - aligned_start; uint32_t padding_at_end = aligned_end - end_addr; buffer = malloc(aligned_size); if (!buffer) { fileio_close(fileio); LOG_ERROR("Out of memory"); return ERROR_FAIL; } if (padding_at_start) { memset(buffer, bank->default_padded_value, padding_at_start); LOG_WARNING("Start offset 0x%08" PRIx32 " breaks the required alignment of flash bank %s", offset, bank->name); LOG_WARNING("Padding %" PRIu32 " bytes from " TARGET_ADDR_FMT, padding_at_start, aligned_start); } uint8_t *ptr = buffer + padding_at_start; size_t buf_cnt; if (fileio_read(fileio, length, ptr, &buf_cnt) != ERROR_OK) { free(buffer); fileio_close(fileio); return ERROR_FAIL; } if (buf_cnt != length) { LOG_ERROR("Short read"); free(buffer); fileio_close(fileio); return ERROR_FAIL; } ptr += length; if (padding_at_end) { memset(ptr, bank->default_padded_value, padding_at_end); LOG_INFO("Padding at " TARGET_ADDR_FMT " with %" PRIu32 " bytes (bank write end alignment)", end_addr + 1, padding_at_end); } retval = flash_driver_write(bank, buffer, aligned_start - bank->base, aligned_size); free(buffer); if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "wrote %zu bytes from file %s to flash bank %u" " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", length, CMD_ARGV[1], bank->bank_number, offset, duration_elapsed(&bench), duration_kbps(&bench, length)); } fileio_close(fileio); return retval; } COMMAND_HANDLER(handle_flash_read_bank_command) { uint32_t offset; uint8_t *buffer; struct fileio *fileio; uint32_t length; size_t written; if (CMD_ARGC < 2 || CMD_ARGC > 4) return ERROR_COMMAND_SYNTAX_ERROR; struct duration bench; duration_start(&bench); struct flash_bank *p; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (retval != ERROR_OK) return retval; offset = 0; if (CMD_ARGC > 2) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset); if (offset > p->size) { LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank", offset); return ERROR_COMMAND_ARGUMENT_INVALID; } length = p->size - offset; if (CMD_ARGC > 3) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], length); if (offset + length > p->size) { LOG_ERROR("Length of %" PRIu32 " bytes with offset 0x%8.8" PRIx32 " is out of range of the flash bank", length, offset); return ERROR_COMMAND_ARGUMENT_INVALID; } buffer = malloc(length); if (!buffer) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } retval = flash_driver_read(p, buffer, offset, length); if (retval != ERROR_OK) { LOG_ERROR("Read error"); free(buffer); return retval; } retval = fileio_open(&fileio, CMD_ARGV[1], FILEIO_WRITE, FILEIO_BINARY); if (retval != ERROR_OK) { LOG_ERROR("Could not open file"); free(buffer); return retval; } retval = fileio_write(fileio, length, buffer, &written); fileio_close(fileio); free(buffer); if (retval != ERROR_OK) { LOG_ERROR("Could not write file"); return ERROR_FAIL; } if (duration_measure(&bench) == ERROR_OK) command_print(CMD, "wrote %zd bytes to file %s from flash bank %u" " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", written, CMD_ARGV[1], p->bank_number, offset, duration_elapsed(&bench), duration_kbps(&bench, written)); return retval; } COMMAND_HANDLER(handle_flash_verify_bank_command) { uint32_t offset; uint8_t *buffer_file, *buffer_flash; struct fileio *fileio; size_t read_cnt; size_t filesize; size_t length; int differ; if (CMD_ARGC < 2 || CMD_ARGC > 3) return ERROR_COMMAND_SYNTAX_ERROR; struct duration bench; duration_start(&bench); struct flash_bank *p; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (retval != ERROR_OK) return retval; offset = 0; if (CMD_ARGC > 2) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset); if (offset > p->size) { LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank", offset); return ERROR_COMMAND_ARGUMENT_INVALID; } retval = fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) { LOG_ERROR("Could not open file"); return retval; } retval = fileio_size(fileio, &filesize); if (retval != ERROR_OK) { fileio_close(fileio); return retval; } length = MIN(filesize, p->size - offset); if (!length) { LOG_INFO("Nothing to compare with flash bank"); fileio_close(fileio); return ERROR_OK; } if (length != filesize) LOG_INFO("File content exceeds flash bank size. Only comparing the " "first %zu bytes of the file", length); buffer_file = malloc(length); if (!buffer_file) { LOG_ERROR("Out of memory"); fileio_close(fileio); return ERROR_FAIL; } retval = fileio_read(fileio, length, buffer_file, &read_cnt); fileio_close(fileio); if (retval != ERROR_OK) { LOG_ERROR("File read failure"); free(buffer_file); return retval; } if (read_cnt != length) { LOG_ERROR("Short read"); free(buffer_file); return ERROR_FAIL; } buffer_flash = malloc(length); if (!buffer_flash) { LOG_ERROR("Out of memory"); free(buffer_file); return ERROR_FAIL; } retval = flash_driver_read(p, buffer_flash, offset, length); if (retval != ERROR_OK) { LOG_ERROR("Flash read error"); free(buffer_flash); free(buffer_file); return retval; } if (duration_measure(&bench) == ERROR_OK) command_print(CMD, "read %zd bytes from file %s and flash bank %u" " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", length, CMD_ARGV[1], p->bank_number, offset, duration_elapsed(&bench), duration_kbps(&bench, length)); differ = memcmp(buffer_file, buffer_flash, length); command_print(CMD, "contents %s", differ ? "differ" : "match"); if (differ) { uint32_t t; int diffs = 0; for (t = 0; t < length; t++) { if (buffer_flash[t] == buffer_file[t]) continue; command_print(CMD, "diff %d address 0x%08" PRIx32 ". Was 0x%02x instead of 0x%02x", diffs, t + offset, buffer_flash[t], buffer_file[t]); if (diffs++ >= 127) { command_print(CMD, "More than 128 errors, the rest are not printed."); break; } keep_alive(); } } free(buffer_flash); free(buffer_file); return differ ? ERROR_FAIL : ERROR_OK; } void flash_set_dirty(void) { struct flash_bank *c; /* set all flash to require erasing */ for (c = flash_bank_list(); c; c = c->next) { for (unsigned int i = 0; i < c->num_sectors; i++) c->sectors[i].is_erased = 0; } } COMMAND_HANDLER(handle_flash_padded_value_command) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *p; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (retval != ERROR_OK) return retval; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], p->default_padded_value); command_print(CMD, "Default padded value set to 0x%" PRIx8 " for flash bank %u", p->default_padded_value, p->bank_number); return retval; } static const struct command_registration flash_exec_command_handlers[] = { { .name = "probe", .handler = handle_flash_probe_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Identify a flash bank.", }, { .name = "info", .handler = handle_flash_info_command, .mode = COMMAND_EXEC, .usage = "bank_id ['sectors']", .help = "Print information about a flash bank.", }, { .name = "erase_check", .handler = handle_flash_erase_check_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Check erase state of all blocks in a " "flash bank.", }, { .name = "erase_sector", .handler = handle_flash_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id first_sector_num (last_sector_num|'last')", .help = "Erase a range of sectors in a flash bank.", }, { .name = "erase_address", .handler = handle_flash_erase_address_command, .mode = COMMAND_EXEC, .usage = "['pad'] ['unlock'] address length", .help = "Erase flash sectors starting at address and " "continuing for length bytes. If 'pad' is specified, " "data outside that range may also be erased: the start " "address may be decreased, and length increased, so " "that all of the first and last sectors are erased. " "If 'unlock' is specified, then the flash is unprotected " "before erasing.", }, { .name = "filld", .handler = handle_flash_fill_command, .mode = COMMAND_EXEC, .usage = "address value n", .help = "Fill n double-words with 64-bit value, starting at " "word address. (No autoerase.)", }, { .name = "fillw", .handler = handle_flash_fill_command, .mode = COMMAND_EXEC, .usage = "address value n", .help = "Fill n words with 32-bit value, starting at " "word address. (No autoerase.)", }, { .name = "fillh", .handler = handle_flash_fill_command, .mode = COMMAND_EXEC, .usage = "address value n", .help = "Fill n halfwords with 16-bit value, starting at " "word address. (No autoerase.)", }, { .name = "fillb", .handler = handle_flash_fill_command, .mode = COMMAND_EXEC, .usage = "address value n", .help = "Fill n bytes with 8-bit value, starting at " "word address. (No autoerase.)", }, { .name = "mdb", .handler = handle_flash_md_command, .mode = COMMAND_EXEC, .usage = "address [count]", .help = "Display bytes from flash.", }, { .name = "mdh", .handler = handle_flash_md_command, .mode = COMMAND_EXEC, .usage = "address [count]", .help = "Display half-words from flash.", }, { .name = "mdw", .handler = handle_flash_md_command, .mode = COMMAND_EXEC, .usage = "address [count]", .help = "Display words from flash.", }, { .name = "write_bank", .handler = handle_flash_write_bank_command, .mode = COMMAND_EXEC, .usage = "bank_id filename [offset]", .help = "Write binary data from file to flash bank. Allow optional " "offset from beginning of the bank (defaults to zero).", }, { .name = "write_image", .handler = handle_flash_write_image_command, .mode = COMMAND_EXEC, .usage = "[erase] [unlock] filename [offset [file_type]]", .help = "Write an image to flash. Optionally first unprotect " "and/or erase the region to be used. Allow optional " "offset from beginning of bank (defaults to zero)", }, { .name = "verify_image", .handler = handle_flash_verify_image_command, .mode = COMMAND_EXEC, .usage = "filename [offset [file_type]]", .help = "Verify an image against flash. Allow optional " "offset from beginning of bank (defaults to zero)", }, { .name = "read_bank", .handler = handle_flash_read_bank_command, .mode = COMMAND_EXEC, .usage = "bank_id filename [offset [length]]", .help = "Read binary data from flash bank to file. Allow optional " "offset from beginning of the bank (defaults to zero).", }, { .name = "verify_bank", .handler = handle_flash_verify_bank_command, .mode = COMMAND_EXEC, .usage = "bank_id filename [offset]", .help = "Compare the contents of a file with the contents of the " "flash bank. Allow optional offset from beginning of the bank " "(defaults to zero).", }, { .name = "protect", .handler = handle_flash_protect_command, .mode = COMMAND_EXEC, .usage = "bank_id first_block [last_block|'last'] " "('on'|'off')", .help = "Turn protection on or off for a range of protection " "blocks or sectors in a given flash bank. " "See 'flash info' output for a list of blocks.", }, { .name = "padded_value", .handler = handle_flash_padded_value_command, .mode = COMMAND_EXEC, .usage = "bank_id value", .help = "Set default flash padded value", }, COMMAND_REGISTRATION_DONE }; static int flash_init_drivers(struct command_context *cmd_ctx) { if (!flash_bank_list()) return ERROR_OK; return register_commands(cmd_ctx, "flash", flash_exec_command_handlers); } COMMAND_HANDLER(handle_flash_bank_command) { if (CMD_ARGC < 7) { LOG_ERROR("usage: flash bank <name> <driver> " "<base> <size> <chip_width> <bus_width> <target>"); return ERROR_COMMAND_SYNTAX_ERROR; } /* save bank name and advance arguments for compatibility */ const char *bank_name = *CMD_ARGV++; CMD_ARGC--; struct target *target = get_target(CMD_ARGV[5]); if (!target) { LOG_ERROR("target '%s' not defined", CMD_ARGV[5]); return ERROR_FAIL; } const char *driver_name = CMD_ARGV[0]; const struct flash_driver *driver = flash_driver_find_by_name(driver_name); if (!driver) { /* no matching flash driver found */ LOG_ERROR("flash driver '%s' not found", driver_name); return ERROR_FAIL; } /* check the flash bank name is unique */ if (get_flash_bank_by_name_noprobe(bank_name)) { /* flash bank name already exists */ LOG_ERROR("flash bank name '%s' already exists", bank_name); return ERROR_FAIL; } /* register flash specific commands */ if (driver->commands) { int retval = register_commands(CMD_CTX, NULL, driver->commands); if (retval != ERROR_OK) { LOG_ERROR("couldn't register '%s' commands", driver_name); return ERROR_FAIL; } } struct flash_bank *c = calloc(1, sizeof(*c)); c->name = strdup(bank_name); c->target = target; c->driver = driver; COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[1], c->base); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], c->size); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[3], c->chip_width); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[4], c->bus_width); c->default_padded_value = c->erased_value = 0xff; c->minimal_write_gap = FLASH_WRITE_GAP_SECTOR; int retval; retval = CALL_COMMAND_HANDLER(driver->flash_bank_command, c); if (retval != ERROR_OK) { LOG_ERROR("'%s' driver rejected flash bank at " TARGET_ADDR_FMT "; usage: %s", driver_name, c->base, driver->usage); free(c); return retval; } if (!driver->usage) LOG_DEBUG("'%s' driver usage field missing", driver_name); flash_bank_add(c); return ERROR_OK; } COMMAND_HANDLER(handle_flash_banks_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; unsigned n = 0; for (struct flash_bank *p = flash_bank_list(); p; p = p->next, n++) { command_print(CMD, "#%d : %s (%s) at " TARGET_ADDR_FMT ", size 0x%8.8" PRIx32 ", " "buswidth %u, chipwidth %u", p->bank_number, p->name, p->driver->name, p->base, p->size, p->bus_width, p->chip_width); } return ERROR_OK; } COMMAND_HANDLER(handle_flash_list) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; for (struct flash_bank *p = flash_bank_list(); p; p = p->next) { command_print(CMD, "{\n" " name %s\n" " driver %s\n" " base " TARGET_ADDR_FMT "\n" " size 0x%" PRIx32 "\n" " bus_width %u\n" " chip_width %u\n" " target %s\n" "}", p->name, p->driver->name, p->base, p->size, p->bus_width, p->chip_width, target_name(p->target)); } return ERROR_OK; } COMMAND_HANDLER(handle_flash_init_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; static bool flash_initialized; if (flash_initialized) { LOG_INFO("'flash init' has already been called"); return ERROR_OK; } flash_initialized = true; LOG_DEBUG("Initializing flash devices..."); return flash_init_drivers(CMD_CTX); } static const struct command_registration flash_config_command_handlers[] = { { .name = "bank", .handler = handle_flash_bank_command, .mode = COMMAND_CONFIG, .usage = "bank_id driver_name base_address size_bytes " "chip_width_bytes bus_width_bytes target " "[driver_options ...]", .help = "Define a new bank with the given name, " "using the specified NOR flash driver.", }, { .name = "init", .mode = COMMAND_CONFIG, .handler = handle_flash_init_command, .help = "Initialize flash devices.", .usage = "", }, { .name = "banks", .mode = COMMAND_ANY, .handler = handle_flash_banks_command, .help = "Display table with information about flash banks.", .usage = "", }, { .name = "list", .mode = COMMAND_ANY, .handler = handle_flash_list, .help = "Returns a list of details about the flash banks.", .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration flash_command_handlers[] = { { .name = "flash", .mode = COMMAND_ANY, .help = "NOR flash command group", .chain = flash_config_command_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; int flash_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, flash_command_handlers); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/tms470.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007,2008 by Christopher Kilgour * * techie |_at_| whiterocker |_dot_| com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" /* ---------------------------------------------------------------------- * Internal Support, Helpers * ---------------------------------------------------------------------- */ struct tms470_flash_bank { unsigned ordinal; /* device identification register */ uint32_t device_ident_reg; uint32_t silicon_version; uint32_t technology_family; uint32_t rom_flash; uint32_t part_number; const char *part_name; }; static const struct flash_sector tms470r1a256_sectors[] = { {0x00000000, 0x00002000, -1, -1}, {0x00002000, 0x00002000, -1, -1}, {0x00004000, 0x00002000, -1, -1}, {0x00006000, 0x00002000, -1, -1}, {0x00008000, 0x00008000, -1, -1}, {0x00010000, 0x00008000, -1, -1}, {0x00018000, 0x00008000, -1, -1}, {0x00020000, 0x00008000, -1, -1}, {0x00028000, 0x00008000, -1, -1}, {0x00030000, 0x00008000, -1, -1}, {0x00038000, 0x00002000, -1, -1}, {0x0003A000, 0x00002000, -1, -1}, {0x0003C000, 0x00002000, -1, -1}, {0x0003E000, 0x00002000, -1, -1}, }; #define TMS470R1A256_NUM_SECTORS \ ARRAY_SIZE(tms470r1a256_sectors) static const struct flash_sector tms470r1a288_bank0_sectors[] = { {0x00000000, 0x00002000, -1, -1}, {0x00002000, 0x00002000, -1, -1}, {0x00004000, 0x00002000, -1, -1}, {0x00006000, 0x00002000, -1, -1}, }; #define TMS470R1A288_BANK0_NUM_SECTORS \ ARRAY_SIZE(tms470r1a288_bank0_sectors) static const struct flash_sector tms470r1a288_bank1_sectors[] = { {0x00040000, 0x00010000, -1, -1}, {0x00050000, 0x00010000, -1, -1}, {0x00060000, 0x00010000, -1, -1}, {0x00070000, 0x00010000, -1, -1}, }; #define TMS470R1A288_BANK1_NUM_SECTORS \ ARRAY_SIZE(tms470r1a288_bank1_sectors) static const struct flash_sector tms470r1a384_bank0_sectors[] = { {0x00000000, 0x00002000, -1, -1}, {0x00002000, 0x00002000, -1, -1}, {0x00004000, 0x00004000, -1, -1}, {0x00008000, 0x00004000, -1, -1}, {0x0000C000, 0x00004000, -1, -1}, {0x00010000, 0x00004000, -1, -1}, {0x00014000, 0x00004000, -1, -1}, {0x00018000, 0x00002000, -1, -1}, {0x0001C000, 0x00002000, -1, -1}, {0x0001E000, 0x00002000, -1, -1}, }; #define TMS470R1A384_BANK0_NUM_SECTORS \ ARRAY_SIZE(tms470r1a384_bank0_sectors) static const struct flash_sector tms470r1a384_bank1_sectors[] = { {0x00020000, 0x00008000, -1, -1}, {0x00028000, 0x00008000, -1, -1}, {0x00030000, 0x00008000, -1, -1}, {0x00038000, 0x00008000, -1, -1}, }; #define TMS470R1A384_BANK1_NUM_SECTORS \ ARRAY_SIZE(tms470r1a384_bank1_sectors) static const struct flash_sector tms470r1a384_bank2_sectors[] = { {0x00040000, 0x00008000, -1, -1}, {0x00048000, 0x00008000, -1, -1}, {0x00050000, 0x00008000, -1, -1}, {0x00058000, 0x00008000, -1, -1}, }; #define TMS470R1A384_BANK2_NUM_SECTORS \ ARRAY_SIZE(tms470r1a384_bank2_sectors) /* ---------------------------------------------------------------------- */ static int tms470_read_part_info(struct flash_bank *bank) { struct tms470_flash_bank *tms470_info = bank->driver_priv; struct target *target = bank->target; uint32_t device_ident_reg; uint32_t silicon_version; uint32_t technology_family; uint32_t rom_flash; uint32_t part_number; const char *part_name; /* we shall not rely on the caller in this test, this function allocates memory, thus and executing the code more than once may cause memory leak */ if (tms470_info->device_ident_reg) return ERROR_OK; /* read and parse the device identification register */ target_read_u32(target, 0xFFFFFFF0, &device_ident_reg); LOG_INFO("device_ident_reg = 0x%08" PRIx32 "", device_ident_reg); if ((device_ident_reg & 7) == 0) { LOG_WARNING("Cannot identify target as a TMS470 family."); return ERROR_FLASH_OPERATION_FAILED; } silicon_version = (device_ident_reg >> 12) & 0xF; technology_family = (device_ident_reg >> 11) & 1; rom_flash = (device_ident_reg >> 10) & 1; part_number = (device_ident_reg >> 3) & 0x7f; free(bank->sectors); bank->sectors = NULL; bank->num_sectors = 0; /* * If the part number is known, determine if the flash bank is valid * based on the base address being within the known flash bank * ranges. Then fixup/complete the remaining fields of the flash * bank structure. */ switch (part_number) { case 0x0a: part_name = "TMS470R1A256"; if (bank->base >= 0x00040000) { LOG_ERROR("No %s flash bank contains base address " TARGET_ADDR_FMT ".", part_name, bank->base); return ERROR_FLASH_OPERATION_FAILED; } tms470_info->ordinal = 0; bank->base = 0x00000000; bank->size = 256 * 1024; bank->num_sectors = TMS470R1A256_NUM_SECTORS; bank->sectors = malloc(sizeof(tms470r1a256_sectors)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; (void)memcpy(bank->sectors, tms470r1a256_sectors, sizeof(tms470r1a256_sectors)); break; case 0x2b: part_name = "TMS470R1A288"; if (bank->base < 0x00008000) { tms470_info->ordinal = 0; bank->base = 0x00000000; bank->size = 32 * 1024; bank->num_sectors = TMS470R1A288_BANK0_NUM_SECTORS; bank->sectors = malloc(sizeof(tms470r1a288_bank0_sectors)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; (void)memcpy(bank->sectors, tms470r1a288_bank0_sectors, sizeof(tms470r1a288_bank0_sectors)); } else if ((bank->base >= 0x00040000) && (bank->base < 0x00080000)) { tms470_info->ordinal = 1; bank->base = 0x00040000; bank->size = 256 * 1024; bank->num_sectors = TMS470R1A288_BANK1_NUM_SECTORS; bank->sectors = malloc(sizeof(tms470r1a288_bank1_sectors)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; (void)memcpy(bank->sectors, tms470r1a288_bank1_sectors, sizeof(tms470r1a288_bank1_sectors)); } else { LOG_ERROR("No %s flash bank contains base address " TARGET_ADDR_FMT ".", part_name, bank->base); return ERROR_FLASH_OPERATION_FAILED; } break; case 0x2d: part_name = "TMS470R1A384"; if (bank->base < 0x00020000) { tms470_info->ordinal = 0; bank->base = 0x00000000; bank->size = 128 * 1024; bank->num_sectors = TMS470R1A384_BANK0_NUM_SECTORS; bank->sectors = malloc(sizeof(tms470r1a384_bank0_sectors)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; (void)memcpy(bank->sectors, tms470r1a384_bank0_sectors, sizeof(tms470r1a384_bank0_sectors)); } else if ((bank->base >= 0x00020000) && (bank->base < 0x00040000)) { tms470_info->ordinal = 1; bank->base = 0x00020000; bank->size = 128 * 1024; bank->num_sectors = TMS470R1A384_BANK1_NUM_SECTORS; bank->sectors = malloc(sizeof(tms470r1a384_bank1_sectors)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; (void)memcpy(bank->sectors, tms470r1a384_bank1_sectors, sizeof(tms470r1a384_bank1_sectors)); } else if ((bank->base >= 0x00040000) && (bank->base < 0x00060000)) { tms470_info->ordinal = 2; bank->base = 0x00040000; bank->size = 128 * 1024; bank->num_sectors = TMS470R1A384_BANK2_NUM_SECTORS; bank->sectors = malloc(sizeof(tms470r1a384_bank2_sectors)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; (void)memcpy(bank->sectors, tms470r1a384_bank2_sectors, sizeof(tms470r1a384_bank2_sectors)); } else { LOG_ERROR("No %s flash bank contains base address " TARGET_ADDR_FMT ".", part_name, bank->base); return ERROR_FLASH_OPERATION_FAILED; } break; default: LOG_WARNING("Could not identify part 0x%02x as a member of the TMS470 family.", (unsigned)part_number); return ERROR_FLASH_OPERATION_FAILED; } /* turn off memory selects */ target_write_u32(target, 0xFFFFFFE4, 0x00000000); target_write_u32(target, 0xFFFFFFE0, 0x00000000); LOG_INFO("Identified %s, ver=%d, core=%s, nvmem=%s.", part_name, (int)(silicon_version), (technology_family ? "1.8v" : "3.3v"), (rom_flash ? "rom" : "flash")); tms470_info->device_ident_reg = device_ident_reg; tms470_info->silicon_version = silicon_version; tms470_info->technology_family = technology_family; tms470_info->rom_flash = rom_flash; tms470_info->part_number = part_number; tms470_info->part_name = part_name; /* * Disable reset on address access violation. */ target_write_u32(target, 0xFFFFFFE0, 0x00004007); return ERROR_OK; } /* ---------------------------------------------------------------------- */ static uint32_t keys_set; static uint32_t flash_keys[4]; COMMAND_HANDLER(tms470_handle_flash_keyset_command) { if (CMD_ARGC > 4) return ERROR_COMMAND_SYNTAX_ERROR; else if (CMD_ARGC == 4) { int i; for (i = 0; i < 4; i++) { int start = (strncmp(CMD_ARGV[i], "0x", 2) == 0) ? 2 : 0; if (sscanf(&CMD_ARGV[i][start], "%" SCNx32 "", &flash_keys[i]) != 1) { command_print(CMD, "could not process flash key %s", CMD_ARGV[i]); LOG_ERROR("could not process flash key %s", CMD_ARGV[i]); return ERROR_COMMAND_SYNTAX_ERROR; } } keys_set = 1; } else if (CMD_ARGC != 0) { command_print(CMD, "tms470 flash_keyset <key0> <key1> <key2> <key3>"); return ERROR_COMMAND_SYNTAX_ERROR; } if (keys_set) { command_print(CMD, "using flash keys 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 "", flash_keys[0], flash_keys[1], flash_keys[2], flash_keys[3]); } else command_print(CMD, "flash keys not set"); return ERROR_OK; } static const uint32_t flash_keys_all_ones[] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,}; static const uint32_t flash_keys_all_zeros[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000,}; static const uint32_t flash_keys_mix1[] = { 0xf0fff0ff, 0xf0fff0ff, 0xf0fff0ff, 0xf0fff0ff}; static const uint32_t flash_keys_mix2[] = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}; /* ---------------------------------------------------------------------- */ static int osc_mhz = 12; COMMAND_HANDLER(tms470_handle_osc_megahertz_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; else if (CMD_ARGC == 1) sscanf(CMD_ARGV[0], "%d", &osc_mhz); if (osc_mhz <= 0) { LOG_ERROR("osc_megahertz must be positive and non-zero!"); command_print(CMD, "osc_megahertz must be positive and non-zero!"); osc_mhz = 12; return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "osc_megahertz=%d", osc_mhz); return ERROR_OK; } /* ---------------------------------------------------------------------- */ static int plldis; COMMAND_HANDLER(tms470_handle_plldis_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; else if (CMD_ARGC == 1) { sscanf(CMD_ARGV[0], "%d", &plldis); plldis = plldis ? 1 : 0; } command_print(CMD, "plldis=%d", plldis); return ERROR_OK; } /* ---------------------------------------------------------------------- */ static int tms470_check_flash_unlocked(struct target *target) { uint32_t fmbbusy; target_read_u32(target, 0xFFE89C08, &fmbbusy); LOG_INFO("tms470 fmbbusy = 0x%08" PRIx32 " -> %s", fmbbusy, fmbbusy & 0x8000 ? "unlocked" : "LOCKED"); return fmbbusy & 0x8000 ? ERROR_OK : ERROR_FLASH_OPERATION_FAILED; } /* ---------------------------------------------------------------------- */ static int tms470_try_flash_keys(struct target *target, const uint32_t *key_set) { uint32_t glbctrl, fmmstat; int retval = ERROR_FLASH_OPERATION_FAILED; /* set GLBCTRL.4 */ target_read_u32(target, 0xFFFFFFDC, &glbctrl); target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10); /* only perform the key match when 3VSTAT is clear */ target_read_u32(target, 0xFFE8BC0C, &fmmstat); if (!(fmmstat & 0x08)) { unsigned i; uint32_t fmbptr, fmbac2, orig_fmregopt; target_write_u32(target, 0xFFE8BC04, fmmstat & ~0x07); /* wait for pump ready */ do { target_read_u32(target, 0xFFE8A814, &fmbptr); alive_sleep(1); } while (!(fmbptr & 0x0200)); /* force max wait states */ target_read_u32(target, 0xFFE88004, &fmbac2); target_write_u32(target, 0xFFE88004, fmbac2 | 0xff); /* save current access mode, force normal read mode */ target_read_u32(target, 0xFFE89C00, &orig_fmregopt); target_write_u32(target, 0xFFE89C00, 0x00); for (i = 0; i < 4; i++) { uint32_t tmp; /* There is no point displaying the value of tmp, it is * filtered by the chip. The purpose of this read is to * prime the unlocking logic rather than read out the value. */ target_read_u32(target, 0x00001FF0 + 4 * i, &tmp); LOG_INFO("tms470 writing fmpkey = 0x%08" PRIx32 "", key_set[i]); target_write_u32(target, 0xFFE89C0C, key_set[i]); } if (tms470_check_flash_unlocked(target) == ERROR_OK) { /* * There seems to be a side-effect of reading the FMPKEY * register in that it re-enables the protection. So we * re-enable it. */ for (i = 0; i < 4; i++) { uint32_t tmp; target_read_u32(target, 0x00001FF0 + 4 * i, &tmp); target_write_u32(target, 0xFFE89C0C, key_set[i]); } retval = ERROR_OK; } /* restore settings */ target_write_u32(target, 0xFFE89C00, orig_fmregopt); target_write_u32(target, 0xFFE88004, fmbac2); } /* clear config bit */ target_write_u32(target, 0xFFFFFFDC, glbctrl); return retval; } /* ---------------------------------------------------------------------- */ static int tms470_unlock_flash(struct flash_bank *bank) { struct target *target = bank->target; const uint32_t *p_key_sets[5]; unsigned i, key_set_count; if (keys_set) { key_set_count = 5; p_key_sets[0] = flash_keys; p_key_sets[1] = flash_keys_all_ones; p_key_sets[2] = flash_keys_all_zeros; p_key_sets[3] = flash_keys_mix1; p_key_sets[4] = flash_keys_mix2; } else { key_set_count = 4; p_key_sets[0] = flash_keys_all_ones; p_key_sets[1] = flash_keys_all_zeros; p_key_sets[2] = flash_keys_mix1; p_key_sets[3] = flash_keys_mix2; } for (i = 0; i < key_set_count; i++) { if (tms470_try_flash_keys(target, p_key_sets[i]) == ERROR_OK) { LOG_INFO("tms470 flash is unlocked"); return ERROR_OK; } } LOG_WARNING("tms470 could not unlock flash memory protection level 2"); return ERROR_FLASH_OPERATION_FAILED; } /* ---------------------------------------------------------------------- */ static int tms470_flash_initialize_internal_state_machine(struct flash_bank *bank) { uint32_t fmmac2, fmmac1, fmmaxep, k, delay, glbctrl, sysclk; struct target *target = bank->target; struct tms470_flash_bank *tms470_info = bank->driver_priv; int result = ERROR_OK; /* * Select the desired bank to be programmed by writing BANK[2:0] of * FMMAC2. */ target_read_u32(target, 0xFFE8BC04, &fmmac2); fmmac2 &= ~0x0007; fmmac2 |= (tms470_info->ordinal & 7); target_write_u32(target, 0xFFE8BC04, fmmac2); LOG_DEBUG("set fmmac2 = 0x%04" PRIx32 "", fmmac2); /* * Disable level 1 sector protection by setting bit 15 of FMMAC1. */ target_read_u32(target, 0xFFE8BC00, &fmmac1); fmmac1 |= 0x8000; target_write_u32(target, 0xFFE8BC00, fmmac1); LOG_DEBUG("set fmmac1 = 0x%04" PRIx32 "", fmmac1); /* * FMTCREG = 0x2fc0; */ target_write_u32(target, 0xFFE8BC10, 0x2fc0); LOG_DEBUG("set fmtcreg = 0x2fc0"); /* * MAXPP = 50 */ target_write_u32(target, 0xFFE8A07C, 50); LOG_DEBUG("set fmmaxpp = 50"); /* * MAXCP = 0xf000 + 2000 */ target_write_u32(target, 0xFFE8A084, 0xf000 + 2000); LOG_DEBUG("set fmmaxcp = 0x%04x", 0xf000 + 2000); /* * configure VHV */ target_read_u32(target, 0xFFE8A080, &fmmaxep); if (fmmaxep == 0xf000) { fmmaxep = 0xf000 + 4095; target_write_u32(target, 0xFFE8A80C, 0x9964); LOG_DEBUG("set fmptr3 = 0x9964"); } else { fmmaxep = 0xa000 + 4095; target_write_u32(target, 0xFFE8A80C, 0x9b64); LOG_DEBUG("set fmptr3 = 0x9b64"); } target_write_u32(target, 0xFFE8A080, fmmaxep); LOG_DEBUG("set fmmaxep = 0x%04" PRIx32 "", fmmaxep); /* * FMPTR4 = 0xa000 */ target_write_u32(target, 0xFFE8A810, 0xa000); LOG_DEBUG("set fmptr4 = 0xa000"); /* * FMPESETUP, delay parameter selected based on clock frequency. * * According to the TI App Note SPNU257 and flashing code, delay is * int((sysclk(MHz) + 1) / 2), with a minimum of 5. The system * clock is usually derived from the ZPLL module, and selected by * the plldis global. */ target_read_u32(target, 0xFFFFFFDC, &glbctrl); sysclk = (plldis ? 1 : (glbctrl & 0x08) ? 4 : 8) * osc_mhz / (1 + (glbctrl & 7)); delay = (sysclk > 10) ? (sysclk + 1) / 2 : 5; target_write_u32(target, 0xFFE8A018, (delay << 4) | (delay << 8)); LOG_DEBUG("set fmpsetup = 0x%04" PRIx32 "", (delay << 4) | (delay << 8)); /* * FMPVEVACCESS, based on delay. */ k = delay | (delay << 8); target_write_u32(target, 0xFFE8A05C, k); LOG_DEBUG("set fmpvevaccess = 0x%04" PRIx32 "", k); /* * FMPCHOLD, FMPVEVHOLD, FMPVEVSETUP, based on delay. */ k <<= 1; target_write_u32(target, 0xFFE8A034, k); LOG_DEBUG("set fmpchold = 0x%04" PRIx32 "", k); target_write_u32(target, 0xFFE8A040, k); LOG_DEBUG("set fmpvevhold = 0x%04" PRIx32 "", k); target_write_u32(target, 0xFFE8A024, k); LOG_DEBUG("set fmpvevsetup = 0x%04" PRIx32 "", k); /* * FMCVACCESS, based on delay. */ k = delay * 16; target_write_u32(target, 0xFFE8A060, k); LOG_DEBUG("set fmcvaccess = 0x%04" PRIx32 "", k); /* * FMCSETUP, based on delay. */ k = 0x3000 | delay * 20; target_write_u32(target, 0xFFE8A020, k); LOG_DEBUG("set fmcsetup = 0x%04" PRIx32 "", k); /* * FMEHOLD, based on delay. */ k = (delay * 20) << 2; target_write_u32(target, 0xFFE8A038, k); LOG_DEBUG("set fmehold = 0x%04" PRIx32 "", k); /* * PWIDTH, CWIDTH, EWIDTH, based on delay. */ target_write_u32(target, 0xFFE8A050, delay * 8); LOG_DEBUG("set fmpwidth = 0x%04" PRIx32 "", delay * 8); target_write_u32(target, 0xFFE8A058, delay * 1000); LOG_DEBUG("set fmcwidth = 0x%04" PRIx32 "", delay * 1000); target_write_u32(target, 0xFFE8A054, delay * 5400); LOG_DEBUG("set fmewidth = 0x%04" PRIx32 "", delay * 5400); return result; } /* ---------------------------------------------------------------------- */ static int tms470_flash_status(struct flash_bank *bank) { struct target *target = bank->target; int result = ERROR_OK; uint32_t fmmstat; target_read_u32(target, 0xFFE8BC0C, &fmmstat); LOG_DEBUG("set fmmstat = 0x%04" PRIx32 "", fmmstat); if (fmmstat & 0x0080) { LOG_WARNING("tms470 flash command: erase still active after busy clear."); result = ERROR_FLASH_OPERATION_FAILED; } if (fmmstat & 0x0040) { LOG_WARNING("tms470 flash command: program still active after busy clear."); result = ERROR_FLASH_OPERATION_FAILED; } if (fmmstat & 0x0020) { LOG_WARNING("tms470 flash command: invalid data command."); result = ERROR_FLASH_OPERATION_FAILED; } if (fmmstat & 0x0010) { LOG_WARNING("tms470 flash command: program, erase or validate sector failed."); result = ERROR_FLASH_OPERATION_FAILED; } if (fmmstat & 0x0008) { LOG_WARNING("tms470 flash command: voltage instability detected."); result = ERROR_FLASH_OPERATION_FAILED; } if (fmmstat & 0x0006) { LOG_WARNING("tms470 flash command: command suspend detected."); result = ERROR_FLASH_OPERATION_FAILED; } if (fmmstat & 0x0001) { LOG_WARNING("tms470 flash command: sector was locked."); result = ERROR_FLASH_OPERATION_FAILED; } return result; } /* ---------------------------------------------------------------------- */ static int tms470_erase_sector(struct flash_bank *bank, int sector) { uint32_t glbctrl, orig_fmregopt, fmbsea, fmbseb, fmmstat; struct target *target = bank->target; uint32_t flash_addr = bank->base + bank->sectors[sector].offset; int result = ERROR_OK; /* * Set the bit GLBCTRL4 of the GLBCTRL register (in the System * module) to enable writing to the flash registers }. */ target_read_u32(target, 0xFFFFFFDC, &glbctrl); target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10); LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl | 0x10); /* Force normal read mode. */ target_read_u32(target, 0xFFE89C00, &orig_fmregopt); target_write_u32(target, 0xFFE89C00, 0); LOG_DEBUG("set fmregopt = 0x%08x", 0); (void)tms470_flash_initialize_internal_state_machine(bank); /* * Select one or more bits in FMBSEA or FMBSEB to disable Level 1 * protection for the particular sector to be erased/written. */ assert(sector >= 0); if (sector < 16) { target_read_u32(target, 0xFFE88008, &fmbsea); target_write_u32(target, 0xFFE88008, fmbsea | (1 << sector)); LOG_DEBUG("set fmbsea = 0x%04" PRIx32 "", fmbsea | (1 << sector)); } else { target_read_u32(target, 0xFFE8800C, &fmbseb); target_write_u32(target, 0xFFE8800C, fmbseb | (1 << (sector - 16))); LOG_DEBUG("set fmbseb = 0x%04" PRIx32 "", fmbseb | (1 << (sector - 16))); } bank->sectors[sector].is_protected = 0; /* * clear status register, sent erase command, kickoff erase */ target_write_u16(target, flash_addr, 0x0040); LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0x0040", flash_addr); target_write_u16(target, flash_addr, 0x0020); LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0x0020", flash_addr); target_write_u16(target, flash_addr, 0xffff); LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0xffff", flash_addr); /* * Monitor FMMSTAT, busy until clear, then check and other flags for * ultimate result of the operation. */ do { target_read_u32(target, 0xFFE8BC0C, &fmmstat); if (fmmstat & 0x0100) alive_sleep(1); } while (fmmstat & 0x0100); result = tms470_flash_status(bank); if (sector < 16) { target_write_u32(target, 0xFFE88008, fmbsea); LOG_DEBUG("set fmbsea = 0x%04" PRIx32 "", fmbsea); bank->sectors[sector].is_protected = fmbsea & (1 << sector) ? 0 : 1; } else { target_write_u32(target, 0xFFE8800C, fmbseb); LOG_DEBUG("set fmbseb = 0x%04" PRIx32 "", fmbseb); bank->sectors[sector].is_protected = fmbseb & (1 << (sector - 16)) ? 0 : 1; } target_write_u32(target, 0xFFE89C00, orig_fmregopt); LOG_DEBUG("set fmregopt = 0x%08" PRIx32 "", orig_fmregopt); target_write_u32(target, 0xFFFFFFDC, glbctrl); LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl); return result; } /*---------------------------------------------------------------------- * Implementation of Flash Driver Interfaces *---------------------------------------------------------------------- */ static const struct command_registration tms470_any_command_handlers[] = { { .name = "flash_keyset", .usage = "<key0> <key1> <key2> <key3>", .handler = tms470_handle_flash_keyset_command, .mode = COMMAND_ANY, .help = "tms470 flash_keyset <key0> <key1> <key2> <key3>", }, { .name = "osc_megahertz", .usage = "<MHz>", .handler = tms470_handle_osc_megahertz_command, .mode = COMMAND_ANY, .help = "tms470 osc_megahertz <MHz>", }, { .name = "plldis", .usage = "<0 | 1>", .handler = tms470_handle_plldis_command, .mode = COMMAND_ANY, .help = "tms470 plldis <0/1>", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration tms470_command_handlers[] = { { .name = "tms470", .mode = COMMAND_ANY, .help = "TI tms470 flash command group", .usage = "", .chain = tms470_any_command_handlers, }, COMMAND_REGISTRATION_DONE }; /* ---------------------------------------------------------------------- */ static int tms470_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct tms470_flash_bank *tms470_info = bank->driver_priv; int result = ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } tms470_read_part_info(bank); if ((first >= bank->num_sectors) || (last >= bank->num_sectors) || (first > last)) { LOG_ERROR("Sector range %u to %u invalid.", first, last); return ERROR_FLASH_SECTOR_INVALID; } result = tms470_unlock_flash(bank); if (result != ERROR_OK) return result; for (unsigned int sector = first; sector <= last; sector++) { LOG_INFO("Erasing tms470 bank %u sector %u...", tms470_info->ordinal, sector); result = tms470_erase_sector(bank, sector); if (result != ERROR_OK) { LOG_ERROR("tms470 could not erase flash sector."); break; } else LOG_INFO("sector erased successfully."); } return result; } /* ---------------------------------------------------------------------- */ static int tms470_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct tms470_flash_bank *tms470_info = bank->driver_priv; struct target *target = bank->target; uint32_t fmmac2, fmbsea, fmbseb; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } tms470_read_part_info(bank); if ((first >= bank->num_sectors) || (last >= bank->num_sectors) || (first > last)) { LOG_ERROR("Sector range %u to %u invalid.", first, last); return ERROR_FLASH_SECTOR_INVALID; } /* enable the appropriate bank */ target_read_u32(target, 0xFFE8BC04, &fmmac2); target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal); /* get the original sector protection flags for this bank */ target_read_u32(target, 0xFFE88008, &fmbsea); target_read_u32(target, 0xFFE8800C, &fmbseb); for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { if (sector < 16) { fmbsea = set ? fmbsea & ~(1 << sector) : fmbsea | (1 << sector); bank->sectors[sector].is_protected = set ? 1 : 0; } else { fmbseb = set ? fmbseb & ~(1 << (sector - 16)) : fmbseb | (1 << (sector - 16)); bank->sectors[sector].is_protected = set ? 1 : 0; } } /* update the protection bits */ target_write_u32(target, 0xFFE88008, fmbsea); target_write_u32(target, 0xFFE8800C, fmbseb); return ERROR_OK; } /* ---------------------------------------------------------------------- */ static int tms470_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t glbctrl, fmbac2, orig_fmregopt, fmbsea, fmbseb, fmmaxpp, fmmstat; int result = ERROR_OK; uint32_t i; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } tms470_read_part_info(bank); LOG_INFO("Writing %" PRIu32 " bytes starting at " TARGET_ADDR_FMT, count, bank->base + offset); /* set GLBCTRL.4 */ target_read_u32(target, 0xFFFFFFDC, &glbctrl); target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10); (void)tms470_flash_initialize_internal_state_machine(bank); /* force max wait states */ target_read_u32(target, 0xFFE88004, &fmbac2); target_write_u32(target, 0xFFE88004, fmbac2 | 0xff); /* save current access mode, force normal read mode */ target_read_u32(target, 0xFFE89C00, &orig_fmregopt); target_write_u32(target, 0xFFE89C00, 0x00); /* * Disable Level 1 protection for all sectors to be erased/written. */ target_read_u32(target, 0xFFE88008, &fmbsea); target_write_u32(target, 0xFFE88008, 0xffff); target_read_u32(target, 0xFFE8800C, &fmbseb); target_write_u32(target, 0xFFE8800C, 0xffff); /* read MAXPP */ target_read_u32(target, 0xFFE8A07C, &fmmaxpp); for (i = 0; i < count; i += 2) { uint32_t addr = bank->base + offset + i; uint16_t word = (((uint16_t) buffer[i]) << 8) | (uint16_t) buffer[i + 1]; if (word != 0xffff) { LOG_INFO("writing 0x%04x at 0x%08" PRIx32 "", word, addr); /* clear status register */ target_write_u16(target, addr, 0x0040); /* program flash command */ target_write_u16(target, addr, 0x0010); /* burn the 16-bit word (big-endian) */ target_write_u16(target, addr, word); /* * Monitor FMMSTAT, busy until clear, then check and other flags * for ultimate result of the operation. */ do { target_read_u32(target, 0xFFE8BC0C, &fmmstat); if (fmmstat & 0x0100) alive_sleep(1); } while (fmmstat & 0x0100); if (fmmstat & 0x3ff) { LOG_ERROR("fmstat = 0x%04" PRIx32 "", fmmstat); LOG_ERROR( "Could not program word 0x%04x at address 0x%08" PRIx32 ".", word, addr); result = ERROR_FLASH_OPERATION_FAILED; break; } } else LOG_INFO("skipping 0xffff at 0x%08" PRIx32 "", addr); } /* restore */ target_write_u32(target, 0xFFE88008, fmbsea); target_write_u32(target, 0xFFE8800C, fmbseb); target_write_u32(target, 0xFFE88004, fmbac2); target_write_u32(target, 0xFFE89C00, orig_fmregopt); target_write_u32(target, 0xFFFFFFDC, glbctrl); return result; } /* ---------------------------------------------------------------------- */ static int tms470_probe(struct flash_bank *bank) { if (bank->target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } return tms470_read_part_info(bank); } static int tms470_auto_probe(struct flash_bank *bank) { struct tms470_flash_bank *tms470_info = bank->driver_priv; if (tms470_info->device_ident_reg) return ERROR_OK; return tms470_probe(bank); } /* ---------------------------------------------------------------------- */ static int tms470_erase_check(struct flash_bank *bank) { struct target *target = bank->target; struct tms470_flash_bank *tms470_info = bank->driver_priv; int result = ERROR_OK; uint32_t fmmac2, fmbac2, glbctrl, orig_fmregopt; static uint8_t buffer[64 * 1024]; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!tms470_info->device_ident_reg) tms470_read_part_info(bank); /* set GLBCTRL.4 */ target_read_u32(target, 0xFFFFFFDC, &glbctrl); target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10); /* save current access mode, force normal read mode */ target_read_u32(target, 0xFFE89C00, &orig_fmregopt); target_write_u32(target, 0xFFE89C00, 0x00); /* enable the appropriate bank */ target_read_u32(target, 0xFFE8BC04, &fmmac2); target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal); /* TCR = 0 */ target_write_u32(target, 0xFFE8BC10, 0x2fc0); /* clear TEZ in fmbrdy */ target_write_u32(target, 0xFFE88010, 0x0b); /* save current wait states, force max */ target_read_u32(target, 0xFFE88004, &fmbac2); target_write_u32(target, 0xFFE88004, fmbac2 | 0xff); /* * The TI primitives inspect the flash memory by reading one 32-bit * word at a time. Here we read an entire sector and inspect it in * an attempt to reduce the JTAG overhead. */ for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { uint32_t i, addr = bank->base + bank->sectors[sector].offset; LOG_INFO("checking flash bank %u sector %u", tms470_info->ordinal, sector); target_read_buffer(target, addr, bank->sectors[sector].size, buffer); bank->sectors[sector].is_erased = 1; for (i = 0; i < bank->sectors[sector].size; i++) { if (buffer[i] != 0xff) { bank->sectors[sector].is_erased = 0; break; } } if (bank->sectors[sector].is_erased != 1) { result = ERROR_FLASH_SECTOR_NOT_ERASED; break; } else LOG_INFO("sector erased"); } /* reset TEZ, wait states, read mode, GLBCTRL.4 */ target_write_u32(target, 0xFFE88010, 0x0f); target_write_u32(target, 0xFFE88004, fmbac2); target_write_u32(target, 0xFFE89C00, orig_fmregopt); target_write_u32(target, 0xFFFFFFDC, glbctrl); return result; } /* ---------------------------------------------------------------------- */ static int tms470_protect_check(struct flash_bank *bank) { struct target *target = bank->target; struct tms470_flash_bank *tms470_info = bank->driver_priv; int result = ERROR_OK; uint32_t fmmac2, fmbsea, fmbseb; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!tms470_info->device_ident_reg) tms470_read_part_info(bank); /* enable the appropriate bank */ target_read_u32(target, 0xFFE8BC04, &fmmac2); target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal); target_read_u32(target, 0xFFE88008, &fmbsea); target_read_u32(target, 0xFFE8800C, &fmbseb); for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { int protected; if (sector < 16) { protected = fmbsea & (1 << sector) ? 0 : 1; bank->sectors[sector].is_protected = protected; } else { protected = fmbseb & (1 << (sector - 16)) ? 0 : 1; bank->sectors[sector].is_protected = protected; } LOG_DEBUG("bank %u sector %u is %s", tms470_info->ordinal, sector, protected ? "protected" : "not protected"); } return result; } /* ---------------------------------------------------------------------- */ static int get_tms470_info(struct flash_bank *bank, struct command_invocation *cmd) { struct tms470_flash_bank *tms470_info = bank->driver_priv; if (!tms470_info->device_ident_reg) tms470_read_part_info(bank); if (!tms470_info->device_ident_reg) { command_print_sameline(cmd, "Cannot identify target as a TMS470\n"); return ERROR_FLASH_OPERATION_FAILED; } command_print_sameline(cmd, "\ntms470 information: Chip is %s\n", tms470_info->part_name); command_print_sameline(cmd, "Flash protection level 2 is %s\n", tms470_check_flash_unlocked(bank->target) == ERROR_OK ? "disabled" : "enabled"); return ERROR_OK; } /* ---------------------------------------------------------------------- */ /* * flash bank tms470 <base> <size> <chip_width> <bus_width> <target> * [options...] */ FLASH_BANK_COMMAND_HANDLER(tms470_flash_bank_command) { bank->driver_priv = malloc(sizeof(struct tms470_flash_bank)); if (!bank->driver_priv) return ERROR_FLASH_OPERATION_FAILED; (void)memset(bank->driver_priv, 0, sizeof(struct tms470_flash_bank)); return ERROR_OK; } const struct flash_driver tms470_flash = { .name = "tms470", .commands = tms470_command_handlers, .flash_bank_command = tms470_flash_bank_command, .erase = tms470_erase, .protect = tms470_protect, .write = tms470_write, .read = default_flash_read, .probe = tms470_probe, .auto_probe = tms470_auto_probe, .erase_check = tms470_erase_check, .protect_check = tms470_protect_check, .info = get_tms470_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/virtual.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" static struct flash_bank *virtual_get_master_bank(struct flash_bank *bank) { struct flash_bank *master_bank; master_bank = get_flash_bank_by_name_noprobe(bank->driver_priv); if (!master_bank) LOG_ERROR("master flash bank '%s' does not exist", (char *)bank->driver_priv); return master_bank; } static void virtual_update_bank_info(struct flash_bank *bank) { struct flash_bank *master_bank = virtual_get_master_bank(bank); if (!master_bank) return; /* update the info we do not have */ bank->size = master_bank->size; bank->chip_width = master_bank->chip_width; bank->bus_width = master_bank->bus_width; bank->erased_value = master_bank->erased_value; bank->default_padded_value = master_bank->default_padded_value; bank->write_start_alignment = master_bank->write_start_alignment; bank->write_end_alignment = master_bank->write_end_alignment; bank->minimal_write_gap = master_bank->minimal_write_gap; bank->num_sectors = master_bank->num_sectors; bank->sectors = master_bank->sectors; bank->num_prot_blocks = master_bank->num_prot_blocks; bank->prot_blocks = master_bank->prot_blocks; } FLASH_BANK_COMMAND_HANDLER(virtual_flash_bank_command) { if (CMD_ARGC < 7) return ERROR_COMMAND_SYNTAX_ERROR; /* get the master flash bank */ const char *bank_name = CMD_ARGV[6]; struct flash_bank *master_bank = get_flash_bank_by_name_noprobe(bank_name); if (!master_bank) { LOG_ERROR("master flash bank '%s' does not exist", bank_name); return ERROR_FLASH_OPERATION_FAILED; } /* save master bank name - use this to get settings later */ bank->driver_priv = strdup(bank_name); return ERROR_OK; } static int virtual_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct flash_bank *master_bank = virtual_get_master_bank(bank); if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; return flash_driver_protect(master_bank, set, first, last); } static int virtual_protect_check(struct flash_bank *bank) { struct flash_bank *master_bank = virtual_get_master_bank(bank); if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; if (!master_bank->driver->protect_check) return ERROR_FLASH_OPER_UNSUPPORTED; /* call master handler */ return master_bank->driver->protect_check(master_bank); } static int virtual_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ retval = master_bank->driver->erase(master_bank, first, last); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int virtual_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ retval = master_bank->driver->write(master_bank, buffer, offset, count); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int virtual_probe(struct flash_bank *bank) { struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ retval = master_bank->driver->probe(master_bank); if (retval != ERROR_OK) return retval; /* update the info we do not have */ virtual_update_bank_info(bank); return ERROR_OK; } static int virtual_auto_probe(struct flash_bank *bank) { struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ retval = master_bank->driver->auto_probe(master_bank); if (retval != ERROR_OK) return retval; /* update the info we do not have */ virtual_update_bank_info(bank); return ERROR_OK; } static int virtual_info(struct flash_bank *bank, struct command_invocation *cmd) { struct flash_bank *master_bank = virtual_get_master_bank(bank); if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; command_print_sameline(cmd, "%s driver for flash bank %s at " TARGET_ADDR_FMT, bank->driver->name, master_bank->name, master_bank->base); return ERROR_OK; } static int virtual_blank_check(struct flash_bank *bank) { struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ retval = master_bank->driver->erase_check(master_bank); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int virtual_flash_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ retval = master_bank->driver->read(master_bank, buffer, offset, count); if (retval != ERROR_OK) return retval; return ERROR_OK; } const struct flash_driver virtual_flash = { .name = "virtual", .flash_bank_command = virtual_flash_bank_command, .erase = virtual_erase, .protect = virtual_protect, .write = virtual_write, .read = virtual_flash_read, .probe = virtual_probe, .auto_probe = virtual_auto_probe, .erase_check = virtual_blank_check, .protect_check = virtual_protect_check, .info = virtual_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/w600.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2018 by Simon Qian * * SimonQian@SimonQian.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> #define W600_FLASH_SECSIZE 0x1000 #define W600_FLASH_PAGESIZE 0x100 #define W600_FLASH_BASE 0x08000000 #define W600_FLASH_PROTECT_SIZE 0x2000 /* w600 register locations */ #define QFLASH_REGBASE 0X40002000 #define QFLASH_CMD_INFO (QFLASH_REGBASE + 0) #define QFLASH_CMD_START (QFLASH_REGBASE + 4) #define QFLASH_BUFFER (QFLASH_REGBASE + 0X200) #define QFLASH_CMD_READ (1ul << 14) #define QFLASH_CMD_WRITE 0 #define QFLASH_CMD_ADDR (1ul << 31) #define QFLASH_CMD_DATA (1ul << 15) #define QFLASH_CMD_DATALEN(len) (((len) & 0x3FF) << 16) #define QFLASH_CMD_RDID (QFLASH_CMD_READ | 0x9F) #define QFLASH_CMD_WREN (QFLASH_CMD_WRITE | 0x06) #define QFLASH_CMD_WRDI (QFLASH_CMD_WRITE | 0x04) #define QFLASH_CMD_SE (QFLASH_CMD_WRITE | QFLASH_CMD_ADDR | (1ul << 11) | 0x20) #define QFLASH_CMD_PP (QFLASH_CMD_WRITE | QFLASH_CMD_ADDR | (1ul << 12) | 0x02) #define QFLASH_START (1ul << 28) #define QFLASH_ADDR(addr) (((addr) & 0xFFFFF) << 8) #define QFLASH_CRM(crm) (((crm) & 0xFF) << 0) struct w600_flash_param { uint8_t id; uint8_t se_delay; uint8_t pp_delay; }; static const struct w600_flash_param w600_param[] = { { .id = 0x85, .se_delay = 8, .pp_delay = 2, }, { .id = 0x1C, .se_delay = 50, .pp_delay = 1, }, { .id = 0xC8, .se_delay = 45, .pp_delay = 1, }, { .id = 0x0B, .se_delay = 60, .pp_delay = 1, }, { .id = 0x68, .se_delay = 50, .pp_delay = 1, }, }; struct w600_flash_bank { bool probed; uint32_t id; const struct w600_flash_param *param; uint32_t register_base; uint32_t user_bank_size; }; /* flash bank w600 <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(w600_flash_bank_command) { struct w600_flash_bank *w600_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; w600_info = malloc(sizeof(struct w600_flash_bank)); bank->driver_priv = w600_info; w600_info->probed = false; w600_info->register_base = QFLASH_REGBASE; w600_info->user_bank_size = bank->size; return ERROR_OK; } static int w600_get_delay(struct flash_bank *bank, uint32_t cmd) { struct w600_flash_bank *w600_info = bank->driver_priv; if (!w600_info->param) return 0; switch (cmd) { case QFLASH_CMD_SE: return w600_info->param->se_delay; case QFLASH_CMD_PP: return w600_info->param->pp_delay; default: return 0; } } static int w600_start_do(struct flash_bank *bank, uint32_t cmd, uint32_t addr, uint32_t len, int timeout) { struct target *target = bank->target; if (len > 0) cmd |= QFLASH_CMD_DATALEN(len - 1) | QFLASH_CMD_DATA; LOG_DEBUG("WRITE CMD: 0x%08" PRIx32 "", cmd); int retval = target_write_u32(target, QFLASH_CMD_INFO, cmd); if (retval != ERROR_OK) return retval; addr |= QFLASH_START; LOG_DEBUG("WRITE START: 0x%08" PRIx32 "", addr); retval = target_write_u32(target, QFLASH_CMD_START, addr); if (retval != ERROR_OK) return retval; LOG_DEBUG("DELAY %dms", timeout); alive_sleep(timeout); int retry = 100; uint32_t status; for (;;) { LOG_DEBUG("READ START..."); retval = target_read_u32(target, QFLASH_CMD_START, &status); if (retval == ERROR_OK) LOG_DEBUG("READ START: 0x%08" PRIx32 "", status); else LOG_DEBUG("READ START FAILED"); if ((retval != ERROR_OK) || (status & QFLASH_START)) { if (retry-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FAIL; } continue; } break; } return retval; } static int w600_write_enable(struct flash_bank *bank) { return w600_start_do(bank, QFLASH_CMD_WREN, 0, 0, 0); } static int w600_write_disable(struct flash_bank *bank) { return w600_start_do(bank, QFLASH_CMD_WRDI, 0, 0, 0); } static int w600_start(struct flash_bank *bank, uint32_t cmd, uint32_t addr, uint32_t len) { int retval = w600_write_enable(bank); if (retval != ERROR_OK) return retval; retval = w600_start_do(bank, cmd, addr, len, w600_get_delay(bank, cmd)); if (retval != ERROR_OK) return retval; retval = w600_write_disable(bank); if (retval != ERROR_OK) return retval; return retval; } static int w600_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int retval = ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (first < W600_FLASH_PROTECT_SIZE / W600_FLASH_SECSIZE) { LOG_ERROR("can not erase protected area"); return ERROR_FAIL; } for (unsigned int i = first; i <= last; i++) { retval = w600_start(bank, QFLASH_CMD_SE, QFLASH_ADDR(bank->sectors[i].offset), 0); if (retval != ERROR_OK) break; } return retval; } static int w600_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; int retval = ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((offset % W600_FLASH_PAGESIZE) != 0) { LOG_WARNING("offset 0x%" PRIx32 " breaks required %d-byte alignment", offset, W600_FLASH_PAGESIZE); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } if ((count % W600_FLASH_PAGESIZE) != 0) { LOG_WARNING("count 0x%" PRIx32 " breaks required %d-byte alignment", offset, W600_FLASH_PAGESIZE); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } while (count > 0) { retval = target_write_buffer(target, QFLASH_BUFFER, W600_FLASH_PAGESIZE, buffer); if (retval != ERROR_OK) break; retval = w600_start(bank, QFLASH_CMD_PP, QFLASH_ADDR(offset), W600_FLASH_PAGESIZE); if (retval != ERROR_OK) break; count -= W600_FLASH_PAGESIZE; offset += W600_FLASH_PAGESIZE; buffer += W600_FLASH_PAGESIZE; } return retval; } static int w600_get_flash_id(struct flash_bank *bank, uint32_t *flash_id) { struct target *target = bank->target; int retval = w600_start(bank, QFLASH_CMD_RDID, 0, 4); if (retval != ERROR_OK) return retval; return target_read_u32(target, QFLASH_BUFFER, flash_id); } static int w600_probe(struct flash_bank *bank) { struct w600_flash_bank *w600_info = bank->driver_priv; uint32_t flash_size; uint32_t flash_id; size_t i; w600_info->probed = false; /* read stm32 device id register */ int retval = w600_get_flash_id(bank, &flash_id); if (retval != ERROR_OK) return retval; LOG_INFO("flash_id id = 0x%08" PRIx32 "", flash_id); w600_info->id = flash_id; w600_info->param = NULL; for (i = 0; i < ARRAY_SIZE(w600_param); i++) { if (w600_param[i].id == (flash_id & 0xFF)) { w600_info->param = &w600_param[i]; break; } } if (!w600_info->param) { LOG_ERROR("flash_id not supported for w600"); return ERROR_FAIL; } /* if the user sets the size manually then ignore the probed value * this allows us to work around devices that have a invalid flash size register value */ if (w600_info->user_bank_size) { LOG_INFO("ignoring flash probed value, using configured bank size"); flash_size = w600_info->user_bank_size; } else { flash_size = ((flash_id & 0xFFFFFF) >> 16) & 0xFF; if ((flash_size != 0x14) && (flash_size != 0x13)) { LOG_ERROR("w600 flash size failed, probe inaccurate"); return ERROR_FAIL; } flash_size = 1 << flash_size; } LOG_INFO("flash size = %" PRIu32 " KiB", flash_size / 1024); /* calculate numbers of pages */ size_t num_pages = flash_size / W600_FLASH_SECSIZE; /* check that calculation result makes sense */ assert(num_pages > 0); free(bank->sectors); bank->sectors = NULL; bank->base = W600_FLASH_BASE; bank->size = num_pages * W600_FLASH_SECSIZE; bank->num_sectors = num_pages; bank->write_start_alignment = W600_FLASH_PAGESIZE; bank->write_end_alignment = W600_FLASH_PAGESIZE; bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); for (i = 0; i < num_pages; i++) { bank->sectors[i].offset = i * W600_FLASH_SECSIZE; bank->sectors[i].size = W600_FLASH_SECSIZE; bank->sectors[i].is_erased = -1; /* offset 0 to W600_FLASH_PROTECT_SIZE should be protected */ bank->sectors[i].is_protected = (i < W600_FLASH_PROTECT_SIZE / W600_FLASH_SECSIZE); } w600_info->probed = true; return ERROR_OK; } static int w600_auto_probe(struct flash_bank *bank) { struct w600_flash_bank *w600_info = bank->driver_priv; if (w600_info->probed) return ERROR_OK; return w600_probe(bank); } static int get_w600_info(struct flash_bank *bank, struct command_invocation *cmd) { uint32_t flash_id; /* read w600 device id register */ int retval = w600_get_flash_id(bank, &flash_id); if (retval != ERROR_OK) return retval; command_print_sameline(cmd, "w600 : 0x%08" PRIx32 "", flash_id); return ERROR_OK; } const struct flash_driver w600_flash = { .name = "w600", .flash_bank_command = w600_flash_bank_command, .erase = w600_erase, .write = w600_write, .read = default_flash_read, .probe = w600_probe, .auto_probe = w600_auto_probe, .erase_check = default_flash_blank_check, .info = get_w600_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/xcf.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2016 by Uladzimir Pylinski aka barthess * * barthess@yandex.ru * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <string.h> #include "imp.h" #include <jtag/jtag.h> #include <helper/time_support.h> /* ****************************************************************************** * DEFINES ****************************************************************************** */ #define SECTOR_ERASE_TIMEOUT_MS (35 * 1000) #define XCF_PAGE_SIZE 32 #define XCF_DATA_SECTOR_SIZE (1024 * 1024) #define ID_XCF01S 0x05044093 #define ID_XCF02S 0x05045093 #define ID_XCF04S 0x05046093 #define ID_XCF08P 0x05057093 #define ID_XCF16P 0x05058093 #define ID_XCF32P 0x05059093 #define ID_MEANINGFUL_MASK 0x0FFFFFFF static const char * const xcf_name_list[] = { "XCF08P", "XCF16P", "XCF32P", "unknown" }; struct xcf_priv { bool probed; }; struct xcf_status { bool isc_error; /* false == OK, true == error */ bool prog_error; /* false == OK, true == error */ bool prog_busy; /* false == idle, true == busy */ bool isc_mode; /* false == normal mode, true == ISC mode */ }; /* ****************************************************************************** * GLOBAL VARIABLES ****************************************************************************** */ static const uint8_t cmd_bypass[2] = {0xFF, 0xFF}; static const uint8_t cmd_isc_address_shift[2] = {0xEB, 0x00}; static const uint8_t cmd_isc_data_shift[2] = {0xED, 0x00}; static const uint8_t cmd_isc_disable[2] = {0xF0, 0x00}; static const uint8_t cmd_isc_enable[2] = {0xE8, 0x00}; static const uint8_t cmd_isc_erase[2] = {0xEC, 0x00}; static const uint8_t cmd_isc_program[2] = {0xEA, 0x00}; static const uint8_t cmd_xsc_blank_check[2] = {0x0D, 0x00}; static const uint8_t cmd_xsc_config[2] = {0xEE, 0x00}; static const uint8_t cmd_xsc_data_btc[2] = {0xF2, 0x00}; static const uint8_t cmd_xsc_data_ccb[2] = {0x0C, 0x00}; static const uint8_t cmd_xsc_data_done[2] = {0x09, 0x00}; static const uint8_t cmd_xsc_data_sucr[2] = {0x0E, 0x00}; static const uint8_t cmd_xsc_data_wrpt[2] = {0xF7, 0x00}; static const uint8_t cmd_xsc_op_status[2] = {0xE3, 0x00}; static const uint8_t cmd_xsc_read[2] = {0xEF, 0x00}; static const uint8_t cmd_xsc_unlock[2] = {0x55, 0xAA}; /* ****************************************************************************** * LOCAL FUNCTIONS ****************************************************************************** */ static const char *product_name(const struct flash_bank *bank) { switch (bank->target->tap->idcode & ID_MEANINGFUL_MASK) { case ID_XCF08P: return xcf_name_list[0]; case ID_XCF16P: return xcf_name_list[1]; case ID_XCF32P: return xcf_name_list[2]; default: return xcf_name_list[3]; } } static void fill_sector_table(struct flash_bank *bank) { /* Note: is_erased and is_protected fields must be set here to an unknown * state, they will be correctly filled from other API calls. */ for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].size = XCF_DATA_SECTOR_SIZE; bank->sectors[i].offset = i * XCF_DATA_SECTOR_SIZE; } bank->size = bank->num_sectors * XCF_DATA_SECTOR_SIZE; } static struct xcf_status read_status(struct flash_bank *bank) { struct xcf_status ret; uint8_t irdata[2]; struct scan_field scan; scan.check_mask = NULL; scan.check_value = NULL; scan.num_bits = 16; scan.out_value = cmd_bypass; scan.in_value = irdata; jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); jtag_execute_queue(); ret.isc_error = ((irdata[0] >> 7) & 3) == 0b01; ret.prog_error = ((irdata[0] >> 5) & 3) == 0b01; ret.prog_busy = ((irdata[0] >> 4) & 1) == 0; ret.isc_mode = ((irdata[0] >> 3) & 1) == 1; return ret; } static int isc_enter(struct flash_bank *bank) { struct xcf_status status = read_status(bank); if (true == status.isc_mode) return ERROR_OK; else { struct scan_field scan; scan.check_mask = NULL; scan.check_value = NULL; scan.num_bits = 16; scan.out_value = cmd_isc_enable; scan.in_value = NULL; jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); jtag_execute_queue(); status = read_status(bank); if (!status.isc_mode) { LOG_ERROR("*** XCF: FAILED to enter ISC mode"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } } static int isc_leave(struct flash_bank *bank) { struct xcf_status status = read_status(bank); if (!status.isc_mode) return ERROR_OK; else { struct scan_field scan; scan.check_mask = NULL; scan.check_value = NULL; scan.num_bits = 16; scan.out_value = cmd_isc_disable; scan.in_value = NULL; jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); jtag_execute_queue(); alive_sleep(1); /* device needs 50 uS to leave ISC mode */ status = read_status(bank); if (status.isc_mode) { LOG_ERROR("*** XCF: FAILED to leave ISC mode"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } } static int sector_state(uint8_t wrpt, int sector) { if (((wrpt >> sector) & 1) == 1) return 0; else return 1; } static uint8_t fill_select_block(unsigned int first, unsigned int last) { uint8_t ret = 0; for (unsigned int i = first; i <= last; i++) ret |= 1 << i; return ret; } static int isc_read_register(struct flash_bank *bank, const uint8_t *cmd, uint8_t *data_buf, int num_bits) { struct scan_field scan; scan.check_mask = NULL; scan.check_value = NULL; scan.out_value = cmd; scan.in_value = NULL; scan.num_bits = 16; jtag_add_ir_scan(bank->target->tap, &scan, TAP_DRSHIFT); scan.out_value = NULL; scan.in_value = data_buf; scan.num_bits = num_bits; jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IDLE); return jtag_execute_queue(); } static int isc_wait_erase_program(struct flash_bank *bank, int64_t timeout_ms) { uint8_t isc_default; int64_t t0 = timeval_ms(); int64_t dt; do { isc_read_register(bank, cmd_xsc_op_status, &isc_default, 8); if (((isc_default >> 2) & 1) == 1) return ERROR_OK; dt = timeval_ms() - t0; } while (dt <= timeout_ms); return ERROR_FLASH_OPERATION_FAILED; } /* * helper function for procedures without program jtag command at the end */ static int isc_set_register(struct flash_bank *bank, const uint8_t *cmd, const uint8_t *data_buf, int num_bits, int64_t timeout_ms) { struct scan_field scan; scan.check_mask = NULL; scan.check_value = NULL; scan.num_bits = 16; scan.out_value = cmd; scan.in_value = NULL; jtag_add_ir_scan(bank->target->tap, &scan, TAP_DRSHIFT); scan.num_bits = num_bits; scan.out_value = data_buf; scan.in_value = NULL; jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IDLE); if (timeout_ms == 0) return jtag_execute_queue(); else return isc_wait_erase_program(bank, timeout_ms); } /* * helper function for procedures required program jtag command at the end */ static int isc_program_register(struct flash_bank *bank, const uint8_t *cmd, const uint8_t *data_buf, int num_bits, int64_t timeout_ms) { struct scan_field scan; scan.check_mask = NULL; scan.check_value = NULL; scan.num_bits = 16; scan.out_value = cmd; scan.in_value = NULL; jtag_add_ir_scan(bank->target->tap, &scan, TAP_DRSHIFT); scan.num_bits = num_bits; scan.out_value = data_buf; scan.in_value = NULL; jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IRSHIFT); scan.num_bits = 16; scan.out_value = cmd_isc_program; scan.in_value = NULL; jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); if (timeout_ms == 0) return jtag_execute_queue(); else return isc_wait_erase_program(bank, timeout_ms); } static int isc_clear_protect(struct flash_bank *bank, unsigned int first, unsigned int last) { uint8_t select_block[3] = {0x0, 0x0, 0x0}; select_block[0] = fill_select_block(first, last); return isc_set_register(bank, cmd_xsc_unlock, select_block, 24, 0); } static int isc_set_protect(struct flash_bank *bank, unsigned int first, unsigned int last) { uint8_t wrpt[2] = {0xFF, 0xFF}; for (unsigned int i = first; i <= last; i++) wrpt[0] &= ~(1 << i); return isc_program_register(bank, cmd_xsc_data_wrpt, wrpt, 16, 0); } static int isc_erase_sectors(struct flash_bank *bank, unsigned int first, unsigned int last) { uint8_t select_block[3] = {0, 0, 0}; select_block[0] = fill_select_block(first, last); int64_t timeout = SECTOR_ERASE_TIMEOUT_MS * (last - first + 1); return isc_set_register(bank, cmd_isc_erase, select_block, 24, timeout); } static int isc_adr_shift(struct flash_bank *bank, int adr) { uint8_t adr_buf[3]; h_u24_to_le(adr_buf, adr); return isc_set_register(bank, cmd_isc_address_shift, adr_buf, 24, 0); } static int isc_program_data_page(struct flash_bank *bank, const uint8_t *page_buf) { return isc_program_register(bank, cmd_isc_data_shift, page_buf, 8 * XCF_PAGE_SIZE, 100); } static void isc_data_read_out(struct flash_bank *bank, uint8_t *buffer, uint32_t count) { struct scan_field scan; /* Do not change this code with isc_read_register() call because it needs * transition to IDLE state before data retrieving. */ scan.check_mask = NULL; scan.check_value = NULL; scan.num_bits = 16; scan.out_value = cmd_xsc_read; scan.in_value = NULL; jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); scan.num_bits = 8 * count; scan.out_value = NULL; scan.in_value = buffer; jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IDLE); jtag_execute_queue(); } static int isc_set_data_done(struct flash_bank *bank, int sector) { uint8_t done = 0xFF; done &= ~(1 << sector); return isc_program_register(bank, cmd_xsc_data_done, &done, 8, 100); } static void flip_u8(uint8_t *out, const uint8_t *in, int len) { for (int i = 0; i < len; i++) out[i] = flip_u32(in[i], 8); } /* * Xilinx bin file contains simple fixed header for automatic bus width detection: * 16 bytes of 0xFF * 4 byte sync word 0xAA995566 or (bit reversed) 0x5599AA66 in MSC file * * Function presumes need of bit reversing if it can not exactly detects * the opposite. */ static bool need_bit_reverse(const uint8_t *buffer) { const size_t L = 20; uint8_t reference[L]; memset(reference, 0xFF, 16); reference[16] = 0x55; reference[17] = 0x99; reference[18] = 0xAA; reference[19] = 0x66; if (memcmp(reference, buffer, L) == 0) return false; else return true; } /* * The page address to be programmed is determined by loading the * internal ADDRESS Register using an ISC_ADDRESS_SHIFT instruction sequence. * The page address automatically increments to the next 256-bit * page address after each programming sequence until the last address * in the 8 Mb block is reached. To continue programming the next block, * the next 8 Mb block's starting address must be loaded into the * internal ADDRESS register. */ static int read_write_data(struct flash_bank *bank, const uint8_t *w_buffer, uint8_t *r_buffer, bool write_flag, uint32_t offset, uint32_t count) { int dbg_count = count; int dbg_written = 0; int ret = ERROR_OK; uint8_t *page_buf = malloc(XCF_PAGE_SIZE); bool revbit = true; isc_enter(bank); if (offset % XCF_PAGE_SIZE != 0) { ret = ERROR_FLASH_DST_BREAKS_ALIGNMENT; goto EXIT; } if ((offset + count) > (bank->num_sectors * XCF_DATA_SECTOR_SIZE)) { ret = ERROR_FLASH_DST_OUT_OF_BANK; goto EXIT; } if ((write_flag) && (offset == 0) && (count >= XCF_PAGE_SIZE)) revbit = need_bit_reverse(w_buffer); while (count > 0) { uint32_t sector_num = offset / XCF_DATA_SECTOR_SIZE; uint32_t sector_offset = offset - sector_num * XCF_DATA_SECTOR_SIZE; uint32_t sector_bytes = XCF_DATA_SECTOR_SIZE - sector_offset; if (count < sector_bytes) sector_bytes = count; isc_adr_shift(bank, offset); offset += sector_bytes; count -= sector_bytes; if (write_flag) { while (sector_bytes > 0) { int len; if (sector_bytes < XCF_PAGE_SIZE) { len = sector_bytes; memset(page_buf, 0xFF, XCF_PAGE_SIZE); } else len = XCF_PAGE_SIZE; if (revbit) flip_u8(page_buf, w_buffer, len); else memcpy(page_buf, w_buffer, len); w_buffer += len; sector_bytes -= len; ret = isc_program_data_page(bank, page_buf); if (ret != ERROR_OK) goto EXIT; else { LOG_DEBUG("written %d bytes from %d", dbg_written, dbg_count); dbg_written += len; } } } else { isc_data_read_out(bank, r_buffer, sector_bytes); flip_u8(r_buffer, r_buffer, sector_bytes); r_buffer += sector_bytes; } } /* Set 'done' flags for all data sectors because driver supports * only single revision. */ if (write_flag) { for (unsigned int i = 0; i < bank->num_sectors; i++) { ret = isc_set_data_done(bank, i); if (ret != ERROR_OK) goto EXIT; } } EXIT: free(page_buf); isc_leave(bank); return ret; } static uint16_t isc_read_ccb(struct flash_bank *bank) { uint8_t ccb[2]; isc_read_register(bank, cmd_xsc_data_ccb, ccb, 16); return le_to_h_u16(ccb); } static unsigned int gucr_num(const struct flash_bank *bank) { return bank->num_sectors; } static unsigned int sucr_num(const struct flash_bank *bank) { return bank->num_sectors + 1; } static int isc_program_ccb(struct flash_bank *bank, uint16_t ccb) { uint8_t buf[2]; h_u16_to_le(buf, ccb); return isc_program_register(bank, cmd_xsc_data_ccb, buf, 16, 100); } static int isc_program_singe_revision_sucr(struct flash_bank *bank) { uint8_t sucr[2] = {0xFC, 0xFF}; return isc_program_register(bank, cmd_xsc_data_sucr, sucr, 16, 100); } static int isc_program_single_revision_btc(struct flash_bank *bank) { uint8_t buf[4]; uint32_t btc = 0xFFFFFFFF; btc &= ~0b1111; btc |= ((bank->num_sectors - 1) << 2); btc &= ~(1 << 4); h_u32_to_le(buf, btc); return isc_program_register(bank, cmd_xsc_data_btc, buf, 32, 100); } static int fpga_configure(struct flash_bank *bank) { struct scan_field scan; scan.check_mask = NULL; scan.check_value = NULL; scan.num_bits = 16; scan.out_value = cmd_xsc_config; scan.in_value = NULL; jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); jtag_execute_queue(); return ERROR_OK; } /* ****************************************************************************** * EXPORTED FUNCTIONS ****************************************************************************** */ FLASH_BANK_COMMAND_HANDLER(xcf_flash_bank_command) { struct xcf_priv *priv; priv = malloc(sizeof(struct xcf_priv)); if (!priv) { LOG_ERROR("no memory for flash bank info"); return ERROR_FAIL; } bank->driver_priv = priv; priv->probed = false; return ERROR_OK; } static int xcf_info(struct flash_bank *bank, struct command_invocation *cmd) { const struct xcf_priv *priv = bank->driver_priv; if (!priv->probed) { command_print_sameline(cmd, "\nXCF flash bank not probed yet\n"); return ERROR_OK; } command_print_sameline(cmd, "%s", product_name(bank)); return ERROR_OK; } static int xcf_probe(struct flash_bank *bank) { struct xcf_priv *priv = bank->driver_priv; uint32_t id; if (priv->probed) free(bank->sectors); priv->probed = false; if (!bank->target->tap) { LOG_ERROR("Target has no JTAG tap"); return ERROR_FAIL; } /* check idcode and alloc memory for sector table */ if (!bank->target->tap->hasidcode) return ERROR_FLASH_OPERATION_FAILED; /* guess number of blocks using chip ID */ id = bank->target->tap->idcode; switch (id & ID_MEANINGFUL_MASK) { case ID_XCF08P: bank->num_sectors = 1; break; case ID_XCF16P: bank->num_sectors = 2; break; case ID_XCF32P: bank->num_sectors = 4; break; default: LOG_ERROR("Unknown flash device ID 0x%" PRIX32, id); return ERROR_FAIL; } bank->sectors = malloc(bank->num_sectors * sizeof(struct flash_sector)); if (!bank->sectors) { LOG_ERROR("No memory for sector table"); return ERROR_FAIL; } fill_sector_table(bank); priv->probed = true; /* REVISIT: Why is unchanged bank->driver_priv rewritten by same value? */ bank->driver_priv = priv; LOG_INFO("product name: %s", product_name(bank)); LOG_INFO("device id = 0x%" PRIX32, bank->target->tap->idcode); LOG_INFO("flash size = %d configuration bits", bank->num_sectors * XCF_DATA_SECTOR_SIZE * 8); LOG_INFO("number of sectors = %u", bank->num_sectors); return ERROR_OK; } static int xcf_auto_probe(struct flash_bank *bank) { struct xcf_priv *priv = bank->driver_priv; if (priv->probed) return ERROR_OK; else return xcf_probe(bank); } static int xcf_protect_check(struct flash_bank *bank) { uint8_t wrpt[2]; isc_enter(bank); isc_read_register(bank, cmd_xsc_data_wrpt, wrpt, 16); isc_leave(bank); for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = sector_state(wrpt[0], i); return ERROR_OK; } static int xcf_erase_check(struct flash_bank *bank) { uint8_t blankreg; struct scan_field scan; isc_enter(bank); /* Do not change this code with isc_read_register() call because it needs * transition to IDLE state and pause before data retrieving. */ scan.check_mask = NULL; scan.check_value = NULL; scan.num_bits = 16; scan.out_value = cmd_xsc_blank_check; scan.in_value = NULL; jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); jtag_execute_queue(); alive_sleep(500); /* device needs at least 0.5s to self check */ scan.num_bits = 8; scan.in_value = &blankreg; jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IDLE); jtag_execute_queue(); isc_leave(bank); for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = sector_state(blankreg, i); return ERROR_OK; } static int xcf_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { if ((first >= bank->num_sectors) || (last >= bank->num_sectors) || (last < first)) return ERROR_FLASH_SECTOR_INVALID; else { isc_enter(bank); isc_clear_protect(bank, first, last); int ret = isc_erase_sectors(bank, first, last); isc_leave(bank); return ret; } } static int xcf_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { return read_write_data(bank, NULL, buffer, false, offset, count); } static int xcf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { return read_write_data(bank, buffer, NULL, true, offset, count); } static int xcf_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int ret; isc_enter(bank); if (set) ret = isc_set_protect(bank, first, last); else { /* write protection may be removed only with following erase */ isc_clear_protect(bank, first, last); ret = isc_erase_sectors(bank, first, last); } isc_leave(bank); return ret; } COMMAND_HANDLER(xcf_handle_ccb_command) { if (!((CMD_ARGC == 1) || (CMD_ARGC == 5))) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; uint16_t ccb = 0xFFFF; isc_enter(bank); uint16_t old_ccb = isc_read_ccb(bank); isc_leave(bank); if (CMD_ARGC == 1) { LOG_INFO("current CCB = 0x%X", old_ccb); return ERROR_OK; } else { /* skip over flash bank */ CMD_ARGC--; CMD_ARGV++; while (CMD_ARGC) { if (strcmp("external", CMD_ARGV[0]) == 0) ccb |= (1 << 0); else if (strcmp("internal", CMD_ARGV[0]) == 0) ccb &= ~(1 << 0); else if (strcmp("serial", CMD_ARGV[0]) == 0) ccb |= (3 << 1); else if (strcmp("parallel", CMD_ARGV[0]) == 0) ccb &= ~(3 << 1); else if (strcmp("slave", CMD_ARGV[0]) == 0) ccb |= (1 << 3); else if (strcmp("master", CMD_ARGV[0]) == 0) ccb &= ~(1 << 3); else if (strcmp("40", CMD_ARGV[0]) == 0) ccb |= (3 << 4); else if (strcmp("20", CMD_ARGV[0]) == 0) ccb &= ~(1 << 5); else return ERROR_COMMAND_SYNTAX_ERROR; CMD_ARGC--; CMD_ARGV++; } isc_enter(bank); int sector; /* GUCR sector */ sector = gucr_num(bank); isc_clear_protect(bank, sector, sector); int ret = isc_erase_sectors(bank, sector, sector); if (ret != ERROR_OK) goto EXIT; ret = isc_program_ccb(bank, ccb); if (ret != ERROR_OK) goto EXIT; ret = isc_program_single_revision_btc(bank); if (ret != ERROR_OK) goto EXIT; ret = isc_set_data_done(bank, sector); if (ret != ERROR_OK) goto EXIT; /* SUCR sector */ sector = sucr_num(bank); isc_clear_protect(bank, sector, sector); ret = isc_erase_sectors(bank, sector, sector); if (ret != ERROR_OK) goto EXIT; ret = isc_program_singe_revision_sucr(bank); if (ret != ERROR_OK) goto EXIT; ret = isc_set_data_done(bank, sector); if (ret != ERROR_OK) goto EXIT; EXIT: isc_leave(bank); return ret; } } COMMAND_HANDLER(xcf_handle_configure_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; return fpga_configure(bank); } static const struct command_registration xcf_exec_command_handlers[] = { { .name = "configure", .handler = xcf_handle_configure_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Initiate FPGA loading procedure." }, { .name = "ccb", .handler = xcf_handle_ccb_command, .mode = COMMAND_EXEC, .usage = "bank_id [('external'|'internal') " "('serial'|'parallel') " "('slave'|'master') " "('40'|'20')]", .help = "Write CCB register with supplied options and (silently) BTC " "register with single revision options. Display current " "CCB value when only bank_id supplied. " "Following options available: " "1) external or internal clock source; " "2) serial or parallel bus mode; " "3) slave or master mode; " "4) clock frequency in MHz for internal clock in master mode;" }, COMMAND_REGISTRATION_DONE }; static const struct command_registration xcf_command_handlers[] = { { .name = "xcf", .mode = COMMAND_ANY, .help = "Xilinx platform flash command group", .usage = "", .chain = xcf_exec_command_handlers }, COMMAND_REGISTRATION_DONE }; const struct flash_driver xcf_flash = { .name = "xcf", .usage = NULL, .commands = xcf_command_handlers, .flash_bank_command = xcf_flash_bank_command, .erase = xcf_erase, .protect = xcf_protect, .write = xcf_write, .read = xcf_read, .probe = xcf_probe, .auto_probe = xcf_auto_probe, .erase_check = xcf_erase_check, .protect_check = xcf_protect_check, .info = xcf_info, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/xmc1xxx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * XMC1000 flash driver * * Copyright (c) 2016 Andreas Färber */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/align.h> #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> #define FLASH_BASE 0x10000000 #define PAU_BASE 0x40000000 #define SCU_BASE 0x40010000 #define NVM_BASE 0x40050000 #define FLASH_CS0 (FLASH_BASE + 0xf00) #define PAU_FLSIZE (PAU_BASE + 0x404) #define SCU_IDCHIP (SCU_BASE + 0x004) #define NVMSTATUS (NVM_BASE + 0x00) #define NVMPROG (NVM_BASE + 0x04) #define NVMCONF (NVM_BASE + 0x08) #define NVMSTATUS_BUSY (1 << 0) #define NVMSTATUS_VERR_MASK (0x3 << 2) #define NVMPROG_ACTION_OPTYPE_IDLE_VERIFY (0 << 0) #define NVMPROG_ACTION_OPTYPE_WRITE (1 << 0) #define NVMPROG_ACTION_OPTYPE_PAGE_ERASE (2 << 0) #define NVMPROG_ACTION_ONE_SHOT_ONCE (1 << 4) #define NVMPROG_ACTION_ONE_SHOT_CONTINUOUS (2 << 4) #define NVMPROG_ACTION_VERIFY_EACH (1 << 6) #define NVMPROG_ACTION_VERIFY_NO (2 << 6) #define NVMPROG_ACTION_VERIFY_ARRAY (3 << 6) #define NVMPROG_ACTION_IDLE 0x00 #define NVMPROG_ACTION_MASK 0xff #define NVM_WORD_SIZE 4 #define NVM_BLOCK_SIZE (4 * NVM_WORD_SIZE) #define NVM_PAGE_SIZE (16 * NVM_BLOCK_SIZE) struct xmc1xxx_flash_bank { bool probed; }; static int xmc1xxx_nvm_set_idle(struct target *target) { return target_write_u16(target, NVMPROG, NVMPROG_ACTION_IDLE); } static int xmc1xxx_nvm_check_idle(struct target *target) { uint16_t val; int retval; retval = target_read_u16(target, NVMPROG, &val); if (retval != ERROR_OK) return retval; if ((val & NVMPROG_ACTION_MASK) != NVMPROG_ACTION_IDLE) { LOG_WARNING("NVMPROG.ACTION"); retval = xmc1xxx_nvm_set_idle(target); } return retval; } static int xmc1xxx_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct target *target = bank->target; struct working_area *workarea; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_algo; unsigned i; int retval; const uint8_t erase_code[] = { #include "../../../contrib/loaders/flash/xmc1xxx/erase.inc" }; LOG_DEBUG("Infineon XMC1000 erase sectors %u to %u", first, last); if (bank->target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } retval = xmc1xxx_nvm_check_idle(target); if (retval != ERROR_OK) return retval; retval = target_alloc_working_area(target, sizeof(erase_code), &workarea); if (retval != ERROR_OK) { LOG_ERROR("No working area available."); retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; goto err_alloc_code; } retval = target_write_buffer(target, workarea->address, sizeof(erase_code), erase_code); if (retval != ERROR_OK) goto err_write_code; armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC; armv7m_algo.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, NVM_BASE); buf_set_u32(reg_params[1].value, 0, 32, bank->base + bank->sectors[first].offset); buf_set_u32(reg_params[2].value, 0, 32, bank->base + bank->sectors[last].offset + bank->sectors[last].size); retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, workarea->address, 0, 1000, &armv7m_algo); if (retval != ERROR_OK) { LOG_ERROR("Error executing flash sector erase " "programming algorithm"); retval = xmc1xxx_nvm_set_idle(target); if (retval != ERROR_OK) LOG_WARNING("Couldn't restore NVMPROG.ACTION"); retval = ERROR_FLASH_OPERATION_FAILED; goto err_run; } err_run: for (i = 0; i < ARRAY_SIZE(reg_params); i++) destroy_reg_param(®_params[i]); err_write_code: target_free_working_area(target, workarea); err_alloc_code: return retval; } static int xmc1xxx_erase_check(struct flash_bank *bank) { struct target *target = bank->target; struct working_area *workarea; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_algo; uint16_t val; unsigned i; int retval; const uint8_t erase_check_code[] = { #include "../../../contrib/loaders/flash/xmc1xxx/erase_check.inc" }; if (bank->target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } retval = target_alloc_working_area(target, sizeof(erase_check_code), &workarea); if (retval != ERROR_OK) { LOG_ERROR("No working area available."); retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; goto err_alloc_code; } retval = target_write_buffer(target, workarea->address, sizeof(erase_check_code), erase_check_code); if (retval != ERROR_OK) goto err_write_code; armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC; armv7m_algo.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, NVM_BASE); for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { uint32_t start = bank->base + bank->sectors[sector].offset; buf_set_u32(reg_params[1].value, 0, 32, start); buf_set_u32(reg_params[2].value, 0, 32, start + bank->sectors[sector].size); retval = xmc1xxx_nvm_check_idle(target); if (retval != ERROR_OK) goto err_nvmprog; LOG_DEBUG("Erase-checking 0x%08" PRIx32, start); retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, workarea->address, 0, 1000, &armv7m_algo); if (retval != ERROR_OK) { LOG_ERROR("Error executing flash sector erase check " "programming algorithm"); retval = xmc1xxx_nvm_set_idle(target); if (retval != ERROR_OK) LOG_WARNING("Couldn't restore NVMPROG.ACTION"); retval = ERROR_FLASH_OPERATION_FAILED; goto err_run; } retval = target_read_u16(target, NVMSTATUS, &val); if (retval != ERROR_OK) { LOG_ERROR("Couldn't read NVMSTATUS"); goto err_nvmstatus; } bank->sectors[sector].is_erased = (val & NVMSTATUS_VERR_MASK) ? 0 : 1; } err_nvmstatus: err_run: err_nvmprog: for (i = 0; i < ARRAY_SIZE(reg_params); i++) destroy_reg_param(®_params[i]); err_write_code: target_free_working_area(target, workarea); err_alloc_code: return retval; } static int xmc1xxx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t byte_count) { struct target *target = bank->target; struct working_area *code_workarea, *data_workarea; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_algo; uint32_t block_count = DIV_ROUND_UP(byte_count, NVM_BLOCK_SIZE); unsigned i; int retval; const uint8_t write_code[] = { #include "../../../contrib/loaders/flash/xmc1xxx/write.inc" }; LOG_DEBUG("Infineon XMC1000 write at 0x%08" PRIx32 " (%" PRIu32 " bytes)", offset, byte_count); if (!IS_ALIGNED(offset, NVM_BLOCK_SIZE)) { LOG_ERROR("offset 0x%" PRIx32 " breaks required block alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } if (!IS_ALIGNED(byte_count, NVM_BLOCK_SIZE)) { LOG_WARNING("length %" PRIu32 " is not block aligned, rounding up", byte_count); } if (target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } retval = target_alloc_working_area(target, sizeof(write_code), &code_workarea); if (retval != ERROR_OK) { LOG_ERROR("No working area available for write code."); retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; goto err_alloc_code; } retval = target_write_buffer(target, code_workarea->address, sizeof(write_code), write_code); if (retval != ERROR_OK) goto err_write_code; retval = target_alloc_working_area(target, MAX(NVM_BLOCK_SIZE, MIN(block_count * NVM_BLOCK_SIZE, target_get_working_area_avail(target))), &data_workarea); if (retval != ERROR_OK) { LOG_ERROR("No working area available for write data."); retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; goto err_alloc_data; } armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC; armv7m_algo.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, NVM_BASE); while (byte_count > 0) { uint32_t blocks = MIN(block_count, data_workarea->size / NVM_BLOCK_SIZE); uint32_t addr = bank->base + offset; LOG_DEBUG("copying %" PRIu32 " bytes to SRAM " TARGET_ADDR_FMT, MIN(blocks * NVM_BLOCK_SIZE, byte_count), data_workarea->address); retval = target_write_buffer(target, data_workarea->address, MIN(blocks * NVM_BLOCK_SIZE, byte_count), buffer); if (retval != ERROR_OK) { LOG_ERROR("Error writing data buffer"); retval = ERROR_FLASH_OPERATION_FAILED; goto err_write_data; } if (byte_count < blocks * NVM_BLOCK_SIZE) { retval = target_write_memory(target, data_workarea->address + byte_count, 1, blocks * NVM_BLOCK_SIZE - byte_count, &bank->default_padded_value); if (retval != ERROR_OK) { LOG_ERROR("Error writing data padding"); retval = ERROR_FLASH_OPERATION_FAILED; goto err_write_pad; } } LOG_DEBUG("writing 0x%08" PRIx32 "-0x%08" PRIx32 " (%" PRIu32 "x)", addr, addr + blocks * NVM_BLOCK_SIZE - 1, blocks); retval = xmc1xxx_nvm_check_idle(target); if (retval != ERROR_OK) goto err_nvmprog; buf_set_u32(reg_params[1].value, 0, 32, addr); buf_set_u32(reg_params[2].value, 0, 32, data_workarea->address); buf_set_u32(reg_params[3].value, 0, 32, blocks); retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, code_workarea->address, 0, 5 * 60 * 1000, &armv7m_algo); if (retval != ERROR_OK) { LOG_ERROR("Error executing flash write " "programming algorithm"); retval = xmc1xxx_nvm_set_idle(target); if (retval != ERROR_OK) LOG_WARNING("Couldn't restore NVMPROG.ACTION"); retval = ERROR_FLASH_OPERATION_FAILED; goto err_run; } block_count -= blocks; offset += blocks * NVM_BLOCK_SIZE; buffer += blocks * NVM_BLOCK_SIZE; byte_count -= MIN(blocks * NVM_BLOCK_SIZE, byte_count); } err_run: err_nvmprog: err_write_pad: err_write_data: for (i = 0; i < ARRAY_SIZE(reg_params); i++) destroy_reg_param(®_params[i]); target_free_working_area(target, data_workarea); err_alloc_data: err_write_code: target_free_working_area(target, code_workarea); err_alloc_code: return retval; } static int xmc1xxx_protect_check(struct flash_bank *bank) { uint32_t nvmconf; unsigned int num_protected; int retval; if (bank->target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } retval = target_read_u32(bank->target, NVMCONF, &nvmconf); if (retval != ERROR_OK) { LOG_ERROR("Cannot read NVMCONF register."); return retval; } LOG_DEBUG("NVMCONF = %08" PRIx32, nvmconf); num_protected = (nvmconf >> 4) & 0xff; for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = (i < num_protected) ? 1 : 0; return ERROR_OK; } static int xmc1xxx_get_info_command(struct flash_bank *bank, struct command_invocation *cmd) { uint32_t chipid[8]; int i, retval; if (bank->target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } /* Obtain the 8-word Chip Identification Number */ for (i = 0; i < 7; i++) { retval = target_read_u32(bank->target, FLASH_CS0 + i * 4, &chipid[i]); if (retval != ERROR_OK) { LOG_ERROR("Cannot read CS0 register %i.", i); return retval; } LOG_DEBUG("ID[%d] = %08" PRIX32, i, chipid[i]); } retval = target_read_u32(bank->target, SCU_BASE + 0x000, &chipid[7]); if (retval != ERROR_OK) { LOG_ERROR("Cannot read DBGROMID register."); return retval; } LOG_DEBUG("ID[7] = %08" PRIX32, chipid[7]); command_print_sameline(cmd, "XMC%" PRIx32 "00 %" PRIX32 " flash %" PRIu32 "KB ROM %" PRIu32 "KB SRAM %" PRIu32 "KB", (chipid[0] >> 12) & 0xff, 0xAA + (chipid[7] >> 28) - 1, (((chipid[6] >> 12) & 0x3f) - 1) * 4, (((chipid[4] >> 8) & 0x3f) * 256) / 1024, (((chipid[5] >> 8) & 0x1f) * 256 * 4) / 1024); return ERROR_OK; } static int xmc1xxx_probe(struct flash_bank *bank) { struct xmc1xxx_flash_bank *xmc_bank = bank->driver_priv; uint32_t flash_addr = bank->base; uint32_t idchip, flsize; int retval; if (xmc_bank->probed) return ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } retval = target_read_u32(bank->target, SCU_IDCHIP, &idchip); if (retval != ERROR_OK) { LOG_ERROR("Cannot read IDCHIP register."); return retval; } if ((idchip & 0xffff0000) != 0x10000) { LOG_ERROR("IDCHIP register does not match XMC1xxx."); return ERROR_FAIL; } LOG_DEBUG("IDCHIP = %08" PRIx32, idchip); retval = target_read_u32(bank->target, PAU_FLSIZE, &flsize); if (retval != ERROR_OK) { LOG_ERROR("Cannot read FLSIZE register."); return retval; } bank->num_sectors = 1 + ((flsize >> 12) & 0x3f) - 1; bank->size = bank->num_sectors * 4 * 1024; bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); for (unsigned int i = 0; i < bank->num_sectors; i++) { if (i == 0) { bank->sectors[i].size = 0x200; bank->sectors[i].offset = 0xE00; flash_addr += 0x1000; } else { bank->sectors[i].size = 4 * 1024; bank->sectors[i].offset = flash_addr - bank->base; flash_addr += bank->sectors[i].size; } bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } xmc_bank->probed = true; return ERROR_OK; } static int xmc1xxx_auto_probe(struct flash_bank *bank) { struct xmc1xxx_flash_bank *xmc_bank = bank->driver_priv; if (xmc_bank->probed) return ERROR_OK; return xmc1xxx_probe(bank); } FLASH_BANK_COMMAND_HANDLER(xmc1xxx_flash_bank_command) { struct xmc1xxx_flash_bank *xmc_bank; xmc_bank = malloc(sizeof(struct xmc1xxx_flash_bank)); if (!xmc_bank) return ERROR_FLASH_OPERATION_FAILED; xmc_bank->probed = false; bank->driver_priv = xmc_bank; return ERROR_OK; } const struct flash_driver xmc1xxx_flash = { .name = "xmc1xxx", .flash_bank_command = xmc1xxx_flash_bank_command, .info = xmc1xxx_get_info_command, .probe = xmc1xxx_probe, .auto_probe = xmc1xxx_auto_probe, .protect_check = xmc1xxx_protect_check, .read = default_flash_read, .erase = xmc1xxx_erase, .erase_check = xmc1xxx_erase_check, .write = xmc1xxx_write, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/nor/xmc4xxx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /************************************************************************** * Copyright (C) 2015 Jeff Ciesielski <jeffciesielski@gmail.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> /* Maximum number of sectors */ #define MAX_XMC_SECTORS 12 /* System control unit registers */ #define SCU_REG_BASE 0x50004000 #define SCU_ID_CHIP 0x04 /* Base of the non-cached flash memory */ #define PFLASH_BASE 0x0C000000 /* User configuration block offsets */ #define UCB0_BASE 0x00000000 #define UCB1_BASE 0x00000400 #define UCB2_BASE 0x00000800 /* Flash register base */ #define FLASH_REG_BASE 0x58000000 /* PMU ID Registers */ #define FLASH_REG_PMU_ID (FLASH_REG_BASE | 0x0508) /* PMU Fields */ #define PMU_MOD_REV_MASK 0xFF #define PMU_MOD_TYPE_MASK 0xFF00 #define PMU_MOD_NO_MASK 0xFFFF0000 /* Prefetch Config */ #define FLASH_REG_PREF_PCON (FLASH_REG_BASE | 0x4000) /* Prefetch Fields */ #define PCON_IBYP (1 << 0) #define PCON_IINV (1 << 1) /* Flash ID Register */ #define FLASH_REG_FLASH0_ID (FLASH_REG_BASE | 0x2008) /* Flash Status Register */ #define FLASH_REG_FLASH0_FSR (FLASH_REG_BASE | 0x2010) #define FSR_PBUSY (0) #define FSR_FABUSY (1) #define FSR_PROG (4) #define FSR_ERASE (5) #define FSR_PFPAGE (6) #define FSR_PFOPER (8) #define FSR_SQER (10) #define FSR_PROER (11) #define FSR_PFSBER (12) #define FSR_PFDBER (14) #define FSR_PROIN (16) #define FSR_RPROIN (18) #define FSR_RPRODIS (19) #define FSR_WPROIN0 (21) #define FSR_WPROIN1 (22) #define FSR_WPROIN2 (23) #define FSR_WPRODIS0 (25) #define FSR_WPRODIS1 (26) #define FSR_SLM (28) #define FSR_VER (31) #define FSR_PBUSY_MASK (0x01 << FSR_PBUSY) #define FSR_FABUSY_MASK (0x01 << FSR_FABUSY) #define FSR_PROG_MASK (0x01 << FSR_PROG) #define FSR_ERASE_MASK (0x01 << FSR_ERASE) #define FSR_PFPAGE_MASK (0x01 << FSR_PFPAGE) #define FSR_PFOPER_MASK (0x01 << FSR_PFOPER) #define FSR_SQER_MASK (0x01 << FSR_SQER) #define FSR_PROER_MASK (0x01 << FSR_PROER) #define FSR_PFSBER_MASK (0x01 << FSR_PFSBER) #define FSR_PFDBER_MASK (0x01 << FSR_PFDBER) #define FSR_PROIN_MASK (0x01 << FSR_PROIN) #define FSR_RPROIN_MASK (0x01 << FSR_RPROIN) #define FSR_RPRODIS_MASK (0x01 << FSR_RPRODIS) #define FSR_WPROIN0_MASK (0x01 << FSR_WPROIN0) #define FSR_WPROIN1_MASK (0x01 << FSR_WPROIN1) #define FSR_WPROIN2_MASK (0x01 << FSR_WPROIN2) #define FSR_WPRODIS0_MASK (0x01 << FSR_WPRODIS0) #define FSR_WPRODIS1_MASK (0x01 << FSR_WPRODIS1) #define FSR_SLM_MASK (0x01 << FSR_SLM) #define FSR_VER_MASK (0x01 << FSR_VER) /* Flash Config Register */ #define FLASH_REG_FLASH0_FCON (FLASH_REG_BASE | 0x2014) #define FCON_WSPFLASH (0) #define FCON_WSECPF (4) #define FCON_IDLE (13) #define FCON_ESLDIS (14) #define FCON_SLEEP (15) #define FCON_RPA (16) #define FCON_DCF (17) #define FCON_DDF (18) #define FCON_VOPERM (24) #define FCON_SQERM (25) #define FCON_PROERM (26) #define FCON_PFSBERM (27) #define FCON_PFDBERM (29) #define FCON_EOBM (31) #define FCON_WSPFLASH_MASK (0x0f << FCON_WSPFLASH) #define FCON_WSECPF_MASK (0x01 << FCON_WSECPF) #define FCON_IDLE_MASK (0x01 << FCON_IDLE) #define FCON_ESLDIS_MASK (0x01 << FCON_ESLDIS) #define FCON_SLEEP_MASK (0x01 << FCON_SLEEP) #define FCON_RPA_MASK (0x01 << FCON_RPA) #define FCON_DCF_MASK (0x01 << FCON_DCF) #define FCON_DDF_MASK (0x01 << FCON_DDF) #define FCON_VOPERM_MASK (0x01 << FCON_VOPERM) #define FCON_SQERM_MASK (0x01 << FCON_SQERM) #define FCON_PROERM_MASK (0x01 << FCON_PROERM) #define FCON_PFSBERM_MASK (0x01 << FCON_PFSBERM) #define FCON_PFDBERM_MASK (0x01 << FCON_PFDBERM) #define FCON_EOBM_MASK (0x01 << FCON_EOBM) /* Flash Margin Control Register */ #define FLASH_REG_FLASH0_MARP (FLASH_REG_BASE | 0x2018) #define MARP_MARGIN (0) #define MARP_TRAPDIS (15) #define MARP_MARGIN_MASK (0x0f << MARP_MARGIN) #define MARP_TRAPDIS_MASK (0x01 << MARP_TRAPDIS) /* Flash Protection Registers */ #define FLASH_REG_FLASH0_PROCON0 (FLASH_REG_BASE | 0x2020) #define FLASH_REG_FLASH0_PROCON1 (FLASH_REG_BASE | 0x2024) #define FLASH_REG_FLASH0_PROCON2 (FLASH_REG_BASE | 0x2028) #define PROCON_S0L (0) #define PROCON_S1L (1) #define PROCON_S2L (2) #define PROCON_S3L (3) #define PROCON_S4L (4) #define PROCON_S5L (5) #define PROCON_S6L (6) #define PROCON_S7L (7) #define PROCON_S8L (8) #define PROCON_S9L (9) #define PROCON_S10_S11L (10) #define PROCON_RPRO (15) #define PROCON_S0L_MASK (0x01 << PROCON_S0L) #define PROCON_S1L_MASK (0x01 << PROCON_S1L) #define PROCON_S2L_MASK (0x01 << PROCON_S2L) #define PROCON_S3L_MASK (0x01 << PROCON_S3L) #define PROCON_S4L_MASK (0x01 << PROCON_S4L) #define PROCON_S5L_MASK (0x01 << PROCON_S5L) #define PROCON_S6L_MASK (0x01 << PROCON_S6L) #define PROCON_S7L_MASK (0x01 << PROCON_S7L) #define PROCON_S8L_MASK (0x01 << PROCON_S8L) #define PROCON_S9L_MASK (0x01 << PROCON_S9L) #define PROCON_S10_S11L_MASK (0x01 << PROCON_S10_S11L) #define PROCON_RPRO_MASK (0x01 << PROCON_RPRO) #define FLASH_PROTECT_CONFIRMATION_CODE 0x8AFE15C3 /* Flash controller configuration values */ #define FLASH_ID_XMC4500 0xA2 #define FLASH_ID_XMC4300_XMC4700_4800 0x92 #define FLASH_ID_XMC4100_4200 0x9C #define FLASH_ID_XMC4400 0x9F /* Timeouts */ #define FLASH_OP_TIMEOUT 5000 /* Flash commands (write/erase/protect) are performed using special * command sequences that are written to magic addresses in the flash controller */ /* Command sequence addresses. See reference manual, section 8: Flash Command Sequences */ #define FLASH_CMD_ERASE_1 0x0C005554 #define FLASH_CMD_ERASE_2 0x0C00AAA8 #define FLASH_CMD_ERASE_3 FLASH_CMD_ERASE_1 #define FLASH_CMD_ERASE_4 FLASH_CMD_ERASE_1 #define FLASH_CMD_ERASE_5 FLASH_CMD_ERASE_2 /* ERASE_6 is the sector base address */ #define FLASH_CMD_CLEAR_STATUS FLASH_CMD_ERASE_1 #define FLASH_CMD_ENTER_PAGEMODE FLASH_CMD_ERASE_1 #define FLASH_CMD_LOAD_PAGE_1 0x0C0055F0 #define FLASH_CMD_LOAD_PAGE_2 0x0C0055F4 #define FLASH_CMD_WRITE_PAGE_1 FLASH_CMD_ERASE_1 #define FLASH_CMD_WRITE_PAGE_2 FLASH_CMD_ERASE_2 #define FLASH_CMD_WRITE_PAGE_3 FLASH_CMD_ERASE_1 /* WRITE_PAGE_4 is the page base address */ #define FLASH_CMD_TEMP_UNPROT_1 FLASH_CMD_ERASE_1 #define FLASH_CMD_TEMP_UNPROT_2 FLASH_CMD_ERASE_2 #define FLASH_CMD_TEMP_UNPROT_3 0x0C00553C #define FLASH_CMD_TEMP_UNPROT_4 FLASH_CMD_ERASE_2 #define FLASH_CMD_TEMP_UNPROT_5 FLASH_CMD_ERASE_2 #define FLASH_CMD_TEMP_UNPROT_6 0x0C005558 struct xmc4xxx_flash_bank { bool probed; /* We need the flash controller ID to choose the sector layout */ uint32_t fcon_id; /* Passwords used for protection operations */ uint32_t pw1; uint32_t pw2; bool pw_set; /* Protection flags */ bool read_protected; bool write_prot_otp[MAX_XMC_SECTORS]; }; struct xmc4xxx_command_seq { uint32_t address; uint32_t magic; }; /* Sector capacities. See section 8 of xmc4x00_rm */ static const unsigned int sector_capacity_8[8] = { 16, 16, 16, 16, 16, 16, 16, 128 }; static const unsigned int sector_capacity_9[9] = { 16, 16, 16, 16, 16, 16, 16, 128, 256 }; static const unsigned int sector_capacity_12[12] = { 16, 16, 16, 16, 16, 16, 16, 16, 128, 256, 256, 256 }; static const unsigned int sector_capacity_16[16] = { 16, 16, 16, 16, 16, 16, 16, 16, 128, 256, 256, 256, 256, 256, 256, 256 }; static int xmc4xxx_write_command_sequence(struct flash_bank *bank, struct xmc4xxx_command_seq *seq, int seq_len) { int res = ERROR_OK; for (int i = 0; i < seq_len; i++) { res = target_write_u32(bank->target, seq[i].address, seq[i].magic); if (res != ERROR_OK) return res; } return ERROR_OK; } static int xmc4xxx_load_bank_layout(struct flash_bank *bank) { const unsigned int *capacity = NULL; /* At this point, we know which flash controller ID we're * talking to and simply need to fill out the bank structure accordingly */ LOG_DEBUG("%u sectors", bank->num_sectors); switch (bank->num_sectors) { case 8: capacity = sector_capacity_8; break; case 9: capacity = sector_capacity_9; break; case 12: capacity = sector_capacity_12; break; case 16: capacity = sector_capacity_16; break; default: LOG_ERROR("Unexpected number of sectors, %u\n", bank->num_sectors); return ERROR_FAIL; } /* This looks like a bank that we understand, now we know the * corresponding sector capacities and we can add those up into the * bank size. */ uint32_t total_offset = 0; bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].size = capacity[i] * 1024; bank->sectors[i].offset = total_offset; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; bank->size += bank->sectors[i].size; LOG_DEBUG("\t%d: %uk", i, capacity[i]); total_offset += bank->sectors[i].size; } /* This part doesn't follow the typical standard of 0xff * being the erased value.*/ bank->default_padded_value = bank->erased_value = 0x00; return ERROR_OK; } static int xmc4xxx_probe(struct flash_bank *bank) { int res; uint32_t devid, config; struct xmc4xxx_flash_bank *fb = bank->driver_priv; uint8_t flash_id; if (fb->probed) return ERROR_OK; /* It's not possible for the DAP to access the OTP locations needed for * probing the part info and Flash geometry so we require that the target * be halted before proceeding. */ if (bank->target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } /* The SCU registers contain the ID of the chip */ res = target_read_u32(bank->target, SCU_REG_BASE + SCU_ID_CHIP, &devid); if (res != ERROR_OK) { LOG_ERROR("Cannot read device identification register."); return res; } /* Make sure this is a XMC4000 family device */ if ((devid & 0xF0000) != 0x40000 && devid != 0) { LOG_ERROR("Platform ID doesn't match XMC4xxx: 0x%08" PRIx32, devid); return ERROR_FAIL; } LOG_DEBUG("Found XMC4xxx with devid: 0x%08" PRIx32, devid); /* Now sanity-check the Flash controller itself. */ res = target_read_u32(bank->target, FLASH_REG_FLASH0_ID, &config); if (res != ERROR_OK) { LOG_ERROR("Cannot read Flash bank configuration."); return res; } flash_id = (config & 0xff0000) >> 16; /* The Flash configuration register is our only means of * determining the sector layout. We need to make sure that * we understand the type of controller we're dealing with */ switch (flash_id) { case FLASH_ID_XMC4100_4200: bank->num_sectors = 8; LOG_DEBUG("XMC4xxx: XMC4100/4200 detected."); break; case FLASH_ID_XMC4400: bank->num_sectors = 9; LOG_DEBUG("XMC4xxx: XMC4400 detected."); break; case FLASH_ID_XMC4500: bank->num_sectors = 12; LOG_DEBUG("XMC4xxx: XMC4500 detected."); break; case FLASH_ID_XMC4300_XMC4700_4800: bank->num_sectors = 16; LOG_DEBUG("XMC4xxx: XMC4700/4800 detected."); break; default: LOG_ERROR("XMC4xxx: Unexpected flash ID. got %02" PRIx8, flash_id); return ERROR_FAIL; } /* Retrieve information about the particular bank we're probing and fill in * the bank structure accordingly. */ res = xmc4xxx_load_bank_layout(bank); if (res == ERROR_OK) { /* We're done */ fb->probed = true; } else { LOG_ERROR("Unable to load bank information."); return ERROR_FAIL; } return ERROR_OK; } static int xmc4xxx_get_sector_start_addr(struct flash_bank *bank, unsigned int sector, uint32_t *ret_addr) { /* Make sure we understand this sector */ if (sector > bank->num_sectors) return ERROR_FAIL; *ret_addr = bank->base + bank->sectors[sector].offset; return ERROR_OK; } static int xmc4xxx_clear_flash_status(struct flash_bank *bank) { int res; /* TODO: Do we need to check for sequence error? */ LOG_INFO("Clearing flash status"); res = target_write_u32(bank->target, FLASH_CMD_CLEAR_STATUS, 0xF5); if (res != ERROR_OK) { LOG_ERROR("Unable to write erase command sequence"); return res; } return ERROR_OK; } static int xmc4xxx_get_flash_status(struct flash_bank *bank, uint32_t *status) { int res; res = target_read_u32(bank->target, FLASH_REG_FLASH0_FSR, status); if (res != ERROR_OK) LOG_ERROR("Cannot read flash status register."); return res; } static int xmc4xxx_wait_status_busy(struct flash_bank *bank, int timeout) { int res; uint32_t status; res = xmc4xxx_get_flash_status(bank, &status); if (res != ERROR_OK) return res; /* While the flash controller is busy, wait */ while (status & FSR_PBUSY_MASK) { res = xmc4xxx_get_flash_status(bank, &status); if (res != ERROR_OK) return res; if (timeout-- <= 0) { LOG_ERROR("Timed out waiting for flash"); return ERROR_FAIL; } alive_sleep(1); keep_alive(); } if (status & FSR_PROER_MASK) { LOG_ERROR("XMC4xxx flash protected"); res = ERROR_FAIL; } return res; } static int xmc4xxx_erase_sector(struct flash_bank *bank, uint32_t address, bool user_config) { int res; uint32_t status; /* See reference manual table 8.4: Command Sequences for Flash Control */ struct xmc4xxx_command_seq erase_cmd_seq[6] = { {FLASH_CMD_ERASE_1, 0xAA}, {FLASH_CMD_ERASE_2, 0x55}, {FLASH_CMD_ERASE_3, 0x80}, {FLASH_CMD_ERASE_4, 0xAA}, {FLASH_CMD_ERASE_5, 0x55}, {0xFF, 0xFF} /* Needs filled in */ }; /* We need to fill in the base address of the sector we'll be * erasing, as well as the magic code that determines whether * this is a standard flash sector or a user configuration block */ erase_cmd_seq[5].address = address; if (user_config) { /* Removing flash protection requires the addition of * the base address */ erase_cmd_seq[5].address += bank->base; erase_cmd_seq[5].magic = 0xC0; } else { erase_cmd_seq[5].magic = 0x30; } res = xmc4xxx_write_command_sequence(bank, erase_cmd_seq, ARRAY_SIZE(erase_cmd_seq)); if (res != ERROR_OK) return res; /* Read the flash status register */ res = target_read_u32(bank->target, FLASH_REG_FLASH0_FSR, &status); if (res != ERROR_OK) { LOG_ERROR("Cannot read flash status register."); return res; } /* Check for a sequence error */ if (status & FSR_SQER_MASK) { LOG_ERROR("Error with flash erase sequence"); return ERROR_FAIL; } /* Make sure a flash erase was triggered */ if (!(status & FSR_ERASE_MASK)) { LOG_ERROR("Flash failed to erase"); return ERROR_FAIL; } /* Now we must wait for the erase operation to end */ res = xmc4xxx_wait_status_busy(bank, FLASH_OP_TIMEOUT); return res; } static int xmc4xxx_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct xmc4xxx_flash_bank *fb = bank->driver_priv; int res; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Unable to erase, target is not halted"); return ERROR_TARGET_NOT_HALTED; } if (!fb->probed) { res = xmc4xxx_probe(bank); if (res != ERROR_OK) return res; } uint32_t tmp_addr; /* Loop through the sectors and erase each one */ for (unsigned int i = first; i <= last; i++) { res = xmc4xxx_get_sector_start_addr(bank, i, &tmp_addr); if (res != ERROR_OK) { LOG_ERROR("Invalid sector %u", i); return res; } LOG_DEBUG("Erasing sector %u @ 0x%08"PRIx32, i, tmp_addr); res = xmc4xxx_erase_sector(bank, tmp_addr, false); if (res != ERROR_OK) { LOG_ERROR("Unable to write erase command sequence"); goto clear_status_and_exit; } /* Now we must wait for the erase operation to end */ res = xmc4xxx_wait_status_busy(bank, FLASH_OP_TIMEOUT); if (res != ERROR_OK) goto clear_status_and_exit; } clear_status_and_exit: res = xmc4xxx_clear_flash_status(bank); return res; } static int xmc4xxx_enter_page_mode(struct flash_bank *bank) { int res; uint32_t status; res = target_write_u32(bank->target, FLASH_CMD_ENTER_PAGEMODE, 0x50); if (res != ERROR_OK) { LOG_ERROR("Unable to write enter page mode command"); return ERROR_FAIL; } res = xmc4xxx_get_flash_status(bank, &status); if (res != ERROR_OK) return res; /* Make sure we're in page mode */ if (!(status & FSR_PFPAGE_MASK)) { LOG_ERROR("Unable to enter page mode"); return ERROR_FAIL; } /* Make sure we didn't encounter a sequence error */ if (status & FSR_SQER_MASK) { LOG_ERROR("Sequence error while entering page mode"); return ERROR_FAIL; } return res; } static int xmc4xxx_write_page(struct flash_bank *bank, const uint8_t *pg_buf, uint32_t offset, bool user_config) { int res; uint32_t status; /* Base of the flash write command */ struct xmc4xxx_command_seq write_cmd_seq[4] = { {FLASH_CMD_WRITE_PAGE_1, 0xAA}, {FLASH_CMD_WRITE_PAGE_2, 0x55}, {FLASH_CMD_WRITE_PAGE_3, 0xFF}, /* Needs filled in */ {0xFF, 0xFF} /* Needs filled in */ }; /* The command sequence differs depending on whether this is * being written to standard flash or the user configuration * area */ if (user_config) write_cmd_seq[2].magic = 0xC0; else write_cmd_seq[2].magic = 0xA0; /* Finally, we need to add the address that this page will be * written to */ write_cmd_seq[3].address = bank->base + offset; write_cmd_seq[3].magic = 0xAA; /* Flash pages are written 256 bytes at a time. For each 256 * byte chunk, we need to: * 1. Enter page mode. This activates the flash write buffer * 2. Load the page buffer with data (2x 32 bit words at a time) * 3. Burn the page buffer into its intended location * If the starting offset is not on a 256 byte boundary, we * will need to pad the beginning of the write buffer * accordingly. Likewise, if the last page does not fill the * buffer, we should pad it to avoid leftover data from being * written to flash */ res = xmc4xxx_enter_page_mode(bank); if (res != ERROR_OK) return res; /* Copy the data into the page buffer*/ for (int i = 0; i < 256; i += 8) { uint32_t w_lo = target_buffer_get_u32(bank->target, &pg_buf[i]); uint32_t w_hi = target_buffer_get_u32(bank->target, &pg_buf[i + 4]); LOG_DEBUG("WLO: %08"PRIx32, w_lo); LOG_DEBUG("WHI: %08"PRIx32, w_hi); /* Data is loaded 2x 32 bit words at a time */ res = target_write_u32(bank->target, FLASH_CMD_LOAD_PAGE_1, w_lo); if (res != ERROR_OK) return res; res = target_write_u32(bank->target, FLASH_CMD_LOAD_PAGE_2, w_hi); if (res != ERROR_OK) return res; /* Check for an error */ res = xmc4xxx_get_flash_status(bank, &status); if (res != ERROR_OK) return res; if (status & FSR_SQER_MASK) { LOG_ERROR("Error loading page buffer"); return ERROR_FAIL; } } /* The page buffer is now full, time to commit it to flash */ res = xmc4xxx_write_command_sequence(bank, write_cmd_seq, ARRAY_SIZE(write_cmd_seq)); if (res != ERROR_OK) { LOG_ERROR("Unable to enter write command sequence"); return res; } /* Read the flash status register */ res = xmc4xxx_get_flash_status(bank, &status); if (res != ERROR_OK) return res; /* Check for a sequence error */ if (status & FSR_SQER_MASK) { LOG_ERROR("Error with flash write sequence"); return ERROR_FAIL; } /* Make sure a flash write was triggered */ if (!(status & FSR_PROG_MASK)) { LOG_ERROR("Failed to write flash page"); return ERROR_FAIL; } /* Wait for the write operation to end */ res = xmc4xxx_wait_status_busy(bank, FLASH_OP_TIMEOUT); if (res != ERROR_OK) return res; /* TODO: Verify that page was written without error */ return res; } static int xmc4xxx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct xmc4xxx_flash_bank *fb = bank->driver_priv; int res = ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Unable to erase, target is not halted"); return ERROR_TARGET_NOT_HALTED; } if (!fb->probed) { res = xmc4xxx_probe(bank); if (res != ERROR_OK) return res; } /* Make sure we won't run off the end of the flash bank */ if ((offset + count) > (bank->size)) { LOG_ERROR("Attempting to write past the end of flash"); return ERROR_FAIL; } /* Attempt to write the passed in buffer to flash */ /* Pages are written 256 bytes at a time, we need to handle * scenarios where padding is required at the beginning and * end of a page */ while (count) { /* page working area */ uint8_t tmp_buf[256] = {0}; /* Amount of data we'll be writing to this page */ int remaining; int end_pad; remaining = MIN(count, sizeof(tmp_buf)); end_pad = sizeof(tmp_buf) - remaining; /* Make sure we're starting on a page boundary */ int start_pad = offset % 256; if (start_pad) { LOG_INFO("Write does not start on a 256 byte boundary. " "Padding by %d bytes", start_pad); memset(tmp_buf, 0xff, start_pad); /* Subtract the amount of start offset from * the amount of data we'll need to write */ remaining -= start_pad; } /* Remove the amount we'll be writing from the total count */ count -= remaining; /* Now copy in the remaining data */ memcpy(&tmp_buf[start_pad], buffer, remaining); if (end_pad) { LOG_INFO("Padding end of page @" TARGET_ADDR_FMT " by %d bytes", bank->base + offset, end_pad); memset(&tmp_buf[256 - end_pad], 0xff, end_pad); } /* Now commit this page to flash, if there was start * padding, we should subtract that from the target offset */ res = xmc4xxx_write_page(bank, tmp_buf, (offset - start_pad), false); if (res != ERROR_OK) { LOG_ERROR("Unable to write flash page"); goto abort_write_and_exit; } /* Advance the buffer pointer */ buffer += remaining; /* Advance the offset */ offset += remaining; } abort_write_and_exit: xmc4xxx_clear_flash_status(bank); return res; } static int xmc4xxx_get_info_command(struct flash_bank *bank, struct command_invocation *cmd) { struct xmc4xxx_flash_bank *fb = bank->driver_priv; uint32_t scu_idcode; if (bank->target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } /* The SCU registers contain the ID of the chip */ int res = target_read_u32(bank->target, SCU_REG_BASE + SCU_ID_CHIP, &scu_idcode); if (res != ERROR_OK) { LOG_ERROR("Cannot read device identification register."); return res; } uint16_t dev_id = (scu_idcode & 0xfff0) >> 4; uint16_t rev_id = scu_idcode & 0xf; const char *dev_str; const char *rev_str = NULL; switch (dev_id) { case 0x100: dev_str = "XMC4100"; switch (rev_id) { case 0x1: rev_str = "AA"; break; case 0x2: rev_str = "AB"; break; } break; case 0x200: dev_str = "XMC4200"; switch (rev_id) { case 0x1: rev_str = "AA"; break; case 0x2: rev_str = "AB"; break; } break; case 0x300: dev_str = "XMC4300"; switch (rev_id) { case 0x1: rev_str = "AA"; } break; case 0x400: dev_str = "XMC4400"; switch (rev_id) { case 0x1: rev_str = "AA"; break; case 0x2: rev_str = "AB"; break; } break; case 0: /* XMC4500 EES AA13 with date codes before GE212 * had zero SCU_IDCHIP */ dev_str = "XMC4500 EES"; rev_str = "AA13"; break; case 0x500: dev_str = "XMC4500"; switch (rev_id) { case 0x2: rev_str = "AA"; break; case 0x3: rev_str = "AB"; break; case 0x4: rev_str = "AC"; break; } break; case 0x700: dev_str = "XMC4700"; switch (rev_id) { case 0x1: rev_str = "EES-AA"; break; } break; case 0x800: dev_str = "XMC4800"; switch (rev_id) { case 0x1: rev_str = "EES-AA"; break; } break; default: command_print_sameline(cmd, "Cannot identify target as an XMC4xxx. SCU_ID: %"PRIx32 "\n", scu_idcode); return ERROR_OK; } /* String to declare protection data held in the private driver */ char prot_str[512] = {0}; if (fb->read_protected) snprintf(prot_str, sizeof(prot_str), "\nFlash is read protected"); bool otp_enabled = false; for (unsigned int i = 0; i < bank->num_sectors; i++) if (fb->write_prot_otp[i]) otp_enabled = true; /* If OTP Write protection is enabled (User 2), list each * sector that has it enabled */ char otp_str[14]; if (otp_enabled) { strcat(prot_str, "\nOTP Protection is enabled for sectors:\n"); for (unsigned int i = 0; i < bank->num_sectors; i++) { if (fb->write_prot_otp[i]) { snprintf(otp_str, sizeof(otp_str), "- %d\n", i); strncat(prot_str, otp_str, sizeof(prot_str) - strlen(prot_str) - 1); } } } if (rev_str) command_print_sameline(cmd, "%s - Rev: %s%s", dev_str, rev_str, prot_str); else command_print_sameline(cmd, "%s - Rev: unknown (0x%01x)%s", dev_str, rev_id, prot_str); return ERROR_OK; } static int xmc4xxx_temp_unprotect(struct flash_bank *bank, int user_level) { struct xmc4xxx_flash_bank *fb; int res = ERROR_OK; uint32_t status = 0; struct xmc4xxx_command_seq temp_unprot_seq[6] = { {FLASH_CMD_TEMP_UNPROT_1, 0xAA}, {FLASH_CMD_TEMP_UNPROT_2, 0x55}, {FLASH_CMD_TEMP_UNPROT_3, 0xFF}, /* Needs filled in */ {FLASH_CMD_TEMP_UNPROT_4, 0xFF}, /* Needs filled in */ {FLASH_CMD_TEMP_UNPROT_5, 0xFF}, /* Needs filled in */ {FLASH_CMD_TEMP_UNPROT_6, 0x05} }; if (user_level < 0 || user_level > 2) { LOG_ERROR("Invalid user level, must be 0-2"); return ERROR_FAIL; } fb = bank->driver_priv; /* Fill in the user level and passwords */ temp_unprot_seq[2].magic = user_level; temp_unprot_seq[3].magic = fb->pw1; temp_unprot_seq[4].magic = fb->pw2; res = xmc4xxx_write_command_sequence(bank, temp_unprot_seq, ARRAY_SIZE(temp_unprot_seq)); if (res != ERROR_OK) { LOG_ERROR("Unable to write temp unprotect sequence"); return res; } res = xmc4xxx_get_flash_status(bank, &status); if (res != ERROR_OK) return res; if (status & FSR_WPRODIS0) { LOG_INFO("Flash is temporarily unprotected"); } else { LOG_INFO("Unable to disable flash protection"); res = ERROR_FAIL; } return res; } static int xmc4xxx_flash_unprotect(struct flash_bank *bank, int32_t level) { uint32_t addr; int res; switch (level) { case 0: addr = UCB0_BASE; break; case 1: addr = UCB1_BASE; break; default: LOG_ERROR("Invalid user level. Must be 0-1"); return ERROR_FAIL; } res = xmc4xxx_erase_sector(bank, addr, true); if (res != ERROR_OK) LOG_ERROR("Error erasing user configuration block"); return res; } /* Reference: "XMC4500 Flash Protection.pptx" app note */ static int xmc4xxx_flash_protect(struct flash_bank *bank, int level, bool read_protect, unsigned int first, unsigned int last) { /* User configuration block buffers */ uint8_t ucp0_buf[8 * sizeof(uint32_t)] = {0}; uint32_t ucb_base = 0; uint32_t procon = 0; int res = ERROR_OK; uint32_t status = 0; bool proin = false; struct xmc4xxx_flash_bank *fb = bank->driver_priv; /* Read protect only works for user 0, make sure we don't try * to do something silly */ if (level != 0 && read_protect) { LOG_ERROR("Read protection is for user level 0 only!"); return ERROR_FAIL; } /* Check to see if protection is already installed for the * specified user level. If it is, the user configuration * block will need to be erased before we can continue */ /* Grab the flash status register*/ res = xmc4xxx_get_flash_status(bank, &status); if (res != ERROR_OK) return res; switch (level) { case 0: if ((status & FSR_RPROIN_MASK) || (status & FSR_WPROIN0_MASK)) proin = true; break; case 1: if (status & FSR_WPROIN1_MASK) proin = true; break; case 2: if (status & FSR_WPROIN2_MASK) proin = true; break; } if (proin) { LOG_ERROR("Flash protection is installed for user %d" " and must be removed before continuing", level); return ERROR_FAIL; } /* If this device has 12 flash sectors, protection for * sectors 10 & 11 are handled jointly. If we are trying to * write all sectors, we should decrement * last to ensure we don't write to a register bit that * doesn't exist*/ if ((bank->num_sectors == 12) && (last == 12)) last--; /* We need to fill out the procon register representation * that we will be writing to the device */ for (unsigned int i = first; i <= last; i++) procon |= 1 << i; /* If read protection is requested, set the appropriate bit * (we checked that this is allowed above) */ if (read_protect) procon |= PROCON_RPRO_MASK; LOG_DEBUG("Setting flash protection with procon:"); LOG_DEBUG("PROCON: %"PRIx32, procon); /* First we need to copy in the procon register to the buffer * we're going to attempt to write. This is written twice */ target_buffer_set_u32(bank->target, &ucp0_buf[0 * 4], procon); target_buffer_set_u32(bank->target, &ucp0_buf[2 * 4], procon); /* Now we must copy in both flash passwords. As with the * procon data, this must be written twice (4 total words * worth of data) */ target_buffer_set_u32(bank->target, &ucp0_buf[4 * 4], fb->pw1); target_buffer_set_u32(bank->target, &ucp0_buf[5 * 4], fb->pw2); target_buffer_set_u32(bank->target, &ucp0_buf[6 * 4], fb->pw1); target_buffer_set_u32(bank->target, &ucp0_buf[7 * 4], fb->pw2); /* Finally, (if requested) we copy in the confirmation * code so that the protection is permanent and will * require a password to undo. */ target_buffer_set_u32(bank->target, &ucp0_buf[0 * 4], FLASH_PROTECT_CONFIRMATION_CODE); target_buffer_set_u32(bank->target, &ucp0_buf[2 * 4], FLASH_PROTECT_CONFIRMATION_CODE); /* Now that the data is copied into place, we must write * these pages into flash */ /* The user configuration block base depends on what level of * protection we're trying to install, select the proper one */ switch (level) { case 0: ucb_base = UCB0_BASE; break; case 1: ucb_base = UCB1_BASE; break; case 2: ucb_base = UCB2_BASE; break; } /* Write the user config pages */ res = xmc4xxx_write_page(bank, ucp0_buf, ucb_base, true); if (res != ERROR_OK) { LOG_ERROR("Error writing user configuration block 0"); return res; } return ERROR_OK; } static int xmc4xxx_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int ret; struct xmc4xxx_flash_bank *fb = bank->driver_priv; /* Check for flash passwords */ if (!fb->pw_set) { LOG_ERROR("Flash passwords not set, use xmc4xxx flash_password to set them"); return ERROR_FAIL; } /* We want to clear flash protection temporarily*/ if (set == 0) { LOG_WARNING("Flash protection will be temporarily disabled" " for all pages (User 0 only)!"); ret = xmc4xxx_temp_unprotect(bank, 0); return ret; } /* Install write protection for user 0 on the specified pages */ ret = xmc4xxx_flash_protect(bank, 0, false, first, last); return ret; } static int xmc4xxx_protect_check(struct flash_bank *bank) { int ret; uint32_t protection[3] = {0}; struct xmc4xxx_flash_bank *fb = bank->driver_priv; ret = target_read_u32(bank->target, FLASH_REG_FLASH0_PROCON0, &protection[0]); if (ret != ERROR_OK) { LOG_ERROR("Unable to read flash User0 protection register"); return ret; } ret = target_read_u32(bank->target, FLASH_REG_FLASH0_PROCON1, &protection[1]); if (ret != ERROR_OK) { LOG_ERROR("Unable to read flash User1 protection register"); return ret; } ret = target_read_u32(bank->target, FLASH_REG_FLASH0_PROCON2, &protection[2]); if (ret != ERROR_OK) { LOG_ERROR("Unable to read flash User2 protection register"); return ret; } unsigned int sectors = bank->num_sectors; /* On devices with 12 sectors, sectors 10 & 11 are protected * together instead of individually */ if (sectors == 12) sectors--; /* Clear the protection status */ for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].is_protected = 0; fb->write_prot_otp[i] = false; } fb->read_protected = false; /* The xmc4xxx series supports 3 levels of user protection * (User0, User1 (low priority), and User 2(OTP), we need to * check all 3 */ for (unsigned int i = 0; i < ARRAY_SIZE(protection); i++) { /* Check for write protection on every available * sector */ for (unsigned int j = 0; j < sectors; j++) { int set = (protection[i] & (1 << j)) ? 1 : 0; bank->sectors[j].is_protected |= set; /* Handle sector 11 */ if (j == 10) bank->sectors[j + 1].is_protected |= set; /* User 2 indicates this protection is * permanent, make note in the private driver structure */ if (i == 2 && set) { fb->write_prot_otp[j] = true; /* Handle sector 11 */ if (j == 10) fb->write_prot_otp[j + 1] = true; } } } /* XMC4xxx also supports read protection, make a note * in the private driver structure */ if (protection[0] & PROCON_RPRO_MASK) fb->read_protected = true; return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(xmc4xxx_flash_bank_command) { bank->driver_priv = malloc(sizeof(struct xmc4xxx_flash_bank)); if (!bank->driver_priv) return ERROR_FLASH_OPERATION_FAILED; (void)memset(bank->driver_priv, 0, sizeof(struct xmc4xxx_flash_bank)); return ERROR_OK; } COMMAND_HANDLER(xmc4xxx_handle_flash_password_command) { int res; struct flash_bank *bank; if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; res = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (res != ERROR_OK) return res; struct xmc4xxx_flash_bank *fb = bank->driver_priv; errno = 0; /* We skip over the flash bank */ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], fb->pw1); if (errno) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], fb->pw2); if (errno) return ERROR_COMMAND_SYNTAX_ERROR; fb->pw_set = true; command_print(CMD, "XMC4xxx flash passwords set to:\n"); command_print(CMD, "-0x%08"PRIx32"\n", fb->pw1); command_print(CMD, "-0x%08"PRIx32"\n", fb->pw2); return ERROR_OK; } COMMAND_HANDLER(xmc4xxx_handle_flash_unprotect_command) { struct flash_bank *bank; int res; int32_t level; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; res = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (res != ERROR_OK) return res; COMMAND_PARSE_NUMBER(s32, CMD_ARGV[1], level); res = xmc4xxx_flash_unprotect(bank, level); return res; } static const struct command_registration xmc4xxx_exec_command_handlers[] = { { .name = "flash_password", .handler = xmc4xxx_handle_flash_password_command, .mode = COMMAND_EXEC, .usage = "bank_id password1 password2", .help = "Set the flash passwords used for protect operations. " "Passwords should be in standard hex form (0x00000000). " "(You must call this before any other protect commands) " "NOTE: The xmc4xxx's UCB area only allows for FOUR cycles. " "Please use protection carefully!", }, { .name = "flash_unprotect", .handler = xmc4xxx_handle_flash_unprotect_command, .mode = COMMAND_EXEC, .usage = "bank_id user_level[0-1]", .help = "Permanently Removes flash protection (read and write) " "for the specified user level", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration xmc4xxx_command_handlers[] = { { .name = "xmc4xxx", .mode = COMMAND_ANY, .help = "xmc4xxx flash command group", .usage = "", .chain = xmc4xxx_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver xmc4xxx_flash = { .name = "xmc4xxx", .commands = xmc4xxx_command_handlers, .flash_bank_command = xmc4xxx_flash_bank_command, .erase = xmc4xxx_erase, .write = xmc4xxx_write, .read = default_flash_read, .probe = xmc4xxx_probe, .auto_probe = xmc4xxx_probe, .erase_check = default_flash_blank_check, .info = xmc4xxx_get_info_command, .protect_check = xmc4xxx_protect_check, .protect = xmc4xxx_protect, .free_driver_priv = default_flash_free_driver_priv, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/flash/startup.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Defines basic Tcl procs for OpenOCD flash module # # program utility proc # usage: program filename # optional args: verify, reset, exit and address # lappend _telnet_autocomplete_skip program_error proc program_error {description exit} { if {$exit == 1} { echo $description shutdown error } error $description } proc program {filename args} { set exit 0 set needsflash 1 foreach arg $args { if {[string equal $arg "preverify"]} { set preverify 1 } elseif {[string equal $arg "verify"]} { set verify 1 } elseif {[string equal $arg "reset"]} { set reset 1 } elseif {[string equal $arg "exit"]} { set exit 1 } else { set address $arg } } # Set variables set filename \{$filename\} if {[info exists address]} { set flash_args "$filename $address" } else { set flash_args "$filename" } # make sure init is called if {[catch {init}] != 0} { program_error "** OpenOCD init failed **" 1 } # reset target and call any init scripts if {[catch {reset init}] != 0} { program_error "** Unable to reset target **" $exit } # Check whether programming is needed if {[info exists preverify]} { echo "**pre-verifying**" if {[catch {eval verify_image $flash_args}] == 0} { echo "**Verified OK - No flashing**" set needsflash 0 } } # start programming phase if {$needsflash == 1} { echo "** Programming Started **" if {[catch {eval flash write_image erase $flash_args}] == 0} { echo "** Programming Finished **" if {[info exists verify]} { # verify phase echo "** Verify Started **" if {[catch {eval verify_image $flash_args}] == 0} { echo "** Verified OK **" } else { program_error "** Verify Failed **" $exit } } } else { program_error "** Programming Failed **" $exit } } if {[info exists reset]} { # reset target if requested if {$exit == 1} { # also disable target polling, we are shutting down anyway poll off } echo "** Resetting Target **" reset run } if {$exit == 1} { shutdown } return } add_help_text program "write an image to flash, address is only required for binary images. verify, reset, exit are optional" add_usage_text program "<filename> \[address\] \[pre-verify\] \[verify\] \[reset\] \[exit\]" # stm32[f0x|f3x] uses the same flash driver as the stm32f1x proc stm32f0x args { eval stm32f1x $args } proc stm32f3x args { eval stm32f1x $args } # stm32[f4x|f7x] uses the same flash driver as the stm32f2x proc stm32f4x args { eval stm32f2x $args } proc stm32f7x args { eval stm32f2x $args } # stm32lx driver supports both STM32 L0 and L1 devices proc stm32l0x args { eval stm32lx $args } proc stm32l1x args { eval stm32lx $args } # stm32[g0|g4|l5|u5|wb|wl] uses the same flash driver as the stm32l4x proc stm32g0x args { eval stm32l4x $args } proc stm32g4x args { eval stm32l4x $args } proc stm32l5x args { eval stm32l4x $args } proc stm32u5x args { eval stm32l4x $args } proc stm32wbx args { eval stm32l4x $args } proc stm32wlx args { eval stm32l4x $args } # gd32e23x uses the same flash driver as the stm32f1x proc gd32e23x args { eval stm32f1x $args } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/hello.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <helper/log.h> #include "hello.h" COMMAND_HANDLER(handle_foo_command) { if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t address; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); const char *msg = "<unchanged>"; if (CMD_ARGC == 2) { bool enable; COMMAND_PARSE_ENABLE(CMD_ARGV[1], enable); msg = enable ? "enable" : "disable"; } LOG_INFO("%s: address=0x%8.8" PRIx32 " enabled=%s", CMD_NAME, address, msg); return ERROR_OK; } static bool foo_flag; COMMAND_HANDLER(handle_flag_command) { return CALL_COMMAND_HANDLER(handle_command_parse_bool, &foo_flag, "foo flag"); } static const struct command_registration foo_command_handlers[] = { { .name = "bar", .handler = &handle_foo_command, .mode = COMMAND_ANY, .usage = "address ['enable'|'disable']", .help = "an example command", }, { .name = "baz", .handler = &handle_foo_command, .mode = COMMAND_ANY, .usage = "address ['enable'|'disable']", .help = "a sample command", }, { .name = "flag", .handler = &handle_flag_command, .mode = COMMAND_ANY, .usage = "[on|off]", .help = "set a flag", }, COMMAND_REGISTRATION_DONE }; static COMMAND_HELPER(handle_hello_args, const char **sep, const char **name) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (1 == CMD_ARGC) { *sep = " "; *name = CMD_ARGV[0]; } else *sep = *name = ""; return ERROR_OK; } COMMAND_HANDLER(handle_hello_command) { const char *sep, *name; int retval = CALL_COMMAND_HANDLER(handle_hello_args, &sep, &name); if (retval == ERROR_OK) command_print(CMD, "Greetings%s%s!", sep, name); return retval; } const struct command_registration hello_command_handlers[] = { { .name = "hello", .handler = handle_hello_command, .mode = COMMAND_ANY, .help = "prints a warm welcome", .usage = "[name]", }, { .name = "foo", .mode = COMMAND_ANY, .help = "example command handler skeleton", .chain = foo_command_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/hello.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifndef OPENOCD_HELLO_H #define OPENOCD_HELLO_H struct command_registration; /** * Export the registration for the hello command group, so it can be * embedded in example drivers. */ extern const struct command_registration hello_command_handlers[]; #endif /* OPENOCD_HELLO_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libhelper.la %C%_libhelper_la_SOURCES = \ %D%/binarybuffer.c \ %D%/options.c \ %D%/time_support_common.c \ %D%/configuration.c \ %D%/log.c \ %D%/command.c \ %D%/crc32.c \ %D%/time_support.c \ %D%/replacements.c \ %D%/fileio.c \ %D%/util.c \ %D%/jep106.c \ %D%/jim-nvp.c \ %D%/nvp.c \ %D%/align.h \ %D%/binarybuffer.h \ %D%/bits.h \ %D%/configuration.h \ %D%/list.h \ %D%/util.h \ %D%/types.h \ %D%/log.h \ %D%/command.h \ %D%/crc32.h \ %D%/time_support.h \ %D%/replacements.h \ %D%/fileio.h \ %D%/system.h \ %D%/jep106.h \ %D%/jep106.inc \ %D%/jim-nvp.h \ %D%/nvp.h \ %D%/compiler.h STARTUP_TCL_SRCS += %D%/startup.tcl EXTRA_DIST += \ %D%/bin2char.sh \ %D%/update_jep106.pl ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/align.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * The content of this file is mainly copied/inspired from Linux kernel * code in include/linux/align.h and include/uapi/linux/const.h * * Macro name 'ALIGN' conflicts with macOS/BSD file param.h */ #ifndef OPENOCD_HELPER_ALIGN_H #define OPENOCD_HELPER_ALIGN_H #define ALIGN_MASK(x, mask) \ ({ \ typeof(mask) _mask = (mask); \ ((x) + _mask) & ~_mask; \ }) /* @a is a power of 2 value */ #define ALIGN_UP(x, a) ALIGN_MASK(x, (typeof(x))(a) - 1) #define ALIGN_DOWN(x, a) ((x) & ~((typeof(x))(a) - 1)) #define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) #define IS_PWR_OF_2(x) \ ({ \ typeof(x) _x = (x); \ _x == 0 || (_x & (_x - 1)) == 0; \ }) #endif /* OPENOCD_HELPER_ALIGN_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/bin2char.sh ================================================ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later [ $# != 0 ] && { echo "Usage: $0" echo echo "Read binary data from standard input and write it as a comma separated" echo "list of hexadecimal byte values to standard output. The output is usable" echo "as a C array initializer. It is terminated with a comma so it can be" echo "continued e.g. for zero termination." exit 1 } echo "/* Autogenerated with $0 */" od -v -A n -t x1 | sed 's/ *\(..\) */0x\1,/g' ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/binarybuffer.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "helper/replacements.h" #include "log.h" #include "binarybuffer.h" static const unsigned char bit_reverse_table256[] = { 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF }; static const char hex_digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; void *buf_cpy(const void *from, void *_to, unsigned size) { if (!from || !_to) return NULL; /* copy entire buffer */ memcpy(_to, from, DIV_ROUND_UP(size, 8)); /* mask out bits that don't belong to the buffer */ unsigned trailing_bits = size % 8; if (trailing_bits) { uint8_t *to = _to; to[size / 8] &= (1 << trailing_bits) - 1; } return _to; } static bool buf_cmp_masked(uint8_t a, uint8_t b, uint8_t m) { return (a & m) != (b & m); } static bool buf_cmp_trailing(uint8_t a, uint8_t b, uint8_t m, unsigned trailing) { uint8_t mask = (1 << trailing) - 1; return buf_cmp_masked(a, b, mask & m); } bool buf_cmp(const void *_buf1, const void *_buf2, unsigned size) { if (!_buf1 || !_buf2) return _buf1 != _buf2; unsigned last = size / 8; if (memcmp(_buf1, _buf2, last) != 0) return false; unsigned trailing = size % 8; if (!trailing) return false; const uint8_t *buf1 = _buf1, *buf2 = _buf2; return buf_cmp_trailing(buf1[last], buf2[last], 0xff, trailing); } bool buf_cmp_mask(const void *_buf1, const void *_buf2, const void *_mask, unsigned size) { if (!_buf1 || !_buf2) return _buf1 != _buf2 || _buf1 != _mask; const uint8_t *buf1 = _buf1, *buf2 = _buf2, *mask = _mask; unsigned last = size / 8; for (unsigned i = 0; i < last; i++) { if (buf_cmp_masked(buf1[i], buf2[i], mask[i])) return true; } unsigned trailing = size % 8; if (!trailing) return false; return buf_cmp_trailing(buf1[last], buf2[last], mask[last], trailing); } void *buf_set_ones(void *_buf, unsigned size) { uint8_t *buf = _buf; if (!buf) return NULL; memset(buf, 0xff, size / 8); unsigned trailing_bits = size % 8; if (trailing_bits) buf[size / 8] = (1 << trailing_bits) - 1; return buf; } void *buf_set_buf(const void *_src, unsigned src_start, void *_dst, unsigned dst_start, unsigned len) { const uint8_t *src = _src; uint8_t *dst = _dst; unsigned i, sb, db, sq, dq, lb, lq; sb = src_start / 8; db = dst_start / 8; sq = src_start % 8; dq = dst_start % 8; lb = len / 8; lq = len % 8; src += sb; dst += db; /* check if both buffers are on byte boundary and * len is a multiple of 8bit so we can simple copy * the buffer */ if ((sq == 0) && (dq == 0) && (lq == 0)) { for (i = 0; i < lb; i++) *dst++ = *src++; return _dst; } /* fallback to slow bit copy */ for (i = 0; i < len; i++) { if (((*src >> (sq&7)) & 1) == 1) *dst |= 1 << (dq&7); else *dst &= ~(1 << (dq&7)); if (sq++ == 7) { sq = 0; src++; } if (dq++ == 7) { dq = 0; dst++; } } return _dst; } uint32_t flip_u32(uint32_t value, unsigned int num) { uint32_t c = (bit_reverse_table256[value & 0xff] << 24) | (bit_reverse_table256[(value >> 8) & 0xff] << 16) | (bit_reverse_table256[(value >> 16) & 0xff] << 8) | (bit_reverse_table256[(value >> 24) & 0xff]); if (num < 32) c = c >> (32 - num); return c; } static int ceil_f_to_u32(float x) { if (x < 0) /* return zero for negative numbers */ return 0; uint32_t y = x; /* cut off fraction */ if ((x - y) > 0.0) /* if there was a fractional part, increase by one */ y++; return y; } char *buf_to_hex_str(const void *_buf, unsigned buf_len) { unsigned len_bytes = DIV_ROUND_UP(buf_len, 8); char *str = calloc(len_bytes * 2 + 1, 1); const uint8_t *buf = _buf; for (unsigned i = 0; i < len_bytes; i++) { uint8_t tmp = buf[len_bytes - i - 1]; if ((i == 0) && (buf_len % 8)) tmp &= (0xff >> (8 - (buf_len % 8))); str[2 * i] = hex_digits[tmp >> 4]; str[2 * i + 1] = hex_digits[tmp & 0xf]; } return str; } /** identify radix, and skip radix-prefix (0, 0x or 0X) */ static void str_radix_guess(const char **_str, unsigned *_str_len, unsigned *_radix) { unsigned radix = *_radix; if (radix != 0) return; const char *str = *_str; unsigned str_len = *_str_len; if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { radix = 16; str += 2; str_len -= 2; } else if ((str[0] == '0') && (str_len != 1)) { radix = 8; str += 1; str_len -= 1; } else radix = 10; *_str = str; *_str_len = str_len; *_radix = radix; } int str_to_buf(const char *str, unsigned str_len, void *_buf, unsigned buf_len, unsigned radix) { str_radix_guess(&str, &str_len, &radix); float factor; if (radix == 16) factor = 0.5; /* log(16) / log(256) = 0.5 */ else if (radix == 10) factor = 0.41524; /* log(10) / log(256) = 0.41524 */ else if (radix == 8) factor = 0.375; /* log(8) / log(256) = 0.375 */ else return 0; /* copy to zero-terminated buffer */ char *charbuf = strndup(str, str_len); /* number of digits in base-256 notation */ unsigned b256_len = ceil_f_to_u32(str_len * factor); uint8_t *b256_buf = calloc(b256_len, 1); /* go through zero terminated buffer * input digits (ASCII) */ unsigned i; for (i = 0; charbuf[i]; i++) { uint32_t tmp = charbuf[i]; if ((tmp >= '0') && (tmp <= '9')) tmp = (tmp - '0'); else if ((tmp >= 'a') && (tmp <= 'f')) tmp = (tmp - 'a' + 10); else if ((tmp >= 'A') && (tmp <= 'F')) tmp = (tmp - 'A' + 10); else continue; /* skip characters other than [0-9,a-f,A-F] */ if (tmp >= radix) continue; /* skip digits invalid for the current radix */ /* base-256 digits */ for (unsigned j = 0; j < b256_len; j++) { tmp += (uint32_t)b256_buf[j] * radix; b256_buf[j] = (uint8_t)(tmp & 0xFF); tmp >>= 8; } } uint8_t *buf = _buf; for (unsigned j = 0; j < DIV_ROUND_UP(buf_len, 8); j++) { if (j < b256_len) buf[j] = b256_buf[j]; else buf[j] = 0; } /* mask out bits that don't belong to the buffer */ if (buf_len % 8) buf[(buf_len / 8)] &= 0xff >> (8 - (buf_len % 8)); free(b256_buf); free(charbuf); return i; } void bit_copy_queue_init(struct bit_copy_queue *q) { INIT_LIST_HEAD(&q->list); } int bit_copy_queued(struct bit_copy_queue *q, uint8_t *dst, unsigned dst_offset, const uint8_t *src, unsigned src_offset, unsigned bit_count) { struct bit_copy_queue_entry *qe = malloc(sizeof(*qe)); if (!qe) return ERROR_FAIL; qe->dst = dst; qe->dst_offset = dst_offset; qe->src = src; qe->src_offset = src_offset; qe->bit_count = bit_count; list_add_tail(&qe->list, &q->list); return ERROR_OK; } void bit_copy_execute(struct bit_copy_queue *q) { struct bit_copy_queue_entry *qe; struct bit_copy_queue_entry *tmp; list_for_each_entry_safe(qe, tmp, &q->list, list) { bit_copy(qe->dst, qe->dst_offset, qe->src, qe->src_offset, qe->bit_count); list_del(&qe->list); free(qe); } } void bit_copy_discard(struct bit_copy_queue *q) { struct bit_copy_queue_entry *qe; struct bit_copy_queue_entry *tmp; list_for_each_entry_safe(qe, tmp, &q->list, list) { list_del(&qe->list); free(qe); } } /** * Convert a string of hexadecimal pairs into its binary * representation. * * @param[out] bin Buffer to store binary representation. The buffer size must * be at least @p count. * @param[in] hex String with hexadecimal pairs to convert into its binary * representation. * @param[in] count Number of hexadecimal pairs to convert. * * @return The number of converted hexadecimal pairs. */ size_t unhexify(uint8_t *bin, const char *hex, size_t count) { size_t i; char tmp; if (!bin || !hex) return 0; memset(bin, 0, count); for (i = 0; i < 2 * count; i++) { if (hex[i] >= 'a' && hex[i] <= 'f') tmp = hex[i] - 'a' + 10; else if (hex[i] >= 'A' && hex[i] <= 'F') tmp = hex[i] - 'A' + 10; else if (hex[i] >= '0' && hex[i] <= '9') tmp = hex[i] - '0'; else return i / 2; bin[i / 2] |= tmp << (4 * ((i + 1) % 2)); } return i / 2; } /** * Convert binary data into a string of hexadecimal pairs. * * @param[out] hex Buffer to store string of hexadecimal pairs. The buffer size * must be at least @p length. * @param[in] bin Buffer with binary data to convert into hexadecimal pairs. * @param[in] count Number of bytes to convert. * @param[in] length Maximum number of characters, including null-terminator, * to store into @p hex. * * @returns The length of the converted string excluding null-terminator. */ size_t hexify(char *hex, const uint8_t *bin, size_t count, size_t length) { size_t i; uint8_t tmp; if (!length) return 0; for (i = 0; i < length - 1 && i < 2 * count; i++) { tmp = (bin[i / 2] >> (4 * ((i + 1) % 2))) & 0x0f; hex[i] = hex_digits[tmp]; } hex[i] = 0; return i; } void buffer_shr(void *_buf, unsigned buf_len, unsigned count) { unsigned i; unsigned char *buf = _buf; unsigned bytes_to_remove; unsigned shift; bytes_to_remove = count / 8; shift = count - (bytes_to_remove * 8); for (i = 0; i < (buf_len - 1); i++) buf[i] = (buf[i] >> shift) | ((buf[i+1] << (8 - shift)) & 0xff); buf[(buf_len - 1)] = buf[(buf_len - 1)] >> shift; if (bytes_to_remove) { memmove(buf, &buf[bytes_to_remove], buf_len - bytes_to_remove); memset(&buf[buf_len - bytes_to_remove], 0, bytes_to_remove); } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/binarybuffer.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifndef OPENOCD_HELPER_BINARYBUFFER_H #define OPENOCD_HELPER_BINARYBUFFER_H #include "list.h" /** @file * Support functions to access arbitrary bits in a byte array */ /** * Sets @c num bits in @c _buffer, starting at the @c first bit, * using the bits in @c value. This routine fast-paths writes * of little-endian, byte-aligned, 32-bit words. * @param _buffer The buffer whose bits will be set. * Do not use uninitialized buffer or clang static analyzer emits a warning. * @param first The bit offset in @c _buffer to start writing (0-31). * @param num The number of bits from @c value to copy (1-32). * @param value Up to 32 bits that will be copied to _buffer. */ static inline void buf_set_u32(uint8_t *_buffer, unsigned first, unsigned num, uint32_t value) { uint8_t *buffer = _buffer; if ((num == 32) && (first == 0)) { buffer[3] = (value >> 24) & 0xff; buffer[2] = (value >> 16) & 0xff; buffer[1] = (value >> 8) & 0xff; buffer[0] = (value >> 0) & 0xff; } else { for (unsigned i = first; i < first + num; i++) { if (((value >> (i - first)) & 1) == 1) buffer[i / 8] |= 1 << (i % 8); else buffer[i / 8] &= ~(1 << (i % 8)); } } } /** * Sets @c num bits in @c _buffer, starting at the @c first bit, * using the bits in @c value. This routine fast-paths writes * of little-endian, byte-aligned, 64-bit words. * @param _buffer The buffer whose bits will be set. * Do not use uninitialized buffer or clang static analyzer emits a warning. * @param first The bit offset in @c _buffer to start writing (0-63). * @param num The number of bits from @c value to copy (1-64). * @param value Up to 64 bits that will be copied to _buffer. */ static inline void buf_set_u64(uint8_t *_buffer, unsigned first, unsigned num, uint64_t value) { uint8_t *buffer = _buffer; if ((num == 32) && (first == 0)) { buffer[3] = (value >> 24) & 0xff; buffer[2] = (value >> 16) & 0xff; buffer[1] = (value >> 8) & 0xff; buffer[0] = (value >> 0) & 0xff; } else if ((num == 64) && (first == 0)) { buffer[7] = (value >> 56) & 0xff; buffer[6] = (value >> 48) & 0xff; buffer[5] = (value >> 40) & 0xff; buffer[4] = (value >> 32) & 0xff; buffer[3] = (value >> 24) & 0xff; buffer[2] = (value >> 16) & 0xff; buffer[1] = (value >> 8) & 0xff; buffer[0] = (value >> 0) & 0xff; } else { for (unsigned i = first; i < first + num; i++) { if (((value >> (i - first)) & 1) == 1) buffer[i / 8] |= 1 << (i % 8); else buffer[i / 8] &= ~(1 << (i % 8)); } } } /** * Retrieves @c num bits from @c _buffer, starting at the @c first bit, * returning the bits in a 32-bit word. This routine fast-paths reads * of little-endian, byte-aligned, 32-bit words. * @param _buffer The buffer whose bits will be read. * @param first The bit offset in @c _buffer to start reading (0-31). * @param num The number of bits from @c _buffer to read (1-32). * @returns Up to 32-bits that were read from @c _buffer. */ static inline uint32_t buf_get_u32(const uint8_t *_buffer, unsigned first, unsigned num) { const uint8_t *buffer = _buffer; if ((num == 32) && (first == 0)) { return (((uint32_t)buffer[3]) << 24) | (((uint32_t)buffer[2]) << 16) | (((uint32_t)buffer[1]) << 8) | (((uint32_t)buffer[0]) << 0); } else { uint32_t result = 0; for (unsigned i = first; i < first + num; i++) { if (((buffer[i / 8] >> (i % 8)) & 1) == 1) result |= 1U << (i - first); } return result; } } /** * Retrieves @c num bits from @c _buffer, starting at the @c first bit, * returning the bits in a 64-bit word. This routine fast-paths reads * of little-endian, byte-aligned, 64-bit words. * @param _buffer The buffer whose bits will be read. * @param first The bit offset in @c _buffer to start reading (0-63). * @param num The number of bits from @c _buffer to read (1-64). * @returns Up to 64-bits that were read from @c _buffer. */ static inline uint64_t buf_get_u64(const uint8_t *_buffer, unsigned first, unsigned num) { const uint8_t *buffer = _buffer; if ((num == 32) && (first == 0)) { return 0 + ((((uint32_t)buffer[3]) << 24) | /* Note - zero plus is to avoid a checkpatch bug */ (((uint32_t)buffer[2]) << 16) | (((uint32_t)buffer[1]) << 8) | (((uint32_t)buffer[0]) << 0)); } else if ((num == 64) && (first == 0)) { return 0 + ((((uint64_t)buffer[7]) << 56) | /* Note - zero plus is to avoid a checkpatch bug */ (((uint64_t)buffer[6]) << 48) | (((uint64_t)buffer[5]) << 40) | (((uint64_t)buffer[4]) << 32) | (((uint64_t)buffer[3]) << 24) | (((uint64_t)buffer[2]) << 16) | (((uint64_t)buffer[1]) << 8) | (((uint64_t)buffer[0]) << 0)); } else { uint64_t result = 0; for (unsigned i = first; i < first + num; i++) { if (((buffer[i / 8] >> (i % 8)) & 1) == 1) result = result | ((uint64_t)1 << (uint64_t)(i - first)); } return result; } } /** * Inverts the ordering of bits inside a 32-bit word (e.g. 31..0 -> 0..31). * This routine can be used to flip smaller data types by using smaller * values for @c width. * @param value The word to flip. * @param width The number of bits in value (2-32). * @returns A 32-bit word with @c value in reversed bit-order. */ uint32_t flip_u32(uint32_t value, unsigned width); bool buf_cmp(const void *buf1, const void *buf2, unsigned size); bool buf_cmp_mask(const void *buf1, const void *buf2, const void *mask, unsigned size); /** * Copies @c size bits out of @c from and into @c to. Any extra * bits in the final byte will be set to zero. * @param from The buffer to copy into @c to. * @param to The buffer that will receive the copy of @c from. * @param size The number of bits to copy. */ void *buf_cpy(const void *from, void *to, unsigned size); /** * Set the contents of @c buf with @c count bits, all set to 1. * @param buf The buffer to fill with ones. * @param size The number of bits. * @returns The original buffer (@c buf). */ void *buf_set_ones(void *buf, unsigned size); void *buf_set_buf(const void *src, unsigned src_start, void *dst, unsigned dst_start, unsigned len); int str_to_buf(const char *str, unsigned len, void *bin_buf, unsigned buf_size, unsigned radix); char *buf_to_hex_str(const void *buf, unsigned size); /* read a uint32_t from a buffer in target memory endianness */ static inline uint32_t fast_target_buffer_get_u32(const void *p, bool le) { return le ? le_to_h_u32(p) : be_to_h_u32(p); } static inline void bit_copy(uint8_t *dst, unsigned dst_offset, const uint8_t *src, unsigned src_offset, unsigned bit_count) { buf_set_buf(src, src_offset, dst, dst_offset, bit_count); } struct bit_copy_queue { struct list_head list; }; struct bit_copy_queue_entry { uint8_t *dst; unsigned dst_offset; const uint8_t *src; unsigned src_offset; unsigned bit_count; struct list_head list; }; void bit_copy_queue_init(struct bit_copy_queue *q); int bit_copy_queued(struct bit_copy_queue *q, uint8_t *dst, unsigned dst_offset, const uint8_t *src, unsigned src_offset, unsigned bit_count); void bit_copy_execute(struct bit_copy_queue *q); void bit_copy_discard(struct bit_copy_queue *q); /* functions to convert to/from hex encoded buffer * used in ti-icdi driver and gdb server */ size_t unhexify(uint8_t *bin, const char *hex, size_t count); size_t hexify(char *hex, const uint8_t *bin, size_t count, size_t out_maxlen); void buffer_shr(void *_buf, unsigned buf_len, unsigned count); #endif /* OPENOCD_HELPER_BINARYBUFFER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/bits.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2018, STMicroelectronics - All Rights Reserved * Author(s): Antonio Borneo <borneo.antonio@gmail.com> for STMicroelectronics */ /* * The content of this file is mainly copied/inspired from Linux kernel * code in include/linux/types.h include/linux/bitmap.h include/linux/bitops.h */ #ifndef OPENOCD_HELPER_BITS_H #define OPENOCD_HELPER_BITS_H #include <helper/replacements.h> #include <helper/types.h> #define BIT(nr) (1UL << (nr)) #define BIT_ULL(nr) (1ULL << (nr)) #define BITS_PER_BYTE 8 #define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) #define BITS_PER_LONG_LONG (BITS_PER_BYTE * sizeof(long long)) #define GENMASK(h, l) (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) #define GENMASK_ULL(h, l) (((~0ULL) - (1ULL << (l)) + 1) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) #define DECLARE_BITMAP(name, bits) unsigned long name[BITS_TO_LONGS(bits)] /** * bitmap_zero - Clears all the bits in memory * @param dst the address of the bitmap * @param nbits the number of bits to clear */ static inline void bitmap_zero(unsigned long *dst, unsigned int nbits) { unsigned int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); memset(dst, 0, len); } /** * clear_bit - Clear a bit in memory * @param nr the bit to set * @param addr the address to start counting from */ static inline void clear_bit(unsigned int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); *p &= ~mask; } /** * set_bit - Set a bit in memory * @param nr the bit to set * @param addr the address to start counting from */ static inline void set_bit(unsigned int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); *p |= mask; } /** * test_bit - Determine whether a bit is set * @param nr bit number to test * @param addr Address to start counting from */ static inline int test_bit(unsigned int nr, const volatile unsigned long *addr) { return 1UL & (addr[BIT_WORD(nr)] >> (nr % BITS_PER_LONG)); } #endif /* OPENOCD_HELPER_BITS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/command.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008, Duane Ellis * * openocd@duaneeellis.com * * * * part of this file is taken from libcli (libcli.sourceforge.net) * * Copyright (C) David Parrish (david@dparrish.com) * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* @todo the inclusion of target.h here is a layering violation */ #include <jtag/jtag.h> #include <target/target.h> #include "command.h" #include "configuration.h" #include "log.h" #include "time_support.h" #include "jim-eventloop.h" /* nice short description of source file */ #define __THIS__FILE__ "command.c" struct log_capture_state { Jim_Interp *interp; Jim_Obj *output; }; static int unregister_command(struct command_context *context, const char *cmd_prefix, const char *name); static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *argv); static int help_add_command(struct command_context *cmd_ctx, const char *cmd_name, const char *help_text, const char *usage_text); static int help_del_command(struct command_context *cmd_ctx, const char *cmd_name); /* set of functions to wrap jimtcl internal data */ static inline bool jimcmd_is_proc(Jim_Cmd *cmd) { return cmd->isproc; } bool jimcmd_is_oocd_command(Jim_Cmd *cmd) { return !cmd->isproc && cmd->u.native.cmdProc == jim_command_dispatch; } void *jimcmd_privdata(Jim_Cmd *cmd) { return cmd->isproc ? NULL : cmd->u.native.privData; } static void tcl_output(void *privData, const char *file, unsigned line, const char *function, const char *string) { struct log_capture_state *state = privData; Jim_AppendString(state->interp, state->output, string, strlen(string)); } static struct log_capture_state *command_log_capture_start(Jim_Interp *interp) { /* capture log output and return it. A garbage collect can * happen, so we need a reference count to this object */ Jim_Obj *jim_output = Jim_NewStringObj(interp, "", 0); if (!jim_output) return NULL; Jim_IncrRefCount(jim_output); struct log_capture_state *state = malloc(sizeof(*state)); if (!state) { LOG_ERROR("Out of memory"); Jim_DecrRefCount(interp, jim_output); return NULL; } state->interp = interp; state->output = jim_output; log_add_callback(tcl_output, state); return state; } /* Classic openocd commands provide progress output which we * will capture and return as a Tcl return value. * * However, if a non-openocd command has been invoked, then it * makes sense to return the tcl return value from that command. * * The tcl return value is empty for openocd commands that provide * progress output. * * Therefore we set the tcl return value only if we actually * captured output. */ static void command_log_capture_finish(struct log_capture_state *state) { if (!state) return; log_remove_callback(tcl_output, state); int length; Jim_GetString(state->output, &length); if (length > 0) Jim_SetResult(state->interp, state->output); else { /* No output captured, use tcl return value (which could * be empty too). */ } Jim_DecrRefCount(state->interp, state->output); free(state); } static int command_retval_set(Jim_Interp *interp, int retval) { int *return_retval = Jim_GetAssocData(interp, "retval"); if (return_retval) *return_retval = retval; return (retval == ERROR_OK) ? JIM_OK : retval; } extern struct command_context *global_cmd_ctx; /* dump a single line to the log for the command. * Do nothing in case we are not at debug level 3 */ static void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv) { if (debug_level < LOG_LVL_DEBUG) return; char *dbg = alloc_printf("command -"); for (unsigned i = 0; i < argc; i++) { int len; const char *w = Jim_GetString(argv[i], &len); char *t = alloc_printf("%s %s", dbg, w); free(dbg); dbg = t; } LOG_DEBUG("%s", dbg); free(dbg); } static void script_command_args_free(char **words, unsigned nwords) { for (unsigned i = 0; i < nwords; i++) free(words[i]); free(words); } static char **script_command_args_alloc( unsigned argc, Jim_Obj * const *argv, unsigned *nwords) { char **words = malloc(argc * sizeof(char *)); if (!words) return NULL; unsigned i; for (i = 0; i < argc; i++) { int len; const char *w = Jim_GetString(argv[i], &len); words[i] = strdup(w); if (!words[i]) { script_command_args_free(words, i); return NULL; } } *nwords = i; return words; } struct command_context *current_command_context(Jim_Interp *interp) { /* grab the command context from the associated data */ struct command_context *cmd_ctx = Jim_GetAssocData(interp, "context"); if (!cmd_ctx) { /* Tcl can invoke commands directly instead of via command_run_line(). This would * happen when the Jim Tcl interpreter is provided by eCos or if we are running * commands in a startup script. * * A telnet or gdb server would provide a non-default command context to * handle piping of error output, have a separate current target, etc. */ cmd_ctx = global_cmd_ctx; } return cmd_ctx; } /** * Find a openocd command from fullname. * @returns Returns the named command if it is registred in interp. * Returns NULL otherwise. */ static struct command *command_find_from_name(Jim_Interp *interp, const char *name) { if (!name) return NULL; Jim_Obj *jim_name = Jim_NewStringObj(interp, name, -1); Jim_IncrRefCount(jim_name); Jim_Cmd *cmd = Jim_GetCommand(interp, jim_name, JIM_NONE); Jim_DecrRefCount(interp, jim_name); if (!cmd || jimcmd_is_proc(cmd) || !jimcmd_is_oocd_command(cmd)) return NULL; return jimcmd_privdata(cmd); } static struct command *command_new(struct command_context *cmd_ctx, const char *full_name, const struct command_registration *cr) { assert(cr->name); /* * If it is a non-jim command with no .usage specified, * log an error. * * strlen(.usage) == 0 means that the command takes no * arguments. */ if (!cr->jim_handler && !cr->usage) LOG_ERROR("BUG: command '%s' does not have the " "'.usage' field filled out", full_name); struct command *c = calloc(1, sizeof(struct command)); if (!c) return NULL; c->name = strdup(cr->name); if (!c->name) { free(c); return NULL; } c->handler = cr->handler; c->jim_handler = cr->jim_handler; c->mode = cr->mode; if (cr->help || cr->usage) help_add_command(cmd_ctx, full_name, cr->help, cr->usage); return c; } static void command_free(struct Jim_Interp *interp, void *priv) { struct command *c = priv; free(c->name); free(c); } static struct command *register_command(struct command_context *context, const char *cmd_prefix, const struct command_registration *cr) { char *full_name; if (!context || !cr->name) return NULL; if (cmd_prefix) full_name = alloc_printf("%s %s", cmd_prefix, cr->name); else full_name = strdup(cr->name); if (!full_name) return NULL; struct command *c = command_find_from_name(context->interp, full_name); if (c) { /* TODO: originally we treated attempting to register a cmd twice as an error * Sometimes we need this behaviour, such as with flash banks. * http://www.mail-archive.com/openocd-development@lists.berlios.de/msg11152.html */ LOG_DEBUG("command '%s' is already registered", full_name); free(full_name); return c; } c = command_new(context, full_name, cr); if (!c) { free(full_name); return NULL; } if (false) /* too noisy with debug_level 3 */ LOG_DEBUG("registering '%s'...", full_name); int retval = Jim_CreateCommand(context->interp, full_name, jim_command_dispatch, c, command_free); if (retval != JIM_OK) { command_run_linef(context, "del_help_text {%s}", full_name); command_run_linef(context, "del_usage_text {%s}", full_name); free(c); free(full_name); return NULL; } free(full_name); return c; } int __register_commands(struct command_context *cmd_ctx, const char *cmd_prefix, const struct command_registration *cmds, void *data, struct target *override_target) { int retval = ERROR_OK; unsigned i; for (i = 0; cmds[i].name || cmds[i].chain; i++) { const struct command_registration *cr = cmds + i; struct command *c = NULL; if (cr->name) { c = register_command(cmd_ctx, cmd_prefix, cr); if (!c) { retval = ERROR_FAIL; break; } c->jim_handler_data = data; c->jim_override_target = override_target; } if (cr->chain) { if (cr->name) { if (cmd_prefix) { char *new_prefix = alloc_printf("%s %s", cmd_prefix, cr->name); if (!new_prefix) { retval = ERROR_FAIL; break; } retval = __register_commands(cmd_ctx, new_prefix, cr->chain, data, override_target); free(new_prefix); } else { retval = __register_commands(cmd_ctx, cr->name, cr->chain, data, override_target); } } else { retval = __register_commands(cmd_ctx, cmd_prefix, cr->chain, data, override_target); } if (retval != ERROR_OK) break; } } if (retval != ERROR_OK) { for (unsigned j = 0; j < i; j++) unregister_command(cmd_ctx, cmd_prefix, cmds[j].name); } return retval; } static __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))) int unregister_commands_match(struct command_context *cmd_ctx, const char *format, ...) { Jim_Interp *interp = cmd_ctx->interp; va_list ap; va_start(ap, format); char *query = alloc_vprintf(format, ap); va_end(ap); if (!query) return ERROR_FAIL; char *query_cmd = alloc_printf("info commands {%s}", query); free(query); if (!query_cmd) return ERROR_FAIL; int retval = Jim_EvalSource(interp, __THIS__FILE__, __LINE__, query_cmd); free(query_cmd); if (retval != JIM_OK) return ERROR_FAIL; Jim_Obj *list = Jim_GetResult(interp); Jim_IncrRefCount(list); int len = Jim_ListLength(interp, list); for (int i = 0; i < len; i++) { Jim_Obj *elem = Jim_ListGetIndex(interp, list, i); Jim_IncrRefCount(elem); const char *name = Jim_GetString(elem, NULL); struct command *c = command_find_from_name(interp, name); if (!c) { /* not openocd command */ Jim_DecrRefCount(interp, elem); continue; } if (false) /* too noisy with debug_level 3 */ LOG_DEBUG("delete command \"%s\"", name); #if JIM_VERSION >= 80 Jim_DeleteCommand(interp, elem); #else Jim_DeleteCommand(interp, name); #endif help_del_command(cmd_ctx, name); Jim_DecrRefCount(interp, elem); } Jim_DecrRefCount(interp, list); return ERROR_OK; } int unregister_all_commands(struct command_context *context, const char *cmd_prefix) { if (!context) return ERROR_OK; if (!cmd_prefix || !*cmd_prefix) return unregister_commands_match(context, "*"); int retval = unregister_commands_match(context, "%s *", cmd_prefix); if (retval != ERROR_OK) return retval; return unregister_commands_match(context, "%s", cmd_prefix); } static int unregister_command(struct command_context *context, const char *cmd_prefix, const char *name) { if (!context || !name) return ERROR_COMMAND_SYNTAX_ERROR; if (!cmd_prefix || !*cmd_prefix) return unregister_commands_match(context, "%s", name); return unregister_commands_match(context, "%s %s", cmd_prefix, name); } void command_output_text(struct command_context *context, const char *data) { if (context && context->output_handler && data) context->output_handler(context, data); } void command_print_sameline(struct command_invocation *cmd, const char *format, ...) { char *string; va_list ap; va_start(ap, format); string = alloc_vprintf(format, ap); if (string && cmd) { /* we want this collected in the log + we also want to pick it up as a tcl return * value. * * The latter bit isn't precisely neat, but will do for now. */ Jim_AppendString(cmd->ctx->interp, cmd->output, string, -1); /* We already printed it above * command_output_text(context, string); */ free(string); } va_end(ap); } void command_print(struct command_invocation *cmd, const char *format, ...) { char *string; va_list ap; va_start(ap, format); string = alloc_vprintf(format, ap); if (string && cmd) { strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one *char longer */ /* we want this collected in the log + we also want to pick it up as a tcl return * value. * * The latter bit isn't precisely neat, but will do for now. */ Jim_AppendString(cmd->ctx->interp, cmd->output, string, -1); /* We already printed it above * command_output_text(context, string); */ free(string); } va_end(ap); } static bool command_can_run(struct command_context *cmd_ctx, struct command *c, const char *full_name) { if (c->mode == COMMAND_ANY || c->mode == cmd_ctx->mode) return true; /* Many commands may be run only before/after 'init' */ const char *when; switch (c->mode) { case COMMAND_CONFIG: when = "before"; break; case COMMAND_EXEC: when = "after"; break; /* handle the impossible with humor; it guarantees a bug report! */ default: when = "if Cthulhu is summoned by"; break; } LOG_ERROR("The '%s' command must be used %s 'init'.", full_name ? full_name : c->name, when); return false; } static int run_command(struct command_context *context, struct command *c, const char **words, unsigned num_words) { struct command_invocation cmd = { .ctx = context, .current = c, .name = c->name, .argc = num_words - 1, .argv = words + 1, }; cmd.output = Jim_NewEmptyStringObj(context->interp); Jim_IncrRefCount(cmd.output); int retval = c->handler(&cmd); if (retval == ERROR_COMMAND_SYNTAX_ERROR) { /* Print help for command */ command_run_linef(context, "usage %s", words[0]); } else if (retval == ERROR_COMMAND_CLOSE_CONNECTION) { /* just fall through for a shutdown request */ } else { if (retval != ERROR_OK) LOG_DEBUG("Command '%s' failed with error code %d", words[0], retval); /* * Use the command output as the Tcl result. * Drop last '\n' to allow command output concatenation * while keep using command_print() everywhere. */ const char *output_txt = Jim_String(cmd.output); int len = strlen(output_txt); if (len && output_txt[len - 1] == '\n') --len; Jim_SetResultString(context->interp, output_txt, len); } Jim_DecrRefCount(context->interp, cmd.output); return retval; } int command_run_line(struct command_context *context, char *line) { /* all the parent commands have been registered with the interpreter * so, can just evaluate the line as a script and check for * results */ /* run the line thru a script engine */ int retval = ERROR_FAIL; int retcode; /* Beware! This code needs to be reentrant. It is also possible * for OpenOCD commands to be invoked directly from Tcl. This would * happen when the Jim Tcl interpreter is provided by eCos for * instance. */ struct target *saved_target_override = context->current_target_override; context->current_target_override = NULL; Jim_Interp *interp = context->interp; struct command_context *old_context = Jim_GetAssocData(interp, "context"); Jim_DeleteAssocData(interp, "context"); retcode = Jim_SetAssocData(interp, "context", NULL, context); if (retcode == JIM_OK) { /* associated the return value */ Jim_DeleteAssocData(interp, "retval"); retcode = Jim_SetAssocData(interp, "retval", NULL, &retval); if (retcode == JIM_OK) { retcode = Jim_Eval_Named(interp, line, NULL, 0); Jim_DeleteAssocData(interp, "retval"); } Jim_DeleteAssocData(interp, "context"); int inner_retcode = Jim_SetAssocData(interp, "context", NULL, old_context); if (retcode == JIM_OK) retcode = inner_retcode; } context->current_target_override = saved_target_override; if (retcode == JIM_OK) { const char *result; int reslen; result = Jim_GetString(Jim_GetResult(interp), &reslen); if (reslen > 0) { command_output_text(context, result); command_output_text(context, "\n"); } retval = ERROR_OK; } else if (retcode == JIM_EXIT) { /* ignore. * exit(Jim_GetExitCode(interp)); */ } else if (retcode == ERROR_COMMAND_CLOSE_CONNECTION) { return retcode; } else { Jim_MakeErrorMessage(interp); /* error is broadcast */ LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL)); if (retval == ERROR_OK) { /* It wasn't a low level OpenOCD command that failed */ return ERROR_FAIL; } return retval; } return retval; } int command_run_linef(struct command_context *context, const char *format, ...) { int retval = ERROR_FAIL; char *string; va_list ap; va_start(ap, format); string = alloc_vprintf(format, ap); if (string) { retval = command_run_line(context, string); free(string); } va_end(ap); return retval; } void command_set_output_handler(struct command_context *context, command_output_handler_t output_handler, void *priv) { context->output_handler = output_handler; context->output_handler_priv = priv; } struct command_context *copy_command_context(struct command_context *context) { struct command_context *copy_context = malloc(sizeof(struct command_context)); *copy_context = *context; return copy_context; } void command_done(struct command_context *cmd_ctx) { if (!cmd_ctx) return; free(cmd_ctx); } /* find full path to file */ COMMAND_HANDLER(handle_find) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; char *full_path = find_file(CMD_ARGV[0]); if (!full_path) return ERROR_COMMAND_ARGUMENT_INVALID; command_print(CMD, "%s", full_path); free(full_path); return ERROR_OK; } COMMAND_HANDLER(handle_echo) { if (CMD_ARGC == 2 && !strcmp(CMD_ARGV[0], "-n")) { LOG_USER_N("%s", CMD_ARGV[1]); return ERROR_OK; } if (CMD_ARGC != 1) return ERROR_FAIL; LOG_USER("%s", CMD_ARGV[0]); return ERROR_OK; } /* Capture progress output and return as tcl return value. If the * progress output was empty, return tcl return value. */ static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2) return JIM_ERR; struct log_capture_state *state = command_log_capture_start(interp); /* disable polling during capture. This avoids capturing output * from polling. * * This is necessary in order to avoid accidentally getting a non-empty * string for tcl fn's. */ bool save_poll_mask = jtag_poll_mask(); const char *str = Jim_GetString(argv[1], NULL); int retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__); jtag_poll_unmask(save_poll_mask); command_log_capture_finish(state); return retcode; } struct help_entry { struct list_head lh; char *cmd_name; char *help; char *usage; }; static COMMAND_HELPER(command_help_show, struct help_entry *c, bool show_help, const char *cmd_match); static COMMAND_HELPER(command_help_show_list, bool show_help, const char *cmd_match) { struct help_entry *entry; list_for_each_entry(entry, CMD_CTX->help_list, lh) CALL_COMMAND_HANDLER(command_help_show, entry, show_help, cmd_match); return ERROR_OK; } #define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n)) static void command_help_show_indent(unsigned n) { for (unsigned i = 0; i < n; i++) LOG_USER_N(" "); } static void command_help_show_wrap(const char *str, unsigned n, unsigned n2) { const char *cp = str, *last = str; while (*cp) { const char *next = last; do { cp = next; do { next++; } while (*next != ' ' && *next != '\t' && *next != '\0'); } while ((next - last < HELP_LINE_WIDTH(n)) && *next != '\0'); if (next - last < HELP_LINE_WIDTH(n)) cp = next; command_help_show_indent(n); LOG_USER("%.*s", (int)(cp - last), last); last = cp + 1; n = n2; } } static COMMAND_HELPER(command_help_show, struct help_entry *c, bool show_help, const char *cmd_match) { unsigned int n = 0; for (const char *s = strchr(c->cmd_name, ' '); s; s = strchr(s + 1, ' ')) n++; /* If the match string occurs anywhere, we print out * stuff for this command. */ bool is_match = strstr(c->cmd_name, cmd_match) || (c->usage && strstr(c->usage, cmd_match)) || (c->help && strstr(c->help, cmd_match)); if (is_match) { if (c->usage && strlen(c->usage) > 0) { char *msg = alloc_printf("%s %s", c->cmd_name, c->usage); command_help_show_wrap(msg, n, n + 5); free(msg); } else { command_help_show_wrap(c->cmd_name, n, n + 5); } } if (is_match && show_help) { char *msg; /* TODO: factorize jim_command_mode() to avoid running jim command here */ char *request = alloc_printf("command mode %s", c->cmd_name); if (!request) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } int retval = Jim_Eval(CMD_CTX->interp, request); free(request); enum command_mode mode = COMMAND_UNKNOWN; if (retval != JIM_ERR) { const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL); if (!strcmp(result, "any")) mode = COMMAND_ANY; else if (!strcmp(result, "config")) mode = COMMAND_CONFIG; else if (!strcmp(result, "exec")) mode = COMMAND_EXEC; } /* Normal commands are runtime-only; highlight exceptions */ if (mode != COMMAND_EXEC) { const char *stage_msg = ""; switch (mode) { case COMMAND_CONFIG: stage_msg = " (configuration command)"; break; case COMMAND_ANY: stage_msg = " (command valid any time)"; break; default: stage_msg = " (?mode error?)"; break; } msg = alloc_printf("%s%s", c->help ? c->help : "", stage_msg); } else msg = alloc_printf("%s", c->help ? c->help : ""); if (msg) { command_help_show_wrap(msg, n + 3, n + 3); free(msg); } else return -ENOMEM; } return ERROR_OK; } COMMAND_HANDLER(handle_help_command) { bool full = strcmp(CMD_NAME, "help") == 0; int retval; char *cmd_match; if (CMD_ARGC <= 0) cmd_match = strdup(""); else { cmd_match = strdup(CMD_ARGV[0]); for (unsigned int i = 1; i < CMD_ARGC && cmd_match; ++i) { char *prev = cmd_match; cmd_match = alloc_printf("%s %s", prev, CMD_ARGV[i]); free(prev); } } if (!cmd_match) { LOG_ERROR("unable to build search string"); return -ENOMEM; } retval = CALL_COMMAND_HANDLER(command_help_show_list, full, cmd_match); free(cmd_match); return retval; } static char *alloc_concatenate_strings(int argc, Jim_Obj * const *argv) { char *prev, *all; int i; assert(argc >= 1); all = strdup(Jim_GetString(argv[0], NULL)); if (!all) { LOG_ERROR("Out of memory"); return NULL; } for (i = 1; i < argc; ++i) { prev = all; all = alloc_printf("%s %s", all, Jim_GetString(argv[i], NULL)); free(prev); if (!all) { LOG_ERROR("Out of memory"); return NULL; } } return all; } static int exec_command(Jim_Interp *interp, struct command_context *cmd_ctx, struct command *c, int argc, Jim_Obj * const *argv) { if (c->jim_handler) return c->jim_handler(interp, argc, argv); /* use c->handler */ unsigned int nwords; char **words = script_command_args_alloc(argc, argv, &nwords); if (!words) return JIM_ERR; int retval = run_command(cmd_ctx, c, (const char **)words, nwords); script_command_args_free(words, nwords); return command_retval_set(interp, retval); } static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { /* check subcommands */ if (argc > 1) { char *s = alloc_printf("%s %s", Jim_GetString(argv[0], NULL), Jim_GetString(argv[1], NULL)); Jim_Obj *js = Jim_NewStringObj(interp, s, -1); Jim_IncrRefCount(js); free(s); Jim_Cmd *cmd = Jim_GetCommand(interp, js, JIM_NONE); if (cmd) { int retval = Jim_EvalObjPrefix(interp, js, argc - 2, argv + 2); Jim_DecrRefCount(interp, js); return retval; } Jim_DecrRefCount(interp, js); } script_debug(interp, argc, argv); struct command *c = jim_to_command(interp); if (!c->jim_handler && !c->handler) { Jim_EvalObjPrefix(interp, Jim_NewStringObj(interp, "usage", -1), 1, argv); return JIM_ERR; } struct command_context *cmd_ctx = current_command_context(interp); if (!command_can_run(cmd_ctx, c, Jim_GetString(argv[0], NULL))) return JIM_ERR; target_call_timer_callbacks(); /* * Black magic of overridden current target: * If the command we are going to handle has a target prefix, * override the current target temporarily for the time * of processing the command. * current_target_override is used also for event handlers * therefore we prevent touching it if command has no prefix. * Previous override is saved and restored back to ensure * correct work when jim_command_dispatch() is re-entered. */ struct target *saved_target_override = cmd_ctx->current_target_override; if (c->jim_override_target) cmd_ctx->current_target_override = c->jim_override_target; int retval = exec_command(interp, cmd_ctx, c, argc, argv); if (c->jim_override_target) cmd_ctx->current_target_override = saved_target_override; return retval; } static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct command_context *cmd_ctx = current_command_context(interp); enum command_mode mode; if (argc > 1) { char *full_name = alloc_concatenate_strings(argc - 1, argv + 1); if (!full_name) return JIM_ERR; Jim_Obj *s = Jim_NewStringObj(interp, full_name, -1); Jim_IncrRefCount(s); Jim_Cmd *cmd = Jim_GetCommand(interp, s, JIM_NONE); Jim_DecrRefCount(interp, s); free(full_name); if (!cmd || !(jimcmd_is_proc(cmd) || jimcmd_is_oocd_command(cmd))) { Jim_SetResultString(interp, "unknown", -1); return JIM_OK; } if (jimcmd_is_proc(cmd)) { /* tcl proc */ mode = COMMAND_ANY; } else { struct command *c = jimcmd_privdata(cmd); mode = c->mode; } } else mode = cmd_ctx->mode; const char *mode_str; switch (mode) { case COMMAND_ANY: mode_str = "any"; break; case COMMAND_CONFIG: mode_str = "config"; break; case COMMAND_EXEC: mode_str = "exec"; break; default: mode_str = "unknown"; break; } Jim_SetResultString(interp, mode_str, -1); return JIM_OK; } int help_del_all_commands(struct command_context *cmd_ctx) { struct help_entry *curr, *n; list_for_each_entry_safe(curr, n, cmd_ctx->help_list, lh) { list_del(&curr->lh); free(curr->cmd_name); free(curr->help); free(curr->usage); free(curr); } return ERROR_OK; } static int help_del_command(struct command_context *cmd_ctx, const char *cmd_name) { struct help_entry *curr; list_for_each_entry(curr, cmd_ctx->help_list, lh) { if (!strcmp(cmd_name, curr->cmd_name)) { list_del(&curr->lh); free(curr->cmd_name); free(curr->help); free(curr->usage); free(curr); break; } } return ERROR_OK; } static int help_add_command(struct command_context *cmd_ctx, const char *cmd_name, const char *help_text, const char *usage_text) { int cmp = -1; /* add after curr */ struct help_entry *curr; list_for_each_entry_reverse(curr, cmd_ctx->help_list, lh) { cmp = strcmp(cmd_name, curr->cmd_name); if (cmp >= 0) break; } struct help_entry *entry; if (cmp) { entry = calloc(1, sizeof(*entry)); if (!entry) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } entry->cmd_name = strdup(cmd_name); if (!entry->cmd_name) { LOG_ERROR("Out of memory"); free(entry); return ERROR_FAIL; } list_add(&entry->lh, &curr->lh); } else { entry = curr; } if (help_text) { char *text = strdup(help_text); if (!text) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } free(entry->help); entry->help = text; } if (usage_text) { char *text = strdup(usage_text); if (!text) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } free(entry->usage); entry->usage = text; } return ERROR_OK; } COMMAND_HANDLER(handle_help_add_command) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; const char *help = !strcmp(CMD_NAME, "add_help_text") ? CMD_ARGV[1] : NULL; const char *usage = !strcmp(CMD_NAME, "add_usage_text") ? CMD_ARGV[1] : NULL; if (!help && !usage) { LOG_ERROR("command name '%s' is unknown", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; } const char *cmd_name = CMD_ARGV[0]; return help_add_command(CMD_CTX, cmd_name, help, usage); } /* sleep command sleeps for <n> milliseconds * this is useful in target startup scripts */ COMMAND_HANDLER(handle_sleep_command) { bool busy = false; if (CMD_ARGC == 2) { if (strcmp(CMD_ARGV[1], "busy") == 0) busy = true; else return ERROR_COMMAND_SYNTAX_ERROR; } else if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; unsigned long duration = 0; int retval = parse_ulong(CMD_ARGV[0], &duration); if (retval != ERROR_OK) return retval; if (!busy) { int64_t then = timeval_ms(); while (timeval_ms() - then < (int64_t)duration) { target_call_timer_callbacks_now(); keep_alive(); usleep(1000); } } else busy_sleep(duration); return ERROR_OK; } static const struct command_registration command_subcommand_handlers[] = { { .name = "mode", .mode = COMMAND_ANY, .jim_handler = jim_command_mode, .usage = "[command_name ...]", .help = "Returns the command modes allowed by a command: " "'any', 'config', or 'exec'. If no command is " "specified, returns the current command mode. " "Returns 'unknown' if an unknown command is given. " "Command can be multiple tokens.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration command_builtin_handlers[] = { { .name = "ocd_find", .mode = COMMAND_ANY, .handler = handle_find, .help = "find full path to file", .usage = "file", }, { .name = "capture", .mode = COMMAND_ANY, .jim_handler = jim_capture, .help = "Capture progress output and return as tcl return value. If the " "progress output was empty, return tcl return value.", .usage = "command", }, { .name = "echo", .handler = handle_echo, .mode = COMMAND_ANY, .help = "Logs a message at \"user\" priority. " "Option \"-n\" suppresses trailing newline", .usage = "[-n] string", }, { .name = "add_help_text", .handler = handle_help_add_command, .mode = COMMAND_ANY, .help = "Add new command help text; " "Command can be multiple tokens.", .usage = "command_name helptext_string", }, { .name = "add_usage_text", .handler = handle_help_add_command, .mode = COMMAND_ANY, .help = "Add new command usage text; " "command can be multiple tokens.", .usage = "command_name usage_string", }, { .name = "sleep", .handler = handle_sleep_command, .mode = COMMAND_ANY, .help = "Sleep for specified number of milliseconds. " "\"busy\" will busy wait instead (avoid this).", .usage = "milliseconds ['busy']", }, { .name = "help", .handler = handle_help_command, .mode = COMMAND_ANY, .help = "Show full command help; " "command can be multiple tokens.", .usage = "[command_name]", }, { .name = "usage", .handler = handle_help_command, .mode = COMMAND_ANY, .help = "Show basic command usage; " "command can be multiple tokens.", .usage = "[command_name]", }, { .name = "command", .mode = COMMAND_ANY, .help = "core command group (introspection)", .chain = command_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp) { struct command_context *context = calloc(1, sizeof(struct command_context)); context->mode = COMMAND_EXEC; /* context can be duplicated. Put list head on separate mem-chunk to keep list consistent */ context->help_list = malloc(sizeof(*context->help_list)); INIT_LIST_HEAD(context->help_list); /* Create a jim interpreter if we were not handed one */ if (!interp) { /* Create an interpreter */ interp = Jim_CreateInterp(); /* Add all the Jim core commands */ Jim_RegisterCoreCommands(interp); Jim_InitStaticExtensions(interp); } context->interp = interp; register_commands(context, NULL, command_builtin_handlers); Jim_SetAssocData(interp, "context", NULL, context); if (Jim_Eval_Named(interp, startup_tcl, "embedded:startup.tcl", 1) == JIM_ERR) { LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)"); Jim_MakeErrorMessage(interp); LOG_USER_N("%s", Jim_GetString(Jim_GetResult(interp), NULL)); exit(-1); } Jim_DeleteAssocData(interp, "context"); return context; } void command_exit(struct command_context *context) { if (!context) return; Jim_FreeInterp(context->interp); free(context->help_list); command_done(context); } int command_context_mode(struct command_context *cmd_ctx, enum command_mode mode) { if (!cmd_ctx) return ERROR_COMMAND_SYNTAX_ERROR; cmd_ctx->mode = mode; return ERROR_OK; } void process_jim_events(struct command_context *cmd_ctx) { static int recursion; if (recursion) return; recursion++; Jim_ProcessEvents(cmd_ctx->interp, JIM_ALL_EVENTS | JIM_DONT_WAIT); recursion--; } #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \ int parse ## name(const char *str, type * ul) \ { \ if (!*str) { \ LOG_ERROR("Invalid command argument"); \ return ERROR_COMMAND_ARGUMENT_INVALID; \ } \ char *end; \ errno = 0; \ *ul = func(str, &end, 0); \ if (*end) { \ LOG_ERROR("Invalid command argument"); \ return ERROR_COMMAND_ARGUMENT_INVALID; \ } \ if ((max == *ul) && (errno == ERANGE)) { \ LOG_ERROR("Argument overflow"); \ return ERROR_COMMAND_ARGUMENT_OVERFLOW; \ } \ if (min && (min == *ul) && (errno == ERANGE)) { \ LOG_ERROR("Argument underflow"); \ return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \ } \ return ERROR_OK; \ } DEFINE_PARSE_NUM_TYPE(_ulong, unsigned long, strtoul, 0, ULONG_MAX) DEFINE_PARSE_NUM_TYPE(_ullong, unsigned long long, strtoull, 0, ULLONG_MAX) DEFINE_PARSE_NUM_TYPE(_long, long, strtol, LONG_MIN, LONG_MAX) DEFINE_PARSE_NUM_TYPE(_llong, long long, strtoll, LLONG_MIN, LLONG_MAX) #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \ int parse ## name(const char *str, type * ul) \ { \ functype n; \ int retval = parse ## funcname(str, &n); \ if (retval != ERROR_OK) \ return retval; \ if (n > max) \ return ERROR_COMMAND_ARGUMENT_OVERFLOW; \ if (min) \ return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \ *ul = n; \ return ERROR_OK; \ } #define DEFINE_PARSE_ULONGLONG(name, type, min, max) \ DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long long, _ullong) DEFINE_PARSE_ULONGLONG(_uint, unsigned, 0, UINT_MAX) DEFINE_PARSE_ULONGLONG(_u64, uint64_t, 0, UINT64_MAX) DEFINE_PARSE_ULONGLONG(_u32, uint32_t, 0, UINT32_MAX) DEFINE_PARSE_ULONGLONG(_u16, uint16_t, 0, UINT16_MAX) DEFINE_PARSE_ULONGLONG(_u8, uint8_t, 0, UINT8_MAX) DEFINE_PARSE_ULONGLONG(_target_addr, target_addr_t, 0, TARGET_ADDR_MAX) #define DEFINE_PARSE_LONGLONG(name, type, min, max) \ DEFINE_PARSE_WRAPPER(name, type, min, max, long long, _llong) DEFINE_PARSE_LONGLONG(_int, int, n < INT_MIN, INT_MAX) DEFINE_PARSE_LONGLONG(_s64, int64_t, n < INT64_MIN, INT64_MAX) DEFINE_PARSE_LONGLONG(_s32, int32_t, n < INT32_MIN, INT32_MAX) DEFINE_PARSE_LONGLONG(_s16, int16_t, n < INT16_MIN, INT16_MAX) DEFINE_PARSE_LONGLONG(_s8, int8_t, n < INT8_MIN, INT8_MAX) static int command_parse_bool(const char *in, bool *out, const char *on, const char *off) { if (strcasecmp(in, on) == 0) *out = true; else if (strcasecmp(in, off) == 0) *out = false; else return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } int command_parse_bool_arg(const char *in, bool *out) { if (command_parse_bool(in, out, "on", "off") == ERROR_OK) return ERROR_OK; if (command_parse_bool(in, out, "enable", "disable") == ERROR_OK) return ERROR_OK; if (command_parse_bool(in, out, "true", "false") == ERROR_OK) return ERROR_OK; if (command_parse_bool(in, out, "yes", "no") == ERROR_OK) return ERROR_OK; if (command_parse_bool(in, out, "1", "0") == ERROR_OK) return ERROR_OK; return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label) { switch (CMD_ARGC) { case 1: { const char *in = CMD_ARGV[0]; if (command_parse_bool_arg(in, out) != ERROR_OK) { LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in); return ERROR_COMMAND_SYNTAX_ERROR; } } /* fallthrough */ case 0: LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled"); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/command.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifndef OPENOCD_HELPER_COMMAND_H #define OPENOCD_HELPER_COMMAND_H #include <stdint.h> #include <stdbool.h> #include <helper/jim-nvp.h> #include <helper/list.h> #include <helper/types.h> /* To achieve C99 printf compatibility in MinGW, gnu_printf should be * used for __attribute__((format( ... ))), with GCC v4.4 or later */ #if (defined(IS_MINGW) && (((__GNUC__ << 16) + __GNUC_MINOR__) >= 0x00040004)) #define PRINTF_ATTRIBUTE_FORMAT gnu_printf #else #define PRINTF_ATTRIBUTE_FORMAT printf #endif /** * OpenOCD command mode is COMMAND_CONFIG at start, then switches to COMMAND_EXEC * during the execution of command 'init'. * The field 'mode' in struct command_registration specifies in which command mode * the command can be executed: * - during COMMAND_CONFIG only, * - during COMMAND_EXEC only, * - in both modes (COMMAND_ANY). */ enum command_mode { COMMAND_EXEC, COMMAND_CONFIG, COMMAND_ANY, COMMAND_UNKNOWN = -1, /* error condition */ }; struct command_context; /** The type signature for command context's output handler. */ typedef int (*command_output_handler_t)(struct command_context *context, const char *line); struct command_context { Jim_Interp *interp; enum command_mode mode; struct target *current_target; /* The target set by 'targets xx' command or the latest created */ struct target *current_target_override; /* If set overrides current_target * It happens during processing of * 1) a target prefixed command * 2) an event handler * Pay attention to reentrancy when setting override. */ command_output_handler_t output_handler; void *output_handler_priv; struct list_head *help_list; }; struct command; /** * When run_command is called, a new instance will be created on the * stack, filled with the proper values, and passed by reference to the * required COMMAND_HANDLER routine. */ struct command_invocation { struct command_context *ctx; struct command *current; const char *name; unsigned argc; const char **argv; Jim_Obj *output; }; /** * Return true if the command @c cmd is registered by OpenOCD. */ bool jimcmd_is_oocd_command(Jim_Cmd *cmd); /** * Return the pointer to the command's private data specified during the * registration of command @a cmd . */ void *jimcmd_privdata(Jim_Cmd *cmd); /** * Command handlers may be defined with more parameters than the base * set provided by command.c. This macro uses C99 magic to allow * defining all such derivative types using this macro. */ #define __COMMAND_HANDLER(name, extra ...) \ int name(struct command_invocation *cmd, ## extra) /** * Use this to macro to call a command helper (or a nested handler). * It provides command handler authors protection against reordering or * removal of unused parameters. * * @b Note: This macro uses lexical capture to provide some arguments. * As a result, this macro should be used @b only within functions * defined by the COMMAND_HANDLER or COMMAND_HELPER macros. Those * macros provide the expected lexical context captured by this macro. * Furthermore, it should be used only from the top-level of handler or * helper function, or care must be taken to avoid redefining the same * variables in intervening scope(s) by accident. */ #define CALL_COMMAND_HANDLER(name, extra ...) \ name(cmd, ## extra) /** * Always use this macro to define new command handler functions. * It ensures the parameters are ordered, typed, and named properly, so * they be can be used by other macros (e.g. COMMAND_PARSE_NUMBER). * All command handler functions must be defined as static in scope. */ #define COMMAND_HANDLER(name) \ static __COMMAND_HANDLER(name) /** * Similar to COMMAND_HANDLER, except some parameters are expected. * A helper is globally-scoped because it may be shared between several * source files (e.g. the s3c24xx device command helper). */ #define COMMAND_HELPER(name, extra ...) __COMMAND_HANDLER(name, extra) /** * Use this macro to access the command being handled, * rather than accessing the variable directly. It may be moved. */ #define CMD (cmd) /** * Use this macro to access the context of the command being handled, * rather than accessing the variable directly. It may be moved. */ #define CMD_CTX (cmd->ctx) /** * Use this macro to access the number of arguments for the command being * handled, rather than accessing the variable directly. It may be moved. */ #define CMD_ARGC (cmd->argc) /** * Use this macro to access the arguments for the command being handled, * rather than accessing the variable directly. It may be moved. */ #define CMD_ARGV (cmd->argv) /** * Use this macro to access the name of the command being handled, * rather than accessing the variable directly. It may be moved. */ #define CMD_NAME (cmd->name) /** * Use this macro to access the current command being handled, * rather than accessing the variable directly. It may be moved. */ #define CMD_CURRENT (cmd->current) /** * Use this macro to access the invoked command handler's data pointer, * rather than accessing the variable directly. It may be moved. */ #define CMD_DATA (CMD_CURRENT->jim_handler_data) /** * The type signature for command handling functions. They are * usually registered as part of command_registration, providing * a high-level means for executing a command. * * If the command fails, it *MUST* return a value != ERROR_OK * (many commands break this rule, patches welcome!) * * This is *especially* important for commands such as writing * to flash or verifying memory. The reason is that those commands * can be used by programs to determine if the operation succeeded * or not. If the operation failed, then a program can try * an alternative approach. * * Returning ERROR_COMMAND_SYNTAX_ERROR will have the effect of * printing out the syntax of the command. */ typedef __COMMAND_HANDLER((*command_handler_t)); struct command { char *name; command_handler_t handler; Jim_CmdProc *jim_handler; void *jim_handler_data; /* Command handlers can use it for any handler specific data */ struct target *jim_override_target; /* Used only for target of target-prefixed cmd */ enum command_mode mode; }; /* * Return the struct command pointer kept in private data * Used to enforce check on data type */ static inline struct command *jim_to_command(Jim_Interp *interp) { return Jim_CmdPrivData(interp); } /* * Commands should be registered by filling in one or more of these * structures and passing them to [un]register_commands(). * * A conventional format should be used for help strings, to provide both * usage and basic information: * @code * "@<options@> ... - some explanation text" * @endcode * * @param name The name of the command to register, which must not have * been registered previously in the intended context. * @param handler The callback function that will be called. If NULL, * then the command serves as a placeholder for its children or a script. * @param mode The command mode(s) in which this command may be run. * @param help The help text that will be displayed to the user. */ struct command_registration { const char *name; command_handler_t handler; Jim_CmdProc *jim_handler; enum command_mode mode; const char *help; /** a string listing the options and arguments, required or optional */ const char *usage; /** * If non-NULL, the commands in @c chain will be registered in * the same context and scope of this registration record. * This allows modules to inherit lists commands from other * modules. */ const struct command_registration *chain; }; /** Use this as the last entry in an array of command_registration records. */ #define COMMAND_REGISTRATION_DONE { .name = NULL, .chain = NULL } int __register_commands(struct command_context *cmd_ctx, const char *cmd_prefix, const struct command_registration *cmds, void *data, struct target *override_target); /** * Register one or more commands in the specified context, as children * of @c parent (or top-level commends, if NULL). In a registration's * record contains a non-NULL @c chain member and name is NULL, the * commands on the chain will be registered in the same context. * Otherwise, the chained commands are added as children of the command. * * @param cmd_ctx The command_context in which to register the command. * @param cmd_prefix Register this command as a child of this, or NULL to * register a top-level command. * @param cmds Pointer to an array of command_registration records that * contains the desired command parameters. The last record must have * NULL for all fields. * @returns ERROR_OK on success; ERROR_FAIL if any registration fails. */ static inline int register_commands(struct command_context *cmd_ctx, const char *cmd_prefix, const struct command_registration *cmds) { return __register_commands(cmd_ctx, cmd_prefix, cmds, NULL, NULL); } /** * Register one or more commands, as register_commands(), plus specify * that command should override the current target * * @param cmd_ctx The command_context in which to register the command. * @param cmd_prefix Register this command as a child of this, or NULL to * register a top-level command. * @param cmds Pointer to an array of command_registration records that * contains the desired command parameters. The last record must have * NULL for all fields. * @param target The target that has to override current target. * @returns ERROR_OK on success; ERROR_FAIL if any registration fails. */ static inline int register_commands_override_target(struct command_context *cmd_ctx, const char *cmd_prefix, const struct command_registration *cmds, struct target *target) { return __register_commands(cmd_ctx, cmd_prefix, cmds, NULL, target); } /** * Register one or more commands, as register_commands(), plus specify * a pointer to command private data that would be accessible through * the macro CMD_DATA. The private data will not be freed when command * is unregistered. * * @param cmd_ctx The command_context in which to register the command. * @param cmd_prefix Register this command as a child of this, or NULL to * register a top-level command. * @param cmds Pointer to an array of command_registration records that * contains the desired command parameters. The last record must have * NULL for all fields. * @param data The command private data. * @returns ERROR_OK on success; ERROR_FAIL if any registration fails. */ static inline int register_commands_with_data(struct command_context *cmd_ctx, const char *cmd_prefix, const struct command_registration *cmds, void *data) { return __register_commands(cmd_ctx, cmd_prefix, cmds, data, NULL); } /** * Unregisters all commands from the specified context. * @param cmd_ctx The context that will be cleared of registered commands. * @param cmd_prefix If given, only clear commands from under this one command. * @returns ERROR_OK on success, or an error code. */ int unregister_all_commands(struct command_context *cmd_ctx, const char *cmd_prefix); /** * Unregisters the help for all commands. Used at exit to remove the help * added through the commands 'add_help_text' and 'add_usage_text'. * @param cmd_ctx The context that will be cleared of registered helps. * @returns ERROR_OK on success, or an error code. */ int help_del_all_commands(struct command_context *cmd_ctx); void command_set_output_handler(struct command_context *context, command_output_handler_t output_handler, void *priv); int command_context_mode(struct command_context *context, enum command_mode mode); /* Return the current command context associated with the Jim interpreter or * alternatively the global default command interpreter */ struct command_context *current_command_context(Jim_Interp *interp); /** * Creates a new command context using the startup TCL provided and * the existing Jim interpreter, if any. If interp == NULL, then command_init * creates a command interpreter. */ struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp); /** * Shutdown a command context. * * Free the command context and the associated Jim interpreter. * * @param context The command_context that will be destroyed. */ void command_exit(struct command_context *context); /** * Creates a copy of an existing command context. This does not create * a deep copy of the command list, so modifications in one context will * affect all shared contexts. The caller must track reference counting * and ensure the commands are freed before destroying the last instance. * @param cmd_ctx The command_context that will be copied. * @returns A new command_context with the same state as the original. */ struct command_context *copy_command_context(struct command_context *cmd_ctx); /** * Frees the resources associated with a command context. The commands * are not removed, so unregister_all_commands() must be called first. * @param context The command_context that will be destroyed. */ void command_done(struct command_context *context); /* * command_print() and command_print_sameline() are used to produce the TCL * output of OpenOCD commands. command_print() automatically adds a '\n' at * the end or the format string. Use command_print_sameline() to avoid the * trailing '\n', e.g. to concatenate the command output in the same line. * The very last '\n' of the command is stripped away (see run_command()). * For commands that strictly require a '\n' as last output character, add * it explicitly with either an empty command_print() or with a '\n' in the * last command_print() and add a comment to document it. */ void command_print(struct command_invocation *cmd, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); void command_print_sameline(struct command_invocation *cmd, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); int command_run_line(struct command_context *context, char *line); int command_run_linef(struct command_context *context, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); void command_output_text(struct command_context *context, const char *data); void process_jim_events(struct command_context *cmd_ctx); #define ERROR_COMMAND_CLOSE_CONNECTION (-600) #define ERROR_COMMAND_SYNTAX_ERROR (-601) #define ERROR_COMMAND_NOTFOUND (-602) #define ERROR_COMMAND_ARGUMENT_INVALID (-603) #define ERROR_COMMAND_ARGUMENT_OVERFLOW (-604) #define ERROR_COMMAND_ARGUMENT_UNDERFLOW (-605) int parse_ulong(const char *str, unsigned long *ul); int parse_ullong(const char *str, unsigned long long *ul); int parse_long(const char *str, long *ul); int parse_llong(const char *str, long long *ul); #define DECLARE_PARSE_WRAPPER(name, type) \ int parse ## name(const char *str, type * ul) DECLARE_PARSE_WRAPPER(_uint, unsigned); DECLARE_PARSE_WRAPPER(_u64, uint64_t); DECLARE_PARSE_WRAPPER(_u32, uint32_t); DECLARE_PARSE_WRAPPER(_u16, uint16_t); DECLARE_PARSE_WRAPPER(_u8, uint8_t); DECLARE_PARSE_WRAPPER(_int, int); DECLARE_PARSE_WRAPPER(_s64, int64_t); DECLARE_PARSE_WRAPPER(_s32, int32_t); DECLARE_PARSE_WRAPPER(_s16, int16_t); DECLARE_PARSE_WRAPPER(_s8, int8_t); DECLARE_PARSE_WRAPPER(_target_addr, target_addr_t); /** * @brief parses the string @a in into @a out as a @a type, or prints * a command error and passes the error code to the caller. If an error * does occur, the calling function will return the error code produced * by the parsing function (one of ERROR_COMMAND_ARGUMENT_*). * * This function may cause the calling function to return immediately, * so it should be used carefully to avoid leaking resources. In most * situations, parsing should be completed in full before proceeding * to allocate resources, and this strategy will most prevents leaks. */ #define COMMAND_PARSE_NUMBER(type, in, out) \ do { \ int retval_macro_tmp = parse_ ## type(in, &(out)); \ if (retval_macro_tmp != ERROR_OK) { \ command_print(CMD, stringify(out) \ " option value ('%s') is not valid", in); \ return retval_macro_tmp; \ } \ } while (0) #define COMMAND_PARSE_ADDRESS(in, out) \ COMMAND_PARSE_NUMBER(target_addr, in, out) /** * @brief parses the command argument at position @a argn into @a out * as a @a type, or prints a command error referring to @a name_str * and passes the error code to the caller. @a argn will be incremented * if no error occurred. Otherwise the calling function will return * the error code produced by the parsing function. * * This function may cause the calling function to return immediately, * so it should be used carefully to avoid leaking resources. In most * situations, parsing should be completed in full before proceeding * to allocate resources, and this strategy will most prevents leaks. */ #define COMMAND_PARSE_ADDITIONAL_NUMBER(type, argn, out, name_str) \ do { \ if (argn+1 >= CMD_ARGC || CMD_ARGV[argn+1][0] == '-') { \ command_print(CMD, "no " name_str " given"); \ return ERROR_FAIL; \ } \ ++argn; \ COMMAND_PARSE_NUMBER(type, CMD_ARGV[argn], out); \ } while (0) /** * @brief parses the command argument at position @a argn into @a out * as a @a type if the argument @a argn does not start with '-'. * and passes the error code to the caller. @a argn will be incremented * if no error occurred. Otherwise the calling function will return * the error code produced by the parsing function. * * This function may cause the calling function to return immediately, * so it should be used carefully to avoid leaking resources. In most * situations, parsing should be completed in full before proceeding * to allocate resources, and this strategy will most prevents leaks. */ #define COMMAND_PARSE_OPTIONAL_NUMBER(type, argn, out) \ do { \ if (argn+1 < CMD_ARGC && CMD_ARGV[argn+1][0] != '-') { \ ++argn; \ COMMAND_PARSE_NUMBER(type, CMD_ARGV[argn], out); \ } \ } while (0) /** * Parse the string @c as a binary parameter, storing the boolean value * in @c out. The strings @c on and @c off are used to match different * strings for true and false options (e.g. "on" and "off" or * "enable" and "disable"). */ #define COMMAND_PARSE_BOOL(in, out, on, off) \ do { \ bool value; \ int retval_macro_tmp = command_parse_bool_arg(in, &value); \ if (retval_macro_tmp != ERROR_OK) { \ command_print(CMD, stringify(out) \ " option value ('%s') is not valid", in); \ command_print(CMD, " choices are '%s' or '%s'", \ on, off); \ return retval_macro_tmp; \ } \ out = value; \ } while (0) int command_parse_bool_arg(const char *in, bool *out); COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label); /** parses an on/off command argument */ #define COMMAND_PARSE_ON_OFF(in, out) \ COMMAND_PARSE_BOOL(in, out, "on", "off") /** parses an enable/disable command argument */ #define COMMAND_PARSE_ENABLE(in, out) \ COMMAND_PARSE_BOOL(in, out, "enable", "disable") #endif /* OPENOCD_HELPER_COMMAND_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/compiler.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * This file contains compiler specific workarounds to handle different * compilers and different compiler versions. * Inspired by Linux's include/linux/compiler_attributes.h * and file sys/cdefs.h in libc and newlib. */ #ifndef OPENOCD_HELPER_COMPILER_H #define OPENOCD_HELPER_COMPILER_H /* * __has_attribute is supported on gcc >= 5, clang >= 2.9 and icc >= 17. */ #ifndef __has_attribute # define __has_attribute(x) 0 #endif /* * The __returns_nonnull function attribute marks the return type of the function * as always being non-null. */ #ifndef __returns_nonnull # if __has_attribute(__returns_nonnull__) # define __returns_nonnull __attribute__((__returns_nonnull__)) # else # define __returns_nonnull # endif #endif /* * The __nonnull function attribute marks pointer parameters that * must not be NULL. * * clang for Apple defines * #define __nonnull _Nonnull * that is a per argument attribute, incompatible with the gcc per function attribute __nonnull__. * gcc for Apple includes sys/cdefs.h from MacOSX.sdk that defines * #define __nonnull * In both cases, undefine __nonnull to keep compatibility among compilers and platforms. */ #if defined(__APPLE__) # undef __nonnull #endif #ifndef __nonnull # if __has_attribute(__nonnull__) # define __nonnull(params) __attribute__ ((__nonnull__ params)) # else # define __nonnull(params) # endif #endif #endif /* OPENOCD_HELPER_COMPILER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/configuration.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "configuration.h" #include "log.h" #include "replacements.h" static size_t num_config_files; static char **config_file_names; static size_t num_script_dirs; static char **script_search_dirs; void add_script_search_dir(const char *dir) { num_script_dirs++; script_search_dirs = realloc(script_search_dirs, (num_script_dirs + 1) * sizeof(char *)); script_search_dirs[num_script_dirs-1] = strdup(dir); script_search_dirs[num_script_dirs] = NULL; LOG_DEBUG("adding %s", dir); } void add_config_command(const char *cfg) { num_config_files++; config_file_names = realloc(config_file_names, (num_config_files + 1) * sizeof(char *)); config_file_names[num_config_files-1] = strdup(cfg); config_file_names[num_config_files] = NULL; } void free_config(void) { while (num_config_files) free(config_file_names[--num_config_files]); free(config_file_names); config_file_names = NULL; while (num_script_dirs) free(script_search_dirs[--num_script_dirs]); free(script_search_dirs); script_search_dirs = NULL; } /* return full path or NULL according to search rules */ char *find_file(const char *file) { FILE *fp = NULL; char **search_dirs = script_search_dirs; char *dir; char const *mode = "r"; char *full_path; /* Check absolute and relative to current working dir first. * This keeps full_path reporting belowing working. */ full_path = alloc_printf("%s", file); fp = fopen(full_path, mode); while (!fp) { free(full_path); full_path = NULL; dir = *search_dirs++; if (!dir) break; full_path = alloc_printf("%s/%s", dir, file); fp = fopen(full_path, mode); } if (fp) { fclose(fp); LOG_DEBUG("found %s", full_path); return full_path; } free(full_path); return NULL; } FILE *open_file_from_path(const char *file, const char *mode) { if (mode[0] != 'r') return fopen(file, mode); else { char *full_path = find_file(file); if (!full_path) return NULL; FILE *fp = NULL; fp = fopen(full_path, mode); free(full_path); return fp; } } int parse_config_file(struct command_context *cmd_ctx) { int retval; char **cfg; if (!config_file_names) { command_run_line(cmd_ctx, "script openocd.cfg"); return ERROR_OK; } cfg = config_file_names; while (*cfg) { retval = command_run_line(cmd_ctx, *cfg); if (retval != ERROR_OK) return retval; cfg++; } return ERROR_OK; } #ifndef _WIN32 #include <pwd.h> #endif char *get_home_dir(const char *append_path) { #ifdef _WIN32 char homepath[MAX_PATH]; #endif char *home = getenv("HOME"); if (!home) { #ifdef _WIN32 home = getenv("USERPROFILE"); if (!home) { char *drive = getenv("HOMEDRIVE"); char *path = getenv("HOMEPATH"); if (drive && path) { snprintf(homepath, MAX_PATH, "%s/%s", drive, path); home = homepath; } } #else struct passwd *pwd = getpwuid(getuid()); if (pwd) home = pwd->pw_dir; #endif } if (!home) return home; char *home_path; if (append_path) home_path = alloc_printf("%s/%s", home, append_path); else home_path = alloc_printf("%s", home); return home_path; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/configuration.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifndef OPENOCD_HELPER_CONFIGURATION_H #define OPENOCD_HELPER_CONFIGURATION_H #include <helper/command.h> #include <stdio.h> int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[]); int parse_config_file(struct command_context *cmd_ctx); void add_config_command(const char *cfg); void add_script_search_dir(const char *dir); void free_config(void); int configuration_output_handler(struct command_context *cmd_ctx, const char *line); FILE *open_file_from_path(const char *file, const char *mode); char *find_file(const char *name); char *get_home_dir(const char *append_path); #endif /* OPENOCD_HELPER_CONFIGURATION_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/crc32.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013-2014 by Franck Jullien * * elec4fun@gmail.com * * * * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg * * marian.buschsieweke@ovgu.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "crc32.h" #include <stdint.h> #include <stddef.h> static uint32_t crc_le_step(uint32_t poly, uint32_t crc, uint32_t data_in, unsigned int data_bits) { for (unsigned int i = 0; i < data_bits; i++) { uint32_t d, c; d = ((data_in >> i) & 0x1) ? 0xffffffff : 0; c = (crc & 0x1) ? 0xffffffff : 0; crc = crc >> 1; crc = crc ^ ((d ^ c) & poly); } return crc; } uint32_t crc32_le(uint32_t poly, uint32_t seed, const void *_data, size_t data_len) { if (((uintptr_t)_data & 0x3) || (data_len & 0x3)) { /* data is unaligned, processing data one byte at a time */ const uint8_t *data = _data; for (size_t i = 0; i < data_len; i++) seed = crc_le_step(poly, seed, data[i], 8); } else { /* data is aligned, processing 32 bit at a time */ data_len >>= 2; const uint32_t *data = _data; for (size_t i = 0; i < data_len; i++) seed = crc_le_step(poly, seed, data[i], 32); } return seed; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/crc32.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg * * marian.buschsieweke@ovgu.de * ***************************************************************************/ #ifndef OPENOCD_HELPER_CRC32_H #define OPENOCD_HELPER_CRC32_H #include <stdint.h> #include <stddef.h> /** @file * A generic CRC32 implementation */ /** * CRC32 polynomial commonly used for little endian CRC32 */ #define CRC32_POLY_LE 0xedb88320 /** * Calculate the CRC32 value of the given data * @param poly The polynomial of the CRC * @param seed The seed to use (mostly either `0` or `0xffffffff`) * @param data The data to calculate the CRC32 of * @param data_len The length of the data in @p data in bytes * @return The CRC value of the first @p data_len bytes at @p data * @note This function can be used to incrementally compute the CRC one * chunk of data at a time by using the CRC32 of the previous chunk * as @p seed for the next chunk. */ uint32_t crc32_le(uint32_t poly, uint32_t seed, const void *data, size_t data_len); #endif /* OPENOCD_HELPER_CRC32_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/fileio.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "log.h" #include "configuration.h" #include "fileio.h" #include "replacements.h" struct fileio { char *url; size_t size; enum fileio_type type; enum fileio_access access; FILE *file; }; static inline int fileio_close_local(struct fileio *fileio) { int retval = fclose(fileio->file); if (retval != 0) { if (retval == EBADF) LOG_ERROR("BUG: fileio->file not a valid file descriptor"); else LOG_ERROR("couldn't close %s: %s", fileio->url, strerror(errno)); return ERROR_FILEIO_OPERATION_FAILED; } return ERROR_OK; } static inline int fileio_open_local(struct fileio *fileio) { char file_access[4]; ssize_t file_size; switch (fileio->access) { case FILEIO_READ: strcpy(file_access, "r"); break; case FILEIO_WRITE: strcpy(file_access, "w"); break; case FILEIO_READWRITE: strcpy(file_access, "w+"); break; case FILEIO_APPEND: strcpy(file_access, "a"); break; case FILEIO_APPENDREAD: strcpy(file_access, "a+"); break; default: LOG_ERROR("BUG: access neither read, write nor readwrite"); return ERROR_COMMAND_SYNTAX_ERROR; } /* win32 always opens in binary mode */ #ifndef _WIN32 if (fileio->type == FILEIO_BINARY) #endif strcat(file_access, "b"); fileio->file = open_file_from_path(fileio->url, file_access); if (!fileio->file) { LOG_ERROR("couldn't open %s", fileio->url); return ERROR_FILEIO_OPERATION_FAILED; } file_size = 0; if ((fileio->access != FILEIO_WRITE) || (fileio->access == FILEIO_READWRITE)) { /* NB! Here we use fseek() instead of stat(), since stat is a * more advanced operation that might not apply to e.g. a disk path * that refers to e.g. a tftp client */ int result, result2; result = fseek(fileio->file, 0, SEEK_END); file_size = ftell(fileio->file); result2 = fseek(fileio->file, 0, SEEK_SET); if ((file_size < 0) || (result < 0) || (result2 < 0)) { fileio_close_local(fileio); return ERROR_FILEIO_OPERATION_FAILED; } } fileio->size = file_size; return ERROR_OK; } int fileio_open(struct fileio **fileio, const char *url, enum fileio_access access_type, enum fileio_type type) { int retval; struct fileio *tmp; tmp = malloc(sizeof(struct fileio)); tmp->type = type; tmp->access = access_type; tmp->url = strdup(url); retval = fileio_open_local(tmp); if (retval != ERROR_OK) { free(tmp->url); free(tmp); return retval; } *fileio = tmp; return ERROR_OK; } int fileio_close(struct fileio *fileio) { int retval; retval = fileio_close_local(fileio); free(fileio->url); free(fileio); return retval; } int fileio_feof(struct fileio *fileio) { return feof(fileio->file); } int fileio_seek(struct fileio *fileio, size_t position) { int retval; retval = fseek(fileio->file, position, SEEK_SET); if (retval != 0) { LOG_ERROR("couldn't seek file %s: %s", fileio->url, strerror(errno)); return ERROR_FILEIO_OPERATION_FAILED; } return ERROR_OK; } static int fileio_local_read(struct fileio *fileio, size_t size, void *buffer, size_t *size_read) { ssize_t retval; retval = fread(buffer, 1, size, fileio->file); *size_read = (retval >= 0) ? retval : 0; return (retval < 0) ? retval : ERROR_OK; } int fileio_read(struct fileio *fileio, size_t size, void *buffer, size_t *size_read) { return fileio_local_read(fileio, size, buffer, size_read); } int fileio_read_u32(struct fileio *fileio, uint32_t *data) { int retval; uint8_t buf[4]; size_t size_read; retval = fileio_local_read(fileio, sizeof(uint32_t), buf, &size_read); if (retval == ERROR_OK && sizeof(uint32_t) != size_read) retval = -EIO; if (retval == ERROR_OK) *data = be_to_h_u32(buf); return retval; } static int fileio_local_fgets(struct fileio *fileio, size_t size, void *buffer) { if (!fgets(buffer, size, fileio->file)) return ERROR_FILEIO_OPERATION_FAILED; return ERROR_OK; } int fileio_fgets(struct fileio *fileio, size_t size, void *buffer) { return fileio_local_fgets(fileio, size, buffer); } static int fileio_local_write(struct fileio *fileio, size_t size, const void *buffer, size_t *size_written) { ssize_t retval; retval = fwrite(buffer, 1, size, fileio->file); *size_written = (retval >= 0) ? retval : 0; return (retval < 0) ? retval : ERROR_OK; } int fileio_write(struct fileio *fileio, size_t size, const void *buffer, size_t *size_written) { int retval; retval = fileio_local_write(fileio, size, buffer, size_written); if (retval == ERROR_OK) fileio->size += *size_written; return retval; } int fileio_write_u32(struct fileio *fileio, uint32_t data) { int retval; uint8_t buf[4]; h_u32_to_be(buf, data); size_t size_written; retval = fileio_write(fileio, 4, buf, &size_written); if (retval == ERROR_OK && size_written != sizeof(uint32_t)) retval = -EIO; return retval; } /** * FIX!!!! * * For now this can not fail, but that's because a seek was executed * on startup. * * Avoiding the seek on startup opens up for using streams. * */ int fileio_size(struct fileio *fileio, size_t *size) { *size = fileio->size; return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/fileio.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_HELPER_FILEIO_H #define OPENOCD_HELPER_FILEIO_H #include "types.h" #define FILEIO_MAX_ERROR_STRING (128) enum fileio_type { FILEIO_TEXT, FILEIO_BINARY, }; enum fileio_access { FILEIO_NONE, /* open without any access (invalid mode) */ FILEIO_READ, /* open for reading, position at beginning */ FILEIO_WRITE, /* open for writing, position at beginning */ FILEIO_READWRITE, /* open for writing, position at beginning, allow reading */ FILEIO_APPEND, /* open for writing, position at end */ FILEIO_APPENDREAD, /* open for writing, position at end, allow reading */ }; struct fileio; int fileio_open(struct fileio **fileio, const char *url, enum fileio_access access_type, enum fileio_type type); int fileio_close(struct fileio *fileio); int fileio_feof(struct fileio *fileio); int fileio_seek(struct fileio *fileio, size_t position); int fileio_fgets(struct fileio *fileio, size_t size, void *buffer); int fileio_read(struct fileio *fileio, size_t size, void *buffer, size_t *size_read); int fileio_write(struct fileio *fileio, size_t size, const void *buffer, size_t *size_written); int fileio_read_u32(struct fileio *fileio, uint32_t *data); int fileio_write_u32(struct fileio *fileio, uint32_t data); int fileio_size(struct fileio *fileio, size_t *size); #define ERROR_FILEIO_LOCATION_UNKNOWN (-1200) #define ERROR_FILEIO_NOT_FOUND (-1201) #define ERROR_FILEIO_OPERATION_FAILED (-1202) #define ERROR_FILEIO_ACCESS_NOT_SUPPORTED (-1203) #define ERROR_FILEIO_RESOURCE_TYPE_UNKNOWN (-1204) #define ERROR_FILEIO_OPERATION_NOT_SUPPORTED (-1205) #endif /* OPENOCD_HELPER_FILEIO_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/jep106.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2015 Andreas Fritiofson * * andreas.fritiofson@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jep106.h" #include "log.h" static const char * const jep106[][126] = { #include "jep106.inc" }; const char *jep106_table_manufacturer(unsigned int bank, unsigned int id) { if (id < 1 || id > 126) { LOG_DEBUG("BUG: Caller passed out-of-range JEP106 ID!"); return "<invalid>"; } /* index is zero based */ id--; if (bank >= ARRAY_SIZE(jep106) || !jep106[bank][id]) return "<unknown>"; return jep106[bank][id]; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/jep106.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2015 Andreas Fritiofson * * andreas.fritiofson@gmail.com * ***************************************************************************/ #ifndef OPENOCD_HELPER_JEP106_H #define OPENOCD_HELPER_JEP106_H /** * Get the manufacturer name associated with a JEP106 ID. * @param bank The bank (number of continuation codes) of the manufacturer ID. * @param id The 7-bit manufacturer ID (i.e. with parity stripped). * @return A pointer to static const storage containing the name of the * manufacturer associated with bank and id, or one of the strings * "<invalid>" and "<unknown>". */ const char *jep106_table_manufacturer(unsigned int bank, unsigned int id); static inline const char *jep106_manufacturer(unsigned int manufacturer) { return jep106_table_manufacturer(manufacturer >> 7, manufacturer & 0x7f); } #endif /* OPENOCD_HELPER_JEP106_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/jep106.inc ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * The manufacturer's standard identification code list appears in JEP106. * Copyright (c) 2022 JEDEC. All rights reserved. * * JEP106 is regularly updated. For the current manufacturer's standard * identification code list, please visit the JEDEC website at www.jedec.org . */ /* This file is aligned to revision JEP106BG May 2023. */ /* "NXP (Philips)" is reported below, while missing in JEP106BG */ [0][0x01 - 1] = "AMD", [0][0x02 - 1] = "AMI", [0][0x03 - 1] = "Fairchild", [0][0x04 - 1] = "Fujitsu", [0][0x05 - 1] = "GTE", [0][0x06 - 1] = "Harris", [0][0x07 - 1] = "Hitachi", [0][0x08 - 1] = "Inmos", [0][0x09 - 1] = "Intel", [0][0x0a - 1] = "I.T.T.", [0][0x0b - 1] = "Intersil", [0][0x0c - 1] = "Monolithic Memories", [0][0x0d - 1] = "Mostek", [0][0x0e - 1] = "Freescale (Motorola)", [0][0x0f - 1] = "National", [0][0x10 - 1] = "NEC", [0][0x11 - 1] = "RCA", [0][0x12 - 1] = "Raytheon", [0][0x13 - 1] = "Conexant (Rockwell)", [0][0x14 - 1] = "Seeq", [0][0x15 - 1] = "NXP (Philips)", [0][0x16 - 1] = "Synertek", [0][0x17 - 1] = "Texas Instruments", [0][0x18 - 1] = "Kioxia Corporation", [0][0x19 - 1] = "Xicor", [0][0x1a - 1] = "Zilog", [0][0x1b - 1] = "Eurotechnique", [0][0x1c - 1] = "Mitsubishi", [0][0x1d - 1] = "Lucent (AT&T)", [0][0x1e - 1] = "Exel", [0][0x1f - 1] = "Atmel", [0][0x20 - 1] = "STMicroelectronics", [0][0x21 - 1] = "Lattice Semi.", [0][0x22 - 1] = "NCR", [0][0x23 - 1] = "Wafer Scale Integration", [0][0x24 - 1] = "IBM", [0][0x25 - 1] = "Tristar", [0][0x26 - 1] = "Visic", [0][0x27 - 1] = "Intl. CMOS Technology", [0][0x28 - 1] = "SSSI", [0][0x29 - 1] = "Microchip Technology", [0][0x2a - 1] = "Ricoh Ltd", [0][0x2b - 1] = "VLSI", [0][0x2c - 1] = "Micron Technology", [0][0x2d - 1] = "SK Hynix", [0][0x2e - 1] = "OKI Semiconductor", [0][0x2f - 1] = "ACTEL", [0][0x30 - 1] = "Sharp", [0][0x31 - 1] = "Catalyst", [0][0x32 - 1] = "Panasonic", [0][0x33 - 1] = "IDT", [0][0x34 - 1] = "Cypress", [0][0x35 - 1] = "DEC", [0][0x36 - 1] = "LSI Logic", [0][0x37 - 1] = "Zarlink (Plessey)", [0][0x38 - 1] = "UTMC", [0][0x39 - 1] = "Thinking Machine", [0][0x3a - 1] = "Thomson CSF", [0][0x3b - 1] = "Integrated CMOS (Vertex)", [0][0x3c - 1] = "Honeywell", [0][0x3d - 1] = "Tektronix", [0][0x3e - 1] = "Oracle Corporation", [0][0x3f - 1] = "Silicon Storage Technology", [0][0x40 - 1] = "ProMos/Mosel Vitelic", [0][0x41 - 1] = "Infineon (Siemens)", [0][0x42 - 1] = "Macronix", [0][0x43 - 1] = "Xerox", [0][0x44 - 1] = "Plus Logic", [0][0x45 - 1] = "Western Digital Technologies Inc", [0][0x46 - 1] = "Elan Circuit Tech.", [0][0x47 - 1] = "European Silicon Str.", [0][0x48 - 1] = "Apple Computer", [0][0x49 - 1] = "Xilinx", [0][0x4a - 1] = "Compaq", [0][0x4b - 1] = "Protocol Engines", [0][0x4c - 1] = "SCI", [0][0x4d - 1] = "ABLIC", [0][0x4e - 1] = "Samsung", [0][0x4f - 1] = "I3 Design System", [0][0x50 - 1] = "Klic", [0][0x51 - 1] = "Crosspoint Solutions", [0][0x52 - 1] = "Alliance Memory Inc", [0][0x53 - 1] = "Tandem", [0][0x54 - 1] = "Hewlett-Packard", [0][0x55 - 1] = "Integrated Silicon Solutions", [0][0x56 - 1] = "Brooktree", [0][0x57 - 1] = "New Media", [0][0x58 - 1] = "MHS Electronic", [0][0x59 - 1] = "Performance Semi.", [0][0x5a - 1] = "Winbond Electronic", [0][0x5b - 1] = "Kawasaki Steel", [0][0x5c - 1] = "Bright Micro", [0][0x5d - 1] = "TECMAR", [0][0x5e - 1] = "Exar", [0][0x5f - 1] = "PCMCIA", [0][0x60 - 1] = "LG Semi (Goldstar)", [0][0x61 - 1] = "Northern Telecom", [0][0x62 - 1] = "Sanyo", [0][0x63 - 1] = "Array Microsystems", [0][0x64 - 1] = "Crystal Semiconductor", [0][0x65 - 1] = "Analog Devices", [0][0x66 - 1] = "PMC-Sierra", [0][0x67 - 1] = "Asparix", [0][0x68 - 1] = "Convex Computer", [0][0x69 - 1] = "Quality Semiconductor", [0][0x6a - 1] = "Nimbus Technology", [0][0x6b - 1] = "Transwitch", [0][0x6c - 1] = "Micronas (ITT Intermetall)", [0][0x6d - 1] = "Cannon", [0][0x6e - 1] = "Altera", [0][0x6f - 1] = "NEXCOM", [0][0x70 - 1] = "Qualcomm", [0][0x71 - 1] = "Sony", [0][0x72 - 1] = "Cray Research", [0][0x73 - 1] = "AMS(Austria Micro)", [0][0x74 - 1] = "Vitesse", [0][0x75 - 1] = "Aster Electronics", [0][0x76 - 1] = "Bay Networks (Synoptic)", [0][0x77 - 1] = "Zentrum/ZMD", [0][0x78 - 1] = "TRW", [0][0x79 - 1] = "Thesys", [0][0x7a - 1] = "Solbourne Computer", [0][0x7b - 1] = "Allied-Signal", [0][0x7c - 1] = "Dialog Semiconductor", [0][0x7d - 1] = "Media Vision", [0][0x7e - 1] = "Numonyx Corporation", [1][0x01 - 1] = "Cirrus Logic", [1][0x02 - 1] = "National Instruments", [1][0x03 - 1] = "ILC Data Device", [1][0x04 - 1] = "Alcatel Mietec", [1][0x05 - 1] = "Micro Linear", [1][0x06 - 1] = "Univ. of NC", [1][0x07 - 1] = "JTAG Technologies", [1][0x08 - 1] = "BAE Systems (Loral)", [1][0x09 - 1] = "Nchip", [1][0x0a - 1] = "Galileo Tech", [1][0x0b - 1] = "Bestlink Systems", [1][0x0c - 1] = "Graychip", [1][0x0d - 1] = "GENNUM", [1][0x0e - 1] = "Imagination Technologies Limited", [1][0x0f - 1] = "Robert Bosch", [1][0x10 - 1] = "Chip Express", [1][0x11 - 1] = "DATARAM", [1][0x12 - 1] = "United Microelectronics Corp", [1][0x13 - 1] = "TCSI", [1][0x14 - 1] = "Smart Modular", [1][0x15 - 1] = "Hughes Aircraft", [1][0x16 - 1] = "Lanstar Semiconductor", [1][0x17 - 1] = "Qlogic", [1][0x18 - 1] = "Kingston", [1][0x19 - 1] = "Music Semi", [1][0x1a - 1] = "Ericsson Components", [1][0x1b - 1] = "SpaSE", [1][0x1c - 1] = "Eon Silicon Devices", [1][0x1d - 1] = "Integrated Silicon Solution (ISSI)", [1][0x1e - 1] = "DoD", [1][0x1f - 1] = "Integ. Memories Tech.", [1][0x20 - 1] = "Corollary Inc", [1][0x21 - 1] = "Dallas Semiconductor", [1][0x22 - 1] = "Omnivision", [1][0x23 - 1] = "EIV(Switzerland)", [1][0x24 - 1] = "Novatel Wireless", [1][0x25 - 1] = "Zarlink (Mitel)", [1][0x26 - 1] = "Clearpoint", [1][0x27 - 1] = "Cabletron", [1][0x28 - 1] = "STEC (Silicon Tech)", [1][0x29 - 1] = "Vanguard", [1][0x2a - 1] = "Hagiwara Sys-Com", [1][0x2b - 1] = "Vantis", [1][0x2c - 1] = "Celestica", [1][0x2d - 1] = "Century", [1][0x2e - 1] = "Hal Computers", [1][0x2f - 1] = "Rohm Company Ltd", [1][0x30 - 1] = "Juniper Networks", [1][0x31 - 1] = "Libit Signal Processing", [1][0x32 - 1] = "Mushkin Enhanced Memory", [1][0x33 - 1] = "Tundra Semiconductor", [1][0x34 - 1] = "Adaptec Inc", [1][0x35 - 1] = "LightSpeed Semi.", [1][0x36 - 1] = "ZSP Corp", [1][0x37 - 1] = "AMIC Technology", [1][0x38 - 1] = "Adobe Systems", [1][0x39 - 1] = "Dynachip", [1][0x3a - 1] = "PNY Technologies Inc", [1][0x3b - 1] = "Newport Digital", [1][0x3c - 1] = "MMC Networks", [1][0x3d - 1] = "T Square", [1][0x3e - 1] = "Seiko Epson", [1][0x3f - 1] = "Broadcom", [1][0x40 - 1] = "Viking Components", [1][0x41 - 1] = "V3 Semiconductor", [1][0x42 - 1] = "Flextronics (Orbit Semiconductor)", [1][0x43 - 1] = "Suwa Electronics", [1][0x44 - 1] = "Transmeta", [1][0x45 - 1] = "Micron CMS", [1][0x46 - 1] = "American Computer & Digital Components Inc", [1][0x47 - 1] = "Enhance 3000 Inc", [1][0x48 - 1] = "Tower Semiconductor", [1][0x49 - 1] = "CPU Design", [1][0x4a - 1] = "Price Point", [1][0x4b - 1] = "Maxim Integrated Product", [1][0x4c - 1] = "Tellabs", [1][0x4d - 1] = "Centaur Technology", [1][0x4e - 1] = "Unigen Corporation", [1][0x4f - 1] = "Transcend Information", [1][0x50 - 1] = "Memory Card Technology", [1][0x51 - 1] = "CKD Corporation Ltd", [1][0x52 - 1] = "Capital Instruments Inc", [1][0x53 - 1] = "Aica Kogyo Ltd", [1][0x54 - 1] = "Linvex Technology", [1][0x55 - 1] = "MSC Vertriebs GmbH", [1][0x56 - 1] = "AKM Company Ltd", [1][0x57 - 1] = "Dynamem Inc", [1][0x58 - 1] = "NERA ASA", [1][0x59 - 1] = "GSI Technology", [1][0x5a - 1] = "Dane-Elec (C Memory)", [1][0x5b - 1] = "Acorn Computers", [1][0x5c - 1] = "Lara Technology", [1][0x5d - 1] = "Oak Technology Inc", [1][0x5e - 1] = "Itec Memory", [1][0x5f - 1] = "Tanisys Technology", [1][0x60 - 1] = "Truevision", [1][0x61 - 1] = "Wintec Industries", [1][0x62 - 1] = "Super PC Memory", [1][0x63 - 1] = "MGV Memory", [1][0x64 - 1] = "Galvantech", [1][0x65 - 1] = "Gadzoox Networks", [1][0x66 - 1] = "Multi Dimensional Cons.", [1][0x67 - 1] = "GateField", [1][0x68 - 1] = "Integrated Memory System", [1][0x69 - 1] = "Triscend", [1][0x6a - 1] = "XaQti", [1][0x6b - 1] = "Goldenram", [1][0x6c - 1] = "Clear Logic", [1][0x6d - 1] = "Cimaron Communications", [1][0x6e - 1] = "Nippon Steel Semi. Corp", [1][0x6f - 1] = "Advantage Memory", [1][0x70 - 1] = "AMCC", [1][0x71 - 1] = "LeCroy", [1][0x72 - 1] = "Yamaha Corporation", [1][0x73 - 1] = "Digital Microwave", [1][0x74 - 1] = "NetLogic Microsystems", [1][0x75 - 1] = "MIMOS Semiconductor", [1][0x76 - 1] = "Advanced Fibre", [1][0x77 - 1] = "BF Goodrich Data.", [1][0x78 - 1] = "Epigram", [1][0x79 - 1] = "Acbel Polytech Inc", [1][0x7a - 1] = "Apacer Technology", [1][0x7b - 1] = "Admor Memory", [1][0x7c - 1] = "FOXCONN", [1][0x7d - 1] = "Quadratics Superconductor", [1][0x7e - 1] = "3COM", [2][0x01 - 1] = "Camintonn Corporation", [2][0x02 - 1] = "ISOA Incorporated", [2][0x03 - 1] = "Agate Semiconductor", [2][0x04 - 1] = "ADMtek Incorporated", [2][0x05 - 1] = "HYPERTEC", [2][0x06 - 1] = "Adhoc Technologies", [2][0x07 - 1] = "MOSAID Technologies", [2][0x08 - 1] = "Ardent Technologies", [2][0x09 - 1] = "Switchcore", [2][0x0a - 1] = "Cisco Systems Inc", [2][0x0b - 1] = "Allayer Technologies", [2][0x0c - 1] = "WorkX AG (Wichman)", [2][0x0d - 1] = "Oasis Semiconductor", [2][0x0e - 1] = "Novanet Semiconductor", [2][0x0f - 1] = "E-M Solutions", [2][0x10 - 1] = "Power General", [2][0x11 - 1] = "Advanced Hardware Arch.", [2][0x12 - 1] = "Inova Semiconductors GmbH", [2][0x13 - 1] = "Telocity", [2][0x14 - 1] = "Delkin Devices", [2][0x15 - 1] = "Symagery Microsystems", [2][0x16 - 1] = "C-Port Corporation", [2][0x17 - 1] = "SiberCore Technologies", [2][0x18 - 1] = "Southland Microsystems", [2][0x19 - 1] = "Malleable Technologies", [2][0x1a - 1] = "Kendin Communications", [2][0x1b - 1] = "Great Technology Microcomputer", [2][0x1c - 1] = "Sanmina Corporation", [2][0x1d - 1] = "HADCO Corporation", [2][0x1e - 1] = "Corsair", [2][0x1f - 1] = "Actrans System Inc", [2][0x20 - 1] = "ALPHA Technologies", [2][0x21 - 1] = "Silicon Laboratories Inc (Cygnal)", [2][0x22 - 1] = "Artesyn Technologies", [2][0x23 - 1] = "Align Manufacturing", [2][0x24 - 1] = "Peregrine Semiconductor", [2][0x25 - 1] = "Chameleon Systems", [2][0x26 - 1] = "Aplus Flash Technology", [2][0x27 - 1] = "MIPS Technologies", [2][0x28 - 1] = "Chrysalis ITS", [2][0x29 - 1] = "ADTEC Corporation", [2][0x2a - 1] = "Kentron Technologies", [2][0x2b - 1] = "Win Technologies", [2][0x2c - 1] = "Tezzaron Semiconductor", [2][0x2d - 1] = "Extreme Packet Devices", [2][0x2e - 1] = "RF Micro Devices", [2][0x2f - 1] = "Siemens AG", [2][0x30 - 1] = "Sarnoff Corporation", [2][0x31 - 1] = "Itautec SA", [2][0x32 - 1] = "Radiata Inc", [2][0x33 - 1] = "Benchmark Elect. (AVEX)", [2][0x34 - 1] = "Legend", [2][0x35 - 1] = "SpecTek Incorporated", [2][0x36 - 1] = "Hi/fn", [2][0x37 - 1] = "Enikia Incorporated", [2][0x38 - 1] = "SwitchOn Networks", [2][0x39 - 1] = "AANetcom Incorporated", [2][0x3a - 1] = "Micro Memory Bank", [2][0x3b - 1] = "ESS Technology", [2][0x3c - 1] = "Virata Corporation", [2][0x3d - 1] = "Excess Bandwidth", [2][0x3e - 1] = "West Bay Semiconductor", [2][0x3f - 1] = "DSP Group", [2][0x40 - 1] = "Newport Communications", [2][0x41 - 1] = "Chip2Chip Incorporated", [2][0x42 - 1] = "Phobos Corporation", [2][0x43 - 1] = "Intellitech Corporation", [2][0x44 - 1] = "Nordic VLSI ASA", [2][0x45 - 1] = "Ishoni Networks", [2][0x46 - 1] = "Silicon Spice", [2][0x47 - 1] = "Alchemy Semiconductor", [2][0x48 - 1] = "Agilent Technologies", [2][0x49 - 1] = "Centillium Communications", [2][0x4a - 1] = "W.L. Gore", [2][0x4b - 1] = "HanBit Electronics", [2][0x4c - 1] = "GlobeSpan", [2][0x4d - 1] = "Element 14", [2][0x4e - 1] = "Pycon", [2][0x4f - 1] = "Saifun Semiconductors", [2][0x50 - 1] = "Sibyte Incorporated", [2][0x51 - 1] = "MetaLink Technologies", [2][0x52 - 1] = "Feiya Technology", [2][0x53 - 1] = "I & C Technology", [2][0x54 - 1] = "Shikatronics", [2][0x55 - 1] = "Elektrobit", [2][0x56 - 1] = "Megic", [2][0x57 - 1] = "Com-Tier", [2][0x58 - 1] = "Malaysia Micro Solutions", [2][0x59 - 1] = "Hyperchip", [2][0x5a - 1] = "Gemstone Communications", [2][0x5b - 1] = "Anadigm (Anadyne)", [2][0x5c - 1] = "3ParData", [2][0x5d - 1] = "Mellanox Technologies", [2][0x5e - 1] = "Tenx Technologies", [2][0x5f - 1] = "Helix AG", [2][0x60 - 1] = "Domosys", [2][0x61 - 1] = "Skyup Technology", [2][0x62 - 1] = "HiNT Corporation", [2][0x63 - 1] = "Chiaro", [2][0x64 - 1] = "MDT Technologies GmbH", [2][0x65 - 1] = "Exbit Technology A/S", [2][0x66 - 1] = "Integrated Technology Express", [2][0x67 - 1] = "AVED Memory", [2][0x68 - 1] = "Legerity", [2][0x69 - 1] = "Jasmine Networks", [2][0x6a - 1] = "Caspian Networks", [2][0x6b - 1] = "nCUBE", [2][0x6c - 1] = "Silicon Access Networks", [2][0x6d - 1] = "FDK Corporation", [2][0x6e - 1] = "High Bandwidth Access", [2][0x6f - 1] = "MultiLink Technology", [2][0x70 - 1] = "BRECIS", [2][0x71 - 1] = "World Wide Packets", [2][0x72 - 1] = "APW", [2][0x73 - 1] = "Chicory Systems", [2][0x74 - 1] = "Xstream Logic", [2][0x75 - 1] = "Fast-Chip", [2][0x76 - 1] = "Zucotto Wireless", [2][0x77 - 1] = "Realchip", [2][0x78 - 1] = "Galaxy Power", [2][0x79 - 1] = "eSilicon", [2][0x7a - 1] = "Morphics Technology", [2][0x7b - 1] = "Accelerant Networks", [2][0x7c - 1] = "Silicon Wave", [2][0x7d - 1] = "SandCraft", [2][0x7e - 1] = "Elpida", [3][0x01 - 1] = "Solectron", [3][0x02 - 1] = "Optosys Technologies", [3][0x03 - 1] = "Buffalo (Formerly Melco)", [3][0x04 - 1] = "TriMedia Technologies", [3][0x05 - 1] = "Cyan Technologies", [3][0x06 - 1] = "Global Locate", [3][0x07 - 1] = "Optillion", [3][0x08 - 1] = "Terago Communications", [3][0x09 - 1] = "Ikanos Communications", [3][0x0a - 1] = "Princeton Technology", [3][0x0b - 1] = "Nanya Technology", [3][0x0c - 1] = "Elite Flash Storage", [3][0x0d - 1] = "Mysticom", [3][0x0e - 1] = "LightSand Communications", [3][0x0f - 1] = "ATI Technologies", [3][0x10 - 1] = "Agere Systems", [3][0x11 - 1] = "NeoMagic", [3][0x12 - 1] = "AuroraNetics", [3][0x13 - 1] = "Golden Empire", [3][0x14 - 1] = "Mushkin", [3][0x15 - 1] = "Tioga Technologies", [3][0x16 - 1] = "Netlist", [3][0x17 - 1] = "TeraLogic", [3][0x18 - 1] = "Cicada Semiconductor", [3][0x19 - 1] = "Centon Electronics", [3][0x1a - 1] = "Tyco Electronics", [3][0x1b - 1] = "Magis Works", [3][0x1c - 1] = "Zettacom", [3][0x1d - 1] = "Cogency Semiconductor", [3][0x1e - 1] = "Chipcon AS", [3][0x1f - 1] = "Aspex Technology", [3][0x20 - 1] = "F5 Networks", [3][0x21 - 1] = "Programmable Silicon Solutions", [3][0x22 - 1] = "ChipWrights", [3][0x23 - 1] = "Acorn Networks", [3][0x24 - 1] = "Quicklogic", [3][0x25 - 1] = "Kingmax Semiconductor", [3][0x26 - 1] = "BOPS", [3][0x27 - 1] = "Flasys", [3][0x28 - 1] = "BitBlitz Communications", [3][0x29 - 1] = "eMemory Technology", [3][0x2a - 1] = "Procket Networks", [3][0x2b - 1] = "Purple Ray", [3][0x2c - 1] = "Trebia Networks", [3][0x2d - 1] = "Delta Electronics", [3][0x2e - 1] = "Onex Communications", [3][0x2f - 1] = "Ample Communications", [3][0x30 - 1] = "Memory Experts Intl", [3][0x31 - 1] = "Astute Networks", [3][0x32 - 1] = "Azanda Network Devices", [3][0x33 - 1] = "Dibcom", [3][0x34 - 1] = "Tekmos", [3][0x35 - 1] = "API NetWorks", [3][0x36 - 1] = "Bay Microsystems", [3][0x37 - 1] = "Firecron Ltd", [3][0x38 - 1] = "Resonext Communications", [3][0x39 - 1] = "Tachys Technologies", [3][0x3a - 1] = "Equator Technology", [3][0x3b - 1] = "Concept Computer", [3][0x3c - 1] = "SILCOM", [3][0x3d - 1] = "3Dlabs", [3][0x3e - 1] = "c't Magazine", [3][0x3f - 1] = "Sanera Systems", [3][0x40 - 1] = "Silicon Packets", [3][0x41 - 1] = "Viasystems Group", [3][0x42 - 1] = "Simtek", [3][0x43 - 1] = "Semicon Devices Singapore", [3][0x44 - 1] = "Satron Handelsges", [3][0x45 - 1] = "Improv Systems", [3][0x46 - 1] = "INDUSYS GmbH", [3][0x47 - 1] = "Corrent", [3][0x48 - 1] = "Infrant Technologies", [3][0x49 - 1] = "Ritek Corp", [3][0x4a - 1] = "empowerTel Networks", [3][0x4b - 1] = "Hypertec", [3][0x4c - 1] = "Cavium Networks", [3][0x4d - 1] = "PLX Technology", [3][0x4e - 1] = "Massana Design", [3][0x4f - 1] = "Intrinsity", [3][0x50 - 1] = "Valence Semiconductor", [3][0x51 - 1] = "Terawave Communications", [3][0x52 - 1] = "IceFyre Semiconductor", [3][0x53 - 1] = "Primarion", [3][0x54 - 1] = "Picochip Designs Ltd", [3][0x55 - 1] = "Silverback Systems", [3][0x56 - 1] = "Jade Star Technologies", [3][0x57 - 1] = "Pijnenburg Securealink", [3][0x58 - 1] = "takeMS - Ultron AG", [3][0x59 - 1] = "Cambridge Silicon Radio", [3][0x5a - 1] = "Swissbit", [3][0x5b - 1] = "Nazomi Communications", [3][0x5c - 1] = "eWave System", [3][0x5d - 1] = "Rockwell Collins", [3][0x5e - 1] = "Picocel Co Ltd (Paion)", [3][0x5f - 1] = "Alphamosaic Ltd", [3][0x60 - 1] = "Sandburst", [3][0x61 - 1] = "SiCon Video", [3][0x62 - 1] = "NanoAmp Solutions", [3][0x63 - 1] = "Ericsson Technology", [3][0x64 - 1] = "PrairieComm", [3][0x65 - 1] = "Mitac International", [3][0x66 - 1] = "Layer N Networks", [3][0x67 - 1] = "MtekVision (Atsana)", [3][0x68 - 1] = "Allegro Networks", [3][0x69 - 1] = "Marvell Semiconductors", [3][0x6a - 1] = "Netergy Microelectronic", [3][0x6b - 1] = "NVIDIA", [3][0x6c - 1] = "Internet Machines", [3][0x6d - 1] = "Memorysolution GmbH", [3][0x6e - 1] = "Litchfield Communication", [3][0x6f - 1] = "Accton Technology", [3][0x70 - 1] = "Teradiant Networks", [3][0x71 - 1] = "Scaleo Chip", [3][0x72 - 1] = "Cortina Systems", [3][0x73 - 1] = "RAM Components", [3][0x74 - 1] = "Raqia Networks", [3][0x75 - 1] = "ClearSpeed", [3][0x76 - 1] = "Matsushita Battery", [3][0x77 - 1] = "Xelerated", [3][0x78 - 1] = "SimpleTech", [3][0x79 - 1] = "Utron Technology", [3][0x7a - 1] = "Astec International", [3][0x7b - 1] = "AVM gmbH", [3][0x7c - 1] = "Redux Communications", [3][0x7d - 1] = "Dot Hill Systems", [3][0x7e - 1] = "TeraChip", [4][0x01 - 1] = "T-RAM Incorporated", [4][0x02 - 1] = "Innovics Wireless", [4][0x03 - 1] = "Teknovus", [4][0x04 - 1] = "KeyEye Communications", [4][0x05 - 1] = "Runcom Technologies", [4][0x06 - 1] = "RedSwitch", [4][0x07 - 1] = "Dotcast", [4][0x08 - 1] = "Silicon Mountain Memory", [4][0x09 - 1] = "Signia Technologies", [4][0x0a - 1] = "Pixim", [4][0x0b - 1] = "Galazar Networks", [4][0x0c - 1] = "White Electronic Designs", [4][0x0d - 1] = "Patriot Scientific", [4][0x0e - 1] = "Neoaxiom Corporation", [4][0x0f - 1] = "3Y Power Technology", [4][0x10 - 1] = "Scaleo Chip", [4][0x11 - 1] = "Potentia Power Systems", [4][0x12 - 1] = "C-guys Incorporated", [4][0x13 - 1] = "Digital Communications Technology Inc", [4][0x14 - 1] = "Silicon-Based Technology", [4][0x15 - 1] = "Fulcrum Microsystems", [4][0x16 - 1] = "Positivo Informatica Ltd", [4][0x17 - 1] = "XIOtech Corporation", [4][0x18 - 1] = "PortalPlayer", [4][0x19 - 1] = "Zhiying Software", [4][0x1a - 1] = "ParkerVision Inc", [4][0x1b - 1] = "Phonex Broadband", [4][0x1c - 1] = "Skyworks Solutions", [4][0x1d - 1] = "Entropic Communications", [4][0x1e - 1] = "I'M Intelligent Memory Ltd", [4][0x1f - 1] = "Zensys A/S", [4][0x20 - 1] = "Legend Silicon Corp", [4][0x21 - 1] = "Sci-worx GmbH", [4][0x22 - 1] = "SMSC (Standard Microsystems)", [4][0x23 - 1] = "Renesas Electronics", [4][0x24 - 1] = "Raza Microelectronics", [4][0x25 - 1] = "Phyworks", [4][0x26 - 1] = "MediaTek", [4][0x27 - 1] = "Non-cents Productions", [4][0x28 - 1] = "US Modular", [4][0x29 - 1] = "Wintegra Ltd", [4][0x2a - 1] = "Mathstar", [4][0x2b - 1] = "StarCore", [4][0x2c - 1] = "Oplus Technologies", [4][0x2d - 1] = "Mindspeed", [4][0x2e - 1] = "Just Young Computer", [4][0x2f - 1] = "Radia Communications", [4][0x30 - 1] = "OCZ", [4][0x31 - 1] = "Emuzed", [4][0x32 - 1] = "LOGIC Devices", [4][0x33 - 1] = "Inphi Corporation", [4][0x34 - 1] = "Quake Technologies", [4][0x35 - 1] = "Vixel", [4][0x36 - 1] = "SolusTek", [4][0x37 - 1] = "Kongsberg Maritime", [4][0x38 - 1] = "Faraday Technology", [4][0x39 - 1] = "Altium Ltd", [4][0x3a - 1] = "Insyte", [4][0x3b - 1] = "ARM Ltd", [4][0x3c - 1] = "DigiVision", [4][0x3d - 1] = "Vativ Technologies", [4][0x3e - 1] = "Endicott Interconnect Technologies", [4][0x3f - 1] = "Pericom", [4][0x40 - 1] = "Bandspeed", [4][0x41 - 1] = "LeWiz Communications", [4][0x42 - 1] = "CPU Technology", [4][0x43 - 1] = "Ramaxel Technology", [4][0x44 - 1] = "DSP Group", [4][0x45 - 1] = "Axis Communications", [4][0x46 - 1] = "Legacy Electronics", [4][0x47 - 1] = "Chrontel", [4][0x48 - 1] = "Powerchip Semiconductor", [4][0x49 - 1] = "MobilEye Technologies", [4][0x4a - 1] = "Excel Semiconductor", [4][0x4b - 1] = "A-DATA Technology", [4][0x4c - 1] = "VirtualDigm", [4][0x4d - 1] = "G Skill Intl", [4][0x4e - 1] = "Quanta Computer", [4][0x4f - 1] = "Yield Microelectronics", [4][0x50 - 1] = "Afa Technologies", [4][0x51 - 1] = "KINGBOX Technology Co Ltd", [4][0x52 - 1] = "Ceva", [4][0x53 - 1] = "iStor Networks", [4][0x54 - 1] = "Advance Modules", [4][0x55 - 1] = "Microsoft", [4][0x56 - 1] = "Open-Silicon", [4][0x57 - 1] = "Goal Semiconductor", [4][0x58 - 1] = "ARC International", [4][0x59 - 1] = "Simmtec", [4][0x5a - 1] = "Metanoia", [4][0x5b - 1] = "Key Stream", [4][0x5c - 1] = "Lowrance Electronics", [4][0x5d - 1] = "Adimos", [4][0x5e - 1] = "SiGe Semiconductor", [4][0x5f - 1] = "Fodus Communications", [4][0x60 - 1] = "Credence Systems Corp", [4][0x61 - 1] = "Genesis Microchip Inc", [4][0x62 - 1] = "Vihana Inc", [4][0x63 - 1] = "WIS Technologies", [4][0x64 - 1] = "GateChange Technologies", [4][0x65 - 1] = "High Density Devices AS", [4][0x66 - 1] = "Synopsys", [4][0x67 - 1] = "Gigaram", [4][0x68 - 1] = "Enigma Semiconductor Inc", [4][0x69 - 1] = "Century Micro Inc", [4][0x6a - 1] = "Icera Semiconductor", [4][0x6b - 1] = "Mediaworks Integrated Systems", [4][0x6c - 1] = "O'Neil Product Development", [4][0x6d - 1] = "Supreme Top Technology Ltd", [4][0x6e - 1] = "MicroDisplay Corporation", [4][0x6f - 1] = "Team Group Inc", [4][0x70 - 1] = "Sinett Corporation", [4][0x71 - 1] = "Toshiba Corporation", [4][0x72 - 1] = "Tensilica", [4][0x73 - 1] = "SiRF Technology", [4][0x74 - 1] = "Bacoc Inc", [4][0x75 - 1] = "SMaL Camera Technologies", [4][0x76 - 1] = "Thomson SC", [4][0x77 - 1] = "Airgo Networks", [4][0x78 - 1] = "Wisair Ltd", [4][0x79 - 1] = "SigmaTel", [4][0x7a - 1] = "Arkados", [4][0x7b - 1] = "Compete IT gmbH Co KG", [4][0x7c - 1] = "Eudar Technology Inc", [4][0x7d - 1] = "Focus Enhancements", [4][0x7e - 1] = "Xyratex", [5][0x01 - 1] = "Specular Networks", [5][0x02 - 1] = "Patriot Memory (PDP Systems)", [5][0x03 - 1] = "U-Chip Technology Corp", [5][0x04 - 1] = "Silicon Optix", [5][0x05 - 1] = "Greenfield Networks", [5][0x06 - 1] = "CompuRAM GmbH", [5][0x07 - 1] = "Stargen Inc", [5][0x08 - 1] = "NetCell Corporation", [5][0x09 - 1] = "Excalibrus Technologies Ltd", [5][0x0a - 1] = "SCM Microsystems", [5][0x0b - 1] = "Xsigo Systems Inc", [5][0x0c - 1] = "CHIPS & Systems Inc", [5][0x0d - 1] = "Tier 1 Multichip Solutions", [5][0x0e - 1] = "CWRL Labs", [5][0x0f - 1] = "Teradici", [5][0x10 - 1] = "Gigaram Inc", [5][0x11 - 1] = "g2 Microsystems", [5][0x12 - 1] = "PowerFlash Semiconductor", [5][0x13 - 1] = "P.A. Semi Inc", [5][0x14 - 1] = "NovaTech Solutions S.A.", [5][0x15 - 1] = "c2 Microsystems Inc", [5][0x16 - 1] = "Level5 Networks", [5][0x17 - 1] = "COS Memory AG", [5][0x18 - 1] = "Innovasic Semiconductor", [5][0x19 - 1] = "02IC Co Ltd", [5][0x1a - 1] = "Tabula Inc", [5][0x1b - 1] = "Crucial Technology", [5][0x1c - 1] = "Chelsio Communications", [5][0x1d - 1] = "Solarflare Communications", [5][0x1e - 1] = "Xambala Inc", [5][0x1f - 1] = "EADS Astrium", [5][0x20 - 1] = "Terra Semiconductor Inc", [5][0x21 - 1] = "Imaging Works Inc", [5][0x22 - 1] = "Astute Networks Inc", [5][0x23 - 1] = "Tzero", [5][0x24 - 1] = "Emulex", [5][0x25 - 1] = "Power-One", [5][0x26 - 1] = "Pulse~LINK Inc", [5][0x27 - 1] = "Hon Hai Precision Industry", [5][0x28 - 1] = "White Rock Networks Inc", [5][0x29 - 1] = "Telegent Systems USA Inc", [5][0x2a - 1] = "Atrua Technologies Inc", [5][0x2b - 1] = "Acbel Polytech Inc", [5][0x2c - 1] = "eRide Inc", [5][0x2d - 1] = "ULi Electronics Inc", [5][0x2e - 1] = "Magnum Semiconductor Inc", [5][0x2f - 1] = "neoOne Technology Inc", [5][0x30 - 1] = "Connex Technology Inc", [5][0x31 - 1] = "Stream Processors Inc", [5][0x32 - 1] = "Focus Enhancements", [5][0x33 - 1] = "Telecis Wireless Inc", [5][0x34 - 1] = "uNav Microelectronics", [5][0x35 - 1] = "Tarari Inc", [5][0x36 - 1] = "Ambric Inc", [5][0x37 - 1] = "Newport Media Inc", [5][0x38 - 1] = "VMTS", [5][0x39 - 1] = "Enuclia Semiconductor Inc", [5][0x3a - 1] = "Virtium Technology Inc", [5][0x3b - 1] = "Solid State System Co Ltd", [5][0x3c - 1] = "Kian Tech LLC", [5][0x3d - 1] = "Artimi", [5][0x3e - 1] = "Power Quotient International", [5][0x3f - 1] = "Avago Technologies", [5][0x40 - 1] = "ADTechnology", [5][0x41 - 1] = "Sigma Designs", [5][0x42 - 1] = "SiCortex Inc", [5][0x43 - 1] = "Ventura Technology Group", [5][0x44 - 1] = "eASIC", [5][0x45 - 1] = "M.H.S. SAS", [5][0x46 - 1] = "Micro Star International", [5][0x47 - 1] = "Rapport Inc", [5][0x48 - 1] = "Makway International", [5][0x49 - 1] = "Broad Reach Engineering Co", [5][0x4a - 1] = "Semiconductor Mfg Intl Corp", [5][0x4b - 1] = "SiConnect", [5][0x4c - 1] = "FCI USA Inc", [5][0x4d - 1] = "Validity Sensors", [5][0x4e - 1] = "Coney Technology Co Ltd", [5][0x4f - 1] = "Spans Logic", [5][0x50 - 1] = "Neterion Inc", [5][0x51 - 1] = "Qimonda", [5][0x52 - 1] = "New Japan Radio Co Ltd", [5][0x53 - 1] = "Velogix", [5][0x54 - 1] = "Montalvo Systems", [5][0x55 - 1] = "iVivity Inc", [5][0x56 - 1] = "Walton Chaintech", [5][0x57 - 1] = "AENEON", [5][0x58 - 1] = "Lorom Industrial Co Ltd", [5][0x59 - 1] = "Radiospire Networks", [5][0x5a - 1] = "Sensio Technologies Inc", [5][0x5b - 1] = "Nethra Imaging", [5][0x5c - 1] = "Hexon Technology Pte Ltd", [5][0x5d - 1] = "CompuStocx (CSX)", [5][0x5e - 1] = "Methode Electronics Inc", [5][0x5f - 1] = "Connect One Ltd", [5][0x60 - 1] = "Opulan Technologies", [5][0x61 - 1] = "Septentrio NV", [5][0x62 - 1] = "Goldenmars Technology Inc", [5][0x63 - 1] = "Kreton Corporation", [5][0x64 - 1] = "Cochlear Ltd", [5][0x65 - 1] = "Altair Semiconductor", [5][0x66 - 1] = "NetEffect Inc", [5][0x67 - 1] = "Spansion Inc", [5][0x68 - 1] = "Taiwan Semiconductor Mfg", [5][0x69 - 1] = "Emphany Systems Inc", [5][0x6a - 1] = "ApaceWave Technologies", [5][0x6b - 1] = "Mobilygen Corporation", [5][0x6c - 1] = "Tego", [5][0x6d - 1] = "Cswitch Corporation", [5][0x6e - 1] = "Haier (Beijing) IC Design Co", [5][0x6f - 1] = "MetaRAM", [5][0x70 - 1] = "Axel Electronics Co Ltd", [5][0x71 - 1] = "Tilera Corporation", [5][0x72 - 1] = "Aquantia", [5][0x73 - 1] = "Vivace Semiconductor", [5][0x74 - 1] = "Redpine Signals", [5][0x75 - 1] = "Octalica", [5][0x76 - 1] = "InterDigital Communications", [5][0x77 - 1] = "Avant Technology", [5][0x78 - 1] = "Asrock Inc", [5][0x79 - 1] = "Availink", [5][0x7a - 1] = "Quartics Inc", [5][0x7b - 1] = "Element CXI", [5][0x7c - 1] = "Innovaciones Microelectronicas", [5][0x7d - 1] = "VeriSilicon Microelectronics", [5][0x7e - 1] = "W5 Networks", [6][0x01 - 1] = "MOVEKING", [6][0x02 - 1] = "Mavrix Technology Inc", [6][0x03 - 1] = "CellGuide Ltd", [6][0x04 - 1] = "Faraday Technology", [6][0x05 - 1] = "Diablo Technologies Inc", [6][0x06 - 1] = "Jennic", [6][0x07 - 1] = "Octasic", [6][0x08 - 1] = "Molex Incorporated", [6][0x09 - 1] = "3Leaf Networks", [6][0x0a - 1] = "Bright Micron Technology", [6][0x0b - 1] = "Netxen", [6][0x0c - 1] = "NextWave Broadband Inc", [6][0x0d - 1] = "DisplayLink", [6][0x0e - 1] = "ZMOS Technology", [6][0x0f - 1] = "Tec-Hill", [6][0x10 - 1] = "Multigig Inc", [6][0x11 - 1] = "Amimon", [6][0x12 - 1] = "Euphonic Technologies Inc", [6][0x13 - 1] = "BRN Phoenix", [6][0x14 - 1] = "InSilica", [6][0x15 - 1] = "Ember Corporation", [6][0x16 - 1] = "Avexir Technologies Corporation", [6][0x17 - 1] = "Echelon Corporation", [6][0x18 - 1] = "Edgewater Computer Systems", [6][0x19 - 1] = "XMOS Semiconductor Ltd", [6][0x1a - 1] = "GENUSION Inc", [6][0x1b - 1] = "Memory Corp NV", [6][0x1c - 1] = "SiliconBlue Technologies", [6][0x1d - 1] = "Rambus Inc", [6][0x1e - 1] = "Andes Technology Corporation", [6][0x1f - 1] = "Coronis Systems", [6][0x20 - 1] = "Achronix Semiconductor", [6][0x21 - 1] = "Siano Mobile Silicon Ltd", [6][0x22 - 1] = "Semtech Corporation", [6][0x23 - 1] = "Pixelworks Inc", [6][0x24 - 1] = "Gaisler Research AB", [6][0x25 - 1] = "Teranetics", [6][0x26 - 1] = "Toppan Printing Co Ltd", [6][0x27 - 1] = "Kingxcon", [6][0x28 - 1] = "Silicon Integrated Systems", [6][0x29 - 1] = "I-O Data Device Inc", [6][0x2a - 1] = "NDS Americas Inc", [6][0x2b - 1] = "Solomon Systech Limited", [6][0x2c - 1] = "On Demand Microelectronics", [6][0x2d - 1] = "Amicus Wireless Inc", [6][0x2e - 1] = "SMARDTV SNC", [6][0x2f - 1] = "Comsys Communication Ltd", [6][0x30 - 1] = "Movidia Ltd", [6][0x31 - 1] = "Javad GNSS Inc", [6][0x32 - 1] = "Montage Technology Group", [6][0x33 - 1] = "Trident Microsystems", [6][0x34 - 1] = "Super Talent", [6][0x35 - 1] = "Optichron Inc", [6][0x36 - 1] = "Future Waves UK Ltd", [6][0x37 - 1] = "SiBEAM Inc", [6][0x38 - 1] = "InicoreInc", [6][0x39 - 1] = "Virident Systems", [6][0x3a - 1] = "M2000 Inc", [6][0x3b - 1] = "ZeroG Wireless Inc", [6][0x3c - 1] = "Gingle Technology Co Ltd", [6][0x3d - 1] = "Space Micro Inc", [6][0x3e - 1] = "Wilocity", [6][0x3f - 1] = "Novafora Inc", [6][0x40 - 1] = "iKoa Corporation", [6][0x41 - 1] = "ASint Technology", [6][0x42 - 1] = "Ramtron", [6][0x43 - 1] = "Plato Networks Inc", [6][0x44 - 1] = "IPtronics AS", [6][0x45 - 1] = "Infinite-Memories", [6][0x46 - 1] = "Parade Technologies Inc", [6][0x47 - 1] = "Dune Networks", [6][0x48 - 1] = "GigaDevice Semiconductor", [6][0x49 - 1] = "Modu Ltd", [6][0x4a - 1] = "CEITEC", [6][0x4b - 1] = "Northrop Grumman", [6][0x4c - 1] = "XRONET Corporation", [6][0x4d - 1] = "Sicon Semiconductor AB", [6][0x4e - 1] = "Atla Electronics Co Ltd", [6][0x4f - 1] = "TOPRAM Technology", [6][0x50 - 1] = "Silego Technology Inc", [6][0x51 - 1] = "Kinglife", [6][0x52 - 1] = "Ability Industries Ltd", [6][0x53 - 1] = "Silicon Power Computer & Communications", [6][0x54 - 1] = "Augusta Technology Inc", [6][0x55 - 1] = "Nantronics Semiconductors", [6][0x56 - 1] = "Hilscher Gesellschaft", [6][0x57 - 1] = "Quixant Ltd", [6][0x58 - 1] = "Percello Ltd", [6][0x59 - 1] = "NextIO Inc", [6][0x5a - 1] = "Scanimetrics Inc", [6][0x5b - 1] = "FS-Semi Company Ltd", [6][0x5c - 1] = "Infinera Corporation", [6][0x5d - 1] = "SandForce Inc", [6][0x5e - 1] = "Lexar Media", [6][0x5f - 1] = "Teradyne Inc", [6][0x60 - 1] = "Memory Exchange Corp", [6][0x61 - 1] = "Suzhou Smartek Electronics", [6][0x62 - 1] = "Avantium Corporation", [6][0x63 - 1] = "ATP Electronics Inc", [6][0x64 - 1] = "Valens Semiconductor Ltd", [6][0x65 - 1] = "Agate Logic Inc", [6][0x66 - 1] = "Netronome", [6][0x67 - 1] = "Zenverge Inc", [6][0x68 - 1] = "N-trig Ltd", [6][0x69 - 1] = "SanMax Technologies Inc", [6][0x6a - 1] = "Contour Semiconductor Inc", [6][0x6b - 1] = "TwinMOS", [6][0x6c - 1] = "Silicon Systems Inc", [6][0x6d - 1] = "V-Color Technology Inc", [6][0x6e - 1] = "Certicom Corporation", [6][0x6f - 1] = "JSC ICC Milandr", [6][0x70 - 1] = "PhotoFast Global Inc", [6][0x71 - 1] = "InnoDisk Corporation", [6][0x72 - 1] = "Muscle Power", [6][0x73 - 1] = "Energy Micro", [6][0x74 - 1] = "Innofidei", [6][0x75 - 1] = "CopperGate Communications", [6][0x76 - 1] = "Holtek Semiconductor Inc", [6][0x77 - 1] = "Myson Century Inc", [6][0x78 - 1] = "FIDELIX", [6][0x79 - 1] = "Red Digital Cinema", [6][0x7a - 1] = "Densbits Technology", [6][0x7b - 1] = "Zempro", [6][0x7c - 1] = "MoSys", [6][0x7d - 1] = "Provigent", [6][0x7e - 1] = "Triad Semiconductor Inc", [7][0x01 - 1] = "Siklu Communication Ltd", [7][0x02 - 1] = "A Force Manufacturing Ltd", [7][0x03 - 1] = "Strontium", [7][0x04 - 1] = "ALi Corp (Abilis Systems)", [7][0x05 - 1] = "Siglead Inc", [7][0x06 - 1] = "Ubicom Inc", [7][0x07 - 1] = "Unifosa Corporation", [7][0x08 - 1] = "Stretch Inc", [7][0x09 - 1] = "Lantiq Deutschland GmbH", [7][0x0a - 1] = "Visipro.", [7][0x0b - 1] = "EKMemory", [7][0x0c - 1] = "Microelectronics Institute ZTE", [7][0x0d - 1] = "u-blox AG", [7][0x0e - 1] = "Carry Technology Co Ltd", [7][0x0f - 1] = "Nokia", [7][0x10 - 1] = "King Tiger Technology", [7][0x11 - 1] = "Sierra Wireless", [7][0x12 - 1] = "HT Micron", [7][0x13 - 1] = "Albatron Technology Co Ltd", [7][0x14 - 1] = "Leica Geosystems AG", [7][0x15 - 1] = "BroadLight", [7][0x16 - 1] = "AEXEA", [7][0x17 - 1] = "ClariPhy Communications Inc", [7][0x18 - 1] = "Green Plug", [7][0x19 - 1] = "Design Art Networks", [7][0x1a - 1] = "Mach Xtreme Technology Ltd", [7][0x1b - 1] = "ATO Solutions Co Ltd", [7][0x1c - 1] = "Ramsta", [7][0x1d - 1] = "Greenliant Systems Ltd", [7][0x1e - 1] = "Teikon", [7][0x1f - 1] = "Antec Hadron", [7][0x20 - 1] = "NavCom Technology Inc", [7][0x21 - 1] = "Shanghai Fudan Microelectronics", [7][0x22 - 1] = "Calxeda Inc", [7][0x23 - 1] = "JSC EDC Electronics", [7][0x24 - 1] = "Kandit Technology Co Ltd", [7][0x25 - 1] = "Ramos Technology", [7][0x26 - 1] = "Goldenmars Technology", [7][0x27 - 1] = "XeL Technology Inc", [7][0x28 - 1] = "Newzone Corporation", [7][0x29 - 1] = "ShenZhen MercyPower Tech", [7][0x2a - 1] = "Nanjing Yihuo Technology", [7][0x2b - 1] = "Nethra Imaging Inc", [7][0x2c - 1] = "SiTel Semiconductor BV", [7][0x2d - 1] = "SolidGear Corporation", [7][0x2e - 1] = "Topower Computer Ind Co Ltd", [7][0x2f - 1] = "Wilocity", [7][0x30 - 1] = "Profichip GmbH", [7][0x31 - 1] = "Gerad Technologies", [7][0x32 - 1] = "Ritek Corporation", [7][0x33 - 1] = "Gomos Technology Limited", [7][0x34 - 1] = "Memoright Corporation", [7][0x35 - 1] = "D-Broad Inc", [7][0x36 - 1] = "HiSilicon Technologies", [7][0x37 - 1] = "Syndiant Inc.", [7][0x38 - 1] = "Enverv Inc", [7][0x39 - 1] = "Cognex", [7][0x3a - 1] = "Xinnova Technology Inc", [7][0x3b - 1] = "Ultron AG", [7][0x3c - 1] = "Concord Idea Corporation", [7][0x3d - 1] = "AIM Corporation", [7][0x3e - 1] = "Lifetime Memory Products", [7][0x3f - 1] = "Ramsway", [7][0x40 - 1] = "Recore Systems B.V.", [7][0x41 - 1] = "Haotian Jinshibo Science Tech", [7][0x42 - 1] = "Being Advanced Memory", [7][0x43 - 1] = "Adesto Technologies", [7][0x44 - 1] = "Giantec Semiconductor Inc", [7][0x45 - 1] = "HMD Electronics AG", [7][0x46 - 1] = "Gloway International (HK)", [7][0x47 - 1] = "Kingcore", [7][0x48 - 1] = "Anucell Technology Holding", [7][0x49 - 1] = "Accord Software & Systems Pvt. Ltd", [7][0x4a - 1] = "Active-Semi Inc", [7][0x4b - 1] = "Denso Corporation", [7][0x4c - 1] = "TLSI Inc", [7][0x4d - 1] = "Qidan", [7][0x4e - 1] = "Mustang", [7][0x4f - 1] = "Orca Systems", [7][0x50 - 1] = "Passif Semiconductor", [7][0x51 - 1] = "GigaDevice Semiconductor (Beijing)", [7][0x52 - 1] = "Memphis Electronic", [7][0x53 - 1] = "Beckhoff Automation GmbH", [7][0x54 - 1] = "Harmony Semiconductor Corp", [7][0x55 - 1] = "Air Computers SRL", [7][0x56 - 1] = "TMT Memory", [7][0x57 - 1] = "Eorex Corporation", [7][0x58 - 1] = "Xingtera", [7][0x59 - 1] = "Netsol", [7][0x5a - 1] = "Bestdon Technology Co Ltd", [7][0x5b - 1] = "Baysand Inc", [7][0x5c - 1] = "Uroad Technology Co Ltd", [7][0x5d - 1] = "Wilk Elektronik S.A.", [7][0x5e - 1] = "AAI", [7][0x5f - 1] = "Harman", [7][0x60 - 1] = "Berg Microelectronics Inc", [7][0x61 - 1] = "ASSIA Inc", [7][0x62 - 1] = "Visiontek Products LLC", [7][0x63 - 1] = "OCMEMORY", [7][0x64 - 1] = "Welink Solution Inc", [7][0x65 - 1] = "Shark Gaming", [7][0x66 - 1] = "Avalanche Technology", [7][0x67 - 1] = "R&D Center ELVEES OJSC", [7][0x68 - 1] = "KingboMars Technology Co Ltd", [7][0x69 - 1] = "High Bridge Solutions Industria Eletronica", [7][0x6a - 1] = "Transcend Technology Co Ltd", [7][0x6b - 1] = "Everspin Technologies", [7][0x6c - 1] = "Hon-Hai Precision", [7][0x6d - 1] = "Smart Storage Systems", [7][0x6e - 1] = "Toumaz Group", [7][0x6f - 1] = "Zentel Electronics Corporation", [7][0x70 - 1] = "Panram International Corporation", [7][0x71 - 1] = "Silicon Space Technology", [7][0x72 - 1] = "LITE-ON IT Corporation", [7][0x73 - 1] = "Inuitive", [7][0x74 - 1] = "HMicro", [7][0x75 - 1] = "BittWare Inc", [7][0x76 - 1] = "GLOBALFOUNDRIES", [7][0x77 - 1] = "ACPI Digital Co Ltd", [7][0x78 - 1] = "Annapurna Labs", [7][0x79 - 1] = "AcSiP Technology Corporation", [7][0x7a - 1] = "Idea! Electronic Systems", [7][0x7b - 1] = "Gowe Technology Co Ltd", [7][0x7c - 1] = "Hermes Testing Solutions Inc", [7][0x7d - 1] = "Positivo BGH", [7][0x7e - 1] = "Intelligence Silicon Technology", [8][0x01 - 1] = "3D PLUS", [8][0x02 - 1] = "Diehl Aerospace", [8][0x03 - 1] = "Fairchild", [8][0x04 - 1] = "Mercury Systems", [8][0x05 - 1] = "Sonics Inc", [8][0x06 - 1] = "Emerson Automation Solutions", [8][0x07 - 1] = "Shenzhen Jinge Information Co Ltd", [8][0x08 - 1] = "SCWW", [8][0x09 - 1] = "Silicon Motion Inc", [8][0x0a - 1] = "Anurag", [8][0x0b - 1] = "King Kong", [8][0x0c - 1] = "FROM30 Co Ltd", [8][0x0d - 1] = "Gowin Semiconductor Corp", [8][0x0e - 1] = "Fremont Micro Devices Ltd", [8][0x0f - 1] = "Ericsson Modems", [8][0x10 - 1] = "Exelis", [8][0x11 - 1] = "Satixfy Ltd", [8][0x12 - 1] = "Galaxy Microsystems Ltd", [8][0x13 - 1] = "Gloway International Co Ltd", [8][0x14 - 1] = "Lab", [8][0x15 - 1] = "Smart Energy Instruments", [8][0x16 - 1] = "Approved Memory Corporation", [8][0x17 - 1] = "Axell Corporation", [8][0x18 - 1] = "Essencore Limited", [8][0x19 - 1] = "Phytium", [8][0x1a - 1] = "Xi'an UniIC Semiconductors Co Ltd", [8][0x1b - 1] = "Ambiq Micro", [8][0x1c - 1] = "eveRAM Technology Inc", [8][0x1d - 1] = "Infomax", [8][0x1e - 1] = "Butterfly Network Inc", [8][0x1f - 1] = "Shenzhen City Gcai Electronics", [8][0x20 - 1] = "Stack Devices Corporation", [8][0x21 - 1] = "ADK Media Group", [8][0x22 - 1] = "TSP Global Co Ltd", [8][0x23 - 1] = "HighX", [8][0x24 - 1] = "Shenzhen Elicks Technology", [8][0x25 - 1] = "XinKai/Silicon Kaiser", [8][0x26 - 1] = "Google Inc", [8][0x27 - 1] = "Dasima International Development", [8][0x28 - 1] = "Leahkinn Technology Limited", [8][0x29 - 1] = "HIMA Paul Hildebrandt GmbH Co KG", [8][0x2a - 1] = "Keysight Technologies", [8][0x2b - 1] = "Techcomp International (Fastable)", [8][0x2c - 1] = "Ancore Technology Corporation", [8][0x2d - 1] = "Nuvoton", [8][0x2e - 1] = "Korea Uhbele International Group Ltd", [8][0x2f - 1] = "Ikegami Tsushinki Co Ltd", [8][0x30 - 1] = "RelChip Inc", [8][0x31 - 1] = "Baikal Electronics", [8][0x32 - 1] = "Nemostech Inc", [8][0x33 - 1] = "Memorysolution GmbH", [8][0x34 - 1] = "Silicon Integrated Systems Corporation", [8][0x35 - 1] = "Xiede", [8][0x36 - 1] = "BRC", [8][0x37 - 1] = "Flash Chi", [8][0x38 - 1] = "Jone", [8][0x39 - 1] = "GCT Semiconductor Inc", [8][0x3a - 1] = "Hong Kong Zetta Device Technology", [8][0x3b - 1] = "Unimemory Technology(s) Pte Ltd", [8][0x3c - 1] = "Cuso", [8][0x3d - 1] = "Kuso", [8][0x3e - 1] = "Uniquify Inc", [8][0x3f - 1] = "Skymedi Corporation", [8][0x40 - 1] = "Core Chance Co Ltd", [8][0x41 - 1] = "Tekism Co Ltd", [8][0x42 - 1] = "Seagate Technology PLC", [8][0x43 - 1] = "Hong Kong Gaia Group Co Limited", [8][0x44 - 1] = "Gigacom Semiconductor LLC", [8][0x45 - 1] = "V2 Technologies", [8][0x46 - 1] = "TLi", [8][0x47 - 1] = "Neotion", [8][0x48 - 1] = "Lenovo", [8][0x49 - 1] = "Shenzhen Zhongteng Electronic Corp Ltd", [8][0x4a - 1] = "Compound Photonics", [8][0x4b - 1] = "in2H2 inc", [8][0x4c - 1] = "Shenzhen Pango Microsystems Co Ltd", [8][0x4d - 1] = "Vasekey", [8][0x4e - 1] = "Cal-Comp Industria de Semicondutores", [8][0x4f - 1] = "Eyenix Co Ltd", [8][0x50 - 1] = "Heoriady", [8][0x51 - 1] = "Accelerated Memory Production Inc", [8][0x52 - 1] = "INVECAS Inc", [8][0x53 - 1] = "AP Memory", [8][0x54 - 1] = "Douqi Technology", [8][0x55 - 1] = "Etron Technology Inc", [8][0x56 - 1] = "Indie Semiconductor", [8][0x57 - 1] = "Socionext Inc", [8][0x58 - 1] = "HGST", [8][0x59 - 1] = "EVGA", [8][0x5a - 1] = "Audience Inc", [8][0x5b - 1] = "EpicGear", [8][0x5c - 1] = "Vitesse Enterprise Co", [8][0x5d - 1] = "Foxtronn International Corporation", [8][0x5e - 1] = "Bretelon Inc", [8][0x5f - 1] = "Graphcore", [8][0x60 - 1] = "Eoplex Inc", [8][0x61 - 1] = "MaxLinear Inc", [8][0x62 - 1] = "ETA Devices", [8][0x63 - 1] = "LOKI", [8][0x64 - 1] = "IMS Electronics Co Ltd", [8][0x65 - 1] = "Dosilicon Co Ltd", [8][0x66 - 1] = "Dolphin Integration", [8][0x67 - 1] = "Shenzhen Mic Electronics Technolog", [8][0x68 - 1] = "Boya Microelectronics Inc", [8][0x69 - 1] = "Geniachip (Roche)", [8][0x6a - 1] = "Axign", [8][0x6b - 1] = "Kingred Electronic Technology Ltd", [8][0x6c - 1] = "Chao Yue Zhuo Computer Business Dept.", [8][0x6d - 1] = "Guangzhou Si Nuo Electronic Technology.", [8][0x6e - 1] = "Crocus Technology Inc", [8][0x6f - 1] = "Creative Chips GmbH", [8][0x70 - 1] = "GE Aviation Systems LLC.", [8][0x71 - 1] = "Asgard", [8][0x72 - 1] = "Good Wealth Technology Ltd", [8][0x73 - 1] = "TriCor Technologies", [8][0x74 - 1] = "Nova-Systems GmbH", [8][0x75 - 1] = "JUHOR", [8][0x76 - 1] = "Zhuhai Douke Commerce Co Ltd", [8][0x77 - 1] = "DSL Memory", [8][0x78 - 1] = "Anvo-Systems Dresden GmbH", [8][0x79 - 1] = "Realtek", [8][0x7a - 1] = "AltoBeam", [8][0x7b - 1] = "Wave Computing", [8][0x7c - 1] = "Beijing TrustNet Technology Co Ltd", [8][0x7d - 1] = "Innovium Inc", [8][0x7e - 1] = "Starsway Technology Limited", [9][0x01 - 1] = "Weltronics Co LTD", [9][0x02 - 1] = "VMware Inc", [9][0x03 - 1] = "Hewlett Packard Enterprise", [9][0x04 - 1] = "INTENSO", [9][0x05 - 1] = "Puya Semiconductor", [9][0x06 - 1] = "MEMORFI", [9][0x07 - 1] = "MSC Technologies GmbH", [9][0x08 - 1] = "Txrui", [9][0x09 - 1] = "SiFive Inc", [9][0x0a - 1] = "Spreadtrum Communications", [9][0x0b - 1] = "XTX Technology Limited", [9][0x0c - 1] = "UMAX Technology", [9][0x0d - 1] = "Shenzhen Yong Sheng Technology", [9][0x0e - 1] = "SNOAMOO (Shenzhen Kai Zhuo Yue)", [9][0x0f - 1] = "Daten Tecnologia LTDA", [9][0x10 - 1] = "Shenzhen XinRuiYan Electronics", [9][0x11 - 1] = "Eta Compute", [9][0x12 - 1] = "Energous", [9][0x13 - 1] = "Raspberry Pi Trading Ltd", [9][0x14 - 1] = "Shenzhen Chixingzhe Tech Co Ltd", [9][0x15 - 1] = "Silicon Mobility", [9][0x16 - 1] = "IQ-Analog Corporation", [9][0x17 - 1] = "Uhnder Inc", [9][0x18 - 1] = "Impinj", [9][0x19 - 1] = "DEPO Computers", [9][0x1a - 1] = "Nespeed Sysems", [9][0x1b - 1] = "Yangtze Memory Technologies Co Ltd", [9][0x1c - 1] = "MemxPro Inc", [9][0x1d - 1] = "Tammuz Co Ltd", [9][0x1e - 1] = "Allwinner Technology", [9][0x1f - 1] = "Shenzhen City Futian District Qing Xuan Tong Computer Trading Firm", [9][0x20 - 1] = "XMC", [9][0x21 - 1] = "Teclast", [9][0x22 - 1] = "Maxsun", [9][0x23 - 1] = "Haiguang Integrated Circuit Design", [9][0x24 - 1] = "RamCENTER Technology", [9][0x25 - 1] = "Phison Electronics Corporation", [9][0x26 - 1] = "Guizhou Huaxintong Semi-Conductor", [9][0x27 - 1] = "Network Intelligence", [9][0x28 - 1] = "Continental Technology (Holdings)", [9][0x29 - 1] = "Guangzhou Huayan Suning Electronic", [9][0x2a - 1] = "Guangzhou Zhouji Electronic Co Ltd", [9][0x2b - 1] = "Shenzhen Giant Hui Kang Tech Co Ltd", [9][0x2c - 1] = "Shenzhen Yilong Innovative Co Ltd", [9][0x2d - 1] = "Neo Forza", [9][0x2e - 1] = "Lyontek Inc", [9][0x2f - 1] = "Shanghai Kuxin Microelectronics Ltd", [9][0x30 - 1] = "Shenzhen Larix Technology Co Ltd", [9][0x31 - 1] = "Qbit Semiconductor Ltd", [9][0x32 - 1] = "Insignis Technology Corporation", [9][0x33 - 1] = "Lanson Memory Co Ltd", [9][0x34 - 1] = "Shenzhen Superway Electronics Co Ltd", [9][0x35 - 1] = "Canaan-Creative Co Ltd", [9][0x36 - 1] = "Black Diamond Memory", [9][0x37 - 1] = "Shenzhen City Parker Baking Electronics", [9][0x38 - 1] = "Shenzhen Baihong Technology Co Ltd", [9][0x39 - 1] = "GEO Semiconductors", [9][0x3a - 1] = "OCPC", [9][0x3b - 1] = "Artery Technology Co Ltd", [9][0x3c - 1] = "Jinyu", [9][0x3d - 1] = "ShenzhenYing Chi Technology Development", [9][0x3e - 1] = "Shenzhen Pengcheng Xin Technology", [9][0x3f - 1] = "Pegasus Semiconductor (Shanghai) Co", [9][0x40 - 1] = "Mythic Inc", [9][0x41 - 1] = "Elmos Semiconductor AG", [9][0x42 - 1] = "Kllisre", [9][0x43 - 1] = "Shenzhen Winconway Technology", [9][0x44 - 1] = "Shenzhen Xingmem Technology Corp", [9][0x45 - 1] = "Gold Key Technology Co Ltd", [9][0x46 - 1] = "Habana Labs Ltd", [9][0x47 - 1] = "Hoodisk Electronics Co Ltd", [9][0x48 - 1] = "SemsoTai (SZ) Technology Co Ltd", [9][0x49 - 1] = "OM Nanotech Pvt. Ltd", [9][0x4a - 1] = "Shenzhen Zhifeng Weiye Technology", [9][0x4b - 1] = "Xinshirui (Shenzhen) Electronics Co", [9][0x4c - 1] = "Guangzhou Zhong Hao Tian Electronic", [9][0x4d - 1] = "Shenzhen Longsys Electronics Co Ltd", [9][0x4e - 1] = "Deciso B.V.", [9][0x4f - 1] = "Puya Semiconductor (Shenzhen)", [9][0x50 - 1] = "Shenzhen Veineda Technology Co Ltd", [9][0x51 - 1] = "Antec Memory", [9][0x52 - 1] = "Cortus SAS", [9][0x53 - 1] = "Dust Leopard", [9][0x54 - 1] = "MyWo AS", [9][0x55 - 1] = "J&A Information Inc", [9][0x56 - 1] = "Shenzhen JIEPEI Technology Co Ltd", [9][0x57 - 1] = "Heidelberg University", [9][0x58 - 1] = "Flexxon PTE Ltd", [9][0x59 - 1] = "Wiliot", [9][0x5a - 1] = "Raysun Electronics International Ltd", [9][0x5b - 1] = "Aquarius Production Company LLC", [9][0x5c - 1] = "MACNICA DHW LTDA", [9][0x5d - 1] = "Intelimem", [9][0x5e - 1] = "Zbit Semiconductor Inc", [9][0x5f - 1] = "Shenzhen Technology Co Ltd", [9][0x60 - 1] = "Signalchip", [9][0x61 - 1] = "Shenzen Recadata Storage Technology", [9][0x62 - 1] = "Hyundai Technology", [9][0x63 - 1] = "Shanghai Fudi Investment Development", [9][0x64 - 1] = "Aixi Technology", [9][0x65 - 1] = "Tecon MT", [9][0x66 - 1] = "Onda Electric Co Ltd", [9][0x67 - 1] = "Jinshen", [9][0x68 - 1] = "Kimtigo Semiconductor (HK) Limited", [9][0x69 - 1] = "IIT Madras", [9][0x6a - 1] = "Shenshan (Shenzhen) Electronic", [9][0x6b - 1] = "Hefei Core Storage Electronic Limited", [9][0x6c - 1] = "Colorful Technology Ltd", [9][0x6d - 1] = "Visenta (Xiamen) Technology Co Ltd", [9][0x6e - 1] = "Roa Logic BV", [9][0x6f - 1] = "NSITEXE Inc", [9][0x70 - 1] = "Hong Kong Hyunion Electronics", [9][0x71 - 1] = "ASK Technology Group Limited", [9][0x72 - 1] = "GIGA-BYTE Technology Co Ltd", [9][0x73 - 1] = "Terabyte Co Ltd", [9][0x74 - 1] = "Hyundai Inc", [9][0x75 - 1] = "EXCELERAM", [9][0x76 - 1] = "PsiKick", [9][0x77 - 1] = "Netac Technology Co Ltd", [9][0x78 - 1] = "PCCOOLER", [9][0x79 - 1] = "Jiangsu Huacun Electronic Technology", [9][0x7a - 1] = "Shenzhen Micro Innovation Industry", [9][0x7b - 1] = "Beijing Tongfang Microelectronics Co", [9][0x7c - 1] = "XZN Storage Technology", [9][0x7d - 1] = "ChipCraft Sp. z.o.o.", [9][0x7e - 1] = "ALLFLASH Technology Limited", [10][0x01 - 1] = "Foerd Technology Co Ltd", [10][0x02 - 1] = "KingSpec", [10][0x03 - 1] = "Codasip GmbH", [10][0x04 - 1] = "SL Link Co Ltd", [10][0x05 - 1] = "Shenzhen Kefu Technology Co Limited", [10][0x06 - 1] = "Shenzhen ZST Electronics Technology", [10][0x07 - 1] = "Kyokuto Electronic Inc", [10][0x08 - 1] = "Warrior Technology", [10][0x09 - 1] = "TRINAMIC Motion Control GmbH & Co", [10][0x0a - 1] = "PixelDisplay Inc", [10][0x0b - 1] = "Shenzhen Futian District Bo Yueda Elec", [10][0x0c - 1] = "Richtek Power", [10][0x0d - 1] = "Shenzhen LianTeng Electronics Co Ltd", [10][0x0e - 1] = "AITC Memory", [10][0x0f - 1] = "UNIC Memory Technology Co Ltd", [10][0x10 - 1] = "Shenzhen Huafeng Science Technology", [10][0x11 - 1] = "CXMT", [10][0x12 - 1] = "Guangzhou Xinyi Heng Computer Trading Firm", [10][0x13 - 1] = "SambaNova Systems", [10][0x14 - 1] = "V-GEN", [10][0x15 - 1] = "Jump Trading", [10][0x16 - 1] = "Ampere Computing", [10][0x17 - 1] = "Shenzhen Zhongshi Technology Co Ltd", [10][0x18 - 1] = "Shenzhen Zhongtian Bozhong Technology", [10][0x19 - 1] = "Tri-Tech International", [10][0x1a - 1] = "Silicon Intergrated Systems Corporation", [10][0x1b - 1] = "Shenzhen HongDingChen Information", [10][0x1c - 1] = "Plexton Holdings Limited", [10][0x1d - 1] = "AMS (Jiangsu Advanced Memory Semi)", [10][0x1e - 1] = "Wuhan Jing Tian Interconnected Tech Co", [10][0x1f - 1] = "Axia Memory Technology", [10][0x20 - 1] = "Chipset Technology Holding Limited", [10][0x21 - 1] = "Shenzhen Xinshida Technology Co Ltd", [10][0x22 - 1] = "Shenzhen Chuangshifeida Technology", [10][0x23 - 1] = "Guangzhou MiaoYuanJi Technology", [10][0x24 - 1] = "ADVAN Inc", [10][0x25 - 1] = "Shenzhen Qianhai Weishengda Electronic Commerce Company Ltd", [10][0x26 - 1] = "Guangzhou Guang Xie Cheng Trading", [10][0x27 - 1] = "StarRam International Co Ltd", [10][0x28 - 1] = "Shen Zhen XinShenHua Tech Co Ltd", [10][0x29 - 1] = "UltraMemory Inc", [10][0x2a - 1] = "New Coastline Global Tech Industry Co", [10][0x2b - 1] = "Sinker", [10][0x2c - 1] = "Diamond", [10][0x2d - 1] = "PUSKILL", [10][0x2e - 1] = "Guangzhou Hao Jia Ye Technology Co", [10][0x2f - 1] = "Ming Xin Limited", [10][0x30 - 1] = "Barefoot Networks", [10][0x31 - 1] = "Biwin Semiconductor (HK) Co Ltd", [10][0x32 - 1] = "UD INFO Corporation", [10][0x33 - 1] = "Trek Technology (S) PTE Ltd", [10][0x34 - 1] = "Xiamen Kingblaze Technology Co Ltd", [10][0x35 - 1] = "Shenzhen Lomica Technology Co Ltd", [10][0x36 - 1] = "Nuclei System Technology Co Ltd", [10][0x37 - 1] = "Wuhan Xun Zhan Electronic Technology", [10][0x38 - 1] = "Shenzhen Ingacom Semiconductor Ltd", [10][0x39 - 1] = "Zotac Technology Ltd", [10][0x3a - 1] = "Foxline", [10][0x3b - 1] = "Shenzhen Farasia Science Technology", [10][0x3c - 1] = "Efinix Inc", [10][0x3d - 1] = "Hua Nan San Xian Technology Co Ltd", [10][0x3e - 1] = "Goldtech Electronics Co Ltd", [10][0x3f - 1] = "Shanghai Han Rong Microelectronics Co", [10][0x40 - 1] = "Shenzhen Zhongguang Yunhe Trading", [10][0x41 - 1] = "Smart Shine(QingDao) Microelectronics", [10][0x42 - 1] = "Thermaltake Technology Co Ltd", [10][0x43 - 1] = "Shenzhen O'Yang Maile Technology Ltd", [10][0x44 - 1] = "UPMEM", [10][0x45 - 1] = "Chun Well Technology Holding Limited", [10][0x46 - 1] = "Astera Labs Inc", [10][0x47 - 1] = "Winconway", [10][0x48 - 1] = "Advantech Co Ltd", [10][0x49 - 1] = "Chengdu Fengcai Electronic Technology", [10][0x4a - 1] = "The Boeing Company", [10][0x4b - 1] = "Blaize Inc", [10][0x4c - 1] = "Ramonster Technology Co Ltd", [10][0x4d - 1] = "Wuhan Naonongmai Technology Co Ltd", [10][0x4e - 1] = "Shenzhen Hui ShingTong Technology", [10][0x4f - 1] = "Yourlyon", [10][0x50 - 1] = "Fabu Technology", [10][0x51 - 1] = "Shenzhen Yikesheng Technology Co Ltd", [10][0x52 - 1] = "NOR-MEM", [10][0x53 - 1] = "Cervoz Co Ltd", [10][0x54 - 1] = "Bitmain Technologies Inc.", [10][0x55 - 1] = "Facebook Inc", [10][0x56 - 1] = "Shenzhen Longsys Electronics Co Ltd", [10][0x57 - 1] = "Guangzhou Siye Electronic Technology", [10][0x58 - 1] = "Silergy", [10][0x59 - 1] = "Adamway", [10][0x5a - 1] = "PZG", [10][0x5b - 1] = "Shenzhen King Power Electronics", [10][0x5c - 1] = "Guangzhou ZiaoFu Tranding Co Ltd", [10][0x5d - 1] = "Shenzhen SKIHOTAR Semiconductor", [10][0x5e - 1] = "PulseRain Technology", [10][0x5f - 1] = "Seeker Technology Limited", [10][0x60 - 1] = "Shenzhen OSCOO Tech Co Ltd", [10][0x61 - 1] = "Shenzhen Yze Technology Co Ltd", [10][0x62 - 1] = "Shenzhen Jieshuo Electronic Commerce", [10][0x63 - 1] = "Gazda", [10][0x64 - 1] = "Hua Wei Technology Co Ltd", [10][0x65 - 1] = "Esperanto Technologies", [10][0x66 - 1] = "JinSheng Electronic (Shenzhen) Co Ltd", [10][0x67 - 1] = "Shenzhen Shi Bolunshuai Technology", [10][0x68 - 1] = "Shanghai Rei Zuan Information Tech", [10][0x69 - 1] = "Fraunhofer IIS", [10][0x6a - 1] = "Kandou Bus SA", [10][0x6b - 1] = "Acer", [10][0x6c - 1] = "Artmem Technology Co Ltd", [10][0x6d - 1] = "Gstar Semiconductor Co Ltd", [10][0x6e - 1] = "ShineDisk", [10][0x6f - 1] = "Shenzhen CHN Technology Co Ltd", [10][0x70 - 1] = "UnionChip Semiconductor Co Ltd", [10][0x71 - 1] = "Tanbassh", [10][0x72 - 1] = "Shenzhen Tianyu Jieyun Intl Logistics", [10][0x73 - 1] = "MCLogic Inc", [10][0x74 - 1] = "Eorex Corporation", [10][0x75 - 1] = "Arm Technology (China) Co Ltd", [10][0x76 - 1] = "Lexar Co Limited", [10][0x77 - 1] = "QinetiQ Group plc", [10][0x78 - 1] = "Exascend", [10][0x79 - 1] = "Hong Kong Hyunion Electronics Co Ltd", [10][0x7a - 1] = "Shenzhen Banghong Electronics Co Ltd", [10][0x7b - 1] = "MBit Wireless Inc", [10][0x7c - 1] = "Hex Five Security Inc", [10][0x7d - 1] = "ShenZhen Juhor Precision Tech Co Ltd", [10][0x7e - 1] = "Shenzhen Reeinno Technology Co Ltd", [11][0x01 - 1] = "ABIT Electronics (Shenzhen) Co Ltd", [11][0x02 - 1] = "Semidrive", [11][0x03 - 1] = "MyTek Electronics Corp", [11][0x04 - 1] = "Wxilicon Technology Co Ltd", [11][0x05 - 1] = "Shenzhen Meixin Electronics Ltd", [11][0x06 - 1] = "Ghost Wolf", [11][0x07 - 1] = "LiSion Technologies Inc", [11][0x08 - 1] = "Power Active Co Ltd", [11][0x09 - 1] = "Pioneer High Fidelity Taiwan Co. Ltd", [11][0x0a - 1] = "LuoSilk", [11][0x0b - 1] = "Shenzhen Chuangshifeida Technology", [11][0x0c - 1] = "Black Sesame Technologies Inc", [11][0x0d - 1] = "Jiangsu Xinsheng Intelligent Technology", [11][0x0e - 1] = "MLOONG", [11][0x0f - 1] = "Quadratica LLC", [11][0x10 - 1] = "Anpec Electronics", [11][0x11 - 1] = "Xi'an Morebeck Semiconductor Tech Co", [11][0x12 - 1] = "Kingbank Technology Co Ltd", [11][0x13 - 1] = "ITRenew Inc", [11][0x14 - 1] = "Shenzhen Eaget Innovation Tech Ltd", [11][0x15 - 1] = "Jazer", [11][0x16 - 1] = "Xiamen Semiconductor Investment Group", [11][0x17 - 1] = "Guangzhou Longdao Network Tech Co", [11][0x18 - 1] = "Shenzhen Futian SEC Electronic Market", [11][0x19 - 1] = "Allegro Microsystems LLC", [11][0x1a - 1] = "Hunan RunCore Innovation Technology", [11][0x1b - 1] = "C-Corsa Technology", [11][0x1c - 1] = "Zhuhai Chuangfeixin Technology Co Ltd", [11][0x1d - 1] = "Beijing InnoMem Technologies Co Ltd", [11][0x1e - 1] = "YooTin", [11][0x1f - 1] = "Shenzhen Pengxiong Technology Co Ltd", [11][0x20 - 1] = "Dongguan Yingbang Commercial Trading Co", [11][0x21 - 1] = "Shenzhen Ronisys Electronics Co Ltd", [11][0x22 - 1] = "Hongkong Xinlan Guangke Co Ltd", [11][0x23 - 1] = "Apex Microelectronics Co Ltd", [11][0x24 - 1] = "Beijing Hongda Jinming Technology Co Ltd", [11][0x25 - 1] = "Ling Rui Technology (Shenzhen) Co Ltd", [11][0x26 - 1] = "Hongkong Hyunion Electronics Co Ltd", [11][0x27 - 1] = "Starsystems Inc", [11][0x28 - 1] = "Shenzhen Yingjiaxun Industrial Co Ltd", [11][0x29 - 1] = "Dongguan Crown Code Electronic Commerce", [11][0x2a - 1] = "Monolithic Power Systems Inc", [11][0x2b - 1] = "WuHan SenNaiBo E-Commerce Co Ltd", [11][0x2c - 1] = "Hangzhou Hikstorage Technology Co", [11][0x2d - 1] = "Shenzhen Goodix Technology Co Ltd", [11][0x2e - 1] = "Aigo Electronic Technology Co Ltd", [11][0x2f - 1] = "Hefei Konsemi Storage Technology Co Ltd", [11][0x30 - 1] = "Cactus Technologies Limited", [11][0x31 - 1] = "DSIN", [11][0x32 - 1] = "Blu Wireless Technology", [11][0x33 - 1] = "Nanjing UCUN Technology Inc", [11][0x34 - 1] = "Acacia Communications", [11][0x35 - 1] = "Beijinjinshengyihe Technology Co Ltd", [11][0x36 - 1] = "Zyzyx", [11][0x37 - 1] = "T-HEAD Semiconductor Co Ltd", [11][0x38 - 1] = "Shenzhen Hystou Technology Co Ltd", [11][0x39 - 1] = "Syzexion", [11][0x3a - 1] = "Kembona", [11][0x3b - 1] = "Qingdao Thunderobot Technology Co Ltd", [11][0x3c - 1] = "Morse Micro", [11][0x3d - 1] = "Shenzhen Envida Technology Co Ltd", [11][0x3e - 1] = "UDStore Solution Limited", [11][0x3f - 1] = "Shunlie", [11][0x40 - 1] = "Shenzhen Xin Hong Rui Tech Ltd", [11][0x41 - 1] = "Shenzhen Yze Technology Co Ltd", [11][0x42 - 1] = "Shenzhen Huang Pu He Xin Technology", [11][0x43 - 1] = "Xiamen Pengpai Microelectronics Co Ltd", [11][0x44 - 1] = "JISHUN", [11][0x45 - 1] = "Shenzhen WODPOSIT Technology Co", [11][0x46 - 1] = "Unistar", [11][0x47 - 1] = "UNICORE Electronic (Suzhou) Co Ltd", [11][0x48 - 1] = "Axonne Inc", [11][0x49 - 1] = "Shenzhen SOVERECA Technology Co", [11][0x4a - 1] = "Dire Wolf", [11][0x4b - 1] = "Whampoa Core Technology Co Ltd", [11][0x4c - 1] = "CSI Halbleiter GmbH", [11][0x4d - 1] = "ONE Semiconductor", [11][0x4e - 1] = "SimpleMachines Inc", [11][0x4f - 1] = "Shenzhen Chengyi Qingdian Electronic", [11][0x50 - 1] = "Shenzhen Xinlianxin Network Technology", [11][0x51 - 1] = "Vayyar Imaging Ltd", [11][0x52 - 1] = "Paisen Network Technology Co Ltd", [11][0x53 - 1] = "Shenzhen Fengwensi Technology Co Ltd", [11][0x54 - 1] = "Caplink Technology Limited", [11][0x55 - 1] = "JJT Solution Co Ltd", [11][0x56 - 1] = "HOSIN Global Electronics Co Ltd", [11][0x57 - 1] = "Shenzhen KingDisk Century Technology", [11][0x58 - 1] = "SOYO", [11][0x59 - 1] = "DIT Technology Co Ltd", [11][0x5a - 1] = "iFound", [11][0x5b - 1] = "Aril Computer Company", [11][0x5c - 1] = "ASUS", [11][0x5d - 1] = "Shenzhen Ruiyingtong Technology Co", [11][0x5e - 1] = "HANA Micron", [11][0x5f - 1] = "RANSOR", [11][0x60 - 1] = "Axiado Corporation", [11][0x61 - 1] = "Tesla Corporation", [11][0x62 - 1] = "Pingtouge (Shanghai) Semiconductor Co", [11][0x63 - 1] = "S3Plus Technologies SA", [11][0x64 - 1] = "Integrated Silicon Solution Israel Ltd", [11][0x65 - 1] = "GreenWaves Technologies", [11][0x66 - 1] = "NUVIA Inc", [11][0x67 - 1] = "Guangzhou Shuvrwine Technology Co", [11][0x68 - 1] = "Shenzhen Hangshun Chip Technology", [11][0x69 - 1] = "Chengboliwei Electronic Business", [11][0x6a - 1] = "Kowin Technology HK Limited", [11][0x6b - 1] = "Euronet Technology Inc", [11][0x6c - 1] = "SCY", [11][0x6d - 1] = "Shenzhen Xinhongyusheng Electrical", [11][0x6e - 1] = "PICOCOM", [11][0x6f - 1] = "Shenzhen Toooogo Memory Technology", [11][0x70 - 1] = "VLSI Solution", [11][0x71 - 1] = "Costar Electronics Inc", [11][0x72 - 1] = "Shenzhen Huatop Technology Co Ltd", [11][0x73 - 1] = "Inspur Electronic Information Industry", [11][0x74 - 1] = "Shenzhen Boyuan Computer Technology", [11][0x75 - 1] = "Beijing Welldisk Electronics Co Ltd", [11][0x76 - 1] = "Suzhou EP Semicon Co Ltd", [11][0x77 - 1] = "Zhejiang Dahua Memory Technology", [11][0x78 - 1] = "Virtu Financial", [11][0x79 - 1] = "Datotek International Co Ltd", [11][0x7a - 1] = "Telecom and Microelectronics Industries", [11][0x7b - 1] = "Echow Technology Ltd", [11][0x7c - 1] = "APEX-INFO", [11][0x7d - 1] = "Yingpark", [11][0x7e - 1] = "Shenzhen Bigway Tech Co Ltd", [12][0x01 - 1] = "Beijing Haawking Technology Co Ltd", [12][0x02 - 1] = "Open HW Group", [12][0x03 - 1] = "JHICC", [12][0x04 - 1] = "ncoder AG", [12][0x05 - 1] = "ThinkTech Information Technology Co", [12][0x06 - 1] = "Shenzhen Chixingzhe Technology Co Ltd", [12][0x07 - 1] = "Biao Ram Technology Co Ltd", [12][0x08 - 1] = "Shenzhen Kaizhuoyue Electronics Co Ltd", [12][0x09 - 1] = "Shenzhen YC Storage Technology Co Ltd", [12][0x0a - 1] = "Shenzhen Chixingzhe Technology Co", [12][0x0b - 1] = "Wink Semiconductor (Shenzhen) Co Ltd", [12][0x0c - 1] = "AISTOR", [12][0x0d - 1] = "Palma Ceia SemiDesign", [12][0x0e - 1] = "EM Microelectronic-Marin SA", [12][0x0f - 1] = "Shenzhen Monarch Memory Technology", [12][0x10 - 1] = "Reliance Memory Inc", [12][0x11 - 1] = "Jesis", [12][0x12 - 1] = "Espressif Systems (Shanghai) Co Ltd", [12][0x13 - 1] = "Shenzhen Sati Smart Technology Co Ltd", [12][0x14 - 1] = "NeuMem Co Ltd", [12][0x15 - 1] = "Lifelong", [12][0x16 - 1] = "Beijing Oitech Technology Co Ltd", [12][0x17 - 1] = "Groupe LDLC", [12][0x18 - 1] = "Semidynamics Technology Services SLU", [12][0x19 - 1] = "swordbill", [12][0x1a - 1] = "YIREN", [12][0x1b - 1] = "Shenzhen Yinxiang Technology Co Ltd", [12][0x1c - 1] = "PoweV Electronic Technology Co Ltd", [12][0x1d - 1] = "LEORICE", [12][0x1e - 1] = "Waymo LLC", [12][0x1f - 1] = "Ventana Micro Systems", [12][0x20 - 1] = "Hefei Guangxin Microelectronics Co Ltd", [12][0x21 - 1] = "Shenzhen Sooner Industrial Co Ltd", [12][0x22 - 1] = "Horizon Robotics", [12][0x23 - 1] = "Tangem AG", [12][0x24 - 1] = "FuturePath Technology (Shenzhen) Co", [12][0x25 - 1] = "RC Module", [12][0x26 - 1] = "Timetec International Inc", [12][0x27 - 1] = "ICMAX Technologies Co Limited", [12][0x28 - 1] = "Lynxi Technologies Ltd Co", [12][0x29 - 1] = "Guangzhou Taisupanke Computer Equipment", [12][0x2a - 1] = "Ceremorphic Inc", [12][0x2b - 1] = "Biwin Storage Technology Co Ltd", [12][0x2c - 1] = "Beijing ESWIN Computing Technology", [12][0x2d - 1] = "WeForce Co Ltd", [12][0x2e - 1] = "Shenzhen Fanxiang Information Technology", [12][0x2f - 1] = "Unisoc", [12][0x30 - 1] = "YingChu", [12][0x31 - 1] = "GUANCUN", [12][0x32 - 1] = "IPASON", [12][0x33 - 1] = "Ayar Labs", [12][0x34 - 1] = "Amazon", [12][0x35 - 1] = "Shenzhen Xinxinshun Technology Co", [12][0x36 - 1] = "Galois Inc", [12][0x37 - 1] = "Ubilite Inc", [12][0x38 - 1] = "Shenzhen Quanxing Technology Co Ltd", [12][0x39 - 1] = "Group RZX Technology LTDA", [12][0x3a - 1] = "Yottac Technology (XI'AN) Cooperation", [12][0x3b - 1] = "Shenzhen RuiRen Technology Co Ltd", [12][0x3c - 1] = "Group Star Technology Co Ltd", [12][0x3d - 1] = "RWA (Hong Kong) Ltd", [12][0x3e - 1] = "Genesys Logic Inc", [12][0x3f - 1] = "T3 Robotics Inc.", [12][0x40 - 1] = "Biostar Microtech International Corp", [12][0x41 - 1] = "Shenzhen SXmicro Technology Co Ltd", [12][0x42 - 1] = "Shanghai Yili Computer Technology Co", [12][0x43 - 1] = "Zhixin Semicoducotor Co Ltd", [12][0x44 - 1] = "uFound", [12][0x45 - 1] = "Aigo Data Security Technology Co. Ltd", [12][0x46 - 1] = ".GXore Technologies", [12][0x47 - 1] = "Shenzhen Pradeon Intelligent Technology", [12][0x48 - 1] = "Power LSI", [12][0x49 - 1] = "PRIME", [12][0x4a - 1] = "Shenzhen Juyang Innovative Technology", [12][0x4b - 1] = "CERVO", [12][0x4c - 1] = "SiEngine Technology Co., Ltd.", [12][0x4d - 1] = "Beijing Unigroup Tsingteng MicroSystem", [12][0x4e - 1] = "Brainsao GmbH", [12][0x4f - 1] = "Credo Technology Group Ltd", [12][0x50 - 1] = "Shanghai Biren Technology Co Ltd", [12][0x51 - 1] = "Nucleu Semiconductor", [12][0x52 - 1] = "Shenzhen Guangshuo Electronics Co Ltd", [12][0x53 - 1] = "ZhongsihangTechnology Co Ltd", [12][0x54 - 1] = "Suzhou Mainshine Electronic Co Ltd.", [12][0x55 - 1] = "Guangzhou Riss Electronic Technology", [12][0x56 - 1] = "Shenzhen Cloud Security Storage Co", [12][0x57 - 1] = "ROG", [12][0x58 - 1] = "Perceive", [12][0x59 - 1] = "e-peas", [12][0x5a - 1] = "Fraunhofer IPMS", [12][0x5b - 1] = "Shenzhen Daxinlang Electronic Tech Co", [12][0x5c - 1] = "Abacus Peripherals Private Limited", [12][0x5d - 1] = "OLOy Technology", [12][0x5e - 1] = "Wuhan P&S Semiconductor Co Ltd", [12][0x5f - 1] = "Sitrus Technology", [12][0x60 - 1] = "AnHui Conner Storage Co Ltd", [12][0x61 - 1] = "Rochester Electronics", [12][0x62 - 1] = "Wuxi Petabyte Technologies Co Ltd", [12][0x63 - 1] = "Star Memory", [12][0x64 - 1] = "Agile Memory Technology Co Ltd", [12][0x65 - 1] = "MEJEC", [12][0x66 - 1] = "Rockchip Electronics Co Ltd", [12][0x67 - 1] = "Dongguan Guanma e-commerce Co Ltd", [12][0x68 - 1] = "Rayson Hi-Tech (SZ) Limited", [12][0x69 - 1] = "MINRES Technologies GmbH", [12][0x6a - 1] = "Himax Technologies Inc", [12][0x6b - 1] = "Shenzhen Cwinner Technology Co Ltd", [12][0x6c - 1] = "Tecmiyo", [12][0x6d - 1] = "Shenzhen Suhuicun Technology Co Ltd", [12][0x6e - 1] = "Vickter Electronics Co. Ltd.", [12][0x6f - 1] = "lowRISC", [12][0x70 - 1] = "EXEGate FZE", [12][0x71 - 1] = "Shenzhen 9 Chapter Technologies Co", [12][0x72 - 1] = "Addlink", [12][0x73 - 1] = "Starsway", [12][0x74 - 1] = "Pensando Systems Inc.", [12][0x75 - 1] = "AirDisk", [12][0x76 - 1] = "Shenzhen Speedmobile Technology Co", [12][0x77 - 1] = "PEZY Computing", [12][0x78 - 1] = "Extreme Engineering Solutions Inc", [12][0x79 - 1] = "Shangxin Technology Co Ltd", [12][0x7a - 1] = "Shanghai Zhaoxin Semiconductor Co", [12][0x7b - 1] = "Xsight Labs Ltd", [12][0x7c - 1] = "Hangzhou Hikstorage Technology Co", [12][0x7d - 1] = "Dell Technologies", [12][0x7e - 1] = "Guangdong StarFive Technology Co", [13][0x01 - 1] = "TECOTON", [13][0x02 - 1] = "Abko Co Ltd", [13][0x03 - 1] = "Shenzhen Feisrike Technology Co Ltd", [13][0x04 - 1] = "Shenzhen Sunhome Electronics Co Ltd", [13][0x05 - 1] = "Global Mixed-mode Technology Inc", [13][0x06 - 1] = "Shenzhen Weien Electronics Co. Ltd.", [13][0x07 - 1] = "Shenzhen Cooyes Technology Co Ltd", [13][0x08 - 1] = "Keymos Electronics Co., Limited", [13][0x09 - 1] = "E-Rockic Technology Company Limited", [13][0x0a - 1] = "Aerospace Science Memory Shenzhen", [13][0x0b - 1] = "Shenzhen Quanji Technology Co Ltd", [13][0x0c - 1] = "Dukosi", [13][0x0d - 1] = "Maxell Corporation of America", [13][0x0e - 1] = "Shenshen Xinxintao Electronics Co Ltd", [13][0x0f - 1] = "Zhuhai Sanxia Semiconductor Co Ltd", [13][0x10 - 1] = "Groq Inc", [13][0x11 - 1] = "AstraTek", [13][0x12 - 1] = "Shenzhen Xinyuze Technology Co Ltd", [13][0x13 - 1] = "All Bit Semiconductor", [13][0x14 - 1] = "ACFlow", [13][0x15 - 1] = "Shenzhen Sipeed Technology Co Ltd", [13][0x16 - 1] = "Linzhi Hong Kong Co Limited", [13][0x17 - 1] = "Supreme Wise Limited", [13][0x18 - 1] = "Blue Cheetah Analog Design Inc", [13][0x19 - 1] = "Hefei Laiku Technology Co Ltd", [13][0x1a - 1] = "Zord", [13][0x1b - 1] = "SBO Hearing A/S", [13][0x1c - 1] = "Regent Sharp International Limited", [13][0x1d - 1] = "Permanent Potential Limited", [13][0x1e - 1] = "Creative World International Limited", [13][0x1f - 1] = "Base Creation International Limited", [13][0x20 - 1] = "Shenzhen Zhixin Chuanglian Technology", [13][0x21 - 1] = "Protected Logic Corporation", [13][0x22 - 1] = "Sabrent", [13][0x23 - 1] = "Union Memory", [13][0x24 - 1] = "NEUCHIPS Corporation", [13][0x25 - 1] = "Ingenic Semiconductor Co Ltd", [13][0x26 - 1] = "SiPearl", [13][0x27 - 1] = "Shenzhen Actseno Information Technology", [13][0x28 - 1] = "RIVAI Technologies (Shenzhen) Co Ltd", [13][0x29 - 1] = "Shenzhen Sunny Technology Co Ltd", [13][0x2a - 1] = "Cott Electronics Ltd", [13][0x2b - 1] = "Shanghai Synsense Technologies Co Ltd", [13][0x2c - 1] = "Shenzhen Jintang Fuming Optoelectronics", [13][0x2d - 1] = "CloudBEAR LLC", [13][0x2e - 1] = "Emzior, LLC", [13][0x2f - 1] = "Ehiway Microelectronic Science Tech Co", [13][0x30 - 1] = "UNIM Innovation Technology (Wu XI)", [13][0x31 - 1] = "GDRAMARS", [13][0x32 - 1] = "Meminsights Technology", [13][0x33 - 1] = "Zhuzhou Hongda Electronics Corp Ltd", [13][0x34 - 1] = "Luminous Computing Inc", [13][0x35 - 1] = "PROXMEM", [13][0x36 - 1] = "Draper Labs", [13][0x37 - 1] = "ORICO Technologies Co. Ltd.", [13][0x38 - 1] = "Space Exploration Technologies Corp", [13][0x39 - 1] = "AONDEVICES Inc", [13][0x3a - 1] = "Shenzhen Netforward Micro Electronic", [13][0x3b - 1] = "Syntacore Ltd", [13][0x3c - 1] = "Shenzhen Secmem Microelectronics Co", [13][0x3d - 1] = "ONiO As", [13][0x3e - 1] = "Shenzhen Peladn Technology Co Ltd", [13][0x3f - 1] = "O-Cubes Shanghai Microelectronics", [13][0x40 - 1] = "ASTC", [13][0x41 - 1] = "UMIS", [13][0x42 - 1] = "Paradromics", [13][0x43 - 1] = "Sinh Micro Co Ltd", [13][0x44 - 1] = "Metorage Semiconductor Technology Co", [13][0x45 - 1] = "Aeva Inc", [13][0x46 - 1] = "HongKong Hyunion Electronics Co Ltd", [13][0x47 - 1] = "China Flash Co Ltd", [13][0x48 - 1] = "Sunplus Technology Co Ltd", [13][0x49 - 1] = "Idaho Scientific", [13][0x4a - 1] = "Suzhou SF Micro Electronics Co Ltd", [13][0x4b - 1] = "IMEX Cap AG", [13][0x4c - 1] = "Fitipower Integrated Technology Co Ltd", [13][0x4d - 1] = "ShenzhenWooacme Technology Co Ltd", [13][0x4e - 1] = "KeepData Original Chips", [13][0x4f - 1] = "Rivos Inc", [13][0x50 - 1] = "Big Innovation Company Limited", [13][0x51 - 1] = "Wuhan YuXin Semiconductor Co Ltd", [13][0x52 - 1] = "United Memory Technology (Jiangsu)", [13][0x53 - 1] = "PQShield Ltd", [13][0x54 - 1] = "ArchiTek Corporation", [13][0x55 - 1] = "ShenZhen AZW Technology Co Ltd", [13][0x56 - 1] = "Hengchi Zhixin (Dongguan) Technology", [13][0x57 - 1] = "Eggtronic Engineering Spa", [13][0x58 - 1] = "Fusontai Technology", [13][0x59 - 1] = "PULP Platform", [13][0x5a - 1] = "Koitek Electronic Technology (Shenzhen) Co", [13][0x5b - 1] = "Shenzhen Jiteng Network Technology Co", [13][0x5c - 1] = "Aviva Links Inc", [13][0x5d - 1] = "Trilinear Technologies Inc", [13][0x5e - 1] = "Shenzhen Developer Microelectronics Co", [13][0x5f - 1] = "Guangdong OPPO Mobile Telecommunication", [13][0x60 - 1] = "Akeana", [13][0x61 - 1] = "Lyczar", [13][0x62 - 1] = "Shenzhen Qiji Technology Co Ltd", [13][0x63 - 1] = "Shenzhen Shangzhaoyuan Technology", [13][0x64 - 1] = "Han Stor", [13][0x65 - 1] = "China Micro Semicon Co., Ltd.", [13][0x66 - 1] = "Shenzhen Zhuqin Technology Co Ltd", [13][0x67 - 1] = "Shanghai Ningyuan Electronic Technology", [13][0x68 - 1] = "Auradine", [13][0x69 - 1] = "Suzhou Yishuo Electronics Co Ltd", [13][0x6a - 1] = "Faurecia Clarion Electronics", [13][0x6b - 1] = "SiMa Technologies", [13][0x6c - 1] = "CFD Sales Inc", [13][0x6d - 1] = "Suzhou Comay Information Co Ltd", [13][0x6e - 1] = "Yentek", [13][0x6f - 1] = "Qorvo Inc", [13][0x70 - 1] = "Shenzhen Youzhi Computer Technology", [13][0x71 - 1] = "Sychw Technology (Shenzhen) Co Ltd", [13][0x72 - 1] = "MK Founder Technology Co Ltd", [13][0x73 - 1] = "Siliconwaves Technologies Co Ltd", [13][0x74 - 1] = "Hongkong Hyunion Electronics Co Ltd", [13][0x75 - 1] = "Shenzhen Xinxinzhitao Electronics Business", [13][0x76 - 1] = "Shenzhen HenQi Electronic Commerce Co", [13][0x77 - 1] = "Shenzhen Jingyi Technology Co Ltd", [13][0x78 - 1] = "Xiaohua Semiconductor Co. Ltd.", [13][0x79 - 1] = "Shenzhen Dalu Semiconductor Technology", [13][0x7a - 1] = "Shenzhen Ninespeed Electronics Co Ltd", [13][0x7b - 1] = "ICYC Semiconductor Co Ltd", [13][0x7c - 1] = "Shenzhen Jaguar Microsystems Co Ltd", [13][0x7d - 1] = "Beijing EC-Founder Co Ltd", [13][0x7e - 1] = "Shenzhen Taike Industrial Automation Co", [14][0x01 - 1] = "Kalray SA", [14][0x02 - 1] = "Shanghai Iluvatar CoreX Semiconductor Co", [14][0x03 - 1] = "Fungible Inc", [14][0x04 - 1] = "Song Industria E Comercio de Eletronicos", [14][0x05 - 1] = "DreamBig Semiconductor Inc", [14][0x06 - 1] = "ChampTek Electronics Corp", [14][0x07 - 1] = "Fusontai Technology", [14][0x08 - 1] = "Endress Hauser AG", [14][0x09 - 1] = "altec ComputerSysteme GmbH", [14][0x0a - 1] = "UltraRISC Technology (Shanghai) Co Ltd", [14][0x0b - 1] = "Shenzhen Jing Da Kang Technology Co Ltd", [14][0x0c - 1] = "Hangzhou Hongjun Microelectronics Co Ltd", [14][0x0d - 1] = "Pliops Ltd", [14][0x0e - 1] = "Cix Technology (Shanghai) Co Ltd", [14][0x0f - 1] = "TeraDevices Inc", [14][0x10 - 1] = "SpacemiT (Hangzhou)Technology Co Ltd", [14][0x11 - 1] = "InnoPhase loT Inc", [14][0x12 - 1] = "InnoPhase loT Inc", [14][0x13 - 1] = "Yunhight Microelectronics", [14][0x14 - 1] = "Samnix", [14][0x15 - 1] = "HKC Storage Co Ltd", [14][0x16 - 1] = "Chiplego Technology (Shanghai) Co Ltd", [14][0x17 - 1] = "StoreSkill", [14][0x18 - 1] = "Shenzhen Astou Technology Company", [14][0x19 - 1] = "Guangdong LeafFive Technology Limited", [14][0x1a - 1] = "Jin JuQuan", [14][0x1b - 1] = "Huaxuan Technology (Shenzhen) Co Ltd", [14][0x1c - 1] = "Gigastone Corporation", [14][0x1d - 1] = "Kinsotin", [14][0x1e - 1] = "PengYing", [14][0x1f - 1] = "Shenzhen Xunhi Technology Co Ltd", [14][0x20 - 1] = "FOXX Storage Inc", [14][0x21 - 1] = "Shanghai Belling Corporation Ltd", [14][0x22 - 1] = "Glenfy Tech Co Ltd", [14][0x23 - 1] = "Sahasra Semiconductors Pvt Ltd", [14][0x24 - 1] = "Chongqing SeekWave Technology Co Ltd", [14][0x25 - 1] = "Shenzhen Zhixing Intelligent Manufacturing", [14][0x26 - 1] = "Ethernovia", [14][0x27 - 1] = "Shenzhen Xinrongda Technology Co Ltd", [14][0x28 - 1] = "Hangzhou Clounix Technology Limited", [14][0x29 - 1] = "JGINYUE", [14][0x2a - 1] = "Shenzhen Xinwei Semiconductor Co Ltd", [14][0x2b - 1] = "COLORFIRE Technology Co Ltd", [14][0x2c - 1] = "B LKE", [14][0x2d - 1] = "ZHUDIAN", [14][0x2e - 1] = "REECHO", [14][0x2f - 1] = "Enphase Energy Inc", [14][0x30 - 1] = "Shenzhen Yingrui Storage Technology Co Ltd", [14][0x31 - 1] = "Shenzhen Sinomos Semiconductor Technology", [14][0x32 - 1] = "O2micro International Limited", [14][0x33 - 1] = "Axelera AI BV", [14][0x34 - 1] = "Silicon Legend Technology (Suzhou) Co Ltd", [14][0x35 - 1] = "Suzhou Novosense Microelectronics Co Ltd", [14][0x36 - 1] = "Pirateman", [14][0x37 - 1] = "Yangtze MasonSemi", [14][0x38 - 1] = "Shanghai Yunsilicon Technology Co Ltd", [14][0x39 - 1] = "Rayson", [14][0x3a - 1] = "Alphawave IP", [14][0x3b - 1] = "Shenzhen Visions Chip Electronic Technology", [14][0x3c - 1] = "KYO Group", [14][0x3d - 1] = "Shenzhen Aboison Technology Co Ltd", [14][0x3e - 1] = "Shenzhen JingSheng Semiconducto Co Ltd", [14][0x3f - 1] = "Shenzhen Dingsheng Technology Co Ltd", [14][0x40 - 1] = "EVAS Intelligence Co Ltd", [14][0x41 - 1] = "Kaibright Electronic Technologies", /* EOF */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/jim-nvp.c ================================================ // SPDX-License-Identifier: BSD-2-Clause-Views /* Jim - A small embeddable Tcl interpreter * * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org> * Copyright 2005 Clemens Hintze <c.hintze@gmx.net> * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com * Copyright 2008 Andrew Lunn <andrew@lunn.ch> * Copyright 2008 Duane Ellis <openocd@duaneellis.com> * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de> * Copyright 2008 Steve Bennett <steveb@workware.net.au> * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl> * Copyright 2009 Zachary T Welch zw@superlucidity.net * Copyright 2009 David Brownell * Copyright (c) 2005-2011 Jim Tcl Project. All rights reserved. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jim-nvp.h" #include <string.h> int jim_get_nvp(Jim_Interp *interp, Jim_Obj *objptr, const struct jim_nvp *nvp_table, const struct jim_nvp **result) { struct jim_nvp *n; int e; e = jim_nvp_name2value_obj(interp, nvp_table, objptr, &n); if (e == JIM_ERR) return e; /* Success? found? */ if (n->name) { /* remove const */ *result = (struct jim_nvp *)n; return JIM_OK; } else return JIM_ERR; } struct jim_nvp *jim_nvp_name2value_simple(const struct jim_nvp *p, const char *name) { while (p->name) { if (strcmp(name, p->name) == 0) break; p++; } return (struct jim_nvp *)p; } struct jim_nvp *jim_nvp_name2value_nocase_simple(const struct jim_nvp *p, const char *name) { while (p->name) { if (strcasecmp(name, p->name) == 0) break; p++; } return (struct jim_nvp *)p; } int jim_nvp_name2value_obj(Jim_Interp *interp, const struct jim_nvp *p, Jim_Obj *o, struct jim_nvp **result) { return jim_nvp_name2value(interp, p, Jim_String(o), result); } int jim_nvp_name2value(Jim_Interp *interp, const struct jim_nvp *_p, const char *name, struct jim_nvp **result) { const struct jim_nvp *p; p = jim_nvp_name2value_simple(_p, name); /* result */ if (result) *result = (struct jim_nvp *)p; /* found? */ if (p->name) return JIM_OK; else return JIM_ERR; } int jim_nvp_name2value_obj_nocase(Jim_Interp *interp, const struct jim_nvp *p, Jim_Obj *o, struct jim_nvp **puthere) { return jim_nvp_name2value_nocase(interp, p, Jim_String(o), puthere); } int jim_nvp_name2value_nocase(Jim_Interp *interp, const struct jim_nvp *_p, const char *name, struct jim_nvp **puthere) { const struct jim_nvp *p; p = jim_nvp_name2value_nocase_simple(_p, name); if (puthere) *puthere = (struct jim_nvp *)p; /* found */ if (p->name) return JIM_OK; else return JIM_ERR; } int jim_nvp_value2name_obj(Jim_Interp *interp, const struct jim_nvp *p, Jim_Obj *o, struct jim_nvp **result) { int e; jim_wide w; e = Jim_GetWide(interp, o, &w); if (e != JIM_OK) return e; return jim_nvp_value2name(interp, p, w, result); } struct jim_nvp *jim_nvp_value2name_simple(const struct jim_nvp *p, int value) { while (p->name) { if (value == p->value) break; p++; } return (struct jim_nvp *)p; } int jim_nvp_value2name(Jim_Interp *interp, const struct jim_nvp *_p, int value, struct jim_nvp **result) { const struct jim_nvp *p; p = jim_nvp_value2name_simple(_p, value); if (result) *result = (struct jim_nvp *)p; if (p->name) return JIM_OK; else return JIM_ERR; } int jim_getopt_setup(struct jim_getopt_info *p, Jim_Interp *interp, int argc, Jim_Obj *const *argv) { memset(p, 0, sizeof(*p)); p->interp = interp; p->argc = argc; p->argv = argv; return JIM_OK; } void jim_getopt_debug(struct jim_getopt_info *p) { int x; fprintf(stderr, "---args---\n"); for (x = 0; x < p->argc; x++) fprintf(stderr, "%2d) %s\n", x, Jim_String(p->argv[x])); fprintf(stderr, "-------\n"); } int jim_getopt_obj(struct jim_getopt_info *goi, Jim_Obj **puthere) { Jim_Obj *o; o = NULL; /* failure */ if (goi->argc) { /* success */ o = goi->argv[0]; goi->argc -= 1; goi->argv += 1; } if (puthere) *puthere = o; if (o) return JIM_OK; else return JIM_ERR; } int jim_getopt_string(struct jim_getopt_info *goi, const char **puthere, int *len) { int r; Jim_Obj *o; const char *cp; r = jim_getopt_obj(goi, &o); if (r == JIM_OK) { cp = Jim_GetString(o, len); if (puthere) { *puthere = cp; } } return r; } int jim_getopt_double(struct jim_getopt_info *goi, double *puthere) { int r; Jim_Obj *o; double _safe; if (!puthere) puthere = &_safe; r = jim_getopt_obj(goi, &o); if (r == JIM_OK) { r = Jim_GetDouble(goi->interp, o, puthere); if (r != JIM_OK) Jim_SetResultFormatted(goi->interp, "not a number: %#s", o); } return r; } int jim_getopt_wide(struct jim_getopt_info *goi, jim_wide *puthere) { int r; Jim_Obj *o; jim_wide _safe; if (!puthere) puthere = &_safe; r = jim_getopt_obj(goi, &o); if (r == JIM_OK) r = Jim_GetWide(goi->interp, o, puthere); return r; } int jim_getopt_nvp(struct jim_getopt_info *goi, const struct jim_nvp *nvp, struct jim_nvp **puthere) { struct jim_nvp *_safe; Jim_Obj *o; int e; if (!puthere) puthere = &_safe; e = jim_getopt_obj(goi, &o); if (e == JIM_OK) e = jim_nvp_name2value_obj(goi->interp, nvp, o, puthere); return e; } void jim_getopt_nvp_unknown(struct jim_getopt_info *goi, const struct jim_nvp *nvptable, int hadprefix) { if (hadprefix) jim_set_result_nvp_unknown(goi->interp, goi->argv[-2], goi->argv[-1], nvptable); else jim_set_result_nvp_unknown(goi->interp, NULL, goi->argv[-1], nvptable); } int jim_getopt_enum(struct jim_getopt_info *goi, const char *const *lookup, int *puthere) { int _safe; Jim_Obj *o; int e; if (!puthere) puthere = &_safe; e = jim_getopt_obj(goi, &o); if (e == JIM_OK) e = Jim_GetEnum(goi->interp, o, lookup, puthere, "option", JIM_ERRMSG); return e; } void jim_set_result_nvp_unknown(Jim_Interp *interp, Jim_Obj *param_name, Jim_Obj *param_value, const struct jim_nvp *nvp) { if (param_name) Jim_SetResultFormatted(interp, "%#s: Unknown: %#s, try one of: ", param_name, param_value); else Jim_SetResultFormatted(interp, "Unknown param: %#s, try one of: ", param_value); while (nvp->name) { const char *a; const char *b; if ((nvp + 1)->name) { a = nvp->name; b = ", "; } else { a = "or "; b = nvp->name; } Jim_AppendStrings(interp, Jim_GetResult(interp), a, b, NULL); nvp++; } } const char *jim_debug_argv_string(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { static Jim_Obj *debug_string_obj; int x; if (debug_string_obj) Jim_FreeObj(interp, debug_string_obj); debug_string_obj = Jim_NewEmptyStringObj(interp); for (x = 0; x < argc; x++) Jim_AppendStrings(interp, debug_string_obj, Jim_String(argv[x]), " ", NULL); return Jim_String(debug_string_obj); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/jim-nvp.h ================================================ /* SPDX-License-Identifier: BSD-2-Clause-Views */ /* Jim - A small embeddable Tcl interpreter * * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org> * Copyright 2005 Clemens Hintze <c.hintze@gmx.net> * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com * Copyright 2008 Andrew Lunn <andrew@lunn.ch> * Copyright 2008 Duane Ellis <openocd@duaneellis.com> * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de> * Copyright 2008 Steve Bennett <steveb@workware.net.au> * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl> * Copyright 2009 Zachary T Welch zw@superlucidity.net * Copyright 2009 David Brownell * Copyright (c) 2005-2011 Jim Tcl Project. All rights reserved. */ #ifndef OPENOCD_HELPER_JIM_NVP_H #define OPENOCD_HELPER_JIM_NVP_H #include <jim.h> #include <stdio.h> /** Name Value Pairs, aka: NVP * - Given a string - return the associated int. * - Given a number - return the associated string. * . * * Very useful when the number is not a simple index into an array of * known string, or there may be multiple strings (aliases) that mean then same * thing. * * An NVP Table is terminated with ".name = NULL". * * During the 'name2value' operation, if no matching string is found * the pointer to the terminal element (with p->name == NULL) is returned. * * Example: * \code * const struct jim_nvp yn[] = { * { "yes", 1 }, * { "no" , 0 }, * { "yep", 1 }, * { "nope", 0 }, * { NULL, -1 }, * }; * * struct jim_nvp *result * e = jim_nvp_name2value(interp, yn, "y", &result); * returns &yn[0]; * e = jim_nvp_name2value(interp, yn, "n", &result); * returns &yn[1]; * e = jim_nvp_name2value(interp, yn, "Blah", &result); * returns &yn[4]; * \endcode * * During the number2name operation, the first matching value is returned. */ struct jim_nvp { const char *name; int value; }; int jim_get_nvp(Jim_Interp *interp, Jim_Obj *objptr, const struct jim_nvp *nvp_table, const struct jim_nvp **result); /* Name Value Pairs Operations */ struct jim_nvp *jim_nvp_name2value_simple(const struct jim_nvp *nvp_table, const char *name); struct jim_nvp *jim_nvp_name2value_nocase_simple(const struct jim_nvp *nvp_table, const char *name); struct jim_nvp *jim_nvp_value2name_simple(const struct jim_nvp *nvp_table, int v); int jim_nvp_name2value(Jim_Interp *interp, const struct jim_nvp *nvp_table, const char *name, struct jim_nvp **result); int jim_nvp_name2value_nocase(Jim_Interp *interp, const struct jim_nvp *nvp_table, const char *name, struct jim_nvp **result); int jim_nvp_value2name(Jim_Interp *interp, const struct jim_nvp *nvp_table, int value, struct jim_nvp **result); int jim_nvp_name2value_obj(Jim_Interp *interp, const struct jim_nvp *nvp_table, Jim_Obj *name_obj, struct jim_nvp **result); int jim_nvp_name2value_obj_nocase(Jim_Interp *interp, const struct jim_nvp *nvp_table, Jim_Obj *name_obj, struct jim_nvp **result); int jim_nvp_value2name_obj(Jim_Interp *interp, const struct jim_nvp *nvp_table, Jim_Obj *value_obj, struct jim_nvp **result); /** prints a nice 'unknown' parameter error message to the 'result' */ void jim_set_result_nvp_unknown(Jim_Interp *interp, Jim_Obj *param_name, Jim_Obj *param_value, const struct jim_nvp *nvp_table); /** Debug: convert argc/argv into a printable string for printf() debug * * \param interp - the interpreter * \param argc - arg count * \param argv - the objects * * \returns string pointer holding the text. * * Note, next call to this function will free the old (last) string. * * For example might want do this: * \code * fp = fopen("some.file.log", "a"); * fprintf(fp, "PARAMS are: %s\n", Jim_DebugArgvString(interp, argc, argv)); * fclose(fp); * \endcode */ const char *jim_debug_argv_string(Jim_Interp *interp, int argc, Jim_Obj *const *argv); /** A TCL -ish GetOpt like code. * * Some TCL objects have various "configuration" values. * For example - in Tcl/Tk the "buttons" have many options. * * Useful when dealing with command options. * that may come in any order... * * Does not support "-foo = 123" type options. * Only supports tcl type options, like "-foo 123" */ struct jim_getopt_info { Jim_Interp *interp; int argc; Jim_Obj *const *argv; int isconfigure; /* non-zero if configure */ }; /** GetOpt - how to. * * Example (short and incomplete): * \code * struct jim_getopt_info goi; * * jim_getopt_setup(&goi, interp, argc, argv); * * while (goi.argc) { * e = jim_getopt_nvp(&goi, nvp_options, &n); * if (e != JIM_OK) { * jim_getopt_nvp_unknown(&goi, nvp_options, 0); * return e; * } * * switch (n->value) { * case ALIVE: * printf("Option ALIVE specified\n"); * break; * case FIRST: * if (goi.argc < 1) { * .. not enough args error .. * } * jim_getopt_string(&goi, &cp, NULL); * printf("FIRSTNAME: %s\n", cp); * case AGE: * jim_getopt_wide(&goi, &w); * printf("AGE: %d\n", (int)(w)); * break; * case POLITICS: * e = jim_getopt_nvp(&goi, nvp_politics, &n); * if (e != JIM_OK) { * jim_getopt_nvp_unknown(&goi, nvp_politics, 1); * return e; * } * } * } * * \endcode * */ /** Setup GETOPT * * \param goi - get opt info to be initialized * \param interp - jim interp * \param argc - argc count. * \param argv - argv (will be copied) * * \code * struct jim_getopt_info goi; * * Jim_GetOptSetup(&goi, interp, argc, argv); * \endcode */ int jim_getopt_setup(struct jim_getopt_info *goi, Jim_Interp *interp, int argc, Jim_Obj *const *argv); /** Debug - Dump parameters to stderr * \param goi - current parameters */ void jim_getopt_debug(struct jim_getopt_info *goi); /** Remove argv[0] from the list. * * \param goi - get opt info * \param puthere - where param is put * */ int jim_getopt_obj(struct jim_getopt_info *goi, Jim_Obj **puthere); /** Remove argv[0] as string. * * \param goi - get opt info * \param puthere - where param is put * \param len - return its length */ int jim_getopt_string(struct jim_getopt_info *goi, const char **puthere, int *len); /** Remove argv[0] as double. * * \param goi - get opt info * \param puthere - where param is put. * */ int jim_getopt_double(struct jim_getopt_info *goi, double *puthere); /** Remove argv[0] as wide. * * \param goi - get opt info * \param puthere - where param is put. */ int jim_getopt_wide(struct jim_getopt_info *goi, jim_wide *puthere); /** Remove argv[0] as NVP. * * \param goi - get opt info * \param lookup - nvp lookup table * \param puthere - where param is put. * */ int jim_getopt_nvp(struct jim_getopt_info *goi, const struct jim_nvp *lookup, struct jim_nvp **puthere); /** Create an appropriate error message for an NVP. * * \param goi - options info * \param lookup - the NVP table that was used. * \param hadprefix - 0 or 1 if the option had a prefix. * * This function will set the "interp->result" to a human readable * error message listing the available options. * * This function assumes the previous option argv[-1] is the unknown string. * * If this option had some prefix, then pass "hadprefix = 1" else pass "hadprefix = 0" * * Example: * \code * * while (goi.argc) { * // Get the next option * e = jim_getopt_nvp(&goi, cmd_options, &n); * if (e != JIM_OK) { * // option was not recognized * // pass 'hadprefix = 0' because there is no prefix * jim_getopt_nvp_unknown(&goi, cmd_options, 0); * return e; * } * * switch (n->value) { * case OPT_SEX: * // handle: --sex male | female | lots | needmore * e = jim_getopt_nvp(&goi, &nvp_sex, &n); * if (e != JIM_OK) { * jim_getopt_nvp_unknown(&ogi, nvp_sex, 1); * return e; * } * printf("Code: (%d) is %s\n", n->value, n->name); * break; * case ...: * [snip] * } * } * \endcode * */ void jim_getopt_nvp_unknown(struct jim_getopt_info *goi, const struct jim_nvp *lookup, int hadprefix); /** Remove argv[0] as Enum * * \param goi - get opt info * \param lookup - lookup table. * \param puthere - where param is put. * */ int jim_getopt_enum(struct jim_getopt_info *goi, const char *const *lookup, int *puthere); #endif /* OPENOCD_HELPER_JIM_NVP_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/list.h ================================================ /* SPDX-License-Identifier: GPL-2.0-only */ /* * The content of this file is mainly copied/inspired from Linux kernel * code in include/linux/list.h, include/linux/types.h * Last aligned with kernel v5.12: * - skip the functions hlist_unhashed_lockless() and __list_del_clearprev() * that are relevant only in kernel; * - Remove non-standard GCC extension "omitted conditional operand" from * list_prepare_entry; * - expand READ_ONCE, WRITE_ONCE, smp_load_acquire, smp_store_release; * - make comments compatible with doxygen. * * There is an example of using this file in contrib/list_example.c. */ #ifndef OPENOCD_HELPER_LIST_H #define OPENOCD_HELPER_LIST_H /* begin local changes */ #include <helper/types.h> #define LIST_POISON1 NULL #define LIST_POISON2 NULL struct list_head { struct list_head *next, *prev; }; /* end local changes */ /* * Circular doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) /** * INIT_LIST_HEAD - Initialize a list_head structure * @param list list_head structure to be initialized. * * Initializes the list_head to point to itself. If it is a list header, * the result is an empty list. */ static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } #ifdef CONFIG_DEBUG_LIST extern bool __list_add_valid(struct list_head *new, struct list_head *prev, struct list_head *next); extern bool __list_del_entry_valid(struct list_head *entry); #else static inline bool __list_add_valid(struct list_head *new, struct list_head *prev, struct list_head *next) { return true; } static inline bool __list_del_entry_valid(struct list_head *entry) { return true; } #endif /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { if (!__list_add_valid(new, prev, next)) return; next->prev = new; new->next = next; new->prev = prev; prev->next = new; } /** * list_add - add a new entry * @param new new entry to be added * @param head list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ static inline void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } /** * list_add_tail - add a new entry * @param new new entry to be added * @param head list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_del(struct list_head *prev, struct list_head *next) { next->prev = prev; prev->next = next; } /* Ignore kernel __list_del_clearprev() */ static inline void __list_del_entry(struct list_head *entry) { if (!__list_del_entry_valid(entry)) return; __list_del(entry->prev, entry->next); } /** * list_del - deletes entry from list. * @param entry the element to delete from the list. * Note: list_empty() on entry does not return true after this, the entry is * in an undefined state. */ static inline void list_del(struct list_head *entry) { __list_del_entry(entry); entry->next = LIST_POISON1; entry->prev = LIST_POISON2; } /** * list_replace - replace old entry by new one * @param old the element to be replaced * @param new the new element to insert * * If @a old was empty, it will be overwritten. */ static inline void list_replace(struct list_head *old, struct list_head *new) { new->next = old->next; new->next->prev = new; new->prev = old->prev; new->prev->next = new; } /** * list_replace_init - replace old entry by new one and initialize the old one * @param old the element to be replaced * @param new the new element to insert * * If @a old was empty, it will be overwritten. */ static inline void list_replace_init(struct list_head *old, struct list_head *new) { list_replace(old, new); INIT_LIST_HEAD(old); } /** * list_swap - replace entry1 with entry2 and re-add entry1 at entry2's position * @param entry1 the location to place entry2 * @param entry2 the location to place entry1 */ static inline void list_swap(struct list_head *entry1, struct list_head *entry2) { struct list_head *pos = entry2->prev; list_del(entry2); list_replace(entry1, entry2); if (pos == entry1) pos = entry2; list_add(entry1, pos); } /** * list_del_init - deletes entry from list and reinitialize it. * @param entry the element to delete from the list. */ static inline void list_del_init(struct list_head *entry) { __list_del_entry(entry); INIT_LIST_HEAD(entry); } /** * list_move - delete from one list and add as another's head * @param list the entry to move * @param head the head that will precede our entry */ static inline void list_move(struct list_head *list, struct list_head *head) { __list_del_entry(list); list_add(list, head); } /** * list_move_tail - delete from one list and add as another's tail * @param list the entry to move * @param head the head that will follow our entry */ static inline void list_move_tail(struct list_head *list, struct list_head *head) { __list_del_entry(list); list_add_tail(list, head); } /** * list_bulk_move_tail - move a subsection of a list to its tail * @param head the head that will follow our entry * @param first the first entry to move * @param last the last entry to move, can be the same as first * * Move all entries between @a first and including @a last before @a head. * All three entries must belong to the same linked list. */ static inline void list_bulk_move_tail(struct list_head *head, struct list_head *first, struct list_head *last) { first->prev->next = last->next; last->next->prev = first->prev; head->prev->next = first; first->prev = head->prev; last->next = head; head->prev = last; } /** * list_is_first -- tests whether @a list is the first entry in list @a head * @param list the entry to test * @param head the head of the list */ static inline int list_is_first(const struct list_head *list, const struct list_head *head) { return list->prev == head; } /** * list_is_last - tests whether @a list is the last entry in list @a head * @param list the entry to test * @param head the head of the list */ static inline int list_is_last(const struct list_head *list, const struct list_head *head) { return list->next == head; } /** * list_is_head - tests whether @a list is the list @a head * @param list the entry to test * @param head the head of the list */ static inline int list_is_head(const struct list_head *list, const struct list_head *head) { return list == head; } /** * list_empty - tests whether a list is empty * @param head the list to test. */ static inline int list_empty(const struct list_head *head) { return head->next == head; } /** * list_del_init_careful - deletes entry from list and reinitialize it. * @param entry the element to delete from the list. * * This is the same as list_del_init(), except designed to be used * together with list_empty_careful() in a way to guarantee ordering * of other memory operations. * * Any memory operations done before a list_del_init_careful() are * guaranteed to be visible after a list_empty_careful() test. */ static inline void list_del_init_careful(struct list_head *entry) { __list_del_entry(entry); entry->prev = entry; entry->next = entry; } /** * list_empty_careful - tests whether a list is empty and not being modified * @param head the list to test * * Description: * tests whether a list is empty _and_ checks that no other CPU might be * in the process of modifying either member (next or prev) * * NOTE: using list_empty_careful() without synchronization * can only be safe if the only activity that can happen * to the list entry is list_del_init(). Eg. it cannot be used * if another CPU could re-list_add() it. */ static inline int list_empty_careful(const struct list_head *head) { struct list_head *next = head->next; return (next == head) && (next == head->prev); } /** * list_rotate_left - rotate the list to the left * @param head the head of the list */ static inline void list_rotate_left(struct list_head *head) { struct list_head *first; if (!list_empty(head)) { first = head->next; list_move_tail(first, head); } } /** * list_rotate_to_front() - Rotate list to specific item. * @param list The desired new front of the list. * @param head The head of the list. * * Rotates list so that @a list becomes the new front of the list. */ static inline void list_rotate_to_front(struct list_head *list, struct list_head *head) { /* * Deletes the list head from the list denoted by @a head and * places it as the tail of @a list, this effectively rotates the * list so that @a list is at the front. */ list_move_tail(head, list); } /** * list_is_singular - tests whether a list has just one entry. * @param head the list to test. */ static inline int list_is_singular(const struct list_head *head) { return !list_empty(head) && (head->next == head->prev); } static inline void __list_cut_position(struct list_head *list, struct list_head *head, struct list_head *entry) { struct list_head *new_first = entry->next; list->next = head->next; list->next->prev = list; list->prev = entry; entry->next = list; head->next = new_first; new_first->prev = head; } /** * list_cut_position - cut a list into two * @param list a new list to add all removed entries * @param head a list with entries * @param entry an entry within head, could be the head itself * and if so we won't cut the list * * This helper moves the initial part of @a head, up to and * including @a entry, from @a head to @a list. You should * pass on @a entry an element you know is on @a head. @a list * should be an empty list or a list you do not care about * losing its data. * */ static inline void list_cut_position(struct list_head *list, struct list_head *head, struct list_head *entry) { if (list_empty(head)) return; if (list_is_singular(head) && !list_is_head(entry, head) && (entry != head->next)) return; if (list_is_head(entry, head)) INIT_LIST_HEAD(list); else __list_cut_position(list, head, entry); } /** * list_cut_before - cut a list into two, before given entry * @param list a new list to add all removed entries * @param head a list with entries * @param entry an entry within head, could be the head itself * * This helper moves the initial part of @a head, up to but * excluding @a entry, from @a head to @a list. You should pass * in @a entry an element you know is on @a head. @a list should * be an empty list or a list you do not care about losing * its data. * If @a entry == @a head, all entries on @a head are moved to * @a list. */ static inline void list_cut_before(struct list_head *list, struct list_head *head, struct list_head *entry) { if (head->next == entry) { INIT_LIST_HEAD(list); return; } list->next = head->next; list->next->prev = list; list->prev = entry->prev; list->prev->next = list; head->next = entry; entry->prev = head; } static inline void __list_splice(const struct list_head *list, struct list_head *prev, struct list_head *next) { struct list_head *first = list->next; struct list_head *last = list->prev; first->prev = prev; prev->next = first; last->next = next; next->prev = last; } /** * list_splice - join two lists, this is designed for stacks * @param list the new list to add. * @param head the place to add it in the first list. */ static inline void list_splice(const struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head, head->next); } /** * list_splice_tail - join two lists, each list being a queue * @param list the new list to add. * @param head the place to add it in the first list. */ static inline void list_splice_tail(struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head->prev, head); } /** * list_splice_init - join two lists and reinitialise the emptied list. * @param list the new list to add. * @param head the place to add it in the first list. * * The list at @a list is reinitialised */ static inline void list_splice_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head, head->next); INIT_LIST_HEAD(list); } } /** * list_splice_tail_init - join two lists and reinitialise the emptied list * @param list the new list to add. * @param head the place to add it in the first list. * * Each of the lists is a queue. * The list at @a list is reinitialised */ static inline void list_splice_tail_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head->prev, head); INIT_LIST_HEAD(list); } } /** * list_entry - get the struct for this entry * @param ptr the &struct list_head pointer. * @param type the type of the struct this is embedded in. * @param member the name of the list_head within the struct. */ #define list_entry(ptr, type, member) \ container_of(ptr, type, member) /** * list_first_entry - get the first element from a list * @param ptr the list head to take the element from. * @param type the type of the struct this is embedded in. * @param member the name of the list_head within the struct. * * Note, that list is expected to be not empty. */ #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) /** * list_last_entry - get the last element from a list * @param ptr the list head to take the element from. * @param type the type of the struct this is embedded in. * @param member the name of the list_head within the struct. * * Note, that list is expected to be not empty. */ #define list_last_entry(ptr, type, member) \ list_entry((ptr)->prev, type, member) /** * list_first_entry_or_null - get the first element from a list * @param ptr the list head to take the element from. * @param type the type of the struct this is embedded in. * @param member the name of the list_head within the struct. * * Note that if the list is empty, it returns NULL. */ #define list_first_entry_or_null(ptr, type, member) ({ \ struct list_head *head__ = (ptr); \ struct list_head *pos__ = head__->next; \ pos__ != head__ ? list_entry(pos__, type, member) : NULL; \ }) /** * list_next_entry - get the next element in list * @param pos the type * to cursor * @param member the name of the list_head within the struct. */ #define list_next_entry(pos, member) \ list_entry((pos)->member.next, typeof(*(pos)), member) /** * list_next_entry_circular - get the next element in list * @param pos the type * to cursor. * @param head the list head to take the element from. * @param member the name of the list_head within the struct. * * Wraparound if pos is the last element (return the first element). * Note, that list is expected to be not empty. */ #define list_next_entry_circular(pos, head, member) \ (list_is_last(&(pos)->member, head) ? \ list_first_entry(head, typeof(*(pos)), member) : list_next_entry(pos, member)) /** * list_prev_entry - get the prev element in list * @param pos the type * to cursor * @param member the name of the list_head within the struct. */ #define list_prev_entry(pos, member) \ list_entry((pos)->member.prev, typeof(*(pos)), member) /** * list_prev_entry_circular - get the prev element in list * @param pos the type * to cursor. * @param head the list head to take the element from. * @param member the name of the list_head within the struct. * * Wraparound if pos is the first element (return the last element). * Note, that list is expected to be not empty. */ #define list_prev_entry_circular(pos, head, member) \ (list_is_first(&(pos)->member, head) ? \ list_last_entry(head, typeof(*(pos)), member) : list_prev_entry(pos, member)) /** * list_for_each - iterate over a list * @param pos the &struct list_head to use as a loop cursor. * @param head the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next) /* Ignore kernel list_for_each_rcu() */ /** * list_for_each_continue - continue iteration over a list * @param pos the &struct list_head to use as a loop cursor. * @param head the head for your list. * * Continue to iterate over a list, continuing after the current position. */ #define list_for_each_continue(pos, head) \ for (pos = pos->next; pos != (head); pos = pos->next) /** * list_for_each_prev - iterate over a list backwards * @param pos the &struct list_head to use as a loop cursor. * @param head the head for your list. */ #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); pos = pos->prev) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @param pos the &struct list_head to use as a loop cursor. * @param n another &struct list_head to use as temporary storage * @param head the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) /** * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry * @param pos the &struct list_head to use as a loop cursor. * @param n another &struct list_head to use as temporary storage * @param head the head for your list. */ #define list_for_each_prev_safe(pos, n, head) \ for (pos = (head)->prev, n = pos->prev; \ pos != (head); \ pos = n, n = pos->prev) /** * list_count_nodes - count nodes in the list * @param head the head for your list. */ static inline size_t list_count_nodes(struct list_head *head) { struct list_head *pos; size_t count = 0; list_for_each(pos, head) count++; return count; } /** * list_entry_is_head - test if the entry points to the head of the list * @param pos the type * to cursor * @param head the head for your list. * @param member the name of the list_head within the struct. */ #define list_entry_is_head(pos, head, member) \ (&pos->member == (head)) /** * list_for_each_entry - iterate over list of given type * @param pos the type * to use as a loop cursor. * @param head the head for your list. * @param member the name of the list_head within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_first_entry(head, typeof(*pos), member); \ !list_entry_is_head(pos, head, member); \ pos = list_next_entry(pos, member)) /** * list_for_each_entry_reverse - iterate backwards over list of given type. * @param pos the type * to use as a loop cursor. * @param head the head for your list. * @param member the name of the list_head within the struct. */ #define list_for_each_entry_reverse(pos, head, member) \ for (pos = list_last_entry(head, typeof(*pos), member); \ !list_entry_is_head(pos, head, member); \ pos = list_prev_entry(pos, member)) /** * list_for_each_entry_direction - iterate forward/backward over list of given type * @param forward the iterate direction, true for forward, false for backward. * @param pos the type * to use as a loop cursor. * @param head the head for your list. * @param member the name of the list_head within the struct. */ #define list_for_each_entry_direction(forward, pos, head, member) \ for (pos = forward ? list_first_entry(head, typeof(*pos), member) \ : list_last_entry(head, typeof(*pos), member); \ !list_entry_is_head(pos, head, member); \ pos = forward ? list_next_entry(pos, member) \ : list_prev_entry(pos, member)) /** * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() * @param pos the type * to use as a start point * @param head the head of the list * @param member the name of the list_head within the struct. * * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). */ #define list_prepare_entry(pos, head, member) \ ((pos) ? (pos) : list_entry(head, typeof(*pos), member)) /** * list_for_each_entry_continue - continue iteration over list of given type * @param pos the type * to use as a loop cursor. * @param head the head for your list. * @param member the name of the list_head within the struct. * * Continue to iterate over list of given type, continuing after * the current position. */ #define list_for_each_entry_continue(pos, head, member) \ for (pos = list_next_entry(pos, member); \ !list_entry_is_head(pos, head, member); \ pos = list_next_entry(pos, member)) /** * list_for_each_entry_continue_reverse - iterate backwards from the given point * @param pos the type * to use as a loop cursor. * @param head the head for your list. * @param member the name of the list_head within the struct. * * Start to iterate over list of given type backwards, continuing after * the current position. */ #define list_for_each_entry_continue_reverse(pos, head, member) \ for (pos = list_prev_entry(pos, member); \ !list_entry_is_head(pos, head, member); \ pos = list_prev_entry(pos, member)) /** * list_for_each_entry_from - iterate over list of given type from the current point * @param pos the type * to use as a loop cursor. * @param head the head for your list. * @param member the name of the list_head within the struct. * * Iterate over list of given type, continuing from current position. */ #define list_for_each_entry_from(pos, head, member) \ for (; !list_entry_is_head(pos, head, member); \ pos = list_next_entry(pos, member)) /** * list_for_each_entry_from_reverse - iterate backwards over list of given type * from the current point * @param pos the type * to use as a loop cursor. * @param head the head for your list. * @param member the name of the list_head within the struct. * * Iterate backwards over list of given type, continuing from current position. */ #define list_for_each_entry_from_reverse(pos, head, member) \ for (; !list_entry_is_head(pos, head, member); \ pos = list_prev_entry(pos, member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @param pos the type * to use as a loop cursor. * @param n another type * to use as temporary storage * @param head the head for your list. * @param member the name of the list_head within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_first_entry(head, typeof(*pos), member), \ n = list_next_entry(pos, member); \ !list_entry_is_head(pos, head, member); \ pos = n, n = list_next_entry(n, member)) /** * list_for_each_entry_safe_continue - continue list iteration safe against removal * @param pos the type * to use as a loop cursor. * @param n another type * to use as temporary storage * @param head the head for your list. * @param member the name of the list_head within the struct. * * Iterate over list of given type, continuing after current point, * safe against removal of list entry. */ #define list_for_each_entry_safe_continue(pos, n, head, member) \ for (pos = list_next_entry(pos, member), \ n = list_next_entry(pos, member); \ !list_entry_is_head(pos, head, member); \ pos = n, n = list_next_entry(n, member)) /** * list_for_each_entry_safe_from - iterate over list from current point safe against removal * @param pos the type * to use as a loop cursor. * @param n another type * to use as temporary storage * @param head the head for your list. * @param member the name of the list_head within the struct. * * Iterate over list of given type from current point, safe against * removal of list entry. */ #define list_for_each_entry_safe_from(pos, n, head, member) \ for (n = list_next_entry(pos, member); \ !list_entry_is_head(pos, head, member); \ pos = n, n = list_next_entry(n, member)) /** * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal * @param pos the type * to use as a loop cursor. * @param n another type * to use as temporary storage * @param head the head for your list. * @param member the name of the list_head within the struct. * * Iterate backwards over list of given type, safe against removal * of list entry. */ #define list_for_each_entry_safe_reverse(pos, n, head, member) \ for (pos = list_last_entry(head, typeof(*pos), member), \ n = list_prev_entry(pos, member); \ !list_entry_is_head(pos, head, member); \ pos = n, n = list_prev_entry(n, member)) /** * list_safe_reset_next - reset a stale list_for_each_entry_safe loop * @param pos the loop cursor used in the list_for_each_entry_safe loop * @param n temporary storage used in list_for_each_entry_safe * @param member the name of the list_head within the struct. * * list_safe_reset_next is not safe to use in general if the list may be * modified concurrently (eg. the lock is dropped in the loop body). An * exception to this is if the cursor element (pos) is pinned in the list, * and list_safe_reset_next is called after re-taking the lock and before * completing the current iteration of the loop body. */ #define list_safe_reset_next(pos, n, member) \ n = list_next_entry(pos, member) /* * Double linked lists with a single pointer list head. * IGNORED */ #endif /* OPENOCD_HELPER_LIST_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/log.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "log.h" #include "command.h" #include "replacements.h" #include "time_support.h" #include <server/gdb_server.h> #include <server/server.h> #include <stdarg.h> #ifdef _DEBUG_FREE_SPACE_ #ifdef HAVE_MALLOC_H #include <malloc.h> #else #error "malloc.h is required to use --enable-malloc-logging" #endif #endif int debug_level = LOG_LVL_INFO; static FILE *log_output; static struct log_callback *log_callbacks; static int64_t last_time; static int64_t start; static const char * const log_strings[6] = { "User : ", "Error: ", "Warn : ", /* want a space after each colon, all same width, colons aligned */ "Info : ", "Debug: ", "Debug: " }; static int count; /* forward the log to the listeners */ static void log_forward(const char *file, unsigned line, const char *function, const char *string) { struct log_callback *cb, *next; cb = log_callbacks; /* DANGER!!!! the log callback can remove itself!!!! */ while (cb) { next = cb->next; cb->fn(cb->priv, file, line, function, string); cb = next; } } /* The log_puts() serves two somewhat different goals: * * - logging * - feeding low-level info to the user in GDB or Telnet * * The latter dictates that strings without newline are not logged, lest there * will be *MANY log lines when sending one char at the time(e.g. * target_request.c). * */ static void log_puts(enum log_levels level, const char *file, int line, const char *function, const char *string) { char *f; if (!log_output) { /* log_init() not called yet; print on stderr */ fputs(string, stderr); fflush(stderr); return; } if (level == LOG_LVL_OUTPUT) { /* do not prepend any headers, just print out what we were given and return */ fputs(string, log_output); fflush(log_output); return; } f = strrchr(file, '/'); if (f) file = f + 1; if (debug_level >= LOG_LVL_DEBUG) { /* print with count and time information */ int64_t t = timeval_ms() - start; #ifdef _DEBUG_FREE_SPACE_ struct mallinfo info; info = mallinfo(); #endif fprintf(log_output, "%s%d %" PRId64 " %s:%d %s()" #ifdef _DEBUG_FREE_SPACE_ " %d" #endif ": %s", log_strings[level + 1], count, t, file, line, function, #ifdef _DEBUG_FREE_SPACE_ info.fordblks, #endif string); } else { /* if we are using gdb through pipes then we do not want any output * to the pipe otherwise we get repeated strings */ fprintf(log_output, "%s%s", (level > LOG_LVL_USER) ? log_strings[level + 1] : "", string); } fflush(log_output); /* Never forward LOG_LVL_DEBUG, too verbose and they can be found in the log if need be */ if (level <= LOG_LVL_INFO) log_forward(file, line, function, string); } void log_printf(enum log_levels level, const char *file, unsigned line, const char *function, const char *format, ...) { char *string; va_list ap; count++; if (level > debug_level) return; va_start(ap, format); string = alloc_vprintf(format, ap); if (string) { log_puts(level, file, line, function, string); free(string); } va_end(ap); } void log_vprintf_lf(enum log_levels level, const char *file, unsigned line, const char *function, const char *format, va_list args) { char *tmp; count++; if (level > debug_level) return; tmp = alloc_vprintf(format, args); if (!tmp) return; /* * Note: alloc_vprintf() guarantees that the buffer is at least one * character longer. */ strcat(tmp, "\n"); log_puts(level, file, line, function, tmp); free(tmp); } void log_printf_lf(enum log_levels level, const char *file, unsigned line, const char *function, const char *format, ...) { va_list ap; va_start(ap, format); log_vprintf_lf(level, file, line, function, format, ap); va_end(ap); } COMMAND_HANDLER(handle_debug_level_command) { if (CMD_ARGC == 1) { int new_level; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], new_level); if ((new_level > LOG_LVL_DEBUG_IO) || (new_level < LOG_LVL_SILENT)) { LOG_ERROR("level must be between %d and %d", LOG_LVL_SILENT, LOG_LVL_DEBUG_IO); return ERROR_COMMAND_SYNTAX_ERROR; } debug_level = new_level; } else if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "debug_level: %i", debug_level); return ERROR_OK; } COMMAND_HANDLER(handle_log_output_command) { if (CMD_ARGC == 0 || (CMD_ARGC == 1 && strcmp(CMD_ARGV[0], "default") == 0)) { if (log_output != stderr && log_output) { /* Close previous log file, if it was open and wasn't stderr. */ fclose(log_output); } log_output = stderr; LOG_DEBUG("set log_output to default"); return ERROR_OK; } if (CMD_ARGC == 1) { FILE *file = fopen(CMD_ARGV[0], "w"); if (!file) { LOG_ERROR("failed to open output log '%s'", CMD_ARGV[0]); return ERROR_FAIL; } if (log_output != stderr && log_output) { /* Close previous log file, if it was open and wasn't stderr. */ fclose(log_output); } log_output = file; LOG_DEBUG("set log_output to \"%s\"", CMD_ARGV[0]); return ERROR_OK; } return ERROR_COMMAND_SYNTAX_ERROR; } static const struct command_registration log_command_handlers[] = { { .name = "log_output", .handler = handle_log_output_command, .mode = COMMAND_ANY, .help = "redirect logging to a file (default: stderr)", .usage = "[file_name | \"default\"]", }, { .name = "debug_level", .handler = handle_debug_level_command, .mode = COMMAND_ANY, .help = "Sets the verbosity level of debugging output. " "0 shows errors only; 1 adds warnings; " "2 (default) adds other info; 3 adds debugging; " "4 adds extra verbose debugging.", .usage = "number", }, COMMAND_REGISTRATION_DONE }; int log_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, log_command_handlers); } void log_init(void) { /* set defaults for daemon configuration, * if not set by cmdline or cfgfile */ char *debug_env = getenv("OPENOCD_DEBUG_LEVEL"); if (debug_env) { int value; int retval = parse_int(debug_env, &value); if (retval == ERROR_OK && debug_level >= LOG_LVL_SILENT && debug_level <= LOG_LVL_DEBUG_IO) debug_level = value; } if (!log_output) log_output = stderr; start = last_time = timeval_ms(); } void log_exit(void) { if (log_output && log_output != stderr) { /* Close log file, if it was open and wasn't stderr. */ fclose(log_output); } log_output = NULL; } /* add/remove log callback handler */ int log_add_callback(log_callback_fn fn, void *priv) { struct log_callback *cb; /* prevent the same callback to be registered more than once, just for sure */ for (cb = log_callbacks; cb; cb = cb->next) { if (cb->fn == fn && cb->priv == priv) return ERROR_COMMAND_SYNTAX_ERROR; } /* alloc memory, it is safe just to return in case of an error, no need for the caller to *check this */ cb = malloc(sizeof(struct log_callback)); if (!cb) return ERROR_BUF_TOO_SMALL; /* add item to the beginning of the linked list */ cb->fn = fn; cb->priv = priv; cb->next = log_callbacks; log_callbacks = cb; return ERROR_OK; } int log_remove_callback(log_callback_fn fn, void *priv) { struct log_callback *cb, **p; for (p = &log_callbacks; (cb = *p); p = &(*p)->next) { if (cb->fn == fn && cb->priv == priv) { *p = cb->next; free(cb); return ERROR_OK; } } /* no such item */ return ERROR_COMMAND_SYNTAX_ERROR; } /* return allocated string w/printf() result */ char *alloc_vprintf(const char *fmt, va_list ap) { va_list ap_copy; int len; char *string; /* determine the length of the buffer needed */ va_copy(ap_copy, ap); len = vsnprintf(NULL, 0, fmt, ap_copy); va_end(ap_copy); /* allocate and make room for terminating zero. */ /* FIXME: The old version always allocated at least one byte extra and * other code depend on that. They should be probably be fixed, but for * now reserve the extra byte. */ string = malloc(len + 2); if (!string) return NULL; /* do the real work */ vsnprintf(string, len + 1, fmt, ap); return string; } char *alloc_printf(const char *format, ...) { char *string; va_list ap; va_start(ap, format); string = alloc_vprintf(format, ap); va_end(ap); return string; } /* Code must return to the server loop before 1000ms has returned or invoke * this function. * * The GDB connection will time out if it spends >2000ms and you'll get nasty * error messages from GDB: * * Ignoring packet error, continuing... * Reply contains invalid hex digit 116 * * While it is possible use "set remotetimeout" to more than the default 2000ms * in GDB, OpenOCD guarantees that it sends keep-alive packages on the * GDB protocol and it is a bug in OpenOCD not to either return to the server * loop or invoke keep_alive() every 1000ms. * * This function will send a keep alive packet if >500ms has passed since last time * it was invoked. * * Note that this function can be invoked often, so it needs to be relatively * fast when invoked more often than every 500ms. * */ #define KEEP_ALIVE_KICK_TIME_MS 500 #define KEEP_ALIVE_TIMEOUT_MS 1000 static void gdb_timeout_warning(int64_t delta_time) { if (gdb_get_actual_connections()) LOG_WARNING("keep_alive() was not invoked in the " "%d ms timelimit. GDB alive packet not " "sent! (%" PRId64 " ms). Workaround: increase " "\"set remotetimeout\" in GDB", KEEP_ALIVE_TIMEOUT_MS, delta_time); else LOG_DEBUG("keep_alive() was not invoked in the " "%d ms timelimit (%" PRId64 " ms). This may cause " "trouble with GDB connections.", KEEP_ALIVE_TIMEOUT_MS, delta_time); } void keep_alive(void) { int64_t current_time = timeval_ms(); int64_t delta_time = current_time - last_time; if (delta_time > KEEP_ALIVE_TIMEOUT_MS) { last_time = current_time; gdb_timeout_warning(delta_time); } if (delta_time > KEEP_ALIVE_KICK_TIME_MS) { last_time = current_time; /* this will keep the GDB connection alive */ server_keep_clients_alive(); /* DANGER!!!! do not add code to invoke e.g. target event processing, * jim timer processing, etc. it can cause infinite recursion + * jim event callbacks need to happen at a well defined time, * not anywhere keep_alive() is invoked. * * These functions should be invoked at a well defined spot in server.c */ } } /* reset keep alive timer without sending message */ void kept_alive(void) { int64_t current_time = timeval_ms(); int64_t delta_time = current_time - last_time; last_time = current_time; if (delta_time > KEEP_ALIVE_TIMEOUT_MS) gdb_timeout_warning(delta_time); } /* if we sleep for extended periods of time, we must invoke keep_alive() intermittently */ void alive_sleep(uint64_t ms) { uint64_t nap_time = 10; for (uint64_t i = 0; i < ms; i += nap_time) { uint64_t sleep_a_bit = ms - i; if (sleep_a_bit > nap_time) sleep_a_bit = nap_time; usleep(sleep_a_bit * 1000); keep_alive(); } } void busy_sleep(uint64_t ms) { uint64_t then = timeval_ms(); while (timeval_ms() - then < ms) { /* * busy wait */ } } /* Maximum size of socket error message retrieved from operation system */ #define MAX_SOCKET_ERR_MSG_LENGTH 256 /* Provide log message for the last socket error. Uses errno on *nix and WSAGetLastError() on Windows */ void log_socket_error(const char *socket_desc) { int error_code; #ifdef _WIN32 error_code = WSAGetLastError(); char error_message[MAX_SOCKET_ERR_MSG_LENGTH]; error_message[0] = '\0'; DWORD retval = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, 0, error_message, MAX_SOCKET_ERR_MSG_LENGTH, NULL); error_message[MAX_SOCKET_ERR_MSG_LENGTH - 1] = '\0'; const bool have_message = (retval != 0) && (error_message[0] != '\0'); LOG_ERROR("Error on socket '%s': WSAGetLastError==%d%s%s.", socket_desc, error_code, (have_message ? ", message: " : ""), (have_message ? error_message : "")); #else error_code = errno; LOG_ERROR("Error on socket '%s': errno==%d, message: %s.", socket_desc, error_code, strerror(error_code)); #endif } /** * Find the first non-printable character in the char buffer, return a pointer to it. * If no such character exists, return NULL. */ char *find_nonprint_char(char *buf, unsigned buf_len) { for (unsigned int i = 0; i < buf_len; i++) { if (!isprint(buf[i])) return buf + i; } return NULL; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/log.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_HELPER_LOG_H #define OPENOCD_HELPER_LOG_H #include <helper/command.h> /* To achieve C99 printf compatibility in MinGW, gnu_printf should be * used for __attribute__((format( ... ))), with GCC v4.4 or later */ #if (defined(IS_MINGW) && (((__GNUC__ << 16) + __GNUC_MINOR__) >= 0x00040004)) #define PRINTF_ATTRIBUTE_FORMAT gnu_printf #else #define PRINTF_ATTRIBUTE_FORMAT printf #endif /* logging priorities * LOG_LVL_SILENT - turn off all output. In lieu of try + catch this can be used as a * feeble ersatz. * LOG_LVL_USER - user messages. Could be anything from information * to progress messages. These messages do not represent * incorrect or unexpected behaviour, just normal execution. * LOG_LVL_ERROR - fatal errors, that are likely to cause program abort * LOG_LVL_WARNING - non-fatal errors, that may be resolved later * LOG_LVL_INFO - state information, etc. * LOG_LVL_DEBUG - debug statements, execution trace * LOG_LVL_DEBUG_IO - verbose debug, low-level I/O trace */ enum log_levels { LOG_LVL_SILENT = -3, LOG_LVL_OUTPUT = -2, LOG_LVL_USER = -1, LOG_LVL_ERROR = 0, LOG_LVL_WARNING = 1, LOG_LVL_INFO = 2, LOG_LVL_DEBUG = 3, LOG_LVL_DEBUG_IO = 4, }; void log_printf(enum log_levels level, const char *file, unsigned line, const char *function, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6))); void log_vprintf_lf(enum log_levels level, const char *file, unsigned line, const char *function, const char *format, va_list args); void log_printf_lf(enum log_levels level, const char *file, unsigned line, const char *function, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6))); /** * Initialize logging module. Call during program startup. */ void log_init(void); void log_exit(void); int log_register_commands(struct command_context *cmd_ctx); void keep_alive(void); void kept_alive(void); void alive_sleep(uint64_t ms); void busy_sleep(uint64_t ms); void log_socket_error(const char *socket_desc); typedef void (*log_callback_fn)(void *priv, const char *file, unsigned line, const char *function, const char *string); struct log_callback { log_callback_fn fn; void *priv; struct log_callback *next; }; int log_add_callback(log_callback_fn fn, void *priv); int log_remove_callback(log_callback_fn fn, void *priv); char *alloc_vprintf(const char *fmt, va_list ap); char *alloc_printf(const char *fmt, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 2))); char *find_nonprint_char(char *buf, unsigned buf_len); extern int debug_level; /* Avoid fn call and building parameter list if we're not outputting the information. * Matters on feeble CPUs for DEBUG/INFO statements that are involved frequently */ #define LOG_LEVEL_IS(FOO) ((debug_level) >= (FOO)) #define LOG_DEBUG_IO(expr ...) \ do { \ if (debug_level >= LOG_LVL_DEBUG_IO) \ log_printf_lf(LOG_LVL_DEBUG, \ __FILE__, __LINE__, __func__, \ expr); \ } while (0) #define LOG_DEBUG(expr ...) \ do { \ if (debug_level >= LOG_LVL_DEBUG) \ log_printf_lf(LOG_LVL_DEBUG, \ __FILE__, __LINE__, __func__, \ expr); \ } while (0) #define LOG_INFO(expr ...) \ log_printf_lf(LOG_LVL_INFO, __FILE__, __LINE__, __func__, expr) #define LOG_WARNING(expr ...) \ log_printf_lf(LOG_LVL_WARNING, __FILE__, __LINE__, __func__, expr) #define LOG_ERROR(expr ...) \ log_printf_lf(LOG_LVL_ERROR, __FILE__, __LINE__, __func__, expr) #define LOG_USER(expr ...) \ log_printf_lf(LOG_LVL_USER, __FILE__, __LINE__, __func__, expr) #define LOG_USER_N(expr ...) \ log_printf(LOG_LVL_USER, __FILE__, __LINE__, __func__, expr) #define LOG_OUTPUT(expr ...) \ log_printf(LOG_LVL_OUTPUT, __FILE__, __LINE__, __func__, expr) /* Output a log entry that is related to a given target */ #define LOG_TARGET_DEBUG_IO(target, fmt_str, ...) \ LOG_DEBUG_IO("[%s] " fmt_str, target_name(target), ##__VA_ARGS__) #define LOG_TARGET_DEBUG(target, fmt_str, ...) \ LOG_DEBUG("[%s] " fmt_str, target_name(target), ##__VA_ARGS__) #define LOG_TARGET_INFO(target, fmt_str, ...) \ LOG_INFO("[%s] " fmt_str, target_name(target), ##__VA_ARGS__) #define LOG_TARGET_WARNING(target, fmt_str, ...) \ LOG_WARNING("[%s] " fmt_str, target_name(target), ##__VA_ARGS__) #define LOG_TARGET_ERROR(target, fmt_str, ...) \ LOG_ERROR("[%s] " fmt_str, target_name(target), ##__VA_ARGS__) /* general failures * error codes < 100 */ #define ERROR_OK (0) #define ERROR_NO_CONFIG_FILE (-2) #define ERROR_BUF_TOO_SMALL (-3) /* see "Error:" log entry for meaningful message to the user. The caller should * make no assumptions about what went wrong and try to handle the problem. */ #define ERROR_FAIL (-4) #define ERROR_WAIT (-5) /* ERROR_TIMEOUT is already taken by winerror.h. */ #define ERROR_TIMEOUT_REACHED (-6) #define ERROR_NOT_IMPLEMENTED (-7) #endif /* OPENOCD_HELPER_LOG_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/nvp.c ================================================ // SPDX-License-Identifier: BSD-2-Clause-Views /* * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org> * Copyright 2005 Clemens Hintze <c.hintze@gmx.net> * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com * Copyright 2008 Andrew Lunn <andrew@lunn.ch> * Copyright 2008 Duane Ellis <openocd@duaneellis.com> * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de> * Copyright 2008 Steve Bennett <steveb@workware.net.au> * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl> * Copyright 2009 Zachary T Welch zw@superlucidity.net * Copyright 2009 David Brownell * Copyright (c) 2005-2011 Jim Tcl Project. All rights reserved. * * This file is extracted from jim_nvp.c, originally part of jim TCL code. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <string.h> #include <helper/command.h> #include <helper/nvp.h> const struct nvp *nvp_name2value(const struct nvp *p, const char *name) { while (p->name) { if (strcmp(name, p->name) == 0) break; p++; } return p; } const struct nvp *nvp_value2name(const struct nvp *p, int value) { while (p->name) { if (value == p->value) break; p++; } return p; } void nvp_unknown_command_print(struct command_invocation *cmd, const struct nvp *nvp, const char *param_name, const char *param_value) { if (param_name) command_print_sameline(cmd, "%s: Unknown: %s, try one of: ", param_name, param_value); else command_print_sameline(cmd, "Unknown param: %s, try one of: ", param_value); while (nvp->name) { if ((nvp + 1)->name) command_print_sameline(cmd, "%s, ", nvp->name); else command_print(cmd, "or %s", nvp->name); nvp++; } /* We assume nvp to be not empty and loop has been taken; no need to add a '\n' */ } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/nvp.h ================================================ /* SPDX-License-Identifier: BSD-2-Clause-Views */ /* * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org> * Copyright 2005 Clemens Hintze <c.hintze@gmx.net> * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com * Copyright 2008 Andrew Lunn <andrew@lunn.ch> * Copyright 2008 Duane Ellis <openocd@duaneellis.com> * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de> * Copyright 2008 Steve Bennett <steveb@workware.net.au> * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl> * Copyright 2009 Zachary T Welch zw@superlucidity.net * Copyright 2009 David Brownell * Copyright (c) 2005-2011 Jim Tcl Project. All rights reserved. * * This file is extracted from jim_nvp.h, originally part of jim TCL code. */ #ifndef OPENOCD_HELPER_NVP_H #define OPENOCD_HELPER_NVP_H #include <helper/compiler.h> /** Name Value Pairs, aka: NVP * - Given a string - return the associated int. * - Given a number - return the associated string. * . * * Very useful when the number is not a simple index into an array of * known string, or there may be multiple strings (aliases) that mean then same * thing. * * An NVP Table is terminated with ".name = NULL". * * During the 'name2value' operation, if no matching string is found * the pointer to the terminal element (with p->name == NULL) is returned. * * Example: * \code * const struct nvp yn[] = { * { "yes", 1 }, * { "no" , 0 }, * { "yep", 1 }, * { "nope", 0 }, * { NULL, -1 }, * }; * * struct nvp *result; * result = nvp_name2value(yn, "yes"); * returns &yn[0]; * result = nvp_name2value(yn, "no"); * returns &yn[1]; * result = jim_nvp_name2value(yn, "Blah"); * returns &yn[4]; * \endcode * * During the number2name operation, the first matching value is returned. */ struct nvp { const char *name; int value; }; struct command_invocation; /* Name Value Pairs Operations */ const struct nvp *nvp_name2value(const struct nvp *nvp_table, const char *name) __returns_nonnull __nonnull((1)); const struct nvp *nvp_value2name(const struct nvp *nvp_table, int v) __returns_nonnull __nonnull((1)); void nvp_unknown_command_print(struct command_invocation *cmd, const struct nvp *nvp, const char *param_name, const char *param_value); #endif /* OPENOCD_HELPER_NVP_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/options.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "configuration.h" #include "log.h" #include "command.h" #include <getopt.h> #include <limits.h> #include <stdlib.h> #include <string.h> #if IS_DARWIN #include <libproc.h> #endif /* sys/sysctl.h is deprecated on Linux from glibc 2.30 */ #ifndef __linux__ #ifdef HAVE_SYS_SYSCTL_H #include <sys/sysctl.h> #endif #endif #if IS_WIN32 && !IS_CYGWIN #include <windows.h> #endif static int help_flag, version_flag; static const struct option long_options[] = { {"help", no_argument, &help_flag, 1}, {"version", no_argument, &version_flag, 1}, {"debug", optional_argument, NULL, 'd'}, {"file", required_argument, NULL, 'f'}, {"search", required_argument, NULL, 's'}, {"log_output", required_argument, NULL, 'l'}, {"command", required_argument, NULL, 'c'}, {NULL, 0, NULL, 0} }; int configuration_output_handler(struct command_context *context, const char *line) { LOG_USER_N("%s", line); return ERROR_OK; } /* Return the canonical path to the directory the openocd executable is in. * The path should be absolute, use / as path separator and have all symlinks * resolved. The returned string is malloc'd. */ static char *find_exe_path(void) { char *exepath = NULL; do { #if IS_WIN32 && !IS_CYGWIN exepath = malloc(MAX_PATH); if (!exepath) break; GetModuleFileName(NULL, exepath, MAX_PATH); /* Convert path separators to UNIX style, should work on Windows also. */ for (char *p = exepath; *p; p++) { if (*p == '\\') *p = '/'; } #elif IS_DARWIN exepath = malloc(PROC_PIDPATHINFO_MAXSIZE); if (!exepath) break; if (proc_pidpath(getpid(), exepath, PROC_PIDPATHINFO_MAXSIZE) <= 0) { free(exepath); exepath = NULL; } #elif defined(CTL_KERN) && defined(KERN_PROC) && defined(KERN_PROC_PATHNAME) /* *BSD */ #ifndef PATH_MAX #define PATH_MAX 1024 #endif char *path = malloc(PATH_MAX); if (!path) break; int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; size_t size = PATH_MAX; if (sysctl(mib, (u_int)ARRAY_SIZE(mib), path, &size, NULL, 0) != 0) break; #ifdef HAVE_REALPATH exepath = realpath(path, NULL); free(path); #else exepath = path; #endif #elif defined(HAVE_REALPATH) /* Assume POSIX.1-2008 */ /* Try Unices in order of likelihood. */ exepath = realpath("/proc/self/exe", NULL); /* Linux/Cygwin */ if (!exepath) exepath = realpath("/proc/self/path/a.out", NULL); /* Solaris */ if (!exepath) exepath = realpath("/proc/curproc/file", NULL); /* FreeBSD (Should be covered above) */ #endif } while (0); if (exepath) { /* Strip executable file name, leaving path */ *strrchr(exepath, '/') = '\0'; } else { LOG_WARNING("Could not determine executable path, using configured BINDIR."); LOG_DEBUG("BINDIR = %s", BINDIR); #ifdef HAVE_REALPATH exepath = realpath(BINDIR, NULL); #else exepath = strdup(BINDIR); #endif } return exepath; } static char *find_relative_path(const char *from, const char *to) { size_t i; /* Skip common /-separated parts of from and to */ i = 0; for (size_t n = 0; from[n] == to[n]; n++) { if (from[n] == '\0') { i = n; break; } if (from[n] == '/') i = n + 1; } from += i; to += i; /* Count number of /-separated non-empty parts of from */ i = 0; while (from[0] != '\0') { if (from[0] != '/') i++; char *next = strchr(from, '/'); if (!next) break; from = next + 1; } /* Prepend that number of ../ in front of to */ char *relpath = malloc(i * 3 + strlen(to) + 1); relpath[0] = '\0'; for (size_t n = 0; n < i; n++) strcat(relpath, "../"); strcat(relpath, to); return relpath; } static void add_user_dirs(void) { char *path; #if IS_WIN32 const char *appdata = getenv("APPDATA"); if (appdata) { path = alloc_printf("%s/OpenOCD", appdata); if (path) { /* Convert path separators to UNIX style, should work on Windows also. */ for (char *p = path; *p; p++) { if (*p == '\\') *p = '/'; } add_script_search_dir(path); free(path); } } /* WIN32 may also have HOME defined, particularly under Cygwin, so add those paths below too */ #endif const char *home = getenv("HOME"); #if IS_DARWIN if (home) { path = alloc_printf("%s/Library/Preferences/org.openocd", home); if (path) { add_script_search_dir(path); free(path); } } #endif const char *xdg_config = getenv("XDG_CONFIG_HOME"); if (xdg_config) { path = alloc_printf("%s/openocd", xdg_config); if (path) { add_script_search_dir(path); free(path); } } else if (home) { path = alloc_printf("%s/.config/openocd", home); if (path) { add_script_search_dir(path); free(path); } } if (home) { path = alloc_printf("%s/.openocd", home); if (path) { add_script_search_dir(path); free(path); } } } static void add_default_dirs(void) { char *path; char *exepath = find_exe_path(); char *bin2data = find_relative_path(BINDIR, PKGDATADIR); LOG_DEBUG("bindir=%s", BINDIR); LOG_DEBUG("pkgdatadir=%s", PKGDATADIR); LOG_DEBUG("exepath=%s", exepath); LOG_DEBUG("bin2data=%s", bin2data); /* * The directory containing OpenOCD-supplied scripts should be * listed last in the built-in search order, so the user can * override these scripts with site-specific customizations. */ path = getenv("OPENOCD_SCRIPTS"); if (path) add_script_search_dir(path); add_user_dirs(); path = alloc_printf("%s/%s/%s", exepath, bin2data, "site"); if (path) { add_script_search_dir(path); free(path); } path = alloc_printf("%s/%s/%s", exepath, bin2data, "scripts"); if (path) { add_script_search_dir(path); free(path); } free(exepath); free(bin2data); } int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[]) { int c; while (1) { /* getopt_long stores the option index here. */ int option_index = 0; c = getopt_long(argc, argv, "hvd::l:f:s:c:", long_options, &option_index); /* Detect the end of the options. */ if (c == -1) break; switch (c) { case 0: break; case 'h': /* --help | -h */ help_flag = 1; break; case 'v': /* --version | -v */ version_flag = 1; break; case 'f': /* --file | -f */ { char *command = alloc_printf("script {%s}", optarg); add_config_command(command); free(command); break; } case 's': /* --search | -s */ add_script_search_dir(optarg); break; case 'd': /* --debug | -d */ { int retval = command_run_linef(cmd_ctx, "debug_level %s", optarg ? optarg : "3"); if (retval != ERROR_OK) return retval; break; } case 'l': /* --log_output | -l */ if (optarg) command_run_linef(cmd_ctx, "log_output %s", optarg); break; case 'c': /* --command | -c */ if (optarg) add_config_command(optarg); break; default: /* '?' */ /* getopt will emit an error message, all we have to do is bail. */ return ERROR_FAIL; } } if (optind < argc) { /* Catch extra arguments on the command line. */ LOG_OUTPUT("Unexpected command line argument: %s\n", argv[optind]); return ERROR_FAIL; } if (help_flag) { LOG_OUTPUT("Open On-Chip Debugger\nLicensed under GNU GPL v2\n"); LOG_OUTPUT("--help | -h\tdisplay this help\n"); LOG_OUTPUT("--version | -v\tdisplay OpenOCD version\n"); LOG_OUTPUT("--file | -f\tuse configuration file <name>\n"); LOG_OUTPUT("--search | -s\tdir to search for config files and scripts\n"); LOG_OUTPUT("--debug | -d\tset debug level to 3\n"); LOG_OUTPUT(" | -d<n>\tset debug level to <level>\n"); LOG_OUTPUT("--log_output | -l\tredirect log output to file <name>\n"); LOG_OUTPUT("--command | -c\trun <command>\n"); exit(-1); } if (version_flag) { /* Nothing to do, version gets printed automatically. */ /* It is not an error to request the VERSION number. */ exit(0); } /* paths specified on the command line take precedence over these * built-in paths */ add_default_dirs(); return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/replacements.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* define IN_REPLACEMENTS_C before include replacements.h */ #define IN_REPLACEMENTS_C #include "replacements.h" #include <stdlib.h> #include <string.h> /* * clear_malloc * * will alloc memory and clear it */ void *clear_malloc(size_t size) { void *t = malloc(size); if (t) memset(t, 0x00, size); return t; } void *fill_malloc(size_t size) { void *t = malloc(size); if (t) { /* We want to initialize memory to some known bad state. * 0 and 0xff yields 0 and -1 as integers, which often * have meaningful values. 0x5555... is not often a valid * integer and is quite easily spotted in the debugger * also it is almost certainly an invalid address */ memset(t, 0x55, size); } return t; } #ifdef HAVE_STRINGS_H #include <strings.h> #endif #ifdef _WIN32 #include <io.h> #include <winsock2.h> #endif /* replacements for gettimeofday */ #ifndef HAVE_GETTIMEOFDAY /* Windows */ #ifdef _WIN32 #ifndef __GNUC__ #define EPOCHFILETIME (116444736000000000i64) #else #define EPOCHFILETIME (116444736000000000LL) #endif int gettimeofday(struct timeval *tv, struct timezone *tz) { FILETIME ft; LARGE_INTEGER li; __int64 t; static int tzflag; if (tv) { GetSystemTimeAsFileTime(&ft); li.LowPart = ft.dwLowDateTime; li.HighPart = ft.dwHighDateTime; t = li.QuadPart; /* In 100-nanosecond intervals */ t -= EPOCHFILETIME; /* Offset to the Epoch time */ t /= 10; /* In microseconds */ tv->tv_sec = (long)(t / 1000000); tv->tv_usec = (long)(t % 1000000); } if (tz) { if (!tzflag) { _tzset(); tzflag++; } tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; } return 0; } #endif /* _WIN32 */ #endif /* HAVE_GETTIMEOFDAY */ #ifndef HAVE_STRNLEN size_t strnlen(const char *s, size_t maxlen) { const char *end = (const char *)memchr(s, '\0', maxlen); return end ? (size_t) (end - s) : maxlen; } #endif #ifndef HAVE_STRNDUP char *strndup(const char *s, size_t n) { size_t len = strnlen(s, n); char *new = malloc(len + 1); if (!new) return NULL; new[len] = '\0'; return (char *) memcpy(new, s, len); } #endif #ifdef _WIN32 int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv) { DWORD ms_total, limit; HANDLE handles[MAXIMUM_WAIT_OBJECTS]; int handle_slot_to_fd[MAXIMUM_WAIT_OBJECTS]; int n_handles = 0, i; fd_set sock_read, sock_write, sock_except; fd_set aread, awrite, aexcept; int sock_max_fd = -1; struct timeval tvslice; int retcode; #define SAFE_FD_ISSET(fd, set) (set && FD_ISSET(fd, set)) /* calculate how long we need to wait in milliseconds */ if (!tv) ms_total = INFINITE; else { ms_total = tv->tv_sec * 1000; ms_total += tv->tv_usec / 1000; } FD_ZERO(&sock_read); FD_ZERO(&sock_write); FD_ZERO(&sock_except); /* build an array of handles for non-sockets */ for (i = 0; i < max_fd; i++) { if (SAFE_FD_ISSET(i, rfds) || SAFE_FD_ISSET(i, wfds) || SAFE_FD_ISSET(i, efds)) { intptr_t handle = (intptr_t) _get_osfhandle(i); handles[n_handles] = (HANDLE)handle; if (handles[n_handles] == INVALID_HANDLE_VALUE) { /* socket */ if (SAFE_FD_ISSET(i, rfds)) FD_SET(i, &sock_read); if (SAFE_FD_ISSET(i, wfds)) FD_SET(i, &sock_write); if (SAFE_FD_ISSET(i, efds)) FD_SET(i, &sock_except); if (i > sock_max_fd) sock_max_fd = i; } else { handle_slot_to_fd[n_handles] = i; n_handles++; } } } if (n_handles == 0) { /* plain sockets only - let winsock handle the whole thing */ return select(max_fd, rfds, wfds, efds, tv); } /* mixture of handles and sockets; lets multiplex between * winsock and waiting on the handles */ FD_ZERO(&aread); FD_ZERO(&awrite); FD_ZERO(&aexcept); limit = GetTickCount() + ms_total; do { retcode = 0; if (sock_max_fd >= 0) { /* overwrite the zero'd sets here; the select call * will clear those that are not active */ aread = sock_read; awrite = sock_write; aexcept = sock_except; tvslice.tv_sec = 0; tvslice.tv_usec = 1000; retcode = select(sock_max_fd + 1, &aread, &awrite, &aexcept, &tvslice); } if (n_handles > 0) { /* check handles */ DWORD wret; wret = MsgWaitForMultipleObjects(n_handles, handles, FALSE, retcode > 0 ? 0 : 1, QS_ALLEVENTS); if (wret == WAIT_TIMEOUT) { /* set retcode to 0; this is the default. * select() may have set it to something else, * in which case we leave it alone, so this branch * does nothing */ ; } else if (wret == WAIT_FAILED) { if (retcode == 0) retcode = -1; } else { if (retcode < 0) retcode = 0; for (i = 0; i < n_handles; i++) { if (WaitForSingleObject(handles[i], 0) == WAIT_OBJECT_0) { if (SAFE_FD_ISSET(handle_slot_to_fd[i], rfds)) { DWORD bytes; intptr_t handle = (intptr_t) _get_osfhandle( handle_slot_to_fd[i]); if (PeekNamedPipe((HANDLE)handle, NULL, 0, NULL, &bytes, NULL)) { /* check to see if gdb pipe has data available */ if (bytes) { FD_SET(handle_slot_to_fd[i], &aread); retcode++; } } else { FD_SET(handle_slot_to_fd[i], &aread); retcode++; } } if (SAFE_FD_ISSET(handle_slot_to_fd[i], wfds)) { FD_SET(handle_slot_to_fd[i], &awrite); retcode++; } if (SAFE_FD_ISSET(handle_slot_to_fd[i], efds)) { FD_SET(handle_slot_to_fd[i], &aexcept); retcode++; } } } } } } while (retcode == 0 && (ms_total == INFINITE || GetTickCount() < limit)); if (rfds) *rfds = aread; if (wfds) *wfds = awrite; if (efds) *efds = aexcept; return retcode; } #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/replacements.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_HELPER_REPLACEMENTS_H #define OPENOCD_HELPER_REPLACEMENTS_H #include <stdint.h> #include <helper/system.h> /* MIN,MAX macros */ #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #ifndef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif /* for systems that do not support ENOTSUP * win32 being one of them */ #ifndef ENOTSUP #define ENOTSUP 134 /* Not supported */ #endif /* for systems that do not support O_BINARY * linux being one of them */ #ifndef O_BINARY #define O_BINARY 0 #endif #ifndef HAVE_SYS_TIME_H #ifndef _TIMEVAL_DEFINED #define _TIMEVAL_DEFINED struct timeval { long tv_sec; long tv_usec; }; #endif /* _TIMEVAL_DEFINED */ #endif /* gettimeofday() */ #ifndef HAVE_GETTIMEOFDAY #ifdef _WIN32 struct timezone { int tz_minuteswest; int tz_dsttime; }; #endif struct timezone; int gettimeofday(struct timeval *tv, struct timezone *tz); #endif void *clear_malloc(size_t size); void *fill_malloc(size_t size); #ifndef IN_REPLACEMENTS_C /* * Now you have 3 ways for the malloc function: * * 1. Do not change anything, use the original malloc * * 2. Use the clear_malloc function instead of the original malloc. * In this case you must use the following define: * #define malloc((_a)) clear_malloc((_a)) * * 3. Use the fill_malloc function instead of the original malloc. * In this case you must use the following define: * #define malloc((_a)) fill_malloc((_a)) * * We have figured out that there could exist some malloc problems * where variables are using without to be initialise. To find this * places, use the fill_malloc function. With this function we want * to initialize memory to some known bad state. This is quite easily * spotted in the debugger and will trap to an invalid address. * * clear_malloc can be used if you want to set not initialise * variable to 0. * * If you do not want to change the malloc function, to not use one of * the following macros. Which is the default way. */ /* #define malloc(_a) clear_malloc(_a) * #define malloc(_a) fill_malloc(_a) */ #endif /* IN_REPLACEMENTS_C */ /* GNU extensions to the C library that may be missing on some systems */ #ifndef HAVE_STRNDUP char *strndup(const char *s, size_t n); #endif /* HAVE_STRNDUP */ #ifndef HAVE_STRNLEN size_t strnlen(const char *s, size_t maxlen); #endif /* HAVE_STRNLEN */ #ifndef HAVE_USLEEP #ifdef _WIN32 static inline unsigned usleep(unsigned int usecs) { Sleep((usecs/1000)); return 0; } #else #error no usleep defined for your platform #endif #endif /* HAVE_USLEEP */ /* Windows specific */ #ifdef _WIN32 #include <windows.h> #include <time.h> /* Windows does not declare sockaddr_un */ #define UNIX_PATH_LEN 108 struct sockaddr_un { uint16_t sun_family; char sun_path[UNIX_PATH_LEN]; }; /* win32 systems do not support ETIMEDOUT */ #ifndef ETIMEDOUT #define ETIMEDOUT WSAETIMEDOUT #endif #if IS_MINGW == 1 static inline unsigned char inb(unsigned short int port) { unsigned char _v; __asm__ __volatile__ ("inb %w1,%0" : "=a" (_v) : "Nd" (port)); return _v; } static inline void outb(unsigned char value, unsigned short int port) { __asm__ __volatile__ ("outb %b0,%w1" : : "a" (value), "Nd" (port)); } /* mingw does not have ffs, so use gcc builtin types */ #define ffs __builtin_ffs #endif /* IS_MINGW */ int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv); #endif /* _WIN32 */ /* generic socket functions for Windows and Posix */ static inline int write_socket(int handle, const void *buffer, unsigned int count) { #ifdef _WIN32 return send(handle, buffer, count, 0); #else return write(handle, buffer, count); #endif } static inline int read_socket(int handle, void *buffer, unsigned int count) { #ifdef _WIN32 return recv(handle, buffer, count, 0); #else return read(handle, buffer, count); #endif } static inline int close_socket(int sock) { #ifdef _WIN32 return closesocket(sock); #else return close(sock); #endif } static inline void socket_block(int fd) { #ifdef _WIN32 unsigned long nonblock = 0; ioctlsocket(fd, FIONBIO, &nonblock); #else int oldopts = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, oldopts & ~O_NONBLOCK); #endif } static inline void socket_nonblock(int fd) { #ifdef _WIN32 unsigned long nonblock = 1; ioctlsocket(fd, FIONBIO, &nonblock); #else int oldopts = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, oldopts | O_NONBLOCK); #endif } static inline int socket_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv) { #ifdef _WIN32 return win_select(max_fd, rfds, wfds, efds, tv); #else return select(max_fd, rfds, wfds, efds, tv); #endif } #ifndef HAVE_ELF_H typedef uint32_t Elf32_Addr; typedef uint16_t Elf32_Half; typedef uint32_t Elf32_Off; typedef uint32_t Elf32_Word; typedef uint32_t Elf32_Size; #define EI_NIDENT 16 typedef struct { unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf32_Half e_type; /* Object file type */ Elf32_Half e_machine; /* Architecture */ Elf32_Word e_version; /* Object file version */ Elf32_Addr e_entry; /* Entry point virtual address */ Elf32_Off e_phoff; /* Program header table file offset */ Elf32_Off e_shoff; /* Section header table file offset */ Elf32_Word e_flags; /* Processor-specific flags */ Elf32_Half e_ehsize; /* ELF header size in bytes */ Elf32_Half e_phentsize; /* Program header table entry size */ Elf32_Half e_phnum; /* Program header table entry count */ Elf32_Half e_shentsize; /* Section header table entry size */ Elf32_Half e_shnum; /* Section header table entry count */ Elf32_Half e_shstrndx; /* Section header string table index */ } Elf32_Ehdr; #define ELFMAG "\177ELF" #define SELFMAG 4 #define EI_CLASS 4 /* File class byte index */ #define ELFCLASS32 1 /* 32-bit objects */ #define ELFCLASS64 2 /* 64-bit objects */ #define EI_DATA 5 /* Data encoding byte index */ #define ELFDATA2LSB 1 /* 2's complement, little endian */ #define ELFDATA2MSB 2 /* 2's complement, big endian */ typedef struct { Elf32_Word p_type; /* Segment type */ Elf32_Off p_offset; /* Segment file offset */ Elf32_Addr p_vaddr; /* Segment virtual address */ Elf32_Addr p_paddr; /* Segment physical address */ Elf32_Size p_filesz; /* Segment size in file */ Elf32_Size p_memsz; /* Segment size in memory */ Elf32_Word p_flags; /* Segment flags */ Elf32_Size p_align; /* Segment alignment */ } Elf32_Phdr; #define PT_LOAD 1 /* Loadable program segment */ #endif /* HAVE_ELF_H */ #ifndef HAVE_ELF64 typedef uint64_t Elf64_Addr; typedef uint16_t Elf64_Half; typedef uint64_t Elf64_Off; typedef uint32_t Elf64_Word; typedef uint64_t Elf64_Xword; typedef struct { unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf64_Half e_type; /* Object file type */ Elf64_Half e_machine; /* Architecture */ Elf64_Word e_version; /* Object file version */ Elf64_Addr e_entry; /* Entry point virtual address */ Elf64_Off e_phoff; /* Program header table file offset */ Elf64_Off e_shoff; /* Section header table file offset */ Elf64_Word e_flags; /* Processor-specific flags */ Elf64_Half e_ehsize; /* ELF header size in bytes */ Elf64_Half e_phentsize; /* Program header table entry size */ Elf64_Half e_phnum; /* Program header table entry count */ Elf64_Half e_shentsize; /* Section header table entry size */ Elf64_Half e_shnum; /* Section header table entry count */ Elf64_Half e_shstrndx; /* Section header string table index */ } Elf64_Ehdr; typedef struct { Elf64_Word p_type; /* Segment type */ Elf64_Word p_flags; /* Segment flags */ Elf64_Off p_offset; /* Segment file offset */ Elf64_Addr p_vaddr; /* Segment virtual address */ Elf64_Addr p_paddr; /* Segment physical address */ Elf64_Xword p_filesz; /* Segment size in file */ Elf64_Xword p_memsz; /* Segment size in memory */ Elf64_Xword p_align; /* Segment alignment */ } Elf64_Phdr; #endif /* HAVE_ELF64 */ #endif /* OPENOCD_HELPER_REPLACEMENTS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/startup.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Defines basic Tcl procs that must exist for OpenOCD scripts to work. # # Embedded into OpenOCD executable # # Try flipping / and \ to find file if the filename does not # match the precise spelling proc find {filename} { if {[catch {ocd_find $filename} t]==0} { return $t } if {[catch {ocd_find [string map {\ /} $filename} t]==0} { return $t } if {[catch {ocd_find [string map {/ \\} $filename} t]==0} { return $t } # make sure error message matches original input string return -code error "Can't find $filename" } add_usage_text find "<file>" add_help_text find "print full path to file according to OpenOCD search rules" # Find and run a script proc script {filename} { uplevel #0 [list source [find $filename]] } add_help_text script "filename of OpenOCD script (tcl) to run" add_usage_text script "<file>" # Run a list of post-init commands # Each command should be added with 'lappend post_init_commands command' lappend _telnet_autocomplete_skip _run_post_init_commands proc _run_post_init_commands {} { if {[info exists ::post_init_commands]} { foreach cmd $::post_init_commands { eval $cmd } } } # Run a list of pre-shutdown commands # Each command should be added with 'lappend pre_shutdown_commands command' lappend _telnet_autocomplete_skip _run_pre_shutdown_commands proc _run_pre_shutdown_commands {} { if {[info exists ::pre_shutdown_commands]} { foreach cmd $::pre_shutdown_commands { eval $cmd } } } ######### ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/system.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2006 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007-2008 by Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifndef OPENOCD_HELPER_SYSTEM_H #define OPENOCD_HELPER_SYSTEM_H /* +++ platform specific headers +++ */ #ifdef _WIN32 #include <winsock2.h> #include <ws2tcpip.h> #include <sys/types.h> #include <sys/stat.h> #endif /* --- platform specific headers --- */ /* standard C library header files */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <ctype.h> #include <errno.h> #include <time.h> #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif #ifdef HAVE_POLL_H #include <poll.h> #endif #ifdef __ECOS /* missing from eCos */ #ifndef EFAULT #define EFAULT 14 /* Bad address */ #endif #endif #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif #ifdef HAVE_SYS_SELECT_H #include <sys/select.h> /* select, FD_SET and friends (POSIX.1-2001) */ #endif #ifdef HAVE_SYS_PARAM_H #include <sys/param.h> /* for MIN/MAX macros */ #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif #ifndef true #define true 1 #define false 0 #endif #endif /* OPENOCD_HELPER_SYSTEM_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/time_support.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "time_support.h" /* calculate difference between two struct timeval values */ int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) { if (x->tv_usec < y->tv_usec) { int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; y->tv_usec -= 1000000 * nsec; y->tv_sec += nsec; } if (x->tv_usec - y->tv_usec > 1000000) { int nsec = (x->tv_usec - y->tv_usec) / 1000000; y->tv_usec += 1000000 * nsec; y->tv_sec -= nsec; } result->tv_sec = x->tv_sec - y->tv_sec; result->tv_usec = x->tv_usec - y->tv_usec; /* Return 1 if result is negative. */ return x->tv_sec < y->tv_sec; } int timeval_add_time(struct timeval *result, long sec, long usec) { result->tv_sec += sec; result->tv_usec += usec; while (result->tv_usec > 1000000) { result->tv_usec -= 1000000; result->tv_sec++; } return 0; } /* compare two timevals and return -1/0/+1 accordingly */ int timeval_compare(const struct timeval *x, const struct timeval *y) { if (x->tv_sec < y->tv_sec) return -1; else if (x->tv_sec > y->tv_sec) return 1; else if (x->tv_usec < y->tv_usec) return -1; else if (x->tv_usec > y->tv_usec) return 1; else return 0; } int duration_start(struct duration *duration) { return gettimeofday(&duration->start, NULL); } int duration_measure(struct duration *duration) { struct timeval end; int retval = gettimeofday(&end, NULL); if (retval == 0) timeval_subtract(&duration->elapsed, &end, &duration->start); return retval; } float duration_elapsed(const struct duration *duration) { float t = duration->elapsed.tv_sec; t += (float)duration->elapsed.tv_usec / 1000000.0; return t; } float duration_kbps(const struct duration *duration, size_t count) { return count / (1024.0 * duration_elapsed(duration)); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/time_support.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_HELPER_TIME_SUPPORT_H #define OPENOCD_HELPER_TIME_SUPPORT_H #include <time.h> #include "types.h" #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y); int timeval_add_time(struct timeval *result, long sec, long usec); int timeval_compare(const struct timeval *x, const struct timeval *y); /** @returns gettimeofday() timeval as 64-bit in ms */ int64_t timeval_ms(void); struct duration { struct timeval start; struct timeval elapsed; }; /** Update the duration->start field to start the @a duration measurement. */ int duration_start(struct duration *duration); /** Update the duration->elapsed field to finish the @a duration measurement. */ int duration_measure(struct duration *duration); /** @returns Elapsed time in seconds. */ float duration_elapsed(const struct duration *duration); /** @returns KB/sec for the elapsed @a duration and @a count bytes. */ float duration_kbps(const struct duration *duration, size_t count); #endif /* OPENOCD_HELPER_TIME_SUPPORT_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/time_support_common.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "time_support.h" /* simple and low overhead fetching of ms counter. Use only * the difference between ms counters returned from this fn. */ int64_t timeval_ms(void) { struct timeval now; int retval = gettimeofday(&now, NULL); if (retval < 0) return retval; return (int64_t)now.tv_sec * 1000 + now.tv_usec / 1000; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/types.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifndef OPENOCD_HELPER_TYPES_H #define OPENOCD_HELPER_TYPES_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stddef.h> #include <assert.h> #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif #ifdef HAVE_STDINT_H #include <stdint.h> #endif #ifdef HAVE_INTTYPES_H #include <inttypes.h> #endif #ifdef HAVE_STDBOOL_H #include <stdbool.h> #else /* HAVE_STDBOOL_H */ #define __bool_true_false_are_defined 1 #ifndef HAVE__BOOL #ifndef __cplusplus #define false 0 #define true 1 #endif /* __cplusplus */ #endif /* HAVE__BOOL */ #endif /* HAVE_STDBOOL_H */ /// turns a macro argument into a string constant #define stringify(s) __stringify(s) #define __stringify(s) #s /** * Compute the number of elements of a variable length array. * <code> * const char *strs[] = { "a", "b", "c" }; * unsigned num_strs = ARRAY_SIZE(strs); * </code> */ #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) /** * Cast a member of a structure out to the containing structure. * @param ptr The pointer to the member. * @param type The type of the container struct this is embedded in. * @param member The name of the member within the struct. * * This is a mechanism which is used throughout the Linux kernel. */ #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (void *) ( (char *)__mptr - offsetof(type,member) ) );}) /** * Rounds @c m up to the nearest multiple of @c n using division. * @param m The value to round up to @c n. * @param n Round @c m up to a multiple of this number. * @returns The rounded integer value. */ #define DIV_ROUND_UP(m, n) (((m) + (n) - 1) / (n)) /* DANGER!!!! here be dragons! * * Leave these fn's as byte accesses because it is safe * across architectures. Clever usage of 32 bit access * will create problems on some hosts. * * Note that the "buf" pointer in memory is probably unaligned. * * Were these functions to be re-written to take a 32 bit wide or 16 bit wide * memory access shortcut, then on some CPU's, i.e. ARM7, the 2 lsbytes of the address are * ignored for 32 bit access, whereas on other CPU's a 32 bit wide unaligned memory access * will cause an exception, and lastly on x86, an unaligned "greater than bytewide" * memory access works as if aligned. So what follows below will work for all * platforms and gives the compiler leeway to do its own platform specific optimizations. * * Again, note that the "buf" pointer in memory is probably unaligned. */ static inline uint64_t le_to_h_u64(const uint8_t *buf) { return (uint64_t)((uint64_t)buf[0] | (uint64_t)buf[1] << 8 | (uint64_t)buf[2] << 16 | (uint64_t)buf[3] << 24 | (uint64_t)buf[4] << 32 | (uint64_t)buf[5] << 40 | (uint64_t)buf[6] << 48 | (uint64_t)buf[7] << 56); } static inline uint32_t le_to_h_u32(const uint8_t *buf) { return (uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16 | (uint32_t)buf[3] << 24); } static inline uint32_t le_to_h_u24(const uint8_t *buf) { return (uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16); } static inline uint16_t le_to_h_u16(const uint8_t *buf) { return (uint16_t)((uint16_t)buf[0] | (uint16_t)buf[1] << 8); } static inline uint64_t be_to_h_u64(const uint8_t *buf) { return (uint64_t)((uint64_t)buf[7] | (uint64_t)buf[6] << 8 | (uint64_t)buf[5] << 16 | (uint64_t)buf[4] << 24 | (uint64_t)buf[3] << 32 | (uint64_t)buf[2] << 40 | (uint64_t)buf[1] << 48 | (uint64_t)buf[0] << 56); } static inline uint32_t be_to_h_u32(const uint8_t *buf) { return (uint32_t)((uint32_t)buf[3] | (uint32_t)buf[2] << 8 | (uint32_t)buf[1] << 16 | (uint32_t)buf[0] << 24); } static inline uint32_t be_to_h_u24(const uint8_t *buf) { return (uint32_t)((uint32_t)buf[2] | (uint32_t)buf[1] << 8 | (uint32_t)buf[0] << 16); } static inline uint16_t be_to_h_u16(const uint8_t *buf) { return (uint16_t)((uint16_t)buf[1] | (uint16_t)buf[0] << 8); } static inline void h_u64_to_le(uint8_t *buf, uint64_t val) { buf[7] = (uint8_t) (val >> 56); buf[6] = (uint8_t) (val >> 48); buf[5] = (uint8_t) (val >> 40); buf[4] = (uint8_t) (val >> 32); buf[3] = (uint8_t) (val >> 24); buf[2] = (uint8_t) (val >> 16); buf[1] = (uint8_t) (val >> 8); buf[0] = (uint8_t) (val >> 0); } static inline void h_u64_to_be(uint8_t *buf, uint64_t val) { buf[0] = (uint8_t) (val >> 56); buf[1] = (uint8_t) (val >> 48); buf[2] = (uint8_t) (val >> 40); buf[3] = (uint8_t) (val >> 32); buf[4] = (uint8_t) (val >> 24); buf[5] = (uint8_t) (val >> 16); buf[6] = (uint8_t) (val >> 8); buf[7] = (uint8_t) (val >> 0); } static inline void h_u32_to_le(uint8_t *buf, uint32_t val) { buf[3] = (val >> 24) & 0xff; buf[2] = (val >> 16) & 0xff; buf[1] = (val >> 8) & 0xff; buf[0] = (val >> 0) & 0xff; } static inline void h_u32_to_be(uint8_t *buf, uint32_t val) { buf[0] = (val >> 24) & 0xff; buf[1] = (val >> 16) & 0xff; buf[2] = (val >> 8) & 0xff; buf[3] = (val >> 0) & 0xff; } static inline void h_u24_to_le(uint8_t *buf, unsigned int val) { buf[2] = (val >> 16) & 0xff; buf[1] = (val >> 8) & 0xff; buf[0] = (val >> 0) & 0xff; } static inline void h_u24_to_be(uint8_t *buf, unsigned int val) { buf[0] = (val >> 16) & 0xff; buf[1] = (val >> 8) & 0xff; buf[2] = (val >> 0) & 0xff; } static inline void h_u16_to_le(uint8_t *buf, uint16_t val) { buf[1] = (val >> 8) & 0xff; buf[0] = (val >> 0) & 0xff; } static inline void h_u16_to_be(uint8_t *buf, uint16_t val) { buf[0] = (val >> 8) & 0xff; buf[1] = (val >> 0) & 0xff; } /** * Byte-swap buffer 16-bit. * * Len must be even, dst and src must be either the same or non-overlapping. * * @param dst Destination buffer. * @param src Source buffer. * @param len Length of source (and destination) buffer, in bytes. */ static inline void buf_bswap16(uint8_t *dst, const uint8_t *src, size_t len) { assert(len % 2 == 0); assert(dst == src || dst + len <= src || src + len <= dst); for (size_t n = 0; n < len; n += 2) { uint16_t x = be_to_h_u16(src + n); h_u16_to_le(dst + n, x); } } /** * Byte-swap buffer 32-bit. * * Len must be divisible by four, dst and src must be either the same or non-overlapping. * * @param dst Destination buffer. * @param src Source buffer. * @param len Length of source (and destination) buffer, in bytes. */ static inline void buf_bswap32(uint8_t *dst, const uint8_t *src, size_t len) { assert(len % 4 == 0); assert(dst == src || dst + len <= src || src + len <= dst); for (size_t n = 0; n < len; n += 4) { uint32_t x = be_to_h_u32(src + n); h_u32_to_le(dst + n, x); } } /** * Calculate the (even) parity of a 32-bit datum. * @param x The datum. * @return 1 if the number of set bits in x is odd, 0 if it is even. */ static inline int parity_u32(uint32_t x) { #ifdef __GNUC__ return __builtin_parityl(x); #else x ^= x >> 16; x ^= x >> 8; x ^= x >> 4; x ^= x >> 2; x ^= x >> 1; return x & 1; #endif } #if defined(__ECOS) /* eCos plain lacks these definition... A series of upstream patches * could probably repair it, but it seems like too much work to be * worth it. */ #if !defined(_STDINT_H) #define PRId32 "d" #define PRIi32 "i" #define PRIo32 "o" #define PRIu32 "u" #define PRIx32 "x" #define PRIX32 "X" #define SCNx32 "x" #define PRId8 PRId32 #define SCNx64 "llx" #define PRId64 "lld" #define PRIi64 "lli" #define PRIo64 "llo" #define PRIu64 "llu" #define PRIx64 "llx" #define PRIX64 "llX" typedef CYG_ADDRWORD intptr_t; typedef int64_t intmax_t; typedef uint64_t uintmax_t; #define INT8_MAX 0x7f #define INT8_MIN (-INT8_MAX - 1) # define UINT8_MAX (255) #define INT16_MAX 0x7fff #define INT16_MIN (-INT16_MAX - 1) # define UINT16_MAX (65535) #define INT32_MAX 0x7fffffffL #define INT32_MIN (-INT32_MAX - 1L) # define UINT32_MAX (4294967295U) #define INT64_MAX 0x7fffffffffffffffLL #define INT64_MIN (-INT64_MAX - 1LL) #define UINT64_MAX (__CONCAT(INT64_MAX, U) * 2ULL + 1ULL) #endif #ifndef LLONG_MAX #define ULLONG_MAX UINT64_C(0xFFFFFFFFFFFFFFFF) #define LLONG_MAX INT64_C(0x7FFFFFFFFFFFFFFF) #define LLONG_MIN ULLONG_MAX #endif #define ULLONG_MAX 18446744073709551615 /* C99, eCos is C90 compliant (with bits of C99) */ #define isblank(c) ((c) == ' ' || (c) == '\t') #endif typedef uint64_t target_addr_t; #define TARGET_ADDR_MAX UINT64_MAX #define TARGET_PRIdADDR PRId64 #define TARGET_PRIuADDR PRIu64 #define TARGET_PRIoADDR PRIo64 #define TARGET_PRIxADDR PRIx64 #define TARGET_PRIXADDR PRIX64 #define TARGET_ADDR_FMT "0x%8.8" TARGET_PRIxADDR #endif /* OPENOCD_HELPER_TYPES_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/update_jep106.pl ================================================ #!/usr/bin/perl # SPDX-License-Identifier: GPL-2.0-or-later use strict; use warnings; use File::Basename; if (@ARGV != 1) { die "Usage: $0 <JEP106 PDF document>\n\n" . "Convert the JEDEC document containing manufacturer identification codes\n" . "to an array initializer suitable for inclusion into jep106.c. The latest\n" . "version of the document can be found here:\n" . "http://www.jedec.org/standards-documents/results/jep106\n"; }; my $outfile = dirname($0) . "/jep106.inc"; open(my $out, ">", $outfile) || die "Cannot open $outfile: $!\n"; open(my $pdftotext, "pdftotext -layout $ARGV[0] - |") || die "Cannot fork: $!\n"; print $out "/* Autogenerated with " . basename($0) . "*/\n"; my $bank = -1; while (<$pdftotext>) { if (/^[0-9]+[[:space:]]+(.*?)[[:space:]]+([01][[:space:]]+){8}([0-9A-F]{2})$/) { if ($3 eq "01") { $bank++ } my $id=sprintf("0x%02x",hex($3)&0x7f); print $out "[$bank][$id - 1] = \"$1\",\n"; } } close $pdftotext || die "Error: $! $?\n"; print $out "/* EOF */\n"; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/util.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2010 by Øyvind Harboe * ***************************************************************************/ /* this file contains various functionality useful to standalone systems */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "log.h" #include "time_support.h" #include "util.h" COMMAND_HANDLER(handler_util_ms) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "%" PRId64, timeval_ms()); return ERROR_OK; } static const struct command_registration util_command_handlers[] = { { .name = "ms", .mode = COMMAND_ANY, .handler = handler_util_ms, .help = "Returns ever increasing milliseconds. Used to calculate differences in time.", .usage = "", }, COMMAND_REGISTRATION_DONE }; int util_init(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, util_command_handlers); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/helper/util.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2010 by Øyvind Harboe * ***************************************************************************/ #ifndef OPENOCD_HELPER_UTIL_H #define OPENOCD_HELPER_UTIL_H struct command_context; int util_init(struct command_context *cmd_ctx); #endif /* OPENOCD_HELPER_UTIL_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libjtag.la %C%_libjtag_la_LIBADD = if HLADAPTER include %D%/hla/Makefile.am %C%_libjtag_la_LIBADD += $(top_builddir)/%D%/hla/libocdhla.la endif include %D%/drivers/Makefile.am %C%_libjtag_la_LIBADD += $(top_builddir)/%D%/drivers/libocdjtagdrivers.la %C%_libjtag_la_SOURCES = \ %D%/adapter.c \ %D%/adapter.h \ %D%/commands.c \ %D%/core.c \ %D%/interface.c \ %D%/interfaces.c \ %D%/tcl.c \ %D%/swim.c \ %D%/commands.h \ %D%/interface.h \ %D%/interfaces.h \ %D%/minidriver.h \ %D%/jtag.h \ %D%/swd.h \ %D%/swim.h \ %D%/tcl.h STARTUP_TCL_SRCS += %D%/startup.tcl ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/adapter.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * Copyright (C) 2007-2010 Øyvind Harboe <oyvind.harboe@zylin.com> * Copyright (C) 2009 SoftPLC Corporation, http://softplc.com, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * Copyright (C) 2018 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "adapter.h" #include "jtag.h" #include "minidriver.h" #include "interface.h" #include "interfaces.h" #include <transport/transport.h> /** * @file * Holds support for configuring debug adapters from TCl scripts. */ struct adapter_driver *adapter_driver; const char * const jtag_only[] = { "jtag", NULL }; enum adapter_clk_mode { CLOCK_MODE_UNSELECTED = 0, CLOCK_MODE_KHZ, CLOCK_MODE_RCLK }; #define DEFAULT_CLOCK_SPEED_KHZ 100U /** * Adapter configuration */ static struct { bool adapter_initialized; char *usb_location; char *serial; enum adapter_clk_mode clock_mode; int speed_khz; int rclk_fallback_speed_khz; struct adapter_gpio_config gpios[ADAPTER_GPIO_IDX_NUM]; bool gpios_initialized; /* Initialization of GPIOs to their unset values performed at run time */ } adapter_config; static const struct gpio_map { const char *name; enum adapter_gpio_direction direction; bool permit_drive_option; bool permit_init_state_option; } gpio_map[ADAPTER_GPIO_IDX_NUM] = { [ADAPTER_GPIO_IDX_TDO] = { "tdo", ADAPTER_GPIO_DIRECTION_INPUT, false, true, }, [ADAPTER_GPIO_IDX_TDI] = { "tdi", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, [ADAPTER_GPIO_IDX_TMS] = { "tms", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, [ADAPTER_GPIO_IDX_TCK] = { "tck", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, [ADAPTER_GPIO_IDX_SWDIO] = { "swdio", ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL, true, true, }, [ADAPTER_GPIO_IDX_SWDIO_DIR] = { "swdio_dir", ADAPTER_GPIO_DIRECTION_OUTPUT, true, false, }, [ADAPTER_GPIO_IDX_SWCLK] = { "swclk", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, [ADAPTER_GPIO_IDX_TRST] = { "trst", ADAPTER_GPIO_DIRECTION_OUTPUT, false, true, }, [ADAPTER_GPIO_IDX_SRST] = { "srst", ADAPTER_GPIO_DIRECTION_OUTPUT, false, true, }, [ADAPTER_GPIO_IDX_LED] = { "led", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, }; bool is_adapter_initialized(void) { return adapter_config.adapter_initialized; } /* For convenience of the bit-banging drivers keep the gpio_config drive * settings for srst and trst in sync with values set by the "adapter * reset_config" command. */ static void sync_adapter_reset_with_gpios(void) { enum reset_types cfg = jtag_get_reset_config(); if (cfg & RESET_SRST_PUSH_PULL) adapter_config.gpios[ADAPTER_GPIO_IDX_SRST].drive = ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL; else adapter_config.gpios[ADAPTER_GPIO_IDX_SRST].drive = ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN; if (cfg & RESET_TRST_OPEN_DRAIN) adapter_config.gpios[ADAPTER_GPIO_IDX_TRST].drive = ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN; else adapter_config.gpios[ADAPTER_GPIO_IDX_TRST].drive = ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL; } static void adapter_driver_gpios_init(void) { if (adapter_config.gpios_initialized) return; for (int i = 0; i < ADAPTER_GPIO_IDX_NUM; ++i) { adapter_config.gpios[i].gpio_num = -1; adapter_config.gpios[i].chip_num = -1; if (gpio_map[i].direction == ADAPTER_GPIO_DIRECTION_INPUT) adapter_config.gpios[i].init_state = ADAPTER_GPIO_INIT_STATE_INPUT; } /* Drivers assume active low, and this is the normal behaviour for reset * lines so should be the default. */ adapter_config.gpios[ADAPTER_GPIO_IDX_SRST].active_low = true; adapter_config.gpios[ADAPTER_GPIO_IDX_TRST].active_low = true; sync_adapter_reset_with_gpios(); /* JTAG GPIOs should be inactive except for tms */ adapter_config.gpios[ADAPTER_GPIO_IDX_TMS].init_state = ADAPTER_GPIO_INIT_STATE_ACTIVE; adapter_config.gpios_initialized = true; } /** * Do low-level setup like initializing registers, output signals, * and clocking. */ int adapter_init(struct command_context *cmd_ctx) { if (is_adapter_initialized()) return ERROR_OK; if (!adapter_driver) { /* nothing was previously specified by "adapter driver" command */ LOG_ERROR("Debug Adapter has to be specified, " "see \"adapter driver\" command"); return ERROR_JTAG_INVALID_INTERFACE; } adapter_driver_gpios_init(); int retval; /* If the adapter supports configurable speed but the speed is not configured, * provide a hint to the user. */ if (adapter_driver->speed && adapter_config.clock_mode == CLOCK_MODE_UNSELECTED) { LOG_WARNING("An adapter speed is not selected in the init scripts." " OpenOCD will try to run the adapter at very low speed (%d kHz).", DEFAULT_CLOCK_SPEED_KHZ); LOG_WARNING("To remove this warnings and achieve reasonable communication speed with the target," " set \"adapter speed\" or \"jtag_rclk\" in the init scripts."); retval = adapter_config_khz(DEFAULT_CLOCK_SPEED_KHZ); if (retval != ERROR_OK) return ERROR_JTAG_INIT_FAILED; } retval = adapter_driver->init(); if (retval != ERROR_OK) return retval; adapter_config.adapter_initialized = true; if (!adapter_driver->speed) { LOG_INFO("Note: The adapter \"%s\" doesn't support configurable speed", adapter_driver->name); return ERROR_OK; } int requested_khz = adapter_get_speed_khz(); int actual_khz = requested_khz; int speed_var = 0; retval = adapter_get_speed(&speed_var); if (retval != ERROR_OK) return retval; retval = adapter_driver->speed(speed_var); if (retval != ERROR_OK) return retval; retval = adapter_get_speed_readable(&actual_khz); if (retval != ERROR_OK) LOG_INFO("adapter-specific clock speed value %d", speed_var); else if (actual_khz) { /* Adaptive clocking -- JTAG-specific */ if ((adapter_config.clock_mode == CLOCK_MODE_RCLK) || ((adapter_config.clock_mode == CLOCK_MODE_KHZ) && !requested_khz)) { LOG_INFO("RCLK (adaptive clock speed) not supported - fallback to %d kHz" , actual_khz); } else LOG_INFO("clock speed %d kHz", actual_khz); } else LOG_INFO("RCLK (adaptive clock speed)"); return ERROR_OK; } int adapter_quit(void) { if (is_adapter_initialized() && adapter_driver->quit) { /* close the JTAG interface */ int result = adapter_driver->quit(); if (result != ERROR_OK) LOG_ERROR("failed: %d", result); } free(adapter_config.serial); free(adapter_config.usb_location); struct jtag_tap *t = jtag_all_taps(); while (t) { struct jtag_tap *n = t->next_tap; jtag_tap_free(t); t = n; } return ERROR_OK; } unsigned int adapter_get_speed_khz(void) { return adapter_config.speed_khz; } static int adapter_khz_to_speed(unsigned int khz, int *speed) { LOG_DEBUG("convert khz to adapter specific speed value"); adapter_config.speed_khz = khz; if (!is_adapter_initialized()) return ERROR_OK; LOG_DEBUG("have adapter set up"); if (!adapter_driver->khz) { LOG_ERROR("Translation from khz to adapter speed not implemented"); return ERROR_FAIL; } int speed_div1; int retval = adapter_driver->khz(adapter_get_speed_khz(), &speed_div1); if (retval != ERROR_OK) return retval; *speed = speed_div1; return ERROR_OK; } static int adapter_rclk_to_speed(unsigned int fallback_speed_khz, int *speed) { int retval = adapter_khz_to_speed(0, speed); if ((retval != ERROR_OK) && fallback_speed_khz) { LOG_DEBUG("trying fallback speed..."); retval = adapter_khz_to_speed(fallback_speed_khz, speed); } return retval; } static int adapter_set_speed(int speed) { /* this command can be called during CONFIG, * in which case adapter isn't initialized */ return is_adapter_initialized() ? adapter_driver->speed(speed) : ERROR_OK; } int adapter_config_khz(unsigned int khz) { LOG_DEBUG("handle adapter khz"); adapter_config.clock_mode = CLOCK_MODE_KHZ; int speed = 0; int retval = adapter_khz_to_speed(khz, &speed); return (retval != ERROR_OK) ? retval : adapter_set_speed(speed); } int adapter_config_rclk(unsigned int fallback_speed_khz) { LOG_DEBUG("handle adapter rclk"); adapter_config.clock_mode = CLOCK_MODE_RCLK; adapter_config.rclk_fallback_speed_khz = fallback_speed_khz; int speed = 0; int retval = adapter_rclk_to_speed(fallback_speed_khz, &speed); return (retval != ERROR_OK) ? retval : adapter_set_speed(speed); } int adapter_get_speed(int *speed) { switch (adapter_config.clock_mode) { case CLOCK_MODE_KHZ: adapter_khz_to_speed(adapter_get_speed_khz(), speed); break; case CLOCK_MODE_RCLK: adapter_rclk_to_speed(adapter_config.rclk_fallback_speed_khz, speed); break; default: LOG_ERROR("BUG: unknown adapter clock mode"); return ERROR_FAIL; } return ERROR_OK; } int adapter_get_speed_readable(int *khz) { int speed_var = 0; int retval = adapter_get_speed(&speed_var); if (retval != ERROR_OK) return retval; if (!is_adapter_initialized()) return ERROR_OK; if (!adapter_driver->speed_div) { LOG_ERROR("Translation from adapter speed to khz not implemented"); return ERROR_FAIL; } return adapter_driver->speed_div(speed_var, khz); } const char *adapter_get_required_serial(void) { return adapter_config.serial; } /* * 1 char: bus * 2 * 7 chars: max 7 ports * 1 char: test for overflow * ------ * 16 chars */ #define USB_MAX_LOCATION_LENGTH 16 #ifdef HAVE_LIBUSB_GET_PORT_NUMBERS static void adapter_usb_set_location(const char *location) { if (strnlen(location, USB_MAX_LOCATION_LENGTH) == USB_MAX_LOCATION_LENGTH) LOG_WARNING("usb location string is too long!!"); free(adapter_config.usb_location); adapter_config.usb_location = strndup(location, USB_MAX_LOCATION_LENGTH); } #endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */ const char *adapter_usb_get_location(void) { return adapter_config.usb_location; } bool adapter_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, size_t path_len) { size_t path_step, string_length; char *ptr, *loc; bool equal = false; if (!adapter_usb_get_location()) return equal; /* strtok need non const char */ loc = strndup(adapter_usb_get_location(), USB_MAX_LOCATION_LENGTH); string_length = strnlen(loc, USB_MAX_LOCATION_LENGTH); ptr = strtok(loc, "-"); if (!ptr) { LOG_WARNING("no '-' in usb path\n"); goto done; } string_length -= strnlen(ptr, string_length); /* check bus mismatch */ if (atoi(ptr) != dev_bus) goto done; path_step = 0; while (path_step < path_len) { ptr = strtok(NULL, "."); /* no more tokens in path */ if (!ptr) break; /* path mismatch at some step */ if (path_step < path_len && atoi(ptr) != port_path[path_step]) break; path_step++; string_length -= strnlen(ptr, string_length) + 1; }; /* walked the full path, all elements match */ if (path_step == path_len && !string_length) equal = true; done: free(loc); return equal; } COMMAND_HANDLER(handle_adapter_name) { /* return the name of the interface */ /* TCL code might need to know the exact type... */ /* FUTURE: we allow this as a means to "set" the interface. */ if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "%s", adapter_driver ? adapter_driver->name : "undefined"); return ERROR_OK; } COMMAND_HANDLER(adapter_transports_command) { char **transports; int retval; retval = CALL_COMMAND_HANDLER(transport_list_parse, &transports); if (retval != ERROR_OK) return retval; retval = allow_transports(CMD_CTX, (const char **)transports); if (retval != ERROR_OK) { for (unsigned i = 0; transports[i]; i++) free(transports[i]); free(transports); } return retval; } COMMAND_HANDLER(handle_adapter_list_command) { if (strcmp(CMD_NAME, "list") == 0 && CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "The following debug adapters are available:"); for (unsigned i = 0; adapter_drivers[i]; i++) { const char *name = adapter_drivers[i]->name; command_print(CMD, "%u: %s", i + 1, name); } return ERROR_OK; } COMMAND_HANDLER(handle_adapter_driver_command) { int retval; /* check whether the interface is already configured */ if (adapter_driver) { LOG_WARNING("Interface already configured, ignoring"); return ERROR_OK; } /* interface name is a mandatory argument */ if (CMD_ARGC != 1 || CMD_ARGV[0][0] == '\0') return ERROR_COMMAND_SYNTAX_ERROR; for (unsigned i = 0; adapter_drivers[i]; i++) { if (strcmp(CMD_ARGV[0], adapter_drivers[i]->name) != 0) continue; if (adapter_drivers[i]->commands) { retval = register_commands(CMD_CTX, NULL, adapter_drivers[i]->commands); if (retval != ERROR_OK) return retval; } adapter_driver = adapter_drivers[i]; return allow_transports(CMD_CTX, adapter_driver->transports); } /* no valid interface was found (i.e. the configuration option, * didn't match one of the compiled-in interfaces */ LOG_ERROR("The specified debug interface was not found (%s)", CMD_ARGV[0]); CALL_COMMAND_HANDLER(handle_adapter_list_command); return ERROR_JTAG_INVALID_INTERFACE; } COMMAND_HANDLER(handle_reset_config_command) { int new_cfg = 0; int mask = 0; /* Original versions cared about the order of these tokens: * reset_config signals [combination [trst_type [srst_type]]] * They also clobbered the previous configuration even on error. * * Here we don't care about the order, and only change values * which have been explicitly specified. */ for (; CMD_ARGC; CMD_ARGC--, CMD_ARGV++) { int tmp = 0; int m; /* gating */ m = RESET_SRST_NO_GATING; if (strcmp(*CMD_ARGV, "srst_gates_jtag") == 0) /* default: don't use JTAG while SRST asserted */; else if (strcmp(*CMD_ARGV, "srst_nogate") == 0) tmp = RESET_SRST_NO_GATING; else m = 0; if (mask & m) { LOG_ERROR("extra reset_config %s spec (%s)", "gating", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; } if (m) goto next; /* signals */ m = RESET_HAS_TRST | RESET_HAS_SRST; if (strcmp(*CMD_ARGV, "none") == 0) tmp = RESET_NONE; else if (strcmp(*CMD_ARGV, "trst_only") == 0) tmp = RESET_HAS_TRST; else if (strcmp(*CMD_ARGV, "srst_only") == 0) tmp = RESET_HAS_SRST; else if (strcmp(*CMD_ARGV, "trst_and_srst") == 0) tmp = RESET_HAS_TRST | RESET_HAS_SRST; else m = 0; if (mask & m) { LOG_ERROR("extra reset_config %s spec (%s)", "signal", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; } if (m) goto next; /* combination (options for broken wiring) */ m = RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST; if (strcmp(*CMD_ARGV, "separate") == 0) /* separate reset lines - default */; else if (strcmp(*CMD_ARGV, "srst_pulls_trst") == 0) tmp |= RESET_SRST_PULLS_TRST; else if (strcmp(*CMD_ARGV, "trst_pulls_srst") == 0) tmp |= RESET_TRST_PULLS_SRST; else if (strcmp(*CMD_ARGV, "combined") == 0) tmp |= RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST; else m = 0; if (mask & m) { LOG_ERROR("extra reset_config %s spec (%s)", "combination", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; } if (m) goto next; /* trst_type (NOP without HAS_TRST) */ m = RESET_TRST_OPEN_DRAIN; if (strcmp(*CMD_ARGV, "trst_open_drain") == 0) tmp |= RESET_TRST_OPEN_DRAIN; else if (strcmp(*CMD_ARGV, "trst_push_pull") == 0) /* push/pull from adapter - default */; else m = 0; if (mask & m) { LOG_ERROR("extra reset_config %s spec (%s)", "trst_type", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; } if (m) goto next; /* srst_type (NOP without HAS_SRST) */ m = RESET_SRST_PUSH_PULL; if (strcmp(*CMD_ARGV, "srst_push_pull") == 0) tmp |= RESET_SRST_PUSH_PULL; else if (strcmp(*CMD_ARGV, "srst_open_drain") == 0) /* open drain from adapter - default */; else m = 0; if (mask & m) { LOG_ERROR("extra reset_config %s spec (%s)", "srst_type", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; } if (m) goto next; /* connect_type - only valid when srst_nogate */ m = RESET_CNCT_UNDER_SRST; if (strcmp(*CMD_ARGV, "connect_assert_srst") == 0) tmp |= RESET_CNCT_UNDER_SRST; else if (strcmp(*CMD_ARGV, "connect_deassert_srst") == 0) /* connect normally - default */; else m = 0; if (mask & m) { LOG_ERROR("extra reset_config %s spec (%s)", "connect_type", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; } if (m) goto next; /* caller provided nonsense; fail */ LOG_ERROR("unknown reset_config flag (%s)", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; next: /* Remember the bits which were specified (mask) * and their new values (new_cfg). */ mask |= m; new_cfg |= tmp; } /* clear previous values of those bits, save new values */ if (mask) { int old_cfg = jtag_get_reset_config(); old_cfg &= ~mask; new_cfg |= old_cfg; jtag_set_reset_config(new_cfg); sync_adapter_reset_with_gpios(); } else new_cfg = jtag_get_reset_config(); /* * Display the (now-)current reset mode */ char *modes[6]; /* minimal JTAG has neither SRST nor TRST (so that's the default) */ switch (new_cfg & (RESET_HAS_TRST | RESET_HAS_SRST)) { case RESET_HAS_SRST: modes[0] = "srst_only"; break; case RESET_HAS_TRST: modes[0] = "trst_only"; break; case RESET_TRST_AND_SRST: modes[0] = "trst_and_srst"; break; default: modes[0] = "none"; break; } /* normally SRST and TRST are decoupled; but bugs happen ... */ switch (new_cfg & (RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST)) { case RESET_SRST_PULLS_TRST: modes[1] = "srst_pulls_trst"; break; case RESET_TRST_PULLS_SRST: modes[1] = "trst_pulls_srst"; break; case RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST: modes[1] = "combined"; break; default: modes[1] = "separate"; break; } /* TRST-less connectors include Altera, Xilinx, and minimal JTAG */ if (new_cfg & RESET_HAS_TRST) { if (new_cfg & RESET_TRST_OPEN_DRAIN) modes[3] = " trst_open_drain"; else modes[3] = " trst_push_pull"; } else modes[3] = ""; /* SRST-less connectors include TI-14, Xilinx, and minimal JTAG */ if (new_cfg & RESET_HAS_SRST) { if (new_cfg & RESET_SRST_NO_GATING) modes[2] = " srst_nogate"; else modes[2] = " srst_gates_jtag"; if (new_cfg & RESET_SRST_PUSH_PULL) modes[4] = " srst_push_pull"; else modes[4] = " srst_open_drain"; if (new_cfg & RESET_CNCT_UNDER_SRST) modes[5] = " connect_assert_srst"; else modes[5] = " connect_deassert_srst"; } else { modes[2] = ""; modes[4] = ""; modes[5] = ""; } command_print(CMD, "%s %s%s%s%s%s", modes[0], modes[1], modes[2], modes[3], modes[4], modes[5]); return ERROR_OK; } COMMAND_HANDLER(handle_adapter_srst_delay_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { unsigned delay; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], delay); jtag_set_nsrst_delay(delay); } command_print(CMD, "adapter srst delay: %u", jtag_get_nsrst_delay()); return ERROR_OK; } COMMAND_HANDLER(handle_adapter_srst_pulse_width_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { unsigned width; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], width); jtag_set_nsrst_assert_width(width); } command_print(CMD, "adapter srst pulse_width: %u", jtag_get_nsrst_assert_width()); return ERROR_OK; } COMMAND_HANDLER(handle_adapter_speed_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; int retval = ERROR_OK; if (CMD_ARGC == 1) { unsigned khz = 0; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], khz); retval = adapter_config_khz(khz); if (retval != ERROR_OK) return retval; } int cur_speed = adapter_get_speed_khz(); retval = adapter_get_speed_readable(&cur_speed); if (retval != ERROR_OK) return retval; if (cur_speed) command_print(CMD, "adapter speed: %d kHz", cur_speed); else command_print(CMD, "adapter speed: RCLK - adaptive"); return retval; } COMMAND_HANDLER(handle_adapter_serial_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; free(adapter_config.serial); adapter_config.serial = strdup(CMD_ARGV[0]); return ERROR_OK; } COMMAND_HANDLER(handle_adapter_reset_de_assert) { enum values { VALUE_UNDEFINED = -1, VALUE_DEASSERT = 0, VALUE_ASSERT = 1, }; enum values value; enum values srst = VALUE_UNDEFINED; enum values trst = VALUE_UNDEFINED; enum reset_types jtag_reset_config = jtag_get_reset_config(); char *signal; if (CMD_ARGC == 0) { if (transport_is_jtag()) { if (jtag_reset_config & RESET_HAS_TRST) signal = jtag_get_trst() ? "asserted" : "deasserted"; else signal = "not present"; command_print(CMD, "trst %s", signal); } if (jtag_reset_config & RESET_HAS_SRST) signal = jtag_get_srst() ? "asserted" : "deasserted"; else signal = "not present"; command_print(CMD, "srst %s", signal); return ERROR_OK; } if (CMD_ARGC != 1 && CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; value = (strcmp(CMD_NAME, "assert") == 0) ? VALUE_ASSERT : VALUE_DEASSERT; if (strcmp(CMD_ARGV[0], "srst") == 0) srst = value; else if (strcmp(CMD_ARGV[0], "trst") == 0) trst = value; else return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 3) { if (strcmp(CMD_ARGV[1], "assert") == 0) value = VALUE_ASSERT; else if (strcmp(CMD_ARGV[1], "deassert") == 0) value = VALUE_DEASSERT; else return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[2], "srst") == 0 && srst == VALUE_UNDEFINED) srst = value; else if (strcmp(CMD_ARGV[2], "trst") == 0 && trst == VALUE_UNDEFINED) trst = value; else return ERROR_COMMAND_SYNTAX_ERROR; } if (trst == VALUE_UNDEFINED) { if (transport_is_jtag()) trst = jtag_get_trst() ? VALUE_ASSERT : VALUE_DEASSERT; else trst = VALUE_DEASSERT; /* unused, safe value */ } if (srst == VALUE_UNDEFINED) { if (jtag_reset_config & RESET_HAS_SRST) srst = jtag_get_srst() ? VALUE_ASSERT : VALUE_DEASSERT; else srst = VALUE_DEASSERT; /* unused, safe value */ } if (trst == VALUE_ASSERT && !transport_is_jtag()) { LOG_ERROR("transport has no trst signal"); return ERROR_FAIL; } if (srst == VALUE_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) { LOG_ERROR("adapter has no srst signal"); return ERROR_FAIL; } return adapter_resets((trst == VALUE_DEASSERT) ? TRST_DEASSERT : TRST_ASSERT, (srst == VALUE_DEASSERT) ? SRST_DEASSERT : SRST_ASSERT); } static int get_gpio_index(const char *signal_name) { for (int i = 0; i < ADAPTER_GPIO_IDX_NUM; ++i) { if (strcmp(gpio_map[i].name, signal_name) == 0) return i; } return -1; } static COMMAND_HELPER(helper_adapter_gpio_print_config, enum adapter_gpio_config_index gpio_idx) { struct adapter_gpio_config *gpio_config = &adapter_config.gpios[gpio_idx]; const char *active_state = gpio_config->active_low ? "low" : "high"; const char *dir = ""; const char *drive = ""; const char *pull = ""; const char *init_state = ""; switch (gpio_map[gpio_idx].direction) { case ADAPTER_GPIO_DIRECTION_INPUT: dir = "input"; break; case ADAPTER_GPIO_DIRECTION_OUTPUT: dir = "output"; break; case ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL: dir = "bidirectional"; break; } if (gpio_map[gpio_idx].permit_drive_option) { switch (gpio_config->drive) { case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL: drive = ", push-pull"; break; case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN: drive = ", open-drain"; break; case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE: drive = ", open-source"; break; } } switch (gpio_config->pull) { case ADAPTER_GPIO_PULL_NONE: pull = ", pull-none"; break; case ADAPTER_GPIO_PULL_UP: pull = ", pull-up"; break; case ADAPTER_GPIO_PULL_DOWN: pull = ", pull-down"; break; } if (gpio_map[gpio_idx].permit_init_state_option) { switch (gpio_config->init_state) { case ADAPTER_GPIO_INIT_STATE_INACTIVE: init_state = ", init-state inactive"; break; case ADAPTER_GPIO_INIT_STATE_ACTIVE: init_state = ", init-state active"; break; case ADAPTER_GPIO_INIT_STATE_INPUT: init_state = ", init-state input"; break; } } command_print(CMD, "adapter gpio %s (%s): num %d, chip %d, active-%s%s%s%s", gpio_map[gpio_idx].name, dir, gpio_config->gpio_num, gpio_config->chip_num, active_state, drive, pull, init_state); return ERROR_OK; } COMMAND_HANDLER(helper_adapter_gpio_print_all_configs) { for (int i = 0; i < ADAPTER_GPIO_IDX_NUM; ++i) CALL_COMMAND_HANDLER(helper_adapter_gpio_print_config, i); return ERROR_OK; } COMMAND_HANDLER(adapter_gpio_config_handler) { unsigned int i = 1; struct adapter_gpio_config *gpio_config; adapter_driver_gpios_init(); if (CMD_ARGC == 0) { CALL_COMMAND_HANDLER(helper_adapter_gpio_print_all_configs); return ERROR_OK; } int gpio_idx = get_gpio_index(CMD_ARGV[0]); if (gpio_idx == -1) { LOG_ERROR("adapter has no gpio named %s", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; } if (CMD_ARGC == 1) { CALL_COMMAND_HANDLER(helper_adapter_gpio_print_config, gpio_idx); return ERROR_OK; } gpio_config = &adapter_config.gpios[gpio_idx]; while (i < CMD_ARGC) { LOG_DEBUG("Processing %s", CMD_ARGV[i]); if (isdigit(*CMD_ARGV[i])) { int gpio_num; /* Use a meaningful output parameter for more helpful error messages */ COMMAND_PARSE_NUMBER(int, CMD_ARGV[i], gpio_num); gpio_config->gpio_num = gpio_num; ++i; continue; } if (strcmp(CMD_ARGV[i], "-chip") == 0) { if (CMD_ARGC - i < 2) { LOG_ERROR("-chip option requires a parameter"); return ERROR_FAIL; } LOG_DEBUG("-chip arg is %s", CMD_ARGV[i + 1]); int chip_num; /* Use a meaningful output parameter for more helpful error messages */ COMMAND_PARSE_NUMBER(int, CMD_ARGV[i + 1], chip_num); gpio_config->chip_num = chip_num; i += 2; continue; } if (strcmp(CMD_ARGV[i], "-active-high") == 0) { ++i; gpio_config->active_low = false; continue; } if (strcmp(CMD_ARGV[i], "-active-low") == 0) { ++i; gpio_config->active_low = true; continue; } if (gpio_map[gpio_idx].permit_drive_option) { if (strcmp(CMD_ARGV[i], "-push-pull") == 0) { ++i; gpio_config->drive = ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL; continue; } if (strcmp(CMD_ARGV[i], "-open-drain") == 0) { ++i; gpio_config->drive = ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN; continue; } if (strcmp(CMD_ARGV[i], "-open-source") == 0) { ++i; gpio_config->drive = ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE; continue; } } if (strcmp(CMD_ARGV[i], "-pull-none") == 0) { ++i; gpio_config->pull = ADAPTER_GPIO_PULL_NONE; continue; } if (strcmp(CMD_ARGV[i], "-pull-up") == 0) { ++i; gpio_config->pull = ADAPTER_GPIO_PULL_UP; continue; } if (strcmp(CMD_ARGV[i], "-pull-down") == 0) { ++i; gpio_config->pull = ADAPTER_GPIO_PULL_DOWN; continue; } if (gpio_map[gpio_idx].permit_init_state_option) { if (strcmp(CMD_ARGV[i], "-init-inactive") == 0) { ++i; gpio_config->init_state = ADAPTER_GPIO_INIT_STATE_INACTIVE; continue; } if (strcmp(CMD_ARGV[i], "-init-active") == 0) { ++i; gpio_config->init_state = ADAPTER_GPIO_INIT_STATE_ACTIVE; continue; } if (gpio_map[gpio_idx].direction == ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL && strcmp(CMD_ARGV[i], "-init-input") == 0) { ++i; gpio_config->init_state = ADAPTER_GPIO_INIT_STATE_INPUT; continue; } } LOG_ERROR("illegal option for adapter %s %s: %s", CMD_NAME, gpio_map[gpio_idx].name, CMD_ARGV[i]); return ERROR_COMMAND_SYNTAX_ERROR; } /* Force swdio_dir init state to be compatible with swdio init state */ if (gpio_idx == ADAPTER_GPIO_IDX_SWDIO) adapter_config.gpios[ADAPTER_GPIO_IDX_SWDIO_DIR].init_state = (gpio_config->init_state == ADAPTER_GPIO_INIT_STATE_INPUT) ? ADAPTER_GPIO_INIT_STATE_INACTIVE : ADAPTER_GPIO_INIT_STATE_ACTIVE; return ERROR_OK; } #ifdef HAVE_LIBUSB_GET_PORT_NUMBERS COMMAND_HANDLER(handle_usb_location_command) { if (CMD_ARGC == 1) adapter_usb_set_location(CMD_ARGV[0]); command_print(CMD, "adapter usb location: %s", adapter_usb_get_location()); return ERROR_OK; } #endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */ static const struct command_registration adapter_usb_command_handlers[] = { #ifdef HAVE_LIBUSB_GET_PORT_NUMBERS { .name = "location", .handler = &handle_usb_location_command, .mode = COMMAND_CONFIG, .help = "display or set the USB bus location of the USB device", .usage = "[<bus>-port[.port]...]", }, #endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */ COMMAND_REGISTRATION_DONE }; static const struct command_registration adapter_srst_command_handlers[] = { { .name = "delay", .handler = handle_adapter_srst_delay_command, .mode = COMMAND_ANY, .help = "delay after deasserting SRST in ms", .usage = "[milliseconds]", }, { .name = "pulse_width", .handler = handle_adapter_srst_pulse_width_command, .mode = COMMAND_ANY, .help = "SRST assertion pulse width in ms", .usage = "[milliseconds]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration adapter_command_handlers[] = { { .name = "driver", .handler = handle_adapter_driver_command, .mode = COMMAND_CONFIG, .help = "Select a debug adapter driver", .usage = "driver_name", }, { .name = "speed", .handler = handle_adapter_speed_command, .mode = COMMAND_ANY, .help = "With an argument, change to the specified maximum " "jtag speed. For JTAG, 0 KHz signifies adaptive " "clocking. " "With or without argument, display current setting.", .usage = "[khz]", }, { .name = "serial", .handler = handle_adapter_serial_command, .mode = COMMAND_CONFIG, .help = "Set the serial number of the adapter", .usage = "serial_string", }, { .name = "list", .handler = handle_adapter_list_command, .mode = COMMAND_ANY, .help = "List all built-in debug adapter drivers", .usage = "", }, { .name = "name", .mode = COMMAND_ANY, .handler = handle_adapter_name, .help = "Returns the name of the currently " "selected adapter (driver)", .usage = "", }, { .name = "srst", .mode = COMMAND_ANY, .help = "srst adapter command group", .usage = "", .chain = adapter_srst_command_handlers, }, { .name = "transports", .handler = adapter_transports_command, .mode = COMMAND_CONFIG, .help = "Declare transports the adapter supports.", .usage = "transport ...", }, { .name = "usb", .mode = COMMAND_ANY, .help = "usb adapter command group", .usage = "", .chain = adapter_usb_command_handlers, }, { .name = "assert", .handler = handle_adapter_reset_de_assert, .mode = COMMAND_EXEC, .help = "Controls SRST and TRST lines.", .usage = "|deassert [srst|trst [assert|deassert srst|trst]]", }, { .name = "deassert", .handler = handle_adapter_reset_de_assert, .mode = COMMAND_EXEC, .help = "Controls SRST and TRST lines.", .usage = "|assert [srst|trst [deassert|assert srst|trst]]", }, { .name = "gpio", .handler = adapter_gpio_config_handler, .mode = COMMAND_CONFIG, .help = "gpio adapter command group", .usage = "[ tdo|tdi|tms|tck|trst|swdio|swdio_dir|swclk|srst|led" "[gpio_number] " "[-chip chip_number] " "[-active-high|-active-low] " "[-push-pull|-open-drain|-open-source] " "[-pull-none|-pull-up|-pull-down]" "[-init-inactive|-init-active|-init-input] ]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration interface_command_handlers[] = { { .name = "adapter", .mode = COMMAND_ANY, .help = "adapter command group", .usage = "", .chain = adapter_command_handlers, }, { .name = "reset_config", .handler = handle_reset_config_command, .mode = COMMAND_ANY, .help = "configure adapter reset behavior", .usage = "[none|trst_only|srst_only|trst_and_srst] " "[srst_pulls_trst|trst_pulls_srst|combined|separate] " "[srst_gates_jtag|srst_nogate] " "[trst_push_pull|trst_open_drain] " "[srst_push_pull|srst_open_drain] " "[connect_deassert_srst|connect_assert_srst]", }, COMMAND_REGISTRATION_DONE }; /** * Register the commands which deal with arbitrary debug adapter drivers. * * @todo Remove internal assumptions that all debug adapters use JTAG for * transport. Various types and data structures are not named generically. */ int adapter_register_commands(struct command_context *ctx) { return register_commands(ctx, NULL, interface_command_handlers); } const char *adapter_gpio_get_name(enum adapter_gpio_config_index idx) { return gpio_map[idx].name; } /* Allow drivers access to the GPIO configuration */ const struct adapter_gpio_config *adapter_gpio_get_config(void) { return adapter_config.gpios; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/adapter.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * Copyright (c) 2018 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> */ #ifndef OPENOCD_JTAG_ADAPTER_H #define OPENOCD_JTAG_ADAPTER_H #include <stdbool.h> #include <stddef.h> #include <stdint.h> /** Supported output drive modes for adaptor GPIO */ enum adapter_gpio_drive_mode { ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL, ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN, ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE, }; /** Supported GPIO directions */ enum adapter_gpio_direction { ADAPTER_GPIO_DIRECTION_INPUT, ADAPTER_GPIO_DIRECTION_OUTPUT, ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL, }; /** Supported initial states for GPIO */ enum adapter_gpio_init_state { ADAPTER_GPIO_INIT_STATE_INACTIVE, /* Should be zero so it is the default state */ ADAPTER_GPIO_INIT_STATE_ACTIVE, ADAPTER_GPIO_INIT_STATE_INPUT, }; /** Supported pull directions for GPIO */ enum adapter_gpio_pull { ADAPTER_GPIO_PULL_NONE, ADAPTER_GPIO_PULL_UP, ADAPTER_GPIO_PULL_DOWN, }; /** Adapter GPIO */ enum adapter_gpio_config_index { ADAPTER_GPIO_IDX_TDO, ADAPTER_GPIO_IDX_TDI, ADAPTER_GPIO_IDX_TMS, ADAPTER_GPIO_IDX_TCK, ADAPTER_GPIO_IDX_TRST, ADAPTER_GPIO_IDX_SWDIO, ADAPTER_GPIO_IDX_SWDIO_DIR, ADAPTER_GPIO_IDX_SWCLK, ADAPTER_GPIO_IDX_SRST, ADAPTER_GPIO_IDX_LED, ADAPTER_GPIO_IDX_NUM, /* must be the last item */ }; /** Configuration options for a single GPIO */ struct adapter_gpio_config { int gpio_num; int chip_num; enum adapter_gpio_drive_mode drive; /* For outputs only */ enum adapter_gpio_init_state init_state; bool active_low; enum adapter_gpio_pull pull; }; struct command_context; /** Register the adapter's commands */ int adapter_register_commands(struct command_context *ctx); /** Initialize debug adapter upon startup. */ int adapter_init(struct command_context *cmd_ctx); /** Shutdown the debug adapter upon program exit. */ int adapter_quit(void); /** @returns true if adapter has been initialized */ bool is_adapter_initialized(void); /** @returns USB location string set with command 'adapter usb location' */ const char *adapter_usb_get_location(void); /** @returns true if USB location string is "<dev_bus>-<port_path[0]>[.<port_path[1]>[...]]" */ bool adapter_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, size_t path_len); /** @returns The current adapter speed setting. */ int adapter_get_speed(int *speed); /** * Given a @a speed setting, use the interface @c speed_div callback to * adjust the setting. * @param speed The speed setting to convert back to readable kHz. * @returns ERROR_OK if the interface has not been initialized or on success; * otherwise, the error code produced by the @c speed_div callback. */ int adapter_get_speed_readable(int *speed); /** Attempt to configure the adapter for the specified kHz. */ int adapter_config_khz(unsigned int khz); /** * Attempt to enable RTCK/RCLK. If that fails, fallback to the * specified frequency. */ int adapter_config_rclk(unsigned int fallback_speed_khz); /** Retrieves the clock speed of the adapter in kHz. */ unsigned int adapter_get_speed_khz(void); /** Retrieves the serial number set with command 'adapter serial' */ const char *adapter_get_required_serial(void); /** * Retrieves gpio name */ const char *adapter_gpio_get_name(enum adapter_gpio_config_index idx); /** * Retrieves gpio configuration set with command "adapter gpio <signal_name>" */ const struct adapter_gpio_config *adapter_gpio_get_config(void); #endif /* OPENOCD_JTAG_ADAPTER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/commands.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/jtag.h> #include <transport/transport.h> #include "commands.h" struct cmd_queue_page { struct cmd_queue_page *next; void *address; size_t used; }; #define CMD_QUEUE_PAGE_SIZE (1024 * 1024) static struct cmd_queue_page *cmd_queue_pages; static struct cmd_queue_page *cmd_queue_pages_tail; struct jtag_command *jtag_command_queue; static struct jtag_command **next_command_pointer = &jtag_command_queue; void jtag_queue_command(struct jtag_command *cmd) { if (!transport_is_jtag()) { /* * FIXME: This should not happen! * There could be old code that queues jtag commands with non jtag interfaces so, for * the moment simply highlight it by log an error. * We should fix it quitting with assert(0) because it is an internal error, or returning * an error after call to jtag_command_queue_reset() to free the jtag queue and avoid * memory leaks. * The fix can be applied immediately after next release (v0.11.0 ?) */ LOG_ERROR("JTAG API jtag_queue_command() called on non JTAG interface"); } /* this command goes on the end, so ensure the queue terminates */ cmd->next = NULL; struct jtag_command **last_cmd = next_command_pointer; assert(last_cmd); assert(!*last_cmd); *last_cmd = cmd; /* store location where the next command pointer will be stored */ next_command_pointer = &cmd->next; } void *cmd_queue_alloc(size_t size) { struct cmd_queue_page **p_page = &cmd_queue_pages; int offset; uint8_t *t; /* * WARNING: * We align/round the *SIZE* per below * so that all pointers returned by * this function are reasonably well * aligned. * * If we did not, then an "odd-length" request would cause the * *next* allocation to be at an *odd* address, and because * this function has the same type of api as malloc() - we * must also return pointers that have the same type of * alignment. * * What I do not/have is a reasonable portable means * to align by... * * The solution here, is based on these suggestions. * http://gcc.gnu.org/ml/gcc-help/2008-12/msg00041.html * */ union worse_case_align { int i; long l; float f; void *v; }; #define ALIGN_SIZE (sizeof(union worse_case_align)) /* The alignment process. */ size = (size + ALIGN_SIZE - 1) & (~(ALIGN_SIZE - 1)); /* Done... */ if (*p_page) { p_page = &cmd_queue_pages_tail; if (CMD_QUEUE_PAGE_SIZE - (*p_page)->used < size) p_page = &((*p_page)->next); } if (!*p_page) { *p_page = malloc(sizeof(struct cmd_queue_page)); (*p_page)->used = 0; size_t alloc_size = (size < CMD_QUEUE_PAGE_SIZE) ? CMD_QUEUE_PAGE_SIZE : size; (*p_page)->address = malloc(alloc_size); (*p_page)->next = NULL; cmd_queue_pages_tail = *p_page; } offset = (*p_page)->used; (*p_page)->used += size; t = (*p_page)->address; return t + offset; } static void cmd_queue_free(void) { struct cmd_queue_page *page = cmd_queue_pages; while (page) { struct cmd_queue_page *last = page; free(page->address); page = page->next; free(last); } cmd_queue_pages = NULL; cmd_queue_pages_tail = NULL; } void jtag_command_queue_reset(void) { cmd_queue_free(); jtag_command_queue = NULL; next_command_pointer = &jtag_command_queue; } /** * Copy a struct scan_field for insertion into the queue. * * This allocates a new copy of out_value using cmd_queue_alloc. */ void jtag_scan_field_clone(struct scan_field *dst, const struct scan_field *src) { dst->num_bits = src->num_bits; dst->out_value = buf_cpy(src->out_value, cmd_queue_alloc(DIV_ROUND_UP(src->num_bits, 8)), src->num_bits); dst->in_value = src->in_value; } enum scan_type jtag_scan_type(const struct scan_command *cmd) { int i; int type = 0; for (i = 0; i < cmd->num_fields; i++) { if (cmd->fields[i].in_value) type |= SCAN_IN; if (cmd->fields[i].out_value) type |= SCAN_OUT; } return type; } int jtag_scan_size(const struct scan_command *cmd) { int bit_count = 0; int i; /* count bits in scan command */ for (i = 0; i < cmd->num_fields; i++) bit_count += cmd->fields[i].num_bits; return bit_count; } int jtag_build_buffer(const struct scan_command *cmd, uint8_t **buffer) { int bit_count = 0; int i; bit_count = jtag_scan_size(cmd); *buffer = calloc(1, DIV_ROUND_UP(bit_count, 8)); bit_count = 0; LOG_DEBUG_IO("%s num_fields: %i", cmd->ir_scan ? "IRSCAN" : "DRSCAN", cmd->num_fields); for (i = 0; i < cmd->num_fields; i++) { if (cmd->fields[i].out_value) { if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { char *char_buf = buf_to_hex_str(cmd->fields[i].out_value, (cmd->fields[i].num_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : cmd->fields[i].num_bits); LOG_DEBUG("fields[%i].out_value[%i]: 0x%s", i, cmd->fields[i].num_bits, char_buf); free(char_buf); } buf_set_buf(cmd->fields[i].out_value, 0, *buffer, bit_count, cmd->fields[i].num_bits); } else { LOG_DEBUG_IO("fields[%i].out_value[%i]: NULL", i, cmd->fields[i].num_bits); } bit_count += cmd->fields[i].num_bits; } /*LOG_DEBUG_IO("bit_count totalling: %i", bit_count); */ return bit_count; } int jtag_read_buffer(uint8_t *buffer, const struct scan_command *cmd) { int i; int bit_count = 0; int retval; /* we return ERROR_OK, unless a check fails, or a handler reports a problem */ retval = ERROR_OK; for (i = 0; i < cmd->num_fields; i++) { /* if neither in_value nor in_handler * are specified we don't have to examine this field */ if (cmd->fields[i].in_value) { int num_bits = cmd->fields[i].num_bits; uint8_t *captured = buf_set_buf(buffer, bit_count, malloc(DIV_ROUND_UP(num_bits, 8)), 0, num_bits); if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { char *char_buf = buf_to_hex_str(captured, (num_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : num_bits); LOG_DEBUG("fields[%i].in_value[%i]: 0x%s", i, num_bits, char_buf); free(char_buf); } if (cmd->fields[i].in_value) buf_cpy(captured, cmd->fields[i].in_value, num_bits); free(captured); } bit_count += cmd->fields[i].num_bits; } return retval; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/commands.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * ***************************************************************************/ #ifndef OPENOCD_JTAG_COMMANDS_H #define OPENOCD_JTAG_COMMANDS_H /** * The inferred type of a scan_command_s structure, indicating whether * the command has the host scan in from the device, the host scan out * to the device, or both. */ enum scan_type { /** From device to host, */ SCAN_IN = 1, /** From host to device, */ SCAN_OUT = 2, /** Full-duplex scan. */ SCAN_IO = 3 }; /** * The scan_command provide a means of encapsulating a set of scan_field_s * structures that should be scanned in/out to the device. */ struct scan_command { /** instruction/not data scan */ bool ir_scan; /** number of fields in *fields array */ int num_fields; /** pointer to an array of data scan fields */ struct scan_field *fields; /** state in which JTAG commands should finish */ tap_state_t end_state; }; struct statemove_command { /** state in which JTAG commands should finish */ tap_state_t end_state; }; struct pathmove_command { /** number of states in *path */ int num_states; /** states that have to be passed */ tap_state_t *path; }; struct runtest_command { /** number of cycles to spend in Run-Test/Idle state */ int num_cycles; /** state in which JTAG commands should finish */ tap_state_t end_state; }; struct stableclocks_command { /** number of clock cycles that should be sent */ int num_cycles; }; struct reset_command { /** Set TRST output: 0 = deassert, 1 = assert, -1 = no change */ int trst; /** Set SRST output: 0 = deassert, 1 = assert, -1 = no change */ int srst; }; struct end_state_command { /** state in which JTAG commands should finish */ tap_state_t end_state; }; struct sleep_command { /** number of microseconds to sleep */ uint32_t us; }; /** * Encapsulates a series of bits to be clocked out, affecting state * and mode of the interface. * * In JTAG mode these are clocked out on TMS, using TCK. They may be * used for link resets, transitioning between JTAG and SWD modes, or * to implement JTAG state machine transitions (implementing pathmove * or statemove operations). * * In SWD mode these are clocked out on SWDIO, using SWCLK, and are * used for link resets and transitioning between SWD and JTAG modes. */ struct tms_command { /** How many bits should be clocked out. */ unsigned num_bits; /** The bits to clock out; the LSB is bit 0 of bits[0]. */ const uint8_t *bits; }; /** * Defines a container type that hold a pointer to a JTAG command * structure of any defined type. */ union jtag_command_container { struct scan_command *scan; struct statemove_command *statemove; struct pathmove_command *pathmove; struct runtest_command *runtest; struct stableclocks_command *stableclocks; struct reset_command *reset; struct end_state_command *end_state; struct sleep_command *sleep; struct tms_command *tms; }; /** * The type of the @c jtag_command_container contained by a * @c jtag_command_s structure. */ enum jtag_command_type { JTAG_SCAN = 1, /* JTAG_TLR_RESET's non-minidriver implementation is a * vestige from a statemove cmd. The statemove command * is obsolete and replaced by pathmove. * * pathmove does not support reset as one of it's states, * hence the need for an explicit statemove command. */ JTAG_TLR_RESET = 2, JTAG_RUNTEST = 3, JTAG_RESET = 4, JTAG_PATHMOVE = 6, JTAG_SLEEP = 7, JTAG_STABLECLOCKS = 8, JTAG_TMS = 9, }; struct jtag_command { union jtag_command_container cmd; enum jtag_command_type type; struct jtag_command *next; }; /** The current queue of jtag_command_s structures. */ extern struct jtag_command *jtag_command_queue; void *cmd_queue_alloc(size_t size); void jtag_queue_command(struct jtag_command *cmd); void jtag_command_queue_reset(void); void jtag_scan_field_clone(struct scan_field *dst, const struct scan_field *src); enum scan_type jtag_scan_type(const struct scan_command *cmd); int jtag_scan_size(const struct scan_command *cmd); int jtag_read_buffer(uint8_t *buffer, const struct scan_command *cmd); int jtag_build_buffer(const struct scan_command *cmd, uint8_t **buffer); #endif /* OPENOCD_JTAG_COMMANDS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/core.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * * * * Copyright (C) 2007,2008,2009 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "adapter.h" #include "jtag.h" #include "swd.h" #include "interface.h" #include <transport/transport.h> #include <helper/jep106.h> #include "helper/system.h" #ifdef HAVE_STRINGS_H #include <strings.h> #endif /* SVF and XSVF are higher level JTAG command sets (for boundary scan) */ #include "svf/svf.h" #include "xsvf/xsvf.h" /* ipdbg are utilities to debug IP-cores. It uses JTAG for transport. */ #include "server/ipdbg.h" /** The number of JTAG queue flushes (for profiling and debugging purposes). */ static int jtag_flush_queue_count; /* Sleep this # of ms after flushing the queue */ static int jtag_flush_queue_sleep; static void jtag_add_scan_check(struct jtag_tap *active, void (*jtag_add_scan)(struct jtag_tap *active, int in_num_fields, const struct scan_field *in_fields, tap_state_t state), int in_num_fields, struct scan_field *in_fields, tap_state_t state); /** * The jtag_error variable is set when an error occurs while executing * the queue. Application code may set this using jtag_set_error(), * when an error occurs during processing that should be reported during * jtag_execute_queue(). * * The value is set and cleared, but never read by normal application code. * * This value is returned (and cleared) by jtag_execute_queue(). */ static int jtag_error = ERROR_OK; static const char *jtag_event_strings[] = { [JTAG_TRST_ASSERTED] = "TAP reset", [JTAG_TAP_EVENT_SETUP] = "TAP setup", [JTAG_TAP_EVENT_ENABLE] = "TAP enabled", [JTAG_TAP_EVENT_DISABLE] = "TAP disabled", }; /* * JTAG adapters must initialize with TRST and SRST de-asserted * (they're negative logic, so that means *high*). But some * hardware doesn't necessarily work that way ... so set things * up so that jtag_init() always forces that state. */ static int jtag_trst = -1; static int jtag_srst = -1; /** * List all TAPs that have been created. */ static struct jtag_tap *__jtag_all_taps; static enum reset_types jtag_reset_config = RESET_NONE; tap_state_t cmd_queue_cur_state = TAP_RESET; static bool jtag_verify_capture_ir = true; static int jtag_verify = 1; /* how long the OpenOCD should wait before attempting JTAG communication after reset lines *deasserted (in ms) */ static int adapter_nsrst_delay; /* default to no nSRST delay */ static int jtag_ntrst_delay;/* default to no nTRST delay */ static int adapter_nsrst_assert_width; /* width of assertion */ static int jtag_ntrst_assert_width; /* width of assertion */ /** * Contains a single callback along with a pointer that will be passed * when an event occurs. */ struct jtag_event_callback { /** a event callback */ jtag_event_handler_t callback; /** the private data to pass to the callback */ void *priv; /** the next callback */ struct jtag_event_callback *next; }; /* callbacks to inform high-level handlers about JTAG state changes */ static struct jtag_event_callback *jtag_event_callbacks; extern struct adapter_driver *adapter_driver; void jtag_set_flush_queue_sleep(int ms) { jtag_flush_queue_sleep = ms; } void jtag_set_error(int error) { if ((error == ERROR_OK) || (jtag_error != ERROR_OK)) return; jtag_error = error; } int jtag_error_clear(void) { int temp = jtag_error; jtag_error = ERROR_OK; return temp; } /************/ static bool jtag_poll = true; static bool jtag_poll_en = true; bool is_jtag_poll_safe(void) { /* Polling can be disabled explicitly with set_enabled(false). * It can also be masked with mask(). * It is also implicitly disabled while TRST is active and * while SRST is gating the JTAG clock. */ if (!jtag_poll_en) return false; if (!transport_is_jtag()) return jtag_poll; if (!jtag_poll || jtag_trst != 0) return false; return jtag_srst == 0 || (jtag_reset_config & RESET_SRST_NO_GATING); } bool jtag_poll_get_enabled(void) { return jtag_poll; } void jtag_poll_set_enabled(bool value) { jtag_poll = value; } bool jtag_poll_mask(void) { bool retval = jtag_poll_en; jtag_poll_en = false; return retval; } void jtag_poll_unmask(bool saved) { jtag_poll_en = saved; } /************/ struct jtag_tap *jtag_all_taps(void) { return __jtag_all_taps; }; unsigned jtag_tap_count(void) { struct jtag_tap *t = jtag_all_taps(); unsigned n = 0; while (t) { n++; t = t->next_tap; } return n; } unsigned jtag_tap_count_enabled(void) { struct jtag_tap *t = jtag_all_taps(); unsigned n = 0; while (t) { if (t->enabled) n++; t = t->next_tap; } return n; } /** Append a new TAP to the chain of all taps. */ static void jtag_tap_add(struct jtag_tap *t) { unsigned jtag_num_taps = 0; struct jtag_tap **tap = &__jtag_all_taps; while (*tap) { jtag_num_taps++; tap = &(*tap)->next_tap; } *tap = t; t->abs_chain_position = jtag_num_taps; } /* returns a pointer to the n-th device in the scan chain */ struct jtag_tap *jtag_tap_by_position(unsigned n) { struct jtag_tap *t = jtag_all_taps(); while (t && n-- > 0) t = t->next_tap; return t; } struct jtag_tap *jtag_tap_by_string(const char *s) { /* try by name first */ struct jtag_tap *t = jtag_all_taps(); while (t) { if (strcmp(t->dotted_name, s) == 0) return t; t = t->next_tap; } /* no tap found by name, so try to parse the name as a number */ unsigned n; if (parse_uint(s, &n) != ERROR_OK) return NULL; /* FIXME remove this numeric fallback code late June 2010, along * with all info in the User's Guide that TAPs have numeric IDs. * Also update "scan_chain" output to not display the numbers. */ t = jtag_tap_by_position(n); if (t) LOG_WARNING("Specify TAP '%s' by name, not number %u", t->dotted_name, n); return t; } struct jtag_tap *jtag_tap_next_enabled(struct jtag_tap *p) { p = p ? p->next_tap : jtag_all_taps(); while (p) { if (p->enabled) return p; p = p->next_tap; } return NULL; } const char *jtag_tap_name(const struct jtag_tap *tap) { return (!tap) ? "(unknown)" : tap->dotted_name; } int jtag_register_event_callback(jtag_event_handler_t callback, void *priv) { struct jtag_event_callback **callbacks_p = &jtag_event_callbacks; if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; if (*callbacks_p) { while ((*callbacks_p)->next) callbacks_p = &((*callbacks_p)->next); callbacks_p = &((*callbacks_p)->next); } (*callbacks_p) = malloc(sizeof(struct jtag_event_callback)); (*callbacks_p)->callback = callback; (*callbacks_p)->priv = priv; (*callbacks_p)->next = NULL; return ERROR_OK; } int jtag_unregister_event_callback(jtag_event_handler_t callback, void *priv) { struct jtag_event_callback **p = &jtag_event_callbacks, *temp; if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; while (*p) { if (((*p)->priv != priv) || ((*p)->callback != callback)) { p = &(*p)->next; continue; } temp = *p; *p = (*p)->next; free(temp); } return ERROR_OK; } int jtag_call_event_callbacks(enum jtag_event event) { struct jtag_event_callback *callback = jtag_event_callbacks; LOG_DEBUG("jtag event: %s", jtag_event_strings[event]); while (callback) { struct jtag_event_callback *next; /* callback may remove itself */ next = callback->next; callback->callback(event, callback->priv); callback = next; } return ERROR_OK; } static void jtag_checks(void) { assert(jtag_trst == 0); } static void jtag_prelude(tap_state_t state) { jtag_checks(); assert(state != TAP_INVALID); cmd_queue_cur_state = state; } void jtag_add_ir_scan_noverify(struct jtag_tap *active, const struct scan_field *in_fields, tap_state_t state) { jtag_prelude(state); int retval = interface_jtag_add_ir_scan(active, in_fields, state); jtag_set_error(retval); } static void jtag_add_ir_scan_noverify_callback(struct jtag_tap *active, int dummy, const struct scan_field *in_fields, tap_state_t state) { jtag_add_ir_scan_noverify(active, in_fields, state); } /* If fields->in_value is filled out, then the captured IR value will be checked */ void jtag_add_ir_scan(struct jtag_tap *active, struct scan_field *in_fields, tap_state_t state) { assert(state != TAP_RESET); if (jtag_verify && jtag_verify_capture_ir) { /* 8 x 32 bit id's is enough for all invocations */ /* if we are to run a verification of the ir scan, we need to get the input back. * We may have to allocate space if the caller didn't ask for the input back. */ in_fields->check_value = active->expected; in_fields->check_mask = active->expected_mask; jtag_add_scan_check(active, jtag_add_ir_scan_noverify_callback, 1, in_fields, state); } else jtag_add_ir_scan_noverify(active, in_fields, state); } void jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { assert(out_bits); assert(state != TAP_RESET); jtag_prelude(state); int retval = interface_jtag_add_plain_ir_scan( num_bits, out_bits, in_bits, state); jtag_set_error(retval); } static int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value, uint8_t *in_check_mask, int num_bits); static int jtag_check_value_mask_callback(jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3) { return jtag_check_value_inner((uint8_t *)data0, (uint8_t *)data1, (uint8_t *)data2, (int)data3); } static void jtag_add_scan_check(struct jtag_tap *active, void (*jtag_add_scan)( struct jtag_tap *active, int in_num_fields, const struct scan_field *in_fields, tap_state_t state), int in_num_fields, struct scan_field *in_fields, tap_state_t state) { jtag_add_scan(active, in_num_fields, in_fields, state); for (int i = 0; i < in_num_fields; i++) { if ((in_fields[i].check_value) && (in_fields[i].in_value)) { jtag_add_callback4(jtag_check_value_mask_callback, (jtag_callback_data_t)in_fields[i].in_value, (jtag_callback_data_t)in_fields[i].check_value, (jtag_callback_data_t)in_fields[i].check_mask, (jtag_callback_data_t)in_fields[i].num_bits); } } } void jtag_add_dr_scan_check(struct jtag_tap *active, int in_num_fields, struct scan_field *in_fields, tap_state_t state) { if (jtag_verify) jtag_add_scan_check(active, jtag_add_dr_scan, in_num_fields, in_fields, state); else jtag_add_dr_scan(active, in_num_fields, in_fields, state); } void jtag_add_dr_scan(struct jtag_tap *active, int in_num_fields, const struct scan_field *in_fields, tap_state_t state) { assert(state != TAP_RESET); jtag_prelude(state); int retval; retval = interface_jtag_add_dr_scan(active, in_num_fields, in_fields, state); jtag_set_error(retval); } void jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { assert(out_bits); assert(state != TAP_RESET); jtag_prelude(state); int retval; retval = interface_jtag_add_plain_dr_scan(num_bits, out_bits, in_bits, state); jtag_set_error(retval); } void jtag_add_tlr(void) { jtag_prelude(TAP_RESET); jtag_set_error(interface_jtag_add_tlr()); /* NOTE: order here matches TRST path in jtag_add_reset() */ jtag_call_event_callbacks(JTAG_TRST_ASSERTED); jtag_notify_event(JTAG_TRST_ASSERTED); } /** * If supported by the underlying adapter, this clocks a raw bit sequence * onto TMS for switching between JTAG and SWD modes. * * DO NOT use this to bypass the integrity checks and logging provided * by the jtag_add_pathmove() and jtag_add_statemove() calls. * * @param nbits How many bits to clock out. * @param seq The bit sequence. The LSB is bit 0 of seq[0]. * @param state The JTAG tap state to record on completion. Use * TAP_INVALID to represent being in in SWD mode. * * @todo Update naming conventions to stop assuming everything is JTAG. */ int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state state) { int retval; if (!(adapter_driver->jtag_ops->supported & DEBUG_CAP_TMS_SEQ)) return ERROR_JTAG_NOT_IMPLEMENTED; jtag_checks(); cmd_queue_cur_state = state; retval = interface_add_tms_seq(nbits, seq, state); jtag_set_error(retval); return retval; } void jtag_add_pathmove(int num_states, const tap_state_t *path) { tap_state_t cur_state = cmd_queue_cur_state; /* the last state has to be a stable state */ if (!tap_is_state_stable(path[num_states - 1])) { LOG_ERROR("BUG: TAP path doesn't finish in a stable state"); jtag_set_error(ERROR_JTAG_NOT_STABLE_STATE); return; } for (int i = 0; i < num_states; i++) { if (path[i] == TAP_RESET) { LOG_ERROR("BUG: TAP_RESET is not a valid state for pathmove sequences"); jtag_set_error(ERROR_JTAG_STATE_INVALID); return; } if (tap_state_transition(cur_state, true) != path[i] && tap_state_transition(cur_state, false) != path[i]) { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(cur_state), tap_state_name(path[i])); jtag_set_error(ERROR_JTAG_TRANSITION_INVALID); return; } cur_state = path[i]; } jtag_checks(); jtag_set_error(interface_jtag_add_pathmove(num_states, path)); cmd_queue_cur_state = path[num_states - 1]; } int jtag_add_statemove(tap_state_t goal_state) { tap_state_t cur_state = cmd_queue_cur_state; if (goal_state != cur_state) { LOG_DEBUG("cur_state=%s goal_state=%s", tap_state_name(cur_state), tap_state_name(goal_state)); } /* If goal is RESET, be paranoid and force that that transition * (e.g. five TCK cycles, TMS high). Else trust "cur_state". */ if (goal_state == TAP_RESET) jtag_add_tlr(); else if (goal_state == cur_state) /* nothing to do */; else if (tap_is_state_stable(cur_state) && tap_is_state_stable(goal_state)) { unsigned tms_bits = tap_get_tms_path(cur_state, goal_state); unsigned tms_count = tap_get_tms_path_len(cur_state, goal_state); tap_state_t moves[8]; assert(tms_count < ARRAY_SIZE(moves)); for (unsigned i = 0; i < tms_count; i++, tms_bits >>= 1) { bool bit = tms_bits & 1; cur_state = tap_state_transition(cur_state, bit); moves[i] = cur_state; } jtag_add_pathmove(tms_count, moves); } else if (tap_state_transition(cur_state, true) == goal_state || tap_state_transition(cur_state, false) == goal_state) jtag_add_pathmove(1, &goal_state); else return ERROR_FAIL; return ERROR_OK; } void jtag_add_runtest(int num_cycles, tap_state_t state) { jtag_prelude(state); jtag_set_error(interface_jtag_add_runtest(num_cycles, state)); } void jtag_add_clocks(int num_cycles) { if (!tap_is_state_stable(cmd_queue_cur_state)) { LOG_ERROR("jtag_add_clocks() called with TAP in unstable state \"%s\"", tap_state_name(cmd_queue_cur_state)); jtag_set_error(ERROR_JTAG_NOT_STABLE_STATE); return; } if (num_cycles > 0) { jtag_checks(); jtag_set_error(interface_jtag_add_clocks(num_cycles)); } } static int adapter_system_reset(int req_srst) { int retval; if (req_srst) { if (!(jtag_reset_config & RESET_HAS_SRST)) { LOG_ERROR("BUG: can't assert SRST"); return ERROR_FAIL; } req_srst = 1; } /* Maybe change SRST signal state */ if (jtag_srst != req_srst) { retval = adapter_driver->reset(0, req_srst); if (retval != ERROR_OK) { LOG_ERROR("SRST error"); return ERROR_FAIL; } jtag_srst = req_srst; if (req_srst) { LOG_DEBUG("SRST line asserted"); if (adapter_nsrst_assert_width) jtag_sleep(adapter_nsrst_assert_width * 1000); } else { LOG_DEBUG("SRST line released"); if (adapter_nsrst_delay) jtag_sleep(adapter_nsrst_delay * 1000); } } return ERROR_OK; } static void legacy_jtag_add_reset(int req_tlr_or_trst, int req_srst) { int trst_with_tlr = 0; int new_srst = 0; int new_trst = 0; /* Without SRST, we must use target-specific JTAG operations * on each target; callers should not be requesting SRST when * that signal doesn't exist. * * RESET_SRST_PULLS_TRST is a board or chip level quirk, which * can kick in even if the JTAG adapter can't drive TRST. */ if (req_srst) { if (!(jtag_reset_config & RESET_HAS_SRST)) { LOG_ERROR("BUG: can't assert SRST"); jtag_set_error(ERROR_FAIL); return; } if ((jtag_reset_config & RESET_SRST_PULLS_TRST) != 0 && !req_tlr_or_trst) { LOG_ERROR("BUG: can't assert only SRST"); jtag_set_error(ERROR_FAIL); return; } new_srst = 1; } /* JTAG reset (entry to TAP_RESET state) can always be achieved * using TCK and TMS; that may go through a TAP_{IR,DR}UPDATE * state first. TRST accelerates it, and bypasses those states. * * RESET_TRST_PULLS_SRST is a board or chip level quirk, which * can kick in even if the JTAG adapter can't drive SRST. */ if (req_tlr_or_trst) { if (!(jtag_reset_config & RESET_HAS_TRST)) trst_with_tlr = 1; else if ((jtag_reset_config & RESET_TRST_PULLS_SRST) != 0 && !req_srst) trst_with_tlr = 1; else new_trst = 1; } /* Maybe change TRST and/or SRST signal state */ if (jtag_srst != new_srst || jtag_trst != new_trst) { int retval; retval = interface_jtag_add_reset(new_trst, new_srst); if (retval != ERROR_OK) jtag_set_error(retval); else retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("TRST/SRST error"); return; } } /* SRST resets everything hooked up to that signal */ if (jtag_srst != new_srst) { jtag_srst = new_srst; if (jtag_srst) { LOG_DEBUG("SRST line asserted"); if (adapter_nsrst_assert_width) jtag_add_sleep(adapter_nsrst_assert_width * 1000); } else { LOG_DEBUG("SRST line released"); if (adapter_nsrst_delay) jtag_add_sleep(adapter_nsrst_delay * 1000); } } /* Maybe enter the JTAG TAP_RESET state ... * - using only TMS, TCK, and the JTAG state machine * - or else more directly, using TRST * * TAP_RESET should be invisible to non-debug parts of the system. */ if (trst_with_tlr) { LOG_DEBUG("JTAG reset with TLR instead of TRST"); jtag_add_tlr(); } else if (jtag_trst != new_trst) { jtag_trst = new_trst; if (jtag_trst) { LOG_DEBUG("TRST line asserted"); tap_set_state(TAP_RESET); if (jtag_ntrst_assert_width) jtag_add_sleep(jtag_ntrst_assert_width * 1000); } else { LOG_DEBUG("TRST line released"); if (jtag_ntrst_delay) jtag_add_sleep(jtag_ntrst_delay * 1000); /* We just asserted nTRST, so we're now in TAP_RESET. * Inform possible listeners about this, now that * JTAG instructions and data can be shifted. This * sequence must match jtag_add_tlr(). */ jtag_call_event_callbacks(JTAG_TRST_ASSERTED); jtag_notify_event(JTAG_TRST_ASSERTED); } } } /* FIXME: name is misleading; we do not plan to "add" reset into jtag queue */ void jtag_add_reset(int req_tlr_or_trst, int req_srst) { int retval; int trst_with_tlr = 0; int new_srst = 0; int new_trst = 0; if (!adapter_driver->reset) { legacy_jtag_add_reset(req_tlr_or_trst, req_srst); return; } /* Without SRST, we must use target-specific JTAG operations * on each target; callers should not be requesting SRST when * that signal doesn't exist. * * RESET_SRST_PULLS_TRST is a board or chip level quirk, which * can kick in even if the JTAG adapter can't drive TRST. */ if (req_srst) { if (!(jtag_reset_config & RESET_HAS_SRST)) { LOG_ERROR("BUG: can't assert SRST"); jtag_set_error(ERROR_FAIL); return; } if ((jtag_reset_config & RESET_SRST_PULLS_TRST) != 0 && !req_tlr_or_trst) { LOG_ERROR("BUG: can't assert only SRST"); jtag_set_error(ERROR_FAIL); return; } new_srst = 1; } /* JTAG reset (entry to TAP_RESET state) can always be achieved * using TCK and TMS; that may go through a TAP_{IR,DR}UPDATE * state first. TRST accelerates it, and bypasses those states. * * RESET_TRST_PULLS_SRST is a board or chip level quirk, which * can kick in even if the JTAG adapter can't drive SRST. */ if (req_tlr_or_trst) { if (!(jtag_reset_config & RESET_HAS_TRST)) trst_with_tlr = 1; else if ((jtag_reset_config & RESET_TRST_PULLS_SRST) != 0 && !req_srst) trst_with_tlr = 1; else new_trst = 1; } /* Maybe change TRST and/or SRST signal state */ if (jtag_srst != new_srst || jtag_trst != new_trst) { /* guarantee jtag queue empty before changing reset status */ jtag_execute_queue(); retval = adapter_driver->reset(new_trst, new_srst); if (retval != ERROR_OK) { jtag_set_error(retval); LOG_ERROR("TRST/SRST error"); return; } } /* SRST resets everything hooked up to that signal */ if (jtag_srst != new_srst) { jtag_srst = new_srst; if (jtag_srst) { LOG_DEBUG("SRST line asserted"); if (adapter_nsrst_assert_width) jtag_add_sleep(adapter_nsrst_assert_width * 1000); } else { LOG_DEBUG("SRST line released"); if (adapter_nsrst_delay) jtag_add_sleep(adapter_nsrst_delay * 1000); } } /* Maybe enter the JTAG TAP_RESET state ... * - using only TMS, TCK, and the JTAG state machine * - or else more directly, using TRST * * TAP_RESET should be invisible to non-debug parts of the system. */ if (trst_with_tlr) { LOG_DEBUG("JTAG reset with TLR instead of TRST"); jtag_add_tlr(); jtag_execute_queue(); } else if (jtag_trst != new_trst) { jtag_trst = new_trst; if (jtag_trst) { LOG_DEBUG("TRST line asserted"); tap_set_state(TAP_RESET); if (jtag_ntrst_assert_width) jtag_add_sleep(jtag_ntrst_assert_width * 1000); } else { LOG_DEBUG("TRST line released"); if (jtag_ntrst_delay) jtag_add_sleep(jtag_ntrst_delay * 1000); /* We just asserted nTRST, so we're now in TAP_RESET. * Inform possible listeners about this, now that * JTAG instructions and data can be shifted. This * sequence must match jtag_add_tlr(). */ jtag_call_event_callbacks(JTAG_TRST_ASSERTED); jtag_notify_event(JTAG_TRST_ASSERTED); } } } void jtag_add_sleep(uint32_t us) { /** @todo Here, keep_alive() appears to be a layering violation!!! */ keep_alive(); jtag_set_error(interface_jtag_add_sleep(us)); } static int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value, uint8_t *in_check_mask, int num_bits) { int retval = ERROR_OK; int compare_failed; if (in_check_mask) compare_failed = buf_cmp_mask(captured, in_check_value, in_check_mask, num_bits); else compare_failed = buf_cmp(captured, in_check_value, num_bits); if (compare_failed) { char *captured_str, *in_check_value_str; int bits = (num_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : num_bits; /* NOTE: we've lost diagnostic context here -- 'which tap' */ captured_str = buf_to_hex_str(captured, bits); in_check_value_str = buf_to_hex_str(in_check_value, bits); LOG_WARNING("Bad value '%s' captured during DR or IR scan:", captured_str); LOG_WARNING(" check_value: 0x%s", in_check_value_str); free(captured_str); free(in_check_value_str); if (in_check_mask) { char *in_check_mask_str; in_check_mask_str = buf_to_hex_str(in_check_mask, bits); LOG_WARNING(" check_mask: 0x%s", in_check_mask_str); free(in_check_mask_str); } retval = ERROR_JTAG_QUEUE_FAILED; } return retval; } void jtag_check_value_mask(struct scan_field *field, uint8_t *value, uint8_t *mask) { assert(field->in_value); if (!value) { /* no checking to do */ return; } jtag_execute_queue_noclear(); int retval = jtag_check_value_inner(field->in_value, value, mask, field->num_bits); jtag_set_error(retval); } int default_interface_jtag_execute_queue(void) { if (!is_adapter_initialized()) { LOG_ERROR("No JTAG interface configured yet. " "Issue 'init' command in startup scripts " "before communicating with targets."); return ERROR_FAIL; } if (!transport_is_jtag()) { /* * FIXME: This should not happen! * There could be old code that queues jtag commands with non jtag interfaces so, for * the moment simply highlight it by log an error and return on empty execute_queue. * We should fix it quitting with assert(0) because it is an internal error. * The fix can be applied immediately after next release (v0.11.0 ?) */ LOG_ERROR("JTAG API jtag_execute_queue() called on non JTAG interface"); if (!adapter_driver->jtag_ops || !adapter_driver->jtag_ops->execute_queue) return ERROR_OK; } int result = adapter_driver->jtag_ops->execute_queue(); struct jtag_command *cmd = jtag_command_queue; while (debug_level >= LOG_LVL_DEBUG_IO && cmd) { switch (cmd->type) { case JTAG_SCAN: LOG_DEBUG_IO("JTAG %s SCAN to %s", cmd->cmd.scan->ir_scan ? "IR" : "DR", tap_state_name(cmd->cmd.scan->end_state)); for (int i = 0; i < cmd->cmd.scan->num_fields; i++) { struct scan_field *field = cmd->cmd.scan->fields + i; if (field->out_value) { char *str = buf_to_hex_str(field->out_value, field->num_bits); LOG_DEBUG_IO(" %db out: %s", field->num_bits, str); free(str); } if (field->in_value) { char *str = buf_to_hex_str(field->in_value, field->num_bits); LOG_DEBUG_IO(" %db in: %s", field->num_bits, str); free(str); } } break; case JTAG_TLR_RESET: LOG_DEBUG_IO("JTAG TLR RESET to %s", tap_state_name(cmd->cmd.statemove->end_state)); break; case JTAG_RUNTEST: LOG_DEBUG_IO("JTAG RUNTEST %d cycles to %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); break; case JTAG_RESET: { const char *reset_str[3] = { "leave", "deassert", "assert" }; LOG_DEBUG_IO("JTAG RESET %s TRST, %s SRST", reset_str[cmd->cmd.reset->trst + 1], reset_str[cmd->cmd.reset->srst + 1]); } break; case JTAG_PATHMOVE: LOG_DEBUG_IO("JTAG PATHMOVE (TODO)"); break; case JTAG_SLEEP: LOG_DEBUG_IO("JTAG SLEEP (TODO)"); break; case JTAG_STABLECLOCKS: LOG_DEBUG_IO("JTAG STABLECLOCKS (TODO)"); break; case JTAG_TMS: LOG_DEBUG_IO("JTAG TMS (TODO)"); break; default: LOG_ERROR("Unknown JTAG command: %d", cmd->type); break; } cmd = cmd->next; } return result; } void jtag_execute_queue_noclear(void) { jtag_flush_queue_count++; jtag_set_error(interface_jtag_execute_queue()); if (jtag_flush_queue_sleep > 0) { /* For debug purposes it can be useful to test performance * or behavior when delaying after flushing the queue, * e.g. to simulate long roundtrip times. */ usleep(jtag_flush_queue_sleep * 1000); } } int jtag_get_flush_queue_count(void) { return jtag_flush_queue_count; } int jtag_execute_queue(void) { jtag_execute_queue_noclear(); return jtag_error_clear(); } static int jtag_reset_callback(enum jtag_event event, void *priv) { struct jtag_tap *tap = priv; if (event == JTAG_TRST_ASSERTED) { tap->enabled = !tap->disabled_after_reset; /* current instruction is either BYPASS or IDCODE */ buf_set_ones(tap->cur_instr, tap->ir_length); tap->bypass = 1; } return ERROR_OK; } /* sleep at least us microseconds. When we sleep more than 1000ms we * do an alive sleep, i.e. keep GDB alive. Note that we could starve * GDB if we slept for <1000ms many times. */ void jtag_sleep(uint32_t us) { if (us < 1000) usleep(us); else alive_sleep((us+999)/1000); } #define JTAG_MAX_AUTO_TAPS 20 #define EXTRACT_MFG(X) (((X) & 0xffe) >> 1) #define EXTRACT_PART(X) (((X) & 0xffff000) >> 12) #define EXTRACT_VER(X) (((X) & 0xf0000000) >> 28) /* A reserved manufacturer ID is used in END_OF_CHAIN_FLAG, so we * know that no valid TAP will have it as an IDCODE value. */ #define END_OF_CHAIN_FLAG 0xffffffff /* a larger IR length than we ever expect to autoprobe */ #define JTAG_IRLEN_MAX 60 static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcode) { struct scan_field field = { .num_bits = num_idcode * 32, .out_value = idcode_buffer, .in_value = idcode_buffer, }; /* initialize to the end of chain ID value */ for (unsigned i = 0; i < num_idcode; i++) buf_set_u32(idcode_buffer, i * 32, 32, END_OF_CHAIN_FLAG); jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, TAP_DRPAUSE); jtag_add_tlr(); return jtag_execute_queue(); } static bool jtag_examine_chain_check(uint8_t *idcodes, unsigned count) { uint8_t zero_check = 0x0; uint8_t one_check = 0xff; for (unsigned i = 0; i < count * 4; i++) { zero_check |= idcodes[i]; one_check &= idcodes[i]; } /* if there wasn't a single non-zero bit or if all bits were one, * the scan is not valid. We wrote a mix of both values; either * * - There's a hardware issue (almost certainly): * + all-zeroes can mean a target stuck in JTAG reset * + all-ones tends to mean no target * - The scan chain is WAY longer than we can handle, *AND* either * + there are several hundreds of TAPs in bypass, or * + at least a few dozen TAPs all have an all-ones IDCODE */ if (zero_check == 0x00 || one_check == 0xff) { LOG_ERROR("JTAG scan chain interrogation failed: all %s", (zero_check == 0x00) ? "zeroes" : "ones"); LOG_ERROR("Check JTAG interface, timings, target power, etc."); return false; } return true; } static void jtag_examine_chain_display(enum log_levels level, const char *msg, const char *name, uint32_t idcode) { log_printf_lf(level, __FILE__, __LINE__, __func__, "JTAG tap: %s %16.16s: 0x%08x " "(mfg: 0x%3.3x (%s), part: 0x%4.4x, ver: 0x%1.1x)", name, msg, (unsigned int)idcode, (unsigned int)EXTRACT_MFG(idcode), jep106_manufacturer(EXTRACT_MFG(idcode)), (unsigned int)EXTRACT_PART(idcode), (unsigned int)EXTRACT_VER(idcode)); } static bool jtag_idcode_is_final(uint32_t idcode) { /* * Some devices, such as AVR8, will output all 1's instead * of TDI input value at end of chain. Allow those values * instead of failing. */ return idcode == END_OF_CHAIN_FLAG; } /** * This helper checks that remaining bits in the examined chain data are * all as expected, but a single JTAG device requires only 64 bits to be * read back correctly. This can help identify and diagnose problems * with the JTAG chain earlier, gives more helpful/explicit error messages. * Returns TRUE iff garbage was found. */ static bool jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned max) { bool triggered = false; for (; count < max - 31; count += 32) { uint32_t idcode = buf_get_u32(idcodes, count, 32); /* do not trigger the warning if the data looks good */ if (jtag_idcode_is_final(idcode)) continue; LOG_WARNING("Unexpected idcode after end of chain: %d 0x%08x", count, (unsigned int)idcode); triggered = true; } return triggered; } static bool jtag_examine_chain_match_tap(const struct jtag_tap *tap) { if (tap->expected_ids_cnt == 0 || !tap->hasidcode) return true; /* optionally ignore the JTAG version field - bits 28-31 of IDCODE */ uint32_t mask = tap->ignore_version ? ~(0xfU << 28) : ~0U; uint32_t idcode = tap->idcode & mask; /* Loop over the expected identification codes and test for a match */ for (unsigned ii = 0; ii < tap->expected_ids_cnt; ii++) { uint32_t expected = tap->expected_ids[ii] & mask; if (idcode == expected) return true; /* treat "-expected-id 0" as a "don't-warn" wildcard */ if (tap->expected_ids[ii] == 0) return true; } /* If none of the expected ids matched, warn */ jtag_examine_chain_display(LOG_LVL_WARNING, "UNEXPECTED", tap->dotted_name, tap->idcode); for (unsigned ii = 0; ii < tap->expected_ids_cnt; ii++) { char msg[32]; snprintf(msg, sizeof(msg), "expected %u of %u", ii + 1, tap->expected_ids_cnt); jtag_examine_chain_display(LOG_LVL_ERROR, msg, tap->dotted_name, tap->expected_ids[ii]); } return false; } /* Try to examine chain layout according to IEEE 1149.1 §12 * This is called a "blind interrogation" of the scan chain. */ static int jtag_examine_chain(void) { int retval; unsigned max_taps = jtag_tap_count(); /* Autoprobe up to this many. */ if (max_taps < JTAG_MAX_AUTO_TAPS) max_taps = JTAG_MAX_AUTO_TAPS; /* Add room for end-of-chain marker. */ max_taps++; uint8_t *idcode_buffer = calloc(4, max_taps); if (!idcode_buffer) return ERROR_JTAG_INIT_FAILED; /* DR scan to collect BYPASS or IDCODE register contents. * Then make sure the scan data has both ones and zeroes. */ LOG_DEBUG("DR scan interrogation for IDCODE/BYPASS"); retval = jtag_examine_chain_execute(idcode_buffer, max_taps); if (retval != ERROR_OK) goto out; if (!jtag_examine_chain_check(idcode_buffer, max_taps)) { retval = ERROR_JTAG_INIT_FAILED; goto out; } /* Point at the 1st predefined tap, if any */ struct jtag_tap *tap = jtag_tap_next_enabled(NULL); unsigned bit_count = 0; unsigned autocount = 0; for (unsigned i = 0; i < max_taps; i++) { assert(bit_count < max_taps * 32); uint32_t idcode = buf_get_u32(idcode_buffer, bit_count, 32); /* No predefined TAP? Auto-probe. */ if (!tap) { /* Is there another TAP? */ if (jtag_idcode_is_final(idcode)) break; /* Default everything in this TAP except IR length. * * REVISIT create a jtag_alloc(chip, tap) routine, and * share it with jim_newtap_cmd(). */ tap = calloc(1, sizeof(*tap)); if (!tap) { retval = ERROR_FAIL; goto out; } tap->chip = alloc_printf("auto%u", autocount++); tap->tapname = strdup("tap"); tap->dotted_name = alloc_printf("%s.%s", tap->chip, tap->tapname); tap->ir_length = 0; /* ... signifying irlen autoprobe */ tap->ir_capture_mask = 0x03; tap->ir_capture_value = 0x01; tap->enabled = true; jtag_tap_init(tap); } if ((idcode & 1) == 0 && !tap->ignore_bypass) { /* Zero for LSB indicates a device in bypass */ LOG_INFO("TAP %s does not have valid IDCODE (idcode=0x%" PRIx32 ")", tap->dotted_name, idcode); tap->hasidcode = false; tap->idcode = 0; bit_count += 1; } else { /* Friendly devices support IDCODE */ tap->hasidcode = true; tap->idcode = idcode; jtag_examine_chain_display(LOG_LVL_INFO, "tap/device found", tap->dotted_name, idcode); bit_count += 32; } /* ensure the TAP ID matches what was expected */ if (!jtag_examine_chain_match_tap(tap)) retval = ERROR_JTAG_INIT_SOFT_FAIL; tap = jtag_tap_next_enabled(tap); } /* After those IDCODE or BYPASS register values should be * only the data we fed into the scan chain. */ if (jtag_examine_chain_end(idcode_buffer, bit_count, max_taps * 32)) { LOG_ERROR("double-check your JTAG setup (interface, speed, ...)"); retval = ERROR_JTAG_INIT_FAILED; goto out; } /* Return success or, for backwards compatibility if only * some IDCODE values mismatched, a soft/continuable fault. */ out: free(idcode_buffer); return retval; } /* * Validate the date loaded by entry to the Capture-IR state, to help * find errors related to scan chain configuration (wrong IR lengths) * or communication. * * Entry state can be anything. On non-error exit, all TAPs are in * bypass mode. On error exits, the scan chain is reset. */ static int jtag_validate_ircapture(void) { struct jtag_tap *tap; uint8_t *ir_test = NULL; struct scan_field field; int chain_pos = 0; int retval; /* when autoprobing, accommodate huge IR lengths */ int total_ir_length = 0; for (tap = jtag_tap_next_enabled(NULL); tap; tap = jtag_tap_next_enabled(tap)) { if (tap->ir_length == 0) total_ir_length += JTAG_IRLEN_MAX; else total_ir_length += tap->ir_length; } /* increase length to add 2 bit sentinel after scan */ total_ir_length += 2; ir_test = malloc(DIV_ROUND_UP(total_ir_length, 8)); if (!ir_test) return ERROR_FAIL; /* after this scan, all TAPs will capture BYPASS instructions */ buf_set_ones(ir_test, total_ir_length); field.num_bits = total_ir_length; field.out_value = ir_test; field.in_value = ir_test; jtag_add_plain_ir_scan(field.num_bits, field.out_value, field.in_value, TAP_IDLE); LOG_DEBUG("IR capture validation scan"); retval = jtag_execute_queue(); if (retval != ERROR_OK) goto done; tap = NULL; chain_pos = 0; for (;; ) { tap = jtag_tap_next_enabled(tap); if (!tap) break; /* If we're autoprobing, guess IR lengths. They must be at * least two bits. Guessing will fail if (a) any TAP does * not conform to the JTAG spec; or (b) when the upper bits * captured from some conforming TAP are nonzero. Or if * (c) an IR length is longer than JTAG_IRLEN_MAX bits, * an implementation limit, which could someday be raised. * * REVISIT optimization: if there's a *single* TAP we can * lift restrictions (a) and (b) by scanning a recognizable * pattern before the all-ones BYPASS. Check for where the * pattern starts in the result, instead of an 0...01 value. * * REVISIT alternative approach: escape to some tcl code * which could provide more knowledge, based on IDCODE; and * only guess when that has no success. */ if (tap->ir_length == 0) { tap->ir_length = 2; while (buf_get_u64(ir_test, chain_pos, tap->ir_length + 1) == 1 && tap->ir_length < JTAG_IRLEN_MAX) { tap->ir_length++; } LOG_WARNING("AUTO %s - use \"jtag newtap %s %s -irlen %d " "-expected-id 0x%08" PRIx32 "\"", tap->dotted_name, tap->chip, tap->tapname, tap->ir_length, tap->idcode); } /* Validate the two LSBs, which must be 01 per JTAG spec. * * Or ... more bits could be provided by TAP declaration. * Plus, some taps (notably in i.MX series chips) violate * this part of the JTAG spec, so their capture mask/value * attributes might disable this test. */ uint64_t val = buf_get_u64(ir_test, chain_pos, tap->ir_length); if ((val & tap->ir_capture_mask) != tap->ir_capture_value) { LOG_ERROR("%s: IR capture error; saw 0x%0*" PRIx64 " not 0x%0*" PRIx32, jtag_tap_name(tap), (tap->ir_length + 7) / tap->ir_length, val, (tap->ir_length + 7) / tap->ir_length, tap->ir_capture_value); retval = ERROR_JTAG_INIT_FAILED; goto done; } LOG_DEBUG("%s: IR capture 0x%0*" PRIx64, jtag_tap_name(tap), (tap->ir_length + 7) / tap->ir_length, val); chain_pos += tap->ir_length; } /* verify the '11' sentinel we wrote is returned at the end */ uint64_t val = buf_get_u64(ir_test, chain_pos, 2); if (val != 0x3) { char *cbuf = buf_to_hex_str(ir_test, total_ir_length); LOG_ERROR("IR capture error at bit %d, saw 0x%s not 0x...3", chain_pos, cbuf); free(cbuf); retval = ERROR_JTAG_INIT_FAILED; } done: free(ir_test); if (retval != ERROR_OK) { jtag_add_tlr(); jtag_execute_queue(); } return retval; } void jtag_tap_init(struct jtag_tap *tap) { unsigned ir_len_bits; unsigned ir_len_bytes; /* if we're autoprobing, cope with potentially huge ir_length */ ir_len_bits = tap->ir_length ? tap->ir_length : JTAG_IRLEN_MAX; ir_len_bytes = DIV_ROUND_UP(ir_len_bits, 8); tap->expected = calloc(1, ir_len_bytes); tap->expected_mask = calloc(1, ir_len_bytes); tap->cur_instr = malloc(ir_len_bytes); /** @todo cope better with ir_length bigger than 32 bits */ if (ir_len_bits > 32) ir_len_bits = 32; buf_set_u32(tap->expected, 0, ir_len_bits, tap->ir_capture_value); buf_set_u32(tap->expected_mask, 0, ir_len_bits, tap->ir_capture_mask); /* TAP will be in bypass mode after jtag_validate_ircapture() */ tap->bypass = 1; buf_set_ones(tap->cur_instr, tap->ir_length); /* register the reset callback for the TAP */ jtag_register_event_callback(&jtag_reset_callback, tap); jtag_tap_add(tap); LOG_DEBUG("Created Tap: %s @ abs position %d, " "irlen %d, capture: 0x%x mask: 0x%x", tap->dotted_name, tap->abs_chain_position, tap->ir_length, (unsigned) tap->ir_capture_value, (unsigned) tap->ir_capture_mask); } void jtag_tap_free(struct jtag_tap *tap) { jtag_unregister_event_callback(&jtag_reset_callback, tap); struct jtag_tap_event_action *jteap = tap->event_action; while (jteap) { struct jtag_tap_event_action *next = jteap->next; Jim_DecrRefCount(jteap->interp, jteap->body); free(jteap); jteap = next; } free(tap->expected); free(tap->expected_mask); free(tap->expected_ids); free(tap->cur_instr); free(tap->chip); free(tap->tapname); free(tap->dotted_name); free(tap); } int jtag_init_inner(struct command_context *cmd_ctx) { struct jtag_tap *tap; int retval; bool issue_setup = true; LOG_DEBUG("Init JTAG chain"); tap = jtag_tap_next_enabled(NULL); if (!tap) { /* Once JTAG itself is properly set up, and the scan chain * isn't absurdly large, IDCODE autoprobe should work fine. * * But ... IRLEN autoprobe can fail even on systems which * are fully conformant to JTAG. Also, JTAG setup can be * quite finicky on some systems. * * REVISIT: if TAP autoprobe works OK, then in many cases * we could escape to tcl code and set up targets based on * the TAP's IDCODE values. */ LOG_WARNING("There are no enabled taps. " "AUTO PROBING MIGHT NOT WORK!!"); /* REVISIT default clock will often be too fast ... */ } jtag_add_tlr(); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* Examine DR values first. This discovers problems which will * prevent communication ... hardware issues like TDO stuck, or * configuring the wrong number of (enabled) TAPs. */ retval = jtag_examine_chain(); switch (retval) { case ERROR_OK: /* complete success */ break; default: /* For backward compatibility reasons, try coping with * configuration errors involving only ID mismatches. * We might be able to talk to the devices. * * Also the device might be powered down during startup. * * After OpenOCD starts, we can try to power on the device * and run a reset. */ LOG_ERROR("Trying to use configured scan chain anyway..."); issue_setup = false; break; } /* Now look at IR values. Problems here will prevent real * communication. They mostly mean that the IR length is * wrong ... or that the IR capture value is wrong. (The * latter is uncommon, but easily worked around: provide * ircapture/irmask values during TAP setup.) */ retval = jtag_validate_ircapture(); if (retval != ERROR_OK) { /* The target might be powered down. The user * can power it up and reset it after firing * up OpenOCD. */ issue_setup = false; } if (issue_setup) jtag_notify_event(JTAG_TAP_EVENT_SETUP); else LOG_WARNING("Bypassing JTAG setup events due to errors"); return ERROR_OK; } int swd_init_reset(struct command_context *cmd_ctx) { int retval, retval1; retval = adapter_init(cmd_ctx); if (retval != ERROR_OK) return retval; LOG_DEBUG("Initializing with hard SRST reset"); if (jtag_reset_config & RESET_HAS_SRST) retval = adapter_system_reset(1); retval1 = adapter_system_reset(0); return (retval == ERROR_OK) ? retval1 : retval; } int jtag_init_reset(struct command_context *cmd_ctx) { int retval = adapter_init(cmd_ctx); if (retval != ERROR_OK) return retval; LOG_DEBUG("Initializing with hard TRST+SRST reset"); /* * This procedure is used by default when OpenOCD triggers a reset. * It's now done through an overridable Tcl "init_reset" wrapper. * * This started out as a more powerful "get JTAG working" reset than * jtag_init_inner(), applying TRST because some chips won't activate * JTAG without a TRST cycle (presumed to be async, though some of * those chips synchronize JTAG activation using TCK). * * But some chips only activate JTAG as part of an SRST cycle; SRST * got mixed in. So it became a hard reset routine, which got used * in more places, and which coped with JTAG reset being forced as * part of SRST (srst_pulls_trst). * * And even more corner cases started to surface: TRST and/or SRST * assertion timings matter; some chips need other JTAG operations; * TRST/SRST sequences can need to be different from these, etc. * * Systems should override that wrapper to support system-specific * requirements that this not-fully-generic code doesn't handle. * * REVISIT once Tcl code can read the reset_config modes, this won't * need to be a C routine at all... */ if (jtag_reset_config & RESET_HAS_SRST) { jtag_add_reset(1, 1); if ((jtag_reset_config & RESET_SRST_PULLS_TRST) == 0) jtag_add_reset(0, 1); } else { jtag_add_reset(1, 0); /* TAP_RESET, using TMS+TCK or TRST */ } /* some targets enable us to connect with srst asserted */ if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) jtag_add_reset(0, 1); else { LOG_WARNING("\'srst_nogate\' reset_config option is required"); jtag_add_reset(0, 0); } } else jtag_add_reset(0, 0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* Check that we can communication on the JTAG chain + eventually we want to * be able to perform enumeration only after OpenOCD has started * telnet and GDB server * * That would allow users to more easily perform any magic they need to before * reset happens. */ return jtag_init_inner(cmd_ctx); } int jtag_init(struct command_context *cmd_ctx) { int retval = adapter_init(cmd_ctx); if (retval != ERROR_OK) return retval; /* guard against oddball hardware: force resets to be inactive */ jtag_add_reset(0, 0); /* some targets enable us to connect with srst asserted */ if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) jtag_add_reset(0, 1); else LOG_WARNING("\'srst_nogate\' reset_config option is required"); } retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (Jim_Eval_Named(cmd_ctx->interp, "jtag_init", __FILE__, __LINE__) != JIM_OK) return ERROR_FAIL; return ERROR_OK; } void jtag_set_verify(bool enable) { jtag_verify = enable; } bool jtag_will_verify(void) { return jtag_verify; } void jtag_set_verify_capture_ir(bool enable) { jtag_verify_capture_ir = enable; } bool jtag_will_verify_capture_ir(void) { return jtag_verify_capture_ir; } int jtag_power_dropout(int *dropout) { if (!is_adapter_initialized()) { /* TODO: as the jtag interface is not valid all * we can do at the moment is exit OpenOCD */ LOG_ERROR("No Valid JTAG Interface Configured."); exit(-1); } if (adapter_driver->power_dropout) return adapter_driver->power_dropout(dropout); *dropout = 0; /* by default we can't detect power dropout */ return ERROR_OK; } int jtag_srst_asserted(int *srst_asserted) { if (adapter_driver->srst_asserted) return adapter_driver->srst_asserted(srst_asserted); *srst_asserted = 0; /* by default we can't detect srst asserted */ return ERROR_OK; } enum reset_types jtag_get_reset_config(void) { return jtag_reset_config; } void jtag_set_reset_config(enum reset_types type) { jtag_reset_config = type; } int jtag_get_trst(void) { return jtag_trst == 1; } int jtag_get_srst(void) { return jtag_srst == 1; } void jtag_set_nsrst_delay(unsigned delay) { adapter_nsrst_delay = delay; } unsigned jtag_get_nsrst_delay(void) { return adapter_nsrst_delay; } void jtag_set_ntrst_delay(unsigned delay) { jtag_ntrst_delay = delay; } unsigned jtag_get_ntrst_delay(void) { return jtag_ntrst_delay; } void jtag_set_nsrst_assert_width(unsigned delay) { adapter_nsrst_assert_width = delay; } unsigned jtag_get_nsrst_assert_width(void) { return adapter_nsrst_assert_width; } void jtag_set_ntrst_assert_width(unsigned delay) { jtag_ntrst_assert_width = delay; } unsigned jtag_get_ntrst_assert_width(void) { return jtag_ntrst_assert_width; } static int jtag_select(struct command_context *ctx) { int retval; /* NOTE: interface init must already have been done. * That works with only C code ... no Tcl glue required. */ retval = jtag_register_commands(ctx); if (retval != ERROR_OK) return retval; retval = svf_register_commands(ctx); if (retval != ERROR_OK) return retval; retval = xsvf_register_commands(ctx); if (retval != ERROR_OK) return retval; return ipdbg_register_commands(ctx); } static struct transport jtag_transport = { .name = "jtag", .select = jtag_select, .init = jtag_init, }; static void jtag_constructor(void) __attribute__((constructor)); static void jtag_constructor(void) { transport_register(&jtag_transport); } /** Returns true if the current debug session * is using JTAG as its transport. */ bool transport_is_jtag(void) { return get_current_transport() == &jtag_transport; } int adapter_resets(int trst, int srst) { if (!get_current_transport()) { LOG_ERROR("transport is not selected"); return ERROR_FAIL; } if (transport_is_jtag()) { if (srst == SRST_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) { LOG_ERROR("adapter has no srst signal"); return ERROR_FAIL; } /* adapters without trst signal will eventually use tlr sequence */ jtag_add_reset(trst, srst); /* * The jtag queue is still used for reset by some adapter. Flush it! * FIXME: To be removed when all adapter drivers will be updated! */ jtag_execute_queue(); return ERROR_OK; } else if (transport_is_swd() || transport_is_hla() || transport_is_dapdirect_swd() || transport_is_dapdirect_jtag() || transport_is_swim()) { if (trst == TRST_ASSERT) { LOG_ERROR("transport %s has no trst signal", get_current_transport()->name); return ERROR_FAIL; } if (srst == SRST_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) { LOG_ERROR("adapter has no srst signal"); return ERROR_FAIL; } adapter_system_reset(srst); return ERROR_OK; } if (trst == TRST_DEASSERT && srst == SRST_DEASSERT) return ERROR_OK; LOG_ERROR("reset is not supported on transport %s", get_current_transport()->name); return ERROR_FAIL; } int adapter_assert_reset(void) { if (transport_is_jtag()) { if (jtag_reset_config & RESET_SRST_PULLS_TRST) jtag_add_reset(1, 1); else jtag_add_reset(0, 1); return ERROR_OK; } else if (transport_is_swd() || transport_is_hla() || transport_is_dapdirect_jtag() || transport_is_dapdirect_swd() || transport_is_swim()) return adapter_system_reset(1); else if (get_current_transport()) LOG_ERROR("reset is not supported on %s", get_current_transport()->name); else LOG_ERROR("transport is not selected"); return ERROR_FAIL; } int adapter_deassert_reset(void) { if (transport_is_jtag()) { jtag_add_reset(0, 0); return ERROR_OK; } else if (transport_is_swd() || transport_is_hla() || transport_is_dapdirect_jtag() || transport_is_dapdirect_swd() || transport_is_swim()) return adapter_system_reset(0); else if (get_current_transport()) LOG_ERROR("reset is not supported on %s", get_current_transport()->name); else LOG_ERROR("transport is not selected"); return ERROR_FAIL; } int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler) { if (adapter_driver->config_trace) { return adapter_driver->config_trace(enabled, pin_protocol, port_size, trace_freq, traceclkin_freq, prescaler); } else if (enabled) { LOG_ERROR("The selected interface does not support tracing"); return ERROR_FAIL; } return ERROR_OK; } int adapter_poll_trace(uint8_t *buf, size_t *size) { if (adapter_driver->poll_trace) return adapter_driver->poll_trace(buf, size); return ERROR_FAIL; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libocdjtagdrivers.la %C%_libocdjtagdrivers_la_LIBADD = %C%_libocdjtagdrivers_la_SOURCES = \ $(DRIVERFILES) \ $(DRIVERHEADERS) %C%_libocdjtagdrivers_la_CPPFLAGS = $(AM_CPPFLAGS) ULINK_FIRMWARE = %D%/OpenULINK EXTRA_DIST += $(ULINK_FIRMWARE) \ %D%/usb_blaster/README.CheapClone \ %D%/Makefile.rlink \ %D%/rlink_call.m4 \ %D%/rlink_init.m4 DRIVERFILES = # Standard Driver: common files DRIVERFILES += %D%/driver.c if USE_LIBUSB1 DRIVERFILES += %D%/libusb_helper.c %C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBUSB1_CFLAGS) %C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB1_LIBS) endif if USE_LIBFTDI %C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBFTDI_CFLAGS) %C%_libocdjtagdrivers_la_LIBADD += $(LIBFTDI_LIBS) endif if USE_LIBGPIOD %C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBGPIOD_CFLAGS) %C%_libocdjtagdrivers_la_LIBADD += $(LIBGPIOD_LIBS) endif if USE_HIDAPI %C%_libocdjtagdrivers_la_CPPFLAGS += $(HIDAPI_CFLAGS) %C%_libocdjtagdrivers_la_LIBADD += $(HIDAPI_LIBS) endif if USE_LIBJAYLINK %C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBJAYLINK_CFLAGS) %C%_libocdjtagdrivers_la_LIBADD += $(LIBJAYLINK_LIBS) endif if JLINK DRIVERFILES += %D%/jlink.c if INTERNAL_LIBJAYLINK SUBDIRS += %D%/libjaylink DIST_SUBDIRS += %D%/libjaylink %C%_libocdjtagdrivers_la_LIBADD += %D%/libjaylink/libjaylink/libjaylink.la %C%_libocdjtagdrivers_la_CPPFLAGS += -I$(builddir)/%D%/libjaylink/libjaylink -I$(srcdir)/%D%/libjaylink endif endif if BITBANG DRIVERFILES += %D%/bitbang.c endif if PARPORT DRIVERFILES += %D%/parport.c endif if DUMMY DRIVERFILES += %D%/dummy.c endif if FTDI DRIVERFILES += %D%/ftdi.c %D%/mpsse.c endif if LINUXGPIOD DRIVERFILES += %D%/linuxgpiod.c endif if JTAG_VPI DRIVERFILES += %D%/jtag_vpi.c endif if VDEBUG DRIVERFILES += %D%/vdebug.c endif if JTAG_DPI DRIVERFILES += %D%/jtag_dpi.c endif if USB_BLASTER_DRIVER %C%_libocdjtagdrivers_la_LIBADD += %D%/usb_blaster/libocdusbblaster.la include %D%/usb_blaster/Makefile.am endif if FT232R DRIVERFILES += %D%/ft232r.c endif if AMTJTAGACCEL DRIVERFILES += %D%/amt_jtagaccel.c endif if EP93XX DRIVERFILES += %D%/ep93xx.c endif if AT91RM9200 DRIVERFILES += %D%/at91rm9200.c endif if GW16012 DRIVERFILES += %D%/gw16012.c endif if BITQ DRIVERFILES += %D%/bitq.c endif if PRESTO DRIVERFILES += %D%/presto.c endif if ESP_USB_JTAG DRIVERFILES += %D%/esp_usb_jtag.c endif if USBPROG DRIVERFILES += %D%/usbprog.c endif if RLINK DRIVERFILES += %D%/rlink.c %D%/rlink_speed_table.c endif if ULINK DRIVERFILES += %D%/ulink.c ulinkdir = $(pkgdatadir)/OpenULINK dist_ulink_DATA = $(ULINK_FIRMWARE)/ulink_firmware.hex %C%_libocdjtagdrivers_la_LIBADD += -lm endif if VSLLINK DRIVERFILES += %D%/versaloon/usbtoxxx/usbtogpio.c DRIVERFILES += %D%/versaloon/usbtoxxx/usbtojtagraw.c DRIVERFILES += %D%/versaloon/usbtoxxx/usbtoswd.c DRIVERFILES += %D%/versaloon/usbtoxxx/usbtopwr.c DRIVERFILES += %D%/versaloon/usbtoxxx/usbtoxxx.c DRIVERFILES += %D%/versaloon/versaloon.c DRIVERFILES += %D%/vsllink.c endif if ARMJTAGEW DRIVERFILES += %D%/arm-jtag-ew.c endif if BUSPIRATE DRIVERFILES += %D%/buspirate.c endif if REMOTE_BITBANG DRIVERFILES += %D%/remote_bitbang.c endif if HLADAPTER_STLINK DRIVERFILES += %D%/stlink_usb.c endif if HLADAPTER_ICDI DRIVERFILES += %D%/ti_icdi_usb.c endif if HLADAPTER_NULINK DRIVERFILES += %D%/nulink_usb.c endif if RSHIM DRIVERFILES += %D%/rshim.c endif if OSBDM DRIVERFILES += %D%/osbdm.c endif if OPENDOUS DRIVERFILES += %D%/opendous.c endif if SYSFSGPIO DRIVERFILES += %D%/sysfsgpio.c endif if XLNX_PCIE_XVC DRIVERFILES += %D%/xlnx-pcie-xvc.c endif if BCM2835GPIO DRIVERFILES += %D%/bcm2835gpio.c endif if OPENJTAG DRIVERFILES += %D%/openjtag.c endif if CMSIS_DAP_HID DRIVERFILES += %D%/cmsis_dap_usb_hid.c DRIVERFILES += %D%/cmsis_dap.c endif if CMSIS_DAP_USB DRIVERFILES += %D%/cmsis_dap_usb_bulk.c if !CMSIS_DAP_HID DRIVERFILES += %D%/cmsis_dap.c endif endif if IMX_GPIO DRIVERFILES += %D%/imx_gpio.c endif if KITPROG DRIVERFILES += %D%/kitprog.c endif if XDS110 DRIVERFILES += %D%/xds110.c endif if AM335XGPIO DRIVERFILES += %D%/am335xgpio.c endif if CH347 DRIVERFILES += %D%/ch347.c endif DRIVERHEADERS = \ %D%/bitbang.h \ %D%/bitq.h \ %D%/libftdi_helper.h \ %D%/libusb_helper.h \ %D%/cmsis_dap.h \ %D%/minidriver_imp.h \ %D%/mpsse.h \ %D%/rlink.h \ %D%/rlink_dtc_cmd.h \ %D%/rlink_ep1_cmd.h \ %D%/rlink_st7.h \ %D%/versaloon/usbtoxxx/usbtoxxx.h \ %D%/versaloon/usbtoxxx/usbtoxxx_internal.h \ %D%/versaloon/versaloon.h \ %D%/versaloon/versaloon_include.h \ %D%/versaloon/versaloon_internal.h ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/Makefile.rlink ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Copyright (C) 2008 Lou Deluxe # lou.openocd012@fixit.nospammail.net # TOP = ../../.. INTERFACE_NAME = rlink PERL = perl M4 = m4 TARGETDIR = ${TOP}/src/target TOOLSDIR = ${TOP}/tools MAKE_SPEED_TABLE = ${TOOLSDIR}/rlink_make_speed_table/rlink_make_speed_table ST7_DTC_AS = ${TOOLSDIR}/st7_dtc_as/st7_dtc_as OPENOCD = ${TOP}/src/openocd OPENOCD_CONFIG = -s ${TARGETDIR} OPENOCD_CONFIG += -f interface/rlink.cfg OPENOCD_CONFIG += -f board/stm32f10x_128k_eval.cfg PATCHFILE = /tmp/openocd_${INTERFACE_NAME}.diff.gz # relative to ${TOP} SVNADDFILES = SVNADDFILES += src/target/interface/rlink.cfg SVNADDFILES += src/jtag/${INTERFACE_NAME}.c SVNADDFILES += src/jtag/${INTERFACE_NAME} PRESCALERS = 64 11 8 2 DTCFILES = DTCFILES += $(addsuffix _init.dtc, ${PRESCALERS}) DTCFILES += $(addsuffix _call.dtc, ${PRESCALERS}) default: rlink_speed_table.c clean %_init.fsm: rlink_init.m4 ${M4} -P -DSHIFTER_PRESCALER=`echo "$@" | sed -e's/_.*//'` $< > $@ %_call.fsm: rlink_call.m4 ${M4} -P -DSHIFTER_PRESCALER=`echo "$@" | sed -e's/_.*//'` $< > $@ %.dtc: %.fsm ${ST7_DTC_AS} -b -o $@ -i $< > /dev/null rlink_speed_table.c: ${DTCFILES} ${MAKE_SPEED_TABLE} ${PRESCALERS} > $@ || rm $@ clean: -rm *.dtc *.fsm distclean: clean test: default (cd ${TOP} && (rm src/jtag/${INTERFACE_NAME}.o; ${MAKE})) ${OPENOCD} -d0 ${OPENOCD_CONFIG} -c init -c 'poll off' ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/README ================================================ This is the OpenULINK firmware for the Keil ULINK JTAG adapter. The main components of the Keil ULINK adapter are: - Cypress EZ-USB microcontroller: enhanced 8051 CPU + USB core (1.1 Full-Speed) - SRAM memory chip - Level shifters to support different JTAG signal voltage levels - Pin headers for various JTAG pin assignments This firmware can only be run on the ORIGINAL Keil ULINK adapter, not on the newer ULINK2, ULINK-ME or ULINK-PRO, as these adapters are based on different hardware. To compile the firmware, the SDCC compiler package is required. Most Linux distributions include SDCC in their official package repositories. The SDCC source code can be found at http://sdcc.sourceforge.net/ Simply type "make hex" in the OpenULINK directory to compile the firmware. "make clean" will remove all generated files except the Intel HEX file required for downloading the firmware to the ULINK adapter. Note that the EZ-USB microcontroller does not have on-chip flash, nor does the Keil ULINK include on-board memory to store the firmware program of the EZ-USB. Instead, upon initial connection of the ULINK adapter to the host PC via USB, the EZ-USB core has enough intelligence to act as a stand-alone USB device, responding to USB control requests and allowing firmware download via a special VENDOR-type control request. Then, the EZ-USB microcontroller simulates a disconnect and re-connect to the USB bus. It may take up to two seconds for the host to recognize the newly connected device before OpenOCD can proceed to execute JTAG commands. This delay is only visible when OpenOCD first uses a blank (unconfigured) ULINK device. Once the user disconnects the ULINK adapter, all its memory contents are lost and the firmware download process has to be executed again. This also maintains compatibility with the original Keil uVision IDE, which will happily download its own firmware image to a blank ULINK adapter. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/include/common.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ #ifndef __COMMON_H #define __COMMON_H #define DIV_ROUND_UP(m, n) (((m) + (n) - 1) / (n)) #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/include/delay.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ #ifndef __DELAY_H #define __DELAY_H #include <stdint.h> #define NOP { __asm nop __endasm; } void delay_5us(void); void delay_1ms(void); void delay_us(uint16_t delay); void delay_ms(uint16_t delay); #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/include/io.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ #ifndef __IO_H #define __IO_H #include "reg_ezusb.h" /*************************************************************************** * JTAG Signals: * *************************************************************************** * TMS ....... Test Mode Select * * TCK ....... Test Clock * * TDI ....... Test Data Input (from device point of view, not JTAG * * adapter point of view!) * * TDO ....... Test Data Output (from device point of view, not JTAG * * adapter point of view!) * * TRST ...... Test Reset: Used to reset the TAP Finite State Machine * * into the Test Logic Reset state * * RTCK ...... Return Test Clock * * OCDSE ..... Enable/Disable OCDS interface (Infineon specific) - shared * * with /JEN * * TRAP ...... Trap Condition (Infineon specific) - shared with TSTAT * * BRKIN ..... Hardware Break-In (Infineon specific) * * BRKOUT .... Hardware Break-Out (Infineon specific) * * /JEN ...... JTAG-Enable (STMicroelectronics specific) - shared * * with OCDSE * * TSTAT ..... JTAG ISP Status (STMicroelectronics specific) - shared * * with TRAP * * RESET ..... Chip Reset (STMicroelectronics specific) * * /TERR ..... JTAG ISP Error (STMicroelectronics specific) - shared * * with BRKOUT * ***************************************************************************/ /* PORT A */ #define PIN_U_OE OUTA0 /* PA1 Not Connected */ #define PIN_OE OUTA2 /* PA3 Not Connected */ #define PIN_RUN_LED OUTA4 #define PIN_TDO PINA5 #define PIN_BRKOUT PINA6 #define PIN_COM_LED OUTA7 /* PORT B */ #define PIN_TDI OUTB0 #define PIN_TMS OUTB1 #define PIN_TCK OUTB2 #define PIN_TRST OUTB3 #define PIN_BRKIN OUTB4 #define PIN_RESET OUTB5 #define PIN_OCDSE OUTB6 #define PIN_TRAP PINB7 /* JTAG Signals with direction 'OUT' on port B */ #define MASK_PORTB_DIRECTION_OUT (PIN_TDI | PIN_TMS | PIN_TCK | PIN_TRST | PIN_BRKIN | PIN_RESET | PIN_OCDSE) /* PORT C */ #define PIN_RXD0 PINC0 #define PIN_TXD0 OUTC1 #define PIN_RESET_2 PINC2 /* PC3 Not Connected */ /* PC4 Not Connected */ #define PIN_RTCK PINC5 #define PIN_WR OUTC6 /* PC7 Not Connected */ /* LED Macros */ #define SET_RUN_LED() (OUTA &= ~PIN_RUN_LED) #define CLEAR_RUN_LED() (OUTA |= PIN_RUN_LED) #define SET_COM_LED() (OUTA &= ~PIN_COM_LED) #define CLEAR_COM_LED() (OUTA |= PIN_COM_LED) /* JTAG Pin Macros */ #define GET_TMS() (PINSB & PIN_TMS) #define GET_TCK() (PINSB & PIN_TCK) #define GET_TDO() (PINSA & PIN_TDO) #define GET_BRKOUT() (PINSA & PIN_BRKOUT) #define GET_TRAP() (PINSB & PIN_TRAP) #define GET_RTCK() (PINSC & PIN_RTCK) #define SET_TMS_HIGH() (OUTB |= PIN_TMS) #define SET_TMS_LOW() (OUTB &= ~PIN_TMS) #define SET_TCK_HIGH() (OUTB |= PIN_TCK) #define SET_TCK_LOW() (OUTB &= ~PIN_TCK) #define SET_TDI_HIGH() (OUTB |= PIN_TDI) #define SET_TDI_LOW() (OUTB &= ~PIN_TDI) /* TRST and RESET are low-active and inverted by hardware. SET_HIGH de-asserts * the signal (enabling reset), SET_LOW asserts the signal (disabling reset) */ #define SET_TRST_HIGH() (OUTB |= PIN_TRST) #define SET_TRST_LOW() (OUTB &= ~PIN_TRST) #define SET_RESET_HIGH() (OUTB |= PIN_RESET) #define SET_RESET_LOW() (OUTB &= ~PIN_RESET) #define SET_OCDSE_HIGH() (OUTB |= PIN_OCDSE) #define SET_OCDSE_LOW() (OUTB &= ~PIN_OCDSE) #define SET_BRKIN_HIGH() (OUTB |= PIN_BRKIN) #define SET_BRKIN_LOW() (OUTB &= ~PIN_BRKIN) #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/include/jtag.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ #ifndef __JTAG_H #define __JTAG_H #include <stdint.h> #define NOP { __asm nop __endasm; } void jtag_scan_in(uint8_t out_offset, uint8_t in_offset); void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset); void jtag_scan_out(uint8_t out_offset); void jtag_slow_scan_out(uint8_t out_offset); void jtag_scan_io(uint8_t out_offset, uint8_t in_offset); void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset); void jtag_clock_tck(uint16_t count); void jtag_slow_clock_tck(uint16_t count); void jtag_clock_tms(uint8_t count, uint8_t sequence); void jtag_slow_clock_tms(uint8_t count, uint8_t sequence); uint16_t jtag_get_signals(void); void jtag_set_signals(uint8_t low, uint8_t high); void jtag_configure_tck_delay(uint8_t scan_in, uint8_t scan_out, uint8_t scan_io, uint8_t tck, uint8_t tms); #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/include/main.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ #ifndef __MAIN_H #define __MAIN_H void io_init(void); #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/include/msgtypes.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ /** * @file * Definition of the commands supported by the OpenULINK firmware. * * Basically, two types of commands can be distinguished: * - Commands with fixed payload size * - Commands with variable payload size * * SCAN commands (in all variations) carry payloads of variable size, all * other commands carry payloads of fixed size. * * In the case of SCAN commands, the payload size (n) is calculated by * dividing the scan_size_bits variable by 8, rounding up the result. * * Offset zero always contains the command ID. * **************************************************************************** * CMD_SCAN_IN, CMD_SLOW_SCAN_IN: * * * * OUT: * * offset 1: scan_size_bytes * * offset 2: bits_last_byte * * offset 3: tms_count_start + tms_count_end * * offset 4: tms_sequence_start * * offset 5: tms_sequence_end * * * * IN: * * offset 0..n: TDO data * **************************************************************************** * CMD_SCAN_OUT, CMD_SLOW_SCAN_OUT: * * * * OUT: * * offset 1: scan_size_bytes * * offset 2: bits_last_byte * * offset 3: tms_count_start + tms_count_end * * offset 4: tms_sequence_start * * offset 5: tms_sequence_end * * offset 6..x: TDI data * **************************************************************************** * CMD_SCAN_IO, CMD_SLOW_SCAN_IO: * * * * OUT: * * offset 1: scan_size_bytes * * offset 2: bits_last_byte * * offset 3: tms_count_start + tms_count_end * * offset 4: tms_sequence_start * * offset 5: tms_sequence_end * * offset 6..x: TDI data * * * * IN: * * offset 0..n: TDO data * **************************************************************************** * CMD_CLOCK_TMS, CMD_SLOW_CLOCK_TMS: * * * * OUT: * * offset 1: tms_count * * offset 2: tms_sequence * **************************************************************************** * CMD_CLOCK_TCK, CMD_SLOW_CLOCK_TCK: * * * * OUT: * * offset 1: low byte of tck_count * * offset 2: high byte of tck_count * **************************************************************************** * CMD_CLOCK_SLEEP_US: * * * * OUT: * * offset 1: low byte of sleep_us * * offset 2: high byte of sleep_us * **************************************************************************** * CMD_CLOCK_SLEEP_MS: * * * * OUT: * * offset 1: low byte of sleep_ms * * offset 2: high byte of sleep_ms * **************************************************************************** * CMD_GET_SIGNALS: * * * * IN: * * offset 0: current state of input signals * * offset 1: current state of output signals * **************************************************************************** * CMD_SET_SIGNALS: * * * * OUT: * * offset 1: signals that should be de-asserted * * offset 2: signals that should be asserted * **************************************************************************** * CMD_CONFIGURE_TCK_FREQ: * * * * OUT: * * offset 1: delay value for scan_in function * * offset 2: delay value for scan_out function * * offset 3: delay value for scan_io function * * offset 4: delay value for clock_tck function * * offset 5: delay value for clock_tms function * **************************************************************************** * CMD_SET_LEDS: * * * * OUT: * * offset 1: LED states: * * Bit 0: turn COM LED on * * Bit 1: turn RUN LED on * * Bit 2: turn COM LED off * * Bit 3: turn RUN LED off * * Bits 7..4: Reserved * **************************************************************************** * CMD_TEST: * * * * OUT: * * offset 1: unused dummy value * **************************************************************************** */ #ifndef __MSGTYPES_H #define __MSGTYPES_H /* * Command IDs: * * Bits 7..6: Reserved, should always be zero * Bits 5..0: Command ID. There are 62 usable IDs. Of this 63 available IDs, * the IDs 0x00..0x1F are commands with variable payload size, * the IDs 0x20..0x3F are commands with fixed payload size. */ #define CMD_ID_MASK 0x3F /* Commands with variable payload size */ #define CMD_SCAN_IN 0x00 #define CMD_SLOW_SCAN_IN 0x01 #define CMD_SCAN_OUT 0x02 #define CMD_SLOW_SCAN_OUT 0x03 #define CMD_SCAN_IO 0x04 #define CMD_SLOW_SCAN_IO 0x05 /* Commands with fixed payload size */ #define CMD_CLOCK_TMS 0x20 #define CMD_SLOW_CLOCK_TMS 0x21 #define CMD_CLOCK_TCK 0x22 #define CMD_SLOW_CLOCK_TCK 0x23 #define CMD_SLEEP_US 0x24 #define CMD_SLEEP_MS 0x25 #define CMD_GET_SIGNALS 0x26 #define CMD_SET_SIGNALS 0x27 #define CMD_CONFIGURE_TCK_FREQ 0x28 #define CMD_SET_LEDS 0x29 #define CMD_TEST 0x2A /* JTAG signal definition for jtag_get_signals() -- Input signals! */ #define SIGNAL_TDO (1<<0) #define SIGNAL_BRKOUT (1<<1) #define SIGNAL_TRAP (1<<2) #define SIGNAL_RTCK (1<<3) /* JTAG signal definition for jtag_get_signals() -- Output signals! */ #define SIGNAL_TDI (1<<0) #define SIGNAL_TMS (1<<1) #define SIGNAL_TCK (1<<2) #define SIGNAL_TRST (1<<3) #define SIGNAL_BRKIN (1<<4) #define SIGNAL_RESET (1<<5) #define SIGNAL_OCDSE (1<<6) /* LED definitions for CMD_SET_LEDS and CMD_CLEAR_LEDS commands */ #define COM_LED_ON (1<<0) #define RUN_LED_ON (1<<1) #define COM_LED_OFF (1<<2) #define RUN_LED_OFF (1<<3) #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/include/protocol.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ #ifndef __PROTOCOL_H #define __PROTOCOL_H #include "common.h" #include <stdbool.h> void execute_set_led_command(void); bool execute_command(void); void command_loop(void); #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/include/reg_ezusb.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ #ifndef REG_EZUSB_H #define REG_EZUSB_H /** * @file * All information in this file was taken from the EZ-USB Technical * Reference Manual, Cypress Semiconductor, 3901 North First Street * San Jose, CA 95134 (www.cypress.com). * * The EZ-USB Technical Reference Manual is called "EZ-USB TRM" hereafter. * * The following bit name definitions differ from those in the EZ-USB TRM: * - All lowercase characters in the EZ-USB TRM bit names have been converted * to capitals (e. g. "WakeSRC" converted to "WAKESRC"). * - CPUCS: 8051RES is named "RES8051". * - ISOCTL: Two MBZ ("Must Be Zero") bits are named "MBZ0" and "MBZ1". * - I2CS: STOP and START bits are preceded by "I2C_" * - INxCS, OUTxCS: the busy and stall bits are named "EPBSY" and "EPSTALL". * - TOGCTL: EZ-USB TRM bit names are preceded by "TOG_". */ /* Compiler-specific definitions of SBIT, SFR, SFRX, ... macros */ #include <mcs51/compiler.h> /* Bit vectors */ #define bmBit0 0x01 #define bmBit1 0x02 #define bmBit2 0x04 #define bmBit3 0x08 #define bmBit4 0x10 #define bmBit5 0x20 #define bmBit6 0x40 #define bmBit7 0x80 /************************************************************************** ************************ Special Function Registers ********************** ***************************************************************************/ /* See EZ-USB TRM, pp. A-9 - A-10 */ SFR(SP, 0x81); SFR(DPL0, 0x82); SFR(DPH0, 0x83); SFR(DPL1, 0x84); SFR(DPL2, 0x85); SFR(DPS, 0x86); #define SEL bmBit0 /* Bit 1 read-only, always reads '0' */ /* Bit 2 read-only, always reads '0' */ /* Bit 3 read-only, always reads '0' */ /* Bit 4 read-only, always reads '0' */ /* Bit 5 read-only, always reads '0' */ /* Bit 6 read-only, always reads '0' */ /* Bit 7 read-only, always reads '0' */ SFR(PCON, 0x87); #define IDLE bmBit0 #define STOP bmBit1 #define GF0 bmBit2 #define GF1 bmBit3 /* Bit 4 read-only, always reads '1' */ /* Bit 5 read-only, always reads '1' */ /* Bit 6 unused */ #define SMOD0 bmBit7 SFR(TCON, 0x88); SBIT(IT0, 0x88, 0); SBIT(IE0, 0x88, 1); SBIT(IT1, 0x88, 2); SBIT(IE1, 0x88, 3); SBIT(TR0, 0x88, 4); SBIT(TF0, 0x88, 5); SBIT(TR1, 0x88, 6); SBIT(TF1, 0x88, 7); SFR(TMOD, 0x89); /* Some bits in this register share the same name in the EZ-USB TRM. Therefore, * we add a '0'/'1' to distinguish them */ #define M00 bmBit0 #define M01 bmBit1 #define CT0 bmBit2 #define GATE0 bmBit3 #define M10 bmBit4 #define M11 bmBit5 #define CT1 bmBit6 #define GATE1 bmBit7 SFR(TL0, 0x8A); SFR(TL1, 0x8B); SFR(TH0, 0x8C); SFR(TH1, 0x8D); SFR(CKCON, 0x8E); #define MD0 bmBit0 #define MD1 bmBit1 #define MD2 bmBit2 #define T0M bmBit3 #define T1M bmBit4 #define T2M bmBit5 /* Bit 6 unused */ /* Bit 7 unused */ SFR(SPC_FNC, 0x8D); #define bmWRS bmBit0 /* Bit 1 read-only, always reads '0' */ /* Bit 2 read-only, always reads '0' */ /* Bit 3 read-only, always reads '0' */ /* Bit 4 read-only, always reads '0' */ /* Bit 5 read-only, always reads '0' */ /* Bit 6 read-only, always reads '0' */ /* Bit 7 read-only, always reads '0' */ SFR(EXIF, 0x91); /* Bit 0 read-only, always reads '0' */ /* Bit 1 read-only, always reads '0' */ /* Bit 2 read-only, always reads '0' */ /* Bit 3 read-only, always reads '1' */ #define USBINT bmBit4 #define I2CINT bmBit5 #define IE4 bmBit6 #define IE5 bmBit7 /* Definition of the _XPAGE register, according to SDCC Compiler User Guide, * Version 3.0.1, Chapter 4, p. 61. Also see EZ-USB TRM, p. 2-4. */ SFR(MPAGE, 0x92); SFR(_XPAGE, 0x92); SFR(SCON0, 0x98); SBIT(RI_0, 0x98, 0); SBIT(TI_0, 0x98, 1); SBIT(RB8_0, 0x98, 2); SBIT(TB8_0, 0x98, 3); SBIT(REN_0, 0x98, 4); SBIT(SM2_0, 0x98, 5); SBIT(SM1_0, 0x98, 6); SBIT(SM0_0, 0x98, 7); SFR(SBUF0, 0x99); SFR(IE, 0xA8); SBIT(EX0, 0xA8, 0); SBIT(ET0, 0xA8, 1); SBIT(EX1, 0xA8, 2); SBIT(ET1, 0xA8, 3); SBIT(ES0, 0xA8, 4); SBIT(ET2, 0xA8, 5); SBIT(ES1, 0xA8, 6); SBIT(EA, 0xA8, 7); SFR(IP, 0xB8); SBIT(PX0, 0xB8, 0); SBIT(PT0, 0xB8, 1); SBIT(PX1, 0xB8, 2); SBIT(PT1, 0xB8, 3); SBIT(PS0, 0xB8, 4); SBIT(PT2, 0xB8, 5); SBIT(PS1, 0xB8, 6); /* Bit 7 read-only, always reads '1' */ SFR(SCON1, 0xC0); SBIT(RI_1, 0xC0, 0); SBIT(TI_1, 0xC0, 1); SBIT(RB8_1, 0xC0, 2); SBIT(TB8_1, 0xC0, 3); SBIT(REN_1, 0xC0, 4); SBIT(SM2_1, 0xC0, 5); SBIT(SM1_1, 0xC0, 6); SBIT(SM0_1, 0xC0, 7); SFR(SBUF1, 0xC1); SFR(T2CON, 0xC8); SBIT(CPRL2, 0xC8, 0); SBIT(CT2, 0xC8, 1); SBIT(TR2, 0xC8, 2); SBIT(EXEN2, 0xC8, 3); SBIT(TCLK, 0xC8, 4); SBIT(RCLK, 0xC8, 5); SBIT(EXF2, 0xC8, 6); SBIT(TF2, 0xC8, 7); SFR(RCAP2L, 0xCA); SFR(RCAP2H, 0xCB); SFR(TL2, 0xCC); SFR(TH2, 0xCD); SFR(PSW, 0xD0); SBIT(P, 0xD0, 0); SBIT(F1, 0xD0, 1); SBIT(OV, 0xD0, 2); SBIT(RS0, 0xD0, 3); SBIT(RS1, 0xD0, 4); SBIT(F0, 0xD0, 5); SBIT(AC, 0xD0, 6); SBIT(CY, 0xD0, 7); SFR(EICON, 0xD8); /* Bit 0 read-only, always reads '0' */ /* Bit 1 read-only, always reads '0' */ /* Bit 2 read-only, always reads '0' */ SBIT(INT6, 0xD8, 3); SBIT(RESI, 0xD8, 4); SBIT(ERESI, 0xD8, 5); /* Bit 6 read-only, always reads '1' */ SBIT(SMOD1, 0xD8, 7); SFR(ACC, 0xE0); SFR(EIE, 0xE8); SBIT(EUSB, 0xE8, 0); SBIT(EI2C, 0xE8, 1); SBIT(EX4, 0xE8, 2); SBIT(EX5, 0xE8, 3); SBIT(EWDI, 0xE8, 4); /* Bit 5 read-only, always reads '1' */ /* Bit 6 read-only, always reads '1' */ /* Bit 7 read-only, always reads '1' */ SFR(B, 0xF0); SFR(EIP, 0xF8); SBIT(PUSB, 0xF8, 0); SBIT(PI2C, 0xF8, 1); SBIT(PX4, 0xF8, 2); SBIT(PX5, 0xF8, 3); SBIT(PX6, 0xF8, 4); /* Bit 5 read-only, always reads '1' */ /* Bit 6 read-only, always reads '1' */ /* Bit 7 read-only, always reads '1' */ /************************************************************************** ***************************** XDATA Registers **************************** ***************************************************************************/ /************************ Endpoint 0-7 Data Buffers ************************/ SFRX(OUT7BUF[64], 0x7B40); SFRX(IN7BUF[64], 0x7B80); SFRX(OUT6BUF[64], 0x7BC0); SFRX(IN6BUF[64], 0x7C00); SFRX(OUT5BUF[64], 0x7C40); SFRX(IN5BUF[64], 0x7C80); SFRX(OUT4BUF[64], 0x7CC0); SFRX(IN4BUF[64], 0x7D00); SFRX(OUT3BUF[64], 0x7D40); SFRX(IN3BUF[64], 0x7D80); SFRX(OUT2BUF[64], 0x7DC0); SFRX(IN2BUF[64], 0x7E00); SFRX(OUT1BUF[64], 0x7E40); SFRX(IN1BUF[64], 0x7E80); SFRX(OUT0BUF[64], 0x7EC0); SFRX(IN0BUF[64], 0x7F00); /* 0x7F40 - 0x7F5F reserved */ /**************************** Isochronous Data *****************************/ SFRX(OUT8DATA, 0x7F60); SFRX(OUT9DATA, 0x7F61); SFRX(OUT10DATA, 0x7F62); SFRX(OUT11DATA, 0x7F63); SFRX(OUT12DATA, 0x7F64); SFRX(OUT13DATA, 0x7F65); SFRX(OUT14DATA, 0x7F66); SFRX(OUT15DATA, 0x7F67); SFRX(IN8DATA, 0x7F68); SFRX(IN9DATA, 0x7F69); SFRX(IN10DATA, 0x7F6A); SFRX(IN11DATA, 0x7F6B); SFRX(IN12DATA, 0x7F6C); SFRX(IN13DATA, 0x7F6D); SFRX(IN14DATA, 0x7F6E); SFRX(IN15DATA, 0x7F6F); /************************* Isochronous Byte Counts *************************/ SFRX(OUT8BCH, 0x7F70); SFRX(OUT8BCL, 0x7F71); SFRX(OUT9BCH, 0x7F72); SFRX(OUT9BCL, 0x7F73); SFRX(OUT10BCH, 0x7F74); SFRX(OUT10BCL, 0x7F75); SFRX(OUT11BCH, 0x7F76); SFRX(OUT11BCL, 0x7F77); SFRX(OUT12BCH, 0x7F78); SFRX(OUT12BCL, 0x7F79); SFRX(OUT13BCH, 0x7F7A); SFRX(OUT13BCL, 0x7F7B); SFRX(OUT14BCH, 0x7F7C); SFRX(OUT14BCL, 0x7F7D); SFRX(OUT15BCH, 0x7F7E); SFRX(OUT16BCL, 0x7F7F); /****************************** CPU Registers ******************************/ SFRX(CPUCS, 0x7F92); #define RES8051 bmBit0 #define CLK24OE bmBit1 /* Bit 2 read-only, always reads '0' */ /* Bit 3 read-only, always reads '0' */ /* Bits 4...7: Chip Revision */ SFRX(PORTACFG, 0x7F93); #define T0OUT bmBit0 #define T1OUT bmBit1 #define OE bmBit2 #define CS bmBit3 #define FWR bmBit4 #define FRD bmBit5 #define RXD0OUT bmBit6 #define RXD1OUT bmBit7 SFRX(PORTBCFG, 0x7F94); #define T2 bmBit0 #define T2EX bmBit1 #define RXD1 bmBit2 #define TXD1 bmBit3 #define INT4 bmBit4 #define INT5 bmBit5 #define INT6 bmBit6 #define T2OUT bmBit7 SFRX(PORTCCFG, 0x7F95); #define RXD0 bmBit0 #define TXD0 bmBit1 #define INT0 bmBit2 #define INT1 bmBit3 #define T0 bmBit4 #define T1 bmBit5 #define WR bmBit6 #define RD bmBit7 /*********************** Input-Output Port Registers ***********************/ SFRX(OUTA, 0x7F96); #define OUTA0 bmBit0 #define OUTA1 bmBit1 #define OUTA2 bmBit2 #define OUTA3 bmBit3 #define OUTA4 bmBit4 #define OUTA5 bmBit5 #define OUTA6 bmBit6 #define OUTA7 bmBit7 SFRX(OUTB, 0x7F97); #define OUTB0 bmBit0 #define OUTB1 bmBit1 #define OUTB2 bmBit2 #define OUTB3 bmBit3 #define OUTB4 bmBit4 #define OUTB5 bmBit5 #define OUTB6 bmBit6 #define OUTB7 bmBit7 SFRX(OUTC, 0x7F98); #define OUTC0 bmBit0 #define OUTC1 bmBit1 #define OUTC2 bmBit2 #define OUTC3 bmBit3 #define OUTC4 bmBit4 #define OUTC5 bmBit5 #define OUTC6 bmBit6 #define OUTC7 bmBit7 SFRX(PINSA, 0x7F99); #define PINA0 bmBit0 #define PINA1 bmBit1 #define PINA2 bmBit2 #define PINA3 bmBit3 #define PINA4 bmBit4 #define PINA5 bmBit5 #define PINA6 bmBit6 #define PINA7 bmBit7 SFRX(PINSB, 0x7F9A); #define PINB0 bmBit0 #define PINB1 bmBit1 #define PINB2 bmBit2 #define PINB3 bmBit3 #define PINB4 bmBit4 #define PINB5 bmBit5 #define PINB6 bmBit6 #define PINB7 bmBit7 SFRX(PINSC, 0x7F9B); #define PINC0 bmBit0 #define PINC1 bmBit1 #define PINC2 bmBit2 #define PINC3 bmBit3 #define PINC4 bmBit4 #define PINC5 bmBit5 #define PINC6 bmBit6 #define PINC7 bmBit7 SFRX(OEA, 0x7F9C); #define OEA0 bmBit0 #define OEA1 bmBit1 #define OEA2 bmBit2 #define OEA3 bmBit3 #define OEA4 bmBit4 #define OEA5 bmBit5 #define OEA6 bmBit6 #define OEA7 bmBit7 SFRX(OEB, 0x7F9D); #define OEB0 bmBit0 #define OEB1 bmBit1 #define OEB2 bmBit2 #define OEB3 bmBit3 #define OEB4 bmBit4 #define OEB5 bmBit5 #define OEB6 bmBit6 #define OEB7 bmBit7 SFRX(OEC, 0x7F9E); #define OEC0 bmBit0 #define OEC1 bmBit1 #define OEC2 bmBit2 #define OEC3 bmBit3 #define OEC4 bmBit4 #define OEC5 bmBit5 #define OEC6 bmBit6 #define OEC7 bmBit7 /* 0x7F9F reserved */ /****************** Isochronous Control/Status Registers *******************/ SFRX(ISOERR, 0x7FA0); #define ISO8ERR bmBit0 #define ISO9ERR bmBit1 #define ISO10ERR bmBit2 #define ISO11ERR bmBit3 #define ISO12ERR bmBit4 #define ISO13ERR bmBit5 #define ISO14ERR bmBit6 #define ISO15ERR bmBit7 SFRX(ISOCTL, 0x7FA1); #define ISODISAB bmBit0 #define MBZ0 bmBit1 #define MBZ1 bmBit2 #define PPSTAT bmBit3 /* Bit 4 unused */ /* Bit 5 unused */ /* Bit 6 unused */ /* Bit 7 unused */ SFRX(ZBCOUT, 0x7FA2); #define EP8 bmBit0 #define EP9 bmBit1 #define EP10 bmBit2 #define EP11 bmBit3 #define EP12 bmBit4 #define EP13 bmBit5 #define EP14 bmBit6 #define EP15 bmBit7 /* 0x7FA3 reserved */ /* 0x7FA4 reserved */ /****************************** I2C Registers ******************************/ SFRX(I2CS, 0x7FA5); #define DONE bmBit0 #define ACK bmBit1 #define BERR bmBit2 #define ID0 bmBit3 #define ID1 bmBit4 #define LASTRD bmBit5 #define I2C_STOP bmBit6 #define I2C_START bmBit7 SFRX(I2DAT, 0x7FA6); /* 0x7FA7 reserved */ /******************************* Interrupts ********************************/ SFRX(IVEC, 0x7FA8); /* Bit 0 read-only, always reads '0' */ /* Bit 1 read-only, always reads '0' */ #define IV0 bmBit2 #define IV1 bmBit3 #define IV2 bmBit4 #define IV3 bmBit5 #define IV4 bmBit6 /* Bit 7 read-only, always reads '0' */ SFRX(IN07IRQ, 0x7FA9); #define IN0IR bmBit0 #define IN1IR bmBit1 #define IN2IR bmBit2 #define IN3IR bmBit3 #define IN4IR bmBit4 #define IN5IR bmBit5 #define IN6IR bmBit6 #define IN7IR bmBit7 SFRX(OUT07IRQ, 0x7FAA); #define OUT0IR bmBit0 #define OUT1IR bmBit1 #define OUT2IR bmBit2 #define OUT3IR bmBit3 #define OUT4IR bmBit4 #define OUT5IR bmBit5 #define OUT6IR bmBit6 #define OUT7IR bmBit7 SFRX(USBIRQ, 0x7FAB); #define SUDAVIR bmBit0 #define SOFIR bmBit1 #define SUTOKIR bmBit2 #define SUSPIR bmBit3 #define URESIR bmBit4 /* Bit 5 unused */ /* Bit 6 unused */ /* Bit 7 unused */ SFRX(IN07IEN, 0x7FAC); #define IN0IEN bmBit0 #define IN1IEN bmBit1 #define IN2IEN bmBit2 #define IN3IEN bmBit3 #define IN4IEN bmBit4 #define IN5IEN bmBit5 #define IN6IEN bmBit6 #define IN7IEN bmBit7 SFRX(OUT07IEN, 0x7FAD); #define OUT0IEN bmBit0 #define OUT1IEN bmBit1 #define OUT2IEN bmBit2 #define OUT3IEN bmBit3 #define OUT4IEN bmBit4 #define OUT5IEN bmBit5 #define OUT6IEN bmBit6 #define OUT7IEN bmBit7 SFRX(USBIEN, 0x7FAE); #define SUDAVIE bmBit0 #define SOFIE bmBit1 #define SUTOKIE bmBit2 #define SUSPIE bmBit3 #define URESIE bmBit4 /* Bit 5 unused */ /* Bit 6 unused */ /* Bit 7 unused */ SFRX(USBBAV, 0x7FAF); #define AVEN bmBit0 #define BPEN bmBit1 #define BPPULSE bmBit2 #define BREAK bmBit3 /* Bit 4 unused */ /* Bit 5 unused */ /* Bit 6 unused */ /* Bit 7 unused */ /* 0x7FB0 reserved */ /* 0x7FB1 reserved */ SFRX(BPADDRH, 0x7FB2); SFRX(BPADDRL, 0x7FB3); /****************************** Endpoints 0-7 ******************************/ SFRX(EP0CS, 0x7FB4); #define EP0STALL bmBit0 #define HSNAK bmBit1 #define IN0BSY bmBit2 #define OUT0BSY bmBit3 /* Bit 4 unused */ /* Bit 5 unused */ /* Bit 6 unused */ /* Bit 7 unused */ SFRX(IN0BC, 0x7FB5); SFRX(IN1CS, 0x7FB6); SFRX(IN1BC, 0x7FB7); SFRX(IN2CS, 0x7FB8); SFRX(IN2BC, 0x7FB9); SFRX(IN3CS, 0x7FBA); SFRX(IN3BC, 0x7FBB); SFRX(IN4CS, 0x7FBC); SFRX(IN4BC, 0x7FBD); SFRX(IN5CS, 0x7FBE); SFRX(IN5BC, 0x7FBF); SFRX(IN6CS, 0x7FC0); SFRX(IN6BC, 0x7FC1); SFRX(IN7CS, 0x7FC2); SFRX(IN7BC, 0x7FC3); /* 0x7FC4 reserved */ SFRX(OUT0BC, 0x7FC5); SFRX(OUT1CS, 0x7FC6); SFRX(OUT1BC, 0x7FC7); SFRX(OUT2CS, 0x7FC8); SFRX(OUT2BC, 0x7FC9); SFRX(OUT3CS, 0x7FCA); SFRX(OUT3BC, 0x7FCB); SFRX(OUT4CS, 0x7FCC); SFRX(OUT4BC, 0x7FCD); SFRX(OUT5CS, 0x7FCE); SFRX(OUT5BC, 0x7FCF); SFRX(OUT6CS, 0x7FD0); SFRX(OUT6BC, 0x7FD1); SFRX(OUT7CS, 0x7FD2); SFRX(OUT7BC, 0x7FD3); /* The INxSTALL, OUTxSTALL, INxBSY and OUTxBSY bits are the same for all * INxCS/OUTxCS registers. For better readability, we define them only once */ #define EPSTALL bmBit0 #define EPBSY bmBit1 /************************** Global USB Registers ***************************/ SFRX(SUDPTRH, 0x7FD4); SFRX(SUDPTRL, 0x7FD5); SFRX(USBCS, 0x7FD6); #define SIGRSUME bmBit0 #define RENUM bmBit1 #define DISCOE bmBit2 #define DISCON bmBit3 /* Bit 4 unused */ /* Bit 5 unused */ /* Bit 6 unused */ #define WAKESRC bmBit7 SFRX(TOGCTL, 0x7FD7); #define TOG_EP0 bmBit0 #define TOG_EP1 bmBit1 #define TOG_EP2 bmBit2 /* Bit 3 is read-only, always reads '0' */ #define TOG_IO bmBit4 #define TOG_R bmBit5 #define TOG_S bmBit6 #define TOG_Q bmBit7 SFRX(USBFRAMEL, 0x7FD8); SFRX(USBFRAMEH, 0x7FD9); /* 0x7FDA reserved */ SFRX(FNADDR, 0x7FDB); /* 0x7FDC reserved */ SFRX(USBPAIR, 0x7FDD); #define PR2IN bmBit0 #define PR4IN bmBit1 #define PR6IN bmBit2 #define PR2OUT bmBit3 #define PR4OUT bmBit4 #define PR6OUT bmBit5 /* Bit 6 unused */ #define ISOSEND0 bmBit7 SFRX(IN07VAL, 0x7FDE); /* Bit 0 is read-only, always reads '1' */ #define IN1VAL bmBit1 #define IN2VAL bmBit2 #define IN3VAL bmBit3 #define IN4VAL bmBit4 #define IN5VAL bmBit5 #define IN6VAL bmBit6 #define IN7VAL bmBit7 SFRX(OUT07VAL, 0x7FDF); /* Bit 0 is read-only, always reads '1' */ #define OUT1VAL bmBit1 #define OUT2VAL bmBit2 #define OUT3VAL bmBit3 #define OUT4VAL bmBit4 #define OUT5VAL bmBit5 #define OUT6VAL bmBit6 #define OUT7VAL bmBit7 SFRX(INISOVAL, 0x7FE0); #define IN8VAL bmBit0 #define IN9VAL bmBit1 #define IN10VAL bmBit2 #define IN11VAL bmBit3 #define IN12VAL bmBit4 #define IN13VAL bmBit5 #define IN14VAL bmBit6 #define IN15VAL bmBit7 SFRX(OUTISOVAL, 0x7FE1); #define OUT8VAL bmBit0 #define OUT9VAL bmBit1 #define OUT10VAL bmBit2 #define OUT11VAL bmBit3 #define OUT12VAL bmBit4 #define OUT13VAL bmBit5 #define OUT14VAL bmBit6 #define OUT15VAL bmBit7 SFRX(FASTXFR, 0x7FE2); #define WMOD0 bmBit0 #define WMOD1 bmBit1 #define WPOL bmBit2 #define RMOD0 bmBit3 #define RMOD1 bmBit4 #define RPOL bmBit5 #define FBLK bmBit6 #define FISO bmBit7 SFRX(AUTOPTRH, 0x7FE3); SFRX(AUTOPTRL, 0x7FE4); SFRX(AUTODATA, 0x7FE5); /* 0x7FE6 reserved */ /* 0x7FE7 reserved */ /******************************* Setup Data ********************************/ SFRX(SETUPDAT[8], 0x7FE8); /************************* Isochronous FIFO sizes **************************/ SFRX(OUT8ADDR, 0x7FF0); SFRX(OUT9ADDR, 0x7FF1); SFRX(OUT10ADDR, 0x7FF2); SFRX(OUT11ADDR, 0x7FF3); SFRX(OUT12ADDR, 0x7FF4); SFRX(OUT13ADDR, 0x7FF5); SFRX(OUT14ADDR, 0x7FF6); SFRX(OUT15ADDR, 0x7FF7); SFRX(IN8ADDR, 0x7FF8); SFRX(IN9ADDR, 0x7FF9); SFRX(IN10ADDR, 0x7FFA); SFRX(IN11ADDR, 0x7FFB); SFRX(IN12ADDR, 0x7FFC); SFRX(IN13ADDR, 0x7FFD); SFRX(IN14ADDR, 0x7FFE); SFRX(IN15ADDR, 0x7FFF); #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/include/usb.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ #ifndef __USB_H #define __USB_H #include "reg_ezusb.h" #include <stdint.h> #include <stdbool.h> #define NULL (void *)0; /* High and Low byte of a word (uint16_t) */ #define HI8(word) (uint8_t)(((uint16_t)word >> 8) & 0xff) #define LO8(word) (uint8_t)((uint16_t)word & 0xff) /* Convenience functions */ #define STALL_EP0() (EP0CS |= EP0STALL) #define CLEAR_IRQ() (EXIF &= ~USBINT) /*********** USB descriptors. See section 9.5 of the USB 1.1 spec **********/ /* USB Descriptor Types. See USB 1.1 spec, page 187, table 9-5 */ #define DESCRIPTOR_TYPE_DEVICE 0x01 #define DESCRIPTOR_TYPE_CONFIGURATION 0x02 #define DESCRIPTOR_TYPE_STRING 0x03 #define DESCRIPTOR_TYPE_INTERFACE 0x04 #define DESCRIPTOR_TYPE_ENDPOINT 0x05 #define STR_DESCR(len, ...) { len * 2 + 2, DESCRIPTOR_TYPE_STRING, { __VA_ARGS__ } } /** USB Device Descriptor. See USB 1.1 spec, pp. 196 - 198 */ struct usb_device_descriptor { uint8_t bLength; /**< Size of this descriptor in bytes. */ uint8_t bDescriptorType; /**< DEVICE Descriptor Type. */ uint16_t bcdUSB; /**< USB specification release number (BCD). */ uint8_t bDeviceClass; /**< Class code. */ uint8_t bDeviceSubClass; /**< Subclass code. */ uint8_t bDeviceProtocol; /**< Protocol code. */ uint8_t bMaxPacketSize0; /**< Maximum packet size for EP0 (8, 16, 32, 64). */ uint16_t idVendor; /**< USB Vendor ID. */ uint16_t idProduct; /**< USB Product ID. */ uint16_t bcdDevice; /**< Device Release Number (BCD). */ uint8_t iManufacturer; /**< Index of manufacturer string descriptor. */ uint8_t iProduct; /**< Index of product string descriptor. */ uint8_t iSerialNumber; /**< Index of string descriptor containing serial #. */ uint8_t bNumConfigurations; /**< Number of possible configurations. */ }; /** USB Configuration Descriptor. See USB 1.1 spec, pp. 199 - 200 */ struct usb_config_descriptor { uint8_t bLength; /**< Size of this descriptor in bytes. */ uint8_t bDescriptorType; /**< CONFIGURATION descriptor type. */ uint16_t wTotalLength; /**< Combined total length of all descriptors. */ uint8_t bNumInterfaces; /**< Number of interfaces in this configuration. */ uint8_t bConfigurationValue; /**< Value used to select this configuration. */ uint8_t iConfiguration; /**< Index of configuration string descriptor. */ uint8_t bmAttributes; /**< Configuration characteristics. */ uint8_t MaxPower; /**< Maximum power consumption in 2 mA units. */ }; /** USB Interface Descriptor. See USB 1.1 spec, pp. 201 - 203 */ struct usb_interface_descriptor { uint8_t bLength; /**< Size of this descriptor in bytes. */ uint8_t bDescriptorType; /**< INTERFACE descriptor type. */ uint8_t bInterfaceNumber; /**< Interface number. */ uint8_t bAlternateSetting; /**< Value used to select alternate setting. */ uint8_t bNumEndpoints; /**< Number of endpoints used by this interface. */ uint8_t bInterfaceClass; /**< Class code. */ uint8_t bInterfaceSubclass; /**< Subclass code. */ uint8_t bInterfaceProtocol; /**< Protocol code. */ uint8_t iInterface; /**< Index of interface string descriptor. */ }; /** USB Endpoint Descriptor. See USB 1.1 spec, pp. 203 - 204 */ struct usb_endpoint_descriptor { uint8_t bLength; /**< Size of this descriptor in bytes. */ uint8_t bDescriptorType; /**< ENDPOINT descriptor type. */ uint8_t bEndpointAddress; /**< Endpoint Address: USB 1.1 spec, table 9-10. */ uint8_t bmAttributes; /**< Endpoint Attributes: USB 1.1 spec, table 9-10. */ uint16_t wMaxPacketSize; /**< Maximum packet size for this endpoint. */ uint8_t bInterval; /**< Polling interval (in ms) for this endpoint. */ }; /** USB Language Descriptor. See USB 1.1 spec, pp. 204 - 205 */ struct usb_language_descriptor { uint8_t bLength; /**< Size of this descriptor in bytes. */ uint8_t bDescriptorType; /**< STRING descriptor type. */ uint16_t wLANGID[]; /**< LANGID codes. */ }; /** USB String Descriptor. See USB 1.1 spec, pp. 204 - 205 */ struct usb_string_descriptor { uint8_t bLength; /**< Size of this descriptor in bytes. */ uint8_t bDescriptorType; /**< STRING descriptor type. */ uint16_t bString[]; /**< UNICODE encoded string. */ }; /********************** USB Control Endpoint 0 related *********************/ /** USB Control Setup Data. See USB 1.1 spec, pp. 183 - 185 */ struct setup_data { uint8_t bmRequestType; /**< Characteristics of a request. */ uint8_t bRequest; /**< Specific request. */ uint16_t wValue; /**< Field that varies according to request. */ uint16_t wIndex; /**< Field that varies according to request. */ uint16_t wLength; /**< Number of bytes to transfer in data stage. */ }; /* External declarations for variables that need to be accessed outside of * the USB module */ extern volatile bool EP2_out; extern volatile bool EP2_in; extern volatile __xdata __at 0x7FE8 struct setup_data setup_data; /* * USB Request Types (bmRequestType): See USB 1.1 spec, page 183, table 9-2 * * Bit 7: Data transfer direction * 0 = Host-to-device * 1 = Device-to-host * Bit 6...5: Type * 0 = Standard * 1 = Class * 2 = Vendor * 3 = Reserved * Bit 4...0: Recipient * 0 = Device * 1 = Interface * 2 = Endpoint * 3 = Other * 4...31 = Reserved */ #define USB_DIR_OUT 0x00 #define USB_DIR_IN 0x80 #define USB_REQ_TYPE_STANDARD (0x00 << 5) #define USB_REQ_TYPE_CLASS (0x01 << 5) #define USB_REQ_TYPE_VENDOR (0x02 << 5) #define USB_REQ_TYPE_RESERVED (0x03 << 5) #define USB_RECIP_DEVICE 0x00 #define USB_RECIP_INTERFACE 0x01 #define USB_RECIP_ENDPOINT 0x02 #define USB_RECIP_OTHER 0x03 /* bmRequestType for USB Standard Requests */ /* Clear Interface Request */ #define CF_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) #define CF_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) #define CF_ENDPOINT (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) /* Get Configuration Request */ #define GC_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) /* Get Descriptor Request */ #define GD_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) /* Get Interface Request */ #define GI_INTERFACE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) /* Get Status Request: See USB 1.1 spec, page 190 */ #define GS_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) #define GS_INTERFACE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) #define GS_ENDPOINT (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) /* Set Address Request is handled by EZ-USB core */ /* Set Configuration Request */ #define SC_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) /* Set Descriptor Request */ #define SD_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) /* Set Feature Request */ #define SF_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) #define SF_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) #define SF_ENDPOINT (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) /* Set Interface Request */ #define SI_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) /* Synch Frame Request */ #define SY_ENDPOINT (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) /* USB Requests (bRequest): See USB 1.1 spec, table 9-4 on page 187 */ #define GET_STATUS 0 #define CLEAR_FEATURE 1 /* Value '2' is reserved for future use */ #define SET_FEATURE 3 /* Value '4' is reserved for future use */ #define SET_ADDRESS 5 #define GET_DESCRIPTOR 6 #define SET_DESCRIPTOR 7 #define GET_CONFIGURATION 8 #define SET_CONFIGURATION 9 #define GET_INTERFACE 10 #define SET_INTERFACE 11 #define SYNCH_FRAME 12 /* Standard Feature Selectors: See USB 1.1 spec, table 9-6 on page 188 */ #define DEVICE_REMOTE_WAKEUP 1 #define ENDPOINT_HALT 0 /************************** EZ-USB specific stuff **************************/ /** USB Interrupts. See AN2131-TRM, page 9-4 for details */ enum usb_isr { SUDAV_ISR = 13, SOF_ISR, SUTOK_ISR, SUSPEND_ISR, USBRESET_ISR, IBN_ISR, EP0IN_ISR, EP0OUT_ISR, EP1IN_ISR, EP1OUT_ISR, EP2IN_ISR, EP2OUT_ISR, EP3IN_ISR, EP3OUT_ISR, EP4IN_ISR, EP4OUT_ISR, EP5IN_ISR, EP5OUT_ISR, EP6IN_ISR, EP6OUT_ISR, EP7IN_ISR, EP7OUT_ISR }; /*************************** Function Prototypes ***************************/ __xdata uint8_t *usb_get_endpoint_cs_reg(uint8_t ep); void usb_reset_data_toggle(uint8_t ep); bool usb_handle_get_status(void); bool usb_handle_clear_feature(void); bool usb_handle_set_feature(void); bool usb_handle_get_descriptor(void); void usb_handle_set_interface(void); void usb_handle_setup_data(void); void usb_init(void); #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/src/USBJmpTb.a51 ================================================ ; SPDX-License-Identifier: GPL-2.0-or-later ; ; Copyright (C) 2011-2013 by Martin Schmoelzer ; <martin.schmoelzer@student.tuwien.ac.at> ; .module JUMPTABLE .globl USB_AutoVector .globl USB_Jump_Table ;--------------------------------------------------------------------------; ; Interrupt Vectors ; ;--------------------------------------------------------------------------; .area USB_JV (ABS,OVR) ; Absolute, Overlay .org 0x43 ; USB interrupt (INT2) jumps here USB_AutoVector = #. + 2 ljmp USB_Jump_Table ;--------------------------------------------------------------------------; ; USB Jump Table ; ;--------------------------------------------------------------------------; .area USB_JT (ABS) ; Absolute placement .org 0x1B00 ; Place jump table at 0x1B00 USB_Jump_Table: ; autovector jump table ljmp _sudav_isr ; Setup Data Available .db 0 ljmp _sof_isr ; Start of Frame .db 0 ljmp _sutok_isr ; Setup Data Loading .db 0 ljmp _suspend_isr ; Global Suspend .db 0 ljmp _usbreset_isr ; USB Reset .db 0 ljmp _ibn_isr ; IN Bulk NAK interrupt .db 0 ljmp _ep0in_isr ; Endpoint 0 IN .db 0 ljmp _ep0out_isr ; Endpoint 0 OUT .db 0 ljmp _ep1in_isr ; Endpoint 1 IN .db 0 ljmp _ep1out_isr ; Endpoint 1 OUT .db 0 ljmp _ep2in_isr ; Endpoint 2 IN .db 0 ljmp _ep2out_isr ; Endpoint 2 OUT .db 0 ljmp _ep3in_isr ; Endpoint 3 IN .db 0 ljmp _ep3out_isr ; Endpoint 3 OUT .db 0 ljmp _ep4in_isr ; Endpoint 4 IN .db 0 ljmp _ep4out_isr ; Endpoint 4 OUT .db 0 ljmp _ep5in_isr ; Endpoint 5 IN .db 0 ljmp _ep5out_isr ; Endpoint 5 OUT .db 0 ljmp _ep6in_isr ; Endpoint 6 IN .db 0 ljmp _ep6out_isr ; Endpoint 6 OUT .db 0 ljmp _ep7in_isr ; Endpoint 7 IN .db 0 ljmp _ep7out_isr ; Endpoint 7 OUT .db 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/src/delay.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ #include "delay.h" void delay_5us(void) { NOP; } void delay_1ms(void) { uint16_t i; for (i = 0; i < 598; i++) ; } void delay_us(uint16_t delay) { uint16_t i; uint16_t maxcount = (delay / 5); for (i = 0; i < maxcount; i++) delay_5us(); } void delay_ms(uint16_t delay) { uint16_t i; for (i = 0; i < delay; i++) delay_1ms(); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/src/jtag.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ #include "jtag.h" #include "io.h" #include "msgtypes.h" #include "common.h" #include <stdbool.h> /** Delay value for SCAN_IN operations with less than maximum TCK frequency */ uint8_t delay_scan_in; /** Delay value for SCAN_OUT operations with less than maximum TCK frequency */ uint8_t delay_scan_out; /** Delay value for SCAN_IO operations with less than maximum TCK frequency */ uint8_t delay_scan_io; /** Delay value for CLOCK_TCK operations with less than maximum frequency */ uint8_t delay_tck; /** Delay value for CLOCK_TMS operations with less than maximum frequency */ uint8_t delay_tms; /** * Perform JTAG SCAN-IN operation at maximum TCK frequency. * * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and * stored in the EP2 IN buffer. * * Maximum achievable TCK frequency is 182 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts * @param in_offset */ void jtag_scan_in(uint8_t out_offset, uint8_t in_offset) { uint8_t scan_size_bytes, bits_last_byte; uint8_t tms_count_start, tms_count_end; uint8_t tms_sequence_start, tms_sequence_end; uint8_t tdo_data, i, j; uint8_t outb_buffer; /* Get parameters from OUT2BUF */ scan_size_bytes = OUT2BUF[out_offset]; bits_last_byte = OUT2BUF[out_offset + 1]; tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; tms_sequence_start = OUT2BUF[out_offset + 3]; tms_sequence_end = OUT2BUF[out_offset + 4]; if (tms_count_start > 0) jtag_clock_tms(tms_count_start, tms_sequence_start); outb_buffer = OUTB & ~(PIN_TDI | PIN_TCK | PIN_TMS); /* Shift all bytes except the last byte */ for (i = 0; i < scan_size_bytes - 1; i++) { tdo_data = 0; for (j = 0; j < 8; j++) { OUTB = outb_buffer; /* TCK changes here */ tdo_data = tdo_data >> 1; OUTB = (outb_buffer | PIN_TCK); if (GET_TDO()) tdo_data |= 0x80; } /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; } tdo_data = 0; /* Shift the last byte */ for (j = 0; j < bits_last_byte; j++) { /* Assert TMS signal if requested and this is the last bit */ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { outb_buffer |= PIN_TMS; tms_count_end--; tms_sequence_end = tms_sequence_end >> 1; } OUTB = outb_buffer; /* TCK changes here */ tdo_data = tdo_data >> 1; OUTB = (outb_buffer | PIN_TCK); if (GET_TDO()) tdo_data |= 0x80; } tdo_data = tdo_data >> (8 - bits_last_byte); /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; /* Move to correct end state */ if (tms_count_end > 0) jtag_clock_tms(tms_count_end, tms_sequence_end); } /** * Perform JTAG SCAN-IN operation at variable TCK frequency. * * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and * stored in the EP2 IN buffer. * * Maximum achievable TCK frequency is 113 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts * @param in_offset */ void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset) { uint8_t scan_size_bytes, bits_last_byte; uint8_t tms_count_start, tms_count_end; uint8_t tms_sequence_start, tms_sequence_end; uint8_t tdo_data, i, j, k; uint8_t outb_buffer; /* Get parameters from OUT2BUF */ scan_size_bytes = OUT2BUF[out_offset]; bits_last_byte = OUT2BUF[out_offset + 1]; tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; tms_sequence_start = OUT2BUF[out_offset + 3]; tms_sequence_end = OUT2BUF[out_offset + 4]; if (tms_count_start > 0) jtag_slow_clock_tms(tms_count_start, tms_sequence_start); outb_buffer = OUTB & ~(PIN_TDI | PIN_TCK | PIN_TMS); /* Shift all bytes except the last byte */ for (i = 0; i < scan_size_bytes - 1; i++) { tdo_data = 0; for (j = 0; j < 8; j++) { OUTB = outb_buffer; /* TCK changes here */ for (k = 0; k < delay_scan_in; k++) ; tdo_data = tdo_data >> 1; OUTB = (outb_buffer | PIN_TCK); for (k = 0; k < delay_scan_in; k++) ; if (GET_TDO()) tdo_data |= 0x80; } /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; } tdo_data = 0; /* Shift the last byte */ for (j = 0; j < bits_last_byte; j++) { /* Assert TMS signal if requested and this is the last bit */ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { outb_buffer |= PIN_TMS; tms_count_end--; tms_sequence_end = tms_sequence_end >> 1; } OUTB = outb_buffer; /* TCK changes here */ for (k = 0; k < delay_scan_in; k++) ; tdo_data = tdo_data >> 1; OUTB = (outb_buffer | PIN_TCK); for (k = 0; k < delay_scan_in; k++) ; if (GET_TDO()) tdo_data |= 0x80; } tdo_data = tdo_data >> (8 - bits_last_byte); /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; /* Move to correct end state */ if (tms_count_end > 0) jtag_slow_clock_tms(tms_count_end, tms_sequence_end); } /** * Perform JTAG SCAN-OUT operation at maximum TCK frequency. * * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO * data is not sampled. * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. * * Maximum achievable TCK frequency is 142 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts */ void jtag_scan_out(uint8_t out_offset) { uint8_t scan_size_bytes, bits_last_byte; uint8_t tms_count_start, tms_count_end; uint8_t tms_sequence_start, tms_sequence_end; uint8_t tdi_data, i, j; uint8_t outb_buffer; /* Get parameters from OUT2BUF */ scan_size_bytes = OUT2BUF[out_offset]; bits_last_byte = OUT2BUF[out_offset + 1]; tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; tms_sequence_start = OUT2BUF[out_offset + 3]; tms_sequence_end = OUT2BUF[out_offset + 4]; if (tms_count_start > 0) jtag_clock_tms(tms_count_start, tms_sequence_start); outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS); /* Shift all bytes except the last byte */ for (i = 0; i < scan_size_bytes - 1; i++) { tdi_data = OUT2BUF[i + out_offset + 5]; for (j = 0; j < 8; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; OUTB = outb_buffer; /* TDI and TCK change here */ tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); } } tdi_data = OUT2BUF[i + out_offset + 5]; /* Shift the last byte */ for (j = 0; j < bits_last_byte; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; /* Assert TMS signal if requested and this is the last bit */ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { outb_buffer |= PIN_TMS; tms_count_end--; tms_sequence_end = tms_sequence_end >> 1; } OUTB = outb_buffer; /* TDI and TCK change here */ tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); } /* Move to correct end state */ if (tms_count_end > 0) jtag_clock_tms(tms_count_end, tms_sequence_end); } /** * Perform JTAG SCAN-OUT operation at maximum TCK frequency. * * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO * data is not sampled. * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. * * Maximum achievable TCK frequency is 97 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts */ void jtag_slow_scan_out(uint8_t out_offset) { uint8_t scan_size_bytes, bits_last_byte; uint8_t tms_count_start, tms_count_end; uint8_t tms_sequence_start, tms_sequence_end; uint8_t tdi_data, i, j, k; uint8_t outb_buffer; /* Get parameters from OUT2BUF */ scan_size_bytes = OUT2BUF[out_offset]; bits_last_byte = OUT2BUF[out_offset + 1]; tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; tms_sequence_start = OUT2BUF[out_offset + 3]; tms_sequence_end = OUT2BUF[out_offset + 4]; if (tms_count_start > 0) jtag_slow_clock_tms(tms_count_start, tms_sequence_start); outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS); /* Shift all bytes except the last byte */ for (i = 0; i < scan_size_bytes - 1; i++) { tdi_data = OUT2BUF[i + out_offset + 5]; for (j = 0; j < 8; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; OUTB = outb_buffer; /* TDI and TCK change here */ for (k = 0; k < delay_scan_out; k++) ; tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); for (k = 0; k < delay_scan_out; k++) ; } } tdi_data = OUT2BUF[i + out_offset + 5]; /* Shift the last byte */ for (j = 0; j < bits_last_byte; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; /* Assert TMS signal if requested and this is the last bit */ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { outb_buffer |= PIN_TMS; tms_count_end--; tms_sequence_end = tms_sequence_end >> 1; } OUTB = outb_buffer; /* TDI and TCK change here */ for (k = 0; k < delay_scan_out; k++) ; tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); for (k = 0; k < delay_scan_out; k++) ; } /* Move to correct end state */ if (tms_count_end > 0) jtag_slow_clock_tms(tms_count_end, tms_sequence_end); } /** * Perform bidirectional JTAG SCAN operation at maximum TCK frequency. * * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO * data is sampled and stored in the EP2 IN buffer. * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. * * Maximum achievable TCK frequency is 100 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts * @param in_offset */ void jtag_scan_io(uint8_t out_offset, uint8_t in_offset) { uint8_t scan_size_bytes, bits_last_byte; uint8_t tms_count_start, tms_count_end; uint8_t tms_sequence_start, tms_sequence_end; uint8_t tdi_data, tdo_data, i, j; uint8_t outb_buffer; /* Get parameters from OUT2BUF */ scan_size_bytes = OUT2BUF[out_offset]; bits_last_byte = OUT2BUF[out_offset + 1]; tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; tms_sequence_start = OUT2BUF[out_offset + 3]; tms_sequence_end = OUT2BUF[out_offset + 4]; if (tms_count_start > 0) jtag_clock_tms(tms_count_start, tms_sequence_start); outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS); /* Shift all bytes except the last byte */ for (i = 0; i < scan_size_bytes - 1; i++) { tdi_data = OUT2BUF[i + out_offset + 5]; tdo_data = 0; for (j = 0; j < 8; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; OUTB = outb_buffer; /* TDI and TCK change here */ tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); tdo_data = tdo_data >> 1; if (GET_TDO()) tdo_data |= 0x80; } /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; } tdi_data = OUT2BUF[i + out_offset + 5]; tdo_data = 0; /* Shift the last byte */ for (j = 0; j < bits_last_byte; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; /* Assert TMS signal if requested and this is the last bit */ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { outb_buffer |= PIN_TMS; tms_count_end--; tms_sequence_end = tms_sequence_end >> 1; } OUTB = outb_buffer; /* TDI and TCK change here */ tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); tdo_data = tdo_data >> 1; if (GET_TDO()) tdo_data |= 0x80; } tdo_data = tdo_data >> (8 - bits_last_byte); /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; /* Move to correct end state */ if (tms_count_end > 0) jtag_clock_tms(tms_count_end, tms_sequence_end); } /** * Perform bidirectional JTAG SCAN operation at maximum TCK frequency. * * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO * data is sampled and stored in the EP2 IN buffer. * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. * * Maximum achievable TCK frequency is 78 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts * @param in_offset */ void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset) { uint8_t scan_size_bytes, bits_last_byte; uint8_t tms_count_start, tms_count_end; uint8_t tms_sequence_start, tms_sequence_end; uint8_t tdi_data, tdo_data, i, j, k; uint8_t outb_buffer; /* Get parameters from OUT2BUF */ scan_size_bytes = OUT2BUF[out_offset]; bits_last_byte = OUT2BUF[out_offset + 1]; tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; tms_sequence_start = OUT2BUF[out_offset + 3]; tms_sequence_end = OUT2BUF[out_offset + 4]; if (tms_count_start > 0) jtag_slow_clock_tms(tms_count_start, tms_sequence_start); outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS); /* Shift all bytes except the last byte */ for (i = 0; i < scan_size_bytes - 1; i++) { tdi_data = OUT2BUF[i + out_offset + 5]; tdo_data = 0; for (j = 0; j < 8; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; OUTB = outb_buffer; /* TDI and TCK change here */ for (k = 0; k < delay_scan_io; k++) ; tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); for (k = 0; k < delay_scan_io; k++) ; tdo_data = tdo_data >> 1; if (GET_TDO()) tdo_data |= 0x80; } /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; } tdi_data = OUT2BUF[i + out_offset + 5]; tdo_data = 0; /* Shift the last byte */ for (j = 0; j < bits_last_byte; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; /* Assert TMS signal if requested and this is the last bit */ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { outb_buffer |= PIN_TMS; tms_count_end--; tms_sequence_end = tms_sequence_end >> 1; } OUTB = outb_buffer; /* TDI and TCK change here */ for (k = 0; k < delay_scan_io; k++) ; tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); for (k = 0; k < delay_scan_io; k++) ; tdo_data = tdo_data >> 1; if (GET_TDO()) tdo_data |= 0x80; } tdo_data = tdo_data >> (8 - bits_last_byte); /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; /* Move to correct end state */ if (tms_count_end > 0) jtag_slow_clock_tms(tms_count_end, tms_sequence_end); } /** * Generate TCK clock cycles. * * Maximum achievable TCK frequency is 375 kHz for ULINK clocked at 24 MHz. * * @param count number of TCK clock cycles to generate. */ void jtag_clock_tck(uint16_t count) { uint16_t i; uint8_t outb_buffer = OUTB & ~(PIN_TCK); for (i = 0; i < count; i++) { OUTB = outb_buffer; OUTB = outb_buffer | PIN_TCK; } } /** * Generate TCK clock cycles at variable frequency. * * Maximum achievable TCK frequency is 166.6 kHz for ULINK clocked at 24 MHz. * * @param count number of TCK clock cycles to generate. */ void jtag_slow_clock_tck(uint16_t count) { uint16_t i; uint8_t j; uint8_t outb_buffer = OUTB & ~(PIN_TCK); for (i = 0; i < count; i++) { OUTB = outb_buffer; for (j = 0; j < delay_tck; j++) ; OUTB = outb_buffer | PIN_TCK; for (j = 0; j < delay_tck; j++) ; } } /** * Perform TAP FSM state transitions at maximum TCK frequency. * * Maximum achievable TCK frequency is 176 kHz for ULINK clocked at 24 MHz. * * @param count the number of state transitions to perform. * @param sequence the TMS pin levels for each state transition, starting with * the least-significant bit. */ void jtag_clock_tms(uint8_t count, uint8_t sequence) { uint8_t outb_buffer = OUTB & ~(PIN_TCK); uint8_t i; for (i = 0; i < count; i++) { /* Set TMS pin according to sequence parameter */ if (sequence & 0x1) outb_buffer |= PIN_TMS; else outb_buffer &= ~PIN_TMS; OUTB = outb_buffer; sequence = sequence >> 1; OUTB = outb_buffer | PIN_TCK; } } /** * Perform TAP-FSM state transitions at less than maximum TCK frequency. * * Maximum achievable TCK frequency is 117 kHz for ULINK clocked at 24 MHz. * * @param count the number of state transitions to perform. * @param sequence the TMS pin levels for each state transition, starting with * the least-significant bit. */ void jtag_slow_clock_tms(uint8_t count, uint8_t sequence) { uint8_t outb_buffer = OUTB & ~(PIN_TCK); uint8_t i, j; for (i = 0; i < count; i++) { /* Set TMS pin according to sequence parameter */ if (sequence & 0x1) outb_buffer |= PIN_TMS; else outb_buffer &= ~PIN_TMS; OUTB = outb_buffer; for (j = 0; j < delay_tms; j++) ; sequence = sequence >> 1; OUTB = outb_buffer | PIN_TCK; for (j = 0; j < delay_tms; j++) ; } } /** * Get current JTAG signal states. * * @return a 16-bit integer where the most-significant byte contains the state * of the JTAG input signals and the least-significant byte contains the state * of the JTAG output signals. */ uint16_t jtag_get_signals(void) { uint8_t input_signal_state, output_signal_state; input_signal_state = 0; output_signal_state = 0; /* Get states of input pins */ if (GET_TDO()) input_signal_state |= SIGNAL_TDO; if (GET_BRKOUT()) input_signal_state |= SIGNAL_BRKOUT; if (GET_TRAP()) input_signal_state |= SIGNAL_TRAP; if (GET_RTCK()) { /* Using RTCK this way would be extremely slow, * implemented only for the sake of completeness */ input_signal_state |= SIGNAL_RTCK; } /* Get states of output pins */ output_signal_state = PINSB & MASK_PORTB_DIRECTION_OUT; return ((uint16_t)input_signal_state << 8) | ((uint16_t)output_signal_state); } /** * Set state of JTAG output signals. * * @param low signals which should be de-asserted. * @param high signals which should be asserted. */ void jtag_set_signals(uint8_t low, uint8_t high) { OUTB &= ~(low & MASK_PORTB_DIRECTION_OUT); OUTB |= (high & MASK_PORTB_DIRECTION_OUT); } /** * Configure TCK delay parameters. * * @param scan_in number of delay cycles in scan_in operations. * @param scan_out number of delay cycles in scan_out operations. * @param scan_io number of delay cycles in scan_io operations. * @param tck number of delay cycles in clock_tck operations. * @param tms number of delay cycles in clock_tms operations. */ void jtag_configure_tck_delay(uint8_t scan_in, uint8_t scan_out, uint8_t scan_io, uint8_t tck, uint8_t tms) { delay_scan_in = scan_in; delay_scan_out = scan_out; delay_scan_io = scan_io; delay_tck = tck; delay_tms = tms; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/src/main.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ #include "main.h" #include "io.h" #include "usb.h" #include "protocol.h" extern void sudav_isr(void) __interrupt SUDAV_ISR; extern void sof_isr(void) __interrupt; extern void sutok_isr(void) __interrupt; extern void suspend_isr(void) __interrupt; extern void usbreset_isr(void) __interrupt; extern void ibn_isr(void) __interrupt; extern void ep0in_isr(void) __interrupt; extern void ep0out_isr(void) __interrupt; extern void ep1in_isr(void) __interrupt; extern void ep1out_isr(void) __interrupt; extern void ep2in_isr(void) __interrupt; extern void ep2out_isr(void) __interrupt; extern void ep3in_isr(void) __interrupt; extern void ep3out_isr(void) __interrupt; extern void ep4in_isr(void) __interrupt; extern void ep4out_isr(void) __interrupt; extern void ep5in_isr(void) __interrupt; extern void ep5out_isr(void) __interrupt; extern void ep6in_isr(void) __interrupt; extern void ep6out_isr(void) __interrupt; extern void ep7in_isr(void) __interrupt; extern void ep7out_isr(void) __interrupt; void io_init(void) { /* PORTxCFG register bits select alternate functions (1 == alternate function, * 0 == standard I/O) * OEx register bits turn on/off output buffer (1 == output, 0 == input) * OUTx register bits determine pin state of output * PINx register bits reflect pin state (high == 1, low == 0) */ /* PORT A */ PORTACFG = PIN_OE; OEA = PIN_U_OE | PIN_OE | PIN_RUN_LED | PIN_COM_LED; OUTA = PIN_RUN_LED | PIN_COM_LED; /* PORT B */ PORTBCFG = 0x00; OEB = PIN_TDI | PIN_TMS | PIN_TCK | PIN_TRST | PIN_BRKIN | PIN_RESET | PIN_OCDSE; /* TRST and RESET signals are low-active but inverted by hardware, so we clear * these signals here! */ OUTB = 0x00; /* PORT C */ PORTCCFG = PIN_WR; OEC = PIN_TXD0 | PIN_WR; OUTC = 0x00; } int main(void) { io_init(); usb_init(); /* Enable Interrupts */ EA = 1; /* Begin executing command(s). This function never returns. */ command_loop(); /* Never reached, but SDCC complains about missing return statement */ return 0; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/src/protocol.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ #include "protocol.h" #include "jtag.h" #include "delay.h" #include "usb.h" #include "io.h" #include "msgtypes.h" #include "reg_ezusb.h" /** * @file * Implementation of the OpenULINK communication protocol. * * The OpenULINK protocol uses one OUT and one IN endpoint. These two endpoints * are configured to use the maximum packet size for full-speed transfers, * 64 bytes. Commands always start with a command ID (see msgtypes.h for * command ID definitions) and contain zero or more payload data bytes in both * transfer directions (IN and OUT). The payload * * Almost all commands contain a fixed number of payload data bytes. The number * of payload data bytes for the IN and OUT direction does not need to be the * same. * * Multiple commands may be sent in one EP2 Bulk-OUT packet. Because the * OpenULINK firmware does not perform bounds checking for EP2 Bulk-IN packets, * the host MUST ensure that the commands sent in the OUT packet require a * maximum of 64 bytes of IN data. */ /** Index in EP2 Bulk-OUT data buffer that contains the current command ID */ volatile uint8_t cmd_id_index; /** Number of data bytes already in EP2 Bulk-IN buffer */ volatile uint8_t payload_index_in; /** * Execute a SET_LEDS command. */ void execute_set_led_command(void) { uint8_t led_state = OUT2BUF[cmd_id_index + 1]; if (led_state & RUN_LED_ON) SET_RUN_LED(); if (led_state & COM_LED_ON) SET_COM_LED(); if (led_state & RUN_LED_OFF) CLEAR_RUN_LED(); if (led_state & COM_LED_OFF) CLEAR_COM_LED(); } /** * Executes one command and updates global command indexes. * * @return true if this command was the last command. * @return false if there are more commands within the current contents of the * Bulk EP2-OUT data buffer. */ bool execute_command(void) { uint8_t usb_out_bytecount, usb_in_bytecount; uint16_t signal_state; uint16_t count; /* Most commands do not transfer IN data. To save code space, we write 0 to * usb_in_bytecount here, then modify it in the switch statement below where * necessary */ usb_in_bytecount = 0; switch (OUT2BUF[cmd_id_index] /* Command ID */) { case CMD_SCAN_IN: usb_out_bytecount = 5; usb_in_bytecount = OUT2BUF[cmd_id_index + 1]; jtag_scan_in(cmd_id_index + 1, payload_index_in); break; case CMD_SCAN_OUT: usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5; jtag_scan_out(cmd_id_index + 1); break; case CMD_SCAN_IO: usb_in_bytecount = OUT2BUF[cmd_id_index + 1]; usb_out_bytecount = usb_in_bytecount + 5; jtag_scan_io(cmd_id_index + 1, payload_index_in); break; case CMD_CLOCK_TMS: usb_out_bytecount = 2; jtag_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]); break; case CMD_CLOCK_TCK: usb_out_bytecount = 2; count = (uint16_t)OUT2BUF[cmd_id_index + 1]; count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8; jtag_clock_tck(count); break; case CMD_SLOW_SCAN_IN: usb_out_bytecount = 5; usb_in_bytecount = OUT2BUF[cmd_id_index + 1]; jtag_slow_scan_in(cmd_id_index + 1, payload_index_in); break; case CMD_SLOW_SCAN_OUT: usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5; jtag_slow_scan_out(cmd_id_index + 1); break; case CMD_SLOW_SCAN_IO: usb_in_bytecount = OUT2BUF[cmd_id_index + 1]; usb_out_bytecount = usb_in_bytecount + 5; jtag_slow_scan_io(cmd_id_index + 1, payload_index_in); break; case CMD_SLOW_CLOCK_TMS: usb_out_bytecount = 2; jtag_slow_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]); break; case CMD_SLOW_CLOCK_TCK: usb_out_bytecount = 2; count = (uint16_t)OUT2BUF[cmd_id_index + 1]; count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8; jtag_slow_clock_tck(count); break; case CMD_SLEEP_US: usb_out_bytecount = 2; count = (uint16_t)OUT2BUF[cmd_id_index + 1]; count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8; delay_us(count); break; case CMD_SLEEP_MS: usb_out_bytecount = 2; count = (uint16_t)OUT2BUF[cmd_id_index + 1]; count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8; delay_ms(count); break; case CMD_GET_SIGNALS: usb_out_bytecount = 0; usb_in_bytecount = 2; signal_state = jtag_get_signals(); IN2BUF[payload_index_in] = (signal_state >> 8) & 0x00FF; IN2BUF[payload_index_in + 1] = signal_state & 0x00FF; break; case CMD_SET_SIGNALS: usb_out_bytecount = 2; jtag_set_signals(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]); break; case CMD_CONFIGURE_TCK_FREQ: usb_out_bytecount = 5; jtag_configure_tck_delay( OUT2BUF[cmd_id_index + 1], /* scan_in */ OUT2BUF[cmd_id_index + 2], /* scan_out */ OUT2BUF[cmd_id_index + 3], /* scan_io */ OUT2BUF[cmd_id_index + 4], /* clock_tck */ OUT2BUF[cmd_id_index + 5]); /* clock_tms */ break; case CMD_SET_LEDS: usb_out_bytecount = 1; execute_set_led_command(); break; case CMD_TEST: usb_out_bytecount = 1; /* Do nothing... This command is only used to test if the device is ready * to accept new commands */ break; default: /* Should never be reached */ usb_out_bytecount = 0; break; } /* Update EP2 Bulk-IN data byte count */ payload_index_in += usb_in_bytecount; /* Determine if this was the last command */ if ((cmd_id_index + usb_out_bytecount + 1) >= OUT2BC) return true; else { /* Not the last command, update cmd_id_index */ cmd_id_index += (usb_out_bytecount + 1); return false; } } /** * Forever wait for commands and execute them as they arrive. */ void command_loop(void) { bool last_command; while (1) { cmd_id_index = 0; payload_index_in = 0; /* Wait until host sends EP2 Bulk-OUT packet */ while (!EP2_out) ; EP2_out = 0; /* Turn on COM LED to indicate command execution */ SET_COM_LED(); /* Execute the commands */ last_command = false; while (last_command == false) last_command = execute_command(); CLEAR_COM_LED(); /* Send back EP2 Bulk-IN packet if required */ if (payload_index_in > 0) { IN2BC = payload_index_in; while (!EP2_in) ; EP2_in = 0; } /* Re-arm EP2-OUT after command execution */ OUT2BC = 0; } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/src/usb.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011-2013 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ /** * @file * Defines USB descriptors, interrupt routines and helper functions. * To minimize code size, we make the following assumptions: * - The OpenULINK has exactly one configuration * - and exactly one alternate setting * * Therefore, we do not have to support the Set Configuration USB request. */ #include "usb.h" #include "delay.h" #include "io.h" /* Also update external declarations in "include/usb.h" if making changes to * these variables! */ volatile bool EP2_out; volatile bool EP2_in; volatile __xdata __at 0x7FE8 struct setup_data setup_data; /* Define number of endpoints (except Control Endpoint 0) in a central place. * Be sure to include the necessary endpoint descriptors! */ #define NUM_ENDPOINTS 2 __code struct usb_device_descriptor device_descriptor = { .bLength = sizeof(struct usb_device_descriptor), .bDescriptorType = DESCRIPTOR_TYPE_DEVICE, .bcdUSB = 0x0110, /* BCD: 01.00 (Version 1.0 USB spec) */ .bDeviceClass = 0xFF, /* 0xFF = vendor-specific */ .bDeviceSubClass = 0xFF, .bDeviceProtocol = 0xFF, .bMaxPacketSize0 = 64, .idVendor = 0xC251, .idProduct = 0x2710, .bcdDevice = 0x0100, .iManufacturer = 1, .iProduct = 2, .iSerialNumber = 3, .bNumConfigurations = 1 }; /* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */ __code struct usb_config_descriptor config_descriptor = { .bLength = sizeof(struct usb_config_descriptor), .bDescriptorType = DESCRIPTOR_TYPE_CONFIGURATION, .wTotalLength = sizeof(struct usb_config_descriptor) + sizeof(struct usb_interface_descriptor) + (NUM_ENDPOINTS * sizeof(struct usb_endpoint_descriptor)), .bNumInterfaces = 1, .bConfigurationValue = 1, .iConfiguration = 4, /* String describing this configuration */ .bmAttributes = 0x80, /* Only MSB set according to USB spec */ .MaxPower = 50 /* 100 mA */ }; __code struct usb_interface_descriptor interface_descriptor00 = { .bLength = sizeof(struct usb_interface_descriptor), .bDescriptorType = DESCRIPTOR_TYPE_INTERFACE, .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = NUM_ENDPOINTS, .bInterfaceClass = 0xFF, .bInterfaceSubclass = 0xFF, .bInterfaceProtocol = 0xFF, .iInterface = 0 }; __code struct usb_endpoint_descriptor Bulk_EP2_IN_Endpoint_Descriptor = { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = 0x05, .bEndpointAddress = (2 | USB_DIR_IN), .bmAttributes = 0x02, .wMaxPacketSize = 64, .bInterval = 0 }; __code struct usb_endpoint_descriptor Bulk_EP2_OUT_Endpoint_Descriptor = { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = 0x05, .bEndpointAddress = (2 | USB_DIR_OUT), .bmAttributes = 0x02, .wMaxPacketSize = 64, .bInterval = 0 }; __code struct usb_language_descriptor language_descriptor = { .bLength = 4, .bDescriptorType = DESCRIPTOR_TYPE_STRING, .wLANGID = {0x0409 /* US English */} }; __code struct usb_string_descriptor strManufacturer = STR_DESCR(9, 'O', 'p', 'e', 'n', 'U', 'L', 'I', 'N', 'K'); __code struct usb_string_descriptor strProduct = STR_DESCR(9, 'O', 'p', 'e', 'n', 'U', 'L', 'I', 'N', 'K'); __code struct usb_string_descriptor strSerialNumber = STR_DESCR(6, '0', '0', '0', '0', '0', '1'); __code struct usb_string_descriptor strConfigDescr = STR_DESCR(12, 'J', 'T', 'A', 'G', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r'); /* Table containing pointers to string descriptors */ __code struct usb_string_descriptor *__code en_string_descriptors[4] = { &strManufacturer, &strProduct, &strSerialNumber, &strConfigDescr }; void sudav_isr(void) __interrupt SUDAV_ISR { CLEAR_IRQ(); usb_handle_setup_data(); USBIRQ = SUDAVIR; EP0CS |= HSNAK; } void sof_isr(void) __interrupt SOF_ISR { } void sutok_isr(void) __interrupt SUTOK_ISR { } void suspend_isr(void) __interrupt SUSPEND_ISR { } void usbreset_isr(void) __interrupt USBRESET_ISR { } void ibn_isr(void) __interrupt IBN_ISR { } void ep0in_isr(void) __interrupt EP0IN_ISR { } void ep0out_isr(void) __interrupt EP0OUT_ISR { } void ep1in_isr(void) __interrupt EP1IN_ISR { } void ep1out_isr(void) __interrupt EP1OUT_ISR { } /** * EP2 IN: called after the transfer from uC->Host has finished: we sent data */ void ep2in_isr(void) __interrupt EP2IN_ISR { EP2_in = 1; CLEAR_IRQ(); IN07IRQ = IN2IR;/* Clear OUT2 IRQ */ } /** * EP2 OUT: called after the transfer from Host->uC has finished: we got data */ void ep2out_isr(void) __interrupt EP2OUT_ISR { EP2_out = 1; CLEAR_IRQ(); OUT07IRQ = OUT2IR; /* Clear OUT2 IRQ */ } void ep3in_isr(void) __interrupt EP3IN_ISR { } void ep3out_isr(void) __interrupt EP3OUT_ISR { } void ep4in_isr(void) __interrupt EP4IN_ISR { } void ep4out_isr(void) __interrupt EP4OUT_ISR { } void ep5in_isr(void) __interrupt EP5IN_ISR { } void ep5out_isr(void) __interrupt EP5OUT_ISR { } void ep6in_isr(void) __interrupt EP6IN_ISR { } void ep6out_isr(void) __interrupt EP6OUT_ISR { } void ep7in_isr(void) __interrupt EP7IN_ISR { } void ep7out_isr(void) __interrupt EP7OUT_ISR { } /** * Return the control/status register for an endpoint * * @param ep endpoint address * @return on success: pointer to Control & Status register for endpoint * specified in \a ep * @return on failure: NULL */ __xdata uint8_t *usb_get_endpoint_cs_reg(uint8_t ep) { /* Mask direction bit */ uint8_t ep_num = ep & 0x7F; switch (ep_num) { case 0: return &EP0CS; break; case 1: return ep & 0x80 ? &IN1CS : &OUT1CS; break; case 2: return ep & 0x80 ? &IN2CS : &OUT2CS; break; case 3: return ep & 0x80 ? &IN3CS : &OUT3CS; break; case 4: return ep & 0x80 ? &IN4CS : &OUT4CS; break; case 5: return ep & 0x80 ? &IN5CS : &OUT5CS; break; case 6: return ep & 0x80 ? &IN6CS : &OUT6CS; break; case 7: return ep & 0x80 ? &IN7CS : &OUT7CS; break; } return NULL; } void usb_reset_data_toggle(uint8_t ep) { /* TOGCTL register: +----+-----+-----+------+-----+-------+-------+-------+ | Q | S | R | IO | 0 | EP2 | EP1 | EP0 | +----+-----+-----+------+-----+-------+-------+-------+ To reset data toggle bits, we have to write the endpoint direction (IN/OUT) to the IO bit and the endpoint number to the EP2..EP0 bits. Then, in a separate write cycle, the R bit needs to be set. */ uint8_t togctl_value = (ep & 0x80 >> 3) | (ep & 0x7); /* First step: Write EP number and direction bit */ TOGCTL = togctl_value; /* Second step: Set R bit */ togctl_value |= TOG_R; TOGCTL = togctl_value; } /** * Handle GET_STATUS request. * * @return on success: true * @return on failure: false */ bool usb_handle_get_status(void) { uint8_t *ep_cs; switch (setup_data.bmRequestType) { case GS_DEVICE: /* Two byte response: Byte 0, Bit 0 = self-powered, Bit 1 = remote wakeup. * Byte 1: reserved, reset to zero */ IN0BUF[0] = 0; IN0BUF[1] = 0; /* Send response */ IN0BC = 2; break; case GS_INTERFACE: /* Always return two zero bytes according to USB 1.1 spec, p. 191 */ IN0BUF[0] = 0; IN0BUF[1] = 0; /* Send response */ IN0BC = 2; break; case GS_ENDPOINT: /* Get stall bit for endpoint specified in low byte of wIndex */ ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex & 0xff); if (*ep_cs & EPSTALL) IN0BUF[0] = 0x01; else IN0BUF[0] = 0x00; /* Second byte sent has to be always zero */ IN0BUF[1] = 0; /* Send response */ IN0BC = 2; break; default: return false; break; } return true; } /** * Handle CLEAR_FEATURE request. * * @return on success: true * @return on failure: false */ bool usb_handle_clear_feature(void) { __xdata uint8_t *ep_cs; switch (setup_data.bmRequestType) { case CF_DEVICE: /* Clear remote wakeup not supported: stall EP0 */ STALL_EP0(); break; case CF_ENDPOINT: if (setup_data.wValue == 0) { /* Unstall the endpoint specified in wIndex */ ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex); if (!ep_cs) return false; *ep_cs &= ~EPSTALL; } else { /* Unsupported feature, stall EP0 */ STALL_EP0(); } break; default: /* Vendor commands... */ } return true; } /** * Handle SET_FEATURE request. * * @return on success: true * @return on failure: false */ bool usb_handle_set_feature(void) { __xdata uint8_t *ep_cs; switch (setup_data.bmRequestType) { case SF_DEVICE: if (setup_data.wValue == 2) return true; break; case SF_ENDPOINT: if (setup_data.wValue == 0) { /* Stall the endpoint specified in wIndex */ ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex); if (!ep_cs) return false; *ep_cs |= EPSTALL; } else { /* Unsupported endpoint feature */ return false; } break; default: /* Vendor commands... */ break; } return true; } /** * Handle GET_DESCRIPTOR request. * * @return on success: true * @return on failure: false */ bool usb_handle_get_descriptor(void) { __xdata uint8_t descriptor_type; __xdata uint8_t descriptor_index; descriptor_type = (setup_data.wValue & 0xff00) >> 8; descriptor_index = setup_data.wValue & 0x00ff; switch (descriptor_type) { case DESCRIPTOR_TYPE_DEVICE: SUDPTRH = HI8(&device_descriptor); SUDPTRL = LO8(&device_descriptor); break; case DESCRIPTOR_TYPE_CONFIGURATION: SUDPTRH = HI8(&config_descriptor); SUDPTRL = LO8(&config_descriptor); break; case DESCRIPTOR_TYPE_STRING: if (setup_data.wIndex == 0) { /* Supply language descriptor */ SUDPTRH = HI8(&language_descriptor); SUDPTRL = LO8(&language_descriptor); } else if (setup_data.wIndex == 0x0409 /* US English */) { /* Supply string descriptor */ SUDPTRH = HI8(en_string_descriptors[descriptor_index - 1]); SUDPTRL = LO8(en_string_descriptors[descriptor_index - 1]); } else return false; break; default: /* Unsupported descriptor type */ return false; break; } return true; } /** * Handle SET_INTERFACE request. */ void usb_handle_set_interface(void) { /* Reset Data Toggle */ usb_reset_data_toggle(USB_DIR_IN | 2); usb_reset_data_toggle(USB_DIR_OUT | 2); /* Unstall & clear busy flag of all valid IN endpoints */ IN2CS = 0 | EPBSY; /* Unstall all valid OUT endpoints, reset bytecounts */ OUT2CS = 0; OUT2BC = 0; } /** * Handle the arrival of a USB Control Setup Packet. */ void usb_handle_setup_data(void) { switch (setup_data.bRequest) { case GET_STATUS: if (!usb_handle_get_status()) STALL_EP0(); break; case CLEAR_FEATURE: if (!usb_handle_clear_feature()) STALL_EP0(); break; case 2: case 4: /* Reserved values */ STALL_EP0(); break; case SET_FEATURE: if (!usb_handle_set_feature()) STALL_EP0(); break; case SET_ADDRESS: /* Handled by USB core */ break; case SET_DESCRIPTOR: /* Set Descriptor not supported. */ STALL_EP0(); break; case GET_DESCRIPTOR: if (!usb_handle_get_descriptor()) STALL_EP0(); break; case GET_CONFIGURATION: /* OpenULINK has only one configuration, return its index */ IN0BUF[0] = config_descriptor.bConfigurationValue; IN0BC = 1; break; case SET_CONFIGURATION: /* OpenULINK has only one configuration -> nothing to do */ break; case GET_INTERFACE: /* OpenULINK only has one interface, return its number */ IN0BUF[0] = interface_descriptor00.bInterfaceNumber; IN0BC = 1; break; case SET_INTERFACE: usb_handle_set_interface(); break; case SYNCH_FRAME: /* Isochronous endpoints not used -> nothing to do */ break; default: /* Any other requests: do nothing */ break; } } /** * USB initialization. Configures USB interrupts, endpoints and performs * ReNumeration. */ void usb_init(void) { /* Mark endpoint 2 IN & OUT as valid */ IN07VAL = IN2VAL; OUT07VAL = OUT2VAL; /* Make sure no isochronous endpoints are marked valid */ INISOVAL = 0; OUTISOVAL = 0; /* Disable isochronous endpoints. This makes the isochronous data buffers * available as 8051 XDATA memory at address 0x2000 - 0x27FF */ ISOCTL = ISODISAB; /* Enable USB Autovectoring */ USBBAV |= AVEN; /* Enable SUDAV interrupt */ USBIEN |= SUDAVIE; /* Enable EP2 OUT & IN interrupts */ OUT07IEN = OUT2IEN; IN07IEN = IN2IEN; /* Enable USB interrupt (EIE register) */ EUSB = 1; /* Perform ReNumeration */ USBCS = DISCON | RENUM; delay_ms(200); USBCS = DISCOE | RENUM; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/OpenULINK/ulink_firmware.hex ================================================ :040000000200713257 :01000B0032C2 :0100130032BA :01001B0032B2 :0100230032AA :01002B0032A2 :01003300329A :01003B003292 :01004300328A :01004B003282 :01005300327A :01005B003272 :01006300326A :03006B000201107F :0300CA0002006EC3 :03006E000201018B :1000CD00907F937404F0907F9C7495F0907F96745C :1000DD0090F0907F94E4F0907F9D747FF0907F97E7 :1000ED00E4F0907F957440F0907F9E7442F0907F85 :1000FD0098E4F0221200CD1204ADD2AF1208E090B8 :10010D00000022C021C0E0C0F0C082C083C007C083 :10011D0006C005C004C003C002C001C000C0D07538 :10012D00D000AF9174EF5FF59112040C907FAB741A :10013D0001F0907FB4E04402F0D0D0D000D001D0D7 :10014D0002D003D004D005D006D007D083D082D002 :10015D00F0D0E0D02132323232323232323232C04D :10016D00E0C082C083C007C0D075D000D201AF916E :10017D0074EF5FF591907FA97404F0D0D0D007D0C3 :10018D0083D082D0E032C0E0C082C083C007C0D02F :10019D0075D000D200AF9174EF5FF591907FAA7486 :1001AD0004F0D0D0D007D083D082D0E032323232BA :1001BD0032323232323232AF82747F5FFE24F850E7 :1001CD0003020278EE240A83F582EE240C83F58374 :1001DD00E473EFF306192C3F52650101020202028E :1001ED000202907FB422EF30E7067DB67E7F800459 :1001FD007DC67E7F8D828E8322EF30E7067DB87EB1 :10020D007F80047DC87E7F8D828E8322EF30E7064E :10021D007DBA7E7F80047DCA7E7F8D828E8322EFA4 :10022D0030E7067DBC7E7F80047DCC7E7F8D828E07 :10023D008322EF30E7067DBE7E7F80047DCE7E7FFC :10024D008D828E8322EF30E7067DC07E7F80047D18 :10025D00D07E7F8D828E8322EF30E7067EC27F7F38 :10026D0080047ED27F7F8E828F832290000022AF0A :10027D008274105FFE74075F4206907FD7EEF074B4 :10028D00204EF022907FE8E0C322907FE8E0FF60EF :10029D0005BF0246800A907FB4E0FF4401F0803A2A :1002AD00907FEAE0FEA3E0FF4E7027907FECE0FE2A :1002BD00A3E08E821201C4AE82AF83EE4F7002C3F3 :1002CD00228E828F83E0FD5305FE8E828F83EDF0AB :1002DD008008907FB4E0FF4401F0D322907FE8E0E6 :1002ED00FF6005BF02468010907FEAE0FEA3E0FFAD :1002FD00BE0239BF0036D322907FEAE0FEA3E0FFB5 :10030D004E7027907FECE0FEA3E08E821201C4AE0A :10031D0082AF83EE4F7002C3228E828F83E0FD4346 :10032D0005018E828F83EDF08002C322D322907F50 :10033D00EAE0A3E0FF907FEAE0FDA3E07E00BF01CD :10034D0002800DBF02028021BF030280340203EC44 :10035D007ED37F138F06907FD4EEF07ED37F137FF5 :10036D0000907FD5EEF00203EE7EE57F138F0690B1 :10037D007FD4EEF07EE57F137F00907FD5EEF08089 :10038D0060907FECE0FEA3E0FF4E70187E057F14B9 :10039D008F06907FD4EEF07E057F147F00907FD581 :1003AD00EEF0803D907FECE0FEA3E0FFBE092EBF96 :1003BD00042BED1475F002A42459F582741435F054 :1003CD00F583E493FEA3E493FF8E048F058D0490D3 :1003DD007FD4ECF07F00907FD5EEF08004C322C374 :1003ED0022D32275828212027C75820212027C90C7 :1003FD007FB87402F0907FC8E4F0907FC9F022902E :10040D007FE9E0FF24F3500122EFF5F0240B83F593 :10041D0082E5F0241183F583E473414F5D655D72D0 :10042D007B73889899A9AC0404040404040404049F :10043D0004040404120291500122907FB4E044019F :10044D00F022120297500122907FB4E04401F02275 :10045D00907FB4E04401F0221202E94042907FB453 :10046D00E04401F02222907FB4E04401F022120317 :10047D003B402C907FB4E04401F0229013EAE493CA :10048D00907F00F0907FB57401F022229013F0E47C :10049D0093907F00F0907FB57401F0221203F0224B :1004AD00907FDE7404F0907FDF7404F0907FE0E4C1 :1004BD00F0907FE1F0907FA17401F0907FAFE04468 :1004CD0001F0907FAEE04401F0907FAD7404F090A8 :1004DD007FAC7404F0D2E8907FD6740AF09000C817 :0A04ED0012137C907FD67406F022F3 :1013D30012011001FFFFFF4051C21027000101025B :1013E3000301090220000101048032090400000204 :1013F300FFFFFF00070582024000000705020240CD :1014030000000403090414034F00700065006E001C :1014130055004C0049004E004B0014034F00700070 :1014230065006E0055004C0049004E004B000E0352 :101433003000300030003000300031001A034A0021 :101443005400410047002000410064006100700027 :0E14530074006500720009141D1431143F145A :1004F700E5080424C0F582E4347DF583E0FF30E1AC :1005070008907F96E0FE54EFF08F06EE30E00890FB :100517007F96E0FE547FF0EF30E308907F96E0FE91 :100527004410F0EF30E208907F96E0FF4480F0221D :100537007F00E50824C0F582E4347DF583E0FE24DE :10054700D550030208A6EE240A83F582EE242F83F2 :10055700F583E473B18AD7B0FAD3A6A6A6A6A6A652 :10056700A6A6A6A6A6A6A6A6A6A6A6A6A6A6A6A624 :10057700A6A6A6A621FA512A639CD5053493A205FF :1005870006050605060808080808080808080808F0 :1005970008080808080808080808080808080806D6 :1005A700060607070707080808087E05E508042464 :1005B700C0F582E4347DF583E0FFE50804F5828524 :1005C7000927C007C00612091DD006D0070208A8D0 :1005D700E5080424C0F582E4347DF583E02405FEB4 :1005E700E50804F582C007C006120BDED006D00767 :1005F7000208A8E5080424C0F582E4347DF583E009 :10060700FF2405FEE50804F58285093CC007C006FE :10061700120E79D006D0070208A87E02E508042446 :10062700C0F582E4347DF583E0FD7402250824C01B :10063700F582E4347DF583E0F50A8D82C007C006B4 :1006470012124AD006D0070208A87E02E508042441 :10065700C0F582E4347DF583E0FC7D007402250853 :1006670024C0F582E4347DF583E0FAE44204EA42EB :10067700058C828D83C007C0061211DDD006D00716 :100687000208A87E05E5080424C0F582E4347DF558 :1006970083E0FFE50804F58285092DC007C006122F :1006A7000A67D006D0070208A8E5080424C0F58227 :1006B700E4347DF583E02405FEE50804F582C007F0 :1006C700C006120D14D006D0070208A8E5080424B6 :1006D700C0F582E4347DF583E0FF2405FEE50804D8 :1006E700F582850943C007C006121013D006D0074C :1006F7000208A87E02E5080424C0F582E4347DF5EB :1007070083E0FB7402250824C0F582E4347DF58379 :10071700E0F50A8B82C007C006121281D006D00707 :100727000208A87E02E5080424C0F582E4347DF5BA :1007370083E0FC7D007402250824C0F582E4347D43 :10074700F583E0FAE44204EA42058C828D83C00710 :10075700C006121207D006D0070208A87E02E508D5 :100767000424C0F582E4347DF583E0FC7D00740247 :10077700250824C0F582E4347DF583E0FAE44204D9 :10078700EA42058C828D83C007C006121349D00642 :10079700D0070208A87E02E5080424C0F582E434E5 :1007A7007DF583E0FC7D007402250824C0F582E412 :1007B700347DF583E0FAE44204EA42058C828D83B6 :1007C700C007C00612137CD006D0070208A87E0017 :1007D7007F02C007C0061212CEAC82AD83D006D00E :1007E7000785098275837E8D03EBF0E509042400F4 :1007F700F582E4347EF5837D00ECF00208A87E02E2 :10080700E5080424C0F582E4347DF583E0FD740235 :10081700250824C0F582E4347DF583E0F50A8D824E :10082700C007C006121311D006D00780747E05E5F5 :10083700080424C0F582E4347DF583E0FD740225C5 :100847000824C0F582E4347DF583E0F50A740325B6 :100857000824C0F582E4347DF583E0F50B740425A4 :100867000824C0F582E4347DF583E0F50C74052592 :100877000824C0F582E4347DF583E0F50D8D82C050 :1008870007C006121329D006D00780157E01C007BE :10089700C0061204F7D006D00780067E0180027ECC :1008A70000EF2509F509AD087F008E037C00EB2DCD :1008B700FDEC3FFF0DBD00010F907FC9E0FC7B0001 :1008C700C3ED9CEF64808BF063F08095F04002D31A :1008D70022EE042508F508C32275080075090010E3 :1008E700000280FB907F96E0FF547FF0C202200257 :1008F70007120537920280F6907F96E0FF4480F05A :10090700E509600B907FB9E509F010010280FB90C3 :100917007FC9E4F080C3E582FF24C0F582E4347D1B :10092700F583E0F528EF0424C0F582E4347DF583F0 :10093700E0F52974022FFC24C0F582E4347DF583A9 :10094700E0C4540FFB53030FEC24C0F582E4347D5D :10095700F583E0FC740F5CF52A74032F24C0F5823D :10096700E4347DF583E0FA74042F24C0F582E4347F :100977007DF583E0F52BEB60078A0A8B8212124A1A :10098700907F97E0FB5303F874044BFA7900A8288B :100997007C0018B8FF011C89067F00C3EE98EF643E :1009A700808CF063F08095F050347F007E00907F5C :1009B70097EBF0EFC313FF907F97EAF0907F99E0F2 :1009C700FC30E5034307800EBE080040E1E5272918 :1009D7002400F582E4347EF583EFF00980B0892C9A :1009E7007F00AC2A7A00C3EA95295040A8297900EC :1009F70018B8FF01198A057E00EDB50011EEB501A3 :100A07000DEC600A4303021CE52BC313F52B907F03 :100A170097EBF0EFC313FF907F9774044BF0907F31 :100A270099E0FE30E5034307800A80BAAD297E00CE :100A37007408C39DFDE49EFE8DF005F0EF8002C3B0 :100A470013D5F0FBFFE527252C2400F582E4347E3F :100A5700F583EFF0EC6008852B0A8C8202124A229C :100A6700E582FF24C0F582E4347DF583E0F52EEFBF :100A77000424C0F582E4347DF583E0F52F74022F5A :100A8700FC24C0F582E4347DF583E0C4540FFB53A6 :100A9700030FEC24C0F582E4347DF583E0FC740F8A :100AA7005CF53074032F24C0F582E4347DF583E0D0 :100AB700FA74042F24C0F582E4347DF583E0F53120 :100AC700EB60078A0A8B82121281907F97E0FB53B3 :100AD70003F874044BFA753200A82E7C0018B8FF8F :100AE700011CA9327E00C3E998EE64808CF063F0A4 :100AF7008095F0504C7E007C00907F97EBF079005A :100B0700C3E9952250030980F7EEC313FE907F9740 :100B1700EAF07900C3E9952250030980F7907F999D :100B2700E0F930E5034306800CBC080040CBE52D17 :100B370025322400F582E4347EF583EEF005328019 :100B4700987E00AA307900C3E9952F5056A82F7CCC :100B57000018B8FF011C89057F00EDB50011EFB53E :100B6700040DEA600A4303021AE531C313F5319015 :100B77007F97EBF07F00C3EF952250030F80F7EECE :100B8700C313FE907F9774044BF07F00C3EF952249 :100B970050030F80F7907F99E0FF30E5034306800D :100BA7000980A4AD2F7F007408C39DFDE49FFF8DCE :100BB700F005F0EE8002C313D5F0FBFEE52D2532DC :100BC7002400F582E4347EF583EEF0EA600885318F :100BD7000A8A8202128122E582FF24C0F582E43468 :100BE7007DF583E0F533EF0424C0F582E4347DF529 :100BF70083E0F53474022FFC24C0F582E4347DF5DC :100C070083E0C4540FFB53030FEC24C0F582E43494 :100C17007DF583E0FC740F5CF53574032F24C0F574 :100C270082E4347DF583E0FA74042F24C0F582E46E :100C3700347DF583E0F536EB600B8A0A8B82C007BB :100C470012124AD007907F97E0FB5303F97A00A866 :100C5700337C0018B8FF011C8A017E00C3E998EEB7 :100C670064808CF063F08095F05039EF2A240524D6 :100C7700C0F582E4347DF583E0FE7C00EE30E005CC :100C870043030180068B0174FE59FB907F97EBF0BD :100C9700EEC313FE907F9774044BF00CBC08004022 :100CA700DB0A80ABEF2A240524C0F582E4347DF506 :100CB70083E0FEAF357C00C3EC95345044EE30E062 :100CC7000543030180068B0274FE5AFBA9347A00A0 :100CD70019B9FF011A8C007D00E8B50111EDB502C5 :100CE7000DEF600A4303021FE536C313F536907F05 :100CF70097EBF0EEC313FE907F9774044BF00C80D4 :100D0700B6EF600885360A8F8202124A22E582F51D :100D17003724C0F582E4347DF583E0F538E5370400 :100D270024C0F582E4347DF583E0F5397402253774 :100D3700FC24C0F582E4347DF583E0C4540FFB53F3 :100D4700030FEC24C0F582E4347DF583E0FC740FD7 :100D57005CF53A7403253724C0F582E4347DF583C6 :100D6700E0FA7404253724C0F582E4347DF583E086 :100D7700F53BEB60078A0A8B82121281907F97E01E :100D8700FB5303F97A00A8387C0018B8FF011C8AC6 :100D9700067F00C3EE98EF64808CF063F08095F0D7 :100DA7005050E5372A240524C0F582E4347DF583C5 :100DB700E0FF7E00EF30E00543030180068B0474FB :100DC700FE5CFB907F97EBF07C00C3EC9523500310 :100DD7000C80F7EFC313FF907F9774044BF07C00F0 :100DE700C3EC952350030C80F70EBE080040C50ADC :100DF7008094E5372A240524C0F582E4347DF58301 :100E0700E0FFAE3A7C00C3EC9539505AEF30E0056D :100E170043030180068B0274FE5AFBA8397A001837 :100E2700B8FF011A8C017D00E9B50011EDB5020D7F :100E3700EE600A4303021EE53BC313F53B907F9721 :100E4700EBF07D00C3ED952350030D80F7EFC3133F :100E5700FF907F9774044BF07D00C3ED95235003FB :100E67000D80F70C80A0EE6008853B0A8E82021287 :100E77008122E582FF24C0F582E4347DF583E0F525 :100E87003DEF0424C0F582E4347DF583E0F53E743C :100E9700022FFC24C0F582E4347DF583E0C4540FAF :100EA700FB53030FEC24C0F582E4347DF583E0FCAB :100EB700740F5CF53F74032F24C0F582E4347DF58D :100EC70083E0FA74042F24C0F582E4347DF583E0CF :100ED700F540EB600B8A0A8B82C00712124AD007D3 :100EE700907F97E0FB5303F97A00A83D7C0018B880 :100EF700FF011C8A017E00C3E998EE64808CF063D1 :100F0700F08095F0505CEF2A240524C0F582E43484 :100F17007DF583E0F5417C007900E54130E005434C :100F2700030180068B0074FE58FB907F97EBF0E57A :100F370041C313F541907F9774044BF0ECC313FC46 :100F4700907F99E0F830E50343048009B908004031 :100F5700C9E53C2A2400F582E4347EF583ECF00AE7 :100F670080888A01EF2A240524C0F582E4347DF5C0 :100F770083E0F5417C00AF3F754200C3E542953EF3 :100F87005057E54130E00543030180068B0074FEAE :100F970058FBA83E7D0018B8FF011DAA427E00EA53 :100FA700B50011EEB5050DEF600A4303021FE540DA :100FB700C313F540907F97EBF0E541C313F54190DC :100FC7007F9774044BF0ECC313FC907F99E0FE30DD :100FD700E503430480054280A2AD3E7E007408C34A :100FE7009DFDE49EFE8DF005F0EC8002C313D5F065 :100FF700FBFCE53C292400F582E4347EF583ECF024 :10100700EF600885400A8F8202124A22E582F54482 :1010170024C0F582E4347DF583E0F545E5440424F6 :10102700C0F582E4347DF583E0F54674022544FC7F :1010370024C0F582E4347DF583E0C4540FFB5303E9 :101047000FEC24C0F582E4347DF583E0FC740F5C7B :10105700F5477403254424C0F582E4347DF583E025 :10106700FA7404254424C0F582E4347DF583E0F561 :1010770048EB60078A0A8B82121281907F97E0FB08 :101087005303F97A00A8457C0018B8FF011C8A06AB :101097007F00C3EE98EF64808CF063F08095F0508A :1010A70074E5442A240524C0F582E4347DF583E001 :1010B700F5497E007C00E54930E0054303018006E1 :1010C7008B0074FE58FB907F97EBF07800C3E89590 :1010D7002450030880F7E549C313F549907F9774B7 :1010E700044BF07800C3E8952450030880F7EEC35B :1010F70013FE907F99E0F830E5034306800CBC08A7 :101107000040B3E5432A2400F582E4347EF583EEFC :10111700F00A02108C8A04E5442A240524C0F582CB :10112700E4347DF583E0F5497E00AA47754A00C39C :10113700E54A9546506DE54930E0054303018006D1 :101147008B0174FE59FBA9467D0019B9FF011DA843 :101157004A7F00E8B50111EFB5050DEA600A4303C0 :10116700021AE548C313F548907F97EBF07F00C359 :10117700EF952450030F80F7E549C313F549907F96 :101187009774044BF07F00C3EF952450030F80F74B :10119700EEC313FE907F99E0FF30E5034306800519 :1011A7004A808CAD467F007408C39DFDE49FFF8D88 :1011B700F005F0EE8002C313D5F0FBFEE5432C24C7 :1011C70000F582E4347EF583EEF0EA600885480A8C :1011D7008A8202128122AE82AF83907F97E0FD530D :1011E70005FB74044DFC7A007B00C3EA9EEB9F501D :1011F7000E907F97EDF0ECF00ABA00EE0B80EB2231 :10120700AE82AF83907F97E0FD5305FB74044DFCDE :101217007A007B00C3EA9EEB9F5027907F97EDF003 :101227007900C3E9952550030980F7907F97ECF083 :101237007900C3E9952550030980F70ABA00D50B51 :1012470080D222AF82907F97E0FE5306FB7D00C3DA :10125700ED9F5025E50A30E00543060280068E041F :1012670074FD5CFE907F97EEF0E50AC313F50A90D4 :101277007F9774044EF00D80D622AF82907F97E05F :10128700FE5306FB7D00C3ED9F503BE50A30E005AA :1012970043060280068E0474FD5CFE907F97EEF095 :1012A7007C00C3EC952650030C80F7E50AC313F5C1 :1012B7000A907F9774044EF07C00C3EC9526500388 :1012C7000C80F70D80C0227F00907F99E0FE30E50B :1012D700027F01907F99E0FE30E603430702907F8B :1012E7009AE0FE30E703430704907F9BE0FE30E57A :1012F70003430708907F9AE0FE53067F8F05E4FFBC :10130700FCEE4FF582EC4DF58322E582547FF4FF26 :10131700907F97E05FF0747F550AFF907F97E04FCB :10132700F022858222850A23850B24850C25850DCD :10133700262200227E567F021EBEFF011FEE4F703F :10134700F722750A05750B001213A6AE82AF837CD0 :10135700007D00C3EC9EED9F501AC007C006C00574 :10136700C004121339D004D005D006D0070CBC0036 :10137700E20D80DF22AE82AF837C007D00C3EC9E4E :10138700ED9F501AC007C006C005C00412133BD01A :0F13970004D005D006D0070CBC00E20D80DF2289 :03004300021B009D :101B0000020110000201630002016400020165008D :101B1000020166000201670002016800020169001B :101B200002016A0002016B0002016C0002019300D5 :101B30000201BA000201BB000201BC000201BD00AB :101B40000201BE000201BF000201C0000201C1008B :081B50000201C2000201C30002 :1013A6007A10E4FBFCE58225E0F582E58333F583DC :1013B600EB33FBEC33FCEB950AF5F0EC950B4006B2 :0913C600FCABF0438201DADD22E8 :0600A000E478FFF6D8FD34 :10007E007900E94400601B7A009014617800759253 :10008E0020E493F2A308B800020592D9F4DAF275CF :02009E0092FFCF :1000A6007800E84400600A7900759220E4F309D8E4 :1000B600FC7800E84400600C7900902000E4F0A38E :0400C600D8FCD9FA8F :0D00710075814A1213CFE582600302006E14 :0413CF007582002201 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/am335xgpio.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2022 by Steve Marple, stevemarple@googlemail.com * * * * Based on bcm2835gpio.c and linuxgpiod.c * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/adapter.h> #include <jtag/interface.h> #include <transport/transport.h> #include "bitbang.h" #include <sys/mman.h> /* GPIO register base addresses. Values taken from "AM335x and AMIC110 Sitara * Processors Technical Reference Manual", Chapter 2 Memory Map. */ #define AM335XGPIO_NUM_GPIO_PER_CHIP 32 #define AM335XGPIO_NUM_GPIO_CHIPS 4 #define AM335XGPIO_GPIO0_HW_ADDR 0x44E07000 #define AM335XGPIO_GPIO1_HW_ADDR 0x4804C000 #define AM335XGPIO_GPIO2_HW_ADDR 0x481AC000 #define AM335XGPIO_GPIO3_HW_ADDR 0x481AE000 /* 32-bit offsets from GPIO chip base address. Values taken from "AM335x and * AMIC110 Sitara Processors Technical Reference Manual", Chapter 25 * General-Purpose Input/Output. */ #define AM335XGPIO_GPIO_OE_OFFSET (0x134 / 4) #define AM335XGPIO_GPIO_DATAIN_OFFSET (0x138 / 4) #define AM335XGPIO_GPIO_DATAOUT_OFFSET (0x13C / 4) /* DATAOUT register uses 0 for output, 1 for input */ #define AM335XGPIO_GPIO_CLEARDATAOUT_OFFSET (0x190 / 4) #define AM335XGPIO_GPIO_SETDATAOUT_OFFSET (0x194 / 4) #define AM335XGPIO_READ_REG(chip_num, offset) \ (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset))) #define AM335XGPIO_WRITE_REG(chip_num, offset, value) \ (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset)) = (value)) #define AM335XGPIO_SET_REG_BITS(chip_num, offset, bit_mask) \ (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset)) |= (bit_mask)) #define AM335XGPIO_CLEAR_REG_BITS(chip_num, offset, bit_mask) \ (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset)) &= ~(bit_mask)) #define AM335XGPIO_SET_INPUT(gpio_config) \ AM335XGPIO_SET_REG_BITS((gpio_config)->chip_num, AM335XGPIO_GPIO_OE_OFFSET, BIT((gpio_config)->gpio_num)) #define AM335XGPIO_SET_OUTPUT(gpio_config) \ AM335XGPIO_CLEAR_REG_BITS((gpio_config)->chip_num, AM335XGPIO_GPIO_OE_OFFSET, BIT((gpio_config)->gpio_num)) #define AM335XGPIO_SET_HIGH(gpio_config) \ AM335XGPIO_WRITE_REG((gpio_config)->chip_num, AM335XGPIO_GPIO_SETDATAOUT_OFFSET, BIT((gpio_config)->gpio_num)) #define AM335XGPIO_SET_LOW(gpio_config) \ AM335XGPIO_WRITE_REG((gpio_config)->chip_num, AM335XGPIO_GPIO_CLEARDATAOUT_OFFSET, BIT((gpio_config)->gpio_num)) enum amx335gpio_initial_gpio_mode { AM335XGPIO_GPIO_MODE_INPUT, AM335XGPIO_GPIO_MODE_OUTPUT_LOW, AM335XGPIO_GPIO_MODE_OUTPUT_HIGH, }; static const uint32_t am335xgpio_gpio_chip_hw_addr[AM335XGPIO_NUM_GPIO_CHIPS] = { AM335XGPIO_GPIO0_HW_ADDR, AM335XGPIO_GPIO1_HW_ADDR, AM335XGPIO_GPIO2_HW_ADDR, AM335XGPIO_GPIO3_HW_ADDR, }; /* Memory-mapped address pointers */ static volatile uint32_t *am335xgpio_gpio_chip_mmap_addr[AM335XGPIO_NUM_GPIO_CHIPS]; static int dev_mem_fd; static enum amx335gpio_initial_gpio_mode initial_gpio_mode[ADAPTER_GPIO_IDX_NUM]; /* Transition delay coefficients */ static int speed_coeff = 600000; static int speed_offset = 575; static unsigned int jtag_delay; static const struct adapter_gpio_config *adapter_gpio_config; static bool is_gpio_config_valid(const struct adapter_gpio_config *gpio_config) { return gpio_config->chip_num >= 0 && gpio_config->chip_num < AM335XGPIO_NUM_GPIO_CHIPS && gpio_config->gpio_num >= 0 && gpio_config->gpio_num < AM335XGPIO_NUM_GPIO_PER_CHIP; } static int get_gpio_value(const struct adapter_gpio_config *gpio_config) { unsigned int shift = gpio_config->gpio_num; uint32_t value = AM335XGPIO_READ_REG(gpio_config->chip_num, AM335XGPIO_GPIO_DATAIN_OFFSET); value = (value >> shift) & 1; return value ^ (gpio_config->active_low ? 1 : 0); } static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int value) { value = value ^ (gpio_config->active_low ? 1 : 0); switch (gpio_config->drive) { case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL: if (value) AM335XGPIO_SET_HIGH(gpio_config); else AM335XGPIO_SET_LOW(gpio_config); /* For performance reasons assume the GPIO is already set as an output * and therefore the call can be omitted here. */ break; case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN: if (value) { AM335XGPIO_SET_INPUT(gpio_config); } else { AM335XGPIO_SET_LOW(gpio_config); AM335XGPIO_SET_OUTPUT(gpio_config); } break; case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE: if (value) { AM335XGPIO_SET_HIGH(gpio_config); AM335XGPIO_SET_OUTPUT(gpio_config); } else { AM335XGPIO_SET_INPUT(gpio_config); } break; } } static enum amx335gpio_initial_gpio_mode get_gpio_mode(const struct adapter_gpio_config *gpio_config) { if (AM335XGPIO_READ_REG(gpio_config->chip_num, AM335XGPIO_GPIO_OE_OFFSET) & BIT(gpio_config->gpio_num)) return AM335XGPIO_GPIO_MODE_INPUT; /* Return output level too so that pin mode can be fully restored */ if (AM335XGPIO_READ_REG(gpio_config->chip_num, AM335XGPIO_GPIO_DATAOUT_OFFSET) & BIT(gpio_config->gpio_num)) return AM335XGPIO_GPIO_MODE_OUTPUT_HIGH; return AM335XGPIO_GPIO_MODE_OUTPUT_LOW; } static const char *get_gpio_mode_name(enum amx335gpio_initial_gpio_mode gpio_mode) { switch (gpio_mode) { case AM335XGPIO_GPIO_MODE_INPUT: return "input"; case AM335XGPIO_GPIO_MODE_OUTPUT_LOW: return "output (low)"; case AM335XGPIO_GPIO_MODE_OUTPUT_HIGH: return "output (high)"; } return "unknown"; } static void initialize_gpio(enum adapter_gpio_config_index idx) { if (!is_gpio_config_valid(&adapter_gpio_config[idx])) return; initial_gpio_mode[idx] = get_gpio_mode(&adapter_gpio_config[idx]); LOG_DEBUG("saved GPIO mode for %s (GPIO %d %d): %s", adapter_gpio_get_name(idx), adapter_gpio_config[idx].chip_num, adapter_gpio_config[idx].gpio_num, get_gpio_mode_name(initial_gpio_mode[idx])); if (adapter_gpio_config[idx].pull != ADAPTER_GPIO_PULL_NONE) { LOG_WARNING("am335xgpio does not support pull-up or pull-down settings (signal %s)", adapter_gpio_get_name(idx)); } switch (adapter_gpio_config[idx].init_state) { case ADAPTER_GPIO_INIT_STATE_INACTIVE: set_gpio_value(&adapter_gpio_config[idx], 0); break; case ADAPTER_GPIO_INIT_STATE_ACTIVE: set_gpio_value(&adapter_gpio_config[idx], 1); break; case ADAPTER_GPIO_INIT_STATE_INPUT: AM335XGPIO_SET_INPUT(&adapter_gpio_config[idx]); break; } /* Direction for non push-pull is already set by set_gpio_value() */ if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL) AM335XGPIO_SET_OUTPUT(&adapter_gpio_config[idx]); } static void restore_gpio(enum adapter_gpio_config_index idx) { if (is_gpio_config_valid(&adapter_gpio_config[idx])) { switch (initial_gpio_mode[idx]) { case AM335XGPIO_GPIO_MODE_INPUT: AM335XGPIO_SET_INPUT(&adapter_gpio_config[idx]); break; case AM335XGPIO_GPIO_MODE_OUTPUT_LOW: AM335XGPIO_SET_LOW(&adapter_gpio_config[idx]); AM335XGPIO_SET_OUTPUT(&adapter_gpio_config[idx]); break; case AM335XGPIO_GPIO_MODE_OUTPUT_HIGH: AM335XGPIO_SET_HIGH(&adapter_gpio_config[idx]); AM335XGPIO_SET_OUTPUT(&adapter_gpio_config[idx]); break; } } } static bb_value_t am335xgpio_read(void) { return get_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TDO]) ? BB_HIGH : BB_LOW; } static int am335xgpio_write(int tck, int tms, int tdi) { set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TDI], tdi); set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TMS], tms); set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TCK], tck); /* Write clock last */ for (unsigned int i = 0; i < jtag_delay; ++i) asm volatile (""); return ERROR_OK; } static int am335xgpio_swd_write(int swclk, int swdio) { set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO], swdio); set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK], swclk); /* Write clock last */ for (unsigned int i = 0; i < jtag_delay; ++i) asm volatile (""); return ERROR_OK; } /* (1) assert or (0) deassert reset lines */ static int am335xgpio_reset(int trst, int srst) { /* As the "adapter reset_config" command keeps the srst and trst gpio drive * mode settings in sync we can use our standard set_gpio_value() function * that honours drive mode and active low. */ if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SRST])) set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SRST], srst); if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TRST])) set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TRST], trst); LOG_DEBUG("am335xgpio_reset(%d, %d), trst_gpio: %d %d, srst_gpio: %d %d", trst, srst, adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].chip_num, adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].gpio_num, adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].chip_num, adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].gpio_num); return ERROR_OK; } static void am335xgpio_swdio_drive(bool is_output) { if (is_output) { if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR])) set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 1); AM335XGPIO_SET_OUTPUT(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO]); } else { AM335XGPIO_SET_INPUT(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO]); if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR])) set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 0); } } static int am335xgpio_swdio_read(void) { return get_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO]); } static int am335xgpio_blink(int on) { if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_LED])) set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_LED], on); return ERROR_OK; } static struct bitbang_interface am335xgpio_bitbang = { .read = am335xgpio_read, .write = am335xgpio_write, .swdio_read = am335xgpio_swdio_read, .swdio_drive = am335xgpio_swdio_drive, .swd_write = am335xgpio_swd_write, .blink = am335xgpio_blink }; static int am335xgpio_khz(int khz, int *jtag_speed) { if (!khz) { LOG_DEBUG("RCLK not supported"); return ERROR_FAIL; } *jtag_speed = speed_coeff / khz - speed_offset; if (*jtag_speed < 0) *jtag_speed = 0; return ERROR_OK; } static int am335xgpio_speed_div(int speed, int *khz) { *khz = speed_coeff / (speed + speed_offset); return ERROR_OK; } static int am335xgpio_speed(int speed) { jtag_delay = speed; return ERROR_OK; } COMMAND_HANDLER(am335xgpio_handle_speed_coeffs) { if (CMD_ARGC == 2) { COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff); COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset); } command_print(CMD, "AM335x GPIO config: speed_coeffs = %d, speed_offset = %d", speed_coeff, speed_offset); return ERROR_OK; } static const struct command_registration am335xgpio_subcommand_handlers[] = { { .name = "speed_coeffs", .handler = am335xgpio_handle_speed_coeffs, .mode = COMMAND_CONFIG, .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.", .usage = "[SPEED_COEFF SPEED_OFFSET]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration am335xgpio_command_handlers[] = { { .name = "am335xgpio", .mode = COMMAND_ANY, .help = "perform am335xgpio management", .chain = am335xgpio_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static const char * const am335xgpio_transports[] = { "jtag", "swd", NULL }; static struct jtag_interface am335xgpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, }; static bool am335xgpio_jtag_mode_possible(void) { if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TCK])) return false; if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TMS])) return false; if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TDI])) return false; if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TDO])) return false; return true; } static bool am335xgpio_swd_mode_possible(void) { if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK])) return false; if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO])) return false; return true; } static void am335xgpio_munmap(void) { for (unsigned int i = 0; i < AM335XGPIO_NUM_GPIO_CHIPS && am335xgpio_gpio_chip_mmap_addr[i] != MAP_FAILED; ++i) if (munmap((void *)am335xgpio_gpio_chip_mmap_addr[i], sysconf(_SC_PAGE_SIZE)) < 0) LOG_ERROR("Cannot unmap GPIO memory for chip %d: %s", i, strerror(errno)); } static int am335xgpio_init(void) { LOG_INFO("AM335x GPIO JTAG/SWD bitbang driver"); bitbang_interface = &am335xgpio_bitbang; adapter_gpio_config = adapter_gpio_get_config(); if (transport_is_jtag() && !am335xgpio_jtag_mode_possible()) { LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode"); return ERROR_JTAG_INIT_FAILED; } if (transport_is_swd() && !am335xgpio_swd_mode_possible()) { LOG_ERROR("Require swclk and swdio gpio for SWD mode"); return ERROR_JTAG_INIT_FAILED; } dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC); if (dev_mem_fd < 0) { LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem"); dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); } if (dev_mem_fd < 0) { LOG_ERROR("open: %s", strerror(errno)); return ERROR_JTAG_INIT_FAILED; } for (unsigned int i = 0; i < AM335XGPIO_NUM_GPIO_CHIPS; ++i) { am335xgpio_gpio_chip_mmap_addr[i] = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, am335xgpio_gpio_chip_hw_addr[i]); if (am335xgpio_gpio_chip_mmap_addr[i] == MAP_FAILED) { LOG_ERROR("mmap: %s", strerror(errno)); am335xgpio_munmap(); close(dev_mem_fd); return ERROR_JTAG_INIT_FAILED; } } close(dev_mem_fd); /* Configure JTAG/SWD signals. Default directions and initial states are handled * by adapter.c and "adapter gpio" command. */ if (transport_is_jtag()) { initialize_gpio(ADAPTER_GPIO_IDX_TDO); initialize_gpio(ADAPTER_GPIO_IDX_TDI); initialize_gpio(ADAPTER_GPIO_IDX_TMS); initialize_gpio(ADAPTER_GPIO_IDX_TCK); initialize_gpio(ADAPTER_GPIO_IDX_TRST); } if (transport_is_swd()) { /* swdio and its buffer should be initialized in the order that prevents * two outputs from being connected together. This will occur if the * swdio GPIO of the AM335x is configured as an output while its * external buffer is configured to send the swdio signal from the * target to the AM335x. */ if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].init_state == ADAPTER_GPIO_INIT_STATE_INPUT) { initialize_gpio(ADAPTER_GPIO_IDX_SWDIO); initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR); } else { initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR); initialize_gpio(ADAPTER_GPIO_IDX_SWDIO); } initialize_gpio(ADAPTER_GPIO_IDX_SWCLK); } initialize_gpio(ADAPTER_GPIO_IDX_SRST); initialize_gpio(ADAPTER_GPIO_IDX_LED); return ERROR_OK; } static int am335xgpio_quit(void) { if (transport_is_jtag()) { restore_gpio(ADAPTER_GPIO_IDX_TDO); restore_gpio(ADAPTER_GPIO_IDX_TDI); restore_gpio(ADAPTER_GPIO_IDX_TMS); restore_gpio(ADAPTER_GPIO_IDX_TCK); restore_gpio(ADAPTER_GPIO_IDX_TRST); } if (transport_is_swd()) { /* Restore swdio/swdio_dir to their initial modes, even if that means * connecting two outputs. Begin by making swdio an input so that the * current and final states of swdio and swdio_dir do not have to be * considered to calculate the safe restoration order. */ AM335XGPIO_SET_INPUT(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO]); restore_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR); restore_gpio(ADAPTER_GPIO_IDX_SWDIO); restore_gpio(ADAPTER_GPIO_IDX_SWCLK); } restore_gpio(ADAPTER_GPIO_IDX_SRST); restore_gpio(ADAPTER_GPIO_IDX_LED); am335xgpio_munmap(); return ERROR_OK; } struct adapter_driver am335xgpio_adapter_driver = { .name = "am335xgpio", .transports = am335xgpio_transports, .commands = am335xgpio_command_handlers, .init = am335xgpio_init, .quit = am335xgpio_quit, .reset = am335xgpio_reset, .speed = am335xgpio_speed, .khz = am335xgpio_khz, .speed_div = am335xgpio_speed_div, .jtag_ops = &am335xgpio_interface, .swd_ops = &bitbang_swd, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/amt_jtagaccel.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/adapter.h> #include <jtag/interface.h> #if PARPORT_USE_PPDEV == 1 #include <linux/parport.h> #include <linux/ppdev.h> #include <sys/ioctl.h> #else /* not PARPORT_USE_PPDEV */ #ifndef _WIN32 #include <sys/io.h> #endif #endif #if PARPORT_USE_GIVEIO == 1 #if IS_CYGWIN == 1 #include <windows.h> #endif #endif /** * @file * Support the Amontec Chameleon POD with JTAG Accelerator support. * This is a parallel port JTAG adapter with a CPLD between the * parallel port and the JTAG connection. VHDL code running in the * CPLD significantly accelerates JTAG operations compared to the * bitbanging "Wiggler" style of most parallel port adapters. */ /* configuration */ static uint16_t amt_jtagaccel_port; /* interface variables */ static uint8_t aw_control_rst; static uint8_t aw_control_fsm = 0x10; static uint8_t aw_control_baudrate = 0x20; static int rtck_enabled; #if PARPORT_USE_PPDEV == 1 static int device_handle; static const int addr_mode = IEEE1284_MODE_EPP | IEEE1284_ADDR; /* FIXME do something sane when these ioctl/read/write calls fail. */ #define AMT_AW(val) \ do { \ int __retval; \ \ __retval = ioctl(device_handle, PPSETMODE, &addr_mode); \ assert(__retval >= 0); \ __retval = write(device_handle, &val, 1); \ assert(__retval >= 0); \ } while (0) #define AMT_AR(val) \ do { \ int __retval; \ \ __retval = ioctl(device_handle, PPSETMODE, &addr_mode); \ assert(__retval >= 0); \ __retval = read(device_handle, &val, 1); \ assert(__retval >= 0); \ } while (0) static const int data_mode = IEEE1284_MODE_EPP | IEEE1284_DATA; #define AMT_DW(val) \ do { \ int __retval; \ \ __retval = ioctl(device_handle, PPSETMODE, &data_mode); \ assert(__retval >= 0); \ __retval = write(device_handle, &val, 1); \ assert(__retval >= 0); \ } while (0) #define AMT_DR(val) \ do { \ int __retval; \ \ __retval = ioctl(device_handle, PPSETMODE, &data_mode); \ assert(__retval >= 0); \ __retval = read(device_handle, &val, 1); \ assert(__retval >= 0); \ } while (0) #else #define AMT_AW(val) do { outb(val, amt_jtagaccel_port + 3); } while (0) #define AMT_AR(val) do { val = inb(amt_jtagaccel_port + 3); } while (0) #define AMT_DW(val) do { outb(val, amt_jtagaccel_port + 4); } while (0) #define AMT_DR(val) do { val = inb(amt_jtagaccel_port + 4); } while (0) #endif /* PARPORT_USE_PPDEV */ /* tap_move[i][j]: tap movement command to go from state i to state j * 0: Test-Logic-Reset * 1: Run-Test/Idle * 2: Shift-DR * 3: Pause-DR * 4: Shift-IR * 5: Pause-IR */ static const uint8_t amt_jtagaccel_tap_move[6][6][2] = { /* RESET IDLE DRSHIFT DRPAUSE IRSHIFT IRPAUSE */ { {0x1f, 0x00}, {0x0f, 0x00}, {0x05, 0x00}, {0x0a, 0x00}, {0x06, 0x00}, {0x96, 0x00} }, /* RESET */ { {0x1f, 0x00}, {0x00, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x0b, 0x00} }, /* IDLE */ { {0x1f, 0x00}, {0x0d, 0x00}, {0x00, 0x00}, {0x01, 0x00}, {0x8f, 0x09}, {0x8f, 0x01} }, /* DRSHIFT */ { {0x1f, 0x00}, {0x0c, 0x00}, {0x08, 0x00}, {0x00, 0x00}, {0x8f, 0x09}, {0x8f, 0x01} }, /* DRPAUSE */ { {0x1f, 0x00}, {0x0d, 0x00}, {0x07, 0x00}, {0x97, 0x00}, {0x00, 0x00}, {0x01, 0x00} }, /* IRSHIFT */ { {0x1f, 0x00}, {0x0c, 0x00}, {0x07, 0x00}, {0x97, 0x00}, {0x08, 0x00}, {0x00, 0x00} }, /* IRPAUSE */ }; static void amt_jtagaccel_reset(int trst, int srst) { if (trst == 1) aw_control_rst |= 0x4; else if (trst == 0) aw_control_rst &= ~0x4; if (srst == 1) aw_control_rst |= 0x1; else if (srst == 0) aw_control_rst &= ~0x1; AMT_AW(aw_control_rst); } static int amt_jtagaccel_speed(int speed) { aw_control_baudrate &= 0xf0; aw_control_baudrate |= speed & 0x0f; AMT_AW(aw_control_baudrate); return ERROR_OK; } static void amt_jtagaccel_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } static void amt_wait_scan_busy(void) { int timeout = 4096; uint8_t ar_status; AMT_AR(ar_status); while (((ar_status) & 0x80) && (timeout-- > 0)) AMT_AR(ar_status); if (ar_status & 0x80) { LOG_ERROR( "amt_jtagaccel timed out while waiting for end of scan, rtck was %s, last AR_STATUS: 0x%2.2x", (rtck_enabled) ? "enabled" : "disabled", ar_status); exit(-1); } } static void amt_jtagaccel_state_move(void) { uint8_t aw_scan_tms_5; uint8_t tms_scan[2]; tap_state_t cur_state = tap_get_state(); tap_state_t end_state = tap_get_end_state(); tms_scan[0] = amt_jtagaccel_tap_move[tap_move_ndx(cur_state)][tap_move_ndx(end_state)][0]; tms_scan[1] = amt_jtagaccel_tap_move[tap_move_ndx(cur_state)][tap_move_ndx(end_state)][1]; aw_scan_tms_5 = 0x40 | (tms_scan[0] & 0x1f); AMT_AW(aw_scan_tms_5); int jtag_speed = 0; int retval = adapter_get_speed(&jtag_speed); assert(retval == ERROR_OK); if (jtag_speed > 3 || rtck_enabled) amt_wait_scan_busy(); if (tms_scan[0] & 0x80) { aw_scan_tms_5 = 0x40 | (tms_scan[1] & 0x1f); AMT_AW(aw_scan_tms_5); if (jtag_speed > 3 || rtck_enabled) amt_wait_scan_busy(); } tap_set_state(end_state); } static void amt_jtagaccel_runtest(int num_cycles) { int i = 0; uint8_t aw_scan_tms_5; uint8_t aw_scan_tms_1to4; tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { amt_jtagaccel_end_state(TAP_IDLE); amt_jtagaccel_state_move(); } while (num_cycles - i >= 5) { aw_scan_tms_5 = 0x40; AMT_AW(aw_scan_tms_5); i += 5; } if (num_cycles - i > 0) { aw_scan_tms_1to4 = 0x80 | ((num_cycles - i - 1) & 0x3) << 4; AMT_AW(aw_scan_tms_1to4); } amt_jtagaccel_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) amt_jtagaccel_state_move(); } static void amt_jtagaccel_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size) { int bits_left = scan_size; int bit_count = 0; tap_state_t saved_end_state = tap_get_end_state(); uint8_t aw_tdi_option; uint8_t dw_tdi_scan; uint8_t dr_tdo; uint8_t aw_tms_scan; uint8_t tms_scan[2]; int jtag_speed_var; int retval = adapter_get_speed(&jtag_speed_var); assert(retval == ERROR_OK); if (ir_scan) amt_jtagaccel_end_state(TAP_IRSHIFT); else amt_jtagaccel_end_state(TAP_DRSHIFT); /* Only move if we're not already there */ if (tap_get_state() != tap_get_end_state()) amt_jtagaccel_state_move(); amt_jtagaccel_end_state(saved_end_state); /* handle unaligned bits at the beginning */ if ((scan_size - 1) % 8) { aw_tdi_option = 0x30 | (((scan_size - 1) % 8) - 1); AMT_AW(aw_tdi_option); dw_tdi_scan = buf_get_u32(buffer, bit_count, (scan_size - 1) % 8) & 0xff; AMT_DW(dw_tdi_scan); if (jtag_speed_var > 3 || rtck_enabled) amt_wait_scan_busy(); if ((type == SCAN_IN) || (type == SCAN_IO)) { AMT_DR(dr_tdo); dr_tdo = dr_tdo >> (8 - ((scan_size - 1) % 8)); buf_set_u32(buffer, bit_count, (scan_size - 1) % 8, dr_tdo); } bit_count += (scan_size - 1) % 8; bits_left -= (scan_size - 1) % 8; } while (bits_left - 1 >= 8) { dw_tdi_scan = buf_get_u32(buffer, bit_count, 8) & 0xff; AMT_DW(dw_tdi_scan); if (jtag_speed_var > 3 || rtck_enabled) amt_wait_scan_busy(); if ((type == SCAN_IN) || (type == SCAN_IO)) { AMT_DR(dr_tdo); buf_set_u32(buffer, bit_count, 8, dr_tdo); } bit_count += 8; bits_left -= 8; } tms_scan[0] = amt_jtagaccel_tap_move[tap_move_ndx(tap_get_state())][tap_move_ndx(tap_get_end_state())][0]; tms_scan[1] = amt_jtagaccel_tap_move[tap_move_ndx(tap_get_state())][tap_move_ndx(tap_get_end_state())][1]; aw_tms_scan = 0x40 | (tms_scan[0] & 0x1f) | (buf_get_u32(buffer, bit_count, 1) << 5); AMT_AW(aw_tms_scan); if (jtag_speed_var > 3 || rtck_enabled) amt_wait_scan_busy(); if ((type == SCAN_IN) || (type == SCAN_IO)) { AMT_DR(dr_tdo); dr_tdo = dr_tdo >> 7; buf_set_u32(buffer, bit_count, 1, dr_tdo); } if (tms_scan[0] & 0x80) { aw_tms_scan = 0x40 | (tms_scan[1] & 0x1f); AMT_AW(aw_tms_scan); if (jtag_speed_var > 3 || rtck_enabled) amt_wait_scan_busy(); } tap_set_state(tap_get_end_state()); } static int amt_jtagaccel_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; int retval; /* return ERROR_OK, unless a jtag_read_buffer returns a failed check * that wasn't handled by a caller-provided error handler */ retval = ERROR_OK; while (cmd) { switch (cmd->type) { case JTAG_RESET: LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); if (cmd->cmd.reset->trst == 1) tap_set_state(TAP_RESET); amt_jtagaccel_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); amt_jtagaccel_end_state(cmd->cmd.runtest->end_state); amt_jtagaccel_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); amt_jtagaccel_end_state(cmd->cmd.statemove->end_state); amt_jtagaccel_state_move(); break; case JTAG_SCAN: LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); amt_jtagaccel_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); amt_jtagaccel_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; free(buffer); break; case JTAG_SLEEP: LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); jtag_sleep(cmd->cmd.sleep->us); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } return retval; } #if PARPORT_USE_GIVEIO == 1 int amt_jtagaccel_get_giveio_access(void) { HANDLE h; OSVERSIONINFO version; version.dwOSVersionInfoSize = sizeof(version); if (!GetVersionEx(&version)) { errno = EINVAL; return -1; } if (version.dwPlatformId != VER_PLATFORM_WIN32_NT) return 0; h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { errno = ENODEV; return -1; } CloseHandle(h); return 0; } #endif static int amt_jtagaccel_init(void) { #if PARPORT_USE_PPDEV == 1 char buffer[256]; int i = 0; uint8_t control_port; #else uint8_t status_port; #endif uint8_t ar_status; #if PARPORT_USE_PPDEV == 1 if (device_handle > 0) { LOG_ERROR("device is already opened"); return ERROR_JTAG_INIT_FAILED; } snprintf(buffer, 256, "/dev/parport%d", amt_jtagaccel_port); device_handle = open(buffer, O_RDWR); if (device_handle < 0) { LOG_ERROR( "cannot open device. check it exists and that user read and write rights are set"); return ERROR_JTAG_INIT_FAILED; } i = ioctl(device_handle, PPCLAIM); if (i < 0) { LOG_ERROR("cannot claim device"); return ERROR_JTAG_INIT_FAILED; } i = IEEE1284_MODE_EPP; i = ioctl(device_handle, PPSETMODE, &i); if (i < 0) { LOG_ERROR(" cannot set compatible mode to device"); return ERROR_JTAG_INIT_FAILED; } control_port = 0x00; i = ioctl(device_handle, PPWCONTROL, &control_port); control_port = 0x04; i = ioctl(device_handle, PPWCONTROL, &control_port); #else if (amt_jtagaccel_port == 0) { amt_jtagaccel_port = 0x378; LOG_WARNING("No parport port specified, using default '0x378' (LPT1)"); } #if PARPORT_USE_GIVEIO == 1 if (amt_jtagaccel_get_giveio_access() != 0) { #else /* PARPORT_USE_GIVEIO */ if (ioperm(amt_jtagaccel_port, 5, 1) != 0) { #endif /* PARPORT_USE_GIVEIO */ LOG_ERROR("missing privileges for direct i/o"); return ERROR_JTAG_INIT_FAILED; } /* prepare epp port * clear timeout */ status_port = inb(amt_jtagaccel_port + 1); outb(status_port | 0x1, amt_jtagaccel_port + 1); /* reset epp port */ outb(0x00, amt_jtagaccel_port + 2); outb(0x04, amt_jtagaccel_port + 2); #endif if (rtck_enabled) { /* set RTCK enable bit */ aw_control_fsm |= 0x02; } /* enable JTAG port */ aw_control_fsm |= 0x04; AMT_AW(aw_control_fsm); enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) aw_control_rst &= ~0x8; else aw_control_rst |= 0x8; if (jtag_reset_config & RESET_SRST_PUSH_PULL) aw_control_rst &= ~0x2; else aw_control_rst |= 0x2; amt_jtagaccel_reset(0, 0); /* read status register */ AMT_AR(ar_status); LOG_DEBUG("AR_STATUS: 0x%2.2x", ar_status); return ERROR_OK; } static int amt_jtagaccel_quit(void) { return ERROR_OK; } COMMAND_HANDLER(amt_jtagaccel_handle_parport_port_command) { if (CMD_ARGC == 1) { /* only if the port wasn't overwritten by cmdline */ if (amt_jtagaccel_port == 0) { uint16_t port; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port); amt_jtagaccel_port = port; } else { LOG_ERROR("The parport port was already configured!"); return ERROR_FAIL; } } command_print(CMD, "parport port = %u", amt_jtagaccel_port); return ERROR_OK; } COMMAND_HANDLER(amt_jtagaccel_handle_rtck_command) { if (CMD_ARGC == 0) { command_print(CMD, "amt_jtagaccel RTCK feature %s", (rtck_enabled) ? "enabled" : "disabled"); return ERROR_OK; } else { if (strcmp(CMD_ARGV[0], "enabled") == 0) rtck_enabled = 1; else rtck_enabled = 0; } return ERROR_OK; } static const struct command_registration amtjtagaccel_command_handlers[] = { { .name = "parport_port", .handler = &amt_jtagaccel_handle_parport_port_command, .mode = COMMAND_CONFIG, .help = "configure or display the parallel port to use", .usage = "[port_num]", }, { /** * @todo Remove this "rtck" command; just use the standard * mechanism to enable/disable adaptive clocking. First * implement the standard mechanism and deprecate "rtck"; * after a year or so, it'll be safe to remove this. */ .name = "rtck", .handler = &amt_jtagaccel_handle_rtck_command, .mode = COMMAND_CONFIG, .help = "configure or display RTCK support", .usage = "[enable|disable]", }, COMMAND_REGISTRATION_DONE }; static struct jtag_interface amt_jtagaccel_interface = { .execute_queue = amt_jtagaccel_execute_queue, }; struct adapter_driver amt_jtagaccel_adapter_driver = { .name = "amt_jtagaccel", .transports = jtag_only, .commands = amtjtagaccel_command_handlers, .init = amt_jtagaccel_init, .quit = amt_jtagaccel_quit, .speed = amt_jtagaccel_speed, .jtag_ops = &amt_jtagaccel_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/arm-jtag-ew.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by Dimitar Dimitrov <dinuxbg@gmail.com> * * based on Dominic Rath's and Benedikt Sauter's usbprog.c * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/interface.h> #include <jtag/commands.h> #include "helper/system.h" #include "libusb_helper.h" #define USB_VID 0x15ba #define USB_PID 0x001e #define ARMJTAGEW_EPT_BULK_OUT 0x01u #define ARMJTAGEW_EPT_BULK_IN 0x82u #define ARMJTAGEW_USB_TIMEOUT 2000 #define ARMJTAGEW_IN_BUFFER_SIZE (4*1024) #define ARMJTAGEW_OUT_BUFFER_SIZE (4*1024) /* USB command request codes. */ #define CMD_GET_VERSION 0x00 #define CMD_SELECT_DPIMPL 0x10 #define CMD_SET_TCK_FREQUENCY 0x11 #define CMD_GET_TCK_FREQUENCY 0x12 #define CMD_MEASURE_MAX_TCK_FREQ 0x15 #define CMD_MEASURE_RTCK_RESPONSE 0x16 #define CMD_TAP_SHIFT 0x17 #define CMD_SET_TAPHW_STATE 0x20 #define CMD_GET_TAPHW_STATE 0x21 #define CMD_TGPWR_SETUP 0x22 /* Global USB buffers */ static uint8_t usb_in_buffer[ARMJTAGEW_IN_BUFFER_SIZE]; static uint8_t usb_out_buffer[ARMJTAGEW_OUT_BUFFER_SIZE]; /* Queue command functions */ static void armjtagew_end_state(tap_state_t state); static void armjtagew_state_move(void); static void armjtagew_path_move(int num_states, tap_state_t *path); static void armjtagew_runtest(int num_cycles); static void armjtagew_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); static void armjtagew_reset(int trst, int srst); /* static void armjtagew_simple_command(uint8_t command); */ static int armjtagew_get_status(void); /* tap buffer functions */ static void armjtagew_tap_init(void); static int armjtagew_tap_execute(void); static void armjtagew_tap_ensure_space(int scans, int bits); static void armjtagew_tap_append_step(int tms, int tdi); static void armjtagew_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command); /* ARM-JTAG-EW lowlevel functions */ struct armjtagew { struct libusb_device_handle *usb_handle; }; static struct armjtagew *armjtagew_usb_open(void); static void armjtagew_usb_close(struct armjtagew *armjtagew); static int armjtagew_usb_message(struct armjtagew *armjtagew, int out_length, int in_length); static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length); static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length); /* helper functions */ static int armjtagew_get_version_info(void); #ifdef _DEBUG_USB_COMMS_ static void armjtagew_debug_buffer(uint8_t *buffer, int length); #endif static struct armjtagew *armjtagew_handle; /************************************************************************** * External interface implementation */ static int armjtagew_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; int scan_size; enum scan_type type; uint8_t *buffer; while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); armjtagew_end_state(cmd->cmd.runtest->end_state); armjtagew_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); armjtagew_end_state(cmd->cmd.statemove->end_state); armjtagew_state_move(); break; case JTAG_PATHMOVE: LOG_DEBUG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); armjtagew_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); break; case JTAG_SCAN: LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); armjtagew_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); LOG_DEBUG_IO("scan input, length = %d", scan_size); #ifdef _DEBUG_USB_COMMS_ armjtagew_debug_buffer(buffer, (scan_size + 7) / 8); #endif type = jtag_scan_type(cmd->cmd.scan); armjtagew_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); break; case JTAG_RESET: LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); armjtagew_tap_execute(); if (cmd->cmd.reset->trst == 1) tap_set_state(TAP_RESET); armjtagew_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_SLEEP: LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); armjtagew_tap_execute(); jtag_sleep(cmd->cmd.sleep->us); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } return armjtagew_tap_execute(); } /* Sets speed in kHz. */ static int armjtagew_speed(int speed) { int result; int speed_real; usb_out_buffer[0] = CMD_SET_TCK_FREQUENCY; buf_set_u32(usb_out_buffer + 1, 0, 32, speed*1000); result = armjtagew_usb_message(armjtagew_handle, 5, 4); if (result < 0) { LOG_ERROR("ARM-JTAG-EW setting speed failed (%d)", result); return ERROR_JTAG_DEVICE_ERROR; } usb_out_buffer[0] = CMD_GET_TCK_FREQUENCY; result = armjtagew_usb_message(armjtagew_handle, 1, 4); speed_real = (int)buf_get_u32(usb_in_buffer, 0, 32) / 1000; if (result < 0) { LOG_ERROR("ARM-JTAG-EW getting speed failed (%d)", result); return ERROR_JTAG_DEVICE_ERROR; } else LOG_INFO("Requested speed %dkHz, emulator reported %dkHz.", speed, speed_real); return ERROR_OK; } static int armjtagew_khz(int khz, int *jtag_speed) { *jtag_speed = khz; return ERROR_OK; } static int armjtagew_speed_div(int speed, int *khz) { *khz = speed; return ERROR_OK; } static int armjtagew_init(void) { int check_cnt; armjtagew_handle = armjtagew_usb_open(); if (!armjtagew_handle) { LOG_ERROR( "Cannot find ARM-JTAG-EW Interface! Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; } check_cnt = 0; while (check_cnt < 3) { if (armjtagew_get_version_info() == ERROR_OK) { /* attempt to get status */ armjtagew_get_status(); break; } check_cnt++; } if (check_cnt == 3) LOG_INFO("ARM-JTAG-EW initial read failed, don't worry"); /* Initial JTAG speed (for reset and initialization): 32 kHz */ armjtagew_speed(32); LOG_INFO("ARM-JTAG-EW JTAG Interface ready"); armjtagew_reset(0, 0); armjtagew_tap_init(); return ERROR_OK; } static int armjtagew_quit(void) { armjtagew_usb_close(armjtagew_handle); return ERROR_OK; } /************************************************************************** * Queue command implementations */ static void armjtagew_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } /* Goes to the end state. */ static void armjtagew_state_move(void) { int i; int tms = 0; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); for (i = 0; i < tms_count; i++) { tms = (tms_scan >> i) & 1; armjtagew_tap_append_step(tms, 0); } tap_set_state(tap_get_end_state()); } static void armjtagew_path_move(int num_states, tap_state_t *path) { int i; for (i = 0; i < num_states; i++) { /* * TODO: The ARM-JTAG-EW hardware delays TDI with 3 TCK cycles when in RTCK mode. * Either handle that here, or update the documentation with examples * how to fix that in the configuration files. */ if (path[i] == tap_state_transition(tap_get_state(), false)) armjtagew_tap_append_step(0, 0); else if (path[i] == tap_state_transition(tap_get_state(), true)) armjtagew_tap_append_step(1, 0); else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(path[i])); exit(-1); } tap_set_state(path[i]); } tap_set_end_state(tap_get_state()); } static void armjtagew_runtest(int num_cycles) { int i; tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { armjtagew_end_state(TAP_IDLE); armjtagew_state_move(); } /* execute num_cycles */ for (i = 0; i < num_cycles; i++) armjtagew_tap_append_step(0, 0); /* finish in end_state */ armjtagew_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) armjtagew_state_move(); } static void armjtagew_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) { tap_state_t saved_end_state; armjtagew_tap_ensure_space(1, scan_size + 8); saved_end_state = tap_get_end_state(); /* Move to appropriate scan state */ armjtagew_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); /* Only move if we're not already there */ if (tap_get_state() != tap_get_end_state()) armjtagew_state_move(); armjtagew_end_state(saved_end_state); /* Scan */ armjtagew_tap_append_scan(scan_size, buffer, command); /* We are in Exit1, go to Pause */ armjtagew_tap_append_step(0, 0); tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) armjtagew_state_move(); } static void armjtagew_reset(int trst, int srst) { const uint8_t trst_mask = (1u << 5); const uint8_t srst_mask = (1u << 6); uint8_t val = 0; uint8_t outp_en = 0; uint8_t change_mask = 0; int result; LOG_DEBUG("trst: %i, srst: %i", trst, srst); if (srst == 0) { val |= srst_mask; outp_en &= ~srst_mask; /* tristate */ change_mask |= srst_mask; } else if (srst == 1) { val &= ~srst_mask; outp_en |= srst_mask; change_mask |= srst_mask; } if (trst == 0) { val |= trst_mask; outp_en &= ~trst_mask; /* tristate */ change_mask |= trst_mask; } else if (trst == 1) { val &= ~trst_mask; outp_en |= trst_mask; change_mask |= trst_mask; } usb_out_buffer[0] = CMD_SET_TAPHW_STATE; usb_out_buffer[1] = val; usb_out_buffer[2] = outp_en; usb_out_buffer[3] = change_mask; result = armjtagew_usb_write(armjtagew_handle, 4); if (result != 4) LOG_ERROR("ARM-JTAG-EW TRST/SRST pin set failed failed (%d)", result); } static int armjtagew_get_status(void) { int result; usb_out_buffer[0] = CMD_GET_TAPHW_STATE; result = armjtagew_usb_message(armjtagew_handle, 1, 12); if (result == 0) { unsigned int u_tg = buf_get_u32(usb_in_buffer, 0, 16); LOG_INFO( "U_tg = %d mV, U_aux = %d mV, U_tgpwr = %d mV, I_tgpwr = %d mA, D1 = %d, Target power %s %s", (int)(buf_get_u32(usb_in_buffer + 0, 0, 16)), (int)(buf_get_u32(usb_in_buffer + 2, 0, 16)), (int)(buf_get_u32(usb_in_buffer + 4, 0, 16)), (int)(buf_get_u32(usb_in_buffer + 6, 0, 16)), usb_in_buffer[9], usb_in_buffer[11] ? "OVERCURRENT" : "OK", usb_in_buffer[10] ? "enabled" : "disabled"); if (u_tg < 1500) LOG_ERROR("Vref too low. Check Target Power"); } else LOG_ERROR("ARM-JTAG-EW command CMD_GET_TAPHW_STATE failed (%d)", result); return ERROR_OK; } static int armjtagew_get_version_info(void) { int result; char sn[16]; char auxinfo[257]; /* query hardware version */ usb_out_buffer[0] = CMD_GET_VERSION; result = armjtagew_usb_message(armjtagew_handle, 1, 4 + 15 + 256); if (result != 0) { LOG_ERROR("ARM-JTAG-EW command CMD_GET_VERSION failed (%d)", result); return ERROR_JTAG_DEVICE_ERROR; } memcpy(sn, usb_in_buffer + 4, 15); sn[15] = '\0'; memcpy(auxinfo, usb_in_buffer + 4+15, 256); auxinfo[256] = '\0'; LOG_INFO( "ARM-JTAG-EW firmware version %d.%d, hardware revision %c, SN=%s, Additional info: %s", usb_in_buffer[1], usb_in_buffer[0], isgraph(usb_in_buffer[2]) ? usb_in_buffer[2] : 'X', sn, auxinfo); if (1 != usb_in_buffer[1] || 6 != usb_in_buffer[0]) LOG_WARNING( "ARM-JTAG-EW firmware version %d.%d is untested with this version of OpenOCD. You might experience unexpected behavior.", usb_in_buffer[1], usb_in_buffer[0]); return ERROR_OK; } COMMAND_HANDLER(armjtagew_handle_armjtagew_info_command) { if (armjtagew_get_version_info() == ERROR_OK) { /* attempt to get status */ armjtagew_get_status(); } return ERROR_OK; } static const struct command_registration armjtagew_command_handlers[] = { { .name = "armjtagew_info", .handler = &armjtagew_handle_armjtagew_info_command, .mode = COMMAND_EXEC, .help = "query armjtagew info", .usage = "", }, COMMAND_REGISTRATION_DONE }; static struct jtag_interface armjtagew_interface = { .execute_queue = armjtagew_execute_queue, }; struct adapter_driver armjtagew_adapter_driver = { .name = "arm-jtag-ew", .transports = jtag_only, .commands = armjtagew_command_handlers, .init = armjtagew_init, .quit = armjtagew_quit, .speed = armjtagew_speed, .khz = armjtagew_khz, .speed_div = armjtagew_speed_div, .jtag_ops = &armjtagew_interface, }; /************************************************************************** * ARM-JTAG-EW tap functions */ /* 2048 is the max value we can use here */ #define ARMJTAGEW_TAP_BUFFER_SIZE 2048 static int tap_length; static uint8_t tms_buffer[ARMJTAGEW_TAP_BUFFER_SIZE]; static uint8_t tdi_buffer[ARMJTAGEW_TAP_BUFFER_SIZE]; static uint8_t tdo_buffer[ARMJTAGEW_TAP_BUFFER_SIZE]; struct pending_scan_result { int first; /* First bit position in tdo_buffer to read */ int length; /* Number of bits to read */ struct scan_command *command; /* Corresponding scan command */ uint8_t *buffer; }; #define MAX_PENDING_SCAN_RESULTS 256 static int pending_scan_results_length; static struct pending_scan_result pending_scan_results_buffer[MAX_PENDING_SCAN_RESULTS]; static int last_tms; static void armjtagew_tap_init(void) { tap_length = 0; pending_scan_results_length = 0; } static void armjtagew_tap_ensure_space(int scans, int bits) { int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length; int available_bits = ARMJTAGEW_TAP_BUFFER_SIZE * 8 - tap_length; if (scans > available_scans || bits > available_bits) armjtagew_tap_execute(); } static void armjtagew_tap_append_step(int tms, int tdi) { last_tms = tms; int index_local = tap_length / 8; if (index_local < ARMJTAGEW_TAP_BUFFER_SIZE) { int bit_index = tap_length % 8; uint8_t bit = 1 << bit_index; if (tms) tms_buffer[index_local] |= bit; else tms_buffer[index_local] &= ~bit; if (tdi) tdi_buffer[index_local] |= bit; else tdi_buffer[index_local] &= ~bit; tap_length++; } else LOG_ERROR("armjtagew_tap_append_step, overflow"); } void armjtagew_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command) { struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[pending_scan_results_length]; int i; pending_scan_result->first = tap_length; pending_scan_result->length = length; pending_scan_result->command = command; pending_scan_result->buffer = buffer; for (i = 0; i < length; i++) armjtagew_tap_append_step((i < length-1 ? 0 : 1), (buffer[i/8] >> (i%8)) & 1); pending_scan_results_length++; } /* Pad and send a tap sequence to the device, and receive the answer. * For the purpose of padding we assume that we are in idle or pause state. */ static int armjtagew_tap_execute(void) { int byte_length; int tms_offset; int tdi_offset; int i; int result; if (tap_length > 0) { /* Pad last byte so that tap_length is divisible by 8 */ while (tap_length % 8 != 0) { /* More of the last TMS value keeps us in the same state, * analogous to free-running JTAG interfaces. */ armjtagew_tap_append_step(last_tms, 0); } byte_length = tap_length / 8; usb_out_buffer[0] = CMD_TAP_SHIFT; buf_set_u32(usb_out_buffer + 1, 0, 16, byte_length); tms_offset = 3; for (i = 0; i < byte_length; i++) usb_out_buffer[tms_offset + i] = flip_u32(tms_buffer[i], 8); tdi_offset = tms_offset + byte_length; for (i = 0; i < byte_length; i++) usb_out_buffer[tdi_offset + i] = flip_u32(tdi_buffer[i], 8); result = armjtagew_usb_message(armjtagew_handle, 3 + 2 * byte_length, byte_length + 4); if (result == 0) { int stat_local; stat_local = (int)buf_get_u32(usb_in_buffer + byte_length, 0, 32); if (stat_local) { LOG_ERROR( "armjtagew_tap_execute, emulator returned error code %d for a CMD_TAP_SHIFT command", stat_local); return ERROR_JTAG_QUEUE_FAILED; } for (i = 0; i < byte_length; i++) tdo_buffer[i] = flip_u32(usb_in_buffer[i], 8); for (i = 0; i < pending_scan_results_length; i++) { struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[i]; uint8_t *buffer = pending_scan_result->buffer; int length = pending_scan_result->length; int first = pending_scan_result->first; struct scan_command *command = pending_scan_result->command; /* Copy to buffer */ buf_set_buf(tdo_buffer, first, buffer, 0, length); LOG_DEBUG_IO("pending scan result, length = %d", length); #ifdef _DEBUG_USB_COMMS_ armjtagew_debug_buffer(buffer, byte_length); #endif if (jtag_read_buffer(buffer, command) != ERROR_OK) { armjtagew_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } free(pending_scan_result->buffer); } } else { LOG_ERROR("armjtagew_tap_execute, wrong result %d, expected %d", result, byte_length); return ERROR_JTAG_QUEUE_FAILED; } armjtagew_tap_init(); } return ERROR_OK; } /**************************************************************************** * JLink USB low-level functions */ static struct armjtagew *armjtagew_usb_open(void) { const uint16_t vids[] = { USB_VID, 0 }; const uint16_t pids[] = { USB_PID, 0 }; struct libusb_device_handle *dev; if (jtag_libusb_open(vids, pids, &dev, NULL) != ERROR_OK) return NULL; struct armjtagew *result = malloc(sizeof(struct armjtagew)); result->usb_handle = dev; #if 0 /* libusb_set_configuration required under win32 */ struct libusb_config_descriptor *config; struct libusb_device *usb_dev = libusb_get_device(dev); libusb_get_config_descriptor(usb_dev, 0, &config); libusb_set_configuration(dev, config->bConfigurationValue); #endif libusb_claim_interface(dev, 0); #if 0 /* * This makes problems under Mac OS X. And is not needed * under Windows. Hopefully this will not break a linux build */ libusb_set_interface_alt_setting(dev, 0, 0); #endif return result; } static void armjtagew_usb_close(struct armjtagew *armjtagew) { libusb_close(armjtagew->usb_handle); free(armjtagew); } /* Send a message and receive the reply. */ static int armjtagew_usb_message(struct armjtagew *armjtagew, int out_length, int in_length) { int result; result = armjtagew_usb_write(armjtagew, out_length); if (result == out_length) { result = armjtagew_usb_read(armjtagew, in_length); if (result != in_length) { LOG_ERROR("jtag_libusb_bulk_read failed (requested=%d, result=%d)", in_length, result); return -1; } } else { LOG_ERROR("jtag_libusb_bulk_write failed (requested=%d, result=%d)", out_length, result); return -1; } return 0; } /* Write data from out_buffer to USB. */ static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length) { int result; int transferred; if (out_length > ARMJTAGEW_OUT_BUFFER_SIZE) { LOG_ERROR("armjtagew_write illegal out_length=%d (max=%d)", out_length, ARMJTAGEW_OUT_BUFFER_SIZE); return -1; } result = jtag_libusb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT, (char *)usb_out_buffer, out_length, ARMJTAGEW_USB_TIMEOUT, &transferred); LOG_DEBUG_IO("armjtagew_usb_write, out_length = %d, result = %d", out_length, result); #ifdef _DEBUG_USB_COMMS_ armjtagew_debug_buffer(usb_out_buffer, out_length); #endif if (result != ERROR_OK) return -1; return transferred; } /* Read data from USB into in_buffer. */ static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length) { int transferred; int result = jtag_libusb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN, (char *)usb_in_buffer, exp_in_length, ARMJTAGEW_USB_TIMEOUT, &transferred); LOG_DEBUG_IO("armjtagew_usb_read, result = %d", result); #ifdef _DEBUG_USB_COMMS_ armjtagew_debug_buffer(usb_in_buffer, result); #endif if (result != ERROR_OK) return -1; return transferred; } #ifdef _DEBUG_USB_COMMS_ #define BYTES_PER_LINE 16 static void armjtagew_debug_buffer(uint8_t *buffer, int length) { char line[8 + 3 * BYTES_PER_LINE + 1]; for (int i = 0; i < length; i += BYTES_PER_LINE) { int n = snprintf(line, 9, "%04x", i); for (int j = i; j < i + BYTES_PER_LINE && j < length; j++) n += snprintf(line + n, 4, " %02x", buffer[j]); LOG_DEBUG("%s", line); /* Prevent GDB timeout (writing to log might take some time) */ keep_alive(); } } #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/at91rm9200.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006 by Anders Larsen * * al@alarsen.net * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/interface.h> #include "bitbang.h" #include <sys/mman.h> /* AT91RM9200 */ #define AT91C_BASE_SYS (0xfffff000) /* GPIO assignment */ #define PIOA (0 << 7) #define PIOB (1 << 7) #define PIOC (2 << 7) #define PIOD (3 << 7) #define PIO_PER (0) /* PIO enable */ #define PIO_OER (4) /* output enable */ #define PIO_ODR (5) /* output disable */ #define PIO_SODR (12) /* set output data */ #define PIO_CODR (13) /* clear output data */ #define PIO_PDSR (15) /* pin data status */ #define PIO_PPUER (25) /* pull-up enable */ #define NC (0) /* not connected */ #define P0 (1 << 0) #define P1 (1 << 1) #define P2 (1 << 2) #define P3 (1 << 3) #define P4 (1 << 4) #define P5 (1 << 5) #define P6 (1 << 6) #define P7 (1 << 7) #define P8 (1 << 8) #define P9 (1 << 9) #define P10 (1 << 10) #define P11 (1 << 11) #define P12 (1 << 12) #define P13 (1 << 13) #define P14 (1 << 14) #define P15 (1 << 15) #define P16 (1 << 16) #define P17 (1 << 17) #define P18 (1 << 18) #define P19 (1 << 19) #define P20 (1 << 20) #define P21 (1 << 21) #define P22 (1 << 22) #define P23 (1 << 23) #define P24 (1 << 24) #define P25 (1 << 25) #define P26 (1 << 26) #define P27 (1 << 27) #define P28 (1 << 28) #define P29 (1 << 29) #define P30 (1 << 30) #define P31 (1 << 31) struct device_t { const char *name; int TDO_PIO; /* PIO holding TDO */ uint32_t TDO_MASK; /* TDO bitmask */ int TRST_PIO; /* PIO holding TRST */ uint32_t TRST_MASK; /* TRST bitmask */ int TMS_PIO; /* PIO holding TMS */ uint32_t TMS_MASK; /* TMS bitmask */ int TCK_PIO; /* PIO holding TCK */ uint32_t TCK_MASK; /* TCK bitmask */ int TDI_PIO; /* PIO holding TDI */ uint32_t TDI_MASK; /* TDI bitmask */ int SRST_PIO; /* PIO holding SRST */ uint32_t SRST_MASK; /* SRST bitmask */ }; static const struct device_t devices[] = { { "rea_ecr", PIOD, P27, PIOA, NC, PIOD, P23, PIOD, P24, PIOD, P26, PIOC, P5 }, { .name = NULL }, }; /* configuration */ static char *at91rm9200_device; /* interface variables */ static const struct device_t *device; static int dev_mem_fd; static void *sys_controller; static uint32_t *pio_base; /* low level command set */ static bb_value_t at91rm9200_read(void); static int at91rm9200_write(int tck, int tms, int tdi); static int at91rm9200_init(void); static int at91rm9200_quit(void); static struct bitbang_interface at91rm9200_bitbang = { .read = at91rm9200_read, .write = at91rm9200_write, .blink = NULL, }; static bb_value_t at91rm9200_read(void) { return (pio_base[device->TDO_PIO + PIO_PDSR] & device->TDO_MASK) ? BB_HIGH : BB_LOW; } static int at91rm9200_write(int tck, int tms, int tdi) { if (tck) pio_base[device->TCK_PIO + PIO_SODR] = device->TCK_MASK; else pio_base[device->TCK_PIO + PIO_CODR] = device->TCK_MASK; if (tms) pio_base[device->TMS_PIO + PIO_SODR] = device->TMS_MASK; else pio_base[device->TMS_PIO + PIO_CODR] = device->TMS_MASK; if (tdi) pio_base[device->TDI_PIO + PIO_SODR] = device->TDI_MASK; else pio_base[device->TDI_PIO + PIO_CODR] = device->TDI_MASK; return ERROR_OK; } /* (1) assert or (0) deassert reset lines */ static int at91rm9200_reset(int trst, int srst) { if (trst == 0) pio_base[device->TRST_PIO + PIO_SODR] = device->TRST_MASK; else if (trst == 1) pio_base[device->TRST_PIO + PIO_CODR] = device->TRST_MASK; if (srst == 0) pio_base[device->SRST_PIO + PIO_SODR] = device->SRST_MASK; else if (srst == 1) pio_base[device->SRST_PIO + PIO_CODR] = device->SRST_MASK; return ERROR_OK; } COMMAND_HANDLER(at91rm9200_handle_device_command) { if (CMD_ARGC == 0) return ERROR_COMMAND_SYNTAX_ERROR; /* only if the device name wasn't overwritten by cmdline */ if (!at91rm9200_device) { at91rm9200_device = malloc(strlen(CMD_ARGV[0]) + sizeof(char)); if (!at91rm9200_device) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } strcpy(at91rm9200_device, CMD_ARGV[0]); } return ERROR_OK; } static const struct command_registration at91rm9200_command_handlers[] = { { .name = "at91rm9200_device", .handler = &at91rm9200_handle_device_command, .mode = COMMAND_CONFIG, .help = "Set at91rm9200 device [default \"rea_ecr\"]", .usage = "<device>", }, COMMAND_REGISTRATION_DONE }; static struct jtag_interface at91rm9200_interface = { .execute_queue = bitbang_execute_queue, }; struct adapter_driver at91rm9200_adapter_driver = { .name = "at91rm9200", .transports = jtag_only, .commands = at91rm9200_command_handlers, .init = at91rm9200_init, .quit = at91rm9200_quit, .reset = at91rm9200_reset, .jtag_ops = &at91rm9200_interface, }; static int at91rm9200_init(void) { const struct device_t *cur_device; cur_device = devices; if (!at91rm9200_device || at91rm9200_device[0] == 0) { at91rm9200_device = "rea_ecr"; LOG_WARNING("No at91rm9200 device specified, using default 'rea_ecr'"); } while (cur_device->name) { if (strcmp(cur_device->name, at91rm9200_device) == 0) { device = cur_device; break; } cur_device++; } if (!device) { LOG_ERROR("No matching device found for %s", at91rm9200_device); return ERROR_JTAG_INIT_FAILED; } bitbang_interface = &at91rm9200_bitbang; dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); if (dev_mem_fd < 0) { LOG_ERROR("open: %s", strerror(errno)); return ERROR_JTAG_INIT_FAILED; } sys_controller = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, AT91C_BASE_SYS); if (sys_controller == MAP_FAILED) { LOG_ERROR("mmap: %s", strerror(errno)); close(dev_mem_fd); return ERROR_JTAG_INIT_FAILED; } pio_base = (uint32_t *)sys_controller + 0x100; /* * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. */ pio_base[device->TDI_PIO + PIO_CODR] = device->TDI_MASK; pio_base[device->TDI_PIO + PIO_OER] = device->TDI_MASK; pio_base[device->TDI_PIO + PIO_PER] = device->TDI_MASK; pio_base[device->TCK_PIO + PIO_CODR] = device->TCK_MASK; pio_base[device->TCK_PIO + PIO_OER] = device->TCK_MASK; pio_base[device->TCK_PIO + PIO_PER] = device->TCK_MASK; pio_base[device->TMS_PIO + PIO_SODR] = device->TMS_MASK; pio_base[device->TMS_PIO + PIO_OER] = device->TMS_MASK; pio_base[device->TMS_PIO + PIO_PER] = device->TMS_MASK; pio_base[device->TRST_PIO + PIO_SODR] = device->TRST_MASK; pio_base[device->TRST_PIO + PIO_OER] = device->TRST_MASK; pio_base[device->TRST_PIO + PIO_PER] = device->TRST_MASK; pio_base[device->SRST_PIO + PIO_SODR] = device->SRST_MASK; pio_base[device->SRST_PIO + PIO_OER] = device->SRST_MASK; pio_base[device->SRST_PIO + PIO_PER] = device->SRST_MASK; pio_base[device->TDO_PIO + PIO_ODR] = device->TDO_MASK; pio_base[device->TDO_PIO + PIO_PPUER] = device->TDO_MASK; pio_base[device->TDO_PIO + PIO_PER] = device->TDO_MASK; return ERROR_OK; } static int at91rm9200_quit(void) { return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/bcm2835gpio.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013 by Paul Fertser, fercerpav@gmail.com * * * * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au * * Based on at91rm9200.c (c) Anders Larsen * * and RPi GPIO examples by Gert van Loo & Dom * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/adapter.h> #include <jtag/interface.h> #include <transport/transport.h> #include "bitbang.h" #include <sys/mman.h> static char *bcm2835_peri_mem_dev; static off_t bcm2835_peri_base = 0x20000000; #define BCM2835_GPIO_BASE (bcm2835_peri_base + 0x200000) /* GPIO controller */ #define BCM2835_PADS_GPIO_0_27 (bcm2835_peri_base + 0x100000) #define BCM2835_PADS_GPIO_0_27_OFFSET (0x2c / 4) /* See "GPIO Function Select Registers (GPFSELn)" in "Broadcom BCM2835 ARM Peripherals" datasheet. */ #define BCM2835_GPIO_MODE_INPUT 0 #define BCM2835_GPIO_MODE_OUTPUT 1 /* GPIO setup macros */ #define MODE_GPIO(g) (*(pio_base+((g)/10))>>(((g)%10)*3) & 7) #define INP_GPIO(g) do { *(pio_base+((g)/10)) &= ~(7<<(((g)%10)*3)); } while (0) #define SET_MODE_GPIO(g, m) do { /* clear the mode bits first, then set as necessary */ \ INP_GPIO(g); \ *(pio_base+((g)/10)) |= ((m)<<(((g)%10)*3)); } while (0) #define OUT_GPIO(g) SET_MODE_GPIO(g, BCM2835_GPIO_MODE_OUTPUT) #define GPIO_SET (*(pio_base+7)) /* sets bits which are 1, ignores bits which are 0 */ #define GPIO_CLR (*(pio_base+10)) /* clears bits which are 1, ignores bits which are 0 */ #define GPIO_LEV (*(pio_base+13)) /* current level of the pin */ static int dev_mem_fd; static volatile uint32_t *pio_base = MAP_FAILED; static volatile uint32_t *pads_base = MAP_FAILED; /* Transition delay coefficients */ static int speed_coeff = 113714; static int speed_offset = 28; static unsigned int jtag_delay; static const struct adapter_gpio_config *adapter_gpio_config; static struct initial_gpio_state { unsigned int mode; unsigned int output_level; } initial_gpio_state[ADAPTER_GPIO_IDX_NUM]; static uint32_t initial_drive_strength_etc; static inline const char *bcm2835_get_mem_dev(void) { if (bcm2835_peri_mem_dev) return bcm2835_peri_mem_dev; return "/dev/gpiomem"; } static inline void bcm2835_gpio_synchronize(void) { /* Ensure that previous writes to GPIO registers are flushed out of * the inner shareable domain to prevent pipelined writes to the * same address being merged. */ __sync_synchronize(); } static inline void bcm2835_delay(void) { for (unsigned int i = 0; i < jtag_delay; i++) asm volatile (""); } static bool is_gpio_config_valid(enum adapter_gpio_config_index idx) { /* Only chip 0 is supported, accept unset value (-1) too */ return adapter_gpio_config[idx].chip_num >= -1 && adapter_gpio_config[idx].chip_num <= 0 && adapter_gpio_config[idx].gpio_num >= 0 && adapter_gpio_config[idx].gpio_num <= 31; } static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int value) { value = value ^ (gpio_config->active_low ? 1 : 0); switch (gpio_config->drive) { case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL: if (value) GPIO_SET = 1 << gpio_config->gpio_num; else GPIO_CLR = 1 << gpio_config->gpio_num; /* For performance reasons assume the GPIO is already set as an output * and therefore the call can be omitted here. */ break; case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN: if (value) { INP_GPIO(gpio_config->gpio_num); } else { GPIO_CLR = 1 << gpio_config->gpio_num; OUT_GPIO(gpio_config->gpio_num); } break; case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE: if (value) { GPIO_SET = 1 << gpio_config->gpio_num; OUT_GPIO(gpio_config->gpio_num); } else { INP_GPIO(gpio_config->gpio_num); } break; } bcm2835_gpio_synchronize(); } static void restore_gpio(enum adapter_gpio_config_index idx) { if (is_gpio_config_valid(idx)) { SET_MODE_GPIO(adapter_gpio_config[idx].gpio_num, initial_gpio_state[idx].mode); if (initial_gpio_state[idx].mode == BCM2835_GPIO_MODE_OUTPUT) { if (initial_gpio_state[idx].output_level) GPIO_SET = 1 << adapter_gpio_config[idx].gpio_num; else GPIO_CLR = 1 << adapter_gpio_config[idx].gpio_num; } } bcm2835_gpio_synchronize(); } static void initialize_gpio(enum adapter_gpio_config_index idx) { if (!is_gpio_config_valid(idx)) return; initial_gpio_state[idx].mode = MODE_GPIO(adapter_gpio_config[idx].gpio_num); unsigned int shift = adapter_gpio_config[idx].gpio_num; initial_gpio_state[idx].output_level = (GPIO_LEV >> shift) & 1; LOG_DEBUG("saved GPIO mode for %s (GPIO %d %d): %d", adapter_gpio_get_name(idx), adapter_gpio_config[idx].chip_num, adapter_gpio_config[idx].gpio_num, initial_gpio_state[idx].mode); if (adapter_gpio_config[idx].pull != ADAPTER_GPIO_PULL_NONE) { LOG_WARNING("BCM2835 GPIO does not support pull-up or pull-down settings (signal %s)", adapter_gpio_get_name(idx)); } switch (adapter_gpio_config[idx].init_state) { case ADAPTER_GPIO_INIT_STATE_INACTIVE: set_gpio_value(&adapter_gpio_config[idx], 0); break; case ADAPTER_GPIO_INIT_STATE_ACTIVE: set_gpio_value(&adapter_gpio_config[idx], 1); break; case ADAPTER_GPIO_INIT_STATE_INPUT: INP_GPIO(adapter_gpio_config[idx].gpio_num); break; } /* Direction for non push-pull is already set by set_gpio_value() */ if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL) OUT_GPIO(adapter_gpio_config[idx].gpio_num); bcm2835_gpio_synchronize(); } static bb_value_t bcm2835gpio_read(void) { unsigned int shift = adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].gpio_num; uint32_t value = (GPIO_LEV >> shift) & 1; return value ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].active_low ? BB_HIGH : BB_LOW); } static int bcm2835gpio_write(int tck, int tms, int tdi) { uint32_t set = tck << adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num | tms << adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num | tdi << adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num; uint32_t clear = !tck << adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num | !tms << adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num | !tdi << adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num; GPIO_SET = set; GPIO_CLR = clear; bcm2835_gpio_synchronize(); bcm2835_delay(); return ERROR_OK; } /* Requires push-pull drive mode for swclk and swdio */ static int bcm2835gpio_swd_write_fast(int swclk, int swdio) { swclk = swclk ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].active_low ? 1 : 0); swdio = swdio ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0); uint32_t set = swclk << adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num | swdio << adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num; uint32_t clear = !swclk << adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num | !swdio << adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num; GPIO_SET = set; GPIO_CLR = clear; bcm2835_gpio_synchronize(); bcm2835_delay(); return ERROR_OK; } /* Generic mode that works for open-drain/open-source drive modes, but slower */ static int bcm2835gpio_swd_write_generic(int swclk, int swdio) { set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO], swdio); set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK], swclk); /* Write clock last */ bcm2835_delay(); return ERROR_OK; } /* (1) assert or (0) deassert reset lines */ static int bcm2835gpio_reset(int trst, int srst) { /* As the "adapter reset_config" command keeps the srst and trst gpio drive * mode settings in sync we can use our standard set_gpio_value() function * that honours drive mode and active low. */ if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SRST)) set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SRST], srst); if (is_gpio_config_valid(ADAPTER_GPIO_IDX_TRST)) set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TRST], trst); LOG_DEBUG("BCM2835 GPIO: bcm2835gpio_reset(%d, %d), trst_gpio: %d %d, srst_gpio: %d %d", trst, srst, adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].chip_num, adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].gpio_num, adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].chip_num, adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].gpio_num); return ERROR_OK; } static void bcm2835_swdio_drive(bool is_output) { if (is_output) { if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR)) set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 1); OUT_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num); } else { INP_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num); if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR)) set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 0); } bcm2835_gpio_synchronize(); } static int bcm2835_swdio_read(void) { unsigned int shift = adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num; uint32_t value = (GPIO_LEV >> shift) & 1; return value ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0); } static int bcm2835gpio_khz(int khz, int *jtag_speed) { if (!khz) { LOG_DEBUG("BCM2835 GPIO: RCLK not supported"); return ERROR_FAIL; } *jtag_speed = DIV_ROUND_UP(speed_coeff, khz) - speed_offset; LOG_DEBUG("jtag_delay %d", *jtag_speed); if (*jtag_speed < 0) *jtag_speed = 0; return ERROR_OK; } static int bcm2835gpio_speed_div(int speed, int *khz) { int divisor = speed + speed_offset; /* divide with roundig to the closest */ *khz = (speed_coeff + divisor / 2) / divisor; return ERROR_OK; } static int bcm2835gpio_speed(int speed) { jtag_delay = speed; return ERROR_OK; } COMMAND_HANDLER(bcm2835gpio_handle_speed_coeffs) { if (CMD_ARGC == 2) { COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff); COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset); } command_print(CMD, "BCM2835 GPIO: speed_coeffs = %d, speed_offset = %d", speed_coeff, speed_offset); return ERROR_OK; } COMMAND_HANDLER(bcm2835gpio_handle_peripheral_mem_dev) { if (CMD_ARGC == 1) { free(bcm2835_peri_mem_dev); bcm2835_peri_mem_dev = strdup(CMD_ARGV[0]); } command_print(CMD, "BCM2835 GPIO: peripheral_mem_dev = %s", bcm2835_get_mem_dev()); return ERROR_OK; } COMMAND_HANDLER(bcm2835gpio_handle_peripheral_base) { uint64_t tmp_base; if (CMD_ARGC == 1) { COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], tmp_base); bcm2835_peri_base = (off_t)tmp_base; } tmp_base = bcm2835_peri_base; command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08" PRIu64, tmp_base); return ERROR_OK; } static const struct command_registration bcm2835gpio_subcommand_handlers[] = { { .name = "speed_coeffs", .handler = &bcm2835gpio_handle_speed_coeffs, .mode = COMMAND_CONFIG, .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.", .usage = "[SPEED_COEFF SPEED_OFFSET]", }, { .name = "peripheral_mem_dev", .handler = &bcm2835gpio_handle_peripheral_mem_dev, .mode = COMMAND_CONFIG, .help = "device to map memory mapped GPIOs from.", .usage = "[device]", }, { .name = "peripheral_base", .handler = &bcm2835gpio_handle_peripheral_base, .mode = COMMAND_CONFIG, .help = "peripheral base to access GPIOs, not needed with /dev/gpiomem.", .usage = "[base]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration bcm2835gpio_command_handlers[] = { { .name = "bcm2835gpio", .mode = COMMAND_ANY, .help = "perform bcm2835gpio management", .chain = bcm2835gpio_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static bool bcm2835gpio_jtag_mode_possible(void) { if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TCK)) return false; if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TMS)) return false; if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TDI)) return false; if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TDO)) return false; return true; } static bool bcm2835gpio_swd_mode_possible(void) { if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_SWCLK)) return false; if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO)) return false; return true; } static void bcm2835gpio_munmap(void) { if (pio_base != MAP_FAILED) { munmap((void *)pio_base, sysconf(_SC_PAGE_SIZE)); pio_base = MAP_FAILED; } if (pads_base != MAP_FAILED) { munmap((void *)pads_base, sysconf(_SC_PAGE_SIZE)); pads_base = MAP_FAILED; } } static int bcm2835gpio_blink(int on) { if (is_gpio_config_valid(ADAPTER_GPIO_IDX_LED)) set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_LED], on); return ERROR_OK; } static struct bitbang_interface bcm2835gpio_bitbang = { .read = bcm2835gpio_read, .write = bcm2835gpio_write, .swdio_read = bcm2835_swdio_read, .swdio_drive = bcm2835_swdio_drive, .swd_write = bcm2835gpio_swd_write_generic, .blink = bcm2835gpio_blink, }; static int bcm2835gpio_init(void) { LOG_INFO("BCM2835 GPIO JTAG/SWD bitbang driver"); bitbang_interface = &bcm2835gpio_bitbang; adapter_gpio_config = adapter_gpio_get_config(); if (transport_is_jtag() && !bcm2835gpio_jtag_mode_possible()) { LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode"); return ERROR_JTAG_INIT_FAILED; } if (transport_is_swd() && !bcm2835gpio_swd_mode_possible()) { LOG_ERROR("Require swclk and swdio gpio for SWD mode"); return ERROR_JTAG_INIT_FAILED; } bool is_gpiomem = strcmp(bcm2835_get_mem_dev(), "/dev/gpiomem") == 0; bool pad_mapping_possible = !is_gpiomem; dev_mem_fd = open(bcm2835_get_mem_dev(), O_RDWR | O_SYNC); if (dev_mem_fd < 0) { LOG_ERROR("open %s: %s", bcm2835_get_mem_dev(), strerror(errno)); /* TODO: add /dev/mem specific doc and refer to it * if (!is_gpiomem && (errno == EACCES || errno == EPERM)) * LOG_INFO("Consult the user's guide chapter 4.? how to set permissions and capabilities"); */ return ERROR_JTAG_INIT_FAILED; } pio_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, BCM2835_GPIO_BASE); if (pio_base == MAP_FAILED) { LOG_ERROR("mmap: %s", strerror(errno)); close(dev_mem_fd); return ERROR_JTAG_INIT_FAILED; } /* TODO: move pads config to a separate utility */ if (pad_mapping_possible) { pads_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, BCM2835_PADS_GPIO_0_27); if (pads_base == MAP_FAILED) { LOG_ERROR("mmap pads: %s", strerror(errno)); LOG_WARNING("Continuing with unchanged GPIO pad settings (drive strength and slew rate)"); } } else { pads_base = MAP_FAILED; } close(dev_mem_fd); if (pads_base != MAP_FAILED) { /* set 4mA drive strength, slew rate limited, hysteresis on */ initial_drive_strength_etc = pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] & 0x1f; LOG_INFO("initial pads conf %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]); pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1; LOG_INFO("pads conf set to %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]); } /* Configure JTAG/SWD signals. Default directions and initial states are handled * by adapter.c and "adapter gpio" command. */ if (transport_is_jtag()) { initialize_gpio(ADAPTER_GPIO_IDX_TDO); initialize_gpio(ADAPTER_GPIO_IDX_TDI); initialize_gpio(ADAPTER_GPIO_IDX_TMS); initialize_gpio(ADAPTER_GPIO_IDX_TCK); initialize_gpio(ADAPTER_GPIO_IDX_TRST); } if (transport_is_swd()) { /* swdio and its buffer should be initialized in the order that prevents * two outputs from being connected together. This will occur if the * swdio GPIO of the AM335x is configured as an output while its * external buffer is configured to send the swdio signal from the * target to the AM335x. */ if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].init_state == ADAPTER_GPIO_INIT_STATE_INPUT) { initialize_gpio(ADAPTER_GPIO_IDX_SWDIO); initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR); } else { initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR); initialize_gpio(ADAPTER_GPIO_IDX_SWDIO); } initialize_gpio(ADAPTER_GPIO_IDX_SWCLK); if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL && adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL) { LOG_DEBUG("BCM2835 GPIO using fast mode for SWD write"); bcm2835gpio_bitbang.swd_write = bcm2835gpio_swd_write_fast; } else { LOG_DEBUG("BCM2835 GPIO using generic mode for SWD write"); bcm2835gpio_bitbang.swd_write = bcm2835gpio_swd_write_generic; } } initialize_gpio(ADAPTER_GPIO_IDX_SRST); initialize_gpio(ADAPTER_GPIO_IDX_LED); return ERROR_OK; } static int bcm2835gpio_quit(void) { if (transport_is_jtag()) { restore_gpio(ADAPTER_GPIO_IDX_TDO); restore_gpio(ADAPTER_GPIO_IDX_TDI); restore_gpio(ADAPTER_GPIO_IDX_TCK); restore_gpio(ADAPTER_GPIO_IDX_TMS); restore_gpio(ADAPTER_GPIO_IDX_TRST); } if (transport_is_swd()) { /* Restore swdio/swdio_dir to their initial modes, even if that means * connecting two outputs. Begin by making swdio an input so that the * current and final states of swdio and swdio_dir do not have to be * considered to calculate the safe restoration order. */ INP_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num); restore_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR); restore_gpio(ADAPTER_GPIO_IDX_SWDIO); restore_gpio(ADAPTER_GPIO_IDX_SWCLK); } restore_gpio(ADAPTER_GPIO_IDX_SRST); restore_gpio(ADAPTER_GPIO_IDX_LED); if (pads_base != MAP_FAILED) { /* Restore drive strength. MSB is password ("5A") */ pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5A000000 | initial_drive_strength_etc; } bcm2835gpio_munmap(); free(bcm2835_peri_mem_dev); return ERROR_OK; } static const char * const bcm2835_transports[] = { "jtag", "swd", NULL }; static struct jtag_interface bcm2835gpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, }; struct adapter_driver bcm2835gpio_adapter_driver = { .name = "bcm2835gpio", .transports = bcm2835_transports, .commands = bcm2835gpio_command_handlers, .init = bcm2835gpio_init, .quit = bcm2835gpio_quit, .reset = bcm2835gpio_reset, .speed = bcm2835gpio_speed, .khz = bcm2835gpio_khz, .speed_div = bcm2835gpio_speed_div, .jtag_ops = &bcm2835gpio_interface, .swd_ops = &bitbang_swd, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/bitbang.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ /* 2014-12: Addition of the SWD protocol support is based on the initial work * by Paul Fertser and modifications by Jean-Christian de Rivaz. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "bitbang.h" #include <jtag/interface.h> #include <jtag/commands.h> /** * Function bitbang_stableclocks * issues a number of clock cycles while staying in a stable state. * Because the TMS value required to stay in the RESET state is a 1, whereas * the TMS value required to stay in any of the other stable states is a 0, * this function checks the current stable state to decide on the value of TMS * to use. */ static int bitbang_stableclocks(int num_cycles); static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk); struct bitbang_interface *bitbang_interface; /* DANGER!!!! clock absolutely *MUST* be 0 in idle or reset won't work! * * Set this to 1 and str912 reset halt will fail. * * If someone can submit a patch with an explanation it will be greatly * appreciated, but as far as I can tell (ØH) DCLK is generated upon * clk = 0 in TAP_IDLE. Good luck deducing that from the ARM documentation! * The ARM documentation uses the term "DCLK is asserted while in the TAP_IDLE * state". With hardware there is no such thing as *while* in a state. There * are only edges. So clk => 0 is in fact a very subtle state transition that * happens *while* in the TAP_IDLE state. "#&¤"#¤&"#&"#& * * For "reset halt" the last thing that happens before srst is asserted * is that the breakpoint is set up. If DCLK is not wiggled one last * time before the reset, then the breakpoint is not set up and * "reset halt" will fail to halt. * */ #define CLOCK_IDLE() 0 /* The bitbang driver leaves the TCK 0 when in idle */ static void bitbang_end_state(tap_state_t state) { assert(tap_is_state_stable(state)); tap_set_end_state(state); } static int bitbang_state_move(int skip) { int i = 0, tms = 0; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); for (i = skip; i < tms_count; i++) { tms = (tms_scan >> i) & 1; if (bitbang_interface->write(0, tms, 0) != ERROR_OK) return ERROR_FAIL; if (bitbang_interface->write(1, tms, 0) != ERROR_OK) return ERROR_FAIL; } if (bitbang_interface->write(CLOCK_IDLE(), tms, 0) != ERROR_OK) return ERROR_FAIL; tap_set_state(tap_get_end_state()); return ERROR_OK; } /** * Clock a bunch of TMS (or SWDIO) transitions, to change the JTAG * (or SWD) state machine. */ static int bitbang_execute_tms(struct jtag_command *cmd) { unsigned num_bits = cmd->cmd.tms->num_bits; const uint8_t *bits = cmd->cmd.tms->bits; LOG_DEBUG_IO("TMS: %d bits", num_bits); int tms = 0; for (unsigned i = 0; i < num_bits; i++) { tms = ((bits[i/8] >> (i % 8)) & 1); if (bitbang_interface->write(0, tms, 0) != ERROR_OK) return ERROR_FAIL; if (bitbang_interface->write(1, tms, 0) != ERROR_OK) return ERROR_FAIL; } if (bitbang_interface->write(CLOCK_IDLE(), tms, 0) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int bitbang_path_move(struct pathmove_command *cmd) { int num_states = cmd->num_states; int state_count; int tms = 0; state_count = 0; while (num_states) { if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) tms = 0; else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count]) tms = 1; else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(cmd->path[state_count])); exit(-1); } if (bitbang_interface->write(0, tms, 0) != ERROR_OK) return ERROR_FAIL; if (bitbang_interface->write(1, tms, 0) != ERROR_OK) return ERROR_FAIL; tap_set_state(cmd->path[state_count]); state_count++; num_states--; } if (bitbang_interface->write(CLOCK_IDLE(), tms, 0) != ERROR_OK) return ERROR_FAIL; tap_set_end_state(tap_get_state()); return ERROR_OK; } static int bitbang_runtest(int num_cycles) { int i; tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { bitbang_end_state(TAP_IDLE); if (bitbang_state_move(0) != ERROR_OK) return ERROR_FAIL; } /* execute num_cycles */ for (i = 0; i < num_cycles; i++) { if (bitbang_interface->write(0, 0, 0) != ERROR_OK) return ERROR_FAIL; if (bitbang_interface->write(1, 0, 0) != ERROR_OK) return ERROR_FAIL; } if (bitbang_interface->write(CLOCK_IDLE(), 0, 0) != ERROR_OK) return ERROR_FAIL; /* finish in end_state */ bitbang_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) if (bitbang_state_move(0) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int bitbang_stableclocks(int num_cycles) { int tms = (tap_get_state() == TAP_RESET ? 1 : 0); int i; /* send num_cycles clocks onto the cable */ for (i = 0; i < num_cycles; i++) { if (bitbang_interface->write(1, tms, 0) != ERROR_OK) return ERROR_FAIL; if (bitbang_interface->write(0, tms, 0) != ERROR_OK) return ERROR_FAIL; } return ERROR_OK; } static int bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, unsigned scan_size) { tap_state_t saved_end_state = tap_get_end_state(); unsigned bit_cnt; if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) || (ir_scan && (tap_get_state() == TAP_IRSHIFT)))) { if (ir_scan) bitbang_end_state(TAP_IRSHIFT); else bitbang_end_state(TAP_DRSHIFT); if (bitbang_state_move(0) != ERROR_OK) return ERROR_FAIL; bitbang_end_state(saved_end_state); } size_t buffered = 0; for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) { int tms = (bit_cnt == scan_size-1) ? 1 : 0; int tdi; int bytec = bit_cnt/8; int bcval = 1 << (bit_cnt % 8); /* if we're just reading the scan, but don't care about the output * default to outputting 'low', this also makes valgrind traces more readable, * as it removes the dependency on an uninitialised value */ tdi = 0; if ((type != SCAN_IN) && (buffer[bytec] & bcval)) tdi = 1; if (bitbang_interface->write(0, tms, tdi) != ERROR_OK) return ERROR_FAIL; if (type != SCAN_OUT) { if (bitbang_interface->buf_size) { if (bitbang_interface->sample() != ERROR_OK) return ERROR_FAIL; buffered++; } else { switch (bitbang_interface->read()) { case BB_LOW: buffer[bytec] &= ~bcval; break; case BB_HIGH: buffer[bytec] |= bcval; break; default: return ERROR_FAIL; } } } if (bitbang_interface->write(1, tms, tdi) != ERROR_OK) return ERROR_FAIL; if (type != SCAN_OUT && bitbang_interface->buf_size && (buffered == bitbang_interface->buf_size || bit_cnt == scan_size - 1)) { for (unsigned i = bit_cnt + 1 - buffered; i <= bit_cnt; i++) { switch (bitbang_interface->read_sample()) { case BB_LOW: buffer[i/8] &= ~(1 << (i % 8)); break; case BB_HIGH: buffer[i/8] |= 1 << (i % 8); break; default: return ERROR_FAIL; } } buffered = 0; } } if (tap_get_state() != tap_get_end_state()) { /* we *KNOW* the above loop transitioned out of * the shift state, so we skip the first state * and move directly to the end state. */ if (bitbang_state_move(1) != ERROR_OK) return ERROR_FAIL; } return ERROR_OK; } int bitbang_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; int retval; if (!bitbang_interface) { LOG_ERROR("BUG: Bitbang interface called, but not yet initialized"); exit(-1); } /* return ERROR_OK, unless a jtag_read_buffer returns a failed check * that wasn't handled by a caller-provided error handler */ retval = ERROR_OK; if (bitbang_interface->blink) { if (bitbang_interface->blink(1) != ERROR_OK) return ERROR_FAIL; } while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); bitbang_end_state(cmd->cmd.runtest->end_state); if (bitbang_runtest(cmd->cmd.runtest->num_cycles) != ERROR_OK) return ERROR_FAIL; break; case JTAG_STABLECLOCKS: /* this is only allowed while in a stable state. A check for a stable * state was done in jtag_add_clocks() */ if (bitbang_stableclocks(cmd->cmd.stableclocks->num_cycles) != ERROR_OK) return ERROR_FAIL; break; case JTAG_TLR_RESET: LOG_DEBUG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); bitbang_end_state(cmd->cmd.statemove->end_state); if (bitbang_state_move(0) != ERROR_OK) return ERROR_FAIL; break; case JTAG_PATHMOVE: LOG_DEBUG_IO("pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states, tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); if (bitbang_path_move(cmd->cmd.pathmove) != ERROR_OK) return ERROR_FAIL; break; case JTAG_SCAN: bitbang_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); LOG_DEBUG_IO("%s scan %d bits; end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, tap_state_name(cmd->cmd.scan->end_state)); type = jtag_scan_type(cmd->cmd.scan); if (bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size) != ERROR_OK) return ERROR_FAIL; if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; free(buffer); break; case JTAG_SLEEP: LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); jtag_sleep(cmd->cmd.sleep->us); break; case JTAG_TMS: retval = bitbang_execute_tms(cmd); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } if (bitbang_interface->blink) { if (bitbang_interface->blink(0) != ERROR_OK) return ERROR_FAIL; } return retval; } static int queued_retval; static int bitbang_swd_init(void) { LOG_DEBUG("bitbang_swd_init"); return ERROR_OK; } static void bitbang_swd_exchange(bool rnw, uint8_t buf[], unsigned int offset, unsigned int bit_cnt) { if (bitbang_interface->blink) { /* FIXME: we should manage errors */ bitbang_interface->blink(1); } for (unsigned int i = offset; i < bit_cnt + offset; i++) { int bytec = i/8; int bcval = 1 << (i % 8); int swdio = !rnw && (buf[bytec] & bcval); bitbang_interface->swd_write(0, swdio); if (rnw && buf) { if (bitbang_interface->swdio_read()) buf[bytec] |= bcval; else buf[bytec] &= ~bcval; } bitbang_interface->swd_write(1, swdio); } if (bitbang_interface->blink) { /* FIXME: we should manage errors */ bitbang_interface->blink(0); } } static int bitbang_swd_switch_seq(enum swd_special_seq seq) { switch (seq) { case LINE_RESET: LOG_DEBUG_IO("SWD line reset"); bitbang_swd_exchange(false, (uint8_t *)swd_seq_line_reset, 0, swd_seq_line_reset_len); break; case JTAG_TO_SWD: LOG_DEBUG("JTAG-to-SWD"); bitbang_swd_exchange(false, (uint8_t *)swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len); break; case JTAG_TO_DORMANT: LOG_DEBUG("JTAG-to-DORMANT"); bitbang_swd_exchange(false, (uint8_t *)swd_seq_jtag_to_dormant, 0, swd_seq_jtag_to_dormant_len); break; case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); bitbang_swd_exchange(false, (uint8_t *)swd_seq_swd_to_jtag, 0, swd_seq_swd_to_jtag_len); break; case SWD_TO_DORMANT: LOG_DEBUG("SWD-to-DORMANT"); bitbang_swd_exchange(false, (uint8_t *)swd_seq_swd_to_dormant, 0, swd_seq_swd_to_dormant_len); break; case DORMANT_TO_SWD: LOG_DEBUG("DORMANT-to-SWD"); bitbang_swd_exchange(false, (uint8_t *)swd_seq_dormant_to_swd, 0, swd_seq_dormant_to_swd_len); break; case DORMANT_TO_JTAG: LOG_DEBUG("DORMANT-to-JTAG"); bitbang_swd_exchange(false, (uint8_t *)swd_seq_dormant_to_jtag, 0, swd_seq_dormant_to_jtag_len); break; default: LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; } return ERROR_OK; } static void swd_clear_sticky_errors(void) { bitbang_swd_write_reg(swd_cmd(false, false, DP_ABORT), STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); } static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { assert(cmd & SWD_CMD_RNW); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skip bitbang_swd_read_reg because queued_retval=%d", queued_retval); return; } for (;;) { uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)]; cmd |= SWD_CMD_START | SWD_CMD_PARK; bitbang_swd_exchange(false, &cmd, 0, 8); bitbang_interface->swdio_drive(false); bitbang_swd_exchange(true, trn_ack_data_parity_trn, 0, 1 + 3 + 32 + 1 + 1); bitbang_interface->swdio_drive(true); int ack = buf_get_u32(trn_ack_data_parity_trn, 1, 3); uint32_t data = buf_get_u32(trn_ack_data_parity_trn, 1 + 3, 32); int parity = buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 32, 1); LOG_DEBUG_IO("%s %s read reg %X = %08" PRIx32, ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", cmd & SWD_CMD_APNDP ? "AP" : "DP", (cmd & SWD_CMD_A32) >> 1, data); if (ack == SWD_ACK_WAIT) { swd_clear_sticky_errors(); continue; } else if (ack != SWD_ACK_OK) { queued_retval = swd_ack_to_error_code(ack); return; } if (parity != parity_u32(data)) { LOG_ERROR("Wrong parity detected"); queued_retval = ERROR_FAIL; return; } if (value) *value = data; if (cmd & SWD_CMD_APNDP) bitbang_swd_exchange(true, NULL, 0, ap_delay_clk); return; } } static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { assert(!(cmd & SWD_CMD_RNW)); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skip bitbang_swd_write_reg because queued_retval=%d", queued_retval); return; } /* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */ bool check_ack = swd_cmd_returns_ack(cmd); /* init the array to silence scan-build */ uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)] = {0}; for (;;) { buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32, value); buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1 + 32, 1, parity_u32(value)); cmd |= SWD_CMD_START | SWD_CMD_PARK; bitbang_swd_exchange(false, &cmd, 0, 8); bitbang_interface->swdio_drive(false); bitbang_swd_exchange(true, trn_ack_data_parity_trn, 0, 1 + 3); /* Avoid a glitch on SWDIO when changing the direction to output. * To keep performance penalty minimal, pre-write the first data * bit to SWDIO GPIO output buffer while clocking the turnaround bit. * Following swdio_drive(true) outputs the pre-written value * and the same value is rewritten by the next swd_write() * instead of glitching SWDIO * HiZ/pull-up --------------> 0 -------------> 1 * swdio_drive(true) swd_write(0,1) * in case of data bit 0 = 1 */ bitbang_swd_exchange(false, trn_ack_data_parity_trn, 1 + 3 + 1, 1); bitbang_interface->swdio_drive(true); bitbang_swd_exchange(false, trn_ack_data_parity_trn, 1 + 3 + 1, 32 + 1); int ack = buf_get_u32(trn_ack_data_parity_trn, 1, 3); LOG_DEBUG_IO("%s%s %s write reg %X = %08" PRIx32, check_ack ? "" : "ack ignored ", ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", cmd & SWD_CMD_APNDP ? "AP" : "DP", (cmd & SWD_CMD_A32) >> 1, buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32)); if (check_ack) { if (ack == SWD_ACK_WAIT) { swd_clear_sticky_errors(); continue; } else if (ack != SWD_ACK_OK) { queued_retval = swd_ack_to_error_code(ack); return; } } if (cmd & SWD_CMD_APNDP) bitbang_swd_exchange(true, NULL, 0, ap_delay_clk); return; } } static int bitbang_swd_run_queue(void) { /* A transaction must be followed by another transaction or at least 8 idle cycles to * ensure that data is clocked through the AP. */ bitbang_swd_exchange(true, NULL, 0, 8); int retval = queued_retval; queued_retval = ERROR_OK; LOG_DEBUG_IO("SWD queue return value: %02x", retval); return retval; } const struct swd_driver bitbang_swd = { .init = bitbang_swd_init, .switch_seq = bitbang_swd_switch_seq, .read_reg = bitbang_swd_read_reg, .write_reg = bitbang_swd_write_reg, .run = bitbang_swd_run_queue, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/bitbang.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_BITBANG_H #define OPENOCD_JTAG_DRIVERS_BITBANG_H #include <jtag/swd.h> typedef enum { BB_LOW, BB_HIGH, BB_ERROR } bb_value_t; /** Low level callbacks (for bitbang). * * Either read(), or sample() and read_sample() must be implemented. * * The sample functions allow an interface to batch a number of writes and * sample requests together. Not waiting for a value to come back can greatly * increase throughput. */ struct bitbang_interface { /** Sample TDO and return the value. */ bb_value_t (*read)(void); /** The number of TDO samples that can be buffered up before the caller has * to call read_sample. */ size_t buf_size; /** Sample TDO and put the result in a buffer. */ int (*sample)(void); /** Return the next unread value from the buffer. */ bb_value_t (*read_sample)(void); /** Set TCK, TMS, and TDI to the given values. */ int (*write)(int tck, int tms, int tdi); /** Blink led (optional). */ int (*blink)(int on); /** Sample SWDIO and return the value. */ int (*swdio_read)(void); /** Set direction of SWDIO. */ void (*swdio_drive)(bool on); /** Set SWCLK and SWDIO to the given value. */ int (*swd_write)(int swclk, int swdio); }; extern const struct swd_driver bitbang_swd; int bitbang_execute_queue(void); extern struct bitbang_interface *bitbang_interface; #endif /* OPENOCD_JTAG_DRIVERS_BITBANG_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/bitq.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/jtag.h> #include "bitq.h" #include <jtag/interface.h> struct bitq_interface *bitq_interface; /* low level bit queue interface */ /* state of input queue */ struct bitq_state { struct jtag_command *cmd; /* command currently processed */ int field_idx; /* index of field currently being processed */ int bit_pos; /* position of bit currently being processed */ int status; /* processing status */ }; static struct bitq_state bitq_in_state; /* * input queue processing does not use jtag_read_buffer() to avoid unnecessary overhead * no parameters, makes use of stored state information */ static void bitq_in_proc(void) { /* loop through the queue */ while (bitq_in_state.cmd) { /* only JTAG_SCAN command may return data */ if (bitq_in_state.cmd->type == JTAG_SCAN) { /* loop through the fields */ while (bitq_in_state.field_idx < bitq_in_state.cmd->cmd.scan->num_fields) { struct scan_field *field; field = &bitq_in_state.cmd->cmd.scan->fields[bitq_in_state.field_idx]; if (field->in_value) { /* field scanning */ while (bitq_in_state.bit_pos < field->num_bits) { /* index of byte being scanned */ int in_idx = bitq_in_state.bit_pos / 8; /* mask of next bit to be scanned */ uint8_t in_mask = 1 << (bitq_in_state.bit_pos % 8); int tdo = bitq_interface->in(); if (tdo < 0) { LOG_DEBUG_IO("bitq in EOF"); return; } if (in_mask == 0x01) field->in_value[in_idx] = 0; if (tdo) field->in_value[in_idx] |= in_mask; bitq_in_state.bit_pos++; } } bitq_in_state.field_idx++; /* advance to next field */ bitq_in_state.bit_pos = 0; /* start next field from the first bit */ } } bitq_in_state.cmd = bitq_in_state.cmd->next; /* advance to next command */ bitq_in_state.field_idx = 0; /* preselect first field */ } } static void bitq_io(int tms, int tdi, int tdo_req) { bitq_interface->out(tms, tdi, tdo_req); /* check and process the input queue */ if (bitq_interface->in_rdy()) bitq_in_proc(); } static void bitq_end_state(tap_state_t state) { if (!tap_is_state_stable(state)) { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } tap_set_end_state(state); } static void bitq_state_move(tap_state_t new_state) { int i = 0; uint8_t tms_scan; if (!tap_is_state_stable(tap_get_state()) || !tap_is_state_stable(new_state)) { LOG_ERROR("TAP move from or to unstable state"); exit(-1); } tms_scan = tap_get_tms_path(tap_get_state(), new_state); int tms_count = tap_get_tms_path_len(tap_get_state(), new_state); for (i = 0; i < tms_count; i++) { bitq_io(tms_scan & 1, 0, 0); tms_scan >>= 1; } tap_set_state(new_state); } static void bitq_path_move(struct pathmove_command *cmd) { int i; for (i = 0; i < cmd->num_states; i++) { if (tap_state_transition(tap_get_state(), false) == cmd->path[i]) bitq_io(0, 0, 0); else if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) bitq_io(1, 0, 0); else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name( tap_get_state()), tap_state_name(cmd->path[i])); exit(-1); } tap_set_state(cmd->path[i]); } tap_set_end_state(tap_get_state()); } static void bitq_runtest(int num_cycles) { int i; /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) bitq_state_move(TAP_IDLE); /* execute num_cycles */ for (i = 0; i < num_cycles; i++) bitq_io(0, 0, 0); /* finish in end_state */ if (tap_get_state() != tap_get_end_state()) bitq_state_move(tap_get_end_state()); } static void bitq_scan_field(struct scan_field *field, int do_pause) { int bit_cnt; int tdo_req; const uint8_t *out_ptr; uint8_t out_mask; if (field->in_value) tdo_req = 1; else tdo_req = 0; if (!field->out_value) { /* just send zeros and request data from TDO */ for (bit_cnt = field->num_bits; bit_cnt > 1; bit_cnt--) bitq_io(0, 0, tdo_req); bitq_io(do_pause, 0, tdo_req); } else { /* send data, and optionally request TDO */ out_mask = 0x01; out_ptr = field->out_value; for (bit_cnt = field->num_bits; bit_cnt > 1; bit_cnt--) { bitq_io(0, ((*out_ptr) & out_mask) != 0, tdo_req); if (out_mask == 0x80) { out_mask = 0x01; out_ptr++; } else out_mask <<= 1; } bitq_io(do_pause, ((*out_ptr) & out_mask) != 0, tdo_req); } if (do_pause) { bitq_io(0, 0, 0); if (tap_get_state() == TAP_IRSHIFT) tap_set_state(TAP_IRPAUSE); else if (tap_get_state() == TAP_DRSHIFT) tap_set_state(TAP_DRPAUSE); } } static void bitq_scan(struct scan_command *cmd) { int i; if (cmd->ir_scan) bitq_state_move(TAP_IRSHIFT); else bitq_state_move(TAP_DRSHIFT); for (i = 0; i < cmd->num_fields - 1; i++) bitq_scan_field(&cmd->fields[i], 0); bitq_scan_field(&cmd->fields[i], 1); } int bitq_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ bitq_in_state.cmd = jtag_command_queue; bitq_in_state.field_idx = 0; bitq_in_state.bit_pos = 0; bitq_in_state.status = ERROR_OK; while (cmd) { switch (cmd->type) { case JTAG_RESET: LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); if ((cmd->cmd.reset->trst == 1) || (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) tap_set_state(TAP_RESET); bitq_interface->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); if (bitq_interface->in_rdy()) bitq_in_proc(); break; case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); bitq_end_state(cmd->cmd.runtest->end_state); bitq_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); bitq_end_state(cmd->cmd.statemove->end_state); bitq_state_move(tap_get_end_state()); /* unconditional TAP move */ break; case JTAG_PATHMOVE: LOG_DEBUG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); bitq_path_move(cmd->cmd.pathmove); break; case JTAG_SCAN: LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); LOG_DEBUG_IO("scan %s", cmd->cmd.scan->ir_scan ? "ir" : "dr"); bitq_end_state(cmd->cmd.scan->end_state); bitq_scan(cmd->cmd.scan); if (tap_get_state() != tap_get_end_state()) bitq_state_move(tap_get_end_state()); break; case JTAG_SLEEP: LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); bitq_interface->sleep(cmd->cmd.sleep->us); if (bitq_interface->in_rdy()) bitq_in_proc(); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } bitq_interface->flush(); bitq_in_proc(); if (bitq_in_state.cmd) { LOG_ERROR("missing data from bitq interface"); return ERROR_JTAG_QUEUE_FAILED; } if (bitq_interface->in() >= 0) { LOG_ERROR("extra data from bitq interface"); return ERROR_JTAG_QUEUE_FAILED; } return bitq_in_state.status; } void bitq_cleanup(void) { } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/bitq.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_BITQ_H #define OPENOCD_JTAG_DRIVERS_BITQ_H #include <jtag/commands.h> struct bitq_interface { /* function to enqueueing low level IO requests */ int (*out)(int tms, int tdi, int tdo_req); int (*flush)(void); int (*sleep)(unsigned long us); int (*reset)(int trst, int srst); /* delayed read of requested TDO data, * the input shall be checked after call to any enqueuing function */ int (*in_rdy)(void); int (*in)(void); }; extern struct bitq_interface *bitq_interface; int bitq_execute_queue(void); void bitq_cleanup(void); #endif /* OPENOCD_JTAG_DRIVERS_BITQ_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/buspirate.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2010 by Michal Demin * * based on usbprog.c and arm-jtag-ew.c * * Several fixes by R. Diez in 2013. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/interface.h> #include <jtag/swd.h> #include <jtag/commands.h> #include <termios.h> #include <fcntl.h> #include <sys/ioctl.h> #undef DEBUG_SERIAL /*#define DEBUG_SERIAL */ static int buspirate_execute_queue(void); static int buspirate_init(void); static int buspirate_quit(void); static int buspirate_reset(int trst, int srst); static void buspirate_end_state(tap_state_t state); static void buspirate_state_move(void); static void buspirate_path_move(int num_states, tap_state_t *path); static void buspirate_runtest(int num_cycles); static void buspirate_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); static void buspirate_stableclocks(int num_cycles); #define CMD_UNKNOWN 0x00 #define CMD_PORT_MODE 0x01 #define CMD_FEATURE 0x02 #define CMD_READ_ADCS 0x03 /*#define CMD_TAP_SHIFT 0x04 // old protocol */ #define CMD_TAP_SHIFT 0x05 #define CMD_ENTER_RWIRE 0x05 #define CMD_ENTER_OOCD 0x06 #define CMD_UART_SPEED 0x07 #define CMD_JTAG_SPEED 0x08 #define CMD_RAW_PERIPH 0x40 #define CMD_RAW_SPEED 0x60 #define CMD_RAW_MODE 0x80 #define CMD_TAP_SHIFT_HEADER_LEN 3 /* raw-wire mode configuration */ #define CMD_RAW_CONFIG_HIZ 0x00 #define CMD_RAW_CONFIG_3V3 0x08 #define CMD_RAW_CONFIG_2W 0x00 #define CMD_RAW_CONFIG_3W 0x04 #define CMD_RAW_CONFIG_MSB 0x00 #define CMD_RAW_CONFIG_LSB 0x02 /* Not all OSes have this speed defined */ #if !defined(B1000000) #define B1000000 0010010 #endif #define SHORT_TIMEOUT 1 /* Must be at least 1. */ #define NORMAL_TIMEOUT 10 enum { MODE_HIZ = 0, MODE_JTAG = 1, /* push-pull outputs */ MODE_JTAG_OD = 2, /* open-drain outputs */ }; enum { FEATURE_LED = 0x01, FEATURE_VREG = 0x02, FEATURE_TRST = 0x04, FEATURE_SRST = 0x08, FEATURE_PULLUP = 0x10 }; enum { ACTION_DISABLE = 0, ACTION_ENABLE = 1 }; enum { SERIAL_NORMAL = 0, SERIAL_FAST = 1 }; enum { SPEED_RAW_5_KHZ = 0x0, SPEED_RAW_50_KHZ = 0x1, SPEED_RAW_100_KHZ = 0x2, SPEED_RAW_400_KHZ = 0x3 }; /* SWD mode specific */ static bool swd_mode; static int queued_retval; static char swd_features; static int buspirate_fd = -1; static int buspirate_pinmode = MODE_JTAG_OD; static int buspirate_baudrate = SERIAL_NORMAL; static int buspirate_vreg; static int buspirate_pullup; static char *buspirate_port; static enum tap_state last_tap_state = TAP_RESET; /* SWD interface */ static int buspirate_swd_init(void); static void buspirate_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk); static void buspirate_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk); static int buspirate_swd_switch_seq(enum swd_special_seq seq); static int buspirate_swd_run_queue(void); /* TAP interface */ static void buspirate_tap_init(void); static int buspirate_tap_execute(void); static void buspirate_tap_append(int tms, int tdi); static void buspirate_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command); static void buspirate_tap_make_space(int scan, int bits); static void buspirate_set_feature(int, char, char); static void buspirate_set_mode(int, char); static void buspirate_set_speed(int, char); /* low level interface */ static void buspirate_bbio_enable(int); static void buspirate_jtag_reset(int); static unsigned char buspirate_jtag_command(int, uint8_t *, int); static void buspirate_jtag_set_speed(int, char); static void buspirate_jtag_set_mode(int, char); static void buspirate_jtag_set_feature(int, char, char); static void buspirate_jtag_get_adcs(int); /* low level two-wire interface */ static void buspirate_swd_set_speed(int, char); static void buspirate_swd_set_feature(int, char, char); static void buspirate_swd_set_mode(int, char); /* low level HW communication interface */ static int buspirate_serial_open(char *port); static int buspirate_serial_setspeed(int fd, char speed, cc_t timeout); static int buspirate_serial_write(int fd, uint8_t *buf, int size); static int buspirate_serial_read(int fd, uint8_t *buf, int size); static void buspirate_serial_close(int fd); static void buspirate_print_buffer(uint8_t *buf, int size); static int buspirate_execute_queue(void) { /* currently processed command */ struct jtag_command *cmd = jtag_command_queue; int scan_size; enum scan_type type; uint8_t *buffer; while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest ->end_state)); buspirate_end_state(cmd->cmd.runtest ->end_state); buspirate_runtest(cmd->cmd.runtest ->num_cycles); break; case JTAG_TLR_RESET: LOG_DEBUG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove ->end_state)); buspirate_end_state(cmd->cmd.statemove ->end_state); buspirate_state_move(); break; case JTAG_PATHMOVE: LOG_DEBUG_IO("pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states, tap_state_name(cmd->cmd.pathmove ->path[cmd->cmd.pathmove ->num_states - 1])); buspirate_path_move(cmd->cmd.pathmove ->num_states, cmd->cmd.pathmove->path); break; case JTAG_SCAN: LOG_DEBUG_IO("scan end in %s", tap_state_name(cmd->cmd.scan ->end_state)); buspirate_end_state(cmd->cmd.scan ->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); buspirate_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); break; case JTAG_SLEEP: LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); buspirate_tap_execute(); jtag_sleep(cmd->cmd.sleep->us); break; case JTAG_STABLECLOCKS: LOG_DEBUG_IO("stable clock %i cycles", cmd->cmd.stableclocks->num_cycles); buspirate_stableclocks(cmd->cmd.stableclocks->num_cycles); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } return buspirate_tap_execute(); } /* Returns true if successful, false if error. */ static bool read_and_discard_all_data(const int fd) { /* LOG_INFO("Discarding any stale data from a previous connection..."); */ bool was_msg_already_printed = false; for ( ; ; ) { uint8_t buffer[1024]; /* Any size will do, it's a trade-off between stack size and performance. */ const ssize_t read_count = read(fd, buffer, sizeof(buffer)); if (read_count == 0) { /* This is the "end of file" or "connection closed at the other end" condition. */ return true; } if (read_count > 0) { if (!was_msg_already_printed) { LOG_INFO("Some stale data from a previous connection was discarded."); was_msg_already_printed = true; } continue; } assert(read_count == -1); /* According to the specification. */ const int errno_code = errno; if (errno_code == EINTR) continue; if (errno_code == EAGAIN || errno_code == EWOULDBLOCK) { /* We know that the file descriptor has been opened with O_NONBLOCK or O_NDELAY, and these codes mean that there is no data to read at present. */ return true; } /* Some other error has occurred. */ return false; } } static int buspirate_init(void) { if (!buspirate_port) { LOG_ERROR("You need to specify the serial port!"); return ERROR_JTAG_INIT_FAILED; } buspirate_fd = buspirate_serial_open(buspirate_port); if (buspirate_fd == -1) { LOG_ERROR("Could not open serial port"); return ERROR_JTAG_INIT_FAILED; } /* The Operating System or the device itself may deliver stale data from the last connection, so discard all available bytes right after the new connection has been established. After all, we are implementing here a master/slave protocol, so the slave should have nothing to say until the master sends the first command. In the past, there was a tcflush() call in buspirate_serial_setspeed(), but that was not enough. I guess you must actively read from the serial port to trigger any data collection from the device and/or lower USB layers. If you disable the serial port read timeout (if you set SHORT_TIMEOUT to 0), then the discarding does not work any more. Note that we are lowering the serial port timeout for this first read operation, otherwise the normal initialisation would be delayed for too long. */ if (-1 == buspirate_serial_setspeed(buspirate_fd, SERIAL_NORMAL, SHORT_TIMEOUT)) { LOG_ERROR("Error configuring the serial port."); return ERROR_JTAG_INIT_FAILED; } if (!read_and_discard_all_data(buspirate_fd)) { LOG_ERROR("Error while attempting to discard any stale data right after establishing the connection."); return ERROR_JTAG_INIT_FAILED; } if (-1 == buspirate_serial_setspeed(buspirate_fd, SERIAL_NORMAL, NORMAL_TIMEOUT)) { LOG_ERROR("Error configuring the serial port."); return ERROR_JTAG_INIT_FAILED; } buspirate_bbio_enable(buspirate_fd); if (swd_mode || buspirate_baudrate != SERIAL_NORMAL) buspirate_set_speed(buspirate_fd, SERIAL_FAST); LOG_INFO("Buspirate %s Interface ready!", swd_mode ? "SWD" : "JTAG"); if (!swd_mode) buspirate_tap_init(); buspirate_set_mode(buspirate_fd, buspirate_pinmode); buspirate_set_feature(buspirate_fd, FEATURE_VREG, (buspirate_vreg == 1) ? ACTION_ENABLE : ACTION_DISABLE); buspirate_set_feature(buspirate_fd, FEATURE_PULLUP, (buspirate_pullup == 1) ? ACTION_ENABLE : ACTION_DISABLE); buspirate_reset(0, 0); return ERROR_OK; } static int buspirate_quit(void) { LOG_INFO("Shutting down buspirate."); buspirate_set_mode(buspirate_fd, MODE_HIZ); buspirate_set_speed(buspirate_fd, SERIAL_NORMAL); buspirate_jtag_reset(buspirate_fd); buspirate_serial_close(buspirate_fd); free(buspirate_port); buspirate_port = NULL; return ERROR_OK; } /* openocd command interface */ COMMAND_HANDLER(buspirate_handle_adc_command) { if (buspirate_fd == -1) return ERROR_OK; /* unavailable in SWD mode */ if (swd_mode) return ERROR_OK; /* send the command */ buspirate_jtag_get_adcs(buspirate_fd); return ERROR_OK; } COMMAND_HANDLER(buspirate_handle_vreg_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (atoi(CMD_ARGV[0]) == 1) buspirate_vreg = 1; else if (atoi(CMD_ARGV[0]) == 0) buspirate_vreg = 0; else LOG_ERROR("usage: buspirate_vreg <1|0>"); return ERROR_OK; } COMMAND_HANDLER(buspirate_handle_pullup_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (atoi(CMD_ARGV[0]) == 1) buspirate_pullup = 1; else if (atoi(CMD_ARGV[0]) == 0) buspirate_pullup = 0; else LOG_ERROR("usage: buspirate_pullup <1|0>"); return ERROR_OK; } COMMAND_HANDLER(buspirate_handle_led_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (atoi(CMD_ARGV[0]) == 1) { /* enable led */ buspirate_set_feature(buspirate_fd, FEATURE_LED, ACTION_ENABLE); } else if (atoi(CMD_ARGV[0]) == 0) { /* disable led */ buspirate_set_feature(buspirate_fd, FEATURE_LED, ACTION_DISABLE); } else { LOG_ERROR("usage: buspirate_led <1|0>"); } return ERROR_OK; } COMMAND_HANDLER(buspirate_handle_mode_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGV[0][0] == 'n') buspirate_pinmode = MODE_JTAG; else if (CMD_ARGV[0][0] == 'o') buspirate_pinmode = MODE_JTAG_OD; else LOG_ERROR("usage: buspirate_mode <normal|open-drain>"); return ERROR_OK; } COMMAND_HANDLER(buspirate_handle_speed_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGV[0][0] == 'n') buspirate_baudrate = SERIAL_NORMAL; else if (CMD_ARGV[0][0] == 'f') buspirate_baudrate = SERIAL_FAST; else LOG_ERROR("usage: buspirate_speed <normal|fast>"); return ERROR_OK; } COMMAND_HANDLER(buspirate_handle_port_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (!buspirate_port) buspirate_port = strdup(CMD_ARGV[0]); return ERROR_OK; } static const struct command_registration buspirate_subcommand_handlers[] = { { .name = "adc", .handler = &buspirate_handle_adc_command, .mode = COMMAND_EXEC, .help = "reads voltages on adc pins", .usage = "", }, { .name = "vreg", .usage = "<1|0>", .handler = &buspirate_handle_vreg_command, .mode = COMMAND_CONFIG, .help = "changes the state of voltage regulators", }, { .name = "pullup", .usage = "<1|0>", .handler = &buspirate_handle_pullup_command, .mode = COMMAND_CONFIG, .help = "changes the state of pullup", }, { .name = "led", .usage = "<1|0>", .handler = &buspirate_handle_led_command, .mode = COMMAND_EXEC, .help = "changes the state of led", }, { .name = "speed", .usage = "<normal|fast>", .handler = &buspirate_handle_speed_command, .mode = COMMAND_CONFIG, .help = "speed of the interface", }, { .name = "mode", .usage = "<normal|open-drain>", .handler = &buspirate_handle_mode_command, .mode = COMMAND_CONFIG, .help = "pin mode of the interface", }, { .name = "port", .usage = "/dev/ttyUSB0", .handler = &buspirate_handle_port_command, .mode = COMMAND_CONFIG, .help = "name of the serial port to open", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration buspirate_command_handlers[] = { { .name = "buspirate", .mode = COMMAND_ANY, .help = "perform buspirate management", .chain = buspirate_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct swd_driver buspirate_swd = { .init = buspirate_swd_init, .switch_seq = buspirate_swd_switch_seq, .read_reg = buspirate_swd_read_reg, .write_reg = buspirate_swd_write_reg, .run = buspirate_swd_run_queue, }; static const char * const buspirate_transports[] = { "jtag", "swd", NULL }; static struct jtag_interface buspirate_interface = { .execute_queue = buspirate_execute_queue, }; struct adapter_driver buspirate_adapter_driver = { .name = "buspirate", .transports = buspirate_transports, .commands = buspirate_command_handlers, .init = buspirate_init, .quit = buspirate_quit, .reset = buspirate_reset, .jtag_ops = &buspirate_interface, .swd_ops = &buspirate_swd, }; /*************** jtag execute commands **********************/ static void buspirate_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } static void buspirate_state_move(void) { int i = 0, tms = 0; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); for (i = 0; i < tms_count; i++) { tms = (tms_scan >> i) & 1; buspirate_tap_append(tms, 0); } tap_set_state(tap_get_end_state()); } static void buspirate_path_move(int num_states, tap_state_t *path) { int i; for (i = 0; i < num_states; i++) { if (tap_state_transition(tap_get_state(), false) == path[i]) { buspirate_tap_append(0, 0); } else if (tap_state_transition(tap_get_state(), true) == path[i]) { buspirate_tap_append(1, 0); } else { LOG_ERROR("BUG: %s -> %s isn't a valid " "TAP transition", tap_state_name(tap_get_state()), tap_state_name(path[i])); exit(-1); } tap_set_state(path[i]); } tap_set_end_state(tap_get_state()); } static void buspirate_runtest(int num_cycles) { int i; tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { buspirate_end_state(TAP_IDLE); buspirate_state_move(); } for (i = 0; i < num_cycles; i++) buspirate_tap_append(0, 0); LOG_DEBUG_IO("runtest: cur_state %s end_state %s", tap_state_name(tap_get_state()), tap_state_name(tap_get_end_state())); /* finish in end_state */ buspirate_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) buspirate_state_move(); } static void buspirate_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) { tap_state_t saved_end_state; buspirate_tap_make_space(1, scan_size+8); /* is 8 correct ? (2 moves = 16) */ saved_end_state = tap_get_end_state(); buspirate_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); /* Only move if we're not already there */ if (tap_get_state() != tap_get_end_state()) buspirate_state_move(); buspirate_tap_append_scan(scan_size, buffer, command); /* move to PAUSE */ buspirate_tap_append(0, 0); /* restore the saved state */ buspirate_end_state(saved_end_state); tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) buspirate_state_move(); } static void buspirate_stableclocks(int num_cycles) { int i; int tms = (tap_get_state() == TAP_RESET ? 1 : 0); buspirate_tap_make_space(0, num_cycles); for (i = 0; i < num_cycles; i++) buspirate_tap_append(tms, 0); } /************************* TAP related stuff **********/ /* This buffer size matches the maximum CMD_TAP_SHIFT bit length in the Bus Pirate firmware, look for constant 0x2000 in OpenOCD.c . */ #define BUSPIRATE_BUFFER_SIZE 1024 /* The old value of 32 scans was not enough to achieve near 100% utilisation ratio for the current BUSPIRATE_BUFFER_SIZE value of 1024. With 128 scans I am getting full USB 2.0 high speed packets (512 bytes long) when using the JtagDue firmware on the Arduino Due instead of the Bus Pirate, which amounts approximately to a 10% overall speed gain. Bigger packets should also benefit the Bus Pirate, but the speed difference is much smaller. Unfortunately, each 512-byte packet is followed by a 329-byte one, which is not ideal. However, increasing BUSPIRATE_BUFFER_SIZE for the benefit of the JtagDue would make it incompatible with the Bus Pirate firmware. */ #define BUSPIRATE_MAX_PENDING_SCANS 128 static uint8_t tms_chain[BUSPIRATE_BUFFER_SIZE]; /* send */ static uint8_t tdi_chain[BUSPIRATE_BUFFER_SIZE]; /* send */ static int tap_chain_index; struct pending_scan_result /* this was stolen from arm-jtag-ew */ { int first; /* First bit position in tdo_buffer to read */ int length; /* Number of bits to read */ struct scan_command *command; /* Corresponding scan command */ uint8_t *buffer; }; static struct pending_scan_result tap_pending_scans[BUSPIRATE_MAX_PENDING_SCANS]; static int tap_pending_scans_num; static void buspirate_tap_init(void) { tap_chain_index = 0; tap_pending_scans_num = 0; } static int buspirate_tap_execute(void) { uint8_t tmp[4096]; uint8_t *in_buf; int i; int fill_index = 0; int ret; int bytes_to_send; if (tap_chain_index <= 0) return ERROR_OK; LOG_DEBUG("executing tap num bits = %i scans = %i", tap_chain_index, tap_pending_scans_num); bytes_to_send = DIV_ROUND_UP(tap_chain_index, 8); tmp[0] = CMD_TAP_SHIFT; /* this command expects number of bits */ tmp[1] = tap_chain_index >> 8; /* high */ tmp[2] = tap_chain_index; /* low */ fill_index = CMD_TAP_SHIFT_HEADER_LEN; for (i = 0; i < bytes_to_send; i++) { tmp[fill_index] = tdi_chain[i]; fill_index++; tmp[fill_index] = tms_chain[i]; fill_index++; } /* jlink.c calls the routine below, which may be useful for debugging purposes. For example, enabling this allows you to compare the log outputs from jlink.c and from this module for JTAG development or troubleshooting purposes. */ if (false) { last_tap_state = jtag_debug_state_machine(tms_chain, tdi_chain, tap_chain_index, last_tap_state); } ret = buspirate_serial_write(buspirate_fd, tmp, CMD_TAP_SHIFT_HEADER_LEN + bytes_to_send*2); if (ret != bytes_to_send*2+CMD_TAP_SHIFT_HEADER_LEN) { LOG_ERROR("error writing :("); return ERROR_JTAG_DEVICE_ERROR; } ret = buspirate_serial_read(buspirate_fd, tmp, bytes_to_send + CMD_TAP_SHIFT_HEADER_LEN); if (ret != bytes_to_send + CMD_TAP_SHIFT_HEADER_LEN) { LOG_ERROR("error reading"); return ERROR_FAIL; } in_buf = (uint8_t *)(&tmp[CMD_TAP_SHIFT_HEADER_LEN]); /* parse the scans */ for (i = 0; i < tap_pending_scans_num; i++) { uint8_t *buffer = tap_pending_scans[i].buffer; int length = tap_pending_scans[i].length; int first = tap_pending_scans[i].first; struct scan_command *command = tap_pending_scans[i].command; /* copy bits from buffer */ buf_set_buf(in_buf, first, buffer, 0, length); /* return buffer to higher level */ if (jtag_read_buffer(buffer, command) != ERROR_OK) { buspirate_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } free(buffer); } buspirate_tap_init(); return ERROR_OK; } static void buspirate_tap_make_space(int scans, int bits) { int have_scans = BUSPIRATE_MAX_PENDING_SCANS - tap_pending_scans_num; int have_bits = BUSPIRATE_BUFFER_SIZE * 8 - tap_chain_index; if ((have_scans < scans) || (have_bits < bits)) buspirate_tap_execute(); } static void buspirate_tap_append(int tms, int tdi) { int chain_index; buspirate_tap_make_space(0, 1); chain_index = tap_chain_index / 8; if (chain_index < BUSPIRATE_BUFFER_SIZE) { int bit_index = tap_chain_index % 8; uint8_t bit = 1 << bit_index; if (bit_index == 0) { /* Let's say that the TAP shift operation wants to shift 9 bits, so we will be sending to the Bus Pirate a bit count of 9 but still full 16 bits (2 bytes) of shift data. If we don't clear all bits at this point, the last 7 bits will contain random data from the last buffer contents, which is not pleasant to the eye. Besides, the Bus Pirate (or some clone) may want to assert in debug builds that, after consuming all significant data bits, the rest of them are zero. Therefore, for aesthetic and for assert purposes, we clear all bits below. */ tms_chain[chain_index] = 0; tdi_chain[chain_index] = 0; } if (tms) tms_chain[chain_index] |= bit; else tms_chain[chain_index] &= ~bit; if (tdi) tdi_chain[chain_index] |= bit; else tdi_chain[chain_index] &= ~bit; tap_chain_index++; } else { LOG_ERROR("tap_chain overflow, bad things will happen"); /* Exit abruptly, like jlink.c does. After a buffer overflow we don't want to carry on, as data will be corrupt. Another option would be to return some error code at this point. */ exit(-1); } } static void buspirate_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command) { int i; tap_pending_scans[tap_pending_scans_num].length = length; tap_pending_scans[tap_pending_scans_num].buffer = buffer; tap_pending_scans[tap_pending_scans_num].command = command; tap_pending_scans[tap_pending_scans_num].first = tap_chain_index; for (i = 0; i < length; i++) { int tms = (i < length-1 ? 0 : 1); int tdi = (buffer[i/8] >> (i%8)) & 1; buspirate_tap_append(tms, tdi); } tap_pending_scans_num++; } /*************** wrapper functions *********************/ /* (1) assert or (0) deassert reset lines */ static int buspirate_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); if (trst) buspirate_set_feature(buspirate_fd, FEATURE_TRST, ACTION_DISABLE); else buspirate_set_feature(buspirate_fd, FEATURE_TRST, ACTION_ENABLE); if (srst) buspirate_set_feature(buspirate_fd, FEATURE_SRST, ACTION_DISABLE); else buspirate_set_feature(buspirate_fd, FEATURE_SRST, ACTION_ENABLE); return ERROR_OK; } static void buspirate_set_feature(int fd, char feat, char action) { if (swd_mode) buspirate_swd_set_feature(fd, feat, action); else buspirate_jtag_set_feature(fd, feat, action); } static void buspirate_set_mode(int fd, char mode) { if (swd_mode) buspirate_swd_set_mode(fd, mode); else buspirate_jtag_set_mode(fd, mode); } static void buspirate_set_speed(int fd, char speed) { if (swd_mode) buspirate_swd_set_speed(fd, speed); else buspirate_jtag_set_speed(fd, speed); } /*************** swd lowlevel functions ********************/ static void buspirate_swd_set_speed(int fd, char speed) { int ret; uint8_t tmp[1]; LOG_DEBUG("Buspirate speed setting in SWD mode defaults to 400 kHz"); /* speed settings */ tmp[0] = CMD_RAW_SPEED | SPEED_RAW_400_KHZ; buspirate_serial_write(fd, tmp, 1); ret = buspirate_serial_read(fd, tmp, 1); if (ret != 1) { LOG_ERROR("Buspirate did not answer correctly"); exit(-1); } if (tmp[0] != 1) { LOG_ERROR("Buspirate did not reply as expected to the speed change command"); exit(-1); } } static void buspirate_swd_set_mode(int fd, char mode) { int ret; uint8_t tmp[1]; /* raw-wire mode configuration */ if (mode == MODE_HIZ) tmp[0] = CMD_RAW_MODE | CMD_RAW_CONFIG_LSB; else tmp[0] = CMD_RAW_MODE | CMD_RAW_CONFIG_LSB | CMD_RAW_CONFIG_3V3; buspirate_serial_write(fd, tmp, 1); ret = buspirate_serial_read(fd, tmp, 1); if (ret != 1) { LOG_ERROR("Buspirate did not answer correctly"); exit(-1); } if (tmp[0] != 1) { LOG_ERROR("Buspirate did not reply as expected to the configure command"); exit(-1); } } static void buspirate_swd_set_feature(int fd, char feat, char action) { int ret; uint8_t tmp[1]; switch (feat) { case FEATURE_TRST: LOG_DEBUG("Buspirate TRST feature not available in SWD mode"); return; case FEATURE_LED: LOG_ERROR("Buspirate LED feature not available in SWD mode"); return; case FEATURE_SRST: swd_features = (action == ACTION_ENABLE) ? swd_features | 0x02 : swd_features & 0x0D; break; case FEATURE_PULLUP: swd_features = (action == ACTION_ENABLE) ? swd_features | 0x04 : swd_features & 0x0B; break; case FEATURE_VREG: swd_features = (action == ACTION_ENABLE) ? swd_features | 0x08 : swd_features & 0x07; break; default: LOG_DEBUG("Buspirate unknown feature %d", feat); return; } tmp[0] = CMD_RAW_PERIPH | swd_features; buspirate_serial_write(fd, tmp, 1); ret = buspirate_serial_read(fd, tmp, 1); if (ret != 1) { LOG_DEBUG("Buspirate feature %d not supported in SWD mode", feat); } else if (tmp[0] != 1) { LOG_ERROR("Buspirate did not reply as expected to the configure command"); exit(-1); } } /*************** jtag lowlevel functions ********************/ static void buspirate_bbio_enable(int fd) { int ret; char command; const char *mode_answers[2] = { "OCD1", "RAW1" }; const char *correct_ans = NULL; uint8_t tmp[21] = { [0 ... 20] = 0x00 }; int done = 0; int cmd_sent = 0; if (swd_mode) { command = CMD_ENTER_RWIRE; correct_ans = mode_answers[1]; } else { command = CMD_ENTER_OOCD; correct_ans = mode_answers[0]; } LOG_DEBUG("Entering binary mode, that is %s", correct_ans); buspirate_serial_write(fd, tmp, 20); usleep(10000); /* reads 1 to n "BBIO1"s and one "OCD1" or "RAW1" */ while (!done) { ret = buspirate_serial_read(fd, tmp, 4); if (ret != 4) { LOG_ERROR("Buspirate error. Is binary" "/OpenOCD support enabled?"); exit(-1); } if (strncmp((char *)tmp, "BBIO", 4) == 0) { ret = buspirate_serial_read(fd, tmp, 1); if (ret != 1) { LOG_ERROR("Buspirate did not answer correctly! " "Do you have correct firmware?"); exit(-1); } if (tmp[0] != '1') { LOG_ERROR("Unsupported binary protocol"); exit(-1); } if (cmd_sent == 0) { cmd_sent = 1; tmp[0] = command; ret = buspirate_serial_write(fd, tmp, 1); if (ret != 1) { LOG_ERROR("error reading"); exit(-1); } } } else if (strncmp((char *)tmp, correct_ans, 4) == 0) done = 1; else { LOG_ERROR("Buspirate did not answer correctly! " "Do you have correct firmware?"); exit(-1); } } } static void buspirate_jtag_reset(int fd) { uint8_t tmp[5]; tmp[0] = 0x00; /* exit OCD1 mode */ buspirate_serial_write(fd, tmp, 1); usleep(10000); /* We ignore the return value here on purpose, nothing we can do */ buspirate_serial_read(fd, tmp, 5); if (strncmp((char *)tmp, "BBIO1", 5) == 0) { tmp[0] = 0x0F; /* reset BP */ buspirate_serial_write(fd, tmp, 1); } else LOG_ERROR("Unable to restart buspirate!"); } static void buspirate_jtag_set_speed(int fd, char speed) { int ret; uint8_t tmp[2]; uint8_t ack[2]; ack[0] = 0xAA; ack[1] = 0x55; tmp[0] = CMD_UART_SPEED; tmp[1] = speed; buspirate_jtag_command(fd, tmp, 2); /* here the adapter changes speed, we need follow */ if (-1 == buspirate_serial_setspeed(fd, speed, NORMAL_TIMEOUT)) { LOG_ERROR("Error configuring the serial port."); exit(-1); } buspirate_serial_write(fd, ack, 2); ret = buspirate_serial_read(fd, tmp, 2); if (ret != 2) { LOG_ERROR("Buspirate did not ack speed change"); exit(-1); } if ((tmp[0] != CMD_UART_SPEED) || (tmp[1] != speed)) { LOG_ERROR("Buspirate did not reply as expected to the speed change command"); exit(-1); } LOG_INFO("Buspirate switched to %s mode", (speed == SERIAL_NORMAL) ? "normal" : "FAST"); } static void buspirate_jtag_set_mode(int fd, char mode) { uint8_t tmp[2]; tmp[0] = CMD_PORT_MODE; tmp[1] = mode; buspirate_jtag_command(fd, tmp, 2); } static void buspirate_jtag_set_feature(int fd, char feat, char action) { uint8_t tmp[3]; tmp[0] = CMD_FEATURE; tmp[1] = feat; /* what */ tmp[2] = action; /* action */ buspirate_jtag_command(fd, tmp, 3); } static void buspirate_jtag_get_adcs(int fd) { uint8_t tmp[10]; uint16_t a, b, c, d; tmp[0] = CMD_READ_ADCS; buspirate_jtag_command(fd, tmp, 1); a = tmp[2] << 8 | tmp[3]; b = tmp[4] << 8 | tmp[5]; c = tmp[6] << 8 | tmp[7]; d = tmp[8] << 8 | tmp[9]; LOG_INFO("ADC: ADC_Pin = %.02f VPullup = %.02f V33 = %.02f " "V50 = %.02f", ((float)a)/155.1515, ((float)b)/155.1515, ((float)c)/155.1515, ((float)d)/155.1515); } static unsigned char buspirate_jtag_command(int fd, uint8_t *cmd, int cmdlen) { int res; int len = 0; res = buspirate_serial_write(fd, cmd, cmdlen); if ((cmd[0] == CMD_UART_SPEED) || (cmd[0] == CMD_PORT_MODE) || (cmd[0] == CMD_FEATURE) || (cmd[0] == CMD_JTAG_SPEED)) return 1; if (res == cmdlen) { switch (cmd[0]) { case CMD_READ_ADCS: len = 10; /* 2*sizeof(char)+4*sizeof(uint16_t) */ break; case CMD_TAP_SHIFT: len = cmdlen; break; default: LOG_INFO("Wrong !"); } res = buspirate_serial_read(fd, cmd, len); if (res > 0) return (unsigned char)cmd[1]; else return -1; } else return -1; return 0; } /* low level serial port */ /* TODO add support for WIN32 and others ! */ static int buspirate_serial_open(char *port) { int fd; fd = open(buspirate_port, O_RDWR | O_NOCTTY | O_NDELAY); return fd; } /* Returns -1 on error. */ static int buspirate_serial_setspeed(int fd, char speed, cc_t timeout) { struct termios t_opt; speed_t baud = (speed == SERIAL_FAST) ? B1000000 : B115200; /* set the serial port parameters */ fcntl(fd, F_SETFL, 0); if (tcgetattr(fd, &t_opt) != 0) return -1; if (cfsetispeed(&t_opt, baud) != 0) return -1; if (cfsetospeed(&t_opt, baud) != 0) return -1; t_opt.c_cflag |= (CLOCAL | CREAD); t_opt.c_cflag &= ~PARENB; t_opt.c_cflag &= ~CSTOPB; t_opt.c_cflag &= ~CSIZE; t_opt.c_cflag |= CS8; t_opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* The serial port may have been configured for human interaction with the Bus Pirate console, but OpenOCD is going to use a binary protocol, so make sure to turn off any CR/LF translation and the like. */ t_opt.c_iflag &= ~(IXON | IXOFF | IXANY | INLCR | ICRNL); t_opt.c_oflag &= ~OPOST; t_opt.c_cc[VMIN] = 0; t_opt.c_cc[VTIME] = timeout; /* Note that, in the past, TCSANOW was used below instead of TCSADRAIN, and CMD_UART_SPEED did not work properly then, at least with the Bus Pirate v3.5 (USB). */ if (tcsetattr(fd, TCSADRAIN, &t_opt) != 0) { /* According to the Linux documentation, this is actually not enough to detect errors, you need to call tcgetattr() and check that all changes have been performed successfully. */ return -1; } return 0; } static int buspirate_serial_write(int fd, uint8_t *buf, int size) { int ret = 0; ret = write(fd, buf, size); LOG_DEBUG("size = %d ret = %d", size, ret); buspirate_print_buffer(buf, size); if (ret != size) LOG_ERROR("Error sending data"); return ret; } static int buspirate_serial_read(int fd, uint8_t *buf, int size) { int len = 0; int ret = 0; int timeout = 0; while (len < size) { ret = read(fd, buf+len, size-len); if (ret == -1) return -1; if (ret == 0) { timeout++; if (timeout >= 10) break; continue; } len += ret; } LOG_DEBUG("should have read = %d actual size = %d", size, len); buspirate_print_buffer(buf, len); if (len != size) LOG_ERROR("Error reading data"); return len; } static void buspirate_serial_close(int fd) { close(fd); } #define LINE_SIZE 81 #define BYTES_PER_LINE 16 static void buspirate_print_buffer(uint8_t *buf, int size) { char line[LINE_SIZE]; char tmp[10]; int offset = 0; line[0] = 0; while (offset < size) { snprintf(tmp, 5, "%02x ", (uint8_t)buf[offset]); offset++; strcat(line, tmp); if (offset % BYTES_PER_LINE == 0) { LOG_DEBUG("%s", line); line[0] = 0; } } if (line[0] != 0) LOG_DEBUG("%s", line); } /************************* SWD related stuff **********/ static int buspirate_swd_init(void) { LOG_INFO("Buspirate SWD mode enabled"); swd_mode = true; return ERROR_OK; } static int buspirate_swd_switch_seq(enum swd_special_seq seq) { const uint8_t *sequence; int sequence_len; uint32_t no_bytes, sequence_offset; switch (seq) { case LINE_RESET: LOG_DEBUG("SWD line reset"); sequence = swd_seq_line_reset; sequence_len = DIV_ROUND_UP(swd_seq_line_reset_len, 8); break; case JTAG_TO_SWD: LOG_DEBUG("JTAG-to-SWD"); sequence = swd_seq_jtag_to_swd; sequence_len = DIV_ROUND_UP(swd_seq_jtag_to_swd_len, 8); break; case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); sequence = swd_seq_swd_to_jtag; sequence_len = DIV_ROUND_UP(swd_seq_swd_to_jtag_len, 8); break; default: LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; } no_bytes = sequence_len; sequence_offset = 0; while (no_bytes) { uint8_t tmp[17]; uint32_t to_send; to_send = no_bytes > 16 ? 16 : no_bytes; tmp[0] = 0x10 + ((to_send - 1) & 0x0F); memcpy(tmp + 1, &sequence[sequence_offset], to_send); buspirate_serial_write(buspirate_fd, tmp, to_send + 1); buspirate_serial_read(buspirate_fd, tmp, to_send + 1); no_bytes -= to_send; sequence_offset += to_send; } return ERROR_OK; } static uint8_t buspirate_swd_write_header(uint8_t cmd) { uint8_t tmp[8]; int to_send; tmp[0] = 0x10; /* bus pirate: send 1 byte */ tmp[1] = cmd; /* swd cmd */ tmp[2] = 0x07; /* ack __x */ tmp[3] = 0x07; /* ack _x_ */ tmp[4] = 0x07; /* ack x__ */ tmp[5] = 0x07; /* write mode trn_1 */ tmp[6] = 0x07; /* write mode trn_2 */ to_send = ((cmd & SWD_CMD_RNW) == 0) ? 7 : 5; buspirate_serial_write(buspirate_fd, tmp, to_send); /* read ack */ buspirate_serial_read(buspirate_fd, tmp, 2); /* drop pirate command ret vals */ buspirate_serial_read(buspirate_fd, tmp, to_send - 2); /* ack bits */ return tmp[2] << 2 | tmp[1] << 1 | tmp[0]; } static void buspirate_swd_idle_clocks(uint32_t no_bits) { uint32_t no_bytes; uint8_t tmp[20]; no_bytes = (no_bits + 7) / 8; memset(tmp + 1, 0x00, sizeof(tmp) - 1); /* unfortunately bus pirate misbehaves when clocks are sent in parts * so we need to limit at 128 clock cycles */ if (no_bytes > 16) no_bytes = 16; while (no_bytes) { uint8_t to_send = no_bytes > 16 ? 16 : no_bytes; tmp[0] = 0x10 + ((to_send - 1) & 0x0F); buspirate_serial_write(buspirate_fd, tmp, to_send + 1); buspirate_serial_read(buspirate_fd, tmp, to_send + 1); no_bytes -= to_send; } } static void buspirate_swd_clear_sticky_errors(void) { buspirate_swd_write_reg(swd_cmd(false, false, DP_ABORT), STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); } static void buspirate_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { uint8_t tmp[16]; LOG_DEBUG("buspirate_swd_read_reg"); assert(cmd & SWD_CMD_RNW); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skip buspirate_swd_read_reg because queued_retval=%d", queued_retval); return; } cmd |= SWD_CMD_START | SWD_CMD_PARK; uint8_t ack = buspirate_swd_write_header(cmd); /* do a read transaction */ tmp[0] = 0x06; /* 4 data bytes */ tmp[1] = 0x06; tmp[2] = 0x06; tmp[3] = 0x06; tmp[4] = 0x07; /* parity bit */ tmp[5] = 0x21; /* 2 turnaround clocks */ buspirate_serial_write(buspirate_fd, tmp, 6); buspirate_serial_read(buspirate_fd, tmp, 6); /* store the data and parity */ uint32_t data = (uint8_t) tmp[0]; data |= (uint8_t) tmp[1] << 8; data |= (uint8_t) tmp[2] << 16; data |= (uint8_t) tmp[3] << 24; int parity = tmp[4] ? 0x01 : 0x00; LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", cmd & SWD_CMD_APNDP ? "AP" : "DP", cmd & SWD_CMD_RNW ? "read" : "write", (cmd & SWD_CMD_A32) >> 1, data); switch (ack) { case SWD_ACK_OK: if (parity != parity_u32(data)) { LOG_DEBUG("Read data parity mismatch %x %x", parity, parity_u32(data)); queued_retval = ERROR_FAIL; return; } if (value) *value = data; if (cmd & SWD_CMD_APNDP) buspirate_swd_idle_clocks(ap_delay_clk); return; case SWD_ACK_WAIT: LOG_DEBUG("SWD_ACK_WAIT"); buspirate_swd_clear_sticky_errors(); return; case SWD_ACK_FAULT: LOG_DEBUG("SWD_ACK_FAULT"); queued_retval = ack; return; default: LOG_DEBUG("No valid acknowledge: ack=%d", ack); queued_retval = ack; return; } } static void buspirate_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { uint8_t tmp[16]; LOG_DEBUG("buspirate_swd_write_reg"); assert(!(cmd & SWD_CMD_RNW)); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skip buspirate_swd_write_reg because queued_retval=%d", queued_retval); return; } cmd |= SWD_CMD_START | SWD_CMD_PARK; uint8_t ack = buspirate_swd_write_header(cmd); /* do a write transaction */ tmp[0] = 0x10 + ((4 + 1 - 1) & 0xF); /* bus pirate: send 4+1 bytes */ buf_set_u32((uint8_t *) tmp + 1, 0, 32, value); /* write sequence ends with parity bit and 7 idle ticks */ tmp[5] = parity_u32(value) ? 0x01 : 0x00; buspirate_serial_write(buspirate_fd, tmp, 6); buspirate_serial_read(buspirate_fd, tmp, 6); LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", cmd & SWD_CMD_APNDP ? "AP" : "DP", cmd & SWD_CMD_RNW ? "read" : "write", (cmd & SWD_CMD_A32) >> 1, value); switch (ack) { case SWD_ACK_OK: if (cmd & SWD_CMD_APNDP) buspirate_swd_idle_clocks(ap_delay_clk); return; case SWD_ACK_WAIT: LOG_DEBUG("SWD_ACK_WAIT"); buspirate_swd_clear_sticky_errors(); return; case SWD_ACK_FAULT: LOG_DEBUG("SWD_ACK_FAULT"); queued_retval = ack; return; default: LOG_DEBUG("No valid acknowledge: ack=%d", ack); queued_retval = ack; return; } } static int buspirate_swd_run_queue(void) { LOG_DEBUG("buspirate_swd_run_queue"); /* A transaction must be followed by another transaction or at least 8 idle cycles to * ensure that data is clocked through the AP. */ buspirate_swd_idle_clocks(8); int retval = queued_retval; queued_retval = ERROR_OK; LOG_DEBUG("SWD queue return value: %02x", retval); return retval; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/ch347.c ================================================ /*************************************************************************** * Driver for CH347-JTAG interface V1.1 * * * * Copyright (C) 2022 by oidcat. * * Author: oidcatiot@163.com * * * * CH347 is a high-speed USB bus converter chip that provides UART, I2C * * and SPI synchronous serial ports and JTAG interface through USB bus. * * * * The Jtag interface by CH347 can supports transmission frequency * * configuration up to 60MHz. * * * * The USB2.0 to JTAG scheme based on CH347 can be used to build * * customized USB high-speed JTAG debugger and other products. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * _____________ * * | |____JTAG/SWD (TDO,TDI,TMS,TCK,TRST) * * USB__| CH347T/F | * * |_____________|____UART(TXD1,RXD1,RTS1,CTS1,DTR1) * * ______|______ * * | | * * | 8 MHz XTAL | * * |_____________| * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see <http://www.gnu.org/licenses/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #if IS_CYGWIN == 1 #include "windows.h" #undef LOG_ERROR #endif /* project specific includes */ #include <jtag/interface.h> #include <jtag/commands.h> #include <jtag/swd.h> #include <helper/time_support.h> #include <helper/replacements.h> #include <helper/list.h> #include <helper/binarybuffer.h> #include "libusb_helper.h" /* system includes */ #include <stdlib.h> #include <string.h> #include <sys/time.h> #include <time.h> #include <unistd.h> #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) #define JTAGIO_STA_OUT_TDI (0x10) #define JTAGIO_STA_OUT_TMS (0x02) #define JTAGIO_STA_OUT_TCK (0x01) #define JTAGIO_STA_OUT_TRST (0x20) #define JTAGIO_STA_OUT_SRST (0x40) #define TDI_H JTAGIO_STA_OUT_TDI #define TDI_L 0 #define TMS_H JTAGIO_STA_OUT_TMS #define TMS_L 0 #define TCK_H JTAGIO_STA_OUT_TCK #define TCK_L 0 #define TRST_H JTAGIO_STA_OUT_TRST #define TRST_L 0 #define SRST_H JTAGIO_STA_OUT_SRST #define SRST_L 0 #define KHZ(n) ((n)*UINT64_C(1000)) #define MHZ(n) ((n)*UINT64_C(1000000)) #define GHZ(n) ((n)*UINT64_C(1000000000)) #define HW_TDO_BUF_SIZE 4096 #define SF_PACKET_BUF_SIZE 51200 /* Command packet length */ #define UCMDPKT_DATA_MAX_BYTES_USBHS 507 /* The data length contained in each command packet during USB high-speed operation */ #define USBC_PACKET_USBHS 512 /* Maximum data length per packet at USB high speed */ #define USBC_PACKET_USBHS_SINGLE 510 /* usb high speed max package length */ #define CH347_CMD_HEADER 3 /* Protocol header length */ /* Protocol transmission format: CMD (1 byte)+Length (2 bytes)+Data */ #define CH347_CMD_INFO_RD 0xCA /* Parameter acquisition, used to obtain firmware version, JTAG interface related parameters, etc */ #define CH347_CMD_JTAG_INIT 0xD0 /* JTAG Interface Initialization Command */ #define CH347_CMD_JTAG_BIT_OP 0xD1 /* JTAG interface pin bit control command */ #define CH347_CMD_JTAG_BIT_OP_RD 0xD2 /* JTAG interface pin bit control and read commands */ #define CH347_CMD_JTAG_DATA_SHIFT 0xD3 /* JTAG interface data shift command */ #define CH347_CMD_JTAG_DATA_SHIFT_RD 0xD4 /* JTAG interface data shift and read command */ /* SWD */ #define CH347_CMD_SWD_INIT 0xE5 /* SWD Interface Initialization Command */ #define CH347_CMD_SWD 0xE8 #define CH347_CMD_SWD_REG_W 0xA0 /* SWD Interface write reg */ #define CH347_CMD_SWD_SEQ_W 0xA1 /* SWD Interface write spec seq */ #define CH347_CMD_SWD_REG_R 0xA2 /* SWD Interface read reg */ #define CH347_MAX_SEND_CMD 0X20 /* max send cmd number */ #define CH347_MAX_SEND_BUF 0X200 #define CH347_MAX_RECV_BUF 0X200 #define BUILD_UINT16(loByte, hiByte) \ ((uint16_t)(((loByte)&0x00FF) + (((hiByte)&0x00FF) << 8))) #pragma pack(1) typedef unsigned char UCHAR; typedef enum pack { STANDARD_PACK = 0, LARGER_PACK = 1, } PACK_SIZE; typedef struct _CH347_info /* Record the CH347 pin status */ { int TMS; int TDI; int TCK; int TRST; int SRST; int buffer_idx; uint8_t buffer[SF_PACKET_BUF_SIZE]; int len_idx; int len_value; uint8_t lastCmd; uint8_t read_buffer[SF_PACKET_BUF_SIZE]; uint32_t read_idx; uint32_t read_count; struct bit_copy_queue read_queue; PACK_SIZE pack_size; } _CH347_Info; int DevIsOpened; /* Whether the device is turned on */ bool UsbHighDev = true; unsigned long USBC_PACKET; typedef struct _CH347_SWD_IO { uint8_t usbcmd; /* 0xA0, 0xA1, 0xA2 */ uint8_t cmd; uint32_t *dst; uint32_t value; struct list_head list_entry; } CH347_SWD_IO, *PCH347_SWD_IO; typedef struct _CH347_SWD_CONTEXT { uint8_t send_buf[CH347_MAX_SEND_BUF]; uint8_t recv_buf[CH347_MAX_RECV_BUF]; uint32_t send_len; uint32_t recv_len; uint32_t need_recv_len; int queued_retval; uint8_t sent_cmd_count; struct list_head send_cmd_head; struct list_head free_cmd_head; uint8_t *ch347_cmd_buf; } CH347_SWD_CONTEXT; static CH347_SWD_CONTEXT ch347_swd_context; static bool swd_mode = false; static int ch347_srst_enable(void); #pragma pack() #ifdef _WIN32 #include <windows.h> //Device Information typedef struct _DEV_INFOR{ UCHAR iIndex; // Current open number UCHAR DevicePath[MAX_PATH]; // Device link name, used for CreateFile UCHAR UsbClass; // 0:CH347_USB_CH341, 2:CH347_USB_HID,3:CH347_USB_VCP UCHAR FuncType; // 0:CH347_FUNC_UART,1:CH347_FUNC_SPI_IIC,2:CH347_FUNC_JTAG_IIC CHAR DeviceID[64]; // USB\VID_xxxx&PID_xxxx UCHAR ChipMode; // Chip Mode, 0:Mode0(UART0/1); 1:Mode1(Uart1+SPI+IIC); 2:Mode2(HID Uart1+SPI+IIC) 3:Mode3(Uart1+Jtag+IIC) HANDLE DevHandle; // Device handle USHORT BulkOutEndpMaxSize; // Upload endpoint size USHORT BulkInEndpMaxSize; // The size of the downstream endpoint UCHAR UsbSpeedType; // USB Speed type,0:FS,1:HS,2:SS UCHAR CH347IfNum; // USB interface number: 0:UART,1:SPI/IIC/JTAG/GPIO UCHAR DataUpEndp; // The endpoint address UCHAR DataDnEndp; // The endpoint address CHAR ProductString[64]; // Product string in USB descriptor CHAR ManufacturerString[64]; // Manufacturer string in USB descriptor ULONG WriteTimeout; // USB write timeout ULONG ReadTimeout; // USB read timeout CHAR FuncDescStr[64]; // Interface functions UCHAR FirewareVer; // Firmware version }mDeviceInforS,*mPDeviceInforS; typedef int(__stdcall * pCH347OpenDevice)(unsigned long iIndex); typedef int(__stdcall * pCH347CloseDevice)(unsigned long iIndex); typedef unsigned long(__stdcall * pCH347SetTimeout)( unsigned long iIndex, /* Specify equipment serial number */ unsigned long iWriteTimeout, /* Specifies the timeout period for USB write out data blocks, in milliseconds mS, and 0xFFFFFFFF specifies no timeout (default) */ unsigned long iReadTimeout); /* Specifies the timeout period for USB reading data blocks, in milliseconds mS, and 0xFFFFFFFF specifies no timeout (default) */ typedef unsigned long(__stdcall * pCH347WriteData)( unsigned long iIndex, /* Specify equipment serial number */ void *oBuffer, /* Point to a buffer large enough to hold the descriptor */ unsigned long *ioLength); /* Pointing to the length unit, the input is the length to be read, and the return is the actual read length */ typedef unsigned long(__stdcall * pCH347ReadData)( unsigned long iIndex, /* Specify equipment serial number */ void *oBuffer, /* Point to a buffer large enough to hold the descriptor */ unsigned long *ioLength); /* Pointing to the length unit, the input is the length to be read, and the return is the actual read length */ typedef unsigned long(__stdcall * pCH347Jtag_INIT)( unsigned long iIndex, /* Specify equipment serial number */ unsigned char iClockRate); /* Pointing to the length unit, the input is the length to be read, and the return is the actual read length */ typedef unsigned long(__stdcall * pCH347GetDeviceInfor)(unsigned long iIndex, mDeviceInforS *DevInformation); HMODULE uhModule; BOOL ugOpen; unsigned long ugIndex; pCH347OpenDevice CH347OpenDevice; pCH347CloseDevice CH347CloseDevice; pCH347SetTimeout CH347SetTimeout; pCH347ReadData CH347ReadData; pCH347WriteData CH347WriteData; pCH347GetDeviceInfor CH347GetDeviceInfor; /* pCH347Jtag_INIT CH347Jtag_INIT; */ #elif defined(__linux__) #include <jtag/drivers/libusb_helper.h> #define CH347_EPOUT 0x06u #define CH347_EPIN 0x86u int g_bus_num = 0; int g_device_addr = 0; bool ugOpen; unsigned long ugIndex; struct libusb_device_handle *ch347_handle; static const uint16_t ch347_vids[] = {0x1a86, 0x1a86, 0x1a86}; static const uint16_t ch347_pids[] = {0x55dd, 0x55de, 0x55e7}; static uint32_t CH347OpenDevice(uint64_t iIndex) { libusb_device** devs; int i = 0; ssize_t cnt; int ret; struct libusb_device *dev; struct libusb_device_descriptor desc; if (libusb_init(NULL) < 0) { return false; } if (g_bus_num != 0 && g_device_addr != 0) { cnt = libusb_get_device_list(NULL, &devs); if (cnt < 0) return false; while ((dev = devs[i++]) != NULL) { if (g_bus_num != 0 && g_device_addr != 0 && (libusb_get_bus_number(dev) != g_bus_num || libusb_get_device_address(dev) != g_device_addr)) continue; if (libusb_open(dev, &ch347_handle) < 0){ return false; }else{ return true; } } libusb_free_device_list(devs, 1); }else{ if (jtag_libusb_open(ch347_vids, ch347_pids, &ch347_handle, NULL) != ERROR_OK) { return false; } else { dev = libusb_get_device(ch347_handle); ret = libusb_get_device_descriptor(dev, &desc); if (ret < 0) { LOG_ERROR("Failed to get device descriptor: '%s'\n", libusb_error_name(ret)); } if (desc.idProduct != 0x55dd){ if (ERROR_OK != ch347_srst_enable()) { LOG_ERROR("ch347 enable srst Error."); } } return true; } } return true; } static bool CH347WriteData(uint64_t iIndex, uint8_t *data, uint64_t *length) { int ret, tmp = 0; ret = jtag_libusb_bulk_write(ch347_handle, CH347_EPOUT, (char *)data, *length, 2000, &tmp); *length = tmp; if (!ret) return true; else return false; } static bool CH347ReadData(uint64_t iIndex, uint8_t *data, uint64_t *length) { int ret, tmp = 0; int size = *length; ret = jtag_libusb_bulk_read(ch347_handle, CH347_EPIN, (char *)data, size, 2000, &tmp); *length = tmp; if (!ret) return true; else return false; } static bool CH347CloseDevice(uint64_t iIndex) { jtag_libusb_close(ch347_handle); return true; } #endif _CH347_Info ch347; static int ch347_swd_run_queue(void); /* swd init func */ static bool CH347SWD_INIT(uint64_t iIndex, uint8_t iClockRate) { uint8_t cmdBuf[128] = ""; unsigned long i = 0; cmdBuf[i++] = CH347_CMD_SWD_INIT; cmdBuf[i++] = 8; /* Data length is 6 */ cmdBuf[i++] = 0; cmdBuf[i++] = 0x40; cmdBuf[i++] = 0x42; cmdBuf[i++] = 0x0f; /* Reserved Bytes */ cmdBuf[i++] = 0x00; /* Reserved Bytes */ cmdBuf[i++] = iClockRate; /* JTAG clock speed */ i += 3; /* Reserved Bytes */ unsigned long mLength = i; if (!CH347WriteData(iIndex, cmdBuf, &mLength) || (mLength != i)) return false; mLength = 4; memset(cmdBuf, 0, sizeof(cmdBuf)); if (!CH347ReadData(iIndex, cmdBuf, &mLength) || (mLength != 4)) return false; return true; } /** * HexToString - Hex Conversion String Function * @param buf Point to a buffer to place the Hex data to be converted * @param size Pointing to the length unit where data needs to be converted * * @return Returns a converted string */ static char *HexToString(uint8_t *buf, uint32_t size) { uint32_t i; if (buf == NULL) return "NULL"; char *str = calloc(size * 2 + 1, 1); for (i = 0; i < size; i++) sprintf(str + 2 * i, "%02x ", buf[i]); return str; } /** * CH347_Write - CH347 Write * @param oBuffer Point to a buffer to place the data to be written out * @param ioLength Pointing to the length unit, the input is the length to be * written out, and the return is the actual written length * * @return Write success returns 1, failure returns 0 */ static int CH347_Write(void *oBuffer, unsigned long *ioLength) { int ret = -1; char *log_buf = NULL; unsigned long wlength = *ioLength, WI; if (*ioLength >= HW_TDO_BUF_SIZE) wlength = HW_TDO_BUF_SIZE; WI = 0; while (1) { ret = CH347WriteData(ugIndex, (uint8_t *)oBuffer + WI, &wlength); if (!ret) { *ioLength = 0; return false; } LOG_DEBUG_IO("(size=%lu, buf=[%s]) -> %" PRIu32, wlength, (log_buf = HexToString((uint8_t *)oBuffer, wlength)), (uint32_t)wlength); WI += wlength; if (WI >= *ioLength) break; if ((*ioLength - WI) > HW_TDO_BUF_SIZE) wlength = HW_TDO_BUF_SIZE; else wlength = *ioLength - WI; free(log_buf); } *ioLength = WI; return true; } /** * CH347_Read - CH347 Read * @param oBuffer Point to a buffer to place the data to be read in * @param ioLength Pointing to the length unit, the input is the length to * be read, and the return is the actual read length * * @return Write success returns 1, failure returns 0 */ static int CH347_Read(void *oBuffer, unsigned long *ioLength) { unsigned long rlength = *ioLength, WI; char* log_buf = NULL; /* The maximum allowable reading for a single read is 4096B of data. If it exceeds the allowable reading limit, it will be calculated as 4096B */ if (rlength > HW_TDO_BUF_SIZE) rlength = HW_TDO_BUF_SIZE; WI = 0; while (1) { if (!CH347ReadData(ugIndex, (uint8_t *)oBuffer + WI, &rlength)) { LOG_ERROR("CH347_Read read data failure."); return false; } WI += rlength; if (WI >= *ioLength) break; if ((*ioLength - WI) > HW_TDO_BUF_SIZE) rlength = HW_TDO_BUF_SIZE; else rlength = *ioLength - WI; } LOG_DEBUG_IO("(size=%lu, buf=[%s]) -> %" PRIu32, WI, (log_buf = HexToString((uint8_t *)oBuffer, WI)), (uint32_t)WI); *ioLength = WI; free(log_buf); return true; } static int ch347_srst_out(unsigned char status) { unsigned long int BI = 0; unsigned char byte = 0; unsigned char cmdPacket[4] = ""; cmdPacket[BI++] = CH347_CMD_JTAG_BIT_OP; cmdPacket[BI++] = 0x01; cmdPacket[BI++] = 0; byte = ch347.TCK | ch347.TDI | ch347.TMS | (ch347.SRST = (status ? SRST_H : SRST_L)); cmdPacket[BI++] = byte; if (!CH347_Write(cmdPacket, &BI)) { LOG_ERROR("SRST set failure."); return ERROR_FAIL; } return ERROR_OK; } static void CH347_Sleep(int us) { LOG_DEBUG_IO("%s(us=%d)", __func__, us); jtag_sleep(us); } static int ch347_srst_enable(void) { uint8_t srst_enable[11] = {0xe2, 0x08, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; unsigned long wLen = 11; unsigned long rLen = 4; CH347_Write(srst_enable, &wLen); CH347_Read(srst_enable, &rLen); if (srst_enable[1] != 0x01) { LOG_ERROR("ch347 enable srst Error."); return ERROR_FAIL; } ch347_srst_out(SRST_H); return ERROR_OK; } static void CH347_Read_Scan(UCHAR *pBuffer, uint32_t length) { unsigned long read_size = 0; unsigned long RxLen = 0; unsigned long index = 0; unsigned long read_buf_index = 0; unsigned char *read_buf = NULL; int dataLen = 0, i = 0; /*, this_bits = 0; */ read_size = length; RxLen = read_size; index = 0; read_buf_index = 0; read_buf = calloc(sizeof(unsigned char), read_size); if (!CH347_Read(read_buf, &RxLen)) { LOG_ERROR("CH347_Read read data failure."); return; } while (index < read_size) { /* deal with the CH347_CMD_JTAG_BIT_OP_RD or CH347_CMD_JTAG_DATA_SHIFT_RD */ if (read_buf[index] == CH347_CMD_JTAG_DATA_SHIFT_RD) { dataLen = read_buf[++index] & 0xFF; dataLen += (read_buf[++index] & 0xFF) << 8; memcpy(pBuffer + read_buf_index, &read_buf[index + 1], dataLen); read_buf_index += dataLen; index += dataLen + 1; } else if (read_buf[index] == CH347_CMD_JTAG_BIT_OP_RD) { dataLen = read_buf[++index] & 0xFF; dataLen += (read_buf[++index] & 0xFF) << 8; for (i = 0; i < dataLen; i++) { if (read_buf[index + 1 + i] == 0x01) *(pBuffer + read_buf_index) |= (1 << i); else *(pBuffer + read_buf_index) &= ~(1 << i); } read_buf_index += 1; index += dataLen + 1; } else { // LOG_ERROR("readbuf read_commend error"); *(pBuffer + read_buf_index) = read_buf[index]; read_buf_index++; index++; } } if (read_buf) { free(read_buf); read_buf = NULL; } } static void CH347_Flush_Buffer(void) { unsigned long retlen = ch347.buffer_idx; int nb = ch347.buffer_idx, ret = ERROR_OK; while (ret == ERROR_OK && nb > 0) { ret = CH347_Write(ch347.buffer, &retlen); nb -= retlen; } memset(&ch347.buffer, 0, sizeof(ch347.buffer)); ch347.buffer_idx = 0; ch347.lastCmd = 0; ch347.len_idx = 0; ch347.len_value = 0; if (ch347.read_count == 0) return; if (ch347.pack_size == LARGER_PACK) { CH347_Read_Scan(&ch347.read_buffer[0], ch347.read_count); bit_copy_execute(&ch347.read_queue); memset(ch347.read_buffer, 0, SF_PACKET_BUF_SIZE); ch347.read_count = 0; ch347.read_idx = 0; } } static void CH347_In_Buffer(uint8_t byte) { if ((SF_PACKET_BUF_SIZE - ch347.buffer_idx) < 1) CH347_Flush_Buffer(); ch347.buffer[ch347.buffer_idx] = byte; ch347.buffer_idx++; if ((SF_PACKET_BUF_SIZE - ch347.buffer_idx) == 0) CH347_Flush_Buffer(); } static void CH347_In_Buffer_bytes(uint8_t *bytes, unsigned long bytes_length) { if ((ch347.buffer_idx + bytes_length) > SF_PACKET_BUF_SIZE) CH347_Flush_Buffer(); memcpy(&ch347.buffer[ch347.buffer_idx], bytes, bytes_length); ch347.buffer_idx += bytes_length; if ((SF_PACKET_BUF_SIZE - ch347.buffer_idx) < 1) CH347_Flush_Buffer(); } static void combinePackets(uint8_t cmd, int cur_idx, unsigned long int len) { if (cmd != ch347.lastCmd) { ch347.buffer[cur_idx] = cmd; ch347.buffer[cur_idx + 1] = (uint8_t)(((len - CH347_CMD_HEADER) >> 0) & 0xFF); ch347.buffer[cur_idx + 2] = (uint8_t)(((len - CH347_CMD_HEADER) >> 8) & 0xFF); /* update the ch347 struct */ ch347.lastCmd = cmd; ch347.len_idx = cur_idx + 1; ch347.len_value = (len - CH347_CMD_HEADER); } else { /* update the ch347 struct cmd data leng */ ch347.len_value += (len - CH347_CMD_HEADER); /* update the cmd packet valid leng */ ch347.buffer[ch347.len_idx] = (uint8_t)((ch347.len_value >> 0) \ & 0xFF); ch347.buffer[ch347.len_idx + 1] = (uint8_t)( (ch347.len_value >> 8) & 0xFF); /* update the buffer data leng */ memcpy(&ch347.buffer[cur_idx], &ch347.buffer[cur_idx + CH347_CMD_HEADER], (len - CH347_CMD_HEADER)); /* update the ch347 buffer index */ ch347.buffer_idx -= CH347_CMD_HEADER; } } /** * CH347_ClockTms - Function function used to change the TMS value at the * rising edge of TCK to switch its Tap state * @param BitBangPkt Protocol package * @param tms TMS value to be changed * @param BI Protocol packet length * * @return Return protocol packet length */ static unsigned long CH347_ClockTms(int tms, unsigned long BI) { uint8_t data = 0; unsigned char cmd = 0; if (tms == 1) cmd = TMS_H; else cmd = TMS_L; BI += 2; data = cmd | TDI_L | TCK_L | TRST_H | SRST_H; CH347_In_Buffer(data); data = cmd | TDI_L | TCK_H | TRST_H | SRST_H; CH347_In_Buffer(data); ch347.TMS = cmd; ch347.TDI = TDI_L; ch347.TCK = TCK_H; ch347.TRST = TRST_H; ch347.SRST = SRST_H; return BI; } /** * CH347_IdleClock - Function function to ensure that the clock is in a low state * @param BitBangPkt Protocol package * @param BI Protocol packet length * * @return Return protocol packet length */ static unsigned long CH347_IdleClock(unsigned long BI) { unsigned char byte = 0; byte |= ch347.TMS ? TMS_H : TMS_L; byte |= ch347.TDI ? TDI_H : TDI_L; byte |= ch347.TRST ? TRST_H : TRST_L; byte |= ch347.SRST ? SRST_H : SRST_L; BI++; CH347_In_Buffer(byte); return BI; } /** * CH347_TmsChange - Function function that performs state switching by changing the value of TMS * @param tmsValue The TMS values that need to be switched form one byte of data in the switching order * @param step The number of bit values that need to be read from the tmsValue value * @param skip Count from the skip bit of tmsValue to step * */ static void CH347_TmsChange(const unsigned char *tmsValue, int step, int skip) { int i; int index = ch347.buffer_idx; unsigned long BI, retlen, cmdLen; BI = CH347_CMD_HEADER; retlen = CH347_CMD_HEADER; LOG_DEBUG_IO("(TMS Value: %02x..., step = %d, skip = %d)", tmsValue[0], step, skip); for (i = 0; i < 3; i++) CH347_In_Buffer(0); for (i = skip; i < step; i++) { retlen = CH347_ClockTms((tmsValue[i / 8] >> (i % 8)) & 0x01, BI); BI = retlen; } cmdLen = CH347_IdleClock(BI); combinePackets(CH347_CMD_JTAG_BIT_OP, index, cmdLen); } /** * CH347_TMS - By ch347_ execute_ Queue call * @param cmd Upper layer transfer command parameters * */ static void CH347_TMS(struct tms_command *cmd) { LOG_DEBUG_IO("(step: %d)", cmd->num_bits); CH347_TmsChange(cmd->bits, cmd->num_bits, 0); } /** * CH347_Reset - CH347 Reset Tap Status Function * @brief If there are more than six consecutive TCKs and TMS is high, the state * machine can be set to a Test-Logic-Reset state * */ static int ch347_reset(int trst, int srst) { LOG_DEBUG_IO("reset trst: %i srst %i", trst, srst); unsigned char BitBang[512] = "", BII, i; unsigned long TxLen; if (!swd_mode) { BII = CH347_CMD_HEADER; for (i = 0; i < 7; i++) { BitBang[BII++] = TMS_H | TDI_L | TCK_L | SRST_H; BitBang[BII++] = TMS_H | TDI_L | TCK_H | SRST_H; } BitBang[BII++] = TMS_H | TDI_L | TCK_L | SRST_H; ch347.TCK = TCK_L; ch347.TDI = TDI_L; ch347.TMS = 0; BitBang[0] = CH347_CMD_JTAG_BIT_OP; BitBang[1] = BII - CH347_CMD_HEADER; BitBang[2] = 0; TxLen = BII; if (!CH347_Write(BitBang, &TxLen) && (TxLen != BII)) { LOG_ERROR("JTAG_Init send usb data failure."); return false; } } return ERROR_OK; } /** * CH347_MovePath - Obtain the current Tap status and switch to the status TMS * value passed down by cmd * @param cmd Upper layer transfer command parameters * */ static void CH347_MovePath(struct pathmove_command *cmd) { int i; int index = ch347.buffer_idx; unsigned long BI, retlen = 0, cmdLen; BI = CH347_CMD_HEADER; for (i = 0; i < 3; i++) CH347_In_Buffer(0); LOG_DEBUG_IO("(num_states=%d, last_state=%d)", cmd->num_states, cmd->path[cmd->num_states - 1]); for (i = 0; i < cmd->num_states; i++) { if (tap_state_transition(tap_get_state(), false) == cmd->path[i]) retlen = CH347_ClockTms(0, BI); BI = retlen; if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) retlen = CH347_ClockTms(1, BI); BI = retlen; tap_set_state(cmd->path[i]); } cmdLen = CH347_IdleClock(BI); combinePackets(CH347_CMD_JTAG_BIT_OP, index, cmdLen); } /** * CH347_MoveState - Toggle the Tap state to the Target state stat * @param stat Pre switch target path * @param skip Number of digits to skip * */ static void CH347_MoveState(tap_state_t state, int skip) { uint8_t tms_scan; int tms_len; LOG_DEBUG_IO("(from %s to %s)", tap_state_name(tap_get_state()), tap_state_name(state)); if (tap_get_state() == state) return; tms_scan = tap_get_tms_path(tap_get_state(), state); tms_len = tap_get_tms_path_len(tap_get_state(), state); CH347_TmsChange(&tms_scan, tms_len, skip); tap_set_state(state); } /** * CH347_WriteRead - CH347 Batch read/write function * @param bits Read and write data this time * @param nb_bits Incoming data length * @param scan The transmission method of incoming data to determine whether * to perform data reading */ static void CH347_WriteRead(struct scan_command *cmd, uint8_t *bits, int nb_bits, enum scan_type scan) { int nb8 = nb_bits / 8; int nb1 = nb_bits % 8; int i, num_bits = 0; bool IsRead = false; /*, isLastByte = false */ uint8_t TMS_Bit = 0, TDI_Bit = 0, CMD_Bit; static uint8_t byte0[SF_PACKET_BUF_SIZE]; uint8_t *readData = calloc(SF_PACKET_BUF_SIZE, 1); unsigned long readLen = 0; unsigned long BI = 0, DI, DII, PktDataLen, DLen = 0, tempIndex, totalReadLength = 0, tempLength = 0; if (ch347.pack_size == LARGER_PACK) { if ((ch347.read_count >= (510 * 1))) CH347_Flush_Buffer(); } else { CH347_Flush_Buffer(); } if (nb8 > 0 && nb1 == 0) { nb8--; nb1 = 8; } IsRead = (scan == SCAN_IN || scan == SCAN_IO); DI = BI = 0; while (DI < (unsigned long)nb8) { if ((nb8 - DI) > UCMDPKT_DATA_MAX_BYTES_USBHS) PktDataLen = UCMDPKT_DATA_MAX_BYTES_USBHS; else PktDataLen = nb8 - DI; DII = PktDataLen; if (IsRead) CH347_In_Buffer(CH347_CMD_JTAG_DATA_SHIFT_RD); else CH347_In_Buffer(CH347_CMD_JTAG_DATA_SHIFT); /* packet data don't deal D3 & D4 */ if ((CH347_CMD_JTAG_DATA_SHIFT_RD != ch347.lastCmd) | (CH347_CMD_JTAG_DATA_SHIFT != ch347.lastCmd)) { /* update the ch347 struct */ ch347.lastCmd = 0; ch347.len_idx = 0; ch347.len_value = 0; } CH347_In_Buffer((uint8_t)(PktDataLen >> 0) & 0xFF); CH347_In_Buffer((uint8_t)(PktDataLen >> 8) & 0xFF); if (bits) CH347_In_Buffer_bytes(&bits[DI], PktDataLen); else CH347_In_Buffer_bytes(byte0, PktDataLen); DI += DII; tempLength += (DII + CH347_CMD_HEADER); } totalReadLength += tempLength; if (IsRead) { ch347.read_count += tempLength; readLen += tempLength; } if (bits) { CMD_Bit = IsRead ? CH347_CMD_JTAG_BIT_OP_RD : \ CH347_CMD_JTAG_BIT_OP; DLen = (nb1 * 2) + 1; if (CMD_Bit != ch347.lastCmd) { CH347_In_Buffer(CMD_Bit); CH347_In_Buffer((uint8_t)(DLen >> 0) & 0xFF); CH347_In_Buffer((uint8_t)(DLen >> 8) & 0xFF); ch347.lastCmd = CMD_Bit; ch347.len_idx = ch347.buffer_idx - 2; ch347.len_value = DLen; } else { /* update the ch347 struct cmd data leng */ ch347.len_value += DLen; /* update the cmd packet valid leng */ ch347.buffer[ch347.len_idx] = (uint8_t)(ch347.len_value >> 0) & 0xFF; ch347.buffer[ch347.len_idx + 1] = (uint8_t)(ch347.len_value >> 8) & 0xFF; } TMS_Bit = TMS_L; for (i = 0; i < nb1; i++) { if ((bits[nb8] >> i) & 0x01) TDI_Bit = TDI_H; else TDI_Bit = TDI_L; if ((i + 1) == nb1) TMS_Bit = TMS_H; CH347_In_Buffer(TMS_Bit | TDI_Bit | TCK_L | TRST_H | SRST_H); CH347_In_Buffer(TMS_Bit | TDI_Bit | TCK_H | TRST_H | SRST_H); } CH347_In_Buffer(TMS_Bit | TDI_Bit | TCK_L | TRST_H | SRST_H); } ch347.TMS = TMS_Bit; ch347.TDI = TDI_Bit; ch347.TCK = TCK_L; if (IsRead) { tempLength = ((DLen / 2) + CH347_CMD_HEADER); totalReadLength += tempLength; ch347.read_count += tempLength; readLen += tempLength; DI = BI = 0; } int offset = 0, bit_count = 0; if (IsRead && totalReadLength > 0) { if (ch347.pack_size == STANDARD_PACK && bits && cmd) { CH347_Flush_Buffer(); CH347_Read_Scan(readData, readLen); } for (i = 0; i < cmd->num_fields; i++) { /* if neither in_value nor in_handler * are specified we don't have to examine this field */ LOG_DEBUG("fields[%i].in_value[%i], offset: %d", i, cmd->fields[i].num_bits, offset); num_bits = cmd->fields[i].num_bits; if (ch347.pack_size == LARGER_PACK) bit_count += num_bits; if (cmd->fields[i].in_value) { if (ch347.pack_size == LARGER_PACK) { bit_copy_queued( &ch347.read_queue, cmd->fields[i].in_value, 0, &ch347.read_buffer[ch347.read_idx], offset, num_bits); if (num_bits > 7) ch347.read_idx += DIV_ROUND_UP(bit_count, 8); } else { num_bits = cmd->fields[i].num_bits; uint8_t *captured = buf_set_buf( readData, bit_count, malloc(DIV_ROUND_UP(num_bits, 8)), 0, num_bits); if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { char *char_buf = buf_to_hex_str( captured, (num_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : num_bits); free(char_buf); } buf_cpy(captured, cmd->fields[i].in_value, num_bits); free(captured); } }else { LOG_DEBUG_IO("cmd->fields with no data"); } if (ch347.pack_size == LARGER_PACK) { offset += num_bits; }else{ bit_count += cmd->fields[i].num_bits; } } } tempIndex = ch347.buffer_idx; for (i = 0; i < CH347_CMD_HEADER; i++) CH347_In_Buffer(0); BI = CH347_CMD_HEADER; BI = CH347_IdleClock(BI); combinePackets(CH347_CMD_JTAG_BIT_OP, tempIndex, BI); if (readData) { free(readData); readData = NULL; } } static void CH347_RunTest(int cycles, tap_state_t state) { LOG_DEBUG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state); if (tap_get_state() != TAP_IDLE) CH347_MoveState(TAP_IDLE, 0); uint8_t tmsValue = 0; CH347_TmsChange(&tmsValue, 7, 1); CH347_WriteRead(NULL, NULL, cycles, SCAN_OUT); CH347_MoveState(state, 0); } static void CH347_TableClocks(int cycles) { LOG_DEBUG_IO("%s(cycles=%i)", __func__, cycles); CH347_WriteRead(NULL, NULL, cycles, SCAN_OUT); } /** * CH347_Scan - Switch to SHIFT-DR or SHIFT-IR status for scanning * @param cmd Upper layer transfer command parameters * * @return Success returns ERROR_OK */ static int CH347_Scan(struct scan_command *cmd) { int scan_bits; uint8_t *buf = NULL; enum scan_type type; int ret = ERROR_OK; static const char *const type2str[] = { "", "SCAN_IN", "SCAN_OUT", "SCAN_IO" }; char *log_buf = NULL; type = jtag_scan_type(cmd); scan_bits = jtag_build_buffer(cmd, &buf); if (cmd->ir_scan) CH347_MoveState(TAP_IRSHIFT, 0); else CH347_MoveState(TAP_DRSHIFT, 0); log_buf = HexToString(buf, DIV_ROUND_UP(scan_bits, 8)); LOG_DEBUG_IO("Scan"); LOG_DEBUG_IO("%s(scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d)", __func__, cmd->ir_scan ? "IRSCAN" : "DRSCAN", type2str[type], scan_bits, log_buf, cmd->end_state); free(log_buf); CH347_WriteRead(cmd, buf, scan_bits, type); free(buf); CH347_MoveState(cmd->end_state, 1); return ret; } static int ch347_execute_queue(void) { struct jtag_command *cmd; int ret = ERROR_OK; for (cmd = jtag_command_queue; ret == ERROR_OK && cmd; cmd = cmd->next) { switch (cmd->type) { case JTAG_RESET: LOG_DEBUG_IO("JTAG_RESET : %d %d.\n", cmd->cmd.reset->trst, cmd->cmd.reset->srst); ch347_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: CH347_RunTest(cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); break; case JTAG_STABLECLOCKS: CH347_TableClocks(cmd->cmd.stableclocks->num_cycles); break; case JTAG_TLR_RESET: CH347_MoveState(cmd->cmd.statemove->end_state, 0); break; case JTAG_PATHMOVE: CH347_MovePath(cmd->cmd.pathmove); break; case JTAG_TMS: CH347_TMS(cmd->cmd.tms); break; case JTAG_SLEEP: CH347_Sleep(cmd->cmd.sleep->us); break; case JTAG_SCAN: ret = CH347_Scan(cmd->cmd.scan); break; default: LOG_ERROR("BUG: unknown JTAG command type 0x%X", cmd->type); ret = ERROR_FAIL; break; } } CH347_Flush_Buffer(); return ret; } /** * ch347_init - CH347 Initialization function * * Todo: * Initialize dynamic library functions * Open Device * @return Success returns 0, failure returns ERROR_FAIL */ static int ch347_init(void) { #ifdef _WIN32 if (uhModule == 0) { #ifdef _WIN64 uhModule = LoadLibrary("CH347DLLA64.DLL"); #else uhModule = LoadLibrary("CH347DLL.DLL"); #endif if (uhModule) { CH347OpenDevice = (pCH347OpenDevice)GetProcAddress( uhModule, "CH347OpenDevice"); CH347CloseDevice = (pCH347CloseDevice)GetProcAddress( uhModule, "CH347CloseDevice"); CH347ReadData = (pCH347ReadData)GetProcAddress( uhModule, "CH347ReadData"); CH347WriteData = (pCH347WriteData)GetProcAddress( uhModule, "CH347WriteData"); CH347SetTimeout = (pCH347SetTimeout)GetProcAddress( uhModule, "CH347SetTimeout"); CH347GetDeviceInfor = (pCH347GetDeviceInfor)GetProcAddress( uhModule, "CH347GetDeviceInfor"); if (CH347OpenDevice == NULL || CH347CloseDevice == NULL || CH347SetTimeout == NULL || CH347ReadData == NULL || CH347WriteData == NULL || CH347GetDeviceInfor == NULL) { LOG_ERROR("Jtag_init error "); return ERROR_FAIL; } } } DevIsOpened = CH347OpenDevice(ugIndex); if (DevIsOpened == INVALID_HANDLE_VALUE) { #elif defined(__linux__) DevIsOpened = CH347OpenDevice(ugIndex); ugIndex = DevIsOpened; if (DevIsOpened == false) { #endif LOG_ERROR("CH347 Open Error."); return ERROR_FAIL; } else { LOG_INFO("CH347 Open Succ."); } #ifdef _WIN32 mDeviceInforS devInfo; CH347GetDeviceInfor(ugIndex, &devInfo); char* pidstr = strstr(devInfo.DeviceID, "PID_"); if (pidstr){ pidstr += 4; } if (strncmp("55DD", pidstr, 4) != 0) { if (ch347_srst_enable() != ERROR_OK) { LOG_ERROR("ch347 enable srst Error."); } } #endif if (!swd_mode) { USBC_PACKET = USBC_PACKET_USBHS; /* ch347 init */ ch347.TCK = TCK_L; ch347.TMS = TMS_H; ch347.TDI = TDI_L; ch347.TRST = TRST_H; ch347.SRST = SRST_H; ch347.buffer_idx = 0; memset(&ch347.buffer, 0, SF_PACKET_BUF_SIZE); ch347.len_idx = 0; ch347.len_value = 0; ch347.lastCmd = 0; memset(&ch347.read_buffer, 0, SF_PACKET_BUF_SIZE); ch347.read_count = 0; ch347.read_idx = 0; bit_copy_queue_init(&ch347.read_queue); /* CH347SetTimeout(ugIndex, 500, 500); */ tap_set_state(TAP_RESET); } return 0; } /** * ch347_quit - CH347 Device Release Function * * Todo: * Reset JTAG pin signal * Close * @return always returns 0 */ static int ch347_quit(void) { unsigned long retlen = 4; uint8_t byte[4] = {CH347_CMD_JTAG_BIT_OP, 0x01, 0x00, ch347.TRST | ch347.SRST}; if (!swd_mode) { CH347_Write(byte, &retlen); bit_copy_discard(&ch347.read_queue); } if (DevIsOpened) { CH347CloseDevice(ugIndex); LOG_INFO("Close the CH347."); DevIsOpened = false; } return 0; } static bool Check_Speed(uint64_t iIndex, uint8_t iClockRate) { unsigned long int i = 0, j; bool retVal; uint8_t cmdBuf[32] = ""; cmdBuf[i++] = CH347_CMD_JTAG_INIT; cmdBuf[i++] = 6; cmdBuf[i++] = 0; cmdBuf[i++] = 0; cmdBuf[i++] = iClockRate; for (j = 0; j < 4; j++) cmdBuf[i++] = ch347.TCK | ch347.TDI | ch347.TMS | ch347.TRST | ch347.SRST; unsigned long int mLength = i; if (!CH347WriteData(iIndex, cmdBuf, &mLength) || (mLength != i)) return false; mLength = 4; memset(cmdBuf, 0, sizeof(cmdBuf)); if (!CH347ReadData(iIndex, cmdBuf, &mLength) || (mLength != 4)) return false; retVal = ((cmdBuf[0] == CH347_CMD_JTAG_INIT) && \ (cmdBuf[CH347_CMD_HEADER] == 0)); return retVal; } static bool CH347Jtag_INIT(uint64_t iIndex, uint8_t iClockRate) { ch347.pack_size = (Check_Speed(iIndex, 0x09) == true) ? \ STANDARD_PACK : LARGER_PACK; if (ch347.pack_size == STANDARD_PACK) { if (iClockRate - 2 < 0) return Check_Speed(iIndex, 0); else return Check_Speed(iIndex, iClockRate - 2); } return Check_Speed(iIndex, iClockRate); } /** * ch347_speed - CH347 TCK frequency setting * @param speed Frequency size set * @return Success returns ERROR_OK,failed returns FALSE */ static int ch347_speed(int speed) { unsigned long i = 0; uint8_t clockRate; int retval = -1; int speed_clock[8] = { KHZ(468.75), KHZ(937.5), MHZ(1.875), MHZ(3.75), MHZ(7.5), MHZ(15), MHZ(30), MHZ(60) }; if (!swd_mode) { for (i = 0; i < ARRAY_SIZE(speed_clock); i++) { if ((speed >= speed_clock[i]) && (speed <= speed_clock[i + 1])) { clockRate = i + 1; retval = CH347Jtag_INIT(ugIndex, clockRate); if (!retval) { LOG_ERROR("Couldn't set CH347 TCK speed"); return retval; } else { break; } } else if (speed < speed_clock[0]) { retval = CH347Jtag_INIT(ugIndex, 0); if (!retval) { LOG_ERROR("Couldn't set CH347 TCK speed"); return retval; } else { break; } } } } else { if (speed > MHZ(5) ) { CH347SWD_INIT(ugIndex, 0); //5Mhz } else if (speed <= MHZ(5) && speed >= MHZ(1)) { CH347SWD_INIT(ugIndex, 1); //1Mhz } else { CH347SWD_INIT(ugIndex, 2); //500Khz } } return ERROR_OK; } static int ch347_speed_div(int speed, int *khz) { *khz = speed / 1000; return ERROR_OK; } static int ch347_khz(int khz, int *jtag_speed) { if (khz == 0) { LOG_ERROR("Couldn't support the adapter speed"); return ERROR_FAIL; } *jtag_speed = khz * 1000; return ERROR_OK; } static int ch347_trst_out(unsigned char status) { unsigned long int BI = 0; unsigned char byte = 0; unsigned char cmdPacket[4] = ""; cmdPacket[BI++] = CH347_CMD_JTAG_BIT_OP; cmdPacket[BI++] = 0x01; cmdPacket[BI++] = 0; byte = ch347.TCK | ch347.TDI | ch347.TMS | (ch347.TRST = (status ? TRST_H : TRST_L)); cmdPacket[BI++] = byte; if (!CH347_Write(cmdPacket, &BI)) { LOG_ERROR("TRST set failure."); return ERROR_FAIL; } return ERROR_OK; } COMMAND_HANDLER(ch347_handle_vid_pid_command) { /* TODO */ return ERROR_OK; } COMMAND_HANDLER(ch347_trst) { ch347_trst_out(TRST_L); jtag_sleep(atoi(CMD_ARGV[0]) * 1000); ch347_trst_out(TRST_H); return ERROR_OK; } COMMAND_HANDLER(ch347_set_index) { LOG_INFO("ch347_index is %d", atoi(CMD_ARGV[0])); ugIndex = atoi(CMD_ARGV[0]); return ERROR_OK; } /* Obtaining the device sn is a follow-up function. Temporarily unavailable */ COMMAND_HANDLER(ch347_set_busdev) { #ifdef __linux__ if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; LOG_INFO("ch347_set_busdev is %d and %d", atoi(CMD_ARGV[0]), atoi(CMD_ARGV[1])); g_bus_num = atoi(CMD_ARGV[0]); g_device_addr = atoi(CMD_ARGV[1]); return ERROR_OK; #endif } static const struct command_registration ch347_subcommand_handlers[] = { { .name = "vid_pid", .handler = &ch347_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "", .usage = "", }, { .name = "ch347_index", .handler = &ch347_set_index, .mode = COMMAND_ANY, .help = "set deivice index of the CH347", .usage = "", }, { .name = "jtag_ntrst_delay", .handler = &ch347_trst, .mode = COMMAND_ANY, .help = "set the trst of the CH347 device that is used as JTAG", .usage = "[milliseconds]", }, { .name = "busdev-num", .handler = &ch347_set_busdev, .mode = COMMAND_ANY, .help = "set bus_num and device_addr of the CH347", .usage = "", }, COMMAND_REGISTRATION_DONE}; static const struct command_registration ch347_command_handlers[] = { { .name = "ch347", .mode = COMMAND_ANY, .help = "perform ch347 management", .chain = ch347_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE}; static int ch347_swd_init(void) { PCH347_SWD_IO pswd_io; LOG_INFO("CH347 SWD mode enabled"); swd_mode = true; memset(&ch347_swd_context, 0, sizeof(ch347_swd_context)); INIT_LIST_HEAD(&ch347_swd_context.send_cmd_head); INIT_LIST_HEAD(&ch347_swd_context.free_cmd_head); ch347_swd_context.queued_retval = ERROR_OK; /* 0XE8 + 2byte len + N byte cmds */ ch347_swd_context.send_len = CH347_CMD_HEADER; /* 0XE8 + 2byte len + N byte ack + data */ ch347_swd_context.need_recv_len = CH347_CMD_HEADER; ch347_swd_context.ch347_cmd_buf = malloc(128 * sizeof(CH347_SWD_IO)); if (ch347_swd_context.ch347_cmd_buf) { pswd_io = (PCH347_SWD_IO)ch347_swd_context.ch347_cmd_buf; for (int i = 0; i < 128; i++, pswd_io++) { INIT_LIST_HEAD(&pswd_io->list_entry); list_add_tail(&pswd_io->list_entry, &ch347_swd_context.free_cmd_head); } } return ch347_swd_context.ch347_cmd_buf ? ERROR_OK : ERROR_FAIL; } static PCH347_SWD_IO ch347_get_one_swd_io(void) { PCH347_SWD_IO pswd_io; if (list_empty(&ch347_swd_context.free_cmd_head)) { return NULL; } else { pswd_io = list_first_entry(&ch347_swd_context.free_cmd_head, CH347_SWD_IO, list_entry); list_del_init(&pswd_io->list_entry); pswd_io->cmd = 0; pswd_io->usbcmd = CH347_CMD_SWD_SEQ_W; pswd_io->dst = NULL; return pswd_io; } } static void ch347_swd_queue_flush(void) { unsigned long mLength = ch347_swd_context.send_len; ch347_swd_context.send_buf[0] = (uint8_t)CH347_CMD_SWD; ch347_swd_context.send_buf[1] = (uint8_t)(ch347_swd_context.send_len - CH347_CMD_HEADER); ch347_swd_context.send_buf[2] = (uint8_t)((ch347_swd_context.send_len - CH347_CMD_HEADER) >> 8); if (!CH347WriteData(ugIndex, ch347_swd_context.send_buf, &mLength) || (mLength != ch347_swd_context.send_len)) { ch347_swd_context.queued_retval = ERROR_FAIL; LOG_DEBUG("CH347WriteData error "); return; } ch347_swd_context.recv_len = 0; do { mLength = CH347_MAX_RECV_BUF - ch347_swd_context.recv_len; if (!CH347ReadData(ugIndex, &ch347_swd_context.recv_buf[ch347_swd_context.recv_len], &mLength)) { ch347_swd_context.queued_retval = ERROR_FAIL; LOG_DEBUG("CH347ReadData error "); return; } ch347_swd_context.recv_len += mLength; } while (ch347_swd_context.recv_len < ch347_swd_context.need_recv_len); if (ch347_swd_context.need_recv_len > ch347_swd_context.recv_len) { LOG_ERROR("ch347_swd_queue_flush write/read failed %d %d %d", __LINE__, ch347_swd_context.recv_len, ch347_swd_context.need_recv_len); } } static void ch347_wrtie_swd_reg(uint8_t cmd, const uint8_t *out, uint8_t parity) { ch347_swd_context.send_buf[ch347_swd_context.send_len++] = CH347_CMD_SWD_REG_W; /* 8bit + 32bit +1bit */ ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x29; ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00; ch347_swd_context.send_buf[ch347_swd_context.send_len++] = cmd; ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out[0]; ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out[1]; ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out[2]; ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out[3]; ch347_swd_context.send_buf[ch347_swd_context.send_len++] = parity; /* 0xA0 + 1 byte(3bit ACK) */ ch347_swd_context.need_recv_len += (1 + 1); } static void ch347_wrtie_spec_seq(const uint8_t *out, uint8_t out_len) { ch347_swd_context.send_buf[ch347_swd_context.send_len++] = CH347_CMD_SWD_SEQ_W; ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out_len; ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00; for (uint8_t i = 0; i < DIV_ROUND_UP(out_len, 8); i++) { if (out) { ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out[i]; } else { ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00; } } ch347_swd_context.need_recv_len += 1; /* 0xA1 */ } static void ch347_read_swd_reg(uint8_t cmd) { ch347_swd_context.send_buf[ch347_swd_context.send_len++] = CH347_CMD_SWD_REG_R; ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x22; ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00; ch347_swd_context.send_buf[ch347_swd_context.send_len++] = cmd; /* 0xA2 + 1 byte(3bit ACK) + 4 byte(data) + 1 byte(1bit parity+1bit trn) */ ch347_swd_context.need_recv_len += 1 + 1 + 4 + 1; } static int ch347_swd_switch_out(enum swd_special_seq seq, const uint8_t *out, unsigned out_len) { PCH347_SWD_IO pswd_io; if ((ch347_swd_context.send_len + (1 + 2 + DIV_ROUND_UP(out_len, 8))) > CH347_MAX_SEND_BUF) { return ERROR_FAIL; } if ((ch347_swd_context.need_recv_len + 2) > CH347_MAX_RECV_BUF) return ERROR_FAIL; pswd_io = ch347_get_one_swd_io(); if (pswd_io) { ch347_wrtie_spec_seq(out, out_len); list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); return ERROR_OK; } else { return ERROR_FAIL; } } /* check read/write REG can fill in remaining buff */ static bool ch347_chk_buf_size(uint8_t cmd, uint32_t ap_delay_clk) { bool bflush; uint32_t send_len, recv_len, len; bflush = false; send_len = ch347_swd_context.send_len; recv_len = ch347_swd_context.need_recv_len; do { if (cmd & SWD_CMD_RNW) { len = 1 + 1 + 1 + 1; /* 0xA2 + len + rev + cmd */ if (send_len + len > CH347_MAX_SEND_BUF) break; send_len += len; len = 1 + 1 + 4 + 1; /* 0xA2 + 1byte(3bit ack) + 4byte(data) + 1byte(1bit parity+1bit trn) */ if (recv_len + len > CH347_MAX_RECV_BUF) break; recv_len += len; } else { /* write reg */ len = 1 + 1 + 1 + 1 + 4 + 1; /* 0xA0 + len + rev + cmd +data + parity */ if (send_len + len > CH347_MAX_SEND_BUF) break; send_len += len; len = 1 + 1; /* 0xA0 + 1byte(3bit ack) */ if (recv_len + len > CH347_MAX_RECV_BUF) break; recv_len += len; } if (cmd & SWD_CMD_APNDP) { len = 1 + 1 + 1 + DIV_ROUND_UP(ap_delay_clk, 8); /* 0xA1 + Len + rev + n byte(delay) */ if (send_len + len > CH347_MAX_SEND_BUF) break; len = 1; /* 0xA1 */ if ((recv_len + len) > CH347_MAX_RECV_BUF) break; } /* swd packet requests */ bflush = true; } while (false); return bflush; } static void ch347_swd_send_idle(uint32_t ap_delay_clk) { PCH347_SWD_IO pswd_io; pswd_io = ch347_get_one_swd_io(); if (!pswd_io) { ch347_swd_run_queue(); pswd_io = ch347_get_one_swd_io(); if (!pswd_io) { LOG_DEBUG("ch347_swd_queue_cmd error "); ch347_swd_context.queued_retval = ERROR_FAIL; return; } } ch347_wrtie_spec_seq(NULL, ap_delay_clk); list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); } static void ch347_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk) { PCH347_SWD_IO pswd_io; if (ap_delay_clk > 255) printf("ch347_swd_queue_cmd ap_delay_clk = %d\r\n", ap_delay_clk); if (ch347_swd_context.sent_cmd_count >= CH347_MAX_SEND_CMD) ch347_swd_run_queue(); if (!ch347_chk_buf_size(cmd, ap_delay_clk)) ch347_swd_run_queue(); pswd_io = ch347_get_one_swd_io(); if (!pswd_io) { ch347_swd_run_queue(); pswd_io = ch347_get_one_swd_io(); if (!pswd_io) { LOG_DEBUG("ch347_swd_queue_cmd error "); ch347_swd_context.queued_retval = ERROR_FAIL; return; } } pswd_io->cmd = cmd | SWD_CMD_START | SWD_CMD_PARK; if (pswd_io->cmd & SWD_CMD_RNW) { pswd_io->usbcmd = CH347_CMD_SWD_REG_R; pswd_io->dst = dst; ch347_read_swd_reg(pswd_io->cmd); } else { pswd_io->usbcmd = CH347_CMD_SWD_REG_W; pswd_io->value = data; ch347_wrtie_swd_reg(pswd_io->cmd, (uint8_t *)&data, parity_u32(data)); } ch347_swd_context.sent_cmd_count++; list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); /* Insert idle cycles after AP accesses to avoid WAIT */ if (cmd & SWD_CMD_APNDP) { if (ap_delay_clk == 0) printf("ap_delay_clk == 0"); ch347_swd_send_idle(ap_delay_clk); } } static int ch347_swd_switch_seq(enum swd_special_seq seq) { printf("ch347_swd_switch_seq %d \r\n", seq); switch (seq) { case LINE_RESET: LOG_DEBUG("SWD line reset"); return ch347_swd_switch_out(seq, swd_seq_line_reset, swd_seq_line_reset_len); case JTAG_TO_SWD: LOG_DEBUG("JTAG-to-SWD"); return ch347_swd_switch_out(seq, swd_seq_jtag_to_swd, swd_seq_jtag_to_swd_len); case JTAG_TO_DORMANT: LOG_DEBUG("JTAG-to-DORMANT"); return ch347_swd_switch_out(seq, swd_seq_jtag_to_dormant, swd_seq_jtag_to_dormant_len); case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); return ch347_swd_switch_out(seq, swd_seq_swd_to_jtag, swd_seq_swd_to_jtag_len); case SWD_TO_DORMANT: LOG_DEBUG("SWD-to-DORMANT"); return ch347_swd_switch_out(seq, swd_seq_swd_to_dormant, swd_seq_swd_to_dormant_len); case DORMANT_TO_SWD: LOG_DEBUG("DORMANT-to-SWD"); return ch347_swd_switch_out(seq, swd_seq_dormant_to_swd, swd_seq_dormant_to_swd_len); case DORMANT_TO_JTAG: LOG_DEBUG("DORMANT-to-JTAG"); return ch347_swd_switch_out(seq, swd_seq_dormant_to_jtag, swd_seq_dormant_to_jtag_len); default: LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; } } static void ch347_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { assert(cmd & SWD_CMD_RNW); ch347_swd_queue_cmd(cmd, value, 0, ap_delay_clk); } static void ch347_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { assert(!(cmd & SWD_CMD_RNW)); ch347_swd_queue_cmd(cmd, NULL, value, ap_delay_clk); } static int ch347_swd_run_queue(void) { LOG_DEBUG_IO("Executing %u queued transactions", ch347_swd_context.sent_cmd_count); int retval, parity; struct list_head *tmp, *pos; uint8_t *recv_buf; uint32_t recv_len, cmds_len, data; PCH347_SWD_IO pswd_io; if (ch347_swd_context.queued_retval != ERROR_OK) { LOG_DEBUG_IO("Skipping due to previous errors: %d", ch347_swd_context.queued_retval); goto skip; } /* A transaction must be followed by another transaction or at least 8 idle cycles to ensure that data is clocked through the AP. */ if ((ch347_swd_context.send_len + (1 + 2 + 1)) > CH347_MAX_SEND_BUF) goto skip_idle; if ((ch347_swd_context.need_recv_len + 1) > CH347_MAX_RECV_BUF) goto skip_idle; ch347_swd_send_idle(8); skip_idle: ch347_swd_queue_flush(); if (ch347_swd_context.queued_retval != ERROR_OK) { LOG_ERROR("CH347 usb write/read failed %d", __LINE__); goto skip; } recv_buf = ch347_swd_context.recv_buf; recv_len = 0; if (recv_buf[recv_len++] != CH347_CMD_SWD) { /* 0XE8 */ ch347_swd_context.queued_retval = ERROR_FAIL; LOG_ERROR("CH347 usb write/read failed %d", __LINE__); goto skip; } cmds_len = BUILD_UINT16(recv_buf[recv_len], recv_buf[recv_len + 1]); recv_len += 2; /* cmds_len */ if ((cmds_len + CH347_CMD_HEADER) > ch347_swd_context.recv_len) { ch347_swd_context.queued_retval = ERROR_FAIL; LOG_ERROR("CH347 usb write/read failed %d", __LINE__); goto skip; } list_for_each_safe(pos, tmp, &ch347_swd_context.send_cmd_head) { pswd_io = list_entry(pos, CH347_SWD_IO, list_entry); if (pswd_io->usbcmd == CH347_CMD_SWD_SEQ_W) { if (recv_buf[recv_len++] != CH347_CMD_SWD_SEQ_W) { ch347_swd_context.queued_retval = ERROR_FAIL; LOG_ERROR("CH347 usb write/read failed %d", __LINE__); goto skip; } } else { /* read/write Reg */ int ack; bool check_ack; /* read Reg */ if (recv_buf[recv_len] == CH347_CMD_SWD_REG_R) { recv_len++; ack = buf_get_u32(&recv_buf[recv_len++], 0, 3); /* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */ check_ack = swd_cmd_returns_ack(pswd_io->cmd); if (ack != SWD_ACK_OK && check_ack) { ch347_swd_context.queued_retval = swd_ack_to_error_code(ack); LOG_ERROR("ack != SWD_ACK_OK %d", __LINE__); goto skip; } if (pswd_io->cmd & SWD_CMD_RNW) { data = buf_get_u32(&recv_buf[recv_len], 0, 32); parity = buf_get_u32( &recv_buf[recv_len], 32, 1); if (parity != parity_u32(data)) { LOG_ERROR("SWD Read data parity mismatch %d", __LINE__); ch347_swd_context.queued_retval = ERROR_FAIL; goto skip; } LOG_DEBUG_IO("%s%s %s %s reg %X = %08X\n" PRIx32, check_ack ? "" : "ack ignored ", ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : \ ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", pswd_io->cmd & SWD_CMD_APNDP ? "AP" : "DP", pswd_io->cmd & SWD_CMD_RNW ? "read" : "write", (pswd_io->cmd & SWD_CMD_A32) >> 1, data); if (pswd_io->dst) *pswd_io->dst = data; } else { ch347_swd_context.queued_retval = ERROR_FAIL; LOG_ERROR("CH347 usb write/read failed %d", __LINE__); goto skip; } recv_len += 5; } else if (recv_buf[recv_len] == CH347_CMD_SWD_REG_W) { recv_len++; ack = buf_get_u32(&recv_buf[recv_len++], 0, 3); /* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */ check_ack = swd_cmd_returns_ack(pswd_io->cmd); if (ack != SWD_ACK_OK && check_ack) { ch347_swd_context.queued_retval = swd_ack_to_error_code(ack); LOG_ERROR("SWD Read data parity mismatch%d", __LINE__); goto skip; } LOG_DEBUG_IO("%s%s %s %s reg %X = %08X\n" PRIx32, check_ack ? "" : "ack ignored ", ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : \ ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", pswd_io->cmd & SWD_CMD_APNDP ? "AP" : "DP", pswd_io->cmd & SWD_CMD_RNW ? "read" : "write", (pswd_io->cmd & SWD_CMD_A32) >> 1, pswd_io->value); } else { ch347_swd_context.queued_retval = ERROR_FAIL; LOG_ERROR("CH347 usb write/read failed %d recv_len = %d", __LINE__, recv_len); goto skip; } } list_del_init(&pswd_io->list_entry); list_add_tail(&pswd_io->list_entry, &ch347_swd_context.free_cmd_head); } skip: if (!list_empty(&ch347_swd_context.send_cmd_head)) { list_for_each_safe(pos, tmp, &ch347_swd_context.send_cmd_head) { pswd_io = list_entry(pos, CH347_SWD_IO, list_entry); list_del_init(&pswd_io->list_entry); list_add_tail(&pswd_io->list_entry, &ch347_swd_context.free_cmd_head); } } /* 0xE8 + 2byte len */ ch347_swd_context.send_len = CH347_CMD_HEADER; /* 0xE8 + 2byte len */ ch347_swd_context.need_recv_len = CH347_CMD_HEADER; ch347_swd_context.recv_len = 0; ch347_swd_context.sent_cmd_count = 0; retval = ch347_swd_context.queued_retval; ch347_swd_context.queued_retval = ERROR_OK; return retval; } static const struct swd_driver ch347_swd = { .init = ch347_swd_init, .switch_seq = ch347_swd_switch_seq, .read_reg = ch347_swd_read_reg, .write_reg = ch347_swd_write_reg, .run = ch347_swd_run_queue, }; static const char *const ch347_transports[] = {"jtag", "swd", NULL}; static struct jtag_interface ch347_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = ch347_execute_queue, }; struct adapter_driver ch347_adapter_driver = { .name = "ch347", .transports = ch347_transports, .commands = ch347_command_handlers, .init = ch347_init, .quit = ch347_quit, .reset = ch347_reset, .speed = ch347_speed, .khz = ch347_khz, .speed_div = ch347_speed_div, .jtag_ops = &ch347_interface, .swd_ops = &ch347_swd, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/cmsis_dap.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2021 by Adrian Negreanu * * groleo@gmail.com * * * * Copyright (C) 2018 by Mickaël Thomas * * mickael9@gmail.com * * * * Copyright (C) 2016 by Maksym Hilliaka * * oter@frozen-team.com * * * * Copyright (C) 2016 by Phillip Pearson * * pp@myelin.co.nz * * * * Copyright (C) 2014 by Paul Fertser * * fercerpav@gmail.com * * * * Copyright (C) 2013 by mike brown * * mike@theshedworks.org.uk * * * * Copyright (C) 2013 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <transport/transport.h> #include "helper/replacements.h" #include <jtag/adapter.h> #include <jtag/swd.h> #include <jtag/interface.h> #include <jtag/commands.h> #include <jtag/tcl.h> #include <target/cortex_m.h> #include "cmsis_dap.h" #include "libusb_helper.h" static const struct cmsis_dap_backend *const cmsis_dap_backends[] = { #if BUILD_CMSIS_DAP_USB == 1 &cmsis_dap_usb_backend, #endif #if BUILD_CMSIS_DAP_HID == 1 &cmsis_dap_hid_backend, #endif }; /* USB Config */ /* Known vid/pid pairs: * VID 0xc251: Keil Software * PID 0xf001: LPC-Link-II CMSIS_DAP * PID 0xf002: OPEN-SDA CMSIS_DAP (Freedom Board) * PID 0x2722: Keil ULINK2 CMSIS-DAP * PID 0x2750: Keil ULINKplus CMSIS-DAP * * VID 0x0d28: mbed Software * PID 0x0204: MBED CMSIS-DAP */ #define MAX_USB_IDS 8 /* vid = pid = 0 marks the end of the list */ static uint16_t cmsis_dap_vid[MAX_USB_IDS + 1] = { 0 }; static uint16_t cmsis_dap_pid[MAX_USB_IDS + 1] = { 0 }; static int cmsis_dap_backend = -1; static bool swd_mode; /* CMSIS-DAP General Commands */ #define CMD_DAP_INFO 0x00 #define CMD_DAP_LED 0x01 #define CMD_DAP_CONNECT 0x02 #define CMD_DAP_DISCONNECT 0x03 #define CMD_DAP_WRITE_ABORT 0x08 #define CMD_DAP_DELAY 0x09 #define CMD_DAP_RESET_TARGET 0x0A /* CMD_INFO */ #define INFO_ID_VENDOR 0x01 /* string */ #define INFO_ID_PRODUCT 0x02 /* string */ #define INFO_ID_SERNUM 0x03 /* string */ #define INFO_ID_FW_VER 0x04 /* string */ #define INFO_ID_TD_VEND 0x05 /* string */ #define INFO_ID_TD_NAME 0x06 /* string */ #define INFO_ID_CAPS 0xf0 /* byte */ #define INFO_ID_PKT_CNT 0xfe /* byte */ #define INFO_ID_PKT_SZ 0xff /* short */ #define INFO_ID_SWO_BUF_SZ 0xfd /* word */ #define INFO_CAPS_SWD BIT(0) #define INFO_CAPS_JTAG BIT(1) #define INFO_CAPS_SWO_UART BIT(2) #define INFO_CAPS_SWO_MANCHESTER BIT(3) #define INFO_CAPS_ATOMIC_CMDS BIT(4) #define INFO_CAPS_TEST_DOMAIN_TIMER BIT(5) #define INFO_CAPS_SWO_STREAMING_TRACE BIT(6) #define INFO_CAPS_UART_PORT BIT(7) #define INFO_CAPS_USB_COM_PORT BIT(8) #define INFO_CAPS__NUM_CAPS 9 /* CMD_LED */ #define LED_ID_CONNECT 0x00 #define LED_ID_RUN 0x01 #define LED_OFF 0x00 #define LED_ON 0x01 /* CMD_CONNECT */ #define CONNECT_DEFAULT 0x00 #define CONNECT_SWD 0x01 #define CONNECT_JTAG 0x02 /* CMSIS-DAP Common SWD/JTAG Commands */ #define CMD_DAP_DELAY 0x09 #define CMD_DAP_SWJ_PINS 0x10 #define CMD_DAP_SWJ_CLOCK 0x11 #define CMD_DAP_SWJ_SEQ 0x12 /* * PINS * Bit 0: SWCLK/TCK * Bit 1: SWDIO/TMS * Bit 2: TDI * Bit 3: TDO * Bit 5: nTRST * Bit 7: nRESET */ #define SWJ_PIN_TCK (1<<0) #define SWJ_PIN_TMS (1<<1) #define SWJ_PIN_TDI (1<<2) #define SWJ_PIN_TDO (1<<3) #define SWJ_PIN_TRST (1<<5) #define SWJ_PIN_SRST (1<<7) /* CMSIS-DAP SWD Commands */ #define CMD_DAP_SWD_CONFIGURE 0x13 #define CMD_DAP_SWD_SEQUENCE 0x1D /* CMSIS-DAP JTAG Commands */ #define CMD_DAP_JTAG_SEQ 0x14 #define CMD_DAP_JTAG_CONFIGURE 0x15 #define CMD_DAP_JTAG_IDCODE 0x16 /* CMSIS-DAP JTAG sequence info masks */ /* Number of bits to clock through (0 means 64) */ #define DAP_JTAG_SEQ_TCK 0x3F /* TMS will be set during the sequence if this bit is set */ #define DAP_JTAG_SEQ_TMS 0x40 /* TDO output will be captured if this bit is set */ #define DAP_JTAG_SEQ_TDO 0x80 /* CMSIS-DAP Transfer Commands */ #define CMD_DAP_TFER_CONFIGURE 0x04 #define CMD_DAP_TFER 0x05 #define CMD_DAP_TFER_BLOCK 0x06 #define CMD_DAP_TFER_ABORT 0x07 /* DAP_TransferBlock increases the sum of command/response sizes * (due to 16-bit Transfer Count) if used in a small packet. * Prevent using it until we have at least r/w operations. */ #define CMD_DAP_TFER_BLOCK_MIN_OPS 4 /* DAP Status Code */ #define DAP_OK 0 #define DAP_ERROR 0xFF /* CMSIS-DAP SWO Commands */ #define CMD_DAP_SWO_TRANSPORT 0x17 #define CMD_DAP_SWO_MODE 0x18 #define CMD_DAP_SWO_BAUDRATE 0x19 #define CMD_DAP_SWO_CONTROL 0x1A #define CMD_DAP_SWO_STATUS 0x1B #define CMD_DAP_SWO_DATA 0x1C #define CMD_DAP_SWO_EX_STATUS 0x1E /* SWO transport mode for reading trace data */ #define DAP_SWO_TRANSPORT_NONE 0 #define DAP_SWO_TRANSPORT_DATA 1 #define DAP_SWO_TRANSPORT_WINUSB 2 /* SWO trace capture mode */ #define DAP_SWO_MODE_OFF 0 #define DAP_SWO_MODE_UART 1 #define DAP_SWO_MODE_MANCHESTER 2 /* SWO trace data capture */ #define DAP_SWO_CONTROL_STOP 0 #define DAP_SWO_CONTROL_START 1 /* SWO trace status */ #define DAP_SWO_STATUS_CAPTURE_INACTIVE 0 #define DAP_SWO_STATUS_CAPTURE_ACTIVE 1 #define DAP_SWO_STATUS_CAPTURE_MASK BIT(0) #define DAP_SWO_STATUS_STREAM_ERROR_MASK BIT(6) #define DAP_SWO_STATUS_BUFFER_OVERRUN_MASK BIT(7) /* CMSIS-DAP Vendor Commands * None as yet... */ static const char * const info_caps_str[INFO_CAPS__NUM_CAPS] = { "SWD supported", "JTAG supported", "SWO-UART supported", "SWO-MANCHESTER supported", "Atomic commands supported", "Test domain timer supported", "SWO streaming trace supported", "UART communication port supported", "UART via USB COM port supported", }; struct pending_scan_result { /** Offset in bytes in the CMD_DAP_JTAG_SEQ response buffer. */ unsigned int first; /** Number of bits to read. */ unsigned int length; /** Location to store the result */ uint8_t *buffer; /** Offset in the destination buffer */ unsigned int buffer_offset; }; /* Each block in FIFO can contain up to pending_queue_len transfers */ static unsigned int pending_queue_len; static unsigned int tfer_max_command_size; static unsigned int tfer_max_response_size; /* pointers to buffers that will receive jtag scan results on the next flush */ #define MAX_PENDING_SCAN_RESULTS 256 static int pending_scan_result_count; static struct pending_scan_result pending_scan_results[MAX_PENDING_SCAN_RESULTS]; /* queued JTAG sequences that will be executed on the next flush */ #define QUEUED_SEQ_BUF_LEN (cmsis_dap_handle->packet_usable_size - 3) static int queued_seq_count; static int queued_seq_buf_end; static int queued_seq_tdo_ptr; static uint8_t queued_seq_buf[1024]; /* TODO: make dynamic / move into cmsis object */ static int queued_retval; static uint8_t output_pins = SWJ_PIN_SRST | SWJ_PIN_TRST; static struct cmsis_dap *cmsis_dap_handle; static int cmsis_dap_quit(void); static int cmsis_dap_open(void) { const struct cmsis_dap_backend *backend = NULL; struct cmsis_dap *dap = calloc(1, sizeof(struct cmsis_dap)); if (!dap) { LOG_ERROR("unable to allocate memory"); return ERROR_FAIL; } if (cmsis_dap_backend >= 0) { /* Use forced backend */ backend = cmsis_dap_backends[cmsis_dap_backend]; if (backend->open(dap, cmsis_dap_vid, cmsis_dap_pid, adapter_get_required_serial()) != ERROR_OK) backend = NULL; } else { /* Try all backends */ for (unsigned int i = 0; i < ARRAY_SIZE(cmsis_dap_backends); i++) { backend = cmsis_dap_backends[i]; if (backend->open(dap, cmsis_dap_vid, cmsis_dap_pid, adapter_get_required_serial()) == ERROR_OK) break; else backend = NULL; } } if (!backend) { LOG_ERROR("unable to find a matching CMSIS-DAP device"); free(dap); return ERROR_FAIL; } dap->backend = backend; cmsis_dap_handle = dap; return ERROR_OK; } static void cmsis_dap_close(struct cmsis_dap *dap) { if (dap->backend) { dap->backend->close(dap); dap->backend = NULL; } free(dap->packet_buffer); for (unsigned int i = 0; i < MAX_PENDING_REQUESTS; i++) { free(dap->pending_fifo[i].transfers); dap->pending_fifo[i].transfers = NULL; } free(cmsis_dap_handle); cmsis_dap_handle = NULL; } static void cmsis_dap_flush_read(struct cmsis_dap *dap) { unsigned int i; /* Some CMSIS-DAP adapters keep buffered packets over * USB close/open so we need to flush up to 64 old packets * to be sure all buffers are empty */ for (i = 0; i < 64; i++) { int retval = dap->backend->read(dap, 10); if (retval == ERROR_TIMEOUT_REACHED) break; } if (i) LOG_DEBUG("Flushed %u packets", i); } /* Send a message and receive the reply */ static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen) { if (dap->pending_fifo_block_count) { LOG_ERROR("pending %u blocks, flushing", dap->pending_fifo_block_count); while (dap->pending_fifo_block_count) { dap->backend->read(dap, 10); dap->pending_fifo_block_count--; } dap->pending_fifo_put_idx = 0; dap->pending_fifo_get_idx = 0; } uint8_t current_cmd = dap->command[0]; int retval = dap->backend->write(dap, txlen, LIBUSB_TIMEOUT_MS); if (retval < 0) return retval; /* get reply */ retval = dap->backend->read(dap, LIBUSB_TIMEOUT_MS); if (retval < 0) return retval; uint8_t *resp = dap->response; if (resp[0] == DAP_ERROR) { LOG_ERROR("CMSIS-DAP command 0x%" PRIx8 " not implemented", current_cmd); return ERROR_NOT_IMPLEMENTED; } if (resp[0] != current_cmd) { LOG_ERROR("CMSIS-DAP command mismatch. Sent 0x%" PRIx8 " received 0x%" PRIx8, current_cmd, resp[0]); cmsis_dap_flush_read(dap); return ERROR_FAIL; } return ERROR_OK; } static int cmsis_dap_cmd_dap_swj_pins(uint8_t pins, uint8_t mask, uint32_t delay, uint8_t *input) { uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_SWJ_PINS; command[1] = pins; command[2] = mask; h_u32_to_le(&command[3], delay); int retval = cmsis_dap_xfer(cmsis_dap_handle, 7); if (retval != ERROR_OK) { LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_PINS failed."); return ERROR_JTAG_DEVICE_ERROR; } if (input) *input = cmsis_dap_handle->response[1]; return ERROR_OK; } static int cmsis_dap_cmd_dap_swj_clock(uint32_t swj_clock) { uint8_t *command = cmsis_dap_handle->command; /* set clock in Hz */ swj_clock *= 1000; command[0] = CMD_DAP_SWJ_CLOCK; h_u32_to_le(&command[1], swj_clock); int retval = cmsis_dap_xfer(cmsis_dap_handle, 5); if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_CLOCK failed."); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } /* clock a sequence of bits out on TMS, to change JTAG states */ static int cmsis_dap_cmd_dap_swj_sequence(uint8_t s_len, const uint8_t *sequence) { uint8_t *command = cmsis_dap_handle->command; #ifdef CMSIS_DAP_JTAG_DEBUG LOG_DEBUG("cmsis-dap TMS sequence: len=%d", s_len); for (unsigned int i = 0; i < DIV_ROUND_UP(s_len, 8); ++i) printf("%02X ", sequence[i]); printf("\n"); #endif command[0] = CMD_DAP_SWJ_SEQ; command[1] = s_len; bit_copy(&command[2], 0, sequence, 0, s_len); int retval = cmsis_dap_xfer(cmsis_dap_handle, 2 + DIV_ROUND_UP(s_len, 8)); if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) return ERROR_FAIL; return ERROR_OK; } static int cmsis_dap_cmd_dap_info(uint8_t info, uint8_t **data) { uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_INFO; command[1] = info; int retval = cmsis_dap_xfer(cmsis_dap_handle, 2); if (retval != ERROR_OK) { LOG_ERROR("CMSIS-DAP command CMD_INFO failed."); return ERROR_JTAG_DEVICE_ERROR; } *data = &cmsis_dap_handle->response[1]; return ERROR_OK; } static int cmsis_dap_cmd_dap_led(uint8_t led, uint8_t state) { uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_LED; command[1] = led; command[2] = state; int retval = cmsis_dap_xfer(cmsis_dap_handle, 3); if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_LED failed."); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int cmsis_dap_cmd_dap_connect(uint8_t mode) { uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_CONNECT; command[1] = mode; int retval = cmsis_dap_xfer(cmsis_dap_handle, 2); if (retval != ERROR_OK) { LOG_ERROR("CMSIS-DAP command CMD_CONNECT failed."); return ERROR_JTAG_DEVICE_ERROR; } if (cmsis_dap_handle->response[1] != mode) { LOG_ERROR("CMSIS-DAP failed to connect in mode (%d)", mode); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int cmsis_dap_cmd_dap_disconnect(void) { uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_DISCONNECT; int retval = cmsis_dap_xfer(cmsis_dap_handle, 1); if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_DISCONNECT failed."); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int cmsis_dap_cmd_dap_tfer_configure(uint8_t idle, uint16_t retry_count, uint16_t match_retry) { uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_TFER_CONFIGURE; command[1] = idle; h_u16_to_le(&command[2], retry_count); h_u16_to_le(&command[4], match_retry); int retval = cmsis_dap_xfer(cmsis_dap_handle, 6); if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_TFER_Configure failed."); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int cmsis_dap_cmd_dap_swd_configure(uint8_t cfg) { uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_SWD_CONFIGURE; command[1] = cfg; int retval = cmsis_dap_xfer(cmsis_dap_handle, 2); if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_SWD_Configure failed."); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } #if 0 static int cmsis_dap_cmd_dap_delay(uint16_t delay_us) { uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_DELAY; h_u16_to_le(&command[1], delay_us); int retval = cmsis_dap_xfer(cmsis_dap_handle, 3); if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_Delay failed."); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } #endif static int cmsis_dap_metacmd_targetsel(uint32_t instance_id) { uint8_t *command = cmsis_dap_handle->command; const uint32_t SEQ_RD = 0x80, SEQ_WR = 0x00; /* SWD multi-drop requires a transfer ala CMD_DAP_TFER, but with no expectation of an SWD ACK response. In CMSIS-DAP v1.20 and v2.00, CMD_DAP_SWD_SEQUENCE was added to allow this special sequence to be generated. The purpose of this operation is to select the target corresponding to the instance_id that is written */ LOG_DEBUG_IO("DP write reg TARGETSEL %" PRIx32, instance_id); size_t idx = 0; command[idx++] = CMD_DAP_SWD_SEQUENCE; command[idx++] = 3; /* sequence count */ /* sequence 0: packet request for TARGETSEL */ command[idx++] = SEQ_WR | 8; command[idx++] = SWD_CMD_START | swd_cmd(false, false, DP_TARGETSEL) | SWD_CMD_STOP | SWD_CMD_PARK; /* sequence 1: read Trn ACK Trn, no expectation for target to ACK */ command[idx++] = SEQ_RD | 5; /* sequence 2: WDATA plus parity */ command[idx++] = SEQ_WR | (32 + 1); h_u32_to_le(command + idx, instance_id); idx += 4; command[idx++] = parity_u32(instance_id); int retval = cmsis_dap_xfer(cmsis_dap_handle, idx); if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command SWD_Sequence failed."); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } /** * Sets the SWO transport mode. * @param[in] transport The transport mode. Can be None, SWO_Data or * WinUSB (requires CMSIS-DAP v2). */ static int cmsis_dap_cmd_dap_swo_transport(uint8_t transport) { uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_SWO_TRANSPORT; command[1] = transport; int retval = cmsis_dap_xfer(cmsis_dap_handle, 2); if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP: command CMD_SWO_Transport(%d) failed.", transport); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } /** * Sets the SWO trace capture mode. * @param[in] mode Trace capture mode. Can be UART or MANCHESTER. */ static int cmsis_dap_cmd_dap_swo_mode(uint8_t mode) { uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_SWO_MODE; command[1] = mode; int retval = cmsis_dap_xfer(cmsis_dap_handle, 2); if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP: command CMD_SWO_Mode(%d) failed.", mode); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } /** * Sets the baudrate for capturing SWO trace data. * Can be called iteratively to determine supported baudrates. * @param[in] in_baudrate Requested baudrate. * @param[out] dev_baudrate Actual baudrate or 0 (baudrate not configured). * When requested baudrate is not achievable the * closest configured baudrate can be returned or * 0 which indicates that baudrate was not configured. */ static int cmsis_dap_cmd_dap_swo_baudrate( uint32_t in_baudrate, uint32_t *dev_baudrate) { uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_SWO_BAUDRATE; h_u32_to_le(&command[1], in_baudrate); int retval = cmsis_dap_xfer(cmsis_dap_handle, 5); uint32_t rvbr = le_to_h_u32(&cmsis_dap_handle->response[1]); if (retval != ERROR_OK || rvbr == 0) { LOG_ERROR("CMSIS-DAP: command CMD_SWO_Baudrate(%u) -> %u failed.", in_baudrate, rvbr); if (dev_baudrate) *dev_baudrate = 0; return ERROR_JTAG_DEVICE_ERROR; } if (dev_baudrate) *dev_baudrate = rvbr; return ERROR_OK; } /** * Controls the SWO trace data capture. * @param[in] control Start or stop a trace. Starting capture automatically * flushes any existing trace data in buffers which has * not yet been read. */ static int cmsis_dap_cmd_dap_swo_control(uint8_t control) { uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_SWO_CONTROL; command[1] = control; int retval = cmsis_dap_xfer(cmsis_dap_handle, 2); if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP: command CMD_SWO_Control(%d) failed.", control); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } /** * Reads the SWO trace status. * @param[out] trace_status The trace's status. * Bit0: Trace Capture (1 - active, 0 - inactive). * Bit6: Trace Stream Error. * Bit7: Trace Buffer Overrun. * @param[out] trace_count Number of bytes in Trace Buffer (not yet read). */ static int cmsis_dap_cmd_dap_swo_status( uint8_t *trace_status, size_t *trace_count) { uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_SWO_STATUS; int retval = cmsis_dap_xfer(cmsis_dap_handle, 1); if (retval != ERROR_OK) { LOG_ERROR("CMSIS-DAP: command CMD_SWO_Status failed."); return ERROR_JTAG_DEVICE_ERROR; } if (trace_status) *trace_status = cmsis_dap_handle->response[1]; if (trace_count) *trace_count = le_to_h_u32(&cmsis_dap_handle->response[2]); return ERROR_OK; } /** * Reads the captured SWO trace data from Trace Buffer. * @param[in] max_trace_count Maximum number of Trace Data bytes to read. * @param[out] trace_status The trace's status. * @param[out] trace_count Number of Trace Data bytes read. * @param[out] data Trace Data bytes read. */ static int cmsis_dap_cmd_dap_swo_data( size_t max_trace_count, uint8_t *trace_status, size_t *trace_count, uint8_t *data) { uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_SWO_DATA; h_u16_to_le(&command[1], max_trace_count); int retval = cmsis_dap_xfer(cmsis_dap_handle, 3); if (retval != ERROR_OK) { LOG_ERROR("CMSIS-DAP: command CMD_SWO_Data failed."); return ERROR_JTAG_DEVICE_ERROR; } *trace_status = cmsis_dap_handle->response[1]; *trace_count = le_to_h_u16(&cmsis_dap_handle->response[2]); if (*trace_count > 0) memcpy(data, &cmsis_dap_handle->response[4], *trace_count); return ERROR_OK; } static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) { uint8_t *command = dap->command; struct pending_request_block *block = &dap->pending_fifo[dap->pending_fifo_put_idx]; assert(dap->write_count + dap->read_count == block->transfer_count); /* Reset packet size check counters for the next packet */ dap->write_count = 0; dap->read_count = 0; LOG_DEBUG_IO("Executing %d queued transactions from FIFO index %u%s", block->transfer_count, dap->pending_fifo_put_idx, cmsis_dap_handle->swd_cmds_differ ? "" : ", same swd ops"); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); goto skip; } if (block->transfer_count == 0) goto skip; bool block_cmd = !cmsis_dap_handle->swd_cmds_differ && block->transfer_count >= CMD_DAP_TFER_BLOCK_MIN_OPS; block->command = block_cmd ? CMD_DAP_TFER_BLOCK : CMD_DAP_TFER; command[0] = block->command; command[1] = 0x00; /* DAP Index */ unsigned int idx; if (block_cmd) { h_u16_to_le(&command[2], block->transfer_count); idx = 4; /* The first transfer will store the common DAP register */ } else { command[2] = block->transfer_count; idx = 3; } for (unsigned int i = 0; i < block->transfer_count; i++) { struct pending_transfer_result *transfer = &(block->transfers[i]); uint8_t cmd = transfer->cmd; uint32_t data = transfer->data; LOG_DEBUG_IO("%s %s reg %x %" PRIx32, cmd & SWD_CMD_APNDP ? "AP" : "DP", cmd & SWD_CMD_RNW ? "read" : "write", (cmd & SWD_CMD_A32) >> 1, data); /* When proper WAIT handling is implemented in the * common SWD framework, this kludge can be * removed. However, this might lead to minor * performance degradation as the adapter wouldn't be * able to automatically retry anything (because ARM * has forgotten to implement sticky error flags * clearing). See also comments regarding * cmsis_dap_cmd_dap_tfer_configure() and * cmsis_dap_cmd_dap_swd_configure() in * cmsis_dap_init(). */ if (!(cmd & SWD_CMD_RNW) && !(cmd & SWD_CMD_APNDP) && (cmd & SWD_CMD_A32) >> 1 == DP_CTRL_STAT && (data & CORUNDETECT)) { LOG_DEBUG("refusing to enable sticky overrun detection"); data &= ~CORUNDETECT; } if (!block_cmd || i == 0) command[idx++] = (cmd >> 1) & 0x0f; if (!(cmd & SWD_CMD_RNW)) { h_u32_to_le(&command[idx], data); idx += 4; } } int retval = dap->backend->write(dap, idx, LIBUSB_TIMEOUT_MS); if (retval < 0) { queued_retval = retval; goto skip; } else { queued_retval = ERROR_OK; } dap->pending_fifo_put_idx = (dap->pending_fifo_put_idx + 1) % dap->packet_count; dap->pending_fifo_block_count++; if (dap->pending_fifo_block_count > dap->packet_count) LOG_ERROR("too much pending writes %u", dap->pending_fifo_block_count); return; skip: block->transfer_count = 0; } static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms) { struct pending_request_block *block = &dap->pending_fifo[dap->pending_fifo_get_idx]; if (dap->pending_fifo_block_count == 0) LOG_ERROR("no pending write"); /* get reply */ int retval = dap->backend->read(dap, timeout_ms); if (retval == ERROR_TIMEOUT_REACHED && timeout_ms < LIBUSB_TIMEOUT_MS) return; if (retval <= 0) { LOG_DEBUG("error reading data"); queued_retval = ERROR_FAIL; goto skip; } uint8_t *resp = dap->response; if (resp[0] != block->command) { LOG_ERROR("CMSIS-DAP command mismatch. Expected 0x%x received 0x%" PRIx8, block->command, resp[0]); queued_retval = ERROR_FAIL; goto skip; } unsigned int transfer_count; unsigned int idx; if (block->command == CMD_DAP_TFER_BLOCK) { transfer_count = le_to_h_u16(&resp[1]); idx = 3; } else { transfer_count = resp[1]; idx = 2; } if (resp[idx] & 0x08) { LOG_DEBUG("CMSIS-DAP Protocol Error @ %d (wrong parity)", transfer_count); queued_retval = ERROR_FAIL; goto skip; } uint8_t ack = resp[idx++] & 0x07; if (ack != SWD_ACK_OK) { LOG_DEBUG("SWD ack not OK @ %d %s", transfer_count, ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK"); queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL; /* TODO: use results of transfers completed before the error occurred? */ goto skip; } if (block->transfer_count != transfer_count) LOG_ERROR("CMSIS-DAP transfer count mismatch: expected %d, got %d", block->transfer_count, transfer_count); LOG_DEBUG_IO("Received results of %d queued transactions FIFO index %u timeout %i", transfer_count, dap->pending_fifo_get_idx, timeout_ms); for (unsigned int i = 0; i < transfer_count; i++) { struct pending_transfer_result *transfer = &(block->transfers[i]); if (transfer->cmd & SWD_CMD_RNW) { static uint32_t last_read; uint32_t data = le_to_h_u32(&resp[idx]); uint32_t tmp = data; idx += 4; LOG_DEBUG_IO("Read result: %" PRIx32, data); /* Imitate posted AP reads */ if ((transfer->cmd & SWD_CMD_APNDP) || ((transfer->cmd & SWD_CMD_A32) >> 1 == DP_RDBUFF)) { tmp = last_read; last_read = data; } if (transfer->buffer) *(uint32_t *)(transfer->buffer) = tmp; } } skip: block->transfer_count = 0; dap->pending_fifo_get_idx = (dap->pending_fifo_get_idx + 1) % dap->packet_count; dap->pending_fifo_block_count--; } static int cmsis_dap_swd_run_queue(void) { if (cmsis_dap_handle->pending_fifo_block_count) cmsis_dap_swd_read_process(cmsis_dap_handle, 0); cmsis_dap_swd_write_from_queue(cmsis_dap_handle); while (cmsis_dap_handle->pending_fifo_block_count) cmsis_dap_swd_read_process(cmsis_dap_handle, LIBUSB_TIMEOUT_MS); cmsis_dap_handle->pending_fifo_put_idx = 0; cmsis_dap_handle->pending_fifo_get_idx = 0; int retval = queued_retval; queued_retval = ERROR_OK; return retval; } static unsigned int cmsis_dap_tfer_cmd_size(unsigned int write_count, unsigned int read_count, bool block_tfer) { unsigned int size; if (block_tfer) { size = 5; /* DAP_TransferBlock header */ size += write_count * 4; /* data */ } else { size = 3; /* DAP_Transfer header */ size += write_count * (1 + 4); /* DAP register + data */ size += read_count; /* DAP register */ } return size; } static unsigned int cmsis_dap_tfer_resp_size(unsigned int write_count, unsigned int read_count, bool block_tfer) { unsigned int size; if (block_tfer) size = 4; /* DAP_TransferBlock response header */ else size = 3; /* DAP_Transfer response header */ size += read_count * 4; /* data */ return size; } static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) { /* Compute sizes of the DAP Transfer command and the expected response * for all queued and this operation */ bool targetsel_cmd = swd_cmd(false, false, DP_TARGETSEL) == cmd; unsigned int write_count = cmsis_dap_handle->write_count; unsigned int read_count = cmsis_dap_handle->read_count; bool block_cmd; if (write_count + read_count < CMD_DAP_TFER_BLOCK_MIN_OPS) block_cmd = false; else block_cmd = !cmsis_dap_handle->swd_cmds_differ && cmd == cmsis_dap_handle->common_swd_cmd; if (cmd & SWD_CMD_RNW) read_count++; else write_count++; unsigned int cmd_size = cmsis_dap_tfer_cmd_size(write_count, read_count, block_cmd); unsigned int resp_size = cmsis_dap_tfer_resp_size(write_count, read_count, block_cmd); unsigned int max_transfer_count = block_cmd ? 65535 : 255; /* Does the DAP Transfer command and the expected response fit into one packet? * Run the queue also before a targetsel - it cannot be queued */ if (cmd_size > tfer_max_command_size || resp_size > tfer_max_response_size || targetsel_cmd || write_count + read_count > max_transfer_count) { if (cmsis_dap_handle->pending_fifo_block_count) cmsis_dap_swd_read_process(cmsis_dap_handle, 0); /* Not enough room in the queue. Run the queue. */ cmsis_dap_swd_write_from_queue(cmsis_dap_handle); if (cmsis_dap_handle->pending_fifo_block_count >= cmsis_dap_handle->packet_count) cmsis_dap_swd_read_process(cmsis_dap_handle, LIBUSB_TIMEOUT_MS); } assert(cmsis_dap_handle->pending_fifo[cmsis_dap_handle->pending_fifo_put_idx].transfer_count < pending_queue_len); if (queued_retval != ERROR_OK) return; if (targetsel_cmd) { cmsis_dap_metacmd_targetsel(data); return; } struct pending_request_block *block = &cmsis_dap_handle->pending_fifo[cmsis_dap_handle->pending_fifo_put_idx]; struct pending_transfer_result *transfer = &(block->transfers[block->transfer_count]); transfer->data = data; transfer->cmd = cmd; if (block->transfer_count == 0) { cmsis_dap_handle->swd_cmds_differ = false; cmsis_dap_handle->common_swd_cmd = cmd; } else if (cmd != cmsis_dap_handle->common_swd_cmd) { cmsis_dap_handle->swd_cmds_differ = true; } if (cmd & SWD_CMD_RNW) { /* Queue a read transaction */ transfer->buffer = dst; cmsis_dap_handle->read_count++; } else { cmsis_dap_handle->write_count++; } block->transfer_count++; } static void cmsis_dap_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { assert(!(cmd & SWD_CMD_RNW)); cmsis_dap_swd_queue_cmd(cmd, NULL, value); } static void cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { assert(cmd & SWD_CMD_RNW); cmsis_dap_swd_queue_cmd(cmd, value, 0); } static int cmsis_dap_get_serial_info(void) { uint8_t *data; int retval = cmsis_dap_cmd_dap_info(INFO_ID_SERNUM, &data); if (retval != ERROR_OK) return retval; if (data[0]) /* strlen */ LOG_INFO("CMSIS-DAP: Serial# = %s", &data[1]); return ERROR_OK; } static int cmsis_dap_get_version_info(void) { uint8_t *data; /* INFO_ID_FW_VER - string */ int retval = cmsis_dap_cmd_dap_info(INFO_ID_FW_VER, &data); if (retval != ERROR_OK) return retval; if (data[0]) /* strlen */ LOG_INFO("CMSIS-DAP: FW Version = %s", &data[1]); return ERROR_OK; } static int cmsis_dap_get_caps_info(void) { uint8_t *data; /* INFO_ID_CAPS - byte */ int retval = cmsis_dap_cmd_dap_info(INFO_ID_CAPS, &data); if (retval != ERROR_OK) return retval; if (data[0] == 1 || data[0] == 2) { uint16_t caps = data[1]; if (data[0] == 2) caps |= (uint16_t)data[2] << 8; cmsis_dap_handle->caps = caps; for (unsigned int i = 0; i < INFO_CAPS__NUM_CAPS; ++i) { if (caps & BIT(i)) LOG_INFO("CMSIS-DAP: %s", info_caps_str[i]); } } return ERROR_OK; } static int cmsis_dap_get_swo_buf_sz(uint32_t *swo_buf_sz) { uint8_t *data; /* INFO_ID_SWO_BUF_SZ - word */ int retval = cmsis_dap_cmd_dap_info(INFO_ID_SWO_BUF_SZ, &data); if (retval != ERROR_OK) return retval; if (data[0] != 4) return ERROR_FAIL; *swo_buf_sz = le_to_h_u32(&data[1]); LOG_INFO("CMSIS-DAP: SWO Trace Buffer Size = %u bytes", *swo_buf_sz); return ERROR_OK; } static int cmsis_dap_get_status(void) { uint8_t d; int retval = cmsis_dap_cmd_dap_swj_pins(0, 0, 0, &d); if (retval == ERROR_OK) { LOG_INFO("SWCLK/TCK = %d SWDIO/TMS = %d TDI = %d TDO = %d nTRST = %d nRESET = %d", (d & SWJ_PIN_TCK) ? 1 : 0, (d & SWJ_PIN_TMS) ? 1 : 0, (d & SWJ_PIN_TDI) ? 1 : 0, (d & SWJ_PIN_TDO) ? 1 : 0, (d & SWJ_PIN_TRST) ? 1 : 0, (d & SWJ_PIN_SRST) ? 1 : 0); } return retval; } static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq) { const uint8_t *s; unsigned int s_len; int retval; if (seq != LINE_RESET && (output_pins & (SWJ_PIN_SRST | SWJ_PIN_TRST)) == (SWJ_PIN_SRST | SWJ_PIN_TRST)) { /* Following workaround deasserts reset on most adapters. * Do not reconnect if a reset line is active! * Reconnecting would break connecting under reset. */ /* First disconnect before connecting, Atmel EDBG needs it for SAMD/R/L/C */ cmsis_dap_cmd_dap_disconnect(); /* When we are reconnecting, DAP_Connect needs to be rerun, at * least on Keil ULINK-ME */ retval = cmsis_dap_cmd_dap_connect(CONNECT_SWD); if (retval != ERROR_OK) return retval; } switch (seq) { case LINE_RESET: LOG_DEBUG_IO("SWD line reset"); s = swd_seq_line_reset; s_len = swd_seq_line_reset_len; break; case JTAG_TO_SWD: LOG_DEBUG("JTAG-to-SWD"); s = swd_seq_jtag_to_swd; s_len = swd_seq_jtag_to_swd_len; break; case JTAG_TO_DORMANT: LOG_DEBUG("JTAG-to-DORMANT"); s = swd_seq_jtag_to_dormant; s_len = swd_seq_jtag_to_dormant_len; break; case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); s = swd_seq_swd_to_jtag; s_len = swd_seq_swd_to_jtag_len; break; case SWD_TO_DORMANT: LOG_DEBUG("SWD-to-DORMANT"); s = swd_seq_swd_to_dormant; s_len = swd_seq_swd_to_dormant_len; break; case DORMANT_TO_SWD: LOG_DEBUG("DORMANT-to-SWD"); s = swd_seq_dormant_to_swd; s_len = swd_seq_dormant_to_swd_len; break; case DORMANT_TO_JTAG: LOG_DEBUG("DORMANT-to-JTAG"); s = swd_seq_dormant_to_jtag; s_len = swd_seq_dormant_to_jtag_len; break; default: LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; } retval = cmsis_dap_cmd_dap_swj_sequence(s_len, s); if (retval != ERROR_OK) return retval; /* Atmel EDBG needs renew clock setting after SWJ_Sequence * otherwise default frequency is used */ return cmsis_dap_cmd_dap_swj_clock(adapter_get_speed_khz()); } static int cmsis_dap_swd_open(void) { if (!(cmsis_dap_handle->caps & INFO_CAPS_SWD)) { LOG_ERROR("CMSIS-DAP: SWD not supported"); return ERROR_JTAG_DEVICE_ERROR; } int retval = cmsis_dap_cmd_dap_connect(CONNECT_SWD); if (retval != ERROR_OK) return retval; /* Add more setup here.??... */ LOG_INFO("CMSIS-DAP: Interface Initialised (SWD)"); return ERROR_OK; } static int cmsis_dap_init(void) { uint8_t *data; int retval = cmsis_dap_open(); if (retval != ERROR_OK) return retval; cmsis_dap_flush_read(cmsis_dap_handle); retval = cmsis_dap_get_caps_info(); if (retval != ERROR_OK) return retval; retval = cmsis_dap_get_version_info(); if (retval != ERROR_OK) return retval; retval = cmsis_dap_get_serial_info(); if (retval != ERROR_OK) return retval; if (swd_mode) { retval = cmsis_dap_swd_open(); if (retval != ERROR_OK) return retval; } else { /* Connect in JTAG mode */ if (!(cmsis_dap_handle->caps & INFO_CAPS_JTAG)) { LOG_ERROR("CMSIS-DAP: JTAG not supported"); return ERROR_JTAG_DEVICE_ERROR; } retval = cmsis_dap_cmd_dap_connect(CONNECT_JTAG); if (retval != ERROR_OK) return retval; LOG_INFO("CMSIS-DAP: Interface Initialised (JTAG)"); } /* Be conservative and suppress submitting multiple HID requests * until we get packet count info from the adaptor */ cmsis_dap_handle->packet_count = 1; /* INFO_ID_PKT_SZ - short */ retval = cmsis_dap_cmd_dap_info(INFO_ID_PKT_SZ, &data); if (retval != ERROR_OK) goto init_err; if (data[0] == 2) { /* short */ uint16_t pkt_sz = data[1] + (data[2] << 8); if (pkt_sz != cmsis_dap_handle->packet_size) { free(cmsis_dap_handle->packet_buffer); retval = cmsis_dap_handle->backend->packet_buffer_alloc(cmsis_dap_handle, pkt_sz); if (retval != ERROR_OK) goto init_err; LOG_DEBUG("CMSIS-DAP: Packet Size = %" PRIu16, pkt_sz); } } /* Maximal number of transfers which fit to one packet: * Limited by response size: 3 bytes of response header + 4 per read * Plus writes to full command size: 3 bytes cmd header + 1 per read + 5 per write */ tfer_max_command_size = cmsis_dap_handle->packet_usable_size; tfer_max_response_size = cmsis_dap_handle->packet_usable_size; unsigned int max_reads = tfer_max_response_size / 4; pending_queue_len = max_reads + (tfer_max_command_size - max_reads) / 5; cmsis_dap_handle->write_count = 0; cmsis_dap_handle->read_count = 0; /* INFO_ID_PKT_CNT - byte */ retval = cmsis_dap_cmd_dap_info(INFO_ID_PKT_CNT, &data); if (retval != ERROR_OK) goto init_err; if (data[0] == 1) { /* byte */ unsigned int pkt_cnt = data[1]; if (pkt_cnt > 1) cmsis_dap_handle->packet_count = MIN(MAX_PENDING_REQUESTS, pkt_cnt); LOG_DEBUG("CMSIS-DAP: Packet Count = %u", pkt_cnt); } LOG_DEBUG("Allocating FIFO for %u pending packets", cmsis_dap_handle->packet_count); for (unsigned int i = 0; i < cmsis_dap_handle->packet_count; i++) { cmsis_dap_handle->pending_fifo[i].transfers = malloc(pending_queue_len * sizeof(struct pending_transfer_result)); if (!cmsis_dap_handle->pending_fifo[i].transfers) { LOG_ERROR("Unable to allocate memory for CMSIS-DAP queue"); retval = ERROR_FAIL; goto init_err; } } /* Intentionally not checked for error, just logs an info message * not vital for further debugging */ (void)cmsis_dap_get_status(); /* Now try to connect to the target * TODO: This is all SWD only @ present */ retval = cmsis_dap_cmd_dap_swj_clock(adapter_get_speed_khz()); if (retval != ERROR_OK) goto init_err; /* Ask CMSIS-DAP to automatically retry on receiving WAIT for * up to 64 times. This must be changed to 0 if sticky * overrun detection is enabled. */ retval = cmsis_dap_cmd_dap_tfer_configure(0, 64, 0); if (retval != ERROR_OK) goto init_err; if (swd_mode) { /* Data Phase (bit 2) must be set to 1 if sticky overrun * detection is enabled */ retval = cmsis_dap_cmd_dap_swd_configure(0); /* 1 TRN, no Data Phase */ if (retval != ERROR_OK) goto init_err; } /* Both LEDs on */ /* Intentionally not checked for error, debugging will work * without LEDs */ (void)cmsis_dap_cmd_dap_led(LED_ID_CONNECT, LED_ON); (void)cmsis_dap_cmd_dap_led(LED_ID_RUN, LED_ON); /* support connecting with srst asserted */ enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) { retval = cmsis_dap_cmd_dap_swj_pins(0, SWJ_PIN_SRST, 0, NULL); if (retval != ERROR_OK) goto init_err; LOG_INFO("Connecting under reset"); } } LOG_INFO("CMSIS-DAP: Interface ready"); return ERROR_OK; init_err: cmsis_dap_quit(); return retval; } static int cmsis_dap_swd_init(void) { swd_mode = true; return ERROR_OK; } static int cmsis_dap_quit(void) { cmsis_dap_cmd_dap_disconnect(); /* Both LEDs off */ cmsis_dap_cmd_dap_led(LED_ID_RUN, LED_OFF); cmsis_dap_cmd_dap_led(LED_ID_CONNECT, LED_OFF); cmsis_dap_close(cmsis_dap_handle); return ERROR_OK; } static int cmsis_dap_reset(int trst, int srst) { /* Set both TRST and SRST even if they're not enabled as * there's no way to tristate them */ output_pins = 0; if (!srst) output_pins |= SWJ_PIN_SRST; if (!trst) output_pins |= SWJ_PIN_TRST; int retval = cmsis_dap_cmd_dap_swj_pins(output_pins, SWJ_PIN_TRST | SWJ_PIN_SRST, 0, NULL); if (retval != ERROR_OK) LOG_ERROR("CMSIS-DAP: Interface reset failed"); return retval; } static void cmsis_dap_execute_sleep(struct jtag_command *cmd) { #if 0 int retval = cmsis_dap_cmd_dap_delay(cmd->cmd.sleep->us); if (retval != ERROR_OK) #endif jtag_sleep(cmd->cmd.sleep->us); } /* Set TMS high for five TCK clocks, to move the TAP to the Test-Logic-Reset state */ static int cmsis_dap_execute_tlr_reset(struct jtag_command *cmd) { LOG_INFO("cmsis-dap JTAG TLR_RESET"); uint8_t seq = 0xff; int retval = cmsis_dap_cmd_dap_swj_sequence(8, &seq); if (retval == ERROR_OK) tap_set_state(TAP_RESET); return retval; } /* Set new end state */ static void cmsis_dap_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } #ifdef SPRINT_BINARY static void sprint_binary(char *s, const uint8_t *buf, unsigned int offset, unsigned int len) { if (!len) return; /* buf = { 0x18 } len=5 should result in: 11000 buf = { 0xff 0x18 } len=13 should result in: 11111111 11000 buf = { 0xc0 0x18 } offset=3 len=10 should result in: 11000 11000 i=3 there means i/8 = 0 so c = 0xFF, and */ for (unsigned int i = offset; i < offset + len; ++i) { uint8_t c = buf[i / 8], mask = 1 << (i % 8); if ((i != offset) && !(i % 8)) putchar(' '); *s++ = (c & mask) ? '1' : '0'; } *s = 0; } #endif #ifdef CMSIS_DAP_JTAG_DEBUG static void debug_parse_cmsis_buf(const uint8_t *cmd, int cmdlen) { /* cmd is a usb packet to go to the cmsis-dap interface */ printf("cmsis-dap buffer (%d b): ", cmdlen); for (int i = 0; i < cmdlen; ++i) printf(" %02x", cmd[i]); printf("\n"); switch (cmd[0]) { case CMD_DAP_JTAG_SEQ: { printf("cmsis-dap jtag sequence command %02x (n=%d)\n", cmd[0], cmd[1]); /* * #1 = number of sequences * #2 = sequence info 1 * #3...4+n_bytes-1 = sequence 1 * #4+n_bytes = sequence info 2 * #5+n_bytes = sequence 2 (single bit) */ int pos = 2; for (int seq = 0; seq < cmd[1]; ++seq) { uint8_t info = cmd[pos++]; int len = info & DAP_JTAG_SEQ_TCK; if (len == 0) len = 64; printf(" sequence %d starting %d: info %02x (len=%d tms=%d read_tdo=%d): ", seq, pos, info, len, info & DAP_JTAG_SEQ_TMS, info & DAP_JTAG_SEQ_TDO); for (int i = 0; i < DIV_ROUND_UP(len, 8); ++i) printf(" %02x", cmd[pos+i]); pos += DIV_ROUND_UP(len, 8); printf("\n"); } if (pos != cmdlen) { printf("BUFFER LENGTH MISMATCH looks like %d but %d specified", pos, cmdlen); exit(-1); } break; } default: LOG_DEBUG("unknown cmsis-dap command %02x", cmd[1]); break; } } #endif static void cmsis_dap_flush(void) { if (!queued_seq_count) return; LOG_DEBUG_IO("Flushing %d queued sequences (%d bytes) with %d pending scan results to capture", queued_seq_count, queued_seq_buf_end, pending_scan_result_count); /* prepare CMSIS-DAP packet */ uint8_t *command = cmsis_dap_handle->command; command[0] = CMD_DAP_JTAG_SEQ; command[1] = queued_seq_count; memcpy(&command[2], queued_seq_buf, queued_seq_buf_end); #ifdef CMSIS_DAP_JTAG_DEBUG debug_parse_cmsis_buf(command, queued_seq_buf_end + 2); #endif /* send command to USB device */ int retval = cmsis_dap_xfer(cmsis_dap_handle, queued_seq_buf_end + 2); uint8_t *resp = cmsis_dap_handle->response; if (retval != ERROR_OK || resp[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_DAP_JTAG_SEQ failed."); exit(-1); } #ifdef CMSIS_DAP_JTAG_DEBUG LOG_DEBUG_IO("USB response buf:"); for (int c = 0; c < queued_seq_buf_end + 3; ++c) printf("%02X ", resp[c]); printf("\n"); #endif /* copy scan results into client buffers */ for (int i = 0; i < pending_scan_result_count; ++i) { struct pending_scan_result *scan = &pending_scan_results[i]; LOG_DEBUG_IO("Copying pending_scan_result %d/%d: %d bits from byte %d -> buffer + %d bits", i, pending_scan_result_count, scan->length, scan->first + 2, scan->buffer_offset); #ifdef CMSIS_DAP_JTAG_DEBUG for (uint32_t b = 0; b < DIV_ROUND_UP(scan->length, 8); ++b) printf("%02X ", resp[2+scan->first+b]); printf("\n"); #endif bit_copy(scan->buffer, scan->buffer_offset, &resp[2 + scan->first], 0, scan->length); } /* reset */ queued_seq_count = 0; queued_seq_buf_end = 0; queued_seq_tdo_ptr = 0; pending_scan_result_count = 0; } /* queue a sequence of bits to clock out TDI / in TDO, executing if the buffer is full. * * sequence=NULL means clock out zeros on TDI * tdo_buffer=NULL means don't capture TDO */ static void cmsis_dap_add_jtag_sequence(unsigned int s_len, const uint8_t *sequence, unsigned int s_offset, bool tms, uint8_t *tdo_buffer, unsigned int tdo_buffer_offset) { LOG_DEBUG_IO("[at %d] %u bits, tms %s, seq offset %u, tdo buf %p, tdo offset %u", queued_seq_buf_end, s_len, tms ? "HIGH" : "LOW", s_offset, tdo_buffer, tdo_buffer_offset); if (s_len == 0) return; if (s_len > 64) { LOG_DEBUG_IO("START JTAG SEQ SPLIT"); for (unsigned int offset = 0; offset < s_len; offset += 64) { unsigned int len = s_len - offset; if (len > 64) len = 64; LOG_DEBUG_IO("Splitting long jtag sequence: %u-bit chunk starting at offset %u", len, offset); cmsis_dap_add_jtag_sequence( len, sequence, s_offset + offset, tms, tdo_buffer, !tdo_buffer ? 0 : (tdo_buffer_offset + offset) ); } LOG_DEBUG_IO("END JTAG SEQ SPLIT"); return; } unsigned int cmd_len = 1 + DIV_ROUND_UP(s_len, 8); if (queued_seq_count >= 255 || queued_seq_buf_end + cmd_len > QUEUED_SEQ_BUF_LEN) /* empty out the buffer */ cmsis_dap_flush(); ++queued_seq_count; /* control byte */ queued_seq_buf[queued_seq_buf_end] = (tms ? DAP_JTAG_SEQ_TMS : 0) | (tdo_buffer ? DAP_JTAG_SEQ_TDO : 0) | (s_len == 64 ? 0 : s_len); if (sequence) bit_copy(&queued_seq_buf[queued_seq_buf_end + 1], 0, sequence, s_offset, s_len); else memset(&queued_seq_buf[queued_seq_buf_end + 1], 0, DIV_ROUND_UP(s_len, 8)); queued_seq_buf_end += cmd_len; if (tdo_buffer) { struct pending_scan_result *scan = &pending_scan_results[pending_scan_result_count++]; scan->first = queued_seq_tdo_ptr; queued_seq_tdo_ptr += DIV_ROUND_UP(s_len, 8); scan->length = s_len; scan->buffer = tdo_buffer; scan->buffer_offset = tdo_buffer_offset; } } /* queue a sequence of bits to clock out TMS, executing if the buffer is full */ static void cmsis_dap_add_tms_sequence(const uint8_t *sequence, int s_len) { LOG_DEBUG_IO("%d bits: %02X", s_len, *sequence); /* we use a series of CMD_DAP_JTAG_SEQ commands to toggle TMS, because even though it seems ridiculously inefficient, it allows us to combine TMS and scan sequences into the same USB packet. */ /* TODO: combine runs of the same tms value */ for (int i = 0; i < s_len; ++i) { bool bit = (sequence[i / 8] & (1 << (i % 8))) != 0; cmsis_dap_add_jtag_sequence(1, NULL, 0, bit, NULL, 0); } } /* Move to the end state by queuing a sequence to clock into TMS */ static void cmsis_dap_state_move(void) { uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); uint8_t tms_scan_bits = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); LOG_DEBUG_IO("state move from %s to %s: %d clocks, %02X on tms", tap_state_name(tap_get_state()), tap_state_name(tap_get_end_state()), tms_scan_bits, tms_scan); cmsis_dap_add_tms_sequence(&tms_scan, tms_scan_bits); tap_set_state(tap_get_end_state()); } /* Execute a JTAG scan operation by queueing TMS and TDI/TDO sequences */ static void cmsis_dap_execute_scan(struct jtag_command *cmd) { LOG_DEBUG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN", jtag_scan_type(cmd->cmd.scan)); /* Make sure there are no trailing fields with num_bits == 0, or the logic below will fail. */ while (cmd->cmd.scan->num_fields > 0 && cmd->cmd.scan->fields[cmd->cmd.scan->num_fields - 1].num_bits == 0) { cmd->cmd.scan->num_fields--; LOG_DEBUG("discarding trailing empty field"); } if (cmd->cmd.scan->num_fields == 0) { LOG_DEBUG("empty scan, doing nothing"); return; } if (cmd->cmd.scan->ir_scan) { if (tap_get_state() != TAP_IRSHIFT) { cmsis_dap_end_state(TAP_IRSHIFT); cmsis_dap_state_move(); } } else { if (tap_get_state() != TAP_DRSHIFT) { cmsis_dap_end_state(TAP_DRSHIFT); cmsis_dap_state_move(); } } cmsis_dap_end_state(cmd->cmd.scan->end_state); struct scan_field *field = cmd->cmd.scan->fields; unsigned scan_size = 0; for (int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) { scan_size += field->num_bits; LOG_DEBUG_IO("%s%s field %d/%d %d bits", field->in_value ? "in" : "", field->out_value ? "out" : "", i, cmd->cmd.scan->num_fields, field->num_bits); if (i == cmd->cmd.scan->num_fields - 1 && tap_get_state() != tap_get_end_state()) { LOG_DEBUG_IO("Last field and have to move out of SHIFT state"); /* Last field, and we're leaving IRSHIFT/DRSHIFT. Clock last bit during tap * movement. This last field can't have length zero, it was checked above. */ cmsis_dap_add_jtag_sequence( field->num_bits - 1, /* number of bits to clock */ field->out_value, /* output sequence */ 0, /* output offset */ false, /* TMS low */ field->in_value, 0); /* Clock the last bit out, with TMS high */ uint8_t last_bit = 0; if (field->out_value) bit_copy(&last_bit, 0, field->out_value, field->num_bits - 1, 1); cmsis_dap_add_jtag_sequence( 1, &last_bit, 0, true, field->in_value, field->num_bits - 1); tap_set_state(tap_state_transition(tap_get_state(), 1)); /* Now clock one more cycle, with TMS low, to get us into a PAUSE state */ cmsis_dap_add_jtag_sequence( 1, &last_bit, 0, false, NULL, 0); tap_set_state(tap_state_transition(tap_get_state(), 0)); } else { LOG_DEBUG_IO("Internal field, staying in SHIFT state afterwards"); /* Clocking part of a sequence into DR or IR with TMS=0, leaving TMS=0 at the end so we can continue later */ cmsis_dap_add_jtag_sequence( field->num_bits, field->out_value, 0, false, field->in_value, 0); } } if (tap_get_state() != tap_get_end_state()) { cmsis_dap_end_state(tap_get_end_state()); cmsis_dap_state_move(); } LOG_DEBUG_IO("%s scan, %i bits, end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, tap_state_name(tap_get_end_state())); } static void cmsis_dap_pathmove(int num_states, tap_state_t *path) { uint8_t tms0 = 0x00; uint8_t tms1 = 0xff; for (int i = 0; i < num_states; i++) { if (path[i] == tap_state_transition(tap_get_state(), false)) cmsis_dap_add_tms_sequence(&tms0, 1); else if (path[i] == tap_state_transition(tap_get_state(), true)) cmsis_dap_add_tms_sequence(&tms1, 1); else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.", tap_state_name(tap_get_state()), tap_state_name(path[i])); exit(-1); } tap_set_state(path[i]); } cmsis_dap_end_state(tap_get_state()); } static void cmsis_dap_execute_pathmove(struct jtag_command *cmd) { LOG_DEBUG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); cmsis_dap_pathmove(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); } static void cmsis_dap_stableclocks(int num_cycles) { uint8_t tms = tap_get_state() == TAP_RESET; /* TODO: Perform optimizations? */ /* Execute num_cycles. */ for (int i = 0; i < num_cycles; i++) cmsis_dap_add_tms_sequence(&tms, 1); } static void cmsis_dap_runtest(int num_cycles) { tap_state_t saved_end_state = tap_get_end_state(); /* Only do a state_move when we're not already in IDLE. */ if (tap_get_state() != TAP_IDLE) { cmsis_dap_end_state(TAP_IDLE); cmsis_dap_state_move(); } cmsis_dap_stableclocks(num_cycles); /* Finish in end_state. */ cmsis_dap_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) cmsis_dap_state_move(); } static void cmsis_dap_execute_runtest(struct jtag_command *cmd) { LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); cmsis_dap_end_state(cmd->cmd.runtest->end_state); cmsis_dap_runtest(cmd->cmd.runtest->num_cycles); } static void cmsis_dap_execute_stableclocks(struct jtag_command *cmd) { LOG_DEBUG_IO("stableclocks %i cycles", cmd->cmd.runtest->num_cycles); cmsis_dap_stableclocks(cmd->cmd.runtest->num_cycles); } static void cmsis_dap_execute_tms(struct jtag_command *cmd) { LOG_DEBUG_IO("TMS: %d bits", cmd->cmd.tms->num_bits); cmsis_dap_cmd_dap_swj_sequence(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits); } /* TODO: Is there need to call cmsis_dap_flush() for the JTAG_PATHMOVE, * JTAG_RUNTEST, JTAG_STABLECLOCKS? */ static void cmsis_dap_execute_command(struct jtag_command *cmd) { switch (cmd->type) { case JTAG_SLEEP: cmsis_dap_flush(); cmsis_dap_execute_sleep(cmd); break; case JTAG_TLR_RESET: cmsis_dap_flush(); cmsis_dap_execute_tlr_reset(cmd); break; case JTAG_SCAN: cmsis_dap_execute_scan(cmd); break; case JTAG_PATHMOVE: cmsis_dap_execute_pathmove(cmd); break; case JTAG_RUNTEST: cmsis_dap_execute_runtest(cmd); break; case JTAG_STABLECLOCKS: cmsis_dap_execute_stableclocks(cmd); break; case JTAG_TMS: cmsis_dap_execute_tms(cmd); break; default: LOG_ERROR("BUG: unknown JTAG command type 0x%X encountered", cmd->type); exit(-1); } } static int cmsis_dap_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; while (cmd) { cmsis_dap_execute_command(cmd); cmd = cmd->next; } cmsis_dap_flush(); return ERROR_OK; } static int cmsis_dap_speed(int speed) { if (speed == 0) { LOG_ERROR("RTCK not supported. Set nonzero \"adapter speed\"."); return ERROR_JTAG_NOT_IMPLEMENTED; } return cmsis_dap_cmd_dap_swj_clock(speed); } static int cmsis_dap_speed_div(int speed, int *khz) { *khz = speed; return ERROR_OK; } static int cmsis_dap_khz(int khz, int *jtag_speed) { *jtag_speed = khz; return ERROR_OK; } static bool calculate_swo_prescaler(unsigned int traceclkin_freq, uint32_t trace_freq, uint16_t *prescaler) { unsigned int presc = (traceclkin_freq + trace_freq / 2) / trace_freq; if (presc == 0 || presc > TPIU_ACPR_MAX_SWOSCALER + 1) return false; /* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */ unsigned int max_deviation = (traceclkin_freq * 3) / 100; if (presc * trace_freq < traceclkin_freq - max_deviation || presc * trace_freq > traceclkin_freq + max_deviation) return false; *prescaler = presc; return true; } /** * @see adapter_driver::config_trace */ static int cmsis_dap_config_trace( bool trace_enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *swo_freq, unsigned int traceclkin_hz, uint16_t *swo_prescaler) { int retval; if (!trace_enabled) { if (cmsis_dap_handle->trace_enabled) { retval = cmsis_dap_cmd_dap_swo_control(DAP_SWO_CONTROL_STOP); if (retval != ERROR_OK) { LOG_ERROR("Failed to disable the SWO-trace."); return retval; } } cmsis_dap_handle->trace_enabled = false; LOG_INFO("SWO-trace disabled."); return ERROR_OK; } if (!(cmsis_dap_handle->caps & INFO_CAPS_SWO_UART) && !(cmsis_dap_handle->caps & INFO_CAPS_SWO_MANCHESTER)) { LOG_ERROR("SWO-trace is not supported by the device."); return ERROR_FAIL; } uint8_t swo_mode; if (pin_protocol == TPIU_PIN_PROTOCOL_ASYNC_UART && (cmsis_dap_handle->caps & INFO_CAPS_SWO_UART)) { swo_mode = DAP_SWO_MODE_UART; } else if (pin_protocol == TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER && (cmsis_dap_handle->caps & INFO_CAPS_SWO_MANCHESTER)) { swo_mode = DAP_SWO_MODE_MANCHESTER; } else { LOG_ERROR("Selected pin protocol is not supported."); return ERROR_FAIL; } if (*swo_freq == 0) { LOG_INFO("SWO-trace frequency autodetection not implemented."); return ERROR_FAIL; } retval = cmsis_dap_cmd_dap_swo_control(DAP_SWO_CONTROL_STOP); if (retval != ERROR_OK) return retval; cmsis_dap_handle->trace_enabled = false; retval = cmsis_dap_get_swo_buf_sz(&cmsis_dap_handle->swo_buf_sz); if (retval != ERROR_OK) return retval; retval = cmsis_dap_cmd_dap_swo_transport(DAP_SWO_TRANSPORT_DATA); if (retval != ERROR_OK) return retval; retval = cmsis_dap_cmd_dap_swo_mode(swo_mode); if (retval != ERROR_OK) return retval; retval = cmsis_dap_cmd_dap_swo_baudrate(*swo_freq, swo_freq); if (retval != ERROR_OK) return retval; if (!calculate_swo_prescaler(traceclkin_hz, *swo_freq, swo_prescaler)) { LOG_ERROR("SWO frequency is not suitable. Please choose a " "different frequency or use auto-detection."); return ERROR_FAIL; } LOG_INFO("SWO frequency: %u Hz.", *swo_freq); LOG_INFO("SWO prescaler: %u.", *swo_prescaler); retval = cmsis_dap_cmd_dap_swo_control(DAP_SWO_CONTROL_START); if (retval != ERROR_OK) return retval; cmsis_dap_handle->trace_enabled = true; return ERROR_OK; } /** * @see adapter_driver::poll_trace */ static int cmsis_dap_poll_trace(uint8_t *buf, size_t *size) { uint8_t trace_status; size_t trace_count; if (!cmsis_dap_handle->trace_enabled) { *size = 0; return ERROR_OK; } int retval = cmsis_dap_cmd_dap_swo_status(&trace_status, &trace_count); if (retval != ERROR_OK) return retval; if ((trace_status & DAP_SWO_STATUS_CAPTURE_MASK) != DAP_SWO_STATUS_CAPTURE_ACTIVE) return ERROR_FAIL; *size = trace_count < *size ? trace_count : *size; size_t read_so_far = 0; do { size_t rb = 0; uint32_t packet_size = cmsis_dap_handle->packet_size - 4 /*data-reply*/; uint32_t remaining = *size - read_so_far; if (remaining < packet_size) packet_size = remaining; retval = cmsis_dap_cmd_dap_swo_data( packet_size, &trace_status, &rb, &buf[read_so_far]); if (retval != ERROR_OK) return retval; if ((trace_status & DAP_SWO_STATUS_CAPTURE_MASK) != DAP_SWO_STATUS_CAPTURE_ACTIVE) return ERROR_FAIL; read_so_far += rb; } while (read_so_far < *size); return ERROR_OK; } COMMAND_HANDLER(cmsis_dap_handle_info_command) { if (cmsis_dap_get_version_info() == ERROR_OK) cmsis_dap_get_status(); return ERROR_OK; } COMMAND_HANDLER(cmsis_dap_handle_cmd_command) { uint8_t *command = cmsis_dap_handle->command; for (unsigned i = 0; i < CMD_ARGC; i++) COMMAND_PARSE_NUMBER(u8, CMD_ARGV[i], command[i]); int retval = cmsis_dap_xfer(cmsis_dap_handle, CMD_ARGC); if (retval != ERROR_OK) { LOG_ERROR("CMSIS-DAP command failed."); return ERROR_JTAG_DEVICE_ERROR; } uint8_t *resp = cmsis_dap_handle->response; LOG_INFO("Returned data %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8, resp[1], resp[2], resp[3], resp[4]); return ERROR_OK; } COMMAND_HANDLER(cmsis_dap_handle_vid_pid_command) { if (CMD_ARGC > MAX_USB_IDS * 2) { LOG_WARNING("ignoring extra IDs in cmsis_dap_vid_pid " "(maximum is %d pairs)", MAX_USB_IDS); CMD_ARGC = MAX_USB_IDS * 2; } if (CMD_ARGC < 2 || (CMD_ARGC & 1)) { LOG_WARNING("incomplete cmsis_dap_vid_pid configuration directive"); if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; /* remove the incomplete trailing id */ CMD_ARGC -= 1; } unsigned i; for (i = 0; i < CMD_ARGC; i += 2) { COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], cmsis_dap_vid[i >> 1]); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], cmsis_dap_pid[i >> 1]); } /* * Explicitly terminate, in case there are multiples instances of * cmsis_dap_vid_pid. */ cmsis_dap_vid[i >> 1] = cmsis_dap_pid[i >> 1] = 0; return ERROR_OK; } COMMAND_HANDLER(cmsis_dap_handle_backend_command) { if (CMD_ARGC == 1) { if (strcmp(CMD_ARGV[0], "auto") == 0) { cmsis_dap_backend = -1; /* autoselect */ } else { for (unsigned int i = 0; i < ARRAY_SIZE(cmsis_dap_backends); i++) { if (strcasecmp(cmsis_dap_backends[i]->name, CMD_ARGV[0]) == 0) { cmsis_dap_backend = i; return ERROR_OK; } } LOG_ERROR("invalid backend argument to cmsis_dap_backend <backend>"); } } else { LOG_ERROR("expected exactly one argument to cmsis_dap_backend <backend>"); } return ERROR_OK; } static const struct command_registration cmsis_dap_subcommand_handlers[] = { { .name = "info", .handler = &cmsis_dap_handle_info_command, .mode = COMMAND_EXEC, .usage = "", .help = "show cmsis-dap info", }, { .name = "cmd", .handler = &cmsis_dap_handle_cmd_command, .mode = COMMAND_EXEC, .usage = "", .help = "issue cmsis-dap command", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration cmsis_dap_command_handlers[] = { { .name = "cmsis-dap", .mode = COMMAND_ANY, .help = "perform CMSIS-DAP management", .usage = "<cmd>", .chain = cmsis_dap_subcommand_handlers, }, { .name = "cmsis_dap_vid_pid", .handler = &cmsis_dap_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "the vendor ID and product ID of the CMSIS-DAP device", .usage = "(vid pid)*", }, { .name = "cmsis_dap_backend", .handler = &cmsis_dap_handle_backend_command, .mode = COMMAND_CONFIG, .help = "set the communication backend to use (USB bulk or HID).", .usage = "(auto | usb_bulk | hid)", }, #if BUILD_CMSIS_DAP_USB { .name = "cmsis_dap_usb", .chain = cmsis_dap_usb_subcommand_handlers, .mode = COMMAND_ANY, .help = "USB bulk backend-specific commands", .usage = "<cmd>", }, #endif COMMAND_REGISTRATION_DONE }; static const struct swd_driver cmsis_dap_swd_driver = { .init = cmsis_dap_swd_init, .switch_seq = cmsis_dap_swd_switch_seq, .read_reg = cmsis_dap_swd_read_reg, .write_reg = cmsis_dap_swd_write_reg, .run = cmsis_dap_swd_run_queue, }; static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL }; static struct jtag_interface cmsis_dap_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = cmsis_dap_execute_queue, }; struct adapter_driver cmsis_dap_adapter_driver = { .name = "cmsis-dap", .transports = cmsis_dap_transport, .commands = cmsis_dap_command_handlers, .init = cmsis_dap_init, .quit = cmsis_dap_quit, .reset = cmsis_dap_reset, .speed = cmsis_dap_speed, .khz = cmsis_dap_khz, .speed_div = cmsis_dap_speed_div, .config_trace = cmsis_dap_config_trace, .poll_trace = cmsis_dap_poll_trace, .jtag_ops = &cmsis_dap_interface, .swd_ops = &cmsis_dap_swd_driver, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/cmsis_dap.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef OPENOCD_JTAG_DRIVERS_CMSIS_DAP_H #define OPENOCD_JTAG_DRIVERS_CMSIS_DAP_H #include <stdint.h> struct cmsis_dap_backend; struct cmsis_dap_backend_data; struct pending_transfer_result { uint8_t cmd; uint32_t data; void *buffer; }; /* Up to MIN(packet_count, MAX_PENDING_REQUESTS) requests may be issued * until the first response arrives */ #define MAX_PENDING_REQUESTS 4 struct pending_request_block { struct pending_transfer_result *transfers; unsigned int transfer_count; uint8_t command; }; struct cmsis_dap { struct cmsis_dap_backend_data *bdata; const struct cmsis_dap_backend *backend; unsigned int packet_size; unsigned int packet_usable_size; unsigned int packet_buffer_size; uint8_t *packet_buffer; uint8_t *command; uint8_t *response; /* DP/AP register r/w operation counters used for checking the packet size * that would result from the queue run */ unsigned int write_count; unsigned int read_count; /* We can use DAP_TransferBlock only if all SWD operations in the packet * are either all writes or all reads and use the same DP/AP register. * The following variables keep track of it */ uint8_t common_swd_cmd; bool swd_cmds_differ; /* Pending requests are organized as a FIFO - circular buffer */ struct pending_request_block pending_fifo[MAX_PENDING_REQUESTS]; unsigned int packet_count; unsigned int pending_fifo_put_idx, pending_fifo_get_idx; unsigned int pending_fifo_block_count; uint16_t caps; uint8_t mode; uint32_t swo_buf_sz; bool trace_enabled; }; struct cmsis_dap_backend { const char *name; int (*open)(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], const char *serial); void (*close)(struct cmsis_dap *dap); int (*read)(struct cmsis_dap *dap, int timeout_ms); int (*write)(struct cmsis_dap *dap, int len, int timeout_ms); int (*packet_buffer_alloc)(struct cmsis_dap *dap, unsigned int pkt_sz); }; extern const struct cmsis_dap_backend cmsis_dap_hid_backend; extern const struct cmsis_dap_backend cmsis_dap_usb_backend; extern const struct command_registration cmsis_dap_usb_subcommand_handlers[]; #define REPORT_ID_SIZE 1 #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/cmsis_dap_usb_bulk.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2018 by Mickaël Thomas * * mickael9@gmail.com * * * * Copyright (C) 2016 by Maksym Hilliaka * * oter@frozen-team.com * * * * Copyright (C) 2016 by Phillip Pearson * * pp@myelin.co.nz * * * * Copyright (C) 2014 by Paul Fertser * * fercerpav@gmail.com * * * * Copyright (C) 2013 by mike brown * * mike@theshedworks.org.uk * * * * Copyright (C) 2013 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/system.h> #include <libusb.h> #include <helper/log.h> #include <helper/replacements.h> #include "cmsis_dap.h" struct cmsis_dap_backend_data { struct libusb_context *usb_ctx; struct libusb_device_handle *dev_handle; unsigned int ep_out; unsigned int ep_in; int interface; }; static int cmsis_dap_usb_interface = -1; static void cmsis_dap_usb_close(struct cmsis_dap *dap); static int cmsis_dap_usb_alloc(struct cmsis_dap *dap, unsigned int pkt_sz); static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], const char *serial) { int err; struct libusb_context *ctx; struct libusb_device **device_list; err = libusb_init(&ctx); if (err) { LOG_ERROR("libusb initialization failed: %s", libusb_strerror(err)); return ERROR_FAIL; } int num_devices = libusb_get_device_list(ctx, &device_list); if (num_devices < 0) { LOG_ERROR("could not enumerate USB devices: %s", libusb_strerror(num_devices)); libusb_exit(ctx); return ERROR_FAIL; } for (int i = 0; i < num_devices; i++) { struct libusb_device *dev = device_list[i]; struct libusb_device_descriptor dev_desc; err = libusb_get_device_descriptor(dev, &dev_desc); if (err) { LOG_ERROR("could not get device descriptor for device %d: %s", i, libusb_strerror(err)); continue; } /* Match VID/PID */ bool id_match = false; bool id_filter = vids[0] || pids[0]; for (int id = 0; vids[id] || pids[id]; id++) { id_match = !vids[id] || dev_desc.idVendor == vids[id]; id_match &= !pids[id] || dev_desc.idProduct == pids[id]; if (id_match) break; } if (id_filter && !id_match) continue; /* Don't continue if we asked for a serial number and the device doesn't have one */ if (dev_desc.iSerialNumber == 0 && serial && serial[0]) continue; struct libusb_device_handle *dev_handle = NULL; err = libusb_open(dev, &dev_handle); if (err) { /* It's to be expected that most USB devices can't be opened * so only report an error if it was explicitly selected */ if (id_filter) { LOG_ERROR("could not open device 0x%04x:0x%04x: %s", dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); } else { LOG_DEBUG("could not open device 0x%04x:0x%04x: %s", dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); } continue; } /* Match serial number */ bool serial_match = false; char dev_serial[256] = {0}; if (dev_desc.iSerialNumber > 0) { err = libusb_get_string_descriptor_ascii( dev_handle, dev_desc.iSerialNumber, (uint8_t *)dev_serial, sizeof(dev_serial)); if (err < 0) { const char *msg = "could not read serial number for device 0x%04x:0x%04x: %s"; if (serial) LOG_WARNING(msg, dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); else LOG_DEBUG(msg, dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); } else if (serial && strncmp(dev_serial, serial, sizeof(dev_serial)) == 0) { serial_match = true; } } if (serial && !serial_match) { libusb_close(dev_handle); continue; } /* Find the CMSIS-DAP string in product string */ bool cmsis_dap_in_product_str = false; char product_string[256] = {0}; if (dev_desc.iProduct > 0) { err = libusb_get_string_descriptor_ascii( dev_handle, dev_desc.iProduct, (uint8_t *)product_string, sizeof(product_string)); if (err < 0) { LOG_WARNING("could not read product string for device 0x%04x:0x%04x: %s", dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); } else if (strstr(product_string, "CMSIS-DAP")) { LOG_DEBUG("found product string of 0x%04x:0x%04x '%s'", dev_desc.idVendor, dev_desc.idProduct, product_string); cmsis_dap_in_product_str = true; } } bool device_identified_reliably = cmsis_dap_in_product_str || serial_match || id_match; /* Find the CMSIS-DAP interface */ for (int config = 0; config < dev_desc.bNumConfigurations; config++) { struct libusb_config_descriptor *config_desc; err = libusb_get_config_descriptor(dev, config, &config_desc); if (err) { LOG_ERROR("could not get configuration descriptor %d for device 0x%04x:0x%04x: %s", config, dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); continue; } LOG_DEBUG("enumerating interfaces of 0x%04x:0x%04x", dev_desc.idVendor, dev_desc.idProduct); int config_num = config_desc->bConfigurationValue; const struct libusb_interface_descriptor *intf_desc_candidate = NULL; const struct libusb_interface_descriptor *intf_desc_found = NULL; for (int interface = 0; interface < config_desc->bNumInterfaces; interface++) { const struct libusb_interface_descriptor *intf_desc = &config_desc->interface[interface].altsetting[0]; int interface_num = intf_desc->bInterfaceNumber; /* Skip this interface if another one was requested explicitly */ if (cmsis_dap_usb_interface != -1 && cmsis_dap_usb_interface != interface_num) continue; /* CMSIS-DAP v2 spec says: * * CMSIS-DAP with default V2 configuration uses WinUSB and is therefore faster. * Optionally support for streaming SWO trace is provided via an additional USB endpoint. * * The WinUSB configuration requires custom class support with the interface setting * Class Code: 0xFF (Vendor specific) * Subclass: 0x00 * Protocol code: 0x00 * * Depending on the configuration it uses the following USB endpoints which should be configured * in the interface descriptor in this order: * - Endpoint 1: Bulk Out – used for commands received from host PC. * - Endpoint 2: Bulk In – used for responses send to host PC. * - Endpoint 3: Bulk In (optional) – used for streaming SWO trace (if enabled with SWO_STREAM). */ /* Search for "CMSIS-DAP" in the interface string */ bool cmsis_dap_in_interface_str = false; if (intf_desc->iInterface != 0) { char interface_str[256] = {0}; err = libusb_get_string_descriptor_ascii( dev_handle, intf_desc->iInterface, (uint8_t *)interface_str, sizeof(interface_str)); if (err < 0) { LOG_DEBUG("could not read interface string %d for device 0x%04x:0x%04x: %s", intf_desc->iInterface, dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); } else if (strstr(interface_str, "CMSIS-DAP")) { cmsis_dap_in_interface_str = true; LOG_DEBUG("found interface %d string '%s'", interface_num, interface_str); } } /* Bypass the following check if this interface was explicitly requested. */ if (cmsis_dap_usb_interface == -1) { if (!cmsis_dap_in_product_str && !cmsis_dap_in_interface_str) continue; } /* check endpoints */ if (intf_desc->bNumEndpoints < 2) { LOG_DEBUG("skipping interface %d, has only %d endpoints", interface_num, intf_desc->bNumEndpoints); continue; } if ((intf_desc->endpoint[0].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK || (intf_desc->endpoint[0].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_OUT) { LOG_DEBUG("skipping interface %d, endpoint[0] is not bulk out", interface_num); continue; } if ((intf_desc->endpoint[1].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK || (intf_desc->endpoint[1].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_IN) { LOG_DEBUG("skipping interface %d, endpoint[1] is not bulk in", interface_num); continue; } /* We can rely on the interface is really CMSIS-DAP if * - we've seen CMSIS-DAP in the interface string * - config asked explicitly for an interface number * - the device has only one interface * The later two cases should be honored only if we know * we are on the right device */ bool intf_identified_reliably = cmsis_dap_in_interface_str || (device_identified_reliably && (cmsis_dap_usb_interface != -1 || config_desc->bNumInterfaces == 1)); if (intf_desc->bInterfaceClass != LIBUSB_CLASS_VENDOR_SPEC || intf_desc->bInterfaceSubClass != 0 || intf_desc->bInterfaceProtocol != 0) { /* If the interface is reliably identified * then we need not insist on setting USB class, subclass and protocol * exactly as the specification requires. * Just filter out the well known classes, mainly CDC and MSC. * At least KitProg3 uses class 0 contrary to the specification */ if (intf_identified_reliably && (intf_desc->bInterfaceClass == 0 || intf_desc->bInterfaceClass > 0x12)) { LOG_WARNING("Using CMSIS-DAPv2 interface %d with wrong class %" PRId8 " subclass %" PRId8 " or protocol %" PRId8, interface_num, intf_desc->bInterfaceClass, intf_desc->bInterfaceSubClass, intf_desc->bInterfaceProtocol); } else { LOG_DEBUG("skipping interface %d, class %" PRId8 " subclass %" PRId8 " protocol %" PRId8, interface_num, intf_desc->bInterfaceClass, intf_desc->bInterfaceSubClass, intf_desc->bInterfaceProtocol); continue; } } if (intf_identified_reliably) { /* That's the one! */ intf_desc_found = intf_desc; break; } if (!intf_desc_candidate && device_identified_reliably) { /* This interface looks suitable for CMSIS-DAP. Store the pointer to it * and keep searching for another one with CMSIS-DAP in interface string */ intf_desc_candidate = intf_desc; } } if (!intf_desc_found) { /* We were not able to identify reliably which interface is CMSIS-DAP. * Let's use the first suitable if we found one */ intf_desc_found = intf_desc_candidate; } if (!intf_desc_found) { libusb_free_config_descriptor(config_desc); continue; } /* We've chosen an interface, connect to it */ int interface_num = intf_desc_found->bInterfaceNumber; int packet_size = intf_desc_found->endpoint[0].wMaxPacketSize; int ep_out = intf_desc_found->endpoint[0].bEndpointAddress; int ep_in = intf_desc_found->endpoint[1].bEndpointAddress; libusb_free_config_descriptor(config_desc); libusb_free_device_list(device_list, true); LOG_INFO("Using CMSIS-DAPv2 interface with VID:PID=0x%04x:0x%04x, serial=%s", dev_desc.idVendor, dev_desc.idProduct, dev_serial); int current_config; err = libusb_get_configuration(dev_handle, ¤t_config); if (err) { LOG_ERROR("could not find current configuration: %s", libusb_strerror(err)); libusb_close(dev_handle); libusb_exit(ctx); return ERROR_FAIL; } if (config_num != current_config) { err = libusb_set_configuration(dev_handle, config_num); if (err) { LOG_ERROR("could not set configuration: %s", libusb_strerror(err)); libusb_close(dev_handle); libusb_exit(ctx); return ERROR_FAIL; } } err = libusb_claim_interface(dev_handle, interface_num); if (err) LOG_WARNING("could not claim interface: %s", libusb_strerror(err)); dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data)); if (!dap->bdata) { LOG_ERROR("unable to allocate memory"); libusb_release_interface(dev_handle, interface_num); libusb_close(dev_handle); libusb_exit(ctx); return ERROR_FAIL; } dap->bdata->usb_ctx = ctx; dap->bdata->dev_handle = dev_handle; dap->bdata->ep_out = ep_out; dap->bdata->ep_in = ep_in; dap->bdata->interface = interface_num; err = cmsis_dap_usb_alloc(dap, packet_size); if (err != ERROR_OK) cmsis_dap_usb_close(dap); return err; } libusb_close(dev_handle); } libusb_free_device_list(device_list, true); libusb_exit(ctx); return ERROR_FAIL; } static void cmsis_dap_usb_close(struct cmsis_dap *dap) { libusb_release_interface(dap->bdata->dev_handle, dap->bdata->interface); libusb_close(dap->bdata->dev_handle); libusb_exit(dap->bdata->usb_ctx); free(dap->bdata); dap->bdata = NULL; free(dap->packet_buffer); dap->packet_buffer = NULL; } static int cmsis_dap_usb_read(struct cmsis_dap *dap, int timeout_ms) { int transferred = 0; int err; err = libusb_bulk_transfer(dap->bdata->dev_handle, dap->bdata->ep_in, dap->packet_buffer, dap->packet_size, &transferred, timeout_ms); if (err) { if (err == LIBUSB_ERROR_TIMEOUT) { return ERROR_TIMEOUT_REACHED; } else { LOG_ERROR("error reading data: %s", libusb_strerror(err)); return ERROR_FAIL; } } memset(&dap->packet_buffer[transferred], 0, dap->packet_buffer_size - transferred); return transferred; } static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen, int timeout_ms) { int transferred = 0; int err; /* skip the first byte that is only used by the HID backend */ err = libusb_bulk_transfer(dap->bdata->dev_handle, dap->bdata->ep_out, dap->packet_buffer, txlen, &transferred, timeout_ms); if (err) { if (err == LIBUSB_ERROR_TIMEOUT) { return ERROR_TIMEOUT_REACHED; } else { LOG_ERROR("error writing data: %s", libusb_strerror(err)); return ERROR_FAIL; } } return transferred; } static int cmsis_dap_usb_alloc(struct cmsis_dap *dap, unsigned int pkt_sz) { uint8_t *buf = malloc(pkt_sz); if (!buf) { LOG_ERROR("unable to allocate CMSIS-DAP packet buffer"); return ERROR_FAIL; } dap->packet_buffer = buf; dap->packet_size = pkt_sz; dap->packet_buffer_size = pkt_sz; /* Prevent sending zero size USB packets */ dap->packet_usable_size = pkt_sz - 1; dap->command = dap->packet_buffer; dap->response = dap->packet_buffer; return ERROR_OK; } COMMAND_HANDLER(cmsis_dap_handle_usb_interface_command) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cmsis_dap_usb_interface); else LOG_ERROR("expected exactly one argument to cmsis_dap_usb_interface <interface_number>"); return ERROR_OK; } const struct command_registration cmsis_dap_usb_subcommand_handlers[] = { { .name = "interface", .handler = &cmsis_dap_handle_usb_interface_command, .mode = COMMAND_CONFIG, .help = "set the USB interface number to use (for USB bulk backend only)", .usage = "<interface_number>", }, COMMAND_REGISTRATION_DONE }; const struct cmsis_dap_backend cmsis_dap_usb_backend = { .name = "usb_bulk", .open = cmsis_dap_usb_open, .close = cmsis_dap_usb_close, .read = cmsis_dap_usb_read, .write = cmsis_dap_usb_write, .packet_buffer_alloc = cmsis_dap_usb_alloc, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/cmsis_dap_usb_hid.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2018 by Mickaël Thomas * * mickael9@gmail.com * * * * Copyright (C) 2016 by Maksym Hilliaka * * oter@frozen-team.com * * * * Copyright (C) 2016 by Phillip Pearson * * pp@myelin.co.nz * * * * Copyright (C) 2014 by Paul Fertser * * fercerpav@gmail.com * * * * Copyright (C) 2013 by mike brown * * mike@theshedworks.org.uk * * * * Copyright (C) 2013 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <string.h> #include <hidapi.h> #include <helper/log.h> #include "cmsis_dap.h" struct cmsis_dap_backend_data { hid_device *dev_handle; }; static void cmsis_dap_hid_close(struct cmsis_dap *dap); static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz); static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], const char *serial) { hid_device *dev = NULL; int i; struct hid_device_info *devs, *cur_dev; unsigned short target_vid, target_pid; target_vid = 0; target_pid = 0; if (hid_init() != 0) { LOG_ERROR("unable to open HIDAPI"); return ERROR_FAIL; } /* * The CMSIS-DAP specification stipulates: * "The Product String must contain "CMSIS-DAP" somewhere in the string. This is used by the * debuggers to identify a CMSIS-DAP compliant Debug Unit that is connected to a host computer." */ devs = hid_enumerate(0x0, 0x0); cur_dev = devs; while (cur_dev) { bool found = false; if (vids[0] == 0) { if (!cur_dev->product_string) { LOG_DEBUG("Cannot read product string of device 0x%x:0x%x", cur_dev->vendor_id, cur_dev->product_id); } else if (wcsstr(cur_dev->product_string, L"CMSIS-DAP")) { /* if the user hasn't specified VID:PID *and* * product string contains "CMSIS-DAP", pick it */ found = true; } } else { /* otherwise, exhaustively compare against all VID:PID in list */ for (i = 0; vids[i] || pids[i]; i++) { if ((vids[i] == cur_dev->vendor_id) && (pids[i] == cur_dev->product_id)) found = true; } } /* LPC-LINK2 has cmsis-dap on interface 0 and other HID functions on other interfaces */ if (cur_dev->vendor_id == 0x1fc9 && cur_dev->product_id == 0x0090 && cur_dev->interface_number != 0) found = false; if (found) { /* check serial number matches if given */ if (!serial) break; if (cur_dev->serial_number) { size_t len = (strlen(serial) + 1) * sizeof(wchar_t); wchar_t *wserial = malloc(len); mbstowcs(wserial, serial, len); if (wcscmp(wserial, cur_dev->serial_number) == 0) { free(wserial); break; } else { free(wserial); wserial = NULL; } } } cur_dev = cur_dev->next; } if (cur_dev) { target_vid = cur_dev->vendor_id; target_pid = cur_dev->product_id; } if (target_vid == 0 && target_pid == 0) { hid_free_enumeration(devs); return ERROR_FAIL; } dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data)); if (!dap->bdata) { LOG_ERROR("unable to allocate memory"); return ERROR_FAIL; } dev = hid_open_path(cur_dev->path); hid_free_enumeration(devs); if (!dev) { LOG_ERROR("unable to open CMSIS-DAP device 0x%x:0x%x", target_vid, target_pid); return ERROR_FAIL; } /* allocate default packet buffer, may be changed later. * currently with HIDAPI we have no way of getting the output report length * without this info we cannot communicate with the adapter. * For the moment we have to hard code the packet size */ unsigned int packet_size = 64; /* atmel cmsis-dap uses 512 byte reports */ /* except when it doesn't e.g. with mEDBG on SAMD10 Xplained * board */ /* TODO: HID report descriptor should be parsed instead of * hardcoding a match by VID */ if (target_vid == 0x03eb && target_pid != 0x2145 && target_pid != 0x2175) packet_size = 512; dap->bdata->dev_handle = dev; int retval = cmsis_dap_hid_alloc(dap, packet_size); if (retval != ERROR_OK) { cmsis_dap_hid_close(dap); return ERROR_FAIL; } dap->command = dap->packet_buffer + REPORT_ID_SIZE; dap->response = dap->packet_buffer; return ERROR_OK; } static void cmsis_dap_hid_close(struct cmsis_dap *dap) { hid_close(dap->bdata->dev_handle); hid_exit(); free(dap->bdata); dap->bdata = NULL; free(dap->packet_buffer); dap->packet_buffer = NULL; } static int cmsis_dap_hid_read(struct cmsis_dap *dap, int timeout_ms) { int retval = hid_read_timeout(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_buffer_size, timeout_ms); if (retval == 0) { return ERROR_TIMEOUT_REACHED; } else if (retval == -1) { LOG_ERROR("error reading data: %ls", hid_error(dap->bdata->dev_handle)); return ERROR_FAIL; } return retval; } static int cmsis_dap_hid_write(struct cmsis_dap *dap, int txlen, int timeout_ms) { (void) timeout_ms; dap->packet_buffer[0] = 0; /* HID report number */ /* Pad the rest of the TX buffer with 0's */ memset(dap->command + txlen, 0, dap->packet_size - txlen); /* write data to device */ int retval = hid_write(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_buffer_size); if (retval == -1) { LOG_ERROR("error writing data: %ls", hid_error(dap->bdata->dev_handle)); return ERROR_FAIL; } return retval; } static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz) { unsigned int packet_buffer_size = pkt_sz + REPORT_ID_SIZE; uint8_t *buf = malloc(packet_buffer_size); if (!buf) { LOG_ERROR("unable to allocate CMSIS-DAP packet buffer"); return ERROR_FAIL; } dap->packet_buffer = buf; dap->packet_size = pkt_sz; dap->packet_usable_size = pkt_sz; dap->packet_buffer_size = packet_buffer_size; dap->command = dap->packet_buffer + REPORT_ID_SIZE; dap->response = dap->packet_buffer; return ERROR_OK; } const struct cmsis_dap_backend cmsis_dap_hid_backend = { .name = "hid", .open = cmsis_dap_hid_open, .close = cmsis_dap_hid_close, .read = cmsis_dap_hid_read, .write = cmsis_dap_hid_write, .packet_buffer_alloc = cmsis_dap_hid_alloc, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/driver.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/jtag.h> #include <jtag/interface.h> #include <jtag/commands.h> #include <jtag/minidriver.h> #include <helper/command.h> struct jtag_callback_entry { struct jtag_callback_entry *next; jtag_callback_t callback; jtag_callback_data_t data0; jtag_callback_data_t data1; jtag_callback_data_t data2; jtag_callback_data_t data3; }; static struct jtag_callback_entry *jtag_callback_queue_head; static struct jtag_callback_entry *jtag_callback_queue_tail; static void jtag_callback_queue_reset(void) { jtag_callback_queue_head = NULL; jtag_callback_queue_tail = NULL; } /** * see jtag_add_ir_scan() * */ int interface_jtag_add_ir_scan(struct jtag_tap *active, const struct scan_field *in_fields, tap_state_t state) { size_t num_taps = jtag_tap_count_enabled(); struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command)); struct scan_field *out_fields = cmd_queue_alloc(num_taps * sizeof(struct scan_field)); jtag_queue_command(cmd); cmd->type = JTAG_SCAN; cmd->cmd.scan = scan; scan->ir_scan = true; scan->num_fields = num_taps; /* one field per device */ scan->fields = out_fields; scan->end_state = state; struct scan_field *field = out_fields; /* keep track where we insert data */ /* loop over all enabled TAPs */ for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap; tap = jtag_tap_next_enabled(tap)) { /* search the input field list for fields for the current TAP */ if (tap == active) { /* if TAP is listed in input fields, copy the value */ tap->bypass = 0; jtag_scan_field_clone(field, in_fields); } else { /* if a TAP isn't listed in input fields, set it to BYPASS */ tap->bypass = 1; field->num_bits = tap->ir_length; field->out_value = buf_set_ones(cmd_queue_alloc(DIV_ROUND_UP(tap->ir_length, 8)), tap->ir_length); field->in_value = NULL; /* do not collect input for tap's in bypass */ } /* update device information */ buf_cpy(field->out_value, tap->cur_instr, tap->ir_length); field++; } /* paranoia: jtag_tap_count_enabled() and jtag_tap_next_enabled() not in sync */ assert(field == out_fields + num_taps); return ERROR_OK; } /** * see jtag_add_dr_scan() * */ int interface_jtag_add_dr_scan(struct jtag_tap *active, int in_num_fields, const struct scan_field *in_fields, tap_state_t state) { /* count devices in bypass */ size_t bypass_devices = 0; for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap; tap = jtag_tap_next_enabled(tap)) { if (tap->bypass) bypass_devices++; } struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command)); struct scan_field *out_fields = cmd_queue_alloc((in_num_fields + bypass_devices) * sizeof(struct scan_field)); jtag_queue_command(cmd); cmd->type = JTAG_SCAN; cmd->cmd.scan = scan; scan->ir_scan = false; scan->num_fields = in_num_fields + bypass_devices; scan->fields = out_fields; scan->end_state = state; struct scan_field *field = out_fields; /* keep track where we insert data */ /* loop over all enabled TAPs */ for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap; tap = jtag_tap_next_enabled(tap)) { /* if TAP is not bypassed insert matching input fields */ if (!tap->bypass) { assert(active == tap); #ifndef NDEBUG /* remember initial position for assert() */ struct scan_field *start_field = field; #endif /* NDEBUG */ for (int j = 0; j < in_num_fields; j++) { jtag_scan_field_clone(field, in_fields + j); field++; } assert(field > start_field); /* must have at least one input field per not bypassed TAP */ } /* if a TAP is bypassed, generated a dummy bit*/ else { field->num_bits = 1; field->out_value = NULL; field->in_value = NULL; field++; } } assert(field == out_fields + scan->num_fields); /* no superfluous input fields permitted */ return ERROR_OK; } static int jtag_add_plain_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state, bool ir_scan) { struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command)); struct scan_field *out_fields = cmd_queue_alloc(sizeof(struct scan_field)); jtag_queue_command(cmd); cmd->type = JTAG_SCAN; cmd->cmd.scan = scan; scan->ir_scan = ir_scan; scan->num_fields = 1; scan->fields = out_fields; scan->end_state = state; out_fields->num_bits = num_bits; out_fields->out_value = buf_cpy(out_bits, cmd_queue_alloc(DIV_ROUND_UP(num_bits, 8)), num_bits); out_fields->in_value = in_bits; return ERROR_OK; } int interface_jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { return jtag_add_plain_scan(num_bits, out_bits, in_bits, state, false); } int interface_jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { return jtag_add_plain_scan(num_bits, out_bits, in_bits, state, true); } int interface_jtag_add_tlr(void) { tap_state_t state = TAP_RESET; /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); jtag_queue_command(cmd); cmd->type = JTAG_TLR_RESET; cmd->cmd.statemove = cmd_queue_alloc(sizeof(struct statemove_command)); cmd->cmd.statemove->end_state = state; return ERROR_OK; } int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state state) { struct jtag_command *cmd; cmd = cmd_queue_alloc(sizeof(struct jtag_command)); if (!cmd) return ERROR_FAIL; cmd->type = JTAG_TMS; cmd->cmd.tms = cmd_queue_alloc(sizeof(*cmd->cmd.tms)); if (!cmd->cmd.tms) return ERROR_FAIL; /* copy the bits; our caller doesn't guarantee they'll persist */ cmd->cmd.tms->num_bits = num_bits; cmd->cmd.tms->bits = buf_cpy(seq, cmd_queue_alloc(DIV_ROUND_UP(num_bits, 8)), num_bits); if (!cmd->cmd.tms->bits) return ERROR_FAIL; jtag_queue_command(cmd); return ERROR_OK; } int interface_jtag_add_pathmove(int num_states, const tap_state_t *path) { /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); jtag_queue_command(cmd); cmd->type = JTAG_PATHMOVE; cmd->cmd.pathmove = cmd_queue_alloc(sizeof(struct pathmove_command)); cmd->cmd.pathmove->num_states = num_states; cmd->cmd.pathmove->path = cmd_queue_alloc(sizeof(tap_state_t) * num_states); for (int i = 0; i < num_states; i++) cmd->cmd.pathmove->path[i] = path[i]; return ERROR_OK; } int interface_jtag_add_runtest(int num_cycles, tap_state_t state) { /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); jtag_queue_command(cmd); cmd->type = JTAG_RUNTEST; cmd->cmd.runtest = cmd_queue_alloc(sizeof(struct runtest_command)); cmd->cmd.runtest->num_cycles = num_cycles; cmd->cmd.runtest->end_state = state; return ERROR_OK; } int interface_jtag_add_clocks(int num_cycles) { /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); jtag_queue_command(cmd); cmd->type = JTAG_STABLECLOCKS; cmd->cmd.stableclocks = cmd_queue_alloc(sizeof(struct stableclocks_command)); cmd->cmd.stableclocks->num_cycles = num_cycles; return ERROR_OK; } int interface_jtag_add_reset(int req_trst, int req_srst) { /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); jtag_queue_command(cmd); cmd->type = JTAG_RESET; cmd->cmd.reset = cmd_queue_alloc(sizeof(struct reset_command)); cmd->cmd.reset->trst = req_trst; cmd->cmd.reset->srst = req_srst; return ERROR_OK; } int interface_jtag_add_sleep(uint32_t us) { /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); jtag_queue_command(cmd); cmd->type = JTAG_SLEEP; cmd->cmd.sleep = cmd_queue_alloc(sizeof(struct sleep_command)); cmd->cmd.sleep->us = us; return ERROR_OK; } /* add callback to end of queue */ void interface_jtag_add_callback4(jtag_callback_t callback, jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3) { struct jtag_callback_entry *entry = cmd_queue_alloc(sizeof(struct jtag_callback_entry)); entry->next = NULL; entry->callback = callback; entry->data0 = data0; entry->data1 = data1; entry->data2 = data2; entry->data3 = data3; if (!jtag_callback_queue_head) { jtag_callback_queue_head = entry; jtag_callback_queue_tail = entry; } else { jtag_callback_queue_tail->next = entry; jtag_callback_queue_tail = entry; } } int interface_jtag_execute_queue(void) { static int reentry; assert(reentry == 0); reentry++; int retval = default_interface_jtag_execute_queue(); if (retval == ERROR_OK) { struct jtag_callback_entry *entry; for (entry = jtag_callback_queue_head; entry; entry = entry->next) { retval = entry->callback(entry->data0, entry->data1, entry->data2, entry->data3); if (retval != ERROR_OK) break; } } jtag_command_queue_reset(); jtag_callback_queue_reset(); reentry--; return retval; } static int jtag_convert_to_callback4(jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3) { ((jtag_callback1_t)data1)(data0); return ERROR_OK; } void interface_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t data0) { jtag_add_callback4(jtag_convert_to_callback4, data0, (jtag_callback_data_t)callback, 0, 0); } void jtag_add_callback(jtag_callback1_t f, jtag_callback_data_t data0) { interface_jtag_add_callback(f, data0); } void jtag_add_callback4(jtag_callback_t f, jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3) { interface_jtag_add_callback4(f, data0, data1, data2, data3); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/dummy.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2008 by Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/interface.h> #include "bitbang.h" #include "hello.h" /* my private tap controller state, which tracks state for calling code */ static tap_state_t dummy_state = TAP_RESET; static int dummy_clock; /* edge detector */ static int clock_count; /* count clocks in any stable state, only stable states */ static uint32_t dummy_data; static bb_value_t dummy_read(void) { int data = 1 & dummy_data; dummy_data = (dummy_data >> 1) | (1 << 31); return data ? BB_HIGH : BB_LOW; } static int dummy_write(int tck, int tms, int tdi) { /* TAP standard: "state transitions occur on rising edge of clock" */ if (tck != dummy_clock) { if (tck) { tap_state_t old_state = dummy_state; dummy_state = tap_state_transition(old_state, tms); if (old_state != dummy_state) { if (clock_count) { LOG_DEBUG("dummy_tap: %d stable clocks", clock_count); clock_count = 0; } LOG_DEBUG("dummy_tap: %s", tap_state_name(dummy_state)); #if defined(DEBUG) if (dummy_state == TAP_DRCAPTURE) dummy_data = 0x01255043; #endif } else { /* this is a stable state clock edge, no change of state here, * simply increment clock_count for subsequent logging */ ++clock_count; } } dummy_clock = tck; } return ERROR_OK; } static int dummy_reset(int trst, int srst) { dummy_clock = 0; if (trst || (srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) dummy_state = TAP_RESET; LOG_DEBUG("reset to: %s", tap_state_name(dummy_state)); return ERROR_OK; } static int dummy_led(int on) { return ERROR_OK; } static struct bitbang_interface dummy_bitbang = { .read = &dummy_read, .write = &dummy_write, .blink = &dummy_led, }; static int dummy_khz(int khz, int *jtag_speed) { if (khz == 0) *jtag_speed = 0; else *jtag_speed = 64000/khz; return ERROR_OK; } static int dummy_speed_div(int speed, int *khz) { if (speed == 0) *khz = 0; else *khz = 64000/speed; return ERROR_OK; } static int dummy_speed(int speed) { return ERROR_OK; } static int dummy_init(void) { bitbang_interface = &dummy_bitbang; return ERROR_OK; } static int dummy_quit(void) { return ERROR_OK; } static const struct command_registration dummy_command_handlers[] = { { .name = "dummy", .mode = COMMAND_ANY, .help = "dummy interface driver commands", .chain = hello_command_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE, }; /* The dummy driver is used to easily check the code path * where the target is unresponsive. */ static struct jtag_interface dummy_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = &bitbang_execute_queue, }; struct adapter_driver dummy_adapter_driver = { .name = "dummy", .transports = jtag_only, .commands = dummy_command_handlers, .init = &dummy_init, .quit = &dummy_quit, .reset = &dummy_reset, .speed = &dummy_speed, .khz = &dummy_khz, .speed_div = &dummy_speed_div, .jtag_ops = &dummy_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/ep93xx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/interface.h> #include "bitbang.h" #define TDO_BIT 1 #define TDI_BIT 2 #define TCK_BIT 4 #define TMS_BIT 8 #define TRST_BIT 16 #define SRST_BIT 32 #define VCC_BIT 64 #include <sys/mman.h> static uint8_t output_value; static int dev_mem_fd; static uint8_t *gpio_controller; static volatile uint8_t *gpio_data_register; static volatile uint8_t *gpio_data_direction_register; /* low level command set */ static bb_value_t ep93xx_read(void); static int ep93xx_write(int tck, int tms, int tdi); static int ep93xx_reset(int trst, int srst); static int ep93xx_init(void); static int ep93xx_quit(void); static struct timespec ep93xx_zzzz; static struct jtag_interface ep93xx_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, }; struct adapter_driver ep93xx_adapter_driver = { .name = "ep93xx", .transports = jtag_only, .init = ep93xx_init, .quit = ep93xx_quit, .reset = ep93xx_reset, .jtag_ops = &ep93xx_interface, }; static struct bitbang_interface ep93xx_bitbang = { .read = ep93xx_read, .write = ep93xx_write, .blink = NULL, }; static bb_value_t ep93xx_read(void) { return (*gpio_data_register & TDO_BIT) ? BB_HIGH : BB_LOW; } static int ep93xx_write(int tck, int tms, int tdi) { if (tck) output_value |= TCK_BIT; else output_value &= ~TCK_BIT; if (tms) output_value |= TMS_BIT; else output_value &= ~TMS_BIT; if (tdi) output_value |= TDI_BIT; else output_value &= ~TDI_BIT; *gpio_data_register = output_value; nanosleep(&ep93xx_zzzz, NULL); return ERROR_OK; } /* (1) assert or (0) deassert reset lines */ static int ep93xx_reset(int trst, int srst) { if (trst == 0) output_value |= TRST_BIT; else if (trst == 1) output_value &= ~TRST_BIT; if (srst == 0) output_value |= SRST_BIT; else if (srst == 1) output_value &= ~SRST_BIT; *gpio_data_register = output_value; nanosleep(&ep93xx_zzzz, NULL); return ERROR_OK; } static int set_gonk_mode(void) { void *syscon = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, 0x80930000); if (syscon == MAP_FAILED) { LOG_ERROR("mmap: %s", strerror(errno)); return ERROR_JTAG_INIT_FAILED; } uint32_t devicecfg = *((volatile uint32_t *)((uintptr_t)syscon + 0x80)); *((volatile uint32_t *)((uintptr_t)syscon + 0xc0)) = 0xaa; *((volatile uint32_t *)((uintptr_t)syscon + 0x80)) = devicecfg | 0x08000000; munmap(syscon, 4096); return ERROR_OK; } static int ep93xx_init(void) { int ret; bitbang_interface = &ep93xx_bitbang; ep93xx_zzzz.tv_sec = 0; ep93xx_zzzz.tv_nsec = 10000000; dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); if (dev_mem_fd < 0) { LOG_ERROR("open: %s", strerror(errno)); return ERROR_JTAG_INIT_FAILED; } gpio_controller = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, 0x80840000); if (gpio_controller == MAP_FAILED) { LOG_ERROR("mmap: %s", strerror(errno)); close(dev_mem_fd); return ERROR_JTAG_INIT_FAILED; } ret = set_gonk_mode(); if (ret != ERROR_OK) { munmap(gpio_controller, 4096); close(dev_mem_fd); return ret; } #if 0 /* Use GPIO port A. */ gpio_data_register = gpio_controller + 0x00; gpio_data_direction_register = gpio_controller + 0x10; /* Use GPIO port B. */ gpio_data_register = gpio_controller + 0x04; gpio_data_direction_register = gpio_controller + 0x14; /* Use GPIO port C. */ gpio_data_register = gpio_controller + 0x08; gpio_data_direction_register = gpio_controller + 0x18; /* Use GPIO port D. */ gpio_data_register = gpio_controller + 0x0c; gpio_data_direction_register = gpio_controller + 0x1c; #endif /* Use GPIO port C. */ gpio_data_register = gpio_controller + 0x08; gpio_data_direction_register = gpio_controller + 0x18; LOG_INFO("gpio_data_register = %p", gpio_data_register); LOG_INFO("gpio_data_direction_reg = %p", gpio_data_direction_register); /* * Configure bit 0 (TDO) as an input, and bits 1-5 (TDI, TCK * TMS, TRST, SRST) as outputs. Drive TDI and TCK low, and * TMS/TRST/SRST high. */ output_value = TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT; *gpio_data_register = output_value; nanosleep(&ep93xx_zzzz, NULL); /* * Configure the direction register. 1 = output, 0 = input. */ *gpio_data_direction_register = TDI_BIT | TCK_BIT | TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT; nanosleep(&ep93xx_zzzz, NULL); return ERROR_OK; } static int ep93xx_quit(void) { return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/esp_usb_jtag.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Espressif USB to Jtag adapter * * Copyright (C) 2020 Espressif Systems (Shanghai) Co. Ltd. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/adapter.h> #include <jtag/interface.h> #include <helper/time_support.h> #include <helper/bits.h> #include "bitq.h" #include "libusb_helper.h" /* Holy Crap, it's protocol documentation, and it's even vendor-provided! A device that speaks this protocol has two endpoints intended for JTAG debugging: one OUT for the host to send encoded commands to, one IN from which the host can read any read TDO bits. The device will also respond to vendor-defined interface requests on ep0. The main communication method is over the IN/OUT endpoints. The commands that are expected on the OUT endpoint are one nibble wide and are processed high-nibble-first, low-nibble-second, and in the order the bytes come in. Commands are defined as follows: bit 3 2 1 0 CMD_CLK [ 0 cap tdi tms ] CMD_RST [ 1 0 0 srst ] CMD_FLUSH [ 1 0 1 0 ] CMD_RSV [ 1 0 1 1 ] CMD_REP [ 1 1 R1 R0 ] CMD_CLK sets the TDI and TMS lines to the value of `tdi` and `tms` and lowers, then raises, TCK. If `cap` is 1, the value of TDO is captured and can be retrieved over the IN endpoint. The bytes read from the IN endpoint specifically are these bits, with the lowest it in every byte captured first and the bytes returned in the order the data in them was captured. The durations of TCK being high / low can be set using the VEND_JTAG_SETDIV vendor-specific interface request. CMD_RST controls the SRST line; as soon as the command is processed, the SRST line will be set to the value of `srst`. CMD_FLUSH flushes the IN endpoint; zeroes will be added to the amount of bits in the endpoint until the payload is a multiple of bytes, and the data is offered to the host. If the IN endpoint has no data, this effectively becomes a no-op; the endpoint won't send any 0-byte payloads. CMD_RSV is reserved for future use. CMD_REP repeats the last command that is not CMD_REP. The amount of times a CMD_REP command will re-execute this command is (r1*2+r0)<<(2*n), where n is the amount of previous repeat commands executed since the command to be repeated. An example for CMD_REP: Say the host queues: 1. CMD_CLK - This will execute one CMD_CLK. 2. CMD_REP with r1=0 and r0=1 - This will execute 1. another (0*2+1)<<(2*0)=1 time. 3. CMD_REP with r1=1 and r0=0 - This will execute 1. another (1*2+0)<<(2*1)=4 times. 4. CMD_REP with r1=0 and r0=1 - This will execute 1. another (0*2+1)<<(2*2)=8 time. 5. CMD_FLUSH - This will flush the IN pipeline. 6. CMD_CLK - This will execute one CMD_CLK 7. CMD_REP with r1=1 and r0=0 - This will execute 6. another (1*2+0)<<(2*0)=2 times. 8. CMD_FLUSH - This will flush the IN pipeline. Note that the net effect of the repetitions is that command 1 is executed (1+1+4+8=) 14 times and command 6 is executed (1+2=) 3 times. Note that the device only has a fairly limited amount of endpoint RAM. It's probably best to keep an eye on the amount of bytes that are supposed to be in the IN endpoint and grab those before stuffing more commands into the OUT endpoint: the OUT endpoint will not accept any more commands (writes will time out) when the IN endpoint buffers are all filled up. The device also supports some vendor-specific interface requests. These requests are sent as control transfers on endpoint 0 to the JTAG endpoint. Note that these commands bypass the data in the OUT endpoint; if timing is important, it's important that this endpoint is empty. This can be done by e.g sending one CMD_CLK capturing TDI, then one CMD_FLUSH, then waiting until the bit appears on the IN endpoint. bmRequestType bRequest wValue wIndex wLength Data 01000000b VEND_JTAG_SETDIV [divide] interface 0 None 01000000b VEND_JTAG_SETIO [iobits] interface 0 None 11000000b VEND_JTAG_GETTDO 0 interface 1 [iostate] 10000000b GET_DESCRIPTOR(6) 0x2000 0 256 [jtag cap desc] VEND_JTAG_SETDIV indirectly controls the speed of the TCK clock. The value written here is the length of a TCK cycle, in ticks of the adapters base clock. Both the base clock value as well as the minimum and maximum divider can be read from the jtag capabilities descriptor, as explained below. Note that this should not be set to a value outside of the range described there, otherwise results are undefined. VEND_JTAG_SETIO can be controlled to directly set the IO pins. The format of [iobits] normally is {11'b0, srst, trst, tck, tms, tdi} Note that the first 11 0 bits are reserved for future use, current hardware ignores them. VEND_JTAG_GETTDO returns one byte, of which bit 0 indicates the current state of the TDO input. Note that other bits are reserved for future use and should be ignored. To describe the capabilities of the JTAG adapter, a specific descriptor (0x20) can be retrieved. The format of the descriptor documented below. The descriptor works in the same fashion as USB descriptors: a header indicating the version and total length followed by descriptors with a specific type and size. Forward compatibility is guaranteed as software can skip over an unknown descriptor. */ #define JTAG_PROTO_CAPS_VER 1 /* Version field. At the moment, only version 1 is defined. */ struct jtag_proto_caps_hdr { uint8_t proto_ver; /* Protocol version. Expects JTAG_PROTO_CAPS_VER for now. */ uint8_t length; /* of this plus any following descriptors */ } __attribute__((packed)); /* start of the descriptor headers */ #define JTAG_BUILTIN_DESCR_START_OFF 0 /* Devices with builtin usb jtag */ /* * ESP USB Bridge https://github.com/espressif/esp-usb-bridge uses string descriptor. * Skip 1 byte length and 1 byte descriptor type */ #define JTAG_EUB_DESCR_START_OFF 2 /* ESP USB Bridge */ /* Note: At the moment, there is only a speed_caps version indicating the base speed of the JTAG hardware is derived from the APB bus speed of the SoC. If later on, there are standalone converters using the protocol, we should define e.g. JTAG_PROTO_CAPS_SPEED_FIXED_TYPE to distinguish between the two. Note: If the JTAG device has larger buffers than endpoint-size-plus-a-bit, we should have some kind of caps header to assume this. If no such caps exist, assume a minimum (in) buffer of endpoint size + 4. */ struct jtag_gen_hdr { uint8_t type; uint8_t length; } __attribute__((packed)); struct jtag_proto_caps_speed_apb { uint8_t type; /* Type, always JTAG_PROTO_CAPS_SPEED_APB_TYPE */ uint8_t length; /* Length of this */ uint8_t apb_speed_10khz[2]; /* ABP bus speed, in 10KHz increments. Base speed is half this. */ uint8_t div_min[2]; /* minimum divisor (to base speed), inclusive */ uint8_t div_max[2]; /* maximum divisor (to base speed), inclusive */ } __attribute__((packed)); #define JTAG_PROTO_CAPS_DATA_LEN 255 #define JTAG_PROTO_CAPS_SPEED_APB_TYPE 1 #define VEND_DESCR_BUILTIN_JTAG_CAPS 0x2000 #define VEND_JTAG_SETDIV 0 #define VEND_JTAG_SETIO 1 #define VEND_JTAG_GETTDO 2 #define VEND_JTAG_SET_CHIPID 3 #define VEND_JTAG_SETIO_TDI BIT(0) #define VEND_JTAG_SETIO_TMS BIT(1) #define VEND_JTAG_SETIO_TCK BIT(2) #define VEND_JTAG_SETIO_TRST BIT(3) #define VEND_JTAG_SETIO_SRST BIT(4) #define CMD_CLK(cap, tdi, tms) ((cap ? BIT(2) : 0) | (tms ? BIT(1) : 0) | (tdi ? BIT(0) : 0)) #define CMD_RST(srst) (0x8 | (srst ? BIT(0) : 0)) #define CMD_FLUSH 0xA #define CMD_RSVD 0xB #define CMD_REP(r) (0xC + ((r) & 3)) /* The internal repeats register is 10 bits, which means we can have 5 repeat commands in a *row at max. This translates to ('b1111111111+1=)1024 reps max. */ #define CMD_REP_MAX_REPS 1024 /* Currently we only support one USB device. */ #define USB_CONFIGURATION 0 /* Buffer size; is equal to the endpoint size. In bytes * TODO for future adapters: read from device configuration? */ #define OUT_EP_SZ 64 /* Out data can be buffered for longer without issues (as long as the in buffer does not overflow), * so we'll use an out buffer that is much larger than the out ep size. */ #define OUT_BUF_SZ (OUT_EP_SZ * 32) /* The in buffer cannot be larger than the device can offer, though. */ #define IN_BUF_SZ 64 /* Because a series of out commands can lead to a multitude of IN_BUF_SZ-sized in packets *to be read, we have multiple buffers to store those before the bitq interface reads them out. */ #define IN_BUF_CT 8 #define ESP_USB_INTERFACE 1 /* Private data */ struct esp_usb_jtag { struct libusb_device_handle *usb_device; uint32_t base_speed_khz; uint16_t div_min; uint16_t div_max; uint8_t out_buf[OUT_BUF_SZ]; unsigned int out_buf_pos_nibbles; /* write position in out_buf */ uint8_t in_buf[IN_BUF_CT][IN_BUF_SZ]; unsigned int in_buf_size_bits[IN_BUF_CT]; /* size in bits of the data stored in an in_buf */ unsigned int cur_in_buf_rd, cur_in_buf_wr; /* read/write index */ unsigned int in_buf_pos_bits; /* which bit in the in buf needs to be returned to bitq next */ unsigned int read_ep; unsigned int write_ep; unsigned int prev_cmd; /* previous command, stored here for RLEing. */ int prev_cmd_repct; /* Amount of repetitions of that command we have seen until now */ /* This is the total number of in bits we need to read, including in unsent commands */ unsigned int pending_in_bits; unsigned int hw_in_fifo_len; struct bitq_interface bitq_interface; }; /* For now, we only use one static private struct. Technically, we can re-work this, but I don't think * OpenOCD supports multiple JTAG adapters anyway. */ static struct esp_usb_jtag esp_usb_jtag_priv; static struct esp_usb_jtag *priv = &esp_usb_jtag_priv; static int esp_usb_vid; static int esp_usb_pid; static int esp_usb_jtag_caps; static int esp_usb_target_chip_id; static int esp_usb_jtag_init(void); static int esp_usb_jtag_quit(void); /* Try to receive from USB endpoint into the current priv->in_buf */ static int esp_usb_jtag_recv_buf(void) { if (priv->in_buf_size_bits[priv->cur_in_buf_wr] != 0) LOG_ERROR("esp_usb_jtag: IN buffer overflow! (%d, size %d)", priv->cur_in_buf_wr, priv->in_buf_size_bits[priv->cur_in_buf_wr]); unsigned int recvd = 0, ct = (priv->pending_in_bits + 7) / 8; if (ct > IN_BUF_SZ) ct = IN_BUF_SZ; if (ct == 0) { /* Note that the adapters IN EP specifically does *not* usually generate 0-byte in * packets if there has been no data since the last flush. * As such, we don't need (and shouldn't) try to read it. */ return ERROR_OK; } priv->in_buf_size_bits[priv->cur_in_buf_wr] = 0; while (recvd < ct) { unsigned int tr; int ret = jtag_libusb_bulk_read(priv->usb_device, priv->read_ep, (char *)priv->in_buf[priv->cur_in_buf_wr] + recvd, ct, LIBUSB_TIMEOUT_MS, /*ms*/ (int *)&tr); if (ret != ERROR_OK || tr == 0) { /* Sometimes the hardware returns 0 bytes instead of NAKking the transaction. Ignore this. */ return ERROR_FAIL; } if (tr != ct) { /* Huh, short read? */ LOG_DEBUG("esp_usb_jtag: usb received only %d out of %d bytes.", tr, ct); } /* Adjust the amount of bits we still expect to read from the USB device after this. */ unsigned int bits_in_buf = priv->pending_in_bits; /* initially assume we read * everything that was pending */ if (bits_in_buf > tr * 8) bits_in_buf = tr * 8; /* ...but correct that if that was not the case. */ priv->pending_in_bits -= bits_in_buf; priv->in_buf_size_bits[priv->cur_in_buf_wr] += bits_in_buf; recvd += tr; } /* next in buffer for the next time. */ priv->cur_in_buf_wr++; if (priv->cur_in_buf_wr == IN_BUF_CT) priv->cur_in_buf_wr = 0; LOG_DEBUG_IO("esp_usb_jtag: In ep: received %d bytes; %d bytes (%d bits) left.", recvd, (priv->pending_in_bits + 7) / 8, priv->pending_in_bits); return ERROR_OK; } /* Sends priv->out_buf to the USB device. */ static int esp_usb_jtag_send_buf(void) { unsigned int ct = priv->out_buf_pos_nibbles / 2; unsigned int written = 0; while (written < ct) { int tr = 0, ret = jtag_libusb_bulk_write(priv->usb_device, priv->write_ep, (char *)priv->out_buf + written, ct - written, LIBUSB_TIMEOUT_MS, /*ms*/ &tr); LOG_DEBUG_IO("esp_usb_jtag: sent %d bytes.", tr); if (written + tr != ct) { LOG_DEBUG("esp_usb_jtag: usb sent only %d out of %d bytes.", written + tr, ct); } if (ret != ERROR_OK) return ret; written += tr; } priv->out_buf_pos_nibbles = 0; /* If there's more than a bufferful of data queuing up in the jtag adapters IN endpoint, empty * all but one buffer. */ while (priv->pending_in_bits > (IN_BUF_SZ + priv->hw_in_fifo_len - 1) * 8) esp_usb_jtag_recv_buf(); return ERROR_OK; } /* Simply adds a command to the buffer. Is called by the RLE encoding mechanism. *Also sends the intermediate buffer if there's enough to go into one USB packet. */ static int esp_usb_jtag_command_add_raw(unsigned int cmd) { int ret = ERROR_OK; if ((priv->out_buf_pos_nibbles & 1) == 0) priv->out_buf[priv->out_buf_pos_nibbles / 2] = (cmd << 4); else priv->out_buf[priv->out_buf_pos_nibbles / 2] |= cmd; priv->out_buf_pos_nibbles++; if (priv->out_buf_pos_nibbles == OUT_BUF_SZ * 2) ret = esp_usb_jtag_send_buf(); if (ret == ERROR_OK && priv->out_buf_pos_nibbles % (OUT_EP_SZ * 2) == 0) { if (priv->pending_in_bits > (IN_BUF_SZ + priv->hw_in_fifo_len - 1) * 8) ret = esp_usb_jtag_send_buf(); } return ret; } /* Writes a command stream equivalent to writing `cmd` `ct` times. */ static int esp_usb_jtag_write_rlestream(unsigned int cmd, int ct) { /* Special case: stacking flush commands does not make sense (and may not make the hardware very happy) */ if (cmd == CMD_FLUSH) ct = 1; /* Output previous command and repeat commands */ int ret = esp_usb_jtag_command_add_raw(cmd); if (ret != ERROR_OK) return ret; ct--; /* as the previous line already executes the command one time */ while (ct > 0) { ret = esp_usb_jtag_command_add_raw(CMD_REP(ct & 3)); if (ret != ERROR_OK) return ret; ct >>= 2; } return ERROR_OK; } /* Adds a command to the buffer of things to be sent. Transparently handles RLE compression using * the CMD_REP_x commands */ static int esp_usb_jtag_command_add(unsigned int cmd) { if (cmd == priv->prev_cmd && priv->prev_cmd_repct < CMD_REP_MAX_REPS) { priv->prev_cmd_repct++; } else { /* We can now write out the previous command plus repeat count. */ if (priv->prev_cmd_repct) { int ret = esp_usb_jtag_write_rlestream(priv->prev_cmd, priv->prev_cmd_repct); if (ret != ERROR_OK) return ret; } /* Ready for new command. */ priv->prev_cmd = cmd; priv->prev_cmd_repct = 1; } return ERROR_OK; } /* Called by bitq interface to output a bit on tdi and perhaps read a bit from tdo */ static int esp_usb_jtag_out(int tms, int tdi, int tdo_req) { int ret = esp_usb_jtag_command_add(CMD_CLK(tdo_req, tdi, tms)); if (ret != ERROR_OK) return ret; if (tdo_req) priv->pending_in_bits++; return ERROR_OK; } /* Called by bitq interface to flush all output commands and get returned data ready to read */ static int esp_usb_jtag_flush(void) { int ret; /*Make sure last command is written */ if (priv->prev_cmd_repct) { ret = esp_usb_jtag_write_rlestream(priv->prev_cmd, priv->prev_cmd_repct); if (ret != ERROR_OK) return ret; } priv->prev_cmd_repct = 0; /* Flush in buffer */ ret = esp_usb_jtag_command_add_raw(CMD_FLUSH); if (ret != ERROR_OK) return ret; /* Make sure we have an even amount of commands, as we can't write a nibble by itself. */ if (priv->out_buf_pos_nibbles & 1) { /*If not, pad with an extra FLUSH */ ret = esp_usb_jtag_command_add_raw(CMD_FLUSH); if (ret != ERROR_OK) return ret; } LOG_DEBUG_IO("esp_usb_jtag: Flush!"); /* Send off the buffer. */ ret = esp_usb_jtag_send_buf(); if (ret != ERROR_OK) return ret; /* Immediately fetch the response bits. */ while (priv->pending_in_bits > 0) esp_usb_jtag_recv_buf(); return ERROR_OK; } /* Called by bitq interface to sleep for a determined amount of time */ static int esp_usb_jtag_sleep(unsigned long us) { esp_usb_jtag_flush(); /* TODO: we can sleep more precisely (for small amounts of sleep at least) by sending dummy * commands to the adapter. */ jtag_sleep(us); return 0; } /* Called by the bitq interface to set the various resets */ static int esp_usb_jtag_reset(int trst, int srst) { /* TODO: handle trst using setup commands. Kind-of superfluous, however, as we can also do * a tap reset using tms, and it's also not implemented on other ESP32 chips with external JTAG. */ return esp_usb_jtag_command_add(CMD_RST(srst)); } /* Called by bitq to see if the IN data already is returned to the host. */ static int esp_usb_jtag_in_rdy(void) { /* We read all bits in the flush() routine, so if we're here, we have bits or are at EOF. */ return 1; } /* Read one bit from the IN data */ static int esp_usb_jtag_in(void) { if (!esp_usb_jtag_in_rdy()) { LOG_ERROR("esp_usb_jtag: Eeek! bitq asked us for in data while not ready!"); return -1; } if (priv->cur_in_buf_rd == priv->cur_in_buf_wr && priv->in_buf_size_bits[priv->cur_in_buf_rd] == 0) return -1; /* Extract the bit */ int r = (priv->in_buf[priv->cur_in_buf_rd][priv->in_buf_pos_bits / 8] & BIT(priv->in_buf_pos_bits & 7)) ? 1 : 0; /* Move to next bit. */ priv->in_buf_pos_bits++; if (priv->in_buf_pos_bits == priv->in_buf_size_bits[priv->cur_in_buf_rd]) { /* No more bits in this buffer; mark as re-usable and move to next buffer. */ priv->in_buf_pos_bits = 0; priv->in_buf_size_bits[priv->cur_in_buf_rd] = 0;/*indicate it is free again */ priv->cur_in_buf_rd++; if (priv->cur_in_buf_rd == IN_BUF_CT) priv->cur_in_buf_rd = 0; } return r; } static int esp_usb_jtag_init(void) { memset(priv, 0, sizeof(struct esp_usb_jtag)); const uint16_t vids[] = { esp_usb_vid, 0 }; /* must be null terminated */ const uint16_t pids[] = { esp_usb_pid, 0 }; /* must be null terminated */ bitq_interface = &priv->bitq_interface; bitq_interface->out = esp_usb_jtag_out; bitq_interface->flush = esp_usb_jtag_flush; bitq_interface->sleep = esp_usb_jtag_sleep; bitq_interface->reset = esp_usb_jtag_reset; bitq_interface->in_rdy = esp_usb_jtag_in_rdy; bitq_interface->in = esp_usb_jtag_in; int r = jtag_libusb_open(vids, pids, &priv->usb_device, NULL); if (r != ERROR_OK) { LOG_ERROR("esp_usb_jtag: could not find or open device!"); goto out; } jtag_libusb_set_configuration(priv->usb_device, USB_CONFIGURATION); r = jtag_libusb_choose_interface(priv->usb_device, &priv->read_ep, &priv->write_ep, LIBUSB_CLASS_VENDOR_SPEC, LIBUSB_CLASS_VENDOR_SPEC, ESP_USB_INTERFACE, LIBUSB_TRANSFER_TYPE_BULK); if (r != ERROR_OK) { LOG_ERROR("esp_usb_jtag: error finding/claiming JTAG interface on device!"); goto out; } /* TODO: This is not proper way to get caps data. Two requests can be done. * 1- With the minimum size required to get to know the total length of that struct, * 2- Then exactly the length of that struct. */ uint8_t jtag_caps_desc[JTAG_PROTO_CAPS_DATA_LEN]; int jtag_caps_read_len = jtag_libusb_control_transfer(priv->usb_device, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, LIBUSB_REQUEST_GET_DESCRIPTOR, esp_usb_jtag_caps, 0, (char *)jtag_caps_desc, JTAG_PROTO_CAPS_DATA_LEN, LIBUSB_TIMEOUT_MS); if (jtag_caps_read_len <= 0) { LOG_ERROR("esp_usb_jtag: could not retrieve jtag_caps descriptor!"); goto out; } /* defaults for values we normally get from the jtag caps descriptor */ priv->base_speed_khz = UINT32_MAX; priv->div_min = 1; priv->div_max = 1; int p = esp_usb_jtag_caps == VEND_DESCR_BUILTIN_JTAG_CAPS ? JTAG_BUILTIN_DESCR_START_OFF : JTAG_EUB_DESCR_START_OFF; if (p + sizeof(struct jtag_proto_caps_hdr) > (unsigned int)jtag_caps_read_len) { LOG_ERROR("esp_usb_jtag: not enough data to get header"); goto out; } struct jtag_proto_caps_hdr *hdr = (struct jtag_proto_caps_hdr *)&jtag_caps_desc[p]; if (hdr->proto_ver != JTAG_PROTO_CAPS_VER) { LOG_ERROR("esp_usb_jtag: unknown jtag_caps descriptor version 0x%X!", hdr->proto_ver); goto out; } if (hdr->length > jtag_caps_read_len) { LOG_ERROR("esp_usb_jtag: header length (%d) bigger then max read bytes (%d)", hdr->length, jtag_caps_read_len); goto out; } p += sizeof(struct jtag_proto_caps_hdr); while (p + sizeof(struct jtag_gen_hdr) < hdr->length) { struct jtag_gen_hdr *dhdr = (struct jtag_gen_hdr *)&jtag_caps_desc[p]; if (dhdr->type == JTAG_PROTO_CAPS_SPEED_APB_TYPE) { if (p + sizeof(struct jtag_proto_caps_speed_apb) < hdr->length) { LOG_ERROR("esp_usb_jtag: not enough data to get caps speed"); goto out; } struct jtag_proto_caps_speed_apb *spcap = (struct jtag_proto_caps_speed_apb *)dhdr; /* base speed always is half APB speed */ priv->base_speed_khz = le_to_h_u16(spcap->apb_speed_10khz) * 10 / 2; priv->div_min = le_to_h_u16(spcap->div_min); priv->div_max = le_to_h_u16(spcap->div_max); /* TODO: mark in priv that this is apb-derived and as such may change if apb * ever changes? */ } else { LOG_WARNING("esp_usb_jtag: unknown caps type 0x%X", dhdr->type); } p += dhdr->length; } if (priv->base_speed_khz == UINT32_MAX) { LOG_WARNING("esp_usb_jtag: No speed caps found... using sane-ish defaults."); priv->base_speed_khz = 1000; } LOG_INFO("esp_usb_jtag: Device found. Base speed %dKHz, div range %d to %d", priv->base_speed_khz, priv->div_min, priv->div_max); /* TODO: grab from (future) descriptor if we ever have a device with larger IN buffers */ priv->hw_in_fifo_len = 4; /* inform bridge board about the connected target chip for the specific operations * it is also safe to send this info to chips that have builtin usb jtag */ jtag_libusb_control_transfer(priv->usb_device, LIBUSB_REQUEST_TYPE_VENDOR, VEND_JTAG_SET_CHIPID, esp_usb_target_chip_id, 0, NULL, 0, LIBUSB_TIMEOUT_MS); return ERROR_OK; out: if (priv->usb_device) jtag_libusb_close(priv->usb_device); bitq_interface = NULL; priv->usb_device = NULL; return ERROR_FAIL; } static int esp_usb_jtag_quit(void) { if (!priv->usb_device) return ERROR_OK; jtag_libusb_close(priv->usb_device); bitq_cleanup(); bitq_interface = NULL; return ERROR_OK; } static int esp_usb_jtag_speed_div(int divisor, int *khz) { *khz = priv->base_speed_khz / divisor; return ERROR_OK; } static int esp_usb_jtag_khz(int khz, int *divisor) { if (khz == 0) { LOG_WARNING("esp_usb_jtag: RCLK not supported"); return ERROR_FAIL; } *divisor = priv->base_speed_khz / khz; LOG_DEBUG("Divisor for %d KHz with base clock of %d khz is %d", khz, priv->base_speed_khz, *divisor); if (*divisor < priv->div_min) *divisor = priv->div_min; if (*divisor > priv->div_max) *divisor = priv->div_max; return ERROR_OK; } static int esp_usb_jtag_speed(int divisor) { if (divisor == 0) { LOG_ERROR("esp_usb_jtag: Adaptive clocking is not supported."); return ERROR_JTAG_NOT_IMPLEMENTED; } LOG_DEBUG("esp_usb_jtag: setting divisor %d", divisor); jtag_libusb_control_transfer(priv->usb_device, LIBUSB_REQUEST_TYPE_VENDOR, VEND_JTAG_SETDIV, divisor, 0, NULL, 0, LIBUSB_TIMEOUT_MS); return ERROR_OK; } COMMAND_HANDLER(esp_usb_jtag_tdo_cmd) { char tdo; if (!priv->usb_device) return ERROR_FAIL; int r = jtag_libusb_control_transfer(priv->usb_device, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR, VEND_JTAG_GETTDO, 0, 0, &tdo, 1, LIBUSB_TIMEOUT_MS); if (r < 1) return r; command_print(CMD, "%d", tdo); return ERROR_OK; } COMMAND_HANDLER(esp_usb_jtag_setio_cmd) { uint32_t tdi, tms, tck, trst, srst; uint16_t d = 0; if (!priv->usb_device) return ERROR_FAIL; if (CMD_ARGC != 5) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], tdi); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], tms); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], tck); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], trst); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], srst); if (tdi) d |= VEND_JTAG_SETIO_TDI; if (tms) d |= VEND_JTAG_SETIO_TMS; if (tck) d |= VEND_JTAG_SETIO_TCK; if (trst) d |= VEND_JTAG_SETIO_TRST; if (srst) d |= VEND_JTAG_SETIO_SRST; jtag_libusb_control_transfer(priv->usb_device, 0x40, VEND_JTAG_SETIO, d, 0, NULL, 0, LIBUSB_TIMEOUT_MS); return ERROR_OK; } COMMAND_HANDLER(esp_usb_jtag_vid_pid) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], esp_usb_vid); COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], esp_usb_pid); LOG_INFO("esp_usb_jtag: VID set to 0x%x and PID to 0x%x", esp_usb_vid, esp_usb_pid); return ERROR_OK; } COMMAND_HANDLER(esp_usb_jtag_caps_descriptor) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], esp_usb_jtag_caps); LOG_INFO("esp_usb_jtag: capabilities descriptor set to 0x%x", esp_usb_jtag_caps); return ERROR_OK; } COMMAND_HANDLER(esp_usb_jtag_chip_id) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], esp_usb_target_chip_id); LOG_INFO("esp_usb_jtag: target chip id set to %d", esp_usb_target_chip_id); return ERROR_OK; } static const struct command_registration esp_usb_jtag_subcommands[] = { { .name = "tdo", .handler = &esp_usb_jtag_tdo_cmd, .mode = COMMAND_EXEC, .help = "Returns the current state of the TDO line", .usage = "", }, { .name = "setio", .handler = &esp_usb_jtag_setio_cmd, .mode = COMMAND_EXEC, .help = "Manually set the status of the output lines", .usage = "tdi tms tck trst srst" }, { .name = "vid_pid", .handler = &esp_usb_jtag_vid_pid, .mode = COMMAND_CONFIG, .help = "set vendor ID and product ID for ESP usb jtag driver", .usage = "vid pid", }, { .name = "caps_descriptor", .handler = &esp_usb_jtag_caps_descriptor, .mode = COMMAND_CONFIG, .help = "set jtag descriptor to read capabilities of ESP usb jtag driver", .usage = "descriptor", }, { .name = "chip_id", .handler = &esp_usb_jtag_chip_id, .mode = COMMAND_CONFIG, .help = "set chip_id to transfer to the bridge", .usage = "chip_id", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration esp_usb_jtag_commands[] = { { .name = "espusbjtag", .mode = COMMAND_ANY, .help = "ESP-USB-JTAG commands", .chain = esp_usb_jtag_subcommands, .usage = "", }, COMMAND_REGISTRATION_DONE }; static struct jtag_interface esp_usb_jtag_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitq_execute_queue, }; struct adapter_driver esp_usb_adapter_driver = { .name = "esp_usb_jtag", .transports = jtag_only, .commands = esp_usb_jtag_commands, .init = esp_usb_jtag_init, .quit = esp_usb_jtag_quit, .speed_div = esp_usb_jtag_speed_div, .speed = esp_usb_jtag_speed, .khz = esp_usb_jtag_khz, .jtag_ops = &esp_usb_jtag_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/ft232r.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2010 Serge Vakulenko * * serge@vak.ru * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #if IS_CYGWIN == 1 #include "windows.h" #undef LOG_ERROR #endif /* project specific includes */ #include <jtag/adapter.h> #include <jtag/interface.h> #include <jtag/commands.h> #include <helper/time_support.h> #include "libusb_helper.h" /* system includes */ #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/time.h> #include <time.h> /* * Sync bit bang mode is implemented as described in FTDI Application * Note AN232R-01: "Bit Bang Modes for the FT232R and FT245R". */ /* * USB endpoints. */ #define IN_EP 0x02 #define OUT_EP 0x81 /* Requests */ #define SIO_RESET 0 /* Reset the port */ #define SIO_MODEM_CTRL 1 /* Set the modem control register */ #define SIO_SET_FLOW_CTRL 2 /* Set flow control register */ #define SIO_SET_BAUD_RATE 3 /* Set baud rate */ #define SIO_SET_DATA 4 /* Set the data characteristics of the port */ #define SIO_POLL_MODEM_STATUS 5 #define SIO_SET_EVENT_CHAR 6 #define SIO_SET_ERROR_CHAR 7 #define SIO_SET_LATENCY_TIMER 9 #define SIO_GET_LATENCY_TIMER 10 #define SIO_SET_BITMODE 11 #define SIO_READ_PINS 12 #define SIO_READ_EEPROM 0x90 #define SIO_WRITE_EEPROM 0x91 #define SIO_ERASE_EEPROM 0x92 #define FT232R_BUF_SIZE_EXTRA 4096 static uint16_t ft232r_vid = 0x0403; /* FTDI */ static uint16_t ft232r_pid = 0x6001; /* FT232R */ static struct libusb_device_handle *adapter; static uint8_t *ft232r_output; static size_t ft232r_output_len; /** * FT232R GPIO bit number to RS232 name */ #define FT232R_BIT_COUNT 8 static char *ft232r_bit_name_array[FT232R_BIT_COUNT] = { "TXD", /* 0: pin 1 TCK output */ "RXD", /* 1: pin 5 TDI output */ "RTS", /* 2: pin 3 TDO input */ "CTS", /* 3: pin 11 TMS output */ "DTR", /* 4: pin 2 /TRST output */ "DSR", /* 5: pin 9 unused */ "DCD", /* 6: pin 10 /SYSRST output */ "RI" /* 7: pin 6 unused */ }; static int tck_gpio; /* initialized to 0 by default */ static int tdi_gpio = 1; static int tdo_gpio = 2; static int tms_gpio = 3; static int ntrst_gpio = 4; static int nsysrst_gpio = 6; static size_t ft232r_buf_size = FT232R_BUF_SIZE_EXTRA; /** 0xFFFF disables restore by default, after exit serial port will not work. * 0x15 sets TXD RTS DTR as outputs, after exit serial port will continue to work. */ static uint16_t ft232r_restore_bitmode = 0xFFFF; /** * Perform sync bitbang output/input transaction. * Before call, an array ft232r_output[] should be filled with data to send. * Counter ft232r_output_len contains the number of bytes to send. * On return, received data is put back to array ft232r_output[]. */ static int ft232r_send_recv(void) { /* FIFO TX buffer has 128 bytes. * FIFO RX buffer has 256 bytes. * First two bytes of received packet contain contain modem * and line status and are ignored. * Unfortunately, transfer sizes bigger than 64 bytes * frequently cause hang ups. */ assert(ft232r_output_len > 0); size_t total_written = 0; size_t total_read = 0; int rxfifo_free = 128; while (total_read < ft232r_output_len) { /* Write */ int bytes_to_write = ft232r_output_len - total_written; if (bytes_to_write > 64) bytes_to_write = 64; if (bytes_to_write > rxfifo_free) bytes_to_write = rxfifo_free; if (bytes_to_write) { int n; if (jtag_libusb_bulk_write(adapter, IN_EP, (char *) ft232r_output + total_written, bytes_to_write, 1000, &n) != ERROR_OK) { LOG_ERROR("usb bulk write failed"); return ERROR_JTAG_DEVICE_ERROR; } total_written += n; rxfifo_free -= n; } /* Read */ uint8_t reply[64]; int n; if (jtag_libusb_bulk_read(adapter, OUT_EP, (char *) reply, sizeof(reply), 1000, &n) != ERROR_OK) { LOG_ERROR("usb bulk read failed"); return ERROR_JTAG_DEVICE_ERROR; } if (n > 2) { /* Copy data, ignoring first 2 bytes. */ memcpy(ft232r_output + total_read, reply + 2, n - 2); int bytes_read = n - 2; total_read += bytes_read; rxfifo_free += bytes_read; if (total_read > total_written) { LOG_ERROR("read more bytes than wrote"); return ERROR_JTAG_DEVICE_ERROR; } } } ft232r_output_len = 0; return ERROR_OK; } static void ft232r_increase_buf_size(size_t new_buf_size) { uint8_t *new_buf_ptr; if (new_buf_size >= ft232r_buf_size) { new_buf_size += FT232R_BUF_SIZE_EXTRA; new_buf_ptr = realloc(ft232r_output, new_buf_size); if (new_buf_ptr) { ft232r_output = new_buf_ptr; ft232r_buf_size = new_buf_size; } } } /** * Add one TCK/TMS/TDI sample to send buffer. */ static void ft232r_write(int tck, int tms, int tdi) { unsigned out_value = (1<<ntrst_gpio) | (1<<nsysrst_gpio); if (tck) out_value |= (1<<tck_gpio); if (tms) out_value |= (1<<tms_gpio); if (tdi) out_value |= (1<<tdi_gpio); ft232r_increase_buf_size(ft232r_output_len); if (ft232r_output_len >= ft232r_buf_size) { /* FIXME: should we just execute queue here? */ LOG_ERROR("ft232r_write: buffer overflow"); return; } ft232r_output[ft232r_output_len++] = out_value; } /** * Control /TRST and /SYSRST pins. * Perform immediate bitbang transaction. */ static void ft232r_reset(int trst, int srst) { unsigned out_value = (1<<ntrst_gpio) | (1<<nsysrst_gpio); LOG_DEBUG("ft232r_reset(%d,%d)", trst, srst); if (trst == 1) out_value &= ~(1<<ntrst_gpio); /* switch /TRST low */ else if (trst == 0) out_value |= (1<<ntrst_gpio); /* switch /TRST high */ if (srst == 1) out_value &= ~(1<<nsysrst_gpio); /* switch /SYSRST low */ else if (srst == 0) out_value |= (1<<nsysrst_gpio); /* switch /SYSRST high */ ft232r_increase_buf_size(ft232r_output_len); if (ft232r_output_len >= ft232r_buf_size) { /* FIXME: should we just execute queue here? */ LOG_ERROR("ft232r_write: buffer overflow"); return; } ft232r_output[ft232r_output_len++] = out_value; ft232r_send_recv(); } static int ft232r_speed(int divisor) { int baud = (divisor == 0) ? 3000000 : (divisor == 1) ? 2000000 : 3000000 / divisor; LOG_DEBUG("ft232r_speed(%d) rate %d bits/sec", divisor, baud); if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, SIO_SET_BAUD_RATE, divisor, 0, NULL, 0, 1000) != 0) { LOG_ERROR("cannot set baud rate"); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int ft232r_init(void) { uint16_t avids[] = {ft232r_vid, 0}; uint16_t apids[] = {ft232r_pid, 0}; if (jtag_libusb_open(avids, apids, &adapter, NULL)) { const char *ft232r_serial_desc = adapter_get_required_serial(); LOG_ERROR("ft232r not found: vid=%04x, pid=%04x, serial=%s\n", ft232r_vid, ft232r_pid, (!ft232r_serial_desc) ? "[any]" : ft232r_serial_desc); return ERROR_JTAG_INIT_FAILED; } if (ft232r_restore_bitmode == 0xFFFF) /* serial port will not be restored after jtag: */ libusb_detach_kernel_driver(adapter, 0); else /* serial port will be restored after jtag: */ libusb_set_auto_detach_kernel_driver(adapter, 1); /* 1: DONT_DETACH_SIO_MODULE */ if (libusb_claim_interface(adapter, 0)) { LOG_ERROR("unable to claim interface"); return ERROR_JTAG_INIT_FAILED; } /* Reset the device. */ if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, SIO_RESET, 0, 0, NULL, 0, 1000) != 0) { LOG_ERROR("unable to reset device"); return ERROR_JTAG_INIT_FAILED; } /* Sync bit bang mode. */ if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, SIO_SET_BITMODE, (1<<tck_gpio) | (1<<tdi_gpio) | (1<<tms_gpio) | (1<<ntrst_gpio) | (1<<nsysrst_gpio) | 0x400, 0, NULL, 0, 1000) != 0) { LOG_ERROR("cannot set sync bitbang mode"); return ERROR_JTAG_INIT_FAILED; } /* Exactly 500 nsec between updates. */ unsigned divisor = 1; unsigned char latency_timer = 1; /* Frequency divisor is 14-bit non-zero value. */ if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, SIO_SET_BAUD_RATE, divisor, 0, NULL, 0, 1000) != 0) { LOG_ERROR("cannot set baud rate"); return ERROR_JTAG_INIT_FAILED; } if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, SIO_SET_LATENCY_TIMER, latency_timer, 0, NULL, 0, 1000) != 0) { LOG_ERROR("unable to set latency timer"); return ERROR_JTAG_INIT_FAILED; } ft232r_output = malloc(ft232r_buf_size); if (!ft232r_output) { LOG_ERROR("Unable to allocate memory for the buffer"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int ft232r_quit(void) { /* to restore serial port: set TXD RTS DTR as outputs, others as inputs, disable sync bit bang mode. */ if (ft232r_restore_bitmode != 0xFFFF) { if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, SIO_SET_BITMODE, ft232r_restore_bitmode, 0, NULL, 0, 1000) != 0) { LOG_ERROR("cannot set bitmode to restore serial port"); } } if (libusb_release_interface(adapter, 0) != 0) LOG_ERROR("usb release interface failed"); jtag_libusb_close(adapter); free(ft232r_output); /* free used memory */ ft232r_output = NULL; /* reset pointer to memory */ ft232r_buf_size = FT232R_BUF_SIZE_EXTRA; /* reset next initial buffer size */ return ERROR_OK; } static int ft232r_speed_div(int divisor, int *khz) { /* Maximum 3 Mbaud for bit bang mode. */ if (divisor == 0) *khz = 3000; else if (divisor == 1) *khz = 2000; else *khz = 3000 / divisor; return ERROR_OK; } static int ft232r_khz(int khz, int *divisor) { if (khz == 0) { LOG_DEBUG("RCLK not supported"); return ERROR_FAIL; } /* Calculate frequency divisor. */ if (khz > 2500) *divisor = 0; /* Special case: 3 MHz */ else if (khz > 1700) *divisor = 1; /* Special case: 2 MHz */ else { *divisor = (2*3000 / khz + 1) / 2; if (*divisor > 0x3FFF) *divisor = 0x3FFF; } return ERROR_OK; } static char *ft232r_bit_number_to_name(int bit) { if (bit >= 0 && bit < FT232R_BIT_COUNT) return ft232r_bit_name_array[bit]; return "?"; } static int ft232r_bit_name_to_number(const char *name) { int i; if (name[0] >= '0' && name[0] <= '9' && name[1] == '\0') { i = atoi(name); if (i >= 0 && i < FT232R_BIT_COUNT) return i; } for (i = 0; i < FT232R_BIT_COUNT; i++) if (strcasecmp(name, ft232r_bit_name_array[i]) == 0) return i; return -1; } COMMAND_HANDLER(ft232r_handle_vid_pid_command) { if (CMD_ARGC > 2) { LOG_WARNING("ignoring extra IDs in ft232r_vid_pid " "(maximum is 1 pair)"); CMD_ARGC = 2; } if (CMD_ARGC == 2) { COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], ft232r_vid); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], ft232r_pid); } else LOG_WARNING("incomplete ft232r_vid_pid configuration"); return ERROR_OK; } COMMAND_HANDLER(ft232r_handle_jtag_nums_command) { if (CMD_ARGC == 4) { tck_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]); tms_gpio = ft232r_bit_name_to_number(CMD_ARGV[1]); tdi_gpio = ft232r_bit_name_to_number(CMD_ARGV[2]); tdo_gpio = ft232r_bit_name_to_number(CMD_ARGV[3]); } else if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (tck_gpio < 0) return ERROR_COMMAND_SYNTAX_ERROR; if (tms_gpio < 0) return ERROR_COMMAND_SYNTAX_ERROR; if (tdi_gpio < 0) return ERROR_COMMAND_SYNTAX_ERROR; if (tdo_gpio < 0) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "FT232R nums: TCK = %d %s, TMS = %d %s, TDI = %d %s, TDO = %d %s", tck_gpio, ft232r_bit_number_to_name(tck_gpio), tms_gpio, ft232r_bit_number_to_name(tms_gpio), tdi_gpio, ft232r_bit_number_to_name(tdi_gpio), tdo_gpio, ft232r_bit_number_to_name(tdo_gpio)); return ERROR_OK; } COMMAND_HANDLER(ft232r_handle_tck_num_command) { if (CMD_ARGC == 1) tck_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]); else if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (tck_gpio < 0) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "FT232R num: TCK = %d %s", tck_gpio, ft232r_bit_number_to_name(tck_gpio)); return ERROR_OK; } COMMAND_HANDLER(ft232r_handle_tms_num_command) { if (CMD_ARGC == 1) tms_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]); else if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (tms_gpio < 0) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "FT232R num: TMS = %d %s", tms_gpio, ft232r_bit_number_to_name(tms_gpio)); return ERROR_OK; } COMMAND_HANDLER(ft232r_handle_tdo_num_command) { if (CMD_ARGC == 1) tdo_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]); else if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (tdo_gpio < 0) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "FT232R num: TDO = %d %s", tdo_gpio, ft232r_bit_number_to_name(tdo_gpio)); return ERROR_OK; } COMMAND_HANDLER(ft232r_handle_tdi_num_command) { if (CMD_ARGC == 1) tdi_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]); else if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (tdi_gpio < 0) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "FT232R num: TDI = %d %s", tdi_gpio, ft232r_bit_number_to_name(tdi_gpio)); return ERROR_OK; } COMMAND_HANDLER(ft232r_handle_trst_num_command) { if (CMD_ARGC == 1) ntrst_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]); else if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (ntrst_gpio < 0) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "FT232R num: TRST = %d %s", ntrst_gpio, ft232r_bit_number_to_name(ntrst_gpio)); return ERROR_OK; } COMMAND_HANDLER(ft232r_handle_srst_num_command) { if (CMD_ARGC == 1) nsysrst_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]); else if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (nsysrst_gpio < 0) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "FT232R num: SRST = %d %s", nsysrst_gpio, ft232r_bit_number_to_name(nsysrst_gpio)); return ERROR_OK; } COMMAND_HANDLER(ft232r_handle_restore_serial_command) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], ft232r_restore_bitmode); else if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "FT232R restore serial: 0x%04X (%s)", ft232r_restore_bitmode, ft232r_restore_bitmode == 0xFFFF ? "disabled" : "enabled"); return ERROR_OK; } static const struct command_registration ft232r_subcommand_handlers[] = { { .name = "vid_pid", .handler = ft232r_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "USB VID and PID of the adapter", .usage = "vid pid", }, { .name = "jtag_nums", .handler = ft232r_handle_jtag_nums_command, .mode = COMMAND_CONFIG, .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)", .usage = "<0-7|TXD-RI> <0-7|TXD-RI> <0-7|TXD-RI> <0-7|TXD-RI>", }, { .name = "tck_num", .handler = ft232r_handle_tck_num_command, .mode = COMMAND_CONFIG, .help = "gpio number for tck.", .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", }, { .name = "tms_num", .handler = ft232r_handle_tms_num_command, .mode = COMMAND_CONFIG, .help = "gpio number for tms.", .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", }, { .name = "tdo_num", .handler = ft232r_handle_tdo_num_command, .mode = COMMAND_CONFIG, .help = "gpio number for tdo.", .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", }, { .name = "tdi_num", .handler = ft232r_handle_tdi_num_command, .mode = COMMAND_CONFIG, .help = "gpio number for tdi.", .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", }, { .name = "srst_num", .handler = ft232r_handle_srst_num_command, .mode = COMMAND_CONFIG, .help = "gpio number for srst.", .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", }, { .name = "trst_num", .handler = ft232r_handle_trst_num_command, .mode = COMMAND_CONFIG, .help = "gpio number for trst.", .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", }, { .name = "restore_serial", .handler = ft232r_handle_restore_serial_command, .mode = COMMAND_CONFIG, .help = "bitmode control word that restores serial port.", .usage = "bitmode_control_word", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration ft232r_command_handlers[] = { { .name = "ft232r", .mode = COMMAND_ANY, .help = "perform ft232r management", .chain = ft232r_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; /* * Synchronous bitbang protocol implementation. */ static void syncbb_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } static void syncbb_state_move(int skip) { int i = 0, tms = 0; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); for (i = skip; i < tms_count; i++) { tms = (tms_scan >> i) & 1; ft232r_write(0, tms, 0); ft232r_write(1, tms, 0); } ft232r_write(0, tms, 0); tap_set_state(tap_get_end_state()); } /** * Clock a bunch of TMS (or SWDIO) transitions, to change the JTAG * (or SWD) state machine. */ static int syncbb_execute_tms(struct jtag_command *cmd) { unsigned num_bits = cmd->cmd.tms->num_bits; const uint8_t *bits = cmd->cmd.tms->bits; LOG_DEBUG_IO("TMS: %d bits", num_bits); int tms = 0; for (unsigned i = 0; i < num_bits; i++) { tms = ((bits[i/8] >> (i % 8)) & 1); ft232r_write(0, tms, 0); ft232r_write(1, tms, 0); } ft232r_write(0, tms, 0); return ERROR_OK; } static void syncbb_path_move(struct pathmove_command *cmd) { int num_states = cmd->num_states; int state_count; int tms = 0; state_count = 0; while (num_states) { if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) { tms = 0; } else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count]) { tms = 1; } else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(cmd->path[state_count])); exit(-1); } ft232r_write(0, tms, 0); ft232r_write(1, tms, 0); tap_set_state(cmd->path[state_count]); state_count++; num_states--; } ft232r_write(0, tms, 0); tap_set_end_state(tap_get_state()); } static void syncbb_runtest(int num_cycles) { int i; tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { syncbb_end_state(TAP_IDLE); syncbb_state_move(0); } /* execute num_cycles */ for (i = 0; i < num_cycles; i++) { ft232r_write(0, 0, 0); ft232r_write(1, 0, 0); } ft232r_write(0, 0, 0); /* finish in end_state */ syncbb_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) syncbb_state_move(0); } /** * Function syncbb_stableclocks * issues a number of clock cycles while staying in a stable state. * Because the TMS value required to stay in the RESET state is a 1, whereas * the TMS value required to stay in any of the other stable states is a 0, * this function checks the current stable state to decide on the value of TMS * to use. */ static void syncbb_stableclocks(int num_cycles) { int tms = (tap_get_state() == TAP_RESET ? 1 : 0); int i; /* send num_cycles clocks onto the cable */ for (i = 0; i < num_cycles; i++) { ft232r_write(1, tms, 0); ft232r_write(0, tms, 0); } } static void syncbb_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size) { tap_state_t saved_end_state = tap_get_end_state(); int bit_cnt, bit0_index; if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) || (ir_scan && (tap_get_state() == TAP_IRSHIFT)))) { if (ir_scan) syncbb_end_state(TAP_IRSHIFT); else syncbb_end_state(TAP_DRSHIFT); syncbb_state_move(0); syncbb_end_state(saved_end_state); } bit0_index = ft232r_output_len; for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) { int tms = (bit_cnt == scan_size-1) ? 1 : 0; int tdi; int bytec = bit_cnt/8; int bcval = 1 << (bit_cnt % 8); /* if we're just reading the scan, but don't care about the output * default to outputting 'low', this also makes valgrind traces more readable, * as it removes the dependency on an uninitialised value */ tdi = 0; if ((type != SCAN_IN) && (buffer[bytec] & bcval)) tdi = 1; ft232r_write(0, tms, tdi); ft232r_write(1, tms, tdi); } if (tap_get_state() != tap_get_end_state()) { /* we *KNOW* the above loop transitioned out of * the shift state, so we skip the first state * and move directly to the end state. */ syncbb_state_move(1); } ft232r_send_recv(); if (type != SCAN_OUT) for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) { int bytec = bit_cnt/8; int bcval = 1 << (bit_cnt % 8); int val = ft232r_output[bit0_index + bit_cnt*2 + 1]; if (val & (1<<tdo_gpio)) buffer[bytec] |= bcval; else buffer[bytec] &= ~bcval; } } static int syncbb_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; int retval; /* return ERROR_OK, unless a jtag_read_buffer returns a failed check * that wasn't handled by a caller-provided error handler */ retval = ERROR_OK; /* ft232r_blink(1);*/ while (cmd) { switch (cmd->type) { case JTAG_RESET: LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); if ((cmd->cmd.reset->trst == 1) || (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) { tap_set_state(TAP_RESET); } ft232r_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); syncbb_end_state(cmd->cmd.runtest->end_state); syncbb_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_STABLECLOCKS: /* this is only allowed while in a stable state. A check for a stable * state was done in jtag_add_clocks() */ syncbb_stableclocks(cmd->cmd.stableclocks->num_cycles); break; case JTAG_TLR_RESET: /* renamed from JTAG_STATEMOVE */ LOG_DEBUG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); syncbb_end_state(cmd->cmd.statemove->end_state); syncbb_state_move(0); break; case JTAG_PATHMOVE: LOG_DEBUG_IO("pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states, tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); syncbb_path_move(cmd->cmd.pathmove); break; case JTAG_SCAN: LOG_DEBUG_IO("%s scan end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", tap_state_name(cmd->cmd.scan->end_state)); syncbb_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); syncbb_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; free(buffer); break; case JTAG_SLEEP: LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); jtag_sleep(cmd->cmd.sleep->us); break; case JTAG_TMS: retval = syncbb_execute_tms(cmd); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } if (ft232r_output_len > 0) ft232r_send_recv(); cmd = cmd->next; } /* ft232r_blink(0);*/ return retval; } static struct jtag_interface ft232r_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = syncbb_execute_queue, }; struct adapter_driver ft232r_adapter_driver = { .name = "ft232r", .transports = jtag_only, .commands = ft232r_command_handlers, .init = ft232r_init, .quit = ft232r_quit, .speed = ft232r_speed, .khz = ft232r_khz, .speed_div = ft232r_speed_div, .jtag_ops = &ft232r_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/ftdi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /************************************************************************** * Copyright (C) 2012 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * ***************************************************************************/ /** * @file * JTAG adapters based on the FT2232 full and high speed USB parts are * popular low cost JTAG debug solutions. Many FT2232 based JTAG adapters * are discrete, but development boards may integrate them as alternatives * to more capable (and expensive) third party JTAG pods. * * JTAG uses only one of the two communications channels ("MPSSE engines") * on these devices. Adapters based on FT4232 parts have four ports/channels * (A/B/C/D), instead of just two (A/B). * * Especially on development boards integrating one of these chips (as * opposed to discrete pods/dongles), the additional channels can be used * for a variety of purposes, but OpenOCD only uses one channel at a time. * * - As a USB-to-serial adapter for the target's console UART ... * which may be able to support ROM boot loaders that load initial * firmware images to flash (or SRAM). * * - On systems which support ARM's SWD in addition to JTAG, or instead * of it, that second port can be used for reading SWV/SWO trace data. * * - Additional JTAG links, e.g. to a CPLD or * FPGA. * * FT2232 based JTAG adapters are "dumb" not "smart", because most JTAG * request/response interactions involve round trips over the USB link. * A "smart" JTAG adapter has intelligence close to the scan chain, so it * can for example poll quickly for a status change (usually taking on the * order of microseconds not milliseconds) before beginning a queued * transaction which require the previous one to have completed. * * There are dozens of adapters of this type, differing in details which * this driver needs to understand. Those "layout" details are required * as part of FT2232 driver configuration. * * This code uses information contained in the MPSSE specification which was * found here: * https://www.ftdichip.com/Support/Documents/AppNotes/AN2232C-01_MPSSE_Cmnd.pdf * Hereafter this is called the "MPSSE Spec". * * The datasheet for the ftdichip.com's FT2232H part is here: * https://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT2232H.pdf * * Also note the issue with code 0x4b (clock data to TMS) noted in * http://developer.intra2net.com/mailarchive/html/libftdi/2009/msg00292.html * which can affect longer JTAG state paths. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include <jtag/adapter.h> #include <jtag/interface.h> #include <jtag/swd.h> #include <transport/transport.h> #include <helper/time_support.h> #include <helper/log.h> #include <helper/nvp.h> #if IS_CYGWIN == 1 #include <windows.h> #endif #include <assert.h> /* FTDI access library includes */ #include "mpsse.h" #define JTAG_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT) #define JTAG_MODE_ALT (LSB_FIRST | NEG_EDGE_IN | NEG_EDGE_OUT) #define SWD_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT) static char *ftdi_device_desc; static uint8_t ftdi_channel; static uint8_t ftdi_jtag_mode = JTAG_MODE; static bool swd_mode; #define MAX_USB_IDS 8 /* vid = pid = 0 marks the end of the list */ static uint16_t ftdi_vid[MAX_USB_IDS + 1] = { 0 }; static uint16_t ftdi_pid[MAX_USB_IDS + 1] = { 0 }; static struct mpsse_ctx *mpsse_ctx; struct signal { const char *name; uint16_t data_mask; uint16_t input_mask; uint16_t oe_mask; bool invert_data; bool invert_input; bool invert_oe; struct signal *next; }; static struct signal *signals; /* FIXME: Where to store per-instance data? We need an SWD context. */ static struct swd_cmd_queue_entry { uint8_t cmd; uint32_t *dst; uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)]; } *swd_cmd_queue; static size_t swd_cmd_queue_length; static size_t swd_cmd_queue_alloced; static int queued_retval; static int freq; static uint16_t output; static uint16_t direction; static uint16_t jtag_output_init; static uint16_t jtag_direction_init; static int ftdi_swd_switch_seq(enum swd_special_seq seq); static struct signal *find_signal_by_name(const char *name) { for (struct signal *sig = signals; sig; sig = sig->next) { if (strcmp(name, sig->name) == 0) return sig; } return NULL; } static struct signal *create_signal(const char *name) { struct signal **psig = &signals; while (*psig) psig = &(*psig)->next; *psig = calloc(1, sizeof(**psig)); if (!*psig) return NULL; (*psig)->name = strdup(name); if (!(*psig)->name) { free(*psig); *psig = NULL; } return *psig; } static int ftdi_set_signal(const struct signal *s, char value) { bool data; bool oe; if (s->data_mask == 0 && s->oe_mask == 0) { LOG_ERROR("interface doesn't provide signal '%s'", s->name); return ERROR_FAIL; } switch (value) { case '0': data = s->invert_data; oe = !s->invert_oe; break; case '1': if (s->data_mask == 0) { LOG_ERROR("interface can't drive '%s' high", s->name); return ERROR_FAIL; } data = !s->invert_data; oe = !s->invert_oe; break; case 'z': case 'Z': if (s->oe_mask == 0) { LOG_ERROR("interface can't tri-state '%s'", s->name); return ERROR_FAIL; } data = s->invert_data; oe = s->invert_oe; break; default: LOG_ERROR("invalid signal level specifier \'%c\'(0x%02x)", value, value); return ERROR_FAIL; } uint16_t old_output = output; uint16_t old_direction = direction; output = data ? output | s->data_mask : output & ~s->data_mask; if (s->oe_mask == s->data_mask) direction = oe ? direction | s->oe_mask : direction & ~s->oe_mask; else output = oe ? output | s->oe_mask : output & ~s->oe_mask; if ((output & 0xff) != (old_output & 0xff) || (direction & 0xff) != (old_direction & 0xff)) mpsse_set_data_bits_low_byte(mpsse_ctx, output & 0xff, direction & 0xff); if ((output >> 8 != old_output >> 8) || (direction >> 8 != old_direction >> 8)) mpsse_set_data_bits_high_byte(mpsse_ctx, output >> 8, direction >> 8); return ERROR_OK; } static int ftdi_get_signal(const struct signal *s, uint16_t *value_out) { uint8_t data_low = 0; uint8_t data_high = 0; if (s->input_mask == 0) { LOG_ERROR("interface doesn't provide signal '%s'", s->name); return ERROR_FAIL; } if (s->input_mask & 0xff) mpsse_read_data_bits_low_byte(mpsse_ctx, &data_low); if (s->input_mask >> 8) mpsse_read_data_bits_high_byte(mpsse_ctx, &data_high); mpsse_flush(mpsse_ctx); *value_out = (((uint16_t)data_high) << 8) | data_low; if (s->invert_input) *value_out = ~(*value_out); *value_out &= s->input_mask; return ERROR_OK; } /** * Function move_to_state * moves the TAP controller from the current state to a * \a goal_state through a path given by tap_get_tms_path(). State transition * logging is performed by delegation to clock_tms(). * * @param goal_state is the destination state for the move. */ static void move_to_state(tap_state_t goal_state) { tap_state_t start_state = tap_get_state(); /* goal_state is 1/2 of a tuple/pair of states which allow convenient lookup of the required TMS pattern to move to this state from the start state. */ /* do the 2 lookups */ uint8_t tms_bits = tap_get_tms_path(start_state, goal_state); int tms_count = tap_get_tms_path_len(start_state, goal_state); assert(tms_count <= 8); LOG_DEBUG_IO("start=%s goal=%s", tap_state_name(start_state), tap_state_name(goal_state)); /* Track state transitions step by step */ for (int i = 0; i < tms_count; i++) tap_set_state(tap_state_transition(tap_get_state(), (tms_bits >> i) & 1)); mpsse_clock_tms_cs_out(mpsse_ctx, &tms_bits, 0, tms_count, false, ftdi_jtag_mode); } static int ftdi_speed(int speed) { int retval; retval = mpsse_set_frequency(mpsse_ctx, speed); if (retval < 0) { LOG_ERROR("couldn't set FTDI TCK speed"); return retval; } if (!swd_mode && speed >= 10000000 && ftdi_jtag_mode != JTAG_MODE_ALT) LOG_INFO("ftdi: if you experience problems at higher adapter clocks, try " "the command \"ftdi tdo_sample_edge falling\""); return ERROR_OK; } static int ftdi_speed_div(int speed, int *khz) { *khz = speed / 1000; return ERROR_OK; } static int ftdi_khz(int khz, int *jtag_speed) { if (khz == 0 && !mpsse_is_high_speed(mpsse_ctx)) { LOG_DEBUG("RCLK not supported"); return ERROR_FAIL; } *jtag_speed = khz * 1000; return ERROR_OK; } static void ftdi_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %s is not a stable end state", tap_state_name(state)); exit(-1); } } static void ftdi_execute_runtest(struct jtag_command *cmd) { int i; uint8_t zero = 0; LOG_DEBUG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); if (tap_get_state() != TAP_IDLE) move_to_state(TAP_IDLE); /* TODO: Reuse ftdi_execute_stableclocks */ i = cmd->cmd.runtest->num_cycles; while (i > 0) { /* there are no state transitions in this code, so omit state tracking */ unsigned this_len = i > 7 ? 7 : i; mpsse_clock_tms_cs_out(mpsse_ctx, &zero, 0, this_len, false, ftdi_jtag_mode); i -= this_len; } ftdi_end_state(cmd->cmd.runtest->end_state); if (tap_get_state() != tap_get_end_state()) move_to_state(tap_get_end_state()); LOG_DEBUG_IO("runtest: %i, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(tap_get_end_state())); } static void ftdi_execute_statemove(struct jtag_command *cmd) { LOG_DEBUG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); ftdi_end_state(cmd->cmd.statemove->end_state); /* shortest-path move to desired end state */ if (tap_get_state() != tap_get_end_state() || tap_get_end_state() == TAP_RESET) move_to_state(tap_get_end_state()); } /** * Clock a bunch of TMS (or SWDIO) transitions, to change the JTAG * (or SWD) state machine. REVISIT: Not the best method, perhaps. */ static void ftdi_execute_tms(struct jtag_command *cmd) { LOG_DEBUG_IO("TMS: %d bits", cmd->cmd.tms->num_bits); /* TODO: Missing tap state tracking, also missing from ft2232.c! */ mpsse_clock_tms_cs_out(mpsse_ctx, cmd->cmd.tms->bits, 0, cmd->cmd.tms->num_bits, false, ftdi_jtag_mode); } static void ftdi_execute_pathmove(struct jtag_command *cmd) { tap_state_t *path = cmd->cmd.pathmove->path; int num_states = cmd->cmd.pathmove->num_states; LOG_DEBUG_IO("pathmove: %i states, current: %s end: %s", num_states, tap_state_name(tap_get_state()), tap_state_name(path[num_states-1])); int state_count = 0; unsigned bit_count = 0; uint8_t tms_byte = 0; LOG_DEBUG_IO("-"); /* this loop verifies that the path is legal and logs each state in the path */ while (num_states--) { /* either TMS=0 or TMS=1 must work ... */ if (tap_state_transition(tap_get_state(), false) == path[state_count]) buf_set_u32(&tms_byte, bit_count++, 1, 0x0); else if (tap_state_transition(tap_get_state(), true) == path[state_count]) { buf_set_u32(&tms_byte, bit_count++, 1, 0x1); /* ... or else the caller goofed BADLY */ } else { LOG_ERROR("BUG: %s -> %s isn't a valid " "TAP state transition", tap_state_name(tap_get_state()), tap_state_name(path[state_count])); exit(-1); } tap_set_state(path[state_count]); state_count++; if (bit_count == 7 || num_states == 0) { mpsse_clock_tms_cs_out(mpsse_ctx, &tms_byte, 0, bit_count, false, ftdi_jtag_mode); bit_count = 0; } } tap_set_end_state(tap_get_state()); } static void ftdi_execute_scan(struct jtag_command *cmd) { LOG_DEBUG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN", jtag_scan_type(cmd->cmd.scan)); /* Make sure there are no trailing fields with num_bits == 0, or the logic below will fail. */ while (cmd->cmd.scan->num_fields > 0 && cmd->cmd.scan->fields[cmd->cmd.scan->num_fields - 1].num_bits == 0) { cmd->cmd.scan->num_fields--; LOG_DEBUG_IO("discarding trailing empty field"); } if (cmd->cmd.scan->num_fields == 0) { LOG_DEBUG_IO("empty scan, doing nothing"); return; } if (cmd->cmd.scan->ir_scan) { if (tap_get_state() != TAP_IRSHIFT) move_to_state(TAP_IRSHIFT); } else { if (tap_get_state() != TAP_DRSHIFT) move_to_state(TAP_DRSHIFT); } ftdi_end_state(cmd->cmd.scan->end_state); struct scan_field *field = cmd->cmd.scan->fields; unsigned scan_size = 0; for (int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) { scan_size += field->num_bits; LOG_DEBUG_IO("%s%s field %d/%d %d bits", field->in_value ? "in" : "", field->out_value ? "out" : "", i, cmd->cmd.scan->num_fields, field->num_bits); if (i == cmd->cmd.scan->num_fields - 1 && tap_get_state() != tap_get_end_state()) { /* Last field, and we're leaving IRSHIFT/DRSHIFT. Clock last bit during tap * movement. This last field can't have length zero, it was checked above. */ mpsse_clock_data(mpsse_ctx, field->out_value, 0, field->in_value, 0, field->num_bits - 1, ftdi_jtag_mode); uint8_t last_bit = 0; if (field->out_value) bit_copy(&last_bit, 0, field->out_value, field->num_bits - 1, 1); /* If endstate is TAP_IDLE, clock out 1-1-0 (->EXIT1 ->UPDATE ->IDLE) * Otherwise, clock out 1-0 (->EXIT1 ->PAUSE) */ uint8_t tms_bits = 0x03; mpsse_clock_tms_cs(mpsse_ctx, &tms_bits, 0, field->in_value, field->num_bits - 1, 1, last_bit, ftdi_jtag_mode); tap_set_state(tap_state_transition(tap_get_state(), 1)); if (tap_get_end_state() == TAP_IDLE) { mpsse_clock_tms_cs_out(mpsse_ctx, &tms_bits, 1, 2, last_bit, ftdi_jtag_mode); tap_set_state(tap_state_transition(tap_get_state(), 1)); tap_set_state(tap_state_transition(tap_get_state(), 0)); } else { mpsse_clock_tms_cs_out(mpsse_ctx, &tms_bits, 2, 1, last_bit, ftdi_jtag_mode); tap_set_state(tap_state_transition(tap_get_state(), 0)); } } else mpsse_clock_data(mpsse_ctx, field->out_value, 0, field->in_value, 0, field->num_bits, ftdi_jtag_mode); } if (tap_get_state() != tap_get_end_state()) move_to_state(tap_get_end_state()); LOG_DEBUG_IO("%s scan, %i bits, end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, tap_state_name(tap_get_end_state())); } static int ftdi_reset(int trst, int srst) { struct signal *sig_ntrst = find_signal_by_name("nTRST"); struct signal *sig_nsrst = find_signal_by_name("nSRST"); LOG_DEBUG_IO("reset trst: %i srst %i", trst, srst); if (!swd_mode) { if (trst == 1) { if (sig_ntrst) ftdi_set_signal(sig_ntrst, '0'); else LOG_ERROR("Can't assert TRST: nTRST signal is not defined"); } else if (sig_ntrst && jtag_get_reset_config() & RESET_HAS_TRST && trst == 0) { if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN) ftdi_set_signal(sig_ntrst, 'z'); else ftdi_set_signal(sig_ntrst, '1'); } } if (srst == 1) { if (sig_nsrst) ftdi_set_signal(sig_nsrst, '0'); else LOG_ERROR("Can't assert SRST: nSRST signal is not defined"); } else if (sig_nsrst && jtag_get_reset_config() & RESET_HAS_SRST && srst == 0) { if (jtag_get_reset_config() & RESET_SRST_PUSH_PULL) ftdi_set_signal(sig_nsrst, '1'); else ftdi_set_signal(sig_nsrst, 'z'); } return mpsse_flush(mpsse_ctx); } static void ftdi_execute_sleep(struct jtag_command *cmd) { LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); mpsse_flush(mpsse_ctx); jtag_sleep(cmd->cmd.sleep->us); LOG_DEBUG_IO("sleep %" PRIu32 " usec while in %s", cmd->cmd.sleep->us, tap_state_name(tap_get_state())); } static void ftdi_execute_stableclocks(struct jtag_command *cmd) { /* this is only allowed while in a stable state. A check for a stable * state was done in jtag_add_clocks() */ int num_cycles = cmd->cmd.stableclocks->num_cycles; /* 7 bits of either ones or zeros. */ uint8_t tms = tap_get_state() == TAP_RESET ? 0x7f : 0x00; /* TODO: Use mpsse_clock_data with in=out=0 for this, if TMS can be set to * the correct level and remain there during the scan */ while (num_cycles > 0) { /* there are no state transitions in this code, so omit state tracking */ unsigned this_len = num_cycles > 7 ? 7 : num_cycles; mpsse_clock_tms_cs_out(mpsse_ctx, &tms, 0, this_len, false, ftdi_jtag_mode); num_cycles -= this_len; } LOG_DEBUG_IO("clocks %i while in %s", cmd->cmd.stableclocks->num_cycles, tap_state_name(tap_get_state())); } static void ftdi_execute_command(struct jtag_command *cmd) { switch (cmd->type) { case JTAG_RUNTEST: ftdi_execute_runtest(cmd); break; case JTAG_TLR_RESET: ftdi_execute_statemove(cmd); break; case JTAG_PATHMOVE: ftdi_execute_pathmove(cmd); break; case JTAG_SCAN: ftdi_execute_scan(cmd); break; case JTAG_SLEEP: ftdi_execute_sleep(cmd); break; case JTAG_STABLECLOCKS: ftdi_execute_stableclocks(cmd); break; case JTAG_TMS: ftdi_execute_tms(cmd); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered: %d", cmd->type); break; } } static int ftdi_execute_queue(void) { /* blink, if the current layout has that feature */ struct signal *led = find_signal_by_name("LED"); if (led) ftdi_set_signal(led, '1'); for (struct jtag_command *cmd = jtag_command_queue; cmd; cmd = cmd->next) { /* fill the write buffer with the desired command */ ftdi_execute_command(cmd); } if (led) ftdi_set_signal(led, '0'); int retval = mpsse_flush(mpsse_ctx); if (retval != ERROR_OK) LOG_ERROR("error while flushing MPSSE queue: %d", retval); return retval; } static int ftdi_initialize(void) { if (tap_get_tms_path_len(TAP_IRPAUSE, TAP_IRPAUSE) == 7) LOG_DEBUG("ftdi interface using 7 step jtag state transitions"); else LOG_DEBUG("ftdi interface using shortest path jtag state transitions"); if (!ftdi_vid[0] && !ftdi_pid[0]) { LOG_ERROR("Please specify ftdi vid_pid"); return ERROR_JTAG_INIT_FAILED; } mpsse_ctx = mpsse_open(ftdi_vid, ftdi_pid, ftdi_device_desc, adapter_get_required_serial(), adapter_usb_get_location(), ftdi_channel); if (!mpsse_ctx) return ERROR_JTAG_INIT_FAILED; output = jtag_output_init; direction = jtag_direction_init; if (swd_mode) { struct signal *sig = find_signal_by_name("SWD_EN"); if (!sig) { LOG_ERROR("SWD mode is active but SWD_EN signal is not defined"); return ERROR_JTAG_INIT_FAILED; } /* A dummy SWD_EN would have zero mask */ if (sig->data_mask) ftdi_set_signal(sig, '1'); } mpsse_set_data_bits_low_byte(mpsse_ctx, output & 0xff, direction & 0xff); mpsse_set_data_bits_high_byte(mpsse_ctx, output >> 8, direction >> 8); mpsse_loopback_config(mpsse_ctx, false); freq = mpsse_set_frequency(mpsse_ctx, adapter_get_speed_khz() * 1000); return mpsse_flush(mpsse_ctx); } static int ftdi_quit(void) { mpsse_close(mpsse_ctx); struct signal *sig = signals; while (sig) { struct signal *next = sig->next; free((void *)sig->name); free(sig); sig = next; } free(ftdi_device_desc); free(swd_cmd_queue); return ERROR_OK; } COMMAND_HANDLER(ftdi_handle_device_desc_command) { if (CMD_ARGC == 1) { free(ftdi_device_desc); ftdi_device_desc = strdup(CMD_ARGV[0]); } else { LOG_ERROR("expected exactly one argument to ftdi device_desc <description>"); } return ERROR_OK; } COMMAND_HANDLER(ftdi_handle_channel_command) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], ftdi_channel); else return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } COMMAND_HANDLER(ftdi_handle_layout_init_command) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], jtag_output_init); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], jtag_direction_init); return ERROR_OK; } COMMAND_HANDLER(ftdi_handle_layout_signal_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; bool invert_data = false; uint16_t data_mask = 0; bool invert_input = false; uint16_t input_mask = 0; bool invert_oe = false; uint16_t oe_mask = 0; for (unsigned i = 1; i < CMD_ARGC; i += 2) { if (strcmp("-data", CMD_ARGV[i]) == 0) { invert_data = false; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], data_mask); } else if (strcmp("-ndata", CMD_ARGV[i]) == 0) { invert_data = true; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], data_mask); } else if (strcmp("-input", CMD_ARGV[i]) == 0) { invert_input = false; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], input_mask); } else if (strcmp("-ninput", CMD_ARGV[i]) == 0) { invert_input = true; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], input_mask); } else if (strcmp("-oe", CMD_ARGV[i]) == 0) { invert_oe = false; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], oe_mask); } else if (strcmp("-noe", CMD_ARGV[i]) == 0) { invert_oe = true; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], oe_mask); } else if (!strcmp("-alias", CMD_ARGV[i]) || !strcmp("-nalias", CMD_ARGV[i])) { if (!strcmp("-nalias", CMD_ARGV[i])) { invert_data = true; invert_input = true; } struct signal *sig = find_signal_by_name(CMD_ARGV[i + 1]); if (!sig) { LOG_ERROR("signal %s is not defined", CMD_ARGV[i + 1]); return ERROR_FAIL; } data_mask = sig->data_mask; input_mask = sig->input_mask; oe_mask = sig->oe_mask; invert_input ^= sig->invert_input; invert_oe = sig->invert_oe; invert_data ^= sig->invert_data; } else { LOG_ERROR("unknown option '%s'", CMD_ARGV[i]); return ERROR_COMMAND_SYNTAX_ERROR; } } struct signal *sig; sig = find_signal_by_name(CMD_ARGV[0]); if (!sig) sig = create_signal(CMD_ARGV[0]); if (!sig) { LOG_ERROR("failed to create signal %s", CMD_ARGV[0]); return ERROR_FAIL; } sig->invert_data = invert_data; sig->data_mask = data_mask; sig->invert_input = invert_input; sig->input_mask = input_mask; sig->invert_oe = invert_oe; sig->oe_mask = oe_mask; return ERROR_OK; } COMMAND_HANDLER(ftdi_handle_set_signal_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct signal *sig; sig = find_signal_by_name(CMD_ARGV[0]); if (!sig) { LOG_ERROR("interface configuration doesn't define signal '%s'", CMD_ARGV[0]); return ERROR_FAIL; } switch (*CMD_ARGV[1]) { case '0': case '1': case 'z': case 'Z': /* single character level specifier only */ if (CMD_ARGV[1][1] == '\0') { ftdi_set_signal(sig, *CMD_ARGV[1]); break; } /* fallthrough */ default: LOG_ERROR("unknown signal level '%s', use 0, 1 or z", CMD_ARGV[1]); return ERROR_COMMAND_SYNTAX_ERROR; } return mpsse_flush(mpsse_ctx); } COMMAND_HANDLER(ftdi_handle_get_signal_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct signal *sig; uint16_t sig_data = 0; sig = find_signal_by_name(CMD_ARGV[0]); if (!sig) { LOG_ERROR("interface configuration doesn't define signal '%s'", CMD_ARGV[0]); return ERROR_FAIL; } int ret = ftdi_get_signal(sig, &sig_data); if (ret != ERROR_OK) return ret; LOG_USER("Signal %s = %#06x", sig->name, sig_data); return ERROR_OK; } COMMAND_HANDLER(ftdi_handle_vid_pid_command) { if (CMD_ARGC > MAX_USB_IDS * 2) { LOG_WARNING("ignoring extra IDs in ftdi vid_pid " "(maximum is %d pairs)", MAX_USB_IDS); CMD_ARGC = MAX_USB_IDS * 2; } if (CMD_ARGC < 2 || (CMD_ARGC & 1)) { LOG_WARNING("incomplete ftdi vid_pid configuration directive"); if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; /* remove the incomplete trailing id */ CMD_ARGC -= 1; } unsigned i; for (i = 0; i < CMD_ARGC; i += 2) { COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], ftdi_vid[i >> 1]); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], ftdi_pid[i >> 1]); } /* * Explicitly terminate, in case there are multiples instances of * ftdi vid_pid. */ ftdi_vid[i >> 1] = ftdi_pid[i >> 1] = 0; return ERROR_OK; } COMMAND_HANDLER(ftdi_handle_tdo_sample_edge_command) { const struct nvp *n; static const struct nvp nvp_ftdi_jtag_modes[] = { { .name = "rising", .value = JTAG_MODE }, { .name = "falling", .value = JTAG_MODE_ALT }, { .name = NULL, .value = -1 }, }; if (CMD_ARGC > 0) { n = nvp_name2value(nvp_ftdi_jtag_modes, CMD_ARGV[0]); if (!n->name) return ERROR_COMMAND_SYNTAX_ERROR; ftdi_jtag_mode = n->value; } n = nvp_value2name(nvp_ftdi_jtag_modes, ftdi_jtag_mode); command_print(CMD, "ftdi samples TDO on %s edge of TCK", n->name); return ERROR_OK; } static const struct command_registration ftdi_subcommand_handlers[] = { { .name = "device_desc", .handler = &ftdi_handle_device_desc_command, .mode = COMMAND_CONFIG, .help = "set the USB device description of the FTDI device", .usage = "description_string", }, { .name = "channel", .handler = &ftdi_handle_channel_command, .mode = COMMAND_CONFIG, .help = "set the channel of the FTDI device that is used as JTAG", .usage = "(0-3)", }, { .name = "layout_init", .handler = &ftdi_handle_layout_init_command, .mode = COMMAND_CONFIG, .help = "initialize the FTDI GPIO signals used " "to control output-enables and reset signals", .usage = "data direction", }, { .name = "layout_signal", .handler = &ftdi_handle_layout_signal_command, .mode = COMMAND_ANY, .help = "define a signal controlled by one or more FTDI GPIO as data " "and/or output enable", .usage = "name [-data mask|-ndata mask] [-oe mask|-noe mask] [-alias|-nalias name]", }, { .name = "set_signal", .handler = &ftdi_handle_set_signal_command, .mode = COMMAND_EXEC, .help = "control a layout-specific signal", .usage = "name (1|0|z)", }, { .name = "get_signal", .handler = &ftdi_handle_get_signal_command, .mode = COMMAND_EXEC, .help = "read the value of a layout-specific signal", .usage = "name", }, { .name = "vid_pid", .handler = &ftdi_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "the vendor ID and product ID of the FTDI device", .usage = "(vid pid)*", }, { .name = "tdo_sample_edge", .handler = &ftdi_handle_tdo_sample_edge_command, .mode = COMMAND_ANY, .help = "set which TCK clock edge is used for sampling TDO " "- default is rising-edge (Setting to falling-edge may " "allow signalling speed increase)", .usage = "(rising|falling)", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration ftdi_command_handlers[] = { { .name = "ftdi", .mode = COMMAND_ANY, .help = "perform ftdi management", .chain = ftdi_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static int create_default_signal(const char *name, uint16_t data_mask) { struct signal *sig = create_signal(name); if (!sig) { LOG_ERROR("failed to create signal %s", name); return ERROR_FAIL; } sig->invert_data = false; sig->data_mask = data_mask; sig->invert_oe = false; sig->oe_mask = 0; return ERROR_OK; } static int create_signals(void) { if (create_default_signal("TCK", 0x01) != ERROR_OK) return ERROR_FAIL; if (create_default_signal("TDI", 0x02) != ERROR_OK) return ERROR_FAIL; if (create_default_signal("TDO", 0x04) != ERROR_OK) return ERROR_FAIL; if (create_default_signal("TMS", 0x08) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int ftdi_swd_init(void) { LOG_INFO("FTDI SWD mode enabled"); swd_mode = true; if (create_signals() != ERROR_OK) return ERROR_FAIL; swd_cmd_queue_alloced = 10; swd_cmd_queue = malloc(swd_cmd_queue_alloced * sizeof(*swd_cmd_queue)); return swd_cmd_queue ? ERROR_OK : ERROR_FAIL; } static void ftdi_swd_swdio_en(bool enable) { struct signal *oe = find_signal_by_name("SWDIO_OE"); if (oe) { if (oe->data_mask) ftdi_set_signal(oe, enable ? '1' : '0'); else { /* Sets TDI/DO pin to input during rx when both pins are connected to SWDIO */ if (enable) direction |= jtag_direction_init & 0x0002U; else direction &= ~0x0002U; mpsse_set_data_bits_low_byte(mpsse_ctx, output & 0xff, direction & 0xff); } } } /** * Flush the MPSSE queue and process the SWD transaction queue * @return */ static int ftdi_swd_run_queue(void) { LOG_DEBUG_IO("Executing %zu queued transactions", swd_cmd_queue_length); int retval; struct signal *led = find_signal_by_name("LED"); if (queued_retval != ERROR_OK) { LOG_DEBUG_IO("Skipping due to previous errors: %d", queued_retval); goto skip; } /* A transaction must be followed by another transaction or at least 8 idle cycles to * ensure that data is clocked through the AP. */ mpsse_clock_data_out(mpsse_ctx, NULL, 0, 8, SWD_MODE); /* Terminate the "blink", if the current layout has that feature */ if (led) ftdi_set_signal(led, '0'); queued_retval = mpsse_flush(mpsse_ctx); if (queued_retval != ERROR_OK) { LOG_ERROR("MPSSE failed"); goto skip; } for (size_t i = 0; i < swd_cmd_queue_length; i++) { int ack = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1, 3); /* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */ bool check_ack = swd_cmd_returns_ack(swd_cmd_queue[i].cmd); LOG_DEBUG_IO("%s%s %s %s reg %X = %08"PRIx32, check_ack ? "" : "ack ignored ", ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", swd_cmd_queue[i].cmd & SWD_CMD_APNDP ? "AP" : "DP", swd_cmd_queue[i].cmd & SWD_CMD_RNW ? "read" : "write", (swd_cmd_queue[i].cmd & SWD_CMD_A32) >> 1, buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1 + 3 + (swd_cmd_queue[i].cmd & SWD_CMD_RNW ? 0 : 1), 32)); if (ack != SWD_ACK_OK && check_ack) { queued_retval = swd_ack_to_error_code(ack); goto skip; } else if (swd_cmd_queue[i].cmd & SWD_CMD_RNW) { uint32_t data = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1 + 3, 32); int parity = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1 + 3 + 32, 1); if (parity != parity_u32(data)) { LOG_ERROR("SWD Read data parity mismatch"); queued_retval = ERROR_FAIL; goto skip; } if (swd_cmd_queue[i].dst) *swd_cmd_queue[i].dst = data; } } skip: swd_cmd_queue_length = 0; retval = queued_retval; queued_retval = ERROR_OK; /* Queue a new "blink" */ if (led && retval == ERROR_OK) ftdi_set_signal(led, '1'); return retval; } static void ftdi_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk) { if (swd_cmd_queue_length >= swd_cmd_queue_alloced) { /* Not enough room in the queue. Run the queue and increase its size for next time. * Note that it's not possible to avoid running the queue here, because mpsse contains * pointers into the queue which may be invalid after the realloc. */ queued_retval = ftdi_swd_run_queue(); struct swd_cmd_queue_entry *q = realloc(swd_cmd_queue, swd_cmd_queue_alloced * 2 * sizeof(*swd_cmd_queue)); if (q) { swd_cmd_queue = q; swd_cmd_queue_alloced *= 2; LOG_DEBUG("Increased SWD command queue to %zu elements", swd_cmd_queue_alloced); } } if (queued_retval != ERROR_OK) return; size_t i = swd_cmd_queue_length++; swd_cmd_queue[i].cmd = cmd | SWD_CMD_START | SWD_CMD_PARK; mpsse_clock_data_out(mpsse_ctx, &swd_cmd_queue[i].cmd, 0, 8, SWD_MODE); if (swd_cmd_queue[i].cmd & SWD_CMD_RNW) { /* Queue a read transaction */ swd_cmd_queue[i].dst = dst; ftdi_swd_swdio_en(false); mpsse_clock_data_in(mpsse_ctx, swd_cmd_queue[i].trn_ack_data_parity_trn, 0, 1 + 3 + 32 + 1 + 1, SWD_MODE); ftdi_swd_swdio_en(true); } else { /* Queue a write transaction */ ftdi_swd_swdio_en(false); mpsse_clock_data_in(mpsse_ctx, swd_cmd_queue[i].trn_ack_data_parity_trn, 0, 1 + 3 + 1, SWD_MODE); ftdi_swd_swdio_en(true); buf_set_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1 + 3 + 1, 32, data); buf_set_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1 + 3 + 1 + 32, 1, parity_u32(data)); mpsse_clock_data_out(mpsse_ctx, swd_cmd_queue[i].trn_ack_data_parity_trn, 1 + 3 + 1, 32 + 1, SWD_MODE); } /* Insert idle cycles after AP accesses to avoid WAIT */ if (cmd & SWD_CMD_APNDP) mpsse_clock_data_out(mpsse_ctx, NULL, 0, ap_delay_clk, SWD_MODE); } static void ftdi_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { assert(cmd & SWD_CMD_RNW); ftdi_swd_queue_cmd(cmd, value, 0, ap_delay_clk); } static void ftdi_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { assert(!(cmd & SWD_CMD_RNW)); ftdi_swd_queue_cmd(cmd, NULL, value, ap_delay_clk); } static int ftdi_swd_switch_seq(enum swd_special_seq seq) { switch (seq) { case LINE_RESET: LOG_DEBUG("SWD line reset"); ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_line_reset, 0, swd_seq_line_reset_len, SWD_MODE); break; case JTAG_TO_SWD: LOG_DEBUG("JTAG-to-SWD"); ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len, SWD_MODE); break; case JTAG_TO_DORMANT: LOG_DEBUG("JTAG-to-DORMANT"); ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_jtag_to_dormant, 0, swd_seq_jtag_to_dormant_len, SWD_MODE); break; case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_swd_to_jtag, 0, swd_seq_swd_to_jtag_len, SWD_MODE); break; case SWD_TO_DORMANT: LOG_DEBUG("SWD-to-DORMANT"); ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_swd_to_dormant, 0, swd_seq_swd_to_dormant_len, SWD_MODE); break; case DORMANT_TO_SWD: LOG_DEBUG("DORMANT-to-SWD"); ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_dormant_to_swd, 0, swd_seq_dormant_to_swd_len, SWD_MODE); break; case DORMANT_TO_JTAG: LOG_DEBUG("DORMANT-to-JTAG"); ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_dormant_to_jtag, 0, swd_seq_dormant_to_jtag_len, SWD_MODE); break; default: LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; } return ERROR_OK; } static const struct swd_driver ftdi_swd = { .init = ftdi_swd_init, .switch_seq = ftdi_swd_switch_seq, .read_reg = ftdi_swd_read_reg, .write_reg = ftdi_swd_write_reg, .run = ftdi_swd_run_queue, }; static const char * const ftdi_transports[] = { "jtag", "swd", NULL }; static struct jtag_interface ftdi_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = ftdi_execute_queue, }; struct adapter_driver ftdi_adapter_driver = { .name = "ftdi", .transports = ftdi_transports, .commands = ftdi_command_handlers, .init = ftdi_initialize, .quit = ftdi_quit, .reset = ftdi_reset, .speed = ftdi_speed, .khz = ftdi_khz, .speed_div = ftdi_speed_div, .jtag_ops = &ftdi_interface, .swd_ops = &ftdi_swd, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/gw16012.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/interface.h> #include <jtag/commands.h> #if 1 #define _DEBUG_GW16012_IO_ #endif /* system includes */ /* -ino: 060521-1036 */ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include <machine/sysarch.h> #include <machine/cpufunc.h> #define ioperm(startport, length, enable) \ 386_set_ioperm((startport), (length), (enable)) #else #endif /* __FreeBSD__, __FreeBSD_kernel__ */ #if PARPORT_USE_PPDEV == 1 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include <dev/ppbus/ppi.h> #include <dev/ppbus/ppbconf.h> #define PPRSTATUS PPIGSTATUS #define PPWDATA PPISDATA #else #include <linux/parport.h> #include <linux/ppdev.h> #endif #include <fcntl.h> #include <sys/ioctl.h> #else /* not PARPORT_USE_PPDEV */ #ifndef _WIN32 #include <sys/io.h> #endif #endif #if PARPORT_USE_GIVEIO == 1 && IS_CYGWIN == 1 #include <windows.h> #endif /* configuration */ static uint16_t gw16012_port; /* interface variables */ static uint8_t gw16012_msb; static uint8_t gw16012_control_value; #if PARPORT_USE_PPDEV == 1 static int device_handle; #endif static void gw16012_data(uint8_t value) { value = (value & 0x7f) | gw16012_msb; gw16012_msb ^= 0x80; /* toggle MSB */ #ifdef _DEBUG_GW16012_IO_ LOG_DEBUG("%2.2x", value); #endif #if PARPORT_USE_PPDEV == 1 ioctl(device_handle, PPWDATA, &value); #else #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) outb(gw16012_port, value); #else outb(value, gw16012_port); #endif #endif } static void gw16012_control(uint8_t value) { if (value != gw16012_control_value) { gw16012_control_value = value; #ifdef _DEBUG_GW16012_IO_ LOG_DEBUG("%2.2x", gw16012_control_value); #endif #if PARPORT_USE_PPDEV == 1 ioctl(device_handle, PPWCONTROL, &gw16012_control_value); #else #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) outb(gw16012_port + 2, gw16012_control_value); #else outb(gw16012_control_value, gw16012_port + 2); #endif #endif } } static void gw16012_input(uint8_t *value) { #if PARPORT_USE_PPDEV == 1 ioctl(device_handle, PPRSTATUS, value); #else *value = inb(gw16012_port + 1); #endif #ifdef _DEBUG_GW16012_IO_ LOG_DEBUG("%2.2x", *value); #endif } /* (1) assert or (0) deassert reset lines */ static void gw16012_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); if (trst == 0) gw16012_control(0x0d); else if (trst == 1) gw16012_control(0x0c); if (srst == 0) gw16012_control(0x0a); else if (srst == 1) gw16012_control(0x0b); } static void gw16012_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } static void gw16012_state_move(void) { int i = 0, tms = 0; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); gw16012_control(0x0); /* single-bit mode */ for (i = 0; i < tms_count; i++) { tms = (tms_scan >> i) & 1; gw16012_data(tms << 1); /* output next TMS bit */ } tap_set_state(tap_get_end_state()); } static void gw16012_path_move(struct pathmove_command *cmd) { int num_states = cmd->num_states; int state_count; state_count = 0; while (num_states) { gw16012_control(0x0); /* single-bit mode */ if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) gw16012_data(0x0); /* TCK cycle with TMS low */ else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count]) gw16012_data(0x2); /* TCK cycle with TMS high */ else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(cmd->path[state_count])); exit(-1); } tap_set_state(cmd->path[state_count]); state_count++; num_states--; } tap_set_end_state(tap_get_state()); } static void gw16012_runtest(int num_cycles) { tap_state_t saved_end_state = tap_get_end_state(); int i; /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { gw16012_end_state(TAP_IDLE); gw16012_state_move(); } for (i = 0; i < num_cycles; i++) { gw16012_control(0x0); /* single-bit mode */ gw16012_data(0x0); /* TMS cycle with TMS low */ } gw16012_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) gw16012_state_move(); } static void gw16012_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size) { int bits_left = scan_size; int bit_count = 0; tap_state_t saved_end_state = tap_get_end_state(); uint8_t scan_out, scan_in; /* only if we're not already in the correct Shift state */ if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) || (ir_scan && (tap_get_state() == TAP_IRSHIFT)))) { if (ir_scan) gw16012_end_state(TAP_IRSHIFT); else gw16012_end_state(TAP_DRSHIFT); gw16012_state_move(); gw16012_end_state(saved_end_state); } while (type == SCAN_OUT && ((bits_left - 1) > 7)) { gw16012_control(0x2); /* seven-bit mode */ scan_out = buf_get_u32(buffer, bit_count, 7); gw16012_data(scan_out); bit_count += 7; bits_left -= 7; } gw16012_control(0x0); /* single-bit mode */ while (bits_left-- > 0) { uint8_t tms = 0; scan_out = buf_get_u32(buffer, bit_count, 1); if (bits_left == 0) /* last bit */ { if ((ir_scan && (tap_get_end_state() == TAP_IRSHIFT)) || (!ir_scan && (tap_get_end_state() == TAP_DRSHIFT))) tms = 0; else tms = 2; } gw16012_data(scan_out | tms); if (type != SCAN_OUT) { gw16012_input(&scan_in); buf_set_u32(buffer, bit_count, 1, ((scan_in & 0x08) >> 3)); } bit_count++; } if (!((ir_scan && (tap_get_end_state() == TAP_IRSHIFT)) || (!ir_scan && (tap_get_end_state() == TAP_DRSHIFT)))) { gw16012_data(0x0); if (ir_scan) tap_set_state(TAP_IRPAUSE); else tap_set_state(TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) gw16012_state_move(); } } static int gw16012_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; int retval; /* return ERROR_OK, unless a jtag_read_buffer returns a failed check * that wasn't handled by a caller-provided error handler */ retval = ERROR_OK; while (cmd) { switch (cmd->type) { case JTAG_RESET: LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); if (cmd->cmd.reset->trst == 1) tap_set_state(TAP_RESET); gw16012_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); gw16012_end_state(cmd->cmd.runtest->end_state); gw16012_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); gw16012_end_state(cmd->cmd.statemove->end_state); gw16012_state_move(); break; case JTAG_PATHMOVE: LOG_DEBUG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); gw16012_path_move(cmd->cmd.pathmove); break; case JTAG_SCAN: gw16012_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); LOG_DEBUG_IO("%s scan (%i) %i bit end in %i", (cmd->cmd.scan->ir_scan) ? "ir" : "dr", type, scan_size, cmd->cmd.scan->end_state); gw16012_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; free(buffer); break; case JTAG_SLEEP: LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); jtag_sleep(cmd->cmd.sleep->us); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } return retval; } #if PARPORT_USE_GIVEIO == 1 static int gw16012_get_giveio_access(void) { HANDLE h; OSVERSIONINFO version; version.dwOSVersionInfoSize = sizeof(version); if (!GetVersionEx(&version)) { errno = EINVAL; return -1; } if (version.dwPlatformId != VER_PLATFORM_WIN32_NT) return 0; h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { errno = ENODEV; return -1; } CloseHandle(h); return 0; } #endif #if PARPORT_USE_PPDEV == 1 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #define GW16012_PPDEV_NAME "ppi" static int gw16012_init_ioctls(void) { int temp = 0; temp = ioctl(device_handle, PPCLAIM); if (temp < 0) { LOG_ERROR("cannot claim device"); return ERROR_JTAG_INIT_FAILED; } temp = PARPORT_MODE_COMPAT; temp = ioctl(device_handle, PPSETMODE, &temp); if (temp < 0) { LOG_ERROR(" cannot set compatible mode to device"); return ERROR_JTAG_INIT_FAILED; } temp = IEEE1284_MODE_COMPAT; temp = ioctl(device_handle, PPNEGOT, &temp); if (temp < 0) { LOG_ERROR("cannot set compatible 1284 mode to device"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } #else #define GW16012_PPDEV_NAME "parport" static int gw16012_init_ioctls(void) { return ERROR_OK; } #endif /* defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */ static int gw16012_init_device(void) { const char *device_name = GW16012_PPDEV_NAME; char buffer[256]; if (device_handle > 0) { LOG_ERROR("device is already opened"); return ERROR_JTAG_INIT_FAILED; } snprintf(buffer, 256, "/dev/%s%d", device_name, gw16012_port); LOG_DEBUG("opening %s...", buffer); device_handle = open(buffer, O_WRONLY); if (device_handle < 0) { LOG_ERROR("cannot open device. check it exists and that user read and write rights are set"); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("...open"); if (gw16012_init_ioctls() != ERROR_OK) return ERROR_JTAG_INIT_FAILED; return ERROR_OK; } #else /* PARPORT_USE_PPDEV */ static int gw16012_init_device(void) { if (gw16012_port == 0) { gw16012_port = 0x378; LOG_WARNING("No gw16012 port specified, using default '0x378' (LPT1)"); } LOG_DEBUG("requesting privileges for parallel port 0x%" PRIx16 "...", gw16012_port); #if PARPORT_USE_GIVEIO == 1 if (gw16012_get_giveio_access() != 0) { #else /* PARPORT_USE_GIVEIO */ if (ioperm(gw16012_port, 3, 1) != 0) { #endif /* PARPORT_USE_GIVEIO */ LOG_ERROR("missing privileges for direct i/o"); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("...privileges granted"); /* make sure parallel port is in right mode (clear tristate and interrupt */ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) outb(gw16012_port + 2, 0x0); #else outb(0x0, gw16012_port + 2); #endif return ERROR_OK; } #endif /* PARPORT_USE_PPDEV */ static int gw16012_init(void) { uint8_t status_port; if (gw16012_init_device() != ERROR_OK) return ERROR_JTAG_INIT_FAILED; gw16012_input(&status_port); gw16012_msb = (status_port & 0x80) ^ 0x80; gw16012_reset(0, 0); return ERROR_OK; } static int gw16012_quit(void) { return ERROR_OK; } COMMAND_HANDLER(gw16012_handle_parport_port_command) { if (CMD_ARGC == 1) { /* only if the port wasn't overwritten by cmdline */ if (gw16012_port == 0) COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], gw16012_port); else { LOG_ERROR("The parport port was already configured!"); return ERROR_FAIL; } } command_print(CMD, "parport port = %u", gw16012_port); return ERROR_OK; } static const struct command_registration gw16012_command_handlers[] = { { .name = "parport_port", .handler = gw16012_handle_parport_port_command, .mode = COMMAND_CONFIG, .help = "Display the address of the I/O port (e.g. 0x378) " "or the number of the '/dev/parport' device used. " "If a parameter is provided, first change that port.", .usage = "[port_number]", }, COMMAND_REGISTRATION_DONE }; static struct jtag_interface gw16012_interface = { .execute_queue = gw16012_execute_queue, }; struct adapter_driver gw16012_adapter_driver = { .name = "gw16012", .transports = jtag_only, .commands = gw16012_command_handlers, .init = gw16012_init, .quit = gw16012_quit, .jtag_ops = &gw16012_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/imx_gpio.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2017 by Grzegorz Kostka, kostka.grzegorz@gmail.com * * * * Based on bcm2835gpio.c * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/interface.h> #include <transport/transport.h> #include "bitbang.h" #include <sys/mman.h> #define IMX_GPIO_BASE 0x0209c000 #define IMX_GPIO_SIZE 0x00004000 #define IMX_GPIO_REGS_COUNT 8 static uint32_t imx_gpio_peri_base = IMX_GPIO_BASE; struct imx_gpio_regs { uint32_t dr; uint32_t gdir; uint32_t psr; uint32_t icr1; uint32_t icr2; uint32_t imr; uint32_t isr; uint32_t edge_sel; } __attribute__((aligned(IMX_GPIO_SIZE))); static int dev_mem_fd; static volatile struct imx_gpio_regs *pio_base; /* GPIO setup functions */ static inline bool gpio_mode_get(int g) { return pio_base[g / 32].gdir >> (g & 0x1F) & 1; } static inline void gpio_mode_input_set(int g) { pio_base[g / 32].gdir &= ~(1u << (g & 0x1F)); } static inline void gpio_mode_output_set(int g) { pio_base[g / 32].gdir |= (1u << (g & 0x1F)); } static inline void gpio_mode_set(int g, int m) { (m) ? gpio_mode_output_set(g) : gpio_mode_input_set(g); } static inline void gpio_set(int g) { pio_base[g / 32].dr |= (1u << (g & 0x1F)); } static inline void gpio_clear(int g) { pio_base[g / 32].dr &= ~(1u << (g & 0x1F)); } static inline bool gpio_level(int g) { return pio_base[g / 32].dr >> (g & 0x1F) & 1; } static bb_value_t imx_gpio_read(void); static int imx_gpio_write(int tck, int tms, int tdi); static int imx_gpio_swdio_read(void); static void imx_gpio_swdio_drive(bool is_output); static int imx_gpio_swd_write(int swclk, int swdio); static int imx_gpio_init(void); static int imx_gpio_quit(void); static struct bitbang_interface imx_gpio_bitbang = { .read = imx_gpio_read, .write = imx_gpio_write, .swdio_read = imx_gpio_swdio_read, .swdio_drive = imx_gpio_swdio_drive, .swd_write = imx_gpio_swd_write, .blink = NULL }; /* GPIO numbers for each signal. Negative values are invalid */ static int tck_gpio = -1; static int tck_gpio_mode; static int tms_gpio = -1; static int tms_gpio_mode; static int tdi_gpio = -1; static int tdi_gpio_mode; static int tdo_gpio = -1; static int tdo_gpio_mode; static int trst_gpio = -1; static int trst_gpio_mode; static int srst_gpio = -1; static int srst_gpio_mode; static int swclk_gpio = -1; static int swclk_gpio_mode; static int swdio_gpio = -1; static int swdio_gpio_mode; /* Transition delay coefficients. Tuned for IMX6UL 528MHz. Adjusted * experimentally for:10kHz, 100Khz, 500KHz. Speeds above 800Khz are impossible * to reach via memory mapped method (at least for IMX6UL@528MHz). * Measured mmap raw GPIO toggling speed on IMX6UL@528MHz: 1.3MHz. */ static int speed_coeff = 50000; static int speed_offset = 100; static unsigned int jtag_delay; static bb_value_t imx_gpio_read(void) { return gpio_level(tdo_gpio) ? BB_HIGH : BB_LOW; } static int imx_gpio_write(int tck, int tms, int tdi) { tms ? gpio_set(tms_gpio) : gpio_clear(tms_gpio); tdi ? gpio_set(tdi_gpio) : gpio_clear(tdi_gpio); tck ? gpio_set(tck_gpio) : gpio_clear(tck_gpio); for (unsigned int i = 0; i < jtag_delay; i++) asm volatile (""); return ERROR_OK; } static int imx_gpio_swd_write(int swclk, int swdio) { swdio ? gpio_set(swdio_gpio) : gpio_clear(swdio_gpio); swclk ? gpio_set(swclk_gpio) : gpio_clear(swclk_gpio); for (unsigned int i = 0; i < jtag_delay; i++) asm volatile (""); return ERROR_OK; } /* (1) assert or (0) deassert reset lines */ static int imx_gpio_reset(int trst, int srst) { if (trst_gpio != -1) trst ? gpio_clear(trst_gpio) : gpio_set(trst_gpio); if (srst_gpio != -1) srst ? gpio_clear(srst_gpio) : gpio_set(srst_gpio); return ERROR_OK; } static void imx_gpio_swdio_drive(bool is_output) { if (is_output) gpio_mode_output_set(swdio_gpio); else gpio_mode_input_set(swdio_gpio); } static int imx_gpio_swdio_read(void) { return gpio_level(swdio_gpio); } static int imx_gpio_khz(int khz, int *jtag_speed) { if (!khz) { LOG_DEBUG("RCLK not supported"); return ERROR_FAIL; } *jtag_speed = speed_coeff/khz - speed_offset; if (*jtag_speed < 0) *jtag_speed = 0; return ERROR_OK; } static int imx_gpio_speed_div(int speed, int *khz) { *khz = speed_coeff/(speed + speed_offset); return ERROR_OK; } static int imx_gpio_speed(int speed) { jtag_delay = speed; return ERROR_OK; } static int is_gpio_valid(int gpio) { return gpio >= 0 && gpio < 32 * IMX_GPIO_REGS_COUNT; } COMMAND_HANDLER(imx_gpio_handle_jtag_gpionums) { if (CMD_ARGC == 4) { COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio); COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio); COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio); } else if (CMD_ARGC != 0) { return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "imx_gpio GPIO config: tck = %d, tms = %d, tdi = %d, tdo = %d", tck_gpio, tms_gpio, tdi_gpio, tdo_gpio); return ERROR_OK; } COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tck) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); command_print(CMD, "imx_gpio GPIO config: tck = %d", tck_gpio); return ERROR_OK; } COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tms) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio); command_print(CMD, "imx_gpio GPIO config: tms = %d", tms_gpio); return ERROR_OK; } COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tdo) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio); command_print(CMD, "imx_gpio GPIO config: tdo = %d", tdo_gpio); return ERROR_OK; } COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tdi) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio); command_print(CMD, "imx_gpio GPIO config: tdi = %d", tdi_gpio); return ERROR_OK; } COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_srst) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio); command_print(CMD, "imx_gpio GPIO config: srst = %d", srst_gpio); return ERROR_OK; } COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_trst) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio); command_print(CMD, "imx_gpio GPIO config: trst = %d", trst_gpio); return ERROR_OK; } COMMAND_HANDLER(imx_gpio_handle_swd_gpionums) { if (CMD_ARGC == 2) { COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio); COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio); } else if (CMD_ARGC != 0) { return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "imx_gpio GPIO nums: swclk = %d, swdio = %d", swclk_gpio, swdio_gpio); return ERROR_OK; } COMMAND_HANDLER(imx_gpio_handle_swd_gpionum_swclk) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio); command_print(CMD, "imx_gpio num: swclk = %d", swclk_gpio); return ERROR_OK; } COMMAND_HANDLER(imx_gpio_handle_swd_gpionum_swdio) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio); command_print(CMD, "imx_gpio num: swdio = %d", swdio_gpio); return ERROR_OK; } COMMAND_HANDLER(imx_gpio_handle_speed_coeffs) { if (CMD_ARGC == 2) { COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff); COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset); } command_print(CMD, "imx_gpio: speed_coeffs = %d, speed_offset = %d", speed_coeff, speed_offset); return ERROR_OK; } COMMAND_HANDLER(imx_gpio_handle_peripheral_base) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], imx_gpio_peri_base); command_print(CMD, "imx_gpio: peripheral_base = 0x%08x", imx_gpio_peri_base); return ERROR_OK; } static const struct command_registration imx_gpio_command_handlers[] = { { .name = "imx_gpio_jtag_nums", .handler = &imx_gpio_handle_jtag_gpionums, .mode = COMMAND_CONFIG, .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)", .usage = "[tck tms tdi tdo]", }, { .name = "imx_gpio_tck_num", .handler = &imx_gpio_handle_jtag_gpionum_tck, .mode = COMMAND_CONFIG, .help = "gpio number for tck.", .usage = "[tck]", }, { .name = "imx_gpio_tms_num", .handler = &imx_gpio_handle_jtag_gpionum_tms, .mode = COMMAND_CONFIG, .help = "gpio number for tms.", .usage = "[tms]", }, { .name = "imx_gpio_tdo_num", .handler = &imx_gpio_handle_jtag_gpionum_tdo, .mode = COMMAND_CONFIG, .help = "gpio number for tdo.", .usage = "[tdo]", }, { .name = "imx_gpio_tdi_num", .handler = &imx_gpio_handle_jtag_gpionum_tdi, .mode = COMMAND_CONFIG, .help = "gpio number for tdi.", .usage = "[tdi]", }, { .name = "imx_gpio_swd_nums", .handler = &imx_gpio_handle_swd_gpionums, .mode = COMMAND_CONFIG, .help = "gpio numbers for swclk, swdio. (in that order)", .usage = "[swclk swdio]", }, { .name = "imx_gpio_swclk_num", .handler = &imx_gpio_handle_swd_gpionum_swclk, .mode = COMMAND_CONFIG, .help = "gpio number for swclk.", .usage = "[swclk]", }, { .name = "imx_gpio_swdio_num", .handler = &imx_gpio_handle_swd_gpionum_swdio, .mode = COMMAND_CONFIG, .help = "gpio number for swdio.", .usage = "[swdio]", }, { .name = "imx_gpio_srst_num", .handler = &imx_gpio_handle_jtag_gpionum_srst, .mode = COMMAND_CONFIG, .help = "gpio number for srst.", .usage = "[srst]", }, { .name = "imx_gpio_trst_num", .handler = &imx_gpio_handle_jtag_gpionum_trst, .mode = COMMAND_CONFIG, .help = "gpio number for trst.", .usage = "[trst]", }, { .name = "imx_gpio_speed_coeffs", .handler = &imx_gpio_handle_speed_coeffs, .mode = COMMAND_CONFIG, .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.", .usage = "[SPEED_COEFF SPEED_OFFSET]", }, { .name = "imx_gpio_peripheral_base", .handler = &imx_gpio_handle_peripheral_base, .mode = COMMAND_CONFIG, .help = "peripheral base to access GPIOs (0x0209c000 for most IMX).", .usage = "[base]", }, COMMAND_REGISTRATION_DONE }; static const char * const imx_gpio_transports[] = { "jtag", "swd", NULL }; static struct jtag_interface imx_gpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, }; struct adapter_driver imx_gpio_adapter_driver = { .name = "imx_gpio", .transports = imx_gpio_transports, .commands = imx_gpio_command_handlers, .init = imx_gpio_init, .quit = imx_gpio_quit, .reset = imx_gpio_reset, .speed = imx_gpio_speed, .khz = imx_gpio_khz, .speed_div = imx_gpio_speed_div, .jtag_ops = &imx_gpio_interface, .swd_ops = &bitbang_swd, }; static bool imx_gpio_jtag_mode_possible(void) { if (!is_gpio_valid(tck_gpio)) return 0; if (!is_gpio_valid(tms_gpio)) return 0; if (!is_gpio_valid(tdi_gpio)) return 0; if (!is_gpio_valid(tdo_gpio)) return 0; return 1; } static bool imx_gpio_swd_mode_possible(void) { if (!is_gpio_valid(swclk_gpio)) return 0; if (!is_gpio_valid(swdio_gpio)) return 0; return 1; } static int imx_gpio_init(void) { bitbang_interface = &imx_gpio_bitbang; LOG_INFO("imx_gpio GPIO JTAG/SWD bitbang driver"); if (transport_is_jtag() && !imx_gpio_jtag_mode_possible()) { LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode"); return ERROR_JTAG_INIT_FAILED; } if (transport_is_swd() && !imx_gpio_swd_mode_possible()) { LOG_ERROR("Require swclk and swdio gpio for SWD mode"); return ERROR_JTAG_INIT_FAILED; } dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); if (dev_mem_fd < 0) { LOG_ERROR("open: %s", strerror(errno)); return ERROR_JTAG_INIT_FAILED; } LOG_INFO("imx_gpio mmap: pagesize: %u, regionsize: %u", (unsigned int) sysconf(_SC_PAGE_SIZE), IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE); pio_base = mmap(NULL, IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, imx_gpio_peri_base); if (pio_base == MAP_FAILED) { LOG_ERROR("mmap: %s", strerror(errno)); close(dev_mem_fd); return ERROR_JTAG_INIT_FAILED; } /* * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. */ if (transport_is_jtag()) { tdo_gpio_mode = gpio_mode_get(tdo_gpio); tdi_gpio_mode = gpio_mode_get(tdi_gpio); tck_gpio_mode = gpio_mode_get(tck_gpio); tms_gpio_mode = gpio_mode_get(tms_gpio); gpio_clear(tdi_gpio); gpio_clear(tck_gpio); gpio_set(tms_gpio); gpio_mode_input_set(tdo_gpio); gpio_mode_output_set(tdi_gpio); gpio_mode_output_set(tck_gpio); gpio_mode_output_set(tms_gpio); if (trst_gpio != -1) { trst_gpio_mode = gpio_mode_get(trst_gpio); gpio_set(trst_gpio); gpio_mode_output_set(trst_gpio); } } if (transport_is_swd()) { swclk_gpio_mode = gpio_mode_get(swclk_gpio); swdio_gpio_mode = gpio_mode_get(swdio_gpio); gpio_clear(swdio_gpio); gpio_clear(swclk_gpio); gpio_mode_output_set(swclk_gpio); gpio_mode_output_set(swdio_gpio); } if (srst_gpio != -1) { srst_gpio_mode = gpio_mode_get(srst_gpio); gpio_set(srst_gpio); gpio_mode_output_set(srst_gpio); } LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d " "tdo %d trst %d srst %d", tck_gpio_mode, tms_gpio_mode, tdi_gpio_mode, tdo_gpio_mode, trst_gpio_mode, srst_gpio_mode); return ERROR_OK; } static int imx_gpio_quit(void) { if (transport_is_jtag()) { gpio_mode_set(tdo_gpio, tdo_gpio_mode); gpio_mode_set(tdi_gpio, tdi_gpio_mode); gpio_mode_set(tck_gpio, tck_gpio_mode); gpio_mode_set(tms_gpio, tms_gpio_mode); if (trst_gpio != -1) gpio_mode_set(trst_gpio, trst_gpio_mode); } if (transport_is_swd()) { gpio_mode_set(swclk_gpio, swclk_gpio_mode); gpio_mode_set(swdio_gpio, swdio_gpio_mode); } if (srst_gpio != -1) gpio_mode_set(srst_gpio, srst_gpio_mode); return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/jlink.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Juergen Stuber <juergen@jstuber.net> * * based on Dominic Rath's and Benedikt Sauter's usbprog.c * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Jean-Christophe PLAGNIOL-VIILARD * * plagnioj@jcrosoft.com * * * * Copyright (C) 2015 by Marc Schink * * openocd-dev@marcschink.de * * * * Copyright (C) 2015 by Paul Fertser * * fercerpav@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdint.h> #include <math.h> #include <jtag/interface.h> #include <jtag/swd.h> #include <jtag/commands.h> #include <jtag/adapter.h> #include <helper/replacements.h> #include <target/cortex_m.h> #include <libjaylink/libjaylink.h> static struct jaylink_context *jayctx; static struct jaylink_device_handle *devh; static struct jaylink_connection conn; static struct jaylink_connection connlist[JAYLINK_MAX_CONNECTIONS]; static enum jaylink_jtag_version jtag_command_version; static uint8_t caps[JAYLINK_DEV_EXT_CAPS_SIZE]; static uint32_t serial_number; static bool use_serial_number; static bool use_usb_location; static enum jaylink_usb_address usb_address; static bool use_usb_address; static enum jaylink_target_interface iface = JAYLINK_TIF_JTAG; static bool trace_enabled; #define JLINK_MAX_SPEED 12000 #define JLINK_TAP_BUFFER_SIZE 2048 static unsigned int swd_buffer_size = JLINK_TAP_BUFFER_SIZE; /* Maximum SWO frequency deviation. */ #define SWO_MAX_FREQ_DEV 0.03 /* 256 byte non-volatile memory */ struct device_config { uint8_t usb_address; /* 0ffset 0x01 to 0x03 */ uint8_t reserved_1[3]; uint32_t target_power; /* 0ffset 0x08 to 0x1f */ uint8_t reserved_2[24]; /* IP only for J-Link Pro */ uint8_t ip_address[4]; uint8_t subnet_mask[4]; /* 0ffset 0x28 to 0x2f */ uint8_t reserved_3[8]; uint8_t mac_address[6]; /* 0ffset 0x36 to 0xff */ uint8_t reserved_4[202]; } __attribute__ ((packed)); static struct device_config config; static struct device_config tmp_config; /* Queue command functions */ static void jlink_end_state(tap_state_t state); static void jlink_state_move(void); static void jlink_path_move(int num_states, tap_state_t *path); static void jlink_stableclocks(int num_cycles); static void jlink_runtest(int num_cycles); static void jlink_reset(int trst, int srst); static int jlink_reset_safe(int trst, int srst); static int jlink_swd_run_queue(void); static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk); static int jlink_swd_switch_seq(enum swd_special_seq seq); /* J-Link tap buffer functions */ static void jlink_tap_init(void); static int jlink_flush(void); /** * Queue data to go out and in, flushing the queue as many times as * necessary. * * @param out A pointer to TDI data, if NULL, old stale data will be used. * @param out_offset A bit offset for TDI data. * @param tms_out A pointer to TMS data, if NULL, zeroes will be emitted. * @param tms_offset A bit offset for TMS data. * @param in A pointer to store TDO data to, if NULL the data will be discarded. * @param in_offset A bit offset for TDO data. * @param length Amount of bits to transfer out and in. */ static void jlink_clock_data(const uint8_t *out, unsigned out_offset, const uint8_t *tms_out, unsigned tms_offset, uint8_t *in, unsigned in_offset, unsigned length); static enum tap_state jlink_last_state = TAP_RESET; static int queued_retval; /***************************************************************************/ /* External interface implementation */ static void jlink_execute_stableclocks(struct jtag_command *cmd) { LOG_DEBUG_IO("stableclocks %i cycles", cmd->cmd.runtest->num_cycles); jlink_stableclocks(cmd->cmd.runtest->num_cycles); } static void jlink_execute_runtest(struct jtag_command *cmd) { LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); jlink_end_state(cmd->cmd.runtest->end_state); jlink_runtest(cmd->cmd.runtest->num_cycles); } static void jlink_execute_statemove(struct jtag_command *cmd) { LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); jlink_end_state(cmd->cmd.statemove->end_state); jlink_state_move(); } static void jlink_execute_pathmove(struct jtag_command *cmd) { LOG_DEBUG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); jlink_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); } static void jlink_execute_scan(struct jtag_command *cmd) { LOG_DEBUG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN", jtag_scan_type(cmd->cmd.scan)); /* Make sure there are no trailing fields with num_bits == 0, or the logic below will fail. */ while (cmd->cmd.scan->num_fields > 0 && cmd->cmd.scan->fields[cmd->cmd.scan->num_fields - 1].num_bits == 0) { cmd->cmd.scan->num_fields--; LOG_DEBUG("discarding trailing empty field"); } if (cmd->cmd.scan->num_fields == 0) { LOG_DEBUG("empty scan, doing nothing"); return; } if (cmd->cmd.scan->ir_scan) { if (tap_get_state() != TAP_IRSHIFT) { jlink_end_state(TAP_IRSHIFT); jlink_state_move(); } } else { if (tap_get_state() != TAP_DRSHIFT) { jlink_end_state(TAP_DRSHIFT); jlink_state_move(); } } jlink_end_state(cmd->cmd.scan->end_state); struct scan_field *field = cmd->cmd.scan->fields; unsigned scan_size = 0; for (int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) { scan_size += field->num_bits; LOG_DEBUG_IO("%s%s field %d/%d %d bits", field->in_value ? "in" : "", field->out_value ? "out" : "", i, cmd->cmd.scan->num_fields, field->num_bits); if (i == cmd->cmd.scan->num_fields - 1 && tap_get_state() != tap_get_end_state()) { /* Last field, and we're leaving IRSHIFT/DRSHIFT. Clock last bit during tap * movement. This last field can't have length zero, it was checked above. */ jlink_clock_data(field->out_value, 0, NULL, 0, field->in_value, 0, field->num_bits - 1); uint8_t last_bit = 0; if (field->out_value) bit_copy(&last_bit, 0, field->out_value, field->num_bits - 1, 1); uint8_t tms_bits = 0x01; jlink_clock_data(&last_bit, 0, &tms_bits, 0, field->in_value, field->num_bits - 1, 1); tap_set_state(tap_state_transition(tap_get_state(), 1)); jlink_clock_data(NULL, 0, &tms_bits, 1, NULL, 0, 1); tap_set_state(tap_state_transition(tap_get_state(), 0)); } else jlink_clock_data(field->out_value, 0, NULL, 0, field->in_value, 0, field->num_bits); } if (tap_get_state() != tap_get_end_state()) { jlink_end_state(tap_get_end_state()); jlink_state_move(); } LOG_DEBUG_IO("%s scan, %i bits, end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, tap_state_name(tap_get_end_state())); } static void jlink_execute_sleep(struct jtag_command *cmd) { LOG_DEBUG_IO("sleep %" PRIu32 "", cmd->cmd.sleep->us); jlink_flush(); jtag_sleep(cmd->cmd.sleep->us); } static int jlink_execute_command(struct jtag_command *cmd) { switch (cmd->type) { case JTAG_STABLECLOCKS: jlink_execute_stableclocks(cmd); break; case JTAG_RUNTEST: jlink_execute_runtest(cmd); break; case JTAG_TLR_RESET: jlink_execute_statemove(cmd); break; case JTAG_PATHMOVE: jlink_execute_pathmove(cmd); break; case JTAG_SCAN: jlink_execute_scan(cmd); break; case JTAG_SLEEP: jlink_execute_sleep(cmd); break; default: LOG_ERROR("BUG: Unknown JTAG command type encountered"); return ERROR_JTAG_QUEUE_FAILED; } return ERROR_OK; } static int jlink_execute_queue(void) { int ret; struct jtag_command *cmd = jtag_command_queue; while (cmd) { ret = jlink_execute_command(cmd); if (ret != ERROR_OK) return ret; cmd = cmd->next; } return jlink_flush(); } static int jlink_speed(int speed) { int ret; struct jaylink_speed tmp; int max_speed; if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_SPEEDS)) { ret = jaylink_get_speeds(devh, &tmp); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_speeds() failed: %s", jaylink_strerror(ret)); return ERROR_JTAG_DEVICE_ERROR; } tmp.freq /= 1000; max_speed = tmp.freq / tmp.div; } else { max_speed = JLINK_MAX_SPEED; } if (!speed) { if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ADAPTIVE_CLOCKING)) { LOG_ERROR("Adaptive clocking is not supported by the device"); return ERROR_JTAG_NOT_IMPLEMENTED; } speed = JAYLINK_SPEED_ADAPTIVE_CLOCKING; } else if (speed > max_speed) { LOG_INFO("Reduced speed from %d kHz to %d kHz (maximum)", speed, max_speed); speed = max_speed; } ret = jaylink_set_speed(devh, speed); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_set_speed() failed: %s", jaylink_strerror(ret)); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int jlink_speed_div(int speed, int *khz) { *khz = speed; return ERROR_OK; } static int jlink_khz(int khz, int *jtag_speed) { *jtag_speed = khz; return ERROR_OK; } static bool read_device_config(struct device_config *cfg) { int ret; ret = jaylink_read_raw_config(devh, (uint8_t *)cfg); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_read_raw_config() failed: %s", jaylink_strerror(ret)); return false; } if (cfg->usb_address == 0xff) cfg->usb_address = 0x00; if (cfg->target_power == 0xffffffff) cfg->target_power = 0; return true; } static int select_interface(void) { int ret; uint32_t interfaces; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SELECT_TIF)) { if (iface != JAYLINK_TIF_JTAG) { LOG_ERROR("Device supports JTAG transport only"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } ret = jaylink_get_available_interfaces(devh, &interfaces); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_available_interfaces() failed: %s", jaylink_strerror(ret)); return ERROR_JTAG_INIT_FAILED; } if (!(interfaces & (1 << iface))) { LOG_ERROR("Selected transport is not supported by the device"); return ERROR_JTAG_INIT_FAILED; } ret = jaylink_select_interface(devh, iface, NULL); if (ret < 0) { LOG_ERROR("jaylink_select_interface() failed: %s", jaylink_strerror(ret)); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int jlink_register(void) { int ret; size_t i; bool handle_found; size_t count; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER)) return ERROR_OK; ret = jaylink_register(devh, &conn, connlist, &count); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_register() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } handle_found = false; for (i = 0; i < count; i++) { if (connlist[i].handle == conn.handle) { handle_found = true; break; } } if (!handle_found) { LOG_ERROR("Registration failed: maximum number of connections on the " "device reached"); return ERROR_FAIL; } return ERROR_OK; } /* * Adjust the SWD transaction buffer size depending on the free device internal * memory. This ensures that the SWD transactions sent to the device do not * exceed the internal memory of the device. */ static bool adjust_swd_buffer_size(void) { int ret; uint32_t tmp; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_FREE_MEMORY)) return true; ret = jaylink_get_free_memory(devh, &tmp); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_free_memory() failed: %s", jaylink_strerror(ret)); return false; } if (tmp < 143) { LOG_ERROR("Not enough free device internal memory: %" PRIu32 " bytes", tmp); return false; } tmp = MIN(JLINK_TAP_BUFFER_SIZE, (tmp - 16) / 2); if (tmp != swd_buffer_size) { swd_buffer_size = tmp; LOG_DEBUG("Adjusted SWD transaction buffer size to %u bytes", swd_buffer_size); } return true; } static int jaylink_log_handler(const struct jaylink_context *ctx, enum jaylink_log_level level, const char *format, va_list args, void *user_data) { enum log_levels tmp; switch (level) { case JAYLINK_LOG_LEVEL_ERROR: tmp = LOG_LVL_ERROR; break; case JAYLINK_LOG_LEVEL_WARNING: tmp = LOG_LVL_WARNING; break; /* * Forward info messages to the debug output because they are more verbose * than info messages of OpenOCD. */ case JAYLINK_LOG_LEVEL_INFO: case JAYLINK_LOG_LEVEL_DEBUG: tmp = LOG_LVL_DEBUG; break; case JAYLINK_LOG_LEVEL_DEBUG_IO: tmp = LOG_LVL_DEBUG_IO; break; default: tmp = LOG_LVL_WARNING; } log_vprintf_lf(tmp, __FILE__, __LINE__, __func__, format, args); return 0; } static bool jlink_usb_location_equal(struct jaylink_device *dev) { int retval; uint8_t bus; uint8_t *ports; size_t num_ports; bool equal = false; retval = jaylink_device_get_usb_bus_ports(dev, &bus, &ports, &num_ports); if (retval == JAYLINK_ERR_NOT_SUPPORTED) { return false; } else if (retval != JAYLINK_OK) { LOG_WARNING("jaylink_device_get_usb_bus_ports() failed: %s", jaylink_strerror(retval)); return false; } equal = adapter_usb_location_equal(bus, ports, num_ports); free(ports); return equal; } static int jlink_open_device(uint32_t ifaces, bool *found_device) { int ret = jaylink_discovery_scan(jayctx, ifaces); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_discovery_scan() failed: %s", jaylink_strerror(ret)); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } size_t num_devices; struct jaylink_device **devs; ret = jaylink_get_devices(jayctx, &devs, &num_devices); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_devices() failed: %s", jaylink_strerror(ret)); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } use_usb_location = !!adapter_usb_get_location(); if (!use_serial_number && !use_usb_address && !use_usb_location && num_devices > 1) { LOG_ERROR("Multiple devices found, specify the desired device"); jaylink_free_devices(devs, true); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } *found_device = false; for (size_t i = 0; devs[i]; i++) { struct jaylink_device *dev = devs[i]; if (use_serial_number) { uint32_t tmp; ret = jaylink_device_get_serial_number(dev, &tmp); if (ret == JAYLINK_ERR_NOT_AVAILABLE) { continue; } else if (ret != JAYLINK_OK) { LOG_WARNING("jaylink_device_get_serial_number() failed: %s", jaylink_strerror(ret)); continue; } if (serial_number != tmp) continue; } if (use_usb_address) { enum jaylink_usb_address address; ret = jaylink_device_get_usb_address(dev, &address); if (ret == JAYLINK_ERR_NOT_SUPPORTED) { continue; } else if (ret != JAYLINK_OK) { LOG_WARNING("jaylink_device_get_usb_address() failed: %s", jaylink_strerror(ret)); continue; } if (usb_address != address) continue; } if (use_usb_location && !jlink_usb_location_equal(dev)) continue; ret = jaylink_open(dev, &devh); if (ret == JAYLINK_OK) { *found_device = true; break; } LOG_ERROR("Failed to open device: %s", jaylink_strerror(ret)); } jaylink_free_devices(devs, true); return ERROR_OK; } static int jlink_init(void) { int ret; char *firmware_version; struct jaylink_hardware_version hwver; struct jaylink_hardware_status hwstatus; size_t length; LOG_DEBUG("Using libjaylink %s (compiled with %s)", jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING); if (!jaylink_library_has_cap(JAYLINK_CAP_HIF_USB) && use_usb_address) { LOG_ERROR("J-Link driver does not support USB devices"); return ERROR_JTAG_INIT_FAILED; } ret = jaylink_init(&jayctx); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_init() failed: %s", jaylink_strerror(ret)); return ERROR_JTAG_INIT_FAILED; } ret = jaylink_log_set_callback(jayctx, &jaylink_log_handler, NULL); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_log_set_callback() failed: %s", jaylink_strerror(ret)); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } const char *serial = adapter_get_required_serial(); if (serial) { ret = jaylink_parse_serial_number(serial, &serial_number); if (ret == JAYLINK_ERR) { LOG_ERROR("Invalid serial number: %s", serial); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_parse_serial_number() failed: %s", jaylink_strerror(ret)); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } use_serial_number = true; use_usb_address = false; } bool found_device; ret = jlink_open_device(JAYLINK_HIF_USB, &found_device); if (ret != ERROR_OK) return ret; if (!found_device && use_serial_number) { ret = jlink_open_device(JAYLINK_HIF_TCP, &found_device); if (ret != ERROR_OK) return ret; } if (!found_device) { LOG_ERROR("No J-Link device found"); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } /* * Be careful with changing the following initialization sequence because * some devices are known to be sensitive regarding the order. */ ret = jaylink_get_firmware_version(devh, &firmware_version, &length); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_firmware_version() failed: %s", jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } else if (length > 0) { LOG_INFO("%s", firmware_version); free(firmware_version); } else { LOG_WARNING("Device responds empty firmware version string"); } memset(caps, 0, JAYLINK_DEV_EXT_CAPS_SIZE); ret = jaylink_get_caps(devh, caps); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_caps() failed: %s", jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_EXT_CAPS)) { ret = jaylink_get_extended_caps(devh, caps); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_extended_caps() failed: %s", jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } } jtag_command_version = JAYLINK_JTAG_VERSION_2; if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_HW_VERSION)) { ret = jaylink_get_hardware_version(devh, &hwver); if (ret != JAYLINK_OK) { LOG_ERROR("Failed to retrieve hardware version: %s", jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } LOG_INFO("Hardware version: %u.%02u", hwver.major, hwver.minor); if (hwver.major >= 5) jtag_command_version = JAYLINK_JTAG_VERSION_3; } if (iface == JAYLINK_TIF_SWD) { /* * Adjust the SWD transaction buffer size in case there is already * allocated memory on the device. This happens for example if the * memory for SWO capturing is still allocated because the software * which used the device before has not been shut down properly. */ if (!adjust_swd_buffer_size()) { jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } } if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { if (!read_device_config(&config)) { LOG_ERROR("Failed to read device configuration data"); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } memcpy(&tmp_config, &config, sizeof(struct device_config)); } ret = jaylink_get_hardware_status(devh, &hwstatus); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_hardware_status() failed: %s", jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } LOG_INFO("VTarget = %u.%03u V", hwstatus.target_voltage / 1000, hwstatus.target_voltage % 1000); conn.handle = 0; conn.pid = 0; strcpy(conn.hid, "0.0.0.0"); conn.iid = 0; conn.cid = 0; ret = jlink_register(); if (ret != ERROR_OK) { jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } ret = select_interface(); if (ret != ERROR_OK) { jaylink_close(devh); jaylink_exit(jayctx); return ret; } jlink_reset(0, 0); jtag_sleep(3000); jlink_tap_init(); jlink_speed(adapter_get_speed_khz()); if (iface == JAYLINK_TIF_JTAG) { /* * J-Link devices with firmware version v5 and v6 seems to have an issue * if the first tap move is not divisible by 8, so we send a TLR on * first power up. */ uint8_t tms = 0xff; jlink_clock_data(NULL, 0, &tms, 0, NULL, 0, 8); jlink_flush(); } return ERROR_OK; } static int jlink_quit(void) { int ret; size_t count; if (trace_enabled) { ret = jaylink_swo_stop(devh); if (ret != JAYLINK_OK) LOG_ERROR("jaylink_swo_stop() failed: %s", jaylink_strerror(ret)); } if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER)) { ret = jaylink_unregister(devh, &conn, connlist, &count); if (ret != JAYLINK_OK) LOG_ERROR("jaylink_unregister() failed: %s", jaylink_strerror(ret)); } jaylink_close(devh); jaylink_exit(jayctx); return ERROR_OK; } /***************************************************************************/ /* Queue command implementations */ static void jlink_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } /* Goes to the end state. */ static void jlink_state_move(void) { uint8_t tms_scan; uint8_t tms_scan_bits; tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); tms_scan_bits = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); jlink_clock_data(NULL, 0, &tms_scan, 0, NULL, 0, tms_scan_bits); tap_set_state(tap_get_end_state()); } static void jlink_path_move(int num_states, tap_state_t *path) { int i; uint8_t tms = 0xff; for (i = 0; i < num_states; i++) { if (path[i] == tap_state_transition(tap_get_state(), false)) jlink_clock_data(NULL, 0, NULL, 0, NULL, 0, 1); else if (path[i] == tap_state_transition(tap_get_state(), true)) jlink_clock_data(NULL, 0, &tms, 0, NULL, 0, 1); else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(path[i])); exit(-1); } tap_set_state(path[i]); } tap_set_end_state(tap_get_state()); } static void jlink_stableclocks(int num_cycles) { int i; uint8_t tms = tap_get_state() == TAP_RESET; /* Execute num_cycles. */ for (i = 0; i < num_cycles; i++) jlink_clock_data(NULL, 0, &tms, 0, NULL, 0, 1); } static void jlink_runtest(int num_cycles) { tap_state_t saved_end_state = tap_get_end_state(); /* Only do a state_move when we're not already in IDLE. */ if (tap_get_state() != TAP_IDLE) { jlink_end_state(TAP_IDLE); jlink_state_move(); /* num_cycles--; */ } jlink_stableclocks(num_cycles); /* Finish in end_state. */ jlink_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) jlink_state_move(); } static void jlink_reset(int trst, int srst) { LOG_DEBUG("TRST: %i, SRST: %i", trst, srst); /* Signals are active low. */ if (srst == 0) jaylink_set_reset(devh); if (srst == 1) jaylink_clear_reset(devh); if (trst == 1) jaylink_jtag_clear_trst(devh); if (trst == 0) jaylink_jtag_set_trst(devh); } static int jlink_reset_safe(int trst, int srst) { jlink_flush(); jlink_reset(trst, srst); return jlink_flush(); } COMMAND_HANDLER(jlink_usb_command) { int tmp; if (CMD_ARGC != 1) { command_print(CMD, "Need exactly one argument for jlink usb"); return ERROR_COMMAND_SYNTAX_ERROR; } if (sscanf(CMD_ARGV[0], "%i", &tmp) != 1) { command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); return ERROR_FAIL; } if (tmp < JAYLINK_USB_ADDRESS_0 || tmp > JAYLINK_USB_ADDRESS_3) { command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); return ERROR_FAIL; } usb_address = tmp; use_usb_address = true; return ERROR_OK; } COMMAND_HANDLER(jlink_handle_hwstatus_command) { int ret; struct jaylink_hardware_status status; ret = jaylink_get_hardware_status(devh, &status); if (ret != JAYLINK_OK) { command_print(CMD, "jaylink_get_hardware_status() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } command_print(CMD, "VTarget = %u.%03u V", status.target_voltage / 1000, status.target_voltage % 1000); command_print(CMD, "TCK = %u TDI = %u TDO = %u TMS = %u SRST = %u " "TRST = %u", status.tck, status.tdi, status.tdo, status.tms, status.tres, status.trst); if (status.target_voltage < 1500) command_print(CMD, "Target voltage too low. Check target power"); return ERROR_OK; } COMMAND_HANDLER(jlink_handle_free_memory_command) { int ret; uint32_t tmp; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_FREE_MEMORY)) { command_print(CMD, "Retrieval of free memory is not supported by " "the device"); return ERROR_OK; } ret = jaylink_get_free_memory(devh, &tmp); if (ret != JAYLINK_OK) { command_print(CMD, "jaylink_get_free_memory() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } command_print(CMD, "Device has %" PRIu32 " bytes of free memory", tmp); return ERROR_OK; } COMMAND_HANDLER(jlink_handle_jlink_jtag_command) { int tmp; int version; if (!CMD_ARGC) { switch (jtag_command_version) { case JAYLINK_JTAG_VERSION_2: version = 2; break; case JAYLINK_JTAG_VERSION_3: version = 3; break; default: return ERROR_FAIL; } command_print(CMD, "JTAG command version: %i", version); } else if (CMD_ARGC == 1) { if (sscanf(CMD_ARGV[0], "%i", &tmp) != 1) { command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; } switch (tmp) { case 2: jtag_command_version = JAYLINK_JTAG_VERSION_2; break; case 3: jtag_command_version = JAYLINK_JTAG_VERSION_3; break; default: command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; } } else { command_print(CMD, "Need exactly one argument for jlink jtag"); return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } COMMAND_HANDLER(jlink_handle_target_power_command) { int ret; int enable; if (CMD_ARGC != 1) { command_print(CMD, "Need exactly one argument for jlink targetpower"); return ERROR_COMMAND_SYNTAX_ERROR; } if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) { command_print(CMD, "Target power supply is not supported by the " "device"); return ERROR_OK; } if (!strcmp(CMD_ARGV[0], "on")) { enable = true; } else if (!strcmp(CMD_ARGV[0], "off")) { enable = false; } else { command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); return ERROR_FAIL; } ret = jaylink_set_target_power(devh, enable); if (ret != JAYLINK_OK) { command_print(CMD, "jaylink_set_target_power() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } return ERROR_OK; } static void show_config_usb_address(struct command_invocation *cmd) { if (config.usb_address != tmp_config.usb_address) command_print(cmd, "USB address: %u [%u]", config.usb_address, tmp_config.usb_address); else command_print(cmd, "USB address: %u", config.usb_address); } static void show_config_ip_address(struct command_invocation *cmd) { if (!memcmp(config.ip_address, tmp_config.ip_address, 4)) command_print(cmd, "IP address: %d.%d.%d.%d", config.ip_address[3], config.ip_address[2], config.ip_address[1], config.ip_address[0]); else command_print(cmd, "IP address: %d.%d.%d.%d [%d.%d.%d.%d]", config.ip_address[3], config.ip_address[2], config.ip_address[1], config.ip_address[0], tmp_config.ip_address[3], tmp_config.ip_address[2], tmp_config.ip_address[1], tmp_config.ip_address[0]); if (!memcmp(config.subnet_mask, tmp_config.subnet_mask, 4)) command_print(cmd, "Subnet mask: %d.%d.%d.%d", config.subnet_mask[3], config.subnet_mask[2], config.subnet_mask[1], config.subnet_mask[0]); else command_print(cmd, "Subnet mask: %d.%d.%d.%d [%d.%d.%d.%d]", config.subnet_mask[3], config.subnet_mask[2], config.subnet_mask[1], config.subnet_mask[0], tmp_config.subnet_mask[3], tmp_config.subnet_mask[2], tmp_config.subnet_mask[1], tmp_config.subnet_mask[0]); } static void show_config_mac_address(struct command_invocation *cmd) { if (!memcmp(config.mac_address, tmp_config.mac_address, 6)) command_print(cmd, "MAC address: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x", config.mac_address[5], config.mac_address[4], config.mac_address[3], config.mac_address[2], config.mac_address[1], config.mac_address[0]); else command_print(cmd, "MAC address: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x " "[%.02x:%.02x:%.02x:%.02x:%.02x:%.02x]", config.mac_address[5], config.mac_address[4], config.mac_address[3], config.mac_address[2], config.mac_address[1], config.mac_address[0], tmp_config.mac_address[5], tmp_config.mac_address[4], tmp_config.mac_address[3], tmp_config.mac_address[2], tmp_config.mac_address[1], tmp_config.mac_address[0]); } static void show_config_target_power(struct command_invocation *cmd) { const char *target_power; const char *current_target_power; if (!config.target_power) target_power = "off"; else target_power = "on"; if (!tmp_config.target_power) current_target_power = "off"; else current_target_power = "on"; if (config.target_power != tmp_config.target_power) command_print(cmd, "Target power supply: %s [%s]", target_power, current_target_power); else command_print(cmd, "Target power supply: %s", target_power); } static void show_config(struct command_invocation *cmd) { command_print(cmd, "J-Link device configuration:"); show_config_usb_address(cmd); if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) show_config_target_power(cmd); if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_ETHERNET)) { show_config_ip_address(cmd); show_config_mac_address(cmd); } } static int poll_trace(uint8_t *buf, size_t *size) { int ret; uint32_t length; length = *size; ret = jaylink_swo_read(devh, buf, &length); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_swo_read() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } *size = length; return ERROR_OK; } static uint32_t calculate_trace_buffer_size(void) { int ret; uint32_t tmp; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_FREE_MEMORY)) return 0; ret = jaylink_get_free_memory(devh, &tmp); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_free_memory() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } if (tmp > 0x3fff || tmp <= 0x600) tmp = tmp >> 1; else tmp = tmp - 0x400; return tmp & 0xffffff00; } static bool calculate_swo_prescaler(unsigned int traceclkin_freq, uint32_t trace_freq, uint16_t *prescaler) { unsigned int presc = (traceclkin_freq + trace_freq / 2) / trace_freq; if (presc == 0 || presc > TPIU_ACPR_MAX_SWOSCALER + 1) return false; /* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */ unsigned int max_deviation = (traceclkin_freq * 3) / 100; if (presc * trace_freq < traceclkin_freq - max_deviation || presc * trace_freq > traceclkin_freq + max_deviation) return false; *prescaler = presc; return true; } static bool detect_swo_freq_and_prescaler(struct jaylink_swo_speed speed, unsigned int traceclkin_freq, unsigned int *trace_freq, uint16_t *prescaler) { uint32_t divider; unsigned int presc; double deviation; for (divider = speed.min_div; divider <= speed.max_div; divider++) { *trace_freq = speed.freq / divider; presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / *trace_freq + 1; if (presc > TPIU_ACPR_MAX_SWOSCALER + 1) break; deviation = fabs(1.0 - ((double)*trace_freq * presc / traceclkin_freq)); if (deviation <= SWO_MAX_FREQ_DEV) { *prescaler = presc; return true; } } return false; } static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler) { int ret; uint32_t buffer_size; struct jaylink_swo_speed speed; uint32_t divider; uint32_t min_freq; uint32_t max_freq; trace_enabled = enabled; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SWO)) { if (!enabled) return ERROR_OK; LOG_ERROR("Trace capturing is not supported by the device"); return ERROR_FAIL; } ret = jaylink_swo_stop(devh); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_swo_stop() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } if (!enabled) { /* * Adjust the SWD transaction buffer size as stopping SWO capturing * deallocates device internal memory. */ if (!adjust_swd_buffer_size()) return ERROR_FAIL; return ERROR_OK; } if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) { LOG_ERROR("Selected pin protocol is not supported"); return ERROR_FAIL; } buffer_size = calculate_trace_buffer_size(); if (!buffer_size) { LOG_ERROR("Not enough free device memory to start trace capturing"); return ERROR_FAIL; } ret = jaylink_swo_get_speeds(devh, JAYLINK_SWO_MODE_UART, &speed); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_swo_get_speeds() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } if (*trace_freq > 0) { divider = speed.freq / *trace_freq; min_freq = speed.freq / speed.max_div; max_freq = speed.freq / speed.min_div; if (*trace_freq > max_freq) { LOG_INFO("Given SWO frequency too high, using %" PRIu32 " Hz instead", max_freq); *trace_freq = max_freq; } else if (*trace_freq < min_freq) { LOG_INFO("Given SWO frequency too low, using %" PRIu32 " Hz instead", min_freq); *trace_freq = min_freq; } else if (*trace_freq != speed.freq / divider) { *trace_freq = speed.freq / divider; LOG_INFO("Given SWO frequency is not supported by the device, " "using %u Hz instead", *trace_freq); } if (!calculate_swo_prescaler(traceclkin_freq, *trace_freq, prescaler)) { LOG_ERROR("SWO frequency is not suitable. Please choose a " "different frequency or use auto-detection"); return ERROR_FAIL; } } else { LOG_INFO("Trying to auto-detect SWO frequency"); if (!detect_swo_freq_and_prescaler(speed, traceclkin_freq, trace_freq, prescaler)) { LOG_ERROR("Maximum permitted frequency deviation of %.02f %% " "could not be achieved", SWO_MAX_FREQ_DEV); LOG_ERROR("Auto-detection of SWO frequency failed"); return ERROR_FAIL; } LOG_INFO("Using SWO frequency of %u Hz", *trace_freq); } ret = jaylink_swo_start(devh, JAYLINK_SWO_MODE_UART, *trace_freq, buffer_size); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_start_swo() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } LOG_DEBUG("Using %" PRIu32 " bytes device memory for trace capturing", buffer_size); /* * Adjust the SWD transaction buffer size as starting SWO capturing * allocates device internal memory. */ if (!adjust_swd_buffer_size()) return ERROR_FAIL; return ERROR_OK; } COMMAND_HANDLER(jlink_handle_config_usb_address_command) { uint8_t tmp; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { command_print(CMD, "Reading configuration is not supported by the " "device"); return ERROR_OK; } if (!CMD_ARGC) { show_config_usb_address(CMD); } else if (CMD_ARGC == 1) { if (sscanf(CMD_ARGV[0], "%" SCNd8, &tmp) != 1) { command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); return ERROR_FAIL; } if (tmp > JAYLINK_USB_ADDRESS_3) { command_print(CMD, "Invalid USB address: %u", tmp); return ERROR_FAIL; } tmp_config.usb_address = tmp; } else { command_print(CMD, "Need exactly one argument for jlink config usb"); return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } COMMAND_HANDLER(jlink_handle_config_target_power_command) { int enable; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { command_print(CMD, "Reading configuration is not supported by the " "device"); return ERROR_OK; } if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) { command_print(CMD, "Target power supply is not supported by the " "device"); return ERROR_OK; } if (!CMD_ARGC) { show_config_target_power(CMD); } else if (CMD_ARGC == 1) { if (!strcmp(CMD_ARGV[0], "on")) { enable = true; } else if (!strcmp(CMD_ARGV[0], "off")) { enable = false; } else { command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); return ERROR_FAIL; } tmp_config.target_power = enable; } else { command_print(CMD, "Need exactly one argument for jlink config " "targetpower"); return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } COMMAND_HANDLER(jlink_handle_config_mac_address_command) { uint8_t addr[6]; int i; char *e; const char *str; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { command_print(CMD, "Reading configuration is not supported by the " "device"); return ERROR_OK; } if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ETHERNET)) { command_print(CMD, "Ethernet connectivity is not supported by the " "device"); return ERROR_OK; } if (!CMD_ARGC) { show_config_mac_address(CMD); } else if (CMD_ARGC == 1) { str = CMD_ARGV[0]; if ((strlen(str) != 17) || (str[2] != ':' || str[5] != ':' || str[8] != ':' || str[11] != ':' || str[14] != ':')) { command_print(CMD, "Invalid MAC address format"); return ERROR_COMMAND_SYNTAX_ERROR; } for (i = 5; i >= 0; i--) { addr[i] = strtoul(str, &e, 16); str = e + 1; } if (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) { command_print(CMD, "Invalid MAC address: zero address"); return ERROR_COMMAND_SYNTAX_ERROR; } if (!(0x01 & addr[0])) { command_print(CMD, "Invalid MAC address: multicast address"); return ERROR_COMMAND_SYNTAX_ERROR; } memcpy(tmp_config.mac_address, addr, sizeof(addr)); } else { command_print(CMD, "Need exactly one argument for jlink config mac"); return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } static bool string_to_ip(const char *s, uint8_t *ip, int *pos) { uint8_t lip[4]; char *e; const char *s_save = s; int i; if (!s) return false; for (i = 0; i < 4; i++) { lip[i] = strtoul(s, &e, 10); if (*e != '.' && i != 3) return false; s = e + 1; } *pos = e - s_save; memcpy(ip, lip, sizeof(lip)); return true; } static void cpy_ip(uint8_t *dst, uint8_t *src) { int i, j; for (i = 0, j = 3; i < 4; i++, j--) dst[i] = src[j]; } COMMAND_HANDLER(jlink_handle_config_ip_address_command) { uint8_t ip_address[4]; uint32_t subnet_mask = 0; int i, len; uint8_t subnet_bits = 24; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { command_print(CMD, "Reading configuration is not supported by the " "device"); return ERROR_OK; } if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ETHERNET)) { command_print(CMD, "Ethernet connectivity is not supported by the " "device"); return ERROR_OK; } if (!CMD_ARGC) { show_config_ip_address(CMD); } else { if (!string_to_ip(CMD_ARGV[0], ip_address, &i)) return ERROR_COMMAND_SYNTAX_ERROR; len = strlen(CMD_ARGV[0]); /* Check for format A.B.C.D/E. */ if (i < len) { if (CMD_ARGV[0][i] != '/') return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0] + i + 1, subnet_bits); } else if (CMD_ARGC > 1) { if (!string_to_ip(CMD_ARGV[1], (uint8_t *)&subnet_mask, &i)) return ERROR_COMMAND_SYNTAX_ERROR; } if (!subnet_mask) subnet_mask = (uint32_t)(subnet_bits < 32 ? ((1ULL << subnet_bits) - 1) : 0xffffffff); cpy_ip(tmp_config.ip_address, ip_address); cpy_ip(tmp_config.subnet_mask, (uint8_t *)&subnet_mask); } return ERROR_OK; } COMMAND_HANDLER(jlink_handle_config_reset_command) { if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) return ERROR_OK; memcpy(&tmp_config, &config, sizeof(struct device_config)); return ERROR_OK; } COMMAND_HANDLER(jlink_handle_config_write_command) { int ret; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { command_print(CMD, "Reading configuration is not supported by the " "device"); return ERROR_OK; } if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_WRITE_CONFIG)) { command_print(CMD, "Writing configuration is not supported by the " "device"); return ERROR_OK; } if (!memcmp(&config, &tmp_config, sizeof(struct device_config))) { command_print(CMD, "Operation not performed due to no changes in " "the configuration"); return ERROR_OK; } ret = jaylink_write_raw_config(devh, (const uint8_t *)&tmp_config); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_write_raw_config() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } if (!read_device_config(&config)) { LOG_ERROR("Failed to read device configuration for verification"); return ERROR_FAIL; } if (memcmp(&config, &tmp_config, sizeof(struct device_config))) { LOG_ERROR("Verification of device configuration failed. Please check " "your device"); return ERROR_FAIL; } memcpy(&tmp_config, &config, sizeof(struct device_config)); command_print(CMD, "The new device configuration applies after power " "cycling the J-Link device"); return ERROR_OK; } COMMAND_HANDLER(jlink_handle_config_command) { if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { command_print(CMD, "Device doesn't support reading configuration"); return ERROR_OK; } if (CMD_ARGC == 0) show_config(CMD); return ERROR_OK; } COMMAND_HANDLER(jlink_handle_emucom_write_command) { int ret; size_t tmp; uint32_t channel; uint32_t length; uint8_t *buf; size_t dummy; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) { LOG_ERROR("Device does not support EMUCOM"); return ERROR_FAIL; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], channel); tmp = strlen(CMD_ARGV[1]); if (tmp % 2 != 0) { LOG_ERROR("Data must be encoded as hexadecimal pairs"); return ERROR_COMMAND_ARGUMENT_INVALID; } buf = malloc(tmp / 2); if (!buf) { LOG_ERROR("Failed to allocate buffer"); return ERROR_FAIL; } dummy = unhexify(buf, CMD_ARGV[1], tmp / 2); if (dummy != (tmp / 2)) { LOG_ERROR("Data must be encoded as hexadecimal pairs"); free(buf); return ERROR_COMMAND_ARGUMENT_INVALID; } length = tmp / 2; ret = jaylink_emucom_write(devh, channel, buf, &length); free(buf); if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) { LOG_ERROR("Channel not supported by the device"); return ERROR_FAIL; } else if (ret != JAYLINK_OK) { LOG_ERROR("Failed to write to channel: %s", jaylink_strerror(ret)); return ERROR_FAIL; } if (length != (tmp / 2)) LOG_WARNING("Only %" PRIu32 " bytes written to the channel", length); return ERROR_OK; } COMMAND_HANDLER(jlink_handle_emucom_read_command) { int ret; uint32_t channel; uint32_t length; uint8_t *buf; size_t tmp; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) { LOG_ERROR("Device does not support EMUCOM"); return ERROR_FAIL; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], channel); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); buf = malloc(length * 3 + 1); if (!buf) { LOG_ERROR("Failed to allocate buffer"); return ERROR_FAIL; } ret = jaylink_emucom_read(devh, channel, buf, &length); if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) { LOG_ERROR("Channel is not supported by the device"); free(buf); return ERROR_FAIL; } else if (ret == JAYLINK_ERR_DEV_NOT_AVAILABLE) { LOG_ERROR("Channel is not available for the requested amount of data. " "%" PRIu32 " bytes are available", length); free(buf); return ERROR_FAIL; } else if (ret != JAYLINK_OK) { LOG_ERROR("Failed to read from channel: %s", jaylink_strerror(ret)); free(buf); return ERROR_FAIL; } tmp = hexify((char *)buf + length, buf, length, 2 * length + 1); if (tmp != 2 * length) { LOG_ERROR("Failed to convert data into hexadecimal string"); free(buf); return ERROR_FAIL; } command_print(CMD, "%s", buf + length); free(buf); return ERROR_OK; } static const struct command_registration jlink_config_subcommand_handlers[] = { { .name = "usb", .handler = &jlink_handle_config_usb_address_command, .mode = COMMAND_EXEC, .help = "set the USB address", .usage = "[0-3]", }, { .name = "targetpower", .handler = &jlink_handle_config_target_power_command, .mode = COMMAND_EXEC, .help = "set the target power supply", .usage = "[on|off]" }, { .name = "mac", .handler = &jlink_handle_config_mac_address_command, .mode = COMMAND_EXEC, .help = "set the MAC Address", .usage = "[ff:ff:ff:ff:ff:ff]", }, { .name = "ip", .handler = &jlink_handle_config_ip_address_command, .mode = COMMAND_EXEC, .help = "set the IP address, where A.B.C.D is the IP address, " "E the bit of the subnet mask, F.G.H.I the subnet mask", .usage = "[A.B.C.D[/E] [F.G.H.I]]", }, { .name = "reset", .handler = &jlink_handle_config_reset_command, .mode = COMMAND_EXEC, .help = "undo configuration changes", .usage = "", }, { .name = "write", .handler = &jlink_handle_config_write_command, .mode = COMMAND_EXEC, .help = "write configuration to the device", .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration jlink_emucom_subcommand_handlers[] = { { .name = "write", .handler = &jlink_handle_emucom_write_command, .mode = COMMAND_EXEC, .help = "write to a channel", .usage = "<channel> <data>", }, { .name = "read", .handler = &jlink_handle_emucom_read_command, .mode = COMMAND_EXEC, .help = "read from a channel", .usage = "<channel> <length>" }, COMMAND_REGISTRATION_DONE }; static const struct command_registration jlink_subcommand_handlers[] = { { .name = "jtag", .handler = &jlink_handle_jlink_jtag_command, .mode = COMMAND_EXEC, .help = "select the JTAG command version", .usage = "[2|3]", }, { .name = "targetpower", .handler = &jlink_handle_target_power_command, .mode = COMMAND_EXEC, .help = "set the target power supply", .usage = "<on|off>" }, { .name = "freemem", .handler = &jlink_handle_free_memory_command, .mode = COMMAND_EXEC, .help = "show free device memory", .usage = "", }, { .name = "hwstatus", .handler = &jlink_handle_hwstatus_command, .mode = COMMAND_EXEC, .help = "show the hardware status", .usage = "", }, { .name = "usb", .handler = &jlink_usb_command, .mode = COMMAND_CONFIG, .help = "set the USB address of the device that should be used", .usage = "<0-3>" }, { .name = "config", .handler = &jlink_handle_config_command, .mode = COMMAND_EXEC, .help = "access the device configuration. If no argument is given " "this will show the device configuration", .chain = jlink_config_subcommand_handlers, .usage = "[<cmd>]", }, { .name = "emucom", .mode = COMMAND_EXEC, .help = "access EMUCOM channel", .chain = jlink_emucom_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration jlink_command_handlers[] = { { .name = "jlink", .mode = COMMAND_ANY, .help = "perform jlink management", .chain = jlink_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static int jlink_swd_init(void) { iface = JAYLINK_TIF_SWD; return ERROR_OK; } static void jlink_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { assert(!(cmd & SWD_CMD_RNW)); jlink_swd_queue_cmd(cmd, NULL, value, ap_delay_clk); } static void jlink_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { assert(cmd & SWD_CMD_RNW); jlink_swd_queue_cmd(cmd, value, 0, ap_delay_clk); } /***************************************************************************/ /* J-Link tap functions */ static unsigned tap_length; /* In SWD mode use tms buffer for direction control */ static uint8_t tms_buffer[JLINK_TAP_BUFFER_SIZE]; static uint8_t tdi_buffer[JLINK_TAP_BUFFER_SIZE]; static uint8_t tdo_buffer[JLINK_TAP_BUFFER_SIZE]; struct pending_scan_result { /** First bit position in tdo_buffer to read. */ unsigned first; /** Number of bits to read. */ unsigned length; /** Location to store the result */ void *buffer; /** Offset in the destination buffer */ unsigned buffer_offset; /** SWD command */ uint8_t swd_cmd; }; #define MAX_PENDING_SCAN_RESULTS 256 static int pending_scan_results_length; static struct pending_scan_result pending_scan_results_buffer[MAX_PENDING_SCAN_RESULTS]; static void jlink_tap_init(void) { tap_length = 0; pending_scan_results_length = 0; memset(tms_buffer, 0, sizeof(tms_buffer)); memset(tdi_buffer, 0, sizeof(tdi_buffer)); } static void jlink_clock_data(const uint8_t *out, unsigned out_offset, const uint8_t *tms_out, unsigned tms_offset, uint8_t *in, unsigned in_offset, unsigned length) { do { unsigned available_length = JLINK_TAP_BUFFER_SIZE - tap_length / 8; if (!available_length || (in && pending_scan_results_length == MAX_PENDING_SCAN_RESULTS)) { if (jlink_flush() != ERROR_OK) return; available_length = JLINK_TAP_BUFFER_SIZE; } struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[pending_scan_results_length]; unsigned scan_length = length > available_length ? available_length : length; if (out) buf_set_buf(out, out_offset, tdi_buffer, tap_length, scan_length); if (tms_out) buf_set_buf(tms_out, tms_offset, tms_buffer, tap_length, scan_length); if (in) { pending_scan_result->first = tap_length; pending_scan_result->length = scan_length; pending_scan_result->buffer = in; pending_scan_result->buffer_offset = in_offset; pending_scan_results_length++; } tap_length += scan_length; out_offset += scan_length; tms_offset += scan_length; in_offset += scan_length; length -= scan_length; } while (length > 0); } static int jlink_flush(void) { int i; int ret; if (!tap_length) return ERROR_OK; jlink_last_state = jtag_debug_state_machine(tms_buffer, tdi_buffer, tap_length, jlink_last_state); ret = jaylink_jtag_io(devh, tms_buffer, tdi_buffer, tdo_buffer, tap_length, jtag_command_version); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_jtag_io() failed: %s", jaylink_strerror(ret)); jlink_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } for (i = 0; i < pending_scan_results_length; i++) { struct pending_scan_result *p = &pending_scan_results_buffer[i]; buf_set_buf(tdo_buffer, p->first, p->buffer, p->buffer_offset, p->length); LOG_DEBUG_IO("Pending scan result, length = %d", p->length); } jlink_tap_init(); return ERROR_OK; } static void fill_buffer(uint8_t *buf, uint32_t val, uint32_t len) { unsigned int tap_pos = tap_length; while (len > 32) { buf_set_u32(buf, tap_pos, 32, val); len -= 32; tap_pos += 32; } if (len) buf_set_u32(buf, tap_pos, len, val); } static void jlink_queue_data_out(const uint8_t *data, uint32_t len) { const uint32_t dir_out = 0xffffffff; if (data) bit_copy(tdi_buffer, tap_length, data, 0, len); else fill_buffer(tdi_buffer, 0, len); fill_buffer(tms_buffer, dir_out, len); tap_length += len; } static void jlink_queue_data_in(uint32_t len) { const uint32_t dir_in = 0; fill_buffer(tms_buffer, dir_in, len); tap_length += len; } static int jlink_swd_switch_seq(enum swd_special_seq seq) { const uint8_t *s; unsigned int s_len; switch (seq) { case LINE_RESET: LOG_DEBUG("SWD line reset"); s = swd_seq_line_reset; s_len = swd_seq_line_reset_len; break; case JTAG_TO_SWD: LOG_DEBUG("JTAG-to-SWD"); s = swd_seq_jtag_to_swd; s_len = swd_seq_jtag_to_swd_len; break; case JTAG_TO_DORMANT: LOG_DEBUG("JTAG-to-DORMANT"); s = swd_seq_jtag_to_dormant; s_len = swd_seq_jtag_to_dormant_len; break; case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); s = swd_seq_swd_to_jtag; s_len = swd_seq_swd_to_jtag_len; break; case SWD_TO_DORMANT: LOG_DEBUG("SWD-to-DORMANT"); s = swd_seq_swd_to_dormant; s_len = swd_seq_swd_to_dormant_len; break; case DORMANT_TO_SWD: LOG_DEBUG("DORMANT-to-SWD"); s = swd_seq_dormant_to_swd; s_len = swd_seq_dormant_to_swd_len; break; case DORMANT_TO_JTAG: LOG_DEBUG("DORMANT-to-JTAG"); s = swd_seq_dormant_to_jtag; s_len = swd_seq_dormant_to_jtag_len; break; default: LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; } jlink_queue_data_out(s, s_len); return ERROR_OK; } static int jlink_swd_run_queue(void) { int i; int ret; LOG_DEBUG("Executing %d queued transactions", pending_scan_results_length); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); goto skip; } /* * A transaction must be followed by another transaction or at least 8 idle * cycles to ensure that data is clocked through the AP. */ jlink_queue_data_out(NULL, 8); ret = jaylink_swd_io(devh, tms_buffer, tdi_buffer, tdo_buffer, tap_length); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_swd_io() failed: %s", jaylink_strerror(ret)); goto skip; } for (i = 0; i < pending_scan_results_length; i++) { /* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */ bool check_ack = swd_cmd_returns_ack(pending_scan_results_buffer[i].swd_cmd); int ack = buf_get_u32(tdo_buffer, pending_scan_results_buffer[i].first, 3); if (check_ack && ack != SWD_ACK_OK) { LOG_DEBUG("SWD ack not OK: %d %s", ack, ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK"); queued_retval = swd_ack_to_error_code(ack); goto skip; } else if (pending_scan_results_buffer[i].length) { uint32_t data = buf_get_u32(tdo_buffer, 3 + pending_scan_results_buffer[i].first, 32); int parity = buf_get_u32(tdo_buffer, 3 + 32 + pending_scan_results_buffer[i].first, 1); if (parity != parity_u32(data)) { LOG_ERROR("SWD: Read data parity mismatch"); queued_retval = ERROR_FAIL; goto skip; } if (pending_scan_results_buffer[i].buffer) *(uint32_t *)pending_scan_results_buffer[i].buffer = data; } } skip: jlink_tap_init(); ret = queued_retval; queued_retval = ERROR_OK; return ret; } static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk) { uint8_t data_parity_trn[DIV_ROUND_UP(32 + 1, 8)]; if (tap_length + 46 + 8 + ap_delay_clk >= swd_buffer_size * 8 || pending_scan_results_length == MAX_PENDING_SCAN_RESULTS) { /* Not enough room in the queue. Run the queue. */ queued_retval = jlink_swd_run_queue(); } if (queued_retval != ERROR_OK) return; pending_scan_results_buffer[pending_scan_results_length].swd_cmd = cmd; cmd |= SWD_CMD_START | SWD_CMD_PARK; jlink_queue_data_out(&cmd, 8); pending_scan_results_buffer[pending_scan_results_length].first = tap_length; if (cmd & SWD_CMD_RNW) { /* Queue a read transaction. */ pending_scan_results_buffer[pending_scan_results_length].length = 32; pending_scan_results_buffer[pending_scan_results_length].buffer = dst; jlink_queue_data_in(1 + 3 + 32 + 1 + 1); } else { /* Queue a write transaction. */ pending_scan_results_buffer[pending_scan_results_length].length = 0; jlink_queue_data_in(1 + 3 + 1); buf_set_u32(data_parity_trn, 0, 32, data); buf_set_u32(data_parity_trn, 32, 1, parity_u32(data)); jlink_queue_data_out(data_parity_trn, 32 + 1); } pending_scan_results_length++; /* Insert idle cycles after AP accesses to avoid WAIT. */ if (cmd & SWD_CMD_APNDP) jlink_queue_data_out(NULL, ap_delay_clk); } static const struct swd_driver jlink_swd = { .init = &jlink_swd_init, .switch_seq = &jlink_swd_switch_seq, .read_reg = &jlink_swd_read_reg, .write_reg = &jlink_swd_write_reg, .run = &jlink_swd_run_queue, }; static const char * const jlink_transports[] = { "jtag", "swd", NULL }; static struct jtag_interface jlink_interface = { .execute_queue = &jlink_execute_queue, }; struct adapter_driver jlink_adapter_driver = { .name = "jlink", .transports = jlink_transports, .commands = jlink_command_handlers, .init = &jlink_init, .quit = &jlink_quit, .reset = &jlink_reset_safe, .speed = &jlink_speed, .khz = &jlink_khz, .speed_div = &jlink_speed_div, .config_trace = &config_trace, .poll_trace = &poll_trace, .jtag_ops = &jlink_interface, .swd_ops = &jlink_swd, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/jtag_dpi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * JTAG to DPI driver * * Copyright (C) 2013 Franck Jullien, <elec4fun@gmail.com> * * Copyright (C) 2019-2020, Ampere Computing LLC * * See file CREDITS for list of people who contributed to this * project. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/interface.h> #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif #ifndef _WIN32 #include <netinet/tcp.h> #endif #define SERVER_ADDRESS "127.0.0.1" #define SERVER_PORT 5555 static uint16_t server_port = SERVER_PORT; static char *server_address; static int sockfd; static struct sockaddr_in serv_addr; static uint8_t *last_ir_buf; static int last_ir_num_bits; static int write_sock(char *buf, size_t len) { if (!buf) { LOG_ERROR("%s: NULL 'buf' argument, file %s, line %d", __func__, __FILE__, __LINE__); return ERROR_FAIL; } if (write(sockfd, buf, len) != (ssize_t)len) { LOG_ERROR("%s: %s, file %s, line %d", __func__, strerror(errno), __FILE__, __LINE__); return ERROR_FAIL; } return ERROR_OK; } static int read_sock(char *buf, size_t len) { if (!buf) { LOG_ERROR("%s: NULL 'buf' argument, file %s, line %d", __func__, __FILE__, __LINE__); return ERROR_FAIL; } if (read(sockfd, buf, len) != (ssize_t)len) { LOG_ERROR("%s: %s, file %s, line %d", __func__, strerror(errno), __FILE__, __LINE__); return ERROR_FAIL; } return ERROR_OK; } /** * jtag_dpi_reset - ask to reset the JTAG device * @param trst 1 if TRST is to be asserted * @param srst 1 if SRST is to be asserted */ static int jtag_dpi_reset(int trst, int srst) { char *buf = "reset\n"; int ret = ERROR_OK; LOG_DEBUG_IO("JTAG DRIVER DEBUG: reset trst: %i srst %i", trst, srst); if (trst == 1) { /* reset the JTAG TAP controller */ ret = write_sock(buf, strlen(buf)); if (ret != ERROR_OK) { LOG_ERROR("write_sock() fail, file %s, line %d", __FILE__, __LINE__); } } if (srst == 1) { /* System target reset not supported */ LOG_ERROR("DPI SRST not supported"); ret = ERROR_FAIL; } return ret; } /** * jtag_dpi_scan - launches a DR-scan or IR-scan * @param cmd the command to launch * * Launch a JTAG IR-scan or DR-scan * * Returns ERROR_OK if OK, ERROR_xxx if a read/write error occurred. */ static int jtag_dpi_scan(struct scan_command *cmd) { char buf[20]; uint8_t *data_buf; int num_bits, bytes; int ret = ERROR_OK; num_bits = jtag_build_buffer(cmd, &data_buf); if (!data_buf) { LOG_ERROR("jtag_build_buffer call failed, data_buf == NULL, " "file %s, line %d", __FILE__, __LINE__); return ERROR_FAIL; } bytes = DIV_ROUND_UP(num_bits, 8); if (cmd->ir_scan) { free(last_ir_buf); last_ir_buf = (uint8_t *)malloc(bytes * sizeof(uint8_t)); if (!last_ir_buf) { LOG_ERROR("%s: malloc fail, file %s, line %d", __func__, __FILE__, __LINE__); ret = ERROR_FAIL; goto out; } memcpy(last_ir_buf, data_buf, bytes); last_ir_num_bits = num_bits; } snprintf(buf, sizeof(buf), "%s %d\n", cmd->ir_scan ? "ib" : "db", num_bits); ret = write_sock(buf, strlen(buf)); if (ret != ERROR_OK) { LOG_ERROR("write_sock() fail, file %s, line %d", __FILE__, __LINE__); goto out; } ret = write_sock((char *)data_buf, bytes); if (ret != ERROR_OK) { LOG_ERROR("write_sock() fail, file %s, line %d", __FILE__, __LINE__); goto out; } ret = read_sock((char *)data_buf, bytes); if (ret != ERROR_OK) { LOG_ERROR("read_sock() fail, file %s, line %d", __FILE__, __LINE__); goto out; } ret = jtag_read_buffer(data_buf, cmd); if (ret != ERROR_OK) { LOG_ERROR("jtag_read_buffer() fail, file %s, line %d", __FILE__, __LINE__); goto out; } out: free(data_buf); return ret; } static int jtag_dpi_runtest(int cycles) { char buf[20]; uint8_t *data_buf = last_ir_buf, *read_scan; int num_bits = last_ir_num_bits, bytes; int ret = ERROR_OK; if (!data_buf) { LOG_ERROR("%s: NULL 'data_buf' argument, file %s, line %d", __func__, __FILE__, __LINE__); return ERROR_FAIL; } if (num_bits <= 0) { LOG_ERROR("%s: 'num_bits' invalid value, file %s, line %d", __func__, __FILE__, __LINE__); return ERROR_FAIL; } bytes = DIV_ROUND_UP(num_bits, 8); read_scan = (uint8_t *)malloc(bytes * sizeof(uint8_t)); if (!read_scan) { LOG_ERROR("%s: malloc fail, file %s, line %d", __func__, __FILE__, __LINE__); return ERROR_FAIL; } snprintf(buf, sizeof(buf), "ib %d\n", num_bits); while (cycles > 0) { ret = write_sock(buf, strlen(buf)); if (ret != ERROR_OK) { LOG_ERROR("write_sock() fail, file %s, line %d", __FILE__, __LINE__); goto out; } ret = write_sock((char *)data_buf, bytes); if (ret != ERROR_OK) { LOG_ERROR("write_sock() fail, file %s, line %d", __FILE__, __LINE__); goto out; } ret = read_sock((char *)read_scan, bytes); if (ret != ERROR_OK) { LOG_ERROR("read_sock() fail, file %s, line %d", __FILE__, __LINE__); goto out; } cycles -= num_bits + 6; } out: free(read_scan); return ret; } static int jtag_dpi_stableclocks(int cycles) { return jtag_dpi_runtest(cycles); } static int jtag_dpi_execute_queue(void) { struct jtag_command *cmd; int ret = ERROR_OK; for (cmd = jtag_command_queue; ret == ERROR_OK && cmd; cmd = cmd->next) { switch (cmd->type) { case JTAG_RUNTEST: ret = jtag_dpi_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_STABLECLOCKS: ret = jtag_dpi_stableclocks(cmd->cmd.stableclocks->num_cycles); break; case JTAG_TLR_RESET: /* Enter Test-Logic-Reset state by asserting TRST */ if (cmd->cmd.statemove->end_state == TAP_RESET) jtag_dpi_reset(1, 0); break; case JTAG_PATHMOVE: /* unsupported */ break; case JTAG_TMS: /* unsupported */ break; case JTAG_SLEEP: jtag_sleep(cmd->cmd.sleep->us); break; case JTAG_SCAN: ret = jtag_dpi_scan(cmd->cmd.scan); break; default: LOG_ERROR("BUG: unknown JTAG command type 0x%X", cmd->type); ret = ERROR_FAIL; break; } } return ret; } static int jtag_dpi_init(void) { sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { LOG_ERROR("socket: %s, function %s, file %s, line %d", strerror(errno), __func__, __FILE__, __LINE__); return ERROR_FAIL; } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(server_port); if (!server_address) { server_address = strdup(SERVER_ADDRESS); if (!server_address) { LOG_ERROR("%s: strdup fail, file %s, line %d", __func__, __FILE__, __LINE__); return ERROR_FAIL; } } serv_addr.sin_addr.s_addr = inet_addr(server_address); if (serv_addr.sin_addr.s_addr == INADDR_NONE) { LOG_ERROR("inet_addr error occurred"); return ERROR_FAIL; } if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { close(sockfd); LOG_ERROR("Can't connect to %s : %" PRIu16, server_address, server_port); return ERROR_FAIL; } if (serv_addr.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { /* This increases performance dramatically for local * connections, which is the most likely arrangement * for a DPI connection. */ int flag = 1; setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)); } LOG_INFO("Connection to %s : %" PRIu16 " succeed", server_address, server_port); return ERROR_OK; } static int jtag_dpi_quit(void) { free(server_address); server_address = NULL; return close(sockfd); } COMMAND_HANDLER(jtag_dpi_set_port) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; else if (CMD_ARGC == 0) LOG_INFO("Using server port %" PRIu16, server_port); else { COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], server_port); LOG_INFO("Set server port to %" PRIu16, server_port); } return ERROR_OK; } COMMAND_HANDLER(jtag_dpi_set_address) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; else if (CMD_ARGC == 0) { if (!server_address) { server_address = strdup(SERVER_ADDRESS); if (!server_address) { LOG_ERROR("%s: strdup fail, file %s, line %d", __func__, __FILE__, __LINE__); return ERROR_FAIL; } } LOG_INFO("Using server address %s", server_address); } else { free(server_address); server_address = strdup(CMD_ARGV[0]); if (!server_address) { LOG_ERROR("%s: strdup fail, file %s, line %d", __func__, __FILE__, __LINE__); return ERROR_FAIL; } LOG_INFO("Set server address to %s", server_address); } return ERROR_OK; } static const struct command_registration jtag_dpi_subcommand_handlers[] = { { .name = "set_port", .handler = &jtag_dpi_set_port, .mode = COMMAND_CONFIG, .help = "set the port of the DPI server", .usage = "[port]", }, { .name = "set_address", .handler = &jtag_dpi_set_address, .mode = COMMAND_CONFIG, .help = "set the address of the DPI server", .usage = "[address]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration jtag_dpi_command_handlers[] = { { .name = "jtag_dpi", .mode = COMMAND_ANY, .help = "perform jtag_dpi management", .chain = jtag_dpi_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static struct jtag_interface jtag_dpi_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = jtag_dpi_execute_queue, }; struct adapter_driver jtag_dpi_adapter_driver = { .name = "jtag_dpi", .transports = jtag_only, .commands = jtag_dpi_command_handlers, .init = jtag_dpi_init, .quit = jtag_dpi_quit, .reset = jtag_dpi_reset, .jtag_ops = &jtag_dpi_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/jtag_vpi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * JTAG to VPI driver * * Copyright (C) 2013 Franck Jullien, <elec4fun@gmail.com> * * See file CREDITS for list of people who contributed to this * project. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/interface.h> #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif #ifndef _WIN32 #include <netinet/tcp.h> #endif #include "helper/replacements.h" #define NO_TAP_SHIFT 0 #define TAP_SHIFT 1 #define DEFAULT_SERVER_ADDRESS "127.0.0.1" #define DEFAULT_SERVER_PORT 5555 #define XFERT_MAX_SIZE 512 #define CMD_RESET 0 #define CMD_TMS_SEQ 1 #define CMD_SCAN_CHAIN 2 #define CMD_SCAN_CHAIN_FLIP_TMS 3 #define CMD_STOP_SIMU 4 /* jtag_vpi server port and address to connect to */ static int server_port = DEFAULT_SERVER_PORT; static char *server_address; /* Send CMD_STOP_SIMU to server when OpenOCD exits? */ static bool stop_sim_on_exit; static int sockfd; static struct sockaddr_in serv_addr; /* One jtag_vpi "packet" as sent over a TCP channel. */ struct vpi_cmd { union { uint32_t cmd; unsigned char cmd_buf[4]; }; unsigned char buffer_out[XFERT_MAX_SIZE]; unsigned char buffer_in[XFERT_MAX_SIZE]; union { uint32_t length; unsigned char length_buf[4]; }; union { uint32_t nb_bits; unsigned char nb_bits_buf[4]; }; }; static char *jtag_vpi_cmd_to_str(int cmd_num) { switch (cmd_num) { case CMD_RESET: return "CMD_RESET"; case CMD_TMS_SEQ: return "CMD_TMS_SEQ"; case CMD_SCAN_CHAIN: return "CMD_SCAN_CHAIN"; case CMD_SCAN_CHAIN_FLIP_TMS: return "CMD_SCAN_CHAIN_FLIP_TMS"; case CMD_STOP_SIMU: return "CMD_STOP_SIMU"; default: return "<unknown>"; } } static int jtag_vpi_send_cmd(struct vpi_cmd *vpi) { int retval; /* Optional low-level JTAG debug */ if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { if (vpi->nb_bits > 0) { /* command with a non-empty data payload */ char *char_buf = buf_to_hex_str(vpi->buffer_out, (vpi->nb_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : vpi->nb_bits); LOG_DEBUG_IO("sending JTAG VPI cmd: cmd=%s, " "length=%" PRIu32 ", " "nb_bits=%" PRIu32 ", " "buf_out=0x%s%s", jtag_vpi_cmd_to_str(vpi->cmd), vpi->length, vpi->nb_bits, char_buf, (vpi->nb_bits > DEBUG_JTAG_IOZ) ? "(...)" : ""); free(char_buf); } else { /* command without data payload */ LOG_DEBUG_IO("sending JTAG VPI cmd: cmd=%s, " "length=%" PRIu32 ", " "nb_bits=%" PRIu32, jtag_vpi_cmd_to_str(vpi->cmd), vpi->length, vpi->nb_bits); } } /* Use little endian when transmitting/receiving jtag_vpi cmds. The choice of little endian goes against usual networking conventions but is intentional to remain compatible with most older OpenOCD builds (i.e. builds on little-endian platforms). */ h_u32_to_le(vpi->cmd_buf, vpi->cmd); h_u32_to_le(vpi->length_buf, vpi->length); h_u32_to_le(vpi->nb_bits_buf, vpi->nb_bits); retry_write: retval = write_socket(sockfd, vpi, sizeof(struct vpi_cmd)); if (retval < 0) { /* Account for the case when socket write is interrupted. */ #ifdef _WIN32 int wsa_err = WSAGetLastError(); if (wsa_err == WSAEINTR) goto retry_write; #else if (errno == EINTR) goto retry_write; #endif /* Otherwise this is an error using the socket, most likely fatal for the connection. B*/ log_socket_error("jtag_vpi xmit"); /* TODO: Clean way how adapter drivers can report fatal errors to upper layers of OpenOCD and let it perform an orderly shutdown? */ exit(-1); } else if (retval < (int)sizeof(struct vpi_cmd)) { /* This means we could not send all data, which is most likely fatal for the jtag_vpi connection (the underlying TCP connection likely not usable anymore) */ LOG_ERROR("jtag_vpi: Could not send all data through jtag_vpi connection."); exit(-1); } /* Otherwise the packet has been sent successfully. */ return ERROR_OK; } static int jtag_vpi_receive_cmd(struct vpi_cmd *vpi) { unsigned bytes_buffered = 0; while (bytes_buffered < sizeof(struct vpi_cmd)) { int bytes_to_receive = sizeof(struct vpi_cmd) - bytes_buffered; int retval = read_socket(sockfd, ((char *)vpi) + bytes_buffered, bytes_to_receive); if (retval < 0) { #ifdef _WIN32 int wsa_err = WSAGetLastError(); if (wsa_err == WSAEINTR) { /* socket read interrupted by WSACancelBlockingCall() */ continue; } #else if (errno == EINTR) { /* socket read interrupted by a signal */ continue; } #endif /* Otherwise, this is an error when accessing the socket. */ log_socket_error("jtag_vpi recv"); exit(-1); } else if (retval == 0) { /* Connection closed by the other side */ LOG_ERROR("Connection prematurely closed by jtag_vpi server."); exit(-1); } /* Otherwise, we have successfully received some data */ bytes_buffered += retval; } /* Use little endian when transmitting/receiving jtag_vpi cmds. */ vpi->cmd = le_to_h_u32(vpi->cmd_buf); vpi->length = le_to_h_u32(vpi->length_buf); vpi->nb_bits = le_to_h_u32(vpi->nb_bits_buf); return ERROR_OK; } /** * jtag_vpi_reset - ask to reset the JTAG device * @param trst 1 if TRST is to be asserted * @param srst 1 if SRST is to be asserted */ static int jtag_vpi_reset(int trst, int srst) { struct vpi_cmd vpi; memset(&vpi, 0, sizeof(struct vpi_cmd)); vpi.cmd = CMD_RESET; vpi.length = 0; return jtag_vpi_send_cmd(&vpi); } /** * jtag_vpi_tms_seq - ask a TMS sequence transition to JTAG * @param bits TMS bits to be written (bit0, bit1 .. bitN) * @param nb_bits number of TMS bits (between 1 and 8) * * Write a series of TMS transitions, where each transition consists in : * - writing out TCK=0, TMS=\<new_state>, TDI=\<???> * - writing out TCK=1, TMS=\<new_state>, TDI=\<???> which triggers the transition * The function ensures that at the end of the sequence, the clock (TCK) is put * low. */ static int jtag_vpi_tms_seq(const uint8_t *bits, int nb_bits) { struct vpi_cmd vpi; int nb_bytes; memset(&vpi, 0, sizeof(struct vpi_cmd)); nb_bytes = DIV_ROUND_UP(nb_bits, 8); vpi.cmd = CMD_TMS_SEQ; memcpy(vpi.buffer_out, bits, nb_bytes); vpi.length = nb_bytes; vpi.nb_bits = nb_bits; return jtag_vpi_send_cmd(&vpi); } /** * jtag_vpi_path_move - ask a TMS sequence transition to JTAG * @param cmd path transition * * Write a series of TMS transitions, where each transition consists in : * - writing out TCK=0, TMS=\<new_state>, TDI=\<???> * - writing out TCK=1, TMS=\<new_state>, TDI=\<???> which triggers the transition * The function ensures that at the end of the sequence, the clock (TCK) is put * low. */ static int jtag_vpi_path_move(struct pathmove_command *cmd) { uint8_t trans[DIV_ROUND_UP(cmd->num_states, 8)]; memset(trans, 0, DIV_ROUND_UP(cmd->num_states, 8)); for (int i = 0; i < cmd->num_states; i++) { if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) buf_set_u32(trans, i, 1, 1); tap_set_state(cmd->path[i]); } return jtag_vpi_tms_seq(trans, cmd->num_states); } /** * jtag_vpi_tms - ask a tms command * @param cmd tms command */ static int jtag_vpi_tms(struct tms_command *cmd) { return jtag_vpi_tms_seq(cmd->bits, cmd->num_bits); } static int jtag_vpi_state_move(tap_state_t state) { if (tap_get_state() == state) return ERROR_OK; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), state); int tms_len = tap_get_tms_path_len(tap_get_state(), state); int retval = jtag_vpi_tms_seq(&tms_scan, tms_len); if (retval != ERROR_OK) return retval; tap_set_state(state); return ERROR_OK; } static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift) { struct vpi_cmd vpi; int nb_bytes = DIV_ROUND_UP(nb_bits, 8); memset(&vpi, 0, sizeof(struct vpi_cmd)); vpi.cmd = tap_shift ? CMD_SCAN_CHAIN_FLIP_TMS : CMD_SCAN_CHAIN; if (bits) memcpy(vpi.buffer_out, bits, nb_bytes); else memset(vpi.buffer_out, 0xff, nb_bytes); vpi.length = nb_bytes; vpi.nb_bits = nb_bits; int retval = jtag_vpi_send_cmd(&vpi); if (retval != ERROR_OK) return retval; retval = jtag_vpi_receive_cmd(&vpi); if (retval != ERROR_OK) return retval; /* Optional low-level JTAG debug */ if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { char *char_buf = buf_to_hex_str(vpi.buffer_in, (nb_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : nb_bits); LOG_DEBUG_IO("recvd JTAG VPI data: nb_bits=%d, buf_in=0x%s%s", nb_bits, char_buf, (nb_bits > DEBUG_JTAG_IOZ) ? "(...)" : ""); free(char_buf); } if (bits) memcpy(bits, vpi.buffer_in, nb_bytes); return ERROR_OK; } /** * jtag_vpi_queue_tdi - short description * @param bits bits to be queued on TDI (or NULL if 0 are to be queued) * @param nb_bits number of bits * @param tap_shift */ static int jtag_vpi_queue_tdi(uint8_t *bits, int nb_bits, int tap_shift) { int nb_xfer = DIV_ROUND_UP(nb_bits, XFERT_MAX_SIZE * 8); int retval; while (nb_xfer) { if (nb_xfer == 1) { retval = jtag_vpi_queue_tdi_xfer(bits, nb_bits, tap_shift); if (retval != ERROR_OK) return retval; } else { retval = jtag_vpi_queue_tdi_xfer(bits, XFERT_MAX_SIZE * 8, NO_TAP_SHIFT); if (retval != ERROR_OK) return retval; nb_bits -= XFERT_MAX_SIZE * 8; if (bits) bits += XFERT_MAX_SIZE; } nb_xfer--; } return ERROR_OK; } /** * jtag_vpi_clock_tms - clock a TMS transition * @param tms the TMS to be sent * * Triggers a TMS transition (ie. one JTAG TAP state move). */ static int jtag_vpi_clock_tms(int tms) { const uint8_t tms_0 = 0; const uint8_t tms_1 = 1; return jtag_vpi_tms_seq(tms ? &tms_1 : &tms_0, 1); } /** * jtag_vpi_scan - launches a DR-scan or IR-scan * @param cmd the command to launch * * Launch a JTAG IR-scan or DR-scan * * Returns ERROR_OK if OK, ERROR_xxx if a read/write error occurred. */ static int jtag_vpi_scan(struct scan_command *cmd) { int scan_bits; uint8_t *buf = NULL; int retval = ERROR_OK; scan_bits = jtag_build_buffer(cmd, &buf); if (cmd->ir_scan) { retval = jtag_vpi_state_move(TAP_IRSHIFT); if (retval != ERROR_OK) return retval; } else { retval = jtag_vpi_state_move(TAP_DRSHIFT); if (retval != ERROR_OK) return retval; } if (cmd->end_state == TAP_DRSHIFT) { retval = jtag_vpi_queue_tdi(buf, scan_bits, NO_TAP_SHIFT); if (retval != ERROR_OK) return retval; } else { retval = jtag_vpi_queue_tdi(buf, scan_bits, TAP_SHIFT); if (retval != ERROR_OK) return retval; } if (cmd->end_state != TAP_DRSHIFT) { /* * As our JTAG is in an unstable state (IREXIT1 or DREXIT1), move it * forward to a stable IRPAUSE or DRPAUSE. */ retval = jtag_vpi_clock_tms(0); if (retval != ERROR_OK) return retval; if (cmd->ir_scan) tap_set_state(TAP_IRPAUSE); else tap_set_state(TAP_DRPAUSE); } retval = jtag_read_buffer(buf, cmd); if (retval != ERROR_OK) return retval; free(buf); if (cmd->end_state != TAP_DRSHIFT) { retval = jtag_vpi_state_move(cmd->end_state); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int jtag_vpi_runtest(int cycles, tap_state_t state) { int retval; retval = jtag_vpi_state_move(TAP_IDLE); if (retval != ERROR_OK) return retval; retval = jtag_vpi_queue_tdi(NULL, cycles, NO_TAP_SHIFT); if (retval != ERROR_OK) return retval; return jtag_vpi_state_move(state); } static int jtag_vpi_stableclocks(int cycles) { uint8_t tms_bits[4]; int cycles_remain = cycles; int nb_bits; int retval; const int CYCLES_ONE_BATCH = sizeof(tms_bits) * 8; assert(cycles >= 0); /* use TMS=1 in TAP RESET state, TMS=0 in all other stable states */ memset(&tms_bits, (tap_get_state() == TAP_RESET) ? 0xff : 0x00, sizeof(tms_bits)); /* send the TMS bits */ while (cycles_remain > 0) { nb_bits = (cycles_remain < CYCLES_ONE_BATCH) ? cycles_remain : CYCLES_ONE_BATCH; retval = jtag_vpi_tms_seq(tms_bits, nb_bits); if (retval != ERROR_OK) return retval; cycles_remain -= nb_bits; } return ERROR_OK; } static int jtag_vpi_execute_queue(void) { struct jtag_command *cmd; int retval = ERROR_OK; for (cmd = jtag_command_queue; retval == ERROR_OK && cmd; cmd = cmd->next) { switch (cmd->type) { case JTAG_RESET: retval = jtag_vpi_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: retval = jtag_vpi_runtest(cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); break; case JTAG_STABLECLOCKS: retval = jtag_vpi_stableclocks(cmd->cmd.stableclocks->num_cycles); break; case JTAG_TLR_RESET: retval = jtag_vpi_state_move(cmd->cmd.statemove->end_state); break; case JTAG_PATHMOVE: retval = jtag_vpi_path_move(cmd->cmd.pathmove); break; case JTAG_TMS: retval = jtag_vpi_tms(cmd->cmd.tms); break; case JTAG_SLEEP: jtag_sleep(cmd->cmd.sleep->us); break; case JTAG_SCAN: retval = jtag_vpi_scan(cmd->cmd.scan); break; default: LOG_ERROR("BUG: unknown JTAG command type 0x%X", cmd->type); retval = ERROR_FAIL; break; } } return retval; } static int jtag_vpi_init(void) { int flag = 1; sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { LOG_ERROR("jtag_vpi: Could not create client socket"); return ERROR_FAIL; } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(server_port); if (!server_address) server_address = strdup(DEFAULT_SERVER_ADDRESS); serv_addr.sin_addr.s_addr = inet_addr(server_address); if (serv_addr.sin_addr.s_addr == INADDR_NONE) { LOG_ERROR("jtag_vpi: inet_addr error occurred"); return ERROR_FAIL; } if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { close(sockfd); LOG_ERROR("jtag_vpi: Can't connect to %s : %u", server_address, server_port); return ERROR_COMMAND_CLOSE_CONNECTION; } if (serv_addr.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { /* This increases performance dramatically for local * connections, which is the most likely arrangement * for a VPI connection. */ setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)); } LOG_INFO("jtag_vpi: Connection to %s : %u successful", server_address, server_port); return ERROR_OK; } static int jtag_vpi_stop_simulation(void) { struct vpi_cmd cmd; memset(&cmd, 0, sizeof(struct vpi_cmd)); cmd.length = 0; cmd.nb_bits = 0; cmd.cmd = CMD_STOP_SIMU; return jtag_vpi_send_cmd(&cmd); } static int jtag_vpi_quit(void) { if (stop_sim_on_exit) { if (jtag_vpi_stop_simulation() != ERROR_OK) LOG_WARNING("jtag_vpi: failed to send \"stop simulation\" command"); } if (close_socket(sockfd) != 0) { LOG_WARNING("jtag_vpi: could not close jtag_vpi client socket"); log_socket_error("jtag_vpi"); } free(server_address); return ERROR_OK; } COMMAND_HANDLER(jtag_vpi_set_port) { if (CMD_ARGC == 0) { LOG_ERROR("Command \"jtag_vpi set_port\" expects 1 argument (TCP port number)"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], server_port); LOG_INFO("jtag_vpi: server port set to %u", server_port); return ERROR_OK; } COMMAND_HANDLER(jtag_vpi_set_address) { if (CMD_ARGC == 0) { LOG_ERROR("Command \"jtag_vpi set_address\" expects 1 argument (IP address)"); return ERROR_COMMAND_SYNTAX_ERROR; } free(server_address); server_address = strdup(CMD_ARGV[0]); LOG_INFO("jtag_vpi: server address set to %s", server_address); return ERROR_OK; } COMMAND_HANDLER(jtag_vpi_stop_sim_on_exit_handler) { if (CMD_ARGC != 1) { LOG_ERROR("Command \"jtag_vpi stop_sim_on_exit\" expects 1 argument (on|off)"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_ON_OFF(CMD_ARGV[0], stop_sim_on_exit); return ERROR_OK; } static const struct command_registration jtag_vpi_subcommand_handlers[] = { { .name = "set_port", .handler = &jtag_vpi_set_port, .mode = COMMAND_CONFIG, .help = "set the TCP port number of the jtag_vpi server (default: 5555)", .usage = "tcp_port_num", }, { .name = "set_address", .handler = &jtag_vpi_set_address, .mode = COMMAND_CONFIG, .help = "set the IP address of the jtag_vpi server (default: 127.0.0.1)", .usage = "ipv4_addr", }, { .name = "stop_sim_on_exit", .handler = &jtag_vpi_stop_sim_on_exit_handler, .mode = COMMAND_CONFIG, .help = "Configure if simulation stop command shall be sent " "before OpenOCD exits (default: off)", .usage = "<on|off>", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration jtag_vpi_command_handlers[] = { { .name = "jtag_vpi", .mode = COMMAND_ANY, .help = "perform jtag_vpi management", .chain = jtag_vpi_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static struct jtag_interface jtag_vpi_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = jtag_vpi_execute_queue, }; struct adapter_driver jtag_vpi_adapter_driver = { .name = "jtag_vpi", .transports = jtag_only, .commands = jtag_vpi_command_handlers, .init = jtag_vpi_init, .quit = jtag_vpi_quit, .jtag_ops = &jtag_vpi_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/kitprog.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Juergen Stuber <juergen@jstuber.net> * * based on Dominic Rath's and Benedikt Sauter's usbprog.c * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Jean-Christophe PLAGNIOL-VIILARD * * plagnioj@jcrosoft.com * * * * Copyright (C) 2015 by Marc Schink * * openocd-dev@marcschink.de * * * * Copyright (C) 2015 by Paul Fertser * * fercerpav@gmail.com * * * * Copyright (C) 2015-2017 by Forest Crossman * * cyrozap@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdint.h> #include <hidapi.h> #include <jtag/interface.h> #include <jtag/swd.h> #include <jtag/commands.h> #include "libusb_helper.h" #define VID 0x04b4 #define PID 0xf139 #define BULK_EP_IN 1 #define BULK_EP_OUT 2 #define CONTROL_TYPE_READ 0x01 #define CONTROL_TYPE_WRITE 0x02 #define CONTROL_COMMAND_PROGRAM 0x07 #define CONTROL_MODE_POLL_PROGRAMMER_STATUS 0x01 #define CONTROL_MODE_RESET_TARGET 0x04 #define CONTROL_MODE_SET_PROGRAMMER_PROTOCOL 0x40 #define CONTROL_MODE_SYNCHRONIZE_TRANSFER 0x41 #define CONTROL_MODE_ACQUIRE_SWD_TARGET 0x42 #define CONTROL_MODE_SEND_SWD_SEQUENCE 0x43 #define PROTOCOL_JTAG 0x00 #define PROTOCOL_SWD 0x01 #define DEVICE_PSOC4 0x00 #define DEVICE_PSOC3 0x01 #define DEVICE_UNKNOWN 0x02 #define DEVICE_PSOC5 0x03 #define ACQUIRE_MODE_RESET 0x00 #define ACQUIRE_MODE_POWER_CYCLE 0x01 #define SEQUENCE_LINE_RESET 0x00 #define SEQUENCE_JTAG_TO_SWD 0x01 #define PROGRAMMER_NOK_NACK 0x00 #define PROGRAMMER_OK_ACK 0x01 #define HID_TYPE_WRITE 0x00 #define HID_TYPE_READ 0x01 #define HID_TYPE_START 0x02 #define HID_COMMAND_POWER 0x80 #define HID_COMMAND_VERSION 0x81 #define HID_COMMAND_RESET 0x82 #define HID_COMMAND_CONFIGURE 0x8f #define HID_COMMAND_BOOTLOADER 0xa0 /* 512 bytes seemed to work reliably. * It works with both full queue of mostly reads or mostly writes. * * Unfortunately the commit 88f429ead019fd6df96ec15f0d897385f3cef0d0 * 5321: target/cortex_m: faster reading of all CPU registers * revealed a serious Kitprog firmware problem: * If the queue contains more than 63 transactions in the repeated pattern * one write, two reads, the firmware fails badly. * Sending 64 transactions makes the adapter to loose the connection with the * device. Sending 65 or more transactions causes the adapter to stop * receiving USB HID commands, next kitprog_hid_command() stops in hid_write(). * * The problem was detected with KitProg v2.12 and v2.16. * We can guess the problem is something like a buffer or stack overflow. * * Use shorter buffer as a workaround. 300 bytes (= 60 transactions) works. */ #define SWD_MAX_BUFFER_LENGTH 300 struct kitprog { hid_device *hid_handle; struct libusb_device_handle *usb_handle; uint16_t packet_size; uint16_t packet_index; uint8_t *packet_buffer; char *serial; uint8_t hardware_version; uint8_t minor_version; uint8_t major_version; uint16_t millivolts; bool supports_jtag_to_swd; }; struct pending_transfer_result { uint8_t cmd; uint32_t data; void *buffer; }; static bool kitprog_init_acquire_psoc; static int pending_transfer_count, pending_queue_len; static struct pending_transfer_result *pending_transfers; static int queued_retval; static struct kitprog *kitprog_handle; static int kitprog_usb_open(void); static void kitprog_usb_close(void); static int kitprog_hid_command(uint8_t *command, size_t command_length, uint8_t *data, size_t data_length); static int kitprog_get_version(void); static int kitprog_get_millivolts(void); static int kitprog_get_info(void); static int kitprog_set_protocol(uint8_t protocol); static int kitprog_get_status(void); static int kitprog_set_unknown(void); static int kitprog_acquire_psoc(uint8_t psoc_type, uint8_t acquire_mode, uint8_t max_attempts); static int kitprog_reset_target(void); static int kitprog_swd_sync(void); static int kitprog_swd_seq(uint8_t seq_type); static int kitprog_generic_acquire(void); static int kitprog_swd_run_queue(void); static void kitprog_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data); static int kitprog_swd_switch_seq(enum swd_special_seq seq); static inline int mm_to_version(uint8_t major, uint8_t minor) { return (major << 8) | minor; } static int kitprog_init(void) { int retval; kitprog_handle = malloc(sizeof(struct kitprog)); if (!kitprog_handle) { LOG_ERROR("Failed to allocate memory"); return ERROR_FAIL; } if (kitprog_usb_open() != ERROR_OK) { LOG_ERROR("Can't find a KitProg device! Please check device connections and permissions."); return ERROR_JTAG_INIT_FAILED; } /* Get the current KitProg version and target voltage */ if (kitprog_get_info() != ERROR_OK) return ERROR_FAIL; /* Compatibility check */ kitprog_handle->supports_jtag_to_swd = true; int kitprog_version = mm_to_version(kitprog_handle->major_version, kitprog_handle->minor_version); if (kitprog_version < mm_to_version(2, 14)) { LOG_WARNING("KitProg firmware versions below v2.14 do not support sending JTAG to SWD sequences. These sequences will be substituted with SWD line resets."); kitprog_handle->supports_jtag_to_swd = false; } /* I have no idea what this does */ if (kitprog_set_unknown() != ERROR_OK) return ERROR_FAIL; /* SWD won't work unless we do this */ if (kitprog_swd_sync() != ERROR_OK) return ERROR_FAIL; /* Set the protocol to SWD */ if (kitprog_set_protocol(PROTOCOL_SWD) != ERROR_OK) return ERROR_FAIL; /* Reset the SWD bus */ if (kitprog_swd_seq(SEQUENCE_LINE_RESET) != ERROR_OK) return ERROR_FAIL; if (kitprog_init_acquire_psoc) { /* Try to acquire any device that will respond */ retval = kitprog_generic_acquire(); if (retval != ERROR_OK) { LOG_ERROR("No PSoC devices found"); return retval; } } /* Allocate packet buffers and queues */ kitprog_handle->packet_size = SWD_MAX_BUFFER_LENGTH; kitprog_handle->packet_buffer = malloc(SWD_MAX_BUFFER_LENGTH); if (!kitprog_handle->packet_buffer) { LOG_ERROR("Failed to allocate memory for the packet buffer"); return ERROR_FAIL; } pending_queue_len = SWD_MAX_BUFFER_LENGTH / 5; pending_transfers = malloc(pending_queue_len * sizeof(*pending_transfers)); if (!pending_transfers) { LOG_ERROR("Failed to allocate memory for the SWD transfer queue"); return ERROR_FAIL; } return ERROR_OK; } static int kitprog_quit(void) { kitprog_usb_close(); free(kitprog_handle->packet_buffer); free(kitprog_handle->serial); free(kitprog_handle); free(pending_transfers); return ERROR_OK; } /*************** kitprog usb functions *********************/ static int kitprog_get_usb_serial(void) { int retval; const uint8_t str_index = 128; /* This seems to be a constant */ char desc_string[256+1]; /* Max size of string descriptor */ retval = libusb_get_string_descriptor_ascii(kitprog_handle->usb_handle, str_index, (unsigned char *)desc_string, sizeof(desc_string)-1); if (retval < 0) { LOG_ERROR("libusb_get_string_descriptor_ascii() failed with %d", retval); return ERROR_FAIL; } /* Null terminate descriptor string */ desc_string[retval] = '\0'; /* Allocate memory for the serial number */ kitprog_handle->serial = calloc(retval + 1, sizeof(char)); if (!kitprog_handle->serial) { LOG_ERROR("Failed to allocate memory for the serial number"); return ERROR_FAIL; } /* Store the serial number */ strncpy(kitprog_handle->serial, desc_string, retval + 1); return ERROR_OK; } static int kitprog_usb_open(void) { const uint16_t vids[] = { VID, 0 }; const uint16_t pids[] = { PID, 0 }; if (jtag_libusb_open(vids, pids, &kitprog_handle->usb_handle, NULL) != ERROR_OK) { LOG_ERROR("Failed to open or find the device"); return ERROR_FAIL; } /* Get the serial number for the device */ if (kitprog_get_usb_serial() != ERROR_OK) LOG_WARNING("Failed to get KitProg serial number"); /* Convert the ASCII serial number into a (wchar_t *) */ size_t len = strlen(kitprog_handle->serial); wchar_t *hid_serial = calloc(len + 1, sizeof(wchar_t)); if (!hid_serial) { LOG_ERROR("Failed to allocate memory for the serial number"); return ERROR_FAIL; } if (mbstowcs(hid_serial, kitprog_handle->serial, len + 1) == (size_t)-1) { free(hid_serial); LOG_ERROR("Failed to convert serial number"); return ERROR_FAIL; } /* Use HID for the KitBridge interface */ kitprog_handle->hid_handle = hid_open(VID, PID, hid_serial); free(hid_serial); if (!kitprog_handle->hid_handle) { LOG_ERROR("Failed to open KitBridge (HID) interface"); return ERROR_FAIL; } /* Claim the KitProg Programmer (bulk transfer) interface */ if (libusb_claim_interface(kitprog_handle->usb_handle, 1) != ERROR_OK) { LOG_ERROR("Failed to claim KitProg Programmer (bulk transfer) interface"); return ERROR_FAIL; } return ERROR_OK; } static void kitprog_usb_close(void) { if (kitprog_handle->hid_handle) { hid_close(kitprog_handle->hid_handle); hid_exit(); } jtag_libusb_close(kitprog_handle->usb_handle); } /*************** kitprog lowlevel functions *********************/ static int kitprog_hid_command(uint8_t *command, size_t command_length, uint8_t *data, size_t data_length) { int ret; ret = hid_write(kitprog_handle->hid_handle, command, command_length); if (ret < 0) { LOG_DEBUG("HID write returned %i", ret); return ERROR_FAIL; } ret = hid_read_timeout(kitprog_handle->hid_handle, data, data_length, LIBUSB_TIMEOUT_MS); if (ret == 0) { LOG_ERROR("HID read timed out"); return ERROR_TIMEOUT_REACHED; } else if (ret < 0) { LOG_ERROR("HID read error %ls", hid_error(kitprog_handle->hid_handle)); return ERROR_FAIL; } return ERROR_OK; } static int kitprog_get_version(void) { int ret; unsigned char command[3] = {HID_TYPE_START | HID_TYPE_WRITE, 0x00, HID_COMMAND_VERSION}; unsigned char data[64]; ret = kitprog_hid_command(command, sizeof(command), data, sizeof(data)); if (ret != ERROR_OK) return ret; kitprog_handle->hardware_version = data[1]; kitprog_handle->minor_version = data[2]; kitprog_handle->major_version = data[3]; return ERROR_OK; } static int kitprog_get_millivolts(void) { int ret; unsigned char command[3] = {HID_TYPE_START | HID_TYPE_READ, 0x00, HID_COMMAND_POWER}; unsigned char data[64]; ret = kitprog_hid_command(command, sizeof(command), data, sizeof(data)); if (ret != ERROR_OK) return ret; kitprog_handle->millivolts = (data[4] << 8) | data[3]; return ERROR_OK; } static int kitprog_get_info(void) { /* Get the device version information */ if (kitprog_get_version() == ERROR_OK) { LOG_INFO("KitProg v%u.%02u", kitprog_handle->major_version, kitprog_handle->minor_version); LOG_INFO("Hardware version: %u", kitprog_handle->hardware_version); } else { LOG_ERROR("Failed to get KitProg version"); return ERROR_FAIL; } /* Get the current reported target voltage */ if (kitprog_get_millivolts() == ERROR_OK) { LOG_INFO("VTARG = %u.%03u V", kitprog_handle->millivolts / 1000, kitprog_handle->millivolts % 1000); } else { LOG_ERROR("Failed to get target voltage"); return ERROR_FAIL; } return ERROR_OK; } static int kitprog_set_protocol(uint8_t protocol) { int transferred; char status = PROGRAMMER_NOK_NACK; transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_SET_PROGRAMMER_PROTOCOL << 8) | CONTROL_COMMAND_PROGRAM, protocol, &status, 1, 0); if (transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } if (status != PROGRAMMER_OK_ACK) { LOG_DEBUG("Programmer did not respond OK"); return ERROR_FAIL; } return ERROR_OK; } static int kitprog_get_status(void) { int transferred = 0; char status = PROGRAMMER_NOK_NACK; /* Try a maximum of three times */ for (int i = 0; (i < 3) && (transferred == 0); i++) { transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_READ, (CONTROL_MODE_POLL_PROGRAMMER_STATUS << 8) | CONTROL_COMMAND_PROGRAM, 0, &status, 1, 0); jtag_sleep(1000); } if (transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } if (status != PROGRAMMER_OK_ACK) { LOG_DEBUG("Programmer did not respond OK"); return ERROR_FAIL; } return ERROR_OK; } static int kitprog_set_unknown(void) { int transferred; char status = PROGRAMMER_NOK_NACK; transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (0x03 << 8) | 0x04, 0, &status, 1, 0); if (transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } if (status != PROGRAMMER_OK_ACK) { LOG_DEBUG("Programmer did not respond OK"); return ERROR_FAIL; } return ERROR_OK; } static int kitprog_acquire_psoc(uint8_t psoc_type, uint8_t acquire_mode, uint8_t max_attempts) { int transferred; char status = PROGRAMMER_NOK_NACK; transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_ACQUIRE_SWD_TARGET << 8) | CONTROL_COMMAND_PROGRAM, (max_attempts << 8) | (acquire_mode << 4) | psoc_type, &status, 1, 0); if (transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } if (status != PROGRAMMER_OK_ACK) { LOG_DEBUG("Programmer did not respond OK"); return ERROR_FAIL; } return ERROR_OK; } static int kitprog_reset_target(void) { int transferred; char status = PROGRAMMER_NOK_NACK; transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_RESET_TARGET << 8) | CONTROL_COMMAND_PROGRAM, 0, &status, 1, 0); if (transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } if (status != PROGRAMMER_OK_ACK) { LOG_DEBUG("Programmer did not respond OK"); return ERROR_FAIL; } return ERROR_OK; } static int kitprog_swd_sync(void) { int transferred; char status = PROGRAMMER_NOK_NACK; transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_SYNCHRONIZE_TRANSFER << 8) | CONTROL_COMMAND_PROGRAM, 0, &status, 1, 0); if (transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } if (status != PROGRAMMER_OK_ACK) { LOG_DEBUG("Programmer did not respond OK"); return ERROR_FAIL; } return ERROR_OK; } static int kitprog_swd_seq(uint8_t seq_type) { int transferred; char status = PROGRAMMER_NOK_NACK; transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_SEND_SWD_SEQUENCE << 8) | CONTROL_COMMAND_PROGRAM, seq_type, &status, 1, 0); if (transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } if (status != PROGRAMMER_OK_ACK) { LOG_DEBUG("Programmer did not respond OK"); return ERROR_FAIL; } return ERROR_OK; } static int kitprog_generic_acquire(void) { const uint8_t devices[] = {DEVICE_PSOC4, DEVICE_PSOC3, DEVICE_PSOC5}; int retval; int acquire_count = 0; /* Due to the way the SWD port is shared between the Test Controller (TC) * and the Cortex-M3 DAP on the PSoC 5LP, the TC is the default SWD target * after power is applied. To access the DAP, the PSoC 5LP requires at least * one acquisition sequence to be run (which switches the SWD mux from the * TC to the DAP). However, after the mux is switched, the Cortex-M3 will be * held in reset until a series of registers are written to (see section 5.2 * of the PSoC 5LP Device Programming Specifications for details). * * Instead of writing the registers in this function, we just do what the * Cypress tools do and run the acquisition sequence a second time. This * will take the Cortex-M3 out of reset and enable debugging. */ for (int i = 0; i < 2; i++) { for (uint8_t j = 0; j < sizeof(devices) && acquire_count == i; j++) { retval = kitprog_acquire_psoc(devices[j], ACQUIRE_MODE_RESET, 3); if (retval != ERROR_OK) { LOG_DEBUG("Acquisition function failed for device 0x%02x.", devices[j]); return retval; } if (kitprog_get_status() == ERROR_OK) acquire_count++; } jtag_sleep(10); } if (acquire_count < 2) return ERROR_FAIL; return ERROR_OK; } /*************** swd wrapper functions *********************/ static int kitprog_swd_init(void) { return ERROR_OK; } static void kitprog_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { assert(!(cmd & SWD_CMD_RNW)); kitprog_swd_queue_cmd(cmd, NULL, value); } static void kitprog_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { assert(cmd & SWD_CMD_RNW); kitprog_swd_queue_cmd(cmd, value, 0); } /*************** swd lowlevel functions ********************/ static int kitprog_swd_switch_seq(enum swd_special_seq seq) { switch (seq) { case JTAG_TO_SWD: if (kitprog_handle->supports_jtag_to_swd) { LOG_DEBUG("JTAG to SWD"); if (kitprog_swd_seq(SEQUENCE_JTAG_TO_SWD) != ERROR_OK) return ERROR_FAIL; break; } else { LOG_DEBUG("JTAG to SWD not supported"); /* Fall through to fix target reset issue */ } /* fallthrough */ case LINE_RESET: LOG_DEBUG("SWD line reset"); if (kitprog_swd_seq(SEQUENCE_LINE_RESET) != ERROR_OK) return ERROR_FAIL; break; default: LOG_ERROR("Sequence %d not supported.", seq); return ERROR_FAIL; } return ERROR_OK; } static int kitprog_swd_run_queue(void) { int ret; size_t read_count = 0; size_t read_index = 0; size_t write_count = 0; uint8_t *buffer = kitprog_handle->packet_buffer; do { LOG_DEBUG_IO("Executing %d queued transactions", pending_transfer_count); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); break; } if (!pending_transfer_count) break; for (int i = 0; i < pending_transfer_count; i++) { uint8_t cmd = pending_transfers[i].cmd; uint32_t data = pending_transfers[i].data; /* When proper WAIT handling is implemented in the * common SWD framework, this kludge can be * removed. However, this might lead to minor * performance degradation as the adapter wouldn't be * able to automatically retry anything (because ARM * has forgotten to implement sticky error flags * clearing). See also comments regarding * cmsis_dap_cmd_DAP_TFER_Configure() and * cmsis_dap_cmd_DAP_SWD_Configure() in * cmsis_dap_init(). */ if (!(cmd & SWD_CMD_RNW) && !(cmd & SWD_CMD_APNDP) && (cmd & SWD_CMD_A32) >> 1 == DP_CTRL_STAT && (data & CORUNDETECT)) { LOG_DEBUG("refusing to enable sticky overrun detection"); data &= ~CORUNDETECT; } LOG_DEBUG_IO("%s %s reg %x %"PRIx32, cmd & SWD_CMD_APNDP ? "AP" : "DP", cmd & SWD_CMD_RNW ? "read" : "write", (cmd & SWD_CMD_A32) >> 1, data); buffer[write_count++] = (cmd | SWD_CMD_START | SWD_CMD_PARK) & ~SWD_CMD_STOP; read_count++; if (!(cmd & SWD_CMD_RNW)) { buffer[write_count++] = (data) & 0xff; buffer[write_count++] = (data >> 8) & 0xff; buffer[write_count++] = (data >> 16) & 0xff; buffer[write_count++] = (data >> 24) & 0xff; } else { read_count += 4; } } if (jtag_libusb_bulk_write(kitprog_handle->usb_handle, BULK_EP_OUT, (char *)buffer, write_count, 0, &ret)) { LOG_ERROR("Bulk write failed"); queued_retval = ERROR_FAIL; break; } else { queued_retval = ERROR_OK; } /* KitProg firmware does not send a zero length packet * after the bulk-in transmission of a length divisible by bulk packet * size (64 bytes) as required by the USB specification. * Therefore libusb would wait for continuation of transmission. * Workaround: Limit bulk read size to expected number of bytes * for problematic transfer sizes. Otherwise use the maximum buffer * size here because the KitProg sometimes doesn't like bulk reads * of fewer than 62 bytes. (?!?!) */ size_t read_count_workaround = SWD_MAX_BUFFER_LENGTH; if (read_count % 64 == 0) read_count_workaround = read_count; if (jtag_libusb_bulk_read(kitprog_handle->usb_handle, BULK_EP_IN | LIBUSB_ENDPOINT_IN, (char *)buffer, read_count_workaround, 1000, &ret)) { LOG_ERROR("Bulk read failed"); queued_retval = ERROR_FAIL; break; } else { /* Handle garbage data by offsetting the initial read index */ if ((unsigned int)ret > read_count) read_index = ret - read_count; queued_retval = ERROR_OK; } for (int i = 0; i < pending_transfer_count; i++) { if (pending_transfers[i].cmd & SWD_CMD_RNW) { uint32_t data = le_to_h_u32(&buffer[read_index]); LOG_DEBUG_IO("Read result: %"PRIx32, data); if (pending_transfers[i].buffer) *(uint32_t *)pending_transfers[i].buffer = data; read_index += 4; } uint8_t ack = buffer[read_index] & 0x07; if (ack != SWD_ACK_OK || (buffer[read_index] & 0x08)) { LOG_DEBUG("SWD ack not OK: %d %s", i, ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK"); queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL; break; } read_index++; } } while (0); pending_transfer_count = 0; int retval = queued_retval; queued_retval = ERROR_OK; return retval; } static void kitprog_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) { if (pending_transfer_count == pending_queue_len) { /* Not enough room in the queue. Run the queue. */ queued_retval = kitprog_swd_run_queue(); } if (queued_retval != ERROR_OK) return; pending_transfers[pending_transfer_count].data = data; pending_transfers[pending_transfer_count].cmd = cmd; if (cmd & SWD_CMD_RNW) { /* Queue a read transaction */ pending_transfers[pending_transfer_count].buffer = dst; } pending_transfer_count++; } /*************** jtag lowlevel functions ********************/ static int kitprog_reset(int trst, int srst) { int retval = ERROR_OK; if (trst == 1) { LOG_ERROR("KitProg: Interface has no TRST"); return ERROR_FAIL; } if (srst == 1) { retval = kitprog_reset_target(); /* Since the previous command also disables SWCLK output, we need to send an * SWD bus reset command to re-enable it. For some reason, running * kitprog_swd_seq() immediately after kitprog_reset_target() won't * actually fix this. Instead, kitprog_swd_seq() will be run once OpenOCD * tries to send a JTAG-to-SWD sequence, which should happen during * swd_check_reconnect (see the JTAG_TO_SWD case in kitprog_swd_switch_seq). */ } if (retval != ERROR_OK) LOG_ERROR("KitProg: Interface reset failed"); return retval; } COMMAND_HANDLER(kitprog_handle_info_command) { int retval = kitprog_get_info(); return retval; } COMMAND_HANDLER(kitprog_handle_acquire_psoc_command) { int retval = kitprog_generic_acquire(); return retval; } COMMAND_HANDLER(kitprog_handle_init_acquire_psoc_command) { kitprog_init_acquire_psoc = true; return ERROR_OK; } static const struct command_registration kitprog_subcommand_handlers[] = { { .name = "info", .handler = &kitprog_handle_info_command, .mode = COMMAND_EXEC, .usage = "", .help = "show KitProg info", }, { .name = "acquire_psoc", .handler = &kitprog_handle_acquire_psoc_command, .mode = COMMAND_EXEC, .usage = "", .help = "try to acquire a PSoC", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration kitprog_command_handlers[] = { { .name = "kitprog", .mode = COMMAND_ANY, .help = "perform KitProg management", .usage = "<cmd>", .chain = kitprog_subcommand_handlers, }, { .name = "kitprog_init_acquire_psoc", .handler = &kitprog_handle_init_acquire_psoc_command, .mode = COMMAND_CONFIG, .help = "try to acquire a PSoC during init", .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct swd_driver kitprog_swd = { .init = kitprog_swd_init, .switch_seq = kitprog_swd_switch_seq, .read_reg = kitprog_swd_read_reg, .write_reg = kitprog_swd_write_reg, .run = kitprog_swd_run_queue, }; static const char * const kitprog_transports[] = { "swd", NULL }; struct adapter_driver kitprog_adapter_driver = { .name = "kitprog", .transports = kitprog_transports, .commands = kitprog_command_handlers, .init = kitprog_init, .quit = kitprog_quit, .reset = kitprog_reset, .swd_ops = &kitprog_swd, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/libftdi_helper.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef OPENOCD_JTAG_DRIVERS_LIBFTDI_HELPER_H #define OPENOCD_JTAG_DRIVERS_LIBFTDI_HELPER_H #include <ftdi.h> #ifndef HAVE_LIBFTDI_TCIOFLUSH /* Backward compatibility with libftdi pre 1.5 */ static inline int ftdi_tciflush(struct ftdi_context *ftdi) { return ftdi_usb_purge_rx_buffer(ftdi); } static inline int ftdi_tcoflush(struct ftdi_context *ftdi) { return ftdi_usb_purge_tx_buffer(ftdi); } static inline int ftdi_tcioflush(struct ftdi_context *ftdi) { return ftdi_usb_purge_buffers(ftdi); } #endif #endif /* OPENOCD_JTAG_DRIVERS_LIBFTDI_HELPER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/libusb_helper.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> * * * * Copyright (C) 2011 by Mauro Gamba <maurillo71@gmail.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <string.h> #include <helper/log.h> #include <jtag/adapter.h> #include "libusb_helper.h" /* * comment from libusb: * As per the USB 3.0 specs, the current maximum limit for the depth is 7. */ #define MAX_USB_PORTS 7 static struct libusb_context *jtag_libusb_context; /**< Libusb context **/ static struct libusb_device **devs; /**< The usb device list **/ static int jtag_libusb_error(int err) { switch (err) { case LIBUSB_SUCCESS: return ERROR_OK; case LIBUSB_ERROR_TIMEOUT: return ERROR_TIMEOUT_REACHED; case LIBUSB_ERROR_IO: case LIBUSB_ERROR_INVALID_PARAM: case LIBUSB_ERROR_ACCESS: case LIBUSB_ERROR_NO_DEVICE: case LIBUSB_ERROR_NOT_FOUND: case LIBUSB_ERROR_BUSY: case LIBUSB_ERROR_OVERFLOW: case LIBUSB_ERROR_PIPE: case LIBUSB_ERROR_INTERRUPTED: case LIBUSB_ERROR_NO_MEM: case LIBUSB_ERROR_NOT_SUPPORTED: case LIBUSB_ERROR_OTHER: return ERROR_FAIL; default: return ERROR_FAIL; } } bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc, const uint16_t vids[], const uint16_t pids[]) { for (unsigned i = 0; vids[i]; i++) { if (dev_desc->idVendor == vids[i] && dev_desc->idProduct == pids[i]) { return true; } } return false; } #ifdef HAVE_LIBUSB_GET_PORT_NUMBERS static bool jtag_libusb_location_equal(struct libusb_device *device) { uint8_t port_path[MAX_USB_PORTS]; uint8_t dev_bus; int path_len; path_len = libusb_get_port_numbers(device, port_path, MAX_USB_PORTS); if (path_len == LIBUSB_ERROR_OVERFLOW) { LOG_WARNING("cannot determine path to usb device! (more than %i ports in path)\n", MAX_USB_PORTS); return false; } dev_bus = libusb_get_bus_number(device); return adapter_usb_location_equal(dev_bus, port_path, path_len); } #else /* HAVE_LIBUSB_GET_PORT_NUMBERS */ static bool jtag_libusb_location_equal(struct libusb_device *device) { return true; } #endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */ /* Returns true if the string descriptor indexed by str_index in device matches string */ static bool string_descriptor_equal(struct libusb_device_handle *device, uint8_t str_index, const char *string) { int retval; bool matched; char desc_string[256+1]; /* Max size of string descriptor */ if (str_index == 0) return false; retval = libusb_get_string_descriptor_ascii(device, str_index, (unsigned char *)desc_string, sizeof(desc_string)-1); if (retval < 0) { LOG_ERROR("libusb_get_string_descriptor_ascii() failed with %d", retval); return false; } /* Null terminate descriptor string in case it needs to be logged. */ desc_string[sizeof(desc_string)-1] = '\0'; matched = strncmp(string, desc_string, sizeof(desc_string)) == 0; if (!matched) LOG_DEBUG("Device serial number '%s' doesn't match requested serial '%s'", desc_string, string); return matched; } static bool jtag_libusb_match_serial(struct libusb_device_handle *device, struct libusb_device_descriptor *dev_desc, const char *serial, adapter_get_alternate_serial_fn adapter_get_alternate_serial) { if (string_descriptor_equal(device, dev_desc->iSerialNumber, serial)) return true; /* check the alternate serial helper */ if (!adapter_get_alternate_serial) return false; /* get the alternate serial */ char *alternate_serial = adapter_get_alternate_serial(device, dev_desc); /* check possible failures */ if (!alternate_serial) return false; /* then compare and free the alternate serial */ bool match = false; if (strcmp(serial, alternate_serial) == 0) match = true; else LOG_DEBUG("Device alternate serial number '%s' doesn't match requested serial '%s'", alternate_serial, serial); free(alternate_serial); return match; } int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], struct libusb_device_handle **out, adapter_get_alternate_serial_fn adapter_get_alternate_serial) { int cnt, idx, err_code; int retval = ERROR_FAIL; bool serial_mismatch = false; struct libusb_device_handle *libusb_handle = NULL; const char *serial = adapter_get_required_serial(); if (libusb_init(&jtag_libusb_context) < 0) return ERROR_FAIL; cnt = libusb_get_device_list(jtag_libusb_context, &devs); for (idx = 0; idx < cnt; idx++) { struct libusb_device_descriptor dev_desc; if (libusb_get_device_descriptor(devs[idx], &dev_desc) != 0) continue; if (!jtag_libusb_match_ids(&dev_desc, vids, pids)) continue; if (adapter_usb_get_location() && !jtag_libusb_location_equal(devs[idx])) continue; err_code = libusb_open(devs[idx], &libusb_handle); if (err_code) { LOG_ERROR("libusb_open() failed with %s", libusb_error_name(err_code)); continue; } /* Device must be open to use libusb_get_string_descriptor_ascii. */ if (serial && !jtag_libusb_match_serial(libusb_handle, &dev_desc, serial, adapter_get_alternate_serial)) { serial_mismatch = true; libusb_close(libusb_handle); continue; } /* Success. */ *out = libusb_handle; retval = ERROR_OK; serial_mismatch = false; break; } if (cnt >= 0) libusb_free_device_list(devs, 1); if (serial_mismatch) LOG_INFO("No device matches the serial string"); if (retval != ERROR_OK) libusb_exit(jtag_libusb_context); return retval; } void jtag_libusb_close(struct libusb_device_handle *dev) { /* Close device */ libusb_close(dev); libusb_exit(jtag_libusb_context); } int jtag_libusb_control_transfer(struct libusb_device_handle *dev, uint8_t request_type, uint8_t request, uint16_t value, uint16_t index, char *bytes, uint16_t size, unsigned int timeout) { int transferred = 0; transferred = libusb_control_transfer(dev, request_type, request, value, index, (unsigned char *)bytes, size, timeout); if (transferred < 0) transferred = 0; return transferred; } int jtag_libusb_bulk_write(struct libusb_device_handle *dev, int ep, char *bytes, int size, int timeout, int *transferred) { int ret; *transferred = 0; ret = libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size, transferred, timeout); if (ret != LIBUSB_SUCCESS) { LOG_ERROR("libusb_bulk_write error: %s", libusb_error_name(ret)); return jtag_libusb_error(ret); } return ERROR_OK; } int jtag_libusb_bulk_read(struct libusb_device_handle *dev, int ep, char *bytes, int size, int timeout, int *transferred) { int ret; *transferred = 0; ret = libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size, transferred, timeout); if (ret != LIBUSB_SUCCESS) { LOG_ERROR("libusb_bulk_read error: %s", libusb_error_name(ret)); return jtag_libusb_error(ret); } return ERROR_OK; } int jtag_libusb_set_configuration(struct libusb_device_handle *devh, int configuration) { struct libusb_device *udev = libusb_get_device(devh); int retval = -99; struct libusb_config_descriptor *config = NULL; int current_config = -1; retval = libusb_get_configuration(devh, ¤t_config); if (retval != 0) return retval; retval = libusb_get_config_descriptor(udev, configuration, &config); if (retval != 0 || !config) return retval; /* Only change the configuration if it is not already set to the same one. Otherwise this issues a lightweight reset and hangs LPC-Link2 with JLink firmware. */ if (current_config != config->bConfigurationValue) retval = libusb_set_configuration(devh, config->bConfigurationValue); libusb_free_config_descriptor(config); return retval; } int jtag_libusb_choose_interface(struct libusb_device_handle *devh, unsigned int *usb_read_ep, unsigned int *usb_write_ep, int bclass, int subclass, int protocol, int trans_type) { struct libusb_device *udev = libusb_get_device(devh); const struct libusb_interface *inter; const struct libusb_interface_descriptor *interdesc; const struct libusb_endpoint_descriptor *epdesc; struct libusb_config_descriptor *config; *usb_read_ep = *usb_write_ep = 0; libusb_get_config_descriptor(udev, 0, &config); for (int i = 0; i < (int)config->bNumInterfaces; i++) { inter = &config->interface[i]; interdesc = &inter->altsetting[0]; for (int k = 0; k < (int)interdesc->bNumEndpoints; k++) { if ((bclass > 0 && interdesc->bInterfaceClass != bclass) || (subclass > 0 && interdesc->bInterfaceSubClass != subclass) || (protocol > 0 && interdesc->bInterfaceProtocol != protocol)) continue; epdesc = &interdesc->endpoint[k]; if (trans_type > 0 && (epdesc->bmAttributes & 0x3) != trans_type) continue; uint8_t epnum = epdesc->bEndpointAddress; bool is_input = epnum & 0x80; LOG_DEBUG("usb ep %s %02x", is_input ? "in" : "out", epnum); if (is_input) *usb_read_ep = epnum; else *usb_write_ep = epnum; if (*usb_read_ep && *usb_write_ep) { LOG_DEBUG("Claiming interface %d", (int)interdesc->bInterfaceNumber); libusb_claim_interface(devh, (int)interdesc->bInterfaceNumber); libusb_free_config_descriptor(config); return ERROR_OK; } } } libusb_free_config_descriptor(config); return ERROR_FAIL; } int jtag_libusb_get_pid(struct libusb_device *dev, uint16_t *pid) { struct libusb_device_descriptor dev_desc; if (libusb_get_device_descriptor(dev, &dev_desc) == 0) { *pid = dev_desc.idProduct; return ERROR_OK; } return ERROR_FAIL; } int jtag_libusb_handle_events_completed(int *completed) { return libusb_handle_events_completed(jtag_libusb_context, completed); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/libusb_helper.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> * * * * Copyright (C) 2011 by Mauro Gamba <maurillo71@gmail.com> * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_LIBUSB_HELPER_H #define OPENOCD_JTAG_DRIVERS_LIBUSB_HELPER_H #include <libusb.h> /* When we debug a target that works as a USB device, halting the target causes the * USB communication with the USB host to become unresponsive. The host will try * to reconnect/reset/setup the unresponsive device during which communication * with other devices on the same USB bus can get stalled for several seconds. * If the JTAG adapter is on the same bus, we need to make sure openOCD will wait * for packets at least as long as the host USB stack. Otherwise the USB stack * might deliver a valid packet, but openOCD would ignore it due to the timeout. * The xHCI spec uses 5 sec timeouts, so let's use that in openOCD with some margin. * * Use this value in all libusb calls. HID API might have a libusb backend and * would probably be victim to the same bug, so it should use this timeout, too. */ #define LIBUSB_TIMEOUT_MS (6000) /* this callback should return a non NULL value only when the serial could not * be retrieved by the standard 'libusb_get_string_descriptor_ascii' */ typedef char * (*adapter_get_alternate_serial_fn)(struct libusb_device_handle *device, struct libusb_device_descriptor *dev_desc); bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc, const uint16_t vids[], const uint16_t pids[]); int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], struct libusb_device_handle **out, adapter_get_alternate_serial_fn adapter_get_alternate_serial); void jtag_libusb_close(struct libusb_device_handle *dev); int jtag_libusb_control_transfer(struct libusb_device_handle *dev, uint8_t request_type, uint8_t request, uint16_t value, uint16_t index, char *bytes, uint16_t size, unsigned int timeout); int jtag_libusb_bulk_write(struct libusb_device_handle *dev, int ep, char *bytes, int size, int timeout, int *transferred); int jtag_libusb_bulk_read(struct libusb_device_handle *dev, int ep, char *bytes, int size, int timeout, int *transferred); int jtag_libusb_set_configuration(struct libusb_device_handle *devh, int configuration); /** * Find the first interface optionally matching class, subclass and * protocol and claim it. * @param devh _libusb_ device handle. * @param usb_read_ep A pointer to a variable where the _IN_ endpoint * number will be stored. * @param usb_write_ep A pointer to a variable where the _OUT_ endpoint * number will be stored. * @param bclass `bInterfaceClass` to match, or -1 to ignore this field. * @param subclass `bInterfaceSubClass` to match, or -1 to ignore this field. * @param protocol `bInterfaceProtocol` to match, or -1 to ignore this field. * @param trans_type `bmAttributes Bits 0..1 Transfer type` to match, or -1 to ignore this field. * @returns Returns ERROR_OK on success, ERROR_FAIL otherwise. */ int jtag_libusb_choose_interface(struct libusb_device_handle *devh, unsigned int *usb_read_ep, unsigned int *usb_write_ep, int bclass, int subclass, int protocol, int trans_type); int jtag_libusb_get_pid(struct libusb_device *dev, uint16_t *pid); int jtag_libusb_handle_events_completed(int *completed); #endif /* OPENOCD_JTAG_DRIVERS_LIBUSB_HELPER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/linuxgpiod.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Bitbang driver for Linux GPIO descriptors through libgpiod * Copyright (C) 2020 Antonio Borneo <borneo.antonio@gmail.com> * * Largely based on sysfsgpio driver * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au * Copyright (C) 2014 by Jean-Christian de Rivaz <jc@eclis.ch> * Copyright (C) 2014 by Paul Fertser <fercerpav@gmail.com> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <gpiod.h> #include <jtag/adapter.h> #include <jtag/interface.h> #include <transport/transport.h> #include "bitbang.h" static struct gpiod_chip *gpiod_chip[ADAPTER_GPIO_IDX_NUM] = {}; static struct gpiod_line *gpiod_line[ADAPTER_GPIO_IDX_NUM] = {}; static int last_swclk; static int last_swdio; static bool last_stored; static bool swdio_input; static const struct adapter_gpio_config *adapter_gpio_config; /* * Helper function to determine if gpio config is valid * * Assume here that there will be less than 10000 gpios per gpiochip, and less * than 1000 gpiochips. */ static bool is_gpio_config_valid(enum adapter_gpio_config_index idx) { return adapter_gpio_config[idx].chip_num >= 0 && adapter_gpio_config[idx].chip_num < 1000 && adapter_gpio_config[idx].gpio_num >= 0 && adapter_gpio_config[idx].gpio_num < 10000; } /* Bitbang interface read of TDO */ static bb_value_t linuxgpiod_read(void) { int retval; retval = gpiod_line_get_value(gpiod_line[ADAPTER_GPIO_IDX_TDO]); if (retval < 0) { LOG_WARNING("reading tdo failed"); return 0; } return retval ? BB_HIGH : BB_LOW; } /* * Bitbang interface write of TCK, TMS, TDI * * Seeing as this is the only function where the outputs are changed, * we can cache the old value to avoid needlessly writing it. */ static int linuxgpiod_write(int tck, int tms, int tdi) { static int last_tck; static int last_tms; static int last_tdi; static int first_time; int retval; if (!first_time) { last_tck = !tck; last_tms = !tms; last_tdi = !tdi; first_time = 1; } if (tdi != last_tdi) { retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TDI], tdi); if (retval < 0) LOG_WARNING("writing tdi failed"); } if (tms != last_tms) { retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TMS], tms); if (retval < 0) LOG_WARNING("writing tms failed"); } /* write clk last */ if (tck != last_tck) { retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TCK], tck); if (retval < 0) LOG_WARNING("writing tck failed"); } last_tdi = tdi; last_tms = tms; last_tck = tck; return ERROR_OK; } static int linuxgpiod_swdio_read(void) { int retval; retval = gpiod_line_get_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO]); if (retval < 0) { LOG_WARNING("Fail read swdio"); return 0; } return retval; } static void linuxgpiod_swdio_drive(bool is_output) { int retval; /* * FIXME: change direction requires release and re-require the line * https://stackoverflow.com/questions/58735140/ * this would change in future libgpiod */ gpiod_line_release(gpiod_line[ADAPTER_GPIO_IDX_SWDIO]); if (is_output) { if (gpiod_line[ADAPTER_GPIO_IDX_SWDIO_DIR]) { retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO_DIR], 1); if (retval < 0) LOG_WARNING("Fail set swdio_dir"); } retval = gpiod_line_request_output(gpiod_line[ADAPTER_GPIO_IDX_SWDIO], "OpenOCD", 1); if (retval < 0) LOG_WARNING("Fail request_output line swdio"); } else { retval = gpiod_line_request_input(gpiod_line[ADAPTER_GPIO_IDX_SWDIO], "OpenOCD"); if (retval < 0) LOG_WARNING("Fail request_input line swdio"); if (gpiod_line[ADAPTER_GPIO_IDX_SWDIO_DIR]) { retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO_DIR], 0); if (retval < 0) LOG_WARNING("Fail set swdio_dir"); } } last_stored = false; swdio_input = !is_output; } static int linuxgpiod_swd_write(int swclk, int swdio) { int retval; if (!swdio_input) { if (!last_stored || (swdio != last_swdio)) { retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO], swdio); if (retval < 0) LOG_WARNING("Fail set swdio"); } } /* write swclk last */ if (!last_stored || (swclk != last_swclk)) { retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWCLK], swclk); if (retval < 0) LOG_WARNING("Fail set swclk"); } last_swdio = swdio; last_swclk = swclk; last_stored = true; return ERROR_OK; } static int linuxgpiod_blink(int on) { int retval; if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_LED)) return ERROR_OK; retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_LED], on); if (retval < 0) LOG_WARNING("Fail set led"); return retval; } static struct bitbang_interface linuxgpiod_bitbang = { .read = linuxgpiod_read, .write = linuxgpiod_write, .swdio_read = linuxgpiod_swdio_read, .swdio_drive = linuxgpiod_swdio_drive, .swd_write = linuxgpiod_swd_write, .blink = linuxgpiod_blink, }; /* * Bitbang interface to manipulate reset lines SRST and TRST * * (1) assert or (0) deassert reset lines */ static int linuxgpiod_reset(int trst, int srst) { int retval1 = 0, retval2 = 0; LOG_DEBUG("linuxgpiod_reset"); /* * active low behaviour handled by "adaptor gpio" command and * GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW flag when requesting the line. */ if (gpiod_line[ADAPTER_GPIO_IDX_SRST]) { retval1 = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SRST], srst); if (retval1 < 0) LOG_WARNING("set srst value failed"); } if (gpiod_line[ADAPTER_GPIO_IDX_TRST]) { retval2 = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TRST], trst); if (retval2 < 0) LOG_WARNING("set trst value failed"); } return ((retval1 < 0) || (retval2 < 0)) ? ERROR_FAIL : ERROR_OK; } static bool linuxgpiod_jtag_mode_possible(void) { if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TCK)) return false; if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TMS)) return false; if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TDI)) return false; if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TDO)) return false; return true; } static bool linuxgpiod_swd_mode_possible(void) { if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_SWCLK)) return false; if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO)) return false; return true; } static inline void helper_release(enum adapter_gpio_config_index idx) { if (gpiod_line[idx]) { gpiod_line_release(gpiod_line[idx]); gpiod_line[idx] = NULL; } if (gpiod_chip[idx]) { gpiod_chip_close(gpiod_chip[idx]); gpiod_chip[idx] = NULL; } } static int linuxgpiod_quit(void) { LOG_DEBUG("linuxgpiod_quit"); for (int i = 0; i < ADAPTER_GPIO_IDX_NUM; ++i) helper_release(i); return ERROR_OK; } static int helper_get_line(enum adapter_gpio_config_index idx) { if (!is_gpio_config_valid(idx)) return ERROR_OK; int dir = GPIOD_LINE_REQUEST_DIRECTION_INPUT, flags = 0, val = 0, retval; gpiod_chip[idx] = gpiod_chip_open_by_number(adapter_gpio_config[idx].chip_num); if (!gpiod_chip[idx]) { LOG_ERROR("Cannot open LinuxGPIOD chip %d for %s", adapter_gpio_config[idx].chip_num, adapter_gpio_get_name(idx)); return ERROR_JTAG_INIT_FAILED; } gpiod_line[idx] = gpiod_chip_get_line(gpiod_chip[idx], adapter_gpio_config[idx].gpio_num); if (!gpiod_line[idx]) { LOG_ERROR("Error get line %s", adapter_gpio_get_name(idx)); return ERROR_JTAG_INIT_FAILED; } switch (adapter_gpio_config[idx].init_state) { case ADAPTER_GPIO_INIT_STATE_INPUT: dir = GPIOD_LINE_REQUEST_DIRECTION_INPUT; break; case ADAPTER_GPIO_INIT_STATE_INACTIVE: dir = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; val = 0; break; case ADAPTER_GPIO_INIT_STATE_ACTIVE: dir = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; val = 1; break; } switch (adapter_gpio_config[idx].drive) { case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL: break; case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN: flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN; break; case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE: flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE; break; } switch (adapter_gpio_config[idx].pull) { case ADAPTER_GPIO_PULL_NONE: #ifdef GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE; #endif break; case ADAPTER_GPIO_PULL_UP: #ifdef GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP; #else LOG_WARNING("linuxgpiod: ignoring request for pull-up on %s: not supported by gpiod v%s", adapter_gpio_get_name(idx), gpiod_version_string()); #endif break; case ADAPTER_GPIO_PULL_DOWN: #ifdef GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN; #else LOG_WARNING("linuxgpiod: ignoring request for pull-down on %s: not supported by gpiod v%s", adapter_gpio_get_name(idx), gpiod_version_string()); #endif break; } if (adapter_gpio_config[idx].active_low) flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; struct gpiod_line_request_config config = { .consumer = "OpenOCD", .request_type = dir, .flags = flags, }; retval = gpiod_line_request(gpiod_line[idx], &config, val); if (retval < 0) { LOG_ERROR("Error requesting gpio line %s", adapter_gpio_get_name(idx)); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int linuxgpiod_init(void) { LOG_INFO("Linux GPIOD JTAG/SWD bitbang driver"); bitbang_interface = &linuxgpiod_bitbang; adapter_gpio_config = adapter_gpio_get_config(); /* * Configure JTAG/SWD signals. Default directions and initial states are handled * by adapter.c and "adapter gpio" command. */ if (transport_is_jtag()) { if (!linuxgpiod_jtag_mode_possible()) { LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode"); goto out_error; } if (helper_get_line(ADAPTER_GPIO_IDX_TDO) != ERROR_OK || helper_get_line(ADAPTER_GPIO_IDX_TDI) != ERROR_OK || helper_get_line(ADAPTER_GPIO_IDX_TCK) != ERROR_OK || helper_get_line(ADAPTER_GPIO_IDX_TMS) != ERROR_OK || helper_get_line(ADAPTER_GPIO_IDX_TRST) != ERROR_OK) goto out_error; } if (transport_is_swd()) { int retval1, retval2; if (!linuxgpiod_swd_mode_possible()) { LOG_ERROR("Require swclk and swdio gpio for SWD mode"); goto out_error; } /* * swdio and its buffer should be initialized in the order that prevents * two outputs from being connected together. This will occur if the * swdio GPIO is configured as an output while the external buffer is * configured to send the swdio signal from the target to the GPIO. */ if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].init_state == ADAPTER_GPIO_INIT_STATE_INPUT) { retval1 = helper_get_line(ADAPTER_GPIO_IDX_SWDIO); retval2 = helper_get_line(ADAPTER_GPIO_IDX_SWDIO_DIR); } else { retval1 = helper_get_line(ADAPTER_GPIO_IDX_SWDIO_DIR); retval2 = helper_get_line(ADAPTER_GPIO_IDX_SWDIO); } if (retval1 != ERROR_OK || retval2 != ERROR_OK) goto out_error; if (helper_get_line(ADAPTER_GPIO_IDX_SWCLK) != ERROR_OK) goto out_error; } if (helper_get_line(ADAPTER_GPIO_IDX_SRST) != ERROR_OK || helper_get_line(ADAPTER_GPIO_IDX_LED) != ERROR_OK) goto out_error; return ERROR_OK; out_error: linuxgpiod_quit(); return ERROR_JTAG_INIT_FAILED; } static const char *const linuxgpiod_transport[] = { "swd", "jtag", NULL }; static struct jtag_interface linuxgpiod_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, }; struct adapter_driver linuxgpiod_adapter_driver = { .name = "linuxgpiod", .transports = linuxgpiod_transport, .init = linuxgpiod_init, .quit = linuxgpiod_quit, .reset = linuxgpiod_reset, .jtag_ops = &linuxgpiod_interface, .swd_ops = &bitbang_swd, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/minidriver_imp.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007-2009 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_MINIDRIVER_IMP_H #define OPENOCD_JTAG_DRIVERS_MINIDRIVER_IMP_H #include <jtag/commands.h> static inline void interface_jtag_add_scan_check_alloc(struct scan_field *field) { unsigned num_bytes = DIV_ROUND_UP(field->num_bits, 8); field->in_value = cmd_queue_alloc(num_bytes); } void interface_jtag_add_callback(jtag_callback1_t f, jtag_callback_data_t data0); void interface_jtag_add_callback4(jtag_callback_t f, jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3); void jtag_add_callback4(jtag_callback_t f, jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3); #endif /* OPENOCD_JTAG_DRIVERS_MINIDRIVER_IMP_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/mpsse.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /************************************************************************** * Copyright (C) 2012 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "mpsse.h" #include "helper/log.h" #include "helper/replacements.h" #include "helper/time_support.h" #include "libusb_helper.h" #include <libusb.h> /* Compatibility define for older libusb-1.0 */ #ifndef LIBUSB_CALL #define LIBUSB_CALL #endif #define DEBUG_PRINT_BUF(buf, len) \ do { \ if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { \ char buf_string[32 * 3 + 1]; \ int buf_string_pos = 0; \ for (int i = 0; i < len; i++) { \ buf_string_pos += sprintf(buf_string + buf_string_pos, " %02x", buf[i]); \ if (i % 32 == 32 - 1) { \ LOG_DEBUG_IO("%s", buf_string); \ buf_string_pos = 0; \ } \ } \ if (buf_string_pos > 0) \ LOG_DEBUG_IO("%s", buf_string);\ } \ } while (0) #define FTDI_DEVICE_OUT_REQTYPE (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE) #define FTDI_DEVICE_IN_REQTYPE (0x80 | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE) #define BITMODE_MPSSE 0x02 #define SIO_RESET_REQUEST 0x00 #define SIO_SET_LATENCY_TIMER_REQUEST 0x09 #define SIO_GET_LATENCY_TIMER_REQUEST 0x0A #define SIO_SET_BITMODE_REQUEST 0x0B #define SIO_RESET_SIO 0 #define SIO_RESET_PURGE_RX 1 #define SIO_RESET_PURGE_TX 2 struct mpsse_ctx { struct libusb_context *usb_ctx; struct libusb_device_handle *usb_dev; unsigned int usb_write_timeout; unsigned int usb_read_timeout; uint8_t in_ep; uint8_t out_ep; uint16_t max_packet_size; uint16_t index; uint8_t interface; enum ftdi_chip_type type; uint8_t *write_buffer; unsigned write_size; unsigned write_count; uint8_t *read_buffer; unsigned read_size; unsigned read_count; uint8_t *read_chunk; unsigned read_chunk_size; struct bit_copy_queue read_queue; int retval; }; /* Returns true if the string descriptor indexed by str_index in device matches string */ static bool string_descriptor_equal(struct libusb_device_handle *device, uint8_t str_index, const char *string) { int retval; char desc_string[256]; /* Max size of string descriptor */ retval = libusb_get_string_descriptor_ascii(device, str_index, (unsigned char *)desc_string, sizeof(desc_string)); if (retval < 0) { LOG_ERROR("libusb_get_string_descriptor_ascii() failed with %s", libusb_error_name(retval)); return false; } return strncmp(string, desc_string, sizeof(desc_string)) == 0; } static bool device_location_equal(struct libusb_device *device, const char *location) { bool result = false; #ifdef HAVE_LIBUSB_GET_PORT_NUMBERS char *loc = strdup(location); uint8_t port_path[7]; int path_step, path_len; uint8_t dev_bus = libusb_get_bus_number(device); char *ptr; path_len = libusb_get_port_numbers(device, port_path, 7); if (path_len == LIBUSB_ERROR_OVERFLOW) { LOG_ERROR("cannot determine path to usb device! (more than 7 ports in path)"); goto done; } LOG_DEBUG("device path has %i steps", path_len); ptr = strtok(loc, "-:"); if (!ptr) { LOG_DEBUG("no ':' in path"); goto done; } if (atoi(ptr) != dev_bus) { LOG_DEBUG("bus mismatch"); goto done; } path_step = 0; while (path_step < 7) { ptr = strtok(NULL, ".,"); if (!ptr) { LOG_DEBUG("no more tokens in path at step %i", path_step); break; } if (path_step < path_len && atoi(ptr) != port_path[path_step]) { LOG_DEBUG("path mismatch at step %i", path_step); break; } path_step++; }; /* walked the full path, all elements match */ if (path_step == path_len) result = true; done: free(loc); #endif return result; } /* Helper to open a libusb device that matches vid, pid, product string and/or serial string. * Set any field to 0 as a wildcard. If the device is found true is returned, with ctx containing * the already opened handle. ctx->interface must be set to the desired interface (channel) number * prior to calling this function. */ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t vids[], const uint16_t pids[], const char *product, const char *serial, const char *location) { struct libusb_device **list; struct libusb_device_descriptor desc; struct libusb_config_descriptor *config0; int err; bool found = false; ssize_t cnt = libusb_get_device_list(ctx->usb_ctx, &list); if (cnt < 0) LOG_ERROR("libusb_get_device_list() failed with %s", libusb_error_name(cnt)); for (ssize_t i = 0; i < cnt; i++) { struct libusb_device *device = list[i]; err = libusb_get_device_descriptor(device, &desc); if (err != LIBUSB_SUCCESS) { LOG_ERROR("libusb_get_device_descriptor() failed with %s", libusb_error_name(err)); continue; } if (!jtag_libusb_match_ids(&desc, vids, pids)) continue; err = libusb_open(device, &ctx->usb_dev); if (err != LIBUSB_SUCCESS) { LOG_ERROR("libusb_open() failed with %s", libusb_error_name(err)); continue; } if (location && !device_location_equal(device, location)) { libusb_close(ctx->usb_dev); continue; } if (product && !string_descriptor_equal(ctx->usb_dev, desc.iProduct, product)) { libusb_close(ctx->usb_dev); continue; } if (serial && !string_descriptor_equal(ctx->usb_dev, desc.iSerialNumber, serial)) { libusb_close(ctx->usb_dev); continue; } found = true; break; } libusb_free_device_list(list, 1); if (!found) { /* The caller reports detailed error desc */ return false; } err = libusb_get_config_descriptor(libusb_get_device(ctx->usb_dev), 0, &config0); if (err != LIBUSB_SUCCESS) { LOG_ERROR("libusb_get_config_descriptor() failed with %s", libusb_error_name(err)); libusb_close(ctx->usb_dev); return false; } /* Make sure the first configuration is selected */ int cfg; err = libusb_get_configuration(ctx->usb_dev, &cfg); if (err != LIBUSB_SUCCESS) { LOG_ERROR("libusb_get_configuration() failed with %s", libusb_error_name(err)); goto error; } if (desc.bNumConfigurations > 0 && cfg != config0->bConfigurationValue) { err = libusb_set_configuration(ctx->usb_dev, config0->bConfigurationValue); if (err != LIBUSB_SUCCESS) { LOG_ERROR("libusb_set_configuration() failed with %s", libusb_error_name(err)); goto error; } } /* Try to detach ftdi_sio kernel module */ err = libusb_detach_kernel_driver(ctx->usb_dev, ctx->interface); if (err != LIBUSB_SUCCESS && err != LIBUSB_ERROR_NOT_FOUND && err != LIBUSB_ERROR_NOT_SUPPORTED) { LOG_WARNING("libusb_detach_kernel_driver() failed with %s, trying to continue anyway", libusb_error_name(err)); } err = libusb_claim_interface(ctx->usb_dev, ctx->interface); if (err != LIBUSB_SUCCESS) { LOG_ERROR("libusb_claim_interface() failed with %s", libusb_error_name(err)); goto error; } /* Reset FTDI device */ err = libusb_control_transfer(ctx->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, SIO_RESET_SIO, ctx->index, NULL, 0, ctx->usb_write_timeout); if (err < 0) { LOG_ERROR("failed to reset FTDI device: %s", libusb_error_name(err)); goto error; } switch (desc.bcdDevice) { case 0x500: ctx->type = TYPE_FT2232C; break; case 0x700: ctx->type = TYPE_FT2232H; break; case 0x800: ctx->type = TYPE_FT4232H; break; case 0x900: ctx->type = TYPE_FT232H; break; default: LOG_ERROR("unsupported FTDI chip type: 0x%04x", desc.bcdDevice); goto error; } /* Determine maximum packet size and endpoint addresses */ if (!(desc.bNumConfigurations > 0 && ctx->interface < config0->bNumInterfaces && config0->interface[ctx->interface].num_altsetting > 0)) goto desc_error; const struct libusb_interface_descriptor *descriptor; descriptor = &config0->interface[ctx->interface].altsetting[0]; if (descriptor->bNumEndpoints != 2) goto desc_error; ctx->in_ep = 0; ctx->out_ep = 0; for (int i = 0; i < descriptor->bNumEndpoints; i++) { if (descriptor->endpoint[i].bEndpointAddress & 0x80) { ctx->in_ep = descriptor->endpoint[i].bEndpointAddress; ctx->max_packet_size = descriptor->endpoint[i].wMaxPacketSize; } else { ctx->out_ep = descriptor->endpoint[i].bEndpointAddress; } } if (ctx->in_ep == 0 || ctx->out_ep == 0) goto desc_error; libusb_free_config_descriptor(config0); return true; desc_error: LOG_ERROR("unrecognized USB device descriptor"); error: libusb_free_config_descriptor(config0); libusb_close(ctx->usb_dev); return false; } struct mpsse_ctx *mpsse_open(const uint16_t vids[], const uint16_t pids[], const char *description, const char *serial, const char *location, int channel) { struct mpsse_ctx *ctx = calloc(1, sizeof(*ctx)); int err; if (!ctx) return NULL; bit_copy_queue_init(&ctx->read_queue); ctx->read_chunk_size = 16384; ctx->read_size = 16384; ctx->write_size = 16384; ctx->read_chunk = malloc(ctx->read_chunk_size); ctx->read_buffer = malloc(ctx->read_size); /* Use calloc to make valgrind happy: buffer_write() sets payload * on bit basis, so some bits can be left uninitialized in write_buffer. * Although this is perfectly ok with MPSSE, valgrind reports * Syscall param ioctl(USBDEVFS_SUBMITURB).buffer points to uninitialised byte(s) */ ctx->write_buffer = calloc(1, ctx->write_size); if (!ctx->read_chunk || !ctx->read_buffer || !ctx->write_buffer) goto error; ctx->interface = channel; ctx->index = channel + 1; ctx->usb_read_timeout = 5000; ctx->usb_write_timeout = 5000; err = libusb_init(&ctx->usb_ctx); if (err != LIBUSB_SUCCESS) { LOG_ERROR("libusb_init() failed with %s", libusb_error_name(err)); goto error; } if (!open_matching_device(ctx, vids, pids, description, serial, location)) { LOG_ERROR("unable to open ftdi device with description '%s', " "serial '%s' at bus location '%s'", description ? description : "*", serial ? serial : "*", location ? location : "*"); ctx->usb_dev = NULL; goto error; } err = libusb_control_transfer(ctx->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_LATENCY_TIMER_REQUEST, 255, ctx->index, NULL, 0, ctx->usb_write_timeout); if (err < 0) { LOG_ERROR("unable to set latency timer: %s", libusb_error_name(err)); goto error; } err = libusb_control_transfer(ctx->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_BITMODE_REQUEST, 0x0b | (BITMODE_MPSSE << 8), ctx->index, NULL, 0, ctx->usb_write_timeout); if (err < 0) { LOG_ERROR("unable to set MPSSE bitmode: %s", libusb_error_name(err)); goto error; } mpsse_purge(ctx); return ctx; error: mpsse_close(ctx); return NULL; } void mpsse_close(struct mpsse_ctx *ctx) { if (ctx->usb_dev) libusb_close(ctx->usb_dev); if (ctx->usb_ctx) libusb_exit(ctx->usb_ctx); bit_copy_discard(&ctx->read_queue); free(ctx->write_buffer); free(ctx->read_buffer); free(ctx->read_chunk); free(ctx); } bool mpsse_is_high_speed(struct mpsse_ctx *ctx) { return ctx->type != TYPE_FT2232C; } void mpsse_purge(struct mpsse_ctx *ctx) { int err; LOG_DEBUG("-"); ctx->write_count = 0; ctx->read_count = 0; ctx->retval = ERROR_OK; bit_copy_discard(&ctx->read_queue); err = libusb_control_transfer(ctx->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, SIO_RESET_PURGE_RX, ctx->index, NULL, 0, ctx->usb_write_timeout); if (err < 0) { LOG_ERROR("unable to purge ftdi rx buffers: %s", libusb_error_name(err)); return; } err = libusb_control_transfer(ctx->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, SIO_RESET_PURGE_TX, ctx->index, NULL, 0, ctx->usb_write_timeout); if (err < 0) { LOG_ERROR("unable to purge ftdi tx buffers: %s", libusb_error_name(err)); return; } } static unsigned buffer_write_space(struct mpsse_ctx *ctx) { /* Reserve one byte for SEND_IMMEDIATE */ return ctx->write_size - ctx->write_count - 1; } static unsigned buffer_read_space(struct mpsse_ctx *ctx) { return ctx->read_size - ctx->read_count; } static void buffer_write_byte(struct mpsse_ctx *ctx, uint8_t data) { LOG_DEBUG_IO("%02x", data); assert(ctx->write_count < ctx->write_size); ctx->write_buffer[ctx->write_count++] = data; } static unsigned buffer_write(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, unsigned bit_count) { LOG_DEBUG_IO("%d bits", bit_count); assert(ctx->write_count + DIV_ROUND_UP(bit_count, 8) <= ctx->write_size); bit_copy(ctx->write_buffer + ctx->write_count, 0, out, out_offset, bit_count); ctx->write_count += DIV_ROUND_UP(bit_count, 8); return bit_count; } static unsigned buffer_add_read(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_offset, unsigned bit_count, unsigned offset) { LOG_DEBUG_IO("%d bits, offset %d", bit_count, offset); assert(ctx->read_count + DIV_ROUND_UP(bit_count, 8) <= ctx->read_size); bit_copy_queued(&ctx->read_queue, in, in_offset, ctx->read_buffer + ctx->read_count, offset, bit_count); ctx->read_count += DIV_ROUND_UP(bit_count, 8); return bit_count; } void mpsse_clock_data_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, unsigned length, uint8_t mode) { mpsse_clock_data(ctx, out, out_offset, NULL, 0, length, mode); } void mpsse_clock_data_in(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_offset, unsigned length, uint8_t mode) { mpsse_clock_data(ctx, NULL, 0, in, in_offset, length, mode); } void mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, unsigned in_offset, unsigned length, uint8_t mode) { /* TODO: Fix MSB first modes */ LOG_DEBUG_IO("%s%s %d bits", in ? "in" : "", out ? "out" : "", length); if (ctx->retval != ERROR_OK) { LOG_DEBUG_IO("Ignoring command due to previous error"); return; } /* TODO: On H chips, use command 0x8E/0x8F if in and out are both 0 */ if (out || (!out && !in)) mode |= 0x10; if (in) mode |= 0x20; while (length > 0) { /* Guarantee buffer space enough for a minimum size transfer */ if (buffer_write_space(ctx) + (length < 8) < (out || (!out && !in) ? 4 : 3) || (in && buffer_read_space(ctx) < 1)) ctx->retval = mpsse_flush(ctx); if (length < 8) { /* Transfer remaining bits in bit mode */ buffer_write_byte(ctx, 0x02 | mode); buffer_write_byte(ctx, length - 1); if (out) out_offset += buffer_write(ctx, out, out_offset, length); if (in) in_offset += buffer_add_read(ctx, in, in_offset, length, 8 - length); if (!out && !in) buffer_write_byte(ctx, 0x00); length = 0; } else { /* Byte transfer */ unsigned this_bytes = length / 8; /* MPSSE command limit */ if (this_bytes > 65536) this_bytes = 65536; /* Buffer space limit. We already made sure there's space for the minimum * transfer. */ if ((out || (!out && !in)) && this_bytes + 3 > buffer_write_space(ctx)) this_bytes = buffer_write_space(ctx) - 3; if (in && this_bytes > buffer_read_space(ctx)) this_bytes = buffer_read_space(ctx); if (this_bytes > 0) { buffer_write_byte(ctx, mode); buffer_write_byte(ctx, (this_bytes - 1) & 0xff); buffer_write_byte(ctx, (this_bytes - 1) >> 8); if (out) out_offset += buffer_write(ctx, out, out_offset, this_bytes * 8); if (in) in_offset += buffer_add_read(ctx, in, in_offset, this_bytes * 8, 0); if (!out && !in) for (unsigned n = 0; n < this_bytes; n++) buffer_write_byte(ctx, 0x00); length -= this_bytes * 8; } } } } void mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, unsigned length, bool tdi, uint8_t mode) { mpsse_clock_tms_cs(ctx, out, out_offset, NULL, 0, length, tdi, mode); } void mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, unsigned in_offset, unsigned length, bool tdi, uint8_t mode) { LOG_DEBUG_IO("%sout %d bits, tdi=%d", in ? "in" : "", length, tdi); assert(out); if (ctx->retval != ERROR_OK) { LOG_DEBUG_IO("Ignoring command due to previous error"); return; } mode |= 0x42; if (in) mode |= 0x20; while (length > 0) { /* Guarantee buffer space enough for a minimum size transfer */ if (buffer_write_space(ctx) < 3 || (in && buffer_read_space(ctx) < 1)) ctx->retval = mpsse_flush(ctx); /* Byte transfer */ unsigned this_bits = length; /* MPSSE command limit */ /* NOTE: there's a report of an FT2232 bug in this area, where shifting * exactly 7 bits can make problems with TMS signaling for the last * clock cycle: * * http://developer.intra2net.com/mailarchive/html/libftdi/2009/msg00292.html */ if (this_bits > 7) this_bits = 7; if (this_bits > 0) { buffer_write_byte(ctx, mode); buffer_write_byte(ctx, this_bits - 1); uint8_t data = 0; /* TODO: Fix MSB first, if allowed in MPSSE */ bit_copy(&data, 0, out, out_offset, this_bits); out_offset += this_bits; buffer_write_byte(ctx, data | (tdi ? 0x80 : 0x00)); if (in) in_offset += buffer_add_read(ctx, in, in_offset, this_bits, 8 - this_bits); length -= this_bits; } } } void mpsse_set_data_bits_low_byte(struct mpsse_ctx *ctx, uint8_t data, uint8_t dir) { LOG_DEBUG_IO("-"); if (ctx->retval != ERROR_OK) { LOG_DEBUG_IO("Ignoring command due to previous error"); return; } if (buffer_write_space(ctx) < 3) ctx->retval = mpsse_flush(ctx); buffer_write_byte(ctx, 0x80); buffer_write_byte(ctx, data); buffer_write_byte(ctx, dir); } void mpsse_set_data_bits_high_byte(struct mpsse_ctx *ctx, uint8_t data, uint8_t dir) { LOG_DEBUG_IO("-"); if (ctx->retval != ERROR_OK) { LOG_DEBUG_IO("Ignoring command due to previous error"); return; } if (buffer_write_space(ctx) < 3) ctx->retval = mpsse_flush(ctx); buffer_write_byte(ctx, 0x82); buffer_write_byte(ctx, data); buffer_write_byte(ctx, dir); } void mpsse_read_data_bits_low_byte(struct mpsse_ctx *ctx, uint8_t *data) { LOG_DEBUG_IO("-"); if (ctx->retval != ERROR_OK) { LOG_DEBUG_IO("Ignoring command due to previous error"); return; } if (buffer_write_space(ctx) < 1 || buffer_read_space(ctx) < 1) ctx->retval = mpsse_flush(ctx); buffer_write_byte(ctx, 0x81); buffer_add_read(ctx, data, 0, 8, 0); } void mpsse_read_data_bits_high_byte(struct mpsse_ctx *ctx, uint8_t *data) { LOG_DEBUG_IO("-"); if (ctx->retval != ERROR_OK) { LOG_DEBUG_IO("Ignoring command due to previous error"); return; } if (buffer_write_space(ctx) < 1 || buffer_read_space(ctx) < 1) ctx->retval = mpsse_flush(ctx); buffer_write_byte(ctx, 0x83); buffer_add_read(ctx, data, 0, 8, 0); } static void single_byte_boolean_helper(struct mpsse_ctx *ctx, bool var, uint8_t val_if_true, uint8_t val_if_false) { if (ctx->retval != ERROR_OK) { LOG_DEBUG_IO("Ignoring command due to previous error"); return; } if (buffer_write_space(ctx) < 1) ctx->retval = mpsse_flush(ctx); buffer_write_byte(ctx, var ? val_if_true : val_if_false); } void mpsse_loopback_config(struct mpsse_ctx *ctx, bool enable) { LOG_DEBUG("%s", enable ? "on" : "off"); single_byte_boolean_helper(ctx, enable, 0x84, 0x85); } void mpsse_set_divisor(struct mpsse_ctx *ctx, uint16_t divisor) { LOG_DEBUG("%d", divisor); if (ctx->retval != ERROR_OK) { LOG_DEBUG_IO("Ignoring command due to previous error"); return; } if (buffer_write_space(ctx) < 3) ctx->retval = mpsse_flush(ctx); buffer_write_byte(ctx, 0x86); buffer_write_byte(ctx, divisor & 0xff); buffer_write_byte(ctx, divisor >> 8); } int mpsse_divide_by_5_config(struct mpsse_ctx *ctx, bool enable) { if (!mpsse_is_high_speed(ctx)) return ERROR_FAIL; LOG_DEBUG("%s", enable ? "on" : "off"); single_byte_boolean_helper(ctx, enable, 0x8b, 0x8a); return ERROR_OK; } int mpsse_rtck_config(struct mpsse_ctx *ctx, bool enable) { if (!mpsse_is_high_speed(ctx)) return ERROR_FAIL; LOG_DEBUG("%s", enable ? "on" : "off"); single_byte_boolean_helper(ctx, enable, 0x96, 0x97); return ERROR_OK; } int mpsse_set_frequency(struct mpsse_ctx *ctx, int frequency) { LOG_DEBUG("target %d Hz", frequency); assert(frequency >= 0); int base_clock; if (frequency == 0) return mpsse_rtck_config(ctx, true); mpsse_rtck_config(ctx, false); /* just try */ if (frequency > 60000000 / 2 / 65536 && mpsse_divide_by_5_config(ctx, false) == ERROR_OK) { base_clock = 60000000; } else { mpsse_divide_by_5_config(ctx, true); /* just try */ base_clock = 12000000; } int divisor = (base_clock / 2 + frequency - 1) / frequency - 1; if (divisor > 65535) divisor = 65535; assert(divisor >= 0); mpsse_set_divisor(ctx, divisor); frequency = base_clock / 2 / (1 + divisor); LOG_DEBUG("actually %d Hz", frequency); return frequency; } /* Context needed by the callbacks */ struct transfer_result { struct mpsse_ctx *ctx; bool done; unsigned transferred; }; static LIBUSB_CALL void read_cb(struct libusb_transfer *transfer) { struct transfer_result *res = transfer->user_data; struct mpsse_ctx *ctx = res->ctx; unsigned packet_size = ctx->max_packet_size; DEBUG_PRINT_BUF(transfer->buffer, transfer->actual_length); /* Strip the two status bytes sent at the beginning of each USB packet * while copying the chunk buffer to the read buffer */ unsigned num_packets = DIV_ROUND_UP(transfer->actual_length, packet_size); unsigned chunk_remains = transfer->actual_length; for (unsigned i = 0; i < num_packets && chunk_remains > 2; i++) { unsigned this_size = packet_size - 2; if (this_size > chunk_remains - 2) this_size = chunk_remains - 2; if (this_size > ctx->read_count - res->transferred) this_size = ctx->read_count - res->transferred; memcpy(ctx->read_buffer + res->transferred, ctx->read_chunk + packet_size * i + 2, this_size); res->transferred += this_size; chunk_remains -= this_size + 2; if (res->transferred == ctx->read_count) { res->done = true; break; } } LOG_DEBUG_IO("raw chunk %d, transferred %d of %d", transfer->actual_length, res->transferred, ctx->read_count); if (!res->done) if (libusb_submit_transfer(transfer) != LIBUSB_SUCCESS) res->done = true; } static LIBUSB_CALL void write_cb(struct libusb_transfer *transfer) { struct transfer_result *res = transfer->user_data; struct mpsse_ctx *ctx = res->ctx; res->transferred += transfer->actual_length; LOG_DEBUG_IO("transferred %d of %d", res->transferred, ctx->write_count); DEBUG_PRINT_BUF(transfer->buffer, transfer->actual_length); if (res->transferred == ctx->write_count) res->done = true; else { transfer->length = ctx->write_count - res->transferred; transfer->buffer = ctx->write_buffer + res->transferred; if (libusb_submit_transfer(transfer) != LIBUSB_SUCCESS) res->done = true; } } int mpsse_flush(struct mpsse_ctx *ctx) { int retval = ctx->retval; if (retval != ERROR_OK) { LOG_DEBUG_IO("Ignoring flush due to previous error"); assert(ctx->write_count == 0 && ctx->read_count == 0); ctx->retval = ERROR_OK; return retval; } LOG_DEBUG_IO("write %d%s, read %d", ctx->write_count, ctx->read_count ? "+1" : "", ctx->read_count); assert(ctx->write_count > 0 || ctx->read_count == 0); /* No read data without write data */ if (ctx->write_count == 0) return retval; struct libusb_transfer *read_transfer = NULL; struct transfer_result read_result = { .ctx = ctx, .done = true }; if (ctx->read_count) { buffer_write_byte(ctx, 0x87); /* SEND_IMMEDIATE */ read_result.done = false; /* delay read transaction to ensure the FTDI chip can support us with data immediately after processing the MPSSE commands in the write transaction */ } struct transfer_result write_result = { .ctx = ctx, .done = false }; struct libusb_transfer *write_transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(write_transfer, ctx->usb_dev, ctx->out_ep, ctx->write_buffer, ctx->write_count, write_cb, &write_result, ctx->usb_write_timeout); retval = libusb_submit_transfer(write_transfer); if (retval != LIBUSB_SUCCESS) goto error_check; if (ctx->read_count) { read_transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(read_transfer, ctx->usb_dev, ctx->in_ep, ctx->read_chunk, ctx->read_chunk_size, read_cb, &read_result, ctx->usb_read_timeout); retval = libusb_submit_transfer(read_transfer); if (retval != LIBUSB_SUCCESS) goto error_check; } /* Polling loop, more or less taken from libftdi */ int64_t start = timeval_ms(); int64_t warn_after = 2000; while (!write_result.done || !read_result.done) { struct timeval timeout_usb; timeout_usb.tv_sec = 1; timeout_usb.tv_usec = 0; retval = libusb_handle_events_timeout_completed(ctx->usb_ctx, &timeout_usb, NULL); keep_alive(); if (retval == LIBUSB_ERROR_NO_DEVICE || retval == LIBUSB_ERROR_INTERRUPTED) break; if (retval != LIBUSB_SUCCESS) { libusb_cancel_transfer(write_transfer); if (read_transfer) libusb_cancel_transfer(read_transfer); while (!write_result.done || !read_result.done) { retval = libusb_handle_events_timeout_completed(ctx->usb_ctx, &timeout_usb, NULL); if (retval != LIBUSB_SUCCESS) break; } } int64_t now = timeval_ms(); if (now - start > warn_after) { LOG_WARNING("Haven't made progress in mpsse_flush() for %" PRId64 "ms.", now - start); warn_after *= 2; } } error_check: if (retval != LIBUSB_SUCCESS) { LOG_ERROR("libusb_handle_events() failed with %s", libusb_error_name(retval)); retval = ERROR_FAIL; } else if (write_result.transferred < ctx->write_count) { LOG_ERROR("ftdi device did not accept all data: %d, tried %d", write_result.transferred, ctx->write_count); retval = ERROR_FAIL; } else if (read_result.transferred < ctx->read_count) { LOG_ERROR("ftdi device did not return all data: %d, expected %d", read_result.transferred, ctx->read_count); retval = ERROR_FAIL; } else if (ctx->read_count) { ctx->write_count = 0; ctx->read_count = 0; bit_copy_execute(&ctx->read_queue); retval = ERROR_OK; } else { ctx->write_count = 0; bit_copy_discard(&ctx->read_queue); retval = ERROR_OK; } if (retval != ERROR_OK) mpsse_purge(ctx); libusb_free_transfer(write_transfer); if (read_transfer) libusb_free_transfer(read_transfer); return retval; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/mpsse.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /************************************************************************** * Copyright (C) 2012 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_MPSSE_H #define OPENOCD_JTAG_DRIVERS_MPSSE_H #include <stdbool.h> #include "helper/binarybuffer.h" /* Mode flags */ #define POS_EDGE_OUT 0x00 #define NEG_EDGE_OUT 0x01 #define POS_EDGE_IN 0x00 #define NEG_EDGE_IN 0x04 #define MSB_FIRST 0x00 #define LSB_FIRST 0x08 enum ftdi_chip_type { TYPE_FT2232C, TYPE_FT2232H, TYPE_FT4232H, TYPE_FT232H, }; struct mpsse_ctx; /* Device handling */ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const char *description, const char *serial, const char *location, int channel); void mpsse_close(struct mpsse_ctx *ctx); bool mpsse_is_high_speed(struct mpsse_ctx *ctx); /* Command queuing. These correspond to the MPSSE commands with the same names, but no need to care * about bit/byte transfer or data length limitation. Read data is guaranteed to be available only * after the following mpsse_flush(). */ void mpsse_clock_data_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, unsigned length, uint8_t mode); void mpsse_clock_data_in(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_offset, unsigned length, uint8_t mode); void mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, unsigned in_offset, unsigned length, uint8_t mode); void mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, unsigned length, bool tdi, uint8_t mode); void mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, unsigned in_offset, unsigned length, bool tdi, uint8_t mode); void mpsse_set_data_bits_low_byte(struct mpsse_ctx *ctx, uint8_t data, uint8_t dir); void mpsse_set_data_bits_high_byte(struct mpsse_ctx *ctx, uint8_t data, uint8_t dir); void mpsse_read_data_bits_low_byte(struct mpsse_ctx *ctx, uint8_t *data); void mpsse_read_data_bits_high_byte(struct mpsse_ctx *ctx, uint8_t *data); void mpsse_loopback_config(struct mpsse_ctx *ctx, bool enable); void mpsse_set_divisor(struct mpsse_ctx *ctx, uint16_t divisor); int mpsse_divide_by_5_config(struct mpsse_ctx *ctx, bool enable); int mpsse_rtck_config(struct mpsse_ctx *ctx, bool enable); /* Helper to set frequency in Hertz. Returns actual realizable frequency or negative error. * Frequency 0 means RTCK. */ int mpsse_set_frequency(struct mpsse_ctx *ctx, int frequency); /* Queue handling */ int mpsse_flush(struct mpsse_ctx *ctx); void mpsse_purge(struct mpsse_ctx *ctx); #endif /* OPENOCD_JTAG_DRIVERS_MPSSE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/nulink_usb.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2016-2017 by Nuvoton * * Zale Yu <cyyu@nuvoton.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include <helper/binarybuffer.h> #include <jtag/adapter.h> #include <jtag/interface.h> #include <jtag/hla/hla_layout.h> #include <jtag/hla/hla_transport.h> #include <jtag/hla/hla_interface.h> #include <target/target.h> #include <target/cortex_m.h> #include <hidapi.h> #include "libusb_helper.h" #define NULINK_READ_TIMEOUT LIBUSB_TIMEOUT_MS #define NULINK_HID_MAX_SIZE (64) #define NULINK2_HID_MAX_SIZE (1024) #define V6M_MAX_COMMAND_LENGTH (NULINK_HID_MAX_SIZE - 2) #define V7M_MAX_COMMAND_LENGTH (NULINK_HID_MAX_SIZE - 3) #define NULINK2_USB_PID1 (0x5200) #define NULINK2_USB_PID2 (0x5201) struct nulink_usb_handle_s { hid_device *dev_handle; uint16_t max_packet_size; uint8_t usbcmdidx; uint8_t cmdidx; uint8_t cmdsize; uint8_t cmdbuf[NULINK2_HID_MAX_SIZE + 1]; uint8_t tempbuf[NULINK2_HID_MAX_SIZE]; uint8_t databuf[NULINK2_HID_MAX_SIZE]; uint32_t max_mem_packet; uint16_t hardware_config; /* bit 0: 1:Nu-Link-Pro, 0:Nu-Link */ int (*xfer)(void *handle, uint8_t *buf, int size); void (*init_buffer)(void *handle, uint32_t size); }; /* ICE Command */ #define CMD_READ_REG 0xB5UL #define CMD_READ_RAM 0xB1UL #define CMD_WRITE_REG 0xB8UL #define CMD_WRITE_RAM 0xB9UL #define CMD_CHECK_ID 0xA3UL #define CMD_MCU_RESET 0xE2UL #define CMD_CHECK_MCU_STOP 0xD8UL #define CMD_MCU_STEP_RUN 0xD1UL #define CMD_MCU_STOP_RUN 0xD2UL #define CMD_MCU_FREE_RUN 0xD3UL #define CMD_SET_CONFIG 0xA2UL #define ARM_SRAM_BASE 0x20000000UL #define HARDWARE_CONFIG_NULINKPRO 1 #define HARDWARE_CONFIG_NULINK2 2 enum nulink_reset { RESET_AUTO = 0, RESET_HW = 1, RESET_SYSRESETREQ = 2, RESET_VECTRESET = 3, RESET_FAST_RESCUE = 4, /* Rescue and erase the chip, need very fast speed */ }; enum nulink_connect { CONNECT_NORMAL = 0, /* Support all reset method */ CONNECT_PRE_RESET = 1, /* Support all reset method */ CONNECT_UNDER_RESET = 2, /* Support all reset method */ CONNECT_NONE = 3, /* Support RESET_HW, (RESET_AUTO = RESET_HW) */ CONNECT_DISCONNECT = 4, /* Support RESET_NONE, (RESET_AUTO = RESET_NONE) */ CONNECT_ICP_MODE = 5 /* Support NUC505 ICP mode*/ }; static int nulink_usb_xfer_rw(void *handle, uint8_t *buf) { struct nulink_usb_handle_s *h = handle; assert(handle); int ret = hid_write(h->dev_handle, h->cmdbuf, h->max_packet_size + 1); if (ret < 0) { LOG_ERROR("hid_write"); return ERROR_FAIL; } ret = hid_read_timeout(h->dev_handle, buf, h->max_packet_size, NULINK_READ_TIMEOUT); if (ret < 0) { LOG_ERROR("hid_read_timeout"); return ERROR_FAIL; } return ERROR_OK; } static int nulink1_usb_xfer(void *handle, uint8_t *buf, int size) { struct nulink_usb_handle_s *h = handle; assert(handle); int err = nulink_usb_xfer_rw(h, h->tempbuf); memcpy(buf, h->tempbuf + 2, V6M_MAX_COMMAND_LENGTH); return err; } static int nulink2_usb_xfer(void *handle, uint8_t *buf, int size) { struct nulink_usb_handle_s *h = handle; assert(handle); int err = nulink_usb_xfer_rw(h, h->tempbuf); memcpy(buf, h->tempbuf + 3, V7M_MAX_COMMAND_LENGTH); return err; } static void nulink1_usb_init_buffer(void *handle, uint32_t size) { struct nulink_usb_handle_s *h = handle; h->cmdidx = 0; memset(h->cmdbuf, 0, h->max_packet_size + 1); memset(h->tempbuf, 0, h->max_packet_size); memset(h->databuf, 0, h->max_packet_size); h->cmdbuf[0] = 0; /* report number */ h->cmdbuf[1] = ++h->usbcmdidx & 0x7F; h->cmdbuf[2] = size; h->cmdidx += 3; } static void nulink2_usb_init_buffer(void *handle, uint32_t size) { struct nulink_usb_handle_s *h = handle; h->cmdidx = 0; memset(h->cmdbuf, 0, h->max_packet_size + 1); memset(h->tempbuf, 0, h->max_packet_size); memset(h->databuf, 0, h->max_packet_size); h->cmdbuf[0] = 0; /* report number */ h->cmdbuf[1] = ++h->usbcmdidx & 0x7F; h_u16_to_le(h->cmdbuf + 2, size); h->cmdidx += 4; } static inline int nulink_usb_xfer(void *handle, uint8_t *buf, int size) { struct nulink_usb_handle_s *h = handle; assert(handle); return h->xfer(handle, buf, size); } static inline void nulink_usb_init_buffer(void *handle, uint32_t size) { struct nulink_usb_handle_s *h = handle; assert(handle); h->init_buffer(handle, size); } static int nulink_usb_version(void *handle) { struct nulink_usb_handle_s *h = handle; LOG_DEBUG("nulink_usb_version"); assert(handle); nulink_usb_init_buffer(handle, V6M_MAX_COMMAND_LENGTH); memset(h->cmdbuf + h->cmdidx, 0xFF, V6M_MAX_COMMAND_LENGTH); h->cmdbuf[h->cmdidx + 4] = 0xA1; /* host_rev_num: 6561 */; h->cmdbuf[h->cmdidx + 5] = 0x19; int res = nulink_usb_xfer(handle, h->databuf, h->cmdsize); if (res != ERROR_OK) return res; LOG_INFO("Nu-Link firmware_version %" PRIu32 ", product_id (0x%08" PRIx32 ")", le_to_h_u32(h->databuf), le_to_h_u32(h->databuf + 4 * 1)); const bool is_nulinkpro = !!(le_to_h_u32(h->databuf + 4 * 2) & 1); if (is_nulinkpro) { LOG_INFO("Adapter is Nu-Link-Pro, target_voltage_mv(%" PRIu16 "), usb_voltage_mv(%" PRIu16 ")", le_to_h_u16(h->databuf + 4 * 3 + 0), le_to_h_u16(h->databuf + 4 * 3 + 2)); h->hardware_config |= HARDWARE_CONFIG_NULINKPRO; } else { LOG_INFO("Adapter is Nu-Link"); } return ERROR_OK; } static int nulink_usb_idcode(void *handle, uint32_t *idcode) { struct nulink_usb_handle_s *h = handle; LOG_DEBUG("nulink_usb_idcode"); assert(handle); nulink_usb_init_buffer(handle, 4 * 1); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_CHECK_ID); h->cmdidx += 4; int res = nulink_usb_xfer(handle, h->databuf, 4 * 2); if (res != ERROR_OK) return res; *idcode = le_to_h_u32(h->databuf + 4 * 1); LOG_INFO("IDCODE: 0x%08" PRIX32, *idcode); return ERROR_OK; } static int nulink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) { struct nulink_usb_handle_s *h = handle; LOG_DEBUG("nulink_usb_write_debug_reg 0x%08" PRIX32 " 0x%08" PRIX32, addr, val); nulink_usb_init_buffer(handle, 8 + 12 * 1); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_WRITE_RAM); h->cmdidx += 4; /* Count of registers */ h->cmdbuf[h->cmdidx] = 1; h->cmdidx += 1; /* Array of bool value (u8ReadOld) */ h->cmdbuf[h->cmdidx] = 0x00; h->cmdidx += 1; /* Array of bool value (u8Verify) */ h->cmdbuf[h->cmdidx] = 0x00; h->cmdidx += 1; /* ignore */ h->cmdbuf[h->cmdidx] = 0; h->cmdidx += 1; /* u32Addr */ h_u32_to_le(h->cmdbuf + h->cmdidx, addr); h->cmdidx += 4; /* u32Data */ h_u32_to_le(h->cmdbuf + h->cmdidx, val); h->cmdidx += 4; /* u32Mask */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0x00000000UL); h->cmdidx += 4; return nulink_usb_xfer(handle, h->databuf, 4 * 2); } static enum target_state nulink_usb_state(void *handle) { struct nulink_usb_handle_s *h = handle; assert(handle); nulink_usb_init_buffer(handle, 4 * 1); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_CHECK_MCU_STOP); h->cmdidx += 4; int res = nulink_usb_xfer(handle, h->databuf, 4 * 4); if (res != ERROR_OK) return TARGET_UNKNOWN; if (!le_to_h_u32(h->databuf + 4 * 2)) return TARGET_HALTED; else return TARGET_RUNNING; } static int nulink_usb_assert_srst(void *handle, int srst) { struct nulink_usb_handle_s *h = handle; LOG_DEBUG("nulink_usb_assert_srst"); assert(handle); nulink_usb_init_buffer(handle, 4 * 4); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_MCU_RESET); h->cmdidx += 4; /* set reset type */ h_u32_to_le(h->cmdbuf + h->cmdidx, RESET_SYSRESETREQ); h->cmdidx += 4; /* set connect type */ h_u32_to_le(h->cmdbuf + h->cmdidx, CONNECT_NORMAL); h->cmdidx += 4; /* set extMode */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0); h->cmdidx += 4; return nulink_usb_xfer(handle, h->databuf, 4 * 4); } static int nulink_usb_reset(void *handle) { struct nulink_usb_handle_s *h = handle; LOG_DEBUG("nulink_usb_reset"); assert(handle); nulink_usb_init_buffer(handle, 4 * 4); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_MCU_RESET); h->cmdidx += 4; /* set reset type */ h_u32_to_le(h->cmdbuf + h->cmdidx, RESET_HW); h->cmdidx += 4; /* set connect type */ h_u32_to_le(h->cmdbuf + h->cmdidx, CONNECT_NORMAL); h->cmdidx += 4; /* set extMode */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0); h->cmdidx += 4; return nulink_usb_xfer(handle, h->databuf, 4 * 4); } static int nulink_usb_run(void *handle) { struct nulink_usb_handle_s *h = handle; LOG_DEBUG("nulink_usb_run"); assert(handle); nulink_usb_init_buffer(handle, 4 * 1); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_MCU_FREE_RUN); h->cmdidx += 4; return nulink_usb_xfer(handle, h->databuf, 4 * 4); } static int nulink_usb_halt(void *handle) { struct nulink_usb_handle_s *h = handle; LOG_DEBUG("nulink_usb_halt"); assert(handle); nulink_usb_init_buffer(handle, 4 * 1); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_MCU_STOP_RUN); h->cmdidx += 4; int res = nulink_usb_xfer(handle, h->databuf, 4 * 4); LOG_DEBUG("Nu-Link stop_pc 0x%08" PRIx32, le_to_h_u32(h->databuf + 4)); return res; } static int nulink_usb_step(void *handle) { struct nulink_usb_handle_s *h = handle; LOG_DEBUG("nulink_usb_step"); assert(handle); nulink_usb_init_buffer(handle, 4 * 1); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_MCU_STEP_RUN); h->cmdidx += 4; int res = nulink_usb_xfer(handle, h->databuf, 4 * 4); LOG_DEBUG("Nu-Link pc 0x%08" PRIx32, le_to_h_u32(h->databuf + 4)); return res; } static int nulink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) { struct nulink_usb_handle_s *h = handle; assert(handle); nulink_usb_init_buffer(handle, 8 + 12 * 1); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_WRITE_REG); h->cmdidx += 4; /* Count of registers */ h->cmdbuf[h->cmdidx] = 1; h->cmdidx += 1; /* Array of bool value (u8ReadOld) */ h->cmdbuf[h->cmdidx] = 0xFF; h->cmdidx += 1; /* Array of bool value (u8Verify) */ h->cmdbuf[h->cmdidx] = 0x00; h->cmdidx += 1; /* ignore */ h->cmdbuf[h->cmdidx] = 0; h->cmdidx += 1; /* u32Addr */ h_u32_to_le(h->cmdbuf + h->cmdidx, regsel); h->cmdidx += 4; /* u32Data */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0); h->cmdidx += 4; /* u32Mask */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0xFFFFFFFFUL); h->cmdidx += 4; int res = nulink_usb_xfer(handle, h->databuf, 4 * 2); *val = le_to_h_u32(h->databuf + 4 * 1); return res; } static int nulink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val) { struct nulink_usb_handle_s *h = handle; assert(handle); nulink_usb_init_buffer(handle, 8 + 12 * 1); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_WRITE_REG); h->cmdidx += 4; /* Count of registers */ h->cmdbuf[h->cmdidx] = 1; h->cmdidx += 1; /* Array of bool value (u8ReadOld) */ h->cmdbuf[h->cmdidx] = 0x00; h->cmdidx += 1; /* Array of bool value (u8Verify) */ h->cmdbuf[h->cmdidx] = 0x00; h->cmdidx += 1; /* ignore */ h->cmdbuf[h->cmdidx] = 0; h->cmdidx += 1; /* u32Addr */ h_u32_to_le(h->cmdbuf + h->cmdidx, regsel); h->cmdidx += 4; /* u32Data */ h_u32_to_le(h->cmdbuf + h->cmdidx, val); h->cmdidx += 4; /* u32Mask */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0x00000000UL); h->cmdidx += 4; return nulink_usb_xfer(handle, h->databuf, 4 * 2); } static int nulink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len, uint8_t *buffer) { int res = ERROR_OK; uint32_t offset = 0; uint32_t bytes_remaining = 12; struct nulink_usb_handle_s *h = handle; LOG_DEBUG("nulink_usb_read_mem8: addr 0x%08" PRIx32 ", len %" PRId16, addr, len); assert(handle); /* check whether data is word aligned */ if (addr % 4) { uint32_t aligned_addr = addr / 4; aligned_addr = aligned_addr * 4; offset = addr - aligned_addr; LOG_DEBUG("nulink_usb_read_mem8: unaligned address addr 0x%08" PRIx32 "/aligned addr 0x%08" PRIx32 " offset %" PRIu32, addr, aligned_addr, offset); addr = aligned_addr; } while (len) { unsigned int count; if (len < bytes_remaining) bytes_remaining = len; if (len < 4) count = 1; else count = 2; nulink_usb_init_buffer(handle, 8 + 12 * count); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_WRITE_RAM); h->cmdidx += 4; /* Count of registers */ h->cmdbuf[h->cmdidx] = count; h->cmdidx += 1; /* Array of bool value (u8ReadOld) */ h->cmdbuf[h->cmdidx] = 0xFF; h->cmdidx += 1; /* Array of bool value (u8Verify) */ h->cmdbuf[h->cmdidx] = 0x00; h->cmdidx += 1; /* ignore */ h->cmdbuf[h->cmdidx] = 0; h->cmdidx += 1; for (unsigned int i = 0; i < count; i++) { /* u32Addr */ h_u32_to_le(h->cmdbuf + h->cmdidx, addr); h->cmdidx += 4; /* u32Data */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0); h->cmdidx += 4; /* u32Mask */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0xFFFFFFFFUL); h->cmdidx += 4; /* proceed to the next one */ addr += 4; } res = nulink_usb_xfer(handle, h->databuf, 4 * count * 2); if (res != ERROR_OK) break; /* fill in the output buffer */ for (unsigned int i = 0; i < count; i++) { if (i == 0) memcpy(buffer, h->databuf + 4 + offset, len); else memcpy(buffer + 2 * i, h->databuf + 4 * (2 * i + 1), len - 2); } if (len >= bytes_remaining) len -= bytes_remaining; } return res; } static int nulink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len, const uint8_t *buffer) { int res = ERROR_OK; uint32_t offset = 0; uint32_t bytes_remaining = 12; struct nulink_usb_handle_s *h = handle; LOG_DEBUG("nulink_usb_write_mem8: addr 0x%08" PRIx32 ", len %" PRIu16, addr, len); assert(handle); /* check whether data is word aligned */ if (addr % 4) { uint32_t aligned_addr = addr / 4; aligned_addr = aligned_addr * 4; offset = addr - aligned_addr; LOG_DEBUG("nulink_usb_write_mem8: address not aligned. addr(0x%08" PRIx32 ")/aligned_addr(0x%08" PRIx32 ")/offset(%" PRIu32 ")", addr, aligned_addr, offset); addr = aligned_addr; } while (len) { unsigned int count; if (len < bytes_remaining) bytes_remaining = len; if (len < 4) count = 1; else count = 2; nulink_usb_init_buffer(handle, 8 + 12 * count); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_WRITE_RAM); h->cmdidx += 4; /* Count of registers */ h->cmdbuf[h->cmdidx] = count; h->cmdidx += 1; /* Array of bool value (u8ReadOld) */ h->cmdbuf[h->cmdidx] = 0x00; h->cmdidx += 1; /* Array of bool value (u8Verify) */ h->cmdbuf[h->cmdidx] = 0x00; h->cmdidx += 1; /* ignore */ h->cmdbuf[h->cmdidx] = 0; h->cmdidx += 1; for (unsigned int i = 0; i < count; i++) { /* u32Addr */ h_u32_to_le(h->cmdbuf + h->cmdidx, addr); h->cmdidx += 4; /* u32Data */ uint32_t u32buffer = buf_get_u32(buffer, 0, len * 8); u32buffer = (u32buffer << offset * 8); h_u32_to_le(h->cmdbuf + h->cmdidx, u32buffer); h->cmdidx += 4; /* u32Mask */ if (i == 0) { if (offset == 0) { if (len == 1) { h_u32_to_le(h->cmdbuf + h->cmdidx, 0xFFFFFF00UL); LOG_DEBUG("nulink_usb_write_mem8: count(%u), mask: 0xFFFFFF00", i); } else { h_u32_to_le(h->cmdbuf + h->cmdidx, 0xFFFF0000UL); LOG_DEBUG("nulink_usb_write_mem8: count(%u), mask: 0xFFFF0000", i); } } else { if (len == 1) { h_u32_to_le(h->cmdbuf + h->cmdidx, 0xFF00FFFFUL); LOG_DEBUG("nulink_usb_write_mem8: count(%u), mask: 0xFF00FFFF", i); } else { h_u32_to_le(h->cmdbuf + h->cmdidx, 0x0000FFFFUL); LOG_DEBUG("nulink_usb_write_mem8: count(%u), mask: 0x0000FFFF", i); } } } else { if (len == 4) { h_u32_to_le(h->cmdbuf + h->cmdidx, 0xFFFF0000UL); LOG_DEBUG("nulink_usb_write_mem8: count(%u), mask: 0xFFFF0000", i); } else { h_u32_to_le(h->cmdbuf + h->cmdidx, 0x00000000UL); LOG_DEBUG("nulink_usb_write_mem8: count(%u), mask: 0x00000000", i); } } h->cmdidx += 4; /* proceed to the next one */ addr += 4; buffer += 4; } res = nulink_usb_xfer(handle, h->databuf, 4 * count * 2); if (res != ERROR_OK) break; if (len >= bytes_remaining) len -= bytes_remaining; } return res; } static int nulink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len, uint8_t *buffer) { int res = ERROR_OK; uint32_t bytes_remaining = 12; struct nulink_usb_handle_s *h = handle; assert(handle); /* data must be a multiple of 4 and word aligned */ if (len % 4 || addr % 4) { LOG_ERROR("Invalid data alignment"); return ERROR_TARGET_UNALIGNED_ACCESS; } while (len) { if (len < bytes_remaining) bytes_remaining = len; unsigned int count = bytes_remaining / 4; nulink_usb_init_buffer(handle, 8 + 12 * count); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_WRITE_RAM); h->cmdidx += 4; /* Count of registers */ h->cmdbuf[h->cmdidx] = count; h->cmdidx += 1; /* Array of bool value (u8ReadOld) */ h->cmdbuf[h->cmdidx] = 0xFF; h->cmdidx += 1; /* Array of bool value (u8Verify) */ h->cmdbuf[h->cmdidx] = 0x00; h->cmdidx += 1; /* ignore */ h->cmdbuf[h->cmdidx] = 0; h->cmdidx += 1; for (unsigned int i = 0; i < count; i++) { /* u32Addr */ h_u32_to_le(h->cmdbuf + h->cmdidx, addr); h->cmdidx += 4; /* u32Data */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0); h->cmdidx += 4; /* u32Mask */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0xFFFFFFFFUL); h->cmdidx += 4; /* proceed to the next one */ addr += 4; } res = nulink_usb_xfer(handle, h->databuf, 4 * count * 2); /* fill in the output buffer */ for (unsigned int i = 0; i < count; i++) { memcpy(buffer, h->databuf + 4 * (2 * i + 1), 4); buffer += 4; } if (len >= bytes_remaining) len -= bytes_remaining; else len = 0; } return res; } static int nulink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len, const uint8_t *buffer) { int res = ERROR_OK; uint32_t bytes_remaining = 12; struct nulink_usb_handle_s *h = handle; assert(handle); /* data must be a multiple of 4 and word aligned */ if (len % 4 || addr % 4) { LOG_ERROR("Invalid data alignment"); return ERROR_TARGET_UNALIGNED_ACCESS; } while (len) { if (len < bytes_remaining) bytes_remaining = len; unsigned int count = bytes_remaining / 4; nulink_usb_init_buffer(handle, 8 + 12 * count); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_WRITE_RAM); h->cmdidx += 4; /* Count of registers */ h->cmdbuf[h->cmdidx] = count; h->cmdidx += 1; /* Array of bool value (u8ReadOld) */ h->cmdbuf[h->cmdidx] = 0x00; h->cmdidx += 1; /* Array of bool value (u8Verify) */ h->cmdbuf[h->cmdidx] = 0x00; h->cmdidx += 1; /* ignore */ h->cmdbuf[h->cmdidx] = 0; h->cmdidx += 1; for (unsigned int i = 0; i < count; i++) { /* u32Addr */ h_u32_to_le(h->cmdbuf + h->cmdidx, addr); h->cmdidx += 4; /* u32Data */ uint32_t u32buffer = buf_get_u32(buffer, 0, 32); h_u32_to_le(h->cmdbuf + h->cmdidx, u32buffer); h->cmdidx += 4; /* u32Mask */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0x00000000); h->cmdidx += 4; /* proceed to the next one */ addr += 4; buffer += 4; } res = nulink_usb_xfer(handle, h->databuf, 4 * count * 2); if (len >= bytes_remaining) len -= bytes_remaining; else len = 0; } return res; } static uint32_t nulink_max_block_size(uint32_t tar_autoincr_block, uint32_t address) { uint32_t max_tar_block = (tar_autoincr_block - ((tar_autoincr_block - 1) & address)); if (max_tar_block == 0) max_tar_block = 4; return max_tar_block; } static int nulink_usb_read_mem(void *handle, uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer) { int retval = ERROR_OK; struct nulink_usb_handle_s *h = handle; /* calculate byte count */ count *= size; while (count) { uint32_t bytes_remaining = nulink_max_block_size(h->max_mem_packet, addr); if (count < bytes_remaining) bytes_remaining = count; if (bytes_remaining >= 4) size = 4; /* the nulink only supports 8/32bit memory read/writes * honour 32bit, all others will be handled as 8bit access */ if (size == 4) { /* When in jtag mode the nulink uses the auto-increment functionality. * However it expects us to pass the data correctly, this includes * alignment and any page boundaries. We already do this as part of the * adi_v5 implementation, but the nulink is a hla adapter and so this * needs implementing manually. * currently this only affects jtag mode, they do single * access in SWD mode - but this may change and so we do it for both modes */ /* we first need to check for any unaligned bytes */ if (addr % 4) { uint32_t head_bytes = 4 - (addr % 4); retval = nulink_usb_read_mem8(handle, addr, head_bytes, buffer); if (retval != ERROR_OK) return retval; buffer += head_bytes; addr += head_bytes; count -= head_bytes; bytes_remaining -= head_bytes; } if (bytes_remaining % 4) retval = nulink_usb_read_mem(handle, addr, 1, bytes_remaining, buffer); else retval = nulink_usb_read_mem32(handle, addr, bytes_remaining, buffer); } else { retval = nulink_usb_read_mem8(handle, addr, bytes_remaining, buffer); } if (retval != ERROR_OK) return retval; buffer += bytes_remaining; addr += bytes_remaining; count -= bytes_remaining; } return retval; } static int nulink_usb_write_mem(void *handle, uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval = ERROR_OK; struct nulink_usb_handle_s *h = handle; if (addr < ARM_SRAM_BASE) { LOG_DEBUG("nulink_usb_write_mem: address below ARM_SRAM_BASE, not supported.\n"); return retval; } /* calculate byte count */ count *= size; while (count) { uint32_t bytes_remaining = nulink_max_block_size(h->max_mem_packet, addr); if (count < bytes_remaining) bytes_remaining = count; if (bytes_remaining >= 4) size = 4; /* the nulink only supports 8/32bit memory read/writes * honour 32bit, all others will be handled as 8bit access */ if (size == 4) { /* When in jtag mode the nulink uses the auto-increment functionality. * However it expects us to pass the data correctly, this includes * alignment and any page boundaries. We already do this as part of the * adi_v5 implementation, but the nulink is a hla adapter and so this * needs implementing manually. * currently this only affects jtag mode, do single * access in SWD mode - but this may change and so we do it for both modes */ /* we first need to check for any unaligned bytes */ if (addr % 4) { uint32_t head_bytes = 4 - (addr % 4); retval = nulink_usb_write_mem8(handle, addr, head_bytes, buffer); if (retval != ERROR_OK) return retval; buffer += head_bytes; addr += head_bytes; count -= head_bytes; bytes_remaining -= head_bytes; } if (bytes_remaining % 4) retval = nulink_usb_write_mem(handle, addr, 1, bytes_remaining, buffer); else retval = nulink_usb_write_mem32(handle, addr, bytes_remaining, buffer); } else { retval = nulink_usb_write_mem8(handle, addr, bytes_remaining, buffer); } if (retval != ERROR_OK) return retval; buffer += bytes_remaining; addr += bytes_remaining; count -= bytes_remaining; } return retval; } static int nulink_usb_override_target(const char *targetname) { LOG_DEBUG("nulink_usb_override_target"); return !strcmp(targetname, "cortex_m"); } static int nulink_speed(void *handle, int khz, bool query) { struct nulink_usb_handle_s *h = handle; unsigned long max_ice_clock = khz; LOG_DEBUG("nulink_speed: query %s", query ? "yes" : "no"); if (max_ice_clock > 12000) max_ice_clock = 12000; else if ((max_ice_clock == 3 * 512) || (max_ice_clock == 1500)) max_ice_clock = 1500; else if (max_ice_clock >= 1000) max_ice_clock = max_ice_clock / 1000 * 1000; else max_ice_clock = max_ice_clock / 100 * 100; LOG_DEBUG("Nu-Link nulink_speed: %lu", max_ice_clock); if (!query) { nulink_usb_init_buffer(handle, 4 * 6); /* set command ID */ h_u32_to_le(h->cmdbuf + h->cmdidx, CMD_SET_CONFIG); h->cmdidx += 4; /* set max SWD clock */ h_u32_to_le(h->cmdbuf + h->cmdidx, max_ice_clock); h->cmdidx += 4; /* chip type: NUC_CHIP_TYPE_GENERAL_V6M */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0); h->cmdidx += 4; /* IO voltage */ h_u32_to_le(h->cmdbuf + h->cmdidx, 5000); h->cmdidx += 4; /* If supply voltage to target or not */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0); h->cmdidx += 4; /* USB_FUNC_E: USB_FUNC_HID_BULK */ h_u32_to_le(h->cmdbuf + h->cmdidx, 2); h->cmdidx += 4; nulink_usb_xfer(handle, h->databuf, 4 * 3); LOG_DEBUG("nulink_speed: h->hardware_config(%" PRId16 ")", h->hardware_config); if (h->hardware_config & HARDWARE_CONFIG_NULINKPRO) LOG_INFO("Nu-Link target_voltage_mv[0](%04" PRIx16 "), target_voltage_mv[1](%04" PRIx16 "), target_voltage_mv[2](%04" PRIx16 "), if_target_power_supplied(%d)", le_to_h_u16(h->databuf + 4 * 1 + 0), le_to_h_u16(h->databuf + 4 * 1 + 2), le_to_h_u16(h->databuf + 4 * 2 + 0), le_to_h_u16(h->databuf + 4 * 2 + 2) & 1); } return max_ice_clock; } static int nulink_usb_close(void *handle) { struct nulink_usb_handle_s *h = handle; LOG_DEBUG("nulink_usb_close"); if (h && h->dev_handle) hid_close(h->dev_handle); free(h); hid_exit(); return ERROR_OK; } static int nulink_usb_open(struct hl_interface_param_s *param, void **fd) { struct hid_device_info *devs, *cur_dev; uint16_t target_vid = 0; uint16_t target_pid = 0; wchar_t *target_serial = NULL; LOG_DEBUG("nulink_usb_open"); if (param->transport != HL_TRANSPORT_SWD) return TARGET_UNKNOWN; if (!param->vid[0] && !param->pid[0]) { LOG_ERROR("Missing vid/pid"); return ERROR_FAIL; } if (hid_init() != 0) { LOG_ERROR("unable to open HIDAPI"); return ERROR_FAIL; } struct nulink_usb_handle_s *h = calloc(1, sizeof(*h)); if (!h) { LOG_ERROR("Out of memory"); goto error_open; } const char *serial = adapter_get_required_serial(); if (serial) { size_t len = mbstowcs(NULL, serial, 0); target_serial = calloc(len + 1, sizeof(wchar_t)); if (!target_serial) { LOG_ERROR("Out of memory"); goto error_open; } if (mbstowcs(target_serial, serial, len + 1) == (size_t)(-1)) { LOG_WARNING("unable to convert serial"); free(target_serial); target_serial = NULL; } } devs = hid_enumerate(0, 0); cur_dev = devs; while (cur_dev) { bool found = false; for (unsigned int i = 0; param->vid[i] || param->pid[i]; i++) { if (param->vid[i] == cur_dev->vendor_id && param->pid[i] == cur_dev->product_id) { found = true; break; } } if (found) { if (!target_serial) break; if (cur_dev->serial_number && wcscmp(target_serial, cur_dev->serial_number) == 0) break; } cur_dev = cur_dev->next; } if (cur_dev) { target_vid = cur_dev->vendor_id; target_pid = cur_dev->product_id; } hid_free_enumeration(devs); if (target_vid == 0 && target_pid == 0) { LOG_ERROR("unable to find Nu-Link"); goto error_open; } hid_device *dev = hid_open(target_vid, target_pid, target_serial); if (!dev) { LOG_ERROR("unable to open Nu-Link device 0x%" PRIx16 ":0x%" PRIx16, target_vid, target_pid); goto error_open; } h->dev_handle = dev; h->usbcmdidx = 0; switch (target_pid) { case NULINK2_USB_PID1: case NULINK2_USB_PID2: h->hardware_config = HARDWARE_CONFIG_NULINK2; h->max_packet_size = NULINK2_HID_MAX_SIZE; h->init_buffer = nulink2_usb_init_buffer; h->xfer = nulink2_usb_xfer; break; default: h->hardware_config = 0; h->max_packet_size = NULINK_HID_MAX_SIZE; h->init_buffer = nulink1_usb_init_buffer; h->xfer = nulink1_usb_xfer; break; } /* get the device version */ h->cmdsize = 4 * 5; int err = nulink_usb_version(h); if (err != ERROR_OK) { LOG_DEBUG("nulink_usb_version failed with cmdSize(4 * 5)"); h->cmdsize = 4 * 6; err = nulink_usb_version(h); if (err != ERROR_OK) LOG_DEBUG("nulink_usb_version failed with cmdSize(4 * 6)"); } /* SWD clock rate : 1MHz */ nulink_speed(h, 1000, false); /* get cpuid, so we can determine the max page size * start with a safe default */ h->max_mem_packet = (1 << 10); LOG_DEBUG("nulink_usb_open: we manually perform nulink_usb_reset"); nulink_usb_reset(h); *fd = h; free(target_serial); return ERROR_OK; error_open: nulink_usb_close(h); free(target_serial); return ERROR_FAIL; } struct hl_layout_api_s nulink_usb_layout_api = { .open = nulink_usb_open, .close = nulink_usb_close, .idcode = nulink_usb_idcode, .state = nulink_usb_state, .reset = nulink_usb_reset, .assert_srst = nulink_usb_assert_srst, .run = nulink_usb_run, .halt = nulink_usb_halt, .step = nulink_usb_step, .read_reg = nulink_usb_read_reg, .write_reg = nulink_usb_write_reg, .read_mem = nulink_usb_read_mem, .write_mem = nulink_usb_write_mem, .write_debug_reg = nulink_usb_write_debug_reg, .override_target = nulink_usb_override_target, .speed = nulink_speed, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/opendous.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * * * Copyright (C) 2009 by Cahya Wirawan <cahya@gmx.at> * * Based on opendous driver by Vladimir Fonov * * * * Copyright (C) 2009 by Vladimir Fonov <vladimir.fonov@gmai.com> * * Based on J-link driver by Juergen Stuber * * * * Copyright (C) 2007 by Juergen Stuber <juergen@jstuber.net> * * based on Dominic Rath's and Benedikt Sauter's usbprog.c * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/interface.h> #include <jtag/commands.h> #include "libusb_helper.h" #include <string.h> #include <time.h> #define OPENDOUS_MAX_VIDS_PIDS 4 /* define some probes with similar interface */ struct opendous_probe { const char *name; uint16_t VID[OPENDOUS_MAX_VIDS_PIDS]; uint16_t PID[OPENDOUS_MAX_VIDS_PIDS]; uint8_t READ_EP; uint8_t WRITE_EP; uint8_t CONTROL_TRANSFER; int BUFFERSIZE; }; static const struct opendous_probe opendous_probes[] = { {"usbprog-jtag", {0x1781, 0}, {0x0C63, 0}, 0x82, 0x02, 0x00, 510 }, {"opendous", {0x1781, 0x03EB, 0}, {0xC0C0, 0x204F, 0}, 0x81, 0x02, 0x00, 360 }, {"usbvlab", {0x16C0, 0}, {0x05DC, 0}, 0x81, 0x02, 0x01, 360 }, {NULL, {0x0000}, {0x0000}, 0x00, 0x00, 0x00, 0 } }; #define OPENDOUS_WRITE_ENDPOINT (opendous_probe->WRITE_EP) #define OPENDOUS_READ_ENDPOINT (opendous_probe->READ_EP) static unsigned int opendous_hw_jtag_version = 1; #define OPENDOUS_USB_TIMEOUT 1000 #define OPENDOUS_USB_BUFFER_SIZE (opendous_probe->BUFFERSIZE) #define OPENDOUS_IN_BUFFER_SIZE (OPENDOUS_USB_BUFFER_SIZE) #define OPENDOUS_OUT_BUFFER_SIZE (OPENDOUS_USB_BUFFER_SIZE) /* Global USB buffers */ static uint8_t *usb_in_buffer; static uint8_t *usb_out_buffer; /* Constants for OPENDOUS command */ #define OPENDOUS_MAX_SPEED 66 #define OPENDOUS_MAX_TAP_TRANSMIT ((opendous_probe->BUFFERSIZE)-10) #define OPENDOUS_MAX_INPUT_DATA (OPENDOUS_MAX_TAP_TRANSMIT*4) /* TAP */ #define OPENDOUS_TAP_BUFFER_SIZE 65536 struct pending_scan_result { int first; /* First bit position in tdo_buffer to read */ int length; /* Number of bits to read */ struct scan_command *command; /* Corresponding scan command */ uint8_t *buffer; }; static int pending_scan_results_length; static struct pending_scan_result *pending_scan_results_buffer; #define MAX_PENDING_SCAN_RESULTS (OPENDOUS_MAX_INPUT_DATA) /* JTAG usb commands */ #define JTAG_CMD_TAP_OUTPUT 0x0 #define JTAG_CMD_SET_TRST 0x1 #define JTAG_CMD_SET_SRST 0x2 #define JTAG_CMD_READ_INPUT 0x3 #define JTAG_CMD_TAP_OUTPUT_EMU 0x4 #define JTAG_CMD_SET_DELAY 0x5 #define JTAG_CMD_SET_SRST_TRST 0x6 #define JTAG_CMD_READ_CONFIG 0x7 /* usbvlab control transfer */ #define FUNC_START_BOOTLOADER 30 #define FUNC_WRITE_DATA 0x50 #define FUNC_READ_DATA 0x51 static char *opendous_type; static const struct opendous_probe *opendous_probe; /* External interface functions */ static int opendous_execute_queue(void); static int opendous_init(void); static int opendous_quit(void); /* Queue command functions */ static void opendous_end_state(tap_state_t state); static void opendous_state_move(void); static void opendous_path_move(int num_states, tap_state_t *path); static void opendous_runtest(int num_cycles); static void opendous_scan(int ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); static void opendous_reset(int trst, int srst); static void opendous_simple_command(uint8_t command, uint8_t _data); static int opendous_get_status(void); /* opendous tap buffer functions */ static void opendous_tap_init(void); static int opendous_tap_execute(void); static void opendous_tap_ensure_space(int scans, int bits); static void opendous_tap_append_step(int tms, int tdi); static void opendous_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command); /* opendous lowlevel functions */ struct opendous_jtag { struct libusb_device_handle *usb_handle; }; static struct opendous_jtag *opendous_usb_open(void); static void opendous_usb_close(struct opendous_jtag *opendous_jtag); static int opendous_usb_message(struct opendous_jtag *opendous_jtag, int out_length, int in_length); static int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length); static int opendous_usb_read(struct opendous_jtag *opendous_jtag); /* helper functions */ static int opendous_get_version_info(void); #ifdef _DEBUG_USB_COMMS_ static void opendous_debug_buffer(uint8_t *buffer, int length); #endif static struct opendous_jtag *opendous_jtag_handle; /***************************************************************************/ /* External interface implementation */ COMMAND_HANDLER(opendous_handle_opendous_type_command) { if (CMD_ARGC == 0) return ERROR_OK; /* only if the cable name wasn't overwritten by cmdline */ if (!opendous_type) { /* REVISIT first verify that it's listed in cables[] ... */ opendous_type = strdup(CMD_ARGV[0]); } /* REVISIT it's probably worth returning the current value ... */ return ERROR_OK; } COMMAND_HANDLER(opendous_handle_opendous_info_command) { if (opendous_get_version_info() == ERROR_OK) { /* attempt to get status */ opendous_get_status(); } return ERROR_OK; } COMMAND_HANDLER(opendous_handle_opendous_hw_jtag_command) { switch (CMD_ARGC) { case 0: command_print(CMD, "opendous hw jtag %i", opendous_hw_jtag_version); break; case 1: { int request_version = atoi(CMD_ARGV[0]); switch (request_version) { case 2: case 3: opendous_hw_jtag_version = request_version; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } break; } default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } static const struct command_registration opendous_command_handlers[] = { { .name = "opendous_info", .handler = &opendous_handle_opendous_info_command, .mode = COMMAND_EXEC, .help = "show opendous info", .usage = "", }, { .name = "opendous_hw_jtag", .handler = &opendous_handle_opendous_hw_jtag_command, .mode = COMMAND_EXEC, .help = "access opendous HW JTAG command version", .usage = "[2|3]", }, { .name = "opendous_type", .handler = &opendous_handle_opendous_type_command, .mode = COMMAND_CONFIG, .help = "set opendous type", .usage = "[usbvlab|usbprog-jtag|opendous]", }, COMMAND_REGISTRATION_DONE }; static struct jtag_interface opendous_interface = { .execute_queue = opendous_execute_queue, }; struct adapter_driver opendous_adapter_driver = { .name = "opendous", .transports = jtag_only, .commands = opendous_command_handlers, .init = opendous_init, .quit = opendous_quit, .jtag_ops = &opendous_interface, }; static int opendous_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; int scan_size; enum scan_type type; uint8_t *buffer; while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); if (cmd->cmd.runtest->end_state != -1) opendous_end_state(cmd->cmd.runtest->end_state); opendous_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); if (cmd->cmd.statemove->end_state != -1) opendous_end_state(cmd->cmd.statemove->end_state); opendous_state_move(); break; case JTAG_PATHMOVE: LOG_DEBUG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); opendous_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); break; case JTAG_SCAN: LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); if (cmd->cmd.scan->end_state != -1) opendous_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); LOG_DEBUG_IO("scan input, length = %d", scan_size); #ifdef _DEBUG_USB_COMMS_ opendous_debug_buffer(buffer, (scan_size + 7) / 8); #endif type = jtag_scan_type(cmd->cmd.scan); opendous_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); break; case JTAG_RESET: LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); opendous_tap_execute(); if (cmd->cmd.reset->trst == 1) tap_set_state(TAP_RESET); opendous_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_SLEEP: LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); opendous_tap_execute(); jtag_sleep(cmd->cmd.sleep->us); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } return opendous_tap_execute(); } static int opendous_init(void) { int check_cnt; const struct opendous_probe *cur_opendous_probe; cur_opendous_probe = opendous_probes; if (!opendous_type) { opendous_type = strdup("opendous"); LOG_WARNING("No opendous_type specified, using default 'opendous'"); } while (cur_opendous_probe->name) { if (strcmp(cur_opendous_probe->name, opendous_type) == 0) { opendous_probe = cur_opendous_probe; break; } cur_opendous_probe++; } if (!opendous_probe) { LOG_ERROR("No matching cable found for %s", opendous_type); return ERROR_JTAG_INIT_FAILED; } usb_in_buffer = malloc(opendous_probe->BUFFERSIZE); usb_out_buffer = malloc(opendous_probe->BUFFERSIZE); pending_scan_results_buffer = malloc( MAX_PENDING_SCAN_RESULTS * sizeof(*pending_scan_results_buffer)); opendous_jtag_handle = opendous_usb_open(); if (!opendous_jtag_handle) { LOG_ERROR("Cannot find opendous Interface! Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; } check_cnt = 0; while (check_cnt < 3) { if (opendous_get_version_info() == ERROR_OK) { /* attempt to get status */ opendous_get_status(); break; } check_cnt++; } LOG_INFO("opendous JTAG Interface ready"); opendous_reset(0, 0); opendous_tap_init(); return ERROR_OK; } static int opendous_quit(void) { opendous_usb_close(opendous_jtag_handle); free(usb_out_buffer); usb_out_buffer = NULL; free(usb_in_buffer); usb_in_buffer = NULL; free(pending_scan_results_buffer); pending_scan_results_buffer = NULL; free(opendous_type); opendous_type = NULL; return ERROR_OK; } /***************************************************************************/ /* Queue command implementations */ void opendous_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } /* Goes to the end state. */ void opendous_state_move(void) { int i; int tms = 0; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); uint8_t tms_scan_bits = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); for (i = 0; i < tms_scan_bits; i++) { tms = (tms_scan >> i) & 1; opendous_tap_append_step(tms, 0); } tap_set_state(tap_get_end_state()); } void opendous_path_move(int num_states, tap_state_t *path) { int i; for (i = 0; i < num_states; i++) { if (path[i] == tap_state_transition(tap_get_state(), false)) opendous_tap_append_step(0, 0); else if (path[i] == tap_state_transition(tap_get_state(), true)) opendous_tap_append_step(1, 0); else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(path[i])); exit(-1); } tap_set_state(path[i]); } tap_set_end_state(tap_get_state()); } void opendous_runtest(int num_cycles) { int i; tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { opendous_end_state(TAP_IDLE); opendous_state_move(); } /* execute num_cycles */ for (i = 0; i < num_cycles; i++) opendous_tap_append_step(0, 0); /* finish in end_state */ opendous_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) opendous_state_move(); } void opendous_scan(int ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) { tap_state_t saved_end_state; opendous_tap_ensure_space(1, scan_size + 8); saved_end_state = tap_get_end_state(); /* Move to appropriate scan state */ opendous_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); if (tap_get_state() != tap_get_end_state()) opendous_state_move(); opendous_end_state(saved_end_state); /* Scan */ opendous_tap_append_scan(scan_size, buffer, command); /* We are in Exit1, go to Pause */ opendous_tap_append_step(0, 0); tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) opendous_state_move(); } void opendous_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); /* Signals are active low */ #if 0 if (srst == 0) opendous_simple_command(JTAG_CMD_SET_SRST, 1); else if (srst == 1) opendous_simple_command(JTAG_CMD_SET_SRST, 0); if (trst == 0) opendous_simple_command(JTAG_CMD_SET_TRST, 1); else if (trst == 1) opendous_simple_command(JTAG_CMD_SET_TRST, 0); #endif srst = srst ? 0 : 1; trst = trst ? 0 : 2; opendous_simple_command(JTAG_CMD_SET_SRST_TRST, srst | trst); } void opendous_simple_command(uint8_t command, uint8_t _data) { int result; LOG_DEBUG_IO("0x%02x 0x%02x", command, _data); usb_out_buffer[0] = 2; usb_out_buffer[1] = 0; usb_out_buffer[2] = command; usb_out_buffer[3] = _data; result = opendous_usb_message(opendous_jtag_handle, 4, 1); if (result != 1) LOG_ERROR("opendous command 0x%02x failed (%d)", command, result); } int opendous_get_status(void) { return ERROR_OK; } static int opendous_get_version_info(void) { return ERROR_OK; } /***************************************************************************/ /* Estick tap functions */ static int tap_length; static uint8_t tms_buffer[OPENDOUS_TAP_BUFFER_SIZE]; static uint8_t tdo_buffer[OPENDOUS_TAP_BUFFER_SIZE]; static int last_tms; void opendous_tap_init(void) { tap_length = 0; pending_scan_results_length = 0; } void opendous_tap_ensure_space(int scans, int bits) { int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length; int available_bits = OPENDOUS_TAP_BUFFER_SIZE / 2 - tap_length; if ((scans > available_scans) || (bits > available_bits)) opendous_tap_execute(); } void opendous_tap_append_step(int tms, int tdi) { last_tms = tms; unsigned char _tms = tms ? 1 : 0; unsigned char _tdi = tdi ? 1 : 0; opendous_tap_ensure_space(0, 1); int tap_index = tap_length / 4; int bits = (tap_length % 4) * 2; if (tap_length < OPENDOUS_TAP_BUFFER_SIZE) { if (!bits) tms_buffer[tap_index] = 0; tms_buffer[tap_index] |= (_tdi << bits)|(_tms << (bits + 1)); tap_length++; } else LOG_ERROR("opendous_tap_append_step, overflow"); } void opendous_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command) { LOG_DEBUG_IO("append scan, length = %d", length); struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[pending_scan_results_length]; int i; pending_scan_result->first = tap_length; pending_scan_result->length = length; pending_scan_result->command = command; pending_scan_result->buffer = buffer; for (i = 0; i < length; i++) opendous_tap_append_step((i < length-1 ? 0 : 1), (buffer[i / 8] >> (i % 8)) & 1); pending_scan_results_length++; } /* Pad and send a tap sequence to the device, and receive the answer. * For the purpose of padding we assume that we are in idle or pause state. */ int opendous_tap_execute(void) { int byte_length; int i, j; int result; #ifdef _DEBUG_USB_COMMS_ int byte_length_out; #endif if (tap_length > 0) { /* memset(tdo_buffer,0,OPENDOUS_TAP_BUFFER_SIZE); */ /* LOG_INFO("OPENDOUS tap execute %d",tap_length); */ byte_length = (tap_length + 3) / 4; #ifdef _DEBUG_USB_COMMS_ byte_length_out = (tap_length + 7) / 8; LOG_DEBUG("opendous is sending %d bytes", byte_length); #endif for (j = 0, i = 0; j < byte_length;) { int receive; int transmit = byte_length - j; if (transmit > OPENDOUS_MAX_TAP_TRANSMIT) { transmit = OPENDOUS_MAX_TAP_TRANSMIT; receive = (OPENDOUS_MAX_TAP_TRANSMIT) / 2; usb_out_buffer[2] = JTAG_CMD_TAP_OUTPUT; } else { usb_out_buffer[2] = JTAG_CMD_TAP_OUTPUT | ((tap_length % 4) << 4); receive = (transmit + 1) / 2; } usb_out_buffer[0] = (transmit + 1) & 0xff; usb_out_buffer[1] = ((transmit + 1) >> 8) & 0xff; memmove(usb_out_buffer + 3, tms_buffer + j, transmit); result = opendous_usb_message(opendous_jtag_handle, 3 + transmit, receive); if (result != receive) { LOG_ERROR("opendous_tap_execute, wrong result %d, expected %d", result, receive); return ERROR_JTAG_QUEUE_FAILED; } memmove(tdo_buffer + i, usb_in_buffer, receive); i += receive; j += transmit; } #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("opendous tap result %d", byte_length_out); opendous_debug_buffer(tdo_buffer, byte_length_out); #endif /* LOG_INFO("eStick tap execute %d",tap_length); */ for (i = 0; i < pending_scan_results_length; i++) { struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[i]; uint8_t *buffer = pending_scan_result->buffer; int length = pending_scan_result->length; int first = pending_scan_result->first; struct scan_command *command = pending_scan_result->command; /* Copy to buffer */ buf_set_buf(tdo_buffer, first, buffer, 0, length); LOG_DEBUG_IO("pending scan result, length = %d", length); #ifdef _DEBUG_USB_COMMS_ opendous_debug_buffer(buffer, byte_length_out); #endif if (jtag_read_buffer(buffer, command) != ERROR_OK) { opendous_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } free(pending_scan_result->buffer); } opendous_tap_init(); } return ERROR_OK; } /*****************************************************************************/ /* Estick USB low-level functions */ struct opendous_jtag *opendous_usb_open(void) { struct opendous_jtag *result; struct libusb_device_handle *devh; if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, &devh, NULL) != ERROR_OK) return NULL; jtag_libusb_set_configuration(devh, 0); libusb_claim_interface(devh, 0); result = malloc(sizeof(*result)); result->usb_handle = devh; return result; } void opendous_usb_close(struct opendous_jtag *opendous_jtag) { jtag_libusb_close(opendous_jtag->usb_handle); free(opendous_jtag); } /* Send a message and receive the reply. */ int opendous_usb_message(struct opendous_jtag *opendous_jtag, int out_length, int in_length) { int result; result = opendous_usb_write(opendous_jtag, out_length); if (result == out_length) { result = opendous_usb_read(opendous_jtag); if (result == in_length) return result; else { LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", in_length, result); return -1; } } else { LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", out_length, result); return -1; } } /* Write data from out_buffer to USB. */ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length) { int result; if (out_length > OPENDOUS_OUT_BUFFER_SIZE) { LOG_ERROR("opendous_jtag_write illegal out_length=%d (max=%d)", out_length, OPENDOUS_OUT_BUFFER_SIZE); return -1; } #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("USB write begin"); #endif if (opendous_probe->CONTROL_TRANSFER) { result = jtag_libusb_control_transfer(opendous_jtag->usb_handle, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, FUNC_WRITE_DATA, 0, 0, (char *) usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT); } else { jtag_libusb_bulk_write(opendous_jtag->usb_handle, OPENDOUS_WRITE_ENDPOINT, (char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT, &result); } #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("USB write end: %d bytes", result); #endif LOG_DEBUG_IO("opendous_usb_write, out_length = %d, result = %d", out_length, result); #ifdef _DEBUG_USB_COMMS_ opendous_debug_buffer(usb_out_buffer, out_length); #endif return result; } /* Read data from USB into in_buffer. */ int opendous_usb_read(struct opendous_jtag *opendous_jtag) { #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("USB read begin"); #endif int result; if (opendous_probe->CONTROL_TRANSFER) { result = jtag_libusb_control_transfer(opendous_jtag->usb_handle, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, FUNC_READ_DATA, 0, 0, (char *) usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT); } else { jtag_libusb_bulk_read(opendous_jtag->usb_handle, OPENDOUS_READ_ENDPOINT, (char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT, &result); } #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("USB read end: %d bytes", result); #endif LOG_DEBUG_IO("opendous_usb_read, result = %d", result); #ifdef _DEBUG_USB_COMMS_ opendous_debug_buffer(usb_in_buffer, result); #endif return result; } #ifdef _DEBUG_USB_COMMS_ #define BYTES_PER_LINE 16 void opendous_debug_buffer(uint8_t *buffer, int length) { char line[8 + 3 * BYTES_PER_LINE + 1]; for (int i = 0; i < length; i += BYTES_PER_LINE) { int n = snprintf(line, 9, "%04x", i); for (int j = i; j < i + BYTES_PER_LINE && j < length; j++) n += snprintf(line + n, 4, " %02x", buffer[j]); LOG_DEBUG("%s", line); } } #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/openjtag.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /******************************************************************************* * Driver for OpenJTAG Project (www.openjtag.org) * * Compatible with libftdi drivers. * * * * Cypress CY7C65215 support * * Copyright (C) 2015 Vianney le Clément de Saint-Marcq, Essensium NV * * <vianney.leclement@essensium.com> * * * * Copyright (C) 2010 by Ivan Meleca <mileca@gmail.com> * * * * Copyright (C) 2013 by Ryan Corbin, GlueLogix Inc. <corbin.ryan@gmail.com> * * Updated to work with OpenOCD v0.7.0. Fixed libftdi read speed issue. * * * * Based on usb_blaster.c * * Copyright (C) 2009 Catalin Patulea * * Copyright (C) 2006 Kolja Waschk * * * * And jlink.c * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ /*************************************************************************** * Version 1.0 Tested on a MCBSTM32 board using a Cortex-M3 (stm32f103x), * * GDB and Eclipse under Linux (Ubuntu 10.04) * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/interface.h> #include <jtag/commands.h> #include "libusb_helper.h" static enum { OPENJTAG_VARIANT_STANDARD, OPENJTAG_VARIANT_CY7C65215, } openjtag_variant = OPENJTAG_VARIANT_STANDARD; static const char * const openjtag_variant_names[] = { "standard", "cy7c65215", NULL }; /* * OpenJTAG-OpenOCD state conversion */ typedef enum openjtag_tap_state { OPENJTAG_TAP_INVALID = -1, OPENJTAG_TAP_RESET = 0, OPENJTAG_TAP_IDLE = 1, OPENJTAG_TAP_SELECT_DR = 2, OPENJTAG_TAP_CAPTURE_DR = 3, OPENJTAG_TAP_SHIFT_DR = 4, OPENJTAG_TAP_EXIT1_DR = 5, OPENJTAG_TAP_PAUSE_DR = 6, OPENJTAG_TAP_EXIT2_DR = 7, OPENJTAG_TAP_UPDATE_DR = 8, OPENJTAG_TAP_SELECT_IR = 9, OPENJTAG_TAP_CAPURE_IR = 10, OPENJTAG_TAP_SHIFT_IR = 11, OPENJTAG_TAP_EXIT1_IR = 12, OPENJTAG_TAP_PAUSE_IR = 13, OPENJTAG_TAP_EXIT2_IR = 14, OPENJTAG_TAP_UPDATE_IR = 15, } openjtag_tap_state_t; /* OPENJTAG access library includes */ #include "libftdi_helper.h" /* OpenJTAG vid/pid */ static uint16_t openjtag_vid = 0x0403; static uint16_t openjtag_pid = 0x6001; static char *openjtag_device_desc; static struct ftdi_context ftdic; #define OPENJTAG_BUFFER_SIZE 504 #define OPENJTAG_MAX_PENDING_RESULTS 256 struct openjtag_scan_result { uint32_t bits; /* Length in bits*/ struct scan_command *command; /* Corresponding scan command */ uint8_t *buffer; }; /* USB RX/TX buffers */ static int usb_tx_buf_offs; static uint8_t usb_tx_buf[OPENJTAG_BUFFER_SIZE]; static uint32_t usb_rx_buf_len; static uint8_t usb_rx_buf[OPENJTAG_BUFFER_SIZE]; /* Pending readings */ static struct openjtag_scan_result openjtag_scan_result_buffer[OPENJTAG_MAX_PENDING_RESULTS]; static int openjtag_scan_result_count; static struct libusb_device_handle *usbh; /* CY7C65215 model only */ #define CY7C65215_JTAG_REQUEST 0x40 /* bmRequestType: vendor host-to-device */ #define CY7C65215_JTAG_ENABLE 0xD0 /* bRequest: enable JTAG */ #define CY7C65215_JTAG_DISABLE 0xD1 /* bRequest: disable JTAG */ #define CY7C65215_JTAG_READ 0xD2 /* bRequest: read buffer */ #define CY7C65215_JTAG_WRITE 0xD3 /* bRequest: write buffer */ #define CY7C65215_USB_TIMEOUT 100 static const uint16_t cy7c65215_vids[] = {0x04b4, 0}; static const uint16_t cy7c65215_pids[] = {0x0007, 0}; #define CY7C65215_JTAG_CLASS 0xff #define CY7C65215_JTAG_SUBCLASS 0x04 static unsigned int ep_in, ep_out; #ifdef _DEBUG_USB_COMMS_ #define DEBUG_TYPE_READ 0 #define DEBUG_TYPE_WRITE 1 #define DEBUG_TYPE_OCD_READ 2 #define DEBUG_TYPE_BUFFER 3 #define LINE_LEN 16 static void openjtag_debug_buffer(uint8_t *buffer, int length, uint8_t type) { char line[128]; char s[4]; int i; int j; switch (type) { case DEBUG_TYPE_READ: sprintf(line, "USB READ %d bytes", length); break; case DEBUG_TYPE_WRITE: sprintf(line, "USB WRITE %d bytes", length); break; case DEBUG_TYPE_OCD_READ: sprintf(line, "TO OpenOCD %d bytes", length); break; case DEBUG_TYPE_BUFFER: sprintf(line, "Buffer %d bytes", length); break; } LOG_DEBUG("%s", line); for (i = 0; i < length; i += LINE_LEN) { switch (type) { case DEBUG_TYPE_READ: sprintf(line, "USB READ: %04x", i); break; case DEBUG_TYPE_WRITE: sprintf(line, "USB WRITE: %04x", i); break; case DEBUG_TYPE_OCD_READ: sprintf(line, "TO OpenOCD: %04x", i); break; case DEBUG_TYPE_BUFFER: sprintf(line, "BUFFER: %04x", i); break; } for (j = i; j < i + LINE_LEN && j < length; j++) { sprintf(s, " %02x", buffer[j]); strcat(line, s); } LOG_DEBUG("%s", line); } } #endif static int8_t openjtag_get_tap_state(int8_t state) { switch (state) { case TAP_DREXIT2: return OPENJTAG_TAP_EXIT2_DR; case TAP_DREXIT1: return OPENJTAG_TAP_EXIT1_DR; case TAP_DRSHIFT: return OPENJTAG_TAP_SHIFT_DR; case TAP_DRPAUSE: return OPENJTAG_TAP_PAUSE_DR; case TAP_IRSELECT: return OPENJTAG_TAP_SELECT_IR; case TAP_DRUPDATE: return OPENJTAG_TAP_UPDATE_DR; case TAP_DRCAPTURE: return OPENJTAG_TAP_CAPTURE_DR; case TAP_DRSELECT: return OPENJTAG_TAP_SELECT_DR; case TAP_IREXIT2: return OPENJTAG_TAP_EXIT2_IR; case TAP_IREXIT1: return OPENJTAG_TAP_EXIT1_IR; case TAP_IRSHIFT: return OPENJTAG_TAP_SHIFT_IR; case TAP_IRPAUSE: return OPENJTAG_TAP_PAUSE_IR; case TAP_IDLE: return OPENJTAG_TAP_IDLE; case TAP_IRUPDATE: return OPENJTAG_TAP_UPDATE_IR; case TAP_IRCAPTURE: return OPENJTAG_TAP_CAPURE_IR; case TAP_RESET: return OPENJTAG_TAP_RESET; case TAP_INVALID: default: return OPENJTAG_TAP_INVALID; } } static int openjtag_buf_write_standard( uint8_t *buf, int size, uint32_t *bytes_written) { int retval; #ifdef _DEBUG_USB_COMMS_ openjtag_debug_buffer(buf, size, DEBUG_TYPE_WRITE); #endif retval = ftdi_write_data(&ftdic, buf, size); if (retval < 0) { *bytes_written = 0; LOG_ERROR("ftdi_write_data: %s", ftdi_get_error_string(&ftdic)); return ERROR_JTAG_DEVICE_ERROR; } *bytes_written = retval; return ERROR_OK; } static int openjtag_buf_write_cy7c65215( uint8_t *buf, int size, uint32_t *bytes_written) { int ret; #ifdef _DEBUG_USB_COMMS_ openjtag_debug_buffer(buf, size, DEBUG_TYPE_WRITE); #endif if (size == 0) { *bytes_written = 0; return ERROR_OK; } ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST, CY7C65215_JTAG_WRITE, size, 0, NULL, 0, CY7C65215_USB_TIMEOUT); if (ret < 0) { LOG_ERROR("vendor command failed, error %d", ret); return ERROR_JTAG_DEVICE_ERROR; } if (jtag_libusb_bulk_write(usbh, ep_out, (char *)buf, size, CY7C65215_USB_TIMEOUT, &ret)) { LOG_ERROR("bulk write failed, error"); return ERROR_JTAG_DEVICE_ERROR; } *bytes_written = ret; return ERROR_OK; } static int openjtag_buf_write( uint8_t *buf, int size, uint32_t *bytes_written) { switch (openjtag_variant) { case OPENJTAG_VARIANT_CY7C65215: return openjtag_buf_write_cy7c65215(buf, size, bytes_written); default: return openjtag_buf_write_standard(buf, size, bytes_written); } } static int openjtag_buf_read_standard( uint8_t *buf, uint32_t qty, uint32_t *bytes_read) { int retval; int timeout = 5; *bytes_read = 0; while ((*bytes_read < qty) && timeout--) { retval = ftdi_read_data(&ftdic, buf + *bytes_read, qty - *bytes_read); if (retval < 0) { *bytes_read = 0; LOG_DEBUG_IO("ftdi_read_data: %s", ftdi_get_error_string(&ftdic)); return ERROR_JTAG_DEVICE_ERROR; } *bytes_read += retval; } #ifdef _DEBUG_USB_COMMS_ openjtag_debug_buffer(buf, *bytes_read, DEBUG_TYPE_READ); #endif return ERROR_OK; } static int openjtag_buf_read_cy7c65215( uint8_t *buf, uint32_t qty, uint32_t *bytes_read) { int ret; if (qty == 0) { *bytes_read = 0; goto out; } ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST, CY7C65215_JTAG_READ, qty, 0, NULL, 0, CY7C65215_USB_TIMEOUT); if (ret < 0) { LOG_ERROR("vendor command failed, error %d", ret); return ERROR_JTAG_DEVICE_ERROR; } if (jtag_libusb_bulk_read(usbh, ep_in, (char *)buf, qty, CY7C65215_USB_TIMEOUT, &ret)) { LOG_ERROR("bulk read failed, error"); return ERROR_JTAG_DEVICE_ERROR; } *bytes_read = ret; out: #ifdef _DEBUG_USB_COMMS_ openjtag_debug_buffer(buf, *bytes_read, DEBUG_TYPE_READ); #endif return ERROR_OK; } static int openjtag_buf_read(uint8_t *buf, uint32_t qty, uint32_t *bytes_read) { switch (openjtag_variant) { case OPENJTAG_VARIANT_CY7C65215: return openjtag_buf_read_cy7c65215(buf, qty, bytes_read); default: return openjtag_buf_read_standard(buf, qty, bytes_read); } } static int openjtag_sendcommand(uint8_t cmd) { uint32_t written; return openjtag_buf_write(&cmd, 1, &written); } static int openjtag_speed(int speed) { int clockcmd; switch (speed) { case 48000: clockcmd = 0x00; break; case 24000: clockcmd = 0x20; break; case 12000: clockcmd = 0x40; break; case 6000: clockcmd = 0x60; break; case 3000: clockcmd = 0x80; break; case 1500: clockcmd = 0xA0; break; case 750: clockcmd = 0xC0; break; case 375: clockcmd = 0xE0; break; default: clockcmd = 0xE0; LOG_WARNING("adapter speed not recognized, reverting to 375 kHz"); break; } openjtag_sendcommand(clockcmd); return ERROR_OK; } static int openjtag_init_standard(void) { uint8_t latency_timer; /* Open by device description */ if (!openjtag_device_desc) { LOG_WARNING("no openjtag device description specified, " "using default 'Open JTAG Project'"); openjtag_device_desc = "Open JTAG Project"; } if (ftdi_init(&ftdic) < 0) return ERROR_JTAG_INIT_FAILED; /* context, vendor id, product id, description, serial id */ if (ftdi_usb_open_desc(&ftdic, openjtag_vid, openjtag_pid, openjtag_device_desc, NULL) < 0) { LOG_ERROR("unable to open ftdi device: %s", ftdic.error_str); return ERROR_JTAG_INIT_FAILED; } if (ftdi_usb_reset(&ftdic) < 0) { LOG_ERROR("unable to reset ftdi device"); return ERROR_JTAG_INIT_FAILED; } if (ftdi_set_latency_timer(&ftdic, 2) < 0) { LOG_ERROR("unable to set latency timer"); return ERROR_JTAG_INIT_FAILED; } if (ftdi_get_latency_timer(&ftdic, &latency_timer) < 0) { LOG_ERROR("unable to get latency timer"); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("current latency timer: %u", latency_timer); ftdi_disable_bitbang(&ftdic); /* was (3000000 / 4) with a comment about a bug in libftdi when using high baudrate */ if (ftdi_set_baudrate(&ftdic, 3000000) < 0) { LOG_ERROR("Can't set baud rate to max: %s", ftdi_get_error_string(&ftdic)); return ERROR_JTAG_DEVICE_ERROR; } if (ftdi_tcioflush(&ftdic) < 0) { LOG_ERROR("ftdi flush: %s", ftdic.error_str); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int openjtag_init_cy7c65215(void) { int ret; usbh = NULL; ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, &usbh, NULL); if (ret != ERROR_OK) { LOG_ERROR("unable to open cy7c65215 device"); goto err; } ret = jtag_libusb_choose_interface(usbh, &ep_in, &ep_out, CY7C65215_JTAG_CLASS, CY7C65215_JTAG_SUBCLASS, -1, LIBUSB_TRANSFER_TYPE_BULK); if (ret != ERROR_OK) { LOG_ERROR("unable to claim JTAG interface"); goto err; } ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST, CY7C65215_JTAG_ENABLE, 0, 0, NULL, 0, CY7C65215_USB_TIMEOUT); if (ret < 0) { LOG_ERROR("could not enable JTAG module"); goto err; } return ERROR_OK; err: if (usbh) jtag_libusb_close(usbh); return ERROR_JTAG_INIT_FAILED; } static int openjtag_init(void) { int ret; usb_tx_buf_offs = 0; usb_rx_buf_len = 0; openjtag_scan_result_count = 0; switch (openjtag_variant) { case OPENJTAG_VARIANT_CY7C65215: ret = openjtag_init_cy7c65215(); break; default: ret = openjtag_init_standard(); } if (ret != ERROR_OK) return ret; openjtag_speed(375); /* Start at slowest adapter speed */ openjtag_sendcommand(0x75); /* MSB */ return ERROR_OK; } static int openjtag_quit_standard(void) { ftdi_usb_close(&ftdic); ftdi_deinit(&ftdic); return ERROR_OK; } static int openjtag_quit_cy7c65215(void) { int ret; ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST, CY7C65215_JTAG_DISABLE, 0, 0, NULL, 0, CY7C65215_USB_TIMEOUT); if (ret < 0) LOG_WARNING("could not disable JTAG module"); jtag_libusb_close(usbh); return ERROR_OK; } static int openjtag_quit(void) { switch (openjtag_variant) { case OPENJTAG_VARIANT_CY7C65215: return openjtag_quit_cy7c65215(); default: return openjtag_quit_standard(); } } static void openjtag_write_tap_buffer(void) { uint32_t written; openjtag_buf_write(usb_tx_buf, usb_tx_buf_offs, &written); openjtag_buf_read(usb_rx_buf, usb_tx_buf_offs, &usb_rx_buf_len); usb_tx_buf_offs = 0; } static int openjtag_execute_tap_queue(void) { openjtag_write_tap_buffer(); int res_count = 0; if (openjtag_scan_result_count && usb_rx_buf_len) { int count; int rx_offs = 0; int len; /* for every pending result */ while (res_count < openjtag_scan_result_count) { /* get sent bits */ len = openjtag_scan_result_buffer[res_count].bits; count = 0; uint8_t *buffer = openjtag_scan_result_buffer[res_count].buffer; while (len > 0) { if (len <= 8 && openjtag_variant != OPENJTAG_VARIANT_CY7C65215) { LOG_DEBUG_IO("bits < 8 buf = 0x%X, will be 0x%X", usb_rx_buf[rx_offs], usb_rx_buf[rx_offs] >> (8 - len)); buffer[count] = usb_rx_buf[rx_offs] >> (8 - len); len = 0; } else { buffer[count] = usb_rx_buf[rx_offs]; len -= 8; } rx_offs++; count++; } #ifdef _DEBUG_USB_COMMS_ openjtag_debug_buffer(buffer, DIV_ROUND_UP(openjtag_scan_result_buffer[res_count].bits, 8), DEBUG_TYPE_OCD_READ); #endif jtag_read_buffer(buffer, openjtag_scan_result_buffer[res_count].command); free(openjtag_scan_result_buffer[res_count].buffer); res_count++; } } openjtag_scan_result_count = 0; return ERROR_OK; } static void openjtag_add_byte(char buf) { if (usb_tx_buf_offs == OPENJTAG_BUFFER_SIZE) { LOG_DEBUG_IO("Forcing execute_tap_queue"); LOG_DEBUG_IO("TX Buff offs=%d", usb_tx_buf_offs); openjtag_execute_tap_queue(); } usb_tx_buf[usb_tx_buf_offs] = buf; usb_tx_buf_offs++; } static void openjtag_add_scan(uint8_t *buffer, int length, struct scan_command *scan_cmd) { /* Ensure space to send long chains */ /* We add two byte for each eight (or less) bits, one for command, one for data */ if (usb_tx_buf_offs + (DIV_ROUND_UP(length, 8) * 2) >= OPENJTAG_BUFFER_SIZE) { LOG_DEBUG_IO("Forcing execute_tap_queue from scan"); LOG_DEBUG_IO("TX Buff offs=%d len=%d", usb_tx_buf_offs, DIV_ROUND_UP(length, 8) * 2); openjtag_execute_tap_queue(); } openjtag_scan_result_buffer[openjtag_scan_result_count].bits = length; openjtag_scan_result_buffer[openjtag_scan_result_count].command = scan_cmd; openjtag_scan_result_buffer[openjtag_scan_result_count].buffer = buffer; uint8_t command; uint8_t bits; int count = 0; while (length) { /* write command */ command = 6; /* last bits? */ if (length <= 8) { /* tms high */ command |= (1 << 4); /* bits to transfer */ bits = (length - 1); command |= bits << 5; length = 0; } else { /* whole byte */ /* bits to transfer */ command |= (7 << 5); length -= 8; } openjtag_add_byte(command); openjtag_add_byte(buffer[count]); count++; } openjtag_scan_result_count++; } static void openjtag_execute_reset(struct jtag_command *cmd) { LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); uint8_t buf = 0x00; if (cmd->cmd.reset->trst) { buf = 0x03; } else { buf |= 0x04; buf |= 0x05 << 4; } openjtag_add_byte(buf); } static void openjtag_execute_sleep(struct jtag_command *cmd) { jtag_sleep(cmd->cmd.sleep->us); } static void openjtag_set_state(uint8_t openocd_state) { uint8_t state = openjtag_get_tap_state(openocd_state); uint8_t buf = 0; buf = 0x01; buf |= state << 4; openjtag_add_byte(buf); } static void openjtag_execute_statemove(struct jtag_command *cmd) { LOG_DEBUG_IO("state move to %i", cmd->cmd.statemove->end_state); tap_set_end_state(cmd->cmd.statemove->end_state); openjtag_set_state(cmd->cmd.statemove->end_state); tap_set_state(tap_get_end_state()); } static void openjtag_execute_scan(struct jtag_command *cmd) { int scan_size, old_state; uint8_t *buffer; LOG_DEBUG_IO("scan ends in %s", tap_state_name(cmd->cmd.scan->end_state)); /* get scan info */ tap_set_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); #ifdef _DEBUG_USB_COMMS_ openjtag_debug_buffer(buffer, (scan_size + 7) / 8, DEBUG_TYPE_BUFFER); #endif /* set state */ old_state = tap_get_end_state(); openjtag_set_state(cmd->cmd.scan->ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); tap_set_state(cmd->cmd.scan->ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); tap_set_end_state(old_state); openjtag_add_scan(buffer, scan_size, cmd->cmd.scan); openjtag_set_state(cmd->cmd.scan->ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); tap_set_state(cmd->cmd.scan->ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) { openjtag_set_state(tap_get_end_state()); tap_set_state(tap_get_end_state()); } } static void openjtag_execute_runtest(struct jtag_command *cmd) { tap_state_t end_state = cmd->cmd.runtest->end_state; tap_set_end_state(end_state); /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { openjtag_set_state(TAP_IDLE); tap_set_state(TAP_IDLE); } if (openjtag_variant != OPENJTAG_VARIANT_CY7C65215 || cmd->cmd.runtest->num_cycles) { uint8_t command; int cycles = cmd->cmd.runtest->num_cycles; do { command = 7; command |= (((cycles > 16 ? 16 : cycles) - 1) & 0x0F) << 4; openjtag_add_byte(command); cycles -= 16; } while (cycles > 0); } tap_set_end_state(end_state); if (tap_get_end_state() != tap_get_state()) { openjtag_set_state(end_state); tap_set_state(end_state); } } static void openjtag_execute_command(struct jtag_command *cmd) { LOG_DEBUG_IO("openjtag_execute_command %i", cmd->type); switch (cmd->type) { case JTAG_RESET: openjtag_execute_reset(cmd); break; case JTAG_SLEEP: openjtag_execute_sleep(cmd); break; case JTAG_TLR_RESET: openjtag_execute_statemove(cmd); break; case JTAG_SCAN: openjtag_execute_scan(cmd); break; case JTAG_RUNTEST: openjtag_execute_runtest(cmd); break; case JTAG_PATHMOVE: /* jlink_execute_pathmove(cmd); break; */ default: LOG_ERROR("BUG: unknown Open JTAG command type encountered"); exit(-1); } } static int openjtag_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; while (cmd) { openjtag_execute_command(cmd); cmd = cmd->next; } return openjtag_execute_tap_queue(); } static int openjtag_speed_div(int speed, int *khz) { *khz = speed; return ERROR_OK; } static int openjtag_khz(int khz, int *jtag_speed) { if (khz >= 48000) *jtag_speed = 48000; else if (khz >= 24000) *jtag_speed = 24000; else if (khz >= 12000) *jtag_speed = 12000; else if (khz >= 6000) *jtag_speed = 6000; else if (khz >= 3000) *jtag_speed = 3000; else if (khz >= 1500) *jtag_speed = 1500; else if (khz >= 750) *jtag_speed = 750; else *jtag_speed = 375; return ERROR_OK; } COMMAND_HANDLER(openjtag_handle_device_desc_command) { if (CMD_ARGC == 1) openjtag_device_desc = strdup(CMD_ARGV[0]); else LOG_ERROR("require exactly one argument to " "openjtag_device_desc <description>"); return ERROR_OK; } COMMAND_HANDLER(openjtag_handle_variant_command) { if (CMD_ARGC == 1) { const char * const *name = openjtag_variant_names; int variant = 0; for (; *name; name++, variant++) { if (strcasecmp(CMD_ARGV[0], *name) == 0) { openjtag_variant = variant; return ERROR_OK; } } LOG_ERROR("unknown openjtag variant '%s'", CMD_ARGV[0]); } else { LOG_ERROR("require exactly one argument to " "openjtag_variant <variant>"); } return ERROR_OK; } static const struct command_registration openjtag_subcommand_handlers[] = { { .name = "device_desc", .handler = openjtag_handle_device_desc_command, .mode = COMMAND_CONFIG, .help = "set the USB device description of the OpenJTAG", .usage = "description-string", }, { .name = "variant", .handler = openjtag_handle_variant_command, .mode = COMMAND_CONFIG, .help = "set the OpenJTAG variant", .usage = "variant-string", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration openjtag_command_handlers[] = { { .name = "openjtag", .mode = COMMAND_ANY, .help = "perform openjtag management", .chain = openjtag_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static struct jtag_interface openjtag_interface = { .execute_queue = openjtag_execute_queue, }; struct adapter_driver openjtag_adapter_driver = { .name = "openjtag", .transports = jtag_only, .commands = openjtag_command_handlers, .init = openjtag_init, .quit = openjtag_quit, .speed = openjtag_speed, .khz = openjtag_khz, .speed_div = openjtag_speed_div, .jtag_ops = &openjtag_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/osbdm.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2012 by Jan Dakinevich * * jan.dakinevich@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include <helper/log.h> #include <helper/binarybuffer.h> #include <helper/command.h> #include <jtag/interface.h> #include "libusb_helper.h" struct sequence { int len; void *tms; void *tdo; const void *tdi; struct sequence *next; }; struct queue { struct sequence *head; struct sequence *tail; }; static struct sequence *queue_add_tail(struct queue *queue, int len) { if (len <= 0) { LOG_ERROR("BUG: sequences with zero length are not allowed"); return NULL; } struct sequence *next; next = malloc(sizeof(*next)); if (next) { next->tms = calloc(1, DIV_ROUND_UP(len, 8)); if (next->tms) { next->len = len; next->tdo = NULL; next->tdi = NULL; next->next = NULL; if (!queue->head) { /* Queue is empty at the moment */ queue->head = next; } else { /* Queue already contains at least one sequence */ queue->tail->next = next; } queue->tail = next; } else { free(next); next = NULL; } } if (!next) LOG_ERROR("Not enough memory"); return next; } static void queue_drop_head(struct queue *queue) { struct sequence *head = queue->head->next; /* New head */ free(queue->head->tms); free(queue->head); queue->head = head; } static void queue_free(struct queue *queue) { if (queue) { while (queue->head) queue_drop_head(queue); free(queue); } } static struct queue *queue_alloc(void) { struct queue *queue = malloc(sizeof(*queue)); if (queue) queue->head = NULL; else LOG_ERROR("Not enough memory"); return queue; } /* Size of usb communication buffer */ #define OSBDM_USB_BUFSIZE 64 /* Timeout for USB transfer, ms */ #define OSBDM_USB_TIMEOUT 1000 /* Write end point */ #define OSBDM_USB_EP_WRITE 0x01 /* Read end point */ #define OSBDM_USB_EP_READ 0x82 /* Initialize OSBDM device */ #define OSBDM_CMD_INIT 0x11 /* Execute special, not-BDM command. But only this * command is used for JTAG operation */ #define OSBDM_CMD_SPECIAL 0x27 /* Execute JTAG swap (tms/tdi -> tdo) */ #define OSBDM_CMD_SPECIAL_SWAP 0x05 /* Reset control */ #define OSBDM_CMD_SPECIAL_SRST 0x01 /* Maximum bit-length in one swap */ #define OSBDM_SWAP_MAX (((OSBDM_USB_BUFSIZE - 6) / 5) * 16) /* Lists of valid VID/PID pairs */ static const uint16_t osbdm_vid[] = { 0x15a2, 0x15a2, 0x15a2, 0 }; static const uint16_t osbdm_pid[] = { 0x0042, 0x0058, 0x005e, 0 }; struct osbdm { struct libusb_device_handle *devh; /* USB handle */ uint8_t buffer[OSBDM_USB_BUFSIZE]; /* Data to send and receive */ int count; /* Count data to send and to read */ }; /* osbdm instance */ static struct osbdm osbdm_context; static int osbdm_send_and_recv(struct osbdm *osbdm) { /* Send request */ int count, ret; ret = jtag_libusb_bulk_write(osbdm->devh, OSBDM_USB_EP_WRITE, (char *)osbdm->buffer, osbdm->count, OSBDM_USB_TIMEOUT, &count); if (ret || count != osbdm->count) { LOG_ERROR("OSBDM communication error: can't write"); return ERROR_FAIL; } /* Save command code for next checking */ uint8_t cmd_saved = osbdm->buffer[0]; /* Reading answer */ ret = jtag_libusb_bulk_read(osbdm->devh, OSBDM_USB_EP_READ, (char *)osbdm->buffer, OSBDM_USB_BUFSIZE, OSBDM_USB_TIMEOUT, &osbdm->count); /* Now perform basic checks for data sent by BDM device */ if (ret) { LOG_ERROR("OSBDM communication error: can't read"); return ERROR_FAIL; } if (osbdm->count < 2) { LOG_ERROR("OSBDM communication error: reply too small"); return ERROR_FAIL; } if (osbdm->count != osbdm->buffer[1]) { LOG_ERROR("OSBDM communication error: reply size mismatch"); return ERROR_FAIL; } if (cmd_saved != osbdm->buffer[0]) { LOG_ERROR("OSBDM communication error: reply command mismatch"); return ERROR_FAIL; } return ERROR_OK; } static int osbdm_srst(struct osbdm *osbdm, int srst) { osbdm->count = 0; (void)memset(osbdm->buffer, 0, OSBDM_USB_BUFSIZE); /* Composing request */ osbdm->buffer[osbdm->count++] = OSBDM_CMD_SPECIAL; /* Command */ osbdm->buffer[osbdm->count++] = OSBDM_CMD_SPECIAL_SRST; /* Subcommand */ /* Length in bytes - not used */ osbdm->buffer[osbdm->count++] = 0; osbdm->buffer[osbdm->count++] = 0; /* SRST state */ osbdm->buffer[osbdm->count++] = (srst ? 0 : 0x08); /* Sending data */ if (osbdm_send_and_recv(osbdm) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int osbdm_swap(struct osbdm *osbdm, void *tms, void *tdi, void *tdo, int length) { if (length > OSBDM_SWAP_MAX) { LOG_ERROR("BUG: bit sequence too long"); return ERROR_FAIL; } if (length <= 0) { LOG_ERROR("BUG: bit sequence equal or less than 0"); return ERROR_FAIL; } int swap_count = DIV_ROUND_UP(length, 16); /* cleanup */ osbdm->count = 0; (void)memset(osbdm->buffer, 0, OSBDM_USB_BUFSIZE); /* Composing request */ osbdm->buffer[osbdm->count++] = OSBDM_CMD_SPECIAL; /* Command */ osbdm->buffer[osbdm->count++] = OSBDM_CMD_SPECIAL_SWAP; /* Subcommand */ /* Length in bytes - not used */ osbdm->buffer[osbdm->count++] = 0; osbdm->buffer[osbdm->count++] = 0; /* Swap count */ osbdm->buffer[osbdm->count++] = 0; osbdm->buffer[osbdm->count++] = (uint8_t)swap_count; for (int bit_idx = 0; bit_idx < length; ) { /* Bit count in swap */ int bit_count = length - bit_idx; if (bit_count > 16) bit_count = 16; osbdm->buffer[osbdm->count++] = (uint8_t)bit_count; /* Copying TMS and TDI data to output buffer */ uint32_t tms_data = buf_get_u32(tms, bit_idx, bit_count); uint32_t tdi_data = buf_get_u32(tdi, bit_idx, bit_count); osbdm->buffer[osbdm->count++] = (uint8_t)(tdi_data >> 8); osbdm->buffer[osbdm->count++] = (uint8_t)tdi_data; osbdm->buffer[osbdm->count++] = (uint8_t)(tms_data >> 8); osbdm->buffer[osbdm->count++] = (uint8_t)tms_data; /* Next bit offset */ bit_idx += bit_count; } assert(osbdm->count <= OSBDM_USB_BUFSIZE); /* Sending data */ if (osbdm_send_and_recv(osbdm) != ERROR_OK) return ERROR_FAIL; /* Extra check */ if (((osbdm->buffer[2] << 8) | osbdm->buffer[3]) != 2 * swap_count) { LOG_ERROR("OSBDM communication error: invalid swap command reply"); return ERROR_FAIL; } /* Copy TDO response */ uint8_t *buffer = osbdm->buffer + 4; for (int bit_idx = 0; bit_idx < length; ) { int bit_count = length - bit_idx; if (bit_count > 16) bit_count = 16; /* Prepare data */ uint32_t tdo_data = 0; tdo_data |= (*buffer++) << 8; tdo_data |= (*buffer++); tdo_data >>= (16 - bit_count); /* Copy TDO to return */ buf_set_u32(tdo, bit_idx, bit_count, tdo_data); bit_idx += bit_count; } return ERROR_OK; } static int osbdm_flush(struct osbdm *osbdm, struct queue *queue) { uint8_t tms[DIV_ROUND_UP(OSBDM_SWAP_MAX, 8)]; uint8_t tdi[DIV_ROUND_UP(OSBDM_SWAP_MAX, 8)]; uint8_t tdo[DIV_ROUND_UP(OSBDM_SWAP_MAX, 8)]; int seq_back_len = 0; while (queue->head) { (void)memset(tms, 0, sizeof(tms)); (void)memset(tdi, 0, sizeof(tdi)); (void)memset(tdo, 0, sizeof(tdo)); int seq_len; int swap_len; struct sequence *seq; /* Copy from queue to tms/tdi streams */ seq = queue->head; seq_len = seq_back_len; swap_len = 0; while (seq && swap_len != OSBDM_SWAP_MAX) { /* Count bit for copy at this iteration. * len should fit into remaining space * in tms/tdo bitstreams */ int len = seq->len - seq_len; if (len > OSBDM_SWAP_MAX - swap_len) len = OSBDM_SWAP_MAX - swap_len; /* Set tms data */ buf_set_buf(seq->tms, seq_len, tms, swap_len, len); /* Set tdi data if they exists */ if (seq->tdi) buf_set_buf(seq->tdi, seq_len, tdi, swap_len, len); swap_len += len; seq_len += len; if (seq_len == seq->len) { seq = seq->next; /* Move to next sequence */ seq_len = 0; } } if (osbdm_swap(osbdm, tms, tdi, tdo, swap_len)) return ERROR_FAIL; /* Copy from tdo stream to queue */ for (int swap_back_len = 0; swap_back_len < swap_len; ) { int len = queue->head->len - seq_back_len; if (len > swap_len - swap_back_len) len = swap_len - swap_back_len; if (queue->head->tdo) buf_set_buf(tdo, swap_back_len, queue->head->tdo, seq_back_len, len); swap_back_len += len; seq_back_len += len; if (seq_back_len == queue->head->len) { queue_drop_head(queue); seq_back_len = 0; } } } return ERROR_OK; } /* Basic operation for opening USB device */ static int osbdm_open(struct osbdm *osbdm) { (void)memset(osbdm, 0, sizeof(*osbdm)); if (jtag_libusb_open(osbdm_vid, osbdm_pid, &osbdm->devh, NULL) != ERROR_OK) return ERROR_FAIL; if (libusb_claim_interface(osbdm->devh, 0) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int osbdm_quit(void) { jtag_libusb_close(osbdm_context.devh); return ERROR_OK; } static int osbdm_add_pathmove( struct queue *queue, tap_state_t *path, int num_states) { assert(num_states <= 32); struct sequence *next = queue_add_tail(queue, num_states); if (!next) { LOG_ERROR("BUG: can't allocate bit sequence"); return ERROR_FAIL; } uint32_t tms = 0; for (int i = 0; i < num_states; i++) { if (tap_state_transition(tap_get_state(), 1) == path[i]) { tms |= (1 << i); } else if (tap_state_transition(tap_get_state(), 0) == path[i]) { tms &= ~(1 << i); /* This line not so needed */ } else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP state transition", tap_state_name(tap_get_state()), tap_state_name(path[i])); return ERROR_FAIL; } tap_set_state(path[i]); } buf_set_u32(next->tms, 0, num_states, tms); tap_set_end_state(tap_get_state()); return ERROR_OK; } static int osbdm_add_statemove( struct queue *queue, tap_state_t new_state, int skip_first) { int len = 0; int tms = 0; tap_set_end_state(new_state); if (tap_get_end_state() == TAP_RESET) { /* Ignore current state */ tms = 0xff; len = 5; } else if (tap_get_state() != tap_get_end_state()) { tms = tap_get_tms_path(tap_get_state(), new_state); len = tap_get_tms_path_len(tap_get_state(), new_state); } if (len && skip_first) { len--; tms >>= 1; } if (len) { struct sequence *next = queue_add_tail(queue, len); if (!next) { LOG_ERROR("BUG: can't allocate bit sequence"); return ERROR_FAIL; } buf_set_u32(next->tms, 0, len, tms); } tap_set_state(tap_get_end_state()); return ERROR_OK; } static int osbdm_add_stableclocks( struct queue *queue, int count) { if (!tap_is_state_stable(tap_get_state())) { LOG_ERROR("BUG: current state (%s) is not stable", tap_state_name(tap_get_state())); return ERROR_FAIL; } struct sequence *next = queue_add_tail(queue, count); if (!next) { LOG_ERROR("BUG: can't allocate bit sequence"); return ERROR_FAIL; } if (tap_get_state() == TAP_RESET) (void)memset(next->tms, 0xff, DIV_ROUND_UP(count, 8)); return ERROR_OK; } static int osbdm_add_tms( struct queue *queue, const uint8_t *tms, int num_bits) { struct sequence *next = queue_add_tail(queue, num_bits); if (!next) { LOG_ERROR("BUG: can't allocate bit sequence"); return ERROR_FAIL; } buf_set_buf(tms, 0, next->tms, 0, num_bits); return ERROR_OK; } static int osbdm_add_scan( struct queue *queue, struct scan_field *fields, int num_fields, tap_state_t end_state, bool ir_scan) { /* Move to desired shift state */ if (ir_scan) { if (tap_get_state() != TAP_IRSHIFT) { if (osbdm_add_statemove(queue, TAP_IRSHIFT, 0) != ERROR_OK) return ERROR_FAIL; } } else { if (tap_get_state() != TAP_DRSHIFT) { if (osbdm_add_statemove(queue, TAP_DRSHIFT, 0) != ERROR_OK) return ERROR_FAIL; } } /* Add scan */ tap_set_end_state(end_state); for (int idx = 0; idx < num_fields; idx++) { struct sequence *next = queue_add_tail(queue, fields[idx].num_bits); if (!next) { LOG_ERROR("Can't allocate bit sequence"); return ERROR_FAIL; } (void)memset(next->tms, 0, DIV_ROUND_UP(fields[idx].num_bits, 8)); next->tdi = fields[idx].out_value; next->tdo = fields[idx].in_value; } /* Move to end state */ if (tap_get_state() != tap_get_end_state()) { /* Exit from IRSHIFT/DRSHIFT */ buf_set_u32(queue->tail->tms, queue->tail->len - 1, 1, 1); /* Move with skip_first flag */ if (osbdm_add_statemove(queue, tap_get_end_state(), 1) != ERROR_OK) return ERROR_FAIL; } return ERROR_OK; } static int osbdm_add_runtest( struct queue *queue, int num_cycles, tap_state_t end_state) { if (osbdm_add_statemove(queue, TAP_IDLE, 0) != ERROR_OK) return ERROR_FAIL; if (osbdm_add_stableclocks(queue, num_cycles) != ERROR_OK) return ERROR_FAIL; if (osbdm_add_statemove(queue, end_state, 0) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int osbdm_execute_command( struct osbdm *osbdm, struct queue *queue, struct jtag_command *cmd) { int retval = ERROR_OK; switch (cmd->type) { case JTAG_RESET: if (cmd->cmd.reset->trst) { LOG_ERROR("BUG: nTRST signal is not supported"); retval = ERROR_FAIL; } else { retval = osbdm_flush(osbdm, queue); if (retval == ERROR_OK) retval = osbdm_srst(osbdm, cmd->cmd.reset->srst); } break; case JTAG_PATHMOVE: retval = osbdm_add_pathmove( queue, cmd->cmd.pathmove->path, cmd->cmd.pathmove->num_states); break; case JTAG_TLR_RESET: retval = osbdm_add_statemove( queue, cmd->cmd.statemove->end_state, 0); break; case JTAG_STABLECLOCKS: retval = osbdm_add_stableclocks( queue, cmd->cmd.stableclocks->num_cycles); break; case JTAG_TMS: retval = osbdm_add_tms( queue, cmd->cmd.tms->bits, cmd->cmd.tms->num_bits); break; case JTAG_SCAN: retval = osbdm_add_scan( queue, cmd->cmd.scan->fields, cmd->cmd.scan->num_fields, cmd->cmd.scan->end_state, cmd->cmd.scan->ir_scan); break; case JTAG_SLEEP: retval = osbdm_flush(osbdm, queue); if (retval == ERROR_OK) jtag_sleep(cmd->cmd.sleep->us); break; case JTAG_RUNTEST: retval = osbdm_add_runtest( queue, cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); retval = ERROR_FAIL; break; } return retval; } static int osbdm_execute_queue(void) { int retval = ERROR_OK; struct queue *queue = queue_alloc(); if (!queue) { LOG_ERROR("BUG: can't allocate bit queue"); retval = ERROR_FAIL; } else { struct jtag_command *cmd = jtag_command_queue; while (retval == ERROR_OK && cmd) { retval = osbdm_execute_command(&osbdm_context, queue, cmd); cmd = cmd->next; } if (retval == ERROR_OK) retval = osbdm_flush(&osbdm_context, queue); queue_free(queue); } if (retval != ERROR_OK) { LOG_ERROR("FATAL: can't execute jtag command"); exit(-1); } return retval; } static int osbdm_init(void) { /* Open device */ if (osbdm_open(&osbdm_context) != ERROR_OK) { LOG_ERROR("Can't open OSBDM device"); return ERROR_FAIL; } else { /* Device successfully opened */ LOG_DEBUG("OSBDM init"); } /* Perform initialize command */ osbdm_context.count = 0; osbdm_context.buffer[osbdm_context.count++] = OSBDM_CMD_INIT; if (osbdm_send_and_recv(&osbdm_context) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static struct jtag_interface osbdm_interface = { .execute_queue = osbdm_execute_queue, }; struct adapter_driver osbdm_adapter_driver = { .name = "osbdm", .transports = jtag_only, .init = osbdm_init, .quit = osbdm_quit, .jtag_ops = &osbdm_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/parport.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/adapter.h> #include <jtag/interface.h> #include "bitbang.h" /* -ino: 060521-1036 */ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include <machine/sysarch.h> #include <machine/cpufunc.h> #define ioperm(startport, length, enable)\ i386_set_ioperm((startport), (length), (enable)) #endif /* __FreeBSD__ */ #if PARPORT_USE_PPDEV == 1 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include <dev/ppbus/ppi.h> #include <dev/ppbus/ppbconf.h> #define PPRSTATUS PPIGSTATUS #define PPWDATA PPISDATA #else #include <linux/parport.h> #include <linux/ppdev.h> #endif #include <sys/ioctl.h> #else /* not PARPORT_USE_PPDEV */ #ifndef _WIN32 #include <sys/io.h> #endif #endif #if PARPORT_USE_GIVEIO == 1 && IS_CYGWIN == 1 #include <windows.h> #endif /* parallel port cable description */ struct cable { const char *name; uint8_t TDO_MASK; /* status port bit containing current TDO value */ uint8_t TRST_MASK; /* data port bit for TRST */ uint8_t TMS_MASK; /* data port bit for TMS */ uint8_t TCK_MASK; /* data port bit for TCK */ uint8_t TDI_MASK; /* data port bit for TDI */ uint8_t SRST_MASK; /* data port bit for SRST */ uint8_t OUTPUT_INVERT; /* data port bits that should be inverted */ uint8_t INPUT_INVERT; /* status port that should be inverted */ uint8_t PORT_INIT; /* initialize data port with this value */ uint8_t PORT_EXIT; /* de-initialize data port with this value */ uint8_t LED_MASK; /* data port bit for LED */ }; static const struct cable cables[] = { /* name tdo trst tms tck tdi srst o_inv i_inv init exit led */ { "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x80, 0x00 }, { "wiggler2", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x00, 0x20 }, { "wiggler_ntrst_inverted", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x11, 0x80, 0x80, 0x80, 0x00 }, { "old_amt_wiggler", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80, 0x80, 0x00 }, { "arm-jtag", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x01, 0x80, 0x80, 0x80, 0x00 }, { "chameleon", 0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 }, { "dlc5", 0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00 }, { "triton", 0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 }, { "lattice", 0x40, 0x10, 0x04, 0x02, 0x01, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00 }, { "flashlink", 0x20, 0x10, 0x02, 0x01, 0x04, 0x20, 0x30, 0x20, 0x00, 0x00, 0x00 }, /* Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows: HARD TCK - Target TCK HARD TMS - Target TMS HARD TDI - Target TDI HARD TDO - Target TDO SOFT TCK - Target TRST SOFT TDI - Target SRST */ { "altium", 0x10, 0x20, 0x04, 0x02, 0x01, 0x80, 0x00, 0x00, 0x10, 0x00, 0x08 }, { "aspo", 0x10, 0x01, 0x04, 0x08, 0x02, 0x10, 0x17, 0x00, 0x17, 0x17, 0x00 }, { NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; /* configuration */ static char *parport_cable; static uint16_t parport_port; static bool parport_exit; static uint32_t parport_toggling_time_ns = 1000; static int wait_states; /* interface variables */ static const struct cable *cable; static uint8_t dataport_value; #if PARPORT_USE_PPDEV == 1 static int device_handle; #else static unsigned long dataport; static unsigned long statusport; #endif static bb_value_t parport_read(void) { int data = 0; #if PARPORT_USE_PPDEV == 1 ioctl(device_handle, PPRSTATUS, &data); #else data = inb(statusport); #endif if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK) return BB_HIGH; else return BB_LOW; } static inline void parport_write_data(void) { uint8_t output; output = dataport_value ^ cable->OUTPUT_INVERT; #if PARPORT_USE_PPDEV == 1 ioctl(device_handle, PPWDATA, &output); #else #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) outb(dataport, output); #else outb(output, dataport); #endif #endif } static int parport_write(int tck, int tms, int tdi) { int i = wait_states + 1; if (tck) dataport_value |= cable->TCK_MASK; else dataport_value &= ~cable->TCK_MASK; if (tms) dataport_value |= cable->TMS_MASK; else dataport_value &= ~cable->TMS_MASK; if (tdi) dataport_value |= cable->TDI_MASK; else dataport_value &= ~cable->TDI_MASK; while (i-- > 0) parport_write_data(); return ERROR_OK; } /* (1) assert or (0) deassert reset lines */ static int parport_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); if (trst == 0) dataport_value |= cable->TRST_MASK; else if (trst == 1) dataport_value &= ~cable->TRST_MASK; if (srst == 0) dataport_value |= cable->SRST_MASK; else if (srst == 1) dataport_value &= ~cable->SRST_MASK; parport_write_data(); return ERROR_OK; } /* turn LED on parport adapter on (1) or off (0) */ static int parport_led(int on) { if (on) dataport_value |= cable->LED_MASK; else dataport_value &= ~cable->LED_MASK; parport_write_data(); return ERROR_OK; } static int parport_speed(int speed) { wait_states = speed; return ERROR_OK; } static int parport_khz(int khz, int *jtag_speed) { if (khz == 0) { LOG_DEBUG("RCLK not supported"); return ERROR_FAIL; } *jtag_speed = 499999 / (khz * parport_toggling_time_ns); return ERROR_OK; } static int parport_speed_div(int speed, int *khz) { uint32_t denominator = (speed + 1) * parport_toggling_time_ns; *khz = (499999 + denominator) / denominator; return ERROR_OK; } #if PARPORT_USE_GIVEIO == 1 static int parport_get_giveio_access(void) { HANDLE h; OSVERSIONINFO version; version.dwOSVersionInfoSize = sizeof(version); if (!GetVersionEx(&version)) { errno = EINVAL; return -1; } if (version.dwPlatformId != VER_PLATFORM_WIN32_NT) return 0; h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { errno = ENODEV; return -1; } CloseHandle(h); return 0; } #endif static struct bitbang_interface parport_bitbang = { .read = &parport_read, .write = &parport_write, .blink = &parport_led, }; static int parport_init(void) { const struct cable *cur_cable; #if PARPORT_USE_PPDEV == 1 char buffer[256]; #endif cur_cable = cables; if (!parport_cable) { parport_cable = strdup("wiggler"); LOG_WARNING("No parport cable specified, using default 'wiggler'"); } while (cur_cable->name) { if (strcmp(cur_cable->name, parport_cable) == 0) { cable = cur_cable; break; } cur_cable++; } if (!cable) { LOG_ERROR("No matching cable found for %s", parport_cable); return ERROR_JTAG_INIT_FAILED; } dataport_value = cable->PORT_INIT; #if PARPORT_USE_PPDEV == 1 if (device_handle > 0) { LOG_ERROR("device is already opened"); return ERROR_JTAG_INIT_FAILED; } #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) LOG_DEBUG("opening /dev/ppi%d...", parport_port); snprintf(buffer, 256, "/dev/ppi%d", parport_port); device_handle = open(buffer, O_WRONLY); #else /* not __FreeBSD__, __FreeBSD_kernel__ */ LOG_DEBUG("opening /dev/parport%d...", parport_port); snprintf(buffer, 256, "/dev/parport%d", parport_port); device_handle = open(buffer, O_WRONLY); #endif /* __FreeBSD__, __FreeBSD_kernel__ */ if (device_handle < 0) { int err = errno; LOG_ERROR("cannot open device. check it exists and that user read and write rights are set. errno=%d", err); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("...open"); #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) int i = ioctl(device_handle, PPCLAIM); if (i < 0) { LOG_ERROR("cannot claim device"); return ERROR_JTAG_INIT_FAILED; } i = PARPORT_MODE_COMPAT; i = ioctl(device_handle, PPSETMODE, &i); if (i < 0) { LOG_ERROR(" cannot set compatible mode to device"); return ERROR_JTAG_INIT_FAILED; } i = IEEE1284_MODE_COMPAT; i = ioctl(device_handle, PPNEGOT, &i); if (i < 0) { LOG_ERROR("cannot set compatible 1284 mode to device"); return ERROR_JTAG_INIT_FAILED; } #endif /* not __FreeBSD__, __FreeBSD_kernel__ */ #else /* not PARPORT_USE_PPDEV */ if (parport_port == 0) { parport_port = 0x378; LOG_WARNING("No parport port specified, using default '0x378' (LPT1)"); } dataport = parport_port; statusport = parport_port + 1; LOG_DEBUG("requesting privileges for parallel port 0x%lx...", dataport); #if PARPORT_USE_GIVEIO == 1 if (parport_get_giveio_access() != 0) { #else /* PARPORT_USE_GIVEIO */ if (ioperm(dataport, 3, 1) != 0) { #endif /* PARPORT_USE_GIVEIO */ LOG_ERROR("missing privileges for direct i/o"); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("...privileges granted"); /* make sure parallel port is in right mode (clear tristate and interrupt */ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) outb(parport_port + 2, 0x0); #else outb(0x0, parport_port + 2); #endif #endif /* PARPORT_USE_PPDEV */ if (parport_reset(0, 0) != ERROR_OK) return ERROR_FAIL; if (parport_write(0, 0, 0) != ERROR_OK) return ERROR_FAIL; if (parport_led(1) != ERROR_OK) return ERROR_FAIL; bitbang_interface = &parport_bitbang; return ERROR_OK; } static int parport_quit(void) { if (parport_led(0) != ERROR_OK) return ERROR_FAIL; if (parport_exit) { dataport_value = cable->PORT_EXIT; parport_write_data(); } free(parport_cable); parport_cable = NULL; return ERROR_OK; } COMMAND_HANDLER(parport_handle_parport_port_command) { if (CMD_ARGC == 1) { /* only if the port wasn't overwritten by cmdline */ if (parport_port == 0) COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], parport_port); else { LOG_ERROR("The parport port was already configured!"); return ERROR_FAIL; } } command_print(CMD, "parport port = 0x%" PRIx16 "", parport_port); return ERROR_OK; } COMMAND_HANDLER(parport_handle_parport_cable_command) { if (CMD_ARGC == 0) return ERROR_OK; /* only if the cable name wasn't overwritten by cmdline */ if (!parport_cable) { /* REVISIT first verify that it's listed in cables[] ... */ parport_cable = malloc(strlen(CMD_ARGV[0]) + sizeof(char)); if (!parport_cable) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } strcpy(parport_cable, CMD_ARGV[0]); } /* REVISIT it's probably worth returning the current value ... */ return ERROR_OK; } COMMAND_HANDLER(parport_handle_write_on_exit_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ON_OFF(CMD_ARGV[0], parport_exit); return ERROR_OK; } COMMAND_HANDLER(parport_handle_parport_toggling_time_command) { if (CMD_ARGC == 1) { uint32_t ns; int retval = parse_u32(CMD_ARGV[0], &ns); if (retval != ERROR_OK) return retval; if (ns == 0) { LOG_ERROR("0 ns is not a valid parport toggling time"); return ERROR_FAIL; } parport_toggling_time_ns = ns; retval = adapter_get_speed(&wait_states); if (retval != ERROR_OK) { /* if adapter_get_speed fails then the clock_mode * has not been configured, this happens if parport_toggling_time is * called before the adapter speed is set */ LOG_INFO("no parport speed set - defaulting to zero wait states"); wait_states = 0; } } command_print(CMD, "parport toggling time = %" PRIu32 " ns", parport_toggling_time_ns); return ERROR_OK; } static const struct command_registration parport_subcommand_handlers[] = { { .name = "port", .handler = parport_handle_parport_port_command, .mode = COMMAND_CONFIG, .help = "Display the address of the I/O port (e.g. 0x378) " "or the number of the '/dev/parport' device used. " "If a parameter is provided, first change that port.", .usage = "[port_number]", }, { .name = "cable", .handler = parport_handle_parport_cable_command, .mode = COMMAND_CONFIG, .help = "Set the layout of the parallel port cable " "used to connect to the target.", /* REVISIT there's no way to list layouts we know ... */ .usage = "[layout]", }, { .name = "write_on_exit", .handler = parport_handle_write_on_exit_command, .mode = COMMAND_CONFIG, .help = "Configure the parallel driver to write " "a known value to the parallel interface on exit.", .usage = "('on'|'off')", }, { .name = "toggling_time", .handler = parport_handle_parport_toggling_time_command, .mode = COMMAND_CONFIG, .help = "Displays or assigns how many nanoseconds it " "takes for the hardware to toggle TCK.", .usage = "[nanoseconds]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration parport_command_handlers[] = { { .name = "parport", .mode = COMMAND_ANY, .help = "perform parport management", .chain = parport_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static struct jtag_interface parport_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, }; struct adapter_driver parport_adapter_driver = { .name = "parport", .transports = jtag_only, .commands = parport_command_handlers, .init = parport_init, .quit = parport_quit, .reset = parport_reset, .speed = parport_speed, .khz = parport_khz, .speed_div = parport_speed_div, .jtag_ops = &parport_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/presto.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * ***************************************************************************/ /** * @file * Holds driver for PRESTO programmer from ASIX. * http://tools.asix.net/prg_presto.htm */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #if IS_CYGWIN == 1 #include "windows.h" #endif #include <jtag/adapter.h> #include <jtag/interface.h> #include <helper/time_support.h> #include "bitq.h" /* PRESTO access library includes */ #include "libftdi_helper.h" /* -------------------------------------------------------------------------- */ #define FT_DEVICE_NAME_LEN 64 #define FT_DEVICE_SERNUM_LEN 64 #define PRESTO_VID_PID 0x0403f1a0 #define PRESTO_VID (0x0403) #define PRESTO_PID (0xf1a0) #define BUFFER_SIZE (64*62) struct presto { struct ftdi_context ftdic; int retval; char serial[FT_DEVICE_SERNUM_LEN]; uint8_t buff_out[BUFFER_SIZE]; int buff_out_pos; uint8_t buff_in[BUFFER_SIZE]; int buff_in_exp;/* expected in buffer length */ int buff_in_len;/* length of data received */ int buff_in_pos; unsigned long total_out; unsigned long total_in; int jtag_tms; /* last tms state */ int jtag_tck; /* last tck state */ int jtag_rst; /* last trst state */ int jtag_tdi_data; int jtag_tdi_count; int jtag_speed; }; static struct presto presto_state; static struct presto *presto = &presto_state; static uint8_t presto_init_seq[] = { 0x80, 0xA0, 0xA8, 0xB0, 0xC0, 0xE0 }; static int presto_write(uint8_t *buf, uint32_t size) { uint32_t ftbytes; presto->retval = ftdi_write_data(&presto->ftdic, buf, size); if (presto->retval < 0) { LOG_ERROR("ftdi_write_data: %s", ftdi_get_error_string(&presto->ftdic)); return ERROR_JTAG_DEVICE_ERROR; } ftbytes = presto->retval; if (ftbytes != size) { LOG_ERROR("couldn't write the requested number of bytes to PRESTO (%u < %u)", (unsigned)ftbytes, (unsigned)size); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int presto_read(uint8_t *buf, uint32_t size) { uint32_t ftbytes = 0; struct timeval timeout, now; gettimeofday(&timeout, NULL); timeval_add_time(&timeout, 1, 0); /* one second timeout */ while (ftbytes < size) { presto->retval = ftdi_read_data(&presto->ftdic, buf + ftbytes, size - ftbytes); if (presto->retval < 0) { LOG_ERROR("ftdi_read_data: %s", ftdi_get_error_string(&presto->ftdic)); return ERROR_JTAG_DEVICE_ERROR; } ftbytes += presto->retval; gettimeofday(&now, NULL); if (timeval_compare(&now, &timeout) > 0) break; } if (ftbytes != size) { /* this is just a warning, there might have been timeout when detecting PRESTO, *which is not fatal */ LOG_WARNING("couldn't read the requested number of bytes from PRESTO (%u < %u)", (unsigned)ftbytes, (unsigned)size); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int presto_open_libftdi(const char *req_serial) { uint8_t presto_data; LOG_DEBUG("searching for PRESTO using libftdi"); /* initialize FTDI context structure */ if (ftdi_init(&presto->ftdic) < 0) { LOG_ERROR("unable to init libftdi: %s", presto->ftdic.error_str); return ERROR_JTAG_DEVICE_ERROR; } /* context, vendor id, product id */ if (ftdi_usb_open_desc(&presto->ftdic, PRESTO_VID, PRESTO_PID, NULL, req_serial) < 0) { LOG_ERROR("unable to open PRESTO: %s", presto->ftdic.error_str); return ERROR_JTAG_DEVICE_ERROR; } if (ftdi_usb_reset(&presto->ftdic) < 0) { LOG_ERROR("unable to reset PRESTO device"); return ERROR_JTAG_DEVICE_ERROR; } if (ftdi_set_latency_timer(&presto->ftdic, 1) < 0) { LOG_ERROR("unable to set latency timer"); return ERROR_JTAG_DEVICE_ERROR; } if (ftdi_tcioflush(&presto->ftdic) < 0) { LOG_ERROR("unable to flush PRESTO buffers"); return ERROR_JTAG_DEVICE_ERROR; } presto_data = 0xD0; if (presto_write(&presto_data, 1) != ERROR_OK) { LOG_ERROR("error writing to PRESTO"); return ERROR_JTAG_DEVICE_ERROR; } if (presto_read(&presto_data, 1) != ERROR_OK) { LOG_DEBUG("no response from PRESTO, retrying"); if (ftdi_tcioflush(&presto->ftdic) < 0) return ERROR_JTAG_DEVICE_ERROR; presto_data = 0xD0; if (presto_write(&presto_data, 1) != ERROR_OK) return ERROR_JTAG_DEVICE_ERROR; if (presto_read(&presto_data, 1) != ERROR_OK) { LOG_ERROR("no response from PRESTO, giving up"); return ERROR_JTAG_DEVICE_ERROR; } } if (presto_write(presto_init_seq, sizeof(presto_init_seq)) != ERROR_OK) { LOG_ERROR("error writing PRESTO init sequence"); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int presto_open(const char *req_serial) { presto->buff_out_pos = 0; presto->buff_in_pos = 0; presto->buff_in_len = 0; presto->buff_in_exp = 0; presto->total_out = 0; presto->total_in = 0; presto->jtag_tms = 0; presto->jtag_tck = 0; presto->jtag_rst = 0; presto->jtag_tdi_data = 0; presto->jtag_tdi_count = 0; presto->jtag_speed = 0; return presto_open_libftdi(req_serial); } static int presto_close(void) { int result = ERROR_OK; presto->retval = ftdi_write_data(&presto->ftdic, presto_init_seq, sizeof(presto_init_seq)); if (presto->retval != sizeof(presto_init_seq)) result = ERROR_JTAG_DEVICE_ERROR; presto->retval = ftdi_set_latency_timer(&presto->ftdic, 16); if (presto->retval < 0) result = ERROR_JTAG_DEVICE_ERROR; presto->retval = ftdi_usb_close(&presto->ftdic); if (presto->retval < 0) result = ERROR_JTAG_DEVICE_ERROR; else ftdi_deinit(&presto->ftdic); return result; } static int presto_flush(void) { if (presto->buff_out_pos == 0) return ERROR_OK; if (presto->retval < 0) { LOG_DEBUG("error in previous communication, canceling I/O operation"); return ERROR_JTAG_DEVICE_ERROR; } if (presto_write(presto->buff_out, presto->buff_out_pos) != ERROR_OK) { presto->buff_out_pos = 0; return ERROR_JTAG_DEVICE_ERROR; } presto->total_out += presto->buff_out_pos; presto->buff_out_pos = 0; if (presto->buff_in_exp == 0) return ERROR_OK; presto->buff_in_pos = 0; presto->buff_in_len = 0; if (presto_read(presto->buff_in, presto->buff_in_exp) != ERROR_OK) { presto->buff_in_exp = 0; return ERROR_JTAG_DEVICE_ERROR; } presto->total_in += presto->buff_in_exp; presto->buff_in_len = presto->buff_in_exp; presto->buff_in_exp = 0; return ERROR_OK; } static int presto_sendbyte(int data) { if (data == EOF) return presto_flush(); if (presto->buff_out_pos < BUFFER_SIZE) { presto->buff_out[presto->buff_out_pos++] = (uint8_t)data; if (((data & 0xC0) == 0x40) || ((data & 0xD0) == 0xD0)) presto->buff_in_exp++; } else return ERROR_JTAG_DEVICE_ERROR; /* libftdi does not do background read, be sure that USB IN buffer does not overflow (128 *bytes only!) */ if (presto->buff_out_pos >= BUFFER_SIZE || presto->buff_in_exp == 128) return presto_flush(); return ERROR_OK; } #if 0 static int presto_getbyte(void) { if (presto->buff_in_pos < presto->buff_in_len) return presto->buff_in[presto->buff_in_pos++]; if (presto->buff_in_exp == 0) return -1; if (presto_flush() != ERROR_OK) return -1; if (presto->buff_in_pos < presto->buff_in_len) return presto->buff_in[presto->buff_in_pos++]; return -1; } #endif /* -------------------------------------------------------------------------- */ static int presto_tdi_flush(void) { if (presto->jtag_tdi_count == 0) return 0; if (presto->jtag_tck == 0) { LOG_ERROR("BUG: unexpected TAP condition, TCK low"); return -1; } presto->jtag_tdi_data |= (presto->jtag_tdi_count - 1) << 4; presto_sendbyte(presto->jtag_tdi_data); presto->jtag_tdi_count = 0; presto->jtag_tdi_data = 0; return 0; } static int presto_tck_idle(void) { if (presto->jtag_tck == 1) { presto_sendbyte(0xCA); presto->jtag_tck = 0; } return 0; } /* -------------------------------------------------------------------------- */ static int presto_bitq_out(int tms, int tdi, int tdo_req) { int i; unsigned char cmd; if (presto->jtag_tck == 0) presto_sendbyte(0xA4); /* LED indicator - JTAG active */ else if (presto->jtag_speed == 0 && !tdo_req && tms == presto->jtag_tms) { presto->jtag_tdi_data |= (tdi != 0) << presto->jtag_tdi_count; if (++presto->jtag_tdi_count == 4) presto_tdi_flush(); return 0; } presto_tdi_flush(); cmd = tdi ? 0xCB : 0xCA; presto_sendbyte(cmd); if (tms != presto->jtag_tms) { presto_sendbyte((tms ? 0xEC : 0xE8) | (presto->jtag_rst ? 0x02 : 0)); presto->jtag_tms = tms; } /* delay with TCK low */ for (i = presto->jtag_speed; i > 1; i--) presto_sendbyte(cmd); cmd |= 0x04; presto_sendbyte(cmd | (tdo_req ? 0x10 : 0)); /* delay with TCK high */ for (i = presto->jtag_speed; i > 1; i--) presto_sendbyte(cmd); presto->jtag_tck = 1; return 0; } static int presto_bitq_flush(void) { presto_tdi_flush(); presto_tck_idle(); presto_sendbyte(0xA0); /* LED indicator - JTAG idle */ return presto_flush(); } static int presto_bitq_in_rdy(void) { if (presto->buff_in_pos >= presto->buff_in_len) return 0; return presto->buff_in_len-presto->buff_in_pos; } static int presto_bitq_in(void) { if (presto->buff_in_pos >= presto->buff_in_len) return -1; if (presto->buff_in[presto->buff_in_pos++]&0x08) return 1; return 0; } static int presto_bitq_sleep(unsigned long us) { long waits; presto_tdi_flush(); presto_tck_idle(); if (us > 100000) { presto_bitq_flush(); jtag_sleep(us); return 0; } waits = us / 170 + 2; while (waits--) presto_sendbyte(0x80); return 0; } static int presto_bitq_reset(int trst, int srst) { presto_tdi_flush(); presto_tck_idle(); /* add a delay after possible TCK transition */ presto_sendbyte(0x80); presto_sendbyte(0x80); presto->jtag_rst = trst || srst; presto_sendbyte((presto->jtag_rst ? 0xEA : 0xE8) | (presto->jtag_tms ? 0x04 : 0)); return 0; } static struct bitq_interface presto_bitq = { .out = &presto_bitq_out, .flush = &presto_bitq_flush, .sleep = &presto_bitq_sleep, .reset = &presto_bitq_reset, .in_rdy = &presto_bitq_in_rdy, .in = &presto_bitq_in, }; /* -------------------------------------------------------------------------- */ static int presto_adapter_khz(int khz, int *jtag_speed) { if (khz < 0) { *jtag_speed = 0; return ERROR_COMMAND_SYNTAX_ERROR; } if (khz >= 3000) *jtag_speed = 0; else *jtag_speed = (1000 + khz-1)/khz; return 0; } static int presto_jtag_speed_div(int speed, int *khz) { if ((speed < 0) || (speed > 1000)) { *khz = 0; return ERROR_COMMAND_SYNTAX_ERROR; } if (speed == 0) *khz = 3000; else *khz = 1000/speed; return 0; } static int presto_jtag_speed(int speed) { int khz; if (presto_jtag_speed_div(speed, &khz)) return ERROR_COMMAND_SYNTAX_ERROR; presto->jtag_speed = speed; if (khz%1000 == 0) LOG_INFO("setting speed to %d, max. TCK freq. is %d MHz", speed, khz/1000); else LOG_INFO("setting speed to %d, max. TCK freq. is %d kHz", speed, khz); return 0; } static int presto_jtag_init(void) { const char *presto_serial = adapter_get_required_serial(); if (presto_open(presto_serial) != ERROR_OK) { presto_close(); if (presto_serial) LOG_ERROR("Cannot open PRESTO, serial number '%s'", presto_serial); else LOG_ERROR("Cannot open PRESTO"); return ERROR_JTAG_INIT_FAILED; } LOG_INFO("PRESTO open, serial number '%s'", presto->serial); bitq_interface = &presto_bitq; return ERROR_OK; } static int presto_jtag_quit(void) { bitq_cleanup(); presto_close(); LOG_INFO("PRESTO closed"); return ERROR_OK; } static struct jtag_interface presto_interface = { .execute_queue = bitq_execute_queue, }; struct adapter_driver presto_adapter_driver = { .name = "presto", .transports = jtag_only, .init = presto_jtag_init, .quit = presto_jtag_quit, .speed = presto_jtag_speed, .khz = presto_adapter_khz, .speed_div = presto_jtag_speed_div, .jtag_ops = &presto_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/remote_bitbang.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Richard Uhler * * ruhler@mit.edu * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _WIN32 #include <sys/un.h> #include <netdb.h> #include <netinet/tcp.h> #endif #include "helper/system.h" #include "helper/replacements.h" #include <jtag/interface.h> #include "bitbang.h" /* arbitrary limit on host name length: */ #define REMOTE_BITBANG_HOST_MAX 255 static char *remote_bitbang_host; static char *remote_bitbang_port; static int remote_bitbang_fd; static uint8_t remote_bitbang_send_buf[512]; static unsigned int remote_bitbang_send_buf_used; /* Circular buffer. When start == end, the buffer is empty. */ static char remote_bitbang_recv_buf[256]; static unsigned int remote_bitbang_recv_buf_start; static unsigned int remote_bitbang_recv_buf_end; static bool remote_bitbang_recv_buf_full(void) { return remote_bitbang_recv_buf_end == ((remote_bitbang_recv_buf_start + sizeof(remote_bitbang_recv_buf) - 1) % sizeof(remote_bitbang_recv_buf)); } static bool remote_bitbang_recv_buf_empty(void) { return remote_bitbang_recv_buf_start == remote_bitbang_recv_buf_end; } static unsigned int remote_bitbang_recv_buf_contiguous_available_space(void) { if (remote_bitbang_recv_buf_end >= remote_bitbang_recv_buf_start) { unsigned int space = sizeof(remote_bitbang_recv_buf) - remote_bitbang_recv_buf_end; if (remote_bitbang_recv_buf_start == 0) space -= 1; return space; } else { return remote_bitbang_recv_buf_start - remote_bitbang_recv_buf_end - 1; } } static int remote_bitbang_flush(void) { if (remote_bitbang_send_buf_used <= 0) return ERROR_OK; unsigned int offset = 0; while (offset < remote_bitbang_send_buf_used) { ssize_t written = write_socket(remote_bitbang_fd, remote_bitbang_send_buf + offset, remote_bitbang_send_buf_used - offset); if (written < 0) { log_socket_error("remote_bitbang_putc"); remote_bitbang_send_buf_used = 0; return ERROR_FAIL; } offset += written; } remote_bitbang_send_buf_used = 0; return ERROR_OK; } enum block_bool { NO_BLOCK, BLOCK }; /* Read any incoming data, placing it into the buffer. */ static int remote_bitbang_fill_buf(enum block_bool block) { if (remote_bitbang_recv_buf_empty()) { /* If the buffer is empty, reset it to 0 so we get more * contiguous space. */ remote_bitbang_recv_buf_start = 0; remote_bitbang_recv_buf_end = 0; } if (block == BLOCK) { if (remote_bitbang_flush() != ERROR_OK) return ERROR_FAIL; socket_block(remote_bitbang_fd); } bool first = true; while (!remote_bitbang_recv_buf_full()) { unsigned int contiguous_available_space = remote_bitbang_recv_buf_contiguous_available_space(); ssize_t count = read_socket(remote_bitbang_fd, remote_bitbang_recv_buf + remote_bitbang_recv_buf_end, contiguous_available_space); if (first && block == BLOCK) socket_nonblock(remote_bitbang_fd); first = false; if (count > 0) { remote_bitbang_recv_buf_end += count; if (remote_bitbang_recv_buf_end == sizeof(remote_bitbang_recv_buf)) remote_bitbang_recv_buf_end = 0; } else if (count == 0) { return ERROR_OK; } else if (count < 0) { #ifdef _WIN32 if (WSAGetLastError() == WSAEWOULDBLOCK) { #else if (errno == EAGAIN) { #endif return ERROR_OK; } else { log_socket_error("remote_bitbang_fill_buf"); return ERROR_FAIL; } } } return ERROR_OK; } typedef enum { NO_FLUSH, FLUSH_SEND_BUF } flush_bool_t; static int remote_bitbang_queue(int c, flush_bool_t flush) { remote_bitbang_send_buf[remote_bitbang_send_buf_used++] = c; if (flush == FLUSH_SEND_BUF || remote_bitbang_send_buf_used >= ARRAY_SIZE(remote_bitbang_send_buf)) return remote_bitbang_flush(); return ERROR_OK; } static int remote_bitbang_quit(void) { if (remote_bitbang_queue('Q', FLUSH_SEND_BUF) == ERROR_FAIL) return ERROR_FAIL; if (close_socket(remote_bitbang_fd) != 0) { log_socket_error("close_socket"); return ERROR_FAIL; } free(remote_bitbang_host); free(remote_bitbang_port); LOG_INFO("remote_bitbang interface quit"); return ERROR_OK; } static bb_value_t char_to_int(int c) { switch (c) { case '0': return BB_LOW; case '1': return BB_HIGH; default: remote_bitbang_quit(); LOG_ERROR("remote_bitbang: invalid read response: %c(%i)", c, c); return BB_ERROR; } } static int remote_bitbang_sample(void) { if (remote_bitbang_fill_buf(NO_BLOCK) != ERROR_OK) return ERROR_FAIL; assert(!remote_bitbang_recv_buf_full()); return remote_bitbang_queue('R', NO_FLUSH); } static bb_value_t remote_bitbang_read_sample(void) { if (remote_bitbang_recv_buf_empty()) { if (remote_bitbang_fill_buf(BLOCK) != ERROR_OK) return BB_ERROR; } assert(!remote_bitbang_recv_buf_empty()); int c = remote_bitbang_recv_buf[remote_bitbang_recv_buf_start]; remote_bitbang_recv_buf_start = (remote_bitbang_recv_buf_start + 1) % sizeof(remote_bitbang_recv_buf); return char_to_int(c); } static int remote_bitbang_write(int tck, int tms, int tdi) { char c = '0' + ((tck ? 0x4 : 0x0) | (tms ? 0x2 : 0x0) | (tdi ? 0x1 : 0x0)); return remote_bitbang_queue(c, NO_FLUSH); } static int remote_bitbang_reset(int trst, int srst) { char c = 'r' + ((trst ? 0x2 : 0x0) | (srst ? 0x1 : 0x0)); /* Always flush the send buffer on reset, because the reset call need not be * followed by jtag_execute_queue(). */ return remote_bitbang_queue(c, FLUSH_SEND_BUF); } static int remote_bitbang_blink(int on) { char c = on ? 'B' : 'b'; return remote_bitbang_queue(c, FLUSH_SEND_BUF); } static struct bitbang_interface remote_bitbang_bitbang = { .buf_size = sizeof(remote_bitbang_recv_buf) - 1, .sample = &remote_bitbang_sample, .read_sample = &remote_bitbang_read_sample, .write = &remote_bitbang_write, .blink = &remote_bitbang_blink, }; static int remote_bitbang_init_tcp(void) { struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM }; struct addrinfo *result, *rp; int fd = 0; LOG_INFO("Connecting to %s:%s", remote_bitbang_host ? remote_bitbang_host : "localhost", remote_bitbang_port); /* Obtain address(es) matching host/port */ int s = getaddrinfo(remote_bitbang_host, remote_bitbang_port, &hints, &result); if (s != 0) { LOG_ERROR("getaddrinfo: %s\n", gai_strerror(s)); return ERROR_FAIL; } /* getaddrinfo() returns a list of address structures. Try each address until we successfully connect(2). If socket(2) (or connect(2)) fails, we (close the socket and) try the next address. */ for (rp = result; rp ; rp = rp->ai_next) { fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (fd == -1) continue; if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) break; /* Success */ close(fd); } /* We work hard to collapse the writes into the minimum number, so when * we write something we want to get it to the other end of the * connection as fast as possible. */ int one = 1; /* On Windows optval has to be a const char *. */ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, sizeof(one)); freeaddrinfo(result); /* No longer needed */ if (!rp) { /* No address succeeded */ log_socket_error("Failed to connect"); return ERROR_FAIL; } return fd; } static int remote_bitbang_init_unix(void) { if (!remote_bitbang_host) { LOG_ERROR("host/socket not specified"); return ERROR_FAIL; } LOG_INFO("Connecting to unix socket %s", remote_bitbang_host); int fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) { log_socket_error("socket"); return ERROR_FAIL; } struct sockaddr_un addr; addr.sun_family = AF_UNIX; strncpy(addr.sun_path, remote_bitbang_host, sizeof(addr.sun_path)); addr.sun_path[sizeof(addr.sun_path)-1] = '\0'; if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { log_socket_error("connect"); return ERROR_FAIL; } return fd; } static int remote_bitbang_init(void) { bitbang_interface = &remote_bitbang_bitbang; remote_bitbang_recv_buf_start = 0; remote_bitbang_recv_buf_end = 0; LOG_INFO("Initializing remote_bitbang driver"); if (!remote_bitbang_port) remote_bitbang_fd = remote_bitbang_init_unix(); else remote_bitbang_fd = remote_bitbang_init_tcp(); if (remote_bitbang_fd < 0) return remote_bitbang_fd; socket_nonblock(remote_bitbang_fd); LOG_INFO("remote_bitbang driver initialized"); return ERROR_OK; } COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_port_command) { if (CMD_ARGC == 1) { uint16_t port; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port); free(remote_bitbang_port); remote_bitbang_port = port == 0 ? NULL : strdup(CMD_ARGV[0]); return ERROR_OK; } return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_host_command) { if (CMD_ARGC == 1) { free(remote_bitbang_host); remote_bitbang_host = strdup(CMD_ARGV[0]); return ERROR_OK; } return ERROR_COMMAND_SYNTAX_ERROR; } static const struct command_registration remote_bitbang_subcommand_handlers[] = { { .name = "port", .handler = remote_bitbang_handle_remote_bitbang_port_command, .mode = COMMAND_CONFIG, .help = "Set the port to use to connect to the remote jtag.\n" " if 0 or unset, use unix sockets to connect to the remote jtag.", .usage = "port_number", }, { .name = "host", .handler = remote_bitbang_handle_remote_bitbang_host_command, .mode = COMMAND_CONFIG, .help = "Set the host to use to connect to the remote jtag.\n" " if port is 0 or unset, this is the name of the unix socket to use.", .usage = "host_name", }, COMMAND_REGISTRATION_DONE, }; static const struct command_registration remote_bitbang_command_handlers[] = { { .name = "remote_bitbang", .mode = COMMAND_ANY, .help = "perform remote_bitbang management", .chain = remote_bitbang_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static int remote_bitbang_execute_queue(void) { /* safety: the send buffer must be empty, no leftover characters from * previous transactions */ assert(remote_bitbang_send_buf_used == 0); /* process the JTAG command queue */ int ret = bitbang_execute_queue(); if (ret != ERROR_OK) return ret; /* flush not-yet-sent characters, if any */ return remote_bitbang_flush(); } static struct jtag_interface remote_bitbang_interface = { .execute_queue = &remote_bitbang_execute_queue, }; struct adapter_driver remote_bitbang_adapter_driver = { .name = "remote_bitbang", .transports = jtag_only, .commands = remote_bitbang_command_handlers, .init = &remote_bitbang_init, .quit = &remote_bitbang_quit, .reset = &remote_bitbang_reset, .jtag_ops = &remote_bitbang_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/rlink.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 Rob Brown, Lou Deluxe * * rob@cobbleware.com, lou.openocd012@fixit.nospammail.net * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include <jtag/interface.h> #include <jtag/commands.h> #include "helper/replacements.h" #include "rlink.h" #include "rlink_st7.h" #include "rlink_ep1_cmd.h" #include "rlink_dtc_cmd.h" #include "libusb_helper.h" /* This feature is made useless by running the DTC all the time. When automatic, the LED is on *whenever the DTC is running. Otherwise, USB messages are sent to turn it on and off. */ #undef AUTOMATIC_BUSY_LED /* This feature may require derating the speed due to reduced hold time. */ #undef USE_HARDWARE_SHIFTER_FOR_TMS #define INTERFACE_NAME "RLink" #define USB_IDVENDOR (0x138e) #define USB_IDPRODUCT (0x9000) #define USB_EP1OUT_ADDR (0x01) #define USB_EP1OUT_SIZE (16) #define USB_EP1IN_ADDR (USB_EP1OUT_ADDR | 0x80) #define USB_EP1IN_SIZE (USB_EP1OUT_SIZE) #define USB_EP2OUT_ADDR (0x02) #define USB_EP2OUT_SIZE (64) #define USB_EP2IN_ADDR (USB_EP2OUT_ADDR | 0x80) #define USB_EP2IN_SIZE (USB_EP2OUT_SIZE) #define USB_EP2BANK_SIZE (512) #define DTC_STATUS_POLL_BYTE (ST7_USB_BUF_EP0OUT + 0xff) #define ST7_PD_NBUSY_LED ST7_PD0 #define ST7_PD_NRUN_LED ST7_PD1 /* low enables VPP at adapter header, high connects it to GND instead */ #define ST7_PD_VPP_SEL ST7_PD6 /* low: VPP = 12v, high: VPP <= 5v */ #define ST7_PD_VPP_SHDN ST7_PD7 /* These pins are connected together */ #define ST7_PE_ADAPTER_SENSE_IN ST7_PE3 #define ST7_PE_ADAPTER_SENSE_OUT ST7_PE4 /* Symbolic mapping between port pins and numbered IO lines */ #define ST7_PA_IO1 ST7_PA1 #define ST7_PA_IO2 ST7_PA2 #define ST7_PA_IO4 ST7_PA4 #define ST7_PA_IO8 ST7_PA6 #define ST7_PA_IO10 ST7_PA7 #define ST7_PB_IO5 ST7_PB5 #define ST7_PC_IO9 ST7_PC1 #define ST7_PC_IO3 ST7_PC2 #define ST7_PC_IO7 ST7_PC3 #define ST7_PE_IO6 ST7_PE5 /* Symbolic mapping between numbered IO lines and adapter signals */ #define ST7_PA_RTCK ST7_PA_IO0 #define ST7_PA_NTRST ST7_PA_IO1 #define ST7_PC_TDI ST7_PC_IO3 #define ST7_PA_DBGRQ ST7_PA_IO4 #define ST7_PB_NSRST ST7_PB_IO5 #define ST7_PE_TMS ST7_PE_IO6 #define ST7_PC_TCK ST7_PC_IO7 #define ST7_PC_TDO ST7_PC_IO9 #define ST7_PA_DBGACK ST7_PA_IO10 static struct libusb_device_handle *hdev; /* * ep1 commands are up to USB_EP1OUT_SIZE bytes in length. * This function takes care of zeroing the unused bytes before sending the packet. * Any reply packet is not handled by this function. */ static int ep1_generic_commandl(struct libusb_device_handle *hdev_param, size_t length, ...) { uint8_t usb_buffer[USB_EP1OUT_SIZE]; uint8_t *usb_buffer_p; va_list ap; int usb_ret; int transferred; if (length > sizeof(usb_buffer)) length = sizeof(usb_buffer); usb_buffer_p = usb_buffer; va_start(ap, length); while (length > 0) { *usb_buffer_p++ = va_arg(ap, int); length--; } memset( usb_buffer_p, 0, sizeof(usb_buffer) - (usb_buffer_p - usb_buffer) ); usb_ret = jtag_libusb_bulk_write( hdev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), LIBUSB_TIMEOUT_MS, &transferred ); if (usb_ret != ERROR_OK) return usb_ret; return transferred; } #if 0 static ssize_t ep1_memory_read( struct libusb_device_handle *hdev_param, uint16_t addr, size_t length, uint8_t *buffer) { uint8_t usb_buffer[USB_EP1OUT_SIZE]; int usb_ret; size_t remain; ssize_t count; int transferred; usb_buffer[0] = EP1_CMD_MEMORY_READ; memset( usb_buffer + 4, 0, sizeof(usb_buffer) - 4 ); remain = length; count = 0; while (remain) { if (remain > sizeof(usb_buffer)) length = sizeof(usb_buffer); else length = remain; usb_buffer[1] = addr >> 8; usb_buffer[2] = addr; usb_buffer[3] = length; usb_ret = jtag_libusb_bulk_write( hdev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), LIBUSB_TIMEOUT_MS, &transferred ); if (usb_ret != ERROR_OK || transferred < (int)sizeof(usb_buffer)) break; usb_ret = jtag_libusb_bulk_read( hdev_param, USB_EP1IN_ADDR, (char *)buffer, length, LIBUSB_TIMEOUT_MS, &transferred ); if (usb_ret != ERROR_OK || transferred < (int)length) break; addr += length; buffer += length; count += length; remain -= length; } return count; } #endif static ssize_t ep1_memory_write(struct libusb_device_handle *hdev_param, uint16_t addr, size_t length, uint8_t const *buffer) { uint8_t usb_buffer[USB_EP1OUT_SIZE]; int usb_ret; size_t remain; ssize_t count; usb_buffer[0] = EP1_CMD_MEMORY_WRITE; remain = length; count = 0; while (remain) { if (remain > (sizeof(usb_buffer) - 4)) length = (sizeof(usb_buffer) - 4); else length = remain; usb_buffer[1] = addr >> 8; usb_buffer[2] = addr; usb_buffer[3] = length; memcpy( usb_buffer + 4, buffer, length ); memset( usb_buffer + 4 + length, 0, sizeof(usb_buffer) - 4 - length ); int transferred; usb_ret = jtag_libusb_bulk_write( hdev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), LIBUSB_TIMEOUT_MS, &transferred ); if (usb_ret != ERROR_OK || transferred < (int)sizeof(usb_buffer)) break; addr += length; buffer += length; count += length; remain -= length; } return count; } #if 0 static ssize_t ep1_memory_writel(struct libusb_device_handle *hdev_param, uint16_t addr, size_t length, ...) { uint8_t buffer[USB_EP1OUT_SIZE - 4]; uint8_t *buffer_p; va_list ap; size_t remain; if (length > sizeof(buffer)) length = sizeof(buffer); remain = length; buffer_p = buffer; va_start(ap, length); while (remain > 0) { *buffer_p++ = va_arg(ap, int); remain--; } return ep1_memory_write(hdev_param, addr, length, buffer); } #endif #define DTCLOAD_COMMENT (0) #define DTCLOAD_ENTRY (1) #define DTCLOAD_LOAD (2) #define DTCLOAD_RUN (3) #define DTCLOAD_LUT_START (4) #define DTCLOAD_LUT (5) #define DTC_LOAD_BUFFER ST7_USB_BUF_EP2UIDO /* This gets set by the DTC loader */ static uint8_t dtc_entry_download; /* The buffer is specially formatted to represent a valid image to load into the DTC. */ static int dtc_load_from_buffer(struct libusb_device_handle *hdev_param, const uint8_t *buffer, size_t length) { struct header_s { uint8_t type; uint8_t length; }; int usb_err; struct header_s *header; uint8_t lut_start = 0xc0; dtc_entry_download = 0; /* Stop the DTC before loading anything. */ usb_err = ep1_generic_commandl( hdev_param, 1, EP1_CMD_DTC_STOP ); if (usb_err < 0) return usb_err; while (length) { if (length < sizeof(*header)) { LOG_ERROR("Malformed DTC image"); exit(1); } header = (struct header_s *)buffer; buffer += sizeof(*header); length -= sizeof(*header); if (length < (size_t)header->length + 1) { LOG_ERROR("Malformed DTC image"); exit(1); } switch (header->type) { case DTCLOAD_COMMENT: break; case DTCLOAD_ENTRY: /* store entry addresses somewhere */ if (!strncmp("download", (char *)buffer + 1, 8)) dtc_entry_download = buffer[0]; break; case DTCLOAD_LOAD: /* Send the DTC program to ST7 RAM. */ usb_err = ep1_memory_write( hdev_param, DTC_LOAD_BUFFER, header->length + 1, buffer ); if (usb_err < 0) return usb_err; /* Load it into the DTC. */ usb_err = ep1_generic_commandl( hdev_param, 3, EP1_CMD_DTC_LOAD, (DTC_LOAD_BUFFER >> 8), DTC_LOAD_BUFFER ); if (usb_err < 0) return usb_err; break; case DTCLOAD_RUN: usb_err = ep1_generic_commandl( hdev_param, 3, EP1_CMD_DTC_CALL, buffer[0], EP1_CMD_DTC_WAIT ); if (usb_err < 0) return usb_err; break; case DTCLOAD_LUT_START: lut_start = buffer[0]; break; case DTCLOAD_LUT: usb_err = ep1_memory_write( hdev_param, ST7_USB_BUF_EP0OUT + lut_start, header->length + 1, buffer ); if (usb_err < 0) return usb_err; break; default: LOG_ERROR("Invalid DTC image record type: 0x%02x", header->type); exit(1); break; } buffer += (header->length + 1); length -= (header->length + 1); } return 0; } /* * Start the DTC running in download mode (waiting for 512 byte command packets on ep2). */ static int dtc_start_download(void) { int usb_err; uint8_t ep2txr; int transferred; /* set up for download mode and make sure EP2 is set up to transmit */ usb_err = ep1_generic_commandl( hdev, 7, EP1_CMD_DTC_STOP, EP1_CMD_SET_UPLOAD, EP1_CMD_SET_DOWNLOAD, EP1_CMD_MEMORY_READ, /* read EP2TXR for its data toggle */ ST7_EP2TXR >> 8, ST7_EP2TXR, 1 ); if (usb_err < 0) return usb_err; /* read back ep2txr */ usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&ep2txr, 1, LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err != ERROR_OK) return usb_err; usb_err = ep1_generic_commandl( hdev, 13, EP1_CMD_MEMORY_WRITE, /* preinitialize poll byte */ DTC_STATUS_POLL_BYTE >> 8, DTC_STATUS_POLL_BYTE, 1, 0x00, EP1_CMD_MEMORY_WRITE, /* set EP2IN to return data */ ST7_EP2TXR >> 8, ST7_EP2TXR, 1, (ep2txr & ST7_EP2TXR_DTOG_TX) | ST7_EP2TXR_STAT_VALID, EP1_CMD_DTC_CALL, /* start running the DTC */ dtc_entry_download, EP1_CMD_DTC_GET_CACHED_STATUS ); if (usb_err < 0) return usb_err; /* wait for completion */ usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&ep2txr, 1, LIBUSB_TIMEOUT_MS, &transferred ); return usb_err; } static int dtc_run_download( struct libusb_device_handle *hdev_param, uint8_t *command_buffer, int command_buffer_size, uint8_t *reply_buffer, int reply_buffer_size ) { char dtc_status; int usb_err; int i; int transferred; LOG_DEBUG("%d/%d", command_buffer_size, reply_buffer_size); usb_err = jtag_libusb_bulk_write( hdev_param, USB_EP2OUT_ADDR, (char *)command_buffer, USB_EP2BANK_SIZE, LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err < 0) return usb_err; /* Wait for DTC to finish running command buffer */ for (i = 50;; ) { usb_err = ep1_generic_commandl( hdev_param, 4, EP1_CMD_MEMORY_READ, DTC_STATUS_POLL_BYTE >> 8, DTC_STATUS_POLL_BYTE, 1 ); if (usb_err < 0) return usb_err; usb_err = jtag_libusb_bulk_read( hdev_param, USB_EP1IN_ADDR, &dtc_status, 1, LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err < 0) return usb_err; if (dtc_status & 0x01) break; if (!--i) { LOG_ERROR("too many retries waiting for DTC status"); return LIBUSB_ERROR_TIMEOUT; } } if (reply_buffer && reply_buffer_size) { usb_err = jtag_libusb_bulk_read( hdev_param, USB_EP2IN_ADDR, (char *)reply_buffer, reply_buffer_size, LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err != ERROR_OK || transferred < reply_buffer_size) { LOG_ERROR("Read of endpoint 2 returned %d, expected %d", usb_err, reply_buffer_size ); return usb_err; } } return usb_err; } /* * The dtc reply queue is a singly linked list that describes what to do * with the reply packet that comes from the DTC. Only SCAN_IN and SCAN_IO generate * these entries. */ struct dtc_reply_queue_entry { struct dtc_reply_queue_entry *next; struct jtag_command *cmd; /* the command that resulted in this entry */ struct { uint8_t *buffer; /* the scan buffer */ int size; /* size of the scan buffer in bits */ int offset; /* how many bits were already done before this? */ int length; /* how many bits are processed in this operation? */ enum scan_type type; /* SCAN_IN/SCAN_OUT/SCAN_IO */ } scan; }; /* * The dtc_queue consists of a buffer of pending commands and a reply queue. * rlink_scan and tap_state_run add to the command buffer and maybe to the reply queue. */ static struct { struct dtc_reply_queue_entry *rq_head; struct dtc_reply_queue_entry *rq_tail; uint32_t cmd_index; uint32_t reply_index; uint8_t cmd_buffer[USB_EP2BANK_SIZE]; } dtc_queue; /* * The tap state queue is for accumulating TAP state changes without needlessly * flushing the dtc_queue. When it fills or is run, it adds the accumulated bytes to * the dtc_queue. */ static struct { uint32_t length; uint32_t buffer; } tap_state_queue; static int dtc_queue_init(void) { dtc_queue.rq_head = NULL; dtc_queue.rq_tail = NULL; dtc_queue.cmd_index = 0; dtc_queue.reply_index = 0; return 0; } static inline struct dtc_reply_queue_entry *dtc_queue_enqueue_reply( enum scan_type type, uint8_t *buffer, int size, int offset, int length, struct jtag_command *cmd) { struct dtc_reply_queue_entry *rq_entry; rq_entry = malloc(sizeof(struct dtc_reply_queue_entry)); if (rq_entry) { rq_entry->scan.type = type; rq_entry->scan.buffer = buffer; rq_entry->scan.size = size; rq_entry->scan.offset = offset; rq_entry->scan.length = length; rq_entry->cmd = cmd; rq_entry->next = NULL; if (!dtc_queue.rq_head) dtc_queue.rq_head = rq_entry; else dtc_queue.rq_tail->next = rq_entry; dtc_queue.rq_tail = rq_entry; } return rq_entry; } /* * Running the queue means that any pending command buffer is run * and any reply data dealt with. The command buffer is then cleared for subsequent processing. * The queue is automatically run by append when it is necessary to get space for the append. */ static int dtc_queue_run(void) { struct dtc_reply_queue_entry *rq_p, *rq_next; int retval; int usb_err; int bit_cnt; int x; uint8_t *dtc_p, *tdo_p; uint8_t dtc_mask, tdo_mask; uint8_t reply_buffer[USB_EP2IN_SIZE]; assert((!!dtc_queue.rq_head) == (dtc_queue.reply_index > 0)); assert(dtc_queue.cmd_index < USB_EP2BANK_SIZE); assert(dtc_queue.reply_index <= USB_EP2IN_SIZE); retval = ERROR_OK; if (dtc_queue.cmd_index < 1) return retval; dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_STOP; usb_err = dtc_run_download(hdev, dtc_queue.cmd_buffer, dtc_queue.cmd_index, reply_buffer, sizeof(reply_buffer) ); if (usb_err < 0) { LOG_ERROR("dtc_run_download: %s", libusb_error_name(usb_err)); exit(1); } if (dtc_queue.rq_head) { /* process the reply, which empties the reply queue and frees its entries */ dtc_p = reply_buffer; /* The rigamarole with the masks and doing it bit-by-bit is due to the fact that the *scan buffer is LSb-first and the DTC code is MSb-first for hardware reasons. It *was that or craft a function to do the reversal, and that wouldn't work with *bit-stuffing (supplying extra bits to use mostly byte operations), or any other *scheme which would throw the byte alignment off. */ for ( rq_p = dtc_queue.rq_head; rq_p; rq_p = rq_next ) { tdo_p = rq_p->scan.buffer + (rq_p->scan.offset / 8); tdo_mask = 1 << (rq_p->scan.offset % 8); bit_cnt = rq_p->scan.length; if (bit_cnt >= 8) { /* bytes */ dtc_mask = 1 << (8 - 1); for ( ; bit_cnt; bit_cnt-- ) { if (*dtc_p & dtc_mask) *tdo_p |= tdo_mask; else *tdo_p &= ~tdo_mask; dtc_mask >>= 1; if (dtc_mask == 0) { dtc_p++; dtc_mask = 1 << (8 - 1); } tdo_mask <<= 1; if (tdo_mask == 0) { tdo_p++; tdo_mask = 1; } } } else { /* extra bits or last bit */ x = *dtc_p++; if ((rq_p->scan.type == SCAN_IN) && ( rq_p->scan.offset != rq_p->scan.size - 1 )) { /* extra bits were sent as a full byte with padding on the *end */ dtc_mask = 1 << (8 - 1); } else dtc_mask = 1 << (bit_cnt - 1); for ( ; bit_cnt; bit_cnt-- ) { if (x & dtc_mask) *tdo_p |= tdo_mask; else *tdo_p &= ~tdo_mask; dtc_mask >>= 1; tdo_mask <<= 1; if (tdo_mask == 0) { tdo_p++; tdo_mask = 1; } } } if ((rq_p->scan.offset + rq_p->scan.length) >= rq_p->scan.size) { /* feed scan buffer back into openocd and free it */ if (jtag_read_buffer(rq_p->scan.buffer, rq_p->cmd->cmd.scan) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; free(rq_p->scan.buffer); } rq_next = rq_p->next; free(rq_p); } dtc_queue.rq_head = NULL; dtc_queue.rq_tail = NULL; } /* reset state for new appends */ dtc_queue.cmd_index = 0; dtc_queue.reply_index = 0; return retval; } /* runs the queue if it cannot take reserved_cmd bytes of command data * or reserved_reply bytes of reply data */ static int dtc_queue_run_if_full(int reserved_cmd, int reserved_reply) { /* reserve one additional byte for the STOP cmd appended during run */ if (dtc_queue.cmd_index + reserved_cmd + 1 > USB_EP2BANK_SIZE) return dtc_queue_run(); if (dtc_queue.reply_index + reserved_reply > USB_EP2IN_SIZE) return dtc_queue_run(); return ERROR_OK; } static int tap_state_queue_init(void) { tap_state_queue.length = 0; tap_state_queue.buffer = 0; return 0; } static int tap_state_queue_run(void) { int i; int bits; uint8_t byte_param; int retval; retval = 0; if (!tap_state_queue.length) return retval; bits = 1; byte_param = 0; for (i = tap_state_queue.length; i--; ) { byte_param <<= 1; if (tap_state_queue.buffer & 1) byte_param |= 1; if ((bits >= 8) || !i) { byte_param <<= (8 - bits); /* make sure there's room for two cmd bytes */ dtc_queue_run_if_full(2, 0); #ifdef USE_HARDWARE_SHIFTER_FOR_TMS if (bits == 8) { dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_SHIFT_TMS_BYTES(1); } else { #endif dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_SHIFT_TMS_BITS(bits); #ifdef USE_HARDWARE_SHIFTER_FOR_TMS } #endif dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = byte_param; byte_param = 0; bits = 1; } else bits++; tap_state_queue.buffer >>= 1; } retval = tap_state_queue_init(); return retval; } static int tap_state_queue_append(uint8_t tms) { int retval; if (tap_state_queue.length >= sizeof(tap_state_queue.buffer) * 8) { retval = tap_state_queue_run(); if (retval != 0) return retval; } if (tms) tap_state_queue.buffer |= (1 << tap_state_queue.length); tap_state_queue.length++; return 0; } static void rlink_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } static void rlink_state_move(void) { int i = 0, tms = 0; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); for (i = 0; i < tms_count; i++) { tms = (tms_scan >> i) & 1; tap_state_queue_append(tms); } tap_set_state(tap_get_end_state()); } static void rlink_path_move(struct pathmove_command *cmd) { int num_states = cmd->num_states; int state_count; int tms = 0; state_count = 0; while (num_states) { if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) tms = 0; else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count]) tms = 1; else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(cmd->path[state_count])); exit(-1); } tap_state_queue_append(tms); tap_set_state(cmd->path[state_count]); state_count++; num_states--; } tap_set_end_state(tap_get_state()); } static void rlink_runtest(int num_cycles) { int i; tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in RTI */ if (tap_get_state() != TAP_IDLE) { rlink_end_state(TAP_IDLE); rlink_state_move(); } /* execute num_cycles */ for (i = 0; i < num_cycles; i++) tap_state_queue_append(0); /* finish in end_state */ rlink_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) rlink_state_move(); } /* (1) assert or (0) deassert reset lines */ static void rlink_reset(int trst, int srst) { uint8_t bitmap; int usb_err; int transferred; /* Read port A for bit op */ usb_err = ep1_generic_commandl( hdev, 4, EP1_CMD_MEMORY_READ, ST7_PADR >> 8, ST7_PADR, 1 ); if (usb_err < 0) { LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&bitmap, 1, LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err != ERROR_OK || transferred < 1) { LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } if (trst) bitmap &= ~ST7_PA_NTRST; else bitmap |= ST7_PA_NTRST; /* Write port A and read port B for bit op * port B has no OR, and we want to emulate open drain on NSRST, so we initialize DR to 0 *and assert NSRST by setting DDR to 1. */ usb_err = ep1_generic_commandl( hdev, 9, EP1_CMD_MEMORY_WRITE, ST7_PADR >> 8, ST7_PADR, 1, bitmap, EP1_CMD_MEMORY_READ, ST7_PBDDR >> 8, ST7_PBDDR, 1 ); if (usb_err < 0) { LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&bitmap, 1, LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err != ERROR_OK || transferred < 1) { LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } if (srst) bitmap |= ST7_PB_NSRST; else bitmap &= ~ST7_PB_NSRST; /* write port B and read dummy to ensure completion before returning */ usb_err = ep1_generic_commandl( hdev, 6, EP1_CMD_MEMORY_WRITE, ST7_PBDDR >> 8, ST7_PBDDR, 1, bitmap, EP1_CMD_DTC_GET_CACHED_STATUS ); if (usb_err < 0) { LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&bitmap, 1, LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err != ERROR_OK || transferred < 1) { LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } } static int rlink_scan(struct jtag_command *cmd, enum scan_type type, uint8_t *buffer, int scan_size) { bool ir_scan; tap_state_t saved_end_state; int byte_bits; int extra_bits; int chunk_bits; int chunk_bytes; int x; int tdi_bit_offset; uint8_t tdi_mask, *tdi_p; uint8_t dtc_mask; if (scan_size < 1) { LOG_ERROR("scan_size cannot be less than 1 bit"); exit(1); } ir_scan = cmd->cmd.scan->ir_scan; /* Move to the proper state before starting to shift TDI/TDO. */ if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) || (ir_scan && (tap_get_state() == TAP_IRSHIFT)))) { saved_end_state = tap_get_end_state(); rlink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); rlink_state_move(); rlink_end_state(saved_end_state); } tap_state_queue_run(); #if 0 printf("scan_size = %d, type = 0x%x\n", scan_size, type); { int i; /* clear unused bits in scan buffer for ease of debugging * (it makes diffing output easier) */ buffer[scan_size / 8] &= ((1 << ((scan_size - 1) % 8) + 1) - 1); printf("before scan:"); for (i = 0; i < (scan_size + 7) / 8; i++) printf(" %02x", buffer[i]); printf("\n"); } #endif /* The number of bits that can be shifted as complete bytes */ byte_bits = (int)(scan_size - 1) / 8 * 8; /* The number of bits left over, not counting the last bit */ extra_bits = (scan_size - 1) - byte_bits; tdi_bit_offset = 0; tdi_p = buffer; tdi_mask = 1; if (extra_bits && (type == SCAN_OUT)) { /* Schedule any extra bits into the DTC command buffer, padding as needed * For SCAN_OUT, this comes before the full bytes so the (leading) padding bits will *fall off the end */ /* make sure there's room for two cmd bytes */ dtc_queue_run_if_full(2, 0); x = 0; dtc_mask = 1 << (extra_bits - 1); while (extra_bits--) { if (*tdi_p & tdi_mask) x |= dtc_mask; dtc_mask >>= 1; tdi_mask <<= 1; if (tdi_mask == 0) { tdi_p++; tdi_mask = 1; } } dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_SHIFT_TDI_BYTES(1); dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; } /* Loop scheduling full bytes into the DTC command buffer */ while (byte_bits) { /* make sure there's room for one (for in scans) or two cmd bytes and * at least one reply byte for in or inout scans*/ dtc_queue_run_if_full(type == SCAN_IN ? 1 : 2, type != SCAN_OUT ? 1 : 0); chunk_bits = byte_bits; /* we can only use up to 16 bytes at a time */ if (chunk_bits > (16 * 8)) chunk_bits = (16 * 8); if (type != SCAN_IN) { /* how much is there room for, considering stop and byte op? */ x = (sizeof(dtc_queue.cmd_buffer) - (dtc_queue.cmd_index + 1 + 1)) * 8; if (chunk_bits > x) chunk_bits = x; } if (type != SCAN_OUT) { /* how much is there room for in the reply buffer? */ x = (USB_EP2IN_SIZE - dtc_queue.reply_index) * 8; if (chunk_bits > x) chunk_bits = x; } /* so the loop will end */ byte_bits -= chunk_bits; if (type != SCAN_OUT) { if (!dtc_queue_enqueue_reply(type, buffer, scan_size, tdi_bit_offset, chunk_bits, cmd)) { LOG_ERROR("enqueuing DTC reply entry: %s", strerror(errno)); exit(1); } dtc_queue.reply_index += (chunk_bits + 7) / 8; tdi_bit_offset += chunk_bits; } /* chunk_bits is a multiple of 8, so there are no rounding issues. */ chunk_bytes = chunk_bits / 8; switch (type) { case SCAN_IN: x = DTC_CMD_SHIFT_TDO_BYTES(chunk_bytes); break; case SCAN_OUT: x = DTC_CMD_SHIFT_TDI_BYTES(chunk_bytes); break; default: x = DTC_CMD_SHIFT_TDIO_BYTES(chunk_bytes); break; } dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; if (type != SCAN_IN) { x = 0; dtc_mask = 1 << (8 - 1); while (chunk_bits--) { if (*tdi_p & tdi_mask) x |= dtc_mask; dtc_mask >>= 1; if (dtc_mask == 0) { dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; x = 0; dtc_mask = 1 << (8 - 1); } tdi_mask <<= 1; if (tdi_mask == 0) { tdi_p++; tdi_mask = 1; } } } } if (extra_bits && (type != SCAN_OUT)) { /* Schedule any extra bits into the DTC command buffer */ /* make sure there's room for one (for in scans) or two cmd bytes * and one reply byte */ dtc_queue_run_if_full(type == SCAN_IN ? 1 : 2, 1); if (!dtc_queue_enqueue_reply(type, buffer, scan_size, tdi_bit_offset, extra_bits, cmd)) { LOG_ERROR("enqueuing DTC reply entry: %s", strerror(errno)); exit(1); } dtc_queue.reply_index++; tdi_bit_offset += extra_bits; if (type == SCAN_IN) { dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_SHIFT_TDO_BYTES(1); } else { dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_SHIFT_TDIO_BITS(extra_bits); x = 0; dtc_mask = 1 << (8 - 1); while (extra_bits--) { if (*tdi_p & tdi_mask) x |= dtc_mask; dtc_mask >>= 1; tdi_mask <<= 1; if (tdi_mask == 0) { tdi_p++; tdi_mask = 1; } } dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; } } /* Schedule the last bit into the DTC command buffer */ /* make sure there's room for one cmd byte and one reply byte * for in or inout scans*/ dtc_queue_run_if_full(1, type == SCAN_OUT ? 0 : 1); if (type == SCAN_OUT) { dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(1, (*tdi_p & tdi_mask), 0); } else { if (!dtc_queue_enqueue_reply(type, buffer, scan_size, tdi_bit_offset, 1, cmd)) { LOG_ERROR("enqueuing DTC reply entry: %s", strerror(errno)); exit(1); } dtc_queue.reply_index++; dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(1, (*tdi_p & tdi_mask), 1); } /* Move to pause state */ tap_state_queue_append(0); tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) rlink_state_move(); return 0; } static int rlink_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; int retval, tmp_retval; /* return ERROR_OK, unless something goes wrong */ retval = ERROR_OK; #ifndef AUTOMATIC_BUSY_LED /* turn LED on */ ep1_generic_commandl(hdev, 2, EP1_CMD_SET_PORTD_LEDS, ~(ST7_PD_NBUSY_LED) ); #endif while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: case JTAG_TLR_RESET: case JTAG_PATHMOVE: case JTAG_SCAN: break; default: /* some events, such as resets, need a queue flush to ensure *consistency */ tap_state_queue_run(); dtc_queue_run(); break; } switch (cmd->type) { case JTAG_RESET: LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); if ((cmd->cmd.reset->trst == 1) || (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) tap_set_state(TAP_RESET); rlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); if (cmd->cmd.runtest->end_state != -1) rlink_end_state(cmd->cmd.runtest->end_state); rlink_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); if (cmd->cmd.statemove->end_state != -1) rlink_end_state(cmd->cmd.statemove->end_state); rlink_state_move(); break; case JTAG_PATHMOVE: LOG_DEBUG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); rlink_path_move(cmd->cmd.pathmove); break; case JTAG_SCAN: LOG_DEBUG_IO("%s scan end in %i", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", cmd->cmd.scan->end_state); if (cmd->cmd.scan->end_state != -1) rlink_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); if (rlink_scan(cmd, type, buffer, scan_size) != ERROR_OK) retval = ERROR_FAIL; break; case JTAG_SLEEP: LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); jtag_sleep(cmd->cmd.sleep->us); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } /* Flush the DTC queue to make sure any pending reads have been done before exiting this *function */ tap_state_queue_run(); tmp_retval = dtc_queue_run(); if (tmp_retval != ERROR_OK) retval = tmp_retval; #ifndef AUTOMATIC_BUSY_LED /* turn LED off */ ep1_generic_commandl(hdev, 2, EP1_CMD_SET_PORTD_LEDS, ~0 ); #endif return retval; } /* Using an unindexed table because it is infrequently accessed and it is short. The table must be *in order of ascending speed (and descending prescaler), as it is scanned in reverse. */ static int rlink_speed(int speed) { int i; if (speed == 0) { /* fastest speed */ speed = rlink_speed_table[rlink_speed_table_size - 1].prescaler; } for (i = rlink_speed_table_size; i--; ) { if (rlink_speed_table[i].prescaler == speed) { if (dtc_load_from_buffer(hdev, rlink_speed_table[i].dtc, rlink_speed_table[i].dtc_size) != 0) { LOG_ERROR( "An error occurred while trying to load DTC code for speed \"%d\".", speed); exit(1); } int ret = dtc_start_download(); if (ret < 0) { LOG_ERROR("starting DTC: %s", libusb_error_name(ret)); exit(1); } return ERROR_OK; } } LOG_ERROR("%d is not a supported speed", speed); return ERROR_FAIL; } static int rlink_speed_div(int speed, int *khz) { int i; for (i = rlink_speed_table_size; i--; ) { if (rlink_speed_table[i].prescaler == speed) { *khz = rlink_speed_table[i].khz; return ERROR_OK; } } LOG_ERROR("%d is not a supported speed", speed); return ERROR_FAIL; } static int rlink_khz(int khz, int *speed) { int i; if (khz == 0) { LOG_ERROR("RCLK not supported"); return ERROR_FAIL; } for (i = rlink_speed_table_size; i--; ) { if (rlink_speed_table[i].khz <= khz) { *speed = rlink_speed_table[i].prescaler; return ERROR_OK; } } LOG_WARNING("The lowest supported JTAG speed is %d KHz", rlink_speed_table[0].khz); *speed = rlink_speed_table[0].prescaler; return ERROR_OK; } static int rlink_init(void) { int i, j, retries; uint8_t reply_buffer[USB_EP1IN_SIZE]; int transferred; const uint16_t vids[] = { USB_IDVENDOR, 0 }; const uint16_t pids[] = { USB_IDPRODUCT, 0 }; if (jtag_libusb_open(vids, pids, &hdev, NULL) != ERROR_OK) return ERROR_FAIL; struct libusb_device_descriptor descriptor; struct libusb_device *usb_dev = libusb_get_device(hdev); int r = libusb_get_device_descriptor(usb_dev, &descriptor); if (r < 0) { LOG_ERROR("error %d getting device descriptor", r); return ERROR_FAIL; } if (descriptor.bNumConfigurations > 1) { LOG_ERROR("Whoops! NumConfigurations is not 1, don't know what to do..."); return ERROR_FAIL; } struct libusb_config_descriptor *config; libusb_get_config_descriptor(usb_dev, 0, &config); if (config->bNumInterfaces > 1) { LOG_ERROR("Whoops! NumInterfaces is not 1, don't know what to do..."); return ERROR_FAIL; } LOG_DEBUG("Opened device, hdev = %p", hdev); /* usb_set_configuration required under win32 */ libusb_set_configuration(hdev, config->bConfigurationValue); retries = 3; do { i = libusb_claim_interface(hdev, 0); if (i != LIBUSB_SUCCESS) { LOG_ERROR("usb_claim_interface: %s", libusb_error_name(i)); j = libusb_detach_kernel_driver(hdev, 0); if (j != LIBUSB_SUCCESS) LOG_ERROR("detach kernel driver: %s", libusb_error_name(j)); } else { LOG_DEBUG("interface claimed!"); break; } } while (--retries); if (i != LIBUSB_SUCCESS) { LOG_ERROR("Initialisation failed."); return ERROR_FAIL; } if (libusb_set_interface_alt_setting(hdev, 0, 0) != LIBUSB_SUCCESS) { LOG_ERROR("Failed to set interface."); return ERROR_FAIL; } /* The device starts out in an unknown state on open. As such, * result reads time out, and it's not even known whether the * command was accepted. So, for this first command, we issue * it repeatedly until its response doesn't time out. Also, if * sending a command is going to time out, we find that out here. * * It must be possible to open the device in such a way that * this special magic isn't needed, but, so far, it escapes us. */ for (i = 0; i < 5; i++) { j = ep1_generic_commandl( hdev, 1, EP1_CMD_GET_FWREV ); if (j < USB_EP1OUT_SIZE) { LOG_ERROR("USB write error: %s", libusb_error_name(j)); return ERROR_FAIL; } j = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)reply_buffer, sizeof(reply_buffer), 200, &transferred ); if (j != LIBUSB_ERROR_TIMEOUT) break; } if (j != ERROR_OK || transferred != (int)sizeof(reply_buffer)) { LOG_ERROR("USB read error: %s", libusb_error_name(j)); return ERROR_FAIL; } LOG_DEBUG(INTERFACE_NAME " firmware version: %d.%d.%d", reply_buffer[0], reply_buffer[1], reply_buffer[2]); if ((reply_buffer[0] != 0) || (reply_buffer[1] != 0) || (reply_buffer[2] != 3)) LOG_WARNING( "The rlink device is not of the version that the developers have played with. It may or may not work."); /* Probe port E for adapter presence */ ep1_generic_commandl( hdev, 16, EP1_CMD_MEMORY_WRITE, /* Drive sense pin with 0 */ ST7_PEDR >> 8, ST7_PEDR, 3, 0x00, /* DR */ ST7_PE_ADAPTER_SENSE_OUT, /* DDR */ ST7_PE_ADAPTER_SENSE_OUT, /* OR */ EP1_CMD_MEMORY_READ, /* Read back */ ST7_PEDR >> 8, ST7_PEDR, 1, EP1_CMD_MEMORY_WRITE, /* Drive sense pin with 1 */ ST7_PEDR >> 8, ST7_PEDR, 1, ST7_PE_ADAPTER_SENSE_OUT ); jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)reply_buffer, 1, LIBUSB_TIMEOUT_MS, &transferred ); if ((reply_buffer[0] & ST7_PE_ADAPTER_SENSE_IN) != 0) LOG_WARNING("target detection problem"); ep1_generic_commandl( hdev, 11, EP1_CMD_MEMORY_READ, /* Read back */ ST7_PEDR >> 8, ST7_PEDR, 1, EP1_CMD_MEMORY_WRITE, /* float port E */ ST7_PEDR >> 8, ST7_PEDR, 3, 0x00, /* DR */ 0x00, /* DDR */ 0x00 /* OR */ ); jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)reply_buffer, 1, LIBUSB_TIMEOUT_MS, &transferred ); if ((reply_buffer[0] & ST7_PE_ADAPTER_SENSE_IN) == 0) LOG_WARNING("target not plugged in"); /* float ports A and B */ ep1_generic_commandl( hdev, 11, EP1_CMD_MEMORY_WRITE, ST7_PADDR >> 8, ST7_PADDR, 2, 0x00, 0x00, EP1_CMD_MEMORY_WRITE, ST7_PBDDR >> 8, ST7_PBDDR, 1, 0x00 ); /* make sure DTC is stopped, set VPP control, set up ports A and B */ ep1_generic_commandl( hdev, 14, EP1_CMD_DTC_STOP, EP1_CMD_SET_PORTD_VPP, ~(ST7_PD_VPP_SHDN), EP1_CMD_MEMORY_WRITE, ST7_PADR >> 8, ST7_PADR, 2, ((~(0)) & (ST7_PA_NTRST)), (ST7_PA_NTRST), /* port B has no OR, and we want to emulate open drain on NSRST, so we set DR to 0 *here and later assert NSRST by setting DDR bit to 1. */ EP1_CMD_MEMORY_WRITE, ST7_PBDR >> 8, ST7_PBDR, 1, 0x00 ); /* set LED updating mode and make sure they're unlit */ ep1_generic_commandl( hdev, 3, #ifdef AUTOMATIC_BUSY_LED EP1_CMD_LEDUE_BUSY, #else EP1_CMD_LEDUE_NONE, #endif EP1_CMD_SET_PORTD_LEDS, ~0 ); tap_state_queue_init(); dtc_queue_init(); rlink_reset(0, 0); return ERROR_OK; } static int rlink_quit(void) { /* stop DTC and make sure LEDs are off */ ep1_generic_commandl( hdev, 6, EP1_CMD_DTC_STOP, EP1_CMD_LEDUE_NONE, EP1_CMD_SET_PORTD_LEDS, ~0, EP1_CMD_SET_PORTD_VPP, ~0 ); libusb_release_interface(hdev, 0); libusb_close(hdev); return ERROR_OK; } static struct jtag_interface rlink_interface = { .execute_queue = rlink_execute_queue, }; struct adapter_driver rlink_adapter_driver = { .name = "rlink", .transports = jtag_only, .init = rlink_init, .quit = rlink_quit, .speed = rlink_speed, .khz = rlink_khz, .speed_div = rlink_speed_div, .jtag_ops = &rlink_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/rlink.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2008 Lou Deluxe * * lou.openocd012@fixit.nospammail.net * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_RLINK_H #define OPENOCD_JTAG_DRIVERS_RLINK_H #include "helper/types.h" struct rlink_speed_table { uint8_t const *dtc; uint16_t dtc_size; uint16_t khz; uint8_t prescaler; }; extern const struct rlink_speed_table rlink_speed_table[]; extern const size_t rlink_speed_table_size; #endif /* OPENOCD_JTAG_DRIVERS_RLINK_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/rlink_call.m4 ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Copyright (C) 2008 Lou Deluxe # lou.openocd012@fixit.nospammail.net # m4_divert(`-1') m4_dnl Setup and hold times depend on SHIFTER_PRESCALER m4_define(`SETUP_DELAY_CYCLES', m4_eval(`('SHIFTER_PRESCALER` + 1) / 2')) m4_define(`HOLD_DELAY_CYCLES', m4_eval(`'SHIFTER_PRESCALER` / 2')) m4_dnl Some macros to make nybble handling a little easier m4_define(`m4_high_nybble', `m4_eval(`(($1) >> 4) & 0xf')') m4_define(`m4_low_nybble', `m4_eval(`($1) & 0xf')') m4_dnl A macro to generate a number of NOPs depending on the argument m4_define(`m4_0_to_5_nops', `m4_ifelse(m4_eval(`($1) >= 1'), 1, ` NOP 'm4_ifelse(m4_eval(`($1) >= 2'), 1, ` NOP 'm4_ifelse(m4_eval(`($1) >= 3'), 1, ` NOP 'm4_ifelse(m4_eval(`($1) >= 4'), 1, ` NOP 'm4_ifelse(m4_eval(`($1) >= 5'), 1, ` NOP ')))))') m4_dnl Some macros to facilitate bit-banging delays. m4_dnl There are 3 of them. One for self-contained delays, and two for those which must be split between setup and loop to keep from disturbing A at delay time. m4_dnl The argument passed to any of them is the number of cycles which the delay should consume. m4_dnl This one is self-contained. m4_define(`m4_delay', `; delay (m4_eval($1) cycles)' `m4_ifelse(m4_eval(`('$1`) < 6'), 1, m4_0_to_5_nops($1) , m4_ifelse(m4_eval(`(('$1`) - 3) % 2'), 1, ` NOP') A.H = m4_high_nybble(`(('$1`) - 3) / 2') A.L = m4_low_nybble(`(('$1`) - 3) / 2') Y = A DECY JP -1 )') m4_dnl These are the setup and loop parts of the split delay. m4_dnl The argument passed to both must match for the result to make sense. m4_dnl The setup does not figure into the delay. It takes 3 cycles when a loop is used and none if nops are used. m4_define(`m4_delay_setup', `; delay setup (m4_eval($1) cycles)' `m4_ifelse(m4_eval(`('$1`) < 6'), 0, ` ' A.H = m4_high_nybble(`('$1`) / 2') A.L = m4_low_nybble(`('$1`) / 2') Y = A )') m4_define(`m4_delay_loop', `; delay loop (m4_eval($1) cycles)' `m4_ifelse(m4_eval(`('$1`) < 6'), 1, m4_0_to_5_nops($1) , m4_ifelse(m4_eval(`('$1`) % 2'), 1, ` NOP') DECY JP -1 )') m4_dnl These are utility macros for use with delays. Specifically, there is code below which needs some predictability in code size for relative jumps to reach. The m4_delay macro generates an extra NOP when an even delay is needed, and the m4_delay_loop macro generates an extra NOP when an odd delay is needed. Using this for the argument to the respective macro rounds up the argument so that the extra NOP will not be generated. There is also logic built in to cancel the rounding when the result is small enough that a loop would not be generated. m4_define(`m4_delay_loop_round_up', `m4_ifelse(m4_eval($1` < 6'), 1, $1, m4_eval(`(('$1`) + 1) / 2 * 2'))') m4_define(`m4_delay_round_up', `m4_ifelse(m4_eval($1` < 6'), 1, $1, m4_eval(`(('$1`) / 2 * 2) + 1'))') m4_divert(`0')m4_dnl ;------------------------------------------------------------------------------ :opcode_error ; This is at address 0x00 in case of empty LUT entries STATUS STOP ERROR ;------------------------------------------------------------------------------ ; Command interpreter at address 0x01 because it is branched to a lot and having it be 0x01 means we can use X for it, which is already used for other purposes which want it to be 1. ; Assumes X is 1 ; Assumes ADR_BUFFER0 points to the next command byte ; Stores the current command byte in CMP01 :command_interpreter A = DATA_BUFFER0 ADR_BUFFER0 += X CMP01 = A ; store the current command for later EXCHANGE ; put MSN into LSN A.H = 0xc ; lookup table at 0x1550 + 0xc0 = 0x1610 ; branch to address in lookup table Y = A A = <Y> BRANCH ;------------------------------------------------------------------------------ ; LUT for high nybble ;LUT; c0 opcode_error ;LUT; c1 opcode_shift_tdi_andor_tms_bytes ;LUT; c2 opcode_shift_tdi_andor_tms_bytes ;LUT; c3 opcode_shift_tdi_andor_tms_bytes ;LUT; c4 opcode_shift_tdo_bytes ;LUT; c5 opcode_error ;LUT; c6 opcode_shift_tdio_bytes ;LUT; c7 opcode_error ;LUT; c8 opcode_shift_tms_tdi_bit_pair ;LUT; c9 opcode_shift_tms_bits ;LUT; ca opcode_error ;LUT; cb opcode_error ;LUT; cc opcode_error ;LUT; cd opcode_error ;LUT; ce opcode_shift_tdio_bits ;LUT; cf opcode_stop ;------------------------------------------------------------------------------ ; USB/buffer handling ; ;ENTRY; download entry_download opcode_stop: opcode_next_buffer: ; pointer to completion flag A.H = 0xf A.L = 0xf Y = A A = OR_MPEG ; buffer indicator from previous iteration <Y> = A ; either indicator will have bit 0 set BSET 1 ; was buffer 1 previously current? ; A.H = 0 ; already zero from OR_MPEG JP opcode_next_buffer_0 opcode_next_buffer_1: A.L = 0x1 ; ack buffer 0 BUFFER_MNGT = A ; A.H = 0x0 ; already zero from BUFFER_MNGT A.L = 0x3 ; Input buffer 1 = 0x1850 (0x0300) JP +4 opcode_next_buffer_0: A.L = 0x2 ; ack buffer 1 BUFFER_MNGT = A entry_download: A = X ; Input buffer 0 = 0x1650 (0x0100) ADR_BUFFER01 = A OR_MPEG = A ; store for next iteration A.L = 0x0 BUFFER_MNGT = A ; finish acking previous buffer Y = A ADR_BUFFER00 = A ADR_BUFFER11 = A A.H = 0x4 ; Output buffer = 0x1590 (0x0040) ADR_BUFFER10 = A EXCHANGE ; 0x04 X = A ; for the spin loop below ; pointer to status in shared memory DECY ; setting to 0 above and decrementing here saves a byte ; wait until a command buffer is available A = BUFFER_MNGT ; spin while neither of bits 2 or 3 are set CP A<X ; this is slightly faster and smaller than trying to AND and compare the result, and it lets us just use the nybble-swapped 0x40 from the output buffer setup. JP -2 <Y> = A ; update status once done spinning ; restore X, since we used it ; A.H = 0 ; high nybble of BUFFER_MNGT will always be 0 the way we use it A.L = 1 X = A ; go to command interpreter BRANCH ;;------------------------------------------------------------------------------ ;:opcode_stop ;; ; ; ; Ack buffer 0 in download mode ; A.L = 0x1 ; BUFFER_MNGT = A ; ; STATUS STOP ;------------------------------------------------------------------------------ :opcode_shift_tdi_andor_tms_bytes ; A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1 A.H = 0 Y = A ; loop counter A = CMP01 EXCHANGE CMP01 = A ; we're interested in bits in the high nybble opcode_shift_tdi_andor_tms_bytes__loop: ; set tdi to supplied byte or zero A = CMP01 BSET 1 JP +4 A.H = 0 A.L = 0 JP +3 A = DATA_BUFFER0 ADR_BUFFER0 += X SHIFT_MPEG = A ; set tms to supplied byte or zero A = CMP01 BCLR 0 JP +5 A = DATA_BUFFER0 ADR_BUFFER0 += X SHIFT_CARD = A SHIFT CARD OUT=>PIN0 ; run both shifters as nearly simultaneously as possible SHIFT MPEG OUT=>PIN1 A = CTRL_FCI EXCHANGE BCLR 3 JP -3 DECY JP opcode_shift_tdi_andor_tms_bytes__loop A = X BRANCH ;------------------------------------------------------------------------------ :opcode_shift_tdo_bytes ; A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1 A.H = 0 Y = A ; loop counter opcode_shift_tdo_bytes__loop: SHIFT MPEG PIN0=>IN A = CTRL_FCI EXCHANGE BCLR 3 JP -3 ; put shifted byte into output buffer A = SHIFT_MPEG DATA_BUFFER1 = A ADR_BUFFER1 += X DECY JP opcode_shift_tdo_bytes__loop A = X BRANCH ;------------------------------------------------------------------------------ :opcode_shift_tdio_bytes ; A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1 A.H = 0 CMP10 = A ; byte loop counter A.H = opcode_shift_tdio_bytes__sub_return A.L = opcode_shift_tdio_bytes__sub_return CMP00 = A ; return address opcode_shift_tdio_bytes__loop: A.H = 0 A.L = 7 CMP11 = A ; always use 8 bits JP sub_shift_tdio_bits opcode_shift_tdio_bytes__sub_return: A = CMP10 ; byte loop counter CP A=>X CLC A -= X CMP10 = A JP opcode_shift_tdio_bytes__loop A = X ;DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it BRANCH ;------------------------------------------------------------------------------ :opcode_shift_tdio_bits ; A = CMP01 ; bits 2..0 contain the number of bits to shift - 1 A.H = 0 BCLR 3 ; set TMS=1 if bit 3 was set CMP11 = A ; bit loop counter A.H = opcode_shift_tdio_bits__sub_return A.L = opcode_shift_tdio_bits__sub_return CMP00 = A ; return address JP sub_shift_tdio_bits A.L = 0x1 ; TMS=1 DR_CARD = A JP sub_shift_tdio_bits opcode_shift_tdio_bits__sub_return: A = X ;DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it BRANCH ;------------------------------------------------------------------------------ :sub_shift_tdio_bits ; A = DATA_BUFFER0 ; get byte from input buffer ADR_BUFFER0 += X MASK = A ; put it in MASK where bit routine will use it :sub_shift_tdio_bits__loop m4_delay_setup(m4_delay_loop_round_up(SETUP_DELAY_CYCLES - 1)) A = MASK ; shift TDO into and TDI out of MASK via carry A += MASK MASK = A ; shifting out TDI A.L = 0x2 ; TCK=0, TDI=1 CP CARRY JP +2 A.L = 0x0 ; TCK=0, TDI=0 DR_MPEG = A m4_delay_loop(m4_delay_loop_round_up(SETUP_DELAY_CYCLES - 1)) BSET 2 ; TCK high DR_MPEG = A A = DR_MPEG ; set carry bit to TDO CLC BCLR 0 JP +2 SEC m4_delay(HOLD_DELAY_CYCLES - 10) A = CMP11 ; bit loop counter Y = A ; use Y to avoid corrupting carry bit with subtract DECY A = Y CMP11 = A JP :sub_shift_tdio_bits__loop ; shift last TDO bit into result A = MASK A += MASK DATA_BUFFER1 = A ADR_BUFFER1 += X A = CMP00 ; return to caller BRANCH ;------------------------------------------------------------------------------ :opcode_shift_tms_tdi_bit_pair ; ; set TMS line manually A = CMP01 ; bits 3..0 contain TDI and TMS bits and whether to return TDO BSET 0 ; TMS bit A.L = 0x1 ; TMS=1 JP +2 A.L = 0x0 ; TMS=0 DR_CARD = A ; stuff command buffer with bitmap of single TDI bit A = CMP01 BSET 1 ; TDI bit A.H = 0x8 ; TDI=1 JP +2 A.H = 0x0 ; TDI=0 ADR_BUFFER0 -= X DATA_BUFFER0 = A A.H = 0 A.L = 0 CMP11 = A ; bit loop counter (only doing one bit) A.H = opcode_shift_tms_tdi_bit_pair__sub_return A.L = opcode_shift_tms_tdi_bit_pair__sub_return CMP00 = A ; return address ; jump this way due to relative jump range issues A.H = sub_shift_tdio_bits A.L = sub_shift_tdio_bits BRANCH opcode_shift_tms_tdi_bit_pair__sub_return: A = CMP01 BSET 3 ; bit says whether to return TDO JP +2 ADR_BUFFER1 -= X ; subroutine returns it, so undo that A = X DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it BRANCH ;------------------------------------------------------------------------------ :opcode_shift_tms_bits ; A = CMP01 ; bits 3..0 contain the number of bits to shift - 1 (only 1-8 bits is valid... no checking, just improper operation) A.H = 0 CMP11 = A ; bit loop counter A = DATA_BUFFER0 ; get byte from input buffer ADR_BUFFER0 += X MASK = A ; The byte we'll be shifting :opcode_shift_tms_bits__loop m4_delay_setup(SETUP_DELAY_CYCLES - 1) A = MASK ; shift TMS out of MASK via carry A += MASK MASK = A ; shifting out TMS A.L = 0x1 ; TCK=0, TDI=0, TMS=1 CP CARRY JP +2 A.L = 0x0 ; TCK=0, TDI=0, TMS=0 DR_CARD = A DR_MPEG = A m4_delay_loop(SETUP_DELAY_CYCLES - 1) BSET 2 ; TCK high DR_MPEG = A m4_delay(HOLD_DELAY_CYCLES - 10) A = CMP11 ; bit loop counter CP A=>X CLC A -= X CMP11 = A JP :opcode_shift_tms_bits__loop A = X DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it BRANCH ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/rlink_dtc_cmd.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2008 Lou Deluxe * * lou.openocd012@fixit.nospammail.net * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_RLINK_DTC_CMD_H #define OPENOCD_JTAG_DRIVERS_RLINK_DTC_CMD_H /* A command position with the high nybble of 0x0 is reserved for an error condition. * If executed, it stops the DTC and raises the ERROR flag */ #define DTC_CMD_SHIFT_TMS_BYTES(bytes) ((0x1 << 4) | ((bytes) - 1)) /* Shift 1-16 bytes out TMS. TDI is 0. */ /* Bytes to shift follow. */ #define DTC_CMD_SHIFT_TDI_BYTES(bytes) ((0x2 << 4) | ((bytes) - 1)) /* Shift 1-16 bytes out TDI. TMS is 0. */ /* Bytes to shift follow. */ #define DTC_CMD_SHIFT_TDI_AND_TMS_BYTES(bytes) ((0x3 << 4) | ((bytes) - 1)) /* Shift 1-16 byte pairs out TDI and TMS. */ /* Byte pairs to shift follow in TDI, TMS order. */ #define DTC_CMD_SHIFT_TDO_BYTES(bytes) ((0x4 << 4) | ((bytes) - 1)) /* Shift 1-16 bytes in TDO. TMS is unaffected. */ /* Reply buffer contains bytes shifted in. */ #define DTC_CMD_SHIFT_TDIO_BYTES(bytes) ((0x6 << 4) | ((bytes) - 1)) /* Shift 1-16 bytes out TDI and in TDO. TMS is unaffected. */ #define DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(tms, tdi, tdo) ((0x8 << 4) | (\ (tms) ? (1 << 0) : 0 \ ) | (\ (tdi) ? (1 << 1) : 0 \ ) | (\ (tdo) ? (1 << 3) : 0 \ )) /* Single bit shift. * tms and tdi are the levels shifted out on TMS and TDI, respectively. * tdo indicates whether a byte will be returned in the reply buffer with its * least significant bit set to reflect TDO * Care should be taken when tdo is zero, as the underlying code actually does put * that byte in the reply buffer. Setting tdo to zero just moves the pointer back. * The result is that if this command is executed when the reply buffer is already full, * a byte will be written erroneously to memory not belonging to the reply buffer. * This could be worked around at the expense of DTC code space and speed. */ #define DTC_CMD_SHIFT_TMS_BITS(bits) ((0x9 << 4) | ((bits) - 1)) /* Shift 1-8 bits out TMS. */ /* Bits to be shifted out are left justified in the following byte. */ #define DTC_CMD_SHIFT_TDIO_BITS(bits) ((0xe << 4) | ((bits) - 1)) /* Shift 1-8 bits out TDI and in TDO, TMS is unaffected. */ /* Bits to be shifted out are left justified in the following byte. */ /* Bits shifted in are right justified in the byte placed in the reply buffer. */ #define DTC_CMD_STOP (0xf << 4) /* Stop processing the command buffer and wait for the next one. */ /* A shared status byte is updated with bit 0 set when this has happened, * and it is cleared when a new command buffer becomes ready. * The host can poll that byte to see when it is safe to read a reply. */ #endif /* OPENOCD_JTAG_DRIVERS_RLINK_DTC_CMD_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/rlink_ep1_cmd.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2008 Lou Deluxe * * lou.openocd012@fixit.nospammail.net * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_RLINK_EP1_CMD_H #define OPENOCD_JTAG_DRIVERS_RLINK_EP1_CMD_H /* * Command opcodes that can be sent over endpoint 1. * This codifies information provided by Rob Brown <rob@cobbleware.com>. * The buffer can contain several of these, but only one which returns data. * Some of these opcodes have arguments, which follow immediately. * If shorter than the packet size, trailing positions should be zero-filled. */ /* LED update enables: * When enabled, each LED is updated automatically. * When not enabled, each LED can be controlled manually with EP1_CMD_SET_PORTD_LEDS. */ #define EP1_CMD_LEDUE_BOTH (0x05) /* EP1_CMD_LEDUE_NONE has the side effect of turning the LEDs on */ #define EP1_CMD_LEDUE_NONE (0x06) #define EP1_CMD_LEDUE_ERROR (0x17) #define EP1_CMD_LEDUE_BUSY (0x18) #define EP1_CMD_DTC_STOP (0x0b) #define EP1_CMD_DTC_LOAD (0x0c) #define EP1_CMD_DTC_CALL (0x0d) #define EP1_CMD_SET_UPLOAD (0x0f) #define EP1_CMD_SET_DOWNLOAD (0x10) #define EP1_CMD_DTC_WAIT (0x12) #define EP1_CMD_DTC_GET_STATUS (0x15) /* a quick way to just read back one byte */ #define EP1_CMD_DTC_GET_CACHED_STATUS (0x16) /* Writes upper 2 bits (SHDN and SEL) of port D with argument */ #define EP1_CMD_SET_PORTD_VPP (0x19) /* Writes lower 2 bits (BUSY and ERROR) of port D with argument */ #define EP1_CMD_SET_PORTD_LEDS (0x1a) #define EP1_CMD_MEMORY_READ (0x28) #define EP1_CMD_MEMORY_WRITE (0x29) #define EP1_CMD_GET_FWREV (0xfe) #define EP1_CMD_GET_SERIAL (0xff) #endif /* OPENOCD_JTAG_DRIVERS_RLINK_EP1_CMD_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/rlink_init.m4 ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Copyright (C) 2008 Lou Deluxe # lou.openocd012@fixit.nospammail.net # m4_divert(`-1') m4_undefine(`CTRL_MPEG_L') m4_undefine(`CTRL_CARD_L') m4_ifelse(SHIFTER_PRESCALER, 1, ` m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x0')') ') m4_ifelse(SHIFTER_PRESCALER, 2, ` m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x2')') m4_define(`CTRL_CARD_L', `m4_eval(`0x8 | 0x1')') ') m4_ifelse(SHIFTER_PRESCALER, 8, ` m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x3')') ') m4_ifelse(SHIFTER_PRESCALER, 11, ` m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x4')') ') m4_ifelse(SHIFTER_PRESCALER, 64, ` m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x7')') ') m4_ifdef(`CTRL_MPEG_L',,` m4_errprint(`SHIFTER_PRESCALER was not defined with a supported value ') m4_m4exit(`1') ') m4_divert(`0')m4_dnl init: A.H = 0 A.L = 0 DR_MPEG = A ; TDI and TCK start out low DR_CARD = A ; TMS starts out low A.L = 0x6 CTRL_FCI = A ; MPEG and CARD driven by FCI DDR_MPEG = A ; TDI and TCK are outputs A.L = 0x1 X = A ; X == 1 DDR_CARD = A ; TMS is output A.L = CTRL_MPEG_L CTRL_MPEG = A m4_ifdef(`CTRL_CARD_L', ` A.L = 'CTRL_CARD_L` ')m4_dnl CTRL_CARD = A STATUS STOP ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/rlink_speed_table.c ================================================ /* This file was created automatically by ../../../tools/rlink_make_speed_table/rlink_make_speed_table.pl. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rlink.h" #include "rlink_st7.h" static const uint8_t dtc_64[] = { 0, 2, 68, 84, 67, 2, 13, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148, 191, 143, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0, 42, 42, 42, 73, 0, 88, 0, 160, 189, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100, 111, 119, 110, 108, 111, 97, 100, 2, 226, 7, 219, 39, 137, 51, 172, 130, 192, 96, 175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159, 193, 133, 153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9, 98, 128, 177, 129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176, 67, 219, 39, 154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60, 118, 193, 96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105, 193, 96, 201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36, 138, 105, 193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67, 193, 96, 219, 39, 131, 161, 176, 130, 195, 53, 131, 178, 10, 66, 176, 151, 60, 97, 58, 151, 215, 2, 40, 66, 1, 0, 160, 185, 130, 60, 97, 203, 130, 60, 194, 139, 127, 195, 53, 156, 47, 200, 96, 201, 56, 177, 66, 176, 147, 201, 57, 168, 66, 160, 38, 155, 160, 176, 139, 171, 182, 136, 167, 183, 96, 201, 59, 66, 46, 193, 151, 96, 201, 160, 139, 219, 39, 131, 160, 191, 130, 195, 53, 131, 177, 10, 66, 176, 147, 151, 0, 60, 97, 58, 151, 0, 160, 185, 130, 60, 97, 203, 8, 2, 36, 139, 124, 193, 151, 96 }; static const uint8_t dtc_11[] = { 0, 2, 68, 84, 67, 2, 13, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148, 188, 143, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0, 42, 42, 42, 73, 0, 88, 0, 154, 183, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100, 111, 119, 110, 108, 111, 97, 100, 2, 213, 7, 219, 39, 137, 51, 172, 130, 192, 96, 175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159, 193, 133, 153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9, 98, 128, 177, 129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176, 67, 219, 39, 154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60, 118, 193, 96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105, 193, 96, 201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36, 138, 105, 193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67, 193, 96, 219, 39, 131, 195, 53, 131, 178, 10, 66, 176, 151, 0, 0, 0, 0, 0, 58, 151, 215, 2, 40, 66, 1, 203, 130, 60, 194, 139, 121, 195, 53, 156, 47, 200, 96, 201, 56, 177, 66, 176, 147, 201, 57, 168, 66, 160, 38, 155, 160, 176, 139, 171, 176, 136, 167, 183, 96, 201, 59, 66, 46, 193, 151, 96, 201, 160, 139, 219, 39, 131, 195, 53, 131, 177, 10, 66, 176, 147, 151, 0, 0, 0, 0, 0, 58, 151, 203, 8, 2, 36, 139, 117, 193, 151, 96 }; static const uint8_t dtc_8[] = { 0, 2, 68, 84, 67, 2, 13, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148, 187, 143, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0, 42, 42, 42, 73, 0, 88, 0, 152, 181, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100, 111, 119, 110, 108, 111, 97, 100, 2, 209, 7, 219, 39, 137, 51, 172, 130, 192, 96, 175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159, 193, 133, 153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9, 98, 128, 177, 129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176, 67, 219, 39, 154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60, 118, 193, 96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105, 193, 96, 201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36, 138, 105, 193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67, 193, 96, 219, 39, 131, 195, 53, 131, 178, 10, 66, 176, 151, 0, 0, 0, 58, 151, 215, 2, 40, 66, 1, 203, 130, 60, 194, 139, 119, 195, 53, 156, 47, 200, 96, 201, 56, 177, 66, 176, 147, 201, 57, 168, 66, 160, 38, 155, 160, 176, 139, 170, 190, 136, 167, 183, 96, 201, 59, 66, 46, 193, 151, 96, 201, 160, 139, 219, 39, 131, 195, 53, 131, 177, 10, 66, 176, 147, 151, 0, 0, 0, 58, 151, 203, 8, 2, 36, 139, 115, 193, 151, 96 }; static const uint8_t dtc_2[] = { 0, 2, 68, 84, 67, 2, 14, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148, 186, 143, 185, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0, 42, 42, 42, 73, 0, 88, 0, 149, 178, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100, 111, 119, 110, 108, 111, 97, 100, 2, 203, 7, 219, 39, 137, 51, 172, 130, 192, 96, 175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159, 193, 133, 153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9, 98, 128, 177, 129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176, 67, 219, 39, 154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60, 118, 193, 96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105, 193, 96, 201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36, 138, 105, 193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67, 193, 96, 219, 39, 131, 195, 53, 131, 178, 10, 66, 176, 151, 58, 151, 215, 2, 40, 66, 1, 203, 130, 60, 194, 139, 116, 195, 53, 156, 47, 200, 96, 201, 56, 177, 66, 176, 147, 201, 57, 168, 66, 160, 38, 155, 160, 176, 139, 170, 187, 136, 167, 183, 96, 201, 59, 66, 46, 193, 151, 96, 201, 160, 139, 219, 39, 131, 195, 53, 131, 177, 10, 66, 176, 147, 151, 58, 151, 203, 8, 2, 36, 139, 112, 193, 151, 96 }; const struct rlink_speed_table rlink_speed_table[] = {{ dtc_64, sizeof(dtc_64), (ST7_FOSC * 2) / (1000 * 64), 64 }, { dtc_11, sizeof(dtc_11), (ST7_FOSC * 2) / (1000 * 11), 11 }, { dtc_8, sizeof(dtc_8), (ST7_FOSC * 2) / (1000 * 8), 8 }, { dtc_2, sizeof(dtc_2), (ST7_FOSC * 2) / (1000 * 2), 2 } }; const size_t rlink_speed_table_size = ARRAY_SIZE(rlink_speed_table); ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/rlink_st7.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2008 Lou Deluxe * * lou.openocd012@fixit.nospammail.net * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_RLINK_ST7_H #define OPENOCD_JTAG_DRIVERS_RLINK_ST7_H #define ST7_FOSC (12 * 1000000) /* This is not a complete enumeration of ST7 registers, but it is sufficient for this interface driver. */ #define ST7_PADR (0x0000) #define ST7_PADDR (ST7_PADR + 1) #define ST7_PAOR (ST7_PADR + 2) #define ST7_PBDR (0x0003) #define ST7_PBDDR (ST7_PBDR + 1) #define ST7_PCDR (0x0006) #define ST7_PCDDR (ST7_PCDR + 1) #define ST7_PCOR (ST7_PCDR + 2) #define ST7_PDDR (0x0009) #define ST7_PDDDR (ST7_PDDR + 1) #define ST7_PDOR (ST7_PDDR + 2) #define ST7_PEDR (0x000c) #define ST7_PEDDR (ST7_PEDR + 1) #define ST7_PEOR (ST7_PEDR + 2) #define ST7_PFDR (0x000f) #define ST7_PFDDR (ST7_PFDR + 1) #define ST7_ADCDR (0x0012) #define ST7_ADCCSR (ST7_ADCDR + 1) #define ST7_EP2TXR (0x003e) #define ST7_EP2TXR_STAT_TX0 (1 << 0) #define ST7_EP2TXR_STAT_TX1 (1 << 1) #define ST7_EP2TXR_STAT_DISABLED (0) #define ST7_EP2TXR_STAT_STALL (ST7_EP2TXR_STAT_TX0) #define ST7_EP2TXR_STAT_VALID (ST7_EP2TXR_STAT_TX1 | ST7_EP2TXR_STAT_TX0) #define ST7_EP2TXR_STAT_NAK (ST7_EP2TXR_STAT_TX1) #define ST7_EP2TXR_DTOG_TX (1 << 2) #define ST7_EP2TXR_CTR_TX (1 << 3) #define ST7_USB_BUF_EP0OUT (0x1550) #define ST7_USB_BUF_EP0IN (0x1560) #define ST7_USB_BUF_EP1OUT (0x1570) #define ST7_USB_BUF_EP1IN (0x1580) #define ST7_USB_BUF_EP2UODI (0x1590) #define ST7_USB_BUF_EP2UIDO (0x1650) #define ST7_PA0 (1 << 0) #define ST7_PA1 (1 << 1) #define ST7_PA2 (1 << 2) #define ST7_PA3 (1 << 3) #define ST7_PA4 (1 << 4) #define ST7_PA5 (1 << 5) #define ST7_PA6 (1 << 6) #define ST7_PA7 (1 << 7) #define ST7_PB0 (1 << 0) #define ST7_PB1 (1 << 1) #define ST7_PB2 (1 << 2) #define ST7_PB3 (1 << 3) #define ST7_PB4 (1 << 4) #define ST7_PB5 (1 << 5) #define ST7_PB6 (1 << 6) #define ST7_PB7 (1 << 7) #define ST7_PC0 (1 << 0) #define ST7_PC1 (1 << 1) #define ST7_PC2 (1 << 2) #define ST7_PC3 (1 << 3) #define ST7_PC4 (1 << 4) #define ST7_PC5 (1 << 5) #define ST7_PC6 (1 << 6) #define ST7_PC7 (1 << 7) #define ST7_PD0 (1 << 0) #define ST7_PD1 (1 << 1) #define ST7_PD2 (1 << 2) #define ST7_PD3 (1 << 3) #define ST7_PD4 (1 << 4) #define ST7_PD5 (1 << 5) #define ST7_PD6 (1 << 6) #define ST7_PD7 (1 << 7) #define ST7_PE0 (1 << 0) #define ST7_PE1 (1 << 1) #define ST7_PE2 (1 << 2) #define ST7_PE3 (1 << 3) #define ST7_PE4 (1 << 4) #define ST7_PE5 (1 << 5) #define ST7_PE6 (1 << 6) #define ST7_PE7 (1 << 7) #define ST7_PF0 (1 << 0) #define ST7_PF1 (1 << 1) #define ST7_PF2 (1 << 2) #define ST7_PF3 (1 << 3) #define ST7_PF4 (1 << 4) #define ST7_PF5 (1 << 5) #define ST7_PF6 (1 << 6) #define ST7_PF7 (1 << 7) #endif /* OPENOCD_JTAG_DRIVERS_RLINK_ST7_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/rshim.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2020, Mellanox Technologies Ltd. - All Rights Reserved * Liming Sun <lsun@mellanox.com> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/types.h> #include <helper/system.h> #include <helper/time_support.h> #include <helper/list.h> #include <jtag/interface.h> #ifdef HAVE_SYS_IOCTL_H #include <sys/ioctl.h> #endif #include <target/arm_adi_v5.h> #include <transport/transport.h> /* Rshim channel where the CoreSight register resides. */ #define RSH_MMIO_CHANNEL_RSHIM 0x1 /* APB and tile address translation. */ #define RSH_CS_ROM_BASE 0x80000000 #define RSH_CS_TILE_BASE 0x44000000 #define RSH_CS_TILE_SIZE 0x04000000 /* * APB-AP Identification Register * The default value is defined in "CoreSight on-chip trace and debug * (Revision: r1p0)", Section 3.16.5 APB-AP register summary. */ #define APB_AP_IDR 0x44770002 /* CoreSight register definition. */ #define RSH_CORESIGHT_CTL 0x0e00 #define RSH_CORESIGHT_CTL_GO_SHIFT 0 #define RSH_CORESIGHT_CTL_GO_MASK 0x1ULL #define RSH_CORESIGHT_CTL_ACTION_SHIFT 1 #define RSH_CORESIGHT_CTL_ACTION_MASK 0x2ULL #define RSH_CORESIGHT_CTL_ADDR_SHIFT 2 #define RSH_CORESIGHT_CTL_ADDR_MASK 0x7ffffffcULL #define RSH_CORESIGHT_CTL_ERR_SHIFT 31 #define RSH_CORESIGHT_CTL_ERR_MASK 0x80000000ULL #define RSH_CORESIGHT_CTL_DATA_SHIFT 32 #define RSH_CORESIGHT_CTL_DATA_MASK 0xffffffff00000000ULL /* Util macros to access the CoreSight register. */ #define RSH_CS_GET_FIELD(reg, field) \ (((uint64_t)(reg) & RSH_CORESIGHT_CTL_##field##_MASK) >> \ RSH_CORESIGHT_CTL_##field##_SHIFT) #define RSH_CS_SET_FIELD(reg, field, value) \ (reg) = (((reg) & ~RSH_CORESIGHT_CTL_##field##_MASK) | \ (((uint64_t)(value) << RSH_CORESIGHT_CTL_##field##_SHIFT) & \ RSH_CORESIGHT_CTL_##field##_MASK)) #ifdef HAVE_SYS_IOCTL_H /* Message used to program rshim via ioctl(). */ typedef struct { uint32_t addr; uint64_t data; } __attribute__((packed)) rshim_ioctl_msg; enum { RSH_IOC_READ = _IOWR('R', 0, rshim_ioctl_msg), RSH_IOC_WRITE = _IOWR('R', 1, rshim_ioctl_msg), }; #endif /* Use local variable stub for DP/AP registers. */ static uint32_t dp_ctrl_stat; static uint32_t dp_id_code; static uint32_t ap_sel, ap_bank; static uint32_t ap_csw; static uint32_t ap_drw; static uint32_t ap_tar, ap_tar_inc; /* Static functions to read/write via rshim/coresight. */ static int (*rshim_read)(int chan, int addr, uint64_t *value); static int (*rshim_write)(int chan, int addr, uint64_t value); static int coresight_write(uint32_t tile, uint32_t addr, uint32_t wdata); static int coresight_read(uint32_t tile, uint32_t addr, uint32_t *value); /* RShim file handler. */ static int rshim_fd = -1; /* DAP error code. */ static int rshim_dap_retval = ERROR_OK; /* Default rshim device. */ #define RSHIM_DEV_PATH_DEFAULT "/dev/rshim0/rshim" static char *rshim_dev_path; static int rshim_dev_read(int chan, int addr, uint64_t *value) { int rc; addr = (addr & 0xFFFF) | (1 << 16); rc = pread(rshim_fd, value, sizeof(*value), addr); #ifdef HAVE_SYS_IOCTL_H if (rc < 0 && errno == ENOSYS) { rshim_ioctl_msg msg; msg.addr = addr; msg.data = 0; rc = ioctl(rshim_fd, RSH_IOC_READ, &msg); if (!rc) *value = msg.data; } #endif return rc; } static int rshim_dev_write(int chan, int addr, uint64_t value) { int rc; addr = (addr & 0xFFFF) | (1 << 16); rc = pwrite(rshim_fd, &value, sizeof(value), addr); #ifdef HAVE_SYS_IOCTL_H if (rc < 0 && errno == ENOSYS) { rshim_ioctl_msg msg; msg.addr = addr; msg.data = value; rc = ioctl(rshim_fd, RSH_IOC_WRITE, &msg); } #endif return rc; } /* Convert AP address to tile local address. */ static void ap_addr_2_tile(int *tile, uint32_t *addr) { *addr -= RSH_CS_ROM_BASE; if (*addr < RSH_CS_TILE_BASE) { *tile = 0; } else { *addr -= RSH_CS_TILE_BASE; *tile = *addr / RSH_CS_TILE_SIZE + 1; *addr = *addr % RSH_CS_TILE_SIZE; } } /* * Write 4 bytes on the APB bus. * tile = 0: access the root CS_ROM table * > 0: access the ROM table of cluster (tile - 1) */ static int coresight_write(uint32_t tile, uint32_t addr, uint32_t wdata) { uint64_t ctl = 0; int rc; if (!rshim_read || !rshim_write) return ERROR_FAIL; /* * ADDR[28] - must be set to 1 due to coresight ip. * ADDR[27:24] - linear tile id */ addr = (addr >> 2) | (tile << 24); if (tile) addr |= (1 << 28); RSH_CS_SET_FIELD(ctl, ADDR, addr); RSH_CS_SET_FIELD(ctl, ACTION, 0); /* write */ RSH_CS_SET_FIELD(ctl, DATA, wdata); RSH_CS_SET_FIELD(ctl, GO, 1); /* start */ rshim_write(RSH_MMIO_CHANNEL_RSHIM, RSH_CORESIGHT_CTL, ctl); do { rc = rshim_read(RSH_MMIO_CHANNEL_RSHIM, RSH_CORESIGHT_CTL, &ctl); if (rc < 0) { LOG_ERROR("Failed to read rshim.\n"); return rc; } } while (RSH_CS_GET_FIELD(ctl, GO)); return ERROR_OK; } static int coresight_read(uint32_t tile, uint32_t addr, uint32_t *value) { uint64_t ctl = 0; int rc; if (!rshim_read || !rshim_write) return ERROR_FAIL; /* * ADDR[28] - must be set to 1 due to coresight ip. * ADDR[27:24] - linear tile id */ addr = (addr >> 2) | (tile << 24); if (tile) addr |= (1 << 28); RSH_CS_SET_FIELD(ctl, ADDR, addr); RSH_CS_SET_FIELD(ctl, ACTION, 1); /* read */ RSH_CS_SET_FIELD(ctl, GO, 1); /* start */ rshim_write(RSH_MMIO_CHANNEL_RSHIM, RSH_CORESIGHT_CTL, ctl); do { rc = rshim_read(RSH_MMIO_CHANNEL_RSHIM, RSH_CORESIGHT_CTL, &ctl); if (rc < 0) { LOG_ERROR("Failed to write rshim.\n"); return rc; } } while (RSH_CS_GET_FIELD(ctl, GO)); *value = RSH_CS_GET_FIELD(ctl, DATA); return ERROR_OK; } static int rshim_dp_q_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *data) { if (!data) return ERROR_OK; switch (reg) { case DP_DPIDR: *data = dp_id_code; break; case DP_CTRL_STAT: *data = CDBGPWRUPACK | CSYSPWRUPACK; break; default: break; } return ERROR_OK; } static int rshim_dp_q_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data) { switch (reg) { case DP_CTRL_STAT: dp_ctrl_stat = data; break; case DP_SELECT: ap_sel = (data & DP_SELECT_APSEL) >> 24; ap_bank = (data & DP_SELECT_APBANK) >> 4; break; default: LOG_INFO("Unknown command"); break; } return ERROR_OK; } static int rshim_ap_q_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data) { uint32_t addr; int rc = ERROR_OK, tile; if (is_adiv6(ap->dap)) { static bool error_flagged; if (!error_flagged) LOG_ERROR("ADIv6 dap not supported by rshim dap-direct mode"); error_flagged = true; return ERROR_FAIL; } switch (reg) { case ADIV5_MEM_AP_REG_CSW: *data = ap_csw; break; case ADIV5_MEM_AP_REG_CFG: *data = 0; break; case ADIV5_MEM_AP_REG_BASE: *data = RSH_CS_ROM_BASE; break; case ADIV5_AP_REG_IDR: if (ap->ap_num == 0) *data = APB_AP_IDR; else *data = 0; break; case ADIV5_MEM_AP_REG_BD0: case ADIV5_MEM_AP_REG_BD1: case ADIV5_MEM_AP_REG_BD2: case ADIV5_MEM_AP_REG_BD3: addr = (ap_tar & ~0xf) + (reg & 0x0C); ap_addr_2_tile(&tile, &addr); rc = coresight_read(tile, addr, data); break; case ADIV5_MEM_AP_REG_DRW: addr = (ap_tar & ~0x3) + ap_tar_inc; ap_addr_2_tile(&tile, &addr); rc = coresight_read(tile, addr, data); if (!rc && (ap_csw & CSW_ADDRINC_MASK)) ap_tar_inc += (ap_csw & 0x03) * 2; break; default: LOG_INFO("Unknown command"); rc = ERROR_FAIL; break; } /* Track the last error code. */ if (rc != ERROR_OK) rshim_dap_retval = rc; return rc; } static int rshim_ap_q_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data) { int rc = ERROR_OK, tile; uint32_t addr; if (is_adiv6(ap->dap)) { static bool error_flagged; if (!error_flagged) LOG_ERROR("ADIv6 dap not supported by rshim dap-direct mode"); error_flagged = true; return ERROR_FAIL; } if (ap_bank != 0) { rshim_dap_retval = ERROR_FAIL; return ERROR_FAIL; } switch (reg) { case ADIV5_MEM_AP_REG_CSW: ap_csw = data; break; case ADIV5_MEM_AP_REG_TAR: ap_tar = data; ap_tar_inc = 0; break; case ADIV5_MEM_AP_REG_BD0: case ADIV5_MEM_AP_REG_BD1: case ADIV5_MEM_AP_REG_BD2: case ADIV5_MEM_AP_REG_BD3: addr = (ap_tar & ~0xf) + (reg & 0x0C); ap_addr_2_tile(&tile, &addr); rc = coresight_write(tile, addr, data); break; case ADIV5_MEM_AP_REG_DRW: ap_drw = data; addr = (ap_tar & ~0x3) + ap_tar_inc; ap_addr_2_tile(&tile, &addr); rc = coresight_write(tile, addr, data); if (!rc && (ap_csw & CSW_ADDRINC_MASK)) ap_tar_inc += (ap_csw & 0x03) * 2; break; default: rc = EINVAL; break; } /* Track the last error code. */ if (rc != ERROR_OK) rshim_dap_retval = rc; return rc; } static int rshim_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack) { return ERROR_OK; } static int rshim_dp_run(struct adiv5_dap *dap) { int retval = rshim_dap_retval; /* Clear the error code. */ rshim_dap_retval = ERROR_OK; return retval; } static int rshim_connect(struct adiv5_dap *dap) { char *path = rshim_dev_path ? rshim_dev_path : RSHIM_DEV_PATH_DEFAULT; rshim_fd = open(path, O_RDWR | O_SYNC); if (rshim_fd == -1) { LOG_ERROR("Unable to open %s\n", path); return ERROR_FAIL; } /* * Set read/write operation via the device file. Function pointers * are used here so more ways like remote accessing via socket could * be added later. */ rshim_read = rshim_dev_read; rshim_write = rshim_dev_write; return ERROR_OK; } static void rshim_disconnect(struct adiv5_dap *dap) { if (rshim_fd != -1) { close(rshim_fd); rshim_fd = -1; } } COMMAND_HANDLER(rshim_dap_device_command) { if (CMD_ARGC != 1) { command_print(CMD, "Too many arguments"); return ERROR_COMMAND_SYNTAX_ERROR; } free(rshim_dev_path); rshim_dev_path = strdup(CMD_ARGV[0]); return ERROR_OK; } static const struct command_registration rshim_dap_subcommand_handlers[] = { { .name = "device", .handler = rshim_dap_device_command, .mode = COMMAND_CONFIG, .help = "set the rshim device", .usage = "</dev/rshim<N>/rshim>", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration rshim_dap_command_handlers[] = { { .name = "rshim", .mode = COMMAND_ANY, .help = "perform rshim management", .chain = rshim_dap_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static int rshim_dap_init(void) { return ERROR_OK; } static int rshim_dap_quit(void) { return ERROR_OK; } static int rshim_dap_reset(int req_trst, int req_srst) { return ERROR_OK; } static int rshim_dap_speed(int speed) { return ERROR_OK; } static int rshim_dap_khz(int khz, int *jtag_speed) { *jtag_speed = khz; return ERROR_OK; } static int rshim_dap_speed_div(int speed, int *khz) { *khz = speed; return ERROR_OK; } /* DAP operations. */ static const struct dap_ops rshim_dap_ops = { .connect = rshim_connect, .queue_dp_read = rshim_dp_q_read, .queue_dp_write = rshim_dp_q_write, .queue_ap_read = rshim_ap_q_read, .queue_ap_write = rshim_ap_q_write, .queue_ap_abort = rshim_ap_q_abort, .run = rshim_dp_run, .quit = rshim_disconnect, }; static const char *const rshim_dap_transport[] = { "dapdirect_swd", NULL }; struct adapter_driver rshim_dap_adapter_driver = { .name = "rshim", .transports = rshim_dap_transport, .commands = rshim_dap_command_handlers, .init = rshim_dap_init, .quit = rshim_dap_quit, .reset = rshim_dap_reset, .speed = rshim_dap_speed, .khz = rshim_dap_khz, .speed_div = rshim_dap_speed_div, .dap_swd_ops = &rshim_dap_ops, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/stlink_usb.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2020 by Tarek Bochkati * * Tarek Bochkati <tarek.bouchkati@gmail.com> * * * * SWIM contributions by Ake Rehnman * * Copyright (C) 2017 Ake Rehnman * * ake.rehnman(at)gmail.com * * * * Copyright (C) 2011-2012 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This code is based on https://github.com/texane/stlink * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include <helper/align.h> #include <helper/binarybuffer.h> #include <helper/bits.h> #include <helper/system.h> #include <helper/time_support.h> #include <jtag/adapter.h> #include <jtag/interface.h> #include <jtag/hla/hla_layout.h> #include <jtag/hla/hla_transport.h> #include <jtag/hla/hla_interface.h> #include <jtag/swim.h> #include <target/arm_adi_v5.h> #include <target/target.h> #include <transport/transport.h> #include <target/cortex_m.h> #include <helper/system.h> #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif #ifdef HAVE_NETINET_TCP_H #include <netinet/tcp.h> #endif #include "libusb_helper.h" #ifdef HAVE_LIBUSB1 #define USE_LIBUSB_ASYNCIO #endif #define STLINK_SERIAL_LEN 24 #define ENDPOINT_IN 0x80 #define ENDPOINT_OUT 0x00 #define STLINK_WRITE_TIMEOUT (LIBUSB_TIMEOUT_MS) #define STLINK_READ_TIMEOUT (LIBUSB_TIMEOUT_MS) #define STLINK_RX_EP (1|ENDPOINT_IN) #define STLINK_TX_EP (2|ENDPOINT_OUT) #define STLINK_TRACE_EP (3|ENDPOINT_IN) #define STLINK_V2_1_TX_EP (1|ENDPOINT_OUT) #define STLINK_V2_1_TRACE_EP (2|ENDPOINT_IN) #define STLINK_SG_SIZE (31) #define STLINK_DATA_SIZE (6144) #define STLINK_CMD_SIZE_V2 (16) #define STLINK_CMD_SIZE_V1 (10) #define STLINK_V1_PID (0x3744) #define STLINK_V2_PID (0x3748) #define STLINK_V2_1_PID (0x374B) #define STLINK_V2_1_NO_MSD_PID (0x3752) #define STLINK_V3_USBLOADER_PID (0x374D) #define STLINK_V3E_PID (0x374E) #define STLINK_V3S_PID (0x374F) #define STLINK_V3_2VCP_PID (0x3753) #define STLINK_V3E_NO_MSD_PID (0x3754) #define STLINK_V3P_USBLOADER_PID (0x3755) #define STLINK_V3P_PID (0x3757) /* * ST-Link/V1, ST-Link/V2 and ST-Link/V2.1 are full-speed USB devices and * this limits the bulk packet size and the 8bit read/writes to max 64 bytes. * STLINK-V3 is a high speed USB 2.0 and the limit is 512 bytes from FW V3J6. * * For 16 and 32bit read/writes stlink handles USB packet split and the limit * is the internal buffer size of 6144 bytes. * TODO: override ADIv5 layer's tar_autoincr_block that limits the transfer * to 1024 or 4096 bytes */ #define STLINK_MAX_RW8 (64) #define STLINKV3_MAX_RW8 (512) #define STLINK_MAX_RW16_32 STLINK_DATA_SIZE #define STLINK_SWIM_DATA_SIZE STLINK_DATA_SIZE /* "WAIT" responses will be retried (with exponential backoff) at * most this many times before failing to caller. */ #define MAX_WAIT_RETRIES 8 /* HLA is currently limited at AP#0 and no control on CSW */ #define STLINK_HLA_AP_NUM 0 #define STLINK_HLA_CSW 0 enum stlink_jtag_api_version { STLINK_JTAG_API_V1 = 1, STLINK_JTAG_API_V2, STLINK_JTAG_API_V3, }; enum stlink_mode { STLINK_MODE_UNKNOWN = 0, STLINK_MODE_DFU, STLINK_MODE_MASS, STLINK_MODE_DEBUG_JTAG, STLINK_MODE_DEBUG_SWD, STLINK_MODE_DEBUG_SWIM }; /** */ struct stlink_usb_version { /** */ int stlink; /** */ int jtag; /** */ int swim; /** jtag api version supported */ enum stlink_jtag_api_version jtag_api; /** one bit for each feature supported. See macros STLINK_F_* */ uint32_t flags; }; struct stlink_usb_priv_s { /** */ struct libusb_device_handle *fd; /** */ struct libusb_transfer *trans; }; struct stlink_tcp_version { uint32_t api; uint32_t major; uint32_t minor; uint32_t build; }; struct stlink_tcp_priv_s { /** */ int fd; /** */ bool connected; /** */ uint32_t device_id; /** */ uint32_t connect_id; /** */ uint8_t *send_buf; /** */ uint8_t *recv_buf; /** */ struct stlink_tcp_version version; }; struct stlink_backend_s { /** */ int (*open)(void *handle, struct hl_interface_param_s *param); /** */ int (*close)(void *handle); /** */ int (*xfer_noerrcheck)(void *handle, const uint8_t *buf, int size); /** */ int (*read_trace)(void *handle, const uint8_t *buf, int size); }; /* TODO: make queue size dynamic */ /* TODO: don't allocate queue for HLA */ #define MAX_QUEUE_DEPTH (4096) enum queue_cmd { CMD_DP_READ = 1, CMD_DP_WRITE, CMD_AP_READ, CMD_AP_WRITE, /* * encode the bytes size in the enum's value. This makes easy to extract it * with a simple logic AND, by using the macro CMD_MEM_AP_2_SIZE() below */ CMD_MEM_AP_READ8 = 0x10 + 1, CMD_MEM_AP_READ16 = 0x10 + 2, CMD_MEM_AP_READ32 = 0x10 + 4, CMD_MEM_AP_WRITE8 = 0x20 + 1, CMD_MEM_AP_WRITE16 = 0x20 + 2, CMD_MEM_AP_WRITE32 = 0x20 + 4, }; #define CMD_MEM_AP_2_SIZE(cmd) ((cmd) & 7) struct dap_queue { enum queue_cmd cmd; union { struct dp_r { unsigned int reg; struct adiv5_dap *dap; uint32_t *p_data; } dp_r; struct dp_w { unsigned int reg; struct adiv5_dap *dap; uint32_t data; } dp_w; struct ap_r { unsigned int reg; struct adiv5_ap *ap; uint32_t *p_data; } ap_r; struct ap_w { unsigned int reg; struct adiv5_ap *ap; uint32_t data; bool changes_csw_default; } ap_w; struct mem_ap { uint32_t addr; struct adiv5_ap *ap; union { uint32_t *p_data; uint32_t data; }; uint32_t csw; } mem_ap; }; }; /** */ struct stlink_usb_handle_s { /** */ struct stlink_backend_s *backend; /** */ union { struct stlink_usb_priv_s usb_backend_priv; struct stlink_tcp_priv_s tcp_backend_priv; }; /** */ uint8_t rx_ep; /** */ uint8_t tx_ep; /** */ uint8_t trace_ep; /** */ uint8_t *cmdbuf; /** */ uint8_t cmdidx; /** */ uint8_t direction; /** */ uint8_t *databuf; /** */ uint32_t max_mem_packet; /** */ enum stlink_mode st_mode; /** */ struct stlink_usb_version version; /** */ uint16_t vid; /** */ uint16_t pid; /** */ struct { /** whether SWO tracing is enabled or not */ bool enabled; /** trace module source clock */ uint32_t source_hz; } trace; /** reconnect is needed next time we try to query the * status */ bool reconnect_pending; /** queue of dap_direct operations */ struct dap_queue queue[MAX_QUEUE_DEPTH]; /** first element available in the queue */ unsigned int queue_index; }; /** */ static inline int stlink_usb_open(void *handle, struct hl_interface_param_s *param) { struct stlink_usb_handle_s *h = handle; return h->backend->open(handle, param); } /** */ static inline int stlink_usb_close(void *handle) { struct stlink_usb_handle_s *h = handle; return h->backend->close(handle); } /** */ static inline int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size) { struct stlink_usb_handle_s *h = handle; return h->backend->xfer_noerrcheck(handle, buf, size); } #define STLINK_SWIM_ERR_OK 0x00 #define STLINK_SWIM_BUSY 0x01 #define STLINK_DEBUG_ERR_OK 0x80 #define STLINK_DEBUG_ERR_FAULT 0x81 #define STLINK_SWD_AP_WAIT 0x10 #define STLINK_SWD_AP_FAULT 0x11 #define STLINK_SWD_AP_ERROR 0x12 #define STLINK_SWD_AP_PARITY_ERROR 0x13 #define STLINK_JTAG_GET_IDCODE_ERROR 0x09 #define STLINK_JTAG_WRITE_ERROR 0x0c #define STLINK_JTAG_WRITE_VERIF_ERROR 0x0d #define STLINK_SWD_DP_WAIT 0x14 #define STLINK_SWD_DP_FAULT 0x15 #define STLINK_SWD_DP_ERROR 0x16 #define STLINK_SWD_DP_PARITY_ERROR 0x17 #define STLINK_SWD_AP_WDATA_ERROR 0x18 #define STLINK_SWD_AP_STICKY_ERROR 0x19 #define STLINK_SWD_AP_STICKYORUN_ERROR 0x1a #define STLINK_BAD_AP_ERROR 0x1d #define STLINK_CORE_RUNNING 0x80 #define STLINK_CORE_HALTED 0x81 #define STLINK_CORE_STAT_UNKNOWN -1 #define STLINK_GET_VERSION 0xF1 #define STLINK_DEBUG_COMMAND 0xF2 #define STLINK_DFU_COMMAND 0xF3 #define STLINK_SWIM_COMMAND 0xF4 #define STLINK_GET_CURRENT_MODE 0xF5 #define STLINK_GET_TARGET_VOLTAGE 0xF7 #define STLINK_DEV_DFU_MODE 0x00 #define STLINK_DEV_MASS_MODE 0x01 #define STLINK_DEV_DEBUG_MODE 0x02 #define STLINK_DEV_SWIM_MODE 0x03 #define STLINK_DEV_BOOTLOADER_MODE 0x04 #define STLINK_DEV_UNKNOWN_MODE -1 #define STLINK_DFU_EXIT 0x07 /* STLINK_SWIM_ENTER_SEQ 1.3ms low then 750Hz then 1.5kHz STLINK_SWIM_GEN_RST STM8 DM pulls reset pin low 50us STLINK_SWIM_SPEED uint8_t (0=low|1=high) STLINK_SWIM_WRITEMEM uint16_t length uint32_t address STLINK_SWIM_RESET send synchronization seq (16us low, response 64 clocks low) */ #define STLINK_SWIM_ENTER 0x00 #define STLINK_SWIM_EXIT 0x01 #define STLINK_SWIM_READ_CAP 0x02 #define STLINK_SWIM_SPEED 0x03 #define STLINK_SWIM_ENTER_SEQ 0x04 #define STLINK_SWIM_GEN_RST 0x05 #define STLINK_SWIM_RESET 0x06 #define STLINK_SWIM_ASSERT_RESET 0x07 #define STLINK_SWIM_DEASSERT_RESET 0x08 #define STLINK_SWIM_READSTATUS 0x09 #define STLINK_SWIM_WRITEMEM 0x0a #define STLINK_SWIM_READMEM 0x0b #define STLINK_SWIM_READBUF 0x0c #define STLINK_DEBUG_GETSTATUS 0x01 #define STLINK_DEBUG_FORCEDEBUG 0x02 #define STLINK_DEBUG_APIV1_RESETSYS 0x03 #define STLINK_DEBUG_APIV1_READALLREGS 0x04 #define STLINK_DEBUG_APIV1_READREG 0x05 #define STLINK_DEBUG_APIV1_WRITEREG 0x06 #define STLINK_DEBUG_READMEM_32BIT 0x07 #define STLINK_DEBUG_WRITEMEM_32BIT 0x08 #define STLINK_DEBUG_RUNCORE 0x09 #define STLINK_DEBUG_STEPCORE 0x0a #define STLINK_DEBUG_APIV1_SETFP 0x0b #define STLINK_DEBUG_READMEM_8BIT 0x0c #define STLINK_DEBUG_WRITEMEM_8BIT 0x0d #define STLINK_DEBUG_APIV1_CLEARFP 0x0e #define STLINK_DEBUG_APIV1_WRITEDEBUGREG 0x0f #define STLINK_DEBUG_APIV1_SETWATCHPOINT 0x10 #define STLINK_DEBUG_ENTER_JTAG_RESET 0x00 #define STLINK_DEBUG_ENTER_SWD_NO_RESET 0xa3 #define STLINK_DEBUG_ENTER_JTAG_NO_RESET 0xa4 #define STLINK_DEBUG_APIV1_ENTER 0x20 #define STLINK_DEBUG_EXIT 0x21 #define STLINK_DEBUG_READCOREID 0x22 #define STLINK_DEBUG_APIV2_ENTER 0x30 #define STLINK_DEBUG_APIV2_READ_IDCODES 0x31 #define STLINK_DEBUG_APIV2_RESETSYS 0x32 #define STLINK_DEBUG_APIV2_READREG 0x33 #define STLINK_DEBUG_APIV2_WRITEREG 0x34 #define STLINK_DEBUG_APIV2_WRITEDEBUGREG 0x35 #define STLINK_DEBUG_APIV2_READDEBUGREG 0x36 #define STLINK_DEBUG_APIV2_READALLREGS 0x3A #define STLINK_DEBUG_APIV2_GETLASTRWSTATUS 0x3B #define STLINK_DEBUG_APIV2_DRIVE_NRST 0x3C #define STLINK_DEBUG_APIV2_GETLASTRWSTATUS2 0x3E #define STLINK_DEBUG_APIV2_START_TRACE_RX 0x40 #define STLINK_DEBUG_APIV2_STOP_TRACE_RX 0x41 #define STLINK_DEBUG_APIV2_GET_TRACE_NB 0x42 #define STLINK_DEBUG_APIV2_SWD_SET_FREQ 0x43 #define STLINK_DEBUG_APIV2_JTAG_SET_FREQ 0x44 #define STLINK_DEBUG_APIV2_READ_DAP_REG 0x45 #define STLINK_DEBUG_APIV2_WRITE_DAP_REG 0x46 #define STLINK_DEBUG_APIV2_READMEM_16BIT 0x47 #define STLINK_DEBUG_APIV2_WRITEMEM_16BIT 0x48 #define STLINK_DEBUG_APIV2_INIT_AP 0x4B #define STLINK_DEBUG_APIV2_CLOSE_AP_DBG 0x4C #define STLINK_DEBUG_WRITEMEM_32BIT_NO_ADDR_INC 0x50 #define STLINK_DEBUG_APIV2_RW_MISC_OUT 0x51 #define STLINK_DEBUG_APIV2_RW_MISC_IN 0x52 #define STLINK_DEBUG_READMEM_32BIT_NO_ADDR_INC 0x54 #define STLINK_APIV3_SET_COM_FREQ 0x61 #define STLINK_APIV3_GET_COM_FREQ 0x62 #define STLINK_APIV3_GET_VERSION_EX 0xFB #define STLINK_DEBUG_APIV2_DRIVE_NRST_LOW 0x00 #define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH 0x01 #define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE 0x02 #define STLINK_DEBUG_PORT_ACCESS 0xffff #define STLINK_TRACE_SIZE 4096 #define STLINK_TRACE_MAX_HZ 2000000 #define STLINK_V3_TRACE_MAX_HZ 24000000 #define STLINK_V3_MAX_FREQ_NB 10 #define REQUEST_SENSE 0x03 #define REQUEST_SENSE_LENGTH 18 /* STLINK TCP commands */ #define STLINK_TCP_CMD_REFRESH_DEVICE_LIST 0x00 #define STLINK_TCP_CMD_GET_NB_DEV 0x01 #define STLINK_TCP_CMD_GET_DEV_INFO 0x02 #define STLINK_TCP_CMD_OPEN_DEV 0x03 #define STLINK_TCP_CMD_CLOSE_DEV 0x04 #define STLINK_TCP_CMD_SEND_USB_CMD 0x05 #define STLINK_TCP_CMD_GET_SERVER_VERSION 0x06 #define STLINK_TCP_CMD_GET_NB_OF_DEV_CLIENTS 0x07 /* STLINK TCP constants */ #define OPENOCD_STLINK_TCP_API_VERSION 1 #define STLINK_TCP_REQUEST_WRITE 0 #define STLINK_TCP_REQUEST_READ 1 #define STLINK_TCP_REQUEST_READ_SWO 3 #define STLINK_TCP_SS_SIZE 4 #define STLINK_TCP_USB_CMD_SIZE 32 #define STLINK_TCP_SERIAL_SIZE 32 #define STLINK_TCP_SEND_BUFFER_SIZE 10240 #define STLINK_TCP_RECV_BUFFER_SIZE 10240 /* STLINK TCP command status */ #define STLINK_TCP_SS_OK 0x00000001 #define STLINK_TCP_SS_MEMORY_PROBLEM 0x00001000 #define STLINK_TCP_SS_TIMEOUT 0x00001001 #define STLINK_TCP_SS_BAD_PARAMETER 0x00001002 #define STLINK_TCP_SS_OPEN_ERR 0x00001003 #define STLINK_TCP_SS_TRUNCATED_DATA 0x00001052 #define STLINK_TCP_SS_CMD_NOT_AVAILABLE 0x00001053 #define STLINK_TCP_SS_TCP_ERROR 0x00002001 #define STLINK_TCP_SS_TCP_CANT_CONNECT 0x00002002 #define STLINK_TCP_SS_TCP_CLOSE_ERROR 0x00002003 #define STLINK_TCP_SS_TCP_BUSY 0x00002004 #define STLINK_TCP_SS_WIN32_ERROR 0x00010000 /* * Map the relevant features, quirks and workaround for specific firmware * version of stlink */ #define STLINK_F_HAS_TRACE BIT(0) /* v2>=j13 || v3 */ #define STLINK_F_HAS_GETLASTRWSTATUS2 BIT(1) /* v2>=j15 || v3 */ #define STLINK_F_HAS_SWD_SET_FREQ BIT(2) /* v2>=j22 */ #define STLINK_F_HAS_JTAG_SET_FREQ BIT(3) /* v2>=j24 */ #define STLINK_F_QUIRK_JTAG_DP_READ BIT(4) /* v2>=j24 && v2<j32 */ #define STLINK_F_HAS_DAP_REG BIT(5) /* v2>=j24 || v3 */ #define STLINK_F_HAS_MEM_16BIT BIT(6) /* v2>=j26 || v3 */ #define STLINK_F_HAS_AP_INIT BIT(7) /* v2>=j28 || v3 */ #define STLINK_F_FIX_CLOSE_AP BIT(8) /* v2>=j29 || v3 */ #define STLINK_F_HAS_DPBANKSEL BIT(9) /* v2>=j32 || v3>=j2 */ #define STLINK_F_HAS_RW8_512BYTES BIT(10) /* v3>=j6 */ /* aliases */ #define STLINK_F_HAS_TARGET_VOLT STLINK_F_HAS_TRACE #define STLINK_F_HAS_FPU_REG STLINK_F_HAS_GETLASTRWSTATUS2 #define STLINK_F_HAS_MEM_WR_NO_INC STLINK_F_HAS_MEM_16BIT #define STLINK_F_HAS_MEM_RD_NO_INC STLINK_F_HAS_DPBANKSEL #define STLINK_F_HAS_RW_MISC STLINK_F_HAS_DPBANKSEL #define STLINK_F_HAS_CSW STLINK_F_HAS_DPBANKSEL #define STLINK_REGSEL_IS_FPU(x) ((x) > 0x1F) struct speed_map { int speed; int speed_divisor; }; /* SWD clock speed */ static const struct speed_map stlink_khz_to_speed_map_swd[] = { {4000, 0}, {1800, 1}, /* default */ {1200, 2}, {950, 3}, {480, 7}, {240, 15}, {125, 31}, {100, 40}, {50, 79}, {25, 158}, {15, 265}, {5, 798} }; /* JTAG clock speed */ static const struct speed_map stlink_khz_to_speed_map_jtag[] = { {9000, 4}, {4500, 8}, {2250, 16}, {1125, 32}, /* default */ {562, 64}, {281, 128}, {140, 256} }; static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size); static int stlink_swim_status(void *handle); static void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size); static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map *map); static int stlink_speed(void *handle, int khz, bool query); static int stlink_usb_open_ap(void *handle, unsigned short apsel); /** */ static unsigned int stlink_usb_block(void *handle) { struct stlink_usb_handle_s *h = handle; assert(handle); if (h->version.flags & STLINK_F_HAS_RW8_512BYTES) return STLINKV3_MAX_RW8; else return STLINK_MAX_RW8; } #ifdef USE_LIBUSB_ASYNCIO static LIBUSB_CALL void sync_transfer_cb(struct libusb_transfer *transfer) { int *completed = transfer->user_data; *completed = 1; /* caller interprets result and frees transfer */ } static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer) { int r, *completed = transfer->user_data; while (!*completed) { r = jtag_libusb_handle_events_completed(completed); if (r < 0) { if (r == LIBUSB_ERROR_INTERRUPTED) continue; libusb_cancel_transfer(transfer); continue; } } } static int transfer_error_status(const struct libusb_transfer *transfer) { int r = 0; switch (transfer->status) { case LIBUSB_TRANSFER_COMPLETED: r = 0; break; case LIBUSB_TRANSFER_TIMED_OUT: r = LIBUSB_ERROR_TIMEOUT; break; case LIBUSB_TRANSFER_STALL: r = LIBUSB_ERROR_PIPE; break; case LIBUSB_TRANSFER_OVERFLOW: r = LIBUSB_ERROR_OVERFLOW; break; case LIBUSB_TRANSFER_NO_DEVICE: r = LIBUSB_ERROR_NO_DEVICE; break; case LIBUSB_TRANSFER_ERROR: case LIBUSB_TRANSFER_CANCELLED: r = LIBUSB_ERROR_IO; break; default: r = LIBUSB_ERROR_OTHER; break; } return r; } struct jtag_xfer { int ep; uint8_t *buf; size_t size; /* Internal */ int retval; int completed; size_t transfer_size; struct libusb_transfer *transfer; }; static int jtag_libusb_bulk_transfer_n( struct libusb_device_handle *dev_handle, struct jtag_xfer *transfers, size_t n_transfers, int timeout) { int retval = 0; int returnval = ERROR_OK; for (size_t i = 0; i < n_transfers; ++i) { transfers[i].retval = 0; transfers[i].completed = 0; transfers[i].transfer_size = 0; transfers[i].transfer = libusb_alloc_transfer(0); if (!transfers[i].transfer) { for (size_t j = 0; j < i; ++j) libusb_free_transfer(transfers[j].transfer); LOG_DEBUG("ERROR, failed to alloc usb transfers"); for (size_t k = 0; k < n_transfers; ++k) transfers[k].retval = LIBUSB_ERROR_NO_MEM; return ERROR_FAIL; } } for (size_t i = 0; i < n_transfers; ++i) { libusb_fill_bulk_transfer( transfers[i].transfer, dev_handle, transfers[i].ep, transfers[i].buf, transfers[i].size, sync_transfer_cb, &transfers[i].completed, timeout); transfers[i].transfer->type = LIBUSB_TRANSFER_TYPE_BULK; retval = libusb_submit_transfer(transfers[i].transfer); if (retval < 0) { LOG_DEBUG("ERROR, failed to submit transfer %zu, error %d", i, retval); /* Probably no point continuing to submit transfers once a submission fails. * As a result, tag all remaining transfers as errors. */ for (size_t j = i; j < n_transfers; ++j) transfers[j].retval = retval; returnval = ERROR_FAIL; break; } } /* Wait for every submitted USB transfer to complete. */ for (size_t i = 0; i < n_transfers; ++i) { if (transfers[i].retval == 0) { sync_transfer_wait_for_completion(transfers[i].transfer); retval = transfer_error_status(transfers[i].transfer); if (retval) { returnval = ERROR_FAIL; transfers[i].retval = retval; LOG_DEBUG("ERROR, transfer %zu failed, error %d", i, retval); } else { /* Assuming actual_length is only valid if there is no transfer error. */ transfers[i].transfer_size = transfers[i].transfer->actual_length; } } libusb_free_transfer(transfers[i].transfer); transfers[i].transfer = NULL; } return returnval; } #endif /** */ static int stlink_usb_xfer_v1_get_status(void *handle) { struct stlink_usb_handle_s *h = handle; int tr, ret; assert(handle); /* read status */ memset(h->cmdbuf, 0, STLINK_SG_SIZE); ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->rx_ep, (char *)h->cmdbuf, 13, STLINK_READ_TIMEOUT, &tr); if (ret || tr != 13) return ERROR_FAIL; uint32_t t1; t1 = buf_get_u32(h->cmdbuf, 0, 32); /* check for USBS */ if (t1 != 0x53425355) return ERROR_FAIL; /* * CSW status: * 0 success * 1 command failure * 2 phase error */ if (h->cmdbuf[12] != 0) return ERROR_FAIL; return ERROR_OK; } #ifdef USE_LIBUSB_ASYNCIO static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int size) { struct stlink_usb_handle_s *h = handle; assert(handle); size_t n_transfers = 0; struct jtag_xfer transfers[2]; memset(transfers, 0, sizeof(transfers)); transfers[0].ep = h->tx_ep; transfers[0].buf = h->cmdbuf; transfers[0].size = cmdsize; ++n_transfers; if (h->direction == h->tx_ep && size) { transfers[1].ep = h->tx_ep; transfers[1].buf = (uint8_t *)buf; transfers[1].size = size; ++n_transfers; } else if (h->direction == h->rx_ep && size) { transfers[1].ep = h->rx_ep; transfers[1].buf = (uint8_t *)buf; transfers[1].size = size; ++n_transfers; } return jtag_libusb_bulk_transfer_n( h->usb_backend_priv.fd, transfers, n_transfers, STLINK_WRITE_TIMEOUT); } #else static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int size) { struct stlink_usb_handle_s *h = handle; int tr, ret; assert(handle); ret = jtag_libusb_bulk_write(h->usb_backend_priv.fd, h->tx_ep, (char *)h->cmdbuf, cmdsize, STLINK_WRITE_TIMEOUT, &tr); if (ret || tr != cmdsize) return ERROR_FAIL; if (h->direction == h->tx_ep && size) { ret = jtag_libusb_bulk_write(h->usb_backend_priv.fd, h->tx_ep, (char *)buf, size, STLINK_WRITE_TIMEOUT, &tr); if (ret || tr != size) { LOG_DEBUG("bulk write failed"); return ERROR_FAIL; } } else if (h->direction == h->rx_ep && size) { ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->rx_ep, (char *)buf, size, STLINK_READ_TIMEOUT, &tr); if (ret || tr != size) { LOG_DEBUG("bulk read failed"); return ERROR_FAIL; } } return ERROR_OK; } #endif /** */ static int stlink_usb_xfer_v1_get_sense(void *handle) { int res; struct stlink_usb_handle_s *h = handle; assert(handle); stlink_usb_init_buffer(handle, h->rx_ep, 16); h->cmdbuf[h->cmdidx++] = REQUEST_SENSE; h->cmdbuf[h->cmdidx++] = 0; h->cmdbuf[h->cmdidx++] = 0; h->cmdbuf[h->cmdidx++] = 0; h->cmdbuf[h->cmdidx++] = REQUEST_SENSE_LENGTH; res = stlink_usb_xfer_rw(handle, REQUEST_SENSE_LENGTH, h->databuf, 16); if (res != ERROR_OK) return res; if (stlink_usb_xfer_v1_get_status(handle) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } /** */ static int stlink_usb_usb_read_trace(void *handle, const uint8_t *buf, int size) { struct stlink_usb_handle_s *h = handle; int tr, ret; ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->trace_ep, (char *)buf, size, STLINK_READ_TIMEOUT, &tr); if (ret || tr != size) { LOG_ERROR("bulk trace read failed"); return ERROR_FAIL; } return ERROR_OK; } /* transfers block in cmdbuf <size> indicates number of bytes in the following data phase. Ignore the (eventual) error code in the received packet. */ static int stlink_usb_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size) { int err, cmdsize = STLINK_CMD_SIZE_V2; struct stlink_usb_handle_s *h = handle; assert(handle); if (h->version.stlink == 1) { cmdsize = STLINK_SG_SIZE; /* put length in bCBWCBLength */ h->cmdbuf[14] = h->cmdidx-15; } err = stlink_usb_xfer_rw(handle, cmdsize, buf, size); if (err != ERROR_OK) return err; if (h->version.stlink == 1) { if (stlink_usb_xfer_v1_get_status(handle) != ERROR_OK) { /* check csw status */ if (h->cmdbuf[12] == 1) { LOG_DEBUG("get sense"); if (stlink_usb_xfer_v1_get_sense(handle) != ERROR_OK) return ERROR_FAIL; } return ERROR_FAIL; } } return ERROR_OK; } static int stlink_tcp_send_cmd(void *handle, int send_size, int recv_size, bool check_tcp_status) { struct stlink_usb_handle_s *h = handle; assert(handle); /* send the TCP command */ int sent_size = send(h->tcp_backend_priv.fd, (void *)h->tcp_backend_priv.send_buf, send_size, 0); if (sent_size != send_size) { LOG_ERROR("failed to send USB CMD"); if (sent_size == -1) LOG_DEBUG("socket send error: %s (errno %d)", strerror(errno), errno); else LOG_DEBUG("sent size %d (expected %d)", sent_size, send_size); return ERROR_FAIL; } /* read the TCP response */ int retval = ERROR_OK; int remaining_bytes = recv_size; uint8_t *recv_buf = h->tcp_backend_priv.recv_buf; const int64_t timeout = timeval_ms() + 1000; /* 1 second */ while (remaining_bytes > 0) { if (timeval_ms() > timeout) { LOG_DEBUG("received size %d (expected %d)", recv_size - remaining_bytes, recv_size); retval = ERROR_TIMEOUT_REACHED; break; } keep_alive(); int received = recv(h->tcp_backend_priv.fd, (void *)recv_buf, remaining_bytes, 0); if (received == -1) { LOG_DEBUG("socket recv error: %s (errno %d)", strerror(errno), errno); retval = ERROR_FAIL; break; } recv_buf += received; remaining_bytes -= received; } if (retval != ERROR_OK) { LOG_ERROR("failed to receive USB CMD response"); return retval; } if (check_tcp_status) { uint32_t tcp_ss = le_to_h_u32(h->tcp_backend_priv.recv_buf); if (tcp_ss != STLINK_TCP_SS_OK) { if (tcp_ss == STLINK_TCP_SS_TCP_BUSY) { LOG_DEBUG("TCP busy"); return ERROR_WAIT; } LOG_ERROR("TCP error status 0x%X", tcp_ss); return ERROR_FAIL; } } return ERROR_OK; } /** */ static int stlink_tcp_xfer_noerrcheck(void *handle, const uint8_t *buf, int size) { struct stlink_usb_handle_s *h = handle; int send_size = STLINK_TCP_USB_CMD_SIZE; int recv_size = STLINK_TCP_SS_SIZE; assert(handle); /* prepare the TCP command */ h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_SEND_USB_CMD; memset(&h->tcp_backend_priv.send_buf[1], 0, 3); /* reserved for alignment and future use, must be zero */ h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.connect_id); /* tcp_backend_priv.send_buf[8..23] already contains the constructed stlink command */ h->tcp_backend_priv.send_buf[24] = h->direction; memset(&h->tcp_backend_priv.send_buf[25], 0, 3); /* reserved for alignment and future use, must be zero */ h_u32_to_le(&h->tcp_backend_priv.send_buf[28], size); /* * if the xfer is a write request (tx_ep) * > then buf content will be copied * into &cmdbuf[32]. * else : the xfer is a read or trace read request (rx_ep or trace_ep) * > the buf content will be filled from &databuf[4]. * * note : if h->direction is trace_ep, h->cmdbuf is zeros. */ if (h->direction == h->tx_ep) { /* STLINK_TCP_REQUEST_WRITE */ send_size += size; if (send_size > STLINK_TCP_SEND_BUFFER_SIZE) { LOG_ERROR("STLINK_TCP command buffer overflow"); return ERROR_FAIL; } memcpy(&h->tcp_backend_priv.send_buf[32], buf, size); } else { /* STLINK_TCP_REQUEST_READ or STLINK_TCP_REQUEST_READ_SWO */ recv_size += size; if (recv_size > STLINK_TCP_RECV_BUFFER_SIZE) { LOG_ERROR("STLINK_TCP data buffer overflow"); return ERROR_FAIL; } } int ret = stlink_tcp_send_cmd(h, send_size, recv_size, true); if (ret != ERROR_OK) return ret; if (h->direction != h->tx_ep) { /* the read data is located in tcp_backend_priv.recv_buf[4] */ /* most of the case it will be copying the data from tcp_backend_priv.recv_buf[4] * to handle->cmd_buff which are the same, so let's avoid unnecessary copying */ if (buf != &h->tcp_backend_priv.recv_buf[4]) memcpy((uint8_t *)buf, &h->tcp_backend_priv.recv_buf[4], size); } return ERROR_OK; } /** */ static int stlink_tcp_read_trace(void *handle, const uint8_t *buf, int size) { struct stlink_usb_handle_s *h = handle; stlink_usb_init_buffer(h, h->trace_ep, 0); return stlink_tcp_xfer_noerrcheck(handle, buf, size); } /** Converts an STLINK status code held in the first byte of a response to an openocd error, logs any error/wait status as debug output. */ static int stlink_usb_error_check(void *handle) { struct stlink_usb_handle_s *h = handle; assert(handle); if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { switch (h->databuf[0]) { case STLINK_SWIM_ERR_OK: return ERROR_OK; case STLINK_SWIM_BUSY: return ERROR_WAIT; default: LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]); return ERROR_FAIL; } } /* TODO: no error checking yet on api V1 */ if (h->version.jtag_api == STLINK_JTAG_API_V1) h->databuf[0] = STLINK_DEBUG_ERR_OK; switch (h->databuf[0]) { case STLINK_DEBUG_ERR_OK: return ERROR_OK; case STLINK_DEBUG_ERR_FAULT: LOG_DEBUG("SWD fault response (0x%x)", STLINK_DEBUG_ERR_FAULT); return ERROR_FAIL; case STLINK_SWD_AP_WAIT: LOG_DEBUG("wait status SWD_AP_WAIT (0x%x)", STLINK_SWD_AP_WAIT); return ERROR_WAIT; case STLINK_SWD_DP_WAIT: LOG_DEBUG("wait status SWD_DP_WAIT (0x%x)", STLINK_SWD_DP_WAIT); return ERROR_WAIT; case STLINK_JTAG_GET_IDCODE_ERROR: LOG_DEBUG("STLINK_JTAG_GET_IDCODE_ERROR"); return ERROR_FAIL; case STLINK_JTAG_WRITE_ERROR: LOG_DEBUG("Write error"); return ERROR_FAIL; case STLINK_JTAG_WRITE_VERIF_ERROR: LOG_DEBUG("Write verify error, ignoring"); return ERROR_OK; case STLINK_SWD_AP_FAULT: /* git://git.ac6.fr/openocd commit 657e3e885b9ee10 * returns ERROR_OK with the comment: * Change in error status when reading outside RAM. * This fix allows CDT plugin to visualize memory. */ LOG_DEBUG("STLINK_SWD_AP_FAULT"); return ERROR_FAIL; case STLINK_SWD_AP_ERROR: LOG_DEBUG("STLINK_SWD_AP_ERROR"); return ERROR_FAIL; case STLINK_SWD_AP_PARITY_ERROR: LOG_DEBUG("STLINK_SWD_AP_PARITY_ERROR"); return ERROR_FAIL; case STLINK_SWD_DP_FAULT: LOG_DEBUG("STLINK_SWD_DP_FAULT"); return ERROR_FAIL; case STLINK_SWD_DP_ERROR: LOG_DEBUG("STLINK_SWD_DP_ERROR"); return ERROR_FAIL; case STLINK_SWD_DP_PARITY_ERROR: LOG_DEBUG("STLINK_SWD_DP_PARITY_ERROR"); return ERROR_FAIL; case STLINK_SWD_AP_WDATA_ERROR: LOG_DEBUG("STLINK_SWD_AP_WDATA_ERROR"); return ERROR_FAIL; case STLINK_SWD_AP_STICKY_ERROR: LOG_DEBUG("STLINK_SWD_AP_STICKY_ERROR"); return ERROR_FAIL; case STLINK_SWD_AP_STICKYORUN_ERROR: LOG_DEBUG("STLINK_SWD_AP_STICKYORUN_ERROR"); return ERROR_FAIL; case STLINK_BAD_AP_ERROR: LOG_DEBUG("STLINK_BAD_AP_ERROR"); return ERROR_FAIL; default: LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]); return ERROR_FAIL; } } /* * Wrapper around stlink_usb_xfer_noerrcheck() * to check the error code in the received packet */ static int stlink_usb_xfer_errcheck(void *handle, const uint8_t *buf, int size) { int retval; assert(size > 0); retval = stlink_usb_xfer_noerrcheck(handle, buf, size); if (retval != ERROR_OK) return retval; return stlink_usb_error_check(handle); } /** Issue an STLINK command via USB transfer, with retries on any wait status responses. Works for commands where the STLINK_DEBUG status is returned in the first byte of the response packet. For SWIM a SWIM_READSTATUS is requested instead. Returns an openocd result code. */ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size) { int retries = 0; int res; struct stlink_usb_handle_s *h = handle; while (1) { if ((h->st_mode != STLINK_MODE_DEBUG_SWIM) || !retries) { res = stlink_usb_xfer_noerrcheck(handle, buf, size); if (res != ERROR_OK) return res; } if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { res = stlink_swim_status(handle); if (res != ERROR_OK) return res; } res = stlink_usb_error_check(handle); if (res == ERROR_WAIT && retries < MAX_WAIT_RETRIES) { unsigned int delay_us = (1<<retries++) * 1000; LOG_DEBUG("stlink_cmd_allow_retry ERROR_WAIT, retry %d, delaying %u microseconds", retries, delay_us); usleep(delay_us); continue; } return res; } } /** */ static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size) { struct stlink_usb_handle_s *h = handle; assert(handle); assert(h->version.flags & STLINK_F_HAS_TRACE); return h->backend->read_trace(handle, buf, size); } /* this function writes transfer length in the right place in the cb */ static void stlink_usb_set_cbw_transfer_datalength(void *handle, uint32_t size) { struct stlink_usb_handle_s *h = handle; buf_set_u32(h->cmdbuf+8, 0, 32, size); } static void stlink_usb_xfer_v1_create_cmd(void *handle, uint8_t direction, uint32_t size) { struct stlink_usb_handle_s *h = handle; /* fill the send buffer */ strcpy((char *)h->cmdbuf, "USBC"); h->cmdidx += 4; /* csw tag not used */ buf_set_u32(h->cmdbuf+h->cmdidx, 0, 32, 0); h->cmdidx += 4; /* cbw data transfer length (in the following data phase in or out) */ buf_set_u32(h->cmdbuf+h->cmdidx, 0, 32, size); h->cmdidx += 4; /* cbw flags */ h->cmdbuf[h->cmdidx++] = (direction == h->rx_ep ? ENDPOINT_IN : ENDPOINT_OUT); h->cmdbuf[h->cmdidx++] = 0; /* lun */ /* cdb clength (is filled in at xfer) */ h->cmdbuf[h->cmdidx++] = 0; } /** */ static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size) { struct stlink_usb_handle_s *h = handle; h->direction = direction; h->cmdidx = 0; memset(h->cmdbuf, 0, STLINK_SG_SIZE); memset(h->databuf, 0, STLINK_DATA_SIZE); if (h->version.stlink == 1) stlink_usb_xfer_v1_create_cmd(handle, direction, size); } /** */ static int stlink_usb_version(void *handle) { int res; uint32_t flags; uint16_t version; uint8_t v, x, y, jtag, swim, msd, bridge = 0; char v_str[5 * (1 + 3) + 1]; /* VvJjMmBbSs */ char *p; struct stlink_usb_handle_s *h = handle; assert(handle); stlink_usb_init_buffer(handle, h->rx_ep, 6); h->cmdbuf[h->cmdidx++] = STLINK_GET_VERSION; res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 6); if (res != ERROR_OK) return res; version = be_to_h_u16(h->databuf); v = (version >> 12) & 0x0f; x = (version >> 6) & 0x3f; y = version & 0x3f; h->vid = le_to_h_u16(h->databuf + 2); h->pid = le_to_h_u16(h->databuf + 4); switch (h->pid) { case STLINK_V2_1_PID: case STLINK_V2_1_NO_MSD_PID: if ((x <= 22 && y == 7) || (x >= 25 && y >= 7 && y <= 12)) { /* MxSy : STM8 V2.1 - SWIM only */ msd = x; swim = y; jtag = 0; } else { /* JxMy : STM32 V2.1 - JTAG/SWD only */ jtag = x; msd = y; swim = 0; } break; default: jtag = x; swim = y; msd = 0; break; } /* STLINK-V3 & STLINK-V3P require a specific command */ if (v >= 3 && x == 0 && y == 0) { stlink_usb_init_buffer(handle, h->rx_ep, 16); h->cmdbuf[h->cmdidx++] = STLINK_APIV3_GET_VERSION_EX; res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 12); if (res != ERROR_OK) return res; v = h->databuf[0]; swim = h->databuf[1]; jtag = h->databuf[2]; msd = h->databuf[3]; bridge = h->databuf[4]; h->vid = le_to_h_u16(h->databuf + 8); h->pid = le_to_h_u16(h->databuf + 10); } h->version.stlink = v; h->version.jtag = jtag; h->version.swim = swim; flags = 0; switch (h->version.stlink) { case 1: /* ST-LINK/V1 from J11 switch to api-v2 (and support SWD) */ if (h->version.jtag >= 11) h->version.jtag_api = STLINK_JTAG_API_V2; else h->version.jtag_api = STLINK_JTAG_API_V1; break; case 2: /* all ST-LINK/V2 and ST-Link/V2.1 use api-v2 */ h->version.jtag_api = STLINK_JTAG_API_V2; /* API for trace from J13 */ /* API for target voltage from J13 */ if (h->version.jtag >= 13) flags |= STLINK_F_HAS_TRACE; /* preferred API to get last R/W status from J15 */ if (h->version.jtag >= 15) flags |= STLINK_F_HAS_GETLASTRWSTATUS2; /* API to set SWD frequency from J22 */ if (h->version.jtag >= 22) flags |= STLINK_F_HAS_SWD_SET_FREQ; /* API to set JTAG frequency from J24 */ /* API to access DAP registers from J24 */ if (h->version.jtag >= 24) { flags |= STLINK_F_HAS_JTAG_SET_FREQ; flags |= STLINK_F_HAS_DAP_REG; } /* Quirk for read DP in JTAG mode (V2 only) from J24, fixed in J32 */ if (h->version.jtag >= 24 && h->version.jtag < 32) flags |= STLINK_F_QUIRK_JTAG_DP_READ; /* API to read/write memory at 16 bit from J26 */ /* API to write memory without address increment from J26 */ if (h->version.jtag >= 26) flags |= STLINK_F_HAS_MEM_16BIT; /* API required to init AP before any AP access from J28 */ if (h->version.jtag >= 28) flags |= STLINK_F_HAS_AP_INIT; /* API required to return proper error code on close AP from J29 */ if (h->version.jtag >= 29) flags |= STLINK_F_FIX_CLOSE_AP; /* Banked regs (DPv1 & DPv2) support from V2J32 */ /* API to read memory without address increment from V2J32 */ /* Memory R/W supports CSW from V2J32 */ if (h->version.jtag >= 32) flags |= STLINK_F_HAS_DPBANKSEL; break; case 3: /* all STLINK-V3 use api-v3 */ h->version.jtag_api = STLINK_JTAG_API_V3; /* STLINK-V3 is a superset of ST-LINK/V2 */ /* API for trace */ /* API for target voltage */ flags |= STLINK_F_HAS_TRACE; /* preferred API to get last R/W status */ flags |= STLINK_F_HAS_GETLASTRWSTATUS2; /* API to access DAP registers */ flags |= STLINK_F_HAS_DAP_REG; /* API to read/write memory at 16 bit */ /* API to write memory without address increment */ flags |= STLINK_F_HAS_MEM_16BIT; /* API required to init AP before any AP access */ flags |= STLINK_F_HAS_AP_INIT; /* API required to return proper error code on close AP */ flags |= STLINK_F_FIX_CLOSE_AP; /* Banked regs (DPv1 & DPv2) support from V3J2 */ /* API to read memory without address increment from V3J2 */ /* Memory R/W supports CSW from V3J2 */ if (h->version.jtag >= 2) flags |= STLINK_F_HAS_DPBANKSEL; /* 8bit read/write max packet size 512 bytes from V3J6 */ if (h->version.jtag >= 6) flags |= STLINK_F_HAS_RW8_512BYTES; break; case 4: /* STLINK-V3P use api-v3 */ h->version.jtag_api = STLINK_JTAG_API_V3; /* STLINK-V3P is a superset of ST-LINK/V3 */ /* API for trace */ /* API for target voltage */ flags |= STLINK_F_HAS_TRACE; /* preferred API to get last R/W status */ flags |= STLINK_F_HAS_GETLASTRWSTATUS2; /* API to access DAP registers */ flags |= STLINK_F_HAS_DAP_REG; /* API to read/write memory at 16 bit */ /* API to write memory without address increment */ flags |= STLINK_F_HAS_MEM_16BIT; /* API required to init AP before any AP access */ flags |= STLINK_F_HAS_AP_INIT; /* API required to return proper error code on close AP */ flags |= STLINK_F_FIX_CLOSE_AP; /* Banked regs (DPv1 & DPv2) support */ /* API to read memory without address increment */ /* Memory R/W supports CSW */ flags |= STLINK_F_HAS_DPBANKSEL; /* 8bit read/write max packet size 512 bytes */ flags |= STLINK_F_HAS_RW8_512BYTES; break; default: break; } h->version.flags = flags; p = v_str; p += sprintf(p, "V%d", v); if (jtag || !msd) p += sprintf(p, "J%d", jtag); if (msd) p += sprintf(p, "M%d", msd); if (bridge) p += sprintf(p, "B%d", bridge); if (swim || !msd) sprintf(p, "S%d", swim); LOG_INFO("STLINK %s (API v%d) VID:PID %04X:%04X", v_str, h->version.jtag_api, h->vid, h->pid); return ERROR_OK; } static int stlink_usb_check_voltage(void *handle, float *target_voltage) { struct stlink_usb_handle_s *h = handle; uint32_t adc_results[2]; /* no error message, simply quit with error */ if (!(h->version.flags & STLINK_F_HAS_TARGET_VOLT)) return ERROR_COMMAND_NOTFOUND; stlink_usb_init_buffer(handle, h->rx_ep, 8); h->cmdbuf[h->cmdidx++] = STLINK_GET_TARGET_VOLTAGE; int result = stlink_usb_xfer_noerrcheck(handle, h->databuf, 8); if (result != ERROR_OK) return result; /* convert result */ adc_results[0] = le_to_h_u32(h->databuf); adc_results[1] = le_to_h_u32(h->databuf + 4); *target_voltage = 0; if (adc_results[0]) *target_voltage = 2 * ((float)adc_results[1]) * (float)(1.2 / adc_results[0]); LOG_INFO("Target voltage: %f", (double)*target_voltage); return ERROR_OK; } static int stlink_usb_set_swdclk(void *handle, uint16_t clk_divisor) { struct stlink_usb_handle_s *h = handle; assert(handle); if (!(h->version.flags & STLINK_F_HAS_SWD_SET_FREQ)) return ERROR_COMMAND_NOTFOUND; stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_SWD_SET_FREQ; h_u16_to_le(h->cmdbuf+h->cmdidx, clk_divisor); h->cmdidx += 2; int result = stlink_cmd_allow_retry(handle, h->databuf, 2); if (result != ERROR_OK) return result; return ERROR_OK; } static int stlink_usb_set_jtagclk(void *handle, uint16_t clk_divisor) { struct stlink_usb_handle_s *h = handle; assert(handle); if (!(h->version.flags & STLINK_F_HAS_JTAG_SET_FREQ)) return ERROR_COMMAND_NOTFOUND; stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_JTAG_SET_FREQ; h_u16_to_le(h->cmdbuf+h->cmdidx, clk_divisor); h->cmdidx += 2; int result = stlink_cmd_allow_retry(handle, h->databuf, 2); if (result != ERROR_OK) return result; return ERROR_OK; } /** */ static int stlink_usb_current_mode(void *handle, uint8_t *mode) { int res; struct stlink_usb_handle_s *h = handle; assert(handle); stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_GET_CURRENT_MODE; res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 2); if (res != ERROR_OK) return res; *mode = h->databuf[0]; return ERROR_OK; } /** */ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type) { int rx_size = 0; struct stlink_usb_handle_s *h = handle; assert(handle); /* on api V2 we are able the read the latest command * status * TODO: we need the test on api V1 too */ if (h->version.jtag_api != STLINK_JTAG_API_V1) rx_size = 2; stlink_usb_init_buffer(handle, h->rx_ep, rx_size); switch (type) { case STLINK_MODE_DEBUG_JTAG: h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->version.jtag_api == STLINK_JTAG_API_V1) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_ENTER; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_ENTER; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_ENTER_JTAG_NO_RESET; break; case STLINK_MODE_DEBUG_SWD: h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->version.jtag_api == STLINK_JTAG_API_V1) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_ENTER; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_ENTER; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_ENTER_SWD_NO_RESET; break; case STLINK_MODE_DEBUG_SWIM: h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER; /* swim enter does not return any response or status */ return stlink_usb_xfer_noerrcheck(handle, h->databuf, 0); case STLINK_MODE_DFU: case STLINK_MODE_MASS: default: return ERROR_FAIL; } return stlink_cmd_allow_retry(handle, h->databuf, rx_size); } /** */ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type) { int res; struct stlink_usb_handle_s *h = handle; assert(handle); /* command with no reply, use a valid endpoint but zero size */ stlink_usb_init_buffer(handle, h->rx_ep, 0); switch (type) { case STLINK_MODE_DEBUG_JTAG: case STLINK_MODE_DEBUG_SWD: h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_EXIT; break; case STLINK_MODE_DEBUG_SWIM: h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_EXIT; break; case STLINK_MODE_DFU: h->cmdbuf[h->cmdidx++] = STLINK_DFU_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DFU_EXIT; break; case STLINK_MODE_MASS: default: return ERROR_FAIL; } res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 0); if (res != ERROR_OK) return res; return ERROR_OK; } static int stlink_usb_assert_srst(void *handle, int srst); static enum stlink_mode stlink_get_mode(enum hl_transports t) { switch (t) { case HL_TRANSPORT_SWD: return STLINK_MODE_DEBUG_SWD; case HL_TRANSPORT_JTAG: return STLINK_MODE_DEBUG_JTAG; default: return STLINK_MODE_UNKNOWN; } } /** */ static int stlink_usb_exit_mode(void *handle) { int res; uint8_t mode; enum stlink_mode emode; assert(handle); res = stlink_usb_current_mode(handle, &mode); if (res != ERROR_OK) return res; LOG_DEBUG("MODE: 0x%02X", mode); /* try to exit current mode */ switch (mode) { case STLINK_DEV_DFU_MODE: emode = STLINK_MODE_DFU; break; case STLINK_DEV_DEBUG_MODE: emode = STLINK_MODE_DEBUG_SWD; break; case STLINK_DEV_SWIM_MODE: emode = STLINK_MODE_DEBUG_SWIM; break; case STLINK_DEV_BOOTLOADER_MODE: case STLINK_DEV_MASS_MODE: default: emode = STLINK_MODE_UNKNOWN; break; } if (emode != STLINK_MODE_UNKNOWN) return stlink_usb_mode_leave(handle, emode); return ERROR_OK; } /** */ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int initial_interface_speed) { int res; uint8_t mode; enum stlink_mode emode; struct stlink_usb_handle_s *h = handle; assert(handle); res = stlink_usb_exit_mode(handle); if (res != ERROR_OK) return res; res = stlink_usb_current_mode(handle, &mode); if (res != ERROR_OK) return res; /* we check the target voltage here as an aid to debugging connection problems. * the stlink requires the target Vdd to be connected for reliable debugging. * this cmd is supported in all modes except DFU */ if (mode != STLINK_DEV_DFU_MODE) { float target_voltage; /* check target voltage (if supported) */ res = stlink_usb_check_voltage(h, &target_voltage); if (res != ERROR_OK) { if (res != ERROR_COMMAND_NOTFOUND) LOG_ERROR("voltage check failed"); /* attempt to continue as it is not a catastrophic failure */ } else { /* check for a sensible target voltage, operating range is 1.65-5.5v * according to datasheet */ if (target_voltage < 1.5) LOG_ERROR("target voltage may be too low for reliable debugging"); } } LOG_DEBUG("MODE: 0x%02X", mode); /* set selected mode */ emode = h->st_mode; if (emode == STLINK_MODE_UNKNOWN) { LOG_ERROR("selected mode (transport) not supported"); return ERROR_FAIL; } /* set the speed before entering the mode, as the chip discovery phase should be done at this speed too */ if (emode == STLINK_MODE_DEBUG_JTAG) { if (h->version.flags & STLINK_F_HAS_JTAG_SET_FREQ) { stlink_dump_speed_map(stlink_khz_to_speed_map_jtag, ARRAY_SIZE(stlink_khz_to_speed_map_jtag)); stlink_speed(h, initial_interface_speed, false); } } else if (emode == STLINK_MODE_DEBUG_SWD) { if (h->version.flags & STLINK_F_HAS_SWD_SET_FREQ) { stlink_dump_speed_map(stlink_khz_to_speed_map_swd, ARRAY_SIZE(stlink_khz_to_speed_map_swd)); stlink_speed(h, initial_interface_speed, false); } } if (h->version.jtag_api == STLINK_JTAG_API_V3 && (emode == STLINK_MODE_DEBUG_JTAG || emode == STLINK_MODE_DEBUG_SWD)) { struct speed_map map[STLINK_V3_MAX_FREQ_NB]; stlink_get_com_freq(h, (emode == STLINK_MODE_DEBUG_JTAG), map); stlink_dump_speed_map(map, ARRAY_SIZE(map)); stlink_speed(h, initial_interface_speed, false); } /* preliminary SRST assert: * We want SRST is asserted before activating debug signals (mode_enter). * As the required mode has not been set, the adapter may not know what pin to use. * Tested firmware STLINK v2 JTAG v29 API v2 SWIM v0 uses T_NRST pin by default * Tested firmware STLINK v2 JTAG v27 API v2 SWIM v6 uses T_NRST pin by default * after power on, SWIM_RST stays unchanged */ if (connect_under_reset && emode != STLINK_MODE_DEBUG_SWIM) stlink_usb_assert_srst(handle, 0); /* do not check the return status here, we will proceed and enter the desired mode below and try asserting srst again. */ res = stlink_usb_mode_enter(handle, emode); if (res != ERROR_OK) return res; /* assert SRST again: a little bit late but now the adapter knows for sure what pin to use */ if (connect_under_reset) { res = stlink_usb_assert_srst(handle, 0); if (res != ERROR_OK) return res; } res = stlink_usb_current_mode(handle, &mode); if (res != ERROR_OK) return res; LOG_DEBUG("MODE: 0x%02X", mode); return ERROR_OK; } /* request status from last swim request */ static int stlink_swim_status(void *handle) { struct stlink_usb_handle_s *h = handle; int res; stlink_usb_init_buffer(handle, h->rx_ep, 4); h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READSTATUS; /* error is checked by the caller */ res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 4); if (res != ERROR_OK) return res; return ERROR_OK; } /* the purpose of this function is unknown... capabilities? anyway for swim v6 it returns 0001020600000000 */ __attribute__((unused)) static int stlink_swim_cap(void *handle, uint8_t *cap) { struct stlink_usb_handle_s *h = handle; int res; stlink_usb_init_buffer(handle, h->rx_ep, 8); h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READ_CAP; h->cmdbuf[h->cmdidx++] = 0x01; res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 8); if (res != ERROR_OK) return res; memcpy(cap, h->databuf, 8); return ERROR_OK; } /* debug dongle assert/deassert sreset line */ static int stlink_swim_assert_reset(void *handle, int reset) { struct stlink_usb_handle_s *h = handle; int res; stlink_usb_init_buffer(handle, h->rx_ep, 0); h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; if (!reset) h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ASSERT_RESET; else h->cmdbuf[h->cmdidx++] = STLINK_SWIM_DEASSERT_RESET; res = stlink_cmd_allow_retry(handle, h->databuf, 0); if (res != ERROR_OK) return res; return ERROR_OK; } /* send swim enter seq 1.3ms low then 750Hz then 1.5kHz */ static int stlink_swim_enter(void *handle) { struct stlink_usb_handle_s *h = handle; int res; stlink_usb_init_buffer(handle, h->rx_ep, 0); h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER_SEQ; res = stlink_cmd_allow_retry(handle, h->databuf, 0); if (res != ERROR_OK) return res; return ERROR_OK; } /* switch high/low speed swim */ static int stlink_swim_speed(void *handle, int speed) { struct stlink_usb_handle_s *h = handle; int res; stlink_usb_init_buffer(handle, h->rx_ep, 0); h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_SPEED; if (speed) h->cmdbuf[h->cmdidx++] = 1; else h->cmdbuf[h->cmdidx++] = 0; res = stlink_cmd_allow_retry(handle, h->databuf, 0); if (res != ERROR_OK) return res; return ERROR_OK; } /* initiate srst from swim. nrst is pulled low for 50us. */ static int stlink_swim_generate_rst(void *handle) { struct stlink_usb_handle_s *h = handle; int res; stlink_usb_init_buffer(handle, h->rx_ep, 0); h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_GEN_RST; res = stlink_cmd_allow_retry(handle, h->databuf, 0); if (res != ERROR_OK) return res; return ERROR_OK; } /* send resynchronize sequence swim is pulled low for 16us reply is 64 clks low */ static int stlink_swim_resync(void *handle) { struct stlink_usb_handle_s *h = handle; int res; stlink_usb_init_buffer(handle, h->rx_ep, 0); h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_RESET; res = stlink_cmd_allow_retry(handle, h->databuf, 0); if (res != ERROR_OK) return res; return ERROR_OK; } static int stlink_swim_writebytes(void *handle, uint32_t addr, uint32_t len, const uint8_t *data) { struct stlink_usb_handle_s *h = handle; int res; unsigned int i; unsigned int datalen = 0; int cmdsize = STLINK_CMD_SIZE_V2; if (len > STLINK_SWIM_DATA_SIZE) return ERROR_FAIL; if (h->version.stlink == 1) cmdsize = STLINK_SG_SIZE; stlink_usb_init_buffer(handle, h->tx_ep, 0); h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_WRITEMEM; h_u16_to_be(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; h_u32_to_be(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; for (i = 0; i < len; i++) { if (h->cmdidx == cmdsize) h->databuf[datalen++] = *(data++); else h->cmdbuf[h->cmdidx++] = *(data++); } if (h->version.stlink == 1) stlink_usb_set_cbw_transfer_datalength(handle, datalen); res = stlink_cmd_allow_retry(handle, h->databuf, datalen); if (res != ERROR_OK) return res; return ERROR_OK; } static int stlink_swim_readbytes(void *handle, uint32_t addr, uint32_t len, uint8_t *data) { struct stlink_usb_handle_s *h = handle; int res; if (len > STLINK_SWIM_DATA_SIZE) return ERROR_FAIL; stlink_usb_init_buffer(handle, h->rx_ep, 0); h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READMEM; h_u16_to_be(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; h_u32_to_be(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; res = stlink_cmd_allow_retry(handle, h->databuf, 0); if (res != ERROR_OK) return res; stlink_usb_init_buffer(handle, h->rx_ep, len); h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_READBUF; res = stlink_usb_xfer_noerrcheck(handle, data, len); if (res != ERROR_OK) return res; return ERROR_OK; } /** */ static int stlink_usb_idcode(void *handle, uint32_t *idcode) { int res, offset; struct stlink_usb_handle_s *h = handle; assert(handle); /* there is no swim read core id cmd */ if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { *idcode = 0; return ERROR_OK; } stlink_usb_init_buffer(handle, h->rx_ep, 12); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->version.jtag_api == STLINK_JTAG_API_V1) { h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READCOREID; res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 4); offset = 0; } else { h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READ_IDCODES; res = stlink_usb_xfer_errcheck(handle, h->databuf, 12); offset = 4; } if (res != ERROR_OK) return res; *idcode = le_to_h_u32(h->databuf + offset); LOG_DEBUG("IDCODE: 0x%08" PRIX32, *idcode); return ERROR_OK; } static int stlink_usb_v2_read_debug_reg(void *handle, uint32_t addr, uint32_t *val) { struct stlink_usb_handle_s *h = handle; int res; assert(handle); stlink_usb_init_buffer(handle, h->rx_ep, 8); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READDEBUGREG; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; res = stlink_cmd_allow_retry(handle, h->databuf, 8); if (res != ERROR_OK) return res; *val = le_to_h_u32(h->databuf + 4); return ERROR_OK; } static int stlink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) { struct stlink_usb_handle_s *h = handle; assert(handle); stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->version.jtag_api == STLINK_JTAG_API_V1) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_WRITEDEBUGREG; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITEDEBUGREG; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; h_u32_to_le(h->cmdbuf+h->cmdidx, val); h->cmdidx += 4; return stlink_cmd_allow_retry(handle, h->databuf, 2); } /** */ static int stlink_usb_trace_read(void *handle, uint8_t *buf, size_t *size) { struct stlink_usb_handle_s *h = handle; assert(handle); if (h->trace.enabled && (h->version.flags & STLINK_F_HAS_TRACE)) { int res; stlink_usb_init_buffer(handle, h->rx_ep, 10); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_GET_TRACE_NB; res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 2); if (res != ERROR_OK) return res; size_t bytes_avail = le_to_h_u16(h->databuf); *size = bytes_avail < *size ? bytes_avail : *size; if (*size > 0) { res = stlink_usb_read_trace(handle, buf, *size); if (res != ERROR_OK) return res; return ERROR_OK; } } *size = 0; return ERROR_OK; } static enum target_state stlink_usb_v2_get_status(void *handle) { int result; uint32_t status; result = stlink_usb_v2_read_debug_reg(handle, DCB_DHCSR, &status); if (result != ERROR_OK) return TARGET_UNKNOWN; if (status & S_HALT) return TARGET_HALTED; else if (status & S_RESET_ST) return TARGET_RESET; return TARGET_RUNNING; } /** */ static enum target_state stlink_usb_state(void *handle) { int res; struct stlink_usb_handle_s *h = handle; assert(handle); if (h->reconnect_pending) { LOG_INFO("Previous state query failed, trying to reconnect"); res = stlink_usb_mode_enter(handle, h->st_mode); if (res != ERROR_OK) return TARGET_UNKNOWN; h->reconnect_pending = false; } if (h->version.jtag_api != STLINK_JTAG_API_V1) { res = stlink_usb_v2_get_status(handle); if (res == TARGET_UNKNOWN) h->reconnect_pending = true; return res; } stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_GETSTATUS; res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 2); if (res != ERROR_OK) return TARGET_UNKNOWN; if (h->databuf[0] == STLINK_CORE_RUNNING) return TARGET_RUNNING; if (h->databuf[0] == STLINK_CORE_HALTED) return TARGET_HALTED; h->reconnect_pending = true; return TARGET_UNKNOWN; } static int stlink_usb_assert_srst(void *handle, int srst) { struct stlink_usb_handle_s *h = handle; assert(handle); if (h->st_mode == STLINK_MODE_DEBUG_SWIM) return stlink_swim_assert_reset(handle, srst); if (h->version.stlink == 1) return ERROR_COMMAND_NOTFOUND; stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_DRIVE_NRST; h->cmdbuf[h->cmdidx++] = srst; return stlink_cmd_allow_retry(handle, h->databuf, 2); } /** */ static void stlink_usb_trace_disable(void *handle) { int res = ERROR_OK; struct stlink_usb_handle_s *h = handle; assert(handle); assert(h->version.flags & STLINK_F_HAS_TRACE); LOG_DEBUG("Tracing: disable"); stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_STOP_TRACE_RX; res = stlink_usb_xfer_errcheck(handle, h->databuf, 2); if (res == ERROR_OK) h->trace.enabled = false; } /** */ static int stlink_usb_trace_enable(void *handle) { int res; struct stlink_usb_handle_s *h = handle; assert(handle); if (h->version.flags & STLINK_F_HAS_TRACE) { stlink_usb_init_buffer(handle, h->rx_ep, 10); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_START_TRACE_RX; h_u16_to_le(h->cmdbuf+h->cmdidx, (uint16_t)STLINK_TRACE_SIZE); h->cmdidx += 2; h_u32_to_le(h->cmdbuf+h->cmdidx, h->trace.source_hz); h->cmdidx += 4; res = stlink_usb_xfer_errcheck(handle, h->databuf, 2); if (res == ERROR_OK) { h->trace.enabled = true; LOG_DEBUG("Tracing: recording at %" PRIu32 "Hz", h->trace.source_hz); } } else { LOG_ERROR("Tracing is not supported by this version."); res = ERROR_FAIL; } return res; } /** */ static int stlink_usb_reset(void *handle) { struct stlink_usb_handle_s *h = handle; int retval; assert(handle); stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->version.jtag_api == STLINK_JTAG_API_V1) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_RESETSYS; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RESETSYS; retval = stlink_cmd_allow_retry(handle, h->databuf, 2); if (retval != ERROR_OK) return retval; if (h->trace.enabled) { stlink_usb_trace_disable(h); return stlink_usb_trace_enable(h); } return ERROR_OK; } /** */ static int stlink_usb_run(void *handle) { int res; struct stlink_usb_handle_s *h = handle; assert(handle); if (h->version.jtag_api != STLINK_JTAG_API_V1) { res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_DEBUGEN); return res; } stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_RUNCORE; return stlink_cmd_allow_retry(handle, h->databuf, 2); } /** */ static int stlink_usb_halt(void *handle) { int res; struct stlink_usb_handle_s *h = handle; assert(handle); if (h->version.jtag_api != STLINK_JTAG_API_V1) { res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN); return res; } stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_FORCEDEBUG; return stlink_cmd_allow_retry(handle, h->databuf, 2); } /** */ static int stlink_usb_step(void *handle) { struct stlink_usb_handle_s *h = handle; assert(handle); if (h->version.jtag_api != STLINK_JTAG_API_V1) { /* TODO: this emulates the v1 api, it should really use a similar auto mask isr * that the Cortex-M3 currently does. */ stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_MASKINTS|C_DEBUGEN); stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_STEP|C_MASKINTS|C_DEBUGEN); return stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN); } stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_STEPCORE; return stlink_cmd_allow_retry(handle, h->databuf, 2); } /** */ static int stlink_usb_read_regs(void *handle) { int res; struct stlink_usb_handle_s *h = handle; assert(handle); stlink_usb_init_buffer(handle, h->rx_ep, 88); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->version.jtag_api == STLINK_JTAG_API_V1) { h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_READALLREGS; res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 84); /* regs data from offset 0 */ } else { h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READALLREGS; res = stlink_usb_xfer_errcheck(handle, h->databuf, 88); /* status at offset 0, regs data from offset 4 */ } return res; } /** */ static int stlink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) { int res; struct stlink_usb_handle_s *h = handle; assert(handle); if (STLINK_REGSEL_IS_FPU(regsel) && !(h->version.flags & STLINK_F_HAS_FPU_REG)) { res = stlink_usb_write_debug_reg(h, DCB_DCRSR, regsel & 0x7f); if (res != ERROR_OK) return res; /* FIXME: poll DHCSR.S_REGRDY before read DCRDR */ return stlink_usb_v2_read_debug_reg(h, DCB_DCRDR, val); } stlink_usb_init_buffer(handle, h->rx_ep, h->version.jtag_api == STLINK_JTAG_API_V1 ? 4 : 8); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->version.jtag_api == STLINK_JTAG_API_V1) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_READREG; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READREG; h->cmdbuf[h->cmdidx++] = regsel; if (h->version.jtag_api == STLINK_JTAG_API_V1) { res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 4); if (res != ERROR_OK) return res; *val = le_to_h_u32(h->databuf); return ERROR_OK; } else { res = stlink_cmd_allow_retry(handle, h->databuf, 8); if (res != ERROR_OK) return res; *val = le_to_h_u32(h->databuf + 4); return ERROR_OK; } } /** */ static int stlink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val) { struct stlink_usb_handle_s *h = handle; assert(handle); if (STLINK_REGSEL_IS_FPU(regsel) && !(h->version.flags & STLINK_F_HAS_FPU_REG)) { int res = stlink_usb_write_debug_reg(h, DCB_DCRDR, val); if (res != ERROR_OK) return res; return stlink_usb_write_debug_reg(h, DCB_DCRSR, DCRSR_WNR | (regsel & 0x7f)); /* FIXME: poll DHCSR.S_REGRDY after write DCRSR */ } stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->version.jtag_api == STLINK_JTAG_API_V1) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_WRITEREG; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITEREG; h->cmdbuf[h->cmdidx++] = regsel; h_u32_to_le(h->cmdbuf+h->cmdidx, val); h->cmdidx += 4; return stlink_cmd_allow_retry(handle, h->databuf, 2); } static int stlink_usb_get_rw_status(void *handle) { struct stlink_usb_handle_s *h = handle; assert(handle); if (h->version.jtag_api == STLINK_JTAG_API_V1) return ERROR_OK; stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->version.flags & STLINK_F_HAS_GETLASTRWSTATUS2) { h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_GETLASTRWSTATUS2; return stlink_usb_xfer_errcheck(handle, h->databuf, 12); } else { h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_GETLASTRWSTATUS; return stlink_usb_xfer_errcheck(handle, h->databuf, 2); } } /** */ static int stlink_usb_read_mem8(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, uint8_t *buffer) { int res; uint16_t read_len = len; struct stlink_usb_handle_s *h = handle; assert(handle); if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW)) return ERROR_COMMAND_NOTFOUND; /* max 8 bit read/write is 64 bytes or 512 bytes for v3 */ if (len > stlink_usb_block(h)) { LOG_DEBUG("max buffer (%d) length exceeded", stlink_usb_block(h)); return ERROR_FAIL; } stlink_usb_init_buffer(handle, h->rx_ep, read_len); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READMEM_8BIT; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; h->cmdbuf[h->cmdidx++] = ap_num; h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); h->cmdidx += 3; /* we need to fix read length for single bytes */ if (read_len == 1) read_len++; res = stlink_usb_xfer_noerrcheck(handle, h->databuf, read_len); if (res != ERROR_OK) return res; memcpy(buffer, h->databuf, len); return stlink_usb_get_rw_status(handle); } /** */ static int stlink_usb_write_mem8(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, const uint8_t *buffer) { int res; struct stlink_usb_handle_s *h = handle; assert(handle); if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW)) return ERROR_COMMAND_NOTFOUND; /* max 8 bit read/write is 64 bytes or 512 bytes for v3 */ if (len > stlink_usb_block(h)) { LOG_DEBUG("max buffer length (%d) exceeded", stlink_usb_block(h)); return ERROR_FAIL; } stlink_usb_init_buffer(handle, h->tx_ep, len); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_WRITEMEM_8BIT; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; h->cmdbuf[h->cmdidx++] = ap_num; h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); h->cmdidx += 3; res = stlink_usb_xfer_noerrcheck(handle, buffer, len); if (res != ERROR_OK) return res; return stlink_usb_get_rw_status(handle); } /** */ static int stlink_usb_read_mem16(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, uint8_t *buffer) { int res; struct stlink_usb_handle_s *h = handle; assert(handle); if (!(h->version.flags & STLINK_F_HAS_MEM_16BIT)) return ERROR_COMMAND_NOTFOUND; if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW)) return ERROR_COMMAND_NOTFOUND; if (len > STLINK_MAX_RW16_32) { LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32); return ERROR_FAIL; } /* data must be a multiple of 2 and half-word aligned */ if (len % 2 || addr % 2) { LOG_DEBUG("Invalid data alignment"); return ERROR_TARGET_UNALIGNED_ACCESS; } stlink_usb_init_buffer(handle, h->rx_ep, len); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READMEM_16BIT; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; h->cmdbuf[h->cmdidx++] = ap_num; h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); h->cmdidx += 3; res = stlink_usb_xfer_noerrcheck(handle, h->databuf, len); if (res != ERROR_OK) return res; memcpy(buffer, h->databuf, len); return stlink_usb_get_rw_status(handle); } /** */ static int stlink_usb_write_mem16(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, const uint8_t *buffer) { int res; struct stlink_usb_handle_s *h = handle; assert(handle); if (!(h->version.flags & STLINK_F_HAS_MEM_16BIT)) return ERROR_COMMAND_NOTFOUND; if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW)) return ERROR_COMMAND_NOTFOUND; if (len > STLINK_MAX_RW16_32) { LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32); return ERROR_FAIL; } /* data must be a multiple of 2 and half-word aligned */ if (len % 2 || addr % 2) { LOG_DEBUG("Invalid data alignment"); return ERROR_TARGET_UNALIGNED_ACCESS; } stlink_usb_init_buffer(handle, h->tx_ep, len); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITEMEM_16BIT; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; h->cmdbuf[h->cmdidx++] = ap_num; h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); h->cmdidx += 3; res = stlink_usb_xfer_noerrcheck(handle, buffer, len); if (res != ERROR_OK) return res; return stlink_usb_get_rw_status(handle); } /** */ static int stlink_usb_read_mem32(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, uint8_t *buffer) { int res; struct stlink_usb_handle_s *h = handle; assert(handle); if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW)) return ERROR_COMMAND_NOTFOUND; if (len > STLINK_MAX_RW16_32) { LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32); return ERROR_FAIL; } /* data must be a multiple of 4 and word aligned */ if (len % 4 || addr % 4) { LOG_DEBUG("Invalid data alignment"); return ERROR_TARGET_UNALIGNED_ACCESS; } stlink_usb_init_buffer(handle, h->rx_ep, len); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READMEM_32BIT; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; h->cmdbuf[h->cmdidx++] = ap_num; h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); h->cmdidx += 3; res = stlink_usb_xfer_noerrcheck(handle, h->databuf, len); if (res != ERROR_OK) return res; memcpy(buffer, h->databuf, len); return stlink_usb_get_rw_status(handle); } /** */ static int stlink_usb_write_mem32(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, const uint8_t *buffer) { int res; struct stlink_usb_handle_s *h = handle; assert(handle); if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW)) return ERROR_COMMAND_NOTFOUND; if (len > STLINK_MAX_RW16_32) { LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32); return ERROR_FAIL; } /* data must be a multiple of 4 and word aligned */ if (len % 4 || addr % 4) { LOG_DEBUG("Invalid data alignment"); return ERROR_TARGET_UNALIGNED_ACCESS; } stlink_usb_init_buffer(handle, h->tx_ep, len); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_WRITEMEM_32BIT; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; h->cmdbuf[h->cmdidx++] = ap_num; h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); h->cmdidx += 3; res = stlink_usb_xfer_noerrcheck(handle, buffer, len); if (res != ERROR_OK) return res; return stlink_usb_get_rw_status(handle); } static int stlink_usb_read_mem32_noaddrinc(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, uint8_t *buffer) { struct stlink_usb_handle_s *h = handle; assert(handle != NULL); if (!(h->version.flags & STLINK_F_HAS_MEM_RD_NO_INC)) return ERROR_COMMAND_NOTFOUND; if (len > STLINK_MAX_RW16_32) { LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32); return ERROR_FAIL; } /* data must be a multiple of 4 and word aligned */ if (len % 4 || addr % 4) { LOG_DEBUG("Invalid data alignment"); return ERROR_TARGET_UNALIGNED_ACCESS; } stlink_usb_init_buffer(handle, h->rx_ep, len); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READMEM_32BIT_NO_ADDR_INC; h_u32_to_le(h->cmdbuf + h->cmdidx, addr); h->cmdidx += 4; h_u16_to_le(h->cmdbuf + h->cmdidx, len); h->cmdidx += 2; h->cmdbuf[h->cmdidx++] = ap_num; h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); h->cmdidx += 3; int retval = stlink_usb_xfer_noerrcheck(handle, h->databuf, len); if (retval != ERROR_OK) return retval; memcpy(buffer, h->databuf, len); return stlink_usb_get_rw_status(handle); } static int stlink_usb_write_mem32_noaddrinc(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, const uint8_t *buffer) { struct stlink_usb_handle_s *h = handle; assert(handle != NULL); if (!(h->version.flags & STLINK_F_HAS_MEM_WR_NO_INC)) return ERROR_COMMAND_NOTFOUND; if (len > STLINK_MAX_RW16_32) { LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32); return ERROR_FAIL; } /* data must be a multiple of 4 and word aligned */ if (len % 4 || addr % 4) { LOG_DEBUG("Invalid data alignment"); return ERROR_TARGET_UNALIGNED_ACCESS; } stlink_usb_init_buffer(handle, h->tx_ep, len); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_WRITEMEM_32BIT_NO_ADDR_INC; h_u32_to_le(h->cmdbuf + h->cmdidx, addr); h->cmdidx += 4; h_u16_to_le(h->cmdbuf + h->cmdidx, len); h->cmdidx += 2; h->cmdbuf[h->cmdidx++] = ap_num; h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); h->cmdidx += 3; int retval = stlink_usb_xfer_noerrcheck(handle, buffer, len); if (retval != ERROR_OK) return retval; return stlink_usb_get_rw_status(handle); } static uint32_t stlink_max_block_size(uint32_t tar_autoincr_block, uint32_t address) { uint32_t max_tar_block = (tar_autoincr_block - ((tar_autoincr_block - 1) & address)); if (max_tar_block == 0) max_tar_block = 4; return max_tar_block; } static int stlink_usb_read_ap_mem(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer) { int retval = ERROR_OK; uint32_t bytes_remaining; int retries = 0; struct stlink_usb_handle_s *h = handle; /* calculate byte count */ count *= size; /* switch to 8 bit if stlink does not support 16 bit memory read */ if (size == 2 && !(h->version.flags & STLINK_F_HAS_MEM_16BIT)) size = 1; while (count) { bytes_remaining = (size != 1) ? stlink_max_block_size(h->max_mem_packet, addr) : stlink_usb_block(h); if (count < bytes_remaining) bytes_remaining = count; /* * all stlink support 8/32bit memory read/writes and only from * stlink V2J26 there is support for 16 bit memory read/write. * Honour 32 bit and, if possible, 16 bit too. Otherwise, handle * as 8bit access. */ if (size != 1) { /* When in jtag mode the stlink uses the auto-increment functionality. * However it expects us to pass the data correctly, this includes * alignment and any page boundaries. We already do this as part of the * adi_v5 implementation, but the stlink is a hla adapter and so this * needs implementing manually. * currently this only affects jtag mode, according to ST they do single * access in SWD mode - but this may change and so we do it for both modes */ /* we first need to check for any unaligned bytes */ if (addr & (size - 1)) { uint32_t head_bytes = size - (addr & (size - 1)); retval = stlink_usb_read_mem8(handle, ap_num, csw, addr, head_bytes, buffer); if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) { usleep((1 << retries++) * 1000); continue; } if (retval != ERROR_OK) return retval; buffer += head_bytes; addr += head_bytes; count -= head_bytes; bytes_remaining -= head_bytes; } if (bytes_remaining & (size - 1)) retval = stlink_usb_read_ap_mem(handle, ap_num, csw, addr, 1, bytes_remaining, buffer); else if (size == 2) retval = stlink_usb_read_mem16(handle, ap_num, csw, addr, bytes_remaining, buffer); else retval = stlink_usb_read_mem32(handle, ap_num, csw, addr, bytes_remaining, buffer); } else { retval = stlink_usb_read_mem8(handle, ap_num, csw, addr, bytes_remaining, buffer); } if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) { usleep((1 << retries++) * 1000); continue; } if (retval != ERROR_OK) return retval; buffer += bytes_remaining; addr += bytes_remaining; count -= bytes_remaining; } return retval; } static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer) { return stlink_usb_read_ap_mem(handle, STLINK_HLA_AP_NUM, STLINK_HLA_CSW, addr, size, count, buffer); } static int stlink_usb_write_ap_mem(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval = ERROR_OK; uint32_t bytes_remaining; int retries = 0; struct stlink_usb_handle_s *h = handle; /* calculate byte count */ count *= size; /* switch to 8 bit if stlink does not support 16 bit memory read */ if (size == 2 && !(h->version.flags & STLINK_F_HAS_MEM_16BIT)) size = 1; while (count) { bytes_remaining = (size != 1) ? stlink_max_block_size(h->max_mem_packet, addr) : stlink_usb_block(h); if (count < bytes_remaining) bytes_remaining = count; /* * all stlink support 8/32bit memory read/writes and only from * stlink V2J26 there is support for 16 bit memory read/write. * Honour 32 bit and, if possible, 16 bit too. Otherwise, handle * as 8bit access. */ if (size != 1) { /* When in jtag mode the stlink uses the auto-increment functionality. * However it expects us to pass the data correctly, this includes * alignment and any page boundaries. We already do this as part of the * adi_v5 implementation, but the stlink is a hla adapter and so this * needs implementing manually. * currently this only affects jtag mode, according to ST they do single * access in SWD mode - but this may change and so we do it for both modes */ /* we first need to check for any unaligned bytes */ if (addr & (size - 1)) { uint32_t head_bytes = size - (addr & (size - 1)); retval = stlink_usb_write_mem8(handle, ap_num, csw, addr, head_bytes, buffer); if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) { usleep((1<<retries++) * 1000); continue; } if (retval != ERROR_OK) return retval; buffer += head_bytes; addr += head_bytes; count -= head_bytes; bytes_remaining -= head_bytes; } if (bytes_remaining & (size - 1)) retval = stlink_usb_write_ap_mem(handle, ap_num, csw, addr, 1, bytes_remaining, buffer); else if (size == 2) retval = stlink_usb_write_mem16(handle, ap_num, csw, addr, bytes_remaining, buffer); else retval = stlink_usb_write_mem32(handle, ap_num, csw, addr, bytes_remaining, buffer); } else retval = stlink_usb_write_mem8(handle, ap_num, csw, addr, bytes_remaining, buffer); if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) { usleep((1<<retries++) * 1000); continue; } if (retval != ERROR_OK) return retval; buffer += bytes_remaining; addr += bytes_remaining; count -= bytes_remaining; } return retval; } static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer) { return stlink_usb_write_ap_mem(handle, STLINK_HLA_AP_NUM, STLINK_HLA_CSW, addr, size, count, buffer); } /** */ static int stlink_usb_override_target(const char *targetname) { return !strcmp(targetname, "cortex_m"); } static int stlink_speed_swim(void *handle, int khz, bool query) { int retval; /* we only have low and high speed... before changing speed the SWIM_CSR HS bit must be updated */ if (!query) { retval = stlink_swim_speed(handle, (khz < SWIM_FREQ_HIGH) ? 0 : 1); if (retval != ERROR_OK) LOG_ERROR("Unable to set adapter speed"); } return (khz < SWIM_FREQ_HIGH) ? SWIM_FREQ_LOW : SWIM_FREQ_HIGH; } static int stlink_match_speed_map(const struct speed_map *map, unsigned int map_size, int khz, bool query) { unsigned int i; int speed_index = -1; int speed_diff = INT_MAX; int last_valid_speed = -1; bool match = true; for (i = 0; i < map_size; i++) { if (!map[i].speed) continue; last_valid_speed = i; if (khz == map[i].speed) { speed_index = i; break; } else { int current_diff = khz - map[i].speed; /* get abs value for comparison */ current_diff = (current_diff > 0) ? current_diff : -current_diff; if ((current_diff < speed_diff) && khz >= map[i].speed) { speed_diff = current_diff; speed_index = i; } } } if (speed_index == -1) { /* this will only be here if we cannot match the slow speed. * use the slowest speed we support.*/ speed_index = last_valid_speed; match = false; } else if (i == map_size) match = false; if (!match && query) { LOG_INFO("Unable to match requested speed %d kHz, using %d kHz", khz, map[speed_index].speed); } return speed_index; } static int stlink_speed_swd(void *handle, int khz, bool query) { int speed_index; struct stlink_usb_handle_s *h = handle; /* old firmware cannot change it */ if (!(h->version.flags & STLINK_F_HAS_SWD_SET_FREQ)) return khz; speed_index = stlink_match_speed_map(stlink_khz_to_speed_map_swd, ARRAY_SIZE(stlink_khz_to_speed_map_swd), khz, query); if (!query) { int result = stlink_usb_set_swdclk(h, stlink_khz_to_speed_map_swd[speed_index].speed_divisor); if (result != ERROR_OK) { LOG_ERROR("Unable to set adapter speed"); return khz; } } return stlink_khz_to_speed_map_swd[speed_index].speed; } static int stlink_speed_jtag(void *handle, int khz, bool query) { int speed_index; struct stlink_usb_handle_s *h = handle; /* old firmware cannot change it */ if (!(h->version.flags & STLINK_F_HAS_JTAG_SET_FREQ)) return khz; speed_index = stlink_match_speed_map(stlink_khz_to_speed_map_jtag, ARRAY_SIZE(stlink_khz_to_speed_map_jtag), khz, query); if (!query) { int result = stlink_usb_set_jtagclk(h, stlink_khz_to_speed_map_jtag[speed_index].speed_divisor); if (result != ERROR_OK) { LOG_ERROR("Unable to set adapter speed"); return khz; } } return stlink_khz_to_speed_map_jtag[speed_index].speed; } static void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size) { unsigned int i; LOG_DEBUG("Supported clock speeds are:"); for (i = 0; i < map_size; i++) if (map[i].speed) LOG_DEBUG("%d kHz", map[i].speed); } static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map *map) { struct stlink_usb_handle_s *h = handle; int i; if (h->version.jtag_api != STLINK_JTAG_API_V3) { LOG_ERROR("Unknown command"); return 0; } stlink_usb_init_buffer(handle, h->rx_ep, 16); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_APIV3_GET_COM_FREQ; h->cmdbuf[h->cmdidx++] = is_jtag ? 1 : 0; int res = stlink_usb_xfer_errcheck(handle, h->databuf, 52); int size = h->databuf[8]; if (size > STLINK_V3_MAX_FREQ_NB) size = STLINK_V3_MAX_FREQ_NB; for (i = 0; i < size; i++) { map[i].speed = le_to_h_u32(&h->databuf[12 + 4 * i]); map[i].speed_divisor = i; } /* set to zero all the next entries */ for (i = size; i < STLINK_V3_MAX_FREQ_NB; i++) map[i].speed = 0; return res; } static int stlink_set_com_freq(void *handle, bool is_jtag, unsigned int frequency) { struct stlink_usb_handle_s *h = handle; if (h->version.jtag_api != STLINK_JTAG_API_V3) { LOG_ERROR("Unknown command"); return 0; } stlink_usb_init_buffer(handle, h->rx_ep, 16); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_APIV3_SET_COM_FREQ; h->cmdbuf[h->cmdidx++] = is_jtag ? 1 : 0; h->cmdbuf[h->cmdidx++] = 0; h_u32_to_le(&h->cmdbuf[4], frequency); return stlink_usb_xfer_errcheck(handle, h->databuf, 8); } static int stlink_speed_v3(void *handle, bool is_jtag, int khz, bool query) { struct stlink_usb_handle_s *h = handle; int speed_index; struct speed_map map[STLINK_V3_MAX_FREQ_NB]; stlink_get_com_freq(h, is_jtag, map); speed_index = stlink_match_speed_map(map, ARRAY_SIZE(map), khz, query); if (!query) { int result = stlink_set_com_freq(h, is_jtag, map[speed_index].speed); if (result != ERROR_OK) { LOG_ERROR("Unable to set adapter speed"); return khz; } } return map[speed_index].speed; } static int stlink_speed(void *handle, int khz, bool query) { struct stlink_usb_handle_s *h = handle; if (!handle) return khz; switch (h->st_mode) { case STLINK_MODE_DEBUG_SWIM: return stlink_speed_swim(handle, khz, query); case STLINK_MODE_DEBUG_SWD: if (h->version.jtag_api == STLINK_JTAG_API_V3) return stlink_speed_v3(handle, false, khz, query); else return stlink_speed_swd(handle, khz, query); break; case STLINK_MODE_DEBUG_JTAG: if (h->version.jtag_api == STLINK_JTAG_API_V3) return stlink_speed_v3(handle, true, khz, query); else return stlink_speed_jtag(handle, khz, query); break; default: break; } return khz; } /** */ static int stlink_usb_usb_close(void *handle) { struct stlink_usb_handle_s *h = handle; if (!h) return ERROR_OK; if (h->usb_backend_priv.fd) { stlink_usb_exit_mode(h); /* do not check return code, it prevent us from closing jtag_libusb */ jtag_libusb_close(h->usb_backend_priv.fd); } free(h->cmdbuf); free(h->databuf); return ERROR_OK; } /** */ static int stlink_tcp_close(void *handle) { struct stlink_usb_handle_s *h = handle; if (!h) return ERROR_OK; int ret = ERROR_OK; if (h->tcp_backend_priv.connected) { if (h->tcp_backend_priv.connect_id) { stlink_usb_exit_mode(h); /* close the stlink */ h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_CLOSE_DEV; memset(&h->tcp_backend_priv.send_buf[1], 0, 4); /* reserved */ h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.connect_id); ret = stlink_tcp_send_cmd(h, 8, 4, true); if (ret != ERROR_OK) LOG_ERROR("cannot close the STLINK"); } if (close_socket(h->tcp_backend_priv.fd) != 0) LOG_ERROR("error closing the socket, errno: %s", strerror(errno)); } free(h->tcp_backend_priv.send_buf); free(h->tcp_backend_priv.recv_buf); return ret; } /** */ static int stlink_close(void *handle) { if (handle) { struct stlink_usb_handle_s *h = handle; stlink_usb_close(handle); free(h); } return ERROR_OK; } /* Compute ST-Link serial number from the device descriptor * this function will help to work-around a bug in old ST-Link/V2 DFU * the buggy DFU returns an incorrect serial in the USB descriptor * example for the following serial "57FF72067265575742132067" * - the correct descriptor serial is: * 0x32, 0x03, 0x35, 0x00, 0x37, 0x00, 0x46, 0x00, 0x46, 0x00, 0x37, 0x00, 0x32, 0x00 ... * this contains the length (0x32 = 50), the type (0x3 = DT_STRING) and the serial in unicode format * the serial part is: 0x0035, 0x0037, 0x0046, 0x0046, 0x0037, 0x0032 ... >> 57FF72 ... * this format could be read correctly by 'libusb_get_string_descriptor_ascii' * so this case is managed by libusb_helper::string_descriptor_equal * - the buggy DFU is not doing any unicode conversion and returns a raw serial data in the descriptor * 0x1a, 0x03, 0x57, 0x00, 0xFF, 0x00, 0x72, 0x00 ... * >> 57 FF 72 ... * based on the length (0x1a = 26) we could easily decide if we have to fixup the serial * and then we have just to convert the raw data into printable characters using sprintf */ static char *stlink_usb_get_alternate_serial(struct libusb_device_handle *device, struct libusb_device_descriptor *dev_desc) { int usb_retval; unsigned char desc_serial[(STLINK_SERIAL_LEN + 1) * 2]; if (dev_desc->iSerialNumber == 0) return NULL; /* get the LANGID from String Descriptor Zero */ usb_retval = libusb_get_string_descriptor(device, 0, 0, desc_serial, sizeof(desc_serial)); if (usb_retval < LIBUSB_SUCCESS) { LOG_ERROR("libusb_get_string_descriptor() failed: %s(%d)", libusb_error_name(usb_retval), usb_retval); return NULL; } else if (usb_retval < 4) { /* the size should be least 4 bytes to contain a minimum of 1 supported LANGID */ LOG_ERROR("could not get the LANGID"); return NULL; } uint32_t langid = desc_serial[2] | (desc_serial[3] << 8); /* get the serial */ usb_retval = libusb_get_string_descriptor(device, dev_desc->iSerialNumber, langid, desc_serial, sizeof(desc_serial)); unsigned char len = desc_serial[0]; if (usb_retval < LIBUSB_SUCCESS) { LOG_ERROR("libusb_get_string_descriptor() failed: %s(%d)", libusb_error_name(usb_retval), usb_retval); return NULL; } else if (desc_serial[1] != LIBUSB_DT_STRING || len > usb_retval) { LOG_ERROR("invalid string in ST-LINK USB serial descriptor"); return NULL; } if (len == ((STLINK_SERIAL_LEN + 1) * 2)) { /* good ST-Link adapter, this case is managed by * libusb::libusb_get_string_descriptor_ascii */ return NULL; } else if (len != ((STLINK_SERIAL_LEN / 2 + 1) * 2)) { LOG_ERROR("unexpected serial length (%d) in descriptor", len); return NULL; } /* else (len == 26) => buggy ST-Link */ char *alternate_serial = malloc((STLINK_SERIAL_LEN + 1) * sizeof(char)); if (!alternate_serial) return NULL; for (unsigned int i = 0; i < STLINK_SERIAL_LEN; i += 2) sprintf(alternate_serial + i, "%02X", desc_serial[i + 2]); alternate_serial[STLINK_SERIAL_LEN] = '\0'; return alternate_serial; } /** */ static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param) { struct stlink_usb_handle_s *h = handle; int err, retry_count = 1; h->cmdbuf = malloc(STLINK_SG_SIZE); h->databuf = malloc(STLINK_DATA_SIZE); if (!h->cmdbuf || !h->databuf) return ERROR_FAIL; /* On certain host USB configurations(e.g. MacBook Air) STLINKv2 dongle seems to have its FW in a funky state if, after plugging it in, you try to use openocd with it more then once (by launching and closing openocd). In cases like that initial attempt to read the FW info via stlink_usb_version will fail and the device has to be reset in order to become operational. */ do { if (jtag_libusb_open(param->vid, param->pid, &h->usb_backend_priv.fd, stlink_usb_get_alternate_serial) != ERROR_OK) { LOG_ERROR("open failed"); return ERROR_FAIL; } jtag_libusb_set_configuration(h->usb_backend_priv.fd, 0); if (libusb_claim_interface(h->usb_backend_priv.fd, 0) != ERROR_OK) { LOG_DEBUG("claim interface failed"); return ERROR_FAIL; } /* RX EP is common for all versions */ h->rx_ep = STLINK_RX_EP; uint16_t pid; if (jtag_libusb_get_pid(libusb_get_device(h->usb_backend_priv.fd), &pid) != ERROR_OK) { LOG_DEBUG("libusb_get_pid failed"); return ERROR_FAIL; } /* wrap version for first read */ switch (pid) { case STLINK_V1_PID: h->version.stlink = 1; h->tx_ep = STLINK_TX_EP; break; case STLINK_V3_USBLOADER_PID: case STLINK_V3E_PID: case STLINK_V3S_PID: case STLINK_V3_2VCP_PID: case STLINK_V3E_NO_MSD_PID: case STLINK_V3P_USBLOADER_PID: case STLINK_V3P_PID: h->version.stlink = 3; h->tx_ep = STLINK_V2_1_TX_EP; h->trace_ep = STLINK_V2_1_TRACE_EP; break; case STLINK_V2_1_PID: case STLINK_V2_1_NO_MSD_PID: h->version.stlink = 2; h->tx_ep = STLINK_V2_1_TX_EP; h->trace_ep = STLINK_V2_1_TRACE_EP; break; default: /* fall through - we assume V2 to be the default version*/ case STLINK_V2_PID: h->version.stlink = 2; h->tx_ep = STLINK_TX_EP; h->trace_ep = STLINK_TRACE_EP; break; } /* get the device version */ err = stlink_usb_version(h); if (err == ERROR_OK) { break; } else if (h->version.stlink == 1 || retry_count == 0) { LOG_ERROR("read version failed"); return ERROR_FAIL; } else { err = libusb_release_interface(h->usb_backend_priv.fd, 0); if (err != ERROR_OK) { LOG_ERROR("release interface failed"); return ERROR_FAIL; } err = libusb_reset_device(h->usb_backend_priv.fd); if (err != ERROR_OK) { LOG_ERROR("reset device failed"); return ERROR_FAIL; } jtag_libusb_close(h->usb_backend_priv.fd); /* Give the device one second to settle down and reenumerate. */ usleep(1 * 1000 * 1000); retry_count--; } } while (1); return ERROR_OK; } /** */ static int stlink_tcp_open(void *handle, struct hl_interface_param_s *param) { struct stlink_usb_handle_s *h = handle; int ret; /* SWIM is not supported using stlink-server */ if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { LOG_ERROR("stlink-server does not support SWIM mode"); return ERROR_FAIL; } h->tcp_backend_priv.send_buf = malloc(STLINK_TCP_SEND_BUFFER_SIZE); h->tcp_backend_priv.recv_buf = malloc(STLINK_TCP_RECV_BUFFER_SIZE); if (!h->tcp_backend_priv.send_buf || !h->tcp_backend_priv.recv_buf) return ERROR_FAIL; h->cmdbuf = &h->tcp_backend_priv.send_buf[8]; h->databuf = &h->tcp_backend_priv.recv_buf[4]; /* configure directions */ h->rx_ep = STLINK_TCP_REQUEST_READ; h->tx_ep = STLINK_TCP_REQUEST_WRITE; h->trace_ep = STLINK_TCP_REQUEST_READ_SWO; h->tcp_backend_priv.fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); h->tcp_backend_priv.connected = false; h->tcp_backend_priv.device_id = 0; h->tcp_backend_priv.connect_id = 0; if (h->tcp_backend_priv.fd == -1) { LOG_ERROR("error creating the socket, errno: %s", strerror(errno)); return ERROR_FAIL; } struct sockaddr_in serv; memset(&serv, 0, sizeof(struct sockaddr_in)); serv.sin_family = AF_INET; serv.sin_port = htons(param->stlink_tcp_port); serv.sin_addr.s_addr = inet_addr("127.0.0.1"); LOG_DEBUG("socket : %x", h->tcp_backend_priv.fd); int optval = 1; if (setsockopt(h->tcp_backend_priv.fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&optval, sizeof(int)) == -1) { LOG_ERROR("cannot set sock option 'TCP_NODELAY', errno: %s", strerror(errno)); return ERROR_FAIL; } optval = STLINK_TCP_RECV_BUFFER_SIZE; if (setsockopt(h->tcp_backend_priv.fd, SOL_SOCKET, SO_RCVBUF, (const void *)&optval, sizeof(int)) == -1) { LOG_ERROR("cannot set sock option 'SO_RCVBUF', errno: %s", strerror(errno)); return ERROR_FAIL; } optval = STLINK_TCP_SEND_BUFFER_SIZE; if (setsockopt(h->tcp_backend_priv.fd, SOL_SOCKET, SO_SNDBUF, (const void *)&optval, sizeof(int)) == -1) { LOG_ERROR("cannot set sock option 'SO_SNDBUF', errno: %s", strerror(errno)); return ERROR_FAIL; } if (connect(h->tcp_backend_priv.fd, (const struct sockaddr *)&serv, sizeof(serv)) == -1) { LOG_ERROR("cannot connect to stlink server, errno: %s", strerror(errno)); return ERROR_FAIL; } h->tcp_backend_priv.connected = true; LOG_INFO("connected to stlink-server"); /* print stlink-server version */ h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_SERVER_VERSION; h->tcp_backend_priv.send_buf[1] = OPENOCD_STLINK_TCP_API_VERSION; memset(&h->tcp_backend_priv.send_buf[2], 0, 2); /* reserved */ ret = stlink_tcp_send_cmd(h, 4, 16, false); if (ret != ERROR_OK) { LOG_ERROR("cannot get the stlink-server version"); return ERROR_FAIL; } h->tcp_backend_priv.version.api = le_to_h_u32(&h->tcp_backend_priv.recv_buf[0]); h->tcp_backend_priv.version.major = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]); h->tcp_backend_priv.version.minor = le_to_h_u32(&h->tcp_backend_priv.recv_buf[8]); h->tcp_backend_priv.version.build = le_to_h_u32(&h->tcp_backend_priv.recv_buf[12]); LOG_INFO("stlink-server API v%d, version %d.%d.%d", h->tcp_backend_priv.version.api, h->tcp_backend_priv.version.major, h->tcp_backend_priv.version.minor, h->tcp_backend_priv.version.build); /* in stlink-server API v1 sending more than 1428 bytes will cause stlink-server * to crash in windows: select a safe default value (1K) */ if (h->tcp_backend_priv.version.api < 2) h->max_mem_packet = (1 << 10); /* refresh stlink list (re-enumerate) */ h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_REFRESH_DEVICE_LIST; h->tcp_backend_priv.send_buf[1] = 0; /* don't clear the list, just refresh it */ ret = stlink_tcp_send_cmd(h, 2, 4, true); if (ret != ERROR_OK) return ret; /* get the number of connected stlinks */ h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_NB_DEV; ret = stlink_tcp_send_cmd(h, 1, 4, false); if (ret != ERROR_OK) return ret; uint32_t connected_stlinks = le_to_h_u32(h->tcp_backend_priv.recv_buf); if (connected_stlinks == 0) { LOG_ERROR("no ST-LINK detected"); return ERROR_FAIL; } LOG_DEBUG("%d ST-LINK detected", connected_stlinks); if (connected_stlinks > 255) { LOG_WARNING("STLink server cannot handle more than 255 ST-LINK connected"); connected_stlinks = 255; } /* list all connected ST-Link and seek for the requested vid:pid and serial */ char serial[STLINK_TCP_SERIAL_SIZE + 1] = {0}; uint8_t stlink_used; bool stlink_id_matched = false; const char *adapter_serial = adapter_get_required_serial(); bool stlink_serial_matched = !adapter_serial; for (uint32_t stlink_id = 0; stlink_id < connected_stlinks; stlink_id++) { /* get the stlink info */ h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_DEV_INFO; h->tcp_backend_priv.send_buf[1] = (uint8_t)stlink_id; memset(&h->tcp_backend_priv.send_buf[2], 0, 2); /* reserved */ h_u32_to_le(&h->tcp_backend_priv.send_buf[4], 41); /* size of TDeviceInfo2 */ ret = stlink_tcp_send_cmd(h, 8, 45, true); if (ret != ERROR_OK) return ret; h->tcp_backend_priv.device_id = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]); memcpy(serial, &h->tcp_backend_priv.recv_buf[8], STLINK_TCP_SERIAL_SIZE); h->vid = le_to_h_u16(&h->tcp_backend_priv.recv_buf[40]); h->pid = le_to_h_u16(&h->tcp_backend_priv.recv_buf[42]); stlink_used = h->tcp_backend_priv.recv_buf[44]; /* check the vid:pid */ for (int i = 0; param->vid[i]; i++) { if (param->vid[i] == h->vid && param->pid[i] == h->pid) { stlink_id_matched = true; break; } } if (!stlink_id_matched) continue; /* check the serial if specified */ if (adapter_serial) { /* ST-Link server fixes the buggy serial returned by old ST-Link DFU * for further details refer to stlink_usb_get_alternate_serial * so if the user passes the buggy serial, we need to fix it before * comparing with the serial returned by ST-Link server */ if (strlen(adapter_serial) == STLINK_SERIAL_LEN / 2) { char fixed_serial[STLINK_SERIAL_LEN + 1]; for (unsigned int i = 0; i < STLINK_SERIAL_LEN; i += 2) sprintf(fixed_serial + i, "%02X", adapter_serial[i / 2]); fixed_serial[STLINK_SERIAL_LEN] = '\0'; stlink_serial_matched = strcmp(fixed_serial, serial) == 0; } else { stlink_serial_matched = strcmp(adapter_serial, serial) == 0; } } if (!stlink_serial_matched) LOG_DEBUG("Device serial number '%s' doesn't match requested serial '%s'", serial, adapter_serial); else /* exit the search loop if there is match */ break; } if (!stlink_id_matched) { LOG_ERROR("ST-LINK open failed (vid/pid mismatch)"); return ERROR_FAIL; } if (!stlink_serial_matched) { LOG_ERROR("ST-LINK open failed (serial mismatch)"); return ERROR_FAIL; } /* check if device is 'exclusively' used by another application */ if (stlink_used) { LOG_ERROR("the selected device is already used"); return ERROR_FAIL; } LOG_DEBUG("transport: vid: 0x%04x pid: 0x%04x serial: %s", h->vid, h->pid, serial); /* now let's open the stlink */ h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_OPEN_DEV; memset(&h->tcp_backend_priv.send_buf[1], 0, 4); /* reserved */ h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.device_id); ret = stlink_tcp_send_cmd(h, 8, 8, true); if (ret != ERROR_OK) return ret; h->tcp_backend_priv.connect_id = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]); /* get stlink version */ return stlink_usb_version(h); } static struct stlink_backend_s stlink_usb_backend = { .open = stlink_usb_usb_open, .close = stlink_usb_usb_close, .xfer_noerrcheck = stlink_usb_usb_xfer_noerrcheck, .read_trace = stlink_usb_usb_read_trace, }; static struct stlink_backend_s stlink_tcp_backend = { .open = stlink_tcp_open, .close = stlink_tcp_close, .xfer_noerrcheck = stlink_tcp_xfer_noerrcheck, .read_trace = stlink_tcp_read_trace, }; static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd) { struct stlink_usb_handle_s *h; LOG_DEBUG("stlink_open"); h = calloc(1, sizeof(struct stlink_usb_handle_s)); if (!h) { LOG_DEBUG("malloc failed"); return ERROR_FAIL; } h->st_mode = mode; for (unsigned i = 0; param->vid[i]; i++) { LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", h->st_mode, param->vid[i], param->pid[i], adapter_get_required_serial() ? adapter_get_required_serial() : ""); } if (param->use_stlink_tcp) h->backend = &stlink_tcp_backend; else h->backend = &stlink_usb_backend; if (stlink_usb_open(h, param) != ERROR_OK) goto error_open; /* check if mode is supported */ int err = ERROR_OK; switch (h->st_mode) { case STLINK_MODE_DEBUG_SWD: if (h->version.jtag_api == STLINK_JTAG_API_V1) err = ERROR_FAIL; /* fall-through */ case STLINK_MODE_DEBUG_JTAG: if (h->version.jtag == 0) err = ERROR_FAIL; break; case STLINK_MODE_DEBUG_SWIM: if (h->version.swim == 0) err = ERROR_FAIL; break; default: err = ERROR_FAIL; break; } if (err != ERROR_OK) { LOG_ERROR("mode (transport) not supported by device"); goto error_open; } /* initialize the debug hardware */ err = stlink_usb_init_mode(h, param->connect_under_reset, param->initial_interface_speed); if (err != ERROR_OK) { LOG_ERROR("init mode failed (unable to connect to the target)"); goto error_open; } if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { err = stlink_swim_enter(h); if (err != ERROR_OK) { LOG_ERROR("stlink_swim_enter_failed (unable to connect to the target)"); goto error_open; } *fd = h; h->max_mem_packet = STLINK_SWIM_DATA_SIZE; return ERROR_OK; } /* set max_mem_packet if it was not set by the low-level interface */ if (h->max_mem_packet == 0) { /* get cpuid, so we can determine the max page size * start with a safe default */ h->max_mem_packet = (1 << 10); uint8_t buffer[4]; stlink_usb_open_ap(h, STLINK_HLA_AP_NUM); err = stlink_usb_read_mem32(h, STLINK_HLA_AP_NUM, STLINK_HLA_CSW, CPUID, 4, buffer); if (err == ERROR_OK) { uint32_t cpuid = le_to_h_u32(buffer); int i = (cpuid >> 4) & 0xf; if (i == 4 || i == 3) { /* Cortex-M3/M4 has 4096 bytes autoincrement range */ h->max_mem_packet = (1 << 12); } } LOG_DEBUG("Using TAR autoincrement: %" PRIu32, h->max_mem_packet); } *fd = h; return ERROR_OK; error_open: stlink_close(h); return ERROR_FAIL; } static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd) { return stlink_open(param, stlink_get_mode(param->transport), fd); } static int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler) { struct stlink_usb_handle_s *h = handle; if (!(h->version.flags & STLINK_F_HAS_TRACE)) { LOG_ERROR("The attached ST-LINK version doesn't support trace"); return ERROR_FAIL; } if (!enabled) { stlink_usb_trace_disable(h); return ERROR_OK; } assert(trace_freq); assert(prescaler); if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) { LOG_ERROR("The attached ST-LINK version doesn't support this trace mode"); return ERROR_FAIL; } unsigned int max_trace_freq = (h->version.stlink >= 3) ? STLINK_V3_TRACE_MAX_HZ : STLINK_TRACE_MAX_HZ; /* Only concern ourselves with the frequency if the STlink is processing it. */ if (*trace_freq > max_trace_freq) { LOG_ERROR("ST-LINK doesn't support SWO frequency higher than %u", max_trace_freq); return ERROR_FAIL; } if (!*trace_freq) *trace_freq = max_trace_freq; unsigned int presc = (traceclkin_freq + *trace_freq / 2) / *trace_freq; if (presc == 0 || presc > TPIU_ACPR_MAX_SWOSCALER + 1) { LOG_ERROR("SWO frequency is not suitable. Please choose a different " "frequency."); return ERROR_FAIL; } /* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */ unsigned int max_deviation = (traceclkin_freq * 3) / 100; if (presc * *trace_freq < traceclkin_freq - max_deviation || presc * *trace_freq > traceclkin_freq + max_deviation) { LOG_ERROR("SWO frequency is not suitable. Please choose a different " "frequency."); return ERROR_FAIL; } *prescaler = presc; stlink_usb_trace_disable(h); h->trace.source_hz = *trace_freq; return stlink_usb_trace_enable(h); } /** */ static int stlink_usb_init_access_port(void *handle, unsigned char ap_num) { struct stlink_usb_handle_s *h = handle; assert(handle); if (!(h->version.flags & STLINK_F_HAS_AP_INIT)) return ERROR_COMMAND_NOTFOUND; LOG_DEBUG_IO("init ap_num = %d", ap_num); stlink_usb_init_buffer(handle, h->rx_ep, 16); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_INIT_AP; h->cmdbuf[h->cmdidx++] = ap_num; return stlink_usb_xfer_errcheck(handle, h->databuf, 2); } /** */ static int stlink_usb_close_access_port(void *handle, unsigned char ap_num) { struct stlink_usb_handle_s *h = handle; assert(handle); if (!(h->version.flags & STLINK_F_HAS_AP_INIT)) return ERROR_COMMAND_NOTFOUND; LOG_DEBUG_IO("close ap_num = %d", ap_num); stlink_usb_init_buffer(handle, h->rx_ep, 16); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_CLOSE_AP_DBG; h->cmdbuf[h->cmdidx++] = ap_num; /* ignore incorrectly returned error on bogus FW */ if (h->version.flags & STLINK_F_FIX_CLOSE_AP) return stlink_usb_xfer_errcheck(handle, h->databuf, 2); else return stlink_usb_xfer_noerrcheck(handle, h->databuf, 2); } static int stlink_usb_rw_misc_out(void *handle, uint32_t items, const uint8_t *buffer) { struct stlink_usb_handle_s *h = handle; unsigned int buflen = ALIGN_UP(items, 4) + 4 * items; LOG_DEBUG_IO("%s(%" PRIu32 ")", __func__, items); assert(handle != NULL); if (!(h->version.flags & STLINK_F_HAS_RW_MISC)) return ERROR_COMMAND_NOTFOUND; stlink_usb_init_buffer(handle, h->tx_ep, buflen); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RW_MISC_OUT; h_u32_to_le(&h->cmdbuf[2], items); return stlink_usb_xfer_noerrcheck(handle, buffer, buflen); } static int stlink_usb_rw_misc_in(void *handle, uint32_t items, uint8_t *buffer) { struct stlink_usb_handle_s *h = handle; unsigned int buflen = 2 * 4 * items; LOG_DEBUG_IO("%s(%" PRIu32 ")", __func__, items); assert(handle != NULL); if (!(h->version.flags & STLINK_F_HAS_RW_MISC)) return ERROR_COMMAND_NOTFOUND; stlink_usb_init_buffer(handle, h->rx_ep, buflen); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RW_MISC_IN; int res = stlink_usb_xfer_noerrcheck(handle, h->databuf, buflen); if (res != ERROR_OK) return res; memcpy(buffer, h->databuf, buflen); return ERROR_OK; } /** */ static int stlink_read_dap_register(void *handle, unsigned short dap_port, unsigned short addr, uint32_t *val) { struct stlink_usb_handle_s *h = handle; int retval; assert(handle); if (!(h->version.flags & STLINK_F_HAS_DAP_REG)) return ERROR_COMMAND_NOTFOUND; stlink_usb_init_buffer(handle, h->rx_ep, 16); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READ_DAP_REG; h_u16_to_le(&h->cmdbuf[2], dap_port); h_u16_to_le(&h->cmdbuf[4], addr); retval = stlink_usb_xfer_errcheck(handle, h->databuf, 8); *val = le_to_h_u32(h->databuf + 4); LOG_DEBUG_IO("dap_port_read = %d, addr = 0x%x, value = 0x%" PRIx32, dap_port, addr, *val); return retval; } /** */ static int stlink_write_dap_register(void *handle, unsigned short dap_port, unsigned short addr, uint32_t val) { struct stlink_usb_handle_s *h = handle; assert(handle); if (!(h->version.flags & STLINK_F_HAS_DAP_REG)) return ERROR_COMMAND_NOTFOUND; LOG_DEBUG_IO("dap_write port = %d, addr = 0x%x, value = 0x%" PRIx32, dap_port, addr, val); stlink_usb_init_buffer(handle, h->rx_ep, 16); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITE_DAP_REG; h_u16_to_le(&h->cmdbuf[2], dap_port); h_u16_to_le(&h->cmdbuf[4], addr); h_u32_to_le(&h->cmdbuf[6], val); return stlink_usb_xfer_errcheck(handle, h->databuf, 2); } /** */ struct hl_layout_api_s stlink_usb_layout_api = { /** */ .open = stlink_usb_hl_open, /** */ .close = stlink_close, /** */ .idcode = stlink_usb_idcode, /** */ .state = stlink_usb_state, /** */ .reset = stlink_usb_reset, /** */ .assert_srst = stlink_usb_assert_srst, /** */ .run = stlink_usb_run, /** */ .halt = stlink_usb_halt, /** */ .step = stlink_usb_step, /** */ .read_regs = stlink_usb_read_regs, /** */ .read_reg = stlink_usb_read_reg, /** */ .write_reg = stlink_usb_write_reg, /** */ .read_mem = stlink_usb_read_mem, /** */ .write_mem = stlink_usb_write_mem, /** */ .write_debug_reg = stlink_usb_write_debug_reg, /** */ .override_target = stlink_usb_override_target, /** */ .speed = stlink_speed, /** */ .config_trace = stlink_config_trace, /** */ .poll_trace = stlink_usb_trace_read, }; /***************************************************************************** * DAP direct interface */ static struct stlink_usb_handle_s *stlink_dap_handle; static struct hl_interface_param_s stlink_dap_param; static DECLARE_BITMAP(opened_ap, DP_APSEL_MAX + 1); static uint32_t last_csw_default[DP_APSEL_MAX + 1]; static int stlink_dap_error = ERROR_OK; /** */ static int stlink_dap_record_error(int error) { if (stlink_dap_error == ERROR_OK) stlink_dap_error = error; return ERROR_OK; } /** */ static int stlink_dap_get_and_clear_error(void) { int retval = stlink_dap_error; stlink_dap_error = ERROR_OK; return retval; } static int stlink_dap_get_error(void) { return stlink_dap_error; } static int stlink_usb_open_ap(void *handle, unsigned short apsel) { struct stlink_usb_handle_s *h = handle; int retval; /* nothing to do on old versions */ if (!(h->version.flags & STLINK_F_HAS_AP_INIT)) return ERROR_OK; if (apsel > DP_APSEL_MAX) return ERROR_FAIL; if (test_bit(apsel, opened_ap)) return ERROR_OK; retval = stlink_usb_init_access_port(h, apsel); if (retval != ERROR_OK) return retval; LOG_DEBUG("AP %d enabled", apsel); set_bit(apsel, opened_ap); last_csw_default[apsel] = 0; return ERROR_OK; } static int stlink_dap_open_ap(unsigned short apsel) { return stlink_usb_open_ap(stlink_dap_handle, apsel); } /** */ static int stlink_dap_closeall_ap(void) { int retval, apsel; /* nothing to do on old versions */ if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT)) return ERROR_OK; for (apsel = 0; apsel <= DP_APSEL_MAX; apsel++) { if (!test_bit(apsel, opened_ap)) continue; retval = stlink_usb_close_access_port(stlink_dap_handle, apsel); if (retval != ERROR_OK) return retval; clear_bit(apsel, opened_ap); } return ERROR_OK; } /** */ static int stlink_dap_reinit_interface(void) { int retval; /* * On JTAG only, it should be enough to call stlink_usb_reset(). But on * some firmware version it does not work as expected, and there is no * equivalent for SWD. * At least for now, to reset the interface quit from JTAG/SWD mode then * select the mode again. */ if (!stlink_dap_handle->reconnect_pending) { stlink_dap_handle->reconnect_pending = true; stlink_usb_mode_leave(stlink_dap_handle, stlink_dap_handle->st_mode); } retval = stlink_usb_mode_enter(stlink_dap_handle, stlink_dap_handle->st_mode); if (retval != ERROR_OK) return retval; stlink_dap_handle->reconnect_pending = false; /* on new FW, calling mode-leave closes all the opened AP; reopen them! */ if (stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT) for (unsigned int apsel = 0; apsel <= DP_APSEL_MAX; apsel++) if (test_bit(apsel, opened_ap)) { clear_bit(apsel, opened_ap); stlink_dap_open_ap(apsel); } return ERROR_OK; } /** */ static int stlink_dap_op_connect(struct adiv5_dap *dap) { uint32_t idcode; int retval; LOG_INFO("stlink_dap_op_connect(%sconnect)", dap->do_reconnect ? "re" : ""); /* Check if we should reset srst already when connecting, but not if reconnecting. */ if (!dap->do_reconnect) { enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) adapter_assert_reset(); else LOG_WARNING("\'srst_nogate\' reset_config option is required"); } } dap->do_reconnect = false; dap_invalidate_cache(dap); for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) last_csw_default[i] = 0; retval = dap_dp_init(dap); if (retval != ERROR_OK) { dap->do_reconnect = true; return retval; } retval = stlink_usb_idcode(stlink_dap_handle, &idcode); if (retval == ERROR_OK) LOG_INFO("%s %#8.8" PRIx32, (stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) ? "JTAG IDCODE" : "SWD DPIDR", idcode); else dap->do_reconnect = true; return retval; } /** */ static int stlink_dap_check_reconnect(struct adiv5_dap *dap) { int retval; if (!dap->do_reconnect) return ERROR_OK; retval = stlink_dap_reinit_interface(); if (retval != ERROR_OK) return retval; return stlink_dap_op_connect(dap); } /** */ static int stlink_dap_op_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq) { /* Ignore the request */ return ERROR_OK; } /** */ static int stlink_dap_dp_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *data) { uint32_t dummy; int retval; if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DPBANKSEL)) if (reg & 0x000000F0) { LOG_ERROR("Banked DP registers not supported in current STLink FW"); return ERROR_COMMAND_NOTFOUND; } data = data ? data : &dummy; if (stlink_dap_handle->version.flags & STLINK_F_QUIRK_JTAG_DP_READ && stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) { /* Quirk required in JTAG. Read RDBUFF to get the data */ retval = stlink_read_dap_register(stlink_dap_handle, STLINK_DEBUG_PORT_ACCESS, reg, &dummy); if (retval == ERROR_OK) retval = stlink_read_dap_register(stlink_dap_handle, STLINK_DEBUG_PORT_ACCESS, DP_RDBUFF, data); } else { retval = stlink_read_dap_register(stlink_dap_handle, STLINK_DEBUG_PORT_ACCESS, reg, data); } return retval; } /** */ static int stlink_dap_dp_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data) { int retval; if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DPBANKSEL)) if (reg & 0x000000F0) { LOG_ERROR("Banked DP registers not supported in current STLink FW"); return ERROR_COMMAND_NOTFOUND; } if (reg == DP_SELECT && (data & DP_SELECT_DPBANK) != 0) { /* ignored if STLINK_F_HAS_DPBANKSEL, not properly managed otherwise */ LOG_DEBUG("Ignoring DPBANKSEL while write SELECT"); data &= ~DP_SELECT_DPBANK; } /* ST-Link does not like that we set CORUNDETECT */ if (reg == DP_CTRL_STAT) data &= ~CORUNDETECT; retval = stlink_write_dap_register(stlink_dap_handle, STLINK_DEBUG_PORT_ACCESS, reg, data); return retval; } /** */ static int stlink_dap_ap_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data) { struct adiv5_dap *dap = ap->dap; uint32_t dummy; int retval; if (is_adiv6(dap)) { static bool error_flagged; if (!error_flagged) LOG_ERROR("ADIv6 dap not supported by stlink dap-direct mode"); error_flagged = true; return ERROR_FAIL; } if (reg != ADIV5_AP_REG_IDR) { retval = stlink_dap_open_ap(ap->ap_num); if (retval != ERROR_OK) return retval; } data = data ? data : &dummy; retval = stlink_read_dap_register(stlink_dap_handle, ap->ap_num, reg, data); dap->stlink_flush_ap_write = false; return retval; } /** */ static int stlink_dap_ap_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data) { struct adiv5_dap *dap = ap->dap; int retval; if (is_adiv6(dap)) { static bool error_flagged; if (!error_flagged) LOG_ERROR("ADIv6 dap not supported by stlink dap-direct mode"); error_flagged = true; return ERROR_FAIL; } retval = stlink_dap_open_ap(ap->ap_num); if (retval != ERROR_OK) return retval; retval = stlink_write_dap_register(stlink_dap_handle, ap->ap_num, reg, data); dap->stlink_flush_ap_write = true; return retval; } /** */ static int stlink_dap_op_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) { LOG_WARNING("stlink_dap_op_queue_ap_abort()"); return ERROR_OK; } #define RW_MISC_CMD_ADDRESS 1 #define RW_MISC_CMD_WRITE 2 #define RW_MISC_CMD_READ 3 #define RW_MISC_CMD_APNUM 5 static int stlink_usb_misc_rw_segment(void *handle, const struct dap_queue *q, unsigned int len, unsigned int items) { uint8_t buf[2 * 4 * items]; LOG_DEBUG("Queue: %u commands in %u items", len, items); uint32_t ap_num = DP_APSEL_INVALID; unsigned int cmd_index = 0; unsigned int val_index = ALIGN_UP(items, 4); for (unsigned int i = 0; i < len; i++) { if (ap_num != q[i].mem_ap.ap->ap_num) { ap_num = q[i].mem_ap.ap->ap_num; buf[cmd_index++] = RW_MISC_CMD_APNUM; h_u32_to_le(&buf[val_index], ap_num); val_index += 4; } switch (q[i].cmd) { case CMD_MEM_AP_READ32: buf[cmd_index++] = RW_MISC_CMD_READ; h_u32_to_le(&buf[val_index], q[i].mem_ap.addr); val_index += 4; break; case CMD_MEM_AP_WRITE32: buf[cmd_index++] = RW_MISC_CMD_ADDRESS; h_u32_to_le(&buf[val_index], q[i].mem_ap.addr); val_index += 4; buf[cmd_index++] = RW_MISC_CMD_WRITE; h_u32_to_le(&buf[val_index], q[i].mem_ap.data); val_index += 4; break; default: /* Not supposed to happen */ return ERROR_FAIL; } } /* pad after last command */ while (!IS_ALIGNED(cmd_index, 4)) buf[cmd_index++] = 0; int retval = stlink_usb_rw_misc_out(handle, items, buf); if (retval != ERROR_OK) return retval; retval = stlink_usb_rw_misc_in(handle, items, buf); if (retval != ERROR_OK) return retval; ap_num = DP_APSEL_INVALID; val_index = 0; unsigned int err_index = 4 * items; for (unsigned int i = 0; i < len; i++) { uint32_t errcode = le_to_h_u32(&buf[err_index]); if (errcode != STLINK_DEBUG_ERR_OK) { LOG_ERROR("unknown/unexpected STLINK status code 0x%x", errcode); return ERROR_FAIL; } if (ap_num != q[i].mem_ap.ap->ap_num) { ap_num = q[i].mem_ap.ap->ap_num; err_index += 4; val_index += 4; errcode = le_to_h_u32(&buf[err_index]); if (errcode != STLINK_DEBUG_ERR_OK) { LOG_ERROR("unknown/unexpected STLINK status code 0x%x", errcode); return ERROR_FAIL; } } if (q[i].cmd == CMD_MEM_AP_READ32) { *q[i].mem_ap.p_data = le_to_h_u32(&buf[val_index]); } else { /* q[i]->cmd == CMD_MEM_AP_WRITE32 */ err_index += 4; val_index += 4; errcode = le_to_h_u32(&buf[err_index]); if (errcode != STLINK_DEBUG_ERR_OK) { LOG_ERROR("unknown/unexpected STLINK status code 0x%x", errcode); return ERROR_FAIL; } } err_index += 4; val_index += 4; } return ERROR_OK; } static int stlink_usb_buf_rw_segment(void *handle, const struct dap_queue *q, unsigned int count) { uint32_t bufsize = count * CMD_MEM_AP_2_SIZE(q[0].cmd); uint8_t buf[bufsize]; uint8_t ap_num = q[0].mem_ap.ap->ap_num; uint32_t addr = q[0].mem_ap.addr; uint32_t csw = q[0].mem_ap.csw; int retval = stlink_dap_open_ap(ap_num); if (retval != ERROR_OK) return retval; switch (q[0].cmd) { case CMD_MEM_AP_WRITE8: for (unsigned int i = 0; i < count; i++) buf[i] = q[i].mem_ap.data >> 8 * (q[i].mem_ap.addr & 3); return stlink_usb_write_mem8(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); case CMD_MEM_AP_WRITE16: for (unsigned int i = 0; i < count; i++) h_u16_to_le(&buf[2 * i], q[i].mem_ap.data >> 8 * (q[i].mem_ap.addr & 2)); return stlink_usb_write_mem16(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); case CMD_MEM_AP_WRITE32: for (unsigned int i = 0; i < count; i++) h_u32_to_le(&buf[4 * i], q[i].mem_ap.data); if (count > 1 && q[0].mem_ap.addr == q[1].mem_ap.addr) return stlink_usb_write_mem32_noaddrinc(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); else return stlink_usb_write_mem32(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); case CMD_MEM_AP_READ8: retval = stlink_usb_read_mem8(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); if (retval == ERROR_OK) for (unsigned int i = 0; i < count; i++) *q[i].mem_ap.p_data = buf[i] << 8 * (q[i].mem_ap.addr & 3); return retval; case CMD_MEM_AP_READ16: retval = stlink_usb_read_mem16(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); if (retval == ERROR_OK) for (unsigned int i = 0; i < count; i++) *q[i].mem_ap.p_data = le_to_h_u16(&buf[2 * i]) << 8 * (q[i].mem_ap.addr & 2); return retval; case CMD_MEM_AP_READ32: if (count > 1 && q[0].mem_ap.addr == q[1].mem_ap.addr) retval = stlink_usb_read_mem32_noaddrinc(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); else retval = stlink_usb_read_mem32(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); if (retval == ERROR_OK) for (unsigned int i = 0; i < count; i++) *q[i].mem_ap.p_data = le_to_h_u32(&buf[4 * i]); return retval; default: return ERROR_FAIL; }; } /* TODO: recover these values with cmd STLINK_DEBUG_APIV2_RW_MISC_GET_MAX (0x53) */ #define STLINK_V2_RW_MISC_SIZE (64) #define STLINK_V3_RW_MISC_SIZE (1227) static int stlink_usb_count_misc_rw_queue(void *handle, const struct dap_queue *q, unsigned int len, unsigned int *pkt_items) { struct stlink_usb_handle_s *h = handle; unsigned int i, items = 0; uint32_t ap_num = DP_APSEL_INVALID; unsigned int misc_max_items = (h->version.stlink == 2) ? STLINK_V2_RW_MISC_SIZE : STLINK_V3_RW_MISC_SIZE; if (!(h->version.flags & STLINK_F_HAS_RW_MISC)) return 0; /* * Before stlink-server API v3, RW_MISC sequence doesn't lock the st-link, * so are not safe in shared mode. * Don't use it with TCP backend to prevent any issue in case of sharing. * This further degrades the performance, on top of TCP server overhead. */ if (h->backend == &stlink_tcp_backend && h->tcp_backend_priv.version.api < 3) return 0; for (i = 0; i < len; i++) { if (q[i].cmd != CMD_MEM_AP_READ32 && q[i].cmd != CMD_MEM_AP_WRITE32) break; unsigned int count = 1; if (ap_num != q[i].mem_ap.ap->ap_num) { count++; ap_num = q[i].mem_ap.ap->ap_num; } if (q[i].cmd == CMD_MEM_AP_WRITE32) count++; if (items + count > misc_max_items) break; items += count; } *pkt_items = items; return i; } static int stlink_usb_count_buf_rw_queue(const struct dap_queue *q, unsigned int len) { uint32_t incr = CMD_MEM_AP_2_SIZE(q[0].cmd); unsigned int len_max; if (incr == 1) len_max = stlink_usb_block(stlink_dap_handle); else len_max = STLINK_MAX_RW16_32 / incr; /* check for no address increment, 32 bits only */ if (len > 1 && incr == 4 && q[0].mem_ap.addr == q[1].mem_ap.addr) incr = 0; if (len > len_max) len = len_max; for (unsigned int i = 1; i < len; i++) if (q[i].cmd != q[0].cmd || q[i].mem_ap.ap != q[0].mem_ap.ap || q[i].mem_ap.csw != q[0].mem_ap.csw || q[i].mem_ap.addr != q[i - 1].mem_ap.addr + incr) return i; return len; } static int stlink_usb_mem_rw_queue(void *handle, const struct dap_queue *q, unsigned int len, unsigned int *skip) { unsigned int count, misc_items = 0; int retval; unsigned int count_misc = stlink_usb_count_misc_rw_queue(handle, q, len, &misc_items); unsigned int count_buf = stlink_usb_count_buf_rw_queue(q, len); if (count_misc > count_buf) { count = count_misc; retval = stlink_usb_misc_rw_segment(handle, q, count, misc_items); } else { count = count_buf; retval = stlink_usb_buf_rw_segment(handle, q, count_buf); } if (retval != ERROR_OK) return retval; *skip = count; return ERROR_OK; } static void stlink_dap_run_internal(struct adiv5_dap *dap) { int retval = stlink_dap_check_reconnect(dap); if (retval != ERROR_OK) { stlink_dap_handle->queue_index = 0; stlink_dap_record_error(retval); return; } unsigned int i = stlink_dap_handle->queue_index; struct dap_queue *q = &stlink_dap_handle->queue[0]; while (i && stlink_dap_get_error() == ERROR_OK) { unsigned int skip = 1; switch (q->cmd) { case CMD_DP_READ: retval = stlink_dap_dp_read(q->dp_r.dap, q->dp_r.reg, q->dp_r.p_data); break; case CMD_DP_WRITE: retval = stlink_dap_dp_write(q->dp_w.dap, q->dp_w.reg, q->dp_w.data); break; case CMD_AP_READ: retval = stlink_dap_ap_read(q->ap_r.ap, q->ap_r.reg, q->ap_r.p_data); break; case CMD_AP_WRITE: /* ignore increment packed, not supported */ if (q->ap_w.reg == ADIV5_MEM_AP_REG_CSW) q->ap_w.data &= ~CSW_ADDRINC_PACKED; retval = stlink_dap_ap_write(q->ap_w.ap, q->ap_w.reg, q->ap_w.data); break; case CMD_MEM_AP_READ8: case CMD_MEM_AP_READ16: case CMD_MEM_AP_READ32: case CMD_MEM_AP_WRITE8: case CMD_MEM_AP_WRITE16: case CMD_MEM_AP_WRITE32: retval = stlink_usb_mem_rw_queue(stlink_dap_handle, q, i, &skip); break; default: LOG_ERROR("ST-Link: Unknown queue command %d", q->cmd); retval = ERROR_FAIL; break; } stlink_dap_record_error(retval); q += skip; i -= skip; } stlink_dap_handle->queue_index = 0; } /** */ static int stlink_dap_run_finalize(struct adiv5_dap *dap) { uint32_t ctrlstat, pwrmask; int retval, saved_retval; /* Here no LOG_DEBUG. This is called continuously! */ /* * ST-Link returns immediately after a DAP write, without waiting for it * to complete. * Run a dummy read to DP_RDBUFF, as suggested in * http://infocenter.arm.com/help/topic/com.arm.doc.faqs/ka16363.html */ if (dap->stlink_flush_ap_write) { dap->stlink_flush_ap_write = false; retval = stlink_dap_dp_read(dap, DP_RDBUFF, NULL); if (retval != ERROR_OK) { dap->do_reconnect = true; return retval; } } saved_retval = stlink_dap_get_and_clear_error(); retval = stlink_dap_dp_read(dap, DP_CTRL_STAT, &ctrlstat); if (retval != ERROR_OK) { LOG_ERROR("Fail reading CTRL/STAT register. Force reconnect"); dap->do_reconnect = true; return retval; } if (ctrlstat & SSTICKYERR) { if (stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) retval = stlink_dap_dp_write(dap, DP_CTRL_STAT, ctrlstat & (dap->dp_ctrl_stat | SSTICKYERR)); else retval = stlink_dap_dp_write(dap, DP_ABORT, STKERRCLR); if (retval != ERROR_OK) { dap->do_reconnect = true; return retval; } } /* check for power lost */ pwrmask = dap->dp_ctrl_stat & (CDBGPWRUPREQ | CSYSPWRUPREQ); if ((ctrlstat & pwrmask) != pwrmask) dap->do_reconnect = true; return saved_retval; } static int stlink_dap_op_queue_run(struct adiv5_dap *dap) { stlink_dap_run_internal(dap); return stlink_dap_run_finalize(dap); } /** */ static void stlink_dap_op_quit(struct adiv5_dap *dap) { int retval; retval = stlink_dap_closeall_ap(); if (retval != ERROR_OK) LOG_ERROR("Error closing APs"); } static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *data) { if (stlink_dap_get_error() != ERROR_OK) return ERROR_OK; unsigned int i = stlink_dap_handle->queue_index++; struct dap_queue *q = &stlink_dap_handle->queue[i]; q->cmd = CMD_DP_READ; q->dp_r.reg = reg; q->dp_r.dap = dap; q->dp_r.p_data = data; if (i == MAX_QUEUE_DEPTH - 1) stlink_dap_run_internal(dap); return ERROR_OK; } static int stlink_dap_op_queue_dp_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data) { if (stlink_dap_get_error() != ERROR_OK) return ERROR_OK; unsigned int i = stlink_dap_handle->queue_index++; struct dap_queue *q = &stlink_dap_handle->queue[i]; q->cmd = CMD_DP_WRITE; q->dp_w.reg = reg; q->dp_w.dap = dap; q->dp_w.data = data; if (i == MAX_QUEUE_DEPTH - 1) stlink_dap_run_internal(dap); return ERROR_OK; } static int stlink_dap_op_queue_ap_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data) { if (stlink_dap_get_error() != ERROR_OK) return ERROR_OK; unsigned int i = stlink_dap_handle->queue_index++; struct dap_queue *q = &stlink_dap_handle->queue[i]; /* test STLINK_F_HAS_CSW implicitly tests STLINK_F_HAS_MEM_16BIT, STLINK_F_HAS_MEM_RD_NO_INC * and STLINK_F_HAS_RW_MISC */ if ((stlink_dap_handle->version.flags & STLINK_F_HAS_CSW) && (reg == ADIV5_MEM_AP_REG_DRW || reg == ADIV5_MEM_AP_REG_BD0 || reg == ADIV5_MEM_AP_REG_BD1 || reg == ADIV5_MEM_AP_REG_BD2 || reg == ADIV5_MEM_AP_REG_BD3)) { /* de-queue previous write-TAR */ struct dap_queue *prev_q = q - 1; if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == ADIV5_MEM_AP_REG_TAR) { stlink_dap_handle->queue_index = i; i--; q = prev_q; prev_q--; } /* de-queue previous write-CSW if it didn't changed ap->csw_default */ if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == ADIV5_MEM_AP_REG_CSW && !prev_q->ap_w.changes_csw_default) { stlink_dap_handle->queue_index = i; q = prev_q; } switch (ap->csw_value & CSW_SIZE_MASK) { case CSW_8BIT: q->cmd = CMD_MEM_AP_READ8; break; case CSW_16BIT: q->cmd = CMD_MEM_AP_READ16; break; case CSW_32BIT: q->cmd = CMD_MEM_AP_READ32; break; default: LOG_ERROR("ST-Link: Unsupported CSW size %d", ap->csw_value & CSW_SIZE_MASK); stlink_dap_record_error(ERROR_FAIL); return ERROR_FAIL; } q->mem_ap.addr = (reg == ADIV5_MEM_AP_REG_DRW) ? ap->tar_value : ((ap->tar_value & ~0x0f) | (reg & 0x0c)); q->mem_ap.ap = ap; q->mem_ap.p_data = data; q->mem_ap.csw = ap->csw_default; /* force TAR and CSW update */ ap->tar_valid = false; ap->csw_value = 0; } else { q->cmd = CMD_AP_READ; q->ap_r.reg = reg; q->ap_r.ap = ap; q->ap_r.p_data = data; } if (i == MAX_QUEUE_DEPTH - 1) stlink_dap_run_internal(ap->dap); return ERROR_OK; } static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data) { if (stlink_dap_get_error() != ERROR_OK) return ERROR_OK; unsigned int i = stlink_dap_handle->queue_index++; struct dap_queue *q = &stlink_dap_handle->queue[i]; /* test STLINK_F_HAS_CSW implicitly tests STLINK_F_HAS_MEM_16BIT, STLINK_F_HAS_MEM_WR_NO_INC * and STLINK_F_HAS_RW_MISC */ if ((stlink_dap_handle->version.flags & STLINK_F_HAS_CSW) && (reg == ADIV5_MEM_AP_REG_DRW || reg == ADIV5_MEM_AP_REG_BD0 || reg == ADIV5_MEM_AP_REG_BD1 || reg == ADIV5_MEM_AP_REG_BD2 || reg == ADIV5_MEM_AP_REG_BD3)) { /* de-queue previous write-TAR */ struct dap_queue *prev_q = q - 1; if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == ADIV5_MEM_AP_REG_TAR) { stlink_dap_handle->queue_index = i; i--; q = prev_q; prev_q--; } /* de-queue previous write-CSW if it didn't changed ap->csw_default */ if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == ADIV5_MEM_AP_REG_CSW && !prev_q->ap_w.changes_csw_default) { stlink_dap_handle->queue_index = i; q = prev_q; } switch (ap->csw_value & CSW_SIZE_MASK) { case CSW_8BIT: q->cmd = CMD_MEM_AP_WRITE8; break; case CSW_16BIT: q->cmd = CMD_MEM_AP_WRITE16; break; case CSW_32BIT: q->cmd = CMD_MEM_AP_WRITE32; break; default: LOG_ERROR("ST-Link: Unsupported CSW size %d", ap->csw_value & CSW_SIZE_MASK); stlink_dap_record_error(ERROR_FAIL); return ERROR_FAIL; } q->mem_ap.addr = (reg == ADIV5_MEM_AP_REG_DRW) ? ap->tar_value : ((ap->tar_value & ~0x0f) | (reg & 0x0c)); q->mem_ap.ap = ap; q->mem_ap.data = data; q->mem_ap.csw = ap->csw_default; /* force TAR and CSW update */ ap->tar_valid = false; ap->csw_value = 0; } else { q->cmd = CMD_AP_WRITE; q->ap_w.reg = reg; q->ap_w.ap = ap; q->ap_w.data = data; uint8_t ap_num = ap->ap_num; if (reg == ADIV5_MEM_AP_REG_CSW && ap->csw_default != last_csw_default[ap_num]) { q->ap_w.changes_csw_default = true; last_csw_default[ap_num] = ap->csw_default; } else { q->ap_w.changes_csw_default = false; } } if (i == MAX_QUEUE_DEPTH - 1) stlink_dap_run_internal(ap->dap); return ERROR_OK; } static int stlink_swim_op_srst(void) { return stlink_swim_generate_rst(stlink_dap_handle); } static int stlink_swim_op_read_mem(uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; uint32_t bytes_remaining; LOG_DEBUG_IO("read at 0x%08" PRIx32 " len %" PRIu32 "*0x%08" PRIx32, addr, size, count); count *= size; while (count) { bytes_remaining = (count > STLINK_SWIM_DATA_SIZE) ? STLINK_SWIM_DATA_SIZE : count; retval = stlink_swim_readbytes(stlink_dap_handle, addr, bytes_remaining, buffer); if (retval != ERROR_OK) return retval; buffer += bytes_remaining; addr += bytes_remaining; count -= bytes_remaining; } return ERROR_OK; } static int stlink_swim_op_write_mem(uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; uint32_t bytes_remaining; LOG_DEBUG_IO("write at 0x%08" PRIx32 " len %" PRIu32 "*0x%08" PRIx32, addr, size, count); count *= size; while (count) { bytes_remaining = (count > STLINK_SWIM_DATA_SIZE) ? STLINK_SWIM_DATA_SIZE : count; retval = stlink_swim_writebytes(stlink_dap_handle, addr, bytes_remaining, buffer); if (retval != ERROR_OK) return retval; buffer += bytes_remaining; addr += bytes_remaining; count -= bytes_remaining; } return ERROR_OK; } static int stlink_swim_op_reconnect(void) { int retval; retval = stlink_usb_mode_enter(stlink_dap_handle, STLINK_MODE_DEBUG_SWIM); if (retval != ERROR_OK) return retval; return stlink_swim_resync(stlink_dap_handle); } static int stlink_dap_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler) { return stlink_config_trace(stlink_dap_handle, enabled, pin_protocol, port_size, trace_freq, traceclkin_freq, prescaler); } static int stlink_dap_trace_read(uint8_t *buf, size_t *size) { return stlink_usb_trace_read(stlink_dap_handle, buf, size); } /** */ COMMAND_HANDLER(stlink_dap_vid_pid) { unsigned int i, max_usb_ids = HLA_MAX_USB_IDS; if (CMD_ARGC > max_usb_ids * 2) { LOG_WARNING("ignoring extra IDs in vid_pid " "(maximum is %d pairs)", max_usb_ids); CMD_ARGC = max_usb_ids * 2; } if (CMD_ARGC < 2 || (CMD_ARGC & 1)) { LOG_WARNING("incomplete vid_pid configuration directive"); return ERROR_COMMAND_SYNTAX_ERROR; } for (i = 0; i < CMD_ARGC; i += 2) { COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], stlink_dap_param.vid[i / 2]); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], stlink_dap_param.pid[i / 2]); } /* null termination */ stlink_dap_param.vid[i / 2] = stlink_dap_param.pid[i / 2] = 0; return ERROR_OK; } /** */ COMMAND_HANDLER(stlink_dap_backend_command) { /* default values */ bool use_stlink_tcp = false; uint16_t stlink_tcp_port = 7184; if (CMD_ARGC == 0 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; else if (strcmp(CMD_ARGV[0], "usb") == 0) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; /* else use_stlink_tcp = false (already the case ) */ } else if (strcmp(CMD_ARGV[0], "tcp") == 0) { use_stlink_tcp = true; if (CMD_ARGC == 2) COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], stlink_tcp_port); } else return ERROR_COMMAND_SYNTAX_ERROR; stlink_dap_param.use_stlink_tcp = use_stlink_tcp; stlink_dap_param.stlink_tcp_port = stlink_tcp_port; return ERROR_OK; } #define BYTES_PER_LINE 16 COMMAND_HANDLER(stlink_dap_cmd_command) { unsigned int rx_n, tx_n; struct stlink_usb_handle_s *h = stlink_dap_handle; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], rx_n); tx_n = CMD_ARGC - 1; if (tx_n > STLINK_SG_SIZE || rx_n > STLINK_DATA_SIZE) { LOG_ERROR("max %x byte sent and %d received", STLINK_SG_SIZE, STLINK_DATA_SIZE); return ERROR_COMMAND_SYNTAX_ERROR; } stlink_usb_init_buffer(h, h->rx_ep, rx_n); for (unsigned int i = 0; i < tx_n; i++) { uint8_t byte; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[i + 1], byte); h->cmdbuf[h->cmdidx++] = byte; } int retval = stlink_usb_xfer_noerrcheck(h, h->databuf, rx_n); if (retval != ERROR_OK) { LOG_ERROR("Error %d", retval); return retval; } for (unsigned int i = 0; i < rx_n; i++) command_print_sameline(CMD, "0x%02x%c", h->databuf[i], ((i == (rx_n - 1)) || ((i % BYTES_PER_LINE) == (BYTES_PER_LINE - 1))) ? '\n' : ' '); return ERROR_OK; } /** */ static const struct command_registration stlink_dap_subcommand_handlers[] = { { .name = "vid_pid", .handler = stlink_dap_vid_pid, .mode = COMMAND_CONFIG, .help = "USB VID and PID of the adapter", .usage = "(vid pid)+", }, { .name = "backend", .handler = &stlink_dap_backend_command, .mode = COMMAND_CONFIG, .help = "select which ST-Link backend to use", .usage = "usb | tcp [port]", }, { .name = "cmd", .handler = stlink_dap_cmd_command, .mode = COMMAND_EXEC, .help = "send arbitrary command", .usage = "rx_n (tx_byte)+", }, COMMAND_REGISTRATION_DONE }; /** */ static const struct command_registration stlink_dap_command_handlers[] = { { .name = "st-link", .mode = COMMAND_ANY, .help = "perform st-link management", .chain = stlink_dap_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; /** */ static int stlink_dap_init(void) { enum reset_types jtag_reset_config = jtag_get_reset_config(); enum stlink_mode mode; int retval; LOG_DEBUG("stlink_dap_init()"); if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) stlink_dap_param.connect_under_reset = true; else LOG_WARNING("\'srst_nogate\' reset_config option is required"); } if (transport_is_dapdirect_swd()) mode = STLINK_MODE_DEBUG_SWD; else if (transport_is_dapdirect_jtag()) mode = STLINK_MODE_DEBUG_JTAG; else if (transport_is_swim()) mode = STLINK_MODE_DEBUG_SWIM; else { LOG_ERROR("Unsupported transport"); return ERROR_FAIL; } retval = stlink_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle); if (retval != ERROR_OK) return retval; if ((mode != STLINK_MODE_DEBUG_SWIM) && !(stlink_dap_handle->version.flags & STLINK_F_HAS_DAP_REG)) { LOG_ERROR("ST-Link version does not support DAP direct transport"); return ERROR_FAIL; } return ERROR_OK; } /** */ static int stlink_dap_quit(void) { LOG_DEBUG("stlink_dap_quit()"); return stlink_close(stlink_dap_handle); } /** */ static int stlink_dap_reset(int req_trst, int req_srst) { LOG_DEBUG("stlink_dap_reset(%d)", req_srst); return stlink_usb_assert_srst(stlink_dap_handle, req_srst ? STLINK_DEBUG_APIV2_DRIVE_NRST_LOW : STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH); } /** */ static int stlink_dap_speed(int speed) { if (speed == 0) { LOG_ERROR("RTCK not supported. Set nonzero adapter_khz."); return ERROR_JTAG_NOT_IMPLEMENTED; } stlink_dap_param.initial_interface_speed = speed; stlink_speed(stlink_dap_handle, speed, false); return ERROR_OK; } /** */ static int stlink_dap_khz(int khz, int *jtag_speed) { if (khz == 0) { LOG_ERROR("RCLK not supported"); return ERROR_FAIL; } *jtag_speed = stlink_speed(stlink_dap_handle, khz, true); return ERROR_OK; } /** */ static int stlink_dap_speed_div(int speed, int *khz) { *khz = speed; return ERROR_OK; } static const struct dap_ops stlink_dap_ops = { .connect = stlink_dap_op_connect, .send_sequence = stlink_dap_op_send_sequence, .queue_dp_read = stlink_dap_op_queue_dp_read, .queue_dp_write = stlink_dap_op_queue_dp_write, .queue_ap_read = stlink_dap_op_queue_ap_read, .queue_ap_write = stlink_dap_op_queue_ap_write, .queue_ap_abort = stlink_dap_op_queue_ap_abort, .run = stlink_dap_op_queue_run, .sync = NULL, /* optional */ .quit = stlink_dap_op_quit, /* optional */ }; static const struct swim_driver stlink_swim_ops = { .srst = stlink_swim_op_srst, .read_mem = stlink_swim_op_read_mem, .write_mem = stlink_swim_op_write_mem, .reconnect = stlink_swim_op_reconnect, }; static const char *const stlink_dap_transport[] = { "dapdirect_swd", "dapdirect_jtag", "swim", NULL }; struct adapter_driver stlink_dap_adapter_driver = { .name = "st-link", .transports = stlink_dap_transport, .commands = stlink_dap_command_handlers, .init = stlink_dap_init, .quit = stlink_dap_quit, .reset = stlink_dap_reset, .speed = stlink_dap_speed, .khz = stlink_dap_khz, .speed_div = stlink_dap_speed_div, .config_trace = stlink_dap_config_trace, .poll_trace = stlink_dap_trace_read, .dap_jtag_ops = &stlink_dap_ops, .dap_swd_ops = &stlink_dap_ops, .swim_ops = &stlink_swim_ops, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/sysfsgpio.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au * ***************************************************************************/ /* 2014-12: Addition of the SWD protocol support is based on the initial work * on bcm2835gpio.c by Paul Fertser and modifications by Jean-Christian de Rivaz. */ /** * @file * This driver implements a bitbang jtag interface using gpio lines via * sysfs. * The aim of this driver implementation is use system GPIOs but avoid the * need for a additional kernel driver. * (Note memory mapped IO is another option, however it doesn't mix well with * the kernel gpiolib driver - which makes sense I guess.) * * A gpio is required for tck, tms, tdi and tdo. One or both of srst and trst * must be also be specified. The required jtag gpios are specified via the * sysfsgpio_jtag_nums command or the relevant sysfsgpio_XXX_num commands. * The srst and trst gpios are set via the sysfsgpio_srst_num and * sysfsgpio_trst_num respectively. GPIO numbering follows the kernel * convention of starting from 0. * * The gpios should not be in use by another entity, and must not be requested * by a kernel driver without also being exported by it (otherwise they can't * be exported by sysfs). * * The sysfs gpio interface can only manipulate one gpio at a time, so the * bitbang write handler remembers the last state for tck, tms, tdi to avoid * superfluous writes. * For speed the sysfs "value" entry is opened at init and held open. * This results in considerable gains over open-write-close (45s vs 900s) * * Further work could address: * -srst and trst open drain/ push pull * -configurable active high/low for srst & trst */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/time_support.h> #include <jtag/interface.h> #include <transport/transport.h> #include "bitbang.h" /* * Helper func to determine if gpio number valid * * Assume here that there will be less than 10000 gpios on a system */ static bool is_gpio_valid(int gpio) { return gpio >= 0 && gpio < 10000; } /* * Helper func to open, write to and close a file * name and valstr must be null terminated. * * Returns negative on failure. */ static int open_write_close(const char *name, const char *valstr) { int ret; int fd = open(name, O_WRONLY); if (fd < 0) return fd; ret = write(fd, valstr, strlen(valstr)); close(fd); return ret; } /* * Helper func to unexport gpio from sysfs */ static void unexport_sysfs_gpio(int gpio) { char gpiostr[5]; if (!is_gpio_valid(gpio)) return; snprintf(gpiostr, sizeof(gpiostr), "%d", gpio); if (open_write_close("/sys/class/gpio/unexport", gpiostr) < 0) LOG_ERROR("Couldn't unexport gpio %d", gpio); } /* * Exports and sets up direction for gpio. * If the gpio is an output, it is initialized according to init_high, * otherwise it is ignored. * * If the gpio is already exported we just show a warning and continue; if * openocd happened to crash (or was killed by user) then the gpios will not * have been cleaned up. */ static int setup_sysfs_gpio(int gpio, int is_output, int init_high) { struct timeval timeout, now; char buf[40]; char gpiostr[5]; int ret; if (!is_gpio_valid(gpio)) return ERROR_OK; snprintf(gpiostr, sizeof(gpiostr), "%d", gpio); ret = open_write_close("/sys/class/gpio/export", gpiostr); if (ret < 0) { if (errno == EBUSY) { LOG_WARNING("gpio %d is already exported", gpio); } else { LOG_ERROR("Couldn't export gpio %d", gpio); LOG_ERROR("sysfsgpio: %s", strerror(errno)); return ERROR_FAIL; } } gettimeofday(&timeout, NULL); timeval_add_time(&timeout, 0, 500000); snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio); for (;;) { ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in"); if (ret >= 0 || errno != EACCES) break; gettimeofday(&now, NULL); if (timeval_compare(&now, &timeout) >= 0) break; jtag_sleep(10000); } if (ret < 0) { LOG_ERROR("Couldn't set direction for gpio %d", gpio); LOG_ERROR("sysfsgpio: %s", strerror(errno)); unexport_sysfs_gpio(gpio); return ERROR_FAIL; } snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio); for (;;) { ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC); if (ret >= 0 || errno != EACCES) break; gettimeofday(&now, NULL); if (timeval_compare(&now, &timeout) >= 0) break; jtag_sleep(10000); } if (ret < 0) { LOG_ERROR("Couldn't open value for gpio %d", gpio); LOG_ERROR("sysfsgpio: %s", strerror(errno)); unexport_sysfs_gpio(gpio); } return ret; } /* gpio numbers for each gpio. Negative values are invalid */ static int tck_gpio = -1; static int tms_gpio = -1; static int tdi_gpio = -1; static int tdo_gpio = -1; static int trst_gpio = -1; static int srst_gpio = -1; static int swclk_gpio = -1; static int swdio_gpio = -1; /* * file descriptors for /sys/class/gpio/gpioXX/value * Set up during init. */ static int tck_fd = -1; static int tms_fd = -1; static int tdi_fd = -1; static int tdo_fd = -1; static int trst_fd = -1; static int srst_fd = -1; static int swclk_fd = -1; static int swdio_fd = -1; static int last_swclk; static int last_swdio; static bool last_stored; static bool swdio_input; static void sysfsgpio_swdio_drive(bool is_output) { char buf[40]; int ret; snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", swdio_gpio); ret = open_write_close(buf, is_output ? "high" : "in"); if (ret < 0) { LOG_ERROR("Couldn't set direction for gpio %d", swdio_gpio); LOG_ERROR("sysfsgpio: %s", strerror(errno)); } last_stored = false; swdio_input = !is_output; } static int sysfsgpio_swdio_read(void) { char buf[1]; /* important to seek to signal sysfs of new read */ lseek(swdio_fd, 0, SEEK_SET); int ret = read(swdio_fd, &buf, sizeof(buf)); if (ret < 0) { LOG_WARNING("reading swdio failed"); return 0; } return buf[0] != '0'; } static int sysfsgpio_swd_write(int swclk, int swdio) { const char one[] = "1"; const char zero[] = "0"; size_t bytes_written; if (!swdio_input) { if (!last_stored || (swdio != last_swdio)) { bytes_written = write(swdio_fd, swdio ? &one : &zero, 1); if (bytes_written != 1) LOG_WARNING("writing swdio failed"); } } /* write swclk last */ if (!last_stored || (swclk != last_swclk)) { bytes_written = write(swclk_fd, swclk ? &one : &zero, 1); if (bytes_written != 1) LOG_WARNING("writing swclk failed"); } last_swdio = swdio; last_swclk = swclk; last_stored = true; return ERROR_OK; } /* * Bitbang interface read of TDO * * The sysfs value will read back either '0' or '1'. The trick here is to call * lseek to bypass buffering in the sysfs kernel driver. */ static bb_value_t sysfsgpio_read(void) { char buf[1]; /* important to seek to signal sysfs of new read */ lseek(tdo_fd, 0, SEEK_SET); int ret = read(tdo_fd, &buf, sizeof(buf)); if (ret < 0) { LOG_WARNING("reading tdo failed"); return 0; } return buf[0] == '0' ? BB_LOW : BB_HIGH; } /* * Bitbang interface write of TCK, TMS, TDI * * Seeing as this is the only function where the outputs are changed, * we can cache the old value to avoid needlessly writing it. */ static int sysfsgpio_write(int tck, int tms, int tdi) { const char one[] = "1"; const char zero[] = "0"; static int last_tck; static int last_tms; static int last_tdi; static int first_time; size_t bytes_written; if (!first_time) { last_tck = !tck; last_tms = !tms; last_tdi = !tdi; first_time = 1; } if (tdi != last_tdi) { bytes_written = write(tdi_fd, tdi ? &one : &zero, 1); if (bytes_written != 1) LOG_WARNING("writing tdi failed"); } if (tms != last_tms) { bytes_written = write(tms_fd, tms ? &one : &zero, 1); if (bytes_written != 1) LOG_WARNING("writing tms failed"); } /* write clk last */ if (tck != last_tck) { bytes_written = write(tck_fd, tck ? &one : &zero, 1); if (bytes_written != 1) LOG_WARNING("writing tck failed"); } last_tdi = tdi; last_tms = tms; last_tck = tck; return ERROR_OK; } /* * Bitbang interface to manipulate reset lines SRST and TRST * * (1) assert or (0) deassert reset lines */ static int sysfsgpio_reset(int trst, int srst) { LOG_DEBUG("sysfsgpio_reset"); const char one[] = "1"; const char zero[] = "0"; size_t bytes_written; /* assume active low */ if (srst_fd >= 0) { bytes_written = write(srst_fd, srst ? &zero : &one, 1); if (bytes_written != 1) LOG_WARNING("writing srst failed"); } /* assume active low */ if (trst_fd >= 0) { bytes_written = write(trst_fd, trst ? &zero : &one, 1); if (bytes_written != 1) LOG_WARNING("writing trst failed"); } return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionums) { if (CMD_ARGC == 4) { COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio); COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio); COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio); } else if (CMD_ARGC != 0) { return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "SysfsGPIO nums: tck = %d, tms = %d, tdi = %d, tdo = %d", tck_gpio, tms_gpio, tdi_gpio, tdo_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tck) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); command_print(CMD, "SysfsGPIO num: tck = %d", tck_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tms) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio); command_print(CMD, "SysfsGPIO num: tms = %d", tms_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tdo) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio); command_print(CMD, "SysfsGPIO num: tdo = %d", tdo_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tdi) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio); command_print(CMD, "SysfsGPIO num: tdi = %d", tdi_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_srst) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio); command_print(CMD, "SysfsGPIO num: srst = %d", srst_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_trst) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio); command_print(CMD, "SysfsGPIO num: trst = %d", trst_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_swd_gpionums) { if (CMD_ARGC == 2) { COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio); COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio); } else if (CMD_ARGC != 0) { return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "SysfsGPIO nums: swclk = %d, swdio = %d", swclk_gpio, swdio_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_swd_gpionum_swclk) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio); command_print(CMD, "SysfsGPIO num: swclk = %d", swclk_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_swd_gpionum_swdio) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio); command_print(CMD, "SysfsGPIO num: swdio = %d", swdio_gpio); return ERROR_OK; } static const struct command_registration sysfsgpio_subcommand_handlers[] = { { .name = "jtag_nums", .handler = &sysfsgpio_handle_jtag_gpionums, .mode = COMMAND_CONFIG, .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)", .usage = "[tck tms tdi tdo]", }, { .name = "tck_num", .handler = &sysfsgpio_handle_jtag_gpionum_tck, .mode = COMMAND_CONFIG, .help = "gpio number for tck.", .usage = "[tck]", }, { .name = "tms_num", .handler = &sysfsgpio_handle_jtag_gpionum_tms, .mode = COMMAND_CONFIG, .help = "gpio number for tms.", .usage = "[tms]", }, { .name = "tdo_num", .handler = &sysfsgpio_handle_jtag_gpionum_tdo, .mode = COMMAND_CONFIG, .help = "gpio number for tdo.", .usage = "[tdo]", }, { .name = "tdi_num", .handler = &sysfsgpio_handle_jtag_gpionum_tdi, .mode = COMMAND_CONFIG, .help = "gpio number for tdi.", .usage = "[tdi]", }, { .name = "srst_num", .handler = &sysfsgpio_handle_jtag_gpionum_srst, .mode = COMMAND_CONFIG, .help = "gpio number for srst.", .usage = "[srst]", }, { .name = "trst_num", .handler = &sysfsgpio_handle_jtag_gpionum_trst, .mode = COMMAND_CONFIG, .help = "gpio number for trst.", .usage = "[trst]", }, { .name = "swd_nums", .handler = &sysfsgpio_handle_swd_gpionums, .mode = COMMAND_CONFIG, .help = "gpio numbers for swclk, swdio. (in that order)", .usage = "[swclk swdio]", }, { .name = "swclk_num", .handler = &sysfsgpio_handle_swd_gpionum_swclk, .mode = COMMAND_CONFIG, .help = "gpio number for swclk.", .usage = "[swclk]", }, { .name = "swdio_num", .handler = &sysfsgpio_handle_swd_gpionum_swdio, .mode = COMMAND_CONFIG, .help = "gpio number for swdio.", .usage = "[swdio]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration sysfsgpio_command_handlers[] = { { .name = "sysfsgpio", .mode = COMMAND_ANY, .help = "perform sysfsgpio management", .chain = sysfsgpio_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static int sysfsgpio_init(void); static int sysfsgpio_quit(void); static const char * const sysfsgpio_transports[] = { "jtag", "swd", NULL }; static struct jtag_interface sysfsgpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, }; struct adapter_driver sysfsgpio_adapter_driver = { .name = "sysfsgpio", .transports = sysfsgpio_transports, .commands = sysfsgpio_command_handlers, .init = sysfsgpio_init, .quit = sysfsgpio_quit, .reset = sysfsgpio_reset, .jtag_ops = &sysfsgpio_interface, .swd_ops = &bitbang_swd, }; static struct bitbang_interface sysfsgpio_bitbang = { .read = sysfsgpio_read, .write = sysfsgpio_write, .swdio_read = sysfsgpio_swdio_read, .swdio_drive = sysfsgpio_swdio_drive, .swd_write = sysfsgpio_swd_write, .blink = NULL, }; /* helper func to close and cleanup files only if they were valid/ used */ static void cleanup_fd(int fd, int gpio) { if (gpio >= 0) { if (fd >= 0) close(fd); unexport_sysfs_gpio(gpio); } } static void cleanup_all_fds(void) { if (transport_is_jtag()) { cleanup_fd(tck_fd, tck_gpio); cleanup_fd(tms_fd, tms_gpio); cleanup_fd(tdi_fd, tdi_gpio); cleanup_fd(tdo_fd, tdo_gpio); cleanup_fd(trst_fd, trst_gpio); } if (transport_is_swd()) { cleanup_fd(swclk_fd, swclk_gpio); cleanup_fd(swdio_fd, swdio_gpio); } cleanup_fd(srst_fd, srst_gpio); } static bool sysfsgpio_jtag_mode_possible(void) { if (!is_gpio_valid(tck_gpio)) return false; if (!is_gpio_valid(tms_gpio)) return false; if (!is_gpio_valid(tdi_gpio)) return false; if (!is_gpio_valid(tdo_gpio)) return false; return true; } static bool sysfsgpio_swd_mode_possible(void) { if (!is_gpio_valid(swclk_gpio)) return false; if (!is_gpio_valid(swdio_gpio)) return false; return true; } static int sysfsgpio_init(void) { bitbang_interface = &sysfsgpio_bitbang; LOG_INFO("SysfsGPIO JTAG/SWD bitbang driver"); /* * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. * For SWD, SWCLK and SWDIO are configures as output high. */ if (transport_is_jtag()) { if (!sysfsgpio_jtag_mode_possible()) { LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode"); return ERROR_JTAG_INIT_FAILED; } tck_fd = setup_sysfs_gpio(tck_gpio, 1, 0); if (tck_fd < 0) goto out_error; tms_fd = setup_sysfs_gpio(tms_gpio, 1, 1); if (tms_fd < 0) goto out_error; tdi_fd = setup_sysfs_gpio(tdi_gpio, 1, 0); if (tdi_fd < 0) goto out_error; tdo_fd = setup_sysfs_gpio(tdo_gpio, 0, 0); if (tdo_fd < 0) goto out_error; /* assume active low*/ if (trst_gpio >= 0) { trst_fd = setup_sysfs_gpio(trst_gpio, 1, 1); if (trst_fd < 0) goto out_error; } } if (transport_is_swd()) { if (!sysfsgpio_swd_mode_possible()) { LOG_ERROR("Require swclk and swdio gpio for SWD mode"); return ERROR_JTAG_INIT_FAILED; } swclk_fd = setup_sysfs_gpio(swclk_gpio, 1, 0); if (swclk_fd < 0) goto out_error; swdio_fd = setup_sysfs_gpio(swdio_gpio, 1, 0); if (swdio_fd < 0) goto out_error; } /* assume active low*/ if (srst_gpio >= 0) { srst_fd = setup_sysfs_gpio(srst_gpio, 1, 1); if (srst_fd < 0) goto out_error; } return ERROR_OK; out_error: cleanup_all_fds(); return ERROR_JTAG_INIT_FAILED; } static int sysfsgpio_quit(void) { cleanup_all_fds(); return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/ti_icdi_usb.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include <helper/binarybuffer.h> #include <jtag/adapter.h> #include <jtag/interface.h> #include <jtag/hla/hla_layout.h> #include <jtag/hla/hla_transport.h> #include <jtag/hla/hla_interface.h> #include <target/target.h> #include <target/cortex_m.h> #include "libusb_helper.h" #define ICDI_WRITE_ENDPOINT 0x02 #define ICDI_READ_ENDPOINT 0x83 #define ICDI_WRITE_TIMEOUT (LIBUSB_TIMEOUT_MS) #define ICDI_READ_TIMEOUT (LIBUSB_TIMEOUT_MS) #define ICDI_PACKET_SIZE 2048 #define PACKET_START "$" #define PACKET_END "#" struct icdi_usb_handle_s { struct libusb_device_handle *usb_dev; char *read_buffer; char *write_buffer; int max_packet; int read_count; uint32_t max_rw_packet; /* max X packet (read/write memory) transfers */ }; static int icdi_usb_read_mem(void *handle, uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer); static int icdi_usb_write_mem(void *handle, uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer); static int remote_escape_output(const char *buffer, int len, char *out_buf, int *out_len, int out_maxlen) { int input_index, output_index; output_index = 0; for (input_index = 0; input_index < len; input_index++) { char b = buffer[input_index]; if (b == '$' || b == '#' || b == '}' || b == '*') { /* These must be escaped. */ if (output_index + 2 > out_maxlen) break; out_buf[output_index++] = '}'; out_buf[output_index++] = b ^ 0x20; } else { if (output_index + 1 > out_maxlen) break; out_buf[output_index++] = b; } } *out_len = input_index; return output_index; } static int remote_unescape_input(const char *buffer, int len, char *out_buf, int out_maxlen) { int input_index, output_index; int escaped; output_index = 0; escaped = 0; for (input_index = 0; input_index < len; input_index++) { char b = buffer[input_index]; if (output_index + 1 > out_maxlen) LOG_ERROR("Received too much data from the target."); if (escaped) { out_buf[output_index++] = b ^ 0x20; escaped = 0; } else if (b == '}') escaped = 1; else out_buf[output_index++] = b; } if (escaped) LOG_ERROR("Unmatched escape character in target response."); return output_index; } static int icdi_send_packet(void *handle, int len) { unsigned char cksum = 0; struct icdi_usb_handle_s *h = handle; int result, retry = 0; int transferred = 0; assert(handle); /* check we have a large enough buffer for checksum "#00" */ if (len + 3 > h->max_packet) { LOG_ERROR("packet buffer too small"); return ERROR_FAIL; } /* calculate checksum - offset start of packet */ for (int i = 1; i < len; i++) cksum += h->write_buffer[i]; len += sprintf(&h->write_buffer[len], PACKET_END "%02x", cksum); #ifdef _DEBUG_USB_COMMS_ char buffer[50]; char ch = h->write_buffer[1]; if (ch == 'x' || ch == 'X') LOG_DEBUG("writing packet: <binary>"); else { memcpy(buffer, h->write_buffer, len >= 50 ? 50-1 : len); buffer[len] = 0; LOG_DEBUG("writing packet: %s", buffer); } #endif while (1) { result = libusb_bulk_transfer(h->usb_dev, ICDI_WRITE_ENDPOINT, (unsigned char *)h->write_buffer, len, &transferred, ICDI_WRITE_TIMEOUT); if (result != 0 || transferred != len) { LOG_DEBUG("Error TX Data %d", result); return ERROR_FAIL; } /* check that the client got the message ok, or shall we resend */ result = libusb_bulk_transfer(h->usb_dev, ICDI_READ_ENDPOINT, (unsigned char *)h->read_buffer, h->max_packet, &transferred, ICDI_READ_TIMEOUT); if (result != 0 || transferred < 1) { LOG_DEBUG("Error RX Data %d", result); return ERROR_FAIL; } #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("received reply: '%c' : count %d", h->read_buffer[0], transferred); #endif if (h->read_buffer[0] == '-') { LOG_DEBUG("Resending packet %d", ++retry); } else { if (h->read_buffer[0] != '+') LOG_DEBUG("Unexpected Reply from ICDI: %c", h->read_buffer[0]); break; } if (retry == 3) { LOG_DEBUG("maximum nack retries attempted"); return ERROR_FAIL; } } retry = 0; h->read_count = transferred; while (1) { /* read reply from icdi */ result = libusb_bulk_transfer(h->usb_dev, ICDI_READ_ENDPOINT, (unsigned char *)h->read_buffer + h->read_count, h->max_packet - h->read_count, &transferred, ICDI_READ_TIMEOUT); #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("received data: count %d", transferred); #endif /* check for errors but retry for timeout */ if (result != 0) { if (result == LIBUSB_ERROR_TIMEOUT) { LOG_DEBUG("Error RX timeout %d", result); } else { LOG_DEBUG("Error RX Data %d", result); return ERROR_FAIL; } } h->read_count += transferred; /* we need to make sure we have a full packet, including checksum */ if (h->read_count > 5) { /* check that we have received an packet delimiter * we do not validate the checksum * reply should contain $...#AA - so we check for # */ if (h->read_buffer[h->read_count - 3] == '#') return ERROR_OK; } if (retry++ == 3) { LOG_DEBUG("maximum data retries attempted"); break; } } return ERROR_FAIL; } static int icdi_send_cmd(void *handle, const char *cmd) { struct icdi_usb_handle_s *h = handle; int cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "%s", cmd); return icdi_send_packet(handle, cmd_len); } static int icdi_send_remote_cmd(void *handle, const char *data) { struct icdi_usb_handle_s *h = handle; size_t cmd_len = sprintf(h->write_buffer, PACKET_START "qRcmd,"); cmd_len += hexify(h->write_buffer + cmd_len, (const uint8_t *)data, strlen(data), h->max_packet - cmd_len); return icdi_send_packet(handle, cmd_len); } static int icdi_get_cmd_result(void *handle) { struct icdi_usb_handle_s *h = handle; int offset = 0; char ch; assert(handle); do { ch = h->read_buffer[offset++]; if (offset > h->read_count) return ERROR_FAIL; } while (ch != '$'); if (memcmp("OK", h->read_buffer + offset, 2) == 0) return ERROR_OK; if (h->read_buffer[offset] == 'E') { /* get error code */ uint8_t result; if (unhexify(&result, h->read_buffer + offset + 1, 1) != 1) return ERROR_FAIL; return result; } /* for now we assume everything else is ok */ return ERROR_OK; } static int icdi_usb_idcode(void *handle, uint32_t *idcode) { *idcode = 0; return ERROR_OK; } static int icdi_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) { uint8_t buf[4]; /* REVISIT: There's no target pointer here so there's no way to use target_buffer_set_u32(). * I guess all supported chips are little-endian anyway. */ h_u32_to_le(buf, val); return icdi_usb_write_mem(handle, addr, 4, 1, buf); } static enum target_state icdi_usb_state(void *handle) { int result; struct icdi_usb_handle_s *h = handle; uint32_t dhcsr; uint8_t buf[4]; result = icdi_usb_read_mem(h, DCB_DHCSR, 4, 1, buf); if (result != ERROR_OK) return TARGET_UNKNOWN; /* REVISIT: There's no target pointer here so there's no way to use target_buffer_get_u32(). * I guess all supported chips are little-endian anyway. */ dhcsr = le_to_h_u32(buf); if (dhcsr & S_HALT) return TARGET_HALTED; return TARGET_RUNNING; } static int icdi_usb_version(void *handle) { struct icdi_usb_handle_s *h = handle; char version[20]; /* get info about icdi */ int result = icdi_send_remote_cmd(handle, "version"); if (result != ERROR_OK) return result; if (h->read_count < 8) { LOG_ERROR("Invalid Reply Received"); return ERROR_FAIL; } /* convert reply */ if (unhexify((uint8_t *)version, h->read_buffer + 2, 4) != 4) { LOG_WARNING("unable to get ICDI version"); return ERROR_OK; } /* null terminate and print info */ version[4] = 0; LOG_INFO("ICDI Firmware version: %s", version); return ERROR_OK; } static int icdi_usb_query(void *handle) { int result; struct icdi_usb_handle_s *h = handle; result = icdi_send_cmd(handle, "qSupported"); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("query supported failed: 0x%x", result); return ERROR_FAIL; } /* from this we can get the max packet supported */ /* query packet buffer size */ char *offset = strstr(h->read_buffer, "PacketSize"); if (offset) { char *separator; int max_packet; max_packet = strtol(offset + 11, &separator, 16); if (!max_packet) LOG_ERROR("invalid max packet, using defaults"); else h->max_packet = max_packet; LOG_DEBUG("max packet supported : %i bytes", h->max_packet); } /* if required re allocate packet buffer */ if (h->max_packet != ICDI_PACKET_SIZE) { h->read_buffer = realloc(h->read_buffer, h->max_packet); h->write_buffer = realloc(h->write_buffer, h->max_packet); if (!h->read_buffer || !h->write_buffer) { LOG_ERROR("unable to reallocate memory"); return ERROR_FAIL; } } /* set extended mode */ result = icdi_send_cmd(handle, "!"); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("unable to enable extended mode: 0x%x", result); return ERROR_FAIL; } return ERROR_OK; } static int icdi_usb_reset(void *handle) { /* we do this in hla_target.c */ return ERROR_OK; } static int icdi_usb_assert_srst(void *handle, int srst) { /* TODO not supported yet */ return ERROR_COMMAND_NOTFOUND; } static int icdi_usb_run(void *handle) { int result; /* resume target at current address */ result = icdi_send_cmd(handle, "c"); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("continue failed: 0x%x", result); return ERROR_FAIL; } return result; } static int icdi_usb_halt(void *handle) { int result; /* this query halts the target ?? */ result = icdi_send_cmd(handle, "?"); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("halt failed: 0x%x", result); return ERROR_FAIL; } return result; } static int icdi_usb_step(void *handle) { int result; /* step target at current address */ result = icdi_send_cmd(handle, "s"); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("step failed: 0x%x", result); return ERROR_FAIL; } return result; } static int icdi_usb_read_regs(void *handle) { /* currently unsupported */ return ERROR_OK; } static int icdi_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) { int result; struct icdi_usb_handle_s *h = handle; char cmd[10]; snprintf(cmd, sizeof(cmd), "p%x", regsel); result = icdi_send_cmd(handle, cmd); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("register read failed: 0x%x", result); return ERROR_FAIL; } /* convert result */ uint8_t buf[4]; if (unhexify(buf, h->read_buffer + 2, 4) != 4) { LOG_ERROR("failed to convert result"); return ERROR_FAIL; } *val = le_to_h_u32(buf); return result; } static int icdi_usb_write_reg(void *handle, unsigned int regsel, uint32_t val) { int result; char cmd[20]; uint8_t buf[4]; h_u32_to_le(buf, val); int cmd_len = snprintf(cmd, sizeof(cmd), "P%x=", regsel); hexify(cmd + cmd_len, buf, 4, sizeof(cmd)); result = icdi_send_cmd(handle, cmd); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("register write failed: 0x%x", result); return ERROR_FAIL; } return result; } static int icdi_usb_read_mem_int(void *handle, uint32_t addr, uint32_t len, uint8_t *buffer) { int result; struct icdi_usb_handle_s *h = handle; char cmd[20]; snprintf(cmd, sizeof(cmd), "x%" PRIx32 ",%" PRIx32, addr, len); result = icdi_send_cmd(handle, cmd); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("memory read failed: 0x%x", result); return ERROR_FAIL; } /* unescape input */ int read_len = remote_unescape_input(h->read_buffer + 5, h->read_count - 8, (char *)buffer, len); if (read_len != (int)len) { LOG_ERROR("read more bytes than expected: actual 0x%x expected 0x%" PRIx32, read_len, len); return ERROR_FAIL; } return ERROR_OK; } static int icdi_usb_write_mem_int(void *handle, uint32_t addr, uint32_t len, const uint8_t *buffer) { int result; struct icdi_usb_handle_s *h = handle; size_t cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "X%" PRIx32 ",%" PRIx32 ":", addr, len); int out_len; cmd_len += remote_escape_output((const char *)buffer, len, h->write_buffer + cmd_len, &out_len, h->max_packet - cmd_len); if (out_len < (int)len) { /* for now issue a error as we have no way of allocating a larger buffer */ LOG_ERROR("memory buffer too small: requires 0x%x actual 0x%" PRIx32, out_len, len); return ERROR_FAIL; } result = icdi_send_packet(handle, cmd_len); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("memory write failed: 0x%x", result); return ERROR_FAIL; } return ERROR_OK; } static int icdi_usb_read_mem(void *handle, uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer) { int retval = ERROR_OK; struct icdi_usb_handle_s *h = handle; uint32_t bytes_remaining; /* calculate byte count */ count *= size; while (count) { bytes_remaining = h->max_rw_packet; if (count < bytes_remaining) bytes_remaining = count; retval = icdi_usb_read_mem_int(handle, addr, bytes_remaining, buffer); if (retval != ERROR_OK) return retval; buffer += bytes_remaining; addr += bytes_remaining; count -= bytes_remaining; } return retval; } static int icdi_usb_write_mem(void *handle, uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval = ERROR_OK; struct icdi_usb_handle_s *h = handle; uint32_t bytes_remaining; /* calculate byte count */ count *= size; while (count) { bytes_remaining = h->max_rw_packet; if (count < bytes_remaining) bytes_remaining = count; retval = icdi_usb_write_mem_int(handle, addr, bytes_remaining, buffer); if (retval != ERROR_OK) return retval; buffer += bytes_remaining; addr += bytes_remaining; count -= bytes_remaining; } return retval; } static int icdi_usb_override_target(const char *targetname) { return !strcmp(targetname, "cortex_m"); } static int icdi_usb_close(void *handle) { struct icdi_usb_handle_s *h = handle; if (!h) return ERROR_OK; if (h->usb_dev) jtag_libusb_close(h->usb_dev); free(h->read_buffer); free(h->write_buffer); free(handle); return ERROR_OK; } static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) { /* TODO: Convert remaining libusb_ calls to jtag_libusb_ */ int retval; struct icdi_usb_handle_s *h; LOG_DEBUG("icdi_usb_open"); h = calloc(1, sizeof(struct icdi_usb_handle_s)); if (!h) { LOG_ERROR("unable to allocate memory"); return ERROR_FAIL; } for (uint8_t i = 0; param->vid[i] && param->pid[i]; ++i) LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", param->transport, param->vid[i], param->pid[i], adapter_get_required_serial() ? adapter_get_required_serial() : ""); /* TI (Stellaris) ICDI provides its serial number in the USB descriptor; no need to provide a callback here. */ jtag_libusb_open(param->vid, param->pid, &h->usb_dev, NULL); if (!h->usb_dev) { LOG_ERROR("open failed"); goto error_open; } if (libusb_claim_interface(h->usb_dev, 2)) { LOG_DEBUG("claim interface failed"); goto error_open; } /* check if mode is supported */ retval = ERROR_OK; switch (param->transport) { #if 0 /* TODO place holder as swd is not currently supported */ case HL_TRANSPORT_SWD: #endif case HL_TRANSPORT_JTAG: break; default: retval = ERROR_FAIL; break; } if (retval != ERROR_OK) { LOG_ERROR("mode (transport) not supported by device"); goto error_open; } /* allocate buffer */ h->read_buffer = malloc(ICDI_PACKET_SIZE); h->write_buffer = malloc(ICDI_PACKET_SIZE); h->max_packet = ICDI_PACKET_SIZE; if (!h->read_buffer || !h->write_buffer) { LOG_DEBUG("malloc failed"); goto error_open; } /* query icdi version etc */ retval = icdi_usb_version(h); if (retval != ERROR_OK) goto error_open; /* query icdi support */ retval = icdi_usb_query(h); if (retval != ERROR_OK) goto error_open; *fd = h; /* set the max target read/write buffer in bytes * as we are using gdb binary packets to transfer memory we have to * reserve half the buffer for any possible escape chars plus * at least 64 bytes for the gdb packet header */ h->max_rw_packet = (((h->max_packet - 64) / 4) * 4) / 2; return ERROR_OK; error_open: icdi_usb_close(h); return ERROR_FAIL; } struct hl_layout_api_s icdi_usb_layout_api = { .open = icdi_usb_open, .close = icdi_usb_close, .idcode = icdi_usb_idcode, .state = icdi_usb_state, .reset = icdi_usb_reset, .assert_srst = icdi_usb_assert_srst, .run = icdi_usb_run, .halt = icdi_usb_halt, .step = icdi_usb_step, .read_regs = icdi_usb_read_regs, .read_reg = icdi_usb_read_reg, .write_reg = icdi_usb_write_reg, .read_mem = icdi_usb_read_mem, .write_mem = icdi_usb_write_mem, .write_debug_reg = icdi_usb_write_debug_reg, .override_target = icdi_usb_override_target, .custom_command = icdi_send_remote_cmd, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/ulink.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011-2013 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <math.h> #include "helper/system.h" #include <jtag/interface.h> #include <jtag/commands.h> #include <target/image.h> #include <libusb.h> #include "libusb_helper.h" #include "OpenULINK/include/msgtypes.h" /** USB Vendor ID of ULINK device in unconfigured state (no firmware loaded * yet) or with OpenULINK firmware. */ #define ULINK_VID 0xC251 /** USB Product ID of ULINK device in unconfigured state (no firmware loaded * yet) or with OpenULINK firmware. */ #define ULINK_PID 0x2710 /** Address of EZ-USB CPU Control & Status register. This register can be * written by issuing a Control EP0 vendor request. */ #define CPUCS_REG 0x7F92 /** USB Control EP0 bRequest: "Firmware Load". */ #define REQUEST_FIRMWARE_LOAD 0xA0 /** Value to write into CPUCS to put EZ-USB into reset. */ #define CPU_RESET 0x01 /** Value to write into CPUCS to put EZ-USB out of reset. */ #define CPU_START 0x00 /** Base address of firmware in EZ-USB code space. */ #define FIRMWARE_ADDR 0x0000 /** USB interface number */ #define USB_INTERFACE 0 /** Delay (in microseconds) to wait while EZ-USB performs ReNumeration. */ #define ULINK_RENUMERATION_DELAY 1500000 /** Default location of OpenULINK firmware image. */ #define ULINK_FIRMWARE_FILE PKGDATADIR "/OpenULINK/ulink_firmware.hex" /** Maximum size of a single firmware section. Entire EZ-USB code space = 8kB */ #define SECTION_BUFFERSIZE 8192 /** Tuning of OpenOCD SCAN commands split into multiple OpenULINK commands. */ #define SPLIT_SCAN_THRESHOLD 10 /** ULINK hardware type */ enum ulink_type { /** Original ULINK adapter, based on Cypress EZ-USB (AN2131): * Full JTAG support, no SWD support. */ ULINK_1, /** Newer ULINK adapter, based on NXP LPC2148. Currently unsupported. */ ULINK_2, /** Newer ULINK adapter, based on EZ-USB FX2 + FPGA. Currently unsupported. */ ULINK_PRO, /** Newer ULINK adapter, possibly based on ULINK 2. Currently unsupported. */ ULINK_ME }; enum ulink_payload_direction { PAYLOAD_DIRECTION_OUT, PAYLOAD_DIRECTION_IN }; enum ulink_delay_type { DELAY_CLOCK_TCK, DELAY_CLOCK_TMS, DELAY_SCAN_IN, DELAY_SCAN_OUT, DELAY_SCAN_IO }; /** * OpenULINK command (OpenULINK command queue element). * * For the OUT direction payload, things are quite easy: Payload is stored * in a rather small array (up to 63 bytes), the payload is always allocated * by the function generating the command and freed by ulink_clear_queue(). * * For the IN direction payload, things get a little bit more complicated: * The maximum IN payload size for a single command is 64 bytes. Assume that * a single OpenOCD command needs to scan 256 bytes. This results in the * generation of four OpenULINK commands. The function generating these * commands shall allocate an uint8_t[256] array. Each command's #payload_in * pointer shall point to the corresponding offset where IN data shall be * placed, while #payload_in_start shall point to the first element of the 256 * byte array. * - first command: #payload_in_start + 0 * - second command: #payload_in_start + 64 * - third command: #payload_in_start + 128 * - fourth command: #payload_in_start + 192 * * The last command sets #needs_postprocessing to true. */ struct ulink_cmd { uint8_t id; /**< ULINK command ID */ uint8_t *payload_out; /**< OUT direction payload data */ uint8_t payload_out_size; /**< OUT direction payload size for this command */ uint8_t *payload_in_start; /**< Pointer to first element of IN payload array */ uint8_t *payload_in; /**< Pointer where IN payload shall be stored */ uint8_t payload_in_size; /**< IN direction payload size for this command */ /** Indicates if this command needs post-processing */ bool needs_postprocessing; /** Indicates if ulink_clear_queue() should free payload_in_start */ bool free_payload_in_start; /** Pointer to corresponding OpenOCD command for post-processing */ struct jtag_command *cmd_origin; struct ulink_cmd *next; /**< Pointer to next command (linked list) */ }; /** Describes one driver instance */ struct ulink { struct libusb_context *libusb_ctx; struct libusb_device_handle *usb_device_handle; enum ulink_type type; unsigned int ep_in; /**< IN endpoint number */ unsigned int ep_out; /**< OUT endpoint number */ int delay_scan_in; /**< Delay value for SCAN_IN commands */ int delay_scan_out; /**< Delay value for SCAN_OUT commands */ int delay_scan_io; /**< Delay value for SCAN_IO commands */ int delay_clock_tck; /**< Delay value for CLOCK_TMS commands */ int delay_clock_tms; /**< Delay value for CLOCK_TCK commands */ int commands_in_queue; /**< Number of commands in queue */ struct ulink_cmd *queue_start; /**< Pointer to first command in queue */ struct ulink_cmd *queue_end; /**< Pointer to last command in queue */ }; /**************************** Function Prototypes *****************************/ /* USB helper functions */ static int ulink_usb_open(struct ulink **device); static int ulink_usb_close(struct ulink **device); /* ULINK MCU (Cypress EZ-USB) specific functions */ static int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit); static int ulink_load_firmware_and_renumerate(struct ulink **device, const char *filename, uint32_t delay); static int ulink_load_firmware(struct ulink *device, const char *filename); static int ulink_write_firmware_section(struct ulink *device, struct image *firmware_image, int section_index); /* Generic helper functions */ static void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals); /* OpenULINK command generation helper functions */ static int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, enum ulink_payload_direction direction); /* OpenULINK command queue helper functions */ static int ulink_get_queue_size(struct ulink *device, enum ulink_payload_direction direction); static void ulink_clear_queue(struct ulink *device); static int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd); static int ulink_execute_queued_commands(struct ulink *device, int timeout); static void ulink_print_queue(struct ulink *device); static int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, int scan_size_bits, uint8_t *tdi, uint8_t *tdo_start, uint8_t *tdo, uint8_t tms_count_start, uint8_t tms_sequence_start, uint8_t tms_count_end, uint8_t tms_sequence_end, struct jtag_command *origin, bool postprocess); static int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, uint8_t sequence); static int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count); static int ulink_append_get_signals_cmd(struct ulink *device); static int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, uint8_t high); static int ulink_append_sleep_cmd(struct ulink *device, uint32_t us); static int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in, int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms); static int __attribute__((unused)) ulink_append_led_cmd(struct ulink *device, uint8_t led_state); static int ulink_append_test_cmd(struct ulink *device); /* OpenULINK TCK frequency helper functions */ static int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay); /* Interface between OpenULINK and OpenOCD */ static void ulink_set_end_state(tap_state_t endstate); static int ulink_queue_statemove(struct ulink *device); static int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd); static int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd); static int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd); static int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd); static int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd); static int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd); static int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd); static int ulink_post_process_scan(struct ulink_cmd *ulink_cmd); static int ulink_post_process_queue(struct ulink *device); /* adapter driver functions */ static int ulink_execute_queue(void); static int ulink_khz(int khz, int *jtag_speed); static int ulink_speed(int speed); static int ulink_speed_div(int speed, int *khz); static int ulink_init(void); static int ulink_quit(void); /****************************** Global Variables ******************************/ static struct ulink *ulink_handle; /**************************** USB helper functions ****************************/ /** * Opens the ULINK device * * Currently, only the original ULINK is supported * * @param device pointer to struct ulink identifying ULINK driver instance. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_usb_open(struct ulink **device) { ssize_t num_devices, i; bool found; struct libusb_device **usb_devices; struct libusb_device_descriptor usb_desc; struct libusb_device_handle *usb_device_handle; num_devices = libusb_get_device_list((*device)->libusb_ctx, &usb_devices); if (num_devices <= 0) return ERROR_FAIL; found = false; for (i = 0; i < num_devices; i++) { if (libusb_get_device_descriptor(usb_devices[i], &usb_desc) != 0) continue; else if (usb_desc.idVendor == ULINK_VID && usb_desc.idProduct == ULINK_PID) { found = true; break; } } if (!found) return ERROR_FAIL; if (libusb_open(usb_devices[i], &usb_device_handle) != 0) return ERROR_FAIL; libusb_free_device_list(usb_devices, 1); (*device)->usb_device_handle = usb_device_handle; (*device)->type = ULINK_1; return ERROR_OK; } /** * Releases the ULINK interface and closes the USB device handle. * * @param device pointer to struct ulink identifying ULINK driver instance. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_usb_close(struct ulink **device) { if (libusb_release_interface((*device)->usb_device_handle, 0) != 0) return ERROR_FAIL; libusb_close((*device)->usb_device_handle); (*device)->usb_device_handle = NULL; return ERROR_OK; } /******************* ULINK CPU (EZ-USB) specific functions ********************/ /** * Writes '0' or '1' to the CPUCS register, putting the EZ-USB CPU into reset * or out of reset. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param reset_bit 0 to put CPU into reset, 1 to put CPU out of reset. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit) { int ret; ret = libusb_control_transfer(device->usb_device_handle, (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), REQUEST_FIRMWARE_LOAD, CPUCS_REG, 0, &reset_bit, 1, LIBUSB_TIMEOUT_MS); /* usb_control_msg() returns the number of bytes transferred during the * DATA stage of the control transfer - must be exactly 1 in this case! */ if (ret != 1) return ERROR_FAIL; return ERROR_OK; } /** * Puts the ULINK's EZ-USB microcontroller into reset state, downloads * the firmware image, resumes the microcontroller and re-enumerates * USB devices. * * @param device pointer to struct ulink identifying ULINK driver instance. * The usb_handle member will be modified during re-enumeration. * @param filename path to the Intel HEX file containing the firmware image. * @param delay the delay to wait for the device to re-enumerate. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_load_firmware_and_renumerate(struct ulink **device, const char *filename, uint32_t delay) { int ret; /* Basic process: After downloading the firmware, the ULINK will disconnect * itself and re-connect after a short amount of time so we have to close * the handle and re-enumerate USB devices */ ret = ulink_load_firmware(*device, filename); if (ret != ERROR_OK) return ret; ret = ulink_usb_close(device); if (ret != ERROR_OK) return ret; usleep(delay); ret = ulink_usb_open(device); if (ret != ERROR_OK) return ret; return ERROR_OK; } /** * Downloads a firmware image to the ULINK's EZ-USB microcontroller * over the USB bus. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param filename an absolute or relative path to the Intel HEX file * containing the firmware image. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_load_firmware(struct ulink *device, const char *filename) { struct image ulink_firmware_image; int ret; ret = ulink_cpu_reset(device, CPU_RESET); if (ret != ERROR_OK) { LOG_ERROR("Could not halt ULINK CPU"); return ret; } ulink_firmware_image.base_address = 0; ulink_firmware_image.base_address_set = false; ret = image_open(&ulink_firmware_image, filename, "ihex"); if (ret != ERROR_OK) { LOG_ERROR("Could not load firmware image"); return ret; } /* Download all sections in the image to ULINK */ for (unsigned int i = 0; i < ulink_firmware_image.num_sections; i++) { ret = ulink_write_firmware_section(device, &ulink_firmware_image, i); if (ret != ERROR_OK) return ret; } image_close(&ulink_firmware_image); ret = ulink_cpu_reset(device, CPU_START); if (ret != ERROR_OK) { LOG_ERROR("Could not restart ULINK CPU"); return ret; } return ERROR_OK; } /** * Send one contiguous firmware section to the ULINK's EZ-USB microcontroller * over the USB bus. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param firmware_image pointer to the firmware image that contains the section * which should be sent to the ULINK's EZ-USB microcontroller. * @param section_index index of the section within the firmware image. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_write_firmware_section(struct ulink *device, struct image *firmware_image, int section_index) { uint16_t addr, size, bytes_remaining, chunk_size; uint8_t data[SECTION_BUFFERSIZE]; uint8_t *data_ptr = data; size_t size_read; int ret; size = (uint16_t)firmware_image->sections[section_index].size; addr = (uint16_t)firmware_image->sections[section_index].base_address; LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04x)", section_index, addr, size); /* Copy section contents to local buffer */ ret = image_read_section(firmware_image, section_index, 0, size, data, &size_read); if ((ret != ERROR_OK) || (size_read != size)) { /* Propagating the return code would return '0' (misleadingly indicating * successful execution of the function) if only the size check fails. */ return ERROR_FAIL; } bytes_remaining = size; /* Send section data in chunks of up to 64 bytes to ULINK */ while (bytes_remaining > 0) { if (bytes_remaining > 64) chunk_size = 64; else chunk_size = bytes_remaining; ret = libusb_control_transfer(device->usb_device_handle, (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), REQUEST_FIRMWARE_LOAD, addr, FIRMWARE_ADDR, (unsigned char *)data_ptr, chunk_size, LIBUSB_TIMEOUT_MS); if (ret != (int)chunk_size) { /* Abort if libusb sent less data than requested */ return ERROR_FAIL; } bytes_remaining -= chunk_size; addr += chunk_size; data_ptr += chunk_size; } return ERROR_OK; } /************************** Generic helper functions **************************/ /** * Print state of interesting signals via LOG_INFO(). * * @param input_signals input signal states as returned by CMD_GET_SIGNALS * @param output_signals output signal states as returned by CMD_GET_SIGNALS */ static void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals) { LOG_INFO("ULINK signal states: TDI: %i, TDO: %i, TMS: %i, TCK: %i, TRST: %i," " SRST: %i", (output_signals & SIGNAL_TDI ? 1 : 0), (input_signals & SIGNAL_TDO ? 1 : 0), (output_signals & SIGNAL_TMS ? 1 : 0), (output_signals & SIGNAL_TCK ? 1 : 0), (output_signals & SIGNAL_TRST ? 0 : 1), /* Inverted by hardware */ (output_signals & SIGNAL_RESET ? 0 : 1)); /* Inverted by hardware */ } /**************** OpenULINK command generation helper functions ***************/ /** * Allocate and initialize space in memory for OpenULINK command payload. * * @param ulink_cmd pointer to command whose payload should be allocated. * @param size the amount of memory to allocate (bytes). * @param direction which payload to allocate. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, enum ulink_payload_direction direction) { uint8_t *payload; payload = calloc(size, sizeof(uint8_t)); if (!payload) { LOG_ERROR("Could not allocate OpenULINK command payload: out of memory"); return ERROR_FAIL; } switch (direction) { case PAYLOAD_DIRECTION_OUT: if (ulink_cmd->payload_out) { LOG_ERROR("BUG: Duplicate payload allocation for OpenULINK command"); free(payload); return ERROR_FAIL; } else { ulink_cmd->payload_out = payload; ulink_cmd->payload_out_size = size; } break; case PAYLOAD_DIRECTION_IN: if (ulink_cmd->payload_in_start) { LOG_ERROR("BUG: Duplicate payload allocation for OpenULINK command"); free(payload); return ERROR_FAIL; } else { ulink_cmd->payload_in_start = payload; ulink_cmd->payload_in = payload; ulink_cmd->payload_in_size = size; /* By default, free payload_in_start in ulink_clear_queue(). Commands * that do not want this behavior (e. g. split scans) must turn it off * separately! */ ulink_cmd->free_payload_in_start = true; } break; } return ERROR_OK; } /****************** OpenULINK command queue helper functions ******************/ /** * Get the current number of bytes in the queue, including command IDs. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param direction the transfer direction for which to get byte count. * @return the number of bytes currently stored in the queue for the specified * direction. */ static int ulink_get_queue_size(struct ulink *device, enum ulink_payload_direction direction) { struct ulink_cmd *current = device->queue_start; int sum = 0; while (current) { switch (direction) { case PAYLOAD_DIRECTION_OUT: sum += current->payload_out_size + 1; /* + 1 byte for Command ID */ break; case PAYLOAD_DIRECTION_IN: sum += current->payload_in_size; break; } current = current->next; } return sum; } /** * Clear the OpenULINK command queue. * * @param device pointer to struct ulink identifying ULINK driver instance. */ static void ulink_clear_queue(struct ulink *device) { struct ulink_cmd *current = device->queue_start; struct ulink_cmd *next = NULL; while (current) { /* Save pointer to next element */ next = current->next; /* Free payloads: OUT payload can be freed immediately */ free(current->payload_out); current->payload_out = NULL; /* IN payload MUST be freed ONLY if no other commands use the * payload_in_start buffer */ if (current->free_payload_in_start == true) { free(current->payload_in_start); current->payload_in_start = NULL; current->payload_in = NULL; } /* Free queue element */ free(current); /* Proceed with next element */ current = next; } device->commands_in_queue = 0; device->queue_start = NULL; device->queue_end = NULL; } /** * Add a command to the OpenULINK command queue. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param ulink_cmd pointer to command that shall be appended to the OpenULINK * command queue. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) { int newsize_out, newsize_in; int ret = ERROR_OK; newsize_out = ulink_get_queue_size(device, PAYLOAD_DIRECTION_OUT) + 1 + ulink_cmd->payload_out_size; newsize_in = ulink_get_queue_size(device, PAYLOAD_DIRECTION_IN) + ulink_cmd->payload_in_size; /* Check if the current command can be appended to the queue */ if ((newsize_out > 64) || (newsize_in > 64)) { /* New command does not fit. Execute all commands in queue before starting * new queue with the current command as first entry. */ ret = ulink_execute_queued_commands(device, LIBUSB_TIMEOUT_MS); if (ret == ERROR_OK) ret = ulink_post_process_queue(device); if (ret == ERROR_OK) ulink_clear_queue(device); } if (!device->queue_start) { /* Queue was empty */ device->commands_in_queue = 1; device->queue_start = ulink_cmd; device->queue_end = ulink_cmd; } else { /* There are already commands in the queue */ device->commands_in_queue++; device->queue_end->next = ulink_cmd; device->queue_end = ulink_cmd; } if (ret != ERROR_OK) ulink_clear_queue(device); return ret; } /** * Sends all queued OpenULINK commands to the ULINK for execution. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param timeout * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_execute_queued_commands(struct ulink *device, int timeout) { struct ulink_cmd *current; int ret, i, index_out, index_in, count_out, count_in, transferred; uint8_t buffer[64]; if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) ulink_print_queue(device); index_out = 0; count_out = 0; count_in = 0; for (current = device->queue_start; current; current = current->next) { /* Add command to packet */ buffer[index_out] = current->id; index_out++; count_out++; for (i = 0; i < current->payload_out_size; i++) buffer[index_out + i] = current->payload_out[i]; index_out += current->payload_out_size; count_in += current->payload_in_size; count_out += current->payload_out_size; } /* Send packet to ULINK */ ret = libusb_bulk_transfer(device->usb_device_handle, device->ep_out, (unsigned char *)buffer, count_out, &transferred, timeout); if (ret != 0) return ERROR_FAIL; if (transferred != count_out) return ERROR_FAIL; /* Wait for response if commands contain IN payload data */ if (count_in > 0) { ret = libusb_bulk_transfer(device->usb_device_handle, device->ep_in, (unsigned char *)buffer, 64, &transferred, timeout); if (ret != 0) return ERROR_FAIL; if (transferred != count_in) return ERROR_FAIL; /* Write back IN payload data */ index_in = 0; for (current = device->queue_start; current; current = current->next) { for (i = 0; i < current->payload_in_size; i++) { current->payload_in[i] = buffer[index_in]; index_in++; } } } return ERROR_OK; } /** * Convert an OpenULINK command ID (\a id) to a human-readable string. * * @param id the OpenULINK command ID. * @return the corresponding human-readable string. */ static const char *ulink_cmd_id_string(uint8_t id) { switch (id) { case CMD_SCAN_IN: return "CMD_SCAN_IN"; case CMD_SLOW_SCAN_IN: return "CMD_SLOW_SCAN_IN"; case CMD_SCAN_OUT: return "CMD_SCAN_OUT"; case CMD_SLOW_SCAN_OUT: return "CMD_SLOW_SCAN_OUT"; case CMD_SCAN_IO: return "CMD_SCAN_IO"; case CMD_SLOW_SCAN_IO: return "CMD_SLOW_SCAN_IO"; case CMD_CLOCK_TMS: return "CMD_CLOCK_TMS"; case CMD_SLOW_CLOCK_TMS: return "CMD_SLOW_CLOCK_TMS"; case CMD_CLOCK_TCK: return "CMD_CLOCK_TCK"; case CMD_SLOW_CLOCK_TCK: return "CMD_SLOW_CLOCK_TCK"; case CMD_SLEEP_US: return "CMD_SLEEP_US"; case CMD_SLEEP_MS: return "CMD_SLEEP_MS"; case CMD_GET_SIGNALS: return "CMD_GET_SIGNALS"; case CMD_SET_SIGNALS: return "CMD_SET_SIGNALS"; case CMD_CONFIGURE_TCK_FREQ: return "CMD_CONFIGURE_TCK_FREQ"; case CMD_SET_LEDS: return "CMD_SET_LEDS"; case CMD_TEST: return "CMD_TEST"; default: return "CMD_UNKNOWN"; } } /** * Print one OpenULINK command to stdout. * * @param ulink_cmd pointer to OpenULINK command. */ static void ulink_print_command(struct ulink_cmd *ulink_cmd) { int i; printf(" %-22s | OUT size = %i, bytes = 0x", ulink_cmd_id_string(ulink_cmd->id), ulink_cmd->payload_out_size); for (i = 0; i < ulink_cmd->payload_out_size; i++) printf("%02X ", ulink_cmd->payload_out[i]); printf("\n | IN size = %i\n", ulink_cmd->payload_in_size); } /** * Print the OpenULINK command queue to stdout. * * @param device pointer to struct ulink identifying ULINK driver instance. */ static void ulink_print_queue(struct ulink *device) { struct ulink_cmd *current; printf("OpenULINK command queue:\n"); for (current = device->queue_start; current; current = current->next) ulink_print_command(current); } /** * Perform JTAG scan * * Creates and appends a JTAG scan command to the OpenULINK command queue. * A JTAG scan consists of three steps: * - Move to the desired SHIFT state, depending on scan type (IR/DR scan). * - Shift TDI data into the JTAG chain, optionally reading the TDO pin. * - Move to the desired end state. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param scan_type the type of the scan (IN, OUT, IO (bidirectional)). * @param scan_size_bits number of bits to shift into the JTAG chain. * @param tdi pointer to array containing TDI data. * @param tdo_start pointer to first element of array where TDO data shall be * stored. See #ulink_cmd for details. * @param tdo pointer to array where TDO data shall be stored * @param tms_count_start number of TMS state transitions to perform BEFORE * shifting data into the JTAG chain. * @param tms_sequence_start sequence of TMS state transitions that will be * performed BEFORE shifting data into the JTAG chain. * @param tms_count_end number of TMS state transitions to perform AFTER * shifting data into the JTAG chain. * @param tms_sequence_end sequence of TMS state transitions that will be * performed AFTER shifting data into the JTAG chain. * @param origin pointer to OpenOCD command that generated this scan command. * @param postprocess whether this command needs to be post-processed after * execution. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, int scan_size_bits, uint8_t *tdi, uint8_t *tdo_start, uint8_t *tdo, uint8_t tms_count_start, uint8_t tms_sequence_start, uint8_t tms_count_end, uint8_t tms_sequence_end, struct jtag_command *origin, bool postprocess) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret, i, scan_size_bytes; uint8_t bits_last_byte; if (!cmd) return ERROR_FAIL; /* Check size of command. USB buffer can hold 64 bytes, 1 byte is command ID, * 5 bytes are setup data -> 58 remaining payload bytes for TDI data */ if (scan_size_bits > (58 * 8)) { LOG_ERROR("BUG: Tried to create CMD_SCAN_IO OpenULINK command with too" " large payload"); free(cmd); return ERROR_FAIL; } scan_size_bytes = DIV_ROUND_UP(scan_size_bits, 8); bits_last_byte = scan_size_bits % 8; if (bits_last_byte == 0) bits_last_byte = 8; /* Allocate out_payload depending on scan type */ switch (scan_type) { case SCAN_IN: if (device->delay_scan_in < 0) cmd->id = CMD_SCAN_IN; else cmd->id = CMD_SLOW_SCAN_IN; ret = ulink_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_OUT); break; case SCAN_OUT: if (device->delay_scan_out < 0) cmd->id = CMD_SCAN_OUT; else cmd->id = CMD_SLOW_SCAN_OUT; ret = ulink_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); break; case SCAN_IO: if (device->delay_scan_io < 0) cmd->id = CMD_SCAN_IO; else cmd->id = CMD_SLOW_SCAN_IO; ret = ulink_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); break; default: LOG_ERROR("BUG: ulink_append_scan_cmd() encountered an unknown scan type"); ret = ERROR_FAIL; break; } if (ret != ERROR_OK) { free(cmd); return ret; } /* Build payload_out that is common to all scan types */ cmd->payload_out[0] = scan_size_bytes & 0xFF; cmd->payload_out[1] = bits_last_byte & 0xFF; cmd->payload_out[2] = ((tms_count_start & 0x0F) << 4) | (tms_count_end & 0x0F); cmd->payload_out[3] = tms_sequence_start; cmd->payload_out[4] = tms_sequence_end; /* Setup payload_out for types with OUT transfer */ if ((scan_type == SCAN_OUT) || (scan_type == SCAN_IO)) { for (i = 0; i < scan_size_bytes; i++) cmd->payload_out[i + 5] = tdi[i]; } /* Setup payload_in pointers for types with IN transfer */ if ((scan_type == SCAN_IN) || (scan_type == SCAN_IO)) { cmd->payload_in_start = tdo_start; cmd->payload_in = tdo; cmd->payload_in_size = scan_size_bytes; } cmd->needs_postprocessing = postprocess; cmd->cmd_origin = origin; /* For scan commands, we free payload_in_start only when the command is * the last in a series of split commands or a stand-alone command */ cmd->free_payload_in_start = postprocess; return ulink_append_queue(device, cmd); } /** * Perform TAP state transitions * * @param device pointer to struct ulink identifying ULINK driver instance. * @param count defines the number of TCK clock cycles generated (up to 8). * @param sequence defines the TMS pin levels for each state transition. The * Least-Significant Bit is read first. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, uint8_t sequence) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (!cmd) return ERROR_FAIL; if (device->delay_clock_tms < 0) cmd->id = CMD_CLOCK_TMS; else cmd->id = CMD_SLOW_CLOCK_TMS; /* CMD_CLOCK_TMS has two OUT payload bytes and zero IN payload bytes */ ret = ulink_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); if (ret != ERROR_OK) { free(cmd); return ret; } cmd->payload_out[0] = count; cmd->payload_out[1] = sequence; return ulink_append_queue(device, cmd); } /** * Generate a defined amount of TCK clock cycles * * All other JTAG signals are left unchanged. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param count the number of TCK clock cycles to generate. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (!cmd) return ERROR_FAIL; if (device->delay_clock_tck < 0) cmd->id = CMD_CLOCK_TCK; else cmd->id = CMD_SLOW_CLOCK_TCK; /* CMD_CLOCK_TCK has two OUT payload bytes and zero IN payload bytes */ ret = ulink_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); if (ret != ERROR_OK) { free(cmd); return ret; } cmd->payload_out[0] = count & 0xff; cmd->payload_out[1] = (count >> 8) & 0xff; return ulink_append_queue(device, cmd); } /** * Read JTAG signals. * * @param device pointer to struct ulink identifying ULINK driver instance. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_append_get_signals_cmd(struct ulink *device) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (!cmd) return ERROR_FAIL; cmd->id = CMD_GET_SIGNALS; cmd->needs_postprocessing = true; /* CMD_GET_SIGNALS has two IN payload bytes */ ret = ulink_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_IN); if (ret != ERROR_OK) { free(cmd); return ret; } return ulink_append_queue(device, cmd); } /** * Arbitrarily set JTAG output signals. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param low defines which signals will be de-asserted. Each bit corresponds * to a JTAG signal: * - SIGNAL_TDI * - SIGNAL_TMS * - SIGNAL_TCK * - SIGNAL_TRST * - SIGNAL_BRKIN * - SIGNAL_RESET * - SIGNAL_OCDSE * @param high defines which signals will be asserted. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, uint8_t high) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (!cmd) return ERROR_FAIL; cmd->id = CMD_SET_SIGNALS; /* CMD_SET_SIGNALS has two OUT payload bytes and zero IN payload bytes */ ret = ulink_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); if (ret != ERROR_OK) { free(cmd); return ret; } cmd->payload_out[0] = low; cmd->payload_out[1] = high; return ulink_append_queue(device, cmd); } /** * Sleep for a pre-defined number of microseconds * * @param device pointer to struct ulink identifying ULINK driver instance. * @param us the number microseconds to sleep. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_append_sleep_cmd(struct ulink *device, uint32_t us) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (!cmd) return ERROR_FAIL; cmd->id = CMD_SLEEP_US; /* CMD_SLEEP_US has two OUT payload bytes and zero IN payload bytes */ ret = ulink_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); if (ret != ERROR_OK) { free(cmd); return ret; } cmd->payload_out[0] = us & 0x00ff; cmd->payload_out[1] = (us >> 8) & 0x00ff; return ulink_append_queue(device, cmd); } /** * Set TCK delay counters * * @param device pointer to struct ulink identifying ULINK driver instance. * @param delay_scan_in delay count top value in jtag_slow_scan_in() function. * @param delay_scan_out delay count top value in jtag_slow_scan_out() function. * @param delay_scan_io delay count top value in jtag_slow_scan_io() function. * @param delay_tck delay count top value in jtag_clock_tck() function. * @param delay_tms delay count top value in jtag_slow_clock_tms() function. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in, int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (!cmd) return ERROR_FAIL; cmd->id = CMD_CONFIGURE_TCK_FREQ; /* CMD_CONFIGURE_TCK_FREQ has five OUT payload bytes and zero * IN payload bytes */ ret = ulink_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_OUT); if (ret != ERROR_OK) { free(cmd); return ret; } if (delay_scan_in < 0) cmd->payload_out[0] = 0; else cmd->payload_out[0] = (uint8_t)delay_scan_in; if (delay_scan_out < 0) cmd->payload_out[1] = 0; else cmd->payload_out[1] = (uint8_t)delay_scan_out; if (delay_scan_io < 0) cmd->payload_out[2] = 0; else cmd->payload_out[2] = (uint8_t)delay_scan_io; if (delay_tck < 0) cmd->payload_out[3] = 0; else cmd->payload_out[3] = (uint8_t)delay_tck; if (delay_tms < 0) cmd->payload_out[4] = 0; else cmd->payload_out[4] = (uint8_t)delay_tms; return ulink_append_queue(device, cmd); } /** * Turn on/off ULINK LEDs. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param led_state which LED(s) to turn on or off. The following bits * influence the LEDS: * - Bit 0: Turn COM LED on * - Bit 1: Turn RUN LED on * - Bit 2: Turn COM LED off * - Bit 3: Turn RUN LED off * If both the on-bit and the off-bit for the same LED is set, the LED is * turned off. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_append_led_cmd(struct ulink *device, uint8_t led_state) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (!cmd) return ERROR_FAIL; cmd->id = CMD_SET_LEDS; /* CMD_SET_LEDS has one OUT payload byte and zero IN payload bytes */ ret = ulink_allocate_payload(cmd, 1, PAYLOAD_DIRECTION_OUT); if (ret != ERROR_OK) { free(cmd); return ret; } cmd->payload_out[0] = led_state; return ulink_append_queue(device, cmd); } /** * Test command. Used to check if the ULINK device is ready to accept new * commands. * * @param device pointer to struct ulink identifying ULINK driver instance. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_append_test_cmd(struct ulink *device) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (!cmd) return ERROR_FAIL; cmd->id = CMD_TEST; /* CMD_TEST has one OUT payload byte and zero IN payload bytes */ ret = ulink_allocate_payload(cmd, 1, PAYLOAD_DIRECTION_OUT); if (ret != ERROR_OK) { free(cmd); return ret; } cmd->payload_out[0] = 0xAA; return ulink_append_queue(device, cmd); } /****************** OpenULINK TCK frequency helper functions ******************/ /** * Calculate delay values for a given TCK frequency. * * The OpenULINK firmware uses five different speed values for different * commands. These speed values are calculated in these functions. * * The five different commands which support variable TCK frequency are * implemented twice in the firmware: * 1. Maximum possible frequency without any artificial delay * 2. Variable frequency with artificial linear delay loop * * To set the ULINK to maximum frequency, it is only necessary to use the * corresponding command IDs. To set the ULINK to a lower frequency, the * delay loop top values have to be calculated first. Then, a * CMD_CONFIGURE_TCK_FREQ command needs to be sent to the ULINK device. * * The delay values are described by linear equations: * t = k * x + d * (t = period, k = constant, x = delay value, d = constant) * * Thus, the delay can be calculated as in the following equation: * x = (t - d) / k * * The constants in these equations have been determined and validated by * measuring the frequency resulting from different delay values. * * @param type for which command to calculate the delay value. * @param f TCK frequency for which to calculate the delay value in Hz. * @param delay where to store resulting delay value. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay) { float t, x, x_ceil; /* Calculate period of requested TCK frequency */ t = 1.0 / (float)(f); switch (type) { case DELAY_CLOCK_TCK: x = (t - (float)(6E-6)) / (float)(4E-6); break; case DELAY_CLOCK_TMS: x = (t - (float)(8.5E-6)) / (float)(4E-6); break; case DELAY_SCAN_IN: x = (t - (float)(8.8308E-6)) / (float)(4E-6); break; case DELAY_SCAN_OUT: x = (t - (float)(1.0527E-5)) / (float)(4E-6); break; case DELAY_SCAN_IO: x = (t - (float)(1.3132E-5)) / (float)(4E-6); break; default: return ERROR_FAIL; break; } /* Check if the delay value is negative. This happens when a frequency is * requested that is too high for the delay loop implementation. In this * case, set delay value to zero. */ if (x < 0) x = 0; /* We need to convert the exact delay value to an integer. Therefore, we * round the exact value UP to ensure that the resulting frequency is NOT * higher than the requested frequency. */ x_ceil = ceilf(x); /* Check if the value is within limits */ if (x_ceil > 255) return ERROR_FAIL; *delay = (int)x_ceil; return ERROR_OK; } /** * Calculate frequency for a given delay value. * * Similar to the #ulink_calculate_delay function, this function calculates the * TCK frequency for a given delay value by using linear equations of the form: * t = k * x + d * (t = period, k = constant, x = delay value, d = constant) * * @param type for which command to calculate the delay value. * @param delay delay value for which to calculate the resulting TCK frequency. * @return the resulting TCK frequency */ static long ulink_calculate_frequency(enum ulink_delay_type type, int delay) { float t, f_float; if (delay > 255) return 0; switch (type) { case DELAY_CLOCK_TCK: if (delay < 0) t = (float)(2.666E-6); else t = (float)(4E-6) * (float)(delay) + (float)(6E-6); break; case DELAY_CLOCK_TMS: if (delay < 0) t = (float)(5.666E-6); else t = (float)(4E-6) * (float)(delay) + (float)(8.5E-6); break; case DELAY_SCAN_IN: if (delay < 0) t = (float)(5.5E-6); else t = (float)(4E-6) * (float)(delay) + (float)(8.8308E-6); break; case DELAY_SCAN_OUT: if (delay < 0) t = (float)(7.0E-6); else t = (float)(4E-6) * (float)(delay) + (float)(1.0527E-5); break; case DELAY_SCAN_IO: if (delay < 0) t = (float)(9.926E-6); else t = (float)(4E-6) * (float)(delay) + (float)(1.3132E-5); break; default: return 0; } f_float = 1.0 / t; return roundf(f_float); } /******************* Interface between OpenULINK and OpenOCD ******************/ /** * Sets the end state follower (see interface.h) if \a endstate is a stable * state. * * @param endstate the state the end state follower should be set to. */ static void ulink_set_end_state(tap_state_t endstate) { if (tap_is_state_stable(endstate)) tap_set_end_state(endstate); else { LOG_ERROR("BUG: %s is not a valid end state", tap_state_name(endstate)); exit(EXIT_FAILURE); } } /** * Move from the current TAP state to the current TAP end state. * * @param device pointer to struct ulink identifying ULINK driver instance. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_queue_statemove(struct ulink *device) { uint8_t tms_sequence, tms_count; int ret; if (tap_get_state() == tap_get_end_state()) { /* Do nothing if we are already there */ return ERROR_OK; } tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); ret = ulink_append_clock_tms_cmd(device, tms_count, tms_sequence); if (ret == ERROR_OK) tap_set_state(tap_get_end_state()); return ret; } /** * Perform a scan operation on a JTAG register. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param cmd pointer to the command that shall be executed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd) { uint32_t scan_size_bits, scan_size_bytes, bits_last_scan; uint32_t scans_max_payload, bytecount; uint8_t *tdi_buffer_start = NULL, *tdi_buffer = NULL; uint8_t *tdo_buffer_start = NULL, *tdo_buffer = NULL; uint8_t first_tms_count, first_tms_sequence; uint8_t last_tms_count, last_tms_sequence; uint8_t tms_count_pause, tms_sequence_pause; uint8_t tms_count_resume, tms_sequence_resume; uint8_t tms_count_start, tms_sequence_start; uint8_t tms_count_end, tms_sequence_end; enum scan_type type; int ret; /* Determine scan size */ scan_size_bits = jtag_scan_size(cmd->cmd.scan); scan_size_bytes = DIV_ROUND_UP(scan_size_bits, 8); /* Determine scan type (IN/OUT/IO) */ type = jtag_scan_type(cmd->cmd.scan); /* Determine number of scan commands with maximum payload */ scans_max_payload = scan_size_bytes / 58; /* Determine size of last shift command */ bits_last_scan = scan_size_bits - (scans_max_payload * 58 * 8); /* Allocate TDO buffer if required */ if ((type == SCAN_IN) || (type == SCAN_IO)) { tdo_buffer_start = calloc(sizeof(uint8_t), scan_size_bytes); if (!tdo_buffer_start) return ERROR_FAIL; tdo_buffer = tdo_buffer_start; } /* Fill TDI buffer if required */ if ((type == SCAN_OUT) || (type == SCAN_IO)) { jtag_build_buffer(cmd->cmd.scan, &tdi_buffer_start); tdi_buffer = tdi_buffer_start; } /* Get TAP state transitions */ if (cmd->cmd.scan->ir_scan) { ulink_set_end_state(TAP_IRSHIFT); first_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); first_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); tap_set_state(TAP_IRSHIFT); tap_set_end_state(cmd->cmd.scan->end_state); last_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); last_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); /* TAP state transitions for split scans */ tms_count_pause = tap_get_tms_path_len(TAP_IRSHIFT, TAP_IRPAUSE); tms_sequence_pause = tap_get_tms_path(TAP_IRSHIFT, TAP_IRPAUSE); tms_count_resume = tap_get_tms_path_len(TAP_IRPAUSE, TAP_IRSHIFT); tms_sequence_resume = tap_get_tms_path(TAP_IRPAUSE, TAP_IRSHIFT); } else { ulink_set_end_state(TAP_DRSHIFT); first_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); first_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); tap_set_state(TAP_DRSHIFT); tap_set_end_state(cmd->cmd.scan->end_state); last_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); last_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); /* TAP state transitions for split scans */ tms_count_pause = tap_get_tms_path_len(TAP_DRSHIFT, TAP_DRPAUSE); tms_sequence_pause = tap_get_tms_path(TAP_DRSHIFT, TAP_DRPAUSE); tms_count_resume = tap_get_tms_path_len(TAP_DRPAUSE, TAP_DRSHIFT); tms_sequence_resume = tap_get_tms_path(TAP_DRPAUSE, TAP_DRSHIFT); } /* Generate scan commands */ bytecount = scan_size_bytes; while (bytecount > 0) { if (bytecount == scan_size_bytes) { /* This is the first scan */ tms_count_start = first_tms_count; tms_sequence_start = first_tms_sequence; } else { /* Resume from previous scan */ tms_count_start = tms_count_resume; tms_sequence_start = tms_sequence_resume; } if (bytecount > 58) { /* Full scan, at least one scan will follow */ tms_count_end = tms_count_pause; tms_sequence_end = tms_sequence_pause; ret = ulink_append_scan_cmd(device, type, 58 * 8, tdi_buffer, tdo_buffer_start, tdo_buffer, tms_count_start, tms_sequence_start, tms_count_end, tms_sequence_end, cmd, false); bytecount -= 58; /* Update TDI and TDO buffer pointers */ if (tdi_buffer_start) tdi_buffer += 58; if (tdo_buffer_start) tdo_buffer += 58; } else if (bytecount == 58) { /* Full scan, no further scans */ tms_count_end = last_tms_count; tms_sequence_end = last_tms_sequence; ret = ulink_append_scan_cmd(device, type, 58 * 8, tdi_buffer, tdo_buffer_start, tdo_buffer, tms_count_start, tms_sequence_start, tms_count_end, tms_sequence_end, cmd, true); bytecount = 0; } else {/* Scan with less than maximum payload, no further scans */ tms_count_end = last_tms_count; tms_sequence_end = last_tms_sequence; ret = ulink_append_scan_cmd(device, type, bits_last_scan, tdi_buffer, tdo_buffer_start, tdo_buffer, tms_count_start, tms_sequence_start, tms_count_end, tms_sequence_end, cmd, true); bytecount = 0; } if (ret != ERROR_OK) { free(tdi_buffer_start); free(tdo_buffer_start); return ret; } } free(tdi_buffer_start); /* Set current state to the end state requested by the command */ tap_set_state(cmd->cmd.scan->end_state); return ERROR_OK; } /** * Move the TAP into the Test Logic Reset state. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param cmd pointer to the command that shall be executed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd) { int ret; ret = ulink_append_clock_tms_cmd(device, 5, 0xff); if (ret == ERROR_OK) tap_set_state(TAP_RESET); return ret; } /** * Run Test. * * Generate TCK clock cycles while remaining * in the Run-Test/Idle state. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param cmd pointer to the command that shall be executed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd) { int ret; /* Only perform statemove if the TAP currently isn't in the TAP_IDLE state */ if (tap_get_state() != TAP_IDLE) { ulink_set_end_state(TAP_IDLE); ulink_queue_statemove(device); } /* Generate the clock cycles */ ret = ulink_append_clock_tck_cmd(device, cmd->cmd.runtest->num_cycles); if (ret != ERROR_OK) return ret; /* Move to end state specified in command */ if (cmd->cmd.runtest->end_state != tap_get_state()) { tap_set_end_state(cmd->cmd.runtest->end_state); ulink_queue_statemove(device); } return ERROR_OK; } /** * Execute a JTAG_RESET command * * @param device * @param cmd pointer to the command that shall be executed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd) { uint8_t low = 0, high = 0; if (cmd->cmd.reset->trst) { tap_set_state(TAP_RESET); high |= SIGNAL_TRST; } else low |= SIGNAL_TRST; if (cmd->cmd.reset->srst) high |= SIGNAL_RESET; else low |= SIGNAL_RESET; return ulink_append_set_signals_cmd(device, low, high); } /** * Move to one TAP state or several states in succession. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param cmd pointer to the command that shall be executed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd) { int ret, i, num_states, batch_size, state_count; tap_state_t *path; uint8_t tms_sequence; num_states = cmd->cmd.pathmove->num_states; path = cmd->cmd.pathmove->path; state_count = 0; while (num_states > 0) { tms_sequence = 0; /* Determine batch size */ if (num_states >= 8) batch_size = 8; else batch_size = num_states; for (i = 0; i < batch_size; i++) { if (tap_state_transition(tap_get_state(), false) == path[state_count]) { /* Append '0' transition: clear bit 'i' in tms_sequence */ buf_set_u32(&tms_sequence, i, 1, 0x0); } else if (tap_state_transition(tap_get_state(), true) == path[state_count]) { /* Append '1' transition: set bit 'i' in tms_sequence */ buf_set_u32(&tms_sequence, i, 1, 0x1); } else { /* Invalid state transition */ LOG_ERROR("BUG: %s -> %s isn't a valid TAP state transition", tap_state_name(tap_get_state()), tap_state_name(path[state_count])); return ERROR_FAIL; } tap_set_state(path[state_count]); state_count++; num_states--; } /* Append CLOCK_TMS command to OpenULINK command queue */ LOG_INFO( "pathmove batch: count = %i, sequence = 0x%x", batch_size, tms_sequence); ret = ulink_append_clock_tms_cmd(ulink_handle, batch_size, tms_sequence); if (ret != ERROR_OK) return ret; } return ERROR_OK; } /** * Sleep for a specific amount of time. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param cmd pointer to the command that shall be executed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd) { /* IMPORTANT! Due to the time offset in command execution introduced by * command queueing, this needs to be implemented in the ULINK device */ return ulink_append_sleep_cmd(device, cmd->cmd.sleep->us); } /** * Generate TCK cycles while remaining in a stable state. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param cmd pointer to the command that shall be executed. */ static int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd) { int ret; unsigned num_cycles; if (!tap_is_state_stable(tap_get_state())) { LOG_ERROR("JTAG_STABLECLOCKS: state not stable"); return ERROR_FAIL; } num_cycles = cmd->cmd.stableclocks->num_cycles; /* TMS stays either high (Test Logic Reset state) or low (all other states) */ if (tap_get_state() == TAP_RESET) ret = ulink_append_set_signals_cmd(device, 0, SIGNAL_TMS); else ret = ulink_append_set_signals_cmd(device, SIGNAL_TMS, 0); if (ret != ERROR_OK) return ret; while (num_cycles > 0) { if (num_cycles > 0xFFFF) { /* OpenULINK CMD_CLOCK_TCK can generate up to 0xFFFF (uint16_t) cycles */ ret = ulink_append_clock_tck_cmd(device, 0xFFFF); num_cycles -= 0xFFFF; } else { ret = ulink_append_clock_tck_cmd(device, num_cycles); num_cycles = 0; } if (ret != ERROR_OK) return ret; } return ERROR_OK; } /** * Post-process JTAG_SCAN command * * @param ulink_cmd pointer to OpenULINK command that shall be processed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_post_process_scan(struct ulink_cmd *ulink_cmd) { struct jtag_command *cmd = ulink_cmd->cmd_origin; int ret; switch (jtag_scan_type(cmd->cmd.scan)) { case SCAN_IN: case SCAN_IO: ret = jtag_read_buffer(ulink_cmd->payload_in_start, cmd->cmd.scan); break; case SCAN_OUT: /* Nothing to do for OUT scans */ ret = ERROR_OK; break; default: LOG_ERROR("BUG: ulink_post_process_scan() encountered an unknown" " JTAG scan type"); ret = ERROR_FAIL; break; } return ret; } /** * Perform post-processing of commands after OpenULINK queue has been executed. * * @param device pointer to struct ulink identifying ULINK driver instance. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_post_process_queue(struct ulink *device) { struct ulink_cmd *current; struct jtag_command *openocd_cmd; int ret; current = device->queue_start; while (current) { openocd_cmd = current->cmd_origin; /* Check if a corresponding OpenOCD command is stored for this * OpenULINK command */ if ((current->needs_postprocessing == true) && (openocd_cmd)) { switch (openocd_cmd->type) { case JTAG_SCAN: ret = ulink_post_process_scan(current); break; case JTAG_TLR_RESET: case JTAG_RUNTEST: case JTAG_RESET: case JTAG_PATHMOVE: case JTAG_SLEEP: case JTAG_STABLECLOCKS: /* Nothing to do for these commands */ ret = ERROR_OK; break; default: ret = ERROR_FAIL; LOG_ERROR("BUG: ulink_post_process_queue() encountered unknown JTAG " "command type"); break; } if (ret != ERROR_OK) return ret; } current = current->next; } return ERROR_OK; } /**************************** JTAG driver functions ***************************/ /** * Executes the JTAG Command Queue. * * This is done in three stages: First, all OpenOCD commands are processed into * queued OpenULINK commands. Next, the OpenULINK command queue is sent to the * ULINK device and data received from the ULINK device is cached. Finally, * the post-processing function writes back data to the corresponding OpenOCD * commands. * * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; int ret; while (cmd) { switch (cmd->type) { case JTAG_SCAN: ret = ulink_queue_scan(ulink_handle, cmd); break; case JTAG_TLR_RESET: ret = ulink_queue_tlr_reset(ulink_handle, cmd); break; case JTAG_RUNTEST: ret = ulink_queue_runtest(ulink_handle, cmd); break; case JTAG_RESET: ret = ulink_queue_reset(ulink_handle, cmd); break; case JTAG_PATHMOVE: ret = ulink_queue_pathmove(ulink_handle, cmd); break; case JTAG_SLEEP: ret = ulink_queue_sleep(ulink_handle, cmd); break; case JTAG_STABLECLOCKS: ret = ulink_queue_stableclocks(ulink_handle, cmd); break; default: ret = ERROR_FAIL; LOG_ERROR("BUG: encountered unknown JTAG command type"); break; } if (ret != ERROR_OK) return ret; cmd = cmd->next; } if (ulink_handle->commands_in_queue > 0) { ret = ulink_execute_queued_commands(ulink_handle, LIBUSB_TIMEOUT_MS); if (ret != ERROR_OK) return ret; ret = ulink_post_process_queue(ulink_handle); if (ret != ERROR_OK) return ret; ulink_clear_queue(ulink_handle); } return ERROR_OK; } /** * Set the TCK frequency of the ULINK adapter. * * @param khz desired JTAG TCK frequency. * @param jtag_speed where to store corresponding adapter-specific speed value. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_khz(int khz, int *jtag_speed) { int ret; if (khz == 0) { LOG_ERROR("RCLK not supported"); return ERROR_FAIL; } /* CLOCK_TCK commands are decoupled from others. Therefore, the frequency * setting can be done independently from all other commands. */ if (khz >= 375) ulink_handle->delay_clock_tck = -1; else { ret = ulink_calculate_delay(DELAY_CLOCK_TCK, khz * 1000, &ulink_handle->delay_clock_tck); if (ret != ERROR_OK) return ret; } /* SCAN_{IN,OUT,IO} commands invoke CLOCK_TMS commands. Therefore, if the * requested frequency goes below the maximum frequency for SLOW_CLOCK_TMS * commands, all SCAN commands MUST also use the variable frequency * implementation! */ if (khz >= 176) { ulink_handle->delay_clock_tms = -1; ulink_handle->delay_scan_in = -1; ulink_handle->delay_scan_out = -1; ulink_handle->delay_scan_io = -1; } else { ret = ulink_calculate_delay(DELAY_CLOCK_TMS, khz * 1000, &ulink_handle->delay_clock_tms); if (ret != ERROR_OK) return ret; ret = ulink_calculate_delay(DELAY_SCAN_IN, khz * 1000, &ulink_handle->delay_scan_in); if (ret != ERROR_OK) return ret; ret = ulink_calculate_delay(DELAY_SCAN_OUT, khz * 1000, &ulink_handle->delay_scan_out); if (ret != ERROR_OK) return ret; ret = ulink_calculate_delay(DELAY_SCAN_IO, khz * 1000, &ulink_handle->delay_scan_io); if (ret != ERROR_OK) return ret; } LOG_DEBUG_IO("ULINK TCK setup: delay_tck = %i (%li Hz),", ulink_handle->delay_clock_tck, ulink_calculate_frequency(DELAY_CLOCK_TCK, ulink_handle->delay_clock_tck)); LOG_DEBUG_IO(" delay_tms = %i (%li Hz),", ulink_handle->delay_clock_tms, ulink_calculate_frequency(DELAY_CLOCK_TMS, ulink_handle->delay_clock_tms)); LOG_DEBUG_IO(" delay_scan_in = %i (%li Hz),", ulink_handle->delay_scan_in, ulink_calculate_frequency(DELAY_SCAN_IN, ulink_handle->delay_scan_in)); LOG_DEBUG_IO(" delay_scan_out = %i (%li Hz),", ulink_handle->delay_scan_out, ulink_calculate_frequency(DELAY_SCAN_OUT, ulink_handle->delay_scan_out)); LOG_DEBUG_IO(" delay_scan_io = %i (%li Hz),", ulink_handle->delay_scan_io, ulink_calculate_frequency(DELAY_SCAN_IO, ulink_handle->delay_scan_io)); /* Configure the ULINK device with the new delay values */ ret = ulink_append_configure_tck_cmd(ulink_handle, ulink_handle->delay_scan_in, ulink_handle->delay_scan_out, ulink_handle->delay_scan_io, ulink_handle->delay_clock_tck, ulink_handle->delay_clock_tms); if (ret != ERROR_OK) return ret; *jtag_speed = khz; return ERROR_OK; } /** * Set the TCK frequency of the ULINK adapter. * * Because of the way the TCK frequency is set up in the OpenULINK firmware, * there are five different speed settings. To simplify things, the * adapter-specific speed setting value is identical to the TCK frequency in * khz. * * @param speed desired adapter-specific speed value. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_speed(int speed) { int dummy; return ulink_khz(speed, &dummy); } /** * Convert adapter-specific speed value to corresponding TCK frequency in kHz. * * Because of the way the TCK frequency is set up in the OpenULINK firmware, * there are five different speed settings. To simplify things, the * adapter-specific speed setting value is identical to the TCK frequency in * khz. * * @param speed adapter-specific speed value. * @param khz where to store corresponding TCK frequency in kHz. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_speed_div(int speed, int *khz) { *khz = speed; return ERROR_OK; } /** * Initiates the firmware download to the ULINK adapter and prepares * the USB handle. * * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_init(void) { int ret, transferred; char str_manufacturer[20]; bool download_firmware = false; unsigned char *dummy; uint8_t input_signals, output_signals; ulink_handle = calloc(1, sizeof(struct ulink)); if (!ulink_handle) return ERROR_FAIL; libusb_init(&ulink_handle->libusb_ctx); ret = ulink_usb_open(&ulink_handle); if (ret != ERROR_OK) { LOG_ERROR("Could not open ULINK device"); free(ulink_handle); ulink_handle = NULL; return ret; } /* Get String Descriptor to determine if firmware needs to be loaded */ ret = libusb_get_string_descriptor_ascii(ulink_handle->usb_device_handle, 1, (unsigned char *)str_manufacturer, 20); if (ret < 0) { /* Could not get descriptor -> Unconfigured or original Keil firmware */ download_firmware = true; } else { /* We got a String Descriptor, check if it is the correct one */ if (strncmp(str_manufacturer, "OpenULINK", 9) != 0) download_firmware = true; } if (download_firmware == true) { LOG_INFO("Loading OpenULINK firmware. This is reversible by power-cycling" " ULINK device."); ret = ulink_load_firmware_and_renumerate(&ulink_handle, ULINK_FIRMWARE_FILE, ULINK_RENUMERATION_DELAY); if (ret != ERROR_OK) { LOG_ERROR("Could not download firmware and re-numerate ULINK"); free(ulink_handle); ulink_handle = NULL; return ret; } } else LOG_INFO("ULINK device is already running OpenULINK firmware"); /* Get OpenULINK USB IN/OUT endpoints and claim the interface */ ret = jtag_libusb_choose_interface(ulink_handle->usb_device_handle, &ulink_handle->ep_in, &ulink_handle->ep_out, -1, -1, -1, -1); if (ret != ERROR_OK) return ret; /* Initialize OpenULINK command queue */ ulink_clear_queue(ulink_handle); /* Issue one test command with short timeout */ ret = ulink_append_test_cmd(ulink_handle); if (ret != ERROR_OK) return ret; ret = ulink_execute_queued_commands(ulink_handle, 200); if (ret != ERROR_OK) { /* Sending test command failed. The ULINK device may be forever waiting for * the host to fetch an USB Bulk IN packet (e. g. OpenOCD crashed or was * shut down by the user via Ctrl-C. Try to retrieve this Bulk IN packet. */ dummy = calloc(64, sizeof(uint8_t)); ret = libusb_bulk_transfer(ulink_handle->usb_device_handle, ulink_handle->ep_in, dummy, 64, &transferred, 200); free(dummy); if (ret != 0 || transferred == 0) { /* Bulk IN transfer failed -> unrecoverable error condition */ LOG_ERROR("Cannot communicate with ULINK device. Disconnect ULINK from " "the USB port and re-connect, then re-run OpenOCD"); free(ulink_handle); ulink_handle = NULL; return ERROR_FAIL; } #ifdef _DEBUG_USB_COMMS_ else { /* Successfully received Bulk IN packet -> continue */ LOG_INFO("Recovered from lost Bulk IN packet"); } #endif } ulink_clear_queue(ulink_handle); ret = ulink_append_get_signals_cmd(ulink_handle); if (ret == ERROR_OK) ret = ulink_execute_queued_commands(ulink_handle, 200); if (ret == ERROR_OK) { /* Post-process the single CMD_GET_SIGNALS command */ input_signals = ulink_handle->queue_start->payload_in[0]; output_signals = ulink_handle->queue_start->payload_in[1]; ulink_print_signal_states(input_signals, output_signals); } ulink_clear_queue(ulink_handle); return ERROR_OK; } /** * Closes the USB handle for the ULINK device. * * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_quit(void) { int ret; ret = ulink_usb_close(&ulink_handle); free(ulink_handle); return ret; } /** * Set a custom path to ULINK firmware image and force downloading to ULINK. */ COMMAND_HANDLER(ulink_download_firmware_handler) { int ret; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; LOG_INFO("Downloading ULINK firmware image %s", CMD_ARGV[0]); /* Download firmware image in CMD_ARGV[0] */ ret = ulink_load_firmware_and_renumerate(&ulink_handle, CMD_ARGV[0], ULINK_RENUMERATION_DELAY); return ret; } /*************************** Command Registration **************************/ static const struct command_registration ulink_subcommand_handlers[] = { { .name = "download_firmware", .handler = &ulink_download_firmware_handler, .mode = COMMAND_EXEC, .help = "download firmware image to ULINK device", .usage = "path/to/ulink_firmware.hex", }, COMMAND_REGISTRATION_DONE, }; static const struct command_registration ulink_command_handlers[] = { { .name = "ulink", .mode = COMMAND_ANY, .help = "perform ulink management", .chain = ulink_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static struct jtag_interface ulink_interface = { .execute_queue = ulink_execute_queue, }; struct adapter_driver ulink_adapter_driver = { .name = "ulink", .transports = jtag_only, .commands = ulink_command_handlers, .init = ulink_init, .quit = ulink_quit, .speed = ulink_speed, .khz = ulink_khz, .speed_div = ulink_speed_div, .jtag_ops = &ulink_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/usb_blaster/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libocdusbblaster.la %C%_libocdusbblaster_la_SOURCES = $(USB_BLASTER_SRC) %C%_libocdusbblaster_la_CPPFLAGS = -I$(top_srcdir)/src/jtag/drivers $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS) $(LIBFTDI_CFLAGS) USB_BLASTER_SRC = %D%/usb_blaster.c %D%/ublast_access.h if USB_BLASTER USB_BLASTER_SRC += %D%/ublast_access_ftdi.c endif if USB_BLASTER_2 USB_BLASTER_SRC += %D%/ublast2_access_libusb.c endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/usb_blaster/README.CheapClone ================================================ USB Blaster Cheap Clone ======================= The Altera USB Blaster has a cheap clone, based on : - a Cypress CY7C68013A-56PVXC as the main chip - a 74HC244D as the output latch - a 24 MHz quartz - a EEPROM 24C64BN The schematics (cut down to essential) is : /-----------------+----------------------\ +--------------+ | | | USB--| CY7C68013A | | +----------+ | | | | | | 74HC244D | | | . . | | | | | . . \--o 1 20 o | 10 pins header | | 47 o-- TCK --o 2 19 o---/ +-------+ | | 46 o-- TDO --o 3 18 o-- TCK -----o 1 2 o | | 45 o-- TMS --o 4 17 o-- TDO -----o 3 4 o | | 44 o o 5 16 o-- TMS -----o 5 6 o | | 43 o-- o 6 15 o o 7 8 o | | 42 o-- o 7 14 o +--o 9 10 o | | 41 o-- TDI --o 8 13 o-- ? | +-------+ | . 40 o-- nOE \ o 9 12 o-- TDI --+ | . . | o 10 11 o | o 28 29 o | | | | | | | +----------+ | +--------------+ \ | ---------------------------------------/ From this one can deduce that : - the cypress emulates the Altera chip - as the cypress pins used are 41-47, all output/input are controlled by 8051 PortA. - as the 8051 is clocked at 24Mhz, and because each USB byte is handled by the 8051, assuming a 40 instruction cycles per USB packet, the maximum throughput would be around 500 kHz. Pinout ====== Port A.0: nOE (output enable of 74HC244D) Port A.1: TDI Port A.5: TMS Port A.6: TDO Port A.7: TCK Throughput considerations ========================= Measurements on a scope reveal that : - for bitbang mode, the throughput is 56.5 kbits/s (as each clock transition is measured at 17.7us) - for byteshift mode, the throughput is 107.7 kbits/s (as 63 bits TDI transmission is measured in 585 us) Let's suppose that to upload a 32 bits value, it is necessary to : - move from IDLE to DR-SHIFT : 3 bitbang (3 TMS transitions) - input the 32 bits of data : 1 byteshift (24 bits) + 8 bitbang (8 bits) - move from DR-SHIFT to IDLE : 5 bitbang (5 TMS transitions) So for this 32 bits of data, the time would be : 3 * 17.7us + 1 * 585us/63*24 + 5 * 17.7us = 53.1us + 222us + 88.5us = 363us Throughput in bit/s: 32 * (1 / 363E-6) = 88000 bits/s Throughput in bytes/s: 11kBytes/s Conclusion ========== Contrary to the original USB Blaster, the cheap clone will never reach high transfer speeds over JTAG. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Driver for USB-JTAG, Altera USB-Blaster II and compatibles * * Copyright (C) 2013 Franck Jullien franck.jullien@gmail.com * */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <jtag/interface.h> #include <jtag/commands.h> #include "helper/system.h" #include <libusb_helper.h> #include <target/image.h> #include "ublast_access.h" #define USBBLASTER_CTRL_READ_REV 0x94 #define USBBLASTER_CTRL_LOAD_FIRM 0xA0 #define USBBLASTER_EPOUT 4 #define USBBLASTER_EPIN 8 #define EZUSB_CPUCS 0xe600 #define CPU_RESET 1 /** Maximum size of a single firmware section. Entire EZ-USB code space = 16kB */ #define SECTION_BUFFERSIZE 16384 static int ublast2_libusb_read(struct ublast_lowlevel *low, uint8_t *buf, unsigned size, uint32_t *bytes_read) { int ret, tmp = 0; ret = jtag_libusb_bulk_read(low->libusb_dev, USBBLASTER_EPIN | LIBUSB_ENDPOINT_IN, (char *)buf, size, 100, &tmp); *bytes_read = tmp; return ret; } static int ublast2_libusb_write(struct ublast_lowlevel *low, uint8_t *buf, int size, uint32_t *bytes_written) { int ret, tmp = 0; ret = jtag_libusb_bulk_write(low->libusb_dev, USBBLASTER_EPOUT | LIBUSB_ENDPOINT_OUT, (char *)buf, size, 100, &tmp); *bytes_written = tmp; return ret; } static int ublast2_write_firmware_section(struct libusb_device_handle *libusb_dev, struct image *firmware_image, int section_index) { uint16_t chunk_size; uint8_t data[SECTION_BUFFERSIZE]; uint8_t *data_ptr = data; size_t size_read; uint16_t size = (uint16_t)firmware_image->sections[section_index].size; uint16_t addr = (uint16_t)firmware_image->sections[section_index].base_address; LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04x)", section_index, addr, size); /* Copy section contents to local buffer */ int ret = image_read_section(firmware_image, section_index, 0, size, data, &size_read); if ((ret != ERROR_OK) || (size_read != size)) { /* Propagating the return code would return '0' (misleadingly indicating * successful execution of the function) if only the size check fails. */ return ERROR_FAIL; } uint16_t bytes_remaining = size; /* Send section data in chunks of up to 64 bytes to ULINK */ while (bytes_remaining > 0) { if (bytes_remaining > 64) chunk_size = 64; else chunk_size = bytes_remaining; jtag_libusb_control_transfer(libusb_dev, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, USBBLASTER_CTRL_LOAD_FIRM, addr, 0, (char *)data_ptr, chunk_size, 100); bytes_remaining -= chunk_size; addr += chunk_size; data_ptr += chunk_size; } return ERROR_OK; } static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev, struct ublast_lowlevel *low) { struct image ublast2_firmware_image; if (!low->firmware_path) { LOG_ERROR("No firmware path specified"); return ERROR_FAIL; } if (libusb_claim_interface(libusb_dev, 0)) { LOG_ERROR("unable to claim interface"); return ERROR_JTAG_INIT_FAILED; } ublast2_firmware_image.base_address = 0; ublast2_firmware_image.base_address_set = false; int ret = image_open(&ublast2_firmware_image, low->firmware_path, "ihex"); if (ret != ERROR_OK) { LOG_ERROR("Could not load firmware image"); goto error_release_usb; } /** A host loader program must write 0x01 to the CPUCS register * to put the CPU into RESET, load all or part of the EZUSB * RAM with firmware, then reload the CPUCS register * with ‘0’ to take the CPU out of RESET. The CPUCS register * (at 0xE600) is the only EZ-USB register that can be written * using the Firmware Download command. */ char value = CPU_RESET; jtag_libusb_control_transfer(libusb_dev, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, USBBLASTER_CTRL_LOAD_FIRM, EZUSB_CPUCS, 0, &value, 1, 100); /* Download all sections in the image to ULINK */ for (unsigned int i = 0; i < ublast2_firmware_image.num_sections; i++) { ret = ublast2_write_firmware_section(libusb_dev, &ublast2_firmware_image, i); if (ret != ERROR_OK) { LOG_ERROR("Error while downloading the firmware"); goto error_close_firmware; } } value = !CPU_RESET; jtag_libusb_control_transfer(libusb_dev, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, USBBLASTER_CTRL_LOAD_FIRM, EZUSB_CPUCS, 0, &value, 1, 100); error_close_firmware: image_close(&ublast2_firmware_image); error_release_usb: /* * Release claimed interface. Most probably it is already disconnected * and re-enumerated as new devices after firmware upload, so we do * not need to care about errors. */ libusb_release_interface(libusb_dev, 0); return ret; } static int ublast2_libusb_init(struct ublast_lowlevel *low) { const uint16_t vids[] = { low->ublast_vid_uninit, 0 }; const uint16_t pids[] = { low->ublast_pid_uninit, 0 }; struct libusb_device_handle *temp; bool renumeration = false; int ret; if (jtag_libusb_open(vids, pids, &temp, NULL) == ERROR_OK) { LOG_INFO("Altera USB-Blaster II (uninitialized) found"); LOG_INFO("Loading firmware..."); ret = load_usb_blaster_firmware(temp, low); jtag_libusb_close(temp); if (ret != ERROR_OK) return ret; renumeration = true; } const uint16_t vids_renum[] = { low->ublast_vid, 0 }; const uint16_t pids_renum[] = { low->ublast_pid, 0 }; if (renumeration == false) { if (jtag_libusb_open(vids_renum, pids_renum, &low->libusb_dev, NULL) != ERROR_OK) { LOG_ERROR("Altera USB-Blaster II not found"); return ERROR_FAIL; } } else { int retry = 10; while (jtag_libusb_open(vids_renum, pids_renum, &low->libusb_dev, NULL) != ERROR_OK && retry--) { usleep(1000000); LOG_INFO("Waiting for reenumerate..."); } if (!retry) { LOG_ERROR("Altera USB-Blaster II not found"); return ERROR_FAIL; } } if (libusb_claim_interface(low->libusb_dev, 0)) { LOG_ERROR("unable to claim interface"); jtag_libusb_close(low->libusb_dev); return ERROR_JTAG_INIT_FAILED; } char buffer[5]; jtag_libusb_control_transfer(low->libusb_dev, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN, USBBLASTER_CTRL_READ_REV, 0, 0, buffer, 5, 100); LOG_INFO("Altera USB-Blaster II found (Firm. rev. = %s)", buffer); return ERROR_OK; } static int ublast2_libusb_quit(struct ublast_lowlevel *low) { if (libusb_release_interface(low->libusb_dev, 0)) LOG_ERROR("usb release interface failed"); jtag_libusb_close(low->libusb_dev); return ERROR_OK; }; static struct ublast_lowlevel low = { .open = ublast2_libusb_init, .close = ublast2_libusb_quit, .read = ublast2_libusb_read, .write = ublast2_libusb_write, .flags = COPY_TDO_BUFFER, }; struct ublast_lowlevel *ublast2_register_libusb(void) { return &low; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/usb_blaster/ublast_access.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Driver for USB-JTAG, Altera USB-Blaster and compatibles * * Inspired from original code from Kolja Waschk's USB-JTAG project * (http://www.ixo.de/info/usb_jtag/), and from openocd project. * * Copyright (C) 2013 Franck Jullien franck.jullien@gmail.com * Copyright (C) 2012 Robert Jarzmik robert.jarzmik@free.fr * Copyright (C) 2011 Ali Lown ali@lown.me.uk * Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca * Copyright (C) 2006 Kolja Waschk usbjtag@ixo.de * */ #ifndef OPENOCD_JTAG_DRIVERS_USB_BLASTER_UBLAST_ACCESS_H #define OPENOCD_JTAG_DRIVERS_USB_BLASTER_UBLAST_ACCESS_H /* Low level flags */ #define COPY_TDO_BUFFER (1 << 0) struct ublast_lowlevel { uint16_t ublast_vid; uint16_t ublast_pid; uint16_t ublast_vid_uninit; uint16_t ublast_pid_uninit; struct libusb_device_handle *libusb_dev; char *firmware_path; int (*write)(struct ublast_lowlevel *low, uint8_t *buf, int size, uint32_t *bytes_written); int (*read)(struct ublast_lowlevel *low, uint8_t *buf, unsigned size, uint32_t *bytes_read); int (*open)(struct ublast_lowlevel *low); int (*close)(struct ublast_lowlevel *low); int (*speed)(struct ublast_lowlevel *low, int speed); void *priv; int flags; }; /** * ublast_register_ftdi - get a lowlevel USB Blaster driver * ublast2_register_libusb - get a lowlevel USB Blaster II driver * * Get a lowlevel USB-Blaster driver. In the current implementation, there are 2 * possible lowlevel drivers : * - one based on libftdi, * - one based on libusb, specific to the USB-Blaster II * * Returns the lowlevel driver structure. */ extern struct ublast_lowlevel *ublast_register_ftdi(void); extern struct ublast_lowlevel *ublast2_register_libusb(void); #endif /* OPENOCD_JTAG_DRIVERS_USB_BLASTER_UBLAST_ACCESS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Driver for USB-JTAG, Altera USB-Blaster and compatibles * * Inspired from original code from Kolja Waschk's USB-JTAG project * (http://www.ixo.de/info/usb_jtag/), and from openocd project. * * Copyright (C) 2012 Robert Jarzmik robert.jarzmik@free.fr * Copyright (C) 2011 Ali Lown ali@lown.me.uk * Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca * Copyright (C) 2006 Kolja Waschk usbjtag@ixo.de * */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <jtag/interface.h> #include <jtag/commands.h> #include "ublast_access.h" #include <ftdi.h> static struct ftdi_context *ublast_getftdic(struct ublast_lowlevel *low) { return low->priv; } static int ublast_ftdi_read(struct ublast_lowlevel *low, uint8_t *buf, unsigned size, uint32_t *bytes_read) { int retval; int timeout = 100; struct ftdi_context *ftdic = ublast_getftdic(low); *bytes_read = 0; while ((*bytes_read < size) && timeout--) { retval = ftdi_read_data(ftdic, buf + *bytes_read, size - *bytes_read); if (retval < 0) { *bytes_read = 0; LOG_ERROR("ftdi_read_data: %s", ftdi_get_error_string(ftdic)); return ERROR_JTAG_DEVICE_ERROR; } *bytes_read += retval; } return ERROR_OK; } static int ublast_ftdi_write(struct ublast_lowlevel *low, uint8_t *buf, int size, uint32_t *bytes_written) { int retval; struct ftdi_context *ftdic = ublast_getftdic(low); retval = ftdi_write_data(ftdic, buf, size); if (retval < 0) { *bytes_written = 0; LOG_ERROR("ftdi_write_data: %s", ftdi_get_error_string(ftdic)); return ERROR_JTAG_DEVICE_ERROR; } *bytes_written = retval; return ERROR_OK; } static int ublast_ftdi_init(struct ublast_lowlevel *low) { uint8_t latency_timer; struct ftdi_context *ftdic = ublast_getftdic(low); LOG_INFO("usb blaster interface using libftdi"); if (ftdi_init(ftdic) < 0) return ERROR_JTAG_INIT_FAILED; /* context, vendor id, product id */ if (ftdi_usb_open(ftdic, low->ublast_vid, low->ublast_pid) < 0) { LOG_ERROR("unable to open ftdi device: %s", ftdic->error_str); return ERROR_JTAG_INIT_FAILED; } if (ftdi_usb_reset(ftdic) < 0) { LOG_ERROR("unable to reset ftdi device"); return ERROR_JTAG_INIT_FAILED; } if (ftdi_set_latency_timer(ftdic, 2) < 0) { LOG_ERROR("unable to set latency timer"); return ERROR_JTAG_INIT_FAILED; } if (ftdi_get_latency_timer(ftdic, &latency_timer) < 0) LOG_ERROR("unable to get latency timer"); else LOG_DEBUG("current latency timer: %u", latency_timer); ftdi_disable_bitbang(ftdic); return ERROR_OK; } static int ublast_ftdi_quit(struct ublast_lowlevel *low) { struct ftdi_context *ftdic = ublast_getftdic(low); ftdi_usb_close(ftdic); ftdi_deinit(ftdic); return ERROR_OK; }; static struct ublast_lowlevel_priv { struct ftdi_context ftdic; } info; static struct ublast_lowlevel low = { .open = ublast_ftdi_init, .close = ublast_ftdi_quit, .read = ublast_ftdi_read, .write = ublast_ftdi_write, .priv = &info, }; struct ublast_lowlevel *ublast_register_ftdi(void) { return &low; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/usb_blaster/usb_blaster.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Driver for USB-JTAG, Altera USB-Blaster and compatibles * * Inspired from original code from Kolja Waschk's USB-JTAG project * (http://www.ixo.de/info/usb_jtag/), and from openocd project. * * Copyright (C) 2013 Franck Jullien franck.jullien@gmail.com * Copyright (C) 2012 Robert Jarzmik robert.jarzmik@free.fr * Copyright (C) 2011 Ali Lown ali@lown.me.uk * Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca * Copyright (C) 2006 Kolja Waschk usbjtag@ixo.de * */ /* * The following information is originally from Kolja Waschk's USB-JTAG, * where it was obtained by reverse engineering an Altera USB-Blaster. * See http://www.ixo.de/info/usb_jtag/ for USB-Blaster block diagram and * usb_jtag-20080705-1200.zip#usb_jtag/host/openocd for protocol. * * The same information is also on the UrJTAG mediawiki, with some additional * notes on bits marked as "unknown" by usb_jtag. * (http://sourceforge.net/apps/mediawiki/urjtag/index.php? * title=Cable_Altera_USB-Blaster) * * USB-JTAG, Altera USB-Blaster and compatibles are typically implemented as * an FTDIChip FT245 followed by a CPLD which handles a two-mode protocol: * * _________ * | | * | AT93C46 | * |_________| * __|__________ _________ * | | | | * USB__| FTDI 245BM |__| EPM7064 |__JTAG (B_TDO,B_TDI,B_TMS,B_TCK) * |_____________| |_________| * __|__________ _|___________ * | | | | * | 6 MHz XTAL | | 24 MHz Osc. | * |_____________| |_____________| * * USB-JTAG, Altera USB-Blaster II are typically implemented as a Cypress * EZ-USB FX2LP followed by a CPLD. * _____________ _________ * | | | | * USB__| EZ-USB FX2 |__| EPM570 |__JTAG (B_TDO,B_TDI,B_TMS,B_TCK) * |_____________| |_________| * __|__________ * | | * | 24 MHz XTAL | * |_____________| */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #if IS_CYGWIN == 1 #include "windows.h" #undef LOG_ERROR #endif /* project specific includes */ #include <jtag/interface.h> #include <jtag/commands.h> #include <helper/time_support.h> #include <helper/replacements.h> #include "ublast_access.h" /* system includes */ #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/time.h> #include <time.h> /* Size of USB endpoint max packet size, ie. 64 bytes */ #define MAX_PACKET_SIZE 64 /* * Size of data buffer that holds bytes in byte-shift mode. * This buffer can hold multiple USB packets aligned to * MAX_PACKET_SIZE bytes boundaries. * BUF_LEN must be grater than or equal MAX_PACKET_SIZE. */ #define BUF_LEN 4096 /* USB-Blaster II specific command */ #define CMD_COPY_TDO_BUFFER 0x5F enum gpio_steer { FIXED_0 = 0, FIXED_1, SRST, TRST, }; struct ublast_info { enum gpio_steer pin6; enum gpio_steer pin8; int tms; int tdi; bool trst_asserted; bool srst_asserted; uint8_t buf[BUF_LEN]; int bufidx; char *lowlevel_name; struct ublast_lowlevel *drv; uint16_t ublast_vid, ublast_pid; uint16_t ublast_vid_uninit, ublast_pid_uninit; int flags; char *firmware_path; }; /* * Global device control */ static struct ublast_info info = { .ublast_vid = 0x09fb, /* Altera */ .ublast_pid = 0x6001, /* USB-Blaster */ .lowlevel_name = NULL, .srst_asserted = false, .trst_asserted = false, .pin6 = FIXED_1, .pin8 = FIXED_1, }; /* * Available lowlevel drivers (FTDI, libusb, ...) */ struct drvs_map { char *name; struct ublast_lowlevel *(*drv_register)(void); }; static struct drvs_map lowlevel_drivers_map[] = { #if BUILD_USB_BLASTER { .name = "ftdi", .drv_register = ublast_register_ftdi }, #endif #if BUILD_USB_BLASTER_2 { .name = "ublast2", .drv_register = ublast2_register_libusb }, #endif { NULL, NULL }, }; /* * Access functions to lowlevel driver, agnostic of libftdi/libftdxx */ static char *hexdump(uint8_t *buf, unsigned int size) { unsigned int i; char *str = calloc(size * 2 + 1, 1); for (i = 0; i < size; i++) sprintf(str + 2*i, "%02x", buf[i]); return str; } static int ublast_buf_read(uint8_t *buf, unsigned size, uint32_t *bytes_read) { int ret = info.drv->read(info.drv, buf, size, bytes_read); char *str = hexdump(buf, *bytes_read); LOG_DEBUG_IO("(size=%d, buf=[%s]) -> %" PRIu32, size, str, *bytes_read); free(str); return ret; } static int ublast_buf_write(uint8_t *buf, int size, uint32_t *bytes_written) { int ret = info.drv->write(info.drv, buf, size, bytes_written); char *str = hexdump(buf, *bytes_written); LOG_DEBUG_IO("(size=%d, buf=[%s]) -> %" PRIu32, size, str, *bytes_written); free(str); return ret; } static int nb_buf_remaining(void) { return BUF_LEN - info.bufidx; } static void ublast_flush_buffer(void) { uint32_t retlen; int nb = info.bufidx, ret = ERROR_OK; while (ret == ERROR_OK && nb > 0) { ret = ublast_buf_write(info.buf, nb, &retlen); nb -= retlen; } info.bufidx = 0; } /* * Actually, the USB-Blaster offers a byte-shift mode to transmit up to 504 data * bits (bidirectional) in a single USB packet. A header byte has to be sent as * the first byte in a packet with the following meaning: * * Bit 7 (0x80): Must be set to indicate byte-shift mode. * Bit 6 (0x40): If set, the USB-Blaster will also read data, not just write. * Bit 5..0: Define the number N of following bytes * * All N following bytes will then be clocked out serially on TDI. If Bit 6 was * set, it will afterwards return N bytes with TDO data read while clocking out * the TDI data. LSB of the first byte after the header byte will appear first * on TDI. */ /* Simple bit banging mode: * * Bit 7 (0x80): Must be zero (see byte-shift mode above) * Bit 6 (0x40): If set, you will receive a byte indicating the state of TDO * in return. * Bit 5 (0x20): Output Enable/LED. * Bit 4 (0x10): TDI Output. * Bit 3 (0x08): nCS Output (not used in JTAG mode). * Bit 2 (0x04): nCE Output (not used in JTAG mode). * Bit 1 (0x02): TMS Output. * Bit 0 (0x01): TCK Output. * * For transmitting a single data bit, you need to write two bytes (one for * setting up TDI/TMS/TCK=0, and one to trigger TCK high with same TDI/TMS * held). Up to 64 bytes can be combined in a single USB packet. * It isn't possible to read a data without transmitting data. */ #define TCK (1 << 0) #define TMS (1 << 1) #define NCE (1 << 2) #define NCS (1 << 3) #define TDI (1 << 4) #define LED (1 << 5) #define READ (1 << 6) #define SHMODE (1 << 7) #define READ_TDO (1 << 0) /** * ublast_queue_byte - queue one 'bitbang mode' byte for USB Blaster * @param abyte the byte to queue * * Queues one byte in 'bitbang mode' to the USB Blaster. The byte is not * actually sent, but stored in a buffer. The write is performed once * the buffer is filled, or if an explicit ublast_flush_buffer() is called. */ static void ublast_queue_byte(uint8_t abyte) { if (nb_buf_remaining() < 1) ublast_flush_buffer(); info.buf[info.bufidx++] = abyte; if (nb_buf_remaining() == 0) ublast_flush_buffer(); LOG_DEBUG_IO("(byte=0x%02x)", abyte); } /** * ublast_compute_pin - compute if gpio should be asserted * @param steer control (ie. TRST driven, SRST driven, of fixed) * * Returns pin value (1 means driven high, 0 mean driven low) */ static bool ublast_compute_pin(enum gpio_steer steer) { switch (steer) { case FIXED_0: return 0; case FIXED_1: return 1; case SRST: return !info.srst_asserted; case TRST: return !info.trst_asserted; default: return 1; } } /** * ublast_build_out - build bitbang mode output byte * @param type says if reading back TDO is required * * Returns the compute bitbang mode byte */ static uint8_t ublast_build_out(enum scan_type type) { uint8_t abyte = 0; abyte |= info.tms ? TMS : 0; abyte |= ublast_compute_pin(info.pin6) ? NCE : 0; abyte |= ublast_compute_pin(info.pin8) ? NCS : 0; abyte |= info.tdi ? TDI : 0; abyte |= LED; if (type == SCAN_IN || type == SCAN_IO) abyte |= READ; return abyte; } /** * ublast_reset - reset the JTAG device is possible * @param trst 1 if TRST is to be asserted * @param srst 1 if SRST is to be asserted */ static void ublast_reset(int trst, int srst) { uint8_t out_value; info.trst_asserted = trst; info.srst_asserted = srst; out_value = ublast_build_out(SCAN_OUT); ublast_queue_byte(out_value); ublast_flush_buffer(); } /** * ublast_clock_tms - clock a TMS transition * @param tms the TMS to be sent * * Triggers a TMS transition (ie. one JTAG TAP state move). */ static void ublast_clock_tms(int tms) { uint8_t out; LOG_DEBUG_IO("(tms=%d)", !!tms); info.tms = !!tms; info.tdi = 0; out = ublast_build_out(SCAN_OUT); ublast_queue_byte(out); ublast_queue_byte(out | TCK); } /** * ublast_idle_clock - put back TCK to low level * * See ublast_queue_tdi() comment for the usage of this function. */ static void ublast_idle_clock(void) { uint8_t out = ublast_build_out(SCAN_OUT); LOG_DEBUG_IO("."); ublast_queue_byte(out); } /** * ublast_clock_tdi - Output a TDI with bitbang mode * @param tdi the TDI bit to be shifted out * @param type scan type (ie. does a readback of TDO is required) * * Output a TDI bit and assert clock to push it into the JTAG device : * - writing out TCK=0, TMS=\<old_state>=0, TDI=\<tdi> * - writing out TCK=1, TMS=\<new_state>, TDI=\<tdi> which triggers the JTAG * device acquiring the data. * * If a TDO is to be read back, the required read is requested (bitbang mode), * and the USB Blaster will send back a byte with bit0 representing the TDO. */ static void ublast_clock_tdi(int tdi, enum scan_type type) { uint8_t out; LOG_DEBUG_IO("(tdi=%d)", !!tdi); info.tdi = !!tdi; out = ublast_build_out(SCAN_OUT); ublast_queue_byte(out); out = ublast_build_out(type); ublast_queue_byte(out | TCK); } /** * ublast_clock_tdi_flip_tms - Output a TDI with bitbang mode, change JTAG state * @param tdi the TDI bit to be shifted out * @param type scan type (ie. does a readback of TDO is required) * * This function is the same as ublast_clock_tdi(), but it changes also the TMS * while output the TDI. This should be the last TDI output of a TDI * sequence, which will change state from : * - IRSHIFT -> IREXIT1 * - or DRSHIFT -> DREXIT1 */ static void ublast_clock_tdi_flip_tms(int tdi, enum scan_type type) { uint8_t out; LOG_DEBUG_IO("(tdi=%d)", !!tdi); info.tdi = !!tdi; info.tms = !info.tms; out = ublast_build_out(SCAN_OUT); ublast_queue_byte(out); out = ublast_build_out(type); ublast_queue_byte(out | TCK); out = ublast_build_out(SCAN_OUT); ublast_queue_byte(out); } /** * ublast_queue_bytes - queue bytes for the USB Blaster * @param bytes byte array * @param nb_bytes number of bytes * * Queues bytes to be sent to the USB Blaster. The bytes are not * actually sent, but stored in a buffer. The write is performed once * the buffer is filled, or if an explicit ublast_flush_buffer() is called. */ static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes) { if (info.bufidx + nb_bytes > BUF_LEN) { LOG_ERROR("buggy code, should never queue more that %d bytes", info.bufidx + nb_bytes); exit(-1); } LOG_DEBUG_IO("(nb_bytes=%d, bytes=[0x%02x, ...])", nb_bytes, bytes ? bytes[0] : 0); if (bytes) memcpy(&info.buf[info.bufidx], bytes, nb_bytes); else memset(&info.buf[info.bufidx], 0, nb_bytes); info.bufidx += nb_bytes; if (nb_buf_remaining() == 0) ublast_flush_buffer(); } /** * ublast_tms_seq - write a TMS sequence transition to JTAG * @param bits TMS bits to be written (bit0, bit1 .. bitN) * @param nb_bits number of TMS bits (between 1 and 8) * @param skip number of TMS bits to skip at the beginning of the series * * Write a series of TMS transitions, where each transition consists in : * - writing out TCK=0, TMS=\<new_state>, TDI=\<???> * - writing out TCK=1, TMS=\<new_state>, TDI=\<???> which triggers the transition * The function ensures that at the end of the sequence, the clock (TCK) is put * low. */ static void ublast_tms_seq(const uint8_t *bits, int nb_bits, int skip) { int i; LOG_DEBUG_IO("(bits=%02x..., nb_bits=%d)", bits[0], nb_bits); for (i = skip; i < nb_bits; i++) ublast_clock_tms((bits[i / 8] >> (i % 8)) & 0x01); ublast_idle_clock(); } /** * ublast_tms - write a tms command * @param cmd tms command */ static void ublast_tms(struct tms_command *cmd) { LOG_DEBUG_IO("(num_bits=%d)", cmd->num_bits); ublast_tms_seq(cmd->bits, cmd->num_bits, 0); } /** * ublast_path_move - write a TMS sequence transition to JTAG * @param cmd path transition * * Write a series of TMS transitions, where each transition consists in : * - writing out TCK=0, TMS=\<new_state>, TDI=\<???> * - writing out TCK=1, TMS=\<new_state>, TDI=\<???> which triggers the transition * The function ensures that at the end of the sequence, the clock (TCK) is put * low. */ static void ublast_path_move(struct pathmove_command *cmd) { int i; LOG_DEBUG_IO("(num_states=%d, last_state=%d)", cmd->num_states, cmd->path[cmd->num_states - 1]); for (i = 0; i < cmd->num_states; i++) { if (tap_state_transition(tap_get_state(), false) == cmd->path[i]) ublast_clock_tms(0); if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) ublast_clock_tms(1); tap_set_state(cmd->path[i]); } ublast_idle_clock(); } /** * ublast_state_move - move JTAG state to the target state * @param state the target state * @param skip number of bits to skip at the beginning of the path * * Input the correct TMS sequence to the JTAG TAP so that we end up in the * target state. This assumes the current state (tap_get_state()) is correct. */ static void ublast_state_move(tap_state_t state, int skip) { uint8_t tms_scan; int tms_len; LOG_DEBUG_IO("(from %s to %s)", tap_state_name(tap_get_state()), tap_state_name(state)); if (tap_get_state() == state) return; tms_scan = tap_get_tms_path(tap_get_state(), state); tms_len = tap_get_tms_path_len(tap_get_state(), state); ublast_tms_seq(&tms_scan, tms_len, skip); tap_set_state(state); } /** * ublast_read_byteshifted_tdos - read TDO of byteshift writes * @param buf the buffer to store the bits * @param nb_bytes the number of bytes * * Reads back from USB Blaster TDO bits, triggered by a 'byteshift write', ie. eight * bits per received byte from USB interface, and store them in buffer. * * As the USB blaster stores the TDO bits in LSB (ie. first bit in (byte0, * bit0), second bit in (byte0, bit1), ...), which is what we want to return, * simply read bytes from USB interface and store them. * * Returns ERROR_OK if OK, ERROR_xxx if a read error occurred */ static int ublast_read_byteshifted_tdos(uint8_t *buf, int nb_bytes) { uint32_t retlen; int ret = ERROR_OK; LOG_DEBUG_IO("%s(buf=%p, num_bits=%d)", __func__, buf, nb_bytes * 8); ublast_flush_buffer(); while (ret == ERROR_OK && nb_bytes > 0) { ret = ublast_buf_read(buf, nb_bytes, &retlen); nb_bytes -= retlen; } return ret; } /** * ublast_read_bitbang_tdos - read TDO of bitbang writes * @param buf the buffer to store the bits * @param nb_bits the number of bits * * Reads back from USB Blaster TDO bits, triggered by a 'bitbang write', ie. one * bit per received byte from USB interface, and store them in buffer, where : * - first bit is stored in byte0, bit0 (LSB) * - second bit is stored in byte0, bit 1 * ... * - eight bit is stored in byte0, bit 7 * - ninth bit is stored in byte1, bit 0 * - etc ... * * Returns ERROR_OK if OK, ERROR_xxx if a read error occurred */ static int ublast_read_bitbang_tdos(uint8_t *buf, int nb_bits) { int nb1 = nb_bits; int i, ret = ERROR_OK; uint32_t retlen; uint8_t tmp[8]; LOG_DEBUG_IO("%s(buf=%p, num_bits=%d)", __func__, buf, nb_bits); /* * Ensure all previous bitbang writes were issued to the dongle, so that * it returns back the read values. */ ublast_flush_buffer(); ret = ublast_buf_read(tmp, nb1, &retlen); for (i = 0; ret == ERROR_OK && i < nb1; i++) if (tmp[i] & READ_TDO) *buf |= (1 << i); else *buf &= ~(1 << i); return ret; } /** * ublast_queue_tdi - short description * @param bits bits to be queued on TDI (or NULL if 0 are to be queued) * @param nb_bits number of bits * @param scan scan type (ie. if TDO read back is required or not) * * Outputs a series of TDI bits on TDI. * As a side effect, the last TDI bit is sent along a TMS=1, and triggers a JTAG * TAP state shift if input bits were non NULL. * * In order to not saturate the USB Blaster queues, this method reads back TDO * if the scan type requests it, and stores them back in bits. * * As a side note, the state of TCK when entering this function *must* be * low. This is because byteshift mode outputs TDI on rising TCK and reads TDO * on falling TCK if and only if TCK is low before queuing byteshift mode bytes. * If TCK was high, the USB blaster will queue TDI on falling edge, and read TDO * on rising edge !!! */ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, enum scan_type scan) { int nb8 = nb_bits / 8; int nb1 = nb_bits % 8; int nbfree_in_packet, i, trans = 0, read_tdos; uint8_t *tdos = calloc(1, nb_bits / 8 + 1); static uint8_t byte0[BUF_LEN]; /* * As the last TDI bit should always be output in bitbang mode in order * to activate the TMS=1 transition to EXIT_?R state. Therefore a * situation where nb_bits is a multiple of 8 is handled as follows: * - the number of TDI shifted out in "byteshift mode" is 8 less than * nb_bits * - nb1 = 8 * This ensures that nb1 is never 0, and allows the TMS transition. */ if (nb8 > 0 && nb1 == 0) { nb8--; nb1 = 8; } read_tdos = (scan == SCAN_IN || scan == SCAN_IO); for (i = 0; i < nb8; i += trans) { /* * Calculate number of bytes to fill USB packet of size MAX_PACKET_SIZE */ nbfree_in_packet = (MAX_PACKET_SIZE - (info.bufidx%MAX_PACKET_SIZE)); trans = MIN(nbfree_in_packet - 1, nb8 - i); /* * Queue a byte-shift mode transmission, with as many bytes as * is possible with regard to : * - current filling level of write buffer * - remaining bytes to write in byte-shift mode */ if (read_tdos) ublast_queue_byte(SHMODE | READ | trans); else ublast_queue_byte(SHMODE | trans); if (bits) ublast_queue_bytes(&bits[i], trans); else ublast_queue_bytes(byte0, trans); if (read_tdos) { if (info.flags & COPY_TDO_BUFFER) ublast_queue_byte(CMD_COPY_TDO_BUFFER); ublast_read_byteshifted_tdos(&tdos[i], trans); } } /* * Queue the remaining TDI bits in bitbang mode. */ for (i = 0; i < nb1; i++) { int tdi = bits ? bits[nb8 + i / 8] & (1 << i) : 0; if (bits && i == nb1 - 1) ublast_clock_tdi_flip_tms(tdi, scan); else ublast_clock_tdi(tdi, scan); } if (nb1 && read_tdos) { if (info.flags & COPY_TDO_BUFFER) ublast_queue_byte(CMD_COPY_TDO_BUFFER); ublast_read_bitbang_tdos(&tdos[nb8], nb1); } if (bits) memcpy(bits, tdos, DIV_ROUND_UP(nb_bits, 8)); free(tdos); /* * Ensure clock is in lower state */ ublast_idle_clock(); } static void ublast_runtest(int cycles, tap_state_t state) { LOG_DEBUG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state); ublast_state_move(TAP_IDLE, 0); ublast_queue_tdi(NULL, cycles, SCAN_OUT); ublast_state_move(state, 0); } static void ublast_stableclocks(int cycles) { LOG_DEBUG_IO("%s(cycles=%i)", __func__, cycles); ublast_queue_tdi(NULL, cycles, SCAN_OUT); } /** * ublast_scan - launches a DR-scan or IR-scan * @param cmd the command to launch * * Launch a JTAG IR-scan or DR-scan * * Returns ERROR_OK if OK, ERROR_xxx if a read/write error occurred. */ static int ublast_scan(struct scan_command *cmd) { int scan_bits; uint8_t *buf = NULL; enum scan_type type; int ret = ERROR_OK; static const char * const type2str[] = { "", "SCAN_IN", "SCAN_OUT", "SCAN_IO" }; char *log_buf = NULL; type = jtag_scan_type(cmd); scan_bits = jtag_build_buffer(cmd, &buf); if (cmd->ir_scan) ublast_state_move(TAP_IRSHIFT, 0); else ublast_state_move(TAP_DRSHIFT, 0); log_buf = hexdump(buf, DIV_ROUND_UP(scan_bits, 8)); LOG_DEBUG_IO("%s(scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d)", __func__, cmd->ir_scan ? "IRSCAN" : "DRSCAN", type2str[type], scan_bits, log_buf, cmd->end_state); free(log_buf); ublast_queue_tdi(buf, scan_bits, type); ret = jtag_read_buffer(buf, cmd); free(buf); /* * ublast_queue_tdi sends the last bit with TMS=1. We are therefore * already in Exit1-DR/IR and have to skip the first step on our way * to end_state. */ ublast_state_move(cmd->end_state, 1); return ret; } static void ublast_usleep(int us) { LOG_DEBUG_IO("%s(us=%d)", __func__, us); jtag_sleep(us); } static void ublast_initial_wipeout(void) { static uint8_t tms_reset = 0xff; uint8_t out_value; uint32_t retlen; int i; out_value = ublast_build_out(SCAN_OUT); for (i = 0; i < BUF_LEN; i++) info.buf[i] = out_value | ((i % 2) ? TCK : 0); /* * Flush USB-Blaster queue fifos * - empty the write FIFO (128 bytes) * - empty the read FIFO (384 bytes) */ ublast_buf_write(info.buf, BUF_LEN, &retlen); /* * Put JTAG in RESET state (five 1 on TMS) */ ublast_tms_seq(&tms_reset, 5, 0); tap_set_state(TAP_RESET); } static int ublast_execute_queue(void) { struct jtag_command *cmd; static int first_call = 1; int ret = ERROR_OK; if (first_call) { first_call--; ublast_initial_wipeout(); } for (cmd = jtag_command_queue; ret == ERROR_OK && cmd; cmd = cmd->next) { switch (cmd->type) { case JTAG_RESET: ublast_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: ublast_runtest(cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); break; case JTAG_STABLECLOCKS: ublast_stableclocks(cmd->cmd.stableclocks->num_cycles); break; case JTAG_TLR_RESET: ublast_state_move(cmd->cmd.statemove->end_state, 0); break; case JTAG_PATHMOVE: ublast_path_move(cmd->cmd.pathmove); break; case JTAG_TMS: ublast_tms(cmd->cmd.tms); break; case JTAG_SLEEP: ublast_usleep(cmd->cmd.sleep->us); break; case JTAG_SCAN: ret = ublast_scan(cmd->cmd.scan); break; default: LOG_ERROR("BUG: unknown JTAG command type 0x%X", cmd->type); ret = ERROR_FAIL; break; } } ublast_flush_buffer(); return ret; } /** * ublast_init - Initialize the Altera device * * Initialize the device : * - open the USB device * - pretend it's initialized while actual init is delayed until first jtag command * * Returns ERROR_OK if USB device found, error if not. */ static int ublast_init(void) { int ret, i; for (i = 0; lowlevel_drivers_map[i].name; i++) { if (info.lowlevel_name) { if (!strcmp(lowlevel_drivers_map[i].name, info.lowlevel_name)) { info.drv = lowlevel_drivers_map[i].drv_register(); if (!info.drv) { LOG_ERROR("Error registering lowlevel driver \"%s\"", info.lowlevel_name); return ERROR_JTAG_DEVICE_ERROR; } break; } } else { info.drv = lowlevel_drivers_map[i].drv_register(); if (info.drv) { info.lowlevel_name = strdup(lowlevel_drivers_map[i].name); LOG_INFO("No lowlevel driver configured, using %s", info.lowlevel_name); break; } } } if (!info.drv) { LOG_ERROR("No lowlevel driver available"); return ERROR_JTAG_DEVICE_ERROR; } /* * Register the lowlevel driver */ info.drv->ublast_vid = info.ublast_vid; info.drv->ublast_pid = info.ublast_pid; info.drv->ublast_vid_uninit = info.ublast_vid_uninit; info.drv->ublast_pid_uninit = info.ublast_pid_uninit; info.drv->firmware_path = info.firmware_path; info.flags |= info.drv->flags; ret = info.drv->open(info.drv); /* * Let lie here : the TAP is in an unknown state, but the first * execute_queue() will trigger a ublast_initial_wipeout(), which will * put the TAP in RESET. */ tap_set_state(TAP_RESET); return ret; } /** * ublast_quit - Release the Altera device * * Releases the device : * - put the device pins in 'high impedance' mode * - close the USB device * * Returns always ERROR_OK */ static int ublast_quit(void) { uint8_t byte0 = 0; uint32_t retlen; ublast_buf_write(&byte0, 1, &retlen); return info.drv->close(info.drv); } COMMAND_HANDLER(ublast_handle_vid_pid_command) { if (CMD_ARGC > 4) { LOG_WARNING("ignoring extra IDs in ublast_vid_pid " "(maximum is 2 pairs)"); CMD_ARGC = 4; } if (CMD_ARGC >= 2) { COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], info.ublast_vid); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], info.ublast_pid); } else { LOG_WARNING("incomplete ublast_vid_pid configuration"); } if (CMD_ARGC == 4) { COMMAND_PARSE_NUMBER(u16, CMD_ARGV[2], info.ublast_vid_uninit); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], info.ublast_pid_uninit); } else { LOG_WARNING("incomplete ublast_vid_pid configuration"); } return ERROR_OK; } COMMAND_HANDLER(ublast_handle_pin_command) { uint8_t out_value; const char * const pin_name = CMD_ARGV[0]; enum gpio_steer *steer = NULL; static const char * const pin_val_str[] = { [FIXED_0] = "0", [FIXED_1] = "1", [SRST] = "SRST driven", [TRST] = "TRST driven", }; if (CMD_ARGC > 2) { LOG_ERROR("%s takes exactly one or two arguments", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; } if (!strcmp(pin_name, "pin6")) steer = &info.pin6; if (!strcmp(pin_name, "pin8")) steer = &info.pin8; if (!steer) { LOG_ERROR("%s: pin name must be \"pin6\" or \"pin8\"", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; } if (CMD_ARGC == 1) { LOG_INFO("%s: %s is set as %s\n", CMD_NAME, pin_name, pin_val_str[*steer]); } if (CMD_ARGC == 2) { const char * const pin_value = CMD_ARGV[1]; char val = pin_value[0]; if (strlen(pin_value) > 1) val = '?'; switch (tolower((unsigned char)val)) { case '0': *steer = FIXED_0; break; case '1': *steer = FIXED_1; break; case 't': *steer = TRST; break; case 's': *steer = SRST; break; default: LOG_ERROR("%s: pin value must be 0, 1, s (SRST) or t (TRST)", pin_value); return ERROR_COMMAND_SYNTAX_ERROR; } if (info.drv) { out_value = ublast_build_out(SCAN_OUT); ublast_queue_byte(out_value); ublast_flush_buffer(); } } return ERROR_OK; } COMMAND_HANDLER(ublast_handle_lowlevel_drv_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; info.lowlevel_name = strdup(CMD_ARGV[0]); return ERROR_OK; } COMMAND_HANDLER(ublast_firmware_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; info.firmware_path = strdup(CMD_ARGV[0]); return ERROR_OK; } static const struct command_registration ublast_subcommand_handlers[] = { { .name = "vid_pid", .handler = ublast_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "the vendor ID and product ID of the USB-Blaster and " "vendor ID and product ID of the uninitialized device " "for USB-Blaster II", .usage = "vid pid vid_uninit pid_uninit", }, { .name = "lowlevel_driver", .handler = ublast_handle_lowlevel_drv_command, .mode = COMMAND_CONFIG, .help = "set the lowlevel access for the USB Blaster (ftdi, ublast2)", .usage = "(ftdi|ublast2)", }, { .name = "pin", .handler = ublast_handle_pin_command, .mode = COMMAND_ANY, .help = "show or set pin state for the unused GPIO pins", .usage = "(pin6|pin8) (0|1|s|t)", }, { .name = "firmware", .handler = &ublast_firmware_command, .mode = COMMAND_CONFIG, .help = "configure the USB-Blaster II firmware location", .usage = "path/to/blaster_xxxx.hex", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration ublast_command_handlers[] = { { .name = "usb_blaster", .mode = COMMAND_ANY, .help = "perform usb_blaster management", .chain = ublast_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static struct jtag_interface usb_blaster_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = ublast_execute_queue, }; struct adapter_driver usb_blaster_adapter_driver = { .name = "usb_blaster", .transports = jtag_only, .commands = ublast_command_handlers, .init = ublast_init, .quit = ublast_quit, .jtag_ops = &usb_blaster_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/usbprog.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Benedikt Sauter * * sauter@ixbat.de * ***************************************************************************/ /* * This file is based on Dominic Rath's amt_jtagaccel.c. * * usbprog is a free programming adapter. You can easily install * different firmware versions from an "online pool" over USB. * The adapter can be used for programming and debugging AVR and ARM * processors, as USB to RS232 converter, as JTAG interface or as * simple I/O interface (5 lines). * * http://www.embedded-projects.net/usbprog */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/interface.h> #include <jtag/commands.h> #include "libusb_helper.h" #define VID 0x1781 #define PID 0x0c63 /* Pins at usbprog */ #define TDO_BIT 0 #define TDI_BIT 3 #define TCK_BIT 2 #define TMS_BIT 1 static void usbprog_end_state(tap_state_t state); static void usbprog_state_move(void); static void usbprog_path_move(struct pathmove_command *cmd); static void usbprog_runtest(int num_cycles); static void usbprog_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size); #define UNKNOWN_COMMAND 0x00 #define PORT_DIRECTION 0x01 #define PORT_SET 0x02 #define PORT_GET 0x03 #define PORT_SETBIT 0x04 #define PORT_GETBIT 0x05 #define WRITE_TDI 0x06 #define READ_TDO 0x07 #define WRITE_AND_READ 0x08 #define WRITE_TMS 0x09 #define WRITE_TMS_CHAIN 0x0A struct usbprog_jtag { struct libusb_device_handle *usb_handle; }; static struct usbprog_jtag *usbprog_jtag_handle; static struct usbprog_jtag *usbprog_jtag_open(void); /* static void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag); */ static void usbprog_jtag_init(struct usbprog_jtag *usbprog_jtag); static unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen); static void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char *buffer, int size); static void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char *buffer, int size); static void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char *buffer, int size); static void usbprog_jtag_write_tms(struct usbprog_jtag *usbprog_jtag, char tms_scan); static char tms_chain[64]; static int tms_chain_index; static void usbprog_jtag_tms_collect(char tms_scan); static void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag); static void usbprog_write(int tck, int tms, int tdi); static void usbprog_reset(int trst, int srst); static void usbprog_jtag_set_direction(struct usbprog_jtag *usbprog_jtag, unsigned char direction); static void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag, unsigned char value); /* static unsigned char usbprog_jtag_get_port(struct usbprog_jtag *usbprog_jtag); */ static void usbprog_jtag_set_bit(struct usbprog_jtag *usbprog_jtag, int bit, int value); /* static int usbprog_jtag_get_bit(struct usbprog_jtag *usbprog_jtag, int bit); */ static int usbprog_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; while (cmd) { switch (cmd->type) { case JTAG_RESET: LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); if (cmd->cmd.reset->trst == 1) tap_set_state(TAP_RESET); usbprog_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); usbprog_end_state(cmd->cmd.runtest->end_state); usbprog_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); usbprog_end_state(cmd->cmd.statemove->end_state); usbprog_state_move(); break; case JTAG_PATHMOVE: LOG_DEBUG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); usbprog_path_move(cmd->cmd.pathmove); break; case JTAG_SCAN: LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); usbprog_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); usbprog_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) return ERROR_JTAG_QUEUE_FAILED; free(buffer); break; case JTAG_SLEEP: LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); jtag_sleep(cmd->cmd.sleep->us); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } return ERROR_OK; } static int usbprog_init(void) { usbprog_jtag_handle = usbprog_jtag_open(); tms_chain_index = 0; if (!usbprog_jtag_handle) { LOG_ERROR("Can't find USB JTAG Interface! Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; } LOG_INFO("USB JTAG Interface ready!"); usbprog_jtag_init(usbprog_jtag_handle); usbprog_reset(0, 0); usbprog_write(0, 0, 0); return ERROR_OK; } static int usbprog_quit(void) { return ERROR_OK; } /*************** jtag execute commands **********************/ static void usbprog_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } static void usbprog_state_move(void) { uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); usbprog_jtag_write_tms(usbprog_jtag_handle, (char)tms_scan); tap_set_state(tap_get_end_state()); } static void usbprog_path_move(struct pathmove_command *cmd) { int num_states = cmd->num_states; int state_count; /* There may be queued transitions, and before following a specified path, we must flush those queued transitions */ usbprog_jtag_tms_send(usbprog_jtag_handle); state_count = 0; while (num_states) { if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) { /* LOG_INFO("1"); */ usbprog_write(0, 0, 0); usbprog_write(1, 0, 0); } else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count]) { /* LOG_INFO("2"); */ usbprog_write(0, 1, 0); usbprog_write(1, 1, 0); } else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(cmd->path[state_count])); exit(-1); } tap_set_state(cmd->path[state_count]); state_count++; num_states--; } tap_set_end_state(tap_get_state()); } static void usbprog_runtest(int num_cycles) { int i; /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { usbprog_end_state(TAP_IDLE); usbprog_state_move(); } /* execute num_cycles */ if (num_cycles > 0) { usbprog_jtag_tms_send(usbprog_jtag_handle); usbprog_write(0, 0, 0); } else { usbprog_jtag_tms_send(usbprog_jtag_handle); /* LOG_INFO("NUM CYCLES %i",num_cycles); */ } for (i = 0; i < num_cycles; i++) { usbprog_write(1, 0, 0); usbprog_write(0, 0, 0); } LOG_DEBUG_IO("runtest: cur_state %s end_state %s", tap_state_name( tap_get_state()), tap_state_name(tap_get_end_state())); /* finish in end_state */ /* usbprog_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) usbprog_state_move(); */ } static void usbprog_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size) { tap_state_t saved_end_state = tap_get_end_state(); if (ir_scan) usbprog_end_state(TAP_IRSHIFT); else usbprog_end_state(TAP_DRSHIFT); /* Only move if we're not already there */ if (tap_get_state() != tap_get_end_state()) usbprog_state_move(); usbprog_end_state(saved_end_state); usbprog_jtag_tms_send(usbprog_jtag_handle); void (*f)(struct usbprog_jtag *usbprog_jtag, char *buffer_local, int size); switch (type) { case SCAN_OUT: f = &usbprog_jtag_write_tdi; break; case SCAN_IN: f = &usbprog_jtag_read_tdo; break; case SCAN_IO: f = &usbprog_jtag_write_and_read; break; default: LOG_ERROR("unknown scan type: %i", type); exit(-1); } f(usbprog_jtag_handle, (char *)buffer, scan_size); /* The adapter does the transition to PAUSE internally */ if (ir_scan) tap_set_state(TAP_IRPAUSE); else tap_set_state(TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) usbprog_state_move(); } /*************** jtag wrapper functions *********************/ static void usbprog_write(int tck, int tms, int tdi) { unsigned char output_value = 0x00; if (tms) output_value |= (1 << TMS_BIT); if (tdi) output_value |= (1 << TDI_BIT); if (tck) output_value |= (1 << TCK_BIT); usbprog_jtag_write_slice(usbprog_jtag_handle, output_value); } /* (1) assert or (0) deassert reset lines */ static void usbprog_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); if (trst) usbprog_jtag_set_bit(usbprog_jtag_handle, 5, 0); else usbprog_jtag_set_bit(usbprog_jtag_handle, 5, 1); if (srst) usbprog_jtag_set_bit(usbprog_jtag_handle, 4, 0); else usbprog_jtag_set_bit(usbprog_jtag_handle, 4, 1); } /*************** jtag lowlevel functions ********************/ struct usbprog_jtag *usbprog_jtag_open(void) { const uint16_t vids[] = { VID, 0 }; const uint16_t pids[] = { PID, 0 }; struct libusb_device_handle *dev; if (jtag_libusb_open(vids, pids, &dev, NULL) != ERROR_OK) return NULL; struct usbprog_jtag *tmp = malloc(sizeof(struct usbprog_jtag)); tmp->usb_handle = dev; libusb_set_configuration(dev, 1); libusb_claim_interface(dev, 0); libusb_set_interface_alt_setting(dev, 0, 0); return tmp; } #if 0 static void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag) { libusb_close(usbprog_jtag->usb_handle); free(usbprog_jtag); } #endif static unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen) { int transferred; int res = jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, msg, msglen, 100, &transferred); if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) || (msg[0] == 6) || (msg[0] == 0x0A) || (msg[0] == 9)) return 1; if (res == ERROR_OK && transferred == msglen) { /* LOG_INFO("HALLLLOOO %i",(int)msg[0]); */ res = jtag_libusb_bulk_read(usbprog_jtag->usb_handle, 0x82, msg, 2, 100, &transferred); if (res == ERROR_OK && transferred > 0) return (unsigned char)msg[1]; else return -1; } else return -1; return 0; } static void usbprog_jtag_init(struct usbprog_jtag *usbprog_jtag) { usbprog_jtag_set_direction(usbprog_jtag, 0xFE); } static void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char *buffer, int size) { char tmp[64]; /* fastest packet size for usb controller */ int send_bits, bufindex = 0, fillindex = 0, i, loops; char swap; /* 61 byte can be transferred (488 bit) */ while (size > 0) { if (size > 488) { send_bits = 488; size = size - 488; loops = 61; } else { send_bits = size; loops = size / 8; loops++; size = 0; } tmp[0] = WRITE_AND_READ; tmp[1] = (char)(send_bits >> 8); /* high */ tmp[2] = (char)(send_bits); /* low */ for (i = 0; i < loops; i++) { tmp[3 + i] = buffer[bufindex]; bufindex++; } int transferred; int res = jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000, &transferred); if (res == ERROR_OK && transferred == 64) { /* LOG_INFO("HALLLLOOO2 %i",(int)tmp[0]); */ usleep(1); int timeout = 0; while (jtag_libusb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 1000, &transferred) != ERROR_OK) { timeout++; if (timeout > 10) break; } for (i = 0; i < loops; i++) { swap = tmp[3 + i]; buffer[fillindex++] = swap; } } } } static void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char *buffer, int size) { char tmp[64]; /* fastest packet size for usb controller */ int send_bits, fillindex = 0, i, loops; char swap; /* 61 byte can be transferred (488 bit) */ while (size > 0) { if (size > 488) { send_bits = 488; size = size - 488; loops = 61; } else { send_bits = size; loops = size / 8; loops++; size = 0; } tmp[0] = WRITE_AND_READ; tmp[1] = (char)(send_bits >> 8); /* high */ tmp[2] = (char)(send_bits); /* low */ int transferred; jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 3, 1000, &transferred); /* LOG_INFO("HALLLLOOO3 %i",(int)tmp[0]); */ int timeout = 0; usleep(1); while (jtag_libusb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 10, &transferred) != ERROR_OK) { timeout++; if (timeout > 10) break; } for (i = 0; i < loops; i++) { swap = tmp[3 + i]; buffer[fillindex++] = swap; } } } static void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char *buffer, int size) { char tmp[64]; /* fastest packet size for usb controller */ int send_bits, bufindex = 0, i, loops; /* 61 byte can be transferred (488 bit) */ while (size > 0) { if (size > 488) { send_bits = 488; size = size - 488; loops = 61; } else { send_bits = size; loops = size/8; /* if (loops == 0) */ loops++; size = 0; } tmp[0] = WRITE_TDI; tmp[1] = (char)(send_bits >> 8); /* high */ tmp[2] = (char)(send_bits); /* low */ for (i = 0; i < loops; i++) { tmp[3 + i] = buffer[bufindex]; bufindex++; } int transferred; jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000, &transferred); } } static void usbprog_jtag_write_tms(struct usbprog_jtag *usbprog_jtag, char tms_scan) { usbprog_jtag_tms_collect(tms_scan); } static void usbprog_jtag_set_direction(struct usbprog_jtag *usbprog_jtag, unsigned char direction) { char tmp[2]; tmp[0] = PORT_DIRECTION; tmp[1] = (char)direction; usbprog_jtag_message(usbprog_jtag, tmp, 2); } static void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag, unsigned char value) { char tmp[2]; tmp[0] = PORT_SET; tmp[1] = (char)value; usbprog_jtag_message(usbprog_jtag, tmp, 2); } #if 0 static unsigned char usbprog_jtag_get_port(struct usbprog_jtag *usbprog_jtag) { char tmp[2]; tmp[0] = PORT_GET; tmp[1] = 0x00; return usbprog_jtag_message(usbprog_jtag, tmp, 2); } #endif static void usbprog_jtag_set_bit(struct usbprog_jtag *usbprog_jtag, int bit, int value) { char tmp[3]; tmp[0] = PORT_SETBIT; tmp[1] = (char)bit; if (value == 1) tmp[2] = 0x01; else tmp[2] = 0x00; usbprog_jtag_message(usbprog_jtag, tmp, 3); } #if 0 static int usbprog_jtag_get_bit(struct usbprog_jtag *usbprog_jtag, int bit) { char tmp[2]; tmp[0] = PORT_GETBIT; tmp[1] = (char)bit; if (usbprog_jtag_message(usbprog_jtag, tmp, 2) > 0) return 1; else return 0; } #endif static void usbprog_jtag_tms_collect(char tms_scan) { tms_chain[tms_chain_index] = tms_scan; tms_chain_index++; } static void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag) { /* LOG_INFO("TMS SEND"); */ if (tms_chain_index > 0) { char tmp[tms_chain_index + 2]; tmp[0] = WRITE_TMS_CHAIN; tmp[1] = (char)(tms_chain_index); for (int i = 0; i < tms_chain_index + 1; i++) tmp[2 + i] = tms_chain[i]; int transferred; jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, tms_chain_index + 2, 1000, &transferred); tms_chain_index = 0; } } static struct jtag_interface usbprog_interface = { .execute_queue = usbprog_execute_queue, }; struct adapter_driver usbprog_adapter_driver = { .name = "usbprog", .transports = jtag_only, .init = usbprog_init, .quit = usbprog_quit, .jtag_ops = &usbprog_interface, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/vdebug.c ================================================ // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) /* Copyright 2020-2022 Cadence Design Systems, Inc. */ /*! * @file * * @brief the virtual debug interface provides a connection between a sw debugger * and the simulated, emulated core. The openOCD client connects via TCP sockets * with vdebug server and over DPI-based transactor with the emulation or simulation * The vdebug debug driver supports JTAG and DAP-level transports * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include <windows.h> #else #ifdef HAVE_UNISTD_H #include <unistd.h> /* close */ #endif #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif #ifdef HAVE_NETDB_H #include <netdb.h> #endif #endif #include <stdio.h> #ifdef HAVE_STDINT_H #include <stdint.h> #endif #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif #include <stdarg.h> #include <string.h> #include <errno.h> #include "jtag/interface.h" #include "jtag/commands.h" #include "transport/transport.h" #include "target/arm_adi_v5.h" #include "helper/time_support.h" #include "helper/replacements.h" #include "helper/log.h" #include "helper/list.h" #define VD_VERSION 46 #define VD_BUFFER_LEN 4024 #define VD_CHEADER_LEN 24 #define VD_SHEADER_LEN 16 #define VD_MAX_MEMORIES 20 #define VD_POLL_INTERVAL 500 #define VD_SCALE_PSTOMS 1000000000 /** * @brief List of transactor types */ enum { VD_BFM_JTDP = 0x0001, /* transactor DAP JTAG DP */ VD_BFM_SWDP = 0x0002, /* transactor DAP SWD DP */ VD_BFM_AHB = 0x0003, /* transactor AMBA AHB */ VD_BFM_APB = 0x0004, /* transactor AMBA APB */ VD_BFM_AXI = 0x0005, /* transactor AMBA AXI */ VD_BFM_JTAG = 0x0006, /* transactor serial JTAG */ VD_BFM_SWD = 0x0007, /* transactor serial SWD */ }; /** * @brief List of signals that can be read or written by the debugger */ enum { VD_SIG_TCK = 0x0001, /* JTAG clock; tclk */ VD_SIG_TDI = 0x0002, /* JTAG TDI; tdi */ VD_SIG_TMS = 0x0004, /* JTAG TMS; tms */ VD_SIG_RESET = 0x0008, /* DUT reset; rst */ VD_SIG_TRST = 0x0010, /* JTAG Reset; trstn */ VD_SIG_TDO = 0x0020, /* JTAG TDO; tdo */ VD_SIG_POWER = 0x0100, /* BFM power; bfm_up */ VD_SIG_TCKDIV = 0x0200, /* JTAG clock divider; tclkdiv */ VD_SIG_BUF = 0x1000, /* memory buffer; mem */ }; /** * @brief List of errors */ enum { VD_ERR_NONE = 0x0000, /* no error */ VD_ERR_NOT_IMPL = 0x0100, /* feature not implemented */ VD_ERR_USAGE = 0x0101, /* incorrect usage */ VD_ERR_PARAM = 0x0102, /* incorrect parameter */ VD_ERR_CONFIG = 0x0107, /* incorrect configuration */ VD_ERR_NO_MEMORY = 0x0104, /* out of memory */ VD_ERR_SHM_OPEN = 0x010a, /* cannot open shared memory */ VD_ERR_SHM_MAP = 0x010b, /* cannot map shared memory */ VD_ERR_SOC_OPEN = 0x011a, /* cannot open socket */ VD_ERR_SOC_OPT = 0x011b, /* cannot set socket option */ VD_ERR_SOC_ADDR = 0x011c, /* cannot resolve host address */ VD_ERR_SOC_CONN = 0x011d, /* cannot connect to host */ VD_ERR_SOC_SEND = 0x011e, /* error sending data on socket */ VD_ERR_SOC_RECV = 0x011f, /* error receiving data from socket */ VD_ERR_LOCKED = 0x0202, /* device locked */ VD_ERR_NOT_RUN = 0x0204, /* transactor not running */ VD_ERR_NOT_OPEN = 0x0205, /* transactor not open/connected */ VD_ERR_LICENSE = 0x0206, /* cannot check out the license */ VD_ERR_VERSION = 0x0207, /* transactor version mismatch */ VD_ERR_TIME_OUT = 0x0301, /* time out, waiting */ VD_ERR_NO_POWER = 0x0302, /* power out error */ VD_ERR_BUS_ERROR = 0x0304, /* bus protocol error, like pslverr */ VD_ERR_NO_ACCESS = 0x0306, /* no access to an object */ VD_ERR_INV_HANDLE = 0x0307, /* invalid object handle */ VD_ERR_INV_SCOPE = 0x0308, /* invalid scope */ }; enum { VD_CMD_OPEN = 0x01, VD_CMD_CLOSE = 0x02, VD_CMD_CONNECT = 0x04, VD_CMD_DISCONNECT = 0x05, VD_CMD_WAIT = 0x09, VD_CMD_SIGSET = 0x0a, VD_CMD_SIGGET = 0x0b, VD_CMD_JTAGCLOCK = 0x0f, VD_CMD_REGWRITE = 0x15, VD_CMD_REGREAD = 0x16, VD_CMD_JTAGSHTAP = 0x1a, VD_CMD_MEMOPEN = 0x21, VD_CMD_MEMCLOSE = 0x22, VD_CMD_MEMWRITE = 0x23, }; enum { VD_ASPACE_AP = 0x01, VD_ASPACE_DP = 0x02, VD_ASPACE_ID = 0x03, VD_ASPACE_AB = 0x04, }; enum { VD_BATCH_NO = 0, VD_BATCH_WO = 1, VD_BATCH_WR = 2, }; struct vd_shm { struct { /* VD_CHEADER_LEN written by client */ uint8_t cmd; /* 000; command */ uint8_t type; /* 001; interface type */ uint8_t waddr[2]; /* 002; write pointer */ uint8_t wbytes[2]; /* 004; data bytes */ uint8_t rbytes[2]; /* 006; data bytes to read */ uint8_t wwords[2]; /* 008; data words */ uint8_t rwords[2]; /* 00a; data words to read */ uint8_t rwdata[4]; /* 00c; read/write data */ uint8_t offset[4]; /* 010; address offset */ uint8_t offseth[2]; /* 014; address offset 47:32 */ uint8_t wid[2]; /* 016; request id*/ }; uint8_t wd8[VD_BUFFER_LEN]; /* 018; */ struct { /* VD_SHEADER_LEN written by server */ uint8_t rid[2]; /* fd0: request id read */ uint8_t awords[2]; /* fd2: actual data words read back */ uint8_t status[4]; /* fd4; */ uint8_t duttime[8]; /* fd8; */ }; uint8_t rd8[VD_BUFFER_LEN]; /* fe0: */ uint8_t state[4]; /* 1f98; connection state */ uint8_t count[4]; /* 1f9c; */ uint8_t dummy[96]; /* 1fa0; 48+40B+8B; */ } __attribute__((packed)); struct vd_rdata { struct list_head lh; uint8_t *rdata; }; struct vd_client { uint8_t trans_batch; bool trans_first; bool trans_last; uint8_t mem_ndx; uint8_t buf_width; uint8_t addr_bits; uint8_t bfm_type; uint16_t sig_read; uint16_t sig_write; uint32_t bfm_period; uint32_t mem_base[VD_MAX_MEMORIES]; uint32_t mem_size[VD_MAX_MEMORIES]; uint32_t mem_width[VD_MAX_MEMORIES]; uint32_t mem_depth[VD_MAX_MEMORIES]; uint16_t server_port; uint32_t poll_cycles; uint32_t poll_min; uint32_t poll_max; uint32_t targ_time; int hsocket; char server_name[32]; char bfm_path[128]; char mem_path[VD_MAX_MEMORIES][128]; struct vd_rdata rdataq; }; struct vd_jtag_hdr { uint64_t tlen:24; uint64_t post:3; uint64_t pre:3; uint64_t cmd:2; uint64_t wlen:16; uint64_t rlen:16; }; struct vd_reg_hdr { uint64_t prot:3; uint64_t nonincr:1; uint64_t haddr:12; uint64_t tlen:11; uint64_t asize:3; uint64_t cmd:2; uint64_t addr:32; }; static struct vd_shm *pbuf; static struct vd_client vdc; static int vdebug_socket_error(void) { #ifdef _WIN32 return WSAGetLastError(); #else return errno; #endif } static int vdebug_socket_open(char *server_addr, uint32_t port) { int hsock; int rc = 0; uint32_t buflen = sizeof(struct vd_shm); /* size of the send and rcv buffer */ struct addrinfo *ainfo = NULL; struct addrinfo ahint = { 0, AF_INET, SOCK_STREAM, 0, 0, NULL, NULL, NULL }; #ifdef _WIN32 hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (hsock == INVALID_SOCKET) rc = vdebug_socket_error(); #else uint32_t rcvwat = VD_SHEADER_LEN; /* size of the rcv header, as rcv min watermark */ hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (hsock < 0) rc = errno; else if (setsockopt(hsock, SOL_SOCKET, SO_RCVLOWAT, &rcvwat, sizeof(rcvwat)) < 0) rc = errno; #endif else if (setsockopt(hsock, SOL_SOCKET, SO_SNDBUF, (const char *)&buflen, sizeof(buflen)) < 0) rc = vdebug_socket_error(); else if (setsockopt(hsock, SOL_SOCKET, SO_RCVBUF, (const char *)&buflen, sizeof(buflen)) < 0) rc = vdebug_socket_error(); if (rc) { LOG_ERROR("socket_open: cannot set socket option, error %d", rc); } else if (getaddrinfo(server_addr, NULL, &ahint, &ainfo) != 0) { LOG_ERROR("socket_open: cannot resolve address %s, error %d", server_addr, vdebug_socket_error()); rc = VD_ERR_SOC_ADDR; } else { h_u16_to_be((uint8_t *)ainfo->ai_addr->sa_data, port); if (connect(hsock, ainfo->ai_addr, sizeof(struct sockaddr)) < 0) { LOG_ERROR("socket_open: cannot connect to %s:%d, error %d", server_addr, port, vdebug_socket_error()); rc = VD_ERR_SOC_CONN; } } if (rc) { close_socket(hsock); hsock = 0; } if (ainfo) freeaddrinfo(ainfo); return hsock; } static int vdebug_socket_receive(int hsock, struct vd_shm *pmem) { int rc; int dreceived = 0; int offset = &pmem->rid[0] - &pmem->cmd; int to_receive = VD_SHEADER_LEN + le_to_h_u16(pmem->rbytes); char *pb = (char *)pmem; do { rc = recv(hsock, pb + offset, to_receive, 0); if (rc <= 0) { LOG_WARNING("socket_receive: recv failed, error %d", rc < 0 ? vdebug_socket_error() : 0); return rc; } to_receive -= rc; offset += rc; LOG_DEBUG_IO("socket_receive: received %d, to receive %d", rc, to_receive); dreceived += rc; } while (to_receive); return dreceived; } static int vdebug_socket_send(int hsock, struct vd_shm *pmem) { int rc = send(hsock, (const char *)&pmem->cmd, VD_CHEADER_LEN + le_to_h_u16(pmem->wbytes), 0); if (rc <= 0) LOG_WARNING("socket_send: send failed, error %d", vdebug_socket_error()); else LOG_DEBUG_IO("socket_send: sent %d, to send 0", rc); return rc; } static uint32_t vdebug_wait_server(int hsock, struct vd_shm *pmem) { if (!hsock) return VD_ERR_SOC_OPEN; int st = vdebug_socket_send(hsock, pmem); if (st <= 0) return VD_ERR_SOC_SEND; int rd = vdebug_socket_receive(hsock, pmem); if (rd <= 0) return VD_ERR_SOC_RECV; int rc = le_to_h_u32(pmem->status); LOG_DEBUG_IO("wait_server: cmd %02" PRIx8 " done, sent %d, rcvd %d, status %d", pmem->cmd, st, rd, rc); return rc; } static int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count) { uint8_t num_pre, num_post, tdi, tms; unsigned int num, anum, bytes, hwords, words; unsigned int req, waddr, rwords; int64_t ts, te; uint8_t *tdo; int rc; uint64_t jhdr; struct vd_rdata *rd; req = 0; /* beginning of request */ waddr = 0; rwords = 0; h_u16_to_le(pm->wbytes, le_to_h_u16(pm->wwords) * vdc.buf_width); h_u16_to_le(pm->rbytes, le_to_h_u16(pm->rwords) * vdc.buf_width); ts = timeval_ms(); rc = vdebug_wait_server(hsock, pm); while (!rc && (req < count)) { /* loop over requests to read data and print out */ jhdr = le_to_h_u64(&pm->wd8[waddr * 4]); words = jhdr >> 48; hwords = (jhdr >> 32) & 0xffff; anum = jhdr & 0xffffff; num_pre = (jhdr >> 27) & 0x7; num_post = (jhdr >> 24) & 0x7; if (num_post) num = anum - num_pre - num_post + 1; else num = anum - num_pre; bytes = (num + 7) / 8; vdc.trans_last = (req + 1) < count ? 0 : 1; vdc.trans_first = waddr ? 0 : 1; if (((jhdr >> 30) & 0x3) == 3) { /* cmd is read */ if (!rwords) { rd = &vdc.rdataq; tdo = rd->rdata; } else { rd = list_first_entry(&vdc.rdataq.lh, struct vd_rdata, lh); tdo = rd->rdata; list_del(&rd->lh); free(rd); } for (unsigned int j = 0; j < bytes; j++) { tdo[j] = (pm->rd8[rwords * 8 + j] >> num_pre) | (pm->rd8[rwords * 8 + j + 1] << (8 - num_pre)); LOG_DEBUG_IO("%04x D0[%02x]:%02x", le_to_h_u16(pm->wid) - count + req, j, tdo[j]); } rwords += words; /* read data offset */ } else { tdo = NULL; } waddr += sizeof(uint64_t) / 4; /* waddr past header */ tdi = (pm->wd8[waddr * 4] >> num_pre) | (pm->wd8[waddr * 4 + 1] << (8 - num_pre)); tms = (pm->wd8[waddr * 4 + 4] >> num_pre) | (pm->wd8[waddr * 4 + 4 + 1] << (8 - num_pre)); LOG_DEBUG_IO("%04x L:%02d O:%05x @%03x DI:%02x MS:%02x DO:%02x", le_to_h_u16(pm->wid) - count + req, num, (vdc.trans_first << 14) | (vdc.trans_last << 15), waddr - 2, tdi, tms, (tdo ? tdo[0] : 0xdd)); waddr += hwords * 2; /* start of next request */ req += 1; } if (rc) { LOG_ERROR("0x%x executing transaction", rc); rc = ERROR_FAIL; } te = timeval_ms(); vdc.targ_time += (uint32_t)(te - ts); h_u16_to_le(pm->offseth, 0); /* reset buffer write address */ h_u32_to_le(pm->offset, 0); h_u16_to_le(pm->rwords, 0); h_u16_to_le(pm->waddr, 0); assert(list_empty(&vdc.rdataq.lh));/* list should be empty after run queue */ return rc; } static int vdebug_run_reg_queue(int hsock, struct vd_shm *pm, unsigned int count) { unsigned int num, awidth, wwidth; unsigned int req, waddr, rwords; uint8_t aspace; uint32_t addr; int64_t ts, te; uint8_t *data; int rc; uint64_t rhdr; struct vd_rdata *rd; req = 0; /* beginning of request */ waddr = 0; rwords = 0; h_u16_to_le(pm->wbytes, le_to_h_u16(pm->wwords) * vdc.buf_width); h_u16_to_le(pm->rbytes, le_to_h_u16(pm->rwords) * vdc.buf_width); ts = timeval_ms(); rc = vdebug_wait_server(hsock, pm); while (!rc && (req < count)) { /* loop over requests to read data and print out */ rhdr = le_to_h_u64(&pm->wd8[waddr * 4]); addr = rhdr >> 32; /* reconstruct data for a single request */ num = (rhdr >> 16) & 0x7ff; aspace = rhdr & 0x3; awidth = (1 << ((rhdr >> 27) & 0x7)); wwidth = (awidth + vdc.buf_width - 1) / vdc.buf_width; vdc.trans_last = (req + 1) < count ? 0 : 1; vdc.trans_first = waddr ? 0 : 1; if (((rhdr >> 30) & 0x3) == 2) { /* cmd is read */ if (num) { if (!rwords) { rd = &vdc.rdataq; data = rd->rdata; } else { rd = list_first_entry(&vdc.rdataq.lh, struct vd_rdata, lh); data = rd->rdata; list_del(&rd->lh); free(rd); } for (unsigned int j = 0; j < num; j++) memcpy(&data[j * awidth], &pm->rd8[(rwords + j) * awidth], awidth); } LOG_DEBUG_IO("read %04x AS:%02x RG:%02x O:%05x @%03x D:%08x", le_to_h_u16(pm->wid) - count + req, aspace, addr, (vdc.trans_first << 14) | (vdc.trans_last << 15), waddr, (num ? le_to_h_u32(&pm->rd8[rwords * 4]) : 0xdead)); rwords += num * wwidth; waddr += sizeof(uint64_t) / 4; /* waddr past header */ } else { LOG_DEBUG_IO("write %04x AS:%02x RG:%02x O:%05x @%03x D:%08x", le_to_h_u16(pm->wid) - count + req, aspace, addr, (vdc.trans_first << 14) | (vdc.trans_last << 15), waddr, le_to_h_u32(&pm->wd8[(waddr + num + 1) * 4])); waddr += sizeof(uint64_t) / 4 + (num * wwidth * awidth + 3) / 4; } req += 1; } if (rc) { LOG_ERROR("0x%x executing transaction", rc); rc = ERROR_FAIL; } te = timeval_ms(); vdc.targ_time += (uint32_t)(te - ts); h_u16_to_le(pm->offseth, 0); /* reset buffer write address */ h_u32_to_le(pm->offset, 0); h_u16_to_le(pm->rwords, 0); h_u16_to_le(pm->waddr, 0); assert(list_empty(&vdc.rdataq.lh));/* list should be empty after run queue */ return rc; } static int vdebug_open(int hsock, struct vd_shm *pm, const char *path, uint8_t type, uint32_t period_ps, uint32_t sig_mask) { int rc = VD_ERR_NOT_OPEN; pm->cmd = VD_CMD_OPEN; h_u16_to_le(pm->wid, VD_VERSION); /* client version */ h_u16_to_le(pm->wbytes, 0); h_u16_to_le(pm->rbytes, 0); h_u16_to_le(pm->wwords, 0); h_u16_to_le(pm->rwords, 0); rc = vdebug_wait_server(hsock, pm); if (rc != 0) { /* communication problem */ LOG_ERROR("0x%x connecting to server", rc); } else if (le_to_h_u16(pm->rid) < le_to_h_u16(pm->wid)) { LOG_ERROR("server version %d too old for the client %d", le_to_h_u16(pm->rid), le_to_h_u16(pm->wid)); pm->cmd = VD_CMD_CLOSE; /* let server close the connection */ vdebug_wait_server(hsock, pm); rc = VD_ERR_VERSION; } else { pm->cmd = VD_CMD_CONNECT; pm->type = type; /* BFM type to connect to, here JTAG */ h_u32_to_le(pm->rwdata, sig_mask | VD_SIG_BUF | (VD_SIG_BUF << 16)); h_u16_to_le(pm->wbytes, strlen(path) + 1); h_u16_to_le(pm->rbytes, 12); h_u16_to_le(pm->wid, 0); /* reset wid for transaction ID */ h_u16_to_le(pm->wwords, 0); h_u16_to_le(pm->rwords, 0); memcpy(pm->wd8, path, le_to_h_u16(pm->wbytes)); rc = vdebug_wait_server(hsock, pm); vdc.sig_read = le_to_h_u32(pm->rwdata) >> 16; /* signal read mask */ vdc.sig_write = le_to_h_u32(pm->rwdata); /* signal write mask */ vdc.bfm_period = period_ps; vdc.buf_width = le_to_h_u32(&pm->rd8[0]) / 8;/* access width in bytes */ vdc.addr_bits = le_to_h_u32(&pm->rd8[2 * 4]); /* supported address bits */ } if (rc) { LOG_ERROR("0x%x connecting to BFM %s", rc, path); return ERROR_FAIL; } INIT_LIST_HEAD(&vdc.rdataq.lh); LOG_DEBUG("%s type %0x, period %dps, buffer %dx%dB signals r%04xw%04x", path, type, vdc.bfm_period, VD_BUFFER_LEN / vdc.buf_width, vdc.buf_width, vdc.sig_read, vdc.sig_write); return ERROR_OK; } static int vdebug_close(int hsock, struct vd_shm *pm, uint8_t type) { pm->cmd = VD_CMD_DISCONNECT; pm->type = type; /* BFM type, here JTAG */ h_u16_to_le(pm->wbytes, 0); h_u16_to_le(pm->rbytes, 0); h_u16_to_le(pm->wwords, 0); h_u16_to_le(pm->rwords, 0); vdebug_wait_server(hsock, pm); pm->cmd = VD_CMD_CLOSE; h_u16_to_le(pm->wid, VD_VERSION); /* client version */ h_u16_to_le(pm->wbytes, 0); h_u16_to_le(pm->rbytes, 0); h_u16_to_le(pm->wwords, 0); h_u16_to_le(pm->rwords, 0); vdebug_wait_server(hsock, pm); LOG_DEBUG("type %0x", type); return ERROR_OK; } static int vdebug_wait(int hsock, struct vd_shm *pm, uint32_t cycles) { if (cycles) { pm->cmd = VD_CMD_WAIT; h_u16_to_le(pm->wbytes, 0); h_u16_to_le(pm->rbytes, 0); h_u32_to_le(pm->rwdata, cycles); /* clock sycles to wait */ int rc = vdebug_wait_server(hsock, pm); if (rc) { LOG_ERROR("0x%x waiting %" PRIx32 " cycles", rc, cycles); return ERROR_FAIL; } LOG_DEBUG("%d cycles", cycles); } return ERROR_OK; } static int vdebug_sig_set(int hsock, struct vd_shm *pm, uint32_t write_mask, uint32_t value) { pm->cmd = VD_CMD_SIGSET; h_u16_to_le(pm->wbytes, 0); h_u16_to_le(pm->rbytes, 0); h_u32_to_le(pm->rwdata, (write_mask << 16) | (value & 0xffff)); /* mask and value of signals to set */ int rc = vdebug_wait_server(hsock, pm); if (rc) { LOG_ERROR("0x%x setting signals %04" PRIx32, rc, write_mask); return ERROR_FAIL; } LOG_DEBUG("setting signals %04" PRIx32 " to %04" PRIx32, write_mask, value); return ERROR_OK; } static int vdebug_jtag_clock(int hsock, struct vd_shm *pm, uint32_t value) { pm->cmd = VD_CMD_JTAGCLOCK; h_u16_to_le(pm->wbytes, 0); h_u16_to_le(pm->rbytes, 0); h_u32_to_le(pm->rwdata, value); /* divider value */ int rc = vdebug_wait_server(hsock, pm); if (rc) { LOG_ERROR("0x%x setting jtag_clock", rc); return ERROR_FAIL; } LOG_DEBUG("setting jtag clock divider to %" PRIx32, value); return ERROR_OK; } static int vdebug_jtag_shift_tap(int hsock, struct vd_shm *pm, uint8_t num_pre, const uint8_t tms_pre, uint32_t num, const uint8_t *tdi, uint8_t num_post, const uint8_t tms_post, uint8_t *tdo, uint8_t f_last) { const uint32_t tobits = 8; uint16_t bytes, hwords, anum, words, waddr; int rc = 0; pm->cmd = VD_CMD_JTAGSHTAP; vdc.trans_last = f_last || (vdc.trans_batch == VD_BATCH_NO); if (vdc.trans_first) waddr = 0; /* reset buffer offset */ else waddr = le_to_h_u32(pm->offseth); /* continue from the previous transaction */ if (num_post) /* actual number of bits to shift */ anum = num + num_pre + num_post - 1; else anum = num + num_pre; hwords = (anum + 4 * vdc.buf_width - 1) / (4 * vdc.buf_width); /* in 4B TDI/TMS words */ words = (hwords + 1) / 2; /* in 8B TDO words to read */ bytes = (num + 7) / 8; /* data only portion in bytes */ /* buffer overflow check and flush */ if (4 * waddr + sizeof(uint64_t) + 8 * hwords + 64 > VD_BUFFER_LEN) { vdc.trans_last = 1; /* force flush within 64B of buffer end */ } else if (4 * waddr + sizeof(uint64_t) + 8 * hwords > VD_BUFFER_LEN) { /* this req does not fit, discard it */ LOG_ERROR("%04x L:%02d O:%05x @%04x too many bits to shift", le_to_h_u16(pm->wid), anum, (vdc.trans_first << 14) | (vdc.trans_last << 15), waddr); rc = ERROR_FAIL; } if (!rc && anum) { uint16_t i, j; /* portability requires to use bit operations for 8B JTAG header */ uint64_t jhdr = (tdo ? ((uint64_t)(words) << 48) : 0) + ((uint64_t)(hwords) << 32) + ((tdo ? 3UL : 1UL) << 30) + (num_pre << 27) + (num_post << 24) + anum; h_u64_to_le(&pm->wd8[4 * waddr], jhdr); h_u16_to_le(pm->wid, le_to_h_u16(pm->wid) + 1); /* transaction ID */ waddr += 2; /* waddr past header */ /* TDI/TMS data follows as 32 bit word pairs {TMS,TDI} */ pm->wd8[4 * waddr] = (tdi ? (tdi[0] << num_pre) : 0); pm->wd8[4 * waddr + 4] = tms_pre; /* init with tms_pre */ if (num + num_pre <= 8) /* and tms_post for num <=4 */ pm->wd8[4 * waddr + 4] |= (tms_post << (num + num_pre - 1)); for (i = 1, j = 4 * waddr; i < bytes; i++) { if (i == bytes - 1 && num + num_pre <= bytes * tobits) pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8); else pm->wd8[j + i + 4] = 0x0;/* placing 4 bytes of TMS bits into high word */ if (!tdi) /* placing 4 bytes of TDI bits into low word */ pm->wd8[j + i] = 0x0; else pm->wd8[j + i] = (tdi[i] << num_pre) | (tdi[i - 1] >> (8 - num_pre)); if (i % 4 == 3) j += 4; } if (tdi) if (num + num_pre > bytes * tobits) /* in case 1 additional byte needed for TDI */ pm->wd8[j + i] = (tdi[i - 1] >> (8 - num_pre)); /* put last TDI bits there */ if (num + num_pre <= bytes * tobits) { /* in case no or 1 additional byte needed */ pm->wd8[j + i + 4] = tms_post >> (8 - (num + num_pre - 1) % 8); /* may need to add higher part */ /* in case exactly 1 additional byte needed */ } else if (num + num_pre > bytes * tobits && anum <= (bytes + 1) * tobits) { pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8); /* add whole tms_post */ } else { /* in case 2 additional bytes, tms_post split */ pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8);/* add lower part of tms_post */ if (i % 4 == 3) /* next byte is in the next 32b word */ pm->wd8[j + i + 4 + 5] = tms_post >> (8 - (num + num_pre - 1) % 8); /* and higher part */ else /* next byte is in the same 32b word */ pm->wd8[j + i + 4 + 1] = tms_post >> (8 - (num + num_pre - 1) % 8); /* and higher part */ } if (tdo) { struct vd_rdata *rd; if (le_to_h_u16(pm->rwords) == 0) { rd = &vdc.rdataq; } else { rd = calloc(1, sizeof(struct vd_rdata)); if (!rd) /* check allocation for 24B */ return ERROR_FAIL; list_add_tail(&rd->lh, &vdc.rdataq.lh); } rd->rdata = tdo; h_u16_to_le(pm->rwords, le_to_h_u16(pm->rwords) + words);/* keep track of the words to read */ } h_u16_to_le(pm->wwords, waddr / 2 + hwords); /* payload size *2 to include both TDI and TMS data */ h_u16_to_le(pm->waddr, le_to_h_u16(pm->waddr) + 1); } if (!waddr) /* flush issued, but buffer empty */ ; else if (!vdc.trans_last) /* buffered request */ h_u16_to_le(pm->offseth, waddr + hwords * 2); /* offset for next transaction, must be even */ else /* execute batch of requests */ rc = vdebug_run_jtag_queue(hsock, pm, le_to_h_u16(pm->waddr)); vdc.trans_first = vdc.trans_last; /* flush forces trans_first flag */ return rc; } static int vdebug_reg_write(int hsock, struct vd_shm *pm, const uint32_t reg, const uint32_t data, uint8_t aspace, uint8_t f_last) { uint32_t waddr; int rc = ERROR_OK; pm->cmd = VD_CMD_REGWRITE; vdc.trans_last = f_last || (vdc.trans_batch == VD_BATCH_NO); if (vdc.trans_first) waddr = 0; /* reset buffer offset */ else waddr = le_to_h_u16(pm->offseth); /* continue from the previous transaction */ if (4 * waddr + 2 * sizeof(uint64_t) + 4 > VD_BUFFER_LEN) vdc.trans_last = 1; /* force flush, no room for next request */ uint64_t rhdr = ((uint64_t)reg << 32) + (1UL << 30) + (2UL << 27) + (1UL << 16) + aspace; h_u64_to_le(&pm->wd8[4 * waddr], rhdr); h_u32_to_le(&pm->wd8[4 * (waddr + 2)], data); h_u16_to_le(pm->wid, le_to_h_u16(pm->wid) + 1); h_u16_to_le(pm->wwords, waddr + 3); h_u16_to_le(pm->waddr, le_to_h_u16(pm->waddr) + 1); if (!vdc.trans_last) /* buffered request */ h_u16_to_le(pm->offseth, waddr + 3); else rc = vdebug_run_reg_queue(hsock, pm, le_to_h_u16(pm->waddr)); vdc.trans_first = vdc.trans_last; /* flush forces trans_first flag */ return rc; } static int vdebug_reg_read(int hsock, struct vd_shm *pm, const uint32_t reg, uint32_t *data, uint8_t aspace, uint8_t f_last) { uint32_t waddr; int rc = ERROR_OK; pm->cmd = VD_CMD_REGREAD; vdc.trans_last = f_last || (vdc.trans_batch == VD_BATCH_NO); if (vdc.trans_first) waddr = 0; /* reset buffer offset */ else waddr = le_to_h_u16(pm->offseth); /* continue from the previous transaction */ if (4 * waddr + 2 * sizeof(uint64_t) + 4 > VD_BUFFER_LEN) vdc.trans_last = 1; /* force flush, no room for next request */ uint64_t rhdr = ((uint64_t)reg << 32) + (2UL << 30) + (2UL << 27) + ((data ? 1UL : 0UL) << 16) + aspace; h_u64_to_le(&pm->wd8[4 * waddr], rhdr); h_u16_to_le(pm->wid, le_to_h_u16(pm->wid) + 1); if (data) { struct vd_rdata *rd; if (le_to_h_u16(pm->rwords) == 0) { rd = &vdc.rdataq; } else { rd = calloc(1, sizeof(struct vd_rdata)); if (!rd) /* check allocation for 24B */ return ERROR_FAIL; list_add_tail(&rd->lh, &vdc.rdataq.lh); } rd->rdata = (uint8_t *)data; h_u16_to_le(pm->rwords, le_to_h_u16(pm->rwords) + 1); } h_u16_to_le(pm->wwords, waddr + 2); h_u16_to_le(pm->waddr, le_to_h_u16(pm->waddr) + 1); if (!vdc.trans_last) /* buffered request */ h_u16_to_le(pm->offseth, waddr + 2); else rc = vdebug_run_reg_queue(hsock, pm, le_to_h_u16(pm->waddr)); vdc.trans_first = vdc.trans_last; /* flush forces trans_first flag */ return rc; } static int vdebug_mem_open(int hsock, struct vd_shm *pm, const char *path, uint8_t ndx) { int rc; if (!path) return ERROR_OK; pm->cmd = VD_CMD_MEMOPEN; h_u16_to_le(pm->wbytes, strlen(path) + 1); /* includes terminating 0 */ h_u16_to_le(pm->rbytes, 8); h_u16_to_le(pm->wwords, 0); h_u16_to_le(pm->rwords, 0); memcpy(pm->wd8, path, le_to_h_u16(pm->wbytes)); rc = vdebug_wait_server(hsock, pm); if (rc) { LOG_ERROR("0x%x opening memory %s", rc, path); } else if (ndx != pm->rd8[2]) { LOG_WARNING("Invalid memory index %" PRIu16 " returned. Direct memory access disabled", pm->rd8[2]); } else { vdc.mem_width[ndx] = le_to_h_u16(&pm->rd8[0]) / 8; /* memory width in bytes */ vdc.mem_depth[ndx] = le_to_h_u32(&pm->rd8[4]); /* memory depth in words */ LOG_DEBUG("%" PRIx8 ": %s memory %" PRIu32 "x%" PRIu32 "B, buffer %" PRIu32 "x%" PRIu32 "B", ndx, path, vdc.mem_depth[ndx], vdc.mem_width[ndx], VD_BUFFER_LEN / vdc.mem_width[ndx], vdc.mem_width[ndx]); } return ERROR_OK; } static void vdebug_mem_close(int hsock, struct vd_shm *pm, uint8_t ndx) { pm->cmd = VD_CMD_MEMCLOSE; h_u32_to_le(pm->rwdata, ndx); /* which memory */ h_u16_to_le(pm->wbytes, 0); h_u16_to_le(pm->rbytes, 0); h_u16_to_le(pm->wwords, 0); h_u16_to_le(pm->rwords, 0); vdebug_wait_server(hsock, pm); LOG_DEBUG("%" PRIx8 ": %s", ndx, vdc.mem_path[ndx]); } static int vdebug_init(void) { vdc.hsocket = vdebug_socket_open(vdc.server_name, vdc.server_port); pbuf = calloc(1, sizeof(struct vd_shm)); if (!pbuf) { close_socket(vdc.hsocket); vdc.hsocket = 0; LOG_ERROR("cannot allocate %zu bytes", sizeof(struct vd_shm)); return ERROR_FAIL; } if (vdc.hsocket <= 0) { free(pbuf); pbuf = NULL; LOG_ERROR("cannot connect to vdebug server %s:%" PRIu16, vdc.server_name, vdc.server_port); return ERROR_FAIL; } vdc.trans_first = 1; vdc.poll_cycles = vdc.poll_max; uint32_t sig_mask = VD_SIG_RESET; if (transport_is_jtag()) sig_mask |= VD_SIG_TRST | VD_SIG_TCKDIV; int rc = vdebug_open(vdc.hsocket, pbuf, vdc.bfm_path, vdc.bfm_type, vdc.bfm_period, sig_mask); if (rc != 0) { LOG_ERROR("0x%x cannot connect to %s", rc, vdc.bfm_path); close_socket(vdc.hsocket); vdc.hsocket = 0; free(pbuf); pbuf = NULL; } else { for (uint8_t i = 0; i < vdc.mem_ndx; i++) { rc = vdebug_mem_open(vdc.hsocket, pbuf, vdc.mem_path[i], i); if (rc != 0) LOG_ERROR("0x%x cannot connect to %s", rc, vdc.mem_path[i]); } LOG_INFO("vdebug %d connected to %s through %s:%" PRIu16, VD_VERSION, vdc.bfm_path, vdc.server_name, vdc.server_port); } return rc; } static int vdebug_quit(void) { for (uint8_t i = 0; i < vdc.mem_ndx; i++) if (vdc.mem_width[i]) vdebug_mem_close(vdc.hsocket, pbuf, i); int rc = vdebug_close(vdc.hsocket, pbuf, vdc.bfm_type); LOG_INFO("vdebug %d disconnected from %s through %s:%" PRIu16 " rc:%d", VD_VERSION, vdc.bfm_path, vdc.server_name, vdc.server_port, rc); if (vdc.hsocket) close_socket(vdc.hsocket); free(pbuf); pbuf = NULL; return ERROR_OK; } static int vdebug_reset(int trst, int srst) { uint16_t sig_val = 0xffff; uint16_t sig_mask = 0; sig_mask |= VD_SIG_RESET; if (srst) sig_val &= ~VD_SIG_RESET;/* active low */ if (transport_is_jtag()) { sig_mask |= VD_SIG_TRST; if (trst) sig_val &= ~VD_SIG_TRST; /* active low */ } LOG_INFO("rst trst:%d srst:%d mask:%" PRIx16 " val:%" PRIx16, trst, srst, sig_mask, sig_val); int rc = vdebug_sig_set(vdc.hsocket, pbuf, sig_mask, sig_val); if (rc == 0) rc = vdebug_wait(vdc.hsocket, pbuf, 20); /* 20 clock cycles pulse */ return rc; } static int vdebug_jtag_tms_seq(const uint8_t *tms, int num, uint8_t f_flush) { LOG_INFO("tms len:%d tms:%x", num, *tms); return vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num, *tms, 0, NULL, 0, 0, NULL, f_flush); } static int vdebug_jtag_path_move(struct pathmove_command *cmd, uint8_t f_flush) { uint8_t tms[DIV_ROUND_UP(cmd->num_states, 8)]; LOG_INFO("path num states %d", cmd->num_states); memset(tms, 0, DIV_ROUND_UP(cmd->num_states, 8)); for (uint8_t i = 0; i < cmd->num_states; i++) { if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) buf_set_u32(tms, i, 1, 1); tap_set_state(cmd->path[i]); } return vdebug_jtag_tms_seq(tms, cmd->num_states, f_flush); } static int vdebug_jtag_tlr(tap_state_t state, uint8_t f_flush) { int rc = ERROR_OK; tap_state_t cur = tap_get_state(); uint8_t tms_pre = tap_get_tms_path(cur, state); uint8_t num_pre = tap_get_tms_path_len(cur, state); LOG_INFO("tlr from %x to %x", cur, state); if (cur != state) { rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, 0, NULL, 0, 0, NULL, f_flush); tap_set_state(state); } return rc; } static int vdebug_jtag_scan(struct scan_command *cmd, uint8_t f_flush) { int rc = ERROR_OK; tap_state_t cur = tap_get_state(); uint8_t state = cmd->ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT; uint8_t tms_pre = tap_get_tms_path(cur, state); uint8_t num_pre = tap_get_tms_path_len(cur, state); uint8_t tms_post = tap_get_tms_path(state, cmd->end_state); uint8_t num_post = tap_get_tms_path_len(state, cmd->end_state); int num_bits = jtag_scan_size(cmd); LOG_DEBUG("scan len:%d fields:%d ir/!dr:%d state cur:%x end:%x", num_bits, cmd->num_fields, cmd->ir_scan, cur, cmd->end_state); for (int i = 0; i < cmd->num_fields; i++) { uint8_t cur_num_pre = i == 0 ? num_pre : 0; uint8_t cur_tms_pre = i == 0 ? tms_pre : 0; uint8_t cur_num_post = i == cmd->num_fields - 1 ? num_post : 0; uint8_t cur_tms_post = i == cmd->num_fields - 1 ? tms_post : 0; uint8_t cur_flush = i == cmd->num_fields - 1 ? f_flush : 0; rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, cur_num_pre, cur_tms_pre, cmd->fields[i].num_bits, cmd->fields[i].out_value, cur_num_post, cur_tms_post, cmd->fields[i].in_value, cur_flush); if (rc) break; } if (cur != cmd->end_state) tap_set_state(cmd->end_state); return rc; } static int vdebug_jtag_runtest(int cycles, tap_state_t state, uint8_t f_flush) { tap_state_t cur = tap_get_state(); uint8_t tms_pre = tap_get_tms_path(cur, state); uint8_t num_pre = tap_get_tms_path_len(cur, state); LOG_DEBUG("idle len:%d state cur:%x end:%x", cycles, cur, state); int rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, cycles, NULL, 0, 0, NULL, f_flush); if (cur != state) tap_set_state(state); return rc; } static int vdebug_jtag_stableclocks(int num, uint8_t f_flush) { LOG_INFO("stab len:%d state cur:%x", num, tap_get_state()); return vdebug_jtag_shift_tap(vdc.hsocket, pbuf, 0, 0, num, NULL, 0, 0, NULL, f_flush); } static int vdebug_sleep(int us) { LOG_INFO("sleep %d us", us); return vdebug_wait(vdc.hsocket, pbuf, us / 1000); } static int vdebug_jtag_speed(int speed) { unsigned int clkmax = VD_SCALE_PSTOMS / (vdc.bfm_period * 2); /* kHz */ unsigned int divval = clkmax / speed; LOG_INFO("jclk speed:%d kHz set, BFM divider %u", speed, divval); return vdebug_jtag_clock(vdc.hsocket, pbuf, divval); } static int vdebug_jtag_khz(int khz, int *jtag_speed) { unsigned int clkmax = VD_SCALE_PSTOMS / (vdc.bfm_period * 2); /* kHz */ unsigned int divval = khz ? clkmax / khz : 1; *jtag_speed = clkmax / divval; LOG_DEBUG("khz speed:%d from khz:%d", *jtag_speed, khz); return ERROR_OK; } static int vdebug_jtag_div(int speed, int *khz) { *khz = speed; LOG_DEBUG("div khz:%d from speed:%d", *khz, speed); return ERROR_OK; } static int vdebug_jtag_execute_queue(void) { int rc = ERROR_OK; for (struct jtag_command *cmd = jtag_command_queue; rc == ERROR_OK && cmd; cmd = cmd->next) { switch (cmd->type) { case JTAG_RUNTEST: rc = vdebug_jtag_runtest(cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state, !cmd->next); break; case JTAG_STABLECLOCKS: rc = vdebug_jtag_stableclocks(cmd->cmd.stableclocks->num_cycles, !cmd->next); break; case JTAG_TLR_RESET: rc = vdebug_jtag_tlr(cmd->cmd.statemove->end_state, !cmd->next); break; case JTAG_PATHMOVE: rc = vdebug_jtag_path_move(cmd->cmd.pathmove, !cmd->next); break; case JTAG_TMS: rc = vdebug_jtag_tms_seq(cmd->cmd.tms->bits, cmd->cmd.tms->num_bits, !cmd->next); break; case JTAG_SLEEP: rc = vdebug_sleep(cmd->cmd.sleep->us); break; case JTAG_SCAN: rc = vdebug_jtag_scan(cmd->cmd.scan, !cmd->next); break; default: LOG_ERROR("Unknown JTAG command type 0x%x encountered", cmd->type); rc = ERROR_FAIL; } } return rc; } static int vdebug_dap_connect(struct adiv5_dap *dap) { return dap_dp_init(dap); } static int vdebug_dap_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq) { return ERROR_OK; } static int vdebug_dap_queue_dp_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *data) { return vdebug_reg_read(vdc.hsocket, pbuf, (reg & DP_SELECT_DPBANK) >> 2, data, VD_ASPACE_DP, 0); } static int vdebug_dap_queue_dp_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data) { return vdebug_reg_write(vdc.hsocket, pbuf, (reg & DP_SELECT_DPBANK) >> 2, data, VD_ASPACE_DP, 0); } static int vdebug_dap_queue_ap_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data) { if ((reg & DP_SELECT_APBANK) != ap->dap->select) { vdebug_reg_write(vdc.hsocket, pbuf, DP_SELECT >> 2, reg & DP_SELECT_APBANK, VD_ASPACE_DP, 0); ap->dap->select = reg & DP_SELECT_APBANK; } vdebug_reg_read(vdc.hsocket, pbuf, (reg & DP_SELECT_DPBANK) >> 2, NULL, VD_ASPACE_AP, 0); return vdebug_reg_read(vdc.hsocket, pbuf, DP_RDBUFF >> 2, data, VD_ASPACE_DP, 0); } static int vdebug_dap_queue_ap_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data) { if ((reg & DP_SELECT_APBANK) != ap->dap->select) { vdebug_reg_write(vdc.hsocket, pbuf, DP_SELECT >> 2, reg & DP_SELECT_APBANK, VD_ASPACE_DP, 0); ap->dap->select = reg & DP_SELECT_APBANK; } return vdebug_reg_write(vdc.hsocket, pbuf, (reg & DP_SELECT_DPBANK) >> 2, data, VD_ASPACE_AP, 0); } static int vdebug_dap_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) { return vdebug_reg_write(vdc.hsocket, pbuf, 0, 0x1, VD_ASPACE_AB, 0); } static int vdebug_dap_run(struct adiv5_dap *dap) { if (le_to_h_u16(pbuf->waddr)) return vdebug_run_reg_queue(vdc.hsocket, pbuf, le_to_h_u16(pbuf->waddr)); return ERROR_OK; } COMMAND_HANDLER(vdebug_set_server) { if ((CMD_ARGC != 1) || !strchr(CMD_ARGV[0], ':')) return ERROR_COMMAND_SYNTAX_ERROR; char *pchar = strchr(CMD_ARGV[0], ':'); *pchar = '\0'; strncpy(vdc.server_name, CMD_ARGV[0], sizeof(vdc.server_name) - 1); int port = atoi(++pchar); if (port < 0 || port > UINT16_MAX) { LOG_ERROR("invalid port number %d specified", port); return ERROR_COMMAND_SYNTAX_ERROR; } vdc.server_port = port; LOG_DEBUG("server: %s port %u", vdc.server_name, vdc.server_port); return ERROR_OK; } COMMAND_HANDLER(vdebug_set_bfm) { char prefix; if ((CMD_ARGC != 2) || (sscanf(CMD_ARGV[1], "%u%c", &vdc.bfm_period, &prefix) != 2)) return ERROR_COMMAND_SYNTAX_ERROR; strncpy(vdc.bfm_path, CMD_ARGV[0], sizeof(vdc.bfm_path) - 1); switch (prefix) { case 'u': vdc.bfm_period *= 1000000; break; case 'n': vdc.bfm_period *= 1000; break; case 'p': default: break; } if (transport_is_dapdirect_swd()) vdc.bfm_type = VD_BFM_SWDP; else vdc.bfm_type = VD_BFM_JTAG; LOG_DEBUG("bfm_path: %s clk_period %ups", vdc.bfm_path, vdc.bfm_period); return ERROR_OK; } COMMAND_HANDLER(vdebug_set_mem) { if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; if (vdc.mem_ndx >= VD_MAX_MEMORIES) { LOG_ERROR("mem_path declared more than %d allowed times", VD_MAX_MEMORIES); return ERROR_FAIL; } strncpy(vdc.mem_path[vdc.mem_ndx], CMD_ARGV[0], sizeof(vdc.mem_path[vdc.mem_ndx]) - 1); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], vdc.mem_base[vdc.mem_ndx]); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], vdc.mem_size[vdc.mem_ndx]); LOG_DEBUG("mem_path: set %s @ 0x%08x+0x%08x", vdc.mem_path[vdc.mem_ndx], vdc.mem_base[vdc.mem_ndx], vdc.mem_size[vdc.mem_ndx]); vdc.mem_ndx++; return ERROR_OK; } COMMAND_HANDLER(vdebug_set_batching) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; if (isdigit((unsigned char)CMD_ARGV[0][0])) vdc.trans_batch = (CMD_ARGV[0][0] == '0' ? 0 : (CMD_ARGV[0][0] == '1' ? 1 : 2)); else if (CMD_ARGV[0][0] == 'r') vdc.trans_batch = VD_BATCH_WR; else if (CMD_ARGV[0][0] == 'w') vdc.trans_batch = VD_BATCH_WO; else vdc.trans_batch = VD_BATCH_NO; LOG_DEBUG("batching: set to %u", vdc.trans_batch); return ERROR_OK; } COMMAND_HANDLER(vdebug_set_polling) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; vdc.poll_min = atoi(CMD_ARGV[0]); vdc.poll_max = atoi(CMD_ARGV[1]); LOG_DEBUG("polling: set min %u max %u", vdc.poll_min, vdc.poll_max); return ERROR_OK; } static const struct command_registration vdebug_command_handlers[] = { { .name = "server", .handler = &vdebug_set_server, .mode = COMMAND_CONFIG, .help = "set the vdebug server name or address", .usage = "<host:port>", }, { .name = "bfm_path", .handler = &vdebug_set_bfm, .mode = COMMAND_CONFIG, .help = "set the vdebug BFM hierarchical path", .usage = "<path> <clk_period[p|n|u]s>", }, { .name = "mem_path", .handler = &vdebug_set_mem, .mode = COMMAND_CONFIG, .help = "set the design memory for the code load", .usage = "<path> <base_address> <size>", }, { .name = "batching", .handler = &vdebug_set_batching, .mode = COMMAND_CONFIG, .help = "set the transaction batching no|wr|rd [0|1|2]", .usage = "<level>", }, { .name = "polling", .handler = &vdebug_set_polling, .mode = COMMAND_CONFIG, .help = "set the polling pause, executing hardware cycles between min and max", .usage = "<min cycles> <max cycles>", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration vdebug_command[] = { { .name = "vdebug", .chain = vdebug_command_handlers, .mode = COMMAND_ANY, .help = "vdebug command group", .usage = "", }, COMMAND_REGISTRATION_DONE }; static struct jtag_interface vdebug_jtag_ops = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = vdebug_jtag_execute_queue, }; static const struct dap_ops vdebug_dap_ops = { .connect = vdebug_dap_connect, .send_sequence = vdebug_dap_send_sequence, .queue_dp_read = vdebug_dap_queue_dp_read, .queue_dp_write = vdebug_dap_queue_dp_write, .queue_ap_read = vdebug_dap_queue_ap_read, .queue_ap_write = vdebug_dap_queue_ap_write, .queue_ap_abort = vdebug_dap_queue_ap_abort, .run = vdebug_dap_run, .sync = NULL, /* optional */ .quit = NULL, /* optional */ }; static const char *const vdebug_transports[] = { "jtag", "dapdirect_swd", NULL }; struct adapter_driver vdebug_adapter_driver = { .name = "vdebug", .transports = vdebug_transports, .speed = vdebug_jtag_speed, .khz = vdebug_jtag_khz, .speed_div = vdebug_jtag_div, .commands = vdebug_command, .init = vdebug_init, .quit = vdebug_quit, .reset = vdebug_reset, .jtag_ops = &vdebug_jtag_ops, .dap_swd_ops = &vdebug_dap_ops, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/versaloon/usbtoxxx/usbtogpio.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <string.h> #include "../versaloon_include.h" #include "../versaloon.h" #include "../versaloon_internal.h" #include "usbtoxxx.h" #include "usbtoxxx_internal.h" RESULT usbtogpio_init(uint8_t interface_index) { return usbtoxxx_init_command(USB_TO_GPIO, interface_index); } RESULT usbtogpio_fini(uint8_t interface_index) { return usbtoxxx_fini_command(USB_TO_GPIO, interface_index); } RESULT usbtogpio_config(uint8_t interface_index, uint32_t mask, uint32_t dir_mask, uint32_t pull_en_mask, uint32_t input_pull_mask) { uint8_t conf[8]; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif dir_mask &= mask; SET_LE_U16(&conf[0], mask); SET_LE_U16(&conf[2], dir_mask); SET_LE_U16(&conf[4], pull_en_mask); SET_LE_U16(&conf[6], input_pull_mask); return usbtoxxx_conf_command(USB_TO_GPIO, interface_index, conf, sizeof(conf)); } RESULT usbtogpio_in(uint8_t interface_index, uint32_t mask, uint32_t *value) { uint8_t buf[2]; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif SET_LE_U16(&buf[0], mask); return usbtoxxx_in_command(USB_TO_GPIO, interface_index, buf, 2, 2, (uint8_t *)value, 0, 2, 0); } RESULT usbtogpio_out(uint8_t interface_index, uint32_t mask, uint32_t value) { uint8_t buf[4]; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif SET_LE_U16(&buf[0], mask); SET_LE_U16(&buf[2], value); return usbtoxxx_out_command(USB_TO_GPIO, interface_index, buf, 4, 0); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/versaloon/usbtoxxx/usbtojtagraw.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <string.h> #include "../versaloon_include.h" #include "../versaloon.h" #include "../versaloon_internal.h" #include "usbtoxxx.h" #include "usbtoxxx_internal.h" RESULT usbtojtagraw_init(uint8_t interface_index) { return usbtoxxx_init_command(USB_TO_JTAG_RAW, interface_index); } RESULT usbtojtagraw_fini(uint8_t interface_index) { return usbtoxxx_fini_command(USB_TO_JTAG_RAW, interface_index); } RESULT usbtojtagraw_config(uint8_t interface_index, uint32_t khz) { uint8_t cfg_buf[4]; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif SET_LE_U32(&cfg_buf[0], khz); return usbtoxxx_conf_command(USB_TO_JTAG_RAW, interface_index, cfg_buf, 4); } RESULT usbtojtagraw_execute(uint8_t interface_index, uint8_t *tdi, uint8_t *tms, uint8_t *tdo, uint32_t bitlen) { uint16_t bytelen; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif if (bitlen > 8 * 0xFFFF) return ERROR_FAIL; bytelen = (uint16_t)((bitlen + 7) >> 3); SET_LE_U32(&versaloon_cmd_buf[0], bitlen); memcpy(versaloon_cmd_buf + 4, tdi, bytelen); memcpy(versaloon_cmd_buf + 4 + bytelen, tms, bytelen); return usbtoxxx_inout_command(USB_TO_JTAG_RAW, interface_index, versaloon_cmd_buf, 4 + bytelen * 2, bytelen, tdo, 0, bytelen, 0); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/versaloon/usbtoxxx/usbtopwr.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <string.h> #include "../versaloon_include.h" #include "../versaloon.h" #include "../versaloon_internal.h" #include "usbtoxxx.h" #include "usbtoxxx_internal.h" RESULT usbtopwr_init(uint8_t interface_index) { return usbtoxxx_init_command(USB_TO_POWER, interface_index); } RESULT usbtopwr_fini(uint8_t interface_index) { return usbtoxxx_fini_command(USB_TO_POWER, interface_index); } RESULT usbtopwr_config(uint8_t interface_index) { #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif return usbtoxxx_conf_command(USB_TO_POWER, interface_index, NULL, 0); } RESULT usbtopwr_output(uint8_t interface_index, uint16_t millivolt) { #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif return usbtoxxx_out_command(USB_TO_POWER, interface_index, (uint8_t *)&millivolt, 2, 0); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdlib.h> #include <string.h> #include "../versaloon_include.h" #include "../versaloon.h" #include "../versaloon_internal.h" #include "usbtoxxx.h" #include "usbtoxxx_internal.h" static RESULT usbtoswd_read_callback(void *p, uint8_t *src, uint8_t *processed) { struct versaloon_pending_t *pending = (struct versaloon_pending_t *)p; if (pending->extra_data) *((uint8_t *)pending->extra_data) = src[0]; return ERROR_OK; } static RESULT usbtoswd_write_callback(void *p, uint8_t *src, uint8_t *processed) { struct versaloon_pending_t *pending = (struct versaloon_pending_t *)p; if (pending->extra_data) *((uint8_t *)pending->extra_data) = src[0]; /* mark it processed to ignore other input data */ *processed = 1; return ERROR_OK; } RESULT usbtoswd_init(uint8_t interface_index) { return usbtoxxx_init_command(USB_TO_SWD, interface_index); } RESULT usbtoswd_fini(uint8_t interface_index) { return usbtoxxx_fini_command(USB_TO_SWD, interface_index); } RESULT usbtoswd_config(uint8_t interface_index, uint8_t trn, uint16_t retry, uint16_t dly) { uint8_t cfg_buf[5]; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif cfg_buf[0] = trn; SET_LE_U16(&cfg_buf[1], retry); SET_LE_U16(&cfg_buf[3], dly); return usbtoxxx_conf_command(USB_TO_SWD, interface_index, cfg_buf, 5); } RESULT usbtoswd_seqout(uint8_t interface_index, const uint8_t *data, uint16_t bitlen) { uint16_t bytelen = (bitlen + 7) >> 3; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif SET_LE_U16(&versaloon_cmd_buf[0], bitlen); memcpy(versaloon_cmd_buf + 2, data, bytelen); return usbtoxxx_out_command(USB_TO_SWD, interface_index, versaloon_cmd_buf, bytelen + 2, 0); } RESULT usbtoswd_seqin(uint8_t interface_index, uint8_t *data, uint16_t bitlen) { uint16_t bytelen = (bitlen + 7) >> 3; uint8_t buff[2]; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif SET_LE_U16(&buff[0], bitlen); return usbtoxxx_in_command(USB_TO_SWD, interface_index, buff, 2, bytelen, data, 0, bytelen, 0); } RESULT usbtoswd_transact(uint8_t interface_index, uint8_t request, uint32_t *data, uint8_t *ack) { uint8_t parity; uint8_t buff[5]; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif parity = (request >> 1) & 1; parity += (request >> 2) & 1; parity += (request >> 3) & 1; parity += (request >> 4) & 1; parity &= 1; buff[0] = (request | 0x81 | (parity << 5)) & ~0x40; if (data) SET_LE_U32(&buff[1], *data); else memset(buff + 1, 0, 4); versaloon_set_extra_data(ack); if (request & 0x04) { /* read */ versaloon_set_callback(usbtoswd_read_callback); } else { /* write */ versaloon_set_callback(usbtoswd_write_callback); } /* Input buffer must be passed even for write operations. Otherwise * the callback function is not called and ack value is not set. */ return usbtoxxx_inout_command(USB_TO_SWD, interface_index, buff, 5, 5, (uint8_t *)data, 1, 4, 0); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <string.h> #include "../versaloon_include.h" #include "../versaloon.h" #include "../versaloon_internal.h" #include "usbtoxxx.h" #include "usbtoxxx_internal.h" #define N_A "n/a" static const char *types_name[96] = { "usbtousart", "usbtospi", "usbtoi2c", "usbtogpio", "usbtocan", "usbtopwm", "usbtoadc", "usbtodac", "usbtomicrowire", "usbtoswim", "usbtodusi", N_A, N_A, N_A, "usbtopower", "usbtodelay", N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, "usbtojtagll", "usbtojtaghl", "usbtoissp", "usbtoc2", "usbtosbw", "usbtolpcicp", "usbtoswd", "usbtojtagraw", "usbtobdm", N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, "usbtomsp430jtag", N_A, N_A, N_A, N_A, N_A, N_A, N_A, "usbtopower", "usbtodelay", "usbtopoll", N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, "usbtoall" }; uint8_t usbtoxxx_abilities[USB_TO_XXX_ABILITIES_LEN]; #define usbtoxxx_get_type_name(type) \ types_name[((type) - VERSALOON_USB_TO_XXX_CMD_START) \ % ARRAY_SIZE(types_name)] static uint8_t type_pre; static uint16_t usbtoxxx_buffer_index; static uint16_t usbtoxxx_current_cmd_index; static uint8_t *usbtoxxx_buffer; static uint16_t collect_index; static uint8_t collect_cmd; static uint8_t poll_nesting; struct usbtoxxx_context_t { uint8_t type_pre; uint8_t *usbtoxxx_buffer; uint16_t usbtoxxx_current_cmd_index; uint16_t usbtoxxx_buffer_index; uint16_t versaloon_pending_idx; }; static struct usbtoxxx_context_t poll_context; static void usbtoxxx_save_context(struct usbtoxxx_context_t *c) { c->type_pre = type_pre; c->usbtoxxx_buffer = usbtoxxx_buffer; c->usbtoxxx_buffer_index = usbtoxxx_buffer_index; c->usbtoxxx_current_cmd_index = usbtoxxx_current_cmd_index; c->versaloon_pending_idx = versaloon_pending_idx; } static void usbtoxxx_pop_context(struct usbtoxxx_context_t *c) { type_pre = c->type_pre; usbtoxxx_buffer = c->usbtoxxx_buffer; usbtoxxx_buffer_index = c->usbtoxxx_buffer_index; usbtoxxx_current_cmd_index = c->usbtoxxx_current_cmd_index; versaloon_pending_idx = c->versaloon_pending_idx; } static RESULT usbtoxxx_validate_current_command_type(void) { if (type_pre > 0) { /* not the first command */ if (!usbtoxxx_buffer) { LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(usbtoxxx_buffer)); return ERRCODE_INVALID_BUFFER; } usbtoxxx_buffer[0] = type_pre; SET_LE_U16(&usbtoxxx_buffer[1], usbtoxxx_current_cmd_index); usbtoxxx_buffer_index += usbtoxxx_current_cmd_index; } else { /* first command */ usbtoxxx_buffer_index = 3; } /* prepare for next command */ usbtoxxx_current_cmd_index = 3; usbtoxxx_buffer = versaloon_buf + usbtoxxx_buffer_index; collect_index = 0; collect_cmd = 0; return ERROR_OK; } RESULT usbtoxxx_execute_command(void) { uint16_t i; uint16_t inlen; RESULT result = ERROR_OK; if (poll_nesting) { LOG_BUG(ERRMSG_INVALID_USAGE, "USB_TO_POLL"); versaloon_free_want_pos(); return ERROR_FAIL; } if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); versaloon_free_want_pos(); return ERRCODE_FAILURE_OPERATION; } if (usbtoxxx_buffer_index == 3) { versaloon_free_want_pos(); return ERROR_OK; } versaloon_buf[0] = USB_TO_ALL; SET_LE_U16(&versaloon_buf[1], usbtoxxx_buffer_index); if (versaloon_send_command(usbtoxxx_buffer_index, &inlen) != ERROR_OK) { versaloon_free_want_pos(); return ERROR_FAIL; } /* process return data */ usbtoxxx_buffer_index = 0; for (i = 0; i < versaloon_pending_idx; i++) { /* check result */ if ((i == 0) || !((versaloon_pending[i].collect) && (versaloon_pending[i - 1].collect) && (versaloon_pending[i].cmd == versaloon_pending[i - 1].cmd))) { if (USB_TO_XXX_CMD_NOT_SUPPORT == versaloon_buf[usbtoxxx_buffer_index]) { LOG_ERROR(ERRMSG_NOT_SUPPORT_BY, usbtoxxx_get_type_name(versaloon_pending[i].type), "current dongle"); result = ERROR_FAIL; break; } else if (versaloon_buf[usbtoxxx_buffer_index] != USB_TO_XXX_OK) { LOG_ERROR("%s command 0x%02x failed with 0x%02x", usbtoxxx_get_type_name(versaloon_pending[i].type), versaloon_pending[i].cmd, versaloon_buf[usbtoxxx_buffer_index]); result = ERROR_FAIL; break; } usbtoxxx_buffer_index++; } /* get result data */ if (versaloon_pending[i].pos) { uint8_t processed = 0; if (versaloon_pending[i].callback) { versaloon_pending[i].callback(&versaloon_pending[i], versaloon_buf + usbtoxxx_buffer_index, &processed); } if (!processed) { struct versaloon_want_pos_t *tmp; tmp = versaloon_pending[i].pos; while (tmp) { if ((tmp->buff) && (tmp->size > 0)) { memcpy(tmp->buff, versaloon_buf + usbtoxxx_buffer_index + tmp->offset, tmp->size); } struct versaloon_want_pos_t *free_tmp; free_tmp = tmp; tmp = tmp->next; free(free_tmp); } versaloon_pending[i].pos = NULL; } } else if ((versaloon_pending[i].want_data_size > 0) && (versaloon_pending[i].data_buffer)) { uint8_t processed = 0; if (versaloon_pending[i].callback) { versaloon_pending[i].callback(&versaloon_pending[i], versaloon_buf + usbtoxxx_buffer_index, &processed); } if (!processed) { memcpy(versaloon_pending[i].data_buffer, versaloon_buf + usbtoxxx_buffer_index + versaloon_pending[i].want_data_pos, versaloon_pending[i].want_data_size); } } usbtoxxx_buffer_index += versaloon_pending[i].actual_data_size; if (usbtoxxx_buffer_index > inlen) { LOG_BUG("%s command 0x%02x process error", usbtoxxx_get_type_name(versaloon_pending[i].type), versaloon_pending[i].cmd); result = ERROR_FAIL; break; } } /* data is not the right size */ if (inlen != usbtoxxx_buffer_index) { LOG_ERROR(ERRMSG_INVALID_TARGET, "length of return data"); result = ERROR_FAIL; } if (versaloon_pending_idx > 0) versaloon_pending_idx = 0; else { /* no receive data, avoid collision */ sleep_ms(10); } type_pre = 0; collect_cmd = 0; collect_index = 0; versaloon_free_want_pos(); return result; } RESULT usbtoxxx_init(void) { versaloon_pending_idx = 0; if ((usbtoinfo_get_abilities(usbtoxxx_abilities) != ERROR_OK) || (usbtoxxx_execute_command() != ERROR_OK)) return ERROR_FAIL; LOG_INFO("USB_TO_XXX abilities: 0x%08X:0x%08X:0x%08X", GET_LE_U32(&usbtoxxx_abilities[0]), GET_LE_U32(&usbtoxxx_abilities[4]), GET_LE_U32(&usbtoxxx_abilities[8])); return ERROR_OK; } RESULT usbtoxxx_fini(void) { usbtoxxx_buffer = NULL; type_pre = 0; return ERROR_OK; } bool usbtoxxx_interface_supported(uint8_t cmd) { if ((cmd < VERSALOON_USB_TO_XXX_CMD_START) || (cmd > VERSALOON_USB_TO_XXX_CMD_END)) return false; cmd -= VERSALOON_USB_TO_XXX_CMD_START; return (usbtoxxx_abilities[cmd / 8] & (1 << (cmd % 8))) > 0; } static RESULT usbtoxxx_ensure_buffer_size(uint16_t cmdlen) { /* check free space, commit if not enough */ if (((usbtoxxx_buffer_index + usbtoxxx_current_cmd_index + cmdlen) >= versaloon_buf_size) || (versaloon_pending_idx >= VERSALOON_MAX_PENDING_NUMBER)) { struct usbtoxxx_context_t context_tmp; uint8_t poll_nesting_tmp = 0; memset(&context_tmp, 0, sizeof(context_tmp)); if (poll_nesting) { if (poll_context.type_pre == 0) { LOG_BUG("USB_TO_POLL toooooo long"); return ERROR_OK; } usbtoxxx_save_context(&context_tmp); usbtoxxx_pop_context(&poll_context); poll_nesting_tmp = poll_nesting; poll_nesting = 0; } if (usbtoxxx_execute_command() != ERROR_OK) return ERROR_FAIL; if (poll_nesting_tmp) { uint16_t newlen, oldlen; newlen = context_tmp.versaloon_pending_idx - poll_context.versaloon_pending_idx; memcpy(&versaloon_pending[0], &versaloon_pending[poll_context.versaloon_pending_idx], sizeof(versaloon_pending[0]) * newlen); context_tmp.versaloon_pending_idx = newlen; oldlen = poll_context.usbtoxxx_buffer_index + poll_context.usbtoxxx_current_cmd_index; newlen = context_tmp.usbtoxxx_buffer_index + context_tmp.usbtoxxx_current_cmd_index; memcpy(versaloon_buf + 3, versaloon_buf + oldlen, newlen - oldlen); oldlen -= 3; context_tmp.usbtoxxx_buffer -= oldlen; context_tmp.usbtoxxx_buffer_index -= oldlen; usbtoxxx_pop_context(&context_tmp); poll_nesting = poll_nesting_tmp; } } return ERROR_OK; } RESULT usbtoxxx_add_command(uint8_t type, uint8_t cmd, uint8_t *cmdbuf, uint16_t cmdlen, uint16_t retlen, uint8_t *wantbuf, uint16_t wantpos, uint16_t wantlen, uint8_t collect) { uint16_t len_tmp; /* 3 more bytes by usbtoxxx_validate_current_command_type */ /* 3 more bytes when ((0 == collect_index) || (collect_cmd != cmd)) */ if (usbtoxxx_ensure_buffer_size(cmdlen + 6) != ERROR_OK) return ERROR_FAIL; if ((type_pre != type) || (!usbtoxxx_buffer)) { if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } type_pre = type; } if ((collect_index == 0) || (collect_cmd != cmd)) { usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = cmd; if (collect) { collect_index = usbtoxxx_current_cmd_index; collect_cmd = cmd; } else { collect_index = 0; collect_cmd = 0; } SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], cmdlen); usbtoxxx_current_cmd_index += 2; } else { len_tmp = GET_LE_U16(&usbtoxxx_buffer[collect_index]) + cmdlen; SET_LE_U16(&usbtoxxx_buffer[collect_index], len_tmp); } if (cmdbuf) { memcpy(usbtoxxx_buffer + usbtoxxx_current_cmd_index, cmdbuf, cmdlen); usbtoxxx_current_cmd_index += cmdlen; } return versaloon_add_pending(type, cmd, retlen, wantpos, wantlen, wantbuf, collect); } RESULT usbtoinfo_get_abilities(uint8_t abilities[USB_TO_XXX_ABILITIES_LEN]) { if (usbtoxxx_ensure_buffer_size(3) != ERROR_OK) return ERROR_FAIL; if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } type_pre = USB_TO_INFO; return versaloon_add_pending(USB_TO_INFO, 0, USB_TO_XXX_ABILITIES_LEN, 0, USB_TO_XXX_ABILITIES_LEN, abilities, 0); } RESULT usbtopoll_start(uint16_t retry_cnt, uint16_t interval_us) { if (usbtoxxx_ensure_buffer_size(3 + 5) != ERROR_OK) return ERROR_FAIL; if (!poll_nesting) usbtoxxx_save_context(&poll_context); if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } poll_nesting++; type_pre = USB_TO_POLL; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_START; SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], retry_cnt); usbtoxxx_current_cmd_index += 2; SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], interval_us); usbtoxxx_current_cmd_index += 2; return versaloon_add_pending(USB_TO_POLL, 0, 0, 0, 0, NULL, 0); } RESULT usbtopoll_end(void) { if (!poll_nesting) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting"); return ERRCODE_FAILURE_OPERATION; } if (usbtoxxx_ensure_buffer_size(3 + 1) != ERROR_OK) return ERROR_FAIL; if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } poll_nesting--; type_pre = USB_TO_POLL; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_END; return versaloon_add_pending(USB_TO_POLL, 0, 0, 0, 0, NULL, 0); } RESULT usbtopoll_checkok(uint8_t equ, uint16_t offset, uint8_t size, uint32_t mask, uint32_t value) { uint8_t i; if (size > 4) { LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__); return ERRCODE_INVALID_PARAMETER; } if (!poll_nesting) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting"); return ERRCODE_FAILURE_OPERATION; } if (usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size) != ERROR_OK) return ERROR_FAIL; if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } type_pre = USB_TO_POLL; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_CHECKOK; SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], offset); usbtoxxx_current_cmd_index += 2; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = size; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = equ; for (i = 0; i < size; i++) usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = (mask >> (8 * i)) & 0xFF; for (i = 0; i < size; i++) usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = (value >> (8 * i)) & 0xFF; return ERROR_OK; } RESULT usbtopoll_checkfail(uint8_t equ, uint16_t offset, uint8_t size, uint32_t mask, uint32_t value) { uint8_t i; if (size > 4) { LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__); return ERRCODE_INVALID_PARAMETER; } if (!poll_nesting) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting"); return ERRCODE_FAILURE_OPERATION; } if (usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size) != ERROR_OK) return ERROR_FAIL; if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } type_pre = USB_TO_POLL; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_CHECKFAIL; SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], offset); usbtoxxx_current_cmd_index += 2; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = size; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = equ; for (i = 0; i < size; i++) usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = (mask >> (8 * i)) & 0xFF; for (i = 0; i < size; i++) usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = (value >> (8 * i)) & 0xFF; return ERROR_OK; } RESULT usbtopoll_verifybuff(uint16_t offset, uint16_t size, uint8_t *buff) { if (!poll_nesting) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting"); return ERRCODE_FAILURE_OPERATION; } if (usbtoxxx_ensure_buffer_size(3 + 5 + size) != ERROR_OK) return ERROR_FAIL; if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } type_pre = USB_TO_POLL; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_VERIFYBUFF; SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], offset); usbtoxxx_current_cmd_index += 2; SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], size); usbtoxxx_current_cmd_index += 2; memcpy(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], buff, size); usbtoxxx_current_cmd_index += size; return ERROR_OK; } RESULT usbtodelay_delay(uint16_t dly) { if (usbtoxxx_ensure_buffer_size(3 + 2) != ERROR_OK) return ERROR_FAIL; if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } type_pre = USB_TO_DELAY; SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], dly); usbtoxxx_current_cmd_index += 2; return versaloon_add_pending(USB_TO_DELAY, 0, 0, 0, 0, NULL, 0); } RESULT usbtodelay_delayms(uint16_t ms) { return usbtodelay_delay(ms | 0x8000); } RESULT usbtodelay_delayus(uint16_t us) { return usbtodelay_delay(us & 0x7FFF); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_VERSALOON_USBTOXXX_USBTOXXX_H #define OPENOCD_JTAG_DRIVERS_VERSALOON_USBTOXXX_USBTOXXX_H RESULT usbtoxxx_init(void); RESULT usbtoxxx_fini(void); RESULT usbtoxxx_execute_command(void); #define USB_TO_XXX_ABILITIES_LEN 12 extern uint8_t usbtoxxx_abilities[USB_TO_XXX_ABILITIES_LEN]; bool usbtoxxx_interface_supported(uint8_t cmd); /* USB_TO_INFO */ RESULT usbtoinfo_get_abilities(uint8_t abilities[USB_TO_XXX_ABILITIES_LEN]); /* USB_TO_DELAY */ RESULT usbtodelay_delay(uint16_t dly); RESULT usbtodelay_delayms(uint16_t ms); RESULT usbtodelay_delayus(uint16_t us); /* USB_TO_USART */ RESULT usbtousart_init(uint8_t interface_index); RESULT usbtousart_fini(uint8_t interface_index); RESULT usbtousart_config(uint8_t interface_index, uint32_t baudrate, uint8_t datalength, uint8_t mode); RESULT usbtousart_send(uint8_t interface_index, uint8_t *buf, uint16_t len); RESULT usbtousart_receive(uint8_t interface_index, uint8_t *buf, uint16_t len); RESULT usbtousart_status(uint8_t interface_index, struct usart_status_t *status); /* USB_TO_SPI */ RESULT usbtospi_init(uint8_t interface_index); RESULT usbtospi_fini(uint8_t interface_index); RESULT usbtospi_config(uint8_t interface_index, uint32_t khz, uint8_t mode); RESULT usbtospi_io(uint8_t interface_index, uint8_t *out, uint8_t *in, uint16_t bytelen); /* USB_TO_GPIO */ RESULT usbtogpio_init(uint8_t interface_index); RESULT usbtogpio_fini(uint8_t interface_index); RESULT usbtogpio_config(uint8_t interface_index, uint32_t mask, uint32_t dir_mask, uint32_t pull_en_mask, uint32_t input_pull_mask); RESULT usbtogpio_in(uint8_t interface_index, uint32_t mask, uint32_t *value); RESULT usbtogpio_out(uint8_t interface_index, uint32_t mask, uint32_t value); /* USB_TO_ISSP */ RESULT usbtoissp_init(uint8_t interface_index); RESULT usbtoissp_fini(uint8_t interface_index); RESULT usbtoissp_enter_program_mode(uint8_t interface_index, uint8_t mode); RESULT usbtoissp_leave_program_mode(uint8_t interface_index, uint8_t mode); RESULT usbtoissp_wait_and_poll(uint8_t interface_index); RESULT usbtoissp_vector(uint8_t interface_index, uint8_t operate, uint8_t addr, uint8_t data, uint8_t *buf); /* USB_TO_LPCICP */ RESULT usbtolpcicp_init(uint8_t interface_index); RESULT usbtolpcicp_fini(uint8_t interface_index); RESULT usbtolpcicp_config(uint8_t interface_index); RESULT usbtolpcicp_enter_program_mode(uint8_t interface_index); RESULT usbtolpcicp_in(uint8_t interface_index, uint8_t *buff, uint16_t len); RESULT usbtolpcicp_out(uint8_t interface_index, uint8_t *buff, uint16_t len); RESULT usbtolpcicp_poll_ready(uint8_t interface_index, uint8_t data, uint8_t *ret, uint8_t setmask, uint8_t clearmask, uint16_t pollcnt); /* USB_TO_JTAG_LL */ RESULT usbtojtagll_init(uint8_t interface_index); RESULT usbtojtagll_fini(uint8_t interface_index); RESULT usbtojtagll_config(uint8_t interface_index, uint32_t khz); RESULT usbtojtagll_tms(uint8_t interface_index, uint8_t *tms, uint8_t bytelen); RESULT usbtojtagll_tms_clocks(uint8_t interface_index, uint32_t bytelen, uint8_t tms); RESULT usbtojtagll_scan(uint8_t interface_index, uint8_t *data, uint16_t bitlen, uint8_t tms_before_valid, uint8_t tms_before, uint8_t tms_after0, uint8_t tms_after1); /* USB_TO_JTAG_HL */ RESULT usbtojtaghl_init(uint8_t interface_index); RESULT usbtojtaghl_fini(uint8_t interface_index); RESULT usbtojtaghl_config(uint8_t interface_index, uint32_t khz, uint8_t ub, uint8_t ua, uint16_t bb, uint16_t ba); RESULT usbtojtaghl_ir(uint8_t interface_index, uint8_t *ir, uint16_t bitlen, uint8_t idle, uint8_t want_ret); RESULT usbtojtaghl_dr(uint8_t interface_index, uint8_t *dr, uint16_t bitlen, uint8_t idle, uint8_t want_ret); RESULT usbtojtaghl_tms(uint8_t interface_index, uint8_t *tms, uint16_t bitlen); RESULT usbtojtaghl_runtest(uint8_t interface_index, uint32_t cycles); RESULT usbtojtaghl_register_callback(uint8_t index, jtag_callback_t send_callback, jtag_callback_t receive_callback); /* USB_TO_JTAG_RAW */ RESULT usbtojtagraw_init(uint8_t interface_index); RESULT usbtojtagraw_fini(uint8_t interface_index); RESULT usbtojtagraw_config(uint8_t interface_index, uint32_t khz); RESULT usbtojtagraw_execute(uint8_t interface_index, uint8_t *tdi, uint8_t *tms, uint8_t *tdo, uint32_t bitlen); /* USB_TO_C2 */ RESULT usbtoc2_init(uint8_t interface_index); RESULT usbtoc2_fini(uint8_t interface_index); RESULT usbtoc2_writeaddr(uint8_t interface_index, uint8_t addr); RESULT usbtoc2_readaddr(uint8_t interface_index, uint8_t *data); RESULT usbtoc2_writedata(uint8_t interface_index, uint8_t *buf, uint8_t len); RESULT usbtoc2_readdata(uint8_t interface_index, uint8_t *buf, uint8_t len); /* USB_TO_I2C */ RESULT usbtoi2c_init(uint8_t interface_index); RESULT usbtoi2c_fini(uint8_t interface_index); RESULT usbtoi2c_config(uint8_t interface_index, uint16_t khz, uint16_t byte_interval, uint16_t max_dly); RESULT usbtoi2c_read(uint8_t interface_index, uint16_t chip_addr, uint8_t *data, uint16_t data_len, uint8_t stop, bool nacklast); RESULT usbtoi2c_write(uint8_t interface_index, uint16_t chip_addr, uint8_t *data, uint16_t data_len, uint8_t stop); /* USB_TO_MSP430_JTAG */ RESULT usbtomsp430jtag_init(uint8_t interface_index); RESULT usbtomsp430jtag_fini(uint8_t interface_index); RESULT usbtomsp430jtag_config(uint8_t interface_index, uint8_t has_test); RESULT usbtomsp430jtag_ir(uint8_t interface_index, uint8_t *ir, uint8_t want_ret); RESULT usbtomsp430jtag_dr(uint8_t interface_index, uint32_t *dr, uint8_t bitlen, uint8_t want_ret); RESULT usbtomsp430jtag_tclk(uint8_t interface_index, uint8_t value); RESULT usbtomsp430jtag_tclk_strobe(uint8_t interface_index, uint16_t cnt); RESULT usbtomsp430jtag_reset(uint8_t interface_index); RESULT usbtomsp430jtag_poll(uint8_t interface_index, uint32_t dr, uint32_t mask, uint32_t value, uint8_t len, uint16_t poll_cnt, uint8_t toggle_tclk); /* USB_TO_MSP430_SBW */ RESULT usbtomsp430sbw_init(uint8_t interface_index); RESULT usbtomsp430sbw_fini(uint8_t interface_index); RESULT usbtomsp430sbw_config(uint8_t interface_index, uint8_t has_test); RESULT usbtomsp430sbw_ir(uint8_t interface_index, uint8_t *ir, uint8_t want_ret); RESULT usbtomsp430sbw_dr(uint8_t interface_index, uint32_t *dr, uint8_t bitlen, uint8_t want_ret); RESULT usbtomsp430sbw_tclk(uint8_t interface_index, uint8_t value); RESULT usbtomsp430sbw_tclk_strobe(uint8_t interface_index, uint16_t cnt); RESULT usbtomsp430sbw_reset(uint8_t interface_index); RESULT usbtomsp430sbw_poll(uint8_t interface_index, uint32_t dr, uint32_t mask, uint32_t value, uint8_t len, uint16_t poll_cnt, uint8_t toggle_tclk); /* USB_TO_POWER */ RESULT usbtopwr_init(uint8_t interface_index); RESULT usbtopwr_fini(uint8_t interface_index); RESULT usbtopwr_config(uint8_t interface_index); RESULT usbtopwr_output(uint8_t interface_index, uint16_t millivolt); /* USB_TO_POLL */ RESULT usbtopoll_start(uint16_t retry_cnt, uint16_t interval_us); RESULT usbtopoll_end(void); RESULT usbtopoll_checkok(uint8_t equ, uint16_t offset, uint8_t size, uint32_t mask, uint32_t value); RESULT usbtopoll_checkfail(uint8_t equ, uint16_t offset, uint8_t size, uint32_t mask, uint32_t value); RESULT usbtopoll_verifybuff(uint16_t offset, uint16_t size, uint8_t *buff); /* USB_TO_SWD */ RESULT usbtoswd_init(uint8_t interface_index); RESULT usbtoswd_fini(uint8_t interface_index); RESULT usbtoswd_config(uint8_t interface_index, uint8_t trn, uint16_t retry, uint16_t dly); RESULT usbtoswd_seqout(uint8_t interface_index, const uint8_t *data, uint16_t bitlen); RESULT usbtoswd_seqin(uint8_t interface_index, uint8_t *data, uint16_t bitlen); RESULT usbtoswd_transact(uint8_t interface_index, uint8_t request, uint32_t *data, uint8_t *ack); /* USB_TO_SWIM */ RESULT usbtoswim_init(uint8_t interface_index); RESULT usbtoswim_fini(uint8_t interface_index); RESULT usbtoswim_config(uint8_t interface_index, uint8_t mhz, uint8_t cnt0, uint8_t cnt1); RESULT usbtoswim_srst(uint8_t interface_index); RESULT usbtoswim_wotf(uint8_t interface_index, uint8_t *data, uint16_t bytelen, uint32_t addr); RESULT usbtoswim_rotf(uint8_t interface_index, uint8_t *data, uint16_t bytelen, uint32_t addr); RESULT usbtoswim_sync(uint8_t interface_index, uint8_t mhz); RESULT usbtoswim_enable(uint8_t interface_index); /* USB_TO_BDM */ RESULT usbtobdm_init(uint8_t interface_index); RESULT usbtobdm_fini(uint8_t interface_index); RESULT usbtobdm_sync(uint8_t interface_index, uint16_t *khz); RESULT usbtobdm_transact(uint8_t interface_index, uint8_t *out, uint8_t outlen, uint8_t *in, uint8_t inlen, uint8_t delay, uint8_t ack); /* USB_TO_DUSI */ RESULT usbtodusi_init(uint8_t interface_index); RESULT usbtodusi_fini(uint8_t interface_index); RESULT usbtodusi_config(uint8_t interface_index, uint32_t khz, uint8_t mode); RESULT usbtodusi_io(uint8_t interface_index, uint8_t *mo, uint8_t *mi, uint8_t *so, uint8_t *si, uint32_t bitlen); /* USB_TO_MICROWIRE */ RESULT usbtomicrowire_init(uint8_t interface_index); RESULT usbtomicrowire_fini(uint8_t interface_index); RESULT usbtomicrowire_config(uint8_t interface_index, uint16_t khz, uint8_t sel_polarity); RESULT usbtomicrowire_transport(uint8_t interface_index, uint32_t opcode, uint8_t opcode_bitlen, uint32_t addr, uint8_t addr_bitlen, uint32_t data, uint8_t data_bitlen, uint8_t *reply, uint8_t reply_bitlen); RESULT usbtomicrowire_poll(uint8_t interface_index, uint16_t interval_us, uint16_t retry_cnt); /* USB_TO_PWM */ RESULT usbtopwm_init(uint8_t interface_index); RESULT usbtopwm_fini(uint8_t interface_index); RESULT usbtopwm_config(uint8_t interface_index, uint16_t khz, uint8_t mode); RESULT usbtopwm_out(uint8_t interface_index, uint16_t count, uint16_t *rate); RESULT usbtopwm_in(uint8_t interface_index, uint16_t count, uint16_t *rate); #endif /* OPENOCD_JTAG_DRIVERS_VERSALOON_USBTOXXX_USBTOXXX_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx_internal.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_VERSALOON_USBTOXXX_USBTOXXX_INTERNAL_H #define OPENOCD_JTAG_DRIVERS_VERSALOON_USBTOXXX_USBTOXXX_INTERNAL_H /* USB_TO_XXX USB Commands */ /* Page0 */ #define USB_TO_USART (VERSALOON_USB_TO_XXX_CMD_START + 0x00) #define USB_TO_SPI (VERSALOON_USB_TO_XXX_CMD_START + 0x01) #define USB_TO_I2C (VERSALOON_USB_TO_XXX_CMD_START + 0x02) #define USB_TO_GPIO (VERSALOON_USB_TO_XXX_CMD_START + 0x03) #define USB_TO_CAN (VERSALOON_USB_TO_XXX_CMD_START + 0x04) #define USB_TO_PWM (VERSALOON_USB_TO_XXX_CMD_START + 0x05) #define USB_TO_ADC (VERSALOON_USB_TO_XXX_CMD_START + 0x06) #define USB_TO_DAC (VERSALOON_USB_TO_XXX_CMD_START + 0x07) #define USB_TO_MICROWIRE (VERSALOON_USB_TO_XXX_CMD_START + 0x08) #define USB_TO_SWIM (VERSALOON_USB_TO_XXX_CMD_START + 0x09) #define USB_TO_DUSI (VERSALOON_USB_TO_XXX_CMD_START + 0x0A) /* Page1 */ #define USB_TO_JTAG_LL (VERSALOON_USB_TO_XXX_CMD_START + 0x20) #define USB_TO_JTAG_HL (VERSALOON_USB_TO_XXX_CMD_START + 0x21) #define USB_TO_ISSP (VERSALOON_USB_TO_XXX_CMD_START + 0x22) #define USB_TO_C2 (VERSALOON_USB_TO_XXX_CMD_START + 0x23) #define USB_TO_SBW (VERSALOON_USB_TO_XXX_CMD_START + 0x24) #define USB_TO_LPCICP (VERSALOON_USB_TO_XXX_CMD_START + 0x25) #define USB_TO_SWD (VERSALOON_USB_TO_XXX_CMD_START + 0x26) #define USB_TO_JTAG_RAW (VERSALOON_USB_TO_XXX_CMD_START + 0x27) #define USB_TO_BDM (VERSALOON_USB_TO_XXX_CMD_START + 0x28) #define USB_TO_MSP430_JTAG (VERSALOON_USB_TO_XXX_CMD_START + 0x38) /* Page2 */ #define USB_TO_POWER (VERSALOON_USB_TO_XXX_CMD_START + 0x40) #define USB_TO_DELAY (VERSALOON_USB_TO_XXX_CMD_START + 0x41) #define USB_TO_POLL (VERSALOON_USB_TO_XXX_CMD_START + 0x42) #define USB_TO_INFO (VERSALOON_USB_TO_XXX_CMD_START + 0x5E) #define USB_TO_ALL (VERSALOON_USB_TO_XXX_CMD_START + 0x5F) /* USB_TO_XXX Masks */ #define USB_TO_XXX_CMDMASK 0xF8 #define USB_TO_XXX_CMDSHIFT 3 #define USB_TO_XXX_IDXMASK 0x07 /* USB_TO_XXX Sub Commands */ /* Common Sub Commands */ #define USB_TO_XXX_INIT (0x00 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_FINI (0x01 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_CONFIG (0x02 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_GETHWINFO (0x03 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_STATUS (0X04 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_IN_OUT (0x05 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_IN (0x06 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_OUT (0x07 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_POLL (0x08 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_SPECIAL (0x09 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_RESET (0x0A << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_SYNC (0x0B << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_ENABLE (0x0C << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_DISABLE (0x0D << USB_TO_XXX_CMDSHIFT) /* USB_TO_POLL */ #define USB_TO_POLL_START 0x00 #define USB_TO_POLL_END 0x01 #define USB_TO_POLL_CHECKOK 0x02 #define USB_TO_POLL_CHECKFAIL 0x03 #define USB_TO_POLL_VERIFYBUFF 0x04 /* USB_TO_XXX Replies */ #define USB_TO_XXX_OK 0x00 #define USB_TO_XXX_FAILED 0x01 #define USB_TO_XXX_TIME_OUT 0x02 #define USB_TO_XXX_INVALID_INDEX 0x03 #define USB_TO_XXX_INVALID_PARA 0x04 #define USB_TO_XXX_INVALID_CMD 0x05 #define USB_TO_XXX_CMD_NOT_SUPPORT 0x06 /* USB_TO_XXX */ RESULT usbtoxxx_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie, uint16_t want_pos, uint16_t want_size, uint8_t *buffer); RESULT usbtoxxx_add_command(uint8_t type, uint8_t cmd, uint8_t *cmdbuf, uint16_t cmdlen, uint16_t retlen, uint8_t *wantbuf, uint16_t wantpos, uint16_t wantlen, uint8_t collect); #define usbtoxxx_init_command(type, port) \ usbtoxxx_add_command((type), (USB_TO_XXX_INIT | (port)), \ NULL, 0, 0, NULL, 0, 0, 0) #define usbtoxxx_fini_command(type, port) \ usbtoxxx_add_command((type), (USB_TO_XXX_FINI | (port)), \ NULL, 0, 0, NULL, 0, 0, 0) #define usbtoxxx_conf_command(type, port, cmdbuf, cmdlen) \ usbtoxxx_add_command((type), (USB_TO_XXX_CONFIG | (port)), \ (cmdbuf), (cmdlen), 0, NULL, 0, 0, 0) #define usbtoxxx_inout_command(type, port, cmdbuf, cmdlen, retlen, wantbuf, \ wantpos, wantlen, c) \ usbtoxxx_add_command((type), (USB_TO_XXX_IN_OUT | (port)), \ (cmdbuf), (cmdlen), (retlen), (wantbuf), \ (wantpos), (wantlen), (c)) #define usbtoxxx_in_command(type, port, cmdbuf, cmdlen, retlen, wantbuf, \ wantpos, wantlen, c) \ usbtoxxx_add_command((type), (USB_TO_XXX_IN | (port)), (cmdbuf), \ (cmdlen), (retlen), (wantbuf), (wantpos), \ (wantlen), (c)) #define usbtoxxx_out_command(type, port, cmdbuf, cmdlen, c) \ usbtoxxx_add_command((type), (USB_TO_XXX_OUT | (port)), (cmdbuf), \ (cmdlen), 0, NULL, 0, 0, (c)) #define usbtoxxx_poll_command(type, port, cmdbuf, cmdlen, retbuf, retlen) \ usbtoxxx_add_command((type), (USB_TO_XXX_POLL | (port)), (cmdbuf), \ (cmdlen), (retlen), (retbuf), 0, (retlen), 0) #define usbtoxxx_status_command(type, port, retlen, wantbuf, wantpos, wantlen, c) \ usbtoxxx_add_command((type), (USB_TO_XXX_STATUS | (port)), \ NULL, 0, (retlen), (wantbuf), (wantpos), \ (wantlen), (c)) #define usbtoxxx_special_command(type, port, cmdbuf, cmdlen, retlen, wantbuf, \ wantpos, wantlen, c) \ usbtoxxx_add_command((type), (USB_TO_XXX_SPECIAL | (port)), \ (cmdbuf), (cmdlen), retlen, wantbuf, \ wantpos, wantlen, (c)) #define usbtoxxx_reset_command(type, port, cmdbuf, cmdlen) \ usbtoxxx_add_command((type), (USB_TO_XXX_RESET | (port)), \ (cmdbuf), (cmdlen), 0, NULL, 0, 0, 0) #define usbtoxxx_sync_command(type, port, cmdbuf, cmdlen, retlen, wantbuf) \ usbtoxxx_add_command((type), (USB_TO_XXX_SYNC | (port)), \ (cmdbuf), (cmdlen), (retlen), (wantbuf), 0, \ (retlen), 0) #define usbtoxxx_enable_command(type, port, cmdbuf, cmdlen) \ usbtoxxx_add_command((type), (USB_TO_XXX_ENABLE | (port)), \ (cmdbuf), (cmdlen), 0, NULL, 0, 0, 0) #define usbtoxxx_disable_command(type, port, cmdbuf, cmdlen) \ usbtoxxx_add_command((type), (USB_TO_XXX_DISABLE | (port)), \ (cmdbuf), (cmdlen), 0, NULL, 0, 0, 0) /* USB_TO_SPI */ #define USB_TO_SPI_BAUDRATE_MSK 0x1F #define USB_TO_SPI_CPOL_MSK 0x20 #define USB_TO_SPI_CPHA_MSK 0x40 #define USB_TO_SPI_MSB_FIRST 0x80 /* USB_TO_DUSI */ #define USB_TO_DUSI_BAUDRATE_MSK 0x1F #define USB_TO_DUSI_CPOL_MSK 0x20 #define USB_TO_DUSI_CPHA_MSK 0x40 #define USB_TO_DUSI_MSB_FIRST 0x80 /* USB_TO_GPIO */ #define USB_TO_GPIO_DIR_MSK 0x01 #endif /* OPENOCD_JTAG_DRIVERS_VERSALOON_USBTOXXX_USBTOXXX_INTERNAL_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/versaloon/versaloon.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "versaloon_include.h" #include <stdio.h> #include <string.h> #include <libusb.h> #include "versaloon.h" #include "versaloon_internal.h" #include "usbtoxxx/usbtoxxx.h" uint8_t *versaloon_buf; uint8_t *versaloon_cmd_buf; uint16_t versaloon_buf_size; struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER]; uint16_t versaloon_pending_idx; struct libusb_device_handle *versaloon_usb_device_handle; static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT; static RESULT versaloon_init(void); static RESULT versaloon_fini(void); static RESULT versaloon_get_target_voltage(uint16_t *voltage); static RESULT versaloon_set_target_voltage(uint16_t voltage); static RESULT versaloon_delay_ms(uint16_t ms); static RESULT versaloon_delay_us(uint16_t us); struct versaloon_interface_t versaloon_interface = { .init = versaloon_init, .fini = versaloon_fini, { /* adaptors */ { /* target_voltage */ .get = versaloon_get_target_voltage, .set = versaloon_set_target_voltage, }, { /* gpio */ .init = usbtogpio_init, .fini = usbtogpio_fini, .config = usbtogpio_config, .out = usbtogpio_out, .in = usbtogpio_in, }, { /* delay */ .delayms = versaloon_delay_ms, .delayus = versaloon_delay_us, }, { /* swd */ .init = usbtoswd_init, .fini = usbtoswd_fini, .config = usbtoswd_config, .seqout = usbtoswd_seqout, .seqin = usbtoswd_seqin, .transact = usbtoswd_transact, }, { /* jtag_raw */ .init = usbtojtagraw_init, .fini = usbtojtagraw_fini, .config = usbtojtagraw_config, .execute = usbtojtagraw_execute, }, .peripheral_commit = usbtoxxx_execute_command, }, { /* usb_setting */ .vid = VERSALOON_VID, .pid = VERSALOON_PID, .ep_out = VERSALOON_OUTP, .ep_in = VERSALOON_INP, .interface = VERSALOON_IFACE, .buf_size = 256, } }; /* programmer_cmd */ static uint32_t versaloon_pending_id; static versaloon_callback_t versaloon_callback; static void *versaloon_extra_data; static struct versaloon_want_pos_t *versaloon_want_pos; void versaloon_set_pending_id(uint32_t id) { versaloon_pending_id = id; } void versaloon_set_callback(versaloon_callback_t callback) { versaloon_callback = callback; } void versaloon_set_extra_data(void *p) { versaloon_extra_data = p; } void versaloon_free_want_pos(void) { uint16_t i; struct versaloon_want_pos_t *tmp, *free_tmp; tmp = versaloon_want_pos; while (tmp) { free_tmp = tmp; tmp = tmp->next; free(free_tmp); } versaloon_want_pos = NULL; for (i = 0; i < ARRAY_SIZE(versaloon_pending); i++) { tmp = versaloon_pending[i].pos; while (tmp) { free_tmp = tmp; tmp = tmp->next; free(free_tmp); } versaloon_pending[i].pos = NULL; } } RESULT versaloon_add_want_pos(uint16_t offset, uint16_t size, uint8_t *buff) { struct versaloon_want_pos_t *new_pos = NULL; new_pos = malloc(sizeof(*new_pos)); if (!new_pos) { LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); return ERRCODE_NOT_ENOUGH_MEMORY; } new_pos->offset = offset; new_pos->size = size; new_pos->buff = buff; new_pos->next = NULL; if (!versaloon_want_pos) versaloon_want_pos = new_pos; else { struct versaloon_want_pos_t *tmp = versaloon_want_pos; while (tmp->next) tmp = tmp->next; tmp->next = new_pos; } return ERROR_OK; } RESULT versaloon_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie, uint16_t want_pos, uint16_t want_size, uint8_t *buffer, uint8_t collect) { #if PARAM_CHECK if (versaloon_pending_idx >= VERSALOON_MAX_PENDING_NUMBER) { LOG_BUG(ERRMSG_INVALID_INDEX, versaloon_pending_idx, "versaloon pending data"); return ERROR_FAIL; } #endif versaloon_pending[versaloon_pending_idx].type = type; versaloon_pending[versaloon_pending_idx].cmd = cmd; versaloon_pending[versaloon_pending_idx].actual_data_size = actual_szie; versaloon_pending[versaloon_pending_idx].want_data_pos = want_pos; versaloon_pending[versaloon_pending_idx].want_data_size = want_size; versaloon_pending[versaloon_pending_idx].data_buffer = buffer; versaloon_pending[versaloon_pending_idx].collect = collect; versaloon_pending[versaloon_pending_idx].id = versaloon_pending_id; versaloon_pending_id = 0; versaloon_pending[versaloon_pending_idx].extra_data = versaloon_extra_data; versaloon_extra_data = NULL; versaloon_pending[versaloon_pending_idx].callback = versaloon_callback; versaloon_callback = NULL; versaloon_pending[versaloon_pending_idx].pos = versaloon_want_pos; versaloon_want_pos = NULL; versaloon_pending_idx++; return ERROR_OK; } RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen) { int ret; int transferred; #if PARAM_CHECK if (!versaloon_buf) { LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf)); return ERRCODE_INVALID_BUFFER; } if ((out_len == 0) || (out_len > versaloon_interface.usb_setting.buf_size)) { LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__); return ERRCODE_INVALID_PARAMETER; } #endif ret = libusb_bulk_transfer(versaloon_usb_device_handle, versaloon_interface.usb_setting.ep_out, versaloon_buf, out_len, &transferred, versaloon_usb_to); if (ret != 0 || transferred != out_len) { LOG_ERROR(ERRMSG_FAILURE_OPERATION, "send usb data"); return ERRCODE_FAILURE_OPERATION; } if (inlen) { ret = libusb_bulk_transfer(versaloon_usb_device_handle, versaloon_interface.usb_setting.ep_in, versaloon_buf, versaloon_interface.usb_setting.buf_size, &transferred, versaloon_usb_to); if (ret == 0) { *inlen = (uint16_t)transferred; return ERROR_OK; } else { LOG_ERROR(ERRMSG_FAILURE_OPERATION, "receive usb data"); return ERROR_FAIL; } } else return ERROR_OK; } #define VERSALOON_RETRY_CNT 10 static RESULT versaloon_init(void) { uint16_t ret = 0; uint8_t retry; uint32_t timeout_tmp; /* malloc temporary buffer */ versaloon_buf = malloc(versaloon_interface.usb_setting.buf_size); if (!versaloon_buf) { LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); return ERRCODE_NOT_ENOUGH_MEMORY; } /* connect to versaloon */ timeout_tmp = versaloon_usb_to; /* not output error message when connecting */ /* 100ms delay when connect */ versaloon_usb_to = 100; for (retry = 0; retry < VERSALOON_RETRY_CNT; retry++) { versaloon_buf[0] = VERSALOON_GET_INFO; if ((versaloon_send_command(1, &ret) == ERROR_OK) && (ret >= 3)) break; } versaloon_usb_to = timeout_tmp; if (retry == VERSALOON_RETRY_CNT) { versaloon_fini(); LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon"); return ERRCODE_FAILURE_OPERATION; } versaloon_buf[ret] = 0; versaloon_buf_size = versaloon_buf[0] + (versaloon_buf[1] << 8); versaloon_interface.usb_setting.buf_size = versaloon_buf_size; LOG_INFO("%s", versaloon_buf + 2); /* free temporary buffer */ free(versaloon_buf); versaloon_buf = NULL; versaloon_buf = malloc(versaloon_interface.usb_setting.buf_size); if (!versaloon_buf) { versaloon_fini(); LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); return ERRCODE_NOT_ENOUGH_MEMORY; } versaloon_cmd_buf = malloc(versaloon_interface.usb_setting.buf_size - 3); if (!versaloon_cmd_buf) { versaloon_fini(); LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); return ERRCODE_NOT_ENOUGH_MEMORY; } if (usbtoxxx_init() != ERROR_OK) { LOG_ERROR(ERRMSG_FAILURE_OPERATION, "initialize usbtoxxx"); return ERROR_FAIL; } return versaloon_get_target_voltage(&ret); } static RESULT versaloon_fini(void) { if (versaloon_usb_device_handle) { usbtoxxx_fini(); versaloon_free_want_pos(); versaloon_usb_device_handle = NULL; free(versaloon_buf); versaloon_buf = NULL; free(versaloon_cmd_buf); versaloon_cmd_buf = NULL; } return ERROR_OK; } static RESULT versaloon_set_target_voltage(uint16_t voltage) { usbtopwr_init(0); usbtopwr_config(0); usbtopwr_output(0, voltage); usbtopwr_fini(0); return usbtoxxx_execute_command(); } static RESULT versaloon_get_target_voltage(uint16_t *voltage) { uint16_t inlen; #if PARAM_CHECK if (!versaloon_buf) { LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf)); return ERRCODE_INVALID_BUFFER; } if (!voltage) { LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__); return ERRCODE_INVALID_PARAMETER; } #endif versaloon_buf[0] = VERSALOON_GET_TVCC; if ((versaloon_send_command(1, &inlen) != ERROR_OK) || (inlen != 2)) { LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon"); return ERRCODE_FAILURE_OPERATION; } else { *voltage = versaloon_buf[0] + (versaloon_buf[1] << 8); return ERROR_OK; } } static RESULT versaloon_delay_ms(uint16_t ms) { return usbtodelay_delay(ms | 0x8000); } static RESULT versaloon_delay_us(uint16_t us) { return usbtodelay_delay(us & 0x7FFF); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/versaloon/versaloon.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 by Simon Qian <SimonQian@SimonQian.com> * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_H #define OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_H #include <libusb.h> struct usart_status_t { uint32_t tx_buff_avail; uint32_t tx_buff_size; uint32_t rx_buff_avail; uint32_t rx_buff_size; }; #include "usbtoxxx/usbtoxxx.h" /* GPIO pins */ #define GPIO_SRST (1 << 0) #define GPIO_TRST (1 << 1) #define GPIO_USR1 (1 << 2) #define GPIO_USR2 (1 << 3) #define GPIO_TCK (1 << 4) #define GPIO_TDO (1 << 5) #define GPIO_TDI (1 << 6) #define GPIO_RTCK (1 << 7) #define GPIO_TMS (1 << 8) struct interface_gpio_t { RESULT(*init)(uint8_t interface_index); RESULT(*fini)(uint8_t interface_index); RESULT(*config)(uint8_t interface_index, uint32_t pin_mask, uint32_t io, uint32_t pull_en_mask, uint32_t input_pull_mask); RESULT(*out)(uint8_t interface_index, uint32_t pin_mask, uint32_t value); RESULT(*in)(uint8_t interface_index, uint32_t pin_mask, uint32_t *value); }; struct interface_delay_t { RESULT(*delayms)(uint16_t ms); RESULT(*delayus)(uint16_t us); }; struct interface_swd_t { RESULT(*init)(uint8_t interface_index); RESULT(*fini)(uint8_t interface_index); RESULT(*config)(uint8_t interface_index, uint8_t trn, uint16_t retry, uint16_t dly); RESULT(*seqout)(uint8_t interface_index, const uint8_t *data, uint16_t bitlen); RESULT(*seqin)(uint8_t interface_index, uint8_t *data, uint16_t bitlen); RESULT(*transact)(uint8_t interface_index, uint8_t request, uint32_t *data, uint8_t *ack); }; struct interface_jtag_raw_t { RESULT(*init)(uint8_t interface_index); RESULT(*fini)(uint8_t interface_index); RESULT(*config)(uint8_t interface_index, uint32_t khz); RESULT(*execute)(uint8_t interface_index, uint8_t *tdi, uint8_t *tms, uint8_t *tdo, uint32_t bitlen); }; struct interface_target_voltage_t { RESULT(*get)(uint16_t *voltage); RESULT(*set)(uint16_t voltage); }; struct versaloon_adaptors_t { struct interface_target_voltage_t target_voltage; struct interface_gpio_t gpio; struct interface_delay_t delay; struct interface_swd_t swd; struct interface_jtag_raw_t jtag_raw; RESULT(*peripheral_commit)(void); }; struct versaloon_usb_setting_t { uint16_t vid; uint16_t pid; uint8_t ep_out; uint8_t ep_in; uint8_t interface; uint16_t buf_size; }; struct versaloon_interface_t { RESULT(*init)(void); RESULT(*fini)(void); struct versaloon_adaptors_t adaptors; struct versaloon_usb_setting_t usb_setting; }; extern struct versaloon_interface_t versaloon_interface; extern struct libusb_device_handle *versaloon_usb_device_handle; #endif /* OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/versaloon/versaloon_include.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 by Simon Qian <SimonQian@SimonQian.com> * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_INCLUDE_H #define OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_INCLUDE_H #include "helper/system.h" /* This file is used to include different header and macros */ /* according to different platform */ #include <jtag/interface.h> #include <jtag/commands.h> #define PARAM_CHECK 1 #define sleep_ms(ms) jtag_sleep((ms) * 1000) #define TO_STR(name) #name #define RESULT int #define LOG_BUG LOG_ERROR /* Common error messages */ #define ERRMSG_NOT_ENOUGH_MEMORY "Lack of memory." #define ERRCODE_NOT_ENOUGH_MEMORY ERROR_FAIL #define ERRMSG_INVALID_VALUE "%d is invalid for %s." #define ERRMSG_INVALID_INDEX "Index %d is invalid for %s." #define ERRMSG_INVALID_USAGE "Invalid usage of %s" #define ERRMSG_INVALID_TARGET "Invalid %s" #define ERRMSG_INVALID_PARAMETER "Invalid parameter of %s." #define ERRMSG_INVALID_INTERFACE_NUM "invalid interface %d" #define ERRMSG_INVALID_BUFFER "Buffer %s is not valid." #define ERRCODE_INVALID_BUFFER ERROR_FAIL #define ERRCODE_INVALID_PARAMETER ERROR_FAIL #define ERRMSG_NOT_SUPPORT_BY "%s is not supported by %s." #define ERRMSG_FAILURE_OPERATION "Fail to %s." #define ERRMSG_FAILURE_OPERATION_MESSAGE "Fail to %s, %s" #define ERRCODE_FAILURE_OPERATION ERROR_FAIL #define GET_U16_MSBFIRST(p) (((*((uint8_t *)(p) + 0)) << 8) | \ ((*((uint8_t *)(p) + 1)) << 0)) #define GET_U32_MSBFIRST(p) (((*((uint8_t *)(p) + 0)) << 24) | \ ((*((uint8_t *)(p) + 1)) << 16) | \ ((*((uint8_t *)(p) + 2)) << 8) | \ ((*((uint8_t *)(p) + 3)) << 0)) #define GET_U16_LSBFIRST(p) (((*((uint8_t *)(p) + 0)) << 0) | \ ((*((uint8_t *)(p) + 1)) << 8)) #define GET_U32_LSBFIRST(p) (((*((uint8_t *)(p) + 0)) << 0) | \ ((*((uint8_t *)(p) + 1)) << 8) | \ ((*((uint8_t *)(p) + 2)) << 16) | \ ((*((uint8_t *)(p) + 3)) << 24)) #define SET_U16_MSBFIRST(p, v) \ do {\ *((uint8_t *)(p) + 0) = (((uint16_t)(v)) >> 8) & 0xFF;\ *((uint8_t *)(p) + 1) = (((uint16_t)(v)) >> 0) & 0xFF;\ } while (0) #define SET_U32_MSBFIRST(p, v) \ do {\ *((uint8_t *)(p) + 0) = (((uint32_t)(v)) >> 24) & 0xFF;\ *((uint8_t *)(p) + 1) = (((uint32_t)(v)) >> 16) & 0xFF;\ *((uint8_t *)(p) + 2) = (((uint32_t)(v)) >> 8) & 0xFF;\ *((uint8_t *)(p) + 3) = (((uint32_t)(v)) >> 0) & 0xFF;\ } while (0) #define SET_U16_LSBFIRST(p, v) \ do {\ *((uint8_t *)(p) + 0) = (((uint16_t)(v)) >> 0) & 0xFF;\ *((uint8_t *)(p) + 1) = (((uint16_t)(v)) >> 8) & 0xFF;\ } while (0) #define SET_U32_LSBFIRST(p, v) \ do {\ *((uint8_t *)(p) + 0) = (((uint32_t)(v)) >> 0) & 0xFF;\ *((uint8_t *)(p) + 1) = (((uint32_t)(v)) >> 8) & 0xFF;\ *((uint8_t *)(p) + 2) = (((uint32_t)(v)) >> 16) & 0xFF;\ *((uint8_t *)(p) + 3) = (((uint32_t)(v)) >> 24) & 0xFF;\ } while (0) #define GET_LE_U16(p) GET_U16_LSBFIRST(p) #define GET_LE_U32(p) GET_U32_LSBFIRST(p) #define GET_BE_U16(p) GET_U16_MSBFIRST(p) #define GET_BE_U32(p) GET_U32_MSBFIRST(p) #define SET_LE_U16(p, v) SET_U16_LSBFIRST(p, v) #define SET_LE_U32(p, v) SET_U32_LSBFIRST(p, v) #define SET_BE_U16(p, v) SET_U16_MSBFIRST(p, v) #define SET_BE_U32(p, v) SET_U32_MSBFIRST(p, v) #endif /* OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_INCLUDE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/versaloon/versaloon_internal.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_INTERNAL_H #define OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_INTERNAL_H #define VERSALOON_PRODUCTSTRING_INDEX 2 #define VERSALOON_SERIALSTRING_INDEX 3 #define VERSALOON_PRODUCTSTRING "Versaloon" #define VERSALOON_VID 0x0483 #define VERSALOON_PID 0xA038 #define VERSALOON_INP 0x82 #define VERSALOON_OUTP 0x03 #define VERSALOON_IFACE 0x00 #define VERSALOON_FULL 1 #define VERSALOON_MINI 2 #define VERSALOON_NANO 3 #define VERSALOON_TIMEOUT 5000 #define VERSALOON_TIMEOUT_LONG 60000 /* USB Commands */ /* Common Commands */ #define VERSALOON_COMMON_CMD_START 0x00 #define VERSALOON_COMMON_CMD_END 0x0F #define VERSALOON_GET_INFO 0x00 #define VERSALOON_GET_TVCC 0x01 #define VERSALOON_GET_HARDWARE 0x02 #define VERSALOON_GET_OFFLINE_SIZE 0x08 #define VERSALOON_ERASE_OFFLINE_DATA 0x09 #define VERSALOON_WRITE_OFFLINE_DATA 0x0A #define VERSALOON_GET_OFFLINE_CHECKSUM 0x0B #define VERSALOON_FW_UPDATE 0x0F #define VERSALOON_FW_UPDATE_KEY 0xAA /* MCU Command */ #define VERSALOON_MCU_CMD_START 0x10 #define VERSALOON_MCU_CMD_END 0x1F /* USB_TO_XXX Command */ #define VERSALOON_USB_TO_XXX_CMD_START 0x20 #define VERSALOON_USB_TO_XXX_CMD_END 0x7F /* VSLLink Command */ #define VERSALOON_VSLLINK_CMD_START 0x80 #define VERSALOON_VSLLINK_CMD_END 0xFF /* Mass-product */ #define MP_OK 0x00 #define MP_FAIL 0x01 #define MP_ISSP 0x11 /* pending struct */ #define VERSALOON_MAX_PENDING_NUMBER 4096 typedef RESULT(*versaloon_callback_t)(void *, uint8_t *, uint8_t *); struct versaloon_want_pos_t { uint16_t offset; uint16_t size; uint8_t *buff; struct versaloon_want_pos_t *next; }; struct versaloon_pending_t { uint8_t type; uint8_t cmd; uint16_t want_data_pos; uint16_t want_data_size; uint16_t actual_data_size; uint8_t *data_buffer; uint8_t collect; uint32_t id; struct versaloon_want_pos_t *pos; void *extra_data; versaloon_callback_t callback; }; extern struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER]; extern uint16_t versaloon_pending_idx; void versaloon_set_pending_id(uint32_t id); void versaloon_set_callback(versaloon_callback_t callback); void versaloon_set_extra_data(void *p); RESULT versaloon_add_want_pos(uint16_t offset, uint16_t size, uint8_t *buff); RESULT versaloon_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie, uint16_t want_pos, uint16_t want_size, uint8_t *buffer, uint8_t collect); void versaloon_free_want_pos(void); RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen); extern uint8_t *versaloon_buf; extern uint8_t *versaloon_cmd_buf; extern uint16_t versaloon_buf_size; #endif /* OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_INTERNAL_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/vsllink.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009-2010 by Simon Qian <SimonQian@SimonQian.com> * ***************************************************************************/ /* Versaloon is a programming tool for multiple MCUs. * It's distributed under GPLv3. * You can find it at http://www.Versaloon.com/. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/adapter.h> #include <jtag/interface.h> #include <jtag/commands.h> #include <jtag/swd.h> #include <libusb.h> #include "versaloon/versaloon_include.h" #include "versaloon/versaloon.h" static int vsllink_tms_offset; struct pending_scan_result { int src_offset; int dest_offset; int length; /* Number of bits to read */ struct scan_command *command; /* Corresponding scan command */ uint8_t *ack; uint8_t *buffer; bool last; /* indicate the last scan pending */ }; #define MAX_PENDING_SCAN_RESULTS 256 static int pending_scan_results_length; static struct pending_scan_result pending_scan_results_buffer[MAX_PENDING_SCAN_RESULTS]; /* Queue command functions */ static void vsllink_end_state(tap_state_t state); static void vsllink_state_move(void); static void vsllink_path_move(int num_states, tap_state_t *path); static void vsllink_tms(int num_bits, const uint8_t *bits); static void vsllink_runtest(int num_cycles); static void vsllink_stableclocks(int num_cycles, int tms); static void vsllink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); static int vsllink_reset(int trst, int srst); /* VSLLink tap buffer functions */ static void vsllink_tap_append_step(int tms, int tdi); static void vsllink_tap_init(void); static int vsllink_tap_execute(void); static void vsllink_tap_ensure_pending(int scans); static void vsllink_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command); /* VSLLink SWD functions */ static int_least32_t vsllink_swd_frequency(int_least32_t hz); static int vsllink_swd_switch_seq(enum swd_special_seq seq); /* VSLLink lowlevel functions */ struct vsllink { struct libusb_context *libusb_ctx; struct libusb_device_handle *usb_device_handle; }; static int vsllink_usb_open(struct vsllink *vsllink); static void vsllink_usb_close(struct vsllink *vsllink); static void vsllink_debug_buffer(uint8_t *buffer, int length); static int tap_length; static int tap_buffer_size; static uint8_t *tms_buffer; static uint8_t *tdi_buffer; static uint8_t *tdo_buffer; static bool swd_mode; static struct vsllink *vsllink_handle; static int vsllink_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; int scan_size; enum scan_type type; uint8_t *buffer; LOG_DEBUG_IO("-------------------------------------" " vsllink " "-------------------------------------"); while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); vsllink_end_state(cmd->cmd.runtest->end_state); vsllink_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: LOG_DEBUG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); vsllink_end_state(cmd->cmd.statemove->end_state); vsllink_state_move(); break; case JTAG_PATHMOVE: LOG_DEBUG_IO("pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states, tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); vsllink_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); break; case JTAG_SCAN: LOG_DEBUG_IO("JTAG Scan..."); vsllink_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer( cmd->cmd.scan, &buffer); if (cmd->cmd.scan->ir_scan) LOG_DEBUG_IO( "JTAG Scan write IR(%d bits), " "end in %s:", scan_size, tap_state_name(cmd->cmd.scan->end_state)); else LOG_DEBUG_IO( "JTAG Scan write DR(%d bits), " "end in %s:", scan_size, tap_state_name(cmd->cmd.scan->end_state)); if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) vsllink_debug_buffer(buffer, DIV_ROUND_UP(scan_size, 8)); type = jtag_scan_type(cmd->cmd.scan); vsllink_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); break; case JTAG_SLEEP: LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); vsllink_tap_execute(); jtag_sleep(cmd->cmd.sleep->us); break; case JTAG_STABLECLOCKS: LOG_DEBUG_IO("add %d clocks", cmd->cmd.stableclocks->num_cycles); switch (tap_get_state()) { case TAP_RESET: /* tms must be '1' to stay * n TAP_RESET mode */ scan_size = 1; break; case TAP_DRSHIFT: case TAP_IDLE: case TAP_DRPAUSE: case TAP_IRSHIFT: case TAP_IRPAUSE: /* else, tms should be '0' */ scan_size = 0; break; /* above stable states are OK */ default: LOG_ERROR("jtag_add_clocks() " "in non-stable state \"%s\"", tap_state_name(tap_get_state()) ); exit(-1); } vsllink_stableclocks(cmd->cmd.stableclocks->num_cycles, scan_size); break; case JTAG_TMS: LOG_DEBUG_IO("add %d jtag tms", cmd->cmd.tms->num_bits); vsllink_tms(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits); break; default: LOG_ERROR("BUG: unknown JTAG command type " "encountered: %d", cmd->type); exit(-1); } cmd = cmd->next; } return vsllink_tap_execute(); } static int vsllink_speed(int speed) { if (swd_mode) { vsllink_swd_frequency(speed * 1000); return ERROR_OK; } versaloon_interface.adaptors.jtag_raw.config(0, (uint16_t)speed); return versaloon_interface.adaptors.peripheral_commit(); } static int vsllink_khz(int khz, int *jtag_speed) { *jtag_speed = khz; return ERROR_OK; } static int vsllink_speed_div(int jtag_speed, int *khz) { *khz = jtag_speed; return ERROR_OK; } static void vsllink_free_buffer(void) { free(tdi_buffer); tdi_buffer = NULL; free(tdo_buffer); tdo_buffer = NULL; free(tms_buffer); tms_buffer = NULL; } static int vsllink_quit(void) { versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST, 0, 0, GPIO_SRST | GPIO_TRST); versaloon_interface.adaptors.gpio.fini(0); if (swd_mode) versaloon_interface.adaptors.swd.fini(0); else versaloon_interface.adaptors.jtag_raw.fini(0); versaloon_interface.adaptors.peripheral_commit(); versaloon_interface.fini(); vsllink_free_buffer(); vsllink_usb_close(vsllink_handle); libusb_exit(vsllink_handle->libusb_ctx); free(vsllink_handle); return ERROR_OK; } static int vsllink_interface_init(void) { vsllink_handle = malloc(sizeof(struct vsllink)); if (!vsllink_handle) { LOG_ERROR("unable to allocate memory"); return ERROR_FAIL; } libusb_init(&vsllink_handle->libusb_ctx); if (vsllink_usb_open(vsllink_handle) != ERROR_OK) { LOG_ERROR("Can't find USB JTAG Interface!" "Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("vsllink found on %04X:%04X", versaloon_interface.usb_setting.vid, versaloon_interface.usb_setting.pid); versaloon_usb_device_handle = vsllink_handle->usb_device_handle; if (versaloon_interface.init() != ERROR_OK) return ERROR_FAIL; if (versaloon_interface.usb_setting.buf_size < 32) { versaloon_interface.fini(); return ERROR_FAIL; } return ERROR_OK; } static int vsllink_init(void) { int retval = vsllink_interface_init(); if (retval != ERROR_OK) return retval; versaloon_interface.adaptors.gpio.init(0); versaloon_interface.adaptors.gpio.config(0, GPIO_SRST, 0, GPIO_SRST, GPIO_SRST); versaloon_interface.adaptors.delay.delayms(100); versaloon_interface.adaptors.peripheral_commit(); if (swd_mode) { versaloon_interface.adaptors.gpio.config(0, GPIO_TRST, 0, GPIO_TRST, GPIO_TRST); versaloon_interface.adaptors.swd.init(0); vsllink_swd_frequency(adapter_get_speed_khz() * 1000); vsllink_swd_switch_seq(JTAG_TO_SWD); } else { /* malloc buffer size for tap */ tap_buffer_size = versaloon_interface.usb_setting.buf_size / 2 - 32; vsllink_free_buffer(); tdi_buffer = malloc(tap_buffer_size); tdo_buffer = malloc(tap_buffer_size); tms_buffer = malloc(tap_buffer_size); if ((!tdi_buffer) || (!tdo_buffer) || (!tms_buffer)) { vsllink_quit(); return ERROR_FAIL; } versaloon_interface.adaptors.jtag_raw.init(0); versaloon_interface.adaptors.jtag_raw.config(0, adapter_get_speed_khz()); versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST, GPIO_TRST, GPIO_SRST, GPIO_SRST); } if (versaloon_interface.adaptors.peripheral_commit() != ERROR_OK) return ERROR_FAIL; vsllink_reset(0, 0); vsllink_tap_init(); return ERROR_OK; } /************************************************************************** * Queue command implementations */ static void vsllink_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } /* Goes to the end state. */ static void vsllink_state_move(void) { int i; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); uint8_t tms_scan_bits = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); for (i = 0; i < tms_scan_bits; i++) vsllink_tap_append_step((tms_scan >> i) & 1, 0); tap_set_state(tap_get_end_state()); } static void vsllink_path_move(int num_states, tap_state_t *path) { for (int i = 0; i < num_states; i++) { if (path[i] == tap_state_transition(tap_get_state(), false)) vsllink_tap_append_step(0, 0); else if (path[i] == tap_state_transition(tap_get_state(), true)) vsllink_tap_append_step(1, 0); else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(path[i])); exit(-1); } tap_set_state(path[i]); } tap_set_end_state(tap_get_state()); } static void vsllink_tms(int num_bits, const uint8_t *bits) { for (int i = 0; i < num_bits; i++) vsllink_tap_append_step((bits[i / 8] >> (i % 8)) & 1, 0); } static void vsllink_stableclocks(int num_cycles, int tms) { while (num_cycles > 0) { vsllink_tap_append_step(tms, 0); num_cycles--; } } static void vsllink_runtest(int num_cycles) { tap_state_t saved_end_state = tap_get_end_state(); if (tap_get_state() != TAP_IDLE) { /* enter IDLE state */ vsllink_end_state(TAP_IDLE); vsllink_state_move(); } vsllink_stableclocks(num_cycles, 0); /* post-process */ /* set end_state */ vsllink_end_state(saved_end_state); if (tap_get_end_state() != tap_get_end_state()) vsllink_state_move(); } static void vsllink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) { tap_state_t saved_end_state; saved_end_state = tap_get_end_state(); /* Move to appropriate scan state */ vsllink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); if (tap_get_state() != tap_get_end_state()) vsllink_state_move(); vsllink_end_state(saved_end_state); /* Scan */ vsllink_tap_append_scan(scan_size, buffer, command); /* Goto Pause and record position to insert tms:0 */ vsllink_tap_append_step(0, 0); vsllink_tms_offset = tap_length; tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) vsllink_state_move(); } static int vsllink_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); if (!srst) versaloon_interface.adaptors.gpio.config(0, GPIO_SRST, 0, GPIO_SRST, GPIO_SRST); else versaloon_interface.adaptors.gpio.config(0, GPIO_SRST, GPIO_SRST, 0, 0); if (!swd_mode) { if (!trst) versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, GPIO_TRST); else versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, 0); } return versaloon_interface.adaptors.peripheral_commit(); } COMMAND_HANDLER(vsllink_handle_usb_vid_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], versaloon_interface.usb_setting.vid); return ERROR_OK; } COMMAND_HANDLER(vsllink_handle_usb_pid_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], versaloon_interface.usb_setting.pid); return ERROR_OK; } COMMAND_HANDLER(vsllink_handle_usb_bulkin_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], versaloon_interface.usb_setting.ep_in); versaloon_interface.usb_setting.ep_in |= 0x80; return ERROR_OK; } COMMAND_HANDLER(vsllink_handle_usb_bulkout_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], versaloon_interface.usb_setting.ep_out); versaloon_interface.usb_setting.ep_out &= ~0x80; return ERROR_OK; } COMMAND_HANDLER(vsllink_handle_usb_interface_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], versaloon_interface.usb_setting.interface); return ERROR_OK; } /************************************************************************** * VSLLink tap functions */ static void vsllink_tap_init(void) { tap_length = 0; pending_scan_results_length = 0; vsllink_tms_offset = 0; } static void vsllink_tap_ensure_pending(int scans) { int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length; if (scans > available_scans) vsllink_tap_execute(); } static void vsllink_tap_append_step(int tms, int tdi) { int index_var = tap_length / 8; int bit_index = tap_length % 8; uint8_t bit = 1 << bit_index; if (tms) tms_buffer[index_var] |= bit; else tms_buffer[index_var] &= ~bit; if (tdi) tdi_buffer[index_var] |= bit; else tdi_buffer[index_var] &= ~bit; tap_length++; if (tap_buffer_size * 8 <= tap_length) vsllink_tap_execute(); } static void vsllink_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command) { struct pending_scan_result *pending_scan_result; int len_tmp, len_all, i; len_all = 0; while (len_all < length) { vsllink_tap_ensure_pending(1); pending_scan_result = &pending_scan_results_buffer[ pending_scan_results_length]; if ((length - len_all) > (tap_buffer_size * 8 - tap_length)) { /* Use all memory available vsllink_tap_append_step will commit automatically */ len_tmp = tap_buffer_size * 8 - tap_length; pending_scan_result->last = false; } else { len_tmp = length - len_all; pending_scan_result->last = true; } pending_scan_result->src_offset = tap_length; pending_scan_result->dest_offset = len_all; pending_scan_result->length = len_tmp; pending_scan_result->command = command; pending_scan_result->buffer = buffer; pending_scan_results_length++; for (i = 0; i < len_tmp; i++) { vsllink_tap_append_step(((len_all + i) < length-1 ? 0 : 1), (buffer[(len_all + i)/8] >> ((len_all + i)%8)) & 1); } len_all += len_tmp; } } static int vsllink_jtag_execute(void) { int i; int result; if (tap_length <= 0) return ERROR_OK; versaloon_interface.adaptors.jtag_raw.execute(0, tdi_buffer, tms_buffer, tdo_buffer, tap_length); result = versaloon_interface.adaptors.peripheral_commit(); if (result == ERROR_OK) { for (i = 0; i < pending_scan_results_length; i++) { struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[i]; uint8_t *buffer = pending_scan_result->buffer; int length = pending_scan_result->length; int src_first = pending_scan_result->src_offset; int dest_first = pending_scan_result->dest_offset; bool last = pending_scan_result->last; struct scan_command *command; command = pending_scan_result->command; buf_set_buf(tdo_buffer, src_first, buffer, dest_first, length); LOG_DEBUG_IO( "JTAG scan read(%d bits, from src %d bits to dest %d bits):", length, src_first, dest_first); if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) vsllink_debug_buffer(buffer + dest_first / 8, DIV_ROUND_UP(length, 7)); if (last) { if (jtag_read_buffer(buffer, command) != ERROR_OK) { vsllink_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } free(pending_scan_result->buffer); } } } else { LOG_ERROR("vsllink_jtag_execute failure"); return ERROR_JTAG_QUEUE_FAILED; } vsllink_tap_init(); return ERROR_OK; } static int vsllink_tap_execute(void) { if (swd_mode) return ERROR_OK; return vsllink_jtag_execute(); } static int vsllink_swd_init(void) { LOG_INFO("VSLLink SWD mode enabled"); swd_mode = true; return ERROR_OK; } static int_least32_t vsllink_swd_frequency(int_least32_t hz) { const int_least32_t delay2hz[] = { 1850000, 235000, 130000, 102000, 85000, 72000 }; if (hz > 0) { uint16_t delay = UINT16_MAX; for (uint16_t i = 0; i < ARRAY_SIZE(delay2hz); i++) { if (hz >= delay2hz[i]) { hz = delay2hz[i]; delay = i; break; } } if (delay == UINT16_MAX) delay = (500000 / hz) - 1; /* Calculate retry count after a WAIT response. This will give * a retry timeout at about ~250 ms. 54 is the number of bits * found in a transaction. */ uint16_t retry_count = 250 * hz / 1000 / 54; LOG_DEBUG("SWD delay: %d, retry count: %d", delay, retry_count); versaloon_interface.adaptors.swd.config(0, 2, retry_count, delay); } return hz; } static int vsllink_swd_switch_seq(enum swd_special_seq seq) { switch (seq) { case LINE_RESET: LOG_DEBUG("SWD line reset"); versaloon_interface.adaptors.swd.seqout(0, swd_seq_line_reset, swd_seq_line_reset_len); break; case JTAG_TO_SWD: LOG_DEBUG("JTAG-to-SWD"); versaloon_interface.adaptors.swd.seqout(0, swd_seq_jtag_to_swd, swd_seq_jtag_to_swd_len); break; case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); versaloon_interface.adaptors.swd.seqout(0, swd_seq_swd_to_jtag, swd_seq_swd_to_jtag_len); break; default: LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; } return ERROR_OK; } static void vsllink_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { versaloon_interface.adaptors.swd.transact(0, cmd, value, NULL); } static void vsllink_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { versaloon_interface.adaptors.swd.transact(0, cmd, &value, NULL); } static int vsllink_swd_run_queue(void) { return versaloon_interface.adaptors.peripheral_commit(); } /**************************************************************************** * VSLLink USB low-level functions */ static int vsllink_check_usb_strings( struct libusb_device_handle *usb_device_handle, struct libusb_device_descriptor *usb_desc) { char desc_string[256]; int retval; if (adapter_get_required_serial()) { retval = libusb_get_string_descriptor_ascii(usb_device_handle, usb_desc->iSerialNumber, (unsigned char *)desc_string, sizeof(desc_string)); if (retval < 0) return ERROR_FAIL; if (strncmp(desc_string, adapter_get_required_serial(), sizeof(desc_string))) return ERROR_FAIL; } retval = libusb_get_string_descriptor_ascii(usb_device_handle, usb_desc->iProduct, (unsigned char *)desc_string, sizeof(desc_string)); if (retval < 0) return ERROR_FAIL; if (!strstr(desc_string, "Versaloon")) return ERROR_FAIL; return ERROR_OK; } static int vsllink_usb_open(struct vsllink *vsllink) { ssize_t num_devices, i; struct libusb_device **usb_devices; struct libusb_device_descriptor usb_desc; struct libusb_device_handle *usb_device_handle; int retval; num_devices = libusb_get_device_list(vsllink->libusb_ctx, &usb_devices); if (num_devices <= 0) return ERROR_FAIL; for (i = 0; i < num_devices; i++) { struct libusb_device *device = usb_devices[i]; retval = libusb_get_device_descriptor(device, &usb_desc); if (retval != 0) continue; if (usb_desc.idVendor != versaloon_interface.usb_setting.vid || usb_desc.idProduct != versaloon_interface.usb_setting.pid) continue; retval = libusb_open(device, &usb_device_handle); if (retval != 0) continue; retval = vsllink_check_usb_strings(usb_device_handle, &usb_desc); if (retval == ERROR_OK) break; libusb_close(usb_device_handle); } libusb_free_device_list(usb_devices, 1); if (i == num_devices) return ERROR_FAIL; retval = libusb_claim_interface(usb_device_handle, versaloon_interface.usb_setting.interface); if (retval != 0) { LOG_ERROR("unable to claim interface"); libusb_close(usb_device_handle); return ERROR_FAIL; } vsllink->usb_device_handle = usb_device_handle; return ERROR_OK; } static void vsllink_usb_close(struct vsllink *vsllink) { libusb_release_interface(vsllink->usb_device_handle, versaloon_interface.usb_setting.interface); libusb_close(vsllink->usb_device_handle); } #define BYTES_PER_LINE 16 static void vsllink_debug_buffer(uint8_t *buffer, int length) { char line[81]; char s[4]; int i; int j; for (i = 0; i < length; i += BYTES_PER_LINE) { snprintf(line, 5, "%04x", i & 0xffff); for (j = i; j < i + BYTES_PER_LINE && j < length; j++) { snprintf(s, 4, " %02x", buffer[j]); strcat(line, s); } LOG_DEBUG_IO("%s", line); } } static const struct command_registration vsllink_subcommand_handlers[] = { { .name = "usb_vid", .handler = &vsllink_handle_usb_vid_command, .mode = COMMAND_CONFIG, .help = "Set USB VID", .usage = "<vid>", }, { .name = "usb_pid", .handler = &vsllink_handle_usb_pid_command, .mode = COMMAND_CONFIG, .help = "Set USB PID", .usage = "<pid>", }, { .name = "usb_bulkin", .handler = &vsllink_handle_usb_bulkin_command, .mode = COMMAND_CONFIG, .help = "Set USB input endpoint", .usage = "<ep_in>", }, { .name = "usb_bulkout", .handler = &vsllink_handle_usb_bulkout_command, .mode = COMMAND_CONFIG, .help = "Set USB output endpoint", .usage = "<ep_out>", }, { .name = "usb_interface", .handler = &vsllink_handle_usb_interface_command, .mode = COMMAND_CONFIG, .help = "Set USB output interface", .usage = "<interface>", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration vsllink_command_handlers[] = { { .name = "vsllink", .mode = COMMAND_ANY, .help = "perform vsllink management", .chain = vsllink_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static const char * const vsllink_transports[] = {"jtag", "swd", NULL}; static const struct swd_driver vsllink_swd_driver = { .init = vsllink_swd_init, .switch_seq = vsllink_swd_switch_seq, .read_reg = vsllink_swd_read_reg, .write_reg = vsllink_swd_write_reg, .run = vsllink_swd_run_queue, }; static struct jtag_interface vsllink_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = vsllink_execute_queue, }; struct adapter_driver vsllink_adapter_driver = { .name = "vsllink", .transports = vsllink_transports, .commands = vsllink_command_handlers, .init = vsllink_init, .quit = vsllink_quit, .reset = vsllink_reset, .speed = vsllink_speed, .khz = vsllink_khz, .speed_div = vsllink_speed_div, .jtag_ops = &vsllink_interface, .swd_ops = &vsllink_swd_driver, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/xds110.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2017 by Texas Instruments, Inc. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <transport/transport.h> #include <jtag/adapter.h> #include <jtag/swd.h> #include <jtag/interface.h> #include <jtag/commands.h> #include <jtag/tcl.h> #include <libusb.h> /* XDS110 stand-alone probe voltage supply limits */ #define XDS110_MIN_VOLTAGE 1800 #define XDS110_MAX_VOLTAGE 3600 /* XDS110 stand-alone probe hardware ID */ #define XDS110_STAND_ALONE_ID 0x21 /* Firmware version that introduced OpenOCD support via block accesses */ #define OCD_FIRMWARE_VERSION 0x02030011 #define OCD_FIRMWARE_UPGRADE \ "XDS110: upgrade to version 2.3.0.11+ for improved support" /* Firmware version that introduced improved TCK performance */ #define FAST_TCK_FIRMWARE_VERSION 0x03000000 /* Firmware version that introduced 10 MHz and 12 MHz TCK support */ #define FAST_TCK_PLUS_FIRMWARE_VERSION 0x03000003 /*************************************************************************** * USB Connection Buffer Definitions * ***************************************************************************/ /* Max USB packet size for up to USB 3.0 */ #define MAX_PACKET 1024 /* * Maximum data payload that can be handled in a single call * Limitation is the size of the buffers in the XDS110 firmware */ #define MAX_DATA_BLOCK 4096 #ifndef USB_PAYLOAD_SIZE /* Largest data block plus parameters */ #define USB_PAYLOAD_SIZE (MAX_DATA_BLOCK + 60) #endif #define MAX_RESULT_QUEUE (MAX_DATA_BLOCK / 4) /*************************************************************************** * XDS110 Firmware API Definitions * ***************************************************************************/ /* * Default values controlling how the host communicates commands * with XDS110 firmware (automatic retry count and wait timeout) */ #define DEFAULT_ATTEMPTS (1) #define DEFAULT_TIMEOUT (4000) /* XDS110 API error codes */ #define SC_ERR_NONE 0 #define SC_ERR_XDS110_FAIL -261 #define SC_ERR_SWD_WAIT -613 #define SC_ERR_SWD_FAULT -614 #define SC_ERR_SWD_PROTOCOL -615 #define SC_ERR_SWD_PARITY -616 #define SC_ERR_SWD_DEVICE_ID -617 /* TCK frequency limits */ #define XDS110_MIN_TCK_SPEED 100 /* kHz */ #define XDS110_MAX_SLOW_TCK_SPEED 2500 /* kHz */ #define XDS110_MAX_FAST_TCK_SPEED 14000 /* kHz */ #define XDS110_DEFAULT_TCK_SPEED 2500 /* kHz */ /* Fixed TCK delay values for "Fast" TCK frequencies */ #define FAST_TCK_DELAY_14000_KHZ 0 #define FAST_TCK_DELAY_10000_KHZ 0xfffffffd #define FAST_TCK_DELAY_12000_KHZ 0xfffffffe #define FAST_TCK_DELAY_8500_KHZ 1 #define FAST_TCK_DELAY_5500_KHZ 2 /* For TCK frequencies below 5500 kHz, use calculated delay */ /* Scan mode on connect */ #define MODE_JTAG 1 /* XDS110 API JTAG state definitions */ #define XDS_JTAG_STATE_RESET 1 #define XDS_JTAG_STATE_IDLE 2 #define XDS_JTAG_STATE_SHIFT_DR 3 #define XDS_JTAG_STATE_SHIFT_IR 4 #define XDS_JTAG_STATE_PAUSE_DR 5 #define XDS_JTAG_STATE_PAUSE_IR 6 #define XDS_JTAG_STATE_EXIT1_DR 8 #define XDS_JTAG_STATE_EXIT1_IR 9 #define XDS_JTAG_STATE_EXIT2_DR 10 #define XDS_JTAG_STATE_EXIT2_IR 11 #define XDS_JTAG_STATE_SELECT_DR 12 #define XDS_JTAG_STATE_SELECT_IR 13 #define XDS_JTAG_STATE_UPDATE_DR 14 #define XDS_JTAG_STATE_UPDATE_IR 15 #define XDS_JTAG_STATE_CAPTURE_DR 16 #define XDS_JTAG_STATE_CAPTURE_IR 17 /* XDS110 API JTAG transit definitions */ #define XDS_JTAG_TRANSIT_QUICKEST 1 #define XDS_JTAG_TRANSIT_VIA_CAPTURE 2 #define XDS_JTAG_TRANSIT_VIA_IDLE 3 /* DAP register definitions as used by XDS110 APIs */ #define DAP_AP 0 /* DAP AP register type */ #define DAP_DP 1 /* DAP DP register type */ #define DAP_DP_IDCODE 0x0 /* DAP DP IDCODE register (read only) */ #define DAP_DP_ABORT 0x0 /* DAP DP ABORT register (write only) */ #define DAP_DP_STAT 0x4 /* DAP DP STAT register (for read only) */ #define DAP_DP_CTRL 0x4 /* DAP DP CTRL register (for write only) */ #define DAP_DP_ADDR 0x8 /* DAP DP SELECT register (legacy name) */ #define DAP_DP_RESEND 0x8 /* DAP DP RESEND register (read only) */ #define DAP_DP_SELECT 0x8 /* DAP DP SELECT register (write only) */ #define DAP_DP_RDBUFF 0xc /* DAP DP RDBUFF Read Buffer register */ #define DAP_AP_CSW 0x00 /* DAP AP Control Status Word */ #define DAP_AP_TAR 0x04 /* DAP AP Transfer Address */ #define DAP_AP_DRW 0x0C /* DAP AP Data Read/Write */ #define DAP_AP_BD0 0x10 /* DAP AP Banked Data 0 */ #define DAP_AP_BD1 0x14 /* DAP AP Banked Data 1 */ #define DAP_AP_BD2 0x18 /* DAP AP Banked Data 2 */ #define DAP_AP_BD3 0x1C /* DAP AP Banked Data 3 */ #define DAP_AP_RTBL 0xF8 /* DAP AP Debug ROM Table */ #define DAP_AP_IDR 0xFC /* DAP AP Identification Register */ /* Command packet definitions */ #define XDS_OUT_LEN 1 /* command (byte) */ #define XDS_IN_LEN 4 /* error code (int) */ /* XDS API Commands */ #define XDS_CONNECT 0x01 /* Connect JTAG connection */ #define XDS_DISCONNECT 0x02 /* Disconnect JTAG connection */ #define XDS_VERSION 0x03 /* Get firmware version and hardware ID */ #define XDS_SET_TCK 0x04 /* Set TCK delay (to set TCK frequency) */ #define XDS_SET_TRST 0x05 /* Assert or deassert nTRST signal */ #define XDS_CYCLE_TCK 0x07 /* Toggle TCK for a number of cycles */ #define XDS_GOTO_STATE 0x09 /* Go to requested JTAG state */ #define XDS_JTAG_SCAN 0x0c /* Send and receive JTAG scan */ #define XDS_SET_SRST 0x0e /* Assert or deassert nSRST signal */ #define CMAPI_CONNECT 0x0f /* CMAPI connect */ #define CMAPI_DISCONNECT 0x10 /* CMAPI disconnect */ #define CMAPI_ACQUIRE 0x11 /* CMAPI acquire */ #define CMAPI_RELEASE 0x12 /* CMAPI release */ #define CMAPI_REG_READ 0x15 /* CMAPI DAP register read */ #define CMAPI_REG_WRITE 0x16 /* CMAPI DAP register write */ #define SWD_CONNECT 0x17 /* Switch from JTAG to SWD connection */ #define SWD_DISCONNECT 0x18 /* Switch from SWD to JTAG connection */ #define CJTAG_CONNECT 0x2b /* Switch from JTAG to cJTAG connection */ #define CJTAG_DISCONNECT 0x2c /* Switch from cJTAG to JTAG connection */ #define XDS_SET_SUPPLY 0x32 /* Set up stand-alone probe upply voltage */ #define OCD_DAP_REQUEST 0x3a /* Handle block of DAP requests */ #define OCD_SCAN_REQUEST 0x3b /* Handle block of JTAG scan requests */ #define OCD_PATHMOVE 0x3c /* Handle PATHMOVE to navigate JTAG states */ #define CMD_IR_SCAN 1 #define CMD_DR_SCAN 2 #define CMD_RUNTEST 3 #define CMD_STABLECLOCKS 4 /* Array to convert from OpenOCD tap_state_t to XDS JTAG state */ static const uint32_t xds_jtag_state[] = { XDS_JTAG_STATE_EXIT2_DR, /* TAP_DREXIT2 = 0x0 */ XDS_JTAG_STATE_EXIT1_DR, /* TAP_DREXIT1 = 0x1 */ XDS_JTAG_STATE_SHIFT_DR, /* TAP_DRSHIFT = 0x2 */ XDS_JTAG_STATE_PAUSE_DR, /* TAP_DRPAUSE = 0x3 */ XDS_JTAG_STATE_SELECT_IR, /* TAP_IRSELECT = 0x4 */ XDS_JTAG_STATE_UPDATE_DR, /* TAP_DRUPDATE = 0x5 */ XDS_JTAG_STATE_CAPTURE_DR, /* TAP_DRCAPTURE = 0x6 */ XDS_JTAG_STATE_SELECT_DR, /* TAP_DRSELECT = 0x7 */ XDS_JTAG_STATE_EXIT2_IR, /* TAP_IREXIT2 = 0x8 */ XDS_JTAG_STATE_EXIT1_IR, /* TAP_IREXIT1 = 0x9 */ XDS_JTAG_STATE_SHIFT_IR, /* TAP_IRSHIFT = 0xa */ XDS_JTAG_STATE_PAUSE_IR, /* TAP_IRPAUSE = 0xb */ XDS_JTAG_STATE_IDLE, /* TAP_IDLE = 0xc */ XDS_JTAG_STATE_UPDATE_IR, /* TAP_IRUPDATE = 0xd */ XDS_JTAG_STATE_CAPTURE_IR, /* TAP_IRCAPTURE = 0xe */ XDS_JTAG_STATE_RESET, /* TAP_RESET = 0xf */ }; struct scan_result { bool first; uint8_t *buffer; uint32_t num_bits; }; struct xds110_info { /* USB connection handles and data buffers */ struct libusb_context *ctx; struct libusb_device_handle *dev; unsigned char read_payload[USB_PAYLOAD_SIZE]; unsigned char write_packet[3]; unsigned char write_payload[USB_PAYLOAD_SIZE]; /* Device vid/pid */ uint16_t vid; uint16_t pid; /* Debug interface */ uint8_t interface; uint8_t endpoint_in; uint8_t endpoint_out; /* Status flags */ bool is_connected; bool is_cmapi_connected; bool is_cmapi_acquired; bool is_swd_mode; bool is_ap_dirty; /* DAP register caches */ uint32_t select; uint32_t rdbuff; bool use_rdbuff; /* TCK speed and delay count*/ uint32_t speed; uint32_t delay_count; /* XDS110 voltage supply setting */ uint32_t voltage; /* XDS110 firmware and hardware version */ uint32_t firmware; uint16_t hardware; /* Transaction queues */ unsigned char txn_requests[MAX_DATA_BLOCK]; uint32_t *txn_dap_results[MAX_DATA_BLOCK / 4]; struct scan_result txn_scan_results[MAX_DATA_BLOCK / 4]; uint32_t txn_request_size; uint32_t txn_result_size; uint32_t txn_result_count; }; static struct xds110_info xds110 = { .ctx = NULL, .dev = NULL, .vid = 0, .pid = 0, .interface = 0, .endpoint_in = 0, .endpoint_out = 0, .is_connected = false, .is_cmapi_connected = false, .is_cmapi_acquired = false, .is_swd_mode = false, .is_ap_dirty = false, .speed = XDS110_DEFAULT_TCK_SPEED, .delay_count = 0, .voltage = 0, .firmware = 0, .hardware = 0, .txn_request_size = 0, .txn_result_size = 0, .txn_result_count = 0 }; static inline void xds110_set_u32(uint8_t *buffer, uint32_t value) { buffer[3] = (value >> 24) & 0xff; buffer[2] = (value >> 16) & 0xff; buffer[1] = (value >> 8) & 0xff; buffer[0] = (value >> 0) & 0xff; } static inline void xds110_set_u16(uint8_t *buffer, uint16_t value) { buffer[1] = (value >> 8) & 0xff; buffer[0] = (value >> 0) & 0xff; } static inline uint32_t xds110_get_u32(uint8_t *buffer) { uint32_t value = (((uint32_t)buffer[3]) << 24) | (((uint32_t)buffer[2]) << 16) | (((uint32_t)buffer[1]) << 8) | (((uint32_t)buffer[0]) << 0); return value; } static inline uint16_t xds110_get_u16(uint8_t *buffer) { uint16_t value = (((uint32_t)buffer[1]) << 8) | (((uint32_t)buffer[0]) << 0); return value; } /*************************************************************************** * usb connection routines * * * * The following functions handle connecting, reading, and writing to * * the XDS110 over USB using the libusb library. * ***************************************************************************/ static bool usb_connect(void) { struct libusb_context *ctx = NULL; struct libusb_device **list = NULL; struct libusb_device_handle *dev = NULL; struct libusb_device_descriptor desc; /* The vid/pids of possible XDS110 configurations */ uint16_t vids[] = { 0x0451, 0x0451, 0x1cbe }; uint16_t pids[] = { 0xbef3, 0xbef4, 0x02a5 }; /* Corresponding interface and endpoint numbers for configurations */ uint8_t interfaces[] = { 2, 2, 0 }; uint8_t endpoints_in[] = { 3, 3, 1 }; uint8_t endpoints_out[] = { 2, 2, 1 }; ssize_t count = 0; ssize_t i = 0; int result = 0; bool found = false; uint32_t device = 0; bool match = false; /* Initialize libusb context */ result = libusb_init(&ctx); if (result == 0) { /* Get list of USB devices attached to system */ count = libusb_get_device_list(ctx, &list); if (count <= 0) { result = -1; list = NULL; } } if (result == 0) { /* Scan through list of devices for any XDS110s */ for (i = 0; i < count; i++) { /* Check for device vid/pid match */ libusb_get_device_descriptor(list[i], &desc); match = false; for (device = 0; device < ARRAY_SIZE(vids); device++) { if (desc.idVendor == vids[device] && desc.idProduct == pids[device]) { match = true; break; } } if (match) { result = libusb_open(list[i], &dev); if (result == 0) { const int max_data = 256; unsigned char data[max_data + 1]; *data = '\0'; /* May be the requested device if serial number matches */ if (!adapter_get_required_serial()) { /* No serial number given; match first XDS110 found */ found = true; break; } else { /* Get the device's serial number string */ result = libusb_get_string_descriptor_ascii(dev, desc.iSerialNumber, data, max_data); if (result > 0 && strcmp((char *)data, adapter_get_required_serial()) == 0) { found = true; break; } } /* If we fall though to here, we don't want this device */ libusb_close(dev); dev = NULL; } } } } /* * We can fall through the for() loop with two possible exit conditions: * 1) found the right XDS110, and that device is open * 2) didn't find the XDS110, and no devices are currently open */ if (list) { /* Free the device list, we're done with it */ libusb_free_device_list(list, 1); } if (found) { /* Save the vid/pid of the device we're using */ xds110.vid = vids[device]; xds110.pid = pids[device]; /* Save the debug interface and endpoints for the device */ xds110.interface = interfaces[device]; xds110.endpoint_in = endpoints_in[device] | LIBUSB_ENDPOINT_IN; xds110.endpoint_out = endpoints_out[device] | LIBUSB_ENDPOINT_OUT; /* Save the context and device handles */ xds110.ctx = ctx; xds110.dev = dev; /* Set libusb to auto detach kernel */ (void)libusb_set_auto_detach_kernel_driver(dev, 1); /* Claim the debug interface on the XDS110 */ result = libusb_claim_interface(dev, xds110.interface); } else { /* Couldn't find an XDS110, flag the error */ result = -1; } /* On an error, clean up what we can */ if (result != 0) { if (dev) { /* Release the debug and data interface on the XDS110 */ (void)libusb_release_interface(dev, xds110.interface); libusb_close(dev); } if (ctx) libusb_exit(ctx); xds110.ctx = NULL; xds110.dev = NULL; } /* Log the results */ if (result == 0) LOG_INFO("XDS110: connected"); else LOG_ERROR("XDS110: failed to connect"); return (result == 0) ? true : false; } static void usb_disconnect(void) { if (xds110.dev) { /* Release the debug and data interface on the XDS110 */ (void)libusb_release_interface(xds110.dev, xds110.interface); libusb_close(xds110.dev); xds110.dev = NULL; } if (xds110.ctx) { libusb_exit(xds110.ctx); xds110.ctx = NULL; } LOG_INFO("XDS110: disconnected"); } static bool usb_read(unsigned char *buffer, int size, int *bytes_read, int timeout) { int result; if (!xds110.dev || !buffer || !bytes_read) return false; /* Force a non-zero timeout to prevent blocking */ if (timeout == 0) timeout = DEFAULT_TIMEOUT; result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_in, buffer, size, bytes_read, timeout); return (result == 0) ? true : false; } static bool usb_write(unsigned char *buffer, int size, int *written) { int bytes_written = 0; int result = LIBUSB_SUCCESS; int retries = 0; if (!xds110.dev || !buffer) return false; result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_out, buffer, size, &bytes_written, 0); while (result == LIBUSB_ERROR_PIPE && retries < 3) { /* Try clearing the pipe stall and retry transfer */ libusb_clear_halt(xds110.dev, xds110.endpoint_out); result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_out, buffer, size, &bytes_written, 0); retries++; } if (written) *written = bytes_written; return (result == 0 && size == bytes_written) ? true : false; } static bool usb_get_response(uint32_t *total_bytes_read, uint32_t timeout) { static unsigned char buffer[MAX_PACKET]; int bytes_read; uint16_t size; uint16_t count; bool success; size = 0; success = true; while (success) { success = usb_read(buffer, sizeof(buffer), &bytes_read, timeout); if (success) { /* * Validate that this appears to be a good response packet * First check it contains enough data for header and error * code, plus the first character is the start character */ if (bytes_read >= 7 && '*' == buffer[0]) { /* Extract the payload size */ size = xds110_get_u16(&buffer[1]); /* Sanity test on payload size */ if (USB_PAYLOAD_SIZE >= size && 4 <= size) { /* Check we didn't get more data than expected */ if ((bytes_read - 3) <= size) { /* Packet appears to be valid, move on */ break; } } } } /* * Somehow received an invalid packet, retry till we * time out or a valid response packet is received */ } /* Abort now if we didn't receive a valid response */ if (!success) { if (total_bytes_read) *total_bytes_read = 0; return false; } /* Build the return payload into xds110.read_payload */ /* Copy over payload data from received buffer (skipping header) */ count = 0; bytes_read -= 3; memcpy((void *)&xds110.read_payload[count], (void *)&buffer[3], bytes_read); count += bytes_read; /* * Drop timeout to just 1/2 second. Once the XDS110 starts sending * a response, the remaining packets should arrive in short order */ if (timeout > 500) timeout = 500; /* ms */ /* If there's more data to retrieve, get it now */ while ((count < size) && success) { success = usb_read(buffer, sizeof(buffer), &bytes_read, timeout); if (success) { if ((count + bytes_read) > size) { /* Read too much data, not a valid packet, abort */ success = false; } else { /* Copy this data over to xds110.read_payload */ memcpy((void *)&xds110.read_payload[count], (void *)buffer, bytes_read); count += bytes_read; } } } if (!success) count = 0; if (total_bytes_read) *total_bytes_read = count; return success; } static bool usb_send_command(uint16_t size) { int written; bool success = true; /* Check the packet length */ if (size > USB_PAYLOAD_SIZE) return false; /* Place the start character into the packet buffer */ xds110.write_packet[0] = '*'; /* Place the payload size into the packet buffer */ xds110_set_u16(&xds110.write_packet[1], size); /* Adjust size to include header */ size += 3; /* Send the data via the USB connection */ success = usb_write(xds110.write_packet, (int)size, &written); /* Check if the correct number of bytes was written */ if (written != (int)size) success = false; return success; } /*************************************************************************** * XDS110 firmware API routines * * * * The following functions handle calling into the XDS110 firmware to * * perform requested debug actions. * ***************************************************************************/ static bool xds_execute(uint32_t out_length, uint32_t in_length, uint32_t attempts, uint32_t timeout) { bool done = false; bool success = true; int error = 0; uint32_t bytes_read = 0; if (!xds110.dev) return false; while (!done && attempts > 0) { attempts--; /* Send command to XDS110 */ success = usb_send_command(out_length); if (success) { /* Get response from XDS110 */ success = usb_get_response(&bytes_read, timeout); } if (success) { /* Check for valid response from XDS code handling */ if (bytes_read != in_length) { /* Unexpected amount of data returned */ success = false; LOG_DEBUG("XDS110: command 0x%02x return %" PRIu32 " bytes, expected %" PRIu32, xds110.write_payload[0], bytes_read, in_length); } else { /* Extract error code from return packet */ error = (int)xds110_get_u32(&xds110.read_payload[0]); done = true; if (error != SC_ERR_NONE) LOG_DEBUG("XDS110: command 0x%02x returned error %d", xds110.write_payload[0], error); } } } if (!success) error = SC_ERR_XDS110_FAIL; if (error != 0) success = false; return success; } static bool xds_connect(void) { bool success; xds110.write_payload[0] = XDS_CONNECT; success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool xds_disconnect(void) { bool success; xds110.write_payload[0] = XDS_DISCONNECT; success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool xds_version(uint32_t *firmware_id, uint16_t *hardware_id) { uint8_t *fw_id_pntr = &xds110.read_payload[XDS_IN_LEN + 0]; /* 32-bits */ uint8_t *hw_id_pntr = &xds110.read_payload[XDS_IN_LEN + 4]; /* 16-bits */ bool success; xds110.write_payload[0] = XDS_VERSION; success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN + 6, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); if (success) { if (firmware_id) *firmware_id = xds110_get_u32(fw_id_pntr); if (hardware_id) *hardware_id = xds110_get_u16(hw_id_pntr); } return success; } static bool xds_set_tck_delay(uint32_t delay) { uint8_t *delay_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 32-bits */ bool success; xds110.write_payload[0] = XDS_SET_TCK; xds110_set_u32(delay_pntr, delay); success = xds_execute(XDS_OUT_LEN + 4, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool xds_set_trst(uint8_t trst) { uint8_t *trst_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 8-bits */ bool success; xds110.write_payload[0] = XDS_SET_TRST; *trst_pntr = trst; success = xds_execute(XDS_OUT_LEN + 1, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool xds_cycle_tck(uint32_t count) { uint8_t *count_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 32-bits */ bool success; xds110.write_payload[0] = XDS_CYCLE_TCK; xds110_set_u32(count_pntr, count); success = xds_execute(XDS_OUT_LEN + 4, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool xds_goto_state(uint32_t state) { uint8_t *state_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 32-bits */ uint8_t *transit_pntr = &xds110.write_payload[XDS_OUT_LEN+4]; /* 32-bits */ bool success; xds110.write_payload[0] = XDS_GOTO_STATE; xds110_set_u32(state_pntr, state); xds110_set_u32(transit_pntr, XDS_JTAG_TRANSIT_QUICKEST); success = xds_execute(XDS_OUT_LEN+8, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool xds_jtag_scan(uint32_t shift_state, uint16_t shift_bits, uint32_t end_state, uint8_t *data_out, uint8_t *data_in) { uint8_t *bits_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 16-bits */ uint8_t *path_pntr = &xds110.write_payload[XDS_OUT_LEN + 2]; /* 8-bits */ uint8_t *trans1_pntr = &xds110.write_payload[XDS_OUT_LEN + 3]; /* 8-bits */ uint8_t *end_pntr = &xds110.write_payload[XDS_OUT_LEN + 4]; /* 8-bits */ uint8_t *trans2_pntr = &xds110.write_payload[XDS_OUT_LEN + 5]; /* 8-bits */ uint8_t *pre_pntr = &xds110.write_payload[XDS_OUT_LEN + 6]; /* 16-bits */ uint8_t *pos_pntr = &xds110.write_payload[XDS_OUT_LEN + 8]; /* 16-bits */ uint8_t *delay_pntr = &xds110.write_payload[XDS_OUT_LEN + 10]; /* 16-bits */ uint8_t *rep_pntr = &xds110.write_payload[XDS_OUT_LEN + 12]; /* 16-bits */ uint8_t *out_pntr = &xds110.write_payload[XDS_OUT_LEN + 14]; /* 16-bits */ uint8_t *in_pntr = &xds110.write_payload[XDS_OUT_LEN + 16]; /* 16-bits */ uint8_t *data_out_pntr = &xds110.write_payload[XDS_OUT_LEN + 18]; uint8_t *data_in_pntr = &xds110.read_payload[XDS_IN_LEN+0]; uint16_t total_bytes = DIV_ROUND_UP(shift_bits, 8); bool success; xds110.write_payload[0] = XDS_JTAG_SCAN; xds110_set_u16(bits_pntr, shift_bits); /* bits to scan */ *path_pntr = (uint8_t)(shift_state & 0xff); /* IR vs DR path */ *trans1_pntr = (uint8_t)XDS_JTAG_TRANSIT_QUICKEST; /* start state route */ *end_pntr = (uint8_t)(end_state & 0xff); /* JTAG state after scan */ *trans2_pntr = (uint8_t)XDS_JTAG_TRANSIT_QUICKEST; /* end state route */ xds110_set_u16(pre_pntr, 0); /* number of preamble bits */ xds110_set_u16(pos_pntr, 0); /* number of postamble bits */ xds110_set_u16(delay_pntr, 0); /* number of extra TCKs after scan */ xds110_set_u16(rep_pntr, 1); /* number of repetitions */ xds110_set_u16(out_pntr, total_bytes); /* out buffer offset (if repeats) */ xds110_set_u16(in_pntr, total_bytes); /* in buffer offset (if repeats) */ memcpy((void *)data_out_pntr, (void *)data_out, total_bytes); success = xds_execute(XDS_OUT_LEN + 18 + total_bytes, XDS_IN_LEN + total_bytes, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); if (success) memcpy((void *)data_in, (void *)data_in_pntr, total_bytes); return success; } static bool xds_set_srst(uint8_t srst) { uint8_t *srst_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 8-bits */ bool success; xds110.write_payload[0] = XDS_SET_SRST; *srst_pntr = srst; success = xds_execute(XDS_OUT_LEN + 1, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool cmapi_connect(uint32_t *idcode) { uint8_t *idcode_pntr = &xds110.read_payload[XDS_IN_LEN + 0]; /* 32-bits */ bool success; xds110.write_payload[0] = CMAPI_CONNECT; success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN+4, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); if (success) { if (idcode) *idcode = xds110_get_u32(idcode_pntr); } return success; } static bool cmapi_disconnect(void) { bool success; xds110.write_payload[0] = CMAPI_DISCONNECT; success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool cmapi_acquire(void) { bool success; xds110.write_payload[0] = CMAPI_ACQUIRE; success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool cmapi_release(void) { bool success; xds110.write_payload[0] = CMAPI_RELEASE; success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool cmapi_read_dap_reg(uint32_t type, uint32_t ap_num, uint32_t address, uint32_t *value) { uint8_t *type_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 8-bits */ uint8_t *ap_num_pntr = &xds110.write_payload[XDS_OUT_LEN + 1]; /* 8-bits */ uint8_t *address_pntr = &xds110.write_payload[XDS_OUT_LEN + 2]; /* 8-bits */ uint8_t *value_pntr = &xds110.read_payload[XDS_IN_LEN + 0]; /* 32-bits */ bool success; xds110.write_payload[0] = CMAPI_REG_READ; *type_pntr = (uint8_t)(type & 0xff); *ap_num_pntr = (uint8_t)(ap_num & 0xff); *address_pntr = (uint8_t)(address & 0xff); success = xds_execute(XDS_OUT_LEN + 3, XDS_IN_LEN + 4, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); if (success) { if (value) *value = xds110_get_u32(value_pntr); } return success; } static bool cmapi_write_dap_reg(uint32_t type, uint32_t ap_num, uint32_t address, uint32_t *value) { uint8_t *type_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 8-bits */ uint8_t *ap_num_pntr = &xds110.write_payload[XDS_OUT_LEN + 1]; /* 8-bits */ uint8_t *address_pntr = &xds110.write_payload[XDS_OUT_LEN + 2]; /* 8-bits */ uint8_t *value_pntr = &xds110.write_payload[XDS_OUT_LEN + 3]; /* 32-bits */ bool success; if (!value) return false; xds110.write_payload[0] = CMAPI_REG_WRITE; *type_pntr = (uint8_t)(type & 0xff); *ap_num_pntr = (uint8_t)(ap_num & 0xff); *address_pntr = (uint8_t)(address & 0xff); xds110_set_u32(value_pntr, *value); success = xds_execute(XDS_OUT_LEN + 7, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool swd_connect(void) { bool success; xds110.write_payload[0] = SWD_CONNECT; success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool swd_disconnect(void) { bool success; xds110.write_payload[0] = SWD_DISCONNECT; success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool cjtag_connect(uint32_t format) { uint8_t *format_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 32-bits */ bool success; xds110.write_payload[0] = CJTAG_CONNECT; xds110_set_u32(format_pntr, format); success = xds_execute(XDS_OUT_LEN + 4, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool cjtag_disconnect(void) { bool success; xds110.write_payload[0] = CJTAG_DISCONNECT; success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool xds_set_supply(uint32_t voltage) { uint8_t *volts_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 32-bits */ uint8_t *source_pntr = &xds110.write_payload[XDS_OUT_LEN + 4]; /* 8-bits */ bool success; xds110.write_payload[0] = XDS_SET_SUPPLY; xds110_set_u32(volts_pntr, voltage); *source_pntr = (uint8_t)(voltage != 0 ? 1 : 0); success = xds_execute(XDS_OUT_LEN + 5, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } static bool ocd_dap_request(uint8_t *dap_requests, uint32_t request_size, uint32_t *dap_results, uint32_t result_count) { uint8_t *request_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; uint8_t *result_pntr = &xds110.read_payload[XDS_IN_LEN + 0]; bool success; if (!dap_requests || !dap_results) return false; xds110.write_payload[0] = OCD_DAP_REQUEST; memcpy((void *)request_pntr, (void *)dap_requests, request_size); success = xds_execute(XDS_OUT_LEN + request_size, XDS_IN_LEN + (result_count * 4), DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); if (success && (result_count > 0)) memcpy((void *)dap_results, (void *)result_pntr, result_count * 4); return success; } static bool ocd_scan_request(uint8_t *scan_requests, uint32_t request_size, uint8_t *scan_results, uint32_t result_size) { uint8_t *request_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; uint8_t *result_pntr = &xds110.read_payload[XDS_IN_LEN + 0]; bool success; if (!scan_requests || !scan_results) return false; xds110.write_payload[0] = OCD_SCAN_REQUEST; memcpy((void *)request_pntr, (void *)scan_requests, request_size); success = xds_execute(XDS_OUT_LEN + request_size, XDS_IN_LEN + result_size, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); if (success && (result_size > 0)) memcpy((void *)scan_results, (void *)result_pntr, result_size); return success; } static bool ocd_pathmove(uint32_t num_states, uint8_t *path) { uint8_t *num_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 32-bits */ uint8_t *path_pntr = &xds110.write_payload[XDS_OUT_LEN + 4]; bool success; if (!path) return false; xds110.write_payload[0] = OCD_PATHMOVE; xds110_set_u32(num_pntr, num_states); memcpy((void *)path_pntr, (void *)path, num_states); success = xds_execute(XDS_OUT_LEN + 4 + num_states, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); return success; } /*************************************************************************** * swd driver interface * * * * The following functions provide SWD support to OpenOCD. * ***************************************************************************/ static int xds110_swd_init(void) { xds110.is_swd_mode = true; return ERROR_OK; } static int xds110_swd_switch_seq(enum swd_special_seq seq) { uint32_t idcode; bool success; switch (seq) { case LINE_RESET: LOG_ERROR("Sequence SWD line reset (%d) not supported", seq); return ERROR_FAIL; case JTAG_TO_SWD: LOG_DEBUG("JTAG-to-SWD"); xds110.is_swd_mode = false; xds110.is_cmapi_connected = false; xds110.is_cmapi_acquired = false; /* Run sequence to put target in SWD mode */ success = swd_connect(); /* Re-initialize CMAPI API for DAP access */ if (success) { xds110.is_swd_mode = true; success = cmapi_connect(&idcode); if (success) { xds110.is_cmapi_connected = true; success = cmapi_acquire(); } } break; case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); xds110.is_swd_mode = false; xds110.is_cmapi_connected = false; xds110.is_cmapi_acquired = false; /* Run sequence to put target in JTAG mode */ success = swd_disconnect(); if (success) { /* Re-initialize JTAG interface */ success = cjtag_connect(MODE_JTAG); } break; default: LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; } if (success) return ERROR_OK; else return ERROR_FAIL; } static bool xds110_legacy_read_reg(uint8_t cmd, uint32_t *value) { /* Make sure this is a read request */ bool is_read_request = (0 != (SWD_CMD_RNW & cmd)); /* Determine whether this is a DP or AP register access */ uint32_t type = (0 != (SWD_CMD_APNDP & cmd)) ? DAP_AP : DAP_DP; /* Determine the AP number from cached SELECT value */ uint32_t ap_num = (xds110.select & 0xff000000) >> 24; /* Extract register address from command */ uint32_t address = ((cmd & SWD_CMD_A32) >> 1); /* Extract bank address from cached SELECT value */ uint32_t bank = (xds110.select & 0x000000f0); uint32_t reg_value = 0; uint32_t temp_value = 0; bool success; if (!is_read_request) return false; if (type == DAP_AP) { /* Add bank address to register address for CMAPI call */ address |= bank; } if (DAP_DP == type && DAP_DP_RDBUFF == address && xds110.use_rdbuff) { /* If RDBUFF is cached and this is a DP RDBUFF read, use the cache */ reg_value = xds110.rdbuff; success = true; } else if (DAP_AP == type && DAP_AP_DRW == address && xds110.use_rdbuff) { /* If RDBUFF is cached and this is an AP DRW read, use the cache, */ /* but still call into the firmware to get the next read. */ reg_value = xds110.rdbuff; success = cmapi_read_dap_reg(type, ap_num, address, &temp_value); } else { success = cmapi_read_dap_reg(type, ap_num, address, &temp_value); if (success) reg_value = temp_value; } /* Mark that we have consumed or invalidated the RDBUFF cache */ xds110.use_rdbuff = false; /* Handle result of read attempt */ if (!success) LOG_ERROR("XDS110: failed to read DAP register"); else if (value) *value = reg_value; if (success && DAP_AP == type) { /* * On a successful DAP AP read, we actually have the value from RDBUFF, * the firmware will have run the AP request and made the RDBUFF read */ xds110.use_rdbuff = true; xds110.rdbuff = temp_value; } return success; } static bool xds110_legacy_write_reg(uint8_t cmd, uint32_t value) { /* Make sure this isn't a read request */ bool is_read_request = (0 != (SWD_CMD_RNW & cmd)); /* Determine whether this is a DP or AP register access */ uint32_t type = (0 != (SWD_CMD_APNDP & cmd)) ? DAP_AP : DAP_DP; /* Determine the AP number from cached SELECT value */ uint32_t ap_num = (xds110.select & 0xff000000) >> 24; /* Extract register address from command */ uint32_t address = ((cmd & SWD_CMD_A32) >> 1); /* Extract bank address from cached SELECT value */ uint32_t bank = (xds110.select & 0x000000f0); bool success; if (is_read_request) return false; /* Invalidate the RDBUFF cache */ xds110.use_rdbuff = false; if (type == DAP_AP) { /* Add bank address to register address for CMAPI call */ address |= bank; /* Any write to an AP register invalidates the firmware's cache */ xds110.is_ap_dirty = true; } else if (address == DAP_DP_SELECT) { /* Any write to the SELECT register invalidates the firmware's cache */ xds110.is_ap_dirty = true; } success = cmapi_write_dap_reg(type, ap_num, address, &value); if (!success) { LOG_ERROR("XDS110: failed to write DAP register"); } else { /* * If the debugger wrote to SELECT, cache the value * to use to build the apNum and address values above */ if ((type == DAP_DP) && (address == DAP_DP_SELECT)) xds110.select = value; } return success; } static int xds110_swd_run_queue(void) { static uint32_t dap_results[MAX_RESULT_QUEUE]; uint8_t cmd; uint32_t request; uint32_t result; uint32_t value; bool success = true; if (xds110.txn_request_size == 0) return ERROR_OK; /* Terminate request queue */ xds110.txn_requests[xds110.txn_request_size++] = 0; if (xds110.firmware >= OCD_FIRMWARE_VERSION) { /* XDS110 firmware has the API to directly handle the queue */ success = ocd_dap_request(xds110.txn_requests, xds110.txn_request_size, dap_results, xds110.txn_result_count); } else { /* Legacy firmware needs to handle queue via discrete DAP calls */ request = 0; result = 0; while (xds110.txn_requests[request] != 0) { cmd = xds110.txn_requests[request++]; if (0 == (SWD_CMD_RNW & cmd)) { /* DAP register write command */ value = (uint32_t)(xds110.txn_requests[request++]) << 0; value |= (uint32_t)(xds110.txn_requests[request++]) << 8; value |= (uint32_t)(xds110.txn_requests[request++]) << 16; value |= (uint32_t)(xds110.txn_requests[request++]) << 24; if (success) success = xds110_legacy_write_reg(cmd, value); } else { /* DAP register read command */ value = 0; if (success) success = xds110_legacy_read_reg(cmd, &value); dap_results[result++] = value; } } } /* Transfer results into caller's buffers */ for (result = 0; result < xds110.txn_result_count; result++) if (xds110.txn_dap_results[result]) *xds110.txn_dap_results[result] = dap_results[result]; xds110.txn_request_size = 0; xds110.txn_result_size = 0; xds110.txn_result_count = 0; return (success) ? ERROR_OK : ERROR_FAIL; } static void xds110_swd_queue_cmd(uint8_t cmd, uint32_t *value) { /* Check if this is a read or write request */ bool is_read_request = (0 != (SWD_CMD_RNW & cmd)); /* Determine whether this is a DP or AP register access */ uint32_t type = (0 != (SWD_CMD_APNDP & cmd)) ? DAP_AP : DAP_DP; /* Extract register address from command */ uint32_t address = ((cmd & SWD_CMD_A32) >> 1); uint32_t request_size = (is_read_request) ? 1 : 5; /* Check if new request would be too large to fit */ if (((xds110.txn_request_size + request_size + 1) > MAX_DATA_BLOCK) || ((xds110.txn_result_count + 1) > MAX_RESULT_QUEUE)) xds110_swd_run_queue(); /* Set the START bit in cmd to ensure cmd is not zero */ /* (a value of zero is used to terminate the buffer) */ cmd |= SWD_CMD_START; /* Add request to queue; queue is built marshalled for XDS110 call */ if (is_read_request) { /* Queue read request, save pointer to pass back result */ xds110.txn_requests[xds110.txn_request_size++] = cmd; xds110.txn_dap_results[xds110.txn_result_count++] = value; xds110.txn_result_size += 4; } else { /* Check for and prevent sticky overrun detection */ if (DAP_DP == type && DAP_DP_CTRL == address && (*value & CORUNDETECT)) { LOG_DEBUG("XDS110: refusing to enable sticky overrun detection"); *value &= ~CORUNDETECT; } /* Queue write request, add value directly to queue buffer */ xds110.txn_requests[xds110.txn_request_size++] = cmd; xds110.txn_requests[xds110.txn_request_size++] = (*value >> 0) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (*value >> 8) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (*value >> 16) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (*value >> 24) & 0xff; } } static void xds110_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { assert(cmd & SWD_CMD_RNW); xds110_swd_queue_cmd(cmd, value); } static void xds110_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { assert(!(cmd & SWD_CMD_RNW)); xds110_swd_queue_cmd(cmd, &value); } /*************************************************************************** * jtag interface * * * * The following functions provide XDS110 interface to OpenOCD. * ***************************************************************************/ static void xds110_show_info(void) { uint32_t firmware = xds110.firmware; LOG_INFO("XDS110: vid/pid = %04x/%04x", xds110.vid, xds110.pid); LOG_INFO("XDS110: firmware version = %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32, (((firmware >> 28) & 0xf) * 10) + ((firmware >> 24) & 0xf), (((firmware >> 20) & 0xf) * 10) + ((firmware >> 16) & 0xf), (((firmware >> 12) & 0xf) * 10) + ((firmware >> 8) & 0xf), (((firmware >> 4) & 0xf) * 10) + ((firmware >> 0) & 0xf)); LOG_INFO("XDS110: hardware version = 0x%04x", xds110.hardware); if (adapter_get_required_serial()) LOG_INFO("XDS110: serial number = %s", adapter_get_required_serial()); if (xds110.is_swd_mode) { LOG_INFO("XDS110: connected to target via SWD"); LOG_INFO("XDS110: SWCLK set to %" PRIu32 " kHz", xds110.speed); } else { LOG_INFO("XDS110: connected to target via JTAG"); LOG_INFO("XDS110: TCK set to %" PRIu32 " kHz", xds110.speed); } /* Alert user that there's a better firmware to use */ if (firmware < OCD_FIRMWARE_VERSION) { LOG_WARNING("XDS110: the firmware is not optimized for OpenOCD"); LOG_WARNING(OCD_FIRMWARE_UPGRADE); } } static int xds110_quit(void) { if (xds110.is_cmapi_acquired) { (void)cmapi_release(); xds110.is_cmapi_acquired = false; } if (xds110.is_cmapi_connected) { (void)cmapi_disconnect(); xds110.is_cmapi_connected = false; } if (xds110.is_connected) { if (xds110.is_swd_mode) { /* Switch out of SWD mode */ (void)swd_disconnect(); } else { /* Switch out of cJTAG mode */ (void)cjtag_disconnect(); } /* Tell firmware we're disconnecting */ (void)xds_disconnect(); xds110.is_connected = false; } /* Close down the USB connection to the XDS110 debug probe */ usb_disconnect(); return ERROR_OK; } static int xds110_init(void) { bool success; /* Establish USB connection to the XDS110 debug probe */ success = usb_connect(); if (success) { /* Send connect message to XDS110 firmware */ success = xds_connect(); if (success) xds110.is_connected = true; } if (success) { uint32_t firmware; uint16_t hardware; /* Retrieve version IDs from firmware */ /* Version numbers are stored in BCD format */ success = xds_version(&firmware, &hardware); if (success) { /* Save the firmware and hardware version */ xds110.firmware = firmware; xds110.hardware = hardware; } } if (success) { /* Set supply voltage for stand-alone probes */ if (xds110.hardware == XDS110_STAND_ALONE_ID) { success = xds_set_supply(xds110.voltage); /* Allow time for target device to power up */ /* (CC32xx takes up to 1300 ms before debug is enabled) */ alive_sleep(1500); } else if (xds110.voltage != 0) { /* Voltage supply not a feature of embedded probes */ LOG_WARNING( "XDS110: ignoring supply voltage, not supported on this probe"); } } if (success) { success = xds_set_trst(0); if (success) success = xds_cycle_tck(50); if (success) success = xds_set_trst(1); if (success) success = xds_cycle_tck(50); } if (success) { if (xds110.is_swd_mode) { /* Switch to SWD if needed */ success = swd_connect(); } else { success = cjtag_connect(MODE_JTAG); } } if (success && xds110.is_swd_mode) { uint32_t idcode; /* Connect to CMAPI interface in XDS110 */ success = cmapi_connect(&idcode); /* Acquire exclusive access to CMAPI interface */ if (success) { xds110.is_cmapi_connected = true; success = cmapi_acquire(); if (success) xds110.is_cmapi_acquired = true; } } if (!success) xds110_quit(); if (success) xds110_show_info(); return (success) ? ERROR_OK : ERROR_FAIL; } static void xds110_legacy_scan(uint32_t shift_state, uint32_t total_bits, uint32_t end_state, uint8_t *data_out, uint8_t *data_in) { (void)xds_jtag_scan(shift_state, total_bits, end_state, data_out, data_in); } static void xds110_legacy_runtest(uint32_t clocks, uint32_t end_state) { xds_goto_state(XDS_JTAG_STATE_IDLE); xds_cycle_tck(clocks); xds_goto_state(end_state); } static void xds110_legacy_stableclocks(uint32_t clocks) { xds_cycle_tck(clocks); } static void xds110_flush(void) { uint8_t command; uint32_t clocks; uint32_t shift_state; uint32_t end_state; uint32_t bits; uint32_t bytes; uint32_t request; uint32_t result; uint8_t *data_out; uint8_t data_in[MAX_DATA_BLOCK]; uint8_t *data_pntr; if (xds110.txn_request_size == 0) return; /* Terminate request queue */ xds110.txn_requests[xds110.txn_request_size++] = 0; if (xds110.firmware >= OCD_FIRMWARE_VERSION) { /* Updated firmware has the API to directly handle the queue */ (void)ocd_scan_request(xds110.txn_requests, xds110.txn_request_size, data_in, xds110.txn_result_size); } else { /* Legacy firmware needs to handle queue via discrete JTAG calls */ request = 0; result = 0; while (xds110.txn_requests[request] != 0) { command = xds110.txn_requests[request++]; switch (command) { case CMD_IR_SCAN: case CMD_DR_SCAN: if (command == CMD_IR_SCAN) shift_state = XDS_JTAG_STATE_SHIFT_IR; else shift_state = XDS_JTAG_STATE_SHIFT_DR; end_state = (uint32_t)(xds110.txn_requests[request++]); bits = (uint32_t)(xds110.txn_requests[request++]) << 0; bits |= (uint32_t)(xds110.txn_requests[request++]) << 8; data_out = &xds110.txn_requests[request]; bytes = DIV_ROUND_UP(bits, 8); xds110_legacy_scan(shift_state, bits, end_state, data_out, &data_in[result]); result += bytes; request += bytes; break; case CMD_RUNTEST: clocks = (uint32_t)(xds110.txn_requests[request++]) << 0; clocks |= (uint32_t)(xds110.txn_requests[request++]) << 8; clocks |= (uint32_t)(xds110.txn_requests[request++]) << 16; clocks |= (uint32_t)(xds110.txn_requests[request++]) << 24; end_state = (uint32_t)xds110.txn_requests[request++]; xds110_legacy_runtest(clocks, end_state); break; case CMD_STABLECLOCKS: clocks = (uint32_t)(xds110.txn_requests[request++]) << 0; clocks |= (uint32_t)(xds110.txn_requests[request++]) << 8; clocks |= (uint32_t)(xds110.txn_requests[request++]) << 16; clocks |= (uint32_t)(xds110.txn_requests[request++]) << 24; xds110_legacy_stableclocks(clocks); break; default: LOG_ERROR("BUG: unknown JTAG command type 0x%x encountered", command); exit(-1); break; } } } /* Transfer results into caller's buffers from data_in buffer */ bits = 0; /* Bit offset into current scan result */ data_pntr = data_in; for (result = 0; result < xds110.txn_result_count; result++) { if (xds110.txn_scan_results[result].first) { if (bits != 0) { bytes = DIV_ROUND_UP(bits, 8); data_pntr += bytes; } bits = 0; } if (xds110.txn_scan_results[result].buffer) bit_copy(xds110.txn_scan_results[result].buffer, 0, data_pntr, bits, xds110.txn_scan_results[result].num_bits); bits += xds110.txn_scan_results[result].num_bits; } xds110.txn_request_size = 0; xds110.txn_result_size = 0; xds110.txn_result_count = 0; } static int xds110_reset(int trst, int srst) { uint8_t value; bool success; int retval = ERROR_OK; if (trst != -1) { if (trst == 0) { /* Deassert nTRST (active low) */ value = 1; } else { /* Assert nTRST (active low) */ value = 0; } success = xds_set_trst(value); if (!success) retval = ERROR_FAIL; } if (srst != -1) { if (srst == 0) { /* Deassert nSRST (active low) */ value = 1; } else { /* Assert nSRST (active low) */ value = 0; } success = xds_set_srst(value); if (!success) retval = ERROR_FAIL; /* Toggle TCK to trigger HIB on CC13x/CC26x devices */ if (success && !xds110.is_swd_mode) { /* Toggle TCK for about 50 ms */ success = xds_cycle_tck(xds110.speed * 50); } if (!success) retval = ERROR_FAIL; } return retval; } static void xds110_execute_sleep(struct jtag_command *cmd) { jtag_sleep(cmd->cmd.sleep->us); } static void xds110_execute_tlr_reset(struct jtag_command *cmd) { (void)xds_goto_state(XDS_JTAG_STATE_RESET); } static void xds110_execute_pathmove(struct jtag_command *cmd) { uint32_t i; uint32_t num_states; uint8_t *path; num_states = (uint32_t)cmd->cmd.pathmove->num_states; if (num_states == 0) return; path = malloc(num_states * sizeof(uint8_t)); if (!path) { LOG_ERROR("XDS110: unable to allocate memory"); return; } /* Convert requested path states into XDS API states */ for (i = 0; i < num_states; i++) path[i] = (uint8_t)xds_jtag_state[cmd->cmd.pathmove->path[i]]; if (xds110.firmware >= OCD_FIRMWARE_VERSION) { /* Updated firmware fully supports pathmove */ (void)ocd_pathmove(num_states, path); } else { /* Notify user that legacy firmware simply cannot handle pathmove */ LOG_ERROR("XDS110: the firmware does not support pathmove command"); LOG_ERROR(OCD_FIRMWARE_UPGRADE); /* If pathmove is required, then debug is not possible */ exit(-1); } free((void *)path); } static void xds110_queue_scan(struct jtag_command *cmd) { int i; uint32_t offset; uint32_t total_fields; uint32_t total_bits; uint32_t total_bytes; uint8_t end_state; uint8_t *buffer; /* Calculate the total number of bits to scan */ total_bits = 0; total_fields = 0; for (i = 0; i < cmd->cmd.scan->num_fields; i++) { total_fields++; total_bits += (uint32_t)cmd->cmd.scan->fields[i].num_bits; } if (total_bits == 0) return; total_bytes = DIV_ROUND_UP(total_bits, 8); /* Check if new request would be too large to fit */ if (((xds110.txn_request_size + 1 + total_bytes + sizeof(end_state) + 1) > MAX_DATA_BLOCK) || ((xds110.txn_result_count + total_fields) > MAX_RESULT_QUEUE)) xds110_flush(); /* Check if this single request is too large to fit */ if ((1 + total_bytes + sizeof(end_state) + 1) > MAX_DATA_BLOCK) { LOG_ERROR("BUG: JTAG scan request is too large to handle (%" PRIu32 " bits)", total_bits); /* Failing to run this scan mucks up debug on this target */ exit(-1); } if (cmd->cmd.scan->ir_scan) xds110.txn_requests[xds110.txn_request_size++] = CMD_IR_SCAN; else xds110.txn_requests[xds110.txn_request_size++] = CMD_DR_SCAN; end_state = (uint8_t)xds_jtag_state[cmd->cmd.scan->end_state]; xds110.txn_requests[xds110.txn_request_size++] = end_state; xds110.txn_requests[xds110.txn_request_size++] = (total_bits >> 0) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (total_bits >> 8) & 0xff; /* Build request data by flattening fields into single buffer */ /* also populate the results array to return the results when run */ offset = 0; buffer = &xds110.txn_requests[xds110.txn_request_size]; /* Clear data out buffer to default value of all zeros */ memset((void *)buffer, 0x00, total_bytes); for (i = 0; i < cmd->cmd.scan->num_fields; i++) { if (cmd->cmd.scan->fields[i].out_value) { /* Copy over data to scan out into request buffer */ bit_copy(buffer, offset, cmd->cmd.scan->fields[i].out_value, 0, cmd->cmd.scan->fields[i].num_bits); } offset += cmd->cmd.scan->fields[i].num_bits; xds110.txn_scan_results[xds110.txn_result_count].first = (i == 0); xds110.txn_scan_results[xds110.txn_result_count].num_bits = cmd->cmd.scan->fields[i].num_bits; xds110.txn_scan_results[xds110.txn_result_count++].buffer = cmd->cmd.scan->fields[i].in_value; } xds110.txn_request_size += total_bytes; xds110.txn_result_size += total_bytes; } static void xds110_queue_runtest(struct jtag_command *cmd) { uint32_t clocks = (uint32_t)cmd->cmd.stableclocks->num_cycles; uint8_t end_state = (uint8_t)xds_jtag_state[cmd->cmd.runtest->end_state]; /* Check if new request would be too large to fit */ if ((xds110.txn_request_size + 1 + sizeof(clocks) + sizeof(end_state) + 1) > MAX_DATA_BLOCK) xds110_flush(); /* Queue request and cycle count directly to queue buffer */ xds110.txn_requests[xds110.txn_request_size++] = CMD_RUNTEST; xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 0) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 8) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 16) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 24) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = end_state; } static void xds110_queue_stableclocks(struct jtag_command *cmd) { uint32_t clocks = (uint32_t)cmd->cmd.stableclocks->num_cycles; /* Check if new request would be too large to fit */ if ((xds110.txn_request_size + 1 + sizeof(clocks) + 1) > MAX_DATA_BLOCK) xds110_flush(); /* Queue request and cycle count directly to queue buffer */ xds110.txn_requests[xds110.txn_request_size++] = CMD_STABLECLOCKS; xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 0) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 8) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 16) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 24) & 0xff; } static void xds110_execute_command(struct jtag_command *cmd) { switch (cmd->type) { case JTAG_SLEEP: xds110_flush(); xds110_execute_sleep(cmd); break; case JTAG_TLR_RESET: xds110_flush(); xds110_execute_tlr_reset(cmd); break; case JTAG_PATHMOVE: xds110_flush(); xds110_execute_pathmove(cmd); break; case JTAG_SCAN: xds110_queue_scan(cmd); break; case JTAG_RUNTEST: xds110_queue_runtest(cmd); break; case JTAG_STABLECLOCKS: xds110_queue_stableclocks(cmd); break; case JTAG_TMS: default: LOG_ERROR("BUG: unknown JTAG command type 0x%x encountered", cmd->type); exit(-1); } } static int xds110_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; while (cmd) { xds110_execute_command(cmd); cmd = cmd->next; } xds110_flush(); return ERROR_OK; } static int xds110_speed(int speed) { double freq_to_use; uint32_t delay_count; bool success; if (speed == 0) { LOG_INFO("XDS110: RTCK not supported"); return ERROR_JTAG_NOT_IMPLEMENTED; } if (speed < XDS110_MIN_TCK_SPEED) { LOG_INFO("XDS110: increase speed request: %d kHz to %d kHz minimum", speed, XDS110_MIN_TCK_SPEED); speed = XDS110_MIN_TCK_SPEED; } /* Older XDS110 firmware had inefficient scan routines and could only */ /* achieve a peak TCK frequency of about 2500 kHz */ if (xds110.firmware < FAST_TCK_FIRMWARE_VERSION) { /* Check for request for top speed or higher */ if (speed >= XDS110_MAX_SLOW_TCK_SPEED) { /* Inform user that speed was adjusted down to max possible */ if (speed > XDS110_MAX_SLOW_TCK_SPEED) { LOG_INFO( "XDS110: reduce speed request: %d kHz to %d kHz maximum", speed, XDS110_MAX_SLOW_TCK_SPEED); speed = XDS110_MAX_SLOW_TCK_SPEED; } delay_count = 0; } else { const double XDS110_TCK_PULSE_INCREMENT = 66.0; freq_to_use = speed * 1000; /* Hz */ delay_count = 0; /* Calculate the delay count value */ double one_giga = 1000000000; /* Get the pulse duration for the max frequency supported in ns */ double max_freq_pulse_duration = one_giga / (XDS110_MAX_SLOW_TCK_SPEED * 1000); /* Convert frequency to pulse duration */ double freq_to_pulse_width_in_ns = one_giga / freq_to_use; /* * Start with the pulse duration for the maximum frequency. Keep * decrementing time added by each count value till the requested * frequency pulse is less than the calculated value. */ double current_value = max_freq_pulse_duration; while (current_value < freq_to_pulse_width_in_ns) { current_value += XDS110_TCK_PULSE_INCREMENT; ++delay_count; } /* * Determine which delay count yields the best match. * The one obtained above or one less. */ if (delay_count) { double diff_freq_1 = freq_to_use - (one_giga / (max_freq_pulse_duration + (XDS110_TCK_PULSE_INCREMENT * delay_count))); double diff_freq_2 = (one_giga / (max_freq_pulse_duration + (XDS110_TCK_PULSE_INCREMENT * (delay_count - 1)))) - freq_to_use; /* One less count value yields a better match */ if (diff_freq_1 > diff_freq_2) --delay_count; } } /* Newer firmware has reworked TCK routines that are much more efficient */ /* and can now achieve a peak TCK frequency of 14000 kHz */ } else { if (speed >= XDS110_MAX_FAST_TCK_SPEED) { if (speed > XDS110_MAX_FAST_TCK_SPEED) { LOG_INFO( "XDS110: reduce speed request: %d kHz to %d kHz maximum", speed, XDS110_MAX_FAST_TCK_SPEED); speed = XDS110_MAX_FAST_TCK_SPEED; } delay_count = 0; } else if (speed >= 12000 && xds110.firmware >= FAST_TCK_PLUS_FIRMWARE_VERSION) { delay_count = FAST_TCK_DELAY_12000_KHZ; } else if (speed >= 10000 && xds110.firmware >= FAST_TCK_PLUS_FIRMWARE_VERSION) { delay_count = FAST_TCK_DELAY_10000_KHZ; } else if (speed >= 8500) { delay_count = FAST_TCK_DELAY_8500_KHZ; } else if (speed >= 5500) { delay_count = FAST_TCK_DELAY_5500_KHZ; } else { /* Calculate the delay count to set the frequency */ /* Formula determined by measuring the waveform on Saeleae logic */ /* analyzer using known values for delay count */ const double m = 17100000.0; /* slope */ const double b = -1.02; /* y-intercept */ freq_to_use = speed * 1000; /* Hz */ double period = 1.0/freq_to_use; double delay = m * period + b; if (delay < 1.0) delay_count = 1; else delay_count = (uint32_t)delay; } } /* Send the delay count to the XDS110 firmware */ success = xds_set_tck_delay(delay_count); if (success) { xds110.delay_count = delay_count; xds110.speed = speed; } return (success) ? ERROR_OK : ERROR_FAIL; } static int xds110_speed_div(int speed, int *khz) { *khz = speed; return ERROR_OK; } static int xds110_khz(int khz, int *jtag_speed) { *jtag_speed = khz; return ERROR_OK; } COMMAND_HANDLER(xds110_handle_info_command) { xds110_show_info(); return ERROR_OK; } COMMAND_HANDLER(xds110_handle_supply_voltage_command) { uint32_t voltage = 0; if (CMD_ARGC == 1) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], voltage); if (voltage == 0 || (voltage >= XDS110_MIN_VOLTAGE && voltage <= XDS110_MAX_VOLTAGE)) { /* Requested voltage is in range */ xds110.voltage = voltage; } else { LOG_ERROR("XDS110: voltage must be 0 or between %d and %d " "millivolts", XDS110_MIN_VOLTAGE, XDS110_MAX_VOLTAGE); return ERROR_FAIL; } xds110.voltage = voltage; } else return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } static const struct command_registration xds110_subcommand_handlers[] = { { .name = "info", .handler = &xds110_handle_info_command, .mode = COMMAND_EXEC, .help = "show XDS110 info", .usage = "", }, { .name = "supply", .handler = &xds110_handle_supply_voltage_command, .mode = COMMAND_CONFIG, .help = "set the XDS110 probe supply voltage", .usage = "voltage_in_millivolts", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration xds110_command_handlers[] = { { .name = "xds110", .mode = COMMAND_ANY, .help = "perform XDS110 management", .usage = "", .chain = xds110_subcommand_handlers, }, COMMAND_REGISTRATION_DONE }; static const struct swd_driver xds110_swd_driver = { .init = xds110_swd_init, .switch_seq = xds110_swd_switch_seq, .read_reg = xds110_swd_read_reg, .write_reg = xds110_swd_write_reg, .run = xds110_swd_run_queue, }; static const char * const xds110_transport[] = { "swd", "jtag", NULL }; static struct jtag_interface xds110_interface = { .execute_queue = xds110_execute_queue, }; struct adapter_driver xds110_adapter_driver = { .name = "xds110", .transports = xds110_transport, .commands = xds110_command_handlers, .init = xds110_init, .quit = xds110_quit, .reset = xds110_reset, .speed = xds110_speed, .khz = xds110_khz, .speed_div = xds110_speed_div, .jtag_ops = &xds110_interface, .swd_ops = &xds110_swd_driver, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/drivers/xlnx-pcie-xvc.c ================================================ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019 Google, LLC. * Author: Moritz Fischer <moritzf@google.com> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdint.h> #include <stdlib.h> #include <math.h> #include <unistd.h> #include <linux/pci.h> #include <jtag/interface.h> #include <jtag/swd.h> #include <jtag/commands.h> #include <helper/replacements.h> #include <helper/bits.h> /* Available only from kernel v4.10 */ #ifndef PCI_CFG_SPACE_EXP_SIZE #define PCI_CFG_SPACE_EXP_SIZE 4096 #endif #define PCIE_EXT_CAP_LST 0x100 #define XLNX_XVC_EXT_CAP 0x00 #define XLNX_XVC_VSEC_HDR 0x04 #define XLNX_XVC_LEN_REG 0x0C #define XLNX_XVC_TMS_REG 0x10 #define XLNX_XVC_TDX_REG 0x14 #define XLNX_XVC_CAP_SIZE 0x20 #define XLNX_XVC_VSEC_ID 0x8 #define XLNX_XVC_MAX_BITS 0x20 #define MASK_ACK(x) (((x) >> 9) & 0x7) #define MASK_PAR(x) ((int)((x) & 0x1)) struct xlnx_pcie_xvc { int fd; unsigned offset; char *device; }; static struct xlnx_pcie_xvc xlnx_pcie_xvc_state; static struct xlnx_pcie_xvc *xlnx_pcie_xvc = &xlnx_pcie_xvc_state; static int xlnx_pcie_xvc_read_reg(const int offset, uint32_t *val) { uint32_t res; int err; /* Note: This should be ok endianness-wise because by going * through sysfs the kernel does the conversion in the config * space accessor functions */ err = pread(xlnx_pcie_xvc->fd, &res, sizeof(res), xlnx_pcie_xvc->offset + offset); if (err != sizeof(res)) { LOG_ERROR("Failed to read offset %x", offset); return ERROR_JTAG_DEVICE_ERROR; } if (val) *val = res; return ERROR_OK; } static int xlnx_pcie_xvc_write_reg(const int offset, const uint32_t val) { int err; /* Note: This should be ok endianness-wise because by going * through sysfs the kernel does the conversion in the config * space accessor functions */ err = pwrite(xlnx_pcie_xvc->fd, &val, sizeof(val), xlnx_pcie_xvc->offset + offset); if (err != sizeof(val)) { LOG_ERROR("Failed to write offset: %x with value: %" PRIx32, offset, val); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int xlnx_pcie_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi, uint32_t *tdo) { int err; err = xlnx_pcie_xvc_write_reg(XLNX_XVC_LEN_REG, num_bits); if (err != ERROR_OK) return err; err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TMS_REG, tms); if (err != ERROR_OK) return err; err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TDX_REG, tdi); if (err != ERROR_OK) return err; err = xlnx_pcie_xvc_read_reg(XLNX_XVC_TDX_REG, tdo); if (err != ERROR_OK) return err; if (tdo) LOG_DEBUG_IO("Transact num_bits: %zu, tms: %" PRIx32 ", tdi: %" PRIx32 ", tdo: %" PRIx32, num_bits, tms, tdi, *tdo); else LOG_DEBUG_IO("Transact num_bits: %zu, tms: %" PRIx32 ", tdi: %" PRIx32 ", tdo: <null>", num_bits, tms, tdi); return ERROR_OK; } static int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd) { int tms = tap_get_state() == TAP_RESET ? 1 : 0; size_t left = cmd->cmd.stableclocks->num_cycles; size_t write; int err; LOG_DEBUG("stableclocks %i cycles", cmd->cmd.runtest->num_cycles); while (left) { write = MIN(XLNX_XVC_MAX_BITS, left); err = xlnx_pcie_xvc_transact(write, tms, 0, NULL); if (err != ERROR_OK) return err; left -= write; }; return ERROR_OK; } static int xlnx_pcie_xvc_execute_statemove(size_t skip) { uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); int err; LOG_DEBUG("statemove starting at (skip: %zu) %s end in %s", skip, tap_state_name(tap_get_state()), tap_state_name(tap_get_end_state())); err = xlnx_pcie_xvc_transact(tms_count - skip, tms_scan >> skip, 0, NULL); if (err != ERROR_OK) return err; tap_set_state(tap_get_end_state()); return ERROR_OK; } static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd) { int err = ERROR_OK; LOG_DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); tap_state_t tmp_state = tap_get_end_state(); if (tap_get_state() != TAP_IDLE) { tap_set_end_state(TAP_IDLE); err = xlnx_pcie_xvc_execute_statemove(0); if (err != ERROR_OK) return err; }; size_t left = cmd->cmd.runtest->num_cycles; size_t write; while (left) { write = MIN(XLNX_XVC_MAX_BITS, left); err = xlnx_pcie_xvc_transact(write, 0, 0, NULL); if (err != ERROR_OK) return err; left -= write; }; tap_set_end_state(tmp_state); if (tap_get_state() != tap_get_end_state()) err = xlnx_pcie_xvc_execute_statemove(0); return err; } static int xlnx_pcie_xvc_execute_pathmove(struct jtag_command *cmd) { size_t num_states = cmd->cmd.pathmove->num_states; tap_state_t *path = cmd->cmd.pathmove->path; int err = ERROR_OK; size_t i; LOG_DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); for (i = 0; i < num_states; i++) { if (path[i] == tap_state_transition(tap_get_state(), false)) { err = xlnx_pcie_xvc_transact(1, 1, 0, NULL); } else if (path[i] == tap_state_transition(tap_get_state(), true)) { err = xlnx_pcie_xvc_transact(1, 0, 0, NULL); } else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.", tap_state_name(tap_get_state()), tap_state_name(path[i])); err = ERROR_JTAG_QUEUE_FAILED; } if (err != ERROR_OK) return err; tap_set_state(path[i]); } tap_set_end_state(tap_get_state()); return ERROR_OK; } static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd) { enum scan_type type = jtag_scan_type(cmd->cmd.scan); tap_state_t saved_end_state = cmd->cmd.scan->end_state; bool ir_scan = cmd->cmd.scan->ir_scan; uint32_t tdi, tms, tdo; uint8_t *buf, *rd_ptr; int err, scan_size; size_t write; size_t left; scan_size = jtag_build_buffer(cmd->cmd.scan, &buf); rd_ptr = buf; LOG_DEBUG("%s scan type %d %d bits; starts in %s end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", type, scan_size, tap_state_name(tap_get_state()), tap_state_name(cmd->cmd.scan->end_state)); /* If we're in TAP_DR_SHIFT state but need to do a IR_SCAN or * vice-versa, do a statemove to corresponding other state, then restore * end state */ if (ir_scan && tap_get_state() != TAP_IRSHIFT) { tap_set_end_state(TAP_IRSHIFT); err = xlnx_pcie_xvc_execute_statemove(0); if (err != ERROR_OK) goto out_err; tap_set_end_state(saved_end_state); } else if (!ir_scan && (tap_get_state() != TAP_DRSHIFT)) { tap_set_end_state(TAP_DRSHIFT); err = xlnx_pcie_xvc_execute_statemove(0); if (err != ERROR_OK) goto out_err; tap_set_end_state(saved_end_state); } left = scan_size; while (left) { write = MIN(XLNX_XVC_MAX_BITS, left); /* the last TMS should be a 1, to leave the state */ tms = left <= XLNX_XVC_MAX_BITS ? BIT(write - 1) : 0; tdi = (type != SCAN_IN) ? buf_get_u32(rd_ptr, 0, write) : 0; err = xlnx_pcie_xvc_transact(write, tms, tdi, type != SCAN_OUT ? &tdo : NULL); if (err != ERROR_OK) goto out_err; left -= write; if (type != SCAN_OUT) buf_set_u32(rd_ptr, 0, write, tdo); rd_ptr += sizeof(uint32_t); }; err = jtag_read_buffer(buf, cmd->cmd.scan); free(buf); if (tap_get_state() != tap_get_end_state()) err = xlnx_pcie_xvc_execute_statemove(1); return err; out_err: free(buf); return err; } static void xlnx_pcie_xvc_execute_reset(struct jtag_command *cmd) { LOG_DEBUG("reset trst: %i srst: %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); } static void xlnx_pcie_xvc_execute_sleep(struct jtag_command *cmd) { LOG_DEBUG("sleep %" PRIu32 "", cmd->cmd.sleep->us); usleep(cmd->cmd.sleep->us); } static int xlnx_pcie_xvc_execute_tms(struct jtag_command *cmd) { const size_t num_bits = cmd->cmd.tms->num_bits; const uint8_t *bits = cmd->cmd.tms->bits; size_t left, write; uint32_t tms; int err; LOG_DEBUG("execute tms %zu", num_bits); left = num_bits; while (left) { write = MIN(XLNX_XVC_MAX_BITS, left); tms = buf_get_u32(bits, 0, write); err = xlnx_pcie_xvc_transact(write, tms, 0, NULL); if (err != ERROR_OK) return err; left -= write; bits += 4; }; return ERROR_OK; } static int xlnx_pcie_xvc_execute_command(struct jtag_command *cmd) { LOG_DEBUG("%s: cmd->type: %u", __func__, cmd->type); switch (cmd->type) { case JTAG_STABLECLOCKS: return xlnx_pcie_xvc_execute_stableclocks(cmd); case JTAG_RUNTEST: return xlnx_pcie_xvc_execute_runtest(cmd); case JTAG_TLR_RESET: tap_set_end_state(cmd->cmd.statemove->end_state); return xlnx_pcie_xvc_execute_statemove(0); case JTAG_PATHMOVE: return xlnx_pcie_xvc_execute_pathmove(cmd); case JTAG_SCAN: return xlnx_pcie_xvc_execute_scan(cmd); case JTAG_RESET: xlnx_pcie_xvc_execute_reset(cmd); break; case JTAG_SLEEP: xlnx_pcie_xvc_execute_sleep(cmd); break; case JTAG_TMS: return xlnx_pcie_xvc_execute_tms(cmd); default: LOG_ERROR("BUG: Unknown JTAG command type encountered."); return ERROR_JTAG_QUEUE_FAILED; } return ERROR_OK; } static int xlnx_pcie_xvc_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; int ret; while (cmd) { ret = xlnx_pcie_xvc_execute_command(cmd); if (ret != ERROR_OK) return ret; cmd = cmd->next; } return ERROR_OK; } static int xlnx_pcie_xvc_init(void) { char filename[PATH_MAX]; uint32_t cap, vh; int err; snprintf(filename, PATH_MAX, "/sys/bus/pci/devices/%s/config", xlnx_pcie_xvc->device); xlnx_pcie_xvc->fd = open(filename, O_RDWR | O_SYNC); if (xlnx_pcie_xvc->fd < 0) { LOG_ERROR("Failed to open device: %s", filename); return ERROR_JTAG_INIT_FAILED; } LOG_INFO("Scanning PCIe device %s's for Xilinx XVC/PCIe ...", xlnx_pcie_xvc->device); /* Parse the PCIe extended capability list and try to find * vendor specific header */ xlnx_pcie_xvc->offset = PCIE_EXT_CAP_LST; while (xlnx_pcie_xvc->offset <= PCI_CFG_SPACE_EXP_SIZE - sizeof(cap) && xlnx_pcie_xvc->offset >= PCIE_EXT_CAP_LST) { err = xlnx_pcie_xvc_read_reg(XLNX_XVC_EXT_CAP, &cap); if (err != ERROR_OK) return err; LOG_DEBUG("Checking capability at 0x%x; id=0x%04" PRIx32 " version=0x%" PRIx32 " next=0x%" PRIx32, xlnx_pcie_xvc->offset, PCI_EXT_CAP_ID(cap), PCI_EXT_CAP_VER(cap), PCI_EXT_CAP_NEXT(cap)); if (PCI_EXT_CAP_ID(cap) == PCI_EXT_CAP_ID_VNDR) { err = xlnx_pcie_xvc_read_reg(XLNX_XVC_VSEC_HDR, &vh); if (err != ERROR_OK) return err; LOG_DEBUG("Checking possible match at 0x%x; id: 0x%" PRIx32 "; rev: 0x%" PRIx32 "; length: 0x%" PRIx32, xlnx_pcie_xvc->offset, PCI_VNDR_HEADER_ID(vh), PCI_VNDR_HEADER_REV(vh), PCI_VNDR_HEADER_LEN(vh)); if ((PCI_VNDR_HEADER_ID(vh) == XLNX_XVC_VSEC_ID) && (PCI_VNDR_HEADER_LEN(vh) == XLNX_XVC_CAP_SIZE)) break; } xlnx_pcie_xvc->offset = PCI_EXT_CAP_NEXT(cap); } if ((xlnx_pcie_xvc->offset > PCI_CFG_SPACE_EXP_SIZE - XLNX_XVC_CAP_SIZE) || xlnx_pcie_xvc->offset < PCIE_EXT_CAP_LST) { close(xlnx_pcie_xvc->fd); return ERROR_JTAG_INIT_FAILED; } LOG_INFO("Found Xilinx XVC/PCIe capability at offset: 0x%x", xlnx_pcie_xvc->offset); return ERROR_OK; } static int xlnx_pcie_xvc_quit(void) { int err; err = close(xlnx_pcie_xvc->fd); if (err) return err; return ERROR_OK; } COMMAND_HANDLER(xlnx_pcie_xvc_handle_config_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; /* we can't really free this in a safe manner, so at least * limit the memory we're leaking by freeing the old one first * before allocating a new one ... */ free(xlnx_pcie_xvc->device); xlnx_pcie_xvc->device = strdup(CMD_ARGV[0]); return ERROR_OK; } static const struct command_registration xlnx_pcie_xvc_subcommand_handlers[] = { { .name = "config", .handler = xlnx_pcie_xvc_handle_config_command, .mode = COMMAND_CONFIG, .help = "Configure XVC/PCIe JTAG adapter", .usage = "device", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration xlnx_pcie_xvc_command_handlers[] = { { .name = "xlnx_pcie_xvc", .mode = COMMAND_ANY, .help = "perform xlnx_pcie_xvc management", .chain = xlnx_pcie_xvc_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static struct jtag_interface xlnx_pcie_xvc_jtag_ops = { .execute_queue = &xlnx_pcie_xvc_execute_queue, }; static int xlnx_pcie_xvc_swd_sequence(const uint8_t *seq, size_t length) { size_t left, write; uint32_t send; int err; left = length; while (left) { write = MIN(XLNX_XVC_MAX_BITS, left); send = buf_get_u32(seq, 0, write); err = xlnx_pcie_xvc_transact(write, send, 0, NULL); if (err != ERROR_OK) return err; left -= write; seq += sizeof(uint32_t); }; return ERROR_OK; } static int xlnx_pcie_xvc_swd_switch_seq(enum swd_special_seq seq) { switch (seq) { case LINE_RESET: LOG_DEBUG("SWD line reset"); return xlnx_pcie_xvc_swd_sequence(swd_seq_line_reset, swd_seq_line_reset_len); case JTAG_TO_SWD: LOG_DEBUG("JTAG-to-SWD"); return xlnx_pcie_xvc_swd_sequence(swd_seq_jtag_to_swd, swd_seq_jtag_to_swd_len); case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); return xlnx_pcie_xvc_swd_sequence(swd_seq_swd_to_jtag, swd_seq_swd_to_jtag_len); default: LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; } return ERROR_OK; } static int queued_retval; static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk); static void swd_clear_sticky_errors(void) { xlnx_pcie_xvc_swd_write_reg(swd_cmd(false, false, DP_ABORT), STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); } static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { uint32_t res, ack, rpar; int err; assert(cmd & SWD_CMD_RNW); cmd |= SWD_CMD_START | SWD_CMD_PARK; /* cmd + ack */ err = xlnx_pcie_xvc_transact(12, cmd, 0, &res); if (err != ERROR_OK) goto err_out; ack = MASK_ACK(res); /* read data */ err = xlnx_pcie_xvc_transact(32, 0, 0, &res); if (err != ERROR_OK) goto err_out; /* parity + trn */ err = xlnx_pcie_xvc_transact(2, 0, 0, &rpar); if (err != ERROR_OK) goto err_out; LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", cmd & SWD_CMD_APNDP ? "AP" : "DP", cmd & SWD_CMD_RNW ? "read" : "write", (cmd & SWD_CMD_A32) >> 1, res); switch (ack) { case SWD_ACK_OK: if (MASK_PAR(rpar) != parity_u32(res)) { LOG_DEBUG_IO("Wrong parity detected"); queued_retval = ERROR_FAIL; return; } if (value) *value = res; if (cmd & SWD_CMD_APNDP) err = xlnx_pcie_xvc_transact(ap_delay_clk, 0, 0, NULL); queued_retval = err; return; case SWD_ACK_WAIT: LOG_DEBUG_IO("SWD_ACK_WAIT"); swd_clear_sticky_errors(); return; case SWD_ACK_FAULT: LOG_DEBUG_IO("SWD_ACK_FAULT"); queued_retval = ack; return; default: LOG_DEBUG_IO("No valid acknowledge: ack=%02"PRIx32, ack); queued_retval = ack; return; } err_out: queued_retval = err; } static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { uint32_t res, ack; int err; assert(!(cmd & SWD_CMD_RNW)); cmd |= SWD_CMD_START | SWD_CMD_PARK; /* cmd + trn + ack */ err = xlnx_pcie_xvc_transact(13, cmd, 0, &res); if (err != ERROR_OK) goto err_out; ack = MASK_ACK(res); /* write data */ err = xlnx_pcie_xvc_transact(32, value, 0, NULL); if (err != ERROR_OK) goto err_out; /* parity + trn */ err = xlnx_pcie_xvc_transact(2, parity_u32(value), 0, NULL); if (err != ERROR_OK) goto err_out; LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", cmd & SWD_CMD_APNDP ? "AP" : "DP", cmd & SWD_CMD_RNW ? "read" : "write", (cmd & SWD_CMD_A32) >> 1, value); switch (ack) { case SWD_ACK_OK: if (cmd & SWD_CMD_APNDP) err = xlnx_pcie_xvc_transact(ap_delay_clk, 0, 0, NULL); queued_retval = err; return; case SWD_ACK_WAIT: LOG_DEBUG_IO("SWD_ACK_WAIT"); swd_clear_sticky_errors(); return; case SWD_ACK_FAULT: LOG_DEBUG_IO("SWD_ACK_FAULT"); queued_retval = ack; return; default: LOG_DEBUG_IO("No valid acknowledge: ack=%02"PRIx32, ack); queued_retval = ack; return; } err_out: queued_retval = err; } static int xlnx_pcie_xvc_swd_run_queue(void) { int err; /* we want at least 8 idle cycles between each transaction */ err = xlnx_pcie_xvc_transact(8, 0, 0, NULL); if (err != ERROR_OK) return err; err = queued_retval; queued_retval = ERROR_OK; LOG_DEBUG("SWD queue return value: %02x", err); return err; } static int xlnx_pcie_xvc_swd_init(void) { return ERROR_OK; } static const struct swd_driver xlnx_pcie_xvc_swd_ops = { .init = xlnx_pcie_xvc_swd_init, .switch_seq = xlnx_pcie_xvc_swd_switch_seq, .read_reg = xlnx_pcie_xvc_swd_read_reg, .write_reg = xlnx_pcie_xvc_swd_write_reg, .run = xlnx_pcie_xvc_swd_run_queue, }; static const char * const xlnx_pcie_xvc_transports[] = { "jtag", "swd", NULL }; struct adapter_driver xlnx_pcie_xvc_adapter_driver = { .name = "xlnx_pcie_xvc", .transports = xlnx_pcie_xvc_transports, .commands = xlnx_pcie_xvc_command_handlers, .init = &xlnx_pcie_xvc_init, .quit = &xlnx_pcie_xvc_quit, .jtag_ops = &xlnx_pcie_xvc_jtag_ops, .swd_ops = &xlnx_pcie_xvc_swd_ops, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/hla/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libocdhla.la %C%_libocdhla_la_SOURCES = \ %D%/hla_transport.c \ %D%/hla_interface.c \ %D%/hla_layout.c \ %D%/hla_transport.h \ %D%/hla_interface.h \ %D%/hla_layout.h ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/hla/hla_interface.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include <jtag/interface.h> #include <transport/transport.h> #include <helper/time_support.h> #include <jtag/hla/hla_layout.h> #include <jtag/hla/hla_transport.h> #include <jtag/hla/hla_interface.h> #include <target/target.h> static struct hl_interface_s hl_if = { .param = { .device_desc = NULL, .vid = { 0 }, .pid = { 0 }, .transport = HL_TRANSPORT_UNKNOWN, .connect_under_reset = false, .initial_interface_speed = -1, .use_stlink_tcp = false, .stlink_tcp_port = 7184, }, .layout = NULL, .handle = NULL, }; int hl_interface_open(enum hl_transports tr) { LOG_DEBUG("hl_interface_open"); enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) hl_if.param.connect_under_reset = true; else LOG_WARNING("\'srst_nogate\' reset_config option is required"); } /* set transport mode */ hl_if.param.transport = tr; int result = hl_if.layout->open(&hl_if); if (result != ERROR_OK) return result; return hl_interface_init_reset(); } int hl_interface_init_target(struct target *t) { int res; LOG_DEBUG("hl_interface_init_target"); /* this is the interface for the current target and we * can setup the private pointer in the tap structure * if the interface match the tap idcode */ res = hl_if.layout->api->idcode(hl_if.handle, &t->tap->idcode); if (res != ERROR_OK) return res; unsigned ii, limit = t->tap->expected_ids_cnt; int found = 0; for (ii = 0; ii < limit; ii++) { uint32_t expected = t->tap->expected_ids[ii]; /* treat "-expected-id 0" as a "don't-warn" wildcard */ if (!expected || !t->tap->idcode || (t->tap->idcode == expected)) { found = 1; break; } } if (found == 0) { LOG_WARNING("UNEXPECTED idcode: 0x%08" PRIx32, t->tap->idcode); for (ii = 0; ii < limit; ii++) LOG_ERROR("expected %u of %u: 0x%08" PRIx32, ii + 1, limit, t->tap->expected_ids[ii]); return ERROR_FAIL; } t->tap->priv = &hl_if; t->tap->hasidcode = 1; return ERROR_OK; } static int hl_interface_init(void) { LOG_DEBUG("hl_interface_init"); /* here we can initialize the layout */ return hl_layout_init(&hl_if); } static int hl_interface_quit(void) { LOG_DEBUG("hl_interface_quit"); if (hl_if.layout->api->close) hl_if.layout->api->close(hl_if.handle); jtag_command_queue_reset(); free((void *)hl_if.param.device_desc); return ERROR_OK; } static int hl_interface_reset(int req_trst, int req_srst) { return hl_if.layout->api->assert_srst(hl_if.handle, req_srst ? 0 : 1); } int hl_interface_init_reset(void) { /* in case the adapter has not already handled asserting srst * we will attempt it again */ if (hl_if.param.connect_under_reset) { adapter_assert_reset(); } else { adapter_deassert_reset(); } return ERROR_OK; } static int hl_interface_khz(int khz, int *jtag_speed) { if (!hl_if.layout->api->speed) return ERROR_OK; *jtag_speed = hl_if.layout->api->speed(hl_if.handle, khz, true); return ERROR_OK; } static int hl_interface_speed_div(int speed, int *khz) { *khz = speed; return ERROR_OK; } static int hl_interface_speed(int speed) { if (!hl_if.layout->api->speed) return ERROR_OK; if (!hl_if.handle) { /* pass speed as initial param as interface not open yet */ hl_if.param.initial_interface_speed = speed; return ERROR_OK; } hl_if.layout->api->speed(hl_if.handle, speed, false); return ERROR_OK; } int hl_interface_override_target(const char **targetname) { if (hl_if.layout->api->override_target) { if (hl_if.layout->api->override_target(*targetname)) { *targetname = "hla_target"; return ERROR_OK; } else return ERROR_FAIL; } return ERROR_FAIL; } static int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler) { if (hl_if.layout->api->config_trace) return hl_if.layout->api->config_trace(hl_if.handle, enabled, pin_protocol, port_size, trace_freq, traceclkin_freq, prescaler); else if (enabled) { LOG_ERROR("The selected interface does not support tracing"); return ERROR_FAIL; } return ERROR_OK; } static int hl_interface_poll_trace(uint8_t *buf, size_t *size) { if (hl_if.layout->api->poll_trace) return hl_if.layout->api->poll_trace(hl_if.handle, buf, size); return ERROR_FAIL; } COMMAND_HANDLER(hl_interface_handle_device_desc_command) { LOG_DEBUG("hl_interface_handle_device_desc_command"); if (CMD_ARGC == 1) { hl_if.param.device_desc = strdup(CMD_ARGV[0]); } else { LOG_ERROR("expected exactly one argument to hl_device_desc <description>"); } return ERROR_OK; } COMMAND_HANDLER(hl_interface_handle_layout_command) { LOG_DEBUG("hl_interface_handle_layout_command"); if (CMD_ARGC != 1) { LOG_ERROR("Need exactly one argument to stlink_layout"); return ERROR_COMMAND_SYNTAX_ERROR; } if (hl_if.layout) { LOG_ERROR("already specified hl_layout %s", hl_if.layout->name); return (strcmp(hl_if.layout->name, CMD_ARGV[0]) != 0) ? ERROR_FAIL : ERROR_OK; } for (const struct hl_layout *l = hl_layout_get_list(); l->name; l++) { if (strcmp(l->name, CMD_ARGV[0]) == 0) { hl_if.layout = l; return ERROR_OK; } } LOG_ERROR("No adapter layout '%s' found", CMD_ARGV[0]); return ERROR_FAIL; } COMMAND_HANDLER(hl_interface_handle_vid_pid_command) { if (CMD_ARGC > HLA_MAX_USB_IDS * 2) { LOG_WARNING("ignoring extra IDs in hla_vid_pid " "(maximum is %d pairs)", HLA_MAX_USB_IDS); CMD_ARGC = HLA_MAX_USB_IDS * 2; } if (CMD_ARGC < 2 || (CMD_ARGC & 1)) { LOG_WARNING("incomplete hla_vid_pid configuration directive"); return ERROR_COMMAND_SYNTAX_ERROR; } unsigned i; for (i = 0; i < CMD_ARGC; i += 2) { COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], hl_if.param.vid[i / 2]); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], hl_if.param.pid[i / 2]); } /* * Explicitly terminate, in case there are multiple instances of * hla_vid_pid. */ hl_if.param.vid[i / 2] = hl_if.param.pid[i / 2] = 0; return ERROR_OK; } COMMAND_HANDLER(hl_interface_handle_stlink_backend_command) { /* default values */ bool use_stlink_tcp = false; uint16_t stlink_tcp_port = 7184; if (CMD_ARGC == 0 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; else if (strcmp(CMD_ARGV[0], "usb") == 0) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; /* else use_stlink_tcp = false (already the case ) */ } else if (strcmp(CMD_ARGV[0], "tcp") == 0) { use_stlink_tcp = true; if (CMD_ARGC == 2) COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], stlink_tcp_port); } else return ERROR_COMMAND_SYNTAX_ERROR; hl_if.param.use_stlink_tcp = use_stlink_tcp; hl_if.param.stlink_tcp_port = stlink_tcp_port; return ERROR_OK; } COMMAND_HANDLER(interface_handle_hla_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; if (!hl_if.layout->api->custom_command) { LOG_ERROR("The selected adapter doesn't support custom commands"); return ERROR_FAIL; } hl_if.layout->api->custom_command(hl_if.handle, CMD_ARGV[0]); return ERROR_OK; } static const struct command_registration hl_interface_command_handlers[] = { { .name = "hla_device_desc", .handler = &hl_interface_handle_device_desc_command, .mode = COMMAND_CONFIG, .help = "set the device description of the adapter", .usage = "description_string", }, { .name = "hla_layout", .handler = &hl_interface_handle_layout_command, .mode = COMMAND_CONFIG, .help = "set the layout of the adapter", .usage = "layout_name", }, { .name = "hla_vid_pid", .handler = &hl_interface_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "the vendor and product ID of the adapter", .usage = "(vid pid)*", }, { .name = "hla_stlink_backend", .handler = &hl_interface_handle_stlink_backend_command, .mode = COMMAND_CONFIG, .help = "select which ST-Link backend to use", .usage = "usb | tcp [port]", }, { .name = "hla_command", .handler = &interface_handle_hla_command, .mode = COMMAND_EXEC, .help = "execute a custom adapter-specific command", .usage = "<command>", }, COMMAND_REGISTRATION_DONE }; struct adapter_driver hl_adapter_driver = { .name = "hla", .transports = hl_transports, .commands = hl_interface_command_handlers, .init = hl_interface_init, .quit = hl_interface_quit, .reset = hl_interface_reset, .speed = &hl_interface_speed, .khz = &hl_interface_khz, .speed_div = &hl_interface_speed_div, .config_trace = &hl_interface_config_trace, .poll_trace = &hl_interface_poll_trace, /* no ops for HLA, targets hla_target and stm8 intercept them all */ }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/hla/hla_interface.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_JTAG_HLA_HLA_INTERFACE_H #define OPENOCD_JTAG_HLA_HLA_INTERFACE_H /** */ struct target; /** */ enum e_hl_transports; /** */ extern const char *hl_transports[]; #define HLA_MAX_USB_IDS 16 struct hl_interface_param_s { /** */ const char *device_desc; /** List of recognised VIDs */ uint16_t vid[HLA_MAX_USB_IDS + 1]; /** List of recognised PIDs */ uint16_t pid[HLA_MAX_USB_IDS + 1]; /** */ enum hl_transports transport; /** */ bool connect_under_reset; /** Initial interface clock clock speed */ int initial_interface_speed; /** */ bool use_stlink_tcp; /** */ uint16_t stlink_tcp_port; }; struct hl_interface_s { /** */ struct hl_interface_param_s param; /** */ const struct hl_layout *layout; /** */ void *handle; }; /** */ int hl_interface_open(enum hl_transports tr); /** */ int hl_interface_init_target(struct target *t); int hl_interface_init_reset(void); int hl_interface_override_target(const char **targetname); #endif /* OPENOCD_JTAG_HLA_HLA_INTERFACE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/hla/hla_layout.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include <jtag/interface.h> #include <transport/transport.h> #include <helper/time_support.h> #include <jtag/hla/hla_layout.h> #include <jtag/hla/hla_transport.h> #include <jtag/hla/hla_interface.h> static int hl_layout_open(struct hl_interface_s *adapter) { int res; LOG_DEBUG("hl_layout_open"); adapter->handle = NULL; res = adapter->layout->api->open(&adapter->param, &adapter->handle); if (res != ERROR_OK) { LOG_DEBUG("failed"); return res; } return ERROR_OK; } static int hl_layout_close(struct hl_interface_s *adapter) { return ERROR_OK; } static const struct hl_layout hl_layouts[] = { #if BUILD_HLADAPTER_STLINK { .name = "stlink", .open = hl_layout_open, .close = hl_layout_close, .api = &stlink_usb_layout_api, }, #endif #if BUILD_HLADAPTER_ICDI { .name = "ti-icdi", .open = hl_layout_open, .close = hl_layout_close, .api = &icdi_usb_layout_api, }, #endif #if BUILD_HLADAPTER_NULINK { .name = "nulink", .open = hl_layout_open, .close = hl_layout_close, .api = &nulink_usb_layout_api, }, #endif {.name = NULL, /* END OF TABLE */ }, }; /** */ const struct hl_layout *hl_layout_get_list(void) { return hl_layouts; } int hl_layout_init(struct hl_interface_s *adapter) { LOG_DEBUG("hl_layout_init"); if (!adapter->layout) { LOG_ERROR("no layout specified"); return ERROR_FAIL; } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/hla/hla_layout.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_JTAG_HLA_HLA_LAYOUT_H #define OPENOCD_JTAG_HLA_HLA_LAYOUT_H #include <target/armv7m_trace.h> #include <target/arm_tpiu_swo.h> /** */ struct hl_interface_s; struct hl_interface_param_s; /** */ extern struct hl_layout_api_s stlink_usb_layout_api; extern struct hl_layout_api_s icdi_usb_layout_api; extern struct hl_layout_api_s nulink_usb_layout_api; /** */ struct hl_layout_api_s { /** */ int (*open)(struct hl_interface_param_s *param, void **handle); /** */ int (*close)(void *handle); /** */ int (*reset)(void *handle); /** */ int (*assert_srst)(void *handle, int srst); /** */ int (*run)(void *handle); /** */ int (*halt)(void *handle); /** */ int (*step)(void *handle); /** */ int (*read_regs)(void *handle); /** * Read one register from the target * * @param handle A pointer to the device-specific handle * @param regsel Register selection index compatible with all the * values allowed by armv7m DCRSR.REGSEL * @param val A pointer to retrieve the register value * @returns ERROR_OK on success, or an error code on failure. */ int (*read_reg)(void *handle, unsigned int regsel, uint32_t *val); /** * Write one register to the target * @param handle A pointer to the device-specific handle * @param regsel Register selection index compatible with all the * values allowed by armv7m DCRSR.REGSEL * @param val The value to be written in the register * @returns ERROR_OK on success, or an error code on failure. */ int (*write_reg)(void *handle, unsigned int regsel, uint32_t val); /** */ int (*read_mem)(void *handle, uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer); /** */ int (*write_mem)(void *handle, uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer); /** */ int (*write_debug_reg)(void *handle, uint32_t addr, uint32_t val); /** * Read the idcode of the target connected to the adapter * * If the adapter doesn't support idcode retrieval, this callback should * store 0 to indicate a wildcard match. * * @param handle A pointer to the device-specific handle * @param idcode Storage for the detected idcode * @returns ERROR_OK on success, or an error code on failure. */ int (*idcode)(void *handle, uint32_t *idcode); /** */ int (*override_target)(const char *targetname); /** */ int (*custom_command)(void *handle, const char *command); /** */ int (*speed)(void *handle, int khz, bool query); /** * Configure trace parameters for the adapter * * @param handle A handle to adapter * @param enabled Whether to enable trace * @param pin_protocol Configured pin protocol * @param port_size Trace port width for sync mode * @param trace_freq A pointer to the configured trace * frequency; if it points to 0, the adapter driver must write * its maximum supported rate there * @returns ERROR_OK on success, an error code on failure. */ int (*config_trace)(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler); /** * Poll for new trace data * * @param handle A handle to adapter * @param buf A pointer to buffer to store received data * @param size A pointer to buffer size; must be filled with * the actual amount of bytes written * * @returns ERROR_OK on success, an error code on failure. */ int (*poll_trace)(void *handle, uint8_t *buf, size_t *size); /** */ enum target_state (*state)(void *fd); }; /** */ struct hl_layout { /** */ char *name; /** */ int (*open)(struct hl_interface_s *adapter); /** */ int (*close)(struct hl_interface_s *adapter); /** */ struct hl_layout_api_s *api; }; /** */ const struct hl_layout *hl_layout_get_list(void); /** */ int hl_layout_init(struct hl_interface_s *adapter); #endif /* OPENOCD_JTAG_HLA_HLA_LAYOUT_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/hla/hla_transport.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include <jtag/interface.h> #include <jtag/tcl.h> #include <transport/transport.h> #include <helper/time_support.h> #include <target/target.h> #include <jtag/hla/hla_transport.h> #include <jtag/hla/hla_interface.h> COMMAND_HANDLER(hl_transport_jtag_command) { LOG_DEBUG("hl_transport_jtag_command"); return ERROR_OK; } COMMAND_HANDLER(hl_transport_reset_command) { return hl_interface_init_reset(); } static const struct command_registration hl_swd_transport_subcommand_handlers[] = { { .name = "newdap", .mode = COMMAND_CONFIG, .handler = handle_jtag_newtap, .help = "declare a new SWD DAP", .usage = "basename dap_type ['-irlen' count] " "['-enable'|'-disable'] " "['-expected_id' number] " "['-ignore-version'] " "['-ignore-bypass'] " "['-ircapture' number] " "['-mask' number]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration hl_swd_transport_command_handlers[] = { { .name = "swd", .mode = COMMAND_ANY, .help = "SWD command group", .usage = "", .chain = hl_swd_transport_subcommand_handlers, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration hl_transport_jtag_subcommand_handlers[] = { { .name = "newtap", .mode = COMMAND_CONFIG, .handler = handle_jtag_newtap, .help = "Create a new TAP instance named basename.tap_type, " "and appends it to the scan chain.", .usage = "basename tap_type '-irlen' count " "['-enable'|'-disable'] " "['-expected_id' number] " "['-ignore-version'] " "['-ignore-bypass'] " "['-ircapture' number] " "['-mask' number]", }, { .name = "init", .mode = COMMAND_ANY, .handler = hl_transport_jtag_command, .usage = "" }, { .name = "arp_init", .mode = COMMAND_ANY, .handler = hl_transport_jtag_command, .usage = "" }, { .name = "arp_init-reset", .mode = COMMAND_ANY, .handler = hl_transport_reset_command, .usage = "" }, { .name = "tapisenabled", .mode = COMMAND_EXEC, .handler = handle_jtag_tap_enabler, .help = "Returns a Tcl boolean (0/1) indicating whether " "the TAP is enabled (1) or not (0).", .usage = "tap_name", }, { .name = "tapenable", .mode = COMMAND_EXEC, .handler = handle_jtag_tap_enabler, .help = "Try to enable the specified TAP using the " "'tap-enable' TAP event.", .usage = "tap_name", }, { .name = "tapdisable", .mode = COMMAND_EXEC, .handler = hl_transport_jtag_command, .usage = "", }, { .name = "configure", .mode = COMMAND_EXEC, .handler = hl_transport_jtag_command, .usage = "", }, { .name = "cget", .mode = COMMAND_EXEC, .jim_handler = jim_jtag_configure, }, { .name = "names", .mode = COMMAND_ANY, .handler = hl_transport_jtag_command, .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration hl_jtag_transport_command_handlers[] = { { .name = "jtag", .mode = COMMAND_ANY, .help = "perform jtag tap actions", .usage = "", .chain = hl_transport_jtag_subcommand_handlers, }, { .name = "jtag_ntrst_delay", .mode = COMMAND_ANY, .handler = hl_transport_jtag_command, .usage = "", }, COMMAND_REGISTRATION_DONE }; static int hl_transport_init(struct command_context *cmd_ctx) { LOG_DEBUG("hl_transport_init"); struct target *t = get_current_target(cmd_ctx); struct transport *transport; enum hl_transports tr; if (!t) { LOG_ERROR("no current target"); return ERROR_FAIL; } transport = get_current_transport(); if (!transport) { LOG_ERROR("no transport selected"); return ERROR_FAIL; } LOG_DEBUG("current transport %s", transport->name); /* get selected transport as enum */ tr = HL_TRANSPORT_UNKNOWN; if (strcmp(transport->name, "hla_swd") == 0) tr = HL_TRANSPORT_SWD; else if (strcmp(transport->name, "hla_jtag") == 0) tr = HL_TRANSPORT_JTAG; int retval = hl_interface_open(tr); if (retval != ERROR_OK) return retval; return hl_interface_init_target(t); } static int hl_jtag_transport_select(struct command_context *cmd_ctx) { LOG_DEBUG("hl_jtag_transport_select"); /* NOTE: interface init must already have been done. * That works with only C code ... no Tcl glue required. */ return register_commands(cmd_ctx, NULL, hl_jtag_transport_command_handlers); } static int hl_swd_transport_select(struct command_context *cmd_ctx) { LOG_DEBUG("hl_swd_transport_select"); return register_commands(cmd_ctx, NULL, hl_swd_transport_command_handlers); } static struct transport hl_swd_transport = { .name = "hla_swd", .select = hl_swd_transport_select, .init = hl_transport_init, .override_target = hl_interface_override_target, }; static struct transport hl_jtag_transport = { .name = "hla_jtag", .select = hl_jtag_transport_select, .init = hl_transport_init, .override_target = hl_interface_override_target, }; const char *hl_transports[] = { "hla_swd", "hla_jtag", NULL }; static void hl_constructor(void) __attribute__ ((constructor)); static void hl_constructor(void) { transport_register(&hl_swd_transport); transport_register(&hl_jtag_transport); } bool transport_is_hla(void) { struct transport *t; t = get_current_transport(); return t == &hl_swd_transport || t == &hl_jtag_transport; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/hla/hla_transport.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_JTAG_HLA_HLA_TRANSPORT_H #define OPENOCD_JTAG_HLA_HLA_TRANSPORT_H enum hl_transports { HL_TRANSPORT_UNKNOWN = 0, HL_TRANSPORT_SWD, HL_TRANSPORT_JTAG, }; #endif /* OPENOCD_JTAG_HLA_HLA_TRANSPORT_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/interface.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag.h" #include "interface.h" /** * @see tap_set_state() and tap_get_state() accessors. * Actual name is not important since accessors hide it. */ static tap_state_t state_follower = TAP_RESET; void tap_set_state_impl(tap_state_t new_state) { /* this is the state we think the TAPs are in now, was cur_state */ state_follower = new_state; } tap_state_t tap_get_state(void) { return state_follower; } /** * @see tap_set_end_state() and tap_get_end_state() accessors. * Actual name is not important because accessors hide it. */ static tap_state_t end_state_follower = TAP_RESET; void tap_set_end_state(tap_state_t new_end_state) { /* this is the state we think the TAPs will be in at completion of the * current TAP operation, was end_state */ end_state_follower = new_end_state; } tap_state_t tap_get_end_state(void) { return end_state_follower; } int tap_move_ndx(tap_state_t astate) { /* given a stable state, return the index into the tms_seqs[] * array within tap_get_tms_path() */ int ndx; switch (astate) { case TAP_RESET: ndx = 0; break; case TAP_IDLE: ndx = 1; break; case TAP_DRSHIFT: ndx = 2; break; case TAP_DRPAUSE: ndx = 3; break; case TAP_IRSHIFT: ndx = 4; break; case TAP_IRPAUSE: ndx = 5; break; default: LOG_ERROR("FATAL: unstable state \"%s\" in tap_move_ndx()", tap_state_name(astate)); exit(1); } return ndx; } /* tap_move[i][j]: tap movement command to go from state i to state j * encodings of i and j are what tap_move_ndx() reports. * * DRSHIFT->DRSHIFT and IRSHIFT->IRSHIFT have to be caught in interface specific code */ struct tms_sequences { uint8_t bits; uint8_t bit_count; }; /* * These macros allow us to specify TMS state transitions by bits rather than hex bytes. * Read the bits from LSBit first to MSBit last (right-to-left). */ #define HEX__(n) 0x##n##LU #define B8__(x) \ ((((x) & 0x0000000FLU) ? (1 << 0) : 0) \ +(((x) & 0x000000F0LU) ? (1 << 1) : 0) \ +(((x) & 0x00000F00LU) ? (1 << 2) : 0) \ +(((x) & 0x0000F000LU) ? (1 << 3) : 0) \ +(((x) & 0x000F0000LU) ? (1 << 4) : 0) \ +(((x) & 0x00F00000LU) ? (1 << 5) : 0) \ +(((x) & 0x0F000000LU) ? (1 << 6) : 0) \ +(((x) & 0xF0000000LU) ? (1 << 7) : 0)) #define B8(bits, count) {((uint8_t)B8__(HEX__(bits))), (count)} static const struct tms_sequences old_tms_seqs[6][6] = { /* [from_state_ndx][to_state_ndx] */ /* value clocked to TMS to move from one of six stable states to another. * N.B. OOCD clocks TMS from LSB first, so read these right-to-left. * N.B. Reset only needs to be 0b11111, but in JLink an even byte of 1's is more stable. * These extra ones cause no TAP state problem, because we go into reset and stay in reset. */ /* to state: */ /* RESET IDLE DRSHIFT DRPAUSE IRSHIFT IRPAUSE */ /* from state: */ {B8(1111111, 7), B8(0000000, 7), B8(0010111, 7), B8(0001010, 7), B8(0011011, 7), B8(0010110, 7)},/* RESET */ {B8(1111111, 7), B8(0000000, 7), B8(0100101, 7), B8(0000101, 7), B8(0101011, 7), B8(0001011, 7)},/* IDLE */ {B8(1111111, 7), B8(0110001, 7), B8(0000000, 7), B8(0000001, 7), B8(0001111, 7), B8(0101111, 7)},/* DRSHIFT */ {B8(1111111, 7), B8(0110000, 7), B8(0100000, 7), B8(0010111, 7), B8(0011110, 7), B8(0101111, 7)},/* DRPAUSE */ {B8(1111111, 7), B8(0110001, 7), B8(0000111, 7), B8(0010111, 7), B8(0000000, 7), B8(0000001, 7)},/* IRSHIFT */ {B8(1111111, 7), B8(0110000, 7), B8(0011100, 7), B8(0010111, 7), B8(0011110, 7), B8(0101111, 7)},/* IRPAUSE */ }; static const struct tms_sequences short_tms_seqs[6][6] = { /* [from_state_ndx][to_state_ndx] */ /* this is the table submitted by Jeff Williams on 3/30/2009 with this comment: OK, I added Peter's version of the state table, and it works OK for me on MC1322x. I've recreated the jlink portion of patch with this new state table. His changes to my state table are pretty minor in terms of total transitions, but Peter feels that his version fixes some long-standing problems. Jeff I added the bit count into the table, reduced RESET column to 7 bits from 8. Dick state specific comments: ------------------------ *->RESET tried the 5 bit reset and it gave me problems, 7 bits seems to work better on ARM9 with ft2232 driver. (Dick) RESET->DRSHIFT add 1 extra clock cycles in the RESET state before advancing. needed on ARM9 with ft2232 driver. (Dick) (For a total of *THREE* extra clocks in RESET; NOP.) RESET->IRSHIFT add 1 extra clock cycles in the RESET state before advancing. needed on ARM9 with ft2232 driver. (Dick) (For a total of *TWO* extra clocks in RESET; NOP.) RESET->* always adds one or more clocks in the target state, which should be NOPS; except shift states which (as noted above) add those clocks in RESET. The X-to-X transitions always add clocks; from *SHIFT, they go via IDLE and thus *DO HAVE SIDE EFFECTS* (capture and update). */ /* to state: */ /* RESET IDLE DRSHIFT DRPAUSE IRSHIFT IRPAUSE */ /* from state: */ {B8(1111111, 7), B8(0000000, 7), B8(0010111, 7), B8(0001010, 7), B8(0011011, 7), B8(0010110, 7)}, /* RESET */ {B8(1111111, 7), B8(0000000, 7), B8(001, 3), B8(0101, 4), B8(0011, 4), B8(01011, 5)}, /* IDLE */ {B8(1111111, 7), B8(011, 3), B8(00111, 5), B8(01, 2), B8(001111, 6), B8(0101111, 7)}, /* DRSHIFT */ {B8(1111111, 7), B8(011, 3), B8(01, 2), B8(0, 1), B8(001111, 6), B8(0101111, 7)}, /* DRPAUSE */ {B8(1111111, 7), B8(011, 3), B8(00111, 5), B8(010111, 6), B8(001111, 6), B8(01, 2)}, /* IRSHIFT */ {B8(1111111, 7), B8(011, 3), B8(00111, 5), B8(010111, 6), B8(01, 2), B8(0, 1)} /* IRPAUSE */ }; typedef const struct tms_sequences tms_table[6][6]; static tms_table *tms_seqs = &short_tms_seqs; int tap_get_tms_path(tap_state_t from, tap_state_t to) { return (*tms_seqs)[tap_move_ndx(from)][tap_move_ndx(to)].bits; } int tap_get_tms_path_len(tap_state_t from, tap_state_t to) { return (*tms_seqs)[tap_move_ndx(from)][tap_move_ndx(to)].bit_count; } bool tap_is_state_stable(tap_state_t astate) { bool is_stable; /* A switch () is used because it is symbol dependent * (not value dependent like an array), and can also check bounds. */ switch (astate) { case TAP_RESET: case TAP_IDLE: case TAP_DRSHIFT: case TAP_DRPAUSE: case TAP_IRSHIFT: case TAP_IRPAUSE: is_stable = true; break; default: is_stable = false; } return is_stable; } tap_state_t tap_state_transition(tap_state_t cur_state, bool tms) { tap_state_t new_state; /* A switch is used because it is symbol dependent and not value dependent * like an array. Also it can check for out of range conditions. */ if (tms) { switch (cur_state) { case TAP_RESET: new_state = cur_state; break; case TAP_IDLE: case TAP_DRUPDATE: case TAP_IRUPDATE: new_state = TAP_DRSELECT; break; case TAP_DRSELECT: new_state = TAP_IRSELECT; break; case TAP_DRCAPTURE: case TAP_DRSHIFT: new_state = TAP_DREXIT1; break; case TAP_DREXIT1: case TAP_DREXIT2: new_state = TAP_DRUPDATE; break; case TAP_DRPAUSE: new_state = TAP_DREXIT2; break; case TAP_IRSELECT: new_state = TAP_RESET; break; case TAP_IRCAPTURE: case TAP_IRSHIFT: new_state = TAP_IREXIT1; break; case TAP_IREXIT1: case TAP_IREXIT2: new_state = TAP_IRUPDATE; break; case TAP_IRPAUSE: new_state = TAP_IREXIT2; break; default: LOG_ERROR("fatal: invalid argument cur_state=%d", cur_state); exit(1); break; } } else { switch (cur_state) { case TAP_RESET: case TAP_IDLE: case TAP_DRUPDATE: case TAP_IRUPDATE: new_state = TAP_IDLE; break; case TAP_DRSELECT: new_state = TAP_DRCAPTURE; break; case TAP_DRCAPTURE: case TAP_DRSHIFT: case TAP_DREXIT2: new_state = TAP_DRSHIFT; break; case TAP_DREXIT1: case TAP_DRPAUSE: new_state = TAP_DRPAUSE; break; case TAP_IRSELECT: new_state = TAP_IRCAPTURE; break; case TAP_IRCAPTURE: case TAP_IRSHIFT: case TAP_IREXIT2: new_state = TAP_IRSHIFT; break; case TAP_IREXIT1: case TAP_IRPAUSE: new_state = TAP_IRPAUSE; break; default: LOG_ERROR("fatal: invalid argument cur_state=%d", cur_state); exit(1); break; } } return new_state; } /* NOTE: do not change these state names. They're documented, * and we rely on them to match SVF input (except for "RUN/IDLE"). */ static const struct name_mapping { enum tap_state symbol; const char *name; } tap_name_mapping[] = { { TAP_RESET, "RESET", }, { TAP_IDLE, "RUN/IDLE", }, { TAP_DRSELECT, "DRSELECT", }, { TAP_DRCAPTURE, "DRCAPTURE", }, { TAP_DRSHIFT, "DRSHIFT", }, { TAP_DREXIT1, "DREXIT1", }, { TAP_DRPAUSE, "DRPAUSE", }, { TAP_DREXIT2, "DREXIT2", }, { TAP_DRUPDATE, "DRUPDATE", }, { TAP_IRSELECT, "IRSELECT", }, { TAP_IRCAPTURE, "IRCAPTURE", }, { TAP_IRSHIFT, "IRSHIFT", }, { TAP_IREXIT1, "IREXIT1", }, { TAP_IRPAUSE, "IRPAUSE", }, { TAP_IREXIT2, "IREXIT2", }, { TAP_IRUPDATE, "IRUPDATE", }, /* only for input: accept standard SVF name */ { TAP_IDLE, "IDLE", }, }; const char *tap_state_name(tap_state_t state) { unsigned i; for (i = 0; i < ARRAY_SIZE(tap_name_mapping); i++) { if (tap_name_mapping[i].symbol == state) return tap_name_mapping[i].name; } return "???"; } tap_state_t tap_state_by_name(const char *name) { unsigned i; for (i = 0; i < ARRAY_SIZE(tap_name_mapping); i++) { /* be nice to the human */ if (strcasecmp(name, tap_name_mapping[i].name) == 0) return tap_name_mapping[i].symbol; } /* not found */ return TAP_INVALID; } #define JTAG_DEBUG_STATE_APPEND(buf, len, bit) \ do { buf[len] = bit ? '1' : '0'; } while (0) #define JTAG_DEBUG_STATE_PRINT(a, b, astr, bstr) \ LOG_DEBUG_IO("TAP/SM: %9s -> %5s\tTMS: %s\tTDI: %s", \ tap_state_name(a), tap_state_name(b), astr, bstr) tap_state_t jtag_debug_state_machine_(const void *tms_buf, const void *tdi_buf, unsigned int tap_bits, tap_state_t next_state) { const uint8_t *tms_buffer; const uint8_t *tdi_buffer; unsigned tap_bytes; unsigned cur_byte; unsigned cur_bit; unsigned tap_out_bits; char tms_str[33]; char tdi_str[33]; tap_state_t last_state; /* set startstate (and possibly last, if tap_bits == 0) */ last_state = next_state; LOG_DEBUG_IO("TAP/SM: START state: %s", tap_state_name(next_state)); tms_buffer = (const uint8_t *)tms_buf; tdi_buffer = (const uint8_t *)tdi_buf; tap_bytes = DIV_ROUND_UP(tap_bits, 8); LOG_DEBUG_IO("TAP/SM: TMS bits: %u (bytes: %u)", tap_bits, tap_bytes); tap_out_bits = 0; for (cur_byte = 0; cur_byte < tap_bytes; cur_byte++) { for (cur_bit = 0; cur_bit < 8; cur_bit++) { /* make sure we do not run off the end of the buffers */ unsigned tap_bit = cur_byte * 8 + cur_bit; if (tap_bit == tap_bits) break; /* check and save TMS bit */ tap_bit = !!(tms_buffer[cur_byte] & (1 << cur_bit)); JTAG_DEBUG_STATE_APPEND(tms_str, tap_out_bits, tap_bit); /* use TMS bit to find the next TAP state */ next_state = tap_state_transition(last_state, tap_bit); /* check and store TDI bit */ tap_bit = !!(tdi_buffer[cur_byte] & (1 << cur_bit)); JTAG_DEBUG_STATE_APPEND(tdi_str, tap_out_bits, tap_bit); /* increment TAP bits */ tap_out_bits++; /* Only show TDO bits on state transitions, or */ /* after some number of bits in the same state. */ if ((next_state == last_state) && (tap_out_bits < 32)) continue; /* terminate strings and display state transition */ tms_str[tap_out_bits] = tdi_str[tap_out_bits] = 0; JTAG_DEBUG_STATE_PRINT(last_state, next_state, tms_str, tdi_str); /* reset state */ last_state = next_state; tap_out_bits = 0; } } if (tap_out_bits) { /* terminate strings and display state transition */ tms_str[tap_out_bits] = tdi_str[tap_out_bits] = 0; JTAG_DEBUG_STATE_PRINT(last_state, next_state, tms_str, tdi_str); } LOG_DEBUG_IO("TAP/SM: FINAL state: %s", tap_state_name(next_state)); return next_state; } void tap_use_new_tms_table(bool use_new) { tms_seqs = use_new ? &short_tms_seqs : &old_tms_seqs; } bool tap_uses_new_tms_table(void) { return tms_seqs == &short_tms_seqs; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/interface.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * ***************************************************************************/ #ifndef OPENOCD_JTAG_INTERFACE_H #define OPENOCD_JTAG_INTERFACE_H #include <jtag/jtag.h> #include <jtag/swim.h> #include <target/arm_tpiu_swo.h> /* @file * The "Cable Helper API" is what the cable drivers can use to help * implement their "Cable API". So a Cable Helper API is a set of * helper functions used by cable drivers, and this is different from a * Cable API. A "Cable API" is what higher level code used to talk to a * cable. */ /** implementation of wrapper function tap_set_state() */ void tap_set_state_impl(tap_state_t new_state); /** * This function sets the state of a "state follower" which tracks the * state of the TAPs connected to the cable. The state follower is * hopefully always in the same state as the actual TAPs in the jtag * chain, and will be so if there are no bugs in the tracking logic * within that cable driver. * * All the cable drivers call this function to indicate the state they * think the TAPs attached to their cables are in. Because this * function can also log transitions, it will be helpful to call this * function with every transition that the TAPs being manipulated are * expected to traverse, not just end points of a multi-step state path. * * @param new_state The state we think the TAPs are currently in (or * are about to enter). */ #define tap_set_state(new_state) \ do { \ LOG_DEBUG_IO("tap_set_state(%s)", tap_state_name(new_state)); \ tap_set_state_impl(new_state); \ } while (0) /** * This function gets the state of the "state follower" which tracks the * state of the TAPs connected to the cable. @see tap_set_state @return * tap_state_t The state the TAPs are in now. */ tap_state_t tap_get_state(void); /** * This function sets the state of an "end state follower" which tracks * the state that any cable driver thinks will be the end (resultant) * state of the current TAP SIR or SDR operation. * * At completion of that TAP operation this value is copied into the * state follower via tap_set_state(). * * @param new_end_state The state the TAPs should enter at completion of * a pending TAP operation. */ void tap_set_end_state(tap_state_t new_end_state); /** * For more information, @see tap_set_end_state * @return tap_state_t - The state the TAPs should be in at completion of the current TAP operation. */ tap_state_t tap_get_end_state(void); /** * This function provides a "bit sequence" indicating what has to be * done with TMS during a sequence of seven TAP clock cycles in order to * get from state \a "from" to state \a "to". * * The length of the sequence must be determined with a parallel call to * tap_get_tms_path_len(). * * @param from The starting state. * @param to The desired final state. * @return int The required TMS bit sequence, with the first bit in the * sequence at bit 0. */ int tap_get_tms_path(tap_state_t from, tap_state_t to); /** * Function int tap_get_tms_path_len * returns the total number of bits that represents a TMS path * transition as given by the function tap_get_tms_path(). * * For at least one interface (JLink) it's not OK to simply "pad" TMS * sequences to fit a whole byte. (I suspect this is a general TAP * problem within OOCD.) Padding TMS causes all manner of instability * that's not easily discovered. Using this routine we can apply * EXACTLY the state transitions required to make something work - no * more - no less. * * @param from is the starting state * @param to is the resultant or final state * @return int - the total number of bits in a transition. */ int tap_get_tms_path_len(tap_state_t from, tap_state_t to); /** * Function tap_move_ndx * when given a stable state, returns an index from 0-5. The index corresponds to a * sequence of stable states which are given in this order: <p> * { TAP_RESET, TAP_IDLE, TAP_DRSHIFT, TAP_DRPAUSE, TAP_IRSHIFT, TAP_IRPAUSE } * <p> * This sequence corresponds to look up tables which are used in some of the * cable drivers. * @param astate is the stable state to find in the sequence. If a non stable * state is passed, this may cause the program to output an error message * and terminate. * @return int - the array (or sequence) index as described above */ int tap_move_ndx(tap_state_t astate); /** * Function tap_is_state_stable * returns true if the \a astate is stable. */ bool tap_is_state_stable(tap_state_t astate); /** * Function tap_state_transition * takes a current TAP state and returns the next state according to the tms value. * @param current_state is the state of a TAP currently. * @param tms is either zero or non-zero, just like a real TMS line in a jtag interface. * @return tap_state_t - the next state a TAP would enter. */ tap_state_t tap_state_transition(tap_state_t current_state, bool tms); /** Allow switching between old and new TMS tables. @see tap_get_tms_path */ void tap_use_new_tms_table(bool use_new); /** @returns True if new TMS table is active; false otherwise. */ bool tap_uses_new_tms_table(void); tap_state_t jtag_debug_state_machine_(const void *tms_buf, const void *tdi_buf, unsigned int tap_len, tap_state_t start_tap_state); /** * @brief Prints verbose TAP state transitions for the given TMS/TDI buffers. * @param tms_buf must points to a buffer containing the TMS bitstream. * @param tdi_buf must points to a buffer containing the TDI bitstream. * @param tap_len must specify the length of the TMS/TDI bitstreams. * @param start_tap_state must specify the current TAP state. * @returns the final TAP state; pass as @a start_tap_state in following call. */ static inline tap_state_t jtag_debug_state_machine(const void *tms_buf, const void *tdi_buf, unsigned tap_len, tap_state_t start_tap_state) { if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) return jtag_debug_state_machine_(tms_buf, tdi_buf, tap_len, start_tap_state); else return start_tap_state; } /** * Represents a driver for a debugging interface. * * @todo Rename; perhaps "debug_driver". This isn't an interface, * it's a driver! Also, not all drivers support JTAG. * * @todo We need a per-instance structure too, and changes to pass * that structure to the driver. Instances can for example be in * either SWD or JTAG modes. This will help remove globals, and * eventually to cope with systems which have more than one such * debugging interface. */ struct jtag_interface { /** * Bit vector listing capabilities exposed by this driver. */ unsigned supported; #define DEBUG_CAP_TMS_SEQ (1 << 0) /** * Execute queued commands. * @returns ERROR_OK on success, or an error code on failure. */ int (*execute_queue)(void); }; /** * Represents a driver for a debugging interface * * @todo We need a per-instance structure too, and changes to pass * that structure to the driver. Instances can for example be in * either SWD or JTAG modes. This will help remove globals, and * eventually to cope with systems which have more than one such * debugging interface. */ struct adapter_driver { /** The name of the interface driver. */ const char * const name; /** transports supported in C code (NULL terminated vector) */ const char * const *transports; /** * The interface driver may register additional commands to expose * additional features not covered by the standard command set. */ const struct command_registration *commands; /** * Interface driver must initialize any resources and connect to a * JTAG device. * * quit() is invoked if and only if init() succeeds. quit() is always * invoked if init() succeeds. Same as malloc() + free(). Always * invoke free() if malloc() succeeds and do not invoke free() * otherwise. * * @returns ERROR_OK on success, or an error code on failure. */ int (*init)(void); /** * Interface driver must tear down all resources and disconnect from * the JTAG device. * * @returns ERROR_OK on success, or an error code on failure. */ int (*quit)(void); /** * Control (assert/deassert) the signals SRST and TRST on the interface. * This function is synchronous and should be called after the adapter * queue has been properly flushed. * This function is optional. * Adapters that don't support resets can either not define this function * or return an error code. * Adapters that don't support one of the two reset should ignore the * request to assert the missing signal and eventually log an error. * * @param srst 1 to assert SRST, 0 to deassert SRST. * @param trst 1 to assert TRST, 0 to deassert TRST. * @returns ERROR_OK on success, or an error code on failure. */ int (*reset)(int srst, int trst); /** * Set the interface speed. * @param speed The new interface speed setting. * @returns ERROR_OK on success, or an error code on failure. */ int (*speed)(int speed); /** * Returns JTAG maximum speed for KHz. 0 = RTCK. The function returns * a failure if it can't support the KHz/RTCK. * * WARNING!!!! if RTCK is *slow* then think carefully about * whether you actually want to support this in the driver. * Many target scripts are written to handle the absence of RTCK * and use a fallback kHz TCK. * @returns ERROR_OK on success, or an error code on failure. */ int (*khz)(int khz, int *jtag_speed); /** * Calculate the clock frequency (in KHz) for the given @a speed. * @param speed The desired interface speed setting. * @param khz On return, contains the speed in KHz (0 for RTCK). * @returns ERROR_OK on success, or an error code if the * interface cannot support the specified speed (KHz or RTCK). */ int (*speed_div)(int speed, int *khz); /** * Read and clear the power dropout flag. Note that a power dropout * can be transitionary, easily much less than a ms. * * To find out if the power is *currently* on, one must invoke this * method twice. Once to clear the power dropout flag and a second * time to read the current state. The default implementation * never reports power dropouts. * * @returns ERROR_OK on success, or an error code on failure. */ int (*power_dropout)(int *power_dropout); /** * Read and clear the srst asserted detection flag. * * Like power_dropout this does *not* read the current * state. SRST assertion is transitionary and may be much * less than 1ms, so the interface driver must watch for these * events until this routine is called. * * @param srst_asserted On return, indicates whether SRST has * been asserted. * @returns ERROR_OK on success, or an error code on failure. */ int (*srst_asserted)(int *srst_asserted); /** * Configure trace parameters for the adapter * * @param enabled Whether to enable trace * @param pin_protocol Configured pin protocol * @param port_size Trace port width for sync mode * @param trace_freq A pointer to the configured trace * frequency; if it points to 0, the adapter driver must write * its maximum supported rate there * @param traceclkin_freq TRACECLKIN frequency provided to the TPIU in Hz * @param prescaler Pointer to the SWO prescaler calculated by the * adapter * @returns ERROR_OK on success, an error code on failure. */ int (*config_trace)(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler); /** * Poll for new trace data * * @param buf A pointer to buffer to store received data * @param size A pointer to buffer size; must be filled with * the actual amount of bytes written * * @returns ERROR_OK on success, an error code on failure. */ int (*poll_trace)(uint8_t *buf, size_t *size); /** Low-level JTAG APIs */ struct jtag_interface *jtag_ops; /** Low-level SWD APIs */ const struct swd_driver *swd_ops; /* DAP APIs over JTAG transport */ const struct dap_ops *dap_jtag_ops; /* DAP APIs over SWD transport */ const struct dap_ops *dap_swd_ops; /* SWIM APIs */ const struct swim_driver *swim_ops; }; extern const char * const jtag_only[]; int adapter_resets(int assert_trst, int assert_srst); int adapter_assert_reset(void); int adapter_deassert_reset(void); int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler); int adapter_poll_trace(uint8_t *buf, size_t *size); extern struct adapter_driver am335xgpio_adapter_driver; extern struct adapter_driver amt_jtagaccel_adapter_driver; extern struct adapter_driver armjtagew_adapter_driver; extern struct adapter_driver at91rm9200_adapter_driver; extern struct adapter_driver bcm2835gpio_adapter_driver; extern struct adapter_driver buspirate_adapter_driver; extern struct adapter_driver cmsis_dap_adapter_driver; extern struct adapter_driver dummy_adapter_driver; extern struct adapter_driver ep93xx_adapter_driver; extern struct adapter_driver esp_usb_adapter_driver; extern struct adapter_driver ft232r_adapter_driver; extern struct adapter_driver ftdi_adapter_driver; extern struct adapter_driver gw16012_adapter_driver; extern struct adapter_driver hl_adapter_driver; extern struct adapter_driver imx_gpio_adapter_driver; extern struct adapter_driver jlink_adapter_driver; extern struct adapter_driver jtag_dpi_adapter_driver; extern struct adapter_driver jtag_vpi_adapter_driver; extern struct adapter_driver kitprog_adapter_driver; extern struct adapter_driver linuxgpiod_adapter_driver; extern struct adapter_driver opendous_adapter_driver; extern struct adapter_driver openjtag_adapter_driver; extern struct adapter_driver osbdm_adapter_driver; extern struct adapter_driver parport_adapter_driver; extern struct adapter_driver presto_adapter_driver; extern struct adapter_driver remote_bitbang_adapter_driver; extern struct adapter_driver rlink_adapter_driver; extern struct adapter_driver rshim_dap_adapter_driver; extern struct adapter_driver stlink_dap_adapter_driver; extern struct adapter_driver sysfsgpio_adapter_driver; extern struct adapter_driver ulink_adapter_driver; extern struct adapter_driver usb_blaster_adapter_driver; extern struct adapter_driver usbprog_adapter_driver; extern struct adapter_driver vdebug_adapter_driver; extern struct adapter_driver vsllink_adapter_driver; extern struct adapter_driver xds110_adapter_driver; extern struct adapter_driver xlnx_pcie_xvc_adapter_driver; extern struct adapter_driver ch347_adapter_driver; #endif /* OPENOCD_JTAG_INTERFACE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/interfaces.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * * * * Copyright (C) 2020, Ampere Computing LLC * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "interfaces.h" /** @file * This file collects all the built-in JTAG interfaces in the adapter_drivers * array. * * Dynamic loading can be implemented be searching for shared libraries * that contain an adapter_driver structure that can added to this list. */ /** * The list of built-in JTAG interfaces, containing entries for those * drivers that were enabled by the @c configure script. */ struct adapter_driver *adapter_drivers[] = { #if BUILD_PARPORT == 1 &parport_adapter_driver, #endif #if BUILD_DUMMY == 1 &dummy_adapter_driver, #endif #if BUILD_FTDI == 1 &ftdi_adapter_driver, #endif #if BUILD_USB_BLASTER || BUILD_USB_BLASTER_2 == 1 &usb_blaster_adapter_driver, #endif #if BUILD_ESP_USB_JTAG == 1 &esp_usb_adapter_driver, #endif #if BUILD_JTAG_VPI == 1 &jtag_vpi_adapter_driver, #endif #if BUILD_VDEBUG == 1 &vdebug_adapter_driver, #endif #if BUILD_JTAG_DPI == 1 &jtag_dpi_adapter_driver, #endif #if BUILD_FT232R == 1 &ft232r_adapter_driver, #endif #if BUILD_AMTJTAGACCEL == 1 &amt_jtagaccel_adapter_driver, #endif #if BUILD_EP93XX == 1 &ep93xx_adapter_driver, #endif #if BUILD_AT91RM9200 == 1 &at91rm9200_adapter_driver, #endif #if BUILD_GW16012 == 1 &gw16012_adapter_driver, #endif #if BUILD_PRESTO &presto_adapter_driver, #endif #if BUILD_USBPROG == 1 &usbprog_adapter_driver, #endif #if BUILD_OPENJTAG == 1 &openjtag_adapter_driver, #endif #if BUILD_JLINK == 1 &jlink_adapter_driver, #endif #if BUILD_VSLLINK == 1 &vsllink_adapter_driver, #endif #if BUILD_RLINK == 1 &rlink_adapter_driver, #endif #if BUILD_ULINK == 1 &ulink_adapter_driver, #endif #if BUILD_ARMJTAGEW == 1 &armjtagew_adapter_driver, #endif #if BUILD_BUSPIRATE == 1 &buspirate_adapter_driver, #endif #if BUILD_REMOTE_BITBANG == 1 &remote_bitbang_adapter_driver, #endif #if BUILD_HLADAPTER == 1 &hl_adapter_driver, #endif #if BUILD_OSBDM == 1 &osbdm_adapter_driver, #endif #if BUILD_OPENDOUS == 1 &opendous_adapter_driver, #endif #if BUILD_SYSFSGPIO == 1 &sysfsgpio_adapter_driver, #endif #if BUILD_LINUXGPIOD == 1 &linuxgpiod_adapter_driver, #endif #if BUILD_XLNX_PCIE_XVC == 1 &xlnx_pcie_xvc_adapter_driver, #endif #if BUILD_BCM2835GPIO == 1 &bcm2835gpio_adapter_driver, #endif #if BUILD_CMSIS_DAP_USB == 1 || BUILD_CMSIS_DAP_HID == 1 &cmsis_dap_adapter_driver, #endif #if BUILD_KITPROG == 1 &kitprog_adapter_driver, #endif #if BUILD_IMX_GPIO == 1 &imx_gpio_adapter_driver, #endif #if BUILD_XDS110 == 1 &xds110_adapter_driver, #endif #if BUILD_HLADAPTER_STLINK == 1 &stlink_dap_adapter_driver, #endif #if BUILD_RSHIM == 1 &rshim_dap_adapter_driver, #endif #if BUILD_AM335XGPIO == 1 &am335xgpio_adapter_driver, #endif #if BUILD_CH347 == 1 &ch347_adapter_driver, #endif NULL, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/interfaces.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * ***************************************************************************/ #ifndef OPENOCD_JTAG_INTERFACES_H #define OPENOCD_JTAG_INTERFACES_H /** @file * Exports the list of JTAG interface drivers, along with routines * for loading and unloading them dynamically from shared libraries. */ #include <jtag/interface.h> extern struct adapter_driver *adapter_drivers[]; #endif /* OPENOCD_JTAG_INTERFACES_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/jtag.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifndef OPENOCD_JTAG_JTAG_H #define OPENOCD_JTAG_JTAG_H #include <helper/binarybuffer.h> #include <helper/command.h> #include <helper/log.h> #include <helper/replacements.h> #ifndef DEBUG_JTAG_IOZ #define DEBUG_JTAG_IOZ 64 #endif /*-----</Macros>-------------------------------------------------*/ /** * Defines JTAG Test Access Port states. * * These definitions were gleaned from the ARM7TDMI-S Technical * Reference Manual and validated against several other ARM core * technical manuals. * * FIXME some interfaces require specific numbers be used, as they * are handed-off directly to their hardware implementations. * Fix those drivers to map as appropriate ... then pick some * sane set of numbers here (where 0/uninitialized == INVALID). */ typedef enum tap_state { TAP_INVALID = -1, /* Proper ARM recommended numbers */ TAP_DREXIT2 = 0x0, TAP_DREXIT1 = 0x1, TAP_DRSHIFT = 0x2, TAP_DRPAUSE = 0x3, TAP_IRSELECT = 0x4, TAP_DRUPDATE = 0x5, TAP_DRCAPTURE = 0x6, TAP_DRSELECT = 0x7, TAP_IREXIT2 = 0x8, TAP_IREXIT1 = 0x9, TAP_IRSHIFT = 0xa, TAP_IRPAUSE = 0xb, TAP_IDLE = 0xc, TAP_IRUPDATE = 0xd, TAP_IRCAPTURE = 0xe, TAP_RESET = 0x0f, } tap_state_t; /** * Defines arguments for reset functions */ #define SRST_DEASSERT 0 #define SRST_ASSERT 1 #define TRST_DEASSERT 0 #define TRST_ASSERT 1 /** * Function tap_state_name * Returns a string suitable for display representing the JTAG tap_state */ const char *tap_state_name(tap_state_t state); /** Provides user-friendly name lookup of TAP states. */ tap_state_t tap_state_by_name(const char *name); /** The current TAP state of the pending JTAG command queue. */ extern tap_state_t cmd_queue_cur_state; /** * This structure defines a single scan field in the scan. It provides * fields for the field's width and pointers to scan input and output * values. * * In addition, this structure includes a value and mask that is used by * jtag_add_dr_scan_check() to validate the value that was scanned out. */ struct scan_field { /** The number of bits this field specifies */ int num_bits; /** A pointer to value to be scanned into the device */ const uint8_t *out_value; /** A pointer to a 32-bit memory location for data scanned out */ uint8_t *in_value; /** The value used to check the data scanned out. */ uint8_t *check_value; /** The mask to go with check_value */ uint8_t *check_mask; }; struct jtag_tap { char *chip; char *tapname; char *dotted_name; int abs_chain_position; /** Is this TAP disabled after JTAG reset? */ bool disabled_after_reset; /** Is this TAP currently enabled? */ bool enabled; int ir_length; /**< size of instruction register */ uint32_t ir_capture_value; uint8_t *expected; /**< Capture-IR expected value */ uint32_t ir_capture_mask; uint8_t *expected_mask; /**< Capture-IR expected mask */ uint32_t idcode; /**< device identification code */ /** not all devices have idcode, * we'll discover this during chain examination */ bool hasidcode; /** Array of expected identification codes */ uint32_t *expected_ids; /** Number of expected identification codes */ uint8_t expected_ids_cnt; /** Flag saying whether to ignore version field in expected_ids[] */ bool ignore_version; /** Flag saying whether to ignore the bypass bit in the code */ bool ignore_bypass; /** current instruction */ uint8_t *cur_instr; /** Bypass register selected */ int bypass; struct jtag_tap_event_action *event_action; struct jtag_tap *next_tap; /* private pointer to support none-jtag specific functions */ void *priv; }; void jtag_tap_init(struct jtag_tap *tap); void jtag_tap_free(struct jtag_tap *tap); struct jtag_tap *jtag_all_taps(void); const char *jtag_tap_name(const struct jtag_tap *tap); struct jtag_tap *jtag_tap_by_string(const char *dotted_name); struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *obj); struct jtag_tap *jtag_tap_by_position(unsigned abs_position); struct jtag_tap *jtag_tap_next_enabled(struct jtag_tap *p); unsigned jtag_tap_count_enabled(void); unsigned jtag_tap_count(void); /* * - TRST_ASSERTED triggers two sets of callbacks, after operations to * reset the scan chain -- via TMS+TCK signaling, or deasserting the * nTRST signal -- are queued: * * + Callbacks in C code fire first, patching internal state * + Then post-reset event scripts fire ... activating JTAG circuits * via TCK cycles, exiting SWD mode via TMS sequences, etc * * During those callbacks, scan chain contents have not been validated. * JTAG operations that address a specific TAP (primarily DR/IR scans) * must *not* be queued. * * - TAP_EVENT_SETUP is reported after TRST_ASSERTED, and after the scan * chain has been validated. JTAG operations including scans that * target specific TAPs may be performed. * * - TAP_EVENT_ENABLE and TAP_EVENT_DISABLE implement TAP activation and * deactivation outside the core using scripted code that understands * the specific JTAG router type. They might be triggered indirectly * from EVENT_SETUP operations. */ enum jtag_event { JTAG_TRST_ASSERTED, JTAG_TAP_EVENT_SETUP, JTAG_TAP_EVENT_ENABLE, JTAG_TAP_EVENT_DISABLE, }; struct jtag_tap_event_action { /** The event for which this action will be triggered. */ enum jtag_event event; /** The interpreter to use for evaluating the @c body. */ Jim_Interp *interp; /** Contains a script to 'eval' when the @c event is triggered. */ Jim_Obj *body; /* next action in linked list */ struct jtag_tap_event_action *next; }; /** * Defines the function signature required for JTAG event callback * functions, which are added with jtag_register_event_callback() * and removed jtag_unregister_event_callback(). * @param event The event to handle. * @param priv A pointer to data that was passed to * jtag_register_event_callback(). * @returns Must return ERROR_OK on success, or an error code on failure. * * @todo Change to return void or define a use for its return code. */ typedef int (*jtag_event_handler_t)(enum jtag_event event, void *priv); int jtag_register_event_callback(jtag_event_handler_t f, void *x); int jtag_unregister_event_callback(jtag_event_handler_t f, void *x); int jtag_call_event_callbacks(enum jtag_event event); enum reset_types { RESET_NONE = 0x0, RESET_HAS_TRST = 0x1, RESET_HAS_SRST = 0x2, RESET_TRST_AND_SRST = 0x3, RESET_SRST_PULLS_TRST = 0x4, RESET_TRST_PULLS_SRST = 0x8, RESET_TRST_OPEN_DRAIN = 0x10, RESET_SRST_PUSH_PULL = 0x20, RESET_SRST_NO_GATING = 0x40, RESET_CNCT_UNDER_SRST = 0x80 }; enum reset_types jtag_get_reset_config(void); void jtag_set_reset_config(enum reset_types type); void jtag_set_nsrst_delay(unsigned delay); unsigned jtag_get_nsrst_delay(void); void jtag_set_ntrst_delay(unsigned delay); unsigned jtag_get_ntrst_delay(void); void jtag_set_nsrst_assert_width(unsigned delay); unsigned jtag_get_nsrst_assert_width(void); void jtag_set_ntrst_assert_width(unsigned delay); unsigned jtag_get_ntrst_assert_width(void); /** @returns The current state of TRST. */ int jtag_get_trst(void); /** @returns The current state of SRST. */ int jtag_get_srst(void); /** Enable or disable data scan verification checking. */ void jtag_set_verify(bool enable); /** @returns True if data scan verification will be performed. */ bool jtag_will_verify(void); /** Enable or disable verification of IR scan checking. */ void jtag_set_verify_capture_ir(bool enable); /** @returns True if IR scan verification will be performed. */ bool jtag_will_verify_capture_ir(void); /** Set ms to sleep after jtag_execute_queue() flushes queue. Debug purposes. */ void jtag_set_flush_queue_sleep(int ms); /** * Initialize JTAG chain using only a RESET reset. If init fails, * try reset + init. */ int jtag_init(struct command_context *cmd_ctx); /** reset, then initialize JTAG chain */ int jtag_init_reset(struct command_context *cmd_ctx); int jtag_register_commands(struct command_context *cmd_ctx); int jtag_init_inner(struct command_context *cmd_ctx); /** * @file * The JTAG interface can be implemented with a software or hardware fifo. * * TAP_DRSHIFT and TAP_IRSHIFT are illegal end states; however, * TAP_DRSHIFT/IRSHIFT can be emulated as end states, by using longer * scans. * * Code that is relatively insensitive to the path taken through state * machine (as long as it is JTAG compliant) can use @a endstate for * jtag_add_xxx_scan(). Otherwise, the pause state must be specified as * end state and a subsequent jtag_add_pathmove() must be issued. */ /** * Generate an IR SCAN with a list of scan fields with one entry for * each enabled TAP. * * If the input field list contains an instruction value for a TAP then * that is used otherwise the TAP is set to bypass. * * TAPs for which no fields are passed are marked as bypassed for * subsequent DR SCANs. * */ void jtag_add_ir_scan(struct jtag_tap *tap, struct scan_field *fields, tap_state_t endstate); /** * The same as jtag_add_ir_scan except no verification is performed out * the output values. */ void jtag_add_ir_scan_noverify(struct jtag_tap *tap, const struct scan_field *fields, tap_state_t state); /** * Scan out the bits in ir scan mode. * * If in_bits == NULL, discard incoming bits. */ void jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t endstate); /** * Generate a DR SCAN using the fields passed to the function. * For connected TAPs, the function checks in_fields and uses fields * specified there. For bypassed TAPs, the function generates a dummy * 1-bit field. The bypass status of TAPs is set by jtag_add_ir_scan(). */ void jtag_add_dr_scan(struct jtag_tap *tap, int num_fields, const struct scan_field *fields, tap_state_t endstate); /** A version of jtag_add_dr_scan() that uses the check_value/mask fields */ void jtag_add_dr_scan_check(struct jtag_tap *tap, int num_fields, struct scan_field *fields, tap_state_t endstate); /** * Scan out the bits in ir scan mode. * * If in_bits == NULL, discard incoming bits. */ void jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t endstate); /** * Defines the type of data passed to the jtag_callback_t interface. * The underlying type must allow storing an @c int or pointer type. */ typedef intptr_t jtag_callback_data_t; /** * Defines a simple JTAG callback that can allow conversions on data * scanned in from an interface. * * This callback should only be used for conversion that cannot fail. * For conversion types or checks that can fail, use the more complete * variant: jtag_callback_t. */ typedef void (*jtag_callback1_t)(jtag_callback_data_t data0); /** A simpler version of jtag_add_callback4(). */ void jtag_add_callback(jtag_callback1_t f, jtag_callback_data_t data0); /** * Defines the interface of the JTAG callback mechanism. Such * callbacks can be executed once the queue has been flushed. * * The JTAG queue can be executed synchronously or asynchronously. * Typically for USB, the queue is executed asynchronously. For * low-latency interfaces, the queue may be executed synchronously. * * The callback mechanism is very general and does not make many * assumptions about what the callback does or what its arguments are. * These callbacks are typically executed *after* the *entire* JTAG * queue has been executed for e.g. USB interfaces, and they are * guaranteed to be invoked in the order that they were queued. * * If the execution of the queue fails before the callbacks, then -- * depending on driver implementation -- the callbacks may or may not be * invoked. * * @todo Make that behavior consistent. * * @param data0 Typically used to point to the data to operate on. * Frequently this will be the data clocked in during a shift operation. * @param data1 An integer big enough to use as an @c int or a pointer. * @param data2 An integer big enough to use as an @c int or a pointer. * @param data3 An integer big enough to use as an @c int or a pointer. * @returns an error code */ typedef int (*jtag_callback_t)(jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3); /** * Run a TAP_RESET reset where the end state is TAP_RESET, * regardless of the start state. */ void jtag_add_tlr(void); /** * Application code *must* assume that interfaces will * implement transitions between states with different * paths and path lengths through the state diagram. The * path will vary across interface and also across versions * of the same interface over time. Even if the OpenOCD code * is unchanged, the actual path taken may vary over time * and versions of interface firmware or PCB revisions. * * Use jtag_add_pathmove() when specific transition sequences * are required. * * Do not use jtag_add_pathmove() unless you need to, but do use it * if you have to. * * DANGER! If the target is dependent upon a particular sequence * of transitions for things to work correctly(e.g. as a workaround * for an errata that contradicts the JTAG standard), then pathmove * must be used, even if some jtag interfaces happen to use the * desired path. Worse, the jtag interface used for testing a * particular implementation, could happen to use the "desired" * path when transitioning to/from end * state. * * A list of unambiguous single clock state transitions, not * all drivers can support this, but it is required for e.g. * XScale and Xilinx support * * Note! TAP_RESET must not be used in the path! * * Note that the first on the list must be reachable * via a single transition from the current state. * * All drivers are required to implement jtag_add_pathmove(). * However, if the pathmove sequence can not be precisely * executed, an interface_jtag_add_pathmove() or jtag_execute_queue() * must return an error. It is legal, but not recommended, that * a driver returns an error in all cases for a pathmove if it * can only implement a few transitions and therefore * a partial implementation of pathmove would have little practical * application. * * If an error occurs, jtag_error will contain one of these error codes: * - ERROR_JTAG_NOT_STABLE_STATE -- The final state was not stable. * - ERROR_JTAG_STATE_INVALID -- The path passed through TAP_RESET. * - ERROR_JTAG_TRANSITION_INVALID -- The path includes invalid * state transitions. */ void jtag_add_pathmove(int num_states, const tap_state_t *path); /** * jtag_add_statemove() moves from the current state to @a goal_state. * * @param goal_state The final TAP state. * @return ERROR_OK on success, or an error code on failure. * * Moves from the current state to the goal \a state. * Both states must be stable. */ int jtag_add_statemove(tap_state_t goal_state); /** * Goes to TAP_IDLE (if we're not already there), cycle * precisely num_cycles in the TAP_IDLE state, after which move * to @a endstate (unless it is also TAP_IDLE). * * @param num_cycles Number of cycles in TAP_IDLE state. This argument * may be 0, in which case this routine will navigate to @a endstate * via TAP_IDLE. * @param endstate The final state. */ void jtag_add_runtest(int num_cycles, tap_state_t endstate); /** * A reset of the TAP state machine can be requested. * * Whether tms or trst reset is used depends on the capabilities of * the target and jtag interface(reset_config command configures this). * * srst can driver a reset of the TAP state machine and vice * versa * * Application code may need to examine value of jtag_reset_config * to determine the proper codepath * * DANGER! Even though srst drives trst, trst might not be connected to * the interface, and it might actually be *harmful* to assert trst in this case. * * This is why combinations such as "reset_config srst_only srst_pulls_trst" * are supported. * * only req_tlr_or_trst and srst can have a transition for a * call as the effects of transitioning both at the "same time" * are undefined, but when srst_pulls_trst or vice versa, * then trst & srst *must* be asserted together. */ void jtag_add_reset(int req_tlr_or_trst, int srst); void jtag_add_sleep(uint32_t us); int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state t); /** * Function jtag_add_clocks * first checks that the state in which the clocks are to be issued is * stable, then queues up num_cycles clocks for transmission. */ void jtag_add_clocks(int num_cycles); /** * For software FIFO implementations, the queued commands can be executed * during this call or earlier. A sw queue might decide to push out * some of the jtag_add_xxx() operations once the queue is "big enough". * * This fn will return an error code if any of the prior jtag_add_xxx() * calls caused a failure, e.g. check failure. Note that it does not * matter if the operation was executed *before* jtag_execute_queue(), * jtag_execute_queue() will still return an error code. * * All jtag_add_xxx() calls that have in_handler != NULL will have been * executed when this fn returns, but if what has been queued only * clocks data out, without reading anything back, then JTAG could * be running *after* jtag_execute_queue() returns. The API does * not define a way to flush a hw FIFO that runs *after* * jtag_execute_queue() returns. * * jtag_add_xxx() commands can either be executed immediately or * at some time between the jtag_add_xxx() fn call and jtag_execute_queue(). */ int jtag_execute_queue(void); /** same as jtag_execute_queue() but does not clear the error flag */ void jtag_execute_queue_noclear(void); /** @returns the number of times the scan queue has been flushed */ int jtag_get_flush_queue_count(void); /** Report Tcl event to all TAPs */ void jtag_notify_event(enum jtag_event); /* can be implemented by hw + sw */ int jtag_power_dropout(int *dropout); int jtag_srst_asserted(int *srst_asserted); /* JTAG support functions */ /** * Execute jtag queue and check value with an optional mask. * @param field Pointer to scan field. * @param value Pointer to scan value. * @param mask Pointer to scan mask; may be NULL. * * returns Nothing, but calls jtag_set_error() on any error. */ void jtag_check_value_mask(struct scan_field *field, uint8_t *value, uint8_t *mask); void jtag_sleep(uint32_t us); /* * The JTAG subsystem defines a number of error codes, * using codes between -100 and -199. */ #define ERROR_JTAG_INIT_FAILED (-100) #define ERROR_JTAG_INVALID_INTERFACE (-101) #define ERROR_JTAG_NOT_IMPLEMENTED (-102) #define ERROR_JTAG_TRST_ASSERTED (-103) #define ERROR_JTAG_QUEUE_FAILED (-104) #define ERROR_JTAG_NOT_STABLE_STATE (-105) #define ERROR_JTAG_DEVICE_ERROR (-107) #define ERROR_JTAG_STATE_INVALID (-108) #define ERROR_JTAG_TRANSITION_INVALID (-109) #define ERROR_JTAG_INIT_SOFT_FAIL (-110) /** * Set the current JTAG core execution error, unless one was set * by a previous call previously. Driver or application code must * use jtag_error_clear to reset jtag_error once this routine has been * called with a non-zero error code. */ void jtag_set_error(int error); /** * Resets jtag_error to ERROR_OK, returning its previous value. * @returns The previous value of @c jtag_error. */ int jtag_error_clear(void); /** * Return true if it's safe for a background polling task to access the * JTAG scan chain. Polling may be explicitly disallowed, and is also * unsafe while nTRST is active or the JTAG clock is gated off. */ bool is_jtag_poll_safe(void); /** * Return flag reporting whether JTAG polling is disallowed. */ bool jtag_poll_get_enabled(void); /** * Assign flag reporting whether JTAG polling is disallowed. */ void jtag_poll_set_enabled(bool value); /** * Mask (disable) polling and return the current mask status that should be * feed to jtag_poll_unmask() to restore it. * Multiple nested calls to jtag_poll_mask() are allowed, each balanced with * its call to jtag_poll_unmask(). */ bool jtag_poll_mask(void); /** * Restore saved mask for polling. */ void jtag_poll_unmask(bool saved); #include <jtag/minidriver.h> __COMMAND_HANDLER(handle_jtag_newtap); #endif /* OPENOCD_JTAG_JTAG_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/minidriver.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * ***************************************************************************/ #ifndef OPENOCD_JTAG_MINIDRIVER_H #define OPENOCD_JTAG_MINIDRIVER_H /** * @page jtagminidriver JTAG Mini-Driver * * The JTAG minidriver interface allows the definition of alternate * interface functions, instead of the built-in asynchronous driver * module that is used by the standard JTAG interface drivers. * * In addition to the functions defined in the @c minidriver.h file, the * @c jtag_minidriver.h file must declare the following functions (or * define static inline versions of them): * - jtag_add_callback * - jtag_add_callback4 * * The following core functions are declared in this file for use by * the minidriver and do @b not need to be defined by an implementation: * - default_interface_jtag_execute_queue() */ /* this header will be provided by the minidriver implementation, */ /* and it may provide additional declarations that must be defined. */ #include <jtag/drivers/minidriver_imp.h> int interface_jtag_add_ir_scan(struct jtag_tap *active, const struct scan_field *fields, tap_state_t endstate); int interface_jtag_add_plain_ir_scan( int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t endstate); int interface_jtag_add_dr_scan(struct jtag_tap *active, int num_fields, const struct scan_field *fields, tap_state_t endstate); int interface_jtag_add_plain_dr_scan( int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t endstate); int interface_jtag_add_tlr(void); int interface_jtag_add_pathmove(int num_states, const tap_state_t *path); int interface_jtag_add_runtest(int num_cycles, tap_state_t endstate); int interface_add_tms_seq(unsigned num_bits, const uint8_t *bits, enum tap_state state); /** * This drives the actual srst and trst pins. srst will always be 0 * if jtag_reset_config & RESET_SRST_PULLS_TRST != 0 and ditto for * trst. * * the higher level jtag_add_reset will invoke jtag_add_tlr() if * appropriate */ int interface_jtag_add_reset(int trst, int srst); int interface_jtag_add_sleep(uint32_t us); int interface_jtag_add_clocks(int num_cycles); int interface_jtag_execute_queue(void); /** * Calls the interface callback to execute the queue. This routine * is used by the JTAG driver layer and should not be called directly. */ int default_interface_jtag_execute_queue(void); #endif /* OPENOCD_JTAG_MINIDRIVER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/startup.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Defines basic Tcl procs for OpenOCD JTAG module # Executed during "init". Can be overridden # by board/target/... scripts proc jtag_init {} { if {[catch {jtag arp_init} err]!=0} { # try resetting additionally init_reset startup } } # This reset logic may be overridden by board/target/... scripts as needed # to provide a reset that, if possible, is close to a power-up reset. # # Exit requirements include: (a) JTAG must be working, (b) the scan # chain was validated with "jtag arp_init" (or equivalent), (c) nothing # stays in reset. No TAP-specific scans were performed. It's OK if # some targets haven't been reset yet; they may need TAP-specific scans. # # The "mode" values include: halt, init, run (from "reset" command); # startup (at OpenOCD server startup, when JTAG may not yet work); and # potentially more (for reset types like cold, warm, etc) proc init_reset { mode } { if {[using_jtag]} { jtag arp_init-reset } } ######### # TODO: power_restore and power_dropout are currently neither # documented nor supported. proc power_restore {} { echo "Sensed power restore, running reset init and halting GDB." reset init # Halt GDB so user can deal with a detected power restore. # # After GDB is halted, then output is no longer forwarded # to the GDB console. set targets [target names] foreach t $targets { # New event script. $t invoke-event arp_halt_gdb } } add_help_text power_restore "Overridable procedure run when power restore is detected. Runs 'reset init' by default." proc power_dropout {} { echo "Sensed power dropout." } ######### # TODO: srst_deasserted and srst_asserted are currently neither # documented nor supported. proc srst_deasserted {} { echo "Sensed nSRST deasserted, running reset init and halting GDB." reset init # Halt GDB so user can deal with a detected reset. # # After GDB is halted, then output is no longer forwarded # to the GDB console. set targets [target names] foreach t $targets { # New event script. $t invoke-event arp_halt_gdb } } add_help_text srst_deasserted "Overridable procedure run when srst deassert is detected. Runs 'reset init' by default." proc srst_asserted {} { echo "Sensed nSRST asserted." } # measure actual JTAG clock proc measure_clk {} { set start_time [ms]; set iterations 10000000; runtest $iterations; set speed [expr "$iterations.0 / ([ms] - $start_time)"] echo "Running at more than $speed kHz"; } add_help_text measure_clk "Runs a test to measure the JTAG clk. Useful with RCLK / RTCK." proc default_to_jtag { f args } { set current_transport [transport select] if {[using_jtag]} { eval $f $args } { error "session transport is \"$current_transport\" but your config requires JTAG" } } proc jtag args { eval default_to_jtag jtag $args } proc jtag_rclk args { eval default_to_jtag jtag_rclk $args } proc jtag_ntrst_delay args { eval default_to_jtag jtag_ntrst_delay $args } proc jtag_ntrst_assert_width args { eval default_to_jtag jtag_ntrst_assert_width $args } # BEGIN MIGRATION AIDS ... these adapter operations originally had # JTAG-specific names despite the fact that the operations were not # specific to JTAG, or otherwise had troublesome/misleading names. # # FIXME phase these aids out after some releases # lappend _telnet_autocomplete_skip adapter_gpio_helper_with_caller # Helper for deprecated driver functions that should call "adapter gpio XXX". # Call this function as: # adapter_gpio_helper_with_caller caller sig_name # adapter_gpio_helper_with_caller caller sig_name gpio_num # adapter_gpio_helper_with_caller caller sig_name chip_num gpio_num proc adapter_gpio_helper_with_caller {caller sig_name args} { echo "DEPRECATED! use 'adapter gpio $sig_name' not '$caller'" switch [llength $args] { 0 {} 1 {eval adapter gpio $sig_name $args} 2 {eval adapter gpio $sig_name [lindex $args 1] -chip [lindex $args 0]} default {return -code 1 -level 1 "$caller: syntax error"} } eval adapter gpio $sig_name } lappend _telnet_autocomplete_skip adapter_gpio_helper # Call this function as: # adapter_gpio_helper sig_name # adapter_gpio_helper sig_name gpio_num # adapter_gpio_helper sig_name chip_num gpio_num proc adapter_gpio_helper {sig_name args} { set caller [lindex [info level -1] 0] eval adapter_gpio_helper_with_caller {"$caller"} $sig_name $args } lappend _telnet_autocomplete_skip adapter_gpio_jtag_nums_with_caller # Helper for deprecated driver functions that implemented jtag_nums proc adapter_gpio_jtag_nums_with_caller {caller tck_num tms_num tdi_num tdo_num} { echo "DEPRECATED! use 'adapter gpio tck; adapter gpio tms; adapter gpio tdi; adapter gpio tdo' not '$caller'" eval adapter gpio tck $tck_num eval adapter gpio tms $tms_num eval adapter gpio tdi $tdi_num eval adapter gpio tdo $tdo_num } lappend _telnet_autocomplete_skip adapter_gpio_jtag_nums # Helper for deprecated driver functions that implemented jtag_nums proc adapter_gpio_jtag_nums {args} { set caller [lindex [info level -1] 0] eval adapter_gpio_jtag_nums_with_caller {"$caller"} $args } lappend _telnet_autocomplete_skip adapter_gpio_swd_nums_with_caller # Helper for deprecated driver functions that implemented swd_nums proc adapter_gpio_swd_nums_with_caller {caller swclk_num swdio_num} { echo "DEPRECATED! use 'adapter gpio swclk; adapter gpio swdio' not '$caller'" eval adapter gpio swclk $swclk_num eval adapter gpio swdio $swdio_num } lappend _telnet_autocomplete_skip adapter_gpio_swd_nums # Helper for deprecated driver functions that implemented jtag_nums proc adapter_gpio_swd_nums {args} { set caller [lindex [info level -1] 0] eval adapter_gpio_swd_nums_with_caller {"$caller"} $args } lappend _telnet_autocomplete_skip jtag_reset proc jtag_reset args { echo "DEPRECATED! use 'adapter \[de\]assert' not 'jtag_reset'" switch $args { "0 0" {eval adapter deassert trst deassert srst} "0 1" {eval adapter deassert trst assert srst} "1 0" {eval adapter assert trst deassert srst} "1 1" {eval adapter assert trst assert srst} default {return -code 1 -level 1 "jtag_reset: syntax error"} } } lappend _telnet_autocomplete_skip adapter_khz proc adapter_khz args { echo "DEPRECATED! use 'adapter speed' not 'adapter_khz'" eval adapter speed $args } lappend _telnet_autocomplete_skip adapter_name proc adapter_name args { echo "DEPRECATED! use 'adapter name' not 'adapter_name'" eval adapter name $args } lappend _telnet_autocomplete_skip adapter_nsrst_delay proc adapter_nsrst_delay args { echo "DEPRECATED! use 'adapter srst delay' not 'adapter_nsrst_delay'" eval adapter srst delay $args } lappend _telnet_autocomplete_skip adapter_nsrst_assert_width proc adapter_nsrst_assert_width args { echo "DEPRECATED! use 'adapter srst pulse_width' not 'adapter_nsrst_assert_width'" eval adapter srst pulse_width $args } lappend _telnet_autocomplete_skip interface proc interface args { echo "DEPRECATED! use 'adapter driver' not 'interface'" eval adapter driver $args } lappend _telnet_autocomplete_skip interface_transports proc interface_transports args { echo "DEPRECATED! use 'adapter transports' not 'interface_transports'" eval adapter transports $args } lappend _telnet_autocomplete_skip interface_list proc interface_list args { echo "DEPRECATED! use 'adapter list' not 'interface_list'" eval adapter list $args } lappend _telnet_autocomplete_skip ftdi_location proc ftdi_location args { echo "DEPRECATED! use 'adapter usb location' not 'ftdi_location'" eval adapter usb location $args } lappend _telnet_autocomplete_skip xds110_serial proc xds110_serial args { echo "DEPRECATED! use 'adapter serial' not 'xds110_serial'" eval adapter serial $args } lappend _telnet_autocomplete_skip xds110_supply_voltage proc xds110_supply_voltage args { echo "DEPRECATED! use 'xds110 supply' not 'xds110_supply_voltage'" eval xds110 supply $args } proc hla {cmd args} { tailcall "hla $cmd" {*}$args } lappend _telnet_autocomplete_skip "hla newtap" proc "hla newtap" {args} { echo "DEPRECATED! use 'swj_newdap' not 'hla newtap'" eval swj_newdap $args } lappend _telnet_autocomplete_skip ftdi_device_desc proc ftdi_device_desc args { echo "DEPRECATED! use 'ftdi device_desc' not 'ftdi_device_desc'" eval ftdi device_desc $args } lappend _telnet_autocomplete_skip ftdi_serial proc ftdi_serial args { echo "DEPRECATED! use 'adapter serial' not 'ftdi_serial'" eval adapter serial $args } lappend _telnet_autocomplete_skip ftdi_channel proc ftdi_channel args { echo "DEPRECATED! use 'ftdi channel' not 'ftdi_channel'" eval ftdi channel $args } lappend _telnet_autocomplete_skip ftdi_layout_init proc ftdi_layout_init args { echo "DEPRECATED! use 'ftdi layout_init' not 'ftdi_layout_init'" eval ftdi layout_init $args } lappend _telnet_autocomplete_skip ftdi_layout_signal proc ftdi_layout_signal args { echo "DEPRECATED! use 'ftdi layout_signal' not 'ftdi_layout_signal'" eval ftdi layout_signal $args } lappend _telnet_autocomplete_skip ftdi_set_signal proc ftdi_set_signal args { echo "DEPRECATED! use 'ftdi set_signal' not 'ftdi_set_signal'" eval ftdi set_signal $args } lappend _telnet_autocomplete_skip ftdi_get_signal proc ftdi_get_signal args { echo "DEPRECATED! use 'ftdi get_signal' not 'ftdi_get_signal'" eval ftdi get_signal $args } lappend _telnet_autocomplete_skip ftdi_vid_pid proc ftdi_vid_pid args { echo "DEPRECATED! use 'ftdi vid_pid' not 'ftdi_vid_pid'" eval ftdi vid_pid $args } lappend _telnet_autocomplete_skip ftdi_tdo_sample_edge proc ftdi_tdo_sample_edge args { echo "DEPRECATED! use 'ftdi tdo_sample_edge' not 'ftdi_tdo_sample_edge'" eval ftdi tdo_sample_edge $args } lappend _telnet_autocomplete_skip remote_bitbang_host proc remote_bitbang_host args { echo "DEPRECATED! use 'remote_bitbang host' not 'remote_bitbang_host'" eval remote_bitbang host $args } lappend _telnet_autocomplete_skip remote_bitbang_port proc remote_bitbang_port args { echo "DEPRECATED! use 'remote_bitbang port' not 'remote_bitbang_port'" eval remote_bitbang port $args } lappend _telnet_autocomplete_skip openjtag_device_desc proc openjtag_device_desc args { echo "DEPRECATED! use 'openjtag device_desc' not 'openjtag_device_desc'" eval openjtag device_desc $args } lappend _telnet_autocomplete_skip openjtag_variant proc openjtag_variant args { echo "DEPRECATED! use 'openjtag variant' not 'openjtag_variant'" eval openjtag variant $args } lappend _telnet_autocomplete_skip parport_port proc parport_port args { echo "DEPRECATED! use 'parport port' not 'parport_port'" eval parport port $args } lappend _telnet_autocomplete_skip parport_cable proc parport_cable args { echo "DEPRECATED! use 'parport cable' not 'parport_cable'" eval parport cable $args } lappend _telnet_autocomplete_skip parport_write_on_exit proc parport_write_on_exit args { echo "DEPRECATED! use 'parport write_on_exit' not 'parport_write_on_exit'" eval parport write_on_exit $args } lappend _telnet_autocomplete_skip parport_toggling_time proc parport_toggling_time args { echo "DEPRECATED! use 'parport toggling_time' not 'parport_toggling_time'" eval parport toggling_time $args } lappend _telnet_autocomplete_skip jtag_dpi_set_port proc jtag_dpi_set_port args { echo "DEPRECATED! use 'jtag_dpi set_port' not 'jtag_dpi_set_port'" eval jtag_dpi set_port $args } lappend _telnet_autocomplete_skip jtag_dpi_set_address proc jtag_dpi_set_address args { echo "DEPRECATED! use 'jtag_dpi set_address' not 'jtag_dpi_set_address'" eval jtag_dpi set_address $args } lappend _telnet_autocomplete_skip jtag_vpi_set_port proc jtag_vpi_set_port args { echo "DEPRECATED! use 'jtag_vpi set_port' not 'jtag_vpi_set_port'" eval jtag_vpi set_port $args } lappend _telnet_autocomplete_skip jtag_vpi_set_address proc jtag_vpi_set_address args { echo "DEPRECATED! use 'jtag_vpi set_address' not 'jtag_vpi_set_address'" eval jtag_vpi set_address $args } lappend _telnet_autocomplete_skip jtag_vpi_stop_sim_on_exit proc jtag_vpi_stop_sim_on_exit args { echo "DEPRECATED! use 'jtag_vpi stop_sim_on_exit' not 'jtag_vpi_stop_sim_on_exit'" eval jtag_vpi stop_sim_on_exit $args } lappend _telnet_autocomplete_skip presto_serial proc presto_serial args { echo "DEPRECATED! use 'presto serial' not 'presto_serial'" eval presto serial $args } lappend _telnet_autocomplete_skip xlnx_pcie_xvc_config proc xlnx_pcie_xvc_config args { echo "DEPRECATED! use 'xlnx_pcie_xvc config' not 'xlnx_pcie_xvc_config'" eval xlnx_pcie_xvc config $args } lappend _telnet_autocomplete_skip ulink_download_firmware proc ulink_download_firmware args { echo "DEPRECATED! use 'ulink download_firmware' not 'ulink_download_firmware'" eval ulink download_firmware $args } lappend _telnet_autocomplete_skip vsllink_usb_vid proc vsllink_usb_vid args { echo "DEPRECATED! use 'vsllink usb_vid' not 'vsllink_usb_vid'" eval vsllink usb_vid $args } lappend _telnet_autocomplete_skip vsllink_usb_pid proc vsllink_usb_pid args { echo "DEPRECATED! use 'vsllink usb_pid' not 'vsllink_usb_pid'" eval vsllink usb_pid $args } lappend _telnet_autocomplete_skip vsllink_usb_serial proc vsllink_usb_serial args { echo "DEPRECATED! use 'adapter serial' not 'vsllink_usb_serial'" eval adapter serial $args } lappend _telnet_autocomplete_skip vsllink_usb_bulkin proc vsllink_usb_bulkin args { echo "DEPRECATED! use 'vsllink usb_bulkin' not 'vsllink_usb_bulkin'" eval vsllink usb_bulkin $args } lappend _telnet_autocomplete_skip vsllink_usb_bulkout proc vsllink_usb_bulkout args { echo "DEPRECATED! use 'vsllink usb_bulkout' not 'vsllink_usb_bulkout'" eval vsllink usb_bulkout $args } lappend _telnet_autocomplete_skip vsllink_usb_interface proc vsllink_usb_interface args { echo "DEPRECATED! use 'vsllink usb_interface' not 'vsllink_usb_interface'" eval vsllink usb_interface $args } lappend _telnet_autocomplete_skip bcm2835_gpio_helper proc bcm2835_gpio_helper {sig_name args} { set caller [lindex [info level -1] 0] echo "DEPRECATED! use 'adapter gpio $sig_name' not '$caller'" switch [llength $args] { 0 {} 1 {eval adapter gpio $sig_name $args -chip 0} 2 {eval adapter gpio $sig_name [lindex $args 1] -chip [lindex $args 0]} default {return -code 1 -level 1 "$caller: syntax error"} } eval adapter gpio $sig_name } lappend _telnet_autocomplete_skip bcm2835gpio_jtag_nums proc bcm2835gpio_jtag_nums {tck_num tms_num tdi_num tdo_num} { echo "DEPRECATED! use 'adapter gpio tck; adapter gpio tms; adapter gpio tdi; adapter gpio tdo' not 'bcm2835gpio_jtag_nums'" eval adapter gpio tck $tck_num -chip 0 eval adapter gpio tms $tms_num -chip 0 eval adapter gpio tdi $tdi_num -chip 0 eval adapter gpio tdo $tdo_num -chip 0 } lappend _telnet_autocomplete_skip bcm2835gpio_tck_num proc bcm2835gpio_tck_num args { eval bcm2835_gpio_helper tck $args } lappend _telnet_autocomplete_skip bcm2835gpio_tms_num proc bcm2835gpio_tms_num args { eval bcm2835_gpio_helper tms $args } lappend _telnet_autocomplete_skip bcm2835gpio_tdo_num proc bcm2835gpio_tdo_num args { eval bcm2835_gpio_helper tdo $args } lappend _telnet_autocomplete_skip bcm2835gpio_tdi_num proc bcm2835gpio_tdi_num args { eval bcm2835_gpio_helper tdi $args } lappend _telnet_autocomplete_skip bcm2835gpio_swd_nums proc bcm2835gpio_swd_nums {swclk_num swdio_num} { echo "DEPRECATED! use 'adapter gpio swclk; adapter gpio swdio' not 'bcm2835gpio_swd_nums'" eval adapter gpio swclk $swclk_num -chip 0 eval adapter gpio swdio $swdio_num -chip 0 } lappend _telnet_autocomplete_skip bcm2835gpio_swclk_num proc bcm2835gpio_swclk_num args { eval bcm2835_gpio_helper swclk $args } lappend _telnet_autocomplete_skip bcm2835gpio_swdio_num proc bcm2835gpio_swdio_num args { eval bcm2835_gpio_helper swdio $args } lappend _telnet_autocomplete_skip bcm2835gpio_swdio_dir_num proc bcm2835gpio_swdio_dir_num args { eval bcm2835_gpio_helper swdio_dir $args } lappend _telnet_autocomplete_skip bcm2835gpio_srst_num proc bcm2835gpio_srst_num args { eval bcm2835_gpio_helper srst $args } lappend _telnet_autocomplete_skip bcm2835gpio_trst_num proc bcm2835gpio_trst_num args { eval bcm2835_gpio_helper trst $args } lappend _telnet_autocomplete_skip "bcm2835gpio jtag_nums" proc "bcm2835gpio jtag_nums" {tck_num tms_num tdi_num tdo_num} { echo "DEPRECATED! use 'adapter gpio tck; adapter gpio tms; adapter gpio tdi; adapter gpio tdo' not 'bcm2835gpio jtag_nums'" eval adapter gpio tck $tck_num -chip 0 eval adapter gpio tms $tms_num -chip 0 eval adapter gpio tdi $tdi_num -chip 0 eval adapter gpio tdo $tdo_num -chip 0 } lappend _telnet_autocomplete_skip "bcm2835gpio tck_num" proc "bcm2835gpio tck_num" args { eval bcm2835_gpio_helper tck $args } lappend _telnet_autocomplete_skip "bcm2835gpio tms_num" proc "bcm2835gpio tms_num" args { eval bcm2835_gpio_helper tms $args } lappend _telnet_autocomplete_skip "bcm2835gpio tdo_num" proc "bcm2835gpio tdo_num" args { eval bcm2835_gpio_helper tdo $args } lappend _telnet_autocomplete_skip "bcm2835gpio tdi_num" proc "bcm2835gpio tdi_num" args { eval bcm2835_gpio_helper tdi $args } lappend _telnet_autocomplete_skip "bcm2835gpio swd_nums" proc "bcm2835gpio swd_nums" {swclk_num swdio_num} { echo "DEPRECATED! use 'adapter gpio swclk; adapter gpio swdio' not 'bcm2835gpio swd_nums'" eval adapter gpio swclk $swclk_num -chip 0 eval adapter gpio swdio $swdio_num -chip 0 } lappend _telnet_autocomplete_skip "bcm2835gpio swclk_num" proc "bcm2835gpio swclk_num" args { eval bcm2835_gpio_helper swclk $args } lappend _telnet_autocomplete_skip "bcm2835gpio swdio_num" proc "bcm2835gpio swdio_num" args { eval bcm2835_gpio_helper swdio $args } lappend _telnet_autocomplete_skip "bcm2835gpio swdio_dir_num" proc "bcm2835gpio swdio_dir_num" args { eval bcm2835_gpio_helper swdio_dir $args } lappend _telnet_autocomplete_skip "bcm2835gpio srst_num" proc "bcm2835gpio srst_num" args { eval bcm2835_gpio_helper srst $args } lappend _telnet_autocomplete_skip "bcm2835gpio trst_num" proc "bcm2835gpio trst_num" args { eval bcm2835_gpio_helper trst $args } lappend _telnet_autocomplete_skip bcm2835gpio_speed_coeffs proc bcm2835gpio_speed_coeffs args { echo "DEPRECATED! use 'bcm2835gpio speed_coeffs' not 'bcm2835gpio_speed_coeffs'" eval bcm2835gpio speed_coeffs $args } lappend _telnet_autocomplete_skip bcm2835gpio_peripheral_base proc bcm2835gpio_peripheral_base args { echo "DEPRECATED! use 'bcm2835gpio peripheral_base' not 'bcm2835gpio_peripheral_base'" eval bcm2835gpio peripheral_base $args } lappend _telnet_autocomplete_skip linuxgpiod_jtag_nums proc linuxgpiod_jtag_nums args { eval adapter_gpio_jtag_nums $args } lappend _telnet_autocomplete_skip linuxgpiod_tck_num proc linuxgpiod_tck_num args { eval adapter_gpio_helper tck $args } lappend _telnet_autocomplete_skip linuxgpiod_tms_num proc linuxgpiod_tms_num args { eval adapter_gpio_helper tms $args } lappend _telnet_autocomplete_skip linuxgpiod_tdo_num proc linuxgpiod_tdo_num args { eval adapter_gpio_helper tdo $args } lappend _telnet_autocomplete_skip linuxgpiod_tdi_num proc linuxgpiod_tdi_num args { eval adapter_gpio_helper tdi $args } lappend _telnet_autocomplete_skip linuxgpiod_srst_num proc linuxgpiod_srst_num args { eval adapter_gpio_helper srst $args } lappend _telnet_autocomplete_skip linuxgpiod_trst_num proc linuxgpiod_trst_num args { eval adapter_gpio_helper trst $args } lappend _telnet_autocomplete_skip linuxgpiod_swd_nums proc linuxgpiod_swd_nums args { eval adapter_gpio_swd_nums $args } lappend _telnet_autocomplete_skip linuxgpiod_swclk_num proc linuxgpiod_swclk_num args { eval adapter_gpio_helper swclk $args } lappend _telnet_autocomplete_skip linuxgpiod_swdio_num proc linuxgpiod_swdio_num args { eval adapter_gpio_helper swdio $args } lappend _telnet_autocomplete_skip linuxgpiod_led_num proc linuxgpiod_led_num args { eval adapter_gpio_helper led $args } lappend _telnet_autocomplete_skip linuxgpiod_gpiochip proc linuxgpiod_gpiochip args { echo "DEPRECATED! use 'adapter <signal_name> -chip' not 'linuxgpiod_gpiochip'" switch [llength $args] { 0 { } 1 { foreach sig_name {tck tms tdi tdo trst srst swclk swdio swdio_dir led} { eval adapter gpio $sig_name -chip $args } } default {return -code 1 -level 1 "linuxgpiod_gpiochip: syntax error"} } eval adapter gpio } lappend _telnet_autocomplete_skip sysfsgpio_jtag_nums proc sysfsgpio_jtag_nums args { echo "DEPRECATED! use 'sysfsgpio jtag_nums' not 'sysfsgpio_jtag_nums'" eval sysfsgpio jtag_nums $args } lappend _telnet_autocomplete_skip sysfsgpio_tck_num proc sysfsgpio_tck_num args { echo "DEPRECATED! use 'sysfsgpio tck_num' not 'sysfsgpio_tck_num'" eval sysfsgpio tck_num $args } lappend _telnet_autocomplete_skip sysfsgpio_tms_num proc sysfsgpio_tms_num args { echo "DEPRECATED! use 'sysfsgpio tms_num' not 'sysfsgpio_tms_num'" eval sysfsgpio tms_num $args } lappend _telnet_autocomplete_skip sysfsgpio_tdo_num proc sysfsgpio_tdo_num args { echo "DEPRECATED! use 'sysfsgpio tdo_num' not 'sysfsgpio_tdo_num'" eval sysfsgpio tdo_num $args } lappend _telnet_autocomplete_skip sysfsgpio_tdi_num proc sysfsgpio_tdi_num args { echo "DEPRECATED! use 'sysfsgpio tdi_num' not 'sysfsgpio_tdi_num'" eval sysfsgpio tdi_num $args } lappend _telnet_autocomplete_skip sysfsgpio_srst_num proc sysfsgpio_srst_num args { echo "DEPRECATED! use 'sysfsgpio srst_num' not 'sysfsgpio_srst_num'" eval sysfsgpio srst_num $args } lappend _telnet_autocomplete_skip sysfsgpio_trst_num proc sysfsgpio_trst_num args { echo "DEPRECATED! use 'sysfsgpio trst_num' not 'sysfsgpio_trst_num'" eval sysfsgpio trst_num $args } lappend _telnet_autocomplete_skip sysfsgpio_swd_nums proc sysfsgpio_swd_nums args { echo "DEPRECATED! use 'sysfsgpio swd_nums' not 'sysfsgpio_swd_nums'" eval sysfsgpio swd_nums $args } lappend _telnet_autocomplete_skip sysfsgpio_swclk_num proc sysfsgpio_swclk_num args { echo "DEPRECATED! use 'sysfsgpio swclk_num' not 'sysfsgpio_swclk_num'" eval sysfsgpio swclk_num $args } lappend _telnet_autocomplete_skip sysfsgpio_swdio_num proc sysfsgpio_swdio_num args { echo "DEPRECATED! use 'sysfsgpio swdio_num' not 'sysfsgpio_swdio_num'" eval sysfsgpio swdio_num $args } lappend _telnet_autocomplete_skip buspirate_adc proc buspirate_adc args { echo "DEPRECATED! use 'buspirate adc' not 'buspirate_adc'" eval buspirate adc $args } lappend _telnet_autocomplete_skip buspirate_vreg proc buspirate_vreg args { echo "DEPRECATED! use 'buspirate vreg' not 'buspirate_vreg'" eval buspirate vreg $args } lappend _telnet_autocomplete_skip buspirate_pullup proc buspirate_pullup args { echo "DEPRECATED! use 'buspirate pullup' not 'buspirate_pullup'" eval buspirate pullup $args } lappend _telnet_autocomplete_skip buspirate_led proc buspirate_led args { echo "DEPRECATED! use 'buspirate led' not 'buspirate_led'" eval buspirate led $args } lappend _telnet_autocomplete_skip buspirate_speed proc buspirate_speed args { echo "DEPRECATED! use 'buspirate speed' not 'buspirate_speed'" eval buspirate speed $args } lappend _telnet_autocomplete_skip buspirate_mode proc buspirate_mode args { echo "DEPRECATED! use 'buspirate mode' not 'buspirate_mode'" eval buspirate mode $args } lappend _telnet_autocomplete_skip buspirate_port proc buspirate_port args { echo "DEPRECATED! use 'buspirate port' not 'buspirate_port'" eval buspirate port $args } lappend _telnet_autocomplete_skip usb_blaster_device_desc proc usb_blaster_device_desc args { echo "DEPRECATED! use 'usb_blaster device_desc' not 'usb_blaster_device_desc'" eval usb_blaster device_desc $args } lappend _telnet_autocomplete_skip usb_blaster_vid_pid proc usb_blaster_vid_pid args { echo "DEPRECATED! use 'usb_blaster vid_pid' not 'usb_blaster_vid_pid'" eval usb_blaster vid_pid $args } lappend _telnet_autocomplete_skip usb_blaster_lowlevel_driver proc usb_blaster_lowlevel_driver args { echo "DEPRECATED! use 'usb_blaster lowlevel_driver' not 'usb_blaster_lowlevel_driver'" eval usb_blaster lowlevel_driver $args } lappend _telnet_autocomplete_skip usb_blaster_pin proc usb_blaster_pin args { echo "DEPRECATED! use 'usb_blaster pin' not 'usb_blaster_pin'" eval usb_blaster pin $args } lappend _telnet_autocomplete_skip usb_blaster_firmware proc usb_blaster_firmware args { echo "DEPRECATED! use 'usb_blaster firmware' not 'usb_blaster_firmware'" eval usb_blaster firmware $args } lappend _telnet_autocomplete_skip ft232r_serial_desc proc ft232r_serial_desc args { echo "DEPRECATED! use 'adapter serial_desc' not 'ft232r_serial_desc'" eval adapter serial_desc $args } lappend _telnet_autocomplete_skip ft232r_vid_pid proc ft232r_vid_pid args { echo "DEPRECATED! use 'ft232r vid_pid' not 'ft232r_vid_pid'" eval ft232r vid_pid $args } lappend _telnet_autocomplete_skip ft232r_jtag_nums proc ft232r_jtag_nums args { echo "DEPRECATED! use 'ft232r jtag_nums' not 'ft232r_jtag_nums'" eval ft232r jtag_nums $args } lappend _telnet_autocomplete_skip ft232r_tck_num proc ft232r_tck_num args { echo "DEPRECATED! use 'ft232r tck_num' not 'ft232r_tck_num'" eval ft232r tck_num $args } lappend _telnet_autocomplete_skip ft232r_tms_num proc ft232r_tms_num args { echo "DEPRECATED! use 'ft232r tms_num' not 'ft232r_tms_num'" eval ft232r tms_num $args } lappend _telnet_autocomplete_skip ft232r_tdo_num proc ft232r_tdo_num args { echo "DEPRECATED! use 'ft232r tdo_num' not 'ft232r_tdo_num'" eval ft232r tdo_num $args } lappend _telnet_autocomplete_skip ft232r_tdi_num proc ft232r_tdi_num args { echo "DEPRECATED! use 'ft232r tdi_num' not 'ft232r_tdi_num'" eval ft232r tdi_num $args } lappend _telnet_autocomplete_skip ft232r_srst_num proc ft232r_srst_num args { echo "DEPRECATED! use 'ft232r srst_num' not 'ft232r_srst_num'" eval ft232r srst_num $args } lappend _telnet_autocomplete_skip ft232r_trst_num proc ft232r_trst_num args { echo "DEPRECATED! use 'ft232r trst_num' not 'ft232r_trst_num'" eval ft232r trst_num $args } lappend _telnet_autocomplete_skip ft232r_restore_serial proc ft232r_restore_serial args { echo "DEPRECATED! use 'ft232r restore_serial' not 'ft232r_restore_serial'" eval ft232r restore_serial $args } lappend _telnet_autocomplete_skip cmsis_dap_serial proc cmsis_dap_serial args { echo "DEPRECATED! use 'adapter serial' not 'cmsis_dap_serial'" eval adapter serial $args } lappend _telnet_autocomplete_skip "ft232r serial_desc" proc "ft232r serial_desc" {args} { echo "DEPRECATED! use 'adapter serial' not 'ft232r serial_desc'" eval adapter serial $args } lappend _telnet_autocomplete_skip "ftdi serial" proc "ftdi serial" {args} { echo "DEPRECATED! use 'adapter serial' not 'ftdi serial'" eval adapter serial $args } lappend _telnet_autocomplete_skip hla_serial proc hla_serial args { echo "DEPRECATED! use 'adapter serial' not 'hla_serial'" eval adapter serial $args } lappend _telnet_autocomplete_skip "jlink serial" proc "jlink serial" {args} { echo "DEPRECATED! use 'adapter serial' not 'jlink serial'" eval adapter serial $args } lappend _telnet_autocomplete_skip kitprog_serial proc kitprog_serial args { echo "DEPRECATED! use 'adapter serial' not 'kitprog_serial'" eval adapter serial $args } lappend _telnet_autocomplete_skip "presto serial" proc "presto serial" {args} { echo "DEPRECATED! use 'adapter serial' not 'presto serial'" eval adapter serial $args } lappend _telnet_autocomplete_skip "st-link serial" proc "st-link serial" {args} { echo "DEPRECATED! use 'adapter serial' not 'st-link serial'" eval adapter serial $args } lappend _telnet_autocomplete_skip "vsllink usb_serial" proc "vsllink usb_serial" {args} { echo "DEPRECATED! use 'adapter serial' not 'vsllink usb_serial'" eval adapter serial $args } lappend _telnet_autocomplete_skip "xds110 serial" proc "xds110 serial" {args} { echo "DEPRECATED! use 'adapter serial' not 'xds110 serial'" eval adapter serial $args } lappend _telnet_autocomplete_skip linuxgpiod # linuxgpiod command completely removed, this is required for the sub-commands to work proc linuxgpiod {subcommand args} { eval {"linuxgpiod $subcommand"} $args } lappend _telnet_autocomplete_skip "linuxgpiod tck_num" proc "linuxgpiod tck_num" {args} { eval adapter_gpio_helper tck $args } lappend _telnet_autocomplete_skip "linuxgpiod tms_num" proc "linuxgpiod tms_num" {args} { eval adapter_gpio_helper tms $args } lappend _telnet_autocomplete_skip "linuxgpiod tdi_num" proc "linuxgpiod tdi_num" {args} { eval adapter_gpio_helper tdi $args } lappend _telnet_autocomplete_skip "linuxgpiod tdo_num" proc "linuxgpiod tdo_num" {args} { eval adapter_gpio_helper tdo $args } lappend _telnet_autocomplete_skip "linuxgpiod trst_num" proc "linuxgpiod trst_num" {args} { eval adapter_gpio_helper trst $args } lappend _telnet_autocomplete_skip "linuxgpiod srst_num" proc "linuxgpiod srst_num" {args} { eval adapter_gpio_helper srst $args } lappend _telnet_autocomplete_skip "linuxgpiod swclk_num" proc "linuxgpiod swclk_num" {args} { eval adapter_gpio_helper swclk $args } lappend _telnet_autocomplete_skip "linuxgpiod swdio_num" proc "linuxgpiod swdio_num" {args} { eval adapter_gpio_helper swdio $args } lappend _telnet_autocomplete_skip "linuxgpiod swdio_dir_num" proc "linuxgpiod swdio_dir_num" {args} { eval adapter_gpio_helper swdio_dir $args } lappend _telnet_autocomplete_skip "linuxgpiod led_num" proc "linuxgpiod led_num" {args} { eval adapter_gpio_helper led $args } lappend _telnet_autocomplete_skip "linuxgpiod gpiochip" proc "linuxgpiod gpiochip" {num} { echo "DEPRECATED! use 'adapter <signal_name> -chip' not 'linuxgpiod gpiochip'" foreach sig_name {tck tms tdi tdo trst srst swclk swdio swdio_dir led} { eval adapter gpio $sig_name -chip $num } eval adapter gpio } lappend _telnet_autocomplete_skip "linuxgpiod jtag_nums" proc "linuxgpiod jtag_nums" {tck_num tms_num tdi_num tdo_num} { echo "DEPRECATED! use 'adapter gpio tck; adapter gpio tms; adapter gpio tdi; adapter gpio tdo' not 'linuxgpiod jtag_nums'" eval adapter gpio tck $tck_num eval adapter gpio tms $tms_num eval adapter gpio tdi $tdi_num eval adapter gpio tdo $tdo_num } lappend _telnet_autocomplete_skip "linuxgpiod swd_nums" proc "linuxgpiod swd_nums" {swclk swdio} { echo "DEPRECATED! use 'adapter gpio swclk; adapter gpio swdio' not 'linuxgpiod jtag_nums'" eval adapter gpio swclk $swclk eval adapter gpio swdio $swdio } lappend _telnet_autocomplete_skip "am335xgpio jtag_nums" proc "am335xgpio jtag_nums" {tck_num tms_num tdi_num tdo_num} { echo "DEPRECATED! use 'adapter gpio tck; adapter gpio tms; adapter gpio tdi; adapter gpio tdo' not 'am335xgpio jtag_nums'" eval adapter gpio tck [expr {$tck_num % 32}] -chip [expr {$tck_num / 32}] eval adapter gpio tms [expr {$tms_num % 32}] -chip [expr {$tms_num / 32}] eval adapter gpio tdi [expr {$tdi_num % 32}] -chip [expr {$tdi_num / 32}] eval adapter gpio tdo [expr {$tdo_num % 32}] -chip [expr {$tdo_num / 32}] } lappend _telnet_autocomplete_skip "am335xgpio tck_num" proc "am335xgpio tck_num" {num} { echo "DEPRECATED! use 'adapter gpio tck' not 'am335xgpio tck_num'" eval adapter gpio tck [expr {$num % 32}] -chip [expr {$num / 32}] } lappend _telnet_autocomplete_skip "am335xgpio tms_num" proc "am335xgpio tms_num" {num} { echo "DEPRECATED! use 'adapter gpio tms' not 'am335xgpio tms_num'" eval adapter gpio tms [expr {$num % 32}] -chip [expr {$num / 32}] } lappend _telnet_autocomplete_skip "am335xgpio tdi_num" proc "am335xgpio tdi_num" {num} { echo "DEPRECATED! use 'adapter gpio tdi' not 'am335xgpio tdi_num'" eval adapter gpio tdi [expr {$num % 32}] -chip [expr {$num / 32}] } lappend _telnet_autocomplete_skip "am335xgpio tdo_num" proc "am335xgpio tdo_num" {num} { echo "DEPRECATED! use 'adapter gpio tdo' not 'am335xgpio tdo_num'" eval adapter gpio tdo [expr {$num % 32}] -chip [expr {$num / 32}] } lappend _telnet_autocomplete_skip "am335xgpio swd_nums" proc "am335xgpio swd_nums" {swclk swdio} { echo "DEPRECATED! use 'adapter gpio swclk; adapter gpio swdio' not 'am335xgpio jtag_nums'" eval adapter gpio swclk [expr {$swclk % 32}] -chip [expr {$swclk / 32}] eval adapter gpio swdio [expr {$swdio % 32}] -chip [expr {$swdio / 32}] } lappend _telnet_autocomplete_skip "am335xgpio swclk_num" proc "am335xgpio swclk_num" {num} { echo "DEPRECATED! use 'adapter gpio swclk' not 'am335xgpio swclk_num'" eval adapter gpio swclk [expr {$num % 32}] -chip [expr {$num / 32}] } lappend _telnet_autocomplete_skip "am335xgpio swdio_num" proc "am335xgpio swdio_num" {num} { echo "DEPRECATED! use 'adapter gpio swdio' not 'am335xgpio swdio_num'" eval adapter gpio swdio [expr {$num % 32}] -chip [expr {$num / 32}] } lappend _telnet_autocomplete_skip "am335xgpio swdio_dir_num" proc "am335xgpio swdio_dir_num" {num} { echo "DEPRECATED! use 'adapter gpio swdio_dir' not 'am335xgpio swdio_dir_num'" eval adapter gpio swdio_dir [expr {$num % 32}] -chip [expr {$num / 32}] } lappend _telnet_autocomplete_skip "am335xgpio swdio_dir_output_state" proc "am335xgpio swdio_dir_output_state" {state} { echo "DEPRECATED! use 'adapter gpio swdio_dir -active-high' or 'adapter gpio swdio_dir -active-low', not 'am335xgpio swdio_dir_output_state'" switch $state { "high" {eval adapter gpio swdio_dir -active-high} "low" {eval adapter gpio swdio_dir -active-low} default {return -code 1 -level 1 "am335xgpio swdio_dir_output_state: syntax error"} } } lappend _telnet_autocomplete_skip "am335xgpio srst_num" proc "am335xgpio srst_num" {num} { echo "DEPRECATED! use 'adapter gpio srst' not 'am335xgpio srst_num'" eval adapter gpio srst [expr {$num % 32}] -chip [expr {$num / 32}] } lappend _telnet_autocomplete_skip "am335xgpio trst_num" proc "am335xgpio trst_num" {num} { echo "DEPRECATED! use 'adapter gpio trst' not 'am335xgpio trst_num'" eval adapter gpio trst [expr {$num % 32}] -chip [expr {$num / 32}] } lappend _telnet_autocomplete_skip "am335xgpio led_num" proc "am335xgpio led_num" {num} { echo "DEPRECATED! use 'adapter gpio led' not 'am335xgpio led_num'" eval adapter gpio led [expr {$num % 32}] -chip [expr {$num / 32}] } lappend _telnet_autocomplete_skip "am335xgpio led_on_state" proc "am335xgpio led_on_state" {state} { echo "DEPRECATED! use 'adapter gpio led -active-high' or 'adapter gpio led -active-low', not 'am335xgpio led_on_state'" switch $state { "high" {eval adapter gpio led -active-high} "low" {eval adapter gpio led -active-low} default {return -code 1 -level 1 "am335xgpio led_on_state: syntax error"} } } lappend _telnet_autocomplete_skip "pld device" proc "pld device" {driver tap_name {opt 0}} { echo "DEPRECATED! use 'pld create ...', not 'pld device ...'" if {[string is integer -strict $opt]} { if {$opt == 0} { eval pld create [lindex [split $tap_name .] 0].pld $driver -chain-position $tap_name } else { eval pld create [lindex [split $tap_name .] 0].pld $driver -chain-position $tap_name -no_jstart } } else { eval pld create [lindex [split $tap_name .] 0].pld $driver -chain-position $tap_name -family $opt } } # END MIGRATION AIDS ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/swd.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009-2010 by David Brownell * ***************************************************************************/ #ifndef OPENOCD_JTAG_SWD_H #define OPENOCD_JTAG_SWD_H #include <helper/log.h> #include <target/arm_adi_v5.h> /* Bits in SWD command packets, written from host to target * first bit on the wire is START */ #define SWD_CMD_START (1 << 0) /* always set */ #define SWD_CMD_APNDP (1 << 1) /* set only for AP access */ #define SWD_CMD_RNW (1 << 2) /* set only for read access */ #define SWD_CMD_A32 (3 << 3) /* bits A[3:2] of register addr */ #define SWD_CMD_PARITY (1 << 5) /* parity of APnDP|RnW|A32 */ #define SWD_CMD_STOP (0 << 6) /* always clear for synch SWD */ #define SWD_CMD_PARK (1 << 7) /* driven high by host */ /* followed by TRN, 3-bits of ACK, TRN */ /* * The SWD subsystem error codes */ #define ERROR_SWD_FAIL (-400) /** protocol or parity error */ #define ERROR_SWD_FAULT (-401) /** device returned FAULT in ACK field */ /** * Construct a "cmd" byte, in lSB bit order, which swd_driver.read_reg() * and swd_driver.write_reg() methods will use directly. */ static inline uint8_t swd_cmd(bool is_read, bool is_ap, uint8_t regnum) { uint8_t cmd = (is_ap ? SWD_CMD_APNDP : 0) | (is_read ? SWD_CMD_RNW : 0) | ((regnum & 0xc) << 1); /* 8 cmd bits 4:1 may be set */ if (parity_u32(cmd)) cmd |= SWD_CMD_PARITY; /* driver handles START, STOP, and TRN */ return cmd; } /* SWD_ACK_* bits are defined in <target/arm_adi_v5.h> */ /** * Test if we can rely on ACK returned by SWD command * * @param cmd Byte constructed by swd_cmd(), START, STOP and TRN are filtered off * @returns true if ACK should be checked, false if should be ignored */ static inline bool swd_cmd_returns_ack(uint8_t cmd) { uint8_t base_cmd = cmd & (SWD_CMD_APNDP | SWD_CMD_RNW | SWD_CMD_A32); /* DPv2 does not reply to DP_TARGETSEL write cmd */ return base_cmd != swd_cmd(false, false, DP_TARGETSEL); } /** * Convert SWD ACK value returned from DP to OpenOCD error code * * @param ack * @returns error code */ static inline int swd_ack_to_error_code(uint8_t ack) { switch (ack) { case SWD_ACK_OK: return ERROR_OK; case SWD_ACK_WAIT: return ERROR_WAIT; case SWD_ACK_FAULT: return ERROR_SWD_FAULT; default: return ERROR_SWD_FAIL; } } /* * The following sequences are updated to * ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031E */ /** * SWD Line reset. * * SWD Line reset is at least 50 SWCLK cycles with SWDIO driven high, * followed by at least two idle (low) cycle. * Bits are stored (and transmitted) LSB-first. */ static const uint8_t swd_seq_line_reset[] = { /* At least 50 SWCLK cycles with SWDIO high */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* At least 2 idle (low) cycles */ 0x00, }; static const unsigned swd_seq_line_reset_len = 64; /** * JTAG-to-SWD sequence. * * The JTAG-to-SWD sequence is at least 50 TCK/SWCLK cycles with TMS/SWDIO * high, putting either interface logic into reset state, followed by a * specific 16-bit sequence and finally a line reset in case the SWJ-DP was * already in SWD mode. * Bits are stored (and transmitted) LSB-first. */ static const uint8_t swd_seq_jtag_to_swd[] = { /* At least 50 TCK/SWCLK cycles with TMS/SWDIO high */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Switching sequence from JTAG to SWD */ 0x9e, 0xe7, /* At least 50 TCK/SWCLK cycles with TMS/SWDIO high */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* At least 2 idle (low) cycles */ 0x00, }; static const unsigned swd_seq_jtag_to_swd_len = 136; /** * SWD-to-JTAG sequence. * * The SWD-to-JTAG sequence is at least 50 TCK/SWCLK cycles with TMS/SWDIO * high, putting either interface logic into reset state, followed by a * specific 16-bit sequence and finally at least 5 TCK/SWCLK cycles with * TMS/SWDIO high to put the JTAG TAP in Test-Logic-Reset state. * Bits are stored (and transmitted) LSB-first. */ static const uint8_t swd_seq_swd_to_jtag[] = { /* At least 50 TCK/SWCLK cycles with TMS/SWDIO high */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Switching sequence from SWD to JTAG */ 0x3c, 0xe7, /* At least 5 TCK/SWCLK cycles with TMS/SWDIO high */ 0xff, }; static const unsigned swd_seq_swd_to_jtag_len = 80; /** * SWD-to-dormant sequence. * * This is at least 50 SWCLK cycles with SWDIO high to put the interface * in reset state, followed by a specific 16-bit sequence. * Bits are stored (and transmitted) LSB-first. */ static const uint8_t swd_seq_swd_to_dormant[] = { /* At least 50 SWCLK cycles with SWDIO high */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Switching sequence from SWD to dormant */ 0xbc, 0xe3, }; static const unsigned swd_seq_swd_to_dormant_len = 72; /** * Dormant-to-SWD sequence. * * This is at least 8 TCK/SWCLK cycles with TMS/SWDIO high to abort any ongoing * selection alert sequence, followed by a specific 128-bit selection alert * sequence, followed by 4 TCK/SWCLK cycles with TMS/SWDIO low, followed by * a specific protocol-dependent activation code. For SWD the activation code * is an 8-bit sequence. The sequence ends with a line reset. * Bits are stored (and transmitted) LSB-first. */ static const uint8_t swd_seq_dormant_to_swd[] = { /* At least 8 SWCLK cycles with SWDIO high */ 0xff, /* Selection alert sequence */ 0x92, 0xf3, 0x09, 0x62, 0x95, 0x2d, 0x85, 0x86, 0xe9, 0xaf, 0xdd, 0xe3, 0xa2, 0x0e, 0xbc, 0x19, /* * 4 SWCLK cycles with SWDIO low ... * + SWD activation code 0x1a ... * + at least 8 SWCLK cycles with SWDIO high */ 0xa0, /* ((0x00) & GENMASK(3, 0)) | ((0x1a << 4) & GENMASK(7, 4)) */ 0xf1, /* ((0x1a >> 4) & GENMASK(3, 0)) | ((0xff << 4) & GENMASK(7, 4)) */ 0xff, /* At least 50 SWCLK cycles with SWDIO high */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* At least 2 idle (low) cycles */ 0x00, }; static const unsigned swd_seq_dormant_to_swd_len = 224; /** * JTAG-to-dormant sequence. * * This is at least 5 TCK cycles with TMS high to put the interface * in test-logic-reset state, followed by a specific 31-bit sequence. * Bits are stored (and transmitted) LSB-first. */ static const uint8_t swd_seq_jtag_to_dormant[] = { /* At least 5 TCK cycles with TMS high */ 0xff, /* * Still one TCK cycle with TMS high followed by 31 bits JTAG-to-DS * select sequence 0xba, 0xbb, 0xbb, 0x33, */ 0x75, /* ((0xff >> 7) & GENMASK(0, 0)) | ((0xba << 1) & GENMASK(7, 1)) */ 0x77, /* ((0xba >> 7) & GENMASK(0, 0)) | ((0xbb << 1) & GENMASK(7, 1)) */ 0x77, /* ((0xbb >> 7) & GENMASK(0, 0)) | ((0xbb << 1) & GENMASK(7, 1)) */ 0x67, /* ((0xbb >> 7) & GENMASK(0, 0)) | ((0x33 << 1) & GENMASK(7, 1)) */ }; static const unsigned swd_seq_jtag_to_dormant_len = 40; /** * Dormant-to-JTAG sequence. * * This is at least 8 TCK/SWCLK cycles with TMS/SWDIO high to abort any ongoing * selection alert sequence, followed by a specific 128-bit selection alert * sequence, followed by 4 TCK/SWCLK cycles with TMS/SWDIO low, followed by * a specific protocol-dependent activation code. For JTAG there are two * possible activation codes: * - "JTAG-Serial": 12 bits 0x00, 0x00 * - "Arm CoreSight JTAG-DP": 8 bits 0x0a * We use "JTAG-Serial" only, which seams more generic. * Since the target TAP can be either in Run/Test Idle or in Test-Logic-Reset * states, Arm recommends to put the TAP in Run/Test Idle using one TCK cycle * with TMS low. To keep the sequence length multiple of 8, 8 TCK cycle with * TMS low are sent (allowed by JTAG state machine). * Bits are stored (and transmitted) LSB-first. */ static const uint8_t swd_seq_dormant_to_jtag[] = { /* At least 8 TCK/SWCLK cycles with TMS/SWDIO high */ 0xff, /* Selection alert sequence */ 0x92, 0xf3, 0x09, 0x62, 0x95, 0x2d, 0x85, 0x86, 0xe9, 0xaf, 0xdd, 0xe3, 0xa2, 0x0e, 0xbc, 0x19, /* * 4 TCK/SWCLK cycles with TMS/SWDIO low ... * + 12 bits JTAG-serial activation code 0x00, 0x00 */ 0x00, 0x00, /* put the TAP in Run/Test Idle */ 0x00, }; static const unsigned swd_seq_dormant_to_jtag_len = 160; struct swd_driver { /** * Initialize the debug link so it can perform SWD operations. * * As an example, this would switch a dual-mode debug adapter * into SWD mode and out of JTAG mode. * * @return ERROR_OK on success, else a negative fault code. */ int (*init)(void); /** * Queue a special SWDIO sequence. * * @param seq The special sequence to generate. * @return ERROR_OK if the sequence was queued, negative error if the * sequence is unsupported. */ int (*switch_seq)(enum swd_special_seq seq); /** * Queued read of an AP or DP register. * * @param Command byte with APnDP/RnW/addr/parity bits * @param Where to store value to read from register * @param ap_delay_hint Number of idle cycles that may be * needed after an AP access to avoid WAITs */ void (*read_reg)(uint8_t cmd, uint32_t *value, uint32_t ap_delay_hint); /** * Queued write of an AP or DP register. * * @param Command byte with APnDP/RnW/addr/parity bits * @param Value to be written to the register * @param ap_delay_hint Number of idle cycles that may be * needed after an AP access to avoid WAITs */ void (*write_reg)(uint8_t cmd, uint32_t value, uint32_t ap_delay_hint); /** * Execute any queued transactions and collect the result. * * @return ERROR_OK on success, Ack response code on WAIT/FAULT * or negative error code on other kinds of failure. */ int (*run)(void); /** * Configures data collection from the Single-wire * trace (SWO) signal. * @param swo true if SWO data collection should be routed. * * For example, some debug adapters include a UART which * is normally connected to a microcontroller's UART TX, * but which may instead be connected to SWO for use in * collecting ITM (and possibly ETM) trace data. * * @return ERROR_OK on success, else a negative fault code. */ int *(*trace)(bool swo); }; int swd_init_reset(struct command_context *cmd_ctx); #endif /* OPENOCD_JTAG_SWD_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/swim.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2020 by Antonio Borneo <borneo.antonio@gmail.com * * SWIM (Single Wire Interface Module) is a low-pin-count debug protocol * used by STMicroelectronics MCU family STM8 and documented in UM470 * https://www.st.com/resource/en/user_manual/cd00173911.pdf */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "interface.h" #include "swim.h" #include <helper/command.h> #include <transport/transport.h> extern struct adapter_driver *adapter_driver; int swim_system_reset(void) { assert(adapter_driver->swim_ops); return adapter_driver->swim_ops->srst(); } int swim_read_mem(uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer) { assert(adapter_driver->swim_ops); return adapter_driver->swim_ops->read_mem(addr, size, count, buffer); } int swim_write_mem(uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer) { assert(adapter_driver->swim_ops); return adapter_driver->swim_ops->write_mem(addr, size, count, buffer); } int swim_reconnect(void) { assert(adapter_driver->swim_ops); return adapter_driver->swim_ops->reconnect(); } COMMAND_HANDLER(handle_swim_newtap_command) { struct jtag_tap *tap; /* * only need "basename" and "tap_type", but for backward compatibility * ignore extra parameters */ if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; tap = calloc(1, sizeof(*tap)); if (!tap) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } tap->chip = strdup(CMD_ARGV[0]); tap->tapname = strdup(CMD_ARGV[1]); tap->dotted_name = alloc_printf("%s.%s", CMD_ARGV[0], CMD_ARGV[1]); if (!tap->chip || !tap->tapname || !tap->dotted_name) { LOG_ERROR("Out of memory"); free(tap->dotted_name); free(tap->tapname); free(tap->chip); free(tap); return ERROR_FAIL; } LOG_DEBUG("Creating new SWIM \"tap\", Chip: %s, Tap: %s, Dotted: %s", tap->chip, tap->tapname, tap->dotted_name); /* default is enabled-after-reset */ tap->enabled = true; jtag_tap_init(tap); return ERROR_OK; } static const struct command_registration swim_transport_subcommand_handlers[] = { { .name = "newtap", .handler = handle_swim_newtap_command, .mode = COMMAND_CONFIG, .help = "Create a new TAP instance named basename.tap_type, " "and appends it to the scan chain.", .usage = "basename tap_type", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration swim_transport_command_handlers[] = { { .name = "swim", .mode = COMMAND_ANY, .help = "perform swim adapter actions", .usage = "", .chain = swim_transport_subcommand_handlers, }, COMMAND_REGISTRATION_DONE }; static int swim_transport_select(struct command_context *cmd_ctx) { LOG_DEBUG(__func__); return register_commands(cmd_ctx, NULL, swim_transport_command_handlers); } static int swim_transport_init(struct command_context *cmd_ctx) { enum reset_types jtag_reset_config = jtag_get_reset_config(); LOG_DEBUG(__func__); if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) adapter_assert_reset(); else LOG_WARNING("\'srst_nogate\' reset_config option is required"); } else adapter_deassert_reset(); return ERROR_OK; } static struct transport swim_transport = { .name = "swim", .select = swim_transport_select, .init = swim_transport_init, }; static void swim_constructor(void) __attribute__ ((constructor)); static void swim_constructor(void) { transport_register(&swim_transport); } bool transport_is_swim(void) { return get_current_transport() == &swim_transport; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/swim.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2020 by Antonio Borneo <borneo.antonio@gmail.com */ /** * @file * This file implements support for STMicroelectronics debug protocol SWIM * (Single Wire Interface Module). */ #ifndef OPENOCD_JTAG_SWIM_H #define OPENOCD_JTAG_SWIM_H #define SWIM_FREQ_LOW 363 #define SWIM_FREQ_HIGH 800 struct swim_driver { /** * Send SRST (system reset) command to target. * * @return ERROR_OK on success, else a fault code. */ int (*srst)(void); /** * Read target memory through ROTF (read on-the-fly) command. * * @param addr Start address to read data from target memory. * @param size Size in bytes of data units, 1, 2 or 4. * @param count Number of units (size units, not bytes) to read. * @param buffer Data buffer to receive data. * @return ERROR_OK on success, else a fault code. */ int (*read_mem)(uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer); /** * Write target memory through WOTF (write on-the-fly) command. * * @param addr Start address to write data to target memory. * @param size Size in bytes of data units, 1, 2 or 4. * @param count Number of units (size units, not bytes) to write. * @param buffer Data buffer to write. * @return ERROR_OK on success, else a fault code. */ int (*write_mem)(uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer); /** * Reconnect to the target. * Should be reworked to be more generic and not linked to current * implementation in stlink driver. * * @return ERROR_OK on success, else a fault code. */ int (*reconnect)(void); }; int swim_system_reset(void); int swim_read_mem(uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer); int swim_write_mem(uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer); int swim_reconnect(void); #endif /* OPENOCD_JTAG_SWIM_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/tcl.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "adapter.h" #include "jtag.h" #include "swd.h" #include "minidriver.h" #include "interface.h" #include "interfaces.h" #include "tcl.h" #ifdef HAVE_STRINGS_H #include <strings.h> #endif #include <helper/command.h> #include <helper/nvp.h> #include <helper/time_support.h> #include "transport/transport.h" /** * @file * Holds support for accessing JTAG-specific mechanisms from TCl scripts. */ static const struct jim_nvp nvp_jtag_tap_event[] = { { .value = JTAG_TRST_ASSERTED, .name = "post-reset" }, { .value = JTAG_TAP_EVENT_SETUP, .name = "setup" }, { .value = JTAG_TAP_EVENT_ENABLE, .name = "tap-enable" }, { .value = JTAG_TAP_EVENT_DISABLE, .name = "tap-disable" }, { .name = NULL, .value = -1 } }; struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) { const char *cp = Jim_GetString(o, NULL); struct jtag_tap *t = cp ? jtag_tap_by_string(cp) : NULL; if (!cp) cp = "(unknown)"; if (!t) Jim_SetResultFormatted(interp, "Tap '%s' could not be found", cp); return t; } static bool scan_is_safe(tap_state_t state) { switch (state) { case TAP_RESET: case TAP_IDLE: case TAP_DRPAUSE: case TAP_IRPAUSE: return true; default: return false; } } static COMMAND_HELPER(handle_jtag_command_drscan_fields, struct scan_field *fields) { unsigned int field_count = 0; for (unsigned int i = 1; i < CMD_ARGC; i += 2) { unsigned int bits; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[i], bits); fields[field_count].num_bits = bits; void *t = malloc(DIV_ROUND_UP(bits, 8)); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } fields[field_count].out_value = t; str_to_buf(CMD_ARGV[i + 1], strlen(CMD_ARGV[i + 1]), t, bits, 0); fields[field_count].in_value = t; field_count++; } return ERROR_OK; } COMMAND_HANDLER(handle_jtag_command_drscan) { /* * CMD_ARGV[0] = device * CMD_ARGV[1] = num_bits * CMD_ARGV[2] = hex string * ... repeat num bits and hex string ... * * ... optionally: * CMD_ARGV[CMD_ARGC-2] = "-endstate" * CMD_ARGV[CMD_ARGC-1] = statename */ if (CMD_ARGC < 3 || (CMD_ARGC % 2) != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[0]); if (!tap) { command_print(CMD, "Tap '%s' could not be found", CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } if (tap->bypass) { command_print(CMD, "Can't execute as the selected tap is in BYPASS"); return ERROR_FAIL; } tap_state_t endstate = TAP_IDLE; if (CMD_ARGC > 3 && !strcmp("-endstate", CMD_ARGV[CMD_ARGC - 2])) { const char *state_name = CMD_ARGV[CMD_ARGC - 1]; endstate = tap_state_by_name(state_name); if (endstate < 0) { command_print(CMD, "endstate: %s invalid", state_name); return ERROR_COMMAND_ARGUMENT_INVALID; } if (!scan_is_safe(endstate)) LOG_WARNING("drscan with unsafe endstate \"%s\"", state_name); CMD_ARGC -= 2; } unsigned int num_fields = (CMD_ARGC - 1) / 2; struct scan_field *fields = calloc(num_fields, sizeof(struct scan_field)); if (!fields) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } int retval = CALL_COMMAND_HANDLER(handle_jtag_command_drscan_fields, fields); if (retval != ERROR_OK) goto fail; jtag_add_dr_scan(tap, num_fields, fields, endstate); retval = jtag_execute_queue(); if (retval != ERROR_OK) { command_print(CMD, "drscan: jtag execute failed"); goto fail; } for (unsigned int i = 0; i < num_fields; i++) { char *str = buf_to_hex_str(fields[i].in_value, fields[i].num_bits); command_print(CMD, "%s", str); free(str); } fail: for (unsigned int i = 0; i < num_fields; i++) free(fields[i].in_value); free(fields); return retval; } COMMAND_HANDLER(handle_jtag_command_pathmove) { tap_state_t states[8]; if (CMD_ARGC < 1 || CMD_ARGC > ARRAY_SIZE(states)) return ERROR_COMMAND_SYNTAX_ERROR; for (unsigned int i = 0; i < CMD_ARGC; i++) { states[i] = tap_state_by_name(CMD_ARGV[i]); if (states[i] < 0) { command_print(CMD, "endstate: %s invalid", CMD_ARGV[i]); return ERROR_COMMAND_ARGUMENT_INVALID; } } int retval = jtag_add_statemove(states[0]); if (retval == ERROR_OK) retval = jtag_execute_queue(); if (retval != ERROR_OK) { command_print(CMD, "pathmove: jtag execute failed"); return retval; } jtag_add_pathmove(CMD_ARGC - 1, states + 1); retval = jtag_execute_queue(); if (retval != ERROR_OK) { command_print(CMD, "pathmove: failed"); return retval; } return ERROR_OK; } COMMAND_HANDLER(handle_jtag_flush_count) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; int count = jtag_get_flush_queue_count(); command_print_sameline(CMD, "%d", count); return ERROR_OK; } /* REVISIT Just what about these should "move" ... ? * These registrations, into the main JTAG table? * * There's a minor compatibility issue, these all show up twice; * that's not desirable: * - jtag drscan ... NOT DOCUMENTED! * - drscan ... * * The "irscan" command (for example) doesn't show twice. */ static const struct command_registration jtag_command_handlers_to_move[] = { { .name = "drscan", .mode = COMMAND_EXEC, .handler = handle_jtag_command_drscan, .help = "Execute Data Register (DR) scan for one TAP. " "Other TAPs must be in BYPASS mode.", .usage = "tap_name (num_bits value)+ ['-endstate' state_name]", }, { .name = "flush_count", .mode = COMMAND_EXEC, .handler = handle_jtag_flush_count, .help = "Returns the number of times the JTAG queue " "has been flushed.", .usage = "", }, { .name = "pathmove", .mode = COMMAND_EXEC, .handler = handle_jtag_command_pathmove, .usage = "start_state state1 [state2 [state3 ...]]", .help = "Move JTAG state machine from current state " "(start_state) to state1, then state2, state3, etc.", }, COMMAND_REGISTRATION_DONE }; enum jtag_tap_cfg_param { JCFG_EVENT, JCFG_IDCODE, }; static struct jim_nvp nvp_config_opts[] = { { .name = "-event", .value = JCFG_EVENT }, { .name = "-idcode", .value = JCFG_IDCODE }, { .name = NULL, .value = -1 } }; static int jtag_tap_configure_event(struct jim_getopt_info *goi, struct jtag_tap *tap) { if (goi->argc == 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event <event-name> ..."); return JIM_ERR; } struct jim_nvp *n; int e = jim_getopt_nvp(goi, nvp_jtag_tap_event, &n); if (e != JIM_OK) { jim_getopt_nvp_unknown(goi, nvp_jtag_tap_event, 1); return e; } if (goi->isconfigure) { if (goi->argc != 1) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event <event-name> <event-body>"); return JIM_ERR; } } else { if (goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event <event-name>"); return JIM_ERR; } } struct jtag_tap_event_action *jteap = tap->event_action; /* replace existing event body */ bool found = false; while (jteap) { if (jteap->event == (enum jtag_event)n->value) { found = true; break; } jteap = jteap->next; } Jim_SetEmptyResult(goi->interp); if (goi->isconfigure) { if (!found) jteap = calloc(1, sizeof(*jteap)); else if (jteap->body) Jim_DecrRefCount(goi->interp, jteap->body); jteap->interp = goi->interp; jteap->event = n->value; Jim_Obj *o; jim_getopt_obj(goi, &o); jteap->body = Jim_DuplicateObj(goi->interp, o); Jim_IncrRefCount(jteap->body); if (!found) { /* add to head of event list */ jteap->next = tap->event_action; tap->event_action = jteap; } } else if (found) { jteap->interp = goi->interp; Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, jteap->body)); } return JIM_OK; } static int jtag_tap_configure_cmd(struct jim_getopt_info *goi, struct jtag_tap *tap) { /* parse config or cget options */ while (goi->argc > 0) { Jim_SetEmptyResult(goi->interp); struct jim_nvp *n; int e = jim_getopt_nvp(goi, nvp_config_opts, &n); if (e != JIM_OK) { jim_getopt_nvp_unknown(goi, nvp_config_opts, 0); return e; } switch (n->value) { case JCFG_EVENT: e = jtag_tap_configure_event(goi, tap); if (e != JIM_OK) return e; break; case JCFG_IDCODE: if (goi->isconfigure) { Jim_SetResultFormatted(goi->interp, "not settable: %s", n->name); return JIM_ERR; } else { if (goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); return JIM_ERR; } } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, tap->idcode)); break; default: Jim_SetResultFormatted(goi->interp, "unknown value: %s", n->name); return JIM_ERR; } } return JIM_OK; } #define NTAP_OPT_IRLEN 0 #define NTAP_OPT_IRMASK 1 #define NTAP_OPT_IRCAPTURE 2 #define NTAP_OPT_ENABLED 3 #define NTAP_OPT_DISABLED 4 #define NTAP_OPT_EXPECTED_ID 5 #define NTAP_OPT_VERSION 6 #define NTAP_OPT_BYPASS 7 static const struct nvp jtag_newtap_opts[] = { { .name = "-irlen", .value = NTAP_OPT_IRLEN }, { .name = "-irmask", .value = NTAP_OPT_IRMASK }, { .name = "-ircapture", .value = NTAP_OPT_IRCAPTURE }, { .name = "-enable", .value = NTAP_OPT_ENABLED }, { .name = "-disable", .value = NTAP_OPT_DISABLED }, { .name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID }, { .name = "-ignore-version", .value = NTAP_OPT_VERSION }, { .name = "-ignore-bypass", .value = NTAP_OPT_BYPASS }, { .name = NULL, .value = -1 }, }; static COMMAND_HELPER(handle_jtag_newtap_args, struct jtag_tap *tap) { /* we expect CHIP + TAP + OPTIONS */ if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; tap->chip = strdup(CMD_ARGV[0]); tap->tapname = strdup(CMD_ARGV[1]); tap->dotted_name = alloc_printf("%s.%s", CMD_ARGV[0], CMD_ARGV[1]); if (!tap->chip || !tap->tapname || !tap->dotted_name) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } CMD_ARGC -= 2; CMD_ARGV += 2; LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params", tap->chip, tap->tapname, tap->dotted_name, CMD_ARGC); /* * IEEE specifies that the two LSBs of an IR scan are 01, so make * that the default. The "-ircapture" and "-irmask" options are only * needed to cope with nonstandard TAPs, or to specify more bits. */ tap->ir_capture_mask = 0x03; tap->ir_capture_value = 0x01; while (CMD_ARGC) { const struct nvp *n = nvp_name2value(jtag_newtap_opts, CMD_ARGV[0]); CMD_ARGC--; CMD_ARGV++; switch (n->value) { case NTAP_OPT_ENABLED: tap->disabled_after_reset = false; break; case NTAP_OPT_DISABLED: tap->disabled_after_reset = true; break; case NTAP_OPT_EXPECTED_ID: if (!CMD_ARGC) return ERROR_COMMAND_ARGUMENT_INVALID; tap->expected_ids = realloc(tap->expected_ids, (tap->expected_ids_cnt + 1) * sizeof(uint32_t)); if (!tap->expected_ids) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } uint32_t id; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], id); CMD_ARGC--; CMD_ARGV++; tap->expected_ids[tap->expected_ids_cnt++] = id; break; case NTAP_OPT_IRLEN: if (!CMD_ARGC) return ERROR_COMMAND_ARGUMENT_INVALID; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tap->ir_length); CMD_ARGC--; CMD_ARGV++; if (tap->ir_length > (int)(8 * sizeof(tap->ir_capture_value))) LOG_WARNING("%s: huge IR length %d", tap->dotted_name, tap->ir_length); break; case NTAP_OPT_IRMASK: if (!CMD_ARGC) return ERROR_COMMAND_ARGUMENT_INVALID; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], tap->ir_capture_mask); CMD_ARGC--; CMD_ARGV++; if ((tap->ir_capture_mask & 3) != 3) LOG_WARNING("%s: nonstandard IR mask", tap->dotted_name); break; case NTAP_OPT_IRCAPTURE: if (!CMD_ARGC) return ERROR_COMMAND_ARGUMENT_INVALID; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], tap->ir_capture_value); CMD_ARGC--; CMD_ARGV++; if ((tap->ir_capture_value & 3) != 1) LOG_WARNING("%s: nonstandard IR value", tap->dotted_name); break; case NTAP_OPT_VERSION: tap->ignore_version = true; break; case NTAP_OPT_BYPASS: tap->ignore_bypass = true; break; default: nvp_unknown_command_print(CMD, jtag_newtap_opts, NULL, CMD_ARGV[-1]); return ERROR_COMMAND_ARGUMENT_INVALID; } } /* default is enabled-after-reset */ tap->enabled = !tap->disabled_after_reset; if (transport_is_jtag() && tap->ir_length == 0) { command_print(CMD, "newtap: %s missing IR length", tap->dotted_name); return ERROR_COMMAND_ARGUMENT_INVALID; } return ERROR_OK; } __COMMAND_HANDLER(handle_jtag_newtap) { struct jtag_tap *tap = calloc(1, sizeof(struct jtag_tap)); if (!tap) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } int retval = CALL_COMMAND_HANDLER(handle_jtag_newtap_args, tap); if (retval != ERROR_OK) { free(tap->chip); free(tap->tapname); free(tap->dotted_name); free(tap->expected_ids); free(tap); return retval; } jtag_tap_init(tap); return ERROR_OK; } static void jtag_tap_handle_event(struct jtag_tap *tap, enum jtag_event e) { struct jtag_tap_event_action *jteap; int retval; for (jteap = tap->event_action; jteap; jteap = jteap->next) { if (jteap->event != e) continue; struct jim_nvp *nvp = jim_nvp_value2name_simple(nvp_jtag_tap_event, e); LOG_DEBUG("JTAG tap: %s event: %d (%s)\n\taction: %s", tap->dotted_name, e, nvp->name, Jim_GetString(jteap->body, NULL)); retval = Jim_EvalObj(jteap->interp, jteap->body); if (retval == JIM_RETURN) retval = jteap->interp->returnCode; if (retval != JIM_OK) { Jim_MakeErrorMessage(jteap->interp); LOG_USER("%s", Jim_GetString(Jim_GetResult(jteap->interp), NULL)); continue; } switch (e) { case JTAG_TAP_EVENT_ENABLE: case JTAG_TAP_EVENT_DISABLE: /* NOTE: we currently assume the handlers * can't fail. Right here is where we should * really be verifying the scan chains ... */ tap->enabled = (e == JTAG_TAP_EVENT_ENABLE); LOG_INFO("JTAG tap: %s %s", tap->dotted_name, tap->enabled ? "enabled" : "disabled"); break; default: break; } } } COMMAND_HANDLER(handle_jtag_arp_init) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; return jtag_init_inner(CMD_CTX); } COMMAND_HANDLER(handle_jtag_arp_init_reset) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (transport_is_jtag()) return jtag_init_reset(CMD_CTX); if (transport_is_swd()) return swd_init_reset(CMD_CTX); return ERROR_OK; } static bool jtag_tap_enable(struct jtag_tap *t) { if (t->enabled) return true; jtag_tap_handle_event(t, JTAG_TAP_EVENT_ENABLE); if (!t->enabled) return false; /* FIXME add JTAG sanity checks, w/o TLR * - scan chain length grew by one (this) * - IDs and IR lengths are as expected */ jtag_call_event_callbacks(JTAG_TAP_EVENT_ENABLE); return true; } static bool jtag_tap_disable(struct jtag_tap *t) { if (!t->enabled) return true; jtag_tap_handle_event(t, JTAG_TAP_EVENT_DISABLE); if (t->enabled) return false; /* FIXME add JTAG sanity checks, w/o TLR * - scan chain length shrank by one (this) * - IDs and IR lengths are as expected */ jtag_call_event_callbacks(JTAG_TAP_EVENT_DISABLE); return true; } __COMMAND_HANDLER(handle_jtag_tap_enabler) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct jtag_tap *t = jtag_tap_by_string(CMD_ARGV[0]); if (!t) { command_print(CMD, "Tap '%s' could not be found", CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } if (strcmp(CMD_NAME, "tapisenabled") == 0) { /* do nothing, just return the value */ } else if (strcmp(CMD_NAME, "tapenable") == 0) { if (!jtag_tap_enable(t)) { command_print(CMD, "failed to enable tap %s", t->dotted_name); return ERROR_FAIL; } } else if (strcmp(CMD_NAME, "tapdisable") == 0) { if (!jtag_tap_disable(t)) { command_print(CMD, "failed to disable tap %s", t->dotted_name); return ERROR_FAIL; } } else { command_print(CMD, "command '%s' unknown", CMD_NAME); return ERROR_FAIL; } command_print(CMD, "%d", t->enabled ? 1 : 0); return ERROR_OK; } int jim_jtag_configure(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct command *c = jim_to_command(interp); const char *cmd_name = c->name; struct jim_getopt_info goi; jim_getopt_setup(&goi, interp, argc-1, argv + 1); goi.isconfigure = !strcmp(cmd_name, "configure"); if (goi.argc < 2 + goi.isconfigure) { Jim_WrongNumArgs(goi.interp, 0, NULL, "<tap_name> <attribute> ..."); return JIM_ERR; } struct jtag_tap *t; Jim_Obj *o; jim_getopt_obj(&goi, &o); t = jtag_tap_by_jim_obj(goi.interp, o); if (!t) return JIM_ERR; return jtag_tap_configure_cmd(&goi, t); } COMMAND_HANDLER(handle_jtag_names) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; for (struct jtag_tap *tap = jtag_all_taps(); tap; tap = tap->next_tap) command_print(CMD, "%s", tap->dotted_name); return ERROR_OK; } COMMAND_HANDLER(handle_jtag_init_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; static bool jtag_initialized; if (jtag_initialized) { LOG_INFO("'jtag init' has already been called"); return ERROR_OK; } jtag_initialized = true; LOG_DEBUG("Initializing jtag devices..."); return jtag_init(CMD_CTX); } static const struct command_registration jtag_subcommand_handlers[] = { { .name = "init", .mode = COMMAND_ANY, .handler = handle_jtag_init_command, .help = "initialize jtag scan chain", .usage = "" }, { .name = "arp_init", .mode = COMMAND_ANY, .handler = handle_jtag_arp_init, .help = "Validates JTAG scan chain against the list of " "declared TAPs using just the four standard JTAG " "signals.", .usage = "", }, { .name = "arp_init-reset", .mode = COMMAND_ANY, .handler = handle_jtag_arp_init_reset, .help = "Uses TRST and SRST to try resetting everything on " "the JTAG scan chain, then performs 'jtag arp_init'.", .usage = "", }, { .name = "newtap", .mode = COMMAND_CONFIG, .handler = handle_jtag_newtap, .help = "Create a new TAP instance named basename.tap_type, " "and appends it to the scan chain.", .usage = "basename tap_type '-irlen' count " "['-enable'|'-disable'] " "['-expected_id' number] " "['-ignore-version'] " "['-ignore-bypass'] " "['-ircapture' number] " "['-mask' number]", }, { .name = "tapisenabled", .mode = COMMAND_EXEC, .handler = handle_jtag_tap_enabler, .help = "Returns a Tcl boolean (0/1) indicating whether " "the TAP is enabled (1) or not (0).", .usage = "tap_name", }, { .name = "tapenable", .mode = COMMAND_EXEC, .handler = handle_jtag_tap_enabler, .help = "Try to enable the specified TAP using the " "'tap-enable' TAP event.", .usage = "tap_name", }, { .name = "tapdisable", .mode = COMMAND_EXEC, .handler = handle_jtag_tap_enabler, .help = "Try to disable the specified TAP using the " "'tap-disable' TAP event.", .usage = "tap_name", }, { .name = "configure", .mode = COMMAND_ANY, .jim_handler = jim_jtag_configure, .help = "Provide a Tcl handler for the specified " "TAP event.", .usage = "tap_name '-event' event_name handler", }, { .name = "cget", .mode = COMMAND_EXEC, .jim_handler = jim_jtag_configure, .help = "Return any Tcl handler for the specified " "TAP event.", .usage = "tap_name '-event' event_name", }, { .name = "names", .mode = COMMAND_ANY, .handler = handle_jtag_names, .help = "Returns list of all JTAG tap names.", .usage = "", }, { .chain = jtag_command_handlers_to_move, }, COMMAND_REGISTRATION_DONE }; void jtag_notify_event(enum jtag_event event) { struct jtag_tap *tap; for (tap = jtag_all_taps(); tap; tap = tap->next_tap) jtag_tap_handle_event(tap, event); } COMMAND_HANDLER(handle_scan_chain_command) { struct jtag_tap *tap; char expected_id[12]; tap = jtag_all_taps(); command_print(CMD, " TapName Enabled IdCode Expected IrLen IrCap IrMask"); command_print(CMD, "-- ------------------- -------- ---------- ---------- ----- ----- ------"); while (tap) { uint32_t expected, expected_mask, ii; snprintf(expected_id, sizeof(expected_id), "0x%08x", (unsigned)((tap->expected_ids_cnt > 0) ? tap->expected_ids[0] : 0)); if (tap->ignore_version) expected_id[2] = '*'; expected = buf_get_u32(tap->expected, 0, tap->ir_length); expected_mask = buf_get_u32(tap->expected_mask, 0, tap->ir_length); command_print(CMD, "%2d %-18s %c 0x%08x %s %5d 0x%02x 0x%02x", tap->abs_chain_position, tap->dotted_name, tap->enabled ? 'Y' : 'n', (unsigned int)(tap->idcode), expected_id, (unsigned int)(tap->ir_length), (unsigned int)(expected), (unsigned int)(expected_mask)); for (ii = 1; ii < tap->expected_ids_cnt; ii++) { snprintf(expected_id, sizeof(expected_id), "0x%08x", (unsigned) tap->expected_ids[ii]); if (tap->ignore_version) expected_id[2] = '*'; command_print(CMD, " %s", expected_id); } tap = tap->next_tap; } return ERROR_OK; } COMMAND_HANDLER(handle_jtag_ntrst_delay_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { unsigned delay; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], delay); jtag_set_ntrst_delay(delay); } command_print(CMD, "jtag_ntrst_delay: %u", jtag_get_ntrst_delay()); return ERROR_OK; } COMMAND_HANDLER(handle_jtag_ntrst_assert_width_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { unsigned delay; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], delay); jtag_set_ntrst_assert_width(delay); } command_print(CMD, "jtag_ntrst_assert_width: %u", jtag_get_ntrst_assert_width()); return ERROR_OK; } COMMAND_HANDLER(handle_jtag_rclk_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; int retval = ERROR_OK; if (CMD_ARGC == 1) { unsigned khz = 0; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], khz); retval = adapter_config_rclk(khz); if (retval != ERROR_OK) return retval; } int cur_khz = adapter_get_speed_khz(); retval = adapter_get_speed_readable(&cur_khz); if (retval != ERROR_OK) return retval; if (cur_khz) command_print(CMD, "RCLK not supported - fallback to %d kHz", cur_khz); else command_print(CMD, "RCLK - adaptive"); return retval; } COMMAND_HANDLER(handle_runtest_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; unsigned num_clocks; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num_clocks); jtag_add_runtest(num_clocks, TAP_IDLE); return jtag_execute_queue(); } /* * For "irscan" or "drscan" commands, the "end" (really, "next") state * should be stable ... and *NOT* a shift state, otherwise free-running * jtag clocks could change the values latched by the update state. * Not surprisingly, this is the same constraint as SVF; the "irscan" * and "drscan" commands are a write-only subset of what SVF provides. */ COMMAND_HANDLER(handle_irscan_command) { int i; struct scan_field *fields; struct jtag_tap *tap = NULL; tap_state_t endstate; if ((CMD_ARGC < 2) || (CMD_ARGC % 2)) return ERROR_COMMAND_SYNTAX_ERROR; /* optional "-endstate" "statename" at the end of the arguments, * so that e.g. IRPAUSE can let us load the data register before * entering RUN/IDLE to execute the instruction we load here. */ endstate = TAP_IDLE; if (CMD_ARGC >= 4) { /* have at least one pair of numbers. * is last pair the magic text? */ if (strcmp("-endstate", CMD_ARGV[CMD_ARGC - 2]) == 0) { endstate = tap_state_by_name(CMD_ARGV[CMD_ARGC - 1]); if (endstate == TAP_INVALID) return ERROR_COMMAND_SYNTAX_ERROR; if (!scan_is_safe(endstate)) LOG_WARNING("unstable irscan endstate \"%s\"", CMD_ARGV[CMD_ARGC - 1]); CMD_ARGC -= 2; } } int num_fields = CMD_ARGC / 2; if (num_fields > 1) { /* we really should be looking at plain_ir_scan if we want * anything more fancy. */ LOG_ERROR("Specify a single value for tap"); return ERROR_COMMAND_SYNTAX_ERROR; } fields = calloc(num_fields, sizeof(*fields)); int retval; for (i = 0; i < num_fields; i++) { tap = jtag_tap_by_string(CMD_ARGV[i*2]); if (!tap) { free(fields); command_print(CMD, "Tap: %s unknown", CMD_ARGV[i*2]); return ERROR_FAIL; } uint64_t value; retval = parse_u64(CMD_ARGV[i * 2 + 1], &value); if (retval != ERROR_OK) goto error_return; int field_size = tap->ir_length; fields[i].num_bits = field_size; uint8_t *v = calloc(1, DIV_ROUND_UP(field_size, 8)); if (!v) { LOG_ERROR("Out of memory"); goto error_return; } buf_set_u64(v, 0, field_size, value); fields[i].out_value = v; fields[i].in_value = NULL; } /* did we have an endstate? */ jtag_add_ir_scan(tap, fields, endstate); retval = jtag_execute_queue(); error_return: for (i = 0; i < num_fields; i++) free((void *)fields[i].out_value); free(fields); return retval; } COMMAND_HANDLER(handle_verify_ircapture_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { bool enable; COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable); jtag_set_verify_capture_ir(enable); } const char *status = jtag_will_verify_capture_ir() ? "enabled" : "disabled"; command_print(CMD, "verify Capture-IR is %s", status); return ERROR_OK; } COMMAND_HANDLER(handle_verify_jtag_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { bool enable; COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable); jtag_set_verify(enable); } const char *status = jtag_will_verify() ? "enabled" : "disabled"; command_print(CMD, "verify jtag capture is %s", status); return ERROR_OK; } COMMAND_HANDLER(handle_tms_sequence_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { bool use_new_table; if (strcmp(CMD_ARGV[0], "short") == 0) use_new_table = true; else if (strcmp(CMD_ARGV[0], "long") == 0) use_new_table = false; else return ERROR_COMMAND_SYNTAX_ERROR; tap_use_new_tms_table(use_new_table); } command_print(CMD, "tms sequence is %s", tap_uses_new_tms_table() ? "short" : "long"); return ERROR_OK; } COMMAND_HANDLER(handle_jtag_flush_queue_sleep) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; int sleep_ms; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], sleep_ms); jtag_set_flush_queue_sleep(sleep_ms); return ERROR_OK; } COMMAND_HANDLER(handle_wait_srst_deassert) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; int timeout_ms; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], timeout_ms); if ((timeout_ms <= 0) || (timeout_ms > 100000)) { LOG_ERROR("Timeout must be an integer between 0 and 100000"); return ERROR_FAIL; } LOG_USER("Waiting for srst assert + deassert for at most %dms", timeout_ms); int asserted_yet; int64_t then = timeval_ms(); while (jtag_srst_asserted(&asserted_yet) == ERROR_OK) { if ((timeval_ms() - then) > timeout_ms) { LOG_ERROR("Timed out"); return ERROR_FAIL; } if (asserted_yet) break; } while (jtag_srst_asserted(&asserted_yet) == ERROR_OK) { if ((timeval_ms() - then) > timeout_ms) { LOG_ERROR("Timed out"); return ERROR_FAIL; } if (!asserted_yet) break; } return ERROR_OK; } static const struct command_registration jtag_command_handlers[] = { { .name = "jtag_flush_queue_sleep", .handler = handle_jtag_flush_queue_sleep, .mode = COMMAND_ANY, .help = "For debug purposes(simulate long delays of interface) " "to test performance or change in behavior. Default 0ms.", .usage = "[sleep in ms]", }, { .name = "jtag_rclk", .handler = handle_jtag_rclk_command, .mode = COMMAND_ANY, .help = "With an argument, change to to use adaptive clocking " "if possible; else to use the fallback speed. " "With or without argument, display current setting.", .usage = "[fallback_speed_khz]", }, { .name = "jtag_ntrst_delay", .handler = handle_jtag_ntrst_delay_command, .mode = COMMAND_ANY, .help = "delay after deasserting trst in ms", .usage = "[milliseconds]", }, { .name = "jtag_ntrst_assert_width", .handler = handle_jtag_ntrst_assert_width_command, .mode = COMMAND_ANY, .help = "delay after asserting trst in ms", .usage = "[milliseconds]", }, { .name = "scan_chain", .handler = handle_scan_chain_command, .mode = COMMAND_ANY, .help = "print current scan chain configuration", .usage = "" }, { .name = "runtest", .handler = handle_runtest_command, .mode = COMMAND_EXEC, .help = "Move to Run-Test/Idle, and issue TCK for num_cycles.", .usage = "num_cycles" }, { .name = "irscan", .handler = handle_irscan_command, .mode = COMMAND_EXEC, .help = "Execute Instruction Register (IR) scan. The " "specified opcodes are put into each TAP's IR, " "and other TAPs are put in BYPASS.", .usage = "[tap_name instruction]* ['-endstate' state_name]", }, { .name = "verify_ircapture", .handler = handle_verify_ircapture_command, .mode = COMMAND_ANY, .help = "Display or assign flag controlling whether to " "verify values captured during Capture-IR.", .usage = "['enable'|'disable']", }, { .name = "verify_jtag", .handler = handle_verify_jtag_command, .mode = COMMAND_ANY, .help = "Display or assign flag controlling whether to " "verify values captured during IR and DR scans.", .usage = "['enable'|'disable']", }, { .name = "tms_sequence", .handler = handle_tms_sequence_command, .mode = COMMAND_ANY, .help = "Display or change what style TMS sequences to use " "for JTAG state transitions: short (default) or " "long. Only for working around JTAG bugs.", /* Specifically for working around DRIVER bugs... */ .usage = "['short'|'long']", }, { .name = "wait_srst_deassert", .handler = handle_wait_srst_deassert, .mode = COMMAND_ANY, .help = "Wait for an SRST deassert. " "Useful for cases where you need something to happen within ms " "of an srst deassert. Timeout in ms", .usage = "ms", }, { .name = "jtag", .mode = COMMAND_ANY, .help = "perform jtag tap actions", .usage = "", .chain = jtag_subcommand_handlers, }, { .chain = jtag_command_handlers_to_move, }, COMMAND_REGISTRATION_DONE }; int jtag_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, jtag_command_handlers); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/jtag/tcl.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * ***************************************************************************/ #ifndef OPENOCD_JTAG_TCL_H #define OPENOCD_JTAG_TCL_H #include <helper/command.h> int jim_jtag_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv); __COMMAND_HANDLER(handle_jtag_tap_enabler); #endif /* OPENOCD_JTAG_TCL_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/main.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "openocd.h" #include "helper/system.h" /* This is the main entry for developer PC hosted OpenOCD. * * OpenOCD can also be used as a library that is linked with * another application(not mainstream yet, but possible), e.g. * w/as an embedded application. * * Those applications will have their own main() implementation * and use bits and pieces from openocd.c. */ int main(int argc, char *argv[]) { /* disable buffering otherwise piping to logs causes problems work */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); return openocd_main(argc, argv); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/openocd.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 Richard Missenden * * richard.missenden@googlemail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "openocd.h" #include <jtag/adapter.h> #include <jtag/jtag.h> #include <transport/transport.h> #include <helper/util.h> #include <helper/configuration.h> #include <flash/nor/core.h> #include <flash/nand/core.h> #include <pld/pld.h> #include <target/arm_cti.h> #include <target/arm_adi_v5.h> #include <target/arm_tpiu_swo.h> #include <rtt/rtt.h> #include <server/server.h> #include <server/gdb_server.h> #include <server/rtt_server.h> #ifdef HAVE_STRINGS_H #include <strings.h> #endif #ifdef PKGBLDDATE #define OPENOCD_VERSION \ "Open On-Chip Debugger " VERSION RELSTR " (" PKGBLDDATE ")" #else #define OPENOCD_VERSION \ "Open On-Chip Debugger " VERSION RELSTR #endif static const char openocd_startup_tcl[] = { #include "startup_tcl.inc" 0 /* Terminate with zero */ }; /* Give scripts and TELNET a way to find out what version this is */ COMMAND_HANDLER(handler_version_command) { char *version_str = OPENOCD_VERSION; if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { if (strcmp("git", CMD_ARGV[0])) return ERROR_COMMAND_ARGUMENT_INVALID; version_str = GITVERSION; } command_print(CMD, "%s", version_str); return ERROR_OK; } static int log_target_callback_event_handler(struct target *target, enum target_event event, void *priv) { switch (event) { case TARGET_EVENT_GDB_START: target->verbose_halt_msg = false; break; case TARGET_EVENT_GDB_END: target->verbose_halt_msg = true; break; case TARGET_EVENT_HALTED: if (target->verbose_halt_msg) { /* do not display information when debugger caused the halt */ target_arch_state(target); } break; default: break; } return ERROR_OK; } static bool init_at_startup = true; COMMAND_HANDLER(handle_noinit_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; init_at_startup = false; return ERROR_OK; } /* OpenOCD can't really handle failure of this command. Patches welcome! :-) */ COMMAND_HANDLER(handle_init_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; int retval; static int initialized; if (initialized) return ERROR_OK; initialized = 1; bool save_poll_mask = jtag_poll_mask(); retval = command_run_line(CMD_CTX, "target init"); if (retval != ERROR_OK) return ERROR_FAIL; retval = adapter_init(CMD_CTX); if (retval != ERROR_OK) { /* we must be able to set up the debug adapter */ return retval; } LOG_DEBUG("Debug Adapter init complete"); /* "transport init" verifies the expected devices are present; * for JTAG, it checks the list of configured TAPs against * what's discoverable, possibly with help from the platform's * JTAG event handlers. (which require COMMAND_EXEC) */ command_context_mode(CMD_CTX, COMMAND_EXEC); retval = command_run_line(CMD_CTX, "transport init"); if (retval != ERROR_OK) return ERROR_FAIL; retval = command_run_line(CMD_CTX, "dap init"); if (retval != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("Examining targets..."); if (target_examine() != ERROR_OK) LOG_DEBUG("target examination failed"); command_context_mode(CMD_CTX, COMMAND_CONFIG); if (command_run_line(CMD_CTX, "flash init") != ERROR_OK) return ERROR_FAIL; if (command_run_line(CMD_CTX, "nand init") != ERROR_OK) return ERROR_FAIL; if (command_run_line(CMD_CTX, "pld init") != ERROR_OK) return ERROR_FAIL; command_context_mode(CMD_CTX, COMMAND_EXEC); /* in COMMAND_EXEC, after target_examine(), only tpiu or only swo */ if (command_run_line(CMD_CTX, "tpiu init") != ERROR_OK) return ERROR_FAIL; jtag_poll_unmask(save_poll_mask); /* initialize telnet subsystem */ gdb_target_add_all(all_targets); target_register_event_callback(log_target_callback_event_handler, CMD_CTX); if (command_run_line(CMD_CTX, "_run_post_init_commands") != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } COMMAND_HANDLER(handle_add_script_search_dir_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; add_script_search_dir(CMD_ARGV[0]); return ERROR_OK; } static const struct command_registration openocd_command_handlers[] = { { .name = "version", .handler = handler_version_command, .mode = COMMAND_ANY, .help = "show program version", .usage = "[git]", }, { .name = "noinit", .handler = &handle_noinit_command, .mode = COMMAND_CONFIG, .help = "Prevent 'init' from being called at startup.", .usage = "" }, { .name = "init", .handler = &handle_init_command, .mode = COMMAND_ANY, .help = "Initializes configured targets and servers. " "Changes command mode from CONFIG to EXEC. " "Unless 'noinit' is called, this command is " "called automatically at the end of startup.", .usage = "" }, { .name = "add_script_search_dir", .handler = &handle_add_script_search_dir_command, .mode = COMMAND_ANY, .help = "dir to search for config files and scripts", .usage = "<directory>" }, COMMAND_REGISTRATION_DONE }; static int openocd_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, openocd_command_handlers); } struct command_context *global_cmd_ctx; static struct command_context *setup_command_handler(Jim_Interp *interp) { log_init(); LOG_DEBUG("log_init: complete"); struct command_context *cmd_ctx = command_init(openocd_startup_tcl, interp); /* register subsystem commands */ typedef int (*command_registrant_t)(struct command_context *cmd_ctx_value); static const command_registrant_t command_registrants[] = { &openocd_register_commands, &server_register_commands, &gdb_register_commands, &log_register_commands, &rtt_server_register_commands, &transport_register_commands, &adapter_register_commands, &target_register_commands, &flash_register_commands, &nand_register_commands, &pld_register_commands, &cti_register_commands, &dap_register_commands, &arm_tpiu_swo_register_commands, NULL }; for (unsigned i = 0; command_registrants[i]; i++) { int retval = (*command_registrants[i])(cmd_ctx); if (retval != ERROR_OK) { command_done(cmd_ctx); return NULL; } } LOG_DEBUG("command registration: complete"); LOG_OUTPUT(OPENOCD_VERSION "\n" "Licensed under GNU GPL v2\n"); global_cmd_ctx = cmd_ctx; return cmd_ctx; } /** OpenOCD runtime meat that can become single-thread in future. It parse * commandline, reads configuration, sets up the target and starts server loop. * Commandline arguments are passed into this function from openocd_main(). */ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ctx) { int ret; if (parse_cmdline_args(cmd_ctx, argc, argv) != ERROR_OK) return ERROR_FAIL; if (server_preinit() != ERROR_OK) return ERROR_FAIL; ret = parse_config_file(cmd_ctx); if (ret == ERROR_COMMAND_CLOSE_CONNECTION) { server_quit(); /* gdb server may be initialized by -c init */ return ERROR_OK; } else if (ret != ERROR_OK) { server_quit(); /* gdb server may be initialized by -c init */ return ERROR_FAIL; } ret = server_init(cmd_ctx); if (ret != ERROR_OK) return ERROR_FAIL; if (init_at_startup) { ret = command_run_line(cmd_ctx, "init"); if (ret != ERROR_OK) { server_quit(); return ERROR_FAIL; } } ret = server_loop(cmd_ctx); int last_signal = server_quit(); if (last_signal != ERROR_OK) return last_signal; if (ret != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } /* normally this is the main() function entry, but if OpenOCD is linked * into application, then this fn will not be invoked, but rather that * application will have it's own implementation of main(). */ int openocd_main(int argc, char *argv[]) { int ret; /* initialize commandline interface */ struct command_context *cmd_ctx; cmd_ctx = setup_command_handler(NULL); if (util_init(cmd_ctx) != ERROR_OK) return EXIT_FAILURE; if (rtt_init() != ERROR_OK) return EXIT_FAILURE; LOG_OUTPUT("For bug reports, read\n\t" "http://openocd.org/doc/doxygen/bugs.html" "\n"); command_context_mode(cmd_ctx, COMMAND_CONFIG); command_set_output_handler(cmd_ctx, configuration_output_handler, NULL); server_host_os_entry(); /* Start the executable meat that can evolve into thread in future. */ ret = openocd_thread(argc, argv, cmd_ctx); flash_free_all_banks(); gdb_service_free(); arm_tpiu_swo_cleanup_all(); server_free(); unregister_all_commands(cmd_ctx, NULL); help_del_all_commands(cmd_ctx); /* free all DAP and CTI objects */ arm_cti_cleanup_all(); dap_cleanup_all(); adapter_quit(); server_host_os_close(); /* Shutdown commandline interface */ command_exit(cmd_ctx); rtt_exit(); free_config(); log_exit(); if (ret == ERROR_FAIL) return EXIT_FAILURE; else if (ret != ERROR_OK) exit_on_signal(ret); return ret; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/openocd.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifndef OPENOCD_OPENOCD_H #define OPENOCD_OPENOCD_H /** * Different applications can define this entry point to override * the default openocd main function. On most systems, this will be * defined in src/openocd.c. * @param argc normally passed from main() * @param argv normally passed from main() * @returns return code for main() */ int openocd_main(int argc, char *argv[]); #endif /* OPENOCD_OPENOCD_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libpld.la %C%_libpld_la_SOURCES = \ %D%/certus.c \ %D%/ecp2_3.c \ %D%/ecp5.c \ %D%/efinix.c \ %D%/gatemate.c \ %D%/gowin.c \ %D%/intel.c \ %D%/lattice.c \ %D%/lattice_bit.c \ %D%/pld.c \ %D%/raw_bit.c \ %D%/xilinx_bit.c \ %D%/virtex2.c \ %D%/certus.h \ %D%/ecp2_3.h \ %D%/ecp5.h \ %D%/lattice.h \ %D%/lattice_bit.h \ %D%/lattice_cmd.h \ %D%/pld.h \ %D%/raw_bit.h \ %D%/xilinx_bit.h \ %D%/virtex2.h ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/certus.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "certus.h" #include "lattice.h" #include "lattice_cmd.h" #define LSC_ENABLE_X 0x74 #define LSC_REFRESH 0x79 #define LSC_DEVICE_CTRL 0x7D int lattice_certus_read_status(struct jtag_tap *tap, uint64_t *status, uint64_t out) { return lattice_read_u64_register(tap, LSC_READ_STATUS, status, out); } int lattice_certus_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out) { return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, false); } int lattice_certus_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode) { LOG_ERROR("Not supported to write usercode on certus devices"); return ERROR_FAIL; } static int lattice_certus_enable_transparent_mode(struct jtag_tap *tap) { struct scan_field field; int retval = lattice_set_instr(tap, LSC_ENABLE_X, TAP_IDLE); if (retval != ERROR_OK) return retval; uint8_t buffer = 0x0; field.num_bits = 8; field.out_value = &buffer; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_runtest(2, TAP_IDLE); return jtag_execute_queue(); } static int lattice_certus_erase_device(struct lattice_pld_device *lattice_device) { struct jtag_tap *tap = lattice_device->tap; if (!tap) return ERROR_FAIL; int retval = lattice_set_instr(tap, LSC_DEVICE_CTRL, TAP_IRPAUSE); if (retval != ERROR_OK) return retval; struct scan_field field; uint8_t buffer = 8; field.num_bits = 8; field.out_value = &buffer; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_runtest(2, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; retval = lattice_set_instr(tap, LSC_DEVICE_CTRL, TAP_IDLE); if (retval != ERROR_OK) return retval; buffer = 0; field.num_bits = 8; field.out_value = &buffer; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_runtest(2, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; retval = lattice_set_instr(tap, ISC_ERASE, TAP_IDLE); if (retval != ERROR_OK) return retval; buffer = 0; field.num_bits = 8; field.out_value = &buffer; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_runtest(100, TAP_IDLE); jtag_add_sleep(5000); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* check done is cleared and fail is cleared */ const uint64_t status_done_flag = 0x100; const uint64_t status_fail_flag = 0x2000; return lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, status_done_flag | status_fail_flag); } static int lattice_certus_enable_programming(struct jtag_tap *tap) { struct scan_field field; int retval = lattice_set_instr(tap, LSC_REFRESH, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(2, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); if (retval != ERROR_OK) return retval; uint8_t buffer = 0; field.num_bits = 8; field.out_value = &buffer; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_runtest(2, TAP_IDLE); return jtag_execute_queue(); } static int lattice_certus_init_address(struct jtag_tap *tap) { int retval = lattice_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(2, TAP_IDLE); return jtag_execute_queue(); } static int lattice_certus_exit_programming_mode(struct jtag_tap *tap) { int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(2, TAP_IDLE); retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(100, TAP_IDLE); return jtag_execute_queue(); } static int lattice_certus_program_config_map(struct jtag_tap *tap, struct lattice_bit_file *bit_file) { struct scan_field field; int retval = lattice_set_instr(tap, LSC_BITSTREAM_BURST, TAP_IDLE); if (retval != ERROR_OK) return retval; field.num_bits = (bit_file->raw_bit.length - bit_file->offset) * 8; field.out_value = bit_file->raw_bit.data + bit_file->offset; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); return jtag_execute_queue(); } int lattice_certus_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file) { struct jtag_tap *tap = lattice_device->tap; if (!tap) return ERROR_FAIL; int retval = lattice_preload(lattice_device); if (retval != ERROR_OK) return retval; /* check password protection is disabled */ const uint64_t status_pwd_protection = 0x20000; retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, status_pwd_protection); if (retval != ERROR_OK) { LOG_ERROR("Password protection is set"); return retval; } retval = lattice_certus_enable_transparent_mode(tap); if (retval != ERROR_OK) return retval; /* Check the SRAM Erase Lock */ const uint64_t status_otp = 0x40; retval = lattice_verify_status_register_u64(lattice_device, 0x0, status_otp, status_otp); if (retval != ERROR_OK) { LOG_ERROR("NV User Feature Sector OTP is Set"); return retval; } /* Check the SRAM Lock */ const uint64_t status_write_protected = 0x400; retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, status_write_protected); if (retval != ERROR_OK) { LOG_ERROR("NV User Feature Sector OTP is Set"); return retval; } retval = lattice_certus_enable_programming(tap); if (retval != ERROR_OK) { LOG_ERROR("failed to enable programming mode"); return retval; } retval = lattice_certus_erase_device(lattice_device); if (retval != ERROR_OK) { LOG_ERROR("erasing device failed"); return retval; } retval = lattice_certus_init_address(tap); if (retval != ERROR_OK) return retval; retval = lattice_certus_program_config_map(tap, bit_file); if (retval != ERROR_OK) return retval; const uint32_t expected = 0x100; // done const uint32_t mask = expected | 0x3000 | // Busy Flag and Fail Flag 0xf000000; // BSE Error retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x100, mask); if (retval != ERROR_OK) return retval; return lattice_certus_exit_programming_mode(tap); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/certus.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifndef OPENOCD_PLD_CERTUS_H #define OPENOCD_PLD_CERTUS_H #include "lattice.h" int lattice_certus_read_status(struct jtag_tap *tap, uint64_t *status, uint64_t out); int lattice_certus_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out); int lattice_certus_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode); int lattice_certus_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file); #endif /* OPENOCD_PLD_CERTUS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/ecp2_3.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "ecp2_3.h" #include "lattice.h" #define LSCC_REFRESH 0x23 #define ISC_ENABLE 0x15 #define LSCC_RESET_ADDRESS 0x21 #define ISC_PROGRAM_USERCODE 0x1A #define ISC_ERASE 0x03 #define READ_USERCODE 0x17 #define ISC_DISABLE 0x1E #define LSCC_READ_STATUS 0x53 #define LSCC_BITSTREAM_BURST 0x02 #define STATUS_DONE_BIT 0x00020000 #define STATUS_ERROR_BITS_ECP2 0x00040003 #define STATUS_ERROR_BITS_ECP3 0x00040007 #define REGISTER_ALL_BITS_1 0xffffffff #define REGISTER_ALL_BITS_0 0x00000000 int lattice_ecp2_3_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle) { return lattice_read_u32_register(tap, LSCC_READ_STATUS, status, out, do_idle); } int lattice_ecp2_3_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out) { return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, false); } int lattice_ecp2_3_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode) { struct jtag_tap *tap = lattice_device->tap; if (!tap) return ERROR_FAIL; int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(20000); retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE); if (retval != ERROR_OK) return retval; struct scan_field field; uint8_t buffer[4]; h_u32_to_le(buffer, usercode); field.num_bits = 32; field.out_value = buffer; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(2000); retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(200000); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; return lattice_verify_usercode(lattice_device, 0x0, usercode, REGISTER_ALL_BITS_1); } static int lattice_ecp2_3_erase_device(struct lattice_pld_device *lattice_device) { struct jtag_tap *tap = lattice_device->tap; if (!tap) return ERROR_FAIL; /* program user code with all bits set */ int retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IRPAUSE); if (retval != ERROR_OK) return retval; struct scan_field field; uint8_t buffer[4] = {0xff, 0xff, 0xff, 0xff}; field.num_bits = 32; field.out_value = buffer; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(2000); /* verify every bit is set */ const uint32_t out = REGISTER_ALL_BITS_1; const uint32_t mask = REGISTER_ALL_BITS_1; const uint32_t expected_pre = REGISTER_ALL_BITS_1; retval = lattice_verify_usercode(lattice_device, out, expected_pre, mask); if (retval != ERROR_OK) return retval; retval = lattice_set_instr(tap, ISC_ERASE, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(5, TAP_IDLE); if (lattice_device->family == LATTICE_ECP2) jtag_add_sleep(100000); else jtag_add_sleep(2000000); retval = lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(2000); /* after erasing check all bits in user register are cleared */ const uint32_t expected_post = REGISTER_ALL_BITS_0; return lattice_verify_usercode(lattice_device, out, expected_post, mask); } static int lattice_ecp2_3_program_config_map(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file) { struct jtag_tap *tap = lattice_device->tap; if (!tap) return ERROR_FAIL; int retval = lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(2000); struct scan_field field; retval = lattice_set_instr(tap, LSCC_BITSTREAM_BURST, TAP_IDLE); if (retval != ERROR_OK) return retval; field.num_bits = (bit_file->raw_bit.length - bit_file->offset) * 8; field.out_value = bit_file->raw_bit.data + bit_file->offset; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_runtest(256, TAP_IDLE); jtag_add_sleep(2000); return jtag_execute_queue(); } static int lattice_ecp2_3_exit_programming_mode(struct lattice_pld_device *lattice_device) { struct jtag_tap *tap = lattice_device->tap; if (!tap) return ERROR_FAIL; int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(200000); retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(100, TAP_IDLE); jtag_add_sleep(1000); return jtag_execute_queue(); } int lattice_ecp2_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file) { struct jtag_tap *tap = lattice_device->tap; if (!tap) return ERROR_FAIL; int retval = lattice_preload(lattice_device); if (retval != ERROR_OK) return retval; /* Enable the programming mode */ retval = lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(20000); /* Erase the device */ retval = lattice_ecp2_3_erase_device(lattice_device); if (retval != ERROR_OK) return retval; /* Program Fuse Map */ retval = lattice_ecp2_3_program_config_map(lattice_device, bit_file); if (retval != ERROR_OK) return retval; retval = lattice_ecp2_3_exit_programming_mode(lattice_device); if (retval != ERROR_OK) return retval; const uint32_t out = REGISTER_ALL_BITS_1; const uint32_t mask = STATUS_DONE_BIT | STATUS_ERROR_BITS_ECP2; const uint32_t expected = STATUS_DONE_BIT; return lattice_verify_status_register_u32(lattice_device, out, expected, mask, false); } int lattice_ecp3_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file) { struct jtag_tap *tap = lattice_device->tap; if (!tap) return ERROR_FAIL; /* Program Bscan register */ int retval = lattice_preload(lattice_device); if (retval != ERROR_OK) return retval; /* Enable the programming mode */ retval = lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(500000); retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(20000); retval = lattice_ecp2_3_erase_device(lattice_device); if (retval != ERROR_OK) return retval; /* Program Fuse Map */ retval = lattice_ecp2_3_program_config_map(lattice_device, bit_file); if (retval != ERROR_OK) return retval; retval = lattice_ecp2_3_exit_programming_mode(lattice_device); if (retval != ERROR_OK) return retval; const uint32_t out = REGISTER_ALL_BITS_1; const uint32_t mask = STATUS_DONE_BIT | STATUS_ERROR_BITS_ECP3; const uint32_t expected = STATUS_DONE_BIT; return lattice_verify_status_register_u32(lattice_device, out, expected, mask, false); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/ecp2_3.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifndef OPENOCD_PLD_ECP2_3_H #define OPENOCD_PLD_ECP2_3_H #include "lattice.h" int lattice_ecp2_3_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle); int lattice_ecp2_3_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out); int lattice_ecp2_3_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode); int lattice_ecp2_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file); int lattice_ecp3_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file); #endif /* OPENOCD_PLD_ECP2_3_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/ecp5.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "ecp5.h" #include "lattice.h" #include "lattice_cmd.h" #define ISC_PROGRAM_USERCODE 0xC2 #define STATUS_DONE_BIT 0x00000100 #define STATUS_ERROR_BITS 0x00020040 #define STATUS_FEA_OTP 0x00004000 #define STATUS_FAIL_FLAG 0x00002000 #define STATUS_BUSY_FLAG 0x00001000 #define REGISTER_ALL_BITS_1 0xffffffff int lattice_ecp5_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle) { return lattice_read_u32_register(tap, LSC_READ_STATUS, status, out, do_idle); } int lattice_ecp5_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out) { return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, true); } int lattice_ecp5_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode) { struct jtag_tap *tap = lattice_device->tap; if (!tap) return ERROR_FAIL; int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(20000); retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE); if (retval != ERROR_OK) return retval; uint8_t buffer[4]; struct scan_field field; h_u32_to_le(buffer, usercode); field.num_bits = 32; field.out_value = buffer; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(2000); retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(200000); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; return lattice_verify_usercode(lattice_device, 0x0, usercode, REGISTER_ALL_BITS_1); } static int lattice_ecp5_enable_sram_programming(struct jtag_tap *tap) { int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); if (retval != ERROR_OK) return retval; struct scan_field field; uint8_t buffer = 0x0; field.num_bits = 8; field.out_value = &buffer; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_runtest(2, TAP_IDLE); jtag_add_sleep(10000); return jtag_execute_queue(); } static int lattice_ecp5_erase_sram(struct jtag_tap *tap) { int retval = lattice_set_instr(tap, ISC_ERASE, TAP_IRPAUSE); if (retval != ERROR_OK) return retval; struct scan_field field; uint8_t buffer = 1; field.num_bits = 8; field.out_value = &buffer; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_runtest(2, TAP_IDLE); jtag_add_sleep(200000); return jtag_execute_queue(); } static int lattice_ecp5_init_address(struct jtag_tap *tap) { int retval = lattice_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE); if (retval != ERROR_OK) return retval; struct scan_field field; uint8_t buffer = 1; field.num_bits = 8; field.out_value = &buffer; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_runtest(2, TAP_IDLE); jtag_add_sleep(10000); return jtag_execute_queue(); } static int lattice_ecp5_program_config_map(struct jtag_tap *tap, struct lattice_bit_file *bit_file) { int retval = lattice_set_instr(tap, LSC_BITSTREAM_BURST, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(2, TAP_IDLE); jtag_add_sleep(10000); struct scan_field field; field.num_bits = (bit_file->raw_bit.length - bit_file->offset) * 8; field.out_value = bit_file->raw_bit.data + bit_file->offset; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(100, TAP_IDLE); jtag_add_sleep(10000); return jtag_execute_queue(); } static int lattice_ecp5_exit_programming_mode(struct jtag_tap *tap) { int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(2, TAP_IDLE); jtag_add_sleep(200000); retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(2, TAP_IDLE); jtag_add_sleep(1000); return jtag_execute_queue(); } int lattice_ecp5_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file) { struct jtag_tap *tap = lattice_device->tap; if (!tap) return ERROR_FAIL; int retval = lattice_preload(lattice_device); if (retval != ERROR_OK) return retval; retval = lattice_ecp5_enable_sram_programming(tap); if (retval != ERROR_OK) return retval; const uint32_t out = 0x0; const uint32_t expected1 = 0x0; const uint32_t mask1 = STATUS_ERROR_BITS | STATUS_FEA_OTP; retval = lattice_verify_status_register_u32(lattice_device, out, expected1, mask1, true); if (retval != ERROR_OK) return retval; retval = lattice_ecp5_erase_sram(tap); if (retval != ERROR_OK) return retval; const uint32_t mask2 = STATUS_FAIL_FLAG | STATUS_BUSY_FLAG; retval = lattice_verify_status_register_u32(lattice_device, out, expected1, mask2, false); if (retval != ERROR_OK) return retval; retval = lattice_ecp5_init_address(tap); if (retval != ERROR_OK) return retval; retval = lattice_ecp5_program_config_map(tap, bit_file); if (retval != ERROR_OK) return retval; retval = lattice_ecp5_exit_programming_mode(tap); if (retval != ERROR_OK) return retval; const uint32_t expected2 = STATUS_DONE_BIT; const uint32_t mask3 = STATUS_DONE_BIT | STATUS_FAIL_FLAG; return lattice_verify_status_register_u32(lattice_device, out, expected2, mask3, false); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/ecp5.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifndef OPENOCD_PLD_ECP5_H #define OPENOCD_PLD_ECP5_H #include "lattice.h" int lattice_ecp5_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle); int lattice_ecp5_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out); int lattice_ecp5_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode); int lattice_ecp5_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file); #endif /* OPENOCD_PLD_ECP5_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/efinix.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/jtag.h> #include "pld.h" #include "raw_bit.h" #define PROGRAM 0x4 #define ENTERUSER 0x7 #define USER1 0x8 #define USER2 0x9 #define USER3 0xa #define USER4 0xb enum efinix_family_e { EFINIX_TRION, EFINIX_TITANIUM, EFINIX_UNKNOWN }; #define TRAILING_ZEROS 4000 #define RUNTEST_START_CYCLES 100 #define RUNTEST_FINISH_CYCLES 100 struct efinix_device { uint32_t idcode; int num_user; }; struct efinix_pld_device { struct jtag_tap *tap; enum efinix_family_e family; }; static int efinix_read_bit_file(struct raw_bit_file *bit_file, const char *filename) { FILE *input_file = fopen(filename, "r"); if (!input_file) { LOG_ERROR("couldn't open %s: %s", filename, strerror(errno)); return ERROR_PLD_FILE_LOAD_FAILED; } fseek(input_file, 0, SEEK_END); long length = ftell(input_file); fseek(input_file, 0, SEEK_SET); if (length < 0 || ((length % 3))) { fclose(input_file); LOG_ERROR("Failed to get length from file %s: %s", filename, strerror(errno)); return ERROR_PLD_FILE_LOAD_FAILED; } bit_file->length = DIV_ROUND_UP(length, 3); bit_file->data = malloc(bit_file->length); if (!bit_file->data) { fclose(input_file); LOG_ERROR("Out of memory"); return ERROR_PLD_FILE_LOAD_FAILED; } bool end_detected = false; char buffer[3]; for (size_t idx = 0; !end_detected && idx < bit_file->length; ++idx) { size_t read_count = fread(buffer, sizeof(char), 3, input_file); end_detected = feof(input_file); if ((read_count == 3 && buffer[2] != '\n') || (read_count != 3 && !end_detected) || (read_count != 2 && end_detected)) { fclose(input_file); free(bit_file->data); bit_file->data = NULL; LOG_ERROR("unexpected line length"); return ERROR_PLD_FILE_LOAD_FAILED; } if (!isxdigit(buffer[0]) || !isxdigit(buffer[1])) { fclose(input_file); free(bit_file->data); bit_file->data = NULL; LOG_ERROR("unexpected char in hex string"); return ERROR_PLD_FILE_LOAD_FAILED; } unhexify(&bit_file->data[idx], buffer, 2); } fclose(input_file); return ERROR_OK; } static int efinix_read_file(struct raw_bit_file *bit_file, const char *filename) { if (!filename || !bit_file) return ERROR_COMMAND_SYNTAX_ERROR; /* check if binary .bin or ascii .bit/.hex */ const char *file_ending_pos = strrchr(filename, '.'); if (!file_ending_pos) { LOG_ERROR("Unable to detect filename suffix"); return ERROR_PLD_FILE_LOAD_FAILED; } if (strcasecmp(file_ending_pos, ".bin") == 0) { return cpld_read_raw_bit_file(bit_file, filename); } else if ((strcasecmp(file_ending_pos, ".bit") == 0) || (strcasecmp(file_ending_pos, ".hex") == 0)) { return efinix_read_bit_file(bit_file, filename); } LOG_ERROR("Unable to detect filetype"); return ERROR_PLD_FILE_LOAD_FAILED; } static int efinix_set_instr(struct jtag_tap *tap, uint8_t new_instr) { struct scan_field field; field.num_bits = tap->ir_length; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); free(t); return ERROR_OK; } static int efinix_load(struct pld_device *pld_device, const char *filename) { struct raw_bit_file bit_file; struct scan_field field[2]; if (!pld_device || !pld_device->driver_priv) return ERROR_FAIL; struct efinix_pld_device *efinix_info = pld_device->driver_priv; if (!efinix_info || !efinix_info->tap) return ERROR_FAIL; struct jtag_tap *tap = efinix_info->tap; jtag_add_tlr(); int retval = efinix_set_instr(tap, PROGRAM); if (retval != ERROR_OK) return retval; jtag_add_runtest(RUNTEST_START_CYCLES, TAP_IDLE); retval = efinix_set_instr(tap, PROGRAM); /* fix for T20 */ if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; retval = efinix_read_file(&bit_file, filename); if (retval != ERROR_OK) return retval; for (size_t i = 0; i < bit_file.length; i++) bit_file.data[i] = flip_u32(bit_file.data[i], 8); /* shift in the bitstream */ field[0].num_bits = bit_file.length * 8; field[0].out_value = bit_file.data; field[0].in_value = NULL; /* followed by zeros */ field[1].num_bits = TRAILING_ZEROS; uint8_t *buf = calloc(TRAILING_ZEROS / 8, 1); if (!buf) { free(bit_file.data); LOG_ERROR("Out of memory"); return ERROR_FAIL; } field[1].out_value = buf; field[1].in_value = NULL; jtag_add_dr_scan(tap, 2, field, TAP_DRPAUSE); retval = jtag_execute_queue(); free(bit_file.data); free(buf); if (retval != ERROR_OK) return retval; retval = efinix_set_instr(tap, ENTERUSER); if (retval != ERROR_OK) return retval; /* entering RUN/TEST for 100 cycles */ jtag_add_runtest(RUNTEST_FINISH_CYCLES, TAP_IDLE); retval = jtag_execute_queue(); return retval; } static int efinix_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) { if (!pld_device) return ERROR_FAIL; struct efinix_pld_device *pld_device_info = pld_device->driver_priv; if (!pld_device_info || !pld_device_info->tap) return ERROR_FAIL; hub->tap = pld_device_info->tap; if (pld_device_info->family == EFINIX_UNKNOWN) { LOG_ERROR("family unknown, please specify for 'pld create'"); return ERROR_FAIL; } int num_user = 2; /* trion */ if (pld_device_info->family == EFINIX_TITANIUM) num_user = 4; if (user_num > num_user) { LOG_ERROR("Devices has only user register 1 to %d", num_user); return ERROR_FAIL; } switch (user_num) { case 1: hub->user_ir_code = USER1; break; case 2: hub->user_ir_code = USER2; break; case 3: hub->user_ir_code = USER3; break; case 4: hub->user_ir_code = USER4; break; default: LOG_ERROR("efinix devices only have user register 1 to %d", num_user); return ERROR_FAIL; } return ERROR_OK; } PLD_CREATE_COMMAND_HANDLER(efinix_pld_create_command) { if (CMD_ARGC != 4 && CMD_ARGC != 6) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[2], "-chain-position") != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); if (!tap) { command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); return ERROR_FAIL; } enum efinix_family_e family = EFINIX_UNKNOWN; if (CMD_ARGC == 6) { if (strcmp(CMD_ARGV[4], "-family") != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[5], "trion") == 0) { family = EFINIX_TRION; } else if (strcmp(CMD_ARGV[5], "titanium") == 0) { family = EFINIX_TITANIUM; } else { command_print(CMD, "unknown family"); return ERROR_FAIL; } } struct efinix_pld_device *efinix_info = malloc(sizeof(struct efinix_pld_device)); if (!efinix_info) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } efinix_info->tap = tap; efinix_info->family = family; pld->driver_priv = efinix_info; return ERROR_OK; } struct pld_driver efinix_pld = { .name = "efinix", .pld_create_command = &efinix_pld_create_command, .load = &efinix_load, .get_ipdbg_hub = efinix_get_ipdbg_hub, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/gatemate.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/jtag.h> #include <jtag/adapter.h> #include "pld.h" #include "raw_bit.h" #define JTAG_CONFIGURE 0x06 struct gatemate_pld_device { struct jtag_tap *tap; }; struct gatemate_bit_file { struct raw_bit_file raw_file; size_t capacity; }; static int gatemate_add_byte_to_bitfile(struct gatemate_bit_file *bit_file, uint8_t byte) { const size_t chunk_size = 8192; if (bit_file->raw_file.length + 1 > bit_file->capacity) { uint8_t *buffer; if (bit_file->raw_file.data) buffer = realloc(bit_file->raw_file.data, bit_file->capacity + chunk_size); else buffer = malloc(chunk_size); if (!buffer) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } bit_file->raw_file.data = buffer; bit_file->capacity += chunk_size; } bit_file->raw_file.data[bit_file->raw_file.length++] = byte; return ERROR_OK; } static int gatemate_read_cfg_line(struct gatemate_bit_file *bit_file, const char *line_buffer, size_t nread) { for (size_t idx = 0; idx < nread; ++idx) { if (line_buffer[idx] == ' ') { continue; } else if (line_buffer[idx] == 0) { break; } else if (idx + 1 < nread) { if (isxdigit(line_buffer[idx]) && isxdigit(line_buffer[idx + 1])) { uint8_t byte; unhexify(&byte, line_buffer + idx, 2); int retval = gatemate_add_byte_to_bitfile(bit_file, byte); if (retval != ERROR_OK) return retval; } else if (line_buffer[idx] == '/' && line_buffer[idx + 1] == '/') { break; } ++idx; } else { LOG_ERROR("parsing failed"); return ERROR_FAIL; } } return ERROR_OK; } static int gatemate_getline(char **buffer, size_t *buf_size, FILE *input_file) { const size_t chunk_size = 32; if (!*buffer) *buf_size = 0; size_t read = 0; do { if (read + 1 > *buf_size) { char *new_buffer; if (*buffer) new_buffer = realloc(*buffer, *buf_size + chunk_size); else new_buffer = malloc(chunk_size); if (!new_buffer) { LOG_ERROR("Out of memory"); return -1; } *buffer = new_buffer; *buf_size += chunk_size; } int c = fgetc(input_file); if ((c == EOF && read) || (char)c == '\n') { (*buffer)[read++] = 0; return read; } else if (c == EOF) { return -1; } (*buffer)[read++] = (char)c; } while (1); return -1; } static int gatemate_read_cfg_file(struct gatemate_bit_file *bit_file, const char *filename) { FILE *input_file = fopen(filename, "r"); if (!input_file) { LOG_ERROR("Couldn't open %s: %s", filename, strerror(errno)); return ERROR_PLD_FILE_LOAD_FAILED; } int retval = ERROR_OK; char *line_buffer = NULL; size_t buffer_length = 0; int nread; while (((nread = gatemate_getline(&line_buffer, &buffer_length, input_file)) != -1) && (retval == ERROR_OK)) retval = gatemate_read_cfg_line(bit_file, line_buffer, (size_t)nread); if (line_buffer) free(line_buffer); fclose(input_file); if (retval != ERROR_OK) free(bit_file->raw_file.data); return retval; } static int gatemate_read_file(struct gatemate_bit_file *bit_file, const char *filename) { memset(bit_file, 0, sizeof(struct gatemate_bit_file)); if (!filename || !bit_file) return ERROR_COMMAND_SYNTAX_ERROR; /* check if binary .bit or ascii .cfg */ const char *file_suffix_pos = strrchr(filename, '.'); if (!file_suffix_pos) { LOG_ERROR("Unable to detect filename suffix"); return ERROR_PLD_FILE_LOAD_FAILED; } if (strcasecmp(file_suffix_pos, ".bit") == 0) return cpld_read_raw_bit_file(&bit_file->raw_file, filename); else if (strcasecmp(file_suffix_pos, ".cfg") == 0) return gatemate_read_cfg_file(bit_file, filename); LOG_ERROR("Filetype not supported, expecting .bit or .cfg file"); return ERROR_PLD_FILE_LOAD_FAILED; } static int gatemate_set_instr(struct jtag_tap *tap, uint8_t new_instr) { struct scan_field field; field.num_bits = tap->ir_length; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); jtag_add_runtest(3, TAP_IDLE); free(t); return ERROR_OK; } static int gatemate_load(struct pld_device *pld_device, const char *filename) { if (!pld_device) return ERROR_FAIL; struct gatemate_pld_device *gatemate_info = pld_device->driver_priv; if (!gatemate_info || !gatemate_info->tap) return ERROR_FAIL; struct jtag_tap *tap = gatemate_info->tap; struct gatemate_bit_file bit_file; int retval = gatemate_read_file(&bit_file, filename); if (retval != ERROR_OK) return retval; retval = gatemate_set_instr(tap, JTAG_CONFIGURE); if (retval != ERROR_OK) { free(bit_file.raw_file.data); return retval; } struct scan_field field; field.num_bits = bit_file.raw_file.length * 8; field.out_value = bit_file.raw_file.data; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); retval = jtag_execute_queue(); free(bit_file.raw_file.data); return retval; } PLD_CREATE_COMMAND_HANDLER(gatemate_pld_create_command) { if (CMD_ARGC != 4) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[2], "-chain-position") != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); if (!tap) { command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); return ERROR_FAIL; } struct gatemate_pld_device *gatemate_info = malloc(sizeof(struct gatemate_pld_device)); if (!gatemate_info) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } gatemate_info->tap = tap; pld->driver_priv = gatemate_info; return ERROR_OK; } struct pld_driver gatemate_pld = { .name = "gatemate", .pld_create_command = &gatemate_pld_create_command, .load = &gatemate_load, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/gowin.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/jtag.h> #include <jtag/adapter.h> #include <helper/bits.h> #include "pld.h" #include "raw_bit.h" #define NO_OP 0x02 #define ERASE_SRAM 0x05 #define SRAM_ERASE_DONE 0x09 #define IDCODE 0x11 #define ADDRESS_INITIALIZATION 0x12 #define READ_USERCODE 0x13 #define CONFIG_ENABLE 0x15 #define TRANSFER_CONFIGURATION_DATA 0x17 #define CONFIG_DISABLE 0x3A #define RELOAD 0x3C #define STATUS_REGISTER 0x41 #define ERASE_FLASH 0x75 #define ENABLE_2ND_FLASH 0x78 #define USER1 0x42 #define USER2 0x43 #define STAUS_MASK_MEMORY_ERASE BIT(5) #define STAUS_MASK_SYSTEM_EDIT_MODE BIT(7) struct gowin_pld_device { struct jtag_tap *tap; }; struct gowin_bit_file { struct raw_bit_file raw_file; size_t capacity; uint32_t id; uint16_t stored_checksum; int compressed; int crc_en; uint16_t checksum; uint8_t replace8x; uint8_t replace4x; uint8_t replace2x; }; static uint64_t gowin_read_fs_file_bitsequence(const char *bits, int length) { uint64_t res = 0; for (int i = 0; i < length; i++) res = (res << 1) | (*bits++ == '1' ? 1 : 0); return res; } static int gowin_add_byte_to_bit_file(struct gowin_bit_file *bit_file, uint8_t byte) { if (bit_file->raw_file.length + 1 > bit_file->capacity) { uint8_t *buffer; if (bit_file->raw_file.data) buffer = realloc(bit_file->raw_file.data, bit_file->capacity + 8192); else buffer = malloc(8192); if (!buffer) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } bit_file->raw_file.data = buffer; bit_file->capacity += 8192; } bit_file->raw_file.data[bit_file->raw_file.length++] = byte; return ERROR_OK; } static int gowin_read_fs_file_header(struct gowin_bit_file *bit_file, FILE *stream) { if (!bit_file) return ERROR_FAIL; int end_of_header = 0; while (!end_of_header) { char buffer[256]; char *line = fgets(buffer, 256, stream); if (!line || feof(stream) || ferror(stream)) return ERROR_FAIL; if (line[0] == '/') continue; size_t line_length = strlen(line); if (line[line_length - 1] != '\n') return ERROR_FAIL; line_length--; for (unsigned int i = 0; i < line_length; i += 8) { uint8_t byte = gowin_read_fs_file_bitsequence(line + i, 8); int retval = gowin_add_byte_to_bit_file(bit_file, byte); if (retval != ERROR_OK) return retval; } uint8_t key = gowin_read_fs_file_bitsequence(line, 8); line += 8; uint64_t value = gowin_read_fs_file_bitsequence(line, line_length - 8); if (key == 0x06) { bit_file->id = value & 0xffffffff; } else if (key == 0x3B) { end_of_header = 1; bit_file->crc_en = (value & BIT(23)) ? 1 : 0; } } return ERROR_OK; } static int gowin_read_fs_file(struct gowin_bit_file *bit_file, const char *filename) { FILE *input_file = fopen(filename, "r"); if (!input_file) { LOG_ERROR("Couldn't open %s: %s", filename, strerror(errno)); return ERROR_PLD_FILE_LOAD_FAILED; } int retval = gowin_read_fs_file_header(bit_file, input_file); if (retval != ERROR_OK) { free(bit_file->raw_file.data); fclose(input_file); return retval; } char digits_buffer[9]; /* 8 + 1 trailing zero */ do { char *digits = fgets(digits_buffer, 9, input_file); if (feof(input_file)) break; if (!digits || ferror(input_file)) { free(bit_file->raw_file.data); fclose(input_file); return ERROR_FAIL; } if (digits[0] == '\n') continue; if (strlen(digits) != 8) { free(bit_file->raw_file.data); fclose(input_file); return ERROR_FAIL; } uint8_t byte = gowin_read_fs_file_bitsequence(digits, 8); retval = gowin_add_byte_to_bit_file(bit_file, byte); if (retval != ERROR_OK) { free(bit_file->raw_file.data); fclose(input_file); return ERROR_FAIL; } } while (1); fclose(input_file); return ERROR_OK; } static int gowin_read_file(struct gowin_bit_file *bit_file, const char *filename, bool *is_fs) { memset(bit_file, 0, sizeof(struct gowin_bit_file)); if (!filename || !bit_file) return ERROR_COMMAND_SYNTAX_ERROR; const char *file_suffix_pos = strrchr(filename, '.'); if (!file_suffix_pos) { LOG_ERROR("Unable to detect filename suffix"); return ERROR_PLD_FILE_LOAD_FAILED; } /* check if binary .bin or ascii .fs */ if (strcasecmp(file_suffix_pos, ".bin") == 0) { *is_fs = false; return cpld_read_raw_bit_file(&bit_file->raw_file, filename); } else if (strcasecmp(file_suffix_pos, ".fs") == 0) { *is_fs = true; return gowin_read_fs_file(bit_file, filename); } LOG_ERROR("Filetype not supported, expecting .fs or .bin file"); return ERROR_PLD_FILE_LOAD_FAILED; } static int gowin_set_instr(struct jtag_tap *tap, uint8_t new_instr) { struct scan_field field; field.num_bits = tap->ir_length; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); jtag_add_runtest(3, TAP_IDLE); free(t); return ERROR_OK; } static int gowin_read_register(struct jtag_tap *tap, uint32_t reg, uint32_t *result) { struct scan_field field; int retval = gowin_set_instr(tap, reg); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; uint8_t buf[4] = {0}; field.check_mask = NULL; field.check_value = NULL; field.num_bits = 32; field.out_value = buf; field.in_value = buf; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); retval = jtag_execute_queue(); *result = le_to_h_u32(buf); return retval; } static int gowin_check_status_flag(struct jtag_tap *tap, uint32_t mask, uint32_t flag) { uint32_t status = 0; int retries = 0; do { int retval = gowin_read_register(tap, STATUS_REGISTER, &status); if (retval != ERROR_OK) return retval; if (retries++ == 100000) return ERROR_FAIL; } while ((status & mask) != flag); return ERROR_OK; } static int gowin_enable_config(struct jtag_tap *tap) { int retval = gowin_set_instr(tap, CONFIG_ENABLE); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; return gowin_check_status_flag(tap, STAUS_MASK_SYSTEM_EDIT_MODE, STAUS_MASK_SYSTEM_EDIT_MODE); } static int gowin_disable_config(struct jtag_tap *tap) { int retval = gowin_set_instr(tap, CONFIG_DISABLE); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; return gowin_check_status_flag(tap, STAUS_MASK_SYSTEM_EDIT_MODE, 0); } static int gowin_reload(struct jtag_tap *tap) { int retval = gowin_set_instr(tap, RELOAD); if (retval != ERROR_OK) return retval; retval = gowin_set_instr(tap, NO_OP); if (retval != ERROR_OK) return retval; return jtag_execute_queue(); } static int gowin_runtest_idle(struct jtag_tap *tap, unsigned int frac_sec) { int speed = adapter_get_speed_khz() * 1000; int cycles = DIV_ROUND_UP(speed, frac_sec); jtag_add_runtest(cycles, TAP_IDLE); return jtag_execute_queue(); } static int gowin_erase_sram(struct jtag_tap *tap, bool tx_erase_done) { /* config is already enabled */ int retval = gowin_set_instr(tap, ERASE_SRAM); if (retval != ERROR_OK) return retval; retval = gowin_set_instr(tap, NO_OP); if (retval != ERROR_OK) return retval; /* Delay or Run Test 2~10ms */ /* 10 ms is worst case for GW2A-55 */ jtag_add_sleep(10000); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; retval = gowin_check_status_flag(tap, STAUS_MASK_MEMORY_ERASE, STAUS_MASK_MEMORY_ERASE); if (retval != ERROR_OK) return retval; if (tx_erase_done) { retval = gowin_set_instr(tap, SRAM_ERASE_DONE); if (retval != ERROR_OK) return retval; retval = gowin_set_instr(tap, NO_OP); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* gen clock cycles in RUN/IDLE for 500us -> 1/500us = 2000/s */ retval = gowin_runtest_idle(tap, 2000); if (retval != ERROR_OK) return retval; } retval = gowin_set_instr(tap, NO_OP); if (retval != ERROR_OK) return retval; return jtag_execute_queue(); } static int gowin_load_to_sram(struct pld_device *pld_device, const char *filename) { if (!pld_device) return ERROR_FAIL; struct gowin_pld_device *gowin_info = pld_device->driver_priv; if (!gowin_info || !gowin_info->tap) return ERROR_FAIL; struct jtag_tap *tap = gowin_info->tap; bool is_fs = false; struct gowin_bit_file bit_file; int retval = gowin_read_file(&bit_file, filename, &is_fs); if (retval != ERROR_OK) return retval; for (unsigned int i = 0; i < bit_file.raw_file.length; i++) bit_file.raw_file.data[i] = flip_u32(bit_file.raw_file.data[i], 8); uint32_t id; retval = gowin_read_register(tap, IDCODE, &id); if (retval != ERROR_OK) { free(bit_file.raw_file.data); return retval; } if (is_fs && id != bit_file.id) { free(bit_file.raw_file.data); LOG_ERROR("Id on device (0x%8.8" PRIx32 ") and id in bit-stream (0x%8.8" PRIx32 ") don't match.", id, bit_file.id); return ERROR_FAIL; } retval = gowin_enable_config(tap); if (retval != ERROR_OK) { free(bit_file.raw_file.data); return retval; } retval = gowin_erase_sram(tap, false); if (retval != ERROR_OK) { free(bit_file.raw_file.data); return retval; } retval = gowin_set_instr(tap, ADDRESS_INITIALIZATION); if (retval != ERROR_OK) { free(bit_file.raw_file.data); return retval; } retval = gowin_set_instr(tap, TRANSFER_CONFIGURATION_DATA); if (retval != ERROR_OK) { free(bit_file.raw_file.data); return retval; } /* scan out the bitstream */ struct scan_field field; field.num_bits = bit_file.raw_file.length * 8; field.out_value = bit_file.raw_file.data; field.in_value = bit_file.raw_file.data; jtag_add_dr_scan(gowin_info->tap, 1, &field, TAP_IDLE); jtag_add_runtest(3, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) { free(bit_file.raw_file.data); return retval; } retval = gowin_disable_config(tap); free(bit_file.raw_file.data); if (retval != ERROR_OK) return retval; retval = gowin_set_instr(gowin_info->tap, NO_OP); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); return retval; } static int gowin_read_register_command(struct pld_device *pld_device, uint32_t cmd, uint32_t *value) { if (!pld_device) return ERROR_FAIL; struct gowin_pld_device *gowin_info = pld_device->driver_priv; if (!gowin_info || !gowin_info->tap) return ERROR_FAIL; return gowin_read_register(gowin_info->tap, cmd, value); } static int gowin_reload_command(struct pld_device *pld_device) { if (!pld_device) return ERROR_FAIL; struct gowin_pld_device *gowin_info = pld_device->driver_priv; if (!gowin_info || !gowin_info->tap) return ERROR_FAIL; return gowin_reload(gowin_info->tap); } static int gowin_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) { if (!pld_device) return ERROR_FAIL; struct gowin_pld_device *pld_device_info = pld_device->driver_priv; if (!pld_device_info || !pld_device_info->tap) return ERROR_FAIL; hub->tap = pld_device_info->tap; if (user_num == 1) { hub->user_ir_code = USER1; } else if (user_num == 2) { hub->user_ir_code = USER2; } else { LOG_ERROR("gowin devices only have user register 1 & 2"); return ERROR_FAIL; } return ERROR_OK; } COMMAND_HANDLER(gowin_read_status_command_handler) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } uint32_t status = 0; int retval = gowin_read_register_command(device, STATUS_REGISTER, &status); if (retval == ERROR_OK) command_print(CMD, "0x%8.8" PRIx32, status); return retval; } COMMAND_HANDLER(gowin_read_user_register_command_handler) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } uint32_t user_reg = 0; int retval = gowin_read_register_command(device, READ_USERCODE, &user_reg); if (retval == ERROR_OK) command_print(CMD, "0x%8.8" PRIx32, user_reg); return retval; } COMMAND_HANDLER(gowin_reload_command_handler) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } return gowin_reload_command(device); } static const struct command_registration gowin_exec_command_handlers[] = { { .name = "read_status", .mode = COMMAND_EXEC, .handler = gowin_read_status_command_handler, .help = "reading status register from FPGA", .usage = "pld_name", }, { .name = "read_user", .mode = COMMAND_EXEC, .handler = gowin_read_user_register_command_handler, .help = "reading user register from FPGA", .usage = "pld_name", }, { .name = "reload", .mode = COMMAND_EXEC, .handler = gowin_reload_command_handler, .help = "reloading bitstream from flash to SRAM", .usage = "pld_name", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration gowin_command_handler[] = { { .name = "gowin", .mode = COMMAND_ANY, .help = "gowin specific commands", .usage = "", .chain = gowin_exec_command_handlers }, COMMAND_REGISTRATION_DONE }; PLD_CREATE_COMMAND_HANDLER(gowin_pld_create_command) { if (CMD_ARGC != 4) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[2], "-chain-position") != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); if (!tap) { command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); return ERROR_FAIL; } struct gowin_pld_device *gowin_info = malloc(sizeof(struct gowin_pld_device)); if (!gowin_info) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } gowin_info->tap = tap; pld->driver_priv = gowin_info; return ERROR_OK; } struct pld_driver gowin_pld = { .name = "gowin", .commands = gowin_command_handler, .pld_create_command = &gowin_pld_create_command, .load = &gowin_load_to_sram, .get_ipdbg_hub = gowin_get_ipdbg_hub, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/intel.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/jtag.h> #include <jtag/adapter.h> #include <helper/system.h> #include <helper/log.h> #include "pld.h" #include "raw_bit.h" #define BYPASS 0x3FF #define USER0 0x00C #define USER1 0x00E enum intel_family_e { INTEL_CYCLONEIII, INTEL_CYCLONEIV, INTEL_CYCLONEV, INTEL_CYCLONE10, INTEL_ARRIAII, INTEL_UNKNOWN }; struct intel_pld_device { struct jtag_tap *tap; unsigned int boundary_scan_length; int checkpos; enum intel_family_e family; }; struct intel_device_parameters_elem { uint32_t id; unsigned int boundary_scan_length; int checkpos; enum intel_family_e family; }; static const struct intel_device_parameters_elem intel_device_parameters[] = { {0x020f10dd, 603, 226, INTEL_CYCLONEIII}, /* EP3C5 EP3C10 */ {0x020f20dd, 1080, 409, INTEL_CYCLONEIII}, /* EP3C16 */ {0x020f30dd, 732, 286, INTEL_CYCLONEIII}, /* EP3C25 */ {0x020f40dd, 1632, 604, INTEL_CYCLONEIII}, /* EP3C40 */ {0x020f50dd, 1164, 442, INTEL_CYCLONEIII}, /* EP3C55 */ {0x020f60dd, 1314, 502, INTEL_CYCLONEIII}, /* EP3C80 */ {0x020f70dd, 1620, 613, INTEL_CYCLONEIII}, /* EP3C120*/ {0x027010dd, 1314, 226, INTEL_CYCLONEIII}, /* EP3CLS70 */ {0x027000dd, 1314, 226, INTEL_CYCLONEIII}, /* EP3CLS100 */ {0x027030dd, 1314, 409, INTEL_CYCLONEIII}, /* EP3CLS150 */ {0x027020dd, 1314, 409, INTEL_CYCLONEIII}, /* EP3CLS200 */ {0x020f10dd, 603, 226, INTEL_CYCLONEIV}, /* EP4CE6 EP4CE10 */ {0x020f20dd, 1080, 409, INTEL_CYCLONEIV}, /* EP4CE15 */ {0x020f30dd, 732, 286, INTEL_CYCLONEIV}, /* EP4CE22 */ {0x020f40dd, 1632, 604, INTEL_CYCLONEIV}, /* EP4CE30 EP4CE40 */ {0x020f50dd, 1164, 442, INTEL_CYCLONEIV}, /* EP4CE55 */ {0x020f60dd, 1314, 502, INTEL_CYCLONEIV}, /* EP4CE75 */ {0x020f70dd, 1620, 613, INTEL_CYCLONEIV}, /* EP4CE115 */ {0x028010dd, 260, 229, INTEL_CYCLONEIV}, /* EP4CGX15 */ {0x028120dd, 494, 463, INTEL_CYCLONEIV}, /* EP4CGX22 */ {0x028020dd, 494, 463, INTEL_CYCLONEIV}, /* EP4CGX30 */ {0x028230dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX30 */ {0x028130dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX50 */ {0x028030dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX75 */ {0x028140dd, 1495, 1438, INTEL_CYCLONEIV}, /* EP4CGX110 */ {0x028040dd, 1495, 1438, INTEL_CYCLONEIV}, /* EP4CGX150 */ {0x02b150dd, 864, 163, INTEL_CYCLONEV}, /* 5CEBA2F23 5CEBA2F17 5CEFA2M13 5CEFA2F23 5CEBA2U15 5CEFA2U19 5CEBA2U19 */ {0x02d020dd, 1485, 19, INTEL_CYCLONEV}, /* 5CSXFC6D6F31 5CSTFD6D5F31 5CSEBA6U23 5CSEMA6U23 5CSEBA6U19 5CSEBA6U23 5CSEBA6U19 5CSEMA6F31 5CSXFC6C6U23 */ {0x02b040dd, 1728, -1, INTEL_CYCLONEV}, /* 5CGXFC9EF35 5CGXBC9AU19 5CGXBC9CF23 5CGTFD9CF23 5CGXFC9AU19 5CGXFC9CF23 5CGXFC9EF31 5CGXFC9DF27 5CGXBC9DF27 5CGXBC9EF31 5CGTFD9EF31 5CGTFD9EF35 5CGTFD9AU19 5CGXBC9EF35 5CGTFD9DF27 */ {0x02b050dd, 864, 163, INTEL_CYCLONEV}, /* 5CEFA4U19 5CEFA4F23 5CEFA4M13 5CEBA4F17 5CEBA4U15 5CEBA4U19 5CEBA4F23 */ {0x02b030dd, 1488, 19, INTEL_CYCLONEV}, /* 5CGXBC7CU19 5CGTFD7CU19 5CGTFD7DF27 5CGXFC7BM15 5CGXFC7DF27 5CGXFC7DF31 5CGTFD7CF23 5CGXBC7CF23 5CGXBC7DF31 5CGTFD7BM15 5CGXFC7CU19 5CGTFD7DF31 5CGXBC7BM15 5CGXFC7CF23 5CGXBC7DF27 */ {0x02d120dd, 1485, -1, INTEL_CYCLONEV}, /* 5CSEBA5U23 5CSEBA5U23 5CSTFD5D5F31 5CSEBA5U19 5CSXFC5D6F31 5CSEMA5U23 5CSEMA5F31 5CSXFC5C6U23 5CSEBA5U19 */ {0x02b220dd, 1104, 19, INTEL_CYCLONEV}, /* 5CEBA5U19 5CEFA5U19 5CEFA5M13 5CEBA5F23 5CEFA5F23 */ {0x02b020dd, 1104, 19, INTEL_CYCLONEV}, /* 5CGXBC5CU19 5CGXFC5F6M11 5CGXFC5CM13 5CGTFD5CF23 5CGXBC5CF23 5CGTFD5CF27 5CGTFD5F5M11 5CGXFC5CF27 5CGXFC5CU19 5CGTFD5CM13 5CGXFC5CF23 5CGXBC5CF27 5CGTFD5CU19 */ {0x02d010dd, 1197, -1, INTEL_CYCLONEV}, /* 5CSEBA4U23 5CSXFC4C6U23 5CSEMA4U23 5CSEBA4U23 5CSEBA4U19 5CSEBA4U19 5CSXFC2C6U23 */ {0x02b120dd, 1104, 19, INTEL_CYCLONEV}, /* 5CGXFC4CM13 5CGXFC4CU19 5CGXFC4F6M11 5CGXBC4CU19 5CGXFC4CF27 5CGXBC4CF23 5CGXBC4CF27 5CGXFC4CF23 */ {0x02b140dd, 1728, -1, INTEL_CYCLONEV}, /* 5CEFA9F31 5CEBA9F31 5CEFA9F27 5CEBA9U19 5CEBA9F27 5CEFA9U19 5CEBA9F23 5CEFA9F23 */ {0x02b010dd, 720, 19, INTEL_CYCLONEV}, /* 5CGXFC3U15 5CGXBC3U15 5CGXFC3F23 5CGXFC3U19 5CGXBC3U19 5CGXBC3F23 */ {0x02b130dd, 1488, 19, INTEL_CYCLONEV}, /* 5CEFA7F31 5CEBA7F27 5CEBA7M15 5CEFA7U19 5CEBA7F23 5CEFA7F23 5CEFA7F27 5CEFA7M15 5CEBA7U19 5CEBA7F31 */ {0x02d110dd, 1197, -1, INTEL_CYCLONEV}, /* 5CSEBA2U23 5CSEMA2U23 5CSEBA2U23 5CSEBA2U19 5CSEBA2U19 */ {0x020f10dd, 603, 226, INTEL_CYCLONE10}, /* 10CL006E144 10CL006U256 10CL010M164 10CL010U256 10CL010E144 */ {0x020f20dd, 1080, 409, INTEL_CYCLONE10}, /* 10CL016U256 10CL016E144 10CL016U484 10CL016F484 10CL016M164 */ {0x020f30dd, 732, 286, INTEL_CYCLONE10}, /* 10CL025U256 10CL025E144 */ {0x020f40dd, 1632, 604, INTEL_CYCLONE10}, /* 10CL040F484 10CL040U484 */ {0x020f50dd, 1164, 442, INTEL_CYCLONE10}, /* 10CL055F484 10CL055U484 */ {0x020f60dd, 1314, 502, INTEL_CYCLONE10}, /* 10CL080F484 10CL080F780 10CL080U484 */ {0x020f70dd, 1620, 613, INTEL_CYCLONE10}, /* 10CL120F484 10CL120F780 */ {0x02e120dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX085U484 10CX085F672 */ {0x02e320dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX105F780 10CX105U484 10CX105F672 */ {0x02e720dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX150F672 10CX150F780 10CX150U484 */ {0x02ef20dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX220F672 10CX220F780 10CX220U484 */ {0x025120dd, 1227, 1174, INTEL_ARRIAII}, /* EP2AGX45 */ {0x025020dd, 1227, -1, INTEL_ARRIAII}, /* EP2AGX65 */ {0x025130dd, 1467, -1, INTEL_ARRIAII}, /* EP2AGX95 */ {0x025030dd, 1467, -1, INTEL_ARRIAII}, /* EP2AGX125 */ {0x025140dd, 1971, -1, INTEL_ARRIAII}, /* EP2AGX190 */ {0x025040dd, 1971, -1, INTEL_ARRIAII}, /* EP2AGX260 */ {0x024810dd, 2274, -1, INTEL_ARRIAII}, /* EP2AGZ225 */ {0x0240a0dd, 2682, -1, INTEL_ARRIAII}, /* EP2AGZ300 */ {0x024820dd, 2682, -1, INTEL_ARRIAII}, /* EP2AGZ350 */ }; static int intel_fill_device_parameters(struct intel_pld_device *intel_info) { for (size_t i = 0; i < ARRAY_SIZE(intel_device_parameters); ++i) { if (intel_device_parameters[i].id == intel_info->tap->idcode && intel_info->family == intel_device_parameters[i].family) { if (intel_info->boundary_scan_length == 0) intel_info->boundary_scan_length = intel_device_parameters[i].boundary_scan_length; if (intel_info->checkpos == -1) intel_info->checkpos = intel_device_parameters[i].checkpos; return ERROR_OK; } } return ERROR_FAIL; } static int intel_check_for_unique_id(struct intel_pld_device *intel_info) { int found = 0; for (size_t i = 0; i < ARRAY_SIZE(intel_device_parameters); ++i) { if (intel_device_parameters[i].id == intel_info->tap->idcode) { ++found; intel_info->family = intel_device_parameters[i].family; } } return (found == 1) ? ERROR_OK : ERROR_FAIL; } static int intel_check_config(struct intel_pld_device *intel_info) { if (!intel_info->tap->hasidcode) { LOG_ERROR("no IDCODE"); return ERROR_FAIL; } if (intel_info->family == INTEL_UNKNOWN) { if (intel_check_for_unique_id(intel_info) != ERROR_OK) { LOG_ERROR("id is ambiguous, please specify family"); return ERROR_FAIL; } } if (intel_info->boundary_scan_length == 0 || intel_info->checkpos == -1) { int ret = intel_fill_device_parameters(intel_info); if (ret != ERROR_OK) return ret; } if (intel_info->checkpos >= 0 && (unsigned int)intel_info->checkpos >= intel_info->boundary_scan_length) { LOG_ERROR("checkpos has to be smaller than scan length %d < %u", intel_info->checkpos, intel_info->boundary_scan_length); return ERROR_FAIL; } return ERROR_OK; } static int intel_read_file(struct raw_bit_file *bit_file, const char *filename) { if (!filename || !bit_file) return ERROR_COMMAND_SYNTAX_ERROR; /* check if binary .bin or ascii .bit/.hex */ const char *file_ending_pos = strrchr(filename, '.'); if (!file_ending_pos) { LOG_ERROR("Unable to detect filename suffix"); return ERROR_PLD_FILE_LOAD_FAILED; } if (strcasecmp(file_ending_pos, ".rbf") == 0) return cpld_read_raw_bit_file(bit_file, filename); LOG_ERROR("Unable to detect filetype"); return ERROR_PLD_FILE_LOAD_FAILED; } static int intel_set_instr(struct jtag_tap *tap, uint16_t new_instr) { struct scan_field field; field.num_bits = tap->ir_length; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); free(t); return ERROR_OK; } static int intel_load(struct pld_device *pld_device, const char *filename) { unsigned int speed = adapter_get_speed_khz(); if (speed < 1) speed = 1; unsigned int cycles = DIV_ROUND_UP(speed, 200); if (cycles < 1) cycles = 1; if (!pld_device || !pld_device->driver_priv) return ERROR_FAIL; struct intel_pld_device *intel_info = pld_device->driver_priv; if (!intel_info || !intel_info->tap) return ERROR_FAIL; struct jtag_tap *tap = intel_info->tap; int retval = intel_check_config(intel_info); if (retval != ERROR_OK) return retval; struct raw_bit_file bit_file; retval = intel_read_file(&bit_file, filename); if (retval != ERROR_OK) return retval; if (retval != ERROR_OK) return retval; retval = intel_set_instr(tap, 0x002); if (retval != ERROR_OK) { free(bit_file.data); return retval; } jtag_add_runtest(speed, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) { free(bit_file.data); return retval; } /* shift in the bitstream */ struct scan_field field; field.num_bits = bit_file.length * 8; field.out_value = bit_file.data; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_DRPAUSE); retval = jtag_execute_queue(); free(bit_file.data); if (retval != ERROR_OK) return retval; retval = intel_set_instr(tap, 0x004); if (retval != ERROR_OK) return retval; jtag_add_runtest(cycles, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (intel_info->boundary_scan_length != 0) { uint8_t *buf = calloc(DIV_ROUND_UP(intel_info->boundary_scan_length, 8), 1); if (!buf) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } field.num_bits = intel_info->boundary_scan_length; field.out_value = buf; field.in_value = buf; jtag_add_dr_scan(tap, 1, &field, TAP_DRPAUSE); retval = jtag_execute_queue(); if (retval != ERROR_OK) { free(buf); return retval; } if (intel_info->checkpos != -1) retval = ((buf[intel_info->checkpos / 8] & (1 << (intel_info->checkpos % 8)))) ? ERROR_OK : ERROR_FAIL; free(buf); if (retval != ERROR_OK) { LOG_ERROR("Check failed"); return ERROR_FAIL; } } retval = intel_set_instr(tap, 0x003); if (retval != ERROR_OK) return retval; switch (intel_info->family) { case INTEL_CYCLONEIII: case INTEL_CYCLONEIV: jtag_add_runtest(5 * speed + 512, TAP_IDLE); break; case INTEL_CYCLONEV: jtag_add_runtest(5 * speed + 512, TAP_IDLE); break; case INTEL_CYCLONE10: jtag_add_runtest(DIV_ROUND_UP(512ul * speed, 125ul) + 512, TAP_IDLE); break; case INTEL_ARRIAII: jtag_add_runtest(DIV_ROUND_UP(64ul * speed, 125ul) + 512, TAP_IDLE); break; case INTEL_UNKNOWN: LOG_ERROR("unknown family"); return ERROR_FAIL; } retval = intel_set_instr(tap, BYPASS); if (retval != ERROR_OK) return retval; jtag_add_runtest(speed, TAP_IDLE); return jtag_execute_queue(); } static int intel_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) { if (!pld_device) return ERROR_FAIL; struct intel_pld_device *pld_device_info = pld_device->driver_priv; if (!pld_device_info || !pld_device_info->tap) return ERROR_FAIL; hub->tap = pld_device_info->tap; if (user_num == 0) { hub->user_ir_code = USER0; } else if (user_num == 1) { hub->user_ir_code = USER1; } else { LOG_ERROR("intel devices only have user register 0 & 1"); return ERROR_FAIL; } return ERROR_OK; } COMMAND_HANDLER(intel_set_bscan_command_handler) { unsigned int boundary_scan_length; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; struct pld_device *pld_device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!pld_device) { command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], boundary_scan_length); struct intel_pld_device *intel_info = pld_device->driver_priv; if (!intel_info) return ERROR_FAIL; intel_info->boundary_scan_length = boundary_scan_length; return ERROR_OK; } COMMAND_HANDLER(intel_set_check_pos_command_handler) { int checkpos; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; struct pld_device *pld_device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!pld_device) { command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], checkpos); struct intel_pld_device *intel_info = pld_device->driver_priv; if (!intel_info) return ERROR_FAIL; intel_info->checkpos = checkpos; return ERROR_OK; } PLD_CREATE_COMMAND_HANDLER(intel_pld_create_command) { if (CMD_ARGC != 4 && CMD_ARGC != 6) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[2], "-chain-position") != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); if (!tap) { command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); return ERROR_FAIL; } enum intel_family_e family = INTEL_UNKNOWN; if (CMD_ARGC == 6) { if (strcmp(CMD_ARGV[4], "-family") != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[5], "cycloneiii") == 0) { family = INTEL_CYCLONEIII; } else if (strcmp(CMD_ARGV[5], "cycloneiv") == 0) { family = INTEL_CYCLONEIV; } else if (strcmp(CMD_ARGV[5], "cyclonev") == 0) { family = INTEL_CYCLONEV; } else if (strcmp(CMD_ARGV[5], "cyclone10") == 0) { family = INTEL_CYCLONE10; } else if (strcmp(CMD_ARGV[5], "arriaii") == 0) { family = INTEL_ARRIAII; } else { command_print(CMD, "unknown family"); return ERROR_FAIL; } } struct intel_pld_device *intel_info = malloc(sizeof(struct intel_pld_device)); if (!intel_info) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } intel_info->tap = tap; intel_info->boundary_scan_length = 0; intel_info->checkpos = -1; intel_info->family = family; pld->driver_priv = intel_info; return ERROR_OK; } static const struct command_registration intel_exec_command_handlers[] = { { .name = "set_bscan", .mode = COMMAND_EXEC, .handler = intel_set_bscan_command_handler, .help = "set boundary scan register length of FPGA", .usage = "pld_name len", }, { .name = "set_check_pos", .mode = COMMAND_EXEC, .handler = intel_set_check_pos_command_handler, .help = "set check_pos of FPGA", .usage = "pld_name pos", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration intel_command_handler[] = { { .name = "intel", .mode = COMMAND_ANY, .help = "intel specific commands", .usage = "", .chain = intel_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct pld_driver intel_pld = { .name = "intel", .commands = intel_command_handler, .pld_create_command = &intel_pld_create_command, .load = &intel_load, .get_ipdbg_hub = intel_get_ipdbg_hub, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/lattice.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "lattice.h" #include <jtag/jtag.h> #include "pld.h" #include "lattice_bit.h" #include "ecp2_3.h" #include "ecp5.h" #include "certus.h" #define PRELOAD 0x1C #define USER1 0x32 #define USER2 0x38 struct lattice_devices_elem { uint32_t id; size_t preload_length; enum lattice_family_e family; }; static const struct lattice_devices_elem lattice_devices[] = { {0x01270043, 654, LATTICE_ECP2 /* ecp2-6e */}, {0x01271043, 643, LATTICE_ECP2 /* ecp2-12e */}, {0x01272043, 827, LATTICE_ECP2 /* ecp2-20e */}, {0x01274043, 1011, LATTICE_ECP2 /* ecp2-35e */}, {0x01273043, 1219, LATTICE_ECP2 /* ecp2-50e */}, {0x01275043, 654, LATTICE_ECP2 /* ecp2-70e */}, {0x01279043, 680, LATTICE_ECP2 /* ecp2m20e */}, {0x0127A043, 936, LATTICE_ECP2 /* ecp2m35e */}, {0x0127B043, 1056, LATTICE_ECP2 /* ecp2m50e */}, {0x0127C043, 1039, LATTICE_ECP2 /* ecp2m70e */}, {0x0127D043, 1311, LATTICE_ECP2 /* ecp2m100e */}, {0x01010043, 467, LATTICE_ECP3 /* ecp3 lae3-17ea & lfe3-17ea*/}, {0x01012043, 675, LATTICE_ECP3 /* ecp3 lae3-35ea & lfe3-35ea*/}, {0x01014043, 1077, LATTICE_ECP3 /* ecp3 lfe3-70ea & lfe3-70e & lfe3-95ea && lfe3-95e*/}, {0x01015043, 1326, LATTICE_ECP3 /* ecp3 lfe3-150e*/}, {0x21111043, 409, LATTICE_ECP5 /* "LAE5U-12F & LFE5U-12F" */}, {0x41111043, 409, LATTICE_ECP5 /* "LFE5U-25F" */}, {0x41112043, 510, LATTICE_ECP5 /* "LFE5U-45F" */}, {0x41113043, 750, LATTICE_ECP5 /* "LFE5U-85F" */}, {0x81111043, 409, LATTICE_ECP5 /* "LFE5UM5G-25F" */}, {0x81112043, 510, LATTICE_ECP5 /* "LFE5UM5G-45F" */}, {0x81113043, 750, LATTICE_ECP5 /* "LFE5UM5G-85F" */}, {0x01111043, 409, LATTICE_ECP5 /* "LAE5UM-25F" */}, {0x01112043, 510, LATTICE_ECP5 /* "LAE5UM-45F" */}, {0x01113043, 750, LATTICE_ECP5 /* "LAE5UM-85F" */}, {0x310f0043, 362, LATTICE_CERTUS /* LFD2NX-17 */}, {0x310f1043, 362, LATTICE_CERTUS /* LFD2NX-40 */}, {0x010f4043, 362, LATTICE_CERTUS /* LFCPNX-100 */}, }; int lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate) { struct scan_field field; field.num_bits = tap->ir_length; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, endstate); free(t); return ERROR_OK; } static int lattice_check_device_family(struct lattice_pld_device *lattice_device) { if (lattice_device->family != LATTICE_UNKNOWN && lattice_device->preload_length != 0) return ERROR_OK; if (!lattice_device->tap || !lattice_device->tap->hasidcode) return ERROR_FAIL; for (size_t i = 0; i < ARRAY_SIZE(lattice_devices); ++i) { if (lattice_devices[i].id == lattice_device->tap->idcode) { if (lattice_device->family == LATTICE_UNKNOWN) lattice_device->family = lattice_devices[i].family; if (lattice_device->preload_length == 0) lattice_device->preload_length = lattice_devices[i].preload_length; return ERROR_OK; } } LOG_ERROR("Unknown id! Specify family and preload-length manually."); return ERROR_FAIL; } int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t *in_val, uint32_t out_val, bool do_idle) { struct scan_field field; uint8_t buffer[4]; int retval = lattice_set_instr(tap, cmd, TAP_IDLE); if (retval != ERROR_OK) return retval; if (do_idle) { jtag_add_runtest(2, TAP_IDLE); jtag_add_sleep(1000); } h_u32_to_le(buffer, out_val); field.num_bits = 32; field.out_value = buffer; field.in_value = buffer; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); retval = jtag_execute_queue(); if (retval == ERROR_OK) *in_val = le_to_h_u32(buffer); return retval; } int lattice_read_u64_register(struct jtag_tap *tap, uint8_t cmd, uint64_t *in_val, uint64_t out_val) { struct scan_field field; uint8_t buffer[8]; int retval = lattice_set_instr(tap, cmd, TAP_IDLE); if (retval != ERROR_OK) return retval; h_u64_to_le(buffer, out_val); field.num_bits = 64; field.out_value = buffer; field.in_value = buffer; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); retval = jtag_execute_queue(); if (retval == ERROR_OK) *in_val = le_to_h_u64(buffer); return retval; } int lattice_preload(struct lattice_pld_device *lattice_device) { struct scan_field field; size_t sz_bytes = DIV_ROUND_UP(lattice_device->preload_length, 8); int retval = lattice_set_instr(lattice_device->tap, PRELOAD, TAP_IDLE); if (retval != ERROR_OK) return retval; uint8_t *buffer = malloc(sz_bytes); if (!buffer) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } memset(buffer, 0xff, sz_bytes); field.num_bits = lattice_device->preload_length; field.out_value = buffer; field.in_value = NULL; jtag_add_dr_scan(lattice_device->tap, 1, &field, TAP_IDLE); retval = jtag_execute_queue(); free(buffer); return retval; } static int lattice_read_usercode(struct lattice_pld_device *lattice_device, uint32_t *usercode, uint32_t out) { struct jtag_tap *tap = lattice_device->tap; if (!tap) return ERROR_FAIL; if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3) return lattice_ecp2_3_read_usercode(tap, usercode, out); else if (lattice_device->family == LATTICE_ECP5) return lattice_ecp5_read_usercode(tap, usercode, out); else if (lattice_device->family == LATTICE_CERTUS) return lattice_certus_read_usercode(tap, usercode, out); return ERROR_FAIL; } int lattice_verify_usercode(struct lattice_pld_device *lattice_device, uint32_t out, uint32_t expected, uint32_t mask) { uint32_t usercode; int retval = lattice_read_usercode(lattice_device, &usercode, out); if (retval != ERROR_OK) return retval; if ((usercode & mask) != expected) { LOG_ERROR("verifying user code register failed got: 0x%08" PRIx32 " expected: 0x%08" PRIx32, usercode & mask, expected); return ERROR_FAIL; } return ERROR_OK; } static int lattice_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode) { if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3) return lattice_ecp2_3_write_usercode(lattice_device, usercode); else if (lattice_device->family == LATTICE_ECP5) return lattice_ecp5_write_usercode(lattice_device, usercode); else if (lattice_device->family == LATTICE_CERTUS) return lattice_certus_write_usercode(lattice_device, usercode); return ERROR_FAIL; } static int lattice_read_status_u32(struct lattice_pld_device *lattice_device, uint32_t *status, uint32_t out, bool do_idle) { if (!lattice_device->tap) return ERROR_FAIL; if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3) return lattice_ecp2_3_read_status(lattice_device->tap, status, out, do_idle); else if (lattice_device->family == LATTICE_ECP5) return lattice_ecp5_read_status(lattice_device->tap, status, out, do_idle); return ERROR_FAIL; } static int lattice_read_status_u64(struct lattice_pld_device *lattice_device, uint64_t *status, uint64_t out) { if (!lattice_device->tap) return ERROR_FAIL; if (lattice_device->family == LATTICE_CERTUS) return lattice_certus_read_status(lattice_device->tap, status, out); return ERROR_FAIL; } int lattice_verify_status_register_u32(struct lattice_pld_device *lattice_device, uint32_t out, uint32_t expected, uint32_t mask, bool do_idle) { uint32_t status; int retval = lattice_read_status_u32(lattice_device, &status, out, do_idle); if (retval != ERROR_OK) return retval; if ((status & mask) != expected) { LOG_ERROR("verifying status register failed got: 0x%08" PRIx32 " expected: 0x%08" PRIx32, status & mask, expected); return ERROR_FAIL; } return ERROR_OK; } int lattice_verify_status_register_u64(struct lattice_pld_device *lattice_device, uint64_t out, uint64_t expected, uint64_t mask) { uint64_t status; int retval = lattice_read_status_u64(lattice_device, &status, out); if (retval != ERROR_OK) return retval; if ((status & mask) != expected) { LOG_ERROR("verifying status register failed got: 0x%08" PRIx64 " expected: 0x%08" PRIx64, status & mask, expected); return ERROR_FAIL; } return ERROR_OK; } static int lattice_load_command(struct pld_device *pld_device, const char *filename) { if (!pld_device) return ERROR_FAIL; struct lattice_pld_device *lattice_device = pld_device->driver_priv; if (!lattice_device || !lattice_device->tap) return ERROR_FAIL; struct jtag_tap *tap = lattice_device->tap; if (!tap || !tap->hasidcode) return ERROR_FAIL; int retval = lattice_check_device_family(lattice_device); if (retval != ERROR_OK) return retval; struct lattice_bit_file bit_file; retval = lattice_read_file(&bit_file, filename, lattice_device->family); if (retval != ERROR_OK) return retval; uint32_t id = tap->idcode; retval = ERROR_FAIL; switch (lattice_device->family) { case LATTICE_ECP2: retval = lattice_ecp2_load(lattice_device, &bit_file); break; case LATTICE_ECP3: retval = lattice_ecp3_load(lattice_device, &bit_file); break; case LATTICE_ECP5: case LATTICE_CERTUS: if (bit_file.has_id && id != bit_file.idcode) LOG_WARNING("Id on device (0x%8.8" PRIx32 ") and id in bit-stream (0x%8.8" PRIx32 ") don't match.", id, bit_file.idcode); if (lattice_device->family == LATTICE_ECP5) retval = lattice_ecp5_load(lattice_device, &bit_file); else retval = lattice_certus_load(lattice_device, &bit_file); break; default: LOG_ERROR("loading unknown device family"); break; } free(bit_file.raw_bit.data); return retval; } int lattice_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) { if (!pld_device) return ERROR_FAIL; struct lattice_pld_device *pld_device_info = pld_device->driver_priv; if (!pld_device_info || !pld_device_info->tap) return ERROR_FAIL; hub->tap = pld_device_info->tap; if (user_num == 1) { hub->user_ir_code = USER1; } else if (user_num == 2) { hub->user_ir_code = USER2; } else { LOG_ERROR("lattice devices only have user register 1 & 2"); return ERROR_FAIL; } return ERROR_OK; } PLD_CREATE_COMMAND_HANDLER(lattice_pld_create_command) { if (CMD_ARGC != 4 && CMD_ARGC != 6) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[2], "-chain-position") != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); if (!tap) { command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); return ERROR_FAIL; } /* id is not known yet -> postpone lattice_check_device_family() */ enum lattice_family_e family = LATTICE_UNKNOWN; if (CMD_ARGC == 6) { if (strcmp(CMD_ARGV[4], "-family") != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (strcasecmp(CMD_ARGV[5], "ecp2") == 0) { family = LATTICE_ECP2; } else if (strcasecmp(CMD_ARGV[5], "ecp3") == 0) { family = LATTICE_ECP3; } else if (strcasecmp(CMD_ARGV[5], "ecp5") == 0) { family = LATTICE_ECP5; } else if (strcasecmp(CMD_ARGV[5], "certus") == 0) { family = LATTICE_CERTUS; } else { command_print(CMD, "unknown family"); return ERROR_FAIL; } } struct lattice_pld_device *lattice_device = malloc(sizeof(struct lattice_pld_device)); if (!lattice_device) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } lattice_device->tap = tap; lattice_device->family = family; lattice_device->preload_length = 0; pld->driver_priv = lattice_device; return ERROR_OK; } COMMAND_HANDLER(lattice_read_usercode_register_command_handler) { uint32_t usercode; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } struct lattice_pld_device *lattice_device = device->driver_priv; if (!lattice_device) return ERROR_FAIL; int retval = lattice_check_device_family(lattice_device); if (retval != ERROR_OK) return retval; retval = lattice_read_usercode(lattice_device, &usercode, 0x0); if (retval == ERROR_OK) command_print(CMD, "0x%8.8" PRIx32, usercode); return retval; } COMMAND_HANDLER(lattice_set_preload_command_handler) { unsigned int preload_length; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], preload_length); struct lattice_pld_device *lattice_device = device->driver_priv; if (!lattice_device) return ERROR_FAIL; lattice_device->preload_length = preload_length; return ERROR_OK; } COMMAND_HANDLER(lattice_write_usercode_register_command_handler) { uint32_t usercode; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], usercode); struct lattice_pld_device *lattice_device = device->driver_priv; if (!lattice_device) return ERROR_FAIL; int retval = lattice_check_device_family(lattice_device); if (retval != ERROR_OK) return retval; return lattice_write_usercode(lattice_device, usercode); } COMMAND_HANDLER(lattice_read_status_command_handler) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } struct lattice_pld_device *lattice_device = device->driver_priv; if (!lattice_device) return ERROR_FAIL; int retval = lattice_check_device_family(lattice_device); if (retval != ERROR_OK) return retval; if (lattice_device->family == LATTICE_CERTUS) { uint64_t status; retval = lattice_read_status_u64(lattice_device, &status, 0x0); if (retval == ERROR_OK) command_print(CMD, "0x%016" PRIx64, status); } else { uint32_t status; const bool do_idle = lattice_device->family == LATTICE_ECP5; retval = lattice_read_status_u32(lattice_device, &status, 0x0, do_idle); if (retval == ERROR_OK) command_print(CMD, "0x%8.8" PRIx32, status); } return retval; } static const struct command_registration lattice_exec_command_handlers[] = { { .name = "read_status", .mode = COMMAND_EXEC, .handler = lattice_read_status_command_handler, .help = "reading status register from FPGA", .usage = "pld_name", }, { .name = "read_user", .mode = COMMAND_EXEC, .handler = lattice_read_usercode_register_command_handler, .help = "reading usercode register from FPGA", .usage = "pld_name", }, { .name = "write_user", .mode = COMMAND_EXEC, .handler = lattice_write_usercode_register_command_handler, .help = "writing usercode register to FPGA", .usage = "pld_name value", }, { .name = "set_preload", .mode = COMMAND_EXEC, .handler = lattice_set_preload_command_handler, .help = "set length for preload (device specific)", .usage = "pld_name value", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration lattice_command_handler[] = { { .name = "lattice", .mode = COMMAND_ANY, .help = "lattice specific commands", .usage = "", .chain = lattice_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct pld_driver lattice_pld = { .name = "lattice", .commands = lattice_command_handler, .pld_create_command = &lattice_pld_create_command, .load = &lattice_load_command, .get_ipdbg_hub = lattice_get_ipdbg_hub, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/lattice.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifndef OPENOCD_PLD_LATTICE_H #define OPENOCD_PLD_LATTICE_H #include <jtag/jtag.h> #include "pld.h" #include "lattice_bit.h" #define BYPASS 0xFF struct lattice_pld_device { struct jtag_tap *tap; size_t preload_length; enum lattice_family_e family; }; int lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate); int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t *in_val, uint32_t out_val, bool do_idle); int lattice_read_u64_register(struct jtag_tap *tap, uint8_t cmd, uint64_t *in_val, uint64_t out_val); int lattice_verify_usercode(struct lattice_pld_device *lattice_device, uint32_t out, uint32_t expected, uint32_t mask); int lattice_verify_status_register_u32(struct lattice_pld_device *lattice_device, uint32_t out, uint32_t expected, uint32_t mask, bool do_idle); int lattice_verify_status_register_u64(struct lattice_pld_device *lattice_device, uint64_t out, uint64_t expected, uint64_t mask); int lattice_preload(struct lattice_pld_device *lattice_device); #endif /* OPENOCD_PLD_LATTICE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/lattice_bit.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "lattice_bit.h" #include "raw_bit.h" #include "pld.h" #include <helper/system.h> #include <helper/log.h> #include <helper/binarybuffer.h> enum read_bit_state { SEEK_HEADER_START, SEEK_HEADER_END, SEEK_PREAMBLE, SEEK_ID, DONE, }; static int lattice_read_bit_file(struct lattice_bit_file *bit_file, const char *filename, enum lattice_family_e family) { int retval = cpld_read_raw_bit_file(&bit_file->raw_bit, filename); if (retval != ERROR_OK) return retval; bit_file->part = NULL; bit_file->has_id = false; enum read_bit_state state = SEEK_HEADER_START; for (size_t pos = 1; pos < bit_file->raw_bit.length && state != DONE; ++pos) { switch (state) { case SEEK_HEADER_START: if (bit_file->raw_bit.data[pos] == 0 && bit_file->raw_bit.data[pos - 1] == 0xff) state = SEEK_HEADER_END; break; case SEEK_HEADER_END: if (pos + 6 < bit_file->raw_bit.length && strncmp((const char *)(bit_file->raw_bit.data + pos), "Part: ", 6) == 0) { bit_file->part = (const char *)bit_file->raw_bit.data + pos + 6; LOG_INFO("part found: %s\n", bit_file->part); } else if (bit_file->raw_bit.data[pos] == 0xff && bit_file->raw_bit.data[pos - 1] == 0) { bit_file->offset = pos; state = (family != LATTICE_ECP2 && family != LATTICE_ECP3) ? SEEK_PREAMBLE : DONE; } break; case SEEK_PREAMBLE: if (pos >= 4) { uint32_t preamble = be_to_h_u32(bit_file->raw_bit.data + pos - 3); switch (preamble) { case 0xffffbdb3: state = SEEK_ID; break; case 0xffffbfb3: case 0xffffbeb3: state = DONE; break; } } break; case SEEK_ID: if (pos + 7 < bit_file->raw_bit.length && bit_file->raw_bit.data[pos] == 0xe2) { bit_file->idcode = be_to_h_u32(&bit_file->raw_bit.data[pos + 4]); bit_file->has_id = true; state = DONE; } break; default: break; } } if (state != DONE) { LOG_ERROR("parsing bitstream failed"); return ERROR_PLD_FILE_LOAD_FAILED; } for (size_t i = bit_file->offset; i < bit_file->raw_bit.length; i++) bit_file->raw_bit.data[i] = flip_u32(bit_file->raw_bit.data[i], 8); return ERROR_OK; } int lattice_read_file(struct lattice_bit_file *bit_file, const char *filename, enum lattice_family_e family) { if (!filename || !bit_file) return ERROR_COMMAND_SYNTAX_ERROR; /* check if binary .bin or ascii .bit/.hex */ const char *file_suffix_pos = strrchr(filename, '.'); if (!file_suffix_pos) { LOG_ERROR("Unable to detect filename suffix"); return ERROR_PLD_FILE_LOAD_FAILED; } if (strcasecmp(file_suffix_pos, ".bit") == 0) return lattice_read_bit_file(bit_file, filename, family); LOG_ERROR("Filetype not supported"); return ERROR_PLD_FILE_LOAD_FAILED; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/lattice_bit.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifndef OPENOCD_PLD_LATTICE_BIT_H #define OPENOCD_PLD_LATTICE_BIT_H #include "helper/types.h" #include "raw_bit.h" struct lattice_bit_file { struct raw_bit_file raw_bit; size_t offset; uint32_t idcode; const char *part; /* reuses memory in raw_bit_file */ bool has_id; }; enum lattice_family_e { LATTICE_ECP2, LATTICE_ECP3, LATTICE_ECP5, LATTICE_CERTUS, LATTICE_UNKNOWN, }; int lattice_read_file(struct lattice_bit_file *bit_file, const char *filename, enum lattice_family_e family); #endif /* OPENOCD_PLD_LATTICE_BIT_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/lattice_cmd.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifndef OPENOCD_PLD_LATTICE_CMD_H #define OPENOCD_PLD_LATTICE_CMD_H #define ISC_ERASE 0x0E #define ISC_DISABLE 0x26 #define LSC_READ_STATUS 0x3C #define LSC_INIT_ADDRESS 0x46 #define LSC_BITSTREAM_BURST 0x7A #define READ_USERCODE 0xC0 #define ISC_ENABLE 0xC6 #endif /* OPENOCD_PLD_LATTICE_CMD_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/pld.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pld.h" #include <sys/stat.h> #include <helper/log.h> #include <helper/replacements.h> #include <helper/time_support.h> static struct pld_driver *pld_drivers[] = { &efinix_pld, &gatemate_pld, &gowin_pld, &intel_pld, &lattice_pld, &virtex2_pld, NULL, }; static struct pld_device *pld_devices; struct pld_device *get_pld_device_by_num(int num) { struct pld_device *p; int i = 0; for (p = pld_devices; p; p = p->next) { if (i++ == num) { LOG_WARNING("DEPRECATED: use pld name \"%s\" instead of number %d", p->name, num); return p; } } return NULL; } struct pld_device *get_pld_device_by_name(const char *name) { for (struct pld_device *p = pld_devices; p; p = p->next) { if (strcmp(p->name, name) == 0) return p; } return NULL; } struct pld_device *get_pld_device_by_name_or_numstr(const char *str) { struct pld_device *dev = get_pld_device_by_name(str); if (dev) return dev; char *end; unsigned long dev_num = strtoul(str, &end, 0); if (*end || dev_num > INT_MAX) { LOG_ERROR("Invalid argument"); return NULL; } return get_pld_device_by_num(dev_num); } /* @deffn {Config Command} {pld create} pld_name driver -chain-position tap_name [options] */ COMMAND_HANDLER(handle_pld_create_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct pld_driver *pld_driver = NULL; for (int i = 0; pld_drivers[i]; i++) { if (strcmp(CMD_ARGV[1], pld_drivers[i]->name) == 0) { pld_driver = pld_drivers[i]; break; } } if (!pld_driver) { LOG_ERROR("pld driver '%s' not found", CMD_ARGV[1]); return ERROR_FAIL; /* exit(-1); */ } if (get_pld_device_by_name(CMD_ARGV[0])) { LOG_ERROR("pld device with name '%s' already exists", CMD_ARGV[0]); return ERROR_FAIL; } struct pld_device *pld_device = malloc(sizeof(struct pld_device)); if (!pld_device) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } pld_device->driver = pld_driver; pld_device->next = NULL; int retval = CALL_COMMAND_HANDLER(pld_driver->pld_create_command, pld_device); if (retval != ERROR_OK) { LOG_ERROR("'%s' driver rejected pld device", CMD_ARGV[1]); free(pld_device); return ERROR_OK; } pld_device->name = strdup(CMD_ARGV[0]); if (!pld_device->name) { LOG_ERROR("Out of memory"); free(pld_device); return ERROR_FAIL; } /* register pld specific commands */ if (pld_driver->commands) { retval = register_commands(CMD_CTX, NULL, pld_driver->commands); if (retval != ERROR_OK) { LOG_ERROR("couldn't register '%s' commands", CMD_ARGV[1]); free(pld_device->name); free(pld_device); return ERROR_FAIL; } } if (pld_devices) { /* find last pld device */ struct pld_device *p = pld_devices; for (; p && p->next; p = p->next) ; if (p) p->next = pld_device; } else { pld_devices = pld_device; } return ERROR_OK; } COMMAND_HANDLER(handle_pld_devices_command) { struct pld_device *p; int i = 0; if (!pld_devices) { command_print(CMD, "no pld devices configured"); return ERROR_OK; } for (p = pld_devices; p; p = p->next) command_print(CMD, "#%i: %s (driver: %s)", i++, p->name, p->driver->name); return ERROR_OK; } COMMAND_HANDLER(handle_pld_load_command) { int retval; struct timeval start, end, duration; struct pld_device *p; gettimeofday(&start, NULL); if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; p = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!p) { command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_OK; } struct stat input_stat; if (stat(CMD_ARGV[1], &input_stat) == -1) { LOG_ERROR("couldn't stat() %s: %s", CMD_ARGV[1], strerror(errno)); return ERROR_PLD_FILE_LOAD_FAILED; } if (S_ISDIR(input_stat.st_mode)) { LOG_ERROR("%s is a directory", CMD_ARGV[1]); return ERROR_PLD_FILE_LOAD_FAILED; } if (input_stat.st_size == 0) { LOG_ERROR("Empty file %s", CMD_ARGV[1]); return ERROR_PLD_FILE_LOAD_FAILED; } retval = p->driver->load(p, CMD_ARGV[1]); if (retval != ERROR_OK) { command_print(CMD, "failed loading file %s to pld device %s", CMD_ARGV[1], CMD_ARGV[0]); return retval; } else { gettimeofday(&end, NULL); timeval_subtract(&duration, &end, &start); command_print(CMD, "loaded file %s to pld device %s in %jis %jius", CMD_ARGV[1], CMD_ARGV[0], (intmax_t)duration.tv_sec, (intmax_t)duration.tv_usec); } return ERROR_OK; } static const struct command_registration pld_exec_command_handlers[] = { { .name = "devices", .handler = handle_pld_devices_command, .mode = COMMAND_EXEC, .help = "list configured pld devices", .usage = "", }, { .name = "load", .handler = handle_pld_load_command, .mode = COMMAND_EXEC, .help = "load configuration file into PLD", .usage = "pld_name filename", }, COMMAND_REGISTRATION_DONE }; static int pld_init(struct command_context *cmd_ctx) { if (!pld_devices) return ERROR_OK; return register_commands(cmd_ctx, "pld", pld_exec_command_handlers); } COMMAND_HANDLER(handle_pld_init_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; static bool pld_initialized; if (pld_initialized) { LOG_INFO("'pld init' has already been called"); return ERROR_OK; } pld_initialized = true; LOG_DEBUG("Initializing PLDs..."); return pld_init(CMD_CTX); } static const struct command_registration pld_config_command_handlers[] = { { .name = "create", .mode = COMMAND_CONFIG, .handler = handle_pld_create_command, .help = "create a PLD device", .usage = "name.pld driver_name [driver_args ... ]", }, { .name = "init", .mode = COMMAND_CONFIG, .handler = handle_pld_init_command, .help = "initialize PLD devices", .usage = "" }, COMMAND_REGISTRATION_DONE }; static const struct command_registration pld_command_handler[] = { { .name = "pld", .mode = COMMAND_ANY, .help = "programmable logic device commands", .usage = "", .chain = pld_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; int pld_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, pld_command_handler); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/pld.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_PLD_PLD_H #define OPENOCD_PLD_PLD_H #include <helper/command.h> struct pld_device; #define __PLD_CREATE_COMMAND(name) \ COMMAND_HELPER(name, struct pld_device *pld) struct pld_ipdbg_hub { struct jtag_tap *tap; unsigned int user_ir_code; }; struct pld_driver { const char *name; __PLD_CREATE_COMMAND((*pld_create_command)); const struct command_registration *commands; int (*load)(struct pld_device *pld_device, const char *filename); int (*get_ipdbg_hub)(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub); }; #define PLD_CREATE_COMMAND_HANDLER(name) \ static __PLD_CREATE_COMMAND(name) struct pld_device { struct pld_driver *driver; void *driver_priv; struct pld_device *next; char *name; }; int pld_register_commands(struct command_context *cmd_ctx); struct pld_device *get_pld_device_by_num(int num); struct pld_device *get_pld_device_by_name(const char *name); struct pld_device *get_pld_device_by_name_or_numstr(const char *str); #define ERROR_PLD_DEVICE_INVALID (-1000) #define ERROR_PLD_FILE_LOAD_FAILED (-1001) extern struct pld_driver efinix_pld; extern struct pld_driver gatemate_pld; extern struct pld_driver gowin_pld; extern struct pld_driver intel_pld; extern struct pld_driver lattice_pld; extern struct pld_driver virtex2_pld; #endif /* OPENOCD_PLD_PLD_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/raw_bit.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "raw_bit.h" #include "pld.h" #include <helper/system.h> #include <helper/log.h> int cpld_read_raw_bit_file(struct raw_bit_file *bit_file, const char *filename) { FILE *input_file = fopen(filename, "rb"); if (!input_file) { LOG_ERROR("Couldn't open %s: %s", filename, strerror(errno)); return ERROR_PLD_FILE_LOAD_FAILED; } fseek(input_file, 0, SEEK_END); long length = ftell(input_file); fseek(input_file, 0, SEEK_SET); if (length < 0) { fclose(input_file); LOG_ERROR("Failed to get length of file %s: %s", filename, strerror(errno)); return ERROR_PLD_FILE_LOAD_FAILED; } bit_file->length = (size_t)length; bit_file->data = malloc(bit_file->length); if (!bit_file->data) { fclose(input_file); LOG_ERROR("Out of memory"); return ERROR_PLD_FILE_LOAD_FAILED; } size_t read_count = fread(bit_file->data, sizeof(char), bit_file->length, input_file); fclose(input_file); if (read_count != bit_file->length) { free(bit_file->data); bit_file->data = NULL; return ERROR_PLD_FILE_LOAD_FAILED; } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/raw_bit.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2022 by Daniel Anselmi * * danselmi@gmx.ch * ***************************************************************************/ #ifndef OPENOCD_PLD_RAW_BIN_H #define OPENOCD_PLD_RAW_BIN_H #include <stddef.h> #include <stdint.h> struct raw_bit_file { size_t length; uint8_t *data; }; int cpld_read_raw_bit_file(struct raw_bit_file *bit_file, const char *filename); #endif /* OPENOCD_PLD_RAW_BIN_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/virtex2.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "virtex2.h" #include "xilinx_bit.h" #include "pld.h" static const struct virtex2_command_set virtex2_default_commands = { .cfg_out = 0x04, .cfg_in = 0x05, .jprog_b = 0x0b, .jstart = 0x0c, .jshutdown = 0x0d, .bypass = 0x3f, .user = {0x02, 0x03}, .num_user = 2, /* virtex II has only 2 user instructions */ }; static int virtex2_set_instr(struct jtag_tap *tap, uint64_t new_instr) { if (!tap) return ERROR_FAIL; if (buf_get_u64(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; field.num_bits = tap->ir_length; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } field.out_value = t; buf_set_u64(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); free(t); } return ERROR_OK; } static int virtex2_send_32(struct pld_device *pld_device, int num_words, uint32_t *words) { struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; struct scan_field scan_field; uint8_t *values; int i; values = malloc(num_words * 4); if (!values) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } scan_field.num_bits = num_words * 32; scan_field.out_value = values; scan_field.in_value = NULL; for (i = 0; i < num_words; i++) buf_set_u32(values + 4 * i, 0, 32, flip_u32(*words++, 32)); int retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.cfg_in); if (retval != ERROR_OK) { free(values); return retval; } jtag_add_dr_scan(virtex2_info->tap, 1, &scan_field, TAP_DRPAUSE); free(values); return ERROR_OK; } static inline void virtexflip32(jtag_callback_data_t arg) { uint8_t *in = (uint8_t *)arg; *((uint32_t *)arg) = flip_u32(le_to_h_u32(in), 32); } static int virtex2_receive_32(struct pld_device *pld_device, int num_words, uint32_t *words) { struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; struct scan_field scan_field; scan_field.num_bits = 32; scan_field.out_value = NULL; scan_field.in_value = NULL; int retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.cfg_out); if (retval != ERROR_OK) return retval; while (num_words--) { scan_field.in_value = (uint8_t *)words; jtag_add_dr_scan(virtex2_info->tap, 1, &scan_field, TAP_DRPAUSE); jtag_add_callback(virtexflip32, (jtag_callback_data_t)words); words++; } return ERROR_OK; } static int virtex2_read_stat(struct pld_device *pld_device, uint32_t *status) { uint32_t data[5]; jtag_add_tlr(); data[0] = 0xaa995566; /* synch word */ data[1] = 0x2800E001; /* Type 1, read, address 7, 1 word */ data[2] = 0x20000000; /* NOOP (Type 1, read, address 0, 0 words */ data[3] = 0x20000000; /* NOOP */ data[4] = 0x20000000; /* NOOP */ int retval = virtex2_send_32(pld_device, 5, data); if (retval != ERROR_OK) return retval; retval = virtex2_receive_32(pld_device, 1, status); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval == ERROR_OK) LOG_DEBUG("status: 0x%8.8" PRIx32, *status); return retval; } static int virtex2_program(struct pld_device *pld_device) { struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; if (!virtex2_info) return ERROR_FAIL; int retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jshutdown); if (retval != ERROR_OK) return retval; retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jprog_b); if (retval != ERROR_OK) return retval; jtag_add_runtest(62000, TAP_IDLE); if (!(virtex2_info->no_jstart)) { retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jstart); if (retval != ERROR_OK) return retval; } retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.bypass); if (retval != ERROR_OK) return retval; jtag_add_runtest(2000, TAP_IDLE); return jtag_execute_queue(); } static int virtex2_load_prepare(struct pld_device *pld_device) { struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; int retval; retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jprog_b); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; jtag_add_sleep(1000); retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.cfg_in); if (retval != ERROR_OK) return retval; return jtag_execute_queue(); } static int virtex2_load_cleanup(struct pld_device *pld_device) { struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; int retval; jtag_add_tlr(); if (!(virtex2_info->no_jstart)) { retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jstart); if (retval != ERROR_OK) return retval; } jtag_add_runtest(13, TAP_IDLE); retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.bypass); if (retval != ERROR_OK) return retval; retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.bypass); if (retval != ERROR_OK) return retval; if (!(virtex2_info->no_jstart)) { retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jstart); if (retval != ERROR_OK) return retval; } jtag_add_runtest(13, TAP_IDLE); retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.bypass); if (retval != ERROR_OK) return retval; return jtag_execute_queue(); } static int virtex2_load(struct pld_device *pld_device, const char *filename) { struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; struct xilinx_bit_file bit_file; int retval; unsigned int i; struct scan_field field; field.in_value = NULL; retval = xilinx_read_bit_file(&bit_file, filename); if (retval != ERROR_OK) return retval; retval = virtex2_load_prepare(pld_device); if (retval != ERROR_OK) { xilinx_free_bit_file(&bit_file); return retval; } for (i = 0; i < bit_file.length; i++) bit_file.data[i] = flip_u32(bit_file.data[i], 8); field.num_bits = bit_file.length * 8; field.out_value = bit_file.data; jtag_add_dr_scan(virtex2_info->tap, 1, &field, TAP_DRPAUSE); retval = jtag_execute_queue(); if (retval != ERROR_OK) { xilinx_free_bit_file(&bit_file); return retval; } retval = virtex2_load_cleanup(pld_device); xilinx_free_bit_file(&bit_file); return retval; } COMMAND_HANDLER(virtex2_handle_program_command) { struct pld_device *device; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } return virtex2_program(device); } COMMAND_HANDLER(virtex2_handle_read_stat_command) { struct pld_device *device; uint32_t status; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_FAIL; } int retval = virtex2_read_stat(device, &status); if (retval != ERROR_OK) { command_print(CMD, "cannot read virtex2 status register"); return retval; } command_print(CMD, "virtex2 status register: 0x%8.8" PRIx32, status); return ERROR_OK; } static int xilinx_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) { if (!pld_device) return ERROR_FAIL; struct virtex2_pld_device *pld_device_info = pld_device->driver_priv; if (!pld_device_info || !pld_device_info->tap) return ERROR_FAIL; hub->tap = pld_device_info->tap; if (user_num < 1 || (unsigned int)user_num > pld_device_info->command_set.num_user) { LOG_ERROR("device has only user register 1 to %d", pld_device_info->command_set.num_user); return ERROR_FAIL; } hub->user_ir_code = pld_device_info->command_set.user[user_num - 1]; return ERROR_OK; } COMMAND_HANDLER(virtex2_handle_set_instuction_codes_command) { if (CMD_ARGC < 6 || CMD_ARGC > (6 + VIRTEX2_MAX_USER_INSTRUCTIONS)) return ERROR_COMMAND_SYNTAX_ERROR; struct pld_device *device = get_pld_device_by_name(CMD_ARGV[0]); if (!device) { command_print(CMD, "pld device '#%s' is unknown", CMD_ARGV[0]); return ERROR_FAIL; } struct virtex2_pld_device *virtex2_info = device->driver_priv; if (!virtex2_info) return ERROR_FAIL; struct virtex2_command_set instr_codes; COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], instr_codes.cfg_out); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[2], instr_codes.cfg_in); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[3], instr_codes.jprog_b); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[4], instr_codes.jstart); COMMAND_PARSE_NUMBER(u64, CMD_ARGV[5], instr_codes.jshutdown); instr_codes.bypass = 0xffffffffffffffff; unsigned int num_user = CMD_ARGC - 6; for (unsigned int i = 0; i < num_user; ++i) COMMAND_PARSE_NUMBER(u64, CMD_ARGV[6 + i], instr_codes.user[i]); instr_codes.num_user = num_user; virtex2_info->command_set = instr_codes; return ERROR_OK; } COMMAND_HANDLER(virtex2_handle_set_user_codes_command) { if (CMD_ARGC < 2 || CMD_ARGC > (1 + VIRTEX2_MAX_USER_INSTRUCTIONS)) return ERROR_COMMAND_SYNTAX_ERROR; struct pld_device *device = get_pld_device_by_name(CMD_ARGV[0]); if (!device) { command_print(CMD, "pld device '#%s' is unknown", CMD_ARGV[0]); return ERROR_FAIL; } struct virtex2_pld_device *virtex2_info = device->driver_priv; if (!virtex2_info) return ERROR_FAIL; uint64_t user[VIRTEX2_MAX_USER_INSTRUCTIONS]; unsigned int num_user = CMD_ARGC - 1; for (unsigned int i = 0; i < num_user; ++i) COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1 + i], user[i]); virtex2_info->command_set.num_user = num_user; memcpy(virtex2_info->command_set.user, user, num_user * sizeof(uint64_t)); return ERROR_OK; } PLD_CREATE_COMMAND_HANDLER(virtex2_pld_create_command) { if (CMD_ARGC < 4) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[2], "-chain-position") != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); if (!tap) { command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); return ERROR_FAIL; } struct virtex2_pld_device *virtex2_info = malloc(sizeof(struct virtex2_pld_device)); if (!virtex2_info) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } virtex2_info->tap = tap; virtex2_info->command_set = virtex2_default_commands; virtex2_info->no_jstart = 0; if (CMD_ARGC >= 5 && strcmp(CMD_ARGV[4], "-no_jstart") == 0) virtex2_info->no_jstart = 1; pld->driver_priv = virtex2_info; return ERROR_OK; } static const struct command_registration virtex2_exec_command_handlers[] = { { .name = "read_stat", .mode = COMMAND_EXEC, .handler = virtex2_handle_read_stat_command, .help = "read status register", .usage = "pld_name", }, { .name = "set_instr_codes", .mode = COMMAND_EXEC, .handler = virtex2_handle_set_instuction_codes_command, .help = "set instructions codes used for loading the bitstream/refreshing/jtag-hub", .usage = "pld_name cfg_out cfg_in jprogb jstart jshutdown" " [user1 [user2 [user3 [user4]]]]", }, { .name = "set_user_codes", .mode = COMMAND_EXEC, .handler = virtex2_handle_set_user_codes_command, .help = "set instructions codes used for jtag-hub", .usage = "pld_name user1 [user2 [user3 [user4]]]", }, { .name = "program", .mode = COMMAND_EXEC, .handler = virtex2_handle_program_command, .help = "start loading of configuration (refresh)", .usage = "pld_name", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration virtex2_command_handler[] = { { .name = "virtex2", .mode = COMMAND_ANY, .help = "Virtex-II specific commands", .usage = "", .chain = virtex2_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct pld_driver virtex2_pld = { .name = "virtex2", .commands = virtex2_command_handler, .pld_create_command = &virtex2_pld_create_command, .load = &virtex2_load, .get_ipdbg_hub = xilinx_get_ipdbg_hub, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/virtex2.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_PLD_VIRTEX2_H #define OPENOCD_PLD_VIRTEX2_H #include <jtag/jtag.h> #define VIRTEX2_MAX_USER_INSTRUCTIONS 4 struct virtex2_command_set { uint64_t cfg_out; uint64_t cfg_in; uint64_t jprog_b; uint64_t jstart; uint64_t jshutdown; uint64_t bypass; uint64_t user[VIRTEX2_MAX_USER_INSTRUCTIONS]; unsigned int num_user; }; struct virtex2_pld_device { struct jtag_tap *tap; int no_jstart; struct virtex2_command_set command_set; }; #endif /* OPENOCD_PLD_VIRTEX2_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/xilinx_bit.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "xilinx_bit.h" #include "pld.h" #include <helper/log.h> #include <helper/system.h> static int read_section(FILE *input_file, int length_size, char section, uint32_t *buffer_length, uint8_t **buffer) { uint8_t length_buffer[4]; int length; char section_char; int read_count; if ((length_size != 2) && (length_size != 4)) { LOG_ERROR("BUG: length_size neither 2 nor 4"); return ERROR_PLD_FILE_LOAD_FAILED; } read_count = fread(§ion_char, 1, 1, input_file); if (read_count != 1) return ERROR_PLD_FILE_LOAD_FAILED; if (section_char != section) return ERROR_PLD_FILE_LOAD_FAILED; read_count = fread(length_buffer, 1, length_size, input_file); if (read_count != length_size) return ERROR_PLD_FILE_LOAD_FAILED; if (length_size == 4) length = be_to_h_u32(length_buffer); else /* (length_size == 2) */ length = be_to_h_u16(length_buffer); if (buffer_length) *buffer_length = length; *buffer = malloc(length); read_count = fread(*buffer, 1, length, input_file); if (read_count != length) return ERROR_PLD_FILE_LOAD_FAILED; return ERROR_OK; } int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename) { FILE *input_file; int read_count; if (!filename || !bit_file) return ERROR_COMMAND_SYNTAX_ERROR; input_file = fopen(filename, "rb"); if (!input_file) { LOG_ERROR("couldn't open %s: %s", filename, strerror(errno)); return ERROR_PLD_FILE_LOAD_FAILED; } bit_file->source_file = NULL; bit_file->part_name = NULL; bit_file->date = NULL; bit_file->time = NULL; bit_file->data = NULL; read_count = fread(bit_file->unknown_header, 1, 13, input_file); if (read_count != 13) { LOG_ERROR("couldn't read unknown_header from file '%s'", filename); fclose(input_file); return ERROR_PLD_FILE_LOAD_FAILED; } if (read_section(input_file, 2, 'a', NULL, &bit_file->source_file) != ERROR_OK) { xilinx_free_bit_file(bit_file); fclose(input_file); return ERROR_PLD_FILE_LOAD_FAILED; } if (read_section(input_file, 2, 'b', NULL, &bit_file->part_name) != ERROR_OK) { xilinx_free_bit_file(bit_file); fclose(input_file); return ERROR_PLD_FILE_LOAD_FAILED; } if (read_section(input_file, 2, 'c', NULL, &bit_file->date) != ERROR_OK) { xilinx_free_bit_file(bit_file); fclose(input_file); return ERROR_PLD_FILE_LOAD_FAILED; } if (read_section(input_file, 2, 'd', NULL, &bit_file->time) != ERROR_OK) { xilinx_free_bit_file(bit_file); fclose(input_file); return ERROR_PLD_FILE_LOAD_FAILED; } if (read_section(input_file, 4, 'e', &bit_file->length, &bit_file->data) != ERROR_OK) { xilinx_free_bit_file(bit_file); fclose(input_file); return ERROR_PLD_FILE_LOAD_FAILED; } LOG_DEBUG("bit_file: %s %s %s,%s %" PRIu32 "", bit_file->source_file, bit_file->part_name, bit_file->date, bit_file->time, bit_file->length); fclose(input_file); return ERROR_OK; } void xilinx_free_bit_file(struct xilinx_bit_file *bit_file) { free(bit_file->source_file); free(bit_file->part_name); free(bit_file->date); free(bit_file->time); free(bit_file->data); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/pld/xilinx_bit.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_PLD_XILINX_BIT_H #define OPENOCD_PLD_XILINX_BIT_H #include "helper/types.h" struct xilinx_bit_file { uint8_t unknown_header[13]; uint8_t *source_file; uint8_t *part_name; uint8_t *date; uint8_t *time; uint32_t length; uint8_t *data; }; int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename); void xilinx_free_bit_file(struct xilinx_bit_file *bit_file); #endif /* OPENOCD_PLD_XILINX_BIT_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/FreeRTOS.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/time_support.h> #include <jtag/jtag.h> #include "target/target.h" #include "target/target_type.h" #include "rtos.h" #include "helper/log.h" #include "helper/types.h" #include "rtos_standard_stackings.h" #include "target/armv7m.h" #include "target/cortex_m.h" #define FREERTOS_MAX_PRIORITIES 63 /* FIXME: none of the _width parameters are actually observed properly! * you WILL need to edit more if you actually attempt to target a 8/16/64 * bit target! */ struct freertos_params { const char *target_name; const unsigned char thread_count_width; const unsigned char pointer_width; const unsigned char list_next_offset; const unsigned char list_width; const unsigned char list_elem_next_offset; const unsigned char list_elem_content_offset; const unsigned char thread_stack_offset; const unsigned char thread_name_offset; const struct rtos_register_stacking *stacking_info_cm3; const struct rtos_register_stacking *stacking_info_cm4f; const struct rtos_register_stacking *stacking_info_cm4f_fpu; }; static const struct freertos_params freertos_params_list[] = { { "cortex_m", /* target_name */ 4, /* thread_count_width; */ 4, /* pointer_width; */ 16, /* list_next_offset; */ 20, /* list_width; */ 8, /* list_elem_next_offset; */ 12, /* list_elem_content_offset */ 0, /* thread_stack_offset; */ 52, /* thread_name_offset; */ &rtos_standard_cortex_m3_stacking, /* stacking_info */ &rtos_standard_cortex_m4f_stacking, &rtos_standard_cortex_m4f_fpu_stacking, }, { "hla_target", /* target_name */ 4, /* thread_count_width; */ 4, /* pointer_width; */ 16, /* list_next_offset; */ 20, /* list_width; */ 8, /* list_elem_next_offset; */ 12, /* list_elem_content_offset */ 0, /* thread_stack_offset; */ 52, /* thread_name_offset; */ &rtos_standard_cortex_m3_stacking, /* stacking_info */ &rtos_standard_cortex_m4f_stacking, &rtos_standard_cortex_m4f_fpu_stacking, }, }; static bool freertos_detect_rtos(struct target *target); static int freertos_create(struct target *target); static int freertos_update_threads(struct rtos *rtos); static int freertos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int freertos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); const struct rtos_type freertos_rtos = { .name = "FreeRTOS", .detect_rtos = freertos_detect_rtos, .create = freertos_create, .update_threads = freertos_update_threads, .get_thread_reg_list = freertos_get_thread_reg_list, .get_symbol_list_to_lookup = freertos_get_symbol_list_to_lookup, }; enum freertos_symbol_values { FREERTOS_VAL_PX_CURRENT_TCB = 0, FREERTOS_VAL_PX_READY_TASKS_LISTS = 1, FREERTOS_VAL_X_DELAYED_TASK_LIST1 = 2, FREERTOS_VAL_X_DELAYED_TASK_LIST2 = 3, FREERTOS_VAL_PX_DELAYED_TASK_LIST = 4, FREERTOS_VAL_PX_OVERFLOW_DELAYED_TASK_LIST = 5, FREERTOS_VAL_X_PENDING_READY_LIST = 6, FREERTOS_VAL_X_TASKS_WAITING_TERMINATION = 7, FREERTOS_VAL_X_SUSPENDED_TASK_LIST = 8, FREERTOS_VAL_UX_CURRENT_NUMBER_OF_TASKS = 9, FREERTOS_VAL_UX_TOP_USED_PRIORITY = 10, FREERTOS_VAL_X_SCHEDULER_RUNNING = 11, }; struct symbols { const char *name; bool optional; }; static const struct symbols freertos_symbol_list[] = { { "pxCurrentTCB", false }, { "pxReadyTasksLists", false }, { "xDelayedTaskList1", false }, { "xDelayedTaskList2", false }, { "pxDelayedTaskList", false }, { "pxOverflowDelayedTaskList", false }, { "xPendingReadyList", false }, { "xTasksWaitingTermination", true }, /* Only if INCLUDE_vTaskDelete */ { "xSuspendedTaskList", true }, /* Only if INCLUDE_vTaskSuspend */ { "uxCurrentNumberOfTasks", false }, { "uxTopUsedPriority", true }, /* Unavailable since v7.5.3 */ { "xSchedulerRunning", false }, { NULL, false } }; /* TODO: */ /* this is not safe for little endian yet */ /* may be problems reading if sizes are not 32 bit long integers. */ /* test mallocs for failure */ static int freertos_update_threads(struct rtos *rtos) { int retval; unsigned int tasks_found = 0; const struct freertos_params *param; if (!rtos->rtos_specific_params) return -1; param = (const struct freertos_params *) rtos->rtos_specific_params; if (!rtos->symbols) { LOG_ERROR("No symbols for FreeRTOS"); return -3; } if (rtos->symbols[FREERTOS_VAL_UX_CURRENT_NUMBER_OF_TASKS].address == 0) { LOG_ERROR("Don't have the number of threads in FreeRTOS"); return -2; } uint32_t thread_list_size = 0; retval = target_read_u32(rtos->target, rtos->symbols[FREERTOS_VAL_UX_CURRENT_NUMBER_OF_TASKS].address, &thread_list_size); LOG_DEBUG("FreeRTOS: Read uxCurrentNumberOfTasks at 0x%" PRIx64 ", value %" PRIu32, rtos->symbols[FREERTOS_VAL_UX_CURRENT_NUMBER_OF_TASKS].address, thread_list_size); if (retval != ERROR_OK) { LOG_ERROR("Could not read FreeRTOS thread count from target"); return retval; } /* wipe out previous thread details if any */ rtos_free_threadlist(rtos); /* read the current thread */ uint32_t pointer_casts_are_bad; retval = target_read_u32(rtos->target, rtos->symbols[FREERTOS_VAL_PX_CURRENT_TCB].address, &pointer_casts_are_bad); if (retval != ERROR_OK) { LOG_ERROR("Error reading current thread in FreeRTOS thread list"); return retval; } rtos->current_thread = pointer_casts_are_bad; LOG_DEBUG("FreeRTOS: Read pxCurrentTCB at 0x%" PRIx64 ", value 0x%" PRIx64, rtos->symbols[FREERTOS_VAL_PX_CURRENT_TCB].address, rtos->current_thread); /* read scheduler running */ uint32_t scheduler_running; retval = target_read_u32(rtos->target, rtos->symbols[FREERTOS_VAL_X_SCHEDULER_RUNNING].address, &scheduler_running); if (retval != ERROR_OK) { LOG_ERROR("Error reading FreeRTOS scheduler state"); return retval; } LOG_DEBUG("FreeRTOS: Read xSchedulerRunning at 0x%" PRIx64 ", value 0x%" PRIx32, rtos->symbols[FREERTOS_VAL_X_SCHEDULER_RUNNING].address, scheduler_running); if ((thread_list_size == 0) || (rtos->current_thread == 0) || (scheduler_running != 1)) { /* Either : No RTOS threads - there is always at least the current execution though */ /* OR : No current thread - all threads suspended - show the current execution * of idling */ char tmp_str[] = "Current Execution"; thread_list_size++; tasks_found++; rtos->thread_details = malloc( sizeof(struct thread_detail) * thread_list_size); if (!rtos->thread_details) { LOG_ERROR("Error allocating memory for %d threads", thread_list_size); return ERROR_FAIL; } rtos->current_thread = 1; rtos->thread_details->threadid = rtos->current_thread; rtos->thread_details->exists = true; rtos->thread_details->extra_info_str = NULL; rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str)); strcpy(rtos->thread_details->thread_name_str, tmp_str); if (thread_list_size == 1) { rtos->thread_count = 1; return ERROR_OK; } } else { /* create space for new thread details */ rtos->thread_details = malloc( sizeof(struct thread_detail) * thread_list_size); if (!rtos->thread_details) { LOG_ERROR("Error allocating memory for %d threads", thread_list_size); return ERROR_FAIL; } } /* Find out how many lists are needed to be read from pxReadyTasksLists, */ if (rtos->symbols[FREERTOS_VAL_UX_TOP_USED_PRIORITY].address == 0) { LOG_ERROR("FreeRTOS: uxTopUsedPriority is not defined, consult the OpenOCD manual for a work-around"); return ERROR_FAIL; } uint32_t top_used_priority = 0; retval = target_read_u32(rtos->target, rtos->symbols[FREERTOS_VAL_UX_TOP_USED_PRIORITY].address, &top_used_priority); if (retval != ERROR_OK) return retval; LOG_DEBUG("FreeRTOS: Read uxTopUsedPriority at 0x%" PRIx64 ", value %" PRIu32, rtos->symbols[FREERTOS_VAL_UX_TOP_USED_PRIORITY].address, top_used_priority); if (top_used_priority > FREERTOS_MAX_PRIORITIES) { LOG_ERROR("FreeRTOS top used priority is unreasonably big, not proceeding: %" PRIu32, top_used_priority); return ERROR_FAIL; } /* uxTopUsedPriority was defined as configMAX_PRIORITIES - 1 * in old FreeRTOS versions (before V7.5.3) * Use contrib/rtos-helpers/FreeRTOS-openocd.c to get compatible symbol * in newer FreeRTOS versions. * Here we restore the original configMAX_PRIORITIES value */ unsigned int config_max_priorities = top_used_priority + 1; symbol_address_t *list_of_lists = malloc(sizeof(symbol_address_t) * (config_max_priorities + 5)); if (!list_of_lists) { LOG_ERROR("Error allocating memory for %u priorities", config_max_priorities); return ERROR_FAIL; } unsigned int num_lists; for (num_lists = 0; num_lists < config_max_priorities; num_lists++) list_of_lists[num_lists] = rtos->symbols[FREERTOS_VAL_PX_READY_TASKS_LISTS].address + num_lists * param->list_width; list_of_lists[num_lists++] = rtos->symbols[FREERTOS_VAL_X_DELAYED_TASK_LIST1].address; list_of_lists[num_lists++] = rtos->symbols[FREERTOS_VAL_X_DELAYED_TASK_LIST2].address; list_of_lists[num_lists++] = rtos->symbols[FREERTOS_VAL_X_PENDING_READY_LIST].address; list_of_lists[num_lists++] = rtos->symbols[FREERTOS_VAL_X_SUSPENDED_TASK_LIST].address; list_of_lists[num_lists++] = rtos->symbols[FREERTOS_VAL_X_TASKS_WAITING_TERMINATION].address; for (unsigned int i = 0; i < num_lists; i++) { if (list_of_lists[i] == 0) continue; /* Read the number of threads in this list */ uint32_t list_thread_count = 0; retval = target_read_u32(rtos->target, list_of_lists[i], &list_thread_count); if (retval != ERROR_OK) { LOG_ERROR("Error reading number of threads in FreeRTOS thread list"); free(list_of_lists); return retval; } LOG_DEBUG("FreeRTOS: Read thread count for list %u at 0x%" PRIx64 ", value %" PRIu32, i, list_of_lists[i], list_thread_count); if (list_thread_count == 0) continue; /* Read the location of first list item */ uint32_t prev_list_elem_ptr = -1; uint32_t list_elem_ptr = 0; retval = target_read_u32(rtos->target, list_of_lists[i] + param->list_next_offset, &list_elem_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading first thread item location in FreeRTOS thread list"); free(list_of_lists); return retval; } LOG_DEBUG("FreeRTOS: Read first item for list %u at 0x%" PRIx64 ", value 0x%" PRIx32, i, list_of_lists[i] + param->list_next_offset, list_elem_ptr); while ((list_thread_count > 0) && (list_elem_ptr != 0) && (list_elem_ptr != prev_list_elem_ptr) && (tasks_found < thread_list_size)) { /* Get the location of the thread structure. */ retval = target_read_u32(rtos->target, list_elem_ptr + param->list_elem_content_offset, &pointer_casts_are_bad); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread list item object in FreeRTOS thread list"); free(list_of_lists); return retval; } rtos->thread_details[tasks_found].threadid = pointer_casts_are_bad; LOG_DEBUG("FreeRTOS: Read Thread ID at 0x%" PRIx32 ", value 0x%" PRIx64, list_elem_ptr + param->list_elem_content_offset, rtos->thread_details[tasks_found].threadid); /* get thread name */ #define FREERTOS_THREAD_NAME_STR_SIZE (200) char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE]; /* Read the thread name */ retval = target_read_buffer(rtos->target, rtos->thread_details[tasks_found].threadid + param->thread_name_offset, FREERTOS_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); if (retval != ERROR_OK) { LOG_ERROR("Error reading first thread item location in FreeRTOS thread list"); free(list_of_lists); return retval; } tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00'; LOG_DEBUG("FreeRTOS: Read Thread Name at 0x%" PRIx64 ", value '%s'", rtos->thread_details[tasks_found].threadid + param->thread_name_offset, tmp_str); if (tmp_str[0] == '\x00') strcpy(tmp_str, "No Name"); rtos->thread_details[tasks_found].thread_name_str = malloc(strlen(tmp_str)+1); strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str); rtos->thread_details[tasks_found].exists = true; if (rtos->thread_details[tasks_found].threadid == rtos->current_thread) { char running_str[] = "State: Running"; rtos->thread_details[tasks_found].extra_info_str = malloc( sizeof(running_str)); strcpy(rtos->thread_details[tasks_found].extra_info_str, running_str); } else rtos->thread_details[tasks_found].extra_info_str = NULL; tasks_found++; list_thread_count--; rtos->thread_count = tasks_found; prev_list_elem_ptr = list_elem_ptr; list_elem_ptr = 0; retval = target_read_u32(rtos->target, prev_list_elem_ptr + param->list_elem_next_offset, &list_elem_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading next thread item location in FreeRTOS thread list"); free(list_of_lists); return retval; } LOG_DEBUG("FreeRTOS: Read next thread location at 0x%" PRIx32 ", value 0x%" PRIx32, prev_list_elem_ptr + param->list_elem_next_offset, list_elem_ptr); } } free(list_of_lists); return 0; } static int freertos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { int retval; const struct freertos_params *param; int64_t stack_ptr = 0; if (!rtos) return -1; if (thread_id == 0) return -2; if (!rtos->rtos_specific_params) return -1; param = (const struct freertos_params *) rtos->rtos_specific_params; /* Read the stack pointer */ uint32_t pointer_casts_are_bad; retval = target_read_u32(rtos->target, thread_id + param->thread_stack_offset, &pointer_casts_are_bad); if (retval != ERROR_OK) { LOG_ERROR("Error reading stack frame from FreeRTOS thread"); return retval; } stack_ptr = pointer_casts_are_bad; LOG_DEBUG("FreeRTOS: Read stack pointer at 0x%" PRIx64 ", value 0x%" PRIx64, thread_id + param->thread_stack_offset, stack_ptr); /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */ int cm4_fpu_enabled = 0; struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); if (is_armv7m(armv7m_target)) { if ((armv7m_target->fp_feature == FPV4_SP) || (armv7m_target->fp_feature == FPV5_SP) || (armv7m_target->fp_feature == FPV5_DP)) { /* Found ARM v7m target which includes a FPU */ uint32_t cpacr; retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr); if (retval != ERROR_OK) { LOG_ERROR("Could not read CPACR register to check FPU state"); return -1; } /* Check if CP10 and CP11 are set to full access. */ if (cpacr & 0x00F00000) { /* Found target with enabled FPU */ cm4_fpu_enabled = 1; } } } if (cm4_fpu_enabled == 1) { /* Read the LR to decide between stacking with or without FPU */ uint32_t lr_svc = 0; retval = target_read_u32(rtos->target, stack_ptr + 0x20, &lr_svc); if (retval != ERROR_OK) { LOG_OUTPUT("Error reading stack frame from FreeRTOS thread"); return retval; } if ((lr_svc & 0x10) == 0) return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f_fpu, stack_ptr, reg_list, num_regs); else return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f, stack_ptr, reg_list, num_regs); } else return rtos_generic_stack_read(rtos->target, param->stacking_info_cm3, stack_ptr, reg_list, num_regs); } static int freertos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; *symbol_list = calloc( ARRAY_SIZE(freertos_symbol_list), sizeof(struct symbol_table_elem)); for (i = 0; i < ARRAY_SIZE(freertos_symbol_list); i++) { (*symbol_list)[i].symbol_name = freertos_symbol_list[i].name; (*symbol_list)[i].optional = freertos_symbol_list[i].optional; } return 0; } #if 0 static int freertos_set_current_thread(struct rtos *rtos, threadid_t thread_id) { return 0; } static int freertos_get_thread_ascii_info(struct rtos *rtos, threadid_t thread_id, char **info) { int retval; const struct freertos_params *param; if (!rtos) return -1; if (thread_id == 0) return -2; if (!rtos->rtos_specific_params) return -3; param = (const struct freertos_params *) rtos->rtos_specific_params; #define FREERTOS_THREAD_NAME_STR_SIZE (200) char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE]; /* Read the thread name */ retval = target_read_buffer(rtos->target, thread_id + param->thread_name_offset, FREERTOS_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); if (retval != ERROR_OK) { LOG_ERROR("Error reading first thread item location in FreeRTOS thread list"); return retval; } tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00'; if (tmp_str[0] == '\x00') strcpy(tmp_str, "No Name"); *info = malloc(strlen(tmp_str)+1); strcpy(*info, tmp_str); return 0; } #endif static bool freertos_detect_rtos(struct target *target) { if ((target->rtos->symbols) && (target->rtos->symbols[FREERTOS_VAL_PX_READY_TASKS_LISTS].address != 0)) { /* looks like FreeRTOS */ return true; } return false; } static int freertos_create(struct target *target) { for (unsigned int i = 0; i < ARRAY_SIZE(freertos_params_list); i++) if (strcmp(freertos_params_list[i].target_name, target->type->name) == 0) { target->rtos->rtos_specific_params = (void *)&freertos_params_list[i]; return 0; } LOG_ERROR("Could not find target in FreeRTOS compatibility list"); return -1; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/librtos.la %C%_librtos_la_SOURCES = \ %D%/rtos.c \ %D%/rtos_standard_stackings.c \ %D%/rtos_ecos_stackings.c \ %D%/rtos_chibios_stackings.c \ %D%/rtos_embkernel_stackings.c \ %D%/rtos_mqx_stackings.c \ %D%/rtos_ucos_iii_stackings.c \ %D%/rtos_riot_stackings.c \ %D%/rtos_nuttx_stackings.c \ %D%/FreeRTOS.c \ %D%/ThreadX.c \ %D%/eCos.c \ %D%/linux.c \ %D%/chibios.c \ %D%/chromium-ec.c \ %D%/embKernel.c \ %D%/mqx.c \ %D%/uCOS-III.c \ %D%/nuttx.c \ %D%/rtkernel.c \ %D%/hwthread.c \ %D%/zephyr.c \ %D%/riot.c \ %D%/rtos.h \ %D%/rtos_standard_stackings.h \ %D%/rtos_ecos_stackings.h \ %D%/linux_header.h \ %D%/rtos_chibios_stackings.h \ %D%/rtos_embkernel_stackings.h \ %D%/rtos_mqx_stackings.h \ %D%/rtos_riot_stackings.h \ %D%/rtos_ucos_iii_stackings.h \ %D%/rtos_nuttx_stackings.h ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/ThreadX.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/time_support.h> #include <jtag/jtag.h> #include "target/target.h" #include "target/target_type.h" #include "rtos.h" #include "helper/log.h" #include "helper/types.h" #include "rtos_standard_stackings.h" static const struct rtos_register_stacking *get_stacking_info(const struct rtos *rtos, int64_t stack_ptr); static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const struct rtos *rtos, int64_t stack_ptr); static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id); static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id); static bool threadx_detect_rtos(struct target *target); static int threadx_create(struct target *target); static int threadx_update_threads(struct rtos *rtos); static int threadx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); struct threadx_thread_state { int value; const char *desc; }; static const struct threadx_thread_state threadx_thread_states[] = { { 0, "Ready" }, { 1, "Completed" }, { 2, "Terminated" }, { 3, "Suspended" }, { 4, "Sleeping" }, { 5, "Waiting - Queue" }, { 6, "Waiting - Semaphore" }, { 7, "Waiting - Event flag" }, { 8, "Waiting - Memory" }, { 9, "Waiting - Memory" }, { 10, "Waiting - I/O" }, { 11, "Waiting - Filesystem" }, { 12, "Waiting - Network" }, { 13, "Waiting - Mutex" }, }; #define THREADX_NUM_STATES ARRAY_SIZE(threadx_thread_states) #define ARM926EJS_REGISTERS_SIZE_SOLICITED (11 * 4) static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_solicited[] = { { 0, -1, 32 }, /* r0 */ { 1, -1, 32 }, /* r1 */ { 2, -1, 32 }, /* r2 */ { 3, -1, 32 }, /* r3 */ { 4, 0x08, 32 }, /* r4 */ { 5, 0x0C, 32 }, /* r5 */ { 6, 0x10, 32 }, /* r6 */ { 7, 0x14, 32 }, /* r7 */ { 8, 0x18, 32 }, /* r8 */ { 9, 0x1C, 32 }, /* r9 */ { 10, 0x20, 32 }, /* r10 */ { 11, 0x24, 32 }, /* r11 */ { 12, -1, 32 }, /* r12 */ { 13, -2, 32 }, /* sp (r13) */ { 14, 0x28, 32 }, /* lr (r14) */ { 15, -1, 32 }, /* pc (r15) */ /*{ 16, -1, 32 },*/ /* lr (r14) */ /*{ 17, 0x28, 32 },*/ /* pc (r15) */ { 16, 0x04, 32 }, /* xPSR */ }; #define ARM926EJS_REGISTERS_SIZE_INTERRUPT (17 * 4) static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_interrupt[] = { { 0, 0x08, 32 }, /* r0 */ { 1, 0x0C, 32 }, /* r1 */ { 2, 0x10, 32 }, /* r2 */ { 3, 0x14, 32 }, /* r3 */ { 4, 0x18, 32 }, /* r4 */ { 5, 0x1C, 32 }, /* r5 */ { 6, 0x20, 32 }, /* r6 */ { 7, 0x24, 32 }, /* r7 */ { 8, 0x28, 32 }, /* r8 */ { 9, 0x2C, 32 }, /* r9 */ { 10, 0x30, 32 }, /* r10 */ { 11, 0x34, 32 }, /* r11 */ { 12, 0x38, 32 }, /* r12 */ { 13, -2, 32 }, /* sp (r13) */ { 14, 0x3C, 32 }, /* lr (r14) */ { 15, 0x40, 32 }, /* pc (r15) */ { 16, 0x04, 32 }, /* xPSR */ }; static const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking[] = { { .stack_registers_size = ARM926EJS_REGISTERS_SIZE_SOLICITED, .stack_growth_direction = -1, .num_output_registers = 17, .register_offsets = rtos_threadx_arm926ejs_stack_offsets_solicited }, { .stack_registers_size = ARM926EJS_REGISTERS_SIZE_INTERRUPT, .stack_growth_direction = -1, .num_output_registers = 17, .register_offsets = rtos_threadx_arm926ejs_stack_offsets_interrupt }, }; struct threadx_params { const char *target_name; unsigned char pointer_width; unsigned char thread_stack_offset; unsigned char thread_name_offset; unsigned char thread_state_offset; unsigned char thread_next_offset; const struct rtos_register_stacking *stacking_info; size_t stacking_info_nb; const struct rtos_register_stacking* (*fn_get_stacking_info)(const struct rtos *rtos, int64_t stack_ptr); int (*fn_is_thread_id_valid)(const struct rtos *rtos, int64_t thread_id); }; static const struct threadx_params threadx_params_list[] = { { "cortex_m", /* target_name */ 4, /* pointer_width; */ 8, /* thread_stack_offset; */ 40, /* thread_name_offset; */ 48, /* thread_state_offset; */ 136, /* thread_next_offset */ &rtos_standard_cortex_m3_stacking, /* stacking_info */ 1, /* stacking_info_nb */ NULL, /* fn_get_stacking_info */ NULL, /* fn_is_thread_id_valid */ }, { "cortex_r4", /* target_name */ 4, /* pointer_width; */ 8, /* thread_stack_offset; */ 40, /* thread_name_offset; */ 48, /* thread_state_offset; */ 136, /* thread_next_offset */ &rtos_standard_cortex_r4_stacking, /* stacking_info */ 1, /* stacking_info_nb */ NULL, /* fn_get_stacking_info */ NULL, /* fn_is_thread_id_valid */ }, { "arm926ejs", /* target_name */ 4, /* pointer_width; */ 8, /* thread_stack_offset; */ 40, /* thread_name_offset; */ 48, /* thread_state_offset; */ 136, /* thread_next_offset */ rtos_threadx_arm926ejs_stacking, /* stacking_info */ 2, /* stacking_info_nb */ get_stacking_info_arm926ejs, /* fn_get_stacking_info */ is_thread_id_valid_arm926ejs, /* fn_is_thread_id_valid */ }, { "hla_target", /* target_name */ 4, /* pointer_width; */ 8, /* thread_stack_offset; */ 40, /* thread_name_offset; */ 48, /* thread_state_offset; */ 136, /* thread_next_offset */ &rtos_standard_cortex_m3_stacking, /* stacking_info */ 1, /* stacking_info_nb */ NULL, /* fn_get_stacking_info */ NULL, /* fn_is_thread_id_valid */ }, }; enum threadx_symbol_values { THREADX_VAL_TX_THREAD_CURRENT_PTR = 0, THREADX_VAL_TX_THREAD_CREATED_PTR = 1, THREADX_VAL_TX_THREAD_CREATED_COUNT = 2, }; static const char * const threadx_symbol_list[] = { "_tx_thread_current_ptr", "_tx_thread_created_ptr", "_tx_thread_created_count", NULL }; const struct rtos_type threadx_rtos = { .name = "ThreadX", .detect_rtos = threadx_detect_rtos, .create = threadx_create, .update_threads = threadx_update_threads, .get_thread_reg_list = threadx_get_thread_reg_list, .get_symbol_list_to_lookup = threadx_get_symbol_list_to_lookup, }; static const struct rtos_register_stacking *get_stacking_info(const struct rtos *rtos, int64_t stack_ptr) { const struct threadx_params *param = (const struct threadx_params *) rtos->rtos_specific_params; if (param->fn_get_stacking_info) return param->fn_get_stacking_info(rtos, stack_ptr); return param->stacking_info + 0; } static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id) { const struct threadx_params *param; if (!rtos->rtos_specific_params) return 0; /* invalid */ param = (const struct threadx_params *) rtos->rtos_specific_params; if (param->fn_is_thread_id_valid) return param->fn_is_thread_id_valid(rtos, thread_id); return (thread_id != 0); } static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const struct rtos *rtos, int64_t stack_ptr) { const struct threadx_params *param = (const struct threadx_params *) rtos->rtos_specific_params; int retval; uint32_t flag; retval = target_read_buffer(rtos->target, stack_ptr, sizeof(flag), (uint8_t *)&flag); if (retval != ERROR_OK) { LOG_ERROR("Error reading stack data from ThreadX thread: stack_ptr=0x%" PRIx64, stack_ptr); return NULL; } if (flag == 0) { LOG_DEBUG(" solicited stack"); return param->stacking_info + 0; } else { LOG_DEBUG(" interrupt stack: %" PRIu32, flag); return param->stacking_info + 1; } } static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id) { return (thread_id != 0 && thread_id != 1); } static int threadx_update_threads(struct rtos *rtos) { int retval; int tasks_found = 0; int thread_list_size = 0; const struct threadx_params *param; if (!rtos) return -1; if (!rtos->rtos_specific_params) return -3; param = (const struct threadx_params *) rtos->rtos_specific_params; if (!rtos->symbols) { LOG_ERROR("No symbols for ThreadX"); return -4; } if (rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_COUNT].address == 0) { LOG_ERROR("Don't have the number of threads in ThreadX"); return -2; } /* read the number of threads */ retval = target_read_buffer(rtos->target, rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_COUNT].address, 4, (uint8_t *)&thread_list_size); if (retval != ERROR_OK) { LOG_ERROR("Could not read ThreadX thread count from target"); return retval; } /* wipe out previous thread details if any */ rtos_free_threadlist(rtos); /* read the current thread id */ retval = target_read_buffer(rtos->target, rtos->symbols[THREADX_VAL_TX_THREAD_CURRENT_PTR].address, 4, (uint8_t *)&rtos->current_thread); if (retval != ERROR_OK) { LOG_ERROR("Could not read ThreadX current thread from target"); return retval; } if ((thread_list_size == 0) || (rtos->current_thread == 0)) { /* Either : No RTOS threads - there is always at least the current execution though */ /* OR : No current thread - all threads suspended - show the current execution * of idling */ char tmp_str[] = "Current Execution"; thread_list_size++; tasks_found++; rtos->thread_details = malloc( sizeof(struct thread_detail) * thread_list_size); rtos->thread_details->threadid = 1; rtos->thread_details->exists = true; rtos->thread_details->extra_info_str = NULL; rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str)); strcpy(rtos->thread_details->thread_name_str, tmp_str); /* If we just invented thread 1 to represent the current execution, we * need to make sure the RTOS object also claims it's the current thread * so that threadx_get_thread_reg_list() doesn't attempt to read a * thread control block at 0x00000001. */ rtos->current_thread = 1; if (thread_list_size == 0) { rtos->thread_count = 1; return ERROR_OK; } } else { /* create space for new thread details */ rtos->thread_details = malloc( sizeof(struct thread_detail) * thread_list_size); } /* Read the pointer to the first thread */ int64_t thread_ptr = 0; retval = target_read_buffer(rtos->target, rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_PTR].address, param->pointer_width, (uint8_t *)&thread_ptr); if (retval != ERROR_OK) { LOG_ERROR("Could not read ThreadX thread location from target"); return retval; } /* loop over all threads */ int64_t prev_thread_ptr = 0; while ((thread_ptr != prev_thread_ptr) && (tasks_found < thread_list_size)) { #define THREADX_THREAD_NAME_STR_SIZE (200) char tmp_str[THREADX_THREAD_NAME_STR_SIZE]; unsigned int i = 0; int64_t name_ptr = 0; /* Save the thread pointer */ rtos->thread_details[tasks_found].threadid = thread_ptr; /* read the name pointer */ retval = target_read_buffer(rtos->target, thread_ptr + param->thread_name_offset, param->pointer_width, (uint8_t *)&name_ptr); if (retval != ERROR_OK) { LOG_ERROR("Could not read ThreadX thread name pointer from target"); return retval; } /* Read the thread name */ tmp_str[0] = '\x00'; /* Check if thread has a valid name */ if (name_ptr != 0) { retval = target_read_buffer(rtos->target, name_ptr, THREADX_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread name from ThreadX target"); return retval; } tmp_str[THREADX_THREAD_NAME_STR_SIZE - 1] = '\x00'; } if (tmp_str[0] == '\x00') strcpy(tmp_str, "No Name"); rtos->thread_details[tasks_found].thread_name_str = malloc(strlen(tmp_str)+1); strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str); /* Read the thread status */ int64_t thread_status = 0; retval = target_read_buffer(rtos->target, thread_ptr + param->thread_state_offset, 4, (uint8_t *)&thread_status); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread state from ThreadX target"); return retval; } for (i = 0; (i < THREADX_NUM_STATES) && (threadx_thread_states[i].value != thread_status); i++) { /* empty */ } const char *state_desc; if (i < THREADX_NUM_STATES) state_desc = threadx_thread_states[i].desc; else state_desc = "Unknown state"; rtos->thread_details[tasks_found].extra_info_str = malloc(strlen( state_desc)+8); sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc); rtos->thread_details[tasks_found].exists = true; tasks_found++; prev_thread_ptr = thread_ptr; /* Get the location of the next thread structure. */ thread_ptr = 0; retval = target_read_buffer(rtos->target, prev_thread_ptr + param->thread_next_offset, param->pointer_width, (uint8_t *) &thread_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading next thread pointer in ThreadX thread list"); return retval; } } rtos->thread_count = tasks_found; return 0; } static int threadx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { int retval; const struct threadx_params *param; if (!rtos) return -1; if (!is_thread_id_valid(rtos, thread_id)) return -2; if (!rtos->rtos_specific_params) return -3; param = (const struct threadx_params *) rtos->rtos_specific_params; /* Read the stack pointer */ int64_t stack_ptr = 0; retval = target_read_buffer(rtos->target, thread_id + param->thread_stack_offset, param->pointer_width, (uint8_t *)&stack_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading stack frame from ThreadX thread"); return retval; } LOG_INFO("thread: 0x%" PRIx64 ", stack_ptr=0x%" PRIx64, (uint64_t)thread_id, (uint64_t)stack_ptr); if (stack_ptr == 0) { LOG_ERROR("null stack pointer in thread"); return -5; } const struct rtos_register_stacking *stacking_info = get_stacking_info(rtos, stack_ptr); if (!stacking_info) { LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64, (uint64_t)thread_id); return -6; } return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, reg_list, num_regs); } static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; *symbol_list = calloc( ARRAY_SIZE(threadx_symbol_list), sizeof(struct symbol_table_elem)); for (i = 0; i < ARRAY_SIZE(threadx_symbol_list); i++) (*symbol_list)[i].symbol_name = threadx_symbol_list[i]; return 0; } static bool threadx_detect_rtos(struct target *target) { if ((target->rtos->symbols) && (target->rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_PTR].address != 0)) { /* looks like ThreadX */ return true; } return false; } #if 0 static int threadx_set_current_thread(struct rtos *rtos, threadid_t thread_id) { return 0; } static int threadx_get_thread_detail(struct rtos *rtos, threadid_t thread_id, struct thread_detail *detail) { unsigned int i = 0; int retval; #define THREADX_THREAD_NAME_STR_SIZE (200) char tmp_str[THREADX_THREAD_NAME_STR_SIZE]; const struct threadx_params *param; if (!rtos) return -1; if (thread_id == 0) return -2; if (!rtos->rtos_specific_params) return -3; param = (const struct threadx_params *) rtos->rtos_specific_params; if (!rtos->symbols) { LOG_ERROR("No symbols for ThreadX"); return -3; } detail->threadid = thread_id; int64_t name_ptr = 0; /* read the name pointer */ retval = target_read_buffer(rtos->target, thread_id + param->thread_name_offset, param->pointer_width, (uint8_t *)&name_ptr); if (retval != ERROR_OK) { LOG_ERROR("Could not read ThreadX thread name pointer from target"); return retval; } /* Read the thread name */ retval = target_read_buffer(rtos->target, name_ptr, THREADX_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread name from ThreadX target"); return retval; } tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00'; if (tmp_str[0] == '\x00') strcpy(tmp_str, "No Name"); detail->thread_name_str = malloc(strlen(tmp_str)+1); /* Read the thread status */ int64_t thread_status = 0; retval = target_read_buffer(rtos->target, thread_id + param->thread_state_offset, 4, (uint8_t *)&thread_status); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread state from ThreadX target"); return retval; } for (i = 0; (i < THREADX_NUM_STATES) && (threadx_thread_states[i].value != thread_status); i++) { /* empty */ } char *state_desc; if (i < THREADX_NUM_STATES) state_desc = threadx_thread_states[i].desc; else state_desc = "Unknown state"; detail->extra_info_str = malloc(strlen(state_desc)+1); detail->exists = true; return 0; } #endif static int threadx_create(struct target *target) { for (unsigned int i = 0; i < ARRAY_SIZE(threadx_params_list); i++) if (strcmp(threadx_params_list[i].target_name, target->type->name) == 0) { target->rtos->rtos_specific_params = (void *)&threadx_params_list[i]; target->rtos->current_thread = 0; target->rtos->thread_details = NULL; return 0; } LOG_ERROR("Could not find target in ThreadX compatibility list"); return -1; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/chibios.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2012 by Matthias Blaicher * * Matthias Blaicher - matthias@blaicher.com * * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/time_support.h> #include <jtag/jtag.h> #include "target/target.h" #include "target/target_type.h" #include "target/armv7m.h" #include "target/cortex_m.h" #include "rtos.h" #include "helper/log.h" #include "helper/types.h" #include "rtos_chibios_stackings.h" /** * @brief ChibiOS/RT memory signature record. * * @details Definition copied from os/kernel/include/chregistry.h of ChibiOS/RT. */ struct chibios_chdebug { char ch_identifier[4]; /**< @brief Always set to "main". */ uint8_t ch_zero; /**< @brief Must be zero. */ uint8_t ch_size; /**< @brief Size of this structure. */ uint16_t ch_version; /**< @brief Encoded ChibiOS/RT version. */ uint8_t ch_ptrsize; /**< @brief Size of a pointer. */ uint8_t ch_timesize; /**< @brief Size of a @p systime_t. */ uint8_t ch_threadsize; /**< @brief Size of a @p Thread struct. */ uint8_t cf_off_prio; /**< @brief Offset of @p p_prio field. */ uint8_t cf_off_ctx; /**< @brief Offset of @p p_ctx field. */ uint8_t cf_off_newer; /**< @brief Offset of @p p_newer field. */ uint8_t cf_off_older; /**< @brief Offset of @p p_older field. */ uint8_t cf_off_name; /**< @brief Offset of @p p_name field. */ uint8_t cf_off_stklimit; /**< @brief Offset of @p p_stklimit field. */ uint8_t cf_off_state; /**< @brief Offset of @p p_state field. */ uint8_t cf_off_flags; /**< @brief Offset of @p p_flags field. */ uint8_t cf_off_refs; /**< @brief Offset of @p p_refs field. */ uint8_t cf_off_preempt; /**< @brief Offset of @p p_preempt field. */ uint8_t cf_off_time; /**< @brief Offset of @p p_time field. */ }; #define GET_CH_KERNEL_MAJOR(coded_version) ((coded_version >> 11) & 0x1f) #define GET_CH_KERNEL_MINOR(coded_version) ((coded_version >> 6) & 0x1f) #define GET_CH_KERNEL_PATCH(coded_version) ((coded_version >> 0) & 0x3f) /** * @brief ChibiOS thread states. */ static const char * const chibios_thread_states[] = { "READY", "CURRENT", "WTSTART", "SUSPENDED", "QUEUED", "WTSEM", "WTMTX", "WTCOND", "SLEEPING", "WTEXIT", "WTOREVT", "WTANDEVT", "SNDMSGQ", "SNDMSG", "WTMSG", "FINAL" }; #define CHIBIOS_NUM_STATES ARRAY_SIZE(chibios_thread_states) /* Maximum ChibiOS thread name. There is no real limit set by ChibiOS but 64 * chars ought to be enough. */ #define CHIBIOS_THREAD_NAME_STR_SIZE (64) struct chibios_params { const char *target_name; struct chibios_chdebug *signature; const struct rtos_register_stacking *stacking_info; }; static struct chibios_params chibios_params_list[] = { { "cortex_m", /* target_name */ NULL, NULL, /* stacking_info */ }, { "hla_target", /* target_name */ NULL, NULL, /* stacking_info */ } }; static bool chibios_detect_rtos(struct target *target); static int chibios_create(struct target *target); static int chibios_update_threads(struct rtos *rtos); static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); const struct rtos_type chibios_rtos = { .name = "chibios", .detect_rtos = chibios_detect_rtos, .create = chibios_create, .update_threads = chibios_update_threads, .get_thread_reg_list = chibios_get_thread_reg_list, .get_symbol_list_to_lookup = chibios_get_symbol_list_to_lookup, }; /* In ChibiOS/RT 3.0 the rlist structure has become part of a system * data structure ch. We declare both symbols as optional and later * use whatever is available. */ enum chibios_symbol_values { CHIBIOS_VAL_RLIST = 0, CHIBIOS_VAL_CH = 1, CHIBIOS_VAL_CH_DEBUG = 2 }; static struct symbol_table_elem chibios_symbol_list[] = { { "rlist", 0, true}, /* Thread ready list */ { "ch", 0, true}, /* System data structure */ { "ch_debug", 0, false}, /* Memory Signature containing offsets of fields in rlist */ { NULL, 0, false} }; /* Offset of the rlist structure within the system data structure (ch) */ #define CH_RLIST_OFFSET 0x00 static int chibios_update_memory_signature(struct rtos *rtos) { int retval; struct chibios_params *param; struct chibios_chdebug *signature; param = (struct chibios_params *) rtos->rtos_specific_params; /* Free existing memory description.*/ free(param->signature); param->signature = NULL; signature = malloc(sizeof(*signature)); if (!signature) { LOG_ERROR("Could not allocate space for ChibiOS/RT memory signature"); return -1; } retval = target_read_buffer(rtos->target, rtos->symbols[CHIBIOS_VAL_CH_DEBUG].address, sizeof(*signature), (uint8_t *) signature); if (retval != ERROR_OK) { LOG_ERROR("Could not read ChibiOS/RT memory signature from target"); goto errfree; } if (strncmp(signature->ch_identifier, "main", 4) != 0) { LOG_ERROR("Memory signature identifier does not contain magic bytes."); goto errfree; } if (signature->ch_size < sizeof(*signature)) { LOG_ERROR("ChibiOS/RT memory signature claims to be smaller " "than expected"); goto errfree; } if (signature->ch_size > sizeof(*signature)) { LOG_WARNING("ChibiOS/RT memory signature claims to be bigger than" " expected. Assuming compatibility..."); } /* Convert endianness of version field */ const uint8_t *versiontarget = (const uint8_t *) &signature->ch_version; signature->ch_version = rtos->target->endianness == TARGET_LITTLE_ENDIAN ? le_to_h_u32(versiontarget) : be_to_h_u32(versiontarget); const uint16_t ch_version = signature->ch_version; LOG_INFO("Successfully loaded memory map of ChibiOS/RT target " "running version %i.%i.%i", GET_CH_KERNEL_MAJOR(ch_version), GET_CH_KERNEL_MINOR(ch_version), GET_CH_KERNEL_PATCH(ch_version)); /* Currently, we have the inherent assumption that all address pointers * are 32 bit wide. */ if (signature->ch_ptrsize != sizeof(uint32_t)) { LOG_ERROR("ChibiOS/RT target memory signature claims an address " "width unequal to 32 bits!"); free(signature); return -1; } param->signature = signature; return 0; errfree: /* Error reading the ChibiOS memory structure */ free(signature); param->signature = NULL; return -1; } static int chibios_update_stacking(struct rtos *rtos) { /* Sometimes the stacking can not be determined only by looking at the * target name but only a runtime. * * For example, this is the case for Cortex-M4 targets and ChibiOS which * only stack the FPU registers if it is enabled during ChibiOS build. * * Terminating which stacking is used is target depending. * * Assumptions: * - Once ChibiOS is actually initialized, the stacking is fixed. * - During startup code, the FPU might not be initialized and the * detection might fail. * - Since no threads are running during startup, the problem is solved * by delaying stacking detection until there are more threads * available than the current execution. In which case * chibios_get_thread_reg_list is called. */ int retval; if (!rtos->rtos_specific_params) return -1; struct chibios_params *param; param = (struct chibios_params *) rtos->rtos_specific_params; /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4 */ struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); if (is_armv7m(armv7m_target)) { if (armv7m_target->fp_feature != FP_NONE) { /* Found ARM v7m target which includes a FPU */ uint32_t cpacr; retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr); if (retval != ERROR_OK) { LOG_ERROR("Could not read CPACR register to check FPU state"); return -1; } /* Check if CP10 and CP11 are set to full access. * In ChibiOS this is done in ResetHandler() in crt0.c */ if (cpacr & 0x00F00000) { LOG_DEBUG("Enabled FPU detected."); param->stacking_info = &rtos_chibios_arm_v7m_stacking_w_fpu; return 0; } } /* Found ARM v7m target with no or disabled FPU */ param->stacking_info = &rtos_chibios_arm_v7m_stacking; return 0; } return -1; } static int chibios_update_threads(struct rtos *rtos) { int retval; const struct chibios_params *param; int tasks_found = 0; int rtos_valid = -1; if (!rtos->rtos_specific_params) return -1; if (!rtos->symbols) { LOG_ERROR("No symbols for ChibiOS"); return -3; } param = (const struct chibios_params *) rtos->rtos_specific_params; /* Update the memory signature saved in the target memory */ if (!param->signature) { retval = chibios_update_memory_signature(rtos); if (retval != ERROR_OK) { LOG_ERROR("Reading the memory signature of ChibiOS/RT failed"); return retval; } } /* wipe out previous thread details if any */ rtos_free_threadlist(rtos); /* ChibiOS does not save the current thread count. We have to first * parse the double linked thread list to check for errors and the number of * threads. */ const uint32_t rlist = rtos->symbols[CHIBIOS_VAL_RLIST].address ? rtos->symbols[CHIBIOS_VAL_RLIST].address : rtos->symbols[CHIBIOS_VAL_CH].address + CH_RLIST_OFFSET /* ChibiOS3 */; const struct chibios_chdebug *signature = param->signature; uint32_t current; uint32_t previous; uint32_t older; current = rlist; previous = rlist; while (1) { retval = target_read_u32(rtos->target, current + signature->cf_off_newer, ¤t); if (retval != ERROR_OK) { LOG_ERROR("Could not read next ChibiOS thread"); return retval; } /* Could be NULL if the kernel is not initialized yet or if the * registry is corrupted. */ if (current == 0) { LOG_ERROR("ChibiOS registry integrity check failed, NULL pointer"); rtos_valid = 0; break; } /* Fetch previous thread in the list as a integrity check. */ retval = target_read_u32(rtos->target, current + signature->cf_off_older, &older); if ((retval != ERROR_OK) || (older == 0) || (older != previous)) { LOG_ERROR("ChibiOS registry integrity check failed, " "double linked list violation"); rtos_valid = 0; break; } /* Check for full iteration of the linked list. */ if (current == rlist) break; tasks_found++; previous = current; } if (!rtos_valid) { /* No RTOS, there is always at least the current execution, though */ LOG_INFO("Only showing current execution because of a broken " "ChibiOS thread registry."); const char tmp_thread_name[] = "Current Execution"; const char tmp_thread_extra_info[] = "No RTOS thread"; rtos->thread_details = malloc( sizeof(struct thread_detail)); rtos->thread_details->threadid = 1; rtos->thread_details->exists = true; rtos->thread_details->extra_info_str = malloc( sizeof(tmp_thread_extra_info)); strcpy(rtos->thread_details->extra_info_str, tmp_thread_extra_info); rtos->thread_details->thread_name_str = malloc( sizeof(tmp_thread_name)); strcpy(rtos->thread_details->thread_name_str, tmp_thread_name); rtos->current_thread = 1; rtos->thread_count = 1; return ERROR_OK; } /* create space for new thread details */ rtos->thread_details = malloc( sizeof(struct thread_detail) * tasks_found); if (!rtos->thread_details) { LOG_ERROR("Could not allocate space for thread details"); return -1; } rtos->thread_count = tasks_found; /* Loop through linked list. */ struct thread_detail *curr_thrd_details = rtos->thread_details; while (curr_thrd_details < rtos->thread_details + tasks_found) { uint32_t name_ptr = 0; char tmp_str[CHIBIOS_THREAD_NAME_STR_SIZE]; retval = target_read_u32(rtos->target, current + signature->cf_off_newer, ¤t); if (retval != ERROR_OK) { LOG_ERROR("Could not read next ChibiOS thread"); return -6; } /* Check for full iteration of the linked list. */ if (current == rlist) break; /* Save the thread pointer */ curr_thrd_details->threadid = current; /* read the name pointer */ retval = target_read_u32(rtos->target, current + signature->cf_off_name, &name_ptr); if (retval != ERROR_OK) { LOG_ERROR("Could not read ChibiOS thread name pointer from target"); return retval; } /* Read the thread name */ retval = target_read_buffer(rtos->target, name_ptr, CHIBIOS_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread name from ChibiOS target"); return retval; } tmp_str[CHIBIOS_THREAD_NAME_STR_SIZE - 1] = '\x00'; if (tmp_str[0] == '\x00') strcpy(tmp_str, "No Name"); curr_thrd_details->thread_name_str = malloc( strlen(tmp_str) + 1); strcpy(curr_thrd_details->thread_name_str, tmp_str); /* State info */ uint8_t thread_state; const char *state_desc; retval = target_read_u8(rtos->target, current + signature->cf_off_state, &thread_state); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread state from ChibiOS target"); return retval; } if (thread_state < CHIBIOS_NUM_STATES) state_desc = chibios_thread_states[thread_state]; else state_desc = "Unknown"; curr_thrd_details->extra_info_str = malloc(strlen( state_desc)+8); sprintf(curr_thrd_details->extra_info_str, "State: %s", state_desc); curr_thrd_details->exists = true; curr_thrd_details++; } uint32_t current_thrd; /* NOTE: By design, cf_off_name equals readylist_current_offset */ retval = target_read_u32(rtos->target, rlist + signature->cf_off_name, ¤t_thrd); if (retval != ERROR_OK) { LOG_ERROR("Could not read current Thread from ChibiOS target"); return retval; } rtos->current_thread = current_thrd; return 0; } static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { int retval; const struct chibios_params *param; uint32_t stack_ptr = 0; if ((!rtos) || (thread_id == 0) || (!rtos->rtos_specific_params)) return -1; param = (const struct chibios_params *) rtos->rtos_specific_params; if (!param->signature) return -1; /* Update stacking if it can only be determined from runtime information */ if (!param->stacking_info && (chibios_update_stacking(rtos) != ERROR_OK)) { LOG_ERROR("Failed to determine exact stacking for the target type %s", rtos->target->type->name); return -1; } /* Read the stack pointer */ retval = target_read_u32(rtos->target, thread_id + param->signature->cf_off_ctx, &stack_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading stack frame from ChibiOS thread"); return retval; } return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs); } static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { *symbol_list = malloc(sizeof(chibios_symbol_list)); if (!*symbol_list) return ERROR_FAIL; memcpy(*symbol_list, chibios_symbol_list, sizeof(chibios_symbol_list)); return 0; } static bool chibios_detect_rtos(struct target *target) { if ((target->rtos->symbols) && ((target->rtos->symbols[CHIBIOS_VAL_RLIST].address != 0) || (target->rtos->symbols[CHIBIOS_VAL_CH].address != 0))) { if (target->rtos->symbols[CHIBIOS_VAL_CH_DEBUG].address == 0) { LOG_INFO("It looks like the target may be running ChibiOS " "without ch_debug."); return false; } /* looks like ChibiOS with memory map enabled.*/ return true; } return false; } static int chibios_create(struct target *target) { for (unsigned int i = 0; i < ARRAY_SIZE(chibios_params_list); i++) if (strcmp(chibios_params_list[i].target_name, target->type->name) == 0) { target->rtos->rtos_specific_params = (void *)&chibios_params_list[i]; return 0; } LOG_WARNING("Could not find target \"%s\" in ChibiOS compatibility " "list", target->type->name); return -1; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/chromium-ec.c ================================================ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018 National Instruments Corp * Author: Moritz Fischer <moritz.fischer@ettus.com> * * Chromium-EC RTOS Task Awareness */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/bits.h> #include <rtos/rtos.h> #include <target/target.h> #include <target/target_type.h> #include "rtos_standard_stackings.h" #define CROS_EC_MAX_TASKS 32 #define CROS_EC_MAX_NAME 200 #define CROS_EC_IDLE_STRING "<< idle >>" struct chromium_ec_params { const char *target_name; size_t ptr_size; off_t task_offset_next; off_t task_offset_sp; off_t task_offset_events; off_t task_offset_runtime; const struct rtos_register_stacking *stacking; }; static const struct chromium_ec_params chromium_ec_params_list[] = { { .target_name = "hla_target", .ptr_size = 4, .task_offset_next = 24, .task_offset_sp = 0, .task_offset_events = 4, .task_offset_runtime = 8, .stacking = &rtos_standard_cortex_m3_stacking, }, { .target_name = "cortex_m", .ptr_size = 4, .task_offset_next = 24, .task_offset_sp = 0, .task_offset_events = 4, .task_offset_runtime = 8, .stacking = &rtos_standard_cortex_m3_stacking, }, }; static const char * const chromium_ec_symbol_list[] = { "start_called", "current_task", "tasks", "tasks_enabled", "tasks_ready", "task_names", "build_info", NULL, }; enum chromium_ec_symbol_values { CHROMIUM_EC_VAL_START_CALLED = 0, CHROMIUM_EC_VAL_CURRENT_TASK, CHROMIUM_EC_VAL_TASKS, CHROMIUM_EC_VAL_TASKS_ENABLED, CHROMIUM_EC_VAL_TASKS_READY, CHROMIUM_EC_VAL_TASK_NAMES, CHROMIUM_EC_VAL_BUILD_INFO, CHROMIUM_EC_VAL_COUNT, }; #define CROS_EC_MAX_BUILDINFO 512 static bool chromium_ec_detect_rtos(struct target *target) { char build_info_buf[CROS_EC_MAX_BUILDINFO]; enum chromium_ec_symbol_values sym; int ret; if (!target || !target->rtos || !target->rtos->symbols) return false; for (sym = CHROMIUM_EC_VAL_START_CALLED; sym < CHROMIUM_EC_VAL_COUNT; sym++) { if (target->rtos->symbols[sym].address) { LOG_DEBUG("Chromium-EC: Symbol \"%s\" found", chromium_ec_symbol_list[sym]); } else { LOG_ERROR("Chromium-EC: Symbol \"%s\" missing", chromium_ec_symbol_list[sym]); return false; } } ret = target_read_buffer(target, target->rtos->symbols[CHROMIUM_EC_VAL_BUILD_INFO].address, sizeof(build_info_buf), (uint8_t *)build_info_buf); if (ret != ERROR_OK) return false; LOG_INFO("Chromium-EC: Buildinfo: %s", build_info_buf); return target->rtos->symbols && target->rtos->symbols[CHROMIUM_EC_VAL_START_CALLED].address; } static int chromium_ec_create(struct target *target) { struct chromium_ec_params *params; size_t t; for (t = 0; t < ARRAY_SIZE(chromium_ec_params_list); t++) if (!strcmp(chromium_ec_params_list[t].target_name, target->type->name)) { params = malloc(sizeof(*params)); if (!params) { LOG_ERROR("Chromium-EC: out of memory"); return ERROR_FAIL; } memcpy(params, &chromium_ec_params_list[t], sizeof(*params)); target->rtos->rtos_specific_params = (void *)params; target->rtos->current_thread = 0; target->rtos->thread_details = NULL; target->rtos->thread_count = 0; LOG_INFO("Chromium-EC: Using target: %s", target->type->name); return ERROR_OK; } LOG_ERROR("Chromium-EC: target not supported: %s", target->type->name); return ERROR_FAIL; } static int chromium_ec_get_current_task_ptr(struct rtos *rtos, uint32_t *current_task) { if (!rtos || !rtos->symbols) return ERROR_FAIL; return target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_CURRENT_TASK].address, current_task); } static int chromium_ec_get_num_tasks(struct rtos *rtos, int *num_tasks) { uint32_t tasks_enabled; int ret, t, found; ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_TASKS_ENABLED].address, &tasks_enabled); if (ret != ERROR_OK) { LOG_ERROR("Failed to determine #of tasks"); return ret; } found = 0; for (t = 0; t < CROS_EC_MAX_TASKS; t++) if (tasks_enabled & BIT(t)) found++; *num_tasks = found; return ERROR_OK; } static int chromium_ec_update_threads(struct rtos *rtos) { uint32_t tasks_enabled, tasks_ready, start_called; uint32_t current_task, thread_ptr, name_ptr; char thread_str_buf[CROS_EC_MAX_NAME]; int ret, t, num_tasks, tasks_found; struct chromium_ec_params *params; uint8_t runtime_buf[8]; uint64_t runtime; uint32_t events; params = rtos->rtos_specific_params; if (!params) return ERROR_FAIL; if (!rtos->symbols) return ERROR_FAIL; num_tasks = 0; ret = chromium_ec_get_num_tasks(rtos, &num_tasks); if (ret != ERROR_OK) { LOG_ERROR("Failed to get number of tasks"); return ret; } current_task = 0; ret = chromium_ec_get_current_task_ptr(rtos, ¤t_task); if (ret != ERROR_OK) { LOG_ERROR("Failed to get current task"); return ret; } LOG_DEBUG("Current task: %lx tasks_found: %d", (unsigned long)current_task, num_tasks); /* set current task to what we read */ rtos->current_thread = current_task; /* Nuke the old tasks */ rtos_free_threadlist(rtos); /* One check if task switching has started ... */ start_called = 0; ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_START_CALLED].address, &start_called); if (ret != ERROR_OK) { LOG_ERROR("Failed to load start_called"); return ret; } if (!rtos->current_thread || !num_tasks || !start_called) { num_tasks++; rtos->thread_details = malloc( sizeof(struct thread_detail) * num_tasks); rtos->thread_details->threadid = 1; rtos->thread_details->exists = true; rtos->thread_details->extra_info_str = NULL; rtos->thread_details->thread_name_str = strdup("Current Execution"); if (!num_tasks || !start_called) { rtos->thread_count = 1; return ERROR_OK; } } else { /* create space for new thread details */ rtos->thread_details = malloc( sizeof(struct thread_detail) * num_tasks); } tasks_enabled = 0; ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_TASKS_ENABLED].address, &tasks_enabled); if (ret != ERROR_OK) { LOG_ERROR("Failed to load tasks_enabled"); return ret; } tasks_ready = 0; ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_TASKS_READY].address, &tasks_ready); if (ret != ERROR_OK) { LOG_ERROR("Failed to load tasks_ready"); return ret; } thread_ptr = rtos->symbols[CHROMIUM_EC_VAL_TASKS].address; tasks_found = 0; for (t = 0; t < CROS_EC_MAX_TASKS; t++) { if (!(tasks_enabled & BIT(t))) continue; if (thread_ptr == current_task) rtos->current_thread = thread_ptr; rtos->thread_details[tasks_found].threadid = thread_ptr; ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_TASK_NAMES].address + params->ptr_size * t, &name_ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read name_ptr"); return ret; } /* read name buffer */ ret = target_read_buffer(rtos->target, name_ptr, CROS_EC_MAX_NAME, (uint8_t *)thread_str_buf); if (ret != ERROR_OK) { LOG_ERROR("Failed to read task name"); return ret; } /* sanitize string, gdb chokes on "<< idle >>" */ if (thread_str_buf[CROS_EC_MAX_NAME - 1] != '\0') thread_str_buf[CROS_EC_MAX_NAME - 1] = '\0'; if (!strncmp(thread_str_buf, CROS_EC_IDLE_STRING, CROS_EC_MAX_NAME)) rtos->thread_details[tasks_found].thread_name_str = strdup("IDLE"); else rtos->thread_details[tasks_found].thread_name_str = strdup(thread_str_buf); events = 0; ret = target_read_u32(rtos->target, thread_ptr + params->task_offset_events, &events); if (ret != ERROR_OK) LOG_ERROR("Failed to get task %d's events", t); /* this is a bit kludgy but will do for now */ ret = target_read_buffer(rtos->target, thread_ptr + params->task_offset_runtime, sizeof(runtime_buf), runtime_buf); if (ret != ERROR_OK) LOG_ERROR("Failed to get task %d's runtime", t); runtime = target_buffer_get_u64(rtos->target, runtime_buf); /* Priority is simply the position in the array */ if (thread_ptr == current_task) snprintf(thread_str_buf, sizeof(thread_str_buf), "State: Running, Priority: %u, Events: %" PRIx32 ", Runtime: %" PRIu64 "\n", t, events, runtime); else snprintf(thread_str_buf, sizeof(thread_str_buf), "State: %s, Priority: %u, Events: %" PRIx32 ", Runtime: %" PRIu64 "\n", tasks_ready & BIT(t) ? "Ready" : "Waiting", t, events, runtime); rtos->thread_details[tasks_found].extra_info_str = strdup(thread_str_buf); rtos->thread_details[tasks_found].exists = true; thread_ptr += params->task_offset_next; tasks_found++; } rtos->thread_count = tasks_found; return ERROR_OK; } static int chromium_ec_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, struct rtos_reg **reg_list, int *num_regs) { struct chromium_ec_params *params = rtos->rtos_specific_params; uint32_t stack_ptr = 0; int ret, t; for (t = 0; t < rtos->thread_count; t++) if (threadid == rtos->thread_details[t].threadid) break; /* if we didn't find threadid, bail */ if (t == rtos->thread_count) return ERROR_FAIL; ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_TASKS].address + params->task_offset_next * t, &stack_ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to load TCB"); return ret; } return rtos_generic_stack_read(rtos->target, params->stacking, stack_ptr, reg_list, num_regs); } static int chromium_ec_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { size_t s; *symbol_list = calloc(ARRAY_SIZE(chromium_ec_symbol_list), sizeof(struct symbol_table_elem)); if (!(*symbol_list)) { LOG_ERROR("Chromium-EC: out of memory"); return ERROR_FAIL; } for (s = 0; s < ARRAY_SIZE(chromium_ec_symbol_list); s++) (*symbol_list)[s].symbol_name = chromium_ec_symbol_list[s]; return ERROR_OK; } const struct rtos_type chromium_ec_rtos = { .name = "Chromium-EC", .detect_rtos = chromium_ec_detect_rtos, .create = chromium_ec_create, .update_threads = chromium_ec_update_threads, .get_thread_reg_list = chromium_ec_get_thread_reg_list, .get_symbol_list_to_lookup = chromium_ec_get_symbol_list_to_lookup, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/eCos.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/time_support.h> #include <jtag/jtag.h> #include "target/target.h" #include "target/target_type.h" #include "target/armv7m.h" #include "rtos.h" #include "helper/log.h" #include "helper/types.h" #include "helper/bits.h" #include "rtos_standard_stackings.h" #include "rtos_ecos_stackings.h" #include "server/gdb_server.h" /* Unfortunately for the moment we are limited to returning the hardwired * register count (ARMV7M_NUM_CORE_REGS for Cortex-M) since the openocd RTOS * support does not yet support accessing all per-thread "stacked" * registers. e.g. For Cortex-M under eCos we have a per-thread BASEPRI, and for * all eCos targets we may have per-thread VFP/FPU register state. * * So, for the moment, we continue to use the hardwired limit for the depth of * the returned register description vector. The current openocd * rtos_standard_stackings.c just provides the main core regs for the Cortex_M* * targets regardless of whether FPU is present/enabled. * * However, this code is written with the expectation that we may eventually be * able to provide more register information ("m-system" and "vfp" for example) * and also with the expectation of supporting different register sets being * returned depending on the per-thread Cortex-M eCos contex_m for * example. Hence the fact that the eCos_stack_layout_*() functions below allow * for the stack context descriptor vector to be returned by those calls * allowing for eventual support where this code will potentially cache * different sets of register descriptors for the different shapes of contexts * in a *single* application/binary run-time. * * TODO: Extend openocd generic RTOS support to allow thread-specific system and * FPU register state to be returned. */ struct ecos_params; static bool ecos_detect_rtos(struct target *target); static int ecos_create(struct target *target); static int ecos_update_threads(struct rtos *rtos); static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int ecos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); static int ecos_stack_layout_cortexm(struct rtos *rtos, struct ecos_params *param, int64_t stack_ptr, const struct rtos_register_stacking **si); static int ecos_stack_layout_arm(struct rtos *rtos, struct ecos_params *param, int64_t stack_ptr, const struct rtos_register_stacking **si); /* The current eCos thread IDentifier uses 0 as an unused (not a valid thread * ID) value. Currently the unique_id field is 16-bits, but the eCos SMP support * convention is that only 12-bits of the ID will be used. This * ECOS_MAX_THREAD_COUNT manifest is provided to limit the potential for * interpreting stale/inconsistent thread list state when the debug host scans * the thread list before the target RTOS has completed its initialisation. This * support will need to revisited when eCos is re-engineered to support more * than 16 CPU SMP setups. */ #define ECOS_MAX_THREAD_COUNT (4095) struct ecos_thread_state { int value; const char *desc; }; /* The status is actually a logical-OR bitmask of states: */ enum ecos_thread_state_flags { RUNNING = 0, /* explicit no-bits-set value */ SLEEPING = BIT(0), COUNTSLEEP = BIT(1), SUSPENDED = BIT(2), CREATING = BIT(3), EXITED = BIT(4), SLEEPSET = (SLEEPING | COUNTSLEEP) }; /* Cyg_Thread:: reason codes for wake and sleep fields: */ static const struct ecos_thread_state ecos_thread_reasons[] = { { 0, "NONE" }, /* normally indicates "not yet started" */ { 1, "WAIT" }, /* wait with no timeout */ { 2, "DELAY" }, /* simple time delay */ { 3, "TIMEOUT" }, /* wait with timeout *or* timeout expired */ { 4, "BREAK" }, /* forced break out of sleep */ { 5, "DESTRUCT" }, /* wait on object being destroyed */ { 6, "EXIT" }, /* forced termination */ { 7, "DONE" } /* wait/delay completed */ }; static const char * const target_cortex_m[] = { "cortex_m", "hla_target", NULL }; static const char * const target_arm[] = { "cortex_a", "arm7tdmi", "arm720t", "arm9tdmi", "arm920t", "arm926ejs", "arm946e", "arm966e", "arm11", NULL }; /* Since individual eCos application configurations may have different thread * object structure layouts depending on the actual build-time enabled features * we provide support for applications built containing the relevant symbolic * support to match the actual application binary being debugged, rather than * relying on a set of default/fixed (and potentially incorrect) * offsets. However, for backwards compatibility, we do *NOT* enforce the * requirement for the common extra helper symbols to be present to allow the * fallback to the simple fixed CM3 model to avoid affecting existing users of * older eCos worlds. Similarly we need to provide support for per-thread * register context offsets, as well as for per-application-configurations, * since some targets can have different stacked state on a per-thread basis * (e.g. "cortex_m"). This is why the stacking_info is now set at run-time * rather than being fixed. */ struct ecos_params { const char * const *target_names; /* NULL terminated list of targets */ int (*target_stack_layout)(struct rtos *rtos, struct ecos_params *param, int64_t stack_ptr, const struct rtos_register_stacking **si); bool flush_common; unsigned char pointer_width; unsigned char uid_width; unsigned char state_width; unsigned int thread_stack_offset; unsigned int thread_name_offset; unsigned int thread_state_offset; unsigned int thread_next_offset; unsigned int thread_uniqueid_offset; const struct rtos_register_stacking *stacking_info; }; /* As mentioned above we provide default offset values for the "cortex_m" * targets for backwards compatibility with older eCos application builds and * previous users of this RTOS specific support that do not have the * configuration specific offsets provided in the symbol table. The support for * other targets (e.g. "cortex_a") we do expect the application to provide the * required symbolic information. We do not populate the stacking_info reference * until we have had a chance to interrogate the symbol table. */ static struct ecos_params ecos_params_list[] = { { .target_names = target_cortex_m, .pointer_width = 4, .uid_width = 2, .state_width = 4, .thread_stack_offset = 0x0c, .thread_name_offset = 0x9c, .thread_state_offset = 0x3c, .thread_next_offset = 0xa0, .thread_uniqueid_offset = 0x4c, .target_stack_layout = ecos_stack_layout_cortexm, .stacking_info = NULL }, { .target_names = target_arm, .pointer_width = 0, .uid_width = 0, .state_width = 0, .thread_stack_offset = 0, .thread_name_offset = 0, .thread_state_offset = 0, .thread_next_offset = 0, .thread_uniqueid_offset = 0, .target_stack_layout = ecos_stack_layout_arm, .stacking_info = NULL } }; #define ECOS_NUM_PARAMS ARRAY_SIZE(ecos_params_list) /* To eventually allow for more than just the ARMV7M_NUM_CORE_REGS to be * returned by the Cortex-M support, and to avoid run-time lookups we manually * maintain our own mapping for the supplied stack register vector entries. This * enum needs to match the rtos_ecos_regoff_cortexm[] vector. Admittedly the * initial indices just match the corresponding ARMV7M_R* definitions, but after * the base registers the ARMV7M_* number space does not match the vector we * wish to populate in this eCos support code. */ enum ecos_reglist_cortexm { ECOS_REGLIST_R0 = 0, ECOS_REGLIST_R1, ECOS_REGLIST_R2, ECOS_REGLIST_R3, ECOS_REGLIST_R4, ECOS_REGLIST_R5, ECOS_REGLIST_R6, ECOS_REGLIST_R7, ECOS_REGLIST_R8, ECOS_REGLIST_R9, ECOS_REGLIST_R10, ECOS_REGLIST_R11, ECOS_REGLIST_R12, ECOS_REGLIST_R13, ECOS_REGLIST_R14, ECOS_REGLIST_PC, ECOS_REGLIST_XPSR, /* ARMV7M_NUM_CORE_REGS */ ECOS_REGLIST_BASEPRI, ECOS_REGLIST_FPSCR, /* Following for FPU contexts */ ECOS_REGLIST_D0, ECOS_REGLIST_D1, ECOS_REGLIST_D2, ECOS_REGLIST_D3, ECOS_REGLIST_D4, ECOS_REGLIST_D5, ECOS_REGLIST_D6, ECOS_REGLIST_D7, ECOS_REGLIST_D8, ECOS_REGLIST_D9, ECOS_REGLIST_D10, ECOS_REGLIST_D11, ECOS_REGLIST_D12, ECOS_REGLIST_D13, ECOS_REGLIST_D14, ECOS_REGLIST_D15 }; #define ECOS_CORTEXM_BASE_NUMREGS (ARMV7M_NUM_CORE_REGS) /* NOTE: The offsets in this vector are overwritten by the architecture specific * layout functions depending on the specific application configuration. The * ordering of this vector MUST match eCos_reglist. */ static struct stack_register_offset rtos_ecos_regoff_cortexm[] = { { ARMV7M_R0, -1, 32 }, /* r0 */ { ARMV7M_R1, -1, 32 }, /* r1 */ { ARMV7M_R2, -1, 32 }, /* r2 */ { ARMV7M_R3, -1, 32 }, /* r3 */ { ARMV7M_R4, -1, 32 }, /* r4 */ { ARMV7M_R5, -1, 32 }, /* r5 */ { ARMV7M_R6, -1, 32 }, /* r6 */ { ARMV7M_R7, -1, 32 }, /* r7 */ { ARMV7M_R8, -1, 32 }, /* r8 */ { ARMV7M_R9, -1, 32 }, /* r9 */ { ARMV7M_R10, -1, 32 }, /* r10 */ { ARMV7M_R11, -1, 32 }, /* r11 */ { ARMV7M_R12, -1, 32 }, /* r12 */ { ARMV7M_R13, -1, 32 }, /* sp */ { ARMV7M_R14, -1, 32 }, /* lr */ { ARMV7M_PC, -1, 32 }, /* pc */ { ARMV7M_XPSR, -1, 32 }, /* xPSR */ { ARMV7M_BASEPRI, -1, 32 }, /* BASEPRI */ { ARMV7M_FPSCR, -1, 32 }, /* FPSCR */ { ARMV7M_D0, -1, 64 }, /* D0 (S0/S1) */ { ARMV7M_D1, -1, 64 }, /* D1 (S2/S3) */ { ARMV7M_D2, -1, 64 }, /* D2 (S4/S5) */ { ARMV7M_D3, -1, 64 }, /* D3 (S6/S7) */ { ARMV7M_D4, -1, 64 }, /* D4 (S8/S9) */ { ARMV7M_D5, -1, 64 }, /* D5 (S10/S11) */ { ARMV7M_D6, -1, 64 }, /* D6 (S12/S13) */ { ARMV7M_D7, -1, 64 }, /* D7 (S14/S15) */ { ARMV7M_D8, -1, 64 }, /* D8 (S16/S17) */ { ARMV7M_D9, -1, 64 }, /* D9 (S18/S19) */ { ARMV7M_D10, -1, 64 }, /* D10 (S20/S21) */ { ARMV7M_D11, -1, 64 }, /* D11 (S22/S23) */ { ARMV7M_D12, -1, 64 }, /* D12 (S24/S25) */ { ARMV7M_D13, -1, 64 }, /* D13 (S26/S27) */ { ARMV7M_D14, -1, 64 }, /* D14 (S28/S29) */ { ARMV7M_D15, -1, 64 }, /* D15 (S30/S31) */ }; static struct stack_register_offset rtos_ecos_regoff_arm[] = { { 0, -1, 32 }, /* r0 */ { 1, -1, 32 }, /* r1 */ { 2, -1, 32 }, /* r2 */ { 3, -1, 32 }, /* r3 */ { 4, -1, 32 }, /* r4 */ { 5, -1, 32 }, /* r5 */ { 6, -1, 32 }, /* r6 */ { 7, -1, 32 }, /* r7 */ { 8, -1, 32 }, /* r8 */ { 9, -1, 32 }, /* r9 */ { 10, -1, 32 }, /* r10 */ { 11, -1, 32 }, /* r11 (fp) */ { 12, -1, 32 }, /* r12 (ip) */ { 13, -1, 32 }, /* sp (r13) */ { 14, -1, 32 }, /* lr (r14) */ { 15, -1, 32 }, /* pc (r15) */ { 16, -1, 32 }, /* xPSR */ }; static struct rtos_register_stacking rtos_ecos_stacking = { .stack_registers_size = 0, .stack_growth_direction = -1, .num_output_registers = 0, .calculate_process_stack = NULL, /* stack_alignment */ .register_offsets = NULL }; /* To avoid the run-time cost of matching explicit symbol names we push the * lookup offsets to this *manually* maintained enumeration which must match the * ecos_symbol_list[] order below. */ enum ecos_symbol_values { ECOS_VAL_THREAD_LIST = 0, ECOS_VAL_CURRENT_THREAD_PTR, ECOS_VAL_COMMON_THREAD_NEXT_OFF, ECOS_VAL_COMMON_THREAD_NEXT_SIZE, ECOS_VAL_COMMON_THREAD_STATE_OFF, ECOS_VAL_COMMON_THREAD_STATE_SIZE, ECOS_VAL_COMMON_THREAD_SLEEP_OFF, ECOS_VAL_COMMON_THREAD_SLEEP_SIZE, ECOS_VAL_COMMON_THREAD_WAKE_OFF, ECOS_VAL_COMMON_THREAD_WAKE_SIZE, ECOS_VAL_COMMON_THREAD_ID_OFF, ECOS_VAL_COMMON_THREAD_ID_SIZE, ECOS_VAL_COMMON_THREAD_NAME_OFF, ECOS_VAL_COMMON_THREAD_NAME_SIZE, ECOS_VAL_COMMON_THREAD_PRI_OFF, ECOS_VAL_COMMON_THREAD_PRI_SIZE, ECOS_VAL_COMMON_THREAD_STACK_OFF, ECOS_VAL_COMMON_THREAD_STACK_SIZE, ECOS_VAL_CORTEXM_THREAD_SAVED, ECOS_VAL_CORTEXM_CTX_THREAD_SIZE, ECOS_VAL_CORTEXM_CTX_TYPE_OFF, ECOS_VAL_CORTEXM_CTX_TYPE_SIZE, ECOS_VAL_CORTEXM_CTX_BASEPRI_OFF, ECOS_VAL_CORTEXM_CTX_BASEPRI_SIZE, ECOS_VAL_CORTEXM_CTX_SP_OFF, ECOS_VAL_CORTEXM_CTX_SP_SIZE, ECOS_VAL_CORTEXM_CTX_REG_OFF, ECOS_VAL_CORTEXM_CTX_REG_SIZE, ECOS_VAL_CORTEXM_CTX_PC_OFF, ECOS_VAL_CORTEXM_CTX_PC_SIZE, ECOS_VAL_CORTEXM_VAL_EXCEPTION, ECOS_VAL_CORTEXM_VAL_THREAD, ECOS_VAL_CORTEXM_VAL_INTERRUPT, ECOS_VAL_CORTEXM_VAL_FPU, ECOS_VAL_CORTEXM_CTX_FPSCR_OFF, ECOS_VAL_CORTEXM_CTX_FPSCR_SIZE, ECOS_VAL_CORTEXM_CTX_S_OFF, ECOS_VAL_CORTEXM_CTX_S_SIZE, ECOS_VAL_ARM_REGSIZE, ECOS_VAL_ARM_CTX_R0_OFF, ECOS_VAL_ARM_CTX_R1_OFF, ECOS_VAL_ARM_CTX_R2_OFF, ECOS_VAL_ARM_CTX_R3_OFF, ECOS_VAL_ARM_CTX_R4_OFF, ECOS_VAL_ARM_CTX_R5_OFF, ECOS_VAL_ARM_CTX_R6_OFF, ECOS_VAL_ARM_CTX_R7_OFF, ECOS_VAL_ARM_CTX_R8_OFF, ECOS_VAL_ARM_CTX_R9_OFF, ECOS_VAL_ARM_CTX_R10_OFF, ECOS_VAL_ARM_CTX_FP_OFF, ECOS_VAL_ARM_CTX_IP_OFF, ECOS_VAL_ARM_CTX_SP_OFF, ECOS_VAL_ARM_CTX_LR_OFF, ECOS_VAL_ARM_CTX_PC_OFF, ECOS_VAL_ARM_CTX_CPSR_OFF, ECOS_VAL_ARM_FPUSIZE, ECOS_VAL_ARM_CTX_FPSCR_OFF, ECOS_VAL_ARM_SCOUNT, ECOS_VAL_ARM_CTX_SVEC_OFF, ECOS_VAL_ARM_VFPCOUNT, ECOS_VAL_ARM_CTX_VFPVEC_OFF }; struct symbols { const char *name; const char * const *target_names; /* non-NULL when for a specific architecture */ bool optional; }; #define ECOSSYM(_n, _o, _t) { .name = _n, .optional = (_o), .target_names = _t } /* Some of offset/size helper symbols are common to all eCos * targets. Unfortunately, for historical reasons, some information is in * architecture specific namespaces leading to some duplication and a larger * vector below. */ static const struct symbols ecos_symbol_list[] = { ECOSSYM("Cyg_Thread::thread_list", false, NULL), ECOSSYM("Cyg_Scheduler_Base::current_thread", false, NULL), /* Following symbols *are* required for generic application-specific * configuration support, but we mark as optional for backwards * compatibility with the previous fixed Cortex-M3 only RTOS plugin * implementation. */ ECOSSYM("__ecospro_syminfo.off.cyg_thread.list_next", true, NULL), ECOSSYM("__ecospro_syminfo.size.cyg_thread.list_next", true, NULL), ECOSSYM("__ecospro_syminfo.off.cyg_thread.state", true, NULL), ECOSSYM("__ecospro_syminfo.size.cyg_thread.state", true, NULL), ECOSSYM("__ecospro_syminfo.off.cyg_thread.sleep_reason", true, NULL), ECOSSYM("__ecospro_syminfo.size.cyg_thread.sleep_reason", true, NULL), ECOSSYM("__ecospro_syminfo.off.cyg_thread.wake_reason", true, NULL), ECOSSYM("__ecospro_syminfo.size.cyg_thread.wake_reason", true, NULL), ECOSSYM("__ecospro_syminfo.off.cyg_thread.unique_id", true, NULL), ECOSSYM("__ecospro_syminfo.size.cyg_thread.unique_id", true, NULL), ECOSSYM("__ecospro_syminfo.off.cyg_thread.name", true, NULL), ECOSSYM("__ecospro_syminfo.size.cyg_thread.name", true, NULL), ECOSSYM("__ecospro_syminfo.off.cyg_thread.priority", true, NULL), ECOSSYM("__ecospro_syminfo.size.cyg_thread.priority", true, NULL), ECOSSYM("__ecospro_syminfo.off.cyg_thread.stack_ptr", true, NULL), ECOSSYM("__ecospro_syminfo.size.cyg_thread.stack_ptr", true, NULL), /* optional Cortex-M: */ ECOSSYM("__ecospro_syminfo.cortexm.thread.saved", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.Thread", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.type", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.type", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.basepri", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.basepri", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.sp", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.sp", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.r", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.r", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.pc", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.pc", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.value.HAL_SAVEDREGISTERS.EXCEPTION", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.value.HAL_SAVEDREGISTERS.THREAD", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.value.HAL_SAVEDREGISTERS.INTERRUPT", true, target_cortex_m), /* optional Cortex-M with H/W FPU configured: */ ECOSSYM("__ecospro_syminfo.value.HAL_SAVEDREGISTERS.WITH_FPU", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.fpscr", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.fpscr", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.s", true, target_cortex_m), ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.s", true, target_cortex_m), /* optional ARM: */ ECOSSYM("ARMREG_SIZE", true, target_arm), ECOSSYM("armreg_r0", true, target_arm), ECOSSYM("armreg_r1", true, target_arm), ECOSSYM("armreg_r2", true, target_arm), ECOSSYM("armreg_r3", true, target_arm), ECOSSYM("armreg_r4", true, target_arm), ECOSSYM("armreg_r5", true, target_arm), ECOSSYM("armreg_r6", true, target_arm), ECOSSYM("armreg_r7", true, target_arm), ECOSSYM("armreg_r8", true, target_arm), ECOSSYM("armreg_r9", true, target_arm), ECOSSYM("armreg_r10", true, target_arm), ECOSSYM("armreg_fp", true, target_arm), ECOSSYM("armreg_ip", true, target_arm), ECOSSYM("armreg_sp", true, target_arm), ECOSSYM("armreg_lr", true, target_arm), ECOSSYM("armreg_pc", true, target_arm), ECOSSYM("armreg_cpsr", true, target_arm), /* optional ARM FPU common: */ ECOSSYM("ARMREG_FPUCONTEXT_SIZE", true, target_arm), ECOSSYM("armreg_fpscr", true, target_arm), /* optional ARM FPU single-precision: */ ECOSSYM("ARMREG_S_COUNT", true, target_arm), ECOSSYM("armreg_s_vec", true, target_arm), /* optional ARM FPU double-precision: */ ECOSSYM("ARMREG_VFP_COUNT", true, target_arm), ECOSSYM("armreg_vfp_vec", true, target_arm), }; const struct rtos_type ecos_rtos = { .name = "eCos", .detect_rtos = ecos_detect_rtos, .create = ecos_create, .update_threads = ecos_update_threads, .get_thread_reg_list = ecos_get_thread_reg_list, .get_symbol_list_to_lookup = ecos_get_symbol_list_to_lookup, }; static symbol_address_t ecos_value(struct rtos *rtos, unsigned int idx) { if (idx < ARRAY_SIZE(ecos_symbol_list)) return rtos->symbols[idx].address; /* We do not terminate, just return 0 in this case. */ LOG_ERROR("eCos: Invalid symbol index %u", idx); return 0; } #define XMLENTRY(_c, _s) { .xc = (_c), .rs = (_s), .rlen = (sizeof(_s) - 1) } static const struct { char xc; const char *rs; size_t rlen; } xmlchars[] = { XMLENTRY('<', "<"), XMLENTRY('&', "&"), XMLENTRY('>', ">"), XMLENTRY('\'', "'"), XMLENTRY('"', """) }; /** Escape any XML reserved characters in a string. */ static bool ecos_escape_string(const char *raw, char *out, size_t limit) { static const char *tokens = "<&>\'\""; bool escaped = false; if (!out || !limit) return false; (void)memset(out, '\0', limit); while (raw && *raw && limit) { size_t lok = strcspn(raw, tokens); if (lok) { size_t tocopy; tocopy = ((limit < lok) ? limit : lok); (void)memcpy(out, raw, tocopy); limit -= tocopy; out += tocopy; raw += lok; continue; } char *fidx = strchr(tokens, *raw); if (!fidx) { /* Should never happen assuming xmlchars * vector and tokens string match. */ LOG_ERROR("eCos: Unexpected XML char %c", *raw); continue; } uint32_t cidx = (fidx - tokens); size_t tocopy = xmlchars[cidx].rlen; if (limit < tocopy) break; escaped = true; (void)memcpy(out, xmlchars[cidx].rs, tocopy); limit -= tocopy; out += tocopy; raw++; } return escaped; } static int ecos_check_app_info(struct rtos *rtos, struct ecos_params *param) { if (!rtos || !param) return -1; if (param->flush_common) { if (debug_level >= LOG_LVL_DEBUG) { for (unsigned int idx = 0; idx < ARRAY_SIZE(ecos_symbol_list); idx++) { LOG_DEBUG("eCos: %s 0x%016" PRIX64 " %s", rtos->symbols[idx].optional ? "OPTIONAL" : " ", rtos->symbols[idx].address, rtos->symbols[idx].symbol_name); } } /* If "__ecospro_syminfo.size.cyg_thread.list_next" is non-zero then we * expect all of the generic thread structure symbols to have been * provided. */ symbol_address_t thread_next_size = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_NEXT_SIZE); if (thread_next_size != 0) { param->pointer_width = thread_next_size; param->uid_width = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_ID_SIZE); param->state_width = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_STATE_SIZE); param->thread_stack_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_STACK_OFF); param->thread_name_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_NAME_OFF); param->thread_state_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_STATE_OFF); param->thread_next_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_NEXT_OFF); param->thread_uniqueid_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_ID_OFF); } if (param->uid_width != sizeof(uint16_t)) { /* Currently all eCos configurations use a 16-bit field to hold the * unique thread ID. */ LOG_WARNING("eCos: Unexpected unique_id width %" PRIu8, param->uid_width); param->uid_width = (unsigned char)sizeof(uint16_t); } param->stacking_info = NULL; param->flush_common = false; } return ERROR_OK; } /* The Cortex-M eCosPro "thread" contexts have a "type" indicator, which tracks * the context state of (THREAD | EXCEPTION | INTERRUPT) and whether FPU * registers are saved. * * For thread-aware debugging from GDB we are only interested in THREAD states * and so do not need to implement support for INTERRUPT or EXCEPTION thread * contexts since this code does not expose those stack contexts via the * constructed thread list support. */ static int ecos_stack_layout_cortexm(struct rtos *rtos, struct ecos_params *param, int64_t stack_ptr, const struct rtos_register_stacking **si) { int retval = ERROR_OK; /* CONSIDER: We could return * ecos_value(rtos, ECOS_VAL_CORTEXM_THREAD_SAVED) as the actual PC * address of a context switch, with the LR being set to the context PC * field to give a true representation of where the thread switch * occurs. However that would require extending the common * rtos_generic_stack_read() code with suitable support for applying a * supplied value, or just implementing our own version of that code that * can inject data into what is passed onwards to GDB. */ /* UPDATE: When we can return VFP register state then we will NOT be * basing the cached state on the single param->stacking_info value, * since we will need a different stacking_info structure returned for * each thread type when FPU support is enabled. The use of the single * param->stacking_info is a holder whilst we are limited to the fixed * ARMV7M_NUM_CORE_REGS set of descriptors. */ if (!param->stacking_info && ecos_value(rtos, ECOS_VAL_CORTEXM_THREAD_SAVED) && ecos_value(rtos, ECOS_VAL_CORTEXM_VAL_THREAD)) { unsigned char numoutreg = ECOS_CORTEXM_BASE_NUMREGS; rtos_ecos_stacking.stack_registers_size = ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_THREAD_SIZE); rtos_ecos_stacking.calculate_process_stack = rtos_generic_stack_align8; rtos_ecos_stacking.register_offsets = rtos_ecos_regoff_cortexm; rtos_ecos_regoff_cortexm[ECOS_REGLIST_R0].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x00); rtos_ecos_regoff_cortexm[ECOS_REGLIST_R1].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x04); rtos_ecos_regoff_cortexm[ECOS_REGLIST_R2].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x08); rtos_ecos_regoff_cortexm[ECOS_REGLIST_R3].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x0C); rtos_ecos_regoff_cortexm[ECOS_REGLIST_R4].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x10); rtos_ecos_regoff_cortexm[ECOS_REGLIST_R5].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x14); rtos_ecos_regoff_cortexm[ECOS_REGLIST_R6].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x18); rtos_ecos_regoff_cortexm[ECOS_REGLIST_R7].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x1C); rtos_ecos_regoff_cortexm[ECOS_REGLIST_R8].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x20); rtos_ecos_regoff_cortexm[ECOS_REGLIST_R9].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x24); rtos_ecos_regoff_cortexm[ECOS_REGLIST_R10].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x28); rtos_ecos_regoff_cortexm[ECOS_REGLIST_R11].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x2C); rtos_ecos_regoff_cortexm[ECOS_REGLIST_R12].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x30); /* Rather than using the stacked ECOS_VAL_CORTEXM_CTX_SP_OFF * value we force the reported sp to be after the stacked * register context. */ rtos_ecos_regoff_cortexm[ECOS_REGLIST_R13].offset = -2; rtos_ecos_regoff_cortexm[ECOS_REGLIST_R14].offset = -1; rtos_ecos_regoff_cortexm[ECOS_REGLIST_PC].offset = ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_PC_OFF); rtos_ecos_regoff_cortexm[ECOS_REGLIST_XPSR].offset = -1; param->stacking_info = &rtos_ecos_stacking; /* Common Cortex-M thread register offsets for the current * symbol table: */ if (retval == ERROR_OK && param->stacking_info) { if (numoutreg > ECOS_REGLIST_BASEPRI) { rtos_ecos_regoff_cortexm[ECOS_REGLIST_BASEPRI].offset = ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_BASEPRI_OFF); } rtos_ecos_stacking.num_output_registers = numoutreg; } } if (si) *si = param->stacking_info; return retval; } static int ecos_stack_layout_arm(struct rtos *rtos, struct ecos_params *param, int64_t stack_ptr, const struct rtos_register_stacking **si) { int retval = ERROR_OK; if (!param->stacking_info && ecos_value(rtos, ECOS_VAL_ARM_REGSIZE)) { /* When OpenOCD is extended to allow FPU registers to be returned from a * stacked thread context we can check: * if (0 != ecos_value(rtos, ECOS_VAL_ARM_FPUSIZE)) { FPU } * for presence of FPU registers in the context. */ rtos_ecos_stacking.stack_registers_size = ecos_value(rtos, ECOS_VAL_ARM_REGSIZE); rtos_ecos_stacking.num_output_registers = ARRAY_SIZE(rtos_ecos_regoff_arm); rtos_ecos_stacking.register_offsets = rtos_ecos_regoff_arm; rtos_ecos_regoff_arm[0].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R0_OFF); rtos_ecos_regoff_arm[1].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R1_OFF); rtos_ecos_regoff_arm[2].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R2_OFF); rtos_ecos_regoff_arm[3].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R3_OFF); rtos_ecos_regoff_arm[4].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R4_OFF); rtos_ecos_regoff_arm[5].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R5_OFF); rtos_ecos_regoff_arm[6].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R6_OFF); rtos_ecos_regoff_arm[7].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R7_OFF); rtos_ecos_regoff_arm[8].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R8_OFF); rtos_ecos_regoff_arm[9].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R9_OFF); rtos_ecos_regoff_arm[10].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R10_OFF); rtos_ecos_regoff_arm[11].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_FP_OFF); rtos_ecos_regoff_arm[12].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_IP_OFF); rtos_ecos_regoff_arm[13].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_SP_OFF); rtos_ecos_regoff_arm[14].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_LR_OFF); rtos_ecos_regoff_arm[15].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_PC_OFF); rtos_ecos_regoff_arm[16].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_CPSR_OFF); param->stacking_info = &rtos_ecos_stacking; } if (si) *si = param->stacking_info; return retval; } /* We see this function called on a new connection, it looks like before and * after the "tar rem"/"tar extended-remote". It might be the only point we can * decide to cache information (to check if the symbol table has changed). */ static int ecos_update_threads(struct rtos *rtos) { int retval; int tasks_found = 0; int thread_list_size = 0; struct ecos_params *param; if (!rtos) return -1; /* wipe out previous thread details if any */ rtos_free_threadlist(rtos); if (!rtos->rtos_specific_params) return -3; param = rtos->rtos_specific_params; if (!rtos->symbols) { /* NOTE: We only see this when connecting from GDB the first * time before the application image is loaded. So it is not a * hook for detecting an application change. */ param->flush_common = true; LOG_ERROR("No symbols for eCos"); return -4; } retval = ecos_check_app_info(rtos, param); if (retval != ERROR_OK) return retval; if (rtos->symbols[ECOS_VAL_THREAD_LIST].address == 0) { LOG_ERROR("Don't have the thread list head"); return -2; } /* determine the number of current threads */ uint32_t thread_list_head = rtos->symbols[ECOS_VAL_THREAD_LIST].address; uint32_t thread_index; target_read_buffer(rtos->target, thread_list_head, param->pointer_width, (uint8_t *) &thread_index); uint32_t first_thread = thread_index; /* Even if 0==first_thread indicates a system with no defined eCos * threads, instead of early exiting here we fall through the code to * allow the creation of a faked "Current Execution" descriptor as * needed. */ if (first_thread) { /* Since the OpenOCD RTOS support can attempt to obtain thread * information on initial connection when the system *may* have * undefined memory state it is possible for a simple thread count scan * to produce invalid results. To avoid blocking indefinitely when * encountering an invalid closed loop we limit the number of threads to * the maximum possible, and if we pass that limit then something is * wrong so treat the system as having no threads defined. */ do { thread_list_size++; if (thread_list_size > ECOS_MAX_THREAD_COUNT) { /* Treat as "no threads" case: */ first_thread = 0; thread_list_size = 0; break; } retval = target_read_buffer(rtos->target, thread_index + param->thread_next_offset, param->pointer_width, (uint8_t *)&thread_index); if (retval != ERROR_OK) return retval; } while (thread_index != first_thread); } /* read the current thread id */ rtos->current_thread = 0; uint32_t current_thread_addr; retval = target_read_buffer(rtos->target, rtos->symbols[ECOS_VAL_CURRENT_THREAD_PTR].address, param->pointer_width, (uint8_t *)¤t_thread_addr); if (retval != ERROR_OK) { LOG_ERROR("Reading active thread address"); return retval; } if (current_thread_addr) { uint16_t id = 0; retval = target_read_buffer(rtos->target, current_thread_addr + param->thread_uniqueid_offset, param->uid_width, (uint8_t *)&id); if (retval != ERROR_OK) { LOG_ERROR("Could not read eCos current thread from target"); return retval; } rtos->current_thread = (threadid_t)id; } if (thread_list_size == 0 || rtos->current_thread == 0) { /* Either : No RTOS threads - there is always at least the current execution though */ /* OR : No current thread - all threads suspended - show the current execution * of idling */ static const char tmp_str[] = "Current Execution"; thread_list_size++; tasks_found++; rtos->thread_details = malloc( sizeof(struct thread_detail) * thread_list_size); /* 1 is a valid eCos thread id, so we return 0 for this faked * "current" CPU state: */ rtos->thread_details->threadid = 0; rtos->thread_details->exists = true; rtos->thread_details->extra_info_str = NULL; rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str)); strcpy(rtos->thread_details->thread_name_str, tmp_str); /* Early exit if current CPU state our only "thread": */ if (thread_list_size == 1) { rtos->thread_count = 1; return ERROR_OK; } } else { /* create space for new thread details */ rtos->thread_details = malloc( sizeof(struct thread_detail) * thread_list_size); } /* loop over all threads */ thread_index = first_thread; do { #define ECOS_THREAD_NAME_STR_SIZE (200) char tmp_str[ECOS_THREAD_NAME_STR_SIZE]; uint32_t name_ptr = 0; uint32_t prev_thread_ptr; /* Save the thread ID. For eCos the thread has a unique ID distinct from * the thread_index descriptor pointer. We present this scheduler ID * instead of the descriptor memory address. */ uint16_t thread_id = 0; retval = target_read_buffer(rtos->target, thread_index + param->thread_uniqueid_offset, param->uid_width, (uint8_t *)&thread_id); if (retval != ERROR_OK) { LOG_ERROR("Could not read eCos thread id from target"); return retval; } rtos->thread_details[tasks_found].threadid = thread_id; /* Read the name pointer */ retval = target_read_buffer(rtos->target, thread_index + param->thread_name_offset, param->pointer_width, (uint8_t *)&name_ptr); if (retval != ERROR_OK) { LOG_ERROR("Could not read eCos thread name pointer from target"); return retval; } /* Read the thread name */ retval = target_read_buffer(rtos->target, name_ptr, ECOS_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread name from eCos target"); return retval; } tmp_str[ECOS_THREAD_NAME_STR_SIZE-1] = '\x00'; /* Since eCos can have arbitrary C string names we can sometimes * get an internal warning from GDB about "not well-formed * (invalid token)" since the XML post-processing done by GDB on * the OpenOCD returned response containing the thread strings * is not escaped. For example the eCos kernel testsuite * application tm_basic uses the thread name "<<NULL>>" which * will trigger this failure unless escaped. */ if (tmp_str[0] == '\x00') { snprintf(tmp_str, ECOS_THREAD_NAME_STR_SIZE, "NoName:[0x%08" PRIX32 "]", thread_index); } else { /* The following is a workaround to avoid any issues * from arbitrary eCos thread names causing GDB/OpenOCD * issues. We limit the escaped thread name passed to * GDB to the same length as the un-escaped just to * avoid overly long strings. */ char esc_str[ECOS_THREAD_NAME_STR_SIZE]; bool escaped = ecos_escape_string(tmp_str, esc_str, sizeof(esc_str)); if (escaped) strcpy(tmp_str, esc_str); } rtos->thread_details[tasks_found].thread_name_str = malloc(strlen(tmp_str)+1); strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str); /* Read the thread status */ int64_t thread_status = 0; retval = target_read_buffer(rtos->target, thread_index + param->thread_state_offset, param->state_width, (uint8_t *)&thread_status); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread state from eCos target"); return retval; } /* The thread_status is a BITMASK */ char state_desc[21]; /* Enough for "suspended+countsleep\0" maximum */ if (thread_status & SUSPENDED) strcpy(state_desc, "suspended+"); else state_desc[0] = '\0'; switch (thread_status & ~SUSPENDED) { case RUNNING: if (thread_index == current_thread_addr) strcat(state_desc, "running"); else if (thread_status & SUSPENDED) state_desc[9] = '\0'; /* Drop '+' from "suspended+" */ else strcat(state_desc, "ready"); break; case SLEEPING: strcat(state_desc, "sleeping"); break; case SLEEPSET: case COUNTSLEEP: strcat(state_desc, "counted sleep"); break; case CREATING: strcpy(state_desc, "creating"); break; case EXITED: strcpy(state_desc, "exited"); break; default: strcpy(state_desc, "unknown state"); break; } /* For the moment we do not bother decoding the wake reason for the * active "running" thread, but it is useful providing the sleep reason * for stacked threads. */ int64_t sleep_reason = 0; /* sleep reason */ if (thread_index != current_thread_addr && ecos_value(rtos, ECOS_VAL_COMMON_THREAD_SLEEP_SIZE)) { retval = target_read_buffer(rtos->target, (thread_index + ecos_value(rtos, ECOS_VAL_COMMON_THREAD_SLEEP_OFF)), ecos_value(rtos, ECOS_VAL_COMMON_THREAD_SLEEP_SIZE), (uint8_t *)&sleep_reason); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread sleep reason from eCos target"); return retval; } if (sleep_reason < 0 || sleep_reason > (int64_t)ARRAY_SIZE(ecos_thread_reasons)) { sleep_reason = 0; } } /* We do not display anything for the Cyg_Thread::NONE reason */ size_t tr_extra = 0; const char *reason_desc = NULL; if (sleep_reason) reason_desc = ecos_thread_reasons[sleep_reason].desc; if (reason_desc) tr_extra = 2 + strlen(reason_desc) + 1; /* Display thread priority if available: */ int64_t priority = 0; size_t pri_extra = 0; if (ecos_value(rtos, ECOS_VAL_COMMON_THREAD_PRI_SIZE)) { retval = target_read_buffer(rtos->target, (thread_index + ecos_value(rtos, ECOS_VAL_COMMON_THREAD_PRI_OFF)), ecos_value(rtos, ECOS_VAL_COMMON_THREAD_PRI_SIZE), (uint8_t *)&priority); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread priority from eCos target"); return retval; } pri_extra = (12 + 20); /* worst-case ", Priority: " */ } size_t eilen = (8 + strlen(state_desc) + tr_extra + pri_extra); char *eistr = malloc(eilen); /* We do not need to treat a malloc failure as a fatal error here since * the code below will just not report extra thread information if NULL, * thus allowing all of the threads to be enumerated even with reduced * information when the host is low on memory. However... */ if (!eistr) { LOG_ERROR("OOM allocating extra information buffer"); return ERROR_FAIL; } int soff = snprintf(eistr, eilen, "State: %s", state_desc); if (tr_extra && reason_desc) soff += snprintf(&eistr[soff], (eilen - soff), " (%s)", reason_desc); if (pri_extra) (void)snprintf(&eistr[soff], (eilen - soff), ", Priority: %" PRId64 "", priority); rtos->thread_details[tasks_found].extra_info_str = eistr; rtos->thread_details[tasks_found].exists = true; tasks_found++; prev_thread_ptr = thread_index; /* Get the location of the next thread structure. */ thread_index = rtos->symbols[ECOS_VAL_THREAD_LIST].address; retval = target_read_buffer(rtos->target, prev_thread_ptr + param->thread_next_offset, param->pointer_width, (uint8_t *) &thread_index); if (retval != ERROR_OK) { LOG_ERROR("Error reading next thread pointer in eCos thread list"); return retval; } } while (thread_index != first_thread); rtos->thread_count = tasks_found; return ERROR_OK; } static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { int retval; struct ecos_params *param; if (!rtos) return -1; if (thread_id == 0) return -2; if (!rtos->rtos_specific_params) return -3; param = rtos->rtos_specific_params; retval = ecos_check_app_info(rtos, param); if (retval != ERROR_OK) return retval; /* We can get memory access errors reported by this function on * re-connecting to a board with stale thread information in memory. The * initial ecos_update_threads() is called twice and may read * stale/invalid information depending on the memory state. This happens * as part of the "target remote" connection so cannot be avoided by GDB * scripting. It is not critical and allowing the application to run and * initialise its BSS etc. will allow correct thread and register * information to be obtained. This really only affects debug sessions * where "info thr" is used before the initial run-time initialisation * has occurred. */ /* Find the thread with that thread id */ uint16_t id = 0; uint32_t thread_list_head = rtos->symbols[ECOS_VAL_THREAD_LIST].address; uint32_t thread_index; target_read_buffer(rtos->target, thread_list_head, param->pointer_width, (uint8_t *)&thread_index); bool done = false; while (!done) { retval = target_read_buffer(rtos->target, thread_index + param->thread_uniqueid_offset, param->uid_width, (uint8_t *)&id); if (retval != ERROR_OK) { LOG_ERROR("Error reading unique id from eCos thread 0x%08" PRIX32 "", thread_index); return retval; } if (id == thread_id) { done = true; break; } target_read_buffer(rtos->target, thread_index + param->thread_next_offset, param->pointer_width, (uint8_t *) &thread_index); } if (done) { /* Read the stack pointer */ int64_t stack_ptr = 0; retval = target_read_buffer(rtos->target, thread_index + param->thread_stack_offset, param->pointer_width, (uint8_t *)&stack_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading stack frame from eCos thread"); return retval; } if (!stack_ptr) { LOG_ERROR("NULL stack pointer in thread %" PRIu64, thread_id); return -5; } const struct rtos_register_stacking *stacking_info = NULL; if (param->target_stack_layout) { retval = param->target_stack_layout(rtos, param, stack_ptr, &stacking_info); if (retval != ERROR_OK) { LOG_ERROR("Error reading stack layout for eCos thread"); return retval; } } if (!stacking_info) stacking_info = &rtos_ecos_cortex_m3_stacking; return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, reg_list, num_regs); } return -1; } /* NOTE: This is only called once when the first GDB connection is made to * OpenOCD and not on subsequent connections (when the application symbol table * may have changed, affecting the offsets of critical fields and the stacked * context shape). */ static int ecos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; *symbol_list = calloc( ARRAY_SIZE(ecos_symbol_list), sizeof(struct symbol_table_elem)); /* If the target reference was passed into this function we could limit * the symbols we need to lookup to the target->type->name based * range. For the moment we need to provide a single vector with all of * the symbols across all of the supported architectures. */ for (i = 0; i < ARRAY_SIZE(ecos_symbol_list); i++) { (*symbol_list)[i].symbol_name = ecos_symbol_list[i].name; (*symbol_list)[i].optional = ecos_symbol_list[i].optional; } return 0; } /* NOTE: Only called by rtos.c:rtos_qsymbol() when auto-detecting the RTOS. If * the target configuration uses the explicit "-rtos" config option then this * detection routine is NOT called. */ static bool ecos_detect_rtos(struct target *target) { if ((target->rtos->symbols) && (target->rtos->symbols[ECOS_VAL_THREAD_LIST].address != 0)) { /* looks like eCos */ return true; } return false; } /* Since we should never have 0 as a valid eCos thread ID we use $Hg0 as the * indicator of a new session as regards flushing any cached state. */ static int ecos_packet_hook(struct connection *connection, const char *packet, int packet_size) { int64_t current_threadid; if (packet[0] == 'H' && packet[1] == 'g') { int numscan = sscanf(packet, "Hg%16" SCNx64, ¤t_threadid); if (numscan == 1 && current_threadid == 0) { struct target *target = get_target_from_connection(connection); if (target && target->rtos && target->rtos->rtos_specific_params) { struct ecos_params *param; param = target->rtos->rtos_specific_params; param->flush_common = true; } } } return rtos_thread_packet(connection, packet, packet_size); } /* Called at start of day when eCos detected or specified in config file. */ static int ecos_create(struct target *target) { for (unsigned int i = 0; i < ARRAY_SIZE(ecos_params_list); i++) { const char * const *tnames = ecos_params_list[i].target_names; while (*tnames) { if (strcmp(*tnames, target->type->name) == 0) { /* LOG_DEBUG("eCos: matched target \"%s\"", target->type->name); */ target->rtos->rtos_specific_params = (void *)&ecos_params_list[i]; ecos_params_list[i].flush_common = true; ecos_params_list[i].stacking_info = NULL; target->rtos->current_thread = 0; target->rtos->thread_details = NULL; /* We use the $Hg0 packet as a new GDB connection "start-of-day" hook to * force a re-cache of information. It is possible for a single OpenOCD * session to be connected to a target with multiple GDB debug sessions * started/stopped. With eCos it is possible for those GDB sessions to * present applications with different offsets within a thread * descriptor for fields used by this module, and for the stacked * context within the connected target architecture to differ between * applications and even between threads in a single application. So we * need to ensure any information we cache is flushed on an application * change, and GDB referencing an invalid eCos thread ID (0) is a good * enough point, since we can accept the re-cache hit if that packet * appears during an established session, whilst benefiting from not * re-loading information on every update_threads or get_thread_reg_list * call. */ target->rtos->gdb_thread_packet = ecos_packet_hook; /* We do not currently use the target->rtos->gdb_target_for_threadid * hook. */ return 0; } tnames++; } } LOG_ERROR("Could not find target in eCos compatibility list"); return -1; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/embKernel.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/time_support.h> #include <jtag/jtag.h> #include "target/target.h" #include "target/target_type.h" #include "rtos.h" #include "helper/log.h" #include "helper/types.h" #include "rtos_embkernel_stackings.h" #define EMBKERNEL_MAX_THREAD_NAME_STR_SIZE (64) static bool embkernel_detect_rtos(struct target *target); static int embkernel_create(struct target *target); static int embkernel_update_threads(struct rtos *rtos); static int embkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int embkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); const struct rtos_type embkernel_rtos = { .name = "embKernel", .detect_rtos = embkernel_detect_rtos, .create = embkernel_create, .update_threads = embkernel_update_threads, .get_thread_reg_list = embkernel_get_thread_reg_list, .get_symbol_list_to_lookup = embkernel_get_symbol_list_to_lookup, }; enum { SYMBOL_ID_S_CURRENT_TASK = 0, SYMBOL_ID_S_LIST_READY = 1, SYMBOL_ID_S_LIST_SLEEP = 2, SYMBOL_ID_S_LIST_SUSPENDED = 3, SYMBOL_ID_S_MAX_PRIORITIES = 4, SYMBOL_ID_S_CURRENT_TASK_COUNT = 5, }; static const char * const embkernel_symbol_list[] = { "Rtos::sCurrentTask", "Rtos::sListReady", "Rtos::sListSleep", "Rtos::sListSuspended", "Rtos::sMaxPriorities", "Rtos::sCurrentTaskCount", NULL }; struct embkernel_params { const char *target_name; const unsigned char pointer_width; const unsigned char thread_count_width; const unsigned char rtos_list_size; const unsigned char thread_stack_offset; const unsigned char thread_name_offset; const unsigned char thread_priority_offset; const unsigned char thread_priority_width; const unsigned char iterable_next_offset; const unsigned char iterable_task_owner_offset; const struct rtos_register_stacking *stacking_info; }; static const struct embkernel_params embkernel_params_list[] = { { "cortex_m", /* target_name */ 4, /* pointer_width */ 4, /* thread_count_width */ 8, /*rtos_list_size */ 0, /*thread_stack_offset */ 4, /*thread_name_offset */ 8, /*thread_priority_offset */ 4, /*thread_priority_width */ 4, /*iterable_next_offset */ 12, /*iterable_task_owner_offset */ &rtos_embkernel_cortex_m_stacking, /* stacking_info*/ }, { "hla_target", /* target_name */ 4, /* pointer_width */ 4, /* thread_count_width */ 8, /*rtos_list_size */ 0, /*thread_stack_offset */ 4, /*thread_name_offset */ 8, /*thread_priority_offset */ 4, /*thread_priority_width */ 4, /*iterable_next_offset */ 12, /*iterable_task_owner_offset */ &rtos_embkernel_cortex_m_stacking, /* stacking_info */ } }; static bool embkernel_detect_rtos(struct target *target) { if (target->rtos->symbols) { if (target->rtos->symbols[SYMBOL_ID_S_CURRENT_TASK].address != 0) return true; } return false; } static int embkernel_create(struct target *target) { size_t i = 0; while ((i < ARRAY_SIZE(embkernel_params_list)) && (strcmp(embkernel_params_list[i].target_name, target->type->name) != 0)) i++; if (i >= ARRAY_SIZE(embkernel_params_list)) { LOG_WARNING("Could not find target \"%s\" in embKernel compatibility " "list", target->type->name); return -1; } target->rtos->rtos_specific_params = (void *) &embkernel_params_list[i]; return 0; } static int embkernel_get_tasks_details(struct rtos *rtos, int64_t iterable, const struct embkernel_params *param, struct thread_detail *details, const char *state_str) { int64_t task = 0; int retval = target_read_buffer(rtos->target, iterable + param->iterable_task_owner_offset, param->pointer_width, (uint8_t *) &task); if (retval != ERROR_OK) return retval; details->threadid = (threadid_t) task; details->exists = true; int64_t name_ptr = 0; retval = target_read_buffer(rtos->target, task + param->thread_name_offset, param->pointer_width, (uint8_t *) &name_ptr); if (retval != ERROR_OK) return retval; details->thread_name_str = malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE); if (name_ptr) { retval = target_read_buffer(rtos->target, name_ptr, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, (uint8_t *) details->thread_name_str); if (retval != ERROR_OK) return retval; details->thread_name_str[EMBKERNEL_MAX_THREAD_NAME_STR_SIZE - 1] = 0; } else { snprintf(details->thread_name_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "NoName:[0x%08X]", (unsigned int) task); } int64_t priority = 0; retval = target_read_buffer(rtos->target, task + param->thread_priority_offset, param->thread_priority_width, (uint8_t *) &priority); if (retval != ERROR_OK) return retval; details->extra_info_str = malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE); if (task == rtos->current_thread) { snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "State: Running, Priority: %u", (unsigned int) priority); } else { snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "State: %s, Priority: %u", state_str, (unsigned int) priority); } LOG_OUTPUT("Getting task details: iterable=0x%08X, task=0x%08X, name=%s\n", (unsigned int)iterable, (unsigned int)task, details->thread_name_str); return 0; } static int embkernel_update_threads(struct rtos *rtos) { /* int i = 0; */ int retval; const struct embkernel_params *param; if (!rtos) return -1; if (!rtos->rtos_specific_params) return -3; if (!rtos->symbols) { LOG_ERROR("No symbols for embKernel"); return -4; } if (rtos->symbols[SYMBOL_ID_S_CURRENT_TASK].address == 0) { LOG_ERROR("Don't have the thread list head"); return -2; } /* wipe out previous thread details if any */ rtos_free_threadlist(rtos); param = (const struct embkernel_params *) rtos->rtos_specific_params; retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_CURRENT_TASK].address, param->pointer_width, (uint8_t *) &rtos->current_thread); if (retval != ERROR_OK) { LOG_ERROR("Error reading current thread in embKernel thread list"); return retval; } int64_t max_used_priority = 0; retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_MAX_PRIORITIES].address, param->pointer_width, (uint8_t *) &max_used_priority); if (retval != ERROR_OK) return retval; int thread_list_size = 0; retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_CURRENT_TASK_COUNT].address, param->thread_count_width, (uint8_t *) &thread_list_size); if (retval != ERROR_OK) { LOG_ERROR("Could not read embKernel thread count from target"); return retval; } /* create space for new thread details */ rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size); if (!rtos->thread_details) { LOG_ERROR("Error allocating memory for %d threads", thread_list_size); return ERROR_FAIL; } int thread_idx = 0; /* Look for ready tasks */ for (int pri = 0; pri < max_used_priority; pri++) { /* Get first item in queue */ int64_t iterable = 0; retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_LIST_READY].address + (pri * param->rtos_list_size), param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; for (; iterable && thread_idx < thread_list_size; thread_idx++) { /* Get info from this iterable item */ retval = embkernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[thread_idx], "Ready"); if (retval != ERROR_OK) return retval; /* Get next iterable item */ retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; } } /* Look for sleeping tasks */ int64_t iterable = 0; retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_LIST_SLEEP].address, param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; for (; iterable && thread_idx < thread_list_size; thread_idx++) { /*Get info from this iterable item */ retval = embkernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[thread_idx], "Sleeping"); if (retval != ERROR_OK) return retval; /*Get next iterable item */ retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; } /* Look for suspended tasks */ iterable = 0; retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_LIST_SUSPENDED].address, param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; for (; iterable && thread_idx < thread_list_size; thread_idx++) { /* Get info from this iterable item */ retval = embkernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[thread_idx], "Suspended"); if (retval != ERROR_OK) return retval; /*Get next iterable item */ retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; } rtos->thread_count = 0; rtos->thread_count = thread_idx; LOG_OUTPUT("Found %u tasks\n", (unsigned int)thread_idx); return 0; } static int embkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { int retval; const struct embkernel_params *param; int64_t stack_ptr = 0; if (!rtos) return -1; if (thread_id == 0) return -2; if (!rtos->rtos_specific_params) return -1; param = (const struct embkernel_params *) rtos->rtos_specific_params; /* Read the stack pointer */ retval = target_read_buffer(rtos->target, thread_id + param->thread_stack_offset, param->pointer_width, (uint8_t *) &stack_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading stack frame from embKernel thread"); return retval; } return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs); } static int embkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; *symbol_list = calloc(ARRAY_SIZE(embkernel_symbol_list), sizeof(struct symbol_table_elem)); for (i = 0; i < ARRAY_SIZE(embkernel_symbol_list); i++) (*symbol_list)[i].symbol_name = embkernel_symbol_list[i]; return 0; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/hwthread.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/time_support.h> #include <jtag/jtag.h> #include "target/target.h" #include "target/target_type.h" #include "target/register.h" #include <target/smp.h> #include "rtos.h" #include "helper/log.h" #include "helper/types.h" #include "server/gdb_server.h" static bool hwthread_detect_rtos(struct target *target); static int hwthread_create(struct target *target); static int hwthread_update_threads(struct rtos *rtos); static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id, uint32_t reg_num, struct rtos_reg *rtos_reg); static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); static int hwthread_smp_init(struct target *target); static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, uint8_t *buffer); static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, const uint8_t *buffer); #define HW_THREAD_NAME_STR_SIZE (32) static inline threadid_t threadid_from_target(const struct target *target) { return target->coreid + 1; } const struct rtos_type hwthread_rtos = { .name = "hwthread", .detect_rtos = hwthread_detect_rtos, .create = hwthread_create, .update_threads = hwthread_update_threads, .get_thread_reg_list = hwthread_get_thread_reg_list, .get_thread_reg = hwthread_get_thread_reg, .get_symbol_list_to_lookup = hwthread_get_symbol_list_to_lookup, .smp_init = hwthread_smp_init, .set_reg = hwthread_set_reg, .read_buffer = hwthread_read_buffer, .write_buffer = hwthread_write_buffer, }; struct hwthread_params { int dummy_param; }; static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num) { char tmp_str[HW_THREAD_NAME_STR_SIZE]; threadid_t tid = threadid_from_target(curr); memset(tmp_str, 0, HW_THREAD_NAME_STR_SIZE); /* thread-id is the core-id of this core inside the SMP group plus 1 */ rtos->thread_details[thread_num].threadid = tid; /* create the thread name */ rtos->thread_details[thread_num].exists = true; rtos->thread_details[thread_num].thread_name_str = strdup(target_name(curr)); snprintf(tmp_str, HW_THREAD_NAME_STR_SIZE-1, "state: %s", debug_reason_name(curr)); rtos->thread_details[thread_num].extra_info_str = strdup(tmp_str); return ERROR_OK; } static int hwthread_update_threads(struct rtos *rtos) { int threads_found = 0; int thread_list_size = 0; struct target_list *head; struct target *target; int64_t current_thread = 0; int64_t current_threadid = rtos->current_threadid; /* thread selected by GDB */ enum target_debug_reason current_reason = DBG_REASON_UNDEFINED; if (!rtos) return -1; target = rtos->target; /* wipe out previous thread details if any */ rtos_free_threadlist(rtos); /* determine the number of "threads" */ if (target->smp) { foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (!target_was_examined(curr)) continue; ++thread_list_size; } } else thread_list_size = 1; /* restore the threadid which is currently selected by GDB * because rtos_free_threadlist() wipes out it * (GDB thread id is 1-based indexing) */ if (current_threadid <= thread_list_size) rtos->current_threadid = current_threadid; else LOG_WARNING("SMP node change, disconnect GDB from core/thread %" PRId64, current_threadid); /* create space for new thread details */ rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size); if (target->smp) { /* loop over all threads */ foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (!target_was_examined(curr)) continue; threadid_t tid = threadid_from_target(curr); hwthread_fill_thread(rtos, curr, threads_found); /* find an interesting thread to set as current */ switch (current_reason) { case DBG_REASON_UNDEFINED: current_reason = curr->debug_reason; current_thread = tid; break; case DBG_REASON_SINGLESTEP: /* single-step can only be overridden by itself */ if (curr->debug_reason == DBG_REASON_SINGLESTEP) { if (tid == rtos->current_threadid) current_thread = tid; } break; case DBG_REASON_BREAKPOINT: /* single-step overrides breakpoint */ if (curr->debug_reason == DBG_REASON_SINGLESTEP) { current_reason = curr->debug_reason; current_thread = tid; } else /* multiple breakpoints, prefer gdbs' threadid */ if (curr->debug_reason == DBG_REASON_BREAKPOINT) { if (tid == rtos->current_threadid) current_thread = tid; } break; case DBG_REASON_WATCHPOINT: /* breakpoint and single-step override watchpoint */ if (curr->debug_reason == DBG_REASON_SINGLESTEP || curr->debug_reason == DBG_REASON_BREAKPOINT) { current_reason = curr->debug_reason; current_thread = tid; } break; case DBG_REASON_DBGRQ: /* all other reasons override debug-request */ if (curr->debug_reason == DBG_REASON_SINGLESTEP || curr->debug_reason == DBG_REASON_WATCHPOINT || curr->debug_reason == DBG_REASON_BREAKPOINT) { current_reason = curr->debug_reason; current_thread = tid; } else if (curr->debug_reason == DBG_REASON_DBGRQ) { if (tid == rtos->current_threadid) current_thread = tid; } break; default: break; } threads_found++; } } else { hwthread_fill_thread(rtos, target, threads_found); current_thread = threadid_from_target(target); threads_found++; } rtos->thread_count = threads_found; /* we found an interesting thread, set it as current */ if (current_thread != 0) rtos->current_thread = current_thread; else if (rtos->current_threadid != 0) rtos->current_thread = rtos->current_threadid; else rtos->current_thread = threadid_from_target(target); LOG_DEBUG("%s current_thread=%i", __func__, (int)rtos->current_thread); return 0; } static int hwthread_smp_init(struct target *target) { return hwthread_update_threads(target->rtos); } static struct target *hwthread_find_thread(struct target *target, int64_t thread_id) { /* Find the thread with that thread_id */ if (!target) return NULL; if (target->smp) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { if (thread_id == threadid_from_target(head->target)) return head->target; } } else if (thread_id == threadid_from_target(target)) { return target; } return NULL; } static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **rtos_reg_list, int *rtos_reg_list_size) { if (!rtos) return ERROR_FAIL; struct target *target = rtos->target; struct target *curr = hwthread_find_thread(target, thread_id); if (!curr) return ERROR_FAIL; if (!target_was_examined(curr)) return ERROR_FAIL; int reg_list_size; struct reg **reg_list; int retval = target_get_gdb_reg_list(curr, ®_list, ®_list_size, REG_CLASS_GENERAL); if (retval != ERROR_OK) return retval; int j = 0; for (int i = 0; i < reg_list_size; i++) { if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden) continue; j++; } *rtos_reg_list_size = j; *rtos_reg_list = calloc(*rtos_reg_list_size, sizeof(struct rtos_reg)); if (!*rtos_reg_list) { free(reg_list); return ERROR_FAIL; } j = 0; for (int i = 0; i < reg_list_size; i++) { if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden) continue; if (!reg_list[i]->valid) { retval = reg_list[i]->type->get(reg_list[i]); if (retval != ERROR_OK) { LOG_ERROR("Couldn't get register %s.", reg_list[i]->name); free(reg_list); free(*rtos_reg_list); return retval; } } (*rtos_reg_list)[j].number = reg_list[i]->number; (*rtos_reg_list)[j].size = reg_list[i]->size; memcpy((*rtos_reg_list)[j].value, reg_list[i]->value, DIV_ROUND_UP(reg_list[i]->size, 8)); j++; } free(reg_list); return ERROR_OK; } static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id, uint32_t reg_num, struct rtos_reg *rtos_reg) { if (!rtos) return ERROR_FAIL; struct target *target = rtos->target; struct target *curr = hwthread_find_thread(target, thread_id); if (!curr) { LOG_ERROR("Couldn't find RTOS thread for id %" PRId64 ".", thread_id); return ERROR_FAIL; } if (!target_was_examined(curr)) { LOG_ERROR("Target %d hasn't been examined yet.", curr->coreid); return ERROR_FAIL; } struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true); if (!reg) { LOG_ERROR("Couldn't find register %" PRIu32 " in thread %" PRId64 ".", reg_num, thread_id); return ERROR_FAIL; } if (reg->type->get(reg) != ERROR_OK) return ERROR_FAIL; rtos_reg->number = reg->number; rtos_reg->size = reg->size; unsigned bytes = (reg->size + 7) / 8; assert(bytes <= sizeof(rtos_reg->value)); memcpy(rtos_reg->value, reg->value, bytes); return ERROR_OK; } static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value) { if (!rtos) return ERROR_FAIL; struct target *target = rtos->target; struct target *curr = hwthread_find_thread(target, rtos->current_thread); if (!curr) return ERROR_FAIL; struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true); if (!reg) return ERROR_FAIL; return reg->type->set(reg, reg_value); } static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { /* return an empty list, we don't have any symbols to look up */ *symbol_list = calloc(1, sizeof(struct symbol_table_elem)); (*symbol_list)[0].symbol_name = NULL; return 0; } static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target) { struct target *target = get_target_from_connection(connection); struct target *curr = hwthread_find_thread(target, thread_id); if (!curr) return ERROR_FAIL; *p_target = curr; return ERROR_OK; } static bool hwthread_detect_rtos(struct target *target) { /* always return 0, avoid auto-detection */ return false; } static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); struct target *curr = NULL; int64_t current_threadid; if (packet[0] == 'H' && packet[1] == 'g') { sscanf(packet, "Hg%16" SCNx64, ¤t_threadid); if (current_threadid > 0) { if (hwthread_target_for_threadid(connection, current_threadid, &curr) != ERROR_OK) { LOG_ERROR("hwthread: cannot find thread id %"PRId64, current_threadid); gdb_put_packet(connection, "E01", 3); return ERROR_FAIL; } target->rtos->current_thread = current_threadid; } else if (current_threadid == 0 || current_threadid == -1) target->rtos->current_thread = threadid_from_target(target); target->rtos->current_threadid = current_threadid; gdb_put_packet(connection, "OK", 2); return ERROR_OK; } return rtos_thread_packet(connection, packet, packet_size); } static int hwthread_create(struct target *target) { LOG_INFO("Hardware thread awareness created"); target->rtos->rtos_specific_params = NULL; target->rtos->current_thread = 0; target->rtos->thread_details = NULL; target->rtos->gdb_target_for_threadid = hwthread_target_for_threadid; target->rtos->gdb_thread_packet = hwthread_thread_packet; return 0; } static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, uint8_t *buffer) { if (!rtos) return ERROR_FAIL; struct target *target = rtos->target; struct target *curr = hwthread_find_thread(target, rtos->current_thread); if (!curr) return ERROR_FAIL; return target_read_buffer(curr, address, size, buffer); } static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, const uint8_t *buffer) { if (!rtos) return ERROR_FAIL; struct target *target = rtos->target; struct target *curr = hwthread_find_thread(target, rtos->current_thread); if (!curr) return ERROR_FAIL; return target_write_buffer(curr, address, size, buffer); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/linux.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by STEricsson * * Heythem Bouhaja heythem.bouhaja@stericsson.com : creation * * Michel JAOUEN michel.jaouen@stericsson.com : adaptation to rtos * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/time_support.h> #include <jtag/jtag.h> #include "target/target.h" #include "target/target_type.h" #include "helper/log.h" #include "helper/types.h" #include "rtos.h" #include "rtos_standard_stackings.h" #include <target/register.h> #include <target/smp.h> #include "server/gdb_server.h" #define LINUX_USER_KERNEL_BORDER 0xc0000000 #include "linux_header.h" #define PHYS #define MAX_THREADS 200 /* specific task */ struct linux_os { const char *name; uint32_t init_task_addr; int thread_count; int threadid_count; int preupdtate_threadid_count; int nr_cpus; int threads_lookup; int threads_needs_update; struct current_thread *current_threads; struct threads *thread_list; /* virt2phys parameter */ uint32_t phys_mask; uint32_t phys_base; }; struct current_thread { int64_t threadid; int32_t core_id; #ifdef PID_CHECK uint32_t pid; #endif uint32_t TS; struct current_thread *next; }; struct threads { char name[17]; uint32_t base_addr; /* address to read magic */ uint32_t state; /* magic value : filled only at creation */ uint32_t pid; /* linux pid : id for identifying a thread */ uint32_t oncpu; /* content cpu number in current thread */ uint32_t asid; /* filled only at creation */ int64_t threadid; int status; /* dead = 1 alive = 2 current = 3 alive and current */ /* value that should not change during the live of a thread ? */ uint32_t thread_info_addr; /* contain latest thread_info_addr computed */ /* retrieve from thread_info */ struct cpu_context *context; struct threads *next; }; struct cpu_context { uint32_t R4; uint32_t R5; uint32_t R6; uint32_t R7; uint32_t R8; uint32_t R9; uint32_t IP; uint32_t FP; uint32_t SP; uint32_t PC; uint32_t preempt_count; }; static struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr, uint32_t *info_addr); static int insert_into_threadlist(struct target *target, struct threads *t); static int linux_os_create(struct target *target); static int linux_os_dummy_update(struct rtos *rtos) { /* update is done only when thread request come * too many thread to do it on each stop */ return 0; } static int linux_compute_virt2phys(struct target *target, target_addr_t address) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; target_addr_t pa = 0; int retval = target->type->virt2phys(target, address, &pa); if (retval != ERROR_OK) { LOG_ERROR("Cannot compute linux virt2phys translation"); /* fixes default address */ linux_os->phys_base = 0; return ERROR_FAIL; } linux_os->init_task_addr = address; address = address & linux_os->phys_mask; linux_os->phys_base = pa - address; return ERROR_OK; } static int linux_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { #ifdef PHYS struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; uint32_t pa = (address & linux_os->phys_mask) + linux_os->phys_base; #endif if (address < 0xc0000000) { LOG_ERROR("linux awareness : address in user space"); return ERROR_FAIL; } #ifdef PHYS target_read_phys_memory(target, pa, size, count, buffer); #endif target_read_memory(target, address, size, count, buffer); return ERROR_OK; } static int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer) { if ((addr & 0xfffffffc) != addr) LOG_INFO("unaligned address %" PRIx32 "!!", addr); int retval = linux_read_memory(target, addr, 4, 1, buffer); return retval; } static uint32_t get_buffer(struct target *target, const uint8_t *buffer) { uint32_t value = 0; const uint8_t *value_ptr = buffer; value = target_buffer_get_u32(target, value_ptr); return value; } static int linux_os_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { struct target *target = rtos->target; struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct current_thread *tmp = linux_os->current_threads; struct current_thread *next; int found = 0; int retval; /* check if a current thread is requested */ next = tmp; do { if (next->threadid == thread_id) found = 1; else next = next->next; } while ((found == 0) && (next != tmp) && (next)); if (found == 0) { LOG_ERROR("could not find thread: %" PRIx64, thread_id); return ERROR_FAIL; } /* search target to perform the access */ struct reg **gdb_reg_list; struct target_list *head; found = 0; foreach_smp_target(head, target->smp_targets) { if (head->target->coreid == next->core_id) { target = head->target; found = 1; break; } } if (found == 0) { LOG_ERROR ( "current thread %" PRIx64 ": no target to perform access of core id %" PRIx32, thread_id, next->core_id); return ERROR_FAIL; } /*LOG_INFO("thread %lx current on core %x",thread_id, target->coreid);*/ retval = target_get_gdb_reg_list(target, &gdb_reg_list, num_regs, REG_CLASS_GENERAL); if (retval != ERROR_OK) return retval; *reg_list = calloc(*num_regs, sizeof(struct rtos_reg)); for (int i = 0; i < *num_regs; ++i) { if (!gdb_reg_list[i]->valid) gdb_reg_list[i]->type->get(gdb_reg_list[i]); (*reg_list)[i].number = gdb_reg_list[i]->number; (*reg_list)[i].size = gdb_reg_list[i]->size; buf_cpy(gdb_reg_list[i]->value, (*reg_list)[i].value, (*reg_list)[i].size); } return ERROR_OK; } static bool linux_os_detect(struct target *target) { LOG_INFO("should no be called"); return false; } static int linux_os_smp_init(struct target *target); static int linux_os_clean(struct target *target); #define INIT_TASK 0 static const char * const linux_symbol_list[] = { "init_task", NULL }; static int linux_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; *symbol_list = (struct symbol_table_elem *) calloc(ARRAY_SIZE(linux_symbol_list), sizeof(struct symbol_table_elem)); for (i = 0; i < ARRAY_SIZE(linux_symbol_list); i++) (*symbol_list)[i].symbol_name = linux_symbol_list[i]; return 0; } static char *linux_ps_command(struct target *target); const struct rtos_type linux_rtos = { .name = "linux", .detect_rtos = linux_os_detect, .create = linux_os_create, .smp_init = linux_os_smp_init, .update_threads = linux_os_dummy_update, .get_thread_reg_list = linux_os_thread_reg_list, .get_symbol_list_to_lookup = linux_get_symbol_list_to_lookup, .clean = linux_os_clean, .ps_command = linux_ps_command, }; static int linux_thread_packet(struct connection *connection, char const *packet, int packet_size); static void linux_identify_current_threads(struct target *target); #ifdef PID_CHECK int fill_task_pid(struct target *target, struct threads *t) { uint32_t pid_addr = t->base_addr + PID; uint8_t buffer[4]; int retval = fill_buffer(target, pid_addr, buffer); if (retval == ERROR_OK) { uint32_t val = get_buffer(target, buffer); t->pid = val; } else LOG_ERROR("fill_task_pid: unable to read memory"); return retval; } #endif static int fill_task(struct target *target, struct threads *t) { int retval; uint32_t pid_addr = t->base_addr + PID; uint32_t mem_addr = t->base_addr + MEM; uint32_t on_cpu = t->base_addr + ONCPU; uint8_t *buffer = calloc(1, 4); retval = fill_buffer(target, t->base_addr, buffer); if (retval == ERROR_OK) { uint32_t val = get_buffer(target, buffer); t->state = val; } else LOG_ERROR("fill_task: unable to read memory"); retval = fill_buffer(target, pid_addr, buffer); if (retval == ERROR_OK) { uint32_t val = get_buffer(target, buffer); t->pid = val; } else LOG_ERROR("fill task: unable to read memory"); retval = fill_buffer(target, on_cpu, buffer); if (retval == ERROR_OK) { uint32_t val = get_buffer(target, buffer); t->oncpu = val; } else LOG_ERROR("fill task: unable to read memory"); retval = fill_buffer(target, mem_addr, buffer); if (retval == ERROR_OK) { uint32_t val = get_buffer(target, buffer); if (val != 0) { uint32_t asid_addr = val + MM_CTX; retval = fill_buffer(target, asid_addr, buffer); if (retval == ERROR_OK) { val = get_buffer(target, buffer); t->asid = val; } else LOG_ERROR ("fill task: unable to read memory -- ASID"); } else t->asid = 0; } else LOG_ERROR("fill task: unable to read memory"); free(buffer); return retval; } static int get_name(struct target *target, struct threads *t) { int retval; uint32_t full_name[4]; uint32_t comm = t->base_addr + COMM; int i; for (i = 0; i < 17; i++) t->name[i] = 0; retval = linux_read_memory(target, comm, 4, 4, (uint8_t *) full_name); if (retval != ERROR_OK) { LOG_ERROR("get_name: unable to read memory\n"); return ERROR_FAIL; } uint32_t raw_name = target_buffer_get_u32(target, (const uint8_t *) &full_name[0]); t->name[3] = raw_name >> 24; t->name[2] = raw_name >> 16; t->name[1] = raw_name >> 8; t->name[0] = raw_name; raw_name = target_buffer_get_u32(target, (const uint8_t *)&full_name[1]); t->name[7] = raw_name >> 24; t->name[6] = raw_name >> 16; t->name[5] = raw_name >> 8; t->name[4] = raw_name; raw_name = target_buffer_get_u32(target, (const uint8_t *)&full_name[2]); t->name[11] = raw_name >> 24; t->name[10] = raw_name >> 16; t->name[9] = raw_name >> 8; t->name[8] = raw_name; raw_name = target_buffer_get_u32(target, (const uint8_t *)&full_name[3]); t->name[15] = raw_name >> 24; t->name[14] = raw_name >> 16; t->name[13] = raw_name >> 8; t->name[12] = raw_name; return ERROR_OK; } static int get_current(struct target *target, int create) { struct target_list *head; uint8_t *buf; uint32_t val; uint32_t ti_addr; uint8_t *buffer = calloc(1, 4); struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct current_thread *ctt = linux_os->current_threads; /* invalid current threads content */ while (ctt) { ctt->threadid = -1; ctt->TS = 0xdeadbeef; ctt = ctt->next; } foreach_smp_target(head, target->smp_targets) { struct reg **reg_list; int reg_list_size; int retval; if (target_get_gdb_reg_list(head->target, ®_list, ®_list_size, REG_CLASS_GENERAL) != ERROR_OK) { free(buffer); return ERROR_TARGET_FAILURE; } if (!reg_list[13]->valid) reg_list[13]->type->get(reg_list[13]); buf = reg_list[13]->value; val = get_buffer(target, buf); ti_addr = (val & 0xffffe000); uint32_t ts_addr = ti_addr + 0xc; retval = fill_buffer(target, ts_addr, buffer); if (retval == ERROR_OK) { uint32_t TS = get_buffer(target, buffer); uint32_t cpu, on_cpu = TS + ONCPU; retval = fill_buffer(target, on_cpu, buffer); if (retval == ERROR_OK) { /*uint32_t cpu = get_buffer(target, buffer);*/ struct current_thread *ct = linux_os->current_threads; cpu = head->target->coreid; while ((ct) && (ct->core_id != (int32_t) cpu)) ct = ct->next; if ((ct) && (ct->TS == 0xdeadbeef)) ct->TS = TS; else LOG_ERROR ("error in linux current thread update"); if (create && ct) { struct threads *t; t = calloc(1, sizeof(struct threads)); t->base_addr = ct->TS; fill_task(target, t); get_name(target, t); t->oncpu = cpu; insert_into_threadlist(target, t); t->status = 3; t->thread_info_addr = 0xdeadbeef; ct->threadid = t->threadid; linux_os->thread_count++; #ifdef PID_CHECK ct->pid = t->pid; #endif /*LOG_INFO("Creation of current thread %s",t->name);*/ } } } free(reg_list); } free(buffer); return ERROR_OK; } static struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr, uint32_t *thread_info_addr_old) { struct cpu_context *context = calloc(1, sizeof(struct cpu_context)); uint32_t preempt_count_addr = 0; uint32_t registers[10]; uint8_t *buffer = calloc(1, 4); uint32_t stack = base_addr + QAT; uint32_t thread_info_addr = 0; uint32_t thread_info_addr_update = 0; int retval = ERROR_FAIL; context->R4 = 0xdeadbeef; context->R5 = 0xdeadbeef; context->R6 = 0xdeadbeef; context->R7 = 0xdeadbeef; context->R8 = 0xdeadbeef; context->R9 = 0xdeadbeef; context->IP = 0xdeadbeef; context->FP = 0xdeadbeef; context->SP = 0xdeadbeef; context->PC = 0xdeadbeef; retry: if (*thread_info_addr_old == 0xdeadbeef) { retval = fill_buffer(target, stack, buffer); if (retval == ERROR_OK) thread_info_addr = get_buffer(target, buffer); else LOG_ERROR("cpu_context: unable to read memory"); thread_info_addr_update = thread_info_addr; } else thread_info_addr = *thread_info_addr_old; preempt_count_addr = thread_info_addr + PREEMPT; retval = fill_buffer(target, preempt_count_addr, buffer); if (retval == ERROR_OK) context->preempt_count = get_buffer(target, buffer); else { if (*thread_info_addr_old != 0xdeadbeef) { LOG_ERROR ("cpu_context: cannot read at thread_info_addr"); if (*thread_info_addr_old < LINUX_USER_KERNEL_BORDER) LOG_INFO ("cpu_context : thread_info_addr in userspace!!!"); *thread_info_addr_old = 0xdeadbeef; goto retry; } LOG_ERROR("cpu_context: unable to read memory"); } thread_info_addr += CPU_CONT; retval = linux_read_memory(target, thread_info_addr, 4, 10, (uint8_t *) registers); if (retval != ERROR_OK) { free(buffer); LOG_ERROR("cpu_context: unable to read memory\n"); return context; } context->R4 = target_buffer_get_u32(target, (const uint8_t *)®isters[0]); context->R5 = target_buffer_get_u32(target, (const uint8_t *)®isters[1]); context->R6 = target_buffer_get_u32(target, (const uint8_t *)®isters[2]); context->R7 = target_buffer_get_u32(target, (const uint8_t *)®isters[3]); context->R8 = target_buffer_get_u32(target, (const uint8_t *)®isters[4]); context->R9 = target_buffer_get_u32(target, (const uint8_t *)®isters[5]); context->IP = target_buffer_get_u32(target, (const uint8_t *)®isters[6]); context->FP = target_buffer_get_u32(target, (const uint8_t *)®isters[7]); context->SP = target_buffer_get_u32(target, (const uint8_t *)®isters[8]); context->PC = target_buffer_get_u32(target, (const uint8_t *)®isters[9]); if (*thread_info_addr_old == 0xdeadbeef) *thread_info_addr_old = thread_info_addr_update; free(buffer); return context; } static uint32_t next_task(struct target *target, struct threads *t) { uint8_t *buffer = calloc(1, 4); uint32_t next_addr = t->base_addr + NEXT; int retval = fill_buffer(target, next_addr, buffer); if (retval == ERROR_OK) { uint32_t val = get_buffer(target, buffer); val = val - NEXT; free(buffer); return val; } else LOG_ERROR("next task: unable to read memory"); free(buffer); return 0; } static struct current_thread *add_current_thread(struct current_thread *currents, struct current_thread *ct) { ct->next = NULL; if (!currents) { currents = ct; return currents; } else { struct current_thread *temp = currents; while (temp->next) temp = temp->next; temp->next = ct; return currents; } } static struct threads *liste_del_task(struct threads *task_list, struct threads **t, struct threads *prev) { LOG_INFO("del task %" PRId64, (*t)->threadid); if (prev) prev->next = (*t)->next; else task_list = (*t)->next; /* free content of threads */ free((*t)->context); free(*t); *t = prev ? prev : task_list; return task_list; } static struct threads *liste_add_task(struct threads *task_list, struct threads *t, struct threads **last) { t->next = NULL; if (!*last) if (!task_list) { task_list = t; return task_list; } else { struct threads *temp = task_list; while (temp->next) temp = temp->next; temp->next = t; *last = t; return task_list; } else { (*last)->next = t; *last = t; return task_list; } } #ifdef PID_CHECK static int current_pid(struct linux_os *linux_os, uint32_t pid) #else static int current_base_addr(struct linux_os *linux_os, uint32_t base_addr) #endif { struct current_thread *ct = linux_os->current_threads; #ifdef PID_CHECK while ((ct) && (ct->pid != pid)) #else while ((ct) && (ct->TS != base_addr)) #endif ct = ct->next; #ifdef PID_CHECK if ((ct) && (ct->pid == pid)) #else if ((ct) && (ct->TS == base_addr)) #endif return 1; return 0; } static int linux_get_tasks(struct target *target, int context) { int loop = 0; int retval = 0; struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; linux_os->thread_list = NULL; linux_os->thread_count = 0; if (linux_os->init_task_addr == 0xdeadbeef) { LOG_INFO("no init symbol\n"); return ERROR_FAIL; } int64_t start = timeval_ms(); struct threads *t = calloc(1, sizeof(struct threads)); struct threads *last = NULL; t->base_addr = linux_os->init_task_addr; /* retrieve the thread id , currently running in the different smp core */ get_current(target, 1); while (((t->base_addr != linux_os->init_task_addr) && (t->base_addr != 0)) || (loop == 0)) { loop++; fill_task(target, t); retval = get_name(target, t); if (loop > MAX_THREADS) { free(t); LOG_INFO("more than %d threads !!", MAX_THREADS); return ERROR_FAIL; } if (retval != ERROR_OK) { free(t); return ERROR_FAIL; } /* check that this thread is not one the current threads already * created */ uint32_t base_addr; #ifdef PID_CHECK if (!current_pid(linux_os, t->pid)) { #else if (!current_base_addr(linux_os, t->base_addr)) { #endif t->threadid = linux_os->threadid_count; t->status = 1; linux_os->threadid_count++; linux_os->thread_list = liste_add_task(linux_os->thread_list, t, &last); /* no interest to fill the context if it is a current thread. */ linux_os->thread_count++; t->thread_info_addr = 0xdeadbeef; if (context) t->context = cpu_context_read(target, t->base_addr, &t->thread_info_addr); base_addr = next_task(target, t); } else { /*LOG_INFO("thread %s is a current thread already created",t->name); */ base_addr = next_task(target, t); free(t); } t = calloc(1, sizeof(struct threads)); t->base_addr = base_addr; } linux_os->threads_lookup = 1; linux_os->threads_needs_update = 0; linux_os->preupdtate_threadid_count = linux_os->threadid_count - 1; /* check that all current threads have been identified */ LOG_INFO("complete time %" PRId64 ", thread mean %" PRId64 "\n", (timeval_ms() - start), (timeval_ms() - start) / linux_os->threadid_count); LOG_INFO("threadid count %d", linux_os->threadid_count); free(t); return ERROR_OK; } static int clean_threadlist(struct target *target) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct threads *old, *temp = linux_os->thread_list; while (temp) { old = temp; free(temp->context); temp = temp->next; free(old); } return ERROR_OK; } static int linux_os_clean(struct target *target) { struct linux_os *os_linux = (struct linux_os *) target->rtos->rtos_specific_params; clean_threadlist(target); os_linux->init_task_addr = 0xdeadbeef; os_linux->name = "linux"; os_linux->thread_list = NULL; os_linux->thread_count = 0; os_linux->nr_cpus = 0; os_linux->threads_lookup = 0; os_linux->threads_needs_update = 0; os_linux->threadid_count = 1; return ERROR_OK; } static int insert_into_threadlist(struct target *target, struct threads *t) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct threads *temp = linux_os->thread_list; t->threadid = linux_os->threadid_count; linux_os->threadid_count++; t->status = 1; t->next = NULL; if (!temp) linux_os->thread_list = t; else { while (temp->next) temp = temp->next; t->next = NULL; temp->next = t; } return ERROR_OK; } static void linux_identify_current_threads(struct target *target) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct threads *thread_list = linux_os->thread_list; struct current_thread *ct = linux_os->current_threads; struct threads *t = NULL; while ((ct)) { if (ct->threadid == -1) { /* un-identified thread */ int found = 0; t = calloc(1, sizeof(struct threads)); t->base_addr = ct->TS; #ifdef PID_CHECK if (fill_task_pid(target, t) != ERROR_OK) { error_handling: free(t); LOG_ERROR ("linux identify_current_threads: unable to read pid"); return; } #endif /* search in the list of threads if pid already present */ while ((thread_list) && (found == 0)) { #ifdef PID_CHECK if (thread_list->pid == t->pid) { #else if (thread_list->base_addr == t->base_addr) { #endif free(t); t = thread_list; found = 1; } thread_list = thread_list->next; } if (!found) { /* it is a new thread */ if (fill_task(target, t) != ERROR_OK) goto error_handling; get_name(target, t); insert_into_threadlist(target, t); t->thread_info_addr = 0xdeadbeef; } t->status = 3; ct->threadid = t->threadid; #ifdef PID_CHECK ct->pid = t->pid; #endif linux_os->thread_count++; #if 0 if (found == 0) LOG_INFO("current thread core %x identified %s", ct->core_id, t->name); else LOG_INFO("current thread core %x, reused %s", ct->core_id, t->name); #endif } #if 0 else { struct threads tmp; tmp.base_addr = ct->TS; get_name(target, &tmp); LOG_INFO("current thread core %x , already identified %s !!!", ct->core_id, tmp.name); } #endif ct = ct->next; } return; #ifndef PID_CHECK error_handling: free(t); LOG_ERROR("unable to read pid"); return; #endif } static int linux_task_update(struct target *target, int context) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct threads *thread_list = linux_os->thread_list; int retval; int loop = 0; linux_os->thread_count = 0; /*thread_list = thread_list->next; skip init_task*/ while (thread_list) { thread_list->status = 0; /*setting all tasks to dead state*/ free(thread_list->context); thread_list->context = NULL; thread_list = thread_list->next; } int found = 0; if (linux_os->init_task_addr == 0xdeadbeef) { LOG_INFO("no init symbol\n"); return ERROR_FAIL; } int64_t start = timeval_ms(); struct threads *t = calloc(1, sizeof(struct threads)); uint32_t previous = 0xdeadbeef; t->base_addr = linux_os->init_task_addr; retval = get_current(target, 0); /*check that all current threads have been identified */ linux_identify_current_threads(target); while (((t->base_addr != linux_os->init_task_addr) && (t->base_addr != previous)) || (loop == 0)) { /* for avoiding any permanent loop for any reason possibly due to * target */ loop++; previous = t->base_addr; /* read only pid */ #ifdef PID_CHECK retval = fill_task_pid(target, t); #endif if (retval != ERROR_OK) { free(t); return ERROR_FAIL; } thread_list = linux_os->thread_list; while (thread_list) { #ifdef PID_CHECK if (t->pid == thread_list->pid) { #else if (t->base_addr == thread_list->base_addr) { #endif if (!thread_list->status) { #ifdef PID_CHECK if (t->base_addr != thread_list->base_addr) LOG_INFO("thread base_addr has changed !!"); #endif /* this is not a current thread */ thread_list->base_addr = t->base_addr; thread_list->status = 1; /* we don 't update this field any more */ /*thread_list->state = t->state; thread_list->oncpu = t->oncpu; thread_list->asid = t->asid; */ if (context) thread_list->context = cpu_context_read(target, thread_list->base_addr, &thread_list->thread_info_addr); } else { /* it is a current thread no need to read context */ } linux_os->thread_count++; found = 1; break; } else { found = 0; thread_list = thread_list->next; } } if (found == 0) { uint32_t base_addr; fill_task(target, t); get_name(target, t); retval = insert_into_threadlist(target, t); t->thread_info_addr = 0xdeadbeef; if (context) t->context = cpu_context_read(target, t->base_addr, &t->thread_info_addr); base_addr = next_task(target, t); t = calloc(1, sizeof(struct threads)); t->base_addr = base_addr; linux_os->thread_count++; } else t->base_addr = next_task(target, t); } LOG_INFO("update thread done %" PRId64 ", mean%" PRId64 "\n", (timeval_ms() - start), (timeval_ms() - start) / loop); free(t); linux_os->threads_needs_update = 0; return ERROR_OK; } static int linux_gdb_thread_packet(struct target *target, struct connection *connection, char const *packet, int packet_size) { int retval; struct linux_os *linux_os = (struct linux_os *)target->rtos->rtos_specific_params; if (linux_os->init_task_addr == 0xdeadbeef) { /* it has not been initialized */ LOG_INFO("received thread request without init task address"); gdb_put_packet(connection, "l", 1); return ERROR_OK; } retval = linux_get_tasks(target, 1); if (retval != ERROR_OK) return ERROR_TARGET_FAILURE; char *out_str = calloc(MAX_THREADS * 17 + 10, 1); char *tmp_str = out_str; tmp_str += sprintf(tmp_str, "m"); struct threads *temp = linux_os->thread_list; while (temp) { tmp_str += sprintf(tmp_str, "%016" PRIx64, temp->threadid); temp = temp->next; if (temp) tmp_str += sprintf(tmp_str, ","); } gdb_put_packet(connection, out_str, strlen(out_str)); free(out_str); return ERROR_OK; } static int linux_gdb_thread_update(struct target *target, struct connection *connection, char const *packet, int packet_size) { int found = 0; struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct threads *temp = linux_os->thread_list; while (temp) { if (temp->threadid == linux_os->preupdtate_threadid_count + 1) { /*LOG_INFO("FOUND");*/ found = 1; break; } else temp = temp->next; } if (found == 1) { /*LOG_INFO("INTO GDB THREAD UPDATE FOUNDING START TASK");*/ char *out_strr = calloc(MAX_THREADS * 17 + 10, 1); char *tmp_strr = out_strr; tmp_strr += sprintf(tmp_strr, "m"); /*LOG_INFO("CHAR MALLOC & M DONE");*/ tmp_strr += sprintf(tmp_strr, "%016" PRIx64, temp->threadid); temp = temp->next; while (temp) { /*LOG_INFO("INTO GDB THREAD UPDATE WHILE");*/ tmp_strr += sprintf(tmp_strr, ","); tmp_strr += sprintf(tmp_strr, "%016" PRIx64, temp->threadid); temp = temp->next; } /*tmp_str[0] = 0;*/ gdb_put_packet(connection, out_strr, strlen(out_strr)); linux_os->preupdtate_threadid_count = linux_os->threadid_count - 1; free(out_strr); } else gdb_put_packet(connection, "l", 1); return ERROR_OK; } static int linux_thread_extra_info(struct target *target, struct connection *connection, char const *packet, int packet_size) { int64_t threadid = 0; struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid); /*LOG_INFO("lookup extra info for thread %" SCNx64, threadid);*/ struct threads *temp = linux_os->thread_list; while (temp) { if (temp->threadid == threadid) { char *pid = " PID: "; char *pid_current = "*PID: "; char *name = "Name: "; int str_size = strlen(pid) + strlen(name); char *tmp_str = calloc(1, str_size + 50); char *tmp_str_ptr = tmp_str; /* discriminate current task */ if (temp->status == 3) tmp_str_ptr += sprintf(tmp_str_ptr, "%s", pid_current); else tmp_str_ptr += sprintf(tmp_str_ptr, "%s", pid); tmp_str_ptr += sprintf(tmp_str_ptr, "%d, ", (int)temp->pid); sprintf(tmp_str_ptr, "%s", name); sprintf(tmp_str_ptr, "%s", temp->name); char *hex_str = calloc(1, strlen(tmp_str) * 2 + 1); size_t pkt_len = hexify(hex_str, (const uint8_t *)tmp_str, strlen(tmp_str), strlen(tmp_str) * 2 + 1); gdb_put_packet(connection, hex_str, pkt_len); free(hex_str); free(tmp_str); return ERROR_OK; } temp = temp->next; } LOG_INFO("thread not found"); return ERROR_OK; } static int linux_gdb_t_packet(struct connection *connection, struct target *target, char const *packet, int packet_size) { int64_t threadid; struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; int retval = ERROR_OK; sscanf(packet, "T%" SCNx64, &threadid); if (linux_os->threads_needs_update == 0) { struct threads *temp = linux_os->thread_list; struct threads *prev = NULL; while (temp) { if (temp->threadid == threadid) { if (temp->status != 0) { gdb_put_packet(connection, "OK", 2); return ERROR_OK; } else { /* delete item in the list */ linux_os->thread_list = liste_del_task(linux_os->thread_list, &temp, prev); linux_os->thread_count--; gdb_put_packet(connection, "E01", 3); return ERROR_OK; } } /* for deletion */ prev = temp; temp = temp->next; } LOG_INFO("gdb requested status on non existing thread"); gdb_put_packet(connection, "E01", 3); return ERROR_OK; } else { retval = linux_task_update(target, 1); struct threads *temp = linux_os->thread_list; while (temp) { if (temp->threadid == threadid) { if (temp->status == 1) { gdb_put_packet(connection, "OK", 2); return ERROR_OK; } else { gdb_put_packet(connection, "E01", 3); return ERROR_OK; } } temp = temp->next; } } return retval; } static int linux_gdb_h_packet(struct connection *connection, struct target *target, char const *packet, int packet_size) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct current_thread *ct = linux_os->current_threads; /* select to display the current thread of the selected target */ while ((ct) && (ct->core_id != target->coreid)) ct = ct->next; int64_t current_gdb_thread_rq; if (linux_os->threads_lookup == 1) { if ((ct) && (ct->threadid == -1)) { ct = linux_os->current_threads; while ((ct) && (ct->threadid == -1)) ct = ct->next; } if (!ct) { /* no current thread can be identified * any way with smp */ LOG_INFO("no current thread identified"); /* attempt to display the name of the 2 threads identified with * get_current */ struct threads t; ct = linux_os->current_threads; while ((ct) && (ct->threadid == -1)) { t.base_addr = ct->TS; get_name(target, &t); LOG_INFO("name of unidentified thread %s", t.name); ct = ct->next; } gdb_put_packet(connection, "OK", 2); return ERROR_OK; } if (packet[1] == 'g') { sscanf(packet, "Hg%16" SCNx64, ¤t_gdb_thread_rq); if (current_gdb_thread_rq == 0) { target->rtos->current_threadid = ct->threadid; gdb_put_packet(connection, "OK", 2); } else { target->rtos->current_threadid = current_gdb_thread_rq; gdb_put_packet(connection, "OK", 2); } } else if (packet[1] == 'c') { sscanf(packet, "Hc%16" SCNx64, ¤t_gdb_thread_rq); if ((current_gdb_thread_rq == 0) || (current_gdb_thread_rq == ct->threadid)) { target->rtos->current_threadid = ct->threadid; gdb_put_packet(connection, "OK", 2); } else gdb_put_packet(connection, "E01", 3); } } else gdb_put_packet(connection, "OK", 2); return ERROR_OK; } static int linux_thread_packet(struct connection *connection, char const *packet, int packet_size) { int retval = ERROR_OK; struct current_thread *ct; struct target *target = get_target_from_connection(connection); struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; switch (packet[0]) { case 'T': /* Is thread alive?*/ linux_gdb_t_packet(connection, target, packet, packet_size); break; case 'H': /* Set current thread */ /* ( 'c' for step and continue, 'g' for all other operations )*/ /*LOG_INFO(" H packet received '%s'", packet);*/ linux_gdb_h_packet(connection, target, packet, packet_size); break; case 'q': if (strncmp(packet, "qSymbol", 7) == 0) { if (rtos_qsymbol(connection, packet, packet_size) == 1) { linux_compute_virt2phys(target, target->rtos->symbols[INIT_TASK].address); } break; } else if (strncmp(packet, "qfThreadInfo", 12) == 0) { if (!linux_os->thread_list) { retval = linux_gdb_thread_packet(target, connection, packet, packet_size); break; } else { retval = linux_gdb_thread_update(target, connection, packet, packet_size); break; } } else if (strncmp(packet, "qsThreadInfo", 12) == 0) { gdb_put_packet(connection, "l", 1); break; } else if (strncmp(packet, "qThreadExtraInfo,", 17) == 0) { linux_thread_extra_info(target, connection, packet, packet_size); break; } else { retval = GDB_THREAD_PACKET_NOT_CONSUMED; break; } case 'Q': /* previously response was : thread not found * gdb_put_packet(connection, "E01", 3); */ retval = GDB_THREAD_PACKET_NOT_CONSUMED; break; case 'c': case 's': { if (linux_os->threads_lookup == 1) { ct = linux_os->current_threads; while ((ct) && (ct->core_id) != target->coreid) ct = ct->next; if ((ct) && (ct->threadid == -1)) { ct = linux_os->current_threads; while ((ct) && (ct->threadid == -1)) ct = ct->next; } if ((ct) && (ct->threadid != target->rtos->current_threadid) && (target->rtos->current_threadid != -1)) LOG_WARNING("WARNING! current GDB thread do not match " "current thread running. " "Switch thread in GDB to threadid %d", (int)ct->threadid); LOG_INFO("threads_needs_update = 1"); linux_os->threads_needs_update = 1; } } /* if a packet handler returned an error, exit input loop */ if (retval != ERROR_OK) return retval; } return retval; } static int linux_os_smp_init(struct target *target) { struct target_list *head; /* keep only target->rtos */ struct rtos *rtos = target->rtos; struct linux_os *os_linux = (struct linux_os *)rtos->rtos_specific_params; struct current_thread *ct; foreach_smp_target(head, target->smp_targets) { if (head->target->rtos != rtos) { struct linux_os *smp_os_linux = (struct linux_os *)head->target->rtos->rtos_specific_params; /* remap smp target on rtos */ free(head->target->rtos); head->target->rtos = rtos; /* reuse allocated ct */ ct = smp_os_linux->current_threads; ct->threadid = -1; ct->TS = 0xdeadbeef; ct->core_id = head->target->coreid; os_linux->current_threads = add_current_thread(os_linux->current_threads, ct); os_linux->nr_cpus++; free(smp_os_linux); } } return ERROR_OK; } static int linux_os_create(struct target *target) { struct linux_os *os_linux = calloc(1, sizeof(struct linux_os)); struct current_thread *ct = calloc(1, sizeof(struct current_thread)); LOG_INFO("linux os creation\n"); os_linux->init_task_addr = 0xdeadbeef; os_linux->name = "linux"; os_linux->thread_list = NULL; os_linux->thread_count = 0; target->rtos->current_threadid = -1; os_linux->nr_cpus = 1; os_linux->threads_lookup = 0; os_linux->threads_needs_update = 0; os_linux->threadid_count = 1; os_linux->current_threads = NULL; target->rtos->rtos_specific_params = os_linux; ct->core_id = target->coreid; ct->threadid = -1; ct->TS = 0xdeadbeef; os_linux->current_threads = add_current_thread(os_linux->current_threads, ct); /* overload rtos thread default handler */ target->rtos->gdb_thread_packet = linux_thread_packet; /* initialize a default virt 2 phys translation */ os_linux->phys_mask = ~0xc0000000; os_linux->phys_base = 0x0; return JIM_OK; } static char *linux_ps_command(struct target *target) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; int retval = ERROR_OK; char *display; if (linux_os->threads_lookup == 0) retval = linux_get_tasks(target, 1); else { if (linux_os->threads_needs_update != 0) retval = linux_task_update(target, 0); } if (retval == ERROR_OK) { struct threads *temp = linux_os->thread_list; char *tmp; LOG_INFO("allocation for %d threads line", linux_os->thread_count); display = calloc((linux_os->thread_count + 2) * 80, 1); if (!display) goto error; tmp = display; tmp += sprintf(tmp, "PID\t\tCPU\t\tASID\t\tNAME\n"); tmp += sprintf(tmp, "---\t\t---\t\t----\t\t----\n"); while (temp) { if (temp->status) { if (temp->context) tmp += sprintf(tmp, "%" PRIu32 "\t\t%" PRIu32 "\t\t%" PRIx32 "\t\t%s\n", temp->pid, temp->oncpu, temp->asid, temp->name); else tmp += sprintf(tmp, "%" PRIu32 "\t\t%" PRIu32 "\t\t%" PRIx32 "\t\t%s\n", temp->pid, temp->oncpu, temp->asid, temp->name); } temp = temp->next; } return display; } error: display = calloc(40, 1); sprintf(display, "linux_ps_command failed\n"); return display; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/linux_header.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef OPENOCD_RTOS_LINUX_HEADER_H #define OPENOCD_RTOS_LINUX_HEADER_H /* gdb script to update the header file according to kernel version and build option before executing function awareness kernel symbol must be loaded : symbol vmlinux define awareness set logging off set logging file linux_header.h set logging on printf "#define QAT %p\n",&((struct task_struct *)(0))->stack set $a=&((struct list_head *)(0))->next set $a=(int)$a+(int)&((struct task_struct *)(0))->tasks printf "#define NEXT %p\n",$a printf "#define COMM %p\n",&((struct task_struct *)(0))->comm printf "#define MEM %p\n",&((struct task_struct *)(0))->mm printf "#define ONCPU %p\n",&((struct task_struct *)(0))->on_cpu printf "#define PID %p\n",&((struct task_struct *)(0))->pid printf "#define CPU_CONT %p\n",&((struct thread_info *)(0))->cpu_context printf "#define PREEMPT %p\n",&((struct thread_info *)(0))->preempt_count printf "#define MM_CTX %p\n",&((struct mm_struct *)(0))->context end */ #define QAT 0x4 #define NEXT 0x1b0 #define COMM 0x2d4 #define MEM 0x1cc #define ONCPU 0x18 #define PID 0x1f4 #define CPU_CONT 0x1c #define PREEMPT 0x4 #define MM_CTX 0x160 #endif /* OPENOCD_RTOS_LINUX_HEADER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/mqx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2014 by Marian Cingel * * cingel.marian@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdint.h> #include <helper/time_support.h> #include <jtag/jtag.h> #include "target/target.h" #include "target/target_type.h" #include "rtos.h" #include "helper/log.h" #include "helper/types.h" #include "rtos_mqx_stackings.h" /* constants */ #define MQX_THREAD_NAME_LENGTH (255) #define MQX_KERNEL_OFFSET_TDLIST (0x0108) #define MQX_KERNEL_OFFSET_SYSTEM_TASK (0x0050) #define MQX_KERNEL_OFFSET_ACTIVE_TASK (0x001C) #define MQX_KERNEL_OFFSET_CAPABILITY (0x0000) #define MQX_QUEUE_OFFSET_SIZE (0x0008) #define MQX_TASK_OFFSET_STATE (0x0008) #define MQX_TASK_OFFSET_ID (0x000c) #define MQX_TASK_OFFSET_TEMPLATE (0x0068) #define MQX_TASK_OFFSET_STACK (0x0014) #define MQX_TASK_OFFSET_TDLIST (0x006C) #define MQX_TASK_OFFSET_NEXT (0x0000) #define MQX_TASK_TEMPLATE_OFFSET_NAME (0x0010) #define MQX_TASK_OFFSET_ERROR_CODE (0x005C) #define MQX_TASK_STATE_MASK (0xFFF) /* types */ enum mqx_symbols { MQX_VAL_MQX_KERNEL_DATA, MQX_VAL_MQX_INIT_STRUCT, }; enum mqx_arch { mqx_arch_cortexm, }; struct mqx_params { const char *target_name; const enum mqx_arch target_arch; const struct rtos_register_stacking *stacking_info; }; struct mqx_state { uint32_t state; char *name; }; /* local data */ static const struct mqx_state mqx_states[] = { { 0x0002, "READY" }, { 0x0003, "BLOCKED" }, { 0x0005, "RCV_SPECIFIC_BLOCKED" }, { 0x0007, "RCV_ANY_BLOCKED" }, { 0x0009, "DYING" }, { 0x000B, "UNHANDLED_INT_BLOCKED" }, { 0x000D, "SEND_BLOCKED" }, { 0x000F, "BREAKPOINT_BLOCKED" }, { 0x0211, "IO_BLOCKED" }, { 0x0021, "SEM_BLOCKED" }, { 0x0223, "MUTEX_BLOCKED" }, { 0x0025, "EVENT_BLOCKED" }, { 0x0229, "TASK_QUEUE_BLOCKED" }, { 0x042B, "LWSEM_BLOCKED" }, { 0x042D, "LWEVENT_BLOCKED" }, }; static const char * const mqx_symbol_list[] = { "_mqx_kernel_data", "MQX_init_struct", NULL }; static const struct mqx_params mqx_params_list[] = { { "cortex_m", mqx_arch_cortexm, &rtos_mqx_arm_v7m_stacking }, }; /* * Perform simple address check to avoid bus fault. */ static int mqx_valid_address_check( struct rtos *rtos, uint32_t address ) { enum mqx_arch arch_type = ((struct mqx_params *)rtos->rtos_specific_params)->target_arch; const char *targetname = ((struct mqx_params *)rtos->rtos_specific_params)->target_name; /* Cortex-M address range */ if (arch_type == mqx_arch_cortexm) { if ( /* code and sram area */ (address && address <= 0x3FFFFFFFu) || /* external ram area*/ (address >= 0x6000000u && address <= 0x9FFFFFFFu) ) { return ERROR_OK; } return ERROR_FAIL; } LOG_ERROR("MQX RTOS - unknown architecture %s", targetname); return ERROR_FAIL; } /* * Wrapper of 'target_read_buffer' fn. * Include address check. */ static int mqx_target_read_buffer( struct target *target, uint32_t address, uint32_t size, uint8_t *buffer ) { int status = mqx_valid_address_check(target->rtos, address); if (status != ERROR_OK) { LOG_WARNING("MQX RTOS - target address 0x%" PRIx32 " is not allowed to read", address); return status; } status = target_read_buffer(target, address, size, buffer); if (status != ERROR_OK) { LOG_ERROR("MQX RTOS - reading target address 0x%" PRIx32" failed", address); return status; } return ERROR_OK; } /* * Get symbol address if present */ static int mqx_get_symbol( struct rtos *rtos, enum mqx_symbols symbol, void *result ) { /* TODO: additional check ?? */ (*(int *)result) = (uint32_t)rtos->symbols[symbol].address; return ERROR_OK; } /* * Get value of struct member by passing * member offset, width and name (debug purpose) */ static int mqx_get_member( struct rtos *rtos, const uint32_t base_address, int32_t member_offset, int32_t member_width, const char *member_name, void *result ) { int status = ERROR_FAIL; status = mqx_target_read_buffer( rtos->target, base_address + member_offset, member_width, result ); if (status != ERROR_OK) LOG_WARNING("MQX RTOS - cannot read \"%s\" at address 0x%" PRIx32, member_name, (uint32_t)(base_address + member_offset)); return status; } /* * Check whether scheduler started */ static int mqx_is_scheduler_running( struct rtos *rtos ) { uint32_t kernel_data_symbol = 0; uint32_t kernel_data_addr = 0; uint32_t system_td_addr = 0; uint32_t active_td_addr = 0; uint32_t capability_value = 0; /* get '_mqx_kernel_data' symbol */ if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_symbol) != ERROR_OK) return ERROR_FAIL; /* get '_mqx_kernel_data' */ if (mqx_get_member(rtos, kernel_data_symbol, 0, 4, "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK) return ERROR_FAIL; /* return if '_mqx_kernel_data' is NULL or default 0xFFFFFFFF */ if (kernel_data_addr == 0 || kernel_data_addr == (uint32_t)(-1)) return ERROR_FAIL; /* get kernel_data->ADDRESSING_CAPABILITY */ if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_CAPABILITY, 4, "kernel_data->ADDRESSING_CAPABILITY", (void *)&capability_value) != ERROR_OK) return ERROR_FAIL; /* check first member, the '_mqx_kernel_data->ADDRESSING_CAPABILITY'. it suppose to be set to value 8 */ if (capability_value != 8) { LOG_WARNING("MQX RTOS - value of '_mqx_kernel_data->ADDRESSING_CAPABILITY' contains invalid value"); return ERROR_FAIL; } /* get active ptr */ if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4, "kernel_data->ACTIVE_PTR", (void *)&active_td_addr) != ERROR_OK) return ERROR_FAIL; /* active task is system task, scheduler has not not run yet */ system_td_addr = kernel_data_addr + MQX_KERNEL_OFFSET_SYSTEM_TASK; if (active_td_addr == system_td_addr) { LOG_WARNING("MQX RTOS - scheduler does not run"); return ERROR_FAIL; } return ERROR_OK; } /* * API function, return true if MQX is present */ static bool mqx_detect_rtos( struct target *target ) { if ( (target->rtos->symbols) && (target->rtos->symbols[MQX_VAL_MQX_KERNEL_DATA].address != 0) ) { return true; } return false; } /* * API function, pass MQX extra info to context data */ static int mqx_create( struct target *target ) { /* check target name against supported architectures */ for (unsigned int i = 0; i < ARRAY_SIZE(mqx_params_list); i++) { if (strcmp(mqx_params_list[i].target_name, target->type->name) == 0) { target->rtos->rtos_specific_params = (void *)&mqx_params_list[i]; /* LOG_DEBUG("MQX RTOS - valid architecture: %s", target->type->name); */ return 0; } } LOG_ERROR("MQX RTOS - could not find target \"%s\" in MQX compatibility list", target->type->name); return -1; } /* * API function, update list of threads */ static int mqx_update_threads( struct rtos *rtos ) { uint32_t task_queue_addr = 0; uint32_t kernel_data_addr = 0; uint16_t task_queue_size = 0; uint32_t active_td_addr = 0; if (!rtos->rtos_specific_params) return -3; if (!rtos->symbols) return -4; /* clear old data */ rtos_free_threadlist(rtos); /* check scheduler */ if (mqx_is_scheduler_running(rtos) != ERROR_OK) return ERROR_FAIL; /* get kernel_data symbol */ if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_addr) != ERROR_OK) return ERROR_FAIL; /* read kernel_data */ if (mqx_get_member(rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK) return ERROR_FAIL; /* get task queue address */ task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST; /* get task queue size */ if (mqx_get_member(rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2, "kernel_data->TD_LIST.SIZE", &task_queue_size) != ERROR_OK) return ERROR_FAIL; /* get active ptr */ if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4, "kernel_data->ACTIVE_PTR", (void *)&active_td_addr) != ERROR_OK) return ERROR_FAIL; /* setup threads info */ rtos->thread_count = task_queue_size; rtos->current_thread = 0; rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail)); if (!rtos->thread_details) return ERROR_FAIL; /* loop over each task and setup thread details, the current_taskpool_addr is set to queue head NOTE: debugging functions task create/destroy might cause to show invalid data. */ for ( uint32_t i = 0, taskpool_addr = task_queue_addr; i < (uint32_t)rtos->thread_count; i++ ) { uint8_t task_name[MQX_THREAD_NAME_LENGTH + 1]; uint32_t task_addr = 0, task_template = 0, task_state = 0; uint32_t task_name_addr = 0, task_id = 0, task_errno = 0; uint32_t state_index = 0; uint32_t extra_info_length = 0; char *state_name = "Unknown"; /* set current taskpool address */ if (mqx_get_member(rtos, taskpool_addr, MQX_TASK_OFFSET_NEXT, 4, "td_struct_ptr->NEXT", &taskpool_addr) != ERROR_OK) return ERROR_FAIL; /* get task address from taskpool */ task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST; /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR' */ if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_TEMPLATE, 4, "td_struct_ptr->TEMPLATE_LIST_PTR", &task_template) != ERROR_OK) return ERROR_FAIL; /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR->NAME' */ if (mqx_get_member(rtos, task_template, MQX_TASK_TEMPLATE_OFFSET_NAME, 4, "td_struct_ptr->TEMPLATE_LIST_PTR->NAME", &task_name_addr) != ERROR_OK) return ERROR_FAIL; /* get value of 'td_struct->TEMPLATE_LIST_PTR->NAME' */ if (mqx_get_member(rtos, task_name_addr, 0, MQX_THREAD_NAME_LENGTH, "*td_struct_ptr->TEMPLATE_LIST_PTR->NAME", task_name) != ERROR_OK) return ERROR_FAIL; /* always terminate last character by force, otherwise openocd might fail if task_name has corrupted data */ task_name[MQX_THREAD_NAME_LENGTH] = '\0'; /* get value of 'td_struct_ptr->TASK_ID' */ if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ID, 4, "td_struct_ptr->TASK_ID", &task_id) != ERROR_OK) return ERROR_FAIL; /* get task errno */ if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ERROR_CODE, 4, "td_struct_ptr->TASK_ERROR_CODE", &task_errno) != ERROR_OK) return ERROR_FAIL; /* get value of 'td_struct_ptr->STATE' */ if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_STATE, 4, "td_struct_ptr->STATE", &task_state) != ERROR_OK) return ERROR_FAIL; task_state &= MQX_TASK_STATE_MASK; /* and search for defined state */ for (state_index = 0; state_index < ARRAY_SIZE(mqx_states); state_index++) { if (mqx_states[state_index].state == task_state) { state_name = mqx_states[state_index].name; break; } } /* setup thread details struct */ rtos->thread_details[i].threadid = task_id; rtos->thread_details[i].exists = true; /* set thread name */ rtos->thread_details[i].thread_name_str = malloc(strlen((void *)task_name) + 1); if (!rtos->thread_details[i].thread_name_str) return ERROR_FAIL; strcpy(rtos->thread_details[i].thread_name_str, (void *)task_name); /* set thread extra info * - task state * - task address * - task errno * calculate length as: * state length + address length + errno length + formatter length */ extra_info_length += strlen((void *)state_name) + 7 + 13 + 8 + 15 + 8; rtos->thread_details[i].extra_info_str = malloc(extra_info_length + 1); if (!rtos->thread_details[i].extra_info_str) return ERROR_FAIL; snprintf(rtos->thread_details[i].extra_info_str, extra_info_length, "State: %s, Address: 0x%" PRIx32 ", Error Code: %" PRIu32, state_name, task_addr, task_errno ); /* set active thread */ if (active_td_addr == task_addr) rtos->current_thread = task_id; } return ERROR_OK; } /* * API function, get info of selected thread */ static int mqx_get_thread_reg_list( struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs ) { int64_t stack_ptr = 0; uint32_t my_task_addr = 0; uint32_t task_queue_addr = 0; uint32_t task_queue_size = 0; uint32_t kernel_data_addr = 0; if (thread_id == 0) { LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id); return ERROR_FAIL; } if (mqx_is_scheduler_running(rtos) != ERROR_OK) return ERROR_FAIL; /* get kernel_data symbol */ if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_addr) != ERROR_OK) return ERROR_FAIL; /* read kernel_data */ if (mqx_get_member(rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK) return ERROR_FAIL; /* get task queue address */ task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST; /* get task queue size */ if (mqx_get_member(rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2, "kernel_data->TD_LIST.SIZE", &task_queue_size) != ERROR_OK) return ERROR_FAIL; /* search for taskid */ for ( uint32_t i = 0, taskpool_addr = task_queue_addr; i < (uint32_t)rtos->thread_count; i++ ) { uint32_t tmp_address = 0, task_addr = 0; uint32_t task_id = 0; /* set current taskpool address */ tmp_address = taskpool_addr; if (mqx_get_member(rtos, tmp_address, MQX_TASK_OFFSET_NEXT, 4, "td_struct_ptr->NEXT", &taskpool_addr) != ERROR_OK) return ERROR_FAIL; /* get task address from taskpool */ task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST; /* get value of td_struct->TASK_ID */ if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ID, 4, "td_struct_ptr->TASK_ID", &task_id) != ERROR_OK) return ERROR_FAIL; /* found taskid, break */ if (task_id == thread_id) { my_task_addr = task_addr; break; } } if (!my_task_addr) { LOG_ERROR("MQX_RTOS - threadid %" PRId64 " does not match any task", thread_id); return ERROR_FAIL; } /* get task stack head address */ if (mqx_get_member(rtos, my_task_addr, MQX_TASK_OFFSET_STACK, 4, "task->STACK_PTR", &stack_ptr) != ERROR_OK) return ERROR_FAIL; return rtos_generic_stack_read( rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, reg_list, num_regs ); } /* API function, export list of required symbols */ static int mqx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { *symbol_list = calloc(ARRAY_SIZE(mqx_symbol_list), sizeof(struct symbol_table_elem)); if (!*symbol_list) return ERROR_FAIL; /* export required symbols */ for (int i = 0; i < (int)(ARRAY_SIZE(mqx_symbol_list)); i++) (*symbol_list)[i].symbol_name = mqx_symbol_list[i]; return ERROR_OK; } const struct rtos_type mqx_rtos = { .name = "mqx", .detect_rtos = mqx_detect_rtos, .create = mqx_create, .update_threads = mqx_update_threads, .get_thread_reg_list = mqx_get_thread_reg_list, .get_symbol_list_to_lookup = mqx_get_symbol_list_to_lookup, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/nuttx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright 2016,2017 Sony Video & Sound Products Inc. * * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com * * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/jtag.h> #include "target/target.h" #include "target/target_type.h" #include "target/armv7m.h" #include "target/cortex_m.h" #include "rtos.h" #include "helper/log.h" #include "helper/types.h" #include "target/register.h" #include "rtos_nuttx_stackings.h" #define NAME_SIZE 32 #define EXTRAINFO_SIZE 256 /* Only 32-bit CPUs are supported by the current implementation. Supporting * other CPUs will require reading this information from the target and * adapting the code accordingly. */ #define PTR_WIDTH 4 struct nuttx_params { const char *target_name; const struct rtos_register_stacking *stacking; const struct rtos_register_stacking *(*select_stackinfo)(struct target *target); }; /* * struct tcbinfo_s is located in the sched.h * https://github.com/apache/nuttx/blob/master/include/nuttx/sched.h */ #define TCBINFO_TARGET_SIZE 22 struct tcbinfo { uint16_t pid_off; /* Offset of tcb.pid */ uint16_t state_off; /* Offset of tcb.task_state */ uint16_t pri_off; /* Offset of tcb.sched_priority */ uint16_t name_off; /* Offset of tcb.name */ uint16_t regs_off; /* Offset of tcb.regs */ uint16_t basic_num; /* Num of genernal regs */ uint16_t total_num; /* Num of regs in tcbinfo.reg_offs */ target_addr_t xcpreg_off; /* Offset pointer of xcp.regs */ }; struct symbols { const char *name; bool optional; }; /* Used to index the list of retrieved symbols. See nuttx_symbol_list for the order. */ enum nuttx_symbol_vals { NX_SYM_READYTORUN = 0, NX_SYM_PIDHASH, NX_SYM_NPIDHASH, NX_SYM_TCB_INFO, }; static const struct symbols nuttx_symbol_list[] = { { "g_readytorun", false }, { "g_pidhash", false }, { "g_npidhash", false }, { "g_tcbinfo", false }, { NULL, false } }; static char *task_state_str[] = { "INVALID", "PENDING", "READYTORUN", "RUNNING", "INACTIVE", "WAIT_SEM", "WAIT_SIG", "WAIT_MQNOTEMPTY", "WAIT_MQNOTFULL", "WAIT_PAGEFILL", "STOPPED", }; static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target); static const struct nuttx_params nuttx_params_list[] = { { .target_name = "cortex_m", .stacking = NULL, .select_stackinfo = cortexm_select_stackinfo, }, { .target_name = "hla_target", .stacking = NULL, .select_stackinfo = cortexm_select_stackinfo, }, { .target_name = "esp32", .stacking = &nuttx_esp32_stacking, }, { .target_name = "esp32s2", .stacking = &nuttx_esp32s2_stacking, }, { .target_name = "esp32s3", .stacking = &nuttx_esp32s3_stacking, }, { .target_name = "esp32c3", .stacking = &nuttx_riscv_stacking, }, }; static bool cortexm_hasfpu(struct target *target) { uint32_t cpacr; struct armv7m_common *armv7m_target = target_to_armv7m(target); if (!is_armv7m(armv7m_target) || armv7m_target->fp_feature == FP_NONE) return false; int retval = target_read_u32(target, FPU_CPACR, &cpacr); if (retval != ERROR_OK) { LOG_ERROR("Could not read CPACR register to check FPU state"); return false; } return cpacr & 0x00F00000; } static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target) { return cortexm_hasfpu(target) ? &nuttx_stacking_cortex_m_fpu : &nuttx_stacking_cortex_m; } static bool nuttx_detect_rtos(struct target *target) { if (target->rtos->symbols && target->rtos->symbols[NX_SYM_READYTORUN].address != 0 && target->rtos->symbols[NX_SYM_PIDHASH].address != 0) return true; return false; } static int nuttx_create(struct target *target) { const struct nuttx_params *param; unsigned int i; for (i = 0; i < ARRAY_SIZE(nuttx_params_list); i++) { param = &nuttx_params_list[i]; if (strcmp(target_type_name(target), param->target_name) == 0) { LOG_INFO("Detected target \"%s\"", param->target_name); break; } } if (i >= ARRAY_SIZE(nuttx_params_list)) { LOG_ERROR("Could not find \"%s\" target in NuttX compatibility list", target_type_name(target)); return JIM_ERR; } /* We found a target in our list, copy its reference. */ target->rtos->rtos_specific_params = (void *)param; return JIM_OK; } static int nuttx_smp_init(struct target *target) { /* Return OK for now so that the initialisation sequence doesn't stop. * SMP case will be implemented later. */ return ERROR_OK; } static target_addr_t target_buffer_get_addr(struct target *target, const uint8_t *buffer) { #if PTR_WIDTH == 8 return target_buffer_get_u64(target, buffer); #else return target_buffer_get_u32(target, buffer); #endif } static int nuttx_update_threads(struct rtos *rtos) { struct tcbinfo tcbinfo; uint32_t pidhashaddr, npidhash, tcbaddr; uint16_t pid; uint8_t state; if (!rtos->symbols) { LOG_ERROR("No symbols for nuttx"); return ERROR_FAIL; } /* Free previous thread details */ rtos_free_threadlist(rtos); /* NuttX provides a hash table that keeps track of all the TCBs. * We first read its size from g_npidhash and its address from g_pidhash. * Its content is then read from these values. */ int ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_NPIDHASH].address, &npidhash); if (ret != ERROR_OK) { LOG_ERROR("Failed to read g_npidhash: ret = %d", ret); return ERROR_FAIL; } LOG_DEBUG("Hash table size (g_npidhash) = %" PRId32, npidhash); ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_PIDHASH].address, &pidhashaddr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read g_pidhash address: ret = %d", ret); return ERROR_FAIL; } LOG_DEBUG("Hash table address (g_pidhash) = %" PRIx32, pidhashaddr); uint8_t *pidhash = malloc(npidhash * PTR_WIDTH); if (!pidhash) { LOG_ERROR("Failed to allocate pidhash"); return ERROR_FAIL; } ret = target_read_buffer(rtos->target, pidhashaddr, PTR_WIDTH * npidhash, pidhash); if (ret != ERROR_OK) { LOG_ERROR("Failed to read tcbhash: ret = %d", ret); goto errout; } /* NuttX provides a struct that contains TCB offsets for required members. * Read its content from g_tcbinfo. */ uint8_t buff[TCBINFO_TARGET_SIZE]; ret = target_read_buffer(rtos->target, rtos->symbols[NX_SYM_TCB_INFO].address, sizeof(buff), buff); if (ret != ERROR_OK) { LOG_ERROR("Failed to read tcbinfo: ret = %d", ret); goto errout; } tcbinfo.pid_off = target_buffer_get_u16(rtos->target, buff); tcbinfo.state_off = target_buffer_get_u16(rtos->target, buff + 2); tcbinfo.pri_off = target_buffer_get_u16(rtos->target, buff + 4); tcbinfo.name_off = target_buffer_get_u16(rtos->target, buff + 6); tcbinfo.regs_off = target_buffer_get_u16(rtos->target, buff + 8); tcbinfo.basic_num = target_buffer_get_u16(rtos->target, buff + 10); tcbinfo.total_num = target_buffer_get_u16(rtos->target, buff + 12); tcbinfo.xcpreg_off = target_buffer_get_addr(rtos->target, buff + 14); /* The head of the g_readytorun list is the currently running task. * Reading in a temporary variable first to avoid endianness issues, * rtos->current_thread is int64_t. */ uint32_t current_thread; ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_READYTORUN].address, ¤t_thread); if (ret != ERROR_OK) { LOG_ERROR("Failed to read g_readytorun: ret = %d", ret); goto errout; } rtos->current_thread = current_thread; uint32_t thread_count = 0; for (unsigned int i = 0; i < npidhash; i++) { tcbaddr = target_buffer_get_u32(rtos->target, &pidhash[i * PTR_WIDTH]); if (!tcbaddr) continue; ret = target_read_u16(rtos->target, tcbaddr + tcbinfo.pid_off, &pid); if (ret != ERROR_OK) { LOG_ERROR("Failed to read PID of TCB@0x%x from pidhash[%d]: ret = %d", tcbaddr, i, ret); goto errout; } ret = target_read_u8(rtos->target, tcbaddr + tcbinfo.state_off, &state); if (ret != ERROR_OK) { LOG_ERROR("Failed to read state of TCB@0x%x from pidhash[%d]: ret = %d", tcbaddr, i, ret); goto errout; } struct thread_detail *new_thread_details = realloc(rtos->thread_details, sizeof(struct thread_detail) * (thread_count + 1)); if (!new_thread_details) { ret = ERROR_FAIL; goto errout; } struct thread_detail *thread = &new_thread_details[thread_count]; thread->threadid = tcbaddr; thread->exists = true; thread->extra_info_str = NULL; rtos->thread_details = new_thread_details; thread_count++; if (state < ARRAY_SIZE(task_state_str)) { thread->extra_info_str = malloc(EXTRAINFO_SIZE); if (!thread->extra_info_str) { ret = ERROR_FAIL; goto errout; } snprintf(thread->extra_info_str, EXTRAINFO_SIZE, "pid:%d, %s", pid, task_state_str[state]); } if (tcbinfo.name_off) { thread->thread_name_str = calloc(NAME_SIZE + 1, sizeof(char)); if (!thread->thread_name_str) { ret = ERROR_FAIL; goto errout; } ret = target_read_buffer(rtos->target, tcbaddr + tcbinfo.name_off, sizeof(char) * NAME_SIZE, (uint8_t *)thread->thread_name_str); if (ret != ERROR_OK) { LOG_ERROR("Failed to read thread's name: ret = %d", ret); goto errout; } } else { thread->thread_name_str = strdup("None"); } } ret = ERROR_OK; rtos->thread_count = thread_count; errout: free(pidhash); return ret; } static int nuttx_getreg_current_thread(struct rtos *rtos, struct rtos_reg **reg_list, int *num_regs) { struct reg **gdb_reg_list; /* Registers for currently running thread are not on task's stack and * should be retrieved from reg caches via target_get_gdb_reg_list */ int ret = target_get_gdb_reg_list(rtos->target, &gdb_reg_list, num_regs, REG_CLASS_GENERAL); if (ret != ERROR_OK) { LOG_ERROR("target_get_gdb_reg_list failed %d", ret); return ret; } *reg_list = calloc(*num_regs, sizeof(struct rtos_reg)); if (!(*reg_list)) { LOG_ERROR("Failed to alloc memory for %d", *num_regs); free(gdb_reg_list); return ERROR_FAIL; } for (int i = 0; i < *num_regs; i++) { (*reg_list)[i].number = gdb_reg_list[i]->number; (*reg_list)[i].size = gdb_reg_list[i]->size; memcpy((*reg_list)[i].value, gdb_reg_list[i]->value, ((*reg_list)[i].size + 7) / 8); } free(gdb_reg_list); return ERROR_OK; } static int nuttx_getregs_fromstack(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { uint16_t xcpreg_off; uint32_t regsaddr; const struct nuttx_params *priv = rtos->rtos_specific_params; const struct rtos_register_stacking *stacking = priv->stacking; if (!stacking) { if (priv->select_stackinfo) { stacking = priv->select_stackinfo(rtos->target); } else { LOG_ERROR("Can't find a way to get stacking info"); return ERROR_FAIL; } } int ret = target_read_u16(rtos->target, rtos->symbols[NX_SYM_TCB_INFO].address + offsetof(struct tcbinfo, regs_off), &xcpreg_off); if (ret != ERROR_OK) { LOG_ERROR("Failed to read registers' offset: ret = %d", ret); return ERROR_FAIL; } ret = target_read_u32(rtos->target, thread_id + xcpreg_off, ®saddr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read registers' address: ret = %d", ret); return ERROR_FAIL; } return rtos_generic_stack_read(rtos->target, stacking, regsaddr, reg_list, num_regs); } static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { if (!rtos) { LOG_ERROR("NUTTX: out of memory"); return ERROR_FAIL; } if (thread_id == rtos->current_thread) return nuttx_getreg_current_thread(rtos, reg_list, num_regs); return nuttx_getregs_fromstack(rtos, thread_id, reg_list, num_regs); } static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { *symbol_list = calloc(ARRAY_SIZE(nuttx_symbol_list), sizeof(**symbol_list)); if (!*symbol_list) { LOG_ERROR("NUTTX: out of memory"); return ERROR_FAIL; } for (unsigned int i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++) { (*symbol_list)[i].symbol_name = nuttx_symbol_list[i].name; (*symbol_list)[i].optional = nuttx_symbol_list[i].optional; } return ERROR_OK; } const struct rtos_type nuttx_rtos = { .name = "nuttx", .detect_rtos = nuttx_detect_rtos, .create = nuttx_create, .smp_init = nuttx_smp_init, .update_threads = nuttx_update_threads, .get_thread_reg_list = nuttx_get_thread_reg_list, .get_symbol_list_to_lookup = nuttx_get_symbol_list_to_lookup, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/riot.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2015 by Daniel Krebs * * Daniel Krebs - github@daniel-krebs.net * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/time_support.h> #include <jtag/jtag.h> #include "target/target.h" #include "target/target_type.h" #include "rtos.h" #include "helper/log.h" #include "helper/types.h" #include "target/armv7m.h" #include "rtos_riot_stackings.h" static bool riot_detect_rtos(struct target *target); static int riot_create(struct target *target); static int riot_update_threads(struct rtos *rtos); static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); struct riot_thread_state { int value; const char *desc; }; /* refer RIOT sched.h */ static const struct riot_thread_state riot_thread_states[] = { { 0, "Stopped" }, { 1, "Zombie" }, { 2, "Sleeping" }, { 3, "Blocked mutex" }, { 4, "Blocked receive" }, { 5, "Blocked send" }, { 6, "Blocked reply" }, { 7, "Blocked any flag" }, { 8, "Blocked all flags" }, { 9, "Blocked mbox" }, { 10, "Blocked condition" }, { 11, "Running" }, { 12, "Pending" }, }; #define RIOT_NUM_STATES ARRAY_SIZE(riot_thread_states) struct riot_params { const char *target_name; unsigned char thread_sp_offset; unsigned char thread_status_offset; }; static const struct riot_params riot_params_list[] = { { "cortex_m", /* target_name */ 0x00, /* thread_sp_offset */ 0x04, /* thread_status_offset */ }, { /* STLink */ "hla_target", /* target_name */ 0x00, /* thread_sp_offset */ 0x04, /* thread_status_offset */ } }; #define RIOT_NUM_PARAMS ARRAY_SIZE(riot_params_list) /* Initialize in riot_create() depending on architecture */ static const struct rtos_register_stacking *stacking_info; enum riot_symbol_values { RIOT_THREADS_BASE = 0, RIOT_NUM_THREADS, RIOT_ACTIVE_PID, RIOT_MAX_THREADS, RIOT_NAME_OFFSET, }; struct riot_symbol { const char *const name; bool optional; }; /* refer RIOT core/sched.c */ static struct riot_symbol const riot_symbol_list[] = { {"sched_threads", false}, {"sched_num_threads", false}, {"sched_active_pid", false}, {"max_threads", false}, {"_tcb_name_offset", true}, {NULL, false} }; const struct rtos_type riot_rtos = { .name = "RIOT", .detect_rtos = riot_detect_rtos, .create = riot_create, .update_threads = riot_update_threads, .get_thread_reg_list = riot_get_thread_reg_list, .get_symbol_list_to_lookup = riot_get_symbol_list_to_lookup, }; static int riot_update_threads(struct rtos *rtos) { int retval; int tasks_found = 0; const struct riot_params *param; if (!rtos) return ERROR_FAIL; if (!rtos->rtos_specific_params) return ERROR_FAIL; param = (const struct riot_params *)rtos->rtos_specific_params; if (!rtos->symbols) { LOG_ERROR("No symbols for RIOT"); return ERROR_FAIL; } if (rtos->symbols[RIOT_THREADS_BASE].address == 0) { LOG_ERROR("Can't find symbol `%s`", riot_symbol_list[RIOT_THREADS_BASE].name); return ERROR_FAIL; } /* wipe out previous thread details if any */ rtos_free_threadlist(rtos); /* Reset values */ rtos->current_thread = 0; rtos->thread_count = 0; /* read the current thread id */ int16_t active_pid = 0; retval = target_read_u16(rtos->target, rtos->symbols[RIOT_ACTIVE_PID].address, (uint16_t *)&active_pid); if (retval != ERROR_OK) { LOG_ERROR("Can't read symbol `%s`", riot_symbol_list[RIOT_ACTIVE_PID].name); return retval; } rtos->current_thread = active_pid; /* read the current thread count * It's `int` in RIOT, but this is Cortex M* only anyway */ int32_t thread_count = 0; retval = target_read_u16(rtos->target, rtos->symbols[RIOT_NUM_THREADS].address, (uint16_t *)&thread_count); if (retval != ERROR_OK) { LOG_ERROR("Can't read symbol `%s`", riot_symbol_list[RIOT_NUM_THREADS].name); return retval; } /* read the maximum number of threads */ uint8_t max_threads = 0; retval = target_read_u8(rtos->target, rtos->symbols[RIOT_MAX_THREADS].address, &max_threads); if (retval != ERROR_OK) { LOG_ERROR("Can't read symbol `%s`", riot_symbol_list[RIOT_MAX_THREADS].name); return retval; } if (thread_count > max_threads) { LOG_ERROR("Thread count is invalid"); return ERROR_FAIL; } rtos->thread_count = thread_count; /* Base address of thread array */ uint32_t threads_base = rtos->symbols[RIOT_THREADS_BASE].address; /* Try to get the offset of tcb_t::name, if absent RIOT wasn't compiled * with DEVELHELP, so there are no thread names */ uint8_t name_offset = 0; if (rtos->symbols[RIOT_NAME_OFFSET].address != 0) { retval = target_read_u8(rtos->target, rtos->symbols[RIOT_NAME_OFFSET].address, &name_offset); if (retval != ERROR_OK) { LOG_ERROR("Can't read symbol `%s`", riot_symbol_list[RIOT_NAME_OFFSET].name); return retval; } } /* Allocate memory for thread description */ rtos->thread_details = calloc(thread_count, sizeof(struct thread_detail)); if (!rtos->thread_details) { LOG_ERROR("RIOT: out of memory"); return ERROR_FAIL; } /* Buffer for thread names, maximum to display is 32 */ char buffer[32]; for (unsigned int i = 0; i < max_threads; i++) { if (tasks_found == rtos->thread_count) break; /* get pointer to tcb_t */ uint32_t tcb_pointer = 0; retval = target_read_u32(rtos->target, threads_base + (i * 4), &tcb_pointer); if (retval != ERROR_OK) { LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name); goto error; } if (tcb_pointer == 0) { /* PID unused */ continue; } /* Index is PID */ rtos->thread_details[tasks_found].threadid = i; /* read thread state */ uint8_t status = 0; retval = target_read_u8(rtos->target, tcb_pointer + param->thread_status_offset, &status); if (retval != ERROR_OK) { LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name); goto error; } /* Search for state */ unsigned int k; for (k = 0; k < RIOT_NUM_STATES; k++) { if (riot_thread_states[k].value == status) break; } /* Copy state string */ if (k >= RIOT_NUM_STATES) { rtos->thread_details[tasks_found].extra_info_str = strdup("unknown state"); } else { rtos->thread_details[tasks_found].extra_info_str = strdup(riot_thread_states[k].desc); } if (!rtos->thread_details[tasks_found].extra_info_str) { LOG_ERROR("RIOT: out of memory"); retval = ERROR_FAIL; goto error; } /* Thread names are only available if compiled with DEVELHELP */ if (name_offset != 0) { uint32_t name_pointer = 0; retval = target_read_u32(rtos->target, tcb_pointer + name_offset, &name_pointer); if (retval != ERROR_OK) { LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name); goto error; } /* read thread name */ retval = target_read_buffer(rtos->target, name_pointer, sizeof(buffer), (uint8_t *)&buffer); if (retval != ERROR_OK) { LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name); goto error; } /* Make sure the string in the buffer terminates */ if (buffer[sizeof(buffer) - 1] != 0) buffer[sizeof(buffer) - 1] = 0; /* Copy thread name */ rtos->thread_details[tasks_found].thread_name_str = strdup(buffer); } else { rtos->thread_details[tasks_found].thread_name_str = strdup("Enable DEVELHELP to see task names"); } if (!rtos->thread_details[tasks_found].thread_name_str) { LOG_ERROR("RIOT: out of memory"); retval = ERROR_FAIL; goto error; } rtos->thread_details[tasks_found].exists = true; tasks_found++; } return ERROR_OK; error: rtos_free_threadlist(rtos); return retval; } static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { int retval; const struct riot_params *param; if (!rtos) return ERROR_FAIL; if (thread_id == 0) return ERROR_FAIL; if (!rtos->rtos_specific_params) return ERROR_FAIL; param = (const struct riot_params *)rtos->rtos_specific_params; /* find the thread with given thread id */ uint32_t threads_base = rtos->symbols[RIOT_THREADS_BASE].address; uint32_t tcb_pointer = 0; retval = target_read_u32(rtos->target, threads_base + (thread_id * 4), &tcb_pointer); if (retval != ERROR_OK) { LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name); return retval; } /* read stack pointer for that thread */ uint32_t stackptr = 0; retval = target_read_u32(rtos->target, tcb_pointer + param->thread_sp_offset, &stackptr); if (retval != ERROR_OK) { LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name); return retval; } return rtos_generic_stack_read(rtos->target, stacking_info, stackptr, reg_list, num_regs); } static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { *symbol_list = calloc(ARRAY_SIZE(riot_symbol_list), sizeof(struct symbol_table_elem)); if (!*symbol_list) { LOG_ERROR("RIOT: out of memory"); return ERROR_FAIL; } for (unsigned int i = 0; i < ARRAY_SIZE(riot_symbol_list); i++) { (*symbol_list)[i].symbol_name = riot_symbol_list[i].name; (*symbol_list)[i].optional = riot_symbol_list[i].optional; } return ERROR_OK; } static bool riot_detect_rtos(struct target *target) { if ((target->rtos->symbols) && (target->rtos->symbols[RIOT_THREADS_BASE].address != 0)) { /* looks like RIOT */ return true; } return false; } static int riot_create(struct target *target) { unsigned int i = 0; /* lookup if target is supported by RIOT */ while ((i < RIOT_NUM_PARAMS) && (strcmp(riot_params_list[i].target_name, target->type->name) != 0)) { i++; } if (i >= RIOT_NUM_PARAMS) { LOG_ERROR("Could not find target in RIOT compatibility list"); return ERROR_FAIL; } target->rtos->rtos_specific_params = (void *)&riot_params_list[i]; target->rtos->current_thread = 0; target->rtos->thread_details = NULL; /* Stacking is different depending on architecture */ struct armv7m_common *armv7m_target = target_to_armv7m(target); if (armv7m_target->arm.arch == ARM_ARCH_V6M) stacking_info = &rtos_riot_cortex_m0_stacking; else if (is_armv7m(armv7m_target)) stacking_info = &rtos_riot_cortex_m34_stacking; else { LOG_ERROR("No stacking info for architecture"); return ERROR_FAIL; } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtkernel.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2016-2023 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/time_support.h> #include <jtag/jtag.h> #include "target/target.h" #include "target/target_type.h" #include "rtos.h" #include "helper/log.h" #include "helper/types.h" #include "rtos_standard_stackings.h" #include "target/armv7m.h" #include "target/cortex_m.h" #define ST_DEAD BIT(0) /* Task is waiting to be deleted */ #define ST_WAIT BIT(1) /* Task is blocked: */ #define ST_SEM BIT(2) /* on semaphore */ #define ST_MTX BIT(3) /* on mutex */ #define ST_SIG BIT(4) /* on signal */ #define ST_DLY BIT(5) /* on timer */ #define ST_FLAG BIT(6) /* on flag */ #define ST_FLAG_ALL BIT(7) /* on flag and flag mode is "ALL" */ #define ST_MBOX BIT(8) /* on mailbox */ #define ST_STP BIT(9) /* self stopped */ #define ST_SUSPEND BIT(10) /* Task is suspended */ #define ST_TT BIT(11) /* Time triggered task */ #define ST_TT_YIELD BIT(12) /* Time triggered task that yields */ #define ST_CREATE BIT(13) /* Task was created by task_create() */ struct rtkernel_params { const char *target_name; const struct rtos_register_stacking *stacking_info_cm3; const struct rtos_register_stacking *stacking_info_cm4f; const struct rtos_register_stacking *stacking_info_cm4f_fpu; }; static const struct rtkernel_params rtkernel_params_list[] = { { "cortex_m", /* target_name */ &rtos_standard_cortex_m3_stacking, /* stacking_info */ &rtos_standard_cortex_m4f_stacking, &rtos_standard_cortex_m4f_fpu_stacking, }, { "hla_target", /* target_name */ &rtos_standard_cortex_m3_stacking, /* stacking_info */ &rtos_standard_cortex_m4f_stacking, &rtos_standard_cortex_m4f_fpu_stacking, }, }; enum rtkernel_symbol_values { sym_os_state = 0, sym___off_os_state2chain = 1, sym___off_os_state2current = 2, sym___off_task2chain = 3, sym___off_task2magic = 4, sym___off_task2stack = 5, sym___off_task2state = 6, sym___off_task2name = 7, sym___val_task_magic = 8, }; struct symbols { const char *name; bool optional; }; static const struct symbols rtkernel_symbol_list[] = { { "os_state", false }, { "__off_os_state2chain", false }, { "__off_os_state2current", false }, { "__off_task2chain", false }, { "__off_task2magic", false }, { "__off_task2stack", false }, { "__off_task2state", false }, { "__off_task2name", false }, { "__val_task_magic", false }, { NULL, false } }; static void *realloc_preserve(void *ptr, size_t old_size, size_t new_size) { void *new_ptr = malloc(new_size); if (new_ptr) { memcpy(new_ptr, ptr, MIN(old_size, new_size)); free(ptr); } return new_ptr; } static int rtkernel_add_task(struct rtos *rtos, uint32_t task, uint32_t current_task) { int retval; int new_thread_count = rtos->thread_count + 1; struct thread_detail *new_thread_details = realloc_preserve(rtos->thread_details, rtos->thread_count * sizeof(struct thread_detail), new_thread_count * sizeof(struct thread_detail)); if (!new_thread_details) { LOG_ERROR("Error growing memory to %d threads", new_thread_count); return ERROR_FAIL; } rtos->thread_details = new_thread_details; struct thread_detail *thread = &new_thread_details[rtos->thread_count]; *thread = (struct thread_detail){ .threadid = task, .exists = true }; /* Read the task name */ uint32_t name; retval = target_read_u32(rtos->target, task + rtos->symbols[sym___off_task2name].address, &name); if (retval != ERROR_OK) { LOG_ERROR("Could not read task name pointer from target"); return retval; } uint8_t tmp_str[33]; retval = target_read_buffer(rtos->target, name, sizeof(tmp_str) - 1, tmp_str); if (retval != ERROR_OK) { LOG_ERROR("Error reading task name from target"); return retval; } tmp_str[sizeof(tmp_str) - 1] = '\0'; LOG_DEBUG("task name at 0x%" PRIx32 ", value \"%s\"", name, tmp_str); if (tmp_str[0] != '\0') thread->thread_name_str = strdup((char *)tmp_str); else thread->thread_name_str = strdup("No Name"); /* Read the task state */ uint16_t state; retval = target_read_u16(rtos->target, task + rtos->symbols[sym___off_task2state].address, &state); if (retval != ERROR_OK) { LOG_ERROR("Could not read task state from target"); return retval; } LOG_DEBUG("task state 0x%" PRIx16, state); char state_str[64] = ""; if (state & ST_TT) strcat(state_str, "TT|"); if (task == current_task) { strcat(state_str, "RUN"); } else { if (state & (ST_TT | ST_TT_YIELD)) strcat(state_str, "YIELD"); else if (state & ST_DEAD) strcat(state_str, "DEAD"); else if (state & ST_WAIT) strcat(state_str, "WAIT"); else if (state & ST_SUSPEND) strcat(state_str, "SUSP"); else strcat(state_str, "READY"); } if (state & ST_SEM) strcat(state_str, "|SEM"); if (state & ST_MTX) strcat(state_str, "|MTX"); if (state & ST_SIG) strcat(state_str, "|SIG"); if (state & ST_DLY) strcat(state_str, "|DLY"); if ((state & ST_FLAG) || (state & ST_FLAG_ALL)) strcat(state_str, "|FLAG"); if (state & ST_FLAG_ALL) strcat(state_str, "_ALL"); if (state & ST_MBOX) strcat(state_str, "|MBOX"); if (state & ST_STP) strcat(state_str, "|STP"); thread->extra_info_str = strdup(state_str); rtos->thread_count = new_thread_count; if (task == current_task) rtos->current_thread = task; return ERROR_OK; } static int rtkernel_verify_task(struct rtos *rtos, uint32_t task) { int retval; uint32_t magic; retval = target_read_u32(rtos->target, task + rtos->symbols[sym___off_task2magic].address, &magic); if (retval != ERROR_OK) { LOG_ERROR("Could not read task magic from target"); return retval; } if (magic != rtos->symbols[sym___val_task_magic].address) { LOG_ERROR("Invalid task found (magic=0x%" PRIx32 ")", magic); return ERROR_FAIL; } return retval; } static int rtkernel_update_threads(struct rtos *rtos) { /* wipe out previous thread details if any */ /* do this first because rtos layer does not check our retval */ rtos_free_threadlist(rtos); rtos->current_thread = 0; if (!rtos->symbols) { LOG_ERROR("No symbols for rt-kernel"); return -3; } /* read the current task */ uint32_t current_task; int retval = target_read_u32(rtos->target, rtos->symbols[sym_os_state].address + rtos->symbols[sym___off_os_state2current].address, ¤t_task); if (retval != ERROR_OK) { LOG_ERROR("Error reading current task"); return retval; } LOG_DEBUG("current task is 0x%" PRIx32, current_task); retval = rtkernel_verify_task(rtos, current_task); if (retval != ERROR_OK) { LOG_ERROR("Current task is invalid"); return retval; } /* loop through kernel task list */ uint32_t chain = rtos->symbols[sym_os_state].address + rtos->symbols[sym___off_os_state2chain].address; LOG_DEBUG("chain start at 0x%" PRIx32, chain); uint32_t next = chain; for (;;) { retval = target_read_u32(rtos->target, next, &next); if (retval != ERROR_OK) { LOG_ERROR("Could not read rt-kernel data structure from target"); return retval; } LOG_DEBUG("next entry at 0x%" PRIx32, next); if (next == chain) { LOG_DEBUG("end of chain detected"); break; } uint32_t task = next - rtos->symbols[sym___off_task2chain].address; LOG_DEBUG("found task at 0x%" PRIx32, task); retval = rtkernel_verify_task(rtos, task); if (retval != ERROR_OK) { LOG_ERROR("Invalid task found"); return retval; } retval = rtkernel_add_task(rtos, task, current_task); if (retval != ERROR_OK) { LOG_ERROR("Could not add task to rtos system"); return retval; } } return ERROR_OK; } static int rtkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { uint32_t stack_ptr = 0; if (!rtos) return -1; if (thread_id == 0) return -2; if (!rtos->rtos_specific_params) return -1; const struct rtkernel_params *param = rtos->rtos_specific_params; /* Read the stack pointer */ int retval = target_read_u32(rtos->target, thread_id + rtos->symbols[sym___off_task2stack].address, &stack_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading stack pointer from rtkernel thread"); return retval; } LOG_DEBUG("stack pointer at 0x%" PRIx64 ", value 0x%" PRIx32, thread_id + rtos->symbols[sym___off_task2stack].address, stack_ptr); /* Adjust stack pointer to ignore non-standard BASEPRI register stacking */ stack_ptr += 4; /* Check for armv7m with *enabled* FPU, i.e. a Cortex M4F */ bool cm4_fpu_enabled = false; struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); if (is_armv7m(armv7m_target)) { if (armv7m_target->fp_feature != FP_NONE) { /* Found ARM v7m target which includes a FPU */ uint32_t cpacr; retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr); if (retval != ERROR_OK) { LOG_ERROR("Could not read CPACR register to check FPU state"); return -1; } /* Check if CP10 and CP11 are set to full access. */ if (cpacr & 0x00F00000) { /* Found target with enabled FPU */ cm4_fpu_enabled = true; } } } if (!cm4_fpu_enabled) { LOG_DEBUG("cm3 stacking"); return rtos_generic_stack_read(rtos->target, param->stacking_info_cm3, stack_ptr, reg_list, num_regs); } /* Read the LR to decide between stacking with or without FPU */ uint32_t lr_svc; retval = target_read_u32(rtos->target, stack_ptr + 0x20, &lr_svc); if (retval != ERROR_OK) { LOG_OUTPUT("Error reading stack frame from rtkernel thread\r\n"); return retval; } if ((lr_svc & 0x10) == 0) { LOG_DEBUG("cm4f_fpu stacking"); return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f_fpu, stack_ptr, reg_list, num_regs); } LOG_DEBUG("cm4f stacking"); return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f, stack_ptr, reg_list, num_regs); } static int rtkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { *symbol_list = calloc(ARRAY_SIZE(rtkernel_symbol_list), sizeof(struct symbol_table_elem)); if (!*symbol_list) return ERROR_FAIL; for (size_t i = 0; i < ARRAY_SIZE(rtkernel_symbol_list); i++) { (*symbol_list)[i].symbol_name = rtkernel_symbol_list[i].name; (*symbol_list)[i].optional = rtkernel_symbol_list[i].optional; } return ERROR_OK; } static bool rtkernel_detect_rtos(struct target *target) { return (target->rtos->symbols) && (target->rtos->symbols[sym___off_os_state2chain].address != 0); } static int rtkernel_create(struct target *target) { for (size_t i = 0; i < ARRAY_SIZE(rtkernel_params_list); i++) { if (strcmp(rtkernel_params_list[i].target_name, target->type->name) == 0) { target->rtos->rtos_specific_params = (void *)&rtkernel_params_list[i]; return 0; } } LOG_ERROR("Could not find target in rt-kernel compatibility list"); return -1; } const struct rtos_type rtkernel_rtos = { .name = "rtkernel", .detect_rtos = rtkernel_detect_rtos, .create = rtkernel_create, .update_threads = rtkernel_update_threads, .get_thread_reg_list = rtkernel_get_thread_reg_list, .get_symbol_list_to_lookup = rtkernel_get_symbol_list_to_lookup, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" #include "target/target.h" #include "helper/log.h" #include "helper/binarybuffer.h" #include "server/gdb_server.h" static const struct rtos_type *rtos_types[] = { &threadx_rtos, &freertos_rtos, &ecos_rtos, &linux_rtos, &chibios_rtos, &chromium_ec_rtos, &embkernel_rtos, &mqx_rtos, &ucos_iii_rtos, &nuttx_rtos, &riot_rtos, &zephyr_rtos, &rtkernel_rtos, /* keep this as last, as it always matches with rtos auto */ &hwthread_rtos, NULL }; static int rtos_try_next(struct target *target); int rtos_smp_init(struct target *target) { if (target->rtos->type->smp_init) return target->rtos->type->smp_init(target); return ERROR_TARGET_INIT_FAILED; } static int rtos_target_for_threadid(struct connection *connection, int64_t threadid, struct target **t) { struct target *curr = get_target_from_connection(connection); if (t) *t = curr; return ERROR_OK; } static int os_alloc(struct target *target, const struct rtos_type *ostype) { struct rtos *os = target->rtos = calloc(1, sizeof(struct rtos)); if (!os) return JIM_ERR; os->type = ostype; os->current_threadid = -1; os->current_thread = 0; os->symbols = NULL; os->target = target; /* RTOS drivers can override the packet handler in _create(). */ os->gdb_thread_packet = rtos_thread_packet; os->gdb_target_for_threadid = rtos_target_for_threadid; return JIM_OK; } static void os_free(struct target *target) { if (!target->rtos) return; free(target->rtos->symbols); free(target->rtos); target->rtos = NULL; } static int os_alloc_create(struct target *target, const struct rtos_type *ostype) { int ret = os_alloc(target, ostype); if (ret == JIM_OK) { ret = target->rtos->type->create(target); if (ret != JIM_OK) os_free(target); } return ret; } int rtos_create(struct jim_getopt_info *goi, struct target *target) { int x; const char *cp; Jim_Obj *res; int e; if (!goi->isconfigure && goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); return JIM_ERR; } os_free(target); e = jim_getopt_string(goi, &cp, NULL); if (e != JIM_OK) return e; if (strcmp(cp, "none") == 0) return JIM_OK; if (strcmp(cp, "auto") == 0) { /* Auto detect tries to look up all symbols for each RTOS, * and runs the RTOS driver's _detect() function when GDB * finds all symbols for any RTOS. See rtos_qsymbol(). */ target->rtos_auto_detect = true; /* rtos_qsymbol() will iterate over all RTOSes. Allocate * target->rtos here, and set it to the first RTOS type. */ return os_alloc(target, rtos_types[0]); } for (x = 0; rtos_types[x]; x++) if (strcmp(cp, rtos_types[x]->name) == 0) return os_alloc_create(target, rtos_types[x]); Jim_SetResultFormatted(goi->interp, "Unknown RTOS type %s, try one of: ", cp); res = Jim_GetResult(goi->interp); for (x = 0; rtos_types[x]; x++) Jim_AppendStrings(goi->interp, res, rtos_types[x]->name, ", ", NULL); Jim_AppendStrings(goi->interp, res, ", auto or none", NULL); return JIM_ERR; } void rtos_destroy(struct target *target) { os_free(target); } int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); if (!target->rtos) return rtos_thread_packet(connection, packet, packet_size); /* thread not *found*/ return target->rtos->gdb_thread_packet(connection, packet, packet_size); } static struct symbol_table_elem *find_symbol(const struct rtos *os, const char *symbol) { struct symbol_table_elem *s; for (s = os->symbols; s->symbol_name; s++) if (!strcmp(s->symbol_name, symbol)) return s; return NULL; } static struct symbol_table_elem *next_symbol(struct rtos *os, char *cur_symbol, uint64_t cur_addr) { if (!os->symbols) os->type->get_symbol_list_to_lookup(&os->symbols); if (!cur_symbol[0]) return &os->symbols[0]; struct symbol_table_elem *s = find_symbol(os, cur_symbol); if (!s) return NULL; s->address = cur_addr; s++; return s; } /* rtos_qsymbol() processes and replies to all qSymbol packets from GDB. * * GDB sends a qSymbol:: packet (empty address, empty name) to notify * that it can now answer qSymbol::hexcodedname queries, to look up symbols. * * If the qSymbol packet has no address that means GDB did not find the * symbol, in which case auto-detect will move on to try the next RTOS. * * rtos_qsymbol() then calls the next_symbol() helper function, which * iterates over symbol names for the current RTOS until it finds the * symbol in the received GDB packet, and then returns the next entry * in the list of symbols. * * If GDB replied about the last symbol for the RTOS and the RTOS was * specified explicitly, then no further symbol lookup is done. When * auto-detecting, the RTOS driver _detect() function must return success. * * The symbol is tried twice to handle the -flto case with gcc. The first * attempt uses the symbol as-is, and the second attempt tries the symbol * with ".lto_priv.0" appended to it. We only consider the first static * symbol here from the -flto case. (Each subsequent static symbol with * the same name is exported as .lto_priv.1, .lto_priv.2, etc.) * * rtos_qsymbol() returns 1 if an RTOS has been detected, or 0 otherwise. */ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_size) { int rtos_detected = 0; uint64_t addr = 0; size_t reply_len; char reply[GDB_BUFFER_SIZE + 1], cur_sym[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for null-termination */ struct symbol_table_elem *next_sym = NULL; struct target *target = get_target_from_connection(connection); struct rtos *os = target->rtos; reply_len = sprintf(reply, "OK"); if (!os) goto done; /* Decode any symbol name in the packet*/ size_t len = unhexify((uint8_t *)cur_sym, strchr(packet + 8, ':') + 1, strlen(strchr(packet + 8, ':') + 1)); cur_sym[len] = 0; const char no_suffix[] = ""; const char lto_suffix[] = ".lto_priv.0"; const size_t lto_suffix_len = strlen(lto_suffix); const char *cur_suffix; const char *next_suffix; /* Detect what suffix was used during the previous symbol lookup attempt, and * speculatively determine the next suffix (only used for the unknown address case) */ if (len > lto_suffix_len && !strcmp(cur_sym + len - lto_suffix_len, lto_suffix)) { /* Trim the suffix from cur_sym for comparison purposes below */ cur_sym[len - lto_suffix_len] = '\0'; cur_suffix = lto_suffix; next_suffix = NULL; } else { cur_suffix = no_suffix; next_suffix = lto_suffix; } if ((strcmp(packet, "qSymbol::") != 0) && /* GDB is not offering symbol lookup for the first time */ (!sscanf(packet, "qSymbol:%" SCNx64 ":", &addr))) { /* GDB did not find an address for a symbol */ /* GDB could not find an address for the previous symbol */ struct symbol_table_elem *sym = find_symbol(os, cur_sym); if (next_suffix) { next_sym = sym; } else if (sym && !sym->optional) { /* the symbol is mandatory for this RTOS */ if (!target->rtos_auto_detect) { LOG_WARNING("RTOS %s not detected. (GDB could not find symbol \'%s\')", os->type->name, cur_sym); goto done; } else { /* Autodetecting RTOS - try next RTOS */ if (!rtos_try_next(target)) { LOG_WARNING("No RTOS could be auto-detected!"); goto done; } /* Next RTOS selected - invalidate current symbol */ cur_sym[0] = '\x00'; } } } LOG_DEBUG("RTOS: Address of symbol '%s%s' is 0x%" PRIx64, cur_sym, cur_suffix, addr); if (!next_sym) { next_sym = next_symbol(os, cur_sym, addr); next_suffix = no_suffix; } /* Should never happen unless the debugger misbehaves */ if (!next_sym) { LOG_WARNING("RTOS: Debugger sent us qSymbol with '%s%s' that we did not ask for", cur_sym, cur_suffix); goto done; } if (!next_sym->symbol_name) { /* No more symbols need looking up */ if (!target->rtos_auto_detect) { rtos_detected = 1; goto done; } if (os->type->detect_rtos(target)) { LOG_INFO("Auto-detected RTOS: %s", os->type->name); rtos_detected = 1; goto done; } else { LOG_WARNING("No RTOS could be auto-detected!"); goto done; } } assert(next_suffix); reply_len = 8; /* snprintf(..., "qSymbol:") */ reply_len += 2 * strlen(next_sym->symbol_name); /* hexify(..., next_sym->symbol_name, ...) */ reply_len += 2 * strlen(next_suffix); /* hexify(..., next_suffix, ...) */ reply_len += 1; /* Terminating NUL */ if (reply_len > sizeof(reply)) { LOG_ERROR("ERROR: RTOS symbol '%s%s' name is too long for GDB!", next_sym->symbol_name, next_suffix); goto done; } LOG_DEBUG("RTOS: Requesting symbol lookup of '%s%s' from the debugger", next_sym->symbol_name, next_suffix); reply_len = snprintf(reply, sizeof(reply), "qSymbol:"); reply_len += hexify(reply + reply_len, (const uint8_t *)next_sym->symbol_name, strlen(next_sym->symbol_name), sizeof(reply) - reply_len); reply_len += hexify(reply + reply_len, (const uint8_t *)next_suffix, strlen(next_suffix), sizeof(reply) - reply_len); done: gdb_put_packet(connection, reply, reply_len); return rtos_detected; } int rtos_thread_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); if (strncmp(packet, "qThreadExtraInfo,", 17) == 0) { if ((target->rtos) && (target->rtos->thread_details) && (target->rtos->thread_count != 0)) { threadid_t threadid = 0; int found = -1; sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid); if ((target->rtos) && (target->rtos->thread_details)) { int thread_num; for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) { if (target->rtos->thread_details[thread_num].threadid == threadid) { if (target->rtos->thread_details[thread_num].exists) found = thread_num; } } } if (found == -1) { gdb_put_packet(connection, "E01", 3); /* thread not found */ return ERROR_OK; } struct thread_detail *detail = &target->rtos->thread_details[found]; int str_size = 0; if (detail->thread_name_str) str_size += strlen(detail->thread_name_str); if (detail->extra_info_str) str_size += strlen(detail->extra_info_str); char *tmp_str = calloc(str_size + 9, sizeof(char)); char *tmp_str_ptr = tmp_str; if (detail->thread_name_str) tmp_str_ptr += sprintf(tmp_str_ptr, "Name: %s", detail->thread_name_str); if (detail->extra_info_str) { if (tmp_str_ptr != tmp_str) tmp_str_ptr += sprintf(tmp_str_ptr, ", "); tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->extra_info_str); } assert(strlen(tmp_str) == (size_t) (tmp_str_ptr - tmp_str)); char *hex_str = malloc(strlen(tmp_str) * 2 + 1); size_t pkt_len = hexify(hex_str, (const uint8_t *)tmp_str, strlen(tmp_str), strlen(tmp_str) * 2 + 1); gdb_put_packet(connection, hex_str, pkt_len); free(hex_str); free(tmp_str); return ERROR_OK; } gdb_put_packet(connection, "", 0); return ERROR_OK; } else if (strncmp(packet, "qSymbol", 7) == 0) { if (rtos_qsymbol(connection, packet, packet_size) == 1) { if (target->rtos_auto_detect == true) { target->rtos_auto_detect = false; target->rtos->type->create(target); } target->rtos->type->update_threads(target->rtos); } return ERROR_OK; } else if (strncmp(packet, "qfThreadInfo", 12) == 0) { int i; if (target->rtos) { if (target->rtos->thread_count == 0) { gdb_put_packet(connection, "l", 1); } else { /*thread id are 16 char +1 for ',' */ char *out_str = malloc(17 * target->rtos->thread_count + 1); char *tmp_str = out_str; for (i = 0; i < target->rtos->thread_count; i++) { tmp_str += sprintf(tmp_str, "%c%016" PRIx64, i == 0 ? 'm' : ',', target->rtos->thread_details[i].threadid); } gdb_put_packet(connection, out_str, strlen(out_str)); free(out_str); } } else gdb_put_packet(connection, "l", 1); return ERROR_OK; } else if (strncmp(packet, "qsThreadInfo", 12) == 0) { gdb_put_packet(connection, "l", 1); return ERROR_OK; } else if (strncmp(packet, "qAttached", 9) == 0) { gdb_put_packet(connection, "1", 1); return ERROR_OK; } else if (strncmp(packet, "qOffsets", 8) == 0) { char offsets[] = "Text=0;Data=0;Bss=0"; gdb_put_packet(connection, offsets, sizeof(offsets)-1); return ERROR_OK; } else if (strncmp(packet, "qCRC:", 5) == 0) { /* make sure we check this before "qC" packet below * otherwise it gets incorrectly handled */ return GDB_THREAD_PACKET_NOT_CONSUMED; } else if (strncmp(packet, "qC", 2) == 0) { if (target->rtos) { char buffer[19]; int size; size = snprintf(buffer, 19, "QC%016" PRIx64, target->rtos->current_thread); gdb_put_packet(connection, buffer, size); } else gdb_put_packet(connection, "QC0", 3); return ERROR_OK; } else if (packet[0] == 'T') { /* Is thread alive? */ threadid_t threadid; int found = -1; sscanf(packet, "T%" SCNx64, &threadid); if ((target->rtos) && (target->rtos->thread_details)) { int thread_num; for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) { if (target->rtos->thread_details[thread_num].threadid == threadid) { if (target->rtos->thread_details[thread_num].exists) found = thread_num; } } } if (found != -1) gdb_put_packet(connection, "OK", 2); /* thread alive */ else gdb_put_packet(connection, "E01", 3); /* thread not found */ return ERROR_OK; } else if (packet[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for * all other operations ) */ if ((packet[1] == 'g') && (target->rtos)) { threadid_t threadid; sscanf(packet, "Hg%16" SCNx64, &threadid); LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64, threadid); /* threadid of 0 indicates target should choose */ if (threadid == 0) target->rtos->current_threadid = target->rtos->current_thread; else target->rtos->current_threadid = threadid; } gdb_put_packet(connection, "OK", 2); return ERROR_OK; } return GDB_THREAD_PACKET_NOT_CONSUMED; } static int rtos_put_gdb_reg_list(struct connection *connection, struct rtos_reg *reg_list, int num_regs) { size_t num_bytes = 1; /* NUL */ for (int i = 0; i < num_regs; ++i) num_bytes += DIV_ROUND_UP(reg_list[i].size, 8) * 2; char *hex = malloc(num_bytes); char *hex_p = hex; for (int i = 0; i < num_regs; ++i) { size_t count = DIV_ROUND_UP(reg_list[i].size, 8); size_t n = hexify(hex_p, reg_list[i].value, count, num_bytes); hex_p += n; num_bytes -= n; } gdb_put_packet(connection, hex, strlen(hex)); free(hex); return ERROR_OK; } /** Look through all registers to find this register. */ int rtos_get_gdb_reg(struct connection *connection, int reg_num) { struct target *target = get_target_from_connection(connection); int64_t current_threadid = target->rtos->current_threadid; if ((target->rtos) && (current_threadid != -1) && (current_threadid != 0) && ((current_threadid != target->rtos->current_thread) || (target->smp))) { /* in smp several current thread are possible */ struct rtos_reg *reg_list; int num_regs; LOG_DEBUG("getting register %d for thread 0x%" PRIx64 ", target->rtos->current_thread=0x%" PRIx64, reg_num, current_threadid, target->rtos->current_thread); int retval; if (target->rtos->type->get_thread_reg) { reg_list = calloc(1, sizeof(*reg_list)); num_regs = 1; retval = target->rtos->type->get_thread_reg(target->rtos, current_threadid, reg_num, ®_list[0]); if (retval != ERROR_OK) { LOG_ERROR("RTOS: failed to get register %d", reg_num); return retval; } } else { retval = target->rtos->type->get_thread_reg_list(target->rtos, current_threadid, ®_list, &num_regs); if (retval != ERROR_OK) { LOG_ERROR("RTOS: failed to get register list"); return retval; } } for (int i = 0; i < num_regs; ++i) { if (reg_list[i].number == (uint32_t)reg_num) { rtos_put_gdb_reg_list(connection, reg_list + i, 1); free(reg_list); return ERROR_OK; } } free(reg_list); } return ERROR_FAIL; } /** Return a list of general registers. */ int rtos_get_gdb_reg_list(struct connection *connection) { struct target *target = get_target_from_connection(connection); int64_t current_threadid = target->rtos->current_threadid; if ((target->rtos) && (current_threadid != -1) && (current_threadid != 0) && ((current_threadid != target->rtos->current_thread) || (target->smp))) { /* in smp several current thread are possible */ struct rtos_reg *reg_list; int num_regs; LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64 ", target->rtos->current_thread=0x%" PRIx64 "\r\n", current_threadid, target->rtos->current_thread); int retval = target->rtos->type->get_thread_reg_list(target->rtos, current_threadid, ®_list, &num_regs); if (retval != ERROR_OK) { LOG_ERROR("RTOS: failed to get register list"); return retval; } rtos_put_gdb_reg_list(connection, reg_list, num_regs); free(reg_list); return ERROR_OK; } return ERROR_FAIL; } int rtos_set_reg(struct connection *connection, int reg_num, uint8_t *reg_value) { struct target *target = get_target_from_connection(connection); int64_t current_threadid = target->rtos->current_threadid; if ((target->rtos) && (target->rtos->type->set_reg) && (current_threadid != -1) && (current_threadid != 0)) { return target->rtos->type->set_reg(target->rtos, reg_num, reg_value); } return ERROR_FAIL; } int rtos_generic_stack_read(struct target *target, const struct rtos_register_stacking *stacking, int64_t stack_ptr, struct rtos_reg **reg_list, int *num_regs) { int retval; if (stack_ptr == 0) { LOG_ERROR("Error: null stack pointer in thread"); return -5; } /* Read the stack */ uint8_t *stack_data = malloc(stacking->stack_registers_size); uint32_t address = stack_ptr; if (stacking->stack_growth_direction == 1) address -= stacking->stack_registers_size; if (stacking->read_stack) retval = stacking->read_stack(target, address, stacking, stack_data); else retval = target_read_buffer(target, address, stacking->stack_registers_size, stack_data); if (retval != ERROR_OK) { free(stack_data); LOG_ERROR("Error reading stack frame from thread"); return retval; } LOG_DEBUG("RTOS: Read stack frame at 0x%" PRIx32, address); #if 0 LOG_OUTPUT("Stack Data :"); for (i = 0; i < stacking->stack_registers_size; i++) LOG_OUTPUT("%02X", stack_data[i]); LOG_OUTPUT("\r\n"); #endif target_addr_t new_stack_ptr; if (stacking->calculate_process_stack) { new_stack_ptr = stacking->calculate_process_stack(target, stack_data, stacking, stack_ptr); } else { new_stack_ptr = stack_ptr - stacking->stack_growth_direction * stacking->stack_registers_size; } *reg_list = calloc(stacking->num_output_registers, sizeof(struct rtos_reg)); *num_regs = stacking->num_output_registers; for (int i = 0; i < stacking->num_output_registers; ++i) { (*reg_list)[i].number = stacking->register_offsets[i].number; (*reg_list)[i].size = stacking->register_offsets[i].width_bits; int offset = stacking->register_offsets[i].offset; if (offset == -2) buf_cpy(&new_stack_ptr, (*reg_list)[i].value, (*reg_list)[i].size); else if (offset != -1) buf_cpy(stack_data + offset, (*reg_list)[i].value, (*reg_list)[i].size); } free(stack_data); /* LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */ return ERROR_OK; } static int rtos_try_next(struct target *target) { struct rtos *os = target->rtos; const struct rtos_type **type = rtos_types; if (!os) return 0; while (*type && os->type != *type) type++; if (!*type || !*(++type)) return 0; os->type = *type; free(os->symbols); os->symbols = NULL; return 1; } int rtos_update_threads(struct target *target) { if ((target->rtos) && (target->rtos->type)) target->rtos->type->update_threads(target->rtos); return ERROR_OK; } void rtos_free_threadlist(struct rtos *rtos) { if (rtos->thread_details) { int j; for (j = 0; j < rtos->thread_count; j++) { struct thread_detail *current_thread = &rtos->thread_details[j]; free(current_thread->thread_name_str); free(current_thread->extra_info_str); } free(rtos->thread_details); rtos->thread_details = NULL; rtos->thread_count = 0; rtos->current_threadid = -1; rtos->current_thread = 0; } } int rtos_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { if (target->rtos->type->read_buffer) return target->rtos->type->read_buffer(target->rtos, address, size, buffer); return ERROR_NOT_IMPLEMENTED; } int rtos_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer) { if (target->rtos->type->write_buffer) return target->rtos->type->write_buffer(target->rtos, address, size, buffer); return ERROR_NOT_IMPLEMENTED; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * ***************************************************************************/ #ifndef OPENOCD_RTOS_RTOS_H #define OPENOCD_RTOS_RTOS_H #include "server/server.h" #include "target/target.h" #include <helper/jim-nvp.h> typedef int64_t threadid_t; typedef int64_t symbol_address_t; struct reg; /** * Table should be terminated by an element with NULL in symbol_name */ struct symbol_table_elem { const char *symbol_name; symbol_address_t address; bool optional; }; struct thread_detail { threadid_t threadid; bool exists; char *thread_name_str; char *extra_info_str; }; struct rtos { const struct rtos_type *type; struct symbol_table_elem *symbols; struct target *target; /* add a context variable instead of global variable */ /* The thread currently selected by gdb. */ int64_t current_threadid; /* The currently selected thread according to the target. */ threadid_t current_thread; struct thread_detail *thread_details; int thread_count; int (*gdb_thread_packet)(struct connection *connection, char const *packet, int packet_size); int (*gdb_target_for_threadid)(struct connection *connection, int64_t thread_id, struct target **p_target); void *rtos_specific_params; }; struct rtos_reg { uint32_t number; uint32_t size; uint8_t value[16]; }; struct rtos_type { const char *name; bool (*detect_rtos)(struct target *target); int (*create)(struct target *target); int (*smp_init)(struct target *target); int (*update_threads)(struct rtos *rtos); /** Return a list of general registers, with their values filled out. */ int (*get_thread_reg_list)(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); int (*get_thread_reg)(struct rtos *rtos, int64_t thread_id, uint32_t reg_num, struct rtos_reg *reg); int (*get_symbol_list_to_lookup)(struct symbol_table_elem *symbol_list[]); int (*clean)(struct target *target); char * (*ps_command)(struct target *target); int (*set_reg)(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); /* Implement these if different threads in the RTOS can see memory * differently (for instance because address translation might be different * for each thread). */ int (*read_buffer)(struct rtos *rtos, target_addr_t address, uint32_t size, uint8_t *buffer); int (*write_buffer)(struct rtos *rtos, target_addr_t address, uint32_t size, const uint8_t *buffer); }; struct stack_register_offset { unsigned short number; /* register number */ signed short offset; /* offset in bytes from stack head, or -1 to indicate * register is not stacked, or -2 to indicate this is the * stack pointer register */ unsigned short width_bits; }; struct rtos_register_stacking { unsigned char stack_registers_size; signed char stack_growth_direction; unsigned char num_output_registers; /* Some targets require evaluating the stack to determine the * actual stack pointer for a process. If this field is NULL, * just use stacking->stack_registers_size * stack_growth_direction * to calculate adjustment. */ target_addr_t (*calculate_process_stack)(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, target_addr_t stack_ptr); const struct stack_register_offset *register_offsets; /* Optional field for targets which may have to implement their own stack read function. * Because stack format can be weird or stack data needed to be edited before passing to the gdb. */ int (*read_stack)(struct target *target, int64_t stack_ptr, const struct rtos_register_stacking *stacking, uint8_t *stack_data); }; #define GDB_THREAD_PACKET_NOT_CONSUMED (-40) int rtos_create(struct jim_getopt_info *goi, struct target *target); void rtos_destroy(struct target *target); int rtos_set_reg(struct connection *connection, int reg_num, uint8_t *reg_value); int rtos_generic_stack_read(struct target *target, const struct rtos_register_stacking *stacking, int64_t stack_ptr, struct rtos_reg **reg_list, int *num_regs); int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size); int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size); int rtos_get_gdb_reg(struct connection *connection, int reg_num); int rtos_get_gdb_reg_list(struct connection *connection); int rtos_update_threads(struct target *target); void rtos_free_threadlist(struct rtos *rtos); int rtos_smp_init(struct target *target); /* function for handling symbol access */ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_size); int rtos_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer); int rtos_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer); extern const struct rtos_type chibios_rtos; extern const struct rtos_type chromium_ec_rtos; extern const struct rtos_type ecos_rtos; extern const struct rtos_type embkernel_rtos; extern const struct rtos_type freertos_rtos; extern const struct rtos_type hwthread_rtos; extern const struct rtos_type linux_rtos; extern const struct rtos_type mqx_rtos; extern const struct rtos_type nuttx_rtos; extern const struct rtos_type riot_rtos; extern const struct rtos_type rtkernel_rtos; extern const struct rtos_type threadx_rtos; extern const struct rtos_type ucos_iii_rtos; extern const struct rtos_type zephyr_rtos; #endif /* OPENOCD_RTOS_RTOS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_chibios_stackings.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2012 by Matthias Blaicher * * Matthias Blaicher - matthias@blaicher.com * * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" #include "target/armv7m.h" #include "rtos_chibios_stackings.h" static const struct stack_register_offset rtos_chibios_arm_v7m_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, -1, 32 }, /* r0 */ { ARMV7M_R1, -1, 32 }, /* r1 */ { ARMV7M_R2, -1, 32 }, /* r2 */ { ARMV7M_R3, -1, 32 }, /* r3 */ { ARMV7M_R4, 0x00, 32 }, /* r4 */ { ARMV7M_R5, 0x04, 32 }, /* r5 */ { ARMV7M_R6, 0x08, 32 }, /* r6 */ { ARMV7M_R7, 0x0c, 32 }, /* r7 */ { ARMV7M_R8, 0x10, 32 }, /* r8 */ { ARMV7M_R9, 0x14, 32 }, /* r9 */ { ARMV7M_R10, 0x18, 32 }, /* r10 */ { ARMV7M_R11, 0x1c, 32 }, /* r11 */ { ARMV7M_R12, -1, 32 }, /* r12 */ { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, -1, 32 }, /* lr */ { ARMV7M_PC, 0x20, 32 }, /* pc */ { ARMV7M_XPSR, -1, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking = { .stack_registers_size = 0x24, .stack_growth_direction = -1, .num_output_registers = ARMV7M_NUM_CORE_REGS, .register_offsets = rtos_chibios_arm_v7m_stack_offsets }; static const struct stack_register_offset rtos_chibios_arm_v7m_stack_offsets_w_fpu[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, -1, 32 }, /* r0 */ { ARMV7M_R1, -1, 32 }, /* r1 */ { ARMV7M_R2, -1, 32 }, /* r2 */ { ARMV7M_R3, -1, 32 }, /* r3 */ { ARMV7M_R4, 0x40, 32 }, /* r4 */ { ARMV7M_R5, 0x44, 32 }, /* r5 */ { ARMV7M_R6, 0x48, 32 }, /* r6 */ { ARMV7M_R7, 0x4c, 32 }, /* r7 */ { ARMV7M_R8, 0x50, 32 }, /* r8 */ { ARMV7M_R9, 0x54, 32 }, /* r9 */ { ARMV7M_R10, 0x58, 32 }, /* r10 */ { ARMV7M_R11, 0x5c, 32 }, /* r11 */ { ARMV7M_R12, -1, 32 }, /* r12 */ { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, -1, 32 }, /* lr */ { ARMV7M_PC, 0x60, 32 }, /* pc */ { ARMV7M_XPSR, -1, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking_w_fpu = { .stack_registers_size = 0x64, .stack_growth_direction = -1, .num_output_registers = ARMV7M_NUM_CORE_REGS, .register_offsets = rtos_chibios_arm_v7m_stack_offsets_w_fpu }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_chibios_stackings.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * ***************************************************************************/ #ifndef OPENOCD_RTOS_RTOS_CHIBIOS_STACKINGS_H #define OPENOCD_RTOS_RTOS_CHIBIOS_STACKINGS_H #include "rtos.h" extern const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking; extern const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking_w_fpu; #endif /* OPENOCD_RTOS_RTOS_CHIBIOS_STACKINGS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_ecos_stackings.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" #include "target/armv7m.h" #include "rtos_standard_stackings.h" #include "rtos_ecos_stackings.h" /* For Cortex-M eCos applications the actual thread context register layout can * be different between active threads of an application depending on whether * the FPU is in use, configured for lazy FPU context saving, etc. */ /* Default fixed thread register context description used for older eCos * application builds without the necessary symbolic information describing the * actual configuration-dependent offsets. */ static const struct stack_register_offset rtos_ecos_cortex_m3_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, 0x0c, 32 }, /* r0 */ { ARMV7M_R1, 0x10, 32 }, /* r1 */ { ARMV7M_R2, 0x14, 32 }, /* r2 */ { ARMV7M_R3, 0x18, 32 }, /* r3 */ { ARMV7M_R4, 0x1c, 32 }, /* r4 */ { ARMV7M_R5, 0x20, 32 }, /* r5 */ { ARMV7M_R6, 0x24, 32 }, /* r6 */ { ARMV7M_R7, 0x28, 32 }, /* r7 */ { ARMV7M_R8, 0x2c, 32 }, /* r8 */ { ARMV7M_R9, 0x30, 32 }, /* r9 */ { ARMV7M_R10, 0x34, 32 }, /* r10 */ { ARMV7M_R11, 0x38, 32 }, /* r11 */ { ARMV7M_R12, 0x3c, 32 }, /* r12 */ { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, -1, 32 }, /* lr */ { ARMV7M_PC, 0x40, 32 }, /* pc */ { ARMV7M_XPSR, -1, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_ecos_cortex_m3_stacking = { .stack_registers_size = 0x44, .stack_growth_direction = -1, .num_output_registers = ARMV7M_NUM_CORE_REGS, .calculate_process_stack = rtos_generic_stack_align8, .register_offsets = rtos_ecos_cortex_m3_stack_offsets }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_ecos_stackings.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef OPENOCD_RTOS_RTOS_ECOS_STACKINGS_H #define OPENOCD_RTOS_RTOS_ECOS_STACKINGS_H #include "rtos.h" extern const struct rtos_register_stacking rtos_ecos_cortex_m3_stacking; #endif /* OPENOCD_RTOS_RTOS_ECOS_STACKINGS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_embkernel_stackings.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" #include "target/armv7m.h" #include "rtos_standard_stackings.h" #include "rtos_embkernel_stackings.h" static const struct stack_register_offset rtos_embkernel_cortex_m_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, 0x24, 32 }, /* r0 */ { ARMV7M_R1, 0x28, 32 }, /* r1 */ { ARMV7M_R2, 0x2c, 32 }, /* r2 */ { ARMV7M_R3, 0x30, 32 }, /* r3 */ { ARMV7M_R4, 0x00, 32 }, /* r4 */ { ARMV7M_R5, 0x04, 32 }, /* r5 */ { ARMV7M_R6, 0x08, 32 }, /* r6 */ { ARMV7M_R7, 0x0c, 32 }, /* r7 */ { ARMV7M_R8, 0x10, 32 }, /* r8 */ { ARMV7M_R9, 0x14, 32 }, /* r9 */ { ARMV7M_R10, 0x18, 32 }, /* r10 */ { ARMV7M_R11, 0x1c, 32 }, /* r11 */ { ARMV7M_R12, 0x34, 32 }, /* r12 */ { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x38, 32 }, /* lr */ { ARMV7M_PC, 0x3c, 32 }, /* pc */ { ARMV7M_XPSR, 0x40, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_embkernel_cortex_m_stacking = { .stack_registers_size = 0x40, .stack_growth_direction = -1, .num_output_registers = ARMV7M_NUM_CORE_REGS, .calculate_process_stack = rtos_generic_stack_align8, .register_offsets = rtos_embkernel_cortex_m_stack_offsets }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_embkernel_stackings.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * ***************************************************************************/ #ifndef OPENOCD_RTOS_RTOS_EMBKERNEL_STACKINGS_H #define OPENOCD_RTOS_RTOS_EMBKERNEL_STACKINGS_H #include "rtos.h" extern const struct rtos_register_stacking rtos_embkernel_cortex_m_stacking; #endif /* OPENOCD_RTOS_RTOS_EMBKERNEL_STACKINGS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_mqx_stackings.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2014 by Marian Cingel * * cingel.marian@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" #include "target/armv7m.h" #include "rtos_mqx_stackings.h" /* * standard exception stack * ( stack base, higher memory address ) * - xpsr - 0x48 * - pc - 0x44 * - lr - 0x40 * - r12 - 0x3C * - r3 - 0x38 * - r2 - 0x34 * - r1 - 0x30 * - r0 - 0x2C * extended stack in svc_pending handler * - lr - 0x28 * - r11 - 0x24 * - r10 - 0x20 * - r9 - 0x1C * - r8 - 0x18 * - r7 - 0x14 * - r6 - 0x10 * - r5 - 0x0C * - r4 - 0x08 * - BASEPRI - 0x04 * - SHPR3 - 0x00 ( contains pend_svc exception priority ) * ( stack head, lower address, stored in 'task->STACK_PTR' ) */ static const struct stack_register_offset rtos_mqx_arm_v7m_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, 0x2C, 32 }, /* r0 */ { ARMV7M_R1, 0x30, 32 }, /* r1 */ { ARMV7M_R2, 0x34, 32 }, /* r2 */ { ARMV7M_R3, 0x38, 32 }, /* r3 */ { ARMV7M_R4, 0x08, 32 }, /* r4 */ { ARMV7M_R5, 0x0C, 32 }, /* r5 */ { ARMV7M_R6, 0x10, 32 }, /* r6 */ { ARMV7M_R7, 0x14, 32 }, /* r7 */ { ARMV7M_R8, 0x18, 32 }, /* r8 */ { ARMV7M_R9, 0x1C, 32 }, /* r9 */ { ARMV7M_R10, 0x20, 32 }, /* r10 */ { ARMV7M_R11, 0x24, 32 }, /* r11 */ { ARMV7M_R12, 0x3C, 32 }, /* r12 */ { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x28, 32 }, /* lr */ { ARMV7M_PC, 0x44, 32 }, /* pc */ { ARMV7M_XPSR, 0x48, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_mqx_arm_v7m_stacking = { .stack_registers_size = 0x4C, /* calculate offset base address */ .stack_growth_direction = -1, .num_output_registers = ARMV7M_NUM_CORE_REGS, .register_offsets = rtos_mqx_arm_v7m_stack_offsets }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_mqx_stackings.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2014 by Marian Cingel * * cingel.marian@gmail.com * ***************************************************************************/ #ifndef OPENOCD_RTOS_RTOS_MQX_STACKINGS_H #define OPENOCD_RTOS_RTOS_MQX_STACKINGS_H #include "rtos.h" extern const struct rtos_register_stacking rtos_mqx_arm_v7m_stacking; #endif /* OPENOCD_RTOS_RTOS_MQX_STACKINGS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_nuttx_stackings.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" #include "target/armv7m.h" #include "rtos_nuttx_stackings.h" #include "rtos_standard_stackings.h" #include <target/riscv/riscv.h> /* see arch/arm/include/armv7-m/irq_cmnvector.h */ static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = { { ARMV7M_R0, 0x28, 32 }, /* r0 */ { ARMV7M_R1, 0x2c, 32 }, /* r1 */ { ARMV7M_R2, 0x30, 32 }, /* r2 */ { ARMV7M_R3, 0x34, 32 }, /* r3 */ { ARMV7M_R4, 0x08, 32 }, /* r4 */ { ARMV7M_R5, 0x0c, 32 }, /* r5 */ { ARMV7M_R6, 0x10, 32 }, /* r6 */ { ARMV7M_R7, 0x14, 32 }, /* r7 */ { ARMV7M_R8, 0x18, 32 }, /* r8 */ { ARMV7M_R9, 0x1c, 32 }, /* r9 */ { ARMV7M_R10, 0x20, 32 }, /* r10 */ { ARMV7M_R11, 0x24, 32 }, /* r11 */ { ARMV7M_R12, 0x38, 32 }, /* r12 */ { ARMV7M_R13, 0, 32 }, /* sp */ { ARMV7M_R14, 0x3c, 32 }, /* lr */ { ARMV7M_PC, 0x40, 32 }, /* pc */ { ARMV7M_XPSR, 0x44, 32 }, /* xPSR */ }; const struct rtos_register_stacking nuttx_stacking_cortex_m = { .stack_registers_size = 0x48, .stack_growth_direction = -1, .num_output_registers = 17, .register_offsets = nuttx_stack_offsets_cortex_m, }; static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = { { ARMV7M_R0, 0x6c, 32 }, /* r0 */ { ARMV7M_R1, 0x70, 32 }, /* r1 */ { ARMV7M_R2, 0x74, 32 }, /* r2 */ { ARMV7M_R3, 0x78, 32 }, /* r3 */ { ARMV7M_R4, 0x08, 32 }, /* r4 */ { ARMV7M_R5, 0x0c, 32 }, /* r5 */ { ARMV7M_R6, 0x10, 32 }, /* r6 */ { ARMV7M_R7, 0x14, 32 }, /* r7 */ { ARMV7M_R8, 0x18, 32 }, /* r8 */ { ARMV7M_R9, 0x1c, 32 }, /* r9 */ { ARMV7M_R10, 0x20, 32 }, /* r10 */ { ARMV7M_R11, 0x24, 32 }, /* r11 */ { ARMV7M_R12, 0x7c, 32 }, /* r12 */ { ARMV7M_R13, 0, 32 }, /* sp */ { ARMV7M_R14, 0x80, 32 }, /* lr */ { ARMV7M_PC, 0x84, 32 }, /* pc */ { ARMV7M_XPSR, 0x88, 32 }, /* xPSR */ }; const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = { .stack_registers_size = 0x8c, .stack_growth_direction = -1, .num_output_registers = 17, .register_offsets = nuttx_stack_offsets_cortex_m_fpu, }; static const struct stack_register_offset nuttx_stack_offsets_riscv[] = { { GDB_REGNO_ZERO, -1, 32 }, { GDB_REGNO_RA, 0x04, 32 }, { GDB_REGNO_SP, 0x08, 32 }, { GDB_REGNO_GP, 0x0c, 32 }, { GDB_REGNO_TP, 0x10, 32 }, { GDB_REGNO_T0, 0x14, 32 }, { GDB_REGNO_T1, 0x18, 32 }, { GDB_REGNO_T2, 0x1c, 32 }, { GDB_REGNO_FP, 0x20, 32 }, { GDB_REGNO_S1, 0x24, 32 }, { GDB_REGNO_A0, 0x28, 32 }, { GDB_REGNO_A1, 0x2c, 32 }, { GDB_REGNO_A2, 0x30, 32 }, { GDB_REGNO_A3, 0x34, 32 }, { GDB_REGNO_A4, 0x38, 32 }, { GDB_REGNO_A5, 0x3c, 32 }, { GDB_REGNO_A6, 0x40, 32 }, { GDB_REGNO_A7, 0x44, 32 }, { GDB_REGNO_S2, 0x48, 32 }, { GDB_REGNO_S3, 0x4c, 32 }, { GDB_REGNO_S4, 0x50, 32 }, { GDB_REGNO_S5, 0x54, 32 }, { GDB_REGNO_S6, 0x58, 32 }, { GDB_REGNO_S7, 0x5c, 32 }, { GDB_REGNO_S8, 0x60, 32 }, { GDB_REGNO_S9, 0x64, 32 }, { GDB_REGNO_S10, 0x68, 32 }, { GDB_REGNO_S11, 0x6c, 32 }, { GDB_REGNO_T3, 0x70, 32 }, { GDB_REGNO_T4, 0x74, 32 }, { GDB_REGNO_T5, 0x78, 32 }, { GDB_REGNO_T6, 0x7c, 32 }, { GDB_REGNO_PC, 0x00, 32 }, }; const struct rtos_register_stacking nuttx_riscv_stacking = { .stack_registers_size = 33 * 4, .stack_growth_direction = -1, .num_output_registers = 33, .calculate_process_stack = rtos_generic_stack_align8, .register_offsets = nuttx_stack_offsets_riscv, }; static int nuttx_esp_xtensa_stack_read(struct target *target, int64_t stack_ptr, const struct rtos_register_stacking *stacking, uint8_t *stack_data) { int retval = target_read_buffer(target, stack_ptr, stacking->stack_registers_size, stack_data); if (retval != ERROR_OK) return retval; stack_data[4] &= ~0x10; /* Clear exception bit in PS */ return ERROR_OK; } static const struct stack_register_offset nuttx_stack_offsets_esp32[] = { { 0, 0x00, 32 }, /* PC */ { 1, 0x08, 32 }, /* A0 */ { 2, 0x0c, 32 }, /* A1 */ { 3, 0x10, 32 }, /* A2 */ { 4, 0x14, 32 }, /* A3 */ { 5, 0x18, 32 }, /* A4 */ { 6, 0x1c, 32 }, /* A5 */ { 7, 0x20, 32 }, /* A6 */ { 8, 0x24, 32 }, /* A7 */ { 9, 0x28, 32 }, /* A8 */ { 10, 0x2c, 32 }, /* A9 */ { 11, 0x30, 32 }, /* A10 */ { 12, 0x34, 32 }, /* A11 */ { 13, 0x38, 32 }, /* A12 */ { 14, 0x3c, 32 }, /* A13 */ { 15, 0x40, 32 }, /* A14 */ { 16, 0x44, 32 }, /* A15 */ /* A16-A63 aren't in the stack frame because they've been flushed to the stack earlier */ { 17, -1, 32 }, /* A16 */ { 18, -1, 32 }, /* A17 */ { 19, -1, 32 }, /* A18 */ { 20, -1, 32 }, /* A19 */ { 21, -1, 32 }, /* A20 */ { 22, -1, 32 }, /* A21 */ { 23, -1, 32 }, /* A22 */ { 24, -1, 32 }, /* A23 */ { 25, -1, 32 }, /* A24 */ { 26, -1, 32 }, /* A25 */ { 27, -1, 32 }, /* A26 */ { 28, -1, 32 }, /* A27 */ { 29, -1, 32 }, /* A28 */ { 30, -1, 32 }, /* A29 */ { 31, -1, 32 }, /* A30 */ { 32, -1, 32 }, /* A31 */ { 33, -1, 32 }, /* A32 */ { 34, -1, 32 }, /* A33 */ { 35, -1, 32 }, /* A34 */ { 36, -1, 32 }, /* A35 */ { 37, -1, 32 }, /* A36 */ { 38, -1, 32 }, /* A37 */ { 39, -1, 32 }, /* A38 */ { 40, -1, 32 }, /* A39 */ { 41, -1, 32 }, /* A40 */ { 42, -1, 32 }, /* A41 */ { 43, -1, 32 }, /* A42 */ { 44, -1, 32 }, /* A43 */ { 45, -1, 32 }, /* A44 */ { 46, -1, 32 }, /* A45 */ { 47, -1, 32 }, /* A46 */ { 48, -1, 32 }, /* A47 */ { 49, -1, 32 }, /* A48 */ { 50, -1, 32 }, /* A49 */ { 51, -1, 32 }, /* A50 */ { 52, -1, 32 }, /* A51 */ { 53, -1, 32 }, /* A52 */ { 54, -1, 32 }, /* A53 */ { 55, -1, 32 }, /* A54 */ { 56, -1, 32 }, /* A55 */ { 57, -1, 32 }, /* A56 */ { 58, -1, 32 }, /* A57 */ { 59, -1, 32 }, /* A58 */ { 60, -1, 32 }, /* A59 */ { 61, -1, 32 }, /* A60 */ { 62, -1, 32 }, /* A61 */ { 63, -1, 32 }, /* A62 */ { 64, -1, 32 }, /* A63 */ { 65, 0x58, 32 }, /* lbeg */ { 66, 0x5c, 32 }, /* lend */ { 67, 0x60, 32 }, /* lcount */ { 68, 0x48, 32 }, /* SAR */ { 69, -1, 32 }, /* windowbase */ { 70, -1, 32 }, /* windowstart */ { 71, -1, 32 }, /* configid0 */ { 72, -1, 32 }, /* configid1 */ { 73, 0x04, 32 }, /* PS */ { 74, -1, 32 }, /* threadptr */ { 75, -1, 32 }, /* br */ { 76, 0x54, 32 }, /* scompare1 */ { 77, -1, 32 }, /* acclo */ { 78, -1, 32 }, /* acchi */ { 79, -1, 32 }, /* m0 */ { 80, -1, 32 }, /* m1 */ { 81, -1, 32 }, /* m2 */ { 82, -1, 32 }, /* m3 */ { 83, -1, 32 }, /* expstate */ { 84, -1, 32 }, /* f64r_lo */ { 85, -1, 32 }, /* f64r_hi */ { 86, -1, 32 }, /* f64s */ { 87, -1, 32 }, /* f0 */ { 88, -1, 32 }, /* f1 */ { 89, -1, 32 }, /* f2 */ { 90, -1, 32 }, /* f3 */ { 91, -1, 32 }, /* f4 */ { 92, -1, 32 }, /* f5 */ { 93, -1, 32 }, /* f6 */ { 94, -1, 32 }, /* f7 */ { 95, -1, 32 }, /* f8 */ { 96, -1, 32 }, /* f9 */ { 97, -1, 32 }, /* f10 */ { 98, -1, 32 }, /* f11 */ { 99, -1, 32 }, /* f12 */ { 100, -1, 32 }, /* f13 */ { 101, -1, 32 }, /* f14 */ { 102, -1, 32 }, /* f15 */ { 103, -1, 32 }, /* fcr */ { 104, -1, 32 }, /* fsr */ }; const struct rtos_register_stacking nuttx_esp32_stacking = { .stack_registers_size = 26 * 4, .stack_growth_direction = -1, .num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_esp32), .calculate_process_stack = rtos_generic_stack_align8, .register_offsets = nuttx_stack_offsets_esp32, .read_stack = nuttx_esp_xtensa_stack_read, }; static const struct stack_register_offset nuttx_stack_offsets_esp32s2[] = { { 0, 0x00, 32 }, /* PC */ { 1, 0x08, 32 }, /* A0 */ { 2, 0x0c, 32 }, /* A1 */ { 3, 0x10, 32 }, /* A2 */ { 4, 0x14, 32 }, /* A3 */ { 5, 0x18, 32 }, /* A4 */ { 6, 0x1c, 32 }, /* A5 */ { 7, 0x20, 32 }, /* A6 */ { 8, 0x24, 32 }, /* A7 */ { 9, 0x28, 32 }, /* A8 */ { 10, 0x2c, 32 }, /* A9 */ { 11, 0x30, 32 }, /* A10 */ { 12, 0x34, 32 }, /* A11 */ { 13, 0x38, 32 }, /* A12 */ { 14, 0x3c, 32 }, /* A13 */ { 15, 0x40, 32 }, /* A14 */ { 16, 0x44, 32 }, /* A15 */ /* A16-A63 aren't in the stack frame because they've been flushed to the stack earlier */ { 17, -1, 32 }, /* A16 */ { 18, -1, 32 }, /* A17 */ { 19, -1, 32 }, /* A18 */ { 20, -1, 32 }, /* A19 */ { 21, -1, 32 }, /* A20 */ { 22, -1, 32 }, /* A21 */ { 23, -1, 32 }, /* A22 */ { 24, -1, 32 }, /* A23 */ { 25, -1, 32 }, /* A24 */ { 26, -1, 32 }, /* A25 */ { 27, -1, 32 }, /* A26 */ { 28, -1, 32 }, /* A27 */ { 29, -1, 32 }, /* A28 */ { 30, -1, 32 }, /* A29 */ { 31, -1, 32 }, /* A30 */ { 32, -1, 32 }, /* A31 */ { 33, -1, 32 }, /* A32 */ { 34, -1, 32 }, /* A33 */ { 35, -1, 32 }, /* A34 */ { 36, -1, 32 }, /* A35 */ { 37, -1, 32 }, /* A36 */ { 38, -1, 32 }, /* A37 */ { 39, -1, 32 }, /* A38 */ { 40, -1, 32 }, /* A39 */ { 41, -1, 32 }, /* A40 */ { 42, -1, 32 }, /* A41 */ { 43, -1, 32 }, /* A42 */ { 44, -1, 32 }, /* A43 */ { 45, -1, 32 }, /* A44 */ { 46, -1, 32 }, /* A45 */ { 47, -1, 32 }, /* A46 */ { 48, -1, 32 }, /* A47 */ { 49, -1, 32 }, /* A48 */ { 50, -1, 32 }, /* A49 */ { 51, -1, 32 }, /* A50 */ { 52, -1, 32 }, /* A51 */ { 53, -1, 32 }, /* A52 */ { 54, -1, 32 }, /* A53 */ { 55, -1, 32 }, /* A54 */ { 56, -1, 32 }, /* A55 */ { 57, -1, 32 }, /* A56 */ { 58, -1, 32 }, /* A57 */ { 59, -1, 32 }, /* A58 */ { 60, -1, 32 }, /* A59 */ { 61, -1, 32 }, /* A60 */ { 62, -1, 32 }, /* A61 */ { 63, -1, 32 }, /* A62 */ { 64, -1, 32 }, /* A63 */ { 65, 0x48, 32 }, /* SAR */ { 66, -1, 32 }, /* windowbase */ { 67, -1, 32 }, /* windowstart */ { 68, -1, 32 }, /* configid0 */ { 69, -1, 32 }, /* configid1 */ { 70, 0x04, 32 }, /* PS */ { 71, -1, 32 }, /* threadptr */ { 72, -1, 32 }, /* gpio_out */ }; const struct rtos_register_stacking nuttx_esp32s2_stacking = { .stack_registers_size = 25 * 4, .stack_growth_direction = -1, .num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_esp32s2), .calculate_process_stack = rtos_generic_stack_align8, .register_offsets = nuttx_stack_offsets_esp32s2, .read_stack = nuttx_esp_xtensa_stack_read, }; static const struct stack_register_offset nuttx_stack_offsets_esp32s3[] = { { 0, 0x00, 32 }, /* PC */ { 1, 0x08, 32 }, /* A0 */ { 2, 0x0c, 32 }, /* A1 */ { 3, 0x10, 32 }, /* A2 */ { 4, 0x14, 32 }, /* A3 */ { 5, 0x18, 32 }, /* A4 */ { 6, 0x1c, 32 }, /* A5 */ { 7, 0x20, 32 }, /* A6 */ { 8, 0x24, 32 }, /* A7 */ { 9, 0x28, 32 }, /* A8 */ { 10, 0x2c, 32 }, /* A9 */ { 11, 0x30, 32 }, /* A10 */ { 12, 0x34, 32 }, /* A11 */ { 13, 0x38, 32 }, /* A12 */ { 14, 0x3c, 32 }, /* A13 */ { 15, 0x40, 32 }, /* A14 */ { 16, 0x44, 32 }, /* A15 */ /* A16-A63 aren't in the stack frame because they've been flushed to the stack earlier */ { 17, -1, 32 }, /* A16 */ { 18, -1, 32 }, /* A17 */ { 19, -1, 32 }, /* A18 */ { 20, -1, 32 }, /* A19 */ { 21, -1, 32 }, /* A20 */ { 22, -1, 32 }, /* A21 */ { 23, -1, 32 }, /* A22 */ { 24, -1, 32 }, /* A23 */ { 25, -1, 32 }, /* A24 */ { 26, -1, 32 }, /* A25 */ { 27, -1, 32 }, /* A26 */ { 28, -1, 32 }, /* A27 */ { 29, -1, 32 }, /* A28 */ { 30, -1, 32 }, /* A29 */ { 31, -1, 32 }, /* A30 */ { 32, -1, 32 }, /* A31 */ { 33, -1, 32 }, /* A32 */ { 34, -1, 32 }, /* A33 */ { 35, -1, 32 }, /* A34 */ { 36, -1, 32 }, /* A35 */ { 37, -1, 32 }, /* A36 */ { 38, -1, 32 }, /* A37 */ { 39, -1, 32 }, /* A38 */ { 40, -1, 32 }, /* A39 */ { 41, -1, 32 }, /* A40 */ { 42, -1, 32 }, /* A41 */ { 43, -1, 32 }, /* A42 */ { 44, -1, 32 }, /* A43 */ { 45, -1, 32 }, /* A44 */ { 46, -1, 32 }, /* A45 */ { 47, -1, 32 }, /* A46 */ { 48, -1, 32 }, /* A47 */ { 49, -1, 32 }, /* A48 */ { 50, -1, 32 }, /* A49 */ { 51, -1, 32 }, /* A50 */ { 52, -1, 32 }, /* A51 */ { 53, -1, 32 }, /* A52 */ { 54, -1, 32 }, /* A53 */ { 55, -1, 32 }, /* A54 */ { 56, -1, 32 }, /* A55 */ { 57, -1, 32 }, /* A56 */ { 58, -1, 32 }, /* A57 */ { 59, -1, 32 }, /* A58 */ { 60, -1, 32 }, /* A59 */ { 61, -1, 32 }, /* A60 */ { 62, -1, 32 }, /* A61 */ { 63, -1, 32 }, /* A62 */ { 64, -1, 32 }, /* A63 */ { 65, 0x58, 32 }, /* lbeg */ { 66, 0x5c, 32 }, /* lend */ { 67, 0x60, 32 }, /* lcount */ { 68, 0x48, 32 }, /* SAR */ { 69, -1, 32 }, /* windowbase */ { 70, -1, 32 }, /* windowstart */ { 71, -1, 32 }, /* configid0 */ { 72, -1, 32 }, /* configid1 */ { 73, 0x04, 32 }, /* PS */ { 74, -1, 32 }, /* threadptr */ { 75, -1, 32 }, /* br */ { 76, 0x54, 32 }, /* scompare1 */ { 77, -1, 32 }, /* acclo */ { 78, -1, 32 }, /* acchi */ { 79, -1, 32 }, /* m0 */ { 80, -1, 32 }, /* m1 */ { 81, -1, 32 }, /* m2 */ { 82, -1, 32 }, /* m3 */ { 83, -1, 32 }, /* gpio_out */ { 84, -1, 32 }, /* f0 */ { 85, -1, 32 }, /* f1 */ { 86, -1, 32 }, /* f2 */ { 87, -1, 32 }, /* f3 */ { 88, -1, 32 }, /* f4 */ { 89, -1, 32 }, /* f5 */ { 90, -1, 32 }, /* f6 */ { 91, -1, 32 }, /* f7 */ { 92, -1, 32 }, /* f8 */ { 93, -1, 32 }, /* f9 */ { 94, -1, 32 }, /* f10 */ { 95, -1, 32 }, /* f11 */ { 96, -1, 32 }, /* f12 */ { 97, -1, 32 }, /* f13 */ { 98, -1, 32 }, /* f14 */ { 99, -1, 32 }, /* f15 */ { 100, -1, 32 }, /* fcr */ { 101, -1, 32 }, /* fsr */ { 102, -1, 32 }, /* accx_0 */ { 103, -1, 32 }, /* accx_1 */ { 104, -1, 32 }, /* qacc_h_0 */ { 105, -1, 32 }, /* qacc_h_1 */ { 106, -1, 32 }, /* qacc_h_2 */ { 107, -1, 32 }, /* qacc_h_3 */ { 108, -1, 32 }, /* qacc_h_4 */ { 109, -1, 32 }, /* qacc_l_0 */ { 110, -1, 32 }, /* qacc_l_1 */ { 111, -1, 32 }, /* qacc_l_2 */ { 112, -1, 32 }, /* qacc_l_3 */ { 113, -1, 32 }, /* qacc_l_4 */ { 114, -1, 32 }, /* sar_byte */ { 115, -1, 32 }, /* fft_bit_width */ { 116, -1, 32 }, /* ua_state_0 */ { 117, -1, 32 }, /* ua_state_1 */ { 118, -1, 32 }, /* ua_state_2 */ { 119, -1, 32 }, /* ua_state_3 */ { 120, -1, 128 }, /* q0 */ { 121, -1, 128 }, /* q1 */ { 122, -1, 128 }, /* q2 */ { 123, -1, 128 }, /* q3 */ { 124, -1, 128 }, /* q4 */ { 125, -1, 128 }, /* q5 */ { 126, -1, 128 }, /* q6 */ { 127, -1, 128 }, /* q7 */ }; const struct rtos_register_stacking nuttx_esp32s3_stacking = { .stack_registers_size = 26 * 4, .stack_growth_direction = -1, .num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_esp32s3), .calculate_process_stack = rtos_generic_stack_align8, .register_offsets = nuttx_stack_offsets_esp32s3, .read_stack = nuttx_esp_xtensa_stack_read, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_nuttx_stackings.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef INCLUDED_RTOS_NUTTX_STACKINGS_H #define INCLUDED_RTOS_NUTTX_STACKINGS_H #include "rtos.h" extern const struct rtos_register_stacking nuttx_stacking_cortex_m; extern const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu; extern const struct rtos_register_stacking nuttx_riscv_stacking; extern const struct rtos_register_stacking nuttx_esp32_stacking; extern const struct rtos_register_stacking nuttx_esp32s2_stacking; extern const struct rtos_register_stacking nuttx_esp32s3_stacking; #endif /* INCLUDED_RTOS_NUTTX_STACKINGS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_riot_stackings.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2015 by Daniel Krebs * * Daniel Krebs - github@daniel-krebs.net * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" #include "target/armv7m.h" #include "rtos_standard_stackings.h" #include "rtos_riot_stackings.h" /* This works for the M0 and M34 stackings as xPSR is in a fixed * location */ static target_addr_t rtos_riot_cortex_m_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, target_addr_t stack_ptr) { const int XPSR_OFFSET = 0x40; return rtos_cortex_m_stack_align(target, stack_data, stacking, stack_ptr, XPSR_OFFSET); } /* see thread_arch.c */ static const struct stack_register_offset rtos_riot_cortex_m0_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, 0x24, 32 }, /* r0 */ { ARMV7M_R1, 0x28, 32 }, /* r1 */ { ARMV7M_R2, 0x2c, 32 }, /* r2 */ { ARMV7M_R3, 0x30, 32 }, /* r3 */ { ARMV7M_R4, 0x14, 32 }, /* r4 */ { ARMV7M_R5, 0x18, 32 }, /* r5 */ { ARMV7M_R6, 0x1c, 32 }, /* r6 */ { ARMV7M_R7, 0x20, 32 }, /* r7 */ { ARMV7M_R8, 0x04, 32 }, /* r8 */ { ARMV7M_R9, 0x08, 32 }, /* r9 */ { ARMV7M_R10, 0x0c, 32 }, /* r10 */ { ARMV7M_R11, 0x10, 32 }, /* r11 */ { ARMV7M_R12, 0x34, 32 }, /* r12 */ { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x38, 32 }, /* lr */ { ARMV7M_PC, 0x3c, 32 }, /* pc */ { ARMV7M_XPSR, 0x40, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_riot_cortex_m0_stacking = { .stack_registers_size = 0x44, .stack_growth_direction = -1, .num_output_registers = ARMV7M_NUM_CORE_REGS, .calculate_process_stack = rtos_riot_cortex_m_stack_align, .register_offsets = rtos_riot_cortex_m0_stack_offsets }; /* see thread_arch.c */ static const struct stack_register_offset rtos_riot_cortex_m34_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, 0x24, 32 }, /* r0 */ { ARMV7M_R1, 0x28, 32 }, /* r1 */ { ARMV7M_R2, 0x2c, 32 }, /* r2 */ { ARMV7M_R3, 0x30, 32 }, /* r3 */ { ARMV7M_R4, 0x04, 32 }, /* r4 */ { ARMV7M_R5, 0x08, 32 }, /* r5 */ { ARMV7M_R6, 0x0c, 32 }, /* r6 */ { ARMV7M_R7, 0x10, 32 }, /* r7 */ { ARMV7M_R8, 0x14, 32 }, /* r8 */ { ARMV7M_R9, 0x18, 32 }, /* r9 */ { ARMV7M_R10, 0x1c, 32 }, /* r10 */ { ARMV7M_R11, 0x20, 32 }, /* r11 */ { ARMV7M_R12, 0x34, 32 }, /* r12 */ { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x38, 32 }, /* lr */ { ARMV7M_PC, 0x3c, 32 }, /* pc */ { ARMV7M_XPSR, 0x40, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_riot_cortex_m34_stacking = { .stack_registers_size = 0x44, .stack_growth_direction = -1, .num_output_registers = ARMV7M_NUM_CORE_REGS, .calculate_process_stack = rtos_riot_cortex_m_stack_align, .register_offsets = rtos_riot_cortex_m34_stack_offsets }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_riot_stackings.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2015 by Daniel Krebs * * Daniel Krebs - github@daniel-krebs.net * ***************************************************************************/ #ifndef OPENOCD_RTOS_RTOS_RIOT_STACKINGS_H #define OPENOCD_RTOS_RTOS_RIOT_STACKINGS_H #include "rtos.h" extern const struct rtos_register_stacking rtos_riot_cortex_m0_stacking; extern const struct rtos_register_stacking rtos_riot_cortex_m34_stacking; #endif /* OPENOCD_RTOS_RTOS_RIOT_STACKINGS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_standard_stackings.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" #include "target/armv7m.h" #include "rtos_standard_stackings.h" static const struct stack_register_offset rtos_standard_cortex_m3_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, 0x20, 32 }, /* r0 */ { ARMV7M_R1, 0x24, 32 }, /* r1 */ { ARMV7M_R2, 0x28, 32 }, /* r2 */ { ARMV7M_R3, 0x2c, 32 }, /* r3 */ { ARMV7M_R4, 0x00, 32 }, /* r4 */ { ARMV7M_R5, 0x04, 32 }, /* r5 */ { ARMV7M_R6, 0x08, 32 }, /* r6 */ { ARMV7M_R7, 0x0c, 32 }, /* r7 */ { ARMV7M_R8, 0x10, 32 }, /* r8 */ { ARMV7M_R9, 0x14, 32 }, /* r9 */ { ARMV7M_R10, 0x18, 32 }, /* r10 */ { ARMV7M_R11, 0x1c, 32 }, /* r11 */ { ARMV7M_R12, 0x30, 32 }, /* r12 */ { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x34, 32 }, /* lr */ { ARMV7M_PC, 0x38, 32 }, /* pc */ { ARMV7M_XPSR, 0x3c, 32 }, /* xPSR */ }; static const struct stack_register_offset rtos_standard_cortex_m4f_stack_offsets[] = { { ARMV7M_R0, 0x24, 32 }, /* r0 */ { ARMV7M_R1, 0x28, 32 }, /* r1 */ { ARMV7M_R2, 0x2c, 32 }, /* r2 */ { ARMV7M_R3, 0x30, 32 }, /* r3 */ { ARMV7M_R4, 0x00, 32 }, /* r4 */ { ARMV7M_R5, 0x04, 32 }, /* r5 */ { ARMV7M_R6, 0x08, 32 }, /* r6 */ { ARMV7M_R7, 0x0c, 32 }, /* r7 */ { ARMV7M_R8, 0x10, 32 }, /* r8 */ { ARMV7M_R9, 0x14, 32 }, /* r9 */ { ARMV7M_R10, 0x18, 32 }, /* r10 */ { ARMV7M_R11, 0x1c, 32 }, /* r11 */ { ARMV7M_R12, 0x34, 32 }, /* r12 */ { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x38, 32 }, /* lr */ { ARMV7M_PC, 0x3c, 32 }, /* pc */ { ARMV7M_XPSR, 0x40, 32 }, /* xPSR */ }; static const struct stack_register_offset rtos_standard_cortex_m4f_fpu_stack_offsets[] = { { ARMV7M_R0, 0x64, 32 }, /* r0 */ { ARMV7M_R1, 0x68, 32 }, /* r1 */ { ARMV7M_R2, 0x6c, 32 }, /* r2 */ { ARMV7M_R3, 0x70, 32 }, /* r3 */ { ARMV7M_R4, 0x00, 32 }, /* r4 */ { ARMV7M_R5, 0x04, 32 }, /* r5 */ { ARMV7M_R6, 0x08, 32 }, /* r6 */ { ARMV7M_R7, 0x0c, 32 }, /* r7 */ { ARMV7M_R8, 0x10, 32 }, /* r8 */ { ARMV7M_R9, 0x14, 32 }, /* r9 */ { ARMV7M_R10, 0x18, 32 }, /* r10 */ { ARMV7M_R11, 0x1c, 32 }, /* r11 */ { ARMV7M_R12, 0x74, 32 }, /* r12 */ { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x78, 32 }, /* lr */ { ARMV7M_PC, 0x7c, 32 }, /* pc */ { ARMV7M_XPSR, 0x80, 32 }, /* xPSR */ }; static const struct stack_register_offset rtos_standard_cortex_r4_stack_offsets[] = { { 0, 0x08, 32 }, /* r0 (a1) */ { 1, 0x0c, 32 }, /* r1 (a2) */ { 2, 0x10, 32 }, /* r2 (a3) */ { 3, 0x14, 32 }, /* r3 (a4) */ { 4, 0x18, 32 }, /* r4 (v1) */ { 5, 0x1c, 32 }, /* r5 (v2) */ { 6, 0x20, 32 }, /* r6 (v3) */ { 7, 0x24, 32 }, /* r7 (v4) */ { 8, 0x28, 32 }, /* r8 (a1) */ { 10, 0x2c, 32 }, /* r9 (sb) */ { 11, 0x30, 32 }, /* r10 (sl) */ { 12, 0x34, 32 }, /* r11 (fp) */ { 13, 0x38, 32 }, /* r12 (ip) */ { 14, -2, 32 }, /* sp */ { 15, 0x3c, 32 }, /* lr */ { 16, 0x40, 32 }, /* pc */ { 17, -1, 96 }, /* FPA1 */ { 18, -1, 96 }, /* FPA2 */ { 19, -1, 96 }, /* FPA3 */ { 20, -1, 96 }, /* FPA4 */ { 21, -1, 96 }, /* FPA5 */ { 22, -1, 96 }, /* FPA6 */ { 23, -1, 96 }, /* FPA7 */ { 24, -1, 96 }, /* FPA8 */ { 25, -1, 32 }, /* FPS */ { 26, 0x04, 32 }, /* CSPR */ }; static target_addr_t rtos_generic_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, target_addr_t stack_ptr, int align) { target_addr_t new_stack_ptr; target_addr_t aligned_stack_ptr; new_stack_ptr = stack_ptr - stacking->stack_growth_direction * stacking->stack_registers_size; aligned_stack_ptr = new_stack_ptr & ~((target_addr_t)align - 1); if (aligned_stack_ptr != new_stack_ptr && stacking->stack_growth_direction == -1) { /* If we have a downward growing stack, the simple alignment code * above results in a wrong result (since it rounds down to nearest * alignment). We want to round up so add an extra align. */ aligned_stack_ptr += (target_addr_t)align; } return aligned_stack_ptr; } target_addr_t rtos_generic_stack_align8(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, target_addr_t stack_ptr) { return rtos_generic_stack_align(target, stack_data, stacking, stack_ptr, 8); } /* The Cortex-M3 will indicate that an alignment adjustment * has been done on the stack by setting bit 9 of the stacked xPSR * register. In this case, we can just add an extra 4 bytes to get * to the program stack. Note that some places in the ARM documentation * make this a little unclear but the padding takes place before the * normal exception stacking - so xPSR is always available at a fixed * location. * * Relevant documentation: * Cortex-M series processors -> Cortex-M3 -> Revision: xxx -> * Cortex-M3 Devices Generic User Guide -> The Cortex-M3 Processor -> * Exception Model -> Exception entry and return -> Exception entry * Cortex-M series processors -> Cortex-M3 -> Revision: xxx -> * Cortex-M3 Devices Generic User Guide -> Cortex-M3 Peripherals -> * System control block -> Configuration and Control Register (STKALIGN) * * This is just a helper function for use in the calculate_process_stack * function for a given architecture/rtos. */ target_addr_t rtos_cortex_m_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, target_addr_t stack_ptr, size_t xpsr_offset) { const uint32_t ALIGN_NEEDED = (1 << 9); uint32_t xpsr; target_addr_t new_stack_ptr; new_stack_ptr = stack_ptr - stacking->stack_growth_direction * stacking->stack_registers_size; xpsr = (target->endianness == TARGET_LITTLE_ENDIAN) ? le_to_h_u32(&stack_data[xpsr_offset]) : be_to_h_u32(&stack_data[xpsr_offset]); if ((xpsr & ALIGN_NEEDED) != 0) { LOG_DEBUG("XPSR(0x%08" PRIx32 ") indicated stack alignment was necessary\r\n", xpsr); new_stack_ptr -= (stacking->stack_growth_direction * 4); } return new_stack_ptr; } static target_addr_t rtos_standard_cortex_m3_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, target_addr_t stack_ptr) { const int XPSR_OFFSET = 0x3c; return rtos_cortex_m_stack_align(target, stack_data, stacking, stack_ptr, XPSR_OFFSET); } static target_addr_t rtos_standard_cortex_m4f_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, target_addr_t stack_ptr) { const int XPSR_OFFSET = 0x40; return rtos_cortex_m_stack_align(target, stack_data, stacking, stack_ptr, XPSR_OFFSET); } static target_addr_t rtos_standard_cortex_m4f_fpu_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, target_addr_t stack_ptr) { const int XPSR_OFFSET = 0x80; return rtos_cortex_m_stack_align(target, stack_data, stacking, stack_ptr, XPSR_OFFSET); } const struct rtos_register_stacking rtos_standard_cortex_m3_stacking = { .stack_registers_size = 0x40, .stack_growth_direction = -1, .num_output_registers = ARMV7M_NUM_CORE_REGS, .calculate_process_stack = rtos_standard_cortex_m3_stack_align, .register_offsets = rtos_standard_cortex_m3_stack_offsets }; const struct rtos_register_stacking rtos_standard_cortex_m4f_stacking = { .stack_registers_size = 0x44, .stack_growth_direction = -1, .num_output_registers = ARMV7M_NUM_CORE_REGS, .calculate_process_stack = rtos_standard_cortex_m4f_stack_align, .register_offsets = rtos_standard_cortex_m4f_stack_offsets }; const struct rtos_register_stacking rtos_standard_cortex_m4f_fpu_stacking = { .stack_registers_size = 0xcc, .stack_growth_direction = -1, .num_output_registers = ARMV7M_NUM_CORE_REGS, .calculate_process_stack = rtos_standard_cortex_m4f_fpu_stack_align, .register_offsets = rtos_standard_cortex_m4f_fpu_stack_offsets }; const struct rtos_register_stacking rtos_standard_cortex_r4_stacking = { .stack_registers_size = 0x48, .stack_growth_direction = -1, .num_output_registers = 26, .calculate_process_stack = rtos_generic_stack_align8, .register_offsets = rtos_standard_cortex_r4_stack_offsets }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_standard_stackings.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * ***************************************************************************/ #ifndef OPENOCD_RTOS_RTOS_STANDARD_STACKINGS_H #define OPENOCD_RTOS_RTOS_STANDARD_STACKINGS_H #include "rtos.h" extern const struct rtos_register_stacking rtos_standard_cortex_m3_stacking; extern const struct rtos_register_stacking rtos_standard_cortex_m4f_stacking; extern const struct rtos_register_stacking rtos_standard_cortex_m4f_fpu_stacking; extern const struct rtos_register_stacking rtos_standard_cortex_r4_stacking; target_addr_t rtos_generic_stack_align8(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, target_addr_t stack_ptr); target_addr_t rtos_cortex_m_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, target_addr_t stack_ptr, size_t xpsr_offset); #endif /* OPENOCD_RTOS_RTOS_STANDARD_STACKINGS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_ucos_iii_stackings.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2017 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" #include "target/armv7m.h" #include "target/esirisc.h" #include "rtos_standard_stackings.h" #include "rtos_ucos_iii_stackings.h" static const struct stack_register_offset rtos_ucos_iii_cortex_m_stack_offsets[] = { { ARMV7M_R0, 0x20, 32 }, /* r0 */ { ARMV7M_R1, 0x24, 32 }, /* r1 */ { ARMV7M_R2, 0x28, 32 }, /* r2 */ { ARMV7M_R3, 0x2c, 32 }, /* r3 */ { ARMV7M_R4, 0x00, 32 }, /* r4 */ { ARMV7M_R5, 0x04, 32 }, /* r5 */ { ARMV7M_R6, 0x08, 32 }, /* r6 */ { ARMV7M_R7, 0x0c, 32 }, /* r7 */ { ARMV7M_R8, 0x10, 32 }, /* r8 */ { ARMV7M_R9, 0x14, 32 }, /* r9 */ { ARMV7M_R10, 0x18, 32 }, /* r10 */ { ARMV7M_R11, 0x1c, 32 }, /* r11 */ { ARMV7M_R12, 0x30, 32 }, /* r12 */ { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x34, 32 }, /* lr */ { ARMV7M_PC, 0x38, 32 }, /* pc */ { ARMV7M_XPSR, 0x3c, 32 }, /* xPSR */ }; static const struct stack_register_offset rtos_ucos_iii_esi_risc_stack_offsets[] = { { ESIRISC_SP, -2, 32 }, /* sp */ { ESIRISC_RA, 0x48, 32 }, /* ra */ { ESIRISC_R2, 0x44, 32 }, /* r2 */ { ESIRISC_R3, 0x40, 32 }, /* r3 */ { ESIRISC_R4, 0x3c, 32 }, /* r4 */ { ESIRISC_R5, 0x38, 32 }, /* r5 */ { ESIRISC_R6, 0x34, 32 }, /* r6 */ { ESIRISC_R7, 0x30, 32 }, /* r7 */ { ESIRISC_R8, 0x2c, 32 }, /* r8 */ { ESIRISC_R9, 0x28, 32 }, /* r9 */ { ESIRISC_R10, 0x24, 32 }, /* r10 */ { ESIRISC_R11, 0x20, 32 }, /* r11 */ { ESIRISC_R12, 0x1c, 32 }, /* r12 */ { ESIRISC_R13, 0x18, 32 }, /* r13 */ { ESIRISC_R14, 0x14, 32 }, /* r14 */ { ESIRISC_R15, 0x10, 32 }, /* r15 */ { ESIRISC_PC, 0x04, 32 }, /* PC */ { ESIRISC_CAS, 0x08, 32 }, /* CAS */ }; const struct rtos_register_stacking rtos_ucos_iii_cortex_m_stacking = { .stack_registers_size = 0x40, .stack_growth_direction = -1, .num_output_registers = ARRAY_SIZE(rtos_ucos_iii_cortex_m_stack_offsets), .calculate_process_stack = rtos_generic_stack_align8, .register_offsets = rtos_ucos_iii_cortex_m_stack_offsets }; const struct rtos_register_stacking rtos_ucos_iii_esi_risc_stacking = { .stack_registers_size = 0x4c, .stack_growth_direction = -1, .num_output_registers = ARRAY_SIZE(rtos_ucos_iii_esi_risc_stack_offsets), .register_offsets = rtos_ucos_iii_esi_risc_stack_offsets }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/rtos_ucos_iii_stackings.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2017 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * ***************************************************************************/ #ifndef OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H #define OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H #include "rtos.h" extern const struct rtos_register_stacking rtos_ucos_iii_cortex_m_stacking; extern const struct rtos_register_stacking rtos_ucos_iii_esi_risc_stacking; #endif /* OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/uCOS-III.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2017 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include <helper/time_support.h> #include <helper/types.h> #include <rtos/rtos.h> #include <target/target.h> #include <target/target_type.h> #include "rtos_ucos_iii_stackings.h" #ifndef UCOS_III_MAX_STRLEN #define UCOS_III_MAX_STRLEN 64 #endif #ifndef UCOS_III_MAX_THREADS #define UCOS_III_MAX_THREADS 256 #endif struct ucos_iii_params { const char *target_name; const unsigned char pointer_width; size_t threadid_start; const struct rtos_register_stacking *stacking_info; }; struct ucos_iii_private { const struct ucos_iii_params *params; symbol_address_t thread_stack_offset; symbol_address_t thread_name_offset; symbol_address_t thread_state_offset; symbol_address_t thread_priority_offset; symbol_address_t thread_prev_offset; symbol_address_t thread_next_offset; bool thread_offsets_updated; size_t num_threads; symbol_address_t threads[UCOS_III_MAX_THREADS]; }; static const struct ucos_iii_params ucos_iii_params_list[] = { { .target_name = "cortex_m", .pointer_width = sizeof(uint32_t), .threadid_start = 1, .stacking_info = &rtos_ucos_iii_cortex_m_stacking, }, { .target_name = "esirisc", .pointer_width = sizeof(uint32_t), .threadid_start = 1, .stacking_info = &rtos_ucos_iii_esi_risc_stacking, }, }; static const char * const ucos_iii_symbol_list[] = { "OSRunning", "OSTCBCurPtr", "OSTaskDbgListPtr", "OSTaskQty", /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */ "openocd_OS_TCB_StkPtr_offset", "openocd_OS_TCB_NamePtr_offset", "openocd_OS_TCB_TaskState_offset", "openocd_OS_TCB_Prio_offset", "openocd_OS_TCB_DbgPrevPtr_offset", "openocd_OS_TCB_DbgNextPtr_offset", NULL }; enum ucos_iii_symbol_values { UCOS_III_VAL_OS_RUNNING, UCOS_III_VAL_OS_TCB_CUR_PTR, UCOS_III_VAL_OS_TASK_DBG_LIST_PTR, UCOS_III_VAL_OS_TASK_QTY, /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */ UCOS_III_VAL_OS_TCB_STK_PTR_OFFSET, UCOS_III_VAL_OS_TCB_NAME_PTR_OFFSET, UCOS_III_VAL_OS_TCB_TASK_STATE_OFFSET, UCOS_III_VAL_OS_TCB_PRIO_OFFSET, UCOS_III_VAL_OS_TCB_DBG_PREV_PTR_OFFSET, UCOS_III_VAL_OS_TCB_DBG_NEXT_PTR_OFFSET, }; static const char * const ucos_iii_thread_state_list[] = { "Ready", "Delay", "Pend", "Pend Timeout", "Suspended", "Delay Suspended", "Pend Suspended", "Pend Timeout Suspended", }; static int ucos_iii_find_or_create_thread(struct rtos *rtos, symbol_address_t thread_address, threadid_t *threadid) { struct ucos_iii_private *params = rtos->rtos_specific_params; size_t thread_index; for (thread_index = 0; thread_index < params->num_threads; thread_index++) if (params->threads[thread_index] == thread_address) goto found; if (params->num_threads == UCOS_III_MAX_THREADS) { LOG_WARNING("uCOS-III: too many threads; increase UCOS_III_MAX_THREADS"); return ERROR_FAIL; } params->threads[thread_index] = thread_address; params->num_threads++; found: *threadid = thread_index + params->params->threadid_start; return ERROR_OK; } static int ucos_iii_find_thread_address(struct rtos *rtos, threadid_t threadid, symbol_address_t *thread_address) { struct ucos_iii_private *params = rtos->rtos_specific_params; size_t thread_index; thread_index = threadid - params->params->threadid_start; if (thread_index >= params->num_threads) { LOG_ERROR("uCOS-III: failed to find thread address"); return ERROR_FAIL; } *thread_address = params->threads[thread_index]; return ERROR_OK; } static int ucos_iii_find_last_thread_address(struct rtos *rtos, symbol_address_t *thread_address) { struct ucos_iii_private *params = rtos->rtos_specific_params; int retval; /* read the thread list head */ symbol_address_t thread_list_address = 0; retval = target_read_memory(rtos->target, rtos->symbols[UCOS_III_VAL_OS_TASK_DBG_LIST_PTR].address, params->params->pointer_width, 1, (void *)&thread_list_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread list address"); return retval; } /* advance to end of thread list */ do { *thread_address = thread_list_address; retval = target_read_memory(rtos->target, thread_list_address + params->thread_next_offset, params->params->pointer_width, 1, (void *)&thread_list_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read next thread address"); return retval; } } while (thread_list_address != 0); return ERROR_OK; } static int ucos_iii_update_thread_offsets(struct rtos *rtos) { struct ucos_iii_private *params = rtos->rtos_specific_params; if (params->thread_offsets_updated) return ERROR_OK; const struct thread_offset_map { enum ucos_iii_symbol_values symbol_value; symbol_address_t *thread_offset; } thread_offset_maps[] = { { UCOS_III_VAL_OS_TCB_STK_PTR_OFFSET, ¶ms->thread_stack_offset, }, { UCOS_III_VAL_OS_TCB_NAME_PTR_OFFSET, ¶ms->thread_name_offset, }, { UCOS_III_VAL_OS_TCB_TASK_STATE_OFFSET, ¶ms->thread_state_offset, }, { UCOS_III_VAL_OS_TCB_PRIO_OFFSET, ¶ms->thread_priority_offset, }, { UCOS_III_VAL_OS_TCB_DBG_PREV_PTR_OFFSET, ¶ms->thread_prev_offset, }, { UCOS_III_VAL_OS_TCB_DBG_NEXT_PTR_OFFSET, ¶ms->thread_next_offset, }, }; for (size_t i = 0; i < ARRAY_SIZE(thread_offset_maps); i++) { const struct thread_offset_map *thread_offset_map = &thread_offset_maps[i]; int retval = target_read_memory(rtos->target, rtos->symbols[thread_offset_map->symbol_value].address, params->params->pointer_width, 1, (void *)thread_offset_map->thread_offset); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread offset"); return retval; } } params->thread_offsets_updated = true; return ERROR_OK; } static bool ucos_iii_detect_rtos(struct target *target) { return target->rtos->symbols && target->rtos->symbols[UCOS_III_VAL_OS_RUNNING].address != 0; } static int ucos_iii_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv) { struct ucos_iii_private *params = target->rtos->rtos_specific_params; params->thread_offsets_updated = false; params->num_threads = 0; return ERROR_OK; } static int ucos_iii_create(struct target *target) { struct ucos_iii_private *params; for (size_t i = 0; i < ARRAY_SIZE(ucos_iii_params_list); i++) if (strcmp(ucos_iii_params_list[i].target_name, target->type->name) == 0) { params = calloc(1, sizeof(*params)); if (!params) { LOG_ERROR("uCOS-III: out of memory"); return ERROR_FAIL; } params->params = &ucos_iii_params_list[i]; target->rtos->rtos_specific_params = (void *)params; target_register_reset_callback(ucos_iii_reset_handler, NULL); return ERROR_OK; } LOG_ERROR("uCOS-III: target not supported: %s", target->type->name); return ERROR_FAIL; } static int ucos_iii_update_threads(struct rtos *rtos) { struct ucos_iii_private *params = rtos->rtos_specific_params; int retval; if (!rtos->symbols) { LOG_ERROR("uCOS-III: symbol list not loaded"); return ERROR_FAIL; } /* free previous thread details */ rtos_free_threadlist(rtos); /* verify RTOS is running */ uint8_t rtos_running; retval = target_read_u8(rtos->target, rtos->symbols[UCOS_III_VAL_OS_RUNNING].address, &rtos_running); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read RTOS running"); return retval; } if (rtos_running != 1 && rtos_running != 0) { LOG_ERROR("uCOS-III: invalid RTOS running value"); return ERROR_FAIL; } if (!rtos_running) { rtos->thread_details = calloc(1, sizeof(struct thread_detail)); if (!rtos->thread_details) { LOG_ERROR("uCOS-III: out of memory"); return ERROR_FAIL; } rtos->thread_count = 1; rtos->thread_details->threadid = 0; rtos->thread_details->exists = true; rtos->current_thread = 0; return ERROR_OK; } /* update thread offsets */ retval = ucos_iii_update_thread_offsets(rtos); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to update thread offsets"); return retval; } /* read current thread address */ symbol_address_t current_thread_address = 0; retval = target_read_memory(rtos->target, rtos->symbols[UCOS_III_VAL_OS_TCB_CUR_PTR].address, params->params->pointer_width, 1, (void *)¤t_thread_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read current thread address"); return retval; } /* read number of tasks */ retval = target_read_u16(rtos->target, rtos->symbols[UCOS_III_VAL_OS_TASK_QTY].address, (void *)&rtos->thread_count); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread count"); return retval; } rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail)); if (!rtos->thread_details) { LOG_ERROR("uCOS-III: out of memory"); return ERROR_FAIL; } /* * uC/OS-III adds tasks in LIFO order; advance to the end of the * list and work backwards to preserve the intended order. */ symbol_address_t thread_address = 0; retval = ucos_iii_find_last_thread_address(rtos, &thread_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to find last thread address"); return retval; } for (int i = 0; i < rtos->thread_count; i++) { struct thread_detail *thread_detail = &rtos->thread_details[i]; char thread_str_buffer[UCOS_III_MAX_STRLEN + 1]; /* find or create new threadid */ retval = ucos_iii_find_or_create_thread(rtos, thread_address, &thread_detail->threadid); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to find or create thread"); return retval; } if (thread_address == current_thread_address) rtos->current_thread = thread_detail->threadid; thread_detail->exists = true; /* read thread name */ symbol_address_t thread_name_address = 0; retval = target_read_memory(rtos->target, thread_address + params->thread_name_offset, params->params->pointer_width, 1, (void *)&thread_name_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to name address"); return retval; } retval = target_read_buffer(rtos->target, thread_name_address, sizeof(thread_str_buffer), (void *)thread_str_buffer); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread name"); return retval; } thread_str_buffer[sizeof(thread_str_buffer) - 1] = '\0'; thread_detail->thread_name_str = strdup(thread_str_buffer); /* read thread extra info */ uint8_t thread_state; uint8_t thread_priority; retval = target_read_u8(rtos->target, thread_address + params->thread_state_offset, &thread_state); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread state"); return retval; } retval = target_read_u8(rtos->target, thread_address + params->thread_priority_offset, &thread_priority); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread priority"); return retval; } const char *thread_state_str; if (thread_state < ARRAY_SIZE(ucos_iii_thread_state_list)) thread_state_str = ucos_iii_thread_state_list[thread_state]; else thread_state_str = "Unknown"; snprintf(thread_str_buffer, sizeof(thread_str_buffer), "State: %s, Priority: %d", thread_state_str, thread_priority); thread_detail->extra_info_str = strdup(thread_str_buffer); /* read previous thread address */ retval = target_read_memory(rtos->target, thread_address + params->thread_prev_offset, params->params->pointer_width, 1, (void *)&thread_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read previous thread address"); return retval; } } return ERROR_OK; } static int ucos_iii_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, struct rtos_reg **reg_list, int *num_regs) { struct ucos_iii_private *params = rtos->rtos_specific_params; int retval; /* find thread address for threadid */ symbol_address_t thread_address = 0; retval = ucos_iii_find_thread_address(rtos, threadid, &thread_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to find thread address"); return retval; } /* read thread stack address */ symbol_address_t stack_address = 0; retval = target_read_memory(rtos->target, thread_address + params->thread_stack_offset, params->params->pointer_width, 1, (void *)&stack_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read stack address"); return retval; } return rtos_generic_stack_read(rtos->target, params->params->stacking_info, stack_address, reg_list, num_regs); } static int ucos_iii_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { *symbol_list = calloc(ARRAY_SIZE(ucos_iii_symbol_list), sizeof(struct symbol_table_elem)); if (!*symbol_list) { LOG_ERROR("uCOS-III: out of memory"); return ERROR_FAIL; } for (size_t i = 0; i < ARRAY_SIZE(ucos_iii_symbol_list); i++) (*symbol_list)[i].symbol_name = ucos_iii_symbol_list[i]; return ERROR_OK; } const struct rtos_type ucos_iii_rtos = { .name = "uCOS-III", .detect_rtos = ucos_iii_detect_rtos, .create = ucos_iii_create, .update_threads = ucos_iii_update_threads, .get_thread_reg_list = ucos_iii_get_thread_reg_list, .get_symbol_list_to_lookup = ucos_iii_get_symbol_list_to_lookup, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtos/zephyr.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2017 by Intel Corporation * Leandro Pereira <leandro.pereira@intel.com> * Daniel Glöckner <dg@emlix.com>* * Copyright (C) 2021 by Synopsys, Inc. * Evgeniy Didin <didin@synopsys.com> ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/time_support.h> #include <jtag/jtag.h> #include "helper/log.h" #include "helper/types.h" #include "rtos.h" #include "rtos_standard_stackings.h" #include "target/target.h" #include "target/target_type.h" #include "target/armv7m.h" #include "target/arc.h" #define UNIMPLEMENTED 0xFFFFFFFFU /* ARC specific defines */ #define ARC_AUX_SEC_BUILD_REG 0xdb #define ARC_REG_NUM 38 /* ARM specific defines */ #define ARM_XPSR_OFFSET 28 struct zephyr_thread { uint32_t ptr, next_ptr; uint32_t entry; uint32_t stack_pointer; uint8_t state; uint8_t user_options; int8_t prio; char name[64]; }; enum zephyr_offsets { OFFSET_VERSION, OFFSET_K_CURR_THREAD, OFFSET_K_THREADS, OFFSET_T_ENTRY, OFFSET_T_NEXT_THREAD, OFFSET_T_STATE, OFFSET_T_USER_OPTIONS, OFFSET_T_PRIO, OFFSET_T_STACK_POINTER, OFFSET_T_NAME, OFFSET_T_ARCH, OFFSET_T_PREEMPT_FLOAT, OFFSET_T_COOP_FLOAT, OFFSET_MAX }; struct zephyr_params { const char *target_name; uint8_t size_width; uint8_t pointer_width; uint32_t num_offsets; uint32_t offsets[OFFSET_MAX]; const struct rtos_register_stacking *callee_saved_stacking; const struct rtos_register_stacking *cpu_saved_nofp_stacking; const struct rtos_register_stacking *cpu_saved_fp_stacking; int (*get_cpu_state)(struct rtos *rtos, target_addr_t *addr, struct zephyr_params *params, struct rtos_reg *callee_saved_reg_list, struct rtos_reg **reg_list, int *num_regs); }; static const struct stack_register_offset arm_callee_saved[] = { { ARMV7M_R13, 32, 32 }, { ARMV7M_R4, 0, 32 }, { ARMV7M_R5, 4, 32 }, { ARMV7M_R6, 8, 32 }, { ARMV7M_R7, 12, 32 }, { ARMV7M_R8, 16, 32 }, { ARMV7M_R9, 20, 32 }, { ARMV7M_R10, 24, 32 }, { ARMV7M_R11, 28, 32 }, }; static const struct stack_register_offset arc_callee_saved[] = { { ARC_R13, 0, 32 }, { ARC_R14, 4, 32 }, { ARC_R15, 8, 32 }, { ARC_R16, 12, 32 }, { ARC_R17, 16, 32 }, { ARC_R18, 20, 32 }, { ARC_R19, 24, 32 }, { ARC_R20, 28, 32 }, { ARC_R21, 32, 32 }, { ARC_R22, 36, 32 }, { ARC_R23, 40, 32 }, { ARC_R24, 44, 32 }, { ARC_R25, 48, 32 }, { ARC_GP, 52, 32 }, { ARC_FP, 56, 32 }, { ARC_R30, 60, 32 } }; static const struct rtos_register_stacking arm_callee_saved_stacking = { .stack_registers_size = 36, .stack_growth_direction = -1, .num_output_registers = ARRAY_SIZE(arm_callee_saved), .register_offsets = arm_callee_saved, }; static const struct rtos_register_stacking arc_callee_saved_stacking = { .stack_registers_size = 64, .stack_growth_direction = -1, .num_output_registers = ARRAY_SIZE(arc_callee_saved), .register_offsets = arc_callee_saved, }; static const struct stack_register_offset arm_cpu_saved[] = { { ARMV7M_R0, 0, 32 }, { ARMV7M_R1, 4, 32 }, { ARMV7M_R2, 8, 32 }, { ARMV7M_R3, 12, 32 }, { ARMV7M_R4, -1, 32 }, { ARMV7M_R5, -1, 32 }, { ARMV7M_R6, -1, 32 }, { ARMV7M_R7, -1, 32 }, { ARMV7M_R8, -1, 32 }, { ARMV7M_R9, -1, 32 }, { ARMV7M_R10, -1, 32 }, { ARMV7M_R11, -1, 32 }, { ARMV7M_R12, 16, 32 }, { ARMV7M_R13, -2, 32 }, { ARMV7M_R14, 20, 32 }, { ARMV7M_PC, 24, 32 }, { ARMV7M_XPSR, 28, 32 }, }; static struct stack_register_offset arc_cpu_saved[] = { { ARC_R0, -1, 32 }, { ARC_R1, -1, 32 }, { ARC_R2, -1, 32 }, { ARC_R3, -1, 32 }, { ARC_R4, -1, 32 }, { ARC_R5, -1, 32 }, { ARC_R6, -1, 32 }, { ARC_R7, -1, 32 }, { ARC_R8, -1, 32 }, { ARC_R9, -1, 32 }, { ARC_R10, -1, 32 }, { ARC_R11, -1, 32 }, { ARC_R12, -1, 32 }, { ARC_R13, -1, 32 }, { ARC_R14, -1, 32 }, { ARC_R15, -1, 32 }, { ARC_R16, -1, 32 }, { ARC_R17, -1, 32 }, { ARC_R18, -1, 32 }, { ARC_R19, -1, 32 }, { ARC_R20, -1, 32 }, { ARC_R21, -1, 32 }, { ARC_R22, -1, 32 }, { ARC_R23, -1, 32 }, { ARC_R24, -1, 32 }, { ARC_R25, -1, 32 }, { ARC_GP, -1, 32 }, { ARC_FP, -1, 32 }, { ARC_SP, -1, 32 }, { ARC_ILINK, -1, 32 }, { ARC_R30, -1, 32 }, { ARC_BLINK, 0, 32 }, { ARC_LP_COUNT, -1, 32 }, { ARC_PCL, -1, 32 }, { ARC_PC, -1, 32 }, { ARC_LP_START, -1, 32 }, { ARC_LP_END, -1, 32 }, { ARC_STATUS32, 4, 32 } }; enum zephyr_symbol_values { ZEPHYR_VAL__KERNEL, ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS, ZEPHYR_VAL__KERNEL_OPENOCD_SIZE_T_SIZE, ZEPHYR_VAL__KERNEL_OPENOCD_NUM_OFFSETS, ZEPHYR_VAL_COUNT }; static target_addr_t zephyr_cortex_m_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, target_addr_t stack_ptr) { return rtos_cortex_m_stack_align(target, stack_data, stacking, stack_ptr, ARM_XPSR_OFFSET); } static const struct rtos_register_stacking arm_cpu_saved_nofp_stacking = { .stack_registers_size = 32, .stack_growth_direction = -1, .num_output_registers = ARRAY_SIZE(arm_cpu_saved), .calculate_process_stack = zephyr_cortex_m_stack_align, .register_offsets = arm_cpu_saved, }; static const struct rtos_register_stacking arm_cpu_saved_fp_stacking = { .stack_registers_size = 32 + 18 * 4, .stack_growth_direction = -1, .num_output_registers = ARRAY_SIZE(arm_cpu_saved), .calculate_process_stack = zephyr_cortex_m_stack_align, .register_offsets = arm_cpu_saved, }; /* stack_registers_size is 8 because besides caller registers * there are only blink and Status32 registers on stack left */ static struct rtos_register_stacking arc_cpu_saved_stacking = { .stack_registers_size = 8, .stack_growth_direction = -1, .num_output_registers = ARRAY_SIZE(arc_cpu_saved), .register_offsets = arc_cpu_saved, }; /* ARCv2 specific implementation */ static int zephyr_get_arc_state(struct rtos *rtos, target_addr_t *addr, struct zephyr_params *params, struct rtos_reg *callee_saved_reg_list, struct rtos_reg **reg_list, int *num_regs) { uint32_t real_stack_addr; int retval = 0; int num_callee_saved_regs; const struct rtos_register_stacking *stacking; /* Getting real stack address from Kernel thread struct */ retval = target_read_u32(rtos->target, *addr, &real_stack_addr); if (retval != ERROR_OK) return retval; /* Getting callee registers */ retval = rtos_generic_stack_read(rtos->target, params->callee_saved_stacking, real_stack_addr, &callee_saved_reg_list, &num_callee_saved_regs); if (retval != ERROR_OK) return retval; stacking = params->cpu_saved_nofp_stacking; /* Getting blink and status32 registers */ retval = rtos_generic_stack_read(rtos->target, stacking, real_stack_addr + num_callee_saved_regs * 4, reg_list, num_regs); if (retval != ERROR_OK) return retval; for (int i = 0; i < num_callee_saved_regs; i++) buf_cpy(callee_saved_reg_list[i].value, (*reg_list)[callee_saved_reg_list[i].number].value, callee_saved_reg_list[i].size); /* The blink, sp, pc offsets in arc_cpu_saved structure may be changed, * but the registers number shall not. So the next code searches the * offsetst of these registers in arc_cpu_saved structure. */ unsigned short blink_offset = 0, pc_offset = 0, sp_offset = 0; for (size_t i = 0; i < ARRAY_SIZE(arc_cpu_saved); i++) { if (arc_cpu_saved[i].number == ARC_BLINK) blink_offset = i; if (arc_cpu_saved[i].number == ARC_SP) sp_offset = i; if (arc_cpu_saved[i].number == ARC_PC) pc_offset = i; } if (blink_offset == 0 || sp_offset == 0 || pc_offset == 0) { LOG_ERROR("Basic registers offsets are missing, check <arc_cpu_saved> struct"); return ERROR_FAIL; } /* Put blink value into PC */ buf_cpy((*reg_list)[blink_offset].value, (*reg_list)[pc_offset].value, sizeof((*reg_list)[blink_offset].value)); /* Put address after callee/caller in SP. */ int64_t stack_top; stack_top = real_stack_addr + num_callee_saved_regs * 4 + arc_cpu_saved_stacking.stack_registers_size; buf_cpy(&stack_top, (*reg_list)[sp_offset].value, sizeof(stack_top)); return retval; } /* ARM Cortex-M-specific implementation */ static int zephyr_get_arm_state(struct rtos *rtos, target_addr_t *addr, struct zephyr_params *params, struct rtos_reg *callee_saved_reg_list, struct rtos_reg **reg_list, int *num_regs) { int retval = 0; int num_callee_saved_regs; const struct rtos_register_stacking *stacking; retval = rtos_generic_stack_read(rtos->target, params->callee_saved_stacking, *addr, &callee_saved_reg_list, &num_callee_saved_regs); if (retval != ERROR_OK) return retval; *addr = target_buffer_get_u32(rtos->target, callee_saved_reg_list[0].value); if (params->offsets[OFFSET_T_PREEMPT_FLOAT] != UNIMPLEMENTED) stacking = params->cpu_saved_fp_stacking; else stacking = params->cpu_saved_nofp_stacking; retval = rtos_generic_stack_read(rtos->target, stacking, *addr, reg_list, num_regs); if (retval != ERROR_OK) return retval; for (int i = 1; i < num_callee_saved_regs; i++) buf_cpy(callee_saved_reg_list[i].value, (*reg_list)[callee_saved_reg_list[i].number].value, callee_saved_reg_list[i].size); return 0; } static struct zephyr_params zephyr_params_list[] = { { .target_name = "cortex_m", .pointer_width = 4, .callee_saved_stacking = &arm_callee_saved_stacking, .cpu_saved_nofp_stacking = &arm_cpu_saved_nofp_stacking, .cpu_saved_fp_stacking = &arm_cpu_saved_fp_stacking, .get_cpu_state = &zephyr_get_arm_state, }, { .target_name = "cortex_r4", .pointer_width = 4, .callee_saved_stacking = &arm_callee_saved_stacking, .cpu_saved_nofp_stacking = &arm_cpu_saved_nofp_stacking, .cpu_saved_fp_stacking = &arm_cpu_saved_fp_stacking, .get_cpu_state = &zephyr_get_arm_state, }, { .target_name = "hla_target", .pointer_width = 4, .callee_saved_stacking = &arm_callee_saved_stacking, .cpu_saved_nofp_stacking = &arm_cpu_saved_nofp_stacking, .cpu_saved_fp_stacking = &arm_cpu_saved_fp_stacking, .get_cpu_state = &zephyr_get_arm_state, }, { .target_name = "arcv2", .pointer_width = 4, .callee_saved_stacking = &arc_callee_saved_stacking, .cpu_saved_nofp_stacking = &arc_cpu_saved_stacking, .get_cpu_state = &zephyr_get_arc_state, }, { .target_name = NULL } }; static const struct symbol_table_elem zephyr_symbol_list[] = { { .symbol_name = "_kernel", .optional = false }, { .symbol_name = "_kernel_thread_info_offsets", .optional = false }, { .symbol_name = "_kernel_thread_info_size_t_size", .optional = false }, { .symbol_name = "_kernel_thread_info_num_offsets", .optional = true }, { .symbol_name = NULL } }; static bool zephyr_detect_rtos(struct target *target) { if (!target->rtos->symbols) { LOG_INFO("Zephyr: no symbols while detecting RTOS"); return false; } for (enum zephyr_symbol_values symbol = ZEPHYR_VAL__KERNEL; symbol != ZEPHYR_VAL_COUNT; symbol++) { LOG_INFO("Zephyr: does it have symbol %d (%s)?", symbol, target->rtos->symbols[symbol].optional ? "optional" : "mandatory"); if (target->rtos->symbols[symbol].optional) continue; if (target->rtos->symbols[symbol].address == 0) return false; } LOG_INFO("Zephyr: all mandatory symbols found"); return true; } static int zephyr_create(struct target *target) { const char *name; name = target_type_name(target); LOG_INFO("Zephyr: looking for target: %s", name); /* ARC specific, check if EM target has security subsystem * In case of ARC_HAS_SECURE zephyr option enabled * the thread stack contains blink,sec_stat,status32 register * values. If ARC_HAS_SECURE is disabled, only blink and status32 * register values are saved on stack. */ if (!strcmp(name, "arcv2")) { uint32_t value; struct arc_common *arc = target_to_arc(target); /* Reading SEC_BUILD bcr */ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, ARC_AUX_SEC_BUILD_REG, &value)); if (value != 0) { LOG_DEBUG("ARC EM board has security subsystem, changing offsets"); arc_cpu_saved[ARC_REG_NUM - 1].offset = 8; /* After reading callee registers in stack * now blink,sec_stat,status32 registers * are located. */ arc_cpu_saved_stacking.stack_registers_size = 12; } } for (struct zephyr_params *p = zephyr_params_list; p->target_name; p++) { if (!strcmp(p->target_name, name)) { LOG_INFO("Zephyr: target known, params at %p", p); target->rtos->rtos_specific_params = p; return ERROR_OK; } } LOG_ERROR("Could not find target in Zephyr compatibility list"); return ERROR_FAIL; } struct zephyr_array { void *ptr; size_t elements; }; static void zephyr_array_init(struct zephyr_array *array) { array->ptr = NULL; array->elements = 0; } static void zephyr_array_free(struct zephyr_array *array) { free(array->ptr); zephyr_array_init(array); } static void *zephyr_array_append(struct zephyr_array *array, size_t size) { if (!(array->elements % 16)) { void *ptr = realloc(array->ptr, (array->elements + 16) * size); if (!ptr) { LOG_ERROR("Out of memory"); return NULL; } array->ptr = ptr; } return (unsigned char *)array->ptr + (array->elements++) * size; } static void *zephyr_array_detach_ptr(struct zephyr_array *array) { void *ptr = array->ptr; zephyr_array_init(array); return ptr; } static uint32_t zephyr_kptr(const struct rtos *rtos, enum zephyr_offsets off) { const struct zephyr_params *params = rtos->rtos_specific_params; return rtos->symbols[ZEPHYR_VAL__KERNEL].address + params->offsets[off]; } static int zephyr_fetch_thread(const struct rtos *rtos, struct zephyr_thread *thread, uint32_t ptr) { const struct zephyr_params *param = rtos->rtos_specific_params; int retval; thread->ptr = ptr; retval = target_read_u32(rtos->target, ptr + param->offsets[OFFSET_T_ENTRY], &thread->entry); if (retval != ERROR_OK) return retval; retval = target_read_u32(rtos->target, ptr + param->offsets[OFFSET_T_NEXT_THREAD], &thread->next_ptr); if (retval != ERROR_OK) return retval; retval = target_read_u32(rtos->target, ptr + param->offsets[OFFSET_T_STACK_POINTER], &thread->stack_pointer); if (retval != ERROR_OK) return retval; retval = target_read_u8(rtos->target, ptr + param->offsets[OFFSET_T_STATE], &thread->state); if (retval != ERROR_OK) return retval; retval = target_read_u8(rtos->target, ptr + param->offsets[OFFSET_T_USER_OPTIONS], &thread->user_options); if (retval != ERROR_OK) return retval; uint8_t prio; retval = target_read_u8(rtos->target, ptr + param->offsets[OFFSET_T_PRIO], &prio); if (retval != ERROR_OK) return retval; thread->prio = prio; thread->name[0] = '\0'; if (param->offsets[OFFSET_T_NAME] != UNIMPLEMENTED) { retval = target_read_buffer(rtos->target, ptr + param->offsets[OFFSET_T_NAME], sizeof(thread->name) - 1, (uint8_t *)thread->name); if (retval != ERROR_OK) return retval; thread->name[sizeof(thread->name) - 1] = '\0'; } LOG_DEBUG("Fetched thread%" PRIx32 ": {entry@0x%" PRIx32 ", state=%" PRIu8 ", useropts=%" PRIu8 ", prio=%" PRId8 "}", ptr, thread->entry, thread->state, thread->user_options, thread->prio); return ERROR_OK; } static int zephyr_fetch_thread_list(struct rtos *rtos, uint32_t current_thread) { struct zephyr_array thread_array; struct zephyr_thread thread; struct thread_detail *td; int64_t curr_id = -1; uint32_t curr; int retval; retval = target_read_u32(rtos->target, zephyr_kptr(rtos, OFFSET_K_THREADS), &curr); if (retval != ERROR_OK) { LOG_ERROR("Could not fetch current thread pointer"); return retval; } zephyr_array_init(&thread_array); for (; curr; curr = thread.next_ptr) { retval = zephyr_fetch_thread(rtos, &thread, curr); if (retval != ERROR_OK) goto error; td = zephyr_array_append(&thread_array, sizeof(*td)); if (!td) goto error; td->threadid = thread.ptr; td->exists = true; if (thread.name[0]) td->thread_name_str = strdup(thread.name); else td->thread_name_str = alloc_printf("thr_%" PRIx32 "_%" PRIx32, thread.entry, thread.ptr); td->extra_info_str = alloc_printf("prio:%" PRId8 ",useropts:%" PRIu8, thread.prio, thread.user_options); if (!td->thread_name_str || !td->extra_info_str) goto error; if (td->threadid == current_thread) curr_id = (int64_t)thread_array.elements - 1; } LOG_DEBUG("Got information for %zu threads", thread_array.elements); rtos_free_threadlist(rtos); rtos->thread_count = (int)thread_array.elements; rtos->thread_details = zephyr_array_detach_ptr(&thread_array); rtos->current_threadid = curr_id; rtos->current_thread = current_thread; return ERROR_OK; error: td = thread_array.ptr; for (size_t i = 0; i < thread_array.elements; i++) { free(td[i].thread_name_str); free(td[i].extra_info_str); } zephyr_array_free(&thread_array); return ERROR_FAIL; } static int zephyr_update_threads(struct rtos *rtos) { struct zephyr_params *param; int retval; if (!rtos->rtos_specific_params) return ERROR_FAIL; param = (struct zephyr_params *)rtos->rtos_specific_params; if (!rtos->symbols) { LOG_ERROR("No symbols for Zephyr"); return ERROR_FAIL; } if (rtos->symbols[ZEPHYR_VAL__KERNEL].address == 0) { LOG_ERROR("Can't obtain kernel struct from Zephyr"); return ERROR_FAIL; } if (rtos->symbols[ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS].address == 0) { LOG_ERROR("Please build Zephyr with CONFIG_OPENOCD option set"); return ERROR_FAIL; } retval = target_read_u8(rtos->target, rtos->symbols[ZEPHYR_VAL__KERNEL_OPENOCD_SIZE_T_SIZE].address, ¶m->size_width); if (retval != ERROR_OK) { LOG_ERROR("Couldn't determine size of size_t from host"); return retval; } if (param->size_width != 4) { LOG_ERROR("Only size_t of 4 bytes are supported"); return ERROR_FAIL; } if (rtos->symbols[ZEPHYR_VAL__KERNEL_OPENOCD_NUM_OFFSETS].address) { retval = target_read_u32(rtos->target, rtos->symbols[ZEPHYR_VAL__KERNEL_OPENOCD_NUM_OFFSETS].address, ¶m->num_offsets); if (retval != ERROR_OK) { LOG_ERROR("Couldn't not fetch number of offsets from Zephyr"); return retval; } if (param->num_offsets <= OFFSET_T_STACK_POINTER) { LOG_ERROR("Number of offsets too small"); return ERROR_FAIL; } } else { retval = target_read_u32(rtos->target, rtos->symbols[ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS].address, ¶m->offsets[OFFSET_VERSION]); if (retval != ERROR_OK) { LOG_ERROR("Couldn't not fetch offsets from Zephyr"); return retval; } if (param->offsets[OFFSET_VERSION] > 1) { LOG_ERROR("Unexpected OpenOCD support version %" PRIu32, param->offsets[OFFSET_VERSION]); return ERROR_FAIL; } switch (param->offsets[OFFSET_VERSION]) { case 0: param->num_offsets = OFFSET_T_STACK_POINTER + 1; break; case 1: param->num_offsets = OFFSET_T_COOP_FLOAT + 1; break; } } /* We can fetch the whole array for version 0, as they're supposed * to grow only */ uint32_t address; address = rtos->symbols[ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS].address; for (size_t i = 0; i < OFFSET_MAX; i++, address += param->size_width) { if (i >= param->num_offsets) { param->offsets[i] = UNIMPLEMENTED; continue; } retval = target_read_u32(rtos->target, address, ¶m->offsets[i]); if (retval != ERROR_OK) { LOG_ERROR("Could not fetch offsets from Zephyr"); return ERROR_FAIL; } } LOG_DEBUG("Zephyr OpenOCD support version %" PRId32, param->offsets[OFFSET_VERSION]); uint32_t current_thread; retval = target_read_u32(rtos->target, zephyr_kptr(rtos, OFFSET_K_CURR_THREAD), ¤t_thread); if (retval != ERROR_OK) { LOG_ERROR("Could not obtain current thread ID"); return retval; } retval = zephyr_fetch_thread_list(rtos, current_thread); if (retval != ERROR_OK) { LOG_ERROR("Could not obtain thread list"); return retval; } return ERROR_OK; } static int zephyr_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { struct zephyr_params *params; struct rtos_reg *callee_saved_reg_list = NULL; target_addr_t addr; int retval; LOG_INFO("Getting thread %" PRId64 " reg list", thread_id); if (!rtos) return ERROR_FAIL; if (thread_id == 0) return ERROR_FAIL; params = rtos->rtos_specific_params; if (!params) return ERROR_FAIL; addr = thread_id + params->offsets[OFFSET_T_STACK_POINTER] - params->callee_saved_stacking->register_offsets[0].offset; retval = params->get_cpu_state(rtos, &addr, params, callee_saved_reg_list, reg_list, num_regs); free(callee_saved_reg_list); return retval; } static int zephyr_get_symbol_list_to_lookup(struct symbol_table_elem **symbol_list) { *symbol_list = malloc(sizeof(zephyr_symbol_list)); if (!*symbol_list) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } memcpy(*symbol_list, zephyr_symbol_list, sizeof(zephyr_symbol_list)); return ERROR_OK; } const struct rtos_type zephyr_rtos = { .name = "Zephyr", .detect_rtos = zephyr_detect_rtos, .create = zephyr_create, .update_threads = zephyr_update_threads, .get_thread_reg_list = zephyr_get_thread_reg_list, .get_symbol_list_to_lookup = zephyr_get_symbol_list_to_lookup, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtt/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/librtt.la %C%_librtt_la_SOURCES = %D%/rtt.c %D%/rtt.h %D%/tcl.c ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtt/rtt.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdint.h> #include <stdbool.h> #include <string.h> #include <helper/log.h> #include <helper/list.h> #include <target/target.h> #include <target/rtt.h> #include "rtt.h" static struct { struct rtt_source source; /** Control block. */ struct rtt_control ctrl; struct target *target; /** Start address to search for the control block. */ target_addr_t addr; /** Size of the control block search area. */ size_t size; /** Control block identifier. */ char id[RTT_CB_MAX_ID_LENGTH]; /** Whether RTT is configured. */ bool configured; /** Whether RTT is started. */ bool started; /** Whether configuration changed. */ bool changed; /** Whether the control block was found. */ bool found_cb; struct rtt_sink_list **sink_list; size_t sink_list_length; unsigned int polling_interval; } rtt; int rtt_init(void) { rtt.sink_list_length = 1; rtt.sink_list = calloc(rtt.sink_list_length, sizeof(struct rtt_sink_list *)); if (!rtt.sink_list) return ERROR_FAIL; rtt.sink_list[0] = NULL; rtt.started = false; rtt.polling_interval = 100; return ERROR_OK; } int rtt_exit(void) { free(rtt.sink_list); return ERROR_OK; } static int read_channel_callback(void *user_data) { int ret; ret = rtt.source.read(rtt.target, &rtt.ctrl, rtt.sink_list, rtt.sink_list_length, NULL); if (ret != ERROR_OK) { target_unregister_timer_callback(&read_channel_callback, NULL); rtt.source.stop(rtt.target, NULL); return ret; } return ERROR_OK; } int rtt_setup(target_addr_t address, size_t size, const char *id) { size_t id_length = strlen(id); if (!id_length || id_length >= RTT_CB_MAX_ID_LENGTH) { LOG_ERROR("rtt: Invalid control block ID"); return ERROR_COMMAND_ARGUMENT_INVALID; } rtt.addr = address; rtt.size = size; strncpy(rtt.id, id, id_length + 1); rtt.changed = true; rtt.configured = true; return ERROR_OK; } int rtt_register_source(const struct rtt_source source, struct target *target) { if (!source.find_cb || !source.read_cb || !source.read_channel_info) return ERROR_FAIL; if (!source.start || !source.stop) return ERROR_FAIL; if (!source.read || !source.write) return ERROR_FAIL; rtt.source = source; rtt.target = target; return ERROR_OK; } int rtt_start(void) { int ret; target_addr_t addr = rtt.addr; if (rtt.started) return ERROR_OK; if (!rtt.found_cb || rtt.changed) { rtt.source.find_cb(rtt.target, &addr, rtt.size, rtt.id, &rtt.found_cb, NULL); rtt.changed = false; if (rtt.found_cb) { LOG_INFO("rtt: Control block found at 0x%" TARGET_PRIxADDR, addr); rtt.ctrl.address = addr; } else { LOG_INFO("rtt: No control block found"); return ERROR_OK; } } ret = rtt.source.read_cb(rtt.target, rtt.ctrl.address, &rtt.ctrl, NULL); if (ret != ERROR_OK) return ret; ret = rtt.source.start(rtt.target, &rtt.ctrl, NULL); if (ret != ERROR_OK) return ret; target_register_timer_callback(&read_channel_callback, rtt.polling_interval, 1, NULL); rtt.started = true; return ERROR_OK; } int rtt_stop(void) { int ret; if (!rtt.configured) { LOG_ERROR("rtt: Not configured"); return ERROR_FAIL; } target_unregister_timer_callback(&read_channel_callback, NULL); rtt.started = false; ret = rtt.source.stop(rtt.target, NULL); if (ret != ERROR_OK) return ret; return ERROR_OK; } static int adjust_sink_list(size_t length) { struct rtt_sink_list **tmp; if (length <= rtt.sink_list_length) return ERROR_OK; tmp = realloc(rtt.sink_list, sizeof(struct rtt_sink_list *) * length); if (!tmp) return ERROR_FAIL; for (size_t i = rtt.sink_list_length; i < length; i++) tmp[i] = NULL; rtt.sink_list = tmp; rtt.sink_list_length = length; return ERROR_OK; } int rtt_register_sink(unsigned int channel_index, rtt_sink_read read, void *user_data) { struct rtt_sink_list *tmp; if (channel_index >= rtt.sink_list_length) { if (adjust_sink_list(channel_index + 1) != ERROR_OK) return ERROR_FAIL; } LOG_DEBUG("rtt: Registering sink for channel %u", channel_index); tmp = malloc(sizeof(struct rtt_sink_list)); if (!tmp) return ERROR_FAIL; tmp->read = read; tmp->user_data = user_data; tmp->next = rtt.sink_list[channel_index]; rtt.sink_list[channel_index] = tmp; return ERROR_OK; } int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read, void *user_data) { struct rtt_sink_list *prev_sink; LOG_DEBUG("rtt: Unregistering sink for channel %u", channel_index); if (channel_index >= rtt.sink_list_length) return ERROR_FAIL; prev_sink = rtt.sink_list[channel_index]; for (struct rtt_sink_list *sink = rtt.sink_list[channel_index]; sink; prev_sink = sink, sink = sink->next) { if (sink->read == read && sink->user_data == user_data) { if (sink == rtt.sink_list[channel_index]) rtt.sink_list[channel_index] = sink->next; else prev_sink->next = sink->next; free(sink); return ERROR_OK; } } return ERROR_OK; } int rtt_get_polling_interval(unsigned int *interval) { if (!interval) return ERROR_FAIL; *interval = rtt.polling_interval; return ERROR_OK; } int rtt_set_polling_interval(unsigned int interval) { if (!interval) return ERROR_FAIL; if (rtt.polling_interval != interval) { target_unregister_timer_callback(&read_channel_callback, NULL); target_register_timer_callback(&read_channel_callback, interval, 1, NULL); } rtt.polling_interval = interval; return ERROR_OK; } int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer, size_t *length) { if (channel_index >= rtt.ctrl.num_up_channels) { LOG_WARNING("rtt: Down-channel %u is not available", channel_index); return ERROR_OK; } return rtt.source.write(rtt.target, &rtt.ctrl, channel_index, buffer, length, NULL); } bool rtt_started(void) { return rtt.started; } bool rtt_configured(void) { return rtt.configured; } bool rtt_found_cb(void) { return rtt.found_cb; } const struct rtt_control *rtt_get_control(void) { return &rtt.ctrl; } int rtt_read_channel_info(unsigned int channel_index, enum rtt_channel_type type, struct rtt_channel_info *info) { return rtt.source.read_channel_info(rtt.target, &rtt.ctrl, channel_index, type, info, NULL); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtt/rtt.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de> */ #ifndef OPENOCD_RTT_RTT_H #define OPENOCD_RTT_RTT_H #include <stdint.h> #include <stdbool.h> #include <helper/command.h> #include <target/target.h> /** * Control block ID length in bytes, including the trailing null-terminator. */ #define RTT_CB_MAX_ID_LENGTH 16 /* Control block size in bytes. */ #define RTT_CB_SIZE (RTT_CB_MAX_ID_LENGTH + 2 * sizeof(uint32_t)) /* Channel structure size in bytes. */ #define RTT_CHANNEL_SIZE 24 /* Minimal channel buffer size in bytes. */ #define RTT_CHANNEL_BUFFER_MIN_SIZE 2 /** RTT control block. */ struct rtt_control { /** Control block address on the target. */ target_addr_t address; /** Control block identifier, including trailing null-terminator. */ char id[RTT_CB_MAX_ID_LENGTH]; /** Maximum number of up-channels. */ uint32_t num_up_channels; /** Maximum number of down-channels. */ uint32_t num_down_channels; }; /** RTT channel. */ struct rtt_channel { /** Channel structure address on the target. */ target_addr_t address; /** Channel name address on the target. */ uint32_t name_addr; /** Buffer address on the target. */ uint32_t buffer_addr; /** Channel buffer size in bytes. */ uint32_t size; /** Write position within the buffer in bytes. */ uint32_t write_pos; /** Read position within the buffer in bytes. */ uint32_t read_pos; /** * Buffer flags. * * @note: Not used at the moment. */ uint32_t flags; }; /** RTT channel information. */ struct rtt_channel_info { /** Channel name. */ char *name; /** Length of the name in bytes, including the trailing null-terminator. */ size_t name_length; /** Buffer size in bytes. */ uint32_t size; /** * Buffer flags. * * @note: Not used at the moment. */ uint32_t flags; }; typedef int (*rtt_sink_read)(unsigned int channel, const uint8_t *buffer, size_t length, void *user_data); struct rtt_sink_list { rtt_sink_read read; void *user_data; struct rtt_sink_list *next; }; /** Channel type. */ enum rtt_channel_type { /** Up channel (target to host). */ RTT_CHANNEL_TYPE_UP, /** Down channel (host to target). */ RTT_CHANNEL_TYPE_DOWN }; typedef int (*rtt_source_find_ctrl_block)(struct target *target, target_addr_t *address, size_t size, const char *id, bool *found, void *user_data); typedef int (*rtt_source_read_ctrl_block)(struct target *target, target_addr_t address, struct rtt_control *ctrl_block, void *user_data); typedef int (*rtt_source_read_channel_info)(struct target *target, const struct rtt_control *ctrl, unsigned int channel, enum rtt_channel_type type, struct rtt_channel_info *info, void *user_data); typedef int (*rtt_source_start)(struct target *target, const struct rtt_control *ctrl, void *user_data); typedef int (*rtt_source_stop)(struct target *target, void *user_data); typedef int (*rtt_source_read)(struct target *target, const struct rtt_control *ctrl, struct rtt_sink_list **sinks, size_t num_channels, void *user_data); typedef int (*rtt_source_write)(struct target *target, struct rtt_control *ctrl, unsigned int channel, const uint8_t *buffer, size_t *length, void *user_data); /** RTT source. */ struct rtt_source { rtt_source_find_ctrl_block find_cb; rtt_source_read_ctrl_block read_cb; rtt_source_read_channel_info read_channel_info; rtt_source_start start; rtt_source_stop stop; rtt_source_read read; rtt_source_write write; }; /** * Initialize Real-Time Transfer (RTT). * * @returns ERROR_OK on success, an error code on failure. */ int rtt_init(void); /** * Shutdown Real-Time Transfer (RTT). * * @returns ERROR_OK on success, an error code on failure. */ int rtt_exit(void); /** * Register an RTT source for a target. * * @param[in] source RTT source. * @param[in,out] target Target. * * @returns ERROR_OK on success, an error code on failure. */ int rtt_register_source(const struct rtt_source source, struct target *target); /** * Setup RTT. * * @param[in] address Start address to search for the control block. * @param[in] size Size of the control block search area. * @param[in] id Identifier of the control block. Must be null-terminated. * * @returns ERROR_OK on success, an error code on failure. */ int rtt_setup(target_addr_t address, size_t size, const char *id); /** * Start Real-Time Transfer (RTT). * * @returns ERROR_OK on success, an error code on failure. */ int rtt_start(void); /** * Stop Real-Time Transfer (RTT). * * @returns ERROR_OK on success, an error code on failure. */ int rtt_stop(void); /** * Get the polling interval. * * @param[out] interval Polling interval in milliseconds. * * @returns ERROR_OK on success, an error code on failure. */ int rtt_get_polling_interval(unsigned int *interval); /** * Set the polling interval. * * @param[in] interval Polling interval in milliseconds. * * @returns ERROR_OK on success, an error code on failure. */ int rtt_set_polling_interval(unsigned int interval); /** * Get whether RTT is started. * * @returns Whether RTT is started. */ bool rtt_started(void); /** * Get whether RTT is configured. * * @returns Whether RTT is configured. */ bool rtt_configured(void); /** * Get whether RTT control block was found. * * @returns Whether RTT was found. */ bool rtt_found_cb(void); /** * Get the RTT control block. * * @returns The RTT control block. */ const struct rtt_control *rtt_get_control(void); /** * Read channel information. * * @param[in] channel_index Channel index. * @param[in] type Channel type. * @param[out] info Channel information. * * @returns ERROR_OK on success, an error code on failure. */ int rtt_read_channel_info(unsigned int channel_index, enum rtt_channel_type type, struct rtt_channel_info *info); /** * Register an RTT sink. * * @param[in] channel_index Channel index. * @param[in] read Read callback function. * @param[in,out] user_data User data to be passed to the callback function. * * @returns ERROR_OK on success, an error code on failure. */ int rtt_register_sink(unsigned int channel_index, rtt_sink_read read, void *user_data); /** * Unregister an RTT sink. * * @param[in] channel_index Channel index. * @param[in] read Read callback function. * @param[in,out] user_data User data to be passed to the callback function. * * @returns ERROR_OK on success, an error code on failure. */ int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read, void *user_data); /** * Write to an RTT channel. * * @param[in] channel_index Channel index. * @param[in] buffer Buffer with data that should be written to the channel. * @param[in,out] length Number of bytes to write. On success, the argument gets * updated with the actual number of written bytes. * * @returns ERROR_OK on success, an error code on failure. */ int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer, size_t *length); extern const struct command_registration rtt_target_command_handlers[]; #endif /* OPENOCD_RTT_RTT_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/rtt/tcl.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2019-2020 by Marc Schink <dev@zapb.de> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include <target/rtt.h> #include "rtt.h" #define CHANNEL_NAME_SIZE 128 COMMAND_HANDLER(handle_rtt_setup_command) { struct rtt_source source; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; source.find_cb = &target_rtt_find_control_block; source.read_cb = &target_rtt_read_control_block; source.start = &target_rtt_start; source.stop = &target_rtt_stop; source.read = &target_rtt_read_callback; source.write = &target_rtt_write_callback; source.read_channel_info = &target_rtt_read_channel_info; target_addr_t address; uint32_t size; COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[0], address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size); rtt_register_source(source, get_current_target(CMD_CTX)); if (rtt_setup(address, size, CMD_ARGV[2]) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } COMMAND_HANDLER(handle_rtt_start_command) { if (CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; if (!rtt_configured()) { command_print(CMD, "RTT is not configured"); return ERROR_FAIL; } return rtt_start(); } COMMAND_HANDLER(handle_rtt_stop_command) { if (CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; return rtt_stop(); } COMMAND_HANDLER(handle_rtt_polling_interval_command) { if (CMD_ARGC == 0) { int ret; unsigned int interval; ret = rtt_get_polling_interval(&interval); if (ret != ERROR_OK) { command_print(CMD, "Failed to get polling interval"); return ret; } command_print(CMD, "%u ms", interval); } else if (CMD_ARGC == 1) { int ret; unsigned int interval; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], interval); ret = rtt_set_polling_interval(interval); if (ret != ERROR_OK) { command_print(CMD, "Failed to set polling interval"); return ret; } } else { return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } COMMAND_HANDLER(handle_rtt_channels_command) { int ret; char channel_name[CHANNEL_NAME_SIZE]; const struct rtt_control *ctrl; struct rtt_channel_info info; if (!rtt_found_cb()) { command_print(CMD, "rtt: Control block not available"); return ERROR_FAIL; } ctrl = rtt_get_control(); command_print(CMD, "Channels: up=%u, down=%u", ctrl->num_up_channels, ctrl->num_down_channels); command_print(CMD, "Up-channels:"); info.name = channel_name; info.name_length = sizeof(channel_name); for (unsigned int i = 0; i < ctrl->num_up_channels; i++) { ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info); if (ret != ERROR_OK) return ret; if (!info.size) continue; command_print(CMD, "%u: %s %u %u", i, info.name, info.size, info.flags); } command_print(CMD, "Down-channels:"); for (unsigned int i = 0; i < ctrl->num_down_channels; i++) { ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info); if (ret != ERROR_OK) return ret; if (!info.size) continue; command_print(CMD, "%u: %s %u %u", i, info.name, info.size, info.flags); } return ERROR_OK; } COMMAND_HANDLER(handle_channel_list) { char channel_name[CHANNEL_NAME_SIZE]; const struct rtt_control *ctrl; struct rtt_channel_info info; if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (!rtt_found_cb()) { command_print(CMD, "rtt: Control block not available"); return ERROR_FAIL; } ctrl = rtt_get_control(); info.name = channel_name; info.name_length = sizeof(channel_name); command_print(CMD, "{"); for (unsigned int i = 0; i < ctrl->num_up_channels; i++) { int ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info); if (ret != ERROR_OK) return ret; if (!info.size) continue; command_print(CMD, " {\n" " name %s\n" " size 0x%" PRIx32 "\n" " flags 0x%" PRIx32 "\n" " }", info.name, info.size, info.flags); } command_print(CMD, "}\n{"); for (unsigned int i = 0; i < ctrl->num_down_channels; i++) { int ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info); if (ret != ERROR_OK) return ret; if (!info.size) continue; command_print(CMD, " {\n" " name %s\n" " size 0x%" PRIx32 "\n" " flags 0x%" PRIx32 "\n" " }", info.name, info.size, info.flags); } command_print(CMD, "}"); return ERROR_OK; } static const struct command_registration rtt_subcommand_handlers[] = { { .name = "setup", .handler = handle_rtt_setup_command, .mode = COMMAND_ANY, .help = "setup RTT", .usage = "<address> <size> <ID>" }, { .name = "start", .handler = handle_rtt_start_command, .mode = COMMAND_EXEC, .help = "start RTT", .usage = "" }, { .name = "stop", .handler = handle_rtt_stop_command, .mode = COMMAND_EXEC, .help = "stop RTT", .usage = "" }, { .name = "polling_interval", .handler = handle_rtt_polling_interval_command, .mode = COMMAND_EXEC, .help = "show or set polling interval in ms", .usage = "[interval]" }, { .name = "channels", .handler = handle_rtt_channels_command, .mode = COMMAND_EXEC, .help = "list available channels", .usage = "" }, { .name = "channellist", .handler = handle_channel_list, .mode = COMMAND_EXEC, .help = "list available channels", .usage = "" }, COMMAND_REGISTRATION_DONE }; const struct command_registration rtt_target_command_handlers[] = { { .name = "rtt", .mode = COMMAND_EXEC, .help = "RTT target commands", .usage = "", .chain = rtt_subcommand_handlers }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/server/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libserver.la %C%_libserver_la_SOURCES = \ %D%/server.c \ %D%/telnet_server.c \ %D%/gdb_server.c \ %D%/server.h \ %D%/telnet_server.h \ %D%/gdb_server.h \ %D%/tcl_server.c \ %D%/tcl_server.h \ %D%/rtt_server.c \ %D%/rtt_server.h \ %D%/ipdbg.c \ %D%/ipdbg.h STARTUP_TCL_SRCS += %D%/startup.tcl ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/server/gdb_server.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * Copyright (C) ST-Ericsson SA 2011 * * michel.jaouen@stericsson.com : smp minimum support * * * * Copyright (C) 2013 Andes Technology * * Hsiangkai Wang <hkwang@andestech.com> * * * * Copyright (C) 2013 Franck Jullien * * elec4fun@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <target/breakpoints.h> #include <target/target_request.h> #include <target/register.h> #include <target/target.h> #include <target/target_type.h> #include <target/semihosting_common.h> #include "server.h" #include <flash/nor/core.h> #include "gdb_server.h" #include <target/image.h> #include <jtag/jtag.h> #include "rtos/rtos.h" #include "target/smp.h" /** * @file * GDB server implementation. * * This implements the GDB Remote Serial Protocol, over TCP connections, * giving GDB access to the JTAG or other hardware debugging facilities * found in most modern embedded processors. */ enum gdb_output_flag { /* GDB doesn't accept 'O' packets */ GDB_OUTPUT_NO, /* GDB accepts 'O' packets */ GDB_OUTPUT_ALL, }; struct target_desc_format { char *tdesc; uint32_t tdesc_length; }; /* private connection data for GDB */ struct gdb_connection { char buffer[GDB_BUFFER_SIZE + 1]; /* Extra byte for null-termination */ char *buf_p; int buf_cnt; bool ctrl_c; enum target_state frontend_state; struct image *vflash_image; bool closed; bool busy; int noack_mode; /* set flag to true if you want the next stepi to return immediately. * allowing GDB to pick up a fresh set of register values from the target * without modifying the target state. */ bool sync; /* We delay reporting memory write errors until next step/continue or memory * write. This improves performance of gdb load significantly as the GDB packet * can be replied immediately and a new GDB packet will be ready without delay * (ca. 10% or so...). */ bool mem_write_error; /* with extended-remote it seems we need to better emulate attach/detach. * what this means is we reply with a W stop reply after a kill packet, * normally we reply with a S reply via gdb_last_signal_packet. * as a side note this behaviour only effects gdb > 6.8 */ bool attached; /* set when extended protocol is used */ bool extended_protocol; /* temporarily used for target description support */ struct target_desc_format target_desc; /* temporarily used for thread list support */ char *thread_list; /* flag to mask the output from gdb_log_callback() */ enum gdb_output_flag output_flag; }; #if 0 #define _DEBUG_GDB_IO_ #endif static struct gdb_connection *current_gdb_connection; static int gdb_breakpoint_override; static enum breakpoint_type gdb_breakpoint_override_type; static int gdb_error(struct connection *connection, int retval); static char *gdb_port; static char *gdb_port_next; static void gdb_log_callback(void *priv, const char *file, unsigned line, const char *function, const char *string); static void gdb_sig_halted(struct connection *connection); /* number of gdb connections, mainly to suppress gdb related debugging spam * in helper/log.c when no gdb connections are actually active */ static int gdb_actual_connections; /* set if we are sending a memory map to gdb * via qXfer:memory-map:read packet */ /* enabled by default*/ static int gdb_use_memory_map = 1; /* enabled by default*/ static int gdb_flash_program = 1; /* if set, data aborts cause an error to be reported in memory read packets * see the code in gdb_read_memory_packet() for further explanations. * Disabled by default. */ static int gdb_report_data_abort; /* If set, errors when accessing registers are reported to gdb. Disabled by * default. */ static int gdb_report_register_access_error; /* set if we are sending target descriptions to gdb * via qXfer:features:read packet */ /* enabled by default */ static int gdb_use_target_description = 1; /* current processing free-run type, used by file-I/O */ static char gdb_running_type; static int gdb_last_signal(struct target *target) { LOG_TARGET_DEBUG(target, "Debug reason is: %s", target_debug_reason_str(target->debug_reason)); switch (target->debug_reason) { case DBG_REASON_DBGRQ: return 0x2; /* SIGINT */ case DBG_REASON_BREAKPOINT: case DBG_REASON_WATCHPOINT: case DBG_REASON_WPTANDBKPT: return 0x05; /* SIGTRAP */ case DBG_REASON_SINGLESTEP: return 0x05; /* SIGTRAP */ case DBG_REASON_EXC_CATCH: return 0x05; case DBG_REASON_NOTHALTED: return 0x0; /* no signal... shouldn't happen */ default: LOG_USER("undefined debug reason %d (%s) - target needs reset", target->debug_reason, target_debug_reason_str(target->debug_reason)); return 0x0; } } static int check_pending(struct connection *connection, int timeout_s, int *got_data) { /* a non-blocking socket will block if there is 0 bytes available on the socket, * but return with as many bytes as are available immediately */ struct timeval tv; fd_set read_fds; struct gdb_connection *gdb_con = connection->priv; int t; if (!got_data) got_data = &t; *got_data = 0; if (gdb_con->buf_cnt > 0) { *got_data = 1; return ERROR_OK; } FD_ZERO(&read_fds); FD_SET(connection->fd, &read_fds); tv.tv_sec = timeout_s; tv.tv_usec = 0; if (socket_select(connection->fd + 1, &read_fds, NULL, NULL, &tv) == 0) { /* This can typically be because a "monitor" command took too long * before printing any progress messages */ if (timeout_s > 0) return ERROR_GDB_TIMEOUT; else return ERROR_OK; } *got_data = FD_ISSET(connection->fd, &read_fds) != 0; return ERROR_OK; } static int gdb_get_char_inner(struct connection *connection, int *next_char) { struct gdb_connection *gdb_con = connection->priv; int retval = ERROR_OK; #ifdef _DEBUG_GDB_IO_ char *debug_buffer; #endif for (;; ) { if (connection->service->type != CONNECTION_TCP) gdb_con->buf_cnt = read(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE); else { retval = check_pending(connection, 1, NULL); if (retval != ERROR_OK) return retval; gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE); } if (gdb_con->buf_cnt > 0) break; if (gdb_con->buf_cnt == 0) { LOG_DEBUG("GDB connection closed by the remote client"); gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } #ifdef _WIN32 bool retry = (WSAGetLastError() == WSAEWOULDBLOCK); #else bool retry = (errno == EAGAIN); #endif if (retry) { // Try again after a delay usleep(1000); } else { // Print error and close the socket log_socket_error("GDB"); gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } } #ifdef _DEBUG_GDB_IO_ debug_buffer = strndup(gdb_con->buffer, gdb_con->buf_cnt); LOG_DEBUG("received '%s'", debug_buffer); free(debug_buffer); #endif gdb_con->buf_p = gdb_con->buffer; gdb_con->buf_cnt--; *next_char = *(gdb_con->buf_p++); if (gdb_con->buf_cnt > 0) connection->input_pending = true; else connection->input_pending = false; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char); #endif return retval; } /** * The cool thing about this fn is that it allows buf_p and buf_cnt to be * held in registers in the inner loop. * * For small caches and embedded systems this is important! */ static inline int gdb_get_char_fast(struct connection *connection, int *next_char, char **buf_p, int *buf_cnt) { int retval = ERROR_OK; if ((*buf_cnt)-- > 0) { *next_char = **buf_p; (*buf_p)++; if (*buf_cnt > 0) connection->input_pending = true; else connection->input_pending = false; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char); #endif return ERROR_OK; } struct gdb_connection *gdb_con = connection->priv; gdb_con->buf_p = *buf_p; gdb_con->buf_cnt = *buf_cnt; retval = gdb_get_char_inner(connection, next_char); *buf_p = gdb_con->buf_p; *buf_cnt = gdb_con->buf_cnt; return retval; } static int gdb_get_char(struct connection *connection, int *next_char) { struct gdb_connection *gdb_con = connection->priv; return gdb_get_char_fast(connection, next_char, &gdb_con->buf_p, &gdb_con->buf_cnt); } static int gdb_putback_char(struct connection *connection, int last_char) { struct gdb_connection *gdb_con = connection->priv; if (gdb_con->buf_p > gdb_con->buffer) { *(--gdb_con->buf_p) = last_char; gdb_con->buf_cnt++; } else LOG_ERROR("BUG: couldn't put character back"); return ERROR_OK; } /* The only way we can detect that the socket is closed is the first time * we write to it, we will fail. Subsequent write operations will * succeed. Shudder! */ static int gdb_write(struct connection *connection, void *data, int len) { struct gdb_connection *gdb_con = connection->priv; if (gdb_con->closed) { LOG_DEBUG("GDB socket marked as closed, cannot write to it."); return ERROR_SERVER_REMOTE_CLOSED; } if (connection_write(connection, data, len) == len) return ERROR_OK; LOG_WARNING("Error writing to GDB socket. Dropping the connection."); gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } static void gdb_log_incoming_packet(struct connection *connection, char *packet) { if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return; struct target *target = get_target_from_connection(connection); /* Avoid dumping non-printable characters to the terminal */ const unsigned packet_len = strlen(packet); const char *nonprint = find_nonprint_char(packet, packet_len); if (nonprint) { /* Does packet at least have a prefix that is printable? * Look within the first 50 chars of the packet. */ const char *colon = memchr(packet, ':', MIN(50, packet_len)); const bool packet_has_prefix = (colon); const bool packet_prefix_printable = (packet_has_prefix && nonprint > colon); if (packet_prefix_printable) { const unsigned int prefix_len = colon - packet + 1; /* + 1 to include the ':' */ const unsigned int payload_len = packet_len - prefix_len; LOG_TARGET_DEBUG(target, "received packet: %.*s<binary-data-%u-bytes>", prefix_len, packet, payload_len); } else { LOG_TARGET_DEBUG(target, "received packet: <binary-data-%u-bytes>", packet_len); } } else { /* All chars printable, dump the packet as is */ LOG_TARGET_DEBUG(target, "received packet: %s", packet); } } static void gdb_log_outgoing_packet(struct connection *connection, char *packet_buf, unsigned int packet_len, unsigned char checksum) { if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return; struct target *target = get_target_from_connection(connection); if (find_nonprint_char(packet_buf, packet_len)) LOG_TARGET_DEBUG(target, "sending packet: $<binary-data-%u-bytes>#%2.2x", packet_len, checksum); else LOG_TARGET_DEBUG(target, "sending packet: $%.*s#%2.2x", packet_len, packet_buf, checksum); } static int gdb_put_packet_inner(struct connection *connection, char *buffer, int len) { int i; unsigned char my_checksum = 0; int reply; int retval; struct gdb_connection *gdb_con = connection->priv; for (i = 0; i < len; i++) my_checksum += buffer[i]; #ifdef _DEBUG_GDB_IO_ /* * At this point we should have nothing in the input queue from GDB, * however sometimes '-' is sent even though we've already received * an ACK (+) for everything we've sent off. */ int gotdata; for (;; ) { retval = check_pending(connection, 0, &gotdata); if (retval != ERROR_OK) return retval; if (!gotdata) break; retval = gdb_get_char(connection, &reply); if (retval != ERROR_OK) return retval; if (reply == '$') { /* fix a problem with some IAR tools */ gdb_putback_char(connection, reply); LOG_DEBUG("Unexpected start of new packet"); break; } LOG_WARNING("Discard unexpected char %c", reply); } #endif while (1) { gdb_log_outgoing_packet(connection, buffer, len, my_checksum); char local_buffer[1024]; local_buffer[0] = '$'; if ((size_t)len + 4 <= sizeof(local_buffer)) { /* performance gain on smaller packets by only a single call to gdb_write() */ memcpy(local_buffer + 1, buffer, len++); len += snprintf(local_buffer + len, sizeof(local_buffer) - len, "#%02x", my_checksum); retval = gdb_write(connection, local_buffer, len); if (retval != ERROR_OK) return retval; } else { /* larger packets are transmitted directly from caller supplied buffer * by several calls to gdb_write() to avoid dynamic allocation */ snprintf(local_buffer + 1, sizeof(local_buffer) - 1, "#%02x", my_checksum); retval = gdb_write(connection, local_buffer, 1); if (retval != ERROR_OK) return retval; retval = gdb_write(connection, buffer, len); if (retval != ERROR_OK) return retval; retval = gdb_write(connection, local_buffer + 1, 3); if (retval != ERROR_OK) return retval; } if (gdb_con->noack_mode) break; retval = gdb_get_char(connection, &reply); if (retval != ERROR_OK) return retval; if (reply == '+') { gdb_log_incoming_packet(connection, "+"); break; } else if (reply == '-') { /* Stop sending output packets for now */ gdb_con->output_flag = GDB_OUTPUT_NO; gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative reply, retrying"); } else if (reply == 0x3) { gdb_con->ctrl_c = true; gdb_log_incoming_packet(connection, "<Ctrl-C>"); retval = gdb_get_char(connection, &reply); if (retval != ERROR_OK) return retval; if (reply == '+') { gdb_log_incoming_packet(connection, "+"); break; } else if (reply == '-') { /* Stop sending output packets for now */ gdb_con->output_flag = GDB_OUTPUT_NO; gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative reply, retrying"); } else if (reply == '$') { LOG_ERROR("GDB missing ack(1) - assumed good"); gdb_putback_char(connection, reply); return ERROR_OK; } else { LOG_ERROR("unknown character(1) 0x%2.2x in reply, dropping connection", reply); gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } } else if (reply == '$') { LOG_ERROR("GDB missing ack(2) - assumed good"); gdb_putback_char(connection, reply); return ERROR_OK; } else { LOG_ERROR("unknown character(2) 0x%2.2x in reply, dropping connection", reply); gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } } if (gdb_con->closed) return ERROR_SERVER_REMOTE_CLOSED; return ERROR_OK; } int gdb_put_packet(struct connection *connection, char *buffer, int len) { struct gdb_connection *gdb_con = connection->priv; gdb_con->busy = true; int retval = gdb_put_packet_inner(connection, buffer, len); gdb_con->busy = false; /* we sent some data, reset timer for keep alive messages */ kept_alive(); return retval; } static inline int fetch_packet(struct connection *connection, int *checksum_ok, int noack, int *len, char *buffer) { unsigned char my_checksum = 0; char checksum[3]; int character; int retval = ERROR_OK; struct gdb_connection *gdb_con = connection->priv; my_checksum = 0; int count = 0; count = 0; /* move this over into local variables to use registers and give the * more freedom to optimize */ char *buf_p = gdb_con->buf_p; int buf_cnt = gdb_con->buf_cnt; for (;; ) { /* The common case is that we have an entire packet with no escape chars. * We need to leave at least 2 bytes in the buffer to have * gdb_get_char() update various bits and bobs correctly. */ if ((buf_cnt > 2) && ((buf_cnt + count) < *len)) { /* The compiler will struggle a bit with constant propagation and * aliasing, so we help it by showing that these values do not * change inside the loop */ int i; char *buf = buf_p; int run = buf_cnt - 2; i = 0; int done = 0; while (i < run) { character = *buf++; i++; if (character == '#') { /* Danger! character can be '#' when esc is * used so we need an explicit boolean for done here. */ done = 1; break; } if (character == '}') { /* data transmitted in binary mode (X packet) * uses 0x7d as escape character */ my_checksum += character & 0xff; character = *buf++; i++; my_checksum += character & 0xff; buffer[count++] = (character ^ 0x20) & 0xff; } else { my_checksum += character & 0xff; buffer[count++] = character & 0xff; } } buf_p += i; buf_cnt -= i; if (done) break; } if (count > *len) { LOG_ERROR("packet buffer too small"); retval = ERROR_GDB_BUFFER_TOO_SMALL; break; } retval = gdb_get_char_fast(connection, &character, &buf_p, &buf_cnt); if (retval != ERROR_OK) break; if (character == '#') break; if (character == '}') { /* data transmitted in binary mode (X packet) * uses 0x7d as escape character */ my_checksum += character & 0xff; retval = gdb_get_char_fast(connection, &character, &buf_p, &buf_cnt); if (retval != ERROR_OK) break; my_checksum += character & 0xff; buffer[count++] = (character ^ 0x20) & 0xff; } else { my_checksum += character & 0xff; buffer[count++] = character & 0xff; } } gdb_con->buf_p = buf_p; gdb_con->buf_cnt = buf_cnt; if (retval != ERROR_OK) return retval; *len = count; retval = gdb_get_char(connection, &character); if (retval != ERROR_OK) return retval; checksum[0] = character; retval = gdb_get_char(connection, &character); if (retval != ERROR_OK) return retval; checksum[1] = character; checksum[2] = 0; if (!noack) *checksum_ok = (my_checksum == strtoul(checksum, NULL, 16)); return ERROR_OK; } static int gdb_get_packet_inner(struct connection *connection, char *buffer, int *len) { int character; int retval; struct gdb_connection *gdb_con = connection->priv; while (1) { do { retval = gdb_get_char(connection, &character); if (retval != ERROR_OK) return retval; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("character: '%c'", character); #endif switch (character) { case '$': break; case '+': gdb_log_incoming_packet(connection, "+"); /* According to the GDB documentation * (https://sourceware.org/gdb/onlinedocs/gdb/Packet-Acknowledgment.html): * "gdb sends a final `+` acknowledgment of the stub's `OK` * response, which can be safely ignored by the stub." * However OpenOCD server already is in noack mode at this * point and instead of ignoring this it was emitting a * warning. This code makes server ignore the first ACK * that will be received after going into noack mode, * warning only about subsequent ACK's. */ if (gdb_con->noack_mode > 1) { LOG_WARNING("acknowledgment received, but no packet pending"); } else if (gdb_con->noack_mode) { LOG_DEBUG("Received first acknowledgment after entering noack mode. Ignoring it."); gdb_con->noack_mode = 2; } break; case '-': gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative acknowledgment, but no packet pending"); break; case 0x3: gdb_log_incoming_packet(connection, "<Ctrl-C>"); gdb_con->ctrl_c = true; *len = 0; return ERROR_OK; default: LOG_WARNING("ignoring character 0x%x", character); break; } } while (character != '$'); int checksum_ok = 0; /* explicit code expansion here to get faster inlined code in -O3 by not * calculating checksum */ if (gdb_con->noack_mode) { retval = fetch_packet(connection, &checksum_ok, 1, len, buffer); if (retval != ERROR_OK) return retval; } else { retval = fetch_packet(connection, &checksum_ok, 0, len, buffer); if (retval != ERROR_OK) return retval; } if (gdb_con->noack_mode) { /* checksum is not checked in noack mode */ break; } if (checksum_ok) { retval = gdb_write(connection, "+", 1); if (retval != ERROR_OK) return retval; break; } } if (gdb_con->closed) return ERROR_SERVER_REMOTE_CLOSED; return ERROR_OK; } static int gdb_get_packet(struct connection *connection, char *buffer, int *len) { struct gdb_connection *gdb_con = connection->priv; gdb_con->busy = true; int retval = gdb_get_packet_inner(connection, buffer, len); gdb_con->busy = false; return retval; } static int gdb_output_con(struct connection *connection, const char *line) { char *hex_buffer; int bin_size; bin_size = strlen(line); hex_buffer = malloc(bin_size * 2 + 2); if (!hex_buffer) return ERROR_GDB_BUFFER_TOO_SMALL; hex_buffer[0] = 'O'; size_t pkt_len = hexify(hex_buffer + 1, (const uint8_t *)line, bin_size, bin_size * 2 + 1); int retval = gdb_put_packet(connection, hex_buffer, pkt_len + 1); free(hex_buffer); return retval; } static int gdb_output(struct command_context *context, const char *line) { /* this will be dumped to the log and also sent as an O packet if possible */ LOG_USER_N("%s", line); return ERROR_OK; } static void gdb_signal_reply(struct target *target, struct connection *connection) { struct gdb_connection *gdb_connection = connection->priv; char sig_reply[65]; char stop_reason[32]; char current_thread[25]; int sig_reply_len; int signal_var; rtos_update_threads(target); if (target->debug_reason == DBG_REASON_EXIT) { sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "W00"); } else { struct target *ct; if (target->rtos) { target->rtos->current_threadid = target->rtos->current_thread; target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct); } else { ct = target; } if (gdb_connection->ctrl_c) { LOG_TARGET_DEBUG(target, "Responding with signal 2 (SIGINT) to debugger due to Ctrl-C"); signal_var = 0x2; } else signal_var = gdb_last_signal(ct); stop_reason[0] = '\0'; if (ct->debug_reason == DBG_REASON_WATCHPOINT) { enum watchpoint_rw hit_wp_type; target_addr_t hit_wp_address; if (watchpoint_hit(ct, &hit_wp_type, &hit_wp_address) == ERROR_OK) { switch (hit_wp_type) { case WPT_WRITE: snprintf(stop_reason, sizeof(stop_reason), "watch:%08" TARGET_PRIxADDR ";", hit_wp_address); break; case WPT_READ: snprintf(stop_reason, sizeof(stop_reason), "rwatch:%08" TARGET_PRIxADDR ";", hit_wp_address); break; case WPT_ACCESS: snprintf(stop_reason, sizeof(stop_reason), "awatch:%08" TARGET_PRIxADDR ";", hit_wp_address); break; default: break; } } } current_thread[0] = '\0'; if (target->rtos) snprintf(current_thread, sizeof(current_thread), "thread:%" PRIx64 ";", target->rtos->current_thread); sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s", signal_var, stop_reason, current_thread); gdb_connection->ctrl_c = false; } gdb_put_packet(connection, sig_reply, sig_reply_len); gdb_connection->frontend_state = TARGET_HALTED; } static void gdb_fileio_reply(struct target *target, struct connection *connection) { struct gdb_connection *gdb_connection = connection->priv; char fileio_command[256]; int command_len; bool program_exited = false; if (strcmp(target->fileio_info->identifier, "open") == 0) sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2 + 1, /* len + trailing zero */ target->fileio_info->param_3, target->fileio_info->param_4); else if (strcmp(target->fileio_info->identifier, "close") == 0) sprintf(fileio_command, "F%s,%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1); else if (strcmp(target->fileio_info->identifier, "read") == 0) sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2, target->fileio_info->param_3); else if (strcmp(target->fileio_info->identifier, "write") == 0) sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2, target->fileio_info->param_3); else if (strcmp(target->fileio_info->identifier, "lseek") == 0) sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2, target->fileio_info->param_3); else if (strcmp(target->fileio_info->identifier, "rename") == 0) sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64 "/%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2 + 1, /* len + trailing zero */ target->fileio_info->param_3, target->fileio_info->param_4 + 1); /* len + trailing zero */ else if (strcmp(target->fileio_info->identifier, "unlink") == 0) sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2 + 1); /* len + trailing zero */ else if (strcmp(target->fileio_info->identifier, "stat") == 0) sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2, target->fileio_info->param_3); else if (strcmp(target->fileio_info->identifier, "fstat") == 0) sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2); else if (strcmp(target->fileio_info->identifier, "gettimeofday") == 0) sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2); else if (strcmp(target->fileio_info->identifier, "isatty") == 0) sprintf(fileio_command, "F%s,%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1); else if (strcmp(target->fileio_info->identifier, "system") == 0) sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2 + 1); /* len + trailing zero */ else if (strcmp(target->fileio_info->identifier, "exit") == 0) { /* If target hits exit syscall, report to GDB the program is terminated. * In addition, let target run its own exit syscall handler. */ program_exited = true; sprintf(fileio_command, "W%02" PRIx64, target->fileio_info->param_1); } else { LOG_DEBUG("Unknown syscall: %s", target->fileio_info->identifier); /* encounter unknown syscall, continue */ gdb_connection->frontend_state = TARGET_RUNNING; target_resume(target, 1, 0x0, 0, 0); return; } command_len = strlen(fileio_command); gdb_put_packet(connection, fileio_command, command_len); if (program_exited) { /* Use target_resume() to let target run its own exit syscall handler. */ gdb_connection->frontend_state = TARGET_RUNNING; target_resume(target, 1, 0x0, 0, 0); } else { gdb_connection->frontend_state = TARGET_HALTED; rtos_update_threads(target); } } static void gdb_frontend_halted(struct target *target, struct connection *connection) { struct gdb_connection *gdb_connection = connection->priv; /* In the GDB protocol when we are stepping or continuing execution, * we have a lingering reply. Upon receiving a halted event * when we have that lingering packet, we reply to the original * step or continue packet. * * Executing monitor commands can bring the target in and * out of the running state so we'll see lots of TARGET_EVENT_XXX * that are to be ignored. */ if (gdb_connection->frontend_state == TARGET_RUNNING) { /* stop forwarding log packets! */ gdb_connection->output_flag = GDB_OUTPUT_NO; /* check fileio first */ if (target_get_gdb_fileio_info(target, target->fileio_info) == ERROR_OK) gdb_fileio_reply(target, connection); else gdb_signal_reply(target, connection); } } static int gdb_target_callback_event_handler(struct target *target, enum target_event event, void *priv) { struct connection *connection = priv; struct gdb_service *gdb_service = connection->service->priv; if (gdb_service->target != target) return ERROR_OK; switch (event) { case TARGET_EVENT_GDB_HALT: gdb_frontend_halted(target, connection); break; case TARGET_EVENT_HALTED: target_call_event_callbacks(target, TARGET_EVENT_GDB_END); break; default: break; } return ERROR_OK; } static int gdb_new_connection(struct connection *connection) { struct gdb_connection *gdb_connection = malloc(sizeof(struct gdb_connection)); struct target *target; int retval; int initial_ack; target = get_target_from_connection(connection); connection->priv = gdb_connection; connection->cmd_ctx->current_target = target; /* initialize gdb connection information */ gdb_connection->buf_p = gdb_connection->buffer; gdb_connection->buf_cnt = 0; gdb_connection->ctrl_c = false; gdb_connection->frontend_state = TARGET_HALTED; gdb_connection->vflash_image = NULL; gdb_connection->closed = false; gdb_connection->busy = false; gdb_connection->noack_mode = 0; gdb_connection->sync = false; gdb_connection->mem_write_error = false; gdb_connection->attached = true; gdb_connection->extended_protocol = false; gdb_connection->target_desc.tdesc = NULL; gdb_connection->target_desc.tdesc_length = 0; gdb_connection->thread_list = NULL; gdb_connection->output_flag = GDB_OUTPUT_NO; /* send ACK to GDB for debug request */ gdb_write(connection, "+", 1); /* output goes through gdb connection */ command_set_output_handler(connection->cmd_ctx, gdb_output, connection); /* we must remove all breakpoints registered to the target as a previous * GDB session could leave dangling breakpoints if e.g. communication * timed out. */ breakpoint_clear_target(target); watchpoint_clear_target(target); /* Since version 3.95 (gdb-19990504), with the exclusion of 6.5~6.8, GDB * sends an ACK at connection with the following comment in its source code: * "Ack any packet which the remote side has already sent." * LLDB does the same since the first gdb-remote implementation. * Remove the initial ACK from the incoming buffer. */ retval = gdb_get_char(connection, &initial_ack); if (retval != ERROR_OK) return retval; if (initial_ack != '+') gdb_putback_char(connection, initial_ack); target_call_event_callbacks(target, TARGET_EVENT_GDB_ATTACH); if (target->rtos) { /* clean previous rtos session if supported*/ if (target->rtos->type->clean) target->rtos->type->clean(target); /* update threads */ rtos_update_threads(target); } if (gdb_use_memory_map) { /* Connect must fail if the memory map can't be set up correctly. * * This will cause an auto_probe to be invoked, which is either * a no-op or it will fail when the target isn't ready(e.g. not halted). */ for (unsigned int i = 0; i < flash_get_bank_count(); i++) { struct flash_bank *p; p = get_flash_bank_by_num_noprobe(i); if (p->target != target) continue; retval = get_flash_bank_by_num(i, &p); if (retval != ERROR_OK) { LOG_ERROR("Connect failed. Consider setting up a gdb-attach event for the target " "to prepare target for GDB connect, or use 'gdb_memory_map disable'."); return retval; } } } gdb_actual_connections++; log_printf_lf(all_targets->next ? LOG_LVL_INFO : LOG_LVL_DEBUG, __FILE__, __LINE__, __func__, "New GDB Connection: %d, Target %s, state: %s", gdb_actual_connections, target_name(target), target_state_name(target)); if (!target_was_examined(target)) { LOG_ERROR("Target %s not examined yet, refuse gdb connection %d!", target_name(target), gdb_actual_connections); gdb_actual_connections--; return ERROR_TARGET_NOT_EXAMINED; } if (target->state != TARGET_HALTED) LOG_WARNING("GDB connection %d on target %s not halted", gdb_actual_connections, target_name(target)); /* DANGER! If we fail subsequently, we must remove this handler, * otherwise we occasionally see crashes as the timer can invoke the * callback fn. * * register callback to be informed about target events */ target_register_event_callback(gdb_target_callback_event_handler, connection); log_add_callback(gdb_log_callback, connection); return ERROR_OK; } static int gdb_connection_closed(struct connection *connection) { struct target *target; struct gdb_connection *gdb_connection = connection->priv; target = get_target_from_connection(connection); /* we're done forwarding messages. Tear down callback before * cleaning up connection. */ log_remove_callback(gdb_log_callback, connection); gdb_actual_connections--; LOG_DEBUG("GDB Close, Target: %s, state: %s, gdb_actual_connections=%d", target_name(target), target_state_name(target), gdb_actual_connections); /* see if an image built with vFlash commands is left */ if (gdb_connection->vflash_image) { image_close(gdb_connection->vflash_image); free(gdb_connection->vflash_image); gdb_connection->vflash_image = NULL; } /* if this connection registered a debug-message receiver delete it */ delete_debug_msg_receiver(connection->cmd_ctx, target); free(connection->priv); connection->priv = NULL; target_unregister_event_callback(gdb_target_callback_event_handler, connection); target_call_event_callbacks(target, TARGET_EVENT_GDB_END); target_call_event_callbacks(target, TARGET_EVENT_GDB_DETACH); return ERROR_OK; } static void gdb_send_error(struct connection *connection, uint8_t the_error) { char err[4]; snprintf(err, 4, "E%2.2X", the_error); gdb_put_packet(connection, err, 3); } static int gdb_last_signal_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); struct gdb_connection *gdb_con = connection->priv; char sig_reply[4]; int signal_var; if (!gdb_con->attached) { /* if we are here we have received a kill packet * reply W stop reply otherwise gdb gets very unhappy */ gdb_put_packet(connection, "W00", 3); return ERROR_OK; } signal_var = gdb_last_signal(target); snprintf(sig_reply, 4, "S%2.2x", signal_var); gdb_put_packet(connection, sig_reply, 3); return ERROR_OK; } static inline int gdb_reg_pos(struct target *target, int pos, int len) { if (target->endianness == TARGET_LITTLE_ENDIAN) return pos; else return len - 1 - pos; } /* Convert register to string of bytes. NB! The # of bits in the * register might be non-divisible by 8(a byte), in which * case an entire byte is shown. * * NB! the format on the wire is the target endianness * * The format of reg->value is little endian * */ static void gdb_str_to_target(struct target *target, char *tstr, struct reg *reg) { int i; uint8_t *buf; int buf_len; buf = reg->value; buf_len = DIV_ROUND_UP(reg->size, 8); for (i = 0; i < buf_len; i++) { int j = gdb_reg_pos(target, i, buf_len); tstr += sprintf(tstr, "%02x", buf[j]); } } /* copy over in register buffer */ static void gdb_target_to_reg(struct target *target, char const *tstr, int str_len, uint8_t *bin) { if (str_len % 2) { LOG_ERROR("BUG: gdb value with uneven number of characters encountered"); exit(-1); } int i; for (i = 0; i < str_len; i += 2) { unsigned t; if (sscanf(tstr + i, "%02x", &t) != 1) { LOG_ERROR("BUG: unable to convert register value"); exit(-1); } int j = gdb_reg_pos(target, i/2, str_len/2); bin[j] = t; } } static int gdb_get_registers_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); struct reg **reg_list; int reg_list_size; int retval; int reg_packet_size = 0; char *reg_packet; char *reg_packet_p; int i; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("-"); #endif if ((target->rtos) && (rtos_get_gdb_reg_list(connection) == ERROR_OK)) return ERROR_OK; retval = target_get_gdb_reg_list(target, ®_list, ®_list_size, REG_CLASS_GENERAL); if (retval != ERROR_OK) return gdb_error(connection, retval); for (i = 0; i < reg_list_size; i++) { if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden) continue; reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2; } assert(reg_packet_size > 0); reg_packet = malloc(reg_packet_size + 1); /* plus one for string termination null */ if (!reg_packet) return ERROR_FAIL; reg_packet_p = reg_packet; for (i = 0; i < reg_list_size; i++) { if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden) continue; if (!reg_list[i]->valid) { retval = reg_list[i]->type->get(reg_list[i]); if (retval != ERROR_OK && gdb_report_register_access_error) { LOG_DEBUG("Couldn't get register %s.", reg_list[i]->name); free(reg_packet); free(reg_list); return gdb_error(connection, retval); } } gdb_str_to_target(target, reg_packet_p, reg_list[i]); reg_packet_p += DIV_ROUND_UP(reg_list[i]->size, 8) * 2; } #ifdef _DEBUG_GDB_IO_ { char *reg_packet_p_debug; reg_packet_p_debug = strndup(reg_packet, reg_packet_size); LOG_DEBUG("reg_packet: %s", reg_packet_p_debug); free(reg_packet_p_debug); } #endif gdb_put_packet(connection, reg_packet, reg_packet_size); free(reg_packet); free(reg_list); return ERROR_OK; } static int gdb_set_registers_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); int i; struct reg **reg_list; int reg_list_size; int retval; char const *packet_p; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("-"); #endif /* skip command character */ packet++; packet_size--; if (packet_size % 2) { LOG_WARNING("GDB set_registers packet with uneven characters received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } retval = target_get_gdb_reg_list(target, ®_list, ®_list_size, REG_CLASS_GENERAL); if (retval != ERROR_OK) return gdb_error(connection, retval); packet_p = packet; for (i = 0; i < reg_list_size; i++) { uint8_t *bin_buf; if (!reg_list[i] || !reg_list[i]->exist || reg_list[i]->hidden) continue; int chars = (DIV_ROUND_UP(reg_list[i]->size, 8) * 2); if (packet_p + chars > packet + packet_size) LOG_ERROR("BUG: register packet is too small for registers"); bin_buf = malloc(DIV_ROUND_UP(reg_list[i]->size, 8)); gdb_target_to_reg(target, packet_p, chars, bin_buf); retval = reg_list[i]->type->set(reg_list[i], bin_buf); if (retval != ERROR_OK && gdb_report_register_access_error) { LOG_DEBUG("Couldn't set register %s.", reg_list[i]->name); free(reg_list); free(bin_buf); return gdb_error(connection, retval); } /* advance packet pointer */ packet_p += chars; free(bin_buf); } /* free struct reg *reg_list[] array allocated by get_gdb_reg_list */ free(reg_list); gdb_put_packet(connection, "OK", 2); return ERROR_OK; } static int gdb_get_register_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); char *reg_packet; int reg_num = strtoul(packet + 1, NULL, 16); struct reg **reg_list; int reg_list_size; int retval; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("-"); #endif if ((target->rtos) && (rtos_get_gdb_reg(connection, reg_num) == ERROR_OK)) return ERROR_OK; retval = target_get_gdb_reg_list_noread(target, ®_list, ®_list_size, REG_CLASS_ALL); if (retval != ERROR_OK) return gdb_error(connection, retval); if ((reg_list_size <= reg_num) || !reg_list[reg_num] || !reg_list[reg_num]->exist || reg_list[reg_num]->hidden) { LOG_ERROR("gdb requested a non-existing register (reg_num=%d)", reg_num); return ERROR_SERVER_REMOTE_CLOSED; } if (!reg_list[reg_num]->valid) { retval = reg_list[reg_num]->type->get(reg_list[reg_num]); if (retval != ERROR_OK && gdb_report_register_access_error) { LOG_DEBUG("Couldn't get register %s.", reg_list[reg_num]->name); free(reg_list); return gdb_error(connection, retval); } } reg_packet = calloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1, 1); /* plus one for string termination null */ gdb_str_to_target(target, reg_packet, reg_list[reg_num]); gdb_put_packet(connection, reg_packet, DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2); free(reg_list); free(reg_packet); return ERROR_OK; } static int gdb_set_register_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); char *separator; int reg_num = strtoul(packet + 1, &separator, 16); struct reg **reg_list; int reg_list_size; int retval; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("-"); #endif if (*separator != '=') { LOG_ERROR("GDB 'set register packet', but no '=' following the register number"); return ERROR_SERVER_REMOTE_CLOSED; } size_t chars = strlen(separator + 1); uint8_t *bin_buf = malloc(chars / 2); gdb_target_to_reg(target, separator + 1, chars, bin_buf); if ((target->rtos) && (rtos_set_reg(connection, reg_num, bin_buf) == ERROR_OK)) { free(bin_buf); gdb_put_packet(connection, "OK", 2); return ERROR_OK; } retval = target_get_gdb_reg_list_noread(target, ®_list, ®_list_size, REG_CLASS_ALL); if (retval != ERROR_OK) { free(bin_buf); return gdb_error(connection, retval); } if ((reg_list_size <= reg_num) || !reg_list[reg_num] || !reg_list[reg_num]->exist || reg_list[reg_num]->hidden) { LOG_ERROR("gdb requested a non-existing register (reg_num=%d)", reg_num); free(bin_buf); free(reg_list); return ERROR_SERVER_REMOTE_CLOSED; } if (chars != (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2)) { LOG_ERROR("gdb sent %zu bits for a %" PRIu32 "-bit register (%s)", chars * 4, reg_list[reg_num]->size, reg_list[reg_num]->name); free(bin_buf); free(reg_list); return ERROR_SERVER_REMOTE_CLOSED; } gdb_target_to_reg(target, separator + 1, chars, bin_buf); retval = reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf); if (retval != ERROR_OK && gdb_report_register_access_error) { LOG_DEBUG("Couldn't set register %s.", reg_list[reg_num]->name); free(bin_buf); free(reg_list); return gdb_error(connection, retval); } gdb_put_packet(connection, "OK", 2); free(bin_buf); free(reg_list); return ERROR_OK; } /* No attempt is made to translate the "retval" to * GDB speak. This has to be done at the calling * site as no mapping really exists. */ static int gdb_error(struct connection *connection, int retval) { LOG_DEBUG("Reporting %i to GDB as generic error", retval); gdb_send_error(connection, EFAULT); return ERROR_OK; } /* We don't have to worry about the default 2 second timeout for GDB packets, * because GDB breaks up large memory reads into smaller reads. */ static int gdb_read_memory_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); char *separator; uint64_t addr = 0; uint32_t len = 0; uint8_t *buffer; char *hex_buffer; int retval = ERROR_OK; /* skip command character */ packet++; addr = strtoull(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete read memory packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } len = strtoul(separator + 1, NULL, 16); if (!len) { LOG_WARNING("invalid read memory packet received (len == 0)"); gdb_put_packet(connection, "", 0); return ERROR_OK; } buffer = malloc(len); LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); retval = ERROR_NOT_IMPLEMENTED; if (target->rtos) retval = rtos_read_buffer(target, addr, len, buffer); if (retval == ERROR_NOT_IMPLEMENTED) retval = target_read_buffer(target, addr, len, buffer); if ((retval != ERROR_OK) && !gdb_report_data_abort) { /* TODO : Here we have to lie and send back all zero's lest stack traces won't work. * At some point this might be fixed in GDB, in which case this code can be removed. * * OpenOCD developers are acutely aware of this problem, but there is nothing * gained by involving the user in this problem that hopefully will get resolved * eventually * * http://sourceware.org/cgi-bin/gnatsweb.pl? \ * cmd = view%20audit-trail&database = gdb&pr = 2395 * * For now, the default is to fix up things to make current GDB versions work. * This can be overwritten using the gdb_report_data_abort <'enable'|'disable'> command. */ memset(buffer, 0, len); retval = ERROR_OK; } if (retval == ERROR_OK) { hex_buffer = malloc(len * 2 + 1); size_t pkt_len = hexify(hex_buffer, buffer, len, len * 2 + 1); gdb_put_packet(connection, hex_buffer, pkt_len); free(hex_buffer); } else retval = gdb_error(connection, retval); free(buffer); return retval; } static int gdb_write_memory_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); char *separator; uint64_t addr = 0; uint32_t len = 0; uint8_t *buffer; int retval; /* skip command character */ packet++; addr = strtoull(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete write memory packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } len = strtoul(separator + 1, &separator, 16); if (*(separator++) != ':') { LOG_ERROR("incomplete write memory packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } buffer = malloc(len); LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); if (unhexify(buffer, separator, len) != len) LOG_ERROR("unable to decode memory packet"); retval = ERROR_NOT_IMPLEMENTED; if (target->rtos) retval = rtos_write_buffer(target, addr, len, buffer); if (retval == ERROR_NOT_IMPLEMENTED) retval = target_write_buffer(target, addr, len, buffer); if (retval == ERROR_OK) gdb_put_packet(connection, "OK", 2); else retval = gdb_error(connection, retval); free(buffer); return retval; } static int gdb_write_memory_binary_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); char *separator; uint64_t addr = 0; uint32_t len = 0; int retval = ERROR_OK; /* Packets larger than fast_limit bytes will be acknowledged instantly on * the assumption that we're in a download and it's important to go as fast * as possible. */ uint32_t fast_limit = 8; /* skip command character */ packet++; addr = strtoull(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete write memory binary packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } len = strtoul(separator + 1, &separator, 16); if (*(separator++) != ':') { LOG_ERROR("incomplete write memory binary packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } struct gdb_connection *gdb_connection = connection->priv; if (gdb_connection->mem_write_error) retval = ERROR_FAIL; if (retval == ERROR_OK) { if (len >= fast_limit) { /* By replying the packet *immediately* GDB will send us a new packet * while we write the last one to the target. * We only do this for larger writes, so that users who do something like: * p *((int*)0xdeadbeef)=8675309 * will get immediate feedback that that write failed. */ gdb_put_packet(connection, "OK", 2); } } else { retval = gdb_error(connection, retval); /* now that we have reported the memory write error, we can clear the condition */ gdb_connection->mem_write_error = false; if (retval != ERROR_OK) return retval; } if (len) { LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); retval = ERROR_NOT_IMPLEMENTED; if (target->rtos) retval = rtos_write_buffer(target, addr, len, (uint8_t *)separator); if (retval == ERROR_NOT_IMPLEMENTED) retval = target_write_buffer(target, addr, len, (uint8_t *)separator); if (retval != ERROR_OK) gdb_connection->mem_write_error = true; } if (len < fast_limit) { if (retval != ERROR_OK) { gdb_error(connection, retval); gdb_connection->mem_write_error = false; } else { gdb_put_packet(connection, "OK", 2); } } return ERROR_OK; } static int gdb_step_continue_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); int current = 0; uint64_t address = 0x0; int retval = ERROR_OK; LOG_DEBUG("-"); if (packet_size > 1) address = strtoull(packet + 1, NULL, 16); else current = 1; gdb_running_type = packet[0]; if (packet[0] == 'c') { LOG_DEBUG("continue"); /* resume at current address, don't handle breakpoints, not debugging */ retval = target_resume(target, current, address, 0, 0); } else if (packet[0] == 's') { LOG_DEBUG("step"); /* step at current or address, don't handle breakpoints */ retval = target_step(target, current, address, 0); } return retval; } static int gdb_breakpoint_watchpoint_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); int type; enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */; enum watchpoint_rw wp_type = WPT_READ /* dummy init to avoid warning */; uint64_t address; uint32_t size; char *separator; int retval; LOG_DEBUG("[%s]", target_name(target)); type = strtoul(packet + 1, &separator, 16); if (type == 0) /* memory breakpoint */ bp_type = BKPT_SOFT; else if (type == 1) /* hardware breakpoint */ bp_type = BKPT_HARD; else if (type == 2) /* write watchpoint */ wp_type = WPT_WRITE; else if (type == 3) /* read watchpoint */ wp_type = WPT_READ; else if (type == 4) /* access watchpoint */ wp_type = WPT_ACCESS; else { LOG_ERROR("invalid gdb watch/breakpoint type(%d), dropping connection", type); return ERROR_SERVER_REMOTE_CLOSED; } if (gdb_breakpoint_override && ((bp_type == BKPT_SOFT) || (bp_type == BKPT_HARD))) bp_type = gdb_breakpoint_override_type; if (*separator != ',') { LOG_ERROR("incomplete breakpoint/watchpoint packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } address = strtoull(separator + 1, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete breakpoint/watchpoint packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } size = strtoul(separator + 1, &separator, 16); switch (type) { case 0: case 1: if (packet[0] == 'Z') { retval = breakpoint_add(target, address, size, bp_type); if (retval == ERROR_NOT_IMPLEMENTED) { /* Send empty reply to report that breakpoints of this type are not supported */ gdb_put_packet(connection, "", 0); } else if (retval != ERROR_OK) { retval = gdb_error(connection, retval); if (retval != ERROR_OK) return retval; } else gdb_put_packet(connection, "OK", 2); } else { breakpoint_remove(target, address); gdb_put_packet(connection, "OK", 2); } break; case 2: case 3: case 4: { if (packet[0] == 'Z') { retval = watchpoint_add(target, address, size, wp_type, 0, 0xffffffffu); if (retval == ERROR_NOT_IMPLEMENTED) { /* Send empty reply to report that watchpoints of this type are not supported */ gdb_put_packet(connection, "", 0); } else if (retval != ERROR_OK) { retval = gdb_error(connection, retval); if (retval != ERROR_OK) return retval; } else gdb_put_packet(connection, "OK", 2); } else { watchpoint_remove(target, address); gdb_put_packet(connection, "OK", 2); } break; } default: break; } return ERROR_OK; } /* print out a string and allocate more space as needed, * mainly used for XML at this point */ static __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6))) void xml_printf(int *retval, char **xml, int *pos, int *size, const char *fmt, ...) { if (*retval != ERROR_OK) return; int first = 1; for (;; ) { if ((!*xml) || (!first)) { /* start by 0 to exercise all the code paths. * Need minimum 2 bytes to fit 1 char and 0 terminator. */ *size = *size * 2 + 2; char *t = *xml; *xml = realloc(*xml, *size); if (!*xml) { free(t); *retval = ERROR_SERVER_REMOTE_CLOSED; return; } } va_list ap; int ret; va_start(ap, fmt); ret = vsnprintf(*xml + *pos, *size - *pos, fmt, ap); va_end(ap); if ((ret > 0) && ((ret + 1) < *size - *pos)) { *pos += ret; return; } /* there was just enough or not enough space, allocate more. */ first = 0; } } static int decode_xfer_read(char const *buf, char **annex, int *ofs, unsigned int *len) { /* Locate the annex. */ const char *annex_end = strchr(buf, ':'); if (!annex_end) return ERROR_FAIL; /* After the read marker and annex, qXfer looks like a * traditional 'm' packet. */ char *separator; *ofs = strtoul(annex_end + 1, &separator, 16); if (*separator != ',') return ERROR_FAIL; *len = strtoul(separator + 1, NULL, 16); /* Extract the annex if needed */ if (annex) { *annex = strndup(buf, annex_end - buf); if (!*annex) return ERROR_FAIL; } return ERROR_OK; } static int compare_bank(const void *a, const void *b) { struct flash_bank *b1, *b2; b1 = *((struct flash_bank **)a); b2 = *((struct flash_bank **)b); if (b1->base == b2->base) return 0; else if (b1->base > b2->base) return 1; else return -1; } static int gdb_memory_map(struct connection *connection, char const *packet, int packet_size) { /* We get away with only specifying flash here. Regions that are not * specified are treated as if we provided no memory map(if not we * could detect the holes and mark them as RAM). * Normally we only execute this code once, but no big deal if we * have to regenerate it a couple of times. */ struct target *target = get_target_from_connection(connection); struct flash_bank *p; char *xml = NULL; int size = 0; int pos = 0; int retval = ERROR_OK; struct flash_bank **banks; int offset; int length; char *separator; target_addr_t ram_start = 0; unsigned int target_flash_banks = 0; /* skip command character */ packet += 23; offset = strtoul(packet, &separator, 16); length = strtoul(separator + 1, &separator, 16); xml_printf(&retval, &xml, &pos, &size, "<memory-map>\n"); /* Sort banks in ascending order. We need to report non-flash * memory as ram (or rather read/write) by default for GDB, since * it has no concept of non-cacheable read/write memory (i/o etc). */ banks = malloc(sizeof(struct flash_bank *)*flash_get_bank_count()); for (unsigned int i = 0; i < flash_get_bank_count(); i++) { p = get_flash_bank_by_num_noprobe(i); if (p->target != target) continue; retval = get_flash_bank_by_num(i, &p); if (retval != ERROR_OK) { free(banks); gdb_error(connection, retval); return retval; } banks[target_flash_banks++] = p; } qsort(banks, target_flash_banks, sizeof(struct flash_bank *), compare_bank); for (unsigned int i = 0; i < target_flash_banks; i++) { unsigned sector_size = 0; unsigned group_len = 0; p = banks[i]; if (ram_start < p->base) xml_printf(&retval, &xml, &pos, &size, "<memory type=\"ram\" start=\"" TARGET_ADDR_FMT "\" " "length=\"" TARGET_ADDR_FMT "\"/>\n", ram_start, p->base - ram_start); /* Report adjacent groups of same-size sectors. So for * example top boot CFI flash will list an initial region * with several large sectors (maybe 128KB) and several * smaller ones at the end (maybe 32KB). STR7 will have * regions with 8KB, 32KB, and 64KB sectors; etc. */ for (unsigned int j = 0; j < p->num_sectors; j++) { /* Maybe start a new group of sectors. */ if (sector_size == 0) { if (p->sectors[j].offset + p->sectors[j].size > p->size) { LOG_WARNING("The flash sector at offset 0x%08" PRIx32 " overflows the end of %s bank.", p->sectors[j].offset, p->name); LOG_WARNING("The rest of bank will not show in gdb memory map."); break; } target_addr_t start; start = p->base + p->sectors[j].offset; xml_printf(&retval, &xml, &pos, &size, "<memory type=\"flash\" " "start=\"" TARGET_ADDR_FMT "\" ", start); sector_size = p->sectors[j].size; group_len = sector_size; } else { group_len += sector_size; /* equal to p->sectors[j].size */ } /* Does this finish a group of sectors? * If not, continue an already-started group. */ if (j < p->num_sectors - 1 && p->sectors[j + 1].size == sector_size && p->sectors[j + 1].offset == p->sectors[j].offset + sector_size && p->sectors[j + 1].offset + p->sectors[j + 1].size <= p->size) continue; xml_printf(&retval, &xml, &pos, &size, "length=\"0x%x\">\n" "<property name=\"blocksize\">" "0x%x</property>\n" "</memory>\n", group_len, sector_size); sector_size = 0; } ram_start = p->base + p->size; } if (ram_start != 0) xml_printf(&retval, &xml, &pos, &size, "<memory type=\"ram\" start=\"" TARGET_ADDR_FMT "\" " "length=\"" TARGET_ADDR_FMT "\"/>\n", ram_start, target_address_max(target) - ram_start + 1); /* ELSE a flash chip could be at the very end of the address space, in * which case ram_start will be precisely 0 */ free(banks); xml_printf(&retval, &xml, &pos, &size, "</memory-map>\n"); if (retval != ERROR_OK) { free(xml); gdb_error(connection, retval); return retval; } if (offset + length > pos) length = pos - offset; char *t = malloc(length + 1); t[0] = 'l'; memcpy(t + 1, xml + offset, length); gdb_put_packet(connection, t, length + 1); free(t); free(xml); return ERROR_OK; } static const char *gdb_get_reg_type_name(enum reg_type type) { switch (type) { case REG_TYPE_BOOL: return "bool"; case REG_TYPE_INT: return "int"; case REG_TYPE_INT8: return "int8"; case REG_TYPE_INT16: return "int16"; case REG_TYPE_INT32: return "int32"; case REG_TYPE_INT64: return "int64"; case REG_TYPE_INT128: return "int128"; case REG_TYPE_UINT: return "uint"; case REG_TYPE_UINT8: return "uint8"; case REG_TYPE_UINT16: return "uint16"; case REG_TYPE_UINT32: return "uint32"; case REG_TYPE_UINT64: return "uint64"; case REG_TYPE_UINT128: return "uint128"; case REG_TYPE_CODE_PTR: return "code_ptr"; case REG_TYPE_DATA_PTR: return "data_ptr"; case REG_TYPE_FLOAT: return "float"; case REG_TYPE_IEEE_SINGLE: return "ieee_single"; case REG_TYPE_IEEE_DOUBLE: return "ieee_double"; case REG_TYPE_ARCH_DEFINED: return "int"; /* return arbitrary string to avoid compile warning. */ } return "int"; /* "int" as default value */ } static int lookup_add_arch_defined_types(char const **arch_defined_types_list[], const char *type_id, int *num_arch_defined_types) { int tbl_sz = *num_arch_defined_types; if (type_id && (strcmp(type_id, ""))) { for (int j = 0; j < (tbl_sz + 1); j++) { if (!((*arch_defined_types_list)[j])) { (*arch_defined_types_list)[tbl_sz++] = type_id; *arch_defined_types_list = realloc(*arch_defined_types_list, sizeof(char *) * (tbl_sz + 1)); (*arch_defined_types_list)[tbl_sz] = NULL; *num_arch_defined_types = tbl_sz; return 1; } else { if (!strcmp((*arch_defined_types_list)[j], type_id)) return 0; } } } return -1; } static int gdb_generate_reg_type_description(struct target *target, char **tdesc, int *pos, int *size, struct reg_data_type *type, char const **arch_defined_types_list[], int *num_arch_defined_types) { int retval = ERROR_OK; if (type->type_class == REG_TYPE_CLASS_VECTOR) { struct reg_data_type *data_type = type->reg_type_vector->type; if (data_type->type == REG_TYPE_ARCH_DEFINED) { if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id, num_arch_defined_types)) gdb_generate_reg_type_description(target, tdesc, pos, size, data_type, arch_defined_types_list, num_arch_defined_types); } /* <vector id="id" type="type" count="count"/> */ xml_printf(&retval, tdesc, pos, size, "<vector id=\"%s\" type=\"%s\" count=\"%" PRIu32 "\"/>\n", type->id, type->reg_type_vector->type->id, type->reg_type_vector->count); } else if (type->type_class == REG_TYPE_CLASS_UNION) { struct reg_data_type_union_field *field; field = type->reg_type_union->fields; while (field) { struct reg_data_type *data_type = field->type; if (data_type->type == REG_TYPE_ARCH_DEFINED) { if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id, num_arch_defined_types)) gdb_generate_reg_type_description(target, tdesc, pos, size, data_type, arch_defined_types_list, num_arch_defined_types); } field = field->next; } /* <union id="id"> * <field name="name" type="type"/> ... * </union> */ xml_printf(&retval, tdesc, pos, size, "<union id=\"%s\">\n", type->id); field = type->reg_type_union->fields; while (field) { xml_printf(&retval, tdesc, pos, size, "<field name=\"%s\" type=\"%s\"/>\n", field->name, field->type->id); field = field->next; } xml_printf(&retval, tdesc, pos, size, "</union>\n"); } else if (type->type_class == REG_TYPE_CLASS_STRUCT) { struct reg_data_type_struct_field *field; field = type->reg_type_struct->fields; if (field->use_bitfields) { /* <struct id="id" size="size"> * <field name="name" start="start" end="end"/> ... * </struct> */ xml_printf(&retval, tdesc, pos, size, "<struct id=\"%s\" size=\"%" PRIu32 "\">\n", type->id, type->reg_type_struct->size); while (field) { xml_printf(&retval, tdesc, pos, size, "<field name=\"%s\" start=\"%" PRIu32 "\" end=\"%" PRIu32 "\" type=\"%s\" />\n", field->name, field->bitfield->start, field->bitfield->end, gdb_get_reg_type_name(field->bitfield->type)); field = field->next; } } else { while (field) { struct reg_data_type *data_type = field->type; if (data_type->type == REG_TYPE_ARCH_DEFINED) { if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id, num_arch_defined_types)) gdb_generate_reg_type_description(target, tdesc, pos, size, data_type, arch_defined_types_list, num_arch_defined_types); } } /* <struct id="id"> * <field name="name" type="type"/> ... * </struct> */ xml_printf(&retval, tdesc, pos, size, "<struct id=\"%s\">\n", type->id); while (field) { xml_printf(&retval, tdesc, pos, size, "<field name=\"%s\" type=\"%s\"/>\n", field->name, field->type->id); field = field->next; } } xml_printf(&retval, tdesc, pos, size, "</struct>\n"); } else if (type->type_class == REG_TYPE_CLASS_FLAGS) { /* <flags id="id" size="size"> * <field name="name" start="start" end="end"/> ... * </flags> */ xml_printf(&retval, tdesc, pos, size, "<flags id=\"%s\" size=\"%" PRIu32 "\">\n", type->id, type->reg_type_flags->size); struct reg_data_type_flags_field *field; field = type->reg_type_flags->fields; while (field) { xml_printf(&retval, tdesc, pos, size, "<field name=\"%s\" start=\"%" PRIu32 "\" end=\"%" PRIu32 "\" type=\"%s\" />\n", field->name, field->bitfield->start, field->bitfield->end, gdb_get_reg_type_name(field->bitfield->type)); field = field->next; } xml_printf(&retval, tdesc, pos, size, "</flags>\n"); } return ERROR_OK; } /* Get a list of available target registers features. feature_list must * be freed by caller. */ static int get_reg_features_list(struct target *target, char const **feature_list[], int *feature_list_size, struct reg **reg_list, int reg_list_size) { int tbl_sz = 0; /* Start with only one element */ *feature_list = calloc(1, sizeof(char *)); for (int i = 0; i < reg_list_size; i++) { if (reg_list[i]->exist == false || reg_list[i]->hidden) continue; if (reg_list[i]->feature && reg_list[i]->feature->name && (strcmp(reg_list[i]->feature->name, ""))) { /* We found a feature, check if the feature is already in the * table. If not, allocate a new entry for the table and * put the new feature in it. */ for (int j = 0; j < (tbl_sz + 1); j++) { if (!((*feature_list)[j])) { (*feature_list)[tbl_sz++] = reg_list[i]->feature->name; *feature_list = realloc(*feature_list, sizeof(char *) * (tbl_sz + 1)); (*feature_list)[tbl_sz] = NULL; break; } else { if (!strcmp((*feature_list)[j], reg_list[i]->feature->name)) break; } } } } if (feature_list_size) *feature_list_size = tbl_sz; return ERROR_OK; } /* Create a register list that's the union of all the registers of the SMP * group this target is in. If the target is not part of an SMP group, this * returns the same as target_get_gdb_reg_list_noread(). */ static int smp_reg_list_noread(struct target *target, struct reg **combined_list[], int *combined_list_size, enum target_register_class reg_class) { if (!target->smp) return target_get_gdb_reg_list_noread(target, combined_list, combined_list_size, REG_CLASS_ALL); unsigned int combined_allocated = 256; struct reg **local_list = malloc(combined_allocated * sizeof(struct reg *)); if (!local_list) { LOG_ERROR("malloc(%zu) failed", combined_allocated * sizeof(struct reg *)); return ERROR_FAIL; } unsigned int local_list_size = 0; struct target_list *head; foreach_smp_target(head, target->smp_targets) { if (!target_was_examined(head->target)) continue; struct reg **reg_list = NULL; int reg_list_size; int result = target_get_gdb_reg_list_noread(head->target, ®_list, ®_list_size, reg_class); if (result != ERROR_OK) { free(local_list); return result; } for (int i = 0; i < reg_list_size; i++) { bool found = false; struct reg *a = reg_list[i]; if (a->exist) { /* Nested loop makes this O(n^2), but this entire function with * 5 RISC-V targets takes just 2ms on my computer. Fast enough * for me. */ for (unsigned int j = 0; j < local_list_size; j++) { struct reg *b = local_list[j]; if (!strcmp(a->name, b->name)) { found = true; if (a->size != b->size) { LOG_ERROR("SMP register %s is %d bits on one " "target, but %d bits on another target.", a->name, a->size, b->size); free(reg_list); free(local_list); return ERROR_FAIL; } break; } } if (!found) { LOG_DEBUG("[%s] %s not found in combined list", target_name(target), a->name); if (local_list_size >= combined_allocated) { combined_allocated *= 2; local_list = realloc(local_list, combined_allocated * sizeof(struct reg *)); if (!local_list) { LOG_ERROR("realloc(%zu) failed", combined_allocated * sizeof(struct reg *)); free(reg_list); return ERROR_FAIL; } } local_list[local_list_size] = a; local_list_size++; } } } free(reg_list); } if (local_list_size == 0) { LOG_ERROR("Unable to get register list"); free(local_list); return ERROR_FAIL; } /* Now warn the user about any registers that weren't found in every target. */ foreach_smp_target(head, target->smp_targets) { if (!target_was_examined(head->target)) continue; struct reg **reg_list = NULL; int reg_list_size; int result = target_get_gdb_reg_list_noread(head->target, ®_list, ®_list_size, reg_class); if (result != ERROR_OK) { free(local_list); return result; } for (unsigned int i = 0; i < local_list_size; i++) { bool found = false; struct reg *a = local_list[i]; for (int j = 0; j < reg_list_size; j++) { struct reg *b = reg_list[j]; if (b->exist && !strcmp(a->name, b->name)) { found = true; break; } } if (!found) { LOG_WARNING("Register %s does not exist in %s, which is part of an SMP group where " "this register does exist.", a->name, target_name(head->target)); } } free(reg_list); } *combined_list = local_list; *combined_list_size = local_list_size; return ERROR_OK; } static int gdb_generate_target_description(struct target *target, char **tdesc_out) { int retval = ERROR_OK; struct reg **reg_list = NULL; int reg_list_size; char const *architecture; char const **features = NULL; int feature_list_size = 0; char *tdesc = NULL; int pos = 0; int size = 0; retval = smp_reg_list_noread(target, ®_list, ®_list_size, REG_CLASS_ALL); if (retval != ERROR_OK) { LOG_ERROR("get register list failed"); retval = ERROR_FAIL; goto error; } if (reg_list_size <= 0) { LOG_ERROR("get register list failed"); retval = ERROR_FAIL; goto error; } /* Get a list of available target registers features */ retval = get_reg_features_list(target, &features, &feature_list_size, reg_list, reg_list_size); if (retval != ERROR_OK) { LOG_ERROR("Can't get the registers feature list"); retval = ERROR_FAIL; goto error; } /* If we found some features associated with registers, create sections */ int current_feature = 0; xml_printf(&retval, &tdesc, &pos, &size, "<?xml version=\"1.0\"?>\n" "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">\n" "<target version=\"1.0\">\n"); /* generate architecture element if supported by target */ architecture = target_get_gdb_arch(target); if (architecture) xml_printf(&retval, &tdesc, &pos, &size, "<architecture>%s</architecture>\n", architecture); /* generate target description according to register list */ if (features) { while (features[current_feature]) { char const **arch_defined_types = NULL; int num_arch_defined_types = 0; arch_defined_types = calloc(1, sizeof(char *)); xml_printf(&retval, &tdesc, &pos, &size, "<feature name=\"%s\">\n", features[current_feature]); int i; for (i = 0; i < reg_list_size; i++) { if (reg_list[i]->exist == false || reg_list[i]->hidden) continue; if (strcmp(reg_list[i]->feature->name, features[current_feature])) continue; const char *type_str; if (reg_list[i]->reg_data_type) { if (reg_list[i]->reg_data_type->type == REG_TYPE_ARCH_DEFINED) { /* generate <type... first, if there are architecture-defined types. */ if (lookup_add_arch_defined_types(&arch_defined_types, reg_list[i]->reg_data_type->id, &num_arch_defined_types)) gdb_generate_reg_type_description(target, &tdesc, &pos, &size, reg_list[i]->reg_data_type, &arch_defined_types, &num_arch_defined_types); type_str = reg_list[i]->reg_data_type->id; } else { /* predefined type */ type_str = gdb_get_reg_type_name( reg_list[i]->reg_data_type->type); } } else { /* Default type is "int" */ type_str = "int"; } xml_printf(&retval, &tdesc, &pos, &size, "<reg name=\"%s\"", reg_list[i]->name); xml_printf(&retval, &tdesc, &pos, &size, " bitsize=\"%" PRIu32 "\"", reg_list[i]->size); xml_printf(&retval, &tdesc, &pos, &size, " regnum=\"%" PRIu32 "\"", reg_list[i]->number); if (reg_list[i]->caller_save) xml_printf(&retval, &tdesc, &pos, &size, " save-restore=\"yes\""); else xml_printf(&retval, &tdesc, &pos, &size, " save-restore=\"no\""); xml_printf(&retval, &tdesc, &pos, &size, " type=\"%s\"", type_str); if (reg_list[i]->group) xml_printf(&retval, &tdesc, &pos, &size, " group=\"%s\"", reg_list[i]->group); xml_printf(&retval, &tdesc, &pos, &size, "/>\n"); } xml_printf(&retval, &tdesc, &pos, &size, "</feature>\n"); current_feature++; free(arch_defined_types); } } xml_printf(&retval, &tdesc, &pos, &size, "</target>\n"); error: free(features); free(reg_list); if (retval == ERROR_OK) *tdesc_out = tdesc; else free(tdesc); return retval; } static int gdb_get_target_description_chunk(struct target *target, struct target_desc_format *target_desc, char **chunk, int32_t offset, uint32_t length) { if (!target_desc) { LOG_ERROR("Unable to Generate Target Description"); return ERROR_FAIL; } char *tdesc = target_desc->tdesc; uint32_t tdesc_length = target_desc->tdesc_length; if (!tdesc) { int retval = gdb_generate_target_description(target, &tdesc); if (retval != ERROR_OK) { LOG_ERROR("Unable to Generate Target Description"); return ERROR_FAIL; } tdesc_length = strlen(tdesc); } char transfer_type; if (length < (tdesc_length - offset)) transfer_type = 'm'; else transfer_type = 'l'; *chunk = malloc(length + 2); if (!*chunk) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; } (*chunk)[0] = transfer_type; if (transfer_type == 'm') { strncpy((*chunk) + 1, tdesc + offset, length); (*chunk)[1 + length] = '\0'; } else { strncpy((*chunk) + 1, tdesc + offset, tdesc_length - offset); (*chunk)[1 + (tdesc_length - offset)] = '\0'; /* After gdb-server sends out last chunk, invalidate tdesc. */ free(tdesc); tdesc = NULL; tdesc_length = 0; } target_desc->tdesc = tdesc; target_desc->tdesc_length = tdesc_length; return ERROR_OK; } static int gdb_target_description_supported(struct target *target, int *supported) { int retval = ERROR_OK; struct reg **reg_list = NULL; int reg_list_size = 0; char const **features = NULL; int feature_list_size = 0; char const *architecture = target_get_gdb_arch(target); retval = target_get_gdb_reg_list_noread(target, ®_list, ®_list_size, REG_CLASS_ALL); if (retval != ERROR_OK) { LOG_ERROR("get register list failed"); goto error; } if (reg_list_size <= 0) { LOG_ERROR("get register list failed"); retval = ERROR_FAIL; goto error; } /* Get a list of available target registers features */ retval = get_reg_features_list(target, &features, &feature_list_size, reg_list, reg_list_size); if (retval != ERROR_OK) { LOG_ERROR("Can't get the registers feature list"); goto error; } if (supported) { if (architecture || feature_list_size) *supported = 1; else *supported = 0; } error: free(features); free(reg_list); return retval; } static int gdb_generate_thread_list(struct target *target, char **thread_list_out) { struct rtos *rtos = target->rtos; int retval = ERROR_OK; char *thread_list = NULL; int pos = 0; int size = 0; xml_printf(&retval, &thread_list, &pos, &size, "<?xml version=\"1.0\"?>\n" "<threads>\n"); if (rtos) { for (int i = 0; i < rtos->thread_count; i++) { struct thread_detail *thread_detail = &rtos->thread_details[i]; if (!thread_detail->exists) continue; if (thread_detail->thread_name_str) xml_printf(&retval, &thread_list, &pos, &size, "<thread id=\"%" PRIx64 "\" name=\"%s\">", thread_detail->threadid, thread_detail->thread_name_str); else xml_printf(&retval, &thread_list, &pos, &size, "<thread id=\"%" PRIx64 "\">", thread_detail->threadid); if (thread_detail->thread_name_str) xml_printf(&retval, &thread_list, &pos, &size, "Name: %s", thread_detail->thread_name_str); if (thread_detail->extra_info_str) { if (thread_detail->thread_name_str) xml_printf(&retval, &thread_list, &pos, &size, ", "); xml_printf(&retval, &thread_list, &pos, &size, "%s", thread_detail->extra_info_str); } xml_printf(&retval, &thread_list, &pos, &size, "</thread>\n"); } } xml_printf(&retval, &thread_list, &pos, &size, "</threads>\n"); if (retval == ERROR_OK) *thread_list_out = thread_list; else free(thread_list); return retval; } static int gdb_get_thread_list_chunk(struct target *target, char **thread_list, char **chunk, int32_t offset, uint32_t length) { if (!*thread_list) { int retval = gdb_generate_thread_list(target, thread_list); if (retval != ERROR_OK) { LOG_ERROR("Unable to Generate Thread List"); return ERROR_FAIL; } } size_t thread_list_length = strlen(*thread_list); char transfer_type; length = MIN(length, thread_list_length - offset); if (length < (thread_list_length - offset)) transfer_type = 'm'; else transfer_type = 'l'; *chunk = malloc(length + 2 + 3); /* Allocating extra 3 bytes prevents false positive valgrind report * of strlen(chunk) word access: * Invalid read of size 4 * Address 0x4479934 is 44 bytes inside a block of size 45 alloc'd */ if (!*chunk) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; } (*chunk)[0] = transfer_type; strncpy((*chunk) + 1, (*thread_list) + offset, length); (*chunk)[1 + length] = '\0'; /* After gdb-server sends out last chunk, invalidate thread list. */ if (transfer_type == 'l') { free(*thread_list); *thread_list = NULL; } return ERROR_OK; } static int gdb_query_packet(struct connection *connection, char const *packet, int packet_size) { struct command_context *cmd_ctx = connection->cmd_ctx; struct gdb_connection *gdb_connection = connection->priv; struct target *target = get_target_from_connection(connection); if (strncmp(packet, "qRcmd,", 6) == 0) { if (packet_size > 6) { Jim_Interp *interp = cmd_ctx->interp; char *cmd; cmd = malloc((packet_size - 6) / 2 + 1); size_t len = unhexify((uint8_t *)cmd, packet + 6, (packet_size - 6) / 2); cmd[len] = 0; /* We want to print all debug output to GDB connection */ gdb_connection->output_flag = GDB_OUTPUT_ALL; target_call_timer_callbacks_now(); /* some commands need to know the GDB connection, make note of current * GDB connection. */ current_gdb_connection = gdb_connection; struct target *saved_target_override = cmd_ctx->current_target_override; cmd_ctx->current_target_override = NULL; struct command_context *old_context = Jim_GetAssocData(interp, "context"); Jim_DeleteAssocData(interp, "context"); int retval = Jim_SetAssocData(interp, "context", NULL, cmd_ctx); if (retval == JIM_OK) { retval = Jim_EvalObj(interp, Jim_NewStringObj(interp, cmd, -1)); Jim_DeleteAssocData(interp, "context"); } int inner_retval = Jim_SetAssocData(interp, "context", NULL, old_context); if (retval == JIM_OK) retval = inner_retval; cmd_ctx->current_target_override = saved_target_override; current_gdb_connection = NULL; target_call_timer_callbacks_now(); gdb_connection->output_flag = GDB_OUTPUT_NO; free(cmd); if (retval == JIM_RETURN) retval = interp->returnCode; int lenmsg; const char *cretmsg = Jim_GetString(Jim_GetResult(interp), &lenmsg); char *retmsg; if (lenmsg && cretmsg[lenmsg - 1] != '\n') { retmsg = alloc_printf("%s\n", cretmsg); lenmsg++; } else { retmsg = strdup(cretmsg); } if (!retmsg) return ERROR_GDB_BUFFER_TOO_SMALL; if (retval == JIM_OK) { if (lenmsg) { char *hex_buffer = malloc(lenmsg * 2 + 1); if (!hex_buffer) { free(retmsg); return ERROR_GDB_BUFFER_TOO_SMALL; } size_t pkt_len = hexify(hex_buffer, (const uint8_t *)retmsg, lenmsg, lenmsg * 2 + 1); gdb_put_packet(connection, hex_buffer, pkt_len); free(hex_buffer); } else { gdb_put_packet(connection, "OK", 2); } } else { if (lenmsg) gdb_output_con(connection, retmsg); gdb_send_error(connection, retval); } free(retmsg); return ERROR_OK; } gdb_put_packet(connection, "OK", 2); return ERROR_OK; } else if (strncmp(packet, "qCRC:", 5) == 0) { if (packet_size > 5) { int retval; char gdb_reply[10]; char *separator; uint32_t checksum; target_addr_t addr = 0; uint32_t len = 0; /* skip command character */ packet += 5; addr = strtoull(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete read memory packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } len = strtoul(separator + 1, NULL, 16); retval = target_checksum_memory(target, addr, len, &checksum); if (retval == ERROR_OK) { snprintf(gdb_reply, 10, "C%8.8" PRIx32 "", checksum); gdb_put_packet(connection, gdb_reply, 9); } else { retval = gdb_error(connection, retval); if (retval != ERROR_OK) return retval; } return ERROR_OK; } } else if (strncmp(packet, "qSupported", 10) == 0) { /* we currently support packet size and qXfer:memory-map:read (if enabled) * qXfer:features:read is supported for some targets */ int retval = ERROR_OK; char *buffer = NULL; int pos = 0; int size = 0; int gdb_target_desc_supported = 0; /* we need to test that the target supports target descriptions */ retval = gdb_target_description_supported(target, &gdb_target_desc_supported); if (retval != ERROR_OK) { LOG_INFO("Failed detecting Target Description Support, disabling"); gdb_target_desc_supported = 0; } /* support may be disabled globally */ if (gdb_use_target_description == 0) { if (gdb_target_desc_supported) LOG_WARNING("Target Descriptions Supported, but disabled"); gdb_target_desc_supported = 0; } xml_printf(&retval, &buffer, &pos, &size, "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+;vContSupported+", GDB_BUFFER_SIZE, ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-', (gdb_target_desc_supported == 1) ? '+' : '-'); if (retval != ERROR_OK) { gdb_send_error(connection, 01); return ERROR_OK; } gdb_put_packet(connection, buffer, strlen(buffer)); free(buffer); return ERROR_OK; } else if ((strncmp(packet, "qXfer:memory-map:read::", 23) == 0) && (flash_get_bank_count() > 0)) return gdb_memory_map(connection, packet, packet_size); else if (strncmp(packet, "qXfer:features:read:", 20) == 0) { char *xml = NULL; int retval = ERROR_OK; int offset; unsigned int length; /* skip command character */ packet += 20; if (decode_xfer_read(packet, NULL, &offset, &length) < 0) { gdb_send_error(connection, 01); return ERROR_OK; } /* Target should prepare correct target description for annex. * The first character of returned xml is 'm' or 'l'. 'm' for * there are *more* chunks to transfer. 'l' for it is the *last* * chunk of target description. */ retval = gdb_get_target_description_chunk(target, &gdb_connection->target_desc, &xml, offset, length); if (retval != ERROR_OK) { gdb_error(connection, retval); return retval; } gdb_put_packet(connection, xml, strlen(xml)); free(xml); return ERROR_OK; } else if (strncmp(packet, "qXfer:threads:read:", 19) == 0) { char *xml = NULL; int retval = ERROR_OK; int offset; unsigned int length; /* skip command character */ packet += 19; if (decode_xfer_read(packet, NULL, &offset, &length) < 0) { gdb_send_error(connection, 01); return ERROR_OK; } /* Target should prepare correct thread list for annex. * The first character of returned xml is 'm' or 'l'. 'm' for * there are *more* chunks to transfer. 'l' for it is the *last* * chunk of target description. */ retval = gdb_get_thread_list_chunk(target, &gdb_connection->thread_list, &xml, offset, length); if (retval != ERROR_OK) { gdb_error(connection, retval); return retval; } gdb_put_packet(connection, xml, strlen(xml)); free(xml); return ERROR_OK; } else if (strncmp(packet, "QStartNoAckMode", 15) == 0) { gdb_connection->noack_mode = 1; gdb_put_packet(connection, "OK", 2); return ERROR_OK; } else if (target->type->gdb_query_custom) { char *buffer = NULL; int ret = target->type->gdb_query_custom(target, packet, &buffer); gdb_put_packet(connection, buffer, strlen(buffer)); return ret; } gdb_put_packet(connection, "", 0); return ERROR_OK; } static bool gdb_handle_vcont_packet(struct connection *connection, const char *packet, __attribute__((unused)) int packet_size) { struct gdb_connection *gdb_connection = connection->priv; struct target *target = get_target_from_connection(connection); const char *parse = packet; int retval; /* query for vCont supported */ if (parse[0] == '?') { if (target->type->step) { /* gdb doesn't accept c without C and s without S */ gdb_put_packet(connection, "vCont;c;C;s;S", 13); return true; } return false; } if (parse[0] == ';') { ++parse; } /* simple case, a continue packet */ if (parse[0] == 'c') { gdb_running_type = 'c'; LOG_DEBUG("target %s continue", target_name(target)); gdb_connection->output_flag = GDB_OUTPUT_ALL; retval = target_resume(target, 1, 0, 0, 0); if (retval == ERROR_TARGET_NOT_HALTED) LOG_INFO("target %s was not halted when resume was requested", target_name(target)); /* poll target in an attempt to make its internal state consistent */ if (retval != ERROR_OK) { retval = target_poll(target); if (retval != ERROR_OK) LOG_DEBUG("error polling target %s after failed resume", target_name(target)); } /* * We don't report errors to gdb here, move frontend_state to * TARGET_RUNNING to stay in sync with gdb's expectation of the * target state */ gdb_connection->frontend_state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_GDB_START); return true; } /* single-step or step-over-breakpoint */ if (parse[0] == 's') { gdb_running_type = 's'; bool fake_step = false; struct target *ct = target; int current_pc = 1; int64_t thread_id; parse++; if (parse[0] == ':') { char *endp; parse++; thread_id = strtoll(parse, &endp, 16); if (endp) { parse = endp; } } else { thread_id = 0; } if (target->rtos) { /* FIXME: why is this necessary? rtos state should be up-to-date here already! */ rtos_update_threads(target); target->rtos->gdb_target_for_threadid(connection, thread_id, &ct); /* * check if the thread to be stepped is the current rtos thread * if not, we must fake the step */ if (target->rtos->current_thread != thread_id) fake_step = true; } if (parse[0] == ';') { ++parse; if (parse[0] == 'c') { parse += 1; /* check if thread-id follows */ if (parse[0] == ':') { int64_t tid; parse += 1; tid = strtoll(parse, NULL, 16); if (tid == thread_id) { /* * Special case: only step a single thread (core), * keep the other threads halted. Currently, only * aarch64 target understands it. Other target types don't * care (nobody checks the actual value of 'current') * and it doesn't really matter. This deserves * a symbolic constant and a formal interface documentation * at a later time. */ LOG_DEBUG("request to step current core only"); /* uncomment after checking that indeed other targets are safe */ /*current_pc = 2;*/ } } } } LOG_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id); gdb_connection->output_flag = GDB_OUTPUT_ALL; target_call_event_callbacks(ct, TARGET_EVENT_GDB_START); /* * work around an annoying gdb behaviour: when the current thread * is changed in gdb, it assumes that the target can follow and also * make the thread current. This is an assumption that cannot hold * for a real target running a multi-threading OS. We just fake * the step to not trigger an internal error in gdb. See * https://sourceware.org/bugzilla/show_bug.cgi?id=22925 for details */ if (fake_step) { int sig_reply_len; char sig_reply[128]; LOG_DEBUG("fake step thread %"PRIx64, thread_id); sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T05thread:%016"PRIx64";", thread_id); gdb_put_packet(connection, sig_reply, sig_reply_len); gdb_connection->output_flag = GDB_OUTPUT_NO; return true; } /* support for gdb_sync command */ if (gdb_connection->sync) { gdb_connection->sync = false; if (ct->state == TARGET_HALTED) { LOG_DEBUG("stepi ignored. GDB will now fetch the register state " "from the target."); gdb_sig_halted(connection); gdb_connection->output_flag = GDB_OUTPUT_NO; } else gdb_connection->frontend_state = TARGET_RUNNING; return true; } retval = target_step(ct, current_pc, 0, 0); if (retval == ERROR_TARGET_NOT_HALTED) LOG_INFO("target %s was not halted when step was requested", target_name(ct)); /* if step was successful send a reply back to gdb */ if (retval == ERROR_OK) { retval = target_poll(ct); if (retval != ERROR_OK) LOG_DEBUG("error polling target %s after successful step", target_name(ct)); /* send back signal information */ gdb_signal_reply(ct, connection); /* stop forwarding log packets! */ gdb_connection->output_flag = GDB_OUTPUT_NO; } else gdb_connection->frontend_state = TARGET_RUNNING; return true; } LOG_ERROR("Unknown vCont packet"); return false; } static char *next_hex_encoded_field(const char **str, char sep) { size_t hexlen; const char *hex = *str; if (hex[0] == '\0') return NULL; const char *end = strchr(hex, sep); if (!end) hexlen = strlen(hex); else hexlen = end - hex; *str = hex + hexlen + 1; if (hexlen % 2 != 0) { /* Malformed hex data */ return NULL; } size_t count = hexlen / 2; char *decoded = malloc(count + 1); if (!decoded) return NULL; size_t converted = unhexify((void *)decoded, hex, count); if (converted != count) { free(decoded); return NULL; } decoded[count] = '\0'; return decoded; } /* handle extended restart packet */ static void gdb_restart_inferior(struct connection *connection, const char *packet, int packet_size) { struct gdb_connection *gdb_con = connection->priv; struct target *target = get_target_from_connection(connection); breakpoint_clear_target(target); watchpoint_clear_target(target); command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s", target_name(target)); /* set connection as attached after reset */ gdb_con->attached = true; /* info rtos parts */ gdb_thread_packet(connection, packet, packet_size); } static bool gdb_handle_vrun_packet(struct connection *connection, const char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); const char *parse = packet; /* Skip "vRun" */ parse += 4; if (parse[0] != ';') return false; parse++; /* Skip first field "filename"; don't know what to do with it. */ free(next_hex_encoded_field(&parse, ';')); char *cmdline = next_hex_encoded_field(&parse, ';'); while (cmdline) { char *arg = next_hex_encoded_field(&parse, ';'); if (!arg) break; char *new_cmdline = alloc_printf("%s %s", cmdline, arg); free(cmdline); free(arg); cmdline = new_cmdline; } if (cmdline) { if (target->semihosting) { LOG_INFO("GDB set inferior command line to '%s'", cmdline); free(target->semihosting->cmdline); target->semihosting->cmdline = cmdline; } else { LOG_INFO("GDB set inferior command line to '%s' but semihosting is unavailable", cmdline); free(cmdline); } } gdb_restart_inferior(connection, packet, packet_size); gdb_put_packet(connection, "S00", 3); return true; } static int gdb_v_packet(struct connection *connection, char const *packet, int packet_size) { struct gdb_connection *gdb_connection = connection->priv; int result; struct target *target = get_target_from_connection(connection); if (strncmp(packet, "vCont", 5) == 0) { bool handled; packet += 5; packet_size -= 5; handled = gdb_handle_vcont_packet(connection, packet, packet_size); if (!handled) gdb_put_packet(connection, "", 0); return ERROR_OK; } if (strncmp(packet, "vRun", 4) == 0) { bool handled; handled = gdb_handle_vrun_packet(connection, packet, packet_size); if (!handled) gdb_put_packet(connection, "", 0); return ERROR_OK; } /* if flash programming disabled - send a empty reply */ if (gdb_flash_program == 0) { gdb_put_packet(connection, "", 0); return ERROR_OK; } if (strncmp(packet, "vFlashErase:", 12) == 0) { unsigned long addr; unsigned long length; char const *parse = packet + 12; if (*parse == '\0') { LOG_ERROR("incomplete vFlashErase packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } addr = strtoul(parse, (char **)&parse, 16); if (*(parse++) != ',' || *parse == '\0') { LOG_ERROR("incomplete vFlashErase packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } length = strtoul(parse, (char **)&parse, 16); if (*parse != '\0') { LOG_ERROR("incomplete vFlashErase packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } /* assume all sectors need erasing - stops any problems * when flash_write is called multiple times */ flash_set_dirty(); /* perform any target specific operations before the erase */ target_call_event_callbacks(target, TARGET_EVENT_GDB_FLASH_ERASE_START); /* vFlashErase:addr,length messages require region start and * end to be "block" aligned ... if padding is ever needed, * GDB will have become dangerously confused. */ result = flash_erase_address_range(target, false, addr, length); /* perform any target specific operations after the erase */ target_call_event_callbacks(target, TARGET_EVENT_GDB_FLASH_ERASE_END); /* perform erase */ if (result != ERROR_OK) { /* GDB doesn't evaluate the actual error number returned, * treat a failed erase as an I/O error */ gdb_send_error(connection, EIO); LOG_ERROR("flash_erase returned %i", result); } else gdb_put_packet(connection, "OK", 2); return ERROR_OK; } if (strncmp(packet, "vFlashWrite:", 12) == 0) { int retval; unsigned long addr; unsigned long length; char const *parse = packet + 12; if (*parse == '\0') { LOG_ERROR("incomplete vFlashErase packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } addr = strtoul(parse, (char **)&parse, 16); if (*(parse++) != ':') { LOG_ERROR("incomplete vFlashErase packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } length = packet_size - (parse - packet); /* create a new image if there isn't already one */ if (!gdb_connection->vflash_image) { gdb_connection->vflash_image = malloc(sizeof(struct image)); image_open(gdb_connection->vflash_image, "", "build"); } /* create new section with content from packet buffer */ retval = image_add_section(gdb_connection->vflash_image, addr, length, 0x0, (uint8_t const *)parse); if (retval != ERROR_OK) return retval; gdb_put_packet(connection, "OK", 2); return ERROR_OK; } if (strncmp(packet, "vFlashDone", 10) == 0) { uint32_t written; /* process the flashing buffer. No need to erase as GDB * always issues a vFlashErase first. */ target_call_event_callbacks(target, TARGET_EVENT_GDB_FLASH_WRITE_START); result = flash_write(target, gdb_connection->vflash_image, &written, false); target_call_event_callbacks(target, TARGET_EVENT_GDB_FLASH_WRITE_END); if (result != ERROR_OK) { if (result == ERROR_FLASH_DST_OUT_OF_BANK) gdb_put_packet(connection, "E.memtype", 9); else gdb_send_error(connection, EIO); } else { LOG_DEBUG("wrote %u bytes from vFlash image to flash", (unsigned)written); gdb_put_packet(connection, "OK", 2); } image_close(gdb_connection->vflash_image); free(gdb_connection->vflash_image); gdb_connection->vflash_image = NULL; return ERROR_OK; } gdb_put_packet(connection, "", 0); return ERROR_OK; } static int gdb_detach(struct connection *connection) { /* * Only reply "OK" to GDB * it will close the connection and this will trigger a call to * gdb_connection_closed() that will in turn trigger the event * TARGET_EVENT_GDB_DETACH */ return gdb_put_packet(connection, "OK", 2); } /* The format of 'F' response packet is * Fretcode,errno,Ctrl-C flag;call-specific attachment */ static int gdb_fileio_response_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); char *separator; char *parsing_point; int fileio_retcode = strtoul(packet + 1, &separator, 16); int fileio_errno = 0; bool fileio_ctrl_c = false; int retval; LOG_DEBUG("-"); if (*separator == ',') { parsing_point = separator + 1; fileio_errno = strtoul(parsing_point, &separator, 16); if (*separator == ',') { if (*(separator + 1) == 'C') { /* TODO: process ctrl-c */ fileio_ctrl_c = true; } } } LOG_DEBUG("File-I/O response, retcode: 0x%x, errno: 0x%x, ctrl-c: %s", fileio_retcode, fileio_errno, fileio_ctrl_c ? "true" : "false"); retval = target_gdb_fileio_end(target, fileio_retcode, fileio_errno, fileio_ctrl_c); if (retval != ERROR_OK) return ERROR_FAIL; /* After File-I/O ends, keep continue or step */ if (gdb_running_type == 'c') retval = target_resume(target, 1, 0x0, 0, 0); else if (gdb_running_type == 's') retval = target_step(target, 1, 0x0, 0); else retval = ERROR_FAIL; if (retval != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static void gdb_log_callback(void *priv, const char *file, unsigned line, const char *function, const char *string) { struct connection *connection = priv; struct gdb_connection *gdb_con = connection->priv; if (gdb_con->output_flag == GDB_OUTPUT_NO) /* No out allowed */ return; if (gdb_con->busy) { /* do not reply this using the O packet */ return; } gdb_output_con(connection, string); } static void gdb_sig_halted(struct connection *connection) { char sig_reply[4]; snprintf(sig_reply, 4, "T%2.2x", 2); gdb_put_packet(connection, sig_reply, 3); } static int gdb_input_inner(struct connection *connection) { /* Do not allocate this on the stack */ static char gdb_packet_buffer[GDB_BUFFER_SIZE + 1]; /* Extra byte for null-termination */ struct target *target; char const *packet = gdb_packet_buffer; int packet_size; int retval; struct gdb_connection *gdb_con = connection->priv; static bool warn_use_ext; target = get_target_from_connection(connection); /* drain input buffer. If one of the packets fail, then an error * packet is replied, if applicable. * * This loop will terminate and the error code is returned. * * The calling fn will check if this error is something that * can be recovered from, or if the connection must be closed. * * If the error is recoverable, this fn is called again to * drain the rest of the buffer. */ do { packet_size = GDB_BUFFER_SIZE; retval = gdb_get_packet(connection, gdb_packet_buffer, &packet_size); if (retval != ERROR_OK) return retval; /* terminate with zero */ gdb_packet_buffer[packet_size] = '\0'; if (packet_size > 0) { gdb_log_incoming_packet(connection, gdb_packet_buffer); retval = ERROR_OK; switch (packet[0]) { case 'T': /* Is thread alive? */ gdb_thread_packet(connection, packet, packet_size); break; case 'H': /* Set current thread ( 'c' for step and continue, * 'g' for all other operations ) */ gdb_thread_packet(connection, packet, packet_size); break; case 'q': case 'Q': retval = gdb_thread_packet(connection, packet, packet_size); if (retval == GDB_THREAD_PACKET_NOT_CONSUMED) retval = gdb_query_packet(connection, packet, packet_size); break; case 'g': retval = gdb_get_registers_packet(connection, packet, packet_size); break; case 'G': retval = gdb_set_registers_packet(connection, packet, packet_size); break; case 'p': retval = gdb_get_register_packet(connection, packet, packet_size); break; case 'P': retval = gdb_set_register_packet(connection, packet, packet_size); break; case 'm': retval = gdb_read_memory_packet(connection, packet, packet_size); break; case 'M': retval = gdb_write_memory_packet(connection, packet, packet_size); break; case 'z': case 'Z': retval = gdb_breakpoint_watchpoint_packet(connection, packet, packet_size); break; case '?': gdb_last_signal_packet(connection, packet, packet_size); /* '?' is sent after the eventual '!' */ if (!warn_use_ext && !gdb_con->extended_protocol) { warn_use_ext = true; LOG_WARNING("Prefer GDB command \"target extended-remote :%s\" instead of \"target remote :%s\"", connection->service->port, connection->service->port); } break; case 'c': case 's': { gdb_thread_packet(connection, packet, packet_size); gdb_con->output_flag = GDB_OUTPUT_ALL; if (gdb_con->mem_write_error) { LOG_ERROR("Memory write failure!"); /* now that we have reported the memory write error, * we can clear the condition */ gdb_con->mem_write_error = false; } bool nostep = false; bool already_running = false; if (target->state == TARGET_RUNNING) { LOG_WARNING("WARNING! The target is already running. " "All changes GDB did to registers will be discarded! " "Waiting for target to halt."); already_running = true; } else if (target->state != TARGET_HALTED) { LOG_WARNING("The target is not in the halted nor running stated, " "stepi/continue ignored."); nostep = true; } else if ((packet[0] == 's') && gdb_con->sync) { /* Hmm..... when you issue a continue in GDB, then a "stepi" is * sent by GDB first to OpenOCD, thus defeating the check to * make only the single stepping have the sync feature... */ nostep = true; LOG_DEBUG("stepi ignored. GDB will now fetch the register state " "from the target."); } gdb_con->sync = false; if (!already_running && nostep) { /* Either the target isn't in the halted state, then we can't * step/continue. This might be early setup, etc. * * Or we want to allow GDB to pick up a fresh set of * register values without modifying the target state. * */ gdb_sig_halted(connection); /* stop forwarding log packets! */ gdb_con->output_flag = GDB_OUTPUT_NO; } else { /* We're running/stepping, in which case we can * forward log output until the target is halted */ gdb_con->frontend_state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_GDB_START); if (!already_running) { /* Here we don't want packet processing to stop even if this fails, * so we use a local variable instead of retval. */ retval = gdb_step_continue_packet(connection, packet, packet_size); if (retval != ERROR_OK) { /* we'll never receive a halted * condition... issue a false one.. */ gdb_frontend_halted(target, connection); } } } } break; case 'v': retval = gdb_v_packet(connection, packet, packet_size); break; case 'D': retval = gdb_detach(connection); break; case 'X': retval = gdb_write_memory_binary_packet(connection, packet, packet_size); if (retval != ERROR_OK) return retval; break; case 'k': if (gdb_con->extended_protocol) { gdb_con->attached = false; break; } gdb_put_packet(connection, "OK", 2); return ERROR_SERVER_REMOTE_CLOSED; case '!': /* handle extended remote protocol */ gdb_con->extended_protocol = true; gdb_put_packet(connection, "OK", 2); break; case 'R': /* handle extended restart packet */ gdb_restart_inferior(connection, packet, packet_size); break; case 'j': /* DEPRECATED */ /* packet supported only by smp target i.e cortex_a.c*/ /* handle smp packet replying coreid played to gbd */ gdb_read_smp_packet(connection, packet, packet_size); break; case 'J': /* DEPRECATED */ /* packet supported only by smp target i.e cortex_a.c */ /* handle smp packet setting coreid to be played at next * resume to gdb */ gdb_write_smp_packet(connection, packet, packet_size); break; case 'F': /* File-I/O extension */ /* After gdb uses host-side syscall to complete target file * I/O, gdb sends host-side syscall return value to target * by 'F' packet. * The format of 'F' response packet is * Fretcode,errno,Ctrl-C flag;call-specific attachment */ gdb_con->frontend_state = TARGET_RUNNING; gdb_con->output_flag = GDB_OUTPUT_ALL; gdb_fileio_response_packet(connection, packet, packet_size); break; default: /* ignore unknown packets */ LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]); gdb_put_packet(connection, "", 0); break; } /* if a packet handler returned an error, exit input loop */ if (retval != ERROR_OK) return retval; } if (gdb_con->ctrl_c) { if (target->state == TARGET_RUNNING) { struct target *t = target; if (target->rtos) target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &t); retval = target_halt(t); if (retval == ERROR_OK) retval = target_poll(t); if (retval != ERROR_OK) target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); gdb_con->ctrl_c = false; } else { LOG_INFO("The target is not running when halt was requested, stopping GDB."); target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } } } while (gdb_con->buf_cnt > 0); return ERROR_OK; } static int gdb_input(struct connection *connection) { int retval = gdb_input_inner(connection); struct gdb_connection *gdb_con = connection->priv; if (retval == ERROR_SERVER_REMOTE_CLOSED) return retval; /* logging does not propagate the error, yet can set the gdb_con->closed flag */ if (gdb_con->closed) return ERROR_SERVER_REMOTE_CLOSED; /* we'll recover from any other errors(e.g. temporary timeouts, etc.) */ return ERROR_OK; } static void gdb_keep_client_alive(struct connection *connection) { struct gdb_connection *gdb_con = connection->priv; if (gdb_con->busy) { /* do not send packets, retry asap */ return; } switch (gdb_con->output_flag) { case GDB_OUTPUT_NO: /* no need for keep-alive */ break; case GDB_OUTPUT_ALL: /* send an empty O packet */ gdb_output_con(connection, ""); break; default: break; } } static const struct service_driver gdb_service_driver = { .name = "gdb", .new_connection_during_keep_alive_handler = NULL, .new_connection_handler = gdb_new_connection, .input_handler = gdb_input, .connection_closed_handler = gdb_connection_closed, .keep_client_alive_handler = gdb_keep_client_alive, }; static int gdb_target_start(struct target *target, const char *port) { struct gdb_service *gdb_service; int ret; gdb_service = malloc(sizeof(struct gdb_service)); if (!gdb_service) return -ENOMEM; LOG_INFO("starting gdb server for %s on %s", target_name(target), port); gdb_service->target = target; gdb_service->core[0] = -1; gdb_service->core[1] = -1; target->gdb_service = gdb_service; ret = add_service(&gdb_service_driver, port, target->gdb_max_connections, gdb_service); /* initialize all targets gdb service with the same pointer */ { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (curr != target) curr->gdb_service = gdb_service; } } return ret; } static int gdb_target_add_one(struct target *target) { /* one gdb instance per smp list */ if ((target->smp) && (target->gdb_service)) return ERROR_OK; /* skip targets that cannot handle a gdb connections (e.g. mem_ap) */ if (!target_supports_gdb_connection(target)) { LOG_DEBUG("skip gdb server for target %s", target_name(target)); return ERROR_OK; } if (target->gdb_port_override) { if (strcmp(target->gdb_port_override, "disabled") == 0) { LOG_INFO("gdb port disabled"); return ERROR_OK; } return gdb_target_start(target, target->gdb_port_override); } if (strcmp(gdb_port, "disabled") == 0) { LOG_INFO("gdb port disabled"); return ERROR_OK; } int retval = gdb_target_start(target, gdb_port_next); if (retval == ERROR_OK) { /* save the port number so can be queried with * $target_name cget -gdb-port */ target->gdb_port_override = strdup(gdb_port_next); long portnumber; /* If we can parse the port number * then we increment the port number for the next target. */ char *end; portnumber = strtol(gdb_port_next, &end, 0); if (!*end) { if (parse_long(gdb_port_next, &portnumber) == ERROR_OK) { free(gdb_port_next); if (portnumber) { gdb_port_next = alloc_printf("%ld", portnumber+1); } else { /* Don't increment if gdb_port is 0, since we're just * trying to allocate an unused port. */ gdb_port_next = strdup("0"); } } } } return retval; } int gdb_target_add_all(struct target *target) { if (!target) { LOG_WARNING("gdb services need one or more targets defined"); return ERROR_OK; } while (target) { int retval = gdb_target_add_one(target); if (retval != ERROR_OK) return retval; target = target->next; } return ERROR_OK; } COMMAND_HANDLER(handle_gdb_sync_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (!current_gdb_connection) { command_print(CMD, "gdb_sync command can only be run from within gdb using \"monitor gdb_sync\""); return ERROR_FAIL; } current_gdb_connection->sync = true; return ERROR_OK; } /* daemon configuration command gdb_port */ COMMAND_HANDLER(handle_gdb_port_command) { int retval = CALL_COMMAND_HANDLER(server_pipe_command, &gdb_port); if (retval == ERROR_OK) { free(gdb_port_next); gdb_port_next = strdup(gdb_port); } return retval; } COMMAND_HANDLER(handle_gdb_memory_map_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_use_memory_map); return ERROR_OK; } COMMAND_HANDLER(handle_gdb_flash_program_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_flash_program); return ERROR_OK; } COMMAND_HANDLER(handle_gdb_report_data_abort_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_report_data_abort); return ERROR_OK; } COMMAND_HANDLER(handle_gdb_report_register_access_error) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_report_register_access_error); return ERROR_OK; } /* gdb_breakpoint_override */ COMMAND_HANDLER(handle_gdb_breakpoint_override_command) { if (CMD_ARGC == 0) { /* nothing */ } else if (CMD_ARGC == 1) { gdb_breakpoint_override = 1; if (strcmp(CMD_ARGV[0], "hard") == 0) gdb_breakpoint_override_type = BKPT_HARD; else if (strcmp(CMD_ARGV[0], "soft") == 0) gdb_breakpoint_override_type = BKPT_SOFT; else if (strcmp(CMD_ARGV[0], "disable") == 0) gdb_breakpoint_override = 0; } else return ERROR_COMMAND_SYNTAX_ERROR; if (gdb_breakpoint_override) LOG_USER("force %s breakpoints", (gdb_breakpoint_override_type == BKPT_HARD) ? "hard" : "soft"); else LOG_USER("breakpoint type is not overridden"); return ERROR_OK; } COMMAND_HANDLER(handle_gdb_target_description_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_use_target_description); return ERROR_OK; } COMMAND_HANDLER(handle_gdb_save_tdesc_command) { char *tdesc; uint32_t tdesc_length; struct target *target = get_current_target(CMD_CTX); int retval = gdb_generate_target_description(target, &tdesc); if (retval != ERROR_OK) { LOG_ERROR("Unable to Generate Target Description"); return ERROR_FAIL; } tdesc_length = strlen(tdesc); struct fileio *fileio; size_t size_written; char *tdesc_filename = alloc_printf("%s.xml", target_type_name(target)); if (!tdesc_filename) { retval = ERROR_FAIL; goto out; } retval = fileio_open(&fileio, tdesc_filename, FILEIO_WRITE, FILEIO_TEXT); if (retval != ERROR_OK) { LOG_ERROR("Can't open %s for writing", tdesc_filename); goto out; } retval = fileio_write(fileio, tdesc_length, tdesc, &size_written); fileio_close(fileio); if (retval != ERROR_OK) LOG_ERROR("Error while writing the tdesc file"); out: free(tdesc_filename); free(tdesc); return retval; } static const struct command_registration gdb_command_handlers[] = { { .name = "gdb_sync", .handler = handle_gdb_sync_command, .mode = COMMAND_ANY, .help = "next stepi will return immediately allowing " "GDB to fetch register state without affecting " "target state", .usage = "" }, { .name = "gdb_port", .handler = handle_gdb_port_command, .mode = COMMAND_CONFIG, .help = "Normally gdb listens to a TCP/IP port. Each subsequent GDB " "server listens for the next port number after the " "base port number specified. " "No arguments reports GDB port. \"pipe\" means listen to stdin " "output to stdout, an integer is base port number, \"disabled\" disables " "port. Any other string is are interpreted as named pipe to listen to. " "Output pipe is the same name as input pipe, but with 'o' appended.", .usage = "[port_num]", }, { .name = "gdb_memory_map", .handler = handle_gdb_memory_map_command, .mode = COMMAND_CONFIG, .help = "enable or disable memory map", .usage = "('enable'|'disable')" }, { .name = "gdb_flash_program", .handler = handle_gdb_flash_program_command, .mode = COMMAND_CONFIG, .help = "enable or disable flash program", .usage = "('enable'|'disable')" }, { .name = "gdb_report_data_abort", .handler = handle_gdb_report_data_abort_command, .mode = COMMAND_CONFIG, .help = "enable or disable reporting data aborts", .usage = "('enable'|'disable')" }, { .name = "gdb_report_register_access_error", .handler = handle_gdb_report_register_access_error, .mode = COMMAND_CONFIG, .help = "enable or disable reporting register access errors", .usage = "('enable'|'disable')" }, { .name = "gdb_breakpoint_override", .handler = handle_gdb_breakpoint_override_command, .mode = COMMAND_ANY, .help = "Display or specify type of breakpoint " "to be used by gdb 'break' commands.", .usage = "('hard'|'soft'|'disable')" }, { .name = "gdb_target_description", .handler = handle_gdb_target_description_command, .mode = COMMAND_CONFIG, .help = "enable or disable target description", .usage = "('enable'|'disable')" }, { .name = "gdb_save_tdesc", .handler = handle_gdb_save_tdesc_command, .mode = COMMAND_EXEC, .help = "Save the target description file", .usage = "", }, COMMAND_REGISTRATION_DONE }; int gdb_register_commands(struct command_context *cmd_ctx) { gdb_port = strdup("3333"); gdb_port_next = strdup("3333"); return register_commands(cmd_ctx, NULL, gdb_command_handlers); } void gdb_service_free(void) { free(gdb_port); free(gdb_port_next); } int gdb_get_actual_connections(void) { return gdb_actual_connections; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/server/gdb_server.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2009 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * ***************************************************************************/ #ifndef OPENOCD_SERVER_GDB_SERVER_H #define OPENOCD_SERVER_GDB_SERVER_H struct image; struct reg; #include <target/target.h> #include <server/server.h> #define GDB_BUFFER_SIZE 16384 int gdb_target_add_all(struct target *target); int gdb_register_commands(struct command_context *command_context); void gdb_service_free(void); int gdb_put_packet(struct connection *connection, char *buffer, int len); int gdb_get_actual_connections(void); static inline struct target *get_target_from_connection(struct connection *connection) { struct gdb_service *gdb_service = connection->service->priv; return gdb_service->target; } #define ERROR_GDB_BUFFER_TOO_SMALL (-800) #define ERROR_GDB_TIMEOUT (-801) #endif /* OPENOCD_SERVER_GDB_SERVER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/server/ipdbg.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* Copyright (C) 2020 by Daniel Anselmi <danselmi@gmx.ch> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/bits.h> #include <helper/time_support.h> #include <jtag/jtag.h> #include <server/server.h> #include <target/target.h> #include <pld/pld.h> #include "ipdbg.h" #define IPDBG_BUFFER_SIZE 16384 #define IPDBG_MIN_NUM_OF_OPTIONS 2 #define IPDBG_MAX_NUM_OF_OPTIONS 14 #define IPDBG_MIN_DR_LENGTH 11 #define IPDBG_MAX_DR_LENGTH 13 #define IPDBG_TCP_PORT_STR_MAX_LENGTH 6 /* private connection data for IPDBG */ struct ipdbg_fifo { size_t count; size_t rd_idx; char buffer[IPDBG_BUFFER_SIZE]; }; struct ipdbg_connection { struct ipdbg_fifo dn_fifo; struct ipdbg_fifo up_fifo; bool closed; }; struct ipdbg_service { struct ipdbg_hub *hub; struct ipdbg_service *next; uint16_t port; struct ipdbg_connection connection; uint8_t tool; }; struct ipdbg_virtual_ir_info { uint32_t instruction; uint32_t length; uint32_t value; }; struct ipdbg_hub { uint32_t user_instruction; uint32_t max_tools; uint32_t active_connections; uint32_t active_services; uint32_t valid_mask; uint32_t xoff_mask; uint32_t tool_mask; uint32_t last_dn_tool; struct ipdbg_hub *next; struct jtag_tap *tap; struct connection **connections; uint8_t data_register_length; uint8_t dn_xoff; struct ipdbg_virtual_ir_info *virtual_ir; }; static struct ipdbg_hub *ipdbg_first_hub; static struct ipdbg_service *ipdbg_first_service; static void ipdbg_init_fifo(struct ipdbg_fifo *fifo) { fifo->count = 0; fifo->rd_idx = 0; } static bool ipdbg_fifo_is_empty(struct ipdbg_fifo *fifo) { return fifo->count == 0; } static bool ipdbg_fifo_is_full(struct ipdbg_fifo *fifo) { return fifo->count == IPDBG_BUFFER_SIZE; } static void ipdbg_zero_rd_idx(struct ipdbg_fifo *fifo) { if (fifo->rd_idx == 0) return; size_t ri = fifo->rd_idx; for (size_t idx = 0; idx < fifo->count; ++idx) fifo->buffer[idx] = fifo->buffer[ri++]; fifo->rd_idx = 0; } static void ipdbg_append_to_fifo(struct ipdbg_fifo *fifo, char data) { if (ipdbg_fifo_is_full(fifo)) return; ipdbg_zero_rd_idx(fifo); fifo->buffer[fifo->count++] = data; } static char ipdbg_get_from_fifo(struct ipdbg_fifo *fifo) { if (ipdbg_fifo_is_empty(fifo)) return 0; fifo->count--; return fifo->buffer[fifo->rd_idx++]; } static int ipdbg_move_buffer_to_connection(struct connection *conn, struct ipdbg_fifo *fifo) { if (ipdbg_fifo_is_empty(fifo)) return ERROR_OK; struct ipdbg_connection *connection = conn->priv; if (connection->closed) return ERROR_SERVER_REMOTE_CLOSED; ipdbg_zero_rd_idx(fifo); size_t bytes_written = connection_write(conn, fifo->buffer, fifo->count); if (bytes_written != fifo->count) { LOG_ERROR("error during write: %zu != %zu", bytes_written, fifo->count); connection->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } fifo->count -= bytes_written; return ERROR_OK; } static int ipdbg_max_tools_from_data_register_length(uint8_t data_register_length) { int max_tools = 1; data_register_length -= 10; /* 8 bit payload, 1 xoff-flag, 1 valid-flag; remaining bits used to select tool*/ while (data_register_length--) max_tools *= 2; /* last tool is used to reset JtagCDC and transfer "XON" to host*/ return max_tools - 1; } static struct ipdbg_service *ipdbg_find_service(struct ipdbg_hub *hub, uint8_t tool) { struct ipdbg_service *service; for (service = ipdbg_first_service; service; service = service->next) { if (service->hub == hub && service->tool == tool) break; } return service; } static void ipdbg_add_service(struct ipdbg_service *service) { struct ipdbg_service *iservice; if (ipdbg_first_service) { for (iservice = ipdbg_first_service; iservice->next; iservice = iservice->next) ; iservice->next = service; } else ipdbg_first_service = service; } static int ipdbg_create_service(struct ipdbg_hub *hub, uint8_t tool, struct ipdbg_service **service, uint16_t port) { *service = calloc(1, sizeof(struct ipdbg_service)); if (!*service) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } (*service)->hub = hub; (*service)->tool = tool; (*service)->port = port; return ERROR_OK; } static int ipdbg_remove_service(struct ipdbg_service *service) { if (!ipdbg_first_service) return ERROR_FAIL; if (service == ipdbg_first_service) { ipdbg_first_service = ipdbg_first_service->next; return ERROR_OK; } for (struct ipdbg_service *iservice = ipdbg_first_service; iservice->next; iservice = iservice->next) { if (service == iservice->next) { iservice->next = service->next; return ERROR_OK; } } return ERROR_FAIL; } static struct ipdbg_hub *ipdbg_find_hub(struct jtag_tap *tap, uint32_t user_instruction, struct ipdbg_virtual_ir_info *virtual_ir) { struct ipdbg_hub *hub = NULL; for (hub = ipdbg_first_hub; hub; hub = hub->next) { if (hub->tap == tap && hub->user_instruction == user_instruction) { if ((!virtual_ir && !hub->virtual_ir) || (virtual_ir && hub->virtual_ir && virtual_ir->instruction == hub->virtual_ir->instruction && virtual_ir->length == hub->virtual_ir->length && virtual_ir->value == hub->virtual_ir->value)) { break; } } } return hub; } static void ipdbg_add_hub(struct ipdbg_hub *hub) { struct ipdbg_hub *ihub; if (ipdbg_first_hub) { for (ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next) ; ihub->next = hub; } else ipdbg_first_hub = hub; } static int ipdbg_create_hub(struct jtag_tap *tap, uint32_t user_instruction, uint8_t data_register_length, struct ipdbg_virtual_ir_info *virtual_ir, struct ipdbg_hub **hub) { *hub = NULL; struct ipdbg_hub *new_hub = calloc(1, sizeof(struct ipdbg_hub)); if (!new_hub) { free(virtual_ir); LOG_ERROR("Out of memory"); return ERROR_FAIL; } new_hub->max_tools = ipdbg_max_tools_from_data_register_length(data_register_length); new_hub->connections = calloc(new_hub->max_tools, sizeof(struct connection *)); if (!new_hub->connections) { free(virtual_ir); free(new_hub); LOG_ERROR("Out of memory"); return ERROR_FAIL; } new_hub->tap = tap; new_hub->user_instruction = user_instruction; new_hub->data_register_length = data_register_length; new_hub->valid_mask = BIT(data_register_length - 1); new_hub->xoff_mask = BIT(data_register_length - 2); new_hub->tool_mask = (new_hub->xoff_mask - 1) >> 8; new_hub->last_dn_tool = new_hub->tool_mask; new_hub->virtual_ir = virtual_ir; *hub = new_hub; return ERROR_OK; } static void ipdbg_free_hub(struct ipdbg_hub *hub) { if (!hub) return; free(hub->connections); free(hub->virtual_ir); free(hub); } static int ipdbg_remove_hub(struct ipdbg_hub *hub) { if (!ipdbg_first_hub) return ERROR_FAIL; if (hub == ipdbg_first_hub) { ipdbg_first_hub = ipdbg_first_hub->next; return ERROR_OK; } for (struct ipdbg_hub *ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next) { if (hub == ihub->next) { ihub->next = hub->next; return ERROR_OK; } } return ERROR_FAIL; } static void ipdbg_init_scan_field(struct scan_field *fields, uint8_t *in_value, int num_bits, const uint8_t *out_value) { fields->check_mask = NULL; fields->check_value = NULL; fields->in_value = in_value; fields->num_bits = num_bits; fields->out_value = out_value; } static int ipdbg_shift_instr(struct ipdbg_hub *hub, uint32_t instr) { if (!hub) return ERROR_FAIL; struct jtag_tap *tap = hub->tap; if (!tap) return ERROR_FAIL; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) == instr) { /* there is already the requested instruction in the ir */ return ERROR_OK; } uint8_t *ir_out_val = calloc(DIV_ROUND_UP(tap->ir_length, 8), 1); if (!ir_out_val) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } buf_set_u32(ir_out_val, 0, tap->ir_length, instr); struct scan_field fields; ipdbg_init_scan_field(&fields, NULL, tap->ir_length, ir_out_val); jtag_add_ir_scan(tap, &fields, TAP_IDLE); int retval = jtag_execute_queue(); free(ir_out_val); return retval; } static int ipdbg_shift_vir(struct ipdbg_hub *hub) { if (!hub) return ERROR_FAIL; if (!hub->virtual_ir) return ERROR_OK; int retval = ipdbg_shift_instr(hub, hub->virtual_ir->instruction); if (retval != ERROR_OK) return retval; struct jtag_tap *tap = hub->tap; if (!tap) return ERROR_FAIL; uint8_t *dr_out_val = calloc(DIV_ROUND_UP(hub->virtual_ir->length, 8), 1); if (!dr_out_val) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } buf_set_u32(dr_out_val, 0, hub->virtual_ir->length, hub->virtual_ir->value); struct scan_field fields; ipdbg_init_scan_field(&fields, NULL, hub->virtual_ir->length, dr_out_val); jtag_add_dr_scan(tap, 1, &fields, TAP_IDLE); retval = jtag_execute_queue(); free(dr_out_val); return retval; } static int ipdbg_shift_data(struct ipdbg_hub *hub, uint32_t dn_data, uint32_t *up_data) { if (!hub) return ERROR_FAIL; struct jtag_tap *tap = hub->tap; if (!tap) return ERROR_FAIL; uint8_t *dr_out_val = calloc(DIV_ROUND_UP(hub->data_register_length, 8), 1); if (!dr_out_val) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } buf_set_u32(dr_out_val, 0, hub->data_register_length, dn_data); uint8_t *dr_in_val = NULL; if (up_data) { dr_in_val = calloc(DIV_ROUND_UP(hub->data_register_length, 8), 1); if (!dr_in_val) { LOG_ERROR("Out of memory"); free(dr_out_val); return ERROR_FAIL; } } struct scan_field fields; ipdbg_init_scan_field(&fields, dr_in_val, hub->data_register_length, dr_out_val); jtag_add_dr_scan(tap, 1, &fields, TAP_IDLE); int retval = jtag_execute_queue(); if (up_data && retval == ERROR_OK) *up_data = buf_get_u32(dr_in_val, 0, hub->data_register_length); free(dr_out_val); free(dr_in_val); return retval; } static int ipdbg_distribute_data_from_hub(struct ipdbg_hub *hub, uint32_t up) { const bool valid_up_data = up & hub->valid_mask; if (!valid_up_data) return ERROR_OK; const size_t tool = (up >> 8) & hub->tool_mask; if (tool == hub->tool_mask) { const uint8_t xon_cmd = up & 0x00ff; hub->dn_xoff &= ~xon_cmd; LOG_INFO("received xon cmd: %d\n", xon_cmd); return ERROR_OK; } struct connection *conn = hub->connections[tool]; if (conn) { struct ipdbg_connection *connection = conn->priv; if (ipdbg_fifo_is_full(&connection->up_fifo)) { int retval = ipdbg_move_buffer_to_connection(conn, &connection->up_fifo); if (retval != ERROR_OK) return retval; } ipdbg_append_to_fifo(&connection->up_fifo, up); } return ERROR_OK; } static int ipdbg_jtag_transfer_byte(struct ipdbg_hub *hub, size_t tool, struct ipdbg_connection *connection) { uint32_t dn = hub->valid_mask | ((tool & hub->tool_mask) << 8) | (0x00fful & ipdbg_get_from_fifo(&connection->dn_fifo)); uint32_t up = 0; int ret = ipdbg_shift_data(hub, dn, &up); if (ret != ERROR_OK) return ret; ret = ipdbg_distribute_data_from_hub(hub, up); if (ret != ERROR_OK) return ret; if ((up & hub->xoff_mask) && (hub->last_dn_tool != hub->max_tools)) { hub->dn_xoff |= BIT(hub->last_dn_tool); LOG_INFO("tool %d sent xoff", hub->last_dn_tool); } hub->last_dn_tool = tool; return ERROR_OK; } static int ipdbg_polling_callback(void *priv) { struct ipdbg_hub *hub = priv; int ret = ipdbg_shift_vir(hub); if (ret != ERROR_OK) return ret; ret = ipdbg_shift_instr(hub, hub->user_instruction); if (ret != ERROR_OK) return ret; /* transfer dn buffers to jtag-hub */ unsigned int num_transfers = 0; for (size_t tool = 0; tool < hub->max_tools; ++tool) { struct connection *conn = hub->connections[tool]; if (conn && conn->priv) { struct ipdbg_connection *connection = conn->priv; while (((hub->dn_xoff & BIT(tool)) == 0) && !ipdbg_fifo_is_empty(&connection->dn_fifo)) { ret = ipdbg_jtag_transfer_byte(hub, tool, connection); if (ret != ERROR_OK) return ret; ++num_transfers; } } } /* some transfers to get data from jtag-hub in case there is no dn data */ while (num_transfers++ < hub->max_tools) { uint32_t dn = 0; uint32_t up = 0; int retval = ipdbg_shift_data(hub, dn, &up); if (retval != ERROR_OK) return ret; retval = ipdbg_distribute_data_from_hub(hub, up); if (retval != ERROR_OK) return ret; } /* write from up fifos to sockets */ for (size_t tool = 0; tool < hub->max_tools; ++tool) { struct connection *conn = hub->connections[tool]; if (conn && conn->priv) { struct ipdbg_connection *connection = conn->priv; int retval = ipdbg_move_buffer_to_connection(conn, &connection->up_fifo); if (retval != ERROR_OK) return retval; } } return ERROR_OK; } static int ipdbg_start_polling(struct ipdbg_service *service, struct connection *connection) { struct ipdbg_hub *hub = service->hub; hub->connections[service->tool] = connection; hub->active_connections++; if (hub->active_connections > 1) { /* hub is already initialized */ return ERROR_OK; } const uint32_t reset_hub = hub->valid_mask | ((hub->max_tools) << 8); int ret = ipdbg_shift_vir(hub); if (ret != ERROR_OK) return ret; ret = ipdbg_shift_instr(hub, hub->user_instruction); if (ret != ERROR_OK) return ret; ret = ipdbg_shift_data(hub, reset_hub, NULL); hub->last_dn_tool = hub->tool_mask; hub->dn_xoff = 0; if (ret != ERROR_OK) return ret; LOG_INFO("IPDBG start_polling"); const int time_ms = 20; const int periodic = 1; return target_register_timer_callback(ipdbg_polling_callback, time_ms, periodic, hub); } static int ipdbg_stop_polling(struct ipdbg_service *service) { struct ipdbg_hub *hub = service->hub; hub->connections[service->tool] = NULL; hub->active_connections--; if (hub->active_connections == 0) { LOG_INFO("IPDBG stop_polling"); return target_unregister_timer_callback(ipdbg_polling_callback, hub); } return ERROR_OK; } static int ipdbg_on_new_connection(struct connection *connection) { struct ipdbg_service *service = connection->service->priv; connection->priv = &service->connection; /* initialize ipdbg connection information */ ipdbg_init_fifo(&service->connection.up_fifo); ipdbg_init_fifo(&service->connection.dn_fifo); int retval = ipdbg_start_polling(service, connection); if (retval != ERROR_OK) { LOG_ERROR("BUG: ipdbg_start_polling failed"); return retval; } struct ipdbg_connection *conn = connection->priv; conn->closed = false; LOG_INFO("New IPDBG Connection"); return ERROR_OK; } static int ipdbg_on_connection_input(struct connection *connection) { struct ipdbg_connection *conn = connection->priv; struct ipdbg_fifo *fifo = &conn->dn_fifo; if (ipdbg_fifo_is_full(fifo)) return ERROR_OK; ipdbg_zero_rd_idx(fifo); int bytes_read = connection_read(connection, fifo->buffer + fifo->count, IPDBG_BUFFER_SIZE - fifo->count); if (bytes_read <= 0) { if (bytes_read < 0) LOG_ERROR("error during read: %s", strerror(errno)); return ERROR_SERVER_REMOTE_CLOSED; } fifo->count += bytes_read; return ERROR_OK; } static int ipdbg_on_connection_closed(struct connection *connection) { struct ipdbg_connection *conn = connection->priv; conn->closed = true; LOG_INFO("Closed IPDBG Connection"); return ipdbg_stop_polling(connection->service->priv); } static const struct service_driver ipdbg_service_driver = { .name = "ipdbg", .new_connection_during_keep_alive_handler = NULL, .new_connection_handler = ipdbg_on_new_connection, .input_handler = ipdbg_on_connection_input, .connection_closed_handler = ipdbg_on_connection_closed, .keep_client_alive_handler = NULL, }; static int ipdbg_start(uint16_t port, struct jtag_tap *tap, uint32_t user_instruction, uint8_t data_register_length, struct ipdbg_virtual_ir_info *virtual_ir, uint8_t tool) { LOG_INFO("starting ipdbg service on port %d for tool %d", port, tool); struct ipdbg_hub *hub = ipdbg_find_hub(tap, user_instruction, virtual_ir); if (hub) { free(virtual_ir); if (hub->data_register_length != data_register_length) { LOG_DEBUG("hub must have the same data_register_length for all tools"); return ERROR_FAIL; } } else { int retval = ipdbg_create_hub(tap, user_instruction, data_register_length, virtual_ir, &hub); if (retval != ERROR_OK) return retval; } struct ipdbg_service *service = NULL; int retval = ipdbg_create_service(hub, tool, &service, port); if (retval != ERROR_OK || !service) { if (hub->active_services == 0 && hub->active_connections == 0) ipdbg_free_hub(hub); return ERROR_FAIL; } char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH]; snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", port); retval = add_service(&ipdbg_service_driver, port_str_buffer, 1, service); if (retval == ERROR_OK) { ipdbg_add_service(service); if (hub->active_services == 0 && hub->active_connections == 0) ipdbg_add_hub(hub); hub->active_services++; } else { if (hub->active_services == 0 && hub->active_connections == 0) ipdbg_free_hub(hub); free(service); } return retval; } static int ipdbg_stop(struct jtag_tap *tap, uint32_t user_instruction, struct ipdbg_virtual_ir_info *virtual_ir, uint8_t tool) { struct ipdbg_hub *hub = ipdbg_find_hub(tap, user_instruction, virtual_ir); free(virtual_ir); if (!hub) return ERROR_FAIL; struct ipdbg_service *service = ipdbg_find_service(hub, tool); if (!service) return ERROR_FAIL; int retval = ipdbg_remove_service(service); if (retval != ERROR_OK) { LOG_ERROR("BUG: ipdbg_remove_service failed"); return retval; } char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH]; snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", service->port); retval = remove_service("ipdbg", port_str_buffer); /* The ipdbg_service structure is freed by server.c:remove_service(). There the "priv" pointer is freed.*/ if (retval != ERROR_OK) { LOG_ERROR("BUG: remove_service failed"); return retval; } hub->active_services--; if (hub->active_connections == 0 && hub->active_services == 0) { retval = ipdbg_remove_hub(hub); if (retval != ERROR_OK) { LOG_ERROR("BUG: ipdbg_remove_hub failed"); return retval; } ipdbg_free_hub(hub); } return ERROR_OK; } COMMAND_HANDLER(handle_ipdbg_command) { struct jtag_tap *tap = NULL; uint16_t port = 4242; uint8_t tool = 1; uint32_t user_instruction = 0x00; uint8_t data_register_length = IPDBG_MAX_DR_LENGTH; bool start = true; bool hub_configured = false; bool has_virtual_ir = false; uint32_t virtual_ir_instruction = 0x00e; uint32_t virtual_ir_length = 5; uint32_t virtual_ir_value = 0x11; struct ipdbg_virtual_ir_info *virtual_ir = NULL; int user_num = 1; if ((CMD_ARGC < IPDBG_MIN_NUM_OF_OPTIONS) || (CMD_ARGC > IPDBG_MAX_NUM_OF_OPTIONS)) return ERROR_COMMAND_SYNTAX_ERROR; for (unsigned int i = 0; i < CMD_ARGC; ++i) { if (strcmp(CMD_ARGV[i], "-tap") == 0) { if (i + 1 >= CMD_ARGC || CMD_ARGV[i + 1][0] == '-') { command_print(CMD, "no TAP given"); return ERROR_FAIL; } tap = jtag_tap_by_string(CMD_ARGV[i + 1]); if (!tap) { command_print(CMD, "Tap %s unknown", CMD_ARGV[i + 1]); return ERROR_FAIL; } ++i; } else if (strcmp(CMD_ARGV[i], "-hub") == 0) { COMMAND_PARSE_ADDITIONAL_NUMBER(u32, i, user_instruction, "ir_value to select hub"); hub_configured = true; COMMAND_PARSE_OPTIONAL_NUMBER(u8, i, data_register_length); if (data_register_length < IPDBG_MIN_DR_LENGTH || data_register_length > IPDBG_MAX_DR_LENGTH) { command_print(CMD, "length of \"user\"-data register must be at least %d and at most %d.", IPDBG_MIN_DR_LENGTH, IPDBG_MAX_DR_LENGTH); return ERROR_FAIL; } } else if (strcmp(CMD_ARGV[i], "-pld") == 0) { ++i; if (i >= CMD_ARGC || CMD_ARGV[i][0] == '-') return ERROR_COMMAND_SYNTAX_ERROR; struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[i]); if (!device || !device->driver) { command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[i]); return ERROR_FAIL; } COMMAND_PARSE_OPTIONAL_NUMBER(int, i, user_num); struct pld_ipdbg_hub pld_hub; struct pld_driver *driver = device->driver; if (!driver->get_ipdbg_hub) { command_print(CMD, "pld driver has no ipdbg support"); return ERROR_FAIL; } if (driver->get_ipdbg_hub(user_num, device, &pld_hub) != ERROR_OK) { command_print(CMD, "unable to retrieve hub from pld driver"); return ERROR_FAIL; } if (!pld_hub.tap) { command_print(CMD, "no tap received from pld driver"); return ERROR_FAIL; } hub_configured = true; user_instruction = pld_hub.user_ir_code; tap = pld_hub.tap; } else if (strcmp(CMD_ARGV[i], "-vir") == 0) { COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_value); COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_length); COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_instruction); has_virtual_ir = true; } else if (strcmp(CMD_ARGV[i], "-port") == 0) { COMMAND_PARSE_ADDITIONAL_NUMBER(u16, i, port, "port number"); } else if (strcmp(CMD_ARGV[i], "-tool") == 0) { COMMAND_PARSE_ADDITIONAL_NUMBER(u8, i, tool, "tool"); } else if (strcmp(CMD_ARGV[i], "-stop") == 0) { start = false; } else if (strcmp(CMD_ARGV[i], "-start") == 0) { start = true; } else { command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]); return ERROR_FAIL; } } if (!tap) { command_print(CMD, "no valid tap selected"); return ERROR_FAIL; } if (!hub_configured) { command_print(CMD, "hub not configured correctly"); return ERROR_FAIL; } if (tool >= ipdbg_max_tools_from_data_register_length(data_register_length)) { command_print(CMD, "Tool: %d is invalid", tool); return ERROR_FAIL; } if (has_virtual_ir) { virtual_ir = calloc(1, sizeof(struct ipdbg_virtual_ir_info)); if (!virtual_ir) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } virtual_ir->instruction = virtual_ir_instruction; virtual_ir->length = virtual_ir_length; virtual_ir->value = virtual_ir_value; } if (start) return ipdbg_start(port, tap, user_instruction, data_register_length, virtual_ir, tool); else return ipdbg_stop(tap, user_instruction, virtual_ir, tool); } static const struct command_registration ipdbg_command_handlers[] = { { .name = "ipdbg", .handler = handle_ipdbg_command, .mode = COMMAND_EXEC, .help = "Starts or stops an IPDBG JTAG-Host server.", .usage = "[-start|-stop] -tap device.tap -hub ir_value [dr_length]" " [-port number] [-tool number] [-vir [vir_value [length [instr_code]]]]", }, COMMAND_REGISTRATION_DONE }; int ipdbg_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, ipdbg_command_handlers); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/server/ipdbg.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* Copyright (C) 2020 by Daniel Anselmi <danselmi@gmx.ch> */ #ifndef OPENOCD_IPDBG_IPDBG_H #define OPENOCD_IPDBG_IPDBG_H #include <helper/command.h> int ipdbg_register_commands(struct command_context *cmd_ctx); #endif /* OPENOCD_IPDBG_IPDBG_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/server/rtt_server.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016-2017 by Marc Schink <dev@zapb.de> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdint.h> #include <rtt/rtt.h> #include "server.h" #include "rtt_server.h" /** * @file * * RTT server. * * This server allows access to Real Time Transfer (RTT) channels via TCP * connections. */ struct rtt_service { unsigned int channel; }; static int read_callback(unsigned int channel, const uint8_t *buffer, size_t length, void *user_data) { int ret; struct connection *connection; size_t offset; connection = (struct connection *)user_data; offset = 0; while (offset < length) { ret = connection_write(connection, buffer + offset, length - offset); if (ret < 0) { LOG_ERROR("Failed to write data to socket."); return ERROR_FAIL; } offset += ret; } return ERROR_OK; } static int rtt_new_connection(struct connection *connection) { int ret; struct rtt_service *service; service = connection->service->priv; LOG_DEBUG("rtt: New connection for channel %u", service->channel); ret = rtt_register_sink(service->channel, &read_callback, connection); if (ret != ERROR_OK) return ret; return ERROR_OK; } static int rtt_connection_closed(struct connection *connection) { struct rtt_service *service; service = (struct rtt_service *)connection->service->priv; rtt_unregister_sink(service->channel, &read_callback, connection); LOG_DEBUG("rtt: Connection for channel %u closed", service->channel); return ERROR_OK; } static int rtt_input(struct connection *connection) { int bytes_read; unsigned char buffer[1024]; struct rtt_service *service; size_t length; service = (struct rtt_service *)connection->service->priv; bytes_read = connection_read(connection, buffer, sizeof(buffer)); if (!bytes_read) return ERROR_SERVER_REMOTE_CLOSED; else if (bytes_read < 0) { LOG_ERROR("error during read: %s", strerror(errno)); return ERROR_SERVER_REMOTE_CLOSED; } length = bytes_read; rtt_write_channel(service->channel, buffer, &length); return ERROR_OK; } static const struct service_driver rtt_service_driver = { .name = "rtt", .new_connection_during_keep_alive_handler = NULL, .new_connection_handler = rtt_new_connection, .input_handler = rtt_input, .connection_closed_handler = rtt_connection_closed, .keep_client_alive_handler = NULL, }; COMMAND_HANDLER(handle_rtt_start_command) { int ret; struct rtt_service *service; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; service = malloc(sizeof(struct rtt_service)); if (!service) return ERROR_FAIL; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], service->channel); ret = add_service(&rtt_service_driver, CMD_ARGV[0], CONNECTION_LIMIT_UNLIMITED, service); if (ret != ERROR_OK) { free(service); return ERROR_FAIL; } return ERROR_OK; } COMMAND_HANDLER(handle_rtt_stop_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; remove_service("rtt", CMD_ARGV[0]); return ERROR_OK; } static const struct command_registration rtt_server_subcommand_handlers[] = { { .name = "start", .handler = handle_rtt_start_command, .mode = COMMAND_ANY, .help = "Start a RTT server", .usage = "<port> <channel>" }, { .name = "stop", .handler = handle_rtt_stop_command, .mode = COMMAND_ANY, .help = "Stop a RTT server", .usage = "<port>" }, COMMAND_REGISTRATION_DONE }; static const struct command_registration rtt_server_command_handlers[] = { { .name = "server", .mode = COMMAND_ANY, .help = "RTT server", .usage = "", .chain = rtt_server_subcommand_handlers }, COMMAND_REGISTRATION_DONE }; static const struct command_registration rtt_command_handlers[] = { { .name = "rtt", .mode = COMMAND_ANY, .help = "RTT", .usage = "", .chain = rtt_server_command_handlers }, COMMAND_REGISTRATION_DONE }; int rtt_server_register_commands(struct command_context *ctx) { return register_commands(ctx, NULL, rtt_command_handlers); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/server/rtt_server.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2016-2017 by Marc Schink <dev@zapb.de> */ #ifndef OPENOCD_SERVER_RTT_SERVER_H #define OPENOCD_SERVER_RTT_SERVER_H #include <helper/command.h> int rtt_server_register_commands(struct command_context *ctx); #endif /* OPENOCD_SERVER_RTT_SERVER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/server/server.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "server.h" #include <helper/time_support.h> #include <target/target.h> #include <target/target_request.h> #include <target/openrisc/jsp_server.h> #include "openocd.h" #include "tcl_server.h" #include "telnet_server.h" #include <signal.h> #ifdef HAVE_NETDB_H #include <netdb.h> #endif #ifndef _WIN32 #include <netinet/tcp.h> #endif static struct service *services; enum shutdown_reason { CONTINUE_MAIN_LOOP, /* stay in main event loop */ SHUTDOWN_REQUESTED, /* set by shutdown command; exit the event loop and quit the debugger */ SHUTDOWN_WITH_ERROR_CODE, /* set by shutdown command; quit with non-zero return code */ SHUTDOWN_WITH_SIGNAL_CODE /* set by sig_handler; exec shutdown then exit with signal as return code */ }; static enum shutdown_reason shutdown_openocd = CONTINUE_MAIN_LOOP; /* store received signal to exit application by killing ourselves */ static int last_signal; /* set the polling period to 100ms */ static int polling_period = 100; /* address by name on which to listen for incoming TCP/IP connections */ static char *bindto_name; static int add_connection(struct service *service, struct command_context *cmd_ctx) { socklen_t address_size; struct connection *c, **p; int retval; int flag = 1; c = malloc(sizeof(struct connection)); c->fd = -1; c->fd_out = -1; memset(&c->sin, 0, sizeof(c->sin)); c->cmd_ctx = copy_command_context(cmd_ctx); c->service = service; c->input_pending = false; c->priv = NULL; c->next = NULL; if (service->type == CONNECTION_TCP) { address_size = sizeof(c->sin); c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); c->fd_out = c->fd; /* This increases performance dramatically for e.g. GDB load which * does not have a sliding window protocol. * * Ignore errors from this fn as it probably just means less performance */ setsockopt(c->fd, /* socket affected */ IPPROTO_TCP, /* set option at TCP level */ TCP_NODELAY, /* name of option */ (char *)&flag, /* the cast is historical cruft */ sizeof(int)); /* length of option value */ LOG_INFO("accepting '%s' connection on tcp/%s", service->name, service->port); retval = service->new_connection(c); if (retval != ERROR_OK) { close_socket(c->fd); LOG_ERROR("attempted '%s' connection rejected", service->name); command_done(c->cmd_ctx); free(c); return retval; } } else if (service->type == CONNECTION_STDINOUT) { c->fd = service->fd; c->fd_out = fileno(stdout); #ifdef _WIN32 /* we are using stdin/out so ignore ctrl-c under windoze */ SetConsoleCtrlHandler(NULL, TRUE); #endif /* do not check for new connections again on stdin */ service->fd = -1; LOG_INFO("accepting '%s' connection from pipe", service->name); retval = service->new_connection(c); if (retval != ERROR_OK) { LOG_ERROR("attempted '%s' connection rejected", service->name); command_done(c->cmd_ctx); free(c); return retval; } } else if (service->type == CONNECTION_PIPE) { c->fd = service->fd; /* do not check for new connections again on stdin */ service->fd = -1; char *out_file = alloc_printf("%so", service->port); c->fd_out = open(out_file, O_WRONLY); free(out_file); if (c->fd_out == -1) { LOG_ERROR("could not open %s", service->port); command_done(c->cmd_ctx); free(c); return ERROR_FAIL; } LOG_INFO("accepting '%s' connection from pipe %s", service->name, service->port); retval = service->new_connection(c); if (retval != ERROR_OK) { LOG_ERROR("attempted '%s' connection rejected", service->name); command_done(c->cmd_ctx); free(c); return retval; } } /* add to the end of linked list */ for (p = &service->connections; *p; p = &(*p)->next) ; *p = c; if (service->max_connections != CONNECTION_LIMIT_UNLIMITED) service->max_connections--; return ERROR_OK; } static int remove_connection(struct service *service, struct connection *connection) { struct connection **p = &service->connections; struct connection *c; /* find connection */ while ((c = *p)) { if (c->fd == connection->fd) { service->connection_closed(c); if (service->type == CONNECTION_TCP) close_socket(c->fd); else if (service->type == CONNECTION_PIPE) { /* The service will listen to the pipe again */ c->service->fd = c->fd; } command_done(c->cmd_ctx); /* delete connection */ *p = c->next; free(c); if (service->max_connections != CONNECTION_LIMIT_UNLIMITED) service->max_connections++; break; } /* redirect p to next list pointer */ p = &(*p)->next; } return ERROR_OK; } static void free_service(struct service *c) { free(c->name); free(c->port); free(c); } int add_service(const struct service_driver *driver, const char *port, int max_connections, void *priv) { struct service *c, **p; struct hostent *hp; int so_reuseaddr_option = 1; c = malloc(sizeof(struct service)); c->name = strdup(driver->name); c->port = strdup(port); c->max_connections = 1; /* Only TCP/IP ports can support more than one connection */ c->fd = -1; c->connections = NULL; c->new_connection_during_keep_alive = driver->new_connection_during_keep_alive_handler; c->new_connection = driver->new_connection_handler; c->input = driver->input_handler; c->connection_closed = driver->connection_closed_handler; c->keep_client_alive = driver->keep_client_alive_handler; c->priv = priv; c->next = NULL; long portnumber; if (strcmp(c->port, "pipe") == 0) c->type = CONNECTION_STDINOUT; else { char *end; portnumber = strtol(c->port, &end, 0); if (!*end && (parse_long(c->port, &portnumber) == ERROR_OK)) { c->portnumber = portnumber; c->type = CONNECTION_TCP; } else c->type = CONNECTION_PIPE; } if (c->type == CONNECTION_TCP) { c->max_connections = max_connections; c->fd = socket(AF_INET, SOCK_STREAM, 0); if (c->fd == -1) { LOG_ERROR("error creating socket: %s", strerror(errno)); free_service(c); return ERROR_FAIL; } setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&so_reuseaddr_option, sizeof(int)); socket_nonblock(c->fd); memset(&c->sin, 0, sizeof(c->sin)); c->sin.sin_family = AF_INET; if (!bindto_name) c->sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); else { hp = gethostbyname(bindto_name); if (!hp) { LOG_ERROR("couldn't resolve bindto address: %s", bindto_name); close_socket(c->fd); free_service(c); return ERROR_FAIL; } memcpy(&c->sin.sin_addr, hp->h_addr_list[0], hp->h_length); } c->sin.sin_port = htons(c->portnumber); if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) { LOG_ERROR("couldn't bind %s to socket on port %d: %s", c->name, c->portnumber, strerror(errno)); close_socket(c->fd); free_service(c); return ERROR_FAIL; } #ifndef _WIN32 int segsize = 65536; setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int)); #endif int window_size = 128 * 1024; /* These setsockopt()s must happen before the listen() */ setsockopt(c->fd, SOL_SOCKET, SO_SNDBUF, (char *)&window_size, sizeof(window_size)); setsockopt(c->fd, SOL_SOCKET, SO_RCVBUF, (char *)&window_size, sizeof(window_size)); if (listen(c->fd, 1) == -1) { LOG_ERROR("couldn't listen on socket: %s", strerror(errno)); close_socket(c->fd); free_service(c); return ERROR_FAIL; } struct sockaddr_in addr_in; addr_in.sin_port = 0; socklen_t addr_in_size = sizeof(addr_in); if (getsockname(c->fd, (struct sockaddr *)&addr_in, &addr_in_size) == 0) LOG_INFO("Listening on port %hu for %s connections", ntohs(addr_in.sin_port), c->name); } else if (c->type == CONNECTION_STDINOUT) { c->fd = fileno(stdin); #ifdef _WIN32 /* for win32 set stdin/stdout to binary mode */ if (_setmode(_fileno(stdout), _O_BINARY) < 0) LOG_WARNING("cannot change stdout mode to binary"); if (_setmode(_fileno(stdin), _O_BINARY) < 0) LOG_WARNING("cannot change stdin mode to binary"); if (_setmode(_fileno(stderr), _O_BINARY) < 0) LOG_WARNING("cannot change stderr mode to binary"); #else socket_nonblock(c->fd); #endif } else if (c->type == CONNECTION_PIPE) { #ifdef _WIN32 /* we currently do not support named pipes under win32 * so exit openocd for now */ LOG_ERROR("Named pipes currently not supported under this os"); free_service(c); return ERROR_FAIL; #else /* Pipe we're reading from */ c->fd = open(c->port, O_RDONLY | O_NONBLOCK); if (c->fd == -1) { LOG_ERROR("could not open %s", c->port); free_service(c); return ERROR_FAIL; } #endif } /* add to the end of linked list */ for (p = &services; *p; p = &(*p)->next) ; *p = c; return ERROR_OK; } static void remove_connections(struct service *service) { struct connection *connection; connection = service->connections; while (connection) { struct connection *tmp; tmp = connection->next; remove_connection(service, connection); connection = tmp; } } int remove_service(const char *name, const char *port) { struct service *tmp; struct service *prev; prev = services; for (tmp = services; tmp; prev = tmp, tmp = tmp->next) { if (!strcmp(tmp->name, name) && !strcmp(tmp->port, port)) { remove_connections(tmp); if (tmp == services) services = tmp->next; else prev->next = tmp->next; if (tmp->type != CONNECTION_STDINOUT) close_socket(tmp->fd); free(tmp->priv); free_service(tmp); return ERROR_OK; } } return ERROR_OK; } static int remove_services(void) { struct service *c = services; /* loop service */ while (c) { struct service *next = c->next; remove_connections(c); free(c->name); if (c->type == CONNECTION_PIPE) { if (c->fd != -1) close(c->fd); } free(c->port); free(c->priv); /* delete service */ free(c); /* remember the last service for unlinking */ c = next; } services = NULL; return ERROR_OK; } void server_keep_clients_alive(void) { for (struct service *s = services; s; s = s->next) if (s->keep_client_alive) for (struct connection *c = s->connections; c; c = c->next) s->keep_client_alive(c); } int server_loop(struct command_context *command_context) { struct service *service; bool poll_ok = true; /* used in select() */ fd_set read_fds; int fd_max; /* used in accept() */ int retval; int64_t next_event = timeval_ms() + polling_period; #ifndef _WIN32 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) LOG_ERROR("couldn't set SIGPIPE to SIG_IGN"); #endif while (shutdown_openocd == CONTINUE_MAIN_LOOP) { /* monitor sockets for activity */ fd_max = 0; FD_ZERO(&read_fds); /* add service and connection fds to read_fds */ for (service = services; service; service = service->next) { if (service->fd != -1) { /* listen for new connections */ FD_SET(service->fd, &read_fds); if (service->fd > fd_max) fd_max = service->fd; } if (service->connections) { struct connection *c; for (c = service->connections; c; c = c->next) { /* check for activity on the connection */ FD_SET(c->fd, &read_fds); if (c->fd > fd_max) fd_max = c->fd; } } } struct timeval tv; tv.tv_sec = 0; if (poll_ok) { /* we're just polling this iteration, this is faster on embedded * hosts */ tv.tv_usec = 0; retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv); } else { /* Timeout socket_select() when a target timer expires or every polling_period */ int timeout_ms = next_event - timeval_ms(); if (timeout_ms < 0) timeout_ms = 0; else if (timeout_ms > polling_period) timeout_ms = polling_period; tv.tv_usec = timeout_ms * 1000; /* Only while we're sleeping we'll let others run */ retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv); } if (retval == -1) { #ifdef _WIN32 errno = WSAGetLastError(); if (errno == WSAEINTR) FD_ZERO(&read_fds); else { LOG_ERROR("error during select: %s", strerror(errno)); return ERROR_FAIL; } #else if (errno == EINTR) FD_ZERO(&read_fds); else { LOG_ERROR("error during select: %s", strerror(errno)); return ERROR_FAIL; } #endif } if (retval == 0) { /* Execute callbacks of expired timers when * - there was nothing to do if poll_ok was true * - socket_select() timed out if poll_ok was false, now one or more * timers expired or the polling period elapsed */ target_call_timer_callbacks(); next_event = target_timer_next_event(); process_jim_events(command_context); FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */ /* We timed out/there was nothing to do, timeout rather than poll next time **/ poll_ok = false; } else { /* There was something to do, next time we'll just poll */ poll_ok = true; } /* This is a simple back-off algorithm where we immediately * re-poll if we did something this time around. * * This greatly improves performance of DCC. */ poll_ok = poll_ok || target_got_message(); for (service = services; service; service = service->next) { /* handle new connections on listeners */ if ((service->fd != -1) && (FD_ISSET(service->fd, &read_fds))) { if (service->max_connections != 0) add_connection(service, command_context); else { if (service->type == CONNECTION_TCP) { struct sockaddr_in sin; socklen_t address_size = sizeof(sin); int tmp_fd; tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); close_socket(tmp_fd); } LOG_INFO( "rejected '%s' connection, no more connections allowed", service->name); } } /* handle activity on connections */ if (service->connections) { struct connection *c; for (c = service->connections; c; ) { if ((c->fd >= 0 && FD_ISSET(c->fd, &read_fds)) || c->input_pending) { retval = service->input(c); if (retval != ERROR_OK) { struct connection *next = c->next; if (service->type == CONNECTION_PIPE || service->type == CONNECTION_STDINOUT) { /* if connection uses a pipe then * shutdown openocd on error */ shutdown_openocd = SHUTDOWN_REQUESTED; } remove_connection(service, c); LOG_INFO("dropped '%s' connection", service->name); c = next; continue; } } c = c->next; } } } #ifdef _WIN32 MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE; } #endif } /* when quit for signal or CTRL-C, run (eventually user implemented) "shutdown" */ if (shutdown_openocd == SHUTDOWN_WITH_SIGNAL_CODE) command_run_line(command_context, "shutdown"); return shutdown_openocd == SHUTDOWN_WITH_ERROR_CODE ? ERROR_FAIL : ERROR_OK; } static void sig_handler(int sig) { /* store only first signal that hits us */ if (shutdown_openocd == CONTINUE_MAIN_LOOP) { shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE; last_signal = sig; LOG_DEBUG("Terminating on Signal %d", sig); } else LOG_DEBUG("Ignored extra Signal %d", sig); } #ifdef _WIN32 BOOL WINAPI control_handler(DWORD ctrl_type) { shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE; return TRUE; } #else static void sigkey_handler(int sig) { /* ignore keystroke generated signals if not in foreground process group */ if (tcgetpgrp(STDIN_FILENO) > 0) sig_handler(sig); else LOG_DEBUG("Ignored Signal %d", sig); } #endif int server_host_os_entry(void) { /* this currently only calls WSAStartup on native win32 systems * before any socket operations are performed. * This is an issue if you call init in your config script */ #ifdef _WIN32 WORD version_requested; WSADATA wsadata; version_requested = MAKEWORD(2, 2); if (WSAStartup(version_requested, &wsadata) != 0) { LOG_ERROR("Failed to Open Winsock"); return ERROR_FAIL; } #endif return ERROR_OK; } int server_host_os_close(void) { #ifdef _WIN32 WSACleanup(); #endif return ERROR_OK; } int server_preinit(void) { #ifdef _WIN32 /* register ctrl-c handler */ SetConsoleCtrlHandler(control_handler, TRUE); signal(SIGBREAK, sig_handler); signal(SIGINT, sig_handler); #else signal(SIGHUP, sig_handler); signal(SIGPIPE, sig_handler); signal(SIGQUIT, sigkey_handler); signal(SIGINT, sigkey_handler); #endif signal(SIGTERM, sig_handler); signal(SIGABRT, sig_handler); return ERROR_OK; } int server_init(struct command_context *cmd_ctx) { int ret = tcl_init(); if (ret != ERROR_OK) return ret; ret = telnet_init("Open On-Chip Debugger"); if (ret != ERROR_OK) { remove_services(); return ret; } return ERROR_OK; } int server_quit(void) { remove_services(); target_quit(); #ifdef _WIN32 SetConsoleCtrlHandler(control_handler, FALSE); return ERROR_OK; #endif /* return signal number so we can kill ourselves */ return last_signal; } void server_free(void) { tcl_service_free(); telnet_service_free(); jsp_service_free(); free(bindto_name); } void exit_on_signal(int sig) { #ifndef _WIN32 /* bring back default system handler and kill yourself */ signal(sig, SIG_DFL); kill(getpid(), sig); #endif } int connection_write(struct connection *connection, const void *data, int len) { if (len == 0) { /* successful no-op. Sockets and pipes behave differently here... */ return 0; } if (connection->service->type == CONNECTION_TCP) return write_socket(connection->fd_out, data, len); else return write(connection->fd_out, data, len); } int connection_read(struct connection *connection, void *data, int len) { if (connection->service->type == CONNECTION_TCP) return read_socket(connection->fd, data, len); else return read(connection->fd, data, len); } bool openocd_is_shutdown_pending(void) { return shutdown_openocd != CONTINUE_MAIN_LOOP; } /* tell the server we want to shut down */ COMMAND_HANDLER(handle_shutdown_command) { LOG_USER("shutdown command invoked"); shutdown_openocd = SHUTDOWN_REQUESTED; command_run_line(CMD_CTX, "_run_pre_shutdown_commands"); if (CMD_ARGC == 1) { if (!strcmp(CMD_ARGV[0], "error")) { shutdown_openocd = SHUTDOWN_WITH_ERROR_CODE; return ERROR_FAIL; } } return ERROR_COMMAND_CLOSE_CONNECTION; } COMMAND_HANDLER(handle_poll_period_command) { if (CMD_ARGC == 0) LOG_WARNING("You need to set a period value"); else COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], polling_period); LOG_INFO("set servers polling period to %ums", polling_period); return ERROR_OK; } COMMAND_HANDLER(handle_bindto_command) { switch (CMD_ARGC) { case 0: command_print(CMD, "bindto name: %s", bindto_name); break; case 1: free(bindto_name); bindto_name = strdup(CMD_ARGV[0]); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } static const struct command_registration server_command_handlers[] = { { .name = "shutdown", .handler = &handle_shutdown_command, .mode = COMMAND_ANY, .usage = "", .help = "shut the server down", }, { .name = "poll_period", .handler = &handle_poll_period_command, .mode = COMMAND_ANY, .usage = "", .help = "set the servers polling period", }, { .name = "bindto", .handler = &handle_bindto_command, .mode = COMMAND_CONFIG, .usage = "[name]", .help = "Specify address by name on which to listen for " "incoming TCP/IP connections", }, COMMAND_REGISTRATION_DONE }; int server_register_commands(struct command_context *cmd_ctx) { int retval = telnet_register_commands(cmd_ctx); if (retval != ERROR_OK) return retval; retval = tcl_register_commands(cmd_ctx); if (retval != ERROR_OK) return retval; retval = jsp_register_commands(cmd_ctx); if (retval != ERROR_OK) return retval; return register_commands(cmd_ctx, NULL, server_command_handlers); } COMMAND_HELPER(server_port_command, unsigned short *out) { switch (CMD_ARGC) { case 0: command_print(CMD, "%d", *out); break; case 1: { uint16_t port; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port); *out = port; break; } default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } COMMAND_HELPER(server_pipe_command, char **out) { switch (CMD_ARGC) { case 0: command_print(CMD, "%s", *out); break; case 1: { if (CMD_CTX->mode == COMMAND_EXEC) { LOG_WARNING("unable to change server port after init"); return ERROR_COMMAND_ARGUMENT_INVALID; } free(*out); *out = strdup(CMD_ARGV[0]); break; } default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/server/server.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_SERVER_SERVER_H #define OPENOCD_SERVER_SERVER_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include <helper/replacements.h> #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif enum connection_type { CONNECTION_TCP, CONNECTION_PIPE, CONNECTION_STDINOUT }; #define CONNECTION_LIMIT_UNLIMITED (-1) struct connection { int fd; int fd_out; /* When using pipes we're writing to a different fd */ struct sockaddr_in sin; struct command_context *cmd_ctx; struct service *service; bool input_pending; void *priv; struct connection *next; }; struct service_driver { /** the name of the server */ const char *name; /** optional minimal setup to accept a connection during keep-alive */ int (*new_connection_during_keep_alive_handler)(struct connection *connection); /** * complete code to accept a new connection. * If 'new_connection_during_keep_alive_handler' above is present, this can be * either called alone during the server_loop, or after the function above. * Check the implementation in gdb_server. * */ int (*new_connection_handler)(struct connection *connection); /** callback to handle incoming data */ int (*input_handler)(struct connection *connection); /** callback to tear down the connection */ int (*connection_closed_handler)(struct connection *connection); /** called periodically to send keep-alive messages on the connection */ void (*keep_client_alive_handler)(struct connection *connection); }; struct service { char *name; enum connection_type type; char *port; unsigned short portnumber; int fd; struct sockaddr_in sin; int max_connections; struct connection *connections; int (*new_connection_during_keep_alive)(struct connection *connection); int (*new_connection)(struct connection *connection); int (*input)(struct connection *connection); int (*connection_closed)(struct connection *connection); void (*keep_client_alive)(struct connection *connection); void *priv; struct service *next; }; int add_service(const struct service_driver *driver, const char *port, int max_connections, void *priv); int remove_service(const char *name, const char *port); int server_host_os_entry(void); int server_host_os_close(void); int server_preinit(void); int server_init(struct command_context *cmd_ctx); int server_quit(void); void server_free(void); void exit_on_signal(int sig); void server_keep_clients_alive(void); int server_loop(struct command_context *command_context); int server_register_commands(struct command_context *context); int connection_write(struct connection *connection, const void *data, int len); int connection_read(struct connection *connection, void *data, int len); bool openocd_is_shutdown_pending(void); /** * Defines an extended command handler function declaration to enable * access to (and manipulation of) the server port number. * Call server_port like a normal COMMAND_HANDLER with an extra @a out parameter * to receive the specified port number. */ COMMAND_HELPER(server_pipe_command, char **out); COMMAND_HELPER(server_port_command, unsigned short *out); #define ERROR_SERVER_REMOTE_CLOSED (-400) #define ERROR_CONNECTION_REJECTED (-401) #endif /* OPENOCD_SERVER_SERVER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/server/startup.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Defines basic Tcl procs for OpenOCD server modules # Handle GDB 'R' packet. Can be overridden by configuration script, # but it's not something one would expect target scripts to do # normally proc ocd_gdb_restart {target_id} { # Fix!!! we're resetting all targets here! Really we should reset only # one target reset halt } lappend _telnet_autocomplete_skip prevent_cps lappend _telnet_autocomplete_skip POST lappend _telnet_autocomplete_skip Host: proc prevent_cps {} { echo "Possible SECURITY ATTACK detected." echo "It looks like somebody is sending POST or Host: commands to OpenOCD." echo "This is likely due to an attacker attempting to use Cross Protocol Scripting" echo "to compromise your OpenOCD instance. Connection aborted." exit } proc POST {args} { prevent_cps } proc Host: {args} { prevent_cps } # list of commands we don't want to appear in autocomplete lappend _telnet_autocomplete_skip _telnet_autocomplete_helper # helper for telnet autocomplete proc _telnet_autocomplete_helper pattern { set cmds [info commands $pattern] # skip matches in variable '_telnet_autocomplete_skip' foreach skip $::_telnet_autocomplete_skip { foreach n [lsearch -all -regexp $cmds "^$skip\$"] { set cmds [lreplace $cmds $n $n] } } return [lsort $cmds] } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/server/tcl_server.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2010 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "tcl_server.h" #include <target/target.h> #include <helper/binarybuffer.h> #define TCL_SERVER_VERSION "TCL Server 0.1" #define TCL_LINE_INITIAL (4*1024) #define TCL_LINE_MAX (4*1024*1024) struct tcl_connection { int tc_linedrop; int tc_lineoffset; int tc_line_size; char *tc_line; int tc_outerror;/* flag an output error */ enum target_state tc_laststate; bool tc_notify; bool tc_trace; }; static char *tcl_port; /* handlers */ static int tcl_new_connection(struct connection *connection); static int tcl_input(struct connection *connection); static int tcl_output(struct connection *connection, const void *buf, ssize_t len); static int tcl_closed(struct connection *connection); static int tcl_target_callback_event_handler(struct target *target, enum target_event event, void *priv) { struct connection *connection = priv; struct tcl_connection *tclc; char buf[256]; tclc = connection->priv; if (tclc->tc_notify) { snprintf(buf, sizeof(buf), "type target_event event %s\r\n\x1a", target_event_name(event)); tcl_output(connection, buf, strlen(buf)); } if (tclc->tc_laststate != target->state) { tclc->tc_laststate = target->state; if (tclc->tc_notify) { snprintf(buf, sizeof(buf), "type target_state state %s\r\n\x1a", target_state_name(target)); tcl_output(connection, buf, strlen(buf)); } } return ERROR_OK; } static int tcl_target_callback_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv) { struct connection *connection = priv; struct tcl_connection *tclc; char buf[256]; tclc = connection->priv; if (tclc->tc_notify) { snprintf(buf, sizeof(buf), "type target_reset mode %s\r\n\x1a", target_reset_mode_name(reset_mode)); tcl_output(connection, buf, strlen(buf)); } return ERROR_OK; } static int tcl_target_callback_trace_handler(struct target *target, size_t len, uint8_t *data, void *priv) { struct connection *connection = priv; struct tcl_connection *tclc; char *header = "type target_trace data "; char *trailer = "\r\n\x1a"; size_t hex_len = len * 2 + 1; size_t max_len = hex_len + strlen(header) + strlen(trailer); char *buf, *hex; tclc = connection->priv; if (tclc->tc_trace) { hex = malloc(hex_len); buf = malloc(max_len); hexify(hex, data, len, hex_len); snprintf(buf, max_len, "%s%s%s", header, hex, trailer); tcl_output(connection, buf, strlen(buf)); free(hex); free(buf); } return ERROR_OK; } /* write data out to a socket. * * this is a blocking write, so the return value must equal the length, if * that is not the case then flag the connection with an output error. */ int tcl_output(struct connection *connection, const void *data, ssize_t len) { ssize_t wlen; struct tcl_connection *tclc; tclc = connection->priv; if (tclc->tc_outerror) return ERROR_SERVER_REMOTE_CLOSED; wlen = connection_write(connection, data, len); if (wlen == len) return ERROR_OK; LOG_ERROR("error during write: %d != %d", (int)wlen, (int)len); tclc->tc_outerror = 1; return ERROR_SERVER_REMOTE_CLOSED; } /* connections */ static int tcl_new_connection(struct connection *connection) { struct tcl_connection *tclc; tclc = calloc(1, sizeof(struct tcl_connection)); if (!tclc) return ERROR_CONNECTION_REJECTED; tclc->tc_line_size = TCL_LINE_INITIAL; tclc->tc_line = malloc(tclc->tc_line_size); if (!tclc->tc_line) { free(tclc); return ERROR_CONNECTION_REJECTED; } connection->priv = tclc; struct target *target = get_current_target_or_null(connection->cmd_ctx); if (target) tclc->tc_laststate = target->state; /* store the connection object on cmd_ctx so we can access it from command handlers */ connection->cmd_ctx->output_handler_priv = connection; target_register_event_callback(tcl_target_callback_event_handler, connection); target_register_reset_callback(tcl_target_callback_reset_handler, connection); target_register_trace_callback(tcl_target_callback_trace_handler, connection); return ERROR_OK; } static int tcl_input(struct connection *connection) { Jim_Interp *interp = (Jim_Interp *)connection->cmd_ctx->interp; int retval; int i; ssize_t rlen; const char *result; int reslen; struct tcl_connection *tclc; unsigned char in[256]; char *tc_line_new; int tc_line_size_new; rlen = connection_read(connection, &in, sizeof(in)); if (rlen <= 0) { if (rlen < 0) LOG_ERROR("error during read: %s", strerror(errno)); return ERROR_SERVER_REMOTE_CLOSED; } tclc = connection->priv; if (!tclc) return ERROR_CONNECTION_REJECTED; /* push as much data into the line as possible */ for (i = 0; i < rlen; i++) { /* buffer the data */ tclc->tc_line[tclc->tc_lineoffset] = in[i]; if (tclc->tc_lineoffset + 1 < tclc->tc_line_size) { tclc->tc_lineoffset++; } else if (tclc->tc_line_size >= TCL_LINE_MAX) { /* maximum line size reached, drop line */ tclc->tc_linedrop = 1; } else { /* grow line buffer: exponential below 1 MB, linear above */ if (tclc->tc_line_size <= 1*1024*1024) tc_line_size_new = tclc->tc_line_size * 2; else tc_line_size_new = tclc->tc_line_size + 1*1024*1024; if (tc_line_size_new > TCL_LINE_MAX) tc_line_size_new = TCL_LINE_MAX; tc_line_new = realloc(tclc->tc_line, tc_line_size_new); if (!tc_line_new) { tclc->tc_linedrop = 1; } else { tclc->tc_line = tc_line_new; tclc->tc_line_size = tc_line_size_new; tclc->tc_lineoffset++; } } /* ctrl-z is end of command. When testing from telnet, just * press ctrl-z a couple of times first to put telnet into the * mode where it will send 0x1a in response to pressing ctrl-z */ if (in[i] != '\x1a') continue; /* process the line */ if (tclc->tc_linedrop) { #define ESTR "line too long\n" retval = tcl_output(connection, ESTR, sizeof(ESTR)); if (retval != ERROR_OK) return retval; #undef ESTR } else { tclc->tc_line[tclc->tc_lineoffset-1] = '\0'; command_run_line(connection->cmd_ctx, tclc->tc_line); result = Jim_GetString(Jim_GetResult(interp), &reslen); retval = tcl_output(connection, result, reslen); if (retval != ERROR_OK) return retval; /* Always output ctrl-z as end of line to allow multiline results */ tcl_output(connection, "\x1a", 1); } tclc->tc_lineoffset = 0; tclc->tc_linedrop = 0; } return ERROR_OK; } static int tcl_closed(struct connection *connection) { struct tcl_connection *tclc; tclc = connection->priv; /* cleanup connection context */ if (tclc) { free(tclc->tc_line); free(tclc); connection->priv = NULL; } target_unregister_event_callback(tcl_target_callback_event_handler, connection); target_unregister_reset_callback(tcl_target_callback_reset_handler, connection); target_unregister_trace_callback(tcl_target_callback_trace_handler, connection); return ERROR_OK; } static const struct service_driver tcl_service_driver = { .name = "tcl", .new_connection_during_keep_alive_handler = NULL, .new_connection_handler = tcl_new_connection, .input_handler = tcl_input, .connection_closed_handler = tcl_closed, .keep_client_alive_handler = NULL, }; int tcl_init(void) { if (strcmp(tcl_port, "disabled") == 0) { LOG_INFO("tcl server disabled"); return ERROR_OK; } return add_service(&tcl_service_driver, tcl_port, CONNECTION_LIMIT_UNLIMITED, NULL); } COMMAND_HANDLER(handle_tcl_port_command) { return CALL_COMMAND_HANDLER(server_pipe_command, &tcl_port); } COMMAND_HANDLER(handle_tcl_notifications_command) { struct connection *connection = NULL; struct tcl_connection *tclc = NULL; if (CMD_CTX->output_handler_priv) connection = CMD_CTX->output_handler_priv; if (connection && !strcmp(connection->service->name, "tcl")) { tclc = connection->priv; return CALL_COMMAND_HANDLER(handle_command_parse_bool, &tclc->tc_notify, "Target Notification output "); } else { LOG_ERROR("%s: can only be called from the tcl server", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; } } COMMAND_HANDLER(handle_tcl_trace_command) { struct connection *connection = NULL; struct tcl_connection *tclc = NULL; if (CMD_CTX->output_handler_priv) connection = CMD_CTX->output_handler_priv; if (connection && !strcmp(connection->service->name, "tcl")) { tclc = connection->priv; return CALL_COMMAND_HANDLER(handle_command_parse_bool, &tclc->tc_trace, "Target trace output "); } else { LOG_ERROR("%s: can only be called from the tcl server", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; } } static const struct command_registration tcl_command_handlers[] = { { .name = "tcl_port", .handler = handle_tcl_port_command, .mode = COMMAND_CONFIG, .help = "Specify port on which to listen " "for incoming Tcl syntax. " "Read help on 'gdb_port'.", .usage = "[port_num]", }, { .name = "tcl_notifications", .handler = handle_tcl_notifications_command, .mode = COMMAND_EXEC, .help = "Target Notification output", .usage = "[on|off]", }, { .name = "tcl_trace", .handler = handle_tcl_trace_command, .mode = COMMAND_EXEC, .help = "Target trace output", .usage = "[on|off]", }, COMMAND_REGISTRATION_DONE }; int tcl_register_commands(struct command_context *cmd_ctx) { tcl_port = strdup("6666"); return register_commands(cmd_ctx, NULL, tcl_command_handlers); } void tcl_service_free(void) { free(tcl_port); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/server/tcl_server.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2008 * ***************************************************************************/ #ifndef OPENOCD_SERVER_TCL_SERVER_H #define OPENOCD_SERVER_TCL_SERVER_H #include <server/server.h> int tcl_init(void); int tcl_register_commands(struct command_context *cmd_ctx); void tcl_service_free(void); #endif /* OPENOCD_SERVER_TCL_SERVER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/server/telnet_server.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "telnet_server.h" #include <target/target_request.h> #include <helper/configuration.h> #include <helper/list.h> static char *telnet_port; static char *negotiate = "\xFF\xFB\x03" /* IAC WILL Suppress Go Ahead */ "\xFF\xFB\x01" /* IAC WILL Echo */ "\xFF\xFD\x03" /* IAC DO Suppress Go Ahead */ "\xFF\xFE\x01"; /* IAC DON'T Echo */ #define CTRL(c) (c - '@') #define TELNET_HISTORY ".openocd_history" /* The only way we can detect that the socket is closed is the first time * we write to it, we will fail. Subsequent write operations will * succeed. Shudder! */ static int telnet_write(struct connection *connection, const void *data, int len) { struct telnet_connection *t_con = connection->priv; if (t_con->closed) return ERROR_SERVER_REMOTE_CLOSED; if (connection_write(connection, data, len) == len) return ERROR_OK; t_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } /* output an audible bell */ static int telnet_bell(struct connection *connection) { /* ("\a" does not work, at least on windows) */ return telnet_write(connection, "\x07", 1); } static int telnet_prompt(struct connection *connection) { struct telnet_connection *t_con = connection->priv; return telnet_write(connection, t_con->prompt, strlen(t_con->prompt)); } static int telnet_outputline(struct connection *connection, const char *line) { int len; /* process lines in buffer */ while (*line) { char *line_end = strchr(line, '\n'); if (line_end) len = line_end-line; else len = strlen(line); telnet_write(connection, line, len); if (line_end) { telnet_write(connection, "\r\n", 2); line += len + 1; } else line += len; } return ERROR_OK; } static int telnet_output(struct command_context *cmd_ctx, const char *line) { struct connection *connection = cmd_ctx->output_handler_priv; return telnet_outputline(connection, line); } static void telnet_log_callback(void *priv, const char *file, unsigned line, const char *function, const char *string) { struct connection *connection = priv; struct telnet_connection *t_con = connection->priv; size_t i; size_t tmp; /* If the prompt is not visible, simply output the message. */ if (!t_con->prompt_visible) { telnet_outputline(connection, string); return; } /* Clear the command line. */ tmp = strlen(t_con->prompt) + t_con->line_size; for (i = 0; i < tmp; i += 16) telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", MIN(tmp - i, 16)); for (i = 0; i < tmp; i += 16) telnet_write(connection, " ", MIN(tmp - i, 16)); for (i = 0; i < tmp; i += 16) telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", MIN(tmp - i, 16)); telnet_outputline(connection, string); /* Put the command line to its previous state. */ telnet_prompt(connection); telnet_write(connection, t_con->line, t_con->line_size); for (i = t_con->line_cursor; i < t_con->line_size; i++) telnet_write(connection, "\b", 1); } static void telnet_load_history(struct telnet_connection *t_con) { FILE *histfp; char buffer[TELNET_BUFFER_SIZE]; int i = 0; char *history = get_home_dir(TELNET_HISTORY); if (!history) { LOG_INFO("unable to get user home directory, telnet history will be disabled"); return; } histfp = fopen(history, "rb"); if (histfp) { while (fgets(buffer, sizeof(buffer), histfp)) { char *p = strchr(buffer, '\n'); if (p) *p = '\0'; if (buffer[0] && i < TELNET_LINE_HISTORY_SIZE) t_con->history[i++] = strdup(buffer); } t_con->next_history = i; t_con->next_history %= TELNET_LINE_HISTORY_SIZE; /* try to set to last entry - 1, that way we skip over any exit/shutdown cmds */ t_con->current_history = t_con->next_history > 0 ? i - 1 : 0; fclose(histfp); } free(history); } static void telnet_save_history(struct telnet_connection *t_con) { FILE *histfp; int i; int num; char *history = get_home_dir(TELNET_HISTORY); if (!history) { LOG_INFO("unable to get user home directory, telnet history will be disabled"); return; } histfp = fopen(history, "wb"); if (histfp) { num = TELNET_LINE_HISTORY_SIZE; i = t_con->current_history + 1; i %= TELNET_LINE_HISTORY_SIZE; while (!t_con->history[i] && num > 0) { i++; i %= TELNET_LINE_HISTORY_SIZE; num--; } if (num > 0) { for (; num > 0; num--) { fprintf(histfp, "%s\n", t_con->history[i]); i++; i %= TELNET_LINE_HISTORY_SIZE; } } fclose(histfp); } free(history); } static int telnet_new_connection(struct connection *connection) { struct telnet_connection *telnet_connection; struct telnet_service *telnet_service = connection->service->priv; telnet_connection = calloc(1, sizeof(struct telnet_connection)); if (!telnet_connection) { LOG_ERROR("Failed to allocate telnet connection."); return ERROR_FAIL; } connection->priv = telnet_connection; /* initialize telnet connection information */ telnet_connection->prompt = strdup("> "); telnet_connection->prompt_visible = true; telnet_connection->state = TELNET_STATE_DATA; /* output goes through telnet connection */ command_set_output_handler(connection->cmd_ctx, telnet_output, connection); /* negotiate telnet options */ telnet_write(connection, negotiate, strlen(negotiate)); /* print connection banner */ if (telnet_service->banner) { telnet_write(connection, telnet_service->banner, strlen(telnet_service->banner)); telnet_write(connection, "\r\n", 2); } /* the prompt is always placed at the line beginning */ telnet_write(connection, "\r", 1); telnet_prompt(connection); telnet_load_history(telnet_connection); log_add_callback(telnet_log_callback, connection); return ERROR_OK; } static void telnet_clear_line(struct connection *connection, struct telnet_connection *t_con) { /* move to end of line */ if (t_con->line_cursor < t_con->line_size) telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor); /* backspace, overwrite with space, backspace */ while (t_con->line_size > 0) { telnet_write(connection, "\b \b", 3); t_con->line_size--; } t_con->line_cursor = 0; } static void telnet_history_go(struct connection *connection, int idx) { struct telnet_connection *t_con = connection->priv; if (t_con->history[idx]) { telnet_clear_line(connection, t_con); t_con->line_size = strlen(t_con->history[idx]); t_con->line_cursor = t_con->line_size; memcpy(t_con->line, t_con->history[idx], t_con->line_size); telnet_write(connection, t_con->line, t_con->line_size); t_con->current_history = idx; } t_con->state = TELNET_STATE_DATA; } static void telnet_history_up(struct connection *connection) { struct telnet_connection *t_con = connection->priv; size_t last_history = (t_con->current_history > 0) ? t_con->current_history - 1 : TELNET_LINE_HISTORY_SIZE-1; telnet_history_go(connection, last_history); } static void telnet_history_down(struct connection *connection) { struct telnet_connection *t_con = connection->priv; size_t next_history; next_history = (t_con->current_history + 1) % TELNET_LINE_HISTORY_SIZE; telnet_history_go(connection, next_history); } static void telnet_history_add(struct connection *connection) { struct telnet_connection *t_con = connection->priv; /* save only non-blank not repeating lines in the history */ char *prev_line = t_con->history[(t_con->current_history > 0) ? t_con->current_history - 1 : TELNET_LINE_HISTORY_SIZE-1]; if (*t_con->line && (!prev_line || strcmp(t_con->line, prev_line))) { /* if the history slot is already taken, free it */ free(t_con->history[t_con->next_history]); /* add line to history */ t_con->history[t_con->next_history] = strdup(t_con->line); /* wrap history at TELNET_LINE_HISTORY_SIZE */ t_con->next_history = (t_con->next_history + 1) % TELNET_LINE_HISTORY_SIZE; /* current history line starts at the new entry */ t_con->current_history = t_con->next_history; free(t_con->history[t_con->current_history]); t_con->history[t_con->current_history] = strdup(""); } } static int telnet_history_print(struct connection *connection) { struct telnet_connection *tc; tc = connection->priv; for (size_t i = 1; i < TELNET_LINE_HISTORY_SIZE; i++) { char *line; /* * The tc->next_history line contains empty string (unless NULL), thus * it is not printed. */ line = tc->history[(tc->next_history + i) % TELNET_LINE_HISTORY_SIZE]; if (line) { telnet_write(connection, line, strlen(line)); telnet_write(connection, "\r\n\x00", 3); } } tc->line_size = 0; tc->line_cursor = 0; /* The prompt is always placed at the line beginning. */ telnet_write(connection, "\r", 1); return telnet_prompt(connection); } static void telnet_move_cursor(struct connection *connection, size_t pos) { struct telnet_connection *tc = connection->priv; size_t tmp; if (pos == tc->line_cursor) /* nothing to do */ return; if (pos > tc->line_size) /* out of bounds */ return; if (pos < tc->line_cursor) { tmp = tc->line_cursor - pos; for (size_t i = 0; i < tmp; i += 16) telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", MIN(tmp - i, 16)); } else { tmp = pos - tc->line_cursor; for (size_t i = 0; i < tmp; i += 16) telnet_write(connection, tc->line + tc->line_cursor + i, MIN(tmp - i, 16)); } tc->line_cursor = pos; } /* check buffer size leaving one spare character for string null termination */ static inline bool telnet_can_insert(struct connection *connection, size_t len) { struct telnet_connection *t_con = connection->priv; return t_con->line_size + len < TELNET_LINE_MAX_SIZE; } /* write to telnet console, and update the telnet_connection members * this function is capable of inserting in the middle of a line * please ensure that data does not contain special characters (\n, \r, \t, \b ...) * * returns false when it fails to insert the requested data */ static bool telnet_insert(struct connection *connection, const void *data, size_t len) { struct telnet_connection *t_con = connection->priv; if (!telnet_can_insert(connection, len)) { telnet_bell(connection); return false; } if (t_con->line_cursor < t_con->line_size) { /* we have some content after the cursor */ memmove(t_con->line + t_con->line_cursor + len, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor); } strncpy(t_con->line + t_con->line_cursor, data, len); telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size + len - t_con->line_cursor); t_con->line_size += len; t_con->line_cursor += len; for (size_t i = t_con->line_cursor; i < t_con->line_size; i++) telnet_write(connection, "\b", 1); return true; } static void telnet_delete_character(struct connection *connection) { struct telnet_connection *t_con = connection->priv; if (t_con->line_cursor == 0) return; if (t_con->line_cursor != t_con->line_size) { size_t i; telnet_write(connection, "\b", 1); t_con->line_cursor--; t_con->line_size--; memmove(t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor + 1, t_con->line_size - t_con->line_cursor); telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor); telnet_write(connection, " \b", 2); for (i = t_con->line_cursor; i < t_con->line_size; i++) telnet_write(connection, "\b", 1); } else { t_con->line_size--; t_con->line_cursor--; /* back space: move the 'printer' head one char * back, overwrite with space, move back again */ telnet_write(connection, "\b \b", 3); } } static void telnet_remove_character(struct connection *connection) { struct telnet_connection *t_con = connection->priv; if (t_con->line_cursor < t_con->line_size) { size_t i; t_con->line_size--; /* remove char from line buffer */ memmove(t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor + 1, t_con->line_size - t_con->line_cursor); /* print remainder of buffer */ telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor); /* overwrite last char with whitespace */ telnet_write(connection, " \b", 2); /* move back to cursor position*/ for (i = t_con->line_cursor; i < t_con->line_size; i++) telnet_write(connection, "\b", 1); } } static int telnet_exec_line(struct connection *connection) { struct telnet_connection *t_con = connection->priv; struct command_context *command_context = connection->cmd_ctx; int retval; telnet_write(connection, "\r\n\x00", 3); if (strcmp(t_con->line, "history") == 0) { retval = telnet_history_print(connection); if (retval != ERROR_OK) return retval; return ERROR_OK; } telnet_history_add(connection); t_con->line_size = 0; /* to suppress prompt in log callback during command execution */ t_con->prompt_visible = false; if (strcmp(t_con->line, "shutdown") == 0) telnet_save_history(t_con); retval = command_run_line(command_context, t_con->line); t_con->line_cursor = 0; t_con->prompt_visible = true; if (retval == ERROR_COMMAND_CLOSE_CONNECTION) return ERROR_SERVER_REMOTE_CLOSED; /* the prompt is always placed at the line beginning */ telnet_write(connection, "\r", 1); retval = telnet_prompt(connection); if (retval == ERROR_SERVER_REMOTE_CLOSED) return ERROR_SERVER_REMOTE_CLOSED; return ERROR_OK; } static void telnet_cut_line_to_end(struct connection *connection) { struct telnet_connection *t_con = connection->priv; /* FIXME: currently this function does not save to clipboard */ if (t_con->line_cursor < t_con->line_size) { /* overwrite with space, until end of line, move back */ for (size_t i = t_con->line_cursor; i < t_con->line_size; i++) telnet_write(connection, " ", 1); for (size_t i = t_con->line_cursor; i < t_con->line_size; i++) telnet_write(connection, "\b", 1); t_con->line[t_con->line_cursor] = '\0'; t_con->line_size = t_con->line_cursor; } } static void telnet_interrupt(struct connection *connection) { struct telnet_connection *t_con = connection->priv; /* print '^C' at line end, and display a new command prompt */ telnet_move_cursor(connection, t_con->line_size); telnet_write(connection, "^C\n\r", 4); t_con->line_cursor = 0; t_con->line_size = 0; telnet_prompt(connection); } static void telnet_auto_complete(struct connection *connection) { struct telnet_connection *t_con = connection->priv; struct command_context *command_context = connection->cmd_ctx; struct cmd_match { char *cmd; struct list_head lh; }; LIST_HEAD(matches); /* - user command sequence, either at line beginning * or we start over after these characters ';', '[', '{' * - user variable sequence, start after the character '$' * and do not contain white spaces */ bool is_variable_auto_completion = false; bool have_spaces = false; size_t seq_start = (t_con->line_cursor == 0) ? 0 : (t_con->line_cursor - 1); while (1) { char c = t_con->line[seq_start]; if (c == ';' || c == '[' || c == '{') { seq_start++; break; } else if (c == ' ') { have_spaces = true; } else if (c == '$' && !have_spaces) { is_variable_auto_completion = true; seq_start++; break; } if (seq_start == 0) break; seq_start--; } /* user command position in the line, ignore leading spaces */ size_t usr_cmd_pos = seq_start; while ((usr_cmd_pos < t_con->line_cursor) && isspace(t_con->line[usr_cmd_pos])) usr_cmd_pos++; /* check user command length */ if (t_con->line_cursor < usr_cmd_pos) { telnet_bell(connection); return; } size_t usr_cmd_len = t_con->line_cursor - usr_cmd_pos; /* optimize multiple spaces in the user command, * because info commands does not tolerate multiple spaces */ size_t optimized_spaces = 0; char query[usr_cmd_len + 1]; for (size_t i = 0; i < usr_cmd_len; i++) { if ((i < usr_cmd_len - 1) && isspace(t_con->line[usr_cmd_pos + i]) && isspace(t_con->line[usr_cmd_pos + i + 1])) { optimized_spaces++; continue; } query[i - optimized_spaces] = t_con->line[usr_cmd_pos + i]; } usr_cmd_len -= optimized_spaces; query[usr_cmd_len] = '\0'; /* filter commands */ char *query_cmd; if (is_variable_auto_completion) query_cmd = alloc_printf("lsort [info vars {%s*}]", query); else query_cmd = alloc_printf("_telnet_autocomplete_helper {%s*}", query); if (!query_cmd) { LOG_ERROR("Out of memory"); return; } int retval = Jim_EvalSource(command_context->interp, __FILE__, __LINE__, query_cmd); free(query_cmd); if (retval != JIM_OK) return; Jim_Obj *list = Jim_GetResult(command_context->interp); Jim_IncrRefCount(list); /* common prefix length of the matched commands */ size_t common_len = 0; char *first_match = NULL; /* used to compute the common prefix length */ int len = Jim_ListLength(command_context->interp, list); for (int i = 0; i < len; i++) { Jim_Obj *elem = Jim_ListGetIndex(command_context->interp, list, i); Jim_IncrRefCount(elem); char *name = (char *)Jim_GetString(elem, NULL); /* validate the command */ bool ignore_cmd = false; if (!is_variable_auto_completion) { Jim_Cmd *jim_cmd = Jim_GetCommand(command_context->interp, elem, JIM_NONE); if (!jim_cmd) { /* Why we are here? Let's ignore it! */ ignore_cmd = true; } else if (jimcmd_is_oocd_command(jim_cmd)) { struct command *cmd = jimcmd_privdata(jim_cmd); if (cmd && !cmd->handler && !cmd->jim_handler) { /* Initial part of a multi-word command. Ignore it! */ ignore_cmd = true; } else if (cmd && cmd->mode == COMMAND_CONFIG) { /* Not executable after config phase. Ignore it! */ ignore_cmd = true; } } } /* save the command in the prediction list */ if (!ignore_cmd) { struct cmd_match *match = calloc(1, sizeof(struct cmd_match)); if (!match) { LOG_ERROR("Out of memory"); Jim_DecrRefCount(command_context->interp, elem); break; /* break the for loop */ } if (list_empty(&matches)) { common_len = strlen(name); first_match = name; } else { size_t new_common_len = usr_cmd_len; /* save some loops */ while (new_common_len < common_len && first_match[new_common_len] == name[new_common_len]) new_common_len++; common_len = new_common_len; } match->cmd = name; list_add_tail(&match->lh, &matches); } Jim_DecrRefCount(command_context->interp, elem); } /* end of command filtering */ /* proceed with auto-completion */ if (list_empty(&matches)) telnet_bell(connection); else if (common_len == usr_cmd_len && list_is_singular(&matches) && t_con->line_cursor == t_con->line_size) telnet_insert(connection, " ", 1); else if (common_len > usr_cmd_len) { int completion_size = common_len - usr_cmd_len; if (telnet_insert(connection, first_match + usr_cmd_len, completion_size)) { /* in bash this extra space is only added when the cursor in at the end of line */ if (list_is_singular(&matches) && t_con->line_cursor == t_con->line_size) telnet_insert(connection, " ", 1); } } else if (!list_is_singular(&matches)) { telnet_write(connection, "\n\r", 2); struct cmd_match *match; list_for_each_entry(match, &matches, lh) { telnet_write(connection, match->cmd, strlen(match->cmd)); telnet_write(connection, "\n\r", 2); } telnet_prompt(connection); telnet_write(connection, t_con->line, t_con->line_size); /* restore the terminal visible cursor location */ for (size_t i = t_con->line_cursor; i < t_con->line_size; i++) telnet_write(connection, "\b", 1); } /* destroy the command_list */ struct cmd_match *tmp, *match; list_for_each_entry_safe(match, tmp, &matches, lh) free(match); Jim_DecrRefCount(command_context->interp, list); } static int telnet_input(struct connection *connection) { int bytes_read; unsigned char buffer[TELNET_BUFFER_SIZE]; unsigned char *buf_p; struct telnet_connection *t_con = connection->priv; bytes_read = connection_read(connection, buffer, TELNET_BUFFER_SIZE); if (bytes_read == 0) return ERROR_SERVER_REMOTE_CLOSED; else if (bytes_read == -1) { LOG_ERROR("error during read: %s", strerror(errno)); return ERROR_SERVER_REMOTE_CLOSED; } buf_p = buffer; while (bytes_read) { switch (t_con->state) { case TELNET_STATE_DATA: if (*buf_p == 0xff) { t_con->state = TELNET_STATE_IAC; } else { if (isprint(*buf_p)) { /* printable character */ telnet_insert(connection, buf_p, 1); } else { /* non-printable */ if (*buf_p == 0x1b) { /* escape */ t_con->state = TELNET_STATE_ESCAPE; t_con->last_escape = '\x00'; } else if ((*buf_p == 0xd) || (*buf_p == 0xa)) { /* CR/LF */ int retval; /* skip over combinations with CR/LF and NUL characters */ if ((bytes_read > 1) && ((*(buf_p + 1) == 0xa) || (*(buf_p + 1) == 0xd))) { buf_p++; bytes_read--; } if ((bytes_read > 1) && (*(buf_p + 1) == 0)) { buf_p++; bytes_read--; } t_con->line[t_con->line_size] = 0; retval = telnet_exec_line(connection); if (retval != ERROR_OK) return retval; } else if ((*buf_p == 0x7f) || (*buf_p == 0x8)) { /* delete character */ telnet_delete_character(connection); } else if (*buf_p == 0x15) { /* clear line */ telnet_clear_line(connection, t_con); } else if (*buf_p == CTRL('B')) { /* cursor left */ telnet_move_cursor(connection, t_con->line_cursor - 1); t_con->state = TELNET_STATE_DATA; } else if (*buf_p == CTRL('C')) { /* interrupt */ telnet_interrupt(connection); } else if (*buf_p == CTRL('F')) { /* cursor right */ telnet_move_cursor(connection, t_con->line_cursor + 1); t_con->state = TELNET_STATE_DATA; } else if (*buf_p == CTRL('P')) { /* cursor up */ telnet_history_up(connection); } else if (*buf_p == CTRL('N')) { /* cursor down */ telnet_history_down(connection); } else if (*buf_p == CTRL('A')) { /* move the cursor to the beginning of the line */ telnet_move_cursor(connection, 0); } else if (*buf_p == CTRL('E')) { /* move the cursor to the end of the line */ telnet_move_cursor(connection, t_con->line_size); } else if (*buf_p == CTRL('K')) { /* kill line to end */ telnet_cut_line_to_end(connection); } else if (*buf_p == '\t') { telnet_auto_complete(connection); } else { LOG_DEBUG("unhandled nonprintable: %2.2x", *buf_p); } } } break; case TELNET_STATE_IAC: switch (*buf_p) { case 0xfe: t_con->state = TELNET_STATE_DONT; break; case 0xfd: t_con->state = TELNET_STATE_DO; break; case 0xfc: t_con->state = TELNET_STATE_WONT; break; case 0xfb: t_con->state = TELNET_STATE_WILL; break; } break; case TELNET_STATE_SB: break; case TELNET_STATE_SE: break; case TELNET_STATE_WILL: case TELNET_STATE_WONT: case TELNET_STATE_DO: case TELNET_STATE_DONT: t_con->state = TELNET_STATE_DATA; break; case TELNET_STATE_ESCAPE: if (t_con->last_escape == '[') { if (*buf_p == 'D') { /* cursor left */ telnet_move_cursor(connection, t_con->line_cursor - 1); t_con->state = TELNET_STATE_DATA; } else if (*buf_p == 'C') { /* cursor right */ telnet_move_cursor(connection, t_con->line_cursor + 1); t_con->state = TELNET_STATE_DATA; } else if (*buf_p == 'A') { /* cursor up */ telnet_history_up(connection); } else if (*buf_p == 'B') { /* cursor down */ telnet_history_down(connection); } else if (*buf_p == 'F') { /* end key */ telnet_move_cursor(connection, t_con->line_size); t_con->state = TELNET_STATE_DATA; } else if (*buf_p == 'H') { /* home key */ telnet_move_cursor(connection, 0); t_con->state = TELNET_STATE_DATA; } else if (*buf_p == '3') { t_con->last_escape = *buf_p; } else { t_con->state = TELNET_STATE_DATA; } } else if (t_con->last_escape == '3') { /* Remove character */ if (*buf_p == '~') { telnet_remove_character(connection); t_con->state = TELNET_STATE_DATA; } else t_con->state = TELNET_STATE_DATA; } else if (t_con->last_escape == '\x00') { if (*buf_p == '[') t_con->last_escape = *buf_p; else t_con->state = TELNET_STATE_DATA; } else { LOG_ERROR("BUG: unexpected value in t_con->last_escape"); t_con->state = TELNET_STATE_DATA; } break; default: LOG_ERROR("unknown telnet state"); return ERROR_FAIL; } bytes_read--; buf_p++; } return ERROR_OK; } static int telnet_connection_closed(struct connection *connection) { struct telnet_connection *t_con = connection->priv; int i; log_remove_callback(telnet_log_callback, connection); free(t_con->prompt); t_con->prompt = NULL; /* save telnet history */ telnet_save_history(t_con); for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++) { free(t_con->history[i]); t_con->history[i] = NULL; } /* if this connection registered a debug-message receiver delete it */ delete_debug_msg_receiver(connection->cmd_ctx, NULL); free(connection->priv); connection->priv = NULL; return ERROR_OK; } static const struct service_driver telnet_service_driver = { .name = "telnet", .new_connection_during_keep_alive_handler = NULL, .new_connection_handler = telnet_new_connection, .input_handler = telnet_input, .connection_closed_handler = telnet_connection_closed, .keep_client_alive_handler = NULL, }; int telnet_init(char *banner) { if (strcmp(telnet_port, "disabled") == 0) { LOG_INFO("telnet server disabled"); return ERROR_OK; } struct telnet_service *telnet_service = malloc(sizeof(struct telnet_service)); if (!telnet_service) { LOG_ERROR("Failed to allocate telnet service."); return ERROR_FAIL; } telnet_service->banner = banner; int ret = add_service(&telnet_service_driver, telnet_port, CONNECTION_LIMIT_UNLIMITED, telnet_service); if (ret != ERROR_OK) { free(telnet_service); return ret; } return ERROR_OK; } /* daemon configuration command telnet_port */ COMMAND_HANDLER(handle_telnet_port_command) { return CALL_COMMAND_HANDLER(server_pipe_command, &telnet_port); } COMMAND_HANDLER(handle_exit_command) { return ERROR_COMMAND_CLOSE_CONNECTION; } static const struct command_registration telnet_command_handlers[] = { { .name = "exit", .handler = handle_exit_command, .mode = COMMAND_EXEC, .usage = "", .help = "exit telnet session", }, { .name = "telnet_port", .handler = handle_telnet_port_command, .mode = COMMAND_CONFIG, .help = "Specify port on which to listen " "for incoming telnet connections. " "Read help on 'gdb_port'.", .usage = "[port_num]", }, COMMAND_REGISTRATION_DONE }; int telnet_register_commands(struct command_context *cmd_ctx) { telnet_port = strdup("4444"); return register_commands(cmd_ctx, NULL, telnet_command_handlers); } void telnet_service_free(void) { free(telnet_port); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/server/telnet_server.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_SERVER_TELNET_SERVER_H #define OPENOCD_SERVER_TELNET_SERVER_H #include <server/server.h> #define TELNET_BUFFER_SIZE (10*1024) #define TELNET_LINE_HISTORY_SIZE (128) #define TELNET_LINE_MAX_SIZE (10*256) enum telnet_states { TELNET_STATE_DATA, TELNET_STATE_IAC, TELNET_STATE_SB, TELNET_STATE_SE, TELNET_STATE_WILL, TELNET_STATE_WONT, TELNET_STATE_DO, TELNET_STATE_DONT, TELNET_STATE_ESCAPE, }; struct telnet_connection { char *prompt; bool prompt_visible; enum telnet_states state; char line[TELNET_LINE_MAX_SIZE]; size_t line_size; size_t line_cursor; char last_escape; char *history[TELNET_LINE_HISTORY_SIZE]; size_t next_history; size_t current_history; bool closed; }; struct telnet_service { char *banner; }; int telnet_init(char *banner); int telnet_register_commands(struct command_context *command_context); void telnet_service_free(void); #endif /* OPENOCD_SERVER_TELNET_SERVER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/svf/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libsvf.la %C%_libsvf_la_SOURCES = %D%/svf.c %D%/svf.h ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/svf/svf.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * ***************************************************************************/ /* The specification for SVF is available here: * http://www.asset-intertech.com/support/svf.pdf * Below, this document is referred to as the "SVF spec". * * The specification for XSVF is available here: * http://www.xilinx.com/support/documentation/application_notes/xapp503.pdf * Below, this document is referred to as the "XSVF spec". */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/jtag.h> #include "svf.h" #include "helper/system.h" #include <helper/time_support.h> #include <helper/nvp.h> #include <stdbool.h> /* SVF command */ enum svf_command { ENDDR, ENDIR, FREQUENCY, HDR, HIR, PIO, PIOMAP, RUNTEST, SDR, SIR, STATE, TDR, TIR, TRST, }; static const char *svf_command_name[14] = { "ENDDR", "ENDIR", "FREQUENCY", "HDR", "HIR", "PIO", "PIOMAP", "RUNTEST", "SDR", "SIR", "STATE", "TDR", "TIR", "TRST" }; enum trst_mode { TRST_ON, TRST_OFF, TRST_Z, TRST_ABSENT }; static const char *svf_trst_mode_name[4] = { "ON", "OFF", "Z", "ABSENT" }; struct svf_statemove { tap_state_t from; tap_state_t to; uint32_t num_of_moves; tap_state_t paths[8]; }; /* * These paths are from the SVF specification for the STATE command, to be * used when the STATE command only includes the final state. The first * element of the path is the "from" (current) state, and the last one is * the "to" (target) state. * * All specified paths are the shortest ones in the JTAG spec, and are thus * not (!!) exact matches for the paths used elsewhere in OpenOCD. Note * that PAUSE-to-PAUSE transitions all go through UPDATE and then CAPTURE, * which has specific effects on the various registers; they are not NOPs. * * Paths to RESET are disabled here. As elsewhere in OpenOCD, and in XSVF * and many SVF implementations, we don't want to risk missing that state. * To get to RESET, always we ignore the current state. */ static const struct svf_statemove svf_statemoves[] = { /* from to num_of_moves, paths[8] */ /* {TAP_RESET, TAP_RESET, 1, {TAP_RESET}}, */ {TAP_RESET, TAP_IDLE, 2, {TAP_RESET, TAP_IDLE} }, {TAP_RESET, TAP_DRPAUSE, 6, {TAP_RESET, TAP_IDLE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DREXIT1, TAP_DRPAUSE} }, {TAP_RESET, TAP_IRPAUSE, 7, {TAP_RESET, TAP_IDLE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IREXIT1, TAP_IRPAUSE} }, /* {TAP_IDLE, TAP_RESET, 4, {TAP_IDLE, * TAP_DRSELECT, TAP_IRSELECT, TAP_RESET}}, */ {TAP_IDLE, TAP_IDLE, 1, {TAP_IDLE} }, {TAP_IDLE, TAP_DRPAUSE, 5, {TAP_IDLE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DREXIT1, TAP_DRPAUSE} }, {TAP_IDLE, TAP_IRPAUSE, 6, {TAP_IDLE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IREXIT1, TAP_IRPAUSE} }, /* {TAP_DRPAUSE, TAP_RESET, 6, {TAP_DRPAUSE, * TAP_DREXIT2, TAP_DRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_RESET}}, */ {TAP_DRPAUSE, TAP_IDLE, 4, {TAP_DRPAUSE, TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE} }, {TAP_DRPAUSE, TAP_DRPAUSE, 7, {TAP_DRPAUSE, TAP_DREXIT2, TAP_DRUPDATE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DREXIT1, TAP_DRPAUSE} }, {TAP_DRPAUSE, TAP_IRPAUSE, 8, {TAP_DRPAUSE, TAP_DREXIT2, TAP_DRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IREXIT1, TAP_IRPAUSE} }, /* {TAP_IRPAUSE, TAP_RESET, 6, {TAP_IRPAUSE, * TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_RESET}}, */ {TAP_IRPAUSE, TAP_IDLE, 4, {TAP_IRPAUSE, TAP_IREXIT2, TAP_IRUPDATE, TAP_IDLE} }, {TAP_IRPAUSE, TAP_DRPAUSE, 7, {TAP_IRPAUSE, TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DREXIT1, TAP_DRPAUSE} }, {TAP_IRPAUSE, TAP_IRPAUSE, 8, {TAP_IRPAUSE, TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IREXIT1, TAP_IRPAUSE} } }; #define XXR_TDI (1 << 0) #define XXR_TDO (1 << 1) #define XXR_MASK (1 << 2) #define XXR_SMASK (1 << 3) #define SVF_MAX_ADDCYCLES 255 struct svf_xxr_para { int len; int data_mask; uint8_t *tdi; uint8_t *tdo; uint8_t *mask; uint8_t *smask; }; struct svf_para { float frequency; tap_state_t ir_end_state; tap_state_t dr_end_state; tap_state_t runtest_run_state; tap_state_t runtest_end_state; enum trst_mode trst_mode; struct svf_xxr_para hir_para; struct svf_xxr_para hdr_para; struct svf_xxr_para tir_para; struct svf_xxr_para tdr_para; struct svf_xxr_para sir_para; struct svf_xxr_para sdr_para; }; static struct svf_para svf_para; static const struct svf_para svf_para_init = { /* frequency, ir_end_state, dr_end_state, runtest_run_state, runtest_end_state, trst_mode */ 0, TAP_IDLE, TAP_IDLE, TAP_IDLE, TAP_IDLE, TRST_Z, /* hir_para */ /* {len, data_mask, tdi, tdo, mask, smask}, */ {0, 0, NULL, NULL, NULL, NULL}, /* hdr_para */ /* {len, data_mask, tdi, tdo, mask, smask}, */ {0, 0, NULL, NULL, NULL, NULL}, /* tir_para */ /* {len, data_mask, tdi, tdo, mask, smask}, */ {0, 0, NULL, NULL, NULL, NULL}, /* tdr_para */ /* {len, data_mask, tdi, tdo, mask, smask}, */ {0, 0, NULL, NULL, NULL, NULL}, /* sir_para */ /* {len, data_mask, tdi, tdo, mask, smask}, */ {0, 0, NULL, NULL, NULL, NULL}, /* sdr_para */ /* {len, data_mask, tdi, tdo, mask, smask}, */ {0, 0, NULL, NULL, NULL, NULL}, }; struct svf_check_tdo_para { int line_num; /* used to record line number of the check operation */ /* so more information could be printed */ int enabled; /* check is enabled or not */ int buffer_offset; /* buffer_offset to buffers */ int bit_len; /* bit length to check */ }; #define SVF_CHECK_TDO_PARA_SIZE 1024 static struct svf_check_tdo_para *svf_check_tdo_para; static int svf_check_tdo_para_index; static int svf_read_command_from_file(FILE *fd); static int svf_check_tdo(void); static int svf_add_check_para(uint8_t enabled, int buffer_offset, int bit_len); static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str); static int svf_execute_tap(void); static FILE *svf_fd; static char *svf_read_line; static size_t svf_read_line_size; static char *svf_command_buffer; static size_t svf_command_buffer_size; static int svf_line_number; static int svf_getline(char **lineptr, size_t *n, FILE *stream); #define SVF_MAX_BUFFER_SIZE_TO_COMMIT (1024 * 1024) static uint8_t *svf_tdi_buffer, *svf_tdo_buffer, *svf_mask_buffer; static int svf_buffer_index, svf_buffer_size; static int svf_quiet; static int svf_nil; static int svf_ignore_error; static bool svf_noreset; static int svf_addcycles; /* Targeting particular tap */ static int svf_tap_is_specified; static int svf_set_padding(struct svf_xxr_para *para, int len, unsigned char tdi); /* Progress Indicator */ static int svf_progress_enabled; static long svf_total_lines; static int svf_percentage; static int svf_last_printed_percentage = -1; /* * macro is used to print the svf hex buffer at desired debug level * DEBUG, INFO, ERROR, USER */ #define SVF_BUF_LOG(_lvl, _buf, _nbits, _desc) \ svf_hexbuf_print(LOG_LVL_##_lvl, __FILE__, __LINE__, __func__, _buf, _nbits, _desc) static void svf_hexbuf_print(int dbg_lvl, const char *file, unsigned line, const char *function, const uint8_t *buf, int bit_len, const char *desc) { int j, len = 0; int byte_len = DIV_ROUND_UP(bit_len, 8); int msbits = bit_len % 8; /* allocate 2 bytes per hex digit */ char *prbuf = malloc((byte_len * 2) + 2 + 1); if (!prbuf) return; /* print correct number of bytes, mask excess bits where applicable */ uint8_t msb = buf[byte_len - 1] & (msbits ? (1 << msbits) - 1 : 0xff); len = sprintf(prbuf, msbits <= 4 ? "0x%01"PRIx8 : "0x%02"PRIx8, msb); for (j = byte_len - 2; j >= 0; j--) len += sprintf(prbuf + len, "%02"PRIx8, buf[j]); log_printf_lf(dbg_lvl, file, line, function, "%8s = %s", desc ? desc : " ", prbuf); free(prbuf); } static int svf_realloc_buffers(size_t len) { void *ptr; if (svf_execute_tap() != ERROR_OK) return ERROR_FAIL; ptr = realloc(svf_tdi_buffer, len); if (!ptr) return ERROR_FAIL; svf_tdi_buffer = ptr; ptr = realloc(svf_tdo_buffer, len); if (!ptr) return ERROR_FAIL; svf_tdo_buffer = ptr; ptr = realloc(svf_mask_buffer, len); if (!ptr) return ERROR_FAIL; svf_mask_buffer = ptr; svf_buffer_size = len; return ERROR_OK; } static void svf_free_xxd_para(struct svf_xxr_para *para) { if (para) { free(para->tdi); para->tdi = NULL; free(para->tdo); para->tdo = NULL; free(para->mask); para->mask = NULL; free(para->smask); para->smask = NULL; } } int svf_add_statemove(tap_state_t state_to) { tap_state_t state_from = cmd_queue_cur_state; unsigned index_var; /* when resetting, be paranoid and ignore current state */ if (state_to == TAP_RESET) { if (svf_nil) return ERROR_OK; jtag_add_tlr(); return ERROR_OK; } for (index_var = 0; index_var < ARRAY_SIZE(svf_statemoves); index_var++) { if ((svf_statemoves[index_var].from == state_from) && (svf_statemoves[index_var].to == state_to)) { if (svf_nil) continue; /* recorded path includes current state ... avoid *extra TCKs! */ if (svf_statemoves[index_var].num_of_moves > 1) jtag_add_pathmove(svf_statemoves[index_var].num_of_moves - 1, svf_statemoves[index_var].paths + 1); else jtag_add_pathmove(svf_statemoves[index_var].num_of_moves, svf_statemoves[index_var].paths); return ERROR_OK; } } LOG_ERROR("SVF: can not move to %s", tap_state_name(state_to)); return ERROR_FAIL; } enum svf_cmd_param { OPT_ADDCYCLES, OPT_IGNORE_ERROR, OPT_NIL, OPT_NORESET, OPT_PROGRESS, OPT_QUIET, OPT_TAP, /* DEPRECATED */ DEPRECATED_OPT_IGNORE_ERROR, DEPRECATED_OPT_NIL, DEPRECATED_OPT_PROGRESS, DEPRECATED_OPT_QUIET, }; static const struct nvp svf_cmd_opts[] = { { .name = "-addcycles", .value = OPT_ADDCYCLES }, { .name = "-ignore_error", .value = OPT_IGNORE_ERROR }, { .name = "-nil", .value = OPT_NIL }, { .name = "-noreset", .value = OPT_NORESET }, { .name = "-progress", .value = OPT_PROGRESS }, { .name = "-quiet", .value = OPT_QUIET }, { .name = "-tap", .value = OPT_TAP }, /* DEPRECATED */ { .name = "ignore_error", .value = DEPRECATED_OPT_IGNORE_ERROR }, { .name = "nil", .value = DEPRECATED_OPT_NIL }, { .name = "progress", .value = DEPRECATED_OPT_PROGRESS }, { .name = "quiet", .value = DEPRECATED_OPT_QUIET }, { .name = NULL, .value = -1 } }; COMMAND_HANDLER(handle_svf_command) { #define SVF_MIN_NUM_OF_OPTIONS 1 #define SVF_MAX_NUM_OF_OPTIONS 8 int command_num = 0; int ret = ERROR_OK; int64_t time_measure_ms; int time_measure_s, time_measure_m; /* * use NULL to indicate a "plain" svf file which accounts for * any additional devices in the scan chain, otherwise the device * that should be affected */ struct jtag_tap *tap = NULL; if ((CMD_ARGC < SVF_MIN_NUM_OF_OPTIONS) || (CMD_ARGC > SVF_MAX_NUM_OF_OPTIONS)) return ERROR_COMMAND_SYNTAX_ERROR; /* parse command line */ svf_quiet = 0; svf_nil = 0; svf_progress_enabled = 0; svf_ignore_error = 0; svf_noreset = false; svf_addcycles = 0; for (unsigned int i = 0; i < CMD_ARGC; i++) { const struct nvp *n = nvp_name2value(svf_cmd_opts, CMD_ARGV[i]); switch (n->value) { case OPT_ADDCYCLES: svf_addcycles = atoi(CMD_ARGV[i + 1]); if (svf_addcycles > SVF_MAX_ADDCYCLES) { command_print(CMD, "addcycles: %s out of range", CMD_ARGV[i + 1]); if (svf_fd) fclose(svf_fd); svf_fd = NULL; return ERROR_COMMAND_ARGUMENT_INVALID; } i++; break; case OPT_TAP: tap = jtag_tap_by_string(CMD_ARGV[i+1]); if (!tap) { command_print(CMD, "Tap: %s unknown", CMD_ARGV[i+1]); if (svf_fd) fclose(svf_fd); svf_fd = NULL; return ERROR_COMMAND_ARGUMENT_INVALID; } i++; break; case DEPRECATED_OPT_QUIET: LOG_INFO("DEPRECATED flag '%s'; use '-%s'", CMD_ARGV[i], CMD_ARGV[i]); /* fallthrough */ case OPT_QUIET: svf_quiet = 1; break; case DEPRECATED_OPT_NIL: LOG_INFO("DEPRECATED flag '%s'; use '-%s'", CMD_ARGV[i], CMD_ARGV[i]); /* fallthrough */ case OPT_NIL: svf_nil = 1; break; case DEPRECATED_OPT_PROGRESS: LOG_INFO("DEPRECATED flag '%s'; use '-%s'", CMD_ARGV[i], CMD_ARGV[i]); /* fallthrough */ case OPT_PROGRESS: svf_progress_enabled = 1; break; case DEPRECATED_OPT_IGNORE_ERROR: LOG_INFO("DEPRECATED flag '%s'; use '-%s'", CMD_ARGV[i], CMD_ARGV[i]); /* fallthrough */ case OPT_IGNORE_ERROR: svf_ignore_error = 1; break; case OPT_NORESET: svf_noreset = true; break; default: svf_fd = fopen(CMD_ARGV[i], "r"); if (!svf_fd) { int err = errno; command_print(CMD, "open(\"%s\"): %s", CMD_ARGV[i], strerror(err)); /* no need to free anything now */ return ERROR_COMMAND_SYNTAX_ERROR; } LOG_USER("svf processing file: \"%s\"", CMD_ARGV[i]); break; } } if (!svf_fd) return ERROR_COMMAND_SYNTAX_ERROR; /* get time */ time_measure_ms = timeval_ms(); /* init */ svf_line_number = 0; svf_command_buffer_size = 0; svf_check_tdo_para_index = 0; svf_check_tdo_para = malloc(sizeof(struct svf_check_tdo_para) * SVF_CHECK_TDO_PARA_SIZE); if (!svf_check_tdo_para) { LOG_ERROR("not enough memory"); ret = ERROR_FAIL; goto free_all; } svf_buffer_index = 0; /* double the buffer size */ /* in case current command cannot be committed, and next command is a bit scan command */ /* here is 32K bits for this big scan command, it should be enough */ /* buffer will be reallocated if buffer size is not enough */ if (svf_realloc_buffers(2 * SVF_MAX_BUFFER_SIZE_TO_COMMIT) != ERROR_OK) { ret = ERROR_FAIL; goto free_all; } memcpy(&svf_para, &svf_para_init, sizeof(svf_para)); if (!svf_nil && !svf_noreset) { /* TAP_RESET */ jtag_add_tlr(); } if (tap) { /* Tap is specified, set header/trailer paddings */ int header_ir_len = 0, header_dr_len = 0, trailer_ir_len = 0, trailer_dr_len = 0; struct jtag_tap *check_tap; svf_tap_is_specified = 1; for (check_tap = jtag_all_taps(); check_tap; check_tap = check_tap->next_tap) { if (check_tap->abs_chain_position < tap->abs_chain_position) { /* Header */ header_ir_len += check_tap->ir_length; header_dr_len++; } else if (check_tap->abs_chain_position > tap->abs_chain_position) { /* Trailer */ trailer_ir_len += check_tap->ir_length; trailer_dr_len++; } } /* HDR %d TDI (0) */ ret = svf_set_padding(&svf_para.hdr_para, header_dr_len, 0); if (ret != ERROR_OK) { command_print(CMD, "failed to set data header"); goto free_all; } /* HIR %d TDI (0xFF) */ ret = svf_set_padding(&svf_para.hir_para, header_ir_len, 0xFF); if (ret != ERROR_OK) { command_print(CMD, "failed to set instruction header"); goto free_all; } /* TDR %d TDI (0) */ ret = svf_set_padding(&svf_para.tdr_para, trailer_dr_len, 0); if (ret != ERROR_OK) { command_print(CMD, "failed to set data trailer"); goto free_all; } /* TIR %d TDI (0xFF) */ ret = svf_set_padding(&svf_para.tir_para, trailer_ir_len, 0xFF); if (ret != ERROR_OK) { command_print(CMD, "failed to set instruction trailer"); goto free_all; } } if (svf_progress_enabled) { /* Count total lines in file. */ while (!feof(svf_fd)) { svf_getline(&svf_command_buffer, &svf_command_buffer_size, svf_fd); svf_total_lines++; } rewind(svf_fd); } while (svf_read_command_from_file(svf_fd) == ERROR_OK) { /* Log Output */ if (svf_quiet) { if (svf_progress_enabled) { svf_percentage = ((svf_line_number * 20) / svf_total_lines) * 5; if (svf_last_printed_percentage != svf_percentage) { LOG_USER_N("\r%d%% ", svf_percentage); svf_last_printed_percentage = svf_percentage; } } } else { if (svf_progress_enabled) { svf_percentage = ((svf_line_number * 20) / svf_total_lines) * 5; LOG_USER_N("%3d%% %s", svf_percentage, svf_read_line); } else LOG_USER_N("%s", svf_read_line); } /* Run Command */ if (svf_run_command(CMD_CTX, svf_command_buffer) != ERROR_OK) { LOG_ERROR("fail to run command at line %d", svf_line_number); ret = ERROR_FAIL; break; } command_num++; } if ((!svf_nil) && (jtag_execute_queue() != ERROR_OK)) ret = ERROR_FAIL; else if (svf_check_tdo() != ERROR_OK) ret = ERROR_FAIL; /* print time */ time_measure_ms = timeval_ms() - time_measure_ms; time_measure_s = time_measure_ms / 1000; time_measure_ms %= 1000; time_measure_m = time_measure_s / 60; time_measure_s %= 60; if (time_measure_ms < 1000) command_print(CMD, "\r\nTime used: %dm%ds%" PRId64 "ms ", time_measure_m, time_measure_s, time_measure_ms); free_all: fclose(svf_fd); svf_fd = NULL; /* free buffers */ free(svf_command_buffer); svf_command_buffer = NULL; svf_command_buffer_size = 0; free(svf_check_tdo_para); svf_check_tdo_para = NULL; svf_check_tdo_para_index = 0; free(svf_tdi_buffer); svf_tdi_buffer = NULL; free(svf_tdo_buffer); svf_tdo_buffer = NULL; free(svf_mask_buffer); svf_mask_buffer = NULL; svf_buffer_index = 0; svf_buffer_size = 0; svf_free_xxd_para(&svf_para.hdr_para); svf_free_xxd_para(&svf_para.hir_para); svf_free_xxd_para(&svf_para.tdr_para); svf_free_xxd_para(&svf_para.tir_para); svf_free_xxd_para(&svf_para.sdr_para); svf_free_xxd_para(&svf_para.sir_para); if (ret == ERROR_OK) command_print(CMD, "svf file programmed %s for %d commands with %d errors", (svf_ignore_error > 1) ? "unsuccessfully" : "successfully", command_num, (svf_ignore_error > 1) ? (svf_ignore_error - 1) : 0); else command_print(CMD, "svf file programmed failed"); svf_ignore_error = 0; return ret; } static int svf_getline(char **lineptr, size_t *n, FILE *stream) { #define MIN_CHUNK 16 /* Buffer is increased by this size each time as required */ size_t i = 0; if (!*lineptr) { *n = MIN_CHUNK; *lineptr = malloc(*n); if (!*lineptr) return -1; } (*lineptr)[0] = fgetc(stream); while ((*lineptr)[i] != '\n') { (*lineptr)[++i] = fgetc(stream); if (feof(stream)) { (*lineptr)[0] = 0; return -1; } if ((i + 2) > *n) { *n += MIN_CHUNK; *lineptr = realloc(*lineptr, *n); } } (*lineptr)[++i] = 0; return sizeof(*lineptr); } #define SVFP_CMD_INC_CNT 1024 static int svf_read_command_from_file(FILE *fd) { unsigned char ch; int i = 0; size_t cmd_pos = 0; int cmd_ok = 0, slash = 0; if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) return ERROR_FAIL; svf_line_number++; ch = svf_read_line[0]; while (!cmd_ok && (ch != 0)) { switch (ch) { case '!': slash = 0; if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) return ERROR_FAIL; svf_line_number++; i = -1; break; case '/': if (++slash == 2) { slash = 0; if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) return ERROR_FAIL; svf_line_number++; i = -1; } break; case ';': slash = 0; cmd_ok = 1; break; case '\n': svf_line_number++; if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) return ERROR_FAIL; i = -1; /* fallthrough */ case '\r': slash = 0; /* Don't save '\r' and '\n' if no data is parsed */ if (!cmd_pos) break; /* fallthrough */ default: /* The parsing code currently expects a space * before parentheses -- "TDI (123)". Also a * space afterwards -- "TDI (123) TDO(456)". * But such spaces are optional... instead of * parser updates, cope with that by adding the * spaces as needed. * * Ensure there are 3 bytes available, for: * - current character * - added space. * - terminating NUL ('\0') */ if (cmd_pos + 3 > svf_command_buffer_size) { svf_command_buffer = realloc(svf_command_buffer, cmd_pos + 3); svf_command_buffer_size = cmd_pos + 3; if (!svf_command_buffer) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } } /* insert a space before '(' */ if ('(' == ch) svf_command_buffer[cmd_pos++] = ' '; svf_command_buffer[cmd_pos++] = (char)toupper(ch); /* insert a space after ')' */ if (')' == ch) svf_command_buffer[cmd_pos++] = ' '; break; } ch = svf_read_line[++i]; } if (cmd_ok) { svf_command_buffer[cmd_pos] = '\0'; return ERROR_OK; } else return ERROR_FAIL; } static int svf_parse_cmd_string(char *str, int len, char **argus, int *num_of_argu) { int pos = 0, num = 0, space_found = 1, in_bracket = 0; while (pos < len) { switch (str[pos]) { case '!': case '/': LOG_ERROR("fail to parse svf command"); return ERROR_FAIL; case '(': in_bracket = 1; goto parse_char; case ')': in_bracket = 0; goto parse_char; default: parse_char: if (!in_bracket && isspace((int) str[pos])) { space_found = 1; str[pos] = '\0'; } else if (space_found) { argus[num++] = &str[pos]; space_found = 0; } break; } pos++; } if (num == 0) return ERROR_FAIL; *num_of_argu = num; return ERROR_OK; } bool svf_tap_state_is_stable(tap_state_t state) { return (state == TAP_RESET) || (state == TAP_IDLE) || (state == TAP_DRPAUSE) || (state == TAP_IRPAUSE); } static int svf_find_string_in_array(char *str, char **strs, int num_of_element) { int i; for (i = 0; i < num_of_element; i++) { if (!strcmp(str, strs[i])) return i; } return 0xFF; } static int svf_adjust_array_length(uint8_t **arr, int orig_bit_len, int new_bit_len) { int new_byte_len = (new_bit_len + 7) >> 3; if ((!*arr) || (((orig_bit_len + 7) >> 3) < ((new_bit_len + 7) >> 3))) { free(*arr); *arr = calloc(1, new_byte_len); if (!*arr) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } } return ERROR_OK; } static int svf_set_padding(struct svf_xxr_para *para, int len, unsigned char tdi) { int error = ERROR_OK; error |= svf_adjust_array_length(¶->tdi, para->len, len); memset(para->tdi, tdi, (len + 7) >> 3); error |= svf_adjust_array_length(¶->tdo, para->len, len); error |= svf_adjust_array_length(¶->mask, para->len, len); para->len = len; para->data_mask = XXR_TDI; return error; } static int svf_copy_hexstring_to_binary(char *str, uint8_t **bin, int orig_bit_len, int bit_len) { int i, str_len = strlen(str), str_hbyte_len = (bit_len + 3) >> 2; uint8_t ch = 0; if (svf_adjust_array_length(bin, orig_bit_len, bit_len) != ERROR_OK) { LOG_ERROR("fail to adjust length of array"); return ERROR_FAIL; } /* fill from LSB (end of str) to MSB (beginning of str) */ for (i = 0; i < str_hbyte_len; i++) { ch = 0; while (str_len > 0) { ch = str[--str_len]; /* Skip whitespace. The SVF specification (rev E) is * deficient in terms of basic lexical issues like * where whitespace is allowed. Long bitstrings may * require line ends for correctness, since there is * a hard limit on line length. */ if (!isspace(ch)) { if ((ch >= '0') && (ch <= '9')) { ch = ch - '0'; break; } else if ((ch >= 'A') && (ch <= 'F')) { ch = ch - 'A' + 10; break; } else { LOG_ERROR("invalid hex string"); return ERROR_FAIL; } } ch = 0; } /* write bin */ if (i % 2) { /* MSB */ (*bin)[i / 2] |= ch << 4; } else { /* LSB */ (*bin)[i / 2] = 0; (*bin)[i / 2] |= ch; } } /* consume optional leading '0' MSBs or whitespace */ while (str_len > 0 && ((str[str_len - 1] == '0') || isspace((int) str[str_len - 1]))) str_len--; /* check validity: we must have consumed everything */ if (str_len > 0 || (ch & ~((2 << ((bit_len - 1) % 4)) - 1)) != 0) { LOG_ERROR("value exceeds length"); return ERROR_FAIL; } return ERROR_OK; } static int svf_check_tdo(void) { int i, len, index_var; for (i = 0; i < svf_check_tdo_para_index; i++) { index_var = svf_check_tdo_para[i].buffer_offset; len = svf_check_tdo_para[i].bit_len; if ((svf_check_tdo_para[i].enabled) && buf_cmp_mask(&svf_tdi_buffer[index_var], &svf_tdo_buffer[index_var], &svf_mask_buffer[index_var], len)) { LOG_ERROR("tdo check error at line %d", svf_check_tdo_para[i].line_num); SVF_BUF_LOG(ERROR, &svf_tdi_buffer[index_var], len, "READ"); SVF_BUF_LOG(ERROR, &svf_tdo_buffer[index_var], len, "WANT"); SVF_BUF_LOG(ERROR, &svf_mask_buffer[index_var], len, "MASK"); if (svf_ignore_error == 0) return ERROR_FAIL; else svf_ignore_error++; } } svf_check_tdo_para_index = 0; return ERROR_OK; } static int svf_add_check_para(uint8_t enabled, int buffer_offset, int bit_len) { if (svf_check_tdo_para_index >= SVF_CHECK_TDO_PARA_SIZE) { LOG_ERROR("toooooo many operation undone"); return ERROR_FAIL; } svf_check_tdo_para[svf_check_tdo_para_index].line_num = svf_line_number; svf_check_tdo_para[svf_check_tdo_para_index].bit_len = bit_len; svf_check_tdo_para[svf_check_tdo_para_index].enabled = enabled; svf_check_tdo_para[svf_check_tdo_para_index].buffer_offset = buffer_offset; svf_check_tdo_para_index++; return ERROR_OK; } static int svf_execute_tap(void) { if ((!svf_nil) && (jtag_execute_queue() != ERROR_OK)) return ERROR_FAIL; else if (svf_check_tdo() != ERROR_OK) return ERROR_FAIL; svf_buffer_index = 0; return ERROR_OK; } static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) { char *argus[256], command; int num_of_argu = 0, i; /* tmp variable */ int i_tmp; /* for RUNTEST */ int run_count; float min_time; /* for XXR */ struct svf_xxr_para *xxr_para_tmp; uint8_t **pbuffer_tmp; struct scan_field field; /* for STATE */ tap_state_t *path = NULL, state; /* flag padding commands skipped due to -tap command */ int padding_command_skipped = 0; if (svf_parse_cmd_string(cmd_str, strlen(cmd_str), argus, &num_of_argu) != ERROR_OK) return ERROR_FAIL; /* NOTE: we're a bit loose here, because we ignore case in * TAP state names (instead of insisting on uppercase). */ command = svf_find_string_in_array(argus[0], (char **)svf_command_name, ARRAY_SIZE(svf_command_name)); switch (command) { case ENDDR: case ENDIR: if (num_of_argu != 2) { LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } i_tmp = tap_state_by_name(argus[1]); if (svf_tap_state_is_stable(i_tmp)) { if (command == ENDIR) { svf_para.ir_end_state = i_tmp; LOG_DEBUG("\tIR end_state = %s", tap_state_name(i_tmp)); } else { svf_para.dr_end_state = i_tmp; LOG_DEBUG("\tDR end_state = %s", tap_state_name(i_tmp)); } } else { LOG_ERROR("%s: %s is not a stable state", argus[0], argus[1]); return ERROR_FAIL; } break; case FREQUENCY: if ((num_of_argu != 1) && (num_of_argu != 3)) { LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } if (num_of_argu == 1) { /* TODO: set jtag speed to full speed */ svf_para.frequency = 0; } else { if (strcmp(argus[2], "HZ")) { LOG_ERROR("HZ not found in FREQUENCY command"); return ERROR_FAIL; } if (svf_execute_tap() != ERROR_OK) return ERROR_FAIL; svf_para.frequency = atof(argus[1]); /* TODO: set jtag speed to */ if (svf_para.frequency > 0) { command_run_linef(cmd_ctx, "adapter speed %d", (int)svf_para.frequency / 1000); LOG_DEBUG("\tfrequency = %f", svf_para.frequency); } } break; case HDR: if (svf_tap_is_specified) { padding_command_skipped = 1; break; } xxr_para_tmp = &svf_para.hdr_para; goto xxr_common; case HIR: if (svf_tap_is_specified) { padding_command_skipped = 1; break; } xxr_para_tmp = &svf_para.hir_para; goto xxr_common; case TDR: if (svf_tap_is_specified) { padding_command_skipped = 1; break; } xxr_para_tmp = &svf_para.tdr_para; goto xxr_common; case TIR: if (svf_tap_is_specified) { padding_command_skipped = 1; break; } xxr_para_tmp = &svf_para.tir_para; goto xxr_common; case SDR: xxr_para_tmp = &svf_para.sdr_para; goto xxr_common; case SIR: xxr_para_tmp = &svf_para.sir_para; goto xxr_common; xxr_common: /* XXR length [TDI (tdi)] [TDO (tdo)][MASK (mask)] [SMASK (smask)] */ if ((num_of_argu > 10) || (num_of_argu % 2)) { LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } i_tmp = xxr_para_tmp->len; xxr_para_tmp->len = atoi(argus[1]); /* If we are to enlarge the buffers, all parts of xxr_para_tmp * need to be freed */ if (i_tmp < xxr_para_tmp->len) { free(xxr_para_tmp->tdi); xxr_para_tmp->tdi = NULL; free(xxr_para_tmp->tdo); xxr_para_tmp->tdo = NULL; free(xxr_para_tmp->mask); xxr_para_tmp->mask = NULL; free(xxr_para_tmp->smask); xxr_para_tmp->smask = NULL; } LOG_DEBUG("\tlength = %d", xxr_para_tmp->len); xxr_para_tmp->data_mask = 0; for (i = 2; i < num_of_argu; i += 2) { if ((strlen(argus[i + 1]) < 3) || (argus[i + 1][0] != '(') || (argus[i + 1][strlen(argus[i + 1]) - 1] != ')')) { LOG_ERROR("data section error"); return ERROR_FAIL; } argus[i + 1][strlen(argus[i + 1]) - 1] = '\0'; /* TDI, TDO, MASK, SMASK */ if (!strcmp(argus[i], "TDI")) { /* TDI */ pbuffer_tmp = &xxr_para_tmp->tdi; xxr_para_tmp->data_mask |= XXR_TDI; } else if (!strcmp(argus[i], "TDO")) { /* TDO */ pbuffer_tmp = &xxr_para_tmp->tdo; xxr_para_tmp->data_mask |= XXR_TDO; } else if (!strcmp(argus[i], "MASK")) { /* MASK */ pbuffer_tmp = &xxr_para_tmp->mask; xxr_para_tmp->data_mask |= XXR_MASK; } else if (!strcmp(argus[i], "SMASK")) { /* SMASK */ pbuffer_tmp = &xxr_para_tmp->smask; xxr_para_tmp->data_mask |= XXR_SMASK; } else { LOG_ERROR("unknown parameter: %s", argus[i]); return ERROR_FAIL; } if (ERROR_OK != svf_copy_hexstring_to_binary(&argus[i + 1][1], pbuffer_tmp, i_tmp, xxr_para_tmp->len)) { LOG_ERROR("fail to parse hex value"); return ERROR_FAIL; } SVF_BUF_LOG(DEBUG, *pbuffer_tmp, xxr_para_tmp->len, argus[i]); } /* If a command changes the length of the last scan of the same type and the * MASK parameter is absent, */ /* the mask pattern used is all cares */ if (!(xxr_para_tmp->data_mask & XXR_MASK) && (i_tmp != xxr_para_tmp->len)) { /* MASK not defined and length changed */ if (ERROR_OK != svf_adjust_array_length(&xxr_para_tmp->mask, i_tmp, xxr_para_tmp->len)) { LOG_ERROR("fail to adjust length of array"); return ERROR_FAIL; } buf_set_ones(xxr_para_tmp->mask, xxr_para_tmp->len); } /* If TDO is absent, no comparison is needed, set the mask to 0 */ if (!(xxr_para_tmp->data_mask & XXR_TDO)) { if (!xxr_para_tmp->tdo) { if (ERROR_OK != svf_adjust_array_length(&xxr_para_tmp->tdo, i_tmp, xxr_para_tmp->len)) { LOG_ERROR("fail to adjust length of array"); return ERROR_FAIL; } } if (!xxr_para_tmp->mask) { if (ERROR_OK != svf_adjust_array_length(&xxr_para_tmp->mask, i_tmp, xxr_para_tmp->len)) { LOG_ERROR("fail to adjust length of array"); return ERROR_FAIL; } } memset(xxr_para_tmp->mask, 0, (xxr_para_tmp->len + 7) >> 3); } /* do scan if necessary */ if (command == SDR) { /* check buffer size first, reallocate if necessary */ i = svf_para.hdr_para.len + svf_para.sdr_para.len + svf_para.tdr_para.len; if ((svf_buffer_size - svf_buffer_index) < ((i + 7) >> 3)) { /* reallocate buffer */ if (svf_realloc_buffers(svf_buffer_index + ((i + 7) >> 3)) != ERROR_OK) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } } /* assemble dr data */ i = 0; buf_set_buf(svf_para.hdr_para.tdi, 0, &svf_tdi_buffer[svf_buffer_index], i, svf_para.hdr_para.len); i += svf_para.hdr_para.len; buf_set_buf(svf_para.sdr_para.tdi, 0, &svf_tdi_buffer[svf_buffer_index], i, svf_para.sdr_para.len); i += svf_para.sdr_para.len; buf_set_buf(svf_para.tdr_para.tdi, 0, &svf_tdi_buffer[svf_buffer_index], i, svf_para.tdr_para.len); i += svf_para.tdr_para.len; /* add check data */ if (svf_para.sdr_para.data_mask & XXR_TDO) { /* assemble dr mask data */ i = 0; buf_set_buf(svf_para.hdr_para.mask, 0, &svf_mask_buffer[svf_buffer_index], i, svf_para.hdr_para.len); i += svf_para.hdr_para.len; buf_set_buf(svf_para.sdr_para.mask, 0, &svf_mask_buffer[svf_buffer_index], i, svf_para.sdr_para.len); i += svf_para.sdr_para.len; buf_set_buf(svf_para.tdr_para.mask, 0, &svf_mask_buffer[svf_buffer_index], i, svf_para.tdr_para.len); /* assemble dr check data */ i = 0; buf_set_buf(svf_para.hdr_para.tdo, 0, &svf_tdo_buffer[svf_buffer_index], i, svf_para.hdr_para.len); i += svf_para.hdr_para.len; buf_set_buf(svf_para.sdr_para.tdo, 0, &svf_tdo_buffer[svf_buffer_index], i, svf_para.sdr_para.len); i += svf_para.sdr_para.len; buf_set_buf(svf_para.tdr_para.tdo, 0, &svf_tdo_buffer[svf_buffer_index], i, svf_para.tdr_para.len); i += svf_para.tdr_para.len; svf_add_check_para(1, svf_buffer_index, i); } else svf_add_check_para(0, svf_buffer_index, i); field.num_bits = i; field.out_value = &svf_tdi_buffer[svf_buffer_index]; field.in_value = (xxr_para_tmp->data_mask & XXR_TDO) ? &svf_tdi_buffer[svf_buffer_index] : NULL; if (!svf_nil) { /* NOTE: doesn't use SVF-specified state paths */ jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, svf_para.dr_end_state); } if (svf_addcycles) jtag_add_clocks(svf_addcycles); svf_buffer_index += (i + 7) >> 3; } else if (command == SIR) { /* check buffer size first, reallocate if necessary */ i = svf_para.hir_para.len + svf_para.sir_para.len + svf_para.tir_para.len; if ((svf_buffer_size - svf_buffer_index) < ((i + 7) >> 3)) { if (svf_realloc_buffers(svf_buffer_index + ((i + 7) >> 3)) != ERROR_OK) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } } /* assemble ir data */ i = 0; buf_set_buf(svf_para.hir_para.tdi, 0, &svf_tdi_buffer[svf_buffer_index], i, svf_para.hir_para.len); i += svf_para.hir_para.len; buf_set_buf(svf_para.sir_para.tdi, 0, &svf_tdi_buffer[svf_buffer_index], i, svf_para.sir_para.len); i += svf_para.sir_para.len; buf_set_buf(svf_para.tir_para.tdi, 0, &svf_tdi_buffer[svf_buffer_index], i, svf_para.tir_para.len); i += svf_para.tir_para.len; /* add check data */ if (svf_para.sir_para.data_mask & XXR_TDO) { /* assemble dr mask data */ i = 0; buf_set_buf(svf_para.hir_para.mask, 0, &svf_mask_buffer[svf_buffer_index], i, svf_para.hir_para.len); i += svf_para.hir_para.len; buf_set_buf(svf_para.sir_para.mask, 0, &svf_mask_buffer[svf_buffer_index], i, svf_para.sir_para.len); i += svf_para.sir_para.len; buf_set_buf(svf_para.tir_para.mask, 0, &svf_mask_buffer[svf_buffer_index], i, svf_para.tir_para.len); /* assemble dr check data */ i = 0; buf_set_buf(svf_para.hir_para.tdo, 0, &svf_tdo_buffer[svf_buffer_index], i, svf_para.hir_para.len); i += svf_para.hir_para.len; buf_set_buf(svf_para.sir_para.tdo, 0, &svf_tdo_buffer[svf_buffer_index], i, svf_para.sir_para.len); i += svf_para.sir_para.len; buf_set_buf(svf_para.tir_para.tdo, 0, &svf_tdo_buffer[svf_buffer_index], i, svf_para.tir_para.len); i += svf_para.tir_para.len; svf_add_check_para(1, svf_buffer_index, i); } else svf_add_check_para(0, svf_buffer_index, i); field.num_bits = i; field.out_value = &svf_tdi_buffer[svf_buffer_index]; field.in_value = (xxr_para_tmp->data_mask & XXR_TDO) ? &svf_tdi_buffer[svf_buffer_index] : NULL; if (!svf_nil) { /* NOTE: doesn't use SVF-specified state paths */ jtag_add_plain_ir_scan(field.num_bits, field.out_value, field.in_value, svf_para.ir_end_state); } svf_buffer_index += (i + 7) >> 3; } break; case PIO: case PIOMAP: LOG_ERROR("PIO and PIOMAP are not supported"); return ERROR_FAIL; case RUNTEST: /* RUNTEST [run_state] run_count run_clk [min_time SEC [MAXIMUM max_time * SEC]] [ENDSTATE end_state] */ /* RUNTEST [run_state] min_time SEC [MAXIMUM max_time SEC] [ENDSTATE * end_state] */ if ((num_of_argu < 3) || (num_of_argu > 11)) { LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } /* init */ run_count = 0; min_time = 0; i = 1; /* run_state */ i_tmp = tap_state_by_name(argus[i]); if (i_tmp != TAP_INVALID) { if (svf_tap_state_is_stable(i_tmp)) { svf_para.runtest_run_state = i_tmp; /* When a run_state is specified, the new * run_state becomes the default end_state. */ svf_para.runtest_end_state = i_tmp; LOG_DEBUG("\trun_state = %s", tap_state_name(i_tmp)); i++; } else { LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(i_tmp)); return ERROR_FAIL; } } /* run_count run_clk */ if (((i + 2) <= num_of_argu) && strcmp(argus[i + 1], "SEC")) { if (!strcmp(argus[i + 1], "TCK")) { /* clock source is TCK */ run_count = atoi(argus[i]); LOG_DEBUG("\trun_count@TCK = %d", run_count); } else { LOG_ERROR("%s not supported for clock", argus[i + 1]); return ERROR_FAIL; } i += 2; } /* min_time SEC */ if (((i + 2) <= num_of_argu) && !strcmp(argus[i + 1], "SEC")) { min_time = atof(argus[i]); LOG_DEBUG("\tmin_time = %fs", min_time); i += 2; } /* MAXIMUM max_time SEC */ if (((i + 3) <= num_of_argu) && !strcmp(argus[i], "MAXIMUM") && !strcmp(argus[i + 2], "SEC")) { float max_time = 0; max_time = atof(argus[i + 1]); LOG_DEBUG("\tmax_time = %fs", max_time); i += 3; } /* ENDSTATE end_state */ if (((i + 2) <= num_of_argu) && !strcmp(argus[i], "ENDSTATE")) { i_tmp = tap_state_by_name(argus[i + 1]); if (svf_tap_state_is_stable(i_tmp)) { svf_para.runtest_end_state = i_tmp; LOG_DEBUG("\tend_state = %s", tap_state_name(i_tmp)); } else { LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(i_tmp)); return ERROR_FAIL; } i += 2; } /* all parameter should be parsed */ if (i == num_of_argu) { #if 1 /* FIXME handle statemove failures */ uint32_t min_usec = 1000000 * min_time; /* enter into run_state if necessary */ if (cmd_queue_cur_state != svf_para.runtest_run_state) svf_add_statemove(svf_para.runtest_run_state); /* add clocks and/or min wait */ if (run_count > 0) { if (!svf_nil) jtag_add_clocks(run_count); } if (min_usec > 0) { if (!svf_nil) jtag_add_sleep(min_usec); } /* move to end_state if necessary */ if (svf_para.runtest_end_state != svf_para.runtest_run_state) svf_add_statemove(svf_para.runtest_end_state); #else if (svf_para.runtest_run_state != TAP_IDLE) { LOG_ERROR("cannot runtest in %s state", tap_state_name(svf_para.runtest_run_state)); return ERROR_FAIL; } if (!svf_nil) jtag_add_runtest(run_count, svf_para.runtest_end_state); #endif } else { LOG_ERROR("fail to parse parameter of RUNTEST, %d out of %d is parsed", i, num_of_argu); return ERROR_FAIL; } break; case STATE: /* STATE [pathstate1 [pathstate2 ...[pathstaten]]] stable_state */ if (num_of_argu < 2) { LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } if (num_of_argu > 2) { /* STATE pathstate1 ... stable_state */ path = malloc((num_of_argu - 1) * sizeof(tap_state_t)); if (!path) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } num_of_argu--; /* num of path */ i_tmp = 1; /* path is from parameter 1 */ for (i = 0; i < num_of_argu; i++, i_tmp++) { path[i] = tap_state_by_name(argus[i_tmp]); if (path[i] == TAP_INVALID) { LOG_ERROR("%s: %s is not a valid state", argus[0], argus[i_tmp]); free(path); return ERROR_FAIL; } /* OpenOCD refuses paths containing TAP_RESET */ if (path[i] == TAP_RESET) { /* FIXME last state MUST be stable! */ if (i > 0) { if (!svf_nil) jtag_add_pathmove(i, path); } if (!svf_nil) jtag_add_tlr(); num_of_argu -= i + 1; i = -1; } } if (num_of_argu > 0) { /* execute last path if necessary */ if (svf_tap_state_is_stable(path[num_of_argu - 1])) { /* last state MUST be stable state */ if (!svf_nil) jtag_add_pathmove(num_of_argu, path); LOG_DEBUG("\tmove to %s by path_move", tap_state_name(path[num_of_argu - 1])); } else { LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(path[num_of_argu - 1])); free(path); return ERROR_FAIL; } } free(path); path = NULL; } else { /* STATE stable_state */ state = tap_state_by_name(argus[1]); if (svf_tap_state_is_stable(state)) { LOG_DEBUG("\tmove to %s by svf_add_statemove", tap_state_name(state)); /* FIXME handle statemove failures */ svf_add_statemove(state); } else { LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(state)); return ERROR_FAIL; } } break; case TRST: /* TRST trst_mode */ if (num_of_argu != 2) { LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } if (svf_para.trst_mode != TRST_ABSENT) { if (svf_execute_tap() != ERROR_OK) return ERROR_FAIL; i_tmp = svf_find_string_in_array(argus[1], (char **)svf_trst_mode_name, ARRAY_SIZE(svf_trst_mode_name)); switch (i_tmp) { case TRST_ON: if (!svf_nil) jtag_add_reset(1, 0); break; case TRST_Z: case TRST_OFF: if (!svf_nil) jtag_add_reset(0, 0); break; case TRST_ABSENT: break; default: LOG_ERROR("unknown TRST mode: %s", argus[1]); return ERROR_FAIL; } svf_para.trst_mode = i_tmp; LOG_DEBUG("\ttrst_mode = %s", svf_trst_mode_name[svf_para.trst_mode]); } else { LOG_ERROR("can not accept TRST command if trst_mode is ABSENT"); return ERROR_FAIL; } break; default: LOG_ERROR("invalid svf command: %s", argus[0]); return ERROR_FAIL; } if (!svf_quiet) { if (padding_command_skipped) LOG_USER("(Above Padding command skipped, as per -tap argument)"); } if (debug_level >= LOG_LVL_DEBUG) { /* for convenient debugging, execute tap if possible */ if ((svf_buffer_index > 0) && (((command != STATE) && (command != RUNTEST)) || ((command == STATE) && (num_of_argu == 2)))) { if (svf_execute_tap() != ERROR_OK) return ERROR_FAIL; /* output debug info */ if ((command == SIR) || (command == SDR)) SVF_BUF_LOG(DEBUG, svf_tdi_buffer, svf_check_tdo_para[0].bit_len, "TDO read"); } } else { /* for fast executing, execute tap if necessary */ /* half of the buffer is for the next command */ if (((svf_buffer_index >= SVF_MAX_BUFFER_SIZE_TO_COMMIT) || (svf_check_tdo_para_index >= SVF_CHECK_TDO_PARA_SIZE / 2)) && (((command != STATE) && (command != RUNTEST)) || ((command == STATE) && (num_of_argu == 2)))) return svf_execute_tap(); } return ERROR_OK; } static const struct command_registration svf_command_handlers[] = { { .name = "svf", .handler = handle_svf_command, .mode = COMMAND_EXEC, .help = "Runs a SVF file.", .usage = "[-tap device.tap] [-quiet] [-nil] [-progress] [-ignore_error] [-noreset] [-addcycles numcycles] file", }, COMMAND_REGISTRATION_DONE }; int svf_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, svf_command_handlers); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/svf/svf.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * ***************************************************************************/ #ifndef OPENOCD_SVF_SVF_H #define OPENOCD_SVF_SVF_H #include <jtag/jtag.h> int svf_register_commands(struct command_context *cmd_ctx); /** * svf_add_statemove() moves from the current state to @a goal_state. * * @param goal_state The final TAP state. * @return ERROR_OK on success, or an error code on failure. * * The current and goal states must satisfy svf_tap_state_is_stable(). * State transition paths used by this routine are those given in the * SVF specification for single-argument STATE commands (and also used * for various other state transitions). */ int svf_add_statemove(tap_state_t goal_state); /** * svf_tap_state_is_stable() returns true for stable non-SHIFT states * * @param state The TAP state in question * @return true iff the state is stable and not a SHIFT state. */ bool svf_tap_state_is_stable(tap_state_t state); #endif /* OPENOCD_SVF_SVF_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later %C%_libtarget_la_LIBADD = %D%/openrisc/libopenrisc.la \ %D%/riscv/libriscv.la \ %D%/xtensa/libxtensa.la \ %D%/espressif/libespressif.la %C%_libtarget_la_CPPFLAGS = $(AM_CPPFLAGS) STARTUP_TCL_SRCS += %D%/startup.tcl noinst_LTLIBRARIES += %D%/libtarget.la %C%_libtarget_la_SOURCES = \ $(TARGET_CORE_SRC) \ $(ARM_DEBUG_SRC) \ $(ARMV4_5_SRC) \ $(ARMV6_SRC) \ $(ARMV7_SRC) \ $(ARM_MISC_SRC) \ $(AVR32_SRC) \ $(MIPS32_SRC) \ $(STM8_SRC) \ $(INTEL_IA32_SRC) \ $(ESIRISC_SRC) \ $(ARC_SRC) \ %D%/avrt.c \ %D%/dsp563xx.c \ %D%/dsp563xx_once.c \ %D%/dsp5680xx.c \ %D%/hla_target.c \ $(ARMV8_SRC) \ $(MIPS64_SRC) if HAVE_CAPSTONE %C%_libtarget_la_CPPFLAGS += $(CAPSTONE_CFLAGS) %C%_libtarget_la_LIBADD += $(CAPSTONE_LIBS) endif TARGET_CORE_SRC = \ %D%/algorithm.c \ %D%/register.c \ %D%/image.c \ %D%/breakpoints.c \ %D%/target.c \ %D%/target_request.c \ %D%/testee.c \ %D%/semihosting_common.c \ %D%/smp.c \ %D%/rtt.c ARMV4_5_SRC = \ %D%/armv4_5.c \ %D%/armv4_5_mmu.c \ %D%/armv4_5_cache.c \ $(ARM7_9_SRC) ARM7_9_SRC = \ %D%/arm7_9_common.c \ %D%/arm7tdmi.c \ %D%/arm720t.c \ %D%/arm9tdmi.c \ %D%/arm920t.c \ %D%/arm966e.c \ %D%/arm946e.c \ %D%/arm926ejs.c \ %D%/feroceon.c ARM_MISC_SRC = \ %D%/fa526.c \ %D%/xscale.c ARMV6_SRC = \ %D%/arm11.c \ %D%/arm11_dbgtap.c ARMV7_SRC = \ %D%/armv7m.c \ %D%/armv7m_trace.c \ %D%/cortex_m.c \ %D%/armv7a.c \ %D%/armv7a_mmu.c \ %D%/cortex_a.c \ %D%/ls1_sap.c \ %D%/mem_ap.c ARMV8_SRC = \ %D%/armv8_dpm.c \ %D%/armv8_opcodes.c \ %D%/aarch64.c \ %D%/a64_disassembler.c \ %D%/armv8.c \ %D%/armv8_cache.c ARM_DEBUG_SRC = \ %D%/arm_dpm.c \ %D%/arm_jtag.c \ %D%/arm_disassembler.c \ %D%/arm_simulator.c \ %D%/arm_semihosting.c \ %D%/arm_adi_v5.c \ %D%/arm_dap.c \ %D%/armv7a_cache.c \ %D%/armv7a_cache_l2x.c \ %D%/adi_v5_dapdirect.c \ %D%/adi_v5_jtag.c \ %D%/adi_v5_swd.c \ %D%/embeddedice.c \ %D%/trace.c \ %D%/etb.c \ %D%/etm.c \ %D%/etm_dummy.c \ %D%/arm_tpiu_swo.c \ %D%/arm_cti.c AVR32_SRC = \ %D%/avr32_ap7k.c \ %D%/avr32_jtag.c \ %D%/avr32_mem.c \ %D%/avr32_regs.c MIPS32_SRC = \ %D%/mips32.c \ %D%/mips_m4k.c \ %D%/mips32_pracc.c \ %D%/mips32_dmaacc.c \ %D%/mips_ejtag.c MIPS64_SRC = \ %D%/mips64.c \ %D%/mips32_pracc.c \ %D%/mips64_pracc.c \ %D%/mips_mips64.c \ %D%/trace.c \ %D%/mips_ejtag.c STM8_SRC = \ %D%/stm8.c INTEL_IA32_SRC = \ %D%/quark_x10xx.c \ %D%/quark_d20xx.c \ %D%/lakemont.c \ %D%/x86_32_common.c ESIRISC_SRC = \ %D%/esirisc.c \ %D%/esirisc_jtag.c \ %D%/esirisc_trace.c ARC_SRC = \ %D%/arc.c \ %D%/arc_cmd.c \ %D%/arc_jtag.c \ %D%/arc_mem.c %C%_libtarget_la_SOURCES += \ %D%/algorithm.h \ %D%/arm.h \ %D%/arm_coresight.h \ %D%/arm_dpm.h \ %D%/arm_jtag.h \ %D%/arm_adi_v5.h \ %D%/armv7a_cache.h \ %D%/armv7a_cache_l2x.h \ %D%/armv7a_mmu.h \ %D%/arm_disassembler.h \ %D%/a64_disassembler.h \ %D%/arm_opcodes.h \ %D%/arm_simulator.h \ %D%/arm_semihosting.h \ %D%/arm7_9_common.h \ %D%/arm7tdmi.h \ %D%/arm720t.h \ %D%/arm9tdmi.h \ %D%/arm920t.h \ %D%/arm926ejs.h \ %D%/arm966e.h \ %D%/arm946e.h \ %D%/arm11.h \ %D%/arm11_dbgtap.h \ %D%/armv4_5.h \ %D%/armv4_5_mmu.h \ %D%/armv4_5_cache.h \ %D%/armv7a.h \ %D%/armv7m.h \ %D%/armv7m_trace.h \ %D%/armv8.h \ %D%/armv8_dpm.h \ %D%/armv8_opcodes.h \ %D%/armv8_cache.h \ %D%/avrt.h \ %D%/dsp563xx.h \ %D%/dsp563xx_once.h \ %D%/dsp5680xx.h \ %D%/breakpoints.h \ %D%/cortex_m.h \ %D%/cortex_a.h \ %D%/aarch64.h \ %D%/embeddedice.h \ %D%/etb.h \ %D%/etm.h \ %D%/etm_dummy.h \ %D%/arm_tpiu_swo.h \ %D%/image.h \ %D%/mips32.h \ %D%/mips64.h \ %D%/mips_m4k.h \ %D%/mips_mips64.h \ %D%/mips_ejtag.h \ %D%/mips32_pracc.h \ %D%/mips32_dmaacc.h \ %D%/mips64_pracc.h \ %D%/register.h \ %D%/target.h \ %D%/target_type.h \ %D%/trace.h \ %D%/target_request.h \ %D%/trace.h \ %D%/xscale.h \ %D%/smp.h \ %D%/avr32_ap7k.h \ %D%/avr32_jtag.h \ %D%/avr32_mem.h \ %D%/avr32_regs.h \ %D%/semihosting_common.h \ %D%/stm8.h \ %D%/lakemont.h \ %D%/x86_32_common.h \ %D%/arm_cti.h \ %D%/esirisc.h \ %D%/esirisc_jtag.h \ %D%/esirisc_regs.h \ %D%/esirisc_trace.h \ %D%/arc.h \ %D%/arc_cmd.h \ %D%/arc_jtag.h \ %D%/arc_mem.h \ %D%/rtt.h include %D%/openrisc/Makefile.am include %D%/riscv/Makefile.am include %D%/xtensa/Makefile.am include %D%/espressif/Makefile.am ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/a64_disassembler.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2019 by Mete Balci * * metebalci@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include "target.h" #include "a64_disassembler.h" #if HAVE_CAPSTONE #include <capstone.h> static void print_opcode(struct command_invocation *cmd, const cs_insn *insn) { uint32_t opcode = 0; memcpy(&opcode, insn->bytes, insn->size); if (insn->size == 4) { uint16_t opcode_high = opcode >> 16; opcode = opcode & 0xffff; command_print(cmd, "0x%08" PRIx64" %04x %04x\t%s\t%s", insn->address, opcode, opcode_high, insn->mnemonic, insn->op_str); } else { command_print( cmd, "0x%08" PRIx64" %04x\t%s\t%s", insn->address, opcode, insn->mnemonic, insn->op_str); } } int a64_disassemble(struct command_invocation *cmd, struct target *target, target_addr_t address, size_t count) { int ret; int csret; csh handle; csret = cs_open(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN, &handle); if (csret != CS_ERR_OK) { LOG_ERROR("cs_open() failed: %s", cs_strerror(csret)); return ERROR_FAIL; } csret = cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON); if (csret != CS_ERR_OK) { LOG_ERROR("cs_option() failed: %s", cs_strerror(csret)); cs_close(&handle); return ERROR_FAIL; } cs_insn *insn = cs_malloc(handle); if (csret != CS_ERR_OK) { LOG_ERROR("cs_malloc() failed: %s", cs_strerror(csret)); cs_close(&handle); return ERROR_FAIL; } while (count > 0) { uint8_t buffer[4]; ret = target_read_buffer(target, address, sizeof(buffer), buffer); if (ret != ERROR_OK) { cs_free(insn, 1); cs_close(&handle); return ret; } size_t size = sizeof(buffer); const uint8_t *tmp = buffer; ret = cs_disasm_iter(handle, &tmp, &size, &address, insn); if (!ret) { LOG_ERROR("cs_disasm_iter() failed: %s", cs_strerror(cs_errno(handle))); cs_free(insn, 1); cs_close(&handle); return ERROR_FAIL; } print_opcode(cmd, insn); count--; } cs_free(insn, 1); cs_close(&handle); return ERROR_OK; } #else int a64_disassemble(struct command_invocation *cmd, struct target *target, target_addr_t address, size_t count) { command_print(cmd, "capstone disassembly framework required"); return ERROR_FAIL; } #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/a64_disassembler.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2019 by Mete Balci * * metebalci@gmail.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_AARCH64_DISASSEMBLER_H #define OPENOCD_TARGET_AARCH64_DISASSEMBLER_H #include "target.h" int a64_disassemble( struct command_invocation *cmd, struct target *target, target_addr_t address, size_t count); #endif /* OPENOCD_TARGET_AARCH64_DISASSEMBLER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/aarch64.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2015 by David Ung * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "breakpoints.h" #include "aarch64.h" #include "a64_disassembler.h" #include "register.h" #include "target_request.h" #include "target_type.h" #include "armv8_opcodes.h" #include "armv8_cache.h" #include "arm_coresight.h" #include "arm_semihosting.h" #include "jtag/interface.h" #include "smp.h" #include <helper/nvp.h> #include <helper/time_support.h> enum restart_mode { RESTART_LAZY, RESTART_SYNC, }; enum halt_mode { HALT_LAZY, HALT_SYNC, }; struct aarch64_private_config { struct adiv5_private_config adiv5_config; struct arm_cti *cti; }; static int aarch64_poll(struct target *target); static int aarch64_debug_entry(struct target *target); static int aarch64_restore_context(struct target *target, bool bpwp); static int aarch64_set_breakpoint(struct target *target, struct breakpoint *breakpoint, uint8_t matchmode); static int aarch64_set_context_breakpoint(struct target *target, struct breakpoint *breakpoint, uint8_t matchmode); static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint); static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); static int aarch64_mmu(struct target *target, int *enabled); static int aarch64_virt2phys(struct target *target, target_addr_t virt, target_addr_t *phys); static int aarch64_read_cpu_memory(struct target *target, uint64_t address, uint32_t size, uint32_t count, uint8_t *buffer); static int aarch64_restore_system_control_reg(struct target *target) { enum arm_mode target_mode = ARM_MODE_ANY; int retval = ERROR_OK; uint32_t instr; struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = target_to_armv8(target); if (aarch64->system_control_reg != aarch64->system_control_reg_curr) { aarch64->system_control_reg_curr = aarch64->system_control_reg; /* LOG_INFO("cp15_control_reg: %8.8" PRIx32, cortex_v8->cp15_control_reg); */ switch (armv8->arm.core_mode) { case ARMV8_64_EL0T: target_mode = ARMV8_64_EL1H; /* fall through */ case ARMV8_64_EL1T: case ARMV8_64_EL1H: instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL1, 0); break; case ARMV8_64_EL2T: case ARMV8_64_EL2H: instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL2, 0); break; case ARMV8_64_EL3H: case ARMV8_64_EL3T: instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL3, 0); break; case ARM_MODE_SVC: case ARM_MODE_ABT: case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: case ARM_MODE_UND: case ARM_MODE_SYS: instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); break; default: LOG_ERROR("cannot read system control register in this mode: (%s : 0x%x)", armv8_mode_name(armv8->arm.core_mode), armv8->arm.core_mode); return ERROR_FAIL; } if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(&armv8->dpm, target_mode); retval = armv8->dpm.instr_write_data_r0(&armv8->dpm, instr, aarch64->system_control_reg); if (retval != ERROR_OK) return retval; if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(&armv8->dpm, ARM_MODE_ANY); } return retval; } /* modify system_control_reg in order to enable or disable mmu for : * - virt2phys address conversion * - read or write memory in phys or virt address */ static int aarch64_mmu_modify(struct target *target, int enable) { struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; int retval = ERROR_OK; enum arm_mode target_mode = ARM_MODE_ANY; uint32_t instr = 0; if (enable) { /* if mmu enabled at target stop and mmu not enable */ if (!(aarch64->system_control_reg & 0x1U)) { LOG_ERROR("trying to enable mmu on target stopped with mmu disable"); return ERROR_FAIL; } if (!(aarch64->system_control_reg_curr & 0x1U)) aarch64->system_control_reg_curr |= 0x1U; } else { if (aarch64->system_control_reg_curr & 0x4U) { /* data cache is active */ aarch64->system_control_reg_curr &= ~0x4U; /* flush data cache armv8 function to be called */ if (armv8->armv8_mmu.armv8_cache.flush_all_data_cache) armv8->armv8_mmu.armv8_cache.flush_all_data_cache(target); } if ((aarch64->system_control_reg_curr & 0x1U)) { aarch64->system_control_reg_curr &= ~0x1U; } } switch (armv8->arm.core_mode) { case ARMV8_64_EL0T: target_mode = ARMV8_64_EL1H; /* fall through */ case ARMV8_64_EL1T: case ARMV8_64_EL1H: instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL1, 0); break; case ARMV8_64_EL2T: case ARMV8_64_EL2H: instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL2, 0); break; case ARMV8_64_EL3H: case ARMV8_64_EL3T: instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL3, 0); break; case ARM_MODE_SVC: case ARM_MODE_ABT: case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: case ARM_MODE_UND: case ARM_MODE_SYS: instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); break; default: LOG_DEBUG("unknown cpu state 0x%x", armv8->arm.core_mode); break; } if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(&armv8->dpm, target_mode); retval = armv8->dpm.instr_write_data_r0(&armv8->dpm, instr, aarch64->system_control_reg_curr); if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(&armv8->dpm, ARM_MODE_ANY); return retval; } /* * Basic debug access, very low level assumes state is saved */ static int aarch64_init_debug_access(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); int retval; uint32_t dummy; LOG_DEBUG("%s", target_name(target)); retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_OSLAR, 0); if (retval != ERROR_OK) { LOG_DEBUG("Examine %s failed", "oslock"); return retval; } /* Clear Sticky Power Down status Bit in PRSR to enable access to the registers in the Core Power Domain */ retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_PRSR, &dummy); if (retval != ERROR_OK) return retval; /* * Static CTI configuration: * Channel 0 -> trigger outputs HALT request to PE * Channel 1 -> trigger outputs Resume request to PE * Gate all channel trigger events from entering the CTM */ /* Enable CTI */ retval = arm_cti_enable(armv8->cti, true); /* By default, gate all channel events to and from the CTM */ if (retval == ERROR_OK) retval = arm_cti_write_reg(armv8->cti, CTI_GATE, 0); /* output halt requests to PE on channel 0 event */ if (retval == ERROR_OK) retval = arm_cti_write_reg(armv8->cti, CTI_OUTEN0, CTI_CHNL(0)); /* output restart requests to PE on channel 1 event */ if (retval == ERROR_OK) retval = arm_cti_write_reg(armv8->cti, CTI_OUTEN1, CTI_CHNL(1)); if (retval != ERROR_OK) return retval; /* Resync breakpoint registers */ return ERROR_OK; } /* Write to memory mapped registers directly with no cache or mmu handling */ static int aarch64_dap_write_memap_register_u32(struct target *target, target_addr_t address, uint32_t value) { int retval; struct armv8_common *armv8 = target_to_armv8(target); retval = mem_ap_write_atomic_u32(armv8->debug_ap, address, value); return retval; } static int aarch64_dpm_setup(struct aarch64_common *a8, uint64_t debug) { struct arm_dpm *dpm = &a8->armv8_common.dpm; int retval; dpm->arm = &a8->armv8_common.arm; dpm->didr = debug; retval = armv8_dpm_setup(dpm); if (retval == ERROR_OK) retval = armv8_dpm_initialize(dpm); return retval; } static int aarch64_set_dscr_bits(struct target *target, unsigned long bit_mask, unsigned long value) { struct armv8_common *armv8 = target_to_armv8(target); return armv8_set_dbgreg_bits(armv8, CPUV8_DBG_DSCR, bit_mask, value); } static int aarch64_check_state_one(struct target *target, uint32_t mask, uint32_t val, int *p_result, uint32_t *p_prsr) { struct armv8_common *armv8 = target_to_armv8(target); uint32_t prsr; int retval; retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_PRSR, &prsr); if (retval != ERROR_OK) return retval; if (p_prsr) *p_prsr = prsr; if (p_result) *p_result = (prsr & mask) == (val & mask); return ERROR_OK; } static int aarch64_wait_halt_one(struct target *target) { int retval = ERROR_OK; uint32_t prsr; int64_t then = timeval_ms(); for (;;) { int halted; retval = aarch64_check_state_one(target, PRSR_HALT, PRSR_HALT, &halted, &prsr); if (retval != ERROR_OK || halted) break; if (timeval_ms() > then + 1000) { retval = ERROR_TARGET_TIMEOUT; LOG_DEBUG("target %s timeout, prsr=0x%08"PRIx32, target_name(target), prsr); break; } } return retval; } static int aarch64_prepare_halt_smp(struct target *target, bool exc_target, struct target **p_first) { int retval = ERROR_OK; struct target_list *head; struct target *first = NULL; LOG_DEBUG("target %s exc %i", target_name(target), exc_target); foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; struct armv8_common *armv8 = target_to_armv8(curr); if (exc_target && curr == target) continue; if (!target_was_examined(curr)) continue; if (curr->state != TARGET_RUNNING) continue; /* HACK: mark this target as prepared for halting */ curr->debug_reason = DBG_REASON_DBGRQ; /* open the gate for channel 0 to let HALT requests pass to the CTM */ retval = arm_cti_ungate_channel(armv8->cti, 0); if (retval == ERROR_OK) retval = aarch64_set_dscr_bits(curr, DSCR_HDE, DSCR_HDE); if (retval != ERROR_OK) break; LOG_DEBUG("target %s prepared", target_name(curr)); if (!first) first = curr; } if (p_first) { if (exc_target && first) *p_first = first; else *p_first = target; } return retval; } static int aarch64_halt_one(struct target *target, enum halt_mode mode) { int retval = ERROR_OK; struct armv8_common *armv8 = target_to_armv8(target); LOG_DEBUG("%s", target_name(target)); /* allow Halting Debug Mode */ retval = aarch64_set_dscr_bits(target, DSCR_HDE, DSCR_HDE); if (retval != ERROR_OK) return retval; /* trigger an event on channel 0, this outputs a halt request to the PE */ retval = arm_cti_pulse_channel(armv8->cti, 0); if (retval != ERROR_OK) return retval; if (mode == HALT_SYNC) { retval = aarch64_wait_halt_one(target); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_TIMEOUT) LOG_ERROR("Timeout waiting for target %s halt", target_name(target)); return retval; } } return ERROR_OK; } static int aarch64_halt_smp(struct target *target, bool exc_target) { struct target *next = target; int retval; /* prepare halt on all PEs of the group */ retval = aarch64_prepare_halt_smp(target, exc_target, &next); if (exc_target && next == target) return retval; /* halt the target PE */ if (retval == ERROR_OK) retval = aarch64_halt_one(next, HALT_LAZY); if (retval != ERROR_OK) return retval; /* wait for all PEs to halt */ int64_t then = timeval_ms(); for (;;) { bool all_halted = true; struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { int halted; curr = head->target; if (!target_was_examined(curr)) continue; retval = aarch64_check_state_one(curr, PRSR_HALT, PRSR_HALT, &halted, NULL); if (retval != ERROR_OK || !halted) { all_halted = false; break; } } if (all_halted) break; if (timeval_ms() > then + 1000) { retval = ERROR_TARGET_TIMEOUT; break; } /* * HACK: on Hi6220 there are 8 cores organized in 2 clusters * and it looks like the CTI's are not connected by a common * trigger matrix. It seems that we need to halt one core in each * cluster explicitly. So if we find that a core has not halted * yet, we trigger an explicit halt for the second cluster. */ retval = aarch64_halt_one(curr, HALT_LAZY); if (retval != ERROR_OK) break; } return retval; } static int update_halt_gdb(struct target *target, enum target_debug_reason debug_reason) { struct target *gdb_target = NULL; struct target_list *head; struct target *curr; if (debug_reason == DBG_REASON_NOTHALTED) { LOG_DEBUG("Halting remaining targets in SMP group"); aarch64_halt_smp(target, true); } /* poll all targets in the group, but skip the target that serves GDB */ foreach_smp_target(head, target->smp_targets) { curr = head->target; /* skip calling context */ if (curr == target) continue; if (!target_was_examined(curr)) continue; /* skip targets that were already halted */ if (curr->state == TARGET_HALTED) continue; /* remember the gdb_service->target */ if (curr->gdb_service) gdb_target = curr->gdb_service->target; /* skip it */ if (curr == gdb_target) continue; /* avoid recursion in aarch64_poll() */ curr->smp = 0; aarch64_poll(curr); curr->smp = 1; } /* after all targets were updated, poll the gdb serving target */ if (gdb_target && gdb_target != target) aarch64_poll(gdb_target); return ERROR_OK; } /* * Aarch64 Run control */ static int aarch64_poll(struct target *target) { enum target_state prev_target_state; int retval = ERROR_OK; int halted; retval = aarch64_check_state_one(target, PRSR_HALT, PRSR_HALT, &halted, NULL); if (retval != ERROR_OK) return retval; if (halted) { prev_target_state = target->state; if (prev_target_state != TARGET_HALTED) { enum target_debug_reason debug_reason = target->debug_reason; /* We have a halting debug event */ target->state = TARGET_HALTED; LOG_DEBUG("Target %s halted", target_name(target)); retval = aarch64_debug_entry(target); if (retval != ERROR_OK) return retval; if (target->smp) update_halt_gdb(target, debug_reason); if (arm_semihosting(target, &retval) != 0) return retval; switch (prev_target_state) { case TARGET_RUNNING: case TARGET_UNKNOWN: case TARGET_RESET: target_call_event_callbacks(target, TARGET_EVENT_HALTED); break; case TARGET_DEBUG_RUNNING: target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); break; default: break; } } } else target->state = TARGET_RUNNING; return retval; } static int aarch64_halt(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); armv8->last_run_control_op = ARMV8_RUNCONTROL_HALT; if (target->smp) return aarch64_halt_smp(target, false); return aarch64_halt_one(target, HALT_SYNC); } static int aarch64_restore_one(struct target *target, int current, uint64_t *address, int handle_breakpoints, int debug_execution) { struct armv8_common *armv8 = target_to_armv8(target); struct arm *arm = &armv8->arm; int retval; uint64_t resume_pc; LOG_DEBUG("%s", target_name(target)); if (!debug_execution) target_free_all_working_areas(target); /* current = 1: continue on current pc, otherwise continue at <address> */ resume_pc = buf_get_u64(arm->pc->value, 0, 64); if (!current) resume_pc = *address; else *address = resume_pc; /* Make sure that the Armv7 gdb thumb fixups does not * kill the return address */ switch (arm->core_state) { case ARM_STATE_ARM: resume_pc &= 0xFFFFFFFC; break; case ARM_STATE_AARCH64: resume_pc &= 0xFFFFFFFFFFFFFFFCULL; break; case ARM_STATE_THUMB: case ARM_STATE_THUMB_EE: /* When the return address is loaded into PC * bit 0 must be 1 to stay in Thumb state */ resume_pc |= 0x1; break; case ARM_STATE_JAZELLE: LOG_ERROR("How do I resume into Jazelle state??"); return ERROR_FAIL; } LOG_DEBUG("resume pc = 0x%016" PRIx64, resume_pc); buf_set_u64(arm->pc->value, 0, 64, resume_pc); arm->pc->dirty = true; arm->pc->valid = true; /* called it now before restoring context because it uses cpu * register r0 for restoring system control register */ retval = aarch64_restore_system_control_reg(target); if (retval == ERROR_OK) retval = aarch64_restore_context(target, handle_breakpoints); return retval; } /** * prepare single target for restart * * */ static int aarch64_prepare_restart_one(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); int retval; uint32_t dscr; uint32_t tmp; LOG_DEBUG("%s", target_name(target)); retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; if ((dscr & DSCR_ITE) == 0) LOG_ERROR("DSCR.ITE must be set before leaving debug!"); if ((dscr & DSCR_ERR) != 0) LOG_ERROR("DSCR.ERR must be cleared before leaving debug!"); /* acknowledge a pending CTI halt event */ retval = arm_cti_ack_events(armv8->cti, CTI_TRIG(HALT)); /* * open the CTI gate for channel 1 so that the restart events * get passed along to all PEs. Also close gate for channel 0 * to isolate the PE from halt events. */ if (retval == ERROR_OK) retval = arm_cti_ungate_channel(armv8->cti, 1); if (retval == ERROR_OK) retval = arm_cti_gate_channel(armv8->cti, 0); /* make sure that DSCR.HDE is set */ if (retval == ERROR_OK) { dscr |= DSCR_HDE; retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, dscr); } if (retval == ERROR_OK) { /* clear sticky bits in PRSR, SDR is now 0 */ retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_PRSR, &tmp); } return retval; } static int aarch64_do_restart_one(struct target *target, enum restart_mode mode) { struct armv8_common *armv8 = target_to_armv8(target); int retval; LOG_DEBUG("%s", target_name(target)); /* trigger an event on channel 1, generates a restart request to the PE */ retval = arm_cti_pulse_channel(armv8->cti, 1); if (retval != ERROR_OK) return retval; if (mode == RESTART_SYNC) { int64_t then = timeval_ms(); for (;;) { int resumed; /* * if PRSR.SDR is set now, the target did restart, even * if it's now already halted again (e.g. due to breakpoint) */ retval = aarch64_check_state_one(target, PRSR_SDR, PRSR_SDR, &resumed, NULL); if (retval != ERROR_OK || resumed) break; if (timeval_ms() > then + 1000) { LOG_ERROR("%s: Timeout waiting for resume"PRIx32, target_name(target)); retval = ERROR_TARGET_TIMEOUT; break; } } } if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_NOTHALTED; target->state = TARGET_RUNNING; return ERROR_OK; } static int aarch64_restart_one(struct target *target, enum restart_mode mode) { int retval; LOG_DEBUG("%s", target_name(target)); retval = aarch64_prepare_restart_one(target); if (retval == ERROR_OK) retval = aarch64_do_restart_one(target, mode); return retval; } /* * prepare all but the current target for restart */ static int aarch64_prep_restart_smp(struct target *target, int handle_breakpoints, struct target **p_first) { int retval = ERROR_OK; struct target_list *head; struct target *first = NULL; uint64_t address; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; /* skip calling target */ if (curr == target) continue; if (!target_was_examined(curr)) continue; if (curr->state != TARGET_HALTED) continue; /* resume at current address, not in step mode */ retval = aarch64_restore_one(curr, 1, &address, handle_breakpoints, 0); if (retval == ERROR_OK) retval = aarch64_prepare_restart_one(curr); if (retval != ERROR_OK) { LOG_ERROR("failed to restore target %s", target_name(curr)); break; } /* remember the first valid target in the group */ if (!first) first = curr; } if (p_first) *p_first = first; return retval; } static int aarch64_step_restart_smp(struct target *target) { int retval = ERROR_OK; struct target_list *head; struct target *first = NULL; LOG_DEBUG("%s", target_name(target)); retval = aarch64_prep_restart_smp(target, 0, &first); if (retval != ERROR_OK) return retval; if (first) retval = aarch64_do_restart_one(first, RESTART_LAZY); if (retval != ERROR_OK) { LOG_DEBUG("error restarting target %s", target_name(first)); return retval; } int64_t then = timeval_ms(); for (;;) { struct target *curr = target; bool all_resumed = true; foreach_smp_target(head, target->smp_targets) { uint32_t prsr; int resumed; curr = head->target; if (curr == target) continue; if (!target_was_examined(curr)) continue; retval = aarch64_check_state_one(curr, PRSR_SDR, PRSR_SDR, &resumed, &prsr); if (retval != ERROR_OK || (!resumed && (prsr & PRSR_HALT))) { all_resumed = false; break; } if (curr->state != TARGET_RUNNING) { curr->state = TARGET_RUNNING; curr->debug_reason = DBG_REASON_NOTHALTED; target_call_event_callbacks(curr, TARGET_EVENT_RESUMED); } } if (all_resumed) break; if (timeval_ms() > then + 1000) { LOG_ERROR("%s: timeout waiting for target resume", __func__); retval = ERROR_TARGET_TIMEOUT; break; } /* * HACK: on Hi6220 there are 8 cores organized in 2 clusters * and it looks like the CTI's are not connected by a common * trigger matrix. It seems that we need to halt one core in each * cluster explicitly. So if we find that a core has not halted * yet, we trigger an explicit resume for the second cluster. */ retval = aarch64_do_restart_one(curr, RESTART_LAZY); if (retval != ERROR_OK) break; } return retval; } static int aarch64_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { int retval = 0; uint64_t addr = address; struct armv8_common *armv8 = target_to_armv8(target); armv8->last_run_control_op = ARMV8_RUNCONTROL_RESUME; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; /* * If this target is part of a SMP group, prepare the others * targets for resuming. This involves restoring the complete * target register context and setting up CTI gates to accept * resume events from the trigger matrix. */ if (target->smp) { retval = aarch64_prep_restart_smp(target, handle_breakpoints, NULL); if (retval != ERROR_OK) return retval; } /* all targets prepared, restore and restart the current target */ retval = aarch64_restore_one(target, current, &addr, handle_breakpoints, debug_execution); if (retval == ERROR_OK) retval = aarch64_restart_one(target, RESTART_SYNC); if (retval != ERROR_OK) return retval; if (target->smp) { int64_t then = timeval_ms(); for (;;) { struct target *curr = target; struct target_list *head; bool all_resumed = true; foreach_smp_target(head, target->smp_targets) { uint32_t prsr; int resumed; curr = head->target; if (curr == target) continue; if (!target_was_examined(curr)) continue; retval = aarch64_check_state_one(curr, PRSR_SDR, PRSR_SDR, &resumed, &prsr); if (retval != ERROR_OK || (!resumed && (prsr & PRSR_HALT))) { all_resumed = false; break; } if (curr->state != TARGET_RUNNING) { curr->state = TARGET_RUNNING; curr->debug_reason = DBG_REASON_NOTHALTED; target_call_event_callbacks(curr, TARGET_EVENT_RESUMED); } } if (all_resumed) break; if (timeval_ms() > then + 1000) { LOG_ERROR("%s: timeout waiting for target %s to resume", __func__, target_name(curr)); retval = ERROR_TARGET_TIMEOUT; break; } /* * HACK: on Hi6220 there are 8 cores organized in 2 clusters * and it looks like the CTI's are not connected by a common * trigger matrix. It seems that we need to halt one core in each * cluster explicitly. So if we find that a core has not halted * yet, we trigger an explicit resume for the second cluster. */ retval = aarch64_do_restart_one(curr, RESTART_LAZY); if (retval != ERROR_OK) break; } } if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_NOTHALTED; if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); LOG_DEBUG("target resumed at 0x%" PRIx64, addr); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); LOG_DEBUG("target debug resumed at 0x%" PRIx64, addr); } return ERROR_OK; } static int aarch64_debug_entry(struct target *target) { int retval = ERROR_OK; struct armv8_common *armv8 = target_to_armv8(target); struct arm_dpm *dpm = &armv8->dpm; enum arm_state core_state; uint32_t dscr; /* make sure to clear all sticky errors */ retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DRCR, DRCR_CSE); if (retval == ERROR_OK) retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, &dscr); if (retval == ERROR_OK) retval = arm_cti_ack_events(armv8->cti, CTI_TRIG(HALT)); if (retval != ERROR_OK) return retval; LOG_DEBUG("%s dscr = 0x%08" PRIx32, target_name(target), dscr); dpm->dscr = dscr; core_state = armv8_dpm_get_core_state(dpm); armv8_select_opcodes(armv8, core_state == ARM_STATE_AARCH64); armv8_select_reg_access(armv8, core_state == ARM_STATE_AARCH64); /* close the CTI gate for all events */ if (retval == ERROR_OK) retval = arm_cti_write_reg(armv8->cti, CTI_GATE, 0); /* discard async exceptions */ if (retval == ERROR_OK) retval = dpm->instr_cpsr_sync(dpm); if (retval != ERROR_OK) return retval; /* Examine debug reason */ armv8_dpm_report_dscr(dpm, dscr); /* save the memory address that triggered the watchpoint */ if (target->debug_reason == DBG_REASON_WATCHPOINT) { uint32_t tmp; retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_EDWAR0, &tmp); if (retval != ERROR_OK) return retval; target_addr_t edwar = tmp; /* EDWAR[63:32] has unknown content in aarch32 state */ if (core_state == ARM_STATE_AARCH64) { retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_EDWAR1, &tmp); if (retval != ERROR_OK) return retval; edwar |= ((target_addr_t)tmp) << 32; } armv8->dpm.wp_addr = edwar; } retval = armv8_dpm_read_current_registers(&armv8->dpm); if (retval == ERROR_OK && armv8->post_debug_entry) retval = armv8->post_debug_entry(target); return retval; } static int aarch64_post_debug_entry(struct target *target) { struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; int retval; enum arm_mode target_mode = ARM_MODE_ANY; uint32_t instr; switch (armv8->arm.core_mode) { case ARMV8_64_EL0T: target_mode = ARMV8_64_EL1H; /* fall through */ case ARMV8_64_EL1T: case ARMV8_64_EL1H: instr = ARMV8_MRS(SYSTEM_SCTLR_EL1, 0); break; case ARMV8_64_EL2T: case ARMV8_64_EL2H: instr = ARMV8_MRS(SYSTEM_SCTLR_EL2, 0); break; case ARMV8_64_EL3H: case ARMV8_64_EL3T: instr = ARMV8_MRS(SYSTEM_SCTLR_EL3, 0); break; case ARM_MODE_SVC: case ARM_MODE_ABT: case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: case ARM_MODE_UND: case ARM_MODE_SYS: instr = ARMV4_5_MRC(15, 0, 0, 1, 0, 0); break; default: LOG_ERROR("cannot read system control register in this mode: (%s : 0x%x)", armv8_mode_name(armv8->arm.core_mode), armv8->arm.core_mode); return ERROR_FAIL; } if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(&armv8->dpm, target_mode); retval = armv8->dpm.instr_read_data_r0(&armv8->dpm, instr, &aarch64->system_control_reg); if (retval != ERROR_OK) return retval; if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(&armv8->dpm, ARM_MODE_ANY); LOG_DEBUG("System_register: %8.8" PRIx32, aarch64->system_control_reg); aarch64->system_control_reg_curr = aarch64->system_control_reg; if (armv8->armv8_mmu.armv8_cache.info == -1) { armv8_identify_cache(armv8); armv8_read_mpidr(armv8); } if (armv8->is_armv8r) { armv8->armv8_mmu.mmu_enabled = 0; } else { armv8->armv8_mmu.mmu_enabled = (aarch64->system_control_reg & 0x1U) ? 1 : 0; } armv8->armv8_mmu.armv8_cache.d_u_cache_enabled = (aarch64->system_control_reg & 0x4U) ? 1 : 0; armv8->armv8_mmu.armv8_cache.i_cache_enabled = (aarch64->system_control_reg & 0x1000U) ? 1 : 0; return ERROR_OK; } /* * single-step a target */ static int aarch64_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { struct armv8_common *armv8 = target_to_armv8(target); struct aarch64_common *aarch64 = target_to_aarch64(target); int saved_retval = ERROR_OK; int retval; uint32_t edecr; armv8->last_run_control_op = ARMV8_RUNCONTROL_STEP; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_EDECR, &edecr); /* make sure EDECR.SS is not set when restoring the register */ if (retval == ERROR_OK) { edecr &= ~0x4; /* set EDECR.SS to enter hardware step mode */ retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_EDECR, (edecr|0x4)); } /* disable interrupts while stepping */ if (retval == ERROR_OK && aarch64->isrmasking_mode == AARCH64_ISRMASK_ON) retval = aarch64_set_dscr_bits(target, 0x3 << 22, 0x3 << 22); /* bail out if stepping setup has failed */ if (retval != ERROR_OK) return retval; if (target->smp && (current == 1)) { /* * isolate current target so that it doesn't get resumed * together with the others */ retval = arm_cti_gate_channel(armv8->cti, 1); /* resume all other targets in the group */ if (retval == ERROR_OK) retval = aarch64_step_restart_smp(target); if (retval != ERROR_OK) { LOG_ERROR("Failed to restart non-stepping targets in SMP group"); return retval; } LOG_DEBUG("Restarted all non-stepping targets in SMP group"); } /* all other targets running, restore and restart the current target */ retval = aarch64_restore_one(target, current, &address, 0, 0); if (retval == ERROR_OK) retval = aarch64_restart_one(target, RESTART_LAZY); if (retval != ERROR_OK) return retval; LOG_DEBUG("target step-resumed at 0x%" PRIx64, address); if (!handle_breakpoints) target_call_event_callbacks(target, TARGET_EVENT_RESUMED); int64_t then = timeval_ms(); for (;;) { int stepped; uint32_t prsr; retval = aarch64_check_state_one(target, PRSR_SDR|PRSR_HALT, PRSR_SDR|PRSR_HALT, &stepped, &prsr); if (retval != ERROR_OK || stepped) break; if (timeval_ms() > then + 100) { LOG_ERROR("timeout waiting for target %s halt after step", target_name(target)); retval = ERROR_TARGET_TIMEOUT; break; } } /* * At least on one SoC (Renesas R8A7795) stepping over a WFI instruction * causes a timeout. The core takes the step but doesn't complete it and so * debug state is never entered. However, you can manually halt the core * as an external debug even is also a WFI wakeup event. */ if (retval == ERROR_TARGET_TIMEOUT) saved_retval = aarch64_halt_one(target, HALT_SYNC); /* restore EDECR */ retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_EDECR, edecr); if (retval != ERROR_OK) return retval; /* restore interrupts */ if (aarch64->isrmasking_mode == AARCH64_ISRMASK_ON) { retval = aarch64_set_dscr_bits(target, 0x3 << 22, 0); if (retval != ERROR_OK) return ERROR_OK; } if (saved_retval != ERROR_OK) return saved_retval; return ERROR_OK; } static int aarch64_restore_context(struct target *target, bool bpwp) { struct armv8_common *armv8 = target_to_armv8(target); struct arm *arm = &armv8->arm; int retval; LOG_DEBUG("%s", target_name(target)); if (armv8->pre_restore_context) armv8->pre_restore_context(target); retval = armv8_dpm_write_dirty_registers(&armv8->dpm, bpwp); if (retval == ERROR_OK) { /* registers are now invalid */ register_cache_invalidate(arm->core_cache); register_cache_invalidate(arm->core_cache->next); } return retval; } /* * Cortex-A8 Breakpoint and watchpoint functions */ /* Setup hardware Breakpoint Register Pair */ static int aarch64_set_breakpoint(struct target *target, struct breakpoint *breakpoint, uint8_t matchmode) { int retval; int brp_i = 0; uint32_t control; uint8_t byte_addr_select = 0x0F; struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { int64_t bpt_value; while (brp_list[brp_i].used && (brp_i < aarch64->brp_num)) brp_i++; if (brp_i >= aarch64->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint_hw_set(breakpoint, brp_i); if (breakpoint->length == 2) byte_addr_select = (3 << (breakpoint->address & 0x02)); control = ((matchmode & 0x7) << 20) | (1 << 13) | (byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_i].used = 1; brp_list[brp_i].value = breakpoint->address & 0xFFFFFFFFFFFFFFFCULL; brp_list[brp_i].control = control; bpt_value = brp_list[brp_i].value; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].brpn, (uint32_t)(bpt_value & 0xFFFFFFFF)); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].brpn, (uint32_t)(bpt_value >> 32)); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; LOG_DEBUG("brp %i control 0x%0" PRIx32 " value 0x%" TARGET_PRIxADDR, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); } else if (breakpoint->type == BKPT_SOFT) { uint32_t opcode; uint8_t code[4]; if (armv8_dpm_get_core_state(&armv8->dpm) == ARM_STATE_AARCH64) { opcode = ARMV8_HLT(11); if (breakpoint->length != 4) LOG_ERROR("bug: breakpoint length should be 4 in AArch64 mode"); } else { /** * core_state is ARM_STATE_ARM * in that case the opcode depends on breakpoint length: * - if length == 4 => A32 opcode * - if length == 2 => T32 opcode * - if length == 3 => T32 opcode (refer to gdb doc : ARM-Breakpoint-Kinds) * in that case the length should be changed from 3 to 4 bytes **/ opcode = (breakpoint->length == 4) ? ARMV8_HLT_A1(11) : (uint32_t) (ARMV8_HLT_T1(11) | ARMV8_HLT_T1(11) << 16); if (breakpoint->length == 3) breakpoint->length = 4; } buf_set_u32(code, 0, 32, opcode); retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; armv8_cache_d_inner_flush_virt(armv8, breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length, 1, code); if (retval != ERROR_OK) return retval; armv8_cache_d_inner_flush_virt(armv8, breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); armv8_cache_i_inner_inval_virt(armv8, breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); breakpoint->is_set = true; } /* Ensure that halting debug mode is enable */ retval = aarch64_set_dscr_bits(target, DSCR_HDE, DSCR_HDE); if (retval != ERROR_OK) { LOG_DEBUG("Failed to set DSCR.HDE"); return retval; } return ERROR_OK; } static int aarch64_set_context_breakpoint(struct target *target, struct breakpoint *breakpoint, uint8_t matchmode) { int retval = ERROR_FAIL; int brp_i = 0; uint32_t control; uint8_t byte_addr_select = 0x0F; struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } /*check available context BRPs*/ while ((brp_list[brp_i].used || (brp_list[brp_i].type != BRP_CONTEXT)) && (brp_i < aarch64->brp_num)) brp_i++; if (brp_i >= aarch64->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; } breakpoint_hw_set(breakpoint, brp_i); control = ((matchmode & 0x7) << 20) | (1 << 13) | (byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_i].used = 1; brp_list[brp_i].value = (breakpoint->asid); brp_list[brp_i].control = control; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; LOG_DEBUG("brp %i control 0x%0" PRIx32 " value 0x%" TARGET_PRIxADDR, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); return ERROR_OK; } static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval = ERROR_FAIL; int brp_1 = 0; /* holds the contextID pair */ int brp_2 = 0; /* holds the IVA pair */ uint32_t control_ctx, control_iva; uint8_t ctx_byte_addr_select = 0x0F; uint8_t iva_byte_addr_select = 0x0F; uint8_t ctx_machmode = 0x03; uint8_t iva_machmode = 0x01; struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } /*check available context BRPs*/ while ((brp_list[brp_1].used || (brp_list[brp_1].type != BRP_CONTEXT)) && (brp_1 < aarch64->brp_num)) brp_1++; LOG_DEBUG("brp(CTX) found num: %d", brp_1); if (brp_1 >= aarch64->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; } while ((brp_list[brp_2].used || (brp_list[brp_2].type != BRP_NORMAL)) && (brp_2 < aarch64->brp_num)) brp_2++; LOG_DEBUG("brp(IVA) found num: %d", brp_2); if (brp_2 >= aarch64->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; } breakpoint_hw_set(breakpoint, brp_1); breakpoint->linked_brp = brp_2; control_ctx = ((ctx_machmode & 0x7) << 20) | (brp_2 << 16) | (0 << 14) | (ctx_byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_1].used = 1; brp_list[brp_1].value = (breakpoint->asid); brp_list[brp_1].control = control_ctx; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_1].brpn, brp_list[brp_1].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_1].brpn, brp_list[brp_1].control); if (retval != ERROR_OK) return retval; control_iva = ((iva_machmode & 0x7) << 20) | (brp_1 << 16) | (1 << 13) | (iva_byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_2].used = 1; brp_list[brp_2].value = breakpoint->address & 0xFFFFFFFFFFFFFFFCULL; brp_list[brp_2].control = control_iva; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_2].brpn, brp_list[brp_2].value & 0xFFFFFFFF); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_2].brpn, brp_list[brp_2].value >> 32); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_2].brpn, brp_list[brp_2].control); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval; struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { int brp_i = breakpoint->number; int brp_j = breakpoint->linked_brp; if (brp_i >= aarch64->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%" TARGET_PRIxADDR, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); brp_list[brp_i].used = 0; brp_list[brp_i].value = 0; brp_list[brp_i].control = 0; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].brpn, (uint32_t)brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].brpn, (uint32_t)brp_list[brp_i].value); if (retval != ERROR_OK) return retval; if ((brp_j < 0) || (brp_j >= aarch64->brp_num)) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx64, brp_j, brp_list[brp_j].control, brp_list[brp_j].value); brp_list[brp_j].used = 0; brp_list[brp_j].value = 0; brp_list[brp_j].control = 0; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_j].brpn, brp_list[brp_j].control); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_j].brpn, (uint32_t)brp_list[brp_j].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_j].brpn, (uint32_t)brp_list[brp_j].value); if (retval != ERROR_OK) return retval; breakpoint->linked_brp = 0; breakpoint->is_set = false; return ERROR_OK; } else { int brp_i = breakpoint->number; if (brp_i >= aarch64->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx64, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); brp_list[brp_i].used = 0; brp_list[brp_i].value = 0; brp_list[brp_i].control = 0; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].brpn, (uint32_t)brp_list[brp_i].value); if (retval != ERROR_OK) return retval; breakpoint->is_set = false; return ERROR_OK; } } else { /* restore original instruction (kept in target endianness) */ armv8_cache_d_inner_flush_virt(armv8, breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); if (breakpoint->length == 4) { retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } else { retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } armv8_cache_d_inner_flush_virt(armv8, breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); armv8_cache_i_inner_inval_virt(armv8, breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); } breakpoint->is_set = false; return ERROR_OK; } static int aarch64_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct aarch64_common *aarch64 = target_to_aarch64(target); if ((breakpoint->type == BKPT_HARD) && (aarch64->brp_num_available < 1)) { LOG_INFO("no hardware breakpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_HARD) aarch64->brp_num_available--; return aarch64_set_breakpoint(target, breakpoint, 0x00); /* Exact match */ } static int aarch64_add_context_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct aarch64_common *aarch64 = target_to_aarch64(target); if ((breakpoint->type == BKPT_HARD) && (aarch64->brp_num_available < 1)) { LOG_INFO("no hardware breakpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_HARD) aarch64->brp_num_available--; return aarch64_set_context_breakpoint(target, breakpoint, 0x02); /* asid match */ } static int aarch64_add_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct aarch64_common *aarch64 = target_to_aarch64(target); if ((breakpoint->type == BKPT_HARD) && (aarch64->brp_num_available < 1)) { LOG_INFO("no hardware breakpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_HARD) aarch64->brp_num_available--; return aarch64_set_hybrid_breakpoint(target, breakpoint); /* ??? */ } static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct aarch64_common *aarch64 = target_to_aarch64(target); #if 0 /* It is perfectly possible to remove breakpoints while the target is running */ if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } #endif if (breakpoint->is_set) { aarch64_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) aarch64->brp_num_available++; } return ERROR_OK; } /* Setup hardware Watchpoint Register Pair */ static int aarch64_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { int retval; int wp_i = 0; uint32_t control, offset, length; struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *wp_list = aarch64->wp_list; if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } while (wp_list[wp_i].used && (wp_i < aarch64->wp_num)) wp_i++; if (wp_i >= aarch64->wp_num) { LOG_ERROR("ERROR Can not find free Watchpoint Register Pair"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } control = (1 << 0) /* enable */ | (3 << 1) /* both user and privileged access */ | (1 << 13); /* higher mode control */ switch (watchpoint->rw) { case WPT_READ: control |= 1 << 3; break; case WPT_WRITE: control |= 2 << 3; break; case WPT_ACCESS: control |= 3 << 3; break; } /* Match up to 8 bytes. */ offset = watchpoint->address & 7; length = watchpoint->length; if (offset + length > sizeof(uint64_t)) { length = sizeof(uint64_t) - offset; LOG_WARNING("Adjust watchpoint match inside 8-byte boundary"); } for (; length > 0; offset++, length--) control |= (1 << offset) << 5; wp_list[wp_i].value = watchpoint->address & 0xFFFFFFFFFFFFFFF8ULL; wp_list[wp_i].control = control; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_WVR_BASE + 16 * wp_list[wp_i].brpn, (uint32_t)(wp_list[wp_i].value & 0xFFFFFFFF)); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_WVR_BASE + 4 + 16 * wp_list[wp_i].brpn, (uint32_t)(wp_list[wp_i].value >> 32)); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_WCR_BASE + 16 * wp_list[wp_i].brpn, control); if (retval != ERROR_OK) return retval; LOG_DEBUG("wp %i control 0x%0" PRIx32 " value 0x%" TARGET_PRIxADDR, wp_i, wp_list[wp_i].control, wp_list[wp_i].value); /* Ensure that halting debug mode is enable */ retval = aarch64_set_dscr_bits(target, DSCR_HDE, DSCR_HDE); if (retval != ERROR_OK) { LOG_DEBUG("Failed to set DSCR.HDE"); return retval; } wp_list[wp_i].used = 1; watchpoint_set(watchpoint, wp_i); return ERROR_OK; } /* Clear hardware Watchpoint Register Pair */ static int aarch64_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { int retval; struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *wp_list = aarch64->wp_list; if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } int wp_i = watchpoint->number; if (wp_i >= aarch64->wp_num) { LOG_DEBUG("Invalid WP number in watchpoint"); return ERROR_OK; } LOG_DEBUG("rwp %i control 0x%0" PRIx32 " value 0x%0" PRIx64, wp_i, wp_list[wp_i].control, wp_list[wp_i].value); wp_list[wp_i].used = 0; wp_list[wp_i].value = 0; wp_list[wp_i].control = 0; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_WCR_BASE + 16 * wp_list[wp_i].brpn, wp_list[wp_i].control); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_WVR_BASE + 16 * wp_list[wp_i].brpn, wp_list[wp_i].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_WVR_BASE + 4 + 16 * wp_list[wp_i].brpn, (uint32_t)wp_list[wp_i].value); if (retval != ERROR_OK) return retval; watchpoint->is_set = false; return ERROR_OK; } static int aarch64_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { int retval; struct aarch64_common *aarch64 = target_to_aarch64(target); if (aarch64->wp_num_available < 1) { LOG_INFO("no hardware watchpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = aarch64_set_watchpoint(target, watchpoint); if (retval == ERROR_OK) aarch64->wp_num_available--; return retval; } static int aarch64_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct aarch64_common *aarch64 = target_to_aarch64(target); if (watchpoint->is_set) { aarch64_unset_watchpoint(target, watchpoint); aarch64->wp_num_available++; } return ERROR_OK; } /** * find out which watchpoint hits * get exception address and compare the address to watchpoints */ static int aarch64_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { if (target->debug_reason != DBG_REASON_WATCHPOINT) return ERROR_FAIL; struct armv8_common *armv8 = target_to_armv8(target); target_addr_t exception_address; struct watchpoint *wp; exception_address = armv8->dpm.wp_addr; if (exception_address == 0xFFFFFFFF) return ERROR_FAIL; for (wp = target->watchpoints; wp; wp = wp->next) if (exception_address >= wp->address && exception_address < (wp->address + wp->length)) { *hit_watchpoint = wp; return ERROR_OK; } return ERROR_FAIL; } /* * Cortex-A8 Reset functions */ static int aarch64_enable_reset_catch(struct target *target, bool enable) { struct armv8_common *armv8 = target_to_armv8(target); uint32_t edecr; int retval; retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_EDECR, &edecr); LOG_DEBUG("EDECR = 0x%08" PRIx32 ", enable=%d", edecr, enable); if (retval != ERROR_OK) return retval; if (enable) edecr |= ECR_RCE; else edecr &= ~ECR_RCE; return mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_EDECR, edecr); } static int aarch64_clear_reset_catch(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); uint32_t edesr; int retval; bool was_triggered; /* check if Reset Catch debug event triggered as expected */ retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_EDESR, &edesr); if (retval != ERROR_OK) return retval; was_triggered = !!(edesr & ESR_RC); LOG_DEBUG("Reset Catch debug event %s", was_triggered ? "triggered" : "NOT triggered!"); if (was_triggered) { /* clear pending Reset Catch debug event */ edesr &= ~ESR_RC; retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_EDESR, edesr); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int aarch64_assert_reset(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); enum reset_types reset_config = jtag_get_reset_config(); int retval; LOG_DEBUG(" "); /* Issue some kind of warm reset. */ if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) target_handle_event(target, TARGET_EVENT_RESET_ASSERT); else if (reset_config & RESET_HAS_SRST) { bool srst_asserted = false; if (target->reset_halt && !(reset_config & RESET_SRST_PULLS_TRST)) { if (target_was_examined(target)) { if (reset_config & RESET_SRST_NO_GATING) { /* * SRST needs to be asserted *before* Reset Catch * debug event can be set up. */ adapter_assert_reset(); srst_asserted = true; } /* make sure to clear all sticky errors */ mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DRCR, DRCR_CSE); /* set up Reset Catch debug event to halt the CPU after reset */ retval = aarch64_enable_reset_catch(target, true); if (retval != ERROR_OK) LOG_WARNING("%s: Error enabling Reset Catch debug event; the CPU will not halt immediately after reset!", target_name(target)); } else { LOG_WARNING("%s: Target not examined, will not halt immediately after reset!", target_name(target)); } } /* REVISIT handle "pulls" cases, if there's * hardware that needs them to work. */ if (!srst_asserted) adapter_assert_reset(); } else { LOG_ERROR("%s: how to reset?", target_name(target)); return ERROR_FAIL; } /* registers are now invalid */ if (target_was_examined(target)) { register_cache_invalidate(armv8->arm.core_cache); register_cache_invalidate(armv8->arm.core_cache->next); } target->state = TARGET_RESET; return ERROR_OK; } static int aarch64_deassert_reset(struct target *target) { int retval; LOG_DEBUG(" "); /* be certain SRST is off */ adapter_deassert_reset(); if (!target_was_examined(target)) return ERROR_OK; retval = aarch64_init_debug_access(target); if (retval != ERROR_OK) return retval; retval = aarch64_poll(target); if (retval != ERROR_OK) return retval; if (target->reset_halt) { /* clear pending Reset Catch debug event */ retval = aarch64_clear_reset_catch(target); if (retval != ERROR_OK) LOG_WARNING("%s: Clearing Reset Catch debug event failed", target_name(target)); /* disable Reset Catch debug event */ retval = aarch64_enable_reset_catch(target, false); if (retval != ERROR_OK) LOG_WARNING("%s: Disabling Reset Catch debug event failed", target_name(target)); if (target->state != TARGET_HALTED) { LOG_WARNING("%s: ran after reset and before halt ...", target_name(target)); if (target_was_examined(target)) { retval = aarch64_halt_one(target, HALT_LAZY); if (retval != ERROR_OK) return retval; } else { target->state = TARGET_UNKNOWN; } } } return ERROR_OK; } static int aarch64_write_cpu_memory_slow(struct target *target, uint32_t size, uint32_t count, const uint8_t *buffer, uint32_t *dscr) { struct armv8_common *armv8 = target_to_armv8(target); struct arm_dpm *dpm = &armv8->dpm; struct arm *arm = &armv8->arm; int retval; armv8_reg_current(arm, 1)->dirty = true; /* change DCC to normal mode if necessary */ if (*dscr & DSCR_MA) { *dscr &= ~DSCR_MA; retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, *dscr); if (retval != ERROR_OK) return retval; } while (count) { uint32_t data, opcode; /* write the data to store into DTRRX */ if (size == 1) data = *buffer; else if (size == 2) data = target_buffer_get_u16(target, buffer); else data = target_buffer_get_u32(target, buffer); retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DTRRX, data); if (retval != ERROR_OK) return retval; if (arm->core_state == ARM_STATE_AARCH64) retval = dpm->instr_execute(dpm, ARMV8_MRS(SYSTEM_DBG_DTRRX_EL0, 1)); else retval = dpm->instr_execute(dpm, ARMV4_5_MRC(14, 0, 1, 0, 5, 0)); if (retval != ERROR_OK) return retval; if (size == 1) opcode = armv8_opcode(armv8, ARMV8_OPC_STRB_IP); else if (size == 2) opcode = armv8_opcode(armv8, ARMV8_OPC_STRH_IP); else opcode = armv8_opcode(armv8, ARMV8_OPC_STRW_IP); retval = dpm->instr_execute(dpm, opcode); if (retval != ERROR_OK) return retval; /* Advance */ buffer += size; --count; } return ERROR_OK; } static int aarch64_write_cpu_memory_fast(struct target *target, uint32_t count, const uint8_t *buffer, uint32_t *dscr) { struct armv8_common *armv8 = target_to_armv8(target); struct arm *arm = &armv8->arm; int retval; armv8_reg_current(arm, 1)->dirty = true; /* Step 1.d - Change DCC to memory mode */ *dscr |= DSCR_MA; retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, *dscr); if (retval != ERROR_OK) return retval; /* Step 2.a - Do the write */ retval = mem_ap_write_buf_noincr(armv8->debug_ap, buffer, 4, count, armv8->debug_base + CPUV8_DBG_DTRRX); if (retval != ERROR_OK) return retval; /* Step 3.a - Switch DTR mode back to Normal mode */ *dscr &= ~DSCR_MA; retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, *dscr); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int aarch64_write_cpu_memory(struct target *target, uint64_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { /* write memory through APB-AP */ int retval = ERROR_COMMAND_SYNTAX_ERROR; struct armv8_common *armv8 = target_to_armv8(target); struct arm_dpm *dpm = &armv8->dpm; struct arm *arm = &armv8->arm; uint32_t dscr; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Mark register X0 as dirty, as it will be used * for transferring the data. * It will be restored automatically when exiting * debug mode */ armv8_reg_current(arm, 0)->dirty = true; /* This algorithm comes from DDI0487A.g, chapter J9.1 */ /* Read DSCR */ retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; /* Set Normal access mode */ dscr = (dscr & ~DSCR_MA); retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, dscr); if (retval != ERROR_OK) return retval; if (arm->core_state == ARM_STATE_AARCH64) { /* Write X0 with value 'address' using write procedure */ /* Step 1.a+b - Write the address for read access into DBGDTR_EL0 */ /* Step 1.c - Copy value from DTR to R0 using instruction mrs DBGDTR_EL0, x0 */ retval = dpm->instr_write_data_dcc_64(dpm, ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0), address); } else { /* Write R0 with value 'address' using write procedure */ /* Step 1.a+b - Write the address for read access into DBGDTRRX */ /* Step 1.c - Copy value from DTR to R0 using instruction mrc DBGDTRTXint, r0 */ retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), address); } if (retval != ERROR_OK) return retval; if (size == 4 && (address % 4) == 0) retval = aarch64_write_cpu_memory_fast(target, count, buffer, &dscr); else retval = aarch64_write_cpu_memory_slow(target, size, count, buffer, &dscr); if (retval != ERROR_OK) { /* Unset DTR mode */ mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, &dscr); dscr &= ~DSCR_MA; mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, dscr); } /* Check for sticky abort flags in the DSCR */ retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; dpm->dscr = dscr; if (dscr & (DSCR_ERR | DSCR_SYS_ERROR_PEND)) { /* Abort occurred - clear it and exit */ LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr); armv8_dpm_handle_exception(dpm, true); return ERROR_FAIL; } /* Done */ return ERROR_OK; } static int aarch64_read_cpu_memory_slow(struct target *target, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t *dscr) { struct armv8_common *armv8 = target_to_armv8(target); struct arm_dpm *dpm = &armv8->dpm; struct arm *arm = &armv8->arm; int retval; armv8_reg_current(arm, 1)->dirty = true; /* change DCC to normal mode (if necessary) */ if (*dscr & DSCR_MA) { *dscr &= DSCR_MA; retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, *dscr); if (retval != ERROR_OK) return retval; } while (count) { uint32_t opcode, data; if (size == 1) opcode = armv8_opcode(armv8, ARMV8_OPC_LDRB_IP); else if (size == 2) opcode = armv8_opcode(armv8, ARMV8_OPC_LDRH_IP); else opcode = armv8_opcode(armv8, ARMV8_OPC_LDRW_IP); retval = dpm->instr_execute(dpm, opcode); if (retval != ERROR_OK) return retval; if (arm->core_state == ARM_STATE_AARCH64) retval = dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DTRTX_EL0, 1)); else retval = dpm->instr_execute(dpm, ARMV4_5_MCR(14, 0, 1, 0, 5, 0)); if (retval != ERROR_OK) return retval; retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DTRTX, &data); if (retval != ERROR_OK) return retval; if (size == 1) *buffer = (uint8_t)data; else if (size == 2) target_buffer_set_u16(target, buffer, (uint16_t)data); else target_buffer_set_u32(target, buffer, data); /* Advance */ buffer += size; --count; } return ERROR_OK; } static int aarch64_read_cpu_memory_fast(struct target *target, uint32_t count, uint8_t *buffer, uint32_t *dscr) { struct armv8_common *armv8 = target_to_armv8(target); struct arm_dpm *dpm = &armv8->dpm; struct arm *arm = &armv8->arm; int retval; uint32_t value; /* Mark X1 as dirty */ armv8_reg_current(arm, 1)->dirty = true; if (arm->core_state == ARM_STATE_AARCH64) { /* Step 1.d - Dummy operation to ensure EDSCR.Txfull == 1 */ retval = dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, 0)); } else { /* Step 1.d - Dummy operation to ensure EDSCR.Txfull == 1 */ retval = dpm->instr_execute(dpm, ARMV4_5_MCR(14, 0, 0, 0, 5, 0)); } if (retval != ERROR_OK) return retval; /* Step 1.e - Change DCC to memory mode */ *dscr |= DSCR_MA; retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, *dscr); if (retval != ERROR_OK) return retval; /* Step 1.f - read DBGDTRTX and discard the value */ retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DTRTX, &value); if (retval != ERROR_OK) return retval; count--; /* Read the data - Each read of the DTRTX register causes the instruction to be reissued * Abort flags are sticky, so can be read at end of transactions * * This data is read in aligned to 32 bit boundary. */ if (count) { /* Step 2.a - Loop n-1 times, each read of DBGDTRTX reads the data from [X0] and * increments X0 by 4. */ retval = mem_ap_read_buf_noincr(armv8->debug_ap, buffer, 4, count, armv8->debug_base + CPUV8_DBG_DTRTX); if (retval != ERROR_OK) return retval; } /* Step 3.a - set DTR access mode back to Normal mode */ *dscr &= ~DSCR_MA; retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, *dscr); if (retval != ERROR_OK) return retval; /* Step 3.b - read DBGDTRTX for the final value */ retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DTRTX, &value); if (retval != ERROR_OK) return retval; target_buffer_set_u32(target, buffer + count * 4, value); return retval; } static int aarch64_read_cpu_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { /* read memory through APB-AP */ int retval = ERROR_COMMAND_SYNTAX_ERROR; struct armv8_common *armv8 = target_to_armv8(target); struct arm_dpm *dpm = &armv8->dpm; struct arm *arm = &armv8->arm; uint32_t dscr; LOG_DEBUG("Reading CPU memory address 0x%016" PRIx64 " size %" PRIu32 " count %" PRIu32, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Mark register X0 as dirty, as it will be used * for transferring the data. * It will be restored automatically when exiting * debug mode */ armv8_reg_current(arm, 0)->dirty = true; /* Read DSCR */ retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; /* This algorithm comes from DDI0487A.g, chapter J9.1 */ /* Set Normal access mode */ dscr &= ~DSCR_MA; retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, dscr); if (retval != ERROR_OK) return retval; if (arm->core_state == ARM_STATE_AARCH64) { /* Write X0 with value 'address' using write procedure */ /* Step 1.a+b - Write the address for read access into DBGDTR_EL0 */ /* Step 1.c - Copy value from DTR to R0 using instruction mrs DBGDTR_EL0, x0 */ retval = dpm->instr_write_data_dcc_64(dpm, ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0), address); } else { /* Write R0 with value 'address' using write procedure */ /* Step 1.a+b - Write the address for read access into DBGDTRRXint */ /* Step 1.c - Copy value from DTR to R0 using instruction mrc DBGDTRTXint, r0 */ retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), address); } if (retval != ERROR_OK) return retval; if (size == 4 && (address % 4) == 0) retval = aarch64_read_cpu_memory_fast(target, count, buffer, &dscr); else retval = aarch64_read_cpu_memory_slow(target, size, count, buffer, &dscr); if (dscr & DSCR_MA) { dscr &= ~DSCR_MA; mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, dscr); } if (retval != ERROR_OK) return retval; /* Check for sticky abort flags in the DSCR */ retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; dpm->dscr = dscr; if (dscr & (DSCR_ERR | DSCR_SYS_ERROR_PEND)) { /* Abort occurred - clear it and exit */ LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr); armv8_dpm_handle_exception(dpm, true); return ERROR_FAIL; } /* Done */ return ERROR_OK; } static int aarch64_read_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval = ERROR_COMMAND_SYNTAX_ERROR; if (count && buffer) { /* read memory through APB-AP */ retval = aarch64_mmu_modify(target, 0); if (retval != ERROR_OK) return retval; retval = aarch64_read_cpu_memory(target, address, size, count, buffer); } return retval; } static int aarch64_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int mmu_enabled = 0; int retval; /* determine if MMU was enabled on target stop */ retval = aarch64_mmu(target, &mmu_enabled); if (retval != ERROR_OK) return retval; if (mmu_enabled) { /* enable MMU as we could have disabled it for phys access */ retval = aarch64_mmu_modify(target, 1); if (retval != ERROR_OK) return retval; } return aarch64_read_cpu_memory(target, address, size, count, buffer); } static int aarch64_write_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval = ERROR_COMMAND_SYNTAX_ERROR; if (count && buffer) { /* write memory through APB-AP */ retval = aarch64_mmu_modify(target, 0); if (retval != ERROR_OK) return retval; return aarch64_write_cpu_memory(target, address, size, count, buffer); } return retval; } static int aarch64_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int mmu_enabled = 0; int retval; /* determine if MMU was enabled on target stop */ retval = aarch64_mmu(target, &mmu_enabled); if (retval != ERROR_OK) return retval; if (mmu_enabled) { /* enable MMU as we could have disabled it for phys access */ retval = aarch64_mmu_modify(target, 1); if (retval != ERROR_OK) return retval; } return aarch64_write_cpu_memory(target, address, size, count, buffer); } static int aarch64_handle_target_request(void *priv) { struct target *target = priv; struct armv8_common *armv8 = target_to_armv8(target); int retval; if (!target_was_examined(target)) return ERROR_OK; if (!target->dbg_msg_enabled) return ERROR_OK; if (target->state == TARGET_RUNNING) { uint32_t request; uint32_t dscr; retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, &dscr); /* check if we have data */ while ((dscr & DSCR_DTR_TX_FULL) && (retval == ERROR_OK)) { retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DTRTX, &request); if (retval == ERROR_OK) { target_request(target, request); retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, &dscr); } } } return ERROR_OK; } static int aarch64_examine_first(struct target *target) { struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct adiv5_dap *swjdp = armv8->arm.dap; struct aarch64_private_config *pc = target->private_config; int i; int retval = ERROR_OK; uint64_t debug, ttypr; uint32_t cpuid; uint32_t tmp0, tmp1, tmp2, tmp3; debug = ttypr = cpuid = 0; if (!pc) return ERROR_FAIL; if (!armv8->debug_ap) { if (pc->adiv5_config.ap_num == DP_APSEL_INVALID) { /* Search for the APB-AB */ retval = dap_find_get_ap(swjdp, AP_TYPE_APB_AP, &armv8->debug_ap); if (retval != ERROR_OK) { LOG_ERROR("Could not find APB-AP for debug access"); return retval; } } else { armv8->debug_ap = dap_get_ap(swjdp, pc->adiv5_config.ap_num); if (!armv8->debug_ap) { LOG_ERROR("Cannot get AP"); return ERROR_FAIL; } } } retval = mem_ap_init(armv8->debug_ap); if (retval != ERROR_OK) { LOG_ERROR("Could not initialize the APB-AP"); return retval; } armv8->debug_ap->memaccess_tck = 10; if (!target->dbgbase_set) { /* Lookup Processor DAP */ retval = dap_lookup_cs_component(armv8->debug_ap, ARM_CS_C9_DEVTYPE_CORE_DEBUG, &armv8->debug_base, target->coreid); if (retval != ERROR_OK) return retval; LOG_DEBUG("Detected core %" PRId32 " dbgbase: " TARGET_ADDR_FMT, target->coreid, armv8->debug_base); } else armv8->debug_base = target->dbgbase; retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_OSLAR, 0); if (retval != ERROR_OK) { LOG_DEBUG("Examine %s failed", "oslock"); return retval; } retval = mem_ap_read_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_MAINID0, &cpuid); if (retval != ERROR_OK) { LOG_DEBUG("Examine %s failed", "CPUID"); return retval; } retval = mem_ap_read_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_MEMFEATURE0, &tmp0); retval += mem_ap_read_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_MEMFEATURE0 + 4, &tmp1); if (retval != ERROR_OK) { LOG_DEBUG("Examine %s failed", "Memory Model Type"); return retval; } retval = mem_ap_read_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DBGFEATURE0, &tmp2); retval += mem_ap_read_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DBGFEATURE0 + 4, &tmp3); if (retval != ERROR_OK) { LOG_DEBUG("Examine %s failed", "ID_AA64DFR0_EL1"); return retval; } retval = dap_run(armv8->debug_ap->dap); if (retval != ERROR_OK) { LOG_ERROR("%s: examination failed\n", target_name(target)); return retval; } ttypr |= tmp1; ttypr = (ttypr << 32) | tmp0; debug |= tmp3; debug = (debug << 32) | tmp2; LOG_DEBUG("cpuid = 0x%08" PRIx32, cpuid); LOG_DEBUG("ttypr = 0x%08" PRIx64, ttypr); LOG_DEBUG("debug = 0x%08" PRIx64, debug); if (!pc->cti) { LOG_TARGET_ERROR(target, "CTI not specified"); return ERROR_FAIL; } armv8->cti = pc->cti; retval = aarch64_dpm_setup(aarch64, debug); if (retval != ERROR_OK) return retval; /* Setup Breakpoint Register Pairs */ aarch64->brp_num = (uint32_t)((debug >> 12) & 0x0F) + 1; aarch64->brp_num_context = (uint32_t)((debug >> 28) & 0x0F) + 1; aarch64->brp_num_available = aarch64->brp_num; aarch64->brp_list = calloc(aarch64->brp_num, sizeof(struct aarch64_brp)); for (i = 0; i < aarch64->brp_num; i++) { aarch64->brp_list[i].used = 0; if (i < (aarch64->brp_num-aarch64->brp_num_context)) aarch64->brp_list[i].type = BRP_NORMAL; else aarch64->brp_list[i].type = BRP_CONTEXT; aarch64->brp_list[i].value = 0; aarch64->brp_list[i].control = 0; aarch64->brp_list[i].brpn = i; } /* Setup Watchpoint Register Pairs */ aarch64->wp_num = (uint32_t)((debug >> 20) & 0x0F) + 1; aarch64->wp_num_available = aarch64->wp_num; aarch64->wp_list = calloc(aarch64->wp_num, sizeof(struct aarch64_brp)); for (i = 0; i < aarch64->wp_num; i++) { aarch64->wp_list[i].used = 0; aarch64->wp_list[i].type = BRP_NORMAL; aarch64->wp_list[i].value = 0; aarch64->wp_list[i].control = 0; aarch64->wp_list[i].brpn = i; } LOG_DEBUG("Configured %i hw breakpoints, %i watchpoints", aarch64->brp_num, aarch64->wp_num); target->state = TARGET_UNKNOWN; target->debug_reason = DBG_REASON_NOTHALTED; aarch64->isrmasking_mode = AARCH64_ISRMASK_ON; target_set_examined(target); return ERROR_OK; } static int aarch64_examine(struct target *target) { int retval = ERROR_OK; /* don't re-probe hardware after each reset */ if (!target_was_examined(target)) retval = aarch64_examine_first(target); /* Configure core debug access */ if (retval == ERROR_OK) retval = aarch64_init_debug_access(target); return retval; } /* * Cortex-A8 target creation and initialization */ static int aarch64_init_target(struct command_context *cmd_ctx, struct target *target) { /* examine_first() does a bunch of this */ arm_semihosting_init(target); return ERROR_OK; } static int aarch64_init_arch_info(struct target *target, struct aarch64_common *aarch64, struct adiv5_dap *dap) { struct armv8_common *armv8 = &aarch64->armv8_common; /* Setup struct aarch64_common */ aarch64->common_magic = AARCH64_COMMON_MAGIC; armv8->arm.dap = dap; /* register arch-specific functions */ armv8->examine_debug_reason = NULL; armv8->post_debug_entry = aarch64_post_debug_entry; armv8->pre_restore_context = NULL; armv8->armv8_mmu.read_physical_memory = aarch64_read_phys_memory; armv8_init_arch_info(target, armv8); target_register_timer_callback(aarch64_handle_target_request, 1, TARGET_TIMER_TYPE_PERIODIC, target); return ERROR_OK; } static int armv8r_target_create(struct target *target, Jim_Interp *interp) { struct aarch64_private_config *pc = target->private_config; struct aarch64_common *aarch64; if (adiv5_verify_config(&pc->adiv5_config) != ERROR_OK) return ERROR_FAIL; aarch64 = calloc(1, sizeof(struct aarch64_common)); if (!aarch64) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } aarch64->armv8_common.is_armv8r = true; return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap); } static int aarch64_target_create(struct target *target, Jim_Interp *interp) { struct aarch64_private_config *pc = target->private_config; struct aarch64_common *aarch64; if (adiv5_verify_config(&pc->adiv5_config) != ERROR_OK) return ERROR_FAIL; aarch64 = calloc(1, sizeof(struct aarch64_common)); if (!aarch64) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } aarch64->armv8_common.is_armv8r = false; return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap); } static void aarch64_deinit_target(struct target *target) { struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct arm_dpm *dpm = &armv8->dpm; if (armv8->debug_ap) dap_put_ap(armv8->debug_ap); armv8_free_reg_cache(target); free(aarch64->brp_list); free(dpm->dbp); free(dpm->dwp); free(target->private_config); free(aarch64); } static int aarch64_mmu(struct target *target, int *enabled) { struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; if (target->state != TARGET_HALTED) { LOG_ERROR("%s: target %s not halted", __func__, target_name(target)); return ERROR_TARGET_INVALID; } if (armv8->is_armv8r) *enabled = 0; else *enabled = target_to_aarch64(target)->armv8_common.armv8_mmu.mmu_enabled; return ERROR_OK; } static int aarch64_virt2phys(struct target *target, target_addr_t virt, target_addr_t *phys) { return armv8_mmu_translate_va_pa(target, virt, phys, 1); } /* * private target configuration items */ enum aarch64_cfg_param { CFG_CTI, }; static const struct jim_nvp nvp_config_opts[] = { { .name = "-cti", .value = CFG_CTI }, { .name = NULL, .value = -1 } }; static int aarch64_jim_configure(struct target *target, struct jim_getopt_info *goi) { struct aarch64_private_config *pc; struct jim_nvp *n; int e; pc = (struct aarch64_private_config *)target->private_config; if (!pc) { pc = calloc(1, sizeof(struct aarch64_private_config)); pc->adiv5_config.ap_num = DP_APSEL_INVALID; target->private_config = pc; } /* * Call adiv5_jim_configure() to parse the common DAP options * It will return JIM_CONTINUE if it didn't find any known * options, JIM_OK if it correctly parsed the topmost option * and JIM_ERR if an error occurred during parameter evaluation. * For JIM_CONTINUE, we check our own params. * * adiv5_jim_configure() assumes 'private_config' to point to * 'struct adiv5_private_config'. Override 'private_config'! */ target->private_config = &pc->adiv5_config; e = adiv5_jim_configure(target, goi); target->private_config = pc; if (e != JIM_CONTINUE) return e; /* parse config or cget options ... */ if (goi->argc > 0) { Jim_SetEmptyResult(goi->interp); /* check first if topmost item is for us */ e = jim_nvp_name2value_obj(goi->interp, nvp_config_opts, goi->argv[0], &n); if (e != JIM_OK) return JIM_CONTINUE; e = jim_getopt_obj(goi, NULL); if (e != JIM_OK) return e; switch (n->value) { case CFG_CTI: { if (goi->isconfigure) { Jim_Obj *o_cti; struct arm_cti *cti; e = jim_getopt_obj(goi, &o_cti); if (e != JIM_OK) return e; cti = cti_instance_by_jim_obj(goi->interp, o_cti); if (!cti) { Jim_SetResultString(goi->interp, "CTI name invalid!", -1); return JIM_ERR; } pc->cti = cti; } else { if (goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); return JIM_ERR; } if (!pc || !pc->cti) { Jim_SetResultString(goi->interp, "CTI not configured", -1); return JIM_ERR; } Jim_SetResultString(goi->interp, arm_cti_name(pc->cti), -1); } break; } default: return JIM_CONTINUE; } } return JIM_OK; } COMMAND_HANDLER(aarch64_handle_cache_info_command) { struct target *target = get_current_target(CMD_CTX); struct armv8_common *armv8 = target_to_armv8(target); return armv8_handle_cache_info_command(CMD, &armv8->armv8_mmu.armv8_cache); } COMMAND_HANDLER(aarch64_handle_dbginit_command) { struct target *target = get_current_target(CMD_CTX); if (!target_was_examined(target)) { LOG_ERROR("target not examined yet"); return ERROR_FAIL; } return aarch64_init_debug_access(target); } COMMAND_HANDLER(aarch64_handle_disassemble_command) { struct target *target = get_current_target(CMD_CTX); if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } struct aarch64_common *aarch64 = target_to_aarch64(target); if (aarch64->common_magic != AARCH64_COMMON_MAGIC) { command_print(CMD, "current target isn't an AArch64"); return ERROR_FAIL; } int count = 1; target_addr_t address; switch (CMD_ARGC) { case 2: COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], count); /* FALL THROUGH */ case 1: COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return a64_disassemble(CMD, target, address, count); } COMMAND_HANDLER(aarch64_mask_interrupts_command) { struct target *target = get_current_target(CMD_CTX); struct aarch64_common *aarch64 = target_to_aarch64(target); static const struct nvp nvp_maskisr_modes[] = { { .name = "off", .value = AARCH64_ISRMASK_OFF }, { .name = "on", .value = AARCH64_ISRMASK_ON }, { .name = NULL, .value = -1 }, }; const struct nvp *n; if (CMD_ARGC > 0) { n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]); if (!n->name) { LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; } aarch64->isrmasking_mode = n->value; } n = nvp_value2name(nvp_maskisr_modes, aarch64->isrmasking_mode); command_print(CMD, "aarch64 interrupt mask %s", n->name); return ERROR_OK; } COMMAND_HANDLER(aarch64_mcrmrc_command) { bool is_mcr = false; unsigned int arg_cnt = 5; if (!strcmp(CMD_NAME, "mcr")) { is_mcr = true; arg_cnt = 6; } if (arg_cnt != CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); if (!target) { command_print(CMD, "no current target"); return ERROR_FAIL; } if (!target_was_examined(target)) { command_print(CMD, "%s: not yet examined", target_name(target)); return ERROR_TARGET_NOT_EXAMINED; } struct arm *arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "%s: not an ARM", target_name(target)); return ERROR_FAIL; } if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; if (arm->core_state == ARM_STATE_AARCH64) { command_print(CMD, "%s: not 32-bit arm target", target_name(target)); return ERROR_FAIL; } int cpnum; uint32_t op1; uint32_t op2; uint32_t crn; uint32_t crm; uint32_t value; /* NOTE: parameter sequence matches ARM instruction set usage: * MCR pNUM, op1, rX, CRn, CRm, op2 ; write CP from rX * MRC pNUM, op1, rX, CRn, CRm, op2 ; read CP into rX * The "rX" is necessarily omitted; it uses Tcl mechanisms. */ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cpnum); if (cpnum & ~0xf) { command_print(CMD, "coprocessor %d out of range", cpnum); return ERROR_COMMAND_ARGUMENT_INVALID; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], op1); if (op1 & ~0x7) { command_print(CMD, "op1 %d out of range", op1); return ERROR_COMMAND_ARGUMENT_INVALID; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], crn); if (crn & ~0xf) { command_print(CMD, "CRn %d out of range", crn); return ERROR_COMMAND_ARGUMENT_INVALID; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], crm); if (crm & ~0xf) { command_print(CMD, "CRm %d out of range", crm); return ERROR_COMMAND_ARGUMENT_INVALID; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], op2); if (op2 & ~0x7) { command_print(CMD, "op2 %d out of range", op2); return ERROR_COMMAND_ARGUMENT_INVALID; } if (is_mcr) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[5], value); /* NOTE: parameters reordered! */ /* ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2) */ int retval = arm->mcr(target, cpnum, op1, op2, crn, crm, value); if (retval != ERROR_OK) return retval; } else { value = 0; /* NOTE: parameters reordered! */ /* ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2) */ int retval = arm->mrc(target, cpnum, op1, op2, crn, crm, &value); if (retval != ERROR_OK) return retval; command_print(CMD, "0x%" PRIx32, value); } return ERROR_OK; } static const struct command_registration aarch64_exec_command_handlers[] = { { .name = "cache_info", .handler = aarch64_handle_cache_info_command, .mode = COMMAND_EXEC, .help = "display information about target caches", .usage = "", }, { .name = "dbginit", .handler = aarch64_handle_dbginit_command, .mode = COMMAND_EXEC, .help = "Initialize core debug", .usage = "", }, { .name = "disassemble", .handler = aarch64_handle_disassemble_command, .mode = COMMAND_EXEC, .help = "Disassemble instructions", .usage = "address [count]", }, { .name = "maskisr", .handler = aarch64_mask_interrupts_command, .mode = COMMAND_ANY, .help = "mask aarch64 interrupts during single-step", .usage = "['on'|'off']", }, { .name = "mcr", .mode = COMMAND_EXEC, .handler = aarch64_mcrmrc_command, .help = "write coprocessor register", .usage = "cpnum op1 CRn CRm op2 value", }, { .name = "mrc", .mode = COMMAND_EXEC, .handler = aarch64_mcrmrc_command, .help = "read coprocessor register", .usage = "cpnum op1 CRn CRm op2", }, { .chain = smp_command_handlers, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration aarch64_command_handlers[] = { { .name = "arm", .mode = COMMAND_ANY, .help = "ARM Command Group", .usage = "", .chain = semihosting_common_handlers }, { .chain = armv8_command_handlers, }, { .name = "aarch64", .mode = COMMAND_ANY, .help = "Aarch64 command group", .usage = "", .chain = aarch64_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type aarch64_target = { .name = "aarch64", .poll = aarch64_poll, .arch_state = armv8_arch_state, .halt = aarch64_halt, .resume = aarch64_resume, .step = aarch64_step, .assert_reset = aarch64_assert_reset, .deassert_reset = aarch64_deassert_reset, /* REVISIT allow exporting VFP3 registers ... */ .get_gdb_arch = armv8_get_gdb_arch, .get_gdb_reg_list = armv8_get_gdb_reg_list, .read_memory = aarch64_read_memory, .write_memory = aarch64_write_memory, .add_breakpoint = aarch64_add_breakpoint, .add_context_breakpoint = aarch64_add_context_breakpoint, .add_hybrid_breakpoint = aarch64_add_hybrid_breakpoint, .remove_breakpoint = aarch64_remove_breakpoint, .add_watchpoint = aarch64_add_watchpoint, .remove_watchpoint = aarch64_remove_watchpoint, .hit_watchpoint = aarch64_hit_watchpoint, .commands = aarch64_command_handlers, .target_create = aarch64_target_create, .target_jim_configure = aarch64_jim_configure, .init_target = aarch64_init_target, .deinit_target = aarch64_deinit_target, .examine = aarch64_examine, .read_phys_memory = aarch64_read_phys_memory, .write_phys_memory = aarch64_write_phys_memory, .mmu = aarch64_mmu, .virt2phys = aarch64_virt2phys, }; struct target_type armv8r_target = { .name = "armv8r", .poll = aarch64_poll, .arch_state = armv8_arch_state, .halt = aarch64_halt, .resume = aarch64_resume, .step = aarch64_step, .assert_reset = aarch64_assert_reset, .deassert_reset = aarch64_deassert_reset, /* REVISIT allow exporting VFP3 registers ... */ .get_gdb_arch = armv8_get_gdb_arch, .get_gdb_reg_list = armv8_get_gdb_reg_list, .read_memory = aarch64_read_phys_memory, .write_memory = aarch64_write_phys_memory, .add_breakpoint = aarch64_add_breakpoint, .add_context_breakpoint = aarch64_add_context_breakpoint, .add_hybrid_breakpoint = aarch64_add_hybrid_breakpoint, .remove_breakpoint = aarch64_remove_breakpoint, .add_watchpoint = aarch64_add_watchpoint, .remove_watchpoint = aarch64_remove_watchpoint, .hit_watchpoint = aarch64_hit_watchpoint, .commands = aarch64_command_handlers, .target_create = armv8r_target_create, .target_jim_configure = aarch64_jim_configure, .init_target = aarch64_init_target, .deinit_target = aarch64_deinit_target, .examine = aarch64_examine, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/aarch64.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2015 by David Ung * ***************************************************************************/ #ifndef OPENOCD_TARGET_AARCH64_H #define OPENOCD_TARGET_AARCH64_H #include "armv8.h" #define AARCH64_COMMON_MAGIC 0x41413634U #define CPUDBG_CPUID 0xD00 #define CPUDBG_CTYPR 0xD04 #define CPUDBG_TTYPR 0xD0C #define ID_AA64PFR0_EL1 0xD20 #define ID_AA64DFR0_EL1 0xD28 #define CPUDBG_LOCKACCESS 0xFB0 #define CPUDBG_LOCKSTATUS 0xFB4 #define BRP_NORMAL 0 #define BRP_CONTEXT 1 #define AARCH64_PADDRDBG_CPU_SHIFT 13 enum aarch64_isrmasking_mode { AARCH64_ISRMASK_OFF, AARCH64_ISRMASK_ON, }; struct aarch64_brp { int used; int type; target_addr_t value; uint32_t control; uint8_t brpn; }; struct aarch64_common { unsigned int common_magic; struct armv8_common armv8_common; /* Context information */ uint32_t system_control_reg; uint32_t system_control_reg_curr; /* Breakpoint register pairs */ int brp_num_context; int brp_num; int brp_num_available; struct aarch64_brp *brp_list; /* Watchpoint register pairs */ int wp_num; int wp_num_available; struct aarch64_brp *wp_list; enum aarch64_isrmasking_mode isrmasking_mode; }; static inline struct aarch64_common * target_to_aarch64(struct target *target) { return container_of(target->arch_info, struct aarch64_common, armv8_common.arm); } #endif /* OPENOCD_TARGET_AARCH64_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/adi_v5_dapdirect.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2019, STMicroelectronics - All Rights Reserved * Author(s): Antonio Borneo <borneo.antonio@gmail.com> for STMicroelectronics */ /** * @file * Utilities to support in-circuit debuggers that provide APIs to access * directly ARM DAP, hiding the access to the underlining transport used * for the physical connection (either JTAG or SWD). * E.g. STMicroelectronics ST-Link/V2 (from version V2J24) and STLINK-V3. * * Single-DAP support only. * * For details, see "ARM IHI 0031A" * ARM Debug Interface v5 Architecture Specification * * FIXME: in JTAG mode, trst is not managed */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/interface.h> #include <jtag/tcl.h> #include <transport/transport.h> COMMAND_HANDLER(dapdirect_jtag_empty_command) { LOG_DEBUG("dapdirect_jtag_empty_command(\"%s\")", CMD_NAME); return ERROR_OK; } COMMAND_HANDLER(dapdirect_jtag_reset_command) { enum reset_types jtag_reset_config = jtag_get_reset_config(); /* * in case the adapter has not already handled asserting srst * we will attempt it again */ if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) { adapter_assert_reset(); return ERROR_OK; } LOG_WARNING("\'srst_nogate\' reset_config option is required"); } adapter_deassert_reset(); return ERROR_OK; } static const struct command_registration dapdirect_jtag_subcommand_handlers[] = { { .name = "newtap", .mode = COMMAND_CONFIG, .handler = handle_jtag_newtap, .help = "declare a new TAP", .usage = "basename tap_type '-irlen' count " "['-enable'|'-disable'] " "['-expected_id' number] " "['-ignore-version'] " "['-ignore-bypass'] " "['-ircapture' number] " "['-mask' number]", }, { .name = "init", .mode = COMMAND_ANY, .handler = dapdirect_jtag_empty_command, .usage = "" }, { .name = "arp_init", .mode = COMMAND_ANY, .handler = dapdirect_jtag_empty_command, .usage = "" }, { .name = "arp_init-reset", .mode = COMMAND_ANY, .handler = dapdirect_jtag_reset_command, .usage = "" }, { .name = "tapisenabled", .mode = COMMAND_EXEC, .handler = handle_jtag_tap_enabler, .help = "Returns a Tcl boolean (0/1) indicating whether " "the TAP is enabled (1) or not (0).", .usage = "tap_name", }, { .name = "tapenable", .mode = COMMAND_EXEC, .handler = handle_jtag_tap_enabler, .help = "Try to enable the specified TAP using the " "'tap-enable' TAP event.", .usage = "tap_name", }, { .name = "tapdisable", .mode = COMMAND_EXEC, .handler = dapdirect_jtag_empty_command, .usage = "", }, { .name = "configure", .mode = COMMAND_ANY, .handler = dapdirect_jtag_empty_command, .usage = "", }, { .name = "cget", .mode = COMMAND_EXEC, .jim_handler = jim_jtag_configure, }, { .name = "names", .mode = COMMAND_ANY, .handler = dapdirect_jtag_empty_command, .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration dapdirect_jtag_handlers[] = { { .name = "jtag", .mode = COMMAND_ANY, .chain = dapdirect_jtag_subcommand_handlers, .usage = "", }, { .name = "jtag_ntrst_delay", .mode = COMMAND_ANY, .handler = dapdirect_jtag_empty_command, .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration dapdirect_swd_subcommand_handlers[] = { { .name = "newdap", .mode = COMMAND_CONFIG, .handler = handle_jtag_newtap, .help = "declare a new SWD DAP", .usage = "basename dap_type ['-irlen' count] " "['-enable'|'-disable'] " "['-expected_id' number] " "['-ignore-version'] " "['-ignore-bypass'] " "['-ircapture' number] " "['-mask' number]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration dapdirect_swd_handlers[] = { { .name = "swd", .mode = COMMAND_ANY, .help = "SWD command group", .usage = "", .chain = dapdirect_swd_subcommand_handlers, }, COMMAND_REGISTRATION_DONE }; static int dapdirect_jtag_select(struct command_context *ctx) { LOG_DEBUG("dapdirect_jtag_select()"); return register_commands(ctx, NULL, dapdirect_jtag_handlers); } static int dapdirect_swd_select(struct command_context *ctx) { LOG_DEBUG("dapdirect_swd_select()"); return register_commands(ctx, NULL, dapdirect_swd_handlers); } static int dapdirect_init(struct command_context *ctx) { enum reset_types jtag_reset_config = jtag_get_reset_config(); LOG_DEBUG("dapdirect_init()"); if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) adapter_assert_reset(); else LOG_WARNING("\'srst_nogate\' reset_config option is required"); } else adapter_deassert_reset(); return ERROR_OK; } static struct transport dapdirect_jtag_transport = { .name = "dapdirect_jtag", .select = dapdirect_jtag_select, .init = dapdirect_init, }; static struct transport dapdirect_swd_transport = { .name = "dapdirect_swd", .select = dapdirect_swd_select, .init = dapdirect_init, }; static void dapdirect_constructor(void) __attribute__((constructor)); static void dapdirect_constructor(void) { transport_register(&dapdirect_jtag_transport); transport_register(&dapdirect_swd_transport); } /** * Returns true if the current debug session * is using JTAG as its transport. */ bool transport_is_dapdirect_jtag(void) { return get_current_transport() == &dapdirect_jtag_transport; } /** * Returns true if the current debug session * is using SWD as its transport. */ bool transport_is_dapdirect_swd(void) { return get_current_transport() == &dapdirect_swd_transport; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/adi_v5_jtag.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * lundin@mlu.mine.nu * * Copyright (C) 2008 by Spencer Oliver * spen@spen-soft.co.uk * * Copyright (C) 2009 by Oyvind Harboe * oyvind.harboe@zylin.com * * Copyright (C) 2009-2010 by David Brownell * * Copyright (C) 2020-2021, Ampere Computing LLC * ***************************************************************************/ /** * @file * This file implements JTAG transport support for cores implementing the ARM Debug Interface version 5 (ADIv5) and version 6 (ADIv6). */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "arm_adi_v5.h" #include <helper/time_support.h> #include <helper/list.h> #include <jtag/swd.h> /*#define DEBUG_WAIT*/ /* JTAG instructions/registers for JTAG-DP and SWJ-DP */ #define JTAG_DP_ABORT 0xF8 #define JTAG_DP_DPACC 0xFA #define JTAG_DP_APACC 0xFB #define JTAG_DP_IDCODE 0xFE /* three-bit ACK values for DPACC and APACC reads */ #define JTAG_ACK_WAIT 0x1 /* ADIv5 and ADIv6 */ #define JTAG_ACK_OK_FAULT 0x2 /* ADIv5 */ #define JTAG_ACK_FAULT 0x2 /* ADIv6 */ #define JTAG_ACK_OK 0x4 /* ADIV6 */ static int jtag_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack); #ifdef DEBUG_WAIT static const char *dap_reg_name(struct adiv5_dap *dap, uint8_t instr, uint16_t reg_addr) { char *reg_name = "UNK"; if (instr == JTAG_DP_DPACC) { switch (reg_addr) { case DP_ABORT: reg_name = "ABORT"; break; case DP_CTRL_STAT: reg_name = "CTRL/STAT"; break; case DP_SELECT: reg_name = "SELECT"; break; case DP_RDBUFF: reg_name = "RDBUFF"; break; case DP_DLCR: reg_name = "DLCR"; break; default: reg_name = "UNK"; break; } } if (instr == JTAG_DP_APACC) { if (reg_addr == MEM_AP_REG_CSW(dap)) reg_name = "CSW"; else if (reg_addr == MEM_AP_REG_TAR(dap)) reg_name = "TAR"; else if (reg_addr == MEM_AP_REG_TAR64(dap)) reg_name = "TAR64"; else if (reg_addr == MEM_AP_REG_DRW(dap)) reg_name = "DRW"; else if (reg_addr == MEM_AP_REG_BD0(dap)) reg_name = "BD0"; else if (reg_addr == MEM_AP_REG_BD1(dap)) reg_name = "BD1"; else if (reg_addr == MEM_AP_REG_BD2(dap)) reg_name = "BD2"; else if (reg_addr == MEM_AP_REG_BD3(dap)) reg_name = "BD3"; else if (reg_addr == MEM_AP_REG_CFG(dap)) reg_name = "CFG"; else if (reg_addr == MEM_AP_REG_BASE(dap)) reg_name = "BASE"; else if (reg_addr == MEM_AP_REG_BASE64(dap)) reg_name = "BASE64"; else if (reg_addr == AP_REG_IDR(dap)) reg_name = "IDR"; else reg_name = "UNK"; } return reg_name; } #endif struct dap_cmd { struct list_head lh; uint8_t instr; uint16_t reg_addr; uint8_t rnw; uint8_t *invalue; uint8_t ack; uint32_t memaccess_tck; uint64_t dp_select; struct scan_field fields[2]; uint8_t out_addr_buf; uint8_t invalue_buf[4]; uint8_t outvalue_buf[4]; }; #define MAX_DAP_COMMAND_NUM 65536 struct dap_cmd_pool { struct list_head lh; struct dap_cmd cmd; }; static void log_dap_cmd(struct adiv5_dap *dap, const char *header, struct dap_cmd *el) { #ifdef DEBUG_WAIT const char *ack; switch (el->ack) { case JTAG_ACK_WAIT: /* ADIv5 and ADIv6 */ ack = "WAIT"; break; case JTAG_ACK_OK_FAULT: /* ADIv5, same value as JTAG_ACK_FAULT */ /* case JTAG_ACK_FAULT: */ /* ADIv6 */ if (is_adiv6(dap)) ack = "FAULT"; else ack = "OK"; break; case JTAG_ACK_OK: /* ADIv6 */ if (is_adiv6(dap)) { ack = "OK"; break; } /* fall-through */ default: ack = "INVAL"; break; } LOG_DEBUG("%s: %2s %6s %5s 0x%08x 0x%08x %2s", header, el->instr == JTAG_DP_APACC ? "AP" : "DP", dap_reg_name(dap, el->instr, el->reg_addr), el->rnw == DPAP_READ ? "READ" : "WRITE", buf_get_u32(el->outvalue_buf, 0, 32), buf_get_u32(el->invalue, 0, 32), ack); #endif } static int jtag_limit_queue_size(struct adiv5_dap *dap) { if (dap->cmd_pool_size < MAX_DAP_COMMAND_NUM) return ERROR_OK; return dap_run(dap); } static struct dap_cmd *dap_cmd_new(struct adiv5_dap *dap, uint8_t instr, uint16_t reg_addr, uint8_t rnw, uint8_t *outvalue, uint8_t *invalue, uint32_t memaccess_tck) { struct dap_cmd_pool *pool = NULL; if (list_empty(&dap->cmd_pool)) { pool = calloc(1, sizeof(struct dap_cmd_pool)); if (!pool) return NULL; } else { pool = list_first_entry(&dap->cmd_pool, struct dap_cmd_pool, lh); list_del(&pool->lh); } INIT_LIST_HEAD(&pool->lh); dap->cmd_pool_size++; struct dap_cmd *cmd = &pool->cmd; INIT_LIST_HEAD(&cmd->lh); cmd->instr = instr; cmd->reg_addr = reg_addr; cmd->rnw = rnw; if (outvalue) memcpy(cmd->outvalue_buf, outvalue, 4); cmd->invalue = (invalue) ? invalue : cmd->invalue_buf; cmd->memaccess_tck = memaccess_tck; return cmd; } static void dap_cmd_release(struct adiv5_dap *dap, struct dap_cmd *cmd) { struct dap_cmd_pool *pool = container_of(cmd, struct dap_cmd_pool, cmd); if (dap->cmd_pool_size > MAX_DAP_COMMAND_NUM) free(pool); else list_add(&pool->lh, &dap->cmd_pool); dap->cmd_pool_size--; } static void flush_journal(struct adiv5_dap *dap, struct list_head *lh) { struct dap_cmd *el, *tmp; list_for_each_entry_safe(el, tmp, lh, lh) { list_del(&el->lh); dap_cmd_release(dap, el); } } static void jtag_quit(struct adiv5_dap *dap) { struct dap_cmd_pool *el, *tmp; struct list_head *lh = &dap->cmd_pool; list_for_each_entry_safe(el, tmp, lh, lh) { list_del(&el->lh); free(el); } } /*************************************************************************** * * DPACC and APACC scanchain access through JTAG-DP (or SWJ-DP) * ***************************************************************************/ static int adi_jtag_dp_scan_cmd(struct adiv5_dap *dap, struct dap_cmd *cmd, uint8_t *ack) { struct jtag_tap *tap = dap->tap; int retval; retval = arm_jtag_set_instr(tap, cmd->instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; /* Scan out a read or write operation using some DP or AP register. * For APACC access with any sticky error flag set, this is discarded. */ cmd->fields[0].num_bits = 3; buf_set_u32(&cmd->out_addr_buf, 0, 3, ((cmd->reg_addr >> 1) & 0x6) | (cmd->rnw & 0x1)); cmd->fields[0].out_value = &cmd->out_addr_buf; cmd->fields[0].in_value = (ack) ? ack : &cmd->ack; /* NOTE: if we receive JTAG_ACK_WAIT, the previous operation did not * complete; data we write is discarded, data we read is unpredictable. * When overrun detect is active, STICKYORUN is set. */ cmd->fields[1].num_bits = 32; cmd->fields[1].out_value = cmd->outvalue_buf; cmd->fields[1].in_value = cmd->invalue; jtag_add_dr_scan(tap, 2, cmd->fields, TAP_IDLE); /* Add specified number of tck clocks after starting AP register * access or memory bus access, giving the hardware time to complete * the access. * They provide more time for the (MEM) AP to complete the read ... * See "Minimum Response Time" for JTAG-DP, in the ADIv5/ADIv6 spec. */ if (cmd->instr == JTAG_DP_APACC && cmd->memaccess_tck != 0) jtag_add_runtest(cmd->memaccess_tck, TAP_IDLE); return ERROR_OK; } static int adi_jtag_dp_scan_cmd_sync(struct adiv5_dap *dap, struct dap_cmd *cmd, uint8_t *ack) { int retval; retval = adi_jtag_dp_scan_cmd(dap, cmd, ack); if (retval != ERROR_OK) return retval; return jtag_execute_queue(); } /** * Scan DPACC or APACC using target ordered uint8_t buffers. No endianness * conversions are performed. See section 4.4.3 of the ADIv5/ADIv6 spec, which * discusses operations which access these registers. * * Note that only one scan is performed. If rnw is set, a separate scan * will be needed to collect the data which was read; the "invalue" collects * the posted result of a preceding operation, not the current one. * * @param dap the DAP * @param instr JTAG_DP_APACC (AP access) or JTAG_DP_DPACC (DP access) * @param reg_addr two significant bits; A[3:2]; for APACC access, the * SELECT register has more addressing bits. * @param rnw false iff outvalue will be written to the DP or AP * @param outvalue points to a 32-bit (little-endian) integer * @param invalue NULL, or points to a 32-bit (little-endian) integer * @param ack points to where the three bit JTAG_ACK_* code will be stored * @param memaccess_tck number of idle cycles to add after AP access */ static int adi_jtag_dp_scan(struct adiv5_dap *dap, uint8_t instr, uint16_t reg_addr, uint8_t rnw, uint8_t *outvalue, uint8_t *invalue, uint32_t memaccess_tck, uint8_t *ack) { struct dap_cmd *cmd; int retval; cmd = dap_cmd_new(dap, instr, reg_addr, rnw, outvalue, invalue, memaccess_tck); if (cmd) cmd->dp_select = dap->select; else return ERROR_JTAG_DEVICE_ERROR; retval = adi_jtag_dp_scan_cmd(dap, cmd, ack); if (retval == ERROR_OK) list_add_tail(&cmd->lh, &dap->cmd_journal); return retval; } /** * Scan DPACC or APACC out and in from host ordered uint32_t buffers. * This is exactly like adi_jtag_dp_scan(), except that endianness * conversions are performed (so the types of invalue and outvalue * must be different). */ static int adi_jtag_dp_scan_u32(struct adiv5_dap *dap, uint8_t instr, uint16_t reg_addr, uint8_t rnw, uint32_t outvalue, uint32_t *invalue, uint32_t memaccess_tck, uint8_t *ack) { uint8_t out_value_buf[4]; int retval; uint64_t sel = (reg_addr >> 4) & 0xf; /* No need to change SELECT or RDBUFF as they are not banked */ if (instr == JTAG_DP_DPACC && reg_addr != DP_SELECT && reg_addr != DP_RDBUFF && sel != (dap->select & 0xf)) { if (dap->select != DP_SELECT_INVALID) sel |= dap->select & ~0xfull; dap->select = sel; LOG_DEBUG("DP BANKSEL: %x", (uint32_t)sel); buf_set_u32(out_value_buf, 0, 32, (uint32_t)sel); retval = adi_jtag_dp_scan(dap, JTAG_DP_DPACC, DP_SELECT, DPAP_WRITE, out_value_buf, NULL, 0, NULL); if (retval != ERROR_OK) return retval; } buf_set_u32(out_value_buf, 0, 32, outvalue); retval = adi_jtag_dp_scan(dap, instr, reg_addr, rnw, out_value_buf, (uint8_t *)invalue, memaccess_tck, ack); if (retval != ERROR_OK) return retval; if (invalue) jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t) invalue); return retval; } static int adi_jtag_finish_read(struct adiv5_dap *dap) { int retval = ERROR_OK; if (dap->last_read) { retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, DP_RDBUFF, DPAP_READ, 0, dap->last_read, 0, NULL); dap->last_read = NULL; } return retval; } static int adi_jtag_scan_inout_check_u32(struct adiv5_dap *dap, uint8_t instr, uint16_t reg_addr, uint8_t rnw, uint32_t outvalue, uint32_t *invalue, uint32_t memaccess_tck) { int retval; /* Issue the read or write */ retval = adi_jtag_dp_scan_u32(dap, instr, reg_addr, rnw, outvalue, NULL, memaccess_tck, NULL); if (retval != ERROR_OK) return retval; /* For reads, collect posted value; RDBUFF has no other effect. * Assumes read gets acked with OK/FAULT, and CTRL_STAT says "OK". */ if ((rnw == DPAP_READ) && (invalue)) { retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, DP_RDBUFF, DPAP_READ, 0, invalue, 0, NULL); if (retval != ERROR_OK) return retval; } return jtag_execute_queue(); } static int jtagdp_overrun_check(struct adiv5_dap *dap) { int retval; struct dap_cmd *el, *tmp, *prev = NULL; int found_wait = 0; int64_t time_now; LIST_HEAD(replay_list); /* make sure all queued transactions are complete */ retval = jtag_execute_queue(); if (retval != ERROR_OK) goto done; /* skip all completed transactions up to the first WAIT */ list_for_each_entry(el, &dap->cmd_journal, lh) { /* * JTAG_ACK_OK_FAULT (ADIv5) and JTAG_ACK_FAULT (ADIv6) are equal so * the following statement is checking to see if an acknowledgment of * OK or FAULT is generated for ADIv5 or ADIv6 */ if (el->ack == JTAG_ACK_OK_FAULT || (is_adiv6(dap) && el->ack == JTAG_ACK_OK)) { log_dap_cmd(dap, "LOG", el); } else if (el->ack == JTAG_ACK_WAIT) { found_wait = 1; break; } else { LOG_ERROR("Invalid ACK (%1x) in DAP response", el->ack); log_dap_cmd(dap, "ERR", el); retval = ERROR_JTAG_DEVICE_ERROR; goto done; } } /* * If we found a stalled transaction and a previous transaction * exists, check if it's a READ access. */ if (found_wait && el != list_first_entry(&dap->cmd_journal, struct dap_cmd, lh)) { prev = list_entry(el->lh.prev, struct dap_cmd, lh); if (prev->rnw == DPAP_READ) { log_dap_cmd(dap, "PND", prev); /* search for the next OK transaction, it contains * the result of the previous READ */ tmp = el; list_for_each_entry_from(tmp, &dap->cmd_journal, lh) { /* The following check covers OK and FAULT ACKs for both ADIv5 and ADIv6 */ if (tmp->ack == JTAG_ACK_OK_FAULT || (is_adiv6(dap) && tmp->ack == JTAG_ACK_OK)) { /* recover the read value */ log_dap_cmd(dap, "FND", tmp); if (el->invalue != el->invalue_buf) { uint32_t invalue = le_to_h_u32(tmp->invalue); memcpy(el->invalue, &invalue, sizeof(uint32_t)); } prev = NULL; break; } } if (prev) { log_dap_cmd(dap, "LST", el); /* * At this point we're sure that no previous * transaction completed and the DAP/AP is still * in busy state. We know that the next "OK" scan * will return the READ result we need to recover. * To complete the READ, we just keep polling RDBUFF * until the WAIT condition clears */ tmp = dap_cmd_new(dap, JTAG_DP_DPACC, DP_RDBUFF, DPAP_READ, NULL, NULL, 0); if (!tmp) { retval = ERROR_JTAG_DEVICE_ERROR; goto done; } /* synchronously retry the command until it succeeds */ time_now = timeval_ms(); do { retval = adi_jtag_dp_scan_cmd_sync(dap, tmp, NULL); if (retval != ERROR_OK) break; /* The following check covers OK and FAULT ACKs for both ADIv5 and ADIv6 */ if (tmp->ack == JTAG_ACK_OK_FAULT || (is_adiv6(dap) && tmp->ack == JTAG_ACK_OK)) { log_dap_cmd(dap, "FND", tmp); if (el->invalue != el->invalue_buf) { uint32_t invalue = le_to_h_u32(tmp->invalue); memcpy(el->invalue, &invalue, sizeof(uint32_t)); } break; } if (tmp->ack != JTAG_ACK_WAIT) { LOG_ERROR("Invalid ACK (%1x) in DAP response", tmp->ack); log_dap_cmd(dap, "ERR", tmp); retval = ERROR_JTAG_DEVICE_ERROR; break; } } while (timeval_ms() - time_now < 1000); if (retval == ERROR_OK) { /* timeout happened */ if (tmp->ack == JTAG_ACK_WAIT) { LOG_ERROR("Timeout during WAIT recovery"); dap->select = DP_SELECT_INVALID; jtag_ap_q_abort(dap, NULL); /* clear the sticky overrun condition */ adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, DP_CTRL_STAT, DPAP_WRITE, dap->dp_ctrl_stat | SSTICKYORUN, NULL, 0); retval = ERROR_JTAG_DEVICE_ERROR; } } /* we're done with this command, release it */ dap_cmd_release(dap, tmp); if (retval != ERROR_OK) goto done; } /* make el->invalue point to the default invalue * so that we can safely retry it without clobbering * the result we just recovered */ el->invalue = el->invalue_buf; } } /* move all remaining transactions over to the replay list */ list_for_each_entry_safe_from(el, tmp, &dap->cmd_journal, lh) { log_dap_cmd(dap, "REP", el); list_move_tail(&el->lh, &replay_list); } /* we're done with the journal, flush it */ flush_journal(dap, &dap->cmd_journal); /* check for overrun condition in the last batch of transactions */ if (found_wait) { LOG_INFO("DAP transaction stalled (WAIT) - slowing down and resending"); /* clear the sticky overrun condition */ retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, DP_CTRL_STAT, DPAP_WRITE, dap->dp_ctrl_stat | SSTICKYORUN, NULL, 0); if (retval != ERROR_OK) goto done; /* restore SELECT register first */ if (!list_empty(&replay_list)) { el = list_first_entry(&replay_list, struct dap_cmd, lh); uint8_t out_value_buf[4]; buf_set_u32(out_value_buf, 0, 32, (uint32_t)(el->dp_select)); tmp = dap_cmd_new(dap, JTAG_DP_DPACC, DP_SELECT, DPAP_WRITE, out_value_buf, NULL, 0); if (!tmp) { retval = ERROR_JTAG_DEVICE_ERROR; goto done; } list_add(&tmp->lh, &replay_list); /* TODO: ADIv6 DP SELECT1 handling */ dap->select = DP_SELECT_INVALID; } list_for_each_entry_safe(el, tmp, &replay_list, lh) { time_now = timeval_ms(); do { retval = adi_jtag_dp_scan_cmd_sync(dap, el, NULL); if (retval != ERROR_OK) break; log_dap_cmd(dap, "REC", el); if (el->ack == JTAG_ACK_OK_FAULT || (is_adiv6(dap) && el->ack == JTAG_ACK_OK)) { if (el->invalue != el->invalue_buf) { uint32_t invalue = le_to_h_u32(el->invalue); memcpy(el->invalue, &invalue, sizeof(uint32_t)); } break; } if (el->ack != JTAG_ACK_WAIT) { LOG_ERROR("Invalid ACK (%1x) in DAP response", el->ack); log_dap_cmd(dap, "ERR", el); retval = ERROR_JTAG_DEVICE_ERROR; break; } LOG_DEBUG("DAP transaction stalled during replay (WAIT) - resending"); /* clear the sticky overrun condition */ retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, DP_CTRL_STAT, DPAP_WRITE, dap->dp_ctrl_stat | SSTICKYORUN, NULL, 0); if (retval != ERROR_OK) break; } while (timeval_ms() - time_now < 1000); if (retval == ERROR_OK) { if (el->ack == JTAG_ACK_WAIT) { LOG_ERROR("Timeout during WAIT recovery"); dap->select = DP_SELECT_INVALID; jtag_ap_q_abort(dap, NULL); /* clear the sticky overrun condition */ adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, DP_CTRL_STAT, DPAP_WRITE, dap->dp_ctrl_stat | SSTICKYORUN, NULL, 0); retval = ERROR_JTAG_DEVICE_ERROR; break; } } else break; } } done: flush_journal(dap, &replay_list); flush_journal(dap, &dap->cmd_journal); return retval; } static int jtagdp_transaction_endcheck(struct adiv5_dap *dap) { int retval; uint32_t ctrlstat, pwrmask; /* too expensive to call keep_alive() here */ /* Post CTRL/STAT read; discard any previous posted read value * but collect its ACK status. */ retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat, 0); if (retval != ERROR_OK) goto done; /* REVISIT also STICKYCMP, for pushed comparisons (nyet used) */ /* Check for STICKYERR */ if (ctrlstat & SSTICKYERR) { LOG_DEBUG("jtag-dp: CTRL/STAT 0x%" PRIx32, ctrlstat); /* Check power to debug regions */ pwrmask = CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ; if (!dap->ignore_syspwrupack) pwrmask |= CSYSPWRUPACK; if ((ctrlstat & pwrmask) != pwrmask) { LOG_ERROR("Debug regions are unpowered, an unexpected reset might have happened"); dap->do_reconnect = true; } if (ctrlstat & SSTICKYERR) LOG_ERROR("JTAG-DP STICKY ERROR"); if (ctrlstat & SSTICKYORUN) LOG_DEBUG("JTAG-DP STICKY OVERRUN"); /* Clear Sticky Error and Sticky Overrun Bits */ retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, DP_CTRL_STAT, DPAP_WRITE, dap->dp_ctrl_stat | SSTICKYERR | SSTICKYORUN, NULL, 0); if (retval != ERROR_OK) goto done; retval = ERROR_JTAG_DEVICE_ERROR; } done: flush_journal(dap, &dap->cmd_journal); return retval; } /*--------------------------------------------------------------------------*/ static int jtag_connect(struct adiv5_dap *dap) { dap->do_reconnect = false; return dap_dp_init(dap); } static int jtag_check_reconnect(struct adiv5_dap *dap) { if (dap->do_reconnect) return jtag_connect(dap); return ERROR_OK; } static int jtag_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq) { int retval; switch (seq) { case JTAG_TO_SWD: retval = jtag_add_tms_seq(swd_seq_jtag_to_swd_len, swd_seq_jtag_to_swd, TAP_INVALID); break; case SWD_TO_JTAG: retval = jtag_add_tms_seq(swd_seq_swd_to_jtag_len, swd_seq_swd_to_jtag, TAP_RESET); break; default: LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; } if (retval == ERROR_OK) retval = jtag_execute_queue(); return retval; } static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { int retval = jtag_limit_queue_size(dap); if (retval != ERROR_OK) return retval; retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, reg, DPAP_READ, 0, dap->last_read, 0, NULL); dap->last_read = data; return retval; } static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { int retval = jtag_limit_queue_size(dap); if (retval != ERROR_OK) return retval; retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, reg, DPAP_WRITE, data, dap->last_read, 0, NULL); dap->last_read = NULL; return retval; } /** Select the AP register bank matching bits 7:4 of reg. */ static int jtag_ap_q_bankselect(struct adiv5_ap *ap, unsigned reg) { int retval; struct adiv5_dap *dap = ap->dap; uint64_t sel; if (is_adiv6(dap)) { sel = ap->ap_num | (reg & 0x00000FF0); if (sel == (dap->select & ~0xfull)) return ERROR_OK; if (dap->select != DP_SELECT_INVALID) sel |= dap->select & 0xf; dap->select = sel; LOG_DEBUG("AP BANKSEL: %" PRIx64, sel); retval = jtag_dp_q_write(dap, DP_SELECT, (uint32_t)sel); if (retval != ERROR_OK) return retval; if (dap->asize > 32) return jtag_dp_q_write(dap, DP_SELECT1, (uint32_t)(sel >> 32)); return ERROR_OK; } /* ADIv5 */ sel = (ap->ap_num << 24) | (reg & 0x000000F0); if (sel == dap->select) return ERROR_OK; dap->select = sel; return jtag_dp_q_write(dap, DP_SELECT, (uint32_t)sel); } static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg, uint32_t *data) { int retval = jtag_limit_queue_size(ap->dap); if (retval != ERROR_OK) return retval; retval = jtag_check_reconnect(ap->dap); if (retval != ERROR_OK) return retval; retval = jtag_ap_q_bankselect(ap, reg); if (retval != ERROR_OK) return retval; retval = adi_jtag_dp_scan_u32(ap->dap, JTAG_DP_APACC, reg, DPAP_READ, 0, ap->dap->last_read, ap->memaccess_tck, NULL); ap->dap->last_read = data; return retval; } static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned reg, uint32_t data) { int retval = jtag_limit_queue_size(ap->dap); if (retval != ERROR_OK) return retval; retval = jtag_check_reconnect(ap->dap); if (retval != ERROR_OK) return retval; retval = jtag_ap_q_bankselect(ap, reg); if (retval != ERROR_OK) return retval; retval = adi_jtag_dp_scan_u32(ap->dap, JTAG_DP_APACC, reg, DPAP_WRITE, data, ap->dap->last_read, ap->memaccess_tck, NULL); ap->dap->last_read = NULL; return retval; } static int jtag_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack) { /* for JTAG, this is the only valid ABORT register operation */ int retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_ABORT, 0, DPAP_WRITE, 1, NULL, 0, NULL); if (retval != ERROR_OK) return retval; return jtag_execute_queue(); } static int jtag_dp_run(struct adiv5_dap *dap) { int retval; int retval2 = ERROR_OK; retval = adi_jtag_finish_read(dap); if (retval != ERROR_OK) goto done; retval2 = jtagdp_overrun_check(dap); retval = jtagdp_transaction_endcheck(dap); done: return (retval2 != ERROR_OK) ? retval2 : retval; } static int jtag_dp_sync(struct adiv5_dap *dap) { return jtagdp_overrun_check(dap); } /* FIXME don't export ... just initialize as * part of DAP setup */ const struct dap_ops jtag_dp_ops = { .connect = jtag_connect, .send_sequence = jtag_send_sequence, .queue_dp_read = jtag_dp_q_read, .queue_dp_write = jtag_dp_q_write, .queue_ap_read = jtag_ap_q_read, .queue_ap_write = jtag_ap_q_write, .queue_ap_abort = jtag_ap_q_abort, .run = jtag_dp_run, .sync = jtag_dp_sync, .quit = jtag_quit, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/adi_v5_swd.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * * Copyright (C) 2010 by David Brownell ***************************************************************************/ /** * @file * Utilities to support ARM "Serial Wire Debug" (SWD), a low pin-count debug * link protocol used in cases where JTAG is not wanted. This is coupled to * recent versions of ARM's "CoreSight" debug framework. This specific code * is a transport level interface, with "target/arm_adi_v5.[hc]" code * understanding operation semantics, shared with the JTAG transport. * * Single DAP and multidrop-SWD support. * * for details, see "ARM IHI 0031A" * ARM Debug Interface v5 Architecture Specification * especially section 5.3 for SWD protocol * and "ARM IHI 0074C" ARM Debug Interface Architecture Specification ADIv6.0 * * On many chips (most current Cortex-M3 parts) SWD is a run-time alternative * to JTAG. Boards may support one or both. There are also SWD-only chips, * (using SW-DP not SWJ-DP). * * Even boards that also support JTAG can benefit from SWD support, because * usually there's no way to access the SWO trace view mechanism in JTAG mode. * That is, trace access may require SWD support. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "arm_adi_v5.h" #include <helper/time_support.h> #include <transport/transport.h> #include <jtag/interface.h> #include <jtag/swd.h> /* for debug, set do_sync to true to force synchronous transfers */ static bool do_sync; static struct adiv5_dap *swd_multidrop_selected_dap; static int swd_queue_dp_write_inner(struct adiv5_dap *dap, unsigned int reg, uint32_t data); static int swd_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq) { const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); return swd->switch_seq(seq); } static void swd_finish_read(struct adiv5_dap *dap) { const struct swd_driver *swd = adiv5_dap_swd_driver(dap); if (dap->last_read) { swd->read_reg(swd_cmd(true, false, DP_RDBUFF), dap->last_read, 0); dap->last_read = NULL; } } static void swd_clear_sticky_errors(struct adiv5_dap *dap) { const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); swd->write_reg(swd_cmd(false, false, DP_ABORT), STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); } static int swd_run_inner(struct adiv5_dap *dap) { const struct swd_driver *swd = adiv5_dap_swd_driver(dap); int retval; retval = swd->run(); if (retval != ERROR_OK) { /* fault response */ dap->do_reconnect = true; } return retval; } static inline int check_sync(struct adiv5_dap *dap) { return do_sync ? swd_run_inner(dap) : ERROR_OK; } /** Select the DP register bank matching bits 7:4 of reg. */ static int swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned int reg) { /* Only register address 0 and 4 are banked. */ if ((reg & 0xf) > 4) return ERROR_OK; uint64_t sel = (reg & 0x000000F0) >> 4; if (dap->select != DP_SELECT_INVALID) sel |= dap->select & ~0xfULL; if (sel == dap->select) return ERROR_OK; dap->select = sel; int retval = swd_queue_dp_write_inner(dap, DP_SELECT, (uint32_t)sel); if (retval != ERROR_OK) dap->select = DP_SELECT_INVALID; return retval; } static int swd_queue_dp_read_inner(struct adiv5_dap *dap, unsigned int reg, uint32_t *data) { const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); int retval = swd_queue_dp_bankselect(dap, reg); if (retval != ERROR_OK) return retval; swd->read_reg(swd_cmd(true, false, reg), data, 0); return check_sync(dap); } static int swd_queue_dp_write_inner(struct adiv5_dap *dap, unsigned int reg, uint32_t data) { int retval; const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); swd_finish_read(dap); if (reg == DP_SELECT) { dap->select = data & (DP_SELECT_APSEL | DP_SELECT_APBANK | DP_SELECT_DPBANK); swd->write_reg(swd_cmd(false, false, reg), data, 0); retval = check_sync(dap); if (retval != ERROR_OK) dap->select = DP_SELECT_INVALID; return retval; } retval = swd_queue_dp_bankselect(dap, reg); if (retval != ERROR_OK) return retval; swd->write_reg(swd_cmd(false, false, reg), data, 0); return check_sync(dap); } static int swd_multidrop_select_inner(struct adiv5_dap *dap, uint32_t *dpidr_ptr, uint32_t *dlpidr_ptr, bool clear_sticky) { int retval; uint32_t dpidr, dlpidr; assert(dap_is_multidrop(dap)); swd_send_sequence(dap, LINE_RESET); /* From ARM IHI 0074C ADIv6.0, chapter B4.3.3 "Connection and line reset * sequence": * - line reset sets DP_SELECT_DPBANK to zero; * - read of DP_DPIDR takes the connection out of reset; * - write of DP_TARGETSEL keeps the connection in reset; * - other accesses return protocol error (SWDIO not driven by target). * * Read DP_DPIDR to get out of reset. Initialize dap->select to zero to * skip the write to DP_SELECT, avoiding the protocol error. Set again * dap->select to DP_SELECT_INVALID because the rest of the register is * unknown after line reset. */ dap->select = 0; retval = swd_queue_dp_write_inner(dap, DP_TARGETSEL, dap->multidrop_targetsel); if (retval != ERROR_OK) return retval; retval = swd_queue_dp_read_inner(dap, DP_DPIDR, &dpidr); if (retval != ERROR_OK) return retval; if (clear_sticky) { /* Clear all sticky errors (including ORUN) */ swd_clear_sticky_errors(dap); } else { /* Ideally just clear ORUN flag which is set by reset */ retval = swd_queue_dp_write_inner(dap, DP_ABORT, ORUNERRCLR); if (retval != ERROR_OK) return retval; } dap->select = DP_SELECT_INVALID; retval = swd_queue_dp_read_inner(dap, DP_DLPIDR, &dlpidr); if (retval != ERROR_OK) return retval; retval = swd_run_inner(dap); if (retval != ERROR_OK) return retval; if ((dpidr & DP_DPIDR_VERSION_MASK) < (2UL << DP_DPIDR_VERSION_SHIFT)) { LOG_INFO("Read DPIDR 0x%08" PRIx32 " has version < 2. A non multidrop capable device connected?", dpidr); return ERROR_FAIL; } /* TODO: check TARGETID if DLIPDR is same for more than one DP */ uint32_t expected_dlpidr = DP_DLPIDR_PROTVSN | (dap->multidrop_targetsel & DP_TARGETSEL_INSTANCEID_MASK); if (dlpidr != expected_dlpidr) { LOG_INFO("Read incorrect DLPIDR 0x%08" PRIx32 " (possibly CTRL/STAT value)", dlpidr); return ERROR_FAIL; } LOG_DEBUG_IO("Selected DP_TARGETSEL 0x%08" PRIx32, dap->multidrop_targetsel); swd_multidrop_selected_dap = dap; if (dpidr_ptr) *dpidr_ptr = dpidr; if (dlpidr_ptr) *dlpidr_ptr = dlpidr; return retval; } static int swd_multidrop_select(struct adiv5_dap *dap) { if (!dap_is_multidrop(dap)) return ERROR_OK; if (swd_multidrop_selected_dap == dap) return ERROR_OK; int retval = ERROR_OK; for (unsigned int retry = 0; ; retry++) { bool clear_sticky = retry > 0; retval = swd_multidrop_select_inner(dap, NULL, NULL, clear_sticky); if (retval == ERROR_OK) break; swd_multidrop_selected_dap = NULL; if (retry > 3) { LOG_ERROR("Failed to select multidrop %s", adiv5_dap_name(dap)); return retval; } LOG_DEBUG("Failed to select multidrop %s, retrying...", adiv5_dap_name(dap)); /* we going to retry localy, do not ask for full reconnect */ dap->do_reconnect = false; } return retval; } static int swd_connect_multidrop(struct adiv5_dap *dap) { int retval; uint32_t dpidr = 0xdeadbeef; uint32_t dlpidr = 0xdeadbeef; int64_t timeout = timeval_ms() + 500; do { swd_send_sequence(dap, JTAG_TO_DORMANT); swd_send_sequence(dap, DORMANT_TO_SWD); /* Clear link state, including the SELECT cache. */ dap->do_reconnect = false; dap_invalidate_cache(dap); swd_multidrop_selected_dap = NULL; retval = swd_multidrop_select_inner(dap, &dpidr, &dlpidr, true); if (retval == ERROR_OK) break; alive_sleep(1); } while (timeval_ms() < timeout); if (retval != ERROR_OK) { swd_multidrop_selected_dap = NULL; LOG_ERROR("Failed to connect multidrop %s", adiv5_dap_name(dap)); return retval; } LOG_INFO("SWD DPIDR 0x%08" PRIx32 ", DLPIDR 0x%08" PRIx32, dpidr, dlpidr); return retval; } static int swd_connect_single(struct adiv5_dap *dap) { int retval; uint32_t dpidr = 0xdeadbeef; int64_t timeout = timeval_ms() + 500; do { if (dap->switch_through_dormant) { swd_send_sequence(dap, JTAG_TO_DORMANT); swd_send_sequence(dap, DORMANT_TO_SWD); } else { swd_send_sequence(dap, JTAG_TO_SWD); } /* Clear link state, including the SELECT cache. */ dap->do_reconnect = false; dap_invalidate_cache(dap); /* The sequences to enter in SWD (JTAG_TO_SWD and DORMANT_TO_SWD) end * with a SWD line reset sequence (50 clk with SWDIO high). * From ARM IHI 0074C ADIv6.0, chapter B4.3.3 "Connection and line reset * sequence": * - line reset sets DP_SELECT_DPBANK to zero; * - read of DP_DPIDR takes the connection out of reset; * - write of DP_TARGETSEL keeps the connection in reset; * - other accesses return protocol error (SWDIO not driven by target). * * Read DP_DPIDR to get out of reset. Initialize dap->select to zero to * skip the write to DP_SELECT, avoiding the protocol error. Set again * dap->select to DP_SELECT_INVALID because the rest of the register is * unknown after line reset. */ dap->select = 0; retval = swd_queue_dp_read_inner(dap, DP_DPIDR, &dpidr); if (retval == ERROR_OK) { retval = swd_run_inner(dap); if (retval == ERROR_OK) break; } alive_sleep(1); dap->switch_through_dormant = !dap->switch_through_dormant; } while (timeval_ms() < timeout); dap->select = DP_SELECT_INVALID; if (retval != ERROR_OK) { LOG_ERROR("Error connecting DP: cannot read IDR"); return retval; } LOG_INFO("SWD DPIDR 0x%08" PRIx32, dpidr); do { dap->do_reconnect = false; /* force clear all sticky faults */ swd_clear_sticky_errors(dap); retval = swd_run_inner(dap); if (retval != ERROR_WAIT) break; alive_sleep(10); } while (timeval_ms() < timeout); return retval; } static int swd_connect(struct adiv5_dap *dap) { int status; /* FIXME validate transport config ... is the * configured DAP present (check IDCODE)? */ /* Check if we should reset srst already when connecting, but not if reconnecting. */ if (!dap->do_reconnect) { enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) adapter_assert_reset(); else LOG_WARNING("\'srst_nogate\' reset_config option is required"); } } if (dap_is_multidrop(dap)) status = swd_connect_multidrop(dap); else status = swd_connect_single(dap); /* IHI 0031E B4.3.2: * "A WAIT response must not be issued to the ... * ... writes to the ABORT register" * swd_clear_sticky_errors() writes to the ABORT register only. * * Unfortunately at least Microchip SAMD51/E53/E54 returns WAIT * in a corner case. Just try if ABORT resolves the problem. */ if (status == ERROR_WAIT) { LOG_WARNING("Connecting DP: stalled AP operation, issuing ABORT"); dap->do_reconnect = false; status = swd_queue_dp_write_inner(dap, DP_ABORT, DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR); if (status == ERROR_OK) status = swd_run_inner(dap); } if (status == ERROR_OK) status = dap_dp_init(dap); return status; } static int swd_check_reconnect(struct adiv5_dap *dap) { if (dap->do_reconnect) return swd_connect(dap); return ERROR_OK; } static int swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) { const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); /* TODO: Send DAPABORT in swd_multidrop_select_inner() * in the case the multidrop dap is not selected? * swd_queue_ap_abort() is not currently used anyway... */ int retval = swd_multidrop_select(dap); if (retval != ERROR_OK) return retval; swd->write_reg(swd_cmd(false, false, DP_ABORT), DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); return check_sync(dap); } static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { int retval = swd_check_reconnect(dap); if (retval != ERROR_OK) return retval; retval = swd_multidrop_select(dap); if (retval != ERROR_OK) return retval; return swd_queue_dp_read_inner(dap, reg, data); } static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); int retval = swd_check_reconnect(dap); if (retval != ERROR_OK) return retval; retval = swd_multidrop_select(dap); if (retval != ERROR_OK) return retval; return swd_queue_dp_write_inner(dap, reg, data); } /** Select the AP register bank matching bits 7:4 of reg. */ static int swd_queue_ap_bankselect(struct adiv5_ap *ap, unsigned reg) { int retval; struct adiv5_dap *dap = ap->dap; uint64_t sel; if (is_adiv6(dap)) { sel = ap->ap_num | (reg & 0x00000FF0); if (sel == (dap->select & ~0xfULL)) return ERROR_OK; if (dap->select != DP_SELECT_INVALID) sel |= dap->select & 0xf; dap->select = sel; LOG_DEBUG("AP BANKSEL: %" PRIx64, sel); retval = swd_queue_dp_write(dap, DP_SELECT, (uint32_t)sel); if (retval == ERROR_OK && dap->asize > 32) retval = swd_queue_dp_write(dap, DP_SELECT1, (uint32_t)(sel >> 32)); if (retval != ERROR_OK) dap->select = DP_SELECT_INVALID; return retval; } /* ADIv5 */ sel = (ap->ap_num << 24) | (reg & 0x000000F0); if (dap->select != DP_SELECT_INVALID) sel |= dap->select & DP_SELECT_DPBANK; if (sel == dap->select) return ERROR_OK; dap->select = sel; retval = swd_queue_dp_write_inner(dap, DP_SELECT, sel); if (retval != ERROR_OK) dap->select = DP_SELECT_INVALID; return retval; } static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned reg, uint32_t *data) { struct adiv5_dap *dap = ap->dap; const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); int retval = swd_check_reconnect(dap); if (retval != ERROR_OK) return retval; retval = swd_multidrop_select(dap); if (retval != ERROR_OK) return retval; retval = swd_queue_ap_bankselect(ap, reg); if (retval != ERROR_OK) return retval; swd->read_reg(swd_cmd(true, true, reg), dap->last_read, ap->memaccess_tck); dap->last_read = data; return check_sync(dap); } static int swd_queue_ap_write(struct adiv5_ap *ap, unsigned reg, uint32_t data) { struct adiv5_dap *dap = ap->dap; const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); int retval = swd_check_reconnect(dap); if (retval != ERROR_OK) return retval; retval = swd_multidrop_select(dap); if (retval != ERROR_OK) return retval; swd_finish_read(dap); retval = swd_queue_ap_bankselect(ap, reg); if (retval != ERROR_OK) return retval; swd->write_reg(swd_cmd(false, true, reg), data, ap->memaccess_tck); return check_sync(dap); } /** Executes all queued DAP operations. */ static int swd_run(struct adiv5_dap *dap) { int retval = swd_multidrop_select(dap); if (retval != ERROR_OK) return retval; swd_finish_read(dap); return swd_run_inner(dap); } /** Put the SWJ-DP back to JTAG mode */ static void swd_quit(struct adiv5_dap *dap) { const struct swd_driver *swd = adiv5_dap_swd_driver(dap); static bool done; /* There is no difference if the sequence is sent at the last * or the first swd_quit() call, send it just once */ if (done) return; done = true; if (dap_is_multidrop(dap)) { swd->switch_seq(SWD_TO_DORMANT); /* Revisit! * Leaving DPs in dormant state was tested and offers some safety * against DPs mismatch in case of unintentional use of non-multidrop SWD. * To put SWJ-DPs to power-on state issue * swd->switch_seq(DORMANT_TO_JTAG); */ } else { if (dap->switch_through_dormant) { swd->switch_seq(SWD_TO_DORMANT); swd->switch_seq(DORMANT_TO_JTAG); } else { swd->switch_seq(SWD_TO_JTAG); } } /* flush the queue to shift out the sequence before exit */ swd->run(); } const struct dap_ops swd_dap_ops = { .connect = swd_connect, .send_sequence = swd_send_sequence, .queue_dp_read = swd_queue_dp_read, .queue_dp_write = swd_queue_dp_write, .queue_ap_read = swd_queue_ap_read, .queue_ap_write = swd_queue_ap_write, .queue_ap_abort = swd_queue_ap_abort, .run = swd_run, .quit = swd_quit, }; static const struct command_registration swd_commands[] = { { /* * Set up SWD and JTAG targets identically, unless/until * infrastructure improves ... meanwhile, ignore all * JTAG-specific stuff like IR length for SWD. * * REVISIT can we verify "just one SWD DAP" here/early? */ .name = "newdap", .handler = handle_jtag_newtap, .mode = COMMAND_CONFIG, .help = "declare a new SWD DAP", .usage = "basename dap_type ['-irlen' count] " "['-enable'|'-disable'] " "['-expected_id' number] " "['-ignore-version'] " "['-ignore-bypass'] " "['-ircapture' number] " "['-mask' number]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration swd_handlers[] = { { .name = "swd", .mode = COMMAND_ANY, .help = "SWD command group", .chain = swd_commands, .usage = "", }, COMMAND_REGISTRATION_DONE }; static int swd_select(struct command_context *ctx) { /* FIXME: only place where global 'adapter_driver' is still needed */ extern struct adapter_driver *adapter_driver; const struct swd_driver *swd = adapter_driver->swd_ops; int retval; retval = register_commands(ctx, NULL, swd_handlers); if (retval != ERROR_OK) return retval; /* be sure driver is in SWD mode; start * with hardware default TRN (1), it can be changed later */ if (!swd || !swd->read_reg || !swd->write_reg || !swd->init) { LOG_DEBUG("no SWD driver?"); return ERROR_FAIL; } retval = swd->init(); if (retval != ERROR_OK) { LOG_DEBUG("can't init SWD driver"); return retval; } return retval; } static int swd_init(struct command_context *ctx) { /* nothing done here, SWD is initialized * together with the DAP */ return ERROR_OK; } static struct transport swd_transport = { .name = "swd", .select = swd_select, .init = swd_init, }; static void swd_constructor(void) __attribute__((constructor)); static void swd_constructor(void) { transport_register(&swd_transport); } /** Returns true if the current debug session * is using SWD as its transport. */ bool transport_is_swd(void) { return get_current_transport() == &swd_transport; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/algorithm.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "algorithm.h" #include <helper/binarybuffer.h> void init_mem_param(struct mem_param *param, uint32_t address, uint32_t size, enum param_direction direction) { param->address = address; param->size = size; param->value = malloc(size); param->direction = direction; } void destroy_mem_param(struct mem_param *param) { free(param->value); param->value = NULL; } void init_reg_param(struct reg_param *param, char *reg_name, uint32_t size, enum param_direction direction) { param->reg_name = reg_name; param->size = size; param->value = malloc(DIV_ROUND_UP(size, 8)); param->direction = direction; } void destroy_reg_param(struct reg_param *param) { free(param->value); param->value = NULL; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/algorithm.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_TARGET_ALGORITHM_H #define OPENOCD_TARGET_ALGORITHM_H #include "helper/types.h" #include "helper/replacements.h" enum param_direction { PARAM_IN, PARAM_OUT, PARAM_IN_OUT }; struct mem_param { target_addr_t address; uint32_t size; uint8_t *value; enum param_direction direction; }; struct reg_param { const char *reg_name; uint32_t size; uint8_t *value; enum param_direction direction; }; void init_mem_param(struct mem_param *param, uint32_t address, uint32_t size, enum param_direction dir); void destroy_mem_param(struct mem_param *param); void init_reg_param(struct reg_param *param, char *reg_name, uint32_t size, enum param_direction dir); void destroy_reg_param(struct reg_param *param); #endif /* OPENOCD_TARGET_ALGORITHM_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arc.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Mischa Jonker <mischa.jonker@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arc.h" /* * ARC architecture specific details. * * ARC has two types of registers: * 1) core registers(e.g. r0,r1..) [is_core = true] * 2) Auxiliary registers [is_core = false].. * * Auxiliary registers at the same time can be divided into * read-only BCR(build configuration regs, e.g. isa_config, mpu_build) and * R/RW non-BCR ("control" register, e.g. pc, status32_t, debug). * * The way of accessing to Core and AUX registers differs on Jtag level. * BCR/non-BCR describes if the register is immutable and that reading * unexisting register is safe RAZ, rather then an error. * Note, core registers cannot be BCR. * * In arc/cpu/ tcl files all registers are defined as core, non-BCR aux * and BCR aux, in "add-reg" command they are passed to three lists * respectively: core_reg_descriptions, aux_reg_descriptions, * bcr_reg_descriptions. * * Due to the specifics of accessing to BCR/non-BCR registers there are two * register caches: * 1) core_and_aux_cache - includes registers described in * core_reg_descriptions and aux_reg_descriptions lists. * Used during save/restore context step. * 2) bcr_cache - includes registers described bcr_reg_descriptions. * Currently used internally during configure step. */ static int arc_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); void arc_reg_data_type_add(struct target *target, struct arc_reg_data_type *data_type) { LOG_DEBUG("Adding %s reg_data_type", data_type->data_type.id); struct arc_common *arc = target_to_arc(target); assert(arc); list_add_tail(&data_type->list, &arc->reg_data_types); } /** * Private implementation of register_get_by_name() for ARC that * doesn't skip not [yet] existing registers. Used in many places * for iteration through registers and even for marking required registers as * existing. */ struct reg *arc_reg_get_by_name(struct reg_cache *first, const char *name, bool search_all) { unsigned int i; struct reg_cache *cache = first; while (cache) { for (i = 0; i < cache->num_regs; i++) { if (!strcmp(cache->reg_list[i].name, name)) return &(cache->reg_list[i]); } if (search_all) cache = cache->next; else break; } return NULL; } /** * Reset internal states of caches. Must be called when entering debugging. * * @param target Target for which to reset caches states. */ static int arc_reset_caches_states(struct target *target) { struct arc_common *arc = target_to_arc(target); LOG_DEBUG("Resetting internal variables of caches states"); /* Reset caches states. */ arc->dcache_flushed = false; arc->l2cache_flushed = false; arc->icache_invalidated = false; arc->dcache_invalidated = false; arc->l2cache_invalidated = false; return ERROR_OK; } /* Initialize arc_common structure, which passes to openocd target instance */ static int arc_init_arch_info(struct target *target, struct arc_common *arc, struct jtag_tap *tap) { arc->common_magic = ARC_COMMON_MAGIC; target->arch_info = arc; arc->jtag_info.tap = tap; /* The only allowed ir_length is 4 for ARC jtag. */ if (tap->ir_length != 4) { LOG_ERROR("ARC jtag instruction length should be equal to 4"); return ERROR_FAIL; } /* On most ARC targets there is a dcache, so we enable its flushing * by default. If there no dcache, there will be no error, just a slight * performance penalty from unnecessary JTAG operations. */ arc->has_dcache = true; arc->has_icache = true; /* L2$ is not available in a target by default. */ arc->has_l2cache = false; arc_reset_caches_states(target); /* Add standard GDB data types */ INIT_LIST_HEAD(&arc->reg_data_types); struct arc_reg_data_type *std_types = calloc(ARRAY_SIZE(standard_gdb_types), sizeof(*std_types)); if (!std_types) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; } for (unsigned int i = 0; i < ARRAY_SIZE(standard_gdb_types); i++) { std_types[i].data_type.type = standard_gdb_types[i].type; std_types[i].data_type.id = standard_gdb_types[i].id; arc_reg_data_type_add(target, &(std_types[i])); } /* Fields related to target descriptions */ INIT_LIST_HEAD(&arc->core_reg_descriptions); INIT_LIST_HEAD(&arc->aux_reg_descriptions); INIT_LIST_HEAD(&arc->bcr_reg_descriptions); arc->num_regs = 0; arc->num_core_regs = 0; arc->num_aux_regs = 0; arc->num_bcr_regs = 0; arc->last_general_reg = ULONG_MAX; arc->pc_index_in_cache = ULONG_MAX; arc->debug_index_in_cache = ULONG_MAX; return ERROR_OK; } int arc_reg_add(struct target *target, struct arc_reg_desc *arc_reg, const char * const type_name, const size_t type_name_len) { assert(target); assert(arc_reg); struct arc_common *arc = target_to_arc(target); assert(arc); /* Find register type */ { struct arc_reg_data_type *type; list_for_each_entry(type, &arc->reg_data_types, list) if (!strncmp(type->data_type.id, type_name, type_name_len)) { arc_reg->data_type = &(type->data_type); break; } if (!arc_reg->data_type) return ERROR_ARC_REGTYPE_NOT_FOUND; } if (arc_reg->is_core) { list_add_tail(&arc_reg->list, &arc->core_reg_descriptions); arc->num_core_regs += 1; } else if (arc_reg->is_bcr) { list_add_tail(&arc_reg->list, &arc->bcr_reg_descriptions); arc->num_bcr_regs += 1; } else { list_add_tail(&arc_reg->list, &arc->aux_reg_descriptions); arc->num_aux_regs += 1; } arc->num_regs += 1; LOG_DEBUG( "added register {name=%s, num=0x%" PRIx32 ", type=%s%s%s%s}", arc_reg->name, arc_reg->arch_num, arc_reg->data_type->id, arc_reg->is_core ? ", core" : "", arc_reg->is_bcr ? ", bcr" : "", arc_reg->is_general ? ", general" : "" ); return ERROR_OK; } /* Reading core or aux register */ static int arc_get_register(struct reg *reg) { assert(reg); struct arc_reg_desc *desc = reg->arch_info; struct target *target = desc->target; struct arc_common *arc = target_to_arc(target); uint32_t value; if (reg->valid) { LOG_DEBUG("Get register (cached) gdb_num=%" PRIu32 ", name=%s, value=0x%" PRIx32, reg->number, desc->name, target_buffer_get_u32(target, reg->value)); return ERROR_OK; } if (desc->is_core) { /* Accessing to R61/R62 registers causes Jtag hang */ if (desc->arch_num == ARC_R61 || desc->arch_num == ARC_R62) { LOG_ERROR("It is forbidden to read core registers 61 and 62."); return ERROR_FAIL; } CHECK_RETVAL(arc_jtag_read_core_reg_one(&arc->jtag_info, desc->arch_num, &value)); } else { CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, desc->arch_num, &value)); } target_buffer_set_u32(target, reg->value, value); /* If target is unhalted all register reads should be uncached. */ if (target->state == TARGET_HALTED) reg->valid = true; else reg->valid = false; reg->dirty = false; LOG_DEBUG("Get register gdb_num=%" PRIu32 ", name=%s, value=0x%" PRIx32, reg->number, desc->name, value); return ERROR_OK; } /* Writing core or aux register */ static int arc_set_register(struct reg *reg, uint8_t *buf) { struct arc_reg_desc *desc = reg->arch_info; struct target *target = desc->target; uint32_t value = target_buffer_get_u32(target, buf); /* Unlike "get" function "set" is supported only if target * is in halt mode. Async writes are not supported yet. */ if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; /* Accessing to R61/R62 registers causes Jtag hang */ if (desc->is_core && (desc->arch_num == ARC_R61 || desc->arch_num == ARC_R62)) { LOG_ERROR("It is forbidden to write core registers 61 and 62."); return ERROR_FAIL; } target_buffer_set_u32(target, reg->value, value); LOG_DEBUG("Set register gdb_num=%" PRIu32 ", name=%s, value=0x%08" PRIx32, reg->number, desc->name, value); reg->valid = true; reg->dirty = true; return ERROR_OK; } static const struct reg_arch_type arc_reg_type = { .get = arc_get_register, .set = arc_set_register, }; /* GDB register groups. For now we support only general and "empty" */ static const char * const reg_group_general = "general"; static const char * const reg_group_other = ""; /* Common code to initialize `struct reg` for different registers: core, aux, bcr. */ static int arc_init_reg(struct target *target, struct reg *reg, struct arc_reg_desc *reg_desc, unsigned long number) { assert(target); assert(reg); assert(reg_desc); struct arc_common *arc = target_to_arc(target); /* Initialize struct reg */ reg->name = reg_desc->name; reg->size = 32; /* All register in ARC are 32-bit */ reg->value = reg_desc->reg_value; reg->type = &arc_reg_type; reg->arch_info = reg_desc; reg->caller_save = true; /* @todo should be configurable. */ reg->reg_data_type = reg_desc->data_type; reg->feature = ®_desc->feature; reg->feature->name = reg_desc->gdb_xml_feature; /* reg->number is used by OpenOCD as value for @regnum. Thus when setting * value of a register GDB will use it as a number of register in * P-packet. OpenOCD gdbserver will then use number of register in * P-packet as an array index in the reg_list returned by * arc_regs_get_gdb_reg_list. So to ensure that registers are assigned * correctly it would be required to either sort registers in * arc_regs_get_gdb_reg_list or to assign numbers sequentially here and * according to how registers will be sorted in * arc_regs_get_gdb_reg_list. Second options is much more simpler. */ reg->number = number; if (reg_desc->is_general) { arc->last_general_reg = reg->number; reg->group = reg_group_general; } else { reg->group = reg_group_other; } return ERROR_OK; } /* Building aux/core reg_cache */ static int arc_build_reg_cache(struct target *target) { unsigned long i = 0; struct arc_reg_desc *reg_desc; /* get pointers to arch-specific information */ struct arc_common *arc = target_to_arc(target); const unsigned long num_regs = arc->num_core_regs + arc->num_aux_regs; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = calloc(1, sizeof(*cache)); struct reg *reg_list = calloc(num_regs, sizeof(*reg_list)); if (!cache || !reg_list) { LOG_ERROR("Not enough memory"); goto fail; } /* Build the process context cache */ cache->name = "arc registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = num_regs; arc->core_and_aux_cache = cache; (*cache_p) = cache; if (list_empty(&arc->core_reg_descriptions)) { LOG_ERROR("No core registers were defined"); goto fail; } list_for_each_entry(reg_desc, &arc->core_reg_descriptions, list) { CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, i)); LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i, reg_list[i].name, reg_list[i].group, reg_list[i].feature->name); i += 1; } if (list_empty(&arc->aux_reg_descriptions)) { LOG_ERROR("No aux registers were defined"); goto fail; } list_for_each_entry(reg_desc, &arc->aux_reg_descriptions, list) { CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, i)); LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i, reg_list[i].name, reg_list[i].group, reg_list[i].feature->name); /* PC and DEBUG are essential so we search for them. */ if (!strcmp("pc", reg_desc->name)) { if (arc->pc_index_in_cache != ULONG_MAX) { LOG_ERROR("Double definition of PC in configuration"); goto fail; } arc->pc_index_in_cache = i; } else if (!strcmp("debug", reg_desc->name)) { if (arc->debug_index_in_cache != ULONG_MAX) { LOG_ERROR("Double definition of DEBUG in configuration"); goto fail; } arc->debug_index_in_cache = i; } i += 1; } if (arc->pc_index_in_cache == ULONG_MAX || arc->debug_index_in_cache == ULONG_MAX) { LOG_ERROR("`pc' and `debug' registers must be present in target description."); goto fail; } assert(i == (arc->num_core_regs + arc->num_aux_regs)); arc->core_aux_cache_built = true; return ERROR_OK; fail: free(cache); free(reg_list); return ERROR_FAIL; } /* Build bcr reg_cache. * This function must be called only after arc_build_reg_cache */ static int arc_build_bcr_reg_cache(struct target *target) { /* get pointers to arch-specific information */ struct arc_common *arc = target_to_arc(target); const unsigned long num_regs = arc->num_bcr_regs; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(*cache)); struct reg *reg_list = calloc(num_regs, sizeof(*reg_list)); struct arc_reg_desc *reg_desc; unsigned long i = 0; unsigned long gdb_regnum = arc->core_and_aux_cache->num_regs; if (!cache || !reg_list) { LOG_ERROR("Unable to allocate memory"); goto fail; } /* Build the process context cache */ cache->name = "arc.bcr"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = num_regs; arc->bcr_cache = cache; (*cache_p) = cache; if (list_empty(&arc->bcr_reg_descriptions)) { LOG_ERROR("No BCR registers are defined"); goto fail; } list_for_each_entry(reg_desc, &arc->bcr_reg_descriptions, list) { CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, gdb_regnum)); /* BCRs always semantically, they are just read-as-zero, if there is * not real register. */ reg_list[i].exist = true; LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i, reg_list[i].name, reg_list[i].group, reg_list[i].feature->name); i += 1; gdb_regnum += 1; } assert(i == arc->num_bcr_regs); arc->bcr_cache_built = true; return ERROR_OK; fail: free(cache); free(reg_list); return ERROR_FAIL; } static int arc_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { assert(target->reg_cache); struct arc_common *arc = target_to_arc(target); /* get pointers to arch-specific information storage */ *reg_list_size = arc->num_regs; *reg_list = calloc(*reg_list_size, sizeof(struct reg *)); if (!*reg_list) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; } /* OpenOCD gdb_server API seems to be inconsistent here: when it generates * XML tdesc it filters out !exist registers, however when creating a * g-packet it doesn't do so. REG_CLASS_ALL is used in first case, and * REG_CLASS_GENERAL used in the latter one. Due to this we had to filter * out !exist register for "general", but not for "all". Attempts to filter out * !exist for "all" as well will cause a failed check in OpenOCD GDB * server. */ if (reg_class == REG_CLASS_ALL) { unsigned long i = 0; struct reg_cache *reg_cache = target->reg_cache; while (reg_cache) { for (unsigned j = 0; j < reg_cache->num_regs; j++, i++) (*reg_list)[i] = ®_cache->reg_list[j]; reg_cache = reg_cache->next; } assert(i == arc->num_regs); LOG_DEBUG("REG_CLASS_ALL: number of regs=%i", *reg_list_size); } else { unsigned long i = 0; unsigned long gdb_reg_number = 0; struct reg_cache *reg_cache = target->reg_cache; while (reg_cache) { for (unsigned j = 0; j < reg_cache->num_regs && gdb_reg_number <= arc->last_general_reg; j++) { if (reg_cache->reg_list[j].exist) { (*reg_list)[i] = ®_cache->reg_list[j]; i++; } gdb_reg_number += 1; } reg_cache = reg_cache->next; } *reg_list_size = i; LOG_DEBUG("REG_CLASS_GENERAL: number of regs=%i", *reg_list_size); } return ERROR_OK; } /* Reading field of struct_type register */ int arc_reg_get_field(struct target *target, const char *reg_name, const char *field_name, uint32_t *value_ptr) { struct reg_data_type_struct_field *field; LOG_DEBUG("getting register field (reg_name=%s, field_name=%s)", reg_name, field_name); /* Get register */ struct reg *reg = arc_reg_get_by_name(target->reg_cache, reg_name, true); if (!reg) { LOG_ERROR("Requested register `%s' doesn't exist.", reg_name); return ERROR_ARC_REGISTER_NOT_FOUND; } if (reg->reg_data_type->type != REG_TYPE_ARCH_DEFINED || reg->reg_data_type->type_class != REG_TYPE_CLASS_STRUCT) return ERROR_ARC_REGISTER_IS_NOT_STRUCT; /* Get field in a register */ struct reg_data_type_struct *reg_struct = reg->reg_data_type->reg_type_struct; for (field = reg_struct->fields; field; field = field->next) { if (!strcmp(field->name, field_name)) break; } if (!field) return ERROR_ARC_REGISTER_FIELD_NOT_FOUND; if (!field->use_bitfields) return ERROR_ARC_FIELD_IS_NOT_BITFIELD; if (!reg->valid) CHECK_RETVAL(reg->type->get(reg)); /* First do endianness-safe read of register value * then convert it to binary buffer for further * field extraction */ *value_ptr = buf_get_u32(reg->value, field->bitfield->start, field->bitfield->end - field->bitfield->start + 1); return ERROR_OK; } static int arc_get_register_value(struct target *target, const char *reg_name, uint32_t *value_ptr) { LOG_DEBUG("reg_name=%s", reg_name); struct reg *reg = arc_reg_get_by_name(target->reg_cache, reg_name, true); if (!reg) return ERROR_ARC_REGISTER_NOT_FOUND; if (!reg->valid) CHECK_RETVAL(reg->type->get(reg)); *value_ptr = target_buffer_get_u32(target, reg->value); return ERROR_OK; } static int arc_set_register_value(struct target *target, const char *reg_name, uint32_t value) { LOG_DEBUG("reg_name=%s value=0x%08" PRIx32, reg_name, value); if (!(target && reg_name)) { LOG_ERROR("Arguments cannot be NULL."); return ERROR_FAIL; } struct reg *reg = arc_reg_get_by_name(target->reg_cache, reg_name, true); if (!reg) return ERROR_ARC_REGISTER_NOT_FOUND; uint8_t value_buf[4]; buf_set_u32(value_buf, 0, 32, value); CHECK_RETVAL(reg->type->set(reg, value_buf)); return ERROR_OK; } /* Configure DCCM's */ static int arc_configure_dccm(struct target *target) { struct arc_common *arc = target_to_arc(target); uint32_t dccm_build_version, dccm_build_size0, dccm_build_size1; CHECK_RETVAL(arc_reg_get_field(target, "dccm_build", "version", &dccm_build_version)); CHECK_RETVAL(arc_reg_get_field(target, "dccm_build", "size0", &dccm_build_size0)); CHECK_RETVAL(arc_reg_get_field(target, "dccm_build", "size1", &dccm_build_size1)); /* There is no yet support of configurable number of cycles, * So there is no difference between v3 and v4 */ if ((dccm_build_version == 3 || dccm_build_version == 4) && dccm_build_size0 > 0) { CHECK_RETVAL(arc_get_register_value(target, "aux_dccm", &(arc->dccm_start))); uint32_t dccm_size = 0x100; dccm_size <<= dccm_build_size0; if (dccm_build_size0 == 0xF) dccm_size <<= dccm_build_size1; arc->dccm_end = arc->dccm_start + dccm_size; LOG_DEBUG("DCCM detected start=0x%" PRIx32 " end=0x%" PRIx32, arc->dccm_start, arc->dccm_end); } return ERROR_OK; } /* Configure ICCM's */ static int arc_configure_iccm(struct target *target) { struct arc_common *arc = target_to_arc(target); /* ICCM0 */ uint32_t iccm_build_version, iccm_build_size00, iccm_build_size01; uint32_t aux_iccm = 0; CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "version", &iccm_build_version)); CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm0_size0", &iccm_build_size00)); CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm0_size1", &iccm_build_size01)); if (iccm_build_version == 4 && iccm_build_size00 > 0) { CHECK_RETVAL(arc_get_register_value(target, "aux_iccm", &aux_iccm)); uint32_t iccm0_size = 0x100; iccm0_size <<= iccm_build_size00; if (iccm_build_size00 == 0xF) iccm0_size <<= iccm_build_size01; /* iccm0 start is located in highest 4 bits of aux_iccm */ arc->iccm0_start = aux_iccm & 0xF0000000; arc->iccm0_end = arc->iccm0_start + iccm0_size; LOG_DEBUG("ICCM0 detected start=0x%" PRIx32 " end=0x%" PRIx32, arc->iccm0_start, arc->iccm0_end); } /* ICCM1 */ uint32_t iccm_build_size10, iccm_build_size11; CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm1_size0", &iccm_build_size10)); CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm1_size1", &iccm_build_size11)); if (iccm_build_version == 4 && iccm_build_size10 > 0) { /* Use value read for ICCM0 */ if (!aux_iccm) CHECK_RETVAL(arc_get_register_value(target, "aux_iccm", &aux_iccm)); uint32_t iccm1_size = 0x100; iccm1_size <<= iccm_build_size10; if (iccm_build_size10 == 0xF) iccm1_size <<= iccm_build_size11; arc->iccm1_start = aux_iccm & 0x0F000000; arc->iccm1_end = arc->iccm1_start + iccm1_size; LOG_DEBUG("ICCM1 detected start=0x%" PRIx32 " end=0x%" PRIx32, arc->iccm1_start, arc->iccm1_end); } return ERROR_OK; } /* Configure some core features, depending on BCRs. */ static int arc_configure(struct target *target) { LOG_DEBUG("Configuring ARC ICCM and DCCM"); /* Configuring DCCM if DCCM_BUILD and AUX_DCCM are known registers. */ if (arc_reg_get_by_name(target->reg_cache, "dccm_build", true) && arc_reg_get_by_name(target->reg_cache, "aux_dccm", true)) CHECK_RETVAL(arc_configure_dccm(target)); /* Configuring ICCM if ICCM_BUILD and AUX_ICCM are known registers. */ if (arc_reg_get_by_name(target->reg_cache, "iccm_build", true) && arc_reg_get_by_name(target->reg_cache, "aux_iccm", true)) CHECK_RETVAL(arc_configure_iccm(target)); return ERROR_OK; } /* arc_examine is function, which is used for all arc targets*/ static int arc_examine(struct target *target) { uint32_t status; struct arc_common *arc = target_to_arc(target); CHECK_RETVAL(arc_jtag_startup(&arc->jtag_info)); if (!target_was_examined(target)) { CHECK_RETVAL(arc_jtag_status(&arc->jtag_info, &status)); if (status & ARC_JTAG_STAT_RU) target->state = TARGET_RUNNING; else target->state = TARGET_HALTED; /* Read BCRs and configure optional registers. */ CHECK_RETVAL(arc_configure(target)); target_set_examined(target); } return ERROR_OK; } static int arc_halt(struct target *target) { uint32_t value, irq_state; struct arc_common *arc = target_to_arc(target); LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); if (target->state == TARGET_RESET) { if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST"); return ERROR_TARGET_FAILURE; } else { target->debug_reason = DBG_REASON_DBGRQ; } } /* Break (stop) processor. * Do read-modify-write sequence, or DEBUG.UB will be reset unintentionally. * We do not use here arc_get/set_core_reg functions here because they imply * that the processor is already halted. */ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, &value)); value |= SET_CORE_FORCE_HALT; /* set the HALT bit */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, value)); alive_sleep(1); /* Save current IRQ state */ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &irq_state)); if (irq_state & AUX_STATUS32_REG_IE_BIT) arc->irq_state = 1; else arc->irq_state = 0; /* update state and notify gdb*/ target->state = TARGET_HALTED; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); /* some more debug information */ if (debug_level >= LOG_LVL_DEBUG) { LOG_DEBUG("core stopped (halted) DEGUB-REG: 0x%08" PRIx32, value); CHECK_RETVAL(arc_get_register_value(target, "status32", &value)); LOG_DEBUG("core STATUS32: 0x%08" PRIx32, value); } return ERROR_OK; } /** * Read registers that are used in GDB g-packet. We don't read them one-by-one, * but do that in one batch operation to improve speed. Calls to JTAG layer are * expensive so it is better to make one big call that reads all necessary * registers, instead of many calls, one for one register. */ static int arc_save_context(struct target *target) { int retval = ERROR_OK; unsigned int i; struct arc_common *arc = target_to_arc(target); struct reg *reg_list = arc->core_and_aux_cache->reg_list; LOG_DEBUG("Saving aux and core registers values"); assert(reg_list); /* It is assumed that there is at least one AUX register in the list, for * example PC. */ const uint32_t core_regs_size = arc->num_core_regs * sizeof(uint32_t); /* last_general_reg is inclusive number. To get count of registers it is * required to do +1. */ const uint32_t regs_to_scan = MIN(arc->last_general_reg + 1, arc->num_regs); const uint32_t aux_regs_size = arc->num_aux_regs * sizeof(uint32_t); uint32_t *core_values = malloc(core_regs_size); uint32_t *aux_values = malloc(aux_regs_size); uint32_t *core_addrs = malloc(core_regs_size); uint32_t *aux_addrs = malloc(aux_regs_size); unsigned int core_cnt = 0; unsigned int aux_cnt = 0; if (!core_values || !core_addrs || !aux_values || !aux_addrs) { LOG_ERROR("Unable to allocate memory"); retval = ERROR_FAIL; goto exit; } memset(core_values, 0xff, core_regs_size); memset(core_addrs, 0xff, core_regs_size); memset(aux_values, 0xff, aux_regs_size); memset(aux_addrs, 0xff, aux_regs_size); for (i = 0; i < MIN(arc->num_core_regs, regs_to_scan); i++) { struct reg *reg = &(reg_list[i]); struct arc_reg_desc *arc_reg = reg->arch_info; if (!reg->valid && reg->exist) { core_addrs[core_cnt] = arc_reg->arch_num; core_cnt += 1; } } for (i = arc->num_core_regs; i < regs_to_scan; i++) { struct reg *reg = &(reg_list[i]); struct arc_reg_desc *arc_reg = reg->arch_info; if (!reg->valid && reg->exist) { aux_addrs[aux_cnt] = arc_reg->arch_num; aux_cnt += 1; } } /* Read data from target. */ if (core_cnt > 0) { retval = arc_jtag_read_core_reg(&arc->jtag_info, core_addrs, core_cnt, core_values); if (retval != ERROR_OK) { LOG_ERROR("Attempt to read core registers failed."); retval = ERROR_FAIL; goto exit; } } if (aux_cnt > 0) { retval = arc_jtag_read_aux_reg(&arc->jtag_info, aux_addrs, aux_cnt, aux_values); if (retval != ERROR_OK) { LOG_ERROR("Attempt to read aux registers failed."); retval = ERROR_FAIL; goto exit; } } /* Parse core regs */ core_cnt = 0; for (i = 0; i < MIN(arc->num_core_regs, regs_to_scan); i++) { struct reg *reg = &(reg_list[i]); struct arc_reg_desc *arc_reg = reg->arch_info; if (!reg->valid && reg->exist) { target_buffer_set_u32(target, reg->value, core_values[core_cnt]); core_cnt += 1; reg->valid = true; reg->dirty = false; LOG_DEBUG("Get core register regnum=%u, name=%s, value=0x%08" PRIx32, i, arc_reg->name, core_values[core_cnt]); } } /* Parse aux regs */ aux_cnt = 0; for (i = arc->num_core_regs; i < regs_to_scan; i++) { struct reg *reg = &(reg_list[i]); struct arc_reg_desc *arc_reg = reg->arch_info; if (!reg->valid && reg->exist) { target_buffer_set_u32(target, reg->value, aux_values[aux_cnt]); aux_cnt += 1; reg->valid = true; reg->dirty = false; LOG_DEBUG("Get aux register regnum=%u, name=%s, value=0x%08" PRIx32, i, arc_reg->name, aux_values[aux_cnt]); } } exit: free(core_values); free(core_addrs); free(aux_values); free(aux_addrs); return retval; } /** * Finds an actionpoint that triggered last actionpoint event, as specified by * DEBUG.ASR. * * @param target * @param actionpoint Pointer to be set to last active actionpoint. Pointer * will be set to NULL if DEBUG.AH is 0. */ static int get_current_actionpoint(struct target *target, struct arc_actionpoint **actionpoint) { assert(target); assert(actionpoint); uint32_t debug_ah; /* Check if actionpoint caused halt */ CHECK_RETVAL(arc_reg_get_field(target, "debug", "ah", &debug_ah)); if (debug_ah) { struct arc_common *arc = target_to_arc(target); unsigned int ap; uint32_t debug_asr; CHECK_RETVAL(arc_reg_get_field(target, "debug", "asr", &debug_asr)); for (ap = 0; debug_asr > 1; debug_asr >>= 1) ap += 1; assert(ap < arc->actionpoints_num); *actionpoint = &(arc->actionpoints_list[ap]); } else { *actionpoint = NULL; } return ERROR_OK; } static int arc_examine_debug_reason(struct target *target) { uint32_t debug_bh; /* Only check for reason if don't know it already. */ /* BTW After singlestep at this point core is not marked as halted, so * reading from memory to get current instruction wouldn't work anyway. */ if (target->debug_reason == DBG_REASON_DBGRQ || target->debug_reason == DBG_REASON_SINGLESTEP) { return ERROR_OK; } CHECK_RETVAL(arc_reg_get_field(target, "debug", "bh", &debug_bh)); if (debug_bh) { /* DEBUG.BH is set if core halted due to BRK instruction. */ target->debug_reason = DBG_REASON_BREAKPOINT; } else { struct arc_actionpoint *actionpoint = NULL; CHECK_RETVAL(get_current_actionpoint(target, &actionpoint)); if (actionpoint) { if (!actionpoint->used) LOG_WARNING("Target halted by an unused actionpoint."); if (actionpoint->type == ARC_AP_BREAKPOINT) target->debug_reason = DBG_REASON_BREAKPOINT; else if (actionpoint->type == ARC_AP_WATCHPOINT) target->debug_reason = DBG_REASON_WATCHPOINT; else LOG_WARNING("Unknown type of actionpoint."); } } return ERROR_OK; } static int arc_debug_entry(struct target *target) { CHECK_RETVAL(arc_save_context(target)); /* TODO: reset internal indicators of caches states, otherwise D$/I$ * will not be flushed/invalidated when required. */ CHECK_RETVAL(arc_reset_caches_states(target)); CHECK_RETVAL(arc_examine_debug_reason(target)); return ERROR_OK; } static int arc_poll(struct target *target) { uint32_t status, value; struct arc_common *arc = target_to_arc(target); /* gdb calls continuously through this arc_poll() function */ CHECK_RETVAL(arc_jtag_status(&arc->jtag_info, &status)); /* check for processor halted */ if (status & ARC_JTAG_STAT_RU) { if (target->state != TARGET_RUNNING) { LOG_WARNING("target is still running!"); target->state = TARGET_RUNNING; } return ERROR_OK; } /* In some cases JTAG status register indicates that * processor is in halt mode, but processor is still running. * We check halt bit of AUX STATUS32 register for setting correct state. */ if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { CHECK_RETVAL(arc_get_register_value(target, "status32", &value)); if (value & AUX_STATUS32_REG_HALT_BIT) { LOG_DEBUG("ARC core in halt or reset state."); /* Save context if target was not in reset state */ if (target->state == TARGET_RUNNING) CHECK_RETVAL(arc_debug_entry(target)); target->state = TARGET_HALTED; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); } else { LOG_DEBUG("Discrepancy of STATUS32[0] HALT bit and ARC_JTAG_STAT_RU, " "target is still running"); } } else if (target->state == TARGET_DEBUG_RUNNING) { target->state = TARGET_HALTED; LOG_DEBUG("ARC core is in debug running mode"); CHECK_RETVAL(arc_debug_entry(target)); CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED)); } return ERROR_OK; } static int arc_assert_reset(struct target *target) { struct arc_common *arc = target_to_arc(target); enum reset_types jtag_reset_config = jtag_get_reset_config(); bool srst_asserted = false; LOG_DEBUG("target->state: %s", target_state_name(target)); if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) { /* allow scripts to override the reset event */ target_handle_event(target, TARGET_EVENT_RESET_ASSERT); register_cache_invalidate(arc->core_and_aux_cache); /* An ARC target might be in halt state after reset, so * if script requested processor to resume, then it must * be manually started to ensure that this request * is satisfied. */ if (target->state == TARGET_HALTED && !target->reset_halt) { /* Resume the target and continue from the current * PC register value. */ LOG_DEBUG("Starting CPU execution after reset"); CHECK_RETVAL(target_resume(target, 1, 0, 0, 0)); } target->state = TARGET_RESET; return ERROR_OK; } /* some cores support connecting while srst is asserted * use that mode if it has been configured */ if (!(jtag_reset_config & RESET_SRST_PULLS_TRST) && (jtag_reset_config & RESET_SRST_NO_GATING)) { jtag_add_reset(0, 1); srst_asserted = true; } if (jtag_reset_config & RESET_HAS_SRST) { /* should issue a srst only, but we may have to assert trst as well */ if (jtag_reset_config & RESET_SRST_PULLS_TRST) jtag_add_reset(1, 1); else if (!srst_asserted) jtag_add_reset(0, 1); } target->state = TARGET_RESET; jtag_add_sleep(50000); register_cache_invalidate(arc->core_and_aux_cache); if (target->reset_halt) CHECK_RETVAL(target_halt(target)); return ERROR_OK; } static int arc_deassert_reset(struct target *target) { LOG_DEBUG("target->state: %s", target_state_name(target)); /* deassert reset lines */ jtag_add_reset(0, 0); return ERROR_OK; } static int arc_arch_state(struct target *target) { uint32_t pc_value; if (debug_level < LOG_LVL_DEBUG) return ERROR_OK; CHECK_RETVAL(arc_get_register_value(target, "pc", &pc_value)); LOG_DEBUG("target state: %s; PC at: 0x%08" PRIx32, target_state_name(target), pc_value); return ERROR_OK; } /** * See arc_save_context() for reason why we want to dump all regs at once. * This however means that if there are dependencies between registers they * will not be observable until target will be resumed. */ static int arc_restore_context(struct target *target) { int retval = ERROR_OK; unsigned int i; struct arc_common *arc = target_to_arc(target); struct reg *reg_list = arc->core_and_aux_cache->reg_list; LOG_DEBUG("Restoring registers values"); assert(reg_list); const uint32_t core_regs_size = arc->num_core_regs * sizeof(uint32_t); const uint32_t aux_regs_size = arc->num_aux_regs * sizeof(uint32_t); uint32_t *core_values = malloc(core_regs_size); uint32_t *aux_values = malloc(aux_regs_size); uint32_t *core_addrs = malloc(core_regs_size); uint32_t *aux_addrs = malloc(aux_regs_size); unsigned int core_cnt = 0; unsigned int aux_cnt = 0; if (!core_values || !core_addrs || !aux_values || !aux_addrs) { LOG_ERROR("Unable to allocate memory"); retval = ERROR_FAIL; goto exit; } memset(core_values, 0xff, core_regs_size); memset(core_addrs, 0xff, core_regs_size); memset(aux_values, 0xff, aux_regs_size); memset(aux_addrs, 0xff, aux_regs_size); for (i = 0; i < arc->num_core_regs; i++) { struct reg *reg = &(reg_list[i]); struct arc_reg_desc *arc_reg = reg->arch_info; if (reg->valid && reg->exist && reg->dirty) { LOG_DEBUG("Will write regnum=%u", i); core_addrs[core_cnt] = arc_reg->arch_num; core_values[core_cnt] = target_buffer_get_u32(target, reg->value); core_cnt += 1; } } for (i = 0; i < arc->num_aux_regs; i++) { struct reg *reg = &(reg_list[arc->num_core_regs + i]); struct arc_reg_desc *arc_reg = reg->arch_info; if (reg->valid && reg->exist && reg->dirty) { LOG_DEBUG("Will write regnum=%lu", arc->num_core_regs + i); aux_addrs[aux_cnt] = arc_reg->arch_num; aux_values[aux_cnt] = target_buffer_get_u32(target, reg->value); aux_cnt += 1; } } /* Write data to target. * Check before write, if aux and core count is greater than 0. */ if (core_cnt > 0) { retval = arc_jtag_write_core_reg(&arc->jtag_info, core_addrs, core_cnt, core_values); if (retval != ERROR_OK) { LOG_ERROR("Attempt to write to core registers failed."); retval = ERROR_FAIL; goto exit; } } if (aux_cnt > 0) { retval = arc_jtag_write_aux_reg(&arc->jtag_info, aux_addrs, aux_cnt, aux_values); if (retval != ERROR_OK) { LOG_ERROR("Attempt to write to aux registers failed."); retval = ERROR_FAIL; goto exit; } } exit: free(core_values); free(core_addrs); free(aux_values); free(aux_addrs); return retval; } static int arc_enable_interrupts(struct target *target, int enable) { uint32_t value; struct arc_common *arc = target_to_arc(target); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value)); if (enable) { /* enable interrupts */ value |= SET_CORE_ENABLE_INTERRUPTS; CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); LOG_DEBUG("interrupts enabled"); } else { /* disable interrupts */ value &= ~SET_CORE_ENABLE_INTERRUPTS; CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); LOG_DEBUG("interrupts disabled"); } return ERROR_OK; } static int arc_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { struct arc_common *arc = target_to_arc(target); uint32_t resume_pc = 0; uint32_t value; struct reg *pc = &arc->core_and_aux_cache->reg_list[arc->pc_index_in_cache]; LOG_DEBUG("current:%i, address:0x%08" TARGET_PRIxADDR ", handle_breakpoints(not supported yet):%i," " debug_execution:%i", current, address, handle_breakpoints, debug_execution); /* We need to reset ARC cache variables so caches * would be invalidated and actual data * would be fetched from memory. */ CHECK_RETVAL(arc_reset_caches_states(target)); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* current = 1: continue on current PC, otherwise continue at <address> */ if (!current) { target_buffer_set_u32(target, pc->value, address); pc->dirty = 1; pc->valid = 1; LOG_DEBUG("Changing the value of current PC to 0x%08" TARGET_PRIxADDR, address); } if (!current) resume_pc = address; else resume_pc = target_buffer_get_u32(target, pc->value); CHECK_RETVAL(arc_restore_context(target)); LOG_DEBUG("Target resumes from PC=0x%" PRIx32 ", pc.dirty=%i, pc.valid=%i", resume_pc, pc->dirty, pc->valid); /* check if GDB tells to set our PC where to continue from */ if ((pc->valid == 1) && (resume_pc == target_buffer_get_u32(target, pc->value))) { value = target_buffer_get_u32(target, pc->value); LOG_DEBUG("resume Core (when start-core) with PC @:0x%08" PRIx32, value); CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_PC_REG, value)); } /* Restore IRQ state if not in debug_execution*/ if (!debug_execution) CHECK_RETVAL(arc_enable_interrupts(target, arc->irq_state)); else CHECK_RETVAL(arc_enable_interrupts(target, !debug_execution)); target->debug_reason = DBG_REASON_NOTHALTED; /* ready to get us going again */ target->state = TARGET_RUNNING; CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value)); value &= ~SET_CORE_HALT_BIT; /* clear the HALT bit */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); LOG_DEBUG("Core started to run"); /* registers are now invalid */ register_cache_invalidate(arc->core_and_aux_cache); if (!debug_execution) { target->state = TARGET_RUNNING; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); LOG_DEBUG("target resumed at 0x%08" PRIx32, resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED)); LOG_DEBUG("target debug resumed at 0x%08" PRIx32, resume_pc); } return ERROR_OK; } static int arc_init_target(struct command_context *cmd_ctx, struct target *target) { CHECK_RETVAL(arc_build_reg_cache(target)); CHECK_RETVAL(arc_build_bcr_reg_cache(target)); target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static void arc_free_reg_cache(struct reg_cache *cache) { free(cache->reg_list); free(cache); } static void arc_deinit_target(struct target *target) { struct arc_common *arc = target_to_arc(target); LOG_DEBUG("deinitialization of target"); if (arc->core_aux_cache_built) arc_free_reg_cache(arc->core_and_aux_cache); if (arc->bcr_cache_built) arc_free_reg_cache(arc->bcr_cache); struct arc_reg_data_type *type, *n; struct arc_reg_desc *desc, *k; /* Free arc-specific reg_data_types allocations*/ list_for_each_entry_safe_reverse(type, n, &arc->reg_data_types, list) { if (type->data_type.type_class == REG_TYPE_CLASS_STRUCT) { free(type->reg_type_struct_field); free(type->bitfields); free(type); } else if (type->data_type.type_class == REG_TYPE_CLASS_FLAGS) { free(type->reg_type_flags_field); free(type->bitfields); free(type); } } /* Free standard_gdb_types reg_data_types allocations */ type = list_first_entry(&arc->reg_data_types, struct arc_reg_data_type, list); free(type); list_for_each_entry_safe(desc, k, &arc->aux_reg_descriptions, list) free_reg_desc(desc); list_for_each_entry_safe(desc, k, &arc->core_reg_descriptions, list) free_reg_desc(desc); list_for_each_entry_safe(desc, k, &arc->bcr_reg_descriptions, list) free_reg_desc(desc); free(arc->actionpoints_list); free(arc); } static int arc_target_create(struct target *target, Jim_Interp *interp) { struct arc_common *arc = calloc(1, sizeof(*arc)); if (!arc) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; } LOG_DEBUG("Entering"); CHECK_RETVAL(arc_init_arch_info(target, arc, target->tap)); return ERROR_OK; } /** * Write 4-byte instruction to memory. This is like target_write_u32, however * in case of little endian ARC instructions are in middle endian format, not * little endian, so different type of conversion should be done. * Middle endian: instruction "aabbccdd", stored as "bbaaddcc" */ static int arc_write_instruction_u32(struct target *target, uint32_t address, uint32_t instr) { uint8_t value_buf[4]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } LOG_DEBUG("Address: 0x%08" PRIx32 ", value: 0x%08" PRIx32, address, instr); if (target->endianness == TARGET_LITTLE_ENDIAN) arc_h_u32_to_me(value_buf, instr); else h_u32_to_be(value_buf, instr); CHECK_RETVAL(target_write_buffer(target, address, 4, value_buf)); return ERROR_OK; } /** * Read 32-bit instruction from memory. It is like target_read_u32, however in * case of little endian ARC instructions are in middle endian format, so * different type of conversion should be done. */ static int arc_read_instruction_u32(struct target *target, uint32_t address, uint32_t *value) { uint8_t value_buf[4]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } *value = 0; CHECK_RETVAL(target_read_buffer(target, address, 4, value_buf)); if (target->endianness == TARGET_LITTLE_ENDIAN) *value = arc_me_to_h_u32(value_buf); else *value = be_to_h_u32(value_buf); LOG_DEBUG("Address: 0x%08" PRIx32 ", value: 0x%08" PRIx32, address, *value); return ERROR_OK; } /* Actionpoint mechanism allows to setup HW breakpoints * and watchpoints. Each actionpoint is controlled by * 3 aux registers: Actionpoint(AP) match mask(AP_AMM), AP match value(AP_AMV) * and AP control(AC). * This function is for setting/unsetting actionpoints: * at - actionpoint target: trigger on mem/reg access * tt - transaction type : trigger on r/w. */ static int arc_configure_actionpoint(struct target *target, uint32_t ap_num, uint32_t match_value, uint32_t control_tt, uint32_t control_at) { struct arc_common *arc = target_to_arc(target); if (control_tt != AP_AC_TT_DISABLE) { if (arc->actionpoints_num_avail < 1) { LOG_ERROR("No free actionpoints, maximum amount is %u", arc->actionpoints_num); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* Names of register to set - 24 chars should be enough. Looks a little * bit out-of-place for C code, but makes it aligned to the bigger * concept of "ARC registers are defined in TCL" as far as possible. */ char ap_amv_reg_name[24], ap_amm_reg_name[24], ap_ac_reg_name[24]; snprintf(ap_amv_reg_name, 24, "ap_amv%" PRIu32, ap_num); snprintf(ap_amm_reg_name, 24, "ap_amm%" PRIu32, ap_num); snprintf(ap_ac_reg_name, 24, "ap_ac%" PRIu32, ap_num); CHECK_RETVAL(arc_set_register_value(target, ap_amv_reg_name, match_value)); CHECK_RETVAL(arc_set_register_value(target, ap_amm_reg_name, 0)); CHECK_RETVAL(arc_set_register_value(target, ap_ac_reg_name, control_tt | control_at)); arc->actionpoints_num_avail--; } else { char ap_ac_reg_name[24]; snprintf(ap_ac_reg_name, 24, "ap_ac%" PRIu32, ap_num); CHECK_RETVAL(arc_set_register_value(target, ap_ac_reg_name, AP_AC_TT_DISABLE)); arc->actionpoints_num_avail++; } return ERROR_OK; } static int arc_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } if (breakpoint->type == BKPT_SOFT) { LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); if (breakpoint->length == 4) { uint32_t verify = 0xffffffff; CHECK_RETVAL(target_read_buffer(target, breakpoint->address, breakpoint->length, breakpoint->orig_instr)); CHECK_RETVAL(arc_write_instruction_u32(target, breakpoint->address, ARC_SDBBP_32)); CHECK_RETVAL(arc_read_instruction_u32(target, breakpoint->address, &verify)); if (verify != ARC_SDBBP_32) { LOG_ERROR("Unable to set 32bit breakpoint at address @0x%" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_FAIL; } } else if (breakpoint->length == 2) { uint16_t verify = 0xffff; CHECK_RETVAL(target_read_buffer(target, breakpoint->address, breakpoint->length, breakpoint->orig_instr)); CHECK_RETVAL(target_write_u16(target, breakpoint->address, ARC_SDBBP_16)); CHECK_RETVAL(target_read_u16(target, breakpoint->address, &verify)); if (verify != ARC_SDBBP_16) { LOG_ERROR("Unable to set 16bit breakpoint at address @0x%" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_FAIL; } } else { LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4"); return ERROR_COMMAND_ARGUMENT_INVALID; } breakpoint->is_set = true; } else if (breakpoint->type == BKPT_HARD) { struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; unsigned int bp_num; for (bp_num = 0; bp_num < arc->actionpoints_num; bp_num++) { if (!ap_list[bp_num].used) break; } if (bp_num >= arc->actionpoints_num) { LOG_ERROR("No free actionpoints, maximum amount is %u", arc->actionpoints_num); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } int retval = arc_configure_actionpoint(target, bp_num, breakpoint->address, AP_AC_TT_READWRITE, AP_AC_AT_INST_ADDR); if (retval == ERROR_OK) { breakpoint_hw_set(breakpoint, bp_num); ap_list[bp_num].used = 1; ap_list[bp_num].bp_value = breakpoint->address; ap_list[bp_num].type = ARC_AP_BREAKPOINT; LOG_DEBUG("bpid: %" PRIu32 ", bp_num %u bp_value 0x%" PRIx32, breakpoint->unique_id, bp_num, ap_list[bp_num].bp_value); } } else { LOG_DEBUG("ERROR: setting unknown breakpoint type"); return ERROR_FAIL; } /* core instruction cache is now invalid. */ CHECK_RETVAL(arc_cache_invalidate(target)); return ERROR_OK; } static int arc_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval = ERROR_OK; if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_SOFT) { /* restore original instruction (kept in target endianness) */ LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); if (breakpoint->length == 4) { uint32_t current_instr; /* check that user program has not modified breakpoint instruction */ CHECK_RETVAL(arc_read_instruction_u32(target, breakpoint->address, ¤t_instr)); if (current_instr == ARC_SDBBP_32) { retval = target_write_buffer(target, breakpoint->address, breakpoint->length, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } else { LOG_WARNING("Software breakpoint @0x%" TARGET_PRIxADDR " has been overwritten outside of debugger." "Expected: @0x%x, got: @0x%" PRIx32, breakpoint->address, ARC_SDBBP_32, current_instr); } } else if (breakpoint->length == 2) { uint16_t current_instr; /* check that user program has not modified breakpoint instruction */ CHECK_RETVAL(target_read_u16(target, breakpoint->address, ¤t_instr)); if (current_instr == ARC_SDBBP_16) { retval = target_write_buffer(target, breakpoint->address, breakpoint->length, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } else { LOG_WARNING("Software breakpoint @0x%" TARGET_PRIxADDR " has been overwritten outside of debugger. " "Expected: 0x%04x, got: 0x%04" PRIx16, breakpoint->address, ARC_SDBBP_16, current_instr); } } else { LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4"); return ERROR_COMMAND_ARGUMENT_INVALID; } breakpoint->is_set = false; } else if (breakpoint->type == BKPT_HARD) { struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; unsigned int bp_num = breakpoint->number; if (bp_num >= arc->actionpoints_num) { LOG_DEBUG("Invalid actionpoint ID: %u in breakpoint: %" PRIu32, bp_num, breakpoint->unique_id); return ERROR_OK; } retval = arc_configure_actionpoint(target, bp_num, breakpoint->address, AP_AC_TT_DISABLE, AP_AC_AT_INST_ADDR); if (retval == ERROR_OK) { breakpoint->is_set = false; ap_list[bp_num].used = 0; ap_list[bp_num].bp_value = 0; LOG_DEBUG("bpid: %" PRIu32 " - released actionpoint ID: %u", breakpoint->unique_id, bp_num); } } else { LOG_DEBUG("ERROR: unsetting unknown breakpoint type"); return ERROR_FAIL; } /* core instruction cache is now invalid. */ CHECK_RETVAL(arc_cache_invalidate(target)); return retval; } static int arc_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state == TARGET_HALTED) { return arc_set_breakpoint(target, breakpoint); } else { LOG_WARNING(" > core was not halted, please try again."); return ERROR_TARGET_NOT_HALTED; } } static int arc_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state == TARGET_HALTED) { if (breakpoint->is_set) CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint)); } else { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } return ERROR_OK; } static void arc_reset_actionpoints(struct target *target) { struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; struct breakpoint *next_b; struct watchpoint *next_w; while (target->breakpoints) { next_b = target->breakpoints->next; arc_remove_breakpoint(target, target->breakpoints); free(target->breakpoints->orig_instr); free(target->breakpoints); target->breakpoints = next_b; } while (target->watchpoints) { next_w = target->watchpoints->next; arc_remove_watchpoint(target, target->watchpoints); free(target->watchpoints); target->watchpoints = next_w; } for (unsigned int i = 0; i < arc->actionpoints_num; i++) { if ((ap_list[i].used) && (ap_list[i].reg_address)) arc_remove_auxreg_actionpoint(target, ap_list[i].reg_address); } } int arc_set_actionpoints_num(struct target *target, uint32_t ap_num) { LOG_DEBUG("target=%s actionpoints=%" PRIu32, target_name(target), ap_num); struct arc_common *arc = target_to_arc(target); /* Make sure that there are no enabled actionpoints in target. */ arc_reset_actionpoints(target); /* Assume that all points have been removed from target. */ free(arc->actionpoints_list); arc->actionpoints_num_avail = ap_num; arc->actionpoints_num = ap_num; /* calloc can be safely called when ncount == 0. */ arc->actionpoints_list = calloc(ap_num, sizeof(struct arc_actionpoint)); if (!arc->actionpoints_list) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; } return ERROR_OK; } int arc_add_auxreg_actionpoint(struct target *target, uint32_t auxreg_addr, uint32_t transaction) { unsigned int ap_num = 0; int retval = ERROR_OK; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; while (ap_list[ap_num].used) ap_num++; if (ap_num >= arc->actionpoints_num) { LOG_ERROR("No actionpoint free, maximum amount is %u", arc->actionpoints_num); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = arc_configure_actionpoint(target, ap_num, auxreg_addr, transaction, AP_AC_AT_AUXREG_ADDR); if (retval == ERROR_OK) { ap_list[ap_num].used = 1; ap_list[ap_num].reg_address = auxreg_addr; } return retval; } int arc_remove_auxreg_actionpoint(struct target *target, uint32_t auxreg_addr) { int retval = ERROR_OK; bool ap_found = false; unsigned int ap_num = 0; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; while ((ap_list[ap_num].used) && (ap_num < arc->actionpoints_num)) { if (ap_list[ap_num].reg_address == auxreg_addr) { ap_found = true; break; } ap_num++; } if (ap_found) { retval = arc_configure_actionpoint(target, ap_num, auxreg_addr, AP_AC_TT_DISABLE, AP_AC_AT_AUXREG_ADDR); if (retval == ERROR_OK) { ap_list[ap_num].used = 0; ap_list[ap_num].bp_value = 0; } } else { LOG_ERROR("Register actionpoint not found"); } return retval; } static int arc_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { unsigned int wp_num; struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } for (wp_num = 0; wp_num < arc->actionpoints_num; wp_num++) { if (!ap_list[wp_num].used) break; } if (wp_num >= arc->actionpoints_num) { LOG_ERROR("No free actionpoints, maximum amount is %u", arc->actionpoints_num); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (watchpoint->length != 4) { LOG_ERROR("Only watchpoints of length 4 are supported"); return ERROR_TARGET_UNALIGNED_ACCESS; } int enable = AP_AC_TT_DISABLE; switch (watchpoint->rw) { case WPT_READ: enable = AP_AC_TT_READ; break; case WPT_WRITE: enable = AP_AC_TT_WRITE; break; case WPT_ACCESS: enable = AP_AC_TT_READWRITE; break; default: LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); return ERROR_FAIL; } int retval = arc_configure_actionpoint(target, wp_num, watchpoint->address, enable, AP_AC_AT_MEMORY_ADDR); if (retval == ERROR_OK) { watchpoint_set(watchpoint, wp_num); ap_list[wp_num].used = 1; ap_list[wp_num].bp_value = watchpoint->address; ap_list[wp_num].type = ARC_AP_WATCHPOINT; LOG_DEBUG("wpid: %" PRIu32 ", wp_num %u wp_value 0x%" PRIx32, watchpoint->unique_id, wp_num, ap_list[wp_num].bp_value); } return retval; } static int arc_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { /* get pointers to arch-specific information */ struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } unsigned int wp_num = watchpoint->number; if (wp_num >= arc->actionpoints_num) { LOG_DEBUG("Invalid actionpoint ID: %u in watchpoint: %" PRIu32, wp_num, watchpoint->unique_id); return ERROR_OK; } int retval = arc_configure_actionpoint(target, wp_num, watchpoint->address, AP_AC_TT_DISABLE, AP_AC_AT_MEMORY_ADDR); if (retval == ERROR_OK) { watchpoint->is_set = false; ap_list[wp_num].used = 0; ap_list[wp_num].bp_value = 0; LOG_DEBUG("wpid: %" PRIu32 " - releasing actionpoint ID: %u", watchpoint->unique_id, wp_num); } return retval; } static int arc_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } CHECK_RETVAL(arc_set_watchpoint(target, watchpoint)); return ERROR_OK; } static int arc_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (watchpoint->is_set) CHECK_RETVAL(arc_unset_watchpoint(target, watchpoint)); return ERROR_OK; } static int arc_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { assert(target); assert(hit_watchpoint); struct arc_actionpoint *actionpoint = NULL; CHECK_RETVAL(get_current_actionpoint(target, &actionpoint)); if (actionpoint) { if (!actionpoint->used) LOG_WARNING("Target halted by unused actionpoint."); /* If this check fails - that is some sort of an error in OpenOCD. */ if (actionpoint->type != ARC_AP_WATCHPOINT) LOG_WARNING("Target halted by breakpoint, but is treated as a watchpoint."); for (struct watchpoint *watchpoint = target->watchpoints; watchpoint; watchpoint = watchpoint->next) { if (actionpoint->bp_value == watchpoint->address) { *hit_watchpoint = watchpoint; LOG_DEBUG("Hit watchpoint, wpid: %" PRIu32 ", watchpoint num: %u", watchpoint->unique_id, watchpoint->number); return ERROR_OK; } } } return ERROR_FAIL; } /* Helper function which switches core to single_step mode by * doing aux r/w operations. */ static int arc_config_step(struct target *target, int enable_step) { uint32_t value; struct arc_common *arc = target_to_arc(target); /* enable core debug step mode */ if (enable_step) { CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value)); value &= ~SET_CORE_AE_BIT; /* clear the AE bit */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); LOG_DEBUG(" [status32:0x%08" PRIx32 "]", value); /* Doing read-modify-write, because DEBUG might contain manually set * bits like UB or ED, which should be preserved. */ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, &value)); value |= SET_CORE_SINGLE_INSTR_STEP; /* set the IS bit */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, value)); LOG_DEBUG("core debug step mode enabled [debug-reg:0x%08" PRIx32 "]", value); } else { /* disable core debug step mode */ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, &value)); value &= ~SET_CORE_SINGLE_INSTR_STEP; /* clear the IS bit */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, value)); LOG_DEBUG("core debug step mode disabled"); } return ERROR_OK; } static int arc_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { /* get pointers to arch-specific information */ struct arc_common *arc = target_to_arc(target); struct breakpoint *breakpoint = NULL; struct reg *pc = &(arc->core_and_aux_cache->reg_list[arc->pc_index_in_cache]); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u32(pc->value, 0, 32, address); pc->dirty = 1; pc->valid = 1; } LOG_DEBUG("Target steps one instruction from PC=0x%" PRIx32, buf_get_u32(pc->value, 0, 32)); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { breakpoint = breakpoint_find(target, buf_get_u32(pc->value, 0, 32)); if (breakpoint) CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint)); } /* restore context */ CHECK_RETVAL(arc_restore_context(target)); target->debug_reason = DBG_REASON_SINGLESTEP; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); /* disable interrupts while stepping */ CHECK_RETVAL(arc_enable_interrupts(target, 0)); /* do a single step */ CHECK_RETVAL(arc_config_step(target, 1)); /* make sure we done our step */ alive_sleep(1); /* registers are now invalid */ register_cache_invalidate(arc->core_and_aux_cache); if (breakpoint) CHECK_RETVAL(arc_set_breakpoint(target, breakpoint)); LOG_DEBUG("target stepped "); target->state = TARGET_HALTED; /* Saving context */ CHECK_RETVAL(arc_debug_entry(target)); CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); return ERROR_OK; } /* This function invalidates icache. */ static int arc_icache_invalidate(struct target *target) { uint32_t value; struct arc_common *arc = target_to_arc(target); /* Don't waste time if already done. */ if (!arc->has_icache || arc->icache_invalidated) return ERROR_OK; LOG_DEBUG("Invalidating I$."); value = IC_IVIC_INVALIDATE; /* invalidate I$ */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_IC_IVIC_REG, value)); arc->icache_invalidated = true; return ERROR_OK; } /* This function invalidates dcache */ static int arc_dcache_invalidate(struct target *target) { uint32_t value, dc_ctrl_value; struct arc_common *arc = target_to_arc(target); if (!arc->has_dcache || arc->dcache_invalidated) return ERROR_OK; LOG_DEBUG("Invalidating D$."); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, &value)); dc_ctrl_value = value; value &= ~DC_CTRL_IM; /* set DC_CTRL invalidate mode to invalidate-only (no flushing!!) */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, value)); value = DC_IVDC_INVALIDATE; /* invalidate D$ */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_IVDC_REG, value)); /* restore DC_CTRL invalidate mode */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, dc_ctrl_value)); arc->dcache_invalidated = true; return ERROR_OK; } /* This function invalidates l2 cache. */ static int arc_l2cache_invalidate(struct target *target) { uint32_t value, slc_ctrl_value; struct arc_common *arc = target_to_arc(target); if (!arc->has_l2cache || arc->l2cache_invalidated) return ERROR_OK; LOG_DEBUG("Invalidating L2$."); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, &value)); slc_ctrl_value = value; value &= ~L2_CTRL_IM; /* set L2_CTRL invalidate mode to invalidate-only (no flushing!!) */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, value)); /* invalidate L2$ */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_INV, L2_INV_IV)); /* Wait until invalidate operation ends */ do { LOG_DEBUG("Waiting for invalidation end."); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, &value)); } while (value & L2_CTRL_BS); /* restore L2_CTRL invalidate mode */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, slc_ctrl_value)); arc->l2cache_invalidated = true; return ERROR_OK; } int arc_cache_invalidate(struct target *target) { CHECK_RETVAL(arc_icache_invalidate(target)); CHECK_RETVAL(arc_dcache_invalidate(target)); CHECK_RETVAL(arc_l2cache_invalidate(target)); return ERROR_OK; } /* Flush data cache. This function is cheap to call and return quickly if D$ * already has been flushed since target had been halted. JTAG debugger reads * values directly from memory, bypassing cache, so if there are unflushed * lines debugger will read invalid values, which will cause a lot of troubles. * */ static int arc_dcache_flush(struct target *target) { uint32_t value, dc_ctrl_value; bool has_to_set_dc_ctrl_im; struct arc_common *arc = target_to_arc(target); /* Don't waste time if already done. */ if (!arc->has_dcache || arc->dcache_flushed) return ERROR_OK; LOG_DEBUG("Flushing D$."); /* Store current value of DC_CTRL */ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, &dc_ctrl_value)); /* Set DC_CTRL invalidate mode to flush (if not already set) */ has_to_set_dc_ctrl_im = (dc_ctrl_value & DC_CTRL_IM) == 0; if (has_to_set_dc_ctrl_im) { value = dc_ctrl_value | DC_CTRL_IM; CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, value)); } /* Flush D$ */ value = DC_IVDC_INVALIDATE; CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_IVDC_REG, value)); /* Restore DC_CTRL invalidate mode (even of flush failed) */ if (has_to_set_dc_ctrl_im) CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, dc_ctrl_value)); arc->dcache_flushed = true; return ERROR_OK; } /* This function flushes l2cache. */ static int arc_l2cache_flush(struct target *target) { uint32_t value; struct arc_common *arc = target_to_arc(target); /* Don't waste time if already done. */ if (!arc->has_l2cache || arc->l2cache_flushed) return ERROR_OK; LOG_DEBUG("Flushing L2$."); /* Flush L2 cache */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_FLUSH, L2_FLUSH_FL)); /* Wait until flush operation ends */ do { LOG_DEBUG("Waiting for flushing end."); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, &value)); } while (value & L2_CTRL_BS); arc->l2cache_flushed = true; return ERROR_OK; } int arc_cache_flush(struct target *target) { CHECK_RETVAL(arc_dcache_flush(target)); CHECK_RETVAL(arc_l2cache_flush(target)); return ERROR_OK; } /* ARC v2 target */ struct target_type arcv2_target = { .name = "arcv2", .poll = arc_poll, .arch_state = arc_arch_state, /* TODO That seems like something similar to metaware hostlink, so perhaps * we can exploit this in the future. */ .target_request_data = NULL, .halt = arc_halt, .resume = arc_resume, .step = arc_step, .assert_reset = arc_assert_reset, .deassert_reset = arc_deassert_reset, /* TODO Implement soft_reset_halt */ .soft_reset_halt = NULL, .get_gdb_reg_list = arc_get_gdb_reg_list, .read_memory = arc_mem_read, .write_memory = arc_mem_write, .checksum_memory = NULL, .blank_check_memory = NULL, .add_breakpoint = arc_add_breakpoint, .add_context_breakpoint = NULL, .add_hybrid_breakpoint = NULL, .remove_breakpoint = arc_remove_breakpoint, .add_watchpoint = arc_add_watchpoint, .remove_watchpoint = arc_remove_watchpoint, .hit_watchpoint = arc_hit_watchpoint, .run_algorithm = NULL, .start_algorithm = NULL, .wait_algorithm = NULL, .commands = arc_monitor_command_handlers, .target_create = arc_target_create, .init_target = arc_init_target, .deinit_target = arc_deinit_target, .examine = arc_examine, .virt2phys = NULL, .read_phys_memory = NULL, .write_phys_memory = NULL, .mmu = NULL, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arc.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Mischa Jonker <mischa.jonker@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARC_H #define OPENOCD_TARGET_ARC_H #include <helper/time_support.h> #include <jtag/jtag.h> #include "algorithm.h" #include "breakpoints.h" #include "jtag/interface.h" #include "register.h" #include "target.h" #include "target_request.h" #include "target_type.h" #include "helper/bits.h" #include "arc_jtag.h" #include "arc_cmd.h" #include "arc_mem.h" #define ARC_COMMON_MAGIC 0xB32EB324U /* just a unique number */ #define AUX_DEBUG_REG 0x5 #define AUX_PC_REG 0x6 #define AUX_STATUS32_REG 0xA #define SET_CORE_FORCE_HALT BIT(1) #define SET_CORE_HALT_BIT BIT(0) /* STATUS32[0] = H field */ #define SET_CORE_ENABLE_INTERRUPTS BIT(31) /* STATUS32[5] or AE bit indicates if the processor is in exception state */ #define SET_CORE_AE_BIT BIT(5) /* Single instruction step bit in Debug register */ #define SET_CORE_SINGLE_INSTR_STEP BIT(11) #define AUX_STATUS32_REG_HALT_BIT BIT(0) #define AUX_STATUS32_REG_IE_BIT BIT(31) /* STATUS32[31] = IE field */ /* ARC register numbers */ enum { ARC_R0, ARC_R1, ARC_R2, ARC_R3, ARC_R4, ARC_R5, ARC_R6, ARC_R7, ARC_R8, ARC_R9, ARC_R10, ARC_R11, ARC_R12, ARC_R13, ARC_R14, ARC_R15, ARC_R16, ARC_R17, ARC_R18, ARC_R19, ARC_R20, ARC_R21, ARC_R22, ARC_R23, ARC_R24, ARC_R25, ARC_GP = 26, ARC_FP = 27, ARC_SP = 28, ARC_ILINK = 29, ARC_R30, ARC_BLINK = 31, ARC_LP_COUNT = 60, /* Reserved registers */ ARC_R61 = 61, ARC_R62 = 62, ARC_PCL = 63, ARC_PC = 64, ARC_LP_START = 65, ARC_LP_END = 66, ARC_STATUS32 = 67, }; #define CORE_REG_MAX_NUMBER (63) /* Limit reg_type/reg_type_field name to 20 symbols */ #define REG_TYPE_MAX_NAME_LENGTH 20 /* ARC 32bits opcodes */ #define ARC_SDBBP_32 0x256F003FU /* BRK */ /* ARC 16bits opcodes */ #define ARC_SDBBP_16 0x7FFF /* BRK_S */ /* Cache registers */ #define AUX_IC_IVIC_REG 0X10 #define IC_IVIC_INVALIDATE 0XFFFFFFFF #define AUX_DC_IVDC_REG 0X47 #define DC_IVDC_INVALIDATE BIT(0) #define AUX_DC_CTRL_REG 0X48 #define DC_CTRL_IM BIT(6) /* L2 cache registers */ #define SLC_AUX_CACHE_CTRL 0x903 #define L2_CTRL_IM BIT(6) #define L2_CTRL_BS BIT(8) /* Busy flag */ #define SLC_AUX_CACHE_FLUSH 0x904 #define L2_FLUSH_FL BIT(0) #define SLC_AUX_CACHE_INV 0x905 #define L2_INV_IV BIT(0) /* Action Point */ #define AP_AC_AT_INST_ADDR 0x0 #define AP_AC_AT_MEMORY_ADDR 0x2 #define AP_AC_AT_AUXREG_ADDR 0x4 #define AP_AC_TT_DISABLE 0x00 #define AP_AC_TT_WRITE 0x10 #define AP_AC_TT_READ 0x20 #define AP_AC_TT_READWRITE 0x30 struct arc_reg_bitfield { struct reg_data_type_bitfield bitfield; char name[REG_TYPE_MAX_NAME_LENGTH]; }; /* Register data type */ struct arc_reg_data_type { struct list_head list; struct reg_data_type data_type; struct reg_data_type_flags data_type_flags; struct reg_data_type_struct data_type_struct; char data_type_id[REG_TYPE_MAX_NAME_LENGTH]; struct arc_reg_bitfield *bitfields; union { struct reg_data_type_struct_field *reg_type_struct_field; struct reg_data_type_flags_field *reg_type_flags_field; }; }; /* Standard GDB register types */ static const struct reg_data_type standard_gdb_types[] = { { .type = REG_TYPE_INT, .id = "int" }, { .type = REG_TYPE_INT8, .id = "int8" }, { .type = REG_TYPE_INT16, .id = "int16" }, { .type = REG_TYPE_INT32, .id = "int32" }, { .type = REG_TYPE_INT64, .id = "int64" }, { .type = REG_TYPE_INT128, .id = "int128" }, { .type = REG_TYPE_UINT8, .id = "uint8" }, { .type = REG_TYPE_UINT16, .id = "uint16" }, { .type = REG_TYPE_UINT32, .id = "uint32" }, { .type = REG_TYPE_UINT64, .id = "uint64" }, { .type = REG_TYPE_UINT128, .id = "uint128" }, { .type = REG_TYPE_CODE_PTR, .id = "code_ptr" }, { .type = REG_TYPE_DATA_PTR, .id = "data_ptr" }, { .type = REG_TYPE_FLOAT, .id = "float" }, { .type = REG_TYPE_IEEE_SINGLE, .id = "ieee_single" }, { .type = REG_TYPE_IEEE_DOUBLE, .id = "ieee_double" }, }; enum arc_actionpointype { ARC_AP_BREAKPOINT, ARC_AP_WATCHPOINT, }; /* Actionpoint related fields */ struct arc_actionpoint { int used; uint32_t bp_value; uint32_t reg_address; enum arc_actionpointype type; }; struct arc_common { unsigned int common_magic; struct arc_jtag jtag_info; struct reg_cache *core_and_aux_cache; struct reg_cache *bcr_cache; /* Cache control */ bool has_dcache; bool has_icache; bool has_l2cache; /* If true, then D$ has been already flushed since core has been * halted. */ bool dcache_flushed; /* If true, then L2 has been already flushed since core has been * halted. */ bool l2cache_flushed; /* If true, then caches have been already flushed since core has been * halted. */ bool icache_invalidated; bool dcache_invalidated; bool l2cache_invalidated; /* Indicate if cache was built (for deinit function) */ bool core_aux_cache_built; bool bcr_cache_built; /* Closely Coupled memory(CCM) regions for performance-critical * code (optional). */ uint32_t iccm0_start; uint32_t iccm0_end; uint32_t iccm1_start; uint32_t iccm1_end; uint32_t dccm_start; uint32_t dccm_end; int irq_state; /* Register descriptions */ struct list_head reg_data_types; struct list_head core_reg_descriptions; struct list_head aux_reg_descriptions; struct list_head bcr_reg_descriptions; unsigned long num_regs; unsigned long num_core_regs; unsigned long num_aux_regs; unsigned long num_bcr_regs; unsigned long last_general_reg; /* PC register location in register cache. */ unsigned long pc_index_in_cache; /* DEBUG register location in register cache. */ unsigned long debug_index_in_cache; /* Actionpoints */ unsigned int actionpoints_num; unsigned int actionpoints_num_avail; struct arc_actionpoint *actionpoints_list; }; /* Borrowed from nds32.h */ #define CHECK_RETVAL(action) \ do { \ int __retval = (action); \ if (__retval != ERROR_OK) { \ LOG_DEBUG("error while calling \"%s\"", \ # action); \ return __retval; \ } \ } while (0) static inline struct arc_common *target_to_arc(struct target *target) { return target->arch_info; } /* ----- Inlined functions ------------------------------------------------- */ /** * Convert data in host endianness to the middle endian. This is required to * write 4-byte instructions. */ static inline void arc_h_u32_to_me(uint8_t *buf, int val) { buf[1] = (uint8_t) (val >> 24); buf[0] = (uint8_t) (val >> 16); buf[3] = (uint8_t) (val >> 8); buf[2] = (uint8_t) (val >> 0); } /** * Convert data in middle endian to host endian. This is required to read 32-bit * instruction from little endian ARCs. */ static inline uint32_t arc_me_to_h_u32(const uint8_t *buf) { return (uint32_t)(buf[2] | buf[3] << 8 | buf[0] << 16 | buf[1] << 24); } /* ARC Register description */ struct arc_reg_desc { struct target *target; /* Register name */ char *name; /* Actual place of storing reg_value */ uint8_t reg_value[4]; /* Actual place of storing register feature */ struct reg_feature feature; /* GDB XML feature */ char *gdb_xml_feature; /* Is this a register in g/G-packet? */ bool is_general; /* Architectural number: core reg num or AUX reg num */ uint32_t arch_num; /* Core or AUX register? */ bool is_core; /* Build configuration register? */ bool is_bcr; /* Data type */ struct reg_data_type *data_type; struct list_head list; }; /* Error codes */ #define ERROR_ARC_REGISTER_NOT_FOUND (-700) #define ERROR_ARC_REGISTER_FIELD_NOT_FOUND (-701) #define ERROR_ARC_REGISTER_IS_NOT_STRUCT (-702) #define ERROR_ARC_FIELD_IS_NOT_BITFIELD (-703) #define ERROR_ARC_REGTYPE_NOT_FOUND (-704) void free_reg_desc(struct arc_reg_desc *r); void arc_reg_data_type_add(struct target *target, struct arc_reg_data_type *data_type); int arc_reg_add(struct target *target, struct arc_reg_desc *arc_reg, const char * const type_name, const size_t type_name_len); struct reg *arc_reg_get_by_name(struct reg_cache *first, const char *name, bool search_all); int arc_reg_get_field(struct target *target, const char *reg_name, const char *field_name, uint32_t *value_ptr); int arc_cache_flush(struct target *target); int arc_cache_invalidate(struct target *target); int arc_add_auxreg_actionpoint(struct target *target, uint32_t auxreg_addr, uint32_t transaction); int arc_remove_auxreg_actionpoint(struct target *target, uint32_t auxreg_addr); int arc_set_actionpoints_num(struct target *target, uint32_t ap_num); #endif /* OPENOCD_TARGET_ARC_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arc_cmd.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Mischa Jonker <mischa.jonker@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arc.h" #include <helper/nvp.h> /* -------------------------------------------------------------------------- * * ARC targets expose command interface. * It can be accessed via GDB through the (gdb) monitor command. * * ------------------------------------------------------------------------- */ enum add_reg_types { CFG_ADD_REG_TYPE_FLAG, CFG_ADD_REG_TYPE_STRUCT, }; /* Add flags register data type */ enum add_reg_type_flags { CFG_ADD_REG_TYPE_FLAGS_NAME, CFG_ADD_REG_TYPE_FLAGS_FLAG, }; static const struct nvp nvp_add_reg_type_flags_opts[] = { { .name = "-name", .value = CFG_ADD_REG_TYPE_FLAGS_NAME }, { .name = "-flag", .value = CFG_ADD_REG_TYPE_FLAGS_FLAG }, { .name = NULL, .value = -1 } }; /* Helper function to check if all field required for register * are set up */ static const char *validate_register(const struct arc_reg_desc * const reg, bool arch_num_set) { /* Check that required fields are set */ if (!reg->name) return "-name option is required"; if (!reg->gdb_xml_feature) return "-feature option is required"; if (!arch_num_set) return "-num option is required"; if (reg->is_bcr && reg->is_core) return "Register cannot be both -core and -bcr."; return NULL; } static COMMAND_HELPER(arc_handle_add_reg_type_flags_ops, struct arc_reg_data_type *type) { struct reg_data_type_flags_field *fields = type->reg_type_flags_field; struct arc_reg_bitfield *bitfields = type->bitfields; struct reg_data_type_flags *flags = &type->data_type_flags; unsigned int cur_field = 0; while (CMD_ARGC) { const struct nvp *n = nvp_name2value(nvp_add_reg_type_flags_opts, CMD_ARGV[0]); CMD_ARGC--; CMD_ARGV++; switch (n->value) { case CFG_ADD_REG_TYPE_FLAGS_NAME: if (!CMD_ARGC) return ERROR_COMMAND_ARGUMENT_INVALID; const char *name = CMD_ARGV[0]; CMD_ARGC--; CMD_ARGV++; if (strlen(name) >= REG_TYPE_MAX_NAME_LENGTH) { command_print(CMD, "Reg type name is too big."); return ERROR_COMMAND_ARGUMENT_INVALID; } strcpy((void *)type->data_type.id, name); break; case CFG_ADD_REG_TYPE_FLAGS_FLAG: if (CMD_ARGC < 2) return ERROR_COMMAND_ARGUMENT_INVALID; uint32_t val; const char *field_name = CMD_ARGV[0]; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], val); CMD_ARGC -= 2; CMD_ARGV += 2; bitfields[cur_field].bitfield.start = val; bitfields[cur_field].bitfield.end = val; if (strlen(field_name) >= REG_TYPE_MAX_NAME_LENGTH) { command_print(CMD, "Reg type field_name is too big."); return ERROR_COMMAND_ARGUMENT_INVALID; } fields[cur_field].name = bitfields[cur_field].name; strcpy(bitfields[cur_field].name, field_name); fields[cur_field].bitfield = &bitfields[cur_field].bitfield; if (cur_field > 0) fields[cur_field - 1].next = &fields[cur_field]; else flags->fields = fields; cur_field += 1; break; default: nvp_unknown_command_print(CMD, nvp_add_reg_type_flags_opts, NULL, CMD_ARGV[-1]); return ERROR_COMMAND_ARGUMENT_INVALID; } } if (!type->data_type.id) { command_print(CMD, "-name is a required option"); return ERROR_COMMAND_ARGUMENT_INVALID; } return ERROR_OK; } COMMAND_HANDLER(arc_handle_add_reg_type_flags) { int retval; LOG_DEBUG("-"); struct target *target = get_current_target(CMD_CTX); if (!target) { command_print(CMD, "No current target"); return ERROR_FAIL; } /* Check if the amount of arguments is not zero */ if (CMD_ARGC == 0) return ERROR_COMMAND_SYNTAX_ERROR; /* Estimate number of registers as (argc - 2)/3 as each -flag option has 2 * arguments while -name is required. */ unsigned int fields_sz = (CMD_ARGC - 2) / 3; /* The maximum amount of bitfields is 32 */ if (fields_sz > 32) { command_print(CMD, "The amount of bitfields exceed 32"); return ERROR_COMMAND_ARGUMENT_INVALID; } struct arc_reg_data_type *type = calloc(1, sizeof(*type)); struct reg_data_type_flags_field *fields = calloc(fields_sz, sizeof(*fields)); struct arc_reg_bitfield *bitfields = calloc(fields_sz, sizeof(*bitfields)); if (!type || !fields || !bitfields) { LOG_ERROR("Out of memory"); retval = ERROR_FAIL; goto fail; } struct reg_data_type_flags *flags = &type->data_type_flags; type->reg_type_flags_field = fields; /* Initialize type */ type->bitfields = bitfields; type->data_type.id = type->data_type_id; type->data_type.type = REG_TYPE_ARCH_DEFINED; type->data_type.type_class = REG_TYPE_CLASS_FLAGS; type->data_type.reg_type_flags = flags; flags->size = 4; /* For now ARC has only 32-bit registers */ retval = CALL_COMMAND_HANDLER(arc_handle_add_reg_type_flags_ops, type); if (retval != ERROR_OK) goto fail; arc_reg_data_type_add(target, type); LOG_DEBUG("added flags type {name=%s}", type->data_type.id); return ERROR_OK; fail: free(type); free(fields); free(bitfields); return retval; } /* Add struct register data type */ enum add_reg_type_struct { CFG_ADD_REG_TYPE_STRUCT_NAME, CFG_ADD_REG_TYPE_STRUCT_BITFIELD, }; static const struct nvp nvp_add_reg_type_struct_opts[] = { { .name = "-name", .value = CFG_ADD_REG_TYPE_STRUCT_NAME }, { .name = "-bitfield", .value = CFG_ADD_REG_TYPE_STRUCT_BITFIELD }, { .name = NULL, .value = -1 } }; COMMAND_HANDLER(arc_handle_set_aux_reg) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); if (!target) { command_print(CMD, "No current target"); return ERROR_FAIL; } /* Register number */ uint32_t regnum; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], regnum); /* Register value */ uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); struct arc_common *arc = target_to_arc(target); assert(arc); CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, regnum, value)); return ERROR_OK; } COMMAND_HANDLER(arc_handle_get_aux_reg) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); if (!target) { command_print(CMD, "No current target"); return ERROR_FAIL; } /* Register number */ uint32_t regnum; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], regnum); struct arc_common *arc = target_to_arc(target); assert(arc); uint32_t value; CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, regnum, &value)); command_print(CMD, "0x%" PRIx32, value); return ERROR_OK; } COMMAND_HANDLER(arc_handle_get_core_reg) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); if (!target) { command_print(CMD, "No current target"); return ERROR_FAIL; } /* Register number */ uint32_t regnum; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], regnum); if (regnum > CORE_REG_MAX_NUMBER || regnum == ARC_R61 || regnum == ARC_R62) { command_print(CMD, "Core register number %i " "is invalid. Must less then 64 and not 61 and 62.", regnum); return ERROR_COMMAND_ARGUMENT_INVALID; } struct arc_common *arc = target_to_arc(target); assert(arc); /* Read value */ uint32_t value; CHECK_RETVAL(arc_jtag_read_core_reg_one(&arc->jtag_info, regnum, &value)); command_print(CMD, "0x%" PRIx32, value); return ERROR_OK; } COMMAND_HANDLER(arc_handle_set_core_reg) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); if (!target) { command_print(CMD, "No current target"); return ERROR_FAIL; } /* Register number */ uint32_t regnum; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], regnum); if (regnum > CORE_REG_MAX_NUMBER || regnum == ARC_R61 || regnum == ARC_R62) { command_print(CMD, "Core register number %i " "is invalid. Must less then 64 and not 61 and 62.", regnum); return ERROR_COMMAND_ARGUMENT_INVALID; } /* Register value */ uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); struct arc_common *arc = target_to_arc(target); assert(arc); CHECK_RETVAL(arc_jtag_write_core_reg_one(&arc->jtag_info, regnum, value)); return ERROR_OK; } static const struct command_registration arc_jtag_command_group[] = { { .name = "get-aux-reg", .handler = arc_handle_get_aux_reg, .mode = COMMAND_EXEC, .help = "Get AUX register by number. This command does a " "raw JTAG request that bypasses OpenOCD register cache " "and thus is unsafe and can have unexpected consequences. " "Use at your own risk.", .usage = "<regnum>" }, { .name = "set-aux-reg", .handler = arc_handle_set_aux_reg, .mode = COMMAND_EXEC, .help = "Set AUX register by number. This command does a " "raw JTAG request that bypasses OpenOCD register cache " "and thus is unsafe and can have unexpected consequences. " "Use at your own risk.", .usage = "<regnum> <value>" }, { .name = "get-core-reg", .handler = arc_handle_get_core_reg, .mode = COMMAND_EXEC, .help = "Get/Set core register by number. This command does a " "raw JTAG request that bypasses OpenOCD register cache " "and thus is unsafe and can have unexpected consequences. " "Use at your own risk.", .usage = "<regnum> [<value>]" }, { .name = "set-core-reg", .handler = arc_handle_set_core_reg, .mode = COMMAND_EXEC, .help = "Get/Set core register by number. This command does a " "raw JTAG request that bypasses OpenOCD register cache " "and thus is unsafe and can have unexpected consequences. " "Use at your own risk.", .usage = "<regnum> [<value>]" }, COMMAND_REGISTRATION_DONE }; /* This function supports only bitfields. */ static COMMAND_HELPER(arc_handle_add_reg_type_struct_opts, struct arc_reg_data_type *type) { struct reg_data_type_struct_field *fields = type->reg_type_struct_field; struct arc_reg_bitfield *bitfields = type->bitfields; struct reg_data_type_struct *struct_type = &type->data_type_struct; unsigned int cur_field = 0; while (CMD_ARGC) { const struct nvp *n = nvp_name2value(nvp_add_reg_type_struct_opts, CMD_ARGV[0]); CMD_ARGC--; CMD_ARGV++; switch (n->value) { case CFG_ADD_REG_TYPE_STRUCT_NAME: if (!CMD_ARGC) return ERROR_COMMAND_ARGUMENT_INVALID; const char *name = CMD_ARGV[0]; CMD_ARGC--; CMD_ARGV++; if (strlen(name) >= REG_TYPE_MAX_NAME_LENGTH) { command_print(CMD, "Reg type name is too big."); return ERROR_COMMAND_ARGUMENT_INVALID; } strcpy((void *)type->data_type.id, name); break; case CFG_ADD_REG_TYPE_STRUCT_BITFIELD: if (CMD_ARGC < 3) return ERROR_COMMAND_ARGUMENT_INVALID; uint32_t start_pos, end_pos; const char *field_name = CMD_ARGV[0]; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], start_pos); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], end_pos); CMD_ARGC -= 3; CMD_ARGV += 3; bitfields[cur_field].bitfield.start = start_pos; bitfields[cur_field].bitfield.end = end_pos; bitfields[cur_field].bitfield.type = REG_TYPE_INT; if (strlen(field_name) >= REG_TYPE_MAX_NAME_LENGTH) { command_print(CMD, "Reg type field_name is too big."); return ERROR_COMMAND_ARGUMENT_INVALID; } fields[cur_field].name = bitfields[cur_field].name; strcpy(bitfields[cur_field].name, field_name); fields[cur_field].bitfield = &bitfields[cur_field].bitfield; fields[cur_field].use_bitfields = true; if (cur_field > 0) fields[cur_field - 1].next = &fields[cur_field]; else struct_type->fields = fields; cur_field += 1; break; default: nvp_unknown_command_print(CMD, nvp_add_reg_type_struct_opts, NULL, CMD_ARGV[-1]); return ERROR_COMMAND_ARGUMENT_INVALID; } } if (!type->data_type.id) { command_print(CMD, "-name is a required option"); return ERROR_COMMAND_ARGUMENT_INVALID; } return ERROR_OK; } COMMAND_HANDLER(arc_handle_add_reg_type_struct) { int retval; LOG_DEBUG("-"); struct target *target = get_current_target(CMD_CTX); if (!target) { command_print(CMD, "No current target"); return ERROR_FAIL; } /* Check if the amount of arguments is not zero */ if (CMD_ARGC == 0) return ERROR_COMMAND_SYNTAX_ERROR; /* Estimate number of registers as (argc - 2)/4 as each -bitfield option has 3 * arguments while -name is required. */ unsigned int fields_sz = (CMD_ARGC - 2) / 4; /* The maximum amount of bitfields is 32 */ if (fields_sz > 32) { command_print(CMD, "The amount of bitfields exceed 32"); return ERROR_COMMAND_ARGUMENT_INVALID; } struct arc_reg_data_type *type = calloc(1, sizeof(*type)); struct reg_data_type_struct_field *fields = calloc(fields_sz, sizeof(*fields)); struct arc_reg_bitfield *bitfields = calloc(fields_sz, sizeof(*bitfields)); if (!type || !fields || !bitfields) { LOG_ERROR("Out of memory"); retval = ERROR_FAIL; goto fail; } struct reg_data_type_struct *struct_type = &type->data_type_struct; type->reg_type_struct_field = fields; /* Initialize type */ type->data_type.id = type->data_type_id; type->bitfields = bitfields; type->data_type.type = REG_TYPE_ARCH_DEFINED; type->data_type.type_class = REG_TYPE_CLASS_STRUCT; type->data_type.reg_type_struct = struct_type; struct_type->size = 4; /* For now ARC has only 32-bit registers */ retval = CALL_COMMAND_HANDLER(arc_handle_add_reg_type_struct_opts, type); if (retval != ERROR_OK) goto fail; arc_reg_data_type_add(target, type); LOG_DEBUG("added struct type {name=%s}", type->data_type.id); return ERROR_OK; fail: free(type); free(fields); free(bitfields); return retval; } /* Add register */ enum opts_add_reg { CFG_ADD_REG_NAME, CFG_ADD_REG_ARCH_NUM, CFG_ADD_REG_IS_CORE, CFG_ADD_REG_IS_BCR, CFG_ADD_REG_GDB_FEATURE, CFG_ADD_REG_TYPE, CFG_ADD_REG_GENERAL, }; static const struct nvp opts_nvp_add_reg[] = { { .name = "-name", .value = CFG_ADD_REG_NAME }, { .name = "-num", .value = CFG_ADD_REG_ARCH_NUM }, { .name = "-core", .value = CFG_ADD_REG_IS_CORE }, { .name = "-bcr", .value = CFG_ADD_REG_IS_BCR }, { .name = "-feature", .value = CFG_ADD_REG_GDB_FEATURE }, { .name = "-type", .value = CFG_ADD_REG_TYPE }, { .name = "-g", .value = CFG_ADD_REG_GENERAL }, { .name = NULL, .value = -1 } }; void free_reg_desc(struct arc_reg_desc *r) { free(r->name); free(r->gdb_xml_feature); free(r); } static COMMAND_HELPER(arc_handle_add_reg_do, struct arc_reg_desc *reg) { /* There is no architecture number that we could treat as invalid, so * separate variable required to ensure that arch num has been set. */ bool arch_num_set = false; const char *type_name = "int"; /* Default type */ /* At least we need to specify 4 parameters: name, number and gdb_feature, * which means there should be 6 arguments. Also there can be additional parameters * "-type <type>", "-g" and "-core" or "-bcr" which makes maximum 10 parameters. */ if (CMD_ARGC < 6 || CMD_ARGC > 10) return ERROR_COMMAND_SYNTAX_ERROR; /* Parse options. */ while (CMD_ARGC) { const struct nvp *n = nvp_name2value(opts_nvp_add_reg, CMD_ARGV[0]); CMD_ARGC--; CMD_ARGV++; switch (n->value) { case CFG_ADD_REG_NAME: if (!CMD_ARGC) return ERROR_COMMAND_ARGUMENT_INVALID; reg->name = strdup(CMD_ARGV[0]); if (!reg->name) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } CMD_ARGC--; CMD_ARGV++; break; case CFG_ADD_REG_IS_CORE: reg->is_core = true; break; case CFG_ADD_REG_IS_BCR: reg->is_bcr = true; break; case CFG_ADD_REG_ARCH_NUM: if (!CMD_ARGC) return ERROR_COMMAND_ARGUMENT_INVALID; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg->arch_num); CMD_ARGC--; CMD_ARGV++; arch_num_set = true; break; case CFG_ADD_REG_GDB_FEATURE: if (!CMD_ARGC) return ERROR_COMMAND_ARGUMENT_INVALID; reg->gdb_xml_feature = strdup(CMD_ARGV[0]); if (!reg->gdb_xml_feature) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } CMD_ARGC--; CMD_ARGV++; break; case CFG_ADD_REG_TYPE: if (!CMD_ARGC) return ERROR_COMMAND_ARGUMENT_INVALID; type_name = CMD_ARGV[0]; CMD_ARGC--; CMD_ARGV++; break; case CFG_ADD_REG_GENERAL: reg->is_general = true; break; default: nvp_unknown_command_print(CMD, opts_nvp_add_reg, NULL, CMD_ARGV[-1]); return ERROR_COMMAND_ARGUMENT_INVALID; } } /* Check that required fields are set */ const char * const errmsg = validate_register(reg, arch_num_set); if (errmsg) { command_print(CMD, "%s", errmsg); return ERROR_COMMAND_ARGUMENT_INVALID; } /* Add new register */ struct target *target = get_current_target(CMD_CTX); if (!target) { command_print(CMD, "No current target"); return ERROR_FAIL; } reg->target = target; int retval = arc_reg_add(target, reg, type_name, strlen(type_name)); if (retval == ERROR_ARC_REGTYPE_NOT_FOUND) { command_print(CMD, "Cannot find type `%s' for register `%s'.", type_name, reg->name); return retval; } return ERROR_OK; } COMMAND_HANDLER(arc_handle_add_reg) { struct arc_reg_desc *reg = calloc(1, sizeof(*reg)); if (!reg) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } int retval = CALL_COMMAND_HANDLER(arc_handle_add_reg_do, reg); if (retval != ERROR_OK) { free_reg_desc(reg); return retval; } return ERROR_OK; } /* arc set-reg-exists ($reg_name)+ * Accepts any amount of register names - will set them as existing in a loop.*/ COMMAND_HANDLER(arc_set_reg_exists) { struct target * const target = get_current_target(CMD_CTX); if (!target) { command_print(CMD, "Unable to get current target."); return ERROR_FAIL; } if (!CMD_ARGC) { command_print(CMD, "At least one register name must be specified."); return ERROR_COMMAND_SYNTAX_ERROR; } for (unsigned int i = 0; i < CMD_ARGC; i++) { const char * const reg_name = CMD_ARGV[i]; struct reg * const r = arc_reg_get_by_name(target->reg_cache, reg_name, true); if (!r) { command_print(CMD, "Register `%s' is not found.", reg_name); return ERROR_COMMAND_ARGUMENT_INVALID; } r->exist = true; } return ERROR_OK; } /* arc reg-field ($reg_name) ($reg_field) * Reads struct type register field */ COMMAND_HANDLER(arc_handle_get_reg_field) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); if (!target) { command_print(CMD, "No current target"); return ERROR_FAIL; } const char *reg_name = CMD_ARGV[0]; const char *field_name = CMD_ARGV[1]; uint32_t value; int retval = arc_reg_get_field(target, reg_name, field_name, &value); switch (retval) { case ERROR_OK: break; case ERROR_ARC_REGISTER_NOT_FOUND: command_print(CMD, "Register `%s' has not been found.", reg_name); return ERROR_COMMAND_ARGUMENT_INVALID; case ERROR_ARC_REGISTER_IS_NOT_STRUCT: command_print(CMD, "Register `%s' must have 'struct' type.", reg_name); return ERROR_COMMAND_ARGUMENT_INVALID; case ERROR_ARC_REGISTER_FIELD_NOT_FOUND: command_print(CMD, "Field `%s' has not been found in register `%s'.", field_name, reg_name); return ERROR_COMMAND_ARGUMENT_INVALID; case ERROR_ARC_FIELD_IS_NOT_BITFIELD: command_print(CMD, "Field `%s' is not a 'bitfield' field in a structure.", field_name); return ERROR_COMMAND_ARGUMENT_INVALID; default: /* Pass through other errors. */ return retval; } command_print(CMD, "0x%" PRIx32, value); return ERROR_OK; } COMMAND_HANDLER(arc_l1_cache_disable_auto_cmd) { bool value; int retval = 0; struct arc_common *arc = target_to_arc(get_current_target(CMD_CTX)); retval = CALL_COMMAND_HANDLER(handle_command_parse_bool, &value, "target has caches enabled"); arc->has_l2cache = value; arc->has_dcache = value; arc->has_icache = value; return retval; } COMMAND_HANDLER(arc_l2_cache_disable_auto_cmd) { struct arc_common *arc = target_to_arc(get_current_target(CMD_CTX)); return CALL_COMMAND_HANDLER(handle_command_parse_bool, &arc->has_l2cache, "target has l2 cache enabled"); } COMMAND_HANDLER(arc_handle_actionpoints_num) { LOG_DEBUG("-"); if (CMD_ARGC >= 2) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); if (!target) { command_print(CMD, "No current target"); return ERROR_FAIL; } struct arc_common *arc = target_to_arc(target); /* It is not possible to pass &arc->actionpoints_num directly to * handle_command_parse_uint, because this value should be valid during * "actionpoint reset, initiated by arc_set_actionpoints_num. */ uint32_t ap_num = arc->actionpoints_num; if (CMD_ARGC == 1) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], ap_num); int e = arc_set_actionpoints_num(target, ap_num); if (e != ERROR_OK) { command_print(CMD, "Failed to set number of actionpoints"); return e; } } command_print(CMD, "%" PRIu32, ap_num); return ERROR_OK; } /* ----- Exported target commands ------------------------------------------ */ static const struct command_registration arc_l2_cache_group_handlers[] = { { .name = "auto", .handler = arc_l2_cache_disable_auto_cmd, .mode = COMMAND_ANY, .usage = "(1|0)", .help = "Disable or enable L2", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration arc_cache_group_handlers[] = { { .name = "auto", .handler = arc_l1_cache_disable_auto_cmd, .mode = COMMAND_ANY, .help = "Disable or enable L1", .usage = "(1|0)", }, { .name = "l2", .mode = COMMAND_ANY, .help = "L2 cache command group", .usage = "", .chain = arc_l2_cache_group_handlers, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration arc_core_command_handlers[] = { { .name = "add-reg-type-flags", .handler = arc_handle_add_reg_type_flags, .mode = COMMAND_CONFIG, .usage = "-name <string> -flag <name> <position> " "[-flag <name> <position>]...", .help = "Add new 'flags' register data type. Only single bit flags " "are supported. Type name is global. Bitsize of register is fixed " "at 32 bits.", }, { .name = "add-reg-type-struct", .handler = arc_handle_add_reg_type_struct, .mode = COMMAND_CONFIG, .usage = "-name <string> -bitfield <name> <start> <end> " "[-bitfield <name> <start> <end>]...", .help = "Add new 'struct' register data type. Only bit-fields are " "supported so far, which means that for each bitfield start and end " "position bits must be specified. GDB also support type-fields, " "where common type can be used instead. Type name is global. Bitsize of " "register is fixed at 32 bits.", }, { .name = "add-reg", .handler = arc_handle_add_reg, .mode = COMMAND_CONFIG, .usage = "-name <string> -num <int> -feature <string> [-gdbnum <int>] " "[-core|-bcr] [-type <type_name>] [-g]", .help = "Add new register. Name, architectural number and feature name " "are required options. GDB regnum will default to previous register " "(gdbnum + 1) and shouldn't be specified in most cases. Type " "defaults to default GDB 'int'.", }, { .name = "set-reg-exists", .handler = arc_set_reg_exists, .mode = COMMAND_ANY, .usage = "<register-name> [<register-name>]...", .help = "Set that register exists. Accepts multiple register names as " "arguments.", }, { .name = "get-reg-field", .handler = arc_handle_get_reg_field, .mode = COMMAND_ANY, .usage = "<regname> <field_name>", .help = "Returns value of field in a register with 'struct' type.", }, { .name = "jtag", .mode = COMMAND_ANY, .help = "ARC JTAG specific commands", .usage = "", .chain = arc_jtag_command_group, }, { .name = "cache", .mode = COMMAND_ANY, .help = "cache command group", .usage = "", .chain = arc_cache_group_handlers, }, { .name = "num-actionpoints", .handler = arc_handle_actionpoints_num, .mode = COMMAND_ANY, .usage = "[<unsigned integer>]", .help = "Prints or sets amount of actionpoints in the processor.", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arc_monitor_command_handlers[] = { { .name = "arc", .mode = COMMAND_ANY, .help = "ARC monitor command group", .usage = "", .chain = arc_core_command_handlers, }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arc_cmd.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Mischa Jonker <mischa.jonker@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARC_CMD_H #define OPENOCD_TARGET_ARC_CMD_H extern const struct command_registration arc_monitor_command_handlers[]; #endif /* OPENOCD_TARGET_ARC_CMD_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arc_jtag.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Mischa Jonker <mischa.jonker@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arc.h" /* * This functions sets instruction register in TAP. TAP end state is always * IRPAUSE. * * @param jtag_info * @param new_instr Instruction to write to instruction register. */ static void arc_jtag_enque_write_ir(struct arc_jtag *jtag_info, uint32_t new_instr) { uint32_t current_instr; struct jtag_tap *tap; uint8_t instr_buffer[sizeof(uint32_t)] = {0}; assert(jtag_info); assert(jtag_info->tap); tap = jtag_info->tap; /* Do not set instruction if it is the same as current. */ current_instr = buf_get_u32(tap->cur_instr, 0, tap->ir_length); if (current_instr == new_instr) return; struct scan_field field = { .num_bits = tap->ir_length, .out_value = instr_buffer }; buf_set_u32(instr_buffer, 0, field.num_bits, new_instr); /* From code in src/jtag/drivers/driver.c it look like that fields are * copied so it is OK that field in this function is allocated in stack and * thus this memory will be repurposed before jtag_execute_queue() will be * invoked. */ jtag_add_ir_scan(tap, &field, TAP_IRPAUSE); } /** * Read 4-byte word from data register. * * Unlike arc_jtag_write_data, this function returns byte-buffer, caller must * convert this data to required format himself. This is done, because it is * impossible to convert data before jtag_execute_queue() is invoked, so it * cannot be done inside this function, so it has to operate with * byte-buffers. Write function on the other hand can "write-and-forget", data * is converted to byte-buffer before jtag_execute_queue(). * * @param jtag_info * @param data Array of bytes to read into. * @param end_state End state after reading. */ static void arc_jtag_enque_read_dr(struct arc_jtag *jtag_info, uint8_t *data, tap_state_t end_state) { assert(jtag_info); assert(jtag_info->tap); struct scan_field field = { .num_bits = 32, .in_value = data }; jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state); } /** * Write 4-byte word to data register. * * @param jtag_info * @param data 4-byte word to write into data register. * @param end_state End state after writing. */ static void arc_jtag_enque_write_dr(struct arc_jtag *jtag_info, uint32_t data, tap_state_t end_state) { uint8_t out_value[sizeof(uint32_t)] = {0}; assert(jtag_info); assert(jtag_info->tap); buf_set_u32(out_value, 0, 32, data); struct scan_field field = { .num_bits = 32, .out_value = out_value }; jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state); } /** * Set transaction in command register. This function sets instruction register * and then transaction register, there is no need to invoke write_ir before * invoking this function. * * @param jtag_info * @param new_trans Transaction to write to transaction command register. * @param end_state End state after writing. */ static void arc_jtag_enque_set_transaction(struct arc_jtag *jtag_info, uint32_t new_trans, tap_state_t end_state) { uint8_t out_value[sizeof(uint32_t)] = {0}; assert(jtag_info); assert(jtag_info->tap); /* No need to do anything. */ if (jtag_info->cur_trans == new_trans) return; /* Set instruction. We used to call write_ir at upper levels, however * write_ir-write_transaction were constantly in pair, so to avoid code * duplication this function does it self. For this reasons it is "set" * instead of "write". */ arc_jtag_enque_write_ir(jtag_info, ARC_TRANSACTION_CMD_REG); buf_set_u32(out_value, 0, ARC_TRANSACTION_CMD_REG_LENGTH, new_trans); struct scan_field field = { .num_bits = ARC_TRANSACTION_CMD_REG_LENGTH, .out_value = out_value }; jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state); jtag_info->cur_trans = new_trans; } /** * Run reset through transaction set. None of the previous * settings/commands/etc. are used anymore (or no influence). */ static void arc_jtag_enque_reset_transaction(struct arc_jtag *jtag_info) { arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_CMD_NOP, TAP_IDLE); } static void arc_jtag_enque_status_read(struct arc_jtag * const jtag_info, uint8_t * const buffer) { assert(jtag_info); assert(jtag_info->tap); assert(buffer); /* first writing code(0x8) of jtag status register in IR */ arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_STATUS_REG); /* Now reading dr performs jtag status register read */ arc_jtag_enque_read_dr(jtag_info, buffer, TAP_IDLE); } /* ----- Exported JTAG functions ------------------------------------------- */ int arc_jtag_startup(struct arc_jtag *jtag_info) { assert(jtag_info); arc_jtag_enque_reset_transaction(jtag_info); return jtag_execute_queue(); } /** Read STATUS register. */ int arc_jtag_status(struct arc_jtag * const jtag_info, uint32_t * const value) { uint8_t buffer[sizeof(uint32_t)]; assert(jtag_info); assert(jtag_info->tap); /* Fill command queue. */ arc_jtag_enque_reset_transaction(jtag_info); arc_jtag_enque_status_read(jtag_info, buffer); arc_jtag_enque_reset_transaction(jtag_info); /* Execute queue. */ CHECK_RETVAL(jtag_execute_queue()); /* Parse output. */ *value = buf_get_u32(buffer, 0, 32); return ERROR_OK; } /* Helper function: Adding read/write register operation to queue */ static void arc_jtag_enque_register_rw(struct arc_jtag *jtag_info, uint32_t *addr, uint8_t *read_buffer, const uint32_t *write_buffer, uint32_t count) { uint32_t i; for (i = 0; i < count; i++) { /* ARC jtag has optimization which is to increment ADDRESS_REG performing * each transaction. Making sequential reads/writes we can set address for * only first register in sequence, and than do read/write in cycle. */ if (i == 0 || (addr[i] != addr[i-1] + 1)) { arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG); /* Going to TAP_IDLE state we initiate jtag transaction. * Reading data we must go to TAP_IDLE, because further * the data would be read. In case of write we go to TAP_DRPAUSE, * because we need to write data to Data register first. */ if (write_buffer) arc_jtag_enque_write_dr(jtag_info, addr[i], TAP_DRPAUSE); else arc_jtag_enque_write_dr(jtag_info, addr[i], TAP_IDLE); arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG); } if (write_buffer) arc_jtag_enque_write_dr(jtag_info, *(write_buffer + i), TAP_IDLE); else arc_jtag_enque_read_dr(jtag_info, read_buffer + i * 4, TAP_IDLE); } /* To prevent pollution of next register due to optimization it is necessary * * to reset transaction */ arc_jtag_enque_reset_transaction(jtag_info); } /** * Write registers. addr is an array of addresses, and those addresses can be * in any order, though it is recommended that they are in sequential order * where possible, as this reduces number of JTAG commands to transfer. * * @param jtag_info * @param type Type of registers to write: core or aux. * @param addr Array of registers numbers. * @param count Amount of registers in arrays. * @param buffer Array of register values. */ static int arc_jtag_write_registers(struct arc_jtag *jtag_info, uint32_t type, uint32_t *addr, uint32_t count, const uint32_t *buffer) { LOG_DEBUG("Writing to %s registers: addr[0]=0x%" PRIx32 ";count=%" PRIu32 ";buffer[0]=0x%08" PRIx32, (type == ARC_JTAG_CORE_REG ? "core" : "aux"), *addr, count, *buffer); if (!count) { LOG_ERROR("Trying to write 0 registers"); return ERROR_FAIL; } arc_jtag_enque_reset_transaction(jtag_info); /* What registers are we writing to? */ const uint32_t transaction = (type == ARC_JTAG_CORE_REG ? ARC_JTAG_WRITE_TO_CORE_REG : ARC_JTAG_WRITE_TO_AUX_REG); arc_jtag_enque_set_transaction(jtag_info, transaction, TAP_DRPAUSE); arc_jtag_enque_register_rw(jtag_info, addr, NULL, buffer, count); return jtag_execute_queue(); } /** * Read registers. addr is an array of addresses, and those addresses can be in * any order, though it is recommended that they are in sequential order where * possible, as this reduces number of JTAG commands to transfer. * * @param jtag_info * @param type Type of registers to read: core or aux. * @param addr Array of registers numbers. * @param count Amount of registers in arrays. * @param buffer Array of register values. */ static int arc_jtag_read_registers(struct arc_jtag *jtag_info, uint32_t type, uint32_t *addr, uint32_t count, uint32_t *buffer) { int retval; uint32_t i; assert(jtag_info); assert(jtag_info->tap); LOG_DEBUG("Reading %s registers: addr[0]=0x%" PRIx32 ";count=%" PRIu32, (type == ARC_JTAG_CORE_REG ? "core" : "aux"), *addr, count); if (!count) { LOG_ERROR("Trying to read 0 registers"); return ERROR_FAIL; } arc_jtag_enque_reset_transaction(jtag_info); /* What type of registers we are reading? */ const uint32_t transaction = (type == ARC_JTAG_CORE_REG ? ARC_JTAG_READ_FROM_CORE_REG : ARC_JTAG_READ_FROM_AUX_REG); arc_jtag_enque_set_transaction(jtag_info, transaction, TAP_DRPAUSE); uint8_t *data_buf = calloc(sizeof(uint8_t), count * 4); arc_jtag_enque_register_rw(jtag_info, addr, data_buf, NULL, count); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("Failed to execute jtag queue: %d", retval); retval = ERROR_FAIL; goto exit; } /* Convert byte-buffers to host /presentation. */ for (i = 0; i < count; i++) buffer[i] = buf_get_u32(data_buf + 4 * i, 0, 32); LOG_DEBUG("Read from register: buf[0]=0x%" PRIx32, buffer[0]); exit: free(data_buf); return retval; } /** Wrapper function to ease writing of one core register. */ int arc_jtag_write_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr, uint32_t value) { return arc_jtag_write_core_reg(jtag_info, &addr, 1, &value); } /** * Write core registers. addr is an array of addresses, and those addresses can * be in any order, though it is recommended that they are in sequential order * where possible, as this reduces number of JTAG commands to transfer. * * @param jtag_info * @param addr Array of registers numbers. * @param count Amount of registers in arrays. * @param buffer Array of register values. */ int arc_jtag_write_core_reg(struct arc_jtag *jtag_info, uint32_t *addr, uint32_t count, const uint32_t *buffer) { return arc_jtag_write_registers(jtag_info, ARC_JTAG_CORE_REG, addr, count, buffer); } /** Wrapper function to ease reading of one core register. */ int arc_jtag_read_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr, uint32_t *value) { return arc_jtag_read_core_reg(jtag_info, &addr, 1, value); } /** * Read core registers. addr is an array of addresses, and those addresses can * be in any order, though it is recommended that they are in sequential order * where possible, as this reduces number of JTAG commands to transfer. * * @param jtag_info * @param addr Array of core register numbers. * @param count Amount of registers in arrays. * @param buffer Array of register values. */ int arc_jtag_read_core_reg(struct arc_jtag *jtag_info, uint32_t *addr, uint32_t count, uint32_t *buffer) { return arc_jtag_read_registers(jtag_info, ARC_JTAG_CORE_REG, addr, count, buffer); } /** Wrapper function to ease writing of one AUX register. */ int arc_jtag_write_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr, uint32_t value) { return arc_jtag_write_aux_reg(jtag_info, &addr, 1, &value); } /** * Write AUX registers. addr is an array of addresses, and those addresses can * be in any order, though it is recommended that they are in sequential order * where possible, as this reduces number of JTAG commands to transfer. * * @param jtag_info * @param addr Array of registers numbers. * @param count Amount of registers in arrays. * @param buffer Array of register values. */ int arc_jtag_write_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr, uint32_t count, const uint32_t *buffer) { return arc_jtag_write_registers(jtag_info, ARC_JTAG_AUX_REG, addr, count, buffer); } /** Wrapper function to ease reading of one AUX register. */ int arc_jtag_read_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr, uint32_t *value) { return arc_jtag_read_aux_reg(jtag_info, &addr, 1, value); } /** * Read AUX registers. addr is an array of addresses, and those addresses can * be in any order, though it is recommended that they are in sequential order * where possible, as this reduces number of JTAG commands to transfer. * * @param jtag_info * @param addr Array of AUX register numbers. * @param count Amount of registers in arrays. * @param buffer Array of register values. */ int arc_jtag_read_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr, uint32_t count, uint32_t *buffer) { return arc_jtag_read_registers(jtag_info, ARC_JTAG_AUX_REG, addr, count, buffer); } /** * Write a sequence of 4-byte words into target memory. * * We can write only 4byte words via JTAG, so any non-word writes should be * handled at higher levels by read-modify-write. * * This function writes directly to the memory, leaving any caches (if there * are any) in inconsistent state. It is responsibility of upper level to * resolve this. * * @param jtag_info * @param addr Address of first word to write into. * @param count Amount of word to write. * @param buffer Array to write into memory. */ int arc_jtag_write_memory(struct arc_jtag *jtag_info, uint32_t addr, uint32_t count, const uint32_t *buffer) { assert(jtag_info); assert(buffer); LOG_DEBUG("Writing to memory: addr=0x%08" PRIx32 ";count=%" PRIu32 ";buffer[0]=0x%08" PRIx32, addr, count, *buffer); /* No need to waste time on useless operations. */ if (!count) return ERROR_OK; /* We do not know where we come from. */ arc_jtag_enque_reset_transaction(jtag_info); /* We want to write to memory. */ arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_WRITE_TO_MEMORY, TAP_DRPAUSE); /* Set target memory address of the first word. */ arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG); arc_jtag_enque_write_dr(jtag_info, addr, TAP_DRPAUSE); /* Start sending words. Address is auto-incremented on 4bytes by HW. */ arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG); uint32_t i; for (i = 0; i < count; i++) arc_jtag_enque_write_dr(jtag_info, *(buffer + i), TAP_IDLE); return jtag_execute_queue(); } /** * Read a sequence of 4-byte words from target memory. * * We can read only 4byte words via JTAG. * * This function read directly from the memory, so it can read invalid data if * data cache hasn't been flushed before hand. It is responsibility of upper * level to resolve this. * * @param jtag_info * @param addr Address of first word to read from. * @param count Amount of words to read. * @param buffer Array of words to read into. * @param slow_memory Whether this is a slow memory (DDR) or fast (CCM). */ int arc_jtag_read_memory(struct arc_jtag *jtag_info, uint32_t addr, uint32_t count, uint32_t *buffer, bool slow_memory) { uint8_t *data_buf; uint32_t i; int retval = ERROR_OK; assert(jtag_info); assert(jtag_info->tap); LOG_DEBUG("Reading memory: addr=0x%" PRIx32 ";count=%" PRIu32 ";slow=%c", addr, count, slow_memory ? 'Y' : 'N'); if (!count) return ERROR_OK; data_buf = calloc(sizeof(uint8_t), count * 4); arc_jtag_enque_reset_transaction(jtag_info); /* We are reading from memory. */ arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_READ_FROM_MEMORY, TAP_DRPAUSE); /* Read data */ for (i = 0; i < count; i++) { /* When several words are read at consequent addresses we can * rely on ARC JTAG auto-incrementing address. That means that * address can be set only once, for a first word. However it * has been noted that at least in some cases when reading from * DDR, JTAG returns 0 instead of a real value. To workaround * this issue we need to do totally non-required address * writes, which however resolve a problem by introducing * delay. See STAR 9000832538... */ if (slow_memory || i == 0) { /* Set address */ arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG); arc_jtag_enque_write_dr(jtag_info, addr + i * 4, TAP_IDLE); arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG); } arc_jtag_enque_read_dr(jtag_info, data_buf + i * 4, TAP_IDLE); } retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("Failed to execute jtag queue: %d", retval); retval = ERROR_FAIL; goto exit; } /* Convert byte-buffers to host presentation. */ for (i = 0; i < count; i++) buffer[i] = buf_get_u32(data_buf + 4*i, 0, 32); exit: free(data_buf); return retval; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arc_jtag.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Mischa Jonker <mischa.jonker@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARC_JTAG_H #define OPENOCD_TARGET_ARC_JTAG_H #define ARC_TRANSACTION_CMD_REG 0x9 /* Command to perform */ #define ARC_TRANSACTION_CMD_REG_LENGTH 4 /* Jtag status register, value is placed in IR to read jtag status register */ #define ARC_JTAG_STATUS_REG 0x8 #define ARC_JTAG_ADDRESS_REG 0xA /* SoC address to access */ #define ARC_JTAG_DATA_REG 0xB /* Data read/written from SoC */ /* Jtag status register field */ #define ARC_JTAG_STAT_RU 0x10 /* ARC Jtag transactions */ #define ARC_JTAG_WRITE_TO_MEMORY 0x0 #define ARC_JTAG_WRITE_TO_CORE_REG 0x1 #define ARC_JTAG_WRITE_TO_AUX_REG 0x2 #define ARC_JTAG_CMD_NOP 0x3 #define ARC_JTAG_READ_FROM_MEMORY 0x4 #define ARC_JTAG_READ_FROM_CORE_REG 0x5 #define ARC_JTAG_READ_FROM_AUX_REG 0x6 #define ARC_JTAG_CORE_REG 0x0 #define ARC_JTAG_AUX_REG 0x1 struct arc_jtag { struct jtag_tap *tap; uint32_t cur_trans; }; /* ----- Exported JTAG functions ------------------------------------------- */ int arc_jtag_startup(struct arc_jtag *jtag_info); int arc_jtag_status(struct arc_jtag *const jtag_info, uint32_t *const value); int arc_jtag_write_core_reg(struct arc_jtag *jtag_info, uint32_t *addr, uint32_t count, const uint32_t *buffer); int arc_jtag_read_core_reg(struct arc_jtag *jtag_info, uint32_t *addr, uint32_t count, uint32_t *buffer); int arc_jtag_write_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr, const uint32_t buffer); int arc_jtag_read_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr, uint32_t *buffer); int arc_jtag_write_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr, uint32_t count, const uint32_t *buffer); int arc_jtag_write_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr, uint32_t value); int arc_jtag_read_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr, uint32_t count, uint32_t *buffer); int arc_jtag_read_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr, uint32_t *value); int arc_jtag_write_memory(struct arc_jtag *jtag_info, uint32_t addr, uint32_t count, const uint32_t *buffer); int arc_jtag_read_memory(struct arc_jtag *jtag_info, uint32_t addr, uint32_t count, uint32_t *buffer, bool slow_memory); #endif /* OPENOCD_TARGET_ARC_JTAG_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arc_mem.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Mischa Jonker <mischa.jonker@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arc.h" /* ----- Supporting functions ---------------------------------------------- */ static bool arc_mem_is_slow_memory(struct arc_common *arc, uint32_t addr, uint32_t size, uint32_t count) { uint32_t addr_end = addr + size * count; /* `_end` field can overflow - it points to the first byte after the end, * therefore if DCCM is right at the end of memory address space, then * dccm_end will be 0. */ assert(addr_end >= addr || addr_end == 0); return !((addr >= arc->dccm_start && addr_end <= arc->dccm_end) || (addr >= arc->iccm0_start && addr_end <= arc->iccm0_end) || (addr >= arc->iccm1_start && addr_end <= arc->iccm1_end)); } /* Write word at word-aligned address */ static int arc_mem_write_block32(struct target *target, uint32_t addr, uint32_t count, void *buf) { struct arc_common *arc = target_to_arc(target); LOG_DEBUG("Write 4-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32, addr, count); /* Check arguments */ assert(!(addr & 3)); /* We need to flush the cache since it might contain dirty * lines, so the cache invalidation may cause data inconsistency. */ CHECK_RETVAL(arc_cache_flush(target)); /* No need to flush cache, because we don't read values from memory. */ CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, addr, count, (uint32_t *)buf)); /* Invalidate caches. */ CHECK_RETVAL(arc_cache_invalidate(target)); return ERROR_OK; } /* Write half-word at half-word-aligned address */ static int arc_mem_write_block16(struct target *target, uint32_t addr, uint32_t count, void *buf) { struct arc_common *arc = target_to_arc(target); uint32_t i; uint32_t buffer_he; uint8_t buffer_te[sizeof(uint32_t)]; uint8_t halfword_te[sizeof(uint16_t)]; LOG_DEBUG("Write 2-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32, addr, count); /* Check arguments */ assert(!(addr & 1)); /* We will read data from memory, so we need to flush the cache. */ CHECK_RETVAL(arc_cache_flush(target)); /* non-word writes are less common than 4-byte writes, so I suppose we can * allow ourselves to write this in a cycle, instead of calling arc_jtag * with count > 1. */ for (i = 0; i < count; i++) { /* We can read only word at word-aligned address. Also *jtag_read_memory * functions return data in host endianness, so host endianness != * target endianness we have to convert data back to target endianness, * or bytes will be at the wrong places.So: * 1) read word * 2) convert to target endianness * 3) make changes * 4) convert back to host endianness * 5) write word back to target. */ bool is_slow_memory = arc_mem_is_slow_memory(arc, (addr + i * sizeof(uint16_t)) & ~3u, 4, 1); CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he, is_slow_memory)); target_buffer_set_u32(target, buffer_te, buffer_he); /* buf is in host endianness, convert to target */ target_buffer_set_u16(target, halfword_te, ((uint16_t *)buf)[i]); memcpy(buffer_te + ((addr + i * sizeof(uint16_t)) & 3u), halfword_te, sizeof(uint16_t)); buffer_he = target_buffer_get_u32(target, buffer_te); CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he)); } /* Invalidate caches. */ CHECK_RETVAL(arc_cache_invalidate(target)); return ERROR_OK; } /* Write byte at address */ static int arc_mem_write_block8(struct target *target, uint32_t addr, uint32_t count, void *buf) { struct arc_common *arc = target_to_arc(target); uint32_t i; uint32_t buffer_he; uint8_t buffer_te[sizeof(uint32_t)]; LOG_DEBUG("Write 1-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32, addr, count); /* We will read data from memory, so we need to flush the cache. */ CHECK_RETVAL(arc_cache_flush(target)); /* non-word writes are less common than 4-byte writes, so I suppose we can * allow ourselves to write this in a cycle, instead of calling arc_jtag * with count > 1. */ for (i = 0; i < count; i++) { /* See comment in arc_mem_write_block16 for details. Since it is a byte * there is not need to convert write buffer to target endianness, but * we still have to convert read buffer. */ CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he, arc_mem_is_slow_memory(arc, (addr + i) & ~3, 4, 1))); target_buffer_set_u32(target, buffer_te, buffer_he); memcpy(buffer_te + ((addr + i) & 3), (uint8_t *)buf + i, 1); buffer_he = target_buffer_get_u32(target, buffer_te); CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he)); } /* Invalidate caches. */ CHECK_RETVAL(arc_cache_invalidate(target)); return ERROR_OK; } /* ----- Exported functions ------------------------------------------------ */ int arc_mem_write(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval = ERROR_OK; void *tunnel = NULL; LOG_DEBUG("address: 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: %" PRIu32, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; /* correct endianness if we have word or hword access */ if (size > 1) { /* * arc_..._write_mem with size 4/2 requires uint32_t/uint16_t * in host endianness, but byte array represents target endianness. */ tunnel = calloc(1, count * size * sizeof(uint8_t)); if (!tunnel) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; } switch (size) { case 4: target_buffer_get_u32_array(target, buffer, count, (uint32_t *)tunnel); break; case 2: target_buffer_get_u16_array(target, buffer, count, (uint16_t *)tunnel); break; } buffer = tunnel; } if (size == 4) { retval = arc_mem_write_block32(target, address, count, (void *)buffer); } else if (size == 2) { /* We convert buffer from host endianness to target. But then in * write_block16, we do the reverse. Is there a way to avoid this without * breaking other cases? */ retval = arc_mem_write_block16(target, address, count, (void *)buffer); } else { retval = arc_mem_write_block8(target, address, count, (void *)buffer); } free(tunnel); return retval; } static int arc_mem_read_block(struct target *target, target_addr_t addr, uint32_t size, uint32_t count, void *buf) { struct arc_common *arc = target_to_arc(target); LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32 ", count=%" PRIu32, addr, size, count); assert(!(addr & 3)); assert(size == 4); /* Flush cache before memory access */ CHECK_RETVAL(arc_cache_flush(target)); CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, addr, count, buf, arc_mem_is_slow_memory(arc, addr, size, count))); return ERROR_OK; } int arc_mem_read(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval = ERROR_OK; void *tunnel_he; uint8_t *tunnel_te; uint32_t words_to_read, bytes_to_read; LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32 ", count=%" PRIu32, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; /* Reads are word-aligned, so padding might be required if count > 1. * NB: +3 is a padding for the last word (in case it's not aligned; * addr&3 is a padding for the first word (since address can be * unaligned as well). */ bytes_to_read = (count * size + 3 + (address & 3u)) & ~3u; words_to_read = bytes_to_read >> 2; tunnel_he = calloc(1, bytes_to_read); tunnel_te = calloc(1, bytes_to_read); if (!tunnel_he || !tunnel_te) { LOG_ERROR("Unable to allocate memory"); free(tunnel_he); free(tunnel_te); return ERROR_FAIL; } /* We can read only word-aligned words. */ retval = arc_mem_read_block(target, address & ~3u, sizeof(uint32_t), words_to_read, tunnel_he); /* arc_..._read_mem with size 4/2 returns uint32_t/uint16_t in host */ /* endianness, but byte array should represent target endianness */ if (retval == ERROR_OK) { switch (size) { case 4: target_buffer_set_u32_array(target, buffer, count, tunnel_he); break; case 2: target_buffer_set_u32_array(target, tunnel_te, words_to_read, tunnel_he); /* Will that work properly with count > 1 and big endian? */ memcpy(buffer, tunnel_te + (address & 3u), count * sizeof(uint16_t)); break; case 1: target_buffer_set_u32_array(target, tunnel_te, words_to_read, tunnel_he); /* Will that work properly with count > 1 and big endian? */ memcpy(buffer, tunnel_te + (address & 3u), count); break; } } free(tunnel_he); free(tunnel_te); return retval; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arc_mem.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARC_MEM_H #define OPENOCD_TARGET_ARC_MEM_H /* ----- Exported functions ------------------------------------------------ */ int arc_mem_read(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); int arc_mem_write(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); #endif /* OPENOCD_TARGET_ARC_MEM_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2005 by Dominic Rath * Dominic.Rath@gmx.de * * Copyright (C) 2008 by Spencer Oliver * spen@spen-soft.co.uk * * Copyright (C) 2009 by Øyvind Harboe * oyvind.harboe@zylin.com * * Copyright (C) 2018 by Liviu Ionescu * <ilg@livius.net> */ #ifndef OPENOCD_TARGET_ARM_H #define OPENOCD_TARGET_ARM_H #include <helper/command.h> #include "target.h" /** * @file * Holds the interface to ARM cores. * * At this writing, only "classic ARM" cores built on the ARMv4 register * and mode model are supported. The Thumb2-only microcontroller profile * support has not yet been integrated, affecting Cortex-M parts. */ /** * Indicates what registers are in the ARM state core register set. * * - ARM_CORE_TYPE_STD indicates the standard set of 37 registers, seen * on for example ARM7TDMI cores. * - ARM_CORE_TYPE_SEC_EXT indicates core has security extensions, thus * three more registers are shadowed for "Secure Monitor" mode. * - ARM_CORE_TYPE_VIRT_EXT indicates core has virtualization extensions * and also security extensions. Additional shadowed registers for * "Secure Monitor" and "Hypervisor" modes. * - ARM_CORE_TYPE_M_PROFILE indicates a microcontroller profile core, * which only shadows SP. */ enum arm_core_type { ARM_CORE_TYPE_STD = -1, ARM_CORE_TYPE_SEC_EXT = 1, ARM_CORE_TYPE_VIRT_EXT, ARM_CORE_TYPE_M_PROFILE, }; /** ARM Architecture specifying the version and the profile */ enum arm_arch { ARM_ARCH_UNKNOWN, ARM_ARCH_V4, ARM_ARCH_V6M, ARM_ARCH_V7M, ARM_ARCH_V8M, }; /** * Represent state of an ARM core. * * Most numbers match the five low bits of the *PSR registers on * "classic ARM" processors, which build on the ARMv4 processor * modes and register set. * * ARM_MODE_ANY is a magic value, often used as a wildcard. * * Only the microcontroller cores (ARMv6-M, ARMv7-M) support ARM_MODE_THREAD, * ARM_MODE_USER_THREAD, and ARM_MODE_HANDLER. Those are the only modes * they support. */ enum arm_mode { ARM_MODE_USR = 16, ARM_MODE_FIQ = 17, ARM_MODE_IRQ = 18, ARM_MODE_SVC = 19, ARM_MODE_MON = 22, ARM_MODE_ABT = 23, ARM_MODE_HYP = 26, ARM_MODE_UND = 27, ARM_MODE_1176_MON = 28, ARM_MODE_SYS = 31, ARM_MODE_THREAD = 0, ARM_MODE_USER_THREAD = 1, ARM_MODE_HANDLER = 2, ARMV8_64_EL0T = 0x0, ARMV8_64_EL1T = 0x4, ARMV8_64_EL1H = 0x5, ARMV8_64_EL2T = 0x8, ARMV8_64_EL2H = 0x9, ARMV8_64_EL3T = 0xC, ARMV8_64_EL3H = 0xD, ARM_MODE_ANY = -1 }; /* VFPv3 internal register numbers mapping to d0:31 */ enum { ARM_VFP_V3_D0 = 51, ARM_VFP_V3_D1, ARM_VFP_V3_D2, ARM_VFP_V3_D3, ARM_VFP_V3_D4, ARM_VFP_V3_D5, ARM_VFP_V3_D6, ARM_VFP_V3_D7, ARM_VFP_V3_D8, ARM_VFP_V3_D9, ARM_VFP_V3_D10, ARM_VFP_V3_D11, ARM_VFP_V3_D12, ARM_VFP_V3_D13, ARM_VFP_V3_D14, ARM_VFP_V3_D15, ARM_VFP_V3_D16, ARM_VFP_V3_D17, ARM_VFP_V3_D18, ARM_VFP_V3_D19, ARM_VFP_V3_D20, ARM_VFP_V3_D21, ARM_VFP_V3_D22, ARM_VFP_V3_D23, ARM_VFP_V3_D24, ARM_VFP_V3_D25, ARM_VFP_V3_D26, ARM_VFP_V3_D27, ARM_VFP_V3_D28, ARM_VFP_V3_D29, ARM_VFP_V3_D30, ARM_VFP_V3_D31, ARM_VFP_V3_FPSCR, }; const char *arm_mode_name(unsigned psr_mode); bool is_arm_mode(unsigned psr_mode); /** The PSR "T" and "J" bits define the mode of "classic ARM" cores. */ enum arm_state { ARM_STATE_ARM, ARM_STATE_THUMB, ARM_STATE_JAZELLE, ARM_STATE_THUMB_EE, ARM_STATE_AARCH64, }; /** ARM vector floating point enabled, if yes which version. */ enum arm_vfp_version { ARM_VFP_DISABLED, ARM_VFP_V1, ARM_VFP_V2, ARM_VFP_V3, }; #define ARM_COMMON_MAGIC 0x0A450A45U /** * Represents a generic ARM core, with standard application registers. * * There are sixteen application registers (including PC, SP, LR) and a PSR. * Cortex-M series cores do not support as many core states or shadowed * registers as traditional ARM cores, and only support Thumb2 instructions. */ struct arm { unsigned int common_magic; struct reg_cache *core_cache; /** Handle to the PC; valid in all core modes. */ struct reg *pc; /** Handle to the CPSR/xPSR; valid in all core modes. */ struct reg *cpsr; /** Handle to the SPSR; valid only in core modes with an SPSR. */ struct reg *spsr; /** Support for arm_reg_current() */ const int *map; /** Indicates what registers are in the ARM state core register set. */ enum arm_core_type core_type; /** Record the current core mode: SVC, USR, or some other mode. */ enum arm_mode core_mode; /** Record the current core state: ARM, Thumb, or otherwise. */ enum arm_state core_state; /** ARM architecture version */ enum arm_arch arch; /** Floating point or VFP version, 0 if disabled. */ int arm_vfp_version; int (*setup_semihosting)(struct target *target, int enable); /** Backpointer to the target. */ struct target *target; /** Handle for the debug module, if one is present. */ struct arm_dpm *dpm; /** Handle for the Embedded Trace Module, if one is present. */ struct etm_context *etm; /* FIXME all these methods should take "struct arm *" not target */ /** Retrieve all core registers, for display. */ int (*full_context)(struct target *target); /** Retrieve a single core register. */ int (*read_core_reg)(struct target *target, struct reg *reg, int num, enum arm_mode mode); int (*write_core_reg)(struct target *target, struct reg *reg, int num, enum arm_mode mode, uint8_t *value); /** Read coprocessor register. */ int (*mrc)(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value); /** Write coprocessor register. */ int (*mcr)(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value); void *arch_info; /** For targets conforming to ARM Debug Interface v5, * this handle references the Debug Access Port (DAP) * used to make requests to the target. */ struct adiv5_dap *dap; }; /** Convert target handle to generic ARM target state handle. */ static inline struct arm *target_to_arm(struct target *target) { assert(target); return target->arch_info; } static inline bool is_arm(struct arm *arm) { assert(arm); return arm->common_magic == ARM_COMMON_MAGIC; } struct arm_algorithm { unsigned int common_magic; enum arm_mode core_mode; enum arm_state core_state; }; struct arm_reg { int num; enum arm_mode mode; struct target *target; struct arm *arm; uint8_t value[16]; }; struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm); void arm_free_reg_cache(struct arm *arm); struct reg_cache *armv8_build_reg_cache(struct target *target); extern const struct command_registration arm_command_handlers[]; extern const struct command_registration arm_all_profiles_command_handlers[]; int arm_arch_state(struct target *target); const char *arm_get_gdb_arch(struct target *target); int arm_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); const char *armv8_get_gdb_arch(struct target *target); int armv8_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); int arm_init_arch_info(struct target *target, struct arm *arm); /* REVISIT rename this once it's usable by ARMv7-M */ int armv4_5_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); int armv4_5_run_algorithm_inner(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, unsigned int timeout_ms, void *arch_info, int (*run_it)(struct target *target, uint32_t exit_point, unsigned int timeout_ms, void *arch_info)); int arm_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); int arm_blank_check_memory(struct target *target, struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value); void arm_set_cpsr(struct arm *arm, uint32_t cpsr); struct reg *arm_reg_current(struct arm *arm, unsigned regnum); struct reg *armv8_reg_current(struct arm *arm, unsigned regnum); #endif /* OPENOCD_TARGET_ARM_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm11.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2008 digenius technology GmbH. * * Michael Bruck * * * * Copyright (C) 2008,2009 Oyvind Harboe oyvind.harboe@zylin.com * * * * Copyright (C) 2008 Georg Acher <acher@in.tum.de> * * * * Copyright (C) 2009 David Brownell * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "etm.h" #include "breakpoints.h" #include "arm11_dbgtap.h" #include "arm_simulator.h" #include <helper/time_support.h> #include "target_type.h" #include "algorithm.h" #include "register.h" #include "arm_opcodes.h" #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif static int arm11_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); /** Check and if necessary take control of the system * * \param arm11 Target state variable. */ static int arm11_check_init(struct arm11_common *arm11) { CHECK_RETVAL(arm11_read_dscr(arm11)); if (!(arm11->dscr & DSCR_HALT_DBG_MODE)) { LOG_DEBUG("DSCR %08x", (unsigned) arm11->dscr); LOG_DEBUG("Bringing target into debug mode"); arm11->dscr |= DSCR_HALT_DBG_MODE; CHECK_RETVAL(arm11_write_dscr(arm11, arm11->dscr)); /* add further reset initialization here */ arm11->simulate_reset_on_next_halt = true; if (arm11->dscr & DSCR_CORE_HALTED) { /** \todo TODO: this needs further scrutiny because * arm11_debug_entry() never gets called. (WHY NOT?) * As a result we don't read the actual register states from * the target. */ arm11->arm.target->state = TARGET_HALTED; arm_dpm_report_dscr(arm11->arm.dpm, arm11->dscr); } else { arm11->arm.target->state = TARGET_RUNNING; arm11->arm.target->debug_reason = DBG_REASON_NOTHALTED; } CHECK_RETVAL(arm11_sc7_clear_vbw(arm11)); } return ERROR_OK; } /** * Save processor state. This is called after a HALT instruction * succeeds, and on other occasions the processor enters debug mode * (breakpoint, watchpoint, etc). Caller has updated arm11->dscr. */ static int arm11_debug_entry(struct arm11_common *arm11) { int retval; arm11->arm.target->state = TARGET_HALTED; arm_dpm_report_dscr(arm11->arm.dpm, arm11->dscr); /* REVISIT entire cache should already be invalid !!! */ register_cache_invalidate(arm11->arm.core_cache); /* See e.g. ARM1136 TRM, "14.8.4 Entering Debug state" */ /* maybe save wDTR (pending DCC write to debug SW, e.g. libdcc) */ arm11->is_wdtr_saved = !!(arm11->dscr & DSCR_DTR_TX_FULL); if (arm11->is_wdtr_saved) { arm11_add_debug_scan_n(arm11, 0x05, ARM11_TAP_DEFAULT); arm11_add_ir(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; arm11_setup_field(arm11, 32, NULL, &arm11->saved_wdtr, chain5_fields + 0); arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 1); arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 2); arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, TAP_DRPAUSE); } /* DSCR: set the Execute ARM instruction enable bit. * * ARM1176 spec says this is needed only for wDTR/rDTR's "ITR mode", * but not to issue ITRs(?). The ARMv7 arch spec says it's required * for executing instructions via ITR. */ CHECK_RETVAL(arm11_write_dscr(arm11, DSCR_ITR_EN | arm11->dscr)); /* From the spec: Before executing any instruction in debug state you have to drain the write buffer. This ensures that no imprecise Data Aborts can return at a later point:*/ /** \todo TODO: Test drain write buffer. */ #if 0 while (1) { /* MRC p14,0,R0,c5,c10,0 */ /* arm11_run_instr_no_data1(arm11, / *0xee150e1a* /0xe320f000); */ /* mcr 15, 0, r0, cr7, cr10, {4} */ arm11_run_instr_no_data1(arm11, 0xee070f9a); uint32_t dscr = arm11_read_dscr(arm11); LOG_DEBUG("DRAIN, DSCR %08x", dscr); if (dscr & ARM11_DSCR_STICKY_IMPRECISE_DATA_ABORT) { arm11_run_instr_no_data1(arm11, 0xe320f000); dscr = arm11_read_dscr(arm11); LOG_DEBUG("DRAIN, DSCR %08x (DONE)", dscr); break; } } #endif /* Save registers. * * NOTE: ARM1136 TRM suggests saving just R0 here now, then * CPSR and PC after the rDTR stuff. We do it all at once. */ retval = arm_dpm_read_current_registers(&arm11->dpm); if (retval != ERROR_OK) LOG_ERROR("DPM REG READ -- fail"); retval = arm11_run_instr_data_prepare(arm11); if (retval != ERROR_OK) return retval; /* maybe save rDTR (pending DCC read from debug SW, e.g. libdcc) */ arm11->is_rdtr_saved = !!(arm11->dscr & DSCR_DTR_RX_FULL); if (arm11->is_rdtr_saved) { /* MRC p14,0,R0,c0,c5,0 (move rDTR -> r0 (-> wDTR -> local var)) */ retval = arm11_run_instr_data_from_core_via_r0(arm11, 0xEE100E15, &arm11->saved_rdtr); if (retval != ERROR_OK) return retval; } /* REVISIT Now that we've saved core state, there's may also * be MMU and cache state to care about ... */ if (arm11->simulate_reset_on_next_halt) { arm11->simulate_reset_on_next_halt = false; LOG_DEBUG("Reset c1 Control Register"); /* Write 0 (reset value) to Control register 0 to disable MMU/Cache etc. */ /* MCR p15,0,R0,c1,c0,0 */ retval = arm11_run_instr_data_to_core_via_r0(arm11, 0xee010f10, 0); if (retval != ERROR_OK) return retval; } if (arm11->arm.target->debug_reason == DBG_REASON_WATCHPOINT) { uint32_t wfar; /* MRC p15, 0, <Rd>, c6, c0, 1 ; Read WFAR */ retval = arm11_run_instr_data_from_core_via_r0(arm11, ARMV4_5_MRC(15, 0, 0, 6, 0, 1), &wfar); if (retval != ERROR_OK) return retval; arm_dpm_report_wfar(arm11->arm.dpm, wfar); } retval = arm11_run_instr_data_finish(arm11); if (retval != ERROR_OK) return retval; return ERROR_OK; } /** * Restore processor state. This is called in preparation for * the RESTART function. */ static int arm11_leave_debug_state(struct arm11_common *arm11, bool bpwp) { int retval; /* See e.g. ARM1136 TRM, "14.8.5 Leaving Debug state" */ /* NOTE: the ARM1136 TRM suggests restoring all registers * except R0/PC/CPSR right now. Instead, we do them all * at once, just a bit later on. */ /* REVISIT once we start caring about MMU and cache state, * address it here ... */ /* spec says clear wDTR and rDTR; we assume they are clear as otherwise our programming would be sloppy */ { CHECK_RETVAL(arm11_read_dscr(arm11)); if (arm11->dscr & (DSCR_DTR_RX_FULL | DSCR_DTR_TX_FULL)) { /* The wDTR/rDTR two registers that are used to send/receive data to/from the core in tandem with corresponding instruction codes that are written into the core. The RDTR FULL/WDTR FULL flag indicates that the registers hold data that was written by one side (CPU or JTAG) and not read out by the other side. */ LOG_ERROR("wDTR/rDTR inconsistent (DSCR %08x)", (unsigned) arm11->dscr); return ERROR_FAIL; } } /* maybe restore original wDTR */ if (arm11->is_wdtr_saved) { retval = arm11_run_instr_data_prepare(arm11); if (retval != ERROR_OK) return retval; /* MCR p14,0,R0,c0,c5,0 */ retval = arm11_run_instr_data_to_core_via_r0(arm11, 0xee000e15, arm11->saved_wdtr); if (retval != ERROR_OK) return retval; retval = arm11_run_instr_data_finish(arm11); if (retval != ERROR_OK) return retval; } /* restore CPSR, PC, and R0 ... after flushing any modified * registers. */ CHECK_RETVAL(arm_dpm_write_dirty_registers(&arm11->dpm, bpwp)); CHECK_RETVAL(arm11_bpwp_flush(arm11)); register_cache_invalidate(arm11->arm.core_cache); /* restore DSCR */ CHECK_RETVAL(arm11_write_dscr(arm11, arm11->dscr)); /* maybe restore rDTR */ if (arm11->is_rdtr_saved) { arm11_add_debug_scan_n(arm11, 0x05, ARM11_TAP_DEFAULT); arm11_add_ir(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; uint8_t ready = 0; /* ignored */ uint8_t valid = 0; /* ignored */ arm11_setup_field(arm11, 32, &arm11->saved_rdtr, NULL, chain5_fields + 0); arm11_setup_field(arm11, 1, &ready, NULL, chain5_fields + 1); arm11_setup_field(arm11, 1, &valid, NULL, chain5_fields + 2); arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, TAP_DRPAUSE); } /* now processor is ready to RESTART */ return ERROR_OK; } /* poll current target status */ static int arm11_poll(struct target *target) { int retval; struct arm11_common *arm11 = target_to_arm11(target); CHECK_RETVAL(arm11_check_init(arm11)); if (arm11->dscr & DSCR_CORE_HALTED) { if (target->state != TARGET_HALTED) { enum target_state old_state = target->state; LOG_DEBUG("enter TARGET_HALTED"); retval = arm11_debug_entry(arm11); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, (old_state == TARGET_DEBUG_RUNNING) ? TARGET_EVENT_DEBUG_HALTED : TARGET_EVENT_HALTED); } } else { if (target->state != TARGET_RUNNING && target->state != TARGET_DEBUG_RUNNING) { LOG_DEBUG("enter TARGET_RUNNING"); target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; } } return ERROR_OK; } /* architecture specific status reply */ static int arm11_arch_state(struct target *target) { struct arm11_common *arm11 = target_to_arm11(target); int retval; retval = arm_arch_state(target); /* REVISIT also display ARM11-specific MMU and cache status ... */ if (target->debug_reason == DBG_REASON_WATCHPOINT) LOG_USER("Watchpoint triggered at PC " TARGET_ADDR_FMT, arm11->dpm.wp_addr); return retval; } /* target execution control */ static int arm11_halt(struct target *target) { struct arm11_common *arm11 = target_to_arm11(target); LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_UNKNOWN) arm11->simulate_reset_on_next_halt = true; if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } arm11_add_ir(arm11, ARM11_HALT, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); int i = 0; while (1) { CHECK_RETVAL(arm11_read_dscr(arm11)); if (arm11->dscr & DSCR_CORE_HALTED) break; int64_t then = 0; if (i == 1000) then = timeval_ms(); if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING("Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } enum target_state old_state = target->state; CHECK_RETVAL(arm11_debug_entry(arm11)); CHECK_RETVAL( target_call_event_callbacks(target, old_state == TARGET_DEBUG_RUNNING ? TARGET_EVENT_DEBUG_HALTED : TARGET_EVENT_HALTED)); return ERROR_OK; } static uint32_t arm11_nextpc(struct arm11_common *arm11, int current, uint32_t address) { void *value = arm11->arm.pc->value; /* use the current program counter */ if (current) address = buf_get_u32(value, 0, 32); /* Make sure that the gdb thumb fixup does not * kill the return address */ switch (arm11->arm.core_state) { case ARM_STATE_ARM: address &= 0xFFFFFFFC; break; case ARM_STATE_THUMB: /* When the return address is loaded into PC * bit 0 must be 1 to stay in Thumb state */ address |= 0x1; break; /* catch-all for JAZELLE and THUMB_EE */ default: break; } buf_set_u32(value, 0, 32, address); arm11->arm.pc->dirty = true; arm11->arm.pc->valid = true; return address; } static int arm11_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { /* LOG_DEBUG("current %d address %08x handle_breakpoints %d debug_execution %d", */ /* current, address, handle_breakpoints, debug_execution); */ struct arm11_common *arm11 = target_to_arm11(target); LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } address = arm11_nextpc(arm11, current, address); LOG_DEBUG("RESUME PC %08" TARGET_PRIxADDR "%s", address, !current ? "!" : ""); /* clear breakpoints/watchpoints and VCR*/ CHECK_RETVAL(arm11_sc7_clear_vbw(arm11)); if (!debug_execution) target_free_all_working_areas(target); /* Should we skip over breakpoints matching the PC? */ if (handle_breakpoints) { struct breakpoint *bp; for (bp = target->breakpoints; bp; bp = bp->next) { if (bp->address == address) { LOG_DEBUG("must step over %08" TARGET_PRIxADDR "", bp->address); arm11_step(target, 1, 0, 0); break; } } } /* activate all breakpoints */ if (true) { struct breakpoint *bp; unsigned brp_num = 0; for (bp = target->breakpoints; bp; bp = bp->next) { struct arm11_sc7_action brp[2]; brp[0].write = 1; brp[0].address = ARM11_SC7_BVR0 + brp_num; brp[0].value = bp->address; brp[1].write = 1; brp[1].address = ARM11_SC7_BCR0 + brp_num; brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (0 << 21); CHECK_RETVAL(arm11_sc7_run(arm11, brp, ARRAY_SIZE(brp))); LOG_DEBUG("Add BP %d at %08" TARGET_PRIxADDR, brp_num, bp->address); brp_num++; } if (arm11->vcr) CHECK_RETVAL(arm11_sc7_set_vcr(arm11, arm11->vcr)); } /* activate all watchpoints and breakpoints */ CHECK_RETVAL(arm11_leave_debug_state(arm11, true)); arm11_add_ir(arm11, ARM11_RESTART, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); int i = 0; while (1) { CHECK_RETVAL(arm11_read_dscr(arm11)); LOG_DEBUG("DSCR %08x", (unsigned) arm11->dscr); if (arm11->dscr & DSCR_CORE_RESTARTED) break; int64_t then = 0; if (i == 1000) then = timeval_ms(); if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING("Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } target->debug_reason = DBG_REASON_NOTHALTED; if (!debug_execution) target->state = TARGET_RUNNING; else target->state = TARGET_DEBUG_RUNNING; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); return ERROR_OK; } static int arm11_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state != TARGET_HALTED) { LOG_WARNING("target was not halted"); return ERROR_TARGET_NOT_HALTED; } struct arm11_common *arm11 = target_to_arm11(target); address = arm11_nextpc(arm11, current, address); LOG_DEBUG("STEP PC %08" TARGET_PRIxADDR "%s", address, !current ? "!" : ""); /** \todo TODO: Thumb not supported here */ uint32_t next_instruction; CHECK_RETVAL(arm11_read_memory_word(arm11, address, &next_instruction)); /* skip over BKPT */ if ((next_instruction & 0xFFF00070) == 0xe1200070) { address = arm11_nextpc(arm11, 0, address + 4); LOG_DEBUG("Skipping BKPT %08" TARGET_PRIxADDR, address); } /* skip over Wait for interrupt / Standby * mcr 15, 0, r?, cr7, cr0, {4} */ else if ((next_instruction & 0xFFFF0FFF) == 0xee070f90) { address = arm11_nextpc(arm11, 0, address + 4); LOG_DEBUG("Skipping WFI %08" TARGET_PRIxADDR, address); } /* ignore B to self */ else if ((next_instruction & 0xFEFFFFFF) == 0xeafffffe) LOG_DEBUG("Not stepping jump to self"); else { /** \todo TODO: check if break-/watchpoints make any sense at all in combination * with this. */ /** \todo TODO: check if disabling IRQs might be a good idea here. Alternatively * the VCR might be something worth looking into. */ /* Set up breakpoint for stepping */ struct arm11_sc7_action brp[2]; brp[0].write = 1; brp[0].address = ARM11_SC7_BVR0; brp[1].write = 1; brp[1].address = ARM11_SC7_BCR0; if (arm11->hardware_step) { /* Hardware single stepping ("instruction address * mismatch") is used if enabled. It's not quite * exactly "run one instruction"; "branch to here" * loops won't break, neither will some other cases, * but it's probably the best default. * * Hardware single stepping isn't supported on v6 * debug modules. ARM1176 and v7 can support it... * * FIXME Thumb stepping likely needs to use 0x03 * or 0xc0 byte masks, not 0x0f. */ brp[0].value = address; brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (2 << 21); } else { /* Sets a breakpoint on the next PC, as calculated * by instruction set simulation. * * REVISIT stepping Thumb on ARM1156 requires Thumb2 * support from the simulator. */ uint32_t next_pc; int retval; retval = arm_simulate_step(target, &next_pc); if (retval != ERROR_OK) return retval; brp[0].value = next_pc; brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (0 << 21); } CHECK_RETVAL(arm11_sc7_run(arm11, brp, ARRAY_SIZE(brp))); /* resume */ if (arm11->step_irq_enable) /* this disable should be redundant ... */ arm11->dscr &= ~DSCR_INT_DIS; else arm11->dscr |= DSCR_INT_DIS; CHECK_RETVAL(arm11_leave_debug_state(arm11, handle_breakpoints)); arm11_add_ir(arm11, ARM11_RESTART, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); /* wait for halt */ int i = 0; while (1) { const uint32_t mask = DSCR_CORE_RESTARTED | DSCR_CORE_HALTED; CHECK_RETVAL(arm11_read_dscr(arm11)); LOG_DEBUG("DSCR %08x e", (unsigned) arm11->dscr); if ((arm11->dscr & mask) == mask) break; long long then = 0; if (i == 1000) then = timeval_ms(); if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING( "Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } /* clear breakpoint */ CHECK_RETVAL(arm11_sc7_clear_vbw(arm11)); /* save state */ CHECK_RETVAL(arm11_debug_entry(arm11)); /* restore default state */ arm11->dscr &= ~DSCR_INT_DIS; } target->debug_reason = DBG_REASON_SINGLESTEP; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); return ERROR_OK; } static int arm11_assert_reset(struct target *target) { struct arm11_common *arm11 = target_to_arm11(target); if (!(target_was_examined(target))) { if (jtag_get_reset_config() & RESET_HAS_SRST) jtag_add_reset(0, 1); else { LOG_WARNING("Reset is not asserted because the target is not examined."); LOG_WARNING("Use a reset button or power cycle the target."); return ERROR_TARGET_NOT_EXAMINED; } } else { /* optionally catch reset vector */ if (target->reset_halt && !(arm11->vcr & 1)) CHECK_RETVAL(arm11_sc7_set_vcr(arm11, arm11->vcr | 1)); /* Issue some kind of warm reset. */ if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) target_handle_event(target, TARGET_EVENT_RESET_ASSERT); else if (jtag_get_reset_config() & RESET_HAS_SRST) { /* REVISIT handle "pulls" cases, if there's * hardware that needs them to work. */ jtag_add_reset(0, 1); } else { LOG_ERROR("%s: how to reset?", target_name(target)); return ERROR_FAIL; } } /* registers are now invalid */ register_cache_invalidate(arm11->arm.core_cache); target->state = TARGET_RESET; return ERROR_OK; } /* * - There is another bug in the arm11 core. (iMX31 specific again?) * When you generate an access to external logic (for example DDR * controller via AHB bus) and that block is not configured (perhaps * it is still held in reset), that transaction will never complete. * This will hang arm11 core but it will also hang JTAG controller. * Nothing short of srst assertion will bring it out of this. */ static int arm11_deassert_reset(struct target *target) { struct arm11_common *arm11 = target_to_arm11(target); int retval; /* be certain SRST is off */ jtag_add_reset(0, 0); /* WORKAROUND i.MX31 problems: SRST goofs the TAP, and resets * at least DSCR. OMAP24xx doesn't show that problem, though * SRST-only reset seems to be problematic for other reasons. * (Secure boot sequences being one likelihood!) */ jtag_add_tlr(); CHECK_RETVAL(arm11_poll(target)); if (target->reset_halt) { if (target->state != TARGET_HALTED) { LOG_WARNING("%s: ran after reset and before halt ...", target_name(target)); retval = target_halt(target); if (retval != ERROR_OK) return retval; } } /* maybe restore vector catch config */ if (target->reset_halt && !(arm11->vcr & 1)) CHECK_RETVAL(arm11_sc7_set_vcr(arm11, arm11->vcr)); return ERROR_OK; } /* target memory access * size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit) * count: number of items of <size> * * arm11_config_memrw_no_increment - in the future we may want to be able * to read/write a range of data to a "port". a "port" is an action on * read memory address for some peripheral. */ static int arm11_read_memory_inner(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer, bool arm11_config_memrw_no_increment) { /** \todo TODO: check if buffer cast to uint32_t* and uint16_t* might cause alignment *problems */ int retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target was not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_DEBUG("ADDR %08" PRIx32 " SIZE %08" PRIx32 " COUNT %08" PRIx32 "", address, size, count); struct arm11_common *arm11 = target_to_arm11(target); retval = arm11_run_instr_data_prepare(arm11); if (retval != ERROR_OK) return retval; /* MRC p14,0,r0,c0,c5,0 */ retval = arm11_run_instr_data_to_core1(arm11, 0xee100e15, address); if (retval != ERROR_OK) return retval; switch (size) { case 1: arm11->arm.core_cache->reg_list[1].dirty = true; for (size_t i = 0; i < count; i++) { /* ldrb r1, [r0], #1 */ /* ldrb r1, [r0] */ CHECK_RETVAL(arm11_run_instr_no_data1(arm11, !arm11_config_memrw_no_increment ? 0xe4d01001 : 0xe5d01000)); uint32_t res; /* MCR p14,0,R1,c0,c5,0 */ CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1)); *buffer++ = res; } break; case 2: { arm11->arm.core_cache->reg_list[1].dirty = true; for (size_t i = 0; i < count; i++) { /* ldrh r1, [r0], #2 */ CHECK_RETVAL(arm11_run_instr_no_data1(arm11, !arm11_config_memrw_no_increment ? 0xe0d010b2 : 0xe1d010b0)); uint32_t res; /* MCR p14,0,R1,c0,c5,0 */ CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1)); uint16_t svalue = res; memcpy(buffer + i * sizeof(uint16_t), &svalue, sizeof(uint16_t)); } break; } case 4: { uint32_t instr = !arm11_config_memrw_no_increment ? 0xecb05e01 : 0xed905e00; /** \todo TODO: buffer cast to uint32_t* causes alignment warnings */ uint32_t *words = (uint32_t *)(void *)buffer; /* LDC p14,c5,[R0],#4 */ /* LDC p14,c5,[R0] */ CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, instr, words, count)); break; } } return arm11_run_instr_data_finish(arm11); } static int arm11_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { return arm11_read_memory_inner(target, address, size, count, buffer, false); } /* * no_increment - in the future we may want to be able * to read/write a range of data to a "port". a "port" is an action on * read memory address for some peripheral. */ static int arm11_write_memory_inner(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer, bool no_increment) { int retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target was not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_DEBUG("ADDR %08" PRIx32 " SIZE %08" PRIx32 " COUNT %08" PRIx32 "", address, size, count); struct arm11_common *arm11 = target_to_arm11(target); retval = arm11_run_instr_data_prepare(arm11); if (retval != ERROR_OK) return retval; /* load r0 with buffer address * MRC p14,0,r0,c0,c5,0 */ retval = arm11_run_instr_data_to_core1(arm11, 0xee100e15, address); if (retval != ERROR_OK) return retval; /* burst writes are not used for single words as those may well be * reset init script writes. * * The other advantage is that as burst writes are default, we'll * now exercise both burst and non-burst code paths with the * default settings, increasing code coverage. */ bool burst = arm11->memwrite_burst && (count > 1); switch (size) { case 1: { arm11->arm.core_cache->reg_list[1].dirty = true; for (size_t i = 0; i < count; i++) { /* load r1 from DCC with byte data */ /* MRC p14,0,r1,c0,c5,0 */ retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buffer++); if (retval != ERROR_OK) return retval; /* write r1 to memory */ /* strb r1, [r0], #1 */ /* strb r1, [r0] */ retval = arm11_run_instr_no_data1(arm11, !no_increment ? 0xe4c01001 : 0xe5c01000); if (retval != ERROR_OK) return retval; } break; } case 2: { arm11->arm.core_cache->reg_list[1].dirty = true; for (size_t i = 0; i < count; i++) { uint16_t value; memcpy(&value, buffer + i * sizeof(uint16_t), sizeof(uint16_t)); /* load r1 from DCC with halfword data */ /* MRC p14,0,r1,c0,c5,0 */ retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, value); if (retval != ERROR_OK) return retval; /* write r1 to memory */ /* strh r1, [r0], #2 */ /* strh r1, [r0] */ retval = arm11_run_instr_no_data1(arm11, !no_increment ? 0xe0c010b2 : 0xe1c010b0); if (retval != ERROR_OK) return retval; } break; } case 4: { /* stream word data through DCC directly to memory */ /* increment: STC p14,c5,[R0],#4 */ /* no increment: STC p14,c5,[R0]*/ uint32_t instr = !no_increment ? 0xeca05e01 : 0xed805e00; /** \todo TODO: buffer cast to uint32_t* causes alignment warnings */ uint32_t *words = (uint32_t *)(void *)buffer; /* "burst" here just means trusting each instruction executes * fully before we run the next one: per-word roundtrips, to * check the Ready flag, are not used. */ if (!burst) retval = arm11_run_instr_data_to_core(arm11, instr, words, count); else retval = arm11_run_instr_data_to_core_noack(arm11, instr, words, count); if (retval != ERROR_OK) return retval; break; } } /* r0 verification */ if (!no_increment) { uint32_t r0; /* MCR p14,0,R0,c0,c5,0 */ retval = arm11_run_instr_data_from_core(arm11, 0xEE000E15, &r0, 1); if (retval != ERROR_OK) return retval; if (address + size * count != r0) { LOG_ERROR("Data transfer failed. Expected end " "address 0x%08x, got 0x%08x", (unsigned) (address + size * count), (unsigned) r0); if (burst) LOG_ERROR( "use 'arm11 memwrite burst disable' to disable fast burst mode"); if (arm11->memwrite_error_fatal) return ERROR_FAIL; } } return arm11_run_instr_data_finish(arm11); } static int arm11_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { /* pointer increment matters only for multi-unit writes ... * not e.g. to a "reset the chip" controller. */ return arm11_write_memory_inner(target, address, size, count, buffer, count == 1); } /* target break-/watchpoint control * rw: 0 = write, 1 = read, 2 = access */ static int arm11_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct arm11_common *arm11 = target_to_arm11(target); #if 0 if (breakpoint->type == BKPT_SOFT) { LOG_INFO("sw breakpoint requested, but software breakpoints not enabled"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } #endif if (!arm11->free_brps) { LOG_DEBUG("no breakpoint unit available for hardware breakpoint"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->length != 4) { LOG_DEBUG("only breakpoints of four bytes length supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } arm11->free_brps--; return ERROR_OK; } static int arm11_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct arm11_common *arm11 = target_to_arm11(target); arm11->free_brps++; return ERROR_OK; } static int arm11_target_create(struct target *target, Jim_Interp *interp) { struct arm11_common *arm11; if (!target->tap) return ERROR_FAIL; if (target->tap->ir_length != 5) { LOG_ERROR("'target arm11' expects IR LENGTH = 5"); return ERROR_COMMAND_SYNTAX_ERROR; } arm11 = calloc(1, sizeof(*arm11)); if (!arm11) return ERROR_FAIL; arm11->arm.core_type = ARM_CORE_TYPE_STD; arm_init_arch_info(target, &arm11->arm); arm11->jtag_info.tap = target->tap; arm11->jtag_info.scann_size = 5; arm11->jtag_info.scann_instr = ARM11_SCAN_N; arm11->jtag_info.cur_scan_chain = ~0; /* invalid/unknown */ arm11->jtag_info.intest_instr = ARM11_INTEST; arm11->memwrite_burst = true; arm11->memwrite_error_fatal = true; return ERROR_OK; } static int arm11_init_target(struct command_context *cmd_ctx, struct target *target) { /* Initialize anything we can set up without talking to the target */ return ERROR_OK; } static void arm11_deinit_target(struct target *target) { struct arm11_common *arm11 = target_to_arm11(target); arm11_dpm_deinit(arm11); free(arm11); } /* talk to the target and set things up */ static int arm11_examine(struct target *target) { int retval; char *type; struct arm11_common *arm11 = target_to_arm11(target); uint32_t didr, device_id; uint8_t implementor; /* FIXME split into do-first-time and do-every-time logic ... */ /* check IDCODE */ arm11_add_ir(arm11, ARM11_IDCODE, ARM11_TAP_DEFAULT); struct scan_field idcode_field; arm11_setup_field(arm11, 32, NULL, &device_id, &idcode_field); arm11_add_dr_scan_vc(arm11->arm.target->tap, 1, &idcode_field, TAP_DRPAUSE); /* check DIDR */ arm11_add_debug_scan_n(arm11, 0x00, ARM11_TAP_DEFAULT); arm11_add_ir(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); struct scan_field chain0_fields[2]; arm11_setup_field(arm11, 32, NULL, &didr, chain0_fields + 0); arm11_setup_field(arm11, 8, NULL, &implementor, chain0_fields + 1); arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain0_fields), chain0_fields, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); /* assume the manufacturer id is ok; check the part # */ switch ((device_id >> 12) & 0xFFFF) { case 0x7B36: type = "ARM1136"; break; case 0x7B37: type = "ARM11 MPCore"; break; case 0x7B56: type = "ARM1156"; break; case 0x7B76: arm11->arm.core_type = ARM_CORE_TYPE_SEC_EXT; /* NOTE: could default arm11->hardware_step to true */ type = "ARM1176"; break; default: LOG_ERROR("unexpected ARM11 ID code"); return ERROR_FAIL; } LOG_INFO("found %s", type); /* unlikely this could ever fail, but ... */ switch ((didr >> 16) & 0x0F) { case ARM11_DEBUG_V6: case ARM11_DEBUG_V61: /* supports security extensions */ break; default: LOG_ERROR("Only ARM v6 and v6.1 debug supported."); return ERROR_FAIL; } arm11->brp = ((didr >> 24) & 0x0F) + 1; /** \todo TODO: reserve one brp slot if we allow breakpoints during step */ arm11->free_brps = arm11->brp; LOG_DEBUG("IDCODE %08" PRIx32 " IMPLEMENTOR %02x DIDR %08" PRIx32, device_id, implementor, didr); /* Build register cache "late", after target_init(), since we * want to know if this core supports Secure Monitor mode. */ if (!target_was_examined(target)) CHECK_RETVAL(arm11_dpm_init(arm11, didr)); /* as a side-effect this reads DSCR and thus * clears the ARM11_DSCR_STICKY_PRECISE_DATA_ABORT / Sticky Precise Data Abort Flag * as suggested by the spec. */ retval = arm11_check_init(arm11); if (retval != ERROR_OK) return retval; /* ETM on ARM11 still uses original scanchain 6 access mode */ if (arm11->arm.etm && !target_was_examined(target)) { *register_get_last_cache_p(&target->reg_cache) = etm_build_reg_cache(target, &arm11->jtag_info, arm11->arm.etm); CHECK_RETVAL(etm_setup(target)); } target_set_examined(target); return ERROR_OK; } #define ARM11_BOOL_WRAPPER(name, print_name) \ COMMAND_HANDLER(arm11_handle_bool_ ## name) \ { \ struct target *target = get_current_target(CMD_CTX); \ struct arm11_common *arm11 = target_to_arm11(target); \ \ return CALL_COMMAND_HANDLER(handle_command_parse_bool, \ &arm11->name, print_name); \ } ARM11_BOOL_WRAPPER(memwrite_burst, "memory write burst mode") ARM11_BOOL_WRAPPER(memwrite_error_fatal, "fatal error mode for memory writes") ARM11_BOOL_WRAPPER(step_irq_enable, "IRQs while stepping") ARM11_BOOL_WRAPPER(hardware_step, "hardware single step") /* REVISIT handle the VCR bits like other ARMs: use symbols for * input and output values. */ COMMAND_HANDLER(arm11_handle_vcr) { struct target *target = get_current_target(CMD_CTX); struct arm11_common *arm11 = target_to_arm11(target); switch (CMD_ARGC) { case 0: break; case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], arm11->vcr); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } LOG_INFO("VCR 0x%08" PRIx32 "", arm11->vcr); return ERROR_OK; } static const struct command_registration arm11_mw_command_handlers[] = { { .name = "burst", .handler = arm11_handle_bool_memwrite_burst, .mode = COMMAND_ANY, .help = "Display or modify flag controlling potentially " "risky fast burst mode (default: enabled)", .usage = "['enable'|'disable']", }, { .name = "error_fatal", .handler = arm11_handle_bool_memwrite_error_fatal, .mode = COMMAND_ANY, .help = "Display or modify flag controlling transfer " "termination on transfer errors" " (default: enabled)", .usage = "['enable'|'disable']", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration arm11_any_command_handlers[] = { { /* "hardware_step" is only here to check if the default * simulate + breakpoint implementation is broken. * TEMPORARY! NOT DOCUMENTED! */ .name = "hardware_step", .handler = arm11_handle_bool_hardware_step, .mode = COMMAND_ANY, .help = "DEBUG ONLY - Hardware single stepping" " (default: disabled)", .usage = "['enable'|'disable']", }, { .name = "memwrite", .mode = COMMAND_ANY, .help = "memwrite command group", .usage = "", .chain = arm11_mw_command_handlers, }, { .name = "step_irq_enable", .handler = arm11_handle_bool_step_irq_enable, .mode = COMMAND_ANY, .help = "Display or modify flag controlling interrupt " "enable while stepping (default: disabled)", .usage = "['enable'|'disable']", }, { .name = "vcr", .handler = arm11_handle_vcr, .mode = COMMAND_ANY, .help = "Display or modify Vector Catch Register", .usage = "[value]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration arm11_command_handlers[] = { { .chain = arm_command_handlers, }, { .chain = etm_command_handlers, }, { .name = "arm11", .mode = COMMAND_ANY, .help = "ARM11 command group", .usage = "", .chain = arm11_any_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Holds methods for ARM11xx targets. */ struct target_type arm11_target = { .name = "arm11", .poll = arm11_poll, .arch_state = arm11_arch_state, .halt = arm11_halt, .resume = arm11_resume, .step = arm11_step, .assert_reset = arm11_assert_reset, .deassert_reset = arm11_deassert_reset, .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm11_read_memory, .write_memory = arm11_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .add_breakpoint = arm11_add_breakpoint, .remove_breakpoint = arm11_remove_breakpoint, .run_algorithm = armv4_5_run_algorithm, .commands = arm11_command_handlers, .target_create = arm11_target_create, .init_target = arm11_init_target, .deinit_target = arm11_deinit_target, .examine = arm11_examine, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm11.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2008 digenius technology GmbH. * * Michael Bruck * * * * Copyright (C) 2008 Georg Acher <acher@in.tum.de> * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM11_H #define OPENOCD_TARGET_ARM11_H #include "arm.h" #include "arm_dpm.h" #define ARM11_TAP_DEFAULT TAP_INVALID #define CHECK_RETVAL(action) \ do { \ int __retval = (action); \ if (__retval != ERROR_OK) { \ LOG_DEBUG("error while calling \"%s\"", \ # action); \ return __retval; \ } \ } while (0) /* bits from ARMv7 DIDR */ enum arm11_debug_version { ARM11_DEBUG_V6 = 0x01, ARM11_DEBUG_V61 = 0x02, ARM11_DEBUG_V7 = 0x03, ARM11_DEBUG_V7_CP14 = 0x04, }; struct arm11_common { struct arm arm; /** Debug module state. */ struct arm_dpm dpm; struct arm11_sc7_action *bpwp_actions; unsigned bpwp_n; size_t brp; /**< Number of Breakpoint Register Pairs from DIDR */ size_t free_brps; /**< Number of breakpoints allocated */ uint32_t dscr; /**< Last retrieved DSCR value. */ uint32_t saved_rdtr; uint32_t saved_wdtr; bool is_rdtr_saved; bool is_wdtr_saved; bool simulate_reset_on_next_halt; /**< Perform cleanups of the ARM state on next halt **/ /* Per-core configurable options. * NOTE that several of these boolean options should not exist * once the relevant code is known to work correctly. */ bool memwrite_burst; bool memwrite_error_fatal; bool step_irq_enable; bool hardware_step; /** Configured Vector Catch Register settings. */ uint32_t vcr; struct arm_jtag jtag_info; }; static inline struct arm11_common *target_to_arm11(struct target *target) { return container_of(target->arch_info, struct arm11_common, arm); } /** * ARM11 DBGTAP instructions * * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/I1006229.html */ enum arm11_instructions { ARM11_EXTEST = 0x00, ARM11_SCAN_N = 0x02, ARM11_RESTART = 0x04, ARM11_HALT = 0x08, ARM11_INTEST = 0x0C, ARM11_ITRSEL = 0x1D, ARM11_IDCODE = 0x1E, ARM11_BYPASS = 0x1F, }; enum arm11_sc7 { ARM11_SC7_NULL = 0, ARM11_SC7_VCR = 7, ARM11_SC7_PC = 8, ARM11_SC7_BVR0 = 64, ARM11_SC7_BCR0 = 80, ARM11_SC7_WVR0 = 96, ARM11_SC7_WCR0 = 112, }; #endif /* OPENOCD_TARGET_ARM11_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm11_dbgtap.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2008 digenius technology GmbH. * * Michael Bruck * * * * Copyright (C) 2008,2009 Oyvind Harboe oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm_jtag.h" #include "arm11_dbgtap.h" #include <helper/time_support.h> #if 0 #define JTAG_DEBUG(expr ...) do { if (1) \ LOG_DEBUG(expr); } while (0) #else #define JTAG_DEBUG(expr ...) do { if (0) \ LOG_DEBUG(expr); } while (0) #endif /* This pathmove goes from Pause-IR to Shift-IR while avoiding RTI. The behavior of the FTDI driver IIRC was to go via RTI. Conversely there may be other places in this code where the ARM11 code relies on the driver to hit through RTI when coming from Update-?R. */ static const tap_state_t arm11_move_pi_to_si_via_ci[] = { TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IRSHIFT }; /* REVISIT no error handling here! */ static void arm11_add_ir_scan_vc(struct jtag_tap *tap, struct scan_field *fields, tap_state_t state) { if (cmd_queue_cur_state == TAP_IRPAUSE) jtag_add_pathmove(ARRAY_SIZE(arm11_move_pi_to_si_via_ci), arm11_move_pi_to_si_via_ci); jtag_add_ir_scan(tap, fields, state); } static const tap_state_t arm11_move_pd_to_sd_via_cd[] = { TAP_DREXIT2, TAP_DRUPDATE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DRSHIFT }; /* REVISIT no error handling here! */ void arm11_add_dr_scan_vc(struct jtag_tap *tap, int num_fields, struct scan_field *fields, tap_state_t state) { if (cmd_queue_cur_state == TAP_DRPAUSE) jtag_add_pathmove(ARRAY_SIZE(arm11_move_pd_to_sd_via_cd), arm11_move_pd_to_sd_via_cd); jtag_add_dr_scan(tap, num_fields, fields, state); } /** Code de-clutter: Construct struct scan_field to write out a value * * \param arm11 Target state variable. * \param num_bits Length of the data field * \param out_data pointer to the data that will be sent out * <em > (data is read when it is added to the JTAG queue)</em> * \param in_data pointer to the memory that will receive data that was clocked in * <em > (data is written when the JTAG queue is executed)</em> * \param field target data structure that will be initialized */ void arm11_setup_field(struct arm11_common *arm11, int num_bits, void *out_data, void *in_data, struct scan_field *field) { field->num_bits = num_bits; field->out_value = out_data; field->in_value = in_data; } static const char *arm11_ir_to_string(uint8_t ir) { const char *s = "unknown"; switch (ir) { case ARM11_EXTEST: s = "EXTEST"; break; case ARM11_SCAN_N: s = "SCAN_N"; break; case ARM11_RESTART: s = "RESTART"; break; case ARM11_HALT: s = "HALT"; break; case ARM11_INTEST: s = "INTEST"; break; case ARM11_ITRSEL: s = "ITRSEL"; break; case ARM11_IDCODE: s = "IDCODE"; break; case ARM11_BYPASS: s = "BYPASS"; break; } return s; } /** Write JTAG instruction register * * \param arm11 Target state variable. * \param instr An ARM11 DBGTAP instruction. Use enum #arm11_instructions. * \param state Pass the final TAP state or ARM11_TAP_DEFAULT for the default value (Pause-IR). * * \remarks This adds to the JTAG command queue but does \em not execute it. */ void arm11_add_ir(struct arm11_common *arm11, uint8_t instr, tap_state_t state) { struct jtag_tap *tap = arm11->arm.target->tap; if (buf_get_u32(tap->cur_instr, 0, 5) == instr) { JTAG_DEBUG("IR <= 0x%02x SKIPPED", instr); return; } JTAG_DEBUG("IR <= %s (0x%02x)", arm11_ir_to_string(instr), instr); struct scan_field field; arm11_setup_field(arm11, 5, &instr, NULL, &field); arm11_add_ir_scan_vc(arm11->arm.target->tap, &field, state == ARM11_TAP_DEFAULT ? TAP_IRPAUSE : state); } /** Verify data shifted out from Scan Chain Register (SCREG). */ static void arm11_in_handler_scan_n(uint8_t *in_value) { /* Don't expect JTAG layer to modify bits we didn't ask it to read */ uint8_t v = *in_value & 0x1F; if (v != 0x10) { LOG_ERROR("'arm11 target' JTAG error SCREG OUT 0x%02x", v); jtag_set_error(ERROR_FAIL); } } /** Select and write to Scan Chain Register (SCREG) * * This function sets the instruction register to SCAN_N and writes * the data register with the selected chain number. * * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/Cacbjhfg.html * * \param arm11 Target state variable. * \param chain Scan chain that will be selected. * \param state Pass the final TAP state or ARM11_TAP_DEFAULT for the default * value (Pause-DR). * * Changes the current scan chain if needed, transitions to the specified * TAP state, and leaves the IR undefined. * * The chain takes effect when Update-DR is passed (usually when subsequently * the INTEXT/EXTEST instructions are written). * * \warning (Obsolete) Using this twice in a row will \em fail. The first * call will end in Pause-DR. The second call, due to the IR * caching, will not go through Capture-DR when shifting in the * new scan chain number. As a result the verification in * arm11_in_handler_scan_n() must fail. * * \remarks This adds to the JTAG command queue but does \em not execute it. */ int arm11_add_debug_scan_n(struct arm11_common *arm11, uint8_t chain, tap_state_t state) { /* Don't needlessly switch the scan chain. * NOTE: the ITRSEL instruction fakes SCREG changing; * but leaves its actual value unchanged. */ #if 0 /* FIX!!! the optimization below is broken because we do not */ /* invalidate the cur_scan_chain upon a TRST/TMS. See arm_jtag.c */ /* for example on how to invalidate cur_scan_chain. Tested patches gladly */ /* accepted! */ if (arm11->jtag_info.cur_scan_chain == chain) { JTAG_DEBUG("SCREG <= %d SKIPPED", chain); return jtag_add_statemove((state == ARM11_TAP_DEFAULT) ? TAP_DRPAUSE : state); } #endif JTAG_DEBUG("SCREG <= %d", chain); arm11_add_ir(arm11, ARM11_SCAN_N, ARM11_TAP_DEFAULT); struct scan_field field; uint8_t tmp[1]; arm11_setup_field(arm11, 5, &chain, &tmp, &field); arm11_add_dr_scan_vc(arm11->arm.target->tap, 1, &field, state == ARM11_TAP_DEFAULT ? TAP_DRPAUSE : state); jtag_execute_queue_noclear(); arm11_in_handler_scan_n(tmp); arm11->jtag_info.cur_scan_chain = chain; return jtag_execute_queue(); } /** * Queue a DR scan of the ITR register. Caller must have selected * scan chain 4 (ITR), possibly using ITRSEL. * * \param arm11 Target state variable. * \param inst An ARM11 processor instruction/opcode. * \param flag Optional parameter to retrieve the Ready flag; * this address will be written when the JTAG chain is scanned. * \param state The TAP state to enter after the DR scan. * * Going through the TAP_DRUPDATE state writes ITR only if Ready was * previously set. Only the Ready flag is readable by the scan. * * An instruction loaded into ITR is executed when going through the * TAP_IDLE state only if Ready was previously set and the debug state * is properly set up. Depending on the instruction, you may also need * to ensure that the rDTR is ready before that Run-Test/Idle state. */ static void arm11_add_debug_inst(struct arm11_common *arm11, uint32_t inst, uint8_t *flag, tap_state_t state) { JTAG_DEBUG("INST <= 0x%08x", (unsigned) inst); struct scan_field itr[2]; arm11_setup_field(arm11, 32, &inst, NULL, itr + 0); arm11_setup_field(arm11, 1, NULL, flag, itr + 1); arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE(itr), itr, state); } /** * Read and save the Debug Status and Control Register (DSCR). * * \param arm11 Target state variable. * \return Error status; arm11->dscr is updated on success. * * \remarks This is a stand-alone function that executes the JTAG * command queue. It does not require the ARM11 debug TAP to be * in any particular state. */ int arm11_read_dscr(struct arm11_common *arm11) { int retval; retval = arm11_add_debug_scan_n(arm11, 0x01, ARM11_TAP_DEFAULT); if (retval != ERROR_OK) return retval; arm11_add_ir(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); uint32_t dscr; struct scan_field chain1_field; arm11_setup_field(arm11, 32, NULL, &dscr, &chain1_field); arm11_add_dr_scan_vc(arm11->arm.target->tap, 1, &chain1_field, TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); if (arm11->dscr != dscr) JTAG_DEBUG("DSCR = %08x (OLD %08x)", (unsigned) dscr, (unsigned) arm11->dscr); arm11->dscr = dscr; return ERROR_OK; } /** Write the Debug Status and Control Register (DSCR) * * same as CP14 c1 * * \param arm11 Target state variable. * \param dscr DSCR content * * \remarks This is a stand-alone function that executes the JTAG command queue. */ int arm11_write_dscr(struct arm11_common *arm11, uint32_t dscr) { int retval; retval = arm11_add_debug_scan_n(arm11, 0x01, ARM11_TAP_DEFAULT); if (retval != ERROR_OK) return retval; arm11_add_ir(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); struct scan_field chain1_field; arm11_setup_field(arm11, 32, &dscr, NULL, &chain1_field); arm11_add_dr_scan_vc(arm11->arm.target->tap, 1, &chain1_field, TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); JTAG_DEBUG("DSCR <= %08x (OLD %08x)", (unsigned) dscr, (unsigned) arm11->dscr); arm11->dscr = dscr; return ERROR_OK; } /** Prepare the stage for ITR/DTR operations * from the arm11_run_instr... group of functions. * * Put arm11_run_instr_data_prepare() and arm11_run_instr_data_finish() * around a block of arm11_run_instr_... calls. * * Select scan chain 5 to allow quick access to DTR. When scan * chain 4 is needed to put in a register the ITRSel instruction * shortcut is used instead of actually changing the Scan_N * register. * * \param arm11 Target state variable. * */ int arm11_run_instr_data_prepare(struct arm11_common *arm11) { return arm11_add_debug_scan_n(arm11, 0x05, ARM11_TAP_DEFAULT); } /** Cleanup after ITR/DTR operations * from the arm11_run_instr... group of functions * * Put arm11_run_instr_data_prepare() and arm11_run_instr_data_finish() * around a block of arm11_run_instr_... calls. * * Any IDLE can lead to an instruction execution when * scan chains 4 or 5 are selected and the IR holds * INTEST or EXTEST. So we must disable that before * any following activities lead to an IDLE. * * \param arm11 Target state variable. * */ int arm11_run_instr_data_finish(struct arm11_common *arm11) { return arm11_add_debug_scan_n(arm11, 0x00, ARM11_TAP_DEFAULT); } /** * Execute one or more instructions via ITR. * Caller guarantees that processor is in debug state, that DSCR_ITR_EN * is set, the ITR Ready flag is set (as seen on the previous entry to * TAP_DRCAPTURE), and the DSCR sticky abort flag is clear. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode Pointer to sequence of ARM opcodes * \param count Number of opcodes to execute * */ static int arm11_run_instr_no_data(struct arm11_common *arm11, uint32_t *opcode, size_t count) { arm11_add_ir(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); while (count--) { arm11_add_debug_inst(arm11, *opcode++, NULL, TAP_IDLE); int i = 0; while (1) { uint8_t flag; arm11_add_debug_inst(arm11, 0, &flag, count ? TAP_IDLE : TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); if (flag) break; int64_t then = 0; if (i == 1000) then = timeval_ms(); if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING( "Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } } return ERROR_OK; } /** Execute one instruction via ITR * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode * */ int arm11_run_instr_no_data1(struct arm11_common *arm11, uint32_t opcode) { return arm11_run_instr_no_data(arm11, &opcode, 1); } /** Execute one instruction via ITR repeatedly while * passing data to the core via DTR on each execution. * * Caller guarantees that processor is in debug state, that DSCR_ITR_EN * is set, the ITR Ready flag is set (as seen on the previous entry to * TAP_DRCAPTURE), and the DSCR sticky abort flag is clear. * * The executed instruction \em must read data from DTR. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode * \param data Pointer to the data words to be passed to the core * \param count Number of data words and instruction repetitions * */ int arm11_run_instr_data_to_core(struct arm11_common *arm11, uint32_t opcode, uint32_t *data, size_t count) { arm11_add_ir(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); arm11_add_debug_inst(arm11, opcode, NULL, TAP_DRPAUSE); arm11_add_ir(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; uint32_t _data; uint8_t ready; uint8_t n_retry; arm11_setup_field(arm11, 32, &_data, NULL, chain5_fields + 0); arm11_setup_field(arm11, 1, NULL, &ready, chain5_fields + 1); arm11_setup_field(arm11, 1, NULL, &n_retry, chain5_fields + 2); while (count--) { int i = 0; do { _data = *data; arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); JTAG_DEBUG("DTR ready %d n_retry %d", ready, n_retry); int64_t then = 0; if (i == 1000) then = timeval_ms(); if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING( "Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } while (!ready); data++; } arm11_add_ir(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); int i = 0; do { _data = 0; arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); JTAG_DEBUG("DTR _data %08x ready %d n_retry %d", (unsigned) _data, ready, n_retry); int64_t then = 0; if (i == 1000) then = timeval_ms(); if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING("Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } while (!ready); return ERROR_OK; } /** JTAG path for arm11_run_instr_data_to_core_noack * * The repeated TAP_IDLE's do not cause a repeated execution * if passed without leaving the state. * * Since this is more than 7 bits (adjustable via adding more * TAP_IDLE's) it produces an artificial delay in the lower * layer (FT2232) that is long enough to finish execution on * the core but still shorter than any manually inducible delays. * * To disable this code, try "memwrite burst false" * * FIX!!! should we use multiple TAP_IDLE here or not??? * * https://lists.berlios.de/pipermail/openocd-development/2009-July/009698.html * https://lists.berlios.de/pipermail/openocd-development/2009-August/009865.html */ static const tap_state_t arm11_move_drpause_idle_drpause_with_delay[] = { TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE, TAP_IDLE, TAP_IDLE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DRSHIFT }; static int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, uint32_t opcode, uint32_t *data, size_t count) { struct scan_field chain5_fields[3]; chain5_fields[0].num_bits = 32; chain5_fields[0].out_value = NULL; /*&Data*/ chain5_fields[0].in_value = NULL; chain5_fields[1].num_bits = 1; chain5_fields[1].out_value = NULL; chain5_fields[1].in_value = NULL; /*&Ready*/ chain5_fields[2].num_bits = 1; chain5_fields[2].out_value = NULL; chain5_fields[2].in_value = NULL; uint8_t *readies; unsigned readies_num = count; unsigned bytes = sizeof(*readies)*readies_num; readies = malloc(bytes); if (!readies) { LOG_ERROR("Out of memory allocating %u bytes", bytes); return ERROR_FAIL; } uint8_t *ready_pos = readies; while (count--) { chain5_fields[0].out_value = (uint8_t *)(data++); chain5_fields[1].in_value = ready_pos++; if (count > 0) { jtag_add_dr_scan(tap, ARRAY_SIZE(chain5_fields), chain5_fields, TAP_DRPAUSE); jtag_add_pathmove(ARRAY_SIZE(arm11_move_drpause_idle_drpause_with_delay), arm11_move_drpause_idle_drpause_with_delay); } else jtag_add_dr_scan(tap, ARRAY_SIZE(chain5_fields), chain5_fields, TAP_IDLE); } int retval = jtag_execute_queue(); if (retval == ERROR_OK) { unsigned error_count = 0; for (size_t i = 0; i < readies_num; i++) { if (readies[i] != 1) error_count++; } if (error_count > 0) { LOG_ERROR("%u words out of %u not transferred", error_count, readies_num); retval = ERROR_FAIL; } } free(readies); return retval; } /** Execute one instruction via ITR repeatedly while * passing data to the core via DTR on each execution. * * Caller guarantees that processor is in debug state, that DSCR_ITR_EN * is set, the ITR Ready flag is set (as seen on the previous entry to * TAP_DRCAPTURE), and the DSCR sticky abort flag is clear. * * No Ready check during transmission. * * The executed instruction \em must read data from DTR. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode * \param data Pointer to the data words to be passed to the core * \param count Number of data words and instruction repetitions * */ int arm11_run_instr_data_to_core_noack(struct arm11_common *arm11, uint32_t opcode, uint32_t *data, size_t count) { arm11_add_ir(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); arm11_add_debug_inst(arm11, opcode, NULL, TAP_DRPAUSE); arm11_add_ir(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); int retval = arm11_run_instr_data_to_core_noack_inner(arm11->arm.target->tap, opcode, data, count); if (retval != ERROR_OK) return retval; arm11_add_ir(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; arm11_setup_field(arm11, 32, NULL /*&Data*/, NULL, chain5_fields + 0); arm11_setup_field(arm11, 1, NULL, NULL /*&Ready*/, chain5_fields + 1); arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 2); uint8_t ready_flag; chain5_fields[1].in_value = &ready_flag; arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, TAP_DRPAUSE); retval = jtag_execute_queue(); if (retval == ERROR_OK) { if (ready_flag != 1) { LOG_ERROR("last word not transferred"); retval = ERROR_FAIL; } } return retval; } /** Execute an instruction via ITR while handing data into the core via DTR. * * The executed instruction \em must read data from DTR. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode * \param data Data word to be passed to the core via DTR * */ int arm11_run_instr_data_to_core1(struct arm11_common *arm11, uint32_t opcode, uint32_t data) { return arm11_run_instr_data_to_core(arm11, opcode, &data, 1); } /** Execute one instruction via ITR repeatedly while * reading data from the core via DTR on each execution. * * Caller guarantees that processor is in debug state, that DSCR_ITR_EN * is set, the ITR Ready flag is set (as seen on the previous entry to * TAP_DRCAPTURE), and the DSCR sticky abort flag is clear. * * The executed instruction \em must write data to DTR. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode * \param data Pointer to an array that receives the data words from the core * \param count Number of data words and instruction repetitions * */ int arm11_run_instr_data_from_core(struct arm11_common *arm11, uint32_t opcode, uint32_t *data, size_t count) { arm11_add_ir(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); arm11_add_debug_inst(arm11, opcode, NULL, TAP_IDLE); arm11_add_ir(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; uint32_t _data; uint8_t ready; uint8_t n_retry; arm11_setup_field(arm11, 32, NULL, &_data, chain5_fields + 0); arm11_setup_field(arm11, 1, NULL, &ready, chain5_fields + 1); arm11_setup_field(arm11, 1, NULL, &n_retry, chain5_fields + 2); while (count--) { int i = 0; do { arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, count ? TAP_IDLE : TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); JTAG_DEBUG("DTR _data %08x ready %d n_retry %d", (unsigned) _data, ready, n_retry); int64_t then = 0; if (i == 1000) then = timeval_ms(); if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING( "Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } while (!ready); *data++ = _data; } return ERROR_OK; } /** Execute one instruction via ITR * then load r0 into DTR and read DTR from core. * * The first executed instruction (\p opcode) should write data to r0. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode to write r0 with the value of interest * \param data Pointer to a data word that receives the value from r0 after \p opcode was executed. * */ int arm11_run_instr_data_from_core_via_r0(struct arm11_common *arm11, uint32_t opcode, uint32_t *data) { int retval; retval = arm11_run_instr_no_data1(arm11, opcode); if (retval != ERROR_OK) return retval; /* MCR p14,0,R0,c0,c5,0 (move r0 -> wDTR -> local var) */ arm11_run_instr_data_from_core(arm11, 0xEE000E15, data, 1); return ERROR_OK; } /** Load data into core via DTR then move it to r0 then * execute one instruction via ITR * * The final executed instruction (\p opcode) should read data from r0. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode to read r0 act upon it * \param data Data word that will be written to r0 before \p opcode is executed * */ int arm11_run_instr_data_to_core_via_r0(struct arm11_common *arm11, uint32_t opcode, uint32_t data) { int retval; /* MRC p14,0,r0,c0,c5,0 */ retval = arm11_run_instr_data_to_core1(arm11, 0xEE100E15, data); if (retval != ERROR_OK) return retval; retval = arm11_run_instr_no_data1(arm11, opcode); if (retval != ERROR_OK) return retval; return ERROR_OK; } /** Apply reads and writes to scan chain 7 * * \see struct arm11_sc7_action * * \param arm11 Target state variable. * \param actions A list of read and/or write instructions * \param count Number of instructions in the list. * */ int arm11_sc7_run(struct arm11_common *arm11, struct arm11_sc7_action *actions, size_t count) { int retval; retval = arm11_add_debug_scan_n(arm11, 0x07, ARM11_TAP_DEFAULT); if (retval != ERROR_OK) return retval; arm11_add_ir(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); struct scan_field chain7_fields[3]; uint8_t n_rw; uint32_t data_out; uint8_t address_out; uint8_t ready; uint32_t data_in; uint8_t address_in; arm11_setup_field(arm11, 1, &n_rw, &ready, chain7_fields + 0); arm11_setup_field(arm11, 32, &data_out, &data_in, chain7_fields + 1); arm11_setup_field(arm11, 7, &address_out, &address_in, chain7_fields + 2); for (size_t i = 0; i < count + 1; i++) { if (i < count) { n_rw = actions[i].write ? 1 : 0; data_out = actions[i].value; address_out = actions[i].address; } else { n_rw = 1; data_out = 0; address_out = 0; } /* Timeout here so we don't get stuck. */ int i_n = 0; while (1) { JTAG_DEBUG("SC7 <= c%-3d Data %08x %s", (unsigned) address_out, (unsigned) data_out, n_rw ? "write" : "read"); arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE(chain7_fields), chain7_fields, TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); /* 'n_rw' is 'ready' on read out */ if (ready) break; int64_t then = 0; if (i_n == 1000) then = timeval_ms(); if (i_n >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING( "Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i_n++; } if (!n_rw) JTAG_DEBUG("SC7 => Data %08x", (unsigned) data_in); if (i > 0) { if (actions[i - 1].address != address_in) LOG_WARNING("Scan chain 7 shifted out unexpected address"); if (!actions[i - 1].write) actions[i - 1].value = data_in; else { if (actions[i - 1].value != data_in) LOG_WARNING("Scan chain 7 shifted out unexpected data"); } } } return ERROR_OK; } /** Clear VCR and all breakpoints and watchpoints via scan chain 7 * * \param arm11 Target state variable. * */ int arm11_sc7_clear_vbw(struct arm11_common *arm11) { size_t clear_bw_size = arm11->brp + 1; struct arm11_sc7_action *clear_bw = malloc(sizeof(struct arm11_sc7_action) * clear_bw_size); struct arm11_sc7_action *pos = clear_bw; for (size_t i = 0; i < clear_bw_size; i++) { clear_bw[i].write = true; clear_bw[i].value = 0; } for (size_t i = 0; i < arm11->brp; i++) (pos++)->address = ARM11_SC7_BCR0 + i; (pos++)->address = ARM11_SC7_VCR; int retval; retval = arm11_sc7_run(arm11, clear_bw, clear_bw_size); free(clear_bw); return retval; } /** Write VCR register * * \param arm11 Target state variable. * \param value Value to be written */ int arm11_sc7_set_vcr(struct arm11_common *arm11, uint32_t value) { struct arm11_sc7_action set_vcr; set_vcr.write = true; set_vcr.address = ARM11_SC7_VCR; set_vcr.value = value; return arm11_sc7_run(arm11, &set_vcr, 1); } /** Read word from address * * \param arm11 Target state variable. * \param address Memory address to be read * \param result Pointer where to store result * */ int arm11_read_memory_word(struct arm11_common *arm11, uint32_t address, uint32_t *result) { int retval; retval = arm11_run_instr_data_prepare(arm11); if (retval != ERROR_OK) return retval; /* MRC p14,0,r0,c0,c5,0 (r0 = address) */ CHECK_RETVAL(arm11_run_instr_data_to_core1(arm11, 0xee100e15, address)); /* LDC p14,c5,[R0],#4 (DTR = [r0]) */ CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xecb05e01, result, 1)); return arm11_run_instr_data_finish(arm11); } /************************************************************************/ /* * ARM11 provider for the OpenOCD implementation of the standard * architectural ARM v6/v7 "Debug Programmer's Model" (DPM). */ static inline struct arm11_common *dpm_to_arm11(struct arm_dpm *dpm) { return container_of(dpm, struct arm11_common, dpm); } static int arm11_dpm_prepare(struct arm_dpm *dpm) { return arm11_run_instr_data_prepare(dpm_to_arm11(dpm)); } static int arm11_dpm_finish(struct arm_dpm *dpm) { return arm11_run_instr_data_finish(dpm_to_arm11(dpm)); } static int arm11_dpm_instr_write_data_dcc(struct arm_dpm *dpm, uint32_t opcode, uint32_t data) { return arm11_run_instr_data_to_core(dpm_to_arm11(dpm), opcode, &data, 1); } static int arm11_dpm_instr_write_data_r0(struct arm_dpm *dpm, uint32_t opcode, uint32_t data) { return arm11_run_instr_data_to_core_via_r0(dpm_to_arm11(dpm), opcode, data); } static int arm11_dpm_instr_read_data_dcc(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data) { return arm11_run_instr_data_from_core(dpm_to_arm11(dpm), opcode, data, 1); } static int arm11_dpm_instr_read_data_r0(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data) { return arm11_run_instr_data_from_core_via_r0(dpm_to_arm11(dpm), opcode, data); } /* Because arm11_sc7_run() takes a vector of actions, we batch breakpoint * and watchpoint operations instead of running them right away. Since we * pre-allocated our vector, we don't need to worry about space. */ static int arm11_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, uint32_t addr, uint32_t control) { struct arm11_common *arm11 = dpm_to_arm11(dpm); struct arm11_sc7_action *action; action = arm11->bpwp_actions + arm11->bpwp_n; /* Invariant: this bp/wp is disabled. * It also happens that the core is halted here, but for * DPM-based cores we don't actually care about that. */ action[0].write = action[1].write = true; action[0].value = addr; action[1].value = control; switch (index_t) { case 0 ... 15: action[0].address = ARM11_SC7_BVR0 + index_t; action[1].address = ARM11_SC7_BCR0 + index_t; break; case 16 ... 32: index_t -= 16; action[0].address = ARM11_SC7_WVR0 + index_t; action[1].address = ARM11_SC7_WCR0 + index_t; break; default: return ERROR_FAIL; } arm11->bpwp_n += 2; return ERROR_OK; } static int arm11_bpwp_disable(struct arm_dpm *dpm, unsigned index_t) { struct arm11_common *arm11 = dpm_to_arm11(dpm); struct arm11_sc7_action *action; action = arm11->bpwp_actions + arm11->bpwp_n; action[0].write = true; action[0].value = 0; switch (index_t) { case 0 ... 15: action[0].address = ARM11_SC7_BCR0 + index_t; break; case 16 ... 32: index_t -= 16; action[0].address = ARM11_SC7_WCR0 + index_t; break; default: return ERROR_FAIL; } arm11->bpwp_n += 1; return ERROR_OK; } /** Flush any pending breakpoint and watchpoint updates. */ int arm11_bpwp_flush(struct arm11_common *arm11) { int retval; if (!arm11->bpwp_n) return ERROR_OK; retval = arm11_sc7_run(arm11, arm11->bpwp_actions, arm11->bpwp_n); arm11->bpwp_n = 0; return retval; } /** Set up high-level debug module utilities */ int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr) { struct arm_dpm *dpm = &arm11->dpm; int retval; dpm->arm = &arm11->arm; dpm->didr = didr; dpm->prepare = arm11_dpm_prepare; dpm->finish = arm11_dpm_finish; dpm->instr_write_data_dcc = arm11_dpm_instr_write_data_dcc; dpm->instr_write_data_r0 = arm11_dpm_instr_write_data_r0; dpm->instr_read_data_dcc = arm11_dpm_instr_read_data_dcc; dpm->instr_read_data_r0 = arm11_dpm_instr_read_data_r0; dpm->bpwp_enable = arm11_bpwp_enable; dpm->bpwp_disable = arm11_bpwp_disable; retval = arm_dpm_setup(dpm); if (retval != ERROR_OK) return retval; /* alloc enough to enable all breakpoints and watchpoints at once */ arm11->bpwp_actions = calloc(2 * (dpm->nbp + dpm->nwp), sizeof(*arm11->bpwp_actions)); if (!arm11->bpwp_actions) return ERROR_FAIL; retval = arm_dpm_initialize(dpm); if (retval != ERROR_OK) return retval; return arm11_bpwp_flush(arm11); } void arm11_dpm_deinit(struct arm11_common *arm11) { struct arm_dpm *dpm = &arm11->dpm; free(arm11->bpwp_actions); arm_free_reg_cache(dpm->arm); free(dpm->dbp); free(dpm->dwp); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm11_dbgtap.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2008 digenius technology GmbH. * * Michael Bruck * * * * Copyright (C) 2008,2009 Oyvind Harboe oyvind.harboe@zylin.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM11_DBGTAP_H #define OPENOCD_TARGET_ARM11_DBGTAP_H #include "arm11.h" /* ARM11 internals */ void arm11_setup_field(struct arm11_common *arm11, int num_bits, void *in_data, void *out_data, struct scan_field *field); void arm11_add_ir(struct arm11_common *arm11, uint8_t instr, tap_state_t state); int arm11_add_debug_scan_n(struct arm11_common *arm11, uint8_t chain, tap_state_t state); int arm11_read_dscr(struct arm11_common *arm11); int arm11_write_dscr(struct arm11_common *arm11, uint32_t dscr); int arm11_run_instr_data_prepare(struct arm11_common *arm11); int arm11_run_instr_data_finish(struct arm11_common *arm11); int arm11_run_instr_no_data1(struct arm11_common *arm11, uint32_t opcode); int arm11_run_instr_data_to_core(struct arm11_common *arm11, uint32_t opcode, uint32_t *data, size_t count); int arm11_run_instr_data_to_core_noack(struct arm11_common *arm11, uint32_t opcode, uint32_t *data, size_t count); int arm11_run_instr_data_to_core1(struct arm11_common *arm11, uint32_t opcode, uint32_t data); int arm11_run_instr_data_from_core(struct arm11_common *arm11, uint32_t opcode, uint32_t *data, size_t count); int arm11_run_instr_data_from_core_via_r0(struct arm11_common *arm11, uint32_t opcode, uint32_t *data); int arm11_run_instr_data_to_core_via_r0(struct arm11_common *arm11, uint32_t opcode, uint32_t data); void arm11_add_dr_scan_vc(struct jtag_tap *tap, int num_fields, struct scan_field *fields, tap_state_t state); /** * Used with arm11_sc7_run to make a list of read/write commands for * scan chain 7 */ struct arm11_sc7_action { bool write; /**< Access mode: true for write, false for read. */ uint8_t address;/**< Register address mode. Use enum #arm11_sc7 */ /** * If write then set this to value to be written. In read mode * this receives the read value when the function returns. */ uint32_t value; }; int arm11_sc7_run(struct arm11_common *arm11, struct arm11_sc7_action *actions, size_t count); /* Mid-level helper functions */ int arm11_sc7_clear_vbw(struct arm11_common *arm11); int arm11_sc7_set_vcr(struct arm11_common *arm11, uint32_t value); int arm11_read_memory_word(struct arm11_common *arm11, uint32_t address, uint32_t *result); int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr); void arm11_dpm_deinit(struct arm11_common *arm11); int arm11_bpwp_flush(struct arm11_common *arm11); #endif /* OPENOCD_TARGET_ARM11_DBGTAP_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm720t.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2009 by Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm720t.h" #include <helper/time_support.h> #include "target_type.h" #include "register.h" #include "arm_opcodes.h" /* * ARM720 is an ARM7TDMI-S with MMU and ETM7. For information, see * ARM DDI 0229C especially Chapter 9 about debug support. */ #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif static int arm720t_scan_cp15(struct target *target, uint32_t out, uint32_t *in, int instruction, int clock_arg) { int retval; struct arm720t_common *arm720t = target_to_arm720(target); struct arm_jtag *jtag_info; struct scan_field fields[2]; uint8_t out_buf[4]; uint8_t instruction_buf = instruction; jtag_info = &arm720t->arm7_9_common.jtag_info; buf_set_u32(out_buf, 0, 32, flip_u32(out, 32)); retval = arm_jtag_scann(jtag_info, 0xf, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 1; fields[0].out_value = &instruction_buf; fields[0].in_value = NULL; fields[1].num_bits = 32; fields[1].out_value = out_buf; fields[1].in_value = NULL; if (in) { fields[1].in_value = (uint8_t *)in; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE); jtag_add_callback(arm7flip32, (jtag_callback_data_t)in); } else jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE); if (clock_arg) jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (in) LOG_DEBUG("out: %8.8x, in: %8.8x, instruction: %i, clock: %i", out, *in, instruction, clock); else LOG_DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock_arg); #else LOG_DEBUG("out: %8.8" PRIx32 ", instruction: %i, clock: %i", out, instruction, clock_arg); #endif return ERROR_OK; } static int arm720t_read_cp15(struct target *target, uint32_t opcode, uint32_t *value) { /* fetch CP15 opcode */ arm720t_scan_cp15(target, opcode, NULL, 1, 1); /* "DECODE" stage */ arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); /* "EXECUTE" stage (1) */ arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0); arm720t_scan_cp15(target, 0x0, NULL, 0, 1); /* "EXECUTE" stage (2) */ arm720t_scan_cp15(target, 0x0, NULL, 0, 1); /* "EXECUTE" stage (3), CDATA is read */ arm720t_scan_cp15(target, ARMV4_5_NOP, value, 1, 1); return ERROR_OK; } static int arm720t_write_cp15(struct target *target, uint32_t opcode, uint32_t value) { /* fetch CP15 opcode */ arm720t_scan_cp15(target, opcode, NULL, 1, 1); /* "DECODE" stage */ arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); /* "EXECUTE" stage (1) */ arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0); arm720t_scan_cp15(target, 0x0, NULL, 0, 1); /* "EXECUTE" stage (2) */ arm720t_scan_cp15(target, value, NULL, 0, 1); arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); return ERROR_OK; } static int arm720t_get_ttb(struct target *target, uint32_t *result) { uint32_t ttb = 0x0; int retval; retval = arm720t_read_cp15(target, 0xee120f10, &ttb); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; ttb &= 0xffffc000; *result = ttb; return ERROR_OK; } static int arm720t_disable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { uint32_t cp15_control; int retval; /* read cp15 control register */ retval = arm720t_read_cp15(target, 0xee110f10, &cp15_control); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (mmu) cp15_control &= ~0x1U; if (d_u_cache || i_cache) cp15_control &= ~0x4U; retval = arm720t_write_cp15(target, 0xee010f10, cp15_control); return retval; } static int arm720t_enable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { uint32_t cp15_control; int retval; /* read cp15 control register */ retval = arm720t_read_cp15(target, 0xee110f10, &cp15_control); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (mmu) cp15_control |= 0x1U; if (d_u_cache || i_cache) cp15_control |= 0x4U; retval = arm720t_write_cp15(target, 0xee010f10, cp15_control); return retval; } static int arm720t_post_debug_entry(struct target *target) { struct arm720t_common *arm720t = target_to_arm720(target); int retval; /* examine cp15 control reg */ retval = arm720t_read_cp15(target, 0xee110f10, &arm720t->cp15_control_reg); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; LOG_DEBUG("cp15_control_reg: %8.8" PRIx32 "", arm720t->cp15_control_reg); arm720t->armv4_5_mmu.mmu_enabled = (arm720t->cp15_control_reg & 0x1U) ? 1 : 0; arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm720t->cp15_control_reg & 0x4U) ? 1 : 0; arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; /* save i/d fault status and address register */ retval = arm720t_read_cp15(target, 0xee150f10, &arm720t->fsr_reg); if (retval != ERROR_OK) return retval; retval = arm720t_read_cp15(target, 0xee160f10, &arm720t->far_reg); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); return retval; } static void arm720t_pre_restore_context(struct target *target) { struct arm720t_common *arm720t = target_to_arm720(target); /* restore i/d fault status and address register */ arm720t_write_cp15(target, 0xee050f10, arm720t->fsr_reg); arm720t_write_cp15(target, 0xee060f10, arm720t->far_reg); } static int arm720t_arch_state(struct target *target) { struct arm720t_common *arm720t = target_to_arm720(target); static const char *state[] = { "disabled", "enabled" }; arm_arch_state(target); LOG_USER("MMU: %s, Cache: %s", state[arm720t->armv4_5_mmu.mmu_enabled], state[arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled]); return ERROR_OK; } static int arm720_mmu(struct target *target, int *enabled) { if (target->state != TARGET_HALTED) { LOG_ERROR("%s: target not halted", __func__); return ERROR_TARGET_INVALID; } *enabled = target_to_arm720(target)->armv4_5_mmu.mmu_enabled; return ERROR_OK; } static int arm720_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical) { uint32_t cb; struct arm720t_common *arm720t = target_to_arm720(target); uint32_t ret; int retval = armv4_5_mmu_translate_va(target, &arm720t->armv4_5_mmu, virtual, &cb, &ret); if (retval != ERROR_OK) return retval; *physical = ret; return ERROR_OK; } static int arm720t_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; struct arm720t_common *arm720t = target_to_arm720(target); /* disable cache, but leave MMU enabled */ if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) { retval = arm720t_disable_mmu_caches(target, 0, 1, 0); if (retval != ERROR_OK) return retval; } retval = arm7_9_read_memory(target, address, size, count, buffer); if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) { retval = arm720t_enable_mmu_caches(target, 0, 1, 0); if (retval != ERROR_OK) return retval; } return retval; } static int arm720t_read_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct arm720t_common *arm720t = target_to_arm720(target); return armv4_5_mmu_read_physical(target, &arm720t->armv4_5_mmu, address, size, count, buffer); } static int arm720t_write_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct arm720t_common *arm720t = target_to_arm720(target); return armv4_5_mmu_write_physical(target, &arm720t->armv4_5_mmu, address, size, count, buffer); } static int arm720t_soft_reset_halt(struct target *target) { int retval = ERROR_OK; struct arm720t_common *arm720t = target_to_arm720(target); struct reg *dbg_stat = &arm720t->arm7_9_common .eice_cache->reg_list[EICE_DBG_STAT]; struct arm *arm = &arm720t->arm7_9_common.arm; retval = target_halt(target); if (retval != ERROR_OK) return retval; int64_t then = timeval_ms(); int timeout; while (!(timeout = ((timeval_ms()-then) > 1000))) { if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) { embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; } else break; if (debug_level >= 3) alive_sleep(100); else keep_alive(); } if (timeout) { LOG_ERROR("Failed to halt CPU after 1 sec"); return ERROR_TARGET_TIMEOUT; } target->state = TARGET_HALTED; /* SVC, ARM state, IRQ and FIQ disabled */ uint32_t cpsr; cpsr = buf_get_u32(arm->cpsr->value, 0, 32); cpsr &= ~0xff; cpsr |= 0xd3; arm_set_cpsr(arm, cpsr); arm->cpsr->dirty = true; /* start fetching from 0x0 */ buf_set_u32(arm->pc->value, 0, 32, 0x0); arm->pc->dirty = true; arm->pc->valid = true; retval = arm720t_disable_mmu_caches(target, 1, 1, 1); if (retval != ERROR_OK) return retval; arm720t->armv4_5_mmu.mmu_enabled = 0; arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; retval = target_call_event_callbacks(target, TARGET_EVENT_HALTED); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int arm720t_init_target(struct command_context *cmd_ctx, struct target *target) { return arm7tdmi_init_target(cmd_ctx, target); } static void arm720t_deinit_target(struct target *target) { arm7tdmi_deinit_target(target); } /* FIXME remove forward decls */ static int arm720t_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value); static int arm720t_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value); static int arm720t_init_arch_info(struct target *target, struct arm720t_common *arm720t, struct jtag_tap *tap) { struct arm7_9_common *arm7_9 = &arm720t->arm7_9_common; arm7_9->arm.mrc = arm720t_mrc; arm7_9->arm.mcr = arm720t_mcr; arm7tdmi_init_arch_info(target, arm7_9, tap); arm720t->common_magic = ARM720T_COMMON_MAGIC; arm7_9->post_debug_entry = arm720t_post_debug_entry; arm7_9->pre_restore_context = arm720t_pre_restore_context; arm720t->armv4_5_mmu.armv4_5_cache.ctype = -1; arm720t->armv4_5_mmu.get_ttb = arm720t_get_ttb; arm720t->armv4_5_mmu.read_memory = arm7_9_read_memory; arm720t->armv4_5_mmu.write_memory = arm7_9_write_memory; arm720t->armv4_5_mmu.disable_mmu_caches = arm720t_disable_mmu_caches; arm720t->armv4_5_mmu.enable_mmu_caches = arm720t_enable_mmu_caches; arm720t->armv4_5_mmu.has_tiny_pages = 0; arm720t->armv4_5_mmu.mmu_enabled = 0; return ERROR_OK; } static int arm720t_target_create(struct target *target, Jim_Interp *interp) { struct arm720t_common *arm720t = calloc(1, sizeof(*arm720t)); arm720t->arm7_9_common.arm.arch = ARM_ARCH_V4; return arm720t_init_arch_info(target, arm720t, target->tap); } static int arm720t_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } /* read "to" r0 */ return arm720t_read_cp15(target, ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2), value); } static int arm720t_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } /* write "from" r0 */ return arm720t_write_cp15(target, ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2), value); } static const struct command_registration arm720t_command_handlers[] = { { .chain = arm7_9_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Holds methods for ARM720 targets. */ struct target_type arm720t_target = { .name = "arm720t", .poll = arm7_9_poll, .arch_state = arm720t_arch_state, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm720t_soft_reset_halt, .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm720t_read_memory, .write_memory = arm7_9_write_memory_opt, .read_phys_memory = arm720t_read_phys_memory, .write_phys_memory = arm720t_write_phys_memory, .mmu = arm720_mmu, .virt2phys = arm720_virt2phys, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm720t_command_handlers, .target_create = arm720t_target_create, .init_target = arm720t_init_target, .deinit_target = arm720t_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm720t.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM720T_H #define OPENOCD_TARGET_ARM720T_H #include "arm7tdmi.h" #include "armv4_5_mmu.h" #define ARM720T_COMMON_MAGIC 0xa720a720U struct arm720t_common { unsigned int common_magic; struct arm7_9_common arm7_9_common; struct armv4_5_mmu_common armv4_5_mmu; uint32_t cp15_control_reg; uint32_t fsr_reg; uint32_t far_reg; }; static inline struct arm720t_common *target_to_arm720(struct target *target) { return container_of(target->arch_info, struct arm720t_common, arm7_9_common.arm); } #endif /* OPENOCD_TARGET_ARM720T_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm7_9_common.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by Hongtao Zheng * * hontor@126.com * * * * Copyright (C) 2009 by David Brownell * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "breakpoints.h" #include "embeddedice.h" #include "target_request.h" #include "etm.h" #include <helper/time_support.h> #include "arm_simulator.h" #include "arm_semihosting.h" #include "algorithm.h" #include "register.h" #include "armv4_5.h" /** * @file * Hold common code supporting the ARM7 and ARM9 core generations. * * While the ARM core implementations evolved substantially during these * two generations, they look quite similar from the JTAG perspective. * Both have similar debug facilities, based on the same two scan chains * providing access to the core and to an EmbeddedICE module. Both can * support similar ETM and ETB modules, for tracing. And both expose * what could be viewed as "ARM Classic", with multiple processor modes, * shadowed registers, and support for the Thumb instruction set. * * Processor differences include things like presence or absence of MMU * and cache, pipeline sizes, use of a modified Harvard Architecture * (with separate instruction and data buses from the CPU), support * for cpu clock gating during idle, and more. */ static int arm7_9_debug_entry(struct target *target); /** * Clear watchpoints for an ARM7/9 target. * * @param arm7_9 Pointer to the common struct for an ARM7/9 target * @return JTAG error status after executing queue */ static int arm7_9_clear_watchpoints(struct arm7_9_common *arm7_9) { LOG_DEBUG("-"); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); arm7_9->sw_breakpoint_count = 0; arm7_9->sw_breakpoints_added = 0; arm7_9->wp0_used = 0; arm7_9->wp1_used = arm7_9->wp1_used_default; arm7_9->wp_available = arm7_9->wp_available_max; return jtag_execute_queue(); } /** * Assign a watchpoint to one of the two available hardware comparators in an * ARM7 or ARM9 target. * * @param arm7_9 Pointer to the common struct for an ARM7/9 target * @param breakpoint Pointer to the breakpoint to be used as a watchpoint */ static void arm7_9_assign_wp(struct arm7_9_common *arm7_9, struct breakpoint *breakpoint) { if (!arm7_9->wp0_used) { arm7_9->wp0_used = 1; breakpoint_hw_set(breakpoint, 0); arm7_9->wp_available--; } else if (!arm7_9->wp1_used) { arm7_9->wp1_used = 1; breakpoint_hw_set(breakpoint, 1); arm7_9->wp_available--; } else { LOG_ERROR("BUG: no hardware comparator available"); } LOG_DEBUG("BPID: %" PRIu32 " (0x%08" TARGET_PRIxADDR ") using hw wp: %u", breakpoint->unique_id, breakpoint->address, breakpoint->number); } /** * Setup an ARM7/9 target's embedded ICE registers for software breakpoints. * * @param arm7_9 Pointer to common struct for ARM7/9 targets * @return Error codes if there is a problem finding a watchpoint or the result * of executing the JTAG queue */ static int arm7_9_set_software_breakpoints(struct arm7_9_common *arm7_9) { if (arm7_9->sw_breakpoints_added) return ERROR_OK; if (arm7_9->wp_available < 1) { LOG_WARNING("can't enable sw breakpoints with no watchpoint unit available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } arm7_9->wp_available--; /* pick a breakpoint unit */ if (!arm7_9->wp0_used) { arm7_9->sw_breakpoints_added = 1; arm7_9->wp0_used = 3; } else if (!arm7_9->wp1_used) { arm7_9->sw_breakpoints_added = 2; arm7_9->wp1_used = 3; } else { LOG_ERROR("BUG: both watchpoints used, but wp_available >= 1"); return ERROR_FAIL; } if (arm7_9->sw_breakpoints_added == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_VALUE], arm7_9->arm_bkpt); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0x0); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0xffffffffu); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); } else if (arm7_9->sw_breakpoints_added == 2) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_VALUE], arm7_9->arm_bkpt); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], 0x0); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], 0xffffffffu); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], EICE_W_CTRL_ENABLE); } else { LOG_ERROR("BUG: both watchpoints used, but wp_available >= 1"); return ERROR_FAIL; } LOG_DEBUG("SW BP using hw wp: %d", arm7_9->sw_breakpoints_added); return jtag_execute_queue(); } /** * Setup the common pieces for an ARM7/9 target after reset or on startup. * * @param target Pointer to an ARM7/9 target to setup * @return Result of clearing the watchpoints on the target */ static int arm7_9_setup(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); return arm7_9_clear_watchpoints(arm7_9); } /** * Set either a hardware or software breakpoint on an ARM7/9 target. The * breakpoint is set up even if it is already set. Some actions, e.g. reset, * might have erased the values in Embedded ICE. * * @param target Pointer to the target device to set the breakpoints on * @param breakpoint Pointer to the breakpoint to be set * @return For hardware breakpoints, this is the result of executing the JTAG * queue. For software breakpoints, this will be the status of the * required memory reads and writes */ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); int retval = ERROR_OK; LOG_DEBUG("BPID: %" PRIu32 ", Address: 0x%08" TARGET_PRIxADDR ", Type: %d", breakpoint->unique_id, breakpoint->address, breakpoint->type); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (breakpoint->type == BKPT_HARD) { /* either an ARM (4 byte) or Thumb (2 byte) breakpoint */ uint32_t mask = (breakpoint->length == 4) ? 0x3u : 0x1u; /* reassign a hw breakpoint */ if (!breakpoint->is_set) arm7_9_assign_wp(arm7_9, breakpoint); if (breakpoint->number == 0) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE], breakpoint->address); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffffu); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); } else if (breakpoint->number == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], breakpoint->address); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], 0xffffffffu); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], EICE_W_CTRL_ENABLE); } else { LOG_ERROR("BUG: no hardware comparator available"); return ERROR_OK; } retval = jtag_execute_queue(); } else if (breakpoint->type == BKPT_SOFT) { /* did we already set this breakpoint? */ if (breakpoint->is_set) return ERROR_OK; if (breakpoint->length == 4) { uint32_t verify = 0xffffffff; /* keep the original instruction in target endianness */ retval = target_read_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; /* write the breakpoint instruction in target * endianness (arm7_9->arm_bkpt is host endian) */ retval = target_write_u32(target, breakpoint->address, arm7_9->arm_bkpt); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, breakpoint->address, &verify); if (retval != ERROR_OK) return retval; if (verify != arm7_9->arm_bkpt) { LOG_ERROR("Unable to set 32 bit software breakpoint at address %08" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } } else { uint16_t verify = 0xffff; /* keep the original instruction in target endianness */ retval = target_read_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; /* write the breakpoint instruction in target * endianness (arm7_9->thumb_bkpt is host endian) */ retval = target_write_u16(target, breakpoint->address, arm7_9->thumb_bkpt); if (retval != ERROR_OK) return retval; retval = target_read_u16(target, breakpoint->address, &verify); if (retval != ERROR_OK) return retval; if (verify != arm7_9->thumb_bkpt) { LOG_ERROR("Unable to set thumb software breakpoint at address %08" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } } retval = arm7_9_set_software_breakpoints(arm7_9); if (retval != ERROR_OK) return retval; arm7_9->sw_breakpoint_count++; breakpoint->is_set = true; } return retval; } /** * Unsets an existing breakpoint on an ARM7/9 target. If it is a hardware * breakpoint, the watchpoint used will be freed and the Embedded ICE registers * will be updated. Otherwise, the software breakpoint will be restored to its * original instruction if it hasn't already been modified. * * @param target Pointer to ARM7/9 target to unset the breakpoint from * @param breakpoint Pointer to breakpoint to be unset * @return For hardware breakpoints, this is the result of executing the JTAG * queue. For software breakpoints, this will be the status of the * required memory reads and writes */ static int arm7_9_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); LOG_DEBUG("BPID: %" PRIu32 ", Address: 0x%08" TARGET_PRIxADDR, breakpoint->unique_id, breakpoint->address); if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { LOG_DEBUG("BPID: %" PRIu32 " Releasing hw wp: %d", breakpoint->unique_id, breakpoint->is_set); if (breakpoint->number == 0) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0); arm7_9->wp0_used = 0; arm7_9->wp_available++; } else if (breakpoint->number == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); arm7_9->wp1_used = 0; arm7_9->wp_available++; } retval = jtag_execute_queue(); breakpoint->is_set = false; } else { /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { uint32_t current_instr; /* check that user program as not modified breakpoint instruction */ retval = target_read_memory(target, breakpoint->address, 4, 1, (uint8_t *)¤t_instr); if (retval != ERROR_OK) return retval; current_instr = target_buffer_get_u32(target, (uint8_t *)¤t_instr); if (current_instr == arm7_9->arm_bkpt) { retval = target_write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } } else { uint16_t current_instr; /* check that user program as not modified breakpoint instruction */ retval = target_read_memory(target, breakpoint->address, 2, 1, (uint8_t *)¤t_instr); if (retval != ERROR_OK) return retval; current_instr = target_buffer_get_u16(target, (uint8_t *)¤t_instr); if (current_instr == arm7_9->thumb_bkpt) { retval = target_write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } } if (--arm7_9->sw_breakpoint_count == 0) { /* We have removed the last sw breakpoint, clear the hw breakpoint we used *to implement it */ if (arm7_9->sw_breakpoints_added == 1) embeddedice_set_reg(&arm7_9->eice_cache->reg_list[ EICE_W0_CONTROL_VALUE], 0); else if (arm7_9->sw_breakpoints_added == 2) embeddedice_set_reg(&arm7_9->eice_cache->reg_list[ EICE_W1_CONTROL_VALUE], 0); } breakpoint->is_set = false; } return retval; } /** * Add a breakpoint to an ARM7/9 target. This makes sure that there are no * dangling breakpoints and that the desired breakpoint can be added. * * @param target Pointer to the target ARM7/9 device to add a breakpoint to * @param breakpoint Pointer to the breakpoint to be added * @return An error status if there is a problem adding the breakpoint or the * result of setting the breakpoint */ int arm7_9_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (arm7_9->breakpoint_count == 0) { /* make sure we don't have any dangling breakpoints. This is vital upon * GDB connect/disconnect */ arm7_9_clear_watchpoints(arm7_9); } if ((breakpoint->type == BKPT_HARD) && (arm7_9->wp_available < 1)) { LOG_INFO("no watchpoint unit available for hardware breakpoint"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if ((breakpoint->length != 2) && (breakpoint->length != 4)) { LOG_INFO("only breakpoints of two (Thumb) or four (ARM) bytes length supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_HARD) arm7_9_assign_wp(arm7_9, breakpoint); arm7_9->breakpoint_count++; return arm7_9_set_breakpoint(target, breakpoint); } /** * Removes a breakpoint from an ARM7/9 target. This will make sure there are no * dangling breakpoints and updates available watchpoints if it is a hardware * breakpoint. * * @param target Pointer to the target to have a breakpoint removed * @param breakpoint Pointer to the breakpoint to be removed * @return Error status if there was a problem unsetting the breakpoint or the * watchpoints could not be cleared */ int arm7_9_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); retval = arm7_9_unset_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; if (breakpoint->type == BKPT_HARD) arm7_9->wp_available++; arm7_9->breakpoint_count--; if (arm7_9->breakpoint_count == 0) { /* make sure we don't have any dangling breakpoints */ retval = arm7_9_clear_watchpoints(arm7_9); if (retval != ERROR_OK) return retval; } return ERROR_OK; } /** * Sets a watchpoint for an ARM7/9 target in one of the watchpoint units. It is * considered a bug to call this function when there are no available watchpoint * units. * * @param target Pointer to an ARM7/9 target to set a watchpoint on * @param watchpoint Pointer to the watchpoint to be set * @return Error status if watchpoint set fails or the result of executing the * JTAG queue */ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); int rw_mask = 1; uint32_t mask; mask = watchpoint->length - 1; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (watchpoint->rw == WPT_ACCESS) rw_mask = 0; else rw_mask = 1; if (!arm7_9->wp0_used) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE], watchpoint->address); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], watchpoint->mask); if (watchpoint->mask != 0xffffffffu) embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_VALUE], watchpoint->value); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], 0xff & ~EICE_W_CTRL_NOPC & ~rw_mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE | EICE_W_CTRL_NOPC | (watchpoint->rw & 1)); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; watchpoint_set(watchpoint, 1); arm7_9->wp0_used = 2; } else if (!arm7_9->wp1_used) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], watchpoint->address); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], watchpoint->mask); if (watchpoint->mask != 0xffffffffu) embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_VALUE], watchpoint->value); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], 0xff & ~EICE_W_CTRL_NOPC & ~rw_mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], EICE_W_CTRL_ENABLE | EICE_W_CTRL_NOPC | (watchpoint->rw & 1)); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; watchpoint_set(watchpoint, 2); arm7_9->wp1_used = 2; } else { LOG_ERROR("BUG: no hardware comparator available"); return ERROR_OK; } return ERROR_OK; } /** * Unset an existing watchpoint and clear the used watchpoint unit. * * @param target Pointer to the target to have the watchpoint removed * @param watchpoint Pointer to the watchpoint to be removed * @return Error status while trying to unset the watchpoint or the result of * executing the JTAG queue */ static int arm7_9_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!watchpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (watchpoint->number == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; arm7_9->wp0_used = 0; } else if (watchpoint->number == 2) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; arm7_9->wp1_used = 0; } watchpoint->is_set = false; return ERROR_OK; } /** * Add a watchpoint to an ARM7/9 target. If there are no watchpoint units * available, an error response is returned. * * @param target Pointer to the ARM7/9 target to add a watchpoint to * @param watchpoint Pointer to the watchpoint to be added * @return Error status while trying to add the watchpoint */ int arm7_9_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (arm7_9->wp_available < 1) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if ((watchpoint->length != 1) && (watchpoint->length != 2) && (watchpoint->length != 4)) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; arm7_9->wp_available--; return ERROR_OK; } /** * Remove a watchpoint from an ARM7/9 target. The watchpoint will be unset and * the used watchpoint unit will be reopened. * * @param target Pointer to the target to remove a watchpoint from * @param watchpoint Pointer to the watchpoint to be removed * @return Result of trying to unset the watchpoint */ int arm7_9_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (watchpoint->is_set) { retval = arm7_9_unset_watchpoint(target, watchpoint); if (retval != ERROR_OK) return retval; } arm7_9->wp_available++; return ERROR_OK; } /** * Restarts the target by sending a RESTART instruction and moving the JTAG * state to IDLE. This includes a timeout waiting for DBGACK and SYSCOMP to be * asserted by the processor. * * @param target Pointer to target to issue commands to * @return Error status if there is a timeout or a problem while executing the * JTAG queue */ int arm7_9_execute_sys_speed(struct target *target) { int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; /* set RESTART instruction */ if (arm7_9->need_bypass_before_restart) { arm7_9->need_bypass_before_restart = 0; retval = arm_jtag_set_instr(jtag_info->tap, 0xf, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; } retval = arm_jtag_set_instr(jtag_info->tap, 0x4, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; int64_t then = timeval_ms(); bool timeout; while (!(timeout = ((timeval_ms()-then) > 1000))) { /* read debug status register */ embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if ((buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1)) && (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_SYSCOMP, 1))) break; if (debug_level >= 3) alive_sleep(100); else keep_alive(); } if (timeout) { LOG_ERROR("timeout waiting for SYSCOMP & DBGACK, last DBG_STATUS: %" PRIx32 "", buf_get_u32(dbg_stat->value, 0, dbg_stat->size)); return ERROR_TARGET_TIMEOUT; } return ERROR_OK; } /** * Restarts the target by sending a RESTART instruction and moving the JTAG * state to IDLE. This validates that DBGACK and SYSCOMP are set without * waiting until they are. * * @param target Pointer to the target to issue commands to * @return Always ERROR_OK */ static int arm7_9_execute_fast_sys_speed(struct target *target) { static int set; static uint8_t check_value[4], check_mask[4]; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; int retval; /* set RESTART instruction */ if (arm7_9->need_bypass_before_restart) { arm7_9->need_bypass_before_restart = 0; retval = arm_jtag_set_instr(jtag_info->tap, 0xf, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; } retval = arm_jtag_set_instr(jtag_info->tap, 0x4, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; if (!set) { /* check for DBGACK and SYSCOMP set (others don't care) */ /* NB! These are constants that must be available until after next jtag_execute() and * we evaluate the values upon first execution in lieu of setting up these constants * during early setup. * */ buf_set_u32(check_value, 0, 32, 0x9); buf_set_u32(check_mask, 0, 32, 0x9); set = 1; } /* read debug status register */ embeddedice_read_reg_w_check(dbg_stat, check_value, check_mask); return ERROR_OK; } /** * Get some data from the ARM7/9 target. * * @param target Pointer to the ARM7/9 target to read data from * @param size The number of 32bit words to be read * @param buffer Pointer to the buffer that will hold the data * @return The result of receiving data from the Embedded ICE unit */ int arm7_9_target_request_data(struct target *target, uint32_t size, uint8_t *buffer) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; uint32_t *data; int retval = ERROR_OK; uint32_t i; data = malloc(size * (sizeof(uint32_t))); retval = embeddedice_receive(jtag_info, data, size); /* return the 32-bit ints in the 8-bit array */ for (i = 0; i < size; i++) h_u32_to_le(buffer + (i * 4), data[i]); free(data); return retval; } /** * Handles requests to an ARM7/9 target. If debug messaging is enabled, the * target is running and the DCC control register has the W bit high, this will * execute the request on the target. * * @param priv Void pointer expected to be a struct target pointer * @return ERROR_OK unless there are issues with the JTAG queue or when reading * from the Embedded ICE unit */ static int arm7_9_handle_target_request(void *priv) { int retval = ERROR_OK; struct target *target = priv; if (!target_was_examined(target)) return ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct reg *dcc_control = &arm7_9->eice_cache->reg_list[EICE_COMMS_CTRL]; if (!target->dbg_msg_enabled) return ERROR_OK; if (target->state == TARGET_RUNNING) { /* read DCC control register */ embeddedice_read_reg(dcc_control); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* check W bit */ if (buf_get_u32(dcc_control->value, 1, 1) == 1) { uint32_t request; retval = embeddedice_receive(jtag_info, &request, 1); if (retval != ERROR_OK) return retval; retval = target_request(target, request); if (retval != ERROR_OK) return retval; } } return ERROR_OK; } /** * Polls an ARM7/9 target for its current status. If DBGACK is set, the target * is manipulated to the right halted state based on its current state. This is * what happens: * * <table> * <tr><th > State</th><th > Action</th></tr> * <tr><td > TARGET_RUNNING | TARGET_RESET</td> * <td > Enters debug mode. If TARGET_RESET, pc may be checked</td></tr> * <tr><td > TARGET_UNKNOWN</td><td > Warning is logged</td></tr> * <tr><td > TARGET_DEBUG_RUNNING</td><td > Enters debug mode</td></tr> * <tr><td > TARGET_HALTED</td><td > Nothing</td></tr> * </table> * * If the target does not end up in the halted state, a warning is produced. If * DBGACK is cleared, then the target is expected to either be running or * running in debug. * * @param target Pointer to the ARM7/9 target to poll * @return ERROR_OK or an error status if a command fails */ int arm7_9_poll(struct target *target) { int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; /* read debug status register */ embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1)) { /* LOG_DEBUG("DBGACK set, dbg_state->value: 0x%x", buf_get_u32(dbg_stat->value, 0, *32));*/ if (target->state == TARGET_UNKNOWN) { /* Starting OpenOCD with target in debug-halt */ target->state = TARGET_RUNNING; LOG_DEBUG("DBGACK already set during server startup."); } if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { target->state = TARGET_HALTED; retval = arm7_9_debug_entry(target); if (retval != ERROR_OK) return retval; if (arm_semihosting(target, &retval) != 0) return retval; retval = target_call_event_callbacks(target, TARGET_EVENT_HALTED); if (retval != ERROR_OK) return retval; } if (target->state == TARGET_DEBUG_RUNNING) { target->state = TARGET_HALTED; retval = arm7_9_debug_entry(target); if (retval != ERROR_OK) return retval; retval = target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); if (retval != ERROR_OK) return retval; } if (target->state != TARGET_HALTED) LOG_WARNING( "DBGACK set, but the target did not end up in the halted state %d", target->state); } else { if (target->state != TARGET_DEBUG_RUNNING) target->state = TARGET_RUNNING; } return ERROR_OK; } /** * Asserts the reset (SRST) on an ARM7/9 target. Some -S targets (ARM966E-S in * the STR912 isn't affected, ARM926EJ-S in the LPC3180 and AT91SAM9260 is * affected) completely stop the JTAG clock while the core is held in reset * (SRST). It isn't possible to program the halt condition once reset is * asserted, hence a hook that allows the target to set up its reset-halt * condition is setup prior to asserting reset. * * @param target Pointer to an ARM7/9 target to assert reset on * @return ERROR_FAIL if the JTAG device does not have SRST, otherwise ERROR_OK */ int arm7_9_assert_reset(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); enum reset_types jtag_reset_config = jtag_get_reset_config(); bool use_event = false; /* TODO: apply hw reset signal in not examined state */ if (!(target_was_examined(target))) { LOG_WARNING("Reset is not asserted because the target is not examined."); LOG_WARNING("Use a reset button or power cycle the target."); return ERROR_TARGET_NOT_EXAMINED; } LOG_DEBUG("target->state: %s", target_state_name(target)); if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) use_event = true; else if (!(jtag_reset_config & RESET_HAS_SRST)) { LOG_ERROR("%s: how to reset?", target_name(target)); return ERROR_FAIL; } /* At this point trst has been asserted/deasserted once. We would * like to program EmbeddedICE while SRST is asserted, instead of * depending on SRST to leave that module alone. However, many CPUs * gate the JTAG clock while SRST is asserted; or JTAG may need * clock stability guarantees (adaptive clocking might help). * * So we assume JTAG access during SRST is off the menu unless it's * been specifically enabled. */ bool srst_asserted = false; if (!use_event && !(jtag_reset_config & RESET_SRST_PULLS_TRST) && (jtag_reset_config & RESET_SRST_NO_GATING)) { jtag_add_reset(0, 1); srst_asserted = true; } if (target->reset_halt) { /* * For targets that don't support communication while SRST is * asserted, we need to set up the reset vector catch first. * * When we use TRST+SRST and that's equivalent to a power-up * reset, these settings may well be reset anyway; so setting * them here won't matter. */ if (arm7_9->has_vector_catch) { /* program vector catch register to catch reset */ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_VEC_CATCH], 0x1); /* extra runtest added as issues were found with * certain ARM9 cores (maybe more) - AT91SAM9260 * and STR9 */ jtag_add_runtest(1, TAP_IDLE); } else { /* program watchpoint unit to match on reset vector * address */ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE], 0x0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0x3); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); } } if (use_event) target_handle_event(target, TARGET_EVENT_RESET_ASSERT); else { /* If we use SRST ... we'd like to issue just SRST, but the * board or chip may be set up so we have to assert TRST as * well. On some chips that combination is equivalent to a * power-up reset, and generally clobbers EICE state. */ if (jtag_reset_config & RESET_SRST_PULLS_TRST) jtag_add_reset(1, 1); else if (!srst_asserted) jtag_add_reset(0, 1); jtag_add_sleep(50000); } target->state = TARGET_RESET; register_cache_invalidate(arm7_9->arm.core_cache); /* REVISIT why isn't standard debug entry logic sufficient?? */ if (target->reset_halt && (!(jtag_reset_config & RESET_SRST_PULLS_TRST) || use_event)) { /* debug entry was prepared above */ target->debug_reason = DBG_REASON_DBGRQ; } return ERROR_OK; } /** * Deassert the reset (SRST) signal on an ARM7/9 target. If SRST pulls TRST * and the target is being reset into a halt, a warning will be triggered * because it is not possible to reset into a halted mode in this case. The * target is halted using the target's functions. * * @param target Pointer to the target to have the reset deasserted * @return ERROR_OK or an error from polling or halting the target */ int arm7_9_deassert_reset(struct target *target) { int retval = ERROR_OK; LOG_DEBUG("target->state: %s", target_state_name(target)); /* deassert reset lines */ jtag_add_reset(0, 0); /* In case polling is disabled, we need to examine the * target and poll here for this target to work correctly. * * Otherwise, e.g. halt will fail afterwards with bogus * error messages as halt will believe that reset is * still in effect. */ retval = target_examine_one(target); if (retval != ERROR_OK) return retval; retval = target_poll(target); if (retval != ERROR_OK) return retval; enum reset_types jtag_reset_config = jtag_get_reset_config(); if (target->reset_halt && (jtag_reset_config & RESET_SRST_PULLS_TRST) != 0) { LOG_WARNING( "srst pulls trst - can not reset into halted mode. Issuing halt after reset."); retval = target_halt(target); if (retval != ERROR_OK) return retval; } return retval; } /** * Clears the halt condition for an ARM7/9 target. If it isn't coming out of * reset and if DBGRQ is used, it is programmed to be deasserted. If the reset * vector catch was used, it is restored. Otherwise, the control value is * restored and the watchpoint unit is restored if it was in use. * * @param target Pointer to the ARM7/9 target to have halt cleared * @return Always ERROR_OK */ static int arm7_9_clear_halt(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; /* we used DBGRQ only if we didn't come out of reset */ if (!arm7_9->debug_entry_from_reset && arm7_9->use_dbgrq) { /* program EmbeddedICE Debug Control Register to deassert DBGRQ */ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGRQ, 1, 0); embeddedice_store_reg(dbg_ctrl); } else { if (arm7_9->debug_entry_from_reset && arm7_9->has_vector_catch) { /* if we came out of reset, and vector catch is supported, we used * vector catch to enter debug state * restore the register in that case */ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_VEC_CATCH]); } else { /* restore registers if watchpoint unit 0 was in use */ if (arm7_9->wp0_used) { if (arm7_9->debug_entry_from_reset) embeddedice_store_reg(&arm7_9->eice_cache->reg_list[ EICE_W0_ADDR_VALUE]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[ EICE_W0_ADDR_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[ EICE_W0_DATA_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[ EICE_W0_CONTROL_MASK]); } /* control value always has to be restored, as it was either disabled, * or enabled with possibly different bits */ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE]); } } return ERROR_OK; } /** * Issue a software reset and halt to an ARM7/9 target. The target is halted * and then there is a wait until the processor shows the halt. This wait can * timeout and results in an error being returned. The software reset involves * clearing the halt, updating the debug control register, changing to ARM mode, * reset of the program counter, and reset of all of the registers. * * @param target Pointer to the ARM7/9 target to be reset and halted by software * @return Error status if any of the commands fail, otherwise ERROR_OK */ int arm7_9_soft_reset_halt(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; int i; int retval; /* FIX!!! replace some of this code with tcl commands * * halt # the halt command is synchronous * armv4_5 core_state arm * */ retval = target_halt(target); if (retval != ERROR_OK) return retval; long long then = timeval_ms(); int timeout; while (!(timeout = ((timeval_ms()-then) > 1000))) { if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) != 0) break; embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (debug_level >= 3) alive_sleep(100); else keep_alive(); } if (timeout) { LOG_ERROR("Failed to halt CPU after 1 sec"); return ERROR_TARGET_TIMEOUT; } target->state = TARGET_HALTED; /* program EmbeddedICE Debug Control Register to assert DBGACK and INTDIS * ensure that DBGRQ is cleared */ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 1); buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGRQ, 1, 0); buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_INTDIS, 1, 1); embeddedice_store_reg(dbg_ctrl); retval = arm7_9_clear_halt(target); if (retval != ERROR_OK) return retval; /* if the target is in Thumb state, change to ARM state */ if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_ITBIT, 1)) { uint32_t r0_thumb, pc_thumb; LOG_DEBUG("target entered debug from Thumb state, changing to ARM"); /* Entered debug from Thumb mode */ arm->core_state = ARM_STATE_THUMB; arm7_9->change_to_arm(target, &r0_thumb, &pc_thumb); } /* REVISIT likewise for bit 5 -- switch Jazelle-to-ARM */ /* all register content is now invalid */ register_cache_invalidate(arm->core_cache); /* SVC, ARM state, IRQ and FIQ disabled */ uint32_t cpsr; cpsr = buf_get_u32(arm->cpsr->value, 0, 32); cpsr &= ~0xff; cpsr |= 0xd3; arm_set_cpsr(arm, cpsr); arm->cpsr->dirty = true; /* start fetching from 0x0 */ buf_set_u32(arm->pc->value, 0, 32, 0x0); arm->pc->dirty = true; arm->pc->valid = true; /* reset registers */ for (i = 0; i <= 14; i++) { struct reg *r = arm_reg_current(arm, i); buf_set_u32(r->value, 0, 32, 0xffffffff); r->dirty = true; r->valid = true; } retval = target_call_event_callbacks(target, TARGET_EVENT_HALTED); if (retval != ERROR_OK) return retval; return ERROR_OK; } /** * Halt an ARM7/9 target. This is accomplished by either asserting the DBGRQ * line or by programming a watchpoint to trigger on any address. It is * considered a bug to call this function while the target is in the * TARGET_RESET state. * * @param target Pointer to the ARM7/9 target to be halted * @return Always ERROR_OK */ int arm7_9_halt(struct target *target) { if (target->state == TARGET_RESET) { LOG_ERROR( "BUG: arm7/9 does not support halt during reset. This is handled in arm7_9_assert_reset()"); return ERROR_OK; } struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); if (arm7_9->use_dbgrq) { /* program EmbeddedICE Debug Control Register to assert DBGRQ */ if (arm7_9->set_special_dbgrq) arm7_9->set_special_dbgrq(target); else { buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGRQ, 1, 1); embeddedice_store_reg(dbg_ctrl); } } else { /* program watchpoint unit to match on any address */ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); } target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } /** * Handle an ARM7/9 target's entry into debug mode. The halt is cleared on the * ARM. The JTAG queue is then executed and the reason for debug entry is * examined. Once done, the target is verified to be halted and the processor * is forced into ARM mode. The core registers are saved for the current core * mode and the program counter (register 15) is updated as needed. The core * registers and CPSR and SPSR are saved for restoration later. * * @param target Pointer to target that is entering debug mode * @return Error code if anything fails, otherwise ERROR_OK */ static int arm7_9_debug_entry(struct target *target) { int i; uint32_t context[16]; uint32_t *context_p[16]; uint32_t r0_thumb, pc_thumb; uint32_t cpsr, cpsr_mask = 0; int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; #ifdef _DEBUG_ARM7_9_ LOG_DEBUG("-"); #endif /* program EmbeddedICE Debug Control Register to assert DBGACK and INTDIS * ensure that DBGRQ is cleared */ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 1); buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGRQ, 1, 0); buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_INTDIS, 1, 1); embeddedice_store_reg(dbg_ctrl); retval = arm7_9_clear_halt(target); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; retval = arm7_9->examine_debug_reason(target); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* if the target is in Thumb state, change to ARM state */ if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_ITBIT, 1)) { LOG_DEBUG("target entered debug from Thumb state"); /* Entered debug from Thumb mode */ arm->core_state = ARM_STATE_THUMB; cpsr_mask = 1 << 5; arm7_9->change_to_arm(target, &r0_thumb, &pc_thumb); LOG_DEBUG("r0_thumb: 0x%8.8" PRIx32 ", pc_thumb: 0x%8.8" PRIx32, r0_thumb, pc_thumb); } else if (buf_get_u32(dbg_stat->value, 5, 1)) { /* \todo Get some vaguely correct handling of Jazelle, if * anyone ever uses it and full info becomes available. * See ARM9EJS TRM B.7.1 for how to switch J->ARM; and * B.7.3 for the reverse. That'd be the bare minimum... */ LOG_DEBUG("target entered debug from Jazelle state"); arm->core_state = ARM_STATE_JAZELLE; cpsr_mask = 1 << 24; LOG_ERROR("Jazelle debug entry -- BROKEN!"); } else { LOG_DEBUG("target entered debug from ARM state"); /* Entered debug from ARM mode */ arm->core_state = ARM_STATE_ARM; } for (i = 0; i < 16; i++) context_p[i] = &context[i]; /* save core registers (r0 - r15 of current core mode) */ arm7_9->read_core_regs(target, 0xffff, context_p); arm7_9->read_xpsr(target, &cpsr, 0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* Sync our CPSR copy with J or T bits EICE reported, but * which we then erased by putting the core into ARM mode. */ arm_set_cpsr(arm, cpsr | cpsr_mask); if (!is_arm_mode(arm->core_mode)) { target->state = TARGET_UNKNOWN; LOG_ERROR("cpsr contains invalid mode value - communication failure"); return ERROR_TARGET_FAILURE; } LOG_DEBUG("target entered debug state in %s mode", arm_mode_name(arm->core_mode)); if (arm->core_state == ARM_STATE_THUMB) { LOG_DEBUG("thumb state, applying fixups"); context[0] = r0_thumb; context[15] = pc_thumb; } else if (arm->core_state == ARM_STATE_ARM) { /* adjust value stored by STM */ context[15] -= 3 * 4; } if ((target->debug_reason != DBG_REASON_DBGRQ) || (!arm7_9->use_dbgrq)) context[15] -= 3 * ((arm->core_state == ARM_STATE_ARM) ? 4 : 2); else context[15] -= arm7_9->dbgreq_adjust_pc * ((arm->core_state == ARM_STATE_ARM) ? 4 : 2); for (i = 0; i <= 15; i++) { struct reg *r = arm_reg_current(arm, i); LOG_DEBUG("r%i: 0x%8.8" PRIx32 "", i, context[i]); buf_set_u32(r->value, 0, 32, context[i]); /* r0 and r15 (pc) have to be restored later */ r->dirty = (i == 0) || (i == 15); r->valid = true; } LOG_DEBUG("entered debug state at PC 0x%" PRIx32 "", context[15]); /* exceptions other than USR & SYS have a saved program status register */ if (arm->spsr) { uint32_t spsr; arm7_9->read_xpsr(target, &spsr, 1); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; buf_set_u32(arm->spsr->value, 0, 32, spsr); arm->spsr->dirty = false; arm->spsr->valid = true; } retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (arm7_9->post_debug_entry) { retval = arm7_9->post_debug_entry(target); if (retval != ERROR_OK) return retval; } return ERROR_OK; } /** * Validate the full context for an ARM7/9 target in all processor modes. If * there are any invalid registers for the target, they will all be read. This * includes the PSR. * * @param target Pointer to the ARM7/9 target to capture the full context from * @return Error if the target is not halted, has an invalid core mode, or if * the JTAG queue fails to execute */ static int arm7_9_full_context(struct target *target) { int i; int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct { uint32_t value; uint8_t *reg_p; } read_cache[6 * (16 + 1)]; int read_cache_idx = 0; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } /* iterate through processor modes (User, FIQ, IRQ, SVC, ABT, UND) * SYS shares registers with User, so we don't touch SYS */ for (i = 0; i < 6; i++) { uint32_t mask = 0; uint32_t *reg_p[16]; int j; bool valid = true; /* check if there are invalid registers in the current mode */ for (j = 0; j <= 16; j++) { if (!ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j).valid) valid = false; } if (!valid) { uint32_t tmp_cpsr; /* change processor mode (and mask T bit) */ tmp_cpsr = buf_get_u32(arm->cpsr->value, 0, 8) & 0xe0; tmp_cpsr |= armv4_5_number_to_mode(i); tmp_cpsr &= ~0x20; arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0); for (j = 0; j < 15; j++) { if (!ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j).valid) { read_cache[read_cache_idx].reg_p = ARMV4_5_CORE_REG_MODE( arm->core_cache, armv4_5_number_to_mode(i), j).value; reg_p[j] = &read_cache[read_cache_idx].value; read_cache_idx++; mask |= 1 << j; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j).valid = true; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j).dirty = false; } } /* if only the PSR is invalid, mask is all zeroes */ if (mask) arm7_9->read_core_regs(target, mask, reg_p); /* check if the PSR has to be read */ if (!ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), 16).valid) { read_cache[read_cache_idx].reg_p = ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), 16).value; arm7_9->read_xpsr(target, &read_cache[read_cache_idx].value, 1); read_cache_idx++; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), 16).valid = true; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), 16).dirty = false; } } } /* restore processor mode (mask T bit) */ arm7_9->write_xpsr_im8(target, buf_get_u32(arm->cpsr->value, 0, 8) & ~0x20, 0, 0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* * FIXME: regs in cache should be tagged as 'valid' only now, * not before the jtag_execute_queue() */ while (read_cache_idx) { read_cache_idx--; buf_set_u32(read_cache[read_cache_idx].reg_p, 0, 32, read_cache[read_cache_idx].value); } return ERROR_OK; } /** * Restore the processor context on an ARM7/9 target. The full processor * context is analyzed to see if any of the registers are dirty on this end, but * have a valid new value. If this is the case, the processor is changed to the * appropriate mode and the new register values are written out to the * processor. If there happens to be a dirty register with an invalid value, an * error will be logged. * * @param target Pointer to the ARM7/9 target to have its context restored * @return Error status if the target is not halted or the core mode in the * armv4_5 struct is invalid. */ static int arm7_9_restore_context(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *reg; enum arm_mode current_mode = arm->core_mode; int i, j; bool dirty; int mode_change; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (arm7_9->pre_restore_context) arm7_9->pre_restore_context(target); if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } /* iterate through processor modes (User, FIQ, IRQ, SVC, ABT, UND) * SYS shares registers with User, so we don't touch SYS */ for (i = 0; i < 6; i++) { LOG_DEBUG("examining %s mode", arm_mode_name(arm->core_mode)); dirty = false; mode_change = 0; /* check if there are dirty registers in the current mode */ for (j = 0; j <= 16; j++) { reg = &ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j); if (reg->dirty) { if (reg->valid) { dirty = true; LOG_DEBUG("examining dirty reg: %s", reg->name); struct arm_reg *reg_arch_info; reg_arch_info = reg->arch_info; if ((reg_arch_info->mode != ARM_MODE_ANY) && (reg_arch_info->mode != current_mode) && !((reg_arch_info->mode == ARM_MODE_USR) && (arm->core_mode == ARM_MODE_SYS)) && !((reg_arch_info->mode == ARM_MODE_SYS) && (arm->core_mode == ARM_MODE_USR))) { mode_change = 1; LOG_DEBUG("require mode change"); } } else LOG_ERROR("BUG: dirty register '%s', but no valid data", reg->name); } } if (dirty) { uint32_t mask = 0x0; uint32_t regs[16]; if (mode_change) { uint32_t tmp_cpsr; /* change processor mode (mask T bit) */ tmp_cpsr = buf_get_u32(arm->cpsr->value, 0, 8) & 0xe0; tmp_cpsr |= armv4_5_number_to_mode(i); tmp_cpsr &= ~0x20; arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0); current_mode = armv4_5_number_to_mode(i); } for (j = 0; j <= 14; j++) { reg = &ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j); if (reg->dirty) { regs[j] = buf_get_u32(reg->value, 0, 32); mask |= 1 << j; reg->dirty = false; reg->valid = true; LOG_DEBUG("writing register %i mode %s " "with value 0x%8.8" PRIx32, j, arm_mode_name(arm->core_mode), regs[j]); } } if (mask) arm7_9->write_core_regs(target, mask, regs); reg = &ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode( i), 16); struct arm_reg *reg_arch_info; reg_arch_info = reg->arch_info; if ((reg->dirty) && (reg_arch_info->mode != ARM_MODE_ANY)) { LOG_DEBUG("writing SPSR of mode %i with value 0x%8.8" PRIx32 "", i, buf_get_u32(reg->value, 0, 32)); arm7_9->write_xpsr(target, buf_get_u32(reg->value, 0, 32), 1); } } } if (!arm->cpsr->dirty && (arm->core_mode != current_mode)) { /* restore processor mode (mask T bit) */ uint32_t tmp_cpsr; tmp_cpsr = buf_get_u32(arm->cpsr->value, 0, 8) & 0xE0; tmp_cpsr |= armv4_5_number_to_mode(i); tmp_cpsr &= ~0x20; LOG_DEBUG("writing lower 8 bit of cpsr with value 0x%2.2x", (unsigned)(tmp_cpsr)); arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0); } else if (arm->cpsr->dirty) { /* CPSR has been changed, full restore necessary (mask T bit) */ LOG_DEBUG("writing cpsr with value 0x%8.8" PRIx32, buf_get_u32(arm->cpsr->value, 0, 32)); arm7_9->write_xpsr(target, buf_get_u32(arm->cpsr->value, 0, 32) & ~0x20, 0); arm->cpsr->dirty = false; arm->cpsr->valid = true; } /* restore PC */ LOG_DEBUG("writing PC with value 0x%8.8" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); arm7_9->write_pc(target, buf_get_u32(arm->pc->value, 0, 32)); arm->pc->dirty = false; return ERROR_OK; } /** * Restart the core of an ARM7/9 target. A RESTART command is sent to the * instruction register and the JTAG state is set to TAP_IDLE causing a core * restart. * * @param target Pointer to the ARM7/9 target to be restarted * @return Result of executing the JTAG queue */ static int arm7_9_restart_core(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; int retval; /* set RESTART instruction */ if (arm7_9->need_bypass_before_restart) { arm7_9->need_bypass_before_restart = 0; retval = arm_jtag_set_instr(jtag_info->tap, 0xf, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; } retval = arm_jtag_set_instr(jtag_info->tap, 0x4, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(1, TAP_IDLE); return jtag_execute_queue(); } /** * Enable the watchpoints on an ARM7/9 target. The target's watchpoints are * iterated through and are set on the target if they aren't already set. * * @param target Pointer to the ARM7/9 target to enable watchpoints on */ static void arm7_9_enable_watchpoints(struct target *target) { struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { if (!watchpoint->is_set) arm7_9_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } } /** * Enable the breakpoints on an ARM7/9 target. The target's breakpoints are * iterated through and are set on the target. * * @param target Pointer to the ARM7/9 target to enable breakpoints on */ static void arm7_9_enable_breakpoints(struct target *target) { struct breakpoint *breakpoint = target->breakpoints; /* set any pending breakpoints */ while (breakpoint) { arm7_9_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } } int arm7_9_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; int err, retval = ERROR_OK; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) target_free_all_working_areas(target); /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) buf_set_u32(arm->pc->value, 0, 32, address); uint32_t current_pc; current_pc = buf_get_u32(arm->pc->value, 0, 32); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { struct breakpoint *breakpoint; breakpoint = breakpoint_find(target, buf_get_u32(arm->pc->value, 0, 32)); if (breakpoint) { LOG_DEBUG("unset breakpoint at 0x%8.8" TARGET_PRIxADDR " (id: %" PRIu32, breakpoint->address, breakpoint->unique_id); retval = arm7_9_unset_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; /* calculate PC of next instruction */ uint32_t next_pc; retval = arm_simulate_step(target, &next_pc); if (retval != ERROR_OK) { uint32_t current_opcode; target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( "Couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", current_opcode); return retval; } LOG_DEBUG("enable single-step"); arm7_9->enable_single_step(target, next_pc); target->debug_reason = DBG_REASON_SINGLESTEP; retval = arm7_9_restore_context(target); if (retval != ERROR_OK) return retval; if (arm->core_state == ARM_STATE_ARM) arm7_9->branch_resume(target); else if (arm->core_state == ARM_STATE_THUMB) arm7_9->branch_resume_thumb(target); else { LOG_ERROR("unhandled core state"); return ERROR_FAIL; } buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 0); embeddedice_write_reg(dbg_ctrl, buf_get_u32(dbg_ctrl->value, 0, dbg_ctrl->size)); err = arm7_9_execute_sys_speed(target); LOG_DEBUG("disable single-step"); arm7_9->disable_single_step(target); if (err != ERROR_OK) { retval = arm7_9_set_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; target->state = TARGET_UNKNOWN; return err; } retval = arm7_9_debug_entry(target); if (retval != ERROR_OK) return retval; LOG_DEBUG("new PC after step: 0x%8.8" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); LOG_DEBUG("set breakpoint at 0x%8.8" TARGET_PRIxADDR "", breakpoint->address); retval = arm7_9_set_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; } } /* enable any pending breakpoints and watchpoints */ arm7_9_enable_breakpoints(target); arm7_9_enable_watchpoints(target); retval = arm7_9_restore_context(target); if (retval != ERROR_OK) return retval; if (arm->core_state == ARM_STATE_ARM) arm7_9->branch_resume(target); else if (arm->core_state == ARM_STATE_THUMB) arm7_9->branch_resume_thumb(target); else { LOG_ERROR("unhandled core state"); return ERROR_FAIL; } /* deassert DBGACK and INTDIS */ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 0); /* INTDIS only when we really resume, not during debug execution */ if (!debug_execution) buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_INTDIS, 1, 0); embeddedice_write_reg(dbg_ctrl, buf_get_u32(dbg_ctrl->value, 0, dbg_ctrl->size)); retval = arm7_9_restart_core(target); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_NOTHALTED; if (!debug_execution) { /* registers are now invalid */ register_cache_invalidate(arm->core_cache); target->state = TARGET_RUNNING; retval = target_call_event_callbacks(target, TARGET_EVENT_RESUMED); if (retval != ERROR_OK) return retval; } else { target->state = TARGET_DEBUG_RUNNING; retval = target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); if (retval != ERROR_OK) return retval; } LOG_DEBUG("target resumed"); return ERROR_OK; } void arm7_9_enable_eice_step(struct target *target, uint32_t next_pc) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; uint32_t current_pc; current_pc = buf_get_u32(arm->pc->value, 0, 32); if (next_pc != current_pc) { /* setup an inverse breakpoint on the current PC * - comparator 1 matches the current address * - rangeout from comparator 1 is connected to comparator 0 rangein * - comparator 0 matches any address, as long as rangein is low */ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~(EICE_W_CTRL_RANGE | EICE_W_CTRL_NOPC) & 0xff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], current_pc); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], 0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); } else { embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], 0xff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], next_pc); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], 0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], EICE_W_CTRL_ENABLE); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); } } void arm7_9_disable_eice_step(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE]); } int arm7_9_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct breakpoint *breakpoint = NULL; int err, retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) buf_set_u32(arm->pc->value, 0, 32, address); uint32_t current_pc = buf_get_u32(arm->pc->value, 0, 32); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) breakpoint = breakpoint_find(target, current_pc); if (breakpoint) { retval = arm7_9_unset_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; } target->debug_reason = DBG_REASON_SINGLESTEP; /* calculate PC of next instruction */ uint32_t next_pc; retval = arm_simulate_step(target, &next_pc); if (retval != ERROR_OK) { uint32_t current_opcode; target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( "Couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", current_opcode); return retval; } retval = arm7_9_restore_context(target); if (retval != ERROR_OK) return retval; arm7_9->enable_single_step(target, next_pc); if (arm->core_state == ARM_STATE_ARM) arm7_9->branch_resume(target); else if (arm->core_state == ARM_STATE_THUMB) arm7_9->branch_resume_thumb(target); else { LOG_ERROR("unhandled core state"); return ERROR_FAIL; } retval = target_call_event_callbacks(target, TARGET_EVENT_RESUMED); if (retval != ERROR_OK) return retval; err = arm7_9_execute_sys_speed(target); arm7_9->disable_single_step(target); /* registers are now invalid */ register_cache_invalidate(arm->core_cache); if (err != ERROR_OK) target->state = TARGET_UNKNOWN; else { retval = arm7_9_debug_entry(target); if (retval != ERROR_OK) return retval; retval = target_call_event_callbacks(target, TARGET_EVENT_HALTED); if (retval != ERROR_OK) return retval; LOG_DEBUG("target stepped"); } if (breakpoint) { retval = arm7_9_set_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; } return err; } static int arm7_9_read_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode) { uint32_t *reg_p[16]; int retval; struct arm_reg *areg = r->arch_info; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; if (!is_arm_mode(arm->core_mode)) return ERROR_FAIL; if ((num < 0) || (num > 16)) return ERROR_COMMAND_SYNTAX_ERROR; if ((mode != ARM_MODE_ANY) && (mode != arm->core_mode) && (areg->mode != ARM_MODE_ANY)) { uint32_t tmp_cpsr; /* change processor mode (mask T bit) */ tmp_cpsr = buf_get_u32(arm->cpsr->value, 0, 8) & 0xE0; tmp_cpsr |= mode; tmp_cpsr &= ~0x20; arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0); } uint32_t value = 0; if ((num >= 0) && (num <= 15)) { /* read a normal core register */ reg_p[num] = &value; arm7_9->read_core_regs(target, 1 << num, reg_p); } else { /* read a program status register * if the register mode is MODE_ANY, we read the cpsr, otherwise a spsr */ arm7_9->read_xpsr(target, &value, areg->mode != ARM_MODE_ANY); } retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; r->valid = true; r->dirty = false; buf_set_u32(r->value, 0, 32, value); if ((mode != ARM_MODE_ANY) && (mode != arm->core_mode) && (areg->mode != ARM_MODE_ANY)) { /* restore processor mode (mask T bit) */ arm7_9->write_xpsr_im8(target, buf_get_u32(arm->cpsr->value, 0, 8) & ~0x20, 0, 0); } return ERROR_OK; } static int arm7_9_write_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode, uint8_t *value) { uint32_t reg[16]; struct arm_reg *areg = r->arch_info; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; if (!is_arm_mode(arm->core_mode)) return ERROR_FAIL; if ((num < 0) || (num > 16)) return ERROR_COMMAND_SYNTAX_ERROR; if ((mode != ARM_MODE_ANY) && (mode != arm->core_mode) && (areg->mode != ARM_MODE_ANY)) { uint32_t tmp_cpsr; /* change processor mode (mask T bit) */ tmp_cpsr = buf_get_u32(arm->cpsr->value, 0, 8) & 0xE0; tmp_cpsr |= mode; tmp_cpsr &= ~0x20; arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0); } if ((num >= 0) && (num <= 15)) { /* write a normal core register */ reg[num] = buf_get_u32(value, 0, 32); arm7_9->write_core_regs(target, 1 << num, reg); } else { /* write a program status register * if the register mode is MODE_ANY, we write the cpsr, otherwise a spsr */ int spsr = (areg->mode != ARM_MODE_ANY); uint32_t t = buf_get_u32(value, 0, 32); /* if we're writing the CPSR, mask the T bit */ if (!spsr) t &= ~0x20; arm7_9->write_xpsr(target, t, spsr); } r->valid = true; r->dirty = false; if ((mode != ARM_MODE_ANY) && (mode != arm->core_mode) && (areg->mode != ARM_MODE_ANY)) { /* restore processor mode (mask T bit) */ arm7_9->write_xpsr_im8(target, buf_get_u32(arm->cpsr->value, 0, 8) & ~0x20, 0, 0); } return jtag_execute_queue(); } int arm7_9_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; uint32_t reg[16]; uint32_t num_accesses = 0; int thisrun_accesses; int i; uint32_t cpsr; int retval; int last_reg = 0; LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; /* load the base register with the address of the first word */ reg[0] = address; arm7_9->write_core_regs(target, 0x1, reg); int j = 0; switch (size) { case 4: while (num_accesses < count) { uint32_t reg_list; thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; if (last_reg <= thisrun_accesses) last_reg = thisrun_accesses; arm7_9->load_word_regs(target, reg_list); /* fast memory reads are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ if (arm7_9->fast_memory_access) retval = arm7_9_execute_fast_sys_speed(target); else retval = arm7_9_execute_sys_speed(target); if (retval != ERROR_OK) return retval; arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 4); /* advance buffer, count number of accesses */ buffer += thisrun_accesses * 4; num_accesses += thisrun_accesses; if ((j++%1024) == 0) keep_alive(); } break; case 2: while (num_accesses < count) { uint32_t reg_list; thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; for (i = 1; i <= thisrun_accesses; i++) { if (i > last_reg) last_reg = i; arm7_9->load_hword_reg(target, i); /* fast memory reads are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ if (arm7_9->fast_memory_access) retval = arm7_9_execute_fast_sys_speed(target); else retval = arm7_9_execute_sys_speed(target); if (retval != ERROR_OK) return retval; } arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 2); /* advance buffer, count number of accesses */ buffer += thisrun_accesses * 2; num_accesses += thisrun_accesses; if ((j++%1024) == 0) keep_alive(); } break; case 1: while (num_accesses < count) { uint32_t reg_list; thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; for (i = 1; i <= thisrun_accesses; i++) { if (i > last_reg) last_reg = i; arm7_9->load_byte_reg(target, i); /* fast memory reads are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ if (arm7_9->fast_memory_access) retval = arm7_9_execute_fast_sys_speed(target); else retval = arm7_9_execute_sys_speed(target); if (retval != ERROR_OK) return retval; } arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 1); /* advance buffer, count number of accesses */ buffer += thisrun_accesses * 1; num_accesses += thisrun_accesses; if ((j++%1024) == 0) keep_alive(); } break; } if (!is_arm_mode(arm->core_mode)) return ERROR_FAIL; for (i = 0; i <= last_reg; i++) { struct reg *r = arm_reg_current(arm, i); r->dirty = r->valid; } arm7_9->read_xpsr(target, &cpsr, 0); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while reading cpsr"); return ERROR_TARGET_DATA_ABORT; } if (((cpsr & 0x1f) == ARM_MODE_ABT) && (arm->core_mode != ARM_MODE_ABT)) { LOG_WARNING( "memory read caused data abort " "(address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%" PRIx32 ", count: 0x%" PRIx32 ")", address, size, count); arm7_9->write_xpsr_im8(target, buf_get_u32(arm->cpsr->value, 0, 8) & ~0x20, 0, 0); return ERROR_TARGET_DATA_ABORT; } return ERROR_OK; } int arm7_9_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; uint32_t reg[16]; uint32_t num_accesses = 0; int thisrun_accesses; int i; uint32_t cpsr; int retval; int last_reg = 0; #ifdef _DEBUG_ARM7_9_ LOG_DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count); #endif if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; /* load the base register with the address of the first word */ reg[0] = address; arm7_9->write_core_regs(target, 0x1, reg); /* Clear DBGACK, to make sure memory fetches work as expected */ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 0); embeddedice_store_reg(dbg_ctrl); switch (size) { case 4: while (num_accesses < count) { uint32_t reg_list; thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; for (i = 1; i <= thisrun_accesses; i++) { if (i > last_reg) last_reg = i; reg[i] = target_buffer_get_u32(target, buffer); buffer += 4; } arm7_9->write_core_regs(target, reg_list, reg); arm7_9->store_word_regs(target, reg_list); /* fast memory writes are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ if (arm7_9->fast_memory_access) retval = arm7_9_execute_fast_sys_speed(target); else { retval = arm7_9_execute_sys_speed(target); /* * if memory writes are made when the clock is running slow * (i.e. 32 kHz) which is necessary in some scripts to reconfigure * processor operations after a "reset halt" or "reset init", * need to immediately stroke the keep alive or will end up with * gdb "keep alive not sent error message" problem. */ keep_alive(); } if (retval != ERROR_OK) return retval; num_accesses += thisrun_accesses; } break; case 2: while (num_accesses < count) { uint32_t reg_list; thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; for (i = 1; i <= thisrun_accesses; i++) { if (i > last_reg) last_reg = i; reg[i] = target_buffer_get_u16(target, buffer) & 0xffff; buffer += 2; } arm7_9->write_core_regs(target, reg_list, reg); for (i = 1; i <= thisrun_accesses; i++) { arm7_9->store_hword_reg(target, i); /* fast memory writes are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ if (arm7_9->fast_memory_access) retval = arm7_9_execute_fast_sys_speed(target); else { retval = arm7_9_execute_sys_speed(target); /* * if memory writes are made when the clock is running slow * (i.e. 32 kHz) which is necessary in some scripts to reconfigure * processor operations after a "reset halt" or "reset init", * need to immediately stroke the keep alive or will end up with * gdb "keep alive not sent error message" problem. */ keep_alive(); } if (retval != ERROR_OK) return retval; } num_accesses += thisrun_accesses; } break; case 1: while (num_accesses < count) { uint32_t reg_list; thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; for (i = 1; i <= thisrun_accesses; i++) { if (i > last_reg) last_reg = i; reg[i] = *buffer++ & 0xff; } arm7_9->write_core_regs(target, reg_list, reg); for (i = 1; i <= thisrun_accesses; i++) { arm7_9->store_byte_reg(target, i); /* fast memory writes are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ if (arm7_9->fast_memory_access) retval = arm7_9_execute_fast_sys_speed(target); else { retval = arm7_9_execute_sys_speed(target); /* * if memory writes are made when the clock is running slow * (i.e. 32 kHz) which is necessary in some scripts to reconfigure * processor operations after a "reset halt" or "reset init", * need to immediately stroke the keep alive or will end up with * gdb "keep alive not sent error message" problem. */ keep_alive(); } if (retval != ERROR_OK) return retval; } num_accesses += thisrun_accesses; } break; } /* Re-Set DBGACK */ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 1); embeddedice_store_reg(dbg_ctrl); if (!is_arm_mode(arm->core_mode)) return ERROR_FAIL; for (i = 0; i <= last_reg; i++) { struct reg *r = arm_reg_current(arm, i); r->dirty = r->valid; } arm7_9->read_xpsr(target, &cpsr, 0); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while reading cpsr"); return ERROR_TARGET_DATA_ABORT; } if (((cpsr & 0x1f) == ARM_MODE_ABT) && (arm->core_mode != ARM_MODE_ABT)) { LOG_WARNING( "memory write caused data abort " "(address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%" PRIx32 ", count: 0x%" PRIx32 ")", address, size, count); arm7_9->write_xpsr_im8(target, buf_get_u32(arm->cpsr->value, 0, 8) & ~0x20, 0, 0); return ERROR_TARGET_DATA_ABORT; } return ERROR_OK; } int arm7_9_write_memory_opt(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); int retval; if (size == 4 && count > 32 && arm7_9->bulk_write_memory) { /* Attempt to do a bulk write */ retval = arm7_9->bulk_write_memory(target, address, count, buffer); if (retval == ERROR_OK) return ERROR_OK; } return arm7_9->write_memory(target, address, size, count, buffer); } int arm7_9_write_memory_no_opt(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); return arm7_9->write_memory(target, address, size, count, buffer); } static int dcc_count; static const uint8_t *dcc_buffer; static int arm7_9_dcc_completion(struct target *target, uint32_t exit_point, unsigned int timeout_ms, void *arch_info) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); retval = target_wait_state(target, TARGET_DEBUG_RUNNING, 500); if (retval != ERROR_OK) return retval; int little = target->endianness == TARGET_LITTLE_ENDIAN; int count = dcc_count; const uint8_t *buffer = dcc_buffer; if (count > 2) { /* Handle first & last using standard embeddedice_write_reg and the middle ones w/the * core function repeated. */ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], fast_target_buffer_get_u32(buffer, little)); buffer += 4; struct embeddedice_reg *ice_reg = arm7_9->eice_cache->reg_list[EICE_COMMS_DATA].arch_info; uint8_t reg_addr = ice_reg->addr & 0x1f; struct jtag_tap *tap; tap = ice_reg->jtag_info->tap; embeddedice_write_dcc(tap, reg_addr, buffer, little, count-2); buffer += (count-2)*4; embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], fast_target_buffer_get_u32(buffer, little)); } else { int i; for (i = 0; i < count; i++) { embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], fast_target_buffer_get_u32(buffer, little)); buffer += 4; } } retval = target_halt(target); if (retval != ERROR_OK) return retval; return target_wait_state(target, TARGET_HALTED, 500); } static const uint32_t dcc_code[] = { /* r0 == input, points to memory buffer * r1 == scratch */ /* spin until DCC control (c0) reports data arrived */ 0xee101e10, /* w: mrc p14, #0, r1, c0, c0 */ 0xe3110001, /* tst r1, #1 */ 0x0afffffc, /* bne w */ /* read word from DCC (c1), write to memory */ 0xee111e10, /* mrc p14, #0, r1, c1, c0 */ 0xe4801004, /* str r1, [r0], #4 */ /* repeat */ 0xeafffff9 /* b w */ }; int arm7_9_bulk_write_memory(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer) { int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (address % 4 != 0) return ERROR_TARGET_UNALIGNED_ACCESS; if (!arm7_9->dcc_downloads) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* regrab previously allocated working_area, or allocate a new one */ if (!arm7_9->dcc_working_area) { uint8_t dcc_code_buf[6 * 4]; /* make sure we have a working area */ if (target_alloc_working_area(target, 24, &arm7_9->dcc_working_area) != ERROR_OK) { LOG_INFO("no working area available, falling back to memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* copy target instructions to target endianness */ target_buffer_set_u32_array(target, dcc_code_buf, ARRAY_SIZE(dcc_code), dcc_code); /* write DCC code to working area, using the non-optimized * memory write to avoid ending up here again */ retval = arm7_9_write_memory_no_opt(target, arm7_9->dcc_working_area->address, 4, 6, dcc_code_buf); if (retval != ERROR_OK) return retval; } struct arm_algorithm arm_algo; struct reg_param reg_params[1]; arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); dcc_count = count; dcc_buffer = buffer; retval = armv4_5_run_algorithm_inner(target, 0, NULL, 1, reg_params, arm7_9->dcc_working_area->address, arm7_9->dcc_working_area->address + 6*4, 20*1000, &arm_algo, arm7_9_dcc_completion); if (retval == ERROR_OK) { uint32_t endaddress = buf_get_u32(reg_params[0].value, 0, 32); if (endaddress != (address + count*4)) { LOG_ERROR( "DCC write failed, expected end address 0x%08" TARGET_PRIxADDR " got 0x%0" PRIx32 "", (address + count*4), endaddress); retval = ERROR_FAIL; } } destroy_reg_param(®_params[0]); return retval; } /** * Perform per-target setup that requires JTAG access. */ int arm7_9_examine(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); int retval; if (!target_was_examined(target)) { struct reg_cache *t, **cache_p; t = embeddedice_build_reg_cache(target, arm7_9); if (!t) return ERROR_FAIL; cache_p = register_get_last_cache_p(&target->reg_cache); (*cache_p) = t; arm7_9->eice_cache = (*cache_p); if (arm7_9->arm.etm) (*cache_p)->next = etm_build_reg_cache(target, &arm7_9->jtag_info, arm7_9->arm.etm); target_set_examined(target); } retval = embeddedice_setup(target); if (retval == ERROR_OK) retval = arm7_9_setup(target); if (retval == ERROR_OK && arm7_9->arm.etm) retval = etm_setup(target); return retval; } void arm7_9_deinit(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (target_was_examined(target)) embeddedice_free_reg_cache(arm7_9->eice_cache); arm_jtag_close_connection(&arm7_9->jtag_info); } int arm7_9_check_reset(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (get_target_reset_nag() && !arm7_9->dcc_downloads) LOG_WARNING( "NOTE! DCC downloads have not been enabled, defaulting to slow memory writes. Type 'help dcc'."); if (get_target_reset_nag() && (target->working_area_size == 0)) LOG_WARNING("NOTE! Severe performance degradation without working memory enabled."); if (get_target_reset_nag() && !arm7_9->fast_memory_access) LOG_WARNING( "NOTE! Severe performance degradation without fast memory access enabled. Type 'help fast'."); return ERROR_OK; } int arm7_9_endianness_callback(jtag_callback_data_t pu8_in, jtag_callback_data_t i_size, jtag_callback_data_t i_be, jtag_callback_data_t i_flip) { uint8_t *in = (uint8_t *)pu8_in; int size = (int)i_size; int be = (int)i_be; int flip = (int)i_flip; uint32_t readback; switch (size) { case 4: readback = le_to_h_u32(in); if (flip) readback = flip_u32(readback, 32); if (be) h_u32_to_be(in, readback); else h_u32_to_le(in, readback); break; case 2: readback = le_to_h_u16(in); if (flip) readback = flip_u32(readback, 16); if (be) h_u16_to_be(in, readback & 0xffff); else h_u16_to_le(in, readback & 0xffff); break; case 1: readback = *in; if (flip) readback = flip_u32(readback, 8); *in = readback & 0xff; break; } return ERROR_OK; } COMMAND_HANDLER(handle_arm7_9_dbgrq_command) { struct target *target = get_current_target(CMD_CTX); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (!is_arm7_9(arm7_9)) { command_print(CMD, "current target isn't an ARM7/ARM9 target"); return ERROR_TARGET_INVALID; } if (CMD_ARGC > 0) COMMAND_PARSE_ENABLE(CMD_ARGV[0], arm7_9->use_dbgrq); command_print(CMD, "use of EmbeddedICE dbgrq instead of breakpoint for target halt %s", (arm7_9->use_dbgrq) ? "enabled" : "disabled"); return ERROR_OK; } COMMAND_HANDLER(handle_arm7_9_fast_memory_access_command) { struct target *target = get_current_target(CMD_CTX); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (!is_arm7_9(arm7_9)) { command_print(CMD, "current target isn't an ARM7/ARM9 target"); return ERROR_TARGET_INVALID; } if (CMD_ARGC > 0) COMMAND_PARSE_ENABLE(CMD_ARGV[0], arm7_9->fast_memory_access); command_print(CMD, "fast memory access is %s", (arm7_9->fast_memory_access) ? "enabled" : "disabled"); return ERROR_OK; } COMMAND_HANDLER(handle_arm7_9_dcc_downloads_command) { struct target *target = get_current_target(CMD_CTX); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (!is_arm7_9(arm7_9)) { command_print(CMD, "current target isn't an ARM7/ARM9 target"); return ERROR_TARGET_INVALID; } if (CMD_ARGC > 0) COMMAND_PARSE_ENABLE(CMD_ARGV[0], arm7_9->dcc_downloads); command_print(CMD, "dcc downloads are %s", (arm7_9->dcc_downloads) ? "enabled" : "disabled"); return ERROR_OK; } static int arm7_9_setup_semihosting(struct target *target, int enable) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (!is_arm7_9(arm7_9)) { LOG_USER("current target isn't an ARM7/ARM9 target"); return ERROR_TARGET_INVALID; } if (arm7_9->has_vector_catch) { struct reg *vector_catch = &arm7_9->eice_cache ->reg_list[EICE_VEC_CATCH]; if (!vector_catch->valid) embeddedice_read_reg(vector_catch); buf_set_u32(vector_catch->value, 2, 1, enable); embeddedice_store_reg(vector_catch); } else { /* TODO: allow optional high vectors and/or BKPT_HARD */ if (enable) breakpoint_add(target, 8, 4, BKPT_SOFT); else breakpoint_remove(target, 8); } return ERROR_OK; } int arm7_9_init_arch_info(struct target *target, struct arm7_9_common *arm7_9) { int retval = ERROR_OK; struct arm *arm = &arm7_9->arm; arm7_9->common_magic = ARM7_9_COMMON_MAGIC; retval = arm_jtag_setup_connection(&arm7_9->jtag_info); if (retval != ERROR_OK) return retval; /* caller must have allocated via calloc(), so everything's zeroed */ arm7_9->wp_available_max = 2; arm7_9->fast_memory_access = false; arm7_9->dcc_downloads = false; arm->arch_info = arm7_9; arm->core_type = ARM_CORE_TYPE_STD; arm->read_core_reg = arm7_9_read_core_reg; arm->write_core_reg = arm7_9_write_core_reg; arm->full_context = arm7_9_full_context; arm->setup_semihosting = arm7_9_setup_semihosting; retval = arm_init_arch_info(target, arm); if (retval != ERROR_OK) return retval; return target_register_timer_callback(arm7_9_handle_target_request, 1, TARGET_TIMER_TYPE_PERIODIC, target); } static const struct command_registration arm7_9_any_command_handlers[] = { { .name = "dbgrq", .handler = handle_arm7_9_dbgrq_command, .mode = COMMAND_ANY, .usage = "['enable'|'disable']", .help = "use EmbeddedICE dbgrq instead of breakpoint " "for target halt requests", }, { .name = "fast_memory_access", .handler = handle_arm7_9_fast_memory_access_command, .mode = COMMAND_ANY, .usage = "['enable'|'disable']", .help = "use fast memory accesses instead of slower " "but potentially safer accesses", }, { .name = "dcc_downloads", .handler = handle_arm7_9_dcc_downloads_command, .mode = COMMAND_ANY, .usage = "['enable'|'disable']", .help = "use DCC downloads for larger memory writes", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm7_9_command_handlers[] = { { .chain = arm_command_handlers, }, { .chain = etm_command_handlers, }, { .name = "arm7_9", .mode = COMMAND_ANY, .help = "arm7/9 specific commands", .usage = "", .chain = arm7_9_any_command_handlers, }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm7_9_common.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by Hongtao Zheng * * hontor@126.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM7_9_COMMON_H #define OPENOCD_TARGET_ARM7_9_COMMON_H #include "arm.h" #include "arm_jtag.h" #define ARM7_9_COMMON_MAGIC 0x0a790a79U /**< */ /** * Structure for items that are common between both ARM7 and ARM9 targets. */ struct arm7_9_common { unsigned int common_magic; struct arm arm; struct arm_jtag jtag_info; /**< JTAG information for target */ struct reg_cache *eice_cache; /**< Embedded ICE register cache */ uint32_t arm_bkpt; /**< ARM breakpoint instruction */ uint16_t thumb_bkpt; /**< Thumb breakpoint instruction */ int sw_breakpoints_added; /**< Specifies which watchpoint software breakpoints are setup on */ int sw_breakpoint_count; /**< keep track of number of software breakpoints we have set */ int breakpoint_count; /**< Current number of set breakpoints */ int wp_available; /**< Current number of available watchpoint units */ int wp_available_max; /**< Maximum number of available watchpoint units */ int wp0_used; /**< Specifies if and how watchpoint unit 0 is used */ int wp1_used; /**< Specifies if and how watchpoint unit 1 is used */ int wp1_used_default; /**< Specifies if and how watchpoint unit 1 is used by default */ int dbgreq_adjust_pc; /**< Amount of PC adjustment caused by a DBGREQ */ bool use_dbgrq; /**< Specifies if DBGRQ should be used to halt the target */ bool need_bypass_before_restart; /**< Specifies if there should be a bypass before a JTAG restart */ bool has_single_step; bool has_monitor_mode; bool has_vector_catch; /**< Specifies if the target has a reset vector catch */ bool debug_entry_from_reset; /**< Specifies if debug entry was from a reset */ bool fast_memory_access; bool dcc_downloads; struct working_area *dcc_working_area; int (*examine_debug_reason)(struct target *target); /**< Function for determining why debug state was entered */ void (*change_to_arm)(struct target *target, uint32_t *r0, uint32_t *pc); /**< Function for changing from Thumb to ARM mode */ void (*read_core_regs)(struct target *target, uint32_t mask, uint32_t *core_regs[16]); /**< Function for reading the core registers */ void (*read_core_regs_target_buffer)(struct target *target, uint32_t mask, void *buffer, int size); void (*read_xpsr)(struct target *target, uint32_t *xpsr, int spsr); /**< Function for reading CPSR or SPSR */ void (*write_xpsr)(struct target *target, uint32_t xpsr, int spsr); /**< Function for writing to CPSR or SPSR */ void (*write_xpsr_im8)(struct target *target, uint8_t xpsr_im, int rot, int spsr); /**< Function for writing an immediate value to CPSR or SPSR */ void (*write_core_regs)(struct target *target, uint32_t mask, uint32_t core_regs[16]); void (*load_word_regs)(struct target *target, uint32_t mask); void (*load_hword_reg)(struct target *target, int num); void (*load_byte_reg)(struct target *target, int num); void (*store_word_regs)(struct target *target, uint32_t mask); void (*store_hword_reg)(struct target *target, int num); void (*store_byte_reg)(struct target *target, int num); void (*write_pc)(struct target *target, uint32_t pc); /**< Function for writing to the program counter */ void (*branch_resume)(struct target *target); void (*branch_resume_thumb)(struct target *target); void (*enable_single_step)(struct target *target, uint32_t next_pc); void (*disable_single_step)(struct target *target); void (*set_special_dbgrq)(struct target *target); /**< Function for setting DBGRQ if the normal way won't work */ int (*post_debug_entry)(struct target *target); /**< Callback function called after entering debug mode */ void (*pre_restore_context)(struct target *target); /**< Callback function called before restoring the processor context */ /** * Variant specific memory write function that does not dispatch to bulk_write_memory. * Used as a fallback when bulk writes are unavailable, or for writing data needed to * do the bulk writes. */ int (*write_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); /** * Write target memory in multiples of 4 bytes, optimized for * writing large quantities of data. */ int (*bulk_write_memory)(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer); }; static inline struct arm7_9_common *target_to_arm7_9(struct target *target) { return container_of(target->arch_info, struct arm7_9_common, arm); } static inline bool is_arm7_9(struct arm7_9_common *arm7_9) { return arm7_9->common_magic == ARM7_9_COMMON_MAGIC; } extern const struct command_registration arm7_9_command_handlers[]; int arm7_9_poll(struct target *target); int arm7_9_target_request_data(struct target *target, uint32_t size, uint8_t *buffer); int arm7_9_assert_reset(struct target *target); int arm7_9_deassert_reset(struct target *target); int arm7_9_reset_request_halt(struct target *target); int arm7_9_early_halt(struct target *target); int arm7_9_soft_reset_halt(struct target *target); int arm7_9_halt(struct target *target); int arm7_9_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); int arm7_9_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); int arm7_9_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); int arm7_9_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int arm7_9_write_memory_opt(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int arm7_9_write_memory_no_opt(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int arm7_9_bulk_write_memory(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer); int arm7_9_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_prams, struct reg_param *reg_param, uint32_t entry_point, void *arch_info); int arm7_9_add_breakpoint(struct target *target, struct breakpoint *breakpoint); int arm7_9_remove_breakpoint(struct target *target, struct breakpoint *breakpoint); int arm7_9_add_watchpoint(struct target *target, struct watchpoint *watchpoint); int arm7_9_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); void arm7_9_enable_eice_step(struct target *target, uint32_t next_pc); void arm7_9_disable_eice_step(struct target *target); int arm7_9_execute_sys_speed(struct target *target); int arm7_9_init_arch_info(struct target *target, struct arm7_9_common *arm7_9); int arm7_9_examine(struct target *target); void arm7_9_deinit(struct target *target); int arm7_9_check_reset(struct target *target); int arm7_9_endianness_callback(jtag_callback_data_t pu8_in, jtag_callback_data_t i_size, jtag_callback_data_t i_be, jtag_callback_data_t i_flip); #endif /* OPENOCD_TARGET_ARM7_9_COMMON_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm7tdmi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm7tdmi.h" #include "target_type.h" #include "register.h" #include "arm_opcodes.h" #include "arm_semihosting.h" /* * For information about ARM7TDMI, see ARM DDI 0210C (r4p1) * or ARM DDI 0029G (r3). "Debug In Depth", Appendix B, * covers JTAG support. */ #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif static int arm7tdmi_examine_debug_reason(struct target *target) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); /* only check the debug reason if we don't know it already */ if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) { struct scan_field fields[2]; uint8_t databus[4]; uint8_t breakpoint; fields[0].num_bits = 1; fields[0].out_value = NULL; fields[0].in_value = &breakpoint; fields[1].num_bits = 32; fields[1].out_value = NULL; fields[1].in_value = databus; retval = arm_jtag_scann(&arm7_9->jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(arm7_9->jtag_info.tap, arm7_9->jtag_info.intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; jtag_add_dr_scan(arm7_9->jtag_info.tap, 2, fields, TAP_DRPAUSE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; fields[0].in_value = NULL; fields[0].out_value = &breakpoint; fields[1].in_value = NULL; fields[1].out_value = databus; jtag_add_dr_scan(arm7_9->jtag_info.tap, 2, fields, TAP_DRPAUSE); if (breakpoint & 1) target->debug_reason = DBG_REASON_WATCHPOINT; else target->debug_reason = DBG_REASON_BREAKPOINT; } return ERROR_OK; } static const int arm7tdmi_num_bits[] = {1, 32}; static inline int arm7tdmi_clock_out_inner(struct arm_jtag *jtag_info, uint32_t out, int breakpoint) { uint8_t bp = breakpoint ? 1 : 0; uint8_t out_value[4]; buf_set_u32(out_value, 0, 32, flip_u32(out, 32)); struct scan_field fields[2] = { { .num_bits = arm7tdmi_num_bits[0], .out_value = &bp }, { .num_bits = arm7tdmi_num_bits[1], .out_value = out_value }, }; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE); jtag_add_runtest(0, TAP_DRPAUSE); return ERROR_OK; } /* put an instruction in the ARM7TDMI pipeline or write the data bus, * and optionally read data */ static inline int arm7tdmi_clock_out(struct arm_jtag *jtag_info, uint32_t out, int breakpoint) { int retval; retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; return arm7tdmi_clock_out_inner(jtag_info, out, breakpoint); } /* clock the target, reading the databus */ static int arm7tdmi_clock_data_in(struct arm_jtag *jtag_info, uint32_t *in) { int retval = ERROR_OK; struct scan_field fields[2]; retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 1; fields[0].out_value = NULL; fields[0].in_value = NULL; fields[1].num_bits = 32; fields[1].out_value = NULL; fields[1].in_value = (uint8_t *)in; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE); jtag_add_callback(arm7flip32, (jtag_callback_data_t)in); jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (in) LOG_DEBUG("in: 0x%8.8x", *in); else LOG_ERROR("BUG: called with in == NULL"); #endif return ERROR_OK; } /* clock the target, and read the databus * the *in pointer points to a buffer where elements of 'size' bytes * are stored in big (be == 1) or little (be == 0) endianness */ static int arm7tdmi_clock_data_in_endianness(struct arm_jtag *jtag_info, void *in, int size, int be) { int retval = ERROR_OK; struct scan_field fields[3]; retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 1; fields[0].out_value = NULL; fields[0].in_value = NULL; if (size == 4) { fields[1].num_bits = 32; fields[1].out_value = NULL; fields[1].in_value = in; } else { /* Discard irrelevant bits of the scan, making sure we don't write more * than size bytes to in */ fields[1].num_bits = 32 - size * 8; fields[1].out_value = NULL; fields[1].in_value = NULL; fields[2].num_bits = size * 8; fields[2].out_value = NULL; fields[2].in_value = in; } jtag_add_dr_scan(jtag_info->tap, size == 4 ? 2 : 3, fields, TAP_DRPAUSE); jtag_add_callback4(arm7_9_endianness_callback, (jtag_callback_data_t)in, (jtag_callback_data_t)size, (jtag_callback_data_t)be, (jtag_callback_data_t)1); jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ { retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (in) LOG_DEBUG("in: 0x%8.8x", *(uint32_t *)in); else LOG_ERROR("BUG: called with in == NULL"); } #endif return ERROR_OK; } static void arm7tdmi_change_to_arm(struct target *target, uint32_t *r0, uint32_t *pc) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* save r0 before using it and put system in ARM state * to allow common handling of ARM and THUMB debugging */ /* fetch STR r0, [r0] */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* nothing fetched, STR r0, [r0] in Execute (2) */ arm7tdmi_clock_data_in(jtag_info, r0); /* MOV r0, r15 fetched, STR in Decode */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* nothing fetched, STR r0, [r0] in Execute (2) */ arm7tdmi_clock_data_in(jtag_info, pc); /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* nothing fetched, data for LDR r0, [PC, #0] */ arm7tdmi_clock_out(jtag_info, 0x0, 0); /* nothing fetched, data from previous cycle is written to register */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* fetch BX */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), 0); /* NOP fetched, BX in Decode, MOV in Execute */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* NOP fetched, BX in Execute (1) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); jtag_execute_queue(); /* fix program counter: * MOV r0, r15 was the 4th instruction (+6) * reading PC in Thumb state gives address of instruction + 4 */ *pc -= 0xa; } /* FIX!!! is this a potential performance bottleneck w.r.t. requiring too many * roundtrips when jtag_execute_queue() has a large overhead(e.g. for USB)s? * * The solution is to arrange for a large out/in scan in this loop and * and convert data afterwards. */ static void arm7tdmi_read_core_regs(struct target *target, uint32_t mask, uint32_t *core_regs[16]) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0); /* fetch NOP, STM in DECODE stage */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, STM still in EXECUTE (1 + i cycle) */ arm7tdmi_clock_data_in(jtag_info, core_regs[i]); } } static void arm7tdmi_read_core_regs_target_buffer(struct target *target, uint32_t mask, void *buffer, int size) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; uint32_t *buf_u32 = buffer; uint16_t *buf_u16 = buffer; uint8_t *buf_u8 = buffer; /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0); /* fetch NOP, STM in DECODE stage */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); for (i = 0; i <= 15; i++) { /* nothing fetched, STM still in EXECUTE (1 + i cycle), read databus */ if (mask & (1 << i)) { switch (size) { case 4: arm7tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); break; case 2: arm7tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); break; case 1: arm7tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); break; } } } } static void arm7tdmi_read_xpsr(struct target *target, uint32_t *xpsr, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* MRS r0, cpsr */ arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0); /* STR r0, [r15] */ arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0); /* fetch NOP, STR in DECODE stage */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, STR in EXECUTE stage (1st cycle) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, STR still in EXECUTE (2nd cycle) */ arm7tdmi_clock_data_in(jtag_info, xpsr); } static void arm7tdmi_write_xpsr(struct target *target, uint32_t xpsr, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr: %8.8" PRIx32 ", spsr: %i", xpsr, spsr); /* MSR1 fetched */ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0); /* MSR2 fetched, MSR1 in DECODE */ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0); /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0); /* nothing fetched, MSR1 in EXECUTE (2) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0); /* nothing fetched, MSR2 in EXECUTE (2) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, MSR3 in EXECUTE (2) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* NOP fetched, MSR4 in EXECUTE (1) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, MSR4 in EXECUTE (2) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); } static void arm7tdmi_write_xpsr_im8(struct target *target, uint8_t xpsr_im, int rot, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); /* MSR fetched */ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0); /* NOP fetched, MSR in DECODE */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* NOP fetched, MSR in EXECUTE (1) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, MSR in EXECUTE (2) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); } static void arm7tdmi_write_core_regs(struct target *target, uint32_t mask, uint32_t core_regs[16]) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0); /* fetch NOP, LDM in DECODE stage */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, LDM still in EXECUTE (1 + i cycle) */ arm7tdmi_clock_out_inner(jtag_info, core_regs[i], 0); } arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); } static void arm7tdmi_load_word_regs(struct target *target, uint32_t mask) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load-multiple into the pipeline */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), 0); } static void arm7tdmi_load_hword_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load half-word into the pipeline */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), 0); } static void arm7tdmi_load_byte_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load byte into the pipeline */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), 0); } static void arm7tdmi_store_word_regs(struct target *target, uint32_t mask) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store-multiple into the pipeline */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), 0); } static void arm7tdmi_store_hword_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store half-word into the pipeline */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), 0); } static void arm7tdmi_store_byte_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store byte into the pipeline */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), 0); } static void arm7tdmi_write_pc(struct target *target, uint32_t pc) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0); /* fetch NOP, LDM in DECODE stage */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, LDM in EXECUTE stage (1st cycle) load register */ arm7tdmi_clock_out_inner(jtag_info, pc, 0); /* nothing fetched, LDM in EXECUTE stage (2nd cycle) load register */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, LDM in EXECUTE stage (3rd cycle) load register */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, LDM in EXECUTE stage (4th cycle) */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, LDM in EXECUTE stage (5th cycle) */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); } static void arm7tdmi_branch_resume(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_B(0xfffffa, 0), 0); } static void arm7tdmi_branch_resume_thumb(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; LOG_DEBUG("-"); /* LDMIA r0, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), 0); /* fetch NOP, LDM in DECODE stage */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */ arm7tdmi_clock_out(jtag_info, buf_get_u32(arm->pc->value, 0, 32) | 1, 0); /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* Branch and eXchange */ arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0); embeddedice_read_reg(dbg_stat); /* fetch NOP, BX in DECODE stage */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* target is now in Thumb state */ embeddedice_read_reg(dbg_stat); /* fetch NOP, BX in EXECUTE stage (1st cycle) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* target is now in Thumb state */ embeddedice_read_reg(dbg_stat); /* load r0 value */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0); /* fetch NOP, LDR in Decode */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* fetch NOP, LDR in Execute */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */ arm7tdmi_clock_out(jtag_info, buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32), 0); /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); embeddedice_read_reg(dbg_stat); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 1); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f8), 0); } static void arm7tdmi_build_reg_cache(struct target *target) { struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct arm *arm = target_to_arm(target); (*cache_p) = arm_build_reg_cache(target, arm); } static void arm7tdmi_free_reg_cache(struct target *target) { struct arm *arm = target_to_arm(target); arm_free_reg_cache(arm); } int arm7tdmi_init_target(struct command_context *cmd_ctx, struct target *target) { arm7tdmi_build_reg_cache(target); arm_semihosting_init(target); return ERROR_OK; } void arm7tdmi_deinit_target(struct target *target) { arm7tdmi_free_reg_cache(target); } int arm7tdmi_init_arch_info(struct target *target, struct arm7_9_common *arm7_9, struct jtag_tap *tap) { /* prepare JTAG information for the new target */ arm7_9->jtag_info.tap = tap; arm7_9->jtag_info.scann_size = 4; /* register arch-specific functions */ arm7_9->examine_debug_reason = arm7tdmi_examine_debug_reason; arm7_9->change_to_arm = arm7tdmi_change_to_arm; arm7_9->read_core_regs = arm7tdmi_read_core_regs; arm7_9->read_core_regs_target_buffer = arm7tdmi_read_core_regs_target_buffer; arm7_9->read_xpsr = arm7tdmi_read_xpsr; arm7_9->write_xpsr = arm7tdmi_write_xpsr; arm7_9->write_xpsr_im8 = arm7tdmi_write_xpsr_im8; arm7_9->write_core_regs = arm7tdmi_write_core_regs; arm7_9->load_word_regs = arm7tdmi_load_word_regs; arm7_9->load_hword_reg = arm7tdmi_load_hword_reg; arm7_9->load_byte_reg = arm7tdmi_load_byte_reg; arm7_9->store_word_regs = arm7tdmi_store_word_regs; arm7_9->store_hword_reg = arm7tdmi_store_hword_reg; arm7_9->store_byte_reg = arm7tdmi_store_byte_reg; arm7_9->write_pc = arm7tdmi_write_pc; arm7_9->branch_resume = arm7tdmi_branch_resume; arm7_9->branch_resume_thumb = arm7tdmi_branch_resume_thumb; arm7_9->enable_single_step = arm7_9_enable_eice_step; arm7_9->disable_single_step = arm7_9_disable_eice_step; arm7_9->write_memory = arm7_9_write_memory; arm7_9->bulk_write_memory = arm7_9_bulk_write_memory; arm7_9->post_debug_entry = NULL; arm7_9->pre_restore_context = NULL; /* initialize arch-specific breakpoint handling */ arm7_9->arm_bkpt = 0xdeeedeee; arm7_9->thumb_bkpt = 0xdeee; arm7_9->dbgreq_adjust_pc = 2; arm7_9_init_arch_info(target, arm7_9); return ERROR_OK; } static int arm7tdmi_target_create(struct target *target, Jim_Interp *interp) { struct arm7_9_common *arm7_9; arm7_9 = calloc(1, sizeof(struct arm7_9_common)); arm7tdmi_init_arch_info(target, arm7_9, target->tap); arm7_9->arm.arch = ARM_ARCH_V4; return ERROR_OK; } /** Holds methods for ARM7TDMI targets. */ struct target_type arm7tdmi_target = { .name = "arm7tdmi", .poll = arm7_9_poll, .arch_state = arm_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm7_9_soft_reset_halt, .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm7_9_read_memory, .write_memory = arm7_9_write_memory_opt, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm7_9_command_handlers, .target_create = arm7tdmi_target_create, .init_target = arm7tdmi_init_target, .deinit_target = arm7tdmi_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm7tdmi.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM7TDMI_H #define OPENOCD_TARGET_ARM7TDMI_H #include "embeddedice.h" int arm7tdmi_init_arch_info(struct target *target, struct arm7_9_common *arm7_9, struct jtag_tap *tap); int arm7tdmi_init_target(struct command_context *cmd_ctx, struct target *target); void arm7tdmi_deinit_target(struct target *target); #endif /* OPENOCD_TARGET_ARM7TDMI_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm920t.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm920t.h" #include <helper/time_support.h> #include "target_type.h" #include "register.h" #include "arm_opcodes.h" /* * For information about the ARM920T, see ARM DDI 0151C especially * Chapter 9 about debug support, which shows how to manipulate each * of the different scan chains: * * 0 ... ARM920 signals, e.g. to rest of SOC (unused here) * 1 ... debugging; watchpoint and breakpoint status, etc; also * MMU and cache access in conjunction with scan chain 15 * 2 ... EmbeddedICE * 3 ... external boundary scan (SoC-specific, unused here) * 4 ... access to cache tag RAM * 6 ... ETM9 * 15 ... access coprocessor 15, "physical" or "interpreted" modes * "interpreted" works with a few actual MRC/MCR instructions * "physical" provides register-like behaviors. Section 9.6.7 * covers these details. * * The ARM922T is similar, but with smaller caches (8K each, vs 16K). */ #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif /* Table 9-8 shows scan chain 15 format during physical access mode, using a * dedicated 6-bit address space (encoded in bits 33:38). Writes use one * JTAG scan, while reads use two. * * Table 9-9 lists the thirteen registers which support physical access. * ARM920T_CP15_PHYS_ADDR() constructs the 6-bit reg_addr parameter passed * to arm920t_read_cp15_physical() and arm920t_write_cp15_physical(). * * x == bit[38] * y == bits[37:34] * z == bit[33] */ #define ARM920T_CP15_PHYS_ADDR(x, y, z) ((x << 5) | (y << 1) << (z)) /* Registers supporting physical Read access (from table 9-9) */ #define CP15PHYS_CACHETYPE ARM920T_CP15_PHYS_ADDR(0, 0x0, 1) #define CP15PHYS_ICACHE_IDX ARM920T_CP15_PHYS_ADDR(1, 0xd, 1) #define CP15PHYS_DCACHE_IDX ARM920T_CP15_PHYS_ADDR(1, 0xe, 1) /* NOTE: several more registers support only physical read access */ /* Registers supporting physical Read/Write access (from table 9-9) */ #define CP15PHYS_CTRL ARM920T_CP15_PHYS_ADDR(0, 0x1, 0) #define CP15PHYS_PID ARM920T_CP15_PHYS_ADDR(0, 0xd, 0) #define CP15PHYS_TESTSTATE ARM920T_CP15_PHYS_ADDR(0, 0xf, 0) #define CP15PHYS_ICACHE ARM920T_CP15_PHYS_ADDR(1, 0x1, 1) #define CP15PHYS_DCACHE ARM920T_CP15_PHYS_ADDR(1, 0x2, 1) static int arm920t_read_cp15_physical(struct target *target, int reg_addr, uint32_t *value) { struct arm920t_common *arm920t = target_to_arm920(target); struct arm_jtag *jtag_info; struct scan_field fields[4]; uint8_t access_type_buf = 1; uint8_t reg_addr_buf = reg_addr & 0x3f; uint8_t nr_w_buf = 0; int retval; jtag_info = &arm920t->arm7_9_common.jtag_info; retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 1; fields[0].out_value = &access_type_buf; fields[0].in_value = NULL; fields[1].num_bits = 32; fields[1].out_value = NULL; fields[1].in_value = NULL; fields[2].num_bits = 6; fields[2].out_value = ®_addr_buf; fields[2].in_value = NULL; fields[3].num_bits = 1; fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); fields[1].in_value = (uint8_t *)value; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ jtag_execute_queue(); LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); #endif return ERROR_OK; } static int arm920t_write_cp15_physical(struct target *target, int reg_addr, uint32_t value) { struct arm920t_common *arm920t = target_to_arm920(target); struct arm_jtag *jtag_info; struct scan_field fields[4]; uint8_t access_type_buf = 1; uint8_t reg_addr_buf = reg_addr & 0x3f; uint8_t nr_w_buf = 1; uint8_t value_buf[4]; int retval; jtag_info = &arm920t->arm7_9_common.jtag_info; buf_set_u32(value_buf, 0, 32, value); retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 1; fields[0].out_value = &access_type_buf; fields[0].in_value = NULL; fields[1].num_bits = 32; fields[1].out_value = value_buf; fields[1].in_value = NULL; fields[2].num_bits = 6; fields[2].out_value = ®_addr_buf; fields[2].in_value = NULL; fields[3].num_bits = 1; fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); #endif return ERROR_OK; } /* See table 9-10 for scan chain 15 format during interpreted access mode. * If the TESTSTATE register is set for interpreted access, certain CP15 * MRC and MCR instructions may be executed through scan chain 15. * * Tables 9-11, 9-12, and 9-13 show which MRC and MCR instructions can be * executed using scan chain 15 interpreted mode. */ static int arm920t_execute_cp15(struct target *target, uint32_t cp15_opcode, uint32_t arm_opcode) { int retval; struct arm920t_common *arm920t = target_to_arm920(target); struct arm_jtag *jtag_info; struct scan_field fields[4]; uint8_t access_type_buf = 0; /* interpreted access */ uint8_t reg_addr_buf = 0x0; uint8_t nr_w_buf = 0; uint8_t cp15_opcode_buf[4]; jtag_info = &arm920t->arm7_9_common.jtag_info; retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; buf_set_u32(cp15_opcode_buf, 0, 32, cp15_opcode); fields[0].num_bits = 1; fields[0].out_value = &access_type_buf; fields[0].in_value = NULL; fields[1].num_bits = 32; fields[1].out_value = cp15_opcode_buf; fields[1].in_value = NULL; fields[2].num_bits = 6; fields[2].out_value = ®_addr_buf; fields[2].in_value = NULL; fields[3].num_bits = 1; fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); arm9tdmi_clock_out(jtag_info, arm_opcode, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); retval = arm7_9_execute_sys_speed(target); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("failed executing JTAG queue"); return retval; } return ERROR_OK; } static int arm920t_read_cp15_interpreted(struct target *target, uint32_t cp15_opcode, uint32_t address, uint32_t *value) { struct arm *arm = target_to_arm(target); uint32_t *regs_p[16]; uint32_t regs[16]; uint32_t cp15c15 = 0x0; struct reg *r = arm->core_cache->reg_list; /* load address into R1 */ regs[1] = address; arm9tdmi_write_core_regs(target, 0x2, regs); /* read-modify-write CP15 test state register * to enable interpreted access mode */ arm920t_read_cp15_physical(target, CP15PHYS_TESTSTATE, &cp15c15); jtag_execute_queue(); cp15c15 |= 1; /* set interpret mode */ arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* execute CP15 instruction and ARM load (reading from coprocessor) */ arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_LDR(0, 1)); /* disable interpreted access mode */ cp15c15 &= ~1U; /* clear interpret mode */ arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* retrieve value from R0 */ regs_p[0] = value; arm9tdmi_read_core_regs(target, 0x1, regs_p); jtag_execute_queue(); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("cp15_opcode: %8.8x, address: %8.8x, value: %8.8x", cp15_opcode, address, *value); #endif if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } r[0].dirty = true; r[1].dirty = true; return ERROR_OK; } static int arm920t_write_cp15_interpreted(struct target *target, uint32_t cp15_opcode, uint32_t value, uint32_t address) { uint32_t cp15c15 = 0x0; struct arm *arm = target_to_arm(target); uint32_t regs[16]; struct reg *r = arm->core_cache->reg_list; /* load value, address into R0, R1 */ regs[0] = value; regs[1] = address; arm9tdmi_write_core_regs(target, 0x3, regs); /* read-modify-write CP15 test state register * to enable interpreted access mode */ arm920t_read_cp15_physical(target, CP15PHYS_TESTSTATE, &cp15c15); jtag_execute_queue(); cp15c15 |= 1; /* set interpret mode */ arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* execute CP15 instruction and ARM store (writing to coprocessor) */ arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_STR(0, 1)); /* disable interpreted access mode */ cp15c15 &= ~1U; /* set interpret mode */ arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("cp15_opcode: %8.8x, value: %8.8x, address: %8.8x", cp15_opcode, value, address); #endif if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } r[0].dirty = true; r[1].dirty = true; return ERROR_OK; } /* EXPORTED to FA256 */ int arm920t_get_ttb(struct target *target, uint32_t *result) { int retval; uint32_t ttb = 0x0; retval = arm920t_read_cp15_interpreted(target, /* FIXME use opcode macro */ 0xeebf0f51, 0x0, &ttb); if (retval != ERROR_OK) return retval; *result = ttb; return ERROR_OK; } /* EXPORTED to FA256 */ int arm920t_disable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { uint32_t cp15_control; int retval; /* read cp15 control register */ retval = arm920t_read_cp15_physical(target, CP15PHYS_CTRL, &cp15_control); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (mmu) cp15_control &= ~0x1U; if (d_u_cache) cp15_control &= ~0x4U; if (i_cache) cp15_control &= ~0x1000U; retval = arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_control); return retval; } /* EXPORTED to FA256 */ int arm920t_enable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { uint32_t cp15_control; int retval; /* read cp15 control register */ retval = arm920t_read_cp15_physical(target, CP15PHYS_CTRL, &cp15_control); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (mmu) cp15_control |= 0x1U; if (d_u_cache) cp15_control |= 0x4U; if (i_cache) cp15_control |= 0x1000U; retval = arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_control); return retval; } /* EXPORTED to FA256 */ int arm920t_post_debug_entry(struct target *target) { uint32_t cp15c15; struct arm920t_common *arm920t = target_to_arm920(target); int retval; /* examine cp15 control reg */ retval = arm920t_read_cp15_physical(target, CP15PHYS_CTRL, &arm920t->cp15_control_reg); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, arm920t->cp15_control_reg); if (arm920t->armv4_5_mmu.armv4_5_cache.ctype == -1) { uint32_t cache_type_reg; /* identify caches */ retval = arm920t_read_cp15_physical(target, CP15PHYS_CACHETYPE, &cache_type_reg); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; armv4_5_identify_cache(cache_type_reg, &arm920t->armv4_5_mmu.armv4_5_cache); } arm920t->armv4_5_mmu.mmu_enabled = (arm920t->cp15_control_reg & 0x1U) ? 1 : 0; arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm920t->cp15_control_reg & 0x4U) ? 1 : 0; arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm920t->cp15_control_reg & 0x1000U) ? 1 : 0; /* save i/d fault status and address register * FIXME use opcode macros */ retval = arm920t_read_cp15_interpreted(target, 0xee150f10, 0x0, &arm920t->d_fsr); if (retval != ERROR_OK) return retval; retval = arm920t_read_cp15_interpreted(target, 0xee150f30, 0x0, &arm920t->i_fsr); if (retval != ERROR_OK) return retval; retval = arm920t_read_cp15_interpreted(target, 0xee160f10, 0x0, &arm920t->d_far); if (retval != ERROR_OK) return retval; retval = arm920t_read_cp15_interpreted(target, 0xee160f30, 0x0, &arm920t->i_far); if (retval != ERROR_OK) return retval; LOG_DEBUG("D FSR: 0x%8.8" PRIx32 ", D FAR: 0x%8.8" PRIx32 ", I FSR: 0x%8.8" PRIx32 ", I FAR: 0x%8.8" PRIx32, arm920t->d_fsr, arm920t->d_far, arm920t->i_fsr, arm920t->i_far); if (arm920t->preserve_cache) { /* read-modify-write CP15 test state register * to disable I/D-cache linefills */ retval = arm920t_read_cp15_physical(target, CP15PHYS_TESTSTATE, &cp15c15); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; cp15c15 |= 0x600; retval = arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); if (retval != ERROR_OK) return retval; } return ERROR_OK; } /* EXPORTED to FA256 */ void arm920t_pre_restore_context(struct target *target) { uint32_t cp15c15 = 0; struct arm920t_common *arm920t = target_to_arm920(target); /* restore i/d fault status and address register */ arm920t_write_cp15_interpreted(target, 0xee050f10, arm920t->d_fsr, 0x0); arm920t_write_cp15_interpreted(target, 0xee050f30, arm920t->i_fsr, 0x0); arm920t_write_cp15_interpreted(target, 0xee060f10, arm920t->d_far, 0x0); arm920t_write_cp15_interpreted(target, 0xee060f30, arm920t->i_far, 0x0); /* read-modify-write CP15 test state register * to reenable I/D-cache linefills */ if (arm920t->preserve_cache) { arm920t_read_cp15_physical(target, CP15PHYS_TESTSTATE, &cp15c15); jtag_execute_queue(); cp15c15 &= ~0x600U; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); } } static const char arm920_not[] = "target is not an ARM920"; static int arm920t_verify_pointer(struct command_invocation *cmd, struct arm920t_common *arm920t) { if (arm920t->common_magic != ARM920T_COMMON_MAGIC) { command_print(cmd, arm920_not); return ERROR_TARGET_INVALID; } return ERROR_OK; } /** Logs summary of ARM920 state for a halted target. */ int arm920t_arch_state(struct target *target) { static const char *state[] = { "disabled", "enabled" }; struct arm920t_common *arm920t = target_to_arm920(target); if (arm920t->common_magic != ARM920T_COMMON_MAGIC) { LOG_ERROR("BUG: %s", arm920_not); return ERROR_TARGET_INVALID; } arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", state[arm920t->armv4_5_mmu.mmu_enabled], state[arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], state[arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); return ERROR_OK; } static int arm920_mmu(struct target *target, int *enabled) { if (target->state != TARGET_HALTED) { LOG_ERROR("%s: target not halted", __func__); return ERROR_TARGET_INVALID; } *enabled = target_to_arm920(target)->armv4_5_mmu.mmu_enabled; return ERROR_OK; } static int arm920_virt2phys(struct target *target, target_addr_t virt, target_addr_t *phys) { uint32_t cb; struct arm920t_common *arm920t = target_to_arm920(target); uint32_t ret; int retval = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu, virt, &cb, &ret); if (retval != ERROR_OK) return retval; *phys = ret; return ERROR_OK; } /** Reads a buffer, in the specified word size, with current MMU settings. */ int arm920t_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; retval = arm7_9_read_memory(target, address, size, count, buffer); return retval; } static int arm920t_read_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct arm920t_common *arm920t = target_to_arm920(target); return armv4_5_mmu_read_physical(target, &arm920t->armv4_5_mmu, address, size, count, buffer); } static int arm920t_write_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct arm920t_common *arm920t = target_to_arm920(target); return armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, address, size, count, buffer); } /** Writes a buffer, in the specified word size, with current MMU settings. */ int arm920t_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; const uint32_t cache_mask = ~0x1f; /* cache line size : 32 byte */ struct arm920t_common *arm920t = target_to_arm920(target); /* FIX!!!! this should be cleaned up and made much more general. The * plan is to write up and test on arm920t specifically and * then generalize and clean up afterwards. * * Also it should be moved to the callbacks that handle breakpoints * specifically and not the generic memory write fn's. See XScale code. */ if (arm920t->armv4_5_mmu.mmu_enabled && (count == 1) && ((size == 2) || (size == 4))) { /* special case the handling of single word writes to * bypass MMU, to allow implementation of breakpoints * in memory marked read only * by MMU */ uint32_t cb; uint32_t pa; /* * We need physical address and cb */ retval = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu, address, &cb, &pa); if (retval != ERROR_OK) return retval; if (arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) { if (cb & 0x1) { LOG_DEBUG("D-Cache buffered, " "drain write buffer"); /* * Buffered ? * Drain write buffer - MCR p15,0,Rd,c7,c10,4 */ retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 10, 4), 0x0, 0); if (retval != ERROR_OK) return retval; } if (cb == 0x3) { /* * Write back memory ? -> clean cache * * There is no way to clean cache lines using * cp15 scan chain, so copy the full cache * line from cache to physical memory. */ uint8_t data[32]; LOG_DEBUG("D-Cache in 'write back' mode, " "flush cache line"); retval = target_read_memory(target, address & cache_mask, 1, sizeof(data), &data[0]); if (retval != ERROR_OK) return retval; retval = armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa & cache_mask, 1, sizeof(data), &data[0]); if (retval != ERROR_OK) return retval; } /* Cached ? */ if (cb & 0x2) { /* * Cached ? -> Invalidate data cache using MVA * * MCR p15,0,Rd,c7,c6,1 */ LOG_DEBUG("D-Cache enabled, " "invalidate cache line"); retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 6, 1), 0x0, address & cache_mask); if (retval != ERROR_OK) return retval; } } /* write directly to physical memory, * bypassing any read only MMU bits, etc. */ retval = armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa, size, count, buffer); if (retval != ERROR_OK) return retval; } else { retval = arm7_9_write_memory(target, address, size, count, buffer); if (retval != ERROR_OK) return retval; } /* If ICache is enabled, we have to invalidate affected ICache lines * the DCache is forced to write-through, * so we don't have to clean it here */ if (arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled) { if (count <= 1) { /* invalidate ICache single entry with MVA * mcr 15, 0, r0, cr7, cr5, {1} */ LOG_DEBUG("I-Cache enabled, " "invalidating affected I-Cache line"); retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 5, 1), 0x0, address & cache_mask); if (retval != ERROR_OK) return retval; } else { /* invalidate ICache * mcr 15, 0, r0, cr7, cr5, {0} */ retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0x0, 0x0); if (retval != ERROR_OK) return retval; } } return ERROR_OK; } /* EXPORTED to FA256 */ int arm920t_soft_reset_halt(struct target *target) { int retval = ERROR_OK; struct arm920t_common *arm920t = target_to_arm920(target); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; retval = target_halt(target); if (retval != ERROR_OK) return retval; int64_t then = timeval_ms(); bool timeout; while (!(timeout = ((timeval_ms()-then) > 1000))) { if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) { embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; } else break; if (debug_level >= 3) { /* do not eat all CPU, time out after 1 se*/ alive_sleep(100); } else keep_alive(); } if (timeout) { LOG_ERROR("Failed to halt CPU after 1 sec"); return ERROR_TARGET_TIMEOUT; } target->state = TARGET_HALTED; /* SVC, ARM state, IRQ and FIQ disabled */ uint32_t cpsr; cpsr = buf_get_u32(arm->cpsr->value, 0, 32); cpsr &= ~0xff; cpsr |= 0xd3; arm_set_cpsr(arm, cpsr); arm->cpsr->dirty = true; /* start fetching from 0x0 */ buf_set_u32(arm->pc->value, 0, 32, 0x0); arm->pc->dirty = true; arm->pc->valid = true; arm920t_disable_mmu_caches(target, 1, 1, 1); arm920t->armv4_5_mmu.mmu_enabled = 0; arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; return target_call_event_callbacks(target, TARGET_EVENT_HALTED); } /* FIXME remove forward decls */ static int arm920t_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value); static int arm920t_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value); static int arm920t_init_arch_info(struct target *target, struct arm920t_common *arm920t, struct jtag_tap *tap) { struct arm7_9_common *arm7_9 = &arm920t->arm7_9_common; arm7_9->arm.mrc = arm920t_mrc; arm7_9->arm.mcr = arm920t_mcr; /* initialize arm7/arm9 specific info (including armv4_5) */ arm9tdmi_init_arch_info(target, arm7_9, tap); arm920t->common_magic = ARM920T_COMMON_MAGIC; arm7_9->post_debug_entry = arm920t_post_debug_entry; arm7_9->pre_restore_context = arm920t_pre_restore_context; arm7_9->write_memory = arm920t_write_memory; arm920t->armv4_5_mmu.armv4_5_cache.ctype = -1; arm920t->armv4_5_mmu.get_ttb = arm920t_get_ttb; arm920t->armv4_5_mmu.read_memory = arm7_9_read_memory; arm920t->armv4_5_mmu.write_memory = arm7_9_write_memory; arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches; arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches; arm920t->armv4_5_mmu.has_tiny_pages = 1; arm920t->armv4_5_mmu.mmu_enabled = 0; /* disabling linefills leads to lockups, so keep them enabled for now * this doesn't affect correctness, but might affect timing issues, if * important data is evicted from the cache during the debug session * */ arm920t->preserve_cache = 0; /* override hw single-step capability from ARM9TDMI */ arm7_9->has_single_step = 1; return ERROR_OK; } static int arm920t_target_create(struct target *target, Jim_Interp *interp) { struct arm920t_common *arm920t; arm920t = calloc(1, sizeof(struct arm920t_common)); return arm920t_init_arch_info(target, arm920t, target->tap); } static void arm920t_deinit_target(struct target *target) { struct arm *arm = target_to_arm(target); struct arm920t_common *arm920t = target_to_arm920(target); arm7_9_deinit(target); arm_free_reg_cache(arm); free(arm920t); } COMMAND_HANDLER(arm920t_handle_read_cache_command) { int retval = ERROR_OK; struct target *target = get_current_target(CMD_CTX); struct arm920t_common *arm920t = target_to_arm920(target); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; uint32_t cp15c15; uint32_t cp15_ctrl, cp15_ctrl_saved; uint32_t regs[16]; uint32_t *regs_p[16]; uint32_t c15_c_d_ind, c15_c_i_ind; int i; FILE *output; int segment, index_t; struct reg *r; retval = arm920t_verify_pointer(CMD, arm920t); if (retval != ERROR_OK) return retval; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; output = fopen(CMD_ARGV[0], "w"); if (!output) { LOG_DEBUG("error opening cache content file"); return ERROR_OK; } for (i = 0; i < 16; i++) regs_p[i] = ®s[i]; /* disable MMU and Caches */ arm920t_read_cp15_physical(target, CP15PHYS_CTRL, &cp15_ctrl); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; cp15_ctrl_saved = cp15_ctrl; cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED); arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_ctrl); /* read CP15 test state register */ arm920t_read_cp15_physical(target, CP15PHYS_TESTSTATE, &cp15c15); jtag_execute_queue(); /* read DCache content */ fprintf(output, "DCache:\n"); /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */ for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++) { fprintf(output, "\nsegment: %i\n----------", segment); /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */ regs[0] = 0x0 | (segment << 5); arm9tdmi_write_core_regs(target, 0x1, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* D CAM Read, loads current victim into C15.C.D.Ind */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 2, 0, 15, 6, 2), ARMV4_5_LDR(1, 0)); /* read current victim */ arm920t_read_cp15_physical(target, CP15PHYS_DCACHE_IDX, &c15_c_d_ind); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); for (index_t = 0; index_t < 64; index_t++) { /* Ra: * r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ regs[0] = 0x0 | (segment << 5) | (index_t << 26); arm9tdmi_write_core_regs(target, 0x1, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write DCache victim */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 9, 1, 0), ARMV4_5_LDR(1, 0)); /* Read D RAM */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 2, 0, 15, 10, 2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0)); /* Read D CAM */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 2, 0, 15, 6, 2), ARMV4_5_LDR(9, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read D RAM and CAM content */ arm9tdmi_read_core_regs(target, 0x3fe, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* mask LFSR[6] */ regs[9] &= 0xfffffffe; fprintf(output, "\nsegment: %i, index: %i, CAM: 0x%8.8" PRIx32 ", content (%s):\n", segment, index_t, regs[9], (regs[9] & 0x10) ? "valid" : "invalid"); for (i = 1; i < 9; i++) { fprintf(output, "%i: 0x%8.8" PRIx32 "\n", i-1, regs[i]); } } /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ regs[0] = 0x0 | (segment << 5) | (c15_c_d_ind << 26); arm9tdmi_write_core_regs(target, 0x1, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write DCache victim */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 9, 1, 0), ARMV4_5_LDR(1, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); } /* read ICache content */ fprintf(output, "ICache:\n"); /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */ for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++) { fprintf(output, "segment: %i\n----------", segment); /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */ regs[0] = 0x0 | (segment << 5); arm9tdmi_write_core_regs(target, 0x1, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* I CAM Read, loads current victim into C15.C.I.Ind */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 2, 0, 15, 5, 2), ARMV4_5_LDR(1, 0)); /* read current victim */ arm920t_read_cp15_physical(target, CP15PHYS_ICACHE_IDX, &c15_c_i_ind); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); for (index_t = 0; index_t < 64; index_t++) { /* Ra: * r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ regs[0] = 0x0 | (segment << 5) | (index_t << 26); arm9tdmi_write_core_regs(target, 0x1, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write ICache victim */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 9, 1, 1), ARMV4_5_LDR(1, 0)); /* Read I RAM */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 2, 0, 15, 9, 2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0)); /* Read I CAM */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 2, 0, 15, 5, 2), ARMV4_5_LDR(9, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read I RAM and CAM content */ arm9tdmi_read_core_regs(target, 0x3fe, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* mask LFSR[6] */ regs[9] &= 0xfffffffe; fprintf(output, "\nsegment: %i, index: %i, " "CAM: 0x%8.8" PRIx32 ", content (%s):\n", segment, index_t, regs[9], (regs[9] & 0x10) ? "valid" : "invalid"); for (i = 1; i < 9; i++) { fprintf(output, "%i: 0x%8.8" PRIx32 "\n", i-1, regs[i]); } } /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ regs[0] = 0x0 | (segment << 5) | (c15_c_d_ind << 26); arm9tdmi_write_core_regs(target, 0x1, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write ICache victim */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 9, 1, 1), ARMV4_5_LDR(1, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); } /* restore CP15 MMU and Cache settings */ arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_ctrl_saved); command_print(CMD, "cache content successfully output to %s", CMD_ARGV[0]); fclose(output); if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } /* force writeback of the valid data */ r = arm->core_cache->reg_list; r[0].dirty = r[0].valid; r[1].dirty = r[1].valid; r[2].dirty = r[2].valid; r[3].dirty = r[3].valid; r[4].dirty = r[4].valid; r[5].dirty = r[5].valid; r[6].dirty = r[6].valid; r[7].dirty = r[7].valid; r = arm_reg_current(arm, 8); r->dirty = r->valid; r = arm_reg_current(arm, 9); r->dirty = r->valid; return ERROR_OK; } COMMAND_HANDLER(arm920t_handle_read_mmu_command) { int retval = ERROR_OK; struct target *target = get_current_target(CMD_CTX); struct arm920t_common *arm920t = target_to_arm920(target); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; uint32_t cp15c15; uint32_t cp15_ctrl, cp15_ctrl_saved; uint32_t regs[16]; uint32_t *regs_p[16]; int i; FILE *output; uint32_t d_lockdown, i_lockdown; struct arm920t_tlb_entry d_tlb[64], i_tlb[64]; int victim; struct reg *r; retval = arm920t_verify_pointer(CMD, arm920t); if (retval != ERROR_OK) return retval; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; output = fopen(CMD_ARGV[0], "w"); if (!output) { LOG_DEBUG("error opening mmu content file"); return ERROR_OK; } for (i = 0; i < 16; i++) regs_p[i] = ®s[i]; /* disable MMU and Caches */ arm920t_read_cp15_physical(target, CP15PHYS_CTRL, &cp15_ctrl); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; cp15_ctrl_saved = cp15_ctrl; cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED); arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_ctrl); /* read CP15 test state register */ arm920t_read_cp15_physical(target, CP15PHYS_TESTSTATE, &cp15c15); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* prepare reading D TLB content * */ /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Read D TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MRC(15, 0, 0, 10, 0, 0), ARMV4_5_LDR(1, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read D TLB lockdown stored to r1 */ arm9tdmi_read_core_regs(target, 0x2, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; d_lockdown = regs[1]; for (victim = 0; victim < 64; victim += 8) { /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] * base remains unchanged, victim goes through entries 0 to 63 */ regs[1] = (d_lockdown & 0xfc000000) | (victim << 20); arm9tdmi_write_core_regs(target, 0x2, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write D TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 10, 0, 0), ARMV4_5_STR(1, 0)); /* Read D TLB CAM */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 4, 0, 15, 6, 4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read D TLB CAM content stored to r2-r9 */ arm9tdmi_read_core_regs(target, 0x3fc, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; for (i = 0; i < 8; i++) d_tlb[victim + i].cam = regs[i + 2]; } for (victim = 0; victim < 64; victim++) { /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] * base remains unchanged, victim goes through entries 0 to 63 */ regs[1] = (d_lockdown & 0xfc000000) | (victim << 20); arm9tdmi_write_core_regs(target, 0x2, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write D TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 10, 0, 0), ARMV4_5_STR(1, 0)); /* Read D TLB RAM1 */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 4, 0, 15, 10, 4), ARMV4_5_LDR(2, 0)); /* Read D TLB RAM2 */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 4, 0, 15, 2, 5), ARMV4_5_LDR(3, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read D TLB RAM content stored to r2 and r3 */ arm9tdmi_read_core_regs(target, 0xc, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; d_tlb[victim].ram1 = regs[2]; d_tlb[victim].ram2 = regs[3]; } /* restore D TLB lockdown */ regs[1] = d_lockdown; arm9tdmi_write_core_regs(target, 0x2, regs); /* Write D TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 10, 0, 0), ARMV4_5_STR(1, 0)); /* prepare reading I TLB content * */ /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Read I TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MRC(15, 0, 0, 10, 0, 1), ARMV4_5_LDR(1, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read I TLB lockdown stored to r1 */ arm9tdmi_read_core_regs(target, 0x2, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; i_lockdown = regs[1]; for (victim = 0; victim < 64; victim += 8) { /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] * base remains unchanged, victim goes through entries 0 to 63 */ regs[1] = (i_lockdown & 0xfc000000) | (victim << 20); arm9tdmi_write_core_regs(target, 0x2, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write I TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 10, 0, 1), ARMV4_5_STR(1, 0)); /* Read I TLB CAM */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 4, 0, 15, 5, 4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read I TLB CAM content stored to r2-r9 */ arm9tdmi_read_core_regs(target, 0x3fc, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; for (i = 0; i < 8; i++) i_tlb[i + victim].cam = regs[i + 2]; } for (victim = 0; victim < 64; victim++) { /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] * base remains unchanged, victim goes through entries 0 to 63 */ regs[1] = (d_lockdown & 0xfc000000) | (victim << 20); arm9tdmi_write_core_regs(target, 0x2, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write I TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 10, 0, 1), ARMV4_5_STR(1, 0)); /* Read I TLB RAM1 */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 4, 0, 15, 9, 4), ARMV4_5_LDR(2, 0)); /* Read I TLB RAM2 */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 4, 0, 15, 1, 5), ARMV4_5_LDR(3, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read I TLB RAM content stored to r2 and r3 */ arm9tdmi_read_core_regs(target, 0xc, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; i_tlb[victim].ram1 = regs[2]; i_tlb[victim].ram2 = regs[3]; } /* restore I TLB lockdown */ regs[1] = i_lockdown; arm9tdmi_write_core_regs(target, 0x2, regs); /* Write I TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 10, 0, 1), ARMV4_5_STR(1, 0)); /* restore CP15 MMU and Cache settings */ arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_ctrl_saved); /* output data to file */ fprintf(output, "D TLB content:\n"); for (i = 0; i < 64; i++) { fprintf(output, "%i: 0x%8.8" PRIx32 " 0x%8.8" PRIx32 " 0x%8.8" PRIx32 " %s\n", i, d_tlb[i].cam, d_tlb[i].ram1, d_tlb[i].ram2, (d_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)"); } fprintf(output, "\n\nI TLB content:\n"); for (i = 0; i < 64; i++) { fprintf(output, "%i: 0x%8.8" PRIx32 " 0x%8.8" PRIx32 " 0x%8.8" PRIx32 " %s\n", i, i_tlb[i].cam, i_tlb[i].ram1, i_tlb[i].ram2, (i_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)"); } command_print(CMD, "mmu content successfully output to %s", CMD_ARGV[0]); fclose(output); if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } /* force writeback of the valid data */ r = arm->core_cache->reg_list; r[0].dirty = r[0].valid; r[1].dirty = r[1].valid; r[2].dirty = r[2].valid; r[3].dirty = r[3].valid; r[4].dirty = r[4].valid; r[5].dirty = r[5].valid; r[6].dirty = r[6].valid; r[7].dirty = r[7].valid; r = arm_reg_current(arm, 8); r->dirty = r->valid; r = arm_reg_current(arm, 9); r->dirty = r->valid; return ERROR_OK; } COMMAND_HANDLER(arm920t_handle_cp15_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct arm920t_common *arm920t = target_to_arm920(target); retval = arm920t_verify_pointer(CMD, arm920t); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD, "target must be stopped for " "\"%s\" command", CMD_NAME); return ERROR_OK; } /* one argument, read a register. * two arguments, write it. */ if (CMD_ARGC >= 1) { int address; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], address); if (CMD_ARGC == 1) { uint32_t value; retval = arm920t_read_cp15_physical(target, address, &value); if (retval != ERROR_OK) { command_print(CMD, "couldn't access reg %i", address); return ERROR_OK; } retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; command_print(CMD, "%i: %8.8" PRIx32, address, value); } else if (CMD_ARGC == 2) { uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); retval = arm920t_write_cp15_physical(target, address, value); if (retval != ERROR_OK) { command_print(CMD, "couldn't access reg %i", address); /* REVISIT why lie? "return retval"? */ return ERROR_OK; } command_print(CMD, "%i: %8.8" PRIx32, address, value); } } return ERROR_OK; } COMMAND_HANDLER(arm920t_handle_cache_info_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct arm920t_common *arm920t = target_to_arm920(target); retval = arm920t_verify_pointer(CMD, arm920t); if (retval != ERROR_OK) return retval; return armv4_5_handle_cache_info_command(CMD, &arm920t->armv4_5_mmu.armv4_5_cache); } static int arm920t_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } /* read "to" r0 */ return arm920t_read_cp15_interpreted(target, ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2), 0, value); } static int arm920t_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } /* write "from" r0 */ return arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2), 0, value); } static const struct command_registration arm920t_exec_command_handlers[] = { { .name = "cp15", .handler = arm920t_handle_cp15_command, .mode = COMMAND_EXEC, .help = "display/modify cp15 register", .usage = "regnum [value]", }, { .name = "cache_info", .handler = arm920t_handle_cache_info_command, .mode = COMMAND_EXEC, .usage = "", .help = "display information about target caches", }, { .name = "read_cache", .handler = arm920t_handle_read_cache_command, .mode = COMMAND_EXEC, .help = "dump I/D cache content to file", .usage = "filename", }, { .name = "read_mmu", .handler = arm920t_handle_read_mmu_command, .mode = COMMAND_EXEC, .help = "dump I/D mmu content to file", .usage = "filename", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm920t_command_handlers[] = { { .chain = arm9tdmi_command_handlers, }, { .name = "arm920t", .mode = COMMAND_ANY, .help = "arm920t command group", .usage = "", .chain = arm920t_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Holds methods for ARM920 targets. */ struct target_type arm920t_target = { .name = "arm920t", .poll = arm7_9_poll, .arch_state = arm920t_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm920t_soft_reset_halt, .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm920t_read_memory, .write_memory = arm7_9_write_memory_opt, .read_phys_memory = arm920t_read_phys_memory, .write_phys_memory = arm920t_write_phys_memory, .mmu = arm920_mmu, .virt2phys = arm920_virt2phys, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm920t_command_handlers, .target_create = arm920t_target_create, .init_target = arm9tdmi_init_target, .deinit_target = arm920t_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm920t.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM920T_H #define OPENOCD_TARGET_ARM920T_H #include "arm9tdmi.h" #include "armv4_5_mmu.h" #define ARM920T_COMMON_MAGIC 0xa920a920U struct arm920t_common { unsigned int common_magic; struct arm7_9_common arm7_9_common; struct armv4_5_mmu_common armv4_5_mmu; uint32_t cp15_control_reg; uint32_t d_fsr; uint32_t i_fsr; uint32_t d_far; uint32_t i_far; int preserve_cache; }; static inline struct arm920t_common *target_to_arm920(struct target *target) { return container_of(target->arch_info, struct arm920t_common, arm7_9_common.arm); } struct arm920t_cache_line { uint32_t cam; uint32_t data[8]; }; struct arm920t_tlb_entry { uint32_t cam; uint32_t ram1; uint32_t ram2; }; int arm920t_arch_state(struct target *target); int arm920t_soft_reset_halt(struct target *target); int arm920t_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); int arm920t_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int arm920t_post_debug_entry(struct target *target); void arm920t_pre_restore_context(struct target *target); int arm920t_get_ttb(struct target *target, uint32_t *result); int arm920t_disable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache); int arm920t_enable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache); extern const struct command_registration arm920t_command_handlers[]; #endif /* OPENOCD_TARGET_ARM920T_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm926ejs.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008,2009 by Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm926ejs.h" #include <helper/time_support.h> #include "target_type.h" #include "register.h" #include "arm_opcodes.h" /* * The ARM926 is built around the ARM9EJ-S core, and most JTAG docs * are in the ARM9EJ-S Technical Reference Manual (ARM DDI 0222B) not * the ARM926 manual (ARM DDI 0198E). The scan chains are: * * 1 ... core debugging * 2 ... EmbeddedICE * 3 ... external boundary scan (SoC-specific, unused here) * 6 ... ETM * 15 ... coprocessor 15 */ #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif #define ARM926EJS_CP15_ADDR(opcode_1, opcode_2, crn, crm) ((opcode_1 << 11) | (opcode_2 << 8) | (crn << 4) | (crm << 0)) static int arm926ejs_cp15_read(struct target *target, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; uint32_t address = ARM926EJS_CP15_ADDR(op1, op2, crn, crm); struct scan_field fields[4]; uint8_t address_buf[2] = {0, 0}; uint8_t nr_w_buf = 0; uint8_t access_t = 1; buf_set_u32(address_buf, 0, 14, address); retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = (uint8_t *)value; fields[1].num_bits = 1; fields[1].out_value = &access_t; fields[1].in_value = &access_t; fields[2].num_bits = 14; fields[2].out_value = address_buf; fields[2].in_value = NULL; fields[3].num_bits = 1; fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); int64_t then = timeval_ms(); for (;;) { /* rescan with NOP, to wait for the access to complete */ access_t = 0; nr_w_buf = 0; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (buf_get_u32(&access_t, 0, 1) == 1) break; /* 10ms timeout */ if ((timeval_ms()-then) > 10) { LOG_ERROR("cp15 read operation timed out"); return ERROR_FAIL; } } #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("addr: 0x%x value: %8.8x", address, *value); #endif retval = arm_jtag_set_instr(jtag_info->tap, 0xc, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int arm926ejs_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } return arm926ejs_cp15_read(target, op1, op2, crn, crm, value); } static int arm926ejs_cp15_write(struct target *target, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; uint32_t address = ARM926EJS_CP15_ADDR(op1, op2, crn, crm); struct scan_field fields[4]; uint8_t value_buf[4]; uint8_t address_buf[2] = {0, 0}; uint8_t nr_w_buf = 1; uint8_t access_t = 1; buf_set_u32(address_buf, 0, 14, address); buf_set_u32(value_buf, 0, 32, value); retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = value_buf; fields[0].in_value = NULL; fields[1].num_bits = 1; fields[1].out_value = &access_t; fields[1].in_value = &access_t; fields[2].num_bits = 14; fields[2].out_value = address_buf; fields[2].in_value = NULL; fields[3].num_bits = 1; fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); int64_t then = timeval_ms(); for (;;) { /* rescan with NOP, to wait for the access to complete */ access_t = 0; nr_w_buf = 0; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (buf_get_u32(&access_t, 0, 1) == 1) break; /* 10ms timeout */ if ((timeval_ms()-then) > 10) { LOG_ERROR("cp15 write operation timed out"); return ERROR_FAIL; } } #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("addr: 0x%x value: %8.8x", address, value); #endif retval = arm_jtag_set_instr(jtag_info->tap, 0xf, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int arm926ejs_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } return arm926ejs_cp15_write(target, op1, op2, crn, crm, value); } static int arm926ejs_examine_debug_reason(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; int debug_reason; int retval; embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* Method-Of-Entry (MOE) field */ debug_reason = buf_get_u32(dbg_stat->value, 6, 4); switch (debug_reason) { case 0: LOG_DEBUG("no *NEW* debug entry (?missed one?)"); /* ... since last restart or debug reset ... */ target->debug_reason = DBG_REASON_DBGRQ; break; case 1: LOG_DEBUG("breakpoint from EICE unit 0"); target->debug_reason = DBG_REASON_BREAKPOINT; break; case 2: LOG_DEBUG("breakpoint from EICE unit 1"); target->debug_reason = DBG_REASON_BREAKPOINT; break; case 3: LOG_DEBUG("soft breakpoint (BKPT instruction)"); target->debug_reason = DBG_REASON_BREAKPOINT; break; case 4: LOG_DEBUG("vector catch breakpoint"); target->debug_reason = DBG_REASON_BREAKPOINT; break; case 5: LOG_DEBUG("external breakpoint"); target->debug_reason = DBG_REASON_BREAKPOINT; break; case 6: LOG_DEBUG("watchpoint from EICE unit 0"); target->debug_reason = DBG_REASON_WATCHPOINT; break; case 7: LOG_DEBUG("watchpoint from EICE unit 1"); target->debug_reason = DBG_REASON_WATCHPOINT; break; case 8: LOG_DEBUG("external watchpoint"); target->debug_reason = DBG_REASON_WATCHPOINT; break; case 9: LOG_DEBUG("internal debug request"); target->debug_reason = DBG_REASON_DBGRQ; break; case 10: LOG_DEBUG("external debug request"); target->debug_reason = DBG_REASON_DBGRQ; break; case 11: LOG_DEBUG("debug re-entry from system speed access"); /* This is normal when connecting to something that's * already halted, or in some related code paths, but * otherwise is surprising (and presumably wrong). */ switch (target->debug_reason) { case DBG_REASON_DBGRQ: break; default: LOG_ERROR("unexpected -- debug re-entry"); /* FALLTHROUGH */ case DBG_REASON_UNDEFINED: target->debug_reason = DBG_REASON_DBGRQ; break; } break; case 12: /* FIX!!!! here be dragons!!! We need to fail here so * the target will interpreted as halted but we won't * try to talk to it right now... a resume + halt seems * to sync things up again. Please send an email to * openocd development mailing list if you have hardware * to donate to look into this problem.... */ LOG_WARNING("WARNING: mystery debug reason MOE = 0xc. Try issuing a resume + halt."); target->debug_reason = DBG_REASON_DBGRQ; break; default: LOG_WARNING("WARNING: unknown debug reason: 0x%x", debug_reason); /* Oh agony! should we interpret this as a halt request or * that the target stopped on it's own accord? */ target->debug_reason = DBG_REASON_DBGRQ; /* if we fail here, we won't talk to the target and it will * be reported to be in the halted state */ break; } return ERROR_OK; } static int arm926ejs_get_ttb(struct target *target, uint32_t *result) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); int retval; uint32_t ttb = 0x0; retval = arm926ejs->read_cp15(target, 0, 0, 2, 0, &ttb); if (retval != ERROR_OK) return retval; *result = ttb; return ERROR_OK; } static int arm926ejs_disable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); uint32_t cp15_control; int retval; /* read cp15 control register */ retval = arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (mmu) { /* invalidate TLB */ retval = arm926ejs->write_cp15(target, 0, 0, 8, 7, 0x0); if (retval != ERROR_OK) return retval; cp15_control &= ~0x1U; } if (d_u_cache) { uint32_t debug_override; /* read-modify-write CP15 debug override register * to enable "test and clean all" */ retval = arm926ejs->read_cp15(target, 0, 0, 15, 0, &debug_override); if (retval != ERROR_OK) return retval; debug_override |= 0x80000; retval = arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override); if (retval != ERROR_OK) return retval; /* clean and invalidate DCache */ retval = arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0); if (retval != ERROR_OK) return retval; /* write CP15 debug override register * to disable "test and clean all" */ debug_override &= ~0x80000; retval = arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override); if (retval != ERROR_OK) return retval; cp15_control &= ~0x4U; } if (i_cache) { /* invalidate ICache */ retval = arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0); if (retval != ERROR_OK) return retval; cp15_control &= ~0x1000U; } retval = arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); return retval; } static int arm926ejs_enable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); uint32_t cp15_control; int retval; /* read cp15 control register */ retval = arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (mmu) cp15_control |= 0x1U; if (d_u_cache) cp15_control |= 0x4U; if (i_cache) cp15_control |= 0x1000U; retval = arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); return retval; } static int arm926ejs_post_debug_entry(struct target *target) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); int retval; /* examine cp15 control reg */ retval = arm926ejs->read_cp15(target, 0, 0, 1, 0, &arm926ejs->cp15_control_reg); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; LOG_DEBUG("cp15_control_reg: %8.8" PRIx32 "", arm926ejs->cp15_control_reg); if (arm926ejs->armv4_5_mmu.armv4_5_cache.ctype == -1) { uint32_t cache_type_reg; /* identify caches */ retval = arm926ejs->read_cp15(target, 0, 1, 0, 0, &cache_type_reg); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; armv4_5_identify_cache(cache_type_reg, &arm926ejs->armv4_5_mmu.armv4_5_cache); } arm926ejs->armv4_5_mmu.mmu_enabled = (arm926ejs->cp15_control_reg & 0x1U) ? 1 : 0; arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm926ejs->cp15_control_reg & 0x4U) ? 1 : 0; arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm926ejs->cp15_control_reg & 0x1000U) ? 1 : 0; /* save i/d fault status and address register */ retval = arm926ejs->read_cp15(target, 0, 0, 5, 0, &arm926ejs->d_fsr); if (retval != ERROR_OK) return retval; retval = arm926ejs->read_cp15(target, 0, 1, 5, 0, &arm926ejs->i_fsr); if (retval != ERROR_OK) return retval; retval = arm926ejs->read_cp15(target, 0, 0, 6, 0, &arm926ejs->d_far); if (retval != ERROR_OK) return retval; LOG_DEBUG("D FSR: 0x%8.8" PRIx32 ", D FAR: 0x%8.8" PRIx32 ", I FSR: 0x%8.8" PRIx32 "", arm926ejs->d_fsr, arm926ejs->d_far, arm926ejs->i_fsr); uint32_t cache_dbg_ctrl; /* read-modify-write CP15 cache debug control register * to disable I/D-cache linefills and force WT */ retval = arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl); if (retval != ERROR_OK) return retval; cache_dbg_ctrl |= 0x7; retval = arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); return retval; } static void arm926ejs_pre_restore_context(struct target *target) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); /* restore i/d fault status and address register */ arm926ejs->write_cp15(target, 0, 0, 5, 0, arm926ejs->d_fsr); arm926ejs->write_cp15(target, 0, 1, 5, 0, arm926ejs->i_fsr); arm926ejs->write_cp15(target, 0, 0, 6, 0, arm926ejs->d_far); uint32_t cache_dbg_ctrl; /* read-modify-write CP15 cache debug control register * to reenable I/D-cache linefills and disable WT */ arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl); cache_dbg_ctrl &= ~0x7; arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); } static const char arm926_not[] = "target is not an ARM926"; static int arm926ejs_verify_pointer(struct command_invocation *cmd, struct arm926ejs_common *arm926) { if (arm926->common_magic != ARM926EJS_COMMON_MAGIC) { command_print(cmd, arm926_not); return ERROR_TARGET_INVALID; } return ERROR_OK; } /** Logs summary of ARM926 state for a halted target. */ int arm926ejs_arch_state(struct target *target) { static const char *state[] = { "disabled", "enabled" }; struct arm926ejs_common *arm926ejs = target_to_arm926(target); if (arm926ejs->common_magic != ARM926EJS_COMMON_MAGIC) { LOG_ERROR("BUG: %s", arm926_not); return ERROR_TARGET_INVALID; } arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", state[arm926ejs->armv4_5_mmu.mmu_enabled], state[arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], state[arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); return ERROR_OK; } int arm926ejs_soft_reset_halt(struct target *target) { int retval = ERROR_OK; struct arm926ejs_common *arm926ejs = target_to_arm926(target); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; retval = target_halt(target); if (retval != ERROR_OK) return retval; int64_t then = timeval_ms(); int timeout; while (!(timeout = ((timeval_ms()-then) > 1000))) { if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) { embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; } else break; if (debug_level >= 1) { /* do not eat all CPU, time out after 1 se*/ alive_sleep(100); } else keep_alive(); } if (timeout) { LOG_ERROR("Failed to halt CPU after 1 sec"); return ERROR_TARGET_TIMEOUT; } target->state = TARGET_HALTED; /* SVC, ARM state, IRQ and FIQ disabled */ uint32_t cpsr; cpsr = buf_get_u32(arm->cpsr->value, 0, 32); cpsr &= ~0xff; cpsr |= 0xd3; arm_set_cpsr(arm, cpsr); arm->cpsr->dirty = true; /* start fetching from 0x0 */ buf_set_u32(arm->pc->value, 0, 32, 0x0); arm->pc->dirty = true; arm->pc->valid = true; retval = arm926ejs_disable_mmu_caches(target, 1, 1, 1); if (retval != ERROR_OK) return retval; arm926ejs->armv4_5_mmu.mmu_enabled = 0; arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; return target_call_event_callbacks(target, TARGET_EVENT_HALTED); } /** Writes a buffer, in the specified word size, with current MMU settings. */ int arm926ejs_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; struct arm926ejs_common *arm926ejs = target_to_arm926(target); /* FIX!!!! this should be cleaned up and made much more general. The * plan is to write up and test on arm926ejs specifically and * then generalize and clean up afterwards. * * * Also it should be moved to the callbacks that handle breakpoints * specifically and not the generic memory write fn's. See XScale code. **/ if (arm926ejs->armv4_5_mmu.mmu_enabled && (count == 1) && ((size == 2) || (size == 4))) { /* special case the handling of single word writes to bypass MMU * to allow implementation of breakpoints in memory marked read only * by MMU */ if (arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) { /* flush and invalidate data cache * * MCR p15,0,p,c7,c10,1 - clean cache line using virtual address * */ retval = arm926ejs->write_cp15(target, 0, 1, 7, 10, address&~0x3); if (retval != ERROR_OK) return retval; } target_addr_t pa; retval = target->type->virt2phys(target, address, &pa); if (retval != ERROR_OK) return retval; /* write directly to physical memory bypassing any read only MMU bits, etc. */ retval = armv4_5_mmu_write_physical(target, &arm926ejs->armv4_5_mmu, pa, size, count, buffer); if (retval != ERROR_OK) return retval; } else { retval = arm7_9_write_memory(target, address, size, count, buffer); if (retval != ERROR_OK) return retval; } /* If ICache is enabled, we have to invalidate affected ICache lines * the DCache is forced to write-through, so we don't have to clean it here */ if (arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled) { if (count <= 1) { /* invalidate ICache single entry with MVA */ arm926ejs->write_cp15(target, 0, 1, 7, 5, address); } else { /* invalidate ICache */ arm926ejs->write_cp15(target, 0, 0, 7, 5, address); } } return retval; } static int arm926ejs_write_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); return armv4_5_mmu_write_physical(target, &arm926ejs->armv4_5_mmu, address, size, count, buffer); } static int arm926ejs_read_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); return armv4_5_mmu_read_physical(target, &arm926ejs->armv4_5_mmu, address, size, count, buffer); } int arm926ejs_init_arch_info(struct target *target, struct arm926ejs_common *arm926ejs, struct jtag_tap *tap) { struct arm7_9_common *arm7_9 = &arm926ejs->arm7_9_common; arm7_9->arm.mrc = arm926ejs_mrc; arm7_9->arm.mcr = arm926ejs_mcr; /* initialize arm7/arm9 specific info (including armv4_5) */ arm9tdmi_init_arch_info(target, arm7_9, tap); arm926ejs->common_magic = ARM926EJS_COMMON_MAGIC; arm7_9->post_debug_entry = arm926ejs_post_debug_entry; arm7_9->pre_restore_context = arm926ejs_pre_restore_context; arm7_9->write_memory = arm926ejs_write_memory; arm926ejs->read_cp15 = arm926ejs_cp15_read; arm926ejs->write_cp15 = arm926ejs_cp15_write; arm926ejs->armv4_5_mmu.armv4_5_cache.ctype = -1; arm926ejs->armv4_5_mmu.get_ttb = arm926ejs_get_ttb; arm926ejs->armv4_5_mmu.read_memory = arm7_9_read_memory; arm926ejs->armv4_5_mmu.write_memory = arm7_9_write_memory; arm926ejs->armv4_5_mmu.disable_mmu_caches = arm926ejs_disable_mmu_caches; arm926ejs->armv4_5_mmu.enable_mmu_caches = arm926ejs_enable_mmu_caches; arm926ejs->armv4_5_mmu.has_tiny_pages = 1; arm926ejs->armv4_5_mmu.mmu_enabled = 0; arm7_9->examine_debug_reason = arm926ejs_examine_debug_reason; /* The ARM926EJ-S implements the ARMv5TE architecture which * has the BKPT instruction, so we don't have to use a watchpoint comparator */ arm7_9->arm_bkpt = ARMV5_BKPT(0x0); arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; return ERROR_OK; } static int arm926ejs_target_create(struct target *target, Jim_Interp *interp) { struct arm926ejs_common *arm926ejs = calloc(1, sizeof(struct arm926ejs_common)); /* ARM9EJ-S core always reports 0x1 in Capture-IR */ target->tap->ir_capture_mask = 0x0f; return arm926ejs_init_arch_info(target, arm926ejs, target->tap); } static void arm926ejs_deinit_target(struct target *target) { struct arm *arm = target_to_arm(target); struct arm926ejs_common *arm926ejs = target_to_arm926(target); arm7_9_deinit(target); arm_free_reg_cache(arm); free(arm926ejs); } COMMAND_HANDLER(arm926ejs_handle_cache_info_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct arm926ejs_common *arm926ejs = target_to_arm926(target); retval = arm926ejs_verify_pointer(CMD, arm926ejs); if (retval != ERROR_OK) return retval; return armv4_5_handle_cache_info_command(CMD, &arm926ejs->armv4_5_mmu.armv4_5_cache); } static int arm926ejs_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical) { uint32_t cb; struct arm926ejs_common *arm926ejs = target_to_arm926(target); uint32_t ret; int retval = armv4_5_mmu_translate_va(target, &arm926ejs->armv4_5_mmu, virtual, &cb, &ret); if (retval != ERROR_OK) return retval; *physical = ret; return ERROR_OK; } static int arm926ejs_mmu(struct target *target, int *enabled) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_INVALID; } *enabled = arm926ejs->armv4_5_mmu.mmu_enabled; return ERROR_OK; } static const struct command_registration arm926ejs_exec_command_handlers[] = { { .name = "cache_info", .handler = arm926ejs_handle_cache_info_command, .mode = COMMAND_EXEC, .usage = "", .help = "display information about target caches", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm926ejs_command_handlers[] = { { .chain = arm9tdmi_command_handlers, }, { .name = "arm926ejs", .mode = COMMAND_ANY, .help = "arm926ejs command group", .usage = "", .chain = arm926ejs_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Holds methods for ARM926 targets. */ struct target_type arm926ejs_target = { .name = "arm926ejs", .poll = arm7_9_poll, .arch_state = arm926ejs_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm926ejs_soft_reset_halt, .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm7_9_read_memory, .write_memory = arm7_9_write_memory_opt, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm926ejs_command_handlers, .target_create = arm926ejs_target_create, .init_target = arm9tdmi_init_target, .deinit_target = arm926ejs_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, .virt2phys = arm926ejs_virt2phys, .mmu = arm926ejs_mmu, .read_phys_memory = arm926ejs_read_phys_memory, .write_phys_memory = arm926ejs_write_phys_memory, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm926ejs.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM926EJS_H #define OPENOCD_TARGET_ARM926EJS_H #include "arm9tdmi.h" #include "armv4_5_mmu.h" #define ARM926EJS_COMMON_MAGIC 0xa926a926U struct arm926ejs_common { unsigned int common_magic; struct arm7_9_common arm7_9_common; struct armv4_5_mmu_common armv4_5_mmu; int (*read_cp15)(struct target *target, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value); int (*write_cp15)(struct target *target, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value); uint32_t cp15_control_reg; uint32_t d_fsr; uint32_t i_fsr; uint32_t d_far; }; static inline struct arm926ejs_common *target_to_arm926(struct target *target) { return container_of(target->arch_info, struct arm926ejs_common, arm7_9_common.arm); } int arm926ejs_init_arch_info(struct target *target, struct arm926ejs_common *arm926ejs, struct jtag_tap *tap); int arm926ejs_arch_state(struct target *target); int arm926ejs_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int arm926ejs_soft_reset_halt(struct target *target); extern const struct command_registration arm926ejs_command_handlers[]; #endif /* OPENOCD_TARGET_ARM926EJS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm946e.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2010 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm946e.h" #include "target_type.h" #include "arm_opcodes.h" #include "breakpoints.h" #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif #define NB_CACHE_WAYS 4 #define CP15_CTL 0x02 #define CP15_CTL_DCACHE (1<<2) #define CP15_CTL_ICACHE (1<<12) /** * flag to give info about cache manipulation during debug : * "0" - cache lines are invalidated "on the fly", for affected addresses. * This is preferred from performance point of view. * "1" - cache is invalidated and switched off on debug_entry, and switched back on on restore. * It is kept off during debugging. */ static uint8_t arm946e_preserve_cache; static int arm946e_post_debug_entry(struct target *target); static void arm946e_pre_restore_context(struct target *target); static int arm946e_read_cp15(struct target *target, int reg_addr, uint32_t *value); static int arm946e_init_arch_info(struct target *target, struct arm946e_common *arm946e, struct jtag_tap *tap) { struct arm7_9_common *arm7_9 = &arm946e->arm7_9_common; /* initialize arm7/arm9 specific info (including armv4_5) */ arm9tdmi_init_arch_info(target, arm7_9, tap); arm946e->common_magic = ARM946E_COMMON_MAGIC; /** * The ARM946E-S implements the ARMv5TE architecture which * has the BKPT instruction, so we don't have to use a watchpoint comparator */ arm7_9->arm_bkpt = ARMV5_BKPT(0x0); arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; arm7_9->post_debug_entry = arm946e_post_debug_entry; arm7_9->pre_restore_context = arm946e_pre_restore_context; /** * disabling linefills leads to lockups, so keep them enabled for now * this doesn't affect correctness, but might affect timing issues, if * important data is evicted from the cache during the debug session */ arm946e_preserve_cache = 0; /* override hw single-step capability from ARM9TDMI */ /* arm7_9->has_single_step = 1; */ return ERROR_OK; } static int arm946e_target_create(struct target *target, Jim_Interp *interp) { struct arm946e_common *arm946e = calloc(1, sizeof(struct arm946e_common)); arm946e_init_arch_info(target, arm946e, target->tap); return ERROR_OK; } static void arm946e_deinit_target(struct target *target) { struct arm *arm = target_to_arm(target); struct arm946e_common *arm946e = target_to_arm946(target); arm7_9_deinit(target); arm_free_reg_cache(arm); free(arm946e); } static int arm946e_verify_pointer(struct command_invocation *cmd, struct arm946e_common *arm946e) { if (arm946e->common_magic != ARM946E_COMMON_MAGIC) { command_print(cmd, "target is not an ARM946"); return ERROR_TARGET_INVALID; } return ERROR_OK; } /* * Update cp15_control_reg, saved on debug_entry. */ static void arm946e_update_cp15_caches(struct target *target, uint32_t value) { struct arm946e_common *arm946e = target_to_arm946(target); arm946e->cp15_control_reg = (arm946e->cp15_control_reg & ~(CP15_CTL_DCACHE|CP15_CTL_ICACHE)) | (value & (CP15_CTL_DCACHE|CP15_CTL_ICACHE)); } /* * REVISIT: The "read_cp15" and "write_cp15" commands could hook up * to eventual mrc() and mcr() routines ... the reg_addr values being * constructed (for CP15 only) from Opcode_1, Opcode_2, and CRn values. * See section 7.3 of the ARM946E-S TRM. */ static int arm946e_read_cp15(struct target *target, int reg_addr, uint32_t *value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct scan_field fields[3]; uint8_t reg_addr_buf = reg_addr & 0x3f; uint8_t nr_w_buf = 0; retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; /* REVISIT: table 7-2 shows that bits 31-31 need to be * specified for accessing BIST registers ... */ fields[0].out_value = NULL; fields[0].in_value = NULL; fields[1].num_bits = 6; fields[1].out_value = ®_addr_buf; fields[1].in_value = NULL; fields[2].num_bits = 1; fields[2].out_value = &nr_w_buf; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); fields[0].in_value = (uint8_t *)value; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); #endif retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int arm946e_write_cp15(struct target *target, int reg_addr, uint32_t value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct scan_field fields[3]; uint8_t reg_addr_buf = reg_addr & 0x3f; uint8_t nr_w_buf = 1; uint8_t value_buf[4]; buf_set_u32(value_buf, 0, 32, value); retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = value_buf; fields[0].in_value = NULL; fields[1].num_bits = 6; fields[1].out_value = ®_addr_buf; fields[1].in_value = NULL; fields[2].num_bits = 1; fields[2].out_value = &nr_w_buf; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); #endif retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; return ERROR_OK; } #define GET_ICACHE_SIZE 6 #define GET_DCACHE_SIZE 18 /* * \param target struct target pointer * \param idsel select GET_ICACHE_SIZE or GET_DCACHE_SIZE * \returns cache size, given in bytes */ static uint32_t arm946e_cp15_get_csize(struct target *target, int idsel) { struct arm946e_common *arm946e = target_to_arm946(target); uint32_t csize = arm946e->cp15_cache_info; if (csize == 0) { if (arm946e_read_cp15(target, 0x01, &csize) == ERROR_OK) arm946e->cp15_cache_info = csize; } if (csize & (1<<(idsel-4))) /* cache absent */ return 0; csize = (csize >> idsel) & 0x0F; return csize ? 1 << (12 + (csize-3)) : 0; } static uint32_t arm946e_invalidate_whole_dcache(struct target *target) { uint32_t csize = arm946e_cp15_get_csize(target, GET_DCACHE_SIZE); if (csize == 0) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* One line (index) is 32 bytes (8 words) long, 4-way assoc * ARM DDI 0201D, Section 3.3.5 */ int nb_idx = (csize / (4*8*NB_CACHE_WAYS)); /* gives nb of lines (indexes) in the cache */ /* Loop for all segments (i.e. ways) */ uint32_t seg; for (seg = 0; seg < NB_CACHE_WAYS; seg++) { /* Loop for all indexes */ int idx; for (idx = 0; idx < nb_idx; idx++) { /* Form and write cp15 index (segment + line idx) */ uint32_t cp15_idx = seg << 30 | idx << 5; int retval = arm946e_write_cp15(target, 0x3a, cp15_idx); if (retval != ERROR_OK) { LOG_DEBUG("ERROR writing index"); return retval; } /* Read dtag */ uint32_t dtag; retval = arm946e_read_cp15(target, 0x16, &dtag); if (retval != ERROR_OK) { LOG_DEBUG("ERROR reading dtag"); return retval; } /* Check cache line VALID bit */ if (!(dtag >> 4 & 0x1)) continue; /* Clean data cache line */ retval = arm946e_write_cp15(target, 0x35, 0x1); if (retval != ERROR_OK) { LOG_DEBUG("ERROR cleaning cache line"); return retval; } /* Flush data cache line */ retval = arm946e_write_cp15(target, 0x1a, 0x1); if (retval != ERROR_OK) { LOG_DEBUG("ERROR flushing cache line"); return retval; } } } return ERROR_OK; } static uint32_t arm946e_invalidate_whole_icache(struct target *target) { /* Check cache presence before flushing - avoid undefined behavior */ uint32_t csize = arm946e_cp15_get_csize(target, GET_ICACHE_SIZE); if (csize == 0) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; LOG_DEBUG("FLUSHING I$"); /** * Invalidate (flush) I$ * mcr 15, 0, r0, cr7, cr5, {0} */ int retval = arm946e_write_cp15(target, 0x0f, 0x1); if (retval != ERROR_OK) { LOG_DEBUG("ERROR flushing I$"); return retval; } return ERROR_OK; } static int arm946e_post_debug_entry(struct target *target) { uint32_t ctr_reg = 0x0; uint32_t retval = ERROR_OK; struct arm946e_common *arm946e = target_to_arm946(target); /* See if CACHES are enabled, and save that info * in the context bits, so that arm946e_pre_restore_context() can use them */ arm946e_read_cp15(target, CP15_CTL, &ctr_reg); /* Save control reg in the context */ arm946e->cp15_control_reg = ctr_reg; if (arm946e_preserve_cache) { if (ctr_reg & CP15_CTL_DCACHE) { /* Clean and flush D$ */ arm946e_invalidate_whole_dcache(target); /* Disable D$ */ ctr_reg &= ~CP15_CTL_DCACHE; } if (ctr_reg & CP15_CTL_ICACHE) { /* Flush I$ */ arm946e_invalidate_whole_icache(target); /* Disable I$ */ ctr_reg &= ~CP15_CTL_ICACHE; } /* Write the new configuration */ retval = arm946e_write_cp15(target, CP15_CTL, ctr_reg); if (retval != ERROR_OK) { LOG_DEBUG("ERROR disabling cache"); return retval; } } /* if preserve_cache */ return ERROR_OK; } static void arm946e_pre_restore_context(struct target *target) { uint32_t ctr_reg = 0x0; uint32_t retval; if (arm946e_preserve_cache) { struct arm946e_common *arm946e = target_to_arm946(target); /* Get the contents of the CTR reg */ arm946e_read_cp15(target, CP15_CTL, &ctr_reg); /** * Read-modify-write CP15 control * to reenable I/D-cache operation * NOTE: It is not possible to disable cache by CP15. * if arm946e_preserve_cache debugging flag enabled. */ ctr_reg |= arm946e->cp15_control_reg & (CP15_CTL_DCACHE|CP15_CTL_ICACHE); /* Write the new configuration */ retval = arm946e_write_cp15(target, CP15_CTL, ctr_reg); if (retval != ERROR_OK) LOG_DEBUG("ERROR enabling cache"); } /* if preserve_cache */ } static uint32_t arm946e_invalidate_dcache(struct target *target, uint32_t address, uint32_t size, uint32_t count) { uint32_t cur_addr = 0x0; uint32_t cp15_idx, set, way, dtag; uint32_t i = 0; int retval; for (i = 0; i < count*size; i++) { cur_addr = address + i; set = (cur_addr >> 5) & 0xff; /* set field is 8 bits long */ for (way = 0; way < NB_CACHE_WAYS; way++) { /** * Find if the affected address is kept in the cache. * Because JTAG Scan Chain 15 offers limited approach, * we have to loop through all cache ways (segments) and * read cache tags, then compare them with with address. */ /* Form and write cp15 index (segment + line idx) */ cp15_idx = way << 30 | set << 5; retval = arm946e_write_cp15(target, 0x3a, cp15_idx); if (retval != ERROR_OK) { LOG_DEBUG("ERROR writing index"); return retval; } /* Read dtag */ retval = arm946e_read_cp15(target, 0x16, &dtag); if (retval != ERROR_OK) { LOG_DEBUG("ERROR reading dtag"); return retval; } /* Check cache line VALID bit */ if (!(dtag >> 4 & 0x1)) continue; /* If line is valid and corresponds to affected address - invalidate it */ if (dtag >> 5 == cur_addr >> 5) { /* Clean data cache line */ retval = arm946e_write_cp15(target, 0x35, 0x1); if (retval != ERROR_OK) { LOG_DEBUG("ERROR cleaning cache line"); return retval; } /* Flush data cache line */ retval = arm946e_write_cp15(target, 0x1c, 0x1); if (retval != ERROR_OK) { LOG_DEBUG("ERROR flushing cache line"); return retval; } break; } } /* loop through all 4 ways */ } /* loop through all addresses */ return ERROR_OK; } static uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address, uint32_t size, uint32_t count) { uint32_t cur_addr = 0x0; uint32_t cp15_idx, set, way, itag; uint32_t i = 0; int retval; for (i = 0; i < count*size; i++) { cur_addr = address + i; set = (cur_addr >> 5) & 0xff; /* set field is 8 bits long */ for (way = 0; way < NB_CACHE_WAYS; way++) { /* Form and write cp15 index (segment + line idx) */ cp15_idx = way << 30 | set << 5; retval = arm946e_write_cp15(target, 0x3a, cp15_idx); if (retval != ERROR_OK) { LOG_DEBUG("ERROR writing index"); return retval; } /* Read itag */ retval = arm946e_read_cp15(target, 0x17, &itag); if (retval != ERROR_OK) { LOG_DEBUG("ERROR reading itag"); return retval; } /* Check cache line VALID bit */ if (!(itag >> 4 & 0x1)) continue; /* If line is valid and corresponds to affected address - invalidate it */ if (itag >> 5 == cur_addr >> 5) { /* Flush I$ line */ retval = arm946e_write_cp15(target, 0x1d, 0x0); if (retval != ERROR_OK) { LOG_DEBUG("ERROR flushing cache line"); return retval; } break; } } /* way loop */ } /* addr loop */ return ERROR_OK; } /** Writes a buffer, in the specified word size, with current MMU settings. */ static int arm946e_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; LOG_DEBUG("-"); struct arm946e_common *arm946e = target_to_arm946(target); /* Invalidate D$ if it is ON */ if (!arm946e_preserve_cache && (arm946e->cp15_control_reg & CP15_CTL_DCACHE)) arm946e_invalidate_dcache(target, address, size, count); /** * Write memory */ retval = arm7_9_write_memory_opt(target, address, size, count, buffer); if (retval != ERROR_OK) return retval; /* * * Invalidate I$ if it is ON. * * D$ has been cleaned and flushed before mem write thus forcing it to behave like write-through, * because arm7_9_write_memory() has seen non-valid bit in D$ * and wrote data into physical RAM (without touching or allocating the cache line). * From ARM946ES Technical Reference Manual we can see that it uses "allocate on read-miss" * policy for both I$ and D$ (Chapter 3.2 and 3.3) * * Explanation : * "ARM system developer's guide: designing and optimizing system software" by * Andrew N. Sloss, Dominic Symes and Chris Wright, * Chapter 12.3.3 Allocating Policy on a Cache Miss : * A read allocate on cache miss policy allocates a cache line only during a read from main memory. * If the victim cache line contains valid data, then it is written to main memory before the cache line * is filled with new data. * Under this strategy, a write of new data to memory does not update the contents of the cache memory * unless a cache line was allocated on a previous read from main memory. * If the cache line contains valid data, then the write updates the cache and may update the main memory if * the cache write policy is write-through. * If the data is not in the cache, the controller writes to main memory only. */ if (!arm946e_preserve_cache && (arm946e->cp15_control_reg & CP15_CTL_ICACHE)) arm946e_invalidate_icache(target, address, size, count); return ERROR_OK; } static int arm946e_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; LOG_DEBUG("-"); retval = arm7_9_read_memory(target, address, size, count, buffer); if (retval != ERROR_OK) return retval; return ERROR_OK; } COMMAND_HANDLER(arm946e_handle_cp15) { /* one or two arguments, access a single register (write if second argument is given) */ if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); struct arm946e_common *arm946e = target_to_arm946(target); int retval = arm946e_verify_pointer(CMD, arm946e); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_TARGET_NOT_HALTED; } uint32_t address; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); if (CMD_ARGC == 1) { uint32_t value; retval = arm946e_read_cp15(target, address, &value); if (retval != ERROR_OK) { command_print(CMD, "%s cp15 reg %" PRIu32 " access failed", target_name(target), address); return retval; } retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* Return value in hex format */ command_print(CMD, "0x%08" PRIx32, value); } else if (CMD_ARGC == 2) { uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); retval = arm946e_write_cp15(target, address, value); if (retval != ERROR_OK) { command_print(CMD, "%s cp15 reg %" PRIu32 " access failed", target_name(target), address); return retval; } if (address == CP15_CTL) arm946e_update_cp15_caches(target, value); } return ERROR_OK; } COMMAND_HANDLER(arm946e_handle_idcache) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; int retval; struct target *target = get_current_target(CMD_CTX); struct arm946e_common *arm946e = target_to_arm946(target); retval = arm946e_verify_pointer(CMD, arm946e); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_TARGET_NOT_HALTED; } bool icache = (strcmp(CMD_NAME, "icache") == 0); uint32_t csize = arm946e_cp15_get_csize(target, icache ? GET_ICACHE_SIZE : GET_DCACHE_SIZE) / 1024; if (CMD_ARGC == 0) { bool bena = ((arm946e->cp15_control_reg & (icache ? CP15_CTL_ICACHE : CP15_CTL_DCACHE)) != 0) && (arm946e->cp15_control_reg & 0x1); if (csize == 0) command_print(CMD, "%s-cache absent", icache ? "I" : "D"); else command_print(CMD, "%s-cache size: %" PRIu32 "K, %s", icache ? "I" : "D", csize, bena ? "enabled" : "disabled"); return ERROR_OK; } bool flush = false; bool enable = false; retval = command_parse_bool_arg(CMD_ARGV[0], &enable); if (retval == ERROR_COMMAND_SYNTAX_ERROR) { if (strcmp(CMD_ARGV[0], "flush") == 0) { flush = true; retval = ERROR_OK; } else return retval; } /* Do not invalidate or change state, if cache is absent */ if (csize == 0) { command_print(CMD, "%s-cache absent, '%s' operation undefined", icache ? "I" : "D", CMD_ARGV[0]); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* NOTE: flushing entire cache will not preserve lock-down cache regions */ if (icache) { if ((arm946e->cp15_control_reg & CP15_CTL_ICACHE) && !enable) retval = arm946e_invalidate_whole_icache(target); } else { if ((arm946e->cp15_control_reg & CP15_CTL_DCACHE) && !enable) retval = arm946e_invalidate_whole_dcache(target); } if (retval != ERROR_OK || flush) return retval; uint32_t value; retval = arm946e_read_cp15(target, CP15_CTL, &value); if (retval != ERROR_OK) return retval; uint32_t vnew = value; uint32_t cmask = icache ? CP15_CTL_ICACHE : CP15_CTL_DCACHE; if (enable) { if ((value & 0x1) == 0) LOG_WARNING("arm946e: MPU must be enabled for cache to operate"); vnew |= cmask; } else vnew &= ~cmask; if (vnew == value) return ERROR_OK; retval = arm946e_write_cp15(target, CP15_CTL, vnew); if (retval != ERROR_OK) return retval; arm946e_update_cp15_caches(target, vnew); return ERROR_OK; } static const struct command_registration arm946e_exec_command_handlers[] = { { .name = "cp15", .handler = arm946e_handle_cp15, .mode = COMMAND_EXEC, .usage = "regnum [value]", .help = "read/modify cp15 register", }, { .name = "icache", .handler = arm946e_handle_idcache, .mode = COMMAND_EXEC, .usage = "['enable'|'disable'|'flush']", .help = "I-cache info and operations", }, { .name = "dcache", .handler = arm946e_handle_idcache, .mode = COMMAND_EXEC, .usage = "['enable'|'disable'|'flush']", .help = "D-cache info and operations", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration arm946e_command_handlers[] = { { .chain = arm9tdmi_command_handlers, }, { .name = "arm946e", .mode = COMMAND_ANY, .help = "arm946e command group", .usage = "", .chain = arm946e_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Holds methods for ARM946 targets. */ struct target_type arm946e_target = { .name = "arm946e", .poll = arm7_9_poll, .arch_state = arm_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm7_9_soft_reset_halt, .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, /* .read_memory = arm7_9_read_memory, */ /* .write_memory = arm7_9_write_memory, */ .read_memory = arm946e_read_memory, .write_memory = arm946e_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, /* .add_breakpoint = arm946e_add_breakpoint, */ /* .remove_breakpoint = arm946e_remove_breakpoint, */ .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm946e_command_handlers, .target_create = arm946e_target_create, .init_target = arm9tdmi_init_target, .deinit_target = arm946e_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm946e.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2010 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM946E_H #define OPENOCD_TARGET_ARM946E_H #include "arm9tdmi.h" #define ARM946E_COMMON_MAGIC 0x20f920f9U struct arm946e_common { unsigned int common_magic; struct arm7_9_common arm7_9_common; uint32_t cp15_control_reg; uint32_t cp15_cache_info; }; static inline struct arm946e_common *target_to_arm946(struct target *target) { return container_of(target->arch_info, struct arm946e_common, arm7_9_common.arm); } #endif /* OPENOCD_TARGET_ARM946E_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm966e.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm966e.h" #include "target_type.h" #include "arm_opcodes.h" #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif int arm966e_init_arch_info(struct target *target, struct arm966e_common *arm966e, struct jtag_tap *tap) { struct arm7_9_common *arm7_9 = &arm966e->arm7_9_common; /* initialize arm7/arm9 specific info (including armv4_5) */ arm9tdmi_init_arch_info(target, arm7_9, tap); arm966e->common_magic = ARM966E_COMMON_MAGIC; /* The ARM966E-S implements the ARMv5TE architecture which * has the BKPT instruction, so we don't have to use a watchpoint comparator */ arm7_9->arm_bkpt = ARMV5_BKPT(0x0); arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; return ERROR_OK; } static int arm966e_target_create(struct target *target, Jim_Interp *interp) { struct arm966e_common *arm966e = calloc(1, sizeof(struct arm966e_common)); return arm966e_init_arch_info(target, arm966e, target->tap); } static void arm966e_deinit_target(struct target *target) { struct arm *arm = target_to_arm(target); struct arm966e_common *arm966e = target_to_arm966(target); arm7_9_deinit(target); arm_free_reg_cache(arm); free(arm966e); } static int arm966e_verify_pointer(struct command_invocation *cmd, struct arm966e_common *arm966e) { if (arm966e->common_magic != ARM966E_COMMON_MAGIC) { command_print(cmd, "target is not an ARM966"); return ERROR_TARGET_INVALID; } return ERROR_OK; } /* * REVISIT: The "read_cp15" and "write_cp15" commands could hook up * to eventual mrc() and mcr() routines ... the reg_addr values being * constructed (for CP15 only) from Opcode_1, Opcode_2, and CRn values. * See section 7.3 of the ARM966E-S TRM. */ static int arm966e_read_cp15(struct target *target, int reg_addr, uint32_t *value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct scan_field fields[3]; uint8_t reg_addr_buf = reg_addr & 0x3f; uint8_t nr_w_buf = 0; retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; /* REVISIT: table 7-2 shows that bits 31-31 need to be * specified for accessing BIST registers ... */ fields[0].out_value = NULL; fields[0].in_value = NULL; fields[1].num_bits = 6; fields[1].out_value = ®_addr_buf; fields[1].in_value = NULL; fields[2].num_bits = 1; fields[2].out_value = &nr_w_buf; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); fields[1].in_value = (uint8_t *)value; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); #endif return ERROR_OK; } /* EXPORTED to str9x (flash) */ int arm966e_write_cp15(struct target *target, int reg_addr, uint32_t value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct scan_field fields[3]; uint8_t reg_addr_buf = reg_addr & 0x3f; uint8_t nr_w_buf = 1; uint8_t value_buf[4]; buf_set_u32(value_buf, 0, 32, value); retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = value_buf; fields[0].in_value = NULL; fields[1].num_bits = 6; fields[1].out_value = ®_addr_buf; fields[1].in_value = NULL; fields[2].num_bits = 1; fields[2].out_value = &nr_w_buf; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); #endif return ERROR_OK; } COMMAND_HANDLER(arm966e_handle_cp15_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct arm966e_common *arm966e = target_to_arm966(target); retval = arm966e_verify_pointer(CMD, arm966e); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } /* one or more argument, access a single register (write if second argument is given */ if (CMD_ARGC >= 1) { uint32_t address; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); if (CMD_ARGC == 1) { uint32_t value; retval = arm966e_read_cp15(target, address, &value); if (retval != ERROR_OK) { command_print(CMD, "couldn't access reg %" PRIu32, address); return ERROR_OK; } retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; command_print(CMD, "%" PRIu32 ": %8.8" PRIx32, address, value); } else if (CMD_ARGC == 2) { uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); retval = arm966e_write_cp15(target, address, value); if (retval != ERROR_OK) { command_print(CMD, "couldn't access reg %" PRIu32, address); return ERROR_OK; } command_print(CMD, "%" PRIu32 ": %8.8" PRIx32, address, value); } } return ERROR_OK; } static const struct command_registration arm966e_exec_command_handlers[] = { { .name = "cp15", .handler = arm966e_handle_cp15_command, .mode = COMMAND_EXEC, .usage = "regnum [value]", .help = "display/modify cp15 register", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm966e_command_handlers[] = { { .chain = arm9tdmi_command_handlers, }, { .name = "arm966e", .mode = COMMAND_ANY, .help = "arm966e command group", .usage = "", .chain = arm966e_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Holds methods for ARM966 targets. */ struct target_type arm966e_target = { .name = "arm966e", .poll = arm7_9_poll, .arch_state = arm_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm7_9_soft_reset_halt, .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm7_9_read_memory, .write_memory = arm7_9_write_memory_opt, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm966e_command_handlers, .target_create = arm966e_target_create, .init_target = arm9tdmi_init_target, .deinit_target = arm966e_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm966e.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM966E_H #define OPENOCD_TARGET_ARM966E_H #include "arm9tdmi.h" #define ARM966E_COMMON_MAGIC 0x20f920f9U struct arm966e_common { unsigned int common_magic; struct arm7_9_common arm7_9_common; uint32_t cp15_control_reg; }; static inline struct arm966e_common * target_to_arm966(struct target *target) { return container_of(target->arch_info, struct arm966e_common, arm7_9_common.arm); } int arm966e_init_arch_info(struct target *target, struct arm966e_common *arm966e, struct jtag_tap *tap); int arm966e_write_cp15(struct target *target, int reg_addr, uint32_t value); extern const struct command_registration arm966e_command_handlers[]; #endif /* OPENOCD_TARGET_ARM966E_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm9tdmi.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by Hongtao Zheng * * hontor@126.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm9tdmi.h" #include "target_type.h" #include "register.h" #include "arm_opcodes.h" #include "arm_semihosting.h" /* * NOTE: this holds code that's used with multiple ARM9 processors: * - ARM9TDMI (ARMv4T) ... in ARM920, ARM922, and ARM940 cores * - ARM9E-S (ARMv5TE) ... in ARM946, ARM966, and ARM968 cores * - ARM9EJS (ARMv5TEJ) ... in ARM926 core * * In short, the file name is a misnomer ... it is NOT specific to * that first generation ARM9 processor, or cores using it. */ #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif enum arm9tdmi_vector_bit { ARM9TDMI_RESET_VECTOR = 0x01, ARM9TDMI_UNDEF_VECTOR = 0x02, ARM9TDMI_SWI_VECTOR = 0x04, ARM9TDMI_PABT_VECTOR = 0x08, ARM9TDMI_DABT_VECTOR = 0x10, /* BIT(5) reserved -- must be zero */ ARM9TDMI_IRQ_VECTOR = 0x40, ARM9TDMI_FIQ_VECTOR = 0x80, }; static const struct arm9tdmi_vector { const char *name; uint32_t value; } arm9tdmi_vectors[] = { {"reset", ARM9TDMI_RESET_VECTOR}, {"undef", ARM9TDMI_UNDEF_VECTOR}, {"swi", ARM9TDMI_SWI_VECTOR}, {"pabt", ARM9TDMI_PABT_VECTOR}, {"dabt", ARM9TDMI_DABT_VECTOR}, {"irq", ARM9TDMI_IRQ_VECTOR}, {"fiq", ARM9TDMI_FIQ_VECTOR}, {NULL, 0}, }; int arm9tdmi_examine_debug_reason(struct target *target) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); /* only check the debug reason if we don't know it already */ if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) { struct scan_field fields[3]; uint8_t databus[4]; uint8_t instructionbus[4]; uint8_t debug_reason; fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = databus; fields[1].num_bits = 3; fields[1].out_value = NULL; fields[1].in_value = &debug_reason; fields[2].num_bits = 32; fields[2].out_value = NULL; fields[2].in_value = instructionbus; retval = arm_jtag_scann(&arm7_9->jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(arm7_9->jtag_info.tap, arm7_9->jtag_info.intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; jtag_add_dr_scan(arm7_9->jtag_info.tap, 3, fields, TAP_DRPAUSE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; fields[0].in_value = NULL; fields[0].out_value = databus; fields[1].in_value = NULL; fields[1].out_value = &debug_reason; fields[2].in_value = NULL; fields[2].out_value = instructionbus; jtag_add_dr_scan(arm7_9->jtag_info.tap, 3, fields, TAP_DRPAUSE); if (debug_reason & 0x4) if (debug_reason & 0x2) target->debug_reason = DBG_REASON_WPTANDBKPT; else target->debug_reason = DBG_REASON_WATCHPOINT; else target->debug_reason = DBG_REASON_BREAKPOINT; } return ERROR_OK; } /* put an instruction in the ARM9TDMI pipeline or write the data bus, * and optionally read data */ int arm9tdmi_clock_out(struct arm_jtag *jtag_info, uint32_t instr, uint32_t out, uint32_t *in, int sysspeed) { int retval = ERROR_OK; struct scan_field fields[3]; uint8_t out_buf[4]; uint8_t instr_buf[4]; uint8_t sysspeed_buf = 0x0; /* prepare buffer */ buf_set_u32(out_buf, 0, 32, out); buf_set_u32(instr_buf, 0, 32, flip_u32(instr, 32)); if (sysspeed) buf_set_u32(&sysspeed_buf, 2, 1, 1); retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = out_buf; fields[0].in_value = NULL; fields[1].num_bits = 3; fields[1].out_value = &sysspeed_buf; fields[1].in_value = NULL; fields[2].num_bits = 32; fields[2].out_value = instr_buf; fields[2].in_value = NULL; if (in) { fields[0].in_value = (uint8_t *)in; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)in); } else jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE); jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ { retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (in) LOG_DEBUG("instr: 0x%8.8x, out: 0x%8.8x, in: 0x%8.8x", instr, out, *in); else LOG_DEBUG("instr: 0x%8.8x, out: 0x%8.8x", instr, out); } #endif return ERROR_OK; } /* just read data (instruction and data-out = don't care) */ int arm9tdmi_clock_data_in(struct arm_jtag *jtag_info, uint32_t *in) { int retval = ERROR_OK; struct scan_field fields[3]; retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = (uint8_t *)in; fields[1].num_bits = 3; fields[1].out_value = NULL; fields[1].in_value = NULL; fields[2].num_bits = 32; fields[2].out_value = NULL; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)in); jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ { retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (in) LOG_DEBUG("in: 0x%8.8x", *in); else LOG_ERROR("BUG: called with in == NULL"); } #endif return ERROR_OK; } /* clock the target, and read the databus * the *in pointer points to a buffer where elements of 'size' bytes * are stored in big (be == 1) or little (be == 0) endianness */ int arm9tdmi_clock_data_in_endianness(struct arm_jtag *jtag_info, void *in, int size, int be) { int retval = ERROR_OK; struct scan_field fields[2]; retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; if (size == 4) { fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = in; fields[1].num_bits = 3 + 32; fields[1].out_value = NULL; fields[1].in_value = NULL; } else { /* Discard irrelevant bits of the scan, making sure we don't write more * than size bytes to in */ fields[0].num_bits = size * 8; fields[0].out_value = NULL; fields[0].in_value = in; fields[1].num_bits = 3 + 32 + 32 - size * 8; fields[1].out_value = NULL; fields[1].in_value = NULL; } jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE); jtag_add_callback4(arm7_9_endianness_callback, (jtag_callback_data_t)in, (jtag_callback_data_t)size, (jtag_callback_data_t)be, (jtag_callback_data_t)0); jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ { retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (in) LOG_DEBUG("in: 0x%8.8x", *(uint32_t *)in); else LOG_ERROR("BUG: called with in == NULL"); } #endif return ERROR_OK; } static void arm9tdmi_change_to_arm(struct target *target, uint32_t *r0, uint32_t *pc) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* save r0 before using it and put system in ARM state * to allow common handling of ARM and THUMB debugging */ /* fetch STR r0, [r0] */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* STR r0, [r0] in Memory */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, r0, 0); /* MOV r0, r15 fetched, STR in Decode */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* nothing fetched, STR r0, [r0] in Memory */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, pc, 0); /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0); /* LDR in Decode */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* LDR in Execute */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* LDR in Memory (to account for interlock) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* fetch BX */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), 0, NULL, 0); /* NOP fetched, BX in Decode, MOV in Execute */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* NOP fetched, BX in Execute (1) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return; /* fix program counter: * MOV r0, r15 was the 5th instruction (+8) * reading PC in Thumb state gives address of instruction + 4 */ *pc -= 0xc; } void arm9tdmi_read_core_regs(struct target *target, uint32_t mask, uint32_t *core_regs[16]) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); /* fetch NOP, STM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, STM in MEMORY (i'th cycle) */ arm9tdmi_clock_data_in(jtag_info, core_regs[i]); } } static void arm9tdmi_read_core_regs_target_buffer(struct target *target, uint32_t mask, void *buffer, int size) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; uint32_t *buf_u32 = buffer; uint16_t *buf_u16 = buffer; uint8_t *buf_u8 = buffer; /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); /* fetch NOP, STM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, STM in MEMORY (i'th cycle) */ switch (size) { case 4: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); break; case 2: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); break; case 1: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); break; } } } static void arm9tdmi_read_xpsr(struct target *target, uint32_t *xpsr, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* MRS r0, cpsr */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* STR r0, [r15] */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0, NULL, 0); /* fetch NOP, STR in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STR in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, STR in MEMORY */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0); } static void arm9tdmi_write_xpsr(struct target *target, uint32_t xpsr, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr: %8.8" PRIx32 ", spsr: %i", xpsr, spsr); /* MSR1 fetched */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0); /* MSR2 fetched, MSR1 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0); /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0); /* nothing fetched, MSR1 in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR1 in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0); /* nothing fetched, MSR2 in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR2 in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR3 in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR3 in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* NOP fetched, MSR4 in EXECUTE (1) */ /* last MSR writes flags, which takes only one cycle */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void arm9tdmi_write_xpsr_im8(struct target *target, uint8_t xpsr_im, int rot, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); /* MSR fetched */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0); /* NOP fetched, MSR in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* NOP fetched, MSR in EXECUTE (1) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* rot == 4 writes flags, which takes only one cycle */ if (rot != 4) { /* nothing fetched, MSR in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } } void arm9tdmi_write_core_regs(struct target *target, uint32_t mask, uint32_t core_regs[16]) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); /* fetch NOP, LDM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, LDM still in EXECUTE (1 + i cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0); } arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } void arm9tdmi_load_word_regs(struct target *target, uint32_t mask) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load-multiple into the pipeline */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); } void arm9tdmi_load_hword_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load half-word into the pipeline */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); } void arm9tdmi_load_byte_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load byte into the pipeline */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); } void arm9tdmi_store_word_regs(struct target *target, uint32_t mask) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store-multiple into the pipeline */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); } void arm9tdmi_store_hword_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store half-word into the pipeline */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); } void arm9tdmi_store_byte_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store byte into the pipeline */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); } static void arm9tdmi_write_pc(struct target *target, uint32_t pc) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0, NULL, 0); /* fetch NOP, LDM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, LDM in EXECUTE stage (2nd cycle) (output data) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, pc, NULL, 0); /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (4th cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (5th cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } void arm9tdmi_branch_resume(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; arm9tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffc, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); } static void arm9tdmi_branch_resume_thumb(struct target *target) { LOG_DEBUG("-"); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), 0, NULL, 0); /* fetch NOP, LDM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, buf_get_u32(arm->pc->value, 0, 32) | 1, NULL, 0); /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* Branch and eXchange */ arm9tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0, NULL, 0); embeddedice_read_reg(dbg_stat); /* fetch NOP, BX in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); embeddedice_read_reg(dbg_stat); /* fetch NOP, BX in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* target is now in Thumb state */ embeddedice_read_reg(dbg_stat); /* load r0 value, MOV_IM in Decode*/ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0); /* fetch NOP, LDR in Decode, MOV_IM in Execute */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* fetch NOP, LDR in Execute */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32), NULL, 0); /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); embeddedice_read_reg(dbg_stat); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f7), 0, NULL, 1); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); } void arm9tdmi_enable_single_step(struct target *target, uint32_t next_pc) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (arm7_9->has_single_step) { buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 1); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]); } else arm7_9_enable_eice_step(target, next_pc); } void arm9tdmi_disable_single_step(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (arm7_9->has_single_step) { buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 0); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]); } else arm7_9_disable_eice_step(target); } static void arm9tdmi_build_reg_cache(struct target *target) { struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct arm *arm = target_to_arm(target); (*cache_p) = arm_build_reg_cache(target, arm); } int arm9tdmi_init_target(struct command_context *cmd_ctx, struct target *target) { arm9tdmi_build_reg_cache(target); arm_semihosting_init(target); return ERROR_OK; } int arm9tdmi_init_arch_info(struct target *target, struct arm7_9_common *arm7_9, struct jtag_tap *tap) { /* prepare JTAG information for the new target */ arm7_9->jtag_info.tap = tap; arm7_9->jtag_info.scann_size = 5; /* register arch-specific functions */ arm7_9->examine_debug_reason = arm9tdmi_examine_debug_reason; arm7_9->change_to_arm = arm9tdmi_change_to_arm; arm7_9->read_core_regs = arm9tdmi_read_core_regs; arm7_9->read_core_regs_target_buffer = arm9tdmi_read_core_regs_target_buffer; arm7_9->read_xpsr = arm9tdmi_read_xpsr; arm7_9->write_xpsr = arm9tdmi_write_xpsr; arm7_9->write_xpsr_im8 = arm9tdmi_write_xpsr_im8; arm7_9->write_core_regs = arm9tdmi_write_core_regs; arm7_9->load_word_regs = arm9tdmi_load_word_regs; arm7_9->load_hword_reg = arm9tdmi_load_hword_reg; arm7_9->load_byte_reg = arm9tdmi_load_byte_reg; arm7_9->store_word_regs = arm9tdmi_store_word_regs; arm7_9->store_hword_reg = arm9tdmi_store_hword_reg; arm7_9->store_byte_reg = arm9tdmi_store_byte_reg; arm7_9->write_pc = arm9tdmi_write_pc; arm7_9->branch_resume = arm9tdmi_branch_resume; arm7_9->branch_resume_thumb = arm9tdmi_branch_resume_thumb; arm7_9->enable_single_step = arm9tdmi_enable_single_step; arm7_9->disable_single_step = arm9tdmi_disable_single_step; arm7_9->write_memory = arm7_9_write_memory; arm7_9->bulk_write_memory = arm7_9_bulk_write_memory; arm7_9->post_debug_entry = NULL; arm7_9->pre_restore_context = NULL; /* initialize arch-specific breakpoint handling */ arm7_9->arm_bkpt = 0xdeeedeee; arm7_9->thumb_bkpt = 0xdeee; arm7_9->dbgreq_adjust_pc = 3; arm7_9_init_arch_info(target, arm7_9); /* override use of DBGRQ, this is safe on ARM9TDMI */ arm7_9->use_dbgrq = 1; /* all ARM9s have the vector catch register */ arm7_9->has_vector_catch = 1; return ERROR_OK; } static int arm9tdmi_target_create(struct target *target, Jim_Interp *interp) { struct arm7_9_common *arm7_9 = calloc(1, sizeof(struct arm7_9_common)); arm9tdmi_init_arch_info(target, arm7_9, target->tap); arm7_9->arm.arch = ARM_ARCH_V4; return ERROR_OK; } void arm9tdmi_deinit_target(struct target *target) { struct arm *arm = target_to_arm(target); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); arm7_9_deinit(target); arm_free_reg_cache(arm); free(arm7_9); } COMMAND_HANDLER(handle_arm9tdmi_catch_vectors_command) { struct target *target = get_current_target(CMD_CTX); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct reg *vector_catch; uint32_t vector_catch_value; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } /* it's uncommon, but some ARM7 chips can support this */ if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC || !arm7_9->has_vector_catch) { command_print(CMD, "target doesn't have EmbeddedICE " "with vector_catch"); return ERROR_TARGET_INVALID; } vector_catch = &arm7_9->eice_cache->reg_list[EICE_VEC_CATCH]; /* read the vector catch register if necessary */ if (!vector_catch->valid) embeddedice_read_reg(vector_catch); /* get the current setting */ vector_catch_value = buf_get_u32(vector_catch->value, 0, 8); if (CMD_ARGC > 0) { vector_catch_value = 0x0; if (strcmp(CMD_ARGV[0], "all") == 0) vector_catch_value = 0xdf; else if (strcmp(CMD_ARGV[0], "none") == 0) { /* do nothing */ } else { for (unsigned i = 0; i < CMD_ARGC; i++) { /* go through list of vectors */ unsigned j; for (j = 0; arm9tdmi_vectors[j].name; j++) { if (strcmp(CMD_ARGV[i], arm9tdmi_vectors[j].name) == 0) { vector_catch_value |= arm9tdmi_vectors[j].value; break; } } /* complain if vector wasn't found */ if (!arm9tdmi_vectors[j].name) { command_print(CMD, "vector '%s' not found, leaving current setting unchanged", CMD_ARGV[i]); /* reread current setting */ vector_catch_value = buf_get_u32( vector_catch->value, 0, 8); break; } } } /* store new settings */ buf_set_u32(vector_catch->value, 0, 8, vector_catch_value); embeddedice_store_reg(vector_catch); } /* output current settings */ for (unsigned i = 0; arm9tdmi_vectors[i].name; i++) { command_print(CMD, "%s: %s", arm9tdmi_vectors[i].name, (vector_catch_value & arm9tdmi_vectors[i].value) ? "catch" : "don't catch"); } return ERROR_OK; } static const struct command_registration arm9tdmi_exec_command_handlers[] = { { .name = "vector_catch", .handler = handle_arm9tdmi_catch_vectors_command, .mode = COMMAND_EXEC, .help = "Display, after optionally updating, configuration " "of vector catch unit.", .usage = "[all|none|(reset|undef|swi|pabt|dabt|irq|fiq)*]", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm9tdmi_command_handlers[] = { { .chain = arm7_9_command_handlers, }, { .name = "arm9", .mode = COMMAND_ANY, .help = "arm9 command group", .usage = "", .chain = arm9tdmi_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Holds methods for ARM9TDMI targets. */ struct target_type arm9tdmi_target = { .name = "arm9tdmi", .poll = arm7_9_poll, .arch_state = arm_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm7_9_soft_reset_halt, .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm7_9_read_memory, .write_memory = arm7_9_write_memory_opt, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm9tdmi_command_handlers, .target_create = arm9tdmi_target_create, .init_target = arm9tdmi_init_target, .deinit_target = arm9tdmi_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm9tdmi.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM9TDMI_H #define OPENOCD_TARGET_ARM9TDMI_H #include "embeddedice.h" int arm9tdmi_init_target(struct command_context *cmd_ctx, struct target *target); void arm9tdmi_deinit_target(struct target *target); int arm9tdmi_init_arch_info(struct target *target, struct arm7_9_common *arm7_9, struct jtag_tap *tap); extern const struct command_registration arm9tdmi_command_handlers[]; int arm9tdmi_clock_out(struct arm_jtag *jtag_info, uint32_t instr, uint32_t out, uint32_t *in, int sysspeed); int arm9tdmi_clock_data_in(struct arm_jtag *jtag_info, uint32_t *in); int arm9tdmi_clock_data_in_endianness(struct arm_jtag *jtag_info, void *in, int size, int be); void arm9tdmi_read_core_regs(struct target *target, uint32_t mask, uint32_t *core_regs[16]); void arm9tdmi_write_core_regs(struct target *target, uint32_t mask, uint32_t core_regs[16]); int arm9tdmi_examine_debug_reason(struct target *target); void arm9tdmi_load_word_regs(struct target *target, uint32_t mask); void arm9tdmi_load_hword_reg(struct target *target, int num); void arm9tdmi_load_byte_reg(struct target *target, int num); void arm9tdmi_store_word_regs(struct target *target, uint32_t mask); void arm9tdmi_store_hword_reg(struct target *target, int num); void arm9tdmi_store_byte_reg(struct target *target, int num); void arm9tdmi_branch_resume(struct target *target); void arm9tdmi_enable_single_step(struct target *target, uint32_t next_pc); void arm9tdmi_disable_single_step(struct target *target); #endif /* OPENOCD_TARGET_ARM9TDMI_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_adi_v5.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2009-2010 by Oyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009-2010 by David Brownell * * * * Copyright (C) 2013 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * * * * Copyright (C) 2019-2021, Ampere Computing LLC * ***************************************************************************/ /** * @file * This file implements support for the ARM Debug Interface version 5 (ADIv5) * debugging architecture. Compared with previous versions, this includes * a low pin-count Serial Wire Debug (SWD) alternative to JTAG for message * transport, and focuses on memory mapped resources as defined by the * CoreSight architecture. * * A key concept in ADIv5 is the Debug Access Port, or DAP. A DAP has two * basic components: a Debug Port (DP) transporting messages to and from a * debugger, and an Access Port (AP) accessing resources. Three types of DP * are defined. One uses only JTAG for communication, and is called JTAG-DP. * One uses only SWD for communication, and is called SW-DP. The third can * use either SWD or JTAG, and is called SWJ-DP. The most common type of AP * is used to access memory mapped resources and is called a MEM-AP. Also a * JTAG-AP is also defined, bridging to JTAG resources; those are uncommon. * * This programming interface allows DAP pipelined operations through a * transaction queue. This primarily affects AP operations (such as using * a MEM-AP to access memory or registers). If the current transaction has * not finished by the time the next one must begin, and the ORUNDETECT bit * is set in the DP_CTRL_STAT register, the SSTICKYORUN status is set and * further AP operations will fail. There are two basic methods to avoid * such overrun errors. One involves polling for status instead of using * transaction pipelining. The other involves adding delays to ensure the * AP has enough time to complete one operation before starting the next * one. (For JTAG these delays are controlled by memaccess_tck.) */ /* * Relevant specifications from ARM include: * * ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031E * CoreSight(tm) v1.0 Architecture Specification ARM IHI 0029B * * CoreSight(tm) DAP-Lite TRM, ARM DDI 0316D * Cortex-M3(tm) TRM, ARM DDI 0337G */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/interface.h" #include "arm.h" #include "arm_adi_v5.h" #include "arm_coresight.h" #include "jtag/swd.h" #include "transport/transport.h" #include <helper/align.h> #include <helper/jep106.h> #include <helper/time_support.h> #include <helper/list.h> #include <helper/jim-nvp.h> /* ARM ADI Specification requires at least 10 bits used for TAR autoincrement */ /* uint32_t tar_block_size(uint32_t address) Return the largest block starting at address that does not cross a tar block size alignment boundary */ static uint32_t max_tar_block_size(uint32_t tar_autoincr_block, target_addr_t address) { return tar_autoincr_block - ((tar_autoincr_block - 1) & address); } /*************************************************************************** * * * DP and MEM-AP register access through APACC and DPACC * * * ***************************************************************************/ static int mem_ap_setup_csw(struct adiv5_ap *ap, uint32_t csw) { csw |= ap->csw_default; if (csw != ap->csw_value) { /* LOG_DEBUG("DAP: Set CSW %x",csw); */ int retval = dap_queue_ap_write(ap, MEM_AP_REG_CSW(ap->dap), csw); if (retval != ERROR_OK) { ap->csw_value = 0; return retval; } ap->csw_value = csw; } return ERROR_OK; } static int mem_ap_setup_tar(struct adiv5_ap *ap, target_addr_t tar) { if (!ap->tar_valid || tar != ap->tar_value) { /* LOG_DEBUG("DAP: Set TAR %x",tar); */ int retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR(ap->dap), (uint32_t)(tar & 0xffffffffUL)); if (retval == ERROR_OK && is_64bit_ap(ap)) { /* See if bits 63:32 of tar is different from last setting */ if (!ap->tar_valid || (ap->tar_value >> 32) != (tar >> 32)) retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR64(ap->dap), (uint32_t)(tar >> 32)); } if (retval != ERROR_OK) { ap->tar_valid = false; return retval; } ap->tar_value = tar; ap->tar_valid = true; } return ERROR_OK; } static int mem_ap_read_tar(struct adiv5_ap *ap, target_addr_t *tar) { uint32_t lower; uint32_t upper = 0; int retval = dap_queue_ap_read(ap, MEM_AP_REG_TAR(ap->dap), &lower); if (retval == ERROR_OK && is_64bit_ap(ap)) retval = dap_queue_ap_read(ap, MEM_AP_REG_TAR64(ap->dap), &upper); if (retval != ERROR_OK) { ap->tar_valid = false; return retval; } retval = dap_run(ap->dap); if (retval != ERROR_OK) { ap->tar_valid = false; return retval; } *tar = (((target_addr_t)upper) << 32) | (target_addr_t)lower; ap->tar_value = *tar; ap->tar_valid = true; return ERROR_OK; } static uint32_t mem_ap_get_tar_increment(struct adiv5_ap *ap) { switch (ap->csw_value & CSW_ADDRINC_MASK) { case CSW_ADDRINC_SINGLE: switch (ap->csw_value & CSW_SIZE_MASK) { case CSW_8BIT: return 1; case CSW_16BIT: return 2; case CSW_32BIT: return 4; default: return 0; } case CSW_ADDRINC_PACKED: return 4; } return 0; } /* mem_ap_update_tar_cache is called after an access to MEM_AP_REG_DRW */ static void mem_ap_update_tar_cache(struct adiv5_ap *ap) { if (!ap->tar_valid) return; uint32_t inc = mem_ap_get_tar_increment(ap); if (inc >= max_tar_block_size(ap->tar_autoincr_block, ap->tar_value)) ap->tar_valid = false; else ap->tar_value += inc; } /** * Queue transactions setting up transfer parameters for the * currently selected MEM-AP. * * Subsequent transfers using registers like MEM_AP_REG_DRW or MEM_AP_REG_BD2 * initiate data reads or writes using memory or peripheral addresses. * If the CSW is configured for it, the TAR may be automatically * incremented after each transfer. * * @param ap The MEM-AP. * @param csw MEM-AP Control/Status Word (CSW) register to assign. If this * matches the cached value, the register is not changed. * @param tar MEM-AP Transfer Address Register (TAR) to assign. If this * matches the cached address, the register is not changed. * * @return ERROR_OK if the transaction was properly queued, else a fault code. */ static int mem_ap_setup_transfer(struct adiv5_ap *ap, uint32_t csw, target_addr_t tar) { int retval; retval = mem_ap_setup_csw(ap, csw); if (retval != ERROR_OK) return retval; retval = mem_ap_setup_tar(ap, tar); if (retval != ERROR_OK) return retval; return ERROR_OK; } /** * Asynchronous (queued) read of a word from memory or a system register. * * @param ap The MEM-AP to access. * @param address Address of the 32-bit word to read; it must be * readable by the currently selected MEM-AP. * @param value points to where the word will be stored when the * transaction queue is flushed (assuming no errors). * * @return ERROR_OK for success. Otherwise a fault code. */ int mem_ap_read_u32(struct adiv5_ap *ap, target_addr_t address, uint32_t *value) { int retval; /* Use banked addressing (REG_BDx) to avoid some link traffic * (updating TAR) when reading several consecutive addresses. */ retval = mem_ap_setup_transfer(ap, CSW_32BIT | (ap->csw_value & CSW_ADDRINC_MASK), address & 0xFFFFFFFFFFFFFFF0ull); if (retval != ERROR_OK) return retval; return dap_queue_ap_read(ap, MEM_AP_REG_BD0(ap->dap) | (address & 0xC), value); } /** * Synchronous read of a word from memory or a system register. * As a side effect, this flushes any queued transactions. * * @param ap The MEM-AP to access. * @param address Address of the 32-bit word to read; it must be * readable by the currently selected MEM-AP. * @param value points to where the result will be stored. * * @return ERROR_OK for success; *value holds the result. * Otherwise a fault code. */ int mem_ap_read_atomic_u32(struct adiv5_ap *ap, target_addr_t address, uint32_t *value) { int retval; retval = mem_ap_read_u32(ap, address, value); if (retval != ERROR_OK) return retval; return dap_run(ap->dap); } /** * Asynchronous (queued) write of a word to memory or a system register. * * @param ap The MEM-AP to access. * @param address Address to be written; it must be writable by * the currently selected MEM-AP. * @param value Word that will be written to the address when transaction * queue is flushed (assuming no errors). * * @return ERROR_OK for success. Otherwise a fault code. */ int mem_ap_write_u32(struct adiv5_ap *ap, target_addr_t address, uint32_t value) { int retval; /* Use banked addressing (REG_BDx) to avoid some link traffic * (updating TAR) when writing several consecutive addresses. */ retval = mem_ap_setup_transfer(ap, CSW_32BIT | (ap->csw_value & CSW_ADDRINC_MASK), address & 0xFFFFFFFFFFFFFFF0ull); if (retval != ERROR_OK) return retval; return dap_queue_ap_write(ap, MEM_AP_REG_BD0(ap->dap) | (address & 0xC), value); } /** * Synchronous write of a word to memory or a system register. * As a side effect, this flushes any queued transactions. * * @param ap The MEM-AP to access. * @param address Address to be written; it must be writable by * the currently selected MEM-AP. * @param value Word that will be written. * * @return ERROR_OK for success; the data was written. Otherwise a fault code. */ int mem_ap_write_atomic_u32(struct adiv5_ap *ap, target_addr_t address, uint32_t value) { int retval = mem_ap_write_u32(ap, address, value); if (retval != ERROR_OK) return retval; return dap_run(ap->dap); } /** * Synchronous write of a block of memory, using a specific access size. * * @param ap The MEM-AP to access. * @param buffer The data buffer to write. No particular alignment is assumed. * @param size Which access size to use, in bytes. 1, 2 or 4. * @param count The number of writes to do (in size units, not bytes). * @param address Address to be written; it must be writable by the currently selected MEM-AP. * @param addrinc Whether the target address should be increased for each write or not. This * should normally be true, except when writing to e.g. a FIFO. * @return ERROR_OK on success, otherwise an error code. */ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address, bool addrinc) { struct adiv5_dap *dap = ap->dap; size_t nbytes = size * count; const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF; uint32_t csw_size; target_addr_t addr_xor; int retval = ERROR_OK; /* TI BE-32 Quirks mode: * Writes on big-endian TMS570 behave very strangely. Observed behavior: * size write address bytes written in order * 4 TAR ^ 0 (val >> 24), (val >> 16), (val >> 8), (val) * 2 TAR ^ 2 (val >> 8), (val) * 1 TAR ^ 3 (val) * For example, if you attempt to write a single byte to address 0, the processor * will actually write a byte to address 3. * * To make writes of size < 4 work as expected, we xor a value with the address before * setting the TAP, and we set the TAP after every transfer rather then relying on * address increment. */ if (size == 4) { csw_size = CSW_32BIT; addr_xor = 0; } else if (size == 2) { csw_size = CSW_16BIT; addr_xor = dap->ti_be_32_quirks ? 2 : 0; } else if (size == 1) { csw_size = CSW_8BIT; addr_xor = dap->ti_be_32_quirks ? 3 : 0; } else { return ERROR_TARGET_UNALIGNED_ACCESS; } if (ap->unaligned_access_bad && (address % size != 0)) return ERROR_TARGET_UNALIGNED_ACCESS; while (nbytes > 0) { uint32_t this_size = size; /* Select packed transfer if possible */ if (addrinc && ap->packed_transfers && nbytes >= 4 && max_tar_block_size(ap->tar_autoincr_block, address) >= 4) { this_size = 4; retval = mem_ap_setup_csw(ap, csw_size | CSW_ADDRINC_PACKED); } else { retval = mem_ap_setup_csw(ap, csw_size | csw_addrincr); } if (retval != ERROR_OK) break; retval = mem_ap_setup_tar(ap, address ^ addr_xor); if (retval != ERROR_OK) return retval; /* How many source bytes each transfer will consume, and their location in the DRW, * depends on the type of transfer and alignment. See ARM document IHI0031C. */ uint32_t outvalue = 0; uint32_t drw_byte_idx = address; if (dap->ti_be_32_quirks) { switch (this_size) { case 4: outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor); outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor); outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor); outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx & 3) ^ addr_xor); break; case 2: outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (drw_byte_idx++ & 3) ^ addr_xor); outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (drw_byte_idx & 3) ^ addr_xor); break; case 1: outvalue |= (uint32_t)*buffer++ << 8 * (0 ^ (drw_byte_idx & 3) ^ addr_xor); break; } } else if (dap->nu_npcx_quirks) { switch (this_size) { case 4: outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3); outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3); outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3); outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx & 3); break; case 2: outvalue |= (uint32_t)*buffer << 8 * (drw_byte_idx++ & 3); outvalue |= (uint32_t)*(buffer+1) << 8 * (drw_byte_idx++ & 3); outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3); outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx & 3); break; case 1: outvalue |= (uint32_t)*buffer << 8 * (drw_byte_idx++ & 3); outvalue |= (uint32_t)*buffer << 8 * (drw_byte_idx++ & 3); outvalue |= (uint32_t)*buffer << 8 * (drw_byte_idx++ & 3); outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx & 3); } } else { switch (this_size) { case 4: outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3); outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3); /* fallthrough */ case 2: outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3); /* fallthrough */ case 1: outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx & 3); } } nbytes -= this_size; retval = dap_queue_ap_write(ap, MEM_AP_REG_DRW(dap), outvalue); if (retval != ERROR_OK) break; mem_ap_update_tar_cache(ap); if (addrinc) address += this_size; } /* REVISIT: Might want to have a queued version of this function that does not run. */ if (retval == ERROR_OK) retval = dap_run(dap); if (retval != ERROR_OK) { target_addr_t tar; if (mem_ap_read_tar(ap, &tar) == ERROR_OK) LOG_ERROR("Failed to write memory at " TARGET_ADDR_FMT, tar); else LOG_ERROR("Failed to write memory and, additionally, failed to find out where"); } return retval; } /** * Synchronous read of a block of memory, using a specific access size. * * @param ap The MEM-AP to access. * @param buffer The data buffer to receive the data. No particular alignment is assumed. * @param size Which access size to use, in bytes. 1, 2 or 4. * @param count The number of reads to do (in size units, not bytes). * @param adr Address to be read; it must be readable by the currently selected MEM-AP. * @param addrinc Whether the target address should be increased after each read or not. This * should normally be true, except when reading from e.g. a FIFO. * @return ERROR_OK on success, otherwise an error code. */ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t adr, bool addrinc) { struct adiv5_dap *dap = ap->dap; size_t nbytes = size * count; const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF; uint32_t csw_size; target_addr_t address = adr; int retval = ERROR_OK; /* TI BE-32 Quirks mode: * Reads on big-endian TMS570 behave strangely differently than writes. * They read from the physical address requested, but with DRW byte-reversed. * For example, a byte read from address 0 will place the result in the high bytes of DRW. * Also, packed 8-bit and 16-bit transfers seem to sometimes return garbage in some bytes, * so avoid them. */ if (size == 4) csw_size = CSW_32BIT; else if (size == 2) csw_size = CSW_16BIT; else if (size == 1) csw_size = CSW_8BIT; else return ERROR_TARGET_UNALIGNED_ACCESS; if (ap->unaligned_access_bad && (adr % size != 0)) return ERROR_TARGET_UNALIGNED_ACCESS; /* Allocate buffer to hold the sequence of DRW reads that will be made. This is a significant * over-allocation if packed transfers are going to be used, but determining the real need at * this point would be messy. */ uint32_t *read_buf = calloc(count, sizeof(uint32_t)); /* Multiplication count * sizeof(uint32_t) may overflow, calloc() is safe */ uint32_t *read_ptr = read_buf; if (!read_buf) { LOG_ERROR("Failed to allocate read buffer"); return ERROR_FAIL; } /* Queue up all reads. Each read will store the entire DRW word in the read buffer. How many * useful bytes it contains, and their location in the word, depends on the type of transfer * and alignment. */ while (nbytes > 0) { uint32_t this_size = size; /* Select packed transfer if possible */ if (addrinc && ap->packed_transfers && nbytes >= 4 && max_tar_block_size(ap->tar_autoincr_block, address) >= 4) { this_size = 4; retval = mem_ap_setup_csw(ap, csw_size | CSW_ADDRINC_PACKED); } else { retval = mem_ap_setup_csw(ap, csw_size | csw_addrincr); } if (retval != ERROR_OK) break; retval = mem_ap_setup_tar(ap, address); if (retval != ERROR_OK) break; retval = dap_queue_ap_read(ap, MEM_AP_REG_DRW(dap), read_ptr++); if (retval != ERROR_OK) break; nbytes -= this_size; if (addrinc) address += this_size; mem_ap_update_tar_cache(ap); } if (retval == ERROR_OK) retval = dap_run(dap); /* Restore state */ address = adr; nbytes = size * count; read_ptr = read_buf; /* If something failed, read TAR to find out how much data was successfully read, so we can * at least give the caller what we have. */ if (retval != ERROR_OK) { target_addr_t tar; if (mem_ap_read_tar(ap, &tar) == ERROR_OK) { /* TAR is incremented after failed transfer on some devices (eg Cortex-M4) */ LOG_ERROR("Failed to read memory at " TARGET_ADDR_FMT, tar); if (nbytes > tar - address) nbytes = tar - address; } else { LOG_ERROR("Failed to read memory and, additionally, failed to find out where"); nbytes = 0; } } /* Replay loop to populate caller's buffer from the correct word and byte lane */ while (nbytes > 0) { uint32_t this_size = size; if (addrinc && ap->packed_transfers && nbytes >= 4 && max_tar_block_size(ap->tar_autoincr_block, address) >= 4) { this_size = 4; } if (dap->ti_be_32_quirks) { switch (this_size) { case 4: *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); /* fallthrough */ case 2: *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); /* fallthrough */ case 1: *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); } } else { switch (this_size) { case 4: *buffer++ = *read_ptr >> 8 * (address++ & 3); *buffer++ = *read_ptr >> 8 * (address++ & 3); /* fallthrough */ case 2: *buffer++ = *read_ptr >> 8 * (address++ & 3); /* fallthrough */ case 1: *buffer++ = *read_ptr >> 8 * (address++ & 3); } } read_ptr++; nbytes -= this_size; } free(read_buf); return retval; } int mem_ap_read_buf(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address) { return mem_ap_read(ap, buffer, size, count, address, true); } int mem_ap_write_buf(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address) { return mem_ap_write(ap, buffer, size, count, address, true); } int mem_ap_read_buf_noincr(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address) { return mem_ap_read(ap, buffer, size, count, address, false); } int mem_ap_write_buf_noincr(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address) { return mem_ap_write(ap, buffer, size, count, address, false); } /*--------------------------------------------------------------------------*/ #define DAP_POWER_DOMAIN_TIMEOUT (10) /*--------------------------------------------------------------------------*/ /** * Invalidate cached DP select and cached TAR and CSW of all APs */ void dap_invalidate_cache(struct adiv5_dap *dap) { dap->select = DP_SELECT_INVALID; dap->last_read = NULL; int i; for (i = 0; i <= DP_APSEL_MAX; i++) { /* force csw and tar write on the next mem-ap access */ dap->ap[i].tar_valid = false; dap->ap[i].csw_value = 0; } } /** * Initialize a DAP. This sets up the power domains, prepares the DP * for further use and activates overrun checking. * * @param dap The DAP being initialized. */ int dap_dp_init(struct adiv5_dap *dap) { int retval; LOG_DEBUG("%s", adiv5_dap_name(dap)); dap->do_reconnect = false; dap_invalidate_cache(dap); /* * Early initialize dap->dp_ctrl_stat. * In jtag mode only, if the following queue run (in dap_dp_poll_register) * fails and sets the sticky error, it will trigger the clearing * of the sticky. Without this initialization system and debug power * would be disabled while clearing the sticky error bit. */ dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; /* * This write operation clears the sticky error bit in jtag mode only and * is ignored in swd mode. It also powers-up system and debug domains in * both jtag and swd modes, if not done before. */ retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat | SSTICKYERR); if (retval != ERROR_OK) return retval; retval = dap_queue_dp_read(dap, DP_CTRL_STAT, NULL); if (retval != ERROR_OK) return retval; retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat); if (retval != ERROR_OK) return retval; /* Check that we have debug power domains activated */ LOG_DEBUG("DAP: wait CDBGPWRUPACK"); retval = dap_dp_poll_register(dap, DP_CTRL_STAT, CDBGPWRUPACK, CDBGPWRUPACK, DAP_POWER_DOMAIN_TIMEOUT); if (retval != ERROR_OK) return retval; if (!dap->ignore_syspwrupack) { LOG_DEBUG("DAP: wait CSYSPWRUPACK"); retval = dap_dp_poll_register(dap, DP_CTRL_STAT, CSYSPWRUPACK, CSYSPWRUPACK, DAP_POWER_DOMAIN_TIMEOUT); if (retval != ERROR_OK) return retval; } retval = dap_queue_dp_read(dap, DP_CTRL_STAT, NULL); if (retval != ERROR_OK) return retval; /* With debug power on we can activate OVERRUN checking */ dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ | CORUNDETECT; retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat); if (retval != ERROR_OK) return retval; retval = dap_queue_dp_read(dap, DP_CTRL_STAT, NULL); if (retval != ERROR_OK) return retval; retval = dap_run(dap); if (retval != ERROR_OK) return retval; return retval; } /** * Initialize a DAP or do reconnect if DAP is not accessible. * * @param dap The DAP being initialized. */ int dap_dp_init_or_reconnect(struct adiv5_dap *dap) { LOG_DEBUG("%s", adiv5_dap_name(dap)); /* * Early initialize dap->dp_ctrl_stat. * In jtag mode only, if the following atomic reads fail and set the * sticky error, it will trigger the clearing of the sticky. Without this * initialization system and debug power would be disabled while clearing * the sticky error bit. */ dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; dap->do_reconnect = false; dap_dp_read_atomic(dap, DP_CTRL_STAT, NULL); if (dap->do_reconnect) { /* dap connect calls dap_dp_init() after transport dependent initialization */ return dap->ops->connect(dap); } else { return dap_dp_init(dap); } } /** * Initialize a DAP. This sets up the power domains, prepares the DP * for further use, and arranges to use AP #0 for all AP operations * until dap_ap-select() changes that policy. * * @param ap The MEM-AP being initialized. */ int mem_ap_init(struct adiv5_ap *ap) { /* check that we support packed transfers */ uint32_t csw, cfg; int retval; struct adiv5_dap *dap = ap->dap; /* Set ap->cfg_reg before calling mem_ap_setup_transfer(). */ /* mem_ap_setup_transfer() needs to know if the MEM_AP supports LPAE. */ retval = dap_queue_ap_read(ap, MEM_AP_REG_CFG(dap), &cfg); if (retval != ERROR_OK) return retval; retval = dap_run(dap); if (retval != ERROR_OK) return retval; ap->cfg_reg = cfg; ap->tar_valid = false; ap->csw_value = 0; /* force csw and tar write */ retval = mem_ap_setup_transfer(ap, CSW_8BIT | CSW_ADDRINC_PACKED, 0); if (retval != ERROR_OK) return retval; retval = dap_queue_ap_read(ap, MEM_AP_REG_CSW(dap), &csw); if (retval != ERROR_OK) return retval; retval = dap_run(dap); if (retval != ERROR_OK) return retval; if (csw & CSW_ADDRINC_PACKED) ap->packed_transfers = true; else ap->packed_transfers = false; /* Packed transfers on TI BE-32 processors do not work correctly in * many cases. */ if (dap->ti_be_32_quirks) ap->packed_transfers = false; LOG_DEBUG("MEM_AP Packed Transfers: %s", ap->packed_transfers ? "enabled" : "disabled"); /* The ARM ADI spec leaves implementation-defined whether unaligned * memory accesses work, only work partially, or cause a sticky error. * On TI BE-32 processors, reads seem to return garbage in some bytes * and unaligned writes seem to cause a sticky error. * TODO: it would be nice to have a way to detect whether unaligned * operations are supported on other processors. */ ap->unaligned_access_bad = dap->ti_be_32_quirks; LOG_DEBUG("MEM_AP CFG: large data %d, long address %d, big-endian %d", !!(cfg & MEM_AP_REG_CFG_LD), !!(cfg & MEM_AP_REG_CFG_LA), !!(cfg & MEM_AP_REG_CFG_BE)); return ERROR_OK; } /** * Put the debug link into SWD mode, if the target supports it. * The link's initial mode may be either JTAG (for example, * with SWJ-DP after reset) or SWD. * * Note that targets using the JTAG-DP do not support SWD, and that * some targets which could otherwise support it may have been * configured to disable SWD signaling * * @param dap The DAP used * @return ERROR_OK or else a fault code. */ int dap_to_swd(struct adiv5_dap *dap) { LOG_DEBUG("Enter SWD mode"); return dap_send_sequence(dap, JTAG_TO_SWD); } /** * Put the debug link into JTAG mode, if the target supports it. * The link's initial mode may be either SWD or JTAG. * * Note that targets implemented with SW-DP do not support JTAG, and * that some targets which could otherwise support it may have been * configured to disable JTAG signaling * * @param dap The DAP used * @return ERROR_OK or else a fault code. */ int dap_to_jtag(struct adiv5_dap *dap) { LOG_DEBUG("Enter JTAG mode"); return dap_send_sequence(dap, SWD_TO_JTAG); } /* CID interpretation -- see ARM IHI 0029E table B2-7 * and ARM IHI 0031E table D1-2. * * From 2009/11/25 commit 21378f58b604: * "OptimoDE DESS" is ARM's semicustom DSPish stuff. * Let's keep it as is, for the time being */ static const char *class_description[16] = { [0x0] = "Generic verification component", [0x1] = "ROM table", [0x2] = "Reserved", [0x3] = "Reserved", [0x4] = "Reserved", [0x5] = "Reserved", [0x6] = "Reserved", [0x7] = "Reserved", [0x8] = "Reserved", [0x9] = "CoreSight component", [0xA] = "Reserved", [0xB] = "Peripheral Test Block", [0xC] = "Reserved", [0xD] = "OptimoDE DESS", /* see above */ [0xE] = "Generic IP component", [0xF] = "CoreLink, PrimeCell or System component", }; #define ARCH_ID(architect, archid) ( \ (((architect) << ARM_CS_C9_DEVARCH_ARCHITECT_SHIFT) & ARM_CS_C9_DEVARCH_ARCHITECT_MASK) | \ (((archid) << ARM_CS_C9_DEVARCH_ARCHID_SHIFT) & ARM_CS_C9_DEVARCH_ARCHID_MASK) \ ) static const struct { uint32_t arch_id; const char *description; } class0x9_devarch[] = { /* keep same unsorted order as in ARM IHI0029E */ { ARCH_ID(ARM_ID, 0x0A00), "RAS architecture" }, { ARCH_ID(ARM_ID, 0x1A01), "Instrumentation Trace Macrocell (ITM) architecture" }, { ARCH_ID(ARM_ID, 0x1A02), "DWT architecture" }, { ARCH_ID(ARM_ID, 0x1A03), "Flash Patch and Breakpoint unit (FPB) architecture" }, { ARCH_ID(ARM_ID, 0x2A04), "Processor debug architecture (ARMv8-M)" }, { ARCH_ID(ARM_ID, 0x6A05), "Processor debug architecture (ARMv8-R)" }, { ARCH_ID(ARM_ID, 0x0A10), "PC sample-based profiling" }, { ARCH_ID(ARM_ID, 0x4A13), "Embedded Trace Macrocell (ETM) architecture" }, { ARCH_ID(ARM_ID, 0x1A14), "Cross Trigger Interface (CTI) architecture" }, { ARCH_ID(ARM_ID, 0x6A15), "Processor debug architecture (v8.0-A)" }, { ARCH_ID(ARM_ID, 0x7A15), "Processor debug architecture (v8.1-A)" }, { ARCH_ID(ARM_ID, 0x8A15), "Processor debug architecture (v8.2-A)" }, { ARCH_ID(ARM_ID, 0x2A16), "Processor Performance Monitor (PMU) architecture" }, { ARCH_ID(ARM_ID, 0x0A17), "Memory Access Port v2 architecture" }, { ARCH_ID(ARM_ID, 0x0A27), "JTAG Access Port v2 architecture" }, { ARCH_ID(ARM_ID, 0x0A31), "Basic trace router" }, { ARCH_ID(ARM_ID, 0x0A37), "Power requestor" }, { ARCH_ID(ARM_ID, 0x0A47), "Unknown Access Port v2 architecture" }, { ARCH_ID(ARM_ID, 0x0A50), "HSSTP architecture" }, { ARCH_ID(ARM_ID, 0x0A63), "System Trace Macrocell (STM) architecture" }, { ARCH_ID(ARM_ID, 0x0A75), "CoreSight ELA architecture" }, { ARCH_ID(ARM_ID, 0x0AF7), "CoreSight ROM architecture" }, }; #define DEVARCH_ID_MASK (ARM_CS_C9_DEVARCH_ARCHITECT_MASK | ARM_CS_C9_DEVARCH_ARCHID_MASK) #define DEVARCH_MEM_AP ARCH_ID(ARM_ID, 0x0A17) #define DEVARCH_ROM_C_0X9 ARCH_ID(ARM_ID, 0x0AF7) #define DEVARCH_UNKNOWN_V2 ARCH_ID(ARM_ID, 0x0A47) static const char *class0x9_devarch_description(uint32_t devarch) { if (!(devarch & ARM_CS_C9_DEVARCH_PRESENT)) return "not present"; for (unsigned int i = 0; i < ARRAY_SIZE(class0x9_devarch); i++) if ((devarch & DEVARCH_ID_MASK) == class0x9_devarch[i].arch_id) return class0x9_devarch[i].description; return "unknown"; } static const struct { enum ap_type type; const char *description; } ap_types[] = { { AP_TYPE_JTAG_AP, "JTAG-AP" }, { AP_TYPE_COM_AP, "COM-AP" }, { AP_TYPE_AHB3_AP, "MEM-AP AHB3" }, { AP_TYPE_APB_AP, "MEM-AP APB2 or APB3" }, { AP_TYPE_AXI_AP, "MEM-AP AXI3 or AXI4" }, { AP_TYPE_AHB5_AP, "MEM-AP AHB5" }, { AP_TYPE_APB4_AP, "MEM-AP APB4" }, { AP_TYPE_AXI5_AP, "MEM-AP AXI5" }, { AP_TYPE_AHB5H_AP, "MEM-AP AHB5 with enhanced HPROT" }, }; static const char *ap_type_to_description(enum ap_type type) { for (unsigned int i = 0; i < ARRAY_SIZE(ap_types); i++) if (type == ap_types[i].type) return ap_types[i].description; return "Unknown"; } bool is_ap_num_valid(struct adiv5_dap *dap, uint64_t ap_num) { if (!dap) return false; /* no autodetection, by now, so uninitialized is equivalent to ADIv5 for * backward compatibility */ if (!is_adiv6(dap)) { if (ap_num > DP_APSEL_MAX) return false; return true; } if (is_adiv6(dap)) { if (ap_num & 0x0fffULL) return false; if (dap->asize != 0) if (ap_num & ((~0ULL) << dap->asize)) return false; return true; } return false; } /* * This function checks the ID for each access port to find the requested Access Port type * It also calls dap_get_ap() to increment the AP refcount */ int dap_find_get_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_ap **ap_out) { if (is_adiv6(dap)) { /* TODO: scan the ROM table and detect the AP available */ LOG_DEBUG("On ADIv6 we cannot scan all the possible AP"); return ERROR_FAIL; } /* Maximum AP number is 255 since the SELECT register is 8 bits */ for (unsigned int ap_num = 0; ap_num <= DP_APSEL_MAX; ap_num++) { struct adiv5_ap *ap = dap_get_ap(dap, ap_num); if (!ap) continue; /* read the IDR register of the Access Port */ uint32_t id_val = 0; int retval = dap_queue_ap_read(ap, AP_REG_IDR(dap), &id_val); if (retval != ERROR_OK) { dap_put_ap(ap); return retval; } retval = dap_run(dap); /* Reading register for a non-existent AP should not cause an error, * but just to be sure, try to continue searching if an error does happen. */ if (retval == ERROR_OK && (id_val & AP_TYPE_MASK) == type_to_find) { LOG_DEBUG("Found %s at AP index: %d (IDR=0x%08" PRIX32 ")", ap_type_to_description(type_to_find), ap_num, id_val); *ap_out = ap; return ERROR_OK; } dap_put_ap(ap); } LOG_DEBUG("No %s found", ap_type_to_description(type_to_find)); return ERROR_FAIL; } static inline bool is_ap_in_use(struct adiv5_ap *ap) { return ap->refcount > 0 || ap->config_ap_never_release; } static struct adiv5_ap *_dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num) { if (!is_ap_num_valid(dap, ap_num)) { LOG_ERROR("Invalid AP#0x%" PRIx64, ap_num); return NULL; } if (is_adiv6(dap)) { for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) { struct adiv5_ap *ap = &dap->ap[i]; if (is_ap_in_use(ap) && ap->ap_num == ap_num) { ++ap->refcount; return ap; } } for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) { struct adiv5_ap *ap = &dap->ap[i]; if (!is_ap_in_use(ap)) { ap->ap_num = ap_num; ++ap->refcount; return ap; } } LOG_ERROR("No more AP available!"); return NULL; } /* ADIv5 */ struct adiv5_ap *ap = &dap->ap[ap_num]; ap->ap_num = ap_num; ++ap->refcount; return ap; } /* Return AP with specified ap_num. Increment AP refcount */ struct adiv5_ap *dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num) { struct adiv5_ap *ap = _dap_get_ap(dap, ap_num); if (ap) LOG_DEBUG("refcount AP#0x%" PRIx64 " get %u", ap_num, ap->refcount); return ap; } /* Return AP with specified ap_num. Increment AP refcount and keep it non-zero */ struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, uint64_t ap_num) { struct adiv5_ap *ap = _dap_get_ap(dap, ap_num); if (ap) { ap->config_ap_never_release = true; LOG_DEBUG("refcount AP#0x%" PRIx64 " get_config %u", ap_num, ap->refcount); } return ap; } /* Decrement AP refcount and release the AP when refcount reaches zero */ int dap_put_ap(struct adiv5_ap *ap) { if (ap->refcount == 0) { LOG_ERROR("BUG: refcount AP#0x%" PRIx64 " put underflow", ap->ap_num); return ERROR_FAIL; } --ap->refcount; LOG_DEBUG("refcount AP#0x%" PRIx64 " put %u", ap->ap_num, ap->refcount); if (!is_ap_in_use(ap)) { /* defaults from dap_instance_init() */ ap->ap_num = DP_APSEL_INVALID; ap->memaccess_tck = 255; ap->tar_autoincr_block = (1 << 10); ap->csw_default = CSW_AHB_DEFAULT; ap->cfg_reg = MEM_AP_REG_CFG_INVALID; } return ERROR_OK; } static int dap_get_debugbase(struct adiv5_ap *ap, target_addr_t *dbgbase, uint32_t *apid) { struct adiv5_dap *dap = ap->dap; int retval; uint32_t baseptr_upper, baseptr_lower; if (ap->cfg_reg == MEM_AP_REG_CFG_INVALID) { retval = dap_queue_ap_read(ap, MEM_AP_REG_CFG(dap), &ap->cfg_reg); if (retval != ERROR_OK) return retval; } retval = dap_queue_ap_read(ap, MEM_AP_REG_BASE(dap), &baseptr_lower); if (retval != ERROR_OK) return retval; retval = dap_queue_ap_read(ap, AP_REG_IDR(dap), apid); if (retval != ERROR_OK) return retval; /* MEM_AP_REG_BASE64 is defined as 'RES0'; can be read and then ignored on 32 bits AP */ if (ap->cfg_reg == MEM_AP_REG_CFG_INVALID || is_64bit_ap(ap)) { retval = dap_queue_ap_read(ap, MEM_AP_REG_BASE64(dap), &baseptr_upper); if (retval != ERROR_OK) return retval; } retval = dap_run(dap); if (retval != ERROR_OK) return retval; if (!is_64bit_ap(ap)) baseptr_upper = 0; *dbgbase = (((target_addr_t)baseptr_upper) << 32) | baseptr_lower; return ERROR_OK; } int adiv6_dap_read_baseptr(struct command_invocation *cmd, struct adiv5_dap *dap, uint64_t *baseptr) { uint32_t baseptr_lower, baseptr_upper = 0; int retval; if (dap->asize > 32) { retval = dap_queue_dp_read(dap, DP_BASEPTR1, &baseptr_upper); if (retval != ERROR_OK) return retval; } retval = dap_dp_read_atomic(dap, DP_BASEPTR0, &baseptr_lower); if (retval != ERROR_OK) return retval; if ((baseptr_lower & DP_BASEPTR0_VALID) != DP_BASEPTR0_VALID) { command_print(cmd, "System root table not present"); return ERROR_FAIL; } baseptr_lower &= ~0x0fff; *baseptr = (((uint64_t)baseptr_upper) << 32) | baseptr_lower; return ERROR_OK; } /** * Method to access the CoreSight component. * On ADIv5, CoreSight components are on the bus behind a MEM-AP. * On ADIv6, CoreSight components can either be on the bus behind a MEM-AP * or directly in the AP. */ enum coresight_access_mode { CS_ACCESS_AP, CS_ACCESS_MEM_AP, }; /** Holds registers and coordinates of a CoreSight component */ struct cs_component_vals { struct adiv5_ap *ap; target_addr_t component_base; uint64_t pid; uint32_t cid; uint32_t devarch; uint32_t devid; uint32_t devtype_memtype; enum coresight_access_mode mode; }; /** * Helper to read CoreSight component's registers, either on the bus * behind a MEM-AP or directly in the AP. * * @param mode Method to access the component (AP or MEM-AP). * @param ap Pointer to AP containing the component. * @param component_base On MEM-AP access method, base address of the component. * @param reg Offset of the component's register to read. * @param value Pointer to the store the read value. * * @return ERROR_OK on success, else a fault code. */ static int dap_queue_read_reg(enum coresight_access_mode mode, struct adiv5_ap *ap, uint64_t component_base, unsigned int reg, uint32_t *value) { if (mode == CS_ACCESS_AP) return dap_queue_ap_read(ap, reg, value); /* mode == CS_ACCESS_MEM_AP */ return mem_ap_read_u32(ap, component_base + reg, value); } /** * Read the CoreSight registers needed during ROM Table Parsing (RTP). * * @param mode Method to access the component (AP or MEM-AP). * @param ap Pointer to AP containing the component. * @param component_base On MEM-AP access method, base address of the component. * @param v Pointer to the struct holding the value of registers. * * @return ERROR_OK on success, else a fault code. */ static int rtp_read_cs_regs(enum coresight_access_mode mode, struct adiv5_ap *ap, target_addr_t component_base, struct cs_component_vals *v) { assert(IS_ALIGNED(component_base, ARM_CS_ALIGN)); assert(ap && v); uint32_t cid0, cid1, cid2, cid3; uint32_t pid0, pid1, pid2, pid3, pid4; int retval = ERROR_OK; v->ap = ap; v->component_base = component_base; v->mode = mode; /* sort by offset to gain speed */ /* * Registers DEVARCH, DEVID and DEVTYPE are valid on Class 0x9 devices * only, but are at offset above 0xf00, so can be read on any device * without triggering error. Read them for eventual use on Class 0x9. */ if (retval == ERROR_OK) retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_C9_DEVARCH, &v->devarch); if (retval == ERROR_OK) retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_C9_DEVID, &v->devid); /* Same address as ARM_CS_C1_MEMTYPE */ if (retval == ERROR_OK) retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_C9_DEVTYPE, &v->devtype_memtype); if (retval == ERROR_OK) retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR4, &pid4); if (retval == ERROR_OK) retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR0, &pid0); if (retval == ERROR_OK) retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR1, &pid1); if (retval == ERROR_OK) retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR2, &pid2); if (retval == ERROR_OK) retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR3, &pid3); if (retval == ERROR_OK) retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR0, &cid0); if (retval == ERROR_OK) retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR1, &cid1); if (retval == ERROR_OK) retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR2, &cid2); if (retval == ERROR_OK) retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR3, &cid3); if (retval == ERROR_OK) retval = dap_run(ap->dap); if (retval != ERROR_OK) { LOG_DEBUG("Failed read CoreSight registers"); return retval; } v->cid = (cid3 & 0xff) << 24 | (cid2 & 0xff) << 16 | (cid1 & 0xff) << 8 | (cid0 & 0xff); v->pid = (uint64_t)(pid4 & 0xff) << 32 | (pid3 & 0xff) << 24 | (pid2 & 0xff) << 16 | (pid1 & 0xff) << 8 | (pid0 & 0xff); return ERROR_OK; } /* Part number interpretations are from Cortex * core specs, the CoreSight components TRM * (ARM DDI 0314H), CoreSight System Design * Guide (ARM DGI 0012D) and ETM specs; also * from chip observation (e.g. TI SDTI). */ static const struct dap_part_nums { uint16_t designer_id; uint16_t part_num; const char *type; const char *full; } dap_part_nums[] = { { ARM_ID, 0x000, "Cortex-M3 SCS", "(System Control Space)", }, { ARM_ID, 0x001, "Cortex-M3 ITM", "(Instrumentation Trace Module)", }, { ARM_ID, 0x002, "Cortex-M3 DWT", "(Data Watchpoint and Trace)", }, { ARM_ID, 0x003, "Cortex-M3 FPB", "(Flash Patch and Breakpoint)", }, { ARM_ID, 0x008, "Cortex-M0 SCS", "(System Control Space)", }, { ARM_ID, 0x00a, "Cortex-M0 DWT", "(Data Watchpoint and Trace)", }, { ARM_ID, 0x00b, "Cortex-M0 BPU", "(Breakpoint Unit)", }, { ARM_ID, 0x00c, "Cortex-M4 SCS", "(System Control Space)", }, { ARM_ID, 0x00d, "CoreSight ETM11", "(Embedded Trace)", }, { ARM_ID, 0x00e, "Cortex-M7 FPB", "(Flash Patch and Breakpoint)", }, { ARM_ID, 0x193, "SoC-600 TSGEN", "(Timestamp Generator)", }, { ARM_ID, 0x470, "Cortex-M1 ROM", "(ROM Table)", }, { ARM_ID, 0x471, "Cortex-M0 ROM", "(ROM Table)", }, { ARM_ID, 0x490, "Cortex-A15 GIC", "(Generic Interrupt Controller)", }, { ARM_ID, 0x492, "Cortex-R52 GICD", "(Distributor)", }, { ARM_ID, 0x493, "Cortex-R52 GICR", "(Redistributor)", }, { ARM_ID, 0x4a1, "Cortex-A53 ROM", "(v8 Memory Map ROM Table)", }, { ARM_ID, 0x4a2, "Cortex-A57 ROM", "(ROM Table)", }, { ARM_ID, 0x4a3, "Cortex-A53 ROM", "(v7 Memory Map ROM Table)", }, { ARM_ID, 0x4a4, "Cortex-A72 ROM", "(ROM Table)", }, { ARM_ID, 0x4a9, "Cortex-A9 ROM", "(ROM Table)", }, { ARM_ID, 0x4aa, "Cortex-A35 ROM", "(v8 Memory Map ROM Table)", }, { ARM_ID, 0x4af, "Cortex-A15 ROM", "(ROM Table)", }, { ARM_ID, 0x4b5, "Cortex-R5 ROM", "(ROM Table)", }, { ARM_ID, 0x4b8, "Cortex-R52 ROM", "(ROM Table)", }, { ARM_ID, 0x4c0, "Cortex-M0+ ROM", "(ROM Table)", }, { ARM_ID, 0x4c3, "Cortex-M3 ROM", "(ROM Table)", }, { ARM_ID, 0x4c4, "Cortex-M4 ROM", "(ROM Table)", }, { ARM_ID, 0x4c7, "Cortex-M7 PPB ROM", "(Private Peripheral Bus ROM Table)", }, { ARM_ID, 0x4c8, "Cortex-M7 ROM", "(ROM Table)", }, { ARM_ID, 0x4e0, "Cortex-A35 ROM", "(v7 Memory Map ROM Table)", }, { ARM_ID, 0x4e4, "Cortex-A76 ROM", "(ROM Table)", }, { ARM_ID, 0x906, "CoreSight CTI", "(Cross Trigger)", }, { ARM_ID, 0x907, "CoreSight ETB", "(Trace Buffer)", }, { ARM_ID, 0x908, "CoreSight CSTF", "(Trace Funnel)", }, { ARM_ID, 0x909, "CoreSight ATBR", "(Advanced Trace Bus Replicator)", }, { ARM_ID, 0x910, "CoreSight ETM9", "(Embedded Trace)", }, { ARM_ID, 0x912, "CoreSight TPIU", "(Trace Port Interface Unit)", }, { ARM_ID, 0x913, "CoreSight ITM", "(Instrumentation Trace Macrocell)", }, { ARM_ID, 0x914, "CoreSight SWO", "(Single Wire Output)", }, { ARM_ID, 0x917, "CoreSight HTM", "(AHB Trace Macrocell)", }, { ARM_ID, 0x920, "CoreSight ETM11", "(Embedded Trace)", }, { ARM_ID, 0x921, "Cortex-A8 ETM", "(Embedded Trace)", }, { ARM_ID, 0x922, "Cortex-A8 CTI", "(Cross Trigger)", }, { ARM_ID, 0x923, "Cortex-M3 TPIU", "(Trace Port Interface Unit)", }, { ARM_ID, 0x924, "Cortex-M3 ETM", "(Embedded Trace)", }, { ARM_ID, 0x925, "Cortex-M4 ETM", "(Embedded Trace)", }, { ARM_ID, 0x930, "Cortex-R4 ETM", "(Embedded Trace)", }, { ARM_ID, 0x931, "Cortex-R5 ETM", "(Embedded Trace)", }, { ARM_ID, 0x932, "CoreSight MTB-M0+", "(Micro Trace Buffer)", }, { ARM_ID, 0x941, "CoreSight TPIU-Lite", "(Trace Port Interface Unit)", }, { ARM_ID, 0x950, "Cortex-A9 PTM", "(Program Trace Macrocell)", }, { ARM_ID, 0x955, "Cortex-A5 ETM", "(Embedded Trace)", }, { ARM_ID, 0x95a, "Cortex-A72 ETM", "(Embedded Trace)", }, { ARM_ID, 0x95b, "Cortex-A17 PTM", "(Program Trace Macrocell)", }, { ARM_ID, 0x95d, "Cortex-A53 ETM", "(Embedded Trace)", }, { ARM_ID, 0x95e, "Cortex-A57 ETM", "(Embedded Trace)", }, { ARM_ID, 0x95f, "Cortex-A15 PTM", "(Program Trace Macrocell)", }, { ARM_ID, 0x961, "CoreSight TMC", "(Trace Memory Controller)", }, { ARM_ID, 0x962, "CoreSight STM", "(System Trace Macrocell)", }, { ARM_ID, 0x975, "Cortex-M7 ETM", "(Embedded Trace)", }, { ARM_ID, 0x9a0, "CoreSight PMU", "(Performance Monitoring Unit)", }, { ARM_ID, 0x9a1, "Cortex-M4 TPIU", "(Trace Port Interface Unit)", }, { ARM_ID, 0x9a4, "CoreSight GPR", "(Granular Power Requester)", }, { ARM_ID, 0x9a5, "Cortex-A5 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9a7, "Cortex-A7 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9a8, "Cortex-A53 CTI", "(Cross Trigger)", }, { ARM_ID, 0x9a9, "Cortex-M7 TPIU", "(Trace Port Interface Unit)", }, { ARM_ID, 0x9ae, "Cortex-A17 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9af, "Cortex-A15 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9b6, "Cortex-R52 PMU/CTI/ETM", "(Performance Monitor Unit/Cross Trigger/ETM)", }, { ARM_ID, 0x9b7, "Cortex-R7 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d3, "Cortex-A53 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d7, "Cortex-A57 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d8, "Cortex-A72 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9da, "Cortex-A35 PMU/CTI/ETM", "(Performance Monitor Unit/Cross Trigger/ETM)", }, { ARM_ID, 0x9e2, "SoC-600 APB-AP", "(APB4 Memory Access Port)", }, { ARM_ID, 0x9e3, "SoC-600 AHB-AP", "(AHB5 Memory Access Port)", }, { ARM_ID, 0x9e4, "SoC-600 AXI-AP", "(AXI Memory Access Port)", }, { ARM_ID, 0x9e5, "SoC-600 APv1 Adapter", "(Access Port v1 Adapter)", }, { ARM_ID, 0x9e6, "SoC-600 JTAG-AP", "(JTAG Access Port)", }, { ARM_ID, 0x9e7, "SoC-600 TPIU", "(Trace Port Interface Unit)", }, { ARM_ID, 0x9e8, "SoC-600 TMC ETR/ETS", "(Embedded Trace Router/Streamer)", }, { ARM_ID, 0x9e9, "SoC-600 TMC ETB", "(Embedded Trace Buffer)", }, { ARM_ID, 0x9ea, "SoC-600 TMC ETF", "(Embedded Trace FIFO)", }, { ARM_ID, 0x9eb, "SoC-600 ATB Funnel", "(Trace Funnel)", }, { ARM_ID, 0x9ec, "SoC-600 ATB Replicator", "(Trace Replicator)", }, { ARM_ID, 0x9ed, "SoC-600 CTI", "(Cross Trigger)", }, { ARM_ID, 0x9ee, "SoC-600 CATU", "(Address Translation Unit)", }, { ARM_ID, 0xc05, "Cortex-A5 Debug", "(Debug Unit)", }, { ARM_ID, 0xc07, "Cortex-A7 Debug", "(Debug Unit)", }, { ARM_ID, 0xc08, "Cortex-A8 Debug", "(Debug Unit)", }, { ARM_ID, 0xc09, "Cortex-A9 Debug", "(Debug Unit)", }, { ARM_ID, 0xc0e, "Cortex-A17 Debug", "(Debug Unit)", }, { ARM_ID, 0xc0f, "Cortex-A15 Debug", "(Debug Unit)", }, { ARM_ID, 0xc14, "Cortex-R4 Debug", "(Debug Unit)", }, { ARM_ID, 0xc15, "Cortex-R5 Debug", "(Debug Unit)", }, { ARM_ID, 0xc17, "Cortex-R7 Debug", "(Debug Unit)", }, { ARM_ID, 0xd03, "Cortex-A53 Debug", "(Debug Unit)", }, { ARM_ID, 0xd04, "Cortex-A35 Debug", "(Debug Unit)", }, { ARM_ID, 0xd07, "Cortex-A57 Debug", "(Debug Unit)", }, { ARM_ID, 0xd08, "Cortex-A72 Debug", "(Debug Unit)", }, { ARM_ID, 0xd0b, "Cortex-A76 Debug", "(Debug Unit)", }, { ARM_ID, 0xd0c, "Neoverse N1", "(Debug Unit)", }, { ARM_ID, 0xd13, "Cortex-R52 Debug", "(Debug Unit)", }, { ARM_ID, 0xd49, "Neoverse N2", "(Debug Unit)", }, { 0x017, 0x120, "TI SDTI", "(System Debug Trace Interface)", }, /* from OMAP3 memmap */ { 0x017, 0x343, "TI DAPCTL", "", }, /* from OMAP3 memmap */ { 0x017, 0x9af, "MSP432 ROM", "(ROM Table)" }, { 0x01f, 0xcd0, "Atmel CPU with DSU", "(CPU)" }, { 0x041, 0x1db, "XMC4500 ROM", "(ROM Table)" }, { 0x041, 0x1df, "XMC4700/4800 ROM", "(ROM Table)" }, { 0x041, 0x1ed, "XMC1000 ROM", "(ROM Table)" }, { 0x065, 0x000, "SHARC+/Blackfin+", "", }, { 0x070, 0x440, "Qualcomm QDSS Component v1", "(Qualcomm Designed CoreSight Component v1)", }, { 0x0bf, 0x100, "Brahma-B53 Debug", "(Debug Unit)", }, { 0x0bf, 0x9d3, "Brahma-B53 PMU", "(Performance Monitor Unit)", }, { 0x0bf, 0x4a1, "Brahma-B53 ROM", "(ROM Table)", }, { 0x0bf, 0x721, "Brahma-B53 ROM", "(ROM Table)", }, { 0x1eb, 0x181, "Tegra 186 ROM", "(ROM Table)", }, { 0x1eb, 0x202, "Denver ETM", "(Denver Embedded Trace)", }, { 0x1eb, 0x211, "Tegra 210 ROM", "(ROM Table)", }, { 0x1eb, 0x302, "Denver Debug", "(Debug Unit)", }, { 0x1eb, 0x402, "Denver PMU", "(Performance Monitor Unit)", }, }; static const struct dap_part_nums *pidr_to_part_num(unsigned int designer_id, unsigned int part_num) { static const struct dap_part_nums unknown = { .type = "Unrecognized", .full = "", }; for (unsigned int i = 0; i < ARRAY_SIZE(dap_part_nums); i++) if (dap_part_nums[i].designer_id == designer_id && dap_part_nums[i].part_num == part_num) return &dap_part_nums[i]; return &unknown; } static int dap_devtype_display(struct command_invocation *cmd, uint32_t devtype) { const char *major = "Reserved", *subtype = "Reserved"; const unsigned int minor = (devtype & ARM_CS_C9_DEVTYPE_SUB_MASK) >> ARM_CS_C9_DEVTYPE_SUB_SHIFT; const unsigned int devtype_major = (devtype & ARM_CS_C9_DEVTYPE_MAJOR_MASK) >> ARM_CS_C9_DEVTYPE_MAJOR_SHIFT; switch (devtype_major) { case 0: major = "Miscellaneous"; switch (minor) { case 0: subtype = "other"; break; case 4: subtype = "Validation component"; break; } break; case 1: major = "Trace Sink"; switch (minor) { case 0: subtype = "other"; break; case 1: subtype = "Port"; break; case 2: subtype = "Buffer"; break; case 3: subtype = "Router"; break; } break; case 2: major = "Trace Link"; switch (minor) { case 0: subtype = "other"; break; case 1: subtype = "Funnel, router"; break; case 2: subtype = "Filter"; break; case 3: subtype = "FIFO, buffer"; break; } break; case 3: major = "Trace Source"; switch (minor) { case 0: subtype = "other"; break; case 1: subtype = "Processor"; break; case 2: subtype = "DSP"; break; case 3: subtype = "Engine/Coprocessor"; break; case 4: subtype = "Bus"; break; case 6: subtype = "Software"; break; } break; case 4: major = "Debug Control"; switch (minor) { case 0: subtype = "other"; break; case 1: subtype = "Trigger Matrix"; break; case 2: subtype = "Debug Auth"; break; case 3: subtype = "Power Requestor"; break; } break; case 5: major = "Debug Logic"; switch (minor) { case 0: subtype = "other"; break; case 1: subtype = "Processor"; break; case 2: subtype = "DSP"; break; case 3: subtype = "Engine/Coprocessor"; break; case 4: subtype = "Bus"; break; case 5: subtype = "Memory"; break; } break; case 6: major = "Performance Monitor"; switch (minor) { case 0: subtype = "other"; break; case 1: subtype = "Processor"; break; case 2: subtype = "DSP"; break; case 3: subtype = "Engine/Coprocessor"; break; case 4: subtype = "Bus"; break; case 5: subtype = "Memory"; break; } break; } command_print(cmd, "\t\tType is 0x%02x, %s, %s", devtype & ARM_CS_C9_DEVTYPE_MASK, major, subtype); return ERROR_OK; } /** * Actions/operations to be executed while parsing ROM tables. */ struct rtp_ops { /** * Executed at the start of a new AP, typically to print the AP header. * @param ap Pointer to AP. * @param depth The current depth level of ROM table. * @param priv Pointer to private data. * @return ERROR_OK on success, else a fault code. */ int (*ap_header)(struct adiv5_ap *ap, int depth, void *priv); /** * Executed at the start of a new MEM-AP, typically to print the MEM-AP header. * @param retval Error encountered while reading AP. * @param ap Pointer to AP. * @param dbgbase Value of MEM-AP Debug Base Address register. * @param apid Value of MEM-AP IDR Identification Register. * @param depth The current depth level of ROM table. * @param priv Pointer to private data. * @return ERROR_OK on success, else a fault code. */ int (*mem_ap_header)(int retval, struct adiv5_ap *ap, uint64_t dbgbase, uint32_t apid, int depth, void *priv); /** * Executed when a CoreSight component is parsed, typically to print * information on the component. * @param retval Error encountered while reading component's registers. * @param v Pointer to a container of the component's registers. * @param depth The current depth level of ROM table. * @param priv Pointer to private data. * @return ERROR_OK on success, else a fault code. */ int (*cs_component)(int retval, struct cs_component_vals *v, int depth, void *priv); /** * Executed for each entry of a ROM table, typically to print the entry * and information about validity or end-of-table mark. * @param retval Error encountered while reading the ROM table entry. * @param depth The current depth level of ROM table. * @param offset The offset of the entry in the ROM table. * @param romentry The value of the ROM table entry. * @param priv Pointer to private data. * @return ERROR_OK on success, else a fault code. */ int (*rom_table_entry)(int retval, int depth, unsigned int offset, uint64_t romentry, void *priv); /** * Private data */ void *priv; }; /** * Wrapper around struct rtp_ops::ap_header. */ static int rtp_ops_ap_header(const struct rtp_ops *ops, struct adiv5_ap *ap, int depth) { if (ops->ap_header) return ops->ap_header(ap, depth, ops->priv); return ERROR_OK; } /** * Wrapper around struct rtp_ops::mem_ap_header. * Input parameter @a retval is propagated. */ static int rtp_ops_mem_ap_header(const struct rtp_ops *ops, int retval, struct adiv5_ap *ap, uint64_t dbgbase, uint32_t apid, int depth) { if (!ops->mem_ap_header) return retval; int retval1 = ops->mem_ap_header(retval, ap, dbgbase, apid, depth, ops->priv); if (retval != ERROR_OK) return retval; return retval1; } /** * Wrapper around struct rtp_ops::cs_component. * Input parameter @a retval is propagated. */ static int rtp_ops_cs_component(const struct rtp_ops *ops, int retval, struct cs_component_vals *v, int depth) { if (!ops->cs_component) return retval; int retval1 = ops->cs_component(retval, v, depth, ops->priv); if (retval != ERROR_OK) return retval; return retval1; } /** * Wrapper around struct rtp_ops::rom_table_entry. * Input parameter @a retval is propagated. */ static int rtp_ops_rom_table_entry(const struct rtp_ops *ops, int retval, int depth, unsigned int offset, uint64_t romentry) { if (!ops->rom_table_entry) return retval; int retval1 = ops->rom_table_entry(retval, depth, offset, romentry, ops->priv); if (retval != ERROR_OK) return retval; return retval1; } /* Broken ROM tables can have circular references. Stop after a while */ #define ROM_TABLE_MAX_DEPTH (16) /** * Value used only during lookup of a CoreSight component in ROM table. * Return CORESIGHT_COMPONENT_FOUND when component is found. * Return ERROR_OK when component is not found yet. * Return any other ERROR_* in case of error. */ #define CORESIGHT_COMPONENT_FOUND (1) static int rtp_ap(const struct rtp_ops *ops, struct adiv5_ap *ap, int depth); static int rtp_cs_component(enum coresight_access_mode mode, const struct rtp_ops *ops, struct adiv5_ap *ap, target_addr_t dbgbase, bool *is_mem_ap, int depth); static int rtp_rom_loop(enum coresight_access_mode mode, const struct rtp_ops *ops, struct adiv5_ap *ap, target_addr_t base_address, int depth, unsigned int width, unsigned int max_entries) { /* ADIv6 AP ROM table provide offset from current AP */ if (mode == CS_ACCESS_AP) base_address = ap->ap_num; assert(IS_ALIGNED(base_address, ARM_CS_ALIGN)); unsigned int offset = 0; while (max_entries--) { uint64_t romentry; uint32_t romentry_low, romentry_high; target_addr_t component_base; unsigned int saved_offset = offset; int retval = dap_queue_read_reg(mode, ap, base_address, offset, &romentry_low); offset += 4; if (retval == ERROR_OK && width == 64) { retval = dap_queue_read_reg(mode, ap, base_address, offset, &romentry_high); offset += 4; } if (retval == ERROR_OK) retval = dap_run(ap->dap); if (retval != ERROR_OK) { LOG_DEBUG("Failed read ROM table entry"); return retval; } if (width == 64) { romentry = (((uint64_t)romentry_high) << 32) | romentry_low; component_base = base_address + ((((uint64_t)romentry_high) << 32) | (romentry_low & ARM_CS_ROMENTRY_OFFSET_MASK)); } else { romentry = romentry_low; /* "romentry" is signed */ component_base = base_address + (int32_t)(romentry_low & ARM_CS_ROMENTRY_OFFSET_MASK); if (!is_64bit_ap(ap)) component_base = (uint32_t)component_base; } retval = rtp_ops_rom_table_entry(ops, retval, depth, saved_offset, romentry); if (retval != ERROR_OK) return retval; if (romentry == 0) { /* End of ROM table */ break; } if (!(romentry & ARM_CS_ROMENTRY_PRESENT)) continue; /* Recurse */ if (mode == CS_ACCESS_AP) { struct adiv5_ap *next_ap = dap_get_ap(ap->dap, component_base); if (!next_ap) { LOG_DEBUG("Wrong AP # 0x%" PRIx64, component_base); continue; } retval = rtp_ap(ops, next_ap, depth + 1); dap_put_ap(next_ap); } else { /* mode == CS_ACCESS_MEM_AP */ retval = rtp_cs_component(mode, ops, ap, component_base, NULL, depth + 1); } if (retval == CORESIGHT_COMPONENT_FOUND) return CORESIGHT_COMPONENT_FOUND; if (retval != ERROR_OK) { /* TODO: do we need to send an ABORT before continuing? */ LOG_DEBUG("Ignore error parsing CoreSight component"); continue; } } return ERROR_OK; } static int rtp_cs_component(enum coresight_access_mode mode, const struct rtp_ops *ops, struct adiv5_ap *ap, target_addr_t base_address, bool *is_mem_ap, int depth) { struct cs_component_vals v; int retval; assert(IS_ALIGNED(base_address, ARM_CS_ALIGN)); if (is_mem_ap) *is_mem_ap = false; if (depth > ROM_TABLE_MAX_DEPTH) retval = ERROR_FAIL; else retval = rtp_read_cs_regs(mode, ap, base_address, &v); retval = rtp_ops_cs_component(ops, retval, &v, depth); if (retval == CORESIGHT_COMPONENT_FOUND) return CORESIGHT_COMPONENT_FOUND; if (retval != ERROR_OK) return ERROR_OK; /* Don't abort recursion */ if (!is_valid_arm_cs_cidr(v.cid)) return ERROR_OK; /* Don't abort recursion */ const unsigned int class = ARM_CS_CIDR_CLASS(v.cid); if (class == ARM_CS_CLASS_0X1_ROM_TABLE) return rtp_rom_loop(mode, ops, ap, base_address, depth, 32, 960); if (class == ARM_CS_CLASS_0X9_CS_COMPONENT) { if ((v.devarch & ARM_CS_C9_DEVARCH_PRESENT) == 0) return ERROR_OK; if (is_mem_ap) { if ((v.devarch & DEVARCH_ID_MASK) == DEVARCH_MEM_AP) *is_mem_ap = true; /* SoC-600 APv1 Adapter */ if ((v.devarch & DEVARCH_ID_MASK) == DEVARCH_UNKNOWN_V2 && ARM_CS_PIDR_DESIGNER(v.pid) == ARM_ID && ARM_CS_PIDR_PART(v.pid) == 0x9e5) *is_mem_ap = true; } /* quit if not ROM table */ if ((v.devarch & DEVARCH_ID_MASK) != DEVARCH_ROM_C_0X9) return ERROR_OK; if ((v.devid & ARM_CS_C9_DEVID_FORMAT_MASK) == ARM_CS_C9_DEVID_FORMAT_64BIT) return rtp_rom_loop(mode, ops, ap, base_address, depth, 64, 256); else return rtp_rom_loop(mode, ops, ap, base_address, depth, 32, 512); } /* Class other than 0x1 and 0x9 */ return ERROR_OK; } static int rtp_ap(const struct rtp_ops *ops, struct adiv5_ap *ap, int depth) { uint32_t apid; target_addr_t dbgbase, invalid_entry; int retval = rtp_ops_ap_header(ops, ap, depth); if (retval != ERROR_OK || depth > ROM_TABLE_MAX_DEPTH) return ERROR_OK; /* Don't abort recursion */ if (is_adiv6(ap->dap)) { bool is_mem_ap; retval = rtp_cs_component(CS_ACCESS_AP, ops, ap, 0, &is_mem_ap, depth); if (retval == CORESIGHT_COMPONENT_FOUND) return CORESIGHT_COMPONENT_FOUND; if (retval != ERROR_OK) return ERROR_OK; /* Don't abort recursion */ if (!is_mem_ap) return ERROR_OK; /* Continue for an ADIv6 MEM-AP or SoC-600 APv1 Adapter */ } /* Now we read ROM table ID registers, ref. ARM IHI 0029B sec */ retval = dap_get_debugbase(ap, &dbgbase, &apid); if (retval != ERROR_OK) return retval; retval = rtp_ops_mem_ap_header(ops, retval, ap, dbgbase, apid, depth); if (retval != ERROR_OK) return retval; if (apid == 0) return ERROR_FAIL; /* NOTE: a MEM-AP may have a single CoreSight component that's * not a ROM table ... or have no such components at all. */ const unsigned int class = (apid & AP_REG_IDR_CLASS_MASK) >> AP_REG_IDR_CLASS_SHIFT; if (class == AP_REG_IDR_CLASS_MEM_AP) { if (is_64bit_ap(ap)) invalid_entry = 0xFFFFFFFFFFFFFFFFull; else invalid_entry = 0xFFFFFFFFul; if (dbgbase != invalid_entry && (dbgbase & 0x3) != 0x2) { retval = rtp_cs_component(CS_ACCESS_MEM_AP, ops, ap, dbgbase & 0xFFFFFFFFFFFFF000ull, NULL, depth); if (retval == CORESIGHT_COMPONENT_FOUND) return CORESIGHT_COMPONENT_FOUND; } } return ERROR_OK; } /* Actions for command "dap info" */ static int dap_info_ap_header(struct adiv5_ap *ap, int depth, void *priv) { struct command_invocation *cmd = priv; if (depth > ROM_TABLE_MAX_DEPTH) { command_print(cmd, "\tTables too deep"); return ERROR_FAIL; } command_print(cmd, "%sAP # 0x%" PRIx64, (depth) ? "\t\t" : "", ap->ap_num); return ERROR_OK; } static int dap_info_mem_ap_header(int retval, struct adiv5_ap *ap, target_addr_t dbgbase, uint32_t apid, int depth, void *priv) { struct command_invocation *cmd = priv; target_addr_t invalid_entry; char tabs[17] = ""; if (retval != ERROR_OK) { command_print(cmd, "\t\tCan't read MEM-AP, the corresponding core might be turned off"); return retval; } if (depth > ROM_TABLE_MAX_DEPTH) { command_print(cmd, "\tTables too deep"); return ERROR_FAIL; } if (depth) snprintf(tabs, sizeof(tabs), "\t[L%02d] ", depth); command_print(cmd, "\t\tAP ID register 0x%8.8" PRIx32, apid); if (apid == 0) { command_print(cmd, "\t\tNo AP found at this AP#0x%" PRIx64, ap->ap_num); return ERROR_FAIL; } command_print(cmd, "\t\tType is %s", ap_type_to_description(apid & AP_TYPE_MASK)); /* NOTE: a MEM-AP may have a single CoreSight component that's * not a ROM table ... or have no such components at all. */ const unsigned int class = (apid & AP_REG_IDR_CLASS_MASK) >> AP_REG_IDR_CLASS_SHIFT; if (class == AP_REG_IDR_CLASS_MEM_AP) { if (is_64bit_ap(ap)) invalid_entry = 0xFFFFFFFFFFFFFFFFull; else invalid_entry = 0xFFFFFFFFul; command_print(cmd, "%sMEM-AP BASE " TARGET_ADDR_FMT, tabs, dbgbase); if (dbgbase == invalid_entry || (dbgbase & 0x3) == 0x2) { command_print(cmd, "\t\tNo ROM table present"); } else { if (dbgbase & 0x01) command_print(cmd, "\t\tValid ROM table present"); else command_print(cmd, "\t\tROM table in legacy format"); } } return ERROR_OK; } static int dap_info_cs_component(int retval, struct cs_component_vals *v, int depth, void *priv) { struct command_invocation *cmd = priv; if (depth > ROM_TABLE_MAX_DEPTH) { command_print(cmd, "\tTables too deep"); return ERROR_FAIL; } if (v->mode == CS_ACCESS_MEM_AP) command_print(cmd, "\t\tComponent base address " TARGET_ADDR_FMT, v->component_base); if (retval != ERROR_OK) { command_print(cmd, "\t\tCan't read component, the corresponding core might be turned off"); return retval; } if (!is_valid_arm_cs_cidr(v->cid)) { command_print(cmd, "\t\tInvalid CID 0x%08" PRIx32, v->cid); return ERROR_OK; /* Don't abort recursion */ } /* component may take multiple 4K pages */ uint32_t size = ARM_CS_PIDR_SIZE(v->pid); if (size > 0) command_print(cmd, "\t\tStart address " TARGET_ADDR_FMT, v->component_base - 0x1000 * size); command_print(cmd, "\t\tPeripheral ID 0x%010" PRIx64, v->pid); const unsigned int part_num = ARM_CS_PIDR_PART(v->pid); unsigned int designer_id = ARM_CS_PIDR_DESIGNER(v->pid); if (v->pid & ARM_CS_PIDR_JEDEC) { /* JEP106 code */ command_print(cmd, "\t\tDesigner is 0x%03x, %s", designer_id, jep106_manufacturer(designer_id)); } else { /* Legacy ASCII ID, clear invalid bits */ designer_id &= 0x7f; command_print(cmd, "\t\tDesigner ASCII code 0x%02x, %s", designer_id, designer_id == 0x41 ? "ARM" : "<unknown>"); } const struct dap_part_nums *partnum = pidr_to_part_num(designer_id, part_num); command_print(cmd, "\t\tPart is 0x%03x, %s %s", part_num, partnum->type, partnum->full); const unsigned int class = ARM_CS_CIDR_CLASS(v->cid); command_print(cmd, "\t\tComponent class is 0x%x, %s", class, class_description[class]); if (class == ARM_CS_CLASS_0X1_ROM_TABLE) { if (v->devtype_memtype & ARM_CS_C1_MEMTYPE_SYSMEM_MASK) command_print(cmd, "\t\tMEMTYPE system memory present on bus"); else command_print(cmd, "\t\tMEMTYPE system memory not present: dedicated debug bus"); return ERROR_OK; } if (class == ARM_CS_CLASS_0X9_CS_COMPONENT) { dap_devtype_display(cmd, v->devtype_memtype); /* REVISIT also show ARM_CS_C9_DEVID */ if ((v->devarch & ARM_CS_C9_DEVARCH_PRESENT) == 0) return ERROR_OK; unsigned int architect_id = ARM_CS_C9_DEVARCH_ARCHITECT(v->devarch); unsigned int revision = ARM_CS_C9_DEVARCH_REVISION(v->devarch); command_print(cmd, "\t\tDev Arch is 0x%08" PRIx32 ", %s \"%s\" rev.%u", v->devarch, jep106_manufacturer(architect_id), class0x9_devarch_description(v->devarch), revision); if ((v->devarch & DEVARCH_ID_MASK) == DEVARCH_ROM_C_0X9) { command_print(cmd, "\t\tType is ROM table"); if (v->devid & ARM_CS_C9_DEVID_SYSMEM_MASK) command_print(cmd, "\t\tMEMTYPE system memory present on bus"); else command_print(cmd, "\t\tMEMTYPE system memory not present: dedicated debug bus"); } return ERROR_OK; } /* Class other than 0x1 and 0x9 */ return ERROR_OK; } static int dap_info_rom_table_entry(int retval, int depth, unsigned int offset, uint64_t romentry, void *priv) { struct command_invocation *cmd = priv; char tabs[16] = ""; if (depth) snprintf(tabs, sizeof(tabs), "[L%02d] ", depth); if (retval != ERROR_OK) { command_print(cmd, "\t%sROMTABLE[0x%x] Read error", tabs, offset); command_print(cmd, "\t\tUnable to continue"); command_print(cmd, "\t%s\tStop parsing of ROM table", tabs); return retval; } command_print(cmd, "\t%sROMTABLE[0x%x] = 0x%08" PRIx64, tabs, offset, romentry); if (romentry == 0) { command_print(cmd, "\t%s\tEnd of ROM table", tabs); return ERROR_OK; } if (!(romentry & ARM_CS_ROMENTRY_PRESENT)) { command_print(cmd, "\t\tComponent not present"); return ERROR_OK; } return ERROR_OK; } int dap_info_command(struct command_invocation *cmd, struct adiv5_ap *ap) { struct rtp_ops dap_info_ops = { .ap_header = dap_info_ap_header, .mem_ap_header = dap_info_mem_ap_header, .cs_component = dap_info_cs_component, .rom_table_entry = dap_info_rom_table_entry, .priv = cmd, }; return rtp_ap(&dap_info_ops, ap, 0); } /* Actions for dap_lookup_cs_component() */ struct dap_lookup_data { /* input */ unsigned int idx; unsigned int type; /* output */ uint64_t component_base; uint64_t ap_num; }; static int dap_lookup_cs_component_cs_component(int retval, struct cs_component_vals *v, int depth, void *priv) { struct dap_lookup_data *lookup = priv; if (retval != ERROR_OK) return retval; if (!is_valid_arm_cs_cidr(v->cid)) return ERROR_OK; const unsigned int class = ARM_CS_CIDR_CLASS(v->cid); if (class != ARM_CS_CLASS_0X9_CS_COMPONENT) return ERROR_OK; if ((v->devtype_memtype & ARM_CS_C9_DEVTYPE_MASK) != lookup->type) return ERROR_OK; if (lookup->idx) { /* search for next one */ --lookup->idx; return ERROR_OK; } /* Found! */ lookup->component_base = v->component_base; lookup->ap_num = v->ap->ap_num; return CORESIGHT_COMPONENT_FOUND; } int dap_lookup_cs_component(struct adiv5_ap *ap, uint8_t type, target_addr_t *addr, int32_t core_id) { struct dap_lookup_data lookup = { .type = type, .idx = core_id, }; struct rtp_ops dap_lookup_cs_component_ops = { .ap_header = NULL, .mem_ap_header = NULL, .cs_component = dap_lookup_cs_component_cs_component, .rom_table_entry = NULL, .priv = &lookup, }; int retval = rtp_ap(&dap_lookup_cs_component_ops, ap, 0); if (retval == CORESIGHT_COMPONENT_FOUND) { if (lookup.ap_num != ap->ap_num) { /* TODO: handle search from root ROM table */ LOG_DEBUG("CS lookup ended in AP # 0x%" PRIx64 ". Ignore it", lookup.ap_num); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } LOG_DEBUG("CS lookup found at 0x%" PRIx64, lookup.component_base); *addr = lookup.component_base; return ERROR_OK; } if (retval != ERROR_OK) { LOG_DEBUG("CS lookup error %d", retval); return retval; } LOG_DEBUG("CS lookup not found"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } enum adiv5_cfg_param { CFG_DAP, CFG_AP_NUM, CFG_BASEADDR, CFG_CTIBASE, /* DEPRECATED */ }; static const struct jim_nvp nvp_config_opts[] = { { .name = "-dap", .value = CFG_DAP }, { .name = "-ap-num", .value = CFG_AP_NUM }, { .name = "-baseaddr", .value = CFG_BASEADDR }, { .name = "-ctibase", .value = CFG_CTIBASE }, /* DEPRECATED */ { .name = NULL, .value = -1 } }; static int adiv5_jim_spot_configure(struct jim_getopt_info *goi, struct adiv5_dap **dap_p, uint64_t *ap_num_p, uint32_t *base_p) { assert(dap_p && ap_num_p); if (!goi->argc) return JIM_OK; Jim_SetEmptyResult(goi->interp); struct jim_nvp *n; int e = jim_nvp_name2value_obj(goi->interp, nvp_config_opts, goi->argv[0], &n); if (e != JIM_OK) return JIM_CONTINUE; /* base_p can be NULL, then '-baseaddr' option is treated as unknown */ if (!base_p && (n->value == CFG_BASEADDR || n->value == CFG_CTIBASE)) return JIM_CONTINUE; e = jim_getopt_obj(goi, NULL); if (e != JIM_OK) return e; switch (n->value) { case CFG_DAP: if (goi->isconfigure) { Jim_Obj *o_t; struct adiv5_dap *dap; e = jim_getopt_obj(goi, &o_t); if (e != JIM_OK) return e; dap = dap_instance_by_jim_obj(goi->interp, o_t); if (!dap) { Jim_SetResultString(goi->interp, "DAP name invalid!", -1); return JIM_ERR; } if (*dap_p && *dap_p != dap) { Jim_SetResultString(goi->interp, "DAP assignment cannot be changed!", -1); return JIM_ERR; } *dap_p = dap; } else { if (goi->argc) goto err_no_param; if (!*dap_p) { Jim_SetResultString(goi->interp, "DAP not configured", -1); return JIM_ERR; } Jim_SetResultString(goi->interp, adiv5_dap_name(*dap_p), -1); } break; case CFG_AP_NUM: if (goi->isconfigure) { /* jim_wide is a signed 64 bits int, ap_num is unsigned with max 52 bits */ jim_wide ap_num; e = jim_getopt_wide(goi, &ap_num); if (e != JIM_OK) return e; /* we still don't know dap->adi_version */ if (ap_num < 0 || (ap_num > DP_APSEL_MAX && (ap_num & 0xfff))) { Jim_SetResultString(goi->interp, "Invalid AP number!", -1); return JIM_ERR; } *ap_num_p = ap_num; } else { if (goi->argc) goto err_no_param; if (*ap_num_p == DP_APSEL_INVALID) { Jim_SetResultString(goi->interp, "AP number not configured", -1); return JIM_ERR; } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, *ap_num_p)); } break; case CFG_CTIBASE: LOG_WARNING("DEPRECATED! use \'-baseaddr' not \'-ctibase\'"); /* fall through */ case CFG_BASEADDR: if (goi->isconfigure) { jim_wide base; e = jim_getopt_wide(goi, &base); if (e != JIM_OK) return e; *base_p = (uint32_t)base; } else { if (goi->argc) goto err_no_param; Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, *base_p)); } break; }; return JIM_OK; err_no_param: Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); return JIM_ERR; } int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi) { struct adiv5_private_config *pc; int e; pc = (struct adiv5_private_config *)target->private_config; if (!pc) { pc = calloc(1, sizeof(struct adiv5_private_config)); if (!pc) { LOG_ERROR("Out of memory"); return JIM_ERR; } pc->ap_num = DP_APSEL_INVALID; target->private_config = pc; } target->has_dap = true; e = adiv5_jim_spot_configure(goi, &pc->dap, &pc->ap_num, NULL); if (e != JIM_OK) return e; if (pc->dap && !target->dap_configured) { if (target->tap_configured) { pc->dap = NULL; Jim_SetResultString(goi->interp, "-chain-position and -dap configparams are mutually exclusive!", -1); return JIM_ERR; } target->tap = pc->dap->tap; target->dap_configured = true; } return JIM_OK; } int adiv5_verify_config(struct adiv5_private_config *pc) { if (!pc) return ERROR_FAIL; if (!pc->dap) return ERROR_FAIL; return ERROR_OK; } int adiv5_jim_mem_ap_spot_configure(struct adiv5_mem_ap_spot *cfg, struct jim_getopt_info *goi) { return adiv5_jim_spot_configure(goi, &cfg->dap, &cfg->ap_num, &cfg->base); } int adiv5_mem_ap_spot_init(struct adiv5_mem_ap_spot *p) { p->dap = NULL; p->ap_num = DP_APSEL_INVALID; p->base = 0; return ERROR_OK; } COMMAND_HANDLER(handle_dap_info_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint64_t apsel; switch (CMD_ARGC) { case 0: apsel = dap->apsel; break; case 1: if (!strcmp(CMD_ARGV[0], "root")) { if (!is_adiv6(dap)) { command_print(CMD, "Option \"root\" not allowed with ADIv5 DAP"); return ERROR_COMMAND_ARGUMENT_INVALID; } int retval = adiv6_dap_read_baseptr(CMD, dap, &apsel); if (retval != ERROR_OK) { command_print(CMD, "Failed reading DAP baseptr"); return retval; } break; } COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); if (!is_ap_num_valid(dap, apsel)) { command_print(CMD, "Invalid AP number"); return ERROR_COMMAND_ARGUMENT_INVALID; } break; default: return ERROR_COMMAND_SYNTAX_ERROR; } struct adiv5_ap *ap = dap_get_ap(dap, apsel); if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; } int retval = dap_info_command(CMD, ap); dap_put_ap(ap); return retval; } COMMAND_HANDLER(dap_baseaddr_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint64_t apsel; uint32_t baseaddr_lower, baseaddr_upper; struct adiv5_ap *ap; target_addr_t baseaddr; int retval; baseaddr_upper = 0; switch (CMD_ARGC) { case 0: apsel = dap->apsel; break; case 1: COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); if (!is_ap_num_valid(dap, apsel)) { command_print(CMD, "Invalid AP number"); return ERROR_COMMAND_ARGUMENT_INVALID; } break; default: return ERROR_COMMAND_SYNTAX_ERROR; } /* NOTE: assumes we're talking to a MEM-AP, which * has a base address. There are other kinds of AP, * though they're not common for now. This should * use the ID register to verify it's a MEM-AP. */ ap = dap_get_ap(dap, apsel); if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; } retval = dap_queue_ap_read(ap, MEM_AP_REG_BASE(dap), &baseaddr_lower); if (retval == ERROR_OK && ap->cfg_reg == MEM_AP_REG_CFG_INVALID) retval = dap_queue_ap_read(ap, MEM_AP_REG_CFG(dap), &ap->cfg_reg); if (retval == ERROR_OK && (ap->cfg_reg == MEM_AP_REG_CFG_INVALID || is_64bit_ap(ap))) { /* MEM_AP_REG_BASE64 is defined as 'RES0'; can be read and then ignored on 32 bits AP */ retval = dap_queue_ap_read(ap, MEM_AP_REG_BASE64(dap), &baseaddr_upper); } if (retval == ERROR_OK) retval = dap_run(dap); dap_put_ap(ap); if (retval != ERROR_OK) return retval; if (is_64bit_ap(ap)) { baseaddr = (((target_addr_t)baseaddr_upper) << 32) | baseaddr_lower; command_print(CMD, "0x%016" PRIx64, baseaddr); } else command_print(CMD, "0x%08" PRIx32, baseaddr_lower); return ERROR_OK; } COMMAND_HANDLER(dap_memaccess_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); struct adiv5_ap *ap; uint32_t memaccess_tck; switch (CMD_ARGC) { case 0: ap = dap_get_ap(dap, dap->apsel); if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; } memaccess_tck = ap->memaccess_tck; break; case 1: ap = dap_get_config_ap(dap, dap->apsel); if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], memaccess_tck); ap->memaccess_tck = memaccess_tck; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } dap_put_ap(ap); command_print(CMD, "memory bus access delay set to %" PRIu32 " tck", memaccess_tck); return ERROR_OK; } COMMAND_HANDLER(dap_apsel_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint64_t apsel; switch (CMD_ARGC) { case 0: command_print(CMD, "0x%" PRIx64, dap->apsel); return ERROR_OK; case 1: COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); if (!is_ap_num_valid(dap, apsel)) { command_print(CMD, "Invalid AP number"); return ERROR_COMMAND_ARGUMENT_INVALID; } break; default: return ERROR_COMMAND_SYNTAX_ERROR; } dap->apsel = apsel; return ERROR_OK; } COMMAND_HANDLER(dap_apcsw_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); struct adiv5_ap *ap; uint32_t csw_val, csw_mask; switch (CMD_ARGC) { case 0: ap = dap_get_ap(dap, dap->apsel); if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; } command_print(CMD, "AP#0x%" PRIx64 " selected, csw 0x%8.8" PRIx32, dap->apsel, ap->csw_default); break; case 1: if (strcmp(CMD_ARGV[0], "default") == 0) csw_val = CSW_AHB_DEFAULT; else COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], csw_val); if (csw_val & (CSW_SIZE_MASK | CSW_ADDRINC_MASK)) { LOG_ERROR("CSW value cannot include 'Size' and 'AddrInc' bit-fields"); return ERROR_COMMAND_ARGUMENT_INVALID; } ap = dap_get_config_ap(dap, dap->apsel); if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; } ap->csw_default = csw_val; break; case 2: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], csw_val); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], csw_mask); if (csw_mask & (CSW_SIZE_MASK | CSW_ADDRINC_MASK)) { LOG_ERROR("CSW mask cannot include 'Size' and 'AddrInc' bit-fields"); return ERROR_COMMAND_ARGUMENT_INVALID; } ap = dap_get_config_ap(dap, dap->apsel); if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; } ap->csw_default = (ap->csw_default & ~csw_mask) | (csw_val & csw_mask); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } dap_put_ap(ap); return ERROR_OK; } COMMAND_HANDLER(dap_apid_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint64_t apsel; uint32_t apid; int retval; switch (CMD_ARGC) { case 0: apsel = dap->apsel; break; case 1: COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); if (!is_ap_num_valid(dap, apsel)) { command_print(CMD, "Invalid AP number"); return ERROR_COMMAND_ARGUMENT_INVALID; } break; default: return ERROR_COMMAND_SYNTAX_ERROR; } struct adiv5_ap *ap = dap_get_ap(dap, apsel); if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; } retval = dap_queue_ap_read(ap, AP_REG_IDR(dap), &apid); if (retval != ERROR_OK) { dap_put_ap(ap); return retval; } retval = dap_run(dap); dap_put_ap(ap); if (retval != ERROR_OK) return retval; command_print(CMD, "0x%8.8" PRIx32, apid); return retval; } COMMAND_HANDLER(dap_apreg_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint64_t apsel; uint32_t reg, value; int retval; if (CMD_ARGC < 2 || CMD_ARGC > 3) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); if (!is_ap_num_valid(dap, apsel)) { command_print(CMD, "Invalid AP number"); return ERROR_COMMAND_ARGUMENT_INVALID; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg); if (is_adiv6(dap)) { if (reg >= 4096 || (reg & 3)) { command_print(CMD, "Invalid reg value (should be less than 4096 and 4 bytes aligned)"); return ERROR_COMMAND_ARGUMENT_INVALID; } } else { /* ADI version 5 */ if (reg >= 256 || (reg & 3)) { command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)"); return ERROR_COMMAND_ARGUMENT_INVALID; } } struct adiv5_ap *ap = dap_get_ap(dap, apsel); if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; } if (CMD_ARGC == 3) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); /* see if user supplied register address is a match for the CSW or TAR register */ if (reg == MEM_AP_REG_CSW(dap)) { ap->csw_value = 0; /* invalid, in case write fails */ retval = dap_queue_ap_write(ap, reg, value); if (retval == ERROR_OK) ap->csw_value = value; } else if (reg == MEM_AP_REG_TAR(dap)) { retval = dap_queue_ap_write(ap, reg, value); if (retval == ERROR_OK) ap->tar_value = (ap->tar_value & ~0xFFFFFFFFull) | value; else { /* To track independent writes to TAR and TAR64, two tar_valid flags */ /* should be used. To keep it simple, tar_valid is only invalidated on a */ /* write fail. This approach causes a later re-write of the TAR and TAR64 */ /* if tar_valid is false. */ ap->tar_valid = false; } } else if (reg == MEM_AP_REG_TAR64(dap)) { retval = dap_queue_ap_write(ap, reg, value); if (retval == ERROR_OK) ap->tar_value = (ap->tar_value & 0xFFFFFFFFull) | (((target_addr_t)value) << 32); else { /* See above comment for the MEM_AP_REG_TAR failed write case */ ap->tar_valid = false; } } else { retval = dap_queue_ap_write(ap, reg, value); } } else { retval = dap_queue_ap_read(ap, reg, &value); } if (retval == ERROR_OK) retval = dap_run(dap); dap_put_ap(ap); if (retval != ERROR_OK) return retval; if (CMD_ARGC == 2) command_print(CMD, "0x%08" PRIx32, value); return retval; } COMMAND_HANDLER(dap_dpreg_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t reg, value; int retval; if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg); if (reg >= 256 || (reg & 3)) { command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)"); return ERROR_COMMAND_ARGUMENT_INVALID; } if (CMD_ARGC == 2) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); retval = dap_queue_dp_write(dap, reg, value); } else { retval = dap_queue_dp_read(dap, reg, &value); } if (retval == ERROR_OK) retval = dap_run(dap); if (retval != ERROR_OK) return retval; if (CMD_ARGC == 1) command_print(CMD, "0x%08" PRIx32, value); return retval; } COMMAND_HANDLER(dap_ti_be_32_quirks_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); return CALL_COMMAND_HANDLER(handle_command_parse_bool, &dap->ti_be_32_quirks, "TI BE-32 quirks mode"); } COMMAND_HANDLER(dap_nu_npcx_quirks_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); return CALL_COMMAND_HANDLER(handle_command_parse_bool, &dap->nu_npcx_quirks, "Nuvoton NPCX quirks mode"); } const struct command_registration dap_instance_commands[] = { { .name = "info", .handler = handle_dap_info_command, .mode = COMMAND_EXEC, .help = "display ROM table for specified MEM-AP (default currently selected AP) " "or the ADIv6 root ROM table", .usage = "[ap_num | 'root']", }, { .name = "apsel", .handler = dap_apsel_command, .mode = COMMAND_ANY, .help = "Set the currently selected AP (default 0) " "and display the result", .usage = "[ap_num]", }, { .name = "apcsw", .handler = dap_apcsw_command, .mode = COMMAND_ANY, .help = "Set CSW default bits", .usage = "[value [mask]]", }, { .name = "apid", .handler = dap_apid_command, .mode = COMMAND_EXEC, .help = "return ID register from AP " "(default currently selected AP)", .usage = "[ap_num]", }, { .name = "apreg", .handler = dap_apreg_command, .mode = COMMAND_EXEC, .help = "read/write a register from AP " "(reg is byte address of a word register, like 0 4 8...)", .usage = "ap_num reg [value]", }, { .name = "dpreg", .handler = dap_dpreg_command, .mode = COMMAND_EXEC, .help = "read/write a register from DP " "(reg is byte address (bank << 4 | reg) of a word register, like 0 4 8...)", .usage = "reg [value]", }, { .name = "baseaddr", .handler = dap_baseaddr_command, .mode = COMMAND_EXEC, .help = "return debug base address from MEM-AP " "(default currently selected AP)", .usage = "[ap_num]", }, { .name = "memaccess", .handler = dap_memaccess_command, .mode = COMMAND_EXEC, .help = "set/get number of extra tck for MEM-AP memory " "bus access [0-255]", .usage = "[cycles]", }, { .name = "ti_be_32_quirks", .handler = dap_ti_be_32_quirks_command, .mode = COMMAND_CONFIG, .help = "set/get quirks mode for TI TMS450/TMS570 processors", .usage = "[enable]", }, { .name = "nu_npcx_quirks", .handler = dap_nu_npcx_quirks_command, .mode = COMMAND_CONFIG, .help = "set/get quirks mode for Nuvoton NPCX controllers", .usage = "[enable]", }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_adi_v5.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2019-2021, Ampere Computing LLC * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM_ADI_V5_H #define OPENOCD_TARGET_ARM_ADI_V5_H /** * @file * This defines formats and data structures used to talk to ADIv5 entities. * Those include a DAP, different types of Debug Port (DP), and memory mapped * resources accessed through a MEM-AP. */ #include <helper/list.h> #include "arm_jtag.h" #include "helper/bits.h" /* JEP106 ID for ARM */ #define ARM_ID 0x23B /* three-bit ACK values for SWD access (sent LSB first) */ #define SWD_ACK_OK 0x1 #define SWD_ACK_WAIT 0x2 #define SWD_ACK_FAULT 0x4 #define DPAP_WRITE 0 #define DPAP_READ 1 #define BANK_REG(bank, reg) (((bank) << 4) | (reg)) /* A[3:0] for DP registers; A[1:0] are always zero. * - JTAG accesses all of these via JTAG_DP_DPACC, except for * IDCODE (JTAG_DP_IDCODE) and ABORT (JTAG_DP_ABORT). * - SWD accesses these directly, sometimes needing SELECT.DPBANKSEL */ #define DP_DPIDR BANK_REG(0x0, 0x0) /* DPv1+: ro */ #define DP_ABORT BANK_REG(0x0, 0x0) /* DPv1+: SWD: wo */ #define DP_DPIDR1 BANK_REG(0x1, 0x0) /* DPv3: ro */ #define DP_BASEPTR0 BANK_REG(0x2, 0x0) /* DPv3: ro */ #define DP_BASEPTR1 BANK_REG(0x3, 0x0) /* DPv3: ro */ #define DP_CTRL_STAT BANK_REG(0x0, 0x4) /* DPv0+: rw */ #define DP_DLCR BANK_REG(0x1, 0x4) /* DPv1+: SWD: rw */ #define DP_TARGETID BANK_REG(0x2, 0x4) /* DPv2: ro */ #define DP_DLPIDR BANK_REG(0x3, 0x4) /* DPv2: ro */ #define DP_EVENTSTAT BANK_REG(0x4, 0x4) /* DPv2: ro */ #define DP_SELECT1 BANK_REG(0x5, 0x4) /* DPv3: ro */ #define DP_RESEND BANK_REG(0x0, 0x8) /* DPv1+: SWD: ro */ #define DP_SELECT BANK_REG(0x0, 0x8) /* DPv0+: JTAG: rw; SWD: wo */ #define DP_RDBUFF BANK_REG(0x0, 0xC) /* DPv0+: ro */ #define DP_TARGETSEL BANK_REG(0x0, 0xC) /* DPv2: SWD: wo */ #define DLCR_TO_TRN(dlcr) ((uint32_t)(1 + ((3 & (dlcr)) >> 8))) /* 1..4 clocks */ /* Fields of DP_DPIDR register */ #define DP_DPIDR_VERSION_SHIFT 12 #define DP_DPIDR_VERSION_MASK (0xFUL << DP_DPIDR_VERSION_SHIFT) /* Fields of the DP's AP ABORT register */ #define DAPABORT (1UL << 0) #define STKCMPCLR (1UL << 1) /* SWD-only */ #define STKERRCLR (1UL << 2) /* SWD-only */ #define WDERRCLR (1UL << 3) /* SWD-only */ #define ORUNERRCLR (1UL << 4) /* SWD-only */ /* Fields of register DP_DPIDR1 */ #define DP_DPIDR1_ASIZE_MASK (0x7F) #define DP_DPIDR1_ERRMODE BIT(7) /* Fields of register DP_BASEPTR0 */ #define DP_BASEPTR0_VALID BIT(0) /* Fields of the DP's CTRL/STAT register */ #define CORUNDETECT (1UL << 0) #define SSTICKYORUN (1UL << 1) /* 3:2 - transaction mode (e.g. pushed compare) */ #define SSTICKYCMP (1UL << 4) #define SSTICKYERR (1UL << 5) #define READOK (1UL << 6) /* SWD-only */ #define WDATAERR (1UL << 7) /* SWD-only */ /* 11:8 - mask lanes for pushed compare or verify ops */ /* 21:12 - transaction counter */ #define CDBGRSTREQ (1UL << 26) #define CDBGRSTACK (1UL << 27) #define CDBGPWRUPREQ (1UL << 28) #define CDBGPWRUPACK (1UL << 29) #define CSYSPWRUPREQ (1UL << 30) #define CSYSPWRUPACK (1UL << 31) #define DP_DLPIDR_PROTVSN 1u #define DP_SELECT_APSEL 0xFF000000 #define DP_SELECT_APBANK 0x000000F0 #define DP_SELECT_DPBANK 0x0000000F #define DP_SELECT_INVALID 0x00FFFF00 /* Reserved bits one */ #define DP_APSEL_MAX (255) /* for ADIv5 only */ #define DP_APSEL_INVALID 0xF00 /* more than DP_APSEL_MAX and not ADIv6 aligned 4k */ #define DP_TARGETSEL_INVALID 0xFFFFFFFFU #define DP_TARGETSEL_DPID_MASK 0x0FFFFFFFU #define DP_TARGETSEL_INSTANCEID_MASK 0xF0000000U #define DP_TARGETSEL_INSTANCEID_SHIFT 28 /* MEM-AP register addresses */ #define ADIV5_MEM_AP_REG_CSW (0x00) #define ADIV5_MEM_AP_REG_TAR (0x04) #define ADIV5_MEM_AP_REG_TAR64 (0x08) /* RW: Large Physical Address Extension */ #define ADIV5_MEM_AP_REG_DRW (0x0C) /* RW: Data Read/Write register */ #define ADIV5_MEM_AP_REG_BD0 (0x10) /* RW: Banked Data register 0-3 */ #define ADIV5_MEM_AP_REG_BD1 (0x14) #define ADIV5_MEM_AP_REG_BD2 (0x18) #define ADIV5_MEM_AP_REG_BD3 (0x1C) #define ADIV5_MEM_AP_REG_MBT (0x20) /* --: Memory Barrier Transfer register */ #define ADIV5_MEM_AP_REG_BASE64 (0xF0) /* RO: Debug Base Address (LA) register */ #define ADIV5_MEM_AP_REG_CFG (0xF4) /* RO: Configuration register */ #define ADIV5_MEM_AP_REG_BASE (0xF8) /* RO: Debug Base Address register */ #define ADIV6_MEM_AP_REG_CSW (0xD00 + ADIV5_MEM_AP_REG_CSW) #define ADIV6_MEM_AP_REG_TAR (0xD00 + ADIV5_MEM_AP_REG_TAR) #define ADIV6_MEM_AP_REG_TAR64 (0xD00 + ADIV5_MEM_AP_REG_TAR64) #define ADIV6_MEM_AP_REG_DRW (0xD00 + ADIV5_MEM_AP_REG_DRW) #define ADIV6_MEM_AP_REG_BD0 (0xD00 + ADIV5_MEM_AP_REG_BD0) #define ADIV6_MEM_AP_REG_BD1 (0xD00 + ADIV5_MEM_AP_REG_BD1) #define ADIV6_MEM_AP_REG_BD2 (0xD00 + ADIV5_MEM_AP_REG_BD2) #define ADIV6_MEM_AP_REG_BD3 (0xD00 + ADIV5_MEM_AP_REG_BD3) #define ADIV6_MEM_AP_REG_MBT (0xD00 + ADIV5_MEM_AP_REG_MBT) #define ADIV6_MEM_AP_REG_BASE64 (0xD00 + ADIV5_MEM_AP_REG_BASE64) #define ADIV6_MEM_AP_REG_CFG (0xD00 + ADIV5_MEM_AP_REG_CFG) #define ADIV6_MEM_AP_REG_BASE (0xD00 + ADIV5_MEM_AP_REG_BASE) #define MEM_AP_REG_CSW(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_CSW : ADIV5_MEM_AP_REG_CSW) #define MEM_AP_REG_TAR(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_TAR : ADIV5_MEM_AP_REG_TAR) #define MEM_AP_REG_TAR64(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_TAR64 : ADIV5_MEM_AP_REG_TAR64) #define MEM_AP_REG_DRW(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_DRW : ADIV5_MEM_AP_REG_DRW) #define MEM_AP_REG_BD0(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_BD0 : ADIV5_MEM_AP_REG_BD0) #define MEM_AP_REG_BD1(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_BD1 : ADIV5_MEM_AP_REG_BD1) #define MEM_AP_REG_BD2(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_BD2 : ADIV5_MEM_AP_REG_BD2) #define MEM_AP_REG_BD3(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_BD3 : ADIV5_MEM_AP_REG_BD3) #define MEM_AP_REG_MBT(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_MBT : ADIV5_MEM_AP_REG_MBT) #define MEM_AP_REG_BASE64(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_BASE64 : ADIV5_MEM_AP_REG_BASE64) #define MEM_AP_REG_CFG(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_CFG : ADIV5_MEM_AP_REG_CFG) #define MEM_AP_REG_BASE(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_BASE : ADIV5_MEM_AP_REG_BASE) /* Generic AP register address */ #define ADIV5_AP_REG_IDR (0xFC) /* RO: Identification Register */ #define ADIV6_AP_REG_IDR (0xD00 + ADIV5_AP_REG_IDR) #define AP_REG_IDR(dap) (is_adiv6(dap) ? ADIV6_AP_REG_IDR : ADIV5_AP_REG_IDR) /* Fields of the MEM-AP's CSW register */ #define CSW_SIZE_MASK 7 #define CSW_8BIT 0 #define CSW_16BIT 1 #define CSW_32BIT 2 #define CSW_ADDRINC_MASK (3UL << 4) #define CSW_ADDRINC_OFF 0UL #define CSW_ADDRINC_SINGLE (1UL << 4) #define CSW_ADDRINC_PACKED (2UL << 4) #define CSW_DEVICE_EN (1UL << 6) #define CSW_TRIN_PROG (1UL << 7) /* All fields in bits 12 and above are implementation-defined * Defaults for AHB/AXI in "Standard Memory Access Port Definitions" from ADI * Some bits are shared between buses */ #define CSW_SPIDEN (1UL << 23) #define CSW_DBGSWENABLE (1UL << 31) /* AHB: Privileged */ #define CSW_AHB_HPROT1 (1UL << 25) /* AHB: set HMASTER signals to AHB-AP ID */ #define CSW_AHB_MASTER_DEBUG (1UL << 29) /* AHB5: non-secure access via HNONSEC * AHB3: SBO, UNPREDICTABLE if zero */ #define CSW_AHB_SPROT (1UL << 30) /* AHB: initial value of csw_default */ #define CSW_AHB_DEFAULT (CSW_AHB_HPROT1 | CSW_AHB_MASTER_DEBUG | CSW_DBGSWENABLE) /* AXI: Privileged */ #define CSW_AXI_ARPROT0_PRIV (1UL << 28) /* AXI: Non-secure */ #define CSW_AXI_ARPROT1_NONSEC (1UL << 29) /* AXI: initial value of csw_default */ #define CSW_AXI_DEFAULT (CSW_AXI_ARPROT0_PRIV | CSW_AXI_ARPROT1_NONSEC | CSW_DBGSWENABLE) /* APB: initial value of csw_default */ #define CSW_APB_DEFAULT (CSW_DBGSWENABLE) /* Fields of the MEM-AP's CFG register */ #define MEM_AP_REG_CFG_BE BIT(0) #define MEM_AP_REG_CFG_LA BIT(1) #define MEM_AP_REG_CFG_LD BIT(2) #define MEM_AP_REG_CFG_INVALID 0xFFFFFFF8 /* Fields of the MEM-AP's IDR register */ #define AP_REG_IDR_REVISION_MASK (0xF0000000) #define AP_REG_IDR_REVISION_SHIFT (28) #define AP_REG_IDR_DESIGNER_MASK (0x0FFE0000) #define AP_REG_IDR_DESIGNER_SHIFT (17) #define AP_REG_IDR_CLASS_MASK (0x0001E000) #define AP_REG_IDR_CLASS_SHIFT (13) #define AP_REG_IDR_VARIANT_MASK (0x000000F0) #define AP_REG_IDR_VARIANT_SHIFT (4) #define AP_REG_IDR_TYPE_MASK (0x0000000F) #define AP_REG_IDR_TYPE_SHIFT (0) #define AP_REG_IDR_CLASS_NONE (0x0) #define AP_REG_IDR_CLASS_COM (0x1) #define AP_REG_IDR_CLASS_MEM_AP (0x8) #define AP_REG_IDR_VALUE(d, c, t) (\ (((d) << AP_REG_IDR_DESIGNER_SHIFT) & AP_REG_IDR_DESIGNER_MASK) | \ (((c) << AP_REG_IDR_CLASS_SHIFT) & AP_REG_IDR_CLASS_MASK) | \ (((t) << AP_REG_IDR_TYPE_SHIFT) & AP_REG_IDR_TYPE_MASK) \ ) #define AP_TYPE_MASK (AP_REG_IDR_DESIGNER_MASK | AP_REG_IDR_CLASS_MASK | AP_REG_IDR_TYPE_MASK) /* FIXME: not SWD specific; should be renamed, e.g. adiv5_special_seq */ enum swd_special_seq { LINE_RESET, JTAG_TO_SWD, JTAG_TO_DORMANT, SWD_TO_JTAG, SWD_TO_DORMANT, DORMANT_TO_SWD, DORMANT_TO_JTAG, }; /** * This represents an ARM Debug Interface (v5) Access Port (AP). * Most common is a MEM-AP, for memory access. */ struct adiv5_ap { /** * DAP this AP belongs to. */ struct adiv5_dap *dap; /** * ADIv5: Number of this AP (0~255) * ADIv6: Base address of this AP (4k aligned) * TODO: to be more coherent, it should be renamed apsel */ uint64_t ap_num; /** * Default value for (MEM-AP) AP_REG_CSW register. */ uint32_t csw_default; /** * Cache for (MEM-AP) AP_REG_CSW register value. This is written to * configure an access mode, such as autoincrementing AP_REG_TAR during * word access. "-1" indicates no cached value. */ uint32_t csw_value; /** * Cache for (MEM-AP) AP_REG_TAR register value This is written to * configure the address being read or written * "-1" indicates no cached value. */ target_addr_t tar_value; /** * Configures how many extra tck clocks are added after starting a * MEM-AP access before we try to read its status (and/or result). */ uint32_t memaccess_tck; /* Size of TAR autoincrement block, ARM ADI Specification requires at least 10 bits */ uint32_t tar_autoincr_block; /* true if packed transfers are supported by the MEM-AP */ bool packed_transfers; /* true if unaligned memory access is not supported by the MEM-AP */ bool unaligned_access_bad; /* true if tar_value is in sync with TAR register */ bool tar_valid; /* MEM AP configuration register indicating LPAE support */ uint32_t cfg_reg; /* references counter */ unsigned int refcount; /* AP referenced during config. Never put it, even when refcount reaches zero */ bool config_ap_never_release; }; /** * This represents an ARM Debug Interface (v5) Debug Access Port (DAP). * A DAP has two types of component: one Debug Port (DP), which is a * transport agent; and at least one Access Port (AP), controlling * resource access. * * There are two basic DP transports: JTAG, and ARM's low pin-count SWD. * Accordingly, this interface is responsible for hiding the transport * differences so upper layer code can largely ignore them. * * When the chip is implemented with JTAG-DP or SW-DP, the transport is * fixed as JTAG or SWD, respectively. Chips incorporating SWJ-DP permit * a choice made at board design time (by only using the SWD pins), or * as part of setting up a debug session (if all the dual-role JTAG/SWD * signals are available). */ struct adiv5_dap { const struct dap_ops *ops; /* dap transaction list for WAIT support */ struct list_head cmd_journal; /* pool for dap_cmd objects */ struct list_head cmd_pool; /* number of dap_cmd objects in the pool */ size_t cmd_pool_size; struct jtag_tap *tap; /* Control config */ uint32_t dp_ctrl_stat; struct adiv5_ap ap[DP_APSEL_MAX + 1]; /* The current manually selected AP by the "dap apsel" command */ uint64_t apsel; /** * Cache for DP_SELECT register. A value of DP_SELECT_INVALID * indicates no cached value and forces rewrite of the register. */ uint64_t select; /* information about current pending SWjDP-AHBAP transaction */ uint8_t ack; /** * Holds the pointer to the destination word for the last queued read, * for use with posted AP read sequence optimization. */ uint32_t *last_read; /* The TI TMS470 and TMS570 series processors use a BE-32 memory ordering * despite lack of support in the ARMv7 architecture. Memory access through * the AHB-AP has strange byte ordering these processors, and we need to * swizzle appropriately. */ bool ti_be_32_quirks; /* The Nuvoton NPCX M4 has an issue with writing to non-4-byte-aligned mmios. * The work around is to repeat the data in all 4 bytes of DRW */ bool nu_npcx_quirks; /** * STLINK adapter need to know if last AP operation was read or write, and * in case of write has to flush it with a dummy read from DP_RDBUFF */ bool stlink_flush_ap_write; /** * Signals that an attempt to reestablish communication afresh * should be performed before the next access. */ bool do_reconnect; /** Flag saying whether to ignore the syspwrupack flag in DAP. Some devices * do not set this bit until later in the bringup sequence */ bool ignore_syspwrupack; /** Value to select DP in SWD multidrop mode or DP_TARGETSEL_INVALID */ uint32_t multidrop_targetsel; /** TPARTNO and TDESIGNER fields of multidrop_targetsel have been configured */ bool multidrop_dp_id_valid; /** TINSTANCE field of multidrop_targetsel has been configured */ bool multidrop_instance_id_valid; /** * Record if enter in SWD required passing through DORMANT */ bool switch_through_dormant; /** Indicates ADI version (5, 6 or 0 for unknown) being used */ unsigned int adi_version; /* ADIv6 only field indicating ROM Table address size */ unsigned int asize; }; /** * Transport-neutral representation of queued DAP transactions, supporting * both JTAG and SWD transports. All submitted transactions are logically * queued, until the queue is executed by run(). Some implementations might * execute transactions as soon as they're submitted, but no status is made * available until run(). */ struct dap_ops { /** connect operation for SWD */ int (*connect)(struct adiv5_dap *dap); /** send a sequence to the DAP */ int (*send_sequence)(struct adiv5_dap *dap, enum swd_special_seq seq); /** DP register read. */ int (*queue_dp_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data); /** DP register write. */ int (*queue_dp_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data); /** AP register read. */ int (*queue_ap_read)(struct adiv5_ap *ap, unsigned reg, uint32_t *data); /** AP register write. */ int (*queue_ap_write)(struct adiv5_ap *ap, unsigned reg, uint32_t data); /** AP operation abort. */ int (*queue_ap_abort)(struct adiv5_dap *dap, uint8_t *ack); /** Executes all queued DAP operations. */ int (*run)(struct adiv5_dap *dap); /** Executes all queued DAP operations but doesn't check * sticky error conditions */ int (*sync)(struct adiv5_dap *dap); /** Optional; called at OpenOCD exit */ void (*quit)(struct adiv5_dap *dap); }; /* * Access Port types */ enum ap_type { AP_TYPE_JTAG_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_NONE, 0), /* JTAG-AP */ AP_TYPE_COM_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_COM, 0), /* COM-AP */ AP_TYPE_AHB3_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 1), /* AHB3 Memory-AP */ AP_TYPE_APB_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 2), /* APB2 or APB3 Memory-AP */ AP_TYPE_AXI_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 4), /* AXI3 or AXI4 Memory-AP */ AP_TYPE_AHB5_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 5), /* AHB5 Memory-AP */ AP_TYPE_APB4_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 6), /* APB4 Memory-AP */ AP_TYPE_AXI5_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 7), /* AXI5 Memory-AP */ AP_TYPE_AHB5H_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 8), /* AHB5 with enhanced HPROT Memory-AP */ }; extern const struct dap_ops jtag_dp_ops; extern const struct dap_ops swd_dap_ops; /* Check the ap->cfg_reg Long Address field (bit 1) * * 0b0: The AP only supports physical addresses 32 bits or smaller * 0b1: The AP supports physical addresses larger than 32 bits * * @param ap The AP used for reading. * * @return true for 64 bit, false for 32 bit */ static inline bool is_64bit_ap(struct adiv5_ap *ap) { return (ap->cfg_reg & MEM_AP_REG_CFG_LA) != 0; } /** * Check if DAP is ADIv6 * * @param dap The DAP to test * * @return true for ADIv6, false for either ADIv5 or unknown version */ static inline bool is_adiv6(const struct adiv5_dap *dap) { return dap->adi_version == 6; } /** * Send an adi-v5 sequence to the DAP. * * @param dap The DAP used for reading. * @param seq The sequence to send. * * @return ERROR_OK for success, else a fault code. */ static inline int dap_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq) { assert(dap->ops); return dap->ops->send_sequence(dap, seq); } /** * Queue a DP register read. * Note that not all DP registers are readable; also, that JTAG and SWD * have slight differences in DP register support. * * @param dap The DAP used for reading. * @param reg The two-bit number of the DP register being read. * @param data Pointer saying where to store the register's value * (in host endianness). * * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { assert(dap->ops); return dap->ops->queue_dp_read(dap, reg, data); } /** * Queue a DP register write. * Note that not all DP registers are writable; also, that JTAG and SWD * have slight differences in DP register support. * * @param dap The DAP used for writing. * @param reg The two-bit number of the DP register being written. * @param data Value being written (host endianness) * * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_dp_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { assert(dap->ops); return dap->ops->queue_dp_write(dap, reg, data); } /** * Queue an AP register read. * * @param ap The AP used for reading. * @param reg The number of the AP register being read. * @param data Pointer saying where to store the register's value * (in host endianness). * * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_ap_read(struct adiv5_ap *ap, unsigned reg, uint32_t *data) { assert(ap->dap->ops); if (ap->refcount == 0) { ap->refcount = 1; LOG_ERROR("BUG: refcount AP#0x%" PRIx64 " used without get", ap->ap_num); } return ap->dap->ops->queue_ap_read(ap, reg, data); } /** * Queue an AP register write. * * @param ap The AP used for writing. * @param reg The number of the AP register being written. * @param data Value being written (host endianness) * * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_ap_write(struct adiv5_ap *ap, unsigned reg, uint32_t data) { assert(ap->dap->ops); if (ap->refcount == 0) { ap->refcount = 1; LOG_ERROR("BUG: refcount AP#0x%" PRIx64 " used without get", ap->ap_num); } return ap->dap->ops->queue_ap_write(ap, reg, data); } /** * Queue an AP abort operation. The current AP transaction is aborted, * including any update of the transaction counter. The AP is left in * an unknown state (so it must be re-initialized). For use only after * the AP has reported WAIT status for an extended period. * * @param dap The DAP used for writing. * @param ack Pointer to where transaction status will be stored. * * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) { assert(dap->ops); return dap->ops->queue_ap_abort(dap, ack); } /** * Perform all queued DAP operations, and clear any errors posted in the * CTRL_STAT register when they are done. Note that if more than one AP * operation will be queued, one of the first operations in the queue * should probably enable CORUNDETECT in the CTRL/STAT register. * * @param dap The DAP used. * * @return ERROR_OK for success, else a fault code. */ static inline int dap_run(struct adiv5_dap *dap) { assert(dap->ops); return dap->ops->run(dap); } static inline int dap_sync(struct adiv5_dap *dap) { assert(dap->ops); if (dap->ops->sync) return dap->ops->sync(dap); return ERROR_OK; } static inline int dap_dp_read_atomic(struct adiv5_dap *dap, unsigned reg, uint32_t *value) { int retval; retval = dap_queue_dp_read(dap, reg, value); if (retval != ERROR_OK) return retval; return dap_run(dap); } static inline int dap_dp_poll_register(struct adiv5_dap *dap, unsigned reg, uint32_t mask, uint32_t value, int timeout) { assert(timeout > 0); assert((value & mask) == value); int ret; uint32_t regval; LOG_DEBUG("DAP: poll %x, mask 0x%08" PRIx32 ", value 0x%08" PRIx32, reg, mask, value); do { ret = dap_dp_read_atomic(dap, reg, ®val); if (ret != ERROR_OK) return ret; if ((regval & mask) == value) break; alive_sleep(10); } while (--timeout); if (!timeout) { LOG_DEBUG("DAP: poll %x timeout", reg); return ERROR_WAIT; } else { return ERROR_OK; } } /* Queued MEM-AP memory mapped single word transfers. */ int mem_ap_read_u32(struct adiv5_ap *ap, target_addr_t address, uint32_t *value); int mem_ap_write_u32(struct adiv5_ap *ap, target_addr_t address, uint32_t value); /* Synchronous MEM-AP memory mapped single word transfers. */ int mem_ap_read_atomic_u32(struct adiv5_ap *ap, target_addr_t address, uint32_t *value); int mem_ap_write_atomic_u32(struct adiv5_ap *ap, target_addr_t address, uint32_t value); /* Synchronous MEM-AP memory mapped bus block transfers. */ int mem_ap_read_buf(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address); int mem_ap_write_buf(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address); /* Synchronous, non-incrementing buffer functions for accessing fifos. */ int mem_ap_read_buf_noincr(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address); int mem_ap_write_buf_noincr(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address); /* Initialisation of the debug system, power domains and registers */ int dap_dp_init(struct adiv5_dap *dap); int dap_dp_init_or_reconnect(struct adiv5_dap *dap); int mem_ap_init(struct adiv5_ap *ap); /* Invalidate cached DP select and cached TAR and CSW of all APs */ void dap_invalidate_cache(struct adiv5_dap *dap); /* read ADIv6 baseptr register */ int adiv6_dap_read_baseptr(struct command_invocation *cmd, struct adiv5_dap *dap, target_addr_t *baseptr); /* test if ap_num is valid, based on current knowledge of dap */ bool is_ap_num_valid(struct adiv5_dap *dap, uint64_t ap_num); /* Probe Access Ports to find a particular type. Increment AP refcount */ int dap_find_get_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_ap **ap_out); /* Return AP with specified ap_num. Increment AP refcount */ struct adiv5_ap *dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num); /* Return AP with specified ap_num. Increment AP refcount and keep it non-zero */ struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, uint64_t ap_num); /* Decrement AP refcount and release the AP when refcount reaches zero */ int dap_put_ap(struct adiv5_ap *ap); /** Check if SWD multidrop configuration is valid */ static inline bool dap_is_multidrop(struct adiv5_dap *dap) { return dap->multidrop_dp_id_valid && dap->multidrop_instance_id_valid; } /* Lookup CoreSight component */ int dap_lookup_cs_component(struct adiv5_ap *ap, uint8_t type, target_addr_t *addr, int32_t idx); struct target; /* Put debug link into SWD mode */ int dap_to_swd(struct adiv5_dap *dap); /* Put debug link into JTAG mode */ int dap_to_jtag(struct adiv5_dap *dap); extern const struct command_registration dap_instance_commands[]; struct arm_dap_object; extern struct adiv5_dap *dap_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o); extern struct adiv5_dap *adiv5_get_dap(struct arm_dap_object *obj); extern int dap_info_command(struct command_invocation *cmd, struct adiv5_ap *ap); extern int dap_register_commands(struct command_context *cmd_ctx); extern const char *adiv5_dap_name(struct adiv5_dap *self); extern const struct swd_driver *adiv5_dap_swd_driver(struct adiv5_dap *self); extern int dap_cleanup_all(void); struct adiv5_private_config { uint64_t ap_num; struct adiv5_dap *dap; }; extern int adiv5_verify_config(struct adiv5_private_config *pc); extern int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi); struct adiv5_mem_ap_spot { struct adiv5_dap *dap; uint64_t ap_num; uint32_t base; }; extern int adiv5_mem_ap_spot_init(struct adiv5_mem_ap_spot *p); extern int adiv5_jim_mem_ap_spot_configure(struct adiv5_mem_ap_spot *cfg, struct jim_getopt_info *goi); #endif /* OPENOCD_TARGET_ARM_ADI_V5_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_coresight.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * General info from: * ARM CoreSight Architecture Specification v3.0 IHI0029E */ #ifndef OPENOCD_TARGET_ARM_CORESIGHT_H #define OPENOCD_TARGET_ARM_CORESIGHT_H #include <stdbool.h> #include <stdint.h> #include <helper/bits.h> #define ARM_CS_ALIGN (0x1000) /* mandatory registers */ #define ARM_CS_PIDR0 (0xFE0) #define ARM_CS_PIDR1 (0xFE4) #define ARM_CS_PIDR2 (0xFE8) #define ARM_CS_PIDR3 (0xFEC) #define ARM_CS_PIDR4 (0xFD0) #define ARM_CS_PIDR5 (0xFD4) #define ARM_CS_PIDR6 (0xFD8) #define ARM_CS_PIDR7 (0xFDC) /* * When PIDR bit JEDEC is zero, only the lowers 7 bits of DESIGNER are valid * and represent a legacy ASCII Identity Code. */ #define ARM_CS_PIDR_PART(pidr) ((pidr) & 0x0FFF) #define ARM_CS_PIDR_DESIGNER(pidr) \ ({ \ typeof(pidr) _x = (pidr); \ ((_x >> 25) & 0x780) | ((_x >> 12) & 0x7F); \ }) #define ARM_CS_PIDR_JEDEC BIT(19) #define ARM_CS_PIDR_SIZE(pidr) (((pidr) >> 36) & 0x000F) #define ARM_CS_CIDR0 (0xFF0) #define ARM_CS_CIDR1 (0xFF4) #define ARM_CS_CIDR2 (0xFF8) #define ARM_CS_CIDR3 (0xFFC) #define ARM_CS_CIDR_CLASS_MASK (0x0000F000) #define ARM_CS_CIDR_CLASS(cidr) (((cidr) >> 12) & 0x000F) #define ARM_CS_CLASS_0X1_ROM_TABLE (0x1) #define ARM_CS_CLASS_0X9_CS_COMPONENT (0x9) static inline bool is_valid_arm_cs_cidr(uint32_t cidr) { return (cidr & ~ARM_CS_CIDR_CLASS_MASK) == 0xB105000D; } /* Class 0x9 only registers */ #define ARM_CS_C9_DEVARCH (0xFBC) #define ARM_CS_C9_DEVARCH_ARCHID_MASK (0x0000FFFF) #define ARM_CS_C9_DEVARCH_ARCHID_SHIFT (0) #define ARM_CS_C9_DEVARCH_REVISION_MASK (0x000F0000) #define ARM_CS_C9_DEVARCH_REVISION_SHIFT (16) #define ARM_CS_C9_DEVARCH_PRESENT BIT(20) #define ARM_CS_C9_DEVARCH_ARCHITECT_MASK (0xFFE00000) #define ARM_CS_C9_DEVARCH_ARCHITECT_SHIFT (21) #define ARM_CS_C9_DEVARCH_REVISION(devarch) \ (((devarch) & ARM_CS_C9_DEVARCH_REVISION_MASK) >> ARM_CS_C9_DEVARCH_REVISION_SHIFT) #define ARM_CS_C9_DEVARCH_ARCHITECT(devarch) \ (((devarch) & ARM_CS_C9_DEVARCH_ARCHITECT_MASK) >> ARM_CS_C9_DEVARCH_ARCHITECT_SHIFT) #define ARM_CS_C9_DEVID (0xFC8) #define ARM_CS_C9_DEVID_FORMAT_MASK (0x0000000F) #define ARM_CS_C9_DEVID_FORMAT_32BIT (0) #define ARM_CS_C9_DEVID_FORMAT_64BIT (1) #define ARM_CS_C9_DEVID_SYSMEM_MASK BIT(4) #define ARM_CS_C9_DEVID_PRR_MASK BIT(5) #define ARM_CS_C9_DEVID_CP_MASK BIT(5) #define ARM_CS_C9_DEVTYPE (0xFCC) #define ARM_CS_C9_DEVTYPE_MAJOR_MASK (0x0000000F) #define ARM_CS_C9_DEVTYPE_MAJOR_SHIFT (0) #define ARM_CS_C9_DEVTYPE_SUB_MASK (0x000000F0) #define ARM_CS_C9_DEVTYPE_SUB_SHIFT (4) #define ARM_CS_C9_DEVTYPE_MASK (0x000000FF) #define ARM_CS_C9_DEVTYPE_CORE_DEBUG (0x00000015) /* Class 0x1 only registers */ #define ARM_CS_C1_MEMTYPE ARM_CS_C9_DEVTYPE #define ARM_CS_C1_MEMTYPE_SYSMEM_MASK BIT(0) /* The coding of ROM entry present differs between Class 0x9 and Class 0x1, * but we can simplify the whole management */ #define ARM_CS_ROMENTRY_PRESENT BIT(0) #define ARM_CS_ROMENTRY_OFFSET_MASK (0xFFFFF000U) #endif /* OPENOCD_TARGET_ARM_CORESIGHT_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_cti.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2016 by Matthias Welwarsky * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdlib.h> #include <stdint.h> #include "target/arm_adi_v5.h" #include "target/arm_cti.h" #include "target/target.h" #include "helper/time_support.h" #include "helper/list.h" #include "helper/command.h" struct arm_cti { struct list_head lh; char *name; struct adiv5_mem_ap_spot spot; struct adiv5_ap *ap; }; static LIST_HEAD(all_cti); const char *arm_cti_name(struct arm_cti *self) { return self->name; } struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) { struct arm_cti *obj = NULL; const char *name; bool found = false; name = Jim_GetString(o, NULL); list_for_each_entry(obj, &all_cti, lh) { if (!strcmp(name, obj->name)) { found = true; break; } } if (found) return obj; return NULL; } static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t mask, uint32_t value) { struct adiv5_ap *ap = self->ap; uint32_t tmp; /* Read register */ int retval = mem_ap_read_atomic_u32(ap, self->spot.base + reg, &tmp); if (retval != ERROR_OK) return retval; /* clear bitfield */ tmp &= ~mask; /* put new value */ tmp |= value & mask; /* write new value */ return mem_ap_write_atomic_u32(ap, self->spot.base + reg, tmp); } int arm_cti_enable(struct arm_cti *self, bool enable) { uint32_t val = enable ? 1 : 0; return mem_ap_write_atomic_u32(self->ap, self->spot.base + CTI_CTR, val); } int arm_cti_ack_events(struct arm_cti *self, uint32_t event) { struct adiv5_ap *ap = self->ap; int retval; uint32_t tmp; retval = mem_ap_write_atomic_u32(ap, self->spot.base + CTI_INACK, event); if (retval == ERROR_OK) { int64_t then = timeval_ms(); for (;;) { retval = mem_ap_read_atomic_u32(ap, self->spot.base + CTI_TROUT_STATUS, &tmp); if (retval != ERROR_OK) break; if ((tmp & event) == 0) break; if (timeval_ms() > then + 1000) { LOG_ERROR("timeout waiting for target"); retval = ERROR_TARGET_TIMEOUT; break; } } } return retval; } int arm_cti_gate_channel(struct arm_cti *self, uint32_t channel) { if (channel > 31) return ERROR_COMMAND_ARGUMENT_INVALID; return arm_cti_mod_reg_bits(self, CTI_GATE, CTI_CHNL(channel), 0); } int arm_cti_ungate_channel(struct arm_cti *self, uint32_t channel) { if (channel > 31) return ERROR_COMMAND_ARGUMENT_INVALID; return arm_cti_mod_reg_bits(self, CTI_GATE, CTI_CHNL(channel), 0xFFFFFFFF); } int arm_cti_write_reg(struct arm_cti *self, unsigned int reg, uint32_t value) { return mem_ap_write_atomic_u32(self->ap, self->spot.base + reg, value); } int arm_cti_read_reg(struct arm_cti *self, unsigned int reg, uint32_t *p_value) { if (!p_value) return ERROR_COMMAND_ARGUMENT_INVALID; return mem_ap_read_atomic_u32(self->ap, self->spot.base + reg, p_value); } int arm_cti_pulse_channel(struct arm_cti *self, uint32_t channel) { if (channel > 31) return ERROR_COMMAND_ARGUMENT_INVALID; return arm_cti_write_reg(self, CTI_APPPULSE, CTI_CHNL(channel)); } int arm_cti_set_channel(struct arm_cti *self, uint32_t channel) { if (channel > 31) return ERROR_COMMAND_ARGUMENT_INVALID; return arm_cti_write_reg(self, CTI_APPSET, CTI_CHNL(channel)); } int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel) { if (channel > 31) return ERROR_COMMAND_ARGUMENT_INVALID; return arm_cti_write_reg(self, CTI_APPCLEAR, CTI_CHNL(channel)); } static uint32_t cti_regs[28]; static const struct { uint32_t offset; const char *label; uint32_t *p_val; } cti_names[] = { { CTI_CTR, "CTR", &cti_regs[0] }, { CTI_GATE, "GATE", &cti_regs[1] }, { CTI_INEN0, "INEN0", &cti_regs[2] }, { CTI_INEN1, "INEN1", &cti_regs[3] }, { CTI_INEN2, "INEN2", &cti_regs[4] }, { CTI_INEN3, "INEN3", &cti_regs[5] }, { CTI_INEN4, "INEN4", &cti_regs[6] }, { CTI_INEN5, "INEN5", &cti_regs[7] }, { CTI_INEN6, "INEN6", &cti_regs[8] }, { CTI_INEN7, "INEN7", &cti_regs[9] }, { CTI_INEN8, "INEN8", &cti_regs[10] }, { CTI_OUTEN0, "OUTEN0", &cti_regs[11] }, { CTI_OUTEN1, "OUTEN1", &cti_regs[12] }, { CTI_OUTEN2, "OUTEN2", &cti_regs[13] }, { CTI_OUTEN3, "OUTEN3", &cti_regs[14] }, { CTI_OUTEN4, "OUTEN4", &cti_regs[15] }, { CTI_OUTEN5, "OUTEN5", &cti_regs[16] }, { CTI_OUTEN6, "OUTEN6", &cti_regs[17] }, { CTI_OUTEN7, "OUTEN7", &cti_regs[18] }, { CTI_OUTEN8, "OUTEN8", &cti_regs[19] }, { CTI_TRIN_STATUS, "TRIN", &cti_regs[20] }, { CTI_TROUT_STATUS, "TROUT", &cti_regs[21] }, { CTI_CHIN_STATUS, "CHIN", &cti_regs[22] }, { CTI_CHOU_STATUS, "CHOUT", &cti_regs[23] }, { CTI_APPSET, "APPSET", &cti_regs[24] }, { CTI_APPCLEAR, "APPCLR", &cti_regs[25] }, { CTI_APPPULSE, "APPPULSE", &cti_regs[26] }, { CTI_INACK, "INACK", &cti_regs[27] }, }; static int cti_find_reg_offset(const char *name) { unsigned int i; for (i = 0; i < ARRAY_SIZE(cti_names); i++) { if (!strcmp(name, cti_names[i].label)) return cti_names[i].offset; } LOG_ERROR("unknown CTI register %s", name); return -1; } int arm_cti_cleanup_all(void) { struct arm_cti *obj, *tmp; list_for_each_entry_safe(obj, tmp, &all_cti, lh) { if (obj->ap) dap_put_ap(obj->ap); free(obj->name); free(obj); } return ERROR_OK; } COMMAND_HANDLER(handle_cti_dump) { struct arm_cti *cti = CMD_DATA; struct adiv5_ap *ap = cti->ap; int retval = ERROR_OK; for (int i = 0; (retval == ERROR_OK) && (i < (int)ARRAY_SIZE(cti_names)); i++) retval = mem_ap_read_u32(ap, cti->spot.base + cti_names[i].offset, cti_names[i].p_val); if (retval == ERROR_OK) retval = dap_run(ap->dap); if (retval != ERROR_OK) return JIM_ERR; for (int i = 0; i < (int)ARRAY_SIZE(cti_names); i++) command_print(CMD, "%8.8s (0x%04"PRIx32") 0x%08"PRIx32, cti_names[i].label, cti_names[i].offset, *cti_names[i].p_val); return JIM_OK; } COMMAND_HANDLER(handle_cti_enable) { struct arm_cti *cti = CMD_DATA; bool on_off; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off); return arm_cti_enable(cti, on_off); } COMMAND_HANDLER(handle_cti_testmode) { struct arm_cti *cti = CMD_DATA; bool on_off; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off); return arm_cti_write_reg(cti, 0xf00, on_off ? 0x1 : 0x0); } COMMAND_HANDLER(handle_cti_write) { struct arm_cti *cti = CMD_DATA; int offset; uint32_t value; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; offset = cti_find_reg_offset(CMD_ARGV[0]); if (offset < 0) return ERROR_FAIL; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); return arm_cti_write_reg(cti, offset, value); } COMMAND_HANDLER(handle_cti_read) { struct arm_cti *cti = CMD_DATA; int offset; int retval; uint32_t value; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; offset = cti_find_reg_offset(CMD_ARGV[0]); if (offset < 0) return ERROR_FAIL; retval = arm_cti_read_reg(cti, offset, &value); if (retval != ERROR_OK) return retval; command_print(CMD, "0x%08"PRIx32, value); return ERROR_OK; } COMMAND_HANDLER(handle_cti_ack) { struct arm_cti *cti = CMD_DATA; uint32_t event; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], event); int retval = arm_cti_ack_events(cti, 1 << event); if (retval != ERROR_OK) return retval; return ERROR_OK; } COMMAND_HANDLER(handle_cti_channel) { struct arm_cti *cti = CMD_DATA; int retval = ERROR_OK; uint32_t ch_num; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], ch_num); if (!strcmp(CMD_ARGV[1], "gate")) retval = arm_cti_gate_channel(cti, ch_num); else if (!strcmp(CMD_ARGV[1], "ungate")) retval = arm_cti_ungate_channel(cti, ch_num); else if (!strcmp(CMD_ARGV[1], "pulse")) retval = arm_cti_pulse_channel(cti, ch_num); else if (!strcmp(CMD_ARGV[1], "set")) retval = arm_cti_set_channel(cti, ch_num); else if (!strcmp(CMD_ARGV[1], "clear")) retval = arm_cti_clear_channel(cti, ch_num); else { command_print(CMD, "Possible channel operations: gate|ungate|set|clear|pulse"); return ERROR_COMMAND_ARGUMENT_INVALID; } if (retval != ERROR_OK) return retval; return ERROR_OK; } static const struct command_registration cti_instance_command_handlers[] = { { .name = "dump", .mode = COMMAND_EXEC, .handler = handle_cti_dump, .help = "dump CTI registers", .usage = "", }, { .name = "enable", .mode = COMMAND_EXEC, .handler = handle_cti_enable, .help = "enable or disable the CTI", .usage = "'on'|'off'", }, { .name = "testmode", .mode = COMMAND_EXEC, .handler = handle_cti_testmode, .help = "enable or disable integration test mode", .usage = "'on'|'off'", }, { .name = "write", .mode = COMMAND_EXEC, .handler = handle_cti_write, .help = "write to a CTI register", .usage = "register_name value", }, { .name = "read", .mode = COMMAND_EXEC, .handler = handle_cti_read, .help = "read a CTI register", .usage = "register_name", }, { .name = "ack", .mode = COMMAND_EXEC, .handler = handle_cti_ack, .help = "acknowledge a CTI event", .usage = "event", }, { .name = "channel", .mode = COMMAND_EXEC, .handler = handle_cti_channel, .help = "do an operation on one CTI channel, possible operations: " "gate, ungate, set, clear and pulse", .usage = "channel_number operation", }, COMMAND_REGISTRATION_DONE }; static int cti_configure(struct jim_getopt_info *goi, struct arm_cti *cti) { /* parse config or cget options ... */ while (goi->argc > 0) { int e = adiv5_jim_mem_ap_spot_configure(&cti->spot, goi); if (e == JIM_CONTINUE) Jim_SetResultFormatted(goi->interp, "unknown option '%s'", Jim_String(goi->argv[0])); if (e != JIM_OK) return JIM_ERR; } if (!cti->spot.dap) { Jim_SetResultString(goi->interp, "-dap required when creating CTI", -1); return JIM_ERR; } return JIM_OK; } static int cti_create(struct jim_getopt_info *goi) { struct command_context *cmd_ctx; static struct arm_cti *cti; Jim_Obj *new_cmd; Jim_Cmd *cmd; const char *cp; int e; cmd_ctx = current_command_context(goi->interp); assert(cmd_ctx); if (goi->argc < 3) { Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options..."); return JIM_ERR; } /* COMMAND */ jim_getopt_obj(goi, &new_cmd); /* does this command exist? */ cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_NONE); if (cmd) { cp = Jim_GetString(new_cmd, NULL); Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp); return JIM_ERR; } /* Create it */ cti = calloc(1, sizeof(*cti)); if (!cti) return JIM_ERR; adiv5_mem_ap_spot_init(&cti->spot); /* Do the rest as "configure" options */ goi->isconfigure = 1; e = cti_configure(goi, cti); if (e != JIM_OK) { free(cti); return e; } cp = Jim_GetString(new_cmd, NULL); cti->name = strdup(cp); /* now - create the new cti name command */ const struct command_registration cti_subcommands[] = { { .chain = cti_instance_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct command_registration cti_commands[] = { { .name = cp, .mode = COMMAND_ANY, .help = "cti instance command group", .usage = "", .chain = cti_subcommands, }, COMMAND_REGISTRATION_DONE }; e = register_commands_with_data(cmd_ctx, NULL, cti_commands, cti); if (e != ERROR_OK) return JIM_ERR; list_add_tail(&cti->lh, &all_cti); cti->ap = dap_get_ap(cti->spot.dap, cti->spot.ap_num); if (!cti->ap) { Jim_SetResultString(goi->interp, "Cannot get AP", -1); return JIM_ERR; } return JIM_OK; } static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct jim_getopt_info goi; jim_getopt_setup(&goi, interp, argc - 1, argv + 1); if (goi.argc < 2) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "<name> [<cti_options> ...]"); return JIM_ERR; } return cti_create(&goi); } COMMAND_HANDLER(cti_handle_names) { struct arm_cti *obj; if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; list_for_each_entry(obj, &all_cti, lh) command_print(CMD, "%s", obj->name); return ERROR_OK; } static const struct command_registration cti_subcommand_handlers[] = { { .name = "create", .mode = COMMAND_ANY, .jim_handler = jim_cti_create, .usage = "name '-chain-position' name [options ...]", .help = "Creates a new CTI object", }, { .name = "names", .mode = COMMAND_ANY, .handler = cti_handle_names, .usage = "", .help = "Lists all registered CTI objects by name", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration cti_command_handlers[] = { { .name = "cti", .mode = COMMAND_CONFIG, .help = "CTI commands", .chain = cti_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; int cti_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, cti_command_handlers); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_cti.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2016 by Matthias Welwarsky * * * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM_CTI_H #define OPENOCD_TARGET_ARM_CTI_H /*define CTI(cross trigger interface)*/ #define CTI_CTR 0x0 #define CTI_INACK 0x10 #define CTI_APPSET 0x14 #define CTI_APPCLEAR 0x18 #define CTI_APPPULSE 0x1C #define CTI_INEN0 0x20 #define CTI_INEN1 0x24 #define CTI_INEN2 0x28 #define CTI_INEN3 0x2C #define CTI_INEN4 0x30 #define CTI_INEN5 0x34 #define CTI_INEN6 0x38 #define CTI_INEN7 0x3C #define CTI_INEN8 0x40 #define CTI_INEN(n) (0x20 + 4 * n) #define CTI_OUTEN0 0xA0 #define CTI_OUTEN1 0xA4 #define CTI_OUTEN2 0xA8 #define CTI_OUTEN3 0xAC #define CTI_OUTEN4 0xB0 #define CTI_OUTEN5 0xB4 #define CTI_OUTEN6 0xB8 #define CTI_OUTEN7 0xBC #define CTI_OUTEN8 0xC0 #define CTI_OUTEN(n) (0xA0 + 4 * n) #define CTI_TRIN_STATUS 0x130 #define CTI_TROUT_STATUS 0x134 #define CTI_CHIN_STATUS 0x138 #define CTI_CHOU_STATUS 0x13C #define CTI_GATE 0x140 #define CTI_UNLOCK 0xFB0 #define CTI_CHNL(x) (1 << x) #define CTI_TRIG_HALT 0 #define CTI_TRIG_RESUME 1 #define CTI_TRIG(n) (1 << CTI_TRIG_##n) /* forward-declare arm_cti struct */ struct arm_cti; struct adiv5_ap; extern const char *arm_cti_name(struct arm_cti *self); extern struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o); extern int arm_cti_enable(struct arm_cti *self, bool enable); extern int arm_cti_ack_events(struct arm_cti *self, uint32_t event); extern int arm_cti_gate_channel(struct arm_cti *self, uint32_t channel); extern int arm_cti_ungate_channel(struct arm_cti *self, uint32_t channel); extern int arm_cti_write_reg(struct arm_cti *self, unsigned int reg, uint32_t value); extern int arm_cti_read_reg(struct arm_cti *self, unsigned int reg, uint32_t *value); extern int arm_cti_pulse_channel(struct arm_cti *self, uint32_t channel); extern int arm_cti_set_channel(struct arm_cti *self, uint32_t channel); extern int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel); extern int arm_cti_cleanup_all(void); extern int cti_register_commands(struct command_context *cmd_ctx); #endif /* OPENOCD_TARGET_ARM_CTI_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_dap.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2016 by Matthias Welwarsky * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdlib.h> #include <stdint.h> #include "target/arm_adi_v5.h" #include "target/arm.h" #include "helper/list.h" #include "helper/command.h" #include "transport/transport.h" #include "jtag/interface.h" static LIST_HEAD(all_dap); extern struct adapter_driver *adapter_driver; /* DAP command support */ struct arm_dap_object { struct list_head lh; struct adiv5_dap dap; char *name; const struct swd_driver *swd; }; static void dap_instance_init(struct adiv5_dap *dap) { int i; /* Set up with safe defaults */ for (i = 0; i <= DP_APSEL_MAX; i++) { dap->ap[i].dap = dap; dap->ap[i].ap_num = DP_APSEL_INVALID; /* memaccess_tck max is 255 */ dap->ap[i].memaccess_tck = 255; /* Number of bits for tar autoincrement, impl. dep. at least 10 */ dap->ap[i].tar_autoincr_block = (1<<10); /* default CSW value */ dap->ap[i].csw_default = CSW_AHB_DEFAULT; dap->ap[i].cfg_reg = MEM_AP_REG_CFG_INVALID; /* mem_ap configuration reg (large physical addr, etc.) */ dap->ap[i].refcount = 0; dap->ap[i].config_ap_never_release = false; } INIT_LIST_HEAD(&dap->cmd_journal); INIT_LIST_HEAD(&dap->cmd_pool); } const char *adiv5_dap_name(struct adiv5_dap *self) { struct arm_dap_object *obj = container_of(self, struct arm_dap_object, dap); return obj->name; } const struct swd_driver *adiv5_dap_swd_driver(struct adiv5_dap *self) { struct arm_dap_object *obj = container_of(self, struct arm_dap_object, dap); return obj->swd; } struct adiv5_dap *adiv5_get_dap(struct arm_dap_object *obj) { return &obj->dap; } struct adiv5_dap *dap_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) { struct arm_dap_object *obj = NULL; const char *name; bool found = false; name = Jim_GetString(o, NULL); list_for_each_entry(obj, &all_dap, lh) { if (!strcmp(name, obj->name)) { found = true; break; } } if (found) return &obj->dap; return NULL; } static int dap_init_all(void) { struct arm_dap_object *obj; int retval; LOG_DEBUG("Initializing all DAPs ..."); list_for_each_entry(obj, &all_dap, lh) { struct adiv5_dap *dap = &obj->dap; /* with hla, dap is just a dummy */ if (transport_is_hla()) continue; /* skip taps that are disabled */ if (!dap->tap->enabled) continue; if (transport_is_swd()) { dap->ops = &swd_dap_ops; obj->swd = adapter_driver->swd_ops; } else if (transport_is_dapdirect_swd()) { dap->ops = adapter_driver->dap_swd_ops; } else if (transport_is_dapdirect_jtag()) { dap->ops = adapter_driver->dap_jtag_ops; } else dap->ops = &jtag_dp_ops; if (dap->adi_version == 0) { LOG_DEBUG("DAP %s configured by default to use ADIv5 protocol", jtag_tap_name(dap->tap)); dap->adi_version = 5; } else { LOG_DEBUG("DAP %s configured to use %s protocol by user cfg file", jtag_tap_name(dap->tap), is_adiv6(dap) ? "ADIv6" : "ADIv5"); } retval = dap->ops->connect(dap); if (retval != ERROR_OK) return retval; /* see if address size of ROM Table is greater than 32-bits */ if (is_adiv6(dap)) { uint32_t dpidr1; retval = dap->ops->queue_dp_read(dap, DP_DPIDR1, &dpidr1); if (retval != ERROR_OK) { LOG_ERROR("DAP read of DPIDR1 failed..."); return retval; } retval = dap_run(dap); if (retval != ERROR_OK) { LOG_ERROR("DAP read of DPIDR1 failed..."); return retval; } dap->asize = dpidr1 & DP_DPIDR1_ASIZE_MASK; } } return ERROR_OK; } int dap_cleanup_all(void) { struct arm_dap_object *obj, *tmp; struct adiv5_dap *dap; list_for_each_entry_safe(obj, tmp, &all_dap, lh) { dap = &obj->dap; for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) { if (dap->ap[i].refcount != 0) LOG_ERROR("BUG: refcount AP#%u still %u at exit", i, dap->ap[i].refcount); } if (dap->ops && dap->ops->quit) dap->ops->quit(dap); free(obj->name); free(obj); } return ERROR_OK; } enum dap_cfg_param { CFG_CHAIN_POSITION, CFG_IGNORE_SYSPWRUPACK, CFG_DP_ID, CFG_INSTANCE_ID, CFG_ADIV6, CFG_ADIV5, }; static const struct jim_nvp nvp_config_opts[] = { { .name = "-chain-position", .value = CFG_CHAIN_POSITION }, { .name = "-ignore-syspwrupack", .value = CFG_IGNORE_SYSPWRUPACK }, { .name = "-dp-id", .value = CFG_DP_ID }, { .name = "-instance-id", .value = CFG_INSTANCE_ID }, { .name = "-adiv6", .value = CFG_ADIV6 }, { .name = "-adiv5", .value = CFG_ADIV5 }, { .name = NULL, .value = -1 } }; static int dap_configure(struct jim_getopt_info *goi, struct arm_dap_object *dap) { struct jim_nvp *n; int e; /* parse config ... */ while (goi->argc > 0) { Jim_SetEmptyResult(goi->interp); e = jim_getopt_nvp(goi, nvp_config_opts, &n); if (e != JIM_OK) { jim_getopt_nvp_unknown(goi, nvp_config_opts, 0); return e; } switch (n->value) { case CFG_CHAIN_POSITION: { Jim_Obj *o_t; e = jim_getopt_obj(goi, &o_t); if (e != JIM_OK) return e; struct jtag_tap *tap; tap = jtag_tap_by_jim_obj(goi->interp, o_t); if (!tap) { Jim_SetResultString(goi->interp, "-chain-position is invalid", -1); return JIM_ERR; } dap->dap.tap = tap; /* loop for more */ break; } case CFG_IGNORE_SYSPWRUPACK: dap->dap.ignore_syspwrupack = true; break; case CFG_DP_ID: { jim_wide w; e = jim_getopt_wide(goi, &w); if (e != JIM_OK) { Jim_SetResultFormatted(goi->interp, "create %s: bad parameter %s", dap->name, n->name); return JIM_ERR; } if (w < 0 || w > DP_TARGETSEL_DPID_MASK) { Jim_SetResultFormatted(goi->interp, "create %s: %s out of range", dap->name, n->name); return JIM_ERR; } dap->dap.multidrop_targetsel = (dap->dap.multidrop_targetsel & DP_TARGETSEL_INSTANCEID_MASK) | (w & DP_TARGETSEL_DPID_MASK); dap->dap.multidrop_dp_id_valid = true; break; } case CFG_INSTANCE_ID: { jim_wide w; e = jim_getopt_wide(goi, &w); if (e != JIM_OK) { Jim_SetResultFormatted(goi->interp, "create %s: bad parameter %s", dap->name, n->name); return JIM_ERR; } if (w < 0 || w > 15) { Jim_SetResultFormatted(goi->interp, "create %s: %s out of range", dap->name, n->name); return JIM_ERR; } dap->dap.multidrop_targetsel = (dap->dap.multidrop_targetsel & DP_TARGETSEL_DPID_MASK) | ((w << DP_TARGETSEL_INSTANCEID_SHIFT) & DP_TARGETSEL_INSTANCEID_MASK); dap->dap.multidrop_instance_id_valid = true; break; } case CFG_ADIV6: dap->dap.adi_version = 6; break; case CFG_ADIV5: dap->dap.adi_version = 5; break; default: break; } } return JIM_OK; } static int dap_check_config(struct adiv5_dap *dap) { if (transport_is_jtag() || transport_is_dapdirect_jtag() || transport_is_hla()) return ERROR_OK; struct arm_dap_object *obj; bool new_multidrop = dap_is_multidrop(dap); bool had_multidrop = new_multidrop; uint32_t targetsel = dap->multidrop_targetsel; unsigned int non_multidrop_count = had_multidrop ? 0 : 1; list_for_each_entry(obj, &all_dap, lh) { struct adiv5_dap *dap_it = &obj->dap; if (transport_is_swd()) { if (dap_is_multidrop(dap_it)) { had_multidrop = true; if (new_multidrop && dap_it->multidrop_targetsel == targetsel) { uint32_t dp_id = targetsel & DP_TARGETSEL_DPID_MASK; uint32_t instance_id = targetsel >> DP_TARGETSEL_INSTANCEID_SHIFT; LOG_ERROR("%s and %s have the same multidrop selectors -dp-id 0x%08" PRIx32 " and -instance-id 0x%" PRIx32, obj->name, adiv5_dap_name(dap), dp_id, instance_id); return ERROR_FAIL; } } else { non_multidrop_count++; } } else if (transport_is_dapdirect_swd()) { non_multidrop_count++; } } if (non_multidrop_count > 1) { LOG_ERROR("Two or more SWD non multidrop DAPs are not supported"); return ERROR_FAIL; } if (had_multidrop && non_multidrop_count) { LOG_ERROR("Mixing of SWD multidrop DAPs and non multidrop DAPs is not supported"); return ERROR_FAIL; } return ERROR_OK; } static int dap_create(struct jim_getopt_info *goi) { struct command_context *cmd_ctx; static struct arm_dap_object *dap; Jim_Obj *new_cmd; Jim_Cmd *cmd; const char *cp; int e; cmd_ctx = current_command_context(goi->interp); assert(cmd_ctx); if (goi->argc < 3) { Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options..."); return JIM_ERR; } /* COMMAND */ jim_getopt_obj(goi, &new_cmd); /* does this command exist? */ cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_NONE); if (cmd) { cp = Jim_GetString(new_cmd, NULL); Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp); return JIM_ERR; } /* Create it */ dap = calloc(1, sizeof(struct arm_dap_object)); if (!dap) return JIM_ERR; dap_instance_init(&dap->dap); cp = Jim_GetString(new_cmd, NULL); dap->name = strdup(cp); e = dap_configure(goi, dap); if (e != JIM_OK) goto err; if (!dap->dap.tap) { Jim_SetResultString(goi->interp, "-chain-position required when creating DAP", -1); e = JIM_ERR; goto err; } e = dap_check_config(&dap->dap); if (e != ERROR_OK) { e = JIM_ERR; goto err; } struct command_registration dap_create_commands[] = { { .name = cp, .mode = COMMAND_ANY, .help = "dap instance command group", .usage = "", .chain = dap_instance_commands, }, COMMAND_REGISTRATION_DONE }; /* don't expose the instance commands when using hla */ if (transport_is_hla()) dap_create_commands[0].chain = NULL; e = register_commands_with_data(cmd_ctx, NULL, dap_create_commands, dap); if (e != ERROR_OK) { e = JIM_ERR; goto err; } list_add_tail(&dap->lh, &all_dap); return JIM_OK; err: free(dap->name); free(dap); return e; } static int jim_dap_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct jim_getopt_info goi; jim_getopt_setup(&goi, interp, argc - 1, argv + 1); if (goi.argc < 2) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "<name> [<dap_options> ...]"); return JIM_ERR; } return dap_create(&goi); } COMMAND_HANDLER(handle_dap_names) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct arm_dap_object *obj; list_for_each_entry(obj, &all_dap, lh) command_print(CMD, "%s", obj->name); return ERROR_OK; } COMMAND_HANDLER(handle_dap_init) { return dap_init_all(); } COMMAND_HANDLER(handle_dap_info_command) { struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct adiv5_dap *dap = arm->dap; uint64_t apsel; if (!dap) { LOG_ERROR("DAP instance not available. Probably a HLA target..."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } switch (CMD_ARGC) { case 0: apsel = dap->apsel; break; case 1: if (!strcmp(CMD_ARGV[0], "root")) { if (!is_adiv6(dap)) { command_print(CMD, "Option \"root\" not allowed with ADIv5 DAP"); return ERROR_COMMAND_ARGUMENT_INVALID; } int retval = adiv6_dap_read_baseptr(CMD, dap, &apsel); if (retval != ERROR_OK) { command_print(CMD, "Failed reading DAP baseptr"); return retval; } break; } COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); if (!is_ap_num_valid(dap, apsel)) return ERROR_COMMAND_SYNTAX_ERROR; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } struct adiv5_ap *ap = dap_get_ap(dap, apsel); if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; } int retval = dap_info_command(CMD, ap); dap_put_ap(ap); return retval; } static const struct command_registration dap_subcommand_handlers[] = { { .name = "create", .mode = COMMAND_ANY, .jim_handler = jim_dap_create, .usage = "name '-chain-position' name", .help = "Creates a new DAP instance", }, { .name = "names", .mode = COMMAND_ANY, .handler = handle_dap_names, .usage = "", .help = "Lists all registered DAP instances by name", }, { .name = "init", .mode = COMMAND_ANY, .handler = handle_dap_init, .usage = "", .help = "Initialize all registered DAP instances" }, { .name = "info", .handler = handle_dap_info_command, .mode = COMMAND_EXEC, .help = "display ROM table for specified MEM-AP (default MEM-AP of current target) " "or the ADIv6 root ROM table of current target's DAP", .usage = "[ap_num | 'root']", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration dap_commands[] = { { .name = "dap", .mode = COMMAND_CONFIG, .help = "DAP commands", .chain = dap_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; int dap_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, dap_commands); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_disassembler.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2009 by David Brownell * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include "arm_disassembler.h" #include <helper/log.h> #if HAVE_CAPSTONE #include <capstone.h> #endif /* * This disassembler supports two main functions for OpenOCD: * * - Various "disassemble" commands. OpenOCD can serve as a * machine-language debugger, without help from GDB. * * - Single stepping. Not all ARM cores support hardware single * stepping. To work without that support, the debugger must * be able to decode instructions to find out where to put a * "next instruction" breakpoint. * * In addition, interpretation of ETM trace data needs some of the * decoding mechanisms. * * At this writing (September 2009) neither function is complete. * * - ARM decoding * * Old-style syntax (not UAL) is generally used * * VFP instructions are not understood (ARMv5 and later) * except as coprocessor 10/11 operations * * Most ARM instructions through ARMv6 are decoded, but some * of the post-ARMv4 opcodes may not be handled yet * CPS, SDIV, UDIV, LDREX*, STREX*, QASX, ... * * NEON instructions are not understood (ARMv7-A) * * - Thumb/Thumb2 decoding * * UAL syntax should be consistently used * * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should * be handled properly. Accordingly, so should the subset * used in Cortex-M0/M1; and "original" 16-bit Thumb from * ARMv4T and ARMv5T. * * Conditional effects of Thumb2 "IT" (if-then) instructions * are not handled: the affected instructions are not shown * with their now-conditional suffixes. * * Some ARMv6 and ARMv7-M Thumb2 instructions may not be * handled (minimally for coprocessor access). * * SIMD instructions, and some other Thumb2 instructions * from ARMv7-A, are not understood. * * - ThumbEE decoding * * As a Thumb2 variant, the Thumb2 comments (above) apply. * * Opcodes changed by ThumbEE mode are not handled; these * instructions wrongly decode as LDM and STM. * * - Jazelle decoding ... no support whatsoever for Jazelle mode * or decoding. ARM encourages use of the more generic ThumbEE * mode, instead of Jazelle mode, in current chips. * * - Single-step/emulation ... spotty support, which is only weakly * tested. Thumb2 is not supported. (Arguably a full simulator * is not needed to support just single stepping. Recognizing * branch vs non-branch instructions suffices, except when the * instruction faults and triggers a synchronous exception which * can be intercepted using other means.) * * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and * ARM v7-R edition" gives the most complete coverage of the various * generations of ARM instructions. At this writing it is publicly * accessible to anyone willing to create an account at the ARM * web site; see http://www.arm.com/documentation/ for information. * * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides * more details relevant to the Thumb2-only processors (such as * the Cortex-M implementations). */ /* textual representation of the condition field * ALways (default) is omitted (empty string) */ static const char *arm_condition_strings[] = { "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV" }; /* make up for C's missing ROR */ static uint32_t ror(uint32_t value, int places) { return (value >> places) | (value << (32 - places)); } static int evaluate_unknown(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", address, opcode); return ERROR_OK; } static int evaluate_pld(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { /* PLD */ if ((opcode & 0x0d30f000) == 0x0510f000) { uint8_t rn; uint8_t u; unsigned offset; instruction->type = ARM_PLD; rn = (opcode & 0xf0000) >> 16; u = (opcode & 0x00800000) >> 23; if (rn == 0xf) { /* literal */ offset = opcode & 0x0fff; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD %s%d", address, opcode, u ? "" : "-", offset); } else { uint8_t i, r; i = (opcode & 0x02000000) >> 25; r = (opcode & 0x00400000) >> 22; if (i) { /* register PLD{W} [<Rn>,+/-<Rm>{, <shift>}] */ offset = (opcode & 0x0F80) >> 7; uint8_t rm; rm = opcode & 0xf; if (offset == 0) { /* No shift */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d]", address, opcode, r ? "" : "W", rn, u ? "" : "-", rm); } else { uint8_t shift; shift = (opcode & 0x60) >> 5; if (shift == 0x0) { /* LSL */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, LSL #0x%x)", address, opcode, r ? "" : "W", rn, u ? "" : "-", rm, offset); } else if (shift == 0x1) { /* LSR */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, LSR #0x%x)", address, opcode, r ? "" : "W", rn, u ? "" : "-", rm, offset); } else if (shift == 0x2) { /* ASR */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, ASR #0x%x)", address, opcode, r ? "" : "W", rn, u ? "" : "-", rm, offset); } else if (shift == 0x3) { /* ROR */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, ROR #0x%x)", address, opcode, r ? "" : "W", rn, u ? "" : "-", rm, offset); } } } else { /* immediate PLD{W} [<Rn>, #+/-<imm12>] */ offset = opcode & 0x0fff; if (offset == 0) { snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d]", address, opcode, r ? "" : "W", rn); } else { snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, #%s%d]", address, opcode, r ? "" : "W", rn, u ? "" : "-", offset); } } } return ERROR_OK; } /* DSB */ if ((opcode & 0x07f000f0) == 0x05700040) { instruction->type = ARM_DSB; char *opt; switch (opcode & 0x0000000f) { case 0xf: opt = "SY"; break; case 0xe: opt = "ST"; break; case 0xb: opt = "ISH"; break; case 0xa: opt = "ISHST"; break; case 0x7: opt = "NSH"; break; case 0x6: opt = "NSHST"; break; case 0x3: opt = "OSH"; break; case 0x2: opt = "OSHST"; break; default: opt = "UNK"; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tDSB %s", address, opcode, opt); return ERROR_OK; } /* ISB */ if ((opcode & 0x07f000f0) == 0x05700060) { instruction->type = ARM_ISB; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tISB %s", address, opcode, ((opcode & 0x0000000f) == 0xf) ? "SY" : "UNK"); return ERROR_OK; } return evaluate_unknown(opcode, address, instruction); } static int evaluate_srs(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { const char *wback = (opcode & (1 << 21)) ? "!" : ""; const char *mode = ""; switch ((opcode >> 23) & 0x3) { case 0: mode = "DA"; break; case 1: /* "IA" is default */ break; case 2: mode = "DB"; break; case 3: mode = "IB"; break; } switch (opcode & 0x0e500000) { case 0x08400000: snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSRS%s\tSP%s, #%d", address, opcode, mode, wback, (unsigned)(opcode & 0x1f)); break; case 0x08100000: snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tRFE%s\tr%d%s", address, opcode, mode, (unsigned)((opcode >> 16) & 0xf), wback); break; default: return evaluate_unknown(opcode, address, instruction); } return ERROR_OK; } static int evaluate_swi(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { instruction->type = ARM_SWI; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSVC %#6.6" PRIx32, address, opcode, (opcode & 0xffffff)); return ERROR_OK; } static int evaluate_blx_imm(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { int offset; uint32_t immediate; uint32_t target_address; instruction->type = ARM_BLX; immediate = opcode & 0x00ffffff; /* sign extend 24-bit immediate */ if (immediate & 0x00800000) offset = 0xff000000 | immediate; else offset = immediate; /* shift two bits left */ offset <<= 2; /* odd/event halfword */ if (opcode & 0x01000000) offset |= 0x2; target_address = address + 8 + offset; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX 0x%8.8" PRIx32 "", address, opcode, target_address); instruction->info.b_bl_bx_blx.reg_operand = -1; instruction->info.b_bl_bx_blx.target_address = target_address; return ERROR_OK; } static int evaluate_b_bl(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t l; uint32_t immediate; int offset; uint32_t target_address; immediate = opcode & 0x00ffffff; l = (opcode & 0x01000000) >> 24; /* sign extend 24-bit immediate */ if (immediate & 0x00800000) offset = 0xff000000 | immediate; else offset = immediate; /* shift two bits left */ offset <<= 2; target_address = address + 8 + offset; if (l) instruction->type = ARM_BL; else instruction->type = ARM_B; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tB%s%s 0x%8.8" PRIx32, address, opcode, (l) ? "L" : "", COND(opcode), target_address); instruction->info.b_bl_bx_blx.reg_operand = -1; instruction->info.b_bl_bx_blx.target_address = target_address; return ERROR_OK; } /* Coprocessor load/store and double register transfers * both normal and extended instruction space (condition field b1111) */ static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t cp_num = (opcode & 0xf00) >> 8; /* MCRR or MRRC */ if (((opcode & 0x0ff00000) == 0x0c400000) || ((opcode & 0x0ff00000) == 0x0c500000)) { uint8_t cp_opcode, rd, rn, crm; char *mnemonic; cp_opcode = (opcode & 0xf0) >> 4; rd = (opcode & 0xf000) >> 12; rn = (opcode & 0xf0000) >> 16; crm = (opcode & 0xf); /* MCRR */ if ((opcode & 0x0ff00000) == 0x0c400000) { instruction->type = ARM_MCRR; mnemonic = "MCRR"; } else if ((opcode & 0x0ff00000) == 0x0c500000) { /* MRRC */ instruction->type = ARM_MRRC; mnemonic = "MRRC"; } else { LOG_ERROR("Unknown instruction"); return ERROR_FAIL; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s p%i, %x, r%i, r%i, c%i", address, opcode, mnemonic, ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode), COND(opcode), cp_num, cp_opcode, rd, rn, crm); } else {/* LDC or STC */ uint8_t crd, rn, offset; uint8_t u; char *mnemonic; char addressing_mode[32]; crd = (opcode & 0xf000) >> 12; rn = (opcode & 0xf0000) >> 16; offset = (opcode & 0xff) << 2; /* load/store */ if (opcode & 0x00100000) { instruction->type = ARM_LDC; mnemonic = "LDC"; } else { instruction->type = ARM_STC; mnemonic = "STC"; } u = (opcode & 0x00800000) >> 23; /* addressing modes */ if ((opcode & 0x01200000) == 0x01000000)/* offset */ snprintf(addressing_mode, 32, "[r%i, #%s%d]", rn, u ? "" : "-", offset); else if ((opcode & 0x01200000) == 0x01200000) /* pre-indexed */ snprintf(addressing_mode, 32, "[r%i, #%s%d]!", rn, u ? "" : "-", offset); else if ((opcode & 0x01200000) == 0x00200000) /* post-indexed */ snprintf(addressing_mode, 32, "[r%i], #%s%d", rn, u ? "" : "-", offset); else if ((opcode & 0x01200000) == 0x00000000) /* unindexed */ snprintf(addressing_mode, 32, "[r%i], {%d}", rn, offset >> 2); snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s p%i, c%i, %s", address, opcode, mnemonic, ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode), (opcode & (1 << 22)) ? "L" : "", cp_num, crd, addressing_mode); } return ERROR_OK; } /* Coprocessor data processing instructions * Coprocessor register transfer instructions * both normal and extended instruction space (condition field b1111) */ static int evaluate_cdp_mcr_mrc(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { const char *cond; char *mnemonic; uint8_t cp_num, opcode_1, crd_rd, crn, crm, opcode_2; cond = ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode); cp_num = (opcode & 0xf00) >> 8; crd_rd = (opcode & 0xf000) >> 12; crn = (opcode & 0xf0000) >> 16; crm = (opcode & 0xf); opcode_2 = (opcode & 0xe0) >> 5; /* CDP or MRC/MCR */ if (opcode & 0x00000010) { /* bit 4 set -> MRC/MCR */ if (opcode & 0x00100000) { /* bit 20 set -> MRC */ instruction->type = ARM_MRC; mnemonic = "MRC"; } else {/* bit 20 not set -> MCR */ instruction->type = ARM_MCR; mnemonic = "MCR"; } opcode_1 = (opcode & 0x00e00000) >> 21; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s p%i, 0x%2.2x, r%i, c%i, c%i, 0x%2.2x", address, opcode, mnemonic, cond, cp_num, opcode_1, crd_rd, crn, crm, opcode_2); } else {/* bit 4 not set -> CDP */ instruction->type = ARM_CDP; mnemonic = "CDP"; opcode_1 = (opcode & 0x00f00000) >> 20; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s p%i, 0x%2.2x, c%i, c%i, c%i, 0x%2.2x", address, opcode, mnemonic, cond, cp_num, opcode_1, crd_rd, crn, crm, opcode_2); } return ERROR_OK; } /* Load/store instructions */ static int evaluate_load_store(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t i, p, u, b, w, l; uint8_t rn, rd; char *operation;/* "LDR" or "STR" */ char *suffix; /* "", "B", "T", "BT" */ char offset[32]; /* examine flags */ i = (opcode & 0x02000000) >> 25; p = (opcode & 0x01000000) >> 24; u = (opcode & 0x00800000) >> 23; b = (opcode & 0x00400000) >> 22; w = (opcode & 0x00200000) >> 21; l = (opcode & 0x00100000) >> 20; /* target register */ rd = (opcode & 0xf000) >> 12; /* base register */ rn = (opcode & 0xf0000) >> 16; instruction->info.load_store.rd = rd; instruction->info.load_store.rn = rn; instruction->info.load_store.u = u; /* determine operation */ if (l) operation = "LDR"; else operation = "STR"; /* determine instruction type and suffix */ if (b) { if ((p == 0) && (w == 1)) { if (l) instruction->type = ARM_LDRBT; else instruction->type = ARM_STRBT; suffix = "BT"; } else { if (l) instruction->type = ARM_LDRB; else instruction->type = ARM_STRB; suffix = "B"; } } else { if ((p == 0) && (w == 1)) { if (l) instruction->type = ARM_LDRT; else instruction->type = ARM_STRT; suffix = "T"; } else { if (l) instruction->type = ARM_LDR; else instruction->type = ARM_STR; suffix = ""; } } if (!i) { /* #+-<offset_12> */ uint32_t offset_12 = (opcode & 0xfff); if (offset_12) snprintf(offset, 32, ", #%s0x%" PRIx32 "", (u) ? "" : "-", offset_12); else snprintf(offset, 32, "%s", ""); instruction->info.load_store.offset_mode = 0; instruction->info.load_store.offset.offset = offset_12; } else {/* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */ uint8_t shift_imm, shift; uint8_t rm; shift_imm = (opcode & 0xf80) >> 7; shift = (opcode & 0x60) >> 5; rm = (opcode & 0xf); /* LSR encodes a shift by 32 bit as 0x0 */ if ((shift == 0x1) && (shift_imm == 0x0)) shift_imm = 0x20; /* ASR encodes a shift by 32 bit as 0x0 */ if ((shift == 0x2) && (shift_imm == 0x0)) shift_imm = 0x20; /* ROR by 32 bit is actually a RRX */ if ((shift == 0x3) && (shift_imm == 0x0)) shift = 0x4; instruction->info.load_store.offset_mode = 1; instruction->info.load_store.offset.reg.rm = rm; instruction->info.load_store.offset.reg.shift = shift; instruction->info.load_store.offset.reg.shift_imm = shift_imm; if ((shift_imm == 0x0) && (shift == 0x0)) /* +-<Rm> */ snprintf(offset, 32, ", %sr%i", (u) ? "" : "-", rm); else { /* +-<Rm>, <Shift>, #<shift_imm> */ switch (shift) { case 0x0: /* LSL */ snprintf(offset, 32, ", %sr%i, LSL #0x%x", (u) ? "" : "-", rm, shift_imm); break; case 0x1: /* LSR */ snprintf(offset, 32, ", %sr%i, LSR #0x%x", (u) ? "" : "-", rm, shift_imm); break; case 0x2: /* ASR */ snprintf(offset, 32, ", %sr%i, ASR #0x%x", (u) ? "" : "-", rm, shift_imm); break; case 0x3: /* ROR */ snprintf(offset, 32, ", %sr%i, ROR #0x%x", (u) ? "" : "-", rm, shift_imm); break; case 0x4: /* RRX */ snprintf(offset, 32, ", %sr%i, RRX", (u) ? "" : "-", rm); break; } } } if (p == 1) { if (w == 0) { /* offset */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i%s]", address, opcode, operation, COND(opcode), suffix, rd, rn, offset); instruction->info.load_store.index_mode = 0; } else {/* pre-indexed */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i%s]!", address, opcode, operation, COND(opcode), suffix, rd, rn, offset); instruction->info.load_store.index_mode = 1; } } else {/* post-indexed */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i]%s", address, opcode, operation, COND(opcode), suffix, rd, rn, offset); instruction->info.load_store.index_mode = 2; } return ERROR_OK; } static int evaluate_extend(uint32_t opcode, uint32_t address, char *cp) { unsigned rm = (opcode >> 0) & 0xf; unsigned rd = (opcode >> 12) & 0xf; unsigned rn = (opcode >> 16) & 0xf; char *type, *rot; switch ((opcode >> 24) & 0x3) { case 0: type = "B16"; break; case 1: sprintf(cp, "UNDEFINED"); return ARM_UNDEFINED_INSTRUCTION; case 2: type = "B"; break; default: type = "H"; break; } switch ((opcode >> 10) & 0x3) { case 0: rot = ""; break; case 1: rot = ", ROR #8"; break; case 2: rot = ", ROR #16"; break; default: rot = ", ROR #24"; break; } if (rn == 0xf) { sprintf(cp, "%cXT%s%s\tr%d, r%d%s", (opcode & (1 << 22)) ? 'U' : 'S', type, COND(opcode), rd, rm, rot); return ARM_MOV; } else { sprintf(cp, "%cXTA%s%s\tr%d, r%d, r%d%s", (opcode & (1 << 22)) ? 'U' : 'S', type, COND(opcode), rd, rn, rm, rot); return ARM_ADD; } } static int evaluate_p_add_sub(uint32_t opcode, uint32_t address, char *cp) { char *prefix; char *op; int type; switch ((opcode >> 20) & 0x7) { case 1: prefix = "S"; break; case 2: prefix = "Q"; break; case 3: prefix = "SH"; break; case 5: prefix = "U"; break; case 6: prefix = "UQ"; break; case 7: prefix = "UH"; break; default: goto undef; } switch ((opcode >> 5) & 0x7) { case 0: op = "ADD16"; type = ARM_ADD; break; case 1: op = "ADDSUBX"; type = ARM_ADD; break; case 2: op = "SUBADDX"; type = ARM_SUB; break; case 3: op = "SUB16"; type = ARM_SUB; break; case 4: op = "ADD8"; type = ARM_ADD; break; case 7: op = "SUB8"; type = ARM_SUB; break; default: goto undef; } sprintf(cp, "%s%s%s\tr%d, r%d, r%d", prefix, op, COND(opcode), (int) (opcode >> 12) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf); return type; undef: /* these opcodes might be used someday */ sprintf(cp, "UNDEFINED"); return ARM_UNDEFINED_INSTRUCTION; } /* ARMv6 and later support "media" instructions (includes SIMD) */ static int evaluate_media(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { char *cp = instruction->text; char *mnemonic = NULL; sprintf(cp, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t", address, opcode); cp = strchr(cp, 0); /* parallel add/subtract */ if ((opcode & 0x01800000) == 0x00000000) { instruction->type = evaluate_p_add_sub(opcode, address, cp); return ERROR_OK; } /* halfword pack */ if ((opcode & 0x01f00020) == 0x00800000) { char *type, *shift; unsigned imm = (unsigned) (opcode >> 7) & 0x1f; if (opcode & (1 << 6)) { type = "TB"; shift = "ASR"; if (imm == 0) imm = 32; } else { type = "BT"; shift = "LSL"; } sprintf(cp, "PKH%s%s\tr%d, r%d, r%d, %s #%d", type, COND(opcode), (int) (opcode >> 12) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, shift, imm); return ERROR_OK; } /* word saturate */ if ((opcode & 0x01a00020) == 0x00a00000) { char *shift; unsigned imm = (unsigned) (opcode >> 7) & 0x1f; if (opcode & (1 << 6)) { shift = "ASR"; if (imm == 0) imm = 32; } else shift = "LSL"; sprintf(cp, "%cSAT%s\tr%d, #%d, r%d, %s #%d", (opcode & (1 << 22)) ? 'U' : 'S', COND(opcode), (int) (opcode >> 12) & 0xf, (int) (opcode >> 16) & 0x1f, (int) (opcode >> 0) & 0xf, shift, imm); return ERROR_OK; } /* sign extension */ if ((opcode & 0x018000f0) == 0x00800070) { instruction->type = evaluate_extend(opcode, address, cp); return ERROR_OK; } /* multiplies */ if ((opcode & 0x01f00080) == 0x01000000) { unsigned rn = (opcode >> 12) & 0xf; if (rn != 0xf) sprintf(cp, "SML%cD%s%s\tr%d, r%d, r%d, r%d", (opcode & (1 << 6)) ? 'S' : 'A', (opcode & (1 << 5)) ? "X" : "", COND(opcode), (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, (int) (opcode >> 8) & 0xf, rn); else sprintf(cp, "SMU%cD%s%s\tr%d, r%d, r%d", (opcode & (1 << 6)) ? 'S' : 'A', (opcode & (1 << 5)) ? "X" : "", COND(opcode), (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, (int) (opcode >> 8) & 0xf); return ERROR_OK; } if ((opcode & 0x01f00000) == 0x01400000) { sprintf(cp, "SML%cLD%s%s\tr%d, r%d, r%d, r%d", (opcode & (1 << 6)) ? 'S' : 'A', (opcode & (1 << 5)) ? "X" : "", COND(opcode), (int) (opcode >> 12) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, (int) (opcode >> 8) & 0xf); return ERROR_OK; } if ((opcode & 0x01f00000) == 0x01500000) { unsigned rn = (opcode >> 12) & 0xf; switch (opcode & 0xc0) { case 3: if (rn == 0xf) goto undef; /* FALL THROUGH */ case 0: break; default: goto undef; } if (rn != 0xf) sprintf(cp, "SMML%c%s%s\tr%d, r%d, r%d, r%d", (opcode & (1 << 6)) ? 'S' : 'A', (opcode & (1 << 5)) ? "R" : "", COND(opcode), (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, (int) (opcode >> 8) & 0xf, rn); else sprintf(cp, "SMMUL%s%s\tr%d, r%d, r%d", (opcode & (1 << 5)) ? "R" : "", COND(opcode), (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, (int) (opcode >> 8) & 0xf); return ERROR_OK; } /* simple matches against the remaining decode bits */ switch (opcode & 0x01f000f0) { case 0x00a00030: case 0x00e00030: /* parallel halfword saturate */ sprintf(cp, "%cSAT16%s\tr%d, #%d, r%d", (opcode & (1 << 22)) ? 'U' : 'S', COND(opcode), (int) (opcode >> 12) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf); return ERROR_OK; case 0x00b00030: mnemonic = "REV"; break; case 0x00b000b0: mnemonic = "REV16"; break; case 0x00f000b0: mnemonic = "REVSH"; break; case 0x008000b0: /* select bytes */ sprintf(cp, "SEL%s\tr%d, r%d, r%d", COND(opcode), (int) (opcode >> 12) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf); return ERROR_OK; case 0x01800010: /* unsigned sum of absolute differences */ if (((opcode >> 12) & 0xf) == 0xf) sprintf(cp, "USAD8%s\tr%d, r%d, r%d", COND(opcode), (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, (int) (opcode >> 8) & 0xf); else sprintf(cp, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode), (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, (int) (opcode >> 8) & 0xf, (int) (opcode >> 12) & 0xf); return ERROR_OK; } if (mnemonic) { unsigned rm = (opcode >> 0) & 0xf; unsigned rd = (opcode >> 12) & 0xf; sprintf(cp, "%s%s\tr%d, r%d", mnemonic, COND(opcode), rm, rd); return ERROR_OK; } undef: /* these opcodes might be used someday */ sprintf(cp, "UNDEFINED"); return ERROR_OK; } /* Miscellaneous load/store instructions */ static int evaluate_misc_load_store(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t p, u, i, w, l, s, h; uint8_t rn, rd; char *operation;/* "LDR" or "STR" */ char *suffix; /* "H", "SB", "SH", "D" */ char offset[32]; /* examine flags */ p = (opcode & 0x01000000) >> 24; u = (opcode & 0x00800000) >> 23; i = (opcode & 0x00400000) >> 22; w = (opcode & 0x00200000) >> 21; l = (opcode & 0x00100000) >> 20; s = (opcode & 0x00000040) >> 6; h = (opcode & 0x00000020) >> 5; /* target register */ rd = (opcode & 0xf000) >> 12; /* base register */ rn = (opcode & 0xf0000) >> 16; instruction->info.load_store.rd = rd; instruction->info.load_store.rn = rn; instruction->info.load_store.u = u; /* determine instruction type and suffix */ if (s) {/* signed */ if (l) {/* load */ if (h) { operation = "LDR"; instruction->type = ARM_LDRSH; suffix = "SH"; } else { operation = "LDR"; instruction->type = ARM_LDRSB; suffix = "SB"; } } else {/* there are no signed stores, so this is used to encode double-register *load/stores */ suffix = "D"; if (h) { operation = "STR"; instruction->type = ARM_STRD; } else { operation = "LDR"; instruction->type = ARM_LDRD; } } } else {/* unsigned */ suffix = "H"; if (l) {/* load */ operation = "LDR"; instruction->type = ARM_LDRH; } else {/* store */ operation = "STR"; instruction->type = ARM_STRH; } } if (i) {/* Immediate offset/index (#+-<offset_8>)*/ uint32_t offset_8 = ((opcode & 0xf00) >> 4) | (opcode & 0xf); snprintf(offset, 32, "#%s0x%" PRIx32 "", (u) ? "" : "-", offset_8); instruction->info.load_store.offset_mode = 0; instruction->info.load_store.offset.offset = offset_8; } else {/* Register offset/index (+-<Rm>) */ uint8_t rm; rm = (opcode & 0xf); snprintf(offset, 32, "%sr%i", (u) ? "" : "-", rm); instruction->info.load_store.offset_mode = 1; instruction->info.load_store.offset.reg.rm = rm; instruction->info.load_store.offset.reg.shift = 0x0; instruction->info.load_store.offset.reg.shift_imm = 0x0; } if (p == 1) { if (w == 0) { /* offset */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i, %s]", address, opcode, operation, COND(opcode), suffix, rd, rn, offset); instruction->info.load_store.index_mode = 0; } else {/* pre-indexed */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i, %s]!", address, opcode, operation, COND(opcode), suffix, rd, rn, offset); instruction->info.load_store.index_mode = 1; } } else {/* post-indexed */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i], %s", address, opcode, operation, COND(opcode), suffix, rd, rn, offset); instruction->info.load_store.index_mode = 2; } return ERROR_OK; } /* Load/store multiples instructions */ static int evaluate_ldm_stm(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t p, u, s, w, l, rn; uint32_t register_list; char *addressing_mode; char *mnemonic; char reg_list[69]; char *reg_list_p; int i; int first_reg = 1; p = (opcode & 0x01000000) >> 24; u = (opcode & 0x00800000) >> 23; s = (opcode & 0x00400000) >> 22; w = (opcode & 0x00200000) >> 21; l = (opcode & 0x00100000) >> 20; register_list = (opcode & 0xffff); rn = (opcode & 0xf0000) >> 16; instruction->info.load_store_multiple.rn = rn; instruction->info.load_store_multiple.register_list = register_list; instruction->info.load_store_multiple.s = s; instruction->info.load_store_multiple.w = w; if (l) { instruction->type = ARM_LDM; mnemonic = "LDM"; } else { instruction->type = ARM_STM; mnemonic = "STM"; } if (p) { if (u) { instruction->info.load_store_multiple.addressing_mode = 1; addressing_mode = "IB"; } else { instruction->info.load_store_multiple.addressing_mode = 3; addressing_mode = "DB"; } } else { if (u) { instruction->info.load_store_multiple.addressing_mode = 0; /* "IA" is the default in UAL syntax */ addressing_mode = ""; } else { instruction->info.load_store_multiple.addressing_mode = 2; addressing_mode = "DA"; } } reg_list_p = reg_list; for (i = 0; i <= 15; i++) { if ((register_list >> i) & 1) { if (first_reg) { first_reg = 0; reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), "r%i", i); } else reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), ", r%i", i); } } snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i%s, {%s}%s", address, opcode, mnemonic, addressing_mode, COND(opcode), rn, (w) ? "!" : "", reg_list, (s) ? "^" : ""); return ERROR_OK; } /* Multiplies, extra load/stores */ static int evaluate_mul_and_extra_ld_st(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { /* Multiply (accumulate) (long) and Swap/swap byte */ if ((opcode & 0x000000f0) == 0x00000090) { /* Multiply (accumulate) */ if ((opcode & 0x0f800000) == 0x00000000) { uint8_t rm, rs, rn, rd, s; rm = opcode & 0xf; rs = (opcode & 0xf00) >> 8; rn = (opcode & 0xf000) >> 12; rd = (opcode & 0xf0000) >> 16; s = (opcode & 0x00100000) >> 20; /* examine A bit (accumulate) */ if (opcode & 0x00200000) { instruction->type = ARM_MLA; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMLA%s%s r%i, r%i, r%i, r%i", address, opcode, COND(opcode), (s) ? "S" : "", rd, rm, rs, rn); } else { instruction->type = ARM_MUL; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMUL%s%s r%i, r%i, r%i", address, opcode, COND(opcode), (s) ? "S" : "", rd, rm, rs); } return ERROR_OK; } /* Multiply (accumulate) long */ if ((opcode & 0x0f800000) == 0x00800000) { char *mnemonic = NULL; uint8_t rm, rs, rd_hi, rd_low, s; rm = opcode & 0xf; rs = (opcode & 0xf00) >> 8; rd_hi = (opcode & 0xf000) >> 12; rd_low = (opcode & 0xf0000) >> 16; s = (opcode & 0x00100000) >> 20; switch ((opcode & 0x00600000) >> 21) { case 0x0: instruction->type = ARM_UMULL; mnemonic = "UMULL"; break; case 0x1: instruction->type = ARM_UMLAL; mnemonic = "UMLAL"; break; case 0x2: instruction->type = ARM_SMULL; mnemonic = "SMULL"; break; case 0x3: instruction->type = ARM_SMLAL; mnemonic = "SMLAL"; break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, r%i, r%i, r%i", address, opcode, mnemonic, COND(opcode), (s) ? "S" : "", rd_low, rd_hi, rm, rs); return ERROR_OK; } /* Swap/swap byte */ if ((opcode & 0x0f800000) == 0x01000000) { uint8_t rm, rd, rn; rm = opcode & 0xf; rd = (opcode & 0xf000) >> 12; rn = (opcode & 0xf0000) >> 16; /* examine B flag */ instruction->type = (opcode & 0x00400000) ? ARM_SWPB : ARM_SWP; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, r%i, [r%i]", address, opcode, (opcode & 0x00400000) ? "SWPB" : "SWP", COND(opcode), rd, rm, rn); return ERROR_OK; } } return evaluate_misc_load_store(opcode, address, instruction); } static int evaluate_mrs_msr(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { int r = (opcode & 0x00400000) >> 22; char *PSR = (r) ? "SPSR" : "CPSR"; /* Move register to status register (MSR) */ if (opcode & 0x00200000) { instruction->type = ARM_MSR; /* immediate variant */ if (opcode & 0x02000000) { uint8_t immediate = (opcode & 0xff); uint8_t rotate = (opcode & 0xf00); snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32, address, opcode, COND(opcode), PSR, (opcode & 0x10000) ? "c" : "", (opcode & 0x20000) ? "x" : "", (opcode & 0x40000) ? "s" : "", (opcode & 0x80000) ? "f" : "", ror(immediate, (rotate * 2)) ); } else {/* register variant */ uint8_t rm = opcode & 0xf; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSR%s %s_%s%s%s%s, r%i", address, opcode, COND(opcode), PSR, (opcode & 0x10000) ? "c" : "", (opcode & 0x20000) ? "x" : "", (opcode & 0x40000) ? "s" : "", (opcode & 0x80000) ? "f" : "", rm ); } } else {/* Move status register to register (MRS) */ uint8_t rd; instruction->type = ARM_MRS; rd = (opcode & 0x0000f000) >> 12; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMRS%s r%i, %s", address, opcode, COND(opcode), rd, PSR); } return ERROR_OK; } /* Miscellaneous instructions */ static int evaluate_misc_instr(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { /* MRS/MSR */ if ((opcode & 0x000000f0) == 0x00000000) evaluate_mrs_msr(opcode, address, instruction); /* BX */ if ((opcode & 0x006000f0) == 0x00200010) { uint8_t rm; instruction->type = ARM_BX; rm = opcode & 0xf; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBX%s r%i", address, opcode, COND(opcode), rm); instruction->info.b_bl_bx_blx.reg_operand = rm; instruction->info.b_bl_bx_blx.target_address = -1; } /* BXJ - "Jazelle" support (ARMv5-J) */ if ((opcode & 0x006000f0) == 0x00200020) { uint8_t rm; instruction->type = ARM_BX; rm = opcode & 0xf; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBXJ%s r%i", address, opcode, COND(opcode), rm); instruction->info.b_bl_bx_blx.reg_operand = rm; instruction->info.b_bl_bx_blx.target_address = -1; } /* CLZ */ if ((opcode & 0x006000f0) == 0x00600010) { uint8_t rm, rd; instruction->type = ARM_CLZ; rm = opcode & 0xf; rd = (opcode & 0xf000) >> 12; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tCLZ%s r%i, r%i", address, opcode, COND(opcode), rd, rm); } /* BLX(2) */ if ((opcode & 0x006000f0) == 0x00200030) { uint8_t rm; instruction->type = ARM_BLX; rm = opcode & 0xf; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX%s r%i", address, opcode, COND(opcode), rm); instruction->info.b_bl_bx_blx.reg_operand = rm; instruction->info.b_bl_bx_blx.target_address = -1; } /* Enhanced DSP add/subtracts */ if ((opcode & 0x0000000f0) == 0x00000050) { uint8_t rm, rd, rn; char *mnemonic = NULL; rm = opcode & 0xf; rd = (opcode & 0xf000) >> 12; rn = (opcode & 0xf0000) >> 16; switch ((opcode & 0x00600000) >> 21) { case 0x0: instruction->type = ARM_QADD; mnemonic = "QADD"; break; case 0x1: instruction->type = ARM_QSUB; mnemonic = "QSUB"; break; case 0x2: instruction->type = ARM_QDADD; mnemonic = "QDADD"; break; case 0x3: instruction->type = ARM_QDSUB; mnemonic = "QDSUB"; break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, r%i, r%i", address, opcode, mnemonic, COND(opcode), rd, rm, rn); } /* exception return */ if ((opcode & 0x0000000f0) == 0x00000060) { if (((opcode & 0x600000) >> 21) == 3) instruction->type = ARM_ERET; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tERET", address, opcode); } /* exception generate instructions */ if ((opcode & 0x0000000f0) == 0x00000070) { uint32_t immediate = 0; char *mnemonic = NULL; switch ((opcode & 0x600000) >> 21) { case 0x1: instruction->type = ARM_BKPT; mnemonic = "BRKT"; immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf); break; case 0x2: instruction->type = ARM_HVC; mnemonic = "HVC"; immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf); break; case 0x3: instruction->type = ARM_SMC; mnemonic = "SMC"; immediate = (opcode & 0xf); break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s 0x%4.4" PRIx32 "", address, opcode, mnemonic, immediate); } /* Enhanced DSP multiplies */ if ((opcode & 0x000000090) == 0x00000080) { int x = (opcode & 0x20) >> 5; int y = (opcode & 0x40) >> 6; /* SMLA < x><y> */ if ((opcode & 0x00600000) == 0x00000000) { uint8_t rd, rm, rs, rn; instruction->type = ARM_SMLAXY; rd = (opcode & 0xf0000) >> 16; rm = (opcode & 0xf); rs = (opcode & 0xf00) >> 8; rn = (opcode & 0xf000) >> 12; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLA%s%s%s r%i, r%i, r%i, r%i", address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode), rd, rm, rs, rn); } /* SMLAL < x><y> */ if ((opcode & 0x00600000) == 0x00400000) { uint8_t rd_low, rd_hi, rm, rs; instruction->type = ARM_SMLAXY; rd_hi = (opcode & 0xf0000) >> 16; rd_low = (opcode & 0xf000) >> 12; rm = (opcode & 0xf); rs = (opcode & 0xf00) >> 8; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLA%s%s%s r%i, r%i, r%i, r%i", address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode), rd_low, rd_hi, rm, rs); } /* SMLAW < y> */ if (((opcode & 0x00600000) == 0x00200000) && (x == 0)) { uint8_t rd, rm, rs, rn; instruction->type = ARM_SMLAWY; rd = (opcode & 0xf0000) >> 16; rm = (opcode & 0xf); rs = (opcode & 0xf00) >> 8; rn = (opcode & 0xf000) >> 12; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLAW%s%s r%i, r%i, r%i, r%i", address, opcode, (y) ? "T" : "B", COND(opcode), rd, rm, rs, rn); } /* SMUL < x><y> */ if ((opcode & 0x00600000) == 0x00600000) { uint8_t rd, rm, rs; instruction->type = ARM_SMULXY; rd = (opcode & 0xf0000) >> 16; rm = (opcode & 0xf); rs = (opcode & 0xf00) >> 8; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMULW%s%s%s r%i, r%i, r%i", address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode), rd, rm, rs); } /* SMULW < y> */ if (((opcode & 0x00600000) == 0x00200000) && (x == 1)) { uint8_t rd, rm, rs; instruction->type = ARM_SMULWY; rd = (opcode & 0xf0000) >> 16; rm = (opcode & 0xf); rs = (opcode & 0xf00) >> 8; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMULW%s%s r%i, r%i, r%i", address, opcode, (y) ? "T" : "B", COND(opcode), rd, rm, rs); } } return ERROR_OK; } static int evaluate_mov_imm(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { uint16_t immediate; uint8_t rd; bool t; rd = (opcode & 0xf000) >> 12; t = opcode & 0x00400000; immediate = (opcode & 0xf0000) >> 4 | (opcode & 0xfff); instruction->type = ARM_MOV; instruction->info.data_proc.rd = rd; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMOV%s%s r%i, #0x%" PRIx16, address, opcode, t ? "T" : "W", COND(opcode), rd, immediate); return ERROR_OK; } static int evaluate_data_proc(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t i, op, s, rn, rd; char *mnemonic = NULL; char shifter_operand[32]; i = (opcode & 0x02000000) >> 25; op = (opcode & 0x01e00000) >> 21; s = (opcode & 0x00100000) >> 20; rd = (opcode & 0xf000) >> 12; rn = (opcode & 0xf0000) >> 16; instruction->info.data_proc.rd = rd; instruction->info.data_proc.rn = rn; instruction->info.data_proc.s = s; switch (op) { case 0x0: instruction->type = ARM_AND; mnemonic = "AND"; break; case 0x1: instruction->type = ARM_EOR; mnemonic = "EOR"; break; case 0x2: instruction->type = ARM_SUB; mnemonic = "SUB"; break; case 0x3: instruction->type = ARM_RSB; mnemonic = "RSB"; break; case 0x4: instruction->type = ARM_ADD; mnemonic = "ADD"; break; case 0x5: instruction->type = ARM_ADC; mnemonic = "ADC"; break; case 0x6: instruction->type = ARM_SBC; mnemonic = "SBC"; break; case 0x7: instruction->type = ARM_RSC; mnemonic = "RSC"; break; case 0x8: instruction->type = ARM_TST; mnemonic = "TST"; break; case 0x9: instruction->type = ARM_TEQ; mnemonic = "TEQ"; break; case 0xa: instruction->type = ARM_CMP; mnemonic = "CMP"; break; case 0xb: instruction->type = ARM_CMN; mnemonic = "CMN"; break; case 0xc: instruction->type = ARM_ORR; mnemonic = "ORR"; break; case 0xd: instruction->type = ARM_MOV; mnemonic = "MOV"; break; case 0xe: instruction->type = ARM_BIC; mnemonic = "BIC"; break; case 0xf: instruction->type = ARM_MVN; mnemonic = "MVN"; break; } if (i) {/* immediate shifter operand (#<immediate>)*/ uint8_t immed_8 = opcode & 0xff; uint8_t rotate_imm = (opcode & 0xf00) >> 8; uint32_t immediate; immediate = ror(immed_8, rotate_imm * 2); snprintf(shifter_operand, 32, "#0x%" PRIx32 "", immediate); instruction->info.data_proc.variant = 0; instruction->info.data_proc.shifter_operand.immediate.immediate = immediate; } else {/* register-based shifter operand */ uint8_t shift, rm; shift = (opcode & 0x60) >> 5; rm = (opcode & 0xf); if ((opcode & 0x10) != 0x10) { /* Immediate shifts ("<Rm>" or "<Rm>, <shift> *#<shift_immediate>") */ uint8_t shift_imm; shift_imm = (opcode & 0xf80) >> 7; instruction->info.data_proc.variant = 1; instruction->info.data_proc.shifter_operand.immediate_shift.rm = rm; instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = shift_imm; instruction->info.data_proc.shifter_operand.immediate_shift.shift = shift; /* LSR encodes a shift by 32 bit as 0x0 */ if ((shift == 0x1) && (shift_imm == 0x0)) shift_imm = 0x20; /* ASR encodes a shift by 32 bit as 0x0 */ if ((shift == 0x2) && (shift_imm == 0x0)) shift_imm = 0x20; /* ROR by 32 bit is actually a RRX */ if ((shift == 0x3) && (shift_imm == 0x0)) shift = 0x4; if ((shift_imm == 0x0) && (shift == 0x0)) snprintf(shifter_operand, 32, "r%i", rm); else { if (shift == 0x0) /* LSL */ snprintf(shifter_operand, 32, "r%i, LSL #0x%x", rm, shift_imm); else if (shift == 0x1) /* LSR */ snprintf(shifter_operand, 32, "r%i, LSR #0x%x", rm, shift_imm); else if (shift == 0x2) /* ASR */ snprintf(shifter_operand, 32, "r%i, ASR #0x%x", rm, shift_imm); else if (shift == 0x3) /* ROR */ snprintf(shifter_operand, 32, "r%i, ROR #0x%x", rm, shift_imm); else if (shift == 0x4) /* RRX */ snprintf(shifter_operand, 32, "r%i, RRX", rm); } } else {/* Register shifts ("<Rm>, <shift> <Rs>") */ uint8_t rs = (opcode & 0xf00) >> 8; instruction->info.data_proc.variant = 2; instruction->info.data_proc.shifter_operand.register_shift.rm = rm; instruction->info.data_proc.shifter_operand.register_shift.rs = rs; instruction->info.data_proc.shifter_operand.register_shift.shift = shift; if (shift == 0x0) /* LSL */ snprintf(shifter_operand, 32, "r%i, LSL r%i", rm, rs); else if (shift == 0x1) /* LSR */ snprintf(shifter_operand, 32, "r%i, LSR r%i", rm, rs); else if (shift == 0x2) /* ASR */ snprintf(shifter_operand, 32, "r%i, ASR r%i", rm, rs); else if (shift == 0x3) /* ROR */ snprintf(shifter_operand, 32, "r%i, ROR r%i", rm, rs); } } if ((op < 0x8) || (op == 0xc) || (op == 0xe)) { /* <opcode3>{<cond>}{S} <Rd>, <Rn>, *<shifter_operand> */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, r%i, %s", address, opcode, mnemonic, COND(opcode), (s) ? "S" : "", rd, rn, shifter_operand); } else if ((op == 0xd) || (op == 0xf)) { /* <opcode1>{<cond>}{S} <Rd>, *<shifter_operand> */ if (opcode == 0xe1a00000) /* print MOV r0,r0 as NOP */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tNOP", address, opcode); else snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, %s", address, opcode, mnemonic, COND(opcode), (s) ? "S" : "", rd, shifter_operand); } else {/* <opcode2>{<cond>} <Rn>, <shifter_operand> */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, %s", address, opcode, mnemonic, COND(opcode), rn, shifter_operand); } return ERROR_OK; } int arm_evaluate_opcode(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { /* clear fields, to avoid confusion */ memset(instruction, 0, sizeof(struct arm_instruction)); instruction->opcode = opcode; instruction->instruction_size = 4; /* catch opcodes with condition field [31:28] = b1111 */ if ((opcode & 0xf0000000) == 0xf0000000) { /* Undefined instruction (or ARMv5E cache preload PLD) */ if ((opcode & 0x08000000) == 0x00000000) return evaluate_pld(opcode, address, instruction); /* Undefined instruction (or ARMv6+ SRS/RFE) */ if ((opcode & 0x0e000000) == 0x08000000) return evaluate_srs(opcode, address, instruction); /* Branch and branch with link and change to Thumb */ if ((opcode & 0x0e000000) == 0x0a000000) return evaluate_blx_imm(opcode, address, instruction); /* Extended coprocessor opcode space (ARMv5 and higher) * Coprocessor load/store and double register transfers */ if ((opcode & 0x0e000000) == 0x0c000000) return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction); /* Coprocessor data processing */ if ((opcode & 0x0f000100) == 0x0c000000) return evaluate_cdp_mcr_mrc(opcode, address, instruction); /* Coprocessor register transfers */ if ((opcode & 0x0f000010) == 0x0c000010) return evaluate_cdp_mcr_mrc(opcode, address, instruction); /* Undefined instruction */ if ((opcode & 0x0f000000) == 0x0f000000) { instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", address, opcode); return ERROR_OK; } } /* catch opcodes with [27:25] = b000 */ if ((opcode & 0x0e000000) == 0x00000000) { /* Multiplies, extra load/stores */ if ((opcode & 0x00000090) == 0x00000090) return evaluate_mul_and_extra_ld_st(opcode, address, instruction); /* Miscellaneous instructions */ if ((opcode & 0x0f900000) == 0x01000000) return evaluate_misc_instr(opcode, address, instruction); return evaluate_data_proc(opcode, address, instruction); } /* catch opcodes with [27:25] = b001 */ if ((opcode & 0x0e000000) == 0x02000000) { /* 16-bit immediate load */ if ((opcode & 0x0fb00000) == 0x03000000) return evaluate_mov_imm(opcode, address, instruction); /* Move immediate to status register */ if ((opcode & 0x0fb00000) == 0x03200000) return evaluate_mrs_msr(opcode, address, instruction); return evaluate_data_proc(opcode, address, instruction); } /* catch opcodes with [27:25] = b010 */ if ((opcode & 0x0e000000) == 0x04000000) { /* Load/store immediate offset */ return evaluate_load_store(opcode, address, instruction); } /* catch opcodes with [27:25] = b011 */ if ((opcode & 0x0e000000) == 0x06000000) { /* Load/store register offset */ if ((opcode & 0x00000010) == 0x00000000) return evaluate_load_store(opcode, address, instruction); /* Architecturally Undefined instruction * ... don't expect these to ever be used */ if ((opcode & 0x07f000f0) == 0x07f000f0) { instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEF", address, opcode); return ERROR_OK; } /* "media" instructions */ return evaluate_media(opcode, address, instruction); } /* catch opcodes with [27:25] = b100 */ if ((opcode & 0x0e000000) == 0x08000000) { /* Load/store multiple */ return evaluate_ldm_stm(opcode, address, instruction); } /* catch opcodes with [27:25] = b101 */ if ((opcode & 0x0e000000) == 0x0a000000) { /* Branch and branch with link */ return evaluate_b_bl(opcode, address, instruction); } /* catch opcodes with [27:25] = b110 */ if ((opcode & 0x0e000000) == 0x0c000000) { /* Coprocessor load/store and double register transfers */ return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction); } /* catch opcodes with [27:25] = b111 */ if ((opcode & 0x0e000000) == 0x0e000000) { /* Software interrupt */ if ((opcode & 0x0f000000) == 0x0f000000) return evaluate_swi(opcode, address, instruction); /* Coprocessor data processing */ if ((opcode & 0x0f000010) == 0x0e000000) return evaluate_cdp_mcr_mrc(opcode, address, instruction); /* Coprocessor register transfers */ if ((opcode & 0x0f000010) == 0x0e000010) return evaluate_cdp_mcr_mrc(opcode, address, instruction); } LOG_ERROR("ARM: should never reach this point (opcode=%08x)", (unsigned) opcode); return -1; } static int evaluate_b_bl_blx_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t offset = opcode & 0x7ff; uint32_t opc = (opcode >> 11) & 0x3; uint32_t target_address; char *mnemonic = NULL; /* sign extend 11-bit offset */ if (((opc == 0) || (opc == 2)) && (offset & 0x00000400)) offset = 0xfffff800 | offset; target_address = address + 4 + (offset << 1); switch (opc) { /* unconditional branch */ case 0: instruction->type = ARM_B; mnemonic = "B"; break; /* BLX suffix */ case 1: instruction->type = ARM_BLX; mnemonic = "BLX"; target_address &= 0xfffffffc; break; /* BL/BLX prefix */ case 2: instruction->type = ARM_UNKNOWN_INSTRUCTION; mnemonic = "prefix"; target_address = offset << 12; break; /* BL suffix */ case 3: instruction->type = ARM_BL; mnemonic = "BL"; break; } /* TODO: deal correctly with dual opcode (prefixed) BL/BLX; * these are effectively 32-bit instructions even in Thumb1. For * disassembly, it's simplest to always use the Thumb2 decoder. * * But some cores will evidently handle them as two instructions, * where exceptions may occur between the two. The ETMv3.2+ ID * register has a bit which exposes this behavior. */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\t%#8.8" PRIx32, address, opcode, mnemonic, target_address); instruction->info.b_bl_bx_blx.reg_operand = -1; instruction->info.b_bl_bx_blx.target_address = target_address; return ERROR_OK; } static int evaluate_add_sub_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t rd = (opcode >> 0) & 0x7; uint8_t rn = (opcode >> 3) & 0x7; uint8_t rm_imm = (opcode >> 6) & 0x7; uint32_t opc = opcode & (1 << 9); uint32_t reg_imm = opcode & (1 << 10); char *mnemonic; if (opc) { instruction->type = ARM_SUB; mnemonic = "SUBS"; } else { /* REVISIT: if reg_imm == 0, display as "MOVS" */ instruction->type = ARM_ADD; mnemonic = "ADDS"; } instruction->info.data_proc.rd = rd; instruction->info.data_proc.rn = rn; instruction->info.data_proc.s = 1; if (reg_imm) { instruction->info.data_proc.variant = 0;/*immediate*/ instruction->info.data_proc.shifter_operand.immediate.immediate = rm_imm; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, #%d", address, opcode, mnemonic, rd, rn, rm_imm); } else { instruction->info.data_proc.variant = 1;/*immediate shift*/ instruction->info.data_proc.shifter_operand.immediate_shift.rm = rm_imm; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, r%i", address, opcode, mnemonic, rd, rn, rm_imm); } return ERROR_OK; } static int evaluate_shift_imm_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t rd = (opcode >> 0) & 0x7; uint8_t rm = (opcode >> 3) & 0x7; uint8_t imm = (opcode >> 6) & 0x1f; uint8_t opc = (opcode >> 11) & 0x3; char *mnemonic = NULL; switch (opc) { case 0: instruction->type = ARM_MOV; mnemonic = "LSLS"; instruction->info.data_proc.shifter_operand.immediate_shift.shift = 0; break; case 1: instruction->type = ARM_MOV; mnemonic = "LSRS"; instruction->info.data_proc.shifter_operand.immediate_shift.shift = 1; break; case 2: instruction->type = ARM_MOV; mnemonic = "ASRS"; instruction->info.data_proc.shifter_operand.immediate_shift.shift = 2; break; } if ((imm == 0) && (opc != 0)) imm = 32; instruction->info.data_proc.rd = rd; instruction->info.data_proc.rn = -1; instruction->info.data_proc.s = 1; instruction->info.data_proc.variant = 1;/*immediate_shift*/ instruction->info.data_proc.shifter_operand.immediate_shift.rm = rm; instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = imm; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, #%#2.2x", address, opcode, mnemonic, rd, rm, imm); return ERROR_OK; } static int evaluate_data_proc_imm_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t imm = opcode & 0xff; uint8_t rd = (opcode >> 8) & 0x7; uint32_t opc = (opcode >> 11) & 0x3; char *mnemonic = NULL; instruction->info.data_proc.rd = rd; instruction->info.data_proc.rn = rd; instruction->info.data_proc.s = 1; instruction->info.data_proc.variant = 0;/*immediate*/ instruction->info.data_proc.shifter_operand.immediate.immediate = imm; switch (opc) { case 0: instruction->type = ARM_MOV; mnemonic = "MOVS"; instruction->info.data_proc.rn = -1; break; case 1: instruction->type = ARM_CMP; mnemonic = "CMP"; instruction->info.data_proc.rd = -1; break; case 2: instruction->type = ARM_ADD; mnemonic = "ADDS"; break; case 3: instruction->type = ARM_SUB; mnemonic = "SUBS"; break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, #%#2.2x", address, opcode, mnemonic, rd, imm); return ERROR_OK; } static int evaluate_data_proc_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t high_reg, op, rm, rd, h1, h2; char *mnemonic = NULL; bool nop = false; high_reg = (opcode & 0x0400) >> 10; op = (opcode & 0x03C0) >> 6; rd = (opcode & 0x0007); rm = (opcode & 0x0038) >> 3; h1 = (opcode & 0x0080) >> 7; h2 = (opcode & 0x0040) >> 6; instruction->info.data_proc.rd = rd; instruction->info.data_proc.rn = rd; instruction->info.data_proc.s = (!high_reg || (instruction->type == ARM_CMP)); instruction->info.data_proc.variant = 1 /*immediate shift*/; instruction->info.data_proc.shifter_operand.immediate_shift.rm = rm; if (high_reg) { rd |= h1 << 3; rm |= h2 << 3; op >>= 2; switch (op) { case 0x0: instruction->type = ARM_ADD; mnemonic = "ADD"; break; case 0x1: instruction->type = ARM_CMP; mnemonic = "CMP"; break; case 0x2: instruction->type = ARM_MOV; mnemonic = "MOV"; if (rd == rm) nop = true; break; case 0x3: if ((opcode & 0x7) == 0x0) { instruction->info.b_bl_bx_blx.reg_operand = rm; if (h1) { instruction->type = ARM_BLX; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tBLX\tr%i", address, opcode, rm); } else { instruction->type = ARM_BX; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tBX\tr%i", address, opcode, rm); } } else { instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t" "UNDEFINED INSTRUCTION", address, opcode); } return ERROR_OK; } } else { switch (op) { case 0x0: instruction->type = ARM_AND; mnemonic = "ANDS"; break; case 0x1: instruction->type = ARM_EOR; mnemonic = "EORS"; break; case 0x2: instruction->type = ARM_MOV; mnemonic = "LSLS"; instruction->info.data_proc.variant = 2 /*register shift*/; instruction->info.data_proc.shifter_operand.register_shift.shift = 0; instruction->info.data_proc.shifter_operand.register_shift.rm = rd; instruction->info.data_proc.shifter_operand.register_shift.rs = rm; break; case 0x3: instruction->type = ARM_MOV; mnemonic = "LSRS"; instruction->info.data_proc.variant = 2 /*register shift*/; instruction->info.data_proc.shifter_operand.register_shift.shift = 1; instruction->info.data_proc.shifter_operand.register_shift.rm = rd; instruction->info.data_proc.shifter_operand.register_shift.rs = rm; break; case 0x4: instruction->type = ARM_MOV; mnemonic = "ASRS"; instruction->info.data_proc.variant = 2 /*register shift*/; instruction->info.data_proc.shifter_operand.register_shift.shift = 2; instruction->info.data_proc.shifter_operand.register_shift.rm = rd; instruction->info.data_proc.shifter_operand.register_shift.rs = rm; break; case 0x5: instruction->type = ARM_ADC; mnemonic = "ADCS"; break; case 0x6: instruction->type = ARM_SBC; mnemonic = "SBCS"; break; case 0x7: instruction->type = ARM_MOV; mnemonic = "RORS"; instruction->info.data_proc.variant = 2 /*register shift*/; instruction->info.data_proc.shifter_operand.register_shift.shift = 3; instruction->info.data_proc.shifter_operand.register_shift.rm = rd; instruction->info.data_proc.shifter_operand.register_shift.rs = rm; break; case 0x8: instruction->type = ARM_TST; mnemonic = "TST"; break; case 0x9: instruction->type = ARM_RSB; mnemonic = "RSBS"; instruction->info.data_proc.variant = 0 /*immediate*/; instruction->info.data_proc.shifter_operand.immediate.immediate = 0; instruction->info.data_proc.rn = rm; break; case 0xA: instruction->type = ARM_CMP; mnemonic = "CMP"; break; case 0xB: instruction->type = ARM_CMN; mnemonic = "CMN"; break; case 0xC: instruction->type = ARM_ORR; mnemonic = "ORRS"; break; case 0xD: instruction->type = ARM_MUL; mnemonic = "MULS"; break; case 0xE: instruction->type = ARM_BIC; mnemonic = "BICS"; break; case 0xF: instruction->type = ARM_MVN; mnemonic = "MVNS"; break; } } if (nop) snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tNOP\t\t\t" "; (%s r%i, r%i)", address, opcode, mnemonic, rd, rm); else snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i", address, opcode, mnemonic, rd, rm); return ERROR_OK; } /* PC-relative data addressing is word-aligned even with Thumb */ static inline uint32_t thumb_alignpc4(uint32_t addr) { return (addr + 4) & ~3; } static int evaluate_load_literal_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t immediate; uint8_t rd = (opcode >> 8) & 0x7; instruction->type = ARM_LDR; immediate = opcode & 0x000000ff; immediate *= 4; instruction->info.load_store.rd = rd; instruction->info.load_store.rn = 15 /*PC*/; instruction->info.load_store.index_mode = 0; /*offset*/ instruction->info.load_store.offset_mode = 0; /*immediate*/ instruction->info.load_store.offset.offset = immediate; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t" "LDR\tr%i, [pc, #%#" PRIx32 "]\t; %#8.8" PRIx32, address, opcode, rd, immediate, thumb_alignpc4(address) + immediate); return ERROR_OK; } static int evaluate_load_store_reg_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t rd = (opcode >> 0) & 0x7; uint8_t rn = (opcode >> 3) & 0x7; uint8_t rm = (opcode >> 6) & 0x7; uint8_t opc = (opcode >> 9) & 0x7; char *mnemonic = NULL; switch (opc) { case 0: instruction->type = ARM_STR; mnemonic = "STR"; break; case 1: instruction->type = ARM_STRH; mnemonic = "STRH"; break; case 2: instruction->type = ARM_STRB; mnemonic = "STRB"; break; case 3: instruction->type = ARM_LDRSB; mnemonic = "LDRSB"; break; case 4: instruction->type = ARM_LDR; mnemonic = "LDR"; break; case 5: instruction->type = ARM_LDRH; mnemonic = "LDRH"; break; case 6: instruction->type = ARM_LDRB; mnemonic = "LDRB"; break; case 7: instruction->type = ARM_LDRSH; mnemonic = "LDRSH"; break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, [r%i, r%i]", address, opcode, mnemonic, rd, rn, rm); instruction->info.load_store.rd = rd; instruction->info.load_store.rn = rn; instruction->info.load_store.index_mode = 0; /*offset*/ instruction->info.load_store.offset_mode = 1; /*register*/ instruction->info.load_store.offset.reg.rm = rm; return ERROR_OK; } static int evaluate_load_store_imm_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t offset = (opcode >> 6) & 0x1f; uint8_t rd = (opcode >> 0) & 0x7; uint8_t rn = (opcode >> 3) & 0x7; uint32_t l = opcode & (1 << 11); uint32_t b = opcode & (1 << 12); char *mnemonic; char suffix = ' '; uint32_t shift = 2; if (l) { instruction->type = ARM_LDR; mnemonic = "LDR"; } else { instruction->type = ARM_STR; mnemonic = "STR"; } if ((opcode&0xF000) == 0x8000) { suffix = 'H'; shift = 1; } else if (b) { suffix = 'B'; shift = 0; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32 "]", address, opcode, mnemonic, suffix, rd, rn, offset << shift); instruction->info.load_store.rd = rd; instruction->info.load_store.rn = rn; instruction->info.load_store.index_mode = 0; /*offset*/ instruction->info.load_store.offset_mode = 0; /*immediate*/ instruction->info.load_store.offset.offset = offset << shift; return ERROR_OK; } static int evaluate_load_store_stack_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t offset = opcode & 0xff; uint8_t rd = (opcode >> 8) & 0x7; uint32_t l = opcode & (1 << 11); char *mnemonic; if (l) { instruction->type = ARM_LDR; mnemonic = "LDR"; } else { instruction->type = ARM_STR; mnemonic = "STR"; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32 "]", address, opcode, mnemonic, rd, offset*4); instruction->info.load_store.rd = rd; instruction->info.load_store.rn = 13 /*SP*/; instruction->info.load_store.index_mode = 0; /*offset*/ instruction->info.load_store.offset_mode = 0; /*immediate*/ instruction->info.load_store.offset.offset = offset*4; return ERROR_OK; } static int evaluate_add_sp_pc_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t imm = opcode & 0xff; uint8_t rd = (opcode >> 8) & 0x7; uint8_t rn; uint32_t sp = opcode & (1 << 11); const char *reg_name; instruction->type = ARM_ADD; if (sp) { reg_name = "SP"; rn = 13; } else { reg_name = "PC"; rn = 15; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32, address, opcode, rd, reg_name, imm * 4); instruction->info.data_proc.variant = 0 /* immediate */; instruction->info.data_proc.rd = rd; instruction->info.data_proc.rn = rn; instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4; return ERROR_OK; } static int evaluate_adjust_stack_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t imm = opcode & 0x7f; uint8_t opc = opcode & (1 << 7); char *mnemonic; if (opc) { instruction->type = ARM_SUB; mnemonic = "SUB"; } else { instruction->type = ARM_ADD; mnemonic = "ADD"; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tSP, #%#" PRIx32, address, opcode, mnemonic, imm*4); instruction->info.data_proc.variant = 0 /* immediate */; instruction->info.data_proc.rd = 13 /*SP*/; instruction->info.data_proc.rn = 13 /*SP*/; instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4; return ERROR_OK; } static int evaluate_breakpoint_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t imm = opcode & 0xff; instruction->type = ARM_BKPT; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tBKPT\t%#2.2" PRIx32 "", address, opcode, imm); return ERROR_OK; } static int evaluate_load_store_multiple_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t reg_list = opcode & 0xff; uint32_t l = opcode & (1 << 11); uint32_t r = opcode & (1 << 8); uint8_t rn = (opcode >> 8) & 7; uint8_t addr_mode = 0 /* IA */; char reg_names[40]; char *reg_names_p; char *mnemonic; char ptr_name[7] = ""; int i; /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions. * The STMIA and LDMIA opcodes are used for other instructions. */ if ((opcode & 0xf000) == 0xc000) { /* generic load/store multiple */ char *wback = "!"; if (l) { instruction->type = ARM_LDM; mnemonic = "LDM"; if (opcode & (1 << rn)) wback = ""; } else { instruction->type = ARM_STM; mnemonic = "STM"; } snprintf(ptr_name, sizeof(ptr_name), "r%i%s, ", rn, wback); } else {/* push/pop */ rn = 13;/* SP */ if (l) { instruction->type = ARM_LDM; mnemonic = "POP"; if (r) reg_list |= (1 << 15) /*PC*/; } else { instruction->type = ARM_STM; mnemonic = "PUSH"; addr_mode = 3; /*DB*/ if (r) reg_list |= (1 << 14) /*LR*/; } } reg_names_p = reg_names; for (i = 0; i <= 15; i++) { if (reg_list & (1 << i)) reg_names_p += snprintf(reg_names_p, (reg_names + 40 - reg_names_p), "r%i, ", i); } if (reg_names_p > reg_names) reg_names_p[-2] = '\0'; else /* invalid op : no registers */ reg_names[0] = '\0'; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\t%s{%s}", address, opcode, mnemonic, ptr_name, reg_names); instruction->info.load_store_multiple.register_list = reg_list; instruction->info.load_store_multiple.rn = rn; instruction->info.load_store_multiple.addressing_mode = addr_mode; return ERROR_OK; } static int evaluate_cond_branch_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t offset = opcode & 0xff; uint8_t cond = (opcode >> 8) & 0xf; uint32_t target_address; if (cond == 0xf) { instruction->type = ARM_SWI; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tSVC\t%#2.2" PRIx32, address, opcode, offset); return ERROR_OK; } else if (cond == 0xe) { instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tUNDEFINED INSTRUCTION", address, opcode); return ERROR_OK; } /* sign extend 8-bit offset */ if (offset & 0x00000080) offset = 0xffffff00 | offset; target_address = address + 4 + (offset << 1); snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tB%s\t%#8.8" PRIx32, address, opcode, arm_condition_strings[cond], target_address); instruction->type = ARM_B; instruction->info.b_bl_bx_blx.reg_operand = -1; instruction->info.b_bl_bx_blx.target_address = target_address; return ERROR_OK; } static int evaluate_cb_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { unsigned offset; /* added in Thumb2 */ offset = (opcode >> 3) & 0x1f; offset |= (opcode & 0x0200) >> 4; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32, address, opcode, (opcode & 0x0800) ? "N" : "", opcode & 0x7, address + 4 + (offset << 1)); return ERROR_OK; } static int evaluate_extend_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { /* added in ARMv6 */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%cXT%c\tr%d, r%d", address, opcode, (opcode & 0x0080) ? 'U' : 'S', (opcode & 0x0040) ? 'B' : 'H', opcode & 0x7, (opcode >> 3) & 0x7); return ERROR_OK; } static int evaluate_cps_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { /* added in ARMv6 */ if ((opcode & 0x0ff0) == 0x0650) snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tSETEND %s", address, opcode, (opcode & 0x80) ? "BE" : "LE"); else /* ASSUME (opcode & 0x0fe0) == 0x0660 */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tCPSI%c\t%s%s%s", address, opcode, (opcode & 0x0010) ? 'D' : 'E', (opcode & 0x0004) ? "A" : "", (opcode & 0x0002) ? "I" : "", (opcode & 0x0001) ? "F" : ""); return ERROR_OK; } static int evaluate_byterev_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { char *suffix; /* added in ARMv6 */ switch ((opcode >> 6) & 3) { case 0: suffix = ""; break; case 1: suffix = "16"; break; default: suffix = "SH"; break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tREV%s\tr%d, r%d", address, opcode, suffix, opcode & 0x7, (opcode >> 3) & 0x7); return ERROR_OK; } static int evaluate_hint_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { char *hint; switch ((opcode >> 4) & 0x0f) { case 0: hint = "NOP"; break; case 1: hint = "YIELD"; break; case 2: hint = "WFE"; break; case 3: hint = "WFI"; break; case 4: hint = "SEV"; break; default: hint = "HINT (UNRECOGNIZED)"; break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s", address, opcode, hint); return ERROR_OK; } static int evaluate_ifthen_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { unsigned cond = (opcode >> 4) & 0x0f; char *x = "", *y = "", *z = ""; if (opcode & 0x01) z = (opcode & 0x02) ? "T" : "E"; if (opcode & 0x03) y = (opcode & 0x04) ? "T" : "E"; if (opcode & 0x07) x = (opcode & 0x08) ? "T" : "E"; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tIT%s%s%s\t%s", address, opcode, x, y, z, arm_condition_strings[cond]); /* NOTE: strictly speaking, the next 1-4 instructions should * now be displayed with the relevant conditional suffix... */ return ERROR_OK; } int thumb_evaluate_opcode(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { /* clear fields, to avoid confusion */ memset(instruction, 0, sizeof(struct arm_instruction)); instruction->opcode = opcode; instruction->instruction_size = 2; if ((opcode & 0xe000) == 0x0000) { /* add/subtract register or immediate */ if ((opcode & 0x1800) == 0x1800) return evaluate_add_sub_thumb(opcode, address, instruction); /* shift by immediate */ else return evaluate_shift_imm_thumb(opcode, address, instruction); } /* Add/subtract/compare/move immediate */ if ((opcode & 0xe000) == 0x2000) return evaluate_data_proc_imm_thumb(opcode, address, instruction); /* Data processing instructions */ if ((opcode & 0xf800) == 0x4000) return evaluate_data_proc_thumb(opcode, address, instruction); /* Load from literal pool */ if ((opcode & 0xf800) == 0x4800) return evaluate_load_literal_thumb(opcode, address, instruction); /* Load/Store register offset */ if ((opcode & 0xf000) == 0x5000) return evaluate_load_store_reg_thumb(opcode, address, instruction); /* Load/Store immediate offset */ if (((opcode & 0xe000) == 0x6000) || ((opcode & 0xf000) == 0x8000)) return evaluate_load_store_imm_thumb(opcode, address, instruction); /* Load/Store from/to stack */ if ((opcode & 0xf000) == 0x9000) return evaluate_load_store_stack_thumb(opcode, address, instruction); /* Add to SP/PC */ if ((opcode & 0xf000) == 0xa000) return evaluate_add_sp_pc_thumb(opcode, address, instruction); /* Misc */ if ((opcode & 0xf000) == 0xb000) { switch ((opcode >> 8) & 0x0f) { case 0x0: return evaluate_adjust_stack_thumb(opcode, address, instruction); case 0x1: case 0x3: case 0x9: case 0xb: return evaluate_cb_thumb(opcode, address, instruction); case 0x2: return evaluate_extend_thumb(opcode, address, instruction); case 0x4: case 0x5: case 0xc: case 0xd: return evaluate_load_store_multiple_thumb(opcode, address, instruction); case 0x6: return evaluate_cps_thumb(opcode, address, instruction); case 0xa: if ((opcode & 0x00c0) == 0x0080) break; return evaluate_byterev_thumb(opcode, address, instruction); case 0xe: return evaluate_breakpoint_thumb(opcode, address, instruction); case 0xf: if (opcode & 0x000f) return evaluate_ifthen_thumb(opcode, address, instruction); else return evaluate_hint_thumb(opcode, address, instruction); } instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tUNDEFINED INSTRUCTION", address, opcode); return ERROR_OK; } /* Load/Store multiple */ if ((opcode & 0xf000) == 0xc000) return evaluate_load_store_multiple_thumb(opcode, address, instruction); /* Conditional branch + SWI */ if ((opcode & 0xf000) == 0xd000) return evaluate_cond_branch_thumb(opcode, address, instruction); if ((opcode & 0xe000) == 0xe000) { /* Undefined instructions */ if ((opcode & 0xf801) == 0xe801) { instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%8.8x\t" "UNDEFINED INSTRUCTION", address, opcode); return ERROR_OK; } else /* Branch to offset */ return evaluate_b_bl_blx_thumb(opcode, address, instruction); } LOG_ERROR("Thumb: should never reach this point (opcode=%04x)", opcode); return -1; } int arm_access_size(struct arm_instruction *instruction) { if ((instruction->type == ARM_LDRB) || (instruction->type == ARM_LDRBT) || (instruction->type == ARM_LDRSB) || (instruction->type == ARM_STRB) || (instruction->type == ARM_STRBT)) return 1; else if ((instruction->type == ARM_LDRH) || (instruction->type == ARM_LDRSH) || (instruction->type == ARM_STRH)) return 2; else if ((instruction->type == ARM_LDR) || (instruction->type == ARM_LDRT) || (instruction->type == ARM_STR) || (instruction->type == ARM_STRT)) return 4; else if ((instruction->type == ARM_LDRD) || (instruction->type == ARM_STRD)) return 8; else { LOG_ERROR("BUG: instruction type %i isn't a load/store instruction", instruction->type); return 0; } } #if HAVE_CAPSTONE static void print_opcode(struct command_invocation *cmd, const cs_insn *insn) { uint32_t opcode = 0; memcpy(&opcode, insn->bytes, insn->size); if (insn->size == 4) { uint16_t opcode_high = opcode >> 16; opcode = opcode & 0xffff; command_print(cmd, "0x%08" PRIx64" %04x %04x\t%s%s%s", insn->address, opcode, opcode_high, insn->mnemonic, insn->op_str[0] ? "\t" : "", insn->op_str); } else { command_print(cmd, "0x%08" PRIx64" %04x\t%s%s%s", insn->address, opcode, insn->mnemonic, insn->op_str[0] ? "\t" : "", insn->op_str); } } int arm_disassemble(struct command_invocation *cmd, struct target *target, target_addr_t address, size_t count, bool thumb_mode) { csh handle; int ret; cs_insn *insn; cs_mode mode; if (!cs_support(CS_ARCH_ARM)) { LOG_ERROR("ARM architecture not supported by capstone"); return ERROR_FAIL; } mode = CS_MODE_LITTLE_ENDIAN; if (thumb_mode) mode |= CS_MODE_THUMB; ret = cs_open(CS_ARCH_ARM, mode, &handle); if (ret != CS_ERR_OK) { LOG_ERROR("cs_open() failed: %s", cs_strerror(ret)); return ERROR_FAIL; } ret = cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON); if (ret != CS_ERR_OK) { LOG_ERROR("cs_option() failed: %s", cs_strerror(ret)); cs_close(&handle); return ERROR_FAIL; } insn = cs_malloc(handle); if (!insn) { LOG_ERROR("cs_malloc() failed\n"); cs_close(&handle); return ERROR_FAIL; } while (count > 0) { uint8_t buffer[4]; ret = target_read_buffer(target, address, sizeof(buffer), buffer); if (ret != ERROR_OK) { cs_free(insn, 1); cs_close(&handle); return ret; } size_t size = sizeof(buffer); const uint8_t *tmp = buffer; ret = cs_disasm_iter(handle, &tmp, &size, &address, insn); if (!ret) { LOG_ERROR("cs_disasm_iter() failed: %s", cs_strerror(cs_errno(handle))); cs_free(insn, 1); cs_close(&handle); return ERROR_FAIL; } print_opcode(cmd, insn); count--; } cs_free(insn, 1); cs_close(&handle); return ERROR_OK; } #endif /* HAVE_CAPSTONE */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_disassembler.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM_DISASSEMBLER_H #define OPENOCD_TARGET_ARM_DISASSEMBLER_H enum arm_instruction_type { ARM_UNKNOWN_INSTRUCTION, /* Branch instructions */ ARM_B, ARM_BL, ARM_BX, ARM_BLX, /* Data processing instructions */ ARM_AND, ARM_EOR, ARM_SUB, ARM_RSB, ARM_ADD, ARM_ADC, ARM_SBC, ARM_RSC, ARM_TST, ARM_TEQ, ARM_CMP, ARM_CMN, ARM_ORR, ARM_MOV, ARM_BIC, ARM_MVN, /* Load/store instructions */ ARM_LDR, ARM_LDRB, ARM_LDRT, ARM_LDRBT, ARM_LDRH, ARM_LDRSB, ARM_LDRSH, ARM_LDM, ARM_STR, ARM_STRB, ARM_STRT, ARM_STRBT, ARM_STRH, ARM_STM, /* Status register access instructions */ ARM_MRS, ARM_MSR, /* Multiply instructions */ ARM_MUL, ARM_MLA, ARM_SMULL, ARM_SMLAL, ARM_UMULL, ARM_UMLAL, /* Miscellaneous instructions */ ARM_CLZ, /* Exception return instructions */ ARM_ERET, /* Exception generating instructions */ ARM_BKPT, ARM_SWI, ARM_HVC, ARM_SMC, /* Coprocessor instructions */ ARM_CDP, ARM_LDC, ARM_STC, ARM_MCR, ARM_MRC, /* Semaphore instructions */ ARM_SWP, ARM_SWPB, /* Enhanced DSP extensions */ ARM_MCRR, ARM_MRRC, ARM_PLD, ARM_DSB, ARM_ISB, ARM_QADD, ARM_QDADD, ARM_QSUB, ARM_QDSUB, ARM_SMLAXY, ARM_SMLALXY, ARM_SMLAWY, ARM_SMULXY, ARM_SMULWY, ARM_LDRD, ARM_STRD, ARM_UNDEFINED_INSTRUCTION = 0xffffffff, }; struct arm_b_bl_bx_blx_instr { int reg_operand; uint32_t target_address; }; union arm_shifter_operand { struct { uint32_t immediate; } immediate; struct { uint8_t rm; uint8_t shift; /* 0: LSL, 1: LSR, 2: ASR, 3: ROR, 4: RRX */ uint8_t shift_imm; } immediate_shift; struct { uint8_t rm; uint8_t shift; uint8_t rs; } register_shift; }; struct arm_data_proc_instr { int variant; /* 0: immediate, 1: immediate_shift, 2: register_shift */ uint8_t s; uint8_t rn; uint8_t rd; union arm_shifter_operand shifter_operand; }; struct arm_load_store_instr { uint8_t rd; uint8_t rn; uint8_t u; int index_mode; /* 0: offset, 1: pre-indexed, 2: post-indexed */ int offset_mode; /* 0: immediate, 1: (scaled) register */ union { uint32_t offset; struct { uint8_t rm; uint8_t shift; /* 0: LSL, 1: LSR, 2: ASR, 3: ROR, 4: RRX */ uint8_t shift_imm; } reg; } offset; }; struct arm_load_store_multiple_instr { uint8_t rn; uint32_t register_list; uint8_t addressing_mode; /* 0: IA, 1: IB, 2: DA, 3: DB */ uint8_t s; uint8_t w; }; struct arm_instruction { enum arm_instruction_type type; char text[128]; uint32_t opcode; /* return value ... Thumb-2 sizes vary */ unsigned instruction_size; union { struct arm_b_bl_bx_blx_instr b_bl_bx_blx; struct arm_data_proc_instr data_proc; struct arm_load_store_instr load_store; struct arm_load_store_multiple_instr load_store_multiple; } info; }; int arm_evaluate_opcode(uint32_t opcode, uint32_t address, struct arm_instruction *instruction); int thumb_evaluate_opcode(uint16_t opcode, uint32_t address, struct arm_instruction *instruction); int arm_access_size(struct arm_instruction *instruction); #if HAVE_CAPSTONE int arm_disassemble(struct command_invocation *cmd, struct target *target, target_addr_t address, size_t count, bool thumb_mode); #endif #define COND(opcode) (arm_condition_strings[(opcode & 0xf0000000) >> 28]) #endif /* OPENOCD_TARGET_ARM_DISASSEMBLER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_dpm.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2009 by David Brownell */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "arm_dpm.h" #include "armv8_dpm.h" #include <jtag/jtag.h> #include "register.h" #include "breakpoints.h" #include "target_type.h" #include "arm_opcodes.h" /** * @file * Implements various ARM DPM operations using architectural debug registers. * These routines layer over core-specific communication methods to cope with * implementation differences between cores like ARM1136 and Cortex-A8. * * The "Debug Programmers' Model" (DPM) for ARMv6 and ARMv7 is defined by * Part C (Debug Architecture) of the ARM Architecture Reference Manual, * ARMv7-A and ARMv7-R edition (ARM DDI 0406B). In OpenOCD, DPM operations * are abstracted through internal programming interfaces to share code and * to minimize needless differences in debug behavior between cores. */ /*----------------------------------------------------------------------*/ /* * Coprocessor support */ /* Read coprocessor */ static int dpm_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; LOG_DEBUG("MRC p%d, %d, r0, c%d, c%d, %d", cpnum, (int) op1, (int) crn, (int) crm, (int) op2); /* read coprocessor register into R0; return via DCC */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2), value); /* (void) */ dpm->finish(dpm); return retval; } static int dpm_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum, (int) op1, (int) crn, (int) crm, (int) op2); /* read DCC into r0; then write coprocessor register from R0 */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2), value); /* (void) */ dpm->finish(dpm); return retval; } /*----------------------------------------------------------------------*/ /* * Register access utilities */ /* Toggles between recorded core mode (USR, SVC, etc) and a temporary one. * Routines *must* restore the original mode before returning!! */ int arm_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) { int retval; uint32_t cpsr; /* restore previous mode */ if (mode == ARM_MODE_ANY) cpsr = buf_get_u32(dpm->arm->cpsr->value, 0, 32); /* else force to the specified mode */ else cpsr = mode; retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MSR_GP(0, 0xf, 0), cpsr); if (retval != ERROR_OK) return retval; if (dpm->instr_cpsr_sync) retval = dpm->instr_cpsr_sync(dpm); return retval; } /* Read 64bit VFP registers */ static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { int retval = ERROR_FAIL; uint32_t value_r0, value_r1; switch (regnum) { case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: /* move from double word register to r0:r1: "vmov r0, r1, vm" * then read r0 via dcc */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_VMOV(1, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4), ((regnum - ARM_VFP_V3_D0) & 0xf)), &value_r0); if (retval != ERROR_OK) break; /* read r1 via dcc */ retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, 1, 0, 5, 0), &value_r1); break; default: break; } if (retval == ERROR_OK) { buf_set_u32(r->value, 0, 32, value_r0); buf_set_u32(r->value + 4, 0, 32, value_r1); r->valid = true; r->dirty = false; LOG_DEBUG("READ: %s, %8.8x, %8.8x", r->name, (unsigned) value_r0, (unsigned) value_r1); } return retval; } /* just read the register -- rely on the core mode being right */ int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { uint32_t value; int retval; switch (regnum) { case 0 ... 14: /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */ retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, regnum, 0, 5, 0), &value); break; case 15:/* PC * "MOV r0, pc"; then return via DCC */ retval = dpm->instr_read_data_r0(dpm, 0xe1a0000f, &value); /* NOTE: this seems like a slightly awkward place to update * this value ... but if the PC gets written (the only way * to change what we compute), the arch spec says subsequent * reads return values which are "unpredictable". So this * is always right except in those broken-by-intent cases. */ switch (dpm->arm->core_state) { case ARM_STATE_ARM: value -= 8; break; case ARM_STATE_THUMB: case ARM_STATE_THUMB_EE: value -= 4; break; case ARM_STATE_JAZELLE: /* core-specific ... ? */ LOG_WARNING("Jazelle PC adjustment unknown"); break; default: LOG_WARNING("unknown core state"); break; } break; case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: return dpm_read_reg_u64(dpm, r, regnum); case ARM_VFP_V3_FPSCR: /* "VMRS r0, FPSCR"; then return via DCC */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_VMRS(0), &value); break; default: /* 16: "MRS r0, CPSR"; then return via DCC * 17: "MRS r0, SPSR"; then return via DCC */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, regnum & 1), &value); break; } if (retval == ERROR_OK) { buf_set_u32(r->value, 0, 32, value); r->valid = true; r->dirty = false; LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned) value); } return retval; } /* Write 64bit VFP registers */ static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { int retval = ERROR_FAIL; uint32_t value_r0 = buf_get_u32(r->value, 0, 32); uint32_t value_r1 = buf_get_u32(r->value + 4, 0, 32); switch (regnum) { case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: /* write value_r1 to r1 via dcc */ retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 1, 0, 5, 0), value_r1); if (retval != ERROR_OK) break; /* write value_r0 to r0 via dcc then, * move to double word register from r0:r1: "vmov vm, r0, r1" */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_VMOV(0, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4), ((regnum - ARM_VFP_V3_D0) & 0xf)), value_r0); break; default: break; } if (retval == ERROR_OK) { r->dirty = false; LOG_DEBUG("WRITE: %s, %8.8x, %8.8x", r->name, (unsigned) value_r0, (unsigned) value_r1); } return retval; } /* just write the register -- rely on the core mode being right */ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { int retval; uint32_t value = buf_get_u32(r->value, 0, 32); switch (regnum) { case 0 ... 14: /* load register from DCC: "MRC p14, 0, Rnum, c0, c5, 0" */ retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, regnum, 0, 5, 0), value); break; case 15:/* PC * read r0 from DCC; then "MOV pc, r0" */ retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value); break; case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: return dpm_write_reg_u64(dpm, r, regnum); case ARM_VFP_V3_FPSCR: /* move to r0 from DCC, then "VMSR FPSCR, r0" */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_VMSR(0), value); break; default: /* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf" * 17: read r0 from DCC, then "MSR r0, SPSR_cxsf" */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MSR_GP(0, 0xf, regnum & 1), value); if (retval != ERROR_OK) return retval; if (regnum == 16 && dpm->instr_cpsr_sync) retval = dpm->instr_cpsr_sync(dpm); break; } if (retval == ERROR_OK) { r->dirty = false; LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned) value); } return retval; } /** * Write to program counter and switch the core state (arm/thumb) according to * the address. */ static int dpm_write_pc_core_state(struct arm_dpm *dpm, struct reg *r) { uint32_t value = buf_get_u32(r->value, 0, 32); /* read r0 from DCC; then "BX r0" */ return dpm->instr_write_data_r0(dpm, ARMV4_5_BX(0), value); } /** * Read basic registers of the current context: R0 to R15, and CPSR; * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb). * In normal operation this is called on entry to halting debug state, * possibly after some other operations supporting restore of debug state * or making sure the CPU is fully idle (drain write buffer, etc). */ int arm_dpm_read_current_registers(struct arm_dpm *dpm) { struct arm *arm = dpm->arm; uint32_t cpsr; int retval; struct reg *r; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; /* read R0 and R1 first (it's used for scratch), then CPSR */ for (unsigned i = 0; i < 2; i++) { r = arm->core_cache->reg_list + i; if (!r->valid) { retval = arm_dpm_read_reg(dpm, r, i); if (retval != ERROR_OK) goto fail; } r->dirty = true; } retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr); if (retval != ERROR_OK) goto fail; /* update core mode and state, plus shadow mapping for R8..R14 */ arm_set_cpsr(arm, cpsr); /* REVISIT we can probably avoid reading R1..R14, saving time... */ for (unsigned i = 2; i < 16; i++) { r = arm_reg_current(arm, i); if (r->valid) continue; retval = arm_dpm_read_reg(dpm, r, i); if (retval != ERROR_OK) goto fail; } /* NOTE: SPSR ignored (if it's even relevant). */ /* REVISIT the debugger can trigger various exceptions. See the * ARMv7A architecture spec, section C5.7, for more info about * what defenses are needed; v6 debug has the most issues. */ fail: /* (void) */ dpm->finish(dpm); return retval; } /* Avoid needless I/O ... leave breakpoints and watchpoints alone * unless they're removed, or need updating because of single-stepping * or running debugger code. */ static int dpm_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp, struct dpm_bpwp *xp, bool *set_p) { int retval = ERROR_OK; bool disable; if (!set_p) { if (!xp->dirty) goto done; xp->dirty = false; /* removed or startup; we must disable it */ disable = true; } else if (bpwp) { if (!xp->dirty) goto done; /* disabled, but we must set it */ xp->dirty = disable = false; *set_p = true; } else { if (!*set_p) goto done; /* set, but we must temporarily disable it */ xp->dirty = disable = true; *set_p = false; } if (disable) retval = dpm->bpwp_disable(dpm, xp->number); else retval = dpm->bpwp_enable(dpm, xp->number, xp->address, xp->control); if (retval != ERROR_OK) LOG_ERROR("%s: can't %s HW %spoint %d", disable ? "disable" : "enable", target_name(dpm->arm->target), (xp->number < 16) ? "break" : "watch", xp->number & 0xf); done: return retval; } static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp); /** * Writes all modified core registers for all processor modes. In normal * operation this is called on exit from halting debug state. * * @param dpm: represents the processor * @param bpwp: true ensures breakpoints and watchpoints are set, * false ensures they are cleared */ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) { struct arm *arm = dpm->arm; struct reg_cache *cache = arm->core_cache; int retval; bool did_write; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* If we're managing hardware breakpoints for this core, enable * or disable them as requested. * * REVISIT We don't yet manage them for ANY cores. Eventually * we should be able to assume we handle them; but until then, * cope with the hand-crafted breakpoint code. */ if (arm->target->type->add_breakpoint == dpm_add_breakpoint) { for (unsigned i = 0; i < dpm->nbp; i++) { struct dpm_bp *dbp = dpm->dbp + i; struct breakpoint *bp = dbp->bp; retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp, bp ? &bp->is_set : NULL); if (retval != ERROR_OK) goto done; } } /* enable/disable watchpoints */ for (unsigned i = 0; i < dpm->nwp; i++) { struct dpm_wp *dwp = dpm->dwp + i; struct watchpoint *wp = dwp->wp; retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp, wp ? &wp->is_set : NULL); if (retval != ERROR_OK) goto done; } /* NOTE: writes to breakpoint and watchpoint registers might * be queued, and need (efficient/batched) flushing later. */ /* Scan the registers until we find one that's both dirty and * eligible for flushing. Flush that and everything else that * shares the same core mode setting. Typically this won't * actually find anything to do... */ do { enum arm_mode mode = ARM_MODE_ANY; did_write = false; /* check everything except our scratch registers R0 and R1 */ for (unsigned i = 2; i < cache->num_regs; i++) { struct arm_reg *r; unsigned regnum; /* also skip PC, CPSR, and non-dirty */ if (i == 15) continue; if (arm->cpsr == cache->reg_list + i) continue; if (!cache->reg_list[i].exist || !cache->reg_list[i].dirty) continue; r = cache->reg_list[i].arch_info; regnum = r->num; /* may need to pick and set a mode */ if (!did_write) { enum arm_mode tmode; did_write = true; mode = tmode = r->mode; /* cope with special cases */ switch (regnum) { case 8 ... 12: /* r8..r12 "anything but FIQ" case; * we "know" core mode is accurate * since we haven't changed it yet */ if (arm->core_mode == ARM_MODE_FIQ && ARM_MODE_ANY != mode) tmode = ARM_MODE_USR; break; case 16: /* SPSR */ regnum++; break; } /* REVISIT error checks */ if (tmode != ARM_MODE_ANY) { retval = arm_dpm_modeswitch(dpm, tmode); if (retval != ERROR_OK) goto done; } } if (r->mode != mode) continue; retval = dpm_write_reg(dpm, &cache->reg_list[i], regnum); if (retval != ERROR_OK) goto done; } } while (did_write); /* Restore original CPSR ... assuming either that we changed it, * or it's dirty. Must write PC to ensure the return address is * defined, and must not write it before CPSR. */ retval = arm_dpm_modeswitch(dpm, ARM_MODE_ANY); if (retval != ERROR_OK) goto done; arm->cpsr->dirty = false; /* restore the PC, make sure to also switch the core state * to whatever it was set to with "arm core_state" command. * target code will have set PC to an appropriate resume address. */ retval = dpm_write_pc_core_state(dpm, arm->pc); if (retval != ERROR_OK) goto done; /* on Cortex-A5 (as found on NXP VF610 SoC), BX instruction * executed in debug state doesn't appear to set the PC, * explicitly set it with a "MOV pc, r0". This doesn't influence * CPSR on Cortex-A9 so it should be OK. Maybe due to different * debug version? */ retval = dpm_write_reg(dpm, arm->pc, 15); if (retval != ERROR_OK) goto done; arm->pc->dirty = false; /* flush R0 and R1 (our scratch registers) */ for (unsigned i = 0; i < 2; i++) { retval = dpm_write_reg(dpm, &cache->reg_list[i], i); if (retval != ERROR_OK) goto done; cache->reg_list[i].dirty = false; } /* (void) */ dpm->finish(dpm); done: return retval; } /* Returns ARM_MODE_ANY or temporary mode to use while reading the * specified register ... works around flakiness from ARM core calls. * Caller already filtered out SPSR access; mode is never MODE_SYS * or MODE_ANY. */ static enum arm_mode dpm_mapmode(struct arm *arm, unsigned num, enum arm_mode mode) { enum arm_mode amode = arm->core_mode; /* don't switch if the mode is already correct */ if (amode == ARM_MODE_SYS) amode = ARM_MODE_USR; if (mode == amode) return ARM_MODE_ANY; switch (num) { /* don't switch for non-shadowed registers (r0..r7, r15/pc, cpsr) */ case 0 ... 7: case 15: case 16: break; /* r8..r12 aren't shadowed for anything except FIQ */ case 8 ... 12: if (mode == ARM_MODE_FIQ) return mode; break; /* r13/sp, and r14/lr are always shadowed */ case 13: case 14: case ARM_VFP_V3_D0 ... ARM_VFP_V3_FPSCR: return mode; default: LOG_WARNING("invalid register #%u", num); break; } return ARM_MODE_ANY; } /* * Standard ARM register accessors ... there are three methods * in "struct arm", to support individual read/write and bulk read * of registers. */ static int arm_dpm_read_core_reg(struct target *target, struct reg *r, int regnum, enum arm_mode mode) { struct arm_dpm *dpm = target_to_arm(target)->dpm; int retval; if (regnum < 0 || (regnum > 16 && regnum < ARM_VFP_V3_D0) || (regnum > ARM_VFP_V3_FPSCR)) return ERROR_COMMAND_SYNTAX_ERROR; if (regnum == 16) { if (mode != ARM_MODE_ANY) regnum = 17; } else mode = dpm_mapmode(dpm->arm, regnum, mode); /* REVISIT what happens if we try to read SPSR in a core mode * which has no such register? */ retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; if (mode != ARM_MODE_ANY) { retval = arm_dpm_modeswitch(dpm, mode); if (retval != ERROR_OK) goto fail; } retval = arm_dpm_read_reg(dpm, r, regnum); if (retval != ERROR_OK) goto fail; /* always clean up, regardless of error */ if (mode != ARM_MODE_ANY) /* (void) */ arm_dpm_modeswitch(dpm, ARM_MODE_ANY); fail: /* (void) */ dpm->finish(dpm); return retval; } static int arm_dpm_write_core_reg(struct target *target, struct reg *r, int regnum, enum arm_mode mode, uint8_t *value) { struct arm_dpm *dpm = target_to_arm(target)->dpm; int retval; if (regnum < 0 || (regnum > 16 && regnum < ARM_VFP_V3_D0) || (regnum > ARM_VFP_V3_FPSCR)) return ERROR_COMMAND_SYNTAX_ERROR; if (regnum == 16) { if (mode != ARM_MODE_ANY) regnum = 17; } else mode = dpm_mapmode(dpm->arm, regnum, mode); /* REVISIT what happens if we try to write SPSR in a core mode * which has no such register? */ retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; if (mode != ARM_MODE_ANY) { retval = arm_dpm_modeswitch(dpm, mode); if (retval != ERROR_OK) goto fail; } retval = dpm_write_reg(dpm, r, regnum); /* always clean up, regardless of error */ if (mode != ARM_MODE_ANY) /* (void) */ arm_dpm_modeswitch(dpm, ARM_MODE_ANY); fail: /* (void) */ dpm->finish(dpm); return retval; } static int arm_dpm_full_context(struct target *target) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; struct reg_cache *cache = arm->core_cache; int retval; bool did_read; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; do { enum arm_mode mode = ARM_MODE_ANY; did_read = false; /* We "know" arm_dpm_read_current_registers() was called so * the unmapped registers (R0..R7, PC, AND CPSR) and some * view of R8..R14 are current. We also "know" oddities of * register mapping: special cases for R8..R12 and SPSR. * * Pick some mode with unread registers and read them all. * Repeat until done. */ for (unsigned i = 0; i < cache->num_regs; i++) { struct arm_reg *r; if (!cache->reg_list[i].exist || cache->reg_list[i].valid) continue; r = cache->reg_list[i].arch_info; /* may need to pick a mode and set CPSR */ if (!did_read) { did_read = true; mode = r->mode; /* For regular (ARM_MODE_ANY) R8..R12 * in case we've entered debug state * in FIQ mode we need to patch mode. */ if (mode != ARM_MODE_ANY) retval = arm_dpm_modeswitch(dpm, mode); else retval = arm_dpm_modeswitch(dpm, ARM_MODE_USR); if (retval != ERROR_OK) goto done; } if (r->mode != mode) continue; /* CPSR was read, so "R16" must mean SPSR */ retval = arm_dpm_read_reg(dpm, &cache->reg_list[i], (r->num == 16) ? 17 : r->num); if (retval != ERROR_OK) goto done; } } while (did_read); retval = arm_dpm_modeswitch(dpm, ARM_MODE_ANY); /* (void) */ dpm->finish(dpm); done: return retval; } /*----------------------------------------------------------------------*/ /* * Breakpoint and Watchpoint support. * * Hardware {break,watch}points are usually left active, to minimize * debug entry/exit costs. When they are set or cleared, it's done in * batches. Also, DPM-conformant hardware can update debug registers * regardless of whether the CPU is running or halted ... though that * fact isn't currently leveraged. */ static int dpm_bpwp_setup(struct arm_dpm *dpm, struct dpm_bpwp *xp, uint32_t addr, uint32_t length) { uint32_t control; control = (1 << 0) /* enable */ | (3 << 1); /* both user and privileged access */ /* Match 1, 2, or all 4 byte addresses in this word. * * FIXME: v7 hardware allows lengths up to 2 GB for BP and WP. * Support larger length, when addr is suitably aligned. In * particular, allow watchpoints on 8 byte "double" values. * * REVISIT allow watchpoints on unaligned 2-bit values; and on * v7 hardware, unaligned 4-byte ones too. */ switch (length) { case 1: control |= (1 << (addr & 3)) << 5; break; case 2: /* require 2-byte alignment */ if (!(addr & 1)) { control |= (3 << (addr & 2)) << 5; break; } /* FALL THROUGH */ case 4: /* require 4-byte alignment */ if (!(addr & 3)) { control |= 0xf << 5; break; } /* FALL THROUGH */ default: LOG_ERROR("unsupported {break,watch}point length/alignment"); return ERROR_COMMAND_SYNTAX_ERROR; } /* other shared control bits: * bits 15:14 == 0 ... both secure and nonsecure states (v6.1+ only) * bit 20 == 0 ... not linked to a context ID * bit 28:24 == 0 ... not ignoring N LSBs (v7 only) */ xp->address = addr & ~3; xp->control = control; xp->dirty = true; LOG_DEBUG("BPWP: addr %8.8" PRIx32 ", control %" PRIx32 ", number %d", xp->address, control, xp->number); /* hardware is updated in write_dirty_registers() */ return ERROR_OK; } static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if (bp->length < 2) return ERROR_COMMAND_SYNTAX_ERROR; if (!dpm->bpwp_enable) return retval; /* FIXME we need a generic solution for software breakpoints. */ if (bp->type == BKPT_SOFT) LOG_DEBUG("using HW bkpt, not SW..."); for (unsigned i = 0; i < dpm->nbp; i++) { if (!dpm->dbp[i].bp) { retval = dpm_bpwp_setup(dpm, &dpm->dbp[i].bpwp, bp->address, bp->length); if (retval == ERROR_OK) dpm->dbp[i].bp = bp; break; } } return retval; } static int dpm_remove_breakpoint(struct target *target, struct breakpoint *bp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_COMMAND_SYNTAX_ERROR; for (unsigned i = 0; i < dpm->nbp; i++) { if (dpm->dbp[i].bp == bp) { dpm->dbp[i].bp = NULL; dpm->dbp[i].bpwp.dirty = true; /* hardware is updated in write_dirty_registers() */ retval = ERROR_OK; break; } } return retval; } static int dpm_watchpoint_setup(struct arm_dpm *dpm, unsigned index_t, struct watchpoint *wp) { int retval; struct dpm_wp *dwp = dpm->dwp + index_t; uint32_t control; /* this hardware doesn't support data value matching or masking */ if (wp->value || wp->mask != ~(uint32_t)0) { LOG_DEBUG("watchpoint values and masking not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = dpm_bpwp_setup(dpm, &dwp->bpwp, wp->address, wp->length); if (retval != ERROR_OK) return retval; control = dwp->bpwp.control; switch (wp->rw) { case WPT_READ: control |= 1 << 3; break; case WPT_WRITE: control |= 2 << 3; break; case WPT_ACCESS: control |= 3 << 3; break; } dwp->bpwp.control = control; dpm->dwp[index_t].wp = wp; return retval; } static int dpm_add_watchpoint(struct target *target, struct watchpoint *wp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if (dpm->bpwp_enable) { for (unsigned i = 0; i < dpm->nwp; i++) { if (!dpm->dwp[i].wp) { retval = dpm_watchpoint_setup(dpm, i, wp); break; } } } return retval; } static int dpm_remove_watchpoint(struct target *target, struct watchpoint *wp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_COMMAND_SYNTAX_ERROR; for (unsigned i = 0; i < dpm->nwp; i++) { if (dpm->dwp[i].wp == wp) { dpm->dwp[i].wp = NULL; dpm->dwp[i].bpwp.dirty = true; /* hardware is updated in write_dirty_registers() */ retval = ERROR_OK; break; } } return retval; } void arm_dpm_report_wfar(struct arm_dpm *dpm, uint32_t addr) { switch (dpm->arm->core_state) { case ARM_STATE_ARM: addr -= 8; break; case ARM_STATE_THUMB: case ARM_STATE_THUMB_EE: addr -= 4; break; case ARM_STATE_JAZELLE: case ARM_STATE_AARCH64: /* ?? */ break; } dpm->wp_addr = addr; } /*----------------------------------------------------------------------*/ /* * Other debug and support utilities */ void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr) { struct target *target = dpm->arm->target; dpm->dscr = dscr; /* Examine debug reason */ switch (DSCR_ENTRY(dscr)) { case DSCR_ENTRY_HALT_REQ: /* HALT request from debugger */ case DSCR_ENTRY_EXT_DBG_REQ: /* EDBGRQ */ target->debug_reason = DBG_REASON_DBGRQ; break; case DSCR_ENTRY_BREAKPOINT: /* HW breakpoint */ case DSCR_ENTRY_BKPT_INSTR: /* vector catch */ target->debug_reason = DBG_REASON_BREAKPOINT; break; case DSCR_ENTRY_IMPRECISE_WATCHPT: /* asynch watchpoint */ case DSCR_ENTRY_PRECISE_WATCHPT:/* precise watchpoint */ target->debug_reason = DBG_REASON_WATCHPOINT; break; default: target->debug_reason = DBG_REASON_UNDEFINED; break; } } /*----------------------------------------------------------------------*/ /* * Setup and management support. */ /** * Hooks up this DPM to its associated target; call only once. * Initially this only covers the register cache. * * Oh, and watchpoints. Yeah. */ int arm_dpm_setup(struct arm_dpm *dpm) { struct arm *arm = dpm->arm; struct target *target = arm->target; struct reg_cache *cache = NULL; arm->dpm = dpm; /* register access setup */ arm->full_context = arm_dpm_full_context; arm->read_core_reg = arm_dpm_read_core_reg; arm->write_core_reg = arm_dpm_write_core_reg; if (!arm->core_cache) { cache = arm_build_reg_cache(target, arm); if (!cache) return ERROR_FAIL; *register_get_last_cache_p(&target->reg_cache) = cache; } /* coprocessor access setup */ arm->mrc = dpm_mrc; arm->mcr = dpm_mcr; /* breakpoint setup -- optional until it works everywhere */ if (!target->type->add_breakpoint) { target->type->add_breakpoint = dpm_add_breakpoint; target->type->remove_breakpoint = dpm_remove_breakpoint; } /* watchpoint setup -- optional until it works everywhere */ if (!target->type->add_watchpoint) { target->type->add_watchpoint = dpm_add_watchpoint; target->type->remove_watchpoint = dpm_remove_watchpoint; } /* FIXME add vector catch support */ dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf); dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf); dpm->dbp = calloc(dpm->nbp, sizeof(*dpm->dbp)); dpm->dwp = calloc(dpm->nwp, sizeof(*dpm->dwp)); if (!dpm->dbp || !dpm->dwp) { arm_free_reg_cache(arm); free(dpm->dbp); free(dpm->dwp); return ERROR_FAIL; } LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints", target_name(target), dpm->nbp, dpm->nwp); /* REVISIT ... and some of those breakpoints could match * execution context IDs... */ return ERROR_OK; } /** * Reinitializes DPM state at the beginning of a new debug session * or after a reset which may have affected the debug module. */ int arm_dpm_initialize(struct arm_dpm *dpm) { /* Disable all breakpoints and watchpoints at startup. */ if (dpm->bpwp_disable) { unsigned i; for (i = 0; i < dpm->nbp; i++) { dpm->dbp[i].bpwp.number = i; (void) dpm->bpwp_disable(dpm, i); } for (i = 0; i < dpm->nwp; i++) { dpm->dwp[i].bpwp.number = 16 + i; (void) dpm->bpwp_disable(dpm, 16 + i); } } else LOG_WARNING("%s: can't disable breakpoints and watchpoints", target_name(dpm->arm->target)); return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_dpm.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2009 by David Brownell */ #ifndef OPENOCD_TARGET_ARM_DPM_H #define OPENOCD_TARGET_ARM_DPM_H /** * @file * This is the interface to the Debug Programmers Model for ARMv6 and * ARMv7 processors. ARMv6 processors (such as ARM11xx implementations) * introduced a model which became part of the ARMv7-AR architecture * which is most familiar through the Cortex-A series parts. While * specific details differ (like how to write the instruction register), * the high level models easily support shared code because those * registers are compatible. */ struct dpm_bpwp { unsigned number; uint32_t address; uint32_t control; /* true if hardware state needs flushing */ bool dirty; }; struct dpm_bp { struct breakpoint *bp; struct dpm_bpwp bpwp; }; struct dpm_wp { struct watchpoint *wp; struct dpm_bpwp bpwp; }; /** * This wraps an implementation of DPM primitives. Each interface * provider supplies a structure like this, which is the glue between * upper level code and the lower level hardware access. * * It is a PRELIMINARY AND INCOMPLETE set of primitives, starting with * support for CPU register access. */ struct arm_dpm { struct arm *arm; /** Cache of DIDR */ uint64_t didr; /** Invoke before a series of instruction operations */ int (*prepare)(struct arm_dpm *dpm); /** Invoke after a series of instruction operations */ int (*finish)(struct arm_dpm *dpm); /** Runs one instruction. */ int (*instr_execute)(struct arm_dpm *dpm, uint32_t opcode); /* WRITE TO CPU */ /** Runs one instruction, writing data to DCC before execution. */ int (*instr_write_data_dcc)(struct arm_dpm *dpm, uint32_t opcode, uint32_t data); int (*instr_write_data_dcc_64)(struct arm_dpm *dpm, uint32_t opcode, uint64_t data); /** Runs one instruction, writing data to R0 before execution. */ int (*instr_write_data_r0)(struct arm_dpm *dpm, uint32_t opcode, uint32_t data); /** Runs one instruction, writing data to R0 before execution. */ int (*instr_write_data_r0_64)(struct arm_dpm *dpm, uint32_t opcode, uint64_t data); /** Optional core-specific operation invoked after CPSR writes. */ int (*instr_cpsr_sync)(struct arm_dpm *dpm); /* READ FROM CPU */ /** Runs one instruction, reading data from dcc after execution. */ int (*instr_read_data_dcc)(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data); int (*instr_read_data_dcc_64)(struct arm_dpm *dpm, uint32_t opcode, uint64_t *data); /** Runs one instruction, reading data from r0 after execution. */ int (*instr_read_data_r0)(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data); int (*instr_read_data_r0_64)(struct arm_dpm *dpm, uint32_t opcode, uint64_t *data); struct reg *(*arm_reg_current)(struct arm *arm, unsigned regnum); /* BREAKPOINT/WATCHPOINT SUPPORT */ /** * Enables one breakpoint or watchpoint by writing to the * hardware registers. The specified breakpoint/watchpoint * must currently be disabled. Indices 0..15 are used for * breakpoints; indices 16..31 are for watchpoints. */ int (*bpwp_enable)(struct arm_dpm *dpm, unsigned index_value, uint32_t addr, uint32_t control); /** * Disables one breakpoint or watchpoint by clearing its * hardware control registers. Indices are the same ones * accepted by bpwp_enable(). */ int (*bpwp_disable)(struct arm_dpm *dpm, unsigned index_value); /* The breakpoint and watchpoint arrays are private to the * DPM infrastructure. There are nbp indices in the dbp * array. There are nwp indices in the dwp array. */ unsigned nbp; unsigned nwp; struct dpm_bp *dbp; struct dpm_wp *dwp; /** * Target dependent watchpoint address. * Either the address of the instruction which triggered a watchpoint * or the memory address whose access triggered a watchpoint. */ target_addr_t wp_addr; /** Recent value of DSCR. */ uint32_t dscr; /** Recent exception level on armv8 */ unsigned int last_el; /* FIXME -- read/write DCSR methods and symbols */ }; int arm_dpm_setup(struct arm_dpm *dpm); int arm_dpm_initialize(struct arm_dpm *dpm); int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum); int arm_dpm_read_current_registers(struct arm_dpm *dpm); int arm_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode); int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp); void arm_dpm_report_wfar(struct arm_dpm *dpm, uint32_t wfar); /* DSCR bits; see ARMv7a arch spec section C10.3.1. * Not all v7 bits are valid in v6. */ #define DSCR_CORE_HALTED (0x1 << 0) #define DSCR_CORE_RESTARTED (0x1 << 1) #define DSCR_ENTRY_MASK (0xF << 2) #define DSCR_STICKY_ABORT_PRECISE (0x1 << 6) #define DSCR_STICKY_ABORT_IMPRECISE (0x1 << 7) #define DSCR_STICKY_UNDEFINED (0x1 << 8) #define DSCR_DBG_NOPWRDWN (0x1 << 9) /* v6 only */ #define DSCR_DBG_ACK (0x1 << 10) #define DSCR_INT_DIS (0x1 << 11) #define DSCR_CP14_USR_COMMS (0x1 << 12) #define DSCR_ITR_EN (0x1 << 13) #define DSCR_HALT_DBG_MODE (0x1 << 14) #define DSCR_MON_DBG_MODE (0x1 << 15) #define DSCR_SEC_PRIV_INVASV_DIS (0x1 << 16) #define DSCR_SEC_PRIV_NINVASV_DIS (0x1 << 17) #define DSCR_NON_SECURE (0x1 << 18) #define DSCR_DSCRD_IMPRECISE_ABORT (0x1 << 19) #define DSCR_EXT_DCC_MASK (0x3 << 20) /* DTR mode */ /* bits 22, 23 are reserved */ #define DSCR_INSTR_COMP (0x1 << 24) #define DSCR_PIPE_ADVANCE (0x1 << 25) #define DSCR_DTRTX_FULL_LATCHED (0x1 << 26) #define DSCR_DTRRX_FULL_LATCHED (0x1 << 27) /* bit 28 is reserved */ #define DSCR_DTR_TX_FULL (0x1 << 29) #define DSCR_DTR_RX_FULL (0x1 << 30) /* bit 31 is reserved */ #define DSCR_ENTRY(dscr) ((dscr) & 0x3f) #define DSCR_RUN_MODE(dscr) ((dscr) & 0x03) /* Methods of entry into debug mode */ #define DSCR_ENTRY_HALT_REQ (0x03) #define DSCR_ENTRY_BREAKPOINT (0x07) #define DSCR_ENTRY_IMPRECISE_WATCHPT (0x0B) #define DSCR_ENTRY_BKPT_INSTR (0x0F) #define DSCR_ENTRY_EXT_DBG_REQ (0x13) #define DSCR_ENTRY_VECT_CATCH (0x17) #define DSCR_ENTRY_D_SIDE_ABORT (0x1B) /* v6 only */ #define DSCR_ENTRY_I_SIDE_ABORT (0x1F) /* v6 only */ #define DSCR_ENTRY_OS_UNLOCK (0x23) #define DSCR_ENTRY_PRECISE_WATCHPT (0x2B) /* DTR modes */ #define DSCR_EXT_DCC_NON_BLOCKING (0x0 << 20) #define DSCR_EXT_DCC_STALL_MODE (0x1 << 20) #define DSCR_EXT_DCC_FAST_MODE (0x2 << 20) /* bits 22, 23 are reserved */ /* DRCR (debug run control register) bits */ #define DRCR_HALT (1 << 0) #define DRCR_RESTART (1 << 1) #define DRCR_CLEAR_EXCEPTIONS (1 << 2) void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dcsr); /* PRCR (Device Power-down and Reset Control Register) bits */ #define PRCR_DEBUG_NO_POWER_DOWN (1 << 0) #define PRCR_WARM_RESET (1 << 1) #define PRCR_HOLD_NON_DEBUG_RESET (1 << 2) /* PRSR (Device Power-down and Reset Status Register) bits */ #define PRSR_POWERUP_STATUS (1 << 0) #define PRSR_STICKY_POWERDOWN_STATUS (1 << 1) #define PRSR_RESET_STATUS (1 << 2) #define PRSR_STICKY_RESET_STATUS (1 << 3) #define PRSR_HALTED (1 << 4) /* v7.1 Debug only */ #define PRSR_OSLK (1 << 5) /* v7.1 Debug only */ #define PRSR_DLK (1 << 6) /* v7.1 Debug only */ /* OSLSR (OS Lock Status Register) bits */ #define OSLSR_OSLM0 (1 << 0) #define OSLSR_OSLK (1 << 1) #define OSLSR_NTT (1 << 2) #define OSLSR_OSLM1 (1 << 3) #define OSLSR_OSLM (OSLSR_OSLM0|OSLSR_OSLM1) #endif /* OPENOCD_TARGET_ARM_DPM_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_jtag.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm_jtag.h" #if 0 #define _ARM_JTAG_SCAN_N_CHECK_ #endif int arm_jtag_set_instr_inner(struct jtag_tap *tap, uint32_t new_instr, void *no_verify_capture, tap_state_t end_state) { struct scan_field field; uint8_t t[4] = { 0 }; field.num_bits = tap->ir_length; field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; if (!no_verify_capture) jtag_add_ir_scan(tap, &field, end_state); else { /* FIX!!!! this is a kludge!!! arm926ejs.c should reimplement this arm_jtag_set_instr to * have special verification code. */ jtag_add_ir_scan_noverify(tap, &field, end_state); } return ERROR_OK; } int arm_jtag_scann_inner(struct arm_jtag *jtag_info, uint32_t new_scan_chain, tap_state_t end_state) { int retval = ERROR_OK; uint8_t out_value[4] = { 0 }; buf_set_u32(out_value, 0, jtag_info->scann_size, new_scan_chain); struct scan_field field = { .num_bits = jtag_info->scann_size, .out_value = out_value, }; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->scann_instr, NULL, end_state); if (retval != ERROR_OK) return retval; jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state); jtag_info->cur_scan_chain = new_scan_chain; return retval; } static int arm_jtag_reset_callback(enum jtag_event event, void *priv) { struct arm_jtag *jtag_info = priv; if (event == JTAG_TRST_ASSERTED) jtag_info->cur_scan_chain = 0; return ERROR_OK; } int arm_jtag_setup_connection(struct arm_jtag *jtag_info) { jtag_info->scann_instr = 0x2; jtag_info->cur_scan_chain = 0; jtag_info->intest_instr = 0xc; return jtag_register_event_callback(arm_jtag_reset_callback, jtag_info); } int arm_jtag_close_connection(struct arm_jtag *jtag_info) { return jtag_unregister_event_callback(arm_jtag_reset_callback, jtag_info); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_jtag.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM_JTAG_H #define OPENOCD_TARGET_ARM_JTAG_H #include <jtag/jtag.h> #include <helper/bits.h> struct arm_jtag { struct jtag_tap *tap; uint32_t scann_size; uint32_t scann_instr; uint32_t cur_scan_chain; uint32_t intest_instr; }; int arm_jtag_set_instr_inner(struct jtag_tap *tap, uint32_t new_instr, void *no_verify_capture, tap_state_t end_state); static inline int arm_jtag_set_instr(struct jtag_tap *tap, uint32_t new_instr, void *no_verify_capture, tap_state_t end_state) { /* inline most common code path */ if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (new_instr & (BIT(tap->ir_length) - 1))) return arm_jtag_set_instr_inner(tap, new_instr, no_verify_capture, end_state); return ERROR_OK; } int arm_jtag_scann_inner(struct arm_jtag *jtag_info, uint32_t new_scan_chain, tap_state_t end_state); static inline int arm_jtag_scann(struct arm_jtag *jtag_info, uint32_t new_scan_chain, tap_state_t end_state) { /* inline most common code path */ int retval = ERROR_OK; if (jtag_info->cur_scan_chain != new_scan_chain) return arm_jtag_scann_inner(jtag_info, new_scan_chain, end_state); return retval; } int arm_jtag_setup_connection(struct arm_jtag *jtag_info); int arm_jtag_close_connection(struct arm_jtag *jtag_info); /* use this as a static so we can inline it in -O3 and refer to it via a pointer */ static inline void arm7flip32(jtag_callback_data_t arg) { uint8_t *in = (uint8_t *)arg; *((uint32_t *)arg) = flip_u32(le_to_h_u32(in), 32); } static inline void arm_le_to_h_u32(jtag_callback_data_t arg) { uint8_t *in = (uint8_t *)arg; *((uint32_t *)arg) = le_to_h_u32(in); } #endif /* OPENOCD_TARGET_ARM_JTAG_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_opcodes.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2005 by Dominic Rath * Dominic.Rath@gmx.de * * Copyright (C) 2006 by Magnus Lundin * lundin@mlu.mine.nu * * Copyright (C) 2008 by Spencer Oliver * spen@spen-soft.co.uk * * Copyright (C) 2009 by Øyvind Harboe * oyvind.harboe@zylin.com */ #ifndef OPENOCD_TARGET_ARM_OPCODES_H #define OPENOCD_TARGET_ARM_OPCODES_H /** * @file * Macros used to generate various ARM or Thumb opcodes. */ /* ARM mode instructions */ /* Store multiple increment after * rn: base register * list: for each bit in list: store register * s: in privileged mode: store user-mode registers * w = 1: update the base register. w = 0: leave the base register untouched */ #define ARMV4_5_STMIA(rn, list, s, w) \ (0xe8800000 | ((s) << 22) | ((w) << 21) | ((rn) << 16) | (list)) /* Load multiple increment after * rn: base register * list: for each bit in list: store register * s: in privileged mode: store user-mode registers * w = 1: update the base register. w = 0: leave the base register untouched */ #define ARMV4_5_LDMIA(rn, list, s, w) \ (0xe8900000 | ((s) << 22) | ((w) << 21) | ((rn) << 16) | (list)) /* MOV r8, r8 */ #define ARMV4_5_NOP (0xe1a08008) /* Move PSR to general purpose register * r = 1: SPSR r = 0: CPSR * rn: target register */ #define ARMV4_5_MRS(rn, r) (0xe10f0000 | ((r) << 22) | ((rn) << 12)) /* Store register * rd: register to store * rn: base register */ #define ARMV4_5_STR(rd, rn) (0xe5800000 | ((rd) << 12) | ((rn) << 16)) /* Load register * rd: register to load * rn: base register */ #define ARMV4_5_LDR(rd, rn) (0xe5900000 | ((rd) << 12) | ((rn) << 16)) /* Move general purpose register to PSR * r = 1: SPSR r = 0: CPSR * field: Field mask * 1: control field 2: extension field 4: status field 8: flags field * rm: source register */ #define ARMV4_5_MSR_GP(rm, field, r) \ (0xe120f000 | (rm) | ((field) << 16) | ((r) << 22)) #define ARMV4_5_MSR_IM(im, rotate, field, r) \ (0xe320f000 | (im) | ((rotate) << 8) | ((field) << 16) | ((r) << 22)) /* Load Register Word Immediate Post-Index * rd: register to load * rn: base register */ #define ARMV4_5_LDRW_IP(rd, rn) (0xe4900004 | ((rd) << 12) | ((rn) << 16)) /* Load Register Halfword Immediate Post-Index * rd: register to load * rn: base register */ #define ARMV4_5_LDRH_IP(rd, rn) (0xe0d000b2 | ((rd) << 12) | ((rn) << 16)) /* Load Register Byte Immediate Post-Index * rd: register to load * rn: base register */ #define ARMV4_5_LDRB_IP(rd, rn) (0xe4d00001 | ((rd) << 12) | ((rn) << 16)) /* Store register Word Immediate Post-Index * rd: register to store * rn: base register */ #define ARMV4_5_STRW_IP(rd, rn) (0xe4800004 | ((rd) << 12) | ((rn) << 16)) /* Store register Halfword Immediate Post-Index * rd: register to store * rn: base register */ #define ARMV4_5_STRH_IP(rd, rn) (0xe0c000b2 | ((rd) << 12) | ((rn) << 16)) /* Store register Byte Immediate Post-Index * rd: register to store * rn: base register */ #define ARMV4_5_STRB_IP(rd, rn) (0xe4c00001 | ((rd) << 12) | ((rn) << 16)) /* Branch (and Link) * im: Branch target (left-shifted by 2 bits, added to PC) * l: 1: branch and link 0: branch only */ #define ARMV4_5_B(im, l) (0xea000000 | (im) | ((l) << 24)) /* Branch and exchange (ARM state) * rm: register holding branch target address */ #define ARMV4_5_BX(rm) (0xe12fff10 | (rm)) /* Copies two words from two ARM core registers * into a doubleword extension register, or * from a doubleword extension register to two ARM core registers. * See Armv7-A arch reference manual section A8.8.345 * rt: Arm core register 1 * rt2: Arm core register 2 * vm: The doubleword extension register * m: m = UInt(m:vm); * op: to_arm_registers = (op == ‘1’); */ #define ARMV4_5_VMOV(op, rt2, rt, m, vm) \ (0xec400b10 | ((op) << 20) | ((rt2) << 16) | \ ((rt) << 12) | ((m) << 5) | (vm)) /* Moves the value of the FPSCR to an ARM core register * rt: Arm core register */ #define ARMV4_5_VMRS(rt) (0xeef10a10 | ((rt) << 12)) /* Moves the value of an ARM core register to the FPSCR. * rt: Arm core register */ #define ARMV4_5_VMSR(rt) (0xeee10a10 | ((rt) << 12)) /* Store data from coprocessor to consecutive memory * See Armv7-A arch doc section A8.6.187 * p: 1=index mode (offset from rn) * u: 1=add, 0=subtract rn address with imm * d: Opcode D encoding * w: write back the offset start address to the rn register * cp: Coprocessor number (4 bits) * crd: Coprocessor source register (4 bits) * rn: Base register for memory address (4 bits) * imm: Immediate value (0 - 1020, must be divisible by 4) */ #define ARMV4_5_STC(p, u, d, w, cp, crd, rn, imm) \ (0xec000000 | ((p) << 24) | ((u) << 23) | ((d) << 22) | \ ((w) << 21) | ((rn) << 16) | ((crd) << 12) | ((cp) << 8) | ((imm)>>2)) /* Loads data from consecutive memory to coprocessor * See Armv7-A arch doc section A8.6.51 * p: 1=index mode (offset from rn) * u: 1=add, 0=subtract rn address with imm * d: Opcode D encoding * w: write back the offset start address to the rn register * cp: Coprocessor number (4 bits) * crd: Coprocessor dest register (4 bits) * rn: Base register for memory address (4 bits) * imm: Immediate value (0 - 1020, must be divisible by 4) */ #define ARMV4_5_LDC(p, u, d, w, cp, crd, rn, imm) \ (0xec100000 | ((p) << 24) | ((u) << 23) | ((d) << 22) | \ ((w) << 21) | ((rn) << 16) | ((crd) << 12) | ((cp) << 8) | ((imm) >> 2)) /* Move to ARM register from coprocessor * cp: Coprocessor number * op1: Coprocessor opcode * rd: destination register * crn: first coprocessor operand * crm: second coprocessor operand * op2: Second coprocessor opcode */ #define ARMV4_5_MRC(cp, op1, rd, crn, crm, op2) \ (0xee100010 | (crm) | ((op2) << 5) | ((cp) << 8) \ | ((rd) << 12) | ((crn) << 16) | ((op1) << 21)) /* Move to coprocessor from ARM register * cp: Coprocessor number * op1: Coprocessor opcode * rd: destination register * crn: first coprocessor operand * crm: second coprocessor operand * op2: Second coprocessor opcode */ #define ARMV4_5_MCR(cp, op1, rd, crn, crm, op2) \ (0xee000010 | (crm) | ((op2) << 5) | ((cp) << 8) \ | ((rd) << 12) | ((crn) << 16) | ((op1) << 21)) /* Breakpoint instruction (ARMv5) * im: 16-bit immediate */ #define ARMV5_BKPT(im) (0xe1200070 | ((im & 0xfff0) << 4) | (im & 0xf)) /* Thumb mode instructions * * NOTE: these 16-bit opcodes fill both halves of a word with the same * value. The reason for this is that when we need to execute Thumb * opcodes on ARM7/ARM9 cores (to switch to ARM state on debug entry), * we must shift 32 bits to the bus using scan chain 1 ... if we write * both halves, we don't need to track which half matters. On ARMv6 and * ARMv7 we don't execute Thumb instructions in debug mode; the ITR * register does not accept Thumb (or Thumb2) opcodes. */ /* Store register (Thumb mode) * rd: source register * rn: base register */ #define ARMV4_5_T_STR(rd, rn) \ ((0x6000 | (rd) | ((rn) << 3)) | \ ((0x6000 | (rd) | ((rn) << 3)) << 16)) /* Load register (Thumb state) * rd: destination register * rn: base register */ #define ARMV4_5_T_LDR(rd, rn) \ ((0x6800 | ((rn) << 3) | (rd)) \ | ((0x6800 | ((rn) << 3) | (rd)) << 16)) /* Load multiple (Thumb state) * rn: base register * list: for each bit in list: store register */ #define ARMV4_5_T_LDMIA(rn, list) \ ((0xc800 | ((rn) << 8) | (list)) \ | ((0xc800 | ((rn) << 8) | (list)) << 16)) /* Load register with PC relative addressing * rd: register to load */ #define ARMV4_5_T_LDR_PCREL(rd) \ ((0x4800 | ((rd) << 8)) \ | ((0x4800 | ((rd) << 8)) << 16)) /* Move hi register (Thumb mode) * rd: destination register * rm: source register */ #define ARMV4_5_T_MOV(rd, rm) \ ((0x4600 | ((rd) & 0x7) | (((rd) & 0x8) << 4) | \ (((rm) & 0x7) << 3) | (((rm) & 0x8) << 3)) \ | ((0x4600 | ((rd) & 0x7) | (((rd) & 0x8) << 4) | \ (((rm) & 0x7) << 3) | (((rm) & 0x8) << 3)) << 16)) /* No operation (Thumb mode) * NOTE: this is "MOV r8, r8" ... Thumb2 adds two * architected NOPs, 16-bit and 32-bit. */ #define ARMV4_5_T_NOP (0x46c0 | (0x46c0 << 16)) /* Move immediate to register (Thumb state) * rd: destination register * im: 8-bit immediate value */ #define ARMV4_5_T_MOV_IM(rd, im) \ ((0x2000 | ((rd) << 8) | (im)) \ | ((0x2000 | ((rd) << 8) | (im)) << 16)) /* Branch and Exchange * rm: register containing branch target */ #define ARMV4_5_T_BX(rm) \ ((0x4700 | ((rm) << 3)) \ | ((0x4700 | ((rm) << 3)) << 16)) /* Branch (Thumb state) * imm: Branch target */ #define ARMV4_5_T_B(imm) \ ((0xe000 | (imm)) \ | ((0xe000 | (imm)) << 16)) /* Breakpoint instruction (ARMv5) (Thumb state) * Im: 8-bit immediate */ #define ARMV5_T_BKPT(im) \ ((0xbe00 | (im)) \ | ((0xbe00 | (im)) << 16)) /* Move to Register from Special Register * 32 bit Thumb2 instruction * rd: destination register * sysm: source special register */ #define ARM_T2_MRS(rd, sysm) \ ((0xF3EF) | ((0x8000 | (rd << 8) | sysm) << 16)) /* Move from Register from Special Register * 32 bit Thumb2 instruction * rd: source register * sysm: destination special register */ #define ARM_T2_MSR(sysm, rn) \ ((0xF380 | (rn << 8)) | ((0x8800 | sysm) << 16)) /* Change Processor State. * 16 bit Thumb2 instruction * rd: source register * IF: A_FLAG and/or I_FLAG and/or F_FLAG */ #define A_FLAG 4 #define I_FLAG 2 #define F_FLAG 1 #define ARM_T2_CPSID(_if) \ ((0xB660 | (1 << 8) | ((_if)&0x3)) \ | ((0xB660 | (1 << 8) | ((_if)&0x3)) << 16)) #define ARM_T2_CPSIE(_if) \ ((0xB660 | (0 << 8) | ((_if)&0x3)) \ | ((0xB660 | (0 << 8) | ((_if)&0x3)) << 16)) #endif /* OPENOCD_TARGET_ARM_OPCODES_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_semihosting.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by Marvell Technology Group Ltd. * * Written by Nicolas Pitre <nico@marvell.com> * * * * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2016 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * * * * Copyright (C) 2018 by Liviu Ionescu * * <ilg@livius.net> * ***************************************************************************/ /** * @file * Hold ARM semihosting support. * * Semihosting enables code running on an ARM target to use the I/O * facilities on the host computer. The target application must be linked * against a library that forwards operation requests by using the SVC * instruction trapped at the Supervisor Call vector by the debugger. * Details can be found in chapter 8 of DUI0203I_rvct_developer_guide.pdf * from ARM Ltd. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "armv4_5.h" #include "arm7_9_common.h" #include "armv7m.h" #include "armv7a.h" #include "armv8.h" #include "cortex_m.h" #include "register.h" #include "arm_opcodes.h" #include "target_type.h" #include "arm_semihosting.h" #include <helper/binarybuffer.h> #include <helper/log.h> #include <sys/stat.h> static int arm_semihosting_resume(struct target *target, int *retval) { if (is_armv8(target_to_armv8(target))) { struct armv8_common *armv8 = target_to_armv8(target); if (armv8->last_run_control_op == ARMV8_RUNCONTROL_RESUME) { *retval = target_resume(target, 1, 0, 0, 0); if (*retval != ERROR_OK) { LOG_ERROR("Failed to resume target"); return 0; } } else if (armv8->last_run_control_op == ARMV8_RUNCONTROL_STEP) target->debug_reason = DBG_REASON_SINGLESTEP; } else { *retval = target_resume(target, 1, 0, 0, 0); if (*retval != ERROR_OK) { LOG_ERROR("Failed to resume target"); return 0; } } return 1; } static int post_result(struct target *target) { struct arm *arm = target_to_arm(target); if (!target->semihosting) return ERROR_FAIL; /* REVISIT this looks wrong ... ARM11 and Cortex-A8 * should work this way at least sometimes. */ if (is_arm7_9(target_to_arm7_9(target)) || is_armv7a(target_to_armv7a(target))) { uint32_t spsr; /* return value in R0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, target->semihosting->result); arm->core_cache->reg_list[0].dirty = true; /* LR --> PC */ buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32, buf_get_u32(arm_reg_current(arm, 14)->value, 0, 32)); arm->core_cache->reg_list[15].dirty = true; /* saved PSR --> current PSR */ spsr = buf_get_u32(arm->spsr->value, 0, 32); /* REVISIT should this be arm_set_cpsr(arm, spsr) * instead of a partially unrolled version? */ buf_set_u32(arm->cpsr->value, 0, 32, spsr); arm->cpsr->dirty = true; arm->core_mode = spsr & 0x1f; if (spsr & 0x20) arm->core_state = ARM_STATE_THUMB; } else if (is_armv8(target_to_armv8(target))) { if (arm->core_state == ARM_STATE_AARCH64) { /* return value in R0 */ buf_set_u64(arm->core_cache->reg_list[0].value, 0, 64, target->semihosting->result); arm->core_cache->reg_list[0].dirty = true; uint64_t pc = buf_get_u64(arm->core_cache->reg_list[32].value, 0, 64); buf_set_u64(arm->pc->value, 0, 64, pc + 4); arm->pc->dirty = true; } else if (arm->core_state == ARM_STATE_ARM) { /* return value in R0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, target->semihosting->result); arm->core_cache->reg_list[0].dirty = true; uint32_t pc = buf_get_u32(arm->core_cache->reg_list[32].value, 0, 32); buf_set_u32(arm->pc->value, 0, 32, pc + 4); arm->pc->dirty = true; } else if (arm->core_state == ARM_STATE_THUMB) { /* return value in R0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, target->semihosting->result); arm->core_cache->reg_list[0].dirty = true; uint32_t pc = buf_get_u32(arm->core_cache->reg_list[32].value, 0, 32); buf_set_u32(arm->pc->value, 0, 32, pc + 2); arm->pc->dirty = true; } } else { /* resume execution, this will be pc+2 to skip over the * bkpt instruction */ /* return result in R0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, target->semihosting->result); arm->core_cache->reg_list[0].dirty = true; } return ERROR_OK; } /** * Initialize ARM semihosting support. * * @param target Pointer to the ARM target to initialize. * @return An error status if there is a problem during initialization. */ int arm_semihosting_init(struct target *target) { struct arm *arm = target_to_arm(target); assert(arm->setup_semihosting); semihosting_common_init(target, arm->setup_semihosting, post_result); return ERROR_OK; } /** * Checks for and processes an ARM semihosting request. This is meant * to be called when the target is stopped due to a debug mode entry. * If the value 0 is returned then there was nothing to process. A non-zero * return value signifies that a request was processed and the target resumed, * or an error was encountered, in which case the caller must return * immediately. * * @param target Pointer to the ARM target to process. This target must * not represent an ARMv6-M or ARMv7-M processor. * @param retval Pointer to a location where the return code will be stored * @return non-zero value if a request was processed or an error encountered */ int arm_semihosting(struct target *target, int *retval) { struct arm *arm = target_to_arm(target); struct armv7a_common *armv7a = target_to_armv7a(target); uint32_t pc, lr, spsr; struct reg *r; struct semihosting *semihosting = target->semihosting; if (!semihosting) return 0; if (!semihosting->is_active) return 0; if (is_arm7_9(target_to_arm7_9(target)) || is_armv7a(armv7a)) { uint32_t vbar = 0x00000000; if (arm->core_mode != ARM_MODE_SVC) return 0; if (is_armv7a(armv7a)) { struct arm_dpm *dpm = armv7a->arm.dpm; *retval = dpm->prepare(dpm); if (*retval == ERROR_OK) { *retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 12, 0, 0), &vbar); dpm->finish(dpm); if (*retval != ERROR_OK) return 1; } else { return 1; } } /* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */ r = arm->pc; pc = buf_get_u32(r->value, 0, 32); if (pc != (vbar + 0x00000008) && pc != 0xffff0008) return 0; r = arm_reg_current(arm, 14); lr = buf_get_u32(r->value, 0, 32); /* Core-specific code should make sure SPSR is retrieved * when the above checks pass... */ if (!arm->spsr->valid) { LOG_ERROR("SPSR not valid!"); *retval = ERROR_FAIL; return 1; } spsr = buf_get_u32(arm->spsr->value, 0, 32); /* check instruction that triggered this trap */ if (spsr & (1 << 5)) { /* was in Thumb (or ThumbEE) mode */ uint8_t insn_buf[2]; uint16_t insn; *retval = target_read_memory(target, lr-2, 2, 1, insn_buf); if (*retval != ERROR_OK) return 1; insn = target_buffer_get_u16(target, insn_buf); /* SVC 0xab */ if (insn != 0xDFAB) return 0; } else if (spsr & (1 << 24)) { /* was in Jazelle mode */ return 0; } else { /* was in ARM mode */ uint8_t insn_buf[4]; uint32_t insn; *retval = target_read_memory(target, lr-4, 4, 1, insn_buf); if (*retval != ERROR_OK) return 1; insn = target_buffer_get_u32(target, insn_buf); /* SVC 0x123456 */ if (insn != 0xEF123456) return 0; } } else if (is_armv7m(target_to_armv7m(target))) { uint16_t insn; if (target->debug_reason != DBG_REASON_BREAKPOINT) return 0; r = arm->pc; pc = buf_get_u32(r->value, 0, 32); pc &= ~1; *retval = target_read_u16(target, pc, &insn); if (*retval != ERROR_OK) return 1; /* bkpt 0xAB */ if (insn != 0xBEAB) return 0; } else if (is_armv8(target_to_armv8(target))) { if (target->debug_reason != DBG_REASON_BREAKPOINT) return 0; /* According to ARM Semihosting for AArch32 and AArch64: * The HLT encodings are new in version 2.0 of the semihosting specification. * Where possible, have semihosting callers continue to use the previously * existing trap instructions to ensure compatibility with legacy semihosting * implementations. * These trap instructions are HLT for A64, SVC on A+R profile A32 or T32, * and BKPT on M profile. * However, it is necessary to change from SVC to HLT instructions to support * AArch32 semihosting properly in a mixed AArch32/AArch64 system. */ if (arm->core_state == ARM_STATE_AARCH64) { uint32_t insn = 0; r = arm->pc; uint64_t pc64 = buf_get_u64(r->value, 0, 64); *retval = target_read_u32(target, pc64, &insn); if (*retval != ERROR_OK) return 1; /* HLT 0xF000 */ if (insn != 0xD45E0000) return 0; } else if (arm->core_state == ARM_STATE_ARM) { r = arm->pc; pc = buf_get_u32(r->value, 0, 32); /* A32 instruction => check for HLT 0xF000 (0xE10F0070) */ uint32_t insn = 0; *retval = target_read_u32(target, pc, &insn); if (*retval != ERROR_OK) return 1; /* HLT 0xF000*/ if (insn != 0xE10F0070) return 0; } else if (arm->core_state == ARM_STATE_THUMB) { r = arm->pc; pc = buf_get_u32(r->value, 0, 32); /* T32 instruction => check for HLT 0x3C (0xBABC) */ uint16_t insn = 0; *retval = target_read_u16(target, pc, &insn); if (*retval != ERROR_OK) return 1; /* HLT 0x3C*/ if (insn != 0xBABC) return 0; } else return 1; } else { LOG_ERROR("Unsupported semi-hosting Target"); return 0; } /* Perform semihosting if we are not waiting on a fileio * operation to complete. */ if (!semihosting->hit_fileio) { if (is_armv8(target_to_armv8(target)) && arm->core_state == ARM_STATE_AARCH64) { /* Read op and param from register x0 and x1 respectively. */ semihosting->op = buf_get_u64(arm->core_cache->reg_list[0].value, 0, 64); semihosting->param = buf_get_u64(arm->core_cache->reg_list[1].value, 0, 64); semihosting->word_size_bytes = 8; } else { /* Read op and param from register r0 and r1 respectively. */ semihosting->op = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32); semihosting->param = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32); semihosting->word_size_bytes = 4; } /* Check for ARM operation numbers. */ if ((semihosting->op >= 0 && semihosting->op <= 0x31) || (semihosting->op >= 0x100 && semihosting->op <= 0x107)) { *retval = semihosting_common(target); if (*retval != ERROR_OK) { LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op); return 0; } } else { /* Unknown operation number, not a semihosting call. */ return 0; } } /* Resume if target it is resumable and we are not waiting on a fileio * operation to complete: */ if (semihosting->is_resumable && !semihosting->hit_fileio) return arm_semihosting_resume(target, retval); return 0; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_semihosting.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 by Marvell Technology Group Ltd. * * Written by Nicolas Pitre <nico@marvell.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM_SEMIHOSTING_H #define OPENOCD_TARGET_ARM_SEMIHOSTING_H #include "semihosting_common.h" int arm_semihosting_init(struct target *target); int arm_semihosting(struct target *target, int *retval); #endif /* OPENOCD_TARGET_ARM_SEMIHOSTING_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_simulator.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Hongtao Zheng * * hontor@126.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "armv4_5.h" #include "arm_disassembler.h" #include "arm_simulator.h" #include <helper/binarybuffer.h> #include "register.h" #include <helper/log.h> static uint32_t arm_shift(uint8_t shift, uint32_t rm, uint32_t shift_amount, uint8_t *carry) { uint32_t return_value = 0; shift_amount &= 0xff; if (shift == 0x0) { /* LSL */ if ((shift_amount > 0) && (shift_amount <= 32)) { return_value = rm << shift_amount; *carry = rm >> (32 - shift_amount); } else if (shift_amount > 32) { return_value = 0x0; *carry = 0x0; } else /* (shift_amount == 0) */ return_value = rm; } else if (shift == 0x1) { /* LSR */ if ((shift_amount > 0) && (shift_amount <= 32)) { return_value = rm >> shift_amount; *carry = (rm >> (shift_amount - 1)) & 1; } else if (shift_amount > 32) { return_value = 0x0; *carry = 0x0; } else /* (shift_amount == 0) */ return_value = rm; } else if (shift == 0x2) { /* ASR */ if ((shift_amount > 0) && (shift_amount <= 32)) { /* C right shifts of unsigned values are guaranteed to * be logical (shift in zeroes); simulate an arithmetic * shift (shift in signed-bit) by adding the sign bit * manually */ return_value = rm >> shift_amount; if (rm & 0x80000000) return_value |= 0xffffffff << (32 - shift_amount); } else if (shift_amount > 32) { if (rm & 0x80000000) { return_value = 0xffffffff; *carry = 0x1; } else { return_value = 0x0; *carry = 0x0; } } else /* (shift_amount == 0) */ return_value = rm; } else if (shift == 0x3) { /* ROR */ if (shift_amount == 0) return_value = rm; else { shift_amount = shift_amount % 32; return_value = (rm >> shift_amount) | (rm << (32 - shift_amount)); *carry = (return_value >> 31) & 0x1; } } else if (shift == 0x4) { /* RRX */ return_value = rm >> 1; if (*carry) rm |= 0x80000000; *carry = rm & 0x1; } return return_value; } static uint32_t arm_shifter_operand(struct arm_sim_interface *sim, int variant, union arm_shifter_operand shifter_operand, uint8_t *shifter_carry_out) { uint32_t return_value; int instruction_size; if (sim->get_state(sim) == ARM_STATE_ARM) instruction_size = 4; else instruction_size = 2; *shifter_carry_out = sim->get_cpsr(sim, 29, 1); if (variant == 0) /* 32-bit immediate */ return_value = shifter_operand.immediate.immediate; else if (variant == 1) {/* immediate shift */ uint32_t rm = sim->get_reg_mode(sim, shifter_operand.immediate_shift.rm); /* adjust RM in case the PC is being read */ if (shifter_operand.immediate_shift.rm == 15) rm += 2 * instruction_size; return_value = arm_shift(shifter_operand.immediate_shift.shift, rm, shifter_operand.immediate_shift.shift_imm, shifter_carry_out); } else if (variant == 2) { /* register shift */ uint32_t rm = sim->get_reg_mode(sim, shifter_operand.register_shift.rm); uint32_t rs = sim->get_reg_mode(sim, shifter_operand.register_shift.rs); /* adjust RM in case the PC is being read */ if (shifter_operand.register_shift.rm == 15) rm += 2 * instruction_size; return_value = arm_shift(shifter_operand.immediate_shift.shift, rm, rs, shifter_carry_out); } else { LOG_ERROR("BUG: shifter_operand.variant not 0, 1 or 2"); return_value = 0xffffffff; } return return_value; } static int pass_condition(uint32_t cpsr, uint32_t opcode) { switch ((opcode & 0xf0000000) >> 28) { case 0x0: /* EQ */ if (cpsr & 0x40000000) return 1; else return 0; case 0x1: /* NE */ if (!(cpsr & 0x40000000)) return 1; else return 0; case 0x2: /* CS */ if (cpsr & 0x20000000) return 1; else return 0; case 0x3: /* CC */ if (!(cpsr & 0x20000000)) return 1; else return 0; case 0x4: /* MI */ if (cpsr & 0x80000000) return 1; else return 0; case 0x5: /* PL */ if (!(cpsr & 0x80000000)) return 1; else return 0; case 0x6: /* VS */ if (cpsr & 0x10000000) return 1; else return 0; case 0x7: /* VC */ if (!(cpsr & 0x10000000)) return 1; else return 0; case 0x8: /* HI */ if ((cpsr & 0x20000000) && !(cpsr & 0x40000000)) return 1; else return 0; case 0x9: /* LS */ if (!(cpsr & 0x20000000) || (cpsr & 0x40000000)) return 1; else return 0; case 0xa: /* GE */ if (((cpsr & 0x80000000) && (cpsr & 0x10000000)) || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000))) return 1; else return 0; case 0xb: /* LT */ if (((cpsr & 0x80000000) && !(cpsr & 0x10000000)) || (!(cpsr & 0x80000000) && (cpsr & 0x10000000))) return 1; else return 0; case 0xc: /* GT */ if (!(cpsr & 0x40000000) && (((cpsr & 0x80000000) && (cpsr & 0x10000000)) || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000)))) return 1; else return 0; case 0xd: /* LE */ if ((cpsr & 0x40000000) || ((cpsr & 0x80000000) && !(cpsr & 0x10000000)) || (!(cpsr & 0x80000000) && (cpsr & 0x10000000))) return 1; else return 0; case 0xe: case 0xf: return 1; } LOG_ERROR("BUG: should never get here"); return 0; } static int thumb_pass_branch_condition(uint32_t cpsr, uint16_t opcode) { return pass_condition(cpsr, (opcode & 0x0f00) << 20); } /* simulate a single step (if possible) * if the dry_run_pc argument is provided, no state is changed, * but the new pc is stored in the variable pointed at by the argument */ static int arm_simulate_step_core(struct target *target, uint32_t *dry_run_pc, struct arm_sim_interface *sim) { uint32_t current_pc = sim->get_reg(sim, 15); struct arm_instruction instruction; int instruction_size; int retval = ERROR_OK; if (sim->get_state(sim) == ARM_STATE_ARM) { uint32_t opcode; /* get current instruction, and identify it */ retval = target_read_u32(target, current_pc, &opcode); if (retval != ERROR_OK) return retval; retval = arm_evaluate_opcode(opcode, current_pc, &instruction); if (retval != ERROR_OK) return retval; instruction_size = 4; /* check condition code (for all instructions) */ if (!pass_condition(sim->get_cpsr(sim, 0, 32), opcode)) { if (dry_run_pc) *dry_run_pc = current_pc + instruction_size; else sim->set_reg(sim, 15, current_pc + instruction_size); return ERROR_OK; } } else { uint16_t opcode; retval = target_read_u16(target, current_pc, &opcode); if (retval != ERROR_OK) return retval; retval = thumb_evaluate_opcode(opcode, current_pc, &instruction); if (retval != ERROR_OK) return retval; instruction_size = 2; /* check condition code (only for branch (1) instructions) */ if ((opcode & 0xf000) == 0xd000 && !thumb_pass_branch_condition( sim->get_cpsr(sim, 0, 32), opcode)) { if (dry_run_pc) *dry_run_pc = current_pc + instruction_size; else sim->set_reg(sim, 15, current_pc + instruction_size); return ERROR_OK; } /* Deal with 32-bit BL/BLX */ if ((opcode & 0xf800) == 0xf000) { uint32_t high = instruction.info.b_bl_bx_blx.target_address; retval = target_read_u16(target, current_pc+2, &opcode); if (retval != ERROR_OK) return retval; retval = thumb_evaluate_opcode(opcode, current_pc, &instruction); if (retval != ERROR_OK) return retval; instruction.info.b_bl_bx_blx.target_address += high; } } /* examine instruction type */ /* branch instructions */ if ((instruction.type >= ARM_B) && (instruction.type <= ARM_BLX)) { uint32_t target_address; if (instruction.info.b_bl_bx_blx.reg_operand == -1) target_address = instruction.info.b_bl_bx_blx.target_address; else { target_address = sim->get_reg_mode(sim, instruction.info.b_bl_bx_blx.reg_operand); if (instruction.info.b_bl_bx_blx.reg_operand == 15) target_address += 2 * instruction_size; } if (dry_run_pc) { *dry_run_pc = target_address & ~1; return ERROR_OK; } else { if (instruction.type == ARM_B) sim->set_reg(sim, 15, target_address); else if (instruction.type == ARM_BL) { uint32_t old_pc = sim->get_reg(sim, 15); int t = (sim->get_state(sim) == ARM_STATE_THUMB); sim->set_reg_mode(sim, 14, old_pc + 4 + t); sim->set_reg(sim, 15, target_address); } else if (instruction.type == ARM_BX) { if (target_address & 0x1) sim->set_state(sim, ARM_STATE_THUMB); else sim->set_state(sim, ARM_STATE_ARM); sim->set_reg(sim, 15, target_address & 0xfffffffe); } else if (instruction.type == ARM_BLX) { uint32_t old_pc = sim->get_reg(sim, 15); int t = (sim->get_state(sim) == ARM_STATE_THUMB); sim->set_reg_mode(sim, 14, old_pc + 4 + t); if (target_address & 0x1) sim->set_state(sim, ARM_STATE_THUMB); else sim->set_state(sim, ARM_STATE_ARM); sim->set_reg(sim, 15, target_address & 0xfffffffe); } return ERROR_OK; } } /* data processing instructions, except compare instructions (CMP, CMN, TST, TEQ) */ else if (((instruction.type >= ARM_AND) && (instruction.type <= ARM_RSC)) || ((instruction.type >= ARM_ORR) && (instruction.type <= ARM_MVN))) { uint32_t rd, rn, shifter_operand; uint8_t c = sim->get_cpsr(sim, 29, 1); uint8_t carry_out; rd = 0x0; /* ARM_MOV and ARM_MVN does not use Rn */ if ((instruction.type != ARM_MOV) && (instruction.type != ARM_MVN)) rn = sim->get_reg_mode(sim, instruction.info.data_proc.rn); else rn = 0; shifter_operand = arm_shifter_operand(sim, instruction.info.data_proc.variant, instruction.info.data_proc.shifter_operand, &carry_out); /* adjust Rn in case the PC is being read */ if (instruction.info.data_proc.rn == 15) rn += 2 * instruction_size; if (instruction.type == ARM_AND) rd = rn & shifter_operand; else if (instruction.type == ARM_EOR) rd = rn ^ shifter_operand; else if (instruction.type == ARM_SUB) rd = rn - shifter_operand; else if (instruction.type == ARM_RSB) rd = shifter_operand - rn; else if (instruction.type == ARM_ADD) rd = rn + shifter_operand; else if (instruction.type == ARM_ADC) rd = rn + shifter_operand + (c & 1); else if (instruction.type == ARM_SBC) rd = rn - shifter_operand - (c & 1) ? 0 : 1; else if (instruction.type == ARM_RSC) rd = shifter_operand - rn - (c & 1) ? 0 : 1; else if (instruction.type == ARM_ORR) rd = rn | shifter_operand; else if (instruction.type == ARM_BIC) rd = rn & ~(shifter_operand); else if (instruction.type == ARM_MOV) rd = shifter_operand; else if (instruction.type == ARM_MVN) rd = ~shifter_operand; else LOG_WARNING("unhandled instruction type"); if (dry_run_pc) { if (instruction.info.data_proc.rd == 15) *dry_run_pc = rd & ~1; else *dry_run_pc = current_pc + instruction_size; return ERROR_OK; } else { if (instruction.info.data_proc.rd == 15) { sim->set_reg_mode(sim, 15, rd & ~1); if (rd & 1) sim->set_state(sim, ARM_STATE_THUMB); else sim->set_state(sim, ARM_STATE_ARM); return ERROR_OK; } sim->set_reg_mode(sim, instruction.info.data_proc.rd, rd); LOG_WARNING("no updating of flags yet"); } } /* compare instructions (CMP, CMN, TST, TEQ) */ else if ((instruction.type >= ARM_TST) && (instruction.type <= ARM_CMN)) { if (dry_run_pc) { *dry_run_pc = current_pc + instruction_size; return ERROR_OK; } else LOG_WARNING("no updating of flags yet"); } /* load register instructions */ else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDRSH)) { uint32_t load_address = 0, modified_address = 0, load_value = 0; uint32_t rn = sim->get_reg_mode(sim, instruction.info.load_store.rn); /* adjust Rn in case the PC is being read */ if (instruction.info.load_store.rn == 15) rn += 2 * instruction_size; if (instruction.info.load_store.offset_mode == 0) { if (instruction.info.load_store.u) modified_address = rn + instruction.info.load_store.offset.offset; else modified_address = rn - instruction.info.load_store.offset.offset; } else if (instruction.info.load_store.offset_mode == 1) { uint32_t offset; uint32_t rm = sim->get_reg_mode(sim, instruction.info.load_store.offset.reg.rm); uint8_t shift = instruction.info.load_store.offset.reg.shift; uint8_t shift_imm = instruction.info.load_store.offset.reg.shift_imm; uint8_t carry = sim->get_cpsr(sim, 29, 1); offset = arm_shift(shift, rm, shift_imm, &carry); if (instruction.info.load_store.u) modified_address = rn + offset; else modified_address = rn - offset; } else LOG_ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)"); if (instruction.info.load_store.index_mode == 0) { /* offset mode * we load from the modified address, but don't change * the base address register */ load_address = modified_address; modified_address = rn; } else if (instruction.info.load_store.index_mode == 1) { /* pre-indexed mode * we load from the modified address, and write it * back to the base address register */ load_address = modified_address; } else if (instruction.info.load_store.index_mode == 2) { /* post-indexed mode * we load from the unmodified address, and write the * modified address back */ load_address = rn; } if ((!dry_run_pc) || (instruction.info.load_store.rd == 15)) { retval = target_read_u32(target, load_address, &load_value); if (retval != ERROR_OK) return retval; } if (dry_run_pc) { if (instruction.info.load_store.rd == 15) *dry_run_pc = load_value & ~1; else *dry_run_pc = current_pc + instruction_size; return ERROR_OK; } else { if ((instruction.info.load_store.index_mode == 1) || (instruction.info.load_store.index_mode == 2)) sim->set_reg_mode(sim, instruction.info.load_store.rn, modified_address); if (instruction.info.load_store.rd == 15) { sim->set_reg_mode(sim, 15, load_value & ~1); if (load_value & 1) sim->set_state(sim, ARM_STATE_THUMB); else sim->set_state(sim, ARM_STATE_ARM); return ERROR_OK; } sim->set_reg_mode(sim, instruction.info.load_store.rd, load_value); } } /* load multiple instruction */ else if (instruction.type == ARM_LDM) { int i; uint32_t rn = sim->get_reg_mode(sim, instruction.info.load_store_multiple.rn); uint32_t load_values[16]; int bits_set = 0; for (i = 0; i < 16; i++) { if (instruction.info.load_store_multiple.register_list & (1 << i)) bits_set++; } switch (instruction.info.load_store_multiple.addressing_mode) { case 0: /* Increment after */ /* rn = rn; */ break; case 1: /* Increment before */ rn = rn + 4; break; case 2: /* Decrement after */ rn = rn - (bits_set * 4) + 4; break; case 3: /* Decrement before */ rn = rn - (bits_set * 4); break; } for (i = 0; i < 16; i++) { if (instruction.info.load_store_multiple.register_list & (1 << i)) { if ((!dry_run_pc) || (i == 15)) target_read_u32(target, rn, &load_values[i]); rn += 4; } } if (dry_run_pc) { if (instruction.info.load_store_multiple.register_list & 0x8000) { *dry_run_pc = load_values[15] & ~1; return ERROR_OK; } } else { int update_cpsr = 0; if (instruction.info.load_store_multiple.s) { if (instruction.info.load_store_multiple.register_list & 0x8000) update_cpsr = 1; } for (i = 0; i < 16; i++) { if (instruction.info.load_store_multiple.register_list & (1 << i)) { if (i == 15) { uint32_t val = load_values[i]; sim->set_reg_mode(sim, i, val & ~1); if (val & 1) sim->set_state(sim, ARM_STATE_THUMB); else sim->set_state(sim, ARM_STATE_ARM); } else sim->set_reg_mode(sim, i, load_values[i]); } } if (update_cpsr) { uint32_t spsr = sim->get_reg_mode(sim, 16); sim->set_reg(sim, ARMV4_5_CPSR, spsr); } /* base register writeback */ if (instruction.info.load_store_multiple.w) sim->set_reg_mode(sim, instruction.info.load_store_multiple.rn, rn); if (instruction.info.load_store_multiple.register_list & 0x8000) return ERROR_OK; } } /* store multiple instruction */ else if (instruction.type == ARM_STM) { int i; if (dry_run_pc) { /* STM wont affect PC (advance by instruction size */ } else { uint32_t rn = sim->get_reg_mode(sim, instruction.info.load_store_multiple.rn); int bits_set = 0; for (i = 0; i < 16; i++) { if (instruction.info.load_store_multiple.register_list & (1 << i)) bits_set++; } switch (instruction.info.load_store_multiple.addressing_mode) { case 0: /* Increment after */ /* rn = rn; */ break; case 1: /* Increment before */ rn = rn + 4; break; case 2: /* Decrement after */ rn = rn - (bits_set * 4) + 4; break; case 3: /* Decrement before */ rn = rn - (bits_set * 4); break; } for (i = 0; i < 16; i++) { if (instruction.info.load_store_multiple.register_list & (1 << i)) { target_write_u32(target, rn, sim->get_reg_mode(sim, i)); rn += 4; } } /* base register writeback */ if (instruction.info.load_store_multiple.w) sim->set_reg_mode(sim, instruction.info.load_store_multiple.rn, rn); } } else if (!dry_run_pc) { /* the instruction wasn't handled, but we're supposed to simulate it */ LOG_ERROR("Unimplemented instruction, could not simulate it."); return ERROR_FAIL; } if (dry_run_pc) { *dry_run_pc = current_pc + instruction_size; return ERROR_OK; } else { sim->set_reg(sim, 15, current_pc + instruction_size); return ERROR_OK; } } static uint32_t armv4_5_get_reg(struct arm_sim_interface *sim, int reg) { struct arm *arm = (struct arm *)sim->user_data; return buf_get_u32(arm->core_cache->reg_list[reg].value, 0, 32); } static void armv4_5_set_reg(struct arm_sim_interface *sim, int reg, uint32_t value) { struct arm *arm = (struct arm *)sim->user_data; buf_set_u32(arm->core_cache->reg_list[reg].value, 0, 32, value); } static uint32_t armv4_5_get_reg_mode(struct arm_sim_interface *sim, int reg) { struct arm *arm = (struct arm *)sim->user_data; return buf_get_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, arm->core_mode, reg).value, 0, 32); } static void armv4_5_set_reg_mode(struct arm_sim_interface *sim, int reg, uint32_t value) { struct arm *arm = (struct arm *)sim->user_data; buf_set_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, arm->core_mode, reg).value, 0, 32, value); } static uint32_t armv4_5_get_cpsr(struct arm_sim_interface *sim, int pos, int bits) { struct arm *arm = (struct arm *)sim->user_data; return buf_get_u32(arm->cpsr->value, pos, bits); } static enum arm_state armv4_5_get_state(struct arm_sim_interface *sim) { struct arm *arm = (struct arm *)sim->user_data; return arm->core_state; } static void armv4_5_set_state(struct arm_sim_interface *sim, enum arm_state mode) { struct arm *arm = (struct arm *)sim->user_data; arm->core_state = mode; } static enum arm_mode armv4_5_get_mode(struct arm_sim_interface *sim) { struct arm *arm = (struct arm *)sim->user_data; return arm->core_mode; } int arm_simulate_step(struct target *target, uint32_t *dry_run_pc) { struct arm *arm = target_to_arm(target); struct arm_sim_interface sim; sim.user_data = arm; sim.get_reg = &armv4_5_get_reg; sim.set_reg = &armv4_5_set_reg; sim.get_reg_mode = &armv4_5_get_reg_mode; sim.set_reg_mode = &armv4_5_set_reg_mode; sim.get_cpsr = &armv4_5_get_cpsr; sim.get_mode = &armv4_5_get_mode; sim.get_state = &armv4_5_get_state; sim.set_state = &armv4_5_set_state; return arm_simulate_step_core(target, dry_run_pc, &sim); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_simulator.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM_SIMULATOR_H #define OPENOCD_TARGET_ARM_SIMULATOR_H struct target; struct arm_sim_interface { void *user_data; uint32_t (*get_reg)(struct arm_sim_interface *sim, int reg); void (*set_reg)(struct arm_sim_interface *sim, int reg, uint32_t value); uint32_t (*get_reg_mode)(struct arm_sim_interface *sim, int reg); void (*set_reg_mode)(struct arm_sim_interface *sim, int reg, uint32_t value); uint32_t (*get_cpsr)(struct arm_sim_interface *sim, int pos, int bits); enum arm_state (*get_state)(struct arm_sim_interface *sim); void (*set_state)(struct arm_sim_interface *sim, enum arm_state mode); enum arm_mode (*get_mode)(struct arm_sim_interface *sim); }; /* armv4_5 version */ int arm_simulate_step(struct target *target, uint32_t *dry_run_pc); #endif /* OPENOCD_TARGET_ARM_SIMULATOR_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_tpiu_swo.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /** * @file * This file implements support for the ARM CoreSight components Trace Port * Interface Unit (TPIU) and Serial Wire Output (SWO). It also supports the * CoreSight TPIU-Lite and the special TPIU version present with Cortex-M3 * and Cortex-M4 (that includes SWO). */ /* * Relevant specifications from ARM include: * * CoreSight(tm) Components Technical Reference Manual ARM DDI 0314H * CoreSight(tm) TPIU-Lite Technical Reference Manual ARM DDI 0317A * Cortex(tm)-M3 Technical Reference Manual ARM DDI 0337G * Cortex(tm)-M4 Technical Reference Manual ARM DDI 0439B * CoreSight(tm) SoC-400 Technical Reference Manual ARM DDI 0480F */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdlib.h> #include <jim.h> #include <helper/bits.h> #include <helper/command.h> #include <helper/jim-nvp.h> #include <helper/list.h> #include <helper/log.h> #include <helper/types.h> #include <jtag/interface.h> #include <server/server.h> #include <target/arm_adi_v5.h> #include <target/target.h> #include <transport/transport.h> #include "arm_tpiu_swo.h" /* START_DEPRECATED_TPIU */ #include <target/cortex_m.h> #include <target/target_type.h> #define MSG "DEPRECATED \'tpiu config\' command: " /* END_DEPRECATED_TPIU */ #define TCP_SERVICE_NAME "tpiu_swo_trace" /* default for Cortex-M3 and Cortex-M4 specific TPIU */ #define TPIU_SWO_DEFAULT_BASE 0xE0040000 #define TPIU_SSPSR_OFFSET 0x000 #define TPIU_CSPSR_OFFSET 0x004 #define TPIU_ACPR_OFFSET 0x010 #define TPIU_SPPR_OFFSET 0x0F0 #define TPIU_FFSR_OFFSET 0x300 #define TPIU_FFCR_OFFSET 0x304 #define TPIU_FSCR_OFFSET 0x308 #define TPIU_DEVID_OFFSET 0xfc8 #define TPIU_ACPR_MAX_PRESCALER 0x1fff #define TPIU_SPPR_PROTOCOL_SYNC (TPIU_PIN_PROTOCOL_SYNC) #define TPIU_SPPR_PROTOCOL_MANCHESTER (TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER) #define TPIU_SPPR_PROTOCOL_UART (TPIU_PIN_PROTOCOL_ASYNC_UART) #define TPIU_DEVID_NOSUPPORT_SYNC BIT(9) #define TPIU_DEVID_SUPPORT_MANCHESTER BIT(10) #define TPIU_DEVID_SUPPORT_UART BIT(11) enum arm_tpiu_swo_event { TPIU_SWO_EVENT_PRE_ENABLE, TPIU_SWO_EVENT_POST_ENABLE, TPIU_SWO_EVENT_PRE_DISABLE, TPIU_SWO_EVENT_POST_DISABLE, }; static const struct jim_nvp nvp_arm_tpiu_swo_event[] = { { .value = TPIU_SWO_EVENT_PRE_ENABLE, .name = "pre-enable" }, { .value = TPIU_SWO_EVENT_POST_ENABLE, .name = "post-enable" }, { .value = TPIU_SWO_EVENT_PRE_DISABLE, .name = "pre-disable" }, { .value = TPIU_SWO_EVENT_POST_DISABLE, .name = "post-disable" }, }; struct arm_tpiu_swo_event_action { enum arm_tpiu_swo_event event; Jim_Interp *interp; Jim_Obj *body; struct arm_tpiu_swo_event_action *next; }; struct arm_tpiu_swo_object { struct list_head lh; struct adiv5_mem_ap_spot spot; struct adiv5_ap *ap; char *name; struct arm_tpiu_swo_event_action *event_action; /* record enable before init */ bool deferred_enable; bool enabled; bool en_capture; /** Handle to output trace data in INTERNAL capture mode */ /** Synchronous output port width */ uint32_t port_width; FILE *file; /** output mode */ unsigned int pin_protocol; /** Enable formatter */ bool en_formatter; /** frequency of TRACECLKIN (usually matches HCLK) */ unsigned int traceclkin_freq; /** SWO pin frequency */ unsigned int swo_pin_freq; /** where to dump the captured output trace data */ char *out_filename; /** track TCP connections */ struct list_head connections; /* START_DEPRECATED_TPIU */ bool recheck_ap_cur_target; /* END_DEPRECATED_TPIU */ }; struct arm_tpiu_swo_connection { struct list_head lh; struct connection *connection; }; struct arm_tpiu_swo_priv_connection { struct arm_tpiu_swo_object *obj; }; static LIST_HEAD(all_tpiu_swo); #define ARM_TPIU_SWO_TRACE_BUF_SIZE 4096 static int arm_tpiu_swo_poll_trace(void *priv) { struct arm_tpiu_swo_object *obj = priv; uint8_t buf[ARM_TPIU_SWO_TRACE_BUF_SIZE]; size_t size = sizeof(buf); struct arm_tpiu_swo_connection *c; int retval = adapter_poll_trace(buf, &size); if (retval != ERROR_OK || !size) return retval; target_call_trace_callbacks(/*target*/NULL, size, buf); if (obj->file) { if (fwrite(buf, 1, size, obj->file) == size) { fflush(obj->file); } else { LOG_ERROR("Error writing to the SWO trace destination file"); return ERROR_FAIL; } } if (obj->out_filename && obj->out_filename[0] == ':') list_for_each_entry(c, &obj->connections, lh) if (connection_write(c->connection, buf, size) != (int)size) LOG_ERROR("Error writing to connection"); /* FIXME: which connection? */ return ERROR_OK; } static void arm_tpiu_swo_handle_event(struct arm_tpiu_swo_object *obj, enum arm_tpiu_swo_event event) { for (struct arm_tpiu_swo_event_action *ea = obj->event_action; ea; ea = ea->next) { if (ea->event != event) continue; LOG_DEBUG("TPIU/SWO: %s event: %s (%d) action : %s", obj->name, jim_nvp_value2name_simple(nvp_arm_tpiu_swo_event, event)->name, event, Jim_GetString(ea->body, NULL)); /* prevent event execution to change current target */ struct command_context *cmd_ctx = current_command_context(ea->interp); struct target *saved_target = cmd_ctx->current_target; int retval = Jim_EvalObj(ea->interp, ea->body); cmd_ctx->current_target = saved_target; if (retval == JIM_RETURN) retval = ea->interp->returnCode; if (retval == JIM_OK || retval == ERROR_COMMAND_CLOSE_CONNECTION) return; Jim_MakeErrorMessage(ea->interp); LOG_USER("Error executing event %s on TPIU/SWO %s:\n%s", jim_nvp_value2name_simple(nvp_arm_tpiu_swo_event, event)->name, obj->name, Jim_GetString(Jim_GetResult(ea->interp), NULL)); /* clean both error code and stacktrace before return */ Jim_Eval(ea->interp, "error \"\" \"\""); return; } } static void arm_tpiu_swo_close_output(struct arm_tpiu_swo_object *obj) { if (obj->file) { fclose(obj->file); obj->file = NULL; } if (obj->out_filename && obj->out_filename[0] == ':') remove_service(TCP_SERVICE_NAME, &obj->out_filename[1]); } int arm_tpiu_swo_cleanup_all(void) { struct arm_tpiu_swo_object *obj, *tmp; list_for_each_entry_safe(obj, tmp, &all_tpiu_swo, lh) { if (obj->enabled) arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE); arm_tpiu_swo_close_output(obj); if (obj->en_capture) { target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj); int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL); if (retval != ERROR_OK) LOG_ERROR("Failed to stop adapter's trace"); } if (obj->enabled) arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_DISABLE); struct arm_tpiu_swo_event_action *ea = obj->event_action; while (ea) { struct arm_tpiu_swo_event_action *next = ea->next; Jim_DecrRefCount(ea->interp, ea->body); free(ea); ea = next; } if (obj->ap) dap_put_ap(obj->ap); free(obj->name); free(obj->out_filename); free(obj); } return ERROR_OK; } static int arm_tpiu_swo_service_new_connection(struct connection *connection) { struct arm_tpiu_swo_priv_connection *priv = connection->service->priv; struct arm_tpiu_swo_object *obj = priv->obj; struct arm_tpiu_swo_connection *c = malloc(sizeof(*c)); if (!c) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } c->connection = connection; list_add(&c->lh, &obj->connections); return ERROR_OK; } static int arm_tpiu_swo_service_input(struct connection *connection) { /* read a dummy buffer to check if the connection is still active */ long dummy; int bytes_read = connection_read(connection, &dummy, sizeof(dummy)); if (bytes_read == 0) { return ERROR_SERVER_REMOTE_CLOSED; } else if (bytes_read == -1) { LOG_ERROR("error during read: %s", strerror(errno)); return ERROR_SERVER_REMOTE_CLOSED; } return ERROR_OK; } static int arm_tpiu_swo_service_connection_closed(struct connection *connection) { struct arm_tpiu_swo_priv_connection *priv = connection->service->priv; struct arm_tpiu_swo_object *obj = priv->obj; struct arm_tpiu_swo_connection *c, *tmp; list_for_each_entry_safe(c, tmp, &obj->connections, lh) if (c->connection == connection) { list_del(&c->lh); free(c); return ERROR_OK; } LOG_ERROR("Failed to find connection to close!"); return ERROR_FAIL; } COMMAND_HANDLER(handle_arm_tpiu_swo_event_list) { struct arm_tpiu_swo_object *obj = CMD_DATA; command_print(CMD, "Event actions for TPIU/SWO %s\n", obj->name); command_print(CMD, "%-25s | Body", "Event"); command_print(CMD, "------------------------- | " "----------------------------------------"); for (struct arm_tpiu_swo_event_action *ea = obj->event_action; ea; ea = ea->next) { struct jim_nvp *opt = jim_nvp_value2name_simple(nvp_arm_tpiu_swo_event, ea->event); command_print(CMD, "%-25s | %s", opt->name, Jim_GetString(ea->body, NULL)); } command_print(CMD, "***END***"); return ERROR_OK; } enum arm_tpiu_swo_cfg_param { CFG_PORT_WIDTH, CFG_PROTOCOL, CFG_FORMATTER, CFG_TRACECLKIN, CFG_BITRATE, CFG_OUTFILE, CFG_EVENT, }; static const struct jim_nvp nvp_arm_tpiu_swo_config_opts[] = { { .name = "-port-width", .value = CFG_PORT_WIDTH }, { .name = "-protocol", .value = CFG_PROTOCOL }, { .name = "-formatter", .value = CFG_FORMATTER }, { .name = "-traceclk", .value = CFG_TRACECLKIN }, { .name = "-pin-freq", .value = CFG_BITRATE }, { .name = "-output", .value = CFG_OUTFILE }, { .name = "-event", .value = CFG_EVENT }, /* handled by mem_ap_spot, added for jim_getopt_nvp_unknown() */ { .name = "-dap", .value = -1 }, { .name = "-ap-num", .value = -1 }, { .name = "-baseaddr", .value = -1 }, { .name = NULL, .value = -1 }, }; static const struct jim_nvp nvp_arm_tpiu_swo_protocol_opts[] = { { .name = "sync", .value = TPIU_SPPR_PROTOCOL_SYNC }, { .name = "uart", .value = TPIU_SPPR_PROTOCOL_UART }, { .name = "manchester", .value = TPIU_SPPR_PROTOCOL_MANCHESTER }, { .name = NULL, .value = -1 }, }; static const struct jim_nvp nvp_arm_tpiu_swo_bool_opts[] = { { .name = "on", .value = 1 }, { .name = "yes", .value = 1 }, { .name = "1", .value = 1 }, { .name = "true", .value = 1 }, { .name = "off", .value = 0 }, { .name = "no", .value = 0 }, { .name = "0", .value = 0 }, { .name = "false", .value = 0 }, { .name = NULL, .value = -1 }, }; static int arm_tpiu_swo_configure(struct jim_getopt_info *goi, struct arm_tpiu_swo_object *obj) { assert(obj); if (goi->isconfigure && obj->enabled) { Jim_SetResultFormatted(goi->interp, "Cannot configure TPIU/SWO; %s is enabled!", obj->name); return JIM_ERR; } /* parse config or cget options ... */ while (goi->argc > 0) { Jim_SetEmptyResult(goi->interp); int e = adiv5_jim_mem_ap_spot_configure(&obj->spot, goi); if (e == JIM_OK) continue; if (e == JIM_ERR) return e; struct jim_nvp *n; e = jim_getopt_nvp(goi, nvp_arm_tpiu_swo_config_opts, &n); if (e != JIM_OK) { jim_getopt_nvp_unknown(goi, nvp_arm_tpiu_swo_config_opts, 0); return e; } switch (n->value) { case CFG_PORT_WIDTH: if (goi->isconfigure) { jim_wide port_width; e = jim_getopt_wide(goi, &port_width); if (e != JIM_OK) return e; if (port_width < 1 || port_width > 32) { Jim_SetResultString(goi->interp, "Invalid port width!", -1); return JIM_ERR; } obj->port_width = (uint32_t)port_width; } else { if (goi->argc) goto err_no_params; Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->port_width)); } break; case CFG_PROTOCOL: if (goi->isconfigure) { struct jim_nvp *p; e = jim_getopt_nvp(goi, nvp_arm_tpiu_swo_protocol_opts, &p); if (e != JIM_OK) return e; obj->pin_protocol = p->value; } else { if (goi->argc) goto err_no_params; struct jim_nvp *p; e = jim_nvp_value2name(goi->interp, nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol, &p); if (e != JIM_OK) { Jim_SetResultString(goi->interp, "protocol error", -1); return JIM_ERR; } Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, p->name, -1)); } break; case CFG_FORMATTER: if (goi->isconfigure) { struct jim_nvp *p; e = jim_getopt_nvp(goi, nvp_arm_tpiu_swo_bool_opts, &p); if (e != JIM_OK) return e; obj->en_formatter = p->value; } else { if (goi->argc) goto err_no_params; struct jim_nvp *p; e = jim_nvp_value2name(goi->interp, nvp_arm_tpiu_swo_bool_opts, obj->en_formatter, &p); if (e != JIM_OK) { Jim_SetResultString(goi->interp, "formatter error", -1); return JIM_ERR; } Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, p->name, -1)); } break; case CFG_TRACECLKIN: if (goi->isconfigure) { jim_wide clk; e = jim_getopt_wide(goi, &clk); if (e != JIM_OK) return e; obj->traceclkin_freq = clk; } else { if (goi->argc) goto err_no_params; Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->traceclkin_freq)); } break; case CFG_BITRATE: if (goi->isconfigure) { jim_wide clk; e = jim_getopt_wide(goi, &clk); if (e != JIM_OK) return e; obj->swo_pin_freq = clk; } else { if (goi->argc) goto err_no_params; Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->swo_pin_freq)); } break; case CFG_OUTFILE: if (goi->isconfigure) { const char *s; e = jim_getopt_string(goi, &s, NULL); if (e != JIM_OK) return e; if (s[0] == ':') { char *end; long port = strtol(s + 1, &end, 0); if (port <= 0 || port > UINT16_MAX || *end != '\0') { Jim_SetResultFormatted(goi->interp, "Invalid TCP port \'%s\'", s + 1); return JIM_ERR; } } free(obj->out_filename); obj->out_filename = strdup(s); if (!obj->out_filename) { LOG_ERROR("Out of memory"); return JIM_ERR; } } else { if (goi->argc) goto err_no_params; if (obj->out_filename) Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, obj->out_filename, -1)); } break; case CFG_EVENT: if (goi->isconfigure) { if (goi->argc < 2) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?"); return JIM_ERR; } } else { if (goi->argc != 1) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?"); return JIM_ERR; } } { struct jim_nvp *p; Jim_Obj *o; struct arm_tpiu_swo_event_action *ea = obj->event_action; e = jim_getopt_nvp(goi, nvp_arm_tpiu_swo_event, &p); if (e != JIM_OK) { jim_getopt_nvp_unknown(goi, nvp_arm_tpiu_swo_event, 1); return e; } while (ea) { /* replace existing? */ if (ea->event == (enum arm_tpiu_swo_event)p->value) break; ea = ea->next; } if (goi->isconfigure) { if (!ea) { ea = calloc(1, sizeof(*ea)); if (!ea) { LOG_ERROR("Out of memory"); return JIM_ERR; } ea->next = obj->event_action; obj->event_action = ea; } if (ea->body) Jim_DecrRefCount(ea->interp, ea->body); ea->event = p->value; ea->interp = goi->interp; jim_getopt_obj(goi, &o); ea->body = Jim_DuplicateObj(goi->interp, o); Jim_IncrRefCount(ea->body); } else { if (ea) Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, ea->body)); } } break; } } return JIM_OK; err_no_params: Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); return JIM_ERR; } static int jim_arm_tpiu_swo_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { struct command *c = jim_to_command(interp); struct jim_getopt_info goi; jim_getopt_setup(&goi, interp, argc - 1, argv + 1); goi.isconfigure = !strcmp(c->name, "configure"); if (goi.argc < 1) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "missing: -option ..."); return JIM_ERR; } struct arm_tpiu_swo_object *obj = c->jim_handler_data; return arm_tpiu_swo_configure(&goi, obj); } static int wrap_write_u32(struct target *target, struct adiv5_ap *tpiu_ap, target_addr_t address, uint32_t value) { if (transport_is_hla()) return target_write_u32(target, address, value); else return mem_ap_write_atomic_u32(tpiu_ap, address, value); } static int wrap_read_u32(struct target *target, struct adiv5_ap *tpiu_ap, target_addr_t address, uint32_t *value) { if (transport_is_hla()) return target_read_u32(target, address, value); else return mem_ap_read_atomic_u32(tpiu_ap, address, value); } static const struct service_driver arm_tpiu_swo_service_driver = { .name = "tpiu_swo_trace", .new_connection_during_keep_alive_handler = NULL, .new_connection_handler = arm_tpiu_swo_service_new_connection, .input_handler = arm_tpiu_swo_service_input, .connection_closed_handler = arm_tpiu_swo_service_connection_closed, .keep_client_alive_handler = NULL, }; COMMAND_HANDLER(handle_arm_tpiu_swo_enable) { struct arm_tpiu_swo_object *obj = CMD_DATA; uint32_t value; int retval; if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_CTX->mode == COMMAND_CONFIG) { LOG_DEBUG("%s: enable deferred", obj->name); obj->deferred_enable = true; return ERROR_OK; } if (obj->enabled) return ERROR_OK; if (transport_is_hla() && obj->spot.ap_num != 0) { command_print(CMD, "Invalid access port 0x%" PRIx64 ". Only AP#0 allowed with hla transport", obj->spot.ap_num); return ERROR_FAIL; } if (!obj->traceclkin_freq) { command_print(CMD, "Trace clock-in frequency not set"); return ERROR_FAIL; } if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) if (!obj->swo_pin_freq) LOG_DEBUG("SWO pin frequency not set, will be autodetected by the adapter"); struct target *target = get_current_target(CMD_CTX); /* START_DEPRECATED_TPIU */ if (obj->recheck_ap_cur_target) { if (strcmp(target->type->name, "cortex_m") && strcmp(target->type->name, "hla_target")) { LOG_ERROR(MSG "Current target is not a Cortex-M nor a HLA"); return ERROR_FAIL; } if (!target_was_examined(target)) { LOG_ERROR(MSG "Current target not examined yet"); return ERROR_FAIL; } struct cortex_m_common *cm = target_to_cm(target); obj->recheck_ap_cur_target = false; obj->spot.ap_num = cm->armv7m.debug_ap->ap_num; if (obj->spot.ap_num == 0) LOG_INFO(MSG "Confirmed TPIU %s is on AP 0", obj->name); else LOG_INFO(MSG "Target %s is on AP#0x%" PRIx64 ". Revised command is " "\'tpiu create %s -dap %s -ap-num 0x%" PRIx64 "\'", target_name(target), obj->spot.ap_num, obj->name, adiv5_dap_name(obj->spot.dap), obj->spot.ap_num); } /* END_DEPRECATED_TPIU */ if (!obj->ap) { obj->ap = dap_get_ap(obj->spot.dap, obj->spot.ap_num); if (!obj->ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; } } /* trigger the event before any attempt to R/W in the TPIU/SWO */ arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_ENABLE); retval = wrap_read_u32(target, obj->ap, obj->spot.base + TPIU_DEVID_OFFSET, &value); if (retval != ERROR_OK) { command_print(CMD, "Unable to read %s", obj->name); return retval; } switch (obj->pin_protocol) { case TPIU_SPPR_PROTOCOL_SYNC: value = !(value & TPIU_DEVID_NOSUPPORT_SYNC); break; case TPIU_SPPR_PROTOCOL_UART: value &= TPIU_DEVID_SUPPORT_UART; break; case TPIU_SPPR_PROTOCOL_MANCHESTER: value &= TPIU_DEVID_SUPPORT_MANCHESTER; break; default: value = 0; } if (!value) { struct jim_nvp *p = jim_nvp_value2name_simple(nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol); command_print(CMD, "%s does not support protocol %s", obj->name, p->name); return ERROR_FAIL; } if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_SYNC) { retval = wrap_read_u32(target, obj->ap, obj->spot.base + TPIU_SSPSR_OFFSET, &value); if (retval != ERROR_OK) { command_print(CMD, "Cannot read TPIU register SSPSR"); return retval; } if (!(value & BIT(obj->port_width - 1))) { command_print(CMD, "TPIU does not support port-width of %d bits", obj->port_width); return ERROR_FAIL; } } uint16_t prescaler = 1; /* dummy value */ unsigned int swo_pin_freq = obj->swo_pin_freq; /* could be replaced */ if (obj->out_filename && strcmp(obj->out_filename, "external") && obj->out_filename[0]) { if (obj->out_filename[0] == ':') { struct arm_tpiu_swo_priv_connection *priv = malloc(sizeof(*priv)); if (!priv) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } priv->obj = obj; LOG_INFO("starting trace server for %s on %s", obj->name, &obj->out_filename[1]); retval = add_service(&arm_tpiu_swo_service_driver, &obj->out_filename[1], CONNECTION_LIMIT_UNLIMITED, priv); if (retval != ERROR_OK) { command_print(CMD, "Can't configure trace TCP port %s", &obj->out_filename[1]); return retval; } } else if (strcmp(obj->out_filename, "-")) { obj->file = fopen(obj->out_filename, "ab"); if (!obj->file) { command_print(CMD, "Can't open trace destination file \"%s\"", obj->out_filename); return ERROR_FAIL; } } retval = adapter_config_trace(true, obj->pin_protocol, obj->port_width, &swo_pin_freq, obj->traceclkin_freq, &prescaler); if (retval != ERROR_OK) { command_print(CMD, "Failed to start adapter's trace"); arm_tpiu_swo_close_output(obj); return retval; } if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) if (!swo_pin_freq) { if (obj->swo_pin_freq) command_print(CMD, "Adapter rejected SWO pin frequency %d Hz", obj->swo_pin_freq); else command_print(CMD, "Adapter does not support auto-detection of SWO pin frequency nor a default value"); arm_tpiu_swo_close_output(obj); return ERROR_FAIL; } if (obj->swo_pin_freq != swo_pin_freq) LOG_INFO("SWO pin data rate adjusted by adapter to %d Hz", swo_pin_freq); obj->swo_pin_freq = swo_pin_freq; target_register_timer_callback(arm_tpiu_swo_poll_trace, 1, TARGET_TIMER_TYPE_PERIODIC, obj); obj->en_capture = true; } else if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) { prescaler = (obj->traceclkin_freq + obj->swo_pin_freq / 2) / obj->swo_pin_freq; if (prescaler > TPIU_ACPR_MAX_PRESCALER) prescaler = TPIU_ACPR_MAX_PRESCALER; swo_pin_freq = obj->traceclkin_freq / prescaler; if (obj->swo_pin_freq != swo_pin_freq) LOG_INFO("SWO pin data rate adjusted to %d Hz", swo_pin_freq); obj->swo_pin_freq = swo_pin_freq; } retval = wrap_write_u32(target, obj->ap, obj->spot.base + TPIU_CSPSR_OFFSET, BIT(obj->port_width - 1)); if (retval != ERROR_OK) goto error_exit; retval = wrap_write_u32(target, obj->ap, obj->spot.base + TPIU_ACPR_OFFSET, prescaler - 1); if (retval != ERROR_OK) goto error_exit; retval = wrap_write_u32(target, obj->ap, obj->spot.base + TPIU_SPPR_OFFSET, obj->pin_protocol); if (retval != ERROR_OK) goto error_exit; retval = wrap_read_u32(target, obj->ap, obj->spot.base + TPIU_FFCR_OFFSET, &value); if (retval != ERROR_OK) goto error_exit; if (obj->en_formatter) value |= BIT(1); else value &= ~BIT(1); retval = wrap_write_u32(target, obj->ap, obj->spot.base + TPIU_FFCR_OFFSET, value); if (retval != ERROR_OK) goto error_exit; arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_ENABLE); /* START_DEPRECATED_TPIU */ target_handle_event(target, TARGET_EVENT_TRACE_CONFIG); /* END_DEPRECATED_TPIU */ obj->enabled = true; return ERROR_OK; error_exit: command_print(CMD, "Error!"); if (obj->en_capture) { obj->en_capture = false; arm_tpiu_swo_close_output(obj); target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj); int retval1 = adapter_config_trace(false, 0, 0, NULL, 0, NULL); if (retval1 != ERROR_OK) command_print(CMD, "Failed to stop adapter's trace"); } return retval; } COMMAND_HANDLER(handle_arm_tpiu_swo_disable) { struct arm_tpiu_swo_object *obj = CMD_DATA; if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (!obj->enabled) return ERROR_OK; obj->enabled = false; arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE); if (obj->en_capture) { obj->en_capture = false; arm_tpiu_swo_close_output(obj); target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj); int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL); if (retval != ERROR_OK) { command_print(CMD, "Failed to stop adapter's trace"); return retval; } } arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_DISABLE); /* START_DEPRECATED_TPIU */ struct target *target = get_current_target(CMD_CTX); target_handle_event(target, TARGET_EVENT_TRACE_CONFIG); /* END_DEPRECATED_TPIU */ return ERROR_OK; } static const struct command_registration arm_tpiu_swo_instance_command_handlers[] = { { .name = "configure", .mode = COMMAND_ANY, .jim_handler = jim_arm_tpiu_swo_configure, .help = "configure a new TPIU/SWO for use", .usage = "[attribute value ...]", }, { .name = "cget", .mode = COMMAND_ANY, .jim_handler = jim_arm_tpiu_swo_configure, .help = "returns the specified TPIU/SWO attribute", .usage = "attribute", }, { .name = "eventlist", .mode = COMMAND_ANY, .handler = handle_arm_tpiu_swo_event_list, .help = "displays a table of events defined for this TPIU/SWO", .usage = "", }, { .name = "enable", .mode = COMMAND_ANY, .handler = handle_arm_tpiu_swo_enable, .usage = "", .help = "Enables the TPIU/SWO output", }, { .name = "disable", .mode = COMMAND_EXEC, .handler = handle_arm_tpiu_swo_disable, .usage = "", .help = "Disables the TPIU/SWO output", }, COMMAND_REGISTRATION_DONE }; static int arm_tpiu_swo_create(Jim_Interp *interp, struct arm_tpiu_swo_object *obj) { struct command_context *cmd_ctx; Jim_Cmd *cmd; int e; cmd_ctx = current_command_context(interp); assert(cmd_ctx); /* does this command exist? */ cmd = Jim_GetCommand(interp, Jim_NewStringObj(interp, obj->name, -1), JIM_NONE); if (cmd) { Jim_SetResultFormatted(interp, "cannot create TPIU object because a command with name '%s' already exists", obj->name); return JIM_ERR; } /* now - create the new tpiu/swo name command */ const struct command_registration obj_commands[] = { { .name = obj->name, .mode = COMMAND_ANY, .help = "tpiu/swo instance command group", .usage = "", .chain = arm_tpiu_swo_instance_command_handlers, }, COMMAND_REGISTRATION_DONE }; e = register_commands_with_data(cmd_ctx, NULL, obj_commands, obj); if (e != ERROR_OK) return JIM_ERR; list_add_tail(&obj->lh, &all_tpiu_swo); return JIM_OK; } static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct jim_getopt_info goi; jim_getopt_setup(&goi, interp, argc - 1, argv + 1); if (goi.argc < 1) { Jim_WrongNumArgs(interp, 1, argv, "name ?option option ...?"); return JIM_ERR; } struct arm_tpiu_swo_object *obj = calloc(1, sizeof(struct arm_tpiu_swo_object)); if (!obj) { LOG_ERROR("Out of memory"); return JIM_ERR; } INIT_LIST_HEAD(&obj->connections); adiv5_mem_ap_spot_init(&obj->spot); obj->spot.base = TPIU_SWO_DEFAULT_BASE; obj->port_width = 1; Jim_Obj *n; jim_getopt_obj(&goi, &n); obj->name = strdup(Jim_GetString(n, NULL)); if (!obj->name) { LOG_ERROR("Out of memory"); free(obj); return JIM_ERR; } /* Do the rest as "configure" options */ goi.isconfigure = 1; int e = arm_tpiu_swo_configure(&goi, obj); if (e != JIM_OK) goto err_exit; if (!obj->spot.dap || obj->spot.ap_num == DP_APSEL_INVALID) { Jim_SetResultString(goi.interp, "-dap and -ap-num required when creating TPIU", -1); goto err_exit; } e = arm_tpiu_swo_create(goi.interp, obj); if (e != JIM_OK) goto err_exit; return JIM_OK; err_exit: free(obj->name); free(obj->out_filename); free(obj); return JIM_ERR; } COMMAND_HANDLER(handle_arm_tpiu_swo_names) { struct arm_tpiu_swo_object *obj; if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; list_for_each_entry(obj, &all_tpiu_swo, lh) command_print(CMD, "%s", obj->name); return ERROR_OK; } COMMAND_HANDLER(handle_arm_tpiu_swo_init) { struct arm_tpiu_swo_object *obj; int retval = ERROR_OK; if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; list_for_each_entry(obj, &all_tpiu_swo, lh) { if (!obj->deferred_enable) continue; LOG_DEBUG("%s: running enable during init", obj->name); int retval2 = command_run_linef(CMD_CTX, "%s enable", obj->name); if (retval2 != ERROR_OK) retval = retval2; } return retval; } /* START_DEPRECATED_TPIU */ /* DEPRECATED: emulation of old command 'tpiu config' */ COMMAND_HANDLER(handle_tpiu_deprecated_config_command) { struct target *target = get_current_target(CMD_CTX); struct arm_tpiu_swo_object *obj = NULL; int retval; if (strcmp(target->type->name, "cortex_m") && strcmp(target->type->name, "hla_target")) { LOG_ERROR(MSG "Current target is not a Cortex-M nor a HLA"); return ERROR_FAIL; } if (!list_empty(&all_tpiu_swo)) { obj = list_first_entry(&all_tpiu_swo, typeof(*obj), lh); LOG_INFO(MSG "Using %s", obj->name); } else { struct cortex_m_common *cm = target_to_cm(target); struct adiv5_private_config *pc = target->private_config; struct adiv5_dap *dap = pc->dap; uint64_t ap_num = pc->ap_num; bool set_recheck_ap_cur_target = false; LOG_INFO(MSG "Adding a TPIU \'%s.tpiu\' in the configuration", target_name(target)); if (ap_num == DP_APSEL_INVALID && transport_is_hla()) ap_num = 0; /* HLA should only support AP 0 */ if (ap_num == DP_APSEL_INVALID && target_was_examined(target)) ap_num = cm->armv7m.debug_ap->ap_num; if (ap_num == DP_APSEL_INVALID) { LOG_INFO(MSG "Target %s uses AP autodetection. Adding TPIU on AP 0; can be revised later", target_name(target)); ap_num = 0; set_recheck_ap_cur_target = true; } LOG_INFO(MSG "Running: \'tpiu create %s.tpiu -dap %s -ap-num 0x%" PRIx64 "\'", target_name(target), adiv5_dap_name(dap), ap_num); retval = command_run_linef(CMD_CTX, "tpiu create %s.tpiu -dap %s -ap-num 0x%" PRIx64, target_name(target), adiv5_dap_name(dap), ap_num); if (retval != ERROR_OK) return retval; obj = list_first_entry(&all_tpiu_swo, typeof(*obj), lh); if (set_recheck_ap_cur_target) obj->recheck_ap_cur_target = true; } unsigned int cmd_idx = 0; if (cmd_idx == CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; if (!strcmp(CMD_ARGV[cmd_idx], "disable")) { if (CMD_ARGC != cmd_idx + 1) return ERROR_COMMAND_SYNTAX_ERROR; LOG_INFO(MSG "Running: \'%s disable\'", obj->name); return command_run_linef(CMD_CTX, "%s disable", obj->name); } const char *output = NULL; const char *protocol; const char *formatter = NULL; const char *port_width = NULL; const char *trace_clk; const char *pin_clk = NULL; if (!strcmp(CMD_ARGV[cmd_idx], "internal")) { cmd_idx++; if (cmd_idx == CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; output = CMD_ARGV[cmd_idx]; } else if (strcmp(CMD_ARGV[cmd_idx], "external")) return ERROR_COMMAND_SYNTAX_ERROR; cmd_idx++; if (cmd_idx == CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; if (!strcmp(CMD_ARGV[cmd_idx], "sync")) { protocol = CMD_ARGV[cmd_idx]; cmd_idx++; if (cmd_idx == CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; port_width = CMD_ARGV[cmd_idx]; } else { if (strcmp(CMD_ARGV[cmd_idx], "manchester") && strcmp(CMD_ARGV[cmd_idx], "uart")) return ERROR_COMMAND_SYNTAX_ERROR; protocol = CMD_ARGV[cmd_idx]; cmd_idx++; if (cmd_idx == CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; formatter = CMD_ARGV[cmd_idx]; } cmd_idx++; if (cmd_idx == CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; trace_clk = CMD_ARGV[cmd_idx]; cmd_idx++; if (cmd_idx != CMD_ARGC) { pin_clk = CMD_ARGV[cmd_idx]; cmd_idx++; } if (cmd_idx != CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; LOG_INFO(MSG "Running: \'%s configure -protocol %s -traceclk %s" "%s%s" "%s%s" "%s%s" "%s%s\'", obj->name, protocol, trace_clk, pin_clk ? " -pin-freq " : "", pin_clk ? pin_clk : "", output ? " -output " : "", output ? output : "", formatter ? " -formatter " : "", formatter ? formatter : "", port_width ? " -port-width " : "", port_width ? port_width : ""); retval = command_run_linef(CMD_CTX, "%s configure -protocol %s -traceclk %s" "%s%s" "%s%s" "%s%s" "%s%s", obj->name, protocol, trace_clk, pin_clk ? " -pin-freq " : "", pin_clk ? pin_clk : "", output ? " -output " : "", output ? output : "", formatter ? " -formatter " : "", formatter ? formatter : "", port_width ? " -port-width " : "", port_width ? port_width : ""); if (retval != ERROR_OK) return retval; LOG_INFO(MSG "Running: \'%s enable\'", obj->name); retval = command_run_linef(CMD_CTX, "%s enable", obj->name); if (retval != ERROR_OK) return retval; return ERROR_OK; } static const struct command_registration arm_tpiu_deprecated_subcommand_handlers[] = { { .name = "config", .handler = handle_tpiu_deprecated_config_command, .mode = COMMAND_ANY, .help = "Configure TPIU features, DEPRECATED, use \'tpiu create\'", .usage = "(disable | " "((external | internal (<filename> | <:port> | -)) " "(sync <port width> | ((manchester | uart) <formatter enable>)) " "<TRACECLKIN freq> [<trace freq>]))", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm_tpiu_deprecated_command_handlers[] = { { .name = "tpiu", .chain = arm_tpiu_deprecated_subcommand_handlers, .usage = "", .help = "tpiu command group", }, COMMAND_REGISTRATION_DONE }; /* END_DEPRECATED_TPIU */ static const struct command_registration arm_tpiu_swo_subcommand_handlers[] = { { .name = "create", .mode = COMMAND_ANY, .jim_handler = jim_arm_tpiu_swo_create, .usage = "name [-dap dap] [-ap-num num] [-baseaddr baseaddr]", .help = "Creates a new TPIU or SWO object", }, { .name = "names", .mode = COMMAND_ANY, .handler = handle_arm_tpiu_swo_names, .usage = "", .help = "Lists all registered TPIU and SWO objects by name", }, { .name = "init", .mode = COMMAND_EXEC, .handler = handle_arm_tpiu_swo_init, .usage = "", .help = "Initialize TPIU and SWO", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration arm_tpiu_swo_command_handlers[] = { { .name = "tpiu", .chain = arm_tpiu_swo_subcommand_handlers, .usage = "", .help = "tpiu command group", }, { .name = "swo", .chain = arm_tpiu_swo_subcommand_handlers, .usage = "", .help = "swo command group", }, COMMAND_REGISTRATION_DONE }; int arm_tpiu_swo_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, arm_tpiu_swo_command_handlers); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/arm_tpiu_swo.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef OPENOCD_TARGET_ARM_TPIU_SWO_H #define OPENOCD_TARGET_ARM_TPIU_SWO_H /* Values should match TPIU_SPPR_PROTOCOL_xxx */ enum tpiu_pin_protocol { TPIU_PIN_PROTOCOL_SYNC = 0, /**< synchronous trace output */ TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER = 1, /**< asynchronous output with Manchester coding */ TPIU_PIN_PROTOCOL_ASYNC_UART = 2, /**< asynchronous output with NRZ coding */ }; /* START_DEPRECATED_TPIU */ /* DEPRECATED: emulation of old command 'tpiu config' */ extern const struct command_registration arm_tpiu_deprecated_command_handlers[]; /* END_DEPRECATED_TPIU */ int arm_tpiu_swo_register_commands(struct command_context *cmd_ctx); int arm_tpiu_swo_cleanup_all(void); #endif /* OPENOCD_TARGET_ARM_TPIU_SWO_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv4_5.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by Oyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2018 by Liviu Ionescu * * <ilg@livius.net> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "armv4_5.h" #include "arm_jtag.h" #include "breakpoints.h" #include "arm_disassembler.h" #include <helper/binarybuffer.h> #include "algorithm.h" #include "register.h" #include "semihosting_common.h" /* offsets into armv4_5 core register cache */ enum { /* ARMV4_5_CPSR = 31, */ ARMV4_5_SPSR_FIQ = 32, ARMV4_5_SPSR_IRQ = 33, ARMV4_5_SPSR_SVC = 34, ARMV4_5_SPSR_ABT = 35, ARMV4_5_SPSR_UND = 36, ARM_SPSR_MON = 41, ARM_SPSR_HYP = 43, }; static const uint8_t arm_usr_indices[17] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ARMV4_5_CPSR, }; static const uint8_t arm_fiq_indices[8] = { 16, 17, 18, 19, 20, 21, 22, ARMV4_5_SPSR_FIQ, }; static const uint8_t arm_irq_indices[3] = { 23, 24, ARMV4_5_SPSR_IRQ, }; static const uint8_t arm_svc_indices[3] = { 25, 26, ARMV4_5_SPSR_SVC, }; static const uint8_t arm_abt_indices[3] = { 27, 28, ARMV4_5_SPSR_ABT, }; static const uint8_t arm_und_indices[3] = { 29, 30, ARMV4_5_SPSR_UND, }; static const uint8_t arm_mon_indices[3] = { 39, 40, ARM_SPSR_MON, }; static const uint8_t arm_hyp_indices[2] = { 42, ARM_SPSR_HYP, }; static const struct { const char *name; unsigned short psr; /* For user and system modes, these list indices for all registers. * otherwise they're just indices for the shadow registers and SPSR. */ unsigned short n_indices; const uint8_t *indices; } arm_mode_data[] = { /* Seven modes are standard from ARM7 on. "System" and "User" share * the same registers; other modes shadow from 3 to 8 registers. */ { .name = "User", .psr = ARM_MODE_USR, .n_indices = ARRAY_SIZE(arm_usr_indices), .indices = arm_usr_indices, }, { .name = "FIQ", .psr = ARM_MODE_FIQ, .n_indices = ARRAY_SIZE(arm_fiq_indices), .indices = arm_fiq_indices, }, { .name = "Supervisor", .psr = ARM_MODE_SVC, .n_indices = ARRAY_SIZE(arm_svc_indices), .indices = arm_svc_indices, }, { .name = "Abort", .psr = ARM_MODE_ABT, .n_indices = ARRAY_SIZE(arm_abt_indices), .indices = arm_abt_indices, }, { .name = "IRQ", .psr = ARM_MODE_IRQ, .n_indices = ARRAY_SIZE(arm_irq_indices), .indices = arm_irq_indices, }, { .name = "Undefined instruction", .psr = ARM_MODE_UND, .n_indices = ARRAY_SIZE(arm_und_indices), .indices = arm_und_indices, }, { .name = "System", .psr = ARM_MODE_SYS, .n_indices = ARRAY_SIZE(arm_usr_indices), .indices = arm_usr_indices, }, /* TrustZone "Security Extensions" add a secure monitor mode. * This is distinct from a "debug monitor" which can support * non-halting debug, in conjunction with some debuggers. */ { .name = "Secure Monitor", .psr = ARM_MODE_MON, .n_indices = ARRAY_SIZE(arm_mon_indices), .indices = arm_mon_indices, }, { .name = "Secure Monitor ARM1176JZF-S", .psr = ARM_MODE_1176_MON, .n_indices = ARRAY_SIZE(arm_mon_indices), .indices = arm_mon_indices, }, /* These special modes are currently only supported * by ARMv6M and ARMv7M profiles */ { .name = "Thread", .psr = ARM_MODE_THREAD, }, { .name = "Thread (User)", .psr = ARM_MODE_USER_THREAD, }, { .name = "Handler", .psr = ARM_MODE_HANDLER, }, /* armv7-a with virtualization extension */ { .name = "Hypervisor", .psr = ARM_MODE_HYP, .n_indices = ARRAY_SIZE(arm_hyp_indices), .indices = arm_hyp_indices, }, }; /** Map PSR mode bits to the name of an ARM processor operating mode. */ const char *arm_mode_name(unsigned psr_mode) { for (unsigned i = 0; i < ARRAY_SIZE(arm_mode_data); i++) { if (arm_mode_data[i].psr == psr_mode) return arm_mode_data[i].name; } LOG_ERROR("unrecognized psr mode: %#02x", psr_mode); return "UNRECOGNIZED"; } /** Return true iff the parameter denotes a valid ARM processor mode. */ bool is_arm_mode(unsigned psr_mode) { for (unsigned i = 0; i < ARRAY_SIZE(arm_mode_data); i++) { if (arm_mode_data[i].psr == psr_mode) return true; } return false; } /** Map PSR mode bits to linear number indexing armv4_5_core_reg_map */ int arm_mode_to_number(enum arm_mode mode) { switch (mode) { case ARM_MODE_ANY: /* map MODE_ANY to user mode */ case ARM_MODE_USR: return 0; case ARM_MODE_FIQ: return 1; case ARM_MODE_IRQ: return 2; case ARM_MODE_SVC: return 3; case ARM_MODE_ABT: return 4; case ARM_MODE_UND: return 5; case ARM_MODE_SYS: return 6; case ARM_MODE_MON: case ARM_MODE_1176_MON: return 7; case ARM_MODE_HYP: return 8; default: LOG_ERROR("invalid mode value encountered %d", mode); return -1; } } /** Map linear number indexing armv4_5_core_reg_map to PSR mode bits. */ enum arm_mode armv4_5_number_to_mode(int number) { switch (number) { case 0: return ARM_MODE_USR; case 1: return ARM_MODE_FIQ; case 2: return ARM_MODE_IRQ; case 3: return ARM_MODE_SVC; case 4: return ARM_MODE_ABT; case 5: return ARM_MODE_UND; case 6: return ARM_MODE_SYS; case 7: return ARM_MODE_MON; case 8: return ARM_MODE_HYP; default: LOG_ERROR("mode index out of bounds %d", number); return ARM_MODE_ANY; } } static const char *arm_state_strings[] = { "ARM", "Thumb", "Jazelle", "ThumbEE", }; /* Templates for ARM core registers. * * NOTE: offsets in this table are coupled to the arm_mode_data * table above, the armv4_5_core_reg_map array below, and also to * the ARMV4_5_CPSR symbol (which should vanish after ARM11 updates). */ static const struct { /* The name is used for e.g. the "regs" command. */ const char *name; /* The {cookie, mode} tuple uniquely identifies one register. * In a given mode, cookies 0..15 map to registers R0..R15, * with R13..R15 usually called SP, LR, PC. * * MODE_ANY is used as *input* to the mapping, and indicates * various special cases (sigh) and errors. * * Cookie 16 is (currently) confusing, since it indicates * CPSR -or- SPSR depending on whether 'mode' is MODE_ANY. * (Exception modes have both CPSR and SPSR registers ...) */ unsigned cookie; unsigned gdb_index; enum arm_mode mode; } arm_core_regs[] = { /* IMPORTANT: we guarantee that the first eight cached registers * correspond to r0..r7, and the fifteenth to PC, so that callers * don't need to map them. */ [0] = { .name = "r0", .cookie = 0, .mode = ARM_MODE_ANY, .gdb_index = 0, }, [1] = { .name = "r1", .cookie = 1, .mode = ARM_MODE_ANY, .gdb_index = 1, }, [2] = { .name = "r2", .cookie = 2, .mode = ARM_MODE_ANY, .gdb_index = 2, }, [3] = { .name = "r3", .cookie = 3, .mode = ARM_MODE_ANY, .gdb_index = 3, }, [4] = { .name = "r4", .cookie = 4, .mode = ARM_MODE_ANY, .gdb_index = 4, }, [5] = { .name = "r5", .cookie = 5, .mode = ARM_MODE_ANY, .gdb_index = 5, }, [6] = { .name = "r6", .cookie = 6, .mode = ARM_MODE_ANY, .gdb_index = 6, }, [7] = { .name = "r7", .cookie = 7, .mode = ARM_MODE_ANY, .gdb_index = 7, }, /* NOTE: regs 8..12 might be shadowed by FIQ ... flagging * them as MODE_ANY creates special cases. (ANY means * "not mapped" elsewhere; here it's "everything but FIQ".) */ [8] = { .name = "r8", .cookie = 8, .mode = ARM_MODE_ANY, .gdb_index = 8, }, [9] = { .name = "r9", .cookie = 9, .mode = ARM_MODE_ANY, .gdb_index = 9, }, [10] = { .name = "r10", .cookie = 10, .mode = ARM_MODE_ANY, .gdb_index = 10, }, [11] = { .name = "r11", .cookie = 11, .mode = ARM_MODE_ANY, .gdb_index = 11, }, [12] = { .name = "r12", .cookie = 12, .mode = ARM_MODE_ANY, .gdb_index = 12, }, /* Historical GDB mapping of indices: * - 13-14 are sp and lr, but banked counterparts are used * - 16-24 are left for deprecated 8 FPA + 1 FPS * - 25 is the cpsr */ /* NOTE all MODE_USR registers are equivalent to MODE_SYS ones */ [13] = { .name = "sp_usr", .cookie = 13, .mode = ARM_MODE_USR, .gdb_index = 26, }, [14] = { .name = "lr_usr", .cookie = 14, .mode = ARM_MODE_USR, .gdb_index = 27, }, /* guaranteed to be at index 15 */ [15] = { .name = "pc", .cookie = 15, .mode = ARM_MODE_ANY, .gdb_index = 15, }, [16] = { .name = "r8_fiq", .cookie = 8, .mode = ARM_MODE_FIQ, .gdb_index = 28, }, [17] = { .name = "r9_fiq", .cookie = 9, .mode = ARM_MODE_FIQ, .gdb_index = 29, }, [18] = { .name = "r10_fiq", .cookie = 10, .mode = ARM_MODE_FIQ, .gdb_index = 30, }, [19] = { .name = "r11_fiq", .cookie = 11, .mode = ARM_MODE_FIQ, .gdb_index = 31, }, [20] = { .name = "r12_fiq", .cookie = 12, .mode = ARM_MODE_FIQ, .gdb_index = 32, }, [21] = { .name = "sp_fiq", .cookie = 13, .mode = ARM_MODE_FIQ, .gdb_index = 33, }, [22] = { .name = "lr_fiq", .cookie = 14, .mode = ARM_MODE_FIQ, .gdb_index = 34, }, [23] = { .name = "sp_irq", .cookie = 13, .mode = ARM_MODE_IRQ, .gdb_index = 35, }, [24] = { .name = "lr_irq", .cookie = 14, .mode = ARM_MODE_IRQ, .gdb_index = 36, }, [25] = { .name = "sp_svc", .cookie = 13, .mode = ARM_MODE_SVC, .gdb_index = 37, }, [26] = { .name = "lr_svc", .cookie = 14, .mode = ARM_MODE_SVC, .gdb_index = 38, }, [27] = { .name = "sp_abt", .cookie = 13, .mode = ARM_MODE_ABT, .gdb_index = 39, }, [28] = { .name = "lr_abt", .cookie = 14, .mode = ARM_MODE_ABT, .gdb_index = 40, }, [29] = { .name = "sp_und", .cookie = 13, .mode = ARM_MODE_UND, .gdb_index = 41, }, [30] = { .name = "lr_und", .cookie = 14, .mode = ARM_MODE_UND, .gdb_index = 42, }, [31] = { .name = "cpsr", .cookie = 16, .mode = ARM_MODE_ANY, .gdb_index = 25, }, [32] = { .name = "spsr_fiq", .cookie = 16, .mode = ARM_MODE_FIQ, .gdb_index = 43, }, [33] = { .name = "spsr_irq", .cookie = 16, .mode = ARM_MODE_IRQ, .gdb_index = 44, }, [34] = { .name = "spsr_svc", .cookie = 16, .mode = ARM_MODE_SVC, .gdb_index = 45, }, [35] = { .name = "spsr_abt", .cookie = 16, .mode = ARM_MODE_ABT, .gdb_index = 46, }, [36] = { .name = "spsr_und", .cookie = 16, .mode = ARM_MODE_UND, .gdb_index = 47, }, /* These are only used for GDB target description, banked registers are accessed instead */ [37] = { .name = "sp", .cookie = 13, .mode = ARM_MODE_ANY, .gdb_index = 13, }, [38] = { .name = "lr", .cookie = 14, .mode = ARM_MODE_ANY, .gdb_index = 14, }, /* These exist only when the Security Extension (TrustZone) is present */ [39] = { .name = "sp_mon", .cookie = 13, .mode = ARM_MODE_MON, .gdb_index = 48, }, [40] = { .name = "lr_mon", .cookie = 14, .mode = ARM_MODE_MON, .gdb_index = 49, }, [41] = { .name = "spsr_mon", .cookie = 16, .mode = ARM_MODE_MON, .gdb_index = 50, }, /* These exist only when the Virtualization Extensions is present */ [42] = { .name = "sp_hyp", .cookie = 13, .mode = ARM_MODE_HYP, .gdb_index = 51, }, [43] = { .name = "spsr_hyp", .cookie = 16, .mode = ARM_MODE_HYP, .gdb_index = 52, }, }; static const struct { unsigned int id; const char *name; uint32_t bits; enum arm_mode mode; enum reg_type type; const char *group; const char *feature; } arm_vfp_v3_regs[] = { { ARM_VFP_V3_D0, "d0", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D1, "d1", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D2, "d2", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D3, "d3", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D4, "d4", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D5, "d5", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D6, "d6", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D7, "d7", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D8, "d8", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D9, "d9", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D10, "d10", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D11, "d11", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D12, "d12", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D13, "d13", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D14, "d14", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D15, "d15", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D16, "d16", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D17, "d17", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D18, "d18", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D19, "d19", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D20, "d20", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D21, "d21", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D22, "d22", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D23, "d23", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D24, "d24", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D25, "d25", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D26, "d26", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D27, "d27", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D28, "d28", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D29, "d29", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D30, "d30", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_D31, "d31", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARM_VFP_V3_FPSCR, "fpscr", 32, ARM_MODE_ANY, REG_TYPE_INT, "float", "org.gnu.gdb.arm.vfp"}, }; /* map core mode (USR, FIQ, ...) and register number to * indices into the register cache */ const int armv4_5_core_reg_map[9][17] = { { /* USR */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31 }, { /* FIQ (8 shadows of USR, vs normal 3) */ 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 15, 32 }, { /* IRQ */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 23, 24, 15, 33 }, { /* SVC */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 25, 26, 15, 34 }, { /* ABT */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 27, 28, 15, 35 }, { /* UND */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 29, 30, 15, 36 }, { /* SYS (same registers as USR) */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31 }, { /* MON */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 39, 40, 15, 41, }, { /* HYP */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 42, 14, 15, 43, } }; /** * Configures host-side ARM records to reflect the specified CPSR. * Later, code can use arm_reg_current() to map register numbers * according to how they are exposed by this mode. */ void arm_set_cpsr(struct arm *arm, uint32_t cpsr) { enum arm_mode mode = cpsr & 0x1f; int num; /* NOTE: this may be called very early, before the register * cache is set up. We can't defend against many errors, in * particular against CPSRs that aren't valid *here* ... */ if (arm->cpsr) { buf_set_u32(arm->cpsr->value, 0, 32, cpsr); arm->cpsr->valid = true; arm->cpsr->dirty = false; } arm->core_mode = mode; /* mode_to_number() warned; set up a somewhat-sane mapping */ num = arm_mode_to_number(mode); if (num < 0) { mode = ARM_MODE_USR; num = 0; } arm->map = &armv4_5_core_reg_map[num][0]; arm->spsr = (mode == ARM_MODE_USR || mode == ARM_MODE_SYS) ? NULL : arm->core_cache->reg_list + arm->map[16]; /* Older ARMs won't have the J bit */ enum arm_state state; if (cpsr & (1 << 5)) { /* T */ if (cpsr & (1 << 24)) { /* J */ LOG_WARNING("ThumbEE -- incomplete support"); state = ARM_STATE_THUMB_EE; } else state = ARM_STATE_THUMB; } else { if (cpsr & (1 << 24)) { /* J */ LOG_ERROR("Jazelle state handling is BROKEN!"); state = ARM_STATE_JAZELLE; } else state = ARM_STATE_ARM; } arm->core_state = state; LOG_DEBUG("set CPSR %#8.8x: %s mode, %s state", (unsigned) cpsr, arm_mode_name(mode), arm_state_strings[arm->core_state]); } /** * Returns handle to the register currently mapped to a given number. * Someone must have called arm_set_cpsr() before. * * \param arm This core's state and registers are used. * \param regnum From 0..15 corresponding to R0..R14 and PC. * Note that R0..R7 don't require mapping; you may access those * as the first eight entries in the register cache. Likewise * R15 (PC) doesn't need mapping; you may also access it directly. * However, R8..R14, and SPSR (arm->spsr) *must* be mapped. * CPSR (arm->cpsr) is also not mapped. */ struct reg *arm_reg_current(struct arm *arm, unsigned regnum) { struct reg *r; if (regnum > 16) return NULL; if (!arm->map) { LOG_ERROR("Register map is not available yet, the target is not fully initialised"); r = arm->core_cache->reg_list + regnum; } else r = arm->core_cache->reg_list + arm->map[regnum]; /* e.g. invalid CPSR said "secure monitor" mode on a core * that doesn't support it... */ if (!r) { LOG_ERROR("Invalid CPSR mode"); r = arm->core_cache->reg_list + regnum; } return r; } static const uint8_t arm_gdb_dummy_fp_value[12]; static struct reg_feature arm_gdb_dummy_fp_features = { .name = "net.sourceforge.openocd.fake_fpa" }; /** * Dummy FPA registers are required to support GDB on ARM. * Register packets require eight obsolete FPA register values. * Modern ARM cores use Vector Floating Point (VFP), if they * have any floating point support. VFP is not FPA-compatible. */ static struct reg arm_gdb_dummy_fp_reg = { .name = "GDB dummy FPA register", .value = (uint8_t *) arm_gdb_dummy_fp_value, .valid = true, .size = 96, .exist = false, .number = 16, .feature = &arm_gdb_dummy_fp_features, .group = "fake_fpa", }; static const uint8_t arm_gdb_dummy_fps_value[4]; /** * Dummy FPA status registers are required to support GDB on ARM. * Register packets require an obsolete FPA status register. */ static struct reg arm_gdb_dummy_fps_reg = { .name = "GDB dummy FPA status register", .value = (uint8_t *) arm_gdb_dummy_fps_value, .valid = true, .size = 32, .exist = false, .number = 24, .feature = &arm_gdb_dummy_fp_features, .group = "fake_fpa", }; static void arm_gdb_dummy_init(void) __attribute__ ((constructor)); static void arm_gdb_dummy_init(void) { register_init_dummy(&arm_gdb_dummy_fp_reg); register_init_dummy(&arm_gdb_dummy_fps_reg); } static int armv4_5_get_core_reg(struct reg *reg) { int retval; struct arm_reg *reg_arch_info = reg->arch_info; struct target *target = reg_arch_info->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = reg_arch_info->arm->read_core_reg(target, reg, reg_arch_info->num, reg_arch_info->mode); if (retval == ERROR_OK) { reg->valid = true; reg->dirty = false; } return retval; } static int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf) { struct arm_reg *reg_arch_info = reg->arch_info; struct target *target = reg_arch_info->target; struct arm *armv4_5_target = target_to_arm(target); uint32_t value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Except for CPSR, the "reg" command exposes a writeback model * for the register cache. */ if (reg == armv4_5_target->cpsr) { arm_set_cpsr(armv4_5_target, value); /* Older cores need help to be in ARM mode during halt * mode debug, so we clear the J and T bits if we flush. * For newer cores (v6/v7a/v7r) we don't need that, but * it won't hurt since CPSR is always flushed anyway. */ if (armv4_5_target->core_mode != (enum arm_mode)(value & 0x1f)) { LOG_DEBUG("changing ARM core mode to '%s'", arm_mode_name(value & 0x1f)); value &= ~((1 << 24) | (1 << 5)); uint8_t t[4]; buf_set_u32(t, 0, 32, value); armv4_5_target->write_core_reg(target, reg, 16, ARM_MODE_ANY, t); } } else { buf_set_u32(reg->value, 0, 32, value); if (reg->size == 64) { value = buf_get_u32(buf + 4, 0, 32); buf_set_u32(reg->value + 4, 0, 32, value); } reg->valid = true; } reg->dirty = true; return ERROR_OK; } static const struct reg_arch_type arm_reg_type = { .get = armv4_5_get_core_reg, .set = armv4_5_set_core_reg, }; struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) { int num_regs = ARRAY_SIZE(arm_core_regs); int num_core_regs = num_regs; if (arm->arm_vfp_version == ARM_VFP_V3) num_regs += ARRAY_SIZE(arm_vfp_v3_regs); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); struct arm_reg *reg_arch_info = calloc(num_regs, sizeof(struct arm_reg)); int i; if (!cache || !reg_list || !reg_arch_info) { free(cache); free(reg_list); free(reg_arch_info); return NULL; } cache->name = "ARM registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = 0; for (i = 0; i < num_core_regs; i++) { /* Skip registers this core doesn't expose */ if (arm_core_regs[i].mode == ARM_MODE_MON && arm->core_type != ARM_CORE_TYPE_SEC_EXT && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; if (arm_core_regs[i].mode == ARM_MODE_HYP && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; /* REVISIT handle Cortex-M, which only shadows R13/SP */ reg_arch_info[i].num = arm_core_regs[i].cookie; reg_arch_info[i].mode = arm_core_regs[i].mode; reg_arch_info[i].target = target; reg_arch_info[i].arm = arm; reg_list[i].name = arm_core_regs[i].name; reg_list[i].number = arm_core_regs[i].gdb_index; reg_list[i].size = 32; reg_list[i].value = reg_arch_info[i].value; reg_list[i].type = &arm_reg_type; reg_list[i].arch_info = ®_arch_info[i]; reg_list[i].exist = true; /* This really depends on the calling convention in use */ reg_list[i].caller_save = false; /* Registers data type, as used by GDB target description */ reg_list[i].reg_data_type = malloc(sizeof(struct reg_data_type)); switch (arm_core_regs[i].cookie) { case 13: reg_list[i].reg_data_type->type = REG_TYPE_DATA_PTR; break; case 14: case 15: reg_list[i].reg_data_type->type = REG_TYPE_CODE_PTR; break; default: reg_list[i].reg_data_type->type = REG_TYPE_UINT32; break; } /* let GDB shows banked registers only in "info all-reg" */ reg_list[i].feature = malloc(sizeof(struct reg_feature)); if (reg_list[i].number <= 15 || reg_list[i].number == 25) { reg_list[i].feature->name = "org.gnu.gdb.arm.core"; reg_list[i].group = "general"; } else { reg_list[i].feature->name = "net.sourceforge.openocd.banked"; reg_list[i].group = "banked"; } cache->num_regs++; } int j; for (i = num_core_regs, j = 0; i < num_regs; i++, j++) { reg_arch_info[i].num = arm_vfp_v3_regs[j].id; reg_arch_info[i].mode = arm_vfp_v3_regs[j].mode; reg_arch_info[i].target = target; reg_arch_info[i].arm = arm; reg_list[i].name = arm_vfp_v3_regs[j].name; reg_list[i].number = arm_vfp_v3_regs[j].id; reg_list[i].size = arm_vfp_v3_regs[j].bits; reg_list[i].value = reg_arch_info[i].value; reg_list[i].type = &arm_reg_type; reg_list[i].arch_info = ®_arch_info[i]; reg_list[i].exist = true; reg_list[i].caller_save = false; reg_list[i].reg_data_type = malloc(sizeof(struct reg_data_type)); reg_list[i].reg_data_type->type = arm_vfp_v3_regs[j].type; reg_list[i].feature = malloc(sizeof(struct reg_feature)); reg_list[i].feature->name = arm_vfp_v3_regs[j].feature; reg_list[i].group = arm_vfp_v3_regs[j].group; cache->num_regs++; } arm->pc = reg_list + 15; arm->cpsr = reg_list + ARMV4_5_CPSR; arm->core_cache = cache; return cache; } void arm_free_reg_cache(struct arm *arm) { if (!arm || !arm->core_cache) return; struct reg_cache *cache = arm->core_cache; for (unsigned int i = 0; i < cache->num_regs; i++) { struct reg *reg = &cache->reg_list[i]; free(reg->feature); free(reg->reg_data_type); } free(cache->reg_list[0].arch_info); free(cache->reg_list); free(cache); arm->core_cache = NULL; } int arm_arch_state(struct target *target) { struct arm *arm = target_to_arm(target); if (arm->common_magic != ARM_COMMON_MAGIC) { LOG_ERROR("BUG: called for a non-ARM target"); return ERROR_FAIL; } /* avoid filling log waiting for fileio reply */ if (target->semihosting && target->semihosting->hit_fileio) return ERROR_OK; LOG_USER("target halted in %s state due to %s, current mode: %s\n" "cpsr: 0x%8.8" PRIx32 " pc: 0x%8.8" PRIx32 "%s%s", arm_state_strings[arm->core_state], debug_reason_name(target), arm_mode_name(arm->core_mode), buf_get_u32(arm->cpsr->value, 0, 32), buf_get_u32(arm->pc->value, 0, 32), (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "", (target->semihosting && target->semihosting->is_fileio) ? " fileio" : ""); return ERROR_OK; } COMMAND_HANDLER(handle_armv4_5_reg_command) { struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct reg *regs; if (!is_arm(arm)) { command_print(CMD, "current target isn't an ARM"); return ERROR_FAIL; } if (target->state != TARGET_HALTED) { command_print(CMD, "error: target must be halted for register accesses"); return ERROR_FAIL; } if (arm->core_type != ARM_CORE_TYPE_STD) { command_print(CMD, "Microcontroller Profile not supported - use standard reg cmd"); return ERROR_OK; } if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } if (!arm->full_context) { command_print(CMD, "error: target doesn't support %s", CMD_NAME); return ERROR_FAIL; } regs = arm->core_cache->reg_list; for (unsigned mode = 0; mode < ARRAY_SIZE(arm_mode_data); mode++) { const char *name; char *sep = "\n"; char *shadow = ""; if (!arm_mode_data[mode].n_indices) continue; /* label this bank of registers (or shadows) */ switch (arm_mode_data[mode].psr) { case ARM_MODE_SYS: continue; case ARM_MODE_USR: name = "System and User"; sep = ""; break; case ARM_MODE_HYP: if (arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; /* FALLTHROUGH */ case ARM_MODE_MON: case ARM_MODE_1176_MON: if (arm->core_type != ARM_CORE_TYPE_SEC_EXT && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; /* FALLTHROUGH */ default: name = arm_mode_data[mode].name; shadow = "shadow "; break; } command_print(CMD, "%s%s mode %sregisters", sep, name, shadow); /* display N rows of up to 4 registers each */ for (unsigned i = 0; i < arm_mode_data[mode].n_indices; ) { char output[80]; int output_len = 0; for (unsigned j = 0; j < 4; j++, i++) { uint32_t value; struct reg *reg = regs; if (i >= arm_mode_data[mode].n_indices) break; reg += arm_mode_data[mode].indices[i]; /* REVISIT be smarter about faults... */ if (!reg->valid) arm->full_context(target); value = buf_get_u32(reg->value, 0, 32); output_len += snprintf(output + output_len, sizeof(output) - output_len, "%8s: %8.8" PRIx32 " ", reg->name, value); } command_print(CMD, "%s", output); } } return ERROR_OK; } COMMAND_HANDLER(handle_arm_core_state_command) { struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); int ret = ERROR_OK; if (!is_arm(arm)) { command_print(CMD, "current target isn't an ARM"); return ERROR_FAIL; } if (CMD_ARGC > 0) { if (strcmp(CMD_ARGV[0], "arm") == 0) { if (arm->core_type == ARM_CORE_TYPE_M_PROFILE) { command_print(CMD, "arm mode not supported on Cortex-M"); ret = ERROR_FAIL; } else { arm->core_state = ARM_STATE_ARM; } } if (strcmp(CMD_ARGV[0], "thumb") == 0) arm->core_state = ARM_STATE_THUMB; } command_print(CMD, "core state: %s", arm_state_strings[arm->core_state]); return ret; } COMMAND_HANDLER(handle_arm_disassemble_command) { #if HAVE_CAPSTONE struct target *target = get_current_target(CMD_CTX); if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } struct arm *arm = target_to_arm(target); target_addr_t address; unsigned int count = 1; bool thumb = false; if (!is_arm(arm)) { command_print(CMD, "current target isn't an ARM"); return ERROR_FAIL; } if (arm->core_type == ARM_CORE_TYPE_M_PROFILE) { /* armv7m is always thumb mode */ thumb = true; } switch (CMD_ARGC) { case 3: if (strcmp(CMD_ARGV[2], "thumb") != 0) return ERROR_COMMAND_SYNTAX_ERROR; thumb = true; /* FALL THROUGH */ case 2: COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], count); /* FALL THROUGH */ case 1: COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); if (address & 0x01) { if (!thumb) { command_print(CMD, "Disassemble as Thumb"); thumb = true; } address &= ~1; } break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return arm_disassemble(CMD, target, address, count, thumb); #else command_print(CMD, "capstone disassembly framework required"); return ERROR_FAIL; #endif } COMMAND_HANDLER(handle_armv4_5_mcrmrc) { bool is_mcr = false; unsigned int arg_cnt = 5; if (!strcmp(CMD_NAME, "mcr")) { is_mcr = true; arg_cnt = 6; } if (arg_cnt != CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); if (!target) { command_print(CMD, "no current target"); return ERROR_FAIL; } if (!target_was_examined(target)) { command_print(CMD, "%s: not yet examined", target_name(target)); return ERROR_TARGET_NOT_EXAMINED; } struct arm *arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "%s: not an ARM", target_name(target)); return ERROR_FAIL; } if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; int cpnum; uint32_t op1; uint32_t op2; uint32_t crn; uint32_t crm; uint32_t value; /* NOTE: parameter sequence matches ARM instruction set usage: * MCR pNUM, op1, rX, CRn, CRm, op2 ; write CP from rX * MRC pNUM, op1, rX, CRn, CRm, op2 ; read CP into rX * The "rX" is necessarily omitted; it uses Tcl mechanisms. */ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cpnum); if (cpnum & ~0xf) { command_print(CMD, "coprocessor %d out of range", cpnum); return ERROR_COMMAND_ARGUMENT_INVALID; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], op1); if (op1 & ~0x7) { command_print(CMD, "op1 %d out of range", op1); return ERROR_COMMAND_ARGUMENT_INVALID; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], crn); if (crn & ~0xf) { command_print(CMD, "CRn %d out of range", crn); return ERROR_COMMAND_ARGUMENT_INVALID; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], crm); if (crm & ~0xf) { command_print(CMD, "CRm %d out of range", crm); return ERROR_COMMAND_ARGUMENT_INVALID; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], op2); if (op2 & ~0x7) { command_print(CMD, "op2 %d out of range", op2); return ERROR_COMMAND_ARGUMENT_INVALID; } /* * FIXME change the call syntax here ... simplest to just pass * the MRC() or MCR() instruction to be executed. That will also * let us support the "mrc2" and "mcr2" opcodes (toggling one bit) * if that's ever needed. */ if (is_mcr) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[5], value); /* NOTE: parameters reordered! */ /* ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2) */ int retval = arm->mcr(target, cpnum, op1, op2, crn, crm, value); if (retval != ERROR_OK) return retval; } else { value = 0; /* NOTE: parameters reordered! */ /* ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2) */ int retval = arm->mrc(target, cpnum, op1, op2, crn, crm, &value); if (retval != ERROR_OK) return retval; command_print(CMD, "0x%" PRIx32, value); } return ERROR_OK; } static const struct command_registration arm_exec_command_handlers[] = { { .name = "reg", .handler = handle_armv4_5_reg_command, .mode = COMMAND_EXEC, .help = "display ARM core registers", .usage = "", }, { .name = "mcr", .mode = COMMAND_EXEC, .handler = handle_armv4_5_mcrmrc, .help = "write coprocessor register", .usage = "cpnum op1 CRn CRm op2 value", }, { .name = "mrc", .mode = COMMAND_EXEC, .handler = handle_armv4_5_mcrmrc, .help = "read coprocessor register", .usage = "cpnum op1 CRn CRm op2", }, { .chain = arm_all_profiles_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm_all_profiles_command_handlers[] = { { .name = "core_state", .handler = handle_arm_core_state_command, .mode = COMMAND_EXEC, .usage = "['arm'|'thumb']", .help = "display/change ARM core state", }, { .name = "disassemble", .handler = handle_arm_disassemble_command, .mode = COMMAND_EXEC, .usage = "address [count ['thumb']]", .help = "disassemble instructions", }, { .chain = semihosting_common_handlers, }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm_command_handlers[] = { { .name = "arm", .mode = COMMAND_ANY, .help = "ARM command group", .usage = "", .chain = arm_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /* * gdb for arm targets (e.g. arm-none-eabi-gdb) supports several variants * of arm architecture. You can list them using the autocompletion of gdb * command prompt by typing "set architecture " and then press TAB key. * The default, selected automatically, is "arm". * Let's use the default value, here, to make gdb-multiarch behave in the * same way as a gdb for arm. This can be changed later on. User can still * set the specific architecture variant with the gdb command. */ const char *arm_get_gdb_arch(struct target *target) { return "arm"; } int arm_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { struct arm *arm = target_to_arm(target); unsigned int i; if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } switch (reg_class) { case REG_CLASS_GENERAL: *reg_list_size = 26; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < 16; i++) (*reg_list)[i] = arm_reg_current(arm, i); /* For GDB compatibility, take FPA registers size into account and zero-fill it*/ for (i = 16; i < 24; i++) (*reg_list)[i] = &arm_gdb_dummy_fp_reg; (*reg_list)[24] = &arm_gdb_dummy_fps_reg; (*reg_list)[25] = arm->cpsr; return ERROR_OK; case REG_CLASS_ALL: switch (arm->core_type) { case ARM_CORE_TYPE_SEC_EXT: *reg_list_size = 51; break; case ARM_CORE_TYPE_VIRT_EXT: *reg_list_size = 53; break; default: *reg_list_size = 48; } unsigned int list_size_core = *reg_list_size; if (arm->arm_vfp_version == ARM_VFP_V3) *reg_list_size += 33; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < 16; i++) (*reg_list)[i] = arm_reg_current(arm, i); for (i = 13; i < ARRAY_SIZE(arm_core_regs); i++) { int reg_index = arm->core_cache->reg_list[i].number; if (arm_core_regs[i].mode == ARM_MODE_MON && arm->core_type != ARM_CORE_TYPE_SEC_EXT && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; if (arm_core_regs[i].mode == ARM_MODE_HYP && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; (*reg_list)[reg_index] = &(arm->core_cache->reg_list[i]); } /* When we supply the target description, there is no need for fake FPA */ for (i = 16; i < 24; i++) { (*reg_list)[i] = &arm_gdb_dummy_fp_reg; (*reg_list)[i]->size = 0; } (*reg_list)[24] = &arm_gdb_dummy_fps_reg; (*reg_list)[24]->size = 0; if (arm->arm_vfp_version == ARM_VFP_V3) { unsigned int num_core_regs = ARRAY_SIZE(arm_core_regs); for (i = 0; i < 33; i++) (*reg_list)[list_size_core + i] = &(arm->core_cache->reg_list[num_core_regs + i]); } return ERROR_OK; default: LOG_ERROR("not a valid register class type in query."); return ERROR_FAIL; } } /* wait for execution to complete and check exit point */ static int armv4_5_run_algorithm_completion(struct target *target, uint32_t exit_point, unsigned int timeout_ms, void *arch_info) { int retval; struct arm *arm = target_to_arm(target); retval = target_wait_state(target, TARGET_HALTED, timeout_ms); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { retval = target_halt(target); if (retval != ERROR_OK) return retval; retval = target_wait_state(target, TARGET_HALTED, 500); if (retval != ERROR_OK) return retval; return ERROR_TARGET_TIMEOUT; } /* fast exit: ARMv5+ code can use BKPT */ if (exit_point && buf_get_u32(arm->pc->value, 0, 32) != exit_point) { LOG_WARNING( "target reentered debug state, but not at the desired exit point: 0x%4.4" PRIx32 "", buf_get_u32(arm->pc->value, 0, 32)); return ERROR_TARGET_TIMEOUT; } return ERROR_OK; } int armv4_5_run_algorithm_inner(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, unsigned int timeout_ms, void *arch_info, int (*run_it)(struct target *target, uint32_t exit_point, unsigned int timeout_ms, void *arch_info)) { struct arm *arm = target_to_arm(target); struct arm_algorithm *arm_algorithm_info = arch_info; enum arm_state core_state = arm->core_state; uint32_t context[17]; uint32_t cpsr; int exit_breakpoint_size = 0; int i; int retval = ERROR_OK; LOG_DEBUG("Running algorithm"); if (arm_algorithm_info->common_magic != ARM_COMMON_MAGIC) { LOG_ERROR("current target isn't an ARMV4/5 target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } /* armv5 and later can terminate with BKPT instruction; less overhead */ if (!exit_point && arm->arch == ARM_ARCH_V4) { LOG_ERROR("ARMv4 target needs HW breakpoint location"); return ERROR_FAIL; } /* save r0..pc, cpsr-or-spsr, and then cpsr-for-sure; * they'll be restored later. */ for (i = 0; i <= 16; i++) { struct reg *r; r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i); if (!r->valid) arm->read_core_reg(target, r, i, arm_algorithm_info->core_mode); context[i] = buf_get_u32(r->value, 0, 32); } cpsr = buf_get_u32(arm->cpsr->value, 0, 32); for (i = 0; i < num_mem_params; i++) { if (mem_params[i].direction == PARAM_IN) continue; retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } for (i = 0; i < num_reg_params; i++) { if (reg_params[i].direction == PARAM_IN) continue; struct reg *reg = register_get_by_name(arm->core_cache, reg_params[i].reg_name, false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } retval = armv4_5_set_core_reg(reg, reg_params[i].value); if (retval != ERROR_OK) return retval; } arm->core_state = arm_algorithm_info->core_state; if (arm->core_state == ARM_STATE_ARM) exit_breakpoint_size = 4; else if (arm->core_state == ARM_STATE_THUMB) exit_breakpoint_size = 2; else { LOG_ERROR("BUG: can't execute algorithms when not in ARM or Thumb state"); return ERROR_COMMAND_SYNTAX_ERROR; } if (arm_algorithm_info->core_mode != ARM_MODE_ANY) { LOG_DEBUG("setting core_mode: 0x%2.2x", arm_algorithm_info->core_mode); buf_set_u32(arm->cpsr->value, 0, 5, arm_algorithm_info->core_mode); arm->cpsr->dirty = true; arm->cpsr->valid = true; } /* terminate using a hardware or (ARMv5+) software breakpoint */ if (exit_point) { retval = breakpoint_add(target, exit_point, exit_breakpoint_size, BKPT_HARD); if (retval != ERROR_OK) { LOG_ERROR("can't add HW breakpoint to terminate algorithm"); return ERROR_TARGET_FAILURE; } } retval = target_resume(target, 0, entry_point, 1, 1); if (retval != ERROR_OK) return retval; retval = run_it(target, exit_point, timeout_ms, arch_info); if (exit_point) breakpoint_remove(target, exit_point); if (retval != ERROR_OK) return retval; for (i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) { int retvaltemp = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retvaltemp != ERROR_OK) retval = retvaltemp; } } for (i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(arm->core_cache, reg_params[i].reg_name, false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); retval = ERROR_COMMAND_SYNTAX_ERROR; continue; } if (reg->size != reg_params[i].size) { LOG_ERROR( "BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); retval = ERROR_COMMAND_SYNTAX_ERROR; continue; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } /* restore everything we saved before (17 or 18 registers) */ for (i = 0; i <= 16; i++) { uint32_t regvalue; regvalue = buf_get_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).value, 0, 32); if (regvalue != context[i]) { LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32 "", ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).name, context[i]); buf_set_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).value, 0, 32, context[i]); ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).valid = true; ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).dirty = true; } } arm_set_cpsr(arm, cpsr); arm->cpsr->dirty = true; arm->core_state = core_state; return retval; } int armv4_5_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { return armv4_5_run_algorithm_inner(target, num_mem_params, mem_params, num_reg_params, reg_params, (uint32_t)entry_point, (uint32_t)exit_point, timeout_ms, arch_info, armv4_5_run_algorithm_completion); } /** * Runs ARM code in the target to calculate a CRC32 checksum. * */ int arm_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct arm_algorithm arm_algo; struct arm *arm = target_to_arm(target); struct reg_param reg_params[2]; int retval; uint32_t i; uint32_t exit_var = 0; static const uint8_t arm_crc_code_le[] = { #include "../../contrib/loaders/checksum/armv4_5_crc.inc" }; assert(sizeof(arm_crc_code_le) % 4 == 0); retval = target_alloc_working_area(target, sizeof(arm_crc_code_le), &crc_algorithm); if (retval != ERROR_OK) return retval; /* convert code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(arm_crc_code_le) / 4; i++) { retval = target_write_u32(target, crc_algorithm->address + i * sizeof(uint32_t), le_to_h_u32(&arm_crc_code_le[i * 4])); if (retval != ERROR_OK) goto cleanup; } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, count); /* 20 second timeout/megabyte */ unsigned int timeout = 20000 * (1 + (count / (1024 * 1024))); /* armv4 must exit using a hardware breakpoint */ if (arm->arch == ARM_ARCH_V4) exit_var = crc_algorithm->address + sizeof(arm_crc_code_le) - 8; retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, exit_var, timeout, &arm_algo); if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); else LOG_ERROR("error executing ARM crc algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); cleanup: target_free_working_area(target, crc_algorithm); return retval; } /** * Runs ARM code in the target to check whether a memory block holds * all ones. NOR flash which has been erased, and thus may be written, * holds all ones. * */ int arm_blank_check_memory(struct target *target, struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value) { struct working_area *check_algorithm; struct reg_param reg_params[3]; struct arm_algorithm arm_algo; struct arm *arm = target_to_arm(target); int retval; uint32_t i; uint32_t exit_var = 0; static const uint8_t check_code_le[] = { #include "../../contrib/loaders/erase_check/armv4_5_erase_check.inc" }; assert(sizeof(check_code_le) % 4 == 0); if (erased_value != 0xff) { LOG_ERROR("Erase value 0x%02" PRIx8 " not yet supported for ARMv4/v5 targets", erased_value); return ERROR_FAIL; } /* make sure we have a working area */ retval = target_alloc_working_area(target, sizeof(check_code_le), &check_algorithm); if (retval != ERROR_OK) return retval; /* convert code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(check_code_le) / 4; i++) { retval = target_write_u32(target, check_algorithm->address + i * sizeof(uint32_t), le_to_h_u32(&check_code_le[i * 4])); if (retval != ERROR_OK) goto cleanup; } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, blocks[0].address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, blocks[0].size); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, erased_value); /* armv4 must exit using a hardware breakpoint */ if (arm->arch == ARM_ARCH_V4) exit_var = check_algorithm->address + sizeof(check_code_le) - 4; retval = target_run_algorithm(target, 0, NULL, 3, reg_params, check_algorithm->address, exit_var, 10000, &arm_algo); if (retval == ERROR_OK) blocks[0].result = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); cleanup: target_free_working_area(target, check_algorithm); if (retval != ERROR_OK) return retval; return 1; /* only one block has been checked */ } static int arm_full_context(struct target *target) { struct arm *arm = target_to_arm(target); unsigned num_regs = arm->core_cache->num_regs; struct reg *reg = arm->core_cache->reg_list; int retval = ERROR_OK; for (; num_regs && retval == ERROR_OK; num_regs--, reg++) { if (!reg->exist || reg->valid) continue; retval = armv4_5_get_core_reg(reg); } return retval; } static int arm_default_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value) { LOG_ERROR("%s doesn't implement MRC", target_type_name(target)); return ERROR_FAIL; } static int arm_default_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) { LOG_ERROR("%s doesn't implement MCR", target_type_name(target)); return ERROR_FAIL; } int arm_init_arch_info(struct target *target, struct arm *arm) { target->arch_info = arm; arm->target = target; arm->common_magic = ARM_COMMON_MAGIC; /* core_type may be overridden by subtype logic */ if (arm->core_type != ARM_CORE_TYPE_M_PROFILE) { arm->core_type = ARM_CORE_TYPE_STD; arm_set_cpsr(arm, ARM_MODE_USR); } /* default full_context() has no core-specific optimizations */ if (!arm->full_context && arm->read_core_reg) arm->full_context = arm_full_context; if (!arm->mrc) arm->mrc = arm_default_mrc; if (!arm->mcr) arm->mcr = arm_default_mcr; return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv4_5.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2009 by Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV4_5_H #define OPENOCD_TARGET_ARMV4_5_H /* This stuff "knows" that its callers aren't talking * to microcontroller profile (current Cortex-M) parts. * We want to phase it out so core code can be shared. */ /* OBSOLETE, DO NOT USE IN NEW CODE! The "number" of an arm_mode is an * index into the armv4_5_core_reg_map array. Its remaining users are * remnants which could as easily walk * the register cache directly as * use the expensive ARMV4_5_CORE_REG_MODE() macro. */ int arm_mode_to_number(enum arm_mode mode); enum arm_mode armv4_5_number_to_mode(int number); extern const int armv4_5_core_reg_map[9][17]; #define ARMV4_5_CORE_REG_MODE(cache, mode, num) \ (cache->reg_list[armv4_5_core_reg_map[arm_mode_to_number(mode)][num]]) /* offset into armv4_5 core register cache -- OBSOLETE, DO NOT USE! */ enum { ARMV4_5_CPSR = 31, }; #endif /* OPENOCD_TARGET_ARMV4_5_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv4_5_cache.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "armv4_5_cache.h" #include <helper/log.h> int armv4_5_identify_cache(uint32_t cache_type_reg, struct armv4_5_cache_common *cache) { int size, assoc, M, len, multiplier; cache->ctype = (cache_type_reg & 0x1e000000U) >> 25; cache->separate = (cache_type_reg & 0x01000000U) >> 24; size = (cache_type_reg & 0x1c0000) >> 18; assoc = (cache_type_reg & 0x38000) >> 15; M = (cache_type_reg & 0x4000) >> 14; len = (cache_type_reg & 0x3000) >> 12; multiplier = 2 + M; if ((assoc != 0) || (M != 1)) /* assoc 0 and M 1 means cache absent */ { /* cache is present */ cache->d_u_size.linelen = 1 << (len + 3); cache->d_u_size.associativity = multiplier << (assoc - 1); cache->d_u_size.nsets = 1 << (size + 6 - assoc - len); cache->d_u_size.cachesize = multiplier << (size + 8); } else { /* cache is absent */ cache->d_u_size.linelen = -1; cache->d_u_size.associativity = -1; cache->d_u_size.nsets = -1; cache->d_u_size.cachesize = -1; } if (cache->separate) { size = (cache_type_reg & 0x1c0) >> 6; assoc = (cache_type_reg & 0x38) >> 3; M = (cache_type_reg & 0x4) >> 2; len = (cache_type_reg & 0x3); multiplier = 2 + M; if ((assoc != 0) || (M != 1)) /* assoc 0 and M 1 means cache absent */ { /* cache is present */ cache->i_size.linelen = 1 << (len + 3); cache->i_size.associativity = multiplier << (assoc - 1); cache->i_size.nsets = 1 << (size + 6 - assoc - len); cache->i_size.cachesize = multiplier << (size + 8); } else { /* cache is absent */ cache->i_size.linelen = -1; cache->i_size.associativity = -1; cache->i_size.nsets = -1; cache->i_size.cachesize = -1; } } else cache->i_size = cache->d_u_size; return ERROR_OK; } int armv4_5_handle_cache_info_command(struct command_invocation *cmd, struct armv4_5_cache_common *armv4_5_cache) { if (armv4_5_cache->ctype == -1) { command_print(cmd, "cache not yet identified"); return ERROR_OK; } command_print(cmd, "cache type: 0x%1.1x, %s", armv4_5_cache->ctype, (armv4_5_cache->separate) ? "separate caches" : "unified cache"); command_print(cmd, "D-Cache: linelen %i, associativity %i, nsets %i, cachesize 0x%x", armv4_5_cache->d_u_size.linelen, armv4_5_cache->d_u_size.associativity, armv4_5_cache->d_u_size.nsets, armv4_5_cache->d_u_size.cachesize); command_print(cmd, "I-Cache: linelen %i, associativity %i, nsets %i, cachesize 0x%x", armv4_5_cache->i_size.linelen, armv4_5_cache->i_size.associativity, armv4_5_cache->i_size.nsets, armv4_5_cache->i_size.cachesize); return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv4_5_cache.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV4_5_CACHE_H #define OPENOCD_TARGET_ARMV4_5_CACHE_H #include "helper/types.h" struct command_invocation; struct armv4_5_cachesize { int linelen; int associativity; int nsets; int cachesize; }; struct armv4_5_cache_common { int ctype; /* specify supported cache operations */ int separate; /* separate caches or unified cache */ struct armv4_5_cachesize d_u_size; /* data cache */ struct armv4_5_cachesize i_size; /* instruction cache */ int i_cache_enabled; int d_u_cache_enabled; }; int armv4_5_identify_cache(uint32_t cache_type_reg, struct armv4_5_cache_common *cache); int armv4_5_cache_state(uint32_t cp15_control_reg, struct armv4_5_cache_common *cache); int armv4_5_handle_cache_info_command(struct command_invocation *cmd, struct armv4_5_cache_common *armv4_5_cache); enum { ARMV4_5_D_U_CACHE_ENABLED = 0x4, ARMV4_5_I_CACHE_ENABLED = 0x1000, ARMV4_5_WRITE_BUFFER_ENABLED = 0x8, ARMV4_5_CACHE_RR_BIT = 0x5000, }; #endif /* OPENOCD_TARGET_ARMV4_5_CACHE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv4_5_mmu.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include "target.h" #include "armv4_5_mmu.h" int armv4_5_mmu_translate_va(struct target *target, struct armv4_5_mmu_common *armv4_5_mmu, uint32_t va, uint32_t *cb, uint32_t *val) { uint32_t first_lvl_descriptor = 0x0; uint32_t second_lvl_descriptor = 0x0; uint32_t ttb; int retval; retval = armv4_5_mmu->get_ttb(target, &ttb); if (retval != ERROR_OK) return retval; retval = armv4_5_mmu_read_physical(target, armv4_5_mmu, (ttb & 0xffffc000) | ((va & 0xfff00000) >> 18), 4, 1, (uint8_t *)&first_lvl_descriptor); if (retval != ERROR_OK) return retval; first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)&first_lvl_descriptor); LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor); if ((first_lvl_descriptor & 0x3) == 0) { LOG_ERROR("Address translation failure"); return ERROR_TARGET_TRANSLATION_FAULT; } if (!armv4_5_mmu->has_tiny_pages && ((first_lvl_descriptor & 0x3) == 3)) { LOG_ERROR("Address translation failure"); return ERROR_TARGET_TRANSLATION_FAULT; } if ((first_lvl_descriptor & 0x3) == 2) { /* section descriptor */ *cb = (first_lvl_descriptor & 0xc) >> 2; *val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff); return ERROR_OK; } if ((first_lvl_descriptor & 0x3) == 1) { /* coarse page table */ retval = armv4_5_mmu_read_physical(target, armv4_5_mmu, (first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10), 4, 1, (uint8_t *)&second_lvl_descriptor); if (retval != ERROR_OK) return retval; } else if ((first_lvl_descriptor & 0x3) == 3) { /* fine page table */ retval = armv4_5_mmu_read_physical(target, armv4_5_mmu, (first_lvl_descriptor & 0xfffff000) | ((va & 0x000ffc00) >> 8), 4, 1, (uint8_t *)&second_lvl_descriptor); if (retval != ERROR_OK) return retval; } second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)&second_lvl_descriptor); LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor); if ((second_lvl_descriptor & 0x3) == 0) { LOG_ERROR("Address translation failure"); return ERROR_TARGET_TRANSLATION_FAULT; } /* cacheable/bufferable is always specified in bits 3-2 */ *cb = (second_lvl_descriptor & 0xc) >> 2; if ((second_lvl_descriptor & 0x3) == 1) { /* large page descriptor */ *val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff); return ERROR_OK; } if ((second_lvl_descriptor & 0x3) == 2) { /* small page descriptor */ *val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff); return ERROR_OK; } if ((second_lvl_descriptor & 0x3) == 3) { /* tiny page descriptor */ *val = (second_lvl_descriptor & 0xfffffc00) | (va & 0x000003ff); return ERROR_OK; } /* should not happen */ LOG_ERROR("Address translation failure"); return ERROR_TARGET_TRANSLATION_FAULT; } int armv4_5_mmu_read_physical(struct target *target, struct armv4_5_mmu_common *armv4_5_mmu, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; /* disable MMU and data (or unified) cache */ retval = armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0); if (retval != ERROR_OK) return retval; retval = armv4_5_mmu->read_memory(target, address, size, count, buffer); if (retval != ERROR_OK) return retval; /* reenable MMU / cache */ retval = armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled, armv4_5_mmu->armv4_5_cache.d_u_cache_enabled, armv4_5_mmu->armv4_5_cache.i_cache_enabled); if (retval != ERROR_OK) return retval; return retval; } int armv4_5_mmu_write_physical(struct target *target, struct armv4_5_mmu_common *armv4_5_mmu, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; /* disable MMU and data (or unified) cache */ retval = armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0); if (retval != ERROR_OK) return retval; retval = armv4_5_mmu->write_memory(target, address, size, count, buffer); if (retval != ERROR_OK) return retval; /* reenable MMU / cache */ retval = armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled, armv4_5_mmu->armv4_5_cache.d_u_cache_enabled, armv4_5_mmu->armv4_5_cache.i_cache_enabled); if (retval != ERROR_OK) return retval; return retval; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv4_5_mmu.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV4_5_MMU_H #define OPENOCD_TARGET_ARMV4_5_MMU_H #include "armv4_5_cache.h" struct target; struct armv4_5_mmu_common { int (*get_ttb)(struct target *target, uint32_t *result); int (*read_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); int (*write_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int (*disable_mmu_caches)(struct target *target, int mmu, int d_u_cache, int i_cache); int (*enable_mmu_caches)(struct target *target, int mmu, int d_u_cache, int i_cache); struct armv4_5_cache_common armv4_5_cache; int has_tiny_pages; int mmu_enabled; }; int armv4_5_mmu_translate_va(struct target *target, struct armv4_5_mmu_common *armv4_5_mmu, uint32_t va, uint32_t *cb, uint32_t *val); int armv4_5_mmu_read_physical(struct target *target, struct armv4_5_mmu_common *armv4_5_mmu, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); int armv4_5_mmu_write_physical(struct target *target, struct armv4_5_mmu_common *armv4_5_mmu, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); enum { ARMV4_5_MMU_ENABLED = 0x1, ARMV4_5_ALIGNMENT_CHECK = 0x2, ARMV4_5_MMU_S_BIT = 0x100, ARMV4_5_MMU_R_BIT = 0x200 }; #endif /* OPENOCD_TARGET_ARMV4_5_MMU_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv7a.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by David Brownell * * * * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/replacements.h> #include "armv7a.h" #include "armv7a_mmu.h" #include "arm_disassembler.h" #include "register.h" #include <helper/binarybuffer.h> #include <helper/command.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "arm_opcodes.h" #include "target.h" #include "target_type.h" #include "smp.h" static void armv7a_show_fault_registers(struct target *target) { uint32_t dfsr, ifsr, dfar, ifar; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return; /* ARMV4_5_MRC(cpnum, op1, r0, crn, crm, op2) */ /* c5/c0 - {data, instruction} fault status registers */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 5, 0, 0), &dfsr); if (retval != ERROR_OK) goto done; retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 5, 0, 1), &ifsr); if (retval != ERROR_OK) goto done; /* c6/c0 - {data, instruction} fault address registers */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 6, 0, 0), &dfar); if (retval != ERROR_OK) goto done; retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 6, 0, 2), &ifar); if (retval != ERROR_OK) goto done; LOG_USER("Data fault registers DFSR: %8.8" PRIx32 ", DFAR: %8.8" PRIx32, dfsr, dfar); LOG_USER("Instruction fault registers IFSR: %8.8" PRIx32 ", IFAR: %8.8" PRIx32, ifsr, ifar); done: /* (void) */ dpm->finish(dpm); } /* retrieve main id register */ static int armv7a_read_midr(struct target *target) { int retval = ERROR_FAIL; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t midr; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* MRC p15,0,<Rd>,c0,c0,0; read main id register*/ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 0, 0, 0), &midr); if (retval != ERROR_OK) goto done; armv7a->rev = (midr & 0xf); armv7a->partnum = (midr >> 4) & 0xfff; armv7a->arch = (midr >> 16) & 0xf; armv7a->variant = (midr >> 20) & 0xf; armv7a->implementor = (midr >> 24) & 0xff; LOG_DEBUG("%s rev %" PRIx32 ", partnum %" PRIx32 ", arch %" PRIx32 ", variant %" PRIx32 ", implementor %" PRIx32, target->cmd_name, armv7a->rev, armv7a->partnum, armv7a->arch, armv7a->variant, armv7a->implementor); done: dpm->finish(dpm); return retval; } int armv7a_read_ttbcr(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t ttbcr, ttbcr_n; int ttbidx; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 2, 0, 2), &ttbcr); if (retval != ERROR_OK) goto done; LOG_DEBUG("ttbcr %" PRIx32, ttbcr); ttbcr_n = ttbcr & 0x7; armv7a->armv7a_mmu.ttbcr = ttbcr; armv7a->armv7a_mmu.cached = 1; for (ttbidx = 0; ttbidx < 2; ttbidx++) { /* MRC p15,0,<Rt>,c2,c0,ttbidx */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 2, 0, ttbidx), &armv7a->armv7a_mmu.ttbr[ttbidx]); if (retval != ERROR_OK) goto done; } /* * ARM Architecture Reference Manual (ARMv7-A and ARMv7-R edition), * document # ARM DDI 0406C */ armv7a->armv7a_mmu.ttbr_range[0] = 0xffffffff >> ttbcr_n; armv7a->armv7a_mmu.ttbr_range[1] = 0xffffffff; armv7a->armv7a_mmu.ttbr_mask[0] = 0xffffffff << (14 - ttbcr_n); armv7a->armv7a_mmu.ttbr_mask[1] = 0xffffffff << 14; armv7a->armv7a_mmu.cached = 1; retval = armv7a_read_midr(target); if (retval != ERROR_OK) goto done; /* FIXME: why this special case based on part number? */ if ((armv7a->partnum & 0xf) == 0) { /* ARM DDI 0344H , ARM DDI 0407F */ armv7a->armv7a_mmu.ttbr_mask[0] = 7 << (32 - ttbcr_n); } LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32 " ttbr1_mask %" PRIx32, (ttbcr_n != 0) ? "used" : "not used", armv7a->armv7a_mmu.ttbr_mask[0], armv7a->armv7a_mmu.ttbr_mask[1]); done: dpm->finish(dpm); return retval; } /* FIXME: remove it */ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way) { struct armv7a_l2x_cache *l2x_cache; struct target_list *head; struct armv7a_common *armv7a = target_to_armv7a(target); l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache)); l2x_cache->base = base; l2x_cache->way = way; /*LOG_INFO("cache l2 initialized base %x way %d", l2x_cache->base,l2x_cache->way);*/ if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) LOG_INFO("outer cache already initialized\n"); armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; /* initialize all target in this cluster (smp target) * l2 cache must be configured after smp declaration */ foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (curr != target) { armv7a = target_to_armv7a(curr); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) LOG_ERROR("smp target : outer cache already initialized\n"); armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; } } return JIM_OK; } /* FIXME: remove it */ COMMAND_HANDLER(handle_cache_l2x) { struct target *target = get_current_target(CMD_CTX); uint32_t base, way; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; /* command_print(CMD, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], base); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], way); /* AP address is in bits 31:24 of DP_SELECT */ armv7a_l2x_cache_init(target, base, way); return ERROR_OK; } int armv7a_handle_cache_info_command(struct command_invocation *cmd, struct armv7a_cache_common *armv7a_cache) { struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) (armv7a_cache->outer_cache); int cl; if (armv7a_cache->info == -1) { command_print(cmd, "cache not yet identified"); return ERROR_OK; } for (cl = 0; cl < armv7a_cache->loc; cl++) { struct armv7a_arch_cache *arch = &(armv7a_cache->arch[cl]); if (arch->ctype & 1) { command_print(cmd, "L%d I-Cache: linelen %" PRIu32 ", associativity %" PRIu32 ", nsets %" PRIu32 ", cachesize %" PRIu32 " KBytes", cl+1, arch->i_size.linelen, arch->i_size.associativity, arch->i_size.nsets, arch->i_size.cachesize); } if (arch->ctype >= 2) { command_print(cmd, "L%d D-Cache: linelen %" PRIu32 ", associativity %" PRIu32 ", nsets %" PRIu32 ", cachesize %" PRIu32 " KBytes", cl+1, arch->d_u_size.linelen, arch->d_u_size.associativity, arch->d_u_size.nsets, arch->d_u_size.cachesize); } } if (l2x_cache) command_print(cmd, "Outer unified cache Base Address 0x%" PRIx32 ", %" PRIu32 " ways", l2x_cache->base, l2x_cache->way); return ERROR_OK; } /* retrieve core id cluster id */ static int armv7a_read_mpidr(struct target *target) { int retval = ERROR_FAIL; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t mpidr; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* MRC p15,0,<Rd>,c0,c0,5; read Multiprocessor ID register*/ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 0, 0, 5), &mpidr); if (retval != ERROR_OK) goto done; /* Is register in Multiprocessing Extensions register format? */ if (mpidr & MPIDR_MP_EXT) { LOG_DEBUG("%s: MPIDR 0x%" PRIx32, target_name(target), mpidr); armv7a->multi_processor_system = (mpidr >> 30) & 1; armv7a->multi_threading_processor = (mpidr >> 24) & 1; armv7a->level2_id = (mpidr >> 16) & 0xf; armv7a->cluster_id = (mpidr >> 8) & 0xf; armv7a->cpu_id = mpidr & 0xf; LOG_INFO("%s: MPIDR level2 %x, cluster %x, core %x, %s, %s", target_name(target), armv7a->level2_id, armv7a->cluster_id, armv7a->cpu_id, armv7a->multi_processor_system == 0 ? "multi core" : "mono core", armv7a->multi_threading_processor == 1 ? "SMT" : "no SMT"); } else LOG_ERROR("MPIDR not in multiprocessor format"); done: dpm->finish(dpm); return retval; } static int get_cache_info(struct arm_dpm *dpm, int cl, int ct, uint32_t *cache_reg) { int retval = ERROR_OK; /* select cache level */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 2, 0, 0, 0, 0), (cl << 1) | (ct == 1 ? 1 : 0)); if (retval != ERROR_OK) goto done; retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 1, 0, 0, 0, 0), cache_reg); done: return retval; } static struct armv7a_cachesize decode_cache_reg(uint32_t cache_reg) { struct armv7a_cachesize size; int i = 0; size.linelen = 16 << (cache_reg & 0x7); size.associativity = ((cache_reg >> 3) & 0x3ff) + 1; size.nsets = ((cache_reg >> 13) & 0x7fff) + 1; size.cachesize = size.linelen * size.associativity * size.nsets / 1024; /* compute info for set way operation on cache */ size.index_shift = (cache_reg & 0x7) + 4; size.index = (cache_reg >> 13) & 0x7fff; size.way = ((cache_reg >> 3) & 0x3ff); while (((size.way << i) & 0x80000000) == 0) i++; size.way_shift = i; return size; } int armv7a_identify_cache(struct target *target) { /* read cache descriptor */ int retval = ERROR_FAIL; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t csselr, clidr, ctr; uint32_t cache_reg; int cl, ctype; struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache); retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* retrieve CTR * mrc p15, 0, r0, c0, c0, 1 @ read ctr */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 0, 0, 1), &ctr); if (retval != ERROR_OK) goto done; cache->iminline = 4UL << (ctr & 0xf); cache->dminline = 4UL << ((ctr & 0xf0000) >> 16); LOG_DEBUG("ctr %" PRIx32 " ctr.iminline %" PRIu32 " ctr.dminline %" PRIu32, ctr, cache->iminline, cache->dminline); /* retrieve CLIDR * mrc p15, 1, r0, c0, c0, 1 @ read clidr */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 1, 0, 0, 0, 1), &clidr); if (retval != ERROR_OK) goto done; cache->loc = (clidr & 0x7000000) >> 24; LOG_DEBUG("Number of cache levels to PoC %" PRId32, cache->loc); /* retrieve selected cache for later restore * MRC p15, 2,<Rd>, c0, c0, 0; Read CSSELR */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 2, 0, 0, 0, 0), &csselr); if (retval != ERROR_OK) goto done; /* retrieve all available inner caches */ for (cl = 0; cl < cache->loc; clidr >>= 3, cl++) { /* isolate cache type at current level */ ctype = clidr & 7; /* skip reserved values */ if (ctype > CACHE_LEVEL_HAS_UNIFIED_CACHE) continue; /* separate d or unified d/i cache at this level ? */ if (ctype & (CACHE_LEVEL_HAS_UNIFIED_CACHE | CACHE_LEVEL_HAS_D_CACHE)) { /* retrieve d-cache info */ retval = get_cache_info(dpm, cl, 0, &cache_reg); if (retval != ERROR_OK) goto done; cache->arch[cl].d_u_size = decode_cache_reg(cache_reg); LOG_DEBUG("data/unified cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, cache->arch[cl].d_u_size.index, cache->arch[cl].d_u_size.index_shift, cache->arch[cl].d_u_size.way, cache->arch[cl].d_u_size.way_shift); LOG_DEBUG("cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", cache->arch[cl].d_u_size.linelen, cache->arch[cl].d_u_size.cachesize, cache->arch[cl].d_u_size.associativity); } /* separate i-cache at this level ? */ if (ctype & CACHE_LEVEL_HAS_I_CACHE) { /* retrieve i-cache info */ retval = get_cache_info(dpm, cl, 1, &cache_reg); if (retval != ERROR_OK) goto done; cache->arch[cl].i_size = decode_cache_reg(cache_reg); LOG_DEBUG("instruction cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, cache->arch[cl].i_size.index, cache->arch[cl].i_size.index_shift, cache->arch[cl].i_size.way, cache->arch[cl].i_size.way_shift); LOG_DEBUG("cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", cache->arch[cl].i_size.linelen, cache->arch[cl].i_size.cachesize, cache->arch[cl].i_size.associativity); } cache->arch[cl].ctype = ctype; } /* restore selected cache */ dpm->instr_write_data_r0(dpm, ARMV4_5_MRC(15, 2, 0, 0, 0, 0), csselr); if (retval != ERROR_OK) goto done; /* if no l2 cache initialize l1 data cache flush function function */ if (!armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache) { armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = armv7a_cache_auto_flush_all_data; } armv7a->armv7a_mmu.armv7a_cache.info = 1; done: dpm->finish(dpm); armv7a_read_mpidr(target); return retval; } static int armv7a_setup_semihosting(struct target *target, int enable) { struct armv7a_common *armv7a = target_to_armv7a(target); uint32_t vcr; int ret; ret = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_VCR, &vcr); if (ret < 0) { LOG_ERROR("Failed to read VCR register\n"); return ret; } if (enable) vcr |= DBG_VCR_SVC_MASK; else vcr &= ~DBG_VCR_SVC_MASK; ret = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_VCR, vcr); if (ret < 0) LOG_ERROR("Failed to write VCR register\n"); return ret; } int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a) { struct arm *arm = &armv7a->arm; arm->arch_info = armv7a; target->arch_info = &armv7a->arm; arm->setup_semihosting = armv7a_setup_semihosting; /* target is useful in all function arm v4 5 compatible */ armv7a->arm.target = target; armv7a->arm.common_magic = ARM_COMMON_MAGIC; armv7a->common_magic = ARMV7_COMMON_MAGIC; armv7a->armv7a_mmu.armv7a_cache.info = -1; armv7a->armv7a_mmu.armv7a_cache.outer_cache = NULL; armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = NULL; armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled = 1; return ERROR_OK; } int armv7a_arch_state(struct target *target) { static const char *state[] = { "disabled", "enabled" }; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; if (armv7a->common_magic != ARMV7_COMMON_MAGIC) { LOG_ERROR("BUG: called for a non-ARMv7A target"); return ERROR_COMMAND_SYNTAX_ERROR; } arm_arch_state(target); if (armv7a->is_armv7r) { LOG_USER("D-Cache: %s, I-Cache: %s", state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled], state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]); } else { LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", state[armv7a->armv7a_mmu.mmu_enabled], state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled], state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]); } if (arm->core_mode == ARM_MODE_ABT) armv7a_show_fault_registers(target); return ERROR_OK; } static const struct command_registration l2_cache_commands[] = { { .name = "l2x", .handler = handle_cache_l2x, .mode = COMMAND_EXEC, .help = "configure l2x cache", .usage = "[base_addr] [number_of_way]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration l2x_cache_command_handlers[] = { { .name = "cache_config", .mode = COMMAND_EXEC, .help = "cache configuration for a target", .usage = "", .chain = l2_cache_commands, }, COMMAND_REGISTRATION_DONE }; const struct command_registration armv7a_command_handlers[] = { { .chain = l2x_cache_command_handlers, }, { .chain = arm7a_cache_command_handlers, }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv7a.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 by David Brownell * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV7A_H #define OPENOCD_TARGET_ARMV7A_H #include "arm_adi_v5.h" #include "armv7a_cache.h" #include "arm.h" #include "armv4_5_mmu.h" #include "armv4_5_cache.h" #include "arm_dpm.h" enum { ARM_PC = 15, ARM_CPSR = 16 }; #define ARMV7_COMMON_MAGIC 0x0A450999U /* VA to PA translation operations opc2 values*/ #define V2PCWPR 0 #define V2PCWPW 1 #define V2PCWUR 2 #define V2PCWUW 3 #define V2POWPR 4 #define V2POWPW 5 #define V2POWUR 6 #define V2POWUW 7 /* L210/L220 cache controller support */ struct armv7a_l2x_cache { uint32_t base; uint32_t way; }; struct armv7a_cachesize { /* cache dimensioning */ uint32_t linelen; uint32_t associativity; uint32_t nsets; uint32_t cachesize; /* info for set way operation on cache */ uint32_t index; uint32_t index_shift; uint32_t way; uint32_t way_shift; }; /* information about one architecture cache at any level */ struct armv7a_arch_cache { int ctype; /* cache type, CLIDR encoding */ struct armv7a_cachesize d_u_size; /* data cache */ struct armv7a_cachesize i_size; /* instruction cache */ }; /* common cache information */ struct armv7a_cache_common { int info; /* -1 invalid, else valid */ int loc; /* level of coherency */ uint32_t dminline; /* minimum d-cache linelen */ uint32_t iminline; /* minimum i-cache linelen */ struct armv7a_arch_cache arch[6]; /* cache info, L1 - L7 */ int i_cache_enabled; int d_u_cache_enabled; int auto_cache_enabled; /* openocd automatic * cache handling */ /* outer unified cache if some */ void *outer_cache; int (*flush_all_data_cache)(struct target *target); }; struct armv7a_mmu_common { /* following field mmu working way */ int32_t cached; /* 0: not initialized, 1: initialized */ uint32_t ttbcr; /* cache for ttbcr register */ uint32_t ttbr[2]; uint32_t ttbr_mask[2]; uint32_t ttbr_range[2]; int (*read_physical_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); struct armv7a_cache_common armv7a_cache; uint32_t mmu_enabled; }; struct armv7a_common { unsigned int common_magic; struct arm arm; struct reg_cache *core_cache; /* Core Debug Unit */ struct arm_dpm dpm; target_addr_t debug_base; struct adiv5_ap *debug_ap; /* mdir */ uint8_t multi_processor_system; uint8_t multi_threading_processor; uint8_t level2_id; uint8_t cluster_id; uint8_t cpu_id; bool is_armv7r; uint32_t rev; uint32_t partnum; uint32_t arch; uint32_t variant; uint32_t implementor; /* cache specific to V7 Memory Management Unit compatible with v4_5*/ struct armv7a_mmu_common armv7a_mmu; int (*examine_debug_reason)(struct target *target); int (*post_debug_entry)(struct target *target); void (*pre_restore_context)(struct target *target); }; static inline struct armv7a_common * target_to_armv7a(struct target *target) { return container_of(target->arch_info, struct armv7a_common, arm); } static inline bool is_armv7a(struct armv7a_common *armv7a) { return armv7a->common_magic == ARMV7_COMMON_MAGIC; } /* register offsets from armv7a.debug_base */ /* See ARMv7a arch spec section C10.2 */ #define CPUDBG_DIDR 0x000 /* See ARMv7a arch spec section C10.3 */ #define CPUDBG_WFAR 0x018 /* PCSR at 0x084 -or- 0x0a0 -or- both ... based on flags in DIDR */ #define CPUDBG_DSCR 0x088 #define CPUDBG_DRCR 0x090 #define CPUDBG_PRCR 0x310 #define CPUDBG_PRSR 0x314 /* See ARMv7a arch spec section C10.4 */ #define CPUDBG_DTRRX 0x080 #define CPUDBG_ITR 0x084 #define CPUDBG_DTRTX 0x08c /* See ARMv7a arch spec section C10.5 */ #define CPUDBG_BVR_BASE 0x100 #define CPUDBG_BCR_BASE 0x140 #define CPUDBG_WVR_BASE 0x180 #define CPUDBG_WCR_BASE 0x1C0 #define CPUDBG_VCR 0x01C /* See ARMv7a arch spec section C10.6 */ #define CPUDBG_OSLAR 0x300 #define CPUDBG_OSLSR 0x304 #define CPUDBG_OSSRR 0x308 #define CPUDBG_ECR 0x024 /* See ARMv7a arch spec section C10.7 */ #define CPUDBG_DSCCR 0x028 #define CPUDBG_DSMCR 0x02C /* See ARMv7a arch spec section C10.8 */ #define CPUDBG_AUTHSTATUS 0xFB8 /* See ARMv7a arch spec DDI 0406C C11.10 */ #define CPUDBG_ID_PFR1 0xD24 /* Masks for Vector Catch register */ #define DBG_VCR_FIQ_MASK ((1 << 31) | (1 << 7)) #define DBG_VCR_IRQ_MASK ((1 << 30) | (1 << 6)) #define DBG_VCR_DATA_ABORT_MASK ((1 << 28) | (1 << 4)) #define DBG_VCR_PREF_ABORT_MASK ((1 << 27) | (1 << 3)) #define DBG_VCR_SVC_MASK ((1 << 26) | (1 << 2)) /* Masks for Multiprocessor Affinity Register */ #define MPIDR_MP_EXT (1UL << 31) int armv7a_arch_state(struct target *target); int armv7a_identify_cache(struct target *target); int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a); int armv7a_handle_cache_info_command(struct command_invocation *cmd, struct armv7a_cache_common *armv7a_cache); int armv7a_read_ttbcr(struct target *target); extern const struct command_registration armv7a_command_handlers[]; #endif /* OPENOCD_TARGET_ARMV7A_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv7a_cache.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2015 by Oleksij Rempel * * linux@rempel-privat.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/interface.h" #include "arm.h" #include "armv7a.h" #include "armv7a_cache.h" #include <helper/time_support.h> #include "arm_opcodes.h" #include "smp.h" static int armv7a_l1_d_cache_sanity_check(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); if (target->state != TARGET_HALTED) { LOG_ERROR("%s: target not halted", __func__); return ERROR_TARGET_NOT_HALTED; } /* check that cache data is on at target halt */ if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) { LOG_DEBUG("data cache is not enabled"); return ERROR_TARGET_INVALID; } return ERROR_OK; } static int armv7a_l1_i_cache_sanity_check(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); if (target->state != TARGET_HALTED) { LOG_ERROR("%s: target not halted", __func__); return ERROR_TARGET_NOT_HALTED; } /* check that cache data is on at target halt */ if (!armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled) { LOG_DEBUG("instruction cache is not enabled"); return ERROR_TARGET_INVALID; } return ERROR_OK; } static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cachesize *size, int cl) { int retval = ERROR_OK; int32_t c_way, c_index = size->index; LOG_DEBUG("cl %" PRId32, cl); do { keep_alive(); c_way = size->way; do { uint32_t value = (c_index << size->index_shift) | (c_way << size->way_shift) | (cl << 1); /* * DCCISW - Clean and invalidate data cache * line by Set/Way. */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 14, 2), value); if (retval != ERROR_OK) goto done; c_way -= 1; } while (c_way >= 0); c_index -= 1; } while (c_index >= 0); done: keep_alive(); return retval; } static int armv7a_l1_d_cache_clean_inval_all(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache); struct arm_dpm *dpm = armv7a->arm.dpm; int cl; int retval; retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) return retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; for (cl = 0; cl < cache->loc; cl++) { /* skip i-only caches */ if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE) continue; armv7a_l1_d_cache_flush_level(dpm, &cache->arch[cl].d_u_size, cl); } retval = dpm->finish(dpm); return retval; done: LOG_ERROR("clean invalidate failed"); dpm->finish(dpm); return retval; } int armv7a_cache_auto_flush_all_data(struct target *target) { int retval = ERROR_FAIL; struct armv7a_common *armv7a = target_to_armv7a(target); if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled) return ERROR_OK; if (target->smp) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (curr->state == TARGET_HALTED) retval = armv7a_l1_d_cache_clean_inval_all(curr); } } else retval = armv7a_l1_d_cache_clean_inval_all(target); if (retval != ERROR_OK) return retval; /* do outer cache flushing after inner caches have been flushed */ return arm7a_l2x_flush_all_data(target); } int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, uint32_t size) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->dminline; uint32_t va_line, va_end; int retval, i = 0; retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) return retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; va_line = virt & (-linelen); va_end = virt + size; /* handle unaligned start */ if (virt != va_line) { /* DCCIMVAC */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line); if (retval != ERROR_OK) goto done; va_line += linelen; } /* handle unaligned end */ if ((va_end & (linelen-1)) != 0) { va_end &= (-linelen); /* DCCIMVAC */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end); if (retval != ERROR_OK) goto done; } while (va_line < va_end) { if ((i++ & 0x3f) == 0) keep_alive(); /* DCIMVAC - Invalidate data cache line by VA to PoC. */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line); if (retval != ERROR_OK) goto done; va_line += linelen; } keep_alive(); dpm->finish(dpm); return retval; done: LOG_ERROR("d-cache invalidate failed"); keep_alive(); dpm->finish(dpm); return retval; } int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, unsigned int size) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->dminline; uint32_t va_line, va_end; int retval, i = 0; retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) return retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; va_line = virt & (-linelen); va_end = virt + size; while (va_line < va_end) { if ((i++ & 0x3f) == 0) keep_alive(); /* DCCMVAC - Data Cache Clean by MVA to PoC */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line); if (retval != ERROR_OK) goto done; va_line += linelen; } keep_alive(); dpm->finish(dpm); return retval; done: LOG_ERROR("d-cache invalidate failed"); keep_alive(); dpm->finish(dpm); return retval; } int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt, unsigned int size) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->dminline; uint32_t va_line, va_end; int retval, i = 0; retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) return retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; va_line = virt & (-linelen); va_end = virt + size; while (va_line < va_end) { if ((i++ & 0x3f) == 0) keep_alive(); /* DCCIMVAC */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line); if (retval != ERROR_OK) goto done; va_line += linelen; } keep_alive(); dpm->finish(dpm); return retval; done: LOG_ERROR("d-cache invalidate failed"); keep_alive(); dpm->finish(dpm); return retval; } int armv7a_l1_i_cache_inval_all(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; int retval; retval = armv7a_l1_i_cache_sanity_check(target); if (retval != ERROR_OK) return retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; if (target->smp) { /* ICIALLUIS */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0); } else { /* ICIALLU */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0); } if (retval != ERROR_OK) goto done; dpm->finish(dpm); return retval; done: LOG_ERROR("i-cache invalidate failed"); dpm->finish(dpm); return retval; } int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt, uint32_t size) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->iminline; uint32_t va_line, va_end; int retval, i = 0; retval = armv7a_l1_i_cache_sanity_check(target); if (retval != ERROR_OK) return retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; va_line = virt & (-linelen); va_end = virt + size; while (va_line < va_end) { if ((i++ & 0x3f) == 0) keep_alive(); /* ICIMVAU - Invalidate instruction cache by VA to PoU. */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line); if (retval != ERROR_OK) goto done; /* BPIMVA */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line); if (retval != ERROR_OK) goto done; va_line += linelen; } keep_alive(); dpm->finish(dpm); return retval; done: LOG_ERROR("i-cache invalidate failed"); keep_alive(); dpm->finish(dpm); return retval; } int armv7a_cache_flush_virt(struct target *target, uint32_t virt, uint32_t size) { armv7a_l1_d_cache_flush_virt(target, virt, size); armv7a_l2x_cache_flush_virt(target, virt, size); return ERROR_OK; } /* * We assume that target core was chosen correctly. It means if same data * was handled by two cores, other core will loose the changes. Since it * is impossible to know (FIXME) which core has correct data, keep in mind * that some kind of data lost or corruption is possible. * Possible scenario: * - core1 loaded and changed data on 0x12345678 * - we halted target and modified same data on core0 * - data on core1 will be lost. */ int armv7a_cache_auto_flush_on_write(struct target *target, uint32_t virt, uint32_t size) { struct armv7a_common *armv7a = target_to_armv7a(target); if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled) return ERROR_OK; return armv7a_cache_flush_virt(target, virt, size); } COMMAND_HANDLER(arm7a_l1_cache_info_cmd) { struct target *target = get_current_target(CMD_CTX); struct armv7a_common *armv7a = target_to_armv7a(target); return armv7a_handle_cache_info_command(CMD, &armv7a->armv7a_mmu.armv7a_cache); } COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd) { struct target *target = get_current_target(CMD_CTX); armv7a_l1_d_cache_clean_inval_all(target); return 0; } COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd) { struct target *target = get_current_target(CMD_CTX); uint32_t virt, size; if (CMD_ARGC == 0 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 2) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size); else size = 1; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt); return armv7a_l1_d_cache_inval_virt(target, virt, size); } COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd) { struct target *target = get_current_target(CMD_CTX); uint32_t virt, size; if (CMD_ARGC == 0 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 2) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size); else size = 1; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt); return armv7a_l1_d_cache_clean_virt(target, virt, size); } COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd) { struct target *target = get_current_target(CMD_CTX); armv7a_l1_i_cache_inval_all(target); return 0; } COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd) { struct target *target = get_current_target(CMD_CTX); uint32_t virt, size; if (CMD_ARGC == 0 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 2) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size); else size = 1; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt); return armv7a_l1_i_cache_inval_virt(target, virt, size); } COMMAND_HANDLER(arm7a_cache_disable_auto_cmd) { struct target *target = get_current_target(CMD_CTX); struct armv7a_common *armv7a = target_to_armv7a(target); if (CMD_ARGC == 0) { command_print(CMD, "auto cache is %s", armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled ? "enabled" : "disabled"); return ERROR_OK; } if (CMD_ARGC == 1) { uint32_t set; COMMAND_PARSE_ENABLE(CMD_ARGV[0], set); armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled = !!set; return ERROR_OK; } return ERROR_COMMAND_SYNTAX_ERROR; } static const struct command_registration arm7a_l1_d_cache_commands[] = { { .name = "flush_all", .handler = armv7a_l1_d_cache_clean_inval_all_cmd, .mode = COMMAND_ANY, .help = "flush (clean and invalidate) complete l1 d-cache", .usage = "", }, { .name = "inval", .handler = arm7a_l1_d_cache_inval_virt_cmd, .mode = COMMAND_ANY, .help = "invalidate l1 d-cache by virtual address offset and range size", .usage = "<virt_addr> [size]", }, { .name = "clean", .handler = arm7a_l1_d_cache_clean_virt_cmd, .mode = COMMAND_ANY, .help = "clean l1 d-cache by virtual address address offset and range size", .usage = "<virt_addr> [size]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration arm7a_l1_i_cache_commands[] = { { .name = "inval_all", .handler = armv7a_i_cache_clean_inval_all_cmd, .mode = COMMAND_ANY, .help = "invalidate complete l1 i-cache", .usage = "", }, { .name = "inval", .handler = arm7a_l1_i_cache_inval_virt_cmd, .mode = COMMAND_ANY, .help = "invalidate l1 i-cache by virtual address offset and range size", .usage = "<virt_addr> [size]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration arm7a_l1_di_cache_group_handlers[] = { { .name = "info", .handler = arm7a_l1_cache_info_cmd, .mode = COMMAND_ANY, .help = "print cache related information", .usage = "", }, { .name = "d", .mode = COMMAND_ANY, .help = "l1 d-cache command group", .usage = "", .chain = arm7a_l1_d_cache_commands, }, { .name = "i", .mode = COMMAND_ANY, .help = "l1 i-cache command group", .usage = "", .chain = arm7a_l1_i_cache_commands, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration arm7a_cache_group_handlers[] = { { .name = "auto", .handler = arm7a_cache_disable_auto_cmd, .mode = COMMAND_ANY, .help = "disable or enable automatic cache handling.", .usage = "(1|0)", }, { .name = "l1", .mode = COMMAND_ANY, .help = "l1 cache command group", .usage = "", .chain = arm7a_l1_di_cache_group_handlers, }, { .chain = arm7a_l2x_cache_command_handler, }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm7a_cache_command_handlers[] = { { .name = "cache", .mode = COMMAND_ANY, .help = "cache command group", .usage = "", .chain = arm7a_cache_group_handlers, }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv7a_cache.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2015 Oleksij Rempel * * linux@rempel-privat.de * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM7A_CACHE_H #define OPENOCD_TARGET_ARM7A_CACHE_H #include "arm_jtag.h" #include "armv7a_cache_l2x.h" int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, unsigned int size); int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, uint32_t size); int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt, unsigned int size); int armv7a_l1_i_cache_inval_all(struct target *target); int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt, uint32_t size); int armv7a_cache_auto_flush_on_write(struct target *target, uint32_t virt, uint32_t size); int armv7a_cache_auto_flush_all_data(struct target *target); int armv7a_cache_flush_virt(struct target *target, uint32_t virt, uint32_t size); extern const struct command_registration arm7a_cache_command_handlers[]; /* CLIDR cache types */ #define CACHE_LEVEL_HAS_UNIFIED_CACHE 0x4 #define CACHE_LEVEL_HAS_D_CACHE 0x2 #define CACHE_LEVEL_HAS_I_CACHE 0x1 #endif /* OPENOCD_TARGET_ARM7A_CACHE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv7a_cache_l2x.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2015 by Oleksij Rempel * * linux@rempel-privat.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/interface.h" #include "arm.h" #include "armv7a.h" #include "armv7a_cache.h" #include <helper/time_support.h> #include "target.h" #include "target_type.h" #include "smp.h" static int arm7a_l2x_sanity_check(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) (armv7a->armv7a_mmu.armv7a_cache.outer_cache); if (target->state != TARGET_HALTED) { LOG_ERROR("%s: target not halted", __func__); return ERROR_TARGET_NOT_HALTED; } if (!l2x_cache || !l2x_cache->base) { LOG_DEBUG("l2x is not configured!"); return ERROR_FAIL; } return ERROR_OK; } /* * clean and invalidate complete l2x cache */ int arm7a_l2x_flush_all_data(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) (armv7a->armv7a_mmu.armv7a_cache.outer_cache); uint32_t l2_way_val; int retval; retval = arm7a_l2x_sanity_check(target); if (retval) return retval; l2_way_val = (1 << l2x_cache->way) - 1; return target_write_phys_u32(target, l2x_cache->base + L2X0_CLEAN_INV_WAY, l2_way_val); } int armv7a_l2x_cache_flush_virt(struct target *target, target_addr_t virt, uint32_t size) { struct armv7a_common *armv7a = target_to_armv7a(target); struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) (armv7a->armv7a_mmu.armv7a_cache.outer_cache); /* FIXME: different controllers have different linelen? */ uint32_t i, linelen = 32; int retval; retval = arm7a_l2x_sanity_check(target); if (retval) return retval; for (i = 0; i < size; i += linelen) { target_addr_t pa, offs = virt + i; /* FIXME: use less verbose virt2phys? */ retval = target->type->virt2phys(target, offs, &pa); if (retval != ERROR_OK) goto done; retval = target_write_phys_u32(target, l2x_cache->base + L2X0_CLEAN_INV_LINE_PA, pa); if (retval != ERROR_OK) goto done; } return retval; done: LOG_ERROR("d-cache invalidate failed"); return retval; } static int armv7a_l2x_cache_inval_virt(struct target *target, target_addr_t virt, uint32_t size) { struct armv7a_common *armv7a = target_to_armv7a(target); struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) (armv7a->armv7a_mmu.armv7a_cache.outer_cache); /* FIXME: different controllers have different linelen */ uint32_t i, linelen = 32; int retval; retval = arm7a_l2x_sanity_check(target); if (retval) return retval; for (i = 0; i < size; i += linelen) { target_addr_t pa, offs = virt + i; /* FIXME: use less verbose virt2phys? */ retval = target->type->virt2phys(target, offs, &pa); if (retval != ERROR_OK) goto done; retval = target_write_phys_u32(target, l2x_cache->base + L2X0_INV_LINE_PA, pa); if (retval != ERROR_OK) goto done; } return retval; done: LOG_ERROR("d-cache invalidate failed"); return retval; } static int armv7a_l2x_cache_clean_virt(struct target *target, target_addr_t virt, unsigned int size) { struct armv7a_common *armv7a = target_to_armv7a(target); struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) (armv7a->armv7a_mmu.armv7a_cache.outer_cache); /* FIXME: different controllers have different linelen */ uint32_t i, linelen = 32; int retval; retval = arm7a_l2x_sanity_check(target); if (retval) return retval; for (i = 0; i < size; i += linelen) { target_addr_t pa, offs = virt + i; /* FIXME: use less verbose virt2phys? */ retval = target->type->virt2phys(target, offs, &pa); if (retval != ERROR_OK) goto done; retval = target_write_phys_u32(target, l2x_cache->base + L2X0_CLEAN_LINE_PA, pa); if (retval != ERROR_OK) goto done; } return retval; done: LOG_ERROR("d-cache invalidate failed"); return retval; } static int arm7a_handle_l2x_cache_info_command(struct command_invocation *cmd, struct armv7a_cache_common *armv7a_cache) { struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) (armv7a_cache->outer_cache); if (armv7a_cache->info == -1) { command_print(cmd, "cache not yet identified"); return ERROR_OK; } command_print(cmd, "L2 unified cache Base Address 0x%" PRIx32 ", %" PRIu32 " ways", l2x_cache->base, l2x_cache->way); return ERROR_OK; } static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way) { struct armv7a_l2x_cache *l2x_cache; struct target_list *head; struct armv7a_common *armv7a = target_to_armv7a(target); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) { LOG_ERROR("L2 cache was already initialised\n"); return ERROR_FAIL; } l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache)); l2x_cache->base = base; l2x_cache->way = way; armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; /* initialize all targets in this cluster (smp target) * l2 cache must be configured after smp declaration */ foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (curr != target) { armv7a = target_to_armv7a(curr); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) { LOG_ERROR("smp target : cache l2 already initialized\n"); return ERROR_FAIL; } armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; } } return ERROR_OK; } COMMAND_HANDLER(arm7a_l2x_cache_info_command) { struct target *target = get_current_target(CMD_CTX); struct armv7a_common *armv7a = target_to_armv7a(target); int retval; retval = arm7a_l2x_sanity_check(target); if (retval) return retval; return arm7a_handle_l2x_cache_info_command(CMD, &armv7a->armv7a_mmu.armv7a_cache); } COMMAND_HANDLER(arm7a_l2x_cache_flush_all_command) { struct target *target = get_current_target(CMD_CTX); return arm7a_l2x_flush_all_data(target); } COMMAND_HANDLER(arm7a_l2x_cache_flush_virt_cmd) { struct target *target = get_current_target(CMD_CTX); target_addr_t virt; uint32_t size; if (CMD_ARGC == 0 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 2) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size); else size = 1; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], virt); return armv7a_l2x_cache_flush_virt(target, virt, size); } COMMAND_HANDLER(arm7a_l2x_cache_inval_virt_cmd) { struct target *target = get_current_target(CMD_CTX); target_addr_t virt; uint32_t size; if (CMD_ARGC == 0 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 2) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size); else size = 1; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], virt); return armv7a_l2x_cache_inval_virt(target, virt, size); } COMMAND_HANDLER(arm7a_l2x_cache_clean_virt_cmd) { struct target *target = get_current_target(CMD_CTX); target_addr_t virt; uint32_t size; if (CMD_ARGC == 0 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 2) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size); else size = 1; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], virt); return armv7a_l2x_cache_clean_virt(target, virt, size); } /* FIXME: should we configure way size? or controller type? */ COMMAND_HANDLER(armv7a_l2x_cache_conf_cmd) { struct target *target = get_current_target(CMD_CTX); uint32_t base, way; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; /* command_print(CMD, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], base); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], way); /* AP address is in bits 31:24 of DP_SELECT */ return armv7a_l2x_cache_init(target, base, way); } static const struct command_registration arm7a_l2x_cache_commands[] = { { .name = "conf", .handler = armv7a_l2x_cache_conf_cmd, .mode = COMMAND_ANY, .help = "configure l2x cache", .usage = "<base_addr> <number_of_way>", }, { .name = "info", .handler = arm7a_l2x_cache_info_command, .mode = COMMAND_ANY, .help = "print cache related information", .usage = "", }, { .name = "flush_all", .handler = arm7a_l2x_cache_flush_all_command, .mode = COMMAND_ANY, .help = "flush complete l2x cache", .usage = "", }, { .name = "flush", .handler = arm7a_l2x_cache_flush_virt_cmd, .mode = COMMAND_ANY, .help = "flush (clean and invalidate) l2x cache by virtual address offset and range size", .usage = "<virt_addr> [size]", }, { .name = "inval", .handler = arm7a_l2x_cache_inval_virt_cmd, .mode = COMMAND_ANY, .help = "invalidate l2x cache by virtual address offset and range size", .usage = "<virt_addr> [size]", }, { .name = "clean", .handler = arm7a_l2x_cache_clean_virt_cmd, .mode = COMMAND_ANY, .help = "clean l2x cache by virtual address address offset and range size", .usage = "<virt_addr> [size]", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm7a_l2x_cache_command_handler[] = { { .name = "l2x", .mode = COMMAND_ANY, .help = "l2x cache command group", .usage = "", .chain = arm7a_l2x_cache_commands, }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv7a_cache_l2x.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2015 Oleksij Rempel * * linux@rempel-privat.de * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM7A_CACHE_L2X_H #define OPENOCD_TARGET_ARM7A_CACHE_L2X_H #define L2X0_CACHE_LINE_SIZE 32 /* source: linux/arch/arm/include/asm/hardware/cache-l2x0.h */ #define L2X0_CACHE_ID 0x000 #define L2X0_CACHE_TYPE 0x004 #define L2X0_CTRL 0x100 #define L2X0_AUX_CTRL 0x104 #define L2X0_TAG_LATENCY_CTRL 0x108 #define L2X0_DATA_LATENCY_CTRL 0x10C #define L2X0_EVENT_CNT_CTRL 0x200 #define L2X0_EVENT_CNT1_CFG 0x204 #define L2X0_EVENT_CNT0_CFG 0x208 #define L2X0_EVENT_CNT1_VAL 0x20C #define L2X0_EVENT_CNT0_VAL 0x210 #define L2X0_INTR_MASK 0x214 #define L2X0_MASKED_INTR_STAT 0x218 #define L2X0_RAW_INTR_STAT 0x21C #define L2X0_INTR_CLEAR 0x220 #define L2X0_CACHE_SYNC 0x730 #define L2X0_DUMMY_REG 0x740 #define L2X0_INV_LINE_PA 0x770 #define L2X0_INV_WAY 0x77C #define L2X0_CLEAN_LINE_PA 0x7B0 #define L2X0_CLEAN_LINE_IDX 0x7B8 #define L2X0_CLEAN_WAY 0x7BC #define L2X0_CLEAN_INV_LINE_PA 0x7F0 #define L2X0_CLEAN_INV_LINE_IDX 0x7F8 #define L2X0_CLEAN_INV_WAY 0x7FC /* * The lockdown registers repeat 8 times for L310, the L210 has only one * D and one I lockdown register at 0x0900 and 0x0904. */ #define L2X0_LOCKDOWN_WAY_D_BASE 0x900 #define L2X0_LOCKDOWN_WAY_I_BASE 0x904 #define L2X0_LOCKDOWN_STRIDE 0x08 #define L2X0_ADDR_FILTER_START 0xC00 #define L2X0_ADDR_FILTER_END 0xC04 #define L2X0_TEST_OPERATION 0xF00 #define L2X0_LINE_DATA 0xF10 #define L2X0_LINE_TAG 0xF30 #define L2X0_DEBUG_CTRL 0xF40 #define L2X0_PREFETCH_CTRL 0xF60 #define L2X0_POWER_CTRL 0xF80 #define L2X0_DYNAMIC_CLK_GATING_EN (1 << 1) #define L2X0_STNDBY_MODE_EN (1 << 0) /* Registers shifts and masks */ #define L2X0_CACHE_ID_PART_MASK (0xf << 6) #define L2X0_CACHE_ID_PART_L210 (1 << 6) #define L2X0_CACHE_ID_PART_L310 (3 << 6) #define L2X0_CACHE_ID_RTL_MASK 0x3f #define L2X0_CACHE_ID_RTL_R0P0 0x0 #define L2X0_CACHE_ID_RTL_R1P0 0x2 #define L2X0_CACHE_ID_RTL_R2P0 0x4 #define L2X0_CACHE_ID_RTL_R3P0 0x5 #define L2X0_CACHE_ID_RTL_R3P1 0x6 #define L2X0_CACHE_ID_RTL_R3P2 0x8 #define L2X0_AUX_CTRL_MASK 0xc0000fff #define L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT 0 #define L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK 0x7 #define L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT 3 #define L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK (0x7 << 3) #define L2X0_AUX_CTRL_TAG_LATENCY_SHIFT 6 #define L2X0_AUX_CTRL_TAG_LATENCY_MASK (0x7 << 6) #define L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT 9 #define L2X0_AUX_CTRL_DIRTY_LATENCY_MASK (0x7 << 9) #define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT 16 #define L2X0_AUX_CTRL_WAY_SIZE_SHIFT 17 #define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x7 << 17) #define L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT 22 #define L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT 26 #define L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT 27 #define L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT 28 #define L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT 29 #define L2X0_AUX_CTRL_EARLY_BRESP_SHIFT 30 #define L2X0_LATENCY_CTRL_SETUP_SHIFT 0 #define L2X0_LATENCY_CTRL_RD_SHIFT 4 #define L2X0_LATENCY_CTRL_WR_SHIFT 8 #define L2X0_ADDR_FILTER_EN 1 #define L2X0_CTRL_EN 1 #define L2X0_WAY_SIZE_SHIFT 3 struct l2x0_regs { unsigned long phy_base; unsigned long aux_ctrl; /* * Whether the following registers need to be saved/restored * depends on platform */ unsigned long tag_latency; unsigned long data_latency; unsigned long filter_start; unsigned long filter_end; unsigned long prefetch_ctrl; unsigned long pwr_ctrl; unsigned long ctrl; unsigned long aux2_ctrl; }; struct outer_cache_fns { void (*inv_range)(unsigned long, unsigned long); void (*clean_range)(unsigned long, unsigned long); void (*flush_range)(unsigned long, unsigned long); void (*flush_all)(void); void (*disable)(void); void (*resume)(void); /* This is an ARM L2C thing */ void (*write_sec)(unsigned long, unsigned); void (*configure)(const struct l2x0_regs *); }; struct l2c_init_data { const char *type; unsigned way_size_0; unsigned num_lock; void (*enable)(uint32_t, uint32_t, unsigned); void (*fixup)(uint32_t, uint32_t, struct outer_cache_fns *); void (*save)(uint32_t); void (*configure)(uint32_t); struct outer_cache_fns outer_cache; }; extern const struct command_registration arm7a_l2x_cache_command_handler[]; int armv7a_l2x_cache_flush_virt(struct target *target, target_addr_t virt, uint32_t size); int arm7a_l2x_flush_all_data(struct target *target); #endif /* OPENOCD_TARGET_ARM7A_CACHE_L2X_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv7a_mmu.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2016 by Matthias Welwarsky * * matthias.welwarsky@sysgo.com * * * * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/binarybuffer.h> #include <helper/command.h> #include "jtag/interface.h" #include "arm.h" #include "armv7a.h" #include "armv7a_mmu.h" #include "arm_opcodes.h" #include "cortex_a.h" #define SCTLR_BIT_AFE (1 << 29) /* V7 method VA TO PA */ int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, target_addr_t *val, int meminfo) { int retval = ERROR_FAIL; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t virt = va & ~0xfff, value; uint32_t NOS, NS, INNER, OUTER, SS; *val = 0xdeadbeef; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* mmu must be enable in order to get a correct translation * use VA to PA CP15 register for conversion */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 8, 0), virt); if (retval != ERROR_OK) goto done; retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 7, 4, 0), &value); if (retval != ERROR_OK) goto done; /* decode memory attribute */ SS = (value >> 1) & 1; NOS = (value >> 10) & 1; /* Not Outer shareable */ NS = (value >> 9) & 1; /* Non secure */ INNER = (value >> 4) & 0x7; OUTER = (value >> 2) & 0x3; if (SS) { /* PAR[31:24] contains PA[31:24] */ *val = value & 0xff000000; /* PAR [23:16] contains PA[39:32] */ *val |= (target_addr_t)(value & 0x00ff0000) << 16; /* PA[23:12] is the same as VA[23:12] */ *val |= (va & 0xffffff); } else { *val = (value & ~0xfff) + (va & 0xfff); } if (meminfo) { LOG_INFO("%" PRIx32 " : %" TARGET_PRIxADDR " %s outer shareable %s secured %s super section", va, *val, NOS == 1 ? "not" : " ", NS == 1 ? "not" : "", SS == 0 ? "not" : ""); switch (OUTER) { case 0: LOG_INFO("outer: Non-Cacheable"); break; case 1: LOG_INFO("outer: Write-Back, Write-Allocate"); break; case 2: LOG_INFO("outer: Write-Through, No Write-Allocate"); break; case 3: LOG_INFO("outer: Write-Back, no Write-Allocate"); break; } switch (INNER) { case 0: LOG_INFO("inner: Non-Cacheable"); break; case 1: LOG_INFO("inner: Strongly-ordered"); break; case 3: LOG_INFO("inner: Device"); break; case 5: LOG_INFO("inner: Write-Back, Write-Allocate"); break; case 6: LOG_INFO("inner: Write-Through"); break; case 7: LOG_INFO("inner: Write-Back, no Write-Allocate"); break; default: LOG_INFO("inner: %" PRIx32 " ???", INNER); } } done: dpm->finish(dpm); return retval; } static const char *desc_bits_to_string(bool c_bit, bool b_bit, bool s_bit, bool ap2, int ap10, bool afe) { static char bits_string[64]; unsigned int len; if (afe) { bool acc_r = true; bool acc_w = !ap2; bool priv = !(ap10 & 2); len = snprintf(bits_string, sizeof(bits_string), "%s%s%s access%s: %s%s", s_bit ? "S " : "", c_bit ? "C " : "", b_bit ? "B " : "", priv ? "(priv)" : "", acc_r ? "R" : "N", acc_w ? "W " : "O "); } else { bool priv_acc_w = !ap2; bool priv_acc_r = true; bool unpriv_acc_w = priv_acc_w; bool unpriv_acc_r = priv_acc_r; switch (ap10) { case 0: priv_acc_r = priv_acc_w = false; unpriv_acc_r = unpriv_acc_w = false; break; case 1: unpriv_acc_r = unpriv_acc_w = false; break; case 2: unpriv_acc_w = false; break; default: break; } len = snprintf(bits_string, sizeof(bits_string), "%s%s%s access(priv): %s%s access(unpriv): %s%s", s_bit ? "S " : "", c_bit ? "C " : "", b_bit ? "B " : "", priv_acc_r ? "R" : "N", priv_acc_w ? "W" : "O", unpriv_acc_r ? "R" : "N", unpriv_acc_w ? "W" : "O"); } if (len >= sizeof(bits_string)) bits_string[63] = 0; return bits_string; } static const char *l2_desc_bits_to_string(uint32_t l2_desc, bool afe) { bool c_bit = !!(l2_desc & (1 << 3)); bool b_bit = !!(l2_desc & (1 << 2)); bool s_bit = !!(l2_desc & (1 << 10)); bool ap2 = !!(l2_desc & (1 << 9)); int ap10 = (l2_desc >> 4) & 3; return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe); } static const char *l1_desc_bits_to_string(uint32_t l1_desc, bool afe) { bool c_bit = !!(l1_desc & (1 << 3)); bool b_bit = !!(l1_desc & (1 << 2)); bool s_bit = !!(l1_desc & (1 << 16)); bool ap2 = !!(l1_desc & (1 << 15)); int ap10 = (l1_desc >> 10) & 3; return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe); } COMMAND_HANDLER(armv7a_mmu_dump_table) { struct target *target = get_current_target(CMD_CTX); struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = target_to_armv7a(target); struct armv7a_mmu_common *mmu = &armv7a->armv7a_mmu; struct armv7a_cache_common *cache = &mmu->armv7a_cache; uint32_t *first_lvl_ptbl; target_addr_t ttb; int ttbidx = 0; int retval; int pt_idx; int max_pt_idx = 4095; bool afe; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (!strcmp(CMD_ARGV[0], "addr")) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[1], ttb); if (CMD_ARGC > 2) { COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], max_pt_idx); if (max_pt_idx < 1 || max_pt_idx > 4096) return ERROR_COMMAND_ARGUMENT_INVALID; max_pt_idx -= 1; } } else { if (mmu->cached != 1) { LOG_ERROR("TTB not cached!"); return ERROR_FAIL; } COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], ttbidx); if (ttbidx < 0 || ttbidx > 1) return ERROR_COMMAND_ARGUMENT_INVALID; ttb = mmu->ttbr[ttbidx] & mmu->ttbr_mask[ttbidx]; if (ttbidx == 0) { int ttbcr_n = mmu->ttbcr & 0x7; max_pt_idx = 0x0fff >> ttbcr_n; } } LOG_USER("Page Directory at (phys): %8.8" TARGET_PRIxADDR, ttb); first_lvl_ptbl = malloc(sizeof(uint32_t)*(max_pt_idx+1)); if (!first_lvl_ptbl) return ERROR_FAIL; /* * this may or may not be necessary depending on whether * the table walker is configured to use the cache or not. */ cache->flush_all_data_cache(target); retval = mmu->read_physical_memory(target, ttb, 4, max_pt_idx+1, (uint8_t *)first_lvl_ptbl); if (retval != ERROR_OK) { LOG_ERROR("Failed to read first-level page table!"); return retval; } afe = !!(cortex_a->cp15_control_reg & SCTLR_BIT_AFE); for (pt_idx = 0; pt_idx <= max_pt_idx;) { uint32_t first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)&first_lvl_ptbl[pt_idx]); LOG_DEBUG("L1 desc[%8.8x]: %8.8"PRIx32, pt_idx << 20, first_lvl_descriptor); /* skip empty entries in the first level table */ if ((first_lvl_descriptor & 3) == 0) { pt_idx++; } else if ((first_lvl_descriptor & 0x40002) == 2) { /* section descriptor */ uint32_t va_range = 1024*1024-1; /* 1MB range */ uint32_t va_start = pt_idx << 20; uint32_t va_end = va_start + va_range; uint32_t pa_start = (first_lvl_descriptor & 0xfff00000); uint32_t pa_end = pa_start + va_range; LOG_USER("SECT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s", va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe)); pt_idx++; } else if ((first_lvl_descriptor & 0x40002) == 0x40002) { /* supersection descriptor */ uint32_t va_range = 16*1024*1024-1; /* 16MB range */ uint32_t va_start = pt_idx << 20; uint32_t va_end = va_start + va_range; uint32_t pa_start = (first_lvl_descriptor & 0xff000000); uint32_t pa_end = pa_start + va_range; LOG_USER("SSCT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s", va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe)); /* skip next 15 entries, they're duplicating the first entry */ pt_idx += 16; } else { target_addr_t second_lvl_ptbl = first_lvl_descriptor & 0xfffffc00; uint32_t second_lvl_descriptor; uint32_t *pt2; int pt2_idx; /* page table, always 1KB long */ pt2 = malloc(1024); retval = mmu->read_physical_memory(target, second_lvl_ptbl, 4, 256, (uint8_t *)pt2); if (retval != ERROR_OK) { LOG_ERROR("Failed to read second-level page table!"); return ERROR_FAIL; } for (pt2_idx = 0; pt2_idx < 256; ) { second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)&pt2[pt2_idx]); if ((second_lvl_descriptor & 3) == 0) { /* skip entry */ pt2_idx++; } else if ((second_lvl_descriptor & 3) == 1) { /* large page */ uint32_t va_range = 64*1024-1; /* 64KB range */ uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12); uint32_t va_end = va_start + va_range; uint32_t pa_start = (second_lvl_descriptor & 0xffff0000); uint32_t pa_end = pa_start + va_range; LOG_USER("LPGE: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s", va_start, va_end, pa_start, pa_end, l2_desc_bits_to_string(second_lvl_descriptor, afe)); pt2_idx += 16; } else { /* small page */ uint32_t va_range = 4*1024-1; /* 4KB range */ uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12); uint32_t va_end = va_start + va_range; uint32_t pa_start = (second_lvl_descriptor & 0xfffff000); uint32_t pa_end = pa_start + va_range; LOG_USER("SPGE: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s", va_start, va_end, pa_start, pa_end, l2_desc_bits_to_string(second_lvl_descriptor, afe)); pt2_idx++; } } free(pt2); pt_idx++; } } free(first_lvl_ptbl); return ERROR_OK; } static const struct command_registration armv7a_mmu_group_handlers[] = { { .name = "dump", .handler = armv7a_mmu_dump_table, .mode = COMMAND_ANY, .help = "dump translation table 0, 1 or from <address>", .usage = "(0|1|addr <address> [num_entries])", }, COMMAND_REGISTRATION_DONE }; const struct command_registration armv7a_mmu_command_handlers[] = { { .name = "mmu", .mode = COMMAND_ANY, .help = "mmu command group", .usage = "", .chain = armv7a_mmu_group_handlers, }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv7a_mmu.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2016 by Matthias Welwarsky * * matthias.welwarsky@sysgo.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV7A_MMU_H #define OPENOCD_TARGET_ARMV7A_MMU_H extern int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, target_addr_t *val, int meminfo); extern const struct command_registration armv7a_mmu_command_handlers[]; #endif /* OPENOCD_TARGET_ARMV7A_MMU_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv7m.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2018 by Liviu Ionescu * * <ilg@livius.net> * * * * Copyright (C) 2019 by Tomas Vanek * * vanekt@fbl.cz * * * * ARMv7-M Architecture, Application Level Reference Manual * * ARM DDI 0405C (September 2008) * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "breakpoints.h" #include "armv7m.h" #include "algorithm.h" #include "register.h" #include "semihosting_common.h" #include <helper/log.h> #include <helper/binarybuffer.h> #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif static const char * const armv7m_exception_strings[] = { "", "Reset", "NMI", "HardFault", "MemManage", "BusFault", "UsageFault", "SecureFault", "RESERVED", "RESERVED", "RESERVED", "SVCall", "DebugMonitor", "RESERVED", "PendSV", "SysTick" }; /* PSP is used in some thread modes */ const int armv7m_psp_reg_map[ARMV7M_NUM_CORE_REGS] = { ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3, ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7, ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11, ARMV7M_R12, ARMV7M_PSP, ARMV7M_R14, ARMV7M_PC, ARMV7M_XPSR, }; /* MSP is used in handler and some thread modes */ const int armv7m_msp_reg_map[ARMV7M_NUM_CORE_REGS] = { ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3, ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7, ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11, ARMV7M_R12, ARMV7M_MSP, ARMV7M_R14, ARMV7M_PC, ARMV7M_XPSR, }; /* * These registers are not memory-mapped. The ARMv7-M profile includes * memory mapped registers too, such as for the NVIC (interrupt controller) * and SysTick (timer) modules; those can mostly be treated as peripherals. * * The ARMv6-M profile is almost identical in this respect, except that it * doesn't include basepri or faultmask registers. */ static const struct { unsigned id; const char *name; unsigned bits; enum reg_type type; const char *group; const char *feature; } armv7m_regs[] = { { ARMV7M_R0, "r0", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R1, "r1", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R2, "r2", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R3, "r3", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R4, "r4", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R5, "r5", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R6, "r6", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R7, "r7", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R8, "r8", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R9, "r9", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R10, "r10", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R11, "r11", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R12, "r12", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R13, "sp", 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R14, "lr", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_PC, "pc", 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_XPSR, "xpsr", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_MSP, "msp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system" }, { ARMV7M_PSP, "psp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system" }, /* A working register for packing/unpacking special regs, hidden from gdb */ { ARMV7M_PMSK_BPRI_FLTMSK_CTRL, "pmsk_bpri_fltmsk_ctrl", 32, REG_TYPE_INT, NULL, NULL }, /* WARNING: If you use armv7m_write_core_reg() on one of 4 following * special registers, the new data go to ARMV7M_PMSK_BPRI_FLTMSK_CTRL * cache only and are not flushed to CPU HW register. * To trigger write to CPU HW register, add * armv7m_write_core_reg(,,ARMV7M_PMSK_BPRI_FLTMSK_CTRL,); */ { ARMV7M_PRIMASK, "primask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, { ARMV7M_BASEPRI, "basepri", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, { ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, { ARMV7M_CONTROL, "control", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, /* ARMv8-M security extension (TrustZone) specific registers */ { ARMV8M_MSP_NS, "msp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, { ARMV8M_PSP_NS, "psp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, { ARMV8M_MSP_S, "msp_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, { ARMV8M_PSP_S, "psp_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, { ARMV8M_MSPLIM_S, "msplim_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, { ARMV8M_PSPLIM_S, "psplim_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, { ARMV8M_MSPLIM_NS, "msplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, { ARMV8M_PSPLIM_NS, "psplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, { ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S, "pmsk_bpri_fltmsk_ctrl_s", 32, REG_TYPE_INT, NULL, NULL }, { ARMV8M_PRIMASK_S, "primask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, { ARMV8M_BASEPRI_S, "basepri_s", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, { ARMV8M_FAULTMASK_S, "faultmask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, { ARMV8M_CONTROL_S, "control_s", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, { ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS, "pmsk_bpri_fltmsk_ctrl_ns", 32, REG_TYPE_INT, NULL, NULL }, { ARMV8M_PRIMASK_NS, "primask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, { ARMV8M_BASEPRI_NS, "basepri_ns", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, { ARMV8M_FAULTMASK_NS, "faultmask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, { ARMV8M_CONTROL_NS, "control_ns", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, /* FPU registers */ { ARMV7M_D0, "d0", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D1, "d1", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D2, "d2", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D3, "d3", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D4, "d4", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D5, "d5", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D6, "d6", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D7, "d7", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D8, "d8", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D9, "d9", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D10, "d10", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D11, "d11", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D12, "d12", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D13, "d13", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D14, "d14", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D15, "d15", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_FPSCR, "fpscr", 32, REG_TYPE_INT, "float", "org.gnu.gdb.arm.vfp" }, }; #define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs) /** * Restores target context using the cache of core registers set up * by armv7m_build_reg_cache(), calling optional core-specific hooks. */ int armv7m_restore_context(struct target *target) { int i; struct armv7m_common *armv7m = target_to_armv7m(target); struct reg_cache *cache = armv7m->arm.core_cache; LOG_DEBUG(" "); if (armv7m->pre_restore_context) armv7m->pre_restore_context(target); /* The descending order of register writes is crucial for correct * packing of ARMV7M_PMSK_BPRI_FLTMSK_CTRL! * See also comments in the register table above */ for (i = cache->num_regs - 1; i >= 0; i--) { struct reg *r = &cache->reg_list[i]; if (r->exist && r->dirty) { int retval = armv7m->arm.write_core_reg(target, r, i, ARM_MODE_ANY, r->value); if (retval != ERROR_OK) return retval; } } return ERROR_OK; } /* Core state functions */ /** * Maps ISR number (from xPSR) to name. * Note that while names and meanings for the first sixteen are standardized * (with zero not a true exception), external interrupts are only numbered. * They are assigned by vendors, which generally assign different numbers to * peripherals (such as UART0 or a USB peripheral controller). */ const char *armv7m_exception_string(int number) { static char enamebuf[32]; if ((number < 0) | (number > 511)) return "Invalid exception"; if (number < 16) return armv7m_exception_strings[number]; sprintf(enamebuf, "External Interrupt(%i)", number - 16); return enamebuf; } static int armv7m_get_core_reg(struct reg *reg) { int retval; struct arm_reg *armv7m_reg = reg->arch_info; struct target *target = armv7m_reg->target; struct arm *arm = target_to_arm(target); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = arm->read_core_reg(target, reg, reg->number, arm->core_mode); return retval; } static int armv7m_set_core_reg(struct reg *reg, uint8_t *buf) { struct arm_reg *armv7m_reg = reg->arch_info; struct target *target = armv7m_reg->target; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; buf_cpy(buf, reg->value, reg->size); reg->dirty = true; reg->valid = true; return ERROR_OK; } uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id) { switch (arm_reg_id) { case ARMV7M_R0 ... ARMV7M_R14: case ARMV7M_PC: case ARMV7M_XPSR: case ARMV7M_MSP: case ARMV7M_PSP: /* NOTE: we "know" here that the register identifiers * match the Cortex-M DCRSR.REGSEL selectors values * for R0..R14, PC, xPSR, MSP, and PSP. */ return arm_reg_id; case ARMV7M_PMSK_BPRI_FLTMSK_CTRL: return ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL; case ARMV8M_MSP_NS...ARMV8M_PSPLIM_NS: return arm_reg_id - ARMV8M_MSP_NS + ARMV8M_REGSEL_MSP_NS; case ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S: return ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_S; case ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS: return ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_NS; case ARMV7M_FPSCR: return ARMV7M_REGSEL_FPSCR; case ARMV7M_D0 ... ARMV7M_D15: return ARMV7M_REGSEL_S0 + 2 * (arm_reg_id - ARMV7M_D0); default: LOG_ERROR("Bad register ID %u", arm_reg_id); return arm_reg_id; } } bool armv7m_map_reg_packing(unsigned int arm_reg_id, unsigned int *reg32_id, uint32_t *offset) { switch (arm_reg_id) { case ARMV7M_PRIMASK...ARMV7M_CONTROL: *reg32_id = ARMV7M_PMSK_BPRI_FLTMSK_CTRL; *offset = arm_reg_id - ARMV7M_PRIMASK; return true; case ARMV8M_PRIMASK_S...ARMV8M_CONTROL_S: *reg32_id = ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S; *offset = arm_reg_id - ARMV8M_PRIMASK_S; return true; case ARMV8M_PRIMASK_NS...ARMV8M_CONTROL_NS: *reg32_id = ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS; *offset = arm_reg_id - ARMV8M_PRIMASK_NS; return true; default: return false; } } static int armv7m_read_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode) { uint32_t reg_value; int retval; struct armv7m_common *armv7m = target_to_armv7m(target); assert(num < (int)armv7m->arm.core_cache->num_regs); assert(num == (int)r->number); /* If a code calls read_reg, it expects the cache is no more dirty. * Clear the dirty flag regardless of the later read succeeds or not * to prevent unwanted cache flush after a read error */ r->dirty = false; if (r->size <= 8) { /* any 8-bit or shorter register is packed */ uint32_t offset; unsigned int reg32_id; bool is_packed = armv7m_map_reg_packing(num, ®32_id, &offset); if (!is_packed) { /* We should not get here as all 8-bit or shorter registers * are packed */ assert(false); /* assert() does nothing if NDEBUG is defined */ return ERROR_FAIL; } struct reg *r32 = &armv7m->arm.core_cache->reg_list[reg32_id]; /* Read 32-bit container register if not cached */ if (!r32->valid) { retval = armv7m_read_core_reg(target, r32, reg32_id, mode); if (retval != ERROR_OK) return retval; } /* Copy required bits of 32-bit container register */ buf_cpy(r32->value + offset, r->value, r->size); } else { assert(r->size == 32 || r->size == 64); struct arm_reg *armv7m_core_reg = r->arch_info; uint32_t regsel = armv7m_map_id_to_regsel(armv7m_core_reg->num); retval = armv7m->load_core_reg_u32(target, regsel, ®_value); if (retval != ERROR_OK) return retval; buf_set_u32(r->value, 0, 32, reg_value); if (r->size == 64) { retval = armv7m->load_core_reg_u32(target, regsel + 1, ®_value); if (retval != ERROR_OK) { r->valid = false; return retval; } buf_set_u32(r->value + 4, 0, 32, reg_value); uint64_t q = buf_get_u64(r->value, 0, 64); LOG_DEBUG("read %s value 0x%016" PRIx64, r->name, q); } else { LOG_DEBUG("read %s value 0x%08" PRIx32, r->name, reg_value); } } r->valid = true; return ERROR_OK; } static int armv7m_write_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode, uint8_t *value) { int retval; uint32_t t; struct armv7m_common *armv7m = target_to_armv7m(target); assert(num < (int)armv7m->arm.core_cache->num_regs); assert(num == (int)r->number); if (value != r->value) { /* If we are not flushing the cache, store the new value to the cache */ buf_cpy(value, r->value, r->size); } if (r->size <= 8) { /* any 8-bit or shorter register is packed */ uint32_t offset; unsigned int reg32_id; bool is_packed = armv7m_map_reg_packing(num, ®32_id, &offset); if (!is_packed) { /* We should not get here as all 8-bit or shorter registers * are packed */ assert(false); /* assert() does nothing if NDEBUG is defined */ return ERROR_FAIL; } struct reg *r32 = &armv7m->arm.core_cache->reg_list[reg32_id]; if (!r32->valid) { /* Before merging with other parts ensure the 32-bit register is valid */ retval = armv7m_read_core_reg(target, r32, reg32_id, mode); if (retval != ERROR_OK) return retval; } /* Write a part to the 32-bit container register */ buf_cpy(value, r32->value + offset, r->size); r32->dirty = true; } else { assert(r->size == 32 || r->size == 64); struct arm_reg *armv7m_core_reg = r->arch_info; uint32_t regsel = armv7m_map_id_to_regsel(armv7m_core_reg->num); t = buf_get_u32(value, 0, 32); retval = armv7m->store_core_reg_u32(target, regsel, t); if (retval != ERROR_OK) goto out_error; if (r->size == 64) { t = buf_get_u32(value + 4, 0, 32); retval = armv7m->store_core_reg_u32(target, regsel + 1, t); if (retval != ERROR_OK) goto out_error; uint64_t q = buf_get_u64(value, 0, 64); LOG_DEBUG("write %s value 0x%016" PRIx64, r->name, q); } else { LOG_DEBUG("write %s value 0x%08" PRIx32, r->name, t); } } r->valid = true; r->dirty = false; return ERROR_OK; out_error: r->dirty = true; LOG_ERROR("Error setting register %s", r->name); return retval; } /** * Returns generic ARM userspace registers to GDB. */ int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { struct armv7m_common *armv7m = target_to_armv7m(target); int i, size; if (reg_class == REG_CLASS_ALL) size = armv7m->arm.core_cache->num_regs; else size = ARMV7M_NUM_CORE_REGS; *reg_list = malloc(sizeof(struct reg *) * size); if (!*reg_list) return ERROR_FAIL; for (i = 0; i < size; i++) (*reg_list)[i] = &armv7m->arm.core_cache->reg_list[i]; *reg_list_size = size; return ERROR_OK; } /** Runs a Thumb algorithm in the target. */ int armv7m_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { int retval; retval = armv7m_start_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_params, entry_point, exit_point, arch_info); if (retval == ERROR_OK) retval = armv7m_wait_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_params, exit_point, timeout_ms, arch_info); return retval; } /** Starts a Thumb algorithm in the target. */ int armv7m_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, void *arch_info) { struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_algorithm *armv7m_algorithm_info = arch_info; enum arm_mode core_mode = armv7m->arm.core_mode; int retval = ERROR_OK; /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) { LOG_ERROR("current target isn't an ARMV7M target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Store all non-debug execution registers to armv7m_algorithm_info context */ for (unsigned i = 0; i < armv7m->arm.core_cache->num_regs; i++) { struct reg *reg = &armv7m->arm.core_cache->reg_list[i]; if (!reg->exist) continue; if (!reg->valid) armv7m_get_core_reg(reg); if (!reg->valid) LOG_TARGET_WARNING(target, "Storing invalid register %s", reg->name); armv7m_algorithm_info->context[i] = buf_get_u32(reg->value, 0, 32); } for (int i = 0; i < num_mem_params; i++) { if (mem_params[i].direction == PARAM_IN) continue; retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } for (int i = 0; i < num_reg_params; i++) { if (reg_params[i].direction == PARAM_IN) continue; struct reg *reg = register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, false); /* uint32_t regvalue; */ if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */ armv7m_set_core_reg(reg, reg_params[i].value); } { /* * Ensure xPSR.T is set to avoid trying to run things in arm * (non-thumb) mode, which armv7m does not support. * * We do this by setting the entirety of xPSR, which should * remove all the unknowns about xPSR state. * * Because xPSR.T is populated on reset from the vector table, * it might be 0 if the vector table has "bad" data in it. */ struct reg *reg = &armv7m->arm.core_cache->reg_list[ARMV7M_XPSR]; buf_set_u32(reg->value, 0, 32, 0x01000000); reg->valid = true; reg->dirty = true; } if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY && armv7m_algorithm_info->core_mode != core_mode) { /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */ if (armv7m_algorithm_info->core_mode == ARM_MODE_HANDLER) { armv7m_algorithm_info->core_mode = ARM_MODE_THREAD; LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead"); } LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode); buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1, armv7m_algorithm_info->core_mode); armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = true; armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = true; } /* save previous core mode */ armv7m_algorithm_info->core_mode = core_mode; retval = target_resume(target, 0, entry_point, 1, 1); return retval; } /** Waits for an algorithm in the target. */ int armv7m_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_algorithm *armv7m_algorithm_info = arch_info; int retval = ERROR_OK; /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) { LOG_ERROR("current target isn't an ARMV7M target"); return ERROR_TARGET_INVALID; } retval = target_wait_state(target, TARGET_HALTED, timeout_ms); /* If the target fails to halt due to the breakpoint, force a halt */ if (retval != ERROR_OK || target->state != TARGET_HALTED) { retval = target_halt(target); if (retval != ERROR_OK) return retval; retval = target_wait_state(target, TARGET_HALTED, 500); if (retval != ERROR_OK) return retval; return ERROR_TARGET_TIMEOUT; } if (exit_point) { /* PC value has been cached in cortex_m_debug_entry() */ uint32_t pc = buf_get_u32(armv7m->arm.pc->value, 0, 32); if (pc != exit_point) { LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" TARGET_PRIxADDR, pc, exit_point); return ERROR_TARGET_ALGO_EXIT; } } /* Read memory values to mem_params[] */ for (int i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) { retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } } /* Copy core register values to reg_params[] */ for (int i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR( "BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } for (int i = armv7m->arm.core_cache->num_regs - 1; i >= 0; i--) { struct reg *reg = &armv7m->arm.core_cache->reg_list[i]; if (!reg->exist) continue; uint32_t regvalue; regvalue = buf_get_u32(reg->value, 0, 32); if (regvalue != armv7m_algorithm_info->context[i]) { LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, reg->name, armv7m_algorithm_info->context[i]); buf_set_u32(reg->value, 0, 32, armv7m_algorithm_info->context[i]); reg->valid = true; reg->dirty = true; } } /* restore previous core mode */ if (armv7m_algorithm_info->core_mode != armv7m->arm.core_mode) { LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode); buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1, armv7m_algorithm_info->core_mode); armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = true; armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = true; } armv7m->arm.core_mode = armv7m_algorithm_info->core_mode; return retval; } /** Logs summary of ARMv7-M state for a halted target. */ int armv7m_arch_state(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); struct arm *arm = &armv7m->arm; uint32_t ctrl, sp; /* avoid filling log waiting for fileio reply */ if (target->semihosting && target->semihosting->hit_fileio) return ERROR_OK; ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32); sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32); LOG_USER("[%s] halted due to %s, current mode: %s %s\n" "xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s%s", target_name(target), debug_reason_name(target), arm_mode_name(arm->core_mode), armv7m_exception_string(armv7m->exception_number), buf_get_u32(arm->cpsr->value, 0, 32), buf_get_u32(arm->pc->value, 0, 32), (ctrl & 0x02) ? 'p' : 'm', sp, (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "", (target->semihosting && target->semihosting->is_fileio) ? " fileio" : ""); return ERROR_OK; } static const struct reg_arch_type armv7m_reg_type = { .get = armv7m_get_core_reg, .set = armv7m_set_core_reg, }; /** Builds cache of architecturally defined registers. */ struct reg_cache *armv7m_build_reg_cache(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); struct arm *arm = &armv7m->arm; int num_regs = ARMV7M_NUM_REGS; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); struct arm_reg *arch_info = calloc(num_regs, sizeof(struct arm_reg)); struct reg_feature *feature; int i; /* Build the process context cache */ cache->name = "arm v7m registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = num_regs; (*cache_p) = cache; for (i = 0; i < num_regs; i++) { arch_info[i].num = armv7m_regs[i].id; arch_info[i].target = target; arch_info[i].arm = arm; reg_list[i].name = armv7m_regs[i].name; reg_list[i].size = armv7m_regs[i].bits; reg_list[i].value = arch_info[i].value; reg_list[i].dirty = false; reg_list[i].valid = false; reg_list[i].hidden = (i == ARMV7M_PMSK_BPRI_FLTMSK_CTRL || i == ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS || i == ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S); reg_list[i].type = &armv7m_reg_type; reg_list[i].arch_info = &arch_info[i]; reg_list[i].group = armv7m_regs[i].group; reg_list[i].number = i; reg_list[i].exist = true; reg_list[i].caller_save = true; /* gdb defaults to true */ if (reg_list[i].hidden) continue; feature = calloc(1, sizeof(struct reg_feature)); if (feature) { feature->name = armv7m_regs[i].feature; reg_list[i].feature = feature; } else LOG_ERROR("unable to allocate feature list"); reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); if (reg_list[i].reg_data_type) reg_list[i].reg_data_type->type = armv7m_regs[i].type; else LOG_ERROR("unable to allocate reg type list"); } arm->cpsr = reg_list + ARMV7M_XPSR; arm->pc = reg_list + ARMV7M_PC; arm->core_cache = cache; return cache; } void armv7m_free_reg_cache(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); struct arm *arm = &armv7m->arm; struct reg_cache *cache; struct reg *reg; unsigned int i; cache = arm->core_cache; if (!cache) return; for (i = 0; i < cache->num_regs; i++) { reg = &cache->reg_list[i]; free(reg->feature); free(reg->reg_data_type); } free(cache->reg_list[0].arch_info); free(cache->reg_list); free(cache); arm->core_cache = NULL; } static int armv7m_setup_semihosting(struct target *target, int enable) { /* nothing todo for armv7m */ return ERROR_OK; } /** Sets up target as a generic ARMv7-M core */ int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m) { struct arm *arm = &armv7m->arm; armv7m->common_magic = ARMV7M_COMMON_MAGIC; armv7m->fp_feature = FP_NONE; armv7m->trace_config.trace_bus_id = 1; /* Enable stimulus port #0 by default */ armv7m->trace_config.itm_ter[0] = 1; arm->core_state = ARM_STATE_THUMB; arm->core_type = ARM_CORE_TYPE_M_PROFILE; arm->arch_info = armv7m; arm->setup_semihosting = armv7m_setup_semihosting; arm->read_core_reg = armv7m_read_core_reg; arm->write_core_reg = armv7m_write_core_reg; return arm_init_arch_info(target, arm); } /** Generates a CRC32 checksum of a memory region. */ int armv7m_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct armv7m_algorithm armv7m_info; struct reg_param reg_params[2]; int retval; static const uint8_t cortex_m_crc_code[] = { #include "../../contrib/loaders/checksum/armv7m_crc.inc" }; retval = target_alloc_working_area(target, sizeof(cortex_m_crc_code), &crc_algorithm); if (retval != ERROR_OK) return retval; retval = target_write_buffer(target, crc_algorithm->address, sizeof(cortex_m_crc_code), (uint8_t *)cortex_m_crc_code); if (retval != ERROR_OK) goto cleanup; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, count); unsigned int timeout = 20000 * (1 + (count / (1024 * 1024))); retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, crc_algorithm->address + (sizeof(cortex_m_crc_code) - 6), timeout, &armv7m_info); if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); else LOG_ERROR("error executing cortex_m crc algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); cleanup: target_free_working_area(target, crc_algorithm); return retval; } /** Checks an array of memory regions whether they are erased. */ int armv7m_blank_check_memory(struct target *target, struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value) { struct working_area *erase_check_algorithm; struct working_area *erase_check_params; struct reg_param reg_params[2]; struct armv7m_algorithm armv7m_info; int retval; static bool timed_out; static const uint8_t erase_check_code[] = { #include "../../contrib/loaders/erase_check/armv7m_erase_check.inc" }; const uint32_t code_size = sizeof(erase_check_code); /* make sure we have a working area */ if (target_alloc_working_area(target, code_size, &erase_check_algorithm) != ERROR_OK) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; retval = target_write_buffer(target, erase_check_algorithm->address, code_size, erase_check_code); if (retval != ERROR_OK) goto cleanup1; /* prepare blocks array for algo */ struct algo_block { union { uint32_t size; uint32_t result; }; uint32_t address; }; uint32_t avail = target_get_working_area_avail(target); int blocks_to_check = avail / sizeof(struct algo_block) - 1; if (num_blocks < blocks_to_check) blocks_to_check = num_blocks; struct algo_block *params = malloc((blocks_to_check+1)*sizeof(struct algo_block)); if (!params) { retval = ERROR_FAIL; goto cleanup1; } int i; uint32_t total_size = 0; for (i = 0; i < blocks_to_check; i++) { total_size += blocks[i].size; target_buffer_set_u32(target, (uint8_t *)&(params[i].size), blocks[i].size / sizeof(uint32_t)); target_buffer_set_u32(target, (uint8_t *)&(params[i].address), blocks[i].address); } target_buffer_set_u32(target, (uint8_t *)&(params[blocks_to_check].size), 0); uint32_t param_size = (blocks_to_check + 1) * sizeof(struct algo_block); if (target_alloc_working_area(target, param_size, &erase_check_params) != ERROR_OK) { retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; goto cleanup2; } retval = target_write_buffer(target, erase_check_params->address, param_size, (uint8_t *)params); if (retval != ERROR_OK) goto cleanup3; uint32_t erased_word = erased_value | (erased_value << 8) | (erased_value << 16) | (erased_value << 24); LOG_DEBUG("Starting erase check of %d blocks, parameters@" TARGET_ADDR_FMT, blocks_to_check, erase_check_params->address); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, erase_check_params->address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, erased_word); /* assume CPU clk at least 1 MHz */ unsigned int timeout = (timed_out ? 30000 : 2000) + total_size * 3 / 1000; retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, erase_check_algorithm->address, erase_check_algorithm->address + (code_size - 2), timeout, &armv7m_info); timed_out = retval == ERROR_TARGET_TIMEOUT; if (retval != ERROR_OK && !timed_out) goto cleanup4; retval = target_read_buffer(target, erase_check_params->address, param_size, (uint8_t *)params); if (retval != ERROR_OK) goto cleanup4; for (i = 0; i < blocks_to_check; i++) { uint32_t result = target_buffer_get_u32(target, (uint8_t *)&(params[i].result)); if (result != 0 && result != 1) break; blocks[i].result = result; } if (i && timed_out) LOG_INFO("Slow CPU clock: %d blocks checked, %d remain. Continuing...", i, num_blocks-i); retval = i; /* return number of blocks really checked */ cleanup4: destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); cleanup3: target_free_working_area(target, erase_check_params); cleanup2: free(params); cleanup1: target_free_working_area(target, erase_check_algorithm); return retval; } int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found) { struct armv7m_common *armv7m = target_to_armv7m(target); struct reg *r = armv7m->arm.pc; bool result = false; /* if we halted last time due to a bkpt instruction * then we have to manually step over it, otherwise * the core will break again */ if (target->debug_reason == DBG_REASON_BREAKPOINT) { uint16_t op; uint32_t pc = buf_get_u32(r->value, 0, 32); pc &= ~1; if (target_read_u16(target, pc, &op) == ERROR_OK) { if ((op & 0xFF00) == 0xBE00) { pc = buf_get_u32(r->value, 0, 32) + 2; buf_set_u32(r->value, 0, 32, pc); r->dirty = true; r->valid = true; result = true; LOG_DEBUG("Skipping over BKPT instruction"); } } } if (inst_found) *inst_found = result; return ERROR_OK; } const struct command_registration armv7m_command_handlers[] = { { .name = "arm", .mode = COMMAND_ANY, .help = "ARM command group", .usage = "", .chain = arm_all_profiles_command_handlers, }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv7m.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV7M_H #define OPENOCD_TARGET_ARMV7M_H #include "arm.h" #include "armv7m_trace.h" struct adiv5_ap; extern const int armv7m_psp_reg_map[]; extern const int armv7m_msp_reg_map[]; const char *armv7m_exception_string(int number); /* Cortex-M DCRSR.REGSEL selectors */ enum { ARMV7M_REGSEL_R0, ARMV7M_REGSEL_R1, ARMV7M_REGSEL_R2, ARMV7M_REGSEL_R3, ARMV7M_REGSEL_R4, ARMV7M_REGSEL_R5, ARMV7M_REGSEL_R6, ARMV7M_REGSEL_R7, ARMV7M_REGSEL_R8, ARMV7M_REGSEL_R9, ARMV7M_REGSEL_R10, ARMV7M_REGSEL_R11, ARMV7M_REGSEL_R12, ARMV7M_REGSEL_R13, ARMV7M_REGSEL_R14, ARMV7M_REGSEL_PC = 15, ARMV7M_REGSEL_XPSR = 16, ARMV7M_REGSEL_MSP, ARMV7M_REGSEL_PSP, ARMV8M_REGSEL_MSP_NS = 0x18, ARMV8M_REGSEL_PSP_NS, ARMV8M_REGSEL_MSP_S, ARMV8M_REGSEL_PSP_S, ARMV8M_REGSEL_MSPLIM_S, ARMV8M_REGSEL_PSPLIM_S, ARMV8M_REGSEL_MSPLIM_NS, ARMV8M_REGSEL_PSPLIM_NS, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL = 0x14, ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_S = 0x22, ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_NS = 0x23, ARMV7M_REGSEL_FPSCR = 0x21, /* 32bit Floating-point registers */ ARMV7M_REGSEL_S0 = 0x40, ARMV7M_REGSEL_S1, ARMV7M_REGSEL_S2, ARMV7M_REGSEL_S3, ARMV7M_REGSEL_S4, ARMV7M_REGSEL_S5, ARMV7M_REGSEL_S6, ARMV7M_REGSEL_S7, ARMV7M_REGSEL_S8, ARMV7M_REGSEL_S9, ARMV7M_REGSEL_S10, ARMV7M_REGSEL_S11, ARMV7M_REGSEL_S12, ARMV7M_REGSEL_S13, ARMV7M_REGSEL_S14, ARMV7M_REGSEL_S15, ARMV7M_REGSEL_S16, ARMV7M_REGSEL_S17, ARMV7M_REGSEL_S18, ARMV7M_REGSEL_S19, ARMV7M_REGSEL_S20, ARMV7M_REGSEL_S21, ARMV7M_REGSEL_S22, ARMV7M_REGSEL_S23, ARMV7M_REGSEL_S24, ARMV7M_REGSEL_S25, ARMV7M_REGSEL_S26, ARMV7M_REGSEL_S27, ARMV7M_REGSEL_S28, ARMV7M_REGSEL_S29, ARMV7M_REGSEL_S30, ARMV7M_REGSEL_S31, }; /* offsets into armv7m core register cache */ enum { /* for convenience, the first set of indices match * the Cortex-M DCRSR.REGSEL selectors */ ARMV7M_R0 = ARMV7M_REGSEL_R0, ARMV7M_R1 = ARMV7M_REGSEL_R1, ARMV7M_R2 = ARMV7M_REGSEL_R2, ARMV7M_R3 = ARMV7M_REGSEL_R3, ARMV7M_R4 = ARMV7M_REGSEL_R4, ARMV7M_R5 = ARMV7M_REGSEL_R5, ARMV7M_R6 = ARMV7M_REGSEL_R6, ARMV7M_R7 = ARMV7M_REGSEL_R7, ARMV7M_R8 = ARMV7M_REGSEL_R8, ARMV7M_R9 = ARMV7M_REGSEL_R9, ARMV7M_R10 = ARMV7M_REGSEL_R10, ARMV7M_R11 = ARMV7M_REGSEL_R11, ARMV7M_R12 = ARMV7M_REGSEL_R12, ARMV7M_R13 = ARMV7M_REGSEL_R13, ARMV7M_R14 = ARMV7M_REGSEL_R14, ARMV7M_PC = ARMV7M_REGSEL_PC, ARMV7M_XPSR = ARMV7M_REGSEL_XPSR, ARMV7M_MSP = ARMV7M_REGSEL_MSP, ARMV7M_PSP = ARMV7M_REGSEL_PSP, /* following indices are arbitrary, do not match DCRSR.REGSEL selectors */ /* A block of container and contained registers follows: * THE ORDER IS IMPORTANT to the end of the block ! */ /* working register for packing/unpacking special regs, hidden from gdb */ ARMV7M_PMSK_BPRI_FLTMSK_CTRL, /* WARNING: If you use armv7m_write_core_reg() on one of 4 following * special registers, the new data go to ARMV7M_PMSK_BPRI_FLTMSK_CTRL * cache only and are not flushed to CPU HW register. * To trigger write to CPU HW register, add * armv7m_write_core_reg(,,ARMV7M_PMSK_BPRI_FLTMSK_CTRL,); */ ARMV7M_PRIMASK, ARMV7M_BASEPRI, ARMV7M_FAULTMASK, ARMV7M_CONTROL, /* The end of block of container and contained registers */ /* ARMv8-M specific registers */ ARMV8M_MSP_NS, ARMV8M_PSP_NS, ARMV8M_MSP_S, ARMV8M_PSP_S, ARMV8M_MSPLIM_S, ARMV8M_PSPLIM_S, ARMV8M_MSPLIM_NS, ARMV8M_PSPLIM_NS, /* A block of container and contained registers follows: * THE ORDER IS IMPORTANT to the end of the block ! */ ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S, ARMV8M_PRIMASK_S, ARMV8M_BASEPRI_S, ARMV8M_FAULTMASK_S, ARMV8M_CONTROL_S, /* The end of block of container and contained registers */ /* A block of container and contained registers follows: * THE ORDER IS IMPORTANT to the end of the block ! */ ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS, ARMV8M_PRIMASK_NS, ARMV8M_BASEPRI_NS, ARMV8M_FAULTMASK_NS, ARMV8M_CONTROL_NS, /* The end of block of container and contained registers */ /* 64bit Floating-point registers */ ARMV7M_D0, ARMV7M_D1, ARMV7M_D2, ARMV7M_D3, ARMV7M_D4, ARMV7M_D5, ARMV7M_D6, ARMV7M_D7, ARMV7M_D8, ARMV7M_D9, ARMV7M_D10, ARMV7M_D11, ARMV7M_D12, ARMV7M_D13, ARMV7M_D14, ARMV7M_D15, /* Floating-point status register */ ARMV7M_FPSCR, /* for convenience add registers' block delimiters */ ARMV7M_LAST_REG, ARMV7M_CORE_FIRST_REG = ARMV7M_R0, ARMV7M_CORE_LAST_REG = ARMV7M_XPSR, ARMV7M_FPU_FIRST_REG = ARMV7M_D0, ARMV7M_FPU_LAST_REG = ARMV7M_FPSCR, ARMV8M_FIRST_REG = ARMV8M_MSP_NS, ARMV8M_LAST_REG = ARMV8M_CONTROL_NS, }; enum { FP_NONE = 0, FPV4_SP, FPV5_SP, FPV5_DP, }; #define ARMV7M_NUM_CORE_REGS (ARMV7M_CORE_LAST_REG - ARMV7M_CORE_FIRST_REG + 1) #define ARMV7M_COMMON_MAGIC 0x2A452A45U struct armv7m_common { unsigned int common_magic; struct arm arm; int exception_number; /* AP this processor is connected to in the DAP */ struct adiv5_ap *debug_ap; int fp_feature; uint32_t demcr; /* hla_target uses a high level adapter that does not support all functions */ bool is_hla_target; struct armv7m_trace_config trace_config; /* Direct processor core register read and writes */ int (*load_core_reg_u32)(struct target *target, uint32_t regsel, uint32_t *value); int (*store_core_reg_u32)(struct target *target, uint32_t regsel, uint32_t value); int (*examine_debug_reason)(struct target *target); int (*post_debug_entry)(struct target *target); void (*pre_restore_context)(struct target *target); }; static inline bool is_armv7m(const struct armv7m_common *armv7m) { return armv7m->common_magic == ARMV7M_COMMON_MAGIC; } /** * @returns the pointer to the target specific struct * without matching a magic number. * Use in target specific service routines, where the correct * type of arch_info is certain. */ static inline struct armv7m_common * target_to_armv7m(struct target *target) { return container_of(target->arch_info, struct armv7m_common, arm); } /** * @returns the pointer to the target specific struct * or NULL if the magic number does not match. * Use in a flash driver or any place where mismatch of the arch_info * type can happen. */ static inline struct armv7m_common * target_to_armv7m_safe(struct target *target) { if (!target) return NULL; if (!target->arch_info) return NULL; /* Check the parent type first to prevent peeking memory too far * from arch_info pointer */ if (!is_arm(target_to_arm(target))) return NULL; struct armv7m_common *armv7m = target_to_armv7m(target); if (!is_armv7m(armv7m)) return NULL; return armv7m; } struct armv7m_algorithm { unsigned int common_magic; enum arm_mode core_mode; uint32_t context[ARMV7M_LAST_REG]; /* ARMV7M_NUM_REGS */ }; struct reg_cache *armv7m_build_reg_cache(struct target *target); void armv7m_free_reg_cache(struct target *target); enum armv7m_mode armv7m_number_to_mode(int number); int armv7m_mode_to_number(enum armv7m_mode mode); int armv7m_arch_state(struct target *target); int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m); int armv7m_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); int armv7m_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, void *arch_info); int armv7m_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); int armv7m_invalidate_core_regs(struct target *target); int armv7m_restore_context(struct target *target); uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id); bool armv7m_map_reg_packing(unsigned int arm_reg_id, unsigned int *reg32_id, uint32_t *offset); int armv7m_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); int armv7m_blank_check_memory(struct target *target, struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value); int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found); extern const struct command_registration armv7m_command_handlers[]; #endif /* OPENOCD_TARGET_ARMV7M_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv7m_trace.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2015 Paul Fertser <fercerpav@gmail.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <target/target.h> #include <target/armv7m.h> #include <target/cortex_m.h> #include <target/armv7m_trace.h> #include <jtag/interface.h> #include <helper/time_support.h> int armv7m_trace_itm_config(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_trace_config *trace_config = &armv7m->trace_config; int retval; retval = target_write_u32(target, ITM_LAR, ITM_LAR_KEY); if (retval != ERROR_OK) return retval; /* pg315 of CoreSight Components * It is recommended that the ITMEn bit is cleared and waits for the * ITMBusy bit to be cleared, before changing any fields in the * Control Register, otherwise the behavior can be unpredictable. */ uint32_t itm_tcr; retval = target_read_u32(target, ITM_TCR, &itm_tcr); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, ITM_TCR, itm_tcr & ~ITM_TCR_ITMENA_BIT ); if (retval != ERROR_OK) return retval; int64_t then = timeval_ms() + 1000; do { retval = target_read_u32(target, ITM_TCR, &itm_tcr); if (retval != ERROR_OK) return retval; if (timeval_ms() > then) { LOG_ERROR("timeout waiting for ITM_TCR_BUSY_BIT"); return ERROR_FAIL; } } while (itm_tcr & ITM_TCR_BUSY_BIT); /* Enable ITM, TXENA, set TraceBusID and other parameters */ retval = target_write_u32(target, ITM_TCR, (1 << 0) | (1 << 3) | (trace_config->itm_diff_timestamps << 1) | (trace_config->itm_synchro_packets << 2) | (trace_config->itm_async_timestamps << 4) | (trace_config->itm_ts_prescale << 8) | (trace_config->trace_bus_id << 16)); if (retval != ERROR_OK) return retval; for (unsigned int i = 0; i < 8; i++) { retval = target_write_u32(target, ITM_TER0 + i * 4, trace_config->itm_ter[i]); if (retval != ERROR_OK) return retval; } return ERROR_OK; } COMMAND_HANDLER(handle_itm_port_command) { struct target *target = get_current_target(CMD_CTX); struct armv7m_common *armv7m = target_to_armv7m(target); unsigned int reg_idx; uint8_t port; bool enable; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], port); COMMAND_PARSE_ON_OFF(CMD_ARGV[1], enable); reg_idx = port / 32; port = port % 32; if (enable) armv7m->trace_config.itm_ter[reg_idx] |= (1 << port); else armv7m->trace_config.itm_ter[reg_idx] &= ~(1 << port); if (CMD_CTX->mode == COMMAND_EXEC) return armv7m_trace_itm_config(target); armv7m->trace_config.itm_deferred_config = true; return ERROR_OK; } COMMAND_HANDLER(handle_itm_ports_command) { struct target *target = get_current_target(CMD_CTX); struct armv7m_common *armv7m = target_to_armv7m(target); bool enable; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable); memset(armv7m->trace_config.itm_ter, enable ? 0xff : 0, sizeof(armv7m->trace_config.itm_ter)); if (CMD_CTX->mode == COMMAND_EXEC) return armv7m_trace_itm_config(target); armv7m->trace_config.itm_deferred_config = true; return ERROR_OK; } static const struct command_registration itm_command_handlers[] = { { .name = "port", .handler = handle_itm_port_command, .mode = COMMAND_ANY, .help = "Enable or disable ITM stimulus port", .usage = "<port> (0|1|on|off)", }, { .name = "ports", .handler = handle_itm_ports_command, .mode = COMMAND_ANY, .help = "Enable or disable all ITM stimulus ports", .usage = "(0|1|on|off)", }, COMMAND_REGISTRATION_DONE }; const struct command_registration armv7m_trace_command_handlers[] = { { .name = "itm", .mode = COMMAND_ANY, .help = "itm command group", .usage = "", .chain = itm_command_handlers, }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv7m_trace.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2015 Paul Fertser <fercerpav@gmail.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV7M_TRACE_H #define OPENOCD_TARGET_ARMV7M_TRACE_H #include <helper/command.h> #include <target/target.h> /** * @file * Holds the interface to ITM and DWT configuration functions. */ enum itm_ts_prescaler { ITM_TS_PRESCALE1, /**< no prescaling for the timestamp counter */ ITM_TS_PRESCALE4, /**< refclock divided by 4 for the timestamp counter */ ITM_TS_PRESCALE16, /**< refclock divided by 16 for the timestamp counter */ ITM_TS_PRESCALE64, /**< refclock divided by 64 for the timestamp counter */ }; struct armv7m_trace_config { /** Bitmask of currently enabled ITM stimuli */ uint32_t itm_ter[8]; /** Identifier for multi-source trace stream formatting */ unsigned int trace_bus_id; /** Prescaler for the timestamp counter */ enum itm_ts_prescaler itm_ts_prescale; /** Enable differential timestamps */ bool itm_diff_timestamps; /** Enable async timestamps model */ bool itm_async_timestamps; /** Enable synchronisation packet transmission (for sync port only) */ bool itm_synchro_packets; /** Config ITM after target examine */ bool itm_deferred_config; }; extern const struct command_registration armv7m_trace_command_handlers[]; /** * Configure hardware accordingly to the current ITM target settings */ int armv7m_trace_itm_config(struct target *target); #endif /* OPENOCD_TARGET_ARMV7M_TRACE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv8.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2015 by David Ung * * * * Copyright (C) 2018 by Liviu Ionescu * * <ilg@livius.net> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/replacements.h> #include "armv8.h" #include "arm_disassembler.h" #include "register.h" #include <helper/binarybuffer.h> #include <helper/command.h> #include <helper/nvp.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "armv8_opcodes.h" #include "target.h" #include "target_type.h" #include "semihosting_common.h" static const char * const armv8_state_strings[] = { "AArch32", "Thumb", "Jazelle", "ThumbEE", "AArch64", }; static const struct { const char *name; unsigned psr; } armv8_mode_data[] = { { .name = "USR", .psr = ARM_MODE_USR, }, { .name = "FIQ", .psr = ARM_MODE_FIQ, }, { .name = "IRQ", .psr = ARM_MODE_IRQ, }, { .name = "SVC", .psr = ARM_MODE_SVC, }, { .name = "MON", .psr = ARM_MODE_MON, }, { .name = "ABT", .psr = ARM_MODE_ABT, }, { .name = "HYP", .psr = ARM_MODE_HYP, }, { .name = "UND", .psr = ARM_MODE_UND, }, { .name = "SYS", .psr = ARM_MODE_SYS, }, { .name = "EL0T", .psr = ARMV8_64_EL0T, }, { .name = "EL1T", .psr = ARMV8_64_EL1T, }, { .name = "EL1H", .psr = ARMV8_64_EL1H, }, { .name = "EL2T", .psr = ARMV8_64_EL2T, }, { .name = "EL2H", .psr = ARMV8_64_EL2H, }, { .name = "EL3T", .psr = ARMV8_64_EL3T, }, { .name = "EL3H", .psr = ARMV8_64_EL3H, }, }; /** Map PSR mode bits to the name of an ARM processor operating mode. */ const char *armv8_mode_name(unsigned psr_mode) { for (unsigned i = 0; i < ARRAY_SIZE(armv8_mode_data); i++) { if (armv8_mode_data[i].psr == psr_mode) return armv8_mode_data[i].name; } LOG_ERROR("unrecognized psr mode: %#02x", psr_mode); return "UNRECOGNIZED"; } static uint8_t armv8_pa_size(uint32_t ps) { uint8_t ret = 0; switch (ps) { case 0: ret = 32; break; case 1: ret = 36; break; case 2: ret = 40; break; case 3: ret = 42; break; case 4: ret = 44; break; case 5: ret = 48; break; default: LOG_INFO("Unknown physical address size"); break; } return ret; } static __attribute__((unused)) int armv8_read_ttbcr32(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); struct arm_dpm *dpm = armv8->arm.dpm; uint32_t ttbcr, ttbcr_n; int retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 2, 0, 2), &ttbcr); if (retval != ERROR_OK) goto done; LOG_DEBUG("ttbcr %" PRIx32, ttbcr); ttbcr_n = ttbcr & 0x7; armv8->armv8_mmu.ttbcr = ttbcr; /* * ARM Architecture Reference Manual (ARMv7-A and ARMv7-R edition), * document # ARM DDI 0406C */ armv8->armv8_mmu.ttbr_range[0] = 0xffffffff >> ttbcr_n; armv8->armv8_mmu.ttbr_range[1] = 0xffffffff; armv8->armv8_mmu.ttbr_mask[0] = 0xffffffff << (14 - ttbcr_n); armv8->armv8_mmu.ttbr_mask[1] = 0xffffffff << 14; LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32 " ttbr1_mask %" PRIx32, (ttbcr_n != 0) ? "used" : "not used", armv8->armv8_mmu.ttbr_mask[0], armv8->armv8_mmu.ttbr_mask[1]); done: dpm->finish(dpm); return retval; } static int armv8_read_ttbcr(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); struct arm_dpm *dpm = armv8->arm.dpm; struct arm *arm = &armv8->arm; uint32_t ttbcr; uint64_t ttbcr_64; int retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* clear ttrr1_used and ttbr0_mask */ memset(&armv8->armv8_mmu.ttbr1_used, 0, sizeof(armv8->armv8_mmu.ttbr1_used)); memset(&armv8->armv8_mmu.ttbr0_mask, 0, sizeof(armv8->armv8_mmu.ttbr0_mask)); switch (armv8_curel_from_core_mode(arm->core_mode)) { case SYSTEM_CUREL_EL3: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_TCR_EL3, 0), &ttbcr); retval += dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_TTBR0_EL3, 0), &armv8->ttbr_base); if (retval != ERROR_OK) goto done; armv8->va_size = 64 - (ttbcr & 0x3F); armv8->pa_size = armv8_pa_size((ttbcr >> 16) & 7); armv8->page_size = (ttbcr >> 14) & 3; break; case SYSTEM_CUREL_EL2: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_TCR_EL2, 0), &ttbcr); retval += dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_TTBR0_EL2, 0), &armv8->ttbr_base); if (retval != ERROR_OK) goto done; armv8->va_size = 64 - (ttbcr & 0x3F); armv8->pa_size = armv8_pa_size((ttbcr >> 16) & 7); armv8->page_size = (ttbcr >> 14) & 3; break; case SYSTEM_CUREL_EL0: armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H); /* fall through */ case SYSTEM_CUREL_EL1: retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_TCR_EL1, 0), &ttbcr_64); armv8->va_size = 64 - (ttbcr_64 & 0x3F); armv8->pa_size = armv8_pa_size((ttbcr_64 >> 32) & 7); armv8->page_size = (ttbcr_64 >> 14) & 3; armv8->armv8_mmu.ttbr1_used = (((ttbcr_64 >> 16) & 0x3F) != 0) ? 1 : 0; armv8->armv8_mmu.ttbr0_mask = 0x0000FFFFFFFFFFFFULL; retval += dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_TTBR0_EL1 | (armv8->armv8_mmu.ttbr1_used), 0), &armv8->ttbr_base); if (retval != ERROR_OK) goto done; break; default: LOG_ERROR("unknown core state"); retval = ERROR_FAIL; break; } if (retval != ERROR_OK) goto done; if (armv8->armv8_mmu.ttbr1_used == 1) LOG_INFO("TTBR0 access above %" PRIx64, (uint64_t)(armv8->armv8_mmu.ttbr0_mask)); done: armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); dpm->finish(dpm); return retval; } static int armv8_get_pauth_mask(struct armv8_common *armv8, uint64_t *mask) { struct arm *arm = &armv8->arm; int retval = ERROR_OK; if (armv8->va_size == 0) retval = armv8_read_ttbcr(arm->target); if (retval != ERROR_OK) return retval; *mask = ~(((uint64_t)1 << armv8->va_size) - 1); return retval; } static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regval) { struct arm_dpm *dpm = &armv8->dpm; int retval; uint32_t value; uint64_t value_64; switch (regnum) { case 0 ... 30: retval = dpm->instr_read_data_dcc_64(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, regnum), &value_64); break; case ARMV8_SP: retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MOVFSP_64(0), &value_64); break; case ARMV8_PC: retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS_DLR(0), &value_64); break; case ARMV8_XPSR: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS_DSPSR(0), &value); value_64 = value; break; case ARMV8_FPSR: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS_FPSR(0), &value); value_64 = value; break; case ARMV8_FPCR: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS_FPCR(0), &value); value_64 = value; break; case ARMV8_ELR_EL1: retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_ELR_EL1, 0), &value_64); break; case ARMV8_ELR_EL2: retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_ELR_EL2, 0), &value_64); break; case ARMV8_ELR_EL3: retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_ELR_EL3, 0), &value_64); break; case ARMV8_ESR_EL1: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_ESR_EL1, 0), &value); value_64 = value; break; case ARMV8_ESR_EL2: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_ESR_EL2, 0), &value); value_64 = value; break; case ARMV8_ESR_EL3: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_ESR_EL3, 0), &value); value_64 = value; break; case ARMV8_SPSR_EL1: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_SPSR_EL1, 0), &value); value_64 = value; break; case ARMV8_SPSR_EL2: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_SPSR_EL2, 0), &value); value_64 = value; break; case ARMV8_SPSR_EL3: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_SPSR_EL3, 0), &value); value_64 = value; break; case ARMV8_PAUTH_CMASK: case ARMV8_PAUTH_DMASK: retval = armv8_get_pauth_mask(armv8, &value_64); break; default: retval = ERROR_FAIL; break; } if (retval == ERROR_OK && regval) *regval = value_64; else retval = ERROR_FAIL; return retval; } static int armv8_read_reg_simdfp_aarch64(struct armv8_common *armv8, int regnum, uint64_t *lvalue, uint64_t *hvalue) { int retval = ERROR_FAIL; struct arm_dpm *dpm = &armv8->dpm; switch (regnum) { case ARMV8_V0 ... ARMV8_V31: retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MOV_GPR_VFP(0, (regnum - ARMV8_V0), 1), hvalue); if (retval != ERROR_OK) return retval; retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MOV_GPR_VFP(0, (regnum - ARMV8_V0), 0), lvalue); break; default: retval = ERROR_FAIL; break; } return retval; } static int armv8_write_reg(struct armv8_common *armv8, int regnum, uint64_t value_64) { struct arm_dpm *dpm = &armv8->dpm; int retval; uint32_t value; switch (regnum) { case 0 ... 30: retval = dpm->instr_write_data_dcc_64(dpm, ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, regnum), value_64); break; case ARMV8_SP: retval = dpm->instr_write_data_r0_64(dpm, ARMV8_MOVTSP_64(0), value_64); break; case ARMV8_PC: retval = dpm->instr_write_data_r0_64(dpm, ARMV8_MSR_DLR(0), value_64); break; case ARMV8_XPSR: value = value_64; retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_DSPSR(0), value); break; case ARMV8_FPSR: value = value_64; retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_FPSR(0), value); break; case ARMV8_FPCR: value = value_64; retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_FPCR(0), value); break; /* registers clobbered by taking exception in debug state */ case ARMV8_ELR_EL1: retval = dpm->instr_write_data_r0_64(dpm, ARMV8_MSR_GP(SYSTEM_ELR_EL1, 0), value_64); break; case ARMV8_ELR_EL2: retval = dpm->instr_write_data_r0_64(dpm, ARMV8_MSR_GP(SYSTEM_ELR_EL2, 0), value_64); break; case ARMV8_ELR_EL3: retval = dpm->instr_write_data_r0_64(dpm, ARMV8_MSR_GP(SYSTEM_ELR_EL3, 0), value_64); break; case ARMV8_ESR_EL1: value = value_64; retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP(SYSTEM_ESR_EL1, 0), value); break; case ARMV8_ESR_EL2: value = value_64; retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP(SYSTEM_ESR_EL2, 0), value); break; case ARMV8_ESR_EL3: value = value_64; retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP(SYSTEM_ESR_EL3, 0), value); break; case ARMV8_SPSR_EL1: value = value_64; retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP(SYSTEM_SPSR_EL1, 0), value); break; case ARMV8_SPSR_EL2: value = value_64; retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP(SYSTEM_SPSR_EL2, 0), value); break; case ARMV8_SPSR_EL3: value = value_64; retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP(SYSTEM_SPSR_EL3, 0), value); break; default: retval = ERROR_FAIL; break; } return retval; } static int armv8_write_reg_simdfp_aarch64(struct armv8_common *armv8, int regnum, uint64_t lvalue, uint64_t hvalue) { int retval = ERROR_FAIL; struct arm_dpm *dpm = &armv8->dpm; switch (regnum) { case ARMV8_V0 ... ARMV8_V31: retval = dpm->instr_write_data_r0_64(dpm, ARMV8_MOV_VFP_GPR((regnum - ARMV8_V0), 0, 1), hvalue); if (retval != ERROR_OK) return retval; retval = dpm->instr_write_data_r0_64(dpm, ARMV8_MOV_VFP_GPR((regnum - ARMV8_V0), 0, 0), lvalue); break; default: retval = ERROR_FAIL; break; } return retval; } static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *regval) { struct arm_dpm *dpm = &armv8->dpm; uint32_t value = 0; int retval; switch (regnum) { case ARMV8_R0 ... ARMV8_R14: /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */ retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, regnum, 0, 5, 0), &value); break; case ARMV8_SP: retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, 13, 0, 5, 0), &value); break; case ARMV8_PC: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRC_DLR(0), &value); break; case ARMV8_XPSR: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRC_DSPSR(0), &value); break; case ARMV8_ELR_EL1: /* mapped to LR_svc */ retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, 14, 0, 5, 0), &value); break; case ARMV8_ELR_EL2: /* mapped to ELR_hyp */ retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS_T1(0, 14, 0, 1), &value); break; case ARMV8_ELR_EL3: /* mapped to LR_mon */ retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, 14, 0, 5, 0), &value); break; case ARMV8_ESR_EL1: /* mapped to DFSR */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 5, 0, 0), &value); break; case ARMV8_ESR_EL2: /* mapped to HSR */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 4, 0, 5, 2, 0), &value); break; case ARMV8_ESR_EL3: /* FIXME: no equivalent in aarch32? */ retval = ERROR_FAIL; break; case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */ retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS_XPSR_T1(1, 0), &value); break; case ARMV8_SPSR_EL2: /* mapped to SPSR_hyp */ retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS_XPSR_T1(1, 0), &value); break; case ARMV8_SPSR_EL3: /* mapped to SPSR_mon */ retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS_XPSR_T1(1, 0), &value); break; case ARMV8_FPSR: /* "VMRS r0, FPSCR"; then return via DCC */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_VMRS(0), &value); break; default: retval = ERROR_FAIL; break; } if (retval == ERROR_OK && regval) *regval = value; return retval; } static int armv8_read_reg_simdfp_aarch32(struct armv8_common *armv8, int regnum, uint64_t *lvalue, uint64_t *hvalue) { int retval = ERROR_FAIL; struct arm_dpm *dpm = &armv8->dpm; struct reg *reg_r1 = dpm->arm->core_cache->reg_list + ARMV8_R1; uint32_t value_r0 = 0, value_r1 = 0; unsigned num = (regnum - ARMV8_V0) << 1; switch (regnum) { case ARMV8_V0 ... ARMV8_V15: /* we are going to write R1, mark it dirty */ reg_r1->dirty = true; /* move from double word register to r0:r1: "vmov r0, r1, vm" * then read r0 via dcc */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_VMOV(1, 1, 0, (num >> 4), (num & 0xf)), &value_r0); if (retval != ERROR_OK) return retval; /* read r1 via dcc */ retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, 1, 0, 5, 0), &value_r1); if (retval != ERROR_OK) return retval; *lvalue = value_r1; *lvalue = ((*lvalue) << 32) | value_r0; num++; /* repeat above steps for high 64 bits of V register */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_VMOV(1, 1, 0, (num >> 4), (num & 0xf)), &value_r0); if (retval != ERROR_OK) return retval; retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, 1, 0, 5, 0), &value_r1); if (retval != ERROR_OK) return retval; *hvalue = value_r1; *hvalue = ((*hvalue) << 32) | value_r0; break; default: retval = ERROR_FAIL; break; } return retval; } static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t value) { struct arm_dpm *dpm = &armv8->dpm; int retval; switch (regnum) { case ARMV8_R0 ... ARMV8_R14: /* load register from DCC: "MRC p14, 0, Rnum, c0, c5, 0" */ retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, regnum, 0, 5, 0), value); break; case ARMV8_SP: retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 13, 0, 5, 0), value); break; case ARMV8_PC:/* PC * read r0 from DCC; then "MOV pc, r0" */ retval = dpm->instr_write_data_r0(dpm, ARMV8_MCR_DLR(0), value); break; case ARMV8_XPSR: /* CPSR */ /* read r0 from DCC, then "MCR r0, DSPSR" */ retval = dpm->instr_write_data_r0(dpm, ARMV8_MCR_DSPSR(0), value); break; case ARMV8_ELR_EL1: /* mapped to LR_svc */ retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 14, 0, 5, 0), value); break; case ARMV8_ELR_EL2: /* mapped to ELR_hyp */ retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP_T1(0, 14, 0, 1), value); break; case ARMV8_ELR_EL3: /* mapped to LR_mon */ retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 14, 0, 5, 0), value); break; case ARMV8_ESR_EL1: /* mapped to DFSR */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 5, 0, 0), value); break; case ARMV8_ESR_EL2: /* mapped to HSR */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 4, 0, 5, 2, 0), value); break; case ARMV8_ESR_EL3: /* FIXME: no equivalent in aarch32? */ retval = ERROR_FAIL; break; case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */ retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP_XPSR_T1(1, 0, 15), value); break; case ARMV8_SPSR_EL2: /* mapped to SPSR_hyp */ retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP_XPSR_T1(1, 0, 15), value); break; case ARMV8_SPSR_EL3: /* mapped to SPSR_mon */ retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP_XPSR_T1(1, 0, 15), value); break; case ARMV8_FPSR: /* move to r0 from DCC, then "VMSR FPSCR, r0" */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_VMSR(0), value); break; default: retval = ERROR_FAIL; break; } return retval; } static int armv8_write_reg_simdfp_aarch32(struct armv8_common *armv8, int regnum, uint64_t lvalue, uint64_t hvalue) { int retval = ERROR_FAIL; struct arm_dpm *dpm = &armv8->dpm; struct reg *reg_r1 = dpm->arm->core_cache->reg_list + ARMV8_R1; uint32_t value_r0 = 0, value_r1 = 0; unsigned num = (regnum - ARMV8_V0) << 1; switch (regnum) { case ARMV8_V0 ... ARMV8_V15: /* we are going to write R1, mark it dirty */ reg_r1->dirty = true; value_r1 = lvalue >> 32; value_r0 = lvalue & 0xFFFFFFFF; /* write value_r1 to r1 via dcc */ retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 1, 0, 5, 0), value_r1); if (retval != ERROR_OK) return retval; /* write value_r0 to r0 via dcc then, * move to double word register from r0:r1: "vmov vm, r0, r1" */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_VMOV(0, 1, 0, (num >> 4), (num & 0xf)), value_r0); if (retval != ERROR_OK) return retval; num++; /* repeat above steps for high 64 bits of V register */ value_r1 = hvalue >> 32; value_r0 = hvalue & 0xFFFFFFFF; retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 1, 0, 5, 0), value_r1); if (retval != ERROR_OK) return retval; retval = dpm->instr_write_data_r0(dpm, ARMV4_5_VMOV(0, 1, 0, (num >> 4), (num & 0xf)), value_r0); break; default: retval = ERROR_FAIL; break; } return retval; } void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64) { if (is_aarch64) { armv8->read_reg_u64 = armv8_read_reg; armv8->write_reg_u64 = armv8_write_reg; armv8->read_reg_u128 = armv8_read_reg_simdfp_aarch64; armv8->write_reg_u128 = armv8_write_reg_simdfp_aarch64; } else { armv8->read_reg_u64 = armv8_read_reg32; armv8->write_reg_u64 = armv8_write_reg32; armv8->read_reg_u128 = armv8_read_reg_simdfp_aarch32; armv8->write_reg_u128 = armv8_write_reg_simdfp_aarch32; } } /* retrieve core id cluster id */ int armv8_read_mpidr(struct armv8_common *armv8) { int retval = ERROR_FAIL; struct arm *arm = &armv8->arm; struct arm_dpm *dpm = armv8->arm.dpm; uint32_t mpidr; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* check if we're in an unprivileged mode */ if (armv8_curel_from_core_mode(arm->core_mode) < SYSTEM_CUREL_EL1) { retval = armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H); if (retval != ERROR_OK) return retval; } retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr); if (retval != ERROR_OK) goto done; if (mpidr & 1U<<31) { armv8->multi_processor_system = (mpidr >> 30) & 1; armv8->cluster_id = (mpidr >> 8) & 0xf; armv8->cpu_id = mpidr & 0x3; LOG_INFO("%s cluster %x core %x %s", target_name(armv8->arm.target), armv8->cluster_id, armv8->cpu_id, armv8->multi_processor_system == 0 ? "multi core" : "single core"); } else LOG_ERROR("mpidr not in multiprocessor format"); done: armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); dpm->finish(dpm); return retval; } /** * Configures host-side ARM records to reflect the specified CPSR. * Later, code can use arm_reg_current() to map register numbers * according to how they are exposed by this mode. */ void armv8_set_cpsr(struct arm *arm, uint32_t cpsr) { uint32_t mode = cpsr & 0x1F; /* NOTE: this may be called very early, before the register * cache is set up. We can't defend against many errors, in * particular against CPSRs that aren't valid *here* ... */ if (arm->cpsr) { buf_set_u32(arm->cpsr->value, 0, 32, cpsr); arm->cpsr->valid = true; arm->cpsr->dirty = false; } /* Older ARMs won't have the J bit */ enum arm_state state = 0xFF; if ((cpsr & 0x10) != 0) { /* Aarch32 state */ if (cpsr & (1 << 5)) { /* T */ if (cpsr & (1 << 24)) { /* J */ LOG_WARNING("ThumbEE -- incomplete support"); state = ARM_STATE_THUMB_EE; } else state = ARM_STATE_THUMB; } else { if (cpsr & (1 << 24)) { /* J */ LOG_ERROR("Jazelle state handling is BROKEN!"); state = ARM_STATE_JAZELLE; } else state = ARM_STATE_ARM; } } else { /* Aarch64 state */ state = ARM_STATE_AARCH64; } arm->core_state = state; arm->core_mode = mode; LOG_DEBUG("set CPSR %#8.8x: %s mode, %s state", (unsigned) cpsr, armv8_mode_name(arm->core_mode), armv8_state_strings[arm->core_state]); } static void armv8_show_fault_registers32(struct armv8_common *armv8) { uint32_t dfsr, ifsr, dfar, ifar; struct arm_dpm *dpm = armv8->arm.dpm; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return; /* ARMV4_5_MRC(cpnum, op1, r0, crn, crm, op2) */ /* c5/c0 - {data, instruction} fault status registers */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 5, 0, 0), &dfsr); if (retval != ERROR_OK) goto done; retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 5, 0, 1), &ifsr); if (retval != ERROR_OK) goto done; /* c6/c0 - {data, instruction} fault address registers */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 6, 0, 0), &dfar); if (retval != ERROR_OK) goto done; retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 6, 0, 2), &ifar); if (retval != ERROR_OK) goto done; LOG_USER("Data fault registers DFSR: %8.8" PRIx32 ", DFAR: %8.8" PRIx32, dfsr, dfar); LOG_USER("Instruction fault registers IFSR: %8.8" PRIx32 ", IFAR: %8.8" PRIx32, ifsr, ifar); done: /* (void) */ dpm->finish(dpm); } static __attribute__((unused)) void armv8_show_fault_registers(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); if (armv8->arm.core_state != ARM_STATE_AARCH64) armv8_show_fault_registers32(armv8); } /* method adapted to cortex A : reused arm v4 v5 method*/ int armv8_mmu_translate_va(struct target *target, target_addr_t va, target_addr_t *val) { return ERROR_OK; } /* V8 method VA TO PA */ int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va, target_addr_t *val, int meminfo) { struct armv8_common *armv8 = target_to_armv8(target); struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = &armv8->dpm; enum arm_mode target_mode = ARM_MODE_ANY; uint32_t retval; uint32_t instr = 0; uint64_t par; static const char * const shared_name[] = { "Non-", "UNDEFINED ", "Outer ", "Inner " }; static const char * const secure_name[] = { "Secure", "Not Secure" }; if (target->state != TARGET_HALTED) { LOG_WARNING("target %s not halted", target_name(target)); return ERROR_TARGET_NOT_HALTED; } retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; switch (armv8_curel_from_core_mode(arm->core_mode)) { case SYSTEM_CUREL_EL0: instr = ARMV8_SYS(SYSTEM_ATS12E0R, 0); /* can only execute instruction at EL2 */ target_mode = ARMV8_64_EL2H; break; case SYSTEM_CUREL_EL1: instr = ARMV8_SYS(SYSTEM_ATS12E1R, 0); /* can only execute instruction at EL2 */ target_mode = ARMV8_64_EL2H; break; case SYSTEM_CUREL_EL2: instr = ARMV8_SYS(SYSTEM_ATS1E2R, 0); break; case SYSTEM_CUREL_EL3: instr = ARMV8_SYS(SYSTEM_ATS1E3R, 0); break; default: break; }; if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(dpm, target_mode); /* write VA to R0 and execute translation instruction */ retval = dpm->instr_write_data_r0_64(dpm, instr, (uint64_t)va); /* read result from PAR_EL1 */ if (retval == ERROR_OK) retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_PAR_EL1, 0), &par); /* switch back to saved PE mode */ if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); dpm->finish(dpm); if (retval != ERROR_OK) return retval; if (par & 1) { LOG_ERROR("Address translation failed at stage %i, FST=%x, PTW=%i", ((int)(par >> 9) & 1)+1, (int)(par >> 1) & 0x3f, (int)(par >> 8) & 1); *val = 0; retval = ERROR_FAIL; } else { *val = (par & 0xFFFFFFFFF000UL) | (va & 0xFFF); if (meminfo) { int SH = (par >> 7) & 3; int NS = (par >> 9) & 1; int ATTR = (par >> 56) & 0xFF; char *memtype = (ATTR & 0xF0) == 0 ? "Device Memory" : "Normal Memory"; LOG_USER("%sshareable, %s", shared_name[SH], secure_name[NS]); LOG_USER("%s", memtype); } } return retval; } COMMAND_HANDLER(armv8_handle_exception_catch_command) { struct target *target = get_current_target(CMD_CTX); struct armv8_common *armv8 = target_to_armv8(target); uint32_t edeccr = 0; unsigned int argp = 0; int retval; static const struct nvp nvp_ecatch_modes[] = { { .name = "off", .value = 0 }, { .name = "nsec_el1", .value = (1 << 5) }, { .name = "nsec_el2", .value = (2 << 5) }, { .name = "nsec_el12", .value = (3 << 5) }, { .name = "sec_el1", .value = (1 << 1) }, { .name = "sec_el3", .value = (4 << 1) }, { .name = "sec_el13", .value = (5 << 1) }, { .name = NULL, .value = -1 }, }; const struct nvp *n; if (CMD_ARGC == 0) { const char *sec = NULL, *nsec = NULL; retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_ECCR, &edeccr); if (retval != ERROR_OK) return retval; n = nvp_value2name(nvp_ecatch_modes, edeccr & 0x0f); if (n->name) sec = n->name; n = nvp_value2name(nvp_ecatch_modes, edeccr & 0xf0); if (n->name) nsec = n->name; if (!sec || !nsec) { LOG_WARNING("Exception Catch: unknown exception catch configuration: EDECCR = %02" PRIx32, edeccr & 0xff); return ERROR_FAIL; } command_print(CMD, "Exception Catch: Secure: %s, Non-Secure: %s", sec, nsec); return ERROR_OK; } while (argp < CMD_ARGC) { n = nvp_name2value(nvp_ecatch_modes, CMD_ARGV[argp]); if (!n->name) { LOG_ERROR("Unknown option: %s", CMD_ARGV[argp]); return ERROR_FAIL; } LOG_DEBUG("found: %s", n->name); edeccr |= n->value; argp++; } retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_ECCR, edeccr); if (retval != ERROR_OK) return retval; return ERROR_OK; } COMMAND_HANDLER(armv8_pauth_command) { struct target *target = get_current_target(CMD_CTX); struct armv8_common *armv8 = target_to_armv8(target); return CALL_COMMAND_HANDLER(handle_command_parse_bool, &armv8->enable_pauth, "pauth feature"); } int armv8_handle_cache_info_command(struct command_invocation *cmd, struct armv8_cache_common *armv8_cache) { if (armv8_cache->info == -1) { command_print(cmd, "cache not yet identified"); return ERROR_OK; } if (armv8_cache->display_cache_info) armv8_cache->display_cache_info(cmd, armv8_cache); return ERROR_OK; } static int armv8_setup_semihosting(struct target *target, int enable) { return ERROR_OK; } int armv8_init_arch_info(struct target *target, struct armv8_common *armv8) { struct arm *arm = &armv8->arm; arm->arch_info = armv8; target->arch_info = &armv8->arm; arm->setup_semihosting = armv8_setup_semihosting; /* target is useful in all function arm v4 5 compatible */ armv8->arm.target = target; armv8->arm.common_magic = ARM_COMMON_MAGIC; armv8->common_magic = ARMV8_COMMON_MAGIC; armv8->armv8_mmu.armv8_cache.l2_cache = NULL; armv8->armv8_mmu.armv8_cache.info = -1; armv8->armv8_mmu.armv8_cache.flush_all_data_cache = NULL; armv8->armv8_mmu.armv8_cache.display_cache_info = NULL; return ERROR_OK; } static int armv8_aarch64_state(struct target *target) { struct arm *arm = target_to_arm(target); if (arm->common_magic != ARM_COMMON_MAGIC) { LOG_ERROR("BUG: called for a non-ARM target"); return ERROR_FAIL; } LOG_USER("%s halted in %s state due to %s, current mode: %s\n" "cpsr: 0x%8.8" PRIx32 " pc: 0x%" PRIx64 "%s", target_name(target), armv8_state_strings[arm->core_state], debug_reason_name(target), armv8_mode_name(arm->core_mode), buf_get_u32(arm->cpsr->value, 0, 32), buf_get_u64(arm->pc->value, 0, 64), (target->semihosting && target->semihosting->is_active) ? ", semihosting" : ""); return ERROR_OK; } int armv8_arch_state(struct target *target) { static const char * const state[] = { "disabled", "enabled" }; struct armv8_common *armv8 = target_to_armv8(target); struct arm *arm = &armv8->arm; if (armv8->common_magic != ARMV8_COMMON_MAGIC) { LOG_ERROR("BUG: called for a non-Armv8 target"); return ERROR_COMMAND_SYNTAX_ERROR; } if (arm->core_state == ARM_STATE_AARCH64) armv8_aarch64_state(target); else arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", state[armv8->armv8_mmu.mmu_enabled], state[armv8->armv8_mmu.armv8_cache.d_u_cache_enabled], state[armv8->armv8_mmu.armv8_cache.i_cache_enabled]); if (arm->core_mode == ARM_MODE_ABT) armv8_show_fault_registers(target); if (target->debug_reason == DBG_REASON_WATCHPOINT) LOG_USER("Watchpoint triggered at " TARGET_ADDR_FMT, armv8->dpm.wp_addr); return ERROR_OK; } static struct reg_data_type aarch64_vector_base_types[] = { {REG_TYPE_IEEE_DOUBLE, "ieee_double", 0, {NULL} }, {REG_TYPE_UINT64, "uint64", 0, {NULL} }, {REG_TYPE_INT64, "int64", 0, {NULL} }, {REG_TYPE_IEEE_SINGLE, "ieee_single", 0, {NULL} }, {REG_TYPE_UINT32, "uint32", 0, {NULL} }, {REG_TYPE_INT32, "int32", 0, {NULL} }, {REG_TYPE_UINT16, "uint16", 0, {NULL} }, {REG_TYPE_INT16, "int16", 0, {NULL} }, {REG_TYPE_UINT8, "uint8", 0, {NULL} }, {REG_TYPE_INT8, "int8", 0, {NULL} }, {REG_TYPE_UINT128, "uint128", 0, {NULL} }, {REG_TYPE_INT128, "int128", 0, {NULL} } }; static struct reg_data_type_vector aarch64_vector_types[] = { {aarch64_vector_base_types + 0, 2}, {aarch64_vector_base_types + 1, 2}, {aarch64_vector_base_types + 2, 2}, {aarch64_vector_base_types + 3, 4}, {aarch64_vector_base_types + 4, 4}, {aarch64_vector_base_types + 5, 4}, {aarch64_vector_base_types + 6, 8}, {aarch64_vector_base_types + 7, 8}, {aarch64_vector_base_types + 8, 16}, {aarch64_vector_base_types + 9, 16}, {aarch64_vector_base_types + 10, 01}, {aarch64_vector_base_types + 11, 01}, }; static struct reg_data_type aarch64_fpu_vector[] = { {REG_TYPE_ARCH_DEFINED, "v2d", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 0} }, {REG_TYPE_ARCH_DEFINED, "v2u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 1} }, {REG_TYPE_ARCH_DEFINED, "v2i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 2} }, {REG_TYPE_ARCH_DEFINED, "v4f", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 3} }, {REG_TYPE_ARCH_DEFINED, "v4u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 4} }, {REG_TYPE_ARCH_DEFINED, "v4i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 5} }, {REG_TYPE_ARCH_DEFINED, "v8u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 6} }, {REG_TYPE_ARCH_DEFINED, "v8i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 7} }, {REG_TYPE_ARCH_DEFINED, "v16u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 8} }, {REG_TYPE_ARCH_DEFINED, "v16i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 9} }, {REG_TYPE_ARCH_DEFINED, "v1u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 10} }, {REG_TYPE_ARCH_DEFINED, "v1i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 11} }, }; static struct reg_data_type_union_field aarch64_union_fields_vnd[] = { {"f", aarch64_fpu_vector + 0, aarch64_union_fields_vnd + 1}, {"u", aarch64_fpu_vector + 1, aarch64_union_fields_vnd + 2}, {"s", aarch64_fpu_vector + 2, NULL}, }; static struct reg_data_type_union_field aarch64_union_fields_vns[] = { {"f", aarch64_fpu_vector + 3, aarch64_union_fields_vns + 1}, {"u", aarch64_fpu_vector + 4, aarch64_union_fields_vns + 2}, {"s", aarch64_fpu_vector + 5, NULL}, }; static struct reg_data_type_union_field aarch64_union_fields_vnh[] = { {"u", aarch64_fpu_vector + 6, aarch64_union_fields_vnh + 1}, {"s", aarch64_fpu_vector + 7, NULL}, }; static struct reg_data_type_union_field aarch64_union_fields_vnb[] = { {"u", aarch64_fpu_vector + 8, aarch64_union_fields_vnb + 1}, {"s", aarch64_fpu_vector + 9, NULL}, }; static struct reg_data_type_union_field aarch64_union_fields_vnq[] = { {"u", aarch64_fpu_vector + 10, aarch64_union_fields_vnq + 1}, {"s", aarch64_fpu_vector + 11, NULL}, }; static struct reg_data_type_union aarch64_union_types[] = { {aarch64_union_fields_vnd}, {aarch64_union_fields_vns}, {aarch64_union_fields_vnh}, {aarch64_union_fields_vnb}, {aarch64_union_fields_vnq}, }; static struct reg_data_type aarch64_fpu_union[] = { {REG_TYPE_ARCH_DEFINED, "vnd", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 0} }, {REG_TYPE_ARCH_DEFINED, "vns", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 1} }, {REG_TYPE_ARCH_DEFINED, "vnh", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 2} }, {REG_TYPE_ARCH_DEFINED, "vnb", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 3} }, {REG_TYPE_ARCH_DEFINED, "vnq", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 4} }, }; static struct reg_data_type_union_field aarch64v_union_fields[] = { {"d", aarch64_fpu_union + 0, aarch64v_union_fields + 1}, {"s", aarch64_fpu_union + 1, aarch64v_union_fields + 2}, {"h", aarch64_fpu_union + 2, aarch64v_union_fields + 3}, {"b", aarch64_fpu_union + 3, aarch64v_union_fields + 4}, {"q", aarch64_fpu_union + 4, NULL}, }; static struct reg_data_type_union aarch64v_union[] = { {aarch64v_union_fields} }; static struct reg_data_type aarch64v[] = { {REG_TYPE_ARCH_DEFINED, "aarch64v", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64v_union} }, }; static struct reg_data_type_bitfield aarch64_cpsr_bits[] = { { 0, 0, REG_TYPE_UINT8 }, { 2, 3, REG_TYPE_UINT8 }, { 4, 4, REG_TYPE_UINT8 }, { 6, 6, REG_TYPE_BOOL }, { 7, 7, REG_TYPE_BOOL }, { 8, 8, REG_TYPE_BOOL }, { 9, 9, REG_TYPE_BOOL }, { 20, 20, REG_TYPE_BOOL }, { 21, 21, REG_TYPE_BOOL }, { 28, 28, REG_TYPE_BOOL }, { 29, 29, REG_TYPE_BOOL }, { 30, 30, REG_TYPE_BOOL }, { 31, 31, REG_TYPE_BOOL }, }; static struct reg_data_type_flags_field aarch64_cpsr_fields[] = { { "SP", aarch64_cpsr_bits + 0, aarch64_cpsr_fields + 1 }, { "EL", aarch64_cpsr_bits + 1, aarch64_cpsr_fields + 2 }, { "nRW", aarch64_cpsr_bits + 2, aarch64_cpsr_fields + 3 }, { "F", aarch64_cpsr_bits + 3, aarch64_cpsr_fields + 4 }, { "I", aarch64_cpsr_bits + 4, aarch64_cpsr_fields + 5 }, { "A", aarch64_cpsr_bits + 5, aarch64_cpsr_fields + 6 }, { "D", aarch64_cpsr_bits + 6, aarch64_cpsr_fields + 7 }, { "IL", aarch64_cpsr_bits + 7, aarch64_cpsr_fields + 8 }, { "SS", aarch64_cpsr_bits + 8, aarch64_cpsr_fields + 9 }, { "V", aarch64_cpsr_bits + 9, aarch64_cpsr_fields + 10 }, { "C", aarch64_cpsr_bits + 10, aarch64_cpsr_fields + 11 }, { "Z", aarch64_cpsr_bits + 11, aarch64_cpsr_fields + 12 }, { "N", aarch64_cpsr_bits + 12, NULL } }; static struct reg_data_type_flags aarch64_cpsr_flags[] = { { 4, aarch64_cpsr_fields } }; static struct reg_data_type aarch64_flags_cpsr[] = { {REG_TYPE_ARCH_DEFINED, "cpsr_flags", REG_TYPE_CLASS_FLAGS, {.reg_type_flags = aarch64_cpsr_flags} }, }; static const struct { unsigned id; const char *name; unsigned bits; enum arm_mode mode; enum reg_type type; const char *group; const char *feature; struct reg_data_type *data_type; } armv8_regs[] = { { ARMV8_R0, "x0", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R1, "x1", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R2, "x2", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R3, "x3", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R4, "x4", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R5, "x5", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R6, "x6", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R7, "x7", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R8, "x8", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R9, "x9", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R10, "x10", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R11, "x11", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R12, "x12", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R13, "x13", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R14, "x14", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R15, "x15", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R16, "x16", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R17, "x17", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R18, "x18", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R19, "x19", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R20, "x20", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R21, "x21", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R22, "x22", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R23, "x23", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R24, "x24", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R25, "x25", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R26, "x26", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R27, "x27", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R28, "x28", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R29, "x29", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_R30, "x30", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_SP, "sp", 64, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_PC, "pc", 64, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_XPSR, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "general", "org.gnu.gdb.aarch64.core", aarch64_flags_cpsr}, { ARMV8_V0, "v0", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V1, "v1", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V2, "v2", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V3, "v3", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V4, "v4", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V5, "v5", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V6, "v6", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V7, "v7", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V8, "v8", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V9, "v9", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V10, "v10", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V11, "v11", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V12, "v12", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V13, "v13", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V14, "v14", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V15, "v15", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V16, "v16", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V17, "v17", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V18, "v18", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V19, "v19", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V20, "v20", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V21, "v21", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V22, "v22", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V23, "v23", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V24, "v24", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V25, "v25", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V26, "v26", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V27, "v27", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V28, "v28", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V29, "v29", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V30, "v30", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V31, "v31", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_FPSR, "fpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "simdfp", "org.gnu.gdb.aarch64.fpu", NULL}, { ARMV8_FPCR, "fpcr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "simdfp", "org.gnu.gdb.aarch64.fpu", NULL}, { ARMV8_ELR_EL1, "ELR_EL1", 64, ARMV8_64_EL1H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked", NULL}, { ARMV8_ESR_EL1, "ESR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", NULL}, { ARMV8_SPSR_EL1, "SPSR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", NULL}, { ARMV8_ELR_EL2, "ELR_EL2", 64, ARMV8_64_EL2H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked", NULL}, { ARMV8_ESR_EL2, "ESR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", NULL}, { ARMV8_SPSR_EL2, "SPSR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", NULL}, { ARMV8_ELR_EL3, "ELR_EL3", 64, ARMV8_64_EL3H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked", NULL}, { ARMV8_ESR_EL3, "ESR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", NULL}, { ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", NULL}, { ARMV8_PAUTH_DMASK, "pauth_dmask", 64, ARM_MODE_ANY, REG_TYPE_UINT64, NULL, "org.gnu.gdb.aarch64.pauth", NULL}, { ARMV8_PAUTH_CMASK, "pauth_cmask", 64, ARM_MODE_ANY, REG_TYPE_UINT64, NULL, "org.gnu.gdb.aarch64.pauth", NULL}, }; static const struct { unsigned id; unsigned mapping; const char *name; unsigned bits; enum arm_mode mode; enum reg_type type; const char *group; const char *feature; } armv8_regs32[] = { { ARMV8_R0, 0, "r0", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R1, 0, "r1", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R2, 0, "r2", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R3, 0, "r3", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R4, 0, "r4", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R5, 0, "r5", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R6, 0, "r6", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R7, 0, "r7", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R8, 0, "r8", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R9, 0, "r9", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R10, 0, "r10", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R11, 0, "r11", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R12, 0, "r12", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R13, 0, "sp", 32, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R14, 0, "lr", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" }, { ARMV8_PC, 0, "pc", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" }, { ARMV8_XPSR, 0, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_V0, 0, "d0", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V0, 8, "d1", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V1, 0, "d2", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V1, 8, "d3", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V2, 0, "d4", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V2, 8, "d5", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V3, 0, "d6", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V3, 8, "d7", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V4, 0, "d8", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V4, 8, "d9", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V5, 0, "d10", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V5, 8, "d11", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V6, 0, "d12", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V6, 8, "d13", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V7, 0, "d14", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V7, 8, "d15", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V8, 0, "d16", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V8, 8, "d17", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V9, 0, "d18", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V9, 8, "d19", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V10, 0, "d20", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V10, 8, "d21", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V11, 0, "d22", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V11, 8, "d23", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V12, 0, "d24", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V12, 8, "d25", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V13, 0, "d26", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V13, 8, "d27", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V14, 0, "d28", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V14, 8, "d29", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V15, 0, "d30", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V15, 8, "d31", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_FPSR, 0, "fpscr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "float", "org.gnu.gdb.arm.vfp"}, }; #define ARMV8_NUM_REGS ARRAY_SIZE(armv8_regs) #define ARMV8_NUM_REGS32 ARRAY_SIZE(armv8_regs32) static int armv8_get_core_reg(struct reg *reg) { struct arm_reg *armv8_reg = reg->arch_info; struct target *target = armv8_reg->target; struct arm *arm = target_to_arm(target); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; return arm->read_core_reg(target, reg, armv8_reg->num, arm->core_mode); } static int armv8_set_core_reg(struct reg *reg, uint8_t *buf) { struct arm_reg *armv8_reg = reg->arch_info; struct target *target = armv8_reg->target; struct arm *arm = target_to_arm(target); uint64_t value = buf_get_u64(buf, 0, reg->size); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; if (reg->size <= 64) { if (reg == arm->cpsr) armv8_set_cpsr(arm, (uint32_t)value); else { buf_set_u64(reg->value, 0, reg->size, value); reg->valid = true; } } else if (reg->size <= 128) { uint64_t hvalue = buf_get_u64(buf + 8, 0, reg->size - 64); buf_set_u64(reg->value, 0, 64, value); buf_set_u64(reg->value + 8, 0, reg->size - 64, hvalue); reg->valid = true; } reg->dirty = true; return ERROR_OK; } static const struct reg_arch_type armv8_reg_type = { .get = armv8_get_core_reg, .set = armv8_set_core_reg, }; static int armv8_get_core_reg32(struct reg *reg) { struct arm_reg *armv8_reg = reg->arch_info; struct target *target = armv8_reg->target; struct arm *arm = target_to_arm(target); struct reg_cache *cache = arm->core_cache; struct reg *reg64; int retval; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; /* get the corresponding Aarch64 register */ reg64 = cache->reg_list + armv8_reg->num; if (reg64->valid) { reg->valid = true; return ERROR_OK; } retval = arm->read_core_reg(target, reg64, armv8_reg->num, arm->core_mode); if (retval == ERROR_OK) reg->valid = reg64->valid; return retval; } static int armv8_set_core_reg32(struct reg *reg, uint8_t *buf) { struct arm_reg *armv8_reg = reg->arch_info; struct target *target = armv8_reg->target; struct arm *arm = target_to_arm(target); struct reg_cache *cache = arm->core_cache; struct reg *reg64 = cache->reg_list + armv8_reg->num; uint32_t value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; if (reg64 == arm->cpsr) { armv8_set_cpsr(arm, value); } else { if (reg->size <= 32) buf_set_u32(reg->value, 0, 32, value); else if (reg->size <= 64) { uint64_t value64 = buf_get_u64(buf, 0, 64); buf_set_u64(reg->value, 0, 64, value64); } reg->valid = true; reg64->valid = true; } reg64->dirty = true; return ERROR_OK; } static const struct reg_arch_type armv8_reg32_type = { .get = armv8_get_core_reg32, .set = armv8_set_core_reg32, }; /** Builds cache of architecturally defined registers. */ struct reg_cache *armv8_build_reg_cache(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); struct arm *arm = &armv8->arm; int num_regs = ARMV8_NUM_REGS; int num_regs32 = ARMV8_NUM_REGS32; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg_cache *cache32 = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); struct reg *reg_list32 = calloc(num_regs32, sizeof(struct reg)); struct arm_reg *arch_info = calloc(num_regs, sizeof(struct arm_reg)); struct reg_feature *feature; int i; /* Build the process context cache */ cache->name = "Aarch64 registers"; cache->next = cache32; cache->reg_list = reg_list; cache->num_regs = num_regs; for (i = 0; i < num_regs; i++) { arch_info[i].num = armv8_regs[i].id; arch_info[i].mode = armv8_regs[i].mode; arch_info[i].target = target; arch_info[i].arm = arm; reg_list[i].name = armv8_regs[i].name; reg_list[i].size = armv8_regs[i].bits; reg_list[i].value = &arch_info[i].value[0]; reg_list[i].type = &armv8_reg_type; reg_list[i].arch_info = &arch_info[i]; reg_list[i].group = armv8_regs[i].group; reg_list[i].number = i; reg_list[i].exist = true; reg_list[i].caller_save = true; /* gdb defaults to true */ feature = calloc(1, sizeof(struct reg_feature)); if (feature) { feature->name = armv8_regs[i].feature; reg_list[i].feature = feature; } else LOG_ERROR("unable to allocate feature list"); reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); if (reg_list[i].reg_data_type) { if (!armv8_regs[i].data_type) reg_list[i].reg_data_type->type = armv8_regs[i].type; else *reg_list[i].reg_data_type = *armv8_regs[i].data_type; } else LOG_ERROR("unable to allocate reg type list"); if (i == ARMV8_PAUTH_CMASK || i == ARMV8_PAUTH_DMASK) reg_list[i].exist = armv8->enable_pauth; } arm->cpsr = reg_list + ARMV8_XPSR; arm->pc = reg_list + ARMV8_PC; arm->core_cache = cache; /* shadow cache for ARM mode registers */ cache32->name = "Aarch32 registers"; cache32->next = NULL; cache32->reg_list = reg_list32; cache32->num_regs = num_regs32; for (i = 0; i < num_regs32; i++) { reg_list32[i].name = armv8_regs32[i].name; reg_list32[i].size = armv8_regs32[i].bits; reg_list32[i].value = &arch_info[armv8_regs32[i].id].value[armv8_regs32[i].mapping]; reg_list32[i].type = &armv8_reg32_type; reg_list32[i].arch_info = &arch_info[armv8_regs32[i].id]; reg_list32[i].group = armv8_regs32[i].group; reg_list32[i].number = i; reg_list32[i].exist = true; reg_list32[i].caller_save = true; feature = calloc(1, sizeof(struct reg_feature)); if (feature) { feature->name = armv8_regs32[i].feature; reg_list32[i].feature = feature; } else LOG_ERROR("unable to allocate feature list"); reg_list32[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); if (reg_list32[i].reg_data_type) reg_list32[i].reg_data_type->type = armv8_regs32[i].type; else LOG_ERROR("unable to allocate reg type list"); } (*cache_p) = cache; return cache; } struct reg *armv8_reg_current(struct arm *arm, unsigned regnum) { struct reg *r; if (regnum > (ARMV8_LAST_REG - 1)) return NULL; r = arm->core_cache->reg_list + regnum; return r; } static void armv8_free_cache(struct reg_cache *cache, bool regs32) { struct reg *reg; unsigned int i; if (!cache) return; for (i = 0; i < cache->num_regs; i++) { reg = &cache->reg_list[i]; free(reg->feature); free(reg->reg_data_type); } if (!regs32) free(cache->reg_list[0].arch_info); free(cache->reg_list); free(cache); } void armv8_free_reg_cache(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); struct arm *arm = &armv8->arm; struct reg_cache *cache = NULL, *cache32 = NULL; cache = arm->core_cache; if (cache) cache32 = cache->next; armv8_free_cache(cache32, true); armv8_free_cache(cache, false); arm->core_cache = NULL; } const struct command_registration armv8_command_handlers[] = { { .name = "catch_exc", .handler = armv8_handle_exception_catch_command, .mode = COMMAND_EXEC, .help = "configure exception catch", .usage = "[(nsec_el1,nsec_el2,sec_el1,sec_el3)+,off]", }, { .name = "pauth", .handler = armv8_pauth_command, .mode = COMMAND_CONFIG, .help = "enable or disable providing GDB with an 8-bytes mask to " "remove signature bits added by pointer authentication." "Pointer authentication feature is broken until gdb 12.1, going to be fixed. " "Consider using a newer version of gdb if you want enable " "pauth feature.", .usage = "[on|off]", }, COMMAND_REGISTRATION_DONE }; const char *armv8_get_gdb_arch(struct target *target) { struct arm *arm = target_to_arm(target); return arm->core_state == ARM_STATE_AARCH64 ? "aarch64" : "arm"; } int armv8_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { struct arm *arm = target_to_arm(target); int i; if (arm->core_state == ARM_STATE_AARCH64) { LOG_DEBUG("Creating Aarch64 register list for target %s", target_name(target)); switch (reg_class) { case REG_CLASS_GENERAL: *reg_list_size = ARMV8_V0; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < *reg_list_size; i++) (*reg_list)[i] = armv8_reg_current(arm, i); return ERROR_OK; case REG_CLASS_ALL: *reg_list_size = ARMV8_LAST_REG; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < *reg_list_size; i++) (*reg_list)[i] = armv8_reg_current(arm, i); return ERROR_OK; default: LOG_ERROR("not a valid register class type in query."); return ERROR_FAIL; } } else { struct reg_cache *cache32 = arm->core_cache->next; LOG_DEBUG("Creating Aarch32 register list for target %s", target_name(target)); switch (reg_class) { case REG_CLASS_GENERAL: *reg_list_size = ARMV8_R14 + 3; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < *reg_list_size; i++) (*reg_list)[i] = cache32->reg_list + i; return ERROR_OK; case REG_CLASS_ALL: *reg_list_size = cache32->num_regs; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < *reg_list_size; i++) (*reg_list)[i] = cache32->reg_list + i; return ERROR_OK; default: LOG_ERROR("not a valid register class type in query."); return ERROR_FAIL; } } } int armv8_set_dbgreg_bits(struct armv8_common *armv8, unsigned int reg, unsigned long mask, unsigned long value) { uint32_t tmp; /* Read register */ int retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + reg, &tmp); if (retval != ERROR_OK) return retval; /* clear bitfield */ tmp &= ~mask; /* put new value */ tmp |= value & mask; /* write new value */ retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + reg, tmp); return retval; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv8.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2015 by David Ung * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV8_H #define OPENOCD_TARGET_ARMV8_H #include "arm_adi_v5.h" #include "arm.h" #include "armv4_5_mmu.h" #include "armv4_5_cache.h" #include "armv8_dpm.h" #include "arm_cti.h" enum { ARMV8_R0 = 0, ARMV8_R1, ARMV8_R2, ARMV8_R3, ARMV8_R4, ARMV8_R5, ARMV8_R6, ARMV8_R7, ARMV8_R8, ARMV8_R9, ARMV8_R10, ARMV8_R11, ARMV8_R12, ARMV8_R13, ARMV8_R14, ARMV8_R15, ARMV8_R16, ARMV8_R17, ARMV8_R18, ARMV8_R19, ARMV8_R20, ARMV8_R21, ARMV8_R22, ARMV8_R23, ARMV8_R24, ARMV8_R25, ARMV8_R26, ARMV8_R27, ARMV8_R28, ARMV8_R29, ARMV8_R30, ARMV8_SP = 31, ARMV8_PC = 32, ARMV8_XPSR = 33, ARMV8_V0 = 34, ARMV8_V1, ARMV8_V2, ARMV8_V3, ARMV8_V4, ARMV8_V5, ARMV8_V6, ARMV8_V7, ARMV8_V8, ARMV8_V9, ARMV8_V10, ARMV8_V11, ARMV8_V12, ARMV8_V13, ARMV8_V14, ARMV8_V15, ARMV8_V16, ARMV8_V17, ARMV8_V18, ARMV8_V19, ARMV8_V20, ARMV8_V21, ARMV8_V22, ARMV8_V23, ARMV8_V24, ARMV8_V25, ARMV8_V26, ARMV8_V27, ARMV8_V28, ARMV8_V29, ARMV8_V30, ARMV8_V31, ARMV8_FPSR, ARMV8_FPCR, ARMV8_ELR_EL1 = 68, ARMV8_ESR_EL1 = 69, ARMV8_SPSR_EL1 = 70, ARMV8_ELR_EL2 = 71, ARMV8_ESR_EL2 = 72, ARMV8_SPSR_EL2 = 73, ARMV8_ELR_EL3 = 74, ARMV8_ESR_EL3 = 75, ARMV8_SPSR_EL3 = 76, /* Pseudo registers defined by GDB to remove the pauth signature. */ ARMV8_PAUTH_DMASK = 77, ARMV8_PAUTH_CMASK = 78, ARMV8_LAST_REG, }; enum run_control_op { ARMV8_RUNCONTROL_UNKNOWN = 0, ARMV8_RUNCONTROL_RESUME = 1, ARMV8_RUNCONTROL_HALT = 2, ARMV8_RUNCONTROL_STEP = 3, }; #define ARMV8_COMMON_MAGIC 0x0A450AAAU /* VA to PA translation operations opc2 values*/ #define V2PCWPR 0 #define V2PCWPW 1 #define V2PCWUR 2 #define V2PCWUW 3 #define V2POWPR 4 #define V2POWPW 5 #define V2POWUR 6 #define V2POWUW 7 /* L210/L220 cache controller support */ struct armv8_l2x_cache { uint32_t base; uint32_t way; }; struct armv8_cachesize { uint32_t level_num; /* cache dimensioning */ uint32_t linelen; uint32_t associativity; uint32_t nsets; uint32_t cachesize; /* info for set way operation on cache */ uint32_t index; uint32_t index_shift; uint32_t way; uint32_t way_shift; }; /* information about one architecture cache at any level */ struct armv8_arch_cache { int ctype; /* cache type, CLIDR encoding */ struct armv8_cachesize d_u_size; /* data cache */ struct armv8_cachesize i_size; /* instruction cache */ }; struct armv8_cache_common { int info; int loc; uint32_t iminline; uint32_t dminline; struct armv8_arch_cache arch[6]; /* cache info, L1 - L7 */ int i_cache_enabled; int d_u_cache_enabled; /* l2 external unified cache if some */ void *l2_cache; int (*flush_all_data_cache)(struct target *target); int (*display_cache_info)(struct command_invocation *cmd, struct armv8_cache_common *armv8_cache); }; struct armv8_mmu_common { /* following field mmu working way */ int32_t ttbr1_used; /* -1 not initialized, 0 no ttbr1 1 ttbr1 used and */ uint64_t ttbr0_mask;/* masked to be used */ uint32_t ttbcr; /* cache for ttbcr register */ uint32_t ttbr_mask[2]; uint32_t ttbr_range[2]; int (*read_physical_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); struct armv8_cache_common armv8_cache; uint32_t mmu_enabled; }; struct armv8_common { unsigned int common_magic; struct arm arm; struct reg_cache *core_cache; /* Core Debug Unit */ struct arm_dpm dpm; target_addr_t debug_base; struct adiv5_ap *debug_ap; const uint32_t *opcodes; /* mdir */ uint8_t multi_processor_system; uint8_t cluster_id; uint8_t cpu_id; /* armv8 aarch64 need below information for page translation */ uint8_t va_size; uint8_t pa_size; uint32_t page_size; uint64_t ttbr_base; bool is_armv8r; struct armv8_mmu_common armv8_mmu; struct arm_cti *cti; /* True if OpenOCD provides pointer auth related info to GDB */ bool enable_pauth; /* last run-control command issued to this target (resume, halt, step) */ enum run_control_op last_run_control_op; /* Direct processor core register read and writes */ int (*read_reg_u64)(struct armv8_common *armv8, int num, uint64_t *value); int (*write_reg_u64)(struct armv8_common *armv8, int num, uint64_t value); /* SIMD/FPU registers read/write interface */ int (*read_reg_u128)(struct armv8_common *armv8, int num, uint64_t *lvalue, uint64_t *hvalue); int (*write_reg_u128)(struct armv8_common *armv8, int num, uint64_t lvalue, uint64_t hvalue); int (*examine_debug_reason)(struct target *target); int (*post_debug_entry)(struct target *target); void (*pre_restore_context)(struct target *target); }; static inline struct armv8_common * target_to_armv8(struct target *target) { return container_of(target->arch_info, struct armv8_common, arm); } static inline bool is_armv8(struct armv8_common *armv8) { return armv8->common_magic == ARMV8_COMMON_MAGIC; } /* register offsets from armv8.debug_base */ #define CPUV8_DBG_MAINID0 0xD00 #define CPUV8_DBG_CPUFEATURE0 0xD20 #define CPUV8_DBG_DBGFEATURE0 0xD28 #define CPUV8_DBG_MEMFEATURE0 0xD38 #define CPUV8_DBG_LOCKACCESS 0xFB0 #define CPUV8_DBG_LOCKSTATUS 0xFB4 #define CPUV8_DBG_EDESR 0x20 #define CPUV8_DBG_EDECR 0x24 #define CPUV8_DBG_EDWAR0 0x30 #define CPUV8_DBG_EDWAR1 0x34 #define CPUV8_DBG_DSCR 0x088 #define CPUV8_DBG_DRCR 0x090 #define CPUV8_DBG_ECCR 0x098 #define CPUV8_DBG_PRCR 0x310 #define CPUV8_DBG_PRSR 0x314 #define CPUV8_DBG_DTRRX 0x080 #define CPUV8_DBG_ITR 0x084 #define CPUV8_DBG_SCR 0x088 #define CPUV8_DBG_DTRTX 0x08c #define CPUV8_DBG_BVR_BASE 0x400 #define CPUV8_DBG_BCR_BASE 0x408 #define CPUV8_DBG_WVR_BASE 0x800 #define CPUV8_DBG_WCR_BASE 0x808 #define CPUV8_DBG_VCR 0x01C #define CPUV8_DBG_OSLAR 0x300 #define CPUV8_DBG_AUTHSTATUS 0xFB8 #define PAGE_SIZE_4KB 0x1000 #define PAGE_SIZE_4KB_LEVEL0_BITS 39 #define PAGE_SIZE_4KB_LEVEL1_BITS 30 #define PAGE_SIZE_4KB_LEVEL2_BITS 21 #define PAGE_SIZE_4KB_LEVEL3_BITS 12 #define PAGE_SIZE_4KB_LEVEL0_MASK ((0x1FFULL) << PAGE_SIZE_4KB_LEVEL0_BITS) #define PAGE_SIZE_4KB_LEVEL1_MASK ((0x1FFULL) << PAGE_SIZE_4KB_LEVEL1_BITS) #define PAGE_SIZE_4KB_LEVEL2_MASK ((0x1FFULL) << PAGE_SIZE_4KB_LEVEL2_BITS) #define PAGE_SIZE_4KB_LEVEL3_MASK ((0x1FFULL) << PAGE_SIZE_4KB_LEVEL3_BITS) #define PAGE_SIZE_4KB_TRBBASE_MASK 0xFFFFFFFFF000 int armv8_arch_state(struct target *target); int armv8_read_mpidr(struct armv8_common *armv8); int armv8_identify_cache(struct armv8_common *armv8); int armv8_init_arch_info(struct target *target, struct armv8_common *armv8); int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va, target_addr_t *val, int meminfo); int armv8_mmu_translate_va(struct target *target, target_addr_t va, target_addr_t *val); int armv8_handle_cache_info_command(struct command_invocation *cmd, struct armv8_cache_common *armv8_cache); void armv8_set_cpsr(struct arm *arm, uint32_t cpsr); static inline unsigned int armv8_curel_from_core_mode(enum arm_mode core_mode) { switch (core_mode) { /* Aarch32 modes */ case ARM_MODE_USR: return 0; case ARM_MODE_SVC: case ARM_MODE_ABT: /* FIXME: EL3? */ case ARM_MODE_IRQ: /* FIXME: EL3? */ case ARM_MODE_FIQ: /* FIXME: EL3? */ case ARM_MODE_UND: /* FIXME: EL3? */ case ARM_MODE_SYS: /* FIXME: EL3? */ return 1; /* case ARM_MODE_HYP: * return 2; */ case ARM_MODE_MON: return 3; /* all Aarch64 modes */ default: return (core_mode >> 2) & 3; } } const char *armv8_mode_name(unsigned psr_mode); void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64); int armv8_set_dbgreg_bits(struct armv8_common *armv8, unsigned int reg, unsigned long mask, unsigned long value); extern void armv8_free_reg_cache(struct target *target); extern const struct command_registration armv8_command_handlers[]; #endif /* OPENOCD_TARGET_ARMV8_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv8_cache.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2016 by Matthias Welwarsky * * matthias.welwarsky@sysgo.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "armv8_cache.h" #include "armv8_dpm.h" #include "armv8_opcodes.h" #include "smp.h" /* CLIDR cache types */ #define CACHE_LEVEL_HAS_UNIFIED_CACHE 0x4 #define CACHE_LEVEL_HAS_D_CACHE 0x2 #define CACHE_LEVEL_HAS_I_CACHE 0x1 static int armv8_d_cache_sanity_check(struct armv8_common *armv8) { struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache; if (armv8_cache->d_u_cache_enabled) return ERROR_OK; return ERROR_TARGET_INVALID; } static int armv8_i_cache_sanity_check(struct armv8_common *armv8) { struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache; if (armv8_cache->i_cache_enabled) return ERROR_OK; return ERROR_TARGET_INVALID; } static int armv8_cache_d_inner_flush_level(struct armv8_common *armv8, struct armv8_cachesize *size, int cl) { struct arm_dpm *dpm = armv8->arm.dpm; int retval = ERROR_OK; int32_t c_way, c_index = size->index; LOG_DEBUG("cl %" PRId32, cl); do { c_way = size->way; do { uint32_t value = (c_index << size->index_shift) | (c_way << size->way_shift) | (cl << 1); /* * DC CISW - Clean and invalidate data cache * line by Set/Way. */ retval = dpm->instr_write_data_r0(dpm, armv8_opcode(armv8, ARMV8_OPC_DCCISW), value); if (retval != ERROR_OK) goto done; c_way -= 1; } while (c_way >= 0); c_index -= 1; } while (c_index >= 0); done: return retval; } static int armv8_cache_d_inner_clean_inval_all(struct armv8_common *armv8) { struct armv8_cache_common *cache = &(armv8->armv8_mmu.armv8_cache); struct arm_dpm *dpm = armv8->arm.dpm; int cl; int retval; retval = armv8_d_cache_sanity_check(armv8); if (retval != ERROR_OK) return retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; for (cl = 0; cl < cache->loc; cl++) { /* skip i-only caches */ if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE) continue; armv8_cache_d_inner_flush_level(armv8, &cache->arch[cl].d_u_size, cl); } retval = dpm->finish(dpm); return retval; done: LOG_ERROR("clean invalidate failed"); dpm->finish(dpm); return retval; } int armv8_cache_d_inner_flush_virt(struct armv8_common *armv8, target_addr_t va, size_t size) { struct arm_dpm *dpm = armv8->arm.dpm; struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache; uint64_t linelen = armv8_cache->dminline; target_addr_t va_line, va_end; int retval; retval = armv8_d_cache_sanity_check(armv8); if (retval != ERROR_OK) return retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; va_line = va & (-linelen); va_end = va + size; while (va_line < va_end) { /* DC CIVAC */ /* Aarch32: DCCIMVAC: ARMV4_5_MCR(15, 0, 0, 7, 14, 1) */ retval = dpm->instr_write_data_r0_64(dpm, armv8_opcode(armv8, ARMV8_OPC_DCCIVAC), va_line); if (retval != ERROR_OK) goto done; va_line += linelen; } dpm->finish(dpm); return retval; done: LOG_ERROR("d-cache invalidate failed"); dpm->finish(dpm); return retval; } int armv8_cache_i_inner_inval_virt(struct armv8_common *armv8, target_addr_t va, size_t size) { struct arm_dpm *dpm = armv8->arm.dpm; struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache; uint64_t linelen = armv8_cache->iminline; target_addr_t va_line, va_end; int retval; retval = armv8_i_cache_sanity_check(armv8); if (retval != ERROR_OK) return retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; va_line = va & (-linelen); va_end = va + size; while (va_line < va_end) { /* IC IVAU - Invalidate instruction cache by VA to PoU. */ retval = dpm->instr_write_data_r0_64(dpm, armv8_opcode(armv8, ARMV8_OPC_ICIVAU), va_line); if (retval != ERROR_OK) goto done; va_line += linelen; } dpm->finish(dpm); return retval; done: LOG_ERROR("d-cache invalidate failed"); dpm->finish(dpm); return retval; } static int armv8_handle_inner_cache_info_command(struct command_invocation *cmd, struct armv8_cache_common *armv8_cache) { int cl; if (armv8_cache->info == -1) { command_print(cmd, "cache not yet identified"); return ERROR_OK; } for (cl = 0; cl < armv8_cache->loc; cl++) { struct armv8_arch_cache *arch = &(armv8_cache->arch[cl]); if (arch->ctype & 1) { command_print(cmd, "L%d I-Cache: linelen %" PRIu32 ", associativity %" PRIu32 ", nsets %" PRIu32 ", cachesize %" PRIu32 " KBytes", cl+1, arch->i_size.linelen, arch->i_size.associativity, arch->i_size.nsets, arch->i_size.cachesize); } if (arch->ctype >= 2) { command_print(cmd, "L%d D-Cache: linelen %" PRIu32 ", associativity %" PRIu32 ", nsets %" PRIu32 ", cachesize %" PRIu32 " KBytes", cl+1, arch->d_u_size.linelen, arch->d_u_size.associativity, arch->d_u_size.nsets, arch->d_u_size.cachesize); } } return ERROR_OK; } static int _armv8_flush_all_data(struct target *target) { return armv8_cache_d_inner_clean_inval_all(target_to_armv8(target)); } static int armv8_flush_all_data(struct target *target) { int retval = ERROR_FAIL; /* check that armv8_cache is correctly identify */ struct armv8_common *armv8 = target_to_armv8(target); if (armv8->armv8_mmu.armv8_cache.info == -1) { LOG_ERROR("trying to flush un-identified cache"); return retval; } if (target->smp) { /* look if all the other target have been flushed in order to flush level * 2 */ struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (curr->state == TARGET_HALTED) { LOG_INFO("Wait flushing data l1 on core %" PRId32, curr->coreid); retval = _armv8_flush_all_data(curr); } } } else retval = _armv8_flush_all_data(target); return retval; } static int get_cache_info(struct arm_dpm *dpm, int cl, int ct, uint32_t *cache_reg) { struct armv8_common *armv8 = dpm->arm->arch_info; int retval = ERROR_OK; /* select cache level */ retval = dpm->instr_write_data_r0(dpm, armv8_opcode(armv8, WRITE_REG_CSSELR), (cl << 1) | (ct == 1 ? 1 : 0)); if (retval != ERROR_OK) goto done; retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_CCSIDR), cache_reg); done: return retval; } static struct armv8_cachesize decode_cache_reg(uint32_t cache_reg) { struct armv8_cachesize size; int i = 0; size.linelen = 16 << (cache_reg & 0x7); size.associativity = ((cache_reg >> 3) & 0x3ff) + 1; size.nsets = ((cache_reg >> 13) & 0x7fff) + 1; size.cachesize = size.linelen * size.associativity * size.nsets / 1024; /* compute info for set way operation on cache */ size.index_shift = (cache_reg & 0x7) + 4; size.index = (cache_reg >> 13) & 0x7fff; size.way = ((cache_reg >> 3) & 0x3ff); while (((size.way << i) & 0x80000000) == 0) i++; size.way_shift = i; return size; } int armv8_identify_cache(struct armv8_common *armv8) { /* read cache descriptor */ int retval = ERROR_FAIL; struct arm *arm = &armv8->arm; struct arm_dpm *dpm = armv8->arm.dpm; uint32_t csselr, clidr, ctr; uint32_t cache_reg; int cl, ctype; struct armv8_cache_common *cache = &(armv8->armv8_mmu.armv8_cache); retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* check if we're in an unprivileged mode */ if (armv8_curel_from_core_mode(arm->core_mode) < SYSTEM_CUREL_EL1) { retval = armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H); if (retval != ERROR_OK) return retval; } /* retrieve CTR */ retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_CTR), &ctr); if (retval != ERROR_OK) goto done; cache->iminline = 4UL << (ctr & 0xf); cache->dminline = 4UL << ((ctr & 0xf0000) >> 16); LOG_DEBUG("ctr %" PRIx32 " ctr.iminline %" PRIu32 " ctr.dminline %" PRIu32, ctr, cache->iminline, cache->dminline); /* retrieve CLIDR */ retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_CLIDR), &clidr); if (retval != ERROR_OK) goto done; cache->loc = (clidr & 0x7000000) >> 24; LOG_DEBUG("Number of cache levels to PoC %" PRId32, cache->loc); /* retrieve selected cache for later restore * MRC p15, 2,<Rd>, c0, c0, 0; Read CSSELR */ retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_CSSELR), &csselr); if (retval != ERROR_OK) goto done; /* retrieve all available inner caches */ for (cl = 0; cl < cache->loc; clidr >>= 3, cl++) { /* isolate cache type at current level */ ctype = clidr & 7; /* skip reserved values */ if (ctype > CACHE_LEVEL_HAS_UNIFIED_CACHE) continue; /* separate d or unified d/i cache at this level ? */ if (ctype & (CACHE_LEVEL_HAS_UNIFIED_CACHE | CACHE_LEVEL_HAS_D_CACHE)) { /* retrieve d-cache info */ retval = get_cache_info(dpm, cl, 0, &cache_reg); if (retval != ERROR_OK) goto done; cache->arch[cl].d_u_size = decode_cache_reg(cache_reg); LOG_DEBUG("data/unified cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, cache->arch[cl].d_u_size.index, cache->arch[cl].d_u_size.index_shift, cache->arch[cl].d_u_size.way, cache->arch[cl].d_u_size.way_shift); LOG_DEBUG("cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", cache->arch[cl].d_u_size.linelen, cache->arch[cl].d_u_size.cachesize, cache->arch[cl].d_u_size.associativity); } /* separate i-cache at this level ? */ if (ctype & CACHE_LEVEL_HAS_I_CACHE) { /* retrieve i-cache info */ retval = get_cache_info(dpm, cl, 1, &cache_reg); if (retval != ERROR_OK) goto done; cache->arch[cl].i_size = decode_cache_reg(cache_reg); LOG_DEBUG("instruction cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, cache->arch[cl].i_size.index, cache->arch[cl].i_size.index_shift, cache->arch[cl].i_size.way, cache->arch[cl].i_size.way_shift); LOG_DEBUG("cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", cache->arch[cl].i_size.linelen, cache->arch[cl].i_size.cachesize, cache->arch[cl].i_size.associativity); } cache->arch[cl].ctype = ctype; } /* restore selected cache */ dpm->instr_write_data_r0(dpm, armv8_opcode(armv8, WRITE_REG_CSSELR), csselr); if (retval != ERROR_OK) goto done; armv8->armv8_mmu.armv8_cache.info = 1; /* if no l2 cache initialize l1 data cache flush function function */ if (!armv8->armv8_mmu.armv8_cache.flush_all_data_cache) { armv8->armv8_mmu.armv8_cache.display_cache_info = armv8_handle_inner_cache_info_command; armv8->armv8_mmu.armv8_cache.flush_all_data_cache = armv8_flush_all_data; } done: armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); dpm->finish(dpm); return retval; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv8_cache.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2016 by Matthias Welwarsky * * matthias.welwarsky@sysgo.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV8_CACHE_H_ #define OPENOCD_TARGET_ARMV8_CACHE_H_ #include "armv8.h" extern int armv8_cache_d_inner_flush_virt(struct armv8_common *armv8, target_addr_t va, size_t size); extern int armv8_cache_i_inner_inval_virt(struct armv8_common *armv8, target_addr_t va, size_t size); #endif /* OPENOCD_TARGET_ARMV8_CACHE_H_ */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv8_dpm.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2009 by David Brownell */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "armv8.h" #include "armv8_dpm.h" #include <jtag/jtag.h> #include "register.h" #include "breakpoints.h" #include "target_type.h" #include "armv8_opcodes.h" #include "helper/time_support.h" /* T32 ITR format */ #define T32_FMTITR(instr) (((instr & 0x0000FFFF) << 16) | ((instr & 0xFFFF0000) >> 16)) /** * @file * Implements various ARM DPM operations using architectural debug registers. * These routines layer over core-specific communication methods to cope with * implementation differences between cores like ARM1136 and Cortex-A8. * * The "Debug Programmers' Model" (DPM) for ARMv6 and ARMv7 is defined by * Part C (Debug Architecture) of the ARM Architecture Reference Manual, * ARMv7-A and ARMv7-R edition (ARM DDI 0406B). In OpenOCD, DPM operations * are abstracted through internal programming interfaces to share code and * to minimize needless differences in debug behavior between cores. */ /** * Get core state from EDSCR, without necessity to retrieve CPSR */ enum arm_state armv8_dpm_get_core_state(struct arm_dpm *dpm) { int el = (dpm->dscr >> 8) & 0x3; int rw = (dpm->dscr >> 10) & 0xF; dpm->last_el = el; /* In Debug state, each bit gives the current Execution state of each EL */ if ((rw >> el) & 0b1) return ARM_STATE_AARCH64; return ARM_STATE_ARM; } /*----------------------------------------------------------------------*/ static int dpmv8_write_dcc(struct armv8_common *armv8, uint32_t data) { return mem_ap_write_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DTRRX, data); } static int dpmv8_write_dcc_64(struct armv8_common *armv8, uint64_t data) { int ret; ret = mem_ap_write_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DTRRX, data); if (ret == ERROR_OK) ret = mem_ap_write_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DTRTX, data >> 32); return ret; } static int dpmv8_read_dcc(struct armv8_common *armv8, uint32_t *data, uint32_t *dscr_p) { uint32_t dscr = DSCR_ITE; int retval; if (dscr_p) dscr = *dscr_p; /* Wait for DTRRXfull */ long long then = timeval_ms(); while ((dscr & DSCR_DTR_TX_FULL) == 0) { retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; if (timeval_ms() > then + 1000) { LOG_ERROR("Timeout waiting for read dcc"); return ERROR_FAIL; } } retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DTRTX, data); if (retval != ERROR_OK) return retval; if (dscr_p) *dscr_p = dscr; return retval; } static int dpmv8_read_dcc_64(struct armv8_common *armv8, uint64_t *data, uint32_t *dscr_p) { uint32_t dscr = DSCR_ITE; uint32_t higher; int retval; if (dscr_p) dscr = *dscr_p; /* Wait for DTRRXfull */ long long then = timeval_ms(); while ((dscr & DSCR_DTR_TX_FULL) == 0) { retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; if (timeval_ms() > then + 1000) { LOG_ERROR("Timeout waiting for DTR_TX_FULL, dscr = 0x%08" PRIx32, dscr); return ERROR_FAIL; } } retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DTRTX, (uint32_t *)data); if (retval != ERROR_OK) return retval; retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DTRRX, &higher); if (retval != ERROR_OK) return retval; *data = *(uint32_t *)data | (uint64_t)higher << 32; if (dscr_p) *dscr_p = dscr; return retval; } static int dpmv8_dpm_prepare(struct arm_dpm *dpm) { struct armv8_common *armv8 = dpm->arm->arch_info; uint32_t dscr; int retval; /* set up invariant: ITE is set after ever DPM operation */ long long then = timeval_ms(); for (;; ) { retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; if ((dscr & DSCR_ITE) != 0) break; if (timeval_ms() > then + 1000) { LOG_ERROR("Timeout waiting for dpm prepare"); return ERROR_FAIL; } } /* update the stored copy of dscr */ dpm->dscr = dscr; /* this "should never happen" ... */ if (dscr & DSCR_DTR_RX_FULL) { LOG_ERROR("DSCR_DTR_RX_FULL, dscr 0x%08" PRIx32, dscr); /* Clear DCCRX */ retval = mem_ap_read_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DTRRX, &dscr); if (retval != ERROR_OK) return retval; } return retval; } static int dpmv8_dpm_finish(struct arm_dpm *dpm) { /* REVISIT what could be done here? */ return ERROR_OK; } static int dpmv8_exec_opcode(struct arm_dpm *dpm, uint32_t opcode, uint32_t *p_dscr) { struct armv8_common *armv8 = dpm->arm->arch_info; uint32_t dscr = dpm->dscr; int retval; if (p_dscr) dscr = *p_dscr; /* Wait for InstrCompl bit to be set */ long long then = timeval_ms(); while ((dscr & DSCR_ITE) == 0) { retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, &dscr); if (retval != ERROR_OK) { LOG_ERROR("Could not read DSCR register, opcode = 0x%08" PRIx32, opcode); return retval; } if (timeval_ms() > then + 1000) { LOG_ERROR("Timeout waiting for aarch64_exec_opcode"); return ERROR_FAIL; } } if (armv8_dpm_get_core_state(dpm) != ARM_STATE_AARCH64) opcode = T32_FMTITR(opcode); retval = mem_ap_write_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_ITR, opcode); if (retval != ERROR_OK) return retval; then = timeval_ms(); do { retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DSCR, &dscr); if (retval != ERROR_OK) { LOG_ERROR("Could not read DSCR register"); return retval; } if (timeval_ms() > then + 1000) { LOG_ERROR("Timeout waiting for aarch64_exec_opcode"); return ERROR_FAIL; } } while ((dscr & DSCR_ITE) == 0); /* Wait for InstrCompl bit to be set */ /* update dscr and el after each command execution */ dpm->dscr = dscr; if (dpm->last_el != ((dscr >> 8) & 3)) LOG_DEBUG("EL %i -> %" PRIu32, dpm->last_el, (dscr >> 8) & 3); dpm->last_el = (dscr >> 8) & 3; if (dscr & DSCR_ERR) { LOG_ERROR("Opcode 0x%08" PRIx32 ", DSCR.ERR=1, DSCR.EL=%i", opcode, dpm->last_el); armv8_dpm_handle_exception(dpm, true); retval = ERROR_FAIL; } if (p_dscr) *p_dscr = dscr; return retval; } static int dpmv8_instr_execute(struct arm_dpm *dpm, uint32_t opcode) { return dpmv8_exec_opcode(dpm, opcode, NULL); } static int dpmv8_instr_write_data_dcc(struct arm_dpm *dpm, uint32_t opcode, uint32_t data) { struct armv8_common *armv8 = dpm->arm->arch_info; int retval; retval = dpmv8_write_dcc(armv8, data); if (retval != ERROR_OK) return retval; return dpmv8_exec_opcode(dpm, opcode, NULL); } static int dpmv8_instr_write_data_dcc_64(struct arm_dpm *dpm, uint32_t opcode, uint64_t data) { struct armv8_common *armv8 = dpm->arm->arch_info; int retval; retval = dpmv8_write_dcc_64(armv8, data); if (retval != ERROR_OK) return retval; return dpmv8_exec_opcode(dpm, opcode, NULL); } static int dpmv8_instr_write_data_r0(struct arm_dpm *dpm, uint32_t opcode, uint32_t data) { struct armv8_common *armv8 = dpm->arm->arch_info; uint32_t dscr = DSCR_ITE; int retval; retval = dpmv8_write_dcc(armv8, data); if (retval != ERROR_OK) return retval; retval = dpmv8_exec_opcode(dpm, armv8_opcode(armv8, READ_REG_DTRRX), &dscr); if (retval != ERROR_OK) return retval; /* then the opcode, taking data from R0 */ return dpmv8_exec_opcode(dpm, opcode, &dscr); } static int dpmv8_instr_write_data_r0_64(struct arm_dpm *dpm, uint32_t opcode, uint64_t data) { struct armv8_common *armv8 = dpm->arm->arch_info; int retval; if (dpm->arm->core_state != ARM_STATE_AARCH64) return dpmv8_instr_write_data_r0(dpm, opcode, data); /* transfer data from DCC to R0 */ retval = dpmv8_write_dcc_64(armv8, data); if (retval == ERROR_OK) retval = dpmv8_exec_opcode(dpm, ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0), &dpm->dscr); /* then the opcode, taking data from R0 */ if (retval == ERROR_OK) retval = dpmv8_exec_opcode(dpm, opcode, &dpm->dscr); return retval; } static int dpmv8_instr_cpsr_sync(struct arm_dpm *dpm) { int retval; struct armv8_common *armv8 = dpm->arm->arch_info; /* "Prefetch flush" after modifying execution status in CPSR */ retval = dpmv8_exec_opcode(dpm, armv8_opcode(armv8, ARMV8_OPC_DSB_SY), &dpm->dscr); if (retval == ERROR_OK) dpmv8_exec_opcode(dpm, armv8_opcode(armv8, ARMV8_OPC_ISB_SY), &dpm->dscr); return retval; } static int dpmv8_instr_read_data_dcc(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data) { struct armv8_common *armv8 = dpm->arm->arch_info; int retval; /* the opcode, writing data to DCC */ retval = dpmv8_exec_opcode(dpm, opcode, &dpm->dscr); if (retval != ERROR_OK) return retval; return dpmv8_read_dcc(armv8, data, &dpm->dscr); } static int dpmv8_instr_read_data_dcc_64(struct arm_dpm *dpm, uint32_t opcode, uint64_t *data) { struct armv8_common *armv8 = dpm->arm->arch_info; int retval; /* the opcode, writing data to DCC */ retval = dpmv8_exec_opcode(dpm, opcode, &dpm->dscr); if (retval != ERROR_OK) return retval; return dpmv8_read_dcc_64(armv8, data, &dpm->dscr); } static int dpmv8_instr_read_data_r0(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data) { struct armv8_common *armv8 = dpm->arm->arch_info; int retval; /* the opcode, writing data to R0 */ retval = dpmv8_exec_opcode(dpm, opcode, &dpm->dscr); if (retval != ERROR_OK) return retval; /* write R0 to DCC */ retval = dpmv8_exec_opcode(dpm, armv8_opcode(armv8, WRITE_REG_DTRTX), &dpm->dscr); if (retval != ERROR_OK) return retval; return dpmv8_read_dcc(armv8, data, &dpm->dscr); } static int dpmv8_instr_read_data_r0_64(struct arm_dpm *dpm, uint32_t opcode, uint64_t *data) { struct armv8_common *armv8 = dpm->arm->arch_info; int retval; if (dpm->arm->core_state != ARM_STATE_AARCH64) { uint32_t tmp; retval = dpmv8_instr_read_data_r0(dpm, opcode, &tmp); if (retval == ERROR_OK) *data = tmp; return retval; } /* the opcode, writing data to R0 */ retval = dpmv8_exec_opcode(dpm, opcode, &dpm->dscr); if (retval != ERROR_OK) return retval; /* write R0 to DCC */ retval = dpmv8_exec_opcode(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, 0), &dpm->dscr); if (retval != ERROR_OK) return retval; return dpmv8_read_dcc_64(armv8, data, &dpm->dscr); } #if 0 static int dpmv8_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, target_addr_t addr, uint32_t control) { struct armv8_common *armv8 = dpm->arm->arch_info; uint32_t vr = armv8->debug_base; uint32_t cr = armv8->debug_base; int retval; switch (index_t) { case 0 ... 15: /* breakpoints */ vr += CPUV8_DBG_BVR_BASE; cr += CPUV8_DBG_BCR_BASE; break; case 16 ... 31: /* watchpoints */ vr += CPUV8_DBG_WVR_BASE; cr += CPUV8_DBG_WCR_BASE; index_t -= 16; break; default: return ERROR_FAIL; } vr += 16 * index_t; cr += 16 * index_t; LOG_DEBUG("A8: bpwp enable, vr %08x cr %08x", (unsigned) vr, (unsigned) cr); retval = mem_ap_write_atomic_u32(armv8->debug_ap, vr, addr); if (retval != ERROR_OK) return retval; return mem_ap_write_atomic_u32(armv8->debug_ap, cr, control); } #endif static int dpmv8_bpwp_disable(struct arm_dpm *dpm, unsigned index_t) { struct armv8_common *armv8 = dpm->arm->arch_info; uint32_t cr; switch (index_t) { case 0 ... 15: cr = armv8->debug_base + CPUV8_DBG_BCR_BASE; break; case 16 ... 31: cr = armv8->debug_base + CPUV8_DBG_WCR_BASE; index_t -= 16; break; default: return ERROR_FAIL; } cr += 16 * index_t; LOG_DEBUG("A: bpwp disable, cr %08x", (unsigned) cr); /* clear control register */ return mem_ap_write_atomic_u32(armv8->debug_ap, cr, 0); } /* * Coprocessor support */ /* Read coprocessor */ static int dpmv8_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; LOG_DEBUG("MRC p%d, %d, r0, c%d, c%d, %d", cpnum, (int) op1, (int) crn, (int) crm, (int) op2); /* read coprocessor register into R0; return via DCC */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2), value); /* (void) */ dpm->finish(dpm); return retval; } static int dpmv8_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum, (int) op1, (int) crn, (int) crm, (int) op2); /* read DCC into r0; then write coprocessor register from R0 */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2), value); /* (void) */ dpm->finish(dpm); return retval; } /*----------------------------------------------------------------------*/ /* * Register access utilities */ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) { struct armv8_common *armv8 = (struct armv8_common *)dpm->arm->arch_info; int retval = ERROR_OK; unsigned int target_el; enum arm_state core_state; uint32_t cpsr; /* restore previous mode */ if (mode == ARM_MODE_ANY) { cpsr = buf_get_u32(dpm->arm->cpsr->value, 0, 32); LOG_DEBUG("restoring mode, cpsr = 0x%08"PRIx32, cpsr); } else { LOG_DEBUG("setting mode 0x%x", mode); cpsr = mode; } switch (cpsr & 0x1f) { /* aarch32 modes */ case ARM_MODE_USR: target_el = 0; break; case ARM_MODE_SVC: case ARM_MODE_ABT: case ARM_MODE_IRQ: case ARM_MODE_FIQ: case ARM_MODE_SYS: target_el = 1; break; /* * TODO: handle ARM_MODE_HYP * case ARM_MODE_HYP: * target_el = 2; * break; */ case ARM_MODE_MON: target_el = 3; break; /* aarch64 modes */ default: target_el = (cpsr >> 2) & 3; } if (target_el > SYSTEM_CUREL_EL3) { LOG_ERROR("%s: Invalid target exception level %i", __func__, target_el); return ERROR_FAIL; } LOG_DEBUG("target_el = %i, last_el = %i", target_el, dpm->last_el); if (dpm->last_el == target_el) return ERROR_OK; /* nothing to do */ if (target_el > dpm->last_el) { retval = dpm->instr_execute(dpm, armv8_opcode(armv8, ARMV8_OPC_DCPS) | target_el); /* DCPS clobbers registers just like an exception taken */ armv8_dpm_handle_exception(dpm, false); } else { core_state = armv8_dpm_get_core_state(dpm); if (core_state != ARM_STATE_AARCH64) { /* cannot do DRPS/ERET when already in EL0 */ if (dpm->last_el != 0) { /* load SPSR with the desired mode and execute DRPS */ LOG_DEBUG("SPSR = 0x%08"PRIx32, cpsr); retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP_XPSR_T1(1, 0, 15), cpsr); if (retval == ERROR_OK) retval = dpm->instr_execute(dpm, armv8_opcode(armv8, ARMV8_OPC_DRPS)); } } else { /* * need to execute multiple DRPS instructions until target_el * is reached */ while (retval == ERROR_OK && dpm->last_el != target_el) { unsigned int cur_el = dpm->last_el; retval = dpm->instr_execute(dpm, armv8_opcode(armv8, ARMV8_OPC_DRPS)); if (cur_el == dpm->last_el) { LOG_INFO("Cannot reach EL %i, SPSR corrupted?", target_el); break; } } } /* On executing DRPS, DSPSR and DLR become UNKNOWN, mark them as dirty */ dpm->arm->cpsr->dirty = true; dpm->arm->pc->dirty = true; /* * re-evaluate the core state, we might be in Aarch32 state now * we rely on dpm->dscr being up-to-date */ core_state = armv8_dpm_get_core_state(dpm); armv8_select_opcodes(armv8, core_state == ARM_STATE_AARCH64); armv8_select_reg_access(armv8, core_state == ARM_STATE_AARCH64); } return retval; } /* * Common register read, relies on armv8_select_reg_access() having been called. */ static int dpmv8_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { struct armv8_common *armv8 = dpm->arm->arch_info; int retval = ERROR_FAIL; if (r->size <= 64) { uint64_t value_64; retval = armv8->read_reg_u64(armv8, regnum, &value_64); if (retval == ERROR_OK) { r->valid = true; r->dirty = false; buf_set_u64(r->value, 0, r->size, value_64); if (r->size == 64) LOG_DEBUG("READ: %s, %16.8llx", r->name, (unsigned long long) value_64); else LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned int) value_64); } } else if (r->size <= 128) { uint64_t lvalue = 0, hvalue = 0; retval = armv8->read_reg_u128(armv8, regnum, &lvalue, &hvalue); if (retval == ERROR_OK) { r->valid = true; r->dirty = false; buf_set_u64(r->value, 0, 64, lvalue); buf_set_u64(r->value + 8, 0, r->size - 64, hvalue); LOG_DEBUG("READ: %s, lvalue=%16.8llx", r->name, (unsigned long long) lvalue); LOG_DEBUG("READ: %s, hvalue=%16.8llx", r->name, (unsigned long long) hvalue); } } if (retval != ERROR_OK) LOG_ERROR("Failed to read %s register", r->name); return retval; } /* * Common register write, relies on armv8_select_reg_access() having been called. */ static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { struct armv8_common *armv8 = dpm->arm->arch_info; int retval = ERROR_FAIL; if (r->size <= 64) { uint64_t value_64; value_64 = buf_get_u64(r->value, 0, r->size); retval = armv8->write_reg_u64(armv8, regnum, value_64); if (retval == ERROR_OK) { r->dirty = false; if (r->size == 64) LOG_DEBUG("WRITE: %s, %16.8llx", r->name, (unsigned long long)value_64); else LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned int)value_64); } } else if (r->size <= 128) { uint64_t lvalue, hvalue; lvalue = buf_get_u64(r->value, 0, 64); hvalue = buf_get_u64(r->value + 8, 0, r->size - 64); retval = armv8->write_reg_u128(armv8, regnum, lvalue, hvalue); if (retval == ERROR_OK) { r->dirty = false; LOG_DEBUG("WRITE: %s, lvalue=%16.8llx", r->name, (unsigned long long) lvalue); LOG_DEBUG("WRITE: %s, hvalue=%16.8llx", r->name, (unsigned long long) hvalue); } } if (retval != ERROR_OK) LOG_ERROR("Failed to write %s register", r->name); return retval; } /** * Read basic registers of the current context: R0 to R15, and CPSR; * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb). * In normal operation this is called on entry to halting debug state, * possibly after some other operations supporting restore of debug state * or making sure the CPU is fully idle (drain write buffer, etc). */ int armv8_dpm_read_current_registers(struct arm_dpm *dpm) { struct arm *arm = dpm->arm; struct armv8_common *armv8 = (struct armv8_common *)arm->arch_info; struct reg_cache *cache; struct reg *r; uint32_t cpsr; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; cache = arm->core_cache; /* read R0 first (it's used for scratch), then CPSR */ r = cache->reg_list + ARMV8_R0; if (!r->valid) { retval = dpmv8_read_reg(dpm, r, ARMV8_R0); if (retval != ERROR_OK) goto fail; } r->dirty = true; /* read R1, too, it will be clobbered during memory access */ r = cache->reg_list + ARMV8_R1; if (!r->valid) { retval = dpmv8_read_reg(dpm, r, ARMV8_R1); if (retval != ERROR_OK) goto fail; } /* read cpsr to r0 and get it back */ retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_DSPSR), &cpsr); if (retval != ERROR_OK) goto fail; /* update core mode and state */ armv8_set_cpsr(arm, cpsr); for (unsigned int i = ARMV8_PC; i < cache->num_regs ; i++) { struct arm_reg *arm_reg; r = armv8_reg_current(arm, i); if (!r->exist || r->valid) continue; /* Skip reading FP-SIMD registers */ if (r->number >= ARMV8_V0 && r->number <= ARMV8_FPCR) continue; /* * Only read registers that are available from the * current EL (or core mode). */ arm_reg = r->arch_info; if (arm_reg->mode != ARM_MODE_ANY && dpm->last_el != armv8_curel_from_core_mode(arm_reg->mode)) continue; /* Special case: ARM_MODE_SYS has no SPSR at EL1 */ if (r->number == ARMV8_SPSR_EL1 && arm->core_mode == ARM_MODE_SYS) continue; retval = dpmv8_read_reg(dpm, r, i); if (retval != ERROR_OK) goto fail; } fail: dpm->finish(dpm); return retval; } /* Avoid needless I/O ... leave breakpoints and watchpoints alone * unless they're removed, or need updating because of single-stepping * or running debugger code. */ static int dpmv8_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp, struct dpm_bpwp *xp, bool *set_p) { int retval = ERROR_OK; bool disable; if (!set_p) { if (!xp->dirty) goto done; xp->dirty = false; /* removed or startup; we must disable it */ disable = true; } else if (bpwp) { if (!xp->dirty) goto done; /* disabled, but we must set it */ xp->dirty = disable = false; *set_p = true; } else { if (!*set_p) goto done; /* set, but we must temporarily disable it */ xp->dirty = disable = true; *set_p = false; } if (disable) retval = dpm->bpwp_disable(dpm, xp->number); else retval = dpm->bpwp_enable(dpm, xp->number, xp->address, xp->control); if (retval != ERROR_OK) LOG_ERROR("%s: can't %s HW %spoint %d", disable ? "disable" : "enable", target_name(dpm->arm->target), (xp->number < 16) ? "break" : "watch", xp->number & 0xf); done: return retval; } static int dpmv8_add_breakpoint(struct target *target, struct breakpoint *bp); /** * Writes all modified core registers for all processor modes. In normal * operation this is called on exit from halting debug state. * * @param dpm: represents the processor * @param bpwp: true ensures breakpoints and watchpoints are set, * false ensures they are cleared */ int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) { struct arm *arm = dpm->arm; struct reg_cache *cache = arm->core_cache; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* If we're managing hardware breakpoints for this core, enable * or disable them as requested. * * REVISIT We don't yet manage them for ANY cores. Eventually * we should be able to assume we handle them; but until then, * cope with the hand-crafted breakpoint code. */ if (arm->target->type->add_breakpoint == dpmv8_add_breakpoint) { for (unsigned i = 0; i < dpm->nbp; i++) { struct dpm_bp *dbp = dpm->dbp + i; struct breakpoint *bp = dbp->bp; retval = dpmv8_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp, bp ? &bp->is_set : NULL); if (retval != ERROR_OK) goto done; } } /* enable/disable watchpoints */ for (unsigned i = 0; i < dpm->nwp; i++) { struct dpm_wp *dwp = dpm->dwp + i; struct watchpoint *wp = dwp->wp; retval = dpmv8_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp, wp ? &wp->is_set : NULL); if (retval != ERROR_OK) goto done; } /* NOTE: writes to breakpoint and watchpoint registers might * be queued, and need (efficient/batched) flushing later. */ /* Restore original core mode and state */ retval = armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); if (retval != ERROR_OK) goto done; /* check everything except our scratch register R0 */ for (unsigned i = 1; i < cache->num_regs; i++) { struct arm_reg *r; /* skip non-existent */ if (!cache->reg_list[i].exist) continue; /* skip PC and CPSR */ if (i == ARMV8_PC || i == ARMV8_XPSR) continue; /* skip invalid */ if (!cache->reg_list[i].valid) continue; /* skip non-dirty */ if (!cache->reg_list[i].dirty) continue; /* skip all registers not on the current EL */ r = cache->reg_list[i].arch_info; if (r->mode != ARM_MODE_ANY && dpm->last_el != armv8_curel_from_core_mode(r->mode)) continue; retval = dpmv8_write_reg(dpm, &cache->reg_list[i], i); if (retval != ERROR_OK) break; } /* flush CPSR and PC */ if (retval == ERROR_OK) retval = dpmv8_write_reg(dpm, &cache->reg_list[ARMV8_XPSR], ARMV8_XPSR); if (retval == ERROR_OK) retval = dpmv8_write_reg(dpm, &cache->reg_list[ARMV8_PC], ARMV8_PC); /* flush R0 -- it's *very* dirty by now */ if (retval == ERROR_OK) retval = dpmv8_write_reg(dpm, &cache->reg_list[0], 0); if (retval == ERROR_OK) dpm->instr_cpsr_sync(dpm); done: dpm->finish(dpm); return retval; } /* * Standard ARM register accessors ... there are three methods * in "struct arm", to support individual read/write and bulk read * of registers. */ static int armv8_dpm_read_core_reg(struct target *target, struct reg *r, int regnum, enum arm_mode mode) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = target_to_arm(target)->dpm; int retval; int max = arm->core_cache->num_regs; if (regnum < 0 || regnum >= max) return ERROR_COMMAND_SYNTAX_ERROR; /* * REVISIT what happens if we try to read SPSR in a core mode * which has no such register? */ retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; retval = dpmv8_read_reg(dpm, r, regnum); if (retval != ERROR_OK) goto fail; fail: /* (void) */ dpm->finish(dpm); return retval; } static int armv8_dpm_write_core_reg(struct target *target, struct reg *r, int regnum, enum arm_mode mode, uint8_t *value) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = target_to_arm(target)->dpm; int retval; int max = arm->core_cache->num_regs; if (regnum < 0 || regnum > max) return ERROR_COMMAND_SYNTAX_ERROR; /* REVISIT what happens if we try to write SPSR in a core mode * which has no such register? */ retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; retval = dpmv8_write_reg(dpm, r, regnum); /* always clean up, regardless of error */ dpm->finish(dpm); return retval; } static int armv8_dpm_full_context(struct target *target) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; struct reg_cache *cache = arm->core_cache; int retval; bool did_read; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; do { enum arm_mode mode = ARM_MODE_ANY; did_read = false; /* We "know" arm_dpm_read_current_registers() was called so * the unmapped registers (R0..R7, PC, AND CPSR) and some * view of R8..R14 are current. We also "know" oddities of * register mapping: special cases for R8..R12 and SPSR. * * Pick some mode with unread registers and read them all. * Repeat until done. */ for (unsigned i = 0; i < cache->num_regs; i++) { struct arm_reg *r; if (!cache->reg_list[i].exist || cache->reg_list[i].valid) continue; r = cache->reg_list[i].arch_info; /* may need to pick a mode and set CPSR */ if (!did_read) { did_read = true; mode = r->mode; /* For regular (ARM_MODE_ANY) R8..R12 * in case we've entered debug state * in FIQ mode we need to patch mode. */ if (mode != ARM_MODE_ANY) retval = armv8_dpm_modeswitch(dpm, mode); else retval = armv8_dpm_modeswitch(dpm, ARM_MODE_USR); if (retval != ERROR_OK) goto done; } if (r->mode != mode) continue; /* CPSR was read, so "R16" must mean SPSR */ retval = dpmv8_read_reg(dpm, &cache->reg_list[i], (r->num == 16) ? 17 : r->num); if (retval != ERROR_OK) goto done; } } while (did_read); retval = armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); /* (void) */ dpm->finish(dpm); done: return retval; } /*----------------------------------------------------------------------*/ /* * Breakpoint and Watchpoint support. * * Hardware {break,watch}points are usually left active, to minimize * debug entry/exit costs. When they are set or cleared, it's done in * batches. Also, DPM-conformant hardware can update debug registers * regardless of whether the CPU is running or halted ... though that * fact isn't currently leveraged. */ static int dpmv8_bpwp_setup(struct arm_dpm *dpm, struct dpm_bpwp *xp, uint32_t addr, uint32_t length) { uint32_t control; control = (1 << 0) /* enable */ | (3 << 1); /* both user and privileged access */ /* Match 1, 2, or all 4 byte addresses in this word. * * FIXME: v7 hardware allows lengths up to 2 GB for BP and WP. * Support larger length, when addr is suitably aligned. In * particular, allow watchpoints on 8 byte "double" values. * * REVISIT allow watchpoints on unaligned 2-bit values; and on * v7 hardware, unaligned 4-byte ones too. */ switch (length) { case 1: control |= (1 << (addr & 3)) << 5; break; case 2: /* require 2-byte alignment */ if (!(addr & 1)) { control |= (3 << (addr & 2)) << 5; break; } /* FALL THROUGH */ case 4: /* require 4-byte alignment */ if (!(addr & 3)) { control |= 0xf << 5; break; } /* FALL THROUGH */ default: LOG_ERROR("unsupported {break,watch}point length/alignment"); return ERROR_COMMAND_SYNTAX_ERROR; } /* other shared control bits: * bits 15:14 == 0 ... both secure and nonsecure states (v6.1+ only) * bit 20 == 0 ... not linked to a context ID * bit 28:24 == 0 ... not ignoring N LSBs (v7 only) */ xp->address = addr & ~3; xp->control = control; xp->dirty = true; LOG_DEBUG("BPWP: addr %8.8" PRIx32 ", control %" PRIx32 ", number %d", xp->address, control, xp->number); /* hardware is updated in write_dirty_registers() */ return ERROR_OK; } static int dpmv8_add_breakpoint(struct target *target, struct breakpoint *bp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if (bp->length < 2) return ERROR_COMMAND_SYNTAX_ERROR; if (!dpm->bpwp_enable) return retval; /* FIXME we need a generic solution for software breakpoints. */ if (bp->type == BKPT_SOFT) LOG_DEBUG("using HW bkpt, not SW..."); for (unsigned i = 0; i < dpm->nbp; i++) { if (!dpm->dbp[i].bp) { retval = dpmv8_bpwp_setup(dpm, &dpm->dbp[i].bpwp, bp->address, bp->length); if (retval == ERROR_OK) dpm->dbp[i].bp = bp; break; } } return retval; } static int dpmv8_remove_breakpoint(struct target *target, struct breakpoint *bp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_COMMAND_SYNTAX_ERROR; for (unsigned i = 0; i < dpm->nbp; i++) { if (dpm->dbp[i].bp == bp) { dpm->dbp[i].bp = NULL; dpm->dbp[i].bpwp.dirty = true; /* hardware is updated in write_dirty_registers() */ retval = ERROR_OK; break; } } return retval; } static int dpmv8_watchpoint_setup(struct arm_dpm *dpm, unsigned index_t, struct watchpoint *wp) { int retval; struct dpm_wp *dwp = dpm->dwp + index_t; uint32_t control; /* this hardware doesn't support data value matching or masking */ if (wp->value || wp->mask != ~(uint32_t)0) { LOG_DEBUG("watchpoint values and masking not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = dpmv8_bpwp_setup(dpm, &dwp->bpwp, wp->address, wp->length); if (retval != ERROR_OK) return retval; control = dwp->bpwp.control; switch (wp->rw) { case WPT_READ: control |= 1 << 3; break; case WPT_WRITE: control |= 2 << 3; break; case WPT_ACCESS: control |= 3 << 3; break; } dwp->bpwp.control = control; dpm->dwp[index_t].wp = wp; return retval; } static int dpmv8_add_watchpoint(struct target *target, struct watchpoint *wp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if (dpm->bpwp_enable) { for (unsigned i = 0; i < dpm->nwp; i++) { if (!dpm->dwp[i].wp) { retval = dpmv8_watchpoint_setup(dpm, i, wp); break; } } } return retval; } static int dpmv8_remove_watchpoint(struct target *target, struct watchpoint *wp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_COMMAND_SYNTAX_ERROR; for (unsigned i = 0; i < dpm->nwp; i++) { if (dpm->dwp[i].wp == wp) { dpm->dwp[i].wp = NULL; dpm->dwp[i].bpwp.dirty = true; /* hardware is updated in write_dirty_registers() */ retval = ERROR_OK; break; } } return retval; } /* * Handle exceptions taken in debug state. This happens mostly for memory * accesses that violated a MMU policy. Taking an exception while in debug * state clobbers certain state registers on the target exception level. * Just mark those registers dirty so that they get restored on resume. * This works both for Aarch32 and Aarch64 states. * * This function must not perform any actions that trigger another exception * or a recursion will happen. */ void armv8_dpm_handle_exception(struct arm_dpm *dpm, bool do_restore) { struct armv8_common *armv8 = dpm->arm->arch_info; struct reg_cache *cache = dpm->arm->core_cache; enum arm_state core_state; uint64_t dlr; uint32_t dspsr; unsigned int el; static const int clobbered_regs_by_el[3][5] = { { ARMV8_PC, ARMV8_XPSR, ARMV8_ELR_EL1, ARMV8_ESR_EL1, ARMV8_SPSR_EL1 }, { ARMV8_PC, ARMV8_XPSR, ARMV8_ELR_EL2, ARMV8_ESR_EL2, ARMV8_SPSR_EL2 }, { ARMV8_PC, ARMV8_XPSR, ARMV8_ELR_EL3, ARMV8_ESR_EL3, ARMV8_SPSR_EL3 }, }; el = (dpm->dscr >> 8) & 3; /* safety check, must not happen since EL0 cannot be a target for an exception */ if (el < SYSTEM_CUREL_EL1 || el > SYSTEM_CUREL_EL3) { LOG_ERROR("%s: EL %i is invalid, DSCR corrupted?", __func__, el); return; } /* Clear sticky error */ mem_ap_write_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DRCR, DRCR_CSE); armv8->read_reg_u64(armv8, ARMV8_XPSR, &dlr); dspsr = dlr; armv8->read_reg_u64(armv8, ARMV8_PC, &dlr); LOG_DEBUG("Exception taken to EL %i, DLR=0x%016"PRIx64" DSPSR=0x%08"PRIx32, el, dlr, dspsr); /* mark all clobbered registers as dirty */ for (int i = 0; i < 5; i++) cache->reg_list[clobbered_regs_by_el[el-1][i]].dirty = true; /* * re-evaluate the core state, we might be in Aarch64 state now * we rely on dpm->dscr being up-to-date */ core_state = armv8_dpm_get_core_state(dpm); armv8_select_opcodes(armv8, core_state == ARM_STATE_AARCH64); armv8_select_reg_access(armv8, core_state == ARM_STATE_AARCH64); if (do_restore) armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); } /*----------------------------------------------------------------------*/ /* * Other debug and support utilities */ void armv8_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr) { struct target *target = dpm->arm->target; dpm->dscr = dscr; dpm->last_el = (dscr >> 8) & 3; /* Examine debug reason */ switch (DSCR_ENTRY(dscr)) { /* FALL THROUGH -- assume a v6 core in abort mode */ case DSCRV8_ENTRY_EXT_DEBUG: /* EDBGRQ */ target->debug_reason = DBG_REASON_DBGRQ; break; case DSCRV8_ENTRY_HALT_STEP_EXECLU: /* HALT step */ case DSCRV8_ENTRY_HALT_STEP_NORMAL: /* Halt step*/ case DSCRV8_ENTRY_HALT_STEP: target->debug_reason = DBG_REASON_SINGLESTEP; break; case DSCRV8_ENTRY_HLT: /* HLT instruction (software breakpoint) */ case DSCRV8_ENTRY_BKPT: /* SW BKPT (?) */ case DSCRV8_ENTRY_RESET_CATCH: /* Reset catch */ case DSCRV8_ENTRY_OS_UNLOCK: /*OS unlock catch*/ case DSCRV8_ENTRY_SW_ACCESS_DBG: /*SW access dbg register*/ target->debug_reason = DBG_REASON_BREAKPOINT; break; case DSCRV8_ENTRY_WATCHPOINT: /* asynch watchpoint */ target->debug_reason = DBG_REASON_WATCHPOINT; break; case DSCRV8_ENTRY_EXCEPTION_CATCH: /*exception catch*/ target->debug_reason = DBG_REASON_EXC_CATCH; break; default: target->debug_reason = DBG_REASON_UNDEFINED; break; } } /*----------------------------------------------------------------------*/ /* * Setup and management support. */ /** * Hooks up this DPM to its associated target; call only once. * Initially this only covers the register cache. * * Oh, and watchpoints. Yeah. */ int armv8_dpm_setup(struct arm_dpm *dpm) { struct arm *arm = dpm->arm; struct target *target = arm->target; struct reg_cache *cache; arm->dpm = dpm; /* register access setup */ arm->full_context = armv8_dpm_full_context; arm->read_core_reg = armv8_dpm_read_core_reg; arm->write_core_reg = armv8_dpm_write_core_reg; if (!arm->core_cache) { cache = armv8_build_reg_cache(target); if (!cache) return ERROR_FAIL; } /* coprocessor access setup */ arm->mrc = dpmv8_mrc; arm->mcr = dpmv8_mcr; dpm->prepare = dpmv8_dpm_prepare; dpm->finish = dpmv8_dpm_finish; dpm->instr_execute = dpmv8_instr_execute; dpm->instr_write_data_dcc = dpmv8_instr_write_data_dcc; dpm->instr_write_data_dcc_64 = dpmv8_instr_write_data_dcc_64; dpm->instr_write_data_r0 = dpmv8_instr_write_data_r0; dpm->instr_write_data_r0_64 = dpmv8_instr_write_data_r0_64; dpm->instr_cpsr_sync = dpmv8_instr_cpsr_sync; dpm->instr_read_data_dcc = dpmv8_instr_read_data_dcc; dpm->instr_read_data_dcc_64 = dpmv8_instr_read_data_dcc_64; dpm->instr_read_data_r0 = dpmv8_instr_read_data_r0; dpm->instr_read_data_r0_64 = dpmv8_instr_read_data_r0_64; dpm->arm_reg_current = armv8_reg_current; /* dpm->bpwp_enable = dpmv8_bpwp_enable; */ dpm->bpwp_disable = dpmv8_bpwp_disable; /* breakpoint setup -- optional until it works everywhere */ if (!target->type->add_breakpoint) { target->type->add_breakpoint = dpmv8_add_breakpoint; target->type->remove_breakpoint = dpmv8_remove_breakpoint; } /* watchpoint setup */ if (!target->type->add_watchpoint) { target->type->add_watchpoint = dpmv8_add_watchpoint; target->type->remove_watchpoint = dpmv8_remove_watchpoint; } /* FIXME add vector catch support */ dpm->nbp = 1 + ((dpm->didr >> 12) & 0xf); dpm->dbp = calloc(dpm->nbp, sizeof(*dpm->dbp)); dpm->nwp = 1 + ((dpm->didr >> 20) & 0xf); dpm->dwp = calloc(dpm->nwp, sizeof(*dpm->dwp)); if (!dpm->dbp || !dpm->dwp) { free(dpm->dbp); free(dpm->dwp); return ERROR_FAIL; } LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints", target_name(target), dpm->nbp, dpm->nwp); /* REVISIT ... and some of those breakpoints could match * execution context IDs... */ return ERROR_OK; } /** * Reinitializes DPM state at the beginning of a new debug session * or after a reset which may have affected the debug module. */ int armv8_dpm_initialize(struct arm_dpm *dpm) { /* Disable all breakpoints and watchpoints at startup. */ if (dpm->bpwp_disable) { unsigned i; for (i = 0; i < dpm->nbp; i++) { dpm->dbp[i].bpwp.number = i; (void) dpm->bpwp_disable(dpm, i); } for (i = 0; i < dpm->nwp; i++) { dpm->dwp[i].bpwp.number = 16 + i; (void) dpm->bpwp_disable(dpm, 16 + i); } } else LOG_WARNING("%s: can't disable breakpoints and watchpoints", target_name(dpm->arm->target)); return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv8_dpm.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2009 by David Brownell */ #ifndef OPENOCD_TARGET_ARMV8_DPM_H #define OPENOCD_TARGET_ARMV8_DPM_H #include "arm_dpm.h" #include "helper/bits.h" /* forward-declare struct armv8_common */ struct armv8_common; /** * This wraps an implementation of DPM primitives. Each interface * provider supplies a structure like this, which is the glue between * upper level code and the lower level hardware access. * * It is a PRELIMINARY AND INCOMPLETE set of primitives, starting with * support for CPU register access. */ int armv8_dpm_setup(struct arm_dpm *dpm); int armv8_dpm_initialize(struct arm_dpm *dpm); int armv8_dpm_read_current_registers(struct arm_dpm *dpm); int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode); int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp); /* DSCR bits; see ARMv7a arch spec section C10.3.1. * Not all v7 bits are valid in v6. */ #define DSCR_DEBUG_STATUS_MASK (0x1F << 0) #define DSCR_ERR (0x1 << 6) #define DSCR_SYS_ERROR_PEND (0x1 << 7) #define DSCR_CUR_EL (0x3 << 8) #define DSCR_EL_STATUS_MASK (0xF << 10) #define DSCR_HDE (0x1 << 14) #define DSCR_SDD (0x1 << 16) #define DSCR_NON_SECURE (0x1 << 18) #define DSCR_MA (0x1 << 20) #define DSCR_TDA (0x1 << 21) #define DSCR_INTDIS_MASK (0x3 << 22) #define DSCR_ITE (0x1 << 24) #define DSCR_PIPE_ADVANCE (0x1 << 25) #define DSCR_TXU (0x1 << 26) #define DSCR_RTO (0x1 << 27) /* bit 28 is reserved */ #define DSCR_ITO (0x1 << 28) #define DSCR_DTR_TX_FULL (0x1 << 29) #define DSCR_DTR_RX_FULL (0x1 << 30) /* bit 31 is reserved */ /* Methods of entry into debug mode */ #define DSCRV8_ENTRY_NON_DEBUG (0x2) #define DSCRV8_ENTRY_RESTARTING (0x1) #define DSCRV8_ENTRY_BKPT (0x7) #define DSCRV8_ENTRY_EXT_DEBUG (0x13) #define DSCRV8_ENTRY_HALT_STEP_NORMAL (0x1B) #define DSCRV8_ENTRY_HALT_STEP_EXECLU (0x1F) #define DSCRV8_ENTRY_OS_UNLOCK (0x23) #define DSCRV8_ENTRY_RESET_CATCH (0x27) #define DSCRV8_ENTRY_WATCHPOINT (0x2B) #define DSCRV8_ENTRY_HLT (0x2F) #define DSCRV8_ENTRY_SW_ACCESS_DBG (0x33) #define DSCRV8_ENTRY_EXCEPTION_CATCH (0x37) #define DSCRV8_ENTRY_HALT_STEP (0x3B) #define DSCRV8_HALT_MASK (0x3C) /*DRCR registers*/ #define DRCR_CSE (1 << 2) #define DRCR_CSPA (1 << 3) #define DRCR_CBRRQ (1 << 4) /* DTR modes */ #define DSCR_EXT_DCC_NON_BLOCKING (0x0 << 20) #define DSCR_EXT_DCC_STALL_MODE (0x1 << 20) #define DSCR_EXT_DCC_FAST_MODE (0x2 << 20) /* bits 22, 23 are reserved */ /* DRCR (debug run control register) bits */ #define DRCR_HALT (1 << 0) #define DRCR_RESTART (1 << 1) #define DRCR_CLEAR_EXCEPTIONS (1 << 2) /* ECR (Execution Control Register) bits */ #define ECR_RCE BIT(1) /* ESR (Event Status Register) bits */ #define ESR_RC BIT(1) /* PRSR (processor debug status register) bits */ #define PRSR_PU (1 << 0) #define PRSR_SPD (1 << 1) #define PRSR_RESET (1 << 2) #define PRSR_SR (1 << 3) #define PRSR_HALT (1 << 4) #define PRSR_OSLK (1 << 5) #define PRSR_DLK (1 << 6) #define PRSR_EDAD (1 << 7) #define PRSR_SDAD (1 << 8) #define PRSR_EPMAD (1 << 9) #define PRSR_SPMAD (1 << 10) #define PRSR_SDR (1 << 11) /* PRCR (processor debug control register) bits */ #define PRCR_CORENPDRQ (1 << 0) #define PRCR_CWRR (1 << 2) #define PRCR_COREPURQ (1 << 3) void armv8_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dcsr); void armv8_dpm_handle_exception(struct arm_dpm *dpm, bool do_restore); enum arm_state armv8_dpm_get_core_state(struct arm_dpm *dpm); #endif /* OPENOCD_TARGET_ARM_DPM_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv8_opcodes.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2015 by Matthias Welwarsky <matthias.welwarsky@sysgo.com> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdint.h> #include <stdbool.h> #include "armv8.h" #include "armv8_opcodes.h" static const uint32_t a64_opcodes[ARMV8_OPC_NUM] = { [READ_REG_CTR] = ARMV8_MRS(SYSTEM_CTR, 0), [READ_REG_CLIDR] = ARMV8_MRS(SYSTEM_CLIDR, 0), [READ_REG_CSSELR] = ARMV8_MRS(SYSTEM_CSSELR, 0), [READ_REG_CCSIDR] = ARMV8_MRS(SYSTEM_CCSIDR, 0), [WRITE_REG_CSSELR] = ARMV8_MSR_GP(SYSTEM_CSSELR, 0), [READ_REG_MPIDR] = ARMV8_MRS(SYSTEM_MPIDR, 0), [READ_REG_DTRRX] = ARMV8_MRS(SYSTEM_DBG_DTRRX_EL0, 0), [WRITE_REG_DTRTX] = ARMV8_MSR_GP(SYSTEM_DBG_DTRTX_EL0, 0), [WRITE_REG_DSPSR] = ARMV8_MSR_DSPSR(0), [READ_REG_DSPSR] = ARMV8_MRS_DSPSR(0), [ARMV8_OPC_DSB_SY] = ARMV8_DSB_SY, [ARMV8_OPC_DCPS] = ARMV8_DCPS(0, 11), [ARMV8_OPC_DRPS] = ARMV8_DRPS, [ARMV8_OPC_ISB_SY] = ARMV8_ISB, [ARMV8_OPC_DCCISW] = ARMV8_SYS(SYSTEM_DCCISW, 0), [ARMV8_OPC_DCCIVAC] = ARMV8_SYS(SYSTEM_DCCIVAC, 0), [ARMV8_OPC_ICIVAU] = ARMV8_SYS(SYSTEM_ICIVAU, 0), [ARMV8_OPC_HLT] = ARMV8_HLT(11), [ARMV8_OPC_LDRB_IP] = ARMV8_LDRB_IP(1, 0), [ARMV8_OPC_LDRH_IP] = ARMV8_LDRH_IP(1, 0), [ARMV8_OPC_LDRW_IP] = ARMV8_LDRW_IP(1, 0), [ARMV8_OPC_STRB_IP] = ARMV8_STRB_IP(1, 0), [ARMV8_OPC_STRH_IP] = ARMV8_STRH_IP(1, 0), [ARMV8_OPC_STRW_IP] = ARMV8_STRW_IP(1, 0), }; static const uint32_t t32_opcodes[ARMV8_OPC_NUM] = { [READ_REG_CTR] = ARMV4_5_MRC(15, 0, 0, 0, 0, 1), [READ_REG_CLIDR] = ARMV4_5_MRC(15, 1, 0, 0, 0, 1), [READ_REG_CSSELR] = ARMV4_5_MRC(15, 2, 0, 0, 0, 0), [READ_REG_CCSIDR] = ARMV4_5_MRC(15, 1, 0, 0, 0, 0), [WRITE_REG_CSSELR] = ARMV4_5_MCR(15, 2, 0, 0, 0, 0), [READ_REG_MPIDR] = ARMV4_5_MRC(15, 0, 0, 0, 0, 5), [READ_REG_DTRRX] = ARMV4_5_MRC(14, 0, 0, 0, 5, 0), [WRITE_REG_DTRTX] = ARMV4_5_MCR(14, 0, 0, 0, 5, 0), [WRITE_REG_DSPSR] = ARMV8_MCR_DSPSR(0), [READ_REG_DSPSR] = ARMV8_MRC_DSPSR(0), [ARMV8_OPC_DSB_SY] = ARMV8_DSB_SY_T1, [ARMV8_OPC_DCPS] = ARMV8_DCPS_T1(0), [ARMV8_OPC_DRPS] = ARMV8_ERET_T1, [ARMV8_OPC_ISB_SY] = ARMV8_ISB_SY_T1, [ARMV8_OPC_DCCISW] = ARMV4_5_MCR(15, 0, 0, 7, 14, 2), [ARMV8_OPC_DCCIVAC] = ARMV4_5_MCR(15, 0, 0, 7, 14, 1), [ARMV8_OPC_ICIVAU] = ARMV4_5_MCR(15, 0, 0, 7, 5, 1), [ARMV8_OPC_HLT] = ARMV8_HLT_T1(11), [ARMV8_OPC_LDRB_IP] = ARMV8_LDRB_IP_T3(1, 0), [ARMV8_OPC_LDRH_IP] = ARMV8_LDRH_IP_T3(1, 0), [ARMV8_OPC_LDRW_IP] = ARMV8_LDRW_IP_T3(1, 0), [ARMV8_OPC_STRB_IP] = ARMV8_STRB_IP_T3(1, 0), [ARMV8_OPC_STRH_IP] = ARMV8_STRH_IP_T3(1, 0), [ARMV8_OPC_STRW_IP] = ARMV8_STRW_IP_T3(1, 0), }; void armv8_select_opcodes(struct armv8_common *armv8, bool state_is_aarch64) { if (state_is_aarch64) armv8->opcodes = &a64_opcodes[0]; else armv8->opcodes = &t32_opcodes[0]; } uint32_t armv8_opcode(struct armv8_common *armv8, enum armv8_opcode code) { if ((int)code >= ARMV8_OPC_NUM) return -1; return *(armv8->opcodes + code); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/armv8_opcodes.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2015 by pierrr kuo <vichy.kuo@gmail.com> */ #ifndef OPENOCD_TARGET_ARMV8_OPCODES_H #define OPENOCD_TARGET_ARMV8_OPCODES_H #include "arm_opcodes.h" #define SYSTEM_CUREL_MASK 0xC0 #define SYSTEM_CUREL_SHIFT 6 #define SYSTEM_CUREL_EL0 0x0 #define SYSTEM_CUREL_EL1 0x1 #define SYSTEM_CUREL_EL2 0x2 #define SYSTEM_CUREL_EL3 0x3 #define SYSTEM_CUREL_NONCH 0xF #define SYSTEM_AARCH64 0x1 #define SYSTEM_AAR64_MODE_EL0T 0x0 #define SYSTEM_AAR64_MODE_EL1T 0x4 #define SYSTEM_AAR64_MODE_EL1H 0x5 #define SYSTEM_AAR64_MODE_EL2T 0x8 #define SYSTEM_AAR64_MODE_EL2H 0x9 #define SYSTEM_AAR64_MODE_EL3T 0xC #define SYSTEM_AAR64_MODE_EL3H 0xd #define SYSTEM_DAIF 0b1101101000010001 #define SYSTEM_DAIF_MASK 0x3C0 #define SYSTEM_DAIF_SHIFT 6 #define SYSTEM_ELR_EL1 0b1100001000000001 #define SYSTEM_ELR_EL2 0b1110001000000001 #define SYSTEM_ELR_EL3 0b1111001000000001 #define SYSTEM_SCTLR_EL1 0b1100000010000000 #define SYSTEM_SCTLR_EL2 0b1110000010000000 #define SYSTEM_SCTLR_EL3 0b1111000010000000 #define SYSTEM_FPCR 0b1101101000100000 #define SYSTEM_FPSR 0b1101101000100001 #define SYSTEM_DAIF 0b1101101000010001 #define SYSTEM_NZCV 0b1101101000010000 #define SYSTEM_SP_EL0 0b1100001000001000 #define SYSTEM_SP_EL1 0b1110001000001000 #define SYSTEM_SP_EL2 0b1111001000001000 #define SYSTEM_SP_SEL 0b1100001000010000 #define SYSTEM_SPSR_ABT 0b1110001000011001 #define SYSTEM_SPSR_FIQ 0b1110001000011011 #define SYSTEM_SPSR_IRQ 0b1110001000011000 #define SYSTEM_SPSR_UND 0b1110001000011010 #define SYSTEM_SPSR_EL1 0b1100001000000000 #define SYSTEM_SPSR_EL2 0b1110001000000000 #define SYSTEM_SPSR_EL3 0b1111001000000000 #define SYSTEM_ISR_EL1 0b1100011000001000 #define SYSTEM_DBG_DSPSR_EL0 0b1101101000101000 #define SYSTEM_DBG_DLR_EL0 0b1101101000101001 #define SYSTEM_DBG_DTRRX_EL0 0b1001100000101000 #define SYSTEM_DBG_DTRTX_EL0 0b1001100000101000 #define SYSTEM_DBG_DBGDTR_EL0 0b1001100000100000 #define SYSTEM_CCSIDR 0b1100100000000000 #define SYSTEM_CLIDR 0b1100100000000001 #define SYSTEM_CSSELR 0b1101000000000000 #define SYSTEM_CTYPE 0b1101100000000001 #define SYSTEM_CTR 0b1101100000000001 #define SYSTEM_DCCISW 0b0100001111110010 #define SYSTEM_DCCSW 0b0100001111010010 #define SYSTEM_ICIVAU 0b0101101110101001 #define SYSTEM_DCCVAU 0b0101101111011001 #define SYSTEM_DCCIVAC 0b0101101111110001 #define SYSTEM_MPIDR 0b1100000000000101 #define SYSTEM_TCR_EL1 0b1100000100000010 #define SYSTEM_TCR_EL2 0b1110000100000010 #define SYSTEM_TCR_EL3 0b1111000100000010 #define SYSTEM_TTBR0_EL1 0b1100000100000000 #define SYSTEM_TTBR0_EL2 0b1110000100000000 #define SYSTEM_TTBR0_EL3 0b1111000100000000 #define SYSTEM_TTBR1_EL1 0b1100000100000001 /* ARMv8 address translation */ #define SYSTEM_PAR_EL1 0b1100001110100000 #define SYSTEM_ATS12E0R 0b0110001111000110 #define SYSTEM_ATS12E1R 0b0110001111000100 #define SYSTEM_ATS1E2R 0b0110001111000000 #define SYSTEM_ATS1E3R 0b0111001111000000 /* fault status and fault address */ #define SYSTEM_FAR_EL1 0b1100001100000000 #define SYSTEM_FAR_EL2 0b1110001100000000 #define SYSTEM_FAR_EL3 0b1111001100000000 #define SYSTEM_ESR_EL1 0b1100001010010000 #define SYSTEM_ESR_EL2 0b1110001010010000 #define SYSTEM_ESR_EL3 0b1111001010010000 #define ARMV8_MRS_DSPSR(rt) (0xd53b4500 | (rt)) #define ARMV8_MSR_DSPSR(rt) (0xd51b4500 | (rt)) #define ARMV8_MRS_DLR(rt) (0xd53b4520 | (rt)) #define ARMV8_MSR_DLR(rt) (0xd51b4520 | (rt)) /* T32 instruction to access coprocessor registers */ #define ARMV8_MCR_T1(cp, crn, opc1, crm, opc2, rt) ARMV4_5_MCR(cp, opc1, rt, crn, crm, opc2) #define ARMV8_MRC_T1(cp, crn, opc1, crm, opc2, rt) ARMV4_5_MRC(cp, opc1, rt, crn, crm, opc2) /* T32 instructions to access DSPSR and DLR */ #define ARMV8_MRC_DSPSR(rt) ARMV8_MRC_T1(15, 4, 3, 5, 0, rt) #define ARMV8_MCR_DSPSR(rt) ARMV8_MCR_T1(15, 4, 3, 5, 0, rt) #define ARMV8_MRC_DLR(rt) ARMV8_MRC_T1(15, 4, 3, 5, 1, rt) #define ARMV8_MCR_DLR(rt) ARMV8_MCR_T1(15, 4, 3, 5, 1, rt) #define ARMV8_DCPS1(im) (0xd4a00001 | (((im) & 0xFFFF) << 5)) #define ARMV8_DCPS2(im) (0xd4a00002 | (((im) & 0xFFFF) << 5)) #define ARMV8_DCPS3(im) (0xd4a00003 | (((im) & 0xFFFF) << 5)) #define ARMV8_DCPS(el, im) (0xd4a00000 | (((im) & 0xFFFF) << 5) | el) #define ARMV8_DCPS_T1(el) (0xf78f8000 | el) #define ARMV8_DRPS 0xd6bf03e0 #define ARMV8_ERET_T1 0xf3de8f00 #define ARMV8_DSB_SY 0xd5033F9F #define ARMV8_DSB_SY_T1 0xf3bf8f4f #define ARMV8_ISB 0xd5033fdf #define ARMV8_ISB_SY_T1 0xf3bf8f6f #define ARMV8_MRS(system, rt) (0xd5300000 | ((system) << 5) | (rt)) /* ARM V8 Move to system register. */ #define ARMV8_MSR_GP(system, rt) \ (0xd5100000 | ((system) << 5) | (rt)) /* ARM V8 Move immediate to process state field. */ #define ARMV8_MSR_IM(op1, crm, op2) \ (0xd500401f | ((op1) << 16) | ((crm) << 8) | ((op2) << 5)) #define ARMV8_MRS_T1(r, m1, rd, m) (0xF3E08020 | (r << 20) | (m1 << 16) | (rd << 8) | (m << 4)) #define ARMV8_MRS_XPSR_T1(r, rd) (0xF3EF8000 | (r << 20) | (rd << 8)) #define ARMV8_MSR_GP_T1(r, m1, rd, m) (0xF3808020 | (r << 20) | (m1 << 8) | (rd << 16) | (m << 4)) #define ARMV8_MSR_GP_XPSR_T1(r, rn, mask) (0xF3808000 | (r << 20) | (rn << 16) | (mask << 8)) #define ARMV8_BKPT(im) (0xD4200000 | ((im & 0xffff) << 5)) #define ARMV8_HLT(im) (0x0D4400000 | ((im & 0xffff) << 5)) #define ARMV8_HLT_A1(im) (0xE1000070 | ((im & 0xFFF0) << 4) | (im & 0xF)) #define ARMV8_HLT_T1(im) (0xba80 | (im & 0x3f)) #define ARMV8_MOVFSP_64(rt) ((1 << 31) | 0x11000000 | (0x1f << 5) | (rt)) #define ARMV8_MOVTSP_64(rt) ((1 << 31) | 0x11000000 | (rt << 5) | (0x1F)) #define ARMV8_MOVFSP_32(rt) (0x11000000 | (0x1f << 5) | (rt)) #define ARMV8_MOVTSP_32(rt) (0x11000000 | (rt << 5) | (0x1F)) #define ARMV8_LDRB_IP(rd, rn) (0x38401400 | (rn << 5) | rd) #define ARMV8_LDRH_IP(rd, rn) (0x78402400 | (rn << 5) | rd) #define ARMV8_LDRW_IP(rd, rn) (0xb8404400 | (rn << 5) | rd) #define ARMV8_LDRB_IP_T3(rd, rn) (0xf8100b01 | (rn << 16) | (rd << 12)) #define ARMV8_LDRH_IP_T3(rd, rn) (0xf8300b02 | (rn << 16) | (rd << 12)) #define ARMV8_LDRW_IP_T3(rd, rn) (0xf8500b04 | (rn << 16) | (rd << 12)) #define ARMV8_STRB_IP(rd, rn) (0x38001400 | (rn << 5) | rd) #define ARMV8_STRH_IP(rd, rn) (0x78002400 | (rn << 5) | rd) #define ARMV8_STRW_IP(rd, rn) (0xb8004400 | (rn << 5) | rd) #define ARMV8_STRB_IP_T3(rd, rn) (0xf8000b01 | (rn << 16) | (rd << 12)) #define ARMV8_STRH_IP_T3(rd, rn) (0xf8200b02 | (rn << 16) | (rd << 12)) #define ARMV8_STRW_IP_T3(rd, rn) (0xf8400b04 | (rn << 16) | (rd << 12)) #define ARMV8_MOV_GPR_VFP(rd, rn, index) (0x4e083c00 | (index << 20) | (rn << 5) | rd) #define ARMV8_MOV_VFP_GPR(rd, rn, index) (0x4e081c00 | (index << 20) | (rn << 5) | rd) #define ARMV8_MRS_FPCR(rt) (0xd53b4400 | (rt)) #define ARMV8_MRS_FPSR(rt) (0xd53b4420 | (rt)) #define ARMV8_MSR_FPCR(rt) (0xd51b4400 | (rt)) #define ARMV8_MSR_FPSR(rt) (0xd51b4420 | (rt)) #define ARMV8_SYS(system, rt) (0xD5080000 | ((system) << 5) | rt) enum armv8_opcode { READ_REG_CTR, READ_REG_CLIDR, READ_REG_CSSELR, READ_REG_CCSIDR, WRITE_REG_CSSELR, READ_REG_MPIDR, READ_REG_DTRRX, WRITE_REG_DTRTX, WRITE_REG_DSPSR, READ_REG_DSPSR, ARMV8_OPC_DSB_SY, ARMV8_OPC_DCPS, ARMV8_OPC_DRPS, ARMV8_OPC_ISB_SY, ARMV8_OPC_DCCISW, ARMV8_OPC_DCCIVAC, ARMV8_OPC_ICIVAU, ARMV8_OPC_HLT, ARMV8_OPC_STRB_IP, ARMV8_OPC_STRH_IP, ARMV8_OPC_STRW_IP, ARMV8_OPC_LDRB_IP, ARMV8_OPC_LDRH_IP, ARMV8_OPC_LDRW_IP, ARMV8_OPC_NUM, }; extern uint32_t armv8_opcode(struct armv8_common *armv8, enum armv8_opcode); extern void armv8_select_opcodes(struct armv8_common *armv8, bool state_is_aarch64); #endif /* OPENOCD_TARGET_ARMV8_OPCODES_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/avr32_ap7k.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * * Based on mips_m4k code: * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2008 by David T.L. Wong * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/jtag.h" #include "register.h" #include "algorithm.h" #include "target.h" #include "breakpoints.h" #include "target_type.h" #include "avr32_jtag.h" #include "avr32_mem.h" #include "avr32_regs.h" #include "avr32_ap7k.h" static const char * const avr32_core_reg_list[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", "sr" }; static const struct avr32_core_reg avr32_core_reg_list_arch_info[AVR32NUMCOREREGS] = { {0, NULL, NULL}, {1, NULL, NULL}, {2, NULL, NULL}, {3, NULL, NULL}, {4, NULL, NULL}, {5, NULL, NULL}, {6, NULL, NULL}, {7, NULL, NULL}, {8, NULL, NULL}, {9, NULL, NULL}, {10, NULL, NULL}, {11, NULL, NULL}, {12, NULL, NULL}, {13, NULL, NULL}, {14, NULL, NULL}, {15, NULL, NULL}, {16, NULL, NULL}, }; static int avr32_read_core_reg(struct target *target, int num); static int avr32_write_core_reg(struct target *target, int num); static int avr32_ap7k_save_context(struct target *target) { int retval, i; struct avr32_ap7k_common *ap7k = target_to_ap7k(target); retval = avr32_jtag_read_regs(&ap7k->jtag, ap7k->core_regs); if (retval != ERROR_OK) return retval; for (i = 0; i < AVR32NUMCOREREGS; i++) { if (!ap7k->core_cache->reg_list[i].valid) avr32_read_core_reg(target, i); } return ERROR_OK; } static int avr32_ap7k_restore_context(struct target *target) { int i; /* get pointers to arch-specific information */ struct avr32_ap7k_common *ap7k = target_to_ap7k(target); for (i = 0; i < AVR32NUMCOREREGS; i++) { if (ap7k->core_cache->reg_list[i].dirty) avr32_write_core_reg(target, i); } /* write core regs */ avr32_jtag_write_regs(&ap7k->jtag, ap7k->core_regs); return ERROR_OK; } static int avr32_read_core_reg(struct target *target, int num) { uint32_t reg_value; /* get pointers to arch-specific information */ struct avr32_ap7k_common *ap7k = target_to_ap7k(target); if ((num < 0) || (num >= AVR32NUMCOREREGS)) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = ap7k->core_regs[num]; buf_set_u32(ap7k->core_cache->reg_list[num].value, 0, 32, reg_value); ap7k->core_cache->reg_list[num].valid = true; ap7k->core_cache->reg_list[num].dirty = false; return ERROR_OK; } static int avr32_write_core_reg(struct target *target, int num) { uint32_t reg_value; /* get pointers to arch-specific information */ struct avr32_ap7k_common *ap7k = target_to_ap7k(target); if ((num < 0) || (num >= AVR32NUMCOREREGS)) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = buf_get_u32(ap7k->core_cache->reg_list[num].value, 0, 32); ap7k->core_regs[num] = reg_value; LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value); ap7k->core_cache->reg_list[num].valid = true; ap7k->core_cache->reg_list[num].dirty = false; return ERROR_OK; } static int avr32_get_core_reg(struct reg *reg) { int retval; struct avr32_core_reg *avr32_reg = reg->arch_info; struct target *target = avr32_reg->target; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = avr32_read_core_reg(target, avr32_reg->num); return retval; } static int avr32_set_core_reg(struct reg *reg, uint8_t *buf) { struct avr32_core_reg *avr32_reg = reg->arch_info; struct target *target = avr32_reg->target; uint32_t value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; buf_set_u32(reg->value, 0, 32, value); reg->dirty = true; reg->valid = true; return ERROR_OK; } static const struct reg_arch_type avr32_reg_type = { .get = avr32_get_core_reg, .set = avr32_set_core_reg, }; static struct reg_cache *avr32_build_reg_cache(struct target *target) { int num_regs = AVR32NUMCOREREGS; struct avr32_ap7k_common *ap7k = target_to_ap7k(target); struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); struct avr32_core_reg *arch_info = malloc(sizeof(struct avr32_core_reg) * num_regs); int i; /* Build the process context cache */ cache->name = "avr32 registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = num_regs; (*cache_p) = cache; ap7k->core_cache = cache; for (i = 0; i < num_regs; i++) { arch_info[i] = avr32_core_reg_list_arch_info[i]; arch_info[i].target = target; arch_info[i].avr32_common = ap7k; reg_list[i].name = avr32_core_reg_list[i]; reg_list[i].size = 32; reg_list[i].value = calloc(1, 4); reg_list[i].dirty = false; reg_list[i].valid = false; reg_list[i].type = &avr32_reg_type; reg_list[i].arch_info = &arch_info[i]; } return cache; } static int avr32_ap7k_debug_entry(struct target *target) { uint32_t dpc, dinst; int retval; struct avr32_ap7k_common *ap7k = target_to_ap7k(target); retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DPC, &dpc); if (retval != ERROR_OK) return retval; retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DINST, &dinst); if (retval != ERROR_OK) return retval; ap7k->jtag.dpc = dpc; avr32_ap7k_save_context(target); return ERROR_OK; } static int avr32_ap7k_poll(struct target *target) { uint32_t ds; int retval; struct avr32_ap7k_common *ap7k = target_to_ap7k(target); retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DS, &ds); if (retval != ERROR_OK) return retval; /* check for processor halted */ if (ds & OCDREG_DS_DBA) { if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { target->state = TARGET_HALTED; retval = avr32_ap7k_debug_entry(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); } else if (target->state == TARGET_DEBUG_RUNNING) { target->state = TARGET_HALTED; retval = avr32_ap7k_debug_entry(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } } else target->state = TARGET_RUNNING; return ERROR_OK; } static int avr32_ap7k_halt(struct target *target) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); if (target->state == TARGET_RESET) { if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST"); return ERROR_TARGET_FAILURE; } else { target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } } avr32_ocd_setbits(&ap7k->jtag, AVR32_OCDREG_DC, OCDREG_DC_DBR); target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int avr32_ap7k_assert_reset(struct target *target) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_deassert_reset(struct target *target) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); struct breakpoint *breakpoint = NULL; uint32_t resume_pc; int retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) { target_free_all_working_areas(target); /* avr32_ap7k_enable_breakpoints(target); avr32_ap7k_enable_watchpoints(target); */ } /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { #if 0 if (retval != ERROR_OK) return retval; #endif } resume_pc = buf_get_u32(ap7k->core_cache->reg_list[AVR32_REG_PC].value, 0, 32); avr32_ap7k_restore_context(target); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { LOG_DEBUG("unset breakpoint at 0x%8.8" TARGET_PRIxADDR "", breakpoint->address); #if 0 avr32_ap7k_unset_breakpoint(target, breakpoint); avr32_ap7k_single_step_core(target); avr32_ap7k_set_breakpoint(target, breakpoint); #endif } } #if 0 /* enable interrupts if we are running */ avr32_ap7k_enable_interrupts(target, !debug_execution); /* exit debug mode */ mips_ejtag_exit_debug(ejtag_info); #endif retval = avr32_ocd_clearbits(&ap7k->jtag, AVR32_OCDREG_DC, OCDREG_DC_DBR); if (retval != ERROR_OK) return retval; retval = avr32_jtag_exec(&ap7k->jtag, RETD); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_NOTHALTED; /* registers are now invalid */ register_cache_invalidate(ap7k->core_cache); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); } return ERROR_OK; } static int avr32_ap7k_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; switch (size) { case 4: return avr32_jtag_read_memory32(&ap7k->jtag, address, count, (uint32_t *)(void *)buffer); break; case 2: return avr32_jtag_read_memory16(&ap7k->jtag, address, count, (uint16_t *)(void *)buffer); break; case 1: return avr32_jtag_read_memory8(&ap7k->jtag, address, count, buffer); default: break; } return ERROR_OK; } static int avr32_ap7k_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; switch (size) { case 4: return avr32_jtag_write_memory32(&ap7k->jtag, address, count, (uint32_t *)(void *)buffer); break; case 2: return avr32_jtag_write_memory16(&ap7k->jtag, address, count, (uint16_t *)(void *)buffer); break; case 1: return avr32_jtag_write_memory8(&ap7k->jtag, address, count, buffer); default: break; } return ERROR_OK; } static int avr32_ap7k_init_target(struct command_context *cmd_ctx, struct target *target) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); ap7k->jtag.tap = target->tap; avr32_build_reg_cache(target); return ERROR_OK; } static int avr32_ap7k_target_create(struct target *target, Jim_Interp *interp) { struct avr32_ap7k_common *ap7k = calloc(1, sizeof(struct avr32_ap7k_common)); ap7k->common_magic = AP7K_COMMON_MAGIC; target->arch_info = ap7k; return ERROR_OK; } static int avr32_ap7k_examine(struct target *target) { uint32_t devid, ds; struct avr32_ap7k_common *ap7k = target_to_ap7k(target); if (!target_was_examined(target)) { target_set_examined(target); avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DID, &devid); LOG_INFO("device id: %08" PRIx32, devid); avr32_ocd_setbits(&ap7k->jtag, AVR32_OCDREG_DC, OCDREG_DC_DBE); avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DS, &ds); /* check for processor halted */ if (ds & OCDREG_DS_DBA) { LOG_INFO("target is halted"); target->state = TARGET_HALTED; } else target->state = TARGET_RUNNING; } return ERROR_OK; } static int avr32_ap7k_arch_state(struct target *target) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32 "", debug_reason_name(target), ap7k->jtag.dpc); return ERROR_OK; } static int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { #if 0 /* get pointers to arch-specific information */ int i; /* include floating point registers */ *reg_list_size = AVR32NUMCOREREGS + AVR32NUMFPREGS; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < AVR32NUMCOREREGS; i++) (*reg_list)[i] = &mips32->core_cache->reg_list[i]; /* add dummy floating points regs */ for (i = AVR32NUMCOREREGS; i < (AVR32NUMCOREREGS + AVR32NUMFPREGS); i++) (*reg_list)[i] = &avr32_ap7k_gdb_dummy_fp_reg; #endif LOG_ERROR("%s: implement me", __func__); return ERROR_FAIL; } struct target_type avr32_ap7k_target = { .name = "avr32_ap7k", .poll = avr32_ap7k_poll, .arch_state = avr32_ap7k_arch_state, .halt = avr32_ap7k_halt, .resume = avr32_ap7k_resume, .step = avr32_ap7k_step, .assert_reset = avr32_ap7k_assert_reset, .deassert_reset = avr32_ap7k_deassert_reset, .get_gdb_reg_list = avr32_ap7k_get_gdb_reg_list, .read_memory = avr32_ap7k_read_memory, .write_memory = avr32_ap7k_write_memory, /* .checksum_memory = avr32_ap7k_checksum_memory, */ /* .blank_check_memory = avr32_ap7k_blank_check_memory, */ /* .run_algorithm = avr32_ap7k_run_algorithm, */ .add_breakpoint = avr32_ap7k_add_breakpoint, .remove_breakpoint = avr32_ap7k_remove_breakpoint, .add_watchpoint = avr32_ap7k_add_watchpoint, .remove_watchpoint = avr32_ap7k_remove_watchpoint, .target_create = avr32_ap7k_target_create, .init_target = avr32_ap7k_init_target, .examine = avr32_ap7k_examine, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/avr32_ap7k.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_AVR32_AP7K_H #define OPENOCD_TARGET_AVR32_AP7K_H struct target; #define AP7K_COMMON_MAGIC 0x4150374bU struct avr32_ap7k_common { unsigned int common_magic; struct avr32_jtag jtag; struct reg_cache *core_cache; uint32_t core_regs[AVR32NUMCOREREGS]; }; static inline struct avr32_ap7k_common * target_to_ap7k(struct target *target) { return (struct avr32_ap7k_common *)target->arch_info; } struct avr32_core_reg { uint32_t num; struct target *target; struct avr32_ap7k_common *avr32_common; }; #endif /* OPENOCD_TARGET_AVR32_AP7K_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/avr32_jtag.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include "jtag/jtag.h" #include "avr32_jtag.h" static int avr32_jtag_set_instr(struct avr32_jtag *jtag_info, int new_instr) { struct jtag_tap *tap; int busy = 0; tap = jtag_info->tap; if (!tap) return ERROR_FAIL; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (uint32_t)new_instr) { do { struct scan_field field; uint8_t t[4] = { 0 }; uint8_t ret[4]; field.num_bits = tap->ir_length; field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = ret; jtag_add_ir_scan(tap, &field, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("%s: setting address failed", __func__); return ERROR_FAIL; } busy = buf_get_u32(ret, 2, 1); } while (busy); /* check for busy bit */ } return ERROR_OK; } static int avr32_jtag_nexus_set_address(struct avr32_jtag *jtag_info, uint32_t addr, int mode) { struct scan_field fields[2]; uint8_t addr_buf[4]; uint8_t busy_buf[4]; int busy; memset(fields, 0, sizeof(fields)); do { memset(addr_buf, 0, sizeof(addr_buf)); memset(busy_buf, 0, sizeof(busy_buf)); buf_set_u32(addr_buf, 0, 1, mode); buf_set_u32(addr_buf, 1, 7, addr); fields[0].num_bits = 26; fields[0].in_value = NULL; fields[0].out_value = NULL; fields[1].num_bits = 8; fields[1].in_value = busy_buf; fields[1].out_value = addr_buf; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("%s: setting address failed", __func__); return ERROR_FAIL; } busy = buf_get_u32(busy_buf, 6, 1); } while (busy); return ERROR_OK; } static int avr32_jtag_nexus_read_data(struct avr32_jtag *jtag_info, uint32_t *pdata) { struct scan_field fields[2]; uint8_t data_buf[4]; uint8_t busy_buf[4]; int busy; do { memset(data_buf, 0, sizeof(data_buf)); memset(busy_buf, 0, sizeof(busy_buf)); fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = data_buf; fields[1].num_bits = 2; fields[1].in_value = busy_buf; fields[1].out_value = NULL; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("%s: reading data failed", __func__); return ERROR_FAIL; } busy = buf_get_u32(busy_buf, 0, 1); } while (busy); *pdata = buf_get_u32(data_buf, 0, 32); return ERROR_OK; } static int avr32_jtag_nexus_write_data(struct avr32_jtag *jtag_info, uint32_t data) { struct scan_field fields[2]; uint8_t data_buf[4]; uint8_t busy_buf[4]; uint8_t dummy_buf[4]; int busy; do { memset(data_buf, 0, sizeof(data_buf)); memset(busy_buf, 0, sizeof(busy_buf)); memset(dummy_buf, 0, sizeof(dummy_buf)); fields[0].num_bits = 2; fields[0].in_value = busy_buf; fields[0].out_value = dummy_buf; buf_set_u32(data_buf, 0, 32, data); fields[1].num_bits = 32; fields[1].in_value = NULL; fields[1].out_value = data_buf; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("%s: reading data failed", __func__); return ERROR_FAIL; } busy = buf_get_u32(busy_buf, 0, 0); } while (busy); return ERROR_OK; } int avr32_jtag_nexus_read(struct avr32_jtag *jtag_info, uint32_t addr, uint32_t *value) { avr32_jtag_set_instr(jtag_info, AVR32_INST_NEXUS_ACCESS); avr32_jtag_nexus_set_address(jtag_info, addr, MODE_READ); return avr32_jtag_nexus_read_data(jtag_info, value); } int avr32_jtag_nexus_write(struct avr32_jtag *jtag_info, uint32_t addr, uint32_t value) { avr32_jtag_set_instr(jtag_info, AVR32_INST_NEXUS_ACCESS); avr32_jtag_nexus_set_address(jtag_info, addr, MODE_WRITE); return avr32_jtag_nexus_write_data(jtag_info, value); } static int avr32_jtag_mwa_set_address(struct avr32_jtag *jtag_info, int slave, uint32_t addr, int mode) { struct scan_field fields[2]; uint8_t addr_buf[4]; uint8_t slave_buf[4]; uint8_t busy_buf[4]; int busy; memset(fields, 0, sizeof(fields)); do { memset(addr_buf, 0, sizeof(addr_buf)); memset(busy_buf, 0, sizeof(busy_buf)); memset(slave_buf, 0, sizeof(slave_buf)); buf_set_u32(slave_buf, 0, 4, slave); buf_set_u32(addr_buf, 0, 1, mode); buf_set_u32(addr_buf, 1, 30, addr >> 2); fields[0].num_bits = 31; fields[0].in_value = NULL; fields[0].out_value = addr_buf; fields[1].num_bits = 4; fields[1].in_value = busy_buf; fields[1].out_value = slave_buf; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("%s: setting address failed", __func__); return ERROR_FAIL; } busy = buf_get_u32(busy_buf, 1, 1); } while (busy); return ERROR_OK; } static int avr32_jtag_mwa_read_data(struct avr32_jtag *jtag_info, uint32_t *pdata) { struct scan_field fields[2]; uint8_t data_buf[4]; uint8_t busy_buf[4]; int busy; do { memset(data_buf, 0, sizeof(data_buf)); memset(busy_buf, 0, sizeof(busy_buf)); fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = data_buf; fields[1].num_bits = 3; fields[1].in_value = busy_buf; fields[1].out_value = NULL; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("%s: reading data failed", __func__); return ERROR_FAIL; } busy = buf_get_u32(busy_buf, 0, 1); } while (busy); *pdata = buf_get_u32(data_buf, 0, 32); return ERROR_OK; } static int avr32_jtag_mwa_write_data(struct avr32_jtag *jtag_info, uint32_t data) { struct scan_field fields[2]; uint8_t data_buf[4]; uint8_t busy_buf[4]; uint8_t zero_buf[4]; int busy; do { memset(data_buf, 0, sizeof(data_buf)); memset(busy_buf, 0, sizeof(busy_buf)); memset(zero_buf, 0, sizeof(zero_buf)); buf_set_u32(data_buf, 0, 32, data); fields[0].num_bits = 3; fields[0].in_value = busy_buf; fields[0].out_value = zero_buf; fields[1].num_bits = 32; fields[1].out_value = data_buf; fields[1].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("%s: reading data failed", __func__); return ERROR_FAIL; } busy = buf_get_u32(busy_buf, 0, 1); } while (busy); return ERROR_OK; } int avr32_jtag_mwa_read(struct avr32_jtag *jtag_info, int slave, uint32_t addr, uint32_t *value) { avr32_jtag_set_instr(jtag_info, AVR32_INST_MW_ACCESS); avr32_jtag_mwa_set_address(jtag_info, slave, addr, MODE_READ); avr32_jtag_mwa_read_data(jtag_info, value); return ERROR_OK; } int avr32_jtag_mwa_write(struct avr32_jtag *jtag_info, int slave, uint32_t addr, uint32_t value) { avr32_jtag_set_instr(jtag_info, AVR32_INST_MW_ACCESS); avr32_jtag_mwa_set_address(jtag_info, slave, addr, MODE_WRITE); avr32_jtag_mwa_write_data(jtag_info, value); return ERROR_OK; } int avr32_jtag_exec(struct avr32_jtag *jtag_info, uint32_t inst) { int retval; uint32_t ds; retval = avr32_jtag_nexus_write(jtag_info, AVR32_OCDREG_DINST, inst); if (retval != ERROR_OK) return retval; do { retval = avr32_jtag_nexus_read(jtag_info, AVR32_OCDREG_DS, &ds); if (retval != ERROR_OK) return retval; } while ((ds & OCDREG_DS_DBA) && !(ds & OCDREG_DS_INC)); return ERROR_OK; } int avr32_ocd_setbits(struct avr32_jtag *jtag, int reg, uint32_t bits) { uint32_t value; int res; res = avr32_jtag_nexus_read(jtag, reg, &value); if (res) return res; value |= bits; res = avr32_jtag_nexus_write(jtag, reg, value); if (res) return res; return ERROR_OK; } int avr32_ocd_clearbits(struct avr32_jtag *jtag, int reg, uint32_t bits) { uint32_t value; int res; res = avr32_jtag_nexus_read(jtag, reg, &value); if (res) return res; value &= ~bits; res = avr32_jtag_nexus_write(jtag, reg, value); if (res) return res; return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/avr32_jtag.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_AVR32_JTAG_H #define OPENOCD_TARGET_AVR32_JTAG_H #define AVR32NUMCOREREGS 17 /* tap instructions */ #define AVR32_INST_IDCODE 0x01 #define AVR32_INST_NEXUS_ACCESS 0x10 #define AVR32_INST_MW_ACCESS 0x11 #define AVR32_INST_MB_ACCESS 0x12 #define SLAVE_OCD 0x01 #define SLAVE_HSB_CACHED 0x04 #define SLAVE_HSB_UNCACHED 0x05 /* * Registers */ #define AVR32_OCDREG_DID 0x00 #define AVR32_OCDREG_DC 0x02 #define OCDREG_DC_SS (1 << 8) #define OCDREG_DC_DBR (1 << 12) #define OCDREG_DC_DBE (1 << 13) #define OCDREG_DC_SQA (1 << 22) #define OCDREG_DC_RES (1 << 30) #define OCDREG_DC_ABORT (1 << 31) #define AVR32_OCDREG_DS 0x04 #define OCDREG_DS_SSS (1 << 0) #define OCDREG_DS_SWB (1 << 1) #define OCDREG_DS_HWB (1 << 2) #define OCDREG_DS_STP (1 << 4) #define OCDREG_DS_DBS (1 << 5) #define OCDREG_DS_BP_SHIFT 8 #define OCDREG_DS_BP_MASK 0xff #define OCDREG_DS_INC (1 << 24) #define OCDREG_DS_BOZ (1 << 25) #define OCDREG_DS_DBA (1 << 26) #define OCDREG_DS_EXB (1 << 27) #define OCDREG_DS_NTBF (1 << 28) #define AVR32_OCDREG_DINST 0x41 #define AVR32_OCDREG_DPC 0x42 #define AVR32_OCDREG_DCCPU 0x44 #define AVR32_OCDREG_DCEMU 0x45 #define AVR32_OCDREG_DCSR 0x46 #define OCDREG_DCSR_CPUD (1 << 0) #define OCDREG_DCSR_EMUD (1 << 1) /* * Direction bit */ #define MODE_WRITE 0x00 #define MODE_READ 0x01 /* * Some instructions */ #define RETD 0xd703d623 #define MTDR(dreg, reg) (0xe7b00044 | ((reg) << 16) | dreg) #define MFDR(reg, dreg) (0xe5b00044 | ((reg) << 16) | dreg) #define MTSR(sysreg, reg) (0xe3b00002 | ((reg) << 16) | sysreg) #define MFSR(reg, sysreg) (0xe1b00002 | ((reg) << 16) | sysreg) struct avr32_jtag { struct jtag_tap *tap; uint32_t dpc; /* Debug PC value */ }; int avr32_jtag_nexus_read(struct avr32_jtag *jtag_info, uint32_t addr, uint32_t *value); int avr32_jtag_nexus_write(struct avr32_jtag *jtag_info, uint32_t addr, uint32_t value); int avr32_jtag_mwa_read(struct avr32_jtag *jtag_info, int slave, uint32_t addr, uint32_t *value); int avr32_jtag_mwa_write(struct avr32_jtag *jtag_info, int slave, uint32_t addr, uint32_t value); int avr32_ocd_setbits(struct avr32_jtag *jtag, int reg, uint32_t bits); int avr32_ocd_clearbits(struct avr32_jtag *jtag, int reg, uint32_t bits); int avr32_jtag_exec(struct avr32_jtag *jtag_info, uint32_t inst); #endif /* OPENOCD_TARGET_AVR32_JTAG_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/avr32_mem.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include "jtag/jtag.h" #include "avr32_jtag.h" #include "avr32_mem.h" int avr32_jtag_read_memory32(struct avr32_jtag *jtag_info, uint32_t addr, int count, uint32_t *buffer) { int i, retval; uint32_t data; for (i = 0; i < count; i++) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i*4, &data); if (retval != ERROR_OK) return retval; /* XXX: Assume AVR32 is BE */ buffer[i] = be_to_h_u32((uint8_t *)&data); } return ERROR_OK; } int avr32_jtag_read_memory16(struct avr32_jtag *jtag_info, uint32_t addr, int count, uint16_t *buffer) { int i, retval; uint32_t data; i = 0; /* any unaligned half-words? */ if (addr & 3) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i*2, &data); if (retval != ERROR_OK) return retval; /* XXX: Assume AVR32 is BE */ data = be_to_h_u32((uint8_t *)&data); buffer[i] = (data >> 16) & 0xffff; i++; } /* read all complete words */ for (; i < (count & ~1); i += 2) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i*2, &data); if (retval != ERROR_OK) return retval; /* XXX: Assume AVR32 is BE */ data = be_to_h_u32((uint8_t *)&data); buffer[i] = data & 0xffff; buffer[i+1] = (data >> 16) & 0xffff; } /* last halfword */ if (i < count) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i*2, &data); if (retval != ERROR_OK) return retval; /* XXX: Assume AVR32 is BE */ data = be_to_h_u32((uint8_t *)&data); buffer[i] = data & 0xffff; } return ERROR_OK; } int avr32_jtag_read_memory8(struct avr32_jtag *jtag_info, uint32_t addr, int count, uint8_t *buffer) { int i, j, retval; uint8_t data[4]; i = 0; /* Do we have non-aligned bytes? */ if (addr & 3) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i, (uint32_t *)(void *)data); if (retval != ERROR_OK) return retval; for (j = addr & 3; (j < 4) && (i < count); j++, i++) buffer[i] = data[3-j]; } /* read all complete words */ for (; i < (count & ~3); i += 4) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i, (uint32_t *)(void *)data); if (retval != ERROR_OK) return retval; for (j = 0; j < 4; j++) buffer[i+j] = data[3-j]; } /* remaining bytes */ if (i < count) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i, (uint32_t *)(void *)data); if (retval != ERROR_OK) return retval; for (j = 0; i + j < count; j++) buffer[i+j] = data[3-j]; } return ERROR_OK; } int avr32_jtag_write_memory32(struct avr32_jtag *jtag_info, uint32_t addr, int count, const uint32_t *buffer) { int i, retval; uint32_t data; for (i = 0; i < count; i++) { /* XXX: Assume AVR32 is BE */ h_u32_to_be((uint8_t *)&data, buffer[i]); retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, addr + i*4, data); if (retval != ERROR_OK) return retval; } return ERROR_OK; } int avr32_jtag_write_memory16(struct avr32_jtag *jtag_info, uint32_t addr, int count, const uint16_t *buffer) { int i, retval; uint32_t data; uint32_t data_out; i = 0; /* * Do we have any non-aligned half-words? */ if (addr & 3) { /* * mwa_read will read whole world, no need to fiddle * with address. It will be truncated in set_addr */ retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr, &data); if (retval != ERROR_OK) return retval; data = be_to_h_u32((uint8_t *)&data); data = (buffer[i] << 16) | (data & 0xffff); h_u32_to_be((uint8_t *)&data_out, data); retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, addr, data_out); if (retval != ERROR_OK) return retval; i++; } /* write all complete words */ for (; i < (count & ~1); i += 2) { /* XXX: Assume AVR32 is BE */ data = (buffer[i+1] << 16) | buffer[i]; h_u32_to_be((uint8_t *)&data_out, data); retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, addr + i*2, data_out); if (retval != ERROR_OK) return retval; } /* last halfword */ if (i < count) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i*2, &data); if (retval != ERROR_OK) return retval; data = be_to_h_u32((uint8_t *)&data); data &= ~0xffff; data |= buffer[i]; h_u32_to_be((uint8_t *)&data_out, data); retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, addr + i*2, data_out); if (retval != ERROR_OK) return retval; } return ERROR_OK; } int avr32_jtag_write_memory8(struct avr32_jtag *jtag_info, uint32_t addr, int count, const uint8_t *buffer) { int i, j, retval; uint32_t data; uint32_t data_out; i = 0; /* * Do we have any non-aligned bytes? */ if (addr & 3) { /* * mwa_read will read whole world, no need to fiddle * with address. It will be truncated in set_addr */ retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr, &data); if (retval != ERROR_OK) return retval; data = be_to_h_u32((uint8_t *)&data); for (j = addr & 3; (j < 4) && (i < count); j++, i++) { data &= ~(0xff << j*8); data |= (buffer[i] << j*8); } h_u32_to_be((uint8_t *)&data_out, data); retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, addr, data_out); if (retval != ERROR_OK) return retval; } /* write all complete words */ for (; i < (count & ~3); i += 4) { data = 0; for (j = 0; j < 4; j++) data |= (buffer[j+i] << j*8); h_u32_to_be((uint8_t *)&data_out, data); retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, addr + i, data_out); if (retval != ERROR_OK) return retval; } /* * Write trailing bytes */ if (i < count) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i, &data); if (retval != ERROR_OK) return retval; data = be_to_h_u32((uint8_t *)&data); for (j = 0; i < count; j++, i++) { data &= ~(0xff << j*8); data |= (buffer[j+i] << j*8); } h_u32_to_be((uint8_t *)&data_out, data); retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, addr+i, data_out); if (retval != ERROR_OK) return retval; } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/avr32_mem.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_AVR32_MEM_H #define OPENOCD_TARGET_AVR32_MEM_H int avr32_jtag_read_memory32(struct avr32_jtag *jtag_info, uint32_t addr, int count, uint32_t *buffer); int avr32_jtag_read_memory16(struct avr32_jtag *jtag_info, uint32_t addr, int count, uint16_t *buffer); int avr32_jtag_read_memory8(struct avr32_jtag *jtag_info, uint32_t addr, int count, uint8_t *buffer); int avr32_jtag_write_memory32(struct avr32_jtag *jtag_info, uint32_t addr, int count, const uint32_t *buffer); int avr32_jtag_write_memory16(struct avr32_jtag *jtag_info, uint32_t addr, int count, const uint16_t *buffer); int avr32_jtag_write_memory8(struct avr32_jtag *jtag_info, uint32_t addr, int count, const uint8_t *buffer); #endif /* OPENOCD_TARGET_AVR32_MEM_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/avr32_regs.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include "jtag/jtag.h" #include "avr32_jtag.h" #include "avr32_regs.h" static int avr32_jtag_read_reg(struct avr32_jtag *jtag_info, int reg, uint32_t *val) { int retval; uint32_t dcsr; retval = avr32_jtag_exec(jtag_info, MTDR(AVR32_OCDREG_DCCPU, reg)); if (retval != ERROR_OK) return retval; do { retval = avr32_jtag_nexus_read(jtag_info, AVR32_OCDREG_DCSR, &dcsr); if (retval != ERROR_OK) return retval; } while (!(dcsr & OCDREG_DCSR_CPUD)); retval = avr32_jtag_nexus_read(jtag_info, AVR32_OCDREG_DCCPU, val); return retval; } static int avr32_jtag_write_reg(struct avr32_jtag *jtag_info, int reg, uint32_t val) { int retval; uint32_t dcsr; /* Restore Status reg */ retval = avr32_jtag_nexus_write(jtag_info, AVR32_OCDREG_DCEMU, val); if (retval != ERROR_OK) return retval; retval = avr32_jtag_exec(jtag_info, MFDR(reg, AVR32_OCDREG_DCEMU)); if (retval != ERROR_OK) return retval; do { retval = avr32_jtag_nexus_read(jtag_info, AVR32_OCDREG_DCSR, &dcsr); } while (!(dcsr & OCDREG_DCSR_EMUD) && (retval == ERROR_OK)); return retval; } int avr32_jtag_read_regs(struct avr32_jtag *jtag_info, uint32_t *regs) { int i, retval; /* read core registers */ for (i = 0; i < AVR32NUMCOREREGS - 1; i++) avr32_jtag_read_reg(jtag_info, i, regs + i); /* read status register */ retval = avr32_jtag_exec(jtag_info, MFSR(0, 0)); if (retval != ERROR_OK) return retval; retval = avr32_jtag_read_reg(jtag_info, 0, regs + AVR32_REG_SR); return retval; } int avr32_jtag_write_regs(struct avr32_jtag *jtag_info, uint32_t *regs) { int i, retval; retval = avr32_jtag_write_reg(jtag_info, 0, regs[AVR32_REG_SR]); if (retval != ERROR_OK) return retval; /* Restore Status reg */ retval = avr32_jtag_exec(jtag_info, MTSR(0, 0)); if (retval != ERROR_OK) return retval; /* * And now the rest of registers */ for (i = 0; i < AVR32NUMCOREREGS - 1; i++) avr32_jtag_write_reg(jtag_info, i, regs[i]); return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/avr32_regs.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_AVR32_REGS_H #define OPENOCD_TARGET_AVR32_REGS_H enum avr32_reg_nums { AVR32_REG_R0 = 0, AVR32_REG_R1, AVR32_REG_R2, AVR32_REG_R3, AVR32_REG_R4, AVR32_REG_R5, AVR32_REG_R6, AVR32_REG_R7, AVR32_REG_R8, AVR32_REG_R9, AVR32_REG_R10, AVR32_REG_R11, AVR32_REG_R12, AVR32_REG_SP, AVR32_REG_LR, AVR32_REG_PC, AVR32_REG_SR, }; int avr32_jtag_read_regs(struct avr32_jtag *jtag_info, uint32_t *regs); int avr32_jtag_write_regs(struct avr32_jtag *jtag_info, uint32_t *regs); #endif /* OPENOCD_TARGET_AVR32_REGS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/avrt.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "avrt.h" #include "target.h" #include "target_type.h" #define AVR_JTAG_INS_LEN 4 /* forward declarations */ static int avr_target_create(struct target *target, Jim_Interp *interp); static int avr_init_target(struct command_context *cmd_ctx, struct target *target); static int avr_arch_state(struct target *target); static int avr_poll(struct target *target); static int avr_halt(struct target *target); static int avr_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); static int avr_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); static int avr_assert_reset(struct target *target); static int avr_deassert_reset(struct target *target); /* IR and DR functions */ static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti); static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_len, int rti); static int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti); static int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *ir_in, uint32_t ir_out, int dr_len, int rti); struct target_type avr_target = { .name = "avr", .poll = avr_poll, .arch_state = avr_arch_state, .halt = avr_halt, .resume = avr_resume, .step = avr_step, .assert_reset = avr_assert_reset, .deassert_reset = avr_deassert_reset, /* .get_gdb_reg_list = avr_get_gdb_reg_list, .read_memory = avr_read_memory, .write_memory = avr_write_memory, .bulk_write_memory = avr_bulk_write_memory, .checksum_memory = avr_checksum_memory, .blank_check_memory = avr_blank_check_memory, .run_algorithm = avr_run_algorithm, .add_breakpoint = avr_add_breakpoint, .remove_breakpoint = avr_remove_breakpoint, .add_watchpoint = avr_add_watchpoint, .remove_watchpoint = avr_remove_watchpoint, */ .target_create = avr_target_create, .init_target = avr_init_target, }; static int avr_target_create(struct target *target, Jim_Interp *interp) { struct avr_common *avr = calloc(1, sizeof(struct avr_common)); avr->jtag_info.tap = target->tap; target->arch_info = avr; return ERROR_OK; } static int avr_init_target(struct command_context *cmd_ctx, struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_arch_state(struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_poll(struct target *target) { if ((target->state == TARGET_RUNNING) || (target->state == TARGET_DEBUG_RUNNING)) target->state = TARGET_HALTED; LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_halt(struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_assert_reset(struct target *target) { target->state = TARGET_RESET; LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_deassert_reset(struct target *target) { target->state = TARGET_RUNNING; LOG_DEBUG("%s", __func__); return ERROR_OK; } int avr_jtag_senddat(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int len) { return mcu_write_dr_u32(tap, dr_in, dr_out, len, 1); } int avr_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out) { return mcu_write_ir_u8(tap, ir_in, ir_out, AVR_JTAG_INS_LEN, 1); } /* IR and DR functions */ static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti) { if (!tap) { LOG_ERROR("invalid tap"); return ERROR_FAIL; } if (ir_len != tap->ir_length) { LOG_ERROR("invalid ir_len"); return ERROR_FAIL; } { jtag_add_plain_ir_scan(tap->ir_length, ir_out, ir_in, TAP_IDLE); } return ERROR_OK; } static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_len, int rti) { if (!tap) { LOG_ERROR("invalid tap"); return ERROR_FAIL; } { jtag_add_plain_dr_scan(dr_len, dr_out, dr_in, TAP_IDLE); } return ERROR_OK; } static int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti) { if (ir_len > 8) { LOG_ERROR("ir_len overflow, maximum is 8"); return ERROR_FAIL; } mcu_write_ir(tap, ir_in, &ir_out, ir_len, rti); return ERROR_OK; } static int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int dr_len, int rti) { if (dr_len > 32) { LOG_ERROR("dr_len overflow, maximum is 32"); return ERROR_FAIL; } mcu_write_dr(tap, (uint8_t *)dr_in, (uint8_t *)&dr_out, dr_len, rti); return ERROR_OK; } int mcu_execute_queue(void) { return jtag_execute_queue(); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/avrt.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_AVRT_H #define OPENOCD_TARGET_AVRT_H #include <jtag/jtag.h> struct mcu_jtag { struct jtag_tap *tap; }; struct avr_common { struct mcu_jtag jtag_info; }; int mcu_execute_queue(void); int avr_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out); int avr_jtag_senddat(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int len); #endif /* OPENOCD_TARGET_AVRT_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/breakpoints.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) ST-Ericsson SA 2011 * * michel.jaouen@stericsson.com : smp minimum support * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include <helper/log.h> #include "breakpoints.h" #include "smp.h" static const char * const breakpoint_type_strings[] = { "hardware", "software" }; static const char * const watchpoint_rw_strings[] = { "read", "write", "access" }; /* monotonic counter/id-number for breakpoints and watch points */ static int bpwp_unique_id; static int breakpoint_add_internal(struct target *target, target_addr_t address, uint32_t length, enum breakpoint_type type) { struct breakpoint *breakpoint = target->breakpoints; struct breakpoint **breakpoint_p = &target->breakpoints; const char *reason; int retval; while (breakpoint) { if (breakpoint->address == address) { /* FIXME don't assume "same address" means "same * breakpoint" ... check all the parameters before * succeeding. */ LOG_ERROR("Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")", address, breakpoint->unique_id); return ERROR_TARGET_DUPLICATE_BREAKPOINT; } breakpoint_p = &breakpoint->next; breakpoint = breakpoint->next; } (*breakpoint_p) = malloc(sizeof(struct breakpoint)); (*breakpoint_p)->address = address; (*breakpoint_p)->asid = 0; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; (*breakpoint_p)->is_set = false; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*breakpoint_p)->unique_id = bpwp_unique_id++; retval = target_add_breakpoint(target, *breakpoint_p); switch (retval) { case ERROR_OK: break; case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: reason = "resource not available"; goto fail; case ERROR_TARGET_NOT_HALTED: reason = "target running"; goto fail; default: reason = "unknown reason"; fail: LOG_ERROR("can't add breakpoint: %s", reason); free((*breakpoint_p)->orig_instr); free(*breakpoint_p); *breakpoint_p = NULL; return retval; } LOG_DEBUG("[%d] added %s breakpoint at " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")", target->coreid, breakpoint_type_strings[(*breakpoint_p)->type], (*breakpoint_p)->address, (*breakpoint_p)->length, (*breakpoint_p)->unique_id); return ERROR_OK; } static int context_breakpoint_add_internal(struct target *target, uint32_t asid, uint32_t length, enum breakpoint_type type) { struct breakpoint *breakpoint = target->breakpoints; struct breakpoint **breakpoint_p = &target->breakpoints; int retval; while (breakpoint) { if (breakpoint->asid == asid) { /* FIXME don't assume "same address" means "same * breakpoint" ... check all the parameters before * succeeding. */ LOG_ERROR("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")", asid, breakpoint->unique_id); return ERROR_TARGET_DUPLICATE_BREAKPOINT; } breakpoint_p = &breakpoint->next; breakpoint = breakpoint->next; } (*breakpoint_p) = malloc(sizeof(struct breakpoint)); (*breakpoint_p)->address = 0; (*breakpoint_p)->asid = asid; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; (*breakpoint_p)->is_set = false; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*breakpoint_p)->unique_id = bpwp_unique_id++; retval = target_add_context_breakpoint(target, *breakpoint_p); if (retval != ERROR_OK) { LOG_ERROR("could not add breakpoint"); free((*breakpoint_p)->orig_instr); free(*breakpoint_p); *breakpoint_p = NULL; return retval; } LOG_DEBUG("added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")", breakpoint_type_strings[(*breakpoint_p)->type], (*breakpoint_p)->asid, (*breakpoint_p)->length, (*breakpoint_p)->unique_id); return ERROR_OK; } static int hybrid_breakpoint_add_internal(struct target *target, target_addr_t address, uint32_t asid, uint32_t length, enum breakpoint_type type) { struct breakpoint *breakpoint = target->breakpoints; struct breakpoint **breakpoint_p = &target->breakpoints; int retval; while (breakpoint) { if ((breakpoint->asid == asid) && (breakpoint->address == address)) { /* FIXME don't assume "same address" means "same * breakpoint" ... check all the parameters before * succeeding. */ LOG_ERROR("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")", asid, breakpoint->unique_id); return ERROR_TARGET_DUPLICATE_BREAKPOINT; } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) { LOG_ERROR("Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")", address, breakpoint->unique_id); return ERROR_TARGET_DUPLICATE_BREAKPOINT; } breakpoint_p = &breakpoint->next; breakpoint = breakpoint->next; } (*breakpoint_p) = malloc(sizeof(struct breakpoint)); (*breakpoint_p)->address = address; (*breakpoint_p)->asid = asid; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; (*breakpoint_p)->is_set = false; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*breakpoint_p)->unique_id = bpwp_unique_id++; retval = target_add_hybrid_breakpoint(target, *breakpoint_p); if (retval != ERROR_OK) { LOG_ERROR("could not add breakpoint"); free((*breakpoint_p)->orig_instr); free(*breakpoint_p); *breakpoint_p = NULL; return retval; } LOG_DEBUG( "added %s Hybrid breakpoint at address " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")", breakpoint_type_strings[(*breakpoint_p)->type], (*breakpoint_p)->address, (*breakpoint_p)->length, (*breakpoint_p)->unique_id); return ERROR_OK; } int breakpoint_add(struct target *target, target_addr_t address, uint32_t length, enum breakpoint_type type) { if (target->smp) { struct target_list *head; if (type == BKPT_SOFT) { head = list_first_entry(target->smp_targets, struct target_list, lh); return breakpoint_add_internal(head->target, address, length, type); } foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; int retval = breakpoint_add_internal(curr, address, length, type); if (retval != ERROR_OK) return retval; } return ERROR_OK; } else { return breakpoint_add_internal(target, address, length, type); } } int context_breakpoint_add(struct target *target, uint32_t asid, uint32_t length, enum breakpoint_type type) { if (target->smp) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; int retval = context_breakpoint_add_internal(curr, asid, length, type); if (retval != ERROR_OK) return retval; } return ERROR_OK; } else { return context_breakpoint_add_internal(target, asid, length, type); } } int hybrid_breakpoint_add(struct target *target, target_addr_t address, uint32_t asid, uint32_t length, enum breakpoint_type type) { if (target->smp) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type); if (retval != ERROR_OK) return retval; } return ERROR_OK; } else return hybrid_breakpoint_add_internal(target, address, asid, length, type); } /* free up a breakpoint */ static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove) { struct breakpoint *breakpoint = target->breakpoints; struct breakpoint **breakpoint_p = &target->breakpoints; int retval; while (breakpoint) { if (breakpoint == breakpoint_to_remove) break; breakpoint_p = &breakpoint->next; breakpoint = breakpoint->next; } if (!breakpoint) return; retval = target_remove_breakpoint(target, breakpoint); LOG_DEBUG("free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval); (*breakpoint_p) = breakpoint->next; free(breakpoint->orig_instr); free(breakpoint); } static int breakpoint_remove_internal(struct target *target, target_addr_t address) { struct breakpoint *breakpoint = target->breakpoints; while (breakpoint) { if ((breakpoint->address == address) || (breakpoint->address == 0 && breakpoint->asid == address)) break; breakpoint = breakpoint->next; } if (breakpoint) { breakpoint_free(target, breakpoint); return 1; } else { if (!target->smp) LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address); return 0; } } static void breakpoint_remove_all_internal(struct target *target) { struct breakpoint *breakpoint = target->breakpoints; while (breakpoint) { struct breakpoint *tmp = breakpoint; breakpoint = breakpoint->next; breakpoint_free(target, tmp); } } void breakpoint_remove(struct target *target, target_addr_t address) { if (target->smp) { unsigned int num_breakpoints = 0; struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; num_breakpoints += breakpoint_remove_internal(curr, address); } if (!num_breakpoints) LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address); } else { breakpoint_remove_internal(target, address); } } void breakpoint_remove_all(struct target *target) { if (target->smp) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; breakpoint_remove_all_internal(curr); } } else { breakpoint_remove_all_internal(target); } } static void breakpoint_clear_target_internal(struct target *target) { LOG_DEBUG("Delete all breakpoints for target: %s", target_name(target)); while (target->breakpoints) breakpoint_free(target, target->breakpoints); } void breakpoint_clear_target(struct target *target) { if (target->smp) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; breakpoint_clear_target_internal(curr); } } else { breakpoint_clear_target_internal(target); } } struct breakpoint *breakpoint_find(struct target *target, target_addr_t address) { struct breakpoint *breakpoint = target->breakpoints; while (breakpoint) { if (breakpoint->address == address) return breakpoint; breakpoint = breakpoint->next; } return NULL; } static int watchpoint_add_internal(struct target *target, target_addr_t address, uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask) { struct watchpoint *watchpoint = target->watchpoints; struct watchpoint **watchpoint_p = &target->watchpoints; int retval; const char *reason; while (watchpoint) { if (watchpoint->address == address) { if (watchpoint->length != length || watchpoint->value != value || watchpoint->mask != mask || watchpoint->rw != rw) { LOG_ERROR("address " TARGET_ADDR_FMT " already has watchpoint %d", address, watchpoint->unique_id); return ERROR_FAIL; } /* ignore duplicate watchpoint */ return ERROR_OK; } watchpoint_p = &watchpoint->next; watchpoint = watchpoint->next; } (*watchpoint_p) = calloc(1, sizeof(struct watchpoint)); (*watchpoint_p)->address = address; (*watchpoint_p)->length = length; (*watchpoint_p)->value = value; (*watchpoint_p)->mask = mask; (*watchpoint_p)->rw = rw; (*watchpoint_p)->unique_id = bpwp_unique_id++; retval = target_add_watchpoint(target, *watchpoint_p); switch (retval) { case ERROR_OK: break; case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: reason = "resource not available"; goto bye; case ERROR_TARGET_NOT_HALTED: reason = "target running"; goto bye; default: reason = "unrecognized error"; bye: LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s", watchpoint_rw_strings[(*watchpoint_p)->rw], address, reason); free(*watchpoint_p); *watchpoint_p = NULL; return retval; } LOG_DEBUG("[%d] added %s watchpoint at " TARGET_ADDR_FMT " of length 0x%8.8" PRIx32 " (WPID: %d)", target->coreid, watchpoint_rw_strings[(*watchpoint_p)->rw], (*watchpoint_p)->address, (*watchpoint_p)->length, (*watchpoint_p)->unique_id); return ERROR_OK; } int watchpoint_add(struct target *target, target_addr_t address, uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask) { if (target->smp) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; int retval = watchpoint_add_internal(curr, address, length, rw, value, mask); if (retval != ERROR_OK) return retval; } return ERROR_OK; } else { return watchpoint_add_internal(target, address, length, rw, value, mask); } } static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove) { struct watchpoint *watchpoint = target->watchpoints; struct watchpoint **watchpoint_p = &target->watchpoints; int retval; while (watchpoint) { if (watchpoint == watchpoint_to_remove) break; watchpoint_p = &watchpoint->next; watchpoint = watchpoint->next; } if (!watchpoint) return; retval = target_remove_watchpoint(target, watchpoint); LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval); (*watchpoint_p) = watchpoint->next; free(watchpoint); } static int watchpoint_remove_internal(struct target *target, target_addr_t address) { struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { if (watchpoint->address == address) break; watchpoint = watchpoint->next; } if (watchpoint) { watchpoint_free(target, watchpoint); return 1; } else { if (!target->smp) LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address); return 0; } } void watchpoint_remove(struct target *target, target_addr_t address) { if (target->smp) { unsigned int num_watchpoints = 0; struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; num_watchpoints += watchpoint_remove_internal(curr, address); } if (num_watchpoints == 0) LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " num_watchpoints", address); } else { watchpoint_remove_internal(target, address); } } void watchpoint_clear_target(struct target *target) { LOG_DEBUG("Delete all watchpoints for target: %s", target_name(target)); while (target->watchpoints) watchpoint_free(target, target->watchpoints); } int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, target_addr_t *address) { int retval; struct watchpoint *hit_watchpoint; retval = target_hit_watchpoint(target, &hit_watchpoint); if (retval != ERROR_OK) return ERROR_FAIL; *rw = hit_watchpoint->rw; *address = hit_watchpoint->address; LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)", hit_watchpoint->address, hit_watchpoint->unique_id); return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/breakpoints.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_TARGET_BREAKPOINTS_H #define OPENOCD_TARGET_BREAKPOINTS_H #include <stdint.h> #include "helper/types.h" struct target; enum breakpoint_type { BKPT_HARD, BKPT_SOFT, }; enum watchpoint_rw { WPT_READ = 0, WPT_WRITE = 1, WPT_ACCESS = 2 }; struct breakpoint { target_addr_t address; uint32_t asid; int length; enum breakpoint_type type; bool is_set; unsigned int number; uint8_t *orig_instr; struct breakpoint *next; uint32_t unique_id; int linked_brp; }; struct watchpoint { target_addr_t address; uint32_t length; uint32_t mask; uint32_t value; enum watchpoint_rw rw; bool is_set; unsigned int number; struct watchpoint *next; int unique_id; }; void breakpoint_clear_target(struct target *target); int breakpoint_add(struct target *target, target_addr_t address, uint32_t length, enum breakpoint_type type); int context_breakpoint_add(struct target *target, uint32_t asid, uint32_t length, enum breakpoint_type type); int hybrid_breakpoint_add(struct target *target, target_addr_t address, uint32_t asid, uint32_t length, enum breakpoint_type type); void breakpoint_remove(struct target *target, target_addr_t address); void breakpoint_remove_all(struct target *target); struct breakpoint *breakpoint_find(struct target *target, target_addr_t address); static inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int hw_number) { breakpoint->is_set = true; breakpoint->number = hw_number; } void watchpoint_clear_target(struct target *target); int watchpoint_add(struct target *target, target_addr_t address, uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask); void watchpoint_remove(struct target *target, target_addr_t address); /* report type and address of just hit watchpoint */ int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, target_addr_t *address); static inline void watchpoint_set(struct watchpoint *watchpoint, unsigned int number) { watchpoint->is_set = true; watchpoint->number = number; } #endif /* OPENOCD_TARGET_BREAKPOINTS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/cortex_a.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2009 by Dirk Behme * * dirk.behme@gmail.com - copy from cortex_m3 * * * * Copyright (C) 2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) ST-Ericsson SA 2011 * * michel.jaouen@stericsson.com : smp minimum support * * * * Copyright (C) Broadcom 2012 * * ehunter@broadcom.com : Cortex-R4 support * * * * Copyright (C) 2013 Kamal Dasu * * kdasu.kdev@gmail.com * * * * Copyright (C) 2016 Chengyu Zheng * * chengyu.zheng@polimi.it : watchpoint support * * * * Cortex-A8(tm) TRM, ARM DDI 0344H * * Cortex-A9(tm) TRM, ARM DDI 0407F * * Cortex-A4(tm) TRM, ARM DDI 0363E * * Cortex-A15(tm)TRM, ARM DDI 0438C * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "breakpoints.h" #include "cortex_a.h" #include "register.h" #include "armv7a_mmu.h" #include "target_request.h" #include "target_type.h" #include "arm_coresight.h" #include "arm_opcodes.h" #include "arm_semihosting.h" #include "jtag/interface.h" #include "transport/transport.h" #include "smp.h" #include <helper/bits.h> #include <helper/nvp.h> #include <helper/time_support.h> static int cortex_a_poll(struct target *target); static int cortex_a_debug_entry(struct target *target); static int cortex_a_restore_context(struct target *target, bool bpwp); static int cortex_a_set_breakpoint(struct target *target, struct breakpoint *breakpoint, uint8_t matchmode); static int cortex_a_set_context_breakpoint(struct target *target, struct breakpoint *breakpoint, uint8_t matchmode); static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint); static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); static int cortex_a_wait_dscr_bits(struct target *target, uint32_t mask, uint32_t value, uint32_t *dscr); static int cortex_a_mmu(struct target *target, int *enabled); static int cortex_a_mmu_modify(struct target *target, int enable); static int cortex_a_virt2phys(struct target *target, target_addr_t virt, target_addr_t *phys); static int cortex_a_read_cpu_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); static unsigned int ilog2(unsigned int x) { unsigned int y = 0; x /= 2; while (x) { ++y; x /= 2; } return y; } /* restore cp15_control_reg at resume */ static int cortex_a_restore_cp15_control_reg(struct target *target) { int retval = ERROR_OK; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = target_to_armv7a(target); if (cortex_a->cp15_control_reg != cortex_a->cp15_control_reg_curr) { cortex_a->cp15_control_reg_curr = cortex_a->cp15_control_reg; /* LOG_INFO("cp15_control_reg: %8.8" PRIx32, cortex_a->cp15_control_reg); */ retval = armv7a->arm.mcr(target, 15, 0, 0, /* op1, op2 */ 1, 0, /* CRn, CRm */ cortex_a->cp15_control_reg); } return retval; } /* * Set up ARM core for memory access. * If !phys_access, switch to SVC mode and make sure MMU is on * If phys_access, switch off mmu */ static int cortex_a_prep_memaccess(struct target *target, int phys_access) { struct armv7a_common *armv7a = target_to_armv7a(target); struct cortex_a_common *cortex_a = target_to_cortex_a(target); int mmu_enabled = 0; if (phys_access == 0) { arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); cortex_a_mmu(target, &mmu_enabled); if (mmu_enabled) cortex_a_mmu_modify(target, 1); if (cortex_a->dacrfixup_mode == CORTEX_A_DACRFIXUP_ON) { /* overwrite DACR to all-manager */ armv7a->arm.mcr(target, 15, 0, 0, 3, 0, 0xFFFFFFFF); } } else { cortex_a_mmu(target, &mmu_enabled); if (mmu_enabled) cortex_a_mmu_modify(target, 0); } return ERROR_OK; } /* * Restore ARM core after memory access. * If !phys_access, switch to previous mode * If phys_access, restore MMU setting */ static int cortex_a_post_memaccess(struct target *target, int phys_access) { struct armv7a_common *armv7a = target_to_armv7a(target); struct cortex_a_common *cortex_a = target_to_cortex_a(target); if (phys_access == 0) { if (cortex_a->dacrfixup_mode == CORTEX_A_DACRFIXUP_ON) { /* restore */ armv7a->arm.mcr(target, 15, 0, 0, 3, 0, cortex_a->cp15_dacr_reg); } arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); } else { int mmu_enabled = 0; cortex_a_mmu(target, &mmu_enabled); if (mmu_enabled) cortex_a_mmu_modify(target, 1); } return ERROR_OK; } /* modify cp15_control_reg in order to enable or disable mmu for : * - virt2phys address conversion * - read or write memory in phys or virt address */ static int cortex_a_mmu_modify(struct target *target, int enable) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = target_to_armv7a(target); int retval = ERROR_OK; int need_write = 0; if (enable) { /* if mmu enabled at target stop and mmu not enable */ if (!(cortex_a->cp15_control_reg & 0x1U)) { LOG_ERROR("trying to enable mmu on target stopped with mmu disable"); return ERROR_FAIL; } if ((cortex_a->cp15_control_reg_curr & 0x1U) == 0) { cortex_a->cp15_control_reg_curr |= 0x1U; need_write = 1; } } else { if ((cortex_a->cp15_control_reg_curr & 0x1U) == 0x1U) { cortex_a->cp15_control_reg_curr &= ~0x1U; need_write = 1; } } if (need_write) { LOG_DEBUG("%s, writing cp15 ctrl: %" PRIx32, enable ? "enable mmu" : "disable mmu", cortex_a->cp15_control_reg_curr); retval = armv7a->arm.mcr(target, 15, 0, 0, /* op1, op2 */ 1, 0, /* CRn, CRm */ cortex_a->cp15_control_reg_curr); } return retval; } /* * Cortex-A Basic debug access, very low level assumes state is saved */ static int cortex_a_init_debug_access(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); uint32_t dscr; int retval; /* lock memory-mapped access to debug registers to prevent * software interference */ retval = mem_ap_write_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_LOCKACCESS, 0); if (retval != ERROR_OK) return retval; /* Disable cacheline fills and force cache write-through in debug state */ retval = mem_ap_write_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCCR, 0); if (retval != ERROR_OK) return retval; /* Disable TLB lookup and refill/eviction in debug state */ retval = mem_ap_write_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSMCR, 0); if (retval != ERROR_OK) return retval; retval = dap_run(armv7a->debug_ap->dap); if (retval != ERROR_OK) return retval; /* Enabling of instruction execution in debug mode is done in debug_entry code */ /* Resync breakpoint registers */ /* Enable halt for breakpoint, watchpoint and vector catch */ retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr | DSCR_HALT_DBG_MODE); if (retval != ERROR_OK) return retval; /* Since this is likely called from init or reset, update target state information*/ return cortex_a_poll(target); } static int cortex_a_wait_instrcmpl(struct target *target, uint32_t *dscr, bool force) { /* Waits until InstrCmpl_l becomes 1, indicating instruction is done. * Writes final value of DSCR into *dscr. Pass force to force always * reading DSCR at least once. */ struct armv7a_common *armv7a = target_to_armv7a(target); int retval; if (force) { retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); if (retval != ERROR_OK) { LOG_ERROR("Could not read DSCR register"); return retval; } } retval = cortex_a_wait_dscr_bits(target, DSCR_INSTR_COMP, DSCR_INSTR_COMP, dscr); if (retval != ERROR_OK) LOG_ERROR("Error waiting for InstrCompl=1"); return retval; } /* To reduce needless round-trips, pass in a pointer to the current * DSCR value. Initialize it to zero if you just need to know the * value on return from this function; or DSCR_INSTR_COMP if you * happen to know that no instruction is pending. */ static int cortex_a_exec_opcode(struct target *target, uint32_t opcode, uint32_t *dscr_p) { uint32_t dscr; int retval; struct armv7a_common *armv7a = target_to_armv7a(target); dscr = dscr_p ? *dscr_p : 0; LOG_DEBUG("exec opcode 0x%08" PRIx32, opcode); /* Wait for InstrCompl bit to be set */ retval = cortex_a_wait_instrcmpl(target, dscr_p, false); if (retval != ERROR_OK) return retval; retval = mem_ap_write_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_ITR, opcode); if (retval != ERROR_OK) return retval; /* Wait for InstrCompl bit to be set */ retval = cortex_a_wait_instrcmpl(target, &dscr, true); if (retval != ERROR_OK) { LOG_ERROR("Error waiting for cortex_a_exec_opcode"); return retval; } if (dscr_p) *dscr_p = dscr; return retval; } /* Write to memory mapped registers directly with no cache or mmu handling */ static int cortex_a_dap_write_memap_register_u32(struct target *target, uint32_t address, uint32_t value) { int retval; struct armv7a_common *armv7a = target_to_armv7a(target); retval = mem_ap_write_atomic_u32(armv7a->debug_ap, address, value); return retval; } /* * Cortex-A implementation of Debug Programmer's Model * * NOTE the invariant: these routines return with DSCR_INSTR_COMP set, * so there's no need to poll for it before executing an instruction. * * NOTE that in several of these cases the "stall" mode might be useful. * It'd let us queue a few operations together... prepare/finish might * be the places to enable/disable that mode. */ static inline struct cortex_a_common *dpm_to_a(struct arm_dpm *dpm) { return container_of(dpm, struct cortex_a_common, armv7a_common.dpm); } static int cortex_a_write_dcc(struct cortex_a_common *a, uint32_t data) { LOG_DEBUG("write DCC 0x%08" PRIx32, data); return mem_ap_write_u32(a->armv7a_common.debug_ap, a->armv7a_common.debug_base + CPUDBG_DTRRX, data); } static int cortex_a_read_dcc(struct cortex_a_common *a, uint32_t *data, uint32_t *dscr_p) { uint32_t dscr = DSCR_INSTR_COMP; int retval; if (dscr_p) dscr = *dscr_p; /* Wait for DTRRXfull */ retval = cortex_a_wait_dscr_bits(a->armv7a_common.arm.target, DSCR_DTR_TX_FULL, DSCR_DTR_TX_FULL, &dscr); if (retval != ERROR_OK) { LOG_ERROR("Error waiting for read dcc"); return retval; } retval = mem_ap_read_atomic_u32(a->armv7a_common.debug_ap, a->armv7a_common.debug_base + CPUDBG_DTRTX, data); if (retval != ERROR_OK) return retval; /* LOG_DEBUG("read DCC 0x%08" PRIx32, *data); */ if (dscr_p) *dscr_p = dscr; return retval; } static int cortex_a_dpm_prepare(struct arm_dpm *dpm) { struct cortex_a_common *a = dpm_to_a(dpm); uint32_t dscr; int retval; /* set up invariant: INSTR_COMP is set after ever DPM operation */ retval = cortex_a_wait_instrcmpl(dpm->arm->target, &dscr, true); if (retval != ERROR_OK) { LOG_ERROR("Error waiting for dpm prepare"); return retval; } /* this "should never happen" ... */ if (dscr & DSCR_DTR_RX_FULL) { LOG_ERROR("DSCR_DTR_RX_FULL, dscr 0x%08" PRIx32, dscr); /* Clear DCCRX */ retval = cortex_a_exec_opcode( a->armv7a_common.arm.target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; } return retval; } static int cortex_a_dpm_finish(struct arm_dpm *dpm) { /* REVISIT what could be done here? */ return ERROR_OK; } static int cortex_a_instr_write_data_dcc(struct arm_dpm *dpm, uint32_t opcode, uint32_t data) { struct cortex_a_common *a = dpm_to_a(dpm); int retval; uint32_t dscr = DSCR_INSTR_COMP; retval = cortex_a_write_dcc(a, data); if (retval != ERROR_OK) return retval; return cortex_a_exec_opcode( a->armv7a_common.arm.target, opcode, &dscr); } static int cortex_a_instr_write_data_rt_dcc(struct arm_dpm *dpm, uint8_t rt, uint32_t data) { struct cortex_a_common *a = dpm_to_a(dpm); uint32_t dscr = DSCR_INSTR_COMP; int retval; if (rt > 15) return ERROR_TARGET_INVALID; retval = cortex_a_write_dcc(a, data); if (retval != ERROR_OK) return retval; /* DCCRX to Rt, "MCR p14, 0, R0, c0, c5, 0", 0xEE000E15 */ return cortex_a_exec_opcode( a->armv7a_common.arm.target, ARMV4_5_MRC(14, 0, rt, 0, 5, 0), &dscr); } static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm, uint32_t opcode, uint32_t data) { struct cortex_a_common *a = dpm_to_a(dpm); uint32_t dscr = DSCR_INSTR_COMP; int retval; retval = cortex_a_instr_write_data_rt_dcc(dpm, 0, data); if (retval != ERROR_OK) return retval; /* then the opcode, taking data from R0 */ retval = cortex_a_exec_opcode( a->armv7a_common.arm.target, opcode, &dscr); return retval; } static int cortex_a_instr_cpsr_sync(struct arm_dpm *dpm) { struct target *target = dpm->arm->target; uint32_t dscr = DSCR_INSTR_COMP; /* "Prefetch flush" after modifying execution status in CPSR */ return cortex_a_exec_opcode(target, ARMV4_5_MCR(15, 0, 0, 7, 5, 4), &dscr); } static int cortex_a_instr_read_data_dcc(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data) { struct cortex_a_common *a = dpm_to_a(dpm); int retval; uint32_t dscr = DSCR_INSTR_COMP; /* the opcode, writing data to DCC */ retval = cortex_a_exec_opcode( a->armv7a_common.arm.target, opcode, &dscr); if (retval != ERROR_OK) return retval; return cortex_a_read_dcc(a, data, &dscr); } static int cortex_a_instr_read_data_rt_dcc(struct arm_dpm *dpm, uint8_t rt, uint32_t *data) { struct cortex_a_common *a = dpm_to_a(dpm); uint32_t dscr = DSCR_INSTR_COMP; int retval; if (rt > 15) return ERROR_TARGET_INVALID; retval = cortex_a_exec_opcode( a->armv7a_common.arm.target, ARMV4_5_MCR(14, 0, rt, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; return cortex_a_read_dcc(a, data, &dscr); } static int cortex_a_instr_read_data_r0(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data) { struct cortex_a_common *a = dpm_to_a(dpm); uint32_t dscr = DSCR_INSTR_COMP; int retval; /* the opcode, writing data to R0 */ retval = cortex_a_exec_opcode( a->armv7a_common.arm.target, opcode, &dscr); if (retval != ERROR_OK) return retval; /* write R0 to DCC */ return cortex_a_instr_read_data_rt_dcc(dpm, 0, data); } static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, uint32_t addr, uint32_t control) { struct cortex_a_common *a = dpm_to_a(dpm); uint32_t vr = a->armv7a_common.debug_base; uint32_t cr = a->armv7a_common.debug_base; int retval; switch (index_t) { case 0 ... 15: /* breakpoints */ vr += CPUDBG_BVR_BASE; cr += CPUDBG_BCR_BASE; break; case 16 ... 31: /* watchpoints */ vr += CPUDBG_WVR_BASE; cr += CPUDBG_WCR_BASE; index_t -= 16; break; default: return ERROR_FAIL; } vr += 4 * index_t; cr += 4 * index_t; LOG_DEBUG("A: bpwp enable, vr %08x cr %08x", (unsigned) vr, (unsigned) cr); retval = cortex_a_dap_write_memap_register_u32(dpm->arm->target, vr, addr); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(dpm->arm->target, cr, control); return retval; } static int cortex_a_bpwp_disable(struct arm_dpm *dpm, unsigned index_t) { struct cortex_a_common *a = dpm_to_a(dpm); uint32_t cr; switch (index_t) { case 0 ... 15: cr = a->armv7a_common.debug_base + CPUDBG_BCR_BASE; break; case 16 ... 31: cr = a->armv7a_common.debug_base + CPUDBG_WCR_BASE; index_t -= 16; break; default: return ERROR_FAIL; } cr += 4 * index_t; LOG_DEBUG("A: bpwp disable, cr %08x", (unsigned) cr); /* clear control register */ return cortex_a_dap_write_memap_register_u32(dpm->arm->target, cr, 0); } static int cortex_a_dpm_setup(struct cortex_a_common *a, uint32_t didr) { struct arm_dpm *dpm = &a->armv7a_common.dpm; int retval; dpm->arm = &a->armv7a_common.arm; dpm->didr = didr; dpm->prepare = cortex_a_dpm_prepare; dpm->finish = cortex_a_dpm_finish; dpm->instr_write_data_dcc = cortex_a_instr_write_data_dcc; dpm->instr_write_data_r0 = cortex_a_instr_write_data_r0; dpm->instr_cpsr_sync = cortex_a_instr_cpsr_sync; dpm->instr_read_data_dcc = cortex_a_instr_read_data_dcc; dpm->instr_read_data_r0 = cortex_a_instr_read_data_r0; dpm->bpwp_enable = cortex_a_bpwp_enable; dpm->bpwp_disable = cortex_a_bpwp_disable; retval = arm_dpm_setup(dpm); if (retval == ERROR_OK) retval = arm_dpm_initialize(dpm); return retval; } static struct target *get_cortex_a(struct target *target, int32_t coreid) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) return curr; } return target; } static int cortex_a_halt(struct target *target); static int cortex_a_halt_smp(struct target *target) { int retval = 0; struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_HALTED) && target_was_examined(curr)) retval += cortex_a_halt(curr); } return retval; } static int update_halt_gdb(struct target *target) { struct target *gdb_target = NULL; struct target_list *head; struct target *curr; int retval = 0; if (target->gdb_service && target->gdb_service->core[0] == -1) { target->gdb_service->target = target; target->gdb_service->core[0] = target->coreid; retval += cortex_a_halt_smp(target); } if (target->gdb_service) gdb_target = target->gdb_service->target; foreach_smp_target(head, target->smp_targets) { curr = head->target; /* skip calling context */ if (curr == target) continue; if (!target_was_examined(curr)) continue; /* skip targets that were already halted */ if (curr->state == TARGET_HALTED) continue; /* Skip gdb_target; it alerts GDB so has to be polled as last one */ if (curr == gdb_target) continue; /* avoid recursion in cortex_a_poll() */ curr->smp = 0; cortex_a_poll(curr); curr->smp = 1; } /* after all targets were updated, poll the gdb serving target */ if (gdb_target && gdb_target != target) cortex_a_poll(gdb_target); return retval; } /* * Cortex-A Run control */ static int cortex_a_poll(struct target *target) { int retval = ERROR_OK; uint32_t dscr; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; enum target_state prev_target_state = target->state; /* toggle to another core is done by gdb as follow */ /* maint packet J core_id */ /* continue */ /* the next polling trigger an halt event sent to gdb */ if ((target->state == TARGET_HALTED) && (target->smp) && (target->gdb_service) && (!target->gdb_service->target)) { target->gdb_service->target = get_cortex_a(target, target->gdb_service->core[1]); target_call_event_callbacks(target, TARGET_EVENT_HALTED); return retval; } retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; cortex_a->cpudbg_dscr = dscr; if (DSCR_RUN_MODE(dscr) == (DSCR_CORE_HALTED | DSCR_CORE_RESTARTED)) { if (prev_target_state != TARGET_HALTED) { /* We have a halting debug event */ LOG_DEBUG("Target halted"); target->state = TARGET_HALTED; retval = cortex_a_debug_entry(target); if (retval != ERROR_OK) return retval; if (target->smp) { retval = update_halt_gdb(target); if (retval != ERROR_OK) return retval; } if (prev_target_state == TARGET_DEBUG_RUNNING) { target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } else { /* prev_target_state is RUNNING, UNKNOWN or RESET */ if (arm_semihosting(target, &retval) != 0) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); } } } else target->state = TARGET_RUNNING; return retval; } static int cortex_a_halt(struct target *target) { int retval; uint32_t dscr; struct armv7a_common *armv7a = target_to_armv7a(target); /* * Tell the core to be halted by writing DRCR with 0x1 * and then wait for the core to be halted. */ retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_HALT); if (retval != ERROR_OK) return retval; dscr = 0; /* force read of dscr */ retval = cortex_a_wait_dscr_bits(target, DSCR_CORE_HALTED, DSCR_CORE_HALTED, &dscr); if (retval != ERROR_OK) { LOG_ERROR("Error waiting for halt"); return retval; } target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int cortex_a_internal_restore(struct target *target, int current, target_addr_t *address, int handle_breakpoints, int debug_execution) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; int retval; uint32_t resume_pc; if (!debug_execution) target_free_all_working_areas(target); #if 0 if (debug_execution) { /* Disable interrupts */ /* We disable interrupts in the PRIMASK register instead of * masking with C_MASKINTS, * This is probably the same issue as Cortex-M3 Errata 377493: * C_MASKINTS in parallel with disabled interrupts can cause * local faults to not be taken. */ buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_PRIMASK].value, 0, 32, 1); armv7m->core_cache->reg_list[ARMV7M_PRIMASK].dirty = true; armv7m->core_cache->reg_list[ARMV7M_PRIMASK].valid = true; /* Make sure we are in Thumb mode */ buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_XPSR].value, 0, 32, buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_XPSR].value, 0, 32) | (1 << 24)); armv7m->core_cache->reg_list[ARMV7M_XPSR].dirty = true; armv7m->core_cache->reg_list[ARMV7M_XPSR].valid = true; } #endif /* current = 1: continue on current pc, otherwise continue at <address> */ resume_pc = buf_get_u32(arm->pc->value, 0, 32); if (!current) resume_pc = *address; else *address = resume_pc; /* Make sure that the Armv7 gdb thumb fixups does not * kill the return address */ switch (arm->core_state) { case ARM_STATE_ARM: resume_pc &= 0xFFFFFFFC; break; case ARM_STATE_THUMB: case ARM_STATE_THUMB_EE: /* When the return address is loaded into PC * bit 0 must be 1 to stay in Thumb state */ resume_pc |= 0x1; break; case ARM_STATE_JAZELLE: LOG_ERROR("How do I resume into Jazelle state??"); return ERROR_FAIL; case ARM_STATE_AARCH64: LOG_ERROR("Shouldn't be in AARCH64 state"); return ERROR_FAIL; } LOG_DEBUG("resume pc = 0x%08" PRIx32, resume_pc); buf_set_u32(arm->pc->value, 0, 32, resume_pc); arm->pc->dirty = true; arm->pc->valid = true; /* restore dpm_mode at system halt */ arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); /* called it now before restoring context because it uses cpu * register r0 for restoring cp15 control register */ retval = cortex_a_restore_cp15_control_reg(target); if (retval != ERROR_OK) return retval; retval = cortex_a_restore_context(target, handle_breakpoints); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_NOTHALTED; target->state = TARGET_RUNNING; /* registers are now invalid */ register_cache_invalidate(arm->core_cache); #if 0 /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { LOG_DEBUG("unset breakpoint at 0x%8.8x", breakpoint->address); cortex_m3_unset_breakpoint(target, breakpoint); cortex_m3_single_step_core(target); cortex_m3_set_breakpoint(target, breakpoint); } } #endif return retval; } static int cortex_a_internal_restart(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; int retval; uint32_t dscr; /* * * Restart core and wait for it to be started. Clear ITRen and sticky * * exception flags: see ARMv7 ARM, C5.9. * * REVISIT: for single stepping, we probably want to * disable IRQs by default, with optional override... */ retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; if ((dscr & DSCR_INSTR_COMP) == 0) LOG_ERROR("DSCR InstrCompl must be set before leaving debug!"); retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr & ~DSCR_ITR_EN); if (retval != ERROR_OK) return retval; retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_RESTART | DRCR_CLEAR_EXCEPTIONS); if (retval != ERROR_OK) return retval; dscr = 0; /* force read of dscr */ retval = cortex_a_wait_dscr_bits(target, DSCR_CORE_RESTARTED, DSCR_CORE_RESTARTED, &dscr); if (retval != ERROR_OK) { LOG_ERROR("Error waiting for resume"); return retval; } target->debug_reason = DBG_REASON_NOTHALTED; target->state = TARGET_RUNNING; /* registers are now invalid */ register_cache_invalidate(arm->core_cache); return ERROR_OK; } static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) { int retval = 0; struct target_list *head; target_addr_t address; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) { /* resume current address , not in step mode */ retval += cortex_a_internal_restore(curr, 1, &address, handle_breakpoints, 0); retval += cortex_a_internal_restart(curr); } } return retval; } static int cortex_a_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { int retval = 0; /* dummy resume for smp toggle in order to reduce gdb impact */ if ((target->smp) && (target->gdb_service->core[1] != -1)) { /* simulate a start and halt of target */ target->gdb_service->target = NULL; target->gdb_service->core[0] = target->gdb_service->core[1]; /* fake resume at next poll we play the target core[1], see poll*/ target_call_event_callbacks(target, TARGET_EVENT_RESUMED); return 0; } cortex_a_internal_restore(target, current, &address, handle_breakpoints, debug_execution); if (target->smp) { target->gdb_service->core[0] = -1; retval = cortex_a_restore_smp(target, handle_breakpoints); if (retval != ERROR_OK) return retval; } cortex_a_internal_restart(target); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); LOG_DEBUG("target resumed at " TARGET_ADDR_FMT, address); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); LOG_DEBUG("target debug resumed at " TARGET_ADDR_FMT, address); } return ERROR_OK; } static int cortex_a_debug_entry(struct target *target) { uint32_t dscr; int retval = ERROR_OK; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; LOG_DEBUG("dscr = 0x%08" PRIx32, cortex_a->cpudbg_dscr); /* REVISIT surely we should not re-read DSCR !! */ retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; /* REVISIT see A TRM 12.11.4 steps 2..3 -- make sure that any * imprecise data aborts get discarded by issuing a Data * Synchronization Barrier: ARMV4_5_MCR(15, 0, 0, 7, 10, 4). */ /* Enable the ITR execution once we are in debug mode */ dscr |= DSCR_ITR_EN; retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); if (retval != ERROR_OK) return retval; /* Examine debug reason */ arm_dpm_report_dscr(&armv7a->dpm, cortex_a->cpudbg_dscr); /* save address of instruction that triggered the watchpoint? */ if (target->debug_reason == DBG_REASON_WATCHPOINT) { uint32_t wfar; retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_WFAR, &wfar); if (retval != ERROR_OK) return retval; arm_dpm_report_wfar(&armv7a->dpm, wfar); } /* First load register accessible through core debug port */ retval = arm_dpm_read_current_registers(&armv7a->dpm); if (retval != ERROR_OK) return retval; if (arm->spsr) { /* read SPSR */ retval = arm_dpm_read_reg(&armv7a->dpm, arm->spsr, 17); if (retval != ERROR_OK) return retval; } #if 0 /* TODO, Move this */ uint32_t cp15_control_register, cp15_cacr, cp15_nacr; cortex_a_read_cp(target, &cp15_control_register, 15, 0, 1, 0, 0); LOG_DEBUG("cp15_control_register = 0x%08x", cp15_control_register); cortex_a_read_cp(target, &cp15_cacr, 15, 0, 1, 0, 2); LOG_DEBUG("cp15 Coprocessor Access Control Register = 0x%08x", cp15_cacr); cortex_a_read_cp(target, &cp15_nacr, 15, 0, 1, 1, 2); LOG_DEBUG("cp15 Nonsecure Access Control Register = 0x%08x", cp15_nacr); #endif /* Are we in an exception handler */ /* armv4_5->exception_number = 0; */ if (armv7a->post_debug_entry) { retval = armv7a->post_debug_entry(target); if (retval != ERROR_OK) return retval; } return retval; } static int cortex_a_post_debug_entry(struct target *target) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; int retval; /* MRC p15,0,<Rt>,c1,c0,0 ; Read CP15 System Control Register */ retval = armv7a->arm.mrc(target, 15, 0, 0, /* op1, op2 */ 1, 0, /* CRn, CRm */ &cortex_a->cp15_control_reg); if (retval != ERROR_OK) return retval; LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, cortex_a->cp15_control_reg); cortex_a->cp15_control_reg_curr = cortex_a->cp15_control_reg; if (!armv7a->is_armv7r) armv7a_read_ttbcr(target); if (armv7a->armv7a_mmu.armv7a_cache.info == -1) armv7a_identify_cache(target); if (armv7a->is_armv7r) { armv7a->armv7a_mmu.mmu_enabled = 0; } else { armv7a->armv7a_mmu.mmu_enabled = (cortex_a->cp15_control_reg & 0x1U) ? 1 : 0; } armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled = (cortex_a->cp15_control_reg & 0x4U) ? 1 : 0; armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled = (cortex_a->cp15_control_reg & 0x1000U) ? 1 : 0; cortex_a->curr_mode = armv7a->arm.core_mode; /* switch to SVC mode to read DACR */ arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); armv7a->arm.mrc(target, 15, 0, 0, 3, 0, &cortex_a->cp15_dacr_reg); LOG_DEBUG("cp15_dacr_reg: %8.8" PRIx32, cortex_a->cp15_dacr_reg); arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); return ERROR_OK; } static int cortex_a_set_dscr_bits(struct target *target, unsigned long bit_mask, unsigned long value) { struct armv7a_common *armv7a = target_to_armv7a(target); uint32_t dscr; /* Read DSCR */ int retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; /* clear bitfield */ dscr &= ~bit_mask; /* put new value */ dscr |= value & bit_mask; /* write new DSCR */ retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); return retval; } static int cortex_a_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; struct breakpoint *breakpoint = NULL; struct breakpoint stepbreakpoint; struct reg *r; int retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* current = 1: continue on current pc, otherwise continue at <address> */ r = arm->pc; if (!current) buf_set_u32(r->value, 0, 32, address); else address = buf_get_u32(r->value, 0, 32); /* The front-end may request us not to handle breakpoints. * But since Cortex-A uses breakpoint for single step, * we MUST handle breakpoints. */ handle_breakpoints = 1; if (handle_breakpoints) { breakpoint = breakpoint_find(target, address); if (breakpoint) cortex_a_unset_breakpoint(target, breakpoint); } /* Setup single step breakpoint */ stepbreakpoint.address = address; stepbreakpoint.asid = 0; stepbreakpoint.length = (arm->core_state == ARM_STATE_THUMB) ? 2 : 4; stepbreakpoint.type = BKPT_HARD; stepbreakpoint.is_set = false; /* Disable interrupts during single step if requested */ if (cortex_a->isrmasking_mode == CORTEX_A_ISRMASK_ON) { retval = cortex_a_set_dscr_bits(target, DSCR_INT_DIS, DSCR_INT_DIS); if (retval != ERROR_OK) return retval; } /* Break on IVA mismatch */ cortex_a_set_breakpoint(target, &stepbreakpoint, 0x04); target->debug_reason = DBG_REASON_SINGLESTEP; retval = cortex_a_resume(target, 1, address, 0, 0); if (retval != ERROR_OK) return retval; int64_t then = timeval_ms(); while (target->state != TARGET_HALTED) { retval = cortex_a_poll(target); if (retval != ERROR_OK) return retval; if (target->state == TARGET_HALTED) break; if (timeval_ms() > then + 1000) { LOG_ERROR("timeout waiting for target halt"); return ERROR_FAIL; } } cortex_a_unset_breakpoint(target, &stepbreakpoint); /* Re-enable interrupts if they were disabled */ if (cortex_a->isrmasking_mode == CORTEX_A_ISRMASK_ON) { retval = cortex_a_set_dscr_bits(target, DSCR_INT_DIS, 0); if (retval != ERROR_OK) return retval; } target->debug_reason = DBG_REASON_BREAKPOINT; if (breakpoint) cortex_a_set_breakpoint(target, breakpoint, 0); if (target->state != TARGET_HALTED) LOG_DEBUG("target stepped"); return ERROR_OK; } static int cortex_a_restore_context(struct target *target, bool bpwp) { struct armv7a_common *armv7a = target_to_armv7a(target); LOG_DEBUG(" "); if (armv7a->pre_restore_context) armv7a->pre_restore_context(target); return arm_dpm_write_dirty_registers(&armv7a->dpm, bpwp); } /* * Cortex-A Breakpoint and watchpoint functions */ /* Setup hardware Breakpoint Register Pair */ static int cortex_a_set_breakpoint(struct target *target, struct breakpoint *breakpoint, uint8_t matchmode) { int retval; int brp_i = 0; uint32_t control; uint8_t byte_addr_select = 0x0F; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { while (brp_list[brp_i].used && (brp_i < cortex_a->brp_num)) brp_i++; if (brp_i >= cortex_a->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint_hw_set(breakpoint, brp_i); if (breakpoint->length == 2) byte_addr_select = (3 << (breakpoint->address & 0x02)); control = ((matchmode & 0x7) << 20) | (byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_i].used = true; brp_list[brp_i].value = (breakpoint->address & 0xFFFFFFFC); brp_list[brp_i].control = control; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; LOG_DEBUG("brp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); } else if (breakpoint->type == BKPT_SOFT) { uint8_t code[4]; /* length == 2: Thumb breakpoint */ if (breakpoint->length == 2) buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11)); else /* length == 3: Thumb-2 breakpoint, actual encoding is * a regular Thumb BKPT instruction but we replace a * 32bit Thumb-2 instruction, so fix-up the breakpoint * length */ if (breakpoint->length == 3) { buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11)); breakpoint->length = 4; } else /* length == 4, normal ARM breakpoint */ buf_set_u32(code, 0, 32, ARMV5_BKPT(0x11)); retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; /* make sure data cache is cleaned & invalidated down to PoC */ if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled) { armv7a_cache_flush_virt(target, breakpoint->address, breakpoint->length); } retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, code); if (retval != ERROR_OK) return retval; /* update i-cache at breakpoint location */ armv7a_l1_d_cache_inval_virt(target, breakpoint->address, breakpoint->length); armv7a_l1_i_cache_inval_virt(target, breakpoint->address, breakpoint->length); breakpoint->is_set = true; } return ERROR_OK; } static int cortex_a_set_context_breakpoint(struct target *target, struct breakpoint *breakpoint, uint8_t matchmode) { int retval = ERROR_FAIL; int brp_i = 0; uint32_t control; uint8_t byte_addr_select = 0x0F; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } /*check available context BRPs*/ while ((brp_list[brp_i].used || (brp_list[brp_i].type != BRP_CONTEXT)) && (brp_i < cortex_a->brp_num)) brp_i++; if (brp_i >= cortex_a->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; } breakpoint_hw_set(breakpoint, brp_i); control = ((matchmode & 0x7) << 20) | (byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_i].used = true; brp_list[brp_i].value = (breakpoint->asid); brp_list[brp_i].control = control; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; LOG_DEBUG("brp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); return ERROR_OK; } static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval = ERROR_FAIL; int brp_1 = 0; /* holds the contextID pair */ int brp_2 = 0; /* holds the IVA pair */ uint32_t control_ctx, control_iva; uint8_t ctx_byte_addr_select = 0x0F; uint8_t iva_byte_addr_select = 0x0F; uint8_t ctx_machmode = 0x03; uint8_t iva_machmode = 0x01; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } /*check available context BRPs*/ while ((brp_list[brp_1].used || (brp_list[brp_1].type != BRP_CONTEXT)) && (brp_1 < cortex_a->brp_num)) brp_1++; LOG_DEBUG("brp(CTX) found num: %d", brp_1); if (brp_1 >= cortex_a->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; } while ((brp_list[brp_2].used || (brp_list[brp_2].type != BRP_NORMAL)) && (brp_2 < cortex_a->brp_num)) brp_2++; LOG_DEBUG("brp(IVA) found num: %d", brp_2); if (brp_2 >= cortex_a->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; } breakpoint_hw_set(breakpoint, brp_1); breakpoint->linked_brp = brp_2; control_ctx = ((ctx_machmode & 0x7) << 20) | (brp_2 << 16) | (0 << 14) | (ctx_byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_1].used = true; brp_list[brp_1].value = (breakpoint->asid); brp_list[brp_1].control = control_ctx; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_1].brpn, brp_list[brp_1].value); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_1].brpn, brp_list[brp_1].control); if (retval != ERROR_OK) return retval; control_iva = ((iva_machmode & 0x7) << 20) | (brp_1 << 16) | (iva_byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_2].used = true; brp_list[brp_2].value = (breakpoint->address & 0xFFFFFFFC); brp_list[brp_2].control = control_iva; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_2].brpn, brp_list[brp_2].value); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_2].brpn, brp_list[brp_2].control); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { int brp_i = breakpoint->number; int brp_j = breakpoint->linked_brp; if (brp_i >= cortex_a->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); brp_list[brp_i].used = false; brp_list[brp_i].value = 0; brp_list[brp_i].control = 0; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; if ((brp_j < 0) || (brp_j >= cortex_a->brp_num)) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_j, brp_list[brp_j].control, brp_list[brp_j].value); brp_list[brp_j].used = false; brp_list[brp_j].value = 0; brp_list[brp_j].control = 0; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_j].brpn, brp_list[brp_j].control); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_j].brpn, brp_list[brp_j].value); if (retval != ERROR_OK) return retval; breakpoint->linked_brp = 0; breakpoint->is_set = false; return ERROR_OK; } else { int brp_i = breakpoint->number; if (brp_i >= cortex_a->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); brp_list[brp_i].used = false; brp_list[brp_i].value = 0; brp_list[brp_i].control = 0; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; breakpoint->is_set = false; return ERROR_OK; } } else { /* make sure data cache is cleaned & invalidated down to PoC */ if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled) { armv7a_cache_flush_virt(target, breakpoint->address, breakpoint->length); } /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } else { retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } /* update i-cache at breakpoint location */ armv7a_l1_d_cache_inval_virt(target, breakpoint->address, breakpoint->length); armv7a_l1_i_cache_inval_virt(target, breakpoint->address, breakpoint->length); } breakpoint->is_set = false; return ERROR_OK; } static int cortex_a_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); if ((breakpoint->type == BKPT_HARD) && (cortex_a->brp_num_available < 1)) { LOG_INFO("no hardware breakpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_HARD) cortex_a->brp_num_available--; return cortex_a_set_breakpoint(target, breakpoint, 0x00); /* Exact match */ } static int cortex_a_add_context_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); if ((breakpoint->type == BKPT_HARD) && (cortex_a->brp_num_available < 1)) { LOG_INFO("no hardware breakpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_HARD) cortex_a->brp_num_available--; return cortex_a_set_context_breakpoint(target, breakpoint, 0x02); /* asid match */ } static int cortex_a_add_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); if ((breakpoint->type == BKPT_HARD) && (cortex_a->brp_num_available < 1)) { LOG_INFO("no hardware breakpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_HARD) cortex_a->brp_num_available--; return cortex_a_set_hybrid_breakpoint(target, breakpoint); /* ??? */ } static int cortex_a_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); #if 0 /* It is perfectly possible to remove breakpoints while the target is running */ if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } #endif if (breakpoint->is_set) { cortex_a_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) cortex_a->brp_num_available++; } return ERROR_OK; } /** * Sets a watchpoint for an Cortex-A target in one of the watchpoint units. It is * considered a bug to call this function when there are no available watchpoint * units. * * @param target Pointer to an Cortex-A target to set a watchpoint on * @param watchpoint Pointer to the watchpoint to be set * @return Error status if watchpoint set fails or the result of executing the * JTAG queue */ static int cortex_a_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { int retval = ERROR_OK; int wrp_i = 0; uint32_t control; uint32_t address; uint8_t address_mask; uint8_t byte_address_select; uint8_t load_store_access_control = 0x3; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_wrp *wrp_list = cortex_a->wrp_list; if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return retval; } /* check available context WRPs */ while (wrp_list[wrp_i].used && (wrp_i < cortex_a->wrp_num)) wrp_i++; if (wrp_i >= cortex_a->wrp_num) { LOG_ERROR("ERROR Can not find free Watchpoint Register Pair"); return ERROR_FAIL; } if (watchpoint->length == 0 || watchpoint->length > 0x80000000U || (watchpoint->length & (watchpoint->length - 1))) { LOG_WARNING("watchpoint length must be a power of 2"); return ERROR_FAIL; } if (watchpoint->address & (watchpoint->length - 1)) { LOG_WARNING("watchpoint address must be aligned at length"); return ERROR_FAIL; } /* FIXME: ARM DDI 0406C: address_mask is optional. What to do if it's missing? */ /* handle wp length 1 and 2 through byte select */ switch (watchpoint->length) { case 1: byte_address_select = BIT(watchpoint->address & 0x3); address = watchpoint->address & ~0x3; address_mask = 0; break; case 2: byte_address_select = 0x03 << (watchpoint->address & 0x2); address = watchpoint->address & ~0x3; address_mask = 0; break; case 4: byte_address_select = 0x0f; address = watchpoint->address; address_mask = 0; break; default: byte_address_select = 0xff; address = watchpoint->address; address_mask = ilog2(watchpoint->length); break; } watchpoint_set(watchpoint, wrp_i); control = (address_mask << 24) | (byte_address_select << 5) | (load_store_access_control << 3) | (0x3 << 1) | 1; wrp_list[wrp_i].used = true; wrp_list[wrp_i].value = address; wrp_list[wrp_i].control = control; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_WVR_BASE + 4 * wrp_list[wrp_i].wrpn, wrp_list[wrp_i].value); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_WCR_BASE + 4 * wrp_list[wrp_i].wrpn, wrp_list[wrp_i].control); if (retval != ERROR_OK) return retval; LOG_DEBUG("wp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, wrp_i, wrp_list[wrp_i].control, wrp_list[wrp_i].value); return ERROR_OK; } /** * Unset an existing watchpoint and clear the used watchpoint unit. * * @param target Pointer to the target to have the watchpoint removed * @param watchpoint Pointer to the watchpoint to be removed * @return Error status while trying to unset the watchpoint or the result of * executing the JTAG queue */ static int cortex_a_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { int retval; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_wrp *wrp_list = cortex_a->wrp_list; if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } int wrp_i = watchpoint->number; if (wrp_i >= cortex_a->wrp_num) { LOG_DEBUG("Invalid WRP number in watchpoint"); return ERROR_OK; } LOG_DEBUG("wrp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, wrp_i, wrp_list[wrp_i].control, wrp_list[wrp_i].value); wrp_list[wrp_i].used = false; wrp_list[wrp_i].value = 0; wrp_list[wrp_i].control = 0; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_WCR_BASE + 4 * wrp_list[wrp_i].wrpn, wrp_list[wrp_i].control); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_WVR_BASE + 4 * wrp_list[wrp_i].wrpn, wrp_list[wrp_i].value); if (retval != ERROR_OK) return retval; watchpoint->is_set = false; return ERROR_OK; } /** * Add a watchpoint to an Cortex-A target. If there are no watchpoint units * available, an error response is returned. * * @param target Pointer to the Cortex-A target to add a watchpoint to * @param watchpoint Pointer to the watchpoint to be added * @return Error status while trying to add the watchpoint */ static int cortex_a_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); if (cortex_a->wrp_num_available < 1) { LOG_INFO("no hardware watchpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } int retval = cortex_a_set_watchpoint(target, watchpoint); if (retval != ERROR_OK) return retval; cortex_a->wrp_num_available--; return ERROR_OK; } /** * Remove a watchpoint from an Cortex-A target. The watchpoint will be unset and * the used watchpoint unit will be reopened. * * @param target Pointer to the target to remove a watchpoint from * @param watchpoint Pointer to the watchpoint to be removed * @return Result of trying to unset the watchpoint */ static int cortex_a_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); if (watchpoint->is_set) { cortex_a->wrp_num_available++; cortex_a_unset_watchpoint(target, watchpoint); } return ERROR_OK; } /* * Cortex-A Reset functions */ static int cortex_a_assert_reset(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); LOG_DEBUG(" "); /* FIXME when halt is requested, make it work somehow... */ /* This function can be called in "target not examined" state */ /* Issue some kind of warm reset. */ if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) target_handle_event(target, TARGET_EVENT_RESET_ASSERT); else if (jtag_get_reset_config() & RESET_HAS_SRST) { /* REVISIT handle "pulls" cases, if there's * hardware that needs them to work. */ /* * FIXME: fix reset when transport is not JTAG. This is a temporary * work-around for release v0.10 that is not intended to stay! */ if (!transport_is_jtag() || (target->reset_halt && (jtag_get_reset_config() & RESET_SRST_NO_GATING))) adapter_assert_reset(); } else { LOG_ERROR("%s: how to reset?", target_name(target)); return ERROR_FAIL; } /* registers are now invalid */ if (target_was_examined(target)) register_cache_invalidate(armv7a->arm.core_cache); target->state = TARGET_RESET; return ERROR_OK; } static int cortex_a_deassert_reset(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); int retval; LOG_DEBUG(" "); /* be certain SRST is off */ adapter_deassert_reset(); if (target_was_examined(target)) { retval = cortex_a_poll(target); if (retval != ERROR_OK) return retval; } if (target->reset_halt) { if (target->state != TARGET_HALTED) { LOG_WARNING("%s: ran after reset and before halt ...", target_name(target)); if (target_was_examined(target)) { retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_HALT); if (retval != ERROR_OK) return retval; } else target->state = TARGET_UNKNOWN; } } return ERROR_OK; } static int cortex_a_set_dcc_mode(struct target *target, uint32_t mode, uint32_t *dscr) { /* Changes the mode of the DCC between non-blocking, stall, and fast mode. * New desired mode must be in mode. Current value of DSCR must be in * *dscr, which is updated with new value. * * This function elides actually sending the mode-change over the debug * interface if the mode is already set as desired. */ uint32_t new_dscr = (*dscr & ~DSCR_EXT_DCC_MASK) | mode; if (new_dscr != *dscr) { struct armv7a_common *armv7a = target_to_armv7a(target); int retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, new_dscr); if (retval == ERROR_OK) *dscr = new_dscr; return retval; } else { return ERROR_OK; } } static int cortex_a_wait_dscr_bits(struct target *target, uint32_t mask, uint32_t value, uint32_t *dscr) { /* Waits until the specified bit(s) of DSCR take on a specified value. */ struct armv7a_common *armv7a = target_to_armv7a(target); int64_t then; int retval; if ((*dscr & mask) == value) return ERROR_OK; then = timeval_ms(); while (1) { retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); if (retval != ERROR_OK) { LOG_ERROR("Could not read DSCR register"); return retval; } if ((*dscr & mask) == value) break; if (timeval_ms() > then + 1000) { LOG_ERROR("timeout waiting for DSCR bit change"); return ERROR_FAIL; } } return ERROR_OK; } static int cortex_a_read_copro(struct target *target, uint32_t opcode, uint32_t *data, uint32_t *dscr) { int retval; struct armv7a_common *armv7a = target_to_armv7a(target); /* Move from coprocessor to R0. */ retval = cortex_a_exec_opcode(target, opcode, dscr); if (retval != ERROR_OK) return retval; /* Move from R0 to DTRTX. */ retval = cortex_a_exec_opcode(target, ARMV4_5_MCR(14, 0, 0, 0, 5, 0), dscr); if (retval != ERROR_OK) return retval; /* Wait until DTRTX is full (according to ARMv7-A/-R architecture * manual section C8.4.3, checking InstrCmpl_l is not sufficient; one * must also check TXfull_l). Most of the time this will be free * because TXfull_l will be set immediately and cached in dscr. */ retval = cortex_a_wait_dscr_bits(target, DSCR_DTRTX_FULL_LATCHED, DSCR_DTRTX_FULL_LATCHED, dscr); if (retval != ERROR_OK) return retval; /* Read the value transferred to DTRTX. */ retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, data); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int cortex_a_read_dfar_dfsr(struct target *target, uint32_t *dfar, uint32_t *dfsr, uint32_t *dscr) { int retval; if (dfar) { retval = cortex_a_read_copro(target, ARMV4_5_MRC(15, 0, 0, 6, 0, 0), dfar, dscr); if (retval != ERROR_OK) return retval; } if (dfsr) { retval = cortex_a_read_copro(target, ARMV4_5_MRC(15, 0, 0, 5, 0, 0), dfsr, dscr); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int cortex_a_write_copro(struct target *target, uint32_t opcode, uint32_t data, uint32_t *dscr) { int retval; struct armv7a_common *armv7a = target_to_armv7a(target); /* Write the value into DTRRX. */ retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, data); if (retval != ERROR_OK) return retval; /* Move from DTRRX to R0. */ retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), dscr); if (retval != ERROR_OK) return retval; /* Move from R0 to coprocessor. */ retval = cortex_a_exec_opcode(target, opcode, dscr); if (retval != ERROR_OK) return retval; /* Wait until DTRRX is empty (according to ARMv7-A/-R architecture manual * section C8.4.3, checking InstrCmpl_l is not sufficient; one must also * check RXfull_l). Most of the time this will be free because RXfull_l * will be cleared immediately and cached in dscr. */ retval = cortex_a_wait_dscr_bits(target, DSCR_DTRRX_FULL_LATCHED, 0, dscr); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int cortex_a_write_dfar_dfsr(struct target *target, uint32_t dfar, uint32_t dfsr, uint32_t *dscr) { int retval; retval = cortex_a_write_copro(target, ARMV4_5_MCR(15, 0, 0, 6, 0, 0), dfar, dscr); if (retval != ERROR_OK) return retval; retval = cortex_a_write_copro(target, ARMV4_5_MCR(15, 0, 0, 5, 0, 0), dfsr, dscr); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int cortex_a_dfsr_to_error_code(uint32_t dfsr) { uint32_t status, upper4; if (dfsr & (1 << 9)) { /* LPAE format. */ status = dfsr & 0x3f; upper4 = status >> 2; if (upper4 == 1 || upper4 == 2 || upper4 == 3 || upper4 == 15) return ERROR_TARGET_TRANSLATION_FAULT; else if (status == 33) return ERROR_TARGET_UNALIGNED_ACCESS; else return ERROR_TARGET_DATA_ABORT; } else { /* Normal format. */ status = ((dfsr >> 6) & 0x10) | (dfsr & 0xf); if (status == 1) return ERROR_TARGET_UNALIGNED_ACCESS; else if (status == 5 || status == 7 || status == 3 || status == 6 || status == 9 || status == 11 || status == 13 || status == 15) return ERROR_TARGET_TRANSLATION_FAULT; else return ERROR_TARGET_DATA_ABORT; } } static int cortex_a_write_cpu_memory_slow(struct target *target, uint32_t size, uint32_t count, const uint8_t *buffer, uint32_t *dscr) { /* Writes count objects of size size from *buffer. Old value of DSCR must * be in *dscr; updated to new value. This is slow because it works for * non-word-sized objects. Avoid unaligned accesses as they do not work * on memory address space without "Normal" attribute. If size == 4 and * the address is aligned, cortex_a_write_cpu_memory_fast should be * preferred. * Preconditions: * - Address is in R0. * - R0 is marked dirty. */ struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; int retval; /* Mark register R1 as dirty, to use for transferring data. */ arm_reg_current(arm, 1)->dirty = true; /* Switch to non-blocking mode if not already in that mode. */ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, dscr); if (retval != ERROR_OK) return retval; /* Go through the objects. */ while (count) { /* Write the value to store into DTRRX. */ uint32_t data, opcode; if (size == 1) data = *buffer; else if (size == 2) data = target_buffer_get_u16(target, buffer); else data = target_buffer_get_u32(target, buffer); retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, data); if (retval != ERROR_OK) return retval; /* Transfer the value from DTRRX to R1. */ retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 1, 0, 5, 0), dscr); if (retval != ERROR_OK) return retval; /* Write the value transferred to R1 into memory. */ if (size == 1) opcode = ARMV4_5_STRB_IP(1, 0); else if (size == 2) opcode = ARMV4_5_STRH_IP(1, 0); else opcode = ARMV4_5_STRW_IP(1, 0); retval = cortex_a_exec_opcode(target, opcode, dscr); if (retval != ERROR_OK) return retval; /* Check for faults and return early. */ if (*dscr & (DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE)) return ERROR_OK; /* A data fault is not considered a system failure. */ /* Wait until DTRRX is empty (according to ARMv7-A/-R architecture * manual section C8.4.3, checking InstrCmpl_l is not sufficient; one * must also check RXfull_l). Most of the time this will be free * because RXfull_l will be cleared immediately and cached in dscr. */ retval = cortex_a_wait_dscr_bits(target, DSCR_DTRRX_FULL_LATCHED, 0, dscr); if (retval != ERROR_OK) return retval; /* Advance. */ buffer += size; --count; } return ERROR_OK; } static int cortex_a_write_cpu_memory_fast(struct target *target, uint32_t count, const uint8_t *buffer, uint32_t *dscr) { /* Writes count objects of size 4 from *buffer. Old value of DSCR must be * in *dscr; updated to new value. This is fast but only works for * word-sized objects at aligned addresses. * Preconditions: * - Address is in R0 and must be a multiple of 4. * - R0 is marked dirty. */ struct armv7a_common *armv7a = target_to_armv7a(target); int retval; /* Switch to fast mode if not already in that mode. */ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_FAST_MODE, dscr); if (retval != ERROR_OK) return retval; /* Latch STC instruction. */ retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_ITR, ARMV4_5_STC(0, 1, 0, 1, 14, 5, 0, 4)); if (retval != ERROR_OK) return retval; /* Transfer all the data and issue all the instructions. */ return mem_ap_write_buf_noincr(armv7a->debug_ap, buffer, 4, count, armv7a->debug_base + CPUDBG_DTRRX); } static int cortex_a_write_cpu_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { /* Write memory through the CPU. */ int retval, final_retval; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; uint32_t dscr, orig_dfar, orig_dfsr, fault_dscr, fault_dfar, fault_dfsr; LOG_DEBUG("Writing CPU memory address 0x%" PRIx32 " size %" PRIu32 " count %" PRIu32, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!count) return ERROR_OK; /* Clear any abort. */ retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_CLEAR_EXCEPTIONS); if (retval != ERROR_OK) return retval; /* Read DSCR. */ retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; /* Switch to non-blocking mode if not already in that mode. */ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, &dscr); if (retval != ERROR_OK) return retval; /* Mark R0 as dirty. */ arm_reg_current(arm, 0)->dirty = true; /* Read DFAR and DFSR, as they will be modified in the event of a fault. */ retval = cortex_a_read_dfar_dfsr(target, &orig_dfar, &orig_dfsr, &dscr); if (retval != ERROR_OK) return retval; /* Get the memory address into R0. */ retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, address); if (retval != ERROR_OK) return retval; retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; if (size == 4 && (address % 4) == 0) { /* We are doing a word-aligned transfer, so use fast mode. */ retval = cortex_a_write_cpu_memory_fast(target, count, buffer, &dscr); } else { /* Use slow path. Adjust size for aligned accesses */ switch (address % 4) { case 1: case 3: count *= size; size = 1; break; case 2: if (size == 4) { count *= 2; size = 2; } case 0: default: break; } retval = cortex_a_write_cpu_memory_slow(target, size, count, buffer, &dscr); } final_retval = retval; /* Switch to non-blocking mode if not already in that mode. */ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, &dscr); if (final_retval == ERROR_OK) final_retval = retval; /* Wait for last issued instruction to complete. */ retval = cortex_a_wait_instrcmpl(target, &dscr, true); if (final_retval == ERROR_OK) final_retval = retval; /* Wait until DTRRX is empty (according to ARMv7-A/-R architecture manual * section C8.4.3, checking InstrCmpl_l is not sufficient; one must also * check RXfull_l). Most of the time this will be free because RXfull_l * will be cleared immediately and cached in dscr. However, don't do this * if there is fault, because then the instruction might not have completed * successfully. */ if (!(dscr & DSCR_STICKY_ABORT_PRECISE)) { retval = cortex_a_wait_dscr_bits(target, DSCR_DTRRX_FULL_LATCHED, 0, &dscr); if (retval != ERROR_OK) return retval; } /* If there were any sticky abort flags, clear them. */ if (dscr & (DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE)) { fault_dscr = dscr; mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_CLEAR_EXCEPTIONS); dscr &= ~(DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE); } else { fault_dscr = 0; } /* Handle synchronous data faults. */ if (fault_dscr & DSCR_STICKY_ABORT_PRECISE) { if (final_retval == ERROR_OK) { /* Final return value will reflect cause of fault. */ retval = cortex_a_read_dfar_dfsr(target, &fault_dfar, &fault_dfsr, &dscr); if (retval == ERROR_OK) { LOG_ERROR("data abort at 0x%08" PRIx32 ", dfsr = 0x%08" PRIx32, fault_dfar, fault_dfsr); final_retval = cortex_a_dfsr_to_error_code(fault_dfsr); } else final_retval = retval; } /* Fault destroyed DFAR/DFSR; restore them. */ retval = cortex_a_write_dfar_dfsr(target, orig_dfar, orig_dfsr, &dscr); if (retval != ERROR_OK) LOG_ERROR("error restoring dfar/dfsr - dscr = 0x%08" PRIx32, dscr); } /* Handle asynchronous data faults. */ if (fault_dscr & DSCR_STICKY_ABORT_IMPRECISE) { if (final_retval == ERROR_OK) /* No other error has been recorded so far, so keep this one. */ final_retval = ERROR_TARGET_DATA_ABORT; } /* If the DCC is nonempty, clear it. */ if (dscr & DSCR_DTRTX_FULL_LATCHED) { uint32_t dummy; retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, &dummy); if (final_retval == ERROR_OK) final_retval = retval; } if (dscr & DSCR_DTRRX_FULL_LATCHED) { retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 1, 0, 5, 0), &dscr); if (final_retval == ERROR_OK) final_retval = retval; } /* Done. */ return final_retval; } static int cortex_a_read_cpu_memory_slow(struct target *target, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t *dscr) { /* Reads count objects of size size into *buffer. Old value of DSCR must be * in *dscr; updated to new value. This is slow because it works for * non-word-sized objects. Avoid unaligned accesses as they do not work * on memory address space without "Normal" attribute. If size == 4 and * the address is aligned, cortex_a_read_cpu_memory_fast should be * preferred. * Preconditions: * - Address is in R0. * - R0 is marked dirty. */ struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; int retval; /* Mark register R1 as dirty, to use for transferring data. */ arm_reg_current(arm, 1)->dirty = true; /* Switch to non-blocking mode if not already in that mode. */ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, dscr); if (retval != ERROR_OK) return retval; /* Go through the objects. */ while (count) { /* Issue a load of the appropriate size to R1. */ uint32_t opcode, data; if (size == 1) opcode = ARMV4_5_LDRB_IP(1, 0); else if (size == 2) opcode = ARMV4_5_LDRH_IP(1, 0); else opcode = ARMV4_5_LDRW_IP(1, 0); retval = cortex_a_exec_opcode(target, opcode, dscr); if (retval != ERROR_OK) return retval; /* Issue a write of R1 to DTRTX. */ retval = cortex_a_exec_opcode(target, ARMV4_5_MCR(14, 0, 1, 0, 5, 0), dscr); if (retval != ERROR_OK) return retval; /* Check for faults and return early. */ if (*dscr & (DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE)) return ERROR_OK; /* A data fault is not considered a system failure. */ /* Wait until DTRTX is full (according to ARMv7-A/-R architecture * manual section C8.4.3, checking InstrCmpl_l is not sufficient; one * must also check TXfull_l). Most of the time this will be free * because TXfull_l will be set immediately and cached in dscr. */ retval = cortex_a_wait_dscr_bits(target, DSCR_DTRTX_FULL_LATCHED, DSCR_DTRTX_FULL_LATCHED, dscr); if (retval != ERROR_OK) return retval; /* Read the value transferred to DTRTX into the buffer. */ retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, &data); if (retval != ERROR_OK) return retval; if (size == 1) *buffer = (uint8_t) data; else if (size == 2) target_buffer_set_u16(target, buffer, (uint16_t) data); else target_buffer_set_u32(target, buffer, data); /* Advance. */ buffer += size; --count; } return ERROR_OK; } static int cortex_a_read_cpu_memory_fast(struct target *target, uint32_t count, uint8_t *buffer, uint32_t *dscr) { /* Reads count objects of size 4 into *buffer. Old value of DSCR must be in * *dscr; updated to new value. This is fast but only works for word-sized * objects at aligned addresses. * Preconditions: * - Address is in R0 and must be a multiple of 4. * - R0 is marked dirty. */ struct armv7a_common *armv7a = target_to_armv7a(target); uint32_t u32; int retval; /* Switch to non-blocking mode if not already in that mode. */ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, dscr); if (retval != ERROR_OK) return retval; /* Issue the LDC instruction via a write to ITR. */ retval = cortex_a_exec_opcode(target, ARMV4_5_LDC(0, 1, 0, 1, 14, 5, 0, 4), dscr); if (retval != ERROR_OK) return retval; count--; if (count > 0) { /* Switch to fast mode if not already in that mode. */ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_FAST_MODE, dscr); if (retval != ERROR_OK) return retval; /* Latch LDC instruction. */ retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_ITR, ARMV4_5_LDC(0, 1, 0, 1, 14, 5, 0, 4)); if (retval != ERROR_OK) return retval; /* Read the value transferred to DTRTX into the buffer. Due to fast * mode rules, this blocks until the instruction finishes executing and * then reissues the read instruction to read the next word from * memory. The last read of DTRTX in this call reads the second-to-last * word from memory and issues the read instruction for the last word. */ retval = mem_ap_read_buf_noincr(armv7a->debug_ap, buffer, 4, count, armv7a->debug_base + CPUDBG_DTRTX); if (retval != ERROR_OK) return retval; /* Advance. */ buffer += count * 4; } /* Wait for last issued instruction to complete. */ retval = cortex_a_wait_instrcmpl(target, dscr, false); if (retval != ERROR_OK) return retval; /* Switch to non-blocking mode if not already in that mode. */ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, dscr); if (retval != ERROR_OK) return retval; /* Check for faults and return early. */ if (*dscr & (DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE)) return ERROR_OK; /* A data fault is not considered a system failure. */ /* Wait until DTRTX is full (according to ARMv7-A/-R architecture manual * section C8.4.3, checking InstrCmpl_l is not sufficient; one must also * check TXfull_l). Most of the time this will be free because TXfull_l * will be set immediately and cached in dscr. */ retval = cortex_a_wait_dscr_bits(target, DSCR_DTRTX_FULL_LATCHED, DSCR_DTRTX_FULL_LATCHED, dscr); if (retval != ERROR_OK) return retval; /* Read the value transferred to DTRTX into the buffer. This is the last * word. */ retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, &u32); if (retval != ERROR_OK) return retval; target_buffer_set_u32(target, buffer, u32); return ERROR_OK; } static int cortex_a_read_cpu_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { /* Read memory through the CPU. */ int retval, final_retval; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; uint32_t dscr, orig_dfar, orig_dfsr, fault_dscr, fault_dfar, fault_dfsr; LOG_DEBUG("Reading CPU memory address 0x%" PRIx32 " size %" PRIu32 " count %" PRIu32, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!count) return ERROR_OK; /* Clear any abort. */ retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_CLEAR_EXCEPTIONS); if (retval != ERROR_OK) return retval; /* Read DSCR */ retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; /* Switch to non-blocking mode if not already in that mode. */ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, &dscr); if (retval != ERROR_OK) return retval; /* Mark R0 as dirty. */ arm_reg_current(arm, 0)->dirty = true; /* Read DFAR and DFSR, as they will be modified in the event of a fault. */ retval = cortex_a_read_dfar_dfsr(target, &orig_dfar, &orig_dfsr, &dscr); if (retval != ERROR_OK) return retval; /* Get the memory address into R0. */ retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, address); if (retval != ERROR_OK) return retval; retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; if (size == 4 && (address % 4) == 0) { /* We are doing a word-aligned transfer, so use fast mode. */ retval = cortex_a_read_cpu_memory_fast(target, count, buffer, &dscr); } else { /* Use slow path. Adjust size for aligned accesses */ switch (address % 4) { case 1: case 3: count *= size; size = 1; break; case 2: if (size == 4) { count *= 2; size = 2; } break; case 0: default: break; } retval = cortex_a_read_cpu_memory_slow(target, size, count, buffer, &dscr); } final_retval = retval; /* Switch to non-blocking mode if not already in that mode. */ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, &dscr); if (final_retval == ERROR_OK) final_retval = retval; /* Wait for last issued instruction to complete. */ retval = cortex_a_wait_instrcmpl(target, &dscr, true); if (final_retval == ERROR_OK) final_retval = retval; /* If there were any sticky abort flags, clear them. */ if (dscr & (DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE)) { fault_dscr = dscr; mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_CLEAR_EXCEPTIONS); dscr &= ~(DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE); } else { fault_dscr = 0; } /* Handle synchronous data faults. */ if (fault_dscr & DSCR_STICKY_ABORT_PRECISE) { if (final_retval == ERROR_OK) { /* Final return value will reflect cause of fault. */ retval = cortex_a_read_dfar_dfsr(target, &fault_dfar, &fault_dfsr, &dscr); if (retval == ERROR_OK) { LOG_ERROR("data abort at 0x%08" PRIx32 ", dfsr = 0x%08" PRIx32, fault_dfar, fault_dfsr); final_retval = cortex_a_dfsr_to_error_code(fault_dfsr); } else final_retval = retval; } /* Fault destroyed DFAR/DFSR; restore them. */ retval = cortex_a_write_dfar_dfsr(target, orig_dfar, orig_dfsr, &dscr); if (retval != ERROR_OK) LOG_ERROR("error restoring dfar/dfsr - dscr = 0x%08" PRIx32, dscr); } /* Handle asynchronous data faults. */ if (fault_dscr & DSCR_STICKY_ABORT_IMPRECISE) { if (final_retval == ERROR_OK) /* No other error has been recorded so far, so keep this one. */ final_retval = ERROR_TARGET_DATA_ABORT; } /* If the DCC is nonempty, clear it. */ if (dscr & DSCR_DTRTX_FULL_LATCHED) { uint32_t dummy; retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, &dummy); if (final_retval == ERROR_OK) final_retval = retval; } if (dscr & DSCR_DTRRX_FULL_LATCHED) { retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 1, 0, 5, 0), &dscr); if (final_retval == ERROR_OK) final_retval = retval; } /* Done. */ return final_retval; } /* * Cortex-A Memory access * * This is same Cortex-M3 but we must also use the correct * ap number for every access. */ static int cortex_a_read_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; LOG_DEBUG("Reading memory at real address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); /* read memory through the CPU */ cortex_a_prep_memaccess(target, 1); retval = cortex_a_read_cpu_memory(target, address, size, count, buffer); cortex_a_post_memaccess(target, 1); return retval; } static int cortex_a_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; /* cortex_a handles unaligned memory access */ LOG_DEBUG("Reading memory at address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); cortex_a_prep_memaccess(target, 0); retval = cortex_a_read_cpu_memory(target, address, size, count, buffer); cortex_a_post_memaccess(target, 0); return retval; } static int cortex_a_write_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; LOG_DEBUG("Writing memory to real address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); /* write memory through the CPU */ cortex_a_prep_memaccess(target, 1); retval = cortex_a_write_cpu_memory(target, address, size, count, buffer); cortex_a_post_memaccess(target, 1); return retval; } static int cortex_a_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; /* cortex_a handles unaligned memory access */ LOG_DEBUG("Writing memory at address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); /* memory writes bypass the caches, must flush before writing */ armv7a_cache_auto_flush_on_write(target, address, size * count); cortex_a_prep_memaccess(target, 0); retval = cortex_a_write_cpu_memory(target, address, size, count, buffer); cortex_a_post_memaccess(target, 0); return retval; } static int cortex_a_read_buffer(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer) { uint32_t size; /* Align up to maximum 4 bytes. The loop condition makes sure the next pass * will have something to do with the size we leave to it. */ for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) { if (address & size) { int retval = target_read_memory(target, address, size, 1, buffer); if (retval != ERROR_OK) return retval; address += size; count -= size; buffer += size; } } /* Read the data with as large access size as possible. */ for (; size > 0; size /= 2) { uint32_t aligned = count - count % size; if (aligned > 0) { int retval = target_read_memory(target, address, size, aligned / size, buffer); if (retval != ERROR_OK) return retval; address += aligned; count -= aligned; buffer += aligned; } } return ERROR_OK; } static int cortex_a_write_buffer(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer) { uint32_t size; /* Align up to maximum 4 bytes. The loop condition makes sure the next pass * will have something to do with the size we leave to it. */ for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) { if (address & size) { int retval = target_write_memory(target, address, size, 1, buffer); if (retval != ERROR_OK) return retval; address += size; count -= size; buffer += size; } } /* Write the data with as large access size as possible. */ for (; size > 0; size /= 2) { uint32_t aligned = count - count % size; if (aligned > 0) { int retval = target_write_memory(target, address, size, aligned / size, buffer); if (retval != ERROR_OK) return retval; address += aligned; count -= aligned; buffer += aligned; } } return ERROR_OK; } static int cortex_a_handle_target_request(void *priv) { struct target *target = priv; struct armv7a_common *armv7a = target_to_armv7a(target); int retval; if (!target_was_examined(target)) return ERROR_OK; if (!target->dbg_msg_enabled) return ERROR_OK; if (target->state == TARGET_RUNNING) { uint32_t request; uint32_t dscr; retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); /* check if we have data */ int64_t then = timeval_ms(); while ((dscr & DSCR_DTR_TX_FULL) && (retval == ERROR_OK)) { retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, &request); if (retval == ERROR_OK) { target_request(target, request); retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); } if (timeval_ms() > then + 1000) { LOG_ERROR("Timeout waiting for dtr tx full"); return ERROR_FAIL; } } } return ERROR_OK; } /* * Cortex-A target information and configuration */ static int cortex_a_examine_first(struct target *target) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct adiv5_dap *swjdp = armv7a->arm.dap; struct adiv5_private_config *pc = target->private_config; int i; int retval = ERROR_OK; uint32_t didr, cpuid, dbg_osreg, dbg_idpfr1; if (!armv7a->debug_ap) { if (pc->ap_num == DP_APSEL_INVALID) { /* Search for the APB-AP - it is needed for access to debug registers */ retval = dap_find_get_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap); if (retval != ERROR_OK) { LOG_ERROR("Could not find APB-AP for debug access"); return retval; } } else { armv7a->debug_ap = dap_get_ap(swjdp, pc->ap_num); if (!armv7a->debug_ap) { LOG_ERROR("Cannot get AP"); return ERROR_FAIL; } } } retval = mem_ap_init(armv7a->debug_ap); if (retval != ERROR_OK) { LOG_ERROR("Could not initialize the APB-AP"); return retval; } armv7a->debug_ap->memaccess_tck = 80; if (!target->dbgbase_set) { LOG_DEBUG("%s's dbgbase is not set, trying to detect using the ROM table", target->cmd_name); /* Lookup Processor DAP */ retval = dap_lookup_cs_component(armv7a->debug_ap, ARM_CS_C9_DEVTYPE_CORE_DEBUG, &armv7a->debug_base, target->coreid); if (retval != ERROR_OK) { LOG_ERROR("Can't detect %s's dbgbase from the ROM table; you need to specify it explicitly.", target->cmd_name); return retval; } LOG_DEBUG("Detected core %" PRId32 " dbgbase: " TARGET_ADDR_FMT, target->coreid, armv7a->debug_base); } else armv7a->debug_base = target->dbgbase; if ((armv7a->debug_base & (1UL<<31)) == 0) LOG_WARNING("Debug base address for target %s has bit 31 set to 0. Access to debug registers will likely fail!\n" "Please fix the target configuration.", target_name(target)); retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DIDR, &didr); if (retval != ERROR_OK) { LOG_DEBUG("Examine %s failed", "DIDR"); return retval; } retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_CPUID, &cpuid); if (retval != ERROR_OK) { LOG_DEBUG("Examine %s failed", "CPUID"); return retval; } LOG_DEBUG("didr = 0x%08" PRIx32, didr); LOG_DEBUG("cpuid = 0x%08" PRIx32, cpuid); cortex_a->didr = didr; cortex_a->cpuid = cpuid; retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_PRSR, &dbg_osreg); if (retval != ERROR_OK) return retval; LOG_DEBUG("target->coreid %" PRId32 " DBGPRSR 0x%" PRIx32, target->coreid, dbg_osreg); if ((dbg_osreg & PRSR_POWERUP_STATUS) == 0) { LOG_ERROR("target->coreid %" PRId32 " powered down!", target->coreid); target->state = TARGET_UNKNOWN; /* TARGET_NO_POWER? */ return ERROR_TARGET_INIT_FAILED; } if (dbg_osreg & PRSR_STICKY_RESET_STATUS) LOG_DEBUG("target->coreid %" PRId32 " was reset!", target->coreid); /* Read DBGOSLSR and check if OSLK is implemented */ retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_OSLSR, &dbg_osreg); if (retval != ERROR_OK) return retval; LOG_DEBUG("target->coreid %" PRId32 " DBGOSLSR 0x%" PRIx32, target->coreid, dbg_osreg); /* check if OS Lock is implemented */ if ((dbg_osreg & OSLSR_OSLM) == OSLSR_OSLM0 || (dbg_osreg & OSLSR_OSLM) == OSLSR_OSLM1) { /* check if OS Lock is set */ if (dbg_osreg & OSLSR_OSLK) { LOG_DEBUG("target->coreid %" PRId32 " OSLock set! Trying to unlock", target->coreid); retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_OSLAR, 0); if (retval == ERROR_OK) retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_OSLSR, &dbg_osreg); /* if we fail to access the register or cannot reset the OSLK bit, bail out */ if (retval != ERROR_OK || (dbg_osreg & OSLSR_OSLK) != 0) { LOG_ERROR("target->coreid %" PRId32 " OSLock sticky, core not powered?", target->coreid); target->state = TARGET_UNKNOWN; /* TARGET_NO_POWER? */ return ERROR_TARGET_INIT_FAILED; } } } retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_ID_PFR1, &dbg_idpfr1); if (retval != ERROR_OK) return retval; if (dbg_idpfr1 & 0x000000f0) { LOG_DEBUG("target->coreid %" PRId32 " has security extensions", target->coreid); armv7a->arm.core_type = ARM_CORE_TYPE_SEC_EXT; } if (dbg_idpfr1 & 0x0000f000) { LOG_DEBUG("target->coreid %" PRId32 " has virtualization extensions", target->coreid); /* * overwrite and simplify the checks. * virtualization extensions require implementation of security extension */ armv7a->arm.core_type = ARM_CORE_TYPE_VIRT_EXT; } /* Avoid recreating the registers cache */ if (!target_was_examined(target)) { retval = cortex_a_dpm_setup(cortex_a, didr); if (retval != ERROR_OK) return retval; } /* Setup Breakpoint Register Pairs */ cortex_a->brp_num = ((didr >> 24) & 0x0F) + 1; cortex_a->brp_num_context = ((didr >> 20) & 0x0F) + 1; cortex_a->brp_num_available = cortex_a->brp_num; free(cortex_a->brp_list); cortex_a->brp_list = calloc(cortex_a->brp_num, sizeof(struct cortex_a_brp)); /* cortex_a->brb_enabled = ????; */ for (i = 0; i < cortex_a->brp_num; i++) { cortex_a->brp_list[i].used = false; if (i < (cortex_a->brp_num-cortex_a->brp_num_context)) cortex_a->brp_list[i].type = BRP_NORMAL; else cortex_a->brp_list[i].type = BRP_CONTEXT; cortex_a->brp_list[i].value = 0; cortex_a->brp_list[i].control = 0; cortex_a->brp_list[i].brpn = i; } LOG_DEBUG("Configured %i hw breakpoints", cortex_a->brp_num); /* Setup Watchpoint Register Pairs */ cortex_a->wrp_num = ((didr >> 28) & 0x0F) + 1; cortex_a->wrp_num_available = cortex_a->wrp_num; free(cortex_a->wrp_list); cortex_a->wrp_list = calloc(cortex_a->wrp_num, sizeof(struct cortex_a_wrp)); for (i = 0; i < cortex_a->wrp_num; i++) { cortex_a->wrp_list[i].used = false; cortex_a->wrp_list[i].value = 0; cortex_a->wrp_list[i].control = 0; cortex_a->wrp_list[i].wrpn = i; } LOG_DEBUG("Configured %i hw watchpoints", cortex_a->wrp_num); /* select debug_ap as default */ swjdp->apsel = armv7a->debug_ap->ap_num; target_set_examined(target); return ERROR_OK; } static int cortex_a_examine(struct target *target) { int retval = ERROR_OK; /* Reestablish communication after target reset */ retval = cortex_a_examine_first(target); /* Configure core debug access */ if (retval == ERROR_OK) retval = cortex_a_init_debug_access(target); return retval; } /* * Cortex-A target creation and initialization */ static int cortex_a_init_target(struct command_context *cmd_ctx, struct target *target) { /* examine_first() does a bunch of this */ arm_semihosting_init(target); return ERROR_OK; } static int cortex_a_init_arch_info(struct target *target, struct cortex_a_common *cortex_a, struct adiv5_dap *dap) { struct armv7a_common *armv7a = &cortex_a->armv7a_common; /* Setup struct cortex_a_common */ cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; armv7a->arm.dap = dap; /* register arch-specific functions */ armv7a->examine_debug_reason = NULL; armv7a->post_debug_entry = cortex_a_post_debug_entry; armv7a->pre_restore_context = NULL; armv7a->armv7a_mmu.read_physical_memory = cortex_a_read_phys_memory; /* arm7_9->handle_target_request = cortex_a_handle_target_request; */ /* REVISIT v7a setup should be in a v7a-specific routine */ armv7a_init_arch_info(target, armv7a); target_register_timer_callback(cortex_a_handle_target_request, 1, TARGET_TIMER_TYPE_PERIODIC, target); return ERROR_OK; } static int cortex_a_target_create(struct target *target, Jim_Interp *interp) { struct cortex_a_common *cortex_a; struct adiv5_private_config *pc; if (!target->private_config) return ERROR_FAIL; pc = (struct adiv5_private_config *)target->private_config; cortex_a = calloc(1, sizeof(struct cortex_a_common)); if (!cortex_a) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; cortex_a->armv7a_common.is_armv7r = false; cortex_a->armv7a_common.arm.arm_vfp_version = ARM_VFP_V3; return cortex_a_init_arch_info(target, cortex_a, pc->dap); } static int cortex_r4_target_create(struct target *target, Jim_Interp *interp) { struct cortex_a_common *cortex_a; struct adiv5_private_config *pc; pc = (struct adiv5_private_config *)target->private_config; if (adiv5_verify_config(pc) != ERROR_OK) return ERROR_FAIL; cortex_a = calloc(1, sizeof(struct cortex_a_common)); if (!cortex_a) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; cortex_a->armv7a_common.is_armv7r = true; return cortex_a_init_arch_info(target, cortex_a, pc->dap); } static void cortex_a_deinit_target(struct target *target) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct arm_dpm *dpm = &armv7a->dpm; uint32_t dscr; int retval; if (target_was_examined(target)) { /* Disable halt for breakpoint, watchpoint and vector catch */ retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval == ERROR_OK) mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr & ~DSCR_HALT_DBG_MODE); } if (armv7a->debug_ap) dap_put_ap(armv7a->debug_ap); free(cortex_a->wrp_list); free(cortex_a->brp_list); arm_free_reg_cache(dpm->arm); free(dpm->dbp); free(dpm->dwp); free(target->private_config); free(cortex_a); } static int cortex_a_mmu(struct target *target, int *enabled) { struct armv7a_common *armv7a = target_to_armv7a(target); if (target->state != TARGET_HALTED) { LOG_ERROR("%s: target not halted", __func__); return ERROR_TARGET_INVALID; } if (armv7a->is_armv7r) *enabled = 0; else *enabled = target_to_cortex_a(target)->armv7a_common.armv7a_mmu.mmu_enabled; return ERROR_OK; } static int cortex_a_virt2phys(struct target *target, target_addr_t virt, target_addr_t *phys) { int retval; int mmu_enabled = 0; /* * If the MMU was not enabled at debug entry, there is no * way of knowing if there was ever a valid configuration * for it and thus it's not safe to enable it. In this case, * just return the virtual address as physical. */ cortex_a_mmu(target, &mmu_enabled); if (!mmu_enabled) { *phys = virt; return ERROR_OK; } /* mmu must be enable in order to get a correct translation */ retval = cortex_a_mmu_modify(target, 1); if (retval != ERROR_OK) return retval; return armv7a_mmu_translate_va_pa(target, (uint32_t)virt, phys, 1); } COMMAND_HANDLER(cortex_a_handle_cache_info_command) { struct target *target = get_current_target(CMD_CTX); struct armv7a_common *armv7a = target_to_armv7a(target); return armv7a_handle_cache_info_command(CMD, &armv7a->armv7a_mmu.armv7a_cache); } COMMAND_HANDLER(cortex_a_handle_dbginit_command) { struct target *target = get_current_target(CMD_CTX); if (!target_was_examined(target)) { LOG_ERROR("target not examined yet"); return ERROR_FAIL; } return cortex_a_init_debug_access(target); } COMMAND_HANDLER(handle_cortex_a_mask_interrupts_command) { struct target *target = get_current_target(CMD_CTX); struct cortex_a_common *cortex_a = target_to_cortex_a(target); static const struct nvp nvp_maskisr_modes[] = { { .name = "off", .value = CORTEX_A_ISRMASK_OFF }, { .name = "on", .value = CORTEX_A_ISRMASK_ON }, { .name = NULL, .value = -1 }, }; const struct nvp *n; if (CMD_ARGC > 0) { n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]); if (!n->name) { LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; } cortex_a->isrmasking_mode = n->value; } n = nvp_value2name(nvp_maskisr_modes, cortex_a->isrmasking_mode); command_print(CMD, "cortex_a interrupt mask %s", n->name); return ERROR_OK; } COMMAND_HANDLER(handle_cortex_a_dacrfixup_command) { struct target *target = get_current_target(CMD_CTX); struct cortex_a_common *cortex_a = target_to_cortex_a(target); static const struct nvp nvp_dacrfixup_modes[] = { { .name = "off", .value = CORTEX_A_DACRFIXUP_OFF }, { .name = "on", .value = CORTEX_A_DACRFIXUP_ON }, { .name = NULL, .value = -1 }, }; const struct nvp *n; if (CMD_ARGC > 0) { n = nvp_name2value(nvp_dacrfixup_modes, CMD_ARGV[0]); if (!n->name) return ERROR_COMMAND_SYNTAX_ERROR; cortex_a->dacrfixup_mode = n->value; } n = nvp_value2name(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode); command_print(CMD, "cortex_a domain access control fixup %s", n->name); return ERROR_OK; } static const struct command_registration cortex_a_exec_command_handlers[] = { { .name = "cache_info", .handler = cortex_a_handle_cache_info_command, .mode = COMMAND_EXEC, .help = "display information about target caches", .usage = "", }, { .name = "dbginit", .handler = cortex_a_handle_dbginit_command, .mode = COMMAND_EXEC, .help = "Initialize core debug", .usage = "", }, { .name = "maskisr", .handler = handle_cortex_a_mask_interrupts_command, .mode = COMMAND_ANY, .help = "mask cortex_a interrupts", .usage = "['on'|'off']", }, { .name = "dacrfixup", .handler = handle_cortex_a_dacrfixup_command, .mode = COMMAND_ANY, .help = "set domain access control (DACR) to all-manager " "on memory access", .usage = "['on'|'off']", }, { .chain = armv7a_mmu_command_handlers, }, { .chain = smp_command_handlers, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration cortex_a_command_handlers[] = { { .chain = arm_command_handlers, }, { .chain = armv7a_command_handlers, }, { .name = "cortex_a", .mode = COMMAND_ANY, .help = "Cortex-A command group", .usage = "", .chain = cortex_a_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type cortexa_target = { .name = "cortex_a", .poll = cortex_a_poll, .arch_state = armv7a_arch_state, .halt = cortex_a_halt, .resume = cortex_a_resume, .step = cortex_a_step, .assert_reset = cortex_a_assert_reset, .deassert_reset = cortex_a_deassert_reset, /* REVISIT allow exporting VFP3 registers ... */ .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = cortex_a_read_memory, .write_memory = cortex_a_write_memory, .read_buffer = cortex_a_read_buffer, .write_buffer = cortex_a_write_buffer, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = cortex_a_add_breakpoint, .add_context_breakpoint = cortex_a_add_context_breakpoint, .add_hybrid_breakpoint = cortex_a_add_hybrid_breakpoint, .remove_breakpoint = cortex_a_remove_breakpoint, .add_watchpoint = cortex_a_add_watchpoint, .remove_watchpoint = cortex_a_remove_watchpoint, .commands = cortex_a_command_handlers, .target_create = cortex_a_target_create, .target_jim_configure = adiv5_jim_configure, .init_target = cortex_a_init_target, .examine = cortex_a_examine, .deinit_target = cortex_a_deinit_target, .read_phys_memory = cortex_a_read_phys_memory, .write_phys_memory = cortex_a_write_phys_memory, .mmu = cortex_a_mmu, .virt2phys = cortex_a_virt2phys, }; static const struct command_registration cortex_r4_exec_command_handlers[] = { { .name = "dbginit", .handler = cortex_a_handle_dbginit_command, .mode = COMMAND_EXEC, .help = "Initialize core debug", .usage = "", }, { .name = "maskisr", .handler = handle_cortex_a_mask_interrupts_command, .mode = COMMAND_EXEC, .help = "mask cortex_r4 interrupts", .usage = "['on'|'off']", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration cortex_r4_command_handlers[] = { { .chain = arm_command_handlers, }, { .name = "cortex_r4", .mode = COMMAND_ANY, .help = "Cortex-R4 command group", .usage = "", .chain = cortex_r4_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type cortexr4_target = { .name = "cortex_r4", .poll = cortex_a_poll, .arch_state = armv7a_arch_state, .halt = cortex_a_halt, .resume = cortex_a_resume, .step = cortex_a_step, .assert_reset = cortex_a_assert_reset, .deassert_reset = cortex_a_deassert_reset, /* REVISIT allow exporting VFP3 registers ... */ .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = cortex_a_read_phys_memory, .write_memory = cortex_a_write_phys_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = cortex_a_add_breakpoint, .add_context_breakpoint = cortex_a_add_context_breakpoint, .add_hybrid_breakpoint = cortex_a_add_hybrid_breakpoint, .remove_breakpoint = cortex_a_remove_breakpoint, .add_watchpoint = cortex_a_add_watchpoint, .remove_watchpoint = cortex_a_remove_watchpoint, .commands = cortex_r4_command_handlers, .target_create = cortex_r4_target_create, .target_jim_configure = adiv5_jim_configure, .init_target = cortex_a_init_target, .examine = cortex_a_examine, .deinit_target = cortex_a_deinit_target, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/cortex_a.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2009 by Dirk Behme * * dirk.behme@gmail.com - copy from cortex_m3 * ***************************************************************************/ #ifndef OPENOCD_TARGET_CORTEX_A_H #define OPENOCD_TARGET_CORTEX_A_H #include "armv7a.h" #define CORTEX_A_COMMON_MAGIC 0x411fc082U #define CORTEX_A5_PARTNUM 0xc05 #define CORTEX_A7_PARTNUM 0xc07 #define CORTEX_A8_PARTNUM 0xc08 #define CORTEX_A9_PARTNUM 0xc09 #define CORTEX_A15_PARTNUM 0xc0f #define CORTEX_A_MIDR_PARTNUM_MASK 0x0000fff0 #define CORTEX_A_MIDR_PARTNUM_SHIFT 4 #define CPUDBG_CPUID 0xD00 #define CPUDBG_CTYPR 0xD04 #define CPUDBG_TTYPR 0xD0C #define CPUDBG_LOCKACCESS 0xFB0 #define CPUDBG_LOCKSTATUS 0xFB4 #define CPUDBG_OSLAR_LK_MASK (1 << 1) #define BRP_NORMAL 0 #define BRP_CONTEXT 1 #define CORTEX_A_PADDRDBG_CPU_SHIFT 13 enum cortex_a_isrmasking_mode { CORTEX_A_ISRMASK_OFF, CORTEX_A_ISRMASK_ON, }; enum cortex_a_dacrfixup_mode { CORTEX_A_DACRFIXUP_OFF, CORTEX_A_DACRFIXUP_ON }; struct cortex_a_brp { bool used; int type; uint32_t value; uint32_t control; uint8_t brpn; }; struct cortex_a_wrp { bool used; uint32_t value; uint32_t control; uint8_t wrpn; }; struct cortex_a_common { unsigned int common_magic; struct armv7a_common armv7a_common; /* Context information */ uint32_t cpudbg_dscr; /* Saved cp15 registers */ uint32_t cp15_control_reg; /* latest cp15 register value written and cpsr processor mode */ uint32_t cp15_control_reg_curr; /* auxiliary control reg */ uint32_t cp15_aux_control_reg; /* DACR */ uint32_t cp15_dacr_reg; enum arm_mode curr_mode; /* Breakpoint register pairs */ int brp_num_context; int brp_num; int brp_num_available; struct cortex_a_brp *brp_list; int wrp_num; int wrp_num_available; struct cortex_a_wrp *wrp_list; uint32_t cpuid; uint32_t didr; enum cortex_a_isrmasking_mode isrmasking_mode; enum cortex_a_dacrfixup_mode dacrfixup_mode; }; static inline struct cortex_a_common * target_to_cortex_a(struct target *target) { return container_of(target->arch_info, struct cortex_a_common, armv7a_common.arm); } #endif /* OPENOCD_TARGET_CORTEX_A_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/cortex_m.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * * * Cortex-M3(tm) TRM, ARM DDI 0337E (r1p1) and 0337G (r2p0) * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/interface.h" #include "breakpoints.h" #include "cortex_m.h" #include "target_request.h" #include "target_type.h" #include "arm_adi_v5.h" #include "arm_disassembler.h" #include "register.h" #include "arm_opcodes.h" #include "arm_semihosting.h" #include "smp.h" #include <helper/nvp.h> #include <helper/time_support.h> #include <rtt/rtt.h> /* NOTE: most of this should work fine for the Cortex-M1 and * Cortex-M0 cores too, although they're ARMv6-M not ARMv7-M. * Some differences: M0/M1 doesn't have FPB remapping or the * DWT tracing/profiling support. (So the cycle counter will * not be usable; the other stuff isn't currently used here.) * * Although there are some workarounds for errata seen only in r0p0 * silicon, such old parts are hard to find and thus not much tested * any longer. */ /* Timeout for register r/w */ #define DHCSR_S_REGRDY_TIMEOUT (500) /* Supported Cortex-M Cores */ static const struct cortex_m_part_info cortex_m_parts[] = { { .partno = CORTEX_M0_PARTNO, .name = "Cortex-M0", .arch = ARM_ARCH_V6M, }, { .partno = CORTEX_M0P_PARTNO, .name = "Cortex-M0+", .arch = ARM_ARCH_V6M, }, { .partno = CORTEX_M1_PARTNO, .name = "Cortex-M1", .arch = ARM_ARCH_V6M, }, { .partno = CORTEX_M3_PARTNO, .name = "Cortex-M3", .arch = ARM_ARCH_V7M, .flags = CORTEX_M_F_TAR_AUTOINCR_BLOCK_4K, }, { .partno = CORTEX_M4_PARTNO, .name = "Cortex-M4", .arch = ARM_ARCH_V7M, .flags = CORTEX_M_F_HAS_FPV4 | CORTEX_M_F_TAR_AUTOINCR_BLOCK_4K, }, { .partno = CORTEX_M7_PARTNO, .name = "Cortex-M7", .arch = ARM_ARCH_V7M, .flags = CORTEX_M_F_HAS_FPV5, }, { .partno = CORTEX_M23_PARTNO, .name = "Cortex-M23", .arch = ARM_ARCH_V8M, }, { .partno = CORTEX_M33_PARTNO, .name = "Cortex-M33", .arch = ARM_ARCH_V8M, .flags = CORTEX_M_F_HAS_FPV5, }, { .partno = CORTEX_M35P_PARTNO, .name = "Cortex-M35P", .arch = ARM_ARCH_V8M, .flags = CORTEX_M_F_HAS_FPV5, }, { .partno = CORTEX_M55_PARTNO, .name = "Cortex-M55", .arch = ARM_ARCH_V8M, .flags = CORTEX_M_F_HAS_FPV5, }, { .partno = STAR_MC1_PARTNO, .name = "STAR-MC1", .arch = ARM_ARCH_V8M, .flags = CORTEX_M_F_HAS_FPV5, }, }; /* forward declarations */ static int cortex_m_store_core_reg_u32(struct target *target, uint32_t num, uint32_t value); static void cortex_m_dwt_free(struct target *target); /** DCB DHCSR register contains S_RETIRE_ST and S_RESET_ST bits cleared * on a read. Call this helper function each time DHCSR is read * to preserve S_RESET_ST state in case of a reset event was detected. */ static inline void cortex_m_cumulate_dhcsr_sticky(struct cortex_m_common *cortex_m, uint32_t dhcsr) { cortex_m->dcb_dhcsr_cumulated_sticky |= dhcsr; } /** Read DCB DHCSR register to cortex_m->dcb_dhcsr and cumulate * sticky bits in cortex_m->dcb_dhcsr_cumulated_sticky */ static int cortex_m_read_dhcsr_atomic_sticky(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = target_to_armv7m(target); int retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); if (retval != ERROR_OK) return retval; cortex_m_cumulate_dhcsr_sticky(cortex_m, cortex_m->dcb_dhcsr); return ERROR_OK; } static int cortex_m_load_core_reg_u32(struct target *target, uint32_t regsel, uint32_t *value) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = target_to_armv7m(target); int retval; uint32_t dcrdr, tmp_value; int64_t then; /* because the DCB_DCRDR is used for the emulated dcc channel * we have to save/restore the DCB_DCRDR when used */ if (target->dbg_msg_enabled) { retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DCRDR, &dcrdr); if (retval != ERROR_OK) return retval; } retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRSR, regsel); if (retval != ERROR_OK) return retval; /* check if value from register is ready and pre-read it */ then = timeval_ms(); while (1) { retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); if (retval != ERROR_OK) return retval; retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DCRDR, &tmp_value); if (retval != ERROR_OK) return retval; cortex_m_cumulate_dhcsr_sticky(cortex_m, cortex_m->dcb_dhcsr); if (cortex_m->dcb_dhcsr & S_REGRDY) break; cortex_m->slow_register_read = true; /* Polling (still) needed. */ if (timeval_ms() > then + DHCSR_S_REGRDY_TIMEOUT) { LOG_TARGET_ERROR(target, "Timeout waiting for DCRDR transfer ready"); return ERROR_TIMEOUT_REACHED; } keep_alive(); } *value = tmp_value; if (target->dbg_msg_enabled) { /* restore DCB_DCRDR - this needs to be in a separate * transaction otherwise the emulated DCC channel breaks */ if (retval == ERROR_OK) retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRDR, dcrdr); } return retval; } static int cortex_m_slow_read_all_regs(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = target_to_armv7m(target); const unsigned int num_regs = armv7m->arm.core_cache->num_regs; /* Opportunistically restore fast read, it'll revert to slow * if any register needed polling in cortex_m_load_core_reg_u32(). */ cortex_m->slow_register_read = false; for (unsigned int reg_id = 0; reg_id < num_regs; reg_id++) { struct reg *r = &armv7m->arm.core_cache->reg_list[reg_id]; if (r->exist) { int retval = armv7m->arm.read_core_reg(target, r, reg_id, ARM_MODE_ANY); if (retval != ERROR_OK) return retval; } } if (!cortex_m->slow_register_read) LOG_TARGET_DEBUG(target, "Switching back to fast register reads"); return ERROR_OK; } static int cortex_m_queue_reg_read(struct target *target, uint32_t regsel, uint32_t *reg_value, uint32_t *dhcsr) { struct armv7m_common *armv7m = target_to_armv7m(target); int retval; retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRSR, regsel); if (retval != ERROR_OK) return retval; retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DHCSR, dhcsr); if (retval != ERROR_OK) return retval; return mem_ap_read_u32(armv7m->debug_ap, DCB_DCRDR, reg_value); } static int cortex_m_fast_read_all_regs(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = target_to_armv7m(target); int retval; uint32_t dcrdr; /* because the DCB_DCRDR is used for the emulated dcc channel * we have to save/restore the DCB_DCRDR when used */ if (target->dbg_msg_enabled) { retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DCRDR, &dcrdr); if (retval != ERROR_OK) return retval; } const unsigned int num_regs = armv7m->arm.core_cache->num_regs; const unsigned int n_r32 = ARMV7M_LAST_REG - ARMV7M_CORE_FIRST_REG + 1 + ARMV7M_FPU_LAST_REG - ARMV7M_FPU_FIRST_REG + 1; /* we need one 32-bit word for each register except FP D0..D15, which * need two words */ uint32_t r_vals[n_r32]; uint32_t dhcsr[n_r32]; unsigned int wi = 0; /* write index to r_vals and dhcsr arrays */ unsigned int reg_id; /* register index in the reg_list, ARMV7M_R0... */ for (reg_id = 0; reg_id < num_regs; reg_id++) { struct reg *r = &armv7m->arm.core_cache->reg_list[reg_id]; if (!r->exist) continue; /* skip non existent registers */ if (r->size <= 8) { /* Any 8-bit or shorter register is unpacked from a 32-bit * container register. Skip it now. */ continue; } uint32_t regsel = armv7m_map_id_to_regsel(reg_id); retval = cortex_m_queue_reg_read(target, regsel, &r_vals[wi], &dhcsr[wi]); if (retval != ERROR_OK) return retval; wi++; assert(r->size == 32 || r->size == 64); if (r->size == 32) continue; /* done with 32-bit register */ assert(reg_id >= ARMV7M_FPU_FIRST_REG && reg_id <= ARMV7M_FPU_LAST_REG); /* the odd part of FP register (S1, S3...) */ retval = cortex_m_queue_reg_read(target, regsel + 1, &r_vals[wi], &dhcsr[wi]); if (retval != ERROR_OK) return retval; wi++; } assert(wi <= n_r32); retval = dap_run(armv7m->debug_ap->dap); if (retval != ERROR_OK) return retval; if (target->dbg_msg_enabled) { /* restore DCB_DCRDR - this needs to be in a separate * transaction otherwise the emulated DCC channel breaks */ retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRDR, dcrdr); if (retval != ERROR_OK) return retval; } bool not_ready = false; for (unsigned int i = 0; i < wi; i++) { if ((dhcsr[i] & S_REGRDY) == 0) { not_ready = true; LOG_TARGET_DEBUG(target, "Register %u was not ready during fast read", i); } cortex_m_cumulate_dhcsr_sticky(cortex_m, dhcsr[i]); } if (not_ready) { /* Any register was not ready, * fall back to slow read with S_REGRDY polling */ return ERROR_TIMEOUT_REACHED; } LOG_TARGET_DEBUG(target, "read %u 32-bit registers", wi); unsigned int ri = 0; /* read index from r_vals array */ for (reg_id = 0; reg_id < num_regs; reg_id++) { struct reg *r = &armv7m->arm.core_cache->reg_list[reg_id]; if (!r->exist) continue; /* skip non existent registers */ r->dirty = false; unsigned int reg32_id; uint32_t offset; if (armv7m_map_reg_packing(reg_id, ®32_id, &offset)) { /* Unpack a partial register from 32-bit container register */ struct reg *r32 = &armv7m->arm.core_cache->reg_list[reg32_id]; /* The container register ought to precede all regs unpacked * from it in the reg_list. So the value should be ready * to unpack */ assert(r32->valid); buf_cpy(r32->value + offset, r->value, r->size); } else { assert(r->size == 32 || r->size == 64); buf_set_u32(r->value, 0, 32, r_vals[ri++]); if (r->size == 64) { assert(reg_id >= ARMV7M_FPU_FIRST_REG && reg_id <= ARMV7M_FPU_LAST_REG); /* the odd part of FP register (S1, S3...) */ buf_set_u32(r->value + 4, 0, 32, r_vals[ri++]); } } r->valid = true; } assert(ri == wi); return retval; } static int cortex_m_store_core_reg_u32(struct target *target, uint32_t regsel, uint32_t value) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = target_to_armv7m(target); int retval; uint32_t dcrdr; int64_t then; /* because the DCB_DCRDR is used for the emulated dcc channel * we have to save/restore the DCB_DCRDR when used */ if (target->dbg_msg_enabled) { retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DCRDR, &dcrdr); if (retval != ERROR_OK) return retval; } retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRDR, value); if (retval != ERROR_OK) return retval; retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRSR, regsel | DCRSR_WNR); if (retval != ERROR_OK) return retval; /* check if value is written into register */ then = timeval_ms(); while (1) { retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) return retval; if (cortex_m->dcb_dhcsr & S_REGRDY) break; if (timeval_ms() > then + DHCSR_S_REGRDY_TIMEOUT) { LOG_TARGET_ERROR(target, "Timeout waiting for DCRDR transfer ready"); return ERROR_TIMEOUT_REACHED; } keep_alive(); } if (target->dbg_msg_enabled) { /* restore DCB_DCRDR - this needs to be in a separate * transaction otherwise the emulated DCC channel breaks */ if (retval == ERROR_OK) retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRDR, dcrdr); } return retval; } static int cortex_m_write_debug_halt_mask(struct target *target, uint32_t mask_on, uint32_t mask_off) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; /* mask off status bits */ cortex_m->dcb_dhcsr &= ~((0xFFFFul << 16) | mask_off); /* create new register mask */ cortex_m->dcb_dhcsr |= DBGKEY | C_DEBUGEN | mask_on; return mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DHCSR, cortex_m->dcb_dhcsr); } static int cortex_m_set_maskints(struct target *target, bool mask) { struct cortex_m_common *cortex_m = target_to_cm(target); if (!!(cortex_m->dcb_dhcsr & C_MASKINTS) != mask) return cortex_m_write_debug_halt_mask(target, mask ? C_MASKINTS : 0, mask ? 0 : C_MASKINTS); else return ERROR_OK; } static int cortex_m_set_maskints_for_halt(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); switch (cortex_m->isrmasking_mode) { case CORTEX_M_ISRMASK_AUTO: /* interrupts taken at resume, whether for step or run -> no mask */ return cortex_m_set_maskints(target, false); case CORTEX_M_ISRMASK_OFF: /* interrupts never masked */ return cortex_m_set_maskints(target, false); case CORTEX_M_ISRMASK_ON: /* interrupts always masked */ return cortex_m_set_maskints(target, true); case CORTEX_M_ISRMASK_STEPONLY: /* interrupts masked for single step only -> mask now if MASKINTS * erratum, otherwise only mask before stepping */ return cortex_m_set_maskints(target, cortex_m->maskints_erratum); } return ERROR_OK; } static int cortex_m_set_maskints_for_run(struct target *target) { switch (target_to_cm(target)->isrmasking_mode) { case CORTEX_M_ISRMASK_AUTO: /* interrupts taken at resume, whether for step or run -> no mask */ return cortex_m_set_maskints(target, false); case CORTEX_M_ISRMASK_OFF: /* interrupts never masked */ return cortex_m_set_maskints(target, false); case CORTEX_M_ISRMASK_ON: /* interrupts always masked */ return cortex_m_set_maskints(target, true); case CORTEX_M_ISRMASK_STEPONLY: /* interrupts masked for single step only -> no mask */ return cortex_m_set_maskints(target, false); } return ERROR_OK; } static int cortex_m_set_maskints_for_step(struct target *target) { switch (target_to_cm(target)->isrmasking_mode) { case CORTEX_M_ISRMASK_AUTO: /* the auto-interrupt should already be done -> mask */ return cortex_m_set_maskints(target, true); case CORTEX_M_ISRMASK_OFF: /* interrupts never masked */ return cortex_m_set_maskints(target, false); case CORTEX_M_ISRMASK_ON: /* interrupts always masked */ return cortex_m_set_maskints(target, true); case CORTEX_M_ISRMASK_STEPONLY: /* interrupts masked for single step only -> mask */ return cortex_m_set_maskints(target, true); } return ERROR_OK; } static int cortex_m_clear_halt(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; int retval; /* clear step if any */ cortex_m_write_debug_halt_mask(target, C_HALT, C_STEP); /* Read Debug Fault Status Register */ retval = mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_DFSR, &cortex_m->nvic_dfsr); if (retval != ERROR_OK) return retval; /* Clear Debug Fault Status */ retval = mem_ap_write_atomic_u32(armv7m->debug_ap, NVIC_DFSR, cortex_m->nvic_dfsr); if (retval != ERROR_OK) return retval; LOG_TARGET_DEBUG(target, "NVIC_DFSR 0x%" PRIx32 "", cortex_m->nvic_dfsr); return ERROR_OK; } static int cortex_m_single_step_core(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); int retval; /* Mask interrupts before clearing halt, if not done already. This avoids * Erratum 377497 (fixed in r1p0) where setting MASKINTS while clearing * HALT can put the core into an unknown state. */ if (!(cortex_m->dcb_dhcsr & C_MASKINTS)) { retval = cortex_m_write_debug_halt_mask(target, C_MASKINTS, 0); if (retval != ERROR_OK) return retval; } retval = cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); if (retval != ERROR_OK) return retval; LOG_TARGET_DEBUG(target, "single step"); /* restore dhcsr reg */ cortex_m_clear_halt(target); return ERROR_OK; } static int cortex_m_enable_fpb(struct target *target) { int retval = target_write_u32(target, FP_CTRL, 3); if (retval != ERROR_OK) return retval; /* check the fpb is actually enabled */ uint32_t fpctrl; retval = target_read_u32(target, FP_CTRL, &fpctrl); if (retval != ERROR_OK) return retval; if (fpctrl & 1) return ERROR_OK; return ERROR_FAIL; } static int cortex_m_endreset_event(struct target *target) { int retval; uint32_t dcb_demcr; struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; struct adiv5_dap *swjdp = cortex_m->armv7m.arm.dap; struct cortex_m_fp_comparator *fp_list = cortex_m->fp_comparator_list; struct cortex_m_dwt_comparator *dwt_list = cortex_m->dwt_comparator_list; /* REVISIT The four debug monitor bits are currently ignored... */ retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DEMCR, &dcb_demcr); if (retval != ERROR_OK) return retval; LOG_TARGET_DEBUG(target, "DCB_DEMCR = 0x%8.8" PRIx32 "", dcb_demcr); /* this register is used for emulated dcc channel */ retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRDR, 0); if (retval != ERROR_OK) return retval; retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) return retval; if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) { /* Enable debug requests */ retval = cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP | C_MASKINTS); if (retval != ERROR_OK) return retval; } /* Restore proper interrupt masking setting for running CPU. */ cortex_m_set_maskints_for_run(target); /* Enable features controlled by ITM and DWT blocks, and catch only * the vectors we were told to pay attention to. * * Target firmware is responsible for all fault handling policy * choices *EXCEPT* explicitly scripted overrides like "vector_catch" * or manual updates to the NVIC SHCSR and CCR registers. */ retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DEMCR, TRCENA | armv7m->demcr); if (retval != ERROR_OK) return retval; /* Paranoia: evidently some (early?) chips don't preserve all the * debug state (including FPB, DWT, etc) across reset... */ /* Enable FPB */ retval = cortex_m_enable_fpb(target); if (retval != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to enable the FPB"); return retval; } cortex_m->fpb_enabled = true; /* Restore FPB registers */ for (unsigned int i = 0; i < cortex_m->fp_num_code + cortex_m->fp_num_lit; i++) { retval = target_write_u32(target, fp_list[i].fpcr_address, fp_list[i].fpcr_value); if (retval != ERROR_OK) return retval; } /* Restore DWT registers */ for (unsigned int i = 0; i < cortex_m->dwt_num_comp; i++) { retval = target_write_u32(target, dwt_list[i].dwt_comparator_address + 0, dwt_list[i].comp); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, dwt_list[i].dwt_comparator_address + 4, dwt_list[i].mask); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, dwt_list[i].dwt_comparator_address + 8, dwt_list[i].function); if (retval != ERROR_OK) return retval; } retval = dap_run(swjdp); if (retval != ERROR_OK) return retval; register_cache_invalidate(armv7m->arm.core_cache); /* TODO: invalidate also working areas (needed in the case of detected reset). * Doing so will require flash drivers to test if working area * is still valid in all target algo calling loops. */ /* make sure we have latest dhcsr flags */ retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) return retval; return retval; } static int cortex_m_examine_debug_reason(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); /* THIS IS NOT GOOD, TODO - better logic for detection of debug state reason * only check the debug reason if we don't know it already */ if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) { if (cortex_m->nvic_dfsr & DFSR_BKPT) { target->debug_reason = DBG_REASON_BREAKPOINT; if (cortex_m->nvic_dfsr & DFSR_DWTTRAP) target->debug_reason = DBG_REASON_WPTANDBKPT; } else if (cortex_m->nvic_dfsr & DFSR_DWTTRAP) target->debug_reason = DBG_REASON_WATCHPOINT; else if (cortex_m->nvic_dfsr & DFSR_VCATCH) target->debug_reason = DBG_REASON_BREAKPOINT; else if (cortex_m->nvic_dfsr & DFSR_EXTERNAL) target->debug_reason = DBG_REASON_DBGRQ; else /* HALTED */ target->debug_reason = DBG_REASON_UNDEFINED; } return ERROR_OK; } static int cortex_m_examine_exception_reason(struct target *target) { uint32_t shcsr = 0, except_sr = 0, cfsr = -1, except_ar = -1; struct armv7m_common *armv7m = target_to_armv7m(target); struct adiv5_dap *swjdp = armv7m->arm.dap; int retval; retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_SHCSR, &shcsr); if (retval != ERROR_OK) return retval; switch (armv7m->exception_number) { case 2: /* NMI */ break; case 3: /* Hard Fault */ retval = mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_HFSR, &except_sr); if (retval != ERROR_OK) return retval; if (except_sr & 0x40000000) { retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &cfsr); if (retval != ERROR_OK) return retval; } break; case 4: /* Memory Management */ retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); if (retval != ERROR_OK) return retval; retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_MMFAR, &except_ar); if (retval != ERROR_OK) return retval; break; case 5: /* Bus Fault */ retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); if (retval != ERROR_OK) return retval; retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_BFAR, &except_ar); if (retval != ERROR_OK) return retval; break; case 6: /* Usage Fault */ retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); if (retval != ERROR_OK) return retval; break; case 7: /* Secure Fault */ retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_SFSR, &except_sr); if (retval != ERROR_OK) return retval; retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_SFAR, &except_ar); if (retval != ERROR_OK) return retval; break; case 11: /* SVCall */ break; case 12: /* Debug Monitor */ retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_DFSR, &except_sr); if (retval != ERROR_OK) return retval; break; case 14: /* PendSV */ break; case 15: /* SysTick */ break; default: except_sr = 0; break; } retval = dap_run(swjdp); if (retval == ERROR_OK) LOG_TARGET_DEBUG(target, "%s SHCSR 0x%" PRIx32 ", SR 0x%" PRIx32 ", CFSR 0x%" PRIx32 ", AR 0x%" PRIx32, armv7m_exception_string(armv7m->exception_number), shcsr, except_sr, cfsr, except_ar); return retval; } static int cortex_m_debug_entry(struct target *target) { uint32_t xpsr; int retval; struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; struct arm *arm = &armv7m->arm; struct reg *r; LOG_TARGET_DEBUG(target, " "); /* Do this really early to minimize the window where the MASKINTS erratum * can pile up pending interrupts. */ cortex_m_set_maskints_for_halt(target); cortex_m_clear_halt(target); retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) return retval; retval = armv7m->examine_debug_reason(target); if (retval != ERROR_OK) return retval; /* examine PE security state */ uint32_t dscsr = 0; if (armv7m->arm.arch == ARM_ARCH_V8M) { retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DSCSR, &dscsr); if (retval != ERROR_OK) return retval; } /* Load all registers to arm.core_cache */ if (!cortex_m->slow_register_read) { retval = cortex_m_fast_read_all_regs(target); if (retval == ERROR_TIMEOUT_REACHED) { cortex_m->slow_register_read = true; LOG_TARGET_DEBUG(target, "Switched to slow register read"); } } if (cortex_m->slow_register_read) retval = cortex_m_slow_read_all_regs(target); if (retval != ERROR_OK) return retval; r = arm->cpsr; xpsr = buf_get_u32(r->value, 0, 32); /* Are we in an exception handler */ if (xpsr & 0x1FF) { armv7m->exception_number = (xpsr & 0x1FF); arm->core_mode = ARM_MODE_HANDLER; arm->map = armv7m_msp_reg_map; } else { unsigned control = buf_get_u32(arm->core_cache ->reg_list[ARMV7M_CONTROL].value, 0, 3); /* is this thread privileged? */ arm->core_mode = control & 1 ? ARM_MODE_USER_THREAD : ARM_MODE_THREAD; /* which stack is it using? */ if (control & 2) arm->map = armv7m_psp_reg_map; else arm->map = armv7m_msp_reg_map; armv7m->exception_number = 0; } if (armv7m->exception_number) cortex_m_examine_exception_reason(target); bool secure_state = (dscsr & DSCSR_CDS) == DSCSR_CDS; LOG_TARGET_DEBUG(target, "entered debug state in core mode: %s at PC 0x%" PRIx32 ", cpu in %s state, target->state: %s", arm_mode_name(arm->core_mode), buf_get_u32(arm->pc->value, 0, 32), secure_state ? "Secure" : "Non-Secure", target_state_name(target)); if (armv7m->post_debug_entry) { retval = armv7m->post_debug_entry(target); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int cortex_m_poll_one(struct target *target) { int detected_failure = ERROR_OK; int retval = ERROR_OK; enum target_state prev_target_state = target->state; struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; /* Read from Debug Halting Control and Status Register */ retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) { target->state = TARGET_UNKNOWN; return retval; } /* Recover from lockup. See ARMv7-M architecture spec, * section B1.5.15 "Unrecoverable exception cases". */ if (cortex_m->dcb_dhcsr & S_LOCKUP) { LOG_TARGET_ERROR(target, "clearing lockup after double fault"); cortex_m_write_debug_halt_mask(target, C_HALT, 0); target->debug_reason = DBG_REASON_DBGRQ; /* We have to execute the rest (the "finally" equivalent, but * still throw this exception again). */ detected_failure = ERROR_FAIL; /* refresh status bits */ retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) return retval; } if (cortex_m->dcb_dhcsr_cumulated_sticky & S_RESET_ST) { cortex_m->dcb_dhcsr_cumulated_sticky &= ~S_RESET_ST; if (target->state != TARGET_RESET) { target->state = TARGET_RESET; LOG_TARGET_INFO(target, "external reset detected"); } return ERROR_OK; } if (target->state == TARGET_RESET) { /* Cannot switch context while running so endreset is * called with target->state == TARGET_RESET */ LOG_TARGET_DEBUG(target, "Exit from reset with dcb_dhcsr 0x%" PRIx32, cortex_m->dcb_dhcsr); retval = cortex_m_endreset_event(target); if (retval != ERROR_OK) { target->state = TARGET_UNKNOWN; return retval; } target->state = TARGET_RUNNING; prev_target_state = TARGET_RUNNING; } if (cortex_m->dcb_dhcsr & S_HALT) { target->state = TARGET_HALTED; if ((prev_target_state == TARGET_RUNNING) || (prev_target_state == TARGET_RESET)) { retval = cortex_m_debug_entry(target); /* arm_semihosting needs to know registers, don't run if debug entry returned error */ if (retval == ERROR_OK && arm_semihosting(target, &retval) != 0) return retval; if (target->smp) { LOG_TARGET_DEBUG(target, "postpone target event 'halted'"); target->smp_halt_event_postponed = true; } else { /* regardless of errors returned in previous code update state */ target_call_event_callbacks(target, TARGET_EVENT_HALTED); } } if (prev_target_state == TARGET_DEBUG_RUNNING) { retval = cortex_m_debug_entry(target); target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } if (retval != ERROR_OK) return retval; } if (target->state == TARGET_UNKNOWN) { /* Check if processor is retiring instructions or sleeping. * Unlike S_RESET_ST here we test if the target *is* running now, * not if it has been running (possibly in the past). Instructions are * typically processed much faster than OpenOCD polls DHCSR so S_RETIRE_ST * is read always 1. That's the reason not to use dcb_dhcsr_cumulated_sticky. */ if (cortex_m->dcb_dhcsr & S_RETIRE_ST || cortex_m->dcb_dhcsr & S_SLEEP) { target->state = TARGET_RUNNING; retval = ERROR_OK; } } /* Check that target is truly halted, since the target could be resumed externally */ if ((prev_target_state == TARGET_HALTED) && !(cortex_m->dcb_dhcsr & S_HALT)) { /* registers are now invalid */ register_cache_invalidate(armv7m->arm.core_cache); target->state = TARGET_RUNNING; LOG_TARGET_WARNING(target, "external resume detected"); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); retval = ERROR_OK; } /* Did we detect a failure condition that we cleared? */ if (detected_failure != ERROR_OK) retval = detected_failure; return retval; } static int cortex_m_halt_one(struct target *target); static int cortex_m_smp_halt_all(struct list_head *smp_targets) { int retval = ERROR_OK; struct target_list *head; foreach_smp_target(head, smp_targets) { struct target *curr = head->target; if (!target_was_examined(curr)) continue; if (curr->state == TARGET_HALTED) continue; int ret2 = cortex_m_halt_one(curr); if (retval == ERROR_OK) retval = ret2; /* store the first error code ignore others */ } return retval; } static int cortex_m_smp_post_halt_poll(struct list_head *smp_targets) { int retval = ERROR_OK; struct target_list *head; foreach_smp_target(head, smp_targets) { struct target *curr = head->target; if (!target_was_examined(curr)) continue; /* skip targets that were already halted */ if (curr->state == TARGET_HALTED) continue; int ret2 = cortex_m_poll_one(curr); if (retval == ERROR_OK) retval = ret2; /* store the first error code ignore others */ } return retval; } static int cortex_m_poll_smp(struct list_head *smp_targets) { int retval = ERROR_OK; struct target_list *head; bool halted = false; foreach_smp_target(head, smp_targets) { struct target *curr = head->target; if (curr->smp_halt_event_postponed) { halted = true; break; } } if (halted) { retval = cortex_m_smp_halt_all(smp_targets); int ret2 = cortex_m_smp_post_halt_poll(smp_targets); if (retval == ERROR_OK) retval = ret2; /* store the first error code ignore others */ foreach_smp_target(head, smp_targets) { struct target *curr = head->target; if (!curr->smp_halt_event_postponed) continue; curr->smp_halt_event_postponed = false; if (curr->state == TARGET_HALTED) { LOG_TARGET_DEBUG(curr, "sending postponed target event 'halted'"); target_call_event_callbacks(curr, TARGET_EVENT_HALTED); } } /* There is no need to set gdb_service->target * as hwthread_update_threads() selects an interesting thread * by its own */ } return retval; } static int cortex_m_poll(struct target *target) { int retval = cortex_m_poll_one(target); if (target->smp) { struct target_list *last; last = list_last_entry(target->smp_targets, struct target_list, lh); if (target == last->target) /* After the last target in SMP group has been polled * check for postponed halted events and eventually halt and re-poll * other targets */ cortex_m_poll_smp(target->smp_targets); } return retval; } static int cortex_m_halt_one(struct target *target) { LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_TARGET_DEBUG(target, "target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_TARGET_WARNING(target, "target was in unknown state when halt was requested"); if (target->state == TARGET_RESET) { if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { LOG_TARGET_ERROR(target, "can't request a halt while in reset if nSRST pulls nTRST"); return ERROR_TARGET_FAILURE; } else { /* we came here in a reset_halt or reset_init sequence * debug entry was already prepared in cortex_m3_assert_reset() */ target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } } /* Write to Debug Halting Control and Status Register */ cortex_m_write_debug_halt_mask(target, C_HALT, 0); /* Do this really early to minimize the window where the MASKINTS erratum * can pile up pending interrupts. */ cortex_m_set_maskints_for_halt(target); target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int cortex_m_halt(struct target *target) { if (target->smp) return cortex_m_smp_halt_all(target->smp_targets); else return cortex_m_halt_one(target); } static int cortex_m_soft_reset_halt(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; int retval, timeout = 0; /* on single cortex_m MCU soft_reset_halt should be avoided as same functionality * can be obtained by using 'reset halt' and 'cortex_m reset_config vectreset'. * As this reset only uses VC_CORERESET it would only ever reset the cortex_m * core, not the peripherals */ LOG_TARGET_DEBUG(target, "soft_reset_halt is discouraged, please use 'reset halt' instead."); if (!cortex_m->vectreset_supported) { LOG_TARGET_ERROR(target, "VECTRESET is not supported on this Cortex-M core"); return ERROR_FAIL; } /* Set C_DEBUGEN */ retval = cortex_m_write_debug_halt_mask(target, 0, C_STEP | C_MASKINTS); if (retval != ERROR_OK) return retval; /* Enter debug state on reset; restore DEMCR in endreset_event() */ retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); if (retval != ERROR_OK) return retval; /* Request a core-only reset */ retval = mem_ap_write_atomic_u32(armv7m->debug_ap, NVIC_AIRCR, AIRCR_VECTKEY | AIRCR_VECTRESET); if (retval != ERROR_OK) return retval; target->state = TARGET_RESET; /* registers are now invalid */ register_cache_invalidate(cortex_m->armv7m.arm.core_cache); while (timeout < 100) { retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval == ERROR_OK) { retval = mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_DFSR, &cortex_m->nvic_dfsr); if (retval != ERROR_OK) return retval; if ((cortex_m->dcb_dhcsr & S_HALT) && (cortex_m->nvic_dfsr & DFSR_VCATCH)) { LOG_TARGET_DEBUG(target, "system reset-halted, DHCSR 0x%08" PRIx32 ", DFSR 0x%08" PRIx32, cortex_m->dcb_dhcsr, cortex_m->nvic_dfsr); cortex_m_poll(target); /* FIXME restore user's vector catch config */ return ERROR_OK; } else { LOG_TARGET_DEBUG(target, "waiting for system reset-halt, " "DHCSR 0x%08" PRIx32 ", %d ms", cortex_m->dcb_dhcsr, timeout); } } timeout++; alive_sleep(1); } return ERROR_OK; } void cortex_m_enable_breakpoints(struct target *target) { struct breakpoint *breakpoint = target->breakpoints; /* set any pending breakpoints */ while (breakpoint) { if (!breakpoint->is_set) cortex_m_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } } static int cortex_m_restore_one(struct target *target, bool current, target_addr_t *address, bool handle_breakpoints, bool debug_execution) { struct armv7m_common *armv7m = target_to_armv7m(target); struct breakpoint *breakpoint = NULL; uint32_t resume_pc; struct reg *r; if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) { target_free_all_working_areas(target); cortex_m_enable_breakpoints(target); cortex_m_enable_watchpoints(target); } if (debug_execution) { r = armv7m->arm.core_cache->reg_list + ARMV7M_PRIMASK; /* Disable interrupts */ /* We disable interrupts in the PRIMASK register instead of * masking with C_MASKINTS. This is probably the same issue * as Cortex-M3 Erratum 377493 (fixed in r1p0): C_MASKINTS * in parallel with disabled interrupts can cause local faults * to not be taken. * * This breaks non-debug (application) execution if not * called from armv7m_start_algorithm() which saves registers. */ buf_set_u32(r->value, 0, 1, 1); r->dirty = true; r->valid = true; /* Make sure we are in Thumb mode, set xPSR.T bit */ /* armv7m_start_algorithm() initializes entire xPSR register. * This duplicity handles the case when cortex_m_resume() * is used with the debug_execution flag directly, * not called through armv7m_start_algorithm(). */ r = armv7m->arm.cpsr; buf_set_u32(r->value, 24, 1, 1); r->dirty = true; r->valid = true; } /* current = 1: continue on current pc, otherwise continue at <address> */ r = armv7m->arm.pc; if (!current) { buf_set_u32(r->value, 0, 32, *address); r->dirty = true; r->valid = true; } /* if we halted last time due to a bkpt instruction * then we have to manually step over it, otherwise * the core will break again */ if (!breakpoint_find(target, buf_get_u32(r->value, 0, 32)) && !debug_execution) armv7m_maybe_skip_bkpt_inst(target, NULL); resume_pc = buf_get_u32(r->value, 0, 32); if (current) *address = resume_pc; int retval = armv7m_restore_context(target); if (retval != ERROR_OK) return retval; /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { LOG_TARGET_DEBUG(target, "unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")", breakpoint->address, breakpoint->unique_id); retval = cortex_m_unset_breakpoint(target, breakpoint); if (retval == ERROR_OK) retval = cortex_m_single_step_core(target); int ret2 = cortex_m_set_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; if (ret2 != ERROR_OK) return ret2; } } return ERROR_OK; } static int cortex_m_restart_one(struct target *target, bool debug_execution) { struct armv7m_common *armv7m = target_to_armv7m(target); /* Restart core */ cortex_m_set_maskints_for_run(target); cortex_m_write_debug_halt_mask(target, 0, C_HALT); target->debug_reason = DBG_REASON_NOTHALTED; /* registers are now invalid */ register_cache_invalidate(armv7m->arm.core_cache); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); } return ERROR_OK; } static int cortex_m_restore_smp(struct target *target, bool handle_breakpoints) { struct target_list *head; target_addr_t address; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; /* skip calling target */ if (curr == target) continue; if (!target_was_examined(curr)) continue; /* skip running targets */ if (curr->state == TARGET_RUNNING) continue; int retval = cortex_m_restore_one(curr, true, &address, handle_breakpoints, false); if (retval != ERROR_OK) return retval; retval = cortex_m_restart_one(curr, false); if (retval != ERROR_OK) return retval; LOG_TARGET_DEBUG(curr, "SMP resumed at " TARGET_ADDR_FMT, address); } return ERROR_OK; } static int cortex_m_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { int retval = cortex_m_restore_one(target, !!current, &address, !!handle_breakpoints, !!debug_execution); if (retval != ERROR_OK) { LOG_TARGET_ERROR(target, "context restore failed, aborting resume"); return retval; } if (target->smp && !debug_execution) { retval = cortex_m_restore_smp(target, !!handle_breakpoints); if (retval != ERROR_OK) LOG_WARNING("resume of a SMP target failed, trying to resume current one"); } cortex_m_restart_one(target, !!debug_execution); if (retval != ERROR_OK) { LOG_TARGET_ERROR(target, "resume failed"); return retval; } LOG_TARGET_DEBUG(target, "%sresumed at " TARGET_ADDR_FMT, debug_execution ? "debug " : "", address); return ERROR_OK; } /* int irqstepcount = 0; */ static int cortex_m_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; struct breakpoint *breakpoint = NULL; struct reg *pc = armv7m->arm.pc; bool bkpt_inst_found = false; int retval; bool isr_timed_out = false; if (target->state != TARGET_HALTED) { LOG_TARGET_WARNING(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Just one of SMP cores will step. Set the gdb control * target to current one or gdb miss gdb-end event */ if (target->smp && target->gdb_service) target->gdb_service->target = target; /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u32(pc->value, 0, 32, address); pc->dirty = true; pc->valid = true; } uint32_t pc_value = buf_get_u32(pc->value, 0, 32); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { breakpoint = breakpoint_find(target, pc_value); if (breakpoint) cortex_m_unset_breakpoint(target, breakpoint); } armv7m_maybe_skip_bkpt_inst(target, &bkpt_inst_found); target->debug_reason = DBG_REASON_SINGLESTEP; armv7m_restore_context(target); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); /* if no bkpt instruction is found at pc then we can perform * a normal step, otherwise we have to manually step over the bkpt * instruction - as such simulate a step */ if (bkpt_inst_found == false) { if (cortex_m->isrmasking_mode != CORTEX_M_ISRMASK_AUTO) { /* Automatic ISR masking mode off: Just step over the next * instruction, with interrupts on or off as appropriate. */ cortex_m_set_maskints_for_step(target); cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); } else { /* Process interrupts during stepping in a way they don't interfere * debugging. * * Principle: * * Set a temporary break point at the current pc and let the core run * with interrupts enabled. Pending interrupts get served and we run * into the breakpoint again afterwards. Then we step over the next * instruction with interrupts disabled. * * If the pending interrupts don't complete within time, we leave the * core running. This may happen if the interrupts trigger faster * than the core can process them or the handler doesn't return. * * If no more breakpoints are available we simply do a step with * interrupts enabled. * */ /* 2012-09-29 ph * * If a break point is already set on the lower half word then a break point on * the upper half word will not break again when the core is restarted. So we * just step over the instruction with interrupts disabled. * * The documentation has no information about this, it was found by observation * on STM32F1 and STM32F2. Proper explanation welcome. STM32F0 doesn't seem to * suffer from this problem. * * To add some confusion: pc_value has bit 0 always set, while the breakpoint * address has it always cleared. The former is done to indicate thumb mode * to gdb. * */ if ((pc_value & 0x02) && breakpoint_find(target, pc_value & ~0x03)) { LOG_TARGET_DEBUG(target, "Stepping over next instruction with interrupts disabled"); cortex_m_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0); cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); /* Re-enable interrupts if appropriate */ cortex_m_write_debug_halt_mask(target, C_HALT, 0); cortex_m_set_maskints_for_halt(target); } else { /* Set a temporary break point */ if (breakpoint) { retval = cortex_m_set_breakpoint(target, breakpoint); } else { enum breakpoint_type type = BKPT_HARD; if (cortex_m->fp_rev == 0 && pc_value > 0x1FFFFFFF) { /* FPB rev.1 cannot handle such addr, try BKPT instr */ type = BKPT_SOFT; } retval = breakpoint_add(target, pc_value, 2, type); } bool tmp_bp_set = (retval == ERROR_OK); /* No more breakpoints left, just do a step */ if (!tmp_bp_set) { cortex_m_set_maskints_for_step(target); cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); /* Re-enable interrupts if appropriate */ cortex_m_write_debug_halt_mask(target, C_HALT, 0); cortex_m_set_maskints_for_halt(target); } else { /* Start the core */ LOG_TARGET_DEBUG(target, "Starting core to serve pending interrupts"); int64_t t_start = timeval_ms(); cortex_m_set_maskints_for_run(target); cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP); /* Wait for pending handlers to complete or timeout */ do { retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) { target->state = TARGET_UNKNOWN; return retval; } isr_timed_out = ((timeval_ms() - t_start) > 500); } while (!((cortex_m->dcb_dhcsr & S_HALT) || isr_timed_out)); /* only remove breakpoint if we created it */ if (breakpoint) cortex_m_unset_breakpoint(target, breakpoint); else { /* Remove the temporary breakpoint */ breakpoint_remove(target, pc_value); } if (isr_timed_out) { LOG_TARGET_DEBUG(target, "Interrupt handlers didn't complete within time, " "leaving target running"); } else { /* Step over next instruction with interrupts disabled */ cortex_m_set_maskints_for_step(target); cortex_m_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0); cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); /* Re-enable interrupts if appropriate */ cortex_m_write_debug_halt_mask(target, C_HALT, 0); cortex_m_set_maskints_for_halt(target); } } } } } retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) return retval; /* registers are now invalid */ register_cache_invalidate(armv7m->arm.core_cache); if (breakpoint) cortex_m_set_breakpoint(target, breakpoint); if (isr_timed_out) { /* Leave the core running. The user has to stop execution manually. */ target->debug_reason = DBG_REASON_NOTHALTED; target->state = TARGET_RUNNING; return ERROR_OK; } LOG_TARGET_DEBUG(target, "target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32, cortex_m->dcb_dhcsr, cortex_m->nvic_icsr); retval = cortex_m_debug_entry(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); LOG_TARGET_DEBUG(target, "target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32, cortex_m->dcb_dhcsr, cortex_m->nvic_icsr); return ERROR_OK; } static int cortex_m_assert_reset(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; enum cortex_m_soft_reset_config reset_config = cortex_m->soft_reset_config; LOG_TARGET_DEBUG(target, "target->state: %s,%s examined", target_state_name(target), target_was_examined(target) ? "" : " not"); enum reset_types jtag_reset_config = jtag_get_reset_config(); if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) { /* allow scripts to override the reset event */ target_handle_event(target, TARGET_EVENT_RESET_ASSERT); register_cache_invalidate(cortex_m->armv7m.arm.core_cache); target->state = TARGET_RESET; return ERROR_OK; } /* some cores support connecting while srst is asserted * use that mode is it has been configured */ bool srst_asserted = false; if ((jtag_reset_config & RESET_HAS_SRST) && ((jtag_reset_config & RESET_SRST_NO_GATING) || !armv7m->debug_ap)) { /* If we have no debug_ap, asserting SRST is the only thing * we can do now */ adapter_assert_reset(); srst_asserted = true; } /* TODO: replace the hack calling target_examine_one() * as soon as a better reset framework is available */ if (!target_was_examined(target) && !target->defer_examine && srst_asserted && (jtag_reset_config & RESET_SRST_NO_GATING)) { LOG_TARGET_DEBUG(target, "Trying to re-examine under reset"); target_examine_one(target); } /* We need at least debug_ap to go further. * Inform user and bail out if we don't have one. */ if (!armv7m->debug_ap) { if (srst_asserted) { if (target->reset_halt) LOG_TARGET_ERROR(target, "Debug AP not available, will not halt after reset!"); /* Do not propagate error: reset was asserted, proceed to deassert! */ target->state = TARGET_RESET; register_cache_invalidate(cortex_m->armv7m.arm.core_cache); return ERROR_OK; } else { LOG_TARGET_ERROR(target, "Debug AP not available, reset NOT asserted!"); return ERROR_FAIL; } } /* Enable debug requests */ int retval = cortex_m_read_dhcsr_atomic_sticky(target); /* Store important errors instead of failing and proceed to reset assert */ if (retval != ERROR_OK || !(cortex_m->dcb_dhcsr & C_DEBUGEN)) retval = cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP | C_MASKINTS); /* If the processor is sleeping in a WFI or WFE instruction, the * C_HALT bit must be asserted to regain control */ if (retval == ERROR_OK && (cortex_m->dcb_dhcsr & S_SLEEP)) retval = cortex_m_write_debug_halt_mask(target, C_HALT, 0); mem_ap_write_u32(armv7m->debug_ap, DCB_DCRDR, 0); /* Ignore less important errors */ if (!target->reset_halt) { /* Set/Clear C_MASKINTS in a separate operation */ cortex_m_set_maskints_for_run(target); /* clear any debug flags before resuming */ cortex_m_clear_halt(target); /* clear C_HALT in dhcsr reg */ cortex_m_write_debug_halt_mask(target, 0, C_HALT); } else { /* Halt in debug on reset; endreset_event() restores DEMCR. * * REVISIT catching BUSERR presumably helps to defend against * bad vector table entries. Should this include MMERR or * other flags too? */ int retval2; retval2 = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); if (retval != ERROR_OK || retval2 != ERROR_OK) LOG_TARGET_INFO(target, "AP write error, reset will not halt"); } if (jtag_reset_config & RESET_HAS_SRST) { /* default to asserting srst */ if (!srst_asserted) adapter_assert_reset(); /* srst is asserted, ignore AP access errors */ retval = ERROR_OK; } else { /* Use a standard Cortex-M3 software reset mechanism. * We default to using VECTRESET as it is supported on all current cores * (except Cortex-M0, M0+ and M1 which support SYSRESETREQ only!) * This has the disadvantage of not resetting the peripherals, so a * reset-init event handler is needed to perform any peripheral resets. */ if (!cortex_m->vectreset_supported && reset_config == CORTEX_M_RESET_VECTRESET) { reset_config = CORTEX_M_RESET_SYSRESETREQ; LOG_TARGET_WARNING(target, "VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ instead."); LOG_TARGET_WARNING(target, "Set 'cortex_m reset_config sysresetreq'."); } LOG_TARGET_DEBUG(target, "Using Cortex-M %s", (reset_config == CORTEX_M_RESET_SYSRESETREQ) ? "SYSRESETREQ" : "VECTRESET"); if (reset_config == CORTEX_M_RESET_VECTRESET) { LOG_TARGET_WARNING(target, "Only resetting the Cortex-M core, use a reset-init event " "handler to reset any peripherals or configure hardware srst support."); } int retval3; retval3 = mem_ap_write_atomic_u32(armv7m->debug_ap, NVIC_AIRCR, AIRCR_VECTKEY | ((reset_config == CORTEX_M_RESET_SYSRESETREQ) ? AIRCR_SYSRESETREQ : AIRCR_VECTRESET)); if (retval3 != ERROR_OK) LOG_TARGET_DEBUG(target, "Ignoring AP write error right after reset"); retval3 = dap_dp_init_or_reconnect(armv7m->debug_ap->dap); if (retval3 != ERROR_OK) { LOG_TARGET_ERROR(target, "DP initialisation failed"); /* The error return value must not be propagated in this case. * SYSRESETREQ or VECTRESET have been possibly triggered * so reset processing should continue */ } else { /* I do not know why this is necessary, but it * fixes strange effects (step/resume cause NMI * after reset) on LM3S6918 -- Michael Schwingen */ uint32_t tmp; mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_AIRCR, &tmp); } } target->state = TARGET_RESET; jtag_sleep(50000); register_cache_invalidate(cortex_m->armv7m.arm.core_cache); /* now return stored error code if any */ if (retval != ERROR_OK) return retval; if (target->reset_halt && target_was_examined(target)) { retval = target_halt(target); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int cortex_m_deassert_reset(struct target *target) { struct armv7m_common *armv7m = &target_to_cm(target)->armv7m; LOG_TARGET_DEBUG(target, "target->state: %s,%s examined", target_state_name(target), target_was_examined(target) ? "" : " not"); /* deassert reset lines */ adapter_deassert_reset(); enum reset_types jtag_reset_config = jtag_get_reset_config(); if ((jtag_reset_config & RESET_HAS_SRST) && !(jtag_reset_config & RESET_SRST_NO_GATING) && armv7m->debug_ap) { int retval = dap_dp_init_or_reconnect(armv7m->debug_ap->dap); if (retval != ERROR_OK) { LOG_TARGET_ERROR(target, "DP initialisation failed"); return retval; } } return ERROR_OK; } int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval; unsigned int fp_num = 0; struct cortex_m_common *cortex_m = target_to_cm(target); struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; if (breakpoint->is_set) { LOG_TARGET_WARNING(target, "breakpoint (BPID: %" PRIu32 ") already set", breakpoint->unique_id); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { uint32_t fpcr_value; while (comparator_list[fp_num].used && (fp_num < cortex_m->fp_num_code)) fp_num++; if (fp_num >= cortex_m->fp_num_code) { LOG_TARGET_ERROR(target, "Can not find free FPB Comparator!"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint_hw_set(breakpoint, fp_num); fpcr_value = breakpoint->address | 1; if (cortex_m->fp_rev == 0) { if (breakpoint->address > 0x1FFFFFFF) { LOG_TARGET_ERROR(target, "Cortex-M Flash Patch Breakpoint rev.1 " "cannot handle HW breakpoint above address 0x1FFFFFFE"); return ERROR_FAIL; } uint32_t hilo; hilo = (breakpoint->address & 0x2) ? FPCR_REPLACE_BKPT_HIGH : FPCR_REPLACE_BKPT_LOW; fpcr_value = (fpcr_value & 0x1FFFFFFC) | hilo | 1; } else if (cortex_m->fp_rev > 1) { LOG_TARGET_ERROR(target, "Unhandled Cortex-M Flash Patch Breakpoint architecture revision"); return ERROR_FAIL; } comparator_list[fp_num].used = true; comparator_list[fp_num].fpcr_value = fpcr_value; target_write_u32(target, comparator_list[fp_num].fpcr_address, comparator_list[fp_num].fpcr_value); LOG_TARGET_DEBUG(target, "fpc_num %i fpcr_value 0x%" PRIx32 "", fp_num, comparator_list[fp_num].fpcr_value); if (!cortex_m->fpb_enabled) { LOG_TARGET_DEBUG(target, "FPB wasn't enabled, do it now"); retval = cortex_m_enable_fpb(target); if (retval != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to enable the FPB"); return retval; } cortex_m->fpb_enabled = true; } } else if (breakpoint->type == BKPT_SOFT) { uint8_t code[4]; /* NOTE: on ARMv6-M and ARMv7-M, BKPT(0xab) is used for * semihosting; don't use that. Otherwise the BKPT * parameter is arbitrary. */ buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11)); retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, code); if (retval != ERROR_OK) return retval; breakpoint->is_set = true; } LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (n=%u)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, breakpoint->length, (breakpoint->type == BKPT_SOFT) ? 0 : breakpoint->number); return ERROR_OK; } int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval; struct cortex_m_common *cortex_m = target_to_cm(target); struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; if (!breakpoint->is_set) { LOG_TARGET_WARNING(target, "breakpoint not set"); return ERROR_OK; } LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (n=%u)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, breakpoint->length, (breakpoint->type == BKPT_SOFT) ? 0 : breakpoint->number); if (breakpoint->type == BKPT_HARD) { unsigned int fp_num = breakpoint->number; if (fp_num >= cortex_m->fp_num_code) { LOG_TARGET_DEBUG(target, "Invalid FP Comparator number in breakpoint"); return ERROR_OK; } comparator_list[fp_num].used = false; comparator_list[fp_num].fpcr_value = 0; target_write_u32(target, comparator_list[fp_num].fpcr_address, comparator_list[fp_num].fpcr_value); } else { /* restore original instruction (kept in target endianness) */ retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } breakpoint->is_set = false; return ERROR_OK; } int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (breakpoint->length == 3) { LOG_TARGET_DEBUG(target, "Using a two byte breakpoint for 32bit Thumb-2 request"); breakpoint->length = 2; } if ((breakpoint->length != 2)) { LOG_TARGET_INFO(target, "only breakpoints of two bytes length supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } return cortex_m_set_breakpoint(target, breakpoint); } int cortex_m_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (!breakpoint->is_set) return ERROR_OK; return cortex_m_unset_breakpoint(target, breakpoint); } static int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { unsigned int dwt_num = 0; struct cortex_m_common *cortex_m = target_to_cm(target); /* REVISIT Don't fully trust these "not used" records ... users * may set up breakpoints by hand, e.g. dual-address data value * watchpoint using comparator #1; comparator #0 matching cycle * count; send data trace info through ITM and TPIU; etc */ struct cortex_m_dwt_comparator *comparator; for (comparator = cortex_m->dwt_comparator_list; comparator->used && dwt_num < cortex_m->dwt_num_comp; comparator++, dwt_num++) continue; if (dwt_num >= cortex_m->dwt_num_comp) { LOG_TARGET_ERROR(target, "Can not find free DWT Comparator"); return ERROR_FAIL; } comparator->used = true; watchpoint_set(watchpoint, dwt_num); comparator->comp = watchpoint->address; target_write_u32(target, comparator->dwt_comparator_address + 0, comparator->comp); if ((cortex_m->dwt_devarch & 0x1FFFFF) != DWT_DEVARCH_ARMV8M) { uint32_t mask = 0, temp; /* watchpoint params were validated earlier */ temp = watchpoint->length; while (temp) { temp >>= 1; mask++; } mask--; comparator->mask = mask; target_write_u32(target, comparator->dwt_comparator_address + 4, comparator->mask); switch (watchpoint->rw) { case WPT_READ: comparator->function = 5; break; case WPT_WRITE: comparator->function = 6; break; case WPT_ACCESS: comparator->function = 7; break; } } else { uint32_t data_size = watchpoint->length >> 1; comparator->mask = (watchpoint->length >> 1) | 1; switch (watchpoint->rw) { case WPT_ACCESS: comparator->function = 4; break; case WPT_WRITE: comparator->function = 5; break; case WPT_READ: comparator->function = 6; break; } comparator->function = comparator->function | (1 << 4) | (data_size << 10); } target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%d 0x%08x 0x%x 0x%05x", watchpoint->unique_id, dwt_num, (unsigned) comparator->comp, (unsigned) comparator->mask, (unsigned) comparator->function); return ERROR_OK; } static int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct cortex_m_common *cortex_m = target_to_cm(target); struct cortex_m_dwt_comparator *comparator; if (!watchpoint->is_set) { LOG_TARGET_WARNING(target, "watchpoint (wpid: %d) not set", watchpoint->unique_id); return ERROR_OK; } unsigned int dwt_num = watchpoint->number; LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%u address: 0x%08x clear", watchpoint->unique_id, dwt_num, (unsigned) watchpoint->address); if (dwt_num >= cortex_m->dwt_num_comp) { LOG_TARGET_DEBUG(target, "Invalid DWT Comparator number in watchpoint"); return ERROR_OK; } comparator = cortex_m->dwt_comparator_list + dwt_num; comparator->used = false; comparator->function = 0; target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); watchpoint->is_set = false; return ERROR_OK; } int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct cortex_m_common *cortex_m = target_to_cm(target); if (cortex_m->dwt_comp_available < 1) { LOG_TARGET_DEBUG(target, "no comparators?"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* hardware doesn't support data value masking */ if (watchpoint->mask != ~(uint32_t)0) { LOG_TARGET_DEBUG(target, "watchpoint value masks not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* hardware allows address masks of up to 32K */ unsigned mask; for (mask = 0; mask < 16; mask++) { if ((1u << mask) == watchpoint->length) break; } if (mask == 16) { LOG_TARGET_DEBUG(target, "unsupported watchpoint length"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (watchpoint->address & ((1 << mask) - 1)) { LOG_TARGET_DEBUG(target, "watchpoint address is unaligned"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* Caller doesn't seem to be able to describe watching for data * values of zero; that flags "no value". * * REVISIT This DWT may well be able to watch for specific data * values. Requires comparator #1 to set DATAVMATCH and match * the data, and another comparator (DATAVADDR0) matching addr. */ if (watchpoint->value) { LOG_TARGET_DEBUG(target, "data value watchpoint not YET supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } cortex_m->dwt_comp_available--; LOG_TARGET_DEBUG(target, "dwt_comp_available: %d", cortex_m->dwt_comp_available); return ERROR_OK; } int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct cortex_m_common *cortex_m = target_to_cm(target); /* REVISIT why check? DWT can be updated with core running ... */ if (target->state != TARGET_HALTED) { LOG_TARGET_WARNING(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } if (watchpoint->is_set) cortex_m_unset_watchpoint(target, watchpoint); cortex_m->dwt_comp_available++; LOG_TARGET_DEBUG(target, "dwt_comp_available: %d", cortex_m->dwt_comp_available); return ERROR_OK; } static int cortex_m_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { if (target->debug_reason != DBG_REASON_WATCHPOINT) return ERROR_FAIL; struct cortex_m_common *cortex_m = target_to_cm(target); for (struct watchpoint *wp = target->watchpoints; wp; wp = wp->next) { if (!wp->is_set) continue; unsigned int dwt_num = wp->number; struct cortex_m_dwt_comparator *comparator = cortex_m->dwt_comparator_list + dwt_num; uint32_t dwt_function; int retval = target_read_u32(target, comparator->dwt_comparator_address + 8, &dwt_function); if (retval != ERROR_OK) return ERROR_FAIL; /* check the MATCHED bit */ if (dwt_function & BIT(24)) { *hit_watchpoint = wp; return ERROR_OK; } } return ERROR_FAIL; } void cortex_m_enable_watchpoints(struct target *target) { struct watchpoint *watchpoint = target->watchpoints; /* set any pending watchpoints */ while (watchpoint) { if (!watchpoint->is_set) cortex_m_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } } static int cortex_m_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct armv7m_common *armv7m = target_to_armv7m(target); if (armv7m->arm.arch == ARM_ARCH_V6M) { /* armv6m does not handle unaligned memory access */ if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; } return mem_ap_read_buf(armv7m->debug_ap, buffer, size, count, address); } static int cortex_m_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct armv7m_common *armv7m = target_to_armv7m(target); if (armv7m->arm.arch == ARM_ARCH_V6M) { /* armv6m does not handle unaligned memory access */ if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; } return mem_ap_write_buf(armv7m->debug_ap, buffer, size, count, address); } static int cortex_m_init_target(struct command_context *cmd_ctx, struct target *target) { armv7m_build_reg_cache(target); arm_semihosting_init(target); return ERROR_OK; } void cortex_m_deinit_target(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = target_to_armv7m(target); if (!armv7m->is_hla_target && armv7m->debug_ap) dap_put_ap(armv7m->debug_ap); free(cortex_m->fp_comparator_list); cortex_m_dwt_free(target); armv7m_free_reg_cache(target); free(target->private_config); free(cortex_m); } int cortex_m_profiling(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { struct timeval timeout, now; struct armv7m_common *armv7m = target_to_armv7m(target); uint32_t reg_value; int retval; retval = target_read_u32(target, DWT_PCSR, ®_value); if (retval != ERROR_OK) { LOG_TARGET_ERROR(target, "Error while reading PCSR"); return retval; } if (reg_value == 0) { LOG_TARGET_INFO(target, "PCSR sampling not supported on this processor."); return target_profiling_default(target, samples, max_num_samples, num_samples, seconds); } gettimeofday(&timeout, NULL); timeval_add_time(&timeout, seconds, 0); LOG_TARGET_INFO(target, "Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can..."); /* Make sure the target is running */ target_poll(target); if (target->state == TARGET_HALTED) retval = target_resume(target, 1, 0, 0, 0); if (retval != ERROR_OK) { LOG_TARGET_ERROR(target, "Error while resuming target"); return retval; } uint32_t sample_count = 0; for (;;) { if (armv7m && armv7m->debug_ap) { uint32_t read_count = max_num_samples - sample_count; if (read_count > 1024) read_count = 1024; retval = mem_ap_read_buf_noincr(armv7m->debug_ap, (void *)&samples[sample_count], 4, read_count, DWT_PCSR); sample_count += read_count; } else { target_read_u32(target, DWT_PCSR, &samples[sample_count++]); } if (retval != ERROR_OK) { LOG_TARGET_ERROR(target, "Error while reading PCSR"); return retval; } gettimeofday(&now, NULL); if (sample_count >= max_num_samples || timeval_compare(&now, &timeout) > 0) { LOG_TARGET_INFO(target, "Profiling completed. %" PRIu32 " samples.", sample_count); break; } } *num_samples = sample_count; return retval; } /* REVISIT cache valid/dirty bits are unmaintained. We could set "valid" * on r/w if the core is not running, and clear on resume or reset ... or * at least, in a post_restore_context() method. */ struct dwt_reg_state { struct target *target; uint32_t addr; uint8_t value[4]; /* scratch/cache */ }; static int cortex_m_dwt_get_reg(struct reg *reg) { struct dwt_reg_state *state = reg->arch_info; uint32_t tmp; int retval = target_read_u32(state->target, state->addr, &tmp); if (retval != ERROR_OK) return retval; buf_set_u32(state->value, 0, 32, tmp); return ERROR_OK; } static int cortex_m_dwt_set_reg(struct reg *reg, uint8_t *buf) { struct dwt_reg_state *state = reg->arch_info; return target_write_u32(state->target, state->addr, buf_get_u32(buf, 0, reg->size)); } struct dwt_reg { uint32_t addr; const char *name; unsigned size; }; static const struct dwt_reg dwt_base_regs[] = { { DWT_CTRL, "dwt_ctrl", 32, }, /* NOTE that Erratum 532314 (fixed r2p0) affects CYCCNT: it wrongly * increments while the core is asleep. */ { DWT_CYCCNT, "dwt_cyccnt", 32, }, /* plus some 8 bit counters, useful for profiling with TPIU */ }; static const struct dwt_reg dwt_comp[] = { #define DWT_COMPARATOR(i) \ { DWT_COMP0 + 0x10 * (i), "dwt_" #i "_comp", 32, }, \ { DWT_MASK0 + 0x10 * (i), "dwt_" #i "_mask", 4, }, \ { DWT_FUNCTION0 + 0x10 * (i), "dwt_" #i "_function", 32, } DWT_COMPARATOR(0), DWT_COMPARATOR(1), DWT_COMPARATOR(2), DWT_COMPARATOR(3), DWT_COMPARATOR(4), DWT_COMPARATOR(5), DWT_COMPARATOR(6), DWT_COMPARATOR(7), DWT_COMPARATOR(8), DWT_COMPARATOR(9), DWT_COMPARATOR(10), DWT_COMPARATOR(11), DWT_COMPARATOR(12), DWT_COMPARATOR(13), DWT_COMPARATOR(14), DWT_COMPARATOR(15), #undef DWT_COMPARATOR }; static const struct reg_arch_type dwt_reg_type = { .get = cortex_m_dwt_get_reg, .set = cortex_m_dwt_set_reg, }; static void cortex_m_dwt_addreg(struct target *t, struct reg *r, const struct dwt_reg *d) { struct dwt_reg_state *state; state = calloc(1, sizeof(*state)); if (!state) return; state->addr = d->addr; state->target = t; r->name = d->name; r->size = d->size; r->value = state->value; r->arch_info = state; r->type = &dwt_reg_type; } static void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target) { uint32_t dwtcr; struct reg_cache *cache; struct cortex_m_dwt_comparator *comparator; int reg; target_read_u32(target, DWT_CTRL, &dwtcr); LOG_TARGET_DEBUG(target, "DWT_CTRL: 0x%" PRIx32, dwtcr); if (!dwtcr) { LOG_TARGET_DEBUG(target, "no DWT"); return; } target_read_u32(target, DWT_DEVARCH, &cm->dwt_devarch); LOG_TARGET_DEBUG(target, "DWT_DEVARCH: 0x%" PRIx32, cm->dwt_devarch); cm->dwt_num_comp = (dwtcr >> 28) & 0xF; cm->dwt_comp_available = cm->dwt_num_comp; cm->dwt_comparator_list = calloc(cm->dwt_num_comp, sizeof(struct cortex_m_dwt_comparator)); if (!cm->dwt_comparator_list) { fail0: cm->dwt_num_comp = 0; LOG_TARGET_ERROR(target, "out of mem"); return; } cache = calloc(1, sizeof(*cache)); if (!cache) { fail1: free(cm->dwt_comparator_list); goto fail0; } cache->name = "Cortex-M DWT registers"; cache->num_regs = 2 + cm->dwt_num_comp * 3; cache->reg_list = calloc(cache->num_regs, sizeof(*cache->reg_list)); if (!cache->reg_list) { free(cache); goto fail1; } for (reg = 0; reg < 2; reg++) cortex_m_dwt_addreg(target, cache->reg_list + reg, dwt_base_regs + reg); comparator = cm->dwt_comparator_list; for (unsigned int i = 0; i < cm->dwt_num_comp; i++, comparator++) { int j; comparator->dwt_comparator_address = DWT_COMP0 + 0x10 * i; for (j = 0; j < 3; j++, reg++) cortex_m_dwt_addreg(target, cache->reg_list + reg, dwt_comp + 3 * i + j); /* make sure we clear any watchpoints enabled on the target */ target_write_u32(target, comparator->dwt_comparator_address + 8, 0); } *register_get_last_cache_p(&target->reg_cache) = cache; cm->dwt_cache = cache; LOG_TARGET_DEBUG(target, "DWT dwtcr 0x%" PRIx32 ", comp %d, watch%s", dwtcr, cm->dwt_num_comp, (dwtcr & (0xf << 24)) ? " only" : "/trigger"); /* REVISIT: if num_comp > 1, check whether comparator #1 can * implement single-address data value watchpoints ... so we * won't need to check it later, when asked to set one up. */ } static void cortex_m_dwt_free(struct target *target) { struct cortex_m_common *cm = target_to_cm(target); struct reg_cache *cache = cm->dwt_cache; free(cm->dwt_comparator_list); cm->dwt_comparator_list = NULL; cm->dwt_num_comp = 0; if (cache) { register_unlink_cache(&target->reg_cache, cache); if (cache->reg_list) { for (size_t i = 0; i < cache->num_regs; i++) free(cache->reg_list[i].arch_info); free(cache->reg_list); } free(cache); } cm->dwt_cache = NULL; } static bool cortex_m_has_tz(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); uint32_t dauthstatus; if (armv7m->arm.arch != ARM_ARCH_V8M) return false; int retval = target_read_u32(target, DAUTHSTATUS, &dauthstatus); if (retval != ERROR_OK) { LOG_WARNING("Error reading DAUTHSTATUS register"); return false; } return (dauthstatus & DAUTHSTATUS_SID_MASK) != 0; } #define MVFR0 0xe000ef40 #define MVFR1 0xe000ef44 #define MVFR0_DEFAULT_M4 0x10110021 #define MVFR1_DEFAULT_M4 0x11000011 #define MVFR0_DEFAULT_M7_SP 0x10110021 #define MVFR0_DEFAULT_M7_DP 0x10110221 #define MVFR1_DEFAULT_M7_SP 0x11000011 #define MVFR1_DEFAULT_M7_DP 0x12000011 static int cortex_m_find_mem_ap(struct adiv5_dap *swjdp, struct adiv5_ap **debug_ap) { if (dap_find_get_ap(swjdp, AP_TYPE_AHB3_AP, debug_ap) == ERROR_OK) return ERROR_OK; return dap_find_get_ap(swjdp, AP_TYPE_AHB5_AP, debug_ap); } int cortex_m_examine(struct target *target) { int retval; uint32_t cpuid, fpcr, mvfr0, mvfr1; struct cortex_m_common *cortex_m = target_to_cm(target); struct adiv5_dap *swjdp = cortex_m->armv7m.arm.dap; struct armv7m_common *armv7m = target_to_armv7m(target); /* hla_target shares the examine handler but does not support * all its calls */ if (!armv7m->is_hla_target) { if (!armv7m->debug_ap) { if (cortex_m->apsel == DP_APSEL_INVALID) { /* Search for the MEM-AP */ retval = cortex_m_find_mem_ap(swjdp, &armv7m->debug_ap); if (retval != ERROR_OK) { LOG_TARGET_ERROR(target, "Could not find MEM-AP to control the core"); return retval; } } else { armv7m->debug_ap = dap_get_ap(swjdp, cortex_m->apsel); if (!armv7m->debug_ap) { LOG_ERROR("Cannot get AP"); return ERROR_FAIL; } } } armv7m->debug_ap->memaccess_tck = 8; retval = mem_ap_init(armv7m->debug_ap); if (retval != ERROR_OK) return retval; } if (!target_was_examined(target)) { target_set_examined(target); /* Read from Device Identification Registers */ retval = target_read_u32(target, CPUID, &cpuid); if (retval != ERROR_OK) return retval; /* Get ARCH and CPU types */ const enum cortex_m_partno core_partno = (cpuid & ARM_CPUID_PARTNO_MASK) >> ARM_CPUID_PARTNO_POS; for (unsigned int n = 0; n < ARRAY_SIZE(cortex_m_parts); n++) { if (core_partno == cortex_m_parts[n].partno) { cortex_m->core_info = &cortex_m_parts[n]; break; } } if (!cortex_m->core_info) { LOG_TARGET_ERROR(target, "Cortex-M PARTNO 0x%x is unrecognized", core_partno); return ERROR_FAIL; } armv7m->arm.arch = cortex_m->core_info->arch; LOG_TARGET_INFO(target, "%s r%" PRId8 "p%" PRId8 " processor detected", cortex_m->core_info->name, (uint8_t)((cpuid >> 20) & 0xf), (uint8_t)((cpuid >> 0) & 0xf)); cortex_m->maskints_erratum = false; if (core_partno == CORTEX_M7_PARTNO) { uint8_t rev, patch; rev = (cpuid >> 20) & 0xf; patch = (cpuid >> 0) & 0xf; if ((rev == 0) && (patch < 2)) { LOG_TARGET_WARNING(target, "Silicon bug: single stepping may enter pending exception handler!"); cortex_m->maskints_erratum = true; } } LOG_TARGET_DEBUG(target, "cpuid: 0x%8.8" PRIx32 "", cpuid); if (cortex_m->core_info->flags & CORTEX_M_F_HAS_FPV4) { target_read_u32(target, MVFR0, &mvfr0); target_read_u32(target, MVFR1, &mvfr1); /* test for floating point feature on Cortex-M4 */ if ((mvfr0 == MVFR0_DEFAULT_M4) && (mvfr1 == MVFR1_DEFAULT_M4)) { LOG_TARGET_DEBUG(target, "%s floating point feature FPv4_SP found", cortex_m->core_info->name); armv7m->fp_feature = FPV4_SP; } } else if (cortex_m->core_info->flags & CORTEX_M_F_HAS_FPV5) { target_read_u32(target, MVFR0, &mvfr0); target_read_u32(target, MVFR1, &mvfr1); /* test for floating point features on Cortex-M7 */ if ((mvfr0 == MVFR0_DEFAULT_M7_SP) && (mvfr1 == MVFR1_DEFAULT_M7_SP)) { LOG_TARGET_DEBUG(target, "%s floating point feature FPv5_SP found", cortex_m->core_info->name); armv7m->fp_feature = FPV5_SP; } else if ((mvfr0 == MVFR0_DEFAULT_M7_DP) && (mvfr1 == MVFR1_DEFAULT_M7_DP)) { LOG_TARGET_DEBUG(target, "%s floating point feature FPv5_DP found", cortex_m->core_info->name); armv7m->fp_feature = FPV5_DP; } } /* VECTRESET is supported only on ARMv7-M cores */ cortex_m->vectreset_supported = armv7m->arm.arch == ARM_ARCH_V7M; /* Check for FPU, otherwise mark FPU register as non-existent */ if (armv7m->fp_feature == FP_NONE) for (size_t idx = ARMV7M_FPU_FIRST_REG; idx <= ARMV7M_FPU_LAST_REG; idx++) armv7m->arm.core_cache->reg_list[idx].exist = false; if (!cortex_m_has_tz(target)) for (size_t idx = ARMV8M_FIRST_REG; idx <= ARMV8M_LAST_REG; idx++) armv7m->arm.core_cache->reg_list[idx].exist = false; if (!armv7m->is_hla_target) { if (cortex_m->core_info->flags & CORTEX_M_F_TAR_AUTOINCR_BLOCK_4K) /* Cortex-M3/M4 have 4096 bytes autoincrement range, * s. ARM IHI 0031C: MEM-AP 7.2.2 */ armv7m->debug_ap->tar_autoincr_block = (1 << 12); } retval = target_read_u32(target, DCB_DHCSR, &cortex_m->dcb_dhcsr); if (retval != ERROR_OK) return retval; /* Don't cumulate sticky S_RESET_ST at the very first read of DHCSR * as S_RESET_ST may indicate a reset that happened long time ago * (most probably the power-on reset before OpenOCD was started). * As we are just initializing the debug system we do not need * to call cortex_m_endreset_event() in the following poll. */ if (!cortex_m->dcb_dhcsr_sticky_is_recent) { cortex_m->dcb_dhcsr_sticky_is_recent = true; if (cortex_m->dcb_dhcsr & S_RESET_ST) { LOG_TARGET_DEBUG(target, "reset happened some time ago, ignore"); cortex_m->dcb_dhcsr &= ~S_RESET_ST; } } cortex_m_cumulate_dhcsr_sticky(cortex_m, cortex_m->dcb_dhcsr); if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) { /* Enable debug requests */ uint32_t dhcsr = (cortex_m->dcb_dhcsr | C_DEBUGEN) & ~(C_HALT | C_STEP | C_MASKINTS); retval = target_write_u32(target, DCB_DHCSR, DBGKEY | (dhcsr & 0x0000FFFFUL)); if (retval != ERROR_OK) return retval; cortex_m->dcb_dhcsr = dhcsr; } /* Configure trace modules */ retval = target_write_u32(target, DCB_DEMCR, TRCENA | armv7m->demcr); if (retval != ERROR_OK) return retval; if (armv7m->trace_config.itm_deferred_config) armv7m_trace_itm_config(target); /* NOTE: FPB and DWT are both optional. */ /* Setup FPB */ target_read_u32(target, FP_CTRL, &fpcr); /* bits [14:12] and [7:4] */ cortex_m->fp_num_code = ((fpcr >> 8) & 0x70) | ((fpcr >> 4) & 0xF); cortex_m->fp_num_lit = (fpcr >> 8) & 0xF; /* Detect flash patch revision, see RM DDI 0403E.b page C1-817. Revision is zero base, fp_rev == 1 means Rev.2 ! */ cortex_m->fp_rev = (fpcr >> 28) & 0xf; free(cortex_m->fp_comparator_list); cortex_m->fp_comparator_list = calloc( cortex_m->fp_num_code + cortex_m->fp_num_lit, sizeof(struct cortex_m_fp_comparator)); cortex_m->fpb_enabled = fpcr & 1; for (unsigned int i = 0; i < cortex_m->fp_num_code + cortex_m->fp_num_lit; i++) { cortex_m->fp_comparator_list[i].type = (i < cortex_m->fp_num_code) ? FPCR_CODE : FPCR_LITERAL; cortex_m->fp_comparator_list[i].fpcr_address = FP_COMP0 + 4 * i; /* make sure we clear any breakpoints enabled on the target */ target_write_u32(target, cortex_m->fp_comparator_list[i].fpcr_address, 0); } LOG_TARGET_DEBUG(target, "FPB fpcr 0x%" PRIx32 ", numcode %i, numlit %i", fpcr, cortex_m->fp_num_code, cortex_m->fp_num_lit); /* Setup DWT */ cortex_m_dwt_free(target); cortex_m_dwt_setup(cortex_m, target); /* These hardware breakpoints only work for code in flash! */ LOG_TARGET_INFO(target, "target has %d breakpoints, %d watchpoints", cortex_m->fp_num_code, cortex_m->dwt_num_comp); } return ERROR_OK; } static int cortex_m_dcc_read(struct target *target, uint8_t *value, uint8_t *ctrl) { struct armv7m_common *armv7m = target_to_armv7m(target); uint16_t dcrdr; uint8_t buf[2]; int retval; retval = mem_ap_read_buf_noincr(armv7m->debug_ap, buf, 2, 1, DCB_DCRDR); if (retval != ERROR_OK) return retval; dcrdr = target_buffer_get_u16(target, buf); *ctrl = (uint8_t)dcrdr; *value = (uint8_t)(dcrdr >> 8); LOG_TARGET_DEBUG(target, "data 0x%x ctrl 0x%x", *value, *ctrl); /* write ack back to software dcc register * signify we have read data */ if (dcrdr & (1 << 0)) { target_buffer_set_u16(target, buf, 0); retval = mem_ap_write_buf_noincr(armv7m->debug_ap, buf, 2, 1, DCB_DCRDR); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int cortex_m_target_request_data(struct target *target, uint32_t size, uint8_t *buffer) { uint8_t data; uint8_t ctrl; uint32_t i; for (i = 0; i < (size * 4); i++) { int retval = cortex_m_dcc_read(target, &data, &ctrl); if (retval != ERROR_OK) return retval; buffer[i] = data; } return ERROR_OK; } static int cortex_m_handle_target_request(void *priv) { struct target *target = priv; if (!target_was_examined(target)) return ERROR_OK; if (!target->dbg_msg_enabled) return ERROR_OK; if (target->state == TARGET_RUNNING) { uint8_t data; uint8_t ctrl; int retval; retval = cortex_m_dcc_read(target, &data, &ctrl); if (retval != ERROR_OK) return retval; /* check if we have data */ if (ctrl & (1 << 0)) { uint32_t request; /* we assume target is quick enough */ request = data; for (int i = 1; i <= 3; i++) { retval = cortex_m_dcc_read(target, &data, &ctrl); if (retval != ERROR_OK) return retval; request |= ((uint32_t)data << (i * 8)); } target_request(target, request); } } return ERROR_OK; } static int cortex_m_init_arch_info(struct target *target, struct cortex_m_common *cortex_m, struct adiv5_dap *dap) { struct armv7m_common *armv7m = &cortex_m->armv7m; armv7m_init_arch_info(target, armv7m); /* default reset mode is to use srst if fitted * if not it will use CORTEX_M3_RESET_VECTRESET */ cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; armv7m->arm.dap = dap; /* register arch-specific functions */ armv7m->examine_debug_reason = cortex_m_examine_debug_reason; armv7m->post_debug_entry = NULL; armv7m->pre_restore_context = NULL; armv7m->load_core_reg_u32 = cortex_m_load_core_reg_u32; armv7m->store_core_reg_u32 = cortex_m_store_core_reg_u32; target_register_timer_callback(cortex_m_handle_target_request, 1, TARGET_TIMER_TYPE_PERIODIC, target); return ERROR_OK; } static int cortex_m_target_create(struct target *target, Jim_Interp *interp) { struct adiv5_private_config *pc; pc = (struct adiv5_private_config *)target->private_config; if (adiv5_verify_config(pc) != ERROR_OK) return ERROR_FAIL; struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common)); if (!cortex_m) { LOG_TARGET_ERROR(target, "No memory creating target"); return ERROR_FAIL; } cortex_m->common_magic = CORTEX_M_COMMON_MAGIC; cortex_m->apsel = pc->ap_num; cortex_m_init_arch_info(target, cortex_m, pc->dap); return ERROR_OK; } /*--------------------------------------------------------------------------*/ static int cortex_m_verify_pointer(struct command_invocation *cmd, struct cortex_m_common *cm) { if (!is_cortex_m_with_dap_access(cm)) { command_print(cmd, "target is not a Cortex-M"); return ERROR_TARGET_INVALID; } return ERROR_OK; } /* * Only stuff below this line should need to verify that its target * is a Cortex-M3. Everything else should have indirected through the * cortexm3_target structure, which is only used with CM3 targets. */ COMMAND_HANDLER(handle_cortex_m_vector_catch_command) { struct target *target = get_current_target(CMD_CTX); struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; uint32_t demcr = 0; int retval; static const struct { char name[10]; unsigned mask; } vec_ids[] = { { "hard_err", VC_HARDERR, }, { "int_err", VC_INTERR, }, { "bus_err", VC_BUSERR, }, { "state_err", VC_STATERR, }, { "chk_err", VC_CHKERR, }, { "nocp_err", VC_NOCPERR, }, { "mm_err", VC_MMERR, }, { "reset", VC_CORERESET, }, }; retval = cortex_m_verify_pointer(CMD, cortex_m); if (retval != ERROR_OK) return retval; if (!target_was_examined(target)) { LOG_TARGET_ERROR(target, "Target not examined yet"); return ERROR_FAIL; } retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DEMCR, &demcr); if (retval != ERROR_OK) return retval; if (CMD_ARGC > 0) { unsigned catch = 0; if (CMD_ARGC == 1) { if (strcmp(CMD_ARGV[0], "all") == 0) { catch = VC_HARDERR | VC_INTERR | VC_BUSERR | VC_STATERR | VC_CHKERR | VC_NOCPERR | VC_MMERR | VC_CORERESET; goto write; } else if (strcmp(CMD_ARGV[0], "none") == 0) goto write; } while (CMD_ARGC-- > 0) { unsigned i; for (i = 0; i < ARRAY_SIZE(vec_ids); i++) { if (strcmp(CMD_ARGV[CMD_ARGC], vec_ids[i].name) != 0) continue; catch |= vec_ids[i].mask; break; } if (i == ARRAY_SIZE(vec_ids)) { LOG_TARGET_ERROR(target, "No CM3 vector '%s'", CMD_ARGV[CMD_ARGC]); return ERROR_COMMAND_SYNTAX_ERROR; } } write: /* For now, armv7m->demcr only stores vector catch flags. */ armv7m->demcr = catch; demcr &= ~0xffff; demcr |= catch; /* write, but don't assume it stuck (why not??) */ retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DEMCR, demcr); if (retval != ERROR_OK) return retval; retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DEMCR, &demcr); if (retval != ERROR_OK) return retval; /* FIXME be sure to clear DEMCR on clean server shutdown. * Otherwise the vector catch hardware could fire when there's * no debugger hooked up, causing much confusion... */ } for (unsigned i = 0; i < ARRAY_SIZE(vec_ids); i++) { command_print(CMD, "%9s: %s", vec_ids[i].name, (demcr & vec_ids[i].mask) ? "catch" : "ignore"); } return ERROR_OK; } COMMAND_HANDLER(handle_cortex_m_mask_interrupts_command) { struct target *target = get_current_target(CMD_CTX); struct cortex_m_common *cortex_m = target_to_cm(target); int retval; static const struct nvp nvp_maskisr_modes[] = { { .name = "auto", .value = CORTEX_M_ISRMASK_AUTO }, { .name = "off", .value = CORTEX_M_ISRMASK_OFF }, { .name = "on", .value = CORTEX_M_ISRMASK_ON }, { .name = "steponly", .value = CORTEX_M_ISRMASK_STEPONLY }, { .name = NULL, .value = -1 }, }; const struct nvp *n; retval = cortex_m_verify_pointer(CMD, cortex_m); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } if (CMD_ARGC > 0) { n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]); if (!n->name) return ERROR_COMMAND_SYNTAX_ERROR; cortex_m->isrmasking_mode = n->value; cortex_m_set_maskints_for_halt(target); } n = nvp_value2name(nvp_maskisr_modes, cortex_m->isrmasking_mode); command_print(CMD, "cortex_m interrupt mask %s", n->name); return ERROR_OK; } COMMAND_HANDLER(handle_cortex_m_reset_config_command) { struct target *target = get_current_target(CMD_CTX); struct cortex_m_common *cortex_m = target_to_cm(target); int retval; char *reset_config; retval = cortex_m_verify_pointer(CMD, cortex_m); if (retval != ERROR_OK) return retval; if (CMD_ARGC > 0) { if (strcmp(*CMD_ARGV, "sysresetreq") == 0) cortex_m->soft_reset_config = CORTEX_M_RESET_SYSRESETREQ; else if (strcmp(*CMD_ARGV, "vectreset") == 0) { if (target_was_examined(target) && !cortex_m->vectreset_supported) LOG_TARGET_WARNING(target, "VECTRESET is not supported on your Cortex-M core!"); else cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; } else return ERROR_COMMAND_SYNTAX_ERROR; } switch (cortex_m->soft_reset_config) { case CORTEX_M_RESET_SYSRESETREQ: reset_config = "sysresetreq"; break; case CORTEX_M_RESET_VECTRESET: reset_config = "vectreset"; break; default: reset_config = "unknown"; break; } command_print(CMD, "cortex_m reset_config %s", reset_config); return ERROR_OK; } static const struct command_registration cortex_m_exec_command_handlers[] = { { .name = "maskisr", .handler = handle_cortex_m_mask_interrupts_command, .mode = COMMAND_EXEC, .help = "mask cortex_m interrupts", .usage = "['auto'|'on'|'off'|'steponly']", }, { .name = "vector_catch", .handler = handle_cortex_m_vector_catch_command, .mode = COMMAND_EXEC, .help = "configure hardware vectors to trigger debug entry", .usage = "['all'|'none'|('bus_err'|'chk_err'|...)*]", }, { .name = "reset_config", .handler = handle_cortex_m_reset_config_command, .mode = COMMAND_ANY, .help = "configure software reset handling", .usage = "['sysresetreq'|'vectreset']", }, { .chain = smp_command_handlers, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration cortex_m_command_handlers[] = { { .chain = armv7m_command_handlers, }, { .chain = armv7m_trace_command_handlers, }, /* START_DEPRECATED_TPIU */ { .chain = arm_tpiu_deprecated_command_handlers, }, /* END_DEPRECATED_TPIU */ { .name = "cortex_m", .mode = COMMAND_EXEC, .help = "Cortex-M command group", .usage = "", .chain = cortex_m_exec_command_handlers, }, { .chain = rtt_target_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type cortexm_target = { .name = "cortex_m", .poll = cortex_m_poll, .arch_state = armv7m_arch_state, .target_request_data = cortex_m_target_request_data, .halt = cortex_m_halt, .resume = cortex_m_resume, .step = cortex_m_step, .assert_reset = cortex_m_assert_reset, .deassert_reset = cortex_m_deassert_reset, .soft_reset_halt = cortex_m_soft_reset_halt, .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = armv7m_get_gdb_reg_list, .read_memory = cortex_m_read_memory, .write_memory = cortex_m_write_memory, .checksum_memory = armv7m_checksum_memory, .blank_check_memory = armv7m_blank_check_memory, .run_algorithm = armv7m_run_algorithm, .start_algorithm = armv7m_start_algorithm, .wait_algorithm = armv7m_wait_algorithm, .add_breakpoint = cortex_m_add_breakpoint, .remove_breakpoint = cortex_m_remove_breakpoint, .add_watchpoint = cortex_m_add_watchpoint, .remove_watchpoint = cortex_m_remove_watchpoint, .hit_watchpoint = cortex_m_hit_watchpoint, .commands = cortex_m_command_handlers, .target_create = cortex_m_target_create, .target_jim_configure = adiv5_jim_configure, .init_target = cortex_m_init_target, .examine = cortex_m_examine, .deinit_target = cortex_m_deinit_target, .profiling = cortex_m_profiling, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/cortex_m.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_TARGET_CORTEX_M_H #define OPENOCD_TARGET_CORTEX_M_H #include "armv7m.h" #include "helper/bits.h" #define CORTEX_M_COMMON_MAGIC 0x1A451A45U #define SYSTEM_CONTROL_BASE 0x400FE000 #define ITM_TER0 0xE0000E00 #define ITM_TPR 0xE0000E40 #define ITM_TCR 0xE0000E80 #define ITM_TCR_ITMENA_BIT BIT(0) #define ITM_TCR_BUSY_BIT BIT(23) #define ITM_LAR 0xE0000FB0 #define ITM_LAR_KEY 0xC5ACCE55 #define CPUID 0xE000ED00 #define ARM_CPUID_PARTNO_POS 4 #define ARM_CPUID_PARTNO_MASK (0xFFF << ARM_CPUID_PARTNO_POS) enum cortex_m_partno { CORTEX_M_PARTNO_INVALID, STAR_MC1_PARTNO = 0x132, CORTEX_M0_PARTNO = 0xC20, CORTEX_M1_PARTNO = 0xC21, CORTEX_M3_PARTNO = 0xC23, CORTEX_M4_PARTNO = 0xC24, CORTEX_M7_PARTNO = 0xC27, CORTEX_M0P_PARTNO = 0xC60, CORTEX_M23_PARTNO = 0xD20, CORTEX_M33_PARTNO = 0xD21, CORTEX_M35P_PARTNO = 0xD31, CORTEX_M55_PARTNO = 0xD22, }; /* Relevant Cortex-M flags, used in struct cortex_m_part_info.flags */ #define CORTEX_M_F_HAS_FPV4 BIT(0) #define CORTEX_M_F_HAS_FPV5 BIT(1) #define CORTEX_M_F_TAR_AUTOINCR_BLOCK_4K BIT(2) struct cortex_m_part_info { enum cortex_m_partno partno; const char *name; enum arm_arch arch; uint32_t flags; }; /* Debug Control Block */ #define DCB_DHCSR 0xE000EDF0 #define DCB_DCRSR 0xE000EDF4 #define DCB_DCRDR 0xE000EDF8 #define DCB_DEMCR 0xE000EDFC #define DCB_DSCSR 0xE000EE08 #define DAUTHSTATUS 0xE000EFB8 #define DAUTHSTATUS_SID_MASK 0x00000030 #define DCRSR_WNR BIT(16) #define DWT_CTRL 0xE0001000 #define DWT_CYCCNT 0xE0001004 #define DWT_PCSR 0xE000101C #define DWT_COMP0 0xE0001020 #define DWT_MASK0 0xE0001024 #define DWT_FUNCTION0 0xE0001028 #define DWT_DEVARCH 0xE0001FBC #define DWT_DEVARCH_ARMV8M 0x101A02 #define FP_CTRL 0xE0002000 #define FP_REMAP 0xE0002004 #define FP_COMP0 0xE0002008 #define FP_COMP1 0xE000200C #define FP_COMP2 0xE0002010 #define FP_COMP3 0xE0002014 #define FP_COMP4 0xE0002018 #define FP_COMP5 0xE000201C #define FP_COMP6 0xE0002020 #define FP_COMP7 0xE0002024 #define FPU_CPACR 0xE000ED88 #define FPU_FPCCR 0xE000EF34 #define FPU_FPCAR 0xE000EF38 #define FPU_FPDSCR 0xE000EF3C #define TPIU_SSPSR 0xE0040000 #define TPIU_CSPSR 0xE0040004 #define TPIU_ACPR 0xE0040010 #define TPIU_SPPR 0xE00400F0 #define TPIU_FFSR 0xE0040300 #define TPIU_FFCR 0xE0040304 #define TPIU_FSCR 0xE0040308 /* Maximum SWO prescaler value. */ #define TPIU_ACPR_MAX_SWOSCALER 0x1fff /* DCB_DHCSR bit and field definitions */ #define DBGKEY (0xA05Ful << 16) #define C_DEBUGEN BIT(0) #define C_HALT BIT(1) #define C_STEP BIT(2) #define C_MASKINTS BIT(3) #define S_REGRDY BIT(16) #define S_HALT BIT(17) #define S_SLEEP BIT(18) #define S_LOCKUP BIT(19) #define S_RETIRE_ST BIT(24) #define S_RESET_ST BIT(25) /* DCB_DEMCR bit and field definitions */ #define TRCENA BIT(24) #define VC_HARDERR BIT(10) #define VC_INTERR BIT(9) #define VC_BUSERR BIT(8) #define VC_STATERR BIT(7) #define VC_CHKERR BIT(6) #define VC_NOCPERR BIT(5) #define VC_MMERR BIT(4) #define VC_CORERESET BIT(0) /* DCB_DSCSR bit and field definitions */ #define DSCSR_CDS BIT(16) /* NVIC registers */ #define NVIC_ICTR 0xE000E004 #define NVIC_ISE0 0xE000E100 #define NVIC_ICSR 0xE000ED04 #define NVIC_AIRCR 0xE000ED0C #define NVIC_SHCSR 0xE000ED24 #define NVIC_CFSR 0xE000ED28 #define NVIC_MMFSRB 0xE000ED28 #define NVIC_BFSRB 0xE000ED29 #define NVIC_USFSRH 0xE000ED2A #define NVIC_HFSR 0xE000ED2C #define NVIC_DFSR 0xE000ED30 #define NVIC_MMFAR 0xE000ED34 #define NVIC_BFAR 0xE000ED38 #define NVIC_SFSR 0xE000EDE4 #define NVIC_SFAR 0xE000EDE8 /* NVIC_AIRCR bits */ #define AIRCR_VECTKEY (0x5FAul << 16) #define AIRCR_SYSRESETREQ BIT(2) #define AIRCR_VECTCLRACTIVE BIT(1) #define AIRCR_VECTRESET BIT(0) /* NVIC_SHCSR bits */ #define SHCSR_BUSFAULTENA BIT(17) /* NVIC_DFSR bits */ #define DFSR_HALTED 1 #define DFSR_BKPT 2 #define DFSR_DWTTRAP 4 #define DFSR_VCATCH 8 #define DFSR_EXTERNAL 16 #define FPCR_CODE 0 #define FPCR_LITERAL 1 #define FPCR_REPLACE_REMAP (0ul << 30) #define FPCR_REPLACE_BKPT_LOW (1ul << 30) #define FPCR_REPLACE_BKPT_HIGH (2ul << 30) #define FPCR_REPLACE_BKPT_BOTH (3ul << 30) struct cortex_m_fp_comparator { bool used; int type; uint32_t fpcr_value; uint32_t fpcr_address; }; struct cortex_m_dwt_comparator { bool used; uint32_t comp; uint32_t mask; uint32_t function; uint32_t dwt_comparator_address; }; enum cortex_m_soft_reset_config { CORTEX_M_RESET_SYSRESETREQ, CORTEX_M_RESET_VECTRESET, }; enum cortex_m_isrmasking_mode { CORTEX_M_ISRMASK_AUTO, CORTEX_M_ISRMASK_OFF, CORTEX_M_ISRMASK_ON, CORTEX_M_ISRMASK_STEPONLY, }; struct cortex_m_common { unsigned int common_magic; struct armv7m_common armv7m; /* Context information */ uint32_t dcb_dhcsr; uint32_t dcb_dhcsr_cumulated_sticky; /* DCB DHCSR has been at least once read, so the sticky bits have been reset */ bool dcb_dhcsr_sticky_is_recent; uint32_t nvic_dfsr; /* Debug Fault Status Register - shows reason for debug halt */ uint32_t nvic_icsr; /* Interrupt Control State Register - shows active and pending IRQ */ /* Flash Patch and Breakpoint (FPB) */ unsigned int fp_num_lit; unsigned int fp_num_code; int fp_rev; bool fpb_enabled; struct cortex_m_fp_comparator *fp_comparator_list; /* Data Watchpoint and Trace (DWT) */ unsigned int dwt_num_comp; unsigned int dwt_comp_available; uint32_t dwt_devarch; struct cortex_m_dwt_comparator *dwt_comparator_list; struct reg_cache *dwt_cache; enum cortex_m_soft_reset_config soft_reset_config; bool vectreset_supported; enum cortex_m_isrmasking_mode isrmasking_mode; const struct cortex_m_part_info *core_info; bool slow_register_read; /* A register has not been ready, poll S_REGRDY */ uint64_t apsel; /* Whether this target has the erratum that makes C_MASKINTS not apply to * already pending interrupts */ bool maskints_erratum; }; static inline bool is_cortex_m_or_hla(const struct cortex_m_common *cortex_m) { return cortex_m->common_magic == CORTEX_M_COMMON_MAGIC; } static inline bool is_cortex_m_with_dap_access(const struct cortex_m_common *cortex_m) { if (!is_cortex_m_or_hla(cortex_m)) return false; return !cortex_m->armv7m.is_hla_target; } /** * @returns the pointer to the target specific struct * without matching a magic number. * Use in target specific service routines, where the correct * type of arch_info is certain. */ static inline struct cortex_m_common * target_to_cm(struct target *target) { return container_of(target->arch_info, struct cortex_m_common, armv7m.arm); } /** * @returns the pointer to the target specific struct * or NULL if the magic number does not match. * Use in a flash driver or any place where mismatch of the arch_info * type can happen. */ static inline struct cortex_m_common * target_to_cortex_m_safe(struct target *target) { /* Check the parent types first to prevent peeking memory too far * from arch_info pointer */ if (!target_to_armv7m_safe(target)) return NULL; struct cortex_m_common *cortex_m = target_to_cm(target); if (!is_cortex_m_or_hla(cortex_m)) return NULL; return cortex_m; } /** * @returns cached value of Cortex-M part number * or CORTEX_M_PARTNO_INVALID if the magic number does not match * or core_info is not initialised. */ static inline enum cortex_m_partno cortex_m_get_partno_safe(struct target *target) { struct cortex_m_common *cortex_m = target_to_cortex_m_safe(target); if (!cortex_m) return CORTEX_M_PARTNO_INVALID; if (!cortex_m->core_info) return CORTEX_M_PARTNO_INVALID; return cortex_m->core_info->partno; } int cortex_m_examine(struct target *target); int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m_remove_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint); int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); void cortex_m_enable_breakpoints(struct target *target); void cortex_m_enable_watchpoints(struct target *target); void cortex_m_deinit_target(struct target *target); int cortex_m_profiling(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds); #endif /* OPENOCD_TARGET_CORTEX_M_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/dsp563xx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009-2011 by Mathias Kuester * * mkdorg@users.sourceforge.net * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jim.h> #include "target.h" #include "breakpoints.h" #include "target_type.h" #include "algorithm.h" #include "register.h" #include "dsp563xx.h" #include "dsp563xx_once.h" #define ASM_REG_W_R0 0x60F400 #define ASM_REG_W_R1 0x61F400 #define ASM_REG_W_R2 0x62F400 #define ASM_REG_W_R3 0x63F400 #define ASM_REG_W_R4 0x64F400 #define ASM_REG_W_R5 0x65F400 #define ASM_REG_W_R6 0x66F400 #define ASM_REG_W_R7 0x67F400 #define ASM_REG_W_N0 0x70F400 #define ASM_REG_W_N1 0x71F400 #define ASM_REG_W_N2 0x72F400 #define ASM_REG_W_N3 0x73F400 #define ASM_REG_W_N4 0x74F400 #define ASM_REG_W_N5 0x75F400 #define ASM_REG_W_N6 0x76F400 #define ASM_REG_W_N7 0x77F400 #define ASM_REG_W_M0 0x05F420 #define ASM_REG_W_M1 0x05F421 #define ASM_REG_W_M2 0x05F422 #define ASM_REG_W_M3 0x05F423 #define ASM_REG_W_M4 0x05F424 #define ASM_REG_W_M5 0x05F425 #define ASM_REG_W_M6 0x05F426 #define ASM_REG_W_M7 0x05F427 #define ASM_REG_W_X0 0x44F400 #define ASM_REG_W_X1 0x45F400 #define ASM_REG_W_Y0 0x46F400 #define ASM_REG_W_Y1 0x47F400 #define ASM_REG_W_A0 0x50F400 #define ASM_REG_W_A1 0x54F400 #define ASM_REG_W_A2 0x52F400 #define ASM_REG_W_B0 0x51F400 #define ASM_REG_W_B1 0x55F400 #define ASM_REG_W_B2 0x53F400 #define ASM_REG_W_VBA 0x05F430 #define ASM_REG_W_OMR 0x05F43A #define ASM_REG_W_EP 0x05F42A #define ASM_REG_W_SC 0x05F431 #define ASM_REG_W_SZ 0x05F438 #define ASM_REG_W_SR 0x05F439 #define ASM_REG_W_SP 0x05F43B #define ASM_REG_W_SSH 0x05F43C #define ASM_REG_W_SSL 0x05F43D #define ASM_REG_W_LA 0x05F43E #define ASM_REG_W_LC 0x05F43F #define ASM_REG_W_PC 0x000000 #define ASM_REG_W_IPRC 0xFFFFFF #define ASM_REG_W_IPRP 0xFFFFFE #define ASM_REG_W_BCR 0xFFFFFB #define ASM_REG_W_DCR 0xFFFFFA #define ASM_REG_W_AAR0 0xFFFFF9 #define ASM_REG_W_AAR1 0xFFFFF8 #define ASM_REG_W_AAR2 0xFFFFF7 #define ASM_REG_W_AAR3 0xFFFFF6 /* * OBCR Register bit definitions */ #define OBCR_B0_AND_B1 ((0x0) << 10) #define OBCR_B0_OR_B1 ((0x1) << 10) #define OBCR_B1_AFTER_B0 ((0x2) << 10) #define OBCR_B0_AFTER_B1 ((0x3) << 10) #define OBCR_BP_DISABLED (0x0) #define OBCR_BP_MEM_P (0x1) #define OBCR_BP_MEM_X (0x2) #define OBCR_BP_MEM_Y (0x3) #define OBCR_BP_ON_READ ((0x2) << 0) #define OBCR_BP_ON_WRITE ((0x1) << 0) #define OBCR_BP_CC_NOT_EQUAL ((0x0) << 2) #define OBCR_BP_CC_EQUAL ((0x1) << 2) #define OBCR_BP_CC_LESS_THAN ((0x2) << 2) #define OBCR_BP_CC_GREATER_THAN ((0x3) << 2) #define OBCR_BP_0(x) ((x)<<2) #define OBCR_BP_1(x) ((x)<<6) enum once_reg_idx { ONCE_REG_IDX_OSCR = 0, ONCE_REG_IDX_OMBC = 1, ONCE_REG_IDX_OBCR = 2, ONCE_REG_IDX_OMLR0 = 3, ONCE_REG_IDX_OMLR1 = 4, ONCE_REG_IDX_OGDBR = 5, ONCE_REG_IDX_OPDBR = 6, ONCE_REG_IDX_OPILR = 7, ONCE_REG_IDX_PDB = 8, ONCE_REG_IDX_OTC = 9, ONCE_REG_IDX_OPABFR = 10, ONCE_REG_IDX_OPABDR = 11, ONCE_REG_IDX_OPABEX = 12, ONCE_REG_IDX_OPABF0 = 13, ONCE_REG_IDX_OPABF1 = 14, ONCE_REG_IDX_OPABF2 = 15, ONCE_REG_IDX_OPABF3 = 16, ONCE_REG_IDX_OPABF4 = 17, ONCE_REG_IDX_OPABF5 = 18, ONCE_REG_IDX_OPABF6 = 19, ONCE_REG_IDX_OPABF7 = 20, ONCE_REG_IDX_OPABF8 = 21, ONCE_REG_IDX_OPABF9 = 22, ONCE_REG_IDX_OPABF10 = 23, ONCE_REG_IDX_OPABF11 = 24, }; static struct once_reg once_regs[] = { {ONCE_REG_IDX_OSCR, DSP563XX_ONCE_OSCR, 24, "OSCR", 0}, {ONCE_REG_IDX_OMBC, DSP563XX_ONCE_OMBC, 24, "OMBC", 0}, {ONCE_REG_IDX_OBCR, DSP563XX_ONCE_OBCR, 24, "OBCR", 0}, {ONCE_REG_IDX_OMLR0, DSP563XX_ONCE_OMLR0, 24, "OMLR0", 0}, {ONCE_REG_IDX_OMLR1, DSP563XX_ONCE_OMLR1, 24, "OMLR1", 0}, {ONCE_REG_IDX_OGDBR, DSP563XX_ONCE_OGDBR, 24, "OGDBR", 0}, {ONCE_REG_IDX_OPDBR, DSP563XX_ONCE_OPDBR, 24, "OPDBR", 0}, {ONCE_REG_IDX_OPILR, DSP563XX_ONCE_OPILR, 24, "OPILR", 0}, {ONCE_REG_IDX_PDB, DSP563XX_ONCE_PDBGOTO, 24, "PDB", 0}, {ONCE_REG_IDX_OTC, DSP563XX_ONCE_OTC, 24, "OTC", 0}, {ONCE_REG_IDX_OPABFR, DSP563XX_ONCE_OPABFR, 24, "OPABFR", 0}, {ONCE_REG_IDX_OPABDR, DSP563XX_ONCE_OPABDR, 24, "OPABDR", 0}, {ONCE_REG_IDX_OPABEX, DSP563XX_ONCE_OPABEX, 24, "OPABEX", 0}, {ONCE_REG_IDX_OPABF0, DSP563XX_ONCE_OPABF11, 25, "OPABF0", 0}, {ONCE_REG_IDX_OPABF1, DSP563XX_ONCE_OPABF11, 25, "OPABF1", 0}, {ONCE_REG_IDX_OPABF2, DSP563XX_ONCE_OPABF11, 25, "OPABF2", 0}, {ONCE_REG_IDX_OPABF3, DSP563XX_ONCE_OPABF11, 25, "OPABF3", 0}, {ONCE_REG_IDX_OPABF4, DSP563XX_ONCE_OPABF11, 25, "OPABF4", 0}, {ONCE_REG_IDX_OPABF5, DSP563XX_ONCE_OPABF11, 25, "OPABF5", 0}, {ONCE_REG_IDX_OPABF6, DSP563XX_ONCE_OPABF11, 25, "OPABF6", 0}, {ONCE_REG_IDX_OPABF7, DSP563XX_ONCE_OPABF11, 25, "OPABF7", 0}, {ONCE_REG_IDX_OPABF8, DSP563XX_ONCE_OPABF11, 25, "OPABF8", 0}, {ONCE_REG_IDX_OPABF9, DSP563XX_ONCE_OPABF11, 25, "OPABF9", 0}, {ONCE_REG_IDX_OPABF10, DSP563XX_ONCE_OPABF11, 25, "OPABF10", 0}, {ONCE_REG_IDX_OPABF11, DSP563XX_ONCE_OPABF11, 25, "OPABF11", 0}, /* {25,0x1f,24,"NRSEL",0}, */ }; enum dsp563xx_reg_idx { DSP563XX_REG_IDX_R0 = 0, DSP563XX_REG_IDX_R1 = 1, DSP563XX_REG_IDX_R2 = 2, DSP563XX_REG_IDX_R3 = 3, DSP563XX_REG_IDX_R4 = 4, DSP563XX_REG_IDX_R5 = 5, DSP563XX_REG_IDX_R6 = 6, DSP563XX_REG_IDX_R7 = 7, DSP563XX_REG_IDX_N0 = 8, DSP563XX_REG_IDX_N1 = 9, DSP563XX_REG_IDX_N2 = 10, DSP563XX_REG_IDX_N3 = 11, DSP563XX_REG_IDX_N4 = 12, DSP563XX_REG_IDX_N5 = 13, DSP563XX_REG_IDX_N6 = 14, DSP563XX_REG_IDX_N7 = 15, DSP563XX_REG_IDX_M0 = 16, DSP563XX_REG_IDX_M1 = 17, DSP563XX_REG_IDX_M2 = 18, DSP563XX_REG_IDX_M3 = 19, DSP563XX_REG_IDX_M4 = 20, DSP563XX_REG_IDX_M5 = 21, DSP563XX_REG_IDX_M6 = 22, DSP563XX_REG_IDX_M7 = 23, DSP563XX_REG_IDX_X0 = 24, DSP563XX_REG_IDX_X1 = 25, DSP563XX_REG_IDX_Y0 = 26, DSP563XX_REG_IDX_Y1 = 27, DSP563XX_REG_IDX_A0 = 28, DSP563XX_REG_IDX_A1 = 29, DSP563XX_REG_IDX_A2 = 30, DSP563XX_REG_IDX_B0 = 31, DSP563XX_REG_IDX_B1 = 32, DSP563XX_REG_IDX_B2 = 33, DSP563XX_REG_IDX_SSH = 34, DSP563XX_REG_IDX_SSL = 35, DSP563XX_REG_IDX_SP = 36, DSP563XX_REG_IDX_EP = 37, DSP563XX_REG_IDX_SZ = 38, DSP563XX_REG_IDX_SC = 39, DSP563XX_REG_IDX_PC = 40, DSP563XX_REG_IDX_SR = 41, DSP563XX_REG_IDX_OMR = 42, DSP563XX_REG_IDX_LA = 43, DSP563XX_REG_IDX_LC = 44, DSP563XX_REG_IDX_VBA = 45, DSP563XX_REG_IDX_IPRC = 46, DSP563XX_REG_IDX_IPRP = 47, DSP563XX_REG_IDX_BCR = 48, DSP563XX_REG_IDX_DCR = 49, DSP563XX_REG_IDX_AAR0 = 50, DSP563XX_REG_IDX_AAR1 = 51, DSP563XX_REG_IDX_AAR2 = 52, DSP563XX_REG_IDX_AAR3 = 53, }; static const struct { unsigned id; const char *name; unsigned bits; /* effective addressing mode encoding */ uint8_t eame; uint32_t instr_mask; } dsp563xx_regs[] = { /* *INDENT-OFF* */ /* address registers */ {DSP563XX_REG_IDX_R0, "r0", 24, 0x10, ASM_REG_W_R0}, {DSP563XX_REG_IDX_R1, "r1", 24, 0x11, ASM_REG_W_R1}, {DSP563XX_REG_IDX_R2, "r2", 24, 0x12, ASM_REG_W_R2}, {DSP563XX_REG_IDX_R3, "r3", 24, 0x13, ASM_REG_W_R3}, {DSP563XX_REG_IDX_R4, "r4", 24, 0x14, ASM_REG_W_R4}, {DSP563XX_REG_IDX_R5, "r5", 24, 0x15, ASM_REG_W_R5}, {DSP563XX_REG_IDX_R6, "r6", 24, 0x16, ASM_REG_W_R6}, {DSP563XX_REG_IDX_R7, "r7", 24, 0x17, ASM_REG_W_R7}, /* offset registers */ {DSP563XX_REG_IDX_N0, "n0", 24, 0x18, ASM_REG_W_N0}, {DSP563XX_REG_IDX_N1, "n1", 24, 0x19, ASM_REG_W_N1}, {DSP563XX_REG_IDX_N2, "n2", 24, 0x1a, ASM_REG_W_N2}, {DSP563XX_REG_IDX_N3, "n3", 24, 0x1b, ASM_REG_W_N3}, {DSP563XX_REG_IDX_N4, "n4", 24, 0x1c, ASM_REG_W_N4}, {DSP563XX_REG_IDX_N5, "n5", 24, 0x1d, ASM_REG_W_N5}, {DSP563XX_REG_IDX_N6, "n6", 24, 0x1e, ASM_REG_W_N6}, {DSP563XX_REG_IDX_N7, "n7", 24, 0x1f, ASM_REG_W_N7}, /* modifier registers */ {DSP563XX_REG_IDX_M0, "m0", 24, 0x20, ASM_REG_W_M0}, {DSP563XX_REG_IDX_M1, "m1", 24, 0x21, ASM_REG_W_M1}, {DSP563XX_REG_IDX_M2, "m2", 24, 0x22, ASM_REG_W_M2}, {DSP563XX_REG_IDX_M3, "m3", 24, 0x23, ASM_REG_W_M3}, {DSP563XX_REG_IDX_M4, "m4", 24, 0x24, ASM_REG_W_M4}, {DSP563XX_REG_IDX_M5, "m5", 24, 0x25, ASM_REG_W_M5}, {DSP563XX_REG_IDX_M6, "m6", 24, 0x26, ASM_REG_W_M6}, {DSP563XX_REG_IDX_M7, "m7", 24, 0x27, ASM_REG_W_M7}, /* data alu input register */ {DSP563XX_REG_IDX_X0, "x0", 24, 0x04, ASM_REG_W_X0}, {DSP563XX_REG_IDX_X1, "x1", 24, 0x05, ASM_REG_W_X1}, {DSP563XX_REG_IDX_Y0, "y0", 24, 0x06, ASM_REG_W_Y0}, {DSP563XX_REG_IDX_Y1, "y1", 24, 0x07, ASM_REG_W_Y1}, /* data alu accumulator register */ {DSP563XX_REG_IDX_A0, "a0", 24, 0x08, ASM_REG_W_A0}, {DSP563XX_REG_IDX_A1, "a1", 24, 0x0c, ASM_REG_W_A1}, {DSP563XX_REG_IDX_A2, "a2", 8, 0x0a, ASM_REG_W_A2}, {DSP563XX_REG_IDX_B0, "b0", 24, 0x09, ASM_REG_W_B0}, {DSP563XX_REG_IDX_B1, "b1", 24, 0x0d, ASM_REG_W_B1}, {DSP563XX_REG_IDX_B2, "b2", 8, 0x0b, ASM_REG_W_B2}, /* stack */ {DSP563XX_REG_IDX_SSH, "ssh", 24, 0x3c, ASM_REG_W_SSH}, {DSP563XX_REG_IDX_SSL, "ssl", 24, 0x3d, ASM_REG_W_SSL}, {DSP563XX_REG_IDX_SP, "sp", 24, 0x3b, ASM_REG_W_SP}, {DSP563XX_REG_IDX_EP, "ep", 24, 0x2a, ASM_REG_W_EP}, {DSP563XX_REG_IDX_SZ, "sz", 24, 0x38, ASM_REG_W_SZ}, {DSP563XX_REG_IDX_SC, "sc", 24, 0x31, ASM_REG_W_SC}, /* system */ {DSP563XX_REG_IDX_PC, "pc", 24, 0x00, ASM_REG_W_PC}, {DSP563XX_REG_IDX_SR, "sr", 24, 0x39, ASM_REG_W_SR}, {DSP563XX_REG_IDX_OMR, "omr", 24, 0x3a, ASM_REG_W_OMR}, {DSP563XX_REG_IDX_LA, "la", 24, 0x3e, ASM_REG_W_LA}, {DSP563XX_REG_IDX_LC, "lc", 24, 0x3f, ASM_REG_W_LC}, /* interrupt */ {DSP563XX_REG_IDX_VBA, "vba", 24, 0x30, ASM_REG_W_VBA}, {DSP563XX_REG_IDX_IPRC, "iprc", 24, 0x00, ASM_REG_W_IPRC}, {DSP563XX_REG_IDX_IPRP, "iprp", 24, 0x00, ASM_REG_W_IPRP}, /* port a */ {DSP563XX_REG_IDX_BCR, "bcr", 24, 0x00, ASM_REG_W_BCR}, {DSP563XX_REG_IDX_DCR, "dcr", 24, 0x00, ASM_REG_W_DCR}, {DSP563XX_REG_IDX_AAR0, "aar0", 24, 0x00, ASM_REG_W_AAR0}, {DSP563XX_REG_IDX_AAR1, "aar1", 24, 0x00, ASM_REG_W_AAR1}, {DSP563XX_REG_IDX_AAR2, "aar2", 24, 0x00, ASM_REG_W_AAR2}, {DSP563XX_REG_IDX_AAR3, "aar3", 24, 0x00, ASM_REG_W_AAR3}, /* *INDENT-ON* */ }; enum memory_type { MEM_X = 0, MEM_Y = 1, MEM_P = 2, MEM_L = 3, }; enum watchpoint_condition { EQUAL, NOT_EQUAL, GREATER, LESS_THAN }; #define INSTR_JUMP 0x0AF080 /* Effective Addressing Mode Encoding */ #define EAME_R0 0x10 /* instruction encoder */ /* movep * s - peripheral space X/Y (X=0,Y=1) * w - write/read * d - source/destination register * p - IO short address */ #define INSTR_MOVEP_REG_HIO(s, w, d, p) (0x084000 | \ ((s & 1) << 16) | ((w & 1) << 15) | ((d & 0x3f) << 8) | (p & 0x3f)) /* the gdb register list is send in this order */ static const uint8_t gdb_reg_list_idx[] = { DSP563XX_REG_IDX_X1, DSP563XX_REG_IDX_X0, DSP563XX_REG_IDX_Y1, DSP563XX_REG_IDX_Y0, DSP563XX_REG_IDX_A2, DSP563XX_REG_IDX_A1, DSP563XX_REG_IDX_A0, DSP563XX_REG_IDX_B2, DSP563XX_REG_IDX_B1, DSP563XX_REG_IDX_B0, DSP563XX_REG_IDX_PC, DSP563XX_REG_IDX_SR, DSP563XX_REG_IDX_OMR, DSP563XX_REG_IDX_LA, DSP563XX_REG_IDX_LC, DSP563XX_REG_IDX_SSH, DSP563XX_REG_IDX_SSL, DSP563XX_REG_IDX_SP, DSP563XX_REG_IDX_EP, DSP563XX_REG_IDX_SZ, DSP563XX_REG_IDX_SC, DSP563XX_REG_IDX_VBA, DSP563XX_REG_IDX_IPRC, DSP563XX_REG_IDX_IPRP, DSP563XX_REG_IDX_BCR, DSP563XX_REG_IDX_DCR, DSP563XX_REG_IDX_AAR0, DSP563XX_REG_IDX_AAR1, DSP563XX_REG_IDX_AAR2, DSP563XX_REG_IDX_AAR3, DSP563XX_REG_IDX_R0, DSP563XX_REG_IDX_R1, DSP563XX_REG_IDX_R2, DSP563XX_REG_IDX_R3, DSP563XX_REG_IDX_R4, DSP563XX_REG_IDX_R5, DSP563XX_REG_IDX_R6, DSP563XX_REG_IDX_R7, DSP563XX_REG_IDX_N0, DSP563XX_REG_IDX_N1, DSP563XX_REG_IDX_N2, DSP563XX_REG_IDX_N3, DSP563XX_REG_IDX_N4, DSP563XX_REG_IDX_N5, DSP563XX_REG_IDX_N6, DSP563XX_REG_IDX_N7, DSP563XX_REG_IDX_M0, DSP563XX_REG_IDX_M1, DSP563XX_REG_IDX_M2, DSP563XX_REG_IDX_M3, DSP563XX_REG_IDX_M4, DSP563XX_REG_IDX_M5, DSP563XX_REG_IDX_M6, DSP563XX_REG_IDX_M7, }; static int dsp563xx_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { int i; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; *reg_list_size = DSP563XX_NUMCOREREGS; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); if (!*reg_list) return ERROR_COMMAND_SYNTAX_ERROR; for (i = 0; i < DSP563XX_NUMCOREREGS; i++) (*reg_list)[i] = &dsp563xx->core_cache->reg_list[gdb_reg_list_idx[i]]; return ERROR_OK; } static int dsp563xx_read_core_reg(struct target *target, int num) { uint32_t reg_value; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if ((num < 0) || (num >= DSP563XX_NUMCOREREGS)) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = dsp563xx->core_regs[num]; buf_set_u32(dsp563xx->core_cache->reg_list[num].value, 0, 32, reg_value); dsp563xx->core_cache->reg_list[num].valid = true; dsp563xx->core_cache->reg_list[num].dirty = false; return ERROR_OK; } static int dsp563xx_write_core_reg(struct target *target, int num) { uint32_t reg_value; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if ((num < 0) || (num >= DSP563XX_NUMCOREREGS)) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = buf_get_u32(dsp563xx->core_cache->reg_list[num].value, 0, 32); dsp563xx->core_regs[num] = reg_value; dsp563xx->core_cache->reg_list[num].valid = true; dsp563xx->core_cache->reg_list[num].dirty = false; return ERROR_OK; } static int dsp563xx_get_core_reg(struct reg *reg) { struct dsp563xx_core_reg *dsp563xx_reg = reg->arch_info; struct target *target = dsp563xx_reg->target; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); LOG_DEBUG("%s", __func__); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; return dsp563xx->read_core_reg(target, dsp563xx_reg->num); } static int dsp563xx_set_core_reg(struct reg *reg, uint8_t *buf) { LOG_DEBUG("%s", __func__); struct dsp563xx_core_reg *dsp563xx_reg = reg->arch_info; struct target *target = dsp563xx_reg->target; uint32_t value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; buf_set_u32(reg->value, 0, reg->size, value); reg->dirty = true; reg->valid = true; return ERROR_OK; } static const struct reg_arch_type dsp563xx_reg_type = { .get = dsp563xx_get_core_reg, .set = dsp563xx_set_core_reg, }; static void dsp563xx_build_reg_cache(struct target *target) { struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(DSP563XX_NUMCOREREGS, sizeof(struct reg)); struct dsp563xx_core_reg *arch_info = malloc( sizeof(struct dsp563xx_core_reg) * DSP563XX_NUMCOREREGS); int i; /* Build the process context cache */ cache->name = "dsp563xx registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = DSP563XX_NUMCOREREGS; (*cache_p) = cache; dsp563xx->core_cache = cache; for (i = 0; i < DSP563XX_NUMCOREREGS; i++) { arch_info[i].num = dsp563xx_regs[i].id; arch_info[i].name = dsp563xx_regs[i].name; arch_info[i].size = dsp563xx_regs[i].bits; arch_info[i].eame = dsp563xx_regs[i].eame; arch_info[i].instr_mask = dsp563xx_regs[i].instr_mask; arch_info[i].target = target; arch_info[i].dsp563xx_common = dsp563xx; reg_list[i].name = dsp563xx_regs[i].name; reg_list[i].size = 32; /* dsp563xx_regs[i].bits; */ reg_list[i].value = calloc(1, 4); reg_list[i].dirty = false; reg_list[i].valid = false; reg_list[i].exist = true; reg_list[i].type = &dsp563xx_reg_type; reg_list[i].arch_info = &arch_info[i]; } } static int dsp563xx_read_register(struct target *target, int num, int force); static int dsp563xx_write_register(struct target *target, int num, int force); static int dsp563xx_reg_read_high_io(struct target *target, uint32_t instr_mask, uint32_t *data) { int err; uint32_t instr; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); /* we use r0 to store temporary data */ if (!dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].valid) dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_R0); /* move source memory to r0 */ instr = INSTR_MOVEP_REG_HIO(MEM_X, 0, EAME_R0, instr_mask); err = dsp563xx_once_execute_sw_ir(target->tap, 0, instr); if (err != ERROR_OK) return err; /* move r0 to debug register */ instr = INSTR_MOVEP_REG_HIO(MEM_X, 1, EAME_R0, 0xfffffc); err = dsp563xx_once_execute_sw_ir(target->tap, 1, instr); if (err != ERROR_OK) return err; /* read debug register */ err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OGDBR, data); if (err != ERROR_OK) return err; /* r0 is no longer valid on target */ dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].dirty = true; return ERROR_OK; } static int dsp563xx_reg_write_high_io(struct target *target, uint32_t instr_mask, uint32_t data) { int err; uint32_t instr; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); /* we use r0 to store temporary data */ if (!dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].valid) dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_R0); /* move data to r0 */ err = dsp563xx_once_execute_dw_ir(target->tap, 0, 0x60F400, data); if (err != ERROR_OK) return err; /* move r0 to destination memory */ instr = INSTR_MOVEP_REG_HIO(MEM_X, 1, EAME_R0, instr_mask); err = dsp563xx_once_execute_sw_ir(target->tap, 1, instr); if (err != ERROR_OK) return err; /* r0 is no longer valid on target */ dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].dirty = true; return ERROR_OK; } static int dsp563xx_reg_read(struct target *target, uint32_t eame, uint32_t *data) { int err; uint32_t instr; instr = INSTR_MOVEP_REG_HIO(MEM_X, 1, eame, 0xfffffc); err = dsp563xx_once_execute_sw_ir(target->tap, 0, instr); if (err != ERROR_OK) return err; /* nop */ err = dsp563xx_once_execute_sw_ir(target->tap, 1, 0x000000); if (err != ERROR_OK) return err; /* read debug register */ return dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OGDBR, data); } static int dsp563xx_reg_write(struct target *target, uint32_t instr_mask, uint32_t data) { int err; err = dsp563xx_once_execute_dw_ir(target->tap, 0, instr_mask, data); if (err != ERROR_OK) return err; /* nop */ return dsp563xx_once_execute_sw_ir(target->tap, 1, 0x000000); } static int dsp563xx_reg_pc_read(struct target *target) { struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); /* pc was changed, nothing todo */ if (dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_PC].dirty) return ERROR_OK; /* conditional branch check */ if (once_regs[ONCE_REG_IDX_OPABDR].reg == once_regs[ONCE_REG_IDX_OPABEX].reg) { if ((once_regs[ONCE_REG_IDX_OPABF11].reg & 1) == 0) { LOG_DEBUG("%s conditional branch not supported yet (0x%" PRIx32 " 0x%" PRIx32 " 0x%" PRIx32 ")", __func__, (once_regs[ONCE_REG_IDX_OPABF11].reg >> 1), once_regs[ONCE_REG_IDX_OPABDR].reg, once_regs[ONCE_REG_IDX_OPABEX].reg); /* TODO: use disassembly to set correct pc offset * read 2 words from OPABF11 and disasm the instruction */ dsp563xx->core_regs[DSP563XX_REG_IDX_PC] = (once_regs[ONCE_REG_IDX_OPABF11].reg >> 1) & 0x00FFFFFF; } else { if (once_regs[ONCE_REG_IDX_OPABEX].reg == once_regs[ONCE_REG_IDX_OPABFR].reg) dsp563xx->core_regs[DSP563XX_REG_IDX_PC] = once_regs[ONCE_REG_IDX_OPABEX].reg; else dsp563xx->core_regs[DSP563XX_REG_IDX_PC] = once_regs[ONCE_REG_IDX_OPABEX].reg - 1; } } else dsp563xx->core_regs[DSP563XX_REG_IDX_PC] = once_regs[ONCE_REG_IDX_OPABEX].reg; dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_PC); return ERROR_OK; } static int dsp563xx_reg_ssh_read(struct target *target) { int err; uint32_t sp; struct dsp563xx_core_reg *arch_info; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSH].arch_info; /* get a valid stack pointer */ err = dsp563xx_read_register(target, DSP563XX_REG_IDX_SP, 0); if (err != ERROR_OK) return err; sp = dsp563xx->core_regs[DSP563XX_REG_IDX_SP]; err = dsp563xx_write_register(target, DSP563XX_REG_IDX_SP, 0); if (err != ERROR_OK) return err; /* get a valid stack count */ err = dsp563xx_read_register(target, DSP563XX_REG_IDX_SC, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_register(target, DSP563XX_REG_IDX_SC, 0); if (err != ERROR_OK) return err; /* get a valid extended pointer */ err = dsp563xx_read_register(target, DSP563XX_REG_IDX_EP, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_register(target, DSP563XX_REG_IDX_EP, 0); if (err != ERROR_OK) return err; if (!sp) sp = 0x00FFFFFF; else { err = dsp563xx_reg_read(target, arch_info->eame, &sp); if (err != ERROR_OK) return err; err = dsp563xx_write_register(target, DSP563XX_REG_IDX_SC, 1); if (err != ERROR_OK) return err; err = dsp563xx_write_register(target, DSP563XX_REG_IDX_SP, 1); if (err != ERROR_OK) return err; err = dsp563xx_write_register(target, DSP563XX_REG_IDX_EP, 1); if (err != ERROR_OK) return err; } dsp563xx->core_regs[DSP563XX_REG_IDX_SSH] = sp; dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_SSH); return ERROR_OK; } static int dsp563xx_reg_ssh_write(struct target *target) { int err; uint32_t sp; struct dsp563xx_core_reg *arch_info; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSH].arch_info; /* get a valid stack pointer */ err = dsp563xx_read_register(target, DSP563XX_REG_IDX_SP, 0); if (err != ERROR_OK) return err; sp = dsp563xx->core_regs[DSP563XX_REG_IDX_SP]; if (sp) { sp--; /* write new stackpointer */ dsp563xx->core_regs[DSP563XX_REG_IDX_SP] = sp; err = dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_SP); if (err != ERROR_OK) return err; err = dsp563xx_write_register(target, DSP563XX_REG_IDX_SP, 1); if (err != ERROR_OK) return err; err = dsp563xx_reg_write(target, arch_info->instr_mask, dsp563xx->core_regs[DSP563XX_REG_IDX_SSH]); if (err != ERROR_OK) return err; err = dsp563xx_read_register(target, DSP563XX_REG_IDX_SP, 1); if (err != ERROR_OK) return err; err = dsp563xx_read_register(target, DSP563XX_REG_IDX_SSH, 1); if (err != ERROR_OK) return err; } return ERROR_OK; } static int dsp563xx_reg_ssl_read(struct target *target) { int err; uint32_t sp; struct dsp563xx_core_reg *arch_info; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSL].arch_info; /* get a valid stack pointer */ err = dsp563xx_read_register(target, DSP563XX_REG_IDX_SP, 0); if (err != ERROR_OK) return err; sp = dsp563xx->core_regs[DSP563XX_REG_IDX_SP]; if (!sp) sp = 0x00FFFFFF; else { err = dsp563xx_reg_read(target, arch_info->eame, &sp); if (err != ERROR_OK) return err; } dsp563xx->core_regs[DSP563XX_REG_IDX_SSL] = sp; dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_SSL); return ERROR_OK; } static int dsp563xx_read_register(struct target *target, int num, int force) { int err = ERROR_OK; uint32_t data = 0; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); struct dsp563xx_core_reg *arch_info; if (force) dsp563xx->core_cache->reg_list[num].valid = false; if (!dsp563xx->core_cache->reg_list[num].valid) { arch_info = dsp563xx->core_cache->reg_list[num].arch_info; switch (arch_info->num) { case DSP563XX_REG_IDX_SSH: err = dsp563xx_reg_ssh_read(target); break; case DSP563XX_REG_IDX_SSL: err = dsp563xx_reg_ssl_read(target); break; case DSP563XX_REG_IDX_PC: err = dsp563xx_reg_pc_read(target); break; case DSP563XX_REG_IDX_IPRC: case DSP563XX_REG_IDX_IPRP: case DSP563XX_REG_IDX_BCR: case DSP563XX_REG_IDX_DCR: case DSP563XX_REG_IDX_AAR0: case DSP563XX_REG_IDX_AAR1: case DSP563XX_REG_IDX_AAR2: case DSP563XX_REG_IDX_AAR3: err = dsp563xx_reg_read_high_io(target, arch_info->instr_mask, &data); if (err == ERROR_OK) { dsp563xx->core_regs[num] = data; dsp563xx->read_core_reg(target, num); } break; default: err = dsp563xx_reg_read(target, arch_info->eame, &data); if (err == ERROR_OK) { dsp563xx->core_regs[num] = data; dsp563xx->read_core_reg(target, num); } break; } } return err; } static int dsp563xx_write_register(struct target *target, int num, int force) { int err = ERROR_OK; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); struct dsp563xx_core_reg *arch_info; if (force) dsp563xx->core_cache->reg_list[num].dirty = true; if (dsp563xx->core_cache->reg_list[num].dirty) { arch_info = dsp563xx->core_cache->reg_list[num].arch_info; dsp563xx->write_core_reg(target, num); switch (arch_info->num) { case DSP563XX_REG_IDX_SSH: err = dsp563xx_reg_ssh_write(target); break; case DSP563XX_REG_IDX_PC: /* pc is updated on resume, no need to write it here */ break; case DSP563XX_REG_IDX_IPRC: case DSP563XX_REG_IDX_IPRP: case DSP563XX_REG_IDX_BCR: case DSP563XX_REG_IDX_DCR: case DSP563XX_REG_IDX_AAR0: case DSP563XX_REG_IDX_AAR1: case DSP563XX_REG_IDX_AAR2: case DSP563XX_REG_IDX_AAR3: err = dsp563xx_reg_write_high_io(target, arch_info->instr_mask, dsp563xx->core_regs[num]); break; default: err = dsp563xx_reg_write(target, arch_info->instr_mask, dsp563xx->core_regs[num]); if ((err == ERROR_OK) && (arch_info->num == DSP563XX_REG_IDX_SP)) { dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSH].valid = 0; dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSL].valid = 0; } break; } } return err; } static int dsp563xx_save_context(struct target *target) { int i, err = ERROR_OK; for (i = 0; i < DSP563XX_NUMCOREREGS; i++) { err = dsp563xx_read_register(target, i, 0); if (err != ERROR_OK) break; } return err; } static int dsp563xx_restore_context(struct target *target) { int i, err = ERROR_OK; for (i = 0; i < DSP563XX_NUMCOREREGS; i++) { err = dsp563xx_write_register(target, i, 0); if (err != ERROR_OK) break; } return err; } static void dsp563xx_invalidate_x_context(struct target *target, uint32_t addr_start, uint32_t addr_end) { int i; struct dsp563xx_core_reg *arch_info; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (addr_start > ASM_REG_W_IPRC) return; if (addr_start < ASM_REG_W_AAR3) return; for (i = DSP563XX_REG_IDX_IPRC; i < DSP563XX_NUMCOREREGS; i++) { arch_info = dsp563xx->core_cache->reg_list[i].arch_info; if ((arch_info->instr_mask >= addr_start) && (arch_info->instr_mask <= addr_end)) { dsp563xx->core_cache->reg_list[i].valid = false; dsp563xx->core_cache->reg_list[i].dirty = false; } } } static int dsp563xx_target_create(struct target *target, Jim_Interp *interp) { struct dsp563xx_common *dsp563xx = calloc(1, sizeof(struct dsp563xx_common)); if (!dsp563xx) return ERROR_COMMAND_SYNTAX_ERROR; dsp563xx->jtag_info.tap = target->tap; target->arch_info = dsp563xx; dsp563xx->read_core_reg = dsp563xx_read_core_reg; dsp563xx->write_core_reg = dsp563xx_write_core_reg; return ERROR_OK; } static int dsp563xx_init_target(struct command_context *cmd_ctx, struct target *target) { LOG_DEBUG("%s", __func__); dsp563xx_build_reg_cache(target); struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); dsp563xx->hardware_breakpoints_cleared = false; dsp563xx->hardware_breakpoint[0].used = BPU_NONE; return ERROR_OK; } static int dsp563xx_examine(struct target *target) { uint32_t chip; if (target->tap->hasidcode == false) { LOG_ERROR("no IDCODE present on device"); return ERROR_COMMAND_SYNTAX_ERROR; } if (!target_was_examined(target)) { target_set_examined(target); /* examine core and chip derivate number */ chip = (target->tap->idcode>>12) & 0x3ff; /* core number 0 means DSP563XX */ if (((chip>>5)&0x1f) == 0) chip += 300; LOG_INFO("DSP56%03" PRIu32 " device found", chip); /* Clear all breakpoints */ dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OBCR, 0); } return ERROR_OK; } static int dsp563xx_arch_state(struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } #define DSP563XX_SR_SA (1<<17) #define DSP563XX_SR_SC (1<<13) static int dsp563xx_debug_once_init(struct target *target) { return dsp563xx_once_read_register(target->tap, 1, once_regs, DSP563XX_NUMONCEREGS); } static int dsp563xx_debug_init(struct target *target) { int err; uint32_t sr; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); struct dsp563xx_core_reg *arch_info; err = dsp563xx_debug_once_init(target); if (err != ERROR_OK) return err; arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SR].arch_info; /* check 24bit mode */ err = dsp563xx_read_register(target, DSP563XX_REG_IDX_SR, 0); if (err != ERROR_OK) return err; sr = dsp563xx->core_regs[DSP563XX_REG_IDX_SR]; if (sr & (DSP563XX_SR_SA | DSP563XX_SR_SC)) { sr &= ~(DSP563XX_SR_SA | DSP563XX_SR_SC); err = dsp563xx_once_execute_dw_ir(target->tap, 1, arch_info->instr_mask, sr); if (err != ERROR_OK) return err; dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SR].dirty = true; } err = dsp563xx_read_register(target, DSP563XX_REG_IDX_N0, 0); if (err != ERROR_OK) return err; err = dsp563xx_read_register(target, DSP563XX_REG_IDX_N1, 0); if (err != ERROR_OK) return err; err = dsp563xx_read_register(target, DSP563XX_REG_IDX_M0, 0); if (err != ERROR_OK) return err; err = dsp563xx_read_register(target, DSP563XX_REG_IDX_M1, 0); if (err != ERROR_OK) return err; if (dsp563xx->core_regs[DSP563XX_REG_IDX_N0] != 0x000000) { arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_N0].arch_info; err = dsp563xx_reg_write(target, arch_info->instr_mask, 0x000000); if (err != ERROR_OK) return err; } dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_N0].dirty = true; if (dsp563xx->core_regs[DSP563XX_REG_IDX_N1] != 0x000000) { arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_N1].arch_info; err = dsp563xx_reg_write(target, arch_info->instr_mask, 0x000000); if (err != ERROR_OK) return err; } dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_N1].dirty = true; if (dsp563xx->core_regs[DSP563XX_REG_IDX_M0] != 0xffffff) { arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_M0].arch_info; err = dsp563xx_reg_write(target, arch_info->instr_mask, 0xffffff); if (err != ERROR_OK) return err; } dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_M0].dirty = true; if (dsp563xx->core_regs[DSP563XX_REG_IDX_M1] != 0xffffff) { arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_M1].arch_info; err = dsp563xx_reg_write(target, arch_info->instr_mask, 0xffffff); if (err != ERROR_OK) return err; } dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_M1].dirty = true; err = dsp563xx_save_context(target); if (err != ERROR_OK) return err; return ERROR_OK; } static int dsp563xx_jtag_debug_request(struct target *target) { return dsp563xx_once_request_debug(target->tap, target->state == TARGET_RESET); } static int dsp563xx_poll(struct target *target) { int err; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); uint32_t once_status = 0; int state; state = dsp563xx_once_target_status(target->tap); if (state == TARGET_UNKNOWN) { target->state = state; LOG_ERROR("jtag status contains invalid mode value - communication failure"); return ERROR_TARGET_FAILURE; } err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OSCR, &once_status); if (err != ERROR_OK) return err; if ((once_status & DSP563XX_ONCE_OSCR_DEBUG_M) == DSP563XX_ONCE_OSCR_DEBUG_M) { if (target->state != TARGET_HALTED) { target->state = TARGET_HALTED; err = dsp563xx_debug_init(target); if (err != ERROR_OK) return err; if (once_status & (DSP563XX_ONCE_OSCR_MBO|DSP563XX_ONCE_OSCR_SWO)) target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); else target_call_event_callbacks(target, TARGET_EVENT_HALTED); LOG_DEBUG("target->state: %s (%" PRIx32 ")", target_state_name(target), once_status); LOG_INFO("halted: PC: 0x%" PRIx32, dsp563xx->core_regs[DSP563XX_REG_IDX_PC]); } } if (!dsp563xx->hardware_breakpoints_cleared) { err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OBCR, 0); if (err != ERROR_OK) return err; err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OMLR0, 0); if (err != ERROR_OK) return err; err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OMLR1, 0); if (err != ERROR_OK) return err; dsp563xx->hardware_breakpoints_cleared = true; } return ERROR_OK; } static int dsp563xx_halt(struct target *target) { int err; LOG_DEBUG("%s", __func__); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); err = dsp563xx_jtag_debug_request(target); if (err != ERROR_OK) return err; target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int dsp563xx_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { int err; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); /* check if pc was changed and resume want to execute the next address * if pc was changed from gdb or other interface we will * jump to this address and don't execute the next address * this will not affect the resume command with an address argument * because current is set to zero then */ if (current && dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_PC].dirty) { dsp563xx_write_core_reg(target, DSP563XX_REG_IDX_PC); address = dsp563xx->core_regs[DSP563XX_REG_IDX_PC]; current = 0; } LOG_DEBUG("%s %08X %08X", __func__, current, (unsigned) address); err = dsp563xx_restore_context(target); if (err != ERROR_OK) return err; register_cache_invalidate(dsp563xx->core_cache); if (current) { /* restore pipeline registers and go */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OPDBR, once_regs[ONCE_REG_IDX_OPILR].reg); if (err != ERROR_OK) return err; err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OPDBR | DSP563XX_ONCE_OCR_EX | DSP563XX_ONCE_OCR_GO, once_regs[ONCE_REG_IDX_OPDBR].reg); if (err != ERROR_OK) return err; } else { /* set to go register and jump */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OPDBR, INSTR_JUMP); if (err != ERROR_OK) return err; err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_PDBGOTO | DSP563XX_ONCE_OCR_EX | DSP563XX_ONCE_OCR_GO, address); if (err != ERROR_OK) return err; } target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); return ERROR_OK; } static int dsp563xx_step_ex(struct target *target, int current, uint32_t address, int handle_breakpoints, int steps) { int err; uint32_t once_status; uint32_t dr_in, cnt; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (target->state != TARGET_HALTED) { LOG_DEBUG("target was not halted"); return ERROR_OK; } /* check if pc was changed and step want to execute the next address * if pc was changed from gdb or other interface we will * jump to this address and don't execute the next address * this will not affect the step command with an address argument * because current is set to zero then */ if (current && dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_PC].dirty) { dsp563xx_write_core_reg(target, DSP563XX_REG_IDX_PC); address = dsp563xx->core_regs[DSP563XX_REG_IDX_PC]; current = 0; } LOG_DEBUG("%s %08X %08X", __func__, current, (unsigned) address); err = dsp563xx_jtag_debug_request(target); if (err != ERROR_OK) return err; err = dsp563xx_restore_context(target); if (err != ERROR_OK) return err; /* reset trace mode */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OSCR, 0x000000); if (err != ERROR_OK) return err; /* enable trace mode */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OSCR, DSP563XX_ONCE_OSCR_TME); if (err != ERROR_OK) return err; cnt = steps; /* on JUMP we need one extra cycle */ if (!current) cnt++; /* load step counter with N-1 */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OTC, cnt); if (err != ERROR_OK) return err; if (current) { /* restore pipeline registers and go */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OPDBR, once_regs[ONCE_REG_IDX_OPILR].reg); if (err != ERROR_OK) return err; err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OPDBR | DSP563XX_ONCE_OCR_EX | DSP563XX_ONCE_OCR_GO, once_regs[ONCE_REG_IDX_OPDBR].reg); if (err != ERROR_OK) return err; } else { /* set to go register and jump */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OPDBR, INSTR_JUMP); if (err != ERROR_OK) return err; err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_PDBGOTO | DSP563XX_ONCE_OCR_EX | DSP563XX_ONCE_OCR_GO, address); if (err != ERROR_OK) return err; } while (1) { err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OSCR, &once_status); if (err != ERROR_OK) return err; if (once_status & DSP563XX_ONCE_OSCR_TO) { err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OPABFR, &dr_in); if (err != ERROR_OK) return err; LOG_DEBUG("fetch: %08X", (unsigned) dr_in&0x00ffffff); err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OPABDR, &dr_in); if (err != ERROR_OK) return err; LOG_DEBUG("decode: %08X", (unsigned) dr_in&0x00ffffff); err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OPABEX, &dr_in); if (err != ERROR_OK) return err; LOG_DEBUG("execute: %08X", (unsigned) dr_in&0x00ffffff); /* reset trace mode */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OSCR, 0x000000); if (err != ERROR_OK) return err; register_cache_invalidate(dsp563xx->core_cache); err = dsp563xx_debug_init(target); if (err != ERROR_OK) return err; break; } } return ERROR_OK; } static int dsp563xx_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { int err; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } err = dsp563xx_step_ex(target, current, address, handle_breakpoints, 0); if (err != ERROR_OK) return err; target->debug_reason = DBG_REASON_SINGLESTEP; target_call_event_callbacks(target, TARGET_EVENT_HALTED); LOG_INFO("halted: PC: 0x%" PRIx32, dsp563xx->core_regs[DSP563XX_REG_IDX_PC]); return err; } static int dsp563xx_assert_reset(struct target *target) { int retval = 0; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_HAS_SRST) { /* default to asserting srst */ if (jtag_reset_config & RESET_SRST_PULLS_TRST) jtag_add_reset(1, 1); else jtag_add_reset(0, 1); } target->state = TARGET_RESET; jtag_add_sleep(5000); /* registers are now invalid */ register_cache_invalidate(dsp563xx->core_cache); if (target->reset_halt) { retval = target_halt(target); if (retval != ERROR_OK) return retval; } LOG_DEBUG("%s", __func__); return ERROR_OK; } static int dsp563xx_deassert_reset(struct target *target) { int err; /* deassert reset lines */ jtag_add_reset(0, 0); err = dsp563xx_poll(target); if (err != ERROR_OK) return err; if (target->reset_halt) { if (target->state == TARGET_HALTED) { /* after a reset the cpu jmp to the * reset vector and need 2 cycles to fill * the cache (fetch,decode,execute) */ err = dsp563xx_step_ex(target, 1, 0, 1, 1); if (err != ERROR_OK) return err; } } else target->state = TARGET_RUNNING; LOG_DEBUG("%s", __func__); return ERROR_OK; } static int dsp563xx_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { int i; int retval = ERROR_OK; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } for (i = 0; i < num_mem_params; i++) { if (mem_params[i].direction == PARAM_IN) continue; retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } for (i = 0; i < num_reg_params; i++) { if (reg_params[i].direction == PARAM_IN) continue; struct reg *reg = register_get_by_name(dsp563xx->core_cache, reg_params[i].reg_name, false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); continue; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); continue; } retval = dsp563xx_set_core_reg(reg, reg_params[i].value); if (retval != ERROR_OK) return retval; } /* exec */ retval = target_resume(target, 0, entry_point, 1, 1); if (retval != ERROR_OK) return retval; retval = target_wait_state(target, TARGET_HALTED, timeout_ms); if (retval != ERROR_OK) return retval; for (i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } for (i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(dsp563xx->core_cache, reg_params[i].reg_name, false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); continue; } if (reg->size != reg_params[i].size) { LOG_ERROR( "BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); continue; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } return ERROR_OK; } /* global command context from openocd.c */ extern struct command_context *global_cmd_ctx; static int dsp563xx_get_default_memory(void) { Jim_Interp *interp; Jim_Obj *memspace; char *c; if (!global_cmd_ctx) return MEM_P; interp = global_cmd_ctx->interp; if (!interp) return MEM_P; memspace = Jim_GetGlobalVariableStr(interp, "memspace", JIM_NONE); if (!memspace) return MEM_P; c = (char *)Jim_GetString(memspace, NULL); if (!c) return MEM_P; switch (c[0]) { case '1': return MEM_X; case '2': return MEM_Y; case '3': return MEM_L; default: break; } return MEM_P; } static int dsp563xx_read_memory_core(struct target *target, int mem_type, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int err; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); uint32_t i, x; uint32_t data, move_cmd = 0; uint8_t *b; LOG_DEBUG( "memtype: %d address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", mem_type, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } switch (mem_type) { case MEM_X: /* TODO: mark effected queued registers */ move_cmd = 0x61d800; break; case MEM_Y: move_cmd = 0x69d800; break; case MEM_P: move_cmd = 0x07d891; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } /* we use r0 to store temporary data */ if (!dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].valid) dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_R0); /* we use r1 to store temporary data */ if (!dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R1].valid) dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_R1); /* r0 is no longer valid on target */ dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].dirty = true; /* r1 is no longer valid on target */ dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R1].dirty = true; x = count; b = buffer; err = dsp563xx_once_execute_dw_ir(target->tap, 1, 0x60F400, address); if (err != ERROR_OK) return err; for (i = 0; i < x; i++) { err = dsp563xx_once_execute_sw_ir(target->tap, 0, move_cmd); if (err != ERROR_OK) return err; err = dsp563xx_once_execute_sw_ir(target->tap, 0, 0x08D13C); if (err != ERROR_OK) return err; err = dsp563xx_once_reg_read(target->tap, 0, DSP563XX_ONCE_OGDBR, (uint32_t *)(void *)b); if (err != ERROR_OK) return err; b += 4; } /* flush the jtag queue */ err = jtag_execute_queue(); if (err != ERROR_OK) return err; /* walk over the buffer and fix target endianness */ b = buffer; for (i = 0; i < x; i++) { data = buf_get_u32(b, 0, 32) & 0x00FFFFFF; /* LOG_DEBUG("R: %08X", *((uint32_t*)b)); */ target_buffer_set_u32(target, b, data); b += 4; } return ERROR_OK; } static int dsp563xx_read_memory(struct target *target, int mem_type, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int err; uint32_t i, i1; uint8_t *buffer_y, *buffer_x; /* if size equals zero we are called from target read memory * and have to handle the parameter here */ if ((size == 0) && (count != 0)) { size = count % 4; if (size) LOG_DEBUG("size is not aligned to 4 byte"); count = (count - size) / 4; size = 4; } /* we only support 4 byte aligned data */ if ((size != 4) || (!count)) return ERROR_COMMAND_SYNTAX_ERROR; if (mem_type != MEM_L) return dsp563xx_read_memory_core(target, mem_type, address, size, count, buffer); buffer_y = malloc(size * count); if (!buffer_y) return ERROR_COMMAND_SYNTAX_ERROR; buffer_x = malloc(size * count); if (!buffer_x) { free(buffer_y); return ERROR_COMMAND_SYNTAX_ERROR; } err = dsp563xx_read_memory_core(target, MEM_Y, address, size, count / 2, buffer_y); if (err != ERROR_OK) { free(buffer_y); free(buffer_x); return err; } err = dsp563xx_read_memory_core(target, MEM_X, address, size, count / 2, buffer_x); if (err != ERROR_OK) { free(buffer_y); free(buffer_x); return err; } for (i = 0, i1 = 0; i < count; i += 2, i1++) { buf_set_u32(buffer + i*sizeof(uint32_t), 0, 32, buf_get_u32(buffer_y + i1 * sizeof(uint32_t), 0, 32)); buf_set_u32(buffer + (i + 1) * sizeof(uint32_t), 0, 32, buf_get_u32(buffer_x + i1 * sizeof(uint32_t), 0, 32)); } free(buffer_y); free(buffer_x); return ERROR_OK; } static int dsp563xx_read_memory_default(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { return dsp563xx_read_memory(target, dsp563xx_get_default_memory(), address, size, count, buffer); } static int dsp563xx_read_buffer_default(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { return dsp563xx_read_memory(target, dsp563xx_get_default_memory(), address, size, 0, buffer); } static int dsp563xx_write_memory_core(struct target *target, int mem_type, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int err; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); uint32_t i, x; uint32_t data, move_cmd = 0; const uint8_t *b; LOG_DEBUG( "memtype: %d address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", mem_type, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } switch (mem_type) { case MEM_X: /* invalidate affected x registers */ dsp563xx_invalidate_x_context(target, address, address + count - 1); move_cmd = 0x615800; break; case MEM_Y: move_cmd = 0x695800; break; case MEM_P: move_cmd = 0x075891; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } /* we use r0 to store temporary data */ if (!dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].valid) dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_R0); /* we use r1 to store temporary data */ if (!dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R1].valid) dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_R1); /* r0 is no longer valid on target */ dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].dirty = true; /* r1 is no longer valid on target */ dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R1].dirty = true; x = count; b = buffer; err = dsp563xx_once_execute_dw_ir(target->tap, 1, 0x60F400, address); if (err != ERROR_OK) return err; for (i = 0; i < x; i++) { data = target_buffer_get_u32(target, b); /* LOG_DEBUG("W: %08X", data); */ data &= 0x00ffffff; err = dsp563xx_once_execute_dw_ir(target->tap, 0, 0x61F400, data); if (err != ERROR_OK) return err; err = dsp563xx_once_execute_sw_ir(target->tap, 0, move_cmd); if (err != ERROR_OK) return err; b += 4; } /* flush the jtag queue */ err = jtag_execute_queue(); if (err != ERROR_OK) return err; return ERROR_OK; } static int dsp563xx_write_memory(struct target *target, int mem_type, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int err; uint32_t i, i1; uint8_t *buffer_y, *buffer_x; /* if size equals zero we are called from target write memory * and have to handle the parameter here */ if ((size == 0) && (count != 0)) { size = count % 4; if (size) LOG_DEBUG("size is not aligned to 4 byte"); count = (count - size) / 4; size = 4; } /* we only support 4 byte aligned data */ if ((size != 4) || (!count)) return ERROR_COMMAND_SYNTAX_ERROR; if (mem_type != MEM_L) return dsp563xx_write_memory_core(target, mem_type, address, size, count, buffer); buffer_y = malloc(size * count); if (!buffer_y) return ERROR_COMMAND_SYNTAX_ERROR; buffer_x = malloc(size * count); if (!buffer_x) { free(buffer_y); return ERROR_COMMAND_SYNTAX_ERROR; } for (i = 0, i1 = 0; i < count; i += 2, i1++) { buf_set_u32(buffer_y + i1 * sizeof(uint32_t), 0, 32, buf_get_u32(buffer + i * sizeof(uint32_t), 0, 32)); buf_set_u32(buffer_x + i1 * sizeof(uint32_t), 0, 32, buf_get_u32(buffer + (i + 1) * sizeof(uint32_t), 0, 32)); } err = dsp563xx_write_memory_core(target, MEM_Y, address, size, count / 2, buffer_y); if (err != ERROR_OK) { free(buffer_y); free(buffer_x); return err; } err = dsp563xx_write_memory_core(target, MEM_X, address, size, count / 2, buffer_x); if (err != ERROR_OK) { free(buffer_y); free(buffer_x); return err; } free(buffer_y); free(buffer_x); return ERROR_OK; } static int dsp563xx_write_memory_default(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { return dsp563xx_write_memory(target, dsp563xx_get_default_memory(), address, size, count, buffer); } static int dsp563xx_write_buffer_default(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer) { return dsp563xx_write_memory(target, dsp563xx_get_default_memory(), address, size, 0, buffer); } /* * Exit with error here, because we support watchpoints over a custom command. * This is because the DSP has separate X,Y,P memspace which is not compatible to the * traditional watchpoint logic. */ static int dsp563xx_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* * @see dsp563xx_add_watchpoint */ static int dsp563xx_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } static int dsp563xx_add_custom_watchpoint(struct target *target, uint32_t address, uint32_t mem_type, enum watchpoint_rw rw, enum watchpoint_condition cond) { int err = ERROR_OK; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); bool was_running = false; /* Only set breakpoint when halted */ if (target->state != TARGET_HALTED) { dsp563xx_halt(target); was_running = true; } if (dsp563xx->hardware_breakpoint[0].used) { LOG_ERROR("Cannot add watchpoint. Hardware resource already used."); err = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } uint32_t obcr_value = 0; if (err == ERROR_OK) { obcr_value |= OBCR_B0_OR_B1; switch (mem_type) { case MEM_X: obcr_value |= OBCR_BP_MEM_X; break; case MEM_Y: obcr_value |= OBCR_BP_MEM_Y; break; case MEM_P: obcr_value |= OBCR_BP_MEM_P; break; default: LOG_ERROR("Unknown mem_type parameter (%" PRIu32 ")", mem_type); err = ERROR_TARGET_INVALID; } } if (err == ERROR_OK) { switch (rw) { case WPT_READ: obcr_value |= OBCR_BP_0(OBCR_BP_ON_READ); break; case WPT_WRITE: obcr_value |= OBCR_BP_0(OBCR_BP_ON_WRITE); break; case WPT_ACCESS: obcr_value |= OBCR_BP_0(OBCR_BP_ON_READ|OBCR_BP_ON_WRITE); break; default: LOG_ERROR("Unsupported write mode (%d)", rw); err = ERROR_TARGET_INVALID; } } if (err == ERROR_OK) { switch (cond) { case EQUAL: obcr_value |= OBCR_BP_0(OBCR_BP_CC_EQUAL); break; case NOT_EQUAL: obcr_value |= OBCR_BP_0(OBCR_BP_CC_NOT_EQUAL); break; case LESS_THAN: obcr_value |= OBCR_BP_0(OBCR_BP_CC_LESS_THAN); break; case GREATER: obcr_value |= OBCR_BP_0(OBCR_BP_CC_GREATER_THAN); break; default: LOG_ERROR("Unsupported condition code (%d)", cond); err = ERROR_TARGET_INVALID; } } if (err == ERROR_OK) err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OMLR0, address); if (err == ERROR_OK) err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OMLR1, 0x0); if (err == ERROR_OK) err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OBCR, obcr_value); if (err == ERROR_OK) { /* You should write the memory breakpoint counter to 0 */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OMBC, 0); } if (err == ERROR_OK) { /* You should write the memory breakpoint counter to 0 */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OTC, 0); } if (err == ERROR_OK) dsp563xx->hardware_breakpoint[0].used = BPU_WATCHPOINT; if (err == ERROR_OK && was_running) { /* Resume from current PC */ err = dsp563xx_resume(target, 1, 0x0, 0, 0); } return err; } static int dsp563xx_remove_custom_watchpoint(struct target *target) { int err = ERROR_OK; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (dsp563xx->hardware_breakpoint[0].used != BPU_WATCHPOINT) { LOG_ERROR("Cannot remove watchpoint, as no watchpoint is currently configured!"); err = ERROR_TARGET_INVALID; } if (err == ERROR_OK) { /* Clear watchpoint by clearing OBCR. */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OBCR, 0); } if (err == ERROR_OK) dsp563xx->hardware_breakpoint[0].used = BPU_NONE; return err; } COMMAND_HANDLER(dsp563xx_add_watchpoint_command) { int err = ERROR_OK; struct target *target = get_current_target(CMD_CTX); uint32_t mem_type = 0; switch (CMD_NAME[2]) { case 'x': mem_type = MEM_X; break; case 'y': mem_type = MEM_Y; break; case 'p': mem_type = MEM_P; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t address = 0; if (CMD_ARGC > 2) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address); enum watchpoint_condition cond; switch (CMD_ARGV[0][0]) { case '>': cond = GREATER; break; case '<': cond = LESS_THAN; break; case '=': cond = EQUAL; break; case '!': cond = NOT_EQUAL; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } enum watchpoint_rw rw; switch (CMD_ARGV[1][0]) { case 'r': rw = WPT_READ; break; case 'w': rw = WPT_WRITE; break; case 'a': rw = WPT_ACCESS; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } err = dsp563xx_add_custom_watchpoint(target, address, mem_type, rw, cond); return err; } /* Adding a breakpoint using the once breakpoint logic. * Note that this mechanism is a true hw breakpoint and is share between the watchpoint logic. * This means, you can only have one breakpoint/watchpoint at any time. */ static int dsp563xx_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { return dsp563xx_add_custom_watchpoint(target, breakpoint->address, MEM_P, WPT_READ, EQUAL); } static int dsp563xx_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { return dsp563xx_remove_custom_watchpoint(target); } COMMAND_HANDLER(dsp563xx_remove_watchpoint_command) { struct target *target = get_current_target(CMD_CTX); return dsp563xx_remove_custom_watchpoint(target); } COMMAND_HANDLER(dsp563xx_mem_command) { struct target *target = get_current_target(CMD_CTX); int err = ERROR_OK; int read_mem; uint32_t address = 0; uint32_t count = 1, i; uint32_t pattern = 0; uint32_t mem_type; uint8_t *buffer, *b; switch (CMD_NAME[1]) { case 'w': read_mem = 0; break; case 'd': read_mem = 1; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } switch (CMD_NAME[3]) { case 'x': mem_type = MEM_X; break; case 'y': mem_type = MEM_Y; break; case 'p': mem_type = MEM_P; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } if (CMD_ARGC > 0) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); if (read_mem == 0) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC > 1) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], pattern); if (CMD_ARGC > 2) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count); } if (read_mem == 1) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC > 1) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], count); } buffer = calloc(count, 4); if (read_mem == 1) { err = dsp563xx_read_memory(target, mem_type, address, sizeof(uint32_t), count, buffer); if (err == ERROR_OK) target_handle_md_output(CMD, target, address, sizeof(uint32_t), count, buffer); } else { b = buffer; for (i = 0; i < count; i++) { target_buffer_set_u32(target, b, pattern); b += 4; } err = dsp563xx_write_memory(target, mem_type, address, sizeof(uint32_t), count, buffer); } free(buffer); return err; } static const struct command_registration dsp563xx_command_handlers[] = { { .name = "mwwx", .handler = dsp563xx_mem_command, .mode = COMMAND_EXEC, .help = "write x memory words", .usage = "address value [count]", }, { .name = "mwwy", .handler = dsp563xx_mem_command, .mode = COMMAND_EXEC, .help = "write y memory words", .usage = "address value [count]", }, { .name = "mwwp", .handler = dsp563xx_mem_command, .mode = COMMAND_EXEC, .help = "write p memory words", .usage = "address value [count]", }, { .name = "mdwx", .handler = dsp563xx_mem_command, .mode = COMMAND_EXEC, .help = "display x memory words", .usage = "address [count]", }, { .name = "mdwy", .handler = dsp563xx_mem_command, .mode = COMMAND_EXEC, .help = "display y memory words", .usage = "address [count]", }, { .name = "mdwp", .handler = dsp563xx_mem_command, .mode = COMMAND_EXEC, .help = "display p memory words", .usage = "address [count]", }, /* * Watchpoint commands */ { .name = "wpp", .handler = dsp563xx_add_watchpoint_command, .mode = COMMAND_EXEC, .help = "Create p memspace watchpoint", .usage = "(>|<|=|!) (r|w|a) address", }, { .name = "wpx", .handler = dsp563xx_add_watchpoint_command, .mode = COMMAND_EXEC, .help = "Create x memspace watchpoint", .usage = "(>|<|=|!) (r|w|a) address", }, { .name = "wpy", .handler = dsp563xx_add_watchpoint_command, .mode = COMMAND_EXEC, .help = "Create y memspace watchpoint", .usage = "(>|<|=|!) (r|w|a) address", }, { .name = "rwpc", .handler = dsp563xx_remove_watchpoint_command, .mode = COMMAND_EXEC, .help = "remove watchpoint custom", .usage = "", }, COMMAND_REGISTRATION_DONE }; /** Holds methods for DSP563XX targets. */ struct target_type dsp563xx_target = { .name = "dsp563xx", .poll = dsp563xx_poll, .arch_state = dsp563xx_arch_state, .get_gdb_reg_list = dsp563xx_get_gdb_reg_list, .halt = dsp563xx_halt, .resume = dsp563xx_resume, .step = dsp563xx_step, .assert_reset = dsp563xx_assert_reset, .deassert_reset = dsp563xx_deassert_reset, .read_memory = dsp563xx_read_memory_default, .write_memory = dsp563xx_write_memory_default, .read_buffer = dsp563xx_read_buffer_default, .write_buffer = dsp563xx_write_buffer_default, .run_algorithm = dsp563xx_run_algorithm, .add_breakpoint = dsp563xx_add_breakpoint, .remove_breakpoint = dsp563xx_remove_breakpoint, .add_watchpoint = dsp563xx_add_watchpoint, .remove_watchpoint = dsp563xx_remove_watchpoint, .commands = dsp563xx_command_handlers, .target_create = dsp563xx_target_create, .init_target = dsp563xx_init_target, .examine = dsp563xx_examine, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/dsp563xx.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009-2011 by Mathias Kuester * * mkdorg@users.sourceforge.net * ***************************************************************************/ #ifndef OPENOCD_TARGET_DSP563XX_H #define OPENOCD_TARGET_DSP563XX_H #include <jtag/jtag.h> #include <target/dsp563xx_once.h> #define DSP563XX_NUMCOREREGS 54 #define DSP563XX_NUMONCEREGS 25 struct mcu_jtag { struct jtag_tap *tap; }; enum breakpoint_usage { BPU_NONE = 0, BPU_BREAKPOINT, BPU_WATCHPOINT }; struct hardware_breakpoint { enum breakpoint_usage used; }; struct dsp563xx_common { struct mcu_jtag jtag_info; struct reg_cache *core_cache; uint32_t core_regs[DSP563XX_NUMCOREREGS]; struct once_reg once_regs[DSP563XX_NUMONCEREGS]; /* register cache to processor synchronization */ int (*read_core_reg)(struct target *target, int num); int (*write_core_reg)(struct target *target, int num); struct hardware_breakpoint hardware_breakpoint[1]; /*Were the hardware breakpoints cleared on startup?*/ bool hardware_breakpoints_cleared; }; struct dsp563xx_core_reg { uint32_t num; const char *name; uint32_t size; uint8_t eame; uint32_t instr_mask; struct target *target; struct dsp563xx_common *dsp563xx_common; }; static inline struct dsp563xx_common *target_to_dsp563xx(struct target *target) { return target->arch_info; } #endif /* OPENOCD_TARGET_DSP563XX_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/dsp563xx_once.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by Mathias Kuester * * mkdorg@users.sourceforge.net * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jim.h> #include "target.h" #include "target_type.h" #include "register.h" #include "dsp563xx.h" #include "dsp563xx_once.h" #define JTAG_STATUS_STATIC_MASK 0x03 #define JTAG_STATUS_STATIC_VALUE 0x01 #define JTAG_STATUS_NORMAL 0x01 #define JTAG_STATUS_STOPWAIT 0x05 #define JTAG_STATUS_BUSY 0x09 #define JTAG_STATUS_DEBUG 0x0d #define JTAG_INSTR_EXTEST 0x00 #define JTAG_INSTR_SAMPLE_PRELOAD 0x01 #define JTAG_INSTR_IDCODE 0x02 #define JTAG_INSTR_HIZ 0x04 #define JTAG_INSTR_CLAMP 0x05 #define JTAG_INSTR_ENABLE_ONCE 0x06 #define JTAG_INSTR_DEBUG_REQUEST 0x07 #define JTAG_INSTR_BYPASS 0x0F /** */ static inline int dsp563xx_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_len, int rti) { jtag_add_plain_dr_scan(dr_len, dr_out, dr_in, TAP_IDLE); return ERROR_OK; } /** */ static inline int dsp563xx_write_dr_u8(struct jtag_tap *tap, uint8_t *dr_in, uint8_t dr_out, int dr_len, int rti) { return dsp563xx_write_dr(tap, dr_in, &dr_out, dr_len, rti); } /** */ static inline int dsp563xx_write_dr_u32(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int dr_len, int rti) { return dsp563xx_write_dr(tap, (uint8_t *) dr_in, (uint8_t *) &dr_out, dr_len, rti); } /** single word instruction */ static inline int dsp563xx_once_ir_exec(struct jtag_tap *tap, int flush, uint8_t instr, uint8_t rw, uint8_t go, uint8_t ex) { int err; err = dsp563xx_write_dr_u8(tap, NULL, instr | (ex << 5) | (go << 6) | (rw << 7), 8, 0); if (err != ERROR_OK) return err; if (flush) err = jtag_execute_queue(); return err; } /* IR and DR functions */ static inline int dsp563xx_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti) { jtag_add_plain_ir_scan(tap->ir_length, ir_out, ir_in, TAP_IDLE); return ERROR_OK; } static inline int dsp563xx_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti) { return dsp563xx_write_ir(tap, ir_in, &ir_out, ir_len, rti); } static inline int dsp563xx_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out) { return dsp563xx_write_ir_u8(tap, ir_in, ir_out, tap->ir_length, 1); } /** */ int dsp563xx_once_target_status(struct jtag_tap *tap) { int err; uint8_t jtag_status; err = dsp563xx_jtag_sendinstr(tap, &jtag_status, JTAG_INSTR_ENABLE_ONCE); if (err != ERROR_OK) return TARGET_UNKNOWN; err = jtag_execute_queue(); if (err != ERROR_OK) return TARGET_UNKNOWN; /* verify correct static status pattern */ if ((jtag_status & JTAG_STATUS_STATIC_MASK) != JTAG_STATUS_STATIC_VALUE) return TARGET_UNKNOWN; if (jtag_status != JTAG_STATUS_DEBUG) return TARGET_RUNNING; return TARGET_HALTED; } /** */ int dsp563xx_once_request_debug(struct jtag_tap *tap, int reset_state) { int err; uint8_t ir_in = 0, pattern = 0; uint32_t retry = 0; /* in reset state we only get a ACK * from the interface */ if (reset_state) pattern = 1; else pattern = JTAG_STATUS_DEBUG; /* wait until we get the ack */ while (ir_in != pattern) { err = dsp563xx_jtag_sendinstr(tap, &ir_in, JTAG_INSTR_DEBUG_REQUEST); if (err != ERROR_OK) return err; err = jtag_execute_queue(); if (err != ERROR_OK) return err; LOG_DEBUG("debug request: %02X", ir_in); if (retry++ == 100) return ERROR_TARGET_FAILURE; } /* we cant enable the once in reset state */ if (pattern == 1) return ERROR_OK; /* try to enable once */ retry = 0; ir_in = 0; while (ir_in != pattern) { err = dsp563xx_jtag_sendinstr(tap, &ir_in, JTAG_INSTR_ENABLE_ONCE); if (err != ERROR_OK) return err; err = jtag_execute_queue(); if (err != ERROR_OK) return err; LOG_DEBUG("enable once: %02X", ir_in); if (retry++ == 100) { LOG_DEBUG("error"); return ERROR_TARGET_FAILURE; } } if (ir_in != JTAG_STATUS_DEBUG) return ERROR_TARGET_FAILURE; return ERROR_OK; } /** once read registers */ int dsp563xx_once_read_register(struct jtag_tap *tap, int flush, struct once_reg *regs, int len) { int i; int err = ERROR_OK; for (i = 0; i < len; i++) { err = dsp563xx_once_reg_read_ex(tap, flush, regs[i].addr, regs[i].len, ®s[i].reg); if (err != ERROR_OK) return err; } if (flush) err = jtag_execute_queue(); return err; } /** once read register with register len */ int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t *data) { int err; err = dsp563xx_once_ir_exec(tap, 1, reg, 1, 0, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_dr_u32(tap, data, 0x00, len, 0); if (err != ERROR_OK) return err; if (flush) err = jtag_execute_queue(); return err; } /** once read register */ int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t *data) { int err; err = dsp563xx_once_ir_exec(tap, flush, reg, 1, 0, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_dr_u32(tap, data, 0x00, 24, 0); if (err != ERROR_OK) return err; if (flush) err = jtag_execute_queue(); return err; } /** once write register */ int dsp563xx_once_reg_write(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t data) { int err; err = dsp563xx_once_ir_exec(tap, flush, reg, 0, 0, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_dr_u32(tap, NULL, data, 24, 0); if (err != ERROR_OK) return err; if (flush) err = jtag_execute_queue(); return err; } /** single word instruction */ int dsp563xx_once_execute_sw_ir(struct jtag_tap *tap, int flush, uint32_t opcode) { int err; err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 1, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_dr_u32(tap, NULL, opcode, 24, 0); if (err != ERROR_OK) return err; if (flush) err = jtag_execute_queue(); return err; } /** double word instruction */ int dsp563xx_once_execute_dw_ir(struct jtag_tap *tap, int flush, uint32_t opcode, uint32_t operand) { int err; err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 0, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_dr_u32(tap, NULL, opcode, 24, 0); if (err != ERROR_OK) return err; if (flush) { err = jtag_execute_queue(); if (err != ERROR_OK) return err; } err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 1, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_dr_u32(tap, NULL, operand, 24, 0); if (err != ERROR_OK) return err; if (flush) { err = jtag_execute_queue(); if (err != ERROR_OK) return err; } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/dsp563xx_once.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2009 by Mathias Kuester * * mkdorg@users.sourceforge.net * ***************************************************************************/ #ifndef OPENOCD_TARGET_DSP563XX_ONCE_H #define OPENOCD_TARGET_DSP563XX_ONCE_H #include <jtag/jtag.h> #ifdef HAVE_CONFIG_H #include "config.h" #endif #define DSP563XX_ONCE_OCR_EX (1<<5) #define DSP563XX_ONCE_OCR_GO (1<<6) #define DSP563XX_ONCE_OCR_RW (1<<7) #define DSP563XX_ONCE_OSCR_OS1 (1<<7) #define DSP563XX_ONCE_OSCR_OS0 (1<<6) #define DSP563XX_ONCE_OSCR_HIT (1<<5) #define DSP563XX_ONCE_OSCR_TO (1<<4) #define DSP563XX_ONCE_OSCR_MBO (1<<3) #define DSP563XX_ONCE_OSCR_SWO (1<<2) #define DSP563XX_ONCE_OSCR_IME (1<<1) #define DSP563XX_ONCE_OSCR_TME (1<<0) #define DSP563XX_ONCE_OSCR_NORMAL_M (0) #define DSP563XX_ONCE_OSCR_STOPWAIT_M (DSP563XX_ONCE_OSCR_OS0) #define DSP563XX_ONCE_OSCR_BUSY_M (DSP563XX_ONCE_OSCR_OS1) #define DSP563XX_ONCE_OSCR_DEBUG_M (DSP563XX_ONCE_OSCR_OS0|DSP563XX_ONCE_OSCR_OS1) #define DSP563XX_ONCE_OSCR 0x000 /* status/ctrl reg. */ #define DSP563XX_ONCE_OMBC 0x001 /* memory breakp. reg. */ #define DSP563XX_ONCE_OBCR 0x002 /* breakp. ctrl reg */ #define DSP563XX_ONCE_OMLR0 0x005 /* memory limit reg */ #define DSP563XX_ONCE_OMLR1 0x006 /* memory limit reg */ #define DSP563XX_ONCE_OGDBR 0x009 /* gdb reg */ #define DSP563XX_ONCE_OPDBR 0x00A /* pdb reg */ #define DSP563XX_ONCE_OPILR 0x00B /* pil reg */ #define DSP563XX_ONCE_PDBGOTO 0x00C /* pdb to go reg */ #define DSP563XX_ONCE_OTC 0x00D /* trace cnt */ #define DSP563XX_ONCE_TAGB 0x00E /* tags buffer */ #define DSP563XX_ONCE_OPABFR 0x00F /* pab fetch reg */ #define DSP563XX_ONCE_OPABDR 0x010 /* pab decode reg */ #define DSP563XX_ONCE_OPABEX 0x011 /* pab exec reg */ #define DSP563XX_ONCE_OPABF11 0x012 /* trace buffer/inc ptr */ #define DSP563XX_ONCE_NOREG 0x01F /* no register selected */ struct once_reg { const uint8_t num; const uint8_t addr; const uint8_t len; const char *name; uint32_t reg; }; /** */ int dsp563xx_once_request_debug(struct jtag_tap *tap, int reset_state); /** */ int dsp563xx_once_target_status(struct jtag_tap *tap); /** once read registers */ int dsp563xx_once_read_register(struct jtag_tap *tap, int flush, struct once_reg *regs, int len); /** once read register */ int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t *data); /** once read register */ int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t *data); /** once write register */ int dsp563xx_once_reg_write(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t data); /** single word instruction */ int dsp563xx_once_execute_sw_ir(struct jtag_tap *tap, int flush, uint32_t opcode); /** double word instruction */ int dsp563xx_once_execute_dw_ir(struct jtag_tap *tap, int flush, uint32_t opcode, uint32_t operand); #endif /* OPENOCD_TARGET_DSP563XX_ONCE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/dsp5680xx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Rodrigo L. Rosa * * rodrigorosa.LG@gmail.com * * * * Based on dsp563xx_once.h written by Mathias Kuester * * mkdorg@users.sourceforge.net * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include "target_type.h" #include "dsp5680xx.h" static struct dsp5680xx_common dsp5680xx_context; #define _E "DSP5680XX_ERROR:%d\nAt:%s:%d:%s" #define err_check(r, c, m) if (r != ERROR_OK) {LOG_ERROR(_E, c, __func__, __LINE__, m); return r; } #define err_check_propagate(retval) if (retval != ERROR_OK) return retval; #define DEBUG_MSG "Debug mode be enabled to read mem." #define DEBUG_FAIL { err_check(ERROR_FAIL, DSP5680XX_ERROR_NOT_IN_DEBUG, DEBUG_MSG) } #define CHECK_DBG if (!dsp5680xx_context.debug_mode_enabled) DEBUG_FAIL #define HALT_MSG "Target must be halted." #define HALT_FAIL { err_check(ERROR_FAIL, DSP5680XX_ERROR_TARGET_RUNNING, HALT_MSG) } #define CHECK_HALT(target) if (target->state != TARGET_HALTED) HALT_FAIL #define check_halt_and_debug(target) { CHECK_HALT(target); CHECK_DBG; } static int dsp5680xx_execute_queue(void) { int retval; retval = jtag_execute_queue(); return retval; } /** * Reset state machine */ static int reset_jtag(void) { int retval; tap_state_t states[2]; const char *cp = "RESET"; states[0] = tap_state_by_name(cp); retval = jtag_add_statemove(states[0]); err_check_propagate(retval); retval = jtag_execute_queue(); err_check_propagate(retval); jtag_add_pathmove(0, states + 1); retval = jtag_execute_queue(); return retval; } static int dsp5680xx_drscan(struct target *target, uint8_t *d_in, uint8_t *d_out, int len) { /* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * *Inputs: * - d_in: This is the data that will be shifted into the JTAG DR reg. * - d_out: The data that will be shifted out of the JTAG DR reg will stored here * - len: Length of the data to be shifted to JTAG DR. * *Note: If d_out == NULL, discard incoming bits. * *-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */ int retval = ERROR_OK; if (!target->tap) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_INVALID_TAP, "Invalid tap"); } if (len > 32) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_DR_LEN_OVERFLOW, "dr_len overflow, maximum is 32"); } /* TODO what values of len are valid for jtag_add_plain_dr_scan? */ /* can i send as many bits as i want? */ /* is the casting necessary? */ jtag_add_plain_dr_scan(len, d_in, d_out, TAP_IDLE); if (dsp5680xx_context.flush) { retval = dsp5680xx_execute_queue(); err_check(retval, DSP5680XX_ERROR_JTAG_DRSCAN, "drscan failed!"); } if (d_out) LOG_DEBUG("Data read (%d bits): 0x%04X", len, *d_out); else LOG_DEBUG("Data read was discarded."); return retval; } /** * Test func * * @param target * @param d_in This is the data that will be shifted into the JTAG IR reg. * @param d_out The data that will be shifted out of the JTAG IR reg will be stored here. * @param ir_len Length of the data to be shifted to JTAG IR. * */ static int dsp5680xx_irscan(struct target *target, uint32_t *d_in, uint32_t *d_out, uint8_t ir_len) { int retval = ERROR_OK; uint16_t tap_ir_len = DSP5680XX_JTAG_MASTER_TAP_IRLEN; if (!target->tap) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_INVALID_TAP, "Invalid tap"); } if (ir_len != target->tap->ir_length) { if (target->tap->enabled) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_INVALID_IR_LEN, "Invalid irlen"); } else { struct jtag_tap *t = jtag_tap_by_string("dsp568013.chp"); if ((!t) || ((t->enabled) && (ir_len != tap_ir_len))) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_INVALID_IR_LEN, "Invalid irlen"); } } } jtag_add_plain_ir_scan(ir_len, (uint8_t *) d_in, (uint8_t *) d_out, TAP_IDLE); if (dsp5680xx_context.flush) { retval = dsp5680xx_execute_queue(); err_check(retval, DSP5680XX_ERROR_JTAG_IRSCAN, "irscan failed!"); } return retval; } static int dsp5680xx_jtag_status(struct target *target, uint8_t *status) { uint32_t read_from_ir; uint32_t instr; int retval; instr = JTAG_INSTR_ENABLE_ONCE; retval = dsp5680xx_irscan(target, &instr, &read_from_ir, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); if (status) *status = (uint8_t) read_from_ir; return ERROR_OK; } static int jtag_data_read(struct target *target, uint8_t *data_read, int num_bits) { uint32_t bogus_instr = 0; int retval = dsp5680xx_drscan(target, (uint8_t *) &bogus_instr, data_read, num_bits); LOG_DEBUG("Data read (%d bits): 0x%04X", num_bits, *data_read); /** TODO remove this or move to jtagio? */ return retval; } #define jtag_data_read8(target, data_read) jtag_data_read(target, data_read, 8) #define jtag_data_read16(target, data_read) jtag_data_read(target, data_read, 16) #define jtag_data_read32(target, data_read) jtag_data_read(target, data_read, 32) static uint32_t data_read_dummy; static int jtag_data_write(struct target *target, uint32_t instr, int num_bits, uint32_t *data_read) { int retval; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &data_read_dummy, num_bits); err_check_propagate(retval); if (data_read) *data_read = data_read_dummy; return retval; } #define jtag_data_write8(target, instr, data_read) jtag_data_write(target, instr, 8, data_read) #define jtag_data_write16(target, instr, data_read) jtag_data_write(target, instr, 16, data_read) #define jtag_data_write24(target, instr, data_read) jtag_data_write(target, instr, 24, data_read) #define jtag_data_write32(target, instr, data_read) jtag_data_write(target, instr, 32, data_read) /** * Executes EOnCE instruction. * * @param target * @param instr Instruction to execute. * @param rw * @param go * @param ex * @param eonce_status Value read from the EOnCE status register. * * @return */ static int eonce_instruction_exec_single(struct target *target, uint8_t instr, uint8_t rw, uint8_t go, uint8_t ex, uint8_t *eonce_status) { int retval; uint32_t dr_out_tmp; uint8_t instr_with_flags = instr | (rw << 7) | (go << 6) | (ex << 5); retval = jtag_data_write(target, instr_with_flags, 8, &dr_out_tmp); err_check_propagate(retval); if (eonce_status) *eonce_status = (uint8_t) dr_out_tmp; return retval; } /* wrappers for multi opcode instructions */ #define dsp5680xx_exe_1(target, oc1, oc2, oc3) dsp5680xx_exe1(target, oc1) #define dsp5680xx_exe_2(target, oc1, oc2, oc3) dsp5680xx_exe2(target, oc1, oc2) #define dsp5680xx_exe_3(target, oc1, oc2, oc3) dsp5680xx_exe3(target, oc1, oc2, oc3) #define dsp5680xx_exe_generic(t, words, oc1, oc2, oc3) dsp5680xx_exe_##words(t, oc1, oc2, oc3) /* Executes one word DSP instruction */ static int dsp5680xx_exe1(struct target *target, uint16_t opcode) { int retval; retval = eonce_instruction_exec_single(target, 0x04, 0, 1, 0, NULL); err_check_propagate(retval); retval = jtag_data_write16(target, opcode, NULL); err_check_propagate(retval); return retval; } /* Executes two word DSP instruction */ static int dsp5680xx_exe2(struct target *target, uint16_t opcode1, uint16_t opcode2) { int retval; retval = eonce_instruction_exec_single(target, 0x04, 0, 0, 0, NULL); err_check_propagate(retval); retval = jtag_data_write16(target, opcode1, NULL); err_check_propagate(retval); retval = eonce_instruction_exec_single(target, 0x04, 0, 1, 0, NULL); err_check_propagate(retval); retval = jtag_data_write16(target, opcode2, NULL); err_check_propagate(retval); return retval; } /* Executes three word DSP instruction */ static int dsp5680xx_exe3(struct target *target, uint16_t opcode1, uint16_t opcode2, uint16_t opcode3) { int retval; retval = eonce_instruction_exec_single(target, 0x04, 0, 0, 0, NULL); err_check_propagate(retval); retval = jtag_data_write16(target, opcode1, NULL); err_check_propagate(retval); retval = eonce_instruction_exec_single(target, 0x04, 0, 0, 0, NULL); err_check_propagate(retval); retval = jtag_data_write16(target, opcode2, NULL); err_check_propagate(retval); retval = eonce_instruction_exec_single(target, 0x04, 0, 1, 0, NULL); err_check_propagate(retval); retval = jtag_data_write16(target, opcode3, NULL); err_check_propagate(retval); return retval; } /* *--------------- Real-time data exchange --------------- * The EOnCE Transmit (OTX) and Receive (ORX) registers are data memory mapped, each with an upper * and lower 16 bit word. * Transmit and receive directions are defined from the core’s perspective. * The core writes to the Transmit register and reads the Receive register, and the host through * JTAG writes to the Receive register and reads the Transmit register. * Both registers have a combined data memory mapped OTXRXSR which provides indication when * each may be accessed. * ref: eonce_rev.1.0_0208081.pdf@36 */ /* writes data into upper ORx register of the target */ static int core_tx_upper_data(struct target *target, uint16_t data, uint32_t *eonce_status_low) { int retval; retval = eonce_instruction_exec_single(target, DSP5680XX_ONCE_ORX1, 0, 0, 0, NULL); err_check_propagate(retval); retval = jtag_data_write16(target, data, eonce_status_low); err_check_propagate(retval); return retval; } /* writes data into lower ORx register of the target */ #define CMD1 eonce_instruction_exec_single(target, DSP5680XX_ONCE_ORX, 0, 0, 0, NULL); #define CMD2 jtag_data_write16((t, data) #define core_tx_lower_data(t, data) PT1\ PT2 /** * * @param target * @param data_read: Returns the data read from the upper OTX register via JTAG. * @return: Returns an error code (see error code documentation) */ static int core_rx_upper_data(struct target *target, uint8_t *data_read) { int retval; retval = eonce_instruction_exec_single(target, DSP5680XX_ONCE_OTX1, 1, 0, 0, NULL); err_check_propagate(retval); retval = jtag_data_read16(target, data_read); err_check_propagate(retval); return retval; } /** * * @param target * @param data_read: Returns the data read from the lower OTX register via JTAG. * @return: Returns an error code (see error code documentation) */ static int core_rx_lower_data(struct target *target, uint8_t *data_read) { int retval; retval = eonce_instruction_exec_single(target, DSP5680XX_ONCE_OTX, 1, 0, 0, NULL); err_check_propagate(retval); retval = jtag_data_read16(target, data_read); err_check_propagate(retval); return retval; } /* *-- -- -- -- --- -- -- -- --- -- -- -- --- -- -- -- --- -- -- -- --- -- *-- -- -- -- --- -- -- -Core Instructions- -- -- -- --- -- -- -- --- -- *-- -- -- -- --- -- -- -- --- -- -- -- --- -- -- -- --- -- -- -- --- -- */ #define exe(a, b, c, d, e) dsp5680xx_exe_generic(a, b, c, d, e) /* move.l #value, r0 */ #define core_move_long_to_r0(target, value) exe(target, 3, 0xe418, value&0xffff, value>>16) /* move.l #value, n */ #define core_move_long_to_n(target, value) exe(target, 3, 0xe41e, value&0xffff, value>>16) /* move x:(r0), y0 */ #define core_move_at_r0_to_y0(target) exe(target, 1, 0xF514, 0, 0) /* move x:(r0), y1 */ #define core_move_at_r0_to_y1(target) exe(target, 1, 0xF714, 0, 0) /* move.l x:(r0), y */ #define core_move_long_at_r0_y(target) exe(target, 1, 0xF734, 0, 0) /* move y0, x:(r0) */ #define core_move_y0_at_r0(target) exe(target, 1, 0xd514, 0, 0) /* bfclr #value, x:(r0) */ #define eonce_bfclr_at_r0(target, value) exe(target, 2, 0x8040, value, 0) /* move #value, y0 */ #define core_move_value_to_y0(target, value) exe(target, 2, 0x8745, value, 0) /* move.w y0, x:(r0)+ */ #define core_move_y0_at_r0_inc(target) exe(target, 1, 0xd500, 0, 0) /* move.w y0, p:(r0)+ */ #define core_move_y0_at_pr0_inc(target) exe(target, 1, 0x8560, 0, 0) /* move.w p:(r0)+, y0 */ #define core_move_at_pr0_inc_to_y0(target) exe(target, 1, 0x8568, 0, 0) /* move.w p:(r0)+, y1 */ #define core_move_at_pr0_inc_to_y1(target) exe(target, 1, 0x8768, 0, 0) /* move.l #value, r2 */ #define core_move_long_to_r2(target, value) exe(target, 3, 0xe41A, value&0xffff, value>>16) /* move y0, x:(r2) */ #define core_move_y0_at_r2(target) exe(target, 1, 0xd516, 0, 0) /* move.w #<value>, x:(r2) */ #define core_move_value_at_r2(target, value) exe(target, 2, 0x8642, value, 0) /* move.w #<value>, x:(r0) */ #define core_move_value_at_r0(target, value) exe(target, 2, 0x8640, value, 0) /* move.w #<value>, x:(R2+<disp>) */ #define core_move_value_at_r2_disp(target, value, disp) exe(target, 3, 0x8646, value, disp) /* move.w x:(r2), Y0 */ #define core_move_at_r2_to_y0(target) exe(target, 1, 0xF516, 0, 0) /* move.w p:(r2)+, y0 */ #define core_move_at_pr2_inc_to_y0(target) exe(target, 1, 0x856A, 0, 0) /* move.l #value, r3 */ #define core_move_long_to_r1(target, value) exe(target, 3, 0xE419, value&0xffff, value>>16) /* move.l #value, r3 */ #define core_move_long_to_r3(target, value) exe(target, 3, 0xE41B, value&0xffff, value>>16) /* move.w y0, p:(r3)+ */ #define core_move_y0_at_pr3_inc(target) exe(target, 1, 0x8563, 0, 0) /* move.w y0, x:(r3) */ #define core_move_y0_at_r3(target) exe(target, 1, 0xD503, 0, 0) /* move.l #value, r4 */ #define core_move_long_to_r4(target, value) exe(target, 3, 0xE41C, value&0xffff, value>>16) /* move pc, r4 */ #define core_move_pc_to_r4(target) exe(target, 1, 0xE716, 0, 0) /* move.l r4, y */ #define core_move_r4_to_y(target) exe(target, 1, 0xe764, 0, 0) /* move.w p:(r0)+, y0 */ #define core_move_at_pr0_inc_to_y0(target) exe(target, 1, 0x8568, 0, 0) /* move.w x:(r0)+, y0 */ #define core_move_at_r0_inc_to_y0(target) exe(target, 1, 0xf500, 0, 0) /* move x:(r0), y0 */ #define core_move_at_r0_y0(target) exe(target, 1, 0xF514, 0, 0) /* nop */ #define eonce_nop(target) exe(target, 1, 0xe700, 0, 0) /* move.w x:(R2+<disp>), Y0 */ #define core_move_at_r2_disp_to_y0(target, disp) exe(target, 2, 0xF542, disp, 0) /* move.w y1, x:(r2) */ #define core_move_y1_at_r2(target) exe(target, 1, 0xd716, 0, 0) /* move.w y1, x:(r0) */ #define core_move_y1_at_r0(target) exe(target, 1, 0xd714, 0, 0) /* move.bp y0, x:(r0)+ */ #define core_move_byte_y0_at_r0(target) exe(target, 1, 0xd5a0, 0, 0) /* move.w y1, p:(r0)+ */ #define core_move_y1_at_pr0_inc(target) exe(target, 1, 0x8760, 0, 0) /* move.w y1, x:(r0)+ */ #define core_move_y1_at_r0_inc(target) exe(target, 1, 0xD700, 0, 0) /* move.l #value, y */ #define core_move_long_to_y(target, value) exe(target, 3, 0xe417, value&0xffff, value>>16) static int core_move_value_to_pc(struct target *target, uint32_t value) { check_halt_and_debug(target); int retval; retval = dsp5680xx_exe_generic(target, 3, 0xE71E, value & 0xffff, value >> 16); err_check_propagate(retval); return retval; } static int eonce_load_tx_rx_to_r0(struct target *target) { int retval; retval = core_move_long_to_r0(target, ((MC568013_EONCE_TX_RX_ADDR) + (MC568013_EONCE_OBASE_ADDR << 16))); return retval; } static int core_load_tx_rx_high_addr_to_r0(struct target *target) { int retval = 0; retval = core_move_long_to_r0(target, ((MC568013_EONCE_TX1_RX1_HIGH_ADDR) + (MC568013_EONCE_OBASE_ADDR << 16))); return retval; } static int dsp5680xx_read_core_reg(struct target *target, uint8_t reg_addr, uint16_t *data_read) { /* TODO implement a general version of this which matches what openocd uses. */ int retval; uint32_t dummy_data_to_shift_into_dr; retval = eonce_instruction_exec_single(target, reg_addr, 1, 0, 0, NULL); err_check_propagate(retval); retval = dsp5680xx_drscan(target, (uint8_t *) &dummy_data_to_shift_into_dr, (uint8_t *) data_read, 8); err_check_propagate(retval); LOG_DEBUG("Reg. data: 0x%02X.", *data_read); return retval; } static int eonce_read_status_reg(struct target *target, uint16_t *data) { int retval; retval = dsp5680xx_read_core_reg(target, DSP5680XX_ONCE_OSR, data); err_check_propagate(retval); return retval; } /** * Takes the core out of debug mode. * * @param target * @param eonce_status Data read from the EOnCE status register. * * @return */ static int eonce_exit_debug_mode(struct target *target, uint8_t *eonce_status) { int retval; retval = eonce_instruction_exec_single(target, 0x1F, 0, 0, 1, eonce_status); err_check_propagate(retval); return retval; } static int switch_tap(struct target *target, struct jtag_tap *master_tap, struct jtag_tap *core_tap) { int retval = ERROR_OK; uint32_t instr; uint32_t ir_out; /* not used, just to make jtag happy. */ if (!master_tap) { master_tap = jtag_tap_by_string("dsp568013.chp"); if (!master_tap) { retval = ERROR_FAIL; const char *msg = "Failed to get master tap."; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_MASTER, msg); } } if (!core_tap) { core_tap = jtag_tap_by_string("dsp568013.cpu"); if (!core_tap) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_CORE, "Failed to get core tap."); } } if (!(((int)master_tap->enabled) ^ ((int)core_tap->enabled))) { LOG_WARNING ("Master:%d\nCore:%d\nOnly 1 should be enabled.\n", (int)master_tap->enabled, (int)core_tap->enabled); } if (master_tap->enabled) { instr = 0x5; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_MASTER_TAP_IRLEN); err_check_propagate(retval); instr = 0x2; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 4); err_check_propagate(retval); core_tap->enabled = true; master_tap->enabled = false; } else { instr = 0x08; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); instr = 0x1; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 4); err_check_propagate(retval); core_tap->enabled = false; master_tap->enabled = true; } return retval; } /** * Puts the core into debug mode, enabling the EOnCE module. * This will not always work, eonce_enter_debug_mode executes much * more complicated routine, which is guaranteed to work, but requires * a reset. This will complicate comm with the flash module, since * after a reset clock divisors must be set again. * This implementation works most of the time, and is not accessible to the * user. * * @param target * @param eonce_status Data read from the EOnCE status register. * * @return */ static int eonce_enter_debug_mode_without_reset(struct target *target, uint16_t *eonce_status) { int retval; uint32_t instr = JTAG_INSTR_DEBUG_REQUEST; uint32_t ir_out; /* not used, just to make jtag happy.*/ /* Debug request #1 */ retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); /* Enable EOnCE module */ instr = JTAG_INSTR_ENABLE_ONCE; /* Two rounds of jtag 0x6 (enable eonce) to enable EOnCE. */ retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); if ((ir_out & JTAG_STATUS_MASK) == JTAG_STATUS_DEBUG) target->state = TARGET_HALTED; else { retval = ERROR_FAIL; err_check_propagate(retval); } /* Verify that debug mode is enabled */ uint16_t data_read_from_dr; retval = eonce_read_status_reg(target, &data_read_from_dr); err_check_propagate(retval); if ((data_read_from_dr & 0x30) == 0x30) { LOG_DEBUG("EOnCE successfully entered debug mode."); dsp5680xx_context.debug_mode_enabled = true; retval = ERROR_OK; } else { dsp5680xx_context.debug_mode_enabled = false; retval = ERROR_TARGET_FAILURE; /** *No error msg here, since there is still hope with full halting sequence */ err_check_propagate(retval); } if (eonce_status) *eonce_status = data_read_from_dr; return retval; } /** * Puts the core into debug mode, enabling the EOnCE module. * * @param target * @param eonce_status Data read from the EOnCE status register. * * @return */ static int eonce_enter_debug_mode(struct target *target, uint16_t *eonce_status) { int retval = ERROR_OK; uint32_t instr = JTAG_INSTR_DEBUG_REQUEST; uint32_t ir_out; /* not used, just to make jtag happy. */ uint16_t instr_16; uint16_t read_16; /* First try the easy way */ retval = eonce_enter_debug_mode_without_reset(target, eonce_status); if (retval == ERROR_OK) return retval; struct jtag_tap *tap_chp; struct jtag_tap *tap_cpu; tap_chp = jtag_tap_by_string("dsp568013.chp"); if (!tap_chp) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_MASTER, "Failed to get master tap."); } tap_cpu = jtag_tap_by_string("dsp568013.cpu"); if (!tap_cpu) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_CORE, "Failed to get master tap."); } /* Enable master tap */ tap_chp->enabled = true; tap_cpu->enabled = false; instr = MASTER_TAP_CMD_IDCODE; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_MASTER_TAP_IRLEN); err_check_propagate(retval); jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); /* Enable EOnCE module */ jtag_add_reset(0, 1); jtag_add_sleep(TIME_DIV_FREESCALE * 200 * 1000); instr = 0x0606ffff; /* This was selected experimentally. */ retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 32); err_check_propagate(retval); /* ir_out now hold tap idcode */ /* Enable core tap */ tap_chp->enabled = true; retval = switch_tap(target, tap_chp, tap_cpu); err_check_propagate(retval); instr = JTAG_INSTR_ENABLE_ONCE; /* Two rounds of jtag 0x6 (enable eonce) to enable EOnCE. */ retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); instr = JTAG_INSTR_DEBUG_REQUEST; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); instr_16 = 0x1; retval = dsp5680xx_drscan(target, (uint8_t *) &instr_16, (uint8_t *) &read_16, 8); err_check_propagate(retval); instr_16 = 0x20; retval = dsp5680xx_drscan(target, (uint8_t *) &instr_16, (uint8_t *) &read_16, 8); err_check_propagate(retval); jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); jtag_add_reset(0, 0); jtag_add_sleep(TIME_DIV_FREESCALE * 300 * 1000); instr = JTAG_INSTR_ENABLE_ONCE; /* Two rounds of jtag 0x6 (enable eonce) to enable EOnCE. */ for (int i = 0; i < 3; i++) { retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); } if ((ir_out & JTAG_STATUS_MASK) == JTAG_STATUS_DEBUG) target->state = TARGET_HALTED; else { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_HALT, "Failed to halt target."); } for (int i = 0; i < 3; i++) { instr_16 = 0x86; dsp5680xx_drscan(target, (uint8_t *) &instr_16, (uint8_t *) &read_16, 16); instr_16 = 0xff; dsp5680xx_drscan(target, (uint8_t *) &instr_16, (uint8_t *) &read_16, 16); } /* Verify that debug mode is enabled */ uint16_t data_read_from_dr; retval = eonce_read_status_reg(target, &data_read_from_dr); err_check_propagate(retval); if ((data_read_from_dr & 0x30) == 0x30) { LOG_DEBUG("EOnCE successfully entered debug mode."); dsp5680xx_context.debug_mode_enabled = true; retval = ERROR_OK; } else { const char *msg = "Failed to set EOnCE module to debug mode"; retval = ERROR_TARGET_FAILURE; err_check(retval, DSP5680XX_ERROR_ENTER_DEBUG_MODE, msg); } if (eonce_status) *eonce_status = data_read_from_dr; return retval; } /** * Reads the current value of the program counter and stores it. * * @param target * * @return */ static int eonce_pc_store(struct target *target) { uint8_t tmp[2]; int retval; retval = core_move_pc_to_r4(target); err_check_propagate(retval); retval = core_move_r4_to_y(target); err_check_propagate(retval); retval = eonce_load_tx_rx_to_r0(target); err_check_propagate(retval); retval = core_move_y0_at_r0(target); err_check_propagate(retval); retval = core_rx_lower_data(target, tmp); err_check_propagate(retval); LOG_USER("PC value: 0x%X%X\n", tmp[1], tmp[0]); dsp5680xx_context.stored_pc = (tmp[0] | (tmp[1] << 8)); return ERROR_OK; } static int dsp5680xx_target_create(struct target *target, Jim_Interp *interp) { struct dsp5680xx_common *dsp5680xx = calloc(1, sizeof(struct dsp5680xx_common)); target->arch_info = dsp5680xx; return ERROR_OK; } static int dsp5680xx_init_target(struct command_context *cmd_ctx, struct target *target) { dsp5680xx_context.stored_pc = 0; dsp5680xx_context.flush = 1; dsp5680xx_context.debug_mode_enabled = false; LOG_DEBUG("target initiated!"); /* TODO core tap must be enabled before running these commands, currently * this is done in the .cfg tcl script. */ return ERROR_OK; } static int dsp5680xx_arch_state(struct target *target) { LOG_USER("%s not implemented yet.", __func__); return ERROR_OK; } static int dsp5680xx_assert_reset(struct target *target) { target->state = TARGET_RESET; return ERROR_OK; } static int dsp5680xx_deassert_reset(struct target *target) { target->state = TARGET_RUNNING; return ERROR_OK; } static int dsp5680xx_halt(struct target *target) { int retval; uint16_t eonce_status = 0xbeef; if ((target->state == TARGET_HALTED) && (dsp5680xx_context.debug_mode_enabled)) { LOG_USER("Target already halted and in debug mode."); return ERROR_OK; } else { if (target->state == TARGET_HALTED) LOG_USER ("Target already halted, re attempting to enter debug mode."); } retval = eonce_enter_debug_mode(target, &eonce_status); err_check_propagate(retval); retval = eonce_pc_store(target); err_check_propagate(retval); if (dsp5680xx_context.debug_mode_enabled) { retval = eonce_pc_store(target); err_check_propagate(retval); } return retval; } static int dsp5680xx_poll(struct target *target) { int retval; uint8_t jtag_status; uint8_t eonce_status; uint16_t read_tmp; retval = dsp5680xx_jtag_status(target, &jtag_status); err_check_propagate(retval); if (jtag_status == JTAG_STATUS_DEBUG) if (target->state != TARGET_HALTED) { retval = eonce_enter_debug_mode(target, &read_tmp); err_check_propagate(retval); eonce_status = (uint8_t) read_tmp; if ((eonce_status & EONCE_STAT_MASK) != DSP5680XX_ONCE_OSCR_DEBUG_M) { const char *msg = "%s: Failed to put EOnCE in debug mode.Flash locked?..."; LOG_WARNING(msg, __func__); return ERROR_TARGET_FAILURE; } else { target->state = TARGET_HALTED; return ERROR_OK; } } if (jtag_status == JTAG_STATUS_NORMAL) { if (target->state == TARGET_RESET) { retval = dsp5680xx_halt(target); err_check_propagate(retval); retval = eonce_exit_debug_mode(target, &eonce_status); err_check_propagate(retval); if ((eonce_status & EONCE_STAT_MASK) != DSP5680XX_ONCE_OSCR_NORMAL_M) { const char *msg = "%s: JTAG running, but EOnCE run failed.Try resetting.."; LOG_WARNING(msg, __func__); return ERROR_TARGET_FAILURE; } else { target->state = TARGET_RUNNING; return ERROR_OK; } } if (target->state != TARGET_RUNNING) { retval = eonce_read_status_reg(target, &read_tmp); err_check_propagate(retval); eonce_status = (uint8_t) read_tmp; if ((eonce_status & EONCE_STAT_MASK) != DSP5680XX_ONCE_OSCR_NORMAL_M) { LOG_WARNING ("Inconsistent target status. Restart!"); return ERROR_TARGET_FAILURE; } } target->state = TARGET_RUNNING; return ERROR_OK; } if (jtag_status == JTAG_STATUS_DEAD) { LOG_ERROR ("%s: Cannot communicate with JTAG. Check connection...", __func__); target->state = TARGET_UNKNOWN; return ERROR_TARGET_FAILURE; } if (target->state == TARGET_UNKNOWN) { LOG_ERROR("%s: Target status invalid - communication failure", __func__); return ERROR_TARGET_FAILURE; } return ERROR_OK; } static int dsp5680xx_resume(struct target *target, int current, target_addr_t address, int hb, int d) { if (target->state == TARGET_RUNNING) { LOG_USER("Target already running."); return ERROR_OK; } int retval; uint8_t eonce_status; uint8_t jtag_status; if (dsp5680xx_context.debug_mode_enabled) { if (!current) { retval = core_move_value_to_pc(target, address); err_check_propagate(retval); } int retry = 20; while (retry-- > 1) { retval = eonce_exit_debug_mode(target, &eonce_status); err_check_propagate(retval); if (eonce_status == DSP5680XX_ONCE_OSCR_NORMAL_M) break; } if (retry == 0) { retval = ERROR_TARGET_FAILURE; err_check(retval, DSP5680XX_ERROR_EXIT_DEBUG_MODE, "Failed to exit debug mode..."); } else { target->state = TARGET_RUNNING; dsp5680xx_context.debug_mode_enabled = false; } LOG_DEBUG("EOnCE status: 0x%02X.", eonce_status); } else { /* * If debug mode was not enabled but target was halted, then it is most likely that * access to eonce registers is locked. * Reset target to make it run again. */ jtag_add_reset(0, 1); jtag_add_sleep(TIME_DIV_FREESCALE * 200 * 1000); retval = reset_jtag(); err_check(retval, DSP5680XX_ERROR_JTAG_RESET, "Failed to reset JTAG state machine"); jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); jtag_add_reset(0, 0); jtag_add_sleep(TIME_DIV_FREESCALE * 300 * 1000); retval = dsp5680xx_jtag_status(target, &jtag_status); err_check_propagate(retval); if ((jtag_status & JTAG_STATUS_MASK) == JTAG_STATUS_NORMAL) { target->state = TARGET_RUNNING; dsp5680xx_context.debug_mode_enabled = false; } else { retval = ERROR_TARGET_FAILURE; err_check(retval, DSP5680XX_ERROR_RESUME, "Failed to resume target"); } } return ERROR_OK; } /** * The value of @a address determines if it corresponds to P: (program) or X: (dat) memory. * If the address is over 0x200000 then it is considered X: memory, and @a pmem = 0. * The special case of 0xFFXXXX is not modified, since it allows to read out the * memory mapped EOnCE registers. * * @param address * @param pmem * * @return */ static int dsp5680xx_convert_address(uint32_t *address, int *pmem) { /* * Distinguish data memory (x) from program memory (p) by the address. * Addresses over S_FILE_DATA_OFFSET are considered (x) memory. */ if (*address >= S_FILE_DATA_OFFSET) { *pmem = 0; if (((*address) & 0xff0000) != 0xff0000) *address -= S_FILE_DATA_OFFSET; } return ERROR_OK; } static int dsp5680xx_read_16_single(struct target *t, uint32_t a, uint8_t *data_read, int r_pmem) { struct target *target = t; uint32_t address = a; int retval; retval = core_move_long_to_r0(target, address); err_check_propagate(retval); if (r_pmem) retval = core_move_at_pr0_inc_to_y0(target); else retval = core_move_at_r0_to_y0(target); err_check_propagate(retval); retval = eonce_load_tx_rx_to_r0(target); err_check_propagate(retval); retval = core_move_y0_at_r0(target); err_check_propagate(retval); /* at this point the data i want is at the reg eonce can read */ retval = core_rx_lower_data(target, data_read); err_check_propagate(retval); LOG_DEBUG("%s:Data read from 0x%06" PRIX32 ": 0x%02X%02X", __func__, address, data_read[1], data_read[0]); return retval; } static int dsp5680xx_read_32_single(struct target *t, uint32_t a, uint8_t *data_read, int r_pmem) { struct target *target = t; uint32_t address = a; int retval; address = (address & 0xFFFFF); /* Get data to an intermediate register */ retval = core_move_long_to_r0(target, address); err_check_propagate(retval); if (r_pmem) { retval = core_move_at_pr0_inc_to_y0(target); err_check_propagate(retval); retval = core_move_at_pr0_inc_to_y1(target); err_check_propagate(retval); } else { retval = core_move_at_r0_inc_to_y0(target); err_check_propagate(retval); retval = core_move_at_r0_to_y1(target); err_check_propagate(retval); } /* Get lower part of data to TX/RX */ retval = eonce_load_tx_rx_to_r0(target); err_check_propagate(retval); retval = core_move_y0_at_r0_inc(target); /* This also load TX/RX high to r0 */ err_check_propagate(retval); /* Get upper part of data to TX/RX */ retval = core_move_y1_at_r0(target); err_check_propagate(retval); /* at this point the data i want is at the reg eonce can read */ retval = core_rx_lower_data(target, data_read); err_check_propagate(retval); retval = core_rx_upper_data(target, data_read + 2); err_check_propagate(retval); return retval; } static int dsp5680xx_read(struct target *t, target_addr_t a, uint32_t size, uint32_t count, uint8_t *buf) { struct target *target = t; uint32_t address = a; uint8_t *buffer = buf; check_halt_and_debug(target); int retval = ERROR_OK; int pmem = 1; retval = dsp5680xx_convert_address(&address, &pmem); err_check_propagate(retval); dsp5680xx_context.flush = 0; int counter = FLUSH_COUNT_READ_WRITE; for (unsigned i = 0; i < count; i++) { if (--counter == 0) { dsp5680xx_context.flush = 1; counter = FLUSH_COUNT_READ_WRITE; } switch (size) { case 1: if (!(i % 2)) retval = dsp5680xx_read_16_single(target, address + i / 2, buffer + i, pmem); break; case 2: retval = dsp5680xx_read_16_single(target, address + i, buffer + 2 * i, pmem); break; case 4: retval = dsp5680xx_read_32_single(target, address + 2 * i, buffer + 4 * i, pmem); break; default: LOG_USER("%s: Invalid read size.", __func__); break; } err_check_propagate(retval); dsp5680xx_context.flush = 0; } dsp5680xx_context.flush = 1; retval = dsp5680xx_execute_queue(); err_check_propagate(retval); return retval; } static int dsp5680xx_write_16_single(struct target *t, uint32_t a, uint16_t data, uint8_t w_pmem) { struct target *target = t; uint32_t address = a; int retval = 0; retval = core_move_long_to_r0(target, address); err_check_propagate(retval); if (w_pmem) { retval = core_move_value_to_y0(target, data); err_check_propagate(retval); retval = core_move_y0_at_pr0_inc(target); err_check_propagate(retval); } else { retval = core_move_value_at_r0(target, data); err_check_propagate(retval); } return retval; } static int dsp5680xx_write_32_single(struct target *t, uint32_t a, uint32_t data, int w_pmem) { struct target *target = t; uint32_t address = a; int retval = ERROR_OK; retval = core_move_long_to_r0(target, address); err_check_propagate(retval); retval = core_move_long_to_y(target, data); err_check_propagate(retval); if (w_pmem) retval = core_move_y0_at_pr0_inc(target); else retval = core_move_y0_at_r0_inc(target); err_check_propagate(retval); if (w_pmem) retval = core_move_y1_at_pr0_inc(target); else retval = core_move_y1_at_r0_inc(target); err_check_propagate(retval); return retval; } static int dsp5680xx_write_8(struct target *t, uint32_t a, uint32_t c, const uint8_t *d, int pmem) { struct target *target = t; uint32_t address = a; uint32_t count = c; const uint8_t *data = d; int retval = 0; uint16_t data_16; uint32_t iter; int counter = FLUSH_COUNT_READ_WRITE; for (iter = 0; iter < count / 2; iter++) { if (--counter == 0) { dsp5680xx_context.flush = 1; counter = FLUSH_COUNT_READ_WRITE; } data_16 = (data[2 * iter] | (data[2 * iter + 1] << 8)); retval = dsp5680xx_write_16_single(target, address + iter, data_16, pmem); if (retval != ERROR_OK) { LOG_ERROR("%s: Could not write to p:0x%04" PRIX32, __func__, address); dsp5680xx_context.flush = 1; return retval; } dsp5680xx_context.flush = 0; } dsp5680xx_context.flush = 1; /* Only one byte left, let's not overwrite the other byte (mem is 16bit) */ /* Need to retrieve the part we do not want to overwrite. */ uint16_t data_old; if ((count == 1) || (count % 2)) { retval = dsp5680xx_read(target, address + iter, 1, 1, (uint8_t *) &data_old); err_check_propagate(retval); if (count == 1) data_old = (((data_old & 0xff) << 8) | data[0]); /* preserve upper byte */ else data_old = (((data_old & 0xff) << 8) | data[2 * iter + 1]); retval = dsp5680xx_write_16_single(target, address + iter, data_old, pmem); err_check_propagate(retval); } return retval; } static int dsp5680xx_write_16(struct target *t, uint32_t a, uint32_t c, const uint8_t *d, int pmem) { struct target *target = t; uint32_t address = a; uint32_t count = c; const uint8_t *data = d; int retval = ERROR_OK; uint32_t iter; int counter = FLUSH_COUNT_READ_WRITE; for (iter = 0; iter < count; iter++) { if (--counter == 0) { dsp5680xx_context.flush = 1; counter = FLUSH_COUNT_READ_WRITE; } retval = dsp5680xx_write_16_single(target, address + iter, data[iter], pmem); if (retval != ERROR_OK) { LOG_ERROR("%s: Could not write to p:0x%04" PRIX32, __func__, address); dsp5680xx_context.flush = 1; return retval; } dsp5680xx_context.flush = 0; } dsp5680xx_context.flush = 1; return retval; } static int dsp5680xx_write_32(struct target *t, uint32_t a, uint32_t c, const uint8_t *d, int pmem) { struct target *target = t; uint32_t address = a; uint32_t count = c; const uint8_t *data = d; int retval = ERROR_OK; uint32_t iter; int counter = FLUSH_COUNT_READ_WRITE; for (iter = 0; iter < count; iter++) { if (--counter == 0) { dsp5680xx_context.flush = 1; counter = FLUSH_COUNT_READ_WRITE; } retval = dsp5680xx_write_32_single(target, address + (iter << 1), data[iter], pmem); if (retval != ERROR_OK) { LOG_ERROR("%s: Could not write to p:0x%04" PRIX32, __func__, address); dsp5680xx_context.flush = 1; return retval; } dsp5680xx_context.flush = 0; } dsp5680xx_context.flush = 1; return retval; } /** * Writes @a buffer to memory. * The parameter @a address determines whether @a buffer should be written to * P: (program) memory or X: (dat) memory. * * @param target * @param a address * @param size Bytes (1), Half words (2), Words (4). * @param count In bytes. * @param b buffer * * @return */ static int dsp5680xx_write(struct target *target, target_addr_t a, uint32_t size, uint32_t count, const uint8_t *b) { /* TODO Cannot write 32bit to odd address, will write 0x12345678 as 0x5678 0x0012 */ uint32_t address = a; uint8_t const *buffer = b; check_halt_and_debug(target); int retval = 0; int p_mem = 1; retval = dsp5680xx_convert_address(&address, &p_mem); err_check_propagate(retval); switch (size) { case 1: retval = dsp5680xx_write_8(target, address, count, buffer, p_mem); break; case 2: retval = dsp5680xx_write_16(target, address, count, buffer, p_mem); break; case 4: retval = dsp5680xx_write_32(target, address, count, buffer, p_mem); break; default: retval = ERROR_TARGET_DATA_ABORT; err_check(retval, DSP5680XX_ERROR_INVALID_DATA_SIZE_UNIT, "Invalid data size."); break; } return retval; } static int dsp5680xx_write_buffer(struct target *t, target_addr_t a, uint32_t size, const uint8_t *b) { check_halt_and_debug(t); return dsp5680xx_write(t, a, 1, size, b); } /** * This function is called by verify_image, it is used to read data from memory. * * @param target * @param address Word addressing. * @param size In bytes. * @param buffer * * @return */ static int dsp5680xx_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { check_halt_and_debug(target); /* The "/2" solves the byte/word addressing issue.*/ return dsp5680xx_read(target, address, 2, size / 2, buffer); } /** * This function is not implemented. * It returns an error in order to get OpenOCD to do read out the data * and calculate the CRC, or try a binary comparison. * * @param target * @param address Start address of the image. * @param size In bytes. * @param checksum * * @return */ static int dsp5680xx_checksum_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t *checksum) { return ERROR_FAIL; } /** * Calculates a signature over @a word_count words in the data from @a buff8. * The algorithm used is the same the FM uses, so the @a return may be used to compare * with the one generated by the FM module, and check if flashing was successful. * This algorithm is based on the perl script available from the Freescale website at FAQ 25630. * * @param buff8 * @param word_count * * @return */ static int perl_crc(const uint8_t *buff8, uint32_t word_count) { uint16_t checksum = 0xffff; uint16_t data, fbmisr; uint32_t i; for (i = 0; i < word_count; i++) { data = (buff8[2 * i] | (buff8[2 * i + 1] << 8)); fbmisr = (checksum & 2) >> 1 ^ (checksum & 4) >> 2 ^ (checksum & 16) >> 4 ^ (checksum & 0x8000) >> 15; checksum = (data ^ ((checksum << 1) | fbmisr)); } i--; for (; !(i & 0x80000000); i--) { data = (buff8[2 * i] | (buff8[2 * i + 1] << 8)); fbmisr = (checksum & 2) >> 1 ^ (checksum & 4) >> 2 ^ (checksum & 16) >> 4 ^ (checksum & 0x8000) >> 15; checksum = (data ^ ((checksum << 1) | fbmisr)); } return checksum; } /** * Resets the SIM. (System Integration Modul). * * @param target * * @return */ static int dsp5680xx_f_sim_reset(struct target *target) { int retval = ERROR_OK; uint16_t sim_cmd = SIM_CMD_RESET; uint32_t sim_addr; if (strcmp(target->tap->chip, "dsp568013") == 0) { sim_addr = MC568013_SIM_BASE_ADDR + S_FILE_DATA_OFFSET; retval = dsp5680xx_write(target, sim_addr, 1, 2, (const uint8_t *)&sim_cmd); err_check_propagate(retval); } return retval; } /** * Halts the core and resets the SIM. (System Integration Modul). * * @param target * * @return */ static int dsp5680xx_soft_reset_halt(struct target *target) { /* TODO is this what this function is expected to do...? */ int retval; retval = dsp5680xx_halt(target); err_check_propagate(retval); retval = dsp5680xx_f_sim_reset(target); err_check_propagate(retval); return retval; } int dsp5680xx_f_protect_check(struct target *target, uint16_t *protected) { int retval; check_halt_and_debug(target); if (!protected) { const char *msg = "NULL pointer not valid."; err_check(ERROR_FAIL, DSP5680XX_ERROR_PROTECT_CHECK_INVALID_ARGS, msg); } retval = dsp5680xx_read_16_single(target, HFM_BASE_ADDR | HFM_PROT, (uint8_t *) protected, 0); err_check_propagate(retval); return retval; } /** * Executes a command on the FM module. * Some commands use the parameters @a address and @a data, others ignore them. * * @param target * @param c Command to execute. * @param address Command parameter. * @param data Command parameter. * @param hfm_ustat FM status register. * @param pmem Address is P: (program) memory (@a pmem == 1) or X: (dat) memory (@a pmem == 0) * * @return */ static int dsp5680xx_f_ex(struct target *target, uint16_t c, uint32_t address, uint32_t data, uint16_t *hfm_ustat, int pmem) { uint32_t command = c; int retval; retval = core_load_tx_rx_high_addr_to_r0(target); err_check_propagate(retval); retval = core_move_long_to_r2(target, HFM_BASE_ADDR); err_check_propagate(retval); uint8_t i[2]; int watchdog = 100; do { retval = core_move_at_r2_disp_to_y0(target, HFM_USTAT); /* read HMF_USTAT */ err_check_propagate(retval); retval = core_move_y0_at_r0(target); err_check_propagate(retval); retval = core_rx_upper_data(target, i); err_check_propagate(retval); if ((watchdog--) == 1) { retval = ERROR_TARGET_FAILURE; const char *msg = "Timed out waiting for FM to finish old command."; err_check(retval, DSP5680XX_ERROR_FM_BUSY, msg); } } while (!(i[0] & 0x40)); /* wait until current command is complete */ dsp5680xx_context.flush = 0; /* write to HFM_CNFG (lock=0,select bank) - flash_desc.bank&0x03, 0x01 == 0x00, 0x01 ??? */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_CNFG); err_check_propagate(retval); /* write to HMF_USTAT, clear PVIOL, ACCERR &BLANK bits */ retval = core_move_value_at_r2_disp(target, 0x04, HFM_USTAT); err_check_propagate(retval); /* clear only one bit at a time */ retval = core_move_value_at_r2_disp(target, 0x10, HFM_USTAT); err_check_propagate(retval); retval = core_move_value_at_r2_disp(target, 0x20, HFM_USTAT); err_check_propagate(retval); /* write to HMF_PROT, clear protection */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_PROT); err_check_propagate(retval); /* write to HMF_PROTB, clear protection */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_PROTB); err_check_propagate(retval); retval = core_move_value_to_y0(target, data); err_check_propagate(retval); /* write to the flash block */ retval = core_move_long_to_r3(target, address); err_check_propagate(retval); if (pmem) { retval = core_move_y0_at_pr3_inc(target); err_check_propagate(retval); } else { retval = core_move_y0_at_r3(target); err_check_propagate(retval); } /* write command to the HFM_CMD reg */ retval = core_move_value_at_r2_disp(target, command, HFM_CMD); err_check_propagate(retval); /* start the command */ retval = core_move_value_at_r2_disp(target, 0x80, HFM_USTAT); err_check_propagate(retval); dsp5680xx_context.flush = 1; retval = dsp5680xx_execute_queue(); err_check_propagate(retval); watchdog = 100; do { /* read HMF_USTAT */ retval = core_move_at_r2_disp_to_y0(target, HFM_USTAT); err_check_propagate(retval); retval = core_move_y0_at_r0(target); err_check_propagate(retval); retval = core_rx_upper_data(target, i); err_check_propagate(retval); if ((watchdog--) == 1) { retval = ERROR_TARGET_FAILURE; err_check(retval, DSP5680XX_ERROR_FM_CMD_TIMED_OUT, "FM execution did not finish."); } } while (!(i[0] & 0x40)); /* wait until the command is complete */ *hfm_ustat = ((i[0] << 8) | (i[1])); if (i[0] & HFM_USTAT_MASK_PVIOL_ACCER) { retval = ERROR_TARGET_FAILURE; const char *msg = "pviol and/or accer bits set. HFM command execution error"; err_check(retval, DSP5680XX_ERROR_FM_EXEC, msg); } return ERROR_OK; } /** * Prior to the execution of any Flash module command, the Flash module Clock * Divider (CLKDIV) register must be initialized. The values of this register * determine the speed of the internal Flash Clock (FCLK). FCLK must be in the * range of 150kHz ≤ FCLK ≤ 200kHz for proper operation of the Flash module. * (Running FCLK too slowly wears out the module, while running it too fast * under programs Flash leading to bit errors.) * * @param target * * @return */ static int set_fm_ck_div(struct target *target) { uint8_t i[2]; int retval; retval = core_move_long_to_r2(target, HFM_BASE_ADDR); err_check_propagate(retval); retval = core_load_tx_rx_high_addr_to_r0(target); err_check_propagate(retval); /* read HFM_CLKD */ retval = core_move_at_r2_to_y0(target); err_check_propagate(retval); retval = core_move_y0_at_r0(target); err_check_propagate(retval); retval = core_rx_upper_data(target, i); err_check_propagate(retval); unsigned int hfm_at_wrong_value = 0; if ((i[0] & 0x7f) != HFM_CLK_DEFAULT) { LOG_DEBUG("HFM CLK divisor contained incorrect value (0x%02X).", i[0] & 0x7f); hfm_at_wrong_value = 1; } else { LOG_DEBUG ("HFM CLK divisor was already set to correct value (0x%02X).", i[0] & 0x7f); return ERROR_OK; } /* write HFM_CLKD */ retval = core_move_value_at_r2(target, HFM_CLK_DEFAULT); err_check_propagate(retval); /* verify HFM_CLKD */ retval = core_move_at_r2_to_y0(target); err_check_propagate(retval); retval = core_move_y0_at_r0(target); err_check_propagate(retval); retval = core_rx_upper_data(target, i); err_check_propagate(retval); if (i[0] != (0x80 | (HFM_CLK_DEFAULT & 0x7f))) { retval = ERROR_TARGET_FAILURE; err_check(retval, DSP5680XX_ERROR_FM_SET_CLK, "Unable to set HFM CLK divisor."); } if (hfm_at_wrong_value) LOG_DEBUG("HFM CLK divisor set to 0x%02x.", i[0] & 0x7f); return ERROR_OK; } /** * Executes the FM calculate signature command. The FM will calculate over the * data from @a address to @a address + @a words -1. The result is written to a * register, then read out by this function and returned in @a signature. The * value @a signature may be compared to the one returned by perl_crc to * verify the flash was written correctly. * * @param target * @param address Start of flash array where the signature should be calculated. * @param words Number of words over which the signature should be calculated. * @param signature Value calculated by the FM. * * @return */ static int dsp5680xx_f_signature(struct target *target, uint32_t address, uint32_t words, uint16_t *signature) { int retval; uint16_t hfm_ustat; if (!dsp5680xx_context.debug_mode_enabled) { retval = eonce_enter_debug_mode_without_reset(target, NULL); /* * Generate error here, since it is not done in eonce_enter_debug_mode_without_reset */ err_check(retval, DSP5680XX_ERROR_HALT, "Failed to halt target."); } retval = dsp5680xx_f_ex(target, HFM_CALCULATE_DATA_SIGNATURE, address, words, &hfm_ustat, 1); err_check_propagate(retval); retval = dsp5680xx_read_16_single(target, HFM_BASE_ADDR | HFM_DATA, (uint8_t *) signature, 0); return retval; } int dsp5680xx_f_erase_check(struct target *target, uint8_t *erased, uint32_t sector) { int retval; uint16_t hfm_ustat; uint32_t tmp; if (!dsp5680xx_context.debug_mode_enabled) { retval = dsp5680xx_halt(target); err_check_propagate(retval); } retval = set_fm_ck_div(target); err_check_propagate(retval); /* * Check if chip is already erased. */ tmp = HFM_FLASH_BASE_ADDR + sector * HFM_SECTOR_SIZE / 2; retval = dsp5680xx_f_ex(target, HFM_ERASE_VERIFY, tmp, 0, &hfm_ustat, 1); err_check_propagate(retval); if (erased) *erased = (uint8_t) (hfm_ustat & HFM_USTAT_MASK_BLANK); return retval; } /** * Executes the FM page erase command. * * @param target * @param sector Page to erase. * @param hfm_ustat FM module status register. * * @return */ static int erase_sector(struct target *target, int sector, uint16_t *hfm_ustat) { int retval; uint32_t tmp = HFM_FLASH_BASE_ADDR + sector * HFM_SECTOR_SIZE / 2; retval = dsp5680xx_f_ex(target, HFM_PAGE_ERASE, tmp, 0, hfm_ustat, 1); err_check_propagate(retval); return retval; } /** * Executes the FM mass erase command. Erases the flash array completely. * * @param target * @param hfm_ustat FM module status register. * * @return */ static int mass_erase(struct target *target, uint16_t *hfm_ustat) { int retval; retval = dsp5680xx_f_ex(target, HFM_MASS_ERASE, 0, 0, hfm_ustat, 1); return retval; } int dsp5680xx_f_erase(struct target *target, int first, int last) { int retval; if (!dsp5680xx_context.debug_mode_enabled) { retval = dsp5680xx_halt(target); err_check_propagate(retval); } /* * Reset SIM * */ retval = dsp5680xx_f_sim_reset(target); err_check_propagate(retval); /* * Set hfmdiv * */ retval = set_fm_ck_div(target); err_check_propagate(retval); uint16_t hfm_ustat; int do_mass_erase = ((!(first | last)) || ((first == 0) && (last == (HFM_SECTOR_COUNT - 1)))); if (do_mass_erase) { /* Mass erase */ retval = mass_erase(target, &hfm_ustat); err_check_propagate(retval); } else { for (int i = first; i <= last; i++) { retval = erase_sector(target, i, &hfm_ustat); err_check_propagate(retval); } } return ERROR_OK; } /* * Algorithm for programming normal p: flash * Follow state machine from "56F801x Peripheral Reference Manual"@163. * Registers to set up before calling: * r0: TX/RX high address. * r2: FM module base address. * r3: Destination address in flash. * * hfm_wait: // wait for buffer empty * brclr #0x80, x:(r2+0x13), hfm_wait * rx_check: // wait for input buffer full * brclr #0x01, x:(r0-2), rx_check * move.w x:(r0), y0 // read from Rx buffer * move.w y0, p:(r3)+ * move.w #0x20, x:(r2+0x14) // write PGM command * move.w #0x80, x:(r2+0x13) // start the command * move.w X:(R2+0x13), A // Read USTAT register * brclr #0x20, A, accerr_check // protection violation check * bfset #0x20, X:(R2+0x13) // clear pviol * bra hfm_wait * accerr_check: * brclr #0x10, A, hfm_wait // access error check * bfset #0x10, X:(R2+0x13) // clear accerr * bra hfm_wait // loop * 0x00000000 0x8A460013807D brclr #0x80, X:(R2+0x13),*+0 * 0x00000003 0xE700 nop * 0x00000004 0xE700 nop * 0x00000005 0x8A44FFFE017B brclr #1, X:(R0-2),*-2 * 0x00000008 0xE700 nop * 0x00000009 0xF514 move.w X:(R0), Y0 * 0x0000000A 0x8563 move.w Y0, P:(R3)+ * 0x0000000B 0x864600200014 move.w #32, X:(R2+0x14) * 0x0000000E 0x864600800013 move.w #128, X:(R2+0x13) * 0x00000011 0xF0420013 move.w X:(R2+0x13), A * 0x00000013 0x8B402004 brclr #0x20, A,*+6 * 0x00000015 0x824600130020 bfset #0x20, X:(R2+0x13) * 0x00000018 0xA967 bra *-24 * 0x00000019 0x8B401065 brclr #0x10, A,*-25 * 0x0000001B 0x824600130010 bfset #0x10, X:(R2+0x13) * 0x0000001E 0xA961 bra *-30 */ static const uint16_t pgm_write_pflash[] = { 0x8A46, 0x0013, 0x807D, 0xE700, 0xE700, 0x8A44, 0xFFFE, 0x017B, 0xE700, 0xF514, 0x8563, 0x8646, 0x0020, 0x0014, 0x8646, 0x0080, 0x0013, 0xF042, 0x0013, 0x8B40, 0x2004, 0x8246, 0x0013, 0x0020, 0xA967, 0x8B40, 0x1065, 0x8246, 0x0013, 0x0010, 0xA961 }; static const uint32_t pgm_write_pflash_length = 31; int dsp5680xx_f_wr(struct target *t, const uint8_t *b, uint32_t a, uint32_t count, int is_flash_lock) { struct target *target = t; uint32_t address = a; const uint8_t *buffer = b; int retval = ERROR_OK; if (!dsp5680xx_context.debug_mode_enabled) { retval = eonce_enter_debug_mode(target, NULL); err_check_propagate(retval); } /* * Download the pgm that flashes. * */ const uint32_t len = pgm_write_pflash_length; uint32_t ram_addr = 0x8700; /* * This seems to be a safe address. * This one is the one used by codewarrior in 56801x_flash.cfg */ if (!is_flash_lock) { retval = dsp5680xx_write(target, ram_addr, 1, len * 2, (uint8_t *) pgm_write_pflash); err_check_propagate(retval); retval = dsp5680xx_execute_queue(); err_check_propagate(retval); } /* * Set hfmdiv * */ retval = set_fm_ck_div(target); err_check_propagate(retval); /* * Setup registers needed by pgm_write_pflash * */ dsp5680xx_context.flush = 0; retval = core_move_long_to_r3(target, address); /* Destination address to r3 */ err_check_propagate(retval); core_load_tx_rx_high_addr_to_r0(target); /* TX/RX reg address to r0 */ err_check_propagate(retval); retval = core_move_long_to_r2(target, HFM_BASE_ADDR); /* FM base address to r2 */ err_check_propagate(retval); /* * Run flashing program. * */ /* write to HFM_CNFG (lock=0, select bank) */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_CNFG); err_check_propagate(retval); /* write to HMF_USTAT, clear PVIOL, ACCERR &BLANK bits */ retval = core_move_value_at_r2_disp(target, 0x04, HFM_USTAT); err_check_propagate(retval); /* clear only one bit at a time */ retval = core_move_value_at_r2_disp(target, 0x10, HFM_USTAT); err_check_propagate(retval); retval = core_move_value_at_r2_disp(target, 0x20, HFM_USTAT); err_check_propagate(retval); /* write to HMF_PROT, clear protection */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_PROT); err_check_propagate(retval); /* write to HMF_PROTB, clear protection */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_PROTB); err_check_propagate(retval); if (count % 2) { /* TODO implement handling of odd number of words. */ retval = ERROR_FAIL; const char *msg = "Cannot handle odd number of words."; err_check(retval, DSP5680XX_ERROR_FLASHING_INVALID_WORD_COUNT, msg); } dsp5680xx_context.flush = 1; retval = dsp5680xx_execute_queue(); err_check_propagate(retval); uint32_t drscan_data; uint16_t tmp = (buffer[0] | (buffer[1] << 8)); retval = core_tx_upper_data(target, tmp, &drscan_data); err_check_propagate(retval); retval = dsp5680xx_resume(target, 0, ram_addr, 0, 0); err_check_propagate(retval); int counter = FLUSH_COUNT_FLASH; dsp5680xx_context.flush = 0; uint32_t i; for (i = 1; (i < count / 2) && (i < HFM_SIZE_WORDS); i++) { if (--counter == 0) { dsp5680xx_context.flush = 1; counter = FLUSH_COUNT_FLASH; } tmp = (buffer[2 * i] | (buffer[2 * i + 1] << 8)); retval = core_tx_upper_data(target, tmp, &drscan_data); if (retval != ERROR_OK) { dsp5680xx_context.flush = 1; err_check_propagate(retval); } dsp5680xx_context.flush = 0; } dsp5680xx_context.flush = 1; if (!is_flash_lock) { /* *Verify flash (skip when exec lock sequence) * */ uint16_t signature; uint16_t pc_crc; retval = dsp5680xx_f_signature(target, address, i, &signature); err_check_propagate(retval); pc_crc = perl_crc(buffer, i); if (pc_crc != signature) { retval = ERROR_FAIL; const char *msg = "Flashed data failed CRC check, flash again!"; err_check(retval, DSP5680XX_ERROR_FLASHING_CRC, msg); } } return retval; } int dsp5680xx_f_unlock(struct target *target) { int retval = ERROR_OK; uint16_t eonce_status; uint32_t instr; uint32_t ir_out; struct jtag_tap *tap_chp; struct jtag_tap *tap_cpu; tap_chp = jtag_tap_by_string("dsp568013.chp"); if (!tap_chp) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_MASTER, "Failed to get master tap."); } tap_cpu = jtag_tap_by_string("dsp568013.cpu"); if (!tap_cpu) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_CORE, "Failed to get master tap."); } retval = eonce_enter_debug_mode_without_reset(target, &eonce_status); if (retval == ERROR_OK) LOG_WARNING("Memory was not locked."); jtag_add_reset(0, 1); jtag_add_sleep(TIME_DIV_FREESCALE * 200 * 1000); retval = reset_jtag(); err_check(retval, DSP5680XX_ERROR_JTAG_RESET, "Failed to reset JTAG state machine"); jtag_add_sleep(150); /* Enable core tap */ tap_chp->enabled = true; retval = switch_tap(target, tap_chp, tap_cpu); err_check_propagate(retval); instr = JTAG_INSTR_DEBUG_REQUEST; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); jtag_add_reset(0, 0); jtag_add_sleep(TIME_DIV_FREESCALE * 300 * 1000); /* Enable master tap */ tap_chp->enabled = false; retval = switch_tap(target, tap_chp, tap_cpu); err_check_propagate(retval); /* Execute mass erase to unlock */ instr = MASTER_TAP_CMD_FLASH_ERASE; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_MASTER_TAP_IRLEN); err_check_propagate(retval); instr = HFM_CLK_DEFAULT; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 16); err_check_propagate(retval); jtag_add_sleep(TIME_DIV_FREESCALE * 150 * 1000); jtag_add_reset(0, 1); jtag_add_sleep(TIME_DIV_FREESCALE * 200 * 1000); retval = reset_jtag(); err_check(retval, DSP5680XX_ERROR_JTAG_RESET, "Failed to reset JTAG state machine"); jtag_add_sleep(150); instr = 0x0606ffff; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 32); err_check_propagate(retval); /* enable core tap */ instr = 0x5; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_MASTER_TAP_IRLEN); err_check_propagate(retval); instr = 0x2; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 4); err_check_propagate(retval); tap_cpu->enabled = true; tap_chp->enabled = false; target->state = TARGET_RUNNING; dsp5680xx_context.debug_mode_enabled = false; return retval; } int dsp5680xx_f_lock(struct target *target) { int retval; struct jtag_tap *tap_chp; struct jtag_tap *tap_cpu; uint16_t lock_word = HFM_LOCK_FLASH; retval = dsp5680xx_f_wr(target, (uint8_t *)&lock_word, HFM_LOCK_ADDR_L, 2, 1); err_check_propagate(retval); jtag_add_reset(0, 1); jtag_add_sleep(TIME_DIV_FREESCALE * 200 * 1000); retval = reset_jtag(); err_check(retval, DSP5680XX_ERROR_JTAG_RESET, "Failed to reset JTAG state machine"); jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); jtag_add_reset(0, 0); jtag_add_sleep(TIME_DIV_FREESCALE * 300 * 1000); tap_chp = jtag_tap_by_string("dsp568013.chp"); if (!tap_chp) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_MASTER, "Failed to get master tap."); } tap_cpu = jtag_tap_by_string("dsp568013.cpu"); if (!tap_cpu) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_CORE, "Failed to get master tap."); } target->state = TARGET_RUNNING; dsp5680xx_context.debug_mode_enabled = false; tap_cpu->enabled = false; tap_chp->enabled = true; retval = switch_tap(target, tap_chp, tap_cpu); return retval; } static int dsp5680xx_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { err_check(ERROR_FAIL, DSP5680XX_ERROR_NOT_IMPLEMENTED_STEP, "Not implemented yet."); } /** Holds methods for dsp5680xx targets. */ struct target_type dsp5680xx_target = { .name = "dsp5680xx", .poll = dsp5680xx_poll, .arch_state = dsp5680xx_arch_state, .halt = dsp5680xx_halt, .resume = dsp5680xx_resume, .step = dsp5680xx_step, .write_buffer = dsp5680xx_write_buffer, .read_buffer = dsp5680xx_read_buffer, .assert_reset = dsp5680xx_assert_reset, .deassert_reset = dsp5680xx_deassert_reset, .soft_reset_halt = dsp5680xx_soft_reset_halt, .read_memory = dsp5680xx_read, .write_memory = dsp5680xx_write, .checksum_memory = dsp5680xx_checksum_memory, .target_create = dsp5680xx_target_create, .init_target = dsp5680xx_init_target, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/dsp5680xx.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Rodrigo L. Rosa * * rodrigorosa.LG@gmail.com * * * * Based on dsp563xx_once.h written by Mathias Kuester * * mkdorg@users.sourceforge.net * ***************************************************************************/ #ifndef OPENOCD_TARGET_DSP5680XX_H #define OPENOCD_TARGET_DSP5680XX_H #include <jtag/jtag.h> /** * @file dsp5680xx.h * @author Rodrigo Rosa <rodrigorosa.LG@gmail.com> * @date Thu Jun 9 18:54:38 2011 * * @brief Basic support for the 5680xx DSP from Freescale. * The chip has two taps in the JTAG chain, the Master tap and the Core tap. * In this code the Master tap is only used to unlock the flash memory by executing a JTAG instruction. * */ #define S_FILE_DATA_OFFSET 0x200000 #define TIME_DIV_FREESCALE 0.3 /** ---------------------------------------------------------------- * JTAG *---------------------------------------------------------------- */ #define DSP5680XX_JTAG_CORE_TAP_IRLEN 4 #define DSP5680XX_JTAG_MASTER_TAP_IRLEN 8 #define JTAG_STATUS_MASK 0x0F #define JTAG_STATUS_NORMAL 0x01 #define JTAG_STATUS_STOPWAIT 0x05 #define JTAG_STATUS_BUSY 0x09 #define JTAG_STATUS_DEBUG 0x0D #define JTAG_STATUS_DEAD 0x0f #define JTAG_INSTR_EXTEST 0x0 #define JTAG_INSTR_SAMPLE_PRELOAD 0x1 #define JTAG_INSTR_IDCODE 0x2 #define JTAG_INSTR_EXTEST_PULLUP 0x3 #define JTAG_INSTR_HIGHZ 0x4 #define JTAG_INSTR_CLAMP 0x5 #define JTAG_INSTR_ENABLE_ONCE 0x6 #define JTAG_INSTR_DEBUG_REQUEST 0x7 #define JTAG_INSTR_BYPASS 0xF /** * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * Master TAP instructions from MC56F8000RM.pdf * ---------------------------------------------------------------- */ #define MASTER_TAP_CMD_BYPASS 0xF #define MASTER_TAP_CMD_IDCODE 0x2 #define MASTER_TAP_CMD_TLM_SEL 0x5 #define MASTER_TAP_CMD_FLASH_ERASE 0x8 /** * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * EOnCE control register info * ---------------------------------------------------------------- */ #define DSP5680XX_ONCE_OCR_EX (1<<5) /* EX Bit Definition 0 Remain in the Debug Processing State 1 Leave the Debug Processing State */ #define DSP5680XX_ONCE_OCR_GO (1<<6) /* GO Bit Definition 0 Inactive—No Action Taken 1 Execute Controller Instruction */ #define DSP5680XX_ONCE_OCR_RW (1<<7) /** RW Bit Definition * 0 Write To the Register Specified by the RS[4:0] Bits * 1 ReadFrom the Register Specified by the RS[4:0] Bits * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * EOnCE Status Register * ---------------------------------------------------------------- */ #define DSP5680XX_ONCE_OSCR_OS1 (1<<5) #define DSP5680XX_ONCE_OSCR_OS0 (1<<4) /** * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * EOnCE Core Status - Describes the operating status of the core controller * ---------------------------------------------------------------- */ #define DSP5680XX_ONCE_OSCR_NORMAL_M (0) /* 00 - Normal - Controller Core Executing Instructions or in Reset */ #define DSP5680XX_ONCE_OSCR_STOPWAIT_M (DSP5680XX_ONCE_OSCR_OS0) /* 01 - Stop/Wait - Controller Core in Stop or Wait Mode */ #define DSP5680XX_ONCE_OSCR_BUSY_M (DSP5680XX_ONCE_OSCR_OS1) /* 10 - Busy - Controller is Performing External or Peripheral Access (Wait States) */ #define DSP5680XX_ONCE_OSCR_DEBUG_M (DSP5680XX_ONCE_OSCR_OS0|DSP5680XX_ONCE_OSCR_OS1) /* 11 - Debug - Controller Core Halted and in Debug Mode */ #define EONCE_STAT_MASK 0x30 /** * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * Register Select Encoding (eonce_rev.1.0_0208081.pdf:14) * ---------------------------------------------------------------- */ #define DSP5680XX_ONCE_NOREG 0x00 /* No register selected */ #define DSP5680XX_ONCE_OCR 0x01 /* OnCE Debug Control Register */ #define DSP5680XX_ONCE_OCNTR 0x02 /* OnCE Breakpoint and Trace Counter */ #define DSP5680XX_ONCE_OSR 0x03 /* EOnCE status register */ #define DSP5680XX_ONCE_OBAR 0x04 /* OnCE Breakpoint Address Register */ #define DSP5680XX_ONCE_OBASE 0x05 /* EOnCE Peripheral Base Address register */ #define DSP5680XX_ONCE_OTXRXSR 0x06 /* EOnCE TXRX Status and Control Register (OTXRXSR) */ #define DSP5680XX_ONCE_OTX 0x07 /* EOnCE Transmit register (OTX) */ #define DSP5680XX_ONCE_OPDBR 0x08 /* EOnCE Program Data Bus Register (OPDBR) */ #define DSP5680XX_ONCE_OTX1 0x09 /* EOnCE Upper Transmit register (OTX1) */ #define DSP5680XX_ONCE_OPABFR 0x0A /* OnCE Program Address Register—Fetch cycle */ #define DSP5680XX_ONCE_ORX 0x0B /* EOnCE Receive register (ORX) */ #define DSP5680XX_ONCE_OCNTR_C 0x0C /* Clear OCNTR */ #define DSP5680XX_ONCE_ORX1 0x0D /* EOnCE Upper Receive register (ORX1) */ #define DSP5680XX_ONCE_OTBCR 0x0E /* EOnCE Trace Buffer Control Reg (OTBCR) */ #define DSP5680XX_ONCE_OPABER 0x10 /* OnCE Program Address Register—Execute cycle */ #define DSP5680XX_ONCE_OPFIFO 0x11 /* OnCE Program address FIFO */ #define DSP5680XX_ONCE_OBAR1 0x12 /* EOnCE Breakpoint 1 Unit 0 Address Reg.(OBAR1) */ #define DSP5680XX_ONCE_OPABDR 0x13 /* OnCE Program Address Register—Decode cycle (OPABDR) */ /** * ---------------------------------------------------------------- */ #define FLUSH_COUNT_READ_WRITE 8192 /* This value works, higher values (and lower...) may work as well. */ #define FLUSH_COUNT_FLASH 8192 /** ---------------------------------------------------------------- * HFM (flash module) Commands (ref:MC56F801xRM.pdf:159) * ---------------------------------------------------------------- */ #define HFM_ERASE_VERIFY 0x05 #define HFM_CALCULATE_DATA_SIGNATURE 0x06 #define HFM_WORD_PROGRAM 0x20 #define HFM_PAGE_ERASE 0x40 #define HFM_MASS_ERASE 0x41 #define HFM_CALCULATE_IFR_BLOCK_SIGNATURE 0x66 /** * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * Flashing (ref:MC56F801xRM.pdf:159) * ---------------------------------------------------------------- */ #define HFM_BASE_ADDR 0x0F400 /** In x: mem. (write to S_FILE_DATA_OFFSET+HFM_BASE_ADDR * to get data into x: mem.) */ /** * The following are register addresses, not memory * addresses (though all registers are memory mapped) */ #define HFM_CLK_DIV 0x00 /* r/w */ #define HFM_CNFG 0x01 /* r/w */ #define HFM_SECHI 0x03 /* r */ #define HFM_SECLO 0x04 /* r */ #define HFM_PROT 0x10 /* r/w */ #define HFM_PROTB 0x11 /* r/w */ #define HFM_USTAT 0x13 /* r/w */ #define HFM_CMD 0x14 /* r/w */ #define HFM_DATA 0x18 /* r */ #define HFM_OPT1 0x1B /* r */ #define HFM_TSTSIG 0x1D /* r */ #define HFM_EXEC_COMPLETE 0x40 /* User status register (USTAT) masks (MC56F80XXRM.pdf:6.7.5) */ #define HFM_USTAT_MASK_BLANK 0x4 #define HFM_USTAT_MASK_PVIOL_ACCER 0x30 /** * The value used on for the FM clock is important to prevent flashing errors and to prevent deterioration of the FM. * This value was calculated using a spreadsheet tool available on the Freescale website under FAQ 25464. * */ #define HFM_CLK_DEFAULT 0x27 /* 0x27 according to freescale cfg, but 0x40 according to freescale spreadsheet... */ #define HFM_FLASH_BASE_ADDR 0x0 #define HFM_SIZE_BYTES 0x4000 /* bytes */ #define HFM_SIZE_WORDS 0x2000 /* words */ #define HFM_SECTOR_SIZE 0x200 /* Size in bytes */ #define HFM_SECTOR_COUNT 0x20 /* A 16K block in pages of 256 words. */ /** * Writing HFM_LOCK_FLASH to HFM_LOCK_ADDR_L and HFM_LOCK_ADDR_H will enable security on flash after the next reset. */ #define HFM_LOCK_FLASH 0xE70A #define HFM_LOCK_ADDR_L 0x1FF7 #define HFM_LOCK_ADDR_H 0x1FF8 /** * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * Register Memory Map (eonce_rev.1.0_0208081.pdf:16) * ---------------------------------------------------------------- */ #define MC568013_EONCE_OBASE_ADDR 0xFF /* The following are relative to EONCE_OBASE_ADDR (EONCE_OBASE_ADDR<<16 + ...) */ #define MC568013_EONCE_TX_RX_ADDR 0xFFFE #define MC568013_EONCE_TX1_RX1_HIGH_ADDR 0xFFFF /* Relative to EONCE_OBASE_ADDR */ #define MC568013_EONCE_OCR 0xFFA0 /* Relative to EONCE_OBASE_ADDR */ /** * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * SIM addresses & commands (MC56F80xx.h from freescale) * ---------------------------------------------------------------- */ #define MC568013_SIM_BASE_ADDR 0xF140 #define MC56803X_2X_SIM_BASE_ADDR 0xF100 #define SIM_CMD_RESET 0x10 /** * ---------------------------------------------------------------- */ /** * ---------------------------------------------------------------- * ERROR codes - enable automatic parsing of output * ---------------------------------------------------------------- */ #define DSP5680XX_ERROR_UNKNOWN_OR_ERROR_OPENOCD -100 #define DSP5680XX_ERROR_JTAG_COMM -1 #define DSP5680XX_ERROR_JTAG_RESET -2 #define DSP5680XX_ERROR_JTAG_INVALID_TAP -3 #define DSP5680XX_ERROR_JTAG_DR_LEN_OVERFLOW -4 #define DSP5680XX_ERROR_INVALID_IR_LEN -5 #define DSP5680XX_ERROR_JTAG_TAP_ENABLE_MASTER -6 #define DSP5680XX_ERROR_JTAG_TAP_ENABLE_CORE -7 #define DSP5680XX_ERROR_JTAG_TAP_FIND_MASTER -8 #define DSP5680XX_ERROR_JTAG_TAP_FIND_CORE -9 #define DSP5680XX_ERROR_JTAG_DRSCAN -10 #define DSP5680XX_ERROR_JTAG_IRSCAN -11 #define DSP5680XX_ERROR_ENTER_DEBUG_MODE -12 #define DSP5680XX_ERROR_RESUME -13 #define DSP5680XX_ERROR_WRITE_WITH_TARGET_RUNNING -14 #define DSP5680XX_ERROR_INVALID_DATA_SIZE_UNIT -15 #define DSP5680XX_ERROR_PROTECT_CHECK_INVALID_ARGS -16 #define DSP5680XX_ERROR_FM_BUSY -17 #define DSP5680XX_ERROR_FM_CMD_TIMED_OUT -18 #define DSP5680XX_ERROR_FM_EXEC -19 #define DSP5680XX_ERROR_FM_SET_CLK -20 #define DSP5680XX_ERROR_FLASHING_INVALID_WORD_COUNT -21 #define DSP5680XX_ERROR_FLASHING_CRC -22 #define DSP5680XX_ERROR_FLASHING -23 #define DSP5680XX_ERROR_NOT_IMPLEMENTED_STEP -24 #define DSP5680XX_ERROR_HALT -25 #define DSP5680XX_ERROR_EXIT_DEBUG_MODE -26 #define DSP5680XX_ERROR_TARGET_RUNNING -27 #define DSP5680XX_ERROR_NOT_IN_DEBUG -28 /** * ---------------------------------------------------------------- */ struct dsp5680xx_common { uint32_t stored_pc; int flush; bool debug_mode_enabled; }; static inline struct dsp5680xx_common *target_to_dsp5680xx(struct target *target) { return target->arch_info; } /** * Writes to flash memory. * Does not check if flash is erased, it's up to the user to erase the flash before running * this function. * The flashing algorithm runs from RAM, reading from a register to which this function * writes to. The algorithm is open loop, there is no control to verify that the FM read * the register before writing the next data. A closed loop approach was much slower, * and the current implementation does not fail, and if it did the crc check would detect it, * allowing to flash again. * * @param target * @param buffer * @param address Word addressing. * @param count In bytes. * @param is_flash_lock * * @return */ int dsp5680xx_f_wr(struct target *target, const uint8_t *buffer, uint32_t address, uint32_t count, int is_flash_lock); /** * The FM has the functionality of checking if the flash array is erased. This function * executes it. It does not support individual sector analysis. * * @param target * @param erased * @param sector This parameter is ignored because the FM does not support checking if * individual sectors are erased. * * @return */ int dsp5680xx_f_erase_check(struct target *target, uint8_t *erased, uint32_t sector); /** * Erases either a sector or the complete flash array. If either the range first-last covers * the complete array or if first == 0 and last == 0 then a mass erase command is executed * on the FM. If not, then individual sectors are erased. * * @param target * @param first * @param last * * @return */ int dsp5680xx_f_erase(struct target *target, int first, int last); /** * Reads the memory mapped protection register. A 1 implies the sector is protected, * a 0 implies the sector is not protected. * * @param target * @param protected Data read from the protection register. * * @return */ int dsp5680xx_f_protect_check(struct target *target, uint16_t *protected); /** * Writes the flash security words with a specific value. The chip's security will be * enabled after the first reset following the execution of this function. * * @param target * * @return */ int dsp5680xx_f_lock(struct target *target); /** * Executes a mass erase command. The must be done from the Master tap. * It is up to the user to select the master tap (jtag tapenable dsp5680xx.chp) * before running this function. * The flash array will be unsecured (and erased) after the first reset following * the execution of this function. * * @param target * * @return */ int dsp5680xx_f_unlock(struct target *target); #endif /* OPENOCD_TARGET_DSP5680XX_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/embeddedice.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "embeddedice.h" #include "register.h" #include <helper/time_support.h> /** * @file * * This provides lowlevel glue to the EmbeddedICE (or EmbeddedICE-RT) * module found on scan chain 2 in ARM7, ARM9, and some other families * of ARM cores. The module is called "EmbeddedICE-RT" if it has * monitor mode support. * * EmbeddedICE provides basic watchpoint/breakpoint hardware and a Debug * Communications Channel (DCC) used to read or write 32-bit words to * OpenOCD-aware code running on the target CPU. * Newer modules also include vector catch hardware. Some versions * support hardware single-stepping, "monitor mode" debug (which is not * currently supported by OpenOCD), or extended reporting on why the * core entered debug mode. */ static int embeddedice_set_reg_w_exec(struct reg *reg, uint8_t *buf); /* * From: ARM9E-S TRM, DDI 0165, table C-4 (and similar, for other cores) */ static const struct { const char *name; unsigned short addr; unsigned short width; } eice_regs[] = { [EICE_DBG_CTRL] = { .name = "debug_ctrl", .addr = 0, /* width is assigned based on EICE version */ }, [EICE_DBG_STAT] = { .name = "debug_status", .addr = 1, /* width is assigned based on EICE version */ }, [EICE_COMMS_CTRL] = { .name = "comms_ctrl", .addr = 4, .width = 6, }, [EICE_COMMS_DATA] = { .name = "comms_data", .addr = 5, .width = 32, }, [EICE_W0_ADDR_VALUE] = { .name = "watch_0_addr_value", .addr = 8, .width = 32, }, [EICE_W0_ADDR_MASK] = { .name = "watch_0_addr_mask", .addr = 9, .width = 32, }, [EICE_W0_DATA_VALUE] = { .name = "watch_0_data_value", .addr = 10, .width = 32, }, [EICE_W0_DATA_MASK] = { .name = "watch_0_data_mask", .addr = 11, .width = 32, }, [EICE_W0_CONTROL_VALUE] = { .name = "watch_0_control_value", .addr = 12, .width = 9, }, [EICE_W0_CONTROL_MASK] = { .name = "watch_0_control_mask", .addr = 13, .width = 8, }, [EICE_W1_ADDR_VALUE] = { .name = "watch_1_addr_value", .addr = 16, .width = 32, }, [EICE_W1_ADDR_MASK] = { .name = "watch_1_addr_mask", .addr = 17, .width = 32, }, [EICE_W1_DATA_VALUE] = { .name = "watch_1_data_value", .addr = 18, .width = 32, }, [EICE_W1_DATA_MASK] = { .name = "watch_1_data_mask", .addr = 19, .width = 32, }, [EICE_W1_CONTROL_VALUE] = { .name = "watch_1_control_value", .addr = 20, .width = 9, }, [EICE_W1_CONTROL_MASK] = { .name = "watch_1_control_mask", .addr = 21, .width = 8, }, /* vector_catch isn't always present */ [EICE_VEC_CATCH] = { .name = "vector_catch", .addr = 2, .width = 8, }, }; static int embeddedice_get_reg(struct reg *reg) { int retval = embeddedice_read_reg(reg); if (retval != ERROR_OK) { LOG_ERROR("error queueing EmbeddedICE register read"); return retval; } retval = jtag_execute_queue(); if (retval != ERROR_OK) LOG_ERROR("EmbeddedICE register read failed"); return retval; } static const struct reg_arch_type eice_reg_type = { .get = embeddedice_get_reg, .set = embeddedice_set_reg_w_exec, }; /** * Probe EmbeddedICE module and set up local records of its registers. * Different versions of the modules have different capabilities, such as * hardware support for vector_catch, single stepping, and monitor mode. */ struct reg_cache *embeddedice_build_reg_cache(struct target *target, struct arm7_9_common *arm7_9) { int retval; struct reg_cache *reg_cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = NULL; struct embeddedice_reg *arch_info = NULL; struct arm_jtag *jtag_info = &arm7_9->jtag_info; int num_regs = ARRAY_SIZE(eice_regs); int i; int eice_version = 0; /* vector_catch isn't always present */ if (!arm7_9->has_vector_catch) num_regs--; /* the actual registers are kept in two arrays */ reg_list = calloc(num_regs, sizeof(struct reg)); arch_info = calloc(num_regs, sizeof(struct embeddedice_reg)); /* fill in values for the reg cache */ reg_cache->name = "EmbeddedICE registers"; reg_cache->next = NULL; reg_cache->reg_list = reg_list; reg_cache->num_regs = num_regs; /* FIXME the second watchpoint unit on Feroceon and Dragonite * seems not to work ... we should have a way to not set up * its four registers here! */ /* set up registers */ for (i = 0; i < num_regs; i++) { reg_list[i].name = eice_regs[i].name; reg_list[i].size = eice_regs[i].width; reg_list[i].dirty = false; reg_list[i].valid = false; reg_list[i].value = calloc(1, 4); reg_list[i].arch_info = &arch_info[i]; reg_list[i].type = &eice_reg_type; arch_info[i].addr = eice_regs[i].addr; arch_info[i].jtag_info = jtag_info; } /* identify EmbeddedICE version by reading DCC control register */ embeddedice_read_reg(®_list[EICE_COMMS_CTRL]); retval = jtag_execute_queue(); if (retval != ERROR_OK) { for (i = 0; i < num_regs; i++) free(reg_list[i].value); free(reg_list); free(reg_cache); free(arch_info); return NULL; } eice_version = buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 28, 4); LOG_INFO("Embedded ICE version %d", eice_version); switch (eice_version) { case 1: /* ARM7TDMI r3, ARM7TDMI-S r3 * * REVISIT docs say ARM7TDMI-S r4 uses version 1 but * that it has 6-bit CTRL and 5-bit STAT... doc bug? * ARM7TDMI r4 docs say EICE v4. */ reg_list[EICE_DBG_CTRL].size = 3; reg_list[EICE_DBG_STAT].size = 5; break; case 2: /* ARM9TDMI */ reg_list[EICE_DBG_CTRL].size = 4; reg_list[EICE_DBG_STAT].size = 5; arm7_9->has_single_step = 1; break; case 3: LOG_ERROR("EmbeddedICE v%d handling might be broken", eice_version); reg_list[EICE_DBG_CTRL].size = 6; reg_list[EICE_DBG_STAT].size = 5; arm7_9->has_single_step = 1; arm7_9->has_monitor_mode = 1; break; case 4: /* ARM7TDMI r4 */ reg_list[EICE_DBG_CTRL].size = 6; reg_list[EICE_DBG_STAT].size = 5; arm7_9->has_monitor_mode = 1; break; case 5: /* ARM9E-S rev 1 */ reg_list[EICE_DBG_CTRL].size = 6; reg_list[EICE_DBG_STAT].size = 5; arm7_9->has_single_step = 1; arm7_9->has_monitor_mode = 1; break; case 6: /* ARM7EJ-S, ARM9E-S rev 2, ARM9EJ-S */ reg_list[EICE_DBG_CTRL].size = 6; reg_list[EICE_DBG_STAT].size = 10; /* DBG_STAT has MOE bits */ arm7_9->has_monitor_mode = 1; break; case 7: LOG_ERROR("EmbeddedICE v%d handling might be broken", eice_version); reg_list[EICE_DBG_CTRL].size = 6; reg_list[EICE_DBG_STAT].size = 5; arm7_9->has_monitor_mode = 1; break; default: /* * The Feroceon implementation has the version number * in some unusual bits. Let feroceon.c validate it * and do the appropriate setup itself. */ if (strcmp(target_type_name(target), "feroceon") == 0 || strcmp(target_type_name(target), "dragonite") == 0) break; LOG_ERROR("unknown EmbeddedICE version " "(comms ctrl: 0x%8.8" PRIx32 ")", buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32)); } /* On Feroceon and Dragonite the second unit is seemingly missing. */ LOG_INFO("%s: hardware has %d breakpoint/watchpoint unit%s", target_name(target), arm7_9->wp_available_max, (arm7_9->wp_available_max != 1) ? "s" : ""); return reg_cache; } /** * Free all memory allocated for EmbeddedICE register cache */ void embeddedice_free_reg_cache(struct reg_cache *reg_cache) { if (!reg_cache) return; for (unsigned int i = 0; i < reg_cache->num_regs; i++) free(reg_cache->reg_list[i].value); free(reg_cache->reg_list[0].arch_info); free(reg_cache->reg_list); free(reg_cache); } /** * Initialize EmbeddedICE module, if needed. */ int embeddedice_setup(struct target *target) { int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); /* Explicitly disable monitor mode. For now we only support halting * debug ... we don't know how to talk with a resident debug monitor * that manages break requests. ARM's "Angel Debug Monitor" is one * common example of such code. */ if (arm7_9->has_monitor_mode) { struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; embeddedice_read_reg(dbg_ctrl); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; buf_set_u32(dbg_ctrl->value, 4, 1, 0); embeddedice_set_reg_w_exec(dbg_ctrl, dbg_ctrl->value); } return jtag_execute_queue(); } /** * Queue a read for an EmbeddedICE register into the register cache, * optionally checking the value read. * Note that at this level, all registers are 32 bits wide. */ int embeddedice_read_reg_w_check(struct reg *reg, uint8_t *check_value, uint8_t *check_mask) { struct embeddedice_reg *ice_reg = reg->arch_info; uint8_t reg_addr = ice_reg->addr & 0x1f; struct scan_field fields[3]; uint8_t field1_out[1]; uint8_t field2_out[1]; int retval; retval = arm_jtag_scann(ice_reg->jtag_info, 0x2, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(ice_reg->jtag_info->tap, ice_reg->jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; /* bits 31:0 -- data (ignored here) */ fields[0].num_bits = 32; fields[0].out_value = reg->value; fields[0].in_value = NULL; fields[0].check_value = NULL; fields[0].check_mask = NULL; /* bits 36:32 -- register */ fields[1].num_bits = 5; fields[1].out_value = field1_out; field1_out[0] = reg_addr; fields[1].in_value = NULL; fields[1].check_value = NULL; fields[1].check_mask = NULL; /* bit 37 -- 0/read */ fields[2].num_bits = 1; fields[2].out_value = field2_out; field2_out[0] = 0; fields[2].in_value = NULL; fields[2].check_value = NULL; fields[2].check_mask = NULL; /* traverse Update-DR, setting address for the next read */ jtag_add_dr_scan(ice_reg->jtag_info->tap, 3, fields, TAP_IDLE); /* bits 31:0 -- the data we're reading (and maybe checking) */ fields[0].in_value = reg->value; fields[0].check_value = check_value; fields[0].check_mask = check_mask; /* when reading the DCC data register, leaving the address field set to * EICE_COMMS_DATA would read the register twice * reading the control register is safe */ field1_out[0] = eice_regs[EICE_COMMS_CTRL].addr; /* traverse Update-DR, reading but with no other side effects */ jtag_add_dr_scan_check(ice_reg->jtag_info->tap, 3, fields, TAP_IDLE); return ERROR_OK; } /** * Receive a block of size 32-bit words from the DCC. * We assume the target is always going to be fast enough (relative to * the JTAG clock) that the debugger won't need to poll the handshake * bit. The JTAG clock is usually at least six times slower than the * functional clock, so the 50+ JTAG clocks needed to receive the word * allow hundreds of instruction cycles (per word) in the target. */ int embeddedice_receive(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size) { struct scan_field fields[3]; uint8_t field1_out[1]; uint8_t field2_out[1]; int retval; retval = arm_jtag_scann(jtag_info, 0x2, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = NULL; fields[1].num_bits = 5; fields[1].out_value = field1_out; field1_out[0] = eice_regs[EICE_COMMS_DATA].addr; fields[1].in_value = NULL; fields[2].num_bits = 1; fields[2].out_value = field2_out; field2_out[0] = 0; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); while (size > 0) { /* when reading the last item, set the register address to the DCC control reg, * to avoid reading additional data from the DCC data reg */ if (size == 1) field1_out[0] = eice_regs[EICE_COMMS_CTRL].addr; fields[0].in_value = (uint8_t *)data; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)data); data++; size--; } return jtag_execute_queue(); } /** * Queue a read for an EmbeddedICE register into the register cache, * not checking the value read. */ int embeddedice_read_reg(struct reg *reg) { return embeddedice_read_reg_w_check(reg, NULL, NULL); } /** * Queue a write for an EmbeddedICE register, updating the register cache. * Uses embeddedice_write_reg(). */ void embeddedice_set_reg(struct reg *reg, uint32_t value) { embeddedice_write_reg(reg, value); buf_set_u32(reg->value, 0, reg->size, value); reg->valid = true; reg->dirty = false; } /** * Write an EmbeddedICE register, updating the register cache. * Uses embeddedice_set_reg(); not queued. */ static int embeddedice_set_reg_w_exec(struct reg *reg, uint8_t *buf) { int retval; embeddedice_set_reg(reg, buf_get_u32(buf, 0, reg->size)); retval = jtag_execute_queue(); if (retval != ERROR_OK) LOG_ERROR("register write failed"); return retval; } /** * Queue a write for an EmbeddedICE register, bypassing the register cache. */ void embeddedice_write_reg(struct reg *reg, uint32_t value) { struct embeddedice_reg *ice_reg = reg->arch_info; LOG_DEBUG("%i: 0x%8.8" PRIx32 "", ice_reg->addr, value); arm_jtag_scann(ice_reg->jtag_info, 0x2, TAP_IDLE); arm_jtag_set_instr(ice_reg->jtag_info->tap, ice_reg->jtag_info->intest_instr, NULL, TAP_IDLE); uint8_t reg_addr = ice_reg->addr & 0x1f; embeddedice_write_reg_inner(ice_reg->jtag_info->tap, reg_addr, value); } /** * Queue a write for an EmbeddedICE register, using cached value. * Uses embeddedice_write_reg(). */ void embeddedice_store_reg(struct reg *reg) { embeddedice_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); } /** * Send a block of size 32-bit words to the DCC. * We assume the target is always going to be fast enough (relative to * the JTAG clock) that the debugger won't need to poll the handshake * bit. The JTAG clock is usually at least six times slower than the * functional clock, so the 50+ JTAG clocks needed to receive the word * allow hundreds of instruction cycles (per word) in the target. */ int embeddedice_send(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size) { struct scan_field fields[3]; uint8_t field0_out[4]; uint8_t field1_out[1]; uint8_t field2_out[1]; int retval; retval = arm_jtag_scann(jtag_info, 0x2, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = field0_out; fields[0].in_value = NULL; fields[1].num_bits = 5; fields[1].out_value = field1_out; field1_out[0] = eice_regs[EICE_COMMS_DATA].addr; fields[1].in_value = NULL; fields[2].num_bits = 1; fields[2].out_value = field2_out; field2_out[0] = 1; fields[2].in_value = NULL; while (size > 0) { buf_set_u32(field0_out, 0, 32, *data); jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); data++; size--; } /* call to jtag_execute_queue() intentionally omitted */ return ERROR_OK; } /** * Poll DCC control register until read or write handshake completes. */ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeout) { struct scan_field fields[3]; uint8_t field0_in[4]; uint8_t field1_out[1]; uint8_t field2_out[1]; int retval; uint32_t hsact; struct timeval now; struct timeval timeout_end; if (hsbit == EICE_COMM_CTRL_WBIT) hsact = 1; else if (hsbit == EICE_COMM_CTRL_RBIT) hsact = 0; else { LOG_ERROR("Invalid arguments"); return ERROR_COMMAND_SYNTAX_ERROR; } retval = arm_jtag_scann(jtag_info, 0x2, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = field0_in; fields[1].num_bits = 5; fields[1].out_value = field1_out; field1_out[0] = eice_regs[EICE_COMMS_DATA].addr; fields[1].in_value = NULL; fields[2].num_bits = 1; fields[2].out_value = field2_out; field2_out[0] = 0; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); gettimeofday(&timeout_end, NULL); timeval_add_time(&timeout_end, 0, timeout * 1000); do { jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (buf_get_u32(field0_in, hsbit, 1) == hsact) return ERROR_OK; gettimeofday(&now, NULL); } while (timeval_compare(&now, &timeout_end) <= 0); LOG_ERROR("embeddedice handshake timeout"); return ERROR_TARGET_TIMEOUT; } /** * This is an inner loop of the open loop DCC write of data to target */ void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, const uint8_t *buffer, int little, int count) { int i; for (i = 0; i < count; i++) { embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer, little)); buffer += 4; } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/embeddedice.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005, 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_TARGET_EMBEDDEDICE_H #define OPENOCD_TARGET_EMBEDDEDICE_H #include "arm7_9_common.h" enum { EICE_DBG_CTRL = 0, EICE_DBG_STAT = 1, EICE_COMMS_CTRL = 2, EICE_COMMS_DATA = 3, EICE_W0_ADDR_VALUE = 4, EICE_W0_ADDR_MASK = 5, EICE_W0_DATA_VALUE = 6, EICE_W0_DATA_MASK = 7, EICE_W0_CONTROL_VALUE = 8, EICE_W0_CONTROL_MASK = 9, EICE_W1_ADDR_VALUE = 10, EICE_W1_ADDR_MASK = 11, EICE_W1_DATA_VALUE = 12, EICE_W1_DATA_MASK = 13, EICE_W1_CONTROL_VALUE = 14, EICE_W1_CONTROL_MASK = 15, EICE_VEC_CATCH = 16 }; enum { EICE_DBG_CONTROL_ICEDIS = 5, EICE_DBG_CONTROL_MONEN = 4, EICE_DBG_CONTROL_INTDIS = 2, EICE_DBG_CONTROL_DBGRQ = 1, EICE_DBG_CONTROL_DBGACK = 0, }; enum { EICE_DBG_STATUS_IJBIT = 5, EICE_DBG_STATUS_ITBIT = 4, EICE_DBG_STATUS_SYSCOMP = 3, EICE_DBG_STATUS_IFEN = 2, EICE_DBG_STATUS_DBGRQ = 1, EICE_DBG_STATUS_DBGACK = 0 }; enum { EICE_W_CTRL_ENABLE = 0x100, EICE_W_CTRL_RANGE = 0x80, EICE_W_CTRL_CHAIN = 0x40, EICE_W_CTRL_EXTERN = 0x20, EICE_W_CTRL_NTRANS = 0x10, EICE_W_CTRL_NOPC = 0x8, EICE_W_CTRL_MAS = 0x6, EICE_W_CTRL_ITBIT = 0x2, EICE_W_CTRL_NRW = 0x1 }; enum { EICE_COMM_CTRL_WBIT = 1, EICE_COMM_CTRL_RBIT = 0 }; struct embeddedice_reg { int addr; struct arm_jtag *jtag_info; }; struct reg_cache *embeddedice_build_reg_cache(struct target *target, struct arm7_9_common *arm7_9); void embeddedice_free_reg_cache(struct reg_cache *reg_cache); int embeddedice_setup(struct target *target); int embeddedice_read_reg(struct reg *reg); int embeddedice_read_reg_w_check(struct reg *reg, uint8_t *check_value, uint8_t *check_mask); void embeddedice_write_reg(struct reg *reg, uint32_t value); void embeddedice_store_reg(struct reg *reg); void embeddedice_set_reg(struct reg *reg, uint32_t value); int embeddedice_receive(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size); int embeddedice_send(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size); int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeout); /* If many embeddedice_write_reg() follow each other, then the >1 invocations can be * this faster version of embeddedice_write_reg */ static inline void embeddedice_write_reg_inner(struct jtag_tap *tap, int reg_addr, uint32_t value) { uint8_t out_reg_addr = (1 << 5) | reg_addr; uint8_t out_value[4]; buf_set_u32(out_value, 0, 32, value); struct scan_field fields[2] = { { .num_bits = 32, .out_value = out_value }, { .num_bits = 6, .out_value = &out_reg_addr }, }; jtag_add_dr_scan(tap, 2, fields, TAP_IDLE); } void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, const uint8_t *buffer, int little, int count); #endif /* OPENOCD_TARGET_EMBEDDEDICE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/esirisc.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * * James Zhao <hjz@squareup.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/binarybuffer.h> #include <helper/command.h> #include <helper/log.h> #include <helper/time_support.h> #include <helper/types.h> #include <jtag/interface.h> #include <target/breakpoints.h> #include <target/register.h> #include <target/target.h> #include <target/target_type.h> #include "esirisc.h" #define RESET_TIMEOUT 5000 /* 5s */ #define STEP_TIMEOUT 1000 /* 1s */ /* * eSi-RISC targets support a configurable number of interrupts; * up to 32 interrupts are supported. */ static const char * const esirisc_exception_strings[] = { [EID_RESET] = "Reset", [EID_HARDWARE_FAILURE] = "HardwareFailure", [EID_NMI] = "NMI", [EID_INST_BREAKPOINT] = "InstBreakpoint", [EID_DATA_BREAKPOINT] = "DataBreakpoint", [EID_UNSUPPORTED] = "Unsupported", [EID_PRIVILEGE_VIOLATION] = "PrivilegeViolation", [EID_INST_BUS_ERROR] = "InstBusError", [EID_DATA_BUS_ERROR] = "DataBusError", [EID_ALIGNMENT_ERROR] = "AlignmentError", [EID_ARITHMETIC_ERROR] = "ArithmeticError", [EID_SYSTEM_CALL] = "SystemCall", [EID_MEMORY_MANAGEMENT] = "MemoryManagement", [EID_UNRECOVERABLE] = "Unrecoverable", [EID_INTERRUPT_N+0] = "Interrupt0", [EID_INTERRUPT_N+1] = "Interrupt1", [EID_INTERRUPT_N+2] = "Interrupt2", [EID_INTERRUPT_N+3] = "Interrupt3", [EID_INTERRUPT_N+4] = "Interrupt4", [EID_INTERRUPT_N+5] = "Interrupt5", [EID_INTERRUPT_N+6] = "Interrupt6", [EID_INTERRUPT_N+7] = "Interrupt7", [EID_INTERRUPT_N+8] = "Interrupt8", [EID_INTERRUPT_N+9] = "Interrupt9", [EID_INTERRUPT_N+10] = "Interrupt10", [EID_INTERRUPT_N+11] = "Interrupt11", [EID_INTERRUPT_N+12] = "Interrupt12", [EID_INTERRUPT_N+13] = "Interrupt13", [EID_INTERRUPT_N+14] = "Interrupt14", [EID_INTERRUPT_N+15] = "Interrupt15", [EID_INTERRUPT_N+16] = "Interrupt16", [EID_INTERRUPT_N+17] = "Interrupt17", [EID_INTERRUPT_N+18] = "Interrupt18", [EID_INTERRUPT_N+19] = "Interrupt19", [EID_INTERRUPT_N+20] = "Interrupt20", [EID_INTERRUPT_N+21] = "Interrupt21", [EID_INTERRUPT_N+22] = "Interrupt22", [EID_INTERRUPT_N+23] = "Interrupt23", [EID_INTERRUPT_N+24] = "Interrupt24", [EID_INTERRUPT_N+25] = "Interrupt25", [EID_INTERRUPT_N+26] = "Interrupt26", [EID_INTERRUPT_N+27] = "Interrupt27", [EID_INTERRUPT_N+28] = "Interrupt28", [EID_INTERRUPT_N+29] = "Interrupt29", [EID_INTERRUPT_N+30] = "Interrupt30", [EID_INTERRUPT_N+31] = "Interrupt31", }; /* * eSi-RISC targets support a configurable number of general purpose * registers; 8, 16, and 32 registers are supported. */ static const struct { enum esirisc_reg_num number; const char *name; enum reg_type type; const char *group; } esirisc_regs[] = { { ESIRISC_SP, "sp", REG_TYPE_DATA_PTR, "general" }, { ESIRISC_RA, "ra", REG_TYPE_INT, "general" }, { ESIRISC_R2, "r2", REG_TYPE_INT, "general" }, { ESIRISC_R3, "r3", REG_TYPE_INT, "general" }, { ESIRISC_R4, "r4", REG_TYPE_INT, "general" }, { ESIRISC_R5, "r5", REG_TYPE_INT, "general" }, { ESIRISC_R6, "r6", REG_TYPE_INT, "general" }, { ESIRISC_R7, "r7", REG_TYPE_INT, "general" }, { ESIRISC_R8, "r8", REG_TYPE_INT, "general" }, { ESIRISC_R9, "r9", REG_TYPE_INT, "general" }, { ESIRISC_R10, "r10", REG_TYPE_INT, "general" }, { ESIRISC_R11, "r11", REG_TYPE_INT, "general" }, { ESIRISC_R12, "r12", REG_TYPE_INT, "general" }, { ESIRISC_R13, "r13", REG_TYPE_INT, "general" }, { ESIRISC_R14, "r14", REG_TYPE_INT, "general" }, { ESIRISC_R15, "r15", REG_TYPE_INT, "general" }, { ESIRISC_R16, "r16", REG_TYPE_INT, "general" }, { ESIRISC_R17, "r17", REG_TYPE_INT, "general" }, { ESIRISC_R18, "r18", REG_TYPE_INT, "general" }, { ESIRISC_R19, "r19", REG_TYPE_INT, "general" }, { ESIRISC_R20, "r20", REG_TYPE_INT, "general" }, { ESIRISC_R21, "r21", REG_TYPE_INT, "general" }, { ESIRISC_R22, "r22", REG_TYPE_INT, "general" }, { ESIRISC_R23, "r23", REG_TYPE_INT, "general" }, { ESIRISC_R24, "r24", REG_TYPE_INT, "general" }, { ESIRISC_R25, "r25", REG_TYPE_INT, "general" }, { ESIRISC_R26, "r26", REG_TYPE_INT, "general" }, { ESIRISC_R27, "r27", REG_TYPE_INT, "general" }, { ESIRISC_R28, "r28", REG_TYPE_INT, "general" }, { ESIRISC_R29, "r29", REG_TYPE_INT, "general" }, { ESIRISC_R30, "r30", REG_TYPE_INT, "general" }, { ESIRISC_R31, "r31", REG_TYPE_INT, "general" }, }; /* * Control and Status Registers (CSRs) are largely defined as belonging * to the system register group. The exception to this rule are the PC * and CAS registers, which belong to the general group. While debug is * active, EPC, ECAS, and ETC must be used to read and write the PC, * CAS, and TC CSRs, respectively. */ static const struct { enum esirisc_reg_num number; uint8_t bank; uint8_t csr; const char *name; enum reg_type type; const char *group; } esirisc_csrs[] = { { ESIRISC_PC, CSR_THREAD, CSR_THREAD_EPC, "PC", REG_TYPE_CODE_PTR, "general" }, /* PC -> EPC */ { ESIRISC_CAS, CSR_THREAD, CSR_THREAD_ECAS, "CAS", REG_TYPE_INT, "general" }, /* CAS -> ECAS */ { ESIRISC_TC, CSR_THREAD, CSR_THREAD_ETC, "TC", REG_TYPE_INT, "system" }, /* TC -> ETC */ { ESIRISC_ETA, CSR_THREAD, CSR_THREAD_ETA, "ETA", REG_TYPE_INT, "system" }, { ESIRISC_ETC, CSR_THREAD, CSR_THREAD_ETC, "ETC", REG_TYPE_INT, "system" }, { ESIRISC_EPC, CSR_THREAD, CSR_THREAD_EPC, "EPC", REG_TYPE_CODE_PTR, "system" }, { ESIRISC_ECAS, CSR_THREAD, CSR_THREAD_ECAS, "ECAS", REG_TYPE_INT, "system" }, { ESIRISC_EID, CSR_THREAD, CSR_THREAD_EID, "EID", REG_TYPE_INT, "system" }, { ESIRISC_ED, CSR_THREAD, CSR_THREAD_ED, "ED", REG_TYPE_INT, "system" }, { ESIRISC_IP, CSR_INTERRUPT, CSR_INTERRUPT_IP, "IP", REG_TYPE_INT, "system"}, { ESIRISC_IM, CSR_INTERRUPT, CSR_INTERRUPT_IM, "IM", REG_TYPE_INT, "system"}, { ESIRISC_IS, CSR_INTERRUPT, CSR_INTERRUPT_IS, "IS", REG_TYPE_INT, "system"}, { ESIRISC_IT, CSR_INTERRUPT, CSR_INTERRUPT_IT, "IT", REG_TYPE_INT, "system"}, }; static int esirisc_disable_interrupts(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; uint32_t etc; int retval; LOG_DEBUG("-"); retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, &etc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Thread CSR: ETC", target_name(target)); return retval; } etc &= ~(1<<0); /* TC.I */ retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, etc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Thread CSR: ETC", target_name(target)); return retval; } return ERROR_OK; } #if 0 static int esirisc_enable_interrupts(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; uint32_t etc; int retval; LOG_DEBUG("-"); retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, &etc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Thread CSR: ETC", target_name(target)); return retval; } etc |= (1<<0); /* TC.I */ retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, etc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Thread CSR: ETC", target_name(target)); return retval; } return ERROR_OK; } #endif static int esirisc_save_interrupts(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; LOG_DEBUG("-"); int retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, &esirisc->etc_save); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Thread CSR: ETC", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_restore_interrupts(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; LOG_DEBUG("-"); int retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, esirisc->etc_save); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Thread CSR: ETC", target_name(target)); return retval; } return ERROR_OK; } #if 0 static int esirisc_save_hwdc(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; LOG_DEBUG("-"); int retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_HWDC, &esirisc->hwdc_save); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Thread CSR: HWDC", target_name(target)); return retval; } return ERROR_OK; } #endif static int esirisc_restore_hwdc(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; LOG_DEBUG("-"); int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_HWDC, esirisc->hwdc_save); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Debug CSR: HWDC", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_save_context(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); LOG_DEBUG("-"); for (unsigned i = 0; i < esirisc->reg_cache->num_regs; ++i) { struct reg *reg = esirisc->reg_cache->reg_list + i; struct esirisc_reg *reg_info = reg->arch_info; if (reg->exist && !reg->valid) reg_info->read(reg); } return ERROR_OK; } static int esirisc_restore_context(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); LOG_DEBUG("-"); for (unsigned i = 0; i < esirisc->reg_cache->num_regs; ++i) { struct reg *reg = esirisc->reg_cache->reg_list + i; struct esirisc_reg *reg_info = reg->arch_info; if (reg->exist && reg->dirty) reg_info->write(reg); } return ERROR_OK; } static int esirisc_flush_caches(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; int retval = esirisc_jtag_flush_caches(jtag_info); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to flush caches", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_wait_debug_active(struct esirisc_common *esirisc, int ms) { struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int64_t t; LOG_DEBUG("-"); t = timeval_ms(); for (;;) { int retval = esirisc_jtag_enable_debug(jtag_info); if (retval == ERROR_OK && esirisc_jtag_is_debug_active(jtag_info)) return retval; if ((timeval_ms() - t) > ms) return ERROR_TARGET_TIMEOUT; alive_sleep(100); } } static int esirisc_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; LOG_DEBUG("-"); int num_bits = 8 * size; for (uint32_t i = 0; i < count; ++i) { union esirisc_memory value; void *value_p; switch (size) { case sizeof(value.word): value_p = &value.word; retval = esirisc_jtag_read_word(jtag_info, address, value_p); break; case sizeof(value.hword): value_p = &value.hword; retval = esirisc_jtag_read_hword(jtag_info, address, value_p); break; case sizeof(value.byte): value_p = &value.byte; retval = esirisc_jtag_read_byte(jtag_info, address, value_p); break; default: LOG_ERROR("%s: unsupported size: %" PRIu32, target_name(target), size); return ERROR_FAIL; } if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read address: 0x%" TARGET_PRIxADDR, target_name(target), address); return retval; } buf_cpy(value_p, buffer, num_bits); address += size; buffer += size; } return ERROR_OK; } static int esirisc_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; LOG_DEBUG("-"); int num_bits = 8 * size; for (uint32_t i = 0; i < count; ++i) { union esirisc_memory value; switch (size) { case sizeof(value.word): value.word = buf_get_u32(buffer, 0, num_bits); retval = esirisc_jtag_write_word(jtag_info, address, value.word); break; case sizeof(value.hword): value.hword = buf_get_u32(buffer, 0, num_bits); retval = esirisc_jtag_write_hword(jtag_info, address, value.hword); break; case sizeof(value.byte): value.byte = buf_get_u32(buffer, 0, num_bits); retval = esirisc_jtag_write_byte(jtag_info, address, value.byte); break; default: LOG_ERROR("%s: unsupported size: %" PRIu32, target_name(target), size); return ERROR_FAIL; } if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write address: 0x%" TARGET_PRIxADDR, target_name(target), address); return retval; } address += size; buffer += size; } return ERROR_OK; } static int esirisc_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { return ERROR_FAIL; /* not supported */ } static int esirisc_next_breakpoint(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct breakpoint **breakpoints_p = esirisc->breakpoints_p; struct breakpoint **breakpoints_e = breakpoints_p + esirisc->num_breakpoints; LOG_DEBUG("-"); for (int bp_index = 0; breakpoints_p < breakpoints_e; ++breakpoints_p, ++bp_index) if (!*breakpoints_p) return bp_index; return -1; } static int esirisc_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int bp_index; uint32_t ibc; int retval; LOG_DEBUG("-"); /* * The default linker scripts provided by the eSi-RISC toolchain do * not specify attributes on memory regions, which results in * incorrect application of software breakpoints by GDB. Targets * must be configured with `gdb_breakpoint_override hard` as * software breakpoints are not supported. */ if (breakpoint->type != BKPT_HARD) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; bp_index = esirisc_next_breakpoint(target); if (bp_index < 0) { LOG_ERROR("%s: out of hardware breakpoints", target_name(target)); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint_hw_set(breakpoint, bp_index); esirisc->breakpoints_p[bp_index] = breakpoint; /* specify instruction breakpoint address */ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBA_N + bp_index, breakpoint->address); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Debug CSR: IBA", target_name(target)); return retval; } /* enable instruction breakpoint */ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, &ibc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Debug CSR: IBC", target_name(target)); return retval; } ibc |= (1 << bp_index); /* IBC.In */ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, ibc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Debug CSR: IBC", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_add_breakpoints(struct target *target) { struct breakpoint *breakpoint = target->breakpoints; LOG_DEBUG("-"); while (breakpoint) { if (!breakpoint->is_set) esirisc_add_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } return ERROR_OK; } static int esirisc_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; unsigned int bp_index = breakpoint->number; uint32_t ibc; int retval; LOG_DEBUG("-"); /* disable instruction breakpoint */ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, &ibc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Debug CSR: IBC", target_name(target)); return retval; } ibc &= ~(1 << bp_index); /* IBC.In */ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, ibc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Debug CSR: IBC", target_name(target)); return retval; } esirisc->breakpoints_p[bp_index] = NULL; breakpoint->is_set = false; return ERROR_OK; } static int esirisc_remove_breakpoints(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; LOG_DEBUG("-"); /* clear instruction breakpoints */ int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, 0); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Debug CSR: IBC", target_name(target)); return retval; } memset(esirisc->breakpoints_p, 0, sizeof(esirisc->breakpoints_p)); return ERROR_OK; } static int esirisc_next_watchpoint(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct watchpoint **watchpoints_p = esirisc->watchpoints_p; struct watchpoint **watchpoints_e = watchpoints_p + esirisc->num_watchpoints; LOG_DEBUG("-"); for (int wp_index = 0; watchpoints_p < watchpoints_e; ++watchpoints_p, ++wp_index) if (!*watchpoints_p) return wp_index; return -1; } static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int wp_index; uint32_t dbs, dbc; int retval; LOG_DEBUG("-"); wp_index = esirisc_next_watchpoint(target); if (wp_index < 0) { LOG_ERROR("%s: out of hardware watchpoints", target_name(target)); return ERROR_FAIL; } watchpoint_set(watchpoint, wp_index); esirisc->watchpoints_p[wp_index] = watchpoint; /* specify data breakpoint address */ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBA_N + wp_index, watchpoint->address); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Debug CSR: DBA", target_name(target)); return retval; } /* specify data breakpoint size */ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBS, &dbs); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Debug CSR: DBS", target_name(target)); return retval; } uint32_t sn; switch (watchpoint->length) { case sizeof(uint64_t): sn = 0x3; break; case sizeof(uint32_t): sn = 0x2; break; case sizeof(uint16_t): sn = 0x1; break; case sizeof(uint8_t): sn = 0x0; break; default: LOG_ERROR("%s: unsupported length: %" PRIu32, target_name(target), watchpoint->length); return ERROR_FAIL; } dbs |= (sn << (2 * wp_index)); /* DBS.Sn */ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBS, dbs); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Debug CSR: DBS", target_name(target)); return retval; } /* enable data breakpoint */ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, &dbc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Debug CSR: DBC", target_name(target)); return retval; } uint32_t dn; switch (watchpoint->rw) { case WPT_READ: dn = 0x1; break; case WPT_WRITE: dn = 0x2; break; case WPT_ACCESS: dn = 0x3; break; default: LOG_ERROR("%s: unsupported rw: %" PRId32, target_name(target), watchpoint->rw); return ERROR_FAIL; } dbc |= (dn << (2 * wp_index)); /* DBC.Dn */ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, dbc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Debug CSR: DBC", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_add_watchpoints(struct target *target) { struct watchpoint *watchpoint = target->watchpoints; LOG_DEBUG("-"); while (watchpoint) { if (!watchpoint->is_set) esirisc_add_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } return ERROR_OK; } static int esirisc_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; unsigned int wp_index = watchpoint->number; uint32_t dbc; int retval; LOG_DEBUG("-"); /* disable data breakpoint */ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, &dbc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Debug CSR: DBC", target_name(target)); return retval; } dbc &= ~(0x3 << (2 * wp_index)); /* DBC.Dn */ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, dbc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Debug CSR: DBC", target_name(target)); return retval; } esirisc->watchpoints_p[wp_index] = NULL; watchpoint->is_set = false; return ERROR_OK; } static int esirisc_remove_watchpoints(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; LOG_DEBUG("-"); /* clear data breakpoints */ int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, 0); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Debug CSR: DBC", target_name(target)); return retval; } memset(esirisc->watchpoints_p, 0, sizeof(esirisc->watchpoints_p)); return ERROR_OK; } static int esirisc_halt(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; LOG_DEBUG("-"); if (target->state == TARGET_HALTED) return ERROR_OK; int retval = esirisc_jtag_break(jtag_info); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to halt target", target_name(target)); return retval; } target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int esirisc_disable_step(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; uint32_t dc; int retval; LOG_DEBUG("-"); retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, &dc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Debug CSR: DC", target_name(target)); return retval; } dc &= ~(1<<0); /* DC.S */ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, dc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Debug CSR: DC", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_enable_step(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; uint32_t dc; int retval; LOG_DEBUG("-"); retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, &dc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Debug CSR: DC", target_name(target)); return retval; } dc |= (1<<0); /* DC.S */ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, dc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Debug CSR: DC", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_resume_or_step(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution, bool step) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; struct breakpoint *breakpoint = NULL; int retval; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; if (!debug_execution) { target_free_all_working_areas(target); esirisc_add_breakpoints(target); esirisc_add_watchpoints(target); } if (current) address = buf_get_u32(esirisc->epc->value, 0, esirisc->epc->size); else { buf_set_u32(esirisc->epc->value, 0, esirisc->epc->size, address); esirisc->epc->dirty = true; esirisc->epc->valid = true; } esirisc_restore_context(target); if (esirisc_has_cache(esirisc)) esirisc_flush_caches(target); if (handle_breakpoints) { breakpoint = breakpoint_find(target, address); if (breakpoint) esirisc_remove_breakpoint(target, breakpoint); } if (step) { esirisc_disable_interrupts(target); esirisc_enable_step(target); target->debug_reason = DBG_REASON_SINGLESTEP; } else { esirisc_disable_step(target); esirisc_restore_interrupts(target); target->debug_reason = DBG_REASON_NOTHALTED; } esirisc_restore_hwdc(target); retval = esirisc_jtag_continue(jtag_info); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to resume target", target_name(target)); return retval; } register_cache_invalidate(esirisc->reg_cache); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); } return ERROR_OK; } static int esirisc_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { LOG_DEBUG("-"); return esirisc_resume_or_step(target, current, address, handle_breakpoints, debug_execution, false); } static int esirisc_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { LOG_DEBUG("-"); return esirisc_resume_or_step(target, current, address, handle_breakpoints, 0, true); } static int esirisc_debug_step(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; LOG_DEBUG("-"); esirisc_disable_interrupts(target); esirisc_enable_step(target); retval = esirisc_jtag_continue(jtag_info); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to resume target", target_name(target)); return retval; } retval = esirisc_wait_debug_active(esirisc, STEP_TIMEOUT); if (retval != ERROR_OK) { LOG_ERROR("%s: step timed out", target_name(target)); return retval; } esirisc_disable_step(target); esirisc_restore_interrupts(target); return ERROR_OK; } static int esirisc_debug_reset(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; LOG_DEBUG("-"); retval = esirisc_jtag_assert_reset(jtag_info); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to assert reset", target_name(target)); return retval; } retval = esirisc_jtag_deassert_reset(jtag_info); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to deassert reset", target_name(target)); return retval; } retval = esirisc_wait_debug_active(esirisc, RESET_TIMEOUT); if (retval != ERROR_OK) { LOG_ERROR("%s: reset timed out", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_debug_enable(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; LOG_DEBUG("-"); retval = esirisc_jtag_enable_debug(jtag_info); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to enable debug mode", target_name(target)); return retval; } /* * The debug clock is inactive until the first command is sent. * If the target is stopped, we must first issue a reset before * attempting further communication. This also handles unpowered * targets, which will respond with all ones and appear active. */ if (esirisc_jtag_is_stopped(jtag_info)) { LOG_INFO("%s: debug clock inactive; attempting debug reset", target_name(target)); retval = esirisc_debug_reset(target); if (retval != ERROR_OK) return retval; if (esirisc_jtag_is_stopped(jtag_info)) { LOG_ERROR("%s: target unresponsive; giving up", target_name(target)); return ERROR_FAIL; } } return ERROR_OK; } static int esirisc_debug_entry(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct breakpoint *breakpoint; LOG_DEBUG("-"); esirisc_save_context(target); if (esirisc_has_cache(esirisc)) esirisc_flush_caches(target); if (target->debug_reason != DBG_REASON_SINGLESTEP) { esirisc_save_interrupts(target); uint32_t eid = buf_get_u32(esirisc->eid->value, 0, esirisc->eid->size); switch (eid) { /* * InstBreakpoint exceptions are also raised when a core is * halted for debugging. The following is required to * determine if a breakpoint was encountered. */ case EID_INST_BREAKPOINT: breakpoint = breakpoint_find(target, buf_get_u32(esirisc->epc->value, 0, esirisc->epc->size)); target->debug_reason = (breakpoint) ? DBG_REASON_BREAKPOINT : DBG_REASON_DBGRQ; break; /* * eSi-RISC treats watchpoints similarly to breakpoints, * however GDB will not request to step over the current * instruction when a watchpoint fires. The following is * required to resume the target. */ case EID_DATA_BREAKPOINT: esirisc_remove_watchpoints(target); esirisc_debug_step(target); esirisc_add_watchpoints(target); target->debug_reason = DBG_REASON_WATCHPOINT; break; default: target->debug_reason = DBG_REASON_DBGRQ; } } return ERROR_OK; } static int esirisc_poll(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; retval = esirisc_jtag_enable_debug(jtag_info); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to poll target", target_name(target)); return retval; } if (esirisc_jtag_is_stopped(jtag_info)) { LOG_ERROR("%s: target has stopped; reset required", target_name(target)); target->state = TARGET_UNKNOWN; return ERROR_TARGET_FAILURE; } if (esirisc_jtag_is_debug_active(jtag_info)) { if (target->state == TARGET_RUNNING || target->state == TARGET_RESET) { target->state = TARGET_HALTED; retval = esirisc_debug_entry(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); } } else if (target->state == TARGET_HALTED || target->state == TARGET_RESET) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); } return ERROR_OK; } static int esirisc_assert_reset(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; LOG_DEBUG("-"); if (jtag_get_reset_config() & RESET_HAS_SRST) { jtag_add_reset(1, 1); if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) == 0) jtag_add_reset(0, 1); } else { esirisc_remove_breakpoints(target); esirisc_remove_watchpoints(target); retval = esirisc_jtag_assert_reset(jtag_info); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to assert reset", target_name(target)); return retval; } } target->state = TARGET_RESET; register_cache_invalidate(esirisc->reg_cache); return ERROR_OK; } static int esirisc_reset_entry(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; uint32_t eta, epc; int retval; LOG_DEBUG("-"); /* read exception table address */ retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETA, &eta); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Thread CSR: ETA", target_name(target)); return retval; } /* read reset entry point */ retval = esirisc_jtag_read_word(jtag_info, eta + ENTRY_RESET, &epc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read address: 0x%" TARGET_PRIxADDR, target_name(target), (target_addr_t)epc); return retval; } /* write reset entry point */ retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_EPC, epc); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Thread CSR: EPC", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_deassert_reset(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; LOG_DEBUG("-"); if (jtag_get_reset_config() & RESET_HAS_SRST) { jtag_add_reset(0, 0); retval = esirisc_debug_enable(target); if (retval != ERROR_OK) return retval; retval = esirisc_debug_reset(target); if (retval != ERROR_OK) return retval; } else { retval = esirisc_jtag_deassert_reset(jtag_info); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to deassert reset", target_name(target)); return retval; } } retval = esirisc_wait_debug_active(esirisc, RESET_TIMEOUT); if (retval != ERROR_OK) { LOG_ERROR("%s: reset timed out", target_name(target)); return retval; } retval = esirisc_reset_entry(target); if (retval != ERROR_OK) return retval; esirisc_add_breakpoints(target); esirisc_add_watchpoints(target); esirisc_restore_hwdc(target); if (!target->reset_halt) { retval = esirisc_jtag_continue(jtag_info); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to resume target", target_name(target)); return retval; } } return ERROR_OK; } static int esirisc_arch_state(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); uint32_t epc = buf_get_u32(esirisc->epc->value, 0, esirisc->epc->size); uint32_t ecas = buf_get_u32(esirisc->ecas->value, 0, esirisc->ecas->size); uint32_t eid = buf_get_u32(esirisc->eid->value, 0, esirisc->eid->size); uint32_t ed = buf_get_u32(esirisc->ed->value, 0, esirisc->ed->size); LOG_USER("target halted due to %s, exception: %s\n" "EPC: 0x%" PRIx32 ", ECAS: 0x%" PRIx32 ", EID: 0x%" PRIx32 ", ED: 0x%" PRIx32, debug_reason_name(target), esirisc_exception_strings[eid], epc, ecas, eid, ed); return ERROR_OK; } static const char *esirisc_get_gdb_arch(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); LOG_DEBUG("-"); /* * Targets with the UNIFIED_ADDRESS_SPACE option disabled employ a * Harvard architecture. This option is not exposed in a CSR, which * requires additional configuration to properly interact with these * targets in GDB (also see: `esirisc cache_arch`). */ if (!esirisc->gdb_arch && target_was_examined(target)) esirisc->gdb_arch = alloc_printf("esirisc:%d_bit_%d_reg_%s", esirisc->num_bits, esirisc->num_regs, esirisc_cache_arch_name(esirisc)); return esirisc->gdb_arch; } static int esirisc_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { struct esirisc_common *esirisc = target_to_esirisc(target); LOG_DEBUG("-"); *reg_list_size = ESIRISC_NUM_REGS; *reg_list = calloc(*reg_list_size, sizeof(struct reg *)); if (!*reg_list) return ERROR_FAIL; if (reg_class == REG_CLASS_ALL) for (int i = 0; i < *reg_list_size; ++i) (*reg_list)[i] = esirisc->reg_cache->reg_list + i; else { for (int i = 0; i < esirisc->num_regs; ++i) (*reg_list)[i] = esirisc->reg_cache->reg_list + i; (*reg_list)[ESIRISC_PC] = esirisc->reg_cache->reg_list + ESIRISC_PC; (*reg_list)[ESIRISC_CAS] = esirisc->reg_cache->reg_list + ESIRISC_CAS; } return ERROR_OK; } static int esirisc_read_reg(struct reg *reg) { struct esirisc_reg *reg_info = reg->arch_info; struct esirisc_common *esirisc = reg_info->esirisc; struct esirisc_jtag *jtag_info = &esirisc->jtag_info; struct target *target = esirisc->target; uint32_t data; LOG_DEBUG("-"); int retval = esirisc_jtag_read_reg(jtag_info, reg->number, &data); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read register: %s", target_name(target), reg->name); return retval; } buf_set_u32(reg->value, 0, reg->size, data); reg->dirty = false; reg->valid = true; return ERROR_OK; } static int esirisc_write_reg(struct reg *reg) { struct esirisc_reg *reg_info = reg->arch_info; struct esirisc_common *esirisc = reg_info->esirisc; struct esirisc_jtag *jtag_info = &esirisc->jtag_info; struct target *target = esirisc->target; uint32_t data = buf_get_u32(reg->value, 0, reg->size); LOG_DEBUG("-"); int retval = esirisc_jtag_write_reg(jtag_info, reg->number, data); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write register: %s", target_name(target), reg->name); return retval; } reg->dirty = false; reg->valid = true; return ERROR_OK; } static int esirisc_read_csr(struct reg *reg) { struct esirisc_reg *reg_info = reg->arch_info; struct esirisc_common *esirisc = reg_info->esirisc; struct esirisc_jtag *jtag_info = &esirisc->jtag_info; struct target *target = esirisc->target; uint32_t data; LOG_DEBUG("-"); int retval = esirisc_jtag_read_csr(jtag_info, reg_info->bank, reg_info->csr, &data); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read CSR: %s", target_name(target), reg->name); return retval; } buf_set_u32(reg->value, 0, reg->size, data); reg->dirty = false; reg->valid = true; return ERROR_OK; } static int esirisc_write_csr(struct reg *reg) { struct esirisc_reg *reg_info = reg->arch_info; struct esirisc_common *esirisc = reg_info->esirisc; struct esirisc_jtag *jtag_info = &esirisc->jtag_info; struct target *target = esirisc->target; uint32_t data = buf_get_u32(reg->value, 0, reg->size); LOG_DEBUG("-"); int retval = esirisc_jtag_write_csr(jtag_info, reg_info->bank, reg_info->csr, data); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write CSR: %s", target_name(target), reg->name); return retval; } reg->dirty = false; reg->valid = true; return ERROR_OK; } static int esirisc_get_reg(struct reg *reg) { struct esirisc_reg *reg_info = reg->arch_info; struct esirisc_common *esirisc = reg_info->esirisc; struct target *target = esirisc->target; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; return reg_info->read(reg); } static int esirisc_set_reg(struct reg *reg, uint8_t *buf) { struct esirisc_reg *reg_info = reg->arch_info; struct esirisc_common *esirisc = reg_info->esirisc; struct target *target = esirisc->target; uint32_t value = buf_get_u32(buf, 0, reg->size); LOG_DEBUG("-"); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; buf_set_u32(reg->value, 0, reg->size, value); reg->dirty = true; reg->valid = true; return ERROR_OK; } static const struct reg_arch_type esirisc_reg_type = { .get = esirisc_get_reg, .set = esirisc_set_reg, }; static struct reg_cache *esirisc_build_reg_cache(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(ESIRISC_NUM_REGS, sizeof(struct reg)); LOG_DEBUG("-"); cache->name = "eSi-RISC registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = ESIRISC_NUM_REGS; (*cache_p) = cache; esirisc->reg_cache = cache; esirisc->epc = reg_list + ESIRISC_EPC; esirisc->ecas = reg_list + ESIRISC_ECAS; esirisc->eid = reg_list + ESIRISC_EID; esirisc->ed = reg_list + ESIRISC_ED; for (int i = 0; i < esirisc->num_regs; ++i) { struct reg *reg = reg_list + esirisc_regs[i].number; struct esirisc_reg *reg_info = calloc(1, sizeof(struct esirisc_reg)); reg->name = esirisc_regs[i].name; reg->number = esirisc_regs[i].number; reg->value = calloc(1, DIV_ROUND_UP(esirisc->num_bits, 8)); reg->size = esirisc->num_bits; reg->reg_data_type = calloc(1, sizeof(struct reg_data_type)); reg->reg_data_type->type = esirisc_regs[i].type; reg->group = esirisc_regs[i].group; reg_info->esirisc = esirisc; reg_info->read = esirisc_read_reg; reg_info->write = esirisc_write_reg; reg->arch_info = reg_info; reg->type = &esirisc_reg_type; reg->exist = true; } for (size_t i = 0; i < ARRAY_SIZE(esirisc_csrs); ++i) { struct reg *reg = reg_list + esirisc_csrs[i].number; struct esirisc_reg *reg_info = calloc(1, sizeof(struct esirisc_reg)); reg->name = esirisc_csrs[i].name; reg->number = esirisc_csrs[i].number; reg->value = calloc(1, DIV_ROUND_UP(esirisc->num_bits, 8)); reg->size = esirisc->num_bits; reg->reg_data_type = calloc(1, sizeof(struct reg_data_type)); reg->reg_data_type->type = esirisc_csrs[i].type; reg->group = esirisc_csrs[i].group; reg_info->esirisc = esirisc; reg_info->bank = esirisc_csrs[i].bank; reg_info->csr = esirisc_csrs[i].csr; reg_info->read = esirisc_read_csr; reg_info->write = esirisc_write_csr; reg->arch_info = reg_info; reg->type = &esirisc_reg_type; reg->exist = true; } return cache; } static int esirisc_identify(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; uint32_t csr; int retval; LOG_DEBUG("-"); retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_ARCH0, &csr); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Configuration CSR: ARCH0", target_name(target)); return retval; } esirisc->num_bits = (csr >> 0) & 0x3f; /* ARCH0.B */ esirisc->num_regs = (csr >> 10) & 0x3f; /* ARCH0.R */ retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_MEM, &csr); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Configuration CSR: MEM", target_name(target)); return retval; } target->endianness = (csr & 1<<0) ? /* MEM.E */ TARGET_BIG_ENDIAN : TARGET_LITTLE_ENDIAN; retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_IC, &csr); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Configuration CSR: IC", target_name(target)); return retval; } esirisc->has_icache = !!(csr & 1<<0); /* IC.E */ retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_DC, &csr); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Configuration CSR: DC", target_name(target)); return retval; } esirisc->has_dcache = !!(csr & 1<<0); /* DC.E */ retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_DBG, &csr); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Configuration CSR: DBG", target_name(target)); return retval; } esirisc->num_breakpoints = (csr >> 7) & 0xf; /* DBG.BP */ esirisc->num_watchpoints = (csr >> 12) & 0xf; /* DBG.WP */ retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_TRACE, &csr); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Configuration CSR: TRACE", target_name(target)); return retval; } esirisc->has_trace = !!(csr & 1<<0); /* TRACE.T */ return ERROR_OK; } static int esirisc_target_create(struct target *target, Jim_Interp *interp) { struct jtag_tap *tap = target->tap; struct esirisc_common *esirisc; if (!tap) return ERROR_FAIL; if (tap->ir_length != INSTR_LENGTH) { LOG_ERROR("%s: invalid IR length; expected %d", target_name(target), INSTR_LENGTH); return ERROR_FAIL; } esirisc = calloc(1, sizeof(struct esirisc_common)); if (!esirisc) return ERROR_FAIL; esirisc->target = target; esirisc->jtag_info.tap = tap; target->arch_info = esirisc; return ERROR_OK; } static int esirisc_init_target(struct command_context *cmd_ctx, struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); /* trap reset, error, and debug exceptions */ esirisc->hwdc_save = HWDC_R | HWDC_E | HWDC_D; return ERROR_OK; } static int esirisc_examine(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; LOG_DEBUG("-"); if (!target_was_examined(target)) { retval = esirisc_debug_enable(target); if (retval != ERROR_OK) return retval; /* * In order to identify the target we must first halt the core. * We quietly resume once identification has completed for those * targets that were running when target_examine was called. */ if (esirisc_jtag_is_debug_active(jtag_info)) { if (target->state == TARGET_UNKNOWN) target->debug_reason = DBG_REASON_DBGRQ; target->state = TARGET_HALTED; } else { retval = esirisc_jtag_break(jtag_info); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to halt target", target_name(target)); return retval; } target->state = TARGET_RUNNING; } retval = esirisc_identify(target); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to identify target", target_name(target)); return retval; } esirisc_build_reg_cache(target); esirisc_remove_breakpoints(target); esirisc_remove_watchpoints(target); esirisc_disable_step(target); esirisc_restore_hwdc(target); if (target->state == TARGET_HALTED) esirisc_save_interrupts(target); else { retval = esirisc_jtag_continue(jtag_info); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to resume target", target_name(target)); return retval; } } target_set_examined(target); LOG_INFO("%s: %d bit, %d registers, %s%s%s", target_name(target), esirisc->num_bits, esirisc->num_regs, target_endianness(target), esirisc->has_icache ? ", icache" : "", esirisc->has_dcache ? ", dcache" : ""); LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints%s", target_name(target), esirisc->num_breakpoints, esirisc->num_watchpoints, esirisc->has_trace ? ", trace" : ""); } return ERROR_OK; } COMMAND_HANDLER(handle_esirisc_cache_arch_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); if (CMD_ARGC > 0) { if (strcmp(*CMD_ARGV, "harvard") == 0) esirisc->cache_arch = ESIRISC_CACHE_HARVARD; else if (strcmp(*CMD_ARGV, "von_neumann") == 0) esirisc->cache_arch = ESIRISC_CACHE_VON_NEUMANN; else { LOG_ERROR("invalid cache_arch: %s", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; } } command_print(CMD, "esirisc cache_arch %s", esirisc_cache_arch_name(esirisc)); return ERROR_OK; } COMMAND_HANDLER(handle_esirisc_flush_caches_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); int retval; if (!esirisc_has_cache(esirisc)) { LOG_ERROR("target does not support caching"); return ERROR_FAIL; } retval = esirisc_flush_caches(target); command_print(CMD, "cache flush %s", (retval == ERROR_OK) ? "successful" : "failed"); return retval; } static const struct { const char *name; int mask; } esirisc_hwdc_masks[] = { { "reset", HWDC_R }, { "interrupt", HWDC_I }, { "syscall", HWDC_S }, { "error", HWDC_E }, { "debug", HWDC_D }, }; static int esirisc_find_hwdc_mask(const char *name) { for (size_t i = 0; i < ARRAY_SIZE(esirisc_hwdc_masks); ++i) if (strcmp(esirisc_hwdc_masks[i].name, name) == 0) return esirisc_hwdc_masks[i].mask; return -1; } COMMAND_HANDLER(handle_esirisc_hwdc_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); if (CMD_ARGC > 0) { if (strcmp(CMD_ARGV[0], "all") == 0) esirisc->hwdc_save = HWDC_R | HWDC_I | HWDC_S | HWDC_E | HWDC_D; else { esirisc->hwdc_save = 0; if (strcmp(CMD_ARGV[0], "none") != 0) { while (CMD_ARGC-- > 0) { int mask = esirisc_find_hwdc_mask(CMD_ARGV[CMD_ARGC]); if (mask < 0) { LOG_ERROR("invalid mask: %s", CMD_ARGV[CMD_ARGC]); return ERROR_COMMAND_SYNTAX_ERROR; } esirisc->hwdc_save |= mask; } } } } for (size_t i = 0; i < ARRAY_SIZE(esirisc_hwdc_masks); ++i) command_print(CMD, "%9s: %s", esirisc_hwdc_masks[i].name, (esirisc->hwdc_save & esirisc_hwdc_masks[i].mask) ? "enabled" : "disabled"); return ERROR_OK; } static const struct command_registration esirisc_exec_command_handlers[] = { { .name = "flush_caches", .handler = handle_esirisc_flush_caches_command, .mode = COMMAND_EXEC, .help = "flush instruction and data caches", .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration esirisc_any_command_handlers[] = { { .name = "cache_arch", .handler = handle_esirisc_cache_arch_command, .mode = COMMAND_ANY, .help = "configure cache architecture", .usage = "['harvard'|'von_neumann']", }, { .name = "hwdc", .handler = handle_esirisc_hwdc_command, .mode = COMMAND_ANY, .help = "configure hardware debug control", .usage = "['all'|'none'|mask ...]", }, { .chain = esirisc_exec_command_handlers }, { .chain = esirisc_trace_command_handlers }, COMMAND_REGISTRATION_DONE }; static const struct command_registration esirisc_command_handlers[] = { { .name = "esirisc", .mode = COMMAND_ANY, .help = "eSi-RISC command group", .usage = "", .chain = esirisc_any_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type esirisc_target = { .name = "esirisc", .poll = esirisc_poll, .arch_state = esirisc_arch_state, .halt = esirisc_halt, .resume = esirisc_resume, .step = esirisc_step, .assert_reset = esirisc_assert_reset, .deassert_reset = esirisc_deassert_reset, .get_gdb_arch = esirisc_get_gdb_arch, .get_gdb_reg_list = esirisc_get_gdb_reg_list, .read_memory = esirisc_read_memory, .write_memory = esirisc_write_memory, .checksum_memory = esirisc_checksum_memory, .add_breakpoint = esirisc_add_breakpoint, .remove_breakpoint = esirisc_remove_breakpoint, .add_watchpoint = esirisc_add_watchpoint, .remove_watchpoint = esirisc_remove_watchpoint, .commands = esirisc_command_handlers, .target_create = esirisc_target_create, .init_target = esirisc_init_target, .examine = esirisc_examine, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/esirisc.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * * James Zhao <hjz@squareup.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESIRISC_H #define OPENOCD_TARGET_ESIRISC_H #include <helper/types.h> #include <target/breakpoints.h> #include <target/register.h> #include <target/target.h> #include "esirisc_jtag.h" #include "esirisc_regs.h" #include "esirisc_trace.h" #define MAX_BREAKPOINTS 8 #define MAX_WATCHPOINTS 8 /* Exception IDs */ #define EID_RESET 0x00 #define EID_HARDWARE_FAILURE 0x01 #define EID_NMI 0x02 #define EID_INST_BREAKPOINT 0x03 #define EID_DATA_BREAKPOINT 0x04 #define EID_UNSUPPORTED 0x05 #define EID_PRIVILEGE_VIOLATION 0x06 #define EID_INST_BUS_ERROR 0x07 #define EID_DATA_BUS_ERROR 0x08 #define EID_ALIGNMENT_ERROR 0x09 #define EID_ARITHMETIC_ERROR 0x0a #define EID_SYSTEM_CALL 0x0b #define EID_MEMORY_MANAGEMENT 0x0c #define EID_UNRECOVERABLE 0x0d #define EID_INTERRUPT_N 0x20 /* Exception Entry Points */ #define ENTRY_RESET 0x00 #define ENTRY_UNRECOVERABLE 0x01 #define ENTRY_HARDWARE_FAILURE 0x02 #define ENTRY_RUNTIME 0x03 #define ENTRY_MEMORY 0x04 #define ENTRY_SYSCALL 0x05 #define ENTRY_DEBUG 0x06 #define ENTRY_NMI 0x07 #define ENTRY_INTERRUPT_N 0x08 /* Hardware Debug Control */ #define HWDC_R (1<<4) /* Reset & Hardware Failure */ #define HWDC_I (1<<3) /* Interrupts */ #define HWDC_S (1<<2) /* System Calls */ #define HWDC_E (1<<1) /* Program Errors */ #define HWDC_D (1<<0) /* Debug Exceptions */ enum esirisc_cache { ESIRISC_CACHE_VON_NEUMANN, ESIRISC_CACHE_HARVARD, }; struct esirisc_common { struct target *target; struct esirisc_jtag jtag_info; enum esirisc_cache cache_arch; char *gdb_arch; struct reg_cache *reg_cache; struct reg *epc; struct reg *ecas; struct reg *eid; struct reg *ed; uint32_t etc_save; uint32_t hwdc_save; int num_bits; int num_regs; bool has_icache; bool has_dcache; bool has_trace; int num_breakpoints; struct breakpoint *breakpoints_p[MAX_BREAKPOINTS]; int num_watchpoints; struct watchpoint *watchpoints_p[MAX_WATCHPOINTS]; struct esirisc_trace trace_info; }; union esirisc_memory { uint32_t word; uint16_t hword; uint8_t byte; }; struct esirisc_reg { struct esirisc_common *esirisc; uint8_t bank; uint8_t csr; int (*read)(struct reg *reg); int (*write)(struct reg *reg); }; static inline struct esirisc_common *target_to_esirisc(struct target *target) { return (struct esirisc_common *)target->arch_info; } static inline char *esirisc_cache_arch_name(struct esirisc_common *esirisc) { return esirisc->cache_arch == ESIRISC_CACHE_HARVARD ? "harvard" : "von_neumann"; } static inline bool esirisc_has_cache(struct esirisc_common *esirisc) { return esirisc->has_icache || esirisc->has_dcache; } #endif /* OPENOCD_TARGET_ESIRISC_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/esirisc_jtag.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * * James Zhao <hjz@squareup.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/binarybuffer.h> #include <helper/log.h> #include <helper/types.h> #include <jtag/jtag.h> #include <jtag/commands.h> #include <jtag/interface.h> #include "esirisc_jtag.h" static void esirisc_jtag_set_instr(struct esirisc_jtag *jtag_info, uint32_t new_instr) { struct jtag_tap *tap = jtag_info->tap; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; uint8_t t[4] = { 0 }; field.num_bits = tap->ir_length; field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); } } /* * The data register is latched every 8 bits while in the Shift-DR state * (Update-DR is not supported). This necessitates prepending padding * bits to ensure data is aligned when multiple TAPs are present. */ static int esirisc_jtag_get_padding(void) { int padding = 0; int bypass_devices = 0; for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap; tap = jtag_tap_next_enabled(tap)) if (tap->bypass) bypass_devices++; int num_bits = bypass_devices % 8; if (num_bits > 0) padding = 8 - num_bits; return padding; } static int esirisc_jtag_count_bits(int num_fields, struct scan_field *fields) { int bit_count = 0; for (int i = 0; i < num_fields; ++i) bit_count += fields[i].num_bits; return bit_count; } /* * Data received from the target will be byte-stuffed if it contains * either the pad byte (0xAA) or stuffing marker (0x55). Buffers should * be sized twice the expected length to account for stuffing overhead. */ static void esirisc_jtag_unstuff(uint8_t *data, size_t len) { uint8_t *r, *w; uint8_t *end; r = w = data; end = data + len; while (r < end) { if (*r == STUFF_MARKER) { r++; /* skip stuffing marker */ assert(r < end); *w++ = *r++ ^ STUFF_MARKER; } else *w++ = *r++; } } /* * The eSi-Debug protocol defines a byte-oriented command/response * channel that operates over serial or JTAG. While not strictly * required, separate DR scans are used for sending and receiving data. * This allows the TAP to recover gracefully if the byte stream is * corrupted at the expense of sending additional padding bits. */ static int esirisc_jtag_send(struct esirisc_jtag *jtag_info, uint8_t command, int num_out_fields, struct scan_field *out_fields) { int num_fields = 2 + num_out_fields; struct scan_field *fields = cmd_queue_alloc(num_fields * sizeof(struct scan_field)); esirisc_jtag_set_instr(jtag_info, INSTR_DEBUG); fields[0].num_bits = esirisc_jtag_get_padding(); fields[0].out_value = NULL; fields[0].in_value = NULL; fields[1].num_bits = 8; fields[1].out_value = &command; fields[1].in_value = NULL; /* append command data */ for (int i = 0; i < num_out_fields; ++i) jtag_scan_field_clone(&fields[2+i], &out_fields[i]); jtag_add_dr_scan(jtag_info->tap, num_fields, fields, TAP_IDLE); return jtag_execute_queue(); } static int esirisc_jtag_recv(struct esirisc_jtag *jtag_info, int num_in_fields, struct scan_field *in_fields) { int num_in_bits = esirisc_jtag_count_bits(num_in_fields, in_fields); int num_in_bytes = DIV_ROUND_UP(num_in_bits, 8); struct scan_field fields[3]; /* prevent zero-size variable length array */ int r_size = num_in_bytes ? num_in_bytes * 2 : 1; uint8_t r[r_size]; esirisc_jtag_set_instr(jtag_info, INSTR_DEBUG); fields[0].num_bits = esirisc_jtag_get_padding() + 1; fields[0].out_value = NULL; fields[0].in_value = NULL; fields[1].num_bits = 8; fields[1].out_value = NULL; fields[1].in_value = &jtag_info->status; fields[2].num_bits = num_in_bits * 2; fields[2].out_value = NULL; fields[2].in_value = r; jtag_add_dr_scan(jtag_info->tap, ARRAY_SIZE(fields), fields, TAP_IDLE); int retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* unstuff response data and write back to caller */ if (num_in_fields > 0) { esirisc_jtag_unstuff(r, ARRAY_SIZE(r)); int bit_count = 0; for (int i = 0; i < num_in_fields; ++i) { buf_set_buf(r, bit_count, in_fields[i].in_value, 0, in_fields[i].num_bits); bit_count += in_fields[i].num_bits; } } return ERROR_OK; } static int esirisc_jtag_check_status(struct esirisc_jtag *jtag_info) { uint8_t eid = esirisc_jtag_get_eid(jtag_info); if (eid != EID_NONE) { LOG_ERROR("esirisc_jtag: bad status: 0x%02" PRIx8 " (DA: %" PRId32 ", " "S: %" PRId32 ", EID: 0x%02" PRIx8 ")", jtag_info->status, esirisc_jtag_is_debug_active(jtag_info), esirisc_jtag_is_stopped(jtag_info), eid); return ERROR_FAIL; } return ERROR_OK; } static int esirisc_jtag_send_and_recv(struct esirisc_jtag *jtag_info, uint8_t command, int num_out_fields, struct scan_field *out_fields, int num_in_fields, struct scan_field *in_fields) { int retval; jtag_info->status = 0; /* clear status */ retval = esirisc_jtag_send(jtag_info, command, num_out_fields, out_fields); if (retval != ERROR_OK) { LOG_ERROR("esirisc_jtag: send failed (command: 0x%02" PRIx8 ")", command); return ERROR_FAIL; } retval = esirisc_jtag_recv(jtag_info, num_in_fields, in_fields); if (retval != ERROR_OK) { LOG_ERROR("esirisc_jtag: recv failed (command: 0x%02" PRIx8 ")", command); return ERROR_FAIL; } return esirisc_jtag_check_status(jtag_info); } /* * Status is automatically updated after each command completes; * these functions make each field available to the caller. */ bool esirisc_jtag_is_debug_active(struct esirisc_jtag *jtag_info) { return !!(jtag_info->status & 1<<7); /* DA */ } bool esirisc_jtag_is_stopped(struct esirisc_jtag *jtag_info) { return !!(jtag_info->status & 1<<6); /* S */ } uint8_t esirisc_jtag_get_eid(struct esirisc_jtag *jtag_info) { return jtag_info->status & 0x3f; /* EID */ } /* * Most commands manipulate target data (eg. memory and registers); each * command returns a status byte that indicates success. Commands must * transmit multibyte values in big-endian order, however response * values are in little-endian order. Target endianness does not have an * effect on this ordering. */ int esirisc_jtag_read_byte(struct esirisc_jtag *jtag_info, uint32_t address, uint8_t *data) { struct scan_field out_fields[1]; uint8_t a[4]; out_fields[0].num_bits = 32; out_fields[0].out_value = a; h_u32_to_be(a, address); out_fields[0].in_value = NULL; struct scan_field in_fields[1]; uint8_t d[1]; in_fields[0].num_bits = 8; in_fields[0].out_value = NULL; in_fields[0].in_value = d; int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_BYTE, ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields); if (retval != ERROR_OK) return retval; *data = *d; LOG_DEBUG("address: 0x%" PRIx32 ", data: 0x%" PRIx8, address, *data); return ERROR_OK; } int esirisc_jtag_read_hword(struct esirisc_jtag *jtag_info, uint32_t address, uint16_t *data) { struct scan_field out_fields[1]; uint8_t a[4]; out_fields[0].num_bits = 32; out_fields[0].out_value = a; h_u32_to_be(a, address); out_fields[0].in_value = NULL; struct scan_field in_fields[1]; uint8_t d[2]; in_fields[0].num_bits = 16; in_fields[0].out_value = NULL; in_fields[0].in_value = d; int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_HWORD, ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields); if (retval != ERROR_OK) return retval; *data = le_to_h_u16(d); LOG_DEBUG("address: 0x%" PRIx32 ", data: 0x%" PRIx16, address, *data); return ERROR_OK; } int esirisc_jtag_read_word(struct esirisc_jtag *jtag_info, uint32_t address, uint32_t *data) { struct scan_field out_fields[1]; uint8_t a[4]; out_fields[0].num_bits = 32; out_fields[0].out_value = a; h_u32_to_be(a, address); out_fields[0].in_value = NULL; struct scan_field in_fields[1]; uint8_t d[4]; in_fields[0].num_bits = 32; in_fields[0].out_value = NULL; in_fields[0].in_value = d; int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_WORD, ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields); if (retval != ERROR_OK) return retval; *data = le_to_h_u32(d); LOG_DEBUG("address: 0x%" PRIx32 ", data: 0x%" PRIx32, address, *data); return ERROR_OK; } int esirisc_jtag_write_byte(struct esirisc_jtag *jtag_info, uint32_t address, uint8_t data) { struct scan_field out_fields[2]; uint8_t a[4]; LOG_DEBUG("address: 0x%" PRIx32 ", data: 0x%" PRIx8, address, data); out_fields[0].num_bits = 32; out_fields[0].out_value = a; h_u32_to_be(a, address); out_fields[0].in_value = NULL; out_fields[1].num_bits = 8; out_fields[1].out_value = &data; out_fields[1].in_value = NULL; return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_BYTE, ARRAY_SIZE(out_fields), out_fields, 0, NULL); } int esirisc_jtag_write_hword(struct esirisc_jtag *jtag_info, uint32_t address, uint16_t data) { struct scan_field out_fields[2]; uint8_t a[4], d[2]; LOG_DEBUG("address: 0x%" PRIx32 ", data: 0x%" PRIx16, address, data); out_fields[0].num_bits = 32; out_fields[0].out_value = a; h_u32_to_be(a, address); out_fields[0].in_value = NULL; out_fields[1].num_bits = 16; out_fields[1].out_value = d; h_u16_to_be(d, data); out_fields[1].in_value = NULL; return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_HWORD, ARRAY_SIZE(out_fields), out_fields, 0, NULL); } int esirisc_jtag_write_word(struct esirisc_jtag *jtag_info, uint32_t address, uint32_t data) { struct scan_field out_fields[2]; uint8_t a[4], d[4]; LOG_DEBUG("address: 0x%" PRIx32 ", data: 0x%" PRIx32, address, data); out_fields[0].num_bits = 32; out_fields[0].out_value = a; h_u32_to_be(a, address); out_fields[0].in_value = NULL; out_fields[1].num_bits = 32; out_fields[1].out_value = d; h_u32_to_be(d, data); out_fields[1].in_value = NULL; return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_WORD, ARRAY_SIZE(out_fields), out_fields, 0, NULL); } int esirisc_jtag_read_reg(struct esirisc_jtag *jtag_info, uint8_t reg, uint32_t *data) { struct scan_field out_fields[1]; out_fields[0].num_bits = 8; out_fields[0].out_value = ® out_fields[0].in_value = NULL; struct scan_field in_fields[1]; uint8_t d[4]; in_fields[0].num_bits = 32; in_fields[0].out_value = NULL; in_fields[0].in_value = d; int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_REG, ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields); if (retval != ERROR_OK) return retval; *data = le_to_h_u32(d); LOG_DEBUG("register: 0x%" PRIx8 ", data: 0x%" PRIx32, reg, *data); return ERROR_OK; } int esirisc_jtag_write_reg(struct esirisc_jtag *jtag_info, uint8_t reg, uint32_t data) { struct scan_field out_fields[2]; uint8_t d[4]; LOG_DEBUG("register: 0x%" PRIx8 ", data: 0x%" PRIx32, reg, data); out_fields[0].num_bits = 8; out_fields[0].out_value = ® out_fields[0].in_value = NULL; out_fields[1].num_bits = 32; out_fields[1].out_value = d; h_u32_to_be(d, data); out_fields[1].in_value = NULL; return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_REG, ARRAY_SIZE(out_fields), out_fields, 0, NULL); } int esirisc_jtag_read_csr(struct esirisc_jtag *jtag_info, uint8_t bank, uint8_t csr, uint32_t *data) { struct scan_field out_fields[1]; uint8_t c[2]; out_fields[0].num_bits = 16; out_fields[0].out_value = c; h_u16_to_be(c, (csr << 5) | bank); out_fields[0].in_value = NULL; struct scan_field in_fields[1]; uint8_t d[4]; in_fields[0].num_bits = 32; in_fields[0].out_value = NULL; in_fields[0].in_value = d; int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_CSR, ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields); if (retval != ERROR_OK) return retval; *data = le_to_h_u32(d); LOG_DEBUG("bank: 0x%" PRIx8 ", csr: 0x%" PRIx8 ", data: 0x%" PRIx32, bank, csr, *data); return ERROR_OK; } int esirisc_jtag_write_csr(struct esirisc_jtag *jtag_info, uint8_t bank, uint8_t csr, uint32_t data) { struct scan_field out_fields[2]; uint8_t c[2], d[4]; LOG_DEBUG("bank: 0x%" PRIx8 ", csr: 0x%" PRIx8 ", data: 0x%" PRIx32, bank, csr, data); out_fields[0].num_bits = 16; out_fields[0].out_value = c; h_u16_to_be(c, (csr << 5) | bank); out_fields[0].in_value = NULL; out_fields[1].num_bits = 32; out_fields[1].out_value = d; h_u32_to_be(d, data); out_fields[1].in_value = NULL; return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_CSR, ARRAY_SIZE(out_fields), out_fields, 0, NULL); } /* * Control commands affect CPU operation; these commands send no data * and return a status byte. */ static inline int esirisc_jtag_send_ctrl(struct esirisc_jtag *jtag_info, uint8_t command) { return esirisc_jtag_send_and_recv(jtag_info, command, 0, NULL, 0, NULL); } int esirisc_jtag_enable_debug(struct esirisc_jtag *jtag_info) { return esirisc_jtag_send_ctrl(jtag_info, DEBUG_ENABLE_DEBUG); } int esirisc_jtag_disable_debug(struct esirisc_jtag *jtag_info) { return esirisc_jtag_send_ctrl(jtag_info, DEBUG_DISABLE_DEBUG); } int esirisc_jtag_assert_reset(struct esirisc_jtag *jtag_info) { return esirisc_jtag_send_ctrl(jtag_info, DEBUG_ASSERT_RESET); } int esirisc_jtag_deassert_reset(struct esirisc_jtag *jtag_info) { return esirisc_jtag_send_ctrl(jtag_info, DEBUG_DEASSERT_RESET); } int esirisc_jtag_break(struct esirisc_jtag *jtag_info) { return esirisc_jtag_send_ctrl(jtag_info, DEBUG_BREAK); } int esirisc_jtag_continue(struct esirisc_jtag *jtag_info) { return esirisc_jtag_send_ctrl(jtag_info, DEBUG_CONTINUE); } int esirisc_jtag_flush_caches(struct esirisc_jtag *jtag_info) { return esirisc_jtag_send_ctrl(jtag_info, DEBUG_FLUSH_CACHES); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/esirisc_jtag.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * * James Zhao <hjz@squareup.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESIRISC_JTAG_H #define OPENOCD_TARGET_ESIRISC_JTAG_H #include <helper/types.h> #include <jtag/jtag.h> /* TAP Instructions */ #define INSTR_IDCODE 0x8 #define INSTR_DEBUG 0x9 #define INSTR_BYPASS 0xf #define INSTR_LENGTH 4 /* eSi-Debug Commands */ #define DEBUG_NOP 0x00 #define DEBUG_READ_BYTE 0x10 #define DEBUG_READ_HWORD 0x20 #define DEBUG_READ_WORD 0x30 #define DEBUG_WRITE_BYTE 0x60 #define DEBUG_WRITE_HWORD 0x70 #define DEBUG_WRITE_WORD 0x80 #define DEBUG_READ_REG 0xb0 #define DEBUG_WRITE_REG 0xc0 #define DEBUG_READ_CSR 0xd0 #define DEBUG_WRITE_CSR 0xe0 #define DEBUG_ENABLE_DEBUG 0xf0 #define DEBUG_DISABLE_DEBUG 0xf2 #define DEBUG_ASSERT_RESET 0xf4 #define DEBUG_DEASSERT_RESET 0xf6 #define DEBUG_BREAK 0xf8 #define DEBUG_CONTINUE 0xfa #define DEBUG_FLUSH_CACHES 0xfc /* Exception IDs */ #define EID_OVERFLOW 0x3d #define EID_CANT_DEBUG 0x3e #define EID_NONE 0x3f /* Byte Stuffing */ #define STUFF_MARKER 0x55 #define PAD_BYTE 0xaa struct esirisc_jtag { struct jtag_tap *tap; uint8_t status; }; bool esirisc_jtag_is_debug_active(struct esirisc_jtag *jtag_info); bool esirisc_jtag_is_stopped(struct esirisc_jtag *jtag_info); uint8_t esirisc_jtag_get_eid(struct esirisc_jtag *jtag_info); int esirisc_jtag_read_byte(struct esirisc_jtag *jtag_info, uint32_t address, uint8_t *data); int esirisc_jtag_read_hword(struct esirisc_jtag *jtag_info, uint32_t address, uint16_t *data); int esirisc_jtag_read_word(struct esirisc_jtag *jtag_info, uint32_t address, uint32_t *data); int esirisc_jtag_write_byte(struct esirisc_jtag *jtag_info, uint32_t address, uint8_t data); int esirisc_jtag_write_hword(struct esirisc_jtag *jtag_info, uint32_t address, uint16_t data); int esirisc_jtag_write_word(struct esirisc_jtag *jtag_info, uint32_t address, uint32_t data); int esirisc_jtag_read_reg(struct esirisc_jtag *jtag_info, uint8_t reg, uint32_t *data); int esirisc_jtag_write_reg(struct esirisc_jtag *jtag_info, uint8_t reg, uint32_t data); int esirisc_jtag_read_csr(struct esirisc_jtag *jtag_info, uint8_t bank, uint8_t csr, uint32_t *data); int esirisc_jtag_write_csr(struct esirisc_jtag *jtag_info, uint8_t bank, uint8_t csr, uint32_t data); int esirisc_jtag_enable_debug(struct esirisc_jtag *jtag_info); int esirisc_jtag_disable_debug(struct esirisc_jtag *jtag_info); int esirisc_jtag_assert_reset(struct esirisc_jtag *jtag_info); int esirisc_jtag_deassert_reset(struct esirisc_jtag *jtag_info); int esirisc_jtag_break(struct esirisc_jtag *jtag_info); int esirisc_jtag_continue(struct esirisc_jtag *jtag_info); int esirisc_jtag_flush_caches(struct esirisc_jtag *jtag_info); #endif /* OPENOCD_TARGET_ESIRISC_JTAG_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/esirisc_regs.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * * James Zhao <hjz@squareup.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESIRISC_REGS_H #define OPENOCD_TARGET_ESIRISC_REGS_H enum esirisc_reg_num { ESIRISC_SP, ESIRISC_RA, ESIRISC_R2, ESIRISC_R3, ESIRISC_R4, ESIRISC_R5, ESIRISC_R6, ESIRISC_R7, ESIRISC_R8, ESIRISC_R9, ESIRISC_R10, ESIRISC_R11, ESIRISC_R12, ESIRISC_R13, ESIRISC_R14, ESIRISC_R15, ESIRISC_R16, ESIRISC_R17, ESIRISC_R18, ESIRISC_R19, ESIRISC_R20, ESIRISC_R21, ESIRISC_R22, ESIRISC_R23, ESIRISC_R24, ESIRISC_R25, ESIRISC_R26, ESIRISC_R27, ESIRISC_R28, ESIRISC_R29, ESIRISC_R30, ESIRISC_R31, ESIRISC_V0, ESIRISC_V1, ESIRISC_V2, ESIRISC_V3, ESIRISC_V4, ESIRISC_V5, ESIRISC_V6, ESIRISC_V7, ESIRISC_V8, ESIRISC_V9, ESIRISC_V10, ESIRISC_V11, ESIRISC_V12, ESIRISC_V13, ESIRISC_V14, ESIRISC_V15, ESIRISC_V16, ESIRISC_V17, ESIRISC_V18, ESIRISC_V19, ESIRISC_V20, ESIRISC_V21, ESIRISC_V22, ESIRISC_V23, ESIRISC_V24, ESIRISC_V25, ESIRISC_V26, ESIRISC_V27, ESIRISC_V28, ESIRISC_V29, ESIRISC_V30, ESIRISC_V31, ESIRISC_A0, ESIRISC_A1, ESIRISC_A2, ESIRISC_A3, ESIRISC_A4, ESIRISC_A5, ESIRISC_A6, ESIRISC_A7, ESIRISC_PC, ESIRISC_CAS, ESIRISC_TC, ESIRISC_ETA, ESIRISC_ETC, ESIRISC_EPC, ESIRISC_ECAS, ESIRISC_EID, ESIRISC_ED, ESIRISC_IP, ESIRISC_IM, ESIRISC_IS, ESIRISC_IT, ESIRISC_NUM_REGS, }; /* CSR Banks */ #define CSR_THREAD 0x00 #define CSR_INTERRUPT 0x01 #define CSR_DEBUG 0x04 #define CSR_CONFIG 0x05 #define CSR_TRACE 0x09 /* Thread CSRs */ #define CSR_THREAD_TC 0x00 /* Thread Control */ #define CSR_THREAD_PC 0x01 /* Program Counter */ #define CSR_THREAD_CAS 0x02 /* Comparison & Arithmetic Status */ #define CSR_THREAD_AC 0x03 /* Arithmetic Control */ #define CSR_THREAD_LF 0x04 /* Locked Flag */ #define CSR_THREAD_LA 0x05 /* Locked Address */ #define CSR_THREAD_ETA 0x07 /* Exception Table Address */ #define CSR_THREAD_ETC 0x08 /* Exception TC */ #define CSR_THREAD_EPC 0x09 /* Exception PC */ #define CSR_THREAD_ECAS 0x0a /* Exception CAS */ #define CSR_THREAD_EID 0x0b /* Exception ID */ #define CSR_THREAD_ED 0x0c /* Exception Data */ /* Interrupt CSRs */ #define CSR_INTERRUPT_IP 0x00 /* Interrupt Pending */ #define CSR_INTERRUPT_IA 0x01 /* Interrupt Acknowledge */ #define CSR_INTERRUPT_IM 0x02 /* Interrupt Mask */ #define CSR_INTERRUPT_IS 0x03 /* Interrupt Sense */ #define CSR_INTERRUPT_IT 0x04 /* Interrupt Trigger */ /* Debug CSRs */ #define CSR_DEBUG_DC 0x00 /* Debug Control */ #define CSR_DEBUG_IBC 0x01 /* Instruction Breakpoint Control */ #define CSR_DEBUG_DBC 0x02 /* Data Breakpoint Control */ #define CSR_DEBUG_HWDC 0x03 /* Hardware Debug Control */ #define CSR_DEBUG_DBS 0x04 /* Data Breakpoint Size */ #define CSR_DEBUG_DBR 0x05 /* Data Breakpoint Range */ #define CSR_DEBUG_IBA_N 0x08 /* Instruction Breakpoint Address [0..7] */ #define CSR_DEBUG_DBA_N 0x10 /* Data Breakpoint Address [0..7] */ /* Configuration CSRs */ #define CSR_CONFIG_ARCH0 0x00 /* Architectural Configuration 0 */ #define CSR_CONFIG_ARCH1 0x01 /* Architectural Configuration 1 */ #define CSR_CONFIG_ARCH2 0x02 /* Architectural Configuration 2 */ #define CSR_CONFIG_ARCH3 0x03 /* Architectural Configuration 3 */ #define CSR_CONFIG_MEM 0x04 /* Memory Configuration */ #define CSR_CONFIG_IC 0x05 /* Instruction Cache Configuration */ #define CSR_CONFIG_DC 0x06 /* Data Cache Configuration */ #define CSR_CONFIG_INT 0x07 /* Interrupt Configuration */ #define CSR_CONFIG_ISA_N 0x08 /* Instruction Set Configuration [0..6] */ #define CSR_CONFIG_DBG 0x0f /* Debug Configuration */ #define CSR_CONFIG_MID 0x10 /* Manufacturer ID */ #define CSR_CONFIG_REV 0x11 /* Revision Number */ #define CSR_CONFIG_MPID 0x12 /* Multiprocessor ID */ #define CSR_CONFIG_FREQ_N 0x13 /* Frequency [0..2] */ #define CSR_CONFIG_TRACE 0x16 /* Trace Configuration */ /* Trace CSRs */ #define CSR_TRACE_CONTROL 0x00 #define CSR_TRACE_STATUS 0x01 #define CSR_TRACE_BUFFER_START 0x02 #define CSR_TRACE_BUFFER_END 0x03 #define CSR_TRACE_BUFFER_CUR 0x04 #define CSR_TRACE_TRIGGER 0x05 #define CSR_TRACE_START_DATA 0x06 #define CSR_TRACE_START_MASK 0x07 #define CSR_TRACE_STOP_DATA 0x08 #define CSR_TRACE_STOP_MASK 0x09 #define CSR_TRACE_DELAY 0x0a #endif /* OPENOCD_TARGET_ESIRISC_REGS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/esirisc_trace.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/binarybuffer.h> #include <helper/command.h> #include <helper/fileio.h> #include <helper/log.h> #include <helper/types.h> #include <target/target.h> #include "esirisc.h" #define BIT_MASK(x) ((1 << (x)) - 1) /* Control Fields */ #define CONTROL_ST (1<<0) /* Start */ #define CONTROL_SP (1<<1) /* Stop */ #define CONTROL_W (1<<2) /* Wrap */ #define CONTROL_FC (1<<3) /* Flow Control */ #define CONTROL_FMT(x) (((x) << 4) & 0x30) /* Format */ #define CONTROL_PCB(x) (((x) << 10) & 0x7c00) /* PC Bits */ /* Status Fields */ #define STATUS_T (1<<0) /* Trace Started */ #define STATUS_TD (1<<1) /* Trace Disabled */ #define STATUS_W (1<<2) /* Wrapped */ #define STATUS_O (1<<3) /* Overflow */ /* Trigger Fields */ #define TRIGGER_TST(x) (((x) << 0) & 0xf) /* Trigger Start */ #define TRIGGER_DST (1<<7) /* Delay Start */ #define TRIGGER_TSP(x) (((x) << 8) & 0xf00) /* Trigger Stop */ #define TRIGGER_DSP (1<<15) /* Delay Start */ static const char * const esirisc_trace_delay_strings[] = { "none", "start", "stop", "both", }; static const char * const esirisc_trace_format_strings[] = { "full", "branch", "icache", }; static const char * const esirisc_trace_id_strings[] = { "sequential instruction", "pipeline stall", "direct branch", "extended ID", }; static const char * const esirisc_trace_ext_id_strings[] = { "", /* unused */ "exception", "eret", "stop instruction", "wait instruction", "multicycle instruction", "count", "initial", "indirect branch", "end of trace", "final", }; static const char * const esirisc_trace_trigger_strings[] = { "none", "pc", "load", "store", "exception", "eret", "wait", "stop", "high", "low", /* start only */ }; static int esirisc_trace_clear_status(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_STATUS, ~0); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Trace CSR: Status", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_trace_get_status(struct target *target, uint32_t *status) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; int retval = esirisc_jtag_read_csr(jtag_info, CSR_TRACE, CSR_TRACE_STATUS, status); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Trace CSR: Status", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_trace_start(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; uint32_t control; int retval; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = esirisc_jtag_read_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, &control); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Trace CSR: Control", target_name(target)); return retval; } control |= CONTROL_ST; retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, control); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Trace CSR: Control", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_trace_stop(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; uint32_t control; int retval; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = esirisc_jtag_read_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, &control); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Trace CSR: Control", target_name(target)); return retval; } control |= CONTROL_SP; retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, control); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Trace CSR: Control", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_trace_init(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; struct esirisc_trace *trace_info = &esirisc->trace_info; uint32_t control, trigger; int retval; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; /* stop if running and clear status */ retval = esirisc_trace_stop(target); if (retval != ERROR_OK) return retval; retval = esirisc_trace_clear_status(target); if (retval != ERROR_OK) return retval; /* initialize Control CSR */ control = CONTROL_FMT(trace_info->format) | CONTROL_PCB(trace_info->pc_bits); if (trace_info->buffer_wrap) control |= CONTROL_W; if (trace_info->flow_control) control |= CONTROL_FC; retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, control); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Trace CSR: Control", target_name(target)); return retval; } /* initialize buffer CSRs */ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_BUFFER_START, trace_info->buffer_start); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Trace CSR: BufferStart", target_name(target)); return retval; } retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_BUFFER_END, trace_info->buffer_end); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Trace CSR: BufferEnd", target_name(target)); return retval; } /* * The BufferCurrent CSR must be initialized to the same value as * BufferStart before tracing can be enabled: */ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_BUFFER_CUR, trace_info->buffer_start); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Trace CSR: BufferCurrent", target_name(target)); return retval; } /* initialize Trigger CSR */ trigger = TRIGGER_TST(trace_info->start_trigger) | TRIGGER_TSP(trace_info->stop_trigger); if (trace_info->delay == ESIRISC_TRACE_DELAY_START || trace_info->delay == ESIRISC_TRACE_DELAY_BOTH) { trigger |= TRIGGER_DST; } if (trace_info->delay == ESIRISC_TRACE_DELAY_STOP || trace_info->delay == ESIRISC_TRACE_DELAY_BOTH) { trigger |= TRIGGER_DSP; } retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_TRIGGER, trigger); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Trace CSR: Trigger", target_name(target)); return retval; } /* initialize StartData/StartMask CSRs */ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_START_DATA, trace_info->start_data); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Trace CSR: StartData", target_name(target)); return retval; } retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_START_MASK, trace_info->start_mask); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Trace CSR: StartMask", target_name(target)); return retval; } /* initialize StopData/StopMask CSRs */ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_STOP_DATA, trace_info->stop_data); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Trace CSR: StopData", target_name(target)); return retval; } retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_STOP_MASK, trace_info->stop_mask); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Trace CSR: StopMask", target_name(target)); return retval; } /* initialize Delay CSR */ retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_DELAY, trace_info->delay_cycles); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Trace CSR: Delay", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_trace_buf_get_u32(uint8_t *buffer, uint32_t size, unsigned *pos, unsigned count, uint32_t *value) { const unsigned num_bits = size * 8; if (*pos+count > num_bits) return ERROR_FAIL; *value = buf_get_u32(buffer, *pos, count); *pos += count; return ERROR_OK; } static int esirisc_trace_buf_get_pc(struct target *target, uint8_t *buffer, uint32_t size, unsigned *pos, uint32_t *value) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; int retval; retval = esirisc_trace_buf_get_u32(buffer, size, pos, trace_info->pc_bits, value); if (retval != ERROR_OK) return retval; *value <<= esirisc->num_bits - trace_info->pc_bits; return ERROR_OK; } static int esirisc_trace_read_memory(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { int retval; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = target_read_memory(target, address, 1, size, buffer); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read trace data", target_name(target)); return retval; } return ERROR_OK; } static int esirisc_trace_read_buffer(struct target *target, uint8_t *buffer) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; struct esirisc_trace *trace_info = &esirisc->trace_info; uint32_t buffer_cur, status; int retval; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = esirisc_jtag_read_csr(jtag_info, CSR_TRACE, CSR_TRACE_BUFFER_CUR, &buffer_cur); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to read Trace CSR: BufferCurrent", target_name(target)); return retval; } /* * If the buffer has wrapped, the BufferCurrent CSR indicates the * next address to be written (ie. the start address). These bytes * must be dumped first to maintain coherency when analyzing * captured data. */ retval = esirisc_trace_get_status(target, &status); if (retval != ERROR_OK) return retval; if (status & STATUS_W) { uint32_t size = trace_info->buffer_end - buffer_cur; retval = esirisc_trace_read_memory(target, buffer_cur, size, buffer); if (retval != ERROR_OK) return retval; buffer += size; } return esirisc_trace_read_memory(target, trace_info->buffer_start, buffer_cur - trace_info->buffer_start, buffer); } static int esirisc_trace_analyze_full(struct command_invocation *cmd, uint8_t *buffer, uint32_t size) { struct target *target = get_current_target(cmd->ctx); const uint32_t num_bits = size * 8; int retval; unsigned pos = 0; while (pos < num_bits) { uint32_t id; retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 2, &id); if (retval != ERROR_OK) goto fail; switch (id) { case ESIRISC_TRACE_ID_EXECUTE: case ESIRISC_TRACE_ID_STALL: case ESIRISC_TRACE_ID_BRANCH: command_print(cmd, "%s", esirisc_trace_id_strings[id]); break; case ESIRISC_TRACE_ID_EXTENDED: { uint32_t ext_id; retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 4, &ext_id); if (retval != ERROR_OK) goto fail; switch (ext_id) { case ESIRISC_TRACE_EXT_ID_STOP: case ESIRISC_TRACE_EXT_ID_WAIT: case ESIRISC_TRACE_EXT_ID_MULTICYCLE: command_print(cmd, "%s", esirisc_trace_ext_id_strings[ext_id]); break; case ESIRISC_TRACE_EXT_ID_ERET: case ESIRISC_TRACE_EXT_ID_PC: case ESIRISC_TRACE_EXT_ID_INDIRECT: case ESIRISC_TRACE_EXT_ID_END_PC: { uint32_t pc; retval = esirisc_trace_buf_get_pc(target, buffer, size, &pos, &pc); if (retval != ERROR_OK) goto fail; command_print(cmd, "%s PC: 0x%" PRIx32, esirisc_trace_ext_id_strings[ext_id], pc); if (ext_id == ESIRISC_TRACE_EXT_ID_END_PC) { command_print(cmd, "--- end of trace ---"); return ERROR_OK; } break; } case ESIRISC_TRACE_EXT_ID_EXCEPTION: { uint32_t eid, epc; retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 6, &eid); if (retval != ERROR_OK) goto fail; retval = esirisc_trace_buf_get_pc(target, buffer, size, &pos, &epc); if (retval != ERROR_OK) goto fail; command_print(cmd, "%s EID: 0x%" PRIx32 ", EPC: 0x%" PRIx32, esirisc_trace_ext_id_strings[ext_id], eid, epc); break; } case ESIRISC_TRACE_EXT_ID_COUNT: { uint32_t count; retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 6, &count); if (retval != ERROR_OK) goto fail; command_print(cmd, "repeats %" PRIu32 " %s", count, (count == 1) ? "time" : "times"); break; } case ESIRISC_TRACE_EXT_ID_END: command_print(cmd, "--- end of trace ---"); return ERROR_OK; default: command_print(cmd, "invalid extended trace ID: %" PRIu32, ext_id); return ERROR_FAIL; } break; } default: command_print(cmd, "invalid trace ID: %" PRIu32, id); return ERROR_FAIL; } } fail: command_print(cmd, "trace buffer too small"); return ERROR_BUF_TOO_SMALL; } static int esirisc_trace_analyze_simple(struct command_invocation *cmd, uint8_t *buffer, uint32_t size) { struct target *target = get_current_target(cmd->ctx); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; const uint32_t end_of_trace = BIT_MASK(trace_info->pc_bits) << 1; const uint32_t num_bits = size * 8; int retval; unsigned pos = 0; while (pos < num_bits) { uint32_t pc; retval = esirisc_trace_buf_get_pc(target, buffer, size, &pos, &pc); if (retval != ERROR_OK) break; if (pc == end_of_trace) { command_print(cmd, "--- end of trace ---"); return ERROR_OK; } command_print(cmd, "PC: 0x%" PRIx32, pc); } command_print(cmd, "trace buffer too small"); return ERROR_BUF_TOO_SMALL; } static int esirisc_trace_analyze(struct command_invocation *cmd, uint8_t *buffer, uint32_t size) { struct target *target = get_current_target(cmd->ctx); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; switch (trace_info->format) { case ESIRISC_TRACE_FORMAT_FULL: command_print(cmd, "--- full pipeline ---"); return esirisc_trace_analyze_full(cmd, buffer, size); case ESIRISC_TRACE_FORMAT_BRANCH: command_print(cmd, "--- branches taken ---"); return esirisc_trace_analyze_full(cmd, buffer, size); case ESIRISC_TRACE_FORMAT_ICACHE: command_print(cmd, "--- icache misses ---"); return esirisc_trace_analyze_simple(cmd, buffer, size); default: command_print(cmd, "invalid trace format: %i", trace_info->format); return ERROR_FAIL; } } static int esirisc_trace_analyze_buffer(struct command_invocation *cmd) { struct target *target = get_current_target(cmd->ctx); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; uint8_t *buffer; uint32_t size; int retval; size = esirisc_trace_buffer_size(trace_info); buffer = calloc(1, size); if (!buffer) { command_print(cmd, "out of memory"); return ERROR_FAIL; } retval = esirisc_trace_read_buffer(target, buffer); if (retval != ERROR_OK) goto done; retval = esirisc_trace_analyze(cmd, buffer, size); done: free(buffer); return retval; } static int esirisc_trace_analyze_memory(struct command_invocation *cmd, target_addr_t address, uint32_t size) { struct target *target = get_current_target(cmd->ctx); uint8_t *buffer; int retval; buffer = calloc(1, size); if (!buffer) { command_print(cmd, "out of memory"); return ERROR_FAIL; } retval = esirisc_trace_read_memory(target, address, size, buffer); if (retval != ERROR_OK) goto done; retval = esirisc_trace_analyze(cmd, buffer, size); done: free(buffer); return retval; } static int esirisc_trace_dump(struct command_invocation *cmd, const char *filename, uint8_t *buffer, uint32_t size) { struct fileio *fileio; size_t size_written; int retval; retval = fileio_open(&fileio, filename, FILEIO_WRITE, FILEIO_BINARY); if (retval != ERROR_OK) { command_print(cmd, "could not open dump file: %s", filename); return retval; } retval = fileio_write(fileio, size, buffer, &size_written); if (retval == ERROR_OK) command_print(cmd, "trace data dumped to: %s", filename); else command_print(cmd, "could not write dump file: %s", filename); fileio_close(fileio); return retval; } static int esirisc_trace_dump_buffer(struct command_invocation *cmd, const char *filename) { struct target *target = get_current_target(cmd->ctx); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; uint8_t *buffer; uint32_t size; int retval; size = esirisc_trace_buffer_size(trace_info); buffer = calloc(1, size); if (!buffer) { command_print(cmd, "out of memory"); return ERROR_FAIL; } retval = esirisc_trace_read_buffer(target, buffer); if (retval != ERROR_OK) goto done; retval = esirisc_trace_dump(cmd, filename, buffer, size); done: free(buffer); return retval; } static int esirisc_trace_dump_memory(struct command_invocation *cmd, const char *filename, target_addr_t address, uint32_t size) { struct target *target = get_current_target(cmd->ctx); uint8_t *buffer; int retval; buffer = calloc(1, size); if (!buffer) { command_print(cmd, "out of memory"); return ERROR_FAIL; } retval = esirisc_trace_read_memory(target, address, size, buffer); if (retval != ERROR_OK) goto done; retval = esirisc_trace_dump(cmd, filename, buffer, size); done: free(buffer); return retval; } COMMAND_HANDLER(handle_esirisc_trace_init_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); if (!esirisc->has_trace) { command_print(CMD, "target does not support trace"); return ERROR_FAIL; } int retval = esirisc_trace_init(target); if (retval == ERROR_OK) command_print(CMD, "trace initialized"); return retval; } COMMAND_HANDLER(handle_esirisc_trace_info_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; if (!esirisc->has_trace) { command_print(CMD, "target does not support trace"); return ERROR_FAIL; } if (esirisc_trace_is_fifo(trace_info)) command_print(CMD, "trace FIFO address: 0x%" TARGET_PRIxADDR, trace_info->buffer_start); else { command_print(CMD, "trace buffer start: 0x%" TARGET_PRIxADDR, trace_info->buffer_start); command_print(CMD, "trace buffer end: 0x%" TARGET_PRIxADDR, trace_info->buffer_end); command_print(CMD, "trace buffer will %swrap", trace_info->buffer_wrap ? "" : "not "); } command_print(CMD, "flow control: %s", trace_info->flow_control ? "enabled" : "disabled"); command_print(CMD, "trace format: %s", esirisc_trace_format_strings[trace_info->format]); command_print(CMD, "number of PC bits: %i", trace_info->pc_bits); command_print(CMD, "start trigger: %s", esirisc_trace_trigger_strings[trace_info->start_trigger]); command_print(CMD, "start data: 0x%" PRIx32, trace_info->start_data); command_print(CMD, "start mask: 0x%" PRIx32, trace_info->start_mask); command_print(CMD, "stop trigger: %s", esirisc_trace_trigger_strings[trace_info->stop_trigger]); command_print(CMD, "stop data: 0x%" PRIx32, trace_info->stop_data); command_print(CMD, "stop mask: 0x%" PRIx32, trace_info->stop_mask); command_print(CMD, "trigger delay: %s", esirisc_trace_delay_strings[trace_info->delay]); command_print(CMD, "trigger delay cycles: %" PRIu32, trace_info->delay_cycles); return ERROR_OK; } COMMAND_HANDLER(handle_esirisc_trace_status_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); uint32_t status; if (!esirisc->has_trace) { command_print(CMD, "target does not support trace"); return ERROR_FAIL; } int retval = esirisc_trace_get_status(target, &status); if (retval != ERROR_OK) return retval; command_print(CMD, "trace is %s%s%s%s", (status & STATUS_T) ? "started" : "stopped", (status & STATUS_TD) ? ", disabled" : "", (status & STATUS_W) ? ", wrapped" : "", (status & STATUS_O) ? ", overflowed" : ""); return ERROR_OK; } COMMAND_HANDLER(handle_esirisc_trace_start_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); if (!esirisc->has_trace) { command_print(CMD, "target does not support trace"); return ERROR_FAIL; } int retval = esirisc_trace_start(target); if (retval == ERROR_OK) command_print(CMD, "trace started"); return retval; } COMMAND_HANDLER(handle_esirisc_trace_stop_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); if (!esirisc->has_trace) { command_print(CMD, "target does not support trace"); return ERROR_FAIL; } int retval = esirisc_trace_stop(target); if (retval == ERROR_OK) command_print(CMD, "trace stopped"); return retval; } COMMAND_HANDLER(handle_esirisc_trace_analyze_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; target_addr_t address; uint32_t size; if (!esirisc->has_trace) { command_print(CMD, "target does not support trace"); return ERROR_FAIL; } if (CMD_ARGC != 0 && CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 0) { /* * Use of the Trace FIFO typically involves DMA to a peripheral * (eg. SPI) or a separately managed buffer in memory, neither * of which may be under our control. If the destination address * and size are known in the latter case, they may be specified * as arguments as a workaround. */ if (esirisc_trace_is_fifo(trace_info)) { command_print(CMD, "analyze from FIFO not supported"); return ERROR_FAIL; } return esirisc_trace_analyze_buffer(CMD); } else { COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size); return esirisc_trace_analyze_memory(CMD, address, size); } } COMMAND_HANDLER(handle_esirisc_trace_dump_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; target_addr_t address; uint32_t size; if (!esirisc->has_trace) { command_print(CMD, "target does not support trace"); return ERROR_FAIL; } if (CMD_ARGC != 1 && CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { /* also see: handle_esirisc_trace_analyze_command() */ if (esirisc_trace_is_fifo(trace_info)) { command_print(CMD, "dump from FIFO not supported"); return ERROR_FAIL; } return esirisc_trace_dump_buffer(CMD, CMD_ARGV[0]); } else { COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size); return esirisc_trace_dump_memory(CMD, CMD_ARGV[2], address, size); } } COMMAND_HANDLER(handle_esirisc_trace_buffer_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; uint32_t size; if (CMD_ARGC < 2 || CMD_ARGC > 3) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], trace_info->buffer_start); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size); trace_info->buffer_end = trace_info->buffer_start + size; if (CMD_ARGC == 3) { if (strcmp("wrap", CMD_ARGV[2]) == 0) trace_info->buffer_wrap = true; else return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } COMMAND_HANDLER(handle_esirisc_trace_fifo_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], trace_info->buffer_start); /* FIFOs have the same start and end address */ trace_info->buffer_end = trace_info->buffer_start; trace_info->buffer_wrap = true; return ERROR_OK; } COMMAND_HANDLER(handle_esirisc_trace_flow_control_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[0], "enable") == 0) trace_info->flow_control = true; else if (strcmp(CMD_ARGV[0], "disable") == 0) trace_info->flow_control = false; else return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } COMMAND_HANDLER(handle_esirisc_trace_format_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; int pc_bits; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[0], "full") == 0) trace_info->format = ESIRISC_TRACE_FORMAT_FULL; else if (strcmp(CMD_ARGV[0], "branch") == 0) trace_info->format = ESIRISC_TRACE_FORMAT_BRANCH; else if (strcmp(CMD_ARGV[0], "icache") == 0) trace_info->format = ESIRISC_TRACE_FORMAT_ICACHE; else return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], pc_bits); if (pc_bits < 1 || pc_bits > 31) { command_print(CMD, "invalid pc_bits: %i; must be 1..31", pc_bits); return ERROR_COMMAND_SYNTAX_ERROR; } trace_info->pc_bits = pc_bits; return ERROR_OK; } COMMAND_HANDLER(handle_esirisc_trace_trigger_start_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; if (CMD_ARGC != 1 && CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[0], "none") == 0) trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_NONE; else if (strcmp(CMD_ARGV[0], "pc") == 0) trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_PC; else if (strcmp(CMD_ARGV[0], "load") == 0) trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_LOAD; else if (strcmp(CMD_ARGV[0], "store") == 0) trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_STORE; else if (strcmp(CMD_ARGV[0], "exception") == 0) trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_EXCEPTION; else if (strcmp(CMD_ARGV[0], "eret") == 0) trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_ERET; else if (strcmp(CMD_ARGV[0], "wait") == 0) trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_WAIT; else if (strcmp(CMD_ARGV[0], "stop") == 0) trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_STOP; else if (strcmp(CMD_ARGV[0], "high") == 0) trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_HIGH; else if (strcmp(CMD_ARGV[0], "low") == 0) trace_info->start_trigger = ESIRISC_TRACE_TRIGGER_LOW; else return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 3) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], trace_info->start_data); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], trace_info->start_mask); } else { trace_info->start_data = 0; trace_info->start_mask = 0; } return ERROR_OK; } COMMAND_HANDLER(handle_esirisc_trace_trigger_stop_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; if (CMD_ARGC != 1 && CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[0], "none") == 0) trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_NONE; else if (strcmp(CMD_ARGV[0], "pc") == 0) trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_PC; else if (strcmp(CMD_ARGV[0], "load") == 0) trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_LOAD; else if (strcmp(CMD_ARGV[0], "store") == 0) trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_STORE; else if (strcmp(CMD_ARGV[0], "exception") == 0) trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_EXCEPTION; else if (strcmp(CMD_ARGV[0], "eret") == 0) trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_ERET; else if (strcmp(CMD_ARGV[0], "wait") == 0) trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_WAIT; else if (strcmp(CMD_ARGV[0], "stop") == 0) trace_info->stop_trigger = ESIRISC_TRACE_TRIGGER_STOP; else return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 3) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], trace_info->stop_data); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], trace_info->stop_mask); } else { trace_info->stop_data = 0; trace_info->stop_mask = 0; } return ERROR_OK; } COMMAND_HANDLER(handle_esirisc_trace_trigger_delay_command) { struct target *target = get_current_target(CMD_CTX); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[0], "none") == 0) trace_info->delay = ESIRISC_TRACE_DELAY_NONE; else if (strcmp(CMD_ARGV[0], "start") == 0) trace_info->delay = ESIRISC_TRACE_DELAY_START; else if (strcmp(CMD_ARGV[0], "stop") == 0) trace_info->delay = ESIRISC_TRACE_DELAY_STOP; else if (strcmp(CMD_ARGV[0], "both") == 0) trace_info->delay = ESIRISC_TRACE_DELAY_BOTH; else return ERROR_COMMAND_SYNTAX_ERROR; if (trace_info->delay == ESIRISC_TRACE_DELAY_NONE) trace_info->delay_cycles = 0; else { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], trace_info->delay_cycles); } return ERROR_OK; } static const struct command_registration esirisc_trace_exec_command_handlers[] = { { .name = "init", .handler = handle_esirisc_trace_init_command, .mode = COMMAND_EXEC, .help = "initialize trace collection", .usage = "", }, { .name = "info", .handler = handle_esirisc_trace_info_command, .mode = COMMAND_EXEC, .help = "display trace configuration", .usage = "", }, { .name = "status", .handler = handle_esirisc_trace_status_command, .mode = COMMAND_EXEC, .help = "display trace collection status", .usage = "", }, { .name = "start", .handler = handle_esirisc_trace_start_command, .mode = COMMAND_EXEC, .help = "start trace collection", .usage = "", }, { .name = "stop", .handler = handle_esirisc_trace_stop_command, .mode = COMMAND_EXEC, .help = "stop trace collection", .usage = "", }, { .name = "analyze", .handler = handle_esirisc_trace_analyze_command, .mode = COMMAND_EXEC, .usage = "[address size]", .help = "analyze collected trace data", }, { .name = "dump", .handler = handle_esirisc_trace_dump_command, .mode = COMMAND_EXEC, .help = "dump collected trace data to file", .usage = "[address size] filename", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration esirisc_trace_trigger_any_command_handlers[] = { { .name = "start", .handler = handle_esirisc_trace_trigger_start_command, .mode = COMMAND_ANY, .help = "configure trigger start condition", .usage = "('none'|'pc'|'load'|'store'|'exception'|'eret'|'wait'|'stop'|'high'|'low')" " [start_data start_mask]", }, { .name = "stop", .handler = handle_esirisc_trace_trigger_stop_command, .mode = COMMAND_ANY, .help = "configure trigger stop condition", .usage = "('none'|'pc'|'load'|'store'|'exception'|'eret'|'wait'|'stop')" " [stop_data stop_mask]", }, { .name = "delay", .handler = handle_esirisc_trace_trigger_delay_command, .mode = COMMAND_ANY, .help = "configure trigger start/stop delay in clock cycles", .usage = "('none'|'start'|'stop'|'both') [cycles]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration esirisc_trace_any_command_handlers[] = { { .name = "buffer", .handler = handle_esirisc_trace_buffer_command, .mode = COMMAND_ANY, .help = "configure trace buffer", .usage = "address size ['wrap']", }, { .name = "fifo", .handler = handle_esirisc_trace_fifo_command, .mode = COMMAND_ANY, .help = "configure trace FIFO", .usage = "address", }, { .name = "flow_control", .handler = handle_esirisc_trace_flow_control_command, .mode = COMMAND_ANY, .help = "enable or disable stalling CPU to collect trace data", .usage = "('enable'|'disable')", }, { .name = "format", .handler = handle_esirisc_trace_format_command, .mode = COMMAND_ANY, .help = "configure trace format", .usage = "('full'|'branch'|'icache') pc_bits", }, { .name = "trigger", .mode = COMMAND_ANY, .help = "eSi-Trace trigger command group", .usage = "", .chain = esirisc_trace_trigger_any_command_handlers, }, { .chain = esirisc_trace_exec_command_handlers }, COMMAND_REGISTRATION_DONE }; const struct command_registration esirisc_trace_command_handlers[] = { { .name = "trace", .mode = COMMAND_ANY, .help = "eSi-Trace command group", .usage = "", .chain = esirisc_trace_any_command_handlers, }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/esirisc_trace.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESIRISC_TRACE_H #define OPENOCD_TARGET_ESIRISC_TRACE_H #include <helper/command.h> #include <helper/types.h> #include <target/target.h> enum esirisc_trace_delay { ESIRISC_TRACE_DELAY_NONE, ESIRISC_TRACE_DELAY_START, ESIRISC_TRACE_DELAY_STOP, ESIRISC_TRACE_DELAY_BOTH, }; enum esirisc_trace_format { ESIRISC_TRACE_FORMAT_FULL, ESIRISC_TRACE_FORMAT_BRANCH, ESIRISC_TRACE_FORMAT_ICACHE, }; enum esirisc_trace_id { ESIRISC_TRACE_ID_EXECUTE, ESIRISC_TRACE_ID_STALL, ESIRISC_TRACE_ID_BRANCH, ESIRISC_TRACE_ID_EXTENDED, }; enum esirisc_trace_ext_id { ESIRISC_TRACE_EXT_ID_EXCEPTION = 1, ESIRISC_TRACE_EXT_ID_ERET, ESIRISC_TRACE_EXT_ID_STOP, ESIRISC_TRACE_EXT_ID_WAIT, ESIRISC_TRACE_EXT_ID_MULTICYCLE, ESIRISC_TRACE_EXT_ID_COUNT, ESIRISC_TRACE_EXT_ID_PC, ESIRISC_TRACE_EXT_ID_INDIRECT, ESIRISC_TRACE_EXT_ID_END, ESIRISC_TRACE_EXT_ID_END_PC, }; enum esirisc_trace_trigger { ESIRISC_TRACE_TRIGGER_NONE, ESIRISC_TRACE_TRIGGER_PC, ESIRISC_TRACE_TRIGGER_LOAD, ESIRISC_TRACE_TRIGGER_STORE, ESIRISC_TRACE_TRIGGER_EXCEPTION, ESIRISC_TRACE_TRIGGER_ERET, ESIRISC_TRACE_TRIGGER_WAIT, ESIRISC_TRACE_TRIGGER_STOP, ESIRISC_TRACE_TRIGGER_HIGH, ESIRISC_TRACE_TRIGGER_LOW, }; struct esirisc_trace { target_addr_t buffer_start; target_addr_t buffer_end; bool buffer_wrap; bool flow_control; enum esirisc_trace_format format; int pc_bits; enum esirisc_trace_trigger start_trigger; uint32_t start_data; uint32_t start_mask; enum esirisc_trace_trigger stop_trigger; uint32_t stop_data; uint32_t stop_mask; enum esirisc_trace_delay delay; uint32_t delay_cycles; }; extern const struct command_registration esirisc_trace_command_handlers[]; static inline uint32_t esirisc_trace_buffer_size(struct esirisc_trace *trace_info) { return trace_info->buffer_end - trace_info->buffer_start; } static inline bool esirisc_trace_is_fifo(struct esirisc_trace *trace_info) { return trace_info->buffer_start == trace_info->buffer_end; } #endif /* OPENOCD_TARGET_ESIRISC_TRACE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libespressif.la %C%_libespressif_la_SOURCES = \ %D%/esp_xtensa.c \ %D%/esp_xtensa.h \ %D%/esp_xtensa_smp.c \ %D%/esp_xtensa_smp.h \ %D%/esp_xtensa_semihosting.c \ %D%/esp_xtensa_semihosting.h \ %D%/esp_xtensa_apptrace.c \ %D%/esp_xtensa_apptrace.h \ %D%/esp32_apptrace.c \ %D%/esp32_apptrace.h \ %D%/esp32.c \ %D%/esp32s2.c \ %D%/esp32s3.c \ %D%/esp.c \ %D%/esp.h \ %D%/esp32_sysview.c \ %D%/esp32_sysview.h \ %D%/segger_sysview.h \ %D%/esp_semihosting.c \ %D%/esp_semihosting.h ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Espressif chips common target API for OpenOCD * * Copyright (C) 2021 Espressif Systems Ltd. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include <helper/binarybuffer.h> #include "target/target.h" #include "esp.h" int esp_dbgstubs_table_read(struct target *target, struct esp_dbg_stubs *dbg_stubs) { uint32_t table_size, table_start_id, desc_entry_id, gcov_entry_id; uint32_t entries[ESP_DBG_STUB_ENTRY_MAX] = {0}; uint8_t entry_buff[sizeof(entries)] = {0}; /* to avoid endiannes issues */ LOG_TARGET_DEBUG(target, "Read debug stubs info %" PRIx32 " / %d", dbg_stubs->base, dbg_stubs->entries_count); /* First of, read 2 entries to get magic num and table size */ int res = target_read_buffer(target, dbg_stubs->base, sizeof(uint32_t) * 2, entry_buff); if (res != ERROR_OK) { LOG_ERROR("%s: Failed to read first debug stub entry!", target_name(target)); return res; } entries[0] = target_buffer_get_u32(target, entry_buff); entries[1] = target_buffer_get_u32(target, entry_buff + sizeof(uint32_t)); if (entries[0] != ESP_DBG_STUB_MAGIC_NUM_VAL) { /* idf with the old table entry structure */ table_size = 2; table_start_id = 0; desc_entry_id = 0; gcov_entry_id = 1; } else { table_size = entries[1]; table_start_id = ESP_DBG_STUB_TABLE_START; desc_entry_id = ESP_DBG_STUB_TABLE_START; gcov_entry_id = ESP_DBG_STUB_ENTRY_FIRST; /* discard unsupported entries */ if (table_size > ESP_DBG_STUB_ENTRY_MAX) table_size = ESP_DBG_STUB_ENTRY_MAX; /* now read the remaining entries */ res = target_read_buffer(target, dbg_stubs->base + 2 * sizeof(uint32_t), sizeof(uint32_t) * table_size - 2, entry_buff + sizeof(uint32_t) * 2); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read debug stubs info!"); return res; } for (unsigned int i = 2; i < table_size; ++i) entries[i] = target_buffer_get_u32(target, entry_buff + sizeof(uint32_t) * i); dbg_stubs->entries[ESP_DBG_STUB_CAPABILITIES] = entries[ESP_DBG_STUB_CAPABILITIES]; } dbg_stubs->entries[ESP_DBG_STUB_DESC] = entries[desc_entry_id]; dbg_stubs->entries[ESP_DBG_STUB_ENTRY_GCOV] = entries[gcov_entry_id]; for (enum esp_dbg_stub_id i = ESP_DBG_STUB_DESC; i < ESP_DBG_STUB_ENTRY_MAX; i++) { LOG_DEBUG("Check dbg stub %d - %x", i, dbg_stubs->entries[i]); if (dbg_stubs->entries[i]) { LOG_DEBUG("New dbg stub %d at %x", dbg_stubs->entries_count, dbg_stubs->entries[i]); dbg_stubs->entries_count++; } } if (dbg_stubs->entries_count < table_size - table_start_id) LOG_WARNING("Not full dbg stub table %d of %d", dbg_stubs->entries_count, table_size - table_start_id); return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Espressif chips common target API for OpenOCD * * Copyright (C) 2021 Espressif Systems Ltd. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESP_H #define OPENOCD_TARGET_ESP_H #include <stdint.h> #include <helper/bits.h> /* must be in sync with ESP-IDF version */ /** Size of the pre-compiled target buffer for stub trampoline. * @note Must be in sync with ESP-IDF version */ #define ESP_DBG_STUBS_CODE_BUF_SIZE 32 /* TODO: move this info to esp_dbg_stubs_desc */ /** Size of the pre-compiled target buffer for stack. * @note Must be in sync with ESP-IDF version */ #define ESP_DBG_STUBS_STACK_MIN_SIZE 2048/* TODO: move this info to esp_dbg_stubs_desc */ /** * Debug stubs table entries IDs * * @note Must be in sync with ESP-IDF version */ enum esp_dbg_stub_id { ESP_DBG_STUB_ENTRY_MAGIC_NUM, ESP_DBG_STUB_TABLE_SIZE, ESP_DBG_STUB_TABLE_START, ESP_DBG_STUB_DESC = ESP_DBG_STUB_TABLE_START, /*< Stubs descriptor ID */ ESP_DBG_STUB_ENTRY_FIRST, ESP_DBG_STUB_ENTRY_GCOV = ESP_DBG_STUB_ENTRY_FIRST, /*< GCOV stub ID */ ESP_DBG_STUB_CAPABILITIES, /* add new stub entries here */ ESP_DBG_STUB_ENTRY_MAX, }; #define ESP_DBG_STUB_MAGIC_NUM_VAL 0xFEEDBEEF #define ESP_DBG_STUB_CAP_GCOV_THREAD BIT(0) /** * Debug stubs descriptor. ID: ESP_DBG_STUB_DESC * * @note Must be in sync with ESP-IDF version */ struct esp_dbg_stubs_desc { /** Address of pre-compiled target buffer for stub trampoline. * Size of the buffer is ESP_DBG_STUBS_CODE_BUF_SIZE */ uint32_t tramp_addr; /** Pre-compiled target buffer's addr for stack. The size of the buffer is ESP_DBG_STUBS_STACK_MIN_SIZE. * Target has the buffer which is used for the stack of onboard algorithms. * If stack size required by algorithm exceeds ESP_DBG_STUBS_STACK_MIN_SIZE, * it should be allocated using onboard function pointed by 'data_alloc' and * freed by 'data_free'. They fit to the minimal stack. See below. */ uint32_t min_stack_addr; /** Address of malloc-like function to allocate buffer on target. */ uint32_t data_alloc; /** Address of free-like function to free buffer allocated with data_alloc. */ uint32_t data_free; }; /** * Debug stubs info. */ struct esp_dbg_stubs { /** Address. */ uint32_t base; /** Table contents. */ uint32_t entries[ESP_DBG_STUB_ENTRY_MAX]; /** Number of table entries. */ uint32_t entries_count; /** Debug stubs decsriptor. */ struct esp_dbg_stubs_desc desc; }; struct esp_common { struct esp_dbg_stubs dbg_stubs; }; int esp_dbgstubs_table_read(struct target *target, struct esp_dbg_stubs *dbg_stubs); #endif /* OPENOCD_TARGET_ESP_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp32.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * ESP32 target API for OpenOCD * * Copyright (C) 2016-2019 Espressif Systems Ltd. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/time_support.h> #include <target/target.h> #include <target/target_type.h> #include <target/smp.h> #include <target/semihosting_common.h> #include "assert.h" #include "esp_xtensa_smp.h" /* This is a JTAG driver for the ESP32, the are two Tensilica cores inside the ESP32 chip. For more information please have a look into ESP32 target implementation. */ /* ESP32 memory map */ #define ESP32_RTC_DATA_LOW 0x50000000 #define ESP32_RTC_DATA_HIGH 0x50002000 #define ESP32_DR_REG_LOW 0x3ff00000 #define ESP32_DR_REG_HIGH 0x3ff71000 #define ESP32_SYS_RAM_LOW 0x60000000UL #define ESP32_SYS_RAM_HIGH (ESP32_SYS_RAM_LOW + 0x20000000UL) #define ESP32_RTC_SLOW_MEM_BASE ESP32_RTC_DATA_LOW /* ESP32 WDT */ #define ESP32_WDT_WKEY_VALUE 0x50d83aa1 #define ESP32_TIMG0_BASE 0x3ff5f000 #define ESP32_TIMG1_BASE 0x3ff60000 #define ESP32_TIMGWDT_CFG0_OFF 0x48 #define ESP32_TIMGWDT_PROTECT_OFF 0x64 #define ESP32_TIMG0WDT_CFG0 (ESP32_TIMG0_BASE + ESP32_TIMGWDT_CFG0_OFF) #define ESP32_TIMG1WDT_CFG0 (ESP32_TIMG1_BASE + ESP32_TIMGWDT_CFG0_OFF) #define ESP32_TIMG0WDT_PROTECT (ESP32_TIMG0_BASE + ESP32_TIMGWDT_PROTECT_OFF) #define ESP32_TIMG1WDT_PROTECT (ESP32_TIMG1_BASE + ESP32_TIMGWDT_PROTECT_OFF) #define ESP32_RTCCNTL_BASE 0x3ff48000 #define ESP32_RTCWDT_CFG_OFF 0x8C #define ESP32_RTCWDT_PROTECT_OFF 0xA4 #define ESP32_RTCWDT_CFG (ESP32_RTCCNTL_BASE + ESP32_RTCWDT_CFG_OFF) #define ESP32_RTCWDT_PROTECT (ESP32_RTCCNTL_BASE + ESP32_RTCWDT_PROTECT_OFF) #define ESP32_TRACEMEM_BLOCK_SZ 0x4000 /* ESP32 dport regs */ #define ESP32_DR_REG_DPORT_BASE ESP32_DR_REG_LOW #define ESP32_DPORT_APPCPU_CTRL_B_REG (ESP32_DR_REG_DPORT_BASE + 0x030) #define ESP32_DPORT_APPCPU_CLKGATE_EN BIT(0) /* ESP32 RTC regs */ #define ESP32_RTC_CNTL_SW_CPU_STALL_REG (ESP32_RTCCNTL_BASE + 0xac) #define ESP32_RTC_CNTL_SW_CPU_STALL_DEF 0x0 /* 0 - don't care, 1 - TMS low, 2 - TMS high */ enum esp32_flash_bootstrap { FBS_DONTCARE = 0, FBS_TMSLOW, FBS_TMSHIGH, }; struct esp32_common { struct esp_xtensa_smp_common esp_xtensa_smp; enum esp32_flash_bootstrap flash_bootstrap; }; static inline struct esp32_common *target_to_esp32(struct target *target) { return container_of(target->arch_info, struct esp32_common, esp_xtensa_smp); } /* Reset ESP32 peripherals. * Postconditions: all peripherals except RTC_CNTL are reset, CPU's PC is undefined, PRO CPU is halted, * APP CPU is in reset * How this works: * 0. make sure target is halted; if not, try to halt it; if that fails, try to reset it (via OCD) and then halt * 1. set CPU initial PC to 0x50000000 (ESP32_SMP_RTC_DATA_LOW) by clearing RTC_CNTL_{PRO,APP}CPU_STAT_VECTOR_SEL * 2. load stub code into ESP32_SMP_RTC_DATA_LOW; once executed, stub code will disable watchdogs and * make CPU spin in an idle loop. * 3. trigger SoC reset using RTC_CNTL_SW_SYS_RST bit * 4. wait for the OCD to be reset * 5. halt the target and wait for it to be halted (at this point CPU is in the idle loop) * 6. restore initial PC and the contents of ESP32_SMP_RTC_DATA_LOW * TODO: some state of RTC_CNTL is not reset during SW_SYS_RST. Need to reset that manually. */ static const uint8_t esp32_reset_stub_code[] = { #include "../../../contrib/loaders/reset/espressif/esp32/cpu_reset_handler_code.inc" }; static int esp32_soc_reset(struct target *target) { int res; struct target_list *head; struct xtensa *xtensa; LOG_DEBUG("start"); /* In order to write to peripheral registers, target must be halted first */ if (target->state != TARGET_HALTED) { LOG_DEBUG("Target not halted before SoC reset, trying to halt it first"); xtensa_halt(target); res = target_wait_state(target, TARGET_HALTED, 1000); if (res != ERROR_OK) { LOG_DEBUG("Couldn't halt target before SoC reset, trying to do reset-halt"); res = xtensa_assert_reset(target); if (res != ERROR_OK) { LOG_ERROR( "Couldn't halt target before SoC reset! (xtensa_assert_reset returned %d)", res); return res; } alive_sleep(10); xtensa_poll(target); bool reset_halt_save = target->reset_halt; target->reset_halt = true; res = xtensa_deassert_reset(target); target->reset_halt = reset_halt_save; if (res != ERROR_OK) { LOG_ERROR( "Couldn't halt target before SoC reset! (xtensa_deassert_reset returned %d)", res); return res; } alive_sleep(10); xtensa_poll(target); xtensa_halt(target); res = target_wait_state(target, TARGET_HALTED, 1000); if (res != ERROR_OK) { LOG_ERROR("Couldn't halt target before SoC reset"); return res; } } } if (target->smp) { foreach_smp_target(head, target->smp_targets) { xtensa = target_to_xtensa(head->target); /* if any of the cores is stalled unstall them */ if (xtensa_dm_core_is_stalled(&xtensa->dbg_mod)) { LOG_TARGET_DEBUG(head->target, "Unstall CPUs before SW reset!"); res = target_write_u32(target, ESP32_RTC_CNTL_SW_CPU_STALL_REG, ESP32_RTC_CNTL_SW_CPU_STALL_DEF); if (res != ERROR_OK) { LOG_TARGET_ERROR(head->target, "Failed to unstall CPUs before SW reset!"); return res; } break; /* both cores are unstalled now, so exit the loop */ } } } LOG_DEBUG("Loading stub code into RTC RAM"); uint8_t slow_mem_save[sizeof(esp32_reset_stub_code)]; /* Save contents of RTC_SLOW_MEM which we are about to overwrite */ res = target_read_buffer(target, ESP32_RTC_SLOW_MEM_BASE, sizeof(slow_mem_save), slow_mem_save); if (res != ERROR_OK) { LOG_ERROR("Failed to save contents of RTC_SLOW_MEM (%d)!", res); return res; } /* Write stub code into RTC_SLOW_MEM */ res = target_write_buffer(target, ESP32_RTC_SLOW_MEM_BASE, sizeof(esp32_reset_stub_code), esp32_reset_stub_code); if (res != ERROR_OK) { LOG_ERROR("Failed to write stub (%d)!", res); return res; } LOG_DEBUG("Resuming the target"); xtensa = target_to_xtensa(target); xtensa->suppress_dsr_errors = true; res = xtensa_resume(target, 0, ESP32_RTC_SLOW_MEM_BASE + 4, 0, 0); xtensa->suppress_dsr_errors = false; if (res != ERROR_OK) { LOG_ERROR("Failed to run stub (%d)!", res); return res; } LOG_DEBUG("resume done, waiting for the target to come alive"); /* Wait for SoC to reset */ alive_sleep(100); int64_t timeout = timeval_ms() + 100; bool get_timeout = false; while (target->state != TARGET_RESET && target->state != TARGET_RUNNING) { alive_sleep(10); xtensa_poll(target); if (timeval_ms() >= timeout) { LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state=%d", target->state); get_timeout = true; break; } } /* Halt the CPU again */ LOG_DEBUG("halting the target"); xtensa_halt(target); res = target_wait_state(target, TARGET_HALTED, 1000); if (res == ERROR_OK) { LOG_DEBUG("restoring RTC_SLOW_MEM"); res = target_write_buffer(target, ESP32_RTC_SLOW_MEM_BASE, sizeof(slow_mem_save), slow_mem_save); if (res != ERROR_OK) LOG_TARGET_ERROR(target, "Failed to restore contents of RTC_SLOW_MEM (%d)!", res); } else { LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be halted after SoC reset"); } return get_timeout ? ERROR_TARGET_TIMEOUT : res; } static int esp32_disable_wdts(struct target *target) { /* TIMG1 WDT */ int res = target_write_u32(target, ESP32_TIMG0WDT_PROTECT, ESP32_WDT_WKEY_VALUE); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_TIMG0WDT_PROTECT (%d)!", res); return res; } res = target_write_u32(target, ESP32_TIMG0WDT_CFG0, 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_TIMG0WDT_CFG0 (%d)!", res); return res; } /* TIMG2 WDT */ res = target_write_u32(target, ESP32_TIMG1WDT_PROTECT, ESP32_WDT_WKEY_VALUE); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_TIMG1WDT_PROTECT (%d)!", res); return res; } res = target_write_u32(target, ESP32_TIMG1WDT_CFG0, 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_TIMG1WDT_CFG0 (%d)!", res); return res; } /* RTC WDT */ res = target_write_u32(target, ESP32_RTCWDT_PROTECT, ESP32_WDT_WKEY_VALUE); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_RTCWDT_PROTECT (%d)!", res); return res; } res = target_write_u32(target, ESP32_RTCWDT_CFG, 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_RTCWDT_CFG (%d)!", res); return res; } return ERROR_OK; } static int esp32_on_halt(struct target *target) { int ret = esp32_disable_wdts(target); if (ret == ERROR_OK) ret = esp_xtensa_smp_on_halt(target); return ret; } static int esp32_arch_state(struct target *target) { return ERROR_OK; } static int esp32_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical) { if (physical) { *physical = virtual; return ERROR_OK; } return ERROR_FAIL; } /* The TDI pin is also used as a flash Vcc bootstrap pin. If we reset the CPU externally, the last state of the TDI pin * can allow the power to an 1.8V flash chip to be raised to 3.3V, or the other way around. Users can use the * esp32 flashbootstrap command to set a level, and this routine will make sure the tdi line will return to * that when the jtag port is idle. */ static void esp32_queue_tdi_idle(struct target *target) { struct esp32_common *esp32 = target_to_esp32(target); static uint32_t value; uint8_t t[4] = { 0, 0, 0, 0 }; if (esp32->flash_bootstrap == FBS_TMSLOW) /* Make sure tdi is 0 at the exit of queue execution */ value = 0; else if (esp32->flash_bootstrap == FBS_TMSHIGH) /* Make sure tdi is 1 at the exit of queue execution */ value = 1; else return; /* Scan out 1 bit, do not move from IRPAUSE after we're done. */ buf_set_u32(t, 0, 1, value); jtag_add_plain_ir_scan(1, t, NULL, TAP_IRPAUSE); } static int esp32_target_init(struct command_context *cmd_ctx, struct target *target) { return esp_xtensa_smp_target_init(cmd_ctx, target); } static const struct xtensa_debug_ops esp32_dbg_ops = { .queue_enable = xtensa_dm_queue_enable, .queue_reg_read = xtensa_dm_queue_reg_read, .queue_reg_write = xtensa_dm_queue_reg_write }; static const struct xtensa_power_ops esp32_pwr_ops = { .queue_reg_read = xtensa_dm_queue_pwr_reg_read, .queue_reg_write = xtensa_dm_queue_pwr_reg_write }; static const struct esp_xtensa_smp_chip_ops esp32_chip_ops = { .reset = esp32_soc_reset, .on_halt = esp32_on_halt }; static const struct esp_semihost_ops esp32_semihost_ops = { .prepare = esp32_disable_wdts }; static int esp32_target_create(struct target *target, Jim_Interp *interp) { struct xtensa_debug_module_config esp32_dm_cfg = { .dbg_ops = &esp32_dbg_ops, .pwr_ops = &esp32_pwr_ops, .tap = target->tap, .queue_tdi_idle = esp32_queue_tdi_idle, .queue_tdi_idle_arg = target }; struct esp32_common *esp32 = calloc(1, sizeof(struct esp32_common)); if (!esp32) { LOG_ERROR("Failed to alloc memory for arch info!"); return ERROR_FAIL; } int ret = esp_xtensa_smp_init_arch_info(target, &esp32->esp_xtensa_smp, &esp32_dm_cfg, &esp32_chip_ops, &esp32_semihost_ops); if (ret != ERROR_OK) { LOG_ERROR("Failed to init arch info!"); free(esp32); return ret; } esp32->flash_bootstrap = FBS_DONTCARE; /* Assume running target. If different, the first poll will fix this. */ target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; return ERROR_OK; } static COMMAND_HELPER(esp32_cmd_flashbootstrap_do, struct esp32_common *esp32) { int state = -1; if (CMD_ARGC < 1) { const char *st; state = esp32->flash_bootstrap; if (state == FBS_DONTCARE) st = "Don't care"; else if (state == FBS_TMSLOW) st = "Low (3.3V)"; else if (state == FBS_TMSHIGH) st = "High (1.8V)"; else st = "None"; command_print(CMD, "Current idle tms state: %s", st); return ERROR_OK; } if (!strcasecmp(CMD_ARGV[0], "none")) state = FBS_DONTCARE; else if (!strcasecmp(CMD_ARGV[0], "1.8")) state = FBS_TMSHIGH; else if (!strcasecmp(CMD_ARGV[0], "3.3")) state = FBS_TMSLOW; else if (!strcasecmp(CMD_ARGV[0], "high")) state = FBS_TMSHIGH; else if (!strcasecmp(CMD_ARGV[0], "low")) state = FBS_TMSLOW; if (state == -1) { command_print(CMD, "Argument unknown. Please pick one of none, high, low, 1.8 or 3.3"); return ERROR_FAIL; } esp32->flash_bootstrap = state; return ERROR_OK; } COMMAND_HANDLER(esp32_cmd_flashbootstrap) { struct target *target = get_current_target(CMD_CTX); if (target->smp) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(esp32_cmd_flashbootstrap_do, target_to_esp32(curr)); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(esp32_cmd_flashbootstrap_do, target_to_esp32(target)); } static const struct command_registration esp32_any_command_handlers[] = { { .name = "flashbootstrap", .handler = esp32_cmd_flashbootstrap, .mode = COMMAND_ANY, .help = "Set the idle state of the TMS pin, which at reset also is the voltage selector for the flash chip.", .usage = "none|1.8|3.3|high|low", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration esp32_command_handlers[] = { { .chain = esp_xtensa_smp_command_handlers, }, { .name = "esp", .usage = "", .chain = esp32_apptrace_command_handlers, }, { .name = "esp32", .usage = "", .chain = smp_command_handlers, }, { .name = "esp32", .usage = "", .chain = esp32_any_command_handlers, }, { .name = "arm", .mode = COMMAND_ANY, .help = "ARM Command Group", .usage = "", .chain = semihosting_common_handlers }, COMMAND_REGISTRATION_DONE }; /** Holds methods for Xtensa targets. */ struct target_type esp32_target = { .name = "esp32", .poll = esp_xtensa_smp_poll, .arch_state = esp32_arch_state, .halt = xtensa_halt, .resume = esp_xtensa_smp_resume, .step = esp_xtensa_smp_step, .assert_reset = esp_xtensa_smp_assert_reset, .deassert_reset = esp_xtensa_smp_deassert_reset, .soft_reset_halt = esp_xtensa_smp_soft_reset_halt, .virt2phys = esp32_virt2phys, .mmu = xtensa_mmu_is_enabled, .read_memory = xtensa_read_memory, .write_memory = xtensa_write_memory, .read_buffer = xtensa_read_buffer, .write_buffer = xtensa_write_buffer, .checksum_memory = xtensa_checksum_memory, .get_gdb_arch = xtensa_get_gdb_arch, .get_gdb_reg_list = xtensa_get_gdb_reg_list, .add_breakpoint = esp_xtensa_breakpoint_add, .remove_breakpoint = esp_xtensa_breakpoint_remove, .add_watchpoint = esp_xtensa_smp_watchpoint_add, .remove_watchpoint = esp_xtensa_smp_watchpoint_remove, .target_create = esp32_target_create, .init_target = esp32_target_init, .examine = xtensa_examine, .deinit_target = esp_xtensa_target_deinit, .commands = esp32_command_handlers, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp32_apptrace.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * ESP32xx application tracing module for OpenOCD * * Copyright (C) 2017 Espressif Systems Ltd. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif #ifdef HAVE_NETDB_H #include <netdb.h> #endif #ifndef _WIN32 #include <netinet/tcp.h> #include <sys/ioctl.h> #endif #include <helper/list.h> #include <helper/time_support.h> #include <target/target.h> #include <target/target_type.h> #include <target/smp.h> #include <server/server.h> #include "esp_xtensa.h" #include "esp_xtensa_smp.h" #include "esp_xtensa_apptrace.h" #include "esp32_apptrace.h" #include "esp32_sysview.h" #include "segger_sysview.h" #define ESP32_APPTRACE_USER_BLOCK_CORE(_v_) ((_v_) >> 15) #define ESP32_APPTRACE_USER_BLOCK_LEN(_v_) ((_v_) & ~BIT(15)) #define ESP32_APPTRACE_USER_BLOCK_HDR_SZ 4 #define ESP_APPTRACE_CMD_MODE_GEN 0 #define ESP_APPTRACE_CMD_MODE_SYSVIEW 1 #define ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE 2 #define ESP_APPTRACE_CMD_MODE_SYNC 3 #define ESP32_APPTRACE_TGT_STATE_TMO 5000 #define ESP_APPTRACE_BLOCKS_POOL_SZ 10 struct esp32_apptrace_dest_file_data { int fout; }; struct esp32_apptrace_dest_tcp_data { int sockfd; }; struct esp32_apptrace_target_state { int running; uint32_t block_id; uint32_t data_len; }; struct esp_apptrace_target2host_hdr { uint16_t block_sz; uint16_t wr_sz; }; #define APPTRACE_BLOCK_SIZE_OFFSET 0 #define APPTRACE_WR_SIZE_OFFSET 2 struct esp32_apptrace_block { struct list_head node; uint8_t *data; uint32_t data_len; }; static int esp32_apptrace_data_processor(void *priv); static int esp32_apptrace_get_data_info(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_target_state *target_state, uint32_t *fired_target_num); static int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_target_state *targets); static struct esp32_apptrace_block *esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx *ctx); static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_block *block); static int esp32_sysview_start(struct esp32_apptrace_cmd_ctx *ctx); static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx); static const bool s_time_stats_enable = true; /********************************************************************* * Trace destination API **********************************************************************/ static int esp32_apptrace_file_dest_write(void *priv, uint8_t *data, int size) { struct esp32_apptrace_dest_file_data *dest_data = (struct esp32_apptrace_dest_file_data *)priv; int wr_sz = write(dest_data->fout, data, size); if (wr_sz != size) { LOG_ERROR("Failed to write %d bytes to out file (%d)! Written %d.", size, errno, wr_sz); return ERROR_FAIL; } return ERROR_OK; } static int esp32_apptrace_file_dest_cleanup(void *priv) { struct esp32_apptrace_dest_file_data *dest_data = (struct esp32_apptrace_dest_file_data *)priv; if (dest_data->fout > 0) close(dest_data->fout); free(dest_data); return ERROR_OK; } static int esp32_apptrace_file_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name) { struct esp32_apptrace_dest_file_data *dest_data = calloc(1, sizeof(*dest_data)); if (!dest_data) { LOG_ERROR("Failed to alloc mem for file dest!"); return ERROR_FAIL; } LOG_INFO("Open file %s", dest_name); dest_data->fout = open(dest_name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); if (dest_data->fout <= 0) { LOG_ERROR("Failed to open file %s", dest_name); free(dest_data); return ERROR_FAIL; } dest->priv = dest_data; dest->write = esp32_apptrace_file_dest_write; dest->clean = esp32_apptrace_file_dest_cleanup; dest->log_progress = true; return ERROR_OK; } static int esp32_apptrace_console_dest_write(void *priv, uint8_t *data, int size) { LOG_USER_N("%.*s", size, data); return ERROR_OK; } static int esp32_apptrace_console_dest_cleanup(void *priv) { return ERROR_OK; } static int esp32_apptrace_console_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name) { dest->priv = NULL; dest->write = esp32_apptrace_console_dest_write; dest->clean = esp32_apptrace_console_dest_cleanup; dest->log_progress = false; return ERROR_OK; } static int esp32_apptrace_tcp_dest_write(void *priv, uint8_t *data, int size) { struct esp32_apptrace_dest_tcp_data *dest_data = (struct esp32_apptrace_dest_tcp_data *)priv; int wr_sz = write_socket(dest_data->sockfd, data, size); if (wr_sz != size) { LOG_ERROR("Failed to write %u bytes to out socket (%d)! Written %d.", size, errno, wr_sz); return ERROR_FAIL; } return ERROR_OK; } static int esp32_apptrace_tcp_dest_cleanup(void *priv) { struct esp32_apptrace_dest_tcp_data *dest_data = (struct esp32_apptrace_dest_tcp_data *)priv; if (dest_data->sockfd > 0) close_socket(dest_data->sockfd); free(dest_data); return ERROR_OK; } static int esp32_apptrace_tcp_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name) { const char *port_sep = strchr(dest_name, ':'); /* separator not found, or was the first or the last character */ if (!port_sep || port_sep == dest_name || port_sep == dest_name + strlen(dest_name) - 1) { LOG_ERROR("apptrace: Invalid connection URI, format should be tcp://host:port"); return ERROR_COMMAND_ARGUMENT_INVALID; } size_t hostname_len = port_sep - dest_name; char hostname[64] = { 0 }; if (hostname_len >= sizeof(hostname)) { LOG_ERROR("apptrace: Hostname too long"); return ERROR_COMMAND_ARGUMENT_INVALID; } memcpy(hostname, dest_name, hostname_len); const char *port_str = port_sep + 1; struct addrinfo *ai; int flags = 0; #ifdef AI_NUMERICSERV flags |= AI_NUMERICSERV; #endif /* AI_NUMERICSERV */ struct addrinfo hint = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_protocol = 0, .ai_flags = flags }; int res = getaddrinfo(hostname, port_str, &hint, &ai); if (res != 0) { LOG_ERROR("apptrace: Failed to resolve host name: %s", hostname); return ERROR_FAIL; } int sockfd = -1; for (struct addrinfo *ai_it = ai; ai_it; ai_it = ai_it->ai_next) { sockfd = socket(ai_it->ai_family, ai_it->ai_socktype, ai_it->ai_protocol); if (sockfd < 0) { LOG_DEBUG("apptrace: Failed to create socket (%d, %d, %d) (%s)", ai_it->ai_family, ai_it->ai_socktype, ai_it->ai_protocol, strerror(errno)); continue; } char cur_hostname[NI_MAXHOST]; char cur_portname[NI_MAXSERV]; res = getnameinfo(ai_it->ai_addr, ai_it->ai_addrlen, cur_hostname, sizeof(cur_hostname), cur_portname, sizeof(cur_portname), NI_NUMERICHOST | NI_NUMERICSERV); if (res != 0) continue; LOG_INFO("apptrace: Trying to connect to %s:%s", cur_hostname, cur_portname); if (connect(sockfd, ai_it->ai_addr, ai_it->ai_addrlen) < 0) { close_socket(sockfd); sockfd = -1; LOG_WARNING("apptrace: Connection failed (%s)", strerror(errno)); continue; } break; } freeaddrinfo(ai); if (sockfd < 0) { LOG_ERROR("apptrace: Could not connect to %s:%s", hostname, port_str); return ERROR_FAIL; } LOG_INFO("apptrace: Connected!"); struct esp32_apptrace_dest_tcp_data *dest_data = calloc(1, sizeof(struct esp32_apptrace_dest_tcp_data)); if (!dest_data) { LOG_ERROR("apptrace: Failed to alloc mem for tcp dest!"); close_socket(sockfd); return ERROR_FAIL; } dest_data->sockfd = sockfd; dest->priv = dest_data; dest->write = esp32_apptrace_tcp_dest_write; dest->clean = esp32_apptrace_tcp_dest_cleanup; dest->log_progress = true; return ERROR_OK; } int esp32_apptrace_dest_init(struct esp32_apptrace_dest dest[], const char *dest_paths[], unsigned int max_dests) { int res; unsigned int i; for (i = 0; i < max_dests; i++) { if (strncmp(dest_paths[i], "file://", 7) == 0) res = esp32_apptrace_file_dest_init(&dest[i], &dest_paths[i][7]); else if (strncmp(dest_paths[i], "con:", 4) == 0) res = esp32_apptrace_console_dest_init(&dest[i], NULL); else if (strncmp(dest_paths[i], "tcp://", 6) == 0) res = esp32_apptrace_tcp_dest_init(&dest[i], &dest_paths[i][6]); else break; if (res != ERROR_OK) { LOG_ERROR("apptrace: Failed to init trace data destination '%s'!", dest_paths[i]); return 0; } } return i; } int esp32_apptrace_dest_cleanup(struct esp32_apptrace_dest dest[], unsigned int max_dests) { for (unsigned int i = 0; i < max_dests; i++) { if (dest[i].clean && dest[i].priv) { int res = dest[i].clean(dest[i].priv); dest[i].priv = NULL; return res; } } return ERROR_OK; } /********************************************************************* * Trace data blocks management API **********************************************************************/ static void esp32_apptrace_blocks_pool_cleanup(struct esp32_apptrace_cmd_ctx *ctx) { struct esp32_apptrace_block *cur; struct list_head *head = &ctx->free_trace_blocks; struct list_head *tmp, *pos; list_for_each_safe(pos, tmp, head) { cur = list_entry(pos, struct esp32_apptrace_block, node); if (cur) { list_del(&cur->node); free(cur->data); free(cur); } } head = &ctx->ready_trace_blocks; list_for_each_safe(pos, tmp, head) { cur = list_entry(pos, struct esp32_apptrace_block, node); if (cur) { list_del(&cur->node); free(cur->data); free(cur); } } } struct esp32_apptrace_block *esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx *ctx) { struct esp32_apptrace_block *block = NULL; if (!list_empty(&ctx->free_trace_blocks)) { /*get first */ block = list_first_entry(&ctx->free_trace_blocks, struct esp32_apptrace_block, node); list_del(&block->node); } return block; } static int esp32_apptrace_ready_block_put(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_block *block) { LOG_DEBUG("esp32_apptrace_ready_block_put"); /* add to ready blocks list */ INIT_LIST_HEAD(&block->node); list_add(&block->node, &ctx->ready_trace_blocks); return ERROR_OK; } static struct esp32_apptrace_block *esp32_apptrace_ready_block_get(struct esp32_apptrace_cmd_ctx *ctx) { if (list_empty(&ctx->ready_trace_blocks)) return NULL; struct esp32_apptrace_block *block = list_last_entry(&ctx->ready_trace_blocks, struct esp32_apptrace_block, node); /* remove it from ready list */ list_del(&block->node); return block; } static int esp32_apptrace_block_free(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_block *block) { /* add to free blocks list */ INIT_LIST_HEAD(&block->node); list_add(&block->node, &ctx->free_trace_blocks); return ERROR_OK; } static int esp32_apptrace_wait_tracing_finished(struct esp32_apptrace_cmd_ctx *ctx) { int64_t timeout = timeval_ms() + (LOG_LEVEL_IS(LOG_LVL_DEBUG) ? 70000 : 5000); while (!list_empty(&ctx->ready_trace_blocks)) { alive_sleep(100); if (timeval_ms() >= timeout) { LOG_ERROR("Failed to wait for pended trace blocks!"); return ERROR_FAIL; } } /* signal timer callback to stop */ ctx->running = 0; target_unregister_timer_callback(esp32_apptrace_data_processor, ctx); return ERROR_OK; } /********************************************************************* * Trace commands **********************************************************************/ int esp32_apptrace_cmd_ctx_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct command_invocation *cmd, int mode) { struct target *target = get_current_target(CMD_CTX); memset(cmd_ctx, 0, sizeof(struct esp32_apptrace_cmd_ctx)); cmd_ctx->target = target; cmd_ctx->mode = mode; cmd_ctx->target_state = target->state; cmd_ctx->cmd = cmd; if (target->smp) { struct target_list *head; struct target *curr; unsigned int i = 0; cmd_ctx->cores_num = 0; foreach_smp_target(head, target->smp_targets) { curr = head->target; if (i == ESP32_APPTRACE_MAX_CORES_NUM) { command_print(cmd, "Too many cores configured! Max %d cores are supported.", ESP32_APPTRACE_MAX_CORES_NUM); return ERROR_FAIL; } if (!target_was_examined(curr)) continue; cmd_ctx->cores_num++; cmd_ctx->cpus[i++] = curr; } } else { cmd_ctx->cores_num = 1; cmd_ctx->cpus[0] = target; } /* some relies on ESP32_APPTRACE_MAX_CORES_NUM * TODO: remove that dependency */ assert(cmd_ctx->cores_num <= ESP32_APPTRACE_MAX_CORES_NUM && "Too many cores number!"); struct xtensa *xtensa = target->arch_info; if (xtensa->common_magic == XTENSA_COMMON_MAGIC) { cmd_ctx->hw = target_to_esp_xtensa(target)->apptrace.hw; } else { /* TODO: riscv is not supported yet */ command_print(cmd, "Unsupported target arch 0x%X", xtensa->common_magic); return ERROR_FAIL; } cmd_ctx->max_trace_block_sz = cmd_ctx->hw->max_block_size_get(cmd_ctx->cpus[0]); if (cmd_ctx->max_trace_block_sz == 0) { command_print(cmd, "Failed to get max trace block size!"); return ERROR_FAIL; } LOG_INFO("Total trace memory: %" PRIu32 " bytes", cmd_ctx->max_trace_block_sz); INIT_LIST_HEAD(&cmd_ctx->ready_trace_blocks); INIT_LIST_HEAD(&cmd_ctx->free_trace_blocks); for (unsigned int i = 0; i < ESP_APPTRACE_BLOCKS_POOL_SZ; i++) { struct esp32_apptrace_block *block = calloc(1, sizeof(struct esp32_apptrace_block)); if (!block) { command_print(cmd, "Failed to alloc trace buffer entry!"); esp32_apptrace_blocks_pool_cleanup(cmd_ctx); return ERROR_FAIL; } block->data = malloc(cmd_ctx->max_trace_block_sz); if (!block->data) { free(block); command_print(cmd, "Failed to alloc trace buffer %" PRIu32 " bytes!", cmd_ctx->max_trace_block_sz); esp32_apptrace_blocks_pool_cleanup(cmd_ctx); return ERROR_FAIL; } INIT_LIST_HEAD(&block->node); list_add(&block->node, &cmd_ctx->free_trace_blocks); } cmd_ctx->running = 1; if (cmd_ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC) { int res = target_register_timer_callback(esp32_apptrace_data_processor, 0, TARGET_TIMER_TYPE_PERIODIC, cmd_ctx); if (res != ERROR_OK) { command_print(cmd, "Failed to start trace data timer callback (%d)!", res); esp32_apptrace_blocks_pool_cleanup(cmd_ctx); return ERROR_FAIL; } } if (s_time_stats_enable) { cmd_ctx->stats.min_blk_read_time = 1000000.0; cmd_ctx->stats.min_blk_proc_time = 1000000.0; } if (duration_start(&cmd_ctx->idle_time) != 0) { command_print(cmd, "Failed to start idle time measurement!"); esp32_apptrace_cmd_ctx_cleanup(cmd_ctx); return ERROR_FAIL; } return ERROR_OK; } int esp32_apptrace_cmd_ctx_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx) { esp32_apptrace_blocks_pool_cleanup(cmd_ctx); return ERROR_OK; } #define ESP32_APPTRACE_CMD_NUM_ARG_CHECK(_cmd_, _arg_, _start_, _end_) \ do { \ if ((_arg_) == 0 && (_start_) == (_end_)) { \ command_print(_cmd_, "Invalid '" # _arg_ "' arg!"); \ return; \ } \ } while (0) void esp32_apptrace_cmd_args_parse(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct esp32_apptrace_cmd_data *cmd_data, const char **argv, int argc) { char *end; cmd_data->poll_period = strtoul(argv[0], &end, 10); ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->poll_period, argv[0], end); if (argc > 1) { cmd_data->max_len = strtoul(argv[1], &end, 10); ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->max_len, argv[1], end); if (argc > 2) { int32_t tmo = strtol(argv[2], &end, 10); ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, tmo, argv[2], end); cmd_ctx->stop_tmo = 1.0 * tmo; if (argc > 3) { cmd_data->wait4halt = strtoul(argv[3], &end, 10); ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->wait4halt, argv[3], end); if (argc > 4) { cmd_data->skip_len = strtoul(argv[4], &end, 10); ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->skip_len, argv[4], end); } } } } } static int esp32_apptrace_core_id_get(struct target *target, uint8_t *hdr_buf) { return ESP32_APPTRACE_USER_BLOCK_CORE(target_buffer_get_u16(target, hdr_buf + APPTRACE_BLOCK_SIZE_OFFSET)); } static uint32_t esp32_apptrace_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len) { *wr_len = ESP32_APPTRACE_USER_BLOCK_LEN(target_buffer_get_u16(target, hdr_buf + APPTRACE_WR_SIZE_OFFSET)); return ESP32_APPTRACE_USER_BLOCK_LEN(target_buffer_get_u16(target, hdr_buf + APPTRACE_BLOCK_SIZE_OFFSET)); } static int esp32_apptrace_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct command_invocation *cmd, int mode, const char **argv, int argc) { struct esp32_apptrace_cmd_data *cmd_data; if (argc < 1) { command_print(cmd, "Not enough args! Need trace data destination!"); return ERROR_FAIL; } int res = esp32_apptrace_cmd_ctx_init(cmd_ctx, cmd, mode); if (res != ERROR_OK) return res; cmd_data = calloc(1, sizeof(*cmd_data)); assert(cmd_data && "No memory for command data!"); cmd_ctx->cmd_priv = cmd_data; /*outfile1 [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] */ res = esp32_apptrace_dest_init(&cmd_data->data_dest, argv, 1); if (res != 1) { /* only one destination needs to be initialized */ command_print(cmd, "Wrong args! Needs a trace data destination!"); free(cmd_data); goto on_error; } cmd_ctx->stop_tmo = -1.0; /* infinite */ cmd_data->max_len = UINT32_MAX; cmd_data->poll_period = 0 /*ms*/; if (argc > 1) /* parse remaining args */ esp32_apptrace_cmd_args_parse(cmd_ctx, cmd_data, &argv[1], argc - 1); LOG_USER("App trace params: from %d cores, size %" PRId32 " bytes, stop_tmo %g s, poll period %" PRId32 " ms, wait_rst %d, skip %" PRId32 " bytes", cmd_ctx->cores_num, cmd_data->max_len, cmd_ctx->stop_tmo, cmd_data->poll_period, cmd_data->wait4halt, cmd_data->skip_len); cmd_ctx->trace_format.hdr_sz = ESP32_APPTRACE_USER_BLOCK_HDR_SZ; cmd_ctx->trace_format.core_id_get = esp32_apptrace_core_id_get; cmd_ctx->trace_format.usr_block_len_get = esp32_apptrace_usr_block_len_get; return ERROR_OK; on_error: command_print(cmd, "Not enough args! Need %d trace data destinations!", cmd_ctx->cores_num); cmd_ctx->running = 0; esp32_apptrace_cmd_ctx_cleanup(cmd_ctx); return res; } static int esp32_apptrace_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx) { struct esp32_apptrace_cmd_data *cmd_data = cmd_ctx->cmd_priv; esp32_apptrace_dest_cleanup(&cmd_data->data_dest, 1); free(cmd_data); cmd_ctx->cmd_priv = NULL; esp32_apptrace_cmd_ctx_cleanup(cmd_ctx); return ERROR_OK; } static void esp32_apptrace_print_stats(struct esp32_apptrace_cmd_ctx *ctx) { struct esp32_apptrace_cmd_data *cmd_data = ctx->cmd_priv; uint32_t trace_sz = 0; if (cmd_data) trace_sz = ctx->tot_len > cmd_data->skip_len ? ctx->tot_len - cmd_data->skip_len : 0; LOG_USER("Tracing is %s. Size is %" PRId32 " of %" PRId32 " @ %f (%f) KiB/s", !ctx->running ? "STOPPED" : "RUNNING", trace_sz, cmd_data ? cmd_data->max_len : 0, duration_kbps(&ctx->read_time, ctx->tot_len), duration_kbps(&ctx->read_time, ctx->raw_tot_len)); LOG_USER("Data: blocks incomplete %" PRId32 ", lost bytes: %" PRId32, ctx->stats.incompl_blocks, ctx->stats.lost_bytes); if (s_time_stats_enable) { LOG_USER("Block read time [%f..%f] ms", 1000 * ctx->stats.min_blk_read_time, 1000 * ctx->stats.max_blk_read_time); LOG_USER("Block proc time [%f..%f] ms", 1000 * ctx->stats.min_blk_proc_time, 1000 * ctx->stats.max_blk_proc_time); } } static int esp32_apptrace_wait4halt(struct esp32_apptrace_cmd_ctx *ctx, struct target *target) { LOG_USER("Wait for halt..."); while (!openocd_is_shutdown_pending()) { int res = target_poll(target); if (res != ERROR_OK) return res; if (target->state == TARGET_HALTED) { LOG_USER("%s: HALTED", target->cmd_name); break; } alive_sleep(500); } return ERROR_OK; } int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_target_state *targets) { int res = ERROR_OK; memset(targets, 0, ctx->cores_num * sizeof(struct esp32_apptrace_target_state)); /* halt all CPUs */ LOG_DEBUG("Halt all targets!"); for (unsigned int k = 0; k < ctx->cores_num; k++) { if (!target_was_examined(ctx->cpus[k])) continue; if (ctx->cpus[k]->state == TARGET_HALTED) continue; res = target_halt(ctx->cpus[k]); if (res != ERROR_OK) { LOG_ERROR("Failed to halt target (%d)!", res); return res; } res = target_wait_state(ctx->cpus[k], TARGET_HALTED, ESP32_APPTRACE_TGT_STATE_TMO); if (res != ERROR_OK) { LOG_ERROR("Failed to wait halt target %s / %d (%d)!", target_name(ctx->cpus[k]), ctx->cpus[k]->state, res); return res; } } /* read current block statuses from CPUs */ LOG_DEBUG("Read current block statuses"); for (unsigned int k = 0; k < ctx->cores_num; k++) { uint32_t stat; res = ctx->hw->status_reg_read(ctx->cpus[k], &stat); if (res != ERROR_OK) { LOG_ERROR("Failed to read trace status (%d)!", res); return res; } /* check if some CPU stopped inside tracing regs update critical section */ if (stat) { if (ctx->hw->leave_trace_crit_section_start) { res = ctx->hw->leave_trace_crit_section_start(ctx->cpus[k]); if (res != ERROR_OK) return res; } uint32_t bp_addr = stat; res = breakpoint_add(ctx->cpus[k], bp_addr, 1, BKPT_HARD); if (res != ERROR_OK) { LOG_ERROR("Failed to set breakpoint (%d)!", res); return res; } while (stat) { /* allow this CPU to leave ERI write critical section */ res = target_resume(ctx->cpus[k], 1, 0, 1, 0); if (res != ERROR_OK) { LOG_ERROR("Failed to resume target (%d)!", res); breakpoint_remove(ctx->cpus[k], bp_addr); return res; } /* wait for CPU to be halted on BP */ enum target_debug_reason debug_reason = DBG_REASON_UNDEFINED; while (debug_reason != DBG_REASON_BREAKPOINT) { res = target_wait_state(ctx->cpus[k], TARGET_HALTED, ESP32_APPTRACE_TGT_STATE_TMO); if (res != ERROR_OK) { LOG_ERROR("Failed to wait halt on bp (%d)!", res); breakpoint_remove(ctx->cpus[k], bp_addr); return res; } debug_reason = ctx->cpus[k]->debug_reason; } res = ctx->hw->status_reg_read(ctx->cpus[k], &stat); if (res != ERROR_OK) { LOG_ERROR("Failed to read trace status (%d)!", res); breakpoint_remove(ctx->cpus[k], bp_addr); return res; } } breakpoint_remove(ctx->cpus[k], bp_addr); if (ctx->hw->leave_trace_crit_section_stop) { res = ctx->hw->leave_trace_crit_section_stop(ctx->cpus[k]); if (res != ERROR_OK) return res; } } res = ctx->hw->data_len_read(ctx->cpus[k], &targets[k].block_id, &targets[k].data_len); if (res != ERROR_OK) { LOG_ERROR("Failed to read trace status (%d)!", res); return res; } } return ERROR_OK; } static int esp32_apptrace_connect_targets(struct esp32_apptrace_cmd_ctx *ctx, bool conn, bool resume_target) { struct esp32_apptrace_target_state target_to_connect[ESP32_APPTRACE_MAX_CORES_NUM]; if (conn) LOG_USER("Connect targets..."); else LOG_USER("Disconnect targets..."); int res = esp32_apptrace_safe_halt_targets(ctx, target_to_connect); if (res != ERROR_OK) { command_print(ctx->cmd, "Failed to halt targets (%d)!", res); return res; } if (ctx->cores_num > 1) { /* set block ids to the highest value */ uint32_t max_id = 0; for (unsigned int k = 0; k < ctx->cores_num; k++) { if (target_to_connect[k].block_id > max_id) max_id = target_to_connect[k].block_id; } for (unsigned int k = 0; k < ctx->cores_num; k++) target_to_connect[k].block_id = max_id; } for (unsigned int k = 0; k < ctx->cores_num; k++) { /* update host connected status */ res = ctx->hw->ctrl_reg_write(ctx->cpus[k], target_to_connect[k].block_id, 0 /*ack target data*/, conn, false /*no host data*/); if (res != ERROR_OK) { command_print(ctx->cmd, "Failed to read trace status (%d)!", res); return res; } } if (resume_target) { LOG_DEBUG("Resume targets"); bool smp_resumed = false; for (unsigned int k = 0; k < ctx->cores_num; k++) { if (smp_resumed && ctx->cpus[k]->smp) { /* in SMP mode we need to call target_resume for one core only */ continue; } res = target_resume(ctx->cpus[k], 1, 0, 1, 0); if (res != ERROR_OK) { command_print(ctx->cmd, "Failed to resume target (%d)!", res); return res; } if (ctx->cpus[k]->smp) smp_resumed = true; } } if (conn) LOG_INFO("Targets connected."); else LOG_INFO("Targets disconnected."); return ERROR_OK; } int esp_apptrace_usr_block_write(const struct esp32_apptrace_hw *hw, struct target *target, uint32_t block_id, const uint8_t *data, uint32_t size) { struct esp_apptrace_host2target_hdr hdr = { .block_sz = size }; uint32_t buf_sz[2] = { sizeof(hdr), size }; const uint8_t *bufs[2] = { (const uint8_t *)&hdr, data }; if (size > hw->usr_block_max_size_get(target)) { LOG_ERROR("Too large user block %" PRId32, size); return ERROR_FAIL; } return hw->buffs_write(target, ARRAY_SIZE(buf_sz), buf_sz, bufs, block_id, true /*ack target data*/, true /*host data*/); } static uint32_t esp32_apptrace_usr_block_check(struct esp32_apptrace_cmd_ctx *ctx, uint8_t *hdr_buf) { uint32_t wr_len = 0; uint32_t usr_len = ctx->trace_format.usr_block_len_get(ctx->target, hdr_buf, &wr_len); if (usr_len != wr_len) { LOG_ERROR("Incomplete block sz %" PRId32 ", wr %" PRId32, usr_len, wr_len); ctx->stats.incompl_blocks++; ctx->stats.lost_bytes += usr_len - wr_len; } return usr_len; } int esp32_apptrace_get_data_info(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_target_state *target_state, uint32_t *fired_target_num) { if (fired_target_num) *fired_target_num = UINT32_MAX; for (unsigned int i = 0; i < ctx->cores_num; i++) { int res = ctx->hw->data_len_read(ctx->cpus[i], &target_state[i].block_id, &target_state[i].data_len); if (res != ERROR_OK) { LOG_ERROR("Failed to read data len on (%s)!", target_name(ctx->cpus[i])); return res; } if (target_state[i].data_len) { LOG_TARGET_DEBUG(ctx->cpus[i], "Block %" PRId32 ", len %" PRId32 " bytes on fired", target_state[i].block_id, target_state[i].data_len); if (fired_target_num) *fired_target_num = i; break; } } return ERROR_OK; } static int esp32_apptrace_process_data(struct esp32_apptrace_cmd_ctx *ctx, unsigned int core_id, uint8_t *data, uint32_t data_len) { struct esp32_apptrace_cmd_data *cmd_data = ctx->cmd_priv; LOG_DEBUG("Got block %" PRId32 " bytes [%x %x...%x %x]", data_len, data[12], data[13], data[data_len - 2], data[data_len - 1]); if (ctx->tot_len + data_len > cmd_data->skip_len) { uint32_t wr_idx = 0, wr_chunk_len = data_len; if (ctx->tot_len < cmd_data->skip_len) { wr_chunk_len = (ctx->tot_len + wr_chunk_len) - cmd_data->skip_len; wr_idx = cmd_data->skip_len - ctx->tot_len; } if (ctx->tot_len + wr_chunk_len > cmd_data->max_len) wr_chunk_len -= (ctx->tot_len + wr_chunk_len - cmd_data->skip_len) - cmd_data->max_len; if (wr_chunk_len > 0) { int res = cmd_data->data_dest.write(cmd_data->data_dest.priv, data + wr_idx, wr_chunk_len); if (res != ERROR_OK) { LOG_ERROR("Failed to write %" PRId32 " bytes to dest 0!", data_len); return res; } } ctx->tot_len += wr_chunk_len; } else { ctx->tot_len += data_len; } if (cmd_data->data_dest.log_progress) LOG_USER("%" PRId32 " ", ctx->tot_len); /* check for stop condition */ if (ctx->tot_len > cmd_data->skip_len && (ctx->tot_len - cmd_data->skip_len >= cmd_data->max_len)) { ctx->running = 0; if (duration_measure(&ctx->read_time) != 0) { LOG_ERROR("Failed to stop trace read time measure!"); return ERROR_FAIL; } } return ERROR_OK; } static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_block *block) { uint32_t processed = 0; uint32_t hdr_sz = ctx->trace_format.hdr_sz; LOG_DEBUG("Got block %" PRId32 " bytes", block->data_len); /* process user blocks one by one */ while (processed < block->data_len) { LOG_DEBUG("Process usr block %" PRId32 "/%" PRId32, processed, block->data_len); /* process user block */ uint32_t usr_len = esp32_apptrace_usr_block_check(ctx, block->data + processed); int core_id = ctx->trace_format.core_id_get(ctx->target, block->data + processed); /* process user data */ int res = ctx->process_data(ctx, core_id, block->data + processed + hdr_sz, usr_len); if (res != ERROR_OK) { LOG_ERROR("Failed to process %" PRId32 " bytes!", usr_len); return res; } processed += usr_len + hdr_sz; } return ERROR_OK; } static int esp32_apptrace_data_processor(void *priv) { struct esp32_apptrace_cmd_ctx *ctx = (struct esp32_apptrace_cmd_ctx *)priv; if (!ctx->running) return ERROR_OK; struct esp32_apptrace_block *block = esp32_apptrace_ready_block_get(ctx); if (!block) return ERROR_OK; int res = esp32_apptrace_handle_trace_block(ctx, block); if (res != ERROR_OK) { ctx->running = 0; LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len); return res; } res = esp32_apptrace_block_free(ctx, block); if (res != ERROR_OK) { ctx->running = 0; LOG_ERROR("Failed to free ready block!"); return res; } return ERROR_OK; } static int esp32_apptrace_check_connection(struct esp32_apptrace_cmd_ctx *ctx) { if (!ctx) return ERROR_FAIL; unsigned int busy_target_num = 0; for (unsigned int i = 0; i < ctx->cores_num; i++) { bool conn = true; int res = ctx->hw->ctrl_reg_read(ctx->cpus[i], NULL, NULL, &conn); if (res != ERROR_OK) { LOG_ERROR("Failed to read apptrace control reg for cpu(%d) res(%d)!", i, res); return res; } if (!conn) { uint32_t stat = 0; LOG_TARGET_WARNING(ctx->cpus[i], "apptrace connection is lost. Re-connect."); res = ctx->hw->status_reg_read(ctx->cpus[i], &stat); if (res != ERROR_OK) { LOG_ERROR("Failed to read trace status (%d)!", res); return res; } if (stat) { LOG_TARGET_WARNING(ctx->cpus[i], "in critical state. Retry in next poll"); if (++busy_target_num == ctx->cores_num) { LOG_WARNING("No available core"); return ERROR_WAIT; } continue; } res = ctx->hw->ctrl_reg_write(ctx->cpus[i], 0, 0, true /*host connected*/, false /*no host data*/); if (res != ERROR_OK) { LOG_ERROR("Failed to write apptrace control reg for cpu(%d) res(%d)!", i, res); return res; } if (ctx->stop_tmo != -1.0) { /* re-start idle time measurement */ if (duration_start(&ctx->idle_time) != 0) { LOG_ERROR("Failed to re-start idle time measure!"); return ERROR_FAIL; } } } } return ERROR_OK; } static int esp32_apptrace_poll(void *priv) { struct esp32_apptrace_cmd_ctx *ctx = (struct esp32_apptrace_cmd_ctx *)priv; int res; uint32_t fired_target_num = 0; struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM]; struct duration blk_proc_time; if (!ctx->running) { if (ctx->auto_clean) ctx->auto_clean(ctx); return ERROR_FAIL; } /* Check for connection is alive.For some reason target and therefore host_connected flag * might have been reset */ res = esp32_apptrace_check_connection(ctx); if (res != ERROR_OK) { if (res != ERROR_WAIT) ctx->running = 0; return res; } /* check for data from target */ res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num); if (res != ERROR_OK) { ctx->running = 0; LOG_ERROR("Failed to read data len!"); return res; } /* LOG_DEBUG("Block %d (%d bytes) on target (%s)!", target_state[0].block_id, * target_state[0].data_len, target_name(ctx->cpus[0])); */ if (fired_target_num == UINT32_MAX) { /* no data has been received, but block could be switched due to the data transferred * from host to target */ if (ctx->cores_num > 1) { uint32_t max_block_id = 0, min_block_id = ctx->hw->max_block_id; /* find maximum block ID and set the same ID in control reg for both cores * */ for (unsigned int i = 0; i < ctx->cores_num; i++) { if (max_block_id < target_state[i].block_id) max_block_id = target_state[i].block_id; if (min_block_id > target_state[i].block_id) min_block_id = target_state[i].block_id; } /* handle block ID overflow */ if (max_block_id == ctx->hw->max_block_id && min_block_id == 0) max_block_id = 0; for (unsigned int i = 0; i < ctx->cores_num; i++) { if (max_block_id != target_state[i].block_id) { LOG_TARGET_DEBUG(ctx->cpus[i], "Ack empty block %" PRId32 "!", max_block_id); res = ctx->hw->ctrl_reg_write(ctx->cpus[i], max_block_id, 0 /*all read*/, true /*host connected*/, false /*no host data*/); if (res != ERROR_OK) { ctx->running = 0; LOG_TARGET_ERROR(ctx->cpus[i], "Failed to ack empty data block!"); return res; } } } ctx->last_blk_id = max_block_id; } if (ctx->stop_tmo != -1.0) { if (duration_measure(&ctx->idle_time) != 0) { ctx->running = 0; LOG_ERROR("Failed to measure idle time!"); return ERROR_FAIL; } if (duration_elapsed(&ctx->idle_time) >= ctx->stop_tmo) { ctx->running = 0; LOG_ERROR("Data timeout!"); return ERROR_FAIL; } } return ERROR_OK;/* no data */ } /* sanity check */ if (target_state[fired_target_num].data_len > ctx->max_trace_block_sz) { ctx->running = 0; LOG_ERROR("Too large block size %" PRId32 "!", target_state[fired_target_num].data_len); return ERROR_FAIL; } if (ctx->tot_len == 0) { if (duration_start(&ctx->read_time) != 0) { ctx->running = 0; LOG_ERROR("Failed to start trace read time measurement!"); return ERROR_FAIL; } } struct esp32_apptrace_block *block = esp32_apptrace_free_block_get(ctx); if (!block) { ctx->running = 0; LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to get free block for data!"); return ERROR_FAIL; } if (s_time_stats_enable) { /* read block */ if (duration_start(&blk_proc_time) != 0) { ctx->running = 0; LOG_ERROR("Failed to start block read time measurement!"); return ERROR_FAIL; } } res = ctx->hw->data_read(ctx->cpus[fired_target_num], target_state[fired_target_num].data_len, block->data, target_state[fired_target_num].block_id, /* do not ack target data in sync mode, esp32_apptrace_handle_trace_block() can write response data and will do ack thereafter */ ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC); if (res != ERROR_OK) { ctx->running = 0; LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to read data!"); return res; } ctx->last_blk_id = target_state[fired_target_num].block_id; block->data_len = target_state[fired_target_num].data_len; ctx->raw_tot_len += block->data_len; if (s_time_stats_enable) { if (duration_measure(&blk_proc_time) != 0) { ctx->running = 0; LOG_ERROR("Failed to measure block read time!"); return ERROR_FAIL; } /* update stats */ float brt = duration_elapsed(&blk_proc_time); if (brt > ctx->stats.max_blk_read_time) ctx->stats.max_blk_read_time = brt; if (brt < ctx->stats.min_blk_read_time) ctx->stats.min_blk_read_time = brt; if (duration_start(&blk_proc_time) != 0) { ctx->running = 0; LOG_ERROR("Failed to start block proc time measurement!"); return ERROR_FAIL; } } /* in sync mode do not ack target data on other cores, esp32_apptrace_handle_trace_block() can write response * data and will do ack thereafter */ if (ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC) { for (unsigned int i = 0; i < ctx->cores_num; i++) { if (i == fired_target_num) continue; res = ctx->hw->ctrl_reg_write(ctx->cpus[i], ctx->last_blk_id, 0 /*all read*/, true /*host connected*/, false /*no host data*/); if (res != ERROR_OK) { ctx->running = 0; LOG_TARGET_ERROR(ctx->cpus[i], "Failed to ack data!"); return res; } LOG_TARGET_DEBUG(ctx->cpus[i], "Ack block %" PRId32, ctx->last_blk_id); } res = esp32_apptrace_ready_block_put(ctx, block); if (res != ERROR_OK) { ctx->running = 0; LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to put ready block of data!"); return res; } } else { res = esp32_apptrace_handle_trace_block(ctx, block); if (res != ERROR_OK) { ctx->running = 0; LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len); return res; } res = esp32_apptrace_block_free(ctx, block); if (res != ERROR_OK) { ctx->running = 0; LOG_ERROR("Failed to free ready block!"); return res; } } if (ctx->stop_tmo != -1.0) { /* start idle time measurement */ if (duration_start(&ctx->idle_time) != 0) { ctx->running = 0; LOG_ERROR("Failed to start idle time measure!"); return ERROR_FAIL; } } if (s_time_stats_enable) { if (duration_measure(&blk_proc_time) != 0) { ctx->running = 0; LOG_ERROR("Failed to stop block proc time measure!"); return ERROR_FAIL; } /* update stats */ float bt = duration_elapsed(&blk_proc_time); if (bt > ctx->stats.max_blk_proc_time) ctx->stats.max_blk_proc_time = bt; if (bt < ctx->stats.min_blk_proc_time) ctx->stats.min_blk_proc_time = bt; } return ERROR_OK; } static inline bool is_sysview_mode(int mode) { return mode == ESP_APPTRACE_CMD_MODE_SYSVIEW || mode == ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE; } static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx) { if (duration_measure(&ctx->read_time) != 0) LOG_ERROR("Failed to stop trace read time measurement!"); int res = target_unregister_timer_callback(esp32_apptrace_poll, ctx); if (res != ERROR_OK) LOG_ERROR("Failed to unregister target timer handler (%d)!", res); if (is_sysview_mode(ctx->mode)) { /* stop tracing */ res = esp32_sysview_stop(ctx); if (res != ERROR_OK) LOG_ERROR("sysview: Failed to stop tracing!"); } /* data processor is alive, so wait for all received blocks to be processed */ res = esp32_apptrace_wait_tracing_finished(ctx); if (res != ERROR_OK) LOG_ERROR("Failed to wait for pended blocks (%d)!", res); res = esp32_apptrace_connect_targets(ctx, false, ctx->target_state == TARGET_RUNNING); if (res != ERROR_OK) LOG_ERROR("Failed to disconnect targets (%d)!", res); esp32_apptrace_print_stats(ctx); res = esp32_apptrace_cmd_cleanup(ctx); if (res != ERROR_OK) LOG_ERROR("Failed to cleanup cmd ctx (%d)!", res); } /* this function must be called after connecting to targets */ static int esp32_sysview_start(struct esp32_apptrace_cmd_ctx *ctx) { uint8_t cmds[] = { SEGGER_SYSVIEW_COMMAND_ID_START }; uint32_t fired_target_num = 0; struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM] = {{0}}; struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv; /* get current block id */ int res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to read target data info!"); return res; } if (fired_target_num == UINT32_MAX) { /* it can happen that there is no pending target data, but block was switched * in this case block_ids on both CPUs are equal, so select the first one */ fired_target_num = 0; } /* start tracing */ res = esp_apptrace_usr_block_write(ctx->hw, ctx->cpus[fired_target_num], target_state[fired_target_num].block_id, cmds, sizeof(cmds)); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to start tracing!"); return res; } cmd_data->sv_trace_running = 1; return res; } static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx) { uint32_t old_block_id, fired_target_num = 0, empty_target_num = 0; struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM]; struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv; uint8_t cmds[] = { SEGGER_SYSVIEW_COMMAND_ID_STOP }; struct duration wait_time; struct esp32_apptrace_block *block = esp32_apptrace_free_block_get(ctx); if (!block) { LOG_ERROR("Failed to get free block for data on (%s)!", target_name(ctx->cpus[fired_target_num])); return ERROR_FAIL; } /* halt all CPUs (not only one), otherwise it can happen that there is no target data and * while we are queueing commands another CPU switches tracing block */ int res = esp32_apptrace_safe_halt_targets(ctx, target_state); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to halt targets (%d)!", res); return res; } /* it can happen that there is no pending target data * in this case block_ids on both CPUs are equal, so the first one will be selected */ for (unsigned int k = 0; k < ctx->cores_num; k++) { if (target_state[k].data_len) { fired_target_num = k; break; } } if (target_state[fired_target_num].data_len) { /* read pending data without ack, they will be acked when stop command is queued */ res = ctx->hw->data_read(ctx->cpus[fired_target_num], target_state[fired_target_num].data_len, block->data, target_state[fired_target_num].block_id, false /*no ack target data*/); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to read data on (%s)!", target_name(ctx->cpus[fired_target_num])); return res; } /* process data */ block->data_len = target_state[fired_target_num].data_len; res = esp32_apptrace_handle_trace_block(ctx, block); if (res != ERROR_OK) { LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len); return res; } } /* stop tracing and ack target data */ res = esp_apptrace_usr_block_write(ctx->hw, ctx->cpus[fired_target_num], target_state[fired_target_num].block_id, cmds, sizeof(cmds)); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to stop tracing!"); return res; } if (ctx->cores_num > 1) { empty_target_num = fired_target_num ? 0 : 1; /* ack target data on another CPU */ res = ctx->hw->ctrl_reg_write(ctx->cpus[empty_target_num], target_state[fired_target_num].block_id, 0 /*target data ack*/, true /*host connected*/, false /*no host data*/); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to ack data on target '%s' (%d)!", target_name(ctx->cpus[empty_target_num]), res); return res; } } /* resume targets to allow command processing */ LOG_INFO("Resume targets"); bool smp_resumed = false; for (unsigned int k = 0; k < ctx->cores_num; k++) { if (smp_resumed && ctx->cpus[k]->smp) { /* in SMP mode we need to call target_resume for one core only */ continue; } res = target_resume(ctx->cpus[k], 1, 0, 1, 0); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to resume target '%s' (%d)!", target_name(ctx->cpus[k]), res); return res; } if (ctx->cpus[k]->smp) smp_resumed = true; } /* wait for block switch (command sent), so we can disconnect from targets */ old_block_id = target_state[fired_target_num].block_id; if (duration_start(&wait_time) != 0) { LOG_ERROR("Failed to start trace stop timeout measurement!"); return ERROR_FAIL; } /* we are waiting for the last data from tracing block and also there can be data in the pended * data buffer */ /* so we are expecting two TRX block switches at most or stopping due to timeout */ while (cmd_data->sv_trace_running) { res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to read targets data info!"); return res; } if (fired_target_num == UINT32_MAX) { /* it can happen that there is no pending (last) target data, but block was * switched */ /* in this case block_ids on both CPUs are equal, so select the first one */ fired_target_num = 0; } if (target_state[fired_target_num].block_id != old_block_id) { if (target_state[fired_target_num].data_len) { /* read last data and ack them */ res = ctx->hw->data_read(ctx->cpus[fired_target_num], target_state[fired_target_num].data_len, block->data, target_state[fired_target_num].block_id, true /*ack target data*/); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to read last data on (%s)!", target_name(ctx->cpus[fired_target_num])); } else { if (ctx->cores_num > 1) { /* ack target data on another CPU */ empty_target_num = fired_target_num ? 0 : 1; res = ctx->hw->ctrl_reg_write(ctx->cpus[empty_target_num], target_state[fired_target_num].block_id, 0 /*all read*/, true /*host connected*/, false /*no host data*/); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to ack data on target '%s' (%d)!", target_name(ctx->cpus[empty_target_num]), res); return res; } } /* process data */ block->data_len = target_state[fired_target_num].data_len; res = esp32_apptrace_handle_trace_block(ctx, block); if (res != ERROR_OK) { LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len); return res; } } old_block_id = target_state[fired_target_num].block_id; } } if (duration_measure(&wait_time) != 0) { LOG_ERROR("Failed to start trace stop timeout measurement!"); return ERROR_FAIL; } const float stop_tmo = LOG_LEVEL_IS(LOG_LVL_DEBUG) ? 30.0 : 0.5; if (duration_elapsed(&wait_time) >= stop_tmo) { LOG_INFO("Stop waiting for the last data due to timeout."); break; } } return res; } static int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const char **argv, int argc) { static struct esp32_apptrace_cmd_ctx s_at_cmd_ctx; struct esp32_apptrace_cmd_data *cmd_data; int res = ERROR_FAIL; enum target_state old_state; struct target *target = get_current_target(CMD_CTX); if (argc < 1) return ERROR_COMMAND_SYNTAX_ERROR; /* command can be invoked on unexamined core, if so find examined one */ if (target->smp && !target_was_examined(target)) { struct target_list *head; struct target *curr; LOG_WARNING("Current target '%s' was not examined!", target_name(target)); foreach_smp_target(head, target->smp_targets) { curr = head->target; if (target_was_examined(curr)) { target = curr; LOG_WARNING("Run command on target '%s'", target_name(target)); break; } } } old_state = target->state; if (strcmp(argv[0], "start") == 0) { if (is_sysview_mode(mode)) { /* init cmd context */ res = esp32_sysview_cmd_init(&s_at_cmd_ctx, cmd, mode, mode == ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE, &argv[1], argc - 1); if (res != ERROR_OK) { command_print(cmd, "Failed to init cmd ctx (%d)!", res); return res; } cmd_data = s_at_cmd_ctx.cmd_priv; if (cmd_data->skip_len != 0) { s_at_cmd_ctx.running = 0; esp32_sysview_cmd_cleanup(&s_at_cmd_ctx); command_print(cmd, "Data skipping not supported!"); return ERROR_FAIL; } s_at_cmd_ctx.process_data = esp32_sysview_process_data; } else { res = esp32_apptrace_cmd_init(&s_at_cmd_ctx, cmd, mode, &argv[1], argc - 1); if (res != ERROR_OK) { command_print(cmd, "Failed to init cmd ctx (%d)!", res); return res; } cmd_data = s_at_cmd_ctx.cmd_priv; s_at_cmd_ctx.process_data = esp32_apptrace_process_data; } s_at_cmd_ctx.auto_clean = esp32_apptrace_cmd_stop; if (cmd_data->wait4halt) { res = esp32_apptrace_wait4halt(&s_at_cmd_ctx, target); if (res != ERROR_OK) { command_print(cmd, "Failed to wait for halt target (%d)!", res); goto _on_start_error; } } res = esp32_apptrace_connect_targets(&s_at_cmd_ctx, true, old_state == TARGET_RUNNING); if (res != ERROR_OK) { command_print(cmd, "Failed to connect to targets (%d)!", res); goto _on_start_error; } if (is_sysview_mode(mode)) { /* start tracing */ res = esp32_sysview_start(&s_at_cmd_ctx); if (res != ERROR_OK) { esp32_apptrace_connect_targets(&s_at_cmd_ctx, false, old_state == TARGET_RUNNING); s_at_cmd_ctx.running = 0; esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx); command_print(cmd, "sysview: Failed to start tracing!"); return res; } } res = target_register_timer_callback(esp32_apptrace_poll, cmd_data->poll_period, TARGET_TIMER_TYPE_PERIODIC, &s_at_cmd_ctx); if (res != ERROR_OK) { command_print(cmd, "Failed to register target timer handler (%d)!", res); goto _on_start_error; } } else if (strcmp(argv[0], "stop") == 0) { if (!s_at_cmd_ctx.running) { command_print(cmd, "Tracing is not running!"); return ERROR_FAIL; } esp32_apptrace_cmd_stop(&s_at_cmd_ctx); return ERROR_OK; } else if (strcmp(argv[0], "status") == 0) { if (s_at_cmd_ctx.running && duration_measure(&s_at_cmd_ctx.read_time) != 0) LOG_ERROR("Failed to measure trace read time!"); esp32_apptrace_print_stats(&s_at_cmd_ctx); return ERROR_OK; } else if (strcmp(argv[0], "dump") == 0) { if (is_sysview_mode(mode)) { command_print(cmd, "Not supported!"); return ERROR_FAIL; } /* [dump outfile] - post-mortem dump without connection to targets */ res = esp32_apptrace_cmd_init(&s_at_cmd_ctx, cmd, mode, &argv[1], argc - 1); if (res != ERROR_OK) { command_print(cmd, "Failed to init cmd ctx (%d)!", res); return res; } s_at_cmd_ctx.stop_tmo = 0.01; /* use small stop tmo */ s_at_cmd_ctx.process_data = esp32_apptrace_process_data; /* check for exit signal and command completion */ while (!openocd_is_shutdown_pending() && s_at_cmd_ctx.running) { res = esp32_apptrace_poll(&s_at_cmd_ctx); if (res != ERROR_OK) { LOG_ERROR("Failed to poll target for trace data (%d)!", res); break; } /* let registered timer callbacks to run */ target_call_timer_callbacks(); } if (s_at_cmd_ctx.running) { /* data processor is alive, so wait for all received blocks to be processed */ res = esp32_apptrace_wait_tracing_finished(&s_at_cmd_ctx); if (res != ERROR_OK) LOG_ERROR("Failed to wait for pended blocks (%d)!", res); } esp32_apptrace_print_stats(&s_at_cmd_ctx); res = esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx); if (res != ERROR_OK) command_print(cmd, "Failed to cleanup cmd ctx (%d)!", res); } else { command_print(cmd, "Invalid action '%s'!", argv[0]); } return res; _on_start_error: s_at_cmd_ctx.running = 0; if (is_sysview_mode(mode)) esp32_sysview_cmd_cleanup(&s_at_cmd_ctx); else esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx); return res; } COMMAND_HANDLER(esp32_cmd_apptrace) { return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_GEN, CMD_ARGV, CMD_ARGC); } COMMAND_HANDLER(esp32_cmd_sysview) { return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_SYSVIEW, CMD_ARGV, CMD_ARGC); } COMMAND_HANDLER(esp32_cmd_sysview_mcore) { return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE, CMD_ARGV, CMD_ARGC); } const struct command_registration esp32_apptrace_command_handlers[] = { { .name = "apptrace", .handler = esp32_cmd_apptrace, .mode = COMMAND_EXEC, .help = "App Tracing: application level trace control. Starts, stops or queries tracing process status.", .usage = "(start <destination> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status) | (dump <destination>)", }, { .name = "sysview", .handler = esp32_cmd_sysview, .mode = COMMAND_EXEC, .help = "App Tracing: SEGGER SystemView compatible trace control. Starts, stops or queries tracing process status.", .usage = "(start file://<outfile1> [file://<outfile2>] [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status)", }, { .name = "sysview_mcore", .handler = esp32_cmd_sysview_mcore, .mode = COMMAND_EXEC, .help = "App Tracing: Espressif multi-core SystemView trace control. Starts, stops or queries tracing process status.", .usage = "(start file://<outfile> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status)", }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp32_apptrace.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * ESP32 application trace module * * Copyright (C) 2017-2019 Espressif Systems Ltd. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESP32_APPTRACE_H #define OPENOCD_TARGET_ESP32_APPTRACE_H #include <helper/command.h> #include <helper/time_support.h> #include <target/target.h> #define ESP32_APPTRACE_MAX_CORES_NUM 2 struct esp32_apptrace_hw { uint32_t max_block_id; uint32_t (*max_block_size_get)(struct target *target); int (*status_reg_read)(struct target *target, uint32_t *stat); int (*ctrl_reg_write)(struct target *target, uint32_t block_id, uint32_t len, bool conn, bool data); int (*ctrl_reg_read)(struct target *target, uint32_t *block_id, uint32_t *len, bool *conn); int (*data_len_read)(struct target *target, uint32_t *block_id, uint32_t *len); int (*data_read)(struct target *target, uint32_t size, uint8_t *buffer, uint32_t block_id, bool ack); uint32_t (*usr_block_max_size_get)(struct target *target); int (*buffs_write)(struct target *target, uint32_t bufs_num, uint32_t buf_sz[], const uint8_t *bufs[], uint32_t block_id, bool ack, bool data); int (*leave_trace_crit_section_start)(struct target *target); int (*leave_trace_crit_section_stop)(struct target *target); }; struct esp_apptrace_host2target_hdr { uint16_t block_sz; }; struct esp32_apptrace_dest { void *priv; int (*write)(void *priv, uint8_t *data, int size); int (*clean)(void *priv); bool log_progress; }; struct esp32_apptrace_format { uint32_t hdr_sz; int (*core_id_get)(struct target *target, uint8_t *hdr_buf); uint32_t (*usr_block_len_get)(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len); }; struct esp32_apptrace_cmd_stats { uint32_t incompl_blocks; uint32_t lost_bytes; float min_blk_read_time; float max_blk_read_time; float min_blk_proc_time; float max_blk_proc_time; }; struct esp32_apptrace_cmd_ctx { volatile int running; int mode; /* TODO: use subtargets from target arch info */ struct target *cpus[ESP32_APPTRACE_MAX_CORES_NUM]; /* TODO: use cores num from target */ unsigned int cores_num; const struct esp32_apptrace_hw *hw; enum target_state target_state; uint32_t last_blk_id; struct list_head free_trace_blocks; struct list_head ready_trace_blocks; uint32_t max_trace_block_sz; struct esp32_apptrace_format trace_format; int (*process_data)(struct esp32_apptrace_cmd_ctx *ctx, unsigned int core_id, uint8_t *data, uint32_t data_len); void (*auto_clean)(struct esp32_apptrace_cmd_ctx *ctx); uint32_t tot_len; uint32_t raw_tot_len; float stop_tmo; struct esp32_apptrace_cmd_stats stats; struct duration read_time; struct duration idle_time; void *cmd_priv; struct target *target; struct command_invocation *cmd; }; struct esp32_apptrace_cmd_data { struct esp32_apptrace_dest data_dest; uint32_t poll_period; uint32_t max_len; uint32_t skip_len; bool wait4halt; }; int esp32_apptrace_cmd_ctx_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct command_invocation *cmd, int mode); int esp32_apptrace_cmd_ctx_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx); void esp32_apptrace_cmd_args_parse(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct esp32_apptrace_cmd_data *cmd_data, const char **argv, int argc); int esp32_apptrace_dest_init(struct esp32_apptrace_dest dest[], const char *dest_paths[], unsigned int max_dests); int esp32_apptrace_dest_cleanup(struct esp32_apptrace_dest dest[], unsigned int max_dests); int esp_apptrace_usr_block_write(const struct esp32_apptrace_hw *hw, struct target *target, uint32_t block_id, const uint8_t *data, uint32_t size); extern const struct command_registration esp32_apptrace_command_handlers[]; #endif /* OPENOCD_TARGET_ESP32_APPTRACE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp32_sysview.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * ESP32 sysview tracing module * * Copyright (C) 2020 Espressif Systems Ltd. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include "esp32_apptrace.h" #include "esp32_sysview.h" #include "segger_sysview.h" /* in SystemView mode core ID is passed in event ID field */ #define ESP32_SYSVIEW_USER_BLOCK_CORE(_v_) (0) /* not used */ #define ESP32_SYSVIEW_USER_BLOCK_LEN(_v_) (_v_) #define ESP32_SYSVIEW_USER_BLOCK_HDR_SZ 2 struct esp_sysview_target2host_hdr { uint8_t block_sz; uint8_t wr_sz; }; #define SYSVIEW_BLOCK_SIZE_OFFSET 0 #define SYSVIEW_WR_SIZE_OFFSET 1 static int esp_sysview_trace_header_write(struct esp32_apptrace_cmd_ctx *ctx, bool mcore_format); static int esp32_sysview_core_id_get(struct target *target, uint8_t *hdr_buf); static uint32_t esp32_sysview_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len); int esp32_sysview_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct command_invocation *cmd, int mode, bool mcore_format, const char **argv, int argc) { struct esp32_sysview_cmd_data *cmd_data; if (argc < 1) { command_print(cmd, "Not enough args! Need trace data destination!"); return ERROR_FAIL; } int res = esp32_apptrace_cmd_ctx_init(cmd_ctx, cmd, mode); if (res != ERROR_OK) return res; int core_num = cmd_ctx->cores_num; if (!mcore_format && argc < core_num) { command_print(cmd, "Not enough args! Need %d trace data destinations!", core_num); res = ERROR_FAIL; goto on_error; } cmd_data = calloc(1, sizeof(*cmd_data)); if (!cmd_data) { command_print(cmd, "No memory for command data!"); res = ERROR_FAIL; goto on_error; } cmd_ctx->cmd_priv = cmd_data; cmd_data->mcore_format = mcore_format; /*outfile1 [outfile2] [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] */ int dests_num = esp32_apptrace_dest_init(cmd_data->data_dests, argv, !mcore_format ? core_num : 1); if (!mcore_format && dests_num < core_num) { command_print(cmd, "Not enough args! Need %d trace data destinations!", core_num); free(cmd_data); res = ERROR_FAIL; goto on_error; } cmd_data->apptrace.max_len = UINT32_MAX; cmd_data->apptrace.poll_period = 0 /*ms*/; cmd_ctx->stop_tmo = -1.0; /* infinite */ if (argc > dests_num) { /* parse remaining args */ esp32_apptrace_cmd_args_parse(cmd_ctx, &cmd_data->apptrace, &argv[dests_num], argc - dests_num); } LOG_USER("App trace params: from %d cores, size %u bytes, stop_tmo %g s, " "poll period %u ms, wait_rst %d, skip %u bytes", cmd_ctx->cores_num, cmd_data->apptrace.max_len, cmd_ctx->stop_tmo, cmd_data->apptrace.poll_period, cmd_data->apptrace.wait4halt, cmd_data->apptrace.skip_len); cmd_ctx->trace_format.hdr_sz = ESP32_SYSVIEW_USER_BLOCK_HDR_SZ; cmd_ctx->trace_format.core_id_get = esp32_sysview_core_id_get; cmd_ctx->trace_format.usr_block_len_get = esp32_sysview_usr_block_len_get; res = esp_sysview_trace_header_write(cmd_ctx, mcore_format); if (res != ERROR_OK) { command_print(cmd, "Failed to write trace header (%d)!", res); esp32_apptrace_dest_cleanup(cmd_data->data_dests, core_num); free(cmd_data); return res; } return ERROR_OK; on_error: cmd_ctx->running = 0; esp32_apptrace_cmd_ctx_cleanup(cmd_ctx); return res; } int esp32_sysview_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx) { struct esp32_sysview_cmd_data *cmd_data = cmd_ctx->cmd_priv; esp32_apptrace_dest_cleanup(cmd_data->data_dests, cmd_ctx->cores_num); free(cmd_data); cmd_ctx->cmd_priv = NULL; esp32_apptrace_cmd_ctx_cleanup(cmd_ctx); return ERROR_OK; } static int esp32_sysview_core_id_get(struct target *target, uint8_t *hdr_buf) { /* for sysview compressed apptrace header is used, so core id is encoded in sysview packet */ return 0; } static uint32_t esp32_sysview_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len) { *wr_len = ESP32_SYSVIEW_USER_BLOCK_LEN(hdr_buf[SYSVIEW_WR_SIZE_OFFSET]); return ESP32_SYSVIEW_USER_BLOCK_LEN(hdr_buf[SYSVIEW_BLOCK_SIZE_OFFSET]); } static int esp_sysview_trace_header_write(struct esp32_apptrace_cmd_ctx *ctx, bool mcore_format) { struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv; char *hdr_str; int dests_num; if (!mcore_format) { hdr_str = ";\n" "; Version " SYSVIEW_MIN_VER_STRING "\n" "; Author Espressif Inc\n" ";\n"; dests_num = ctx->cores_num; } else { hdr_str = ";\n" "; Version " SYSVIEW_MIN_VER_STRING "\n" "; Author Espressif Inc\n" "; ESP_Extension\n" ";\n"; dests_num = 1; } int hdr_len = strlen(hdr_str); for (int i = 0; i < dests_num; i++) { int res = cmd_data->data_dests[i].write(cmd_data->data_dests[i].priv, (uint8_t *)hdr_str, hdr_len); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", hdr_len, i); return ERROR_FAIL; } } return ERROR_OK; } static void sysview_encode_u32(uint8_t **dest, uint32_t val) { uint8_t *sv_ptr = *dest; while (val > 0x7F) { *sv_ptr++ = (uint8_t)(val | 0x80); val >>= 7; } *sv_ptr++ = (uint8_t)val; *dest = sv_ptr; } static uint32_t esp_sysview_decode_u32(uint8_t **ptr) { uint32_t val = 0; for (int k = 0;; k++, (*ptr)++) { if (**ptr & 0x80) { val |= (uint32_t)(**ptr & ~0x80) << 7 * k; } else { val |= (uint32_t)**ptr << 7 * k; (*ptr)++; break; } } return val; } static uint16_t esp_sysview_decode_plen(uint8_t **ptr) { uint16_t payload_len = 0; uint8_t *p = *ptr; /* here pkt points to encoded payload length */ if (*p & 0x80) { payload_len = *(p + 1); /* higher part */ payload_len = (payload_len << 7) | (*p & ~0x80);/* lower 7 bits */ p += 2; /* payload len (2 bytes) */ } else { payload_len = *p; p++; /* payload len (1 byte) */ } *ptr = p; return payload_len; } static uint16_t esp_sysview_get_predef_payload_len(uint16_t id, uint8_t *pkt) { uint16_t len; uint8_t *ptr = pkt; switch (id) { case SYSVIEW_EVTID_OVERFLOW: case SYSVIEW_EVTID_ISR_ENTER: case SYSVIEW_EVTID_TASK_START_EXEC: case SYSVIEW_EVTID_TASK_START_READY: case SYSVIEW_EVTID_TASK_CREATE: case SYSVIEW_EVTID_SYSTIME_CYCLES: case SYSVIEW_EVTID_USER_START: case SYSVIEW_EVTID_USER_STOP: case SYSVIEW_EVTID_TIMER_ENTER: /*ENCODE_U32 */ esp_sysview_decode_u32(&ptr); len = ptr - pkt; break; case SYSVIEW_EVTID_TASK_STOP_READY: case SYSVIEW_EVTID_SYSTIME_US: /*2*ENCODE_U32 */ esp_sysview_decode_u32(&ptr); esp_sysview_decode_u32(&ptr); len = ptr - pkt; break; case SYSVIEW_EVTID_SYSDESC: /*str(128 + 1) */ len = *ptr + 1; break; case SYSVIEW_EVTID_TASK_INFO: case SYSVIEW_EVTID_MODULEDESC: /*2*ENCODE_U32 + str */ esp_sysview_decode_u32(&ptr); esp_sysview_decode_u32(&ptr); /* TODO: add support for strings longer then 255 bytes */ len = ptr - pkt + *ptr + 1; break; case SYSVIEW_EVTID_STACK_INFO: /*4*ENCODE_U32 */ esp_sysview_decode_u32(&ptr); esp_sysview_decode_u32(&ptr); esp_sysview_decode_u32(&ptr); esp_sysview_decode_u32(&ptr); len = ptr - pkt; break; case SYSVIEW_EVTID_ISR_EXIT: case SYSVIEW_EVTID_TASK_STOP_EXEC: case SYSVIEW_EVTID_TRACE_START: case SYSVIEW_EVTID_TRACE_STOP: case SYSVIEW_EVTID_IDLE: case SYSVIEW_EVTID_ISR_TO_SCHEDULER: case SYSVIEW_EVTID_TIMER_EXIT: len = 0; break; /*case SYSVIEW_EVTID_NOP: */ default: LOG_ERROR("sysview: Unsupported predef event %d!", id); len = 0; } return len; } static uint16_t esp_sysview_parse_packet(uint8_t *pkt_buf, uint32_t *pkt_len, unsigned int *pkt_core_id, uint32_t *delta, uint32_t *delta_len, bool clear_core_bit) { uint8_t *pkt = pkt_buf; uint16_t event_id = 0, payload_len = 0; *pkt_core_id = 0; *pkt_len = 0; /* 1-2 byte of message type, 0-2 byte of payload length, payload, 1-5 bytes of timestamp. */ if (*pkt & 0x80) { if (*(pkt + 1) & (1 << 6)) { if (clear_core_bit) *(pkt + 1) &= ~(1 << 6); /* clear core_id bit */ *pkt_core_id = 1; } event_id = *(pkt + 1) & ~(1 << 6); /* higher part */ event_id = (event_id << 7) | (*pkt & ~0x80); /* lower 7 bits */ pkt += 2; /* event_id (2 bytes) */ /* here pkt points to encoded payload length */ payload_len = esp_sysview_decode_plen(&pkt); } else { if (*pkt & (1 << 6)) { if (clear_core_bit) *pkt &= ~(1 << 6); /* clear core_id bit */ *pkt_core_id = 1; } /* event_id (1 byte) */ event_id = *pkt & ~(1 << 6); pkt++; if (event_id < 24) payload_len = esp_sysview_get_predef_payload_len(event_id, pkt); else payload_len = esp_sysview_decode_plen(&pkt); } pkt += payload_len; uint8_t *delta_start = pkt; *delta = esp_sysview_decode_u32(&pkt); *delta_len = pkt - delta_start; *pkt_len = pkt - pkt_buf; LOG_DEBUG("sysview: evt %d len %d plen %d dlen %d", event_id, *pkt_len, payload_len, *delta_len); return event_id; } static int esp32_sysview_write_packet(struct esp32_sysview_cmd_data *cmd_data, int pkt_core_id, uint32_t pkt_len, uint8_t *pkt_buf, uint32_t delta_len, uint8_t *delta_buf) { if (!cmd_data->data_dests[pkt_core_id].write) return ERROR_FAIL; int res = cmd_data->data_dests[pkt_core_id].write(cmd_data->data_dests[pkt_core_id].priv, pkt_buf, pkt_len); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", pkt_len, pkt_core_id); return res; } if (delta_len) { /* write packet with modified delta */ res = cmd_data->data_dests[pkt_core_id].write(cmd_data->data_dests[pkt_core_id].priv, delta_buf, delta_len); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to write %u bytes of delta to dest %d!", delta_len, pkt_core_id); return res; } } return ERROR_OK; } static int esp32_sysview_process_packet(struct esp32_apptrace_cmd_ctx *ctx, unsigned int pkt_core_id, uint16_t event_id, uint32_t delta, uint32_t delta_len, uint32_t pkt_len, uint8_t *pkt_buf) { struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv; int pkt_core_changed = 0; uint32_t new_delta_len = 0; uint8_t new_delta_buf[10]; uint32_t wr_len = pkt_len; if (ctx->cores_num > 1) { if (cmd_data->sv_last_core_id == pkt_core_id) { /* if this packet is for the same core as the prev one acc delta and write packet unmodified */ cmd_data->sv_acc_time_delta += delta; } else { /* if this packet is for another core then prev one set acc delta to the packet's delta */ uint8_t *delta_ptr = new_delta_buf; sysview_encode_u32(&delta_ptr, delta + cmd_data->sv_acc_time_delta); cmd_data->sv_acc_time_delta = delta; wr_len -= delta_len; new_delta_len = delta_ptr - new_delta_buf; pkt_core_changed = 1; } cmd_data->sv_last_core_id = pkt_core_id; } if (pkt_core_id >= ctx->cores_num) { LOG_WARNING("sysview: invalid core ID in packet %d, must be less then %d! Event id %d", pkt_core_id, ctx->cores_num, event_id); return ERROR_FAIL; } int res = esp32_sysview_write_packet(cmd_data, pkt_core_id, wr_len, pkt_buf, new_delta_len, new_delta_buf); if (res != ERROR_OK) return res; for (unsigned int i = 0; i < ctx->cores_num; i++) { if (pkt_core_id == i) continue; switch (event_id) { /* messages below should be sent to trace destinations for all cores */ case SYSVIEW_EVTID_TRACE_START: case SYSVIEW_EVTID_TRACE_STOP: case SYSVIEW_EVTID_SYSTIME_CYCLES: case SYSVIEW_EVTID_SYSTIME_US: case SYSVIEW_EVTID_SYSDESC: case SYSVIEW_EVTID_TASK_INFO: case SYSVIEW_EVTID_STACK_INFO: case SYSVIEW_EVTID_MODULEDESC: case SYSVIEW_EVTID_INIT: case SYSVIEW_EVTID_NUMMODULES: case SYSVIEW_EVTID_OVERFLOW: case SYSVIEW_EVTID_TASK_START_READY: /* if packet's source core has changed */ wr_len = pkt_len; if (pkt_core_changed) { /* clone packet with unmodified delta */ new_delta_len = 0; } else { /* clone packet with modified delta */ uint8_t *delta_ptr = new_delta_buf; sysview_encode_u32(&delta_ptr, cmd_data->sv_acc_time_delta /*delta has been accumulated above*/); wr_len -= delta_len; new_delta_len = delta_ptr - new_delta_buf; } LOG_DEBUG("sysview: Redirect %d bytes of event %d to dest %d", wr_len, event_id, i); res = esp32_sysview_write_packet(cmd_data, i, wr_len, pkt_buf, new_delta_len, new_delta_buf); if (res != ERROR_OK) return res; /* messages above are cloned to trace files for both cores, * so reset acc time delta, both files have actual delta * info */ cmd_data->sv_acc_time_delta = 0; break; default: break; } } return ERROR_OK; } int esp32_sysview_process_data(struct esp32_apptrace_cmd_ctx *ctx, unsigned int core_id, uint8_t *data, uint32_t data_len) { struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv; LOG_DEBUG("sysview: Read from target %d bytes [%x %x %x %x]", data_len, data[0], data[1], data[2], data[3]); int res; uint32_t processed = 0; if (core_id >= ctx->cores_num) { LOG_ERROR("sysview: Invalid core id %d in user block!", core_id); return ERROR_FAIL; } if (cmd_data->mcore_format) core_id = 0; if (ctx->tot_len == 0) { /* handle sync seq */ if (data_len < SYSVIEW_SYNC_LEN) { LOG_ERROR("sysview: Invalid init seq len %d!", data_len); return ERROR_FAIL; } LOG_DEBUG("sysview: Process %d sync bytes", SYSVIEW_SYNC_LEN); uint8_t sync_seq[SYSVIEW_SYNC_LEN] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; if (memcmp(data, sync_seq, SYSVIEW_SYNC_LEN) != 0) { LOG_ERROR("sysview: Invalid init seq [%x %x %x %x %x %x %x %x %x %x]", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9]); return ERROR_FAIL; } res = cmd_data->data_dests[core_id].write(cmd_data->data_dests[core_id].priv, data, SYSVIEW_SYNC_LEN); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to write %u sync bytes to dest %d!", SYSVIEW_SYNC_LEN, core_id); return res; } if (!cmd_data->mcore_format) { for (unsigned int i = 0; i < ctx->cores_num; i++) { if (core_id == i) continue; res = cmd_data->data_dests[i].write(cmd_data->data_dests[i].priv, data, SYSVIEW_SYNC_LEN); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to write %u sync bytes to dest %d!", SYSVIEW_SYNC_LEN, core_id ? 0 : 1); return res; } } } ctx->tot_len += SYSVIEW_SYNC_LEN; processed += SYSVIEW_SYNC_LEN; } while (processed < data_len) { unsigned int pkt_core_id; uint32_t delta_len = 0; uint32_t pkt_len = 0, delta = 0; uint16_t event_id = esp_sysview_parse_packet(data + processed, &pkt_len, &pkt_core_id, &delta, &delta_len, !cmd_data->mcore_format); LOG_DEBUG("sysview: Process packet: core %d, %d id, %d bytes [%x %x %x %x]", pkt_core_id, event_id, pkt_len, data[processed + 0], data[processed + 1], data[processed + 2], data[processed + 3]); if (!cmd_data->mcore_format) { res = esp32_sysview_process_packet(ctx, pkt_core_id, event_id, delta, delta_len, pkt_len, data + processed); if (res != ERROR_OK) return res; } else { res = cmd_data->data_dests[0].write(cmd_data->data_dests[0].priv, data + processed, pkt_len); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", pkt_len, 0); return res; } } if (event_id == SYSVIEW_EVTID_TRACE_STOP) cmd_data->sv_trace_running = 0; ctx->tot_len += pkt_len; processed += pkt_len; } LOG_USER("%u ", ctx->tot_len); /* check for stop condition */ if (ctx->tot_len > cmd_data->apptrace.skip_len && (ctx->tot_len - cmd_data->apptrace.skip_len >= cmd_data->apptrace.max_len)) { ctx->running = 0; if (duration_measure(&ctx->read_time) != 0) { LOG_ERROR("Failed to stop trace read time measure!"); return ERROR_FAIL; } } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp32_sysview.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * ESP32 sysview tracing module * * Copyright (C) 2020 Espressif Systems Ltd. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESP32_SYSVIEW_H #define OPENOCD_TARGET_ESP32_SYSVIEW_H #include <stdint.h> #include "esp32_apptrace.h" struct esp32_sysview_cmd_data { /* Should be the first field. Generic apptrace command handling code accesses it */ struct esp32_apptrace_cmd_data apptrace; struct esp32_apptrace_dest data_dests[ESP32_APPTRACE_MAX_CORES_NUM]; bool mcore_format; uint32_t sv_acc_time_delta; unsigned int sv_last_core_id; int sv_trace_running; }; struct esp32_apptrace_cmd_ctx; int esp32_sysview_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct command_invocation *cmd, int mode, bool mcore_format, const char **argv, int argc); int esp32_sysview_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx); int esp32_sysview_process_data(struct esp32_apptrace_cmd_ctx *ctx, unsigned int core_id, uint8_t *data, uint32_t data_len); #endif /* OPENOCD_TARGET_ESP32_SYSVIEW_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp32s2.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * ESP32-S2 target for OpenOCD * * Copyright (C) 2019 Espressif Systems Ltd. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/time_support.h> #include "assert.h" #include <target/target.h> #include <target/target_type.h> #include <target/semihosting_common.h> #include "esp_xtensa.h" #include "esp_xtensa_semihosting.h" #define ESP32_S2_RTC_DATA_LOW 0x50000000 #define ESP32_S2_RTC_DATA_HIGH 0x50002000 #define ESP32_S2_DR_REG_LOW 0x3f400000 #define ESP32_S2_DR_REG_HIGH 0x3f4d3FFC #define ESP32_S2_SYS_RAM_LOW 0x60000000UL #define ESP32_S2_SYS_RAM_HIGH (ESP32_S2_SYS_RAM_LOW + 0x20000000UL) /* ESP32 WDT */ #define ESP32_S2_WDT_WKEY_VALUE 0x50d83aa1 #define ESP32_S2_TIMG0_BASE 0x3f41F000 #define ESP32_S2_TIMG1_BASE 0x3f420000 #define ESP32_S2_TIMGWDT_CFG0_OFF 0x48 #define ESP32_S2_TIMGWDT_PROTECT_OFF 0x64 #define ESP32_S2_TIMG0WDT_CFG0 (ESP32_S2_TIMG0_BASE + ESP32_S2_TIMGWDT_CFG0_OFF) #define ESP32_S2_TIMG1WDT_CFG0 (ESP32_S2_TIMG1_BASE + ESP32_S2_TIMGWDT_CFG0_OFF) #define ESP32_S2_TIMG0WDT_PROTECT (ESP32_S2_TIMG0_BASE + ESP32_S2_TIMGWDT_PROTECT_OFF) #define ESP32_S2_TIMG1WDT_PROTECT (ESP32_S2_TIMG1_BASE + ESP32_S2_TIMGWDT_PROTECT_OFF) #define ESP32_S2_RTCCNTL_BASE 0x3f408000 #define ESP32_S2_RTCWDT_CFG_OFF 0x94 #define ESP32_S2_RTCWDT_PROTECT_OFF 0xAC #define ESP32_S2_SWD_CONF_OFF 0xB0 #define ESP32_S2_SWD_WPROTECT_OFF 0xB4 #define ESP32_S2_RTC_CNTL_DIG_PWC_REG_OFF 0x8C #define ESP32_S2_RTC_CNTL_DIG_PWC_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTC_CNTL_DIG_PWC_REG_OFF) #define ESP32_S2_RTCWDT_CFG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTCWDT_CFG_OFF) #define ESP32_S2_RTCWDT_PROTECT (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTCWDT_PROTECT_OFF) #define ESP32_S2_SWD_CONF_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_SWD_CONF_OFF) #define ESP32_S2_SWD_WPROTECT_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_SWD_WPROTECT_OFF) #define ESP32_S2_SWD_AUTO_FEED_EN_M BIT(31) #define ESP32_S2_SWD_WKEY_VALUE 0x8F1D312AU #define ESP32_S2_OPTIONS0 (ESP32_S2_RTCCNTL_BASE + 0x0000) #define ESP32_S2_SW_SYS_RST_M 0x80000000 #define ESP32_S2_SW_SYS_RST_V 0x1 #define ESP32_S2_SW_SYS_RST_S 31 #define ESP32_S2_SW_STALL_PROCPU_C0_M ((ESP32_S2_SW_STALL_PROCPU_C0_V) << (ESP32_S2_SW_STALL_PROCPU_C0_S)) #define ESP32_S2_SW_STALL_PROCPU_C0_V 0x3 #define ESP32_S2_SW_STALL_PROCPU_C0_S 2 #define ESP32_S2_SW_CPU_STALL (ESP32_S2_RTCCNTL_BASE + 0x00B8) #define ESP32_S2_SW_STALL_PROCPU_C1_M ((ESP32_S2_SW_STALL_PROCPU_C1_V) << (ESP32_S2_SW_STALL_PROCPU_C1_S)) #define ESP32_S2_SW_STALL_PROCPU_C1_V 0x3FU #define ESP32_S2_SW_STALL_PROCPU_C1_S 26 #define ESP32_S2_CLK_CONF (ESP32_S2_RTCCNTL_BASE + 0x0074) #define ESP32_S2_CLK_CONF_DEF 0x1583218 #define ESP32_S2_STORE4 (ESP32_S2_RTCCNTL_BASE + 0x00BC) #define ESP32_S2_STORE5 (ESP32_S2_RTCCNTL_BASE + 0x00C0) #define ESP32_S2_DPORT_PMS_OCCUPY_3 0x3F4C10E0 #define ESP32_S2_TRACEMEM_BLOCK_SZ 0x4000 #define ESP32_S2_DR_REG_UART_BASE 0x3f400000 #define ESP32_S2_REG_UART_BASE(i) (ESP32_S2_DR_REG_UART_BASE + (i) * 0x10000) #define ESP32_S2_UART_DATE_REG(i) (ESP32_S2_REG_UART_BASE(i) + 0x74) struct esp32s2_common { struct esp_xtensa_common esp_xtensa; }; static int esp32s2_soc_reset(struct target *target); static int esp32s2_disable_wdts(struct target *target); static int esp32s2_assert_reset(struct target *target) { return ERROR_OK; } static int esp32s2_deassert_reset(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); LOG_TARGET_DEBUG(target, "begin"); int res = xtensa_deassert_reset(target); if (res != ERROR_OK) return res; /* restore configured value esp32s2_soc_reset() modified it, but can not restore just after SW reset for some reason (???) */ res = xtensa_smpbreak_write(xtensa, xtensa->smp_break); if (res != ERROR_OK) { LOG_ERROR("Failed to restore smpbreak (%d)!", res); return res; } return ERROR_OK; } static int esp32s2_soft_reset_halt(struct target *target) { LOG_TARGET_DEBUG(target, "begin"); /* Reset the SoC first */ int res = esp32s2_soc_reset(target); if (res != ERROR_OK) return res; return xtensa_soft_reset_halt(target); } static int esp32s2_set_peri_reg_mask(struct target *target, target_addr_t addr, uint32_t mask, uint32_t val) { uint32_t reg_val; int res = target_read_u32(target, addr, ®_val); if (res != ERROR_OK) return res; reg_val = (reg_val & (~mask)) | val; res = target_write_u32(target, addr, reg_val); if (res != ERROR_OK) return res; return ERROR_OK; } static int esp32s2_stall_set(struct target *target, bool stall) { LOG_TARGET_DEBUG(target, "begin"); int res = esp32s2_set_peri_reg_mask(target, ESP32_S2_SW_CPU_STALL, ESP32_S2_SW_STALL_PROCPU_C1_M, stall ? 0x21U << ESP32_S2_SW_STALL_PROCPU_C1_S : 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_SW_CPU_STALL (%d)!", res); return res; } res = esp32s2_set_peri_reg_mask(target, ESP32_S2_OPTIONS0, ESP32_S2_SW_STALL_PROCPU_C0_M, stall ? 0x2 << ESP32_S2_SW_STALL_PROCPU_C0_S : 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_OPTIONS0 (%d)!", res); return res; } return ERROR_OK; } static inline int esp32s2_stall(struct target *target) { return esp32s2_stall_set(target, true); } static inline int esp32s2_unstall(struct target *target) { return esp32s2_stall_set(target, false); } /* Reset ESP32-S2's peripherals. Postconditions: all peripherals except RTC_CNTL are reset, CPU's PC is undefined, PRO CPU is halted, APP CPU is in reset How this works: 0. make sure target is halted; if not, try to halt it; if that fails, try to reset it (via OCD) and then halt 1. Resets clock related registers 2. Stalls CPU 3. trigger SoC reset using RTC_CNTL_SW_SYS_RST bit 4. CPU is reset and stalled at the first reset vector instruction 5. wait for the OCD to be reset 6. halt the target 7. Unstalls CPU 8. Disables WDTs and trace memory mapping */ static int esp32s2_soc_reset(struct target *target) { int res; struct xtensa *xtensa = target_to_xtensa(target); LOG_DEBUG("start"); /* In order to write to peripheral registers, target must be halted first */ if (target->state != TARGET_HALTED) { LOG_TARGET_DEBUG(target, "Target not halted before SoC reset, trying to halt it first"); xtensa_halt(target); res = target_wait_state(target, TARGET_HALTED, 1000); if (res != ERROR_OK) { LOG_TARGET_DEBUG(target, "Couldn't halt target before SoC reset, trying to do reset-halt"); res = xtensa_assert_reset(target); if (res != ERROR_OK) { LOG_TARGET_ERROR( target, "Couldn't halt target before SoC reset! (xtensa_assert_reset returned %d)", res); return res; } alive_sleep(10); xtensa_poll(target); int reset_halt_save = target->reset_halt; target->reset_halt = 1; res = xtensa_deassert_reset(target); target->reset_halt = reset_halt_save; if (res != ERROR_OK) { LOG_TARGET_ERROR( target, "Couldn't halt target before SoC reset! (xtensa_deassert_reset returned %d)", res); return res; } alive_sleep(10); xtensa_poll(target); xtensa_halt(target); res = target_wait_state(target, TARGET_HALTED, 1000); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Couldn't halt target before SoC reset"); return res; } } } assert(target->state == TARGET_HALTED); /* Set some clock-related RTC registers to the default values */ res = target_write_u32(target, ESP32_S2_STORE4, 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_STORE4 (%d)!", res); return res; } res = target_write_u32(target, ESP32_S2_STORE5, 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_STORE5 (%d)!", res); return res; } res = target_write_u32(target, ESP32_S2_RTC_CNTL_DIG_PWC_REG, 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_RTC_CNTL_DIG_PWC_REG (%d)!", res); return res; } res = target_write_u32(target, ESP32_S2_CLK_CONF, ESP32_S2_CLK_CONF_DEF); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_CLK_CONF (%d)!", res); return res; } /* Stall CPU */ res = esp32s2_stall(target); if (res != ERROR_OK) return res; /* enable stall */ res = xtensa_smpbreak_write(xtensa, OCDDCR_RUNSTALLINEN); if (res != ERROR_OK) { LOG_ERROR("Failed to set smpbreak (%d)!", res); return res; } /* Reset CPU */ xtensa->suppress_dsr_errors = true; res = esp32s2_set_peri_reg_mask(target, ESP32_S2_OPTIONS0, ESP32_S2_SW_SYS_RST_M, BIT(ESP32_S2_SW_SYS_RST_S)); xtensa->suppress_dsr_errors = false; if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_OPTIONS0 (%d)!", res); return res; } /* Wait for SoC to reset */ alive_sleep(100); int64_t timeout = timeval_ms() + 100; while (target->state != TARGET_RESET && target->state != TARGET_RUNNING) { alive_sleep(10); xtensa_poll(target); if (timeval_ms() >= timeout) { LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state=%d", target->state); return ERROR_TARGET_TIMEOUT; } } xtensa_halt(target); res = target_wait_state(target, TARGET_HALTED, 1000); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Couldn't halt target before SoC reset"); return res; } /* Unstall CPU */ res = esp32s2_unstall(target); if (res != ERROR_OK) return res; /* Disable WDTs */ res = esp32s2_disable_wdts(target); if (res != ERROR_OK) return res; /* Disable trace memory mapping */ res = target_write_u32(target, ESP32_S2_DPORT_PMS_OCCUPY_3, 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_DPORT_PMS_OCCUPY_3 (%d)!", res); return res; } return ERROR_OK; } static int esp32s2_disable_wdts(struct target *target) { /* TIMG1 WDT */ int res = target_write_u32(target, ESP32_S2_TIMG0WDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_TIMG0WDT_PROTECT (%d)!", res); return res; } res = target_write_u32(target, ESP32_S2_TIMG0WDT_CFG0, 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_TIMG0WDT_CFG0 (%d)!", res); return res; } /* TIMG2 WDT */ res = target_write_u32(target, ESP32_S2_TIMG1WDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_TIMG1WDT_PROTECT (%d)!", res); return res; } res = target_write_u32(target, ESP32_S2_TIMG1WDT_CFG0, 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_TIMG1WDT_CFG0 (%d)!", res); return res; } /* RTC WDT */ res = target_write_u32(target, ESP32_S2_RTCWDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_RTCWDT_PROTECT (%d)!", res); return res; } res = target_write_u32(target, ESP32_S2_RTCWDT_CFG, 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_RTCWDT_CFG (%d)!", res); return res; } /* Enable SWD auto-feed */ res = target_write_u32(target, ESP32_S2_SWD_WPROTECT_REG, ESP32_S2_SWD_WKEY_VALUE); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_SWD_WPROTECT_REG (%d)!", res); return res; } uint32_t swd_conf_reg = 0; res = target_read_u32(target, ESP32_S2_SWD_CONF_REG, &swd_conf_reg); if (res != ERROR_OK) { LOG_ERROR("Failed to read ESP32_S2_SWD_CONF_REG (%d)!", res); return res; } swd_conf_reg |= ESP32_S2_SWD_AUTO_FEED_EN_M; res = target_write_u32(target, ESP32_S2_SWD_CONF_REG, swd_conf_reg); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S2_SWD_CONF_REG (%d)!", res); return res; } return ERROR_OK; } static int esp32s2_arch_state(struct target *target) { return ERROR_OK; } static int esp32s2_on_halt(struct target *target) { int ret = esp32s2_disable_wdts(target); if (ret == ERROR_OK) ret = esp_xtensa_on_halt(target); return ret; } static int esp32s2_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { int ret = xtensa_step(target, current, address, handle_breakpoints); if (ret == ERROR_OK) { esp32s2_on_halt(target); target_call_event_callbacks(target, TARGET_EVENT_HALTED); } return ret; } static int esp32s2_poll(struct target *target) { enum target_state old_state = target->state; int ret = esp_xtensa_poll(target); if (ret != ERROR_OK) return ret; if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) { /* Call any event callbacks that are applicable */ if (old_state == TARGET_DEBUG_RUNNING) { target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } else { if (esp_xtensa_semihosting(target, &ret) == SEMIHOSTING_HANDLED) { struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); if (ret == ERROR_OK && esp_xtensa->semihost.need_resume) { esp_xtensa->semihost.need_resume = false; /* Resume xtensa_resume will handle BREAK instruction. */ ret = target_resume(target, 1, 0, 1, 0); if (ret != ERROR_OK) { LOG_ERROR("Failed to resume target"); return ret; } } return ret; } esp32s2_on_halt(target); target_call_event_callbacks(target, TARGET_EVENT_HALTED); } } return ret; } static int esp32s2_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical) { *physical = virtual; return ERROR_OK; } static int esp32s2_target_init(struct command_context *cmd_ctx, struct target *target) { int ret = esp_xtensa_target_init(cmd_ctx, target); if (ret != ERROR_OK) return ret; return esp_xtensa_semihosting_init(target); } static const struct xtensa_debug_ops esp32s2_dbg_ops = { .queue_enable = xtensa_dm_queue_enable, .queue_reg_read = xtensa_dm_queue_reg_read, .queue_reg_write = xtensa_dm_queue_reg_write }; static const struct xtensa_power_ops esp32s2_pwr_ops = { .queue_reg_read = xtensa_dm_queue_pwr_reg_read, .queue_reg_write = xtensa_dm_queue_pwr_reg_write }; static const struct esp_semihost_ops esp32s2_semihost_ops = { .prepare = esp32s2_disable_wdts }; static int esp32s2_target_create(struct target *target, Jim_Interp *interp) { struct xtensa_debug_module_config esp32s2_dm_cfg = { .dbg_ops = &esp32s2_dbg_ops, .pwr_ops = &esp32s2_pwr_ops, .tap = target->tap, .queue_tdi_idle = NULL, .queue_tdi_idle_arg = NULL }; /* creates xtensa object */ struct esp32s2_common *esp32 = calloc(1, sizeof(*esp32)); if (!esp32) { LOG_ERROR("Failed to alloc memory for arch info!"); return ERROR_FAIL; } int ret = esp_xtensa_init_arch_info(target, &esp32->esp_xtensa, &esp32s2_dm_cfg, &esp32s2_semihost_ops); if (ret != ERROR_OK) { LOG_ERROR("Failed to init arch info!"); free(esp32); return ret; } /* Assume running target. If different, the first poll will fix this */ target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; return ERROR_OK; } static const struct command_registration esp32s2_command_handlers[] = { { .chain = xtensa_command_handlers, }, { .name = "esp", .usage = "", .chain = esp32_apptrace_command_handlers, }, { .name = "arm", .mode = COMMAND_ANY, .help = "ARM Command Group", .usage = "", .chain = semihosting_common_handlers }, COMMAND_REGISTRATION_DONE }; /* Holds methods for Xtensa targets. */ struct target_type esp32s2_target = { .name = "esp32s2", .poll = esp32s2_poll, .arch_state = esp32s2_arch_state, .halt = xtensa_halt, .resume = xtensa_resume, .step = esp32s2_step, .assert_reset = esp32s2_assert_reset, .deassert_reset = esp32s2_deassert_reset, .soft_reset_halt = esp32s2_soft_reset_halt, .virt2phys = esp32s2_virt2phys, .mmu = xtensa_mmu_is_enabled, .read_memory = xtensa_read_memory, .write_memory = xtensa_write_memory, .read_buffer = xtensa_read_buffer, .write_buffer = xtensa_write_buffer, .checksum_memory = xtensa_checksum_memory, .get_gdb_arch = xtensa_get_gdb_arch, .get_gdb_reg_list = xtensa_get_gdb_reg_list, .add_breakpoint = esp_xtensa_breakpoint_add, .remove_breakpoint = esp_xtensa_breakpoint_remove, .add_watchpoint = xtensa_watchpoint_add, .remove_watchpoint = xtensa_watchpoint_remove, .target_create = esp32s2_target_create, .init_target = esp32s2_target_init, .examine = xtensa_examine, .deinit_target = esp_xtensa_target_deinit, .commands = esp32s2_command_handlers, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp32s3.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * ESP32-S3 target API for OpenOCD * * Copyright (C) 2020 Espressif Systems Ltd. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/time_support.h> #include <target/target.h> #include <target/target_type.h> #include <target/smp.h> #include <target/semihosting_common.h> #include "assert.h" #include "esp_xtensa_smp.h" /* This is a JTAG driver for the ESP32_S3, the are two Tensilica cores inside the ESP32_S3 chip. For more information please have a look into ESP32_S3 target implementation. */ /* ESP32_S3 memory map */ #define ESP32_S3_RTC_DATA_LOW 0x50000000 #define ESP32_S3_RTC_DATA_HIGH 0x50002000 #define ESP32_S3_EXTRAM_DATA_LOW 0x3D000000 #define ESP32_S3_EXTRAM_DATA_HIGH 0x3E000000 #define ESP32_S3_SYS_RAM_LOW 0x60000000UL #define ESP32_S3_SYS_RAM_HIGH (ESP32_S3_SYS_RAM_LOW + 0x10000000UL) #define ESP32_S3_RTC_SLOW_MEM_BASE ESP32_S3_RTC_DATA_LOW /* ESP32_S3 WDT */ #define ESP32_S3_WDT_WKEY_VALUE 0x50D83AA1 #define ESP32_S3_TIMG0_BASE 0x6001F000 #define ESP32_S3_TIMG1_BASE 0x60020000 #define ESP32_S3_TIMGWDT_CFG0_OFF 0x48 #define ESP32_S3_TIMGWDT_PROTECT_OFF 0x64 #define ESP32_S3_TIMG0WDT_CFG0 (ESP32_S3_TIMG0_BASE + ESP32_S3_TIMGWDT_CFG0_OFF) #define ESP32_S3_TIMG1WDT_CFG0 (ESP32_S3_TIMG1_BASE + ESP32_S3_TIMGWDT_CFG0_OFF) #define ESP32_S3_TIMG0WDT_PROTECT (ESP32_S3_TIMG0_BASE + ESP32_S3_TIMGWDT_PROTECT_OFF) #define ESP32_S3_TIMG1WDT_PROTECT (ESP32_S3_TIMG1_BASE + ESP32_S3_TIMGWDT_PROTECT_OFF) #define ESP32_S3_RTCCNTL_BASE 0x60008000 #define ESP32_S3_RTCWDT_CFG_OFF 0x98 #define ESP32_S3_RTCWDT_PROTECT_OFF 0xB0 #define ESP32_S3_SWD_CONF_OFF 0xB0 #define ESP32_S3_SWD_WPROTECT_OFF 0xB4 #define ESP32_S3_RTCWDT_CFG (ESP32_S3_RTCCNTL_BASE + ESP32_S3_RTCWDT_CFG_OFF) #define ESP32_S3_RTCWDT_PROTECT (ESP32_S3_RTCCNTL_BASE + ESP32_S3_RTCWDT_PROTECT_OFF) #define ESP32_S3_SWD_CONF_REG (ESP32_S3_RTCCNTL_BASE + ESP32_S3_SWD_CONF_OFF) #define ESP32_S3_SWD_WPROTECT_REG (ESP32_S3_RTCCNTL_BASE + ESP32_S3_SWD_WPROTECT_OFF) #define ESP32_S3_SWD_AUTO_FEED_EN_M BIT(31) #define ESP32_S3_SWD_WKEY_VALUE 0x8F1D312AU #define ESP32_S3_TRACEMEM_BLOCK_SZ 0x4000 /* ESP32_S3 dport regs */ #define ESP32_S3_DR_REG_SYSTEM_BASE 0x600c0000 #define ESP32_S3_SYSTEM_CORE_1_CONTROL_0_REG (ESP32_S3_DR_REG_SYSTEM_BASE + 0x014) #define ESP32_S3_SYSTEM_CONTROL_CORE_1_CLKGATE_EN BIT(1) /* ESP32_S3 RTC regs */ #define ESP32_S3_RTC_CNTL_SW_CPU_STALL_REG (ESP32_S3_RTCCNTL_BASE + 0xBC) #define ESP32_S3_RTC_CNTL_SW_CPU_STALL_DEF 0x0 struct esp32s3_common { struct esp_xtensa_smp_common esp_xtensa_smp; }; /* Reset ESP32-S3's peripherals. * 1. OpenOCD makes sure the target is halted; if not, tries to halt it. * If that fails, tries to reset it (via OCD) and then halt. * 2. OpenOCD loads the stub code into RTC_SLOW_MEM. * 3. Executes the stub code from address 0x50000004. * 4. The stub code changes the reset vector to 0x50000000, and triggers * a system reset using RTC_CNTL_SW_SYS_RST bit. * 5. Once the PRO CPU is out of reset, it executes the stub code from address 0x50000000. * The stub code disables the watchdog, re-enables JTAG and the APP CPU, * restores the reset vector, and enters an infinite loop. * 6. OpenOCD waits until it can talk to the OCD module again, then halts the target. * 7. OpenOCD restores the contents of RTC_SLOW_MEM. * * End result: all the peripherals except RTC_CNTL are reset, CPU's PC is undefined, * PRO CPU is halted, APP CPU is in reset. */ static const uint8_t esp32s3_reset_stub_code[] = { #include "../../../contrib/loaders/reset/espressif/esp32s3/cpu_reset_handler_code.inc" }; static int esp32s3_soc_reset(struct target *target) { int res; struct target_list *head; struct xtensa *xtensa; LOG_DEBUG("start"); /* In order to write to peripheral registers, target must be halted first */ if (target->state != TARGET_HALTED) { LOG_DEBUG("Target not halted before SoC reset, trying to halt it first"); xtensa_halt(target); res = target_wait_state(target, TARGET_HALTED, 1000); if (res != ERROR_OK) { LOG_DEBUG("Couldn't halt target before SoC reset, trying to do reset-halt"); res = xtensa_assert_reset(target); if (res != ERROR_OK) { LOG_ERROR( "Couldn't halt target before SoC reset! (xtensa_assert_reset returned %d)", res); return res; } alive_sleep(10); xtensa_poll(target); bool reset_halt_save = target->reset_halt; target->reset_halt = true; res = xtensa_deassert_reset(target); target->reset_halt = reset_halt_save; if (res != ERROR_OK) { LOG_ERROR( "Couldn't halt target before SoC reset! (xtensa_deassert_reset returned %d)", res); return res; } alive_sleep(10); xtensa_poll(target); xtensa_halt(target); res = target_wait_state(target, TARGET_HALTED, 1000); if (res != ERROR_OK) { LOG_ERROR("Couldn't halt target before SoC reset"); return res; } } } if (target->smp) { foreach_smp_target(head, target->smp_targets) { xtensa = target_to_xtensa(head->target); /* if any of the cores is stalled unstall them */ if (xtensa_dm_core_is_stalled(&xtensa->dbg_mod)) { LOG_TARGET_DEBUG(head->target, "Unstall CPUs before SW reset!"); res = target_write_u32(target, ESP32_S3_RTC_CNTL_SW_CPU_STALL_REG, ESP32_S3_RTC_CNTL_SW_CPU_STALL_DEF); if (res != ERROR_OK) { LOG_TARGET_ERROR(head->target, "Failed to unstall CPUs before SW reset!"); return res; } break; /* both cores are unstalled now, so exit the loop */ } } } LOG_DEBUG("Loading stub code into RTC RAM"); uint8_t slow_mem_save[sizeof(esp32s3_reset_stub_code)]; /* Save contents of RTC_SLOW_MEM which we are about to overwrite */ res = target_read_buffer(target, ESP32_S3_RTC_SLOW_MEM_BASE, sizeof(slow_mem_save), slow_mem_save); if (res != ERROR_OK) { LOG_ERROR("Failed to save contents of RTC_SLOW_MEM (%d)!", res); return res; } /* Write stub code into RTC_SLOW_MEM */ res = target_write_buffer(target, ESP32_S3_RTC_SLOW_MEM_BASE, sizeof(esp32s3_reset_stub_code), esp32s3_reset_stub_code); if (res != ERROR_OK) { LOG_ERROR("Failed to write stub (%d)!", res); return res; } LOG_DEBUG("Resuming the target"); xtensa = target_to_xtensa(target); xtensa->suppress_dsr_errors = true; res = xtensa_resume(target, 0, ESP32_S3_RTC_SLOW_MEM_BASE + 4, 0, 0); xtensa->suppress_dsr_errors = false; if (res != ERROR_OK) { LOG_ERROR("Failed to run stub (%d)!", res); return res; } LOG_DEBUG("resume done, waiting for the target to come alive"); /* Wait for SoC to reset */ alive_sleep(100); int64_t timeout = timeval_ms() + 100; bool get_timeout = false; while (target->state != TARGET_RESET && target->state != TARGET_RUNNING) { alive_sleep(10); xtensa_poll(target); if (timeval_ms() >= timeout) { LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state=%d", target->state); get_timeout = true; break; } } /* Halt the CPU again */ LOG_DEBUG("halting the target"); xtensa_halt(target); res = target_wait_state(target, TARGET_HALTED, 1000); if (res == ERROR_OK) { LOG_DEBUG("restoring RTC_SLOW_MEM"); res = target_write_buffer(target, ESP32_S3_RTC_SLOW_MEM_BASE, sizeof(slow_mem_save), slow_mem_save); if (res != ERROR_OK) LOG_TARGET_ERROR(target, "Failed to restore contents of RTC_SLOW_MEM (%d)!", res); } else { LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be halted after SoC reset"); } return get_timeout ? ERROR_TARGET_TIMEOUT : res; } static int esp32s3_disable_wdts(struct target *target) { /* TIMG1 WDT */ int res = target_write_u32(target, ESP32_S3_TIMG0WDT_PROTECT, ESP32_S3_WDT_WKEY_VALUE); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S3_TIMG0WDT_PROTECT (%d)!", res); return res; } res = target_write_u32(target, ESP32_S3_TIMG0WDT_CFG0, 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S3_TIMG0WDT_CFG0 (%d)!", res); return res; } /* TIMG2 WDT */ res = target_write_u32(target, ESP32_S3_TIMG1WDT_PROTECT, ESP32_S3_WDT_WKEY_VALUE); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S3_TIMG1WDT_PROTECT (%d)!", res); return res; } res = target_write_u32(target, ESP32_S3_TIMG1WDT_CFG0, 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S3_TIMG1WDT_CFG0 (%d)!", res); return res; } /* RTC WDT */ res = target_write_u32(target, ESP32_S3_RTCWDT_PROTECT, ESP32_S3_WDT_WKEY_VALUE); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S3_RTCWDT_PROTECT (%d)!", res); return res; } res = target_write_u32(target, ESP32_S3_RTCWDT_CFG, 0); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S3_RTCWDT_CFG (%d)!", res); return res; } /* Enable SWD auto-feed */ res = target_write_u32(target, ESP32_S3_SWD_WPROTECT_REG, ESP32_S3_SWD_WKEY_VALUE); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S3_SWD_WPROTECT_REG (%d)!", res); return res; } uint32_t swd_conf_reg = 0; res = target_read_u32(target, ESP32_S3_SWD_CONF_REG, &swd_conf_reg); if (res != ERROR_OK) { LOG_ERROR("Failed to read ESP32_S3_SWD_CONF_REG (%d)!", res); return res; } swd_conf_reg |= ESP32_S3_SWD_AUTO_FEED_EN_M; res = target_write_u32(target, ESP32_S3_SWD_CONF_REG, swd_conf_reg); if (res != ERROR_OK) { LOG_ERROR("Failed to write ESP32_S3_SWD_CONF_REG (%d)!", res); return res; } return ERROR_OK; } static int esp32s3_on_halt(struct target *target) { int ret = esp32s3_disable_wdts(target); if (ret == ERROR_OK) ret = esp_xtensa_smp_on_halt(target); return ret; } static int esp32s3_arch_state(struct target *target) { return ERROR_OK; } static int esp32s3_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical) { if (physical) { *physical = virtual; return ERROR_OK; } return ERROR_FAIL; } static int esp32s3_target_init(struct command_context *cmd_ctx, struct target *target) { return esp_xtensa_smp_target_init(cmd_ctx, target); } static const struct xtensa_debug_ops esp32s3_dbg_ops = { .queue_enable = xtensa_dm_queue_enable, .queue_reg_read = xtensa_dm_queue_reg_read, .queue_reg_write = xtensa_dm_queue_reg_write }; static const struct xtensa_power_ops esp32s3_pwr_ops = { .queue_reg_read = xtensa_dm_queue_pwr_reg_read, .queue_reg_write = xtensa_dm_queue_pwr_reg_write }; static const struct esp_xtensa_smp_chip_ops esp32s3_chip_ops = { .reset = esp32s3_soc_reset, .on_halt = esp32s3_on_halt }; static const struct esp_semihost_ops esp32s3_semihost_ops = { .prepare = esp32s3_disable_wdts }; static int esp32s3_target_create(struct target *target, Jim_Interp *interp) { struct xtensa_debug_module_config esp32s3_dm_cfg = { .dbg_ops = &esp32s3_dbg_ops, .pwr_ops = &esp32s3_pwr_ops, .tap = target->tap, .queue_tdi_idle = NULL, .queue_tdi_idle_arg = NULL }; struct esp32s3_common *esp32s3 = calloc(1, sizeof(struct esp32s3_common)); if (!esp32s3) { LOG_ERROR("Failed to alloc memory for arch info!"); return ERROR_FAIL; } int ret = esp_xtensa_smp_init_arch_info(target, &esp32s3->esp_xtensa_smp, &esp32s3_dm_cfg, &esp32s3_chip_ops, &esp32s3_semihost_ops); if (ret != ERROR_OK) { LOG_ERROR("Failed to init arch info!"); free(esp32s3); return ret; } /* Assume running target. If different, the first poll will fix this. */ target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; return ERROR_OK; } static const struct command_registration esp32s3_command_handlers[] = { { .usage = "", .chain = esp_xtensa_smp_command_handlers, }, { .name = "esp", .usage = "", .chain = esp32_apptrace_command_handlers, }, { .name = "esp32", .usage = "", .chain = smp_command_handlers, }, { .name = "arm", .mode = COMMAND_ANY, .help = "ARM Command Group", .usage = "", .chain = semihosting_common_handlers }, COMMAND_REGISTRATION_DONE }; /** Holds methods for Xtensa targets. */ struct target_type esp32s3_target = { .name = "esp32s3", .poll = esp_xtensa_smp_poll, .arch_state = esp32s3_arch_state, .halt = xtensa_halt, .resume = esp_xtensa_smp_resume, .step = esp_xtensa_smp_step, .assert_reset = esp_xtensa_smp_assert_reset, .deassert_reset = esp_xtensa_smp_deassert_reset, .soft_reset_halt = esp_xtensa_smp_soft_reset_halt, .virt2phys = esp32s3_virt2phys, .mmu = xtensa_mmu_is_enabled, .read_memory = xtensa_read_memory, .write_memory = xtensa_write_memory, .read_buffer = xtensa_read_buffer, .write_buffer = xtensa_write_buffer, .checksum_memory = xtensa_checksum_memory, .get_gdb_arch = xtensa_get_gdb_arch, .get_gdb_reg_list = xtensa_get_gdb_reg_list, .add_breakpoint = esp_xtensa_breakpoint_add, .remove_breakpoint = esp_xtensa_breakpoint_remove, .add_watchpoint = esp_xtensa_smp_watchpoint_add, .remove_watchpoint = esp_xtensa_smp_watchpoint_remove, .target_create = esp32s3_target_create, .init_target = esp32s3_target_init, .examine = xtensa_examine, .deinit_target = esp_xtensa_target_deinit, .commands = esp32s3_command_handlers, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp_semihosting.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Semihosting API for Espressif chips * * Copyright (C) 2022 Espressif Systems Ltd. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include <target/target.h> #include <target/semihosting_common.h> #include "esp_semihosting.h" #include "esp_xtensa.h" static struct esp_semihost_data __attribute__((unused)) *target_to_esp_semihost_data(struct target *target) { struct xtensa *xtensa = target->arch_info; if (xtensa->common_magic == XTENSA_COMMON_MAGIC) return &target_to_esp_xtensa(target)->semihost; /* TODO: add riscv */ LOG_ERROR("Unknown target arch!"); return NULL; } static int esp_semihosting_sys_seek(struct target *target, uint64_t fd, uint32_t pos, size_t whence) { struct semihosting *semihosting = target->semihosting; semihosting->result = lseek(fd, pos, whence); semihosting->sys_errno = errno; LOG_TARGET_DEBUG(target, "lseek(%" PRIx64 ", %" PRIu32 " %" PRId64 ")=%d", fd, pos, semihosting->result, errno); return ERROR_OK; } int esp_semihosting_common(struct target *target) { struct semihosting *semihosting = target->semihosting; if (!semihosting) /* Silently ignore if the semihosting field was not set. */ return ERROR_OK; int retval = ERROR_NOT_IMPLEMENTED; /* Enough space to hold 4 long words. */ uint8_t fields[4 * 8]; /* * By default return an error. * The actual result must be set by each function */ semihosting->result = -1; semihosting->sys_errno = EIO; LOG_TARGET_DEBUG(target, "op=0x%x, param=0x%" PRIx64, semihosting->op, semihosting->param); switch (semihosting->op) { case ESP_SEMIHOSTING_SYS_DRV_INFO: /* Return success to make esp-idf application happy */ retval = ERROR_OK; semihosting->result = 0; semihosting->sys_errno = 0; break; case ESP_SEMIHOSTING_SYS_SEEK: retval = semihosting_read_fields(target, 3, fields); if (retval == ERROR_OK) { uint64_t fd = semihosting_get_field(target, 0, fields); uint32_t pos = semihosting_get_field(target, 1, fields); size_t whence = semihosting_get_field(target, 2, fields); retval = esp_semihosting_sys_seek(target, fd, pos, whence); } break; case ESP_SEMIHOSTING_SYS_APPTRACE_INIT: case ESP_SEMIHOSTING_SYS_DEBUG_STUBS_INIT: case ESP_SEMIHOSTING_SYS_BREAKPOINT_SET: case ESP_SEMIHOSTING_SYS_WATCHPOINT_SET: /* For the time being only riscv chips support these commands * TODO: invoke riscv custom command handler */ break; } return retval; } int esp_semihosting_basedir_command(struct command_invocation *cmd) { struct target *target = get_current_target(CMD_CTX); if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } struct semihosting *semihosting = target->semihosting; if (!semihosting) { command_print(CMD, "semihosting not supported for current target"); return ERROR_FAIL; } if (!semihosting->is_active) { if (semihosting->setup(target, true) != ERROR_OK) { LOG_ERROR("Failed to Configure semihosting"); return ERROR_FAIL; } semihosting->is_active = true; } if (CMD_ARGC > 0) { free(semihosting->basedir); semihosting->basedir = strdup(CMD_ARGV[0]); if (!semihosting->basedir) { command_print(CMD, "semihosting failed to allocate memory for basedir!"); return ERROR_FAIL; } } command_print(CMD, "DEPRECATED! semihosting base dir: %s", semihosting->basedir ? semihosting->basedir : ""); return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp_semihosting.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Semihosting API for Espressif chips * * Copyright (C) 2022 Espressif Systems Ltd. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESP_SEMIHOSTING_H #define OPENOCD_TARGET_ESP_SEMIHOSTING_H /* Legacy syscalls */ #define ESP_SYS_DRV_INFO_LEGACY 0xE0 /* syscalls compatible to ARM standard */ #define ESP_SEMIHOSTING_SYS_DRV_INFO 0x100 #define ESP_SEMIHOSTING_SYS_APPTRACE_INIT 0x101 #define ESP_SEMIHOSTING_SYS_DEBUG_STUBS_INIT 0x102 #define ESP_SEMIHOSTING_SYS_BREAKPOINT_SET 0x103 #define ESP_SEMIHOSTING_SYS_WATCHPOINT_SET 0x104 #define ESP_SEMIHOSTING_SYS_SEEK 0x105 /* custom lseek with whence */ /* not implemented yet */ #define ESP_SEMIHOSTING_SYS_MKDIR 0x106 #define ESP_SEMIHOSTING_SYS_OPENDIR 0x107 #define ESP_SEMIHOSTING_SYS_READDIR 0x108 #define ESP_SEMIHOSTING_SYS_READDIR_R 0x109 #define ESP_SEMIHOSTING_SYS_SEEKDIR 0x10A #define ESP_SEMIHOSTING_SYS_TELLDIR 0x10B #define ESP_SEMIHOSTING_SYS_CLOSEDIR 0x10C #define ESP_SEMIHOSTING_SYS_RMDIR 0x10D #define ESP_SEMIHOSTING_SYS_ACCESS 0x10E #define ESP_SEMIHOSTING_SYS_TRUNCATE 0x10F #define ESP_SEMIHOSTING_SYS_UTIME 0x110 #define ESP_SEMIHOSTING_SYS_FSTAT 0x111 #define ESP_SEMIHOSTING_SYS_STAT 0x112 #define ESP_SEMIHOSTING_SYS_FSYNC 0x113 #define ESP_SEMIHOSTING_SYS_LINK 0x114 #define ESP_SEMIHOSTING_SYS_UNLINK 0x115 /** * Semihost calls handling operations. */ struct esp_semihost_ops { /** Callback called before handling semihost call */ int (*prepare)(struct target *target); }; struct esp_semihost_data { bool need_resume; struct esp_semihost_ops *ops; }; int esp_semihosting_common(struct target *target); int esp_semihosting_basedir_command(struct command_invocation *cmd); #endif /* OPENOCD_TARGET_ESP_SEMIHOSTING_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp_xtensa.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Espressif Xtensa target API for OpenOCD * * Copyright (C) 2019 Espressif Systems Ltd. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <stdbool.h> #include <stdint.h> #include <target/smp.h> #include "esp_xtensa_apptrace.h" #include <target/register.h> #include "esp_xtensa.h" #include "esp_semihosting.h" #define ESP_XTENSA_DBGSTUBS_UPDATE_DATA_ENTRY(_e_) \ do { \ uint32_t __internal_val = (_e_); \ if (!xtensa_data_addr_valid(target, __internal_val)) { \ LOG_ERROR("No valid stub data entry found (0x%" PRIx32 ")!", __internal_val); \ return; \ } \ } while (0) #define ESP_XTENSA_DBGSTUBS_UPDATE_CODE_ENTRY(_e_) \ do { \ uint32_t __internal_val = (_e_); \ if (__internal_val == 0) { \ LOG_ERROR("No valid stub code entry found (0x%" PRIx32 ")!", __internal_val); \ return; \ } \ } while (0) static void esp_xtensa_dbgstubs_info_update(struct target *target); static void esp_xtensa_dbgstubs_addr_check(struct target *target); static int esp_xtensa_dbgstubs_restore(struct target *target) { struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); if (esp_xtensa->esp.dbg_stubs.base == 0) return ERROR_OK; LOG_TARGET_INFO(target, "Restore debug stubs address %" PRIx32, esp_xtensa->esp.dbg_stubs.base); int res = esp_xtensa_apptrace_status_reg_write(target, esp_xtensa->esp.dbg_stubs.base); if (res != ERROR_OK) { LOG_ERROR("Failed to write trace status (%d)!", res); return res; } return ERROR_OK; } int esp_xtensa_on_halt(struct target *target) { /* debug stubs can be used in HALTED state only, so it is OK to get info about them here */ esp_xtensa_dbgstubs_info_update(target); return ERROR_OK; } int esp_xtensa_init_arch_info(struct target *target, struct esp_xtensa_common *esp_xtensa, struct xtensa_debug_module_config *dm_cfg, const struct esp_semihost_ops *semihost_ops) { int ret = xtensa_init_arch_info(target, &esp_xtensa->xtensa, dm_cfg); if (ret != ERROR_OK) return ret; esp_xtensa->semihost.ops = (struct esp_semihost_ops *)semihost_ops; esp_xtensa->apptrace.hw = &esp_xtensa_apptrace_hw; return ERROR_OK; } int esp_xtensa_target_init(struct command_context *cmd_ctx, struct target *target) { return xtensa_target_init(cmd_ctx, target); } void esp_xtensa_target_deinit(struct target *target) { LOG_DEBUG("start"); if (target_was_examined(target)) { int ret = esp_xtensa_dbgstubs_restore(target); if (ret != ERROR_OK) return; } xtensa_target_deinit(target); free(target_to_esp_xtensa(target)); /* same as free(xtensa) */ } int esp_xtensa_arch_state(struct target *target) { return ERROR_OK; } int esp_xtensa_poll(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); struct esp_xtensa_common *esp_xtensa_common = target_to_esp_xtensa(target); int ret = xtensa_poll(target); if (xtensa_dm_power_status_get(&xtensa->dbg_mod) & PWRSTAT_COREWASRESET(xtensa)) { LOG_TARGET_DEBUG(target, "Clear debug stubs info"); memset(&esp_xtensa_common->esp.dbg_stubs, 0, sizeof(esp_xtensa_common->esp.dbg_stubs)); } if (target->state != TARGET_DEBUG_RUNNING) esp_xtensa_dbgstubs_addr_check(target); return ret; } static void esp_xtensa_dbgstubs_addr_check(struct target *target) { struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); uint32_t vec_addr = 0; if (esp_xtensa->esp.dbg_stubs.base != 0) return; int res = esp_xtensa_apptrace_status_reg_read(target, &vec_addr); if (res != ERROR_OK) { LOG_ERROR("Failed to read debug stubs address location (%d)!", res); return; } if (xtensa_data_addr_valid(target, vec_addr)) { LOG_TARGET_INFO(target, "Detected debug stubs @ %" PRIx32, vec_addr); res = esp_xtensa_apptrace_status_reg_write(target, 0); if (res != ERROR_OK) LOG_ERROR("Failed to clear debug stubs address location (%d)!", res); esp_xtensa->esp.dbg_stubs.base = vec_addr; } } static void esp_xtensa_dbgstubs_info_update(struct target *target) { struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); if (esp_xtensa->esp.dbg_stubs.base == 0 || esp_xtensa->esp.dbg_stubs.entries_count != 0) return; int res = esp_dbgstubs_table_read(target, &esp_xtensa->esp.dbg_stubs); if (res != ERROR_OK) return; if (esp_xtensa->esp.dbg_stubs.entries_count == 0) return; /* read debug stubs descriptor */ ESP_XTENSA_DBGSTUBS_UPDATE_DATA_ENTRY(esp_xtensa->esp.dbg_stubs.entries[ESP_DBG_STUB_DESC]); res = target_read_buffer(target, esp_xtensa->esp.dbg_stubs.entries[ESP_DBG_STUB_DESC], sizeof(struct esp_dbg_stubs_desc), (uint8_t *)&esp_xtensa->esp.dbg_stubs.desc); if (res != ERROR_OK) { LOG_ERROR("Failed to read debug stubs descriptor (%d)!", res); return; } ESP_XTENSA_DBGSTUBS_UPDATE_CODE_ENTRY(esp_xtensa->esp.dbg_stubs.desc.tramp_addr); ESP_XTENSA_DBGSTUBS_UPDATE_DATA_ENTRY(esp_xtensa->esp.dbg_stubs.desc.min_stack_addr); ESP_XTENSA_DBGSTUBS_UPDATE_CODE_ENTRY(esp_xtensa->esp.dbg_stubs.desc.data_alloc); ESP_XTENSA_DBGSTUBS_UPDATE_CODE_ENTRY(esp_xtensa->esp.dbg_stubs.desc.data_free); } int esp_xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint) { return xtensa_breakpoint_add(target, breakpoint); /* flash breakpoints will be handled in another patch */ } int esp_xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint) { return xtensa_breakpoint_remove(target, breakpoint); /* flash breakpoints will be handled in another patch */ } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp_xtensa.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Generic ESP xtensa target implementation for OpenOCD * * Copyright (C) 2019 Espressif Systems Ltd. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESP_XTENSA_H #define OPENOCD_TARGET_ESP_XTENSA_H #include <target/target.h> #include <target/xtensa/xtensa.h> #include "esp_semihosting.h" #include "esp.h" #include "esp_xtensa_apptrace.h" struct esp_xtensa_common { struct xtensa xtensa; /* must be the first element */ struct esp_common esp; struct esp_semihost_data semihost; struct esp_xtensa_apptrace_info apptrace; }; static inline struct esp_xtensa_common *target_to_esp_xtensa(struct target *target) { return container_of(target->arch_info, struct esp_xtensa_common, xtensa); } int esp_xtensa_init_arch_info(struct target *target, struct esp_xtensa_common *esp_xtensa, struct xtensa_debug_module_config *dm_cfg, const struct esp_semihost_ops *semihost_ops); int esp_xtensa_target_init(struct command_context *cmd_ctx, struct target *target); void esp_xtensa_target_deinit(struct target *target); int esp_xtensa_arch_state(struct target *target); void esp_xtensa_queue_tdi_idle(struct target *target); int esp_xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint); int esp_xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint); int esp_xtensa_poll(struct target *target); int esp_xtensa_on_halt(struct target *target); #endif /* OPENOCD_TARGET_ESP_XTENSA_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp_xtensa_apptrace.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Xtensa application tracing module for OpenOCD * * Copyright (C) 2017 Espressif Systems Ltd. * ***************************************************************************/ /* How it works? https://github.com/espressif/esp-idf/blob/master/components/app_trace/port/xtensa/port.c#L8 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/align.h> #include <target/xtensa/xtensa.h> #include <target/xtensa/xtensa_debug_module.h> #include "esp_xtensa_apptrace.h" /* TRAX is disabled, so we use its registers for our own purposes * | 31..XXXXXX..24 | 23 .(host_connect). 23 | 22 .(host_data). 22| 21..(block_id)..15 | 14..(block_len)..0 | */ #define XTENSA_APPTRACE_CTRL_REG XDMREG_DELAYCNT #define XTENSA_APPTRACE_BLOCK_ID_MSK 0x7FUL #define XTENSA_APPTRACE_BLOCK_ID_MAX XTENSA_APPTRACE_BLOCK_ID_MSK /* if non-zero then apptrace code entered the critical section and the value is an address of the * critical section's exit point */ #define XTENSA_APPTRACE_STAT_REG XDMREG_TRIGGERPC #define XTENSA_APPTRACE_BLOCK_LEN_MSK 0x7FFFUL #define XTENSA_APPTRACE_BLOCK_LEN(_l_) ((_l_) & XTENSA_APPTRACE_BLOCK_LEN_MSK) #define XTENSA_APPTRACE_BLOCK_LEN_GET(_v_) ((_v_) & XTENSA_APPTRACE_BLOCK_LEN_MSK) #define XTENSA_APPTRACE_BLOCK_ID(_id_) (((_id_) & XTENSA_APPTRACE_BLOCK_ID_MSK) << 15) #define XTENSA_APPTRACE_BLOCK_ID_GET(_v_) (((_v_) >> 15) & XTENSA_APPTRACE_BLOCK_ID_MSK) #define XTENSA_APPTRACE_HOST_DATA BIT(22) #define XTENSA_APPTRACE_HOST_CONNECT BIT(23) static int esp_xtensa_apptrace_leave_crit_section_start(struct target *target); static int esp_xtensa_apptrace_leave_crit_section_stop(struct target *target); static int esp_xtensa_apptrace_buffs_write(struct target *target, uint32_t bufs_num, uint32_t buf_sz[], const uint8_t *bufs[], uint32_t block_id, bool ack, bool data); struct esp32_apptrace_hw esp_xtensa_apptrace_hw = { .max_block_id = XTENSA_APPTRACE_BLOCK_ID_MAX, .max_block_size_get = esp_xtensa_apptrace_block_max_size_get, .status_reg_read = esp_xtensa_apptrace_status_reg_read, .ctrl_reg_write = esp_xtensa_apptrace_ctrl_reg_write, .ctrl_reg_read = esp_xtensa_apptrace_ctrl_reg_read, .data_len_read = esp_xtensa_apptrace_data_len_read, .data_read = esp_xtensa_apptrace_data_read, .usr_block_max_size_get = esp_xtensa_apptrace_usr_block_max_size_get, .buffs_write = esp_xtensa_apptrace_buffs_write, .leave_trace_crit_section_start = esp_xtensa_apptrace_leave_crit_section_start, .leave_trace_crit_section_stop = esp_xtensa_apptrace_leave_crit_section_stop, }; uint32_t esp_xtensa_apptrace_block_max_size_get(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); struct xtensa_trace_status trace_status; struct xtensa_trace_config trace_config; uint32_t max_trace_block_sz; int res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status); if (res != ERROR_OK) { LOG_ERROR("Failed to read TRAX status (%d)!", res); return 0; } max_trace_block_sz = BIT(((trace_status.stat >> 8) & 0x1f) - 2) * 4; res = xtensa_dm_trace_config_read(&xtensa->dbg_mod, &trace_config); if (res != ERROR_OK) { LOG_ERROR("Failed to read TRAX config (%d)!", res); return 0; } LOG_DEBUG("ctrl=0x%" PRIx32 " memadrstart=0x%" PRIx32 " memadrend=0x%" PRIx32 " traxadr=0x%" PRIx32, trace_config.ctrl, trace_config.memaddr_start, trace_config.memaddr_end, trace_config.addr); return max_trace_block_sz; } uint32_t esp_xtensa_apptrace_usr_block_max_size_get(struct target *target) { return esp_xtensa_apptrace_block_max_size_get(target) - sizeof(struct esp_apptrace_host2target_hdr); } int esp_xtensa_apptrace_data_len_read(struct target *target, uint32_t *block_id, uint32_t *len) { return esp_xtensa_apptrace_ctrl_reg_read(target, block_id, len, NULL); } int esp_xtensa_apptrace_usr_block_write(struct target *target, uint32_t block_id, const uint8_t *data, uint32_t size) { return esp_apptrace_usr_block_write(&esp_xtensa_apptrace_hw, target, block_id, data, size); } static int esp_xtensa_apptrace_data_reverse_read(struct xtensa *xtensa, uint32_t size, uint8_t *buffer, uint8_t *unal_bytes) { int res = 0; uint32_t rd_sz = ALIGN_UP(size, 4); res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, (xtensa->core_config->trace.mem_sz - rd_sz) / 4); if (res != ERROR_OK) return res; if (!IS_ALIGNED(size, 4)) { res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, unal_bytes); if (res != ERROR_OK) return res; } for (unsigned int i = size / 4; i != 0; i--) { res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, &buffer[(i - 1) * 4]); if (res != ERROR_OK) return res; } return ERROR_OK; } static int esp_xtensa_apptrace_data_normal_read(struct xtensa *xtensa, uint32_t size, uint8_t *buffer, uint8_t *unal_bytes) { int res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, 0); if (res != ERROR_OK) return res; for (unsigned int i = 0; i < size / 4; i++) { res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, &buffer[i * 4]); if (res != ERROR_OK) return res; } if (!IS_ALIGNED(size, 4)) { res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, unal_bytes); if (res != ERROR_OK) return res; } return ERROR_OK; } int esp_xtensa_apptrace_data_read(struct target *target, uint32_t size, uint8_t *buffer, uint32_t block_id, bool ack) { struct xtensa *xtensa = target_to_xtensa(target); int res; uint32_t tmp = XTENSA_APPTRACE_HOST_CONNECT | XTENSA_APPTRACE_BLOCK_ID(block_id) | XTENSA_APPTRACE_BLOCK_LEN(0); uint8_t unal_bytes[4]; LOG_DEBUG("Read data on target (%s)", target_name(target)); if (xtensa->core_config->trace.reversed_mem_access) res = esp_xtensa_apptrace_data_reverse_read(xtensa, size, buffer, unal_bytes); else res = esp_xtensa_apptrace_data_normal_read(xtensa, size, buffer, unal_bytes); if (res != ERROR_OK) return res; if (ack) { LOG_DEBUG("Ack block %" PRIu32 " target (%s)!", block_id, target_name(target)); res = xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp); if (res != ERROR_OK) return res; } xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_ERROR("Failed to exec JTAG queue!"); return res; } if (!IS_ALIGNED(size, 4)) { /* copy the last unaligned bytes */ memcpy(buffer + ALIGN_DOWN(size, 4), unal_bytes, size & 0x3UL); } return ERROR_OK; } int esp_xtensa_apptrace_ctrl_reg_write(struct target *target, uint32_t block_id, uint32_t len, bool conn, bool data) { struct xtensa *xtensa = target_to_xtensa(target); uint32_t tmp = (conn ? XTENSA_APPTRACE_HOST_CONNECT : 0) | (data ? XTENSA_APPTRACE_HOST_DATA : 0) | XTENSA_APPTRACE_BLOCK_ID(block_id) | XTENSA_APPTRACE_BLOCK_LEN(len); xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_ERROR("Failed to exec JTAG queue!"); return res; } return ERROR_OK; } int esp_xtensa_apptrace_ctrl_reg_read(struct target *target, uint32_t *block_id, uint32_t *len, bool *conn) { struct xtensa *xtensa = target_to_xtensa(target); uint8_t tmp[4]; xtensa_queue_dbg_reg_read(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) return res; uint32_t val = target_buffer_get_u32(target, tmp); if (block_id) *block_id = XTENSA_APPTRACE_BLOCK_ID_GET(val); if (len) *len = XTENSA_APPTRACE_BLOCK_LEN_GET(val); if (conn) *conn = val & XTENSA_APPTRACE_HOST_CONNECT; return ERROR_OK; } int esp_xtensa_apptrace_status_reg_read(struct target *target, uint32_t *stat) { struct xtensa *xtensa = target_to_xtensa(target); uint8_t tmp[4]; int res = xtensa_queue_dbg_reg_read(xtensa, XTENSA_APPTRACE_STAT_REG, tmp); if (res != ERROR_OK) return res; xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_ERROR("Failed to exec JTAG queue!"); return res; } *stat = buf_get_u32(tmp, 0, 32); return ERROR_OK; } int esp_xtensa_apptrace_status_reg_write(struct target *target, uint32_t stat) { struct xtensa *xtensa = target_to_xtensa(target); xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_STAT_REG, stat); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_ERROR("Failed to exec JTAG queue!"); return res; } return ERROR_OK; } static int esp_xtensa_swdbg_activate(struct target *target, int enab) { struct xtensa *xtensa = target_to_xtensa(target); xtensa_queue_dbg_reg_write(xtensa, enab ? XDMREG_DCRSET : XDMREG_DCRCLR, OCDDCR_DEBUGSWACTIVE); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_ERROR("%s: writing DCR failed!", target->cmd_name); return res; } return ERROR_OK; } static int esp_xtensa_apptrace_leave_crit_section_start(struct target *target) { /* TODO: not sure that we need this, but it seems that we fail to leave tracing critical *section w/o this */ int res = esp_xtensa_swdbg_activate(target, 1 /*enable*/); if (res != ERROR_OK) { LOG_ERROR("Failed to activate SW debug (%d)!", res); return res; } return ERROR_OK; } static int esp_xtensa_apptrace_leave_crit_section_stop(struct target *target) { int res = esp_xtensa_swdbg_activate(target, 0 /*disable*/); if (res != ERROR_OK) { LOG_ERROR("Failed to activate SW debug (%d)!", res); return res; } return ERROR_OK; } static int esp_xtensa_apptrace_queue_reverse_write(struct target *target, uint32_t bufs_num, uint32_t buf_sz[], const uint8_t *bufs[]) { int res = ERROR_OK; uint32_t cached_bytes = 0, total_sz = 0; uint8_t cached_data8[sizeof(uint32_t)] = { 0 }; uint32_t cached_data32 = 0; struct xtensa *xtensa = target_to_xtensa(target); for (uint32_t i = 0; i < bufs_num; i++) total_sz += buf_sz[i]; if (!IS_ALIGNED(total_sz, 4)) { cached_bytes = sizeof(uint32_t) - (total_sz & 0x3UL); total_sz = ALIGN_UP(total_sz, 4); } xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, (xtensa->core_config->trace.mem_sz - total_sz) / 4); for (uint32_t i = bufs_num; i > 0; i--) { uint32_t bsz = buf_sz[i - 1]; const uint8_t *cur_buf = &bufs[i - 1][bsz]; uint32_t bytes_to_cache; /* if there are cached bytes from the previous buffer, combine them with the last * from the current buffer */ if (cached_bytes) { if ((cached_bytes + bsz) < sizeof(uint32_t)) bytes_to_cache = bsz; else bytes_to_cache = sizeof(uint32_t) - cached_bytes; memcpy(&cached_data8[sizeof(uint32_t) - cached_bytes - bytes_to_cache], cur_buf - bytes_to_cache, bytes_to_cache); cached_data32 = target_buffer_get_u32(target, cached_data8); cached_bytes += bytes_to_cache; if (cached_bytes < sizeof(uint32_t)) continue; res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); if (res != ERROR_OK) return res; bsz -= bytes_to_cache; cur_buf -= bytes_to_cache; memset(cached_data8, 0x00, sizeof(cached_data8)); cached_bytes = 0; } /* write full dwords */ for (unsigned int k = bsz; k >= sizeof(uint32_t); k -= sizeof(uint32_t)) { uint32_t temp = target_buffer_get_u32(target, cur_buf - sizeof(uint32_t)); res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, temp); if (res != ERROR_OK) return res; cur_buf -= sizeof(uint32_t); } /* if there are bytes to be cached (1..3) */ bytes_to_cache = bsz & 0x3UL; if (bytes_to_cache > 0) { if (bytes_to_cache + cached_bytes >= sizeof(uint32_t)) { /* filling the cache buffer from the end to beginning */ uint32_t to_copy = sizeof(uint32_t) - cached_bytes; memcpy(&cached_data8[0], cur_buf - to_copy, to_copy); cached_data32 = target_buffer_get_u32(target, cached_data8); /* write full word of cached bytes */ res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); if (res != ERROR_OK) return res; /* cache remaining bytes */ memset(cached_data8, 0x00, sizeof(cached_data8)); cur_buf -= to_copy; to_copy = bytes_to_cache + cached_bytes - sizeof(uint32_t); memcpy(&cached_data8[sizeof(uint32_t) - to_copy], cur_buf - to_copy, to_copy); cached_bytes = to_copy; } else { /* filling the cache buffer from the end to beginning */ memcpy(&cached_data8[sizeof(uint32_t) - cached_bytes - bytes_to_cache], cur_buf - bytes_to_cache, bytes_to_cache); cached_bytes += bytes_to_cache; } } } return ERROR_OK; } static int esp_xtensa_apptrace_queue_normal_write(struct target *target, uint32_t bufs_num, uint32_t buf_sz[], const uint8_t *bufs[]) { int res = ERROR_OK; uint32_t cached_bytes = 0; uint8_t cached_data8[4] = { 0 }; uint32_t cached_data32 = 0; struct xtensa *xtensa = target_to_xtensa(target); /* | 1 | 2 | 1 | 2 | 4 |.......| * | 4 | 4 | 4 | */ xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, 0); for (unsigned int i = 0; i < bufs_num; i++) { uint32_t bsz = buf_sz[i]; const uint8_t *cur_buf = bufs[i]; uint32_t bytes_to_cache; /* if there are cached bytes from the previous buffer, combine them with the last * from the current buffer */ if (cached_bytes) { if ((cached_bytes + bsz) < sizeof(uint32_t)) bytes_to_cache = bsz; else bytes_to_cache = sizeof(uint32_t) - cached_bytes; memcpy(&cached_data8[cached_bytes], cur_buf, bytes_to_cache); cached_bytes += bytes_to_cache; if (cached_bytes < sizeof(uint32_t)) continue; cached_data32 = target_buffer_get_u32(target, cached_data8); res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); if (res != ERROR_OK) return res; bsz -= bytes_to_cache; cur_buf += bytes_to_cache; memset(cached_data8, 0x00, sizeof(cached_data8)); cached_bytes = 0; } /* write full dwords */ for (unsigned int k = 0; (k + sizeof(uint32_t)) <= bsz; k += sizeof(uint32_t)) { uint32_t temp = target_buffer_get_u32(target, cur_buf); res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, temp); if (res != ERROR_OK) return res; cur_buf += sizeof(uint32_t); } /* if there are bytes to be cached (1..3) */ bytes_to_cache = bsz & 0x3UL; if (bytes_to_cache > 0) { if (bytes_to_cache + cached_bytes >= sizeof(uint32_t)) { memcpy(&cached_data8[0], cur_buf, sizeof(uint32_t) - cached_bytes); cached_data32 = target_buffer_get_u32(target, cached_data8); /* write full word of cached bytes */ res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); if (res != ERROR_OK) return res; /* cache remaining bytes */ memset(cached_data8, 0x00, sizeof(cached_data8)); cur_buf += sizeof(uint32_t) - cached_bytes; cached_bytes = bytes_to_cache + cached_bytes - sizeof(uint32_t); memcpy(&cached_data8[0], cur_buf, cached_bytes); } else { memcpy(&cached_data8[cached_bytes], cur_buf, bytes_to_cache); cached_bytes += bytes_to_cache; } } } if (cached_bytes) { /* write remaining cached bytes */ cached_data32 = target_buffer_get_u32(target, cached_data8); res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); if (res != ERROR_OK) return res; } return ERROR_OK; } static int esp_xtensa_apptrace_buffs_write(struct target *target, uint32_t bufs_num, uint32_t buf_sz[], const uint8_t *bufs[], uint32_t block_id, bool ack, bool data) { struct xtensa *xtensa = target_to_xtensa(target); int res = ERROR_OK; uint32_t tmp = XTENSA_APPTRACE_HOST_CONNECT | (data ? XTENSA_APPTRACE_HOST_DATA : 0) | XTENSA_APPTRACE_BLOCK_ID(block_id) | XTENSA_APPTRACE_BLOCK_LEN(0); if (xtensa->core_config->trace.reversed_mem_access) res = esp_xtensa_apptrace_queue_reverse_write(target, bufs_num, buf_sz, bufs); else res = esp_xtensa_apptrace_queue_normal_write(target, bufs_num, buf_sz, bufs); if (res != ERROR_OK) return res; if (ack) { LOG_DEBUG("Ack block %" PRId32 " on target (%s)!", block_id, target_name(target)); res = xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp); if (res != ERROR_OK) return res; } xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_ERROR("Failed to exec JTAG queue!"); return res; } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp_xtensa_apptrace.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Xtensa application tracing module for OpenOCD * * Copyright (C) 2017 Espressif Systems Ltd. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESP_XTENSA_APPTRACE_H #define OPENOCD_TARGET_ESP_XTENSA_APPTRACE_H #include "esp32_apptrace.h" struct esp_xtensa_apptrace_info { const struct esp32_apptrace_hw *hw; }; extern struct esp32_apptrace_hw esp_xtensa_apptrace_hw; int esp_xtensa_apptrace_data_len_read(struct target *target, uint32_t *block_id, uint32_t *len); int esp_xtensa_apptrace_data_read(struct target *target, uint32_t size, uint8_t *buffer, uint32_t block_id, bool ack); int esp_xtensa_apptrace_ctrl_reg_read(struct target *target, uint32_t *block_id, uint32_t *len, bool *conn); int esp_xtensa_apptrace_ctrl_reg_write(struct target *target, uint32_t block_id, uint32_t len, bool conn, bool data); int esp_xtensa_apptrace_status_reg_write(struct target *target, uint32_t stat); int esp_xtensa_apptrace_status_reg_read(struct target *target, uint32_t *stat); uint32_t esp_xtensa_apptrace_block_max_size_get(struct target *target); uint32_t esp_xtensa_apptrace_usr_block_max_size_get(struct target *target); int esp_xtensa_apptrace_usr_block_write(struct target *target, uint32_t block_id, const uint8_t *data, uint32_t size); #endif /* OPENOCD_TARGET_ESP_XTENSA_APPTRACE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp_xtensa_semihosting.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (c) 2020 Espressif Systems (Shanghai) Co. Ltd. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <target/semihosting_common.h> #include <target/xtensa/xtensa_regs.h> #include <target/xtensa/xtensa.h> #include "esp_xtensa.h" #include "esp_xtensa_semihosting.h" #define ESP_XTENSA_SYSCALL 0x41E0 /* XT_INS_BREAK(1, 14) */ #define ESP_XTENSA_SYSCALL_SZ 3 #define XTENSA_SYSCALL_OP_REG XT_REG_IDX_A2 #define XTENSA_SYSCALL_RETVAL_REG XT_REG_IDX_A2 #define XTENSA_SYSCALL_ERRNO_REG XT_REG_IDX_A3 static int esp_xtensa_semihosting_setup(struct target *target, int enable) { LOG_TARGET_DEBUG(target, "semihosting enable=%d", enable); return ERROR_OK; } static int esp_xtensa_semihosting_post_result(struct target *target) { /* Even with the v2 and later, errno will not retrieved from A3 reg, it is safe to set */ xtensa_reg_set(target, XTENSA_SYSCALL_RETVAL_REG, target->semihosting->result); xtensa_reg_set(target, XTENSA_SYSCALL_ERRNO_REG, target->semihosting->sys_errno); return ERROR_OK; } /** * Checks and processes an ESP Xtensa semihosting request. This is meant * to be called when the target is stopped due to a debug mode entry. * If the value 0 is returned then there was nothing to process. A non-zero * return value signifies that a request was processed and the target resumed, * or an error was encountered, in which case the caller must return immediately. * * @param target Pointer to the ESP Xtensa target to process. * @param retval Pointer to a location where the return code will be stored * @return SEMIHOSTING_HANDLED if a request was processed or SEMIHOSTING_NONE with the proper retval */ int esp_xtensa_semihosting(struct target *target, int *retval) { struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); xtensa_reg_val_t dbg_cause = xtensa_reg_get(target, XT_REG_IDX_DEBUGCAUSE); if ((dbg_cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN)) == 0) return SEMIHOSTING_NONE; uint8_t brk_insn_buf[sizeof(uint32_t)] = { 0 }; xtensa_reg_val_t pc = xtensa_reg_get(target, XT_REG_IDX_PC); *retval = target_read_memory(target, pc, ESP_XTENSA_SYSCALL_SZ, 1, brk_insn_buf); if (*retval != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read break instruction!"); return SEMIHOSTING_NONE; } uint32_t syscall_ins = buf_get_u32(brk_insn_buf, 0, 32); if (syscall_ins != ESP_XTENSA_SYSCALL) { *retval = ERROR_OK; return SEMIHOSTING_NONE; } if (esp_xtensa->semihost.ops && esp_xtensa->semihost.ops->prepare) esp_xtensa->semihost.ops->prepare(target); xtensa_reg_val_t a2 = xtensa_reg_get(target, XT_REG_IDX_A2); xtensa_reg_val_t a3 = xtensa_reg_get(target, XT_REG_IDX_A3); LOG_TARGET_DEBUG(target, "Semihosting call 0x%" PRIx32 " 0x%" PRIx32 " Base dir '%s'", a2, a3, target->semihosting->basedir ? target->semihosting->basedir : ""); target->semihosting->op = a2; target->semihosting->param = a3; *retval = semihosting_common(target); /* Most operations are resumable, except the two exit calls. */ if (*retval != ERROR_OK) { LOG_TARGET_ERROR(target, "Semihosting operation (op: 0x%x) error! Code: %d", target->semihosting->op, *retval); } /* Resume if target it is resumable and we are not waiting on a fileio operation to complete. */ if (target->semihosting->is_resumable && !target->semihosting->hit_fileio) target_to_esp_xtensa(target)->semihost.need_resume = true; return SEMIHOSTING_HANDLED; } static int xtensa_semihosting_init(struct target *target) { return semihosting_common_init(target, esp_xtensa_semihosting_setup, esp_xtensa_semihosting_post_result); } int esp_xtensa_semihosting_init(struct target *target) { int retval = xtensa_semihosting_init(target); if (retval != ERROR_OK) return retval; target->semihosting->word_size_bytes = 4; /* 32 bits */ target->semihosting->user_command_extension = esp_semihosting_common; return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp_xtensa_semihosting.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (c) 2020 Espressif Systems (Shanghai) Co. Ltd. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESP_XTENSA_SEMIHOSTING_H #define OPENOCD_TARGET_ESP_XTENSA_SEMIHOSTING_H #include <target/target.h> int esp_xtensa_semihosting_init(struct target *target); int esp_xtensa_semihosting(struct target *target, int *retval); #endif /* OPENOCD_TARGET_ESP_XTENSA_SEMIHOSTING_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp_xtensa_smp.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * ESP Xtensa SMP target API for OpenOCD * * Copyright (C) 2020 Espressif Systems Ltd. Co * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "assert.h" #include <target/target.h> #include <target/target_type.h> #include <target/smp.h> #include <target/semihosting_common.h> #include "esp_xtensa_smp.h" #include "esp_xtensa_semihosting.h" /* Multiprocessor stuff common: The ESP Xtensa chip can have several cores in it, which can run in SMP-mode if an SMP-capable OS is running. The hardware has a few features which makes SMP debugging much easier. First of all, there's something called a 'break network', consisting of a BreakIn input and a BreakOut output on each CPU. The idea is that as soon as a CPU goes into debug mode for whatever reason, it'll signal that using its DebugOut pin. This signal is connected to the other CPU's DebugIn input, causing this CPU also to go into debugging mode. To resume execution when using only this break network, we will need to manually resume both CPUs. An alternative to this is the XOCDMode output and the RunStall (or DebugStall) input. When these are cross-connected, a CPU that goes into debug mode will halt execution entirely on the other CPU. Execution on the other CPU can be resumed by either the first CPU going out of debug mode, or the second CPU going into debug mode: the stall is temporarily lifted as long as the stalled CPU is in debug mode. A third, separate, signal is CrossTrigger. This is connected in the same way as the breakIn/breakOut network, but is for the TRAX (trace memory) feature; it does not affect OCD in any way. */ /* Multiprocessor stuff: The ESP Xtensa chip has several Xtensa cores inside, but represent themself to the OCD as one chip that works in multithreading mode under FreeRTOS OS. The core that initiate the stop condition will be defined as an active cpu. When one core stops, then other core will be stopped automatically by smpbreak. The core that initiates stop condition will be defined as an active core, and registers of this core will be transferred. */ #define ESP_XTENSA_SMP_EXAMINE_OTHER_CORES 5 static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume); static inline struct esp_xtensa_smp_common *target_to_esp_xtensa_smp(struct target *target) { return container_of(target->arch_info, struct esp_xtensa_smp_common, esp_xtensa); } int esp_xtensa_smp_assert_reset(struct target *target) { return ERROR_OK; } int esp_xtensa_smp_deassert_reset(struct target *target) { LOG_TARGET_DEBUG(target, "begin"); int ret = xtensa_deassert_reset(target); if (ret != ERROR_OK) return ret; /* in SMP mode when chip was running single-core app the other core can be left un-examined, because examination is done before SOC reset. But after SOC reset it is functional and should be handled. So try to examine un-examined core just after SOC reset */ if (target->smp && !target_was_examined(target)) ret = xtensa_examine(target); return ret; } int esp_xtensa_smp_soft_reset_halt(struct target *target) { int res; struct target_list *head; struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target); LOG_TARGET_DEBUG(target, "begin"); /* in SMP mode we need to ensure that at first we reset SOC on PRO-CPU and then call xtensa_assert_reset() for all cores */ if (target->smp && target->coreid != 0) return ERROR_OK; /* Reset the SoC first */ if (esp_xtensa_smp->chip_ops->reset) { res = esp_xtensa_smp->chip_ops->reset(target); if (res != ERROR_OK) return res; } if (!target->smp) return xtensa_assert_reset(target); foreach_smp_target(head, target->smp_targets) { res = xtensa_assert_reset(head->target); if (res != ERROR_OK) return res; } return ERROR_OK; } int esp_xtensa_smp_on_halt(struct target *target) { struct target_list *head; if (!target->smp) return esp_xtensa_on_halt(target); foreach_smp_target(head, target->smp_targets) { int res = esp_xtensa_on_halt(head->target); if (res != ERROR_OK) return res; } return ERROR_OK; } static struct target *get_halted_esp_xtensa_smp(struct target *target, int32_t coreid) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) return curr; } return target; } int esp_xtensa_smp_poll(struct target *target) { enum target_state old_state = target->state; struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target); struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); uint32_t old_dbg_stubs_base = esp_xtensa->esp.dbg_stubs.base; struct target_list *head; struct target *curr; bool other_core_resume_req = false; if (target->state == TARGET_HALTED && target->smp && target->gdb_service && !target->gdb_service->target) { target->gdb_service->target = get_halted_esp_xtensa_smp(target, target->gdb_service->core[1]); LOG_INFO("Switch GDB target to '%s'", target_name(target->gdb_service->target)); if (esp_xtensa_smp->chip_ops->on_halt) esp_xtensa_smp->chip_ops->on_halt(target); target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } int ret = esp_xtensa_poll(target); if (ret != ERROR_OK) return ret; if (esp_xtensa->esp.dbg_stubs.base && old_dbg_stubs_base != esp_xtensa->esp.dbg_stubs.base) { /* debug stubs base is set only in PRO-CPU TRAX register, so sync this info */ foreach_smp_target(head, target->smp_targets) { curr = head->target; if (curr == target) continue; target_to_esp_xtensa(curr)->esp.dbg_stubs.base = esp_xtensa->esp.dbg_stubs.base; } } if (target->smp) { if (target->state == TARGET_RESET) { esp_xtensa_smp->examine_other_cores = ESP_XTENSA_SMP_EXAMINE_OTHER_CORES; } else if (esp_xtensa_smp->examine_other_cores > 0 && (target->state == TARGET_RUNNING || target->state == TARGET_HALTED)) { LOG_TARGET_DEBUG(target, "Check for unexamined cores after reset"); bool all_examined = true; foreach_smp_target(head, target->smp_targets) { curr = head->target; if (curr == target) continue; if (!target_was_examined(curr)) { if (target_examine_one(curr) != ERROR_OK) { LOG_DEBUG("Failed to examine!"); all_examined = false; } } } if (all_examined) esp_xtensa_smp->examine_other_cores = 0; else esp_xtensa_smp->examine_other_cores--; } } if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) { if (target->smp) { ret = esp_xtensa_smp_update_halt_gdb(target, &other_core_resume_req); if (ret != ERROR_OK) return ret; } /* Call any event callbacks that are applicable */ if (old_state == TARGET_DEBUG_RUNNING) { target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } else { if (esp_xtensa_semihosting(target, &ret) == SEMIHOSTING_HANDLED) { if (ret == ERROR_OK && esp_xtensa->semihost.need_resume && !esp_xtensa_smp->other_core_does_resume) { esp_xtensa->semihost.need_resume = false; /* Resume xtensa_resume will handle BREAK instruction. */ ret = target_resume(target, 1, 0, 1, 0); if (ret != ERROR_OK) { LOG_ERROR("Failed to resume target"); return ret; } } return ret; } /* check whether any core polled by esp_xtensa_smp_update_halt_gdb() requested resume */ if (target->smp && other_core_resume_req) { /* Resume xtensa_resume will handle BREAK instruction. */ ret = target_resume(target, 1, 0, 1, 0); if (ret != ERROR_OK) { LOG_ERROR("Failed to resume target"); return ret; } return ERROR_OK; } if (esp_xtensa_smp->chip_ops->on_halt) esp_xtensa_smp->chip_ops->on_halt(target); target_call_event_callbacks(target, TARGET_EVENT_HALTED); } } return ERROR_OK; } static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume) { struct esp_xtensa_smp_common *esp_xtensa_smp; struct target *gdb_target = NULL; struct target_list *head; struct target *curr; int ret = ERROR_OK; *need_resume = false; if (target->gdb_service && target->gdb_service->target) LOG_DEBUG("GDB target '%s'", target_name(target->gdb_service->target)); if (target->gdb_service && target->gdb_service->core[0] == -1) { target->gdb_service->target = target; target->gdb_service->core[0] = target->coreid; LOG_INFO("Set GDB target to '%s'", target_name(target)); } if (target->gdb_service) gdb_target = target->gdb_service->target; /* due to smpbreak config other cores can also go to HALTED state */ foreach_smp_target(head, target->smp_targets) { curr = head->target; LOG_DEBUG("Check target '%s'", target_name(curr)); /* skip calling context */ if (curr == target) continue; if (!target_was_examined(curr)) { curr->state = TARGET_HALTED; continue; } /* skip targets that were already halted */ if (curr->state == TARGET_HALTED) continue; /* Skip gdb_target; it alerts GDB so has to be polled as last one */ if (curr == gdb_target) continue; LOG_DEBUG("Poll target '%s'", target_name(curr)); esp_xtensa_smp = target_to_esp_xtensa_smp(curr); /* avoid auto-resume after syscall, it will be done later */ esp_xtensa_smp->other_core_does_resume = true; /* avoid recursion in esp_xtensa_smp_poll() */ curr->smp = 0; if (esp_xtensa_smp->chip_ops->poll) ret = esp_xtensa_smp->chip_ops->poll(curr); else ret = esp_xtensa_smp_poll(curr); curr->smp = 1; if (ret != ERROR_OK) return ret; esp_xtensa_smp->other_core_does_resume = false; struct esp_xtensa_common *curr_esp_xtensa = target_to_esp_xtensa(curr); if (curr_esp_xtensa->semihost.need_resume) { curr_esp_xtensa->semihost.need_resume = false; *need_resume = true; } } /* after all targets were updated, poll the gdb serving target */ if (gdb_target && gdb_target != target) { esp_xtensa_smp = target_to_esp_xtensa_smp(gdb_target); if (esp_xtensa_smp->chip_ops->poll) ret = esp_xtensa_smp->chip_ops->poll(gdb_target); else ret = esp_xtensa_smp_poll(gdb_target); } LOG_DEBUG("exit"); return ret; } static inline int esp_xtensa_smp_smpbreak_disable(struct target *target, uint32_t *smp_break) { int res = xtensa_smpbreak_get(target, smp_break); if (res != ERROR_OK) return res; return xtensa_smpbreak_set(target, 0); } static inline int esp_xtensa_smp_smpbreak_restore(struct target *target, uint32_t smp_break) { return xtensa_smpbreak_set(target, smp_break); } static int esp_xtensa_smp_resume_cores(struct target *target, int handle_breakpoints, int debug_execution) { struct target_list *head; struct target *curr; LOG_TARGET_DEBUG(target, "begin"); foreach_smp_target(head, target->smp_targets) { curr = head->target; /* in single-core mode disabled core cannot be examined, but need to be resumed too*/ if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) { /* resume current address, not in SMP mode */ curr->smp = 0; int res = esp_xtensa_smp_resume(curr, 1, 0, handle_breakpoints, debug_execution); curr->smp = 1; if (res != ERROR_OK) return res; } } return ERROR_OK; } int esp_xtensa_smp_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { int res; uint32_t smp_break; xtensa_smpbreak_get(target, &smp_break); LOG_TARGET_DEBUG(target, "smp_break=0x%" PRIx32, smp_break); /* dummy resume for smp toggle in order to reduce gdb impact */ if ((target->smp) && (target->gdb_service) && (target->gdb_service->core[1] != -1)) { /* simulate a start and halt of target */ target->gdb_service->target = NULL; target->gdb_service->core[0] = target->gdb_service->core[1]; /* fake resume at next poll we play the target core[1], see poll*/ LOG_TARGET_DEBUG(target, "Fake resume"); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); return ERROR_OK; } /* xtensa_prepare_resume() can step over breakpoint/watchpoint and generate signals on BreakInOut circuit for * other cores. So disconnect this core from BreakInOut circuit and do xtensa_prepare_resume(). */ res = esp_xtensa_smp_smpbreak_disable(target, &smp_break); if (res != ERROR_OK) return res; res = xtensa_prepare_resume(target, current, address, handle_breakpoints, debug_execution); /* restore configured BreakInOut signals config */ int ret = esp_xtensa_smp_smpbreak_restore(target, smp_break); if (ret != ERROR_OK) return ret; if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to prepare for resume!"); return res; } if (target->smp) { if (target->gdb_service) target->gdb_service->core[0] = -1; res = esp_xtensa_smp_resume_cores(target, handle_breakpoints, debug_execution); if (res != ERROR_OK) return res; } res = xtensa_do_resume(target); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to resume!"); return res; } target->debug_reason = DBG_REASON_NOTHALTED; if (!debug_execution) target->state = TARGET_RUNNING; else target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); return ERROR_OK; } int esp_xtensa_smp_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { int res; uint32_t smp_break = 0; struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target); if (target->smp) { res = esp_xtensa_smp_smpbreak_disable(target, &smp_break); if (res != ERROR_OK) return res; } res = xtensa_step(target, current, address, handle_breakpoints); if (res == ERROR_OK) { if (esp_xtensa_smp->chip_ops->on_halt) esp_xtensa_smp->chip_ops->on_halt(target); target_call_event_callbacks(target, TARGET_EVENT_HALTED); } if (target->smp) { int ret = esp_xtensa_smp_smpbreak_restore(target, smp_break); if (ret != ERROR_OK) return ret; } return res; } int esp_xtensa_smp_watchpoint_add(struct target *target, struct watchpoint *watchpoint) { int res = xtensa_watchpoint_add(target, watchpoint); if (res != ERROR_OK) return res; if (!target->smp) return ERROR_OK; struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (curr == target || !target_was_examined(curr)) continue; /* Need to use high level API here because every target for core contains list of watchpoints. * GDB works with active core only, so we need to duplicate every watchpoint on other cores, * otherwise watchpoint_free() on active core can fail if WP has been initially added on another core. */ curr->smp = 0; res = watchpoint_add(curr, watchpoint->address, watchpoint->length, watchpoint->rw, watchpoint->value, watchpoint->mask); curr->smp = 1; if (res != ERROR_OK) return res; } return ERROR_OK; } int esp_xtensa_smp_watchpoint_remove(struct target *target, struct watchpoint *watchpoint) { int res = xtensa_watchpoint_remove(target, watchpoint); if (res != ERROR_OK) return res; if (!target->smp) return ERROR_OK; struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (curr == target) continue; /* see big comment in esp_xtensa_smp_watchpoint_add() */ curr->smp = 0; watchpoint_remove(curr, watchpoint->address); curr->smp = 1; } return ERROR_OK; } int esp_xtensa_smp_init_arch_info(struct target *target, struct esp_xtensa_smp_common *esp_xtensa_smp, struct xtensa_debug_module_config *dm_cfg, const struct esp_xtensa_smp_chip_ops *chip_ops, const struct esp_semihost_ops *semihost_ops) { int ret = esp_xtensa_init_arch_info(target, &esp_xtensa_smp->esp_xtensa, dm_cfg, semihost_ops); if (ret != ERROR_OK) return ret; esp_xtensa_smp->chip_ops = chip_ops; esp_xtensa_smp->examine_other_cores = ESP_XTENSA_SMP_EXAMINE_OTHER_CORES; return ERROR_OK; } int esp_xtensa_smp_target_init(struct command_context *cmd_ctx, struct target *target) { int ret = esp_xtensa_target_init(cmd_ctx, target); if (ret != ERROR_OK) return ret; if (target->smp) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; ret = esp_xtensa_semihosting_init(curr); if (ret != ERROR_OK) return ret; } } else { ret = esp_xtensa_semihosting_init(target); if (ret != ERROR_OK) return ret; } return ERROR_OK; } COMMAND_HANDLER(esp_xtensa_smp_cmd_xtdef) { struct target *target = get_current_target(CMD_CTX); if (target->smp && CMD_ARGC > 0) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do, target_to_xtensa(curr)); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do, target_to_xtensa(target)); } COMMAND_HANDLER(esp_xtensa_smp_cmd_xtopt) { struct target *target = get_current_target(CMD_CTX); if (target->smp && CMD_ARGC > 0) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do, target_to_xtensa(curr)); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do, target_to_xtensa(target)); } COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmem) { struct target *target = get_current_target(CMD_CTX); if (target->smp && CMD_ARGC > 0) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do, target_to_xtensa(curr)); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do, target_to_xtensa(target)); } COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmpu) { struct target *target = get_current_target(CMD_CTX); if (target->smp && CMD_ARGC > 0) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do, target_to_xtensa(curr)); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do, target_to_xtensa(target)); } COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmmu) { struct target *target = get_current_target(CMD_CTX); if (target->smp && CMD_ARGC > 0) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do, target_to_xtensa(curr)); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do, target_to_xtensa(target)); } COMMAND_HANDLER(esp_xtensa_smp_cmd_xtreg) { struct target *target = get_current_target(CMD_CTX); if (target->smp && CMD_ARGC > 0) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do, target_to_xtensa(curr)); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do, target_to_xtensa(target)); } COMMAND_HANDLER(esp_xtensa_smp_cmd_xtregfmt) { struct target *target = get_current_target(CMD_CTX); if (target->smp && CMD_ARGC > 0) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do, target_to_xtensa(curr)); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do, target_to_xtensa(target)); } COMMAND_HANDLER(esp_xtensa_smp_cmd_permissive_mode) { struct target *target = get_current_target(CMD_CTX); if (target->smp && CMD_ARGC > 0) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do, target_to_xtensa(curr)); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do, target_to_xtensa(target)); } COMMAND_HANDLER(esp_xtensa_smp_cmd_smpbreak) { struct target *target = get_current_target(CMD_CTX); if (target->smp && CMD_ARGC > 0) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, curr); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, target); } COMMAND_HANDLER(esp_xtensa_smp_cmd_mask_interrupts) { struct target *target = get_current_target(CMD_CTX); if (target->smp && CMD_ARGC > 0) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do, target_to_xtensa(curr)); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do, target_to_xtensa(target)); } COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_enable) { struct target *target = get_current_target(CMD_CTX); if (target->smp && CMD_ARGC > 0) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do, target_to_xtensa(curr)); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do, target_to_xtensa(target)); } COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_dump) { struct target *target = get_current_target(CMD_CTX); if (target->smp) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; LOG_INFO("CPU%d:", curr->coreid); int ret = CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do, target_to_xtensa(curr)); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do, target_to_xtensa(target)); } COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestart) { struct target *target = get_current_target(CMD_CTX); if (target->smp) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do, target_to_xtensa(curr)); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do, target_to_xtensa(target)); } COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestop) { struct target *target = get_current_target(CMD_CTX); if (target->smp) { struct target_list *head; struct target *curr; foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do, target_to_xtensa(curr)); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do, target_to_xtensa(target)); } COMMAND_HANDLER(esp_xtensa_smp_cmd_tracedump) { struct target *target = get_current_target(CMD_CTX); if (target->smp) { struct target_list *head; struct target *curr; int32_t cores_max_id = 0; /* assume that core IDs are assigned to SMP targets sequentially: 0,1,2... */ foreach_smp_target(head, target->smp_targets) { curr = head->target; if (cores_max_id < curr->coreid) cores_max_id = curr->coreid; } if (CMD_ARGC < ((uint32_t)cores_max_id + 1)) { command_print(CMD, "Need %d filenames to dump to as output!", cores_max_id + 1); return ERROR_FAIL; } foreach_smp_target(head, target->smp_targets) { curr = head->target; int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do, target_to_xtensa(curr), CMD_ARGV[curr->coreid]); if (ret != ERROR_OK) return ret; } return ERROR_OK; } return CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do, target_to_xtensa(target), CMD_ARGV[0]); } const struct command_registration esp_xtensa_smp_xtensa_command_handlers[] = { { .name = "xtdef", .handler = esp_xtensa_smp_cmd_xtdef, .mode = COMMAND_CONFIG, .help = "Configure Xtensa core type", .usage = "<type>", }, { .name = "xtopt", .handler = esp_xtensa_smp_cmd_xtopt, .mode = COMMAND_CONFIG, .help = "Configure Xtensa core option", .usage = "<name> <value>", }, { .name = "xtmem", .handler = esp_xtensa_smp_cmd_xtmem, .mode = COMMAND_CONFIG, .help = "Configure Xtensa memory/cache option", .usage = "<type> [parameters]", }, { .name = "xtmmu", .handler = esp_xtensa_smp_cmd_xtmmu, .mode = COMMAND_CONFIG, .help = "Configure Xtensa MMU option", .usage = "<NIREFILLENTRIES> <NDREFILLENTRIES> <IVARWAY56> <DVARWAY56>", }, { .name = "xtmpu", .handler = esp_xtensa_smp_cmd_xtmpu, .mode = COMMAND_CONFIG, .help = "Configure Xtensa MPU option", .usage = "<num FG seg> <min seg size> <lockable> <executeonly>", }, { .name = "xtreg", .handler = esp_xtensa_smp_cmd_xtreg, .mode = COMMAND_CONFIG, .help = "Configure Xtensa register", .usage = "<regname> <regnum>", }, { .name = "xtregs", .handler = esp_xtensa_smp_cmd_xtreg, .mode = COMMAND_CONFIG, .help = "Configure number of Xtensa registers", .usage = "<numregs>", }, { .name = "xtregfmt", .handler = esp_xtensa_smp_cmd_xtregfmt, .mode = COMMAND_CONFIG, .help = "Configure format of Xtensa register map", .usage = "<numgregs>", }, { .name = "set_permissive", .handler = esp_xtensa_smp_cmd_permissive_mode, .mode = COMMAND_ANY, .help = "When set to 1, enable Xtensa permissive mode (less client-side checks)", .usage = "[0|1]", }, { .name = "maskisr", .handler = esp_xtensa_smp_cmd_mask_interrupts, .mode = COMMAND_ANY, .help = "mask Xtensa interrupts at step", .usage = "['on'|'off']", }, { .name = "smpbreak", .handler = esp_xtensa_smp_cmd_smpbreak, .mode = COMMAND_ANY, .help = "Set the way the CPU chains OCD breaks", .usage = "[none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]", }, { .name = "perfmon_enable", .handler = esp_xtensa_smp_cmd_perfmon_enable, .mode = COMMAND_EXEC, .help = "Enable and start performance counter", .usage = "<counter_id> <select> [mask] [kernelcnt] [tracelevel]", }, { .name = "perfmon_dump", .handler = esp_xtensa_smp_cmd_perfmon_dump, .mode = COMMAND_EXEC, .help = "Dump performance counter value. If no argument specified, dumps all counters.", .usage = "[counter_id]", }, { .name = "tracestart", .handler = esp_xtensa_smp_cmd_tracestart, .mode = COMMAND_EXEC, .help = "Tracing: Set up and start a trace. Optionally set stop trigger address and amount of data captured after.", .usage = "[pc <pcval>/[maskbitcount]] [after <n> [ins|words]]", }, { .name = "tracestop", .handler = esp_xtensa_smp_cmd_tracestop, .mode = COMMAND_EXEC, .help = "Tracing: Stop current trace as started by the tracestart command", .usage = "", }, { .name = "tracedump", .handler = esp_xtensa_smp_cmd_tracedump, .mode = COMMAND_EXEC, .help = "Tracing: Dump trace memory to a files. One file per core.", .usage = "<outfile1> <outfile2>", }, COMMAND_REGISTRATION_DONE }; const struct command_registration esp_xtensa_smp_command_handlers[] = { { .name = "xtensa", .usage = "", .chain = esp_xtensa_smp_xtensa_command_handlers, }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/esp_xtensa_smp.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * ESP Xtensa SMP target for OpenOCD * * Copyright (C) 2020 Espressif Systems Ltd. Co * ***************************************************************************/ #ifndef OPENOCD_TARGET_XTENSA_ESP_SMP_H #define OPENOCD_TARGET_XTENSA_ESP_SMP_H #include "esp_xtensa.h" struct esp_xtensa_smp_chip_ops { int (*poll)(struct target *target); int (*reset)(struct target *target); int (*on_halt)(struct target *target); }; struct esp_xtensa_smp_common { struct esp_xtensa_common esp_xtensa; const struct esp_xtensa_smp_chip_ops *chip_ops; bool other_core_does_resume; /* number of attempts to examine other SMP cores, attempts are made after reset on target poll */ int examine_other_cores; }; int esp_xtensa_smp_poll(struct target *target); int esp_xtensa_smp_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); int esp_xtensa_smp_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); int esp_xtensa_smp_assert_reset(struct target *target); int esp_xtensa_smp_deassert_reset(struct target *target); int esp_xtensa_smp_soft_reset_halt(struct target *target); int esp_xtensa_smp_on_halt(struct target *target); int esp_xtensa_smp_watchpoint_add(struct target *target, struct watchpoint *watchpoint); int esp_xtensa_smp_watchpoint_remove(struct target *target, struct watchpoint *watchpoint); int esp_xtensa_smp_handle_target_event(struct target *target, enum target_event event, void *priv); int esp_xtensa_smp_target_init(struct command_context *cmd_ctx, struct target *target); int esp_xtensa_smp_init_arch_info(struct target *target, struct esp_xtensa_smp_common *esp_xtensa_smp, struct xtensa_debug_module_config *dm_cfg, const struct esp_xtensa_smp_chip_ops *chip_ops, const struct esp_semihost_ops *semihost_ops); extern const struct command_registration esp_xtensa_smp_command_handlers[]; extern const struct command_registration esp_xtensa_smp_xtensa_command_handlers[]; extern const struct command_registration esp_xtensa_smp_esp_command_handlers[]; #endif /* OPENOCD_TARGET_XTENSA_ESP_SMP_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/espressif/segger_sysview.h ================================================ /* SPDX-License-Identifier: BSD-1-Clause */ /* SPDX-FileCopyrightText: (c) 1995-2021 SEGGER Microcontroller GmbH. All rights reserved. */ /* SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD */ /* * The contend below is extracted from files SEGGER_SYSVIEW.h and SEGGER_SYSVIEW_Int.h in: * https://www.segger.com/downloads/systemview/systemview_target_src * SystemView version: 3.42 */ #ifndef OPENOCD_TARGET_SEGGER_SYSVIEW_H #define OPENOCD_TARGET_SEGGER_SYSVIEW_H #define SYSVIEW_EVTID_NOP 0 /* Dummy packet. */ #define SYSVIEW_EVTID_OVERFLOW 1 #define SYSVIEW_EVTID_ISR_ENTER 2 #define SYSVIEW_EVTID_ISR_EXIT 3 #define SYSVIEW_EVTID_TASK_START_EXEC 4 #define SYSVIEW_EVTID_TASK_STOP_EXEC 5 #define SYSVIEW_EVTID_TASK_START_READY 6 #define SYSVIEW_EVTID_TASK_STOP_READY 7 #define SYSVIEW_EVTID_TASK_CREATE 8 #define SYSVIEW_EVTID_TASK_INFO 9 #define SYSVIEW_EVTID_TRACE_START 10 #define SYSVIEW_EVTID_TRACE_STOP 11 #define SYSVIEW_EVTID_SYSTIME_CYCLES 12 #define SYSVIEW_EVTID_SYSTIME_US 13 #define SYSVIEW_EVTID_SYSDESC 14 #define SYSVIEW_EVTID_USER_START 15 #define SYSVIEW_EVTID_USER_STOP 16 #define SYSVIEW_EVTID_IDLE 17 #define SYSVIEW_EVTID_ISR_TO_SCHEDULER 18 #define SYSVIEW_EVTID_TIMER_ENTER 19 #define SYSVIEW_EVTID_TIMER_EXIT 20 #define SYSVIEW_EVTID_STACK_INFO 21 #define SYSVIEW_EVTID_MODULEDESC 22 #define SYSVIEW_EVTID_INIT 24 #define SYSVIEW_EVTID_NAME_RESOURCE 25 #define SYSVIEW_EVTID_PRINT_FORMATTED 26 #define SYSVIEW_EVTID_NUMMODULES 27 #define SYSVIEW_EVTID_END_CALL 28 #define SYSVIEW_EVTID_TASK_TERMINATE 29 #define SYSVIEW_EVTID_EX 31 // // SystemView extended events. Sent with ID 31. // #define SYSVIEW_EVTID_EX_MARK 0 #define SYSVIEW_EVTID_EX_NAME_MARKER 1 #define SYSVIEW_EVTID_EX_HEAP_DEFINE 2 #define SYSVIEW_EVTID_EX_HEAP_ALLOC 3 #define SYSVIEW_EVTID_EX_HEAP_ALLOC_EX 4 #define SYSVIEW_EVTID_EX_HEAP_FREE 5 #define SYSVIEW_SYNC_LEN 10 #define SYSVIEW_EVENT_ID_MAX (200) // // Commands that Host can send to target // enum { SEGGER_SYSVIEW_COMMAND_ID_START = 1, SEGGER_SYSVIEW_COMMAND_ID_STOP, SEGGER_SYSVIEW_COMMAND_ID_GET_SYSTIME, SEGGER_SYSVIEW_COMMAND_ID_GET_TASKLIST, SEGGER_SYSVIEW_COMMAND_ID_GET_SYSDESC, SEGGER_SYSVIEW_COMMAND_ID_GET_NUMMODULES, SEGGER_SYSVIEW_COMMAND_ID_GET_MODULEDESC, SEGGER_SYSVIEW_COMMAND_ID_HEARTBEAT = 127, // Extended commands: Commands >= 128 have a second parameter SEGGER_SYSVIEW_COMMAND_ID_GET_MODULE = 128 }; /* Minimum compatible SEGGER SystemView tool version */ #define SYSVIEW_MIN_VER_STRING "SEGGER SystemViewer V2.42" #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/etb.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "etm.h" #include "etb.h" #include "register.h" static const char * const etb_reg_list[] = { "ETB_identification", "ETB_ram_depth", "ETB_ram_width", "ETB_status", "ETB_ram_data", "ETB_ram_read_pointer", "ETB_ram_write_pointer", "ETB_trigger_counter", "ETB_control", }; static int etb_get_reg(struct reg *reg); static int etb_set_instr(struct etb *etb, uint32_t new_instr) { struct jtag_tap *tap; tap = etb->tap; if (!tap) return ERROR_FAIL; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; field.num_bits = tap->ir_length; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); free(t); } return ERROR_OK; } static int etb_scann(struct etb *etb, uint32_t new_scan_chain) { if (etb->cur_scan_chain != new_scan_chain) { struct scan_field field; field.num_bits = 5; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_scan_chain); field.in_value = NULL; /* select INTEST instruction */ etb_set_instr(etb, 0x2); jtag_add_dr_scan(etb->tap, 1, &field, TAP_IDLE); etb->cur_scan_chain = new_scan_chain; free(t); } return ERROR_OK; } static int etb_read_reg_w_check(struct reg *, uint8_t *, uint8_t *); static int etb_set_reg_w_exec(struct reg *, uint8_t *); static int etb_read_reg(struct reg *reg) { return etb_read_reg_w_check(reg, NULL, NULL); } static int etb_get_reg(struct reg *reg) { int retval; retval = etb_read_reg(reg); if (retval != ERROR_OK) { LOG_ERROR("BUG: error scheduling ETB register read"); return retval; } retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("ETB register read failed"); return retval; } return ERROR_OK; } static const struct reg_arch_type etb_reg_type = { .get = etb_get_reg, .set = etb_set_reg_w_exec, }; struct reg_cache *etb_build_reg_cache(struct etb *etb) { struct reg_cache *reg_cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = NULL; struct etb_reg *arch_info = NULL; int num_regs = 9; int i; /* the actual registers are kept in two arrays */ reg_list = calloc(num_regs, sizeof(struct reg)); arch_info = calloc(num_regs, sizeof(struct etb_reg)); /* fill in values for the reg cache */ reg_cache->name = "etb registers"; reg_cache->next = NULL; reg_cache->reg_list = reg_list; reg_cache->num_regs = num_regs; /* set up registers */ for (i = 0; i < num_regs; i++) { reg_list[i].name = etb_reg_list[i]; reg_list[i].size = 32; reg_list[i].dirty = false; reg_list[i].valid = false; reg_list[i].value = calloc(1, 4); reg_list[i].arch_info = &arch_info[i]; reg_list[i].type = &etb_reg_type; reg_list[i].size = 32; arch_info[i].addr = i; arch_info[i].etb = etb; } return reg_cache; } static void etb_getbuf(jtag_callback_data_t arg) { uint8_t *in = (uint8_t *)arg; *((uint32_t *)arg) = buf_get_u32(in, 0, 32); } static int etb_read_ram(struct etb *etb, uint32_t *data, int num_frames) { struct scan_field fields[3]; int i; etb_scann(etb, 0x0); etb_set_instr(etb, 0xc); fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = NULL; fields[1].num_bits = 7; uint8_t temp1 = 0; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, 4); fields[1].in_value = NULL; fields[2].num_bits = 1; uint8_t temp2 = 0; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 0); fields[2].in_value = NULL; jtag_add_dr_scan(etb->tap, 3, fields, TAP_IDLE); for (i = 0; i < num_frames; i++) { /* ensure nR/W remains set to read */ buf_set_u32(&temp2, 0, 1, 0); /* address remains set to 0x4 (RAM data) until we read the last frame */ if (i < num_frames - 1) buf_set_u32(&temp1, 0, 7, 4); else buf_set_u32(&temp1, 0, 7, 0); fields[0].in_value = (uint8_t *)(data + i); jtag_add_dr_scan(etb->tap, 3, fields, TAP_IDLE); jtag_add_callback(etb_getbuf, (jtag_callback_data_t)(data + i)); } jtag_execute_queue(); return ERROR_OK; } static int etb_read_reg_w_check(struct reg *reg, uint8_t *check_value, uint8_t *check_mask) { struct etb_reg *etb_reg = reg->arch_info; uint8_t reg_addr = etb_reg->addr & 0x7f; struct scan_field fields[3]; LOG_DEBUG("%i", (int)(etb_reg->addr)); etb_scann(etb_reg->etb, 0x0); etb_set_instr(etb_reg->etb, 0xc); fields[0].num_bits = 32; fields[0].out_value = reg->value; fields[0].in_value = NULL; fields[0].check_value = NULL; fields[0].check_mask = NULL; fields[1].num_bits = 7; uint8_t temp1 = 0; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, reg_addr); fields[1].in_value = NULL; fields[1].check_value = NULL; fields[1].check_mask = NULL; fields[2].num_bits = 1; uint8_t temp2 = 0; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 0); fields[2].in_value = NULL; fields[2].check_value = NULL; fields[2].check_mask = NULL; jtag_add_dr_scan(etb_reg->etb->tap, 3, fields, TAP_IDLE); /* read the identification register in the second run, to make sure we * don't read the ETB data register twice, skipping every second entry */ buf_set_u32(&temp1, 0, 7, 0x0); fields[0].in_value = reg->value; fields[0].check_value = check_value; fields[0].check_mask = check_mask; jtag_add_dr_scan_check(etb_reg->etb->tap, 3, fields, TAP_IDLE); return ERROR_OK; } static int etb_write_reg(struct reg *, uint32_t); static int etb_set_reg(struct reg *reg, uint32_t value) { int retval; retval = etb_write_reg(reg, value); if (retval != ERROR_OK) { LOG_ERROR("BUG: error scheduling ETB register write"); return retval; } buf_set_u32(reg->value, 0, reg->size, value); reg->valid = true; reg->dirty = false; return ERROR_OK; } static int etb_set_reg_w_exec(struct reg *reg, uint8_t *buf) { int retval; etb_set_reg(reg, buf_get_u32(buf, 0, reg->size)); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("ETB: register write failed"); return retval; } return ERROR_OK; } static int etb_write_reg(struct reg *reg, uint32_t value) { struct etb_reg *etb_reg = reg->arch_info; uint8_t reg_addr = etb_reg->addr & 0x7f; struct scan_field fields[3]; LOG_DEBUG("%i: 0x%8.8" PRIx32 "", (int)(etb_reg->addr), value); etb_scann(etb_reg->etb, 0x0); etb_set_instr(etb_reg->etb, 0xc); fields[0].num_bits = 32; uint8_t temp0[4]; fields[0].out_value = temp0; buf_set_u32(temp0, 0, 32, value); fields[0].in_value = NULL; fields[1].num_bits = 7; uint8_t temp1 = 0; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, reg_addr); fields[1].in_value = NULL; fields[2].num_bits = 1; uint8_t temp2 = 0; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 1); fields[2].in_value = NULL; jtag_add_dr_scan(etb_reg->etb->tap, 3, fields, TAP_IDLE); return ERROR_OK; } COMMAND_HANDLER(handle_etb_config_command) { struct target *target; struct jtag_tap *tap; struct arm *arm; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; target = get_target(CMD_ARGV[0]); if (!target) { LOG_ERROR("ETB: target '%s' not defined", CMD_ARGV[0]); return ERROR_FAIL; } arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "ETB: '%s' isn't an ARM", CMD_ARGV[0]); return ERROR_FAIL; } tap = jtag_tap_by_string(CMD_ARGV[1]); if (!tap) { command_print(CMD, "ETB: TAP %s does not exist", CMD_ARGV[1]); return ERROR_FAIL; } if (arm->etm) { struct etb *etb = malloc(sizeof(struct etb)); arm->etm->capture_driver_priv = etb; etb->tap = tap; etb->cur_scan_chain = 0xffffffff; etb->reg_cache = NULL; etb->ram_width = 0; etb->ram_depth = 0; } else { LOG_ERROR("ETM: target has no ETM defined, ETB left unconfigured"); return ERROR_FAIL; } return ERROR_OK; } COMMAND_HANDLER(handle_etb_trigger_percent_command) { struct target *target; struct arm *arm; struct etm_context *etm; struct etb *etb; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "ETB: current target isn't an ARM"); return ERROR_FAIL; } etm = arm->etm; if (!etm) { command_print(CMD, "ETB: target has no ETM configured"); return ERROR_FAIL; } if (etm->capture_driver != &etb_capture_driver) { command_print(CMD, "ETB: target not using ETB"); return ERROR_FAIL; } etb = arm->etm->capture_driver_priv; if (CMD_ARGC > 0) { uint32_t new_value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], new_value); if ((new_value < 2) || (new_value > 100)) command_print(CMD, "valid percentages are 2%% to 100%%"); else etb->trigger_percent = (unsigned) new_value; } command_print(CMD, "%d percent of tracebuffer fills after trigger", etb->trigger_percent); return ERROR_OK; } static const struct command_registration etb_config_command_handlers[] = { { /* NOTE: with ADIv5, ETBs are accessed using DAP operations, * possibly over SWD, not through separate TAPs... */ .name = "config", .handler = handle_etb_config_command, .mode = COMMAND_CONFIG, .help = "Associate ETB with target and JTAG TAP.", .usage = "target tap", }, { .name = "trigger_percent", .handler = handle_etb_trigger_percent_command, .mode = COMMAND_EXEC, .help = "Set percent of trace buffer to be filled " "after the trigger occurs (2..100).", .usage = "[percent]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration etb_command_handlers[] = { { .name = "etb", .mode = COMMAND_ANY, .help = "Embedded Trace Buffer command group", .chain = etb_config_command_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static int etb_init(struct etm_context *etm_ctx) { struct etb *etb = etm_ctx->capture_driver_priv; etb->etm_ctx = etm_ctx; /* identify ETB RAM depth and width */ etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_DEPTH]); etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WIDTH]); jtag_execute_queue(); etb->ram_depth = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32); etb->ram_width = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32); etb->trigger_percent = 50; return ERROR_OK; } static trace_status_t etb_status(struct etm_context *etm_ctx) { struct etb *etb = etm_ctx->capture_driver_priv; struct reg *control = &etb->reg_cache->reg_list[ETB_CTRL]; struct reg *status = &etb->reg_cache->reg_list[ETB_STATUS]; trace_status_t retval = 0; int etb_timeout = 100; etb->etm_ctx = etm_ctx; /* read control and status registers */ etb_read_reg(control); etb_read_reg(status); jtag_execute_queue(); /* See if it's (still) active */ retval = buf_get_u32(control->value, 0, 1) ? TRACE_RUNNING : TRACE_IDLE; /* check Full bit to identify wraparound/overflow */ if (buf_get_u32(status->value, 0, 1) == 1) retval |= TRACE_OVERFLOWED; /* check Triggered bit to identify trigger condition */ if (buf_get_u32(status->value, 1, 1) == 1) retval |= TRACE_TRIGGERED; /* check AcqComp to see if trigger counter dropped to zero */ if (buf_get_u32(status->value, 2, 1) == 1) { /* wait for DFEmpty */ while (etb_timeout-- && buf_get_u32(status->value, 3, 1) == 0) etb_get_reg(status); if (etb_timeout == 0) LOG_ERROR("ETB: DFEmpty won't go high, status 0x%02x", (unsigned) buf_get_u32(status->value, 0, 4)); if (!(etm_ctx->capture_status & TRACE_TRIGGERED)) LOG_WARNING("ETB: trace complete without triggering?"); retval |= TRACE_COMPLETED; } /* NOTE: using a trigger is optional; and at least ETB11 has a mode * where it can ignore the trigger counter. */ /* update recorded state */ etm_ctx->capture_status = retval; return retval; } static int etb_read_trace(struct etm_context *etm_ctx) { struct etb *etb = etm_ctx->capture_driver_priv; int first_frame = 0; int num_frames = etb->ram_depth; uint32_t *trace_data = NULL; int i, j; etb_read_reg(&etb->reg_cache->reg_list[ETB_STATUS]); etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]); jtag_execute_queue(); /* check if we overflowed, and adjust first frame of the trace accordingly * if we didn't overflow, read only up to the frame that would be written next, * i.e. don't read invalid entries */ if (buf_get_u32(etb->reg_cache->reg_list[ETB_STATUS].value, 0, 1)) first_frame = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); else num_frames = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame); /* read data into temporary array for unpacking */ trace_data = malloc(sizeof(uint32_t) * num_frames); etb_read_ram(etb, trace_data, num_frames); if (etm_ctx->trace_depth > 0) free(etm_ctx->trace_data); if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) etm_ctx->trace_depth = num_frames * 3; else if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) etm_ctx->trace_depth = num_frames * 2; else etm_ctx->trace_depth = num_frames; etm_ctx->trace_data = malloc(sizeof(struct etmv1_trace_data) * etm_ctx->trace_depth); for (i = 0, j = 0; i < num_frames; i++) { if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) { /* trace word j */ etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; etm_ctx->trace_data[j].packet = (trace_data[i] & 0x78) >> 3; etm_ctx->trace_data[j].flags = 0; if ((trace_data[i] & 0x80) >> 7) etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; if (etm_ctx->trace_data[j].pipestat == STAT_TR) { etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; } /* trace word j + 1 */ etm_ctx->trace_data[j + 1].pipestat = (trace_data[i] & 0x100) >> 8; etm_ctx->trace_data[j + 1].packet = (trace_data[i] & 0x7800) >> 11; etm_ctx->trace_data[j + 1].flags = 0; if ((trace_data[i] & 0x8000) >> 15) etm_ctx->trace_data[j + 1].flags |= ETMV1_TRACESYNC_CYCLE; if (etm_ctx->trace_data[j + 1].pipestat == STAT_TR) { etm_ctx->trace_data[j + 1].pipestat = etm_ctx->trace_data[j + 1].packet & 0x7; etm_ctx->trace_data[j + 1].flags |= ETMV1_TRIGGER_CYCLE; } /* trace word j + 2 */ etm_ctx->trace_data[j + 2].pipestat = (trace_data[i] & 0x10000) >> 16; etm_ctx->trace_data[j + 2].packet = (trace_data[i] & 0x780000) >> 19; etm_ctx->trace_data[j + 2].flags = 0; if ((trace_data[i] & 0x800000) >> 23) etm_ctx->trace_data[j + 2].flags |= ETMV1_TRACESYNC_CYCLE; if (etm_ctx->trace_data[j + 2].pipestat == STAT_TR) { etm_ctx->trace_data[j + 2].pipestat = etm_ctx->trace_data[j + 2].packet & 0x7; etm_ctx->trace_data[j + 2].flags |= ETMV1_TRIGGER_CYCLE; } j += 3; } else if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) { /* trace word j */ etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7f8) >> 3; etm_ctx->trace_data[j].flags = 0; if ((trace_data[i] & 0x800) >> 11) etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; if (etm_ctx->trace_data[j].pipestat == STAT_TR) { etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; } /* trace word j + 1 */ etm_ctx->trace_data[j + 1].pipestat = (trace_data[i] & 0x7000) >> 12; etm_ctx->trace_data[j + 1].packet = (trace_data[i] & 0x7f8000) >> 15; etm_ctx->trace_data[j + 1].flags = 0; if ((trace_data[i] & 0x800000) >> 23) etm_ctx->trace_data[j + 1].flags |= ETMV1_TRACESYNC_CYCLE; if (etm_ctx->trace_data[j + 1].pipestat == STAT_TR) { etm_ctx->trace_data[j + 1].pipestat = etm_ctx->trace_data[j + 1].packet & 0x7; etm_ctx->trace_data[j + 1].flags |= ETMV1_TRIGGER_CYCLE; } j += 2; } else { /* trace word j */ etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7fff8) >> 3; etm_ctx->trace_data[j].flags = 0; if ((trace_data[i] & 0x80000) >> 19) etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; if (etm_ctx->trace_data[j].pipestat == STAT_TR) { etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; } j += 1; } } free(trace_data); return ERROR_OK; } static int etb_start_capture(struct etm_context *etm_ctx) { struct etb *etb = etm_ctx->capture_driver_priv; uint32_t etb_ctrl_value = 0x1; uint32_t trigger_count; if ((etm_ctx->control & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED) { if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) != ETM_PORT_8BIT) { LOG_ERROR("ETB can't run in demultiplexed mode with a 4 or 16 bit port"); return ERROR_ETM_PORTMODE_NOT_SUPPORTED; } etb_ctrl_value |= 0x2; } if ((etm_ctx->control & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED) { LOG_ERROR("ETB: can't run in multiplexed mode"); return ERROR_ETM_PORTMODE_NOT_SUPPORTED; } trigger_count = (etb->ram_depth * etb->trigger_percent) / 100; etb_write_reg(&etb->reg_cache->reg_list[ETB_TRIGGER_COUNTER], trigger_count); etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER], 0x0); etb_write_reg(&etb->reg_cache->reg_list[ETB_CTRL], etb_ctrl_value); jtag_execute_queue(); /* we're starting a new trace, initialize capture status */ etm_ctx->capture_status = TRACE_RUNNING; return ERROR_OK; } static int etb_stop_capture(struct etm_context *etm_ctx) { struct etb *etb = etm_ctx->capture_driver_priv; struct reg *etb_ctrl_reg = &etb->reg_cache->reg_list[ETB_CTRL]; etb_write_reg(etb_ctrl_reg, 0x0); jtag_execute_queue(); /* trace stopped, just clear running flag, but preserve others */ etm_ctx->capture_status &= ~TRACE_RUNNING; return ERROR_OK; } struct etm_capture_driver etb_capture_driver = { .name = "etb", .commands = etb_command_handlers, .init = etb_init, .status = etb_status, .start_capture = etb_start_capture, .stop_capture = etb_stop_capture, .read_trace = etb_read_trace, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/etb.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_TARGET_ETB_H #define OPENOCD_TARGET_ETB_H /* ETB registers */ enum { ETB_ID = 0x00, ETB_RAM_DEPTH = 0x01, ETB_RAM_WIDTH = 0x02, ETB_STATUS = 0x03, ETB_RAM_DATA = 0x04, ETB_RAM_READ_POINTER = 0x05, ETB_RAM_WRITE_POINTER = 0x06, ETB_TRIGGER_COUNTER = 0x07, ETB_CTRL = 0x08, }; struct etb { struct etm_context *etm_ctx; struct jtag_tap *tap; uint32_t cur_scan_chain; struct reg_cache *reg_cache; /* ETB parameters */ uint32_t ram_depth; uint32_t ram_width; /** how much trace buffer to fill after trigger */ unsigned trigger_percent; }; struct etb_reg { uint32_t addr; struct etb *etb; }; extern struct etm_capture_driver etb_capture_driver; struct reg_cache *etb_build_reg_cache(struct etb *etb); #endif /* OPENOCD_TARGET_ETB_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/etm.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "etm.h" #include "etb.h" #include "image.h" #include "arm_disassembler.h" #include "register.h" #include "etm_dummy.h" /* * ARM "Embedded Trace Macrocell" (ETM) support -- direct JTAG access. * * ETM modules collect instruction and/or data trace information, compress * it, and transfer it to a debugging host through either a (buffered) trace * port (often a 38-pin Mictor connector) or an Embedded Trace Buffer (ETB). * * There are several generations of these modules. Original versions have * JTAG access through a dedicated scan chain. Recent versions have added * access via coprocessor instructions, memory addressing, and the ARM Debug * Interface v5 (ADIv5); and phased out direct JTAG access. * * This code supports up to the ETMv1.3 architecture, as seen in ETM9 and * most common ARM9 systems. Note: "CoreSight ETM9" implements ETMv3.2, * implying non-JTAG connectivity options. * * Relevant documentation includes: * ARM DDI 0157G ... ETM9 (r2p2) Technical Reference Manual * ARM DDI 0315B ... CoreSight ETM9 (r0p1) Technical Reference Manual * ARM IHI 0014O ... Embedded Trace Macrocell, Architecture Specification */ enum { RO, /* read/only */ WO, /* write/only */ RW, /* read/write */ }; struct etm_reg_info { uint8_t addr; uint8_t size; /* low-N of 32 bits */ uint8_t mode; /* RO, WO, RW */ uint8_t bcd_vers; /* 1.0, 2.0, etc */ const char *name; }; /* * Registers 0..0x7f are JTAG-addressable using scanchain 6. * (Or on some processors, through coprocessor operations.) * Newer versions of ETM make some W/O registers R/W, and * provide definitions for some previously-unused bits. */ /* core registers used to version/configure the ETM */ static const struct etm_reg_info etm_core[] = { /* NOTE: we "know" the order here ... */ { ETM_CONFIG, 32, RO, 0x10, "ETM_config", }, { ETM_ID, 32, RO, 0x20, "ETM_id", }, }; /* basic registers that are always there given the right ETM version */ static const struct etm_reg_info etm_basic[] = { /* ETM Trace Registers */ { ETM_CTRL, 32, RW, 0x10, "ETM_ctrl", }, { ETM_TRIG_EVENT, 17, WO, 0x10, "ETM_trig_event", }, { ETM_ASIC_CTRL, 8, WO, 0x10, "ETM_asic_ctrl", }, { ETM_STATUS, 3, RO, 0x11, "ETM_status", }, { ETM_SYS_CONFIG, 9, RO, 0x12, "ETM_sys_config", }, /* TraceEnable configuration */ { ETM_TRACE_RESOURCE_CTRL, 32, WO, 0x12, "ETM_trace_resource_ctrl", }, { ETM_TRACE_EN_CTRL2, 16, WO, 0x12, "ETM_trace_en_ctrl2", }, { ETM_TRACE_EN_EVENT, 17, WO, 0x10, "ETM_trace_en_event", }, { ETM_TRACE_EN_CTRL1, 26, WO, 0x10, "ETM_trace_en_ctrl1", }, /* ViewData configuration (data trace) */ { ETM_VIEWDATA_EVENT, 17, WO, 0x10, "ETM_viewdata_event", }, { ETM_VIEWDATA_CTRL1, 32, WO, 0x10, "ETM_viewdata_ctrl1", }, { ETM_VIEWDATA_CTRL2, 32, WO, 0x10, "ETM_viewdata_ctrl2", }, { ETM_VIEWDATA_CTRL3, 17, WO, 0x10, "ETM_viewdata_ctrl3", }, /* REVISIT exclude VIEWDATA_CTRL2 when it's not there */ { 0x78, 12, WO, 0x20, "ETM_sync_freq", }, { 0x7a, 22, RO, 0x31, "ETM_config_code_ext", }, { 0x7b, 32, WO, 0x31, "ETM_ext_input_select", }, { 0x7c, 32, WO, 0x34, "ETM_trace_start_stop", }, { 0x7d, 8, WO, 0x34, "ETM_behavior_control", }, }; static const struct etm_reg_info etm_fifofull[] = { /* FIFOFULL configuration */ { ETM_FIFOFULL_REGION, 25, WO, 0x10, "ETM_fifofull_region", }, { ETM_FIFOFULL_LEVEL, 8, WO, 0x10, "ETM_fifofull_level", }, }; static const struct etm_reg_info etm_addr_comp[] = { /* Address comparator register pairs */ #define ADDR_COMPARATOR(i) \ { ETM_ADDR_COMPARATOR_VALUE + (i) - 1, 32, WO, 0x10, \ "ETM_addr_" #i "_comparator_value", }, \ { ETM_ADDR_ACCESS_TYPE + (i) - 1, 7, WO, 0x10, \ "ETM_addr_" #i "_access_type", } ADDR_COMPARATOR(1), ADDR_COMPARATOR(2), ADDR_COMPARATOR(3), ADDR_COMPARATOR(4), ADDR_COMPARATOR(5), ADDR_COMPARATOR(6), ADDR_COMPARATOR(7), ADDR_COMPARATOR(8), ADDR_COMPARATOR(9), ADDR_COMPARATOR(10), ADDR_COMPARATOR(11), ADDR_COMPARATOR(12), ADDR_COMPARATOR(13), ADDR_COMPARATOR(14), ADDR_COMPARATOR(15), ADDR_COMPARATOR(16), { 0, 0, 0, 0, NULL } #undef ADDR_COMPARATOR }; static const struct etm_reg_info etm_data_comp[] = { /* Data Value Comparators (NOTE: odd addresses are reserved) */ #define DATA_COMPARATOR(i) \ { ETM_DATA_COMPARATOR_VALUE + 2*(i) - 1, 32, WO, 0x10, \ "ETM_data_" #i "_comparator_value", }, \ { ETM_DATA_COMPARATOR_MASK + 2*(i) - 1, 32, WO, 0x10, \ "ETM_data_" #i "_comparator_mask", } DATA_COMPARATOR(1), DATA_COMPARATOR(2), DATA_COMPARATOR(3), DATA_COMPARATOR(4), DATA_COMPARATOR(5), DATA_COMPARATOR(6), DATA_COMPARATOR(7), DATA_COMPARATOR(8), { 0, 0, 0, 0, NULL } #undef DATA_COMPARATOR }; static const struct etm_reg_info etm_counters[] = { #define ETM_COUNTER(i) \ { ETM_COUNTER_RELOAD_VALUE + (i) - 1, 16, WO, 0x10, \ "ETM_counter_" #i "_reload_value", }, \ { ETM_COUNTER_ENABLE + (i) - 1, 18, WO, 0x10, \ "ETM_counter_" #i "_enable", }, \ { ETM_COUNTER_RELOAD_EVENT + (i) - 1, 17, WO, 0x10, \ "ETM_counter_" #i "_reload_event", }, \ { ETM_COUNTER_VALUE + (i) - 1, 16, RO, 0x10, \ "ETM_counter_" #i "_value", } ETM_COUNTER(1), ETM_COUNTER(2), ETM_COUNTER(3), ETM_COUNTER(4), { 0, 0, 0, 0, NULL } #undef ETM_COUNTER }; static const struct etm_reg_info etm_sequencer[] = { #define ETM_SEQ(i) \ { ETM_SEQUENCER_EVENT + (i), 17, WO, 0x10, \ "ETM_sequencer_event" #i, } ETM_SEQ(0), /* 1->2 */ ETM_SEQ(1), /* 2->1 */ ETM_SEQ(2), /* 2->3 */ ETM_SEQ(3), /* 3->1 */ ETM_SEQ(4), /* 3->2 */ ETM_SEQ(5), /* 1->3 */ #undef ETM_SEQ /* 0x66 reserved */ { ETM_SEQUENCER_STATE, 2, RO, 0x10, "ETM_sequencer_state", }, }; static const struct etm_reg_info etm_outputs[] = { #define ETM_OUTPUT(i) \ { ETM_EXTERNAL_OUTPUT + (i) - 1, 17, WO, 0x10, \ "ETM_external_output" #i, } ETM_OUTPUT(1), ETM_OUTPUT(2), ETM_OUTPUT(3), ETM_OUTPUT(4), { 0, 0, 0, 0, NULL } #undef ETM_OUTPUT }; #if 0 /* registers from 0x6c..0x7f were added after ETMv1.3 */ /* Context ID Comparators */ { 0x6c, 32, RO, 0x20, "ETM_contextid_comparator_value1", } { 0x6d, 32, RO, 0x20, "ETM_contextid_comparator_value2", } { 0x6e, 32, RO, 0x20, "ETM_contextid_comparator_value3", } { 0x6f, 32, RO, 0x20, "ETM_contextid_comparator_mask", } #endif static int etm_get_reg(struct reg *reg); static int etm_read_reg_w_check(struct reg *reg, uint8_t *check_value, uint8_t *check_mask); static int etm_register_user_commands(struct command_context *cmd_ctx); static int etm_set_reg_w_exec(struct reg *reg, uint8_t *buf); static int etm_write_reg(struct reg *reg, uint32_t value); static const struct reg_arch_type etm_scan6_type = { .get = etm_get_reg, .set = etm_set_reg_w_exec, }; /* Look up register by ID ... most ETM instances only * support a subset of the possible registers. */ static struct reg *etm_reg_lookup(struct etm_context *etm_ctx, unsigned id) { struct reg_cache *cache = etm_ctx->reg_cache; unsigned i; for (i = 0; i < cache->num_regs; i++) { struct etm_reg *reg = cache->reg_list[i].arch_info; if (reg->reg_info->addr == id) return &cache->reg_list[i]; } /* caller asking for nonexistent register is a bug! * REVISIT say which of the N targets was involved */ LOG_ERROR("ETM: register 0x%02x not available", id); return NULL; } static void etm_reg_add(unsigned bcd_vers, struct arm_jtag *jtag_info, struct reg_cache *cache, struct etm_reg *ereg, const struct etm_reg_info *r, unsigned nreg) { struct reg *reg = cache->reg_list; reg += cache->num_regs; ereg += cache->num_regs; /* add up to "nreg" registers from "r", if supported by this * version of the ETM, to the specified cache. */ for (; nreg--; r++) { /* No more registers to add */ if (!r->size) { LOG_ERROR("etm_reg_add is requested to add non-existing registers, ETM config might be bogus"); return; } /* this ETM may be too old to have some registers */ if (r->bcd_vers > bcd_vers) continue; reg->name = r->name; reg->size = r->size; reg->value = ereg->value; reg->arch_info = ereg; reg->type = &etm_scan6_type; reg++; cache->num_regs++; ereg->reg_info = r; ereg->jtag_info = jtag_info; ereg++; } } struct reg_cache *etm_build_reg_cache(struct target *target, struct arm_jtag *jtag_info, struct etm_context *etm_ctx) { struct reg_cache *reg_cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = NULL; struct etm_reg *arch_info = NULL; unsigned bcd_vers, config; /* the actual registers are kept in two arrays */ reg_list = calloc(128, sizeof(struct reg)); arch_info = calloc(128, sizeof(struct etm_reg)); if (!reg_cache || !reg_list || !arch_info) { LOG_ERROR("No memory"); goto fail; } /* fill in values for the reg cache */ reg_cache->name = "etm registers"; reg_cache->next = NULL; reg_cache->reg_list = reg_list; reg_cache->num_regs = 0; /* add ETM_CONFIG, then parse its values to see * which other registers exist in this ETM */ etm_reg_add(0x10, jtag_info, reg_cache, arch_info, etm_core, 1); etm_get_reg(reg_list); etm_ctx->config = buf_get_u32(arch_info->value, 0, 32); config = etm_ctx->config; /* figure ETM version then add base registers */ if (config & (1 << 31)) { LOG_WARNING("ETMv2+ support is incomplete"); /* REVISIT more registers may exist; they may now be * readable; more register bits have defined meanings; * don't presume trace start/stop support is present; * and include any context ID comparator registers. */ etm_reg_add(0x20, jtag_info, reg_cache, arch_info, etm_core + 1, 1); etm_get_reg(reg_list + 1); etm_ctx->id = buf_get_u32( arch_info[1].value, 0, 32); LOG_DEBUG("ETM ID: %08x", (unsigned) etm_ctx->id); bcd_vers = 0x10 + (((etm_ctx->id) >> 4) & 0xff); } else { switch (config >> 28) { case 7: case 5: case 3: bcd_vers = 0x13; break; case 4: case 2: bcd_vers = 0x12; break; case 1: bcd_vers = 0x11; break; case 0: bcd_vers = 0x10; break; default: LOG_WARNING("Bad ETMv1 protocol %d", config >> 28); goto fail; } } etm_ctx->bcd_vers = bcd_vers; LOG_INFO("ETM v%d.%d", bcd_vers >> 4, bcd_vers & 0xf); etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info, etm_basic, ARRAY_SIZE(etm_basic)); /* address and data comparators; counters; outputs */ etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info, etm_addr_comp, 4 * (0x0f & (config >> 0))); etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info, etm_data_comp, 2 * (0x0f & (config >> 4))); etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info, etm_counters, 4 * (0x07 & (config >> 13))); etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info, etm_outputs, (0x07 & (config >> 20))); /* FIFOFULL presence is optional * REVISIT for ETMv1.2 and later, don't bother adding this * unless ETM_SYS_CONFIG says it's also *supported* ... */ if (config & (1 << 23)) etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info, etm_fifofull, ARRAY_SIZE(etm_fifofull)); /* sequencer is optional (for state-dependant triggering) */ if (config & (1 << 16)) etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info, etm_sequencer, ARRAY_SIZE(etm_sequencer)); /* REVISIT could realloc and likely save half the memory * in the two chunks we allocated... */ /* the ETM might have an ETB connected */ if (strcmp(etm_ctx->capture_driver->name, "etb") == 0) { struct etb *etb = etm_ctx->capture_driver_priv; if (!etb) { LOG_ERROR("etb selected as etm capture driver, but no ETB configured"); goto fail; } reg_cache->next = etb_build_reg_cache(etb); etb->reg_cache = reg_cache->next; } etm_ctx->reg_cache = reg_cache; return reg_cache; fail: free(reg_cache); free(reg_list); free(arch_info); return NULL; } static int etm_read_reg(struct reg *reg) { return etm_read_reg_w_check(reg, NULL, NULL); } static int etm_store_reg(struct reg *reg) { return etm_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); } int etm_setup(struct target *target) { int retval; uint32_t etm_ctrl_value; struct arm *arm = target_to_arm(target); struct etm_context *etm_ctx = arm->etm; struct reg *etm_ctrl_reg; etm_ctrl_reg = etm_reg_lookup(etm_ctx, ETM_CTRL); if (!etm_ctrl_reg) return ERROR_OK; /* initialize some ETM control register settings */ etm_get_reg(etm_ctrl_reg); etm_ctrl_value = buf_get_u32(etm_ctrl_reg->value, 0, 32); /* clear the ETM powerdown bit (0) */ etm_ctrl_value &= ~ETM_CTRL_POWERDOWN; /* configure port width (21,6:4), mode (13,17:16) and * for older modules clocking (13) */ etm_ctrl_value = (etm_ctrl_value & ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK & ~ETM_CTRL_DBGRQ & ~ETM_PORT_CLOCK_MASK) | etm_ctx->control; buf_set_u32(etm_ctrl_reg->value, 0, 32, etm_ctrl_value); etm_store_reg(etm_ctrl_reg); etm_ctx->control = etm_ctrl_value; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* REVISIT for ETMv3.0 and later, read ETM_sys_config to * verify that those width and mode settings are OK ... */ retval = etm_ctx->capture_driver->init(etm_ctx); if (retval != ERROR_OK) { LOG_ERROR("ETM capture driver initialization failed"); return retval; } return ERROR_OK; } static int etm_get_reg(struct reg *reg) { int retval; retval = etm_read_reg(reg); if (retval != ERROR_OK) { LOG_ERROR("BUG: error scheduling etm register read"); return retval; } retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("register read failed"); return retval; } return ERROR_OK; } static int etm_read_reg_w_check(struct reg *reg, uint8_t *check_value, uint8_t *check_mask) { struct etm_reg *etm_reg = reg->arch_info; assert(etm_reg); const struct etm_reg_info *r = etm_reg->reg_info; uint8_t reg_addr = r->addr & 0x7f; struct scan_field fields[3]; int retval; if (etm_reg->reg_info->mode == WO) { LOG_ERROR("BUG: can't read write-only register %s", r->name); return ERROR_COMMAND_SYNTAX_ERROR; } LOG_DEBUG("%s (%u)", r->name, reg_addr); retval = arm_jtag_scann(etm_reg->jtag_info, 0x6, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(etm_reg->jtag_info->tap, etm_reg->jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = reg->value; fields[0].in_value = NULL; fields[0].check_value = NULL; fields[0].check_mask = NULL; fields[1].num_bits = 7; uint8_t temp1 = 0; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, reg_addr); fields[1].in_value = NULL; fields[1].check_value = NULL; fields[1].check_mask = NULL; fields[2].num_bits = 1; uint8_t temp2 = 0; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 0); fields[2].in_value = NULL; fields[2].check_value = NULL; fields[2].check_mask = NULL; jtag_add_dr_scan(etm_reg->jtag_info->tap, 3, fields, TAP_IDLE); fields[0].in_value = reg->value; fields[0].check_value = check_value; fields[0].check_mask = check_mask; jtag_add_dr_scan_check(etm_reg->jtag_info->tap, 3, fields, TAP_IDLE); return ERROR_OK; } static int etm_set_reg(struct reg *reg, uint32_t value) { int retval = etm_write_reg(reg, value); if (retval != ERROR_OK) { LOG_ERROR("BUG: error scheduling etm register write"); return retval; } buf_set_u32(reg->value, 0, reg->size, value); reg->valid = 1; reg->dirty = 0; return ERROR_OK; } static int etm_set_reg_w_exec(struct reg *reg, uint8_t *buf) { int retval; etm_set_reg(reg, buf_get_u32(buf, 0, reg->size)); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("register write failed"); return retval; } return ERROR_OK; } static int etm_write_reg(struct reg *reg, uint32_t value) { struct etm_reg *etm_reg = reg->arch_info; const struct etm_reg_info *r = etm_reg->reg_info; uint8_t reg_addr = r->addr & 0x7f; struct scan_field fields[3]; int retval; if (etm_reg->reg_info->mode == RO) { LOG_ERROR("BUG: can't write read--only register %s", r->name); return ERROR_COMMAND_SYNTAX_ERROR; } LOG_DEBUG("%s (%u): 0x%8.8" PRIx32 "", r->name, reg_addr, value); retval = arm_jtag_scann(etm_reg->jtag_info, 0x6, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(etm_reg->jtag_info->tap, etm_reg->jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; uint8_t tmp1[4]; fields[0].out_value = tmp1; buf_set_u32(tmp1, 0, 32, value); fields[0].in_value = NULL; fields[1].num_bits = 7; uint8_t tmp2 = 0; fields[1].out_value = &tmp2; buf_set_u32(&tmp2, 0, 7, reg_addr); fields[1].in_value = NULL; fields[2].num_bits = 1; uint8_t tmp3 = 0; fields[2].out_value = &tmp3; buf_set_u32(&tmp3, 0, 1, 1); fields[2].in_value = NULL; jtag_add_dr_scan(etm_reg->jtag_info->tap, 3, fields, TAP_IDLE); return ERROR_OK; } /* ETM trace analysis functionality */ static struct etm_capture_driver *etm_capture_drivers[] = { &etb_capture_driver, &etm_dummy_capture_driver, NULL }; static int etm_read_instruction(struct etm_context *ctx, struct arm_instruction *instruction) { int section = -1; size_t size_read; uint32_t opcode; int retval; if (!ctx->image) return ERROR_TRACE_IMAGE_UNAVAILABLE; /* search for the section the current instruction belongs to */ for (unsigned int i = 0; i < ctx->image->num_sections; i++) { if ((ctx->image->sections[i].base_address <= ctx->current_pc) && (ctx->image->sections[i].base_address + ctx->image->sections[i].size > ctx->current_pc)) { section = i; break; } } if (section == -1) { /* current instruction couldn't be found in the image */ return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } if (ctx->core_state == ARM_STATE_ARM) { uint8_t buf[4]; retval = image_read_section(ctx->image, section, ctx->current_pc - ctx->image->sections[section].base_address, 4, buf, &size_read); if (retval != ERROR_OK) { LOG_ERROR("error while reading instruction"); return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } opcode = target_buffer_get_u32(ctx->target, buf); arm_evaluate_opcode(opcode, ctx->current_pc, instruction); } else if (ctx->core_state == ARM_STATE_THUMB) { uint8_t buf[2]; retval = image_read_section(ctx->image, section, ctx->current_pc - ctx->image->sections[section].base_address, 2, buf, &size_read); if (retval != ERROR_OK) { LOG_ERROR("error while reading instruction"); return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } opcode = target_buffer_get_u16(ctx->target, buf); thumb_evaluate_opcode(opcode, ctx->current_pc, instruction); } else if (ctx->core_state == ARM_STATE_JAZELLE) { LOG_ERROR("BUG: tracing of jazelle code not supported"); return ERROR_FAIL; } else { LOG_ERROR("BUG: unknown core state encountered"); return ERROR_FAIL; } return ERROR_OK; } static int etmv1_next_packet(struct etm_context *ctx, uint8_t *packet, int apo) { while (ctx->data_index < ctx->trace_depth) { /* if the caller specified an address packet offset, skip until the * we reach the n-th cycle marked with tracesync */ if (apo > 0) { if (ctx->trace_data[ctx->data_index].flags & ETMV1_TRACESYNC_CYCLE) apo--; if (apo > 0) { ctx->data_index++; ctx->data_half = 0; } continue; } /* no tracedata output during a TD cycle * or in a trigger cycle */ if ((ctx->trace_data[ctx->data_index].pipestat == STAT_TD) || (ctx->trace_data[ctx->data_index].flags & ETMV1_TRIGGER_CYCLE)) { ctx->data_index++; ctx->data_half = 0; continue; } /* FIXME there are more port widths than these... */ if ((ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT) { if (ctx->data_half == 0) { *packet = ctx->trace_data[ctx->data_index].packet & 0xff; ctx->data_half = 1; } else { *packet = (ctx->trace_data[ctx->data_index].packet & 0xff00) >> 8; ctx->data_half = 0; ctx->data_index++; } } else if ((ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) { *packet = ctx->trace_data[ctx->data_index].packet & 0xff; ctx->data_index++; } else { /* on a 4-bit port, a packet will be output during two consecutive cycles */ if (ctx->data_index > (ctx->trace_depth - 2)) return -1; *packet = ctx->trace_data[ctx->data_index].packet & 0xf; *packet |= (ctx->trace_data[ctx->data_index + 1].packet & 0xf) << 4; ctx->data_index += 2; } return 0; } return -1; } static int etmv1_branch_address(struct etm_context *ctx) { int retval; uint8_t packet; int shift = 0; int apo; uint32_t i; /* quit analysis if less than two cycles are left in the trace * because we can't extract the APO */ if (ctx->data_index > (ctx->trace_depth - 2)) return -1; /* a BE could be output during an APO cycle, skip the current * and continue with the new one */ if (ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x4) return 1; if (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x4) return 2; /* address packet offset encoded in the next two cycles' pipestat bits */ apo = ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x3; apo |= (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x3) << 2; /* count number of tracesync cycles between current pipe_index and data_index * i.e. the number of tracesyncs that data_index already passed by * to subtract them from the APO */ for (i = ctx->pipe_index; i < ctx->data_index; i++) { if (ctx->trace_data[ctx->pipe_index + 1].pipestat & ETMV1_TRACESYNC_CYCLE) apo--; } /* extract up to four 7-bit packets */ do { retval = etmv1_next_packet(ctx, &packet, (shift == 0) ? apo + 1 : 0); if (retval != 0) return -1; ctx->last_branch &= ~(0x7f << shift); ctx->last_branch |= (packet & 0x7f) << shift; shift += 7; } while ((packet & 0x80) && (shift < 28)); /* one last packet holding 4 bits of the address, plus the branch reason code */ if ((shift == 28) && (packet & 0x80)) { retval = etmv1_next_packet(ctx, &packet, 0); if (retval != 0) return -1; ctx->last_branch &= 0x0fffffff; ctx->last_branch |= (packet & 0x0f) << 28; ctx->last_branch_reason = (packet & 0x70) >> 4; shift += 4; } else ctx->last_branch_reason = 0; if (shift == 32) ctx->pc_ok = 1; /* if a full address was output, we might have branched into Jazelle state */ if ((shift == 32) && (packet & 0x80)) ctx->core_state = ARM_STATE_JAZELLE; else { /* if we didn't branch into Jazelle state, the current processor state is * encoded in bit 0 of the branch target address */ if (ctx->last_branch & 0x1) { ctx->core_state = ARM_STATE_THUMB; ctx->last_branch &= ~0x1; } else { ctx->core_state = ARM_STATE_ARM; ctx->last_branch &= ~0x3; } } return 0; } static int etmv1_data(struct etm_context *ctx, int size, uint32_t *data) { int j; uint8_t buf[4]; int retval; for (j = 0; j < size; j++) { retval = etmv1_next_packet(ctx, &buf[j], 0); if (retval != 0) return -1; } if (size == 8) { LOG_ERROR("TODO: add support for 64-bit values"); return -1; } else if (size == 4) *data = target_buffer_get_u32(ctx->target, buf); else if (size == 2) *data = target_buffer_get_u16(ctx->target, buf); else if (size == 1) *data = buf[0]; else return -1; return 0; } static int etmv1_analyze_trace(struct etm_context *ctx, struct command_invocation *cmd) { int retval; struct arm_instruction instruction; /* read the trace data if it wasn't read already */ if (ctx->trace_depth == 0) ctx->capture_driver->read_trace(ctx); if (ctx->trace_depth == 0) { command_print(cmd, "Trace is empty."); return ERROR_OK; } /* start at the beginning of the captured trace */ ctx->pipe_index = 0; ctx->data_index = 0; ctx->data_half = 0; /* neither the PC nor the data pointer are valid */ ctx->pc_ok = 0; ctx->ptr_ok = 0; while (ctx->pipe_index < ctx->trace_depth) { uint8_t pipestat = ctx->trace_data[ctx->pipe_index].pipestat; uint32_t next_pc = ctx->current_pc; uint32_t old_data_index = ctx->data_index; uint32_t old_data_half = ctx->data_half; uint32_t old_index = ctx->pipe_index; uint32_t last_instruction = ctx->last_instruction; uint32_t cycles = 0; int current_pc_ok = ctx->pc_ok; if (ctx->trace_data[ctx->pipe_index].flags & ETMV1_TRIGGER_CYCLE) command_print(cmd, "--- trigger ---"); /* instructions execute in IE/D or BE/D cycles */ if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) ctx->last_instruction = ctx->pipe_index; /* if we don't have a valid pc skip until we reach an indirect branch */ if ((!ctx->pc_ok) && (pipestat != STAT_BE)) { ctx->pipe_index++; continue; } /* any indirect branch could have interrupted instruction flow * - the branch reason code could indicate a trace discontinuity * - a branch to the exception vectors indicates an exception */ if ((pipestat == STAT_BE) || (pipestat == STAT_BD)) { /* backup current data index, to be able to consume the branch address * before examining data address and values */ old_data_index = ctx->data_index; old_data_half = ctx->data_half; ctx->last_instruction = ctx->pipe_index; retval = etmv1_branch_address(ctx); if (retval != 0) { /* negative return value from etmv1_branch_address means we ran out of packets, * quit analysing the trace */ if (retval < 0) break; /* a positive return values means the current branch was abandoned, * and a new branch was encountered in cycle ctx->pipe_index + retval; */ LOG_WARNING( "abandoned branch encountered, correctness of analysis uncertain"); ctx->pipe_index += retval; continue; } /* skip over APO cycles */ ctx->pipe_index += 2; switch (ctx->last_branch_reason) { case 0x0: /* normal PC change */ next_pc = ctx->last_branch; break; case 0x1: /* tracing enabled */ command_print(cmd, "--- tracing enabled at 0x%8.8" PRIx32 " ---", ctx->last_branch); ctx->current_pc = ctx->last_branch; ctx->pipe_index++; continue; break; case 0x2: /* trace restarted after FIFO overflow */ command_print(cmd, "--- trace restarted after FIFO overflow at 0x%8.8" PRIx32 " ---", ctx->last_branch); ctx->current_pc = ctx->last_branch; ctx->pipe_index++; continue; break; case 0x3: /* exit from debug state */ command_print(cmd, "--- exit from debug state at 0x%8.8" PRIx32 " ---", ctx->last_branch); ctx->current_pc = ctx->last_branch; ctx->pipe_index++; continue; break; case 0x4: /* periodic synchronization point */ next_pc = ctx->last_branch; /* if we had no valid PC prior to this synchronization point, * we have to move on with the next trace cycle */ if (!current_pc_ok) { command_print(cmd, "--- periodic synchronization point at 0x%8.8" PRIx32 " ---", next_pc); ctx->current_pc = next_pc; ctx->pipe_index++; continue; } break; default: /* reserved */ LOG_ERROR( "BUG: branch reason code 0x%" PRIx32 " is reserved", ctx->last_branch_reason); return ERROR_FAIL; } /* if we got here the branch was a normal PC change * (or a periodic synchronization point, which means the same for that matter) * if we didn't acquire a complete PC continue with the next cycle */ if (!ctx->pc_ok) continue; /* indirect branch to the exception vector means an exception occurred */ if ((ctx->last_branch <= 0x20) || ((ctx->last_branch >= 0xffff0000) && (ctx->last_branch <= 0xffff0020))) { if ((ctx->last_branch & 0xff) == 0x10) command_print(cmd, "data abort"); else { command_print(cmd, "exception vector 0x%2.2" PRIx32 "", ctx->last_branch); ctx->current_pc = ctx->last_branch; ctx->pipe_index++; continue; } } } /* an instruction was executed (or not, depending on the condition flags) * retrieve it from the image for displaying */ if (ctx->pc_ok && (pipestat != STAT_WT) && (pipestat != STAT_TD) && !(((pipestat == STAT_BE) || (pipestat == STAT_BD)) && ((ctx->last_branch_reason != 0x0) && (ctx->last_branch_reason != 0x4)))) { retval = etm_read_instruction(ctx, &instruction); if (retval != ERROR_OK) { /* can't continue tracing with no image available */ if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) return retval; else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) { /* TODO: handle incomplete images * for now we just quit the analysis*/ return retval; } } cycles = old_index - last_instruction; } if ((pipestat == STAT_ID) || (pipestat == STAT_BD)) { uint32_t new_data_index = ctx->data_index; uint32_t new_data_half = ctx->data_half; /* in case of a branch with data, the branch target address was consumed before * we temporarily go back to the saved data index */ if (pipestat == STAT_BD) { ctx->data_index = old_data_index; ctx->data_half = old_data_half; } if (ctx->control & ETM_CTRL_TRACE_ADDR) { uint8_t packet; int shift = 0; do { retval = etmv1_next_packet(ctx, &packet, 0); if (retval != 0) return ERROR_ETM_ANALYSIS_FAILED; ctx->last_ptr &= ~(0x7f << shift); ctx->last_ptr |= (packet & 0x7f) << shift; shift += 7; } while ((packet & 0x80) && (shift < 32)); if (shift >= 32) ctx->ptr_ok = 1; if (ctx->ptr_ok) command_print(cmd, "address: 0x%8.8" PRIx32 "", ctx->last_ptr); } if (ctx->control & ETM_CTRL_TRACE_DATA) { if ((instruction.type == ARM_LDM) || (instruction.type == ARM_STM)) { int i; for (i = 0; i < 16; i++) { if (instruction.info.load_store_multiple.register_list & (1 << i)) { uint32_t data; if (etmv1_data(ctx, 4, &data) != 0) return ERROR_ETM_ANALYSIS_FAILED; command_print(cmd, "data: 0x%8.8" PRIx32 "", data); } } } else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_STRH)) { uint32_t data; if (etmv1_data(ctx, arm_access_size(&instruction), &data) != 0) return ERROR_ETM_ANALYSIS_FAILED; command_print(cmd, "data: 0x%8.8" PRIx32 "", data); } } /* restore data index after consuming BD address and data */ if (pipestat == STAT_BD) { ctx->data_index = new_data_index; ctx->data_half = new_data_half; } } /* adjust PC */ if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) { if (((instruction.type == ARM_B) || (instruction.type == ARM_BL) || (instruction.type == ARM_BLX)) && (instruction.info.b_bl_bx_blx.target_address != 0xffffffff)) next_pc = instruction.info.b_bl_bx_blx.target_address; else next_pc += (ctx->core_state == ARM_STATE_ARM) ? 4 : 2; } else if (pipestat == STAT_IN) next_pc += (ctx->core_state == ARM_STATE_ARM) ? 4 : 2; if ((pipestat != STAT_TD) && (pipestat != STAT_WT)) { char cycles_text[32] = ""; /* if the trace was captured with cycle accurate tracing enabled, * output the number of cycles since the last executed instruction */ if (ctx->control & ETM_CTRL_CYCLE_ACCURATE) { snprintf(cycles_text, 32, " (%i %s)", (int)cycles, (cycles == 1) ? "cycle" : "cycles"); } command_print(cmd, "%s%s%s", instruction.text, (pipestat == STAT_IN) ? " (not executed)" : "", cycles_text); ctx->current_pc = next_pc; /* packets for an instruction don't start on or before the preceding * functional pipestat (i.e. other than WT or TD) */ if (ctx->data_index <= ctx->pipe_index) { ctx->data_index = ctx->pipe_index + 1; ctx->data_half = 0; } } ctx->pipe_index += 1; } return ERROR_OK; } static COMMAND_HELPER(handle_etm_tracemode_command_update, uint32_t *mode) { uint32_t tracemode; /* what parts of data access are traced? */ if (strcmp(CMD_ARGV[0], "none") == 0) tracemode = 0; else if (strcmp(CMD_ARGV[0], "data") == 0) tracemode = ETM_CTRL_TRACE_DATA; else if (strcmp(CMD_ARGV[0], "address") == 0) tracemode = ETM_CTRL_TRACE_ADDR; else if (strcmp(CMD_ARGV[0], "all") == 0) tracemode = ETM_CTRL_TRACE_DATA | ETM_CTRL_TRACE_ADDR; else { command_print(CMD, "invalid option '%s'", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; } uint8_t context_id; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], context_id); switch (context_id) { case 0: tracemode |= ETM_CTRL_CONTEXTID_NONE; break; case 8: tracemode |= ETM_CTRL_CONTEXTID_8; break; case 16: tracemode |= ETM_CTRL_CONTEXTID_16; break; case 32: tracemode |= ETM_CTRL_CONTEXTID_32; break; default: command_print(CMD, "invalid option '%s'", CMD_ARGV[1]); return ERROR_COMMAND_SYNTAX_ERROR; } bool etmv1_cycle_accurate; COMMAND_PARSE_ENABLE(CMD_ARGV[2], etmv1_cycle_accurate); if (etmv1_cycle_accurate) tracemode |= ETM_CTRL_CYCLE_ACCURATE; bool etmv1_branch_output; COMMAND_PARSE_ENABLE(CMD_ARGV[3], etmv1_branch_output); if (etmv1_branch_output) tracemode |= ETM_CTRL_BRANCH_OUTPUT; /* IGNORED: * - CPRT tracing (coprocessor register transfers) * - debug request (causes debug entry on trigger) * - stall on FIFOFULL (preventing tracedata loss) */ *mode = tracemode; return ERROR_OK; } COMMAND_HANDLER(handle_etm_tracemode_command) { struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct etm_context *etm; if (!is_arm(arm)) { command_print(CMD, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm = arm->etm; if (!etm) { command_print(CMD, "current target doesn't have an ETM configured"); return ERROR_FAIL; } uint32_t tracemode = etm->control; switch (CMD_ARGC) { case 0: break; case 4: CALL_COMMAND_HANDLER(handle_etm_tracemode_command_update, &tracemode); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } /** * todo: fail if parameters were invalid for this hardware, * or couldn't be written; display actual hardware state... */ command_print(CMD, "current tracemode configuration:"); switch (tracemode & ETM_CTRL_TRACE_MASK) { default: command_print(CMD, "data tracing: none"); break; case ETM_CTRL_TRACE_DATA: command_print(CMD, "data tracing: data only"); break; case ETM_CTRL_TRACE_ADDR: command_print(CMD, "data tracing: address only"); break; case ETM_CTRL_TRACE_DATA | ETM_CTRL_TRACE_ADDR: command_print(CMD, "data tracing: address and data"); break; } switch (tracemode & ETM_CTRL_CONTEXTID_MASK) { case ETM_CTRL_CONTEXTID_NONE: command_print(CMD, "contextid tracing: none"); break; case ETM_CTRL_CONTEXTID_8: command_print(CMD, "contextid tracing: 8 bit"); break; case ETM_CTRL_CONTEXTID_16: command_print(CMD, "contextid tracing: 16 bit"); break; case ETM_CTRL_CONTEXTID_32: command_print(CMD, "contextid tracing: 32 bit"); break; } if (tracemode & ETM_CTRL_CYCLE_ACCURATE) command_print(CMD, "cycle-accurate tracing enabled"); else command_print(CMD, "cycle-accurate tracing disabled"); if (tracemode & ETM_CTRL_BRANCH_OUTPUT) command_print(CMD, "full branch address output enabled"); else command_print(CMD, "full branch address output disabled"); #define TRACEMODE_MASK ( \ ETM_CTRL_CONTEXTID_MASK \ | ETM_CTRL_BRANCH_OUTPUT \ | ETM_CTRL_CYCLE_ACCURATE \ | ETM_CTRL_TRACE_MASK \ ) /* only update ETM_CTRL register if tracemode changed */ if ((etm->control & TRACEMODE_MASK) != tracemode) { struct reg *etm_ctrl_reg; etm_ctrl_reg = etm_reg_lookup(etm, ETM_CTRL); if (!etm_ctrl_reg) return ERROR_FAIL; etm->control &= ~TRACEMODE_MASK; etm->control |= tracemode & TRACEMODE_MASK; buf_set_u32(etm_ctrl_reg->value, 0, 32, etm->control); etm_store_reg(etm_ctrl_reg); /* invalidate old trace data */ etm->capture_status = TRACE_IDLE; if (etm->trace_depth > 0) { free(etm->trace_data); etm->trace_data = NULL; } etm->trace_depth = 0; } #undef TRACEMODE_MASK return ERROR_OK; } COMMAND_HANDLER(handle_etm_config_command) { struct target *target; struct arm *arm; uint32_t portmode = 0x0; struct etm_context *etm_ctx; int i; if (CMD_ARGC != 5) return ERROR_COMMAND_SYNTAX_ERROR; target = get_target(CMD_ARGV[0]); if (!target) { LOG_ERROR("target '%s' not defined", CMD_ARGV[0]); return ERROR_FAIL; } arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "target '%s' is '%s'; not an ARM", target_name(target), target_type_name(target)); return ERROR_FAIL; } /* FIXME for ETMv3.0 and above -- and we don't yet know what ETM * version we'll be using!! -- so we can't know how to validate * params yet. "etm config" should likely be *AFTER* hookup... * * - Many more widths might be supported ... and we can easily * check whether our setting "took". * * - The "clock" and "mode" bits are interpreted differently. * See ARM IHI 0014O table 2-17 for the old behaviour, and * table 2-18 for the new. With ETB it's best to specify * "normal full" ... */ uint8_t port_width; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], port_width); switch (port_width) { /* before ETMv3.0 */ case 4: portmode |= ETM_PORT_4BIT; break; case 8: portmode |= ETM_PORT_8BIT; break; case 16: portmode |= ETM_PORT_16BIT; break; /* ETMv3.0 and later*/ case 24: portmode |= ETM_PORT_24BIT; break; case 32: portmode |= ETM_PORT_32BIT; break; case 48: portmode |= ETM_PORT_48BIT; break; case 64: portmode |= ETM_PORT_64BIT; break; case 1: portmode |= ETM_PORT_1BIT; break; case 2: portmode |= ETM_PORT_2BIT; break; default: command_print(CMD, "unsupported ETM port width '%s'", CMD_ARGV[1]); return ERROR_FAIL; } if (strcmp("normal", CMD_ARGV[2]) == 0) portmode |= ETM_PORT_NORMAL; else if (strcmp("multiplexed", CMD_ARGV[2]) == 0) portmode |= ETM_PORT_MUXED; else if (strcmp("demultiplexed", CMD_ARGV[2]) == 0) portmode |= ETM_PORT_DEMUXED; else { command_print(CMD, "unsupported ETM port mode '%s', must be 'normal', 'multiplexed' or 'demultiplexed'", CMD_ARGV[2]); return ERROR_FAIL; } if (strcmp("half", CMD_ARGV[3]) == 0) portmode |= ETM_PORT_HALF_CLOCK; else if (strcmp("full", CMD_ARGV[3]) == 0) portmode |= ETM_PORT_FULL_CLOCK; else { command_print(CMD, "unsupported ETM port clocking '%s', must be 'full' or 'half'", CMD_ARGV[3]); return ERROR_FAIL; } etm_ctx = calloc(1, sizeof(struct etm_context)); if (!etm_ctx) { LOG_DEBUG("out of memory"); return ERROR_FAIL; } for (i = 0; etm_capture_drivers[i]; i++) { if (strcmp(CMD_ARGV[4], etm_capture_drivers[i]->name) == 0) { int retval = register_commands(CMD_CTX, NULL, etm_capture_drivers[i]->commands); if (retval != ERROR_OK) { free(etm_ctx); return retval; } etm_ctx->capture_driver = etm_capture_drivers[i]; break; } } if (!etm_capture_drivers[i]) { /* no supported capture driver found, don't register an ETM */ free(etm_ctx); LOG_ERROR("trace capture driver '%s' not found", CMD_ARGV[4]); return ERROR_FAIL; } etm_ctx->target = target; etm_ctx->trace_data = NULL; etm_ctx->control = portmode; etm_ctx->core_state = ARM_STATE_ARM; arm->etm = etm_ctx; return etm_register_user_commands(CMD_CTX); } COMMAND_HANDLER(handle_etm_info_command) { struct target *target; struct arm *arm; struct etm_context *etm; struct reg *etm_sys_config_reg; int max_port_size; uint32_t config; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm = arm->etm; if (!etm) { command_print(CMD, "current target doesn't have an ETM configured"); return ERROR_FAIL; } command_print(CMD, "ETM v%d.%d", etm->bcd_vers >> 4, etm->bcd_vers & 0xf); command_print(CMD, "pairs of address comparators: %i", (int) (etm->config >> 0) & 0x0f); command_print(CMD, "data comparators: %i", (int) (etm->config >> 4) & 0x0f); command_print(CMD, "memory map decoders: %i", (int) (etm->config >> 8) & 0x1f); command_print(CMD, "number of counters: %i", (int) (etm->config >> 13) & 0x07); command_print(CMD, "sequencer %spresent", (int) (etm->config & (1 << 16)) ? "" : "not "); command_print(CMD, "number of ext. inputs: %i", (int) (etm->config >> 17) & 0x07); command_print(CMD, "number of ext. outputs: %i", (int) (etm->config >> 20) & 0x07); command_print(CMD, "FIFO full %spresent", (int) (etm->config & (1 << 23)) ? "" : "not "); if (etm->bcd_vers < 0x20) command_print(CMD, "protocol version: %i", (int) (etm->config >> 28) & 0x07); else { command_print(CMD, "coprocessor and memory access %ssupported", (etm->config & (1 << 26)) ? "" : "not "); command_print(CMD, "trace start/stop %spresent", (etm->config & (1 << 26)) ? "" : "not "); command_print(CMD, "number of context comparators: %i", (int) (etm->config >> 24) & 0x03); } /* SYS_CONFIG isn't present before ETMv1.2 */ etm_sys_config_reg = etm_reg_lookup(etm, ETM_SYS_CONFIG); if (!etm_sys_config_reg) return ERROR_OK; etm_get_reg(etm_sys_config_reg); config = buf_get_u32(etm_sys_config_reg->value, 0, 32); LOG_DEBUG("ETM SYS CONFIG %08x", (unsigned) config); max_port_size = config & 0x7; if (etm->bcd_vers >= 0x30) max_port_size |= (config >> 6) & 0x08; switch (max_port_size) { /* before ETMv3.0 */ case 0: max_port_size = 4; break; case 1: max_port_size = 8; break; case 2: max_port_size = 16; break; /* ETMv3.0 and later*/ case 3: max_port_size = 24; break; case 4: max_port_size = 32; break; case 5: max_port_size = 48; break; case 6: max_port_size = 64; break; case 8: max_port_size = 1; break; case 9: max_port_size = 2; break; default: LOG_ERROR("Illegal max_port_size"); return ERROR_FAIL; } command_print(CMD, "max. port size: %i", max_port_size); if (etm->bcd_vers < 0x30) { command_print(CMD, "half-rate clocking %ssupported", (config & (1 << 3)) ? "" : "not "); command_print(CMD, "full-rate clocking %ssupported", (config & (1 << 4)) ? "" : "not "); command_print(CMD, "normal trace format %ssupported", (config & (1 << 5)) ? "" : "not "); command_print(CMD, "multiplex trace format %ssupported", (config & (1 << 6)) ? "" : "not "); command_print(CMD, "demultiplex trace format %ssupported", (config & (1 << 7)) ? "" : "not "); } else { /* REVISIT show which size and format are selected ... */ command_print(CMD, "current port size %ssupported", (config & (1 << 10)) ? "" : "not "); command_print(CMD, "current trace format %ssupported", (config & (1 << 11)) ? "" : "not "); } if (etm->bcd_vers >= 0x21) command_print(CMD, "fetch comparisons %ssupported", (config & (1 << 17)) ? "not " : ""); command_print(CMD, "FIFO full %ssupported", (config & (1 << 8)) ? "" : "not "); return ERROR_OK; } COMMAND_HANDLER(handle_etm_status_command) { struct target *target; struct arm *arm; struct etm_context *etm; trace_status_t trace_status; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm = arm->etm; if (!etm) { command_print(CMD, "current target doesn't have an ETM configured"); return ERROR_FAIL; } /* ETM status */ if (etm->bcd_vers >= 0x11) { struct reg *reg; reg = etm_reg_lookup(etm, ETM_STATUS); if (!reg) return ERROR_FAIL; if (etm_get_reg(reg) == ERROR_OK) { unsigned s = buf_get_u32(reg->value, 0, reg->size); command_print(CMD, "etm: %s%s%s%s", /* bit(1) == progbit */ (etm->bcd_vers >= 0x12) ? ((s & (1 << 1)) ? "disabled" : "enabled") : "?", ((s & (1 << 3)) && etm->bcd_vers >= 0x31) ? " triggered" : "", ((s & (1 << 2)) && etm->bcd_vers >= 0x12) ? " start/stop" : "", ((s & (1 << 0)) && etm->bcd_vers >= 0x11) ? " untraced-overflow" : ""); } /* else ignore and try showing trace port status */ } /* Trace Port Driver status */ trace_status = etm->capture_driver->status(etm); if (trace_status == TRACE_IDLE) command_print(CMD, "%s: idle", etm->capture_driver->name); else { static char *completed = " completed"; static char *running = " is running"; static char *overflowed = ", overflowed"; static char *triggered = ", triggered"; command_print(CMD, "%s: trace collection%s%s%s", etm->capture_driver->name, (trace_status & TRACE_RUNNING) ? running : completed, (trace_status & TRACE_OVERFLOWED) ? overflowed : "", (trace_status & TRACE_TRIGGERED) ? triggered : ""); if (etm->trace_depth > 0) { command_print(CMD, "%i frames of trace data read", (int)(etm->trace_depth)); } } return ERROR_OK; } COMMAND_HANDLER(handle_etm_image_command) { struct target *target; struct arm *arm; struct etm_context *etm_ctx; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { command_print(CMD, "current target doesn't have an ETM configured"); return ERROR_FAIL; } if (etm_ctx->image) { image_close(etm_ctx->image); free(etm_ctx->image); command_print(CMD, "previously loaded image found and closed"); } etm_ctx->image = malloc(sizeof(struct image)); etm_ctx->image->base_address_set = false; etm_ctx->image->start_address_set = false; /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ if (CMD_ARGC >= 2) { etm_ctx->image->base_address_set = true; COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], etm_ctx->image->base_address); } else etm_ctx->image->base_address_set = false; if (image_open(etm_ctx->image, CMD_ARGV[0], (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL) != ERROR_OK) { free(etm_ctx->image); etm_ctx->image = NULL; return ERROR_FAIL; } return ERROR_OK; } COMMAND_HANDLER(handle_etm_dump_command) { struct fileio *file; struct target *target; struct arm *arm; struct etm_context *etm_ctx; uint32_t i; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { command_print(CMD, "current target doesn't have an ETM configured"); return ERROR_FAIL; } if (etm_ctx->capture_driver->status(etm_ctx) == TRACE_IDLE) { command_print(CMD, "trace capture wasn't enabled, no trace data captured"); return ERROR_OK; } if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) { /* TODO: if on-the-fly capture is to be supported, this needs to be changed */ command_print(CMD, "trace capture not completed"); return ERROR_FAIL; } /* read the trace data if it wasn't read already */ if (etm_ctx->trace_depth == 0) etm_ctx->capture_driver->read_trace(etm_ctx); if (fileio_open(&file, CMD_ARGV[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) return ERROR_FAIL; fileio_write_u32(file, etm_ctx->capture_status); fileio_write_u32(file, etm_ctx->control); fileio_write_u32(file, etm_ctx->trace_depth); for (i = 0; i < etm_ctx->trace_depth; i++) { fileio_write_u32(file, etm_ctx->trace_data[i].pipestat); fileio_write_u32(file, etm_ctx->trace_data[i].packet); fileio_write_u32(file, etm_ctx->trace_data[i].flags); } fileio_close(file); return ERROR_OK; } COMMAND_HANDLER(handle_etm_load_command) { struct fileio *file; struct target *target; struct arm *arm; struct etm_context *etm_ctx; uint32_t i; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { command_print(CMD, "current target doesn't have an ETM configured"); return ERROR_FAIL; } if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) { command_print(CMD, "trace capture running, stop first"); return ERROR_FAIL; } if (fileio_open(&file, CMD_ARGV[0], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) return ERROR_FAIL; size_t filesize; int retval = fileio_size(file, &filesize); if (retval != ERROR_OK) { fileio_close(file); return retval; } if (filesize % 4) { command_print(CMD, "size isn't a multiple of 4, no valid trace data"); fileio_close(file); return ERROR_FAIL; } if (etm_ctx->trace_depth > 0) { free(etm_ctx->trace_data); etm_ctx->trace_data = NULL; } { uint32_t tmp; fileio_read_u32(file, &tmp); etm_ctx->capture_status = tmp; fileio_read_u32(file, &tmp); etm_ctx->control = tmp; fileio_read_u32(file, &etm_ctx->trace_depth); } etm_ctx->trace_data = malloc(sizeof(struct etmv1_trace_data) * etm_ctx->trace_depth); if (!etm_ctx->trace_data) { command_print(CMD, "not enough memory to perform operation"); fileio_close(file); return ERROR_FAIL; } for (i = 0; i < etm_ctx->trace_depth; i++) { uint32_t pipestat, packet, flags; fileio_read_u32(file, &pipestat); fileio_read_u32(file, &packet); fileio_read_u32(file, &flags); etm_ctx->trace_data[i].pipestat = pipestat & 0xff; etm_ctx->trace_data[i].packet = packet & 0xffff; etm_ctx->trace_data[i].flags = flags; } fileio_close(file); return ERROR_OK; } COMMAND_HANDLER(handle_etm_start_command) { struct target *target; struct arm *arm; struct etm_context *etm_ctx; struct reg *etm_ctrl_reg; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { command_print(CMD, "current target doesn't have an ETM configured"); return ERROR_FAIL; } /* invalidate old tracing data */ etm_ctx->capture_status = TRACE_IDLE; if (etm_ctx->trace_depth > 0) { free(etm_ctx->trace_data); etm_ctx->trace_data = NULL; } etm_ctx->trace_depth = 0; etm_ctrl_reg = etm_reg_lookup(etm_ctx, ETM_CTRL); if (!etm_ctrl_reg) return ERROR_FAIL; etm_get_reg(etm_ctrl_reg); /* Clear programming bit (10), set port selection bit (11) */ buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x2); etm_store_reg(etm_ctrl_reg); jtag_execute_queue(); etm_ctx->capture_driver->start_capture(etm_ctx); return ERROR_OK; } COMMAND_HANDLER(handle_etm_stop_command) { struct target *target; struct arm *arm; struct etm_context *etm_ctx; struct reg *etm_ctrl_reg; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { command_print(CMD, "current target doesn't have an ETM configured"); return ERROR_FAIL; } etm_ctrl_reg = etm_reg_lookup(etm_ctx, ETM_CTRL); if (!etm_ctrl_reg) return ERROR_FAIL; etm_get_reg(etm_ctrl_reg); /* Set programming bit (10), clear port selection bit (11) */ buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x1); etm_store_reg(etm_ctrl_reg); jtag_execute_queue(); etm_ctx->capture_driver->stop_capture(etm_ctx); return ERROR_OK; } COMMAND_HANDLER(handle_etm_trigger_debug_command) { struct target *target; struct arm *arm; struct etm_context *etm; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "ETM: %s isn't an ARM", target_name(target)); return ERROR_FAIL; } etm = arm->etm; if (!etm) { command_print(CMD, "ETM: no ETM configured for %s", target_name(target)); return ERROR_FAIL; } if (CMD_ARGC == 1) { struct reg *etm_ctrl_reg; bool dbgrq; etm_ctrl_reg = etm_reg_lookup(etm, ETM_CTRL); if (!etm_ctrl_reg) return ERROR_FAIL; COMMAND_PARSE_ENABLE(CMD_ARGV[0], dbgrq); if (dbgrq) etm->control |= ETM_CTRL_DBGRQ; else etm->control &= ~ETM_CTRL_DBGRQ; /* etm->control will be written to hardware * the next time an "etm start" is issued. */ buf_set_u32(etm_ctrl_reg->value, 0, 32, etm->control); } command_print(CMD, "ETM: %s debug halt", (etm->control & ETM_CTRL_DBGRQ) ? "triggers" : "does not trigger"); return ERROR_OK; } COMMAND_HANDLER(handle_etm_analyze_command) { struct target *target; struct arm *arm; struct etm_context *etm_ctx; int retval; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { command_print(CMD, "current target doesn't have an ETM configured"); return ERROR_FAIL; } retval = etmv1_analyze_trace(etm_ctx, CMD); if (retval != ERROR_OK) { /* FIX! error should be reported inside etmv1_analyze_trace() */ switch (retval) { case ERROR_ETM_ANALYSIS_FAILED: command_print(CMD, "further analysis failed (corrupted trace data or just end of data"); break; case ERROR_TRACE_INSTRUCTION_UNAVAILABLE: command_print(CMD, "no instruction for current address available, analysis aborted"); break; case ERROR_TRACE_IMAGE_UNAVAILABLE: command_print(CMD, "no image available for trace analysis"); break; default: command_print(CMD, "unknown error"); } } return retval; } static const struct command_registration etm_config_command_handlers[] = { { /* NOTE: with ADIv5, ETMs are accessed by DAP operations, * possibly over SWD, not JTAG scanchain 6 of 'target'. * * Also, these parameters don't match ETM v3+ modules... */ .name = "config", .handler = handle_etm_config_command, .mode = COMMAND_CONFIG, .help = "Set up ETM output port.", .usage = "target port_width port_mode clocking capture_driver", }, COMMAND_REGISTRATION_DONE }; const struct command_registration etm_command_handlers[] = { { .name = "etm", .mode = COMMAND_ANY, .help = "Embedded Trace Macrocell command group", .usage = "", .chain = etm_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration etm_exec_command_handlers[] = { { .name = "tracemode", .handler = handle_etm_tracemode_command, .mode = COMMAND_EXEC, .help = "configure/display trace mode", .usage = "('none'|'data'|'address'|'all') " "context_id_bits " "['enable'|'disable'] " "['enable'|'disable']", }, { .name = "info", .handler = handle_etm_info_command, .mode = COMMAND_EXEC, .usage = "", .help = "display info about the current target's ETM", }, { .name = "status", .handler = handle_etm_status_command, .mode = COMMAND_EXEC, .usage = "", .help = "display current target's ETM status", }, { .name = "start", .handler = handle_etm_start_command, .mode = COMMAND_EXEC, .usage = "", .help = "start ETM trace collection", }, { .name = "stop", .handler = handle_etm_stop_command, .mode = COMMAND_EXEC, .usage = "", .help = "stop ETM trace collection", }, { .name = "trigger_debug", .handler = handle_etm_trigger_debug_command, .mode = COMMAND_EXEC, .help = "enable/disable debug entry on trigger", .usage = "['enable'|'disable']", }, { .name = "analyze", .handler = handle_etm_analyze_command, .mode = COMMAND_EXEC, .usage = "", .help = "analyze collected ETM trace", }, { .name = "image", .handler = handle_etm_image_command, .mode = COMMAND_EXEC, .help = "load image from file with optional offset", .usage = "<file> [base address] [type]", }, { .name = "dump", .handler = handle_etm_dump_command, .mode = COMMAND_EXEC, .help = "dump captured trace data to file", .usage = "filename", }, { .name = "load", .handler = handle_etm_load_command, .mode = COMMAND_EXEC, .usage = "", .help = "load trace data for analysis <file>", }, COMMAND_REGISTRATION_DONE }; static int etm_register_user_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, "etm", etm_exec_command_handlers); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/etm.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007 by Vincent Palatin * * vincent.palatin_openocd@m4x.org * ***************************************************************************/ #ifndef OPENOCD_TARGET_ETM_H #define OPENOCD_TARGET_ETM_H #include "trace.h" #include "arm_jtag.h" struct image; /* ETM registers (JTAG protocol) */ enum { ETM_CTRL = 0x00, ETM_CONFIG = 0x01, ETM_TRIG_EVENT = 0x02, ETM_ASIC_CTRL = 0x03, ETM_STATUS = 0x04, ETM_SYS_CONFIG = 0x05, ETM_TRACE_RESOURCE_CTRL = 0x06, ETM_TRACE_EN_CTRL2 = 0x07, ETM_TRACE_EN_EVENT = 0x08, ETM_TRACE_EN_CTRL1 = 0x09, /* optional FIFOFULL */ ETM_FIFOFULL_REGION = 0x0a, ETM_FIFOFULL_LEVEL = 0x0b, /* viewdata support */ ETM_VIEWDATA_EVENT = 0x0c, ETM_VIEWDATA_CTRL1 = 0x0d, ETM_VIEWDATA_CTRL2 = 0x0e, /* optional */ ETM_VIEWDATA_CTRL3 = 0x0f, /* N pairs of ADDR_{COMPARATOR,ACCESS} registers */ ETM_ADDR_COMPARATOR_VALUE = 0x10, ETM_ADDR_ACCESS_TYPE = 0x20, /* N pairs of DATA_COMPARATOR_{VALUE,MASK} registers */ ETM_DATA_COMPARATOR_VALUE = 0x30, ETM_DATA_COMPARATOR_MASK = 0x40, /* N quads of COUNTER_{RELOAD_{VALUE,EVENT},ENABLE,VALUE} registers */ ETM_COUNTER_RELOAD_VALUE = 0x50, ETM_COUNTER_ENABLE = 0x54, ETM_COUNTER_RELOAD_EVENT = 0x58, ETM_COUNTER_VALUE = 0x5c, /* 6 sequencer event transitions */ ETM_SEQUENCER_EVENT = 0x60, ETM_SEQUENCER_STATE = 0x67, /* N triggered outputs */ ETM_EXTERNAL_OUTPUT = 0x68, /* N task contexts */ ETM_CONTEXTID_COMPARATOR_VALUE = 0x6c, ETM_CONTEXTID_COMPARATOR_MASK = 0x6f, ETM_ID = 0x79, }; struct etm_reg { uint8_t value[4]; const struct etm_reg_info *reg_info; struct arm_jtag *jtag_info; }; /* Subset of ETM_CTRL bit assignments. Many of these * control the configuration of trace output, which * hooks up either to ETB or to an external device. * * NOTE that these have evolved since the ~v1.3 defns ... */ enum { ETM_CTRL_POWERDOWN = (1 << 0), ETM_CTRL_MONITOR_CPRT = (1 << 1), /* bits 3:2 == trace type */ ETM_CTRL_TRACE_DATA = (1 << 2), ETM_CTRL_TRACE_ADDR = (2 << 2), ETM_CTRL_TRACE_MASK = (3 << 2), /* Port width (bits 21 and 6:4) */ ETM_PORT_4BIT = 0x00, ETM_PORT_8BIT = 0x10, ETM_PORT_16BIT = 0x20, ETM_PORT_24BIT = 0x30, ETM_PORT_32BIT = 0x40, ETM_PORT_48BIT = 0x50, ETM_PORT_64BIT = 0x60, ETM_PORT_1BIT = 0x00 | (1 << 21), ETM_PORT_2BIT = 0x10 | (1 << 21), ETM_PORT_WIDTH_MASK = 0x70 | (1 << 21), ETM_CTRL_FIFOFULL_STALL = (1 << 7), ETM_CTRL_BRANCH_OUTPUT = (1 << 8), ETM_CTRL_DBGRQ = (1 << 9), ETM_CTRL_ETM_PROG = (1 << 10), ETM_CTRL_ETMEN = (1 << 11), ETM_CTRL_CYCLE_ACCURATE = (1 << 12), /* Clocking modes -- up to v2.1, bit 13 */ ETM_PORT_FULL_CLOCK = (0 << 13), ETM_PORT_HALF_CLOCK = (1 << 13), ETM_PORT_CLOCK_MASK = (1 << 13), /* bits 15:14 == context ID size used in tracing */ ETM_CTRL_CONTEXTID_NONE = (0 << 14), ETM_CTRL_CONTEXTID_8 = (1 << 14), ETM_CTRL_CONTEXTID_16 = (2 << 14), ETM_CTRL_CONTEXTID_32 = (3 << 14), ETM_CTRL_CONTEXTID_MASK = (3 << 14), /* Port modes -- bits 17:16, tied to clocking mode */ ETM_PORT_NORMAL = (0 << 16), ETM_PORT_MUXED = (1 << 16), ETM_PORT_DEMUXED = (2 << 16), ETM_PORT_MODE_MASK = (3 << 16), /* bits 31:18 defined in v3.0 and later (e.g. ARM11+) */ }; /* forward-declare ETM context */ struct etm_context; struct etm_capture_driver { const char *name; const struct command_registration *commands; int (*init)(struct etm_context *etm_ctx); trace_status_t (*status)(struct etm_context *etm_ctx); int (*read_trace)(struct etm_context *etm_ctx); int (*start_capture)(struct etm_context *etm_ctx); int (*stop_capture)(struct etm_context *etm_ctx); }; enum { ETMV1_TRACESYNC_CYCLE = 0x1, ETMV1_TRIGGER_CYCLE = 0x2, }; struct etmv1_trace_data { uint8_t pipestat; /* bits 0-2 pipeline status */ uint16_t packet; /* packet data (4, 8 or 16 bit) */ int flags; /* ETMV1_TRACESYNC_CYCLE, ETMV1_TRIGGER_CYCLE */ }; /* describe a trace context * if support for ETMv2 or ETMv3 is to be implemented, * this will have to be split into version independent elements * and a version specific part */ struct etm_context { struct target *target; /* target this ETM is connected to */ struct reg_cache *reg_cache; /* ETM register cache */ struct etm_capture_driver *capture_driver; /* driver used to access ETM data */ void *capture_driver_priv; /* capture driver private data */ trace_status_t capture_status; /* current state of capture run */ struct etmv1_trace_data *trace_data; /* trace data */ uint32_t trace_depth; /* number of cycles to be analyzed, 0 if no data available */ uint32_t control; /* shadow of ETM_CTRL */ int /*arm_state*/ core_state; /* current core state */ struct image *image; /* source for target opcodes */ uint32_t pipe_index; /* current trace cycle */ uint32_t data_index; /* cycle holding next data packet */ bool data_half; /* port half on a 16 bit port */ bool pc_ok; /* full PC has been acquired */ bool ptr_ok; /* whether last_ptr is valid */ uint8_t bcd_vers; /* e.g. 0x13 == ETMv1.3 */ uint32_t config; /* cache of ETM_CONFIG value */ uint32_t id; /* cache of ETM_ID value, or 0 */ uint32_t current_pc; /* current program counter */ uint32_t last_branch; /* last branch address output */ uint32_t last_branch_reason; /* type of last branch encountered */ uint32_t last_ptr; /* address of the last data access */ uint32_t last_instruction; /* index of last executed (to calc timings) */ }; /* PIPESTAT values */ typedef enum { STAT_IE = 0x0, STAT_ID = 0x1, STAT_IN = 0x2, STAT_WT = 0x3, STAT_BE = 0x4, STAT_BD = 0x5, STAT_TR = 0x6, STAT_TD = 0x7 } etmv1_pipestat_t; /* branch reason values */ typedef enum { BR_NORMAL = 0x0, /* Normal PC change : periodic synchro (ETMv1.1) */ BR_ENABLE = 0x1, /* Trace has been enabled */ BR_RESTART = 0x2, /* Trace restarted after a FIFO overflow */ BR_NODEBUG = 0x3, /* ARM has exited for debug state */ BR_PERIOD = 0x4, /* Periodic synchronization point (ETM >= v1.2)*/ BR_RSVD5 = 0x5, /* reserved */ BR_RSVD6 = 0x6, /* reserved */ BR_RSVD7 = 0x7, /* reserved */ } etmv1_branch_reason_t; struct reg_cache *etm_build_reg_cache(struct target *target, struct arm_jtag *jtag_info, struct etm_context *etm_ctx); int etm_setup(struct target *target); extern const struct command_registration etm_command_handlers[]; #define ERROR_ETM_INVALID_DRIVER (-1300) #define ERROR_ETM_PORTMODE_NOT_SUPPORTED (-1301) #define ERROR_ETM_CAPTURE_INIT_FAILED (-1302) #define ERROR_ETM_ANALYSIS_FAILED (-1303) #endif /* OPENOCD_TARGET_ETM_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/etm_dummy.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "etm_dummy.h" COMMAND_HANDLER(handle_etm_dummy_config_command) { struct target *target; struct arm *arm; target = get_target(CMD_ARGV[0]); if (!target) { LOG_ERROR("target '%s' not defined", CMD_ARGV[0]); return ERROR_FAIL; } arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD, "target '%s' isn't an ARM", CMD_ARGV[0]); return ERROR_FAIL; } if (arm->etm) arm->etm->capture_driver_priv = NULL; else { LOG_ERROR("target has no ETM defined, ETM dummy left unconfigured"); return ERROR_FAIL; } return ERROR_OK; } static const struct command_registration etm_dummy_config_command_handlers[] = { { .name = "config", .handler = handle_etm_dummy_config_command, .mode = COMMAND_CONFIG, .usage = "target", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration etm_dummy_command_handlers[] = { { .name = "etm_dummy", .mode = COMMAND_ANY, .help = "Dummy ETM capture driver command group", .chain = etm_dummy_config_command_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static int etm_dummy_init(struct etm_context *etm_ctx) { return ERROR_OK; } static trace_status_t etm_dummy_status(struct etm_context *etm_ctx) { return TRACE_IDLE; } static int etm_dummy_read_trace(struct etm_context *etm_ctx) { return ERROR_OK; } static int etm_dummy_start_capture(struct etm_context *etm_ctx) { return ERROR_ETM_PORTMODE_NOT_SUPPORTED; } static int etm_dummy_stop_capture(struct etm_context *etm_ctx) { return ERROR_OK; } struct etm_capture_driver etm_dummy_capture_driver = { .name = "dummy", .commands = etm_dummy_command_handlers, .init = etm_dummy_init, .status = etm_dummy_status, .start_capture = etm_dummy_start_capture, .stop_capture = etm_dummy_stop_capture, .read_trace = etm_dummy_read_trace, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/etm_dummy.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_TARGET_ETM_DUMMY_H #define OPENOCD_TARGET_ETM_DUMMY_H #include "etm.h" extern struct etm_capture_driver etm_dummy_capture_driver; #endif /* OPENOCD_TARGET_ETM_DUMMY_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/fa526.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 by Paulius Zaleckas * * paulius.zaleckas@gmail.com * ***************************************************************************/ /* * FA526 is very similar to ARM920T with following differences: * * - execution pipeline is 6 steps * - Unified TLB * - has Branch Target Buffer * - does not support reading of I/D cache contents */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm920t.h" #include "target_type.h" #include "arm_opcodes.h" static void fa526_change_to_arm(struct target *target, uint32_t *r0, uint32_t *pc) { LOG_ERROR("%s: there is no Thumb state on FA526", __func__); } static void fa526_read_core_regs(struct target *target, uint32_t mask, uint32_t *core_regs[16]) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); /* fetch NOP, STM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STM in SHIFT stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, STM in MEMORY (i'th cycle) */ arm9tdmi_clock_data_in(jtag_info, core_regs[i]); } } static void fa526_read_core_regs_target_buffer(struct target *target, uint32_t mask, void *buffer, int size) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; uint32_t *buf_u32 = buffer; uint16_t *buf_u16 = buffer; uint8_t *buf_u8 = buffer; /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); /* fetch NOP, STM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STM in SHIFT stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, STM in MEMORY (i'th cycle) */ switch (size) { case 4: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); break; case 2: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); break; case 1: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); break; } } } static void fa526_read_xpsr(struct target *target, uint32_t *xpsr, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* MRS r0, cpsr */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* STR r0, [r15] */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0, NULL, 0); /* fetch NOP, STR in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STR in SHIFT stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STR in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, STR in MEMORY */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0); } static void fa526_write_xpsr(struct target *target, uint32_t xpsr, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr: %8.8" PRIx32 ", spsr: %i", xpsr, spsr); /* MSR1 fetched */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0); /* MSR2 fetched, MSR1 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0); /* MSR3 fetched, MSR1 in SHIFT, MSR2 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0); /* MSR4 fetched, MSR1 in EXECUTE (1), MSR2 in SHIFT, MSR3 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0); /* nothing fetched, MSR1 in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR1 in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR2 in EXECUTE (1), MSR3 in SHIFT, MSR4 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR2 in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR2 in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in SHIFT */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR3 in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR3 in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* NOP fetched, MSR4 in EXECUTE (1) */ /* last MSR writes flags, which takes only one cycle */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void fa526_write_xpsr_im8(struct target *target, uint8_t xpsr_im, int rot, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); /* MSR fetched */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0); /* NOP fetched, MSR in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* NOP fetched, MSR in SHIFT */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* NOP fetched, MSR in EXECUTE (1) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* rot == 4 writes flags, which takes only one cycle */ if (rot != 4) { /* nothing fetched, MSR in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } } static void fa526_write_core_regs(struct target *target, uint32_t mask, uint32_t core_regs[16]) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); /* fetch NOP, LDM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in SHIFT stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, LDM still in EXECUTE (1 + i cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0); } arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void fa526_write_pc(struct target *target, uint32_t pc) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0, NULL, 0); /* fetch NOP, LDM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in SHIFT stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, LDM in EXECUTE stage (2nd cycle) (output data) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, pc, NULL, 0); /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (4th cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (5th cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void fa526_branch_resume_thumb(struct target *target) { LOG_ERROR("%s: there is no Thumb state on FA526", __func__); } static int fa526_init_arch_info_2(struct target *target, struct arm7_9_common *arm7_9, struct jtag_tap *tap) { /* prepare JTAG information for the new target */ arm7_9->jtag_info.tap = tap; arm7_9->jtag_info.scann_size = 5; /* register arch-specific functions */ arm7_9->examine_debug_reason = arm9tdmi_examine_debug_reason; arm7_9->change_to_arm = fa526_change_to_arm; arm7_9->read_core_regs = fa526_read_core_regs; arm7_9->read_core_regs_target_buffer = fa526_read_core_regs_target_buffer; arm7_9->read_xpsr = fa526_read_xpsr; arm7_9->write_xpsr = fa526_write_xpsr; arm7_9->write_xpsr_im8 = fa526_write_xpsr_im8; arm7_9->write_core_regs = fa526_write_core_regs; arm7_9->load_word_regs = arm9tdmi_load_word_regs; arm7_9->load_hword_reg = arm9tdmi_load_hword_reg; arm7_9->load_byte_reg = arm9tdmi_load_byte_reg; arm7_9->store_word_regs = arm9tdmi_store_word_regs; arm7_9->store_hword_reg = arm9tdmi_store_hword_reg; arm7_9->store_byte_reg = arm9tdmi_store_byte_reg; arm7_9->write_pc = fa526_write_pc; arm7_9->branch_resume = arm9tdmi_branch_resume; arm7_9->branch_resume_thumb = fa526_branch_resume_thumb; arm7_9->enable_single_step = arm9tdmi_enable_single_step; arm7_9->disable_single_step = arm9tdmi_disable_single_step; arm7_9->write_memory = arm920t_write_memory; arm7_9->bulk_write_memory = arm7_9_bulk_write_memory; arm7_9->post_debug_entry = NULL; arm7_9->pre_restore_context = NULL; /* initialize arch-specific breakpoint handling */ arm7_9->arm_bkpt = 0xdeeedeee; arm7_9->thumb_bkpt = 0xdeee; arm7_9->dbgreq_adjust_pc = 3; arm7_9_init_arch_info(target, arm7_9); /* override use of DBGRQ, this is safe on ARM9TDMI */ arm7_9->use_dbgrq = 1; /* all ARM9s have the vector catch register */ arm7_9->has_vector_catch = 1; return ERROR_OK; } static int fa526_init_arch_info(struct target *target, struct arm920t_common *arm920t, struct jtag_tap *tap) { struct arm7_9_common *arm7_9 = &arm920t->arm7_9_common; /* initialize arm7/arm9 specific info (including armv4_5) */ fa526_init_arch_info_2(target, arm7_9, tap); arm920t->common_magic = ARM920T_COMMON_MAGIC; arm7_9->post_debug_entry = arm920t_post_debug_entry; arm7_9->pre_restore_context = arm920t_pre_restore_context; arm920t->armv4_5_mmu.armv4_5_cache.ctype = -1; arm920t->armv4_5_mmu.get_ttb = arm920t_get_ttb; arm920t->armv4_5_mmu.read_memory = arm7_9_read_memory; arm920t->armv4_5_mmu.write_memory = arm7_9_write_memory; arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches; arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches; arm920t->armv4_5_mmu.has_tiny_pages = 1; arm920t->armv4_5_mmu.mmu_enabled = 0; /* disabling linefills leads to lockups, so keep them enabled for now * this doesn't affect correctness, but might affect timing issues, if * important data is evicted from the cache during the debug session * */ arm920t->preserve_cache = 0; /* override hw single-step capability from ARM9TDMI */ arm7_9->has_single_step = 1; return ERROR_OK; } static int fa526_target_create(struct target *target, Jim_Interp *interp) { struct arm920t_common *arm920t = calloc(1, sizeof(struct arm920t_common)); return fa526_init_arch_info(target, arm920t, target->tap); } static void fa526_deinit_target(struct target *target) { struct arm *arm = target_to_arm(target); struct arm920t_common *arm920t = target_to_arm920(target); arm7_9_deinit(target); arm_free_reg_cache(arm); free(arm920t); } /** Holds methods for FA526 targets. */ struct target_type fa526_target = { .name = "fa526", .poll = arm7_9_poll, .arch_state = arm920t_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm920t_soft_reset_halt, .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm920t_read_memory, .write_memory = arm7_9_write_memory_opt, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm920t_command_handlers, .target_create = fa526_target_create, .init_target = arm9tdmi_init_target, .deinit_target = fa526_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/feroceon.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2008-2009 by Marvell Semiconductors, Inc. * * Written by Nicolas Pitre <nico@marvell.com> * * * * Copyright (C) 2008 by Hongtao Zheng * * hontor@126.com * ***************************************************************************/ /* * Marvell Feroceon/Dragonite support. * * The Feroceon core, as found in the Orion and Kirkwood SoCs amongst others, * mimics the ARM926 ICE interface with the following differences: * * - the MOE (method of entry) reporting is not implemented * * - breakpoint/watchpoint comparator #1 is seemingly not implemented * * - due to a different pipeline implementation, some injected debug * instruction sequences have to be somewhat different * * Other issues: * * - asserting DBGRQ doesn't work if target is looping on the undef vector * * - the EICE version signature in the COMMS_CTL reg is next to the flow bits * not at the top, and rather meaningless due to existing discrepancies * * - the DCC channel is half duplex (only one FIFO for both directions) with * seemingly no proper flow control. * * The Dragonite core is the non-mmu version based on the ARM966 model, and * it shares the above issues as well. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm926ejs.h" #include "arm966e.h" #include "target_type.h" #include "register.h" #include "arm_opcodes.h" static int feroceon_assert_reset(struct target *target) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; int ud = arm7_9->use_dbgrq; /* TODO: apply hw reset signal in not examined state */ if (!(target_was_examined(target))) { LOG_WARNING("Reset is not asserted because the target is not examined."); LOG_WARNING("Use a reset button or power cycle the target."); return ERROR_TARGET_NOT_EXAMINED; } arm7_9->use_dbgrq = 0; if (target->reset_halt) arm7_9_halt(target); arm7_9->use_dbgrq = ud; return arm7_9_assert_reset(target); } static int feroceon_dummy_clock_out(struct arm_jtag *jtag_info, uint32_t instr) { struct scan_field fields[3]; uint8_t out_buf[4]; uint8_t instr_buf[4]; uint8_t sysspeed_buf = 0x0; int retval; /* prepare buffer */ buf_set_u32(out_buf, 0, 32, 0); buf_set_u32(instr_buf, 0, 32, flip_u32(instr, 32)); retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = out_buf; fields[0].in_value = NULL; fields[1].num_bits = 3; fields[1].out_value = &sysspeed_buf; fields[1].in_value = NULL; fields[2].num_bits = 32; fields[2].out_value = instr_buf; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE); /* no jtag_add_runtest(0, TAP_DRPAUSE) here */ return ERROR_OK; } static void feroceon_change_to_arm(struct target *target, uint32_t *r0, uint32_t *pc) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* * save r0 before using it and put system in ARM state * to allow common handling of ARM and THUMB debugging */ feroceon_dummy_clock_out(jtag_info, ARMV4_5_T_NOP); feroceon_dummy_clock_out(jtag_info, ARMV4_5_T_NOP); feroceon_dummy_clock_out(jtag_info, ARMV4_5_T_NOP); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, r0, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, pc, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_BX(15), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); jtag_execute_queue(); /* * fix program counter: * MOV R0, PC was the 7th instruction (+12) * reading PC in Thumb state gives address of instruction + 4 */ *pc -= (12 + 4); } static void feroceon_read_core_regs(struct target *target, uint32_t mask, uint32_t *core_regs[16]) { int i; struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) if (mask & (1 << i)) arm9tdmi_clock_data_in(jtag_info, core_regs[i]); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void feroceon_read_core_regs_target_buffer(struct target *target, uint32_t mask, void *buffer, int size) { int i; struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; uint32_t *buf_u32 = buffer; uint16_t *buf_u16 = buffer; uint8_t *buf_u8 = buffer; arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) { switch (size) { case 4: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); break; case 2: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); break; case 1: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); break; } } } arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void feroceon_read_xpsr(struct target *target, uint32_t *xpsr, int spsr) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, 1, 0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void feroceon_write_xpsr(struct target *target, uint32_t xpsr, int spsr) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr: %8.8" PRIx32 ", spsr: %i", xpsr, spsr); arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void feroceon_write_xpsr_im8(struct target *target, uint8_t xpsr_im, int rot, int spsr) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void feroceon_write_core_regs(struct target *target, uint32_t mask, uint32_t core_regs[16]) { int i; struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) if (mask & (1 << i)) arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void feroceon_branch_resume(struct target *target) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffff9, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); arm7_9->need_bypass_before_restart = 1; } static void feroceon_branch_resume_thumb(struct target *target) { LOG_DEBUG("-"); struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32); uint32_t pc = buf_get_u32(arm->pc->value, 0, 32); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, 0xE28F0001, 0, NULL, 0); /* add r0,pc,#1 */ arm9tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDMIA(0, 0x1), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, r0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); pc = (pc & 2) >> 1; arm9tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7e9 + pc), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 1); arm7_9->need_bypass_before_restart = 1; } static int feroceon_read_cp15(struct target *target, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; int err; arm9tdmi_clock_out(jtag_info, ARMV4_5_MRC(15, op1, 0, crn, crm, op2), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); err = arm7_9_execute_sys_speed(target); if (err != ERROR_OK) return err; arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, 1, 0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, value, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); return jtag_execute_queue(); } static int feroceon_write_cp15(struct target *target, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 1, 0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, value, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_MCR(15, op1, 0, crn, crm, op2), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); return arm7_9_execute_sys_speed(target); } static void feroceon_set_dbgrq(struct target *target) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; buf_set_u32(dbg_ctrl->value, 0, 8, 2); embeddedice_store_reg(dbg_ctrl); } static void feroceon_enable_single_step(struct target *target, uint32_t next_pc) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; /* set a breakpoint there */ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE], next_pc); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x100); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], 0xf7); } static void feroceon_disable_single_step(struct target *target) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE]); } static int feroceon_examine_debug_reason(struct target *target) { /* the MOE is not implemented */ if (target->debug_reason != DBG_REASON_SINGLESTEP) target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int feroceon_bulk_write_memory(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer) { int retval; struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; enum arm_state core_state = arm->core_state; uint32_t x, flip, shift, save[7]; uint32_t i; /* * We can't use the dcc flow control bits, so let's transfer data * with 31 bits and flip the MSB each time a new data word is sent. */ static uint32_t dcc_code[] = { 0xee115e10, /* 3: mrc p14, 0, r5, c1, c0, 0 */ 0xe3a0301e, /* 1: mov r3, #30 */ 0xe3a04002, /* mov r4, #2 */ 0xee111e10, /* 2: mrc p14, 0, r1, c1, c0, 0 */ 0xe1310005, /* teq r1, r5 */ 0x0afffffc, /* beq 1b */ 0xe1a05001, /* mov r5, r1 */ 0xe1a01081, /* mov r1, r1, lsl #1 */ 0xee112e10, /* 3: mrc p14, 0, r2, c1, c0, 0 */ 0xe1320005, /* teq r2, r5 */ 0x0afffffc, /* beq 3b */ 0xe1a05002, /* mov r5, r2 */ 0xe3c22102, /* bic r2, r2, #0x80000000 */ 0xe1811332, /* orr r1, r1, r2, lsr r3 */ 0xe2533001, /* subs r3, r3, #1 */ 0xe4801004, /* str r1, [r0], #4 */ 0xe1a01412, /* mov r1, r2, lsl r4 */ 0xe2844001, /* add r4, r4, #1 */ 0x4affffed, /* bmi 1b */ 0xeafffff3, /* b 3b */ }; uint32_t dcc_size = sizeof(dcc_code); if (address % 4 != 0) return ERROR_TARGET_UNALIGNED_ACCESS; if (!arm7_9->dcc_downloads) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* regrab previously allocated working_area, or allocate a new one */ if (!arm7_9->dcc_working_area) { uint8_t dcc_code_buf[dcc_size]; /* make sure we have a working area */ if (target_alloc_working_area(target, dcc_size, &arm7_9->dcc_working_area) != ERROR_OK) { LOG_INFO("no working area available, falling back to memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* copy target instructions to target endianness */ target_buffer_set_u32_array(target, dcc_code_buf, ARRAY_SIZE(dcc_code), dcc_code); /* write DCC code to working area, using the non-optimized * memory write to avoid ending up here again */ retval = arm7_9_write_memory_no_opt(target, arm7_9->dcc_working_area->address, 4, dcc_size/4, dcc_code_buf); if (retval != ERROR_OK) return retval; } /* backup clobbered processor state */ for (i = 0; i <= 5; i++) save[i] = buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32); save[i] = buf_get_u32(arm->pc->value, 0, 32); /* set up target address in r0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, address); arm->core_cache->reg_list[0].valid = true; arm->core_cache->reg_list[0].dirty = true; arm->core_state = ARM_STATE_ARM; embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], 0); arm7_9_resume(target, 0, arm7_9->dcc_working_area->address, 1, 1); /* send data over */ x = 0; flip = 0; shift = 1; for (i = 0; i < count; i++) { uint32_t y = target_buffer_get_u32(target, buffer); uint32_t z = (x >> 1) | (y >> shift) | (flip ^= 0x80000000); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], z); x = y << (32 - shift); if (++shift >= 32 || i + 1 >= count) { z = (x >> 1) | (flip ^= 0x80000000); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], z); x = 0; shift = 1; } buffer += 4; } retval = target_halt(target); if (retval == ERROR_OK) retval = target_wait_state(target, TARGET_HALTED, 500); if (retval == ERROR_OK) { uint32_t endaddress = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32); if (endaddress != address + count*4) { LOG_ERROR("DCC write failed," " expected end address 0x%08" TARGET_PRIxADDR " got 0x%0" PRIx32 "", address + count*4, endaddress); retval = ERROR_FAIL; } } /* restore target state */ for (i = 0; i <= 5; i++) { buf_set_u32(arm->core_cache->reg_list[i].value, 0, 32, save[i]); arm->core_cache->reg_list[i].valid = true; arm->core_cache->reg_list[i].dirty = true; } buf_set_u32(arm->pc->value, 0, 32, save[i]); arm->pc->valid = true; arm->pc->dirty = true; arm->core_state = core_state; return retval; } static int feroceon_init_target(struct command_context *cmd_ctx, struct target *target) { arm9tdmi_init_target(cmd_ctx, target); return ERROR_OK; } static void feroceon_deinit_target(struct target *target) { arm9tdmi_deinit_target(target); } static void feroceon_common_setup(struct target *target) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; /* override some insn sequence functions */ arm7_9->change_to_arm = feroceon_change_to_arm; arm7_9->read_core_regs = feroceon_read_core_regs; arm7_9->read_core_regs_target_buffer = feroceon_read_core_regs_target_buffer; arm7_9->read_xpsr = feroceon_read_xpsr; arm7_9->write_xpsr = feroceon_write_xpsr; arm7_9->write_xpsr_im8 = feroceon_write_xpsr_im8; arm7_9->write_core_regs = feroceon_write_core_regs; arm7_9->branch_resume = feroceon_branch_resume; arm7_9->branch_resume_thumb = feroceon_branch_resume_thumb; /* must be implemented with only one comparator */ arm7_9->enable_single_step = feroceon_enable_single_step; arm7_9->disable_single_step = feroceon_disable_single_step; arm7_9->bulk_write_memory = feroceon_bulk_write_memory; /* MOE is not implemented */ arm7_9->examine_debug_reason = feroceon_examine_debug_reason; /* Note: asserting DBGRQ might not win over the undef exception. If that happens then just use "arm7_9 dbgrq disable". */ arm7_9->use_dbgrq = 1; arm7_9->set_special_dbgrq = feroceon_set_dbgrq; /* only one working comparator */ arm7_9->wp_available_max = 1; arm7_9->wp1_used_default = -1; } static int feroceon_target_create(struct target *target, Jim_Interp *interp) { struct arm926ejs_common *arm926ejs = calloc(1, sizeof(struct arm926ejs_common)); arm926ejs_init_arch_info(target, arm926ejs, target->tap); feroceon_common_setup(target); struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; arm7_9->write_memory = arm926ejs_write_memory; /* the standard ARM926 methods don't always work (don't ask...) */ arm926ejs->read_cp15 = feroceon_read_cp15; arm926ejs->write_cp15 = feroceon_write_cp15; return ERROR_OK; } static int dragonite_target_create(struct target *target, Jim_Interp *interp) { struct arm966e_common *arm966e = calloc(1, sizeof(struct arm966e_common)); arm966e_init_arch_info(target, arm966e, target->tap); feroceon_common_setup(target); struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; arm7_9->write_memory = arm7_9_write_memory; return ERROR_OK; } static int feroceon_examine(struct target *target) { struct arm *arm; struct arm7_9_common *arm7_9; int retval; retval = arm7_9_examine(target); if (retval != ERROR_OK) return retval; arm = target->arch_info; arm7_9 = arm->arch_info; /* the COMMS_CTRL bits are all contiguous */ if (buf_get_u32(arm7_9->eice_cache->reg_list[EICE_COMMS_CTRL].value, 2, 4) != 6) LOG_ERROR("unexpected Feroceon EICE version signature"); arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].size = 6; arm7_9->eice_cache->reg_list[EICE_DBG_STAT].size = 5; arm7_9->has_monitor_mode = 1; /* vector catch reg is not initialized on reset */ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_VEC_CATCH], 0); /* clear monitor mode, enable comparators */ embeddedice_read_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]); jtag_execute_queue(); buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 4, 1, 0); buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 5, 1, 0); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]); return ERROR_OK; } struct target_type feroceon_target = { .name = "feroceon", .poll = arm7_9_poll, .arch_state = arm926ejs_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = feroceon_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm926ejs_soft_reset_halt, .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm7_9_read_memory, .write_memory = arm7_9_write_memory_opt, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm926ejs_command_handlers, .target_create = feroceon_target_create, .init_target = feroceon_init_target, .deinit_target = feroceon_deinit_target, .examine = feroceon_examine, }; struct target_type dragonite_target = { .name = "dragonite", .poll = arm7_9_poll, .arch_state = arm_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = feroceon_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm7_9_soft_reset_halt, .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm7_9_read_memory, .write_memory = arm7_9_write_memory_opt, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm966e_command_handlers, .target_create = dragonite_target_create, .init_target = feroceon_init_target, .examine = feroceon_examine, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/hla_target.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * * * * Copyright (C) 2011 by Spencer Oliver * * spen@spen-soft.co.uk * * * * revised: 4/25/13 by brent@mbari.org [DCC target request support] * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/interface.h" #include "jtag/jtag.h" #include "jtag/hla/hla_transport.h" #include "jtag/hla/hla_interface.h" #include "jtag/hla/hla_layout.h" #include "register.h" #include "algorithm.h" #include "target.h" #include "breakpoints.h" #include "target_type.h" #include "armv7m.h" #include "cortex_m.h" #include "arm_adi_v5.h" #include "arm_semihosting.h" #include "target_request.h" #include <rtt/rtt.h> #define SAVED_DCRDR dbgbase /* FIXME: using target->dbgbase to preserve DCRDR */ #define ARMV7M_SCS_DCRSR DCB_DCRSR #define ARMV7M_SCS_DCRDR DCB_DCRDR static inline struct hl_interface_s *target_to_adapter(struct target *target) { return target->tap->priv; } static int adapter_load_core_reg_u32(struct target *target, uint32_t regsel, uint32_t *value) { struct hl_interface_s *adapter = target_to_adapter(target); return adapter->layout->api->read_reg(adapter->handle, regsel, value); } static int adapter_store_core_reg_u32(struct target *target, uint32_t regsel, uint32_t value) { struct hl_interface_s *adapter = target_to_adapter(target); return adapter->layout->api->write_reg(adapter->handle, regsel, value); } static int adapter_examine_debug_reason(struct target *target) { if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) { target->debug_reason = DBG_REASON_BREAKPOINT; } return ERROR_OK; } static int hl_dcc_read(struct hl_interface_s *hl_if, uint8_t *value, uint8_t *ctrl) { uint16_t dcrdr; int retval = hl_if->layout->api->read_mem(hl_if->handle, DCB_DCRDR, 1, sizeof(dcrdr), (uint8_t *)&dcrdr); if (retval == ERROR_OK) { *ctrl = (uint8_t)dcrdr; *value = (uint8_t)(dcrdr >> 8); LOG_DEBUG("data 0x%x ctrl 0x%x", *value, *ctrl); if (dcrdr & 1) { /* write ack back to software dcc register * to signify we have read data */ /* atomically clear just the byte containing the busy bit */ static const uint8_t zero; retval = hl_if->layout->api->write_mem(hl_if->handle, DCB_DCRDR, 1, 1, &zero); } } return retval; } static int hl_target_request_data(struct target *target, uint32_t size, uint8_t *buffer) { struct hl_interface_s *hl_if = target_to_adapter(target); uint8_t data; uint8_t ctrl; uint32_t i; for (i = 0; i < (size * 4); i++) { int err = hl_dcc_read(hl_if, &data, &ctrl); if (err != ERROR_OK) return err; buffer[i] = data; } return ERROR_OK; } static int hl_handle_target_request(void *priv) { struct target *target = priv; int err; if (!target_was_examined(target)) return ERROR_OK; struct hl_interface_s *hl_if = target_to_adapter(target); if (!target->dbg_msg_enabled) return ERROR_OK; if (target->state == TARGET_RUNNING) { uint8_t data; uint8_t ctrl; err = hl_dcc_read(hl_if, &data, &ctrl); if (err != ERROR_OK) return err; /* check if we have data */ if (ctrl & (1 << 0)) { uint32_t request; /* we assume target is quick enough */ request = data; err = hl_dcc_read(hl_if, &data, &ctrl); if (err != ERROR_OK) return err; request |= (data << 8); err = hl_dcc_read(hl_if, &data, &ctrl); if (err != ERROR_OK) return err; request |= (data << 16); err = hl_dcc_read(hl_if, &data, &ctrl); if (err != ERROR_OK) return err; request |= (data << 24); target_request(target, request); } } return ERROR_OK; } static int adapter_init_arch_info(struct target *target, struct cortex_m_common *cortex_m, struct jtag_tap *tap) { struct armv7m_common *armv7m; LOG_DEBUG("%s", __func__); armv7m = &cortex_m->armv7m; armv7m_init_arch_info(target, armv7m); armv7m->load_core_reg_u32 = adapter_load_core_reg_u32; armv7m->store_core_reg_u32 = adapter_store_core_reg_u32; armv7m->examine_debug_reason = adapter_examine_debug_reason; armv7m->is_hla_target = true; target_register_timer_callback(hl_handle_target_request, 1, TARGET_TIMER_TYPE_PERIODIC, target); return ERROR_OK; } static int adapter_init_target(struct command_context *cmd_ctx, struct target *target) { LOG_DEBUG("%s", __func__); armv7m_build_reg_cache(target); arm_semihosting_init(target); return ERROR_OK; } static int adapter_target_create(struct target *target, Jim_Interp *interp) { LOG_DEBUG("%s", __func__); struct adiv5_private_config *pc = target->private_config; if (pc && pc->ap_num != DP_APSEL_INVALID && pc->ap_num != 0) { LOG_ERROR("hla_target: invalid parameter -ap-num (> 0)"); return ERROR_COMMAND_SYNTAX_ERROR; } struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common)); if (!cortex_m) { LOG_ERROR("No memory creating target"); return ERROR_FAIL; } cortex_m->common_magic = CORTEX_M_COMMON_MAGIC; adapter_init_arch_info(target, cortex_m, target->tap); return ERROR_OK; } static int adapter_load_context(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); int num_regs = armv7m->arm.core_cache->num_regs; for (int i = 0; i < num_regs; i++) { struct reg *r = &armv7m->arm.core_cache->reg_list[i]; if (r->exist && !r->valid) armv7m->arm.read_core_reg(target, r, i, ARM_MODE_ANY); } return ERROR_OK; } static int adapter_debug_entry(struct target *target) { struct hl_interface_s *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); struct arm *arm = &armv7m->arm; struct reg *r; uint32_t xpsr; int retval; /* preserve the DCRDR across halts */ retval = target_read_u32(target, DCB_DCRDR, &target->SAVED_DCRDR); if (retval != ERROR_OK) return retval; retval = armv7m->examine_debug_reason(target); if (retval != ERROR_OK) return retval; adapter_load_context(target); /* make sure we clear the vector catch bit */ adapter->layout->api->write_debug_reg(adapter->handle, DCB_DEMCR, TRCENA); r = arm->cpsr; xpsr = buf_get_u32(r->value, 0, 32); /* Are we in an exception handler */ if (xpsr & 0x1FF) { armv7m->exception_number = (xpsr & 0x1FF); arm->core_mode = ARM_MODE_HANDLER; arm->map = armv7m_msp_reg_map; } else { unsigned control = buf_get_u32(arm->core_cache ->reg_list[ARMV7M_CONTROL].value, 0, 3); /* is this thread privileged? */ arm->core_mode = control & 1 ? ARM_MODE_USER_THREAD : ARM_MODE_THREAD; /* which stack is it using? */ if (control & 2) arm->map = armv7m_psp_reg_map; else arm->map = armv7m_msp_reg_map; armv7m->exception_number = 0; } LOG_DEBUG("entered debug state in core mode: %s at PC 0x%08" PRIx32 ", target->state: %s", arm_mode_name(arm->core_mode), buf_get_u32(arm->pc->value, 0, 32), target_state_name(target)); return retval; } static int adapter_poll(struct target *target) { enum target_state state; struct hl_interface_s *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); enum target_state prev_target_state = target->state; state = adapter->layout->api->state(adapter->handle); if (state == TARGET_UNKNOWN) { LOG_ERROR("jtag status contains invalid mode value - communication failure"); return ERROR_TARGET_FAILURE; } if (prev_target_state == state) return ERROR_OK; if (prev_target_state == TARGET_DEBUG_RUNNING && state == TARGET_RUNNING) return ERROR_OK; target->state = state; if (state == TARGET_HALTED) { int retval = adapter_debug_entry(target); if (retval != ERROR_OK) return retval; if (prev_target_state == TARGET_DEBUG_RUNNING) { target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } else { if (arm_semihosting(target, &retval) != 0) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); } LOG_DEBUG("halted: PC: 0x%08" PRIx32, buf_get_u32(armv7m->arm.pc->value, 0, 32)); } return ERROR_OK; } static int hl_assert_reset(struct target *target) { int res = ERROR_OK; struct hl_interface_s *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); bool use_srst_fallback = true; LOG_DEBUG("%s", __func__); enum reset_types jtag_reset_config = jtag_get_reset_config(); bool srst_asserted = false; if ((jtag_reset_config & RESET_HAS_SRST) && (jtag_reset_config & RESET_SRST_NO_GATING)) { res = adapter_assert_reset(); srst_asserted = true; } adapter->layout->api->write_debug_reg(adapter->handle, DCB_DHCSR, DBGKEY|C_DEBUGEN); if (!target_was_examined(target) && !target->defer_examine && srst_asserted && res == ERROR_OK) { /* If the target is not examined, now under reset it is good time to retry examination */ LOG_TARGET_DEBUG(target, "Trying to re-examine under reset"); target_examine_one(target); } /* only set vector catch if halt is requested */ if (target->reset_halt) adapter->layout->api->write_debug_reg(adapter->handle, DCB_DEMCR, TRCENA|VC_CORERESET); else adapter->layout->api->write_debug_reg(adapter->handle, DCB_DEMCR, TRCENA); if (jtag_reset_config & RESET_HAS_SRST) { if (!srst_asserted) { res = adapter_assert_reset(); } if (res == ERROR_COMMAND_NOTFOUND) LOG_ERROR("Hardware srst not supported, falling back to software reset"); else if (res == ERROR_OK) { /* hardware srst supported */ use_srst_fallback = false; } } if (use_srst_fallback) { /* stlink v1 api does not support hardware srst, so we use a software reset fallback */ adapter->layout->api->write_debug_reg(adapter->handle, NVIC_AIRCR, AIRCR_VECTKEY | AIRCR_SYSRESETREQ); } res = adapter->layout->api->reset(adapter->handle); if (res != ERROR_OK) return res; /* registers are now invalid */ register_cache_invalidate(armv7m->arm.core_cache); if (target->reset_halt) { target->state = TARGET_RESET; target->debug_reason = DBG_REASON_DBGRQ; } else { target->state = TARGET_HALTED; } return ERROR_OK; } static int hl_deassert_reset(struct target *target) { enum reset_types jtag_reset_config = jtag_get_reset_config(); LOG_DEBUG("%s", __func__); if (jtag_reset_config & RESET_HAS_SRST) adapter_deassert_reset(); target->SAVED_DCRDR = 0; /* clear both DCC busy bits on initial resume */ return target->reset_halt ? ERROR_OK : target_resume(target, 1, 0, 0, 0); } static int adapter_halt(struct target *target) { int res; struct hl_interface_s *adapter = target_to_adapter(target); LOG_DEBUG("%s", __func__); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); res = adapter->layout->api->halt(adapter->handle); if (res != ERROR_OK) return res; target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int adapter_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { int res; struct hl_interface_s *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); uint32_t resume_pc; struct breakpoint *breakpoint = NULL; struct reg *pc; LOG_DEBUG("%s %d " TARGET_ADDR_FMT " %d %d", __func__, current, address, handle_breakpoints, debug_execution); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) { target_free_all_working_areas(target); cortex_m_enable_breakpoints(target); cortex_m_enable_watchpoints(target); } pc = armv7m->arm.pc; if (!current) { buf_set_u32(pc->value, 0, 32, address); pc->dirty = true; pc->valid = true; } if (!breakpoint_find(target, buf_get_u32(pc->value, 0, 32)) && !debug_execution) { armv7m_maybe_skip_bkpt_inst(target, NULL); } resume_pc = buf_get_u32(pc->value, 0, 32); /* write any user vector flags */ res = target_write_u32(target, DCB_DEMCR, TRCENA | armv7m->demcr); if (res != ERROR_OK) return res; armv7m_restore_context(target); /* restore SAVED_DCRDR */ res = target_write_u32(target, DCB_DCRDR, target->SAVED_DCRDR); if (res != ERROR_OK) return res; /* registers are now invalid */ register_cache_invalidate(armv7m->arm.core_cache); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")", breakpoint->address, breakpoint->unique_id); cortex_m_unset_breakpoint(target, breakpoint); res = adapter->layout->api->step(adapter->handle); if (res != ERROR_OK) return res; cortex_m_set_breakpoint(target, breakpoint); } } res = adapter->layout->api->run(adapter->handle); if (res != ERROR_OK) return res; target->debug_reason = DBG_REASON_NOTHALTED; if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); } return ERROR_OK; } static int adapter_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { int res; struct hl_interface_s *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); struct breakpoint *breakpoint = NULL; struct reg *pc = armv7m->arm.pc; bool bkpt_inst_found = false; LOG_DEBUG("%s", __func__); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!current) { buf_set_u32(pc->value, 0, 32, address); pc->dirty = true; pc->valid = true; } uint32_t pc_value = buf_get_u32(pc->value, 0, 32); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { breakpoint = breakpoint_find(target, pc_value); if (breakpoint) cortex_m_unset_breakpoint(target, breakpoint); } armv7m_maybe_skip_bkpt_inst(target, &bkpt_inst_found); target->debug_reason = DBG_REASON_SINGLESTEP; armv7m_restore_context(target); /* restore SAVED_DCRDR */ res = target_write_u32(target, DCB_DCRDR, target->SAVED_DCRDR); if (res != ERROR_OK) return res; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); res = adapter->layout->api->step(adapter->handle); if (res != ERROR_OK) return res; /* registers are now invalid */ register_cache_invalidate(armv7m->arm.core_cache); if (breakpoint) cortex_m_set_breakpoint(target, breakpoint); adapter_debug_entry(target); target_call_event_callbacks(target, TARGET_EVENT_HALTED); LOG_INFO("halted: PC: 0x%08" PRIx32, buf_get_u32(armv7m->arm.pc->value, 0, 32)); return ERROR_OK; } static int adapter_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct hl_interface_s *adapter = target_to_adapter(target); if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; LOG_DEBUG("%s " TARGET_ADDR_FMT " %" PRIu32 " %" PRIu32, __func__, address, size, count); return adapter->layout->api->read_mem(adapter->handle, address, size, count, buffer); } static int adapter_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct hl_interface_s *adapter = target_to_adapter(target); if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; LOG_DEBUG("%s " TARGET_ADDR_FMT " %" PRIu32 " %" PRIu32, __func__, address, size, count); return adapter->layout->api->write_mem(adapter->handle, address, size, count, buffer); } static const struct command_registration hla_command_handlers[] = { { .chain = arm_command_handlers, }, { .chain = armv7m_trace_command_handlers, }, { .chain = rtt_target_command_handlers, }, /* START_DEPRECATED_TPIU */ { .chain = arm_tpiu_deprecated_command_handlers, }, /* END_DEPRECATED_TPIU */ COMMAND_REGISTRATION_DONE }; struct target_type hla_target = { .name = "hla_target", .init_target = adapter_init_target, .deinit_target = cortex_m_deinit_target, .target_create = adapter_target_create, .target_jim_configure = adiv5_jim_configure, .examine = cortex_m_examine, .commands = hla_command_handlers, .poll = adapter_poll, .arch_state = armv7m_arch_state, .target_request_data = hl_target_request_data, .assert_reset = hl_assert_reset, .deassert_reset = hl_deassert_reset, .halt = adapter_halt, .resume = adapter_resume, .step = adapter_step, .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = armv7m_get_gdb_reg_list, .read_memory = adapter_read_memory, .write_memory = adapter_write_memory, .checksum_memory = armv7m_checksum_memory, .blank_check_memory = armv7m_blank_check_memory, .run_algorithm = armv7m_run_algorithm, .start_algorithm = armv7m_start_algorithm, .wait_algorithm = armv7m_wait_algorithm, .add_breakpoint = cortex_m_add_breakpoint, .remove_breakpoint = cortex_m_remove_breakpoint, .add_watchpoint = cortex_m_add_watchpoint, .remove_watchpoint = cortex_m_remove_watchpoint, .profiling = cortex_m_profiling, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/image.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2009 by Franck Hereson * * franck.hereson@secad.fr * * * * Copyright (C) 2018 by Advantest * * florian.meister@advantest.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "image.h" #include "target.h" #include <helper/log.h> /* convert ELF header field to host endianness */ #define field16(elf, field) \ ((elf->endianness == ELFDATA2LSB) ? \ le_to_h_u16((uint8_t *)&field) : be_to_h_u16((uint8_t *)&field)) #define field32(elf, field) \ ((elf->endianness == ELFDATA2LSB) ? \ le_to_h_u32((uint8_t *)&field) : be_to_h_u32((uint8_t *)&field)) #define field64(elf, field) \ ((elf->endianness == ELFDATA2LSB) ? \ le_to_h_u64((uint8_t *)&field) : be_to_h_u64((uint8_t *)&field)) static int autodetect_image_type(struct image *image, const char *url) { int retval; struct fileio *fileio; size_t read_bytes; uint8_t buffer[9]; /* read the first 9 bytes of image */ retval = fileio_open(&fileio, url, FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) return retval; retval = fileio_read(fileio, 9, buffer, &read_bytes); if (retval == ERROR_OK) { if (read_bytes != 9) retval = ERROR_FILEIO_OPERATION_FAILED; } fileio_close(fileio); if (retval != ERROR_OK) return retval; /* check header against known signatures */ if (strncmp((char *)buffer, ELFMAG, SELFMAG) == 0) { LOG_DEBUG("ELF image detected."); image->type = IMAGE_ELF; } else if ((buffer[0] == ':') /* record start byte */ && (isxdigit(buffer[1])) && (isxdigit(buffer[2])) && (isxdigit(buffer[3])) && (isxdigit(buffer[4])) && (isxdigit(buffer[5])) && (isxdigit(buffer[6])) && (buffer[7] == '0') /* record type : 00 -> 05 */ && (buffer[8] >= '0') && (buffer[8] < '6')) { LOG_DEBUG("IHEX image detected."); image->type = IMAGE_IHEX; } else if ((buffer[0] == 'S') /* record start byte */ && (isxdigit(buffer[1])) && (isxdigit(buffer[2])) && (isxdigit(buffer[3])) && (buffer[1] >= '0') && (buffer[1] < '9')) { LOG_DEBUG("S19 image detected."); image->type = IMAGE_SRECORD; } else image->type = IMAGE_BINARY; return ERROR_OK; } static int identify_image_type(struct image *image, const char *type_string, const char *url) { if (type_string) { if (!strcmp(type_string, "bin")) image->type = IMAGE_BINARY; else if (!strcmp(type_string, "ihex")) image->type = IMAGE_IHEX; else if (!strcmp(type_string, "elf")) image->type = IMAGE_ELF; else if (!strcmp(type_string, "mem")) image->type = IMAGE_MEMORY; else if (!strcmp(type_string, "s19")) image->type = IMAGE_SRECORD; else if (!strcmp(type_string, "build")) image->type = IMAGE_BUILDER; else return ERROR_IMAGE_TYPE_UNKNOWN; } else return autodetect_image_type(image, url); return ERROR_OK; } static int image_ihex_buffer_complete_inner(struct image *image, char *lpsz_line, struct imagesection *section) { struct image_ihex *ihex = image->type_private; struct fileio *fileio = ihex->fileio; uint32_t full_address; uint32_t cooked_bytes; bool end_rec = false; /* we can't determine the number of sections that we'll have to create ahead of time, * so we locally hold them until parsing is finished */ size_t filesize; int retval; retval = fileio_size(fileio, &filesize); if (retval != ERROR_OK) return retval; ihex->buffer = malloc(filesize >> 1); cooked_bytes = 0x0; image->num_sections = 0; while (!fileio_feof(fileio)) { full_address = 0x0; section[image->num_sections].private = &ihex->buffer[cooked_bytes]; section[image->num_sections].base_address = 0x0; section[image->num_sections].size = 0x0; section[image->num_sections].flags = 0; while (fileio_fgets(fileio, 1023, lpsz_line) == ERROR_OK) { uint32_t count; uint32_t address; uint32_t record_type; uint32_t checksum; uint8_t cal_checksum = 0; size_t bytes_read = 0; /* skip comments and blank lines */ if ((lpsz_line[0] == '#') || (strlen(lpsz_line + strspn(lpsz_line, "\n\t\r ")) == 0)) continue; if (sscanf(&lpsz_line[bytes_read], ":%2" SCNx32 "%4" SCNx32 "%2" SCNx32, &count, &address, &record_type) != 3) return ERROR_IMAGE_FORMAT_ERROR; bytes_read += 9; cal_checksum += (uint8_t)count; cal_checksum += (uint8_t)(address >> 8); cal_checksum += (uint8_t)address; cal_checksum += (uint8_t)record_type; if (record_type == 0) { /* Data Record */ if ((full_address & 0xffff) != address) { /* we encountered a nonconsecutive location, create a new section, * unless the current section has zero size, in which case this specifies * the current section's base address */ if (section[image->num_sections].size != 0) { image->num_sections++; if (image->num_sections >= IMAGE_MAX_SECTIONS) { /* too many sections */ LOG_ERROR("Too many sections found in IHEX file"); return ERROR_IMAGE_FORMAT_ERROR; } section[image->num_sections].size = 0x0; section[image->num_sections].flags = 0; section[image->num_sections].private = &ihex->buffer[cooked_bytes]; } section[image->num_sections].base_address = (full_address & 0xffff0000) | address; full_address = (full_address & 0xffff0000) | address; } while (count-- > 0) { unsigned value; sscanf(&lpsz_line[bytes_read], "%2x", &value); ihex->buffer[cooked_bytes] = (uint8_t)value; cal_checksum += (uint8_t)ihex->buffer[cooked_bytes]; bytes_read += 2; cooked_bytes += 1; section[image->num_sections].size += 1; full_address++; } } else if (record_type == 1) { /* End of File Record */ /* finish the current section */ image->num_sections++; /* copy section information */ image->sections = malloc(sizeof(struct imagesection) * image->num_sections); for (unsigned int i = 0; i < image->num_sections; i++) { image->sections[i].private = section[i].private; image->sections[i].base_address = section[i].base_address; image->sections[i].size = section[i].size; image->sections[i].flags = section[i].flags; } end_rec = true; break; } else if (record_type == 2) { /* Linear Address Record */ uint16_t upper_address; sscanf(&lpsz_line[bytes_read], "%4hx", &upper_address); cal_checksum += (uint8_t)(upper_address >> 8); cal_checksum += (uint8_t)upper_address; bytes_read += 4; if ((full_address >> 4) != upper_address) { /* we encountered a nonconsecutive location, create a new section, * unless the current section has zero size, in which case this specifies * the current section's base address */ if (section[image->num_sections].size != 0) { image->num_sections++; if (image->num_sections >= IMAGE_MAX_SECTIONS) { /* too many sections */ LOG_ERROR("Too many sections found in IHEX file"); return ERROR_IMAGE_FORMAT_ERROR; } section[image->num_sections].size = 0x0; section[image->num_sections].flags = 0; section[image->num_sections].private = &ihex->buffer[cooked_bytes]; } section[image->num_sections].base_address = (full_address & 0xffff) | (upper_address << 4); full_address = (full_address & 0xffff) | (upper_address << 4); } } else if (record_type == 3) { /* Start Segment Address Record */ uint32_t dummy; /* "Start Segment Address Record" will not be supported * but we must consume it, and do not create an error. */ while (count-- > 0) { sscanf(&lpsz_line[bytes_read], "%2" SCNx32, &dummy); cal_checksum += (uint8_t)dummy; bytes_read += 2; } } else if (record_type == 4) { /* Extended Linear Address Record */ uint16_t upper_address; sscanf(&lpsz_line[bytes_read], "%4hx", &upper_address); cal_checksum += (uint8_t)(upper_address >> 8); cal_checksum += (uint8_t)upper_address; bytes_read += 4; if ((full_address >> 16) != upper_address) { /* we encountered a nonconsecutive location, create a new section, * unless the current section has zero size, in which case this specifies * the current section's base address */ if (section[image->num_sections].size != 0) { image->num_sections++; if (image->num_sections >= IMAGE_MAX_SECTIONS) { /* too many sections */ LOG_ERROR("Too many sections found in IHEX file"); return ERROR_IMAGE_FORMAT_ERROR; } section[image->num_sections].size = 0x0; section[image->num_sections].flags = 0; section[image->num_sections].private = &ihex->buffer[cooked_bytes]; } section[image->num_sections].base_address = (full_address & 0xffff) | (upper_address << 16); full_address = (full_address & 0xffff) | (upper_address << 16); } } else if (record_type == 5) { /* Start Linear Address Record */ uint32_t start_address; sscanf(&lpsz_line[bytes_read], "%8" SCNx32, &start_address); cal_checksum += (uint8_t)(start_address >> 24); cal_checksum += (uint8_t)(start_address >> 16); cal_checksum += (uint8_t)(start_address >> 8); cal_checksum += (uint8_t)start_address; bytes_read += 8; image->start_address_set = true; image->start_address = be_to_h_u32((uint8_t *)&start_address); } else { LOG_ERROR("unhandled IHEX record type: %i", (int)record_type); return ERROR_IMAGE_FORMAT_ERROR; } sscanf(&lpsz_line[bytes_read], "%2" SCNx32, &checksum); if ((uint8_t)checksum != (uint8_t)(~cal_checksum + 1)) { /* checksum failed */ LOG_ERROR("incorrect record checksum found in IHEX file"); return ERROR_IMAGE_CHECKSUM; } if (end_rec) { end_rec = false; LOG_WARNING("continuing after end-of-file record: %.40s", lpsz_line); } } } if (end_rec) return ERROR_OK; else { LOG_ERROR("premature end of IHEX file, no matching end-of-file record found"); return ERROR_IMAGE_FORMAT_ERROR; } } /** * Allocate memory dynamically instead of on the stack. This * is important w/embedded hosts. */ static int image_ihex_buffer_complete(struct image *image) { char *lpsz_line = malloc(1023); if (!lpsz_line) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } struct imagesection *section = malloc(sizeof(struct imagesection) * IMAGE_MAX_SECTIONS); if (!section) { free(lpsz_line); LOG_ERROR("Out of memory"); return ERROR_FAIL; } int retval; retval = image_ihex_buffer_complete_inner(image, lpsz_line, section); free(section); free(lpsz_line); return retval; } static int image_elf32_read_headers(struct image *image) { struct image_elf *elf = image->type_private; size_t read_bytes; uint32_t i, j; int retval; uint32_t nload; bool load_to_vaddr = false; retval = fileio_seek(elf->fileio, 0); if (retval != ERROR_OK) { LOG_ERROR("cannot seek to ELF file header, read failed"); return retval; } elf->header32 = malloc(sizeof(Elf32_Ehdr)); if (!elf->header32) { LOG_ERROR("insufficient memory to perform operation"); return ERROR_FILEIO_OPERATION_FAILED; } retval = fileio_read(elf->fileio, sizeof(Elf32_Ehdr), (uint8_t *)elf->header32, &read_bytes); if (retval != ERROR_OK) { LOG_ERROR("cannot read ELF file header, read failed"); return ERROR_FILEIO_OPERATION_FAILED; } if (read_bytes != sizeof(Elf32_Ehdr)) { LOG_ERROR("cannot read ELF file header, only partially read"); return ERROR_FILEIO_OPERATION_FAILED; } elf->segment_count = field16(elf, elf->header32->e_phnum); if (elf->segment_count == 0) { LOG_ERROR("invalid ELF file, no program headers"); return ERROR_IMAGE_FORMAT_ERROR; } retval = fileio_seek(elf->fileio, field32(elf, elf->header32->e_phoff)); if (retval != ERROR_OK) { LOG_ERROR("cannot seek to ELF program header table, read failed"); return retval; } elf->segments32 = malloc(elf->segment_count*sizeof(Elf32_Phdr)); if (!elf->segments32) { LOG_ERROR("insufficient memory to perform operation"); return ERROR_FILEIO_OPERATION_FAILED; } retval = fileio_read(elf->fileio, elf->segment_count*sizeof(Elf32_Phdr), (uint8_t *)elf->segments32, &read_bytes); if (retval != ERROR_OK) { LOG_ERROR("cannot read ELF segment headers, read failed"); return retval; } if (read_bytes != elf->segment_count*sizeof(Elf32_Phdr)) { LOG_ERROR("cannot read ELF segment headers, only partially read"); return ERROR_FILEIO_OPERATION_FAILED; } /* count useful segments (loadable), ignore BSS section */ image->num_sections = 0; for (i = 0; i < elf->segment_count; i++) if ((field32(elf, elf->segments32[i].p_type) == PT_LOAD) && (field32(elf, elf->segments32[i].p_filesz) != 0)) image->num_sections++; if (image->num_sections == 0) { LOG_ERROR("invalid ELF file, no loadable segments"); return ERROR_IMAGE_FORMAT_ERROR; } /** * some ELF linkers produce binaries with *all* the program header * p_paddr fields zero (there can be however one loadable segment * that has valid physical address 0x0). * If we have such a binary with more than * one PT_LOAD header, then use p_vaddr instead of p_paddr * (ARM ELF standard demands p_paddr = 0 anyway, and BFD * library uses this approach to workaround zero-initialized p_paddrs * when obtaining lma - look at elf.c of BDF) */ for (nload = 0, i = 0; i < elf->segment_count; i++) if (elf->segments32[i].p_paddr != 0) break; else if ((field32(elf, elf->segments32[i].p_type) == PT_LOAD) && (field32(elf, elf->segments32[i].p_memsz) != 0)) ++nload; if (i >= elf->segment_count && nload > 1) load_to_vaddr = true; /* alloc and fill sections array with loadable segments */ image->sections = malloc(image->num_sections * sizeof(struct imagesection)); if (!image->sections) { LOG_ERROR("insufficient memory to perform operation"); return ERROR_FILEIO_OPERATION_FAILED; } for (i = 0, j = 0; i < elf->segment_count; i++) { if ((field32(elf, elf->segments32[i].p_type) == PT_LOAD) && (field32(elf, elf->segments32[i].p_filesz) != 0)) { image->sections[j].size = field32(elf, elf->segments32[i].p_filesz); if (load_to_vaddr) image->sections[j].base_address = field32(elf, elf->segments32[i].p_vaddr); else image->sections[j].base_address = field32(elf, elf->segments32[i].p_paddr); image->sections[j].private = &elf->segments32[i]; image->sections[j].flags = field32(elf, elf->segments32[i].p_flags); j++; } } image->start_address_set = true; image->start_address = field32(elf, elf->header32->e_entry); return ERROR_OK; } static int image_elf64_read_headers(struct image *image) { struct image_elf *elf = image->type_private; size_t read_bytes; uint32_t i, j; int retval; uint32_t nload; bool load_to_vaddr = false; retval = fileio_seek(elf->fileio, 0); if (retval != ERROR_OK) { LOG_ERROR("cannot seek to ELF file header, read failed"); return retval; } elf->header64 = malloc(sizeof(Elf64_Ehdr)); if (!elf->header64) { LOG_ERROR("insufficient memory to perform operation"); return ERROR_FILEIO_OPERATION_FAILED; } retval = fileio_read(elf->fileio, sizeof(Elf64_Ehdr), (uint8_t *)elf->header64, &read_bytes); if (retval != ERROR_OK) { LOG_ERROR("cannot read ELF file header, read failed"); return ERROR_FILEIO_OPERATION_FAILED; } if (read_bytes != sizeof(Elf64_Ehdr)) { LOG_ERROR("cannot read ELF file header, only partially read"); return ERROR_FILEIO_OPERATION_FAILED; } elf->segment_count = field16(elf, elf->header64->e_phnum); if (elf->segment_count == 0) { LOG_ERROR("invalid ELF file, no program headers"); return ERROR_IMAGE_FORMAT_ERROR; } retval = fileio_seek(elf->fileio, field64(elf, elf->header64->e_phoff)); if (retval != ERROR_OK) { LOG_ERROR("cannot seek to ELF program header table, read failed"); return retval; } elf->segments64 = malloc(elf->segment_count*sizeof(Elf64_Phdr)); if (!elf->segments64) { LOG_ERROR("insufficient memory to perform operation"); return ERROR_FILEIO_OPERATION_FAILED; } retval = fileio_read(elf->fileio, elf->segment_count*sizeof(Elf64_Phdr), (uint8_t *)elf->segments64, &read_bytes); if (retval != ERROR_OK) { LOG_ERROR("cannot read ELF segment headers, read failed"); return retval; } if (read_bytes != elf->segment_count*sizeof(Elf64_Phdr)) { LOG_ERROR("cannot read ELF segment headers, only partially read"); return ERROR_FILEIO_OPERATION_FAILED; } /* count useful segments (loadable), ignore BSS section */ image->num_sections = 0; for (i = 0; i < elf->segment_count; i++) if ((field32(elf, elf->segments64[i].p_type) == PT_LOAD) && (field64(elf, elf->segments64[i].p_filesz) != 0)) image->num_sections++; if (image->num_sections == 0) { LOG_ERROR("invalid ELF file, no loadable segments"); return ERROR_IMAGE_FORMAT_ERROR; } /** * some ELF linkers produce binaries with *all* the program header * p_paddr fields zero (there can be however one loadable segment * that has valid physical address 0x0). * If we have such a binary with more than * one PT_LOAD header, then use p_vaddr instead of p_paddr * (ARM ELF standard demands p_paddr = 0 anyway, and BFD * library uses this approach to workaround zero-initialized p_paddrs * when obtaining lma - look at elf.c of BDF) */ for (nload = 0, i = 0; i < elf->segment_count; i++) if (elf->segments64[i].p_paddr != 0) break; else if ((field32(elf, elf->segments64[i].p_type) == PT_LOAD) && (field64(elf, elf->segments64[i].p_memsz) != 0)) ++nload; if (i >= elf->segment_count && nload > 1) load_to_vaddr = true; /* alloc and fill sections array with loadable segments */ image->sections = malloc(image->num_sections * sizeof(struct imagesection)); if (!image->sections) { LOG_ERROR("insufficient memory to perform operation"); return ERROR_FILEIO_OPERATION_FAILED; } for (i = 0, j = 0; i < elf->segment_count; i++) { if ((field32(elf, elf->segments64[i].p_type) == PT_LOAD) && (field64(elf, elf->segments64[i].p_filesz) != 0)) { image->sections[j].size = field64(elf, elf->segments64[i].p_filesz); if (load_to_vaddr) image->sections[j].base_address = field64(elf, elf->segments64[i].p_vaddr); else image->sections[j].base_address = field64(elf, elf->segments64[i].p_paddr); image->sections[j].private = &elf->segments64[i]; image->sections[j].flags = field64(elf, elf->segments64[i].p_flags); j++; } } image->start_address_set = true; image->start_address = field64(elf, elf->header64->e_entry); return ERROR_OK; } static int image_elf_read_headers(struct image *image) { struct image_elf *elf = image->type_private; size_t read_bytes; unsigned char e_ident[EI_NIDENT]; int retval; retval = fileio_read(elf->fileio, EI_NIDENT, e_ident, &read_bytes); if (retval != ERROR_OK) { LOG_ERROR("cannot read ELF file header, read failed"); return ERROR_FILEIO_OPERATION_FAILED; } if (read_bytes != EI_NIDENT) { LOG_ERROR("cannot read ELF file header, only partially read"); return ERROR_FILEIO_OPERATION_FAILED; } if (strncmp((char *)e_ident, ELFMAG, SELFMAG) != 0) { LOG_ERROR("invalid ELF file, bad magic number"); return ERROR_IMAGE_FORMAT_ERROR; } elf->endianness = e_ident[EI_DATA]; if ((elf->endianness != ELFDATA2LSB) && (elf->endianness != ELFDATA2MSB)) { LOG_ERROR("invalid ELF file, unknown endianness setting"); return ERROR_IMAGE_FORMAT_ERROR; } switch (e_ident[EI_CLASS]) { case ELFCLASS32: LOG_DEBUG("ELF32 image detected."); elf->is_64_bit = false; return image_elf32_read_headers(image); case ELFCLASS64: LOG_DEBUG("ELF64 image detected."); elf->is_64_bit = true; return image_elf64_read_headers(image); default: LOG_ERROR("invalid ELF file, only 32/64 bit ELF files are supported"); return ERROR_IMAGE_FORMAT_ERROR; } } static int image_elf32_read_section(struct image *image, int section, target_addr_t offset, uint32_t size, uint8_t *buffer, size_t *size_read) { struct image_elf *elf = image->type_private; Elf32_Phdr *segment = (Elf32_Phdr *)image->sections[section].private; size_t read_size, really_read; int retval; *size_read = 0; LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size); /* read initialized data in current segment if any */ if (offset < field32(elf, segment->p_filesz)) { /* maximal size present in file for the current segment */ read_size = MIN(size, field32(elf, segment->p_filesz) - offset); LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size, field32(elf, segment->p_offset) + offset); /* read initialized area of the segment */ retval = fileio_seek(elf->fileio, field32(elf, segment->p_offset) + offset); if (retval != ERROR_OK) { LOG_ERROR("cannot find ELF segment content, seek failed"); return retval; } retval = fileio_read(elf->fileio, read_size, buffer, &really_read); if (retval != ERROR_OK) { LOG_ERROR("cannot read ELF segment content, read failed"); return retval; } size -= read_size; *size_read += read_size; /* need more data ? */ if (!size) return ERROR_OK; } return ERROR_OK; } static int image_elf64_read_section(struct image *image, int section, target_addr_t offset, uint32_t size, uint8_t *buffer, size_t *size_read) { struct image_elf *elf = image->type_private; Elf64_Phdr *segment = (Elf64_Phdr *)image->sections[section].private; size_t read_size, really_read; int retval; *size_read = 0; LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size); /* read initialized data in current segment if any */ if (offset < field64(elf, segment->p_filesz)) { /* maximal size present in file for the current segment */ read_size = MIN(size, field64(elf, segment->p_filesz) - offset); LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size, field64(elf, segment->p_offset) + offset); /* read initialized area of the segment */ retval = fileio_seek(elf->fileio, field64(elf, segment->p_offset) + offset); if (retval != ERROR_OK) { LOG_ERROR("cannot find ELF segment content, seek failed"); return retval; } retval = fileio_read(elf->fileio, read_size, buffer, &really_read); if (retval != ERROR_OK) { LOG_ERROR("cannot read ELF segment content, read failed"); return retval; } size -= read_size; *size_read += read_size; /* need more data ? */ if (!size) return ERROR_OK; } return ERROR_OK; } static int image_elf_read_section(struct image *image, int section, target_addr_t offset, uint32_t size, uint8_t *buffer, size_t *size_read) { struct image_elf *elf = image->type_private; if (elf->is_64_bit) return image_elf64_read_section(image, section, offset, size, buffer, size_read); else return image_elf32_read_section(image, section, offset, size, buffer, size_read); } static int image_mot_buffer_complete_inner(struct image *image, char *lpsz_line, struct imagesection *section) { struct image_mot *mot = image->type_private; struct fileio *fileio = mot->fileio; uint32_t full_address; uint32_t cooked_bytes; bool end_rec = false; /* we can't determine the number of sections that we'll have to create ahead of time, * so we locally hold them until parsing is finished */ int retval; size_t filesize; retval = fileio_size(fileio, &filesize); if (retval != ERROR_OK) return retval; mot->buffer = malloc(filesize >> 1); cooked_bytes = 0x0; image->num_sections = 0; while (!fileio_feof(fileio)) { full_address = 0x0; section[image->num_sections].private = &mot->buffer[cooked_bytes]; section[image->num_sections].base_address = 0x0; section[image->num_sections].size = 0x0; section[image->num_sections].flags = 0; while (fileio_fgets(fileio, 1023, lpsz_line) == ERROR_OK) { uint32_t count; uint32_t address; uint32_t record_type; uint32_t checksum; uint8_t cal_checksum = 0; uint32_t bytes_read = 0; /* skip comments and blank lines */ if ((lpsz_line[0] == '#') || (strlen(lpsz_line + strspn(lpsz_line, "\n\t\r ")) == 0)) continue; /* get record type and record length */ if (sscanf(&lpsz_line[bytes_read], "S%1" SCNx32 "%2" SCNx32, &record_type, &count) != 2) return ERROR_IMAGE_FORMAT_ERROR; bytes_read += 4; cal_checksum += (uint8_t)count; /* skip checksum byte */ count -= 1; if (record_type == 0) { /* S0 - starting record (optional) */ int value; while (count-- > 0) { sscanf(&lpsz_line[bytes_read], "%2x", &value); cal_checksum += (uint8_t)value; bytes_read += 2; } } else if (record_type >= 1 && record_type <= 3) { switch (record_type) { case 1: /* S1 - 16 bit address data record */ sscanf(&lpsz_line[bytes_read], "%4" SCNx32, &address); cal_checksum += (uint8_t)(address >> 8); cal_checksum += (uint8_t)address; bytes_read += 4; count -= 2; break; case 2: /* S2 - 24 bit address data record */ sscanf(&lpsz_line[bytes_read], "%6" SCNx32, &address); cal_checksum += (uint8_t)(address >> 16); cal_checksum += (uint8_t)(address >> 8); cal_checksum += (uint8_t)address; bytes_read += 6; count -= 3; break; case 3: /* S3 - 32 bit address data record */ sscanf(&lpsz_line[bytes_read], "%8" SCNx32, &address); cal_checksum += (uint8_t)(address >> 24); cal_checksum += (uint8_t)(address >> 16); cal_checksum += (uint8_t)(address >> 8); cal_checksum += (uint8_t)address; bytes_read += 8; count -= 4; break; } if (full_address != address) { /* we encountered a nonconsecutive location, create a new section, * unless the current section has zero size, in which case this specifies * the current section's base address */ if (section[image->num_sections].size != 0) { image->num_sections++; section[image->num_sections].size = 0x0; section[image->num_sections].flags = 0; section[image->num_sections].private = &mot->buffer[cooked_bytes]; } section[image->num_sections].base_address = address; full_address = address; } while (count-- > 0) { unsigned value; sscanf(&lpsz_line[bytes_read], "%2x", &value); mot->buffer[cooked_bytes] = (uint8_t)value; cal_checksum += (uint8_t)mot->buffer[cooked_bytes]; bytes_read += 2; cooked_bytes += 1; section[image->num_sections].size += 1; full_address++; } } else if (record_type == 5 || record_type == 6) { /* S5 and S6 are the data count records, we ignore them */ uint32_t dummy; while (count-- > 0) { sscanf(&lpsz_line[bytes_read], "%2" SCNx32, &dummy); cal_checksum += (uint8_t)dummy; bytes_read += 2; } } else if (record_type >= 7 && record_type <= 9) { /* S7, S8, S9 - ending records for 32, 24 and 16bit */ image->num_sections++; /* copy section information */ image->sections = malloc(sizeof(struct imagesection) * image->num_sections); for (unsigned int i = 0; i < image->num_sections; i++) { image->sections[i].private = section[i].private; image->sections[i].base_address = section[i].base_address; image->sections[i].size = section[i].size; image->sections[i].flags = section[i].flags; } end_rec = true; break; } else { LOG_ERROR("unhandled S19 record type: %i", (int)(record_type)); return ERROR_IMAGE_FORMAT_ERROR; } /* account for checksum, will always be 0xFF */ sscanf(&lpsz_line[bytes_read], "%2" SCNx32, &checksum); cal_checksum += (uint8_t)checksum; if (cal_checksum != 0xFF) { /* checksum failed */ LOG_ERROR("incorrect record checksum found in S19 file"); return ERROR_IMAGE_CHECKSUM; } if (end_rec) { end_rec = false; LOG_WARNING("continuing after end-of-file record: %.40s", lpsz_line); } } } if (end_rec) return ERROR_OK; else { LOG_ERROR("premature end of S19 file, no matching end-of-file record found"); return ERROR_IMAGE_FORMAT_ERROR; } } /** * Allocate memory dynamically instead of on the stack. This * is important w/embedded hosts. */ static int image_mot_buffer_complete(struct image *image) { char *lpsz_line = malloc(1023); if (!lpsz_line) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } struct imagesection *section = malloc(sizeof(struct imagesection) * IMAGE_MAX_SECTIONS); if (!section) { free(lpsz_line); LOG_ERROR("Out of memory"); return ERROR_FAIL; } int retval; retval = image_mot_buffer_complete_inner(image, lpsz_line, section); free(section); free(lpsz_line); return retval; } int image_open(struct image *image, const char *url, const char *type_string) { int retval = ERROR_OK; retval = identify_image_type(image, type_string, url); if (retval != ERROR_OK) return retval; if (image->type == IMAGE_BINARY) { struct image_binary *image_binary; image_binary = image->type_private = malloc(sizeof(struct image_binary)); retval = fileio_open(&image_binary->fileio, url, FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) return retval; size_t filesize; retval = fileio_size(image_binary->fileio, &filesize); if (retval != ERROR_OK) { fileio_close(image_binary->fileio); return retval; } image->num_sections = 1; image->sections = malloc(sizeof(struct imagesection)); image->sections[0].base_address = 0x0; image->sections[0].size = filesize; image->sections[0].flags = 0; } else if (image->type == IMAGE_IHEX) { struct image_ihex *image_ihex; image_ihex = image->type_private = malloc(sizeof(struct image_ihex)); retval = fileio_open(&image_ihex->fileio, url, FILEIO_READ, FILEIO_TEXT); if (retval != ERROR_OK) return retval; retval = image_ihex_buffer_complete(image); if (retval != ERROR_OK) { LOG_ERROR( "failed buffering IHEX image, check server output for additional information"); fileio_close(image_ihex->fileio); return retval; } } else if (image->type == IMAGE_ELF) { struct image_elf *image_elf; image_elf = image->type_private = malloc(sizeof(struct image_elf)); retval = fileio_open(&image_elf->fileio, url, FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) return retval; retval = image_elf_read_headers(image); if (retval != ERROR_OK) { fileio_close(image_elf->fileio); return retval; } } else if (image->type == IMAGE_MEMORY) { struct target *target = get_target(url); if (!target) { LOG_ERROR("target '%s' not defined", url); return ERROR_FAIL; } struct image_memory *image_memory; image->num_sections = 1; image->sections = malloc(sizeof(struct imagesection)); image->sections[0].base_address = 0x0; image->sections[0].size = 0xffffffff; image->sections[0].flags = 0; image_memory = image->type_private = malloc(sizeof(struct image_memory)); image_memory->target = target; image_memory->cache = NULL; image_memory->cache_address = 0x0; } else if (image->type == IMAGE_SRECORD) { struct image_mot *image_mot; image_mot = image->type_private = malloc(sizeof(struct image_mot)); retval = fileio_open(&image_mot->fileio, url, FILEIO_READ, FILEIO_TEXT); if (retval != ERROR_OK) return retval; retval = image_mot_buffer_complete(image); if (retval != ERROR_OK) { LOG_ERROR( "failed buffering S19 image, check server output for additional information"); fileio_close(image_mot->fileio); return retval; } } else if (image->type == IMAGE_BUILDER) { image->num_sections = 0; image->base_address_set = false; image->sections = NULL; image->type_private = NULL; } if (image->base_address_set) { /* relocate */ for (unsigned int section = 0; section < image->num_sections; section++) image->sections[section].base_address += image->base_address; /* we're done relocating. The two statements below are mainly * for documentation purposes: stop anyone from empirically * thinking they should use these values henceforth. */ image->base_address = 0; image->base_address_set = false; } return retval; }; int image_read_section(struct image *image, int section, target_addr_t offset, uint32_t size, uint8_t *buffer, size_t *size_read) { int retval; /* don't read past the end of a section */ if (offset + size > image->sections[section].size) { LOG_DEBUG( "read past end of section: 0x%8.8" TARGET_PRIxADDR " + 0x%8.8" PRIx32 " > 0x%8.8" PRIx32 "", offset, size, image->sections[section].size); return ERROR_COMMAND_SYNTAX_ERROR; } if (image->type == IMAGE_BINARY) { struct image_binary *image_binary = image->type_private; /* only one section in a plain binary */ if (section != 0) return ERROR_COMMAND_SYNTAX_ERROR; /* seek to offset */ retval = fileio_seek(image_binary->fileio, offset); if (retval != ERROR_OK) return retval; /* return requested bytes */ retval = fileio_read(image_binary->fileio, size, buffer, size_read); if (retval != ERROR_OK) return retval; } else if (image->type == IMAGE_IHEX) { memcpy(buffer, (uint8_t *)image->sections[section].private + offset, size); *size_read = size; return ERROR_OK; } else if (image->type == IMAGE_ELF) { return image_elf_read_section(image, section, offset, size, buffer, size_read); } else if (image->type == IMAGE_MEMORY) { struct image_memory *image_memory = image->type_private; uint32_t address = image->sections[section].base_address + offset; *size_read = 0; while ((size - *size_read) > 0) { uint32_t size_in_cache; if (!image_memory->cache || (address < image_memory->cache_address) || (address >= (image_memory->cache_address + IMAGE_MEMORY_CACHE_SIZE))) { if (!image_memory->cache) image_memory->cache = malloc(IMAGE_MEMORY_CACHE_SIZE); if (target_read_buffer(image_memory->target, address & ~(IMAGE_MEMORY_CACHE_SIZE - 1), IMAGE_MEMORY_CACHE_SIZE, image_memory->cache) != ERROR_OK) { free(image_memory->cache); image_memory->cache = NULL; return ERROR_IMAGE_TEMPORARILY_UNAVAILABLE; } image_memory->cache_address = address & ~(IMAGE_MEMORY_CACHE_SIZE - 1); } size_in_cache = (image_memory->cache_address + IMAGE_MEMORY_CACHE_SIZE) - address; memcpy(buffer + *size_read, image_memory->cache + (address - image_memory->cache_address), (size_in_cache > size) ? size : size_in_cache ); *size_read += (size_in_cache > size) ? size : size_in_cache; address += (size_in_cache > size) ? size : size_in_cache; } } else if (image->type == IMAGE_SRECORD) { memcpy(buffer, (uint8_t *)image->sections[section].private + offset, size); *size_read = size; return ERROR_OK; } else if (image->type == IMAGE_BUILDER) { memcpy(buffer, (uint8_t *)image->sections[section].private + offset, size); *size_read = size; return ERROR_OK; } return ERROR_OK; } int image_add_section(struct image *image, target_addr_t base, uint32_t size, uint64_t flags, uint8_t const *data) { struct imagesection *section; /* only image builder supports adding sections */ if (image->type != IMAGE_BUILDER) return ERROR_COMMAND_SYNTAX_ERROR; /* see if there's a previous section */ if (image->num_sections) { section = &image->sections[image->num_sections - 1]; /* see if it's enough to extend the last section, * adding data to previous sections or merging is not supported */ if (((section->base_address + section->size) == base) && (section->flags == flags)) { section->private = realloc(section->private, section->size + size); memcpy((uint8_t *)section->private + section->size, data, size); section->size += size; return ERROR_OK; } } /* allocate new section */ image->num_sections++; image->sections = realloc(image->sections, sizeof(struct imagesection) * image->num_sections); section = &image->sections[image->num_sections - 1]; section->base_address = base; section->size = size; section->flags = flags; section->private = malloc(sizeof(uint8_t) * size); memcpy((uint8_t *)section->private, data, size); return ERROR_OK; } void image_close(struct image *image) { if (image->type == IMAGE_BINARY) { struct image_binary *image_binary = image->type_private; fileio_close(image_binary->fileio); } else if (image->type == IMAGE_IHEX) { struct image_ihex *image_ihex = image->type_private; fileio_close(image_ihex->fileio); free(image_ihex->buffer); image_ihex->buffer = NULL; } else if (image->type == IMAGE_ELF) { struct image_elf *image_elf = image->type_private; fileio_close(image_elf->fileio); if (image_elf->is_64_bit) { free(image_elf->header64); image_elf->header64 = NULL; free(image_elf->segments64); image_elf->segments64 = NULL; } else { free(image_elf->header32); image_elf->header32 = NULL; free(image_elf->segments32); image_elf->segments32 = NULL; } } else if (image->type == IMAGE_MEMORY) { struct image_memory *image_memory = image->type_private; free(image_memory->cache); image_memory->cache = NULL; } else if (image->type == IMAGE_SRECORD) { struct image_mot *image_mot = image->type_private; fileio_close(image_mot->fileio); free(image_mot->buffer); image_mot->buffer = NULL; } else if (image->type == IMAGE_BUILDER) { for (unsigned int i = 0; i < image->num_sections; i++) { free(image->sections[i].private); image->sections[i].private = NULL; } } free(image->type_private); image->type_private = NULL; free(image->sections); image->sections = NULL; } int image_calculate_checksum(const uint8_t *buffer, uint32_t nbytes, uint32_t *checksum) { uint32_t crc = 0xffffffff; LOG_DEBUG("Calculating checksum"); static uint32_t crc32_table[256]; static bool first_init; if (!first_init) { /* Initialize the CRC table and the decoding table. */ unsigned int i, j, c; for (i = 0; i < 256; i++) { /* as per gdb */ for (c = i << 24, j = 8; j > 0; --j) c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); crc32_table[i] = c; } first_init = true; } while (nbytes > 0) { int run = nbytes; if (run > 32768) run = 32768; nbytes -= run; while (run--) { /* as per gdb */ crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buffer++) & 255]; } keep_alive(); } LOG_DEBUG("Calculating checksum done; checksum=0x%" PRIx32, crc); *checksum = crc; return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/image.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2018 by Advantest * * florian.meister@advantest.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_IMAGE_H #define OPENOCD_TARGET_IMAGE_H #include <helper/fileio.h> #include <helper/replacements.h> #ifdef HAVE_ELF_H #include <elf.h> #endif #define IMAGE_MAX_ERROR_STRING (256) #define IMAGE_MAX_SECTIONS (512) #define IMAGE_MEMORY_CACHE_SIZE (2048) enum image_type { IMAGE_BINARY, /* plain binary */ IMAGE_IHEX, /* intel hex-record format */ IMAGE_MEMORY, /* target-memory pseudo-image */ IMAGE_ELF, /* ELF binary */ IMAGE_SRECORD, /* motorola s19 */ IMAGE_BUILDER, /* when building a new image */ }; struct imagesection { target_addr_t base_address; uint32_t size; uint64_t flags; void *private; /* private data */ }; struct image { enum image_type type; /* image type (plain, ihex, ...) */ void *type_private; /* type private data */ unsigned int num_sections; /* number of sections contained in the image */ struct imagesection *sections; /* array of sections */ bool base_address_set; /* whether the image has a base address set (for relocation purposes) */ long long base_address; /* base address, if one is set */ bool start_address_set; /* whether the image has a start address (entry point) associated */ uint32_t start_address; /* start address, if one is set */ }; struct image_binary { struct fileio *fileio; }; struct image_ihex { struct fileio *fileio; uint8_t *buffer; }; struct image_memory { struct target *target; uint8_t *cache; uint32_t cache_address; }; struct image_elf { struct fileio *fileio; bool is_64_bit; union { Elf32_Ehdr *header32; Elf64_Ehdr *header64; }; union { Elf32_Phdr *segments32; Elf64_Phdr *segments64; }; uint32_t segment_count; uint8_t endianness; }; struct image_mot { struct fileio *fileio; uint8_t *buffer; }; int image_open(struct image *image, const char *url, const char *type_string); int image_read_section(struct image *image, int section, target_addr_t offset, uint32_t size, uint8_t *buffer, size_t *size_read); void image_close(struct image *image); int image_add_section(struct image *image, target_addr_t base, uint32_t size, uint64_t flags, uint8_t const *data); int image_calculate_checksum(const uint8_t *buffer, uint32_t nbytes, uint32_t *checksum); #define ERROR_IMAGE_FORMAT_ERROR (-1400) #define ERROR_IMAGE_TYPE_UNKNOWN (-1401) #define ERROR_IMAGE_TEMPORARILY_UNAVAILABLE (-1402) #define ERROR_IMAGE_CHECKSUM (-1403) #endif /* OPENOCD_TARGET_IMAGE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/lakemont.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright(c) 2013-2016 Intel Corporation. * * Adrian Burns (adrian.burns@intel.com) * Thomas Faust (thomas.faust@intel.com) * Ivan De Cesaris (ivan.de.cesaris@intel.com) * Julien Carreno (julien.carreno@intel.com) * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com) * Jessica Gomez (jessica.gomez.hernandez@intel.com) * * Contact Information: * Intel Corporation */ /* * @file * This implements the probemode operations for Lakemont 1 (LMT1). */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include "target.h" #include "target_type.h" #include "lakemont.h" #include "register.h" #include "breakpoints.h" #include "x86_32_common.h" static int irscan(struct target *t, uint8_t *out, uint8_t *in, uint8_t ir_len); static int drscan(struct target *t, uint8_t *out, uint8_t *in, uint8_t len); static int save_context(struct target *target); static int restore_context(struct target *target); static uint32_t get_tapstatus(struct target *t); static int enter_probemode(struct target *t); static int exit_probemode(struct target *t); static int halt_prep(struct target *t); static int do_halt(struct target *t); static int do_resume(struct target *t); static int read_all_core_hw_regs(struct target *t); static int write_all_core_hw_regs(struct target *t); static int read_hw_reg(struct target *t, int reg, uint32_t *regval, uint8_t cache); static int write_hw_reg(struct target *t, int reg, uint32_t regval, uint8_t cache); static struct reg_cache *lakemont_build_reg_cache (struct target *target); static int submit_reg_pir(struct target *t, int num); static int submit_instruction_pir(struct target *t, int num); static int submit_pir(struct target *t, uint64_t op); static int lakemont_get_core_reg(struct reg *reg); static int lakemont_set_core_reg(struct reg *reg, uint8_t *buf); static struct scan_blk scan; /* registers and opcodes for register access, pm_idx is used to identify the * registers that are modified for lakemont probemode specific operations */ static const struct { uint8_t id; const char *name; uint64_t op; uint8_t pm_idx; unsigned bits; enum reg_type type; const char *group; const char *feature; } regs[] = { /* general purpose registers */ { EAX, "eax", 0x000000D01D660000ULL, 0, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { ECX, "ecx", 0x000000501D660000ULL, 1, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { EDX, "edx", 0x000000901D660000ULL, 2, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { EBX, "ebx", 0x000000101D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { ESP, "esp", 0x000000E01D660000ULL, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" }, { EBP, "ebp", 0x000000601D660000ULL, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" }, { ESI, "esi", 0x000000A01D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { EDI, "edi", 0x000000201D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, /* instruction pointer & flags */ { EIP, "eip", 0x000000C01D660000ULL, 3, 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.i386.core" }, { EFLAGS, "eflags", 0x000000401D660000ULL, 4, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, /* segment registers */ { CS, "cs", 0x000000281D660000ULL, 5, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { SS, "ss", 0x000000C81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { DS, "ds", 0x000000481D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { ES, "es", 0x000000A81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { FS, "fs", 0x000000881D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { GS, "gs", 0x000000081D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, /* floating point unit registers - not accessible via JTAG - here to satisfy GDB */ { ST0, "st0", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { ST1, "st1", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { ST2, "st2", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { ST3, "st3", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { ST4, "st4", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { ST5, "st5", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { ST6, "st6", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { ST7, "st7", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { FCTRL, "fctrl", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { FSTAT, "fstat", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { FTAG, "ftag", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { FISEG, "fiseg", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { FIOFF, "fioff", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { FOSEG, "foseg", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { FOOFF, "fooff", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, { FOP, "fop", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, /* control registers */ { CR0, "cr0", 0x000000001D660000ULL, 6, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { CR2, "cr2", 0x000000BC1D660000ULL, 7, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { CR3, "cr3", 0x000000801D660000ULL, 8, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { CR4, "cr4", 0x0000002C1D660000ULL, 9, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, /* debug registers */ { DR0, "dr0", 0x0000007C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { DR1, "dr1", 0x000000FC1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { DR2, "dr2", 0x000000021D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { DR3, "dr3", 0x000000821D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { DR6, "dr6", 0x000000301D660000ULL, 10, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { DR7, "dr7", 0x000000B01D660000ULL, 11, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, /* descriptor tables */ { IDTB, "idtbase", 0x000000581D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { IDTL, "idtlimit", 0x000000D81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { IDTAR, "idtar", 0x000000981D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { GDTB, "gdtbase", 0x000000B81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { GDTL, "gdtlimit", 0x000000781D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { GDTAR, "gdtar", 0x000000381D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { TR, "tr", 0x000000701D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { LDTR, "ldtr", 0x000000F01D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { LDTB, "ldbase", 0x000000041D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { LDTL, "ldlimit", 0x000000841D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { LDTAR, "ldtar", 0x000000F81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, /* segment registers */ { CSB, "csbase", 0x000000F41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { CSL, "cslimit", 0x0000000C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { CSAR, "csar", 0x000000741D660000ULL, 12, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { DSB, "dsbase", 0x000000941D660000ULL, 13, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { DSL, "dslimit", 0x000000541D660000ULL, 14, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { DSAR, "dsar", 0x000000141D660000ULL, 15, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { ESB, "esbase", 0x0000004C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { ESL, "eslimit", 0x000000CC1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { ESAR, "esar", 0x0000008C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { FSB, "fsbase", 0x000000641D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { FSL, "fslimit", 0x000000E41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { FSAR, "fsar", 0x000000A41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { GSB, "gsbase", 0x000000C41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { GSL, "gslimit", 0x000000241D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { GSAR, "gsar", 0x000000441D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { SSB, "ssbase", 0x000000341D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { SSL, "sslimit", 0x000000B41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { SSAR, "ssar", 0x000000D41D660000ULL, 16, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { TSSB, "tssbase", 0x000000E81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { TSSL, "tsslimit", 0x000000181D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, { TSSAR, "tssar", 0x000000681D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, /* probemode control register */ { PMCR, "pmcr", 0x000000421D660000ULL, 17, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, }; static const struct { uint8_t id; const char *name; uint64_t op; } instructions[] = { /* memory read/write */ { MEMRDB32, "MEMRDB32", 0x0909090909090851ULL }, { MEMRDB16, "MEMRDB16", 0x09090909090851E6ULL }, { MEMRDH32, "MEMRDH32", 0x090909090908D166ULL }, { MEMRDH16, "MEMRDH16", 0x090909090908D1E6ULL }, { MEMRDW32, "MEMRDW32", 0x09090909090908D1ULL }, { MEMRDW16, "MEMRDW16", 0x0909090908D1E666ULL }, { MEMWRB32, "MEMWRB32", 0x0909090909090811ULL }, { MEMWRB16, "MEMWRB16", 0x09090909090811E6ULL }, { MEMWRH32, "MEMWRH32", 0x0909090909089166ULL }, { MEMWRH16, "MEMWRH16", 0x09090909090891E6ULL }, { MEMWRW32, "MEMWRW32", 0x0909090909090891ULL }, { MEMWRW16, "MEMWRW16", 0x090909090891E666ULL }, /* IO read/write */ { IORDB32, "IORDB32", 0x0909090909090937ULL }, { IORDB16, "IORDB16", 0x09090909090937E6ULL }, { IORDH32, "IORDH32", 0x090909090909B766ULL }, { IORDH16, "IORDH16", 0x090909090909B7E6ULL }, { IORDW32, "IORDW32", 0x09090909090909B7ULL }, { IORDW16, "IORDW16", 0x0909090909B7E666ULL }, { IOWRB32, "IOWRB32", 0x0909090909090977ULL }, { IOWRB16, "IOWRB16", 0x09090909090977E6ULL }, { IOWRH32, "IOWRH32", 0x090909090909F766ULL }, { IOWRH16, "IOWRH16", 0x090909090909F7E6ULL }, { IOWRW32, "IOWRW32", 0x09090909090909F7ULL }, { IOWRW16, "IOWRW16", 0x0909090909F7E666ULL }, /* lakemont1 core shadow ram access opcodes */ { SRAMACCESS, "SRAMACCESS", 0x0000000E9D660000ULL }, { SRAM2PDR, "SRAM2PDR", 0x4CF0000000000000ULL }, { PDR2SRAM, "PDR2SRAM", 0x0CF0000000000000ULL }, { WBINVD, "WBINVD", 0x09090909090990F0ULL }, }; bool check_not_halted(const struct target *t) { bool halted = t->state == TARGET_HALTED; if (!halted) LOG_ERROR("target running, halt it first"); return !halted; } static int irscan(struct target *t, uint8_t *out, uint8_t *in, uint8_t ir_len) { int retval = ERROR_OK; struct x86_32_common *x86_32 = target_to_x86_32(t); if (!t->tap) { retval = ERROR_FAIL; LOG_ERROR("%s invalid target tap", __func__); return retval; } if (ir_len != t->tap->ir_length) { retval = ERROR_FAIL; if (t->tap->enabled) LOG_ERROR("%s tap enabled but tap irlen=%d", __func__, t->tap->ir_length); else LOG_ERROR("%s tap not enabled and irlen=%d", __func__, t->tap->ir_length); return retval; } struct scan_field *fields = &scan.field; fields->num_bits = ir_len; fields->out_value = out; fields->in_value = in; jtag_add_ir_scan(x86_32->curr_tap, fields, TAP_IDLE); if (x86_32->flush) { retval = jtag_execute_queue(); if (retval != ERROR_OK) LOG_ERROR("%s failed to execute queue", __func__); } return retval; } static int drscan(struct target *t, uint8_t *out, uint8_t *in, uint8_t len) { int retval = ERROR_OK; uint64_t data = 0; struct x86_32_common *x86_32 = target_to_x86_32(t); if (!t->tap) { retval = ERROR_FAIL; LOG_ERROR("%s invalid target tap", __func__); return retval; } if (len > MAX_SCAN_SIZE || 0 == len) { retval = ERROR_FAIL; LOG_ERROR("%s data len is %d bits, max is %d bits", __func__, len, MAX_SCAN_SIZE); return retval; } struct scan_field *fields = &scan.field; fields->out_value = out; fields->in_value = in; fields->num_bits = len; jtag_add_dr_scan(x86_32->curr_tap, 1, fields, TAP_IDLE); if (x86_32->flush) { retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("%s drscan failed to execute queue", __func__); return retval; } } if (in) { if (len >= 8) { for (int n = (len / 8) - 1 ; n >= 0; n--) data = (data << 8) + *(in+n); } else LOG_DEBUG("dr in 0x%02" PRIx8, *in); } else { LOG_ERROR("%s no drscan data", __func__); retval = ERROR_FAIL; } return retval; } static int save_context(struct target *t) { int err; /* read core registers from lakemont sram */ err = read_all_core_hw_regs(t); if (err != ERROR_OK) { LOG_ERROR("%s error reading regs", __func__); return err; } return ERROR_OK; } static int restore_context(struct target *t) { int err = ERROR_OK; uint32_t i; struct x86_32_common *x86_32 = target_to_x86_32(t); /* write core regs into the core PM SRAM from the reg_cache */ err = write_all_core_hw_regs(t); if (err != ERROR_OK) { LOG_ERROR("%s error writing regs", __func__); return err; } for (i = 0; i < (x86_32->cache->num_regs); i++) { x86_32->cache->reg_list[i].dirty = false; x86_32->cache->reg_list[i].valid = false; } return err; } /* * we keep reg_cache in sync with hardware at halt/resume time, we avoid * writing to real hardware here because pm_regs reflects the hardware * while we are halted then reg_cache syncs with hw on resume * TODO - in order for "reg eip force" to work it assume get/set reads * and writes from hardware, may be other reasons also because generally * other openocd targets read/write from hardware in get/set - watch this! */ static int lakemont_get_core_reg(struct reg *reg) { int retval = ERROR_OK; struct lakemont_core_reg *lakemont_reg = reg->arch_info; struct target *t = lakemont_reg->target; if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; LOG_DEBUG("reg=%s, value=0x%08" PRIx32, reg->name, buf_get_u32(reg->value, 0, 32)); return retval; } static int lakemont_set_core_reg(struct reg *reg, uint8_t *buf) { struct lakemont_core_reg *lakemont_reg = reg->arch_info; struct target *t = lakemont_reg->target; uint32_t value = buf_get_u32(buf, 0, 32); LOG_DEBUG("reg=%s, newval=0x%08" PRIx32, reg->name, value); if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; buf_set_u32(reg->value, 0, 32, value); reg->dirty = true; reg->valid = true; return ERROR_OK; } static const struct reg_arch_type lakemont_reg_type = { /* these get called if reg_cache doesn't have a "valid" value * of an individual reg eg "reg eip" but not for "reg" block */ .get = lakemont_get_core_reg, .set = lakemont_set_core_reg, }; struct reg_cache *lakemont_build_reg_cache(struct target *t) { struct x86_32_common *x86_32 = target_to_x86_32(t); int num_regs = ARRAY_SIZE(regs); struct reg_cache **cache_p = register_get_last_cache_p(&t->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); struct lakemont_core_reg *arch_info = malloc(sizeof(struct lakemont_core_reg) * num_regs); struct reg_feature *feature; int i; if (!cache || !reg_list || !arch_info) { free(cache); free(reg_list); free(arch_info); LOG_ERROR("%s out of memory", __func__); return NULL; } /* Build the process context cache */ cache->name = "lakemont registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = num_regs; (*cache_p) = cache; x86_32->cache = cache; for (i = 0; i < num_regs; i++) { arch_info[i].target = t; arch_info[i].x86_32_common = x86_32; arch_info[i].op = regs[i].op; arch_info[i].pm_idx = regs[i].pm_idx; reg_list[i].name = regs[i].name; reg_list[i].size = 32; reg_list[i].value = calloc(1, 4); reg_list[i].dirty = false; reg_list[i].valid = false; reg_list[i].type = &lakemont_reg_type; reg_list[i].arch_info = &arch_info[i]; reg_list[i].group = regs[i].group; reg_list[i].number = i; reg_list[i].exist = true; reg_list[i].caller_save = true; /* gdb defaults to true */ feature = calloc(1, sizeof(struct reg_feature)); if (feature) { feature->name = regs[i].feature; reg_list[i].feature = feature; } else LOG_ERROR("%s unable to allocate feature list", __func__); reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); if (reg_list[i].reg_data_type) reg_list[i].reg_data_type->type = regs[i].type; else LOG_ERROR("%s unable to allocate reg type list", __func__); } return cache; } static uint32_t get_tapstatus(struct target *t) { scan.out[0] = TAPSTATUS; if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK) return 0; if (drscan(t, NULL, scan.out, TS_SIZE) != ERROR_OK) return 0; return buf_get_u32(scan.out, 0, 32); } static int enter_probemode(struct target *t) { uint32_t tapstatus = 0; int retries = 100; tapstatus = get_tapstatus(t); LOG_DEBUG("TS before PM enter = 0x%08" PRIx32, tapstatus); if (tapstatus & TS_PM_BIT) { LOG_DEBUG("core already in probemode"); return ERROR_OK; } scan.out[0] = PROBEMODE; if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK) return ERROR_FAIL; scan.out[0] = 1; if (drscan(t, scan.out, scan.in, 1) != ERROR_OK) return ERROR_FAIL; while (retries--) { tapstatus = get_tapstatus(t); LOG_DEBUG("TS after PM enter = 0x%08" PRIx32, tapstatus); if ((tapstatus & TS_PM_BIT) && (!(tapstatus & TS_EN_PM_BIT))) return ERROR_OK; } LOG_ERROR("%s PM enter error, tapstatus = 0x%08" PRIx32 , __func__, tapstatus); return ERROR_FAIL; } static int exit_probemode(struct target *t) { uint32_t tapstatus = get_tapstatus(t); LOG_DEBUG("TS before PM exit = 0x%08" PRIx32, tapstatus); if (!(tapstatus & TS_PM_BIT)) { LOG_USER("core not in PM"); return ERROR_OK; } scan.out[0] = PROBEMODE; if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK) return ERROR_FAIL; scan.out[0] = 0; if (drscan(t, scan.out, scan.in, 1) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } /* do whats needed to properly enter probemode for debug on lakemont */ static int halt_prep(struct target *t) { struct x86_32_common *x86_32 = target_to_x86_32(t); if (write_hw_reg(t, DSB, PM_DSB, 0) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("write %s 0x%08" PRIx32, regs[DSB].name, PM_DSB); if (write_hw_reg(t, DSL, PM_DSL, 0) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("write %s 0x%08" PRIx32, regs[DSL].name, PM_DSL); if (write_hw_reg(t, DSAR, PM_DSAR, 0) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("write DSAR 0x%08" PRIx32, PM_DSAR); if (write_hw_reg(t, CSB, PM_DSB, 0) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("write %s 0x%08" PRIx32, regs[CSB].name, PM_DSB); if (write_hw_reg(t, CSL, PM_DSL, 0) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("write %s 0x%08" PRIx32, regs[CSL].name, PM_DSL); if (write_hw_reg(t, DR7, PM_DR7, 0) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("write DR7 0x%08" PRIx32, PM_DR7); uint32_t eflags = buf_get_u32(x86_32->cache->reg_list[EFLAGS].value, 0, 32); uint32_t csar = buf_get_u32(x86_32->cache->reg_list[CSAR].value, 0, 32); uint32_t ssar = buf_get_u32(x86_32->cache->reg_list[SSAR].value, 0, 32); uint32_t cr0 = buf_get_u32(x86_32->cache->reg_list[CR0].value, 0, 32); /* clear VM86 and IF bits if they are set */ LOG_DEBUG("EFLAGS = 0x%08" PRIx32 ", VM86 = %d, IF = %d", eflags, eflags & EFLAGS_VM86 ? 1 : 0, eflags & EFLAGS_IF ? 1 : 0); if ((eflags & EFLAGS_VM86) || (eflags & EFLAGS_IF)) { x86_32->pm_regs[I(EFLAGS)] = eflags & ~(EFLAGS_VM86 | EFLAGS_IF); if (write_hw_reg(t, EFLAGS, x86_32->pm_regs[I(EFLAGS)], 0) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("EFLAGS now = 0x%08" PRIx32 ", VM86 = %d, IF = %d", x86_32->pm_regs[I(EFLAGS)], x86_32->pm_regs[I(EFLAGS)] & EFLAGS_VM86 ? 1 : 0, x86_32->pm_regs[I(EFLAGS)] & EFLAGS_IF ? 1 : 0); } /* set CPL to 0 for memory access */ if (csar & CSAR_DPL) { x86_32->pm_regs[I(CSAR)] = csar & ~CSAR_DPL; if (write_hw_reg(t, CSAR, x86_32->pm_regs[I(CSAR)], 0) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("write CSAR_CPL to 0 0x%08" PRIx32, x86_32->pm_regs[I(CSAR)]); } if (ssar & SSAR_DPL) { x86_32->pm_regs[I(SSAR)] = ssar & ~SSAR_DPL; if (write_hw_reg(t, SSAR, x86_32->pm_regs[I(SSAR)], 0) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("write SSAR_CPL to 0 0x%08" PRIx32, x86_32->pm_regs[I(SSAR)]); } /* if cache's are enabled, disable and flush, depending on the core version */ if (!(x86_32->core_type == LMT3_5) && !(cr0 & CR0_CD)) { LOG_DEBUG("caching enabled CR0 = 0x%08" PRIx32, cr0); if (cr0 & CR0_PG) { x86_32->pm_regs[I(CR0)] = cr0 & ~CR0_PG; if (write_hw_reg(t, CR0, x86_32->pm_regs[I(CR0)], 0) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("cleared paging CR0_PG = 0x%08" PRIx32, x86_32->pm_regs[I(CR0)]); /* submit wbinvd to flush cache */ if (submit_reg_pir(t, WBINVD) != ERROR_OK) return ERROR_FAIL; x86_32->pm_regs[I(CR0)] = x86_32->pm_regs[I(CR0)] | (CR0_CD | CR0_NW | CR0_PG); if (write_hw_reg(t, CR0, x86_32->pm_regs[I(CR0)], 0) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("set CD, NW and PG, CR0 = 0x%08" PRIx32, x86_32->pm_regs[I(CR0)]); } } return ERROR_OK; } static int do_halt(struct target *t) { /* needs proper handling later if doing a halt errors out */ t->state = TARGET_DEBUG_RUNNING; if (enter_probemode(t) != ERROR_OK) return ERROR_FAIL; return lakemont_update_after_probemode_entry(t); } /* we need to expose the update to be able to complete the reset at SoC level */ int lakemont_update_after_probemode_entry(struct target *t) { if (save_context(t) != ERROR_OK) return ERROR_FAIL; if (halt_prep(t) != ERROR_OK) return ERROR_FAIL; t->state = TARGET_HALTED; return target_call_event_callbacks(t, TARGET_EVENT_HALTED); } static int do_resume(struct target *t) { /* needs proper handling later */ t->state = TARGET_DEBUG_RUNNING; if (restore_context(t) != ERROR_OK) return ERROR_FAIL; if (exit_probemode(t) != ERROR_OK) return ERROR_FAIL; t->state = TARGET_RUNNING; t->debug_reason = DBG_REASON_NOTHALTED; LOG_USER("target running"); return target_call_event_callbacks(t, TARGET_EVENT_RESUMED); } static int read_all_core_hw_regs(struct target *t) { int err; uint32_t regval; unsigned i; struct x86_32_common *x86_32 = target_to_x86_32(t); for (i = 0; i < (x86_32->cache->num_regs); i++) { if (regs[i].pm_idx == NOT_AVAIL_REG) continue; err = read_hw_reg(t, regs[i].id, ®val, 1); if (err != ERROR_OK) { LOG_ERROR("%s error saving reg %s", __func__, x86_32->cache->reg_list[i].name); return err; } } LOG_DEBUG("read_all_core_hw_regs read %u registers ok", i); return ERROR_OK; } static int write_all_core_hw_regs(struct target *t) { int err; unsigned i; struct x86_32_common *x86_32 = target_to_x86_32(t); for (i = 0; i < (x86_32->cache->num_regs); i++) { if (regs[i].pm_idx == NOT_AVAIL_REG) continue; err = write_hw_reg(t, i, 0, 1); if (err != ERROR_OK) { LOG_ERROR("%s error restoring reg %s", __func__, x86_32->cache->reg_list[i].name); return err; } } LOG_DEBUG("write_all_core_hw_regs wrote %u registers ok", i); return ERROR_OK; } /* read reg from lakemont core shadow ram, update reg cache if needed */ static int read_hw_reg(struct target *t, int reg, uint32_t *regval, uint8_t cache) { struct x86_32_common *x86_32 = target_to_x86_32(t); struct lakemont_core_reg *arch_info; arch_info = x86_32->cache->reg_list[reg].arch_info; x86_32->flush = 0; /* don't flush scans till we have a batch */ if (submit_reg_pir(t, reg) != ERROR_OK) return ERROR_FAIL; if (submit_instruction_pir(t, SRAMACCESS) != ERROR_OK) return ERROR_FAIL; if (submit_instruction_pir(t, SRAM2PDR) != ERROR_OK) return ERROR_FAIL; x86_32->flush = 1; scan.out[0] = RDWRPDR; if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK) return ERROR_FAIL; if (drscan(t, NULL, scan.out, PDR_SIZE) != ERROR_OK) return ERROR_FAIL; jtag_add_sleep(DELAY_SUBMITPIR); *regval = buf_get_u32(scan.out, 0, 32); if (cache) { buf_set_u32(x86_32->cache->reg_list[reg].value, 0, 32, *regval); x86_32->cache->reg_list[reg].valid = true; x86_32->cache->reg_list[reg].dirty = false; } LOG_DEBUG("reg=%s, op=0x%016" PRIx64 ", val=0x%08" PRIx32, x86_32->cache->reg_list[reg].name, arch_info->op, *regval); return ERROR_OK; } /* write lakemont core shadow ram reg, update reg cache if needed */ static int write_hw_reg(struct target *t, int reg, uint32_t regval, uint8_t cache) { struct x86_32_common *x86_32 = target_to_x86_32(t); struct lakemont_core_reg *arch_info; arch_info = x86_32->cache->reg_list[reg].arch_info; uint8_t reg_buf[4]; if (cache) regval = buf_get_u32(x86_32->cache->reg_list[reg].value, 0, 32); buf_set_u32(reg_buf, 0, 32, regval); LOG_DEBUG("reg=%s, op=0x%016" PRIx64 ", val=0x%08" PRIx32, x86_32->cache->reg_list[reg].name, arch_info->op, regval); x86_32->flush = 0; /* don't flush scans till we have a batch */ if (submit_reg_pir(t, reg) != ERROR_OK) return ERROR_FAIL; if (submit_instruction_pir(t, SRAMACCESS) != ERROR_OK) return ERROR_FAIL; scan.out[0] = RDWRPDR; if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK) return ERROR_FAIL; if (drscan(t, reg_buf, scan.out, PDR_SIZE) != ERROR_OK) return ERROR_FAIL; x86_32->flush = 1; if (submit_instruction_pir(t, PDR2SRAM) != ERROR_OK) return ERROR_FAIL; /* we are writing from the cache so ensure we reset flags */ if (cache) { x86_32->cache->reg_list[reg].dirty = false; x86_32->cache->reg_list[reg].valid = false; } return ERROR_OK; } static bool is_paging_enabled(struct target *t) { struct x86_32_common *x86_32 = target_to_x86_32(t); if (x86_32->pm_regs[I(CR0)] & CR0_PG) return true; else return false; } static uint8_t get_num_user_regs(struct target *t) { struct x86_32_common *x86_32 = target_to_x86_32(t); return x86_32->cache->num_regs; } /* value of the CR0.PG (paging enabled) bit influences memory reads/writes */ static int disable_paging(struct target *t) { struct x86_32_common *x86_32 = target_to_x86_32(t); x86_32->pm_regs[I(CR0)] = x86_32->pm_regs[I(CR0)] & ~CR0_PG; int err = x86_32->write_hw_reg(t, CR0, x86_32->pm_regs[I(CR0)], 0); if (err != ERROR_OK) { LOG_ERROR("%s error disabling paging", __func__); return err; } return err; } static int enable_paging(struct target *t) { struct x86_32_common *x86_32 = target_to_x86_32(t); x86_32->pm_regs[I(CR0)] = (x86_32->pm_regs[I(CR0)] | CR0_PG); int err = x86_32->write_hw_reg(t, CR0, x86_32->pm_regs[I(CR0)], 0); if (err != ERROR_OK) { LOG_ERROR("%s error enabling paging", __func__); return err; } return err; } static bool sw_bpts_supported(struct target *t) { uint32_t tapstatus = get_tapstatus(t); if (tapstatus & TS_SBP_BIT) return true; else return false; } static int transaction_status(struct target *t) { uint32_t tapstatus = get_tapstatus(t); if ((TS_EN_PM_BIT | TS_PRDY_BIT) & tapstatus) { LOG_ERROR("%s transaction error tapstatus = 0x%08" PRIx32 , __func__, tapstatus); return ERROR_FAIL; } else { return ERROR_OK; } } static int submit_instruction(struct target *t, int num) { int err = submit_instruction_pir(t, num); if (err != ERROR_OK) { LOG_ERROR("%s error submitting pir", __func__); return err; } return err; } static int submit_reg_pir(struct target *t, int num) { LOG_DEBUG("reg %s op=0x%016" PRIx64, regs[num].name, regs[num].op); int err = submit_pir(t, regs[num].op); if (err != ERROR_OK) { LOG_ERROR("%s error submitting pir", __func__); return err; } return err; } static int submit_instruction_pir(struct target *t, int num) { LOG_DEBUG("%s op=0x%016" PRIx64, instructions[num].name, instructions[num].op); int err = submit_pir(t, instructions[num].op); if (err != ERROR_OK) { LOG_ERROR("%s error submitting pir", __func__); return err; } return err; } /* * PIR (Probe Mode Instruction Register), SUBMITPIR is an "IR only" TAP * command; there is no corresponding data register */ static int submit_pir(struct target *t, uint64_t op) { struct x86_32_common *x86_32 = target_to_x86_32(t); uint8_t op_buf[8]; buf_set_u64(op_buf, 0, 64, op); int flush = x86_32->flush; x86_32->flush = 0; scan.out[0] = WRPIR; if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK) return ERROR_FAIL; if (drscan(t, op_buf, scan.out, PIR_SIZE) != ERROR_OK) return ERROR_FAIL; scan.out[0] = SUBMITPIR; x86_32->flush = flush; if (irscan(t, scan.out, NULL, LMT_IRLEN) != ERROR_OK) return ERROR_FAIL; jtag_add_sleep(DELAY_SUBMITPIR); return ERROR_OK; } int lakemont_init_target(struct command_context *cmd_ctx, struct target *t) { lakemont_build_reg_cache(t); t->state = TARGET_RUNNING; t->debug_reason = DBG_REASON_NOTHALTED; return ERROR_OK; } int lakemont_init_arch_info(struct target *t, struct x86_32_common *x86_32) { x86_32->submit_instruction = submit_instruction; x86_32->transaction_status = transaction_status; x86_32->read_hw_reg = read_hw_reg; x86_32->write_hw_reg = write_hw_reg; x86_32->sw_bpts_supported = sw_bpts_supported; x86_32->get_num_user_regs = get_num_user_regs; x86_32->is_paging_enabled = is_paging_enabled; x86_32->disable_paging = disable_paging; x86_32->enable_paging = enable_paging; return ERROR_OK; } int lakemont_poll(struct target *t) { /* LMT1 PMCR register currently allows code breakpoints, data breakpoints, * single stepping and shutdowns to be redirected to PM but does not allow * redirecting into PM as a result of SMM enter and SMM exit */ uint32_t ts = get_tapstatus(t); if (ts == 0xFFFFFFFF && t->state != TARGET_DEBUG_RUNNING) { /* something is wrong here */ LOG_ERROR("tapstatus invalid - scan_chain serialization or locked JTAG access issues"); /* TODO: Give a hint that unlocking is wrong or maybe a * 'jtag arp_init' helps */ t->state = TARGET_DEBUG_RUNNING; return ERROR_OK; } if (t->state == TARGET_HALTED && (!(ts & TS_PM_BIT))) { LOG_INFO("target running for unknown reason"); t->state = TARGET_RUNNING; } if (t->state == TARGET_RUNNING && t->state != TARGET_DEBUG_RUNNING) { if ((ts & TS_PM_BIT) && (ts & TS_PMCR_BIT)) { LOG_DEBUG("redirect to PM, tapstatus=0x%08" PRIx32, get_tapstatus(t)); t->state = TARGET_DEBUG_RUNNING; if (save_context(t) != ERROR_OK) return ERROR_FAIL; if (halt_prep(t) != ERROR_OK) return ERROR_FAIL; t->state = TARGET_HALTED; t->debug_reason = DBG_REASON_UNDEFINED; struct x86_32_common *x86_32 = target_to_x86_32(t); uint32_t eip = buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32); uint32_t dr6 = buf_get_u32(x86_32->cache->reg_list[DR6].value, 0, 32); uint32_t hwbreakpoint = (uint32_t)-1; if (dr6 & DR6_BRKDETECT_0) hwbreakpoint = 0; if (dr6 & DR6_BRKDETECT_1) hwbreakpoint = 1; if (dr6 & DR6_BRKDETECT_2) hwbreakpoint = 2; if (dr6 & DR6_BRKDETECT_3) hwbreakpoint = 3; if (hwbreakpoint != (uint32_t)-1) { uint32_t dr7 = buf_get_u32(x86_32->cache->reg_list[DR7].value, 0, 32); uint32_t type = dr7 & (0x03 << (DR7_RW_SHIFT + hwbreakpoint*DR7_RW_LEN_SIZE)); if (type == DR7_BP_EXECUTE) { LOG_USER("hit hardware breakpoint (hwreg=%" PRIu32 ") at 0x%08" PRIx32, hwbreakpoint, eip); } else { uint32_t address = 0; switch (hwbreakpoint) { default: case 0: address = buf_get_u32(x86_32->cache->reg_list[DR0].value, 0, 32); break; case 1: address = buf_get_u32(x86_32->cache->reg_list[DR1].value, 0, 32); break; case 2: address = buf_get_u32(x86_32->cache->reg_list[DR2].value, 0, 32); break; case 3: address = buf_get_u32(x86_32->cache->reg_list[DR3].value, 0, 32); break; } LOG_USER("hit '%s' watchpoint for 0x%08" PRIx32 " (hwreg=%" PRIu32 ") at 0x%08" PRIx32, type == DR7_BP_WRITE ? "write" : "access", address, hwbreakpoint, eip); } t->debug_reason = DBG_REASON_BREAKPOINT; } else { /* Check if the target hit a software breakpoint. * ! Watch out: EIP is currently pointing after the breakpoint opcode */ struct breakpoint *bp = NULL; bp = breakpoint_find(t, eip-1); if (bp) { t->debug_reason = DBG_REASON_BREAKPOINT; if (bp->type == BKPT_SOFT) { /* The EIP is now pointing the next byte after the * breakpoint instruction. This needs to be corrected. */ buf_set_u32(x86_32->cache->reg_list[EIP].value, 0, 32, eip-1); x86_32->cache->reg_list[EIP].dirty = true; x86_32->cache->reg_list[EIP].valid = true; LOG_USER("hit software breakpoint at 0x%08" PRIx32, eip-1); } else { /* it's not a hardware breakpoint (checked already in DR6 state) * and it's also not a software breakpoint ... */ LOG_USER("hit unknown breakpoint at 0x%08" PRIx32, eip); } } else { /* There is also the case that we hit an breakpoint instruction, * which was not set by us. This needs to be handled be the * application that introduced the breakpoint. */ LOG_USER("unknown break reason at 0x%08" PRIx32, eip); } } return target_call_event_callbacks(t, TARGET_EVENT_HALTED); } } return ERROR_OK; } int lakemont_arch_state(struct target *t) { struct x86_32_common *x86_32 = target_to_x86_32(t); LOG_USER("target halted due to %s at 0x%08" PRIx32 " in %s mode", debug_reason_name(t), buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32), (buf_get_u32(x86_32->cache->reg_list[CR0].value, 0, 32) & CR0_PE) ? "protected" : "real"); return ERROR_OK; } int lakemont_halt(struct target *t) { if (t->state == TARGET_RUNNING) { t->debug_reason = DBG_REASON_DBGRQ; if (do_halt(t) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } else { LOG_ERROR("%s target not running", __func__); return ERROR_FAIL; } } int lakemont_resume(struct target *t, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { struct breakpoint *bp = NULL; struct x86_32_common *x86_32 = target_to_x86_32(t); if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; /* TODO lakemont_enable_breakpoints(t); */ if (t->state == TARGET_HALTED) { /* running away for a software breakpoint needs some special handling */ uint32_t eip = buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32); bp = breakpoint_find(t, eip); if (bp /*&& bp->type == BKPT_SOFT*/) { /* the step will step over the breakpoint */ if (lakemont_step(t, 0, 0, 1) != ERROR_OK) { LOG_ERROR("%s stepping over a software breakpoint at 0x%08" PRIx32 " " "failed to resume the target", __func__, eip); return ERROR_FAIL; } } /* if breakpoints are enabled, we need to redirect these into probe mode */ struct breakpoint *activeswbp = t->breakpoints; while (activeswbp && !activeswbp->is_set) activeswbp = activeswbp->next; struct watchpoint *activehwbp = t->watchpoints; while (activehwbp && !activehwbp->is_set) activehwbp = activehwbp->next; if (activeswbp || activehwbp) buf_set_u32(x86_32->cache->reg_list[PMCR].value, 0, 32, 1); if (do_resume(t) != ERROR_OK) return ERROR_FAIL; } else { LOG_USER("target not halted"); return ERROR_FAIL; } return ERROR_OK; } int lakemont_step(struct target *t, int current, target_addr_t address, int handle_breakpoints) { struct x86_32_common *x86_32 = target_to_x86_32(t); uint32_t eflags = buf_get_u32(x86_32->cache->reg_list[EFLAGS].value, 0, 32); uint32_t eip = buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32); uint32_t pmcr = buf_get_u32(x86_32->cache->reg_list[PMCR].value, 0, 32); struct breakpoint *bp = NULL; int retval = ERROR_OK; uint32_t tapstatus = 0; if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; bp = breakpoint_find(t, eip); if (retval == ERROR_OK && bp/*&& bp->type == BKPT_SOFT*/) { /* TODO: This should only be done for software breakpoints. * Stepping from hardware breakpoints should be possible with the resume flag * Needs testing. */ retval = x86_32_common_remove_breakpoint(t, bp); } /* Set EFLAGS[TF] and PMCR[IR], exit pm and wait for PRDY# */ LOG_DEBUG("modifying PMCR = 0x%08" PRIx32 " and EFLAGS = 0x%08" PRIx32, pmcr, eflags); eflags = eflags | (EFLAGS_TF | EFLAGS_RF); buf_set_u32(x86_32->cache->reg_list[EFLAGS].value, 0, 32, eflags); buf_set_u32(x86_32->cache->reg_list[PMCR].value, 0, 32, 1); LOG_DEBUG("EFLAGS [TF] [RF] bits set=0x%08" PRIx32 ", PMCR=0x%08" PRIx32 ", EIP=0x%08" PRIx32, eflags, pmcr, eip); /* Returned value unused. Can this line be removed? */ get_tapstatus(t); t->debug_reason = DBG_REASON_SINGLESTEP; t->state = TARGET_DEBUG_RUNNING; if (restore_context(t) != ERROR_OK) return ERROR_FAIL; if (exit_probemode(t) != ERROR_OK) return ERROR_FAIL; target_call_event_callbacks(t, TARGET_EVENT_RESUMED); tapstatus = get_tapstatus(t); if (tapstatus & (TS_PM_BIT | TS_EN_PM_BIT | TS_PRDY_BIT | TS_PMCR_BIT)) { /* target has stopped */ if (save_context(t) != ERROR_OK) return ERROR_FAIL; if (halt_prep(t) != ERROR_OK) return ERROR_FAIL; t->state = TARGET_HALTED; LOG_USER("step done from EIP 0x%08" PRIx32 " to 0x%08" PRIx32, eip, buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32)); target_call_event_callbacks(t, TARGET_EVENT_HALTED); } else { /* target didn't stop * I hope the poll() will catch it, but the deleted breakpoint is gone */ LOG_ERROR("%s target didn't stop after executing a single step", __func__); t->state = TARGET_RUNNING; return ERROR_FAIL; } /* try to re-apply the breakpoint, even of step failed * TODO: When a bp was set, we should try to stop the target - fix the return above */ if (bp/*&& bp->type == BKPT_SOFT*/) { /* TODO: This should only be done for software breakpoints. * Stepping from hardware breakpoints should be possible with the resume flag * Needs testing. */ retval = x86_32_common_add_breakpoint(t, bp); } return retval; } static int lakemont_reset_break(struct target *t) { struct x86_32_common *x86_32 = target_to_x86_32(t); struct jtag_tap *saved_tap = x86_32->curr_tap; struct scan_field *fields = &scan.field; int retval = ERROR_OK; LOG_DEBUG("issuing port 0xcf9 reset"); /* prepare resetbreak setting the proper bits in CLTAPC_CPU_VPREQ */ x86_32->curr_tap = jtag_tap_by_position(1); if (!x86_32->curr_tap) { x86_32->curr_tap = saved_tap; LOG_ERROR("%s could not select quark_x10xx.cltap", __func__); return ERROR_FAIL; } fields->in_value = NULL; fields->num_bits = 8; /* select CLTAPC_CPU_VPREQ instruction*/ scan.out[0] = 0x51; fields->out_value = ((uint8_t *)scan.out); jtag_add_ir_scan(x86_32->curr_tap, fields, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) { x86_32->curr_tap = saved_tap; LOG_ERROR("%s irscan failed to execute queue", __func__); return retval; } /* set enable_preq_on_reset & enable_preq_on_reset2 bits*/ scan.out[0] = 0x06; fields->out_value = ((uint8_t *)scan.out); jtag_add_dr_scan(x86_32->curr_tap, 1, fields, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("%s drscan failed to execute queue", __func__); x86_32->curr_tap = saved_tap; return retval; } /* restore current tap */ x86_32->curr_tap = saved_tap; return ERROR_OK; } /* * If we ever get an adapter with support for PREQ# and PRDY#, we should * update this function to add support for using those two signals. * * Meanwhile, we're assuming that we only support reset break. */ int lakemont_reset_assert(struct target *t) { struct x86_32_common *x86_32 = target_to_x86_32(t); /* write 0x6 to I/O port 0xcf9 to cause the reset */ uint8_t cf9_reset_val = 0x6; int retval; LOG_DEBUG(" "); if (t->state != TARGET_HALTED) { LOG_DEBUG("target must be halted first"); retval = lakemont_halt(t); if (retval != ERROR_OK) { LOG_ERROR("could not halt target"); return retval; } x86_32->forced_halt_for_reset = true; } if (t->reset_halt) { retval = lakemont_reset_break(t); if (retval != ERROR_OK) return retval; } retval = x86_32_common_write_io(t, 0xcf9, BYTE, &cf9_reset_val); if (retval != ERROR_OK) { LOG_ERROR("could not write to port 0xcf9"); return retval; } if (!t->reset_halt && x86_32->forced_halt_for_reset) { x86_32->forced_halt_for_reset = false; retval = lakemont_resume(t, true, 0x00, false, true); if (retval != ERROR_OK) return retval; } /* remove breakpoints and watchpoints */ x86_32_common_reset_breakpoints_watchpoints(t); return ERROR_OK; } int lakemont_reset_deassert(struct target *t) { int retval; LOG_DEBUG(" "); if (target_was_examined(t)) { retval = lakemont_poll(t); if (retval != ERROR_OK) return retval; } if (t->reset_halt) { /* entered PM after reset, update the state */ retval = lakemont_update_after_probemode_entry(t); if (retval != ERROR_OK) { LOG_ERROR("could not update state after probemode entry"); return retval; } if (t->state != TARGET_HALTED) { LOG_WARNING("%s: ran after reset and before halt ...", target_name(t)); if (target_was_examined(t)) { retval = target_halt(t); if (retval != ERROR_OK) return retval; } else { t->state = TARGET_UNKNOWN; } } } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/lakemont.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright(c) 2013-2016 Intel Corporation. * * Adrian Burns (adrian.burns@intel.com) * Thomas Faust (thomas.faust@intel.com) * Ivan De Cesaris (ivan.de.cesaris@intel.com) * Julien Carreno (julien.carreno@intel.com) * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com) * * Contact Information: * Intel Corporation */ /* * @file * This is the interface to the probemode operations for Lakemont 1 (LMT1). */ #ifndef OPENOCD_TARGET_LAKEMONT_H #define OPENOCD_TARGET_LAKEMONT_H #include <jtag/jtag.h> #include <helper/types.h> /* The Intel Quark SoC X1000 Core is codenamed lakemont */ #define LMT_IRLEN 8 /* lakemont tap instruction opcodes */ #define IDCODE 2 #define SUBMITPIR 3 #define PROBEMODE 4 #define WRPIR 6 #define RDWRPDR 8 #define TAPSTATUS 11 #define BYPASS 255 #define NOT_NULL 2 /* DR sizes */ #define ID_SIZE 32 #define PM_SIZE 1 #define PIR_SIZE 64 #define PDR_SIZE 32 #define TS_SIZE 32 #define BP_SIZE 1 #define MAX_SCAN_SIZE PIR_SIZE /* needed during lakemont probemode */ #define NOT_PMREG 0xfe #define NOT_AVAIL_REG 0xff #define PM_DSB ((uint32_t)0x00000000) #define PM_DSL ((uint32_t)0xFFFFFFFF) #define PM_DSAR ((uint32_t)0x004F9300) #define PM_DR7 ((uint32_t)0x00000400) #define DELAY_SUBMITPIR 0 /* for now 0 is working */ /* lakemont tapstatus bits */ #define TS_PRDY_BIT ((uint32_t)0x00000001) #define TS_EN_PM_BIT ((uint32_t)0x00000002) #define TS_PM_BIT ((uint32_t)0x00000004) #define TS_PMCR_BIT ((uint32_t)0x00000008) #define TS_SBP_BIT ((uint32_t)0x00000010) struct lakemont_core_reg { uint32_t num; struct target *target; struct x86_32_common *x86_32_common; uint64_t op; uint8_t pm_idx; }; struct scan_blk { uint8_t out[MAX_SCAN_SIZE]; /* scanned out to the tap */ uint8_t in[MAX_SCAN_SIZE]; /* in to our capture buf */ struct scan_field field; }; #define I(name) (((struct lakemont_core_reg *)x86_32->cache->reg_list[name].arch_info)->pm_idx) int lakemont_init_target(struct command_context *cmd_ctx, struct target *t); int lakemont_init_arch_info(struct target *t, struct x86_32_common *x86_32); int lakemont_poll(struct target *t); int lakemont_arch_state(struct target *t); int lakemont_halt(struct target *t); int lakemont_resume(struct target *t, int current, target_addr_t address, int handle_breakpoints, int debug_execution); int lakemont_step(struct target *t, int current, target_addr_t address, int handle_breakpoints); int lakemont_reset_assert(struct target *t); int lakemont_reset_deassert(struct target *t); int lakemont_update_after_probemode_entry(struct target *t); #endif /* OPENOCD_TARGET_LAKEMONT_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/ls1_sap.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2015 by Esben Haabendal <eha@deif.com> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include "target_type.h" #include <jtag/jtag.h> struct ls1_sap { struct jtag_tap *tap; }; static int ls1_sap_target_create(struct target *target, Jim_Interp *interp) { struct ls1_sap *ls1_sap = calloc(1, sizeof(struct ls1_sap)); ls1_sap->tap = target->tap; target->arch_info = ls1_sap; return ERROR_OK; } static int ls1_sap_init_target(struct command_context *cmd_ctx, struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int ls1_sap_arch_state(struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int ls1_sap_poll(struct target *target) { if ((target->state == TARGET_UNKNOWN) || (target->state == TARGET_RUNNING) || (target->state == TARGET_DEBUG_RUNNING)) target->state = TARGET_HALTED; return ERROR_OK; } static int ls1_sap_halt(struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int ls1_sap_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int ls1_sap_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int ls1_sap_assert_reset(struct target *target) { target->state = TARGET_RESET; LOG_DEBUG("%s", __func__); return ERROR_OK; } static int ls1_sap_deassert_reset(struct target *target) { target->state = TARGET_RUNNING; LOG_DEBUG("%s", __func__); return ERROR_OK; } static void ls1_sap_set_instr(struct jtag_tap *tap, uint32_t new_instr) { struct scan_field field; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) == new_instr) return; field.num_bits = tap->ir_length; uint8_t *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); free(t); } static void ls1_sap_set_addr_high(struct jtag_tap *tap, uint16_t addr_high) { struct scan_field field; uint8_t buf[2] = { 0 }; ls1_sap_set_instr(tap, 0x21); field.num_bits = 16; field.out_value = buf; buf_set_u32(buf, 0, 16, addr_high); field.in_value = NULL; field.check_value = NULL; field.check_mask = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); } static void ls1_sap_memory_cmd(struct jtag_tap *tap, uint32_t address, int32_t size, bool rnw) { struct scan_field field; uint8_t cmd[8] = { 0 }; ls1_sap_set_instr(tap, 0x24); field.num_bits = 64; field.out_value = cmd; buf_set_u64(cmd, 0, 9, 0); buf_set_u64(cmd, 9, 3, size); buf_set_u64(cmd, 12, 1, rnw); buf_set_u64(cmd, 13, 3, 0); buf_set_u64(cmd, 16, 32, address); buf_set_u64(cmd, 48, 16, 0); field.in_value = NULL; field.check_value = NULL; field.check_mask = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); } static void ls1_sap_memory_read(struct jtag_tap *tap, uint32_t size, uint8_t *value) { struct scan_field field; ls1_sap_set_instr(tap, 0x25); field.num_bits = 8 * size; field.out_value = NULL; field.in_value = value; field.check_value = NULL; field.check_mask = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); } static void ls1_sap_memory_write(struct jtag_tap *tap, uint32_t size, const uint8_t *value) { struct scan_field field; ls1_sap_set_instr(tap, 0x25); field.num_bits = 8 * size; field.out_value = value; field.in_value = NULL; field.check_value = NULL; field.check_mask = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); } static int ls1_sap_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { LOG_DEBUG("Reading memory at physical address 0x%" TARGET_PRIxADDR "; size %" PRIu32 "; count %" PRIu32, address, size, count); if (count == 0 || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; ls1_sap_set_addr_high(target->tap, 0); while (count--) { ls1_sap_memory_cmd(target->tap, address, size, true); ls1_sap_memory_read(target->tap, size, buffer); address += size; buffer += size; } return jtag_execute_queue(); } static int ls1_sap_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { LOG_DEBUG("Writing memory at physical address 0x%" TARGET_PRIxADDR "; size %" PRIu32 "; count %" PRIu32, address, size, count); if (count == 0 || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; ls1_sap_set_addr_high(target->tap, 0); while (count--) { ls1_sap_memory_cmd(target->tap, address, size, false); ls1_sap_memory_write(target->tap, size, buffer); address += size; buffer += size; } return jtag_execute_queue(); } struct target_type ls1_sap_target = { .name = "ls1_sap", .target_create = ls1_sap_target_create, .init_target = ls1_sap_init_target, .poll = ls1_sap_poll, .arch_state = ls1_sap_arch_state, .halt = ls1_sap_halt, .resume = ls1_sap_resume, .step = ls1_sap_step, .assert_reset = ls1_sap_assert_reset, .deassert_reset = ls1_sap_deassert_reset, .read_memory = ls1_sap_read_memory, .write_memory = ls1_sap_write_memory, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mem_ap.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 by Matthias Welwarsky <matthias.welwarsky@sysgo.com> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include "target_type.h" #include "arm_adi_v5.h" #include "register.h" #include <jtag/jtag.h> #define MEM_AP_COMMON_MAGIC 0x4DE4DA50 struct mem_ap { int common_magic; struct adiv5_dap *dap; struct adiv5_ap *ap; uint64_t ap_num; }; static int mem_ap_target_create(struct target *target, Jim_Interp *interp) { struct mem_ap *mem_ap; struct adiv5_private_config *pc; pc = (struct adiv5_private_config *)target->private_config; if (!pc) return ERROR_FAIL; if (pc->ap_num == DP_APSEL_INVALID) { LOG_ERROR("AP number not specified"); return ERROR_FAIL; } mem_ap = calloc(1, sizeof(struct mem_ap)); if (!mem_ap) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } mem_ap->ap_num = pc->ap_num; mem_ap->common_magic = MEM_AP_COMMON_MAGIC; mem_ap->dap = pc->dap; target->arch_info = mem_ap; if (!target->gdb_port_override) target->gdb_port_override = strdup("disabled"); return ERROR_OK; } static int mem_ap_init_target(struct command_context *cmd_ctx, struct target *target) { LOG_DEBUG("%s", __func__); target->state = TARGET_UNKNOWN; target->debug_reason = DBG_REASON_UNDEFINED; return ERROR_OK; } static void mem_ap_deinit_target(struct target *target) { struct mem_ap *mem_ap = target->arch_info; LOG_DEBUG("%s", __func__); if (mem_ap->ap) dap_put_ap(mem_ap->ap); free(target->private_config); free(target->arch_info); return; } static int mem_ap_arch_state(struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int mem_ap_poll(struct target *target) { if (target->state == TARGET_UNKNOWN) { target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; } return ERROR_OK; } static int mem_ap_halt(struct target *target) { LOG_DEBUG("%s", __func__); target->state = TARGET_HALTED; target->debug_reason = DBG_REASON_DBGRQ; target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } static int mem_ap_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { LOG_DEBUG("%s", __func__); target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; return ERROR_OK; } static int mem_ap_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { LOG_DEBUG("%s", __func__); target->state = TARGET_HALTED; target->debug_reason = DBG_REASON_DBGRQ; target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } static int mem_ap_assert_reset(struct target *target) { target->state = TARGET_RESET; target->debug_reason = DBG_REASON_UNDEFINED; LOG_DEBUG("%s", __func__); return ERROR_OK; } static int mem_ap_examine(struct target *target) { struct mem_ap *mem_ap = target->arch_info; if (!target_was_examined(target)) { if (!mem_ap->ap) { mem_ap->ap = dap_get_ap(mem_ap->dap, mem_ap->ap_num); if (!mem_ap->ap) { LOG_ERROR("Cannot get AP"); return ERROR_FAIL; } } target_set_examined(target); target->state = TARGET_UNKNOWN; target->debug_reason = DBG_REASON_UNDEFINED; return mem_ap_init(mem_ap->ap); } return ERROR_OK; } static int mem_ap_deassert_reset(struct target *target) { if (target->reset_halt) { target->state = TARGET_HALTED; target->debug_reason = DBG_REASON_DBGRQ; target_call_event_callbacks(target, TARGET_EVENT_HALTED); } else { target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; } LOG_DEBUG("%s", __func__); return ERROR_OK; } static int mem_ap_reg_get(struct reg *reg) { return ERROR_OK; } static int mem_ap_reg_set(struct reg *reg, uint8_t *buf) { return ERROR_OK; } static struct reg_arch_type mem_ap_reg_arch_type = { .get = mem_ap_reg_get, .set = mem_ap_reg_set, }; static const char *mem_ap_get_gdb_arch(struct target *target) { return "arm"; } /* * Dummy ARM register emulation: * reg[0..15]: 32 bits, r0~r12, sp, lr, pc * reg[16..23]: 96 bits, f0~f7 * reg[24]: 32 bits, fps * reg[25]: 32 bits, cpsr * * Set 'exist' only to reg[0..15], so initial response to GDB is correct */ #define NUM_REGS 26 #define MAX_REG_SIZE 96 #define REG_EXIST(n) ((n) < 16) #define REG_SIZE(n) ((((n) >= 16) && ((n) < 24)) ? 96 : 32) struct mem_ap_alloc_reg_list { /* reg_list must be the first field */ struct reg *reg_list[NUM_REGS]; struct reg regs[NUM_REGS]; uint8_t regs_value[MAX_REG_SIZE / 8]; }; static int mem_ap_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { struct mem_ap_alloc_reg_list *mem_ap_alloc = calloc(1, sizeof(struct mem_ap_alloc_reg_list)); if (!mem_ap_alloc) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } *reg_list = mem_ap_alloc->reg_list; *reg_list_size = NUM_REGS; struct reg *regs = mem_ap_alloc->regs; for (int i = 0; i < NUM_REGS; i++) { regs[i].number = i; regs[i].value = mem_ap_alloc->regs_value; regs[i].size = REG_SIZE(i); regs[i].exist = REG_EXIST(i); regs[i].type = &mem_ap_reg_arch_type; (*reg_list)[i] = ®s[i]; } return ERROR_OK; } static int mem_ap_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct mem_ap *mem_ap = target->arch_info; LOG_DEBUG("Reading memory at physical address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); if (count == 0 || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; return mem_ap_read_buf(mem_ap->ap, buffer, size, count, address); } static int mem_ap_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct mem_ap *mem_ap = target->arch_info; LOG_DEBUG("Writing memory at physical address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); if (count == 0 || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; return mem_ap_write_buf(mem_ap->ap, buffer, size, count, address); } struct target_type mem_ap_target = { .name = "mem_ap", .target_create = mem_ap_target_create, .init_target = mem_ap_init_target, .deinit_target = mem_ap_deinit_target, .examine = mem_ap_examine, .target_jim_configure = adiv5_jim_configure, .poll = mem_ap_poll, .arch_state = mem_ap_arch_state, .halt = mem_ap_halt, .resume = mem_ap_resume, .step = mem_ap_step, .assert_reset = mem_ap_assert_reset, .deassert_reset = mem_ap_deassert_reset, .get_gdb_arch = mem_ap_get_gdb_arch, .get_gdb_reg_list = mem_ap_get_gdb_reg_list, .read_memory = mem_ap_read_memory, .write_memory = mem_ap_write_memory, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips32.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "mips32.h" #include "breakpoints.h" #include "algorithm.h" #include "register.h" static const char *mips_isa_strings[] = { "MIPS32", "MIPS16", "", "MICRO MIPS32", }; #define MIPS32_GDB_DUMMY_FP_REG 1 /* * GDB registers * based on gdb-7.6.2/gdb/features/mips-{fpu,cp0,cpu}.xml */ static const struct { unsigned id; const char *name; enum reg_type type; const char *group; const char *feature; int flag; } mips32_regs[] = { { 0, "r0", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 1, "r1", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 2, "r2", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 3, "r3", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 4, "r4", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 5, "r5", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 6, "r6", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 7, "r7", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 8, "r8", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 9, "r9", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 10, "r10", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 11, "r11", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 12, "r12", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 13, "r13", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 14, "r14", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 15, "r15", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 16, "r16", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 17, "r17", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 18, "r18", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 19, "r19", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 20, "r20", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 21, "r21", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 22, "r22", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 23, "r23", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 24, "r24", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 25, "r25", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 26, "r26", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 27, "r27", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 28, "r28", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 29, "r29", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 30, "r30", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 31, "r31", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 32, "status", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 }, { 33, "lo", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 34, "hi", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 35, "badvaddr", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 }, { 36, "cause", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 }, { 37, "pc", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 38, "f0", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 39, "f1", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 40, "f2", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 41, "f3", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 42, "f4", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 43, "f5", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 44, "f6", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 45, "f7", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 46, "f8", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 47, "f9", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 48, "f10", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 49, "f11", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 50, "f12", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 51, "f13", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 52, "f14", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 53, "f15", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 54, "f16", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 55, "f17", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 56, "f18", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 57, "f19", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 58, "f20", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 59, "f21", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 60, "f22", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 61, "f23", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 62, "f24", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 63, "f25", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 64, "f26", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 65, "f27", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 66, "f28", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 67, "f29", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 68, "f30", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 69, "f31", REG_TYPE_IEEE_SINGLE, NULL, "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 70, "fcsr", REG_TYPE_INT, "float", "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, { 71, "fir", REG_TYPE_INT, "float", "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, }; #define MIPS32_NUM_REGS ARRAY_SIZE(mips32_regs) static uint8_t mips32_gdb_dummy_fp_value[] = {0, 0, 0, 0}; static int mips32_get_core_reg(struct reg *reg) { int retval; struct mips32_core_reg *mips32_reg = reg->arch_info; struct target *target = mips32_reg->target; struct mips32_common *mips32_target = target_to_mips32(target); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = mips32_target->read_core_reg(target, mips32_reg->num); return retval; } static int mips32_set_core_reg(struct reg *reg, uint8_t *buf) { struct mips32_core_reg *mips32_reg = reg->arch_info; struct target *target = mips32_reg->target; uint32_t value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; buf_set_u32(reg->value, 0, 32, value); reg->dirty = true; reg->valid = true; return ERROR_OK; } static int mips32_read_core_reg(struct target *target, unsigned int num) { uint32_t reg_value; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); if (num >= MIPS32_NUM_REGS) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = mips32->core_regs[num]; buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); mips32->core_cache->reg_list[num].valid = true; mips32->core_cache->reg_list[num].dirty = false; return ERROR_OK; } static int mips32_write_core_reg(struct target *target, unsigned int num) { uint32_t reg_value; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); if (num >= MIPS32_NUM_REGS) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); mips32->core_regs[num] = reg_value; LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value); mips32->core_cache->reg_list[num].valid = true; mips32->core_cache->reg_list[num].dirty = false; return ERROR_OK; } int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); unsigned int i; /* include floating point registers */ *reg_list_size = MIPS32_NUM_REGS; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < MIPS32_NUM_REGS; i++) (*reg_list)[i] = &mips32->core_cache->reg_list[i]; return ERROR_OK; } int mips32_save_context(struct target *target) { unsigned int i; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; /* read core registers */ mips32_pracc_read_regs(ejtag_info, mips32->core_regs); for (i = 0; i < MIPS32_NUM_REGS; i++) { if (!mips32->core_cache->reg_list[i].valid) mips32->read_core_reg(target, i); } return ERROR_OK; } int mips32_restore_context(struct target *target) { unsigned int i; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; for (i = 0; i < MIPS32_NUM_REGS; i++) { if (mips32->core_cache->reg_list[i].dirty) mips32->write_core_reg(target, i); } /* write core regs */ mips32_pracc_write_regs(ejtag_info, mips32->core_regs); return ERROR_OK; } int mips32_arch_state(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); LOG_USER("target halted in %s mode due to %s, pc: 0x%8.8" PRIx32 "", mips_isa_strings[mips32->isa_mode], debug_reason_name(target), buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32)); return ERROR_OK; } static const struct reg_arch_type mips32_reg_type = { .get = mips32_get_core_reg, .set = mips32_set_core_reg, }; struct reg_cache *mips32_build_reg_cache(struct target *target) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); int num_regs = MIPS32_NUM_REGS; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); struct mips32_core_reg *arch_info = malloc(sizeof(struct mips32_core_reg) * num_regs); struct reg_feature *feature; int i; /* Build the process context cache */ cache->name = "mips32 registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = num_regs; (*cache_p) = cache; mips32->core_cache = cache; for (i = 0; i < num_regs; i++) { arch_info[i].num = mips32_regs[i].id; arch_info[i].target = target; arch_info[i].mips32_common = mips32; reg_list[i].name = mips32_regs[i].name; reg_list[i].size = 32; if (mips32_regs[i].flag == MIPS32_GDB_DUMMY_FP_REG) { reg_list[i].value = mips32_gdb_dummy_fp_value; reg_list[i].valid = true; reg_list[i].arch_info = NULL; register_init_dummy(®_list[i]); } else { reg_list[i].value = calloc(1, 4); reg_list[i].valid = false; reg_list[i].type = &mips32_reg_type; reg_list[i].arch_info = &arch_info[i]; reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); if (reg_list[i].reg_data_type) reg_list[i].reg_data_type->type = mips32_regs[i].type; else LOG_ERROR("unable to allocate reg type list"); } reg_list[i].dirty = false; reg_list[i].group = mips32_regs[i].group; reg_list[i].number = i; reg_list[i].exist = true; reg_list[i].caller_save = true; /* gdb defaults to true */ feature = calloc(1, sizeof(struct reg_feature)); if (feature) { feature->name = mips32_regs[i].feature; reg_list[i].feature = feature; } else LOG_ERROR("unable to allocate feature list"); } return cache; } int mips32_init_arch_info(struct target *target, struct mips32_common *mips32, struct jtag_tap *tap) { target->arch_info = mips32; mips32->common_magic = MIPS32_COMMON_MAGIC; mips32->fast_data_area = NULL; mips32->isa_imp = MIPS32_ONLY; /* default */ /* has breakpoint/watchpoint unit been scanned */ mips32->bp_scanned = 0; mips32->data_break_list = NULL; mips32->ejtag_info.tap = tap; mips32->read_core_reg = mips32_read_core_reg; mips32->write_core_reg = mips32_write_core_reg; /* if unknown endianness defaults to little endian, 1 */ mips32->ejtag_info.endianness = target->endianness == TARGET_BIG_ENDIAN ? 0 : 1; mips32->ejtag_info.scan_delay = MIPS32_SCAN_DELAY_LEGACY_MODE; mips32->ejtag_info.mode = 0; /* Initial default value */ mips32->ejtag_info.isa = 0; /* isa on debug mips32, updated by poll function */ mips32->ejtag_info.config_regs = 0; /* no config register read */ return ERROR_OK; } /* run to exit point. return error if exit point was not reached. */ static int mips32_run_and_wait(struct target *target, target_addr_t entry_point, unsigned int timeout_ms, target_addr_t exit_point, struct mips32_common *mips32) { uint32_t pc; int retval; /* This code relies on the target specific resume() and poll()->debug_entry() * sequence to write register values to the processor and the read them back */ retval = target_resume(target, 0, entry_point, 0, 1); if (retval != ERROR_OK) return retval; retval = target_wait_state(target, TARGET_HALTED, timeout_ms); /* If the target fails to halt due to the breakpoint, force a halt */ if (retval != ERROR_OK || target->state != TARGET_HALTED) { retval = target_halt(target); if (retval != ERROR_OK) return retval; retval = target_wait_state(target, TARGET_HALTED, 500); if (retval != ERROR_OK) return retval; return ERROR_TARGET_TIMEOUT; } pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32); if (exit_point && (pc != exit_point)) { LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 " ", pc); return ERROR_TARGET_TIMEOUT; } return ERROR_OK; } int mips32_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { struct mips32_common *mips32 = target_to_mips32(target); struct mips32_algorithm *mips32_algorithm_info = arch_info; enum mips32_isa_mode isa_mode = mips32->isa_mode; uint32_t context[MIPS32_NUM_REGS]; int retval = ERROR_OK; LOG_DEBUG("Running algorithm"); /* NOTE: mips32_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ if (mips32->common_magic != MIPS32_COMMON_MAGIC) { LOG_ERROR("current target isn't a MIPS32 target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* refresh core register cache */ for (unsigned int i = 0; i < MIPS32_NUM_REGS; i++) { if (!mips32->core_cache->reg_list[i].valid) mips32->read_core_reg(target, i); context[i] = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32); } for (int i = 0; i < num_mem_params; i++) { if (mem_params[i].direction == PARAM_IN) continue; retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } for (int i = 0; i < num_reg_params; i++) { if (reg_params[i].direction == PARAM_IN) continue; struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } mips32_set_core_reg(reg, reg_params[i].value); } mips32->isa_mode = mips32_algorithm_info->isa_mode; retval = mips32_run_and_wait(target, entry_point, timeout_ms, exit_point, mips32); if (retval != ERROR_OK) return retval; for (int i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) { retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } } for (int i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } /* restore everything we saved before */ for (unsigned int i = 0; i < MIPS32_NUM_REGS; i++) { uint32_t regvalue; regvalue = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32); if (regvalue != context[i]) { LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, mips32->core_cache->reg_list[i].name, context[i]); buf_set_u32(mips32->core_cache->reg_list[i].value, 0, 32, context[i]); mips32->core_cache->reg_list[i].valid = true; mips32->core_cache->reg_list[i].dirty = true; } } mips32->isa_mode = isa_mode; return ERROR_OK; } int mips32_examine(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); if (!target_was_examined(target)) { target_set_examined(target); /* we will configure later */ mips32->bp_scanned = 0; mips32->num_inst_bpoints = 0; mips32->num_data_bpoints = 0; mips32->num_inst_bpoints_avail = 0; mips32->num_data_bpoints_avail = 0; } return ERROR_OK; } static int mips32_configure_ibs(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int retval, i; uint32_t bpinfo; /* get number of inst breakpoints */ retval = target_read_u32(target, ejtag_info->ejtag_ibs_addr, &bpinfo); if (retval != ERROR_OK) return retval; mips32->num_inst_bpoints = (bpinfo >> 24) & 0x0F; mips32->num_inst_bpoints_avail = mips32->num_inst_bpoints; mips32->inst_break_list = calloc(mips32->num_inst_bpoints, sizeof(struct mips32_comparator)); for (i = 0; i < mips32->num_inst_bpoints; i++) mips32->inst_break_list[i].reg_address = ejtag_info->ejtag_iba0_addr + (ejtag_info->ejtag_iba_step_size * i); /* clear IBIS reg */ retval = target_write_u32(target, ejtag_info->ejtag_ibs_addr, 0); return retval; } static int mips32_configure_dbs(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int retval, i; uint32_t bpinfo; /* get number of data breakpoints */ retval = target_read_u32(target, ejtag_info->ejtag_dbs_addr, &bpinfo); if (retval != ERROR_OK) return retval; mips32->num_data_bpoints = (bpinfo >> 24) & 0x0F; mips32->num_data_bpoints_avail = mips32->num_data_bpoints; mips32->data_break_list = calloc(mips32->num_data_bpoints, sizeof(struct mips32_comparator)); for (i = 0; i < mips32->num_data_bpoints; i++) mips32->data_break_list[i].reg_address = ejtag_info->ejtag_dba0_addr + (ejtag_info->ejtag_dba_step_size * i); /* clear DBIS reg */ retval = target_write_u32(target, ejtag_info->ejtag_dbs_addr, 0); return retval; } int mips32_configure_break_unit(struct target *target) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int retval; uint32_t dcr; if (mips32->bp_scanned) return ERROR_OK; /* get info about breakpoint support */ retval = target_read_u32(target, EJTAG_DCR, &dcr); if (retval != ERROR_OK) return retval; /* EJTAG 2.0 defines IB and DB bits in IMP instead of DCR. */ if (ejtag_info->ejtag_version == EJTAG_VERSION_20) { ejtag_info->debug_caps = dcr & EJTAG_DCR_ENM; if (!(ejtag_info->impcode & EJTAG_V20_IMP_NOIB)) ejtag_info->debug_caps |= EJTAG_DCR_IB; if (!(ejtag_info->impcode & EJTAG_V20_IMP_NODB)) ejtag_info->debug_caps |= EJTAG_DCR_DB; } else /* keep debug caps for later use */ ejtag_info->debug_caps = dcr & (EJTAG_DCR_ENM | EJTAG_DCR_IB | EJTAG_DCR_DB); if (ejtag_info->debug_caps & EJTAG_DCR_IB) { retval = mips32_configure_ibs(target); if (retval != ERROR_OK) return retval; } if (ejtag_info->debug_caps & EJTAG_DCR_DB) { retval = mips32_configure_dbs(target); if (retval != ERROR_OK) return retval; } /* check if target endianness settings matches debug control register */ if (((ejtag_info->debug_caps & EJTAG_DCR_ENM) && (target->endianness == TARGET_LITTLE_ENDIAN)) || (!(ejtag_info->debug_caps & EJTAG_DCR_ENM) && (target->endianness == TARGET_BIG_ENDIAN))) LOG_WARNING("DCR endianness settings does not match target settings"); LOG_DEBUG("DCR 0x%" PRIx32 " numinst %i numdata %i", dcr, mips32->num_inst_bpoints, mips32->num_data_bpoints); mips32->bp_scanned = 1; return ERROR_OK; } int mips32_enable_interrupts(struct target *target, int enable) { int retval; int update = 0; uint32_t dcr; /* read debug control register */ retval = target_read_u32(target, EJTAG_DCR, &dcr); if (retval != ERROR_OK) return retval; if (enable) { if (!(dcr & EJTAG_DCR_INTE)) { /* enable interrupts */ dcr |= EJTAG_DCR_INTE; update = 1; } } else { if (dcr & EJTAG_DCR_INTE) { /* disable interrupts */ dcr &= ~EJTAG_DCR_INTE; update = 1; } } if (update) { retval = target_write_u32(target, EJTAG_DCR, dcr); if (retval != ERROR_OK) return retval; } return ERROR_OK; } /* read config to config3 cp0 registers and log isa implementation */ int mips32_read_config_regs(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; if (ejtag_info->config_regs == 0) for (int i = 0; i != 4; i++) { int retval = mips32_cp0_read(ejtag_info, &ejtag_info->config[i], 16, i); if (retval != ERROR_OK) { LOG_ERROR("isa info not available, failed to read cp0 config register: %" PRId32, i); ejtag_info->config_regs = 0; return retval; } ejtag_info->config_regs = i + 1; if ((ejtag_info->config[i] & (1 << 31)) == 0) break; /* no more config registers implemented */ } else return ERROR_OK; /* already successfully read */ LOG_DEBUG("read %"PRIu32" config registers", ejtag_info->config_regs); if (ejtag_info->impcode & EJTAG_IMP_MIPS16) { mips32->isa_imp = MIPS32_MIPS16; LOG_USER("MIPS32 with MIPS16 support implemented"); } else if (ejtag_info->config_regs >= 4) { /* config3 implemented */ unsigned isa_imp = (ejtag_info->config[3] & MIPS32_CONFIG3_ISA_MASK) >> MIPS32_CONFIG3_ISA_SHIFT; if (isa_imp == 1) { mips32->isa_imp = MMIPS32_ONLY; LOG_USER("MICRO MIPS32 only implemented"); } else if (isa_imp != 0) { mips32->isa_imp = MIPS32_MMIPS32; LOG_USER("MIPS32 and MICRO MIPS32 implemented"); } } if (mips32->isa_imp == MIPS32_ONLY) /* initial default value */ LOG_USER("MIPS32 only implemented"); return ERROR_OK; } int mips32_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct reg_param reg_params[2]; struct mips32_algorithm mips32_info; struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; /* see contrib/loaders/checksum/mips32.s for src */ uint32_t isa = ejtag_info->isa ? 1 : 0; uint32_t mips_crc_code[] = { MIPS32_ADDIU(isa, 12, 4, 0), /* addiu $t4, $a0, 0 */ MIPS32_ADDIU(isa, 10, 5, 0), /* addiu $t2, $a1, 0 */ MIPS32_ADDIU(isa, 4, 0, 0xFFFF), /* addiu $a0, $zero, 0xffff */ MIPS32_BEQ(isa, 0, 0, 0x10 << isa), /* beq $zero, $zero, ncomp */ MIPS32_ADDIU(isa, 11, 0, 0), /* addiu $t3, $zero, 0 */ /* nbyte: */ MIPS32_LB(isa, 5, 0, 12), /* lb $a1, ($t4) */ MIPS32_ADDI(isa, 12, 12, 1), /* addi $t4, $t4, 1 */ MIPS32_SLL(isa, 5, 5, 24), /* sll $a1, $a1, 24 */ MIPS32_LUI(isa, 2, 0x04c1), /* lui $v0, 0x04c1 */ MIPS32_XOR(isa, 4, 4, 5), /* xor $a0, $a0, $a1 */ MIPS32_ORI(isa, 7, 2, 0x1db7), /* ori $a3, $v0, 0x1db7 */ MIPS32_ADDU(isa, 6, 0, 0), /* addu $a2, $zero, $zero */ /* loop */ MIPS32_SLL(isa, 8, 4, 1), /* sll $t0, $a0, 1 */ MIPS32_ADDIU(isa, 6, 6, 1), /* addiu $a2, $a2, 1 */ MIPS32_SLTI(isa, 4, 4, 0), /* slti $a0, $a0, 0 */ MIPS32_XOR(isa, 9, 8, 7), /* xor $t1, $t0, $a3 */ MIPS32_MOVN(isa, 8, 9, 4), /* movn $t0, $t1, $a0 */ MIPS32_SLTI(isa, 3, 6, 8), /* slti $v1, $a2, 8 */ MIPS32_BNE(isa, 3, 0, NEG16(7 << isa)), /* bne $v1, $zero, loop */ MIPS32_ADDU(isa, 4, 8, 0), /* addu $a0, $t0, $zero */ /* ncomp */ MIPS32_BNE(isa, 10, 11, NEG16(16 << isa)), /* bne $t2, $t3, nbyte */ MIPS32_ADDIU(isa, 11, 11, 1), /* addiu $t3, $t3, 1 */ MIPS32_SDBBP(isa), }; /* make sure we have a working area */ if (target_alloc_working_area(target, sizeof(mips_crc_code), &crc_algorithm) != ERROR_OK) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; pracc_swap16_array(ejtag_info, mips_crc_code, ARRAY_SIZE(mips_crc_code)); /* convert mips crc code into a buffer in target endianness */ uint8_t mips_crc_code_8[sizeof(mips_crc_code)]; target_buffer_set_u32_array(target, mips_crc_code_8, ARRAY_SIZE(mips_crc_code), mips_crc_code); int retval = target_write_buffer(target, crc_algorithm->address, sizeof(mips_crc_code), mips_crc_code_8); if (retval != ERROR_OK) return retval; mips32_info.common_magic = MIPS32_COMMON_MAGIC; mips32_info.isa_mode = isa ? MIPS32_ISA_MMIPS32 : MIPS32_ISA_MIPS32; /* run isa as in debug mode */ init_reg_param(®_params[0], "r4", 32, PARAM_IN_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r5", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); unsigned int timeout = 20000 * (1 + (count / (1024 * 1024))); retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, crc_algorithm->address + (sizeof(mips_crc_code) - 4), timeout, &mips32_info); if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); target_free_working_area(target, crc_algorithm); return retval; } /** Checks whether a memory region is erased. */ int mips32_blank_check_memory(struct target *target, struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value) { struct working_area *erase_check_algorithm; struct reg_param reg_params[3]; struct mips32_algorithm mips32_info; struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; if (erased_value != 0xff) { LOG_ERROR("Erase value 0x%02" PRIx8 " not yet supported for MIPS32", erased_value); return ERROR_FAIL; } uint32_t isa = ejtag_info->isa ? 1 : 0; uint32_t erase_check_code[] = { /* nbyte: */ MIPS32_LB(isa, 8, 0, 4), /* lb $t0, ($a0) */ MIPS32_AND(isa, 6, 6, 8), /* and $a2, $a2, $t0 */ MIPS32_ADDIU(isa, 5, 5, NEG16(1)), /* addiu $a1, $a1, -1 */ MIPS32_BNE(isa, 5, 0, NEG16(4 << isa)), /* bne $a1, $zero, nbyte */ MIPS32_ADDIU(isa, 4, 4, 1), /* addiu $a0, $a0, 1 */ MIPS32_SDBBP(isa) /* sdbbp */ }; /* make sure we have a working area */ if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; pracc_swap16_array(ejtag_info, erase_check_code, ARRAY_SIZE(erase_check_code)); /* convert erase check code into a buffer in target endianness */ uint8_t erase_check_code_8[sizeof(erase_check_code)]; target_buffer_set_u32_array(target, erase_check_code_8, ARRAY_SIZE(erase_check_code), erase_check_code); int retval = target_write_buffer(target, erase_check_algorithm->address, sizeof(erase_check_code), erase_check_code_8); if (retval != ERROR_OK) goto cleanup; mips32_info.common_magic = MIPS32_COMMON_MAGIC; mips32_info.isa_mode = isa ? MIPS32_ISA_MMIPS32 : MIPS32_ISA_MIPS32; init_reg_param(®_params[0], "r4", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, blocks[0].address); init_reg_param(®_params[1], "r5", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, blocks[0].size); init_reg_param(®_params[2], "r6", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, erased_value); retval = target_run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address, erase_check_algorithm->address + (sizeof(erase_check_code) - 4), 10000, &mips32_info); if (retval == ERROR_OK) blocks[0].result = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); cleanup: target_free_working_area(target, erase_check_algorithm); if (retval != ERROR_OK) return retval; return 1; /* only one block has been checked */ } static int mips32_verify_pointer(struct command_invocation *cmd, struct mips32_common *mips32) { if (mips32->common_magic != MIPS32_COMMON_MAGIC) { command_print(cmd, "target is not an MIPS32"); return ERROR_TARGET_INVALID; } return ERROR_OK; } /** * MIPS32 targets expose command interface * to manipulate CP0 registers */ COMMAND_HANDLER(mips32_handle_cp0_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; retval = mips32_verify_pointer(CMD, mips32); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } /* two or more argument, access a single register/select (write if third argument is given) */ if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; else { uint32_t cp0_reg, cp0_sel; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel); if (CMD_ARGC == 2) { uint32_t value; retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel); if (retval != ERROR_OK) { command_print(CMD, "couldn't access reg %" PRIu32, cp0_reg); return ERROR_OK; } command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32, cp0_reg, cp0_sel, value); } else if (CMD_ARGC == 3) { uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); retval = mips32_cp0_write(ejtag_info, value, cp0_reg, cp0_sel); if (retval != ERROR_OK) { command_print(CMD, "couldn't access cp0 reg %" PRIu32 ", select %" PRIu32, cp0_reg, cp0_sel); return ERROR_OK; } command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32, cp0_reg, cp0_sel, value); } } return ERROR_OK; } COMMAND_HANDLER(mips32_handle_scan_delay_command) { struct target *target = get_current_target(CMD_CTX); struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], ejtag_info->scan_delay); else if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "scan delay: %d nsec", ejtag_info->scan_delay); if (ejtag_info->scan_delay >= MIPS32_SCAN_DELAY_LEGACY_MODE) { ejtag_info->mode = 0; command_print(CMD, "running in legacy mode"); } else { ejtag_info->mode = 1; command_print(CMD, "running in fast queued mode"); } return ERROR_OK; } static const struct command_registration mips32_exec_command_handlers[] = { { .name = "cp0", .handler = mips32_handle_cp0_command, .mode = COMMAND_EXEC, .usage = "regnum select [value]", .help = "display/modify cp0 register", }, { .name = "scan_delay", .handler = mips32_handle_scan_delay_command, .mode = COMMAND_ANY, .help = "display/set scan delay in nano seconds", .usage = "[value]", }, COMMAND_REGISTRATION_DONE }; const struct command_registration mips32_command_handlers[] = { { .name = "mips32", .mode = COMMAND_ANY, .help = "mips32 command group", .usage = "", .chain = mips32_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips32.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_MIPS32_H #define OPENOCD_TARGET_MIPS32_H #include "target.h" #include "mips32_pracc.h" #define MIPS32_COMMON_MAGIC 0xB320B320U /** * Memory segments (32bit kernel mode addresses) * These are the traditional names used in the 32-bit universe. */ #define KUSEG 0x00000000 #define KSEG0 0x80000000 #define KSEG1 0xa0000000 #define KSEG2 0xc0000000 #define KSEG3 0xe0000000 /** Returns the kernel segment base of a given address */ #define KSEGX(a) ((a) & 0xe0000000) /** CP0 CONFIG register fields */ #define MIPS32_CONFIG0_KU_SHIFT 25 #define MIPS32_CONFIG0_KU_MASK (0x7 << MIPS32_CONFIG0_KU_SHIFT) #define MIPS32_CONFIG0_K0_SHIFT 0 #define MIPS32_CONFIG0_K0_MASK (0x7 << MIPS32_CONFIG0_K0_SHIFT) #define MIPS32_CONFIG0_K23_SHIFT 28 #define MIPS32_CONFIG0_K23_MASK (0x7 << MIPS32_CONFIG0_K23_SHIFT) #define MIPS32_CONFIG0_AR_SHIFT 10 #define MIPS32_CONFIG0_AR_MASK (0x7 << MIPS32_CONFIG0_AR_SHIFT) #define MIPS32_CONFIG1_DL_SHIFT 10 #define MIPS32_CONFIG1_DL_MASK (0x7 << MIPS32_CONFIG1_DL_SHIFT) #define MIPS32_CONFIG3_ISA_SHIFT 14 #define MIPS32_CONFIG3_ISA_MASK (3 << MIPS32_CONFIG3_ISA_SHIFT) #define MIPS32_ARCH_REL1 0x0 #define MIPS32_ARCH_REL2 0x1 #define MIPS32_SCAN_DELAY_LEGACY_MODE 2000000 /* offsets into mips32 core register cache */ enum { MIPS32_PC = 37, MIPS32_FIR = 71, MIPS32NUMCOREREGS }; enum mips32_isa_mode { MIPS32_ISA_MIPS32 = 0, MIPS32_ISA_MIPS16E = 1, MIPS32_ISA_MMIPS32 = 3, }; enum mips32_isa_imp { MIPS32_ONLY = 0, MMIPS32_ONLY = 1, MIPS32_MIPS16 = 2, MIPS32_MMIPS32 = 3, }; struct mips32_comparator { int used; uint32_t bp_value; uint32_t reg_address; }; struct mips32_common { unsigned int common_magic; void *arch_info; struct reg_cache *core_cache; struct mips_ejtag ejtag_info; uint32_t core_regs[MIPS32NUMCOREREGS]; enum mips32_isa_mode isa_mode; enum mips32_isa_imp isa_imp; /* working area for fastdata access */ struct working_area *fast_data_area; int bp_scanned; int num_inst_bpoints; int num_data_bpoints; int num_inst_bpoints_avail; int num_data_bpoints_avail; struct mips32_comparator *inst_break_list; struct mips32_comparator *data_break_list; /* register cache to processor synchronization */ int (*read_core_reg)(struct target *target, unsigned int num); int (*write_core_reg)(struct target *target, unsigned int num); }; static inline struct mips32_common * target_to_mips32(struct target *target) { return target->arch_info; } struct mips32_core_reg { uint32_t num; struct target *target; struct mips32_common *mips32_common; }; struct mips32_algorithm { unsigned int common_magic; enum mips32_isa_mode isa_mode; }; #define MIPS32_OP_ADDU 0x21u #define MIPS32_OP_ADDIU 0x09u #define MIPS32_OP_ANDI 0x0Cu #define MIPS32_OP_BEQ 0x04u #define MIPS32_OP_BGTZ 0x07u #define MIPS32_OP_BNE 0x05u #define MIPS32_OP_ADDI 0x08u #define MIPS32_OP_AND 0x24u #define MIPS32_OP_CACHE 0x2Fu #define MIPS32_OP_COP0 0x10u #define MIPS32_OP_J 0x02u #define MIPS32_OP_JR 0x08u #define MIPS32_OP_LUI 0x0Fu #define MIPS32_OP_LW 0x23u #define MIPS32_OP_LB 0x20u #define MIPS32_OP_LBU 0x24u #define MIPS32_OP_LHU 0x25u #define MIPS32_OP_MFHI 0x10u #define MIPS32_OP_MTHI 0x11u #define MIPS32_OP_MFLO 0x12u #define MIPS32_OP_MTLO 0x13u #define MIPS32_OP_RDHWR 0x3Bu #define MIPS32_OP_SB 0x28u #define MIPS32_OP_SH 0x29u #define MIPS32_OP_SW 0x2Bu #define MIPS32_OP_ORI 0x0Du #define MIPS32_OP_XORI 0x0Eu #define MIPS32_OP_XOR 0x26u #define MIPS32_OP_SLTU 0x2Bu #define MIPS32_OP_SRL 0x03u #define MIPS32_OP_SYNCI 0x1Fu #define MIPS32_OP_SLL 0x00u #define MIPS32_OP_SLTI 0x0Au #define MIPS32_OP_MOVN 0x0Bu #define MIPS32_OP_REGIMM 0x01u #define MIPS32_OP_SDBBP 0x3Fu #define MIPS32_OP_SPECIAL 0x00u #define MIPS32_OP_SPECIAL2 0x07u #define MIPS32_OP_SPECIAL3 0x1Fu #define MIPS32_COP0_MF 0x00u #define MIPS32_COP0_MT 0x04u #define MIPS32_R_INST(opcode, rs, rt, rd, shamt, funct) \ (((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | ((rd) << 11) | ((shamt) << 6) | (funct)) #define MIPS32_I_INST(opcode, rs, rt, immd) \ (((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | (immd)) #define MIPS32_J_INST(opcode, addr) (((opcode) << 26) | (addr)) #define MIPS32_ISA_NOP 0 #define MIPS32_ISA_ADDI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ADDI, src, tar, val) #define MIPS32_ISA_ADDIU(tar, src, val) MIPS32_I_INST(MIPS32_OP_ADDIU, src, tar, val) #define MIPS32_ISA_ADDU(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_ADDU) #define MIPS32_ISA_AND(dst, src, tar) MIPS32_R_INST(0, src, tar, dst, 0, MIPS32_OP_AND) #define MIPS32_ISA_ANDI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ANDI, src, tar, val) #define MIPS32_ISA_B(off) MIPS32_ISA_BEQ(0, 0, off) #define MIPS32_ISA_BEQ(src, tar, off) MIPS32_I_INST(MIPS32_OP_BEQ, src, tar, off) #define MIPS32_ISA_BGTZ(reg, off) MIPS32_I_INST(MIPS32_OP_BGTZ, reg, 0, off) #define MIPS32_ISA_BNE(src, tar, off) MIPS32_I_INST(MIPS32_OP_BNE, src, tar, off) #define MIPS32_ISA_CACHE(op, off, base) MIPS32_I_INST(MIPS32_OP_CACHE, base, op, off) #define MIPS32_ISA_J(tar) MIPS32_J_INST(MIPS32_OP_J, (0x0FFFFFFFu & (tar)) >> 2) #define MIPS32_ISA_JR(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_JR) #define MIPS32_ISA_LB(reg, off, base) MIPS32_I_INST(MIPS32_OP_LB, base, reg, off) #define MIPS32_ISA_LBU(reg, off, base) MIPS32_I_INST(MIPS32_OP_LBU, base, reg, off) #define MIPS32_ISA_LHU(reg, off, base) MIPS32_I_INST(MIPS32_OP_LHU, base, reg, off) #define MIPS32_ISA_LUI(reg, val) MIPS32_I_INST(MIPS32_OP_LUI, 0, reg, val) #define MIPS32_ISA_LW(reg, off, base) MIPS32_I_INST(MIPS32_OP_LW, base, reg, off) #define MIPS32_ISA_MFC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MF, gpr, cpr, 0, sel) #define MIPS32_ISA_MTC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MT, gpr, cpr, 0, sel) #define MIPS32_ISA_MFLO(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFLO) #define MIPS32_ISA_MFHI(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFHI) #define MIPS32_ISA_MTLO(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTLO) #define MIPS32_ISA_MTHI(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTHI) #define MIPS32_ISA_MOVN(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_MOVN) #define MIPS32_ISA_ORI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ORI, src, tar, val) #define MIPS32_ISA_RDHWR(tar, dst) MIPS32_R_INST(MIPS32_OP_SPECIAL3, 0, tar, dst, 0, MIPS32_OP_RDHWR) #define MIPS32_ISA_SB(reg, off, base) MIPS32_I_INST(MIPS32_OP_SB, base, reg, off) #define MIPS32_ISA_SH(reg, off, base) MIPS32_I_INST(MIPS32_OP_SH, base, reg, off) #define MIPS32_ISA_SW(reg, off, base) MIPS32_I_INST(MIPS32_OP_SW, base, reg, off) #define MIPS32_ISA_SLL(dst, src, sa) MIPS32_R_INST(MIPS32_OP_SPECIAL, 0, src, dst, sa, MIPS32_OP_SLL) #define MIPS32_ISA_SLTI(tar, src, val) MIPS32_I_INST(MIPS32_OP_SLTI, src, tar, val) #define MIPS32_ISA_SLTU(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_SLTU) #define MIPS32_ISA_SRL(reg, src, off) MIPS32_R_INST(0, 0, src, reg, off, MIPS32_OP_SRL) #define MIPS32_ISA_SYNC 0xFu #define MIPS32_ISA_SYNCI(off, base) MIPS32_I_INST(MIPS32_OP_REGIMM, base, MIPS32_OP_SYNCI, off) #define MIPS32_ISA_XOR(reg, val1, val2) MIPS32_R_INST(0, val1, val2, reg, 0, MIPS32_OP_XOR) #define MIPS32_ISA_XORI(tar, src, val) MIPS32_I_INST(MIPS32_OP_XORI, src, tar, val) #define MIPS32_ISA_SYNCI_STEP 0x1 /* reg num od address step size to be used with synci instruction */ /** * Cache operations definitions * Operation field is 5 bits long : * 1) bits 1..0 hold cache type * 2) bits 4..2 hold operation code */ #define MIPS32_CACHE_D_HIT_WRITEBACK ((0x1 << 0) | (0x6 << 2)) #define MIPS32_CACHE_I_HIT_INVALIDATE ((0x0 << 0) | (0x4 << 2)) /* ejtag specific instructions */ #define MIPS32_ISA_DRET 0x4200001Fu /* MIPS32_ISA_J_INST(MIPS32_ISA_OP_SPECIAL2, MIPS32_ISA_OP_SDBBP) */ #define MIPS32_ISA_SDBBP 0x7000003Fu #define MIPS16_ISA_SDBBP 0xE801u /*MICRO MIPS INSTRUCTIONS, see doc MD00582 */ #define POOL32A 0X00u #define POOL32AXF 0x3Cu #define POOL32B 0x08u #define POOL32I 0x10u #define MMIPS32_OP_ADDI 0x04u #define MMIPS32_OP_ADDIU 0x0Cu #define MMIPS32_OP_ADDU 0x150u #define MMIPS32_OP_AND 0x250u #define MMIPS32_OP_ANDI 0x34u #define MMIPS32_OP_BEQ 0x25u #define MMIPS32_OP_BGTZ 0x06u #define MMIPS32_OP_BNE 0x2Du #define MMIPS32_OP_CACHE 0x06u #define MMIPS32_OP_J 0x35u #define MMIPS32_OP_JALR 0x03Cu #define MMIPS32_OP_LB 0x07u #define MMIPS32_OP_LBU 0x05u #define MMIPS32_OP_LHU 0x0Du #define MMIPS32_OP_LUI 0x0Du #define MMIPS32_OP_LW 0x3Fu #define MMIPS32_OP_MFC0 0x03u #define MMIPS32_OP_MTC0 0x0Bu #define MMIPS32_OP_MFLO 0x075u #define MMIPS32_OP_MFHI 0x035u #define MMIPS32_OP_MTLO 0x0F5u #define MMIPS32_OP_MTHI 0x0B5u #define MMIPS32_OP_MOVN 0x018u #define MMIPS32_OP_ORI 0x14u #define MMIPS32_OP_RDHWR 0x1ACu #define MMIPS32_OP_SB 0x06u #define MMIPS32_OP_SH 0x0Eu #define MMIPS32_OP_SW 0x3Eu #define MMIPS32_OP_SLTU 0x390u #define MMIPS32_OP_SLL 0x000u #define MMIPS32_OP_SLTI 0x24u #define MMIPS32_OP_SRL 0x040u #define MMIPS32_OP_SYNCI 0x10u #define MMIPS32_OP_XOR 0x310u #define MMIPS32_OP_XORI 0x1Cu #define MMIPS32_ADDI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_ADDI, tar, src, val) #define MMIPS32_ADDIU(tar, src, val) MIPS32_I_INST(MMIPS32_OP_ADDIU, tar, src, val) #define MMIPS32_ADDU(dst, src, tar) MIPS32_R_INST(POOL32A, tar, src, dst, 0, MMIPS32_OP_ADDU) #define MMIPS32_AND(dst, src, tar) MIPS32_R_INST(POOL32A, tar, src, dst, 0, MMIPS32_OP_AND) #define MMIPS32_ANDI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_ANDI, tar, src, val) #define MMIPS32_B(off) MMIPS32_BEQ(0, 0, off) #define MMIPS32_BEQ(src, tar, off) MIPS32_I_INST(MMIPS32_OP_BEQ, tar, src, off) #define MMIPS32_BGTZ(reg, off) MIPS32_I_INST(POOL32I, MMIPS32_OP_BGTZ, reg, off) #define MMIPS32_BNE(src, tar, off) MIPS32_I_INST(MMIPS32_OP_BNE, tar, src, off) #define MMIPS32_CACHE(op, off, base) MIPS32_R_INST(POOL32B, op, base, MMIPS32_OP_CACHE << 1, 0, off) #define MMIPS32_J(tar) MIPS32_J_INST(MMIPS32_OP_J, ((0x07FFFFFFu & ((tar) >> 1)))) #define MMIPS32_JR(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_JALR, POOL32AXF) #define MMIPS32_LB(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LB, reg, base, off) #define MMIPS32_LBU(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LBU, reg, base, off) #define MMIPS32_LHU(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LHU, reg, base, off) #define MMIPS32_LUI(reg, val) MIPS32_I_INST(POOL32I, MMIPS32_OP_LUI, reg, val) #define MMIPS32_LW(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LW, reg, base, off) #define MMIPS32_MFC0(gpr, cpr, sel) MIPS32_R_INST(POOL32A, gpr, cpr, sel, MMIPS32_OP_MFC0, POOL32AXF) #define MMIPS32_MFLO(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_MFLO, POOL32AXF) #define MMIPS32_MFHI(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_MFHI, POOL32AXF) #define MMIPS32_MTC0(gpr, cpr, sel) MIPS32_R_INST(POOL32A, gpr, cpr, sel, MMIPS32_OP_MTC0, POOL32AXF) #define MMIPS32_MTLO(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_MTLO, POOL32AXF) #define MMIPS32_MTHI(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_MTHI, POOL32AXF) #define MMIPS32_MOVN(dst, src, tar) MIPS32_R_INST(POOL32A, tar, src, dst, 0, MMIPS32_OP_MOVN) #define MMIPS32_NOP 0 #define MMIPS32_ORI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_ORI, tar, src, val) #define MMIPS32_RDHWR(tar, dst) MIPS32_R_INST(POOL32A, dst, tar, 0, MMIPS32_OP_RDHWR, POOL32AXF) #define MMIPS32_SB(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SB, reg, base, off) #define MMIPS32_SH(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SH, reg, base, off) #define MMIPS32_SW(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SW, reg, base, off) #define MMIPS32_SRL(reg, src, off) MIPS32_R_INST(POOL32A, reg, src, off, 0, MMIPS32_OP_SRL) #define MMIPS32_SLTU(dst, src, tar) MIPS32_R_INST(POOL32A, tar, src, dst, 0, MMIPS32_OP_SLTU) #define MMIPS32_SYNCI(off, base) MIPS32_I_INST(POOL32I, MMIPS32_OP_SYNCI, base, off) #define MMIPS32_SLL(dst, src, sa) MIPS32_R_INST(POOL32A, dst, src, sa, 0, MMIPS32_OP_SLL) #define MMIPS32_SLTI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_SLTI, tar, src, val) #define MMIPS32_SYNC 0x00001A7Cu /* MIPS32_R_INST(POOL32A, 0, 0, 0, 0x1ADu, POOL32AXF) */ #define MMIPS32_XOR(reg, val1, val2) MIPS32_R_INST(POOL32A, val1, val2, reg, 0, MMIPS32_OP_XOR) #define MMIPS32_XORI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_XORI, tar, src, val) #define MMIPS32_SYNCI_STEP 0x1u /* reg num od address step size to be used with synci instruction */ /* ejtag specific instructions */ #define MMIPS32_DRET 0x0000E37Cu /* MIPS32_R_INST(POOL32A, 0, 0, 0, 0x38D, POOL32AXF) */ #define MMIPS32_SDBBP 0x0000DB7Cu /* MIPS32_R_INST(POOL32A, 0, 0, 0, 0x1BD, POOL32AXF) */ #define MMIPS16_SDBBP 0x46C0u /* POOL16C instr */ /* instruction code with isa selection */ #define MIPS32_NOP 0 /* same for both isa's */ #define MIPS32_ADDI(isa, tar, src, val) (isa ? MMIPS32_ADDI(tar, src, val) : MIPS32_ISA_ADDI(tar, src, val)) #define MIPS32_ADDIU(isa, tar, src, val) (isa ? MMIPS32_ADDIU(tar, src, val) : MIPS32_ISA_ADDIU(tar, src, val)) #define MIPS32_ADDU(isa, dst, src, tar) (isa ? MMIPS32_ADDU(dst, src, tar) : MIPS32_ISA_ADDU(dst, src, tar)) #define MIPS32_AND(isa, dst, src, tar) (isa ? MMIPS32_AND(dst, src, tar) : MIPS32_ISA_AND(dst, src, tar)) #define MIPS32_ANDI(isa, tar, src, val) (isa ? MMIPS32_ANDI(tar, src, val) : MIPS32_ISA_ANDI(tar, src, val)) #define MIPS32_B(isa, off) (isa ? MMIPS32_B(off) : MIPS32_ISA_B(off)) #define MIPS32_BEQ(isa, src, tar, off) (isa ? MMIPS32_BEQ(src, tar, off) : MIPS32_ISA_BEQ(src, tar, off)) #define MIPS32_BGTZ(isa, reg, off) (isa ? MMIPS32_BGTZ(reg, off) : MIPS32_ISA_BGTZ(reg, off)) #define MIPS32_BNE(isa, src, tar, off) (isa ? MMIPS32_BNE(src, tar, off) : MIPS32_ISA_BNE(src, tar, off)) #define MIPS32_CACHE(isa, op, off, base) (isa ? MMIPS32_CACHE(op, off, base) : MIPS32_ISA_CACHE(op, off, base)) #define MIPS32_J(isa, tar) (isa ? MMIPS32_J(tar) : MIPS32_ISA_J(tar)) #define MIPS32_JR(isa, reg) (isa ? MMIPS32_JR(reg) : MIPS32_ISA_JR(reg)) #define MIPS32_LB(isa, reg, off, base) (isa ? MMIPS32_LB(reg, off, base) : MIPS32_ISA_LB(reg, off, base)) #define MIPS32_LBU(isa, reg, off, base) (isa ? MMIPS32_LBU(reg, off, base) : MIPS32_ISA_LBU(reg, off, base)) #define MIPS32_LHU(isa, reg, off, base) (isa ? MMIPS32_LHU(reg, off, base) : MIPS32_ISA_LHU(reg, off, base)) #define MIPS32_LW(isa, reg, off, base) (isa ? MMIPS32_LW(reg, off, base) : MIPS32_ISA_LW(reg, off, base)) #define MIPS32_LUI(isa, reg, val) (isa ? MMIPS32_LUI(reg, val) : MIPS32_ISA_LUI(reg, val)) #define MIPS32_MFC0(isa, gpr, cpr, sel) (isa ? MMIPS32_MFC0(gpr, cpr, sel) : MIPS32_ISA_MFC0(gpr, cpr, sel)) #define MIPS32_MTC0(isa, gpr, cpr, sel) (isa ? MMIPS32_MTC0(gpr, cpr, sel) : MIPS32_ISA_MTC0(gpr, cpr, sel)) #define MIPS32_MFLO(isa, reg) (isa ? MMIPS32_MFLO(reg) : MIPS32_ISA_MFLO(reg)) #define MIPS32_MFHI(isa, reg) (isa ? MMIPS32_MFHI(reg) : MIPS32_ISA_MFHI(reg)) #define MIPS32_MTLO(isa, reg) (isa ? MMIPS32_MTLO(reg) : MIPS32_ISA_MTLO(reg)) #define MIPS32_MTHI(isa, reg) (isa ? MMIPS32_MTHI(reg) : MIPS32_ISA_MTHI(reg)) #define MIPS32_MOVN(isa, dst, src, tar) (isa ? MMIPS32_MOVN(dst, src, tar) : MIPS32_ISA_MOVN(dst, src, tar)) #define MIPS32_ORI(isa, tar, src, val) (isa ? MMIPS32_ORI(tar, src, val) : MIPS32_ISA_ORI(tar, src, val)) #define MIPS32_RDHWR(isa, tar, dst) (isa ? MMIPS32_RDHWR(tar, dst) : MIPS32_ISA_RDHWR(tar, dst)) #define MIPS32_SB(isa, reg, off, base) (isa ? MMIPS32_SB(reg, off, base) : MIPS32_ISA_SB(reg, off, base)) #define MIPS32_SH(isa, reg, off, base) (isa ? MMIPS32_SH(reg, off, base) : MIPS32_ISA_SH(reg, off, base)) #define MIPS32_SW(isa, reg, off, base) (isa ? MMIPS32_SW(reg, off, base) : MIPS32_ISA_SW(reg, off, base)) #define MIPS32_SLL(isa, dst, src, sa) (isa ? MMIPS32_SLL(dst, src, sa) : MIPS32_ISA_SLL(dst, src, sa)) #define MIPS32_SLTI(isa, tar, src, val) (isa ? MMIPS32_SLTI(tar, src, val) : MIPS32_ISA_SLTI(tar, src, val)) #define MIPS32_SLTU(isa, dst, src, tar) (isa ? MMIPS32_SLTU(dst, src, tar) : MIPS32_ISA_SLTU(dst, src, tar)) #define MIPS32_SRL(isa, reg, src, off) (isa ? MMIPS32_SRL(reg, src, off) : MIPS32_ISA_SRL(reg, src, off)) #define MIPS32_SYNCI(isa, off, base) (isa ? MMIPS32_SYNCI(off, base) : MIPS32_ISA_SYNCI(off, base)) #define MIPS32_SYNC(isa) (isa ? MMIPS32_SYNC : MIPS32_ISA_SYNC) #define MIPS32_XOR(isa, reg, val1, val2) (isa ? MMIPS32_XOR(reg, val1, val2) : MIPS32_ISA_XOR(reg, val1, val2)) #define MIPS32_XORI(isa, tar, src, val) (isa ? MMIPS32_XORI(tar, src, val) : MIPS32_ISA_XORI(tar, src, val)) #define MIPS32_SYNCI_STEP 0x1 /* ejtag specific instructions */ #define MIPS32_DRET(isa) (isa ? MMIPS32_DRET : MIPS32_ISA_DRET) #define MIPS32_SDBBP(isa) (isa ? MMIPS32_SDBBP : MIPS32_ISA_SDBBP) #define MIPS16_SDBBP(isa) (isa ? MMIPS16_SDBBP : MIPS16_ISA_SDBBP) extern const struct command_registration mips32_command_handlers[]; int mips32_arch_state(struct target *target); int mips32_init_arch_info(struct target *target, struct mips32_common *mips32, struct jtag_tap *tap); int mips32_restore_context(struct target *target); int mips32_save_context(struct target *target); struct reg_cache *mips32_build_reg_cache(struct target *target); int mips32_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); int mips32_configure_break_unit(struct target *target); int mips32_enable_interrupts(struct target *target, int enable); int mips32_examine(struct target *target); int mips32_read_config_regs(struct target *target); int mips32_register_commands(struct command_context *cmd_ctx); int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); int mips32_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); int mips32_blank_check_memory(struct target *target, struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value); #endif /* OPENOCD_TARGET_MIPS32_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips32_dmaacc.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2008 by John McCarthy * * jgmcc@magma.ca * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "mips32_dmaacc.h" #include <helper/time_support.h> static int mips32_dmaacc_read_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf); static int mips32_dmaacc_read_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf); static int mips32_dmaacc_read_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf); static int mips32_dmaacc_write_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, const uint8_t *buf); static int mips32_dmaacc_write_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, const uint16_t *buf); static int mips32_dmaacc_write_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, const uint32_t *buf); /* * The following logic shamelessly cloned from HairyDairyMaid's wrt54g_debrick * to support the Broadcom BCM5352 SoC in the Linksys WRT54GL wireless router * (and any others that support EJTAG DMA transfers). * Note: This only supports memory read/write. Since the BCM5352 doesn't * appear to support PRACC accesses, all debug functions except halt * do not work. Still, this does allow erasing/writing flash as well as * displaying/modifying memory and memory mapped registers. */ static int ejtag_dma_dstrt_poll(struct mips_ejtag *ejtag_info) { uint32_t ejtag_ctrl; int64_t start = timeval_ms(); do { if (timeval_ms() - start > 1000) { LOG_ERROR("DMA time out"); return -ETIMEDOUT; } ejtag_ctrl = EJTAG_CTRL_DMAACC | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); } while (ejtag_ctrl & EJTAG_CTRL_DSTRT); return 0; } static int ejtag_dma_read(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *data) { uint32_t v; uint32_t ejtag_ctrl; int retries = RETRY_ATTEMPTS; begin_ejtag_dma_read: /* Setup Address */ v = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &v); /* Initiate DMA Read & set DSTRT */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DRWN | EJTAG_CTRL_DMA_WORD | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* Wait for DSTRT to Clear */ ejtag_dma_dstrt_poll(ejtag_info); /* Read Data */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32(ejtag_info, data); /* Clear DMA & Check DERR */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (ejtag_ctrl & EJTAG_CTRL_DERR) { if (retries--) { LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ (retrying)", addr); goto begin_ejtag_dma_read; } else LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ", addr); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int ejtag_dma_read_h(struct mips_ejtag *ejtag_info, uint32_t addr, uint16_t *data) { uint32_t v; uint32_t ejtag_ctrl; int retries = RETRY_ATTEMPTS; begin_ejtag_dma_read_h: /* Setup Address */ v = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &v); /* Initiate DMA Read & set DSTRT */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DRWN | EJTAG_CTRL_DMA_HALFWORD | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* Wait for DSTRT to Clear */ ejtag_dma_dstrt_poll(ejtag_info); /* Read Data */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32(ejtag_info, &v); /* Clear DMA & Check DERR */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (ejtag_ctrl & EJTAG_CTRL_DERR) { if (retries--) { LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ (retrying)", addr); goto begin_ejtag_dma_read_h; } else LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ", addr); return ERROR_JTAG_DEVICE_ERROR; } /* Handle the bigendian/littleendian */ if (addr & 0x2) *data = (v >> 16) & 0xffff; else *data = (v & 0x0000ffff); return ERROR_OK; } static int ejtag_dma_read_b(struct mips_ejtag *ejtag_info, uint32_t addr, uint8_t *data) { uint32_t v; uint32_t ejtag_ctrl; int retries = RETRY_ATTEMPTS; begin_ejtag_dma_read_b: /* Setup Address */ v = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &v); /* Initiate DMA Read & set DSTRT */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DRWN | EJTAG_CTRL_DMA_BYTE | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* Wait for DSTRT to Clear */ ejtag_dma_dstrt_poll(ejtag_info); /* Read Data */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32(ejtag_info, &v); /* Clear DMA & Check DERR */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (ejtag_ctrl & EJTAG_CTRL_DERR) { if (retries--) { LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ (retrying)", addr); goto begin_ejtag_dma_read_b; } else LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ", addr); return ERROR_JTAG_DEVICE_ERROR; } /* Handle the bigendian/littleendian */ switch (addr & 0x3) { case 0: *data = v & 0xff; break; case 1: *data = (v >> 8) & 0xff; break; case 2: *data = (v >> 16) & 0xff; break; case 3: *data = (v >> 24) & 0xff; break; } return ERROR_OK; } static int ejtag_dma_write(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t data) { uint32_t v; uint32_t ejtag_ctrl; int retries = RETRY_ATTEMPTS; begin_ejtag_dma_write: /* Setup Address */ v = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &v); /* Setup Data */ v = data; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32(ejtag_info, &v); /* Initiate DMA Write & set DSTRT */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DMA_WORD | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* Wait for DSTRT to Clear */ ejtag_dma_dstrt_poll(ejtag_info); /* Clear DMA & Check DERR */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (ejtag_ctrl & EJTAG_CTRL_DERR) { if (retries--) { LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE (retrying)", addr); goto begin_ejtag_dma_write; } else LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE", addr); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int ejtag_dma_write_h(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t data) { uint32_t v; uint32_t ejtag_ctrl; int retries = RETRY_ATTEMPTS; /* Handle the bigendian/littleendian */ data &= 0xffff; data |= data << 16; begin_ejtag_dma_write_h: /* Setup Address */ v = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &v); /* Setup Data */ v = data; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32(ejtag_info, &v); /* Initiate DMA Write & set DSTRT */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DMA_HALFWORD | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* Wait for DSTRT to Clear */ ejtag_dma_dstrt_poll(ejtag_info); /* Clear DMA & Check DERR */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (ejtag_ctrl & EJTAG_CTRL_DERR) { if (retries--) { LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE (retrying)", addr); goto begin_ejtag_dma_write_h; } else LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE", addr); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int ejtag_dma_write_b(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t data) { uint32_t v; uint32_t ejtag_ctrl; int retries = RETRY_ATTEMPTS; /* Handle the bigendian/littleendian */ data &= 0xff; data |= data << 8; data |= data << 16; begin_ejtag_dma_write_b: /* Setup Address*/ v = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &v); /* Setup Data */ v = data; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32(ejtag_info, &v); /* Initiate DMA Write & set DSTRT */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DMA_BYTE | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* Wait for DSTRT to Clear */ ejtag_dma_dstrt_poll(ejtag_info); /* Clear DMA & Check DERR */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (ejtag_ctrl & EJTAG_CTRL_DERR) { if (retries--) { LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE (retrying)", addr); goto begin_ejtag_dma_write_b; } else LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE", addr); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } int mips32_dmaacc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf) { switch (size) { case 1: return mips32_dmaacc_read_mem8(ejtag_info, addr, count, (uint8_t *)buf); case 2: return mips32_dmaacc_read_mem16(ejtag_info, addr, count, (uint16_t *)buf); case 4: return mips32_dmaacc_read_mem32(ejtag_info, addr, count, (uint32_t *)buf); } return ERROR_OK; } static int mips32_dmaacc_read_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf) { int i; int retval; for (i = 0; i < count; i++) { retval = ejtag_dma_read(ejtag_info, addr + i * sizeof(*buf), &buf[i]); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int mips32_dmaacc_read_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf) { int i; int retval; for (i = 0; i < count; i++) { retval = ejtag_dma_read_h(ejtag_info, addr + i * sizeof(*buf), &buf[i]); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int mips32_dmaacc_read_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf) { int i; int retval; for (i = 0; i < count; i++) { retval = ejtag_dma_read_b(ejtag_info, addr + i * sizeof(*buf), &buf[i]); if (retval != ERROR_OK) return retval; } return ERROR_OK; } int mips32_dmaacc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, const void *buf) { switch (size) { case 1: return mips32_dmaacc_write_mem8(ejtag_info, addr, count, buf); case 2: return mips32_dmaacc_write_mem16(ejtag_info, addr, count, buf); case 4: return mips32_dmaacc_write_mem32(ejtag_info, addr, count, buf); } return ERROR_OK; } static int mips32_dmaacc_write_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, const uint32_t *buf) { int i; int retval; for (i = 0; i < count; i++) { retval = ejtag_dma_write(ejtag_info, addr + i * sizeof(*buf), buf[i]); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int mips32_dmaacc_write_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, const uint16_t *buf) { int i; int retval; for (i = 0; i < count; i++) { retval = ejtag_dma_write_h(ejtag_info, addr + i * sizeof(*buf), buf[i]); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int mips32_dmaacc_write_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, const uint8_t *buf) { int i; int retval; for (i = 0; i < count; i++) { retval = ejtag_dma_write_b(ejtag_info, addr + i * sizeof(*buf), buf[i]); if (retval != ERROR_OK) return retval; } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips32_dmaacc.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2008 by John McCarthy * * jgmcc@magma.ca * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * ***************************************************************************/ #ifndef OPENOCD_TARGET_MIPS32_DMAACC_H #define OPENOCD_TARGET_MIPS32_DMAACC_H #include "mips_ejtag.h" #define EJTAG_CTRL_DMA_BYTE 0x00000000 #define EJTAG_CTRL_DMA_HALFWORD 0x00000080 #define EJTAG_CTRL_DMA_WORD 0x00000100 #define EJTAG_CTRL_DMA_TRIPLEBYTE 0x00000180 #define RETRY_ATTEMPTS 0 int mips32_dmaacc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf); int mips32_dmaacc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, const void *buf); #endif /* OPENOCD_TARGET_MIPS32_DMAACC_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips32_pracc.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2009 by David N. Claffey <dnclaffey@gmail.com> * * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * ***************************************************************************/ /* * This version has optimized assembly routines for 32 bit operations: * - read word * - write word * - write array of words * * One thing to be aware of is that the MIPS32 cpu will execute the * instruction after a branch instruction (one delay slot). * * For example: * LW $2, ($5 +10) * B foo * LW $1, ($2 +100) * * The LW $1, ($2 +100) instruction is also executed. If this is * not wanted a NOP can be inserted: * * LW $2, ($5 +10) * B foo * NOP * LW $1, ($2 +100) * * or the code can be changed to: * * B foo * LW $2, ($5 +10) * LW $1, ($2 +100) * * The original code contained NOPs. I have removed these and moved * the branches. * * These changes result in a 35% speed increase when programming an * external flash. * * More improvement could be gained if the registers do no need * to be preserved but in that case the routines should be aware * OpenOCD is used as a flash programmer or as a debug tool. * * Nico Coesel */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/align.h> #include <helper/time_support.h> #include <jtag/adapter.h> #include "mips32.h" #include "mips32_pracc.h" static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info) { int64_t then = timeval_ms(); /* wait for the PrAcc to become "1" */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); while (1) { ejtag_info->pa_ctrl = ejtag_info->ejtag_ctrl; int retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_info->pa_ctrl); if (retval != ERROR_OK) return retval; if (ejtag_info->pa_ctrl & EJTAG_CTRL_PRACC) break; int64_t timeout = timeval_ms() - then; if (timeout > 1000) { LOG_DEBUG("DEBUGMODULE: No memory access in progress!"); return ERROR_JTAG_DEVICE_ERROR; } } return ERROR_OK; } /* Shift in control and address for a new processor access, save them in ejtag_info */ static int mips32_pracc_read_ctrl_addr(struct mips_ejtag *ejtag_info) { int retval = wait_for_pracc_rw(ejtag_info); if (retval != ERROR_OK) return retval; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); ejtag_info->pa_addr = 0; return mips_ejtag_drscan_32(ejtag_info, &ejtag_info->pa_addr); } /* Finish processor access */ static void mips32_pracc_finish(struct mips_ejtag *ejtag_info) { uint32_t ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); mips_ejtag_drscan_32_out(ejtag_info, ctrl); } static int mips32_pracc_clean_text_jump(struct mips_ejtag *ejtag_info) { uint32_t jt_code = MIPS32_J(ejtag_info->isa, MIPS32_PRACC_TEXT); pracc_swap16_array(ejtag_info, &jt_code, 1); /* do 3 0/nops to clean pipeline before a jump to pracc text, NOP in delay slot */ for (int i = 0; i != 5; i++) { /* Wait for pracc */ int retval = wait_for_pracc_rw(ejtag_info); if (retval != ERROR_OK) return retval; /* Data or instruction out */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); uint32_t data = (i == 3) ? jt_code : MIPS32_NOP; mips_ejtag_drscan_32_out(ejtag_info, data); /* finish pa */ mips32_pracc_finish(ejtag_info); } if (ejtag_info->mode != 0) /* async mode support only for MIPS ... */ return ERROR_OK; for (int i = 0; i != 2; i++) { int retval = mips32_pracc_read_ctrl_addr(ejtag_info); if (retval != ERROR_OK) return retval; if (ejtag_info->pa_addr != MIPS32_PRACC_TEXT) { /* LEXRA/BMIPS ?, shift out another NOP, max 2 */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32_out(ejtag_info, MIPS32_NOP); mips32_pracc_finish(ejtag_info); } else break; } return ERROR_OK; } static int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, uint32_t *param_out, bool check_last) { int code_count = 0; int store_pending = 0; /* increases with every store instr at dmseg, decreases with every store pa */ uint32_t max_store_addr = 0; /* for store pa address testing */ bool restart = 0; /* restarting control */ int restart_count = 0; uint32_t instr = 0; bool final_check = 0; /* set to 1 if in final checks after function code shifted out */ bool pass = 0; /* to check the pass through pracc text after function code sent */ int retval; while (1) { if (restart) { if (restart_count < 3) { /* max 3 restarts allowed */ retval = mips32_pracc_clean_text_jump(ejtag_info); if (retval != ERROR_OK) return retval; } else return ERROR_JTAG_DEVICE_ERROR; restart_count++; restart = 0; code_count = 0; LOG_DEBUG("restarting code"); } retval = mips32_pracc_read_ctrl_addr(ejtag_info); /* update current pa info: control and address */ if (retval != ERROR_OK) return retval; /* Check for read or write access */ if (ejtag_info->pa_ctrl & EJTAG_CTRL_PRNW) { /* write/store access */ /* Check for pending store from a previous store instruction at dmseg */ if (store_pending == 0) { LOG_DEBUG("unexpected write at address %" PRIx32, ejtag_info->pa_addr); if (code_count < 2) { /* allow for restart */ restart = 1; continue; } else return ERROR_JTAG_DEVICE_ERROR; } else { /* check address */ if (ejtag_info->pa_addr < MIPS32_PRACC_PARAM_OUT || ejtag_info->pa_addr > max_store_addr) { LOG_DEBUG("writing at unexpected address %" PRIx32, ejtag_info->pa_addr); return ERROR_JTAG_DEVICE_ERROR; } } /* read data */ uint32_t data = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); retval = mips_ejtag_drscan_32(ejtag_info, &data); if (retval != ERROR_OK) return retval; /* store data at param out, address based offset */ param_out[(ejtag_info->pa_addr - MIPS32_PRACC_PARAM_OUT) / 4] = data; store_pending--; } else { /* read/fetch access */ if (!final_check) { /* executing function code */ /* check address */ if (ejtag_info->pa_addr != (MIPS32_PRACC_TEXT + code_count * 4)) { LOG_DEBUG("reading at unexpected address %" PRIx32 ", expected %x", ejtag_info->pa_addr, MIPS32_PRACC_TEXT + code_count * 4); /* restart code execution only in some cases */ if (code_count == 1 && ejtag_info->pa_addr == MIPS32_PRACC_TEXT && restart_count == 0) { LOG_DEBUG("restarting, without clean jump"); restart_count++; code_count = 0; continue; } else if (code_count < 2) { restart = 1; continue; } return ERROR_JTAG_DEVICE_ERROR; } /* check for store instruction at dmseg */ uint32_t store_addr = ctx->pracc_list[code_count].addr; if (store_addr != 0) { if (store_addr > max_store_addr) max_store_addr = store_addr; store_pending++; } instr = ctx->pracc_list[code_count++].instr; if (code_count == ctx->code_count) /* last instruction, start final check */ final_check = 1; } else { /* final check after function code shifted out */ /* check address */ if (ejtag_info->pa_addr == MIPS32_PRACC_TEXT) { if (!pass) { /* first pass through pracc text */ if (store_pending == 0) /* done, normal exit */ return ERROR_OK; pass = 1; /* pracc text passed */ code_count = 0; /* restart code count */ } else { LOG_DEBUG("unexpected second pass through pracc text"); return ERROR_JTAG_DEVICE_ERROR; } } else { if (ejtag_info->pa_addr != (MIPS32_PRACC_TEXT + code_count * 4)) { LOG_DEBUG("unexpected read address in final check: %" PRIx32 ", expected: %x", ejtag_info->pa_addr, MIPS32_PRACC_TEXT + code_count * 4); return ERROR_JTAG_DEVICE_ERROR; } } if (!pass) { if ((code_count - ctx->code_count) > 1) { /* allow max 2 instr delay slot */ LOG_DEBUG("failed to jump back to pracc text"); return ERROR_JTAG_DEVICE_ERROR; } } else if (code_count > 10) { /* enough, abandon */ LOG_DEBUG("execution abandoned, store pending: %d", store_pending); return ERROR_JTAG_DEVICE_ERROR; } instr = MIPS32_NOP; /* shift out NOPs instructions */ code_count++; } /* Send instruction out */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32_out(ejtag_info, instr); } /* finish processor access, let the processor eat! */ mips32_pracc_finish(ejtag_info); if (final_check && !check_last) /* last instr, don't check, execute and exit */ return jtag_execute_queue(); if (store_pending == 0 && pass) { /* store access done, but after passing pracc text */ LOG_DEBUG("warning: store access pass pracc text"); return ERROR_OK; } } } inline void pracc_queue_init(struct pracc_queue_info *ctx) { ctx->retval = ERROR_OK; ctx->code_count = 0; ctx->store_count = 0; ctx->max_code = 0; ctx->pracc_list = NULL; ctx->isa = ctx->ejtag_info->isa ? 1 : 0; } void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr) { if (ctx->retval != ERROR_OK) /* On previous out of memory, return */ return; if (ctx->code_count == ctx->max_code) { void *p = realloc(ctx->pracc_list, sizeof(struct pa_list) * (ctx->max_code + PRACC_BLOCK)); if (p) { ctx->max_code += PRACC_BLOCK; ctx->pracc_list = p; } else { ctx->retval = ERROR_FAIL; /* Out of memory */ return; } } ctx->pracc_list[ctx->code_count].instr = instr; ctx->pracc_list[ctx->code_count++].addr = addr; if (addr) ctx->store_count++; } static void pracc_add_li32(struct pracc_queue_info *ctx, uint32_t reg_num, uint32_t data, bool optimize) { if (LOWER16(data) == 0 && optimize) pracc_add(ctx, 0, MIPS32_LUI(ctx->isa, reg_num, UPPER16(data))); /* load only upper value */ else if (UPPER16(data) == 0 && optimize) pracc_add(ctx, 0, MIPS32_ORI(ctx->isa, reg_num, 0, LOWER16(data))); /* load only lower */ else { pracc_add(ctx, 0, MIPS32_LUI(ctx->isa, reg_num, UPPER16(data))); /* load upper and lower */ pracc_add(ctx, 0, MIPS32_ORI(ctx->isa, reg_num, reg_num, LOWER16(data))); } } inline void pracc_queue_free(struct pracc_queue_info *ctx) { free(ctx->pracc_list); } int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, uint32_t *buf, bool check_last) { if (ctx->retval != ERROR_OK) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } if (ejtag_info->isa && ejtag_info->endianness) for (int i = 0; i != ctx->code_count; i++) ctx->pracc_list[i].instr = SWAP16(ctx->pracc_list[i].instr); if (ejtag_info->mode == 0) return mips32_pracc_exec(ejtag_info, ctx, buf, check_last); union scan_in { uint8_t scan_96[12]; struct { uint8_t ctrl[4]; uint8_t data[4]; uint8_t addr[4]; } scan_32; } *scan_in = malloc(sizeof(union scan_in) * (ctx->code_count + ctx->store_count)); if (!scan_in) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } unsigned num_clocks = ((uint64_t)(ejtag_info->scan_delay) * adapter_get_speed_khz() + 500000) / 1000000; uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ALL); int scan_count = 0; for (int i = 0; i != ctx->code_count; i++) { jtag_add_clocks(num_clocks); mips_ejtag_add_scan_96(ejtag_info, ejtag_ctrl, ctx->pracc_list[i].instr, scan_in[scan_count++].scan_96); /* Check store address from previous instruction, if not the first */ if (i > 0 && ctx->pracc_list[i - 1].addr) { jtag_add_clocks(num_clocks); mips_ejtag_add_scan_96(ejtag_info, ejtag_ctrl, 0, scan_in[scan_count++].scan_96); } } int retval = jtag_execute_queue(); /* execute queued scans */ if (retval != ERROR_OK) goto exit; uint32_t fetch_addr = MIPS32_PRACC_TEXT; /* start address */ scan_count = 0; for (int i = 0; i != ctx->code_count; i++) { /* verify every pracc access */ /* check pracc bit */ ejtag_ctrl = buf_get_u32(scan_in[scan_count].scan_32.ctrl, 0, 32); uint32_t addr = buf_get_u32(scan_in[scan_count].scan_32.addr, 0, 32); if (!(ejtag_ctrl & EJTAG_CTRL_PRACC)) { LOG_ERROR("Error: access not pending count: %d", scan_count); retval = ERROR_FAIL; goto exit; } if (ejtag_ctrl & EJTAG_CTRL_PRNW) { LOG_ERROR("Not a fetch/read access, count: %d", scan_count); retval = ERROR_FAIL; goto exit; } if (addr != fetch_addr) { LOG_ERROR("Fetch addr mismatch, read: %" PRIx32 " expected: %" PRIx32 " count: %d", addr, fetch_addr, scan_count); retval = ERROR_FAIL; goto exit; } fetch_addr += 4; scan_count++; /* check if previous instruction is a store instruction at dmesg */ if (i > 0 && ctx->pracc_list[i - 1].addr) { uint32_t store_addr = ctx->pracc_list[i - 1].addr; ejtag_ctrl = buf_get_u32(scan_in[scan_count].scan_32.ctrl, 0, 32); addr = buf_get_u32(scan_in[scan_count].scan_32.addr, 0, 32); if (!(ejtag_ctrl & EJTAG_CTRL_PRNW)) { LOG_ERROR("Not a store/write access, count: %d", scan_count); retval = ERROR_FAIL; goto exit; } if (addr != store_addr) { LOG_ERROR("Store address mismatch, read: %" PRIx32 " expected: %" PRIx32 " count: %d", addr, store_addr, scan_count); retval = ERROR_FAIL; goto exit; } int buf_index = (addr - MIPS32_PRACC_PARAM_OUT) / 4; buf[buf_index] = buf_get_u32(scan_in[scan_count].scan_32.data, 0, 32); scan_count++; } } exit: free(scan_in); return retval; } static int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf) { struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 8, UPPER16((addr + 0x8000)))); /* load $8 with modified upper addr */ pracc_add(&ctx, 0, MIPS32_LW(ctx.isa, 8, LOWER16(addr), 8)); /* lw $8, LOWER16(addr)($8) */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* sw $8,PRACC_OUT_OFFSET($15) */ pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */ pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* move COP0 DeSave to $15 */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, buf, 1); pracc_queue_free(&ctx); return ctx.retval; } int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf) { if (count == 1 && size == 4) return mips32_pracc_read_u32(ejtag_info, addr, (uint32_t *)buf); struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); uint32_t *data = NULL; if (size != 4) { data = malloc(256 * sizeof(uint32_t)); if (!data) { LOG_ERROR("Out of memory"); goto exit; } } uint32_t *buf32 = buf; uint16_t *buf16 = buf; uint8_t *buf8 = buf; while (count) { ctx.code_count = 0; ctx.store_count = 0; int this_round_count = (count > 256) ? 256 : count; uint32_t last_upper_base_addr = UPPER16((addr + 0x8000)); pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 9, last_upper_base_addr)); /* upper memory addr to $9 */ for (int i = 0; i != this_round_count; i++) { /* Main code loop */ uint32_t upper_base_addr = UPPER16((addr + 0x8000)); if (last_upper_base_addr != upper_base_addr) { /* if needed, change upper addr in $9 */ pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 9, upper_base_addr)); last_upper_base_addr = upper_base_addr; } if (size == 4) /* load from memory to $8 */ pracc_add(&ctx, 0, MIPS32_LW(ctx.isa, 8, LOWER16(addr), 9)); else if (size == 2) pracc_add(&ctx, 0, MIPS32_LHU(ctx.isa, 8, LOWER16(addr), 9)); else pracc_add(&ctx, 0, MIPS32_LBU(ctx.isa, 8, LOWER16(addr), 9)); pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + i * 4, /* store $8 at param out */ MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + i * 4, 15)); addr += size; } pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */ pracc_add_li32(&ctx, 9, ejtag_info->reg9, 0); /* restore $9 */ pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */ if (size == 4) { ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, buf32, 1); if (ctx.retval != ERROR_OK) goto exit; buf32 += this_round_count; } else { ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, data, 1); if (ctx.retval != ERROR_OK) goto exit; uint32_t *data_p = data; for (int i = 0; i != this_round_count; i++) { if (size == 2) *buf16++ = *data_p++; else *buf8++ = *data_p++; } } count -= this_round_count; } exit: pracc_queue_free(&ctx); free(data); return ctx.retval; } int mips32_cp0_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp0_reg, uint32_t cp0_sel) { struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 8, cp0_reg, cp0_sel)); /* move cp0 reg / sel to $8 */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */ pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */ pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */ pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, val, 1); pracc_queue_free(&ctx); return ctx.retval; } int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel) { struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); pracc_add_li32(&ctx, 15, val, 0); /* Load val to $15 */ pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, cp0_reg, cp0_sel)); /* write $15 to cp0 reg / sel */ pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); pracc_queue_free(&ctx); return ctx.retval; } /** * \b mips32_pracc_sync_cache * * Synchronize Caches to Make Instruction Writes Effective * (ref. doc. MIPS32 Architecture For Programmers Volume II: The MIPS32 Instruction Set, * Document Number: MD00086, Revision 2.00, June 9, 2003) * * When the instruction stream is written, the SYNCI instruction should be used * in conjunction with other instructions to make the newly-written instructions effective. * * Explanation : * A program that loads another program into memory is actually writing the D- side cache. * The instructions it has loaded can't be executed until they reach the I-cache. * * After the instructions have been written, the loader should arrange * to write back any containing D-cache line and invalidate any locations * already in the I-cache. * * If the cache coherency attribute (CCA) is set to zero, it's a write through cache, there is no need * to write back. * * In the latest MIPS32/64 CPUs, MIPS provides the synci instruction, * which does the whole job for a cache-line-sized chunk of the memory you just loaded: * That is, it arranges a D-cache write-back (if CCA = 3) and an I-cache invalidate. * * The line size is obtained with the rdhwr SYNCI_Step in release 2 or from cp0 config 1 register in release 1. */ static int mips32_pracc_synchronize_cache(struct mips_ejtag *ejtag_info, uint32_t start_addr, uint32_t end_addr, int cached, int rel) { struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); /** Find cache line size in bytes */ uint32_t clsiz; if (rel) { /* Release 2 (rel = 1) */ pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ pracc_add(&ctx, 0, MIPS32_RDHWR(ctx.isa, 8, MIPS32_SYNCI_STEP)); /* load synci_step value to $8 */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */ pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */ pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, &clsiz, 1); if (ctx.retval != ERROR_OK) goto exit; } else { /* Release 1 (rel = 0) */ uint32_t conf; ctx.retval = mips32_cp0_read(ejtag_info, &conf, 16, 1); if (ctx.retval != ERROR_OK) goto exit; uint32_t dl = (conf & MIPS32_CONFIG1_DL_MASK) >> MIPS32_CONFIG1_DL_SHIFT; /* dl encoding : dl=1 => 4 bytes, dl=2 => 8 bytes, etc... max dl=6 => 128 bytes cache line size */ clsiz = 0x2 << dl; if (dl == 0) clsiz = 0; } if (clsiz == 0) goto exit; /* Nothing to do */ /* make sure clsiz is power of 2 */ if (!IS_PWR_OF_2(clsiz)) { LOG_DEBUG("clsiz must be power of 2"); ctx.retval = ERROR_FAIL; goto exit; } /* make sure start_addr and end_addr have the same offset inside de cache line */ start_addr |= clsiz - 1; end_addr |= clsiz - 1; ctx.code_count = 0; ctx.store_count = 0; int count = 0; uint32_t last_upper_base_addr = UPPER16((start_addr + 0x8000)); pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, last_upper_base_addr)); /* load upper memory base addr to $15 */ while (start_addr <= end_addr) { /* main loop */ uint32_t upper_base_addr = UPPER16((start_addr + 0x8000)); if (last_upper_base_addr != upper_base_addr) { /* if needed, change upper addr in $15 */ pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, upper_base_addr)); last_upper_base_addr = upper_base_addr; } if (rel) /* synci instruction, offset($15) */ pracc_add(&ctx, 0, MIPS32_SYNCI(ctx.isa, LOWER16(start_addr), 15)); else { if (cached == 3) /* cache Hit_Writeback_D, offset($15) */ pracc_add(&ctx, 0, MIPS32_CACHE(ctx.isa, MIPS32_CACHE_D_HIT_WRITEBACK, LOWER16(start_addr), 15)); /* cache Hit_Invalidate_I, offset($15) */ pracc_add(&ctx, 0, MIPS32_CACHE(ctx.isa, MIPS32_CACHE_I_HIT_INVALIDATE, LOWER16(start_addr), 15)); } start_addr += clsiz; count++; if (count == 256 && start_addr <= end_addr) { /* more ?, then execute code list */ pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* to start */ pracc_add(&ctx, 0, MIPS32_NOP); /* nop in delay slot */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); if (ctx.retval != ERROR_OK) goto exit; ctx.code_count = 0; /* reset counters for another loop */ ctx.store_count = 0; count = 0; } } pracc_add(&ctx, 0, MIPS32_SYNC(ctx.isa)); pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave*/ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); exit: pracc_queue_free(&ctx); return ctx.retval; } static int mips32_pracc_write_mem_generic(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, const void *buf) { struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); const uint32_t *buf32 = buf; const uint16_t *buf16 = buf; const uint8_t *buf8 = buf; while (count) { ctx.code_count = 0; ctx.store_count = 0; int this_round_count = (count > 128) ? 128 : count; uint32_t last_upper_base_addr = UPPER16((addr + 0x8000)); /* load $15 with memory base address */ pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, last_upper_base_addr)); for (int i = 0; i != this_round_count; i++) { uint32_t upper_base_addr = UPPER16((addr + 0x8000)); if (last_upper_base_addr != upper_base_addr) { /* if needed, change upper address in $15*/ pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, upper_base_addr)); last_upper_base_addr = upper_base_addr; } if (size == 4) { pracc_add_li32(&ctx, 8, *buf32, 1); /* load with li32, optimize */ pracc_add(&ctx, 0, MIPS32_SW(ctx.isa, 8, LOWER16(addr), 15)); /* store word to mem */ buf32++; } else if (size == 2) { pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 8, 0, *buf16)); /* load lower value */ pracc_add(&ctx, 0, MIPS32_SH(ctx.isa, 8, LOWER16(addr), 15)); /* store half word */ buf16++; } else { pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 8, 0, *buf8)); /* load lower value */ pracc_add(&ctx, 0, MIPS32_SB(ctx.isa, 8, LOWER16(addr), 15)); /* store byte */ buf8++; } addr += size; } pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */ pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); if (ctx.retval != ERROR_OK) goto exit; count -= this_round_count; } exit: pracc_queue_free(&ctx); return ctx.retval; } int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, const void *buf) { int retval = mips32_pracc_write_mem_generic(ejtag_info, addr, size, count, buf); if (retval != ERROR_OK) return retval; /** * If we are in the cacheable region and cache is activated, * we must clean D$ (if Cache Coherency Attribute is set to 3) + invalidate I$ after we did the write, * so that changes do not continue to live only in D$ (if CCA = 3), but to be * replicated in I$ also (maybe we wrote the instructions) */ uint32_t conf = 0; int cached = 0; if ((KSEGX(addr) == KSEG1) || ((addr >= 0xff200000) && (addr <= 0xff3fffff))) return retval; /*Nothing to do*/ mips32_cp0_read(ejtag_info, &conf, 16, 0); switch (KSEGX(addr)) { case KUSEG: cached = (conf & MIPS32_CONFIG0_KU_MASK) >> MIPS32_CONFIG0_KU_SHIFT; break; case KSEG0: cached = (conf & MIPS32_CONFIG0_K0_MASK) >> MIPS32_CONFIG0_K0_SHIFT; break; case KSEG2: case KSEG3: cached = (conf & MIPS32_CONFIG0_K23_MASK) >> MIPS32_CONFIG0_K23_SHIFT; break; default: /* what ? */ break; } /** * Check cacheability bits coherency algorithm * is the region cacheable or uncached. * If cacheable we have to synchronize the cache */ if (cached == 3 || cached == 0) { /* Write back cache or write through cache */ uint32_t start_addr = addr; uint32_t end_addr = addr + count * size; uint32_t rel = (conf & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT; if (rel > 1) { LOG_DEBUG("Unknown release in cache code"); return ERROR_FAIL; } retval = mips32_pracc_synchronize_cache(ejtag_info, start_addr, end_addr, cached, rel); } return retval; } int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) { struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); uint32_t cp0_write_code[] = { MIPS32_MTC0(ctx.isa, 1, 12, 0), /* move $1 to status */ MIPS32_MTLO(ctx.isa, 1), /* move $1 to lo */ MIPS32_MTHI(ctx.isa, 1), /* move $1 to hi */ MIPS32_MTC0(ctx.isa, 1, 8, 0), /* move $1 to badvaddr */ MIPS32_MTC0(ctx.isa, 1, 13, 0), /* move $1 to cause*/ MIPS32_MTC0(ctx.isa, 1, 24, 0), /* move $1 to depc (pc) */ }; /* load registers 2 to 31 with li32, optimize */ for (int i = 2; i < 32; i++) pracc_add_li32(&ctx, i, regs[i], 1); for (int i = 0; i != 6; i++) { pracc_add_li32(&ctx, 1, regs[i + 32], 0); /* load CPO value in $1 */ pracc_add(&ctx, 0, cp0_write_code[i]); /* write value from $1 to CPO register */ } pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); /* load $15 in DeSave */ pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 1, UPPER16((regs[1])))); /* load upper half word in $1 */ pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 1, 1, LOWER16((regs[1])))); /* load lower half word in $1 */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); ejtag_info->reg8 = regs[8]; ejtag_info->reg9 = regs[9]; pracc_queue_free(&ctx); return ctx.retval; } int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) { struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); uint32_t cp0_read_code[] = { MIPS32_MFC0(ctx.isa, 8, 12, 0), /* move status to $8 */ MIPS32_MFLO(ctx.isa, 8), /* move lo to $8 */ MIPS32_MFHI(ctx.isa, 8), /* move hi to $8 */ MIPS32_MFC0(ctx.isa, 8, 8, 0), /* move badvaddr to $8 */ MIPS32_MFC0(ctx.isa, 8, 13, 0), /* move cause to $8 */ MIPS32_MFC0(ctx.isa, 8, 24, 0), /* move depc (pc) to $8 */ }; pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 1, 31, 0)); /* move $1 to COP0 DeSave */ pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 1, PRACC_UPPER_BASE_ADDR)); /* $1 = MIP32_PRACC_BASE_ADDR */ for (int i = 2; i != 32; i++) /* store GPR's 2 to 31 */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i * 4), MIPS32_SW(ctx.isa, i, PRACC_OUT_OFFSET + (i * 4), 1)); for (int i = 0; i != 6; i++) { pracc_add(&ctx, 0, cp0_read_code[i]); /* load COP0 needed registers to $8 */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i + 32) * 4, /* store $8 at PARAM OUT */ MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + (i + 32) * 4, 1)); } pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 8, 31, 0)); /* move DeSave to $8, reg1 value */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + 4, /* store reg1 value from $8 to param out */ MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + 4, 1)); pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 1, 31, 0)); /* move COP0 DeSave to $1, restore reg1 */ pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); /* load $15 in DeSave */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, regs, 1); ejtag_info->reg8 = regs[8]; /* reg8 is saved but not restored, next called function should restore it */ ejtag_info->reg9 = regs[9]; pracc_queue_free(&ctx); return ctx.retval; } /* fastdata upload/download requires an initialized working area * to load the download code; it should not be called otherwise * fetch order from the fastdata area * 1. start addr * 2. end addr * 3. data ... */ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source, int write_t, uint32_t addr, int count, uint32_t *buf) { uint32_t isa = ejtag_info->isa ? 1 : 0; uint32_t handler_code[] = { /* r15 points to the start of this code */ MIPS32_SW(isa, 8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15), MIPS32_SW(isa, 9, MIPS32_FASTDATA_HANDLER_SIZE - 8, 15), MIPS32_SW(isa, 10, MIPS32_FASTDATA_HANDLER_SIZE - 12, 15), MIPS32_SW(isa, 11, MIPS32_FASTDATA_HANDLER_SIZE - 16, 15), /* start of fastdata area in t0 */ MIPS32_LUI(isa, 8, UPPER16(MIPS32_PRACC_FASTDATA_AREA)), MIPS32_ORI(isa, 8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA)), MIPS32_LW(isa, 9, 0, 8), /* start addr in t1 */ MIPS32_LW(isa, 10, 0, 8), /* end addr to t2 */ /* loop: */ write_t ? MIPS32_LW(isa, 11, 0, 8) : MIPS32_LW(isa, 11, 0, 9), /* from xfer area : from memory */ write_t ? MIPS32_SW(isa, 11, 0, 9) : MIPS32_SW(isa, 11, 0, 8), /* to memory : to xfer area */ MIPS32_BNE(isa, 10, 9, NEG16(3 << isa)), /* bne $t2,t1,loop */ MIPS32_ADDI(isa, 9, 9, 4), /* addi t1,t1,4 */ MIPS32_LW(isa, 8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15), MIPS32_LW(isa, 9, MIPS32_FASTDATA_HANDLER_SIZE - 8, 15), MIPS32_LW(isa, 10, MIPS32_FASTDATA_HANDLER_SIZE - 12, 15), MIPS32_LW(isa, 11, MIPS32_FASTDATA_HANDLER_SIZE - 16, 15), MIPS32_LUI(isa, 15, UPPER16(MIPS32_PRACC_TEXT)), MIPS32_ORI(isa, 15, 15, LOWER16(MIPS32_PRACC_TEXT) | isa), /* isa bit for JR instr */ MIPS32_JR(isa, 15), /* jr start */ MIPS32_MFC0(isa, 15, 31, 0), /* move COP0 DeSave to $15 */ }; if (source->size < MIPS32_FASTDATA_HANDLER_SIZE) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; pracc_swap16_array(ejtag_info, handler_code, ARRAY_SIZE(handler_code)); /* write program into RAM */ if (write_t != ejtag_info->fast_access_save) { mips32_pracc_write_mem(ejtag_info, source->address, 4, ARRAY_SIZE(handler_code), handler_code); /* save previous operation to speed to any consecutive read/writes */ ejtag_info->fast_access_save = write_t; } LOG_DEBUG("%s using 0x%.8" TARGET_PRIxADDR " for write handler", __func__, source->address); uint32_t jmp_code[] = { MIPS32_LUI(isa, 15, UPPER16(source->address)), /* load addr of jump in $15 */ MIPS32_ORI(isa, 15, 15, LOWER16(source->address) | isa), /* isa bit for JR instr */ MIPS32_JR(isa, 15), /* jump to ram program */ isa ? MIPS32_XORI(isa, 15, 15, 1) : MIPS32_NOP, /* drop isa bit, needed for LW/SW instructions */ }; pracc_swap16_array(ejtag_info, jmp_code, ARRAY_SIZE(jmp_code)); /* execute jump code, with no address check */ for (unsigned i = 0; i < ARRAY_SIZE(jmp_code); i++) { int retval = wait_for_pracc_rw(ejtag_info); if (retval != ERROR_OK) return retval; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32_out(ejtag_info, jmp_code[i]); /* Clear the access pending bit (let the processor eat!) */ mips32_pracc_finish(ejtag_info); } /* wait PrAcc pending bit for FASTDATA write, read address */ int retval = mips32_pracc_read_ctrl_addr(ejtag_info); if (retval != ERROR_OK) return retval; /* next fetch to dmseg should be in FASTDATA_AREA, check */ if (ejtag_info->pa_addr != MIPS32_PRACC_FASTDATA_AREA) return ERROR_FAIL; /* Send the load start address */ uint32_t val = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); mips_ejtag_fastdata_scan(ejtag_info, 1, &val); retval = wait_for_pracc_rw(ejtag_info); if (retval != ERROR_OK) return retval; /* Send the load end address */ val = addr + (count - 1) * 4; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); mips_ejtag_fastdata_scan(ejtag_info, 1, &val); unsigned num_clocks = 0; /* like in legacy code */ if (ejtag_info->mode != 0) num_clocks = ((uint64_t)(ejtag_info->scan_delay) * adapter_get_speed_khz() + 500000) / 1000000; for (int i = 0; i < count; i++) { jtag_add_clocks(num_clocks); mips_ejtag_fastdata_scan(ejtag_info, write_t, buf++); } retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("fastdata load failed"); return retval; } retval = mips32_pracc_read_ctrl_addr(ejtag_info); if (retval != ERROR_OK) return retval; if (ejtag_info->pa_addr != MIPS32_PRACC_TEXT) LOG_ERROR("mini program did not return to start"); return retval; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips32_pracc.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_MIPS32_PRACC_H #define OPENOCD_TARGET_MIPS32_PRACC_H #include <target/mips32.h> #include <target/mips_ejtag.h> #define MIPS32_PRACC_FASTDATA_AREA 0xFF200000 #define MIPS32_PRACC_FASTDATA_SIZE 16 #define MIPS32_PRACC_BASE_ADDR 0xFF200000 #define MIPS32_PRACC_TEXT 0xFF200200 #define MIPS32_PRACC_PARAM_OUT 0xFF202000 #define PRACC_UPPER_BASE_ADDR (MIPS32_PRACC_BASE_ADDR >> 16) #define PRACC_MAX_CODE (MIPS32_PRACC_PARAM_OUT - MIPS32_PRACC_TEXT) #define PRACC_MAX_INSTRUCTIONS (PRACC_MAX_CODE / 4) #define PRACC_OUT_OFFSET (MIPS32_PRACC_PARAM_OUT - MIPS32_PRACC_BASE_ADDR) #define MIPS32_FASTDATA_HANDLER_SIZE 0x80 #define UPPER16(addr) ((addr) >> 16) #define LOWER16(addr) ((addr) & 0xFFFF) #define NEG16(v) (((~(v)) + 1) & 0xFFFF) #define SWAP16(v) ((LOWER16(v) << 16) | (UPPER16(v))) /*#define NEG18(v) (((~(v)) + 1) & 0x3FFFF)*/ #define PRACC_BLOCK 128 /* 1 Kbyte */ struct pa_list { uint32_t instr; uint32_t addr; }; struct pracc_queue_info { struct mips_ejtag *ejtag_info; unsigned isa; int retval; int code_count; int store_count; int max_code; /* max instructions with currently allocated memory */ struct pa_list *pracc_list; /* Code and store addresses at dmseg */ }; void pracc_queue_init(struct pracc_queue_info *ctx); void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr); void pracc_queue_free(struct pracc_queue_info *ctx); int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, uint32_t *buf, bool check_last); int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf); int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, const void *buf); int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source, int write_t, uint32_t addr, int count, uint32_t *buf); int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs); int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs); /** * \b mips32_cp0_read * * Simulates mfc0 ASM instruction (Move From C0), * i.e. implements copro C0 Register read. * * @param[in] ejtag_info * @param[in] val Storage to hold read value * @param[in] cp0_reg Number of copro C0 register we want to read * @param[in] cp0_sel Select for the given C0 register * * @return ERROR_OK on Success, ERROR_FAIL otherwise */ int mips32_cp0_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp0_reg, uint32_t cp0_sel); /** * \b mips32_cp0_write * * Simulates mtc0 ASM instruction (Move To C0), * i.e. implements copro C0 Register read. * * @param[in] ejtag_info * @param[in] val Value to be written * @param[in] cp0_reg Number of copro C0 register we want to write to * @param[in] cp0_sel Select for the given C0 register * * @return ERROR_OK on Success, ERROR_FAIL otherwise */ int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel); static inline void pracc_swap16_array(struct mips_ejtag *ejtag_info, uint32_t *buf, int count) { if (ejtag_info->isa && ejtag_info->endianness) for (int i = 0; i != count; i++) buf[i] = SWAP16(buf[i]); } #endif /* OPENOCD_TARGET_MIPS32_PRACC_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips64.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Support for processors implementing MIPS64 instruction set * * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com> * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru> * Copyright (C) 2014 by Antony Pavlov <antonynpavlov@gmail.com> * Copyright (C) 2014 by Peter Mamonov <pmamonov@gmail.com> * * Based on the work of: * Copyright (C) 2008 by Spencer Oliver * Copyright (C) 2008 by David T.L. Wong * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "mips64.h" static const struct { unsigned id; const char *name; enum reg_type type; const char *group; const char *feature; int flag; } mips64_regs[] = { { 0, "r0", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 1, "r1", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 2, "r2", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 3, "r3", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 4, "r4", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 5, "r5", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 6, "r6", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 7, "r7", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 8, "r8", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 9, "r9", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 10, "r10", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 11, "r11", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 12, "r12", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 13, "r13", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 14, "r14", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 15, "r15", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 16, "r16", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 17, "r17", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 18, "r18", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 19, "r19", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 20, "r20", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 21, "r21", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 22, "r22", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 23, "r23", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 24, "r24", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 25, "r25", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 26, "r26", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 27, "r27", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 28, "r28", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 29, "r29", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 30, "r30", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 31, "r31", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 32, "lo", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 33, "hi", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { MIPS64_NUM_CORE_REGS + 0, "pc", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, { MIPS64_NUM_CORE_REGS + 1, "Random", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 2, "Entrylo_0", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 3, "Entrylo_1", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 4, "Context", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 5, "Pagemask", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 6, "Wired", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 7, "badvaddr", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 8, "Count", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 9, "EntryHi", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 10, "Compare", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 11, "status", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 12, "cause", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 13, "EPC", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 14, "PrID", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 15, "Config", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 16, "LLA", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 17, "WatchLo0", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 18, "WatchLo1", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 19, "WatchHi0", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 20, "WatchHi1", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 21, "Xcontext", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 22, "ChipMemCtrl", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 23, "Debug", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 24, "Perfcount, sel=0", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 25, "Perfcount, sel=1", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 26, "Perfcount, sel=2", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 27, "Perfcount, sel=3", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 28, "ECC", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 29, "CacheErr", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 30, "TagLo", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 31, "TagHi", REG_TYPE_UINT32, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 32, "DataHi", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_REGS + 33, "EEPC", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cp0", 0 }, { MIPS64_NUM_CORE_C0_REGS + 0, "f0", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 1, "f1", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 2, "f2", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 3, "f3", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 4, "f4", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 5, "f5", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 6, "f6", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 7, "f7", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 8, "f8", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 9, "f9", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 10, "f10", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 11, "f11", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 12, "f12", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 13, "f13", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 14, "f14", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 15, "f15", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 16, "f16", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 17, "f17", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 18, "f18", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 19, "f19", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 20, "f20", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 21, "f21", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 22, "f22", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 23, "f23", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 24, "f24", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 25, "f25", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 26, "f26", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 27, "f27", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 28, "f28", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 29, "f29", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 30, "f30", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 31, "f31", REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 32, "fcsr", REG_TYPE_INT, "float", "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 33, "fir", REG_TYPE_INT, "float", "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 34, "fconfig", REG_TYPE_INT, "float", "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 35, "fccr", REG_TYPE_INT, "float", "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 36, "fexr", REG_TYPE_INT, "float", "org.gnu.gdb.mips.fpu", 0 }, { MIPS64_NUM_CORE_C0_REGS + 37, "fenr", REG_TYPE_INT, "float", "org.gnu.gdb.mips.fpu", 0 }, }; static int reg_type2size(enum reg_type type) { switch (type) { case REG_TYPE_UINT32: case REG_TYPE_INT: return 32; case REG_TYPE_UINT64: case REG_TYPE_IEEE_DOUBLE: return 64; default: return 64; } } static int mips64_get_core_reg(struct reg *reg) { int retval; struct mips64_core_reg *mips64_reg = reg->arch_info; struct target *target = mips64_reg->target; struct mips64_common *mips64_target = target->arch_info; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = mips64_target->read_core_reg(target, mips64_reg->num); return retval; } static int mips64_set_core_reg(struct reg *reg, uint8_t *buf) { struct mips64_core_reg *mips64_reg = reg->arch_info; struct target *target = mips64_reg->target; uint64_t value = buf_get_u64(buf, 0, 64); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; buf_set_u64(reg->value, 0, 64, value); reg->dirty = 1; reg->valid = 1; return ERROR_OK; } static int mips64_read_core_reg(struct target *target, int num) { uint64_t reg_value; /* get pointers to arch-specific information */ struct mips64_common *mips64 = target->arch_info; if ((num < 0) || (num >= MIPS64_NUM_REGS)) return ERROR_COMMAND_ARGUMENT_INVALID; reg_value = mips64->core_regs[num]; buf_set_u64(mips64->core_cache->reg_list[num].value, 0, 64, reg_value); mips64->core_cache->reg_list[num].valid = 1; mips64->core_cache->reg_list[num].dirty = 0; return ERROR_OK; } static int mips64_write_core_reg(struct target *target, int num) { uint64_t reg_value; /* get pointers to arch-specific information */ struct mips64_common *mips64 = target->arch_info; if ((num < 0) || (num >= MIPS64_NUM_REGS)) return ERROR_COMMAND_ARGUMENT_INVALID; reg_value = buf_get_u64(mips64->core_cache->reg_list[num].value, 0, 64); mips64->core_regs[num] = reg_value; LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num, reg_value); mips64->core_cache->reg_list[num].valid = 1; mips64->core_cache->reg_list[num].dirty = 0; return ERROR_OK; } int mips64_invalidate_core_regs(struct target *target) { /* get pointers to arch-specific information */ struct mips64_common *mips64 = target->arch_info; unsigned int i; for (i = 0; i < mips64->core_cache->num_regs; i++) { mips64->core_cache->reg_list[i].valid = 0; mips64->core_cache->reg_list[i].dirty = 0; } return ERROR_OK; } int mips64_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { /* get pointers to arch-specific information */ struct mips64_common *mips64 = target->arch_info; register int i; /* include floating point registers */ *reg_list_size = MIPS64_NUM_REGS; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < MIPS64_NUM_REGS; i++) (*reg_list)[i] = &mips64->core_cache->reg_list[i]; return ERROR_OK; } int mips64_save_context(struct target *target) { int retval; struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; retval = mips64_pracc_read_regs(ejtag_info, mips64->core_regs); if (retval != ERROR_OK) return retval; for (unsigned i = 0; i < MIPS64_NUM_REGS; i++) retval = mips64->read_core_reg(target, i); return retval; } int mips64_restore_context(struct target *target) { struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; for (unsigned i = 0; i < MIPS64_NUM_REGS; i++) { if (mips64->core_cache->reg_list[i].dirty) mips64->write_core_reg(target, i); } return mips64_pracc_write_regs(ejtag_info, mips64->core_regs); } int mips64_arch_state(struct target *target) { struct mips64_common *mips64 = target->arch_info; struct reg *pc = &mips64->core_cache->reg_list[MIPS64_PC]; if (mips64->common_magic != MIPS64_COMMON_MAGIC) { LOG_ERROR("BUG: called for a non-MIPS64 target"); exit(-1); } LOG_USER("target halted due to %s, pc: 0x%" PRIx64 "", debug_reason_name(target), buf_get_u64(pc->value, 0, 64)); return ERROR_OK; } static const struct reg_arch_type mips64_reg_type = { .get = mips64_get_core_reg, .set = mips64_set_core_reg, }; int mips64_build_reg_cache(struct target *target) { /* get pointers to arch-specific information */ struct mips64_common *mips64 = target->arch_info; struct reg_cache **cache_p, *cache; struct mips64_core_reg *arch_info = NULL; struct reg *reg_list = NULL; unsigned i; cache = calloc(1, sizeof(*cache)); if (!cache) { LOG_ERROR("unable to allocate cache"); return ERROR_FAIL; } reg_list = calloc(MIPS64_NUM_REGS, sizeof(*reg_list)); if (!reg_list) { LOG_ERROR("unable to allocate reg_list"); goto alloc_fail; } arch_info = calloc(MIPS64_NUM_REGS, sizeof(*arch_info)); if (!arch_info) { LOG_ERROR("unable to allocate arch_info"); goto alloc_fail; } for (i = 0; i < MIPS64_NUM_REGS; i++) { struct mips64_core_reg *a = &arch_info[i]; struct reg *r = ®_list[i]; r->arch_info = &arch_info[i]; r->caller_save = true; /* gdb defaults to true */ r->exist = true; r->feature = &a->feature; r->feature->name = mips64_regs[i].feature; r->group = mips64_regs[i].group; r->name = mips64_regs[i].name; r->number = i; r->reg_data_type = &a->reg_data_type; r->reg_data_type->type = mips64_regs[i].type; r->size = reg_type2size(mips64_regs[i].type); r->type = &mips64_reg_type; r->value = &a->value[0]; a->mips64_common = mips64; a->num = mips64_regs[i].id; a->target = target; } cache->name = "mips64 registers"; cache->reg_list = reg_list; cache->num_regs = MIPS64_NUM_REGS; cache_p = register_get_last_cache_p(&target->reg_cache); (*cache_p) = cache; mips64->core_cache = cache; return ERROR_OK; alloc_fail: free(cache); free(reg_list); free(arch_info); return ERROR_FAIL; } int mips64_init_arch_info(struct target *target, struct mips64_common *mips64, struct jtag_tap *tap) { mips64->bp_scanned = false; mips64->common_magic = MIPS64_COMMON_MAGIC; mips64->data_break_list = NULL; mips64->ejtag_info.tap = tap; mips64->fast_data_area = NULL; mips64->mips64mode32 = false; mips64->read_core_reg = mips64_read_core_reg; mips64->write_core_reg = mips64_write_core_reg; return ERROR_OK; } int mips64_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { /* TODO */ return ERROR_OK; } int mips64_examine(struct target *target) { struct mips64_common *mips64 = target->arch_info; if (target_was_examined(target)) return ERROR_OK; /* TODO: why we do not do mips64_configure_break_unit() here? */ mips64->bp_scanned = false; mips64->num_data_bpoints = 0; mips64->num_data_bpoints_avail = 0; mips64->num_inst_bpoints = 0; mips64->num_inst_bpoints_avail = 0; target_set_examined(target); return ERROR_OK; } static int mips64_configure_i_break_unit(struct target *target) { /* get pointers to arch-specific information */ struct mips64_common *mips64 = target->arch_info; struct mips64_comparator *ibl; uint64_t bpinfo; int retval; int i; /* get number of inst breakpoints */ retval = target_read_u64(target, EJTAG64_V25_IBS, &bpinfo); if (retval != ERROR_OK) return retval; mips64->num_inst_bpoints = (bpinfo >> 24) & 0x0F; mips64->num_inst_bpoints_avail = mips64->num_inst_bpoints; ibl = calloc(mips64->num_inst_bpoints, sizeof(*ibl)); if (!ibl) { LOG_ERROR("unable to allocate inst_break_list"); return ERROR_FAIL; } for (i = 0; i < mips64->num_inst_bpoints; i++) ibl[i].reg_address = EJTAG64_V25_IBA0 + (0x100 * i); mips64->inst_break_list = ibl; /* clear IBIS reg */ retval = target_write_u64(target, EJTAG64_V25_IBS, 0); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int mips64_configure_d_break_unit(struct target *target) { struct mips64_common *mips64 = target->arch_info; struct mips64_comparator *dbl; uint64_t bpinfo; int retval; int i; /* get number of data breakpoints */ retval = target_read_u64(target, EJTAG64_V25_DBS, &bpinfo); if (retval != ERROR_OK) return retval; mips64->num_data_bpoints = (bpinfo >> 24) & 0x0F; mips64->num_data_bpoints_avail = mips64->num_data_bpoints; dbl = calloc(mips64->num_data_bpoints, sizeof(*dbl)); if (!dbl) { LOG_ERROR("unable to allocate data_break_list"); return ERROR_FAIL; } for (i = 0; i < mips64->num_data_bpoints; i++) dbl[i].reg_address = EJTAG64_V25_DBA0 + (0x100 * i); mips64->data_break_list = dbl; /* clear DBIS reg */ retval = target_write_u64(target, EJTAG64_V25_DBS, 0); if (retval != ERROR_OK) return retval; return ERROR_OK; } int mips64_configure_break_unit(struct target *target) { struct mips64_common *mips64 = target->arch_info; uint64_t dcr; int retval; if (mips64->bp_scanned) return ERROR_OK; /* get info about breakpoint support */ retval = target_read_u64(target, EJTAG64_DCR, &dcr); if (retval != ERROR_OK) return retval; if (dcr & EJTAG64_DCR_IB) { retval = mips64_configure_i_break_unit(target); if (retval != ERROR_OK) return retval; } if (dcr & EJTAG64_DCR_DB) { retval = mips64_configure_d_break_unit(target); if (retval != ERROR_OK) return retval; } LOG_DEBUG("DCR 0x%" PRIx64 " numinst %i numdata %i", dcr, mips64->num_inst_bpoints, mips64->num_data_bpoints); mips64->bp_scanned = true; return ERROR_OK; } int mips64_enable_interrupts(struct target *target, bool enable) { int retval; bool update = false; uint64_t dcr; /* read debug control register */ retval = target_read_u64(target, EJTAG64_DCR, &dcr); if (retval != ERROR_OK) return retval; if (enable) { if (!(dcr & EJTAG64_DCR_INTE)) { /* enable interrupts */ dcr |= EJTAG64_DCR_INTE; update = true; } } else { if (dcr & EJTAG64_DCR_INTE) { /* disable interrupts */ dcr &= ~(uint64_t)EJTAG64_DCR_INTE; update = true; } } if (update) { retval = target_write_u64(target, EJTAG64_DCR, dcr); if (retval != ERROR_OK) return retval; } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips64.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Support for processors implementing MIPS64 instruction set * * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com> * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru> * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com> * * Based on the work of: * Copyright (C) 2008 by Spencer Oliver * Copyright (C) 2008 by David T.L. Wong * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev */ #ifndef OPENOCD_TARGET_MIPS64_H #define OPENOCD_TARGET_MIPS64_H #include "target.h" #include "register.h" #include "mips64_pracc.h" #define MIPS64_COMMON_MAGIC 0xB640B640U /* MIPS64 CP0 registers */ #define MIPS64_C0_INDEX 0 #define MIPS64_C0_RANDOM 1 #define MIPS64_C0_ENTRYLO0 2 #define MIPS64_C0_ENTRYLO1 3 #define MIPS64_C0_CONTEXT 4 #define MIPS64_C0_PAGEMASK 5 #define MIPS64_C0_WIRED 6 #define MIPS64_C0_BADVADDR 8 #define MIPS64_C0_COUNT 9 #define MIPS64_C0_ENTRYHI 10 #define MIPS64_C0_COMPARE 11 #define MIPS64_C0_STATUS 12 #define MIPS64_C0_CAUSE 13 #define MIPS64_C0_EPC 14 #define MIPS64_C0_PRID 15 #define MIPS64_C0_CONFIG 16 #define MIPS64_C0_LLA 17 #define MIPS64_C0_WATCHLO 18 #define MIPS64_C0_WATCHHI 19 #define MIPS64_C0_XCONTEXT 20 #define MIPS64_C0_MEMCTRL 22 #define MIPS64_C0_DEBUG 23 #define MIPS64_C0_DEPC 24 #define MIPS64_C0_PERFCOUNT 25 #define MIPS64_C0_ECC 26 #define MIPS64_C0_CACHERR 27 #define MIPS64_C0_TAGLO 28 #define MIPS64_C0_TAGHI 29 #define MIPS64_C0_DATAHI 29 #define MIPS64_C0_EEPC 30 /* MIPS64 CP1 registers */ #define MIPS64_C1_FIR 0 #define MIPS64_C1_FCONFIG 24 #define MIPS64_C1_FCSR 31 #define MIPS64_C1_FCCR 25 #define MIPS64_C1_FEXR 26 #define MIPS64_C1_FENR 28 /* offsets into mips64 register cache */ #define MIPS64_NUM_CORE_REGS 34 #define MIPS64_NUM_C0_REGS 34 #define MIPS64_NUM_FP_REGS 38 #define MIPS64_NUM_REGS (MIPS64_NUM_CORE_REGS + \ MIPS64_NUM_C0_REGS + \ MIPS64_NUM_FP_REGS) #define MIPS64_NUM_CORE_C0_REGS (MIPS64_NUM_CORE_REGS + MIPS64_NUM_C0_REGS) #define MIPS64_PC MIPS64_NUM_CORE_REGS struct mips64_comparator { bool used; uint64_t bp_value; uint64_t reg_address; }; struct mips64_common { unsigned int common_magic; void *arch_info; struct reg_cache *core_cache; struct mips_ejtag ejtag_info; uint64_t core_regs[MIPS64_NUM_REGS]; struct working_area *fast_data_area; bool bp_scanned; int num_inst_bpoints; int num_data_bpoints; int num_inst_bpoints_avail; int num_data_bpoints_avail; struct mips64_comparator *inst_break_list; struct mips64_comparator *data_break_list; /* register cache to processor synchronization */ int (*read_core_reg)(struct target *target, int num); int (*write_core_reg)(struct target *target, int num); bool mips64mode32; }; struct mips64_core_reg { uint32_t num; struct target *target; struct mips64_common *mips64_common; uint8_t value[8]; struct reg_feature feature; struct reg_data_type reg_data_type; }; #define MIPS64_OP_SRL 0x02 #define MIPS64_OP_BEQ 0x04 #define MIPS64_OP_BNE 0x05 #define MIPS64_OP_ADDI 0x08 #define MIPS64_OP_ANDI 0x0c #define MIPS64_OP_DADDI 0x18 #define MIPS64_OP_DADDIU 0x19 #define MIPS64_OP_AND 0x24 #define MIPS64_OP_LUI 0x0F #define MIPS64_OP_LW 0x23 #define MIPS64_OP_LD 0x37 #define MIPS64_OP_LBU 0x24 #define MIPS64_OP_LHU 0x25 #define MIPS64_OP_MFHI 0x10 #define MIPS64_OP_MTHI 0x11 #define MIPS64_OP_MFLO 0x12 #define MIPS64_OP_MTLO 0x13 #define MIPS64_OP_SB 0x28 #define MIPS64_OP_SH 0x29 #define MIPS64_OP_SW 0x2B #define MIPS64_OP_SD 0x3F #define MIPS64_OP_ORI 0x0D #define MIPS64_OP_JR 0x08 #define MIPS64_OP_COP0 0x10 #define MIPS64_OP_COP1 0x11 #define MIPS64_OP_COP2 0x12 #define MIPS64_COP_MF 0x00 #define MIPS64_COP_DMF 0x01 #define MIPS64_COP_MT 0x04 #define MIPS64_COP_DMT 0x05 #define MIPS64_COP_CF 0x02 #define MIPS64_COP_CT 0x06 #define MIPS64_R_INST(opcode, rs, rt, rd, shamt, funct) \ (((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | ((rd) << 11) | ((shamt) << 6) | (funct)) #define MIPS64_I_INST(opcode, rs, rt, immd) (((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | (immd)) #define MIPS64_J_INST(opcode, addr) (((opcode) << 26) | (addr)) #define MIPS64_NOP 0 #define MIPS64_ADDI(tar, src, val) MIPS64_I_INST(MIPS64_OP_ADDI, src, tar, val) #define MIPS64_DADDI(tar, src, val) MIPS64_I_INST(MIPS64_OP_DADDI, src, tar, val) #define MIPS64_DADDIU(tar, src, val) MIPS64_I_INST(MIPS64_OP_DADDIU, src, tar, val) #define MIPS64_AND(reg, off, val) MIPS64_R_INST(0, off, val, reg, 0, MIPS64_OP_AND) #define MIPS64_ANDI(d, s, im) MIPS64_I_INST(MIPS64_OP_ANDI, s, d, im) #define MIPS64_SRL(d, w, sh) MIPS64_R_INST(0, 0, w, d, sh, MIPS64_OP_SRL) #define MIPS64_B(off) MIPS64_BEQ(0, 0, off) #define MIPS64_BEQ(src, tar, off) MIPS64_I_INST(MIPS64_OP_BEQ, src, tar, off) #define MIPS64_BNE(src, tar, off) MIPS64_I_INST(MIPS64_OP_BNE, src, tar, off) #define MIPS64_MFC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_MF, gpr, cpr, 0, sel) #define MIPS64_DMFC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_DMF, gpr, cpr, 0, sel) #define MIPS64_MTC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_MT, gpr, cpr, 0, sel) #define MIPS64_DMTC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_DMT, gpr, cpr, 0, sel) #define MIPS64_MFC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_MF, gpr, cpr, 0, 0) #define MIPS64_DMFC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_DMF, gpr, cpr, 0, 0) #define MIPS64_MTC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_MT, gpr, cpr, 0, 0) #define MIPS64_DMTC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_DMT, gpr, cpr, 0, 0) #define MIPS64_MFC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_MF, gpr, cpr, 0, sel) #define MIPS64_MTC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_MT, gpr, cpr, 0, sel) #define MIPS64_CFC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_CF, gpr, cpr, 0, 0) #define MIPS64_CTC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_CT, gpr, cpr, 0, 0) #define MIPS64_CFC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_CF, gpr, cpr, 0, sel) #define MIPS64_CTC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_CT, gpr, cpr, 0, sel) #define MIPS64_LBU(reg, off, base) MIPS64_I_INST(MIPS64_OP_LBU, base, reg, off) #define MIPS64_LHU(reg, off, base) MIPS64_I_INST(MIPS64_OP_LHU, base, reg, off) #define MIPS64_LUI(reg, val) MIPS64_I_INST(MIPS64_OP_LUI, 0, reg, val) #define MIPS64_LW(reg, off, base) MIPS64_I_INST(MIPS64_OP_LW, base, reg, off) #define MIPS64_LD(reg, off, base) MIPS64_I_INST(MIPS64_OP_LD, base, reg, off) #define MIPS64_MFLO(reg) MIPS64_R_INST(0, 0, 0, reg, 0, MIPS64_OP_MFLO) #define MIPS64_MFHI(reg) MIPS64_R_INST(0, 0, 0, reg, 0, MIPS64_OP_MFHI) #define MIPS64_MTLO(reg) MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_MTLO) #define MIPS64_MTHI(reg) MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_MTHI) #define MIPS64_ORI(src, tar, val) MIPS64_I_INST(MIPS64_OP_ORI, src, tar, val) #define MIPS64_SB(reg, off, base) MIPS64_I_INST(MIPS64_OP_SB, base, reg, off) #define MIPS64_SH(reg, off, base) MIPS64_I_INST(MIPS64_OP_SH, base, reg, off) #define MIPS64_SW(reg, off, base) MIPS64_I_INST(MIPS64_OP_SW, base, reg, off) #define MIPS64_SD(reg, off, base) MIPS64_I_INST(MIPS64_OP_SD, base, reg, off) #define MIPS64_CACHE(op, reg, off) (47 << 26 | (reg) << 21 | (op) << 16 | (off)) #define MIPS64_SYNCI(reg, off) (1 << 26 | (reg) << 21 | 0x1f << 16 | (off)) #define MIPS64_JR(reg) MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_JR) /* ejtag specific instructions */ #define MIPS64_DRET 0x4200001F #define MIPS64_SDBBP 0x7000003F #define MIPS64_SDBBP_LE 0x3f000007 #define MIPS64_SDBBP_SIZE 4 #define MIPS16_SDBBP_SIZE 2 #define MIPS64_SYNC 0x0000000F int mips64_arch_state(struct target *target); int mips64_init_arch_info(struct target *target, struct mips64_common *mips64, struct jtag_tap *tap); int mips64_restore_context(struct target *target); int mips64_save_context(struct target *target); int mips64_build_reg_cache(struct target *target); int mips64_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); int mips64_configure_break_unit(struct target *target); int mips64_enable_interrupts(struct target *target, bool enable); int mips64_examine(struct target *target); int mips64_register_commands(struct command_context *cmd_ctx); int mips64_invalidate_core_regs(struct target *target); int mips64_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); #endif /* OPENOCD_TARGET_MIPS64_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips64_pracc.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Support for processors implementing MIPS64 instruction set * * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com> * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru> * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com> * * Based on the work of: * Copyright (C) 2008 by Spencer Oliver * Copyright (C) 2008 by David T.L. Wong * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "mips64.h" #include "mips64_pracc.h" #include <helper/time_support.h> #include <jtag/adapter.h> #define STACK_DEPTH 32 struct mips64_pracc_context { uint64_t *local_iparam; unsigned num_iparam; uint64_t *local_oparam; unsigned num_oparam; const uint32_t *code; unsigned code_len; uint64_t stack[STACK_DEPTH]; unsigned stack_offset; struct mips_ejtag *ejtag_info; }; static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl) { uint32_t ejtag_ctrl; int nt = 5; int rc; while (1) { mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = ejtag_info->ejtag_ctrl; rc = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (rc != ERROR_OK) return rc; if (ejtag_ctrl & EJTAG_CTRL_PRACC) break; LOG_DEBUG("DEBUGMODULE: No memory access in progress!\n"); if (nt == 0) return ERROR_JTAG_DEVICE_ERROR; nt--; } *ctrl = ejtag_ctrl; return ERROR_OK; } static int mips64_pracc_exec_read(struct mips64_pracc_context *ctx, uint64_t address) { struct mips_ejtag *ejtag_info = ctx->ejtag_info; unsigned offset; uint32_t ejtag_ctrl; uint64_t data; int rc; if ((address >= MIPS64_PRACC_PARAM_IN) && (address < MIPS64_PRACC_PARAM_IN + ctx->num_iparam * MIPS64_PRACC_DATA_STEP)) { offset = (address - MIPS64_PRACC_PARAM_IN) / MIPS64_PRACC_DATA_STEP; if (offset >= MIPS64_PRACC_PARAM_IN_SIZE) { LOG_ERROR("Error: iparam size exceeds MIPS64_PRACC_PARAM_IN_SIZE"); return ERROR_JTAG_DEVICE_ERROR; } if (!ctx->local_iparam) { LOG_ERROR("Error: unexpected reading of input parameter"); return ERROR_JTAG_DEVICE_ERROR; } data = ctx->local_iparam[offset]; LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address); } else if ((address >= MIPS64_PRACC_PARAM_OUT) && (address < MIPS64_PRACC_PARAM_OUT + ctx->num_oparam * MIPS64_PRACC_DATA_STEP)) { offset = (address - MIPS64_PRACC_PARAM_OUT) / MIPS64_PRACC_DATA_STEP; if (!ctx->local_oparam) { LOG_ERROR("Error: unexpected reading of output parameter"); return ERROR_JTAG_DEVICE_ERROR; } data = ctx->local_oparam[offset]; LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address); } else if ((address >= MIPS64_PRACC_TEXT) && (address < MIPS64_PRACC_TEXT + ctx->code_len * MIPS64_PRACC_ADDR_STEP)) { offset = ((address & ~7ull) - MIPS64_PRACC_TEXT) / MIPS64_PRACC_ADDR_STEP; data = (uint64_t)ctx->code[offset] << 32; if (offset + 1 < ctx->code_len) data |= (uint64_t)ctx->code[offset + 1]; LOG_DEBUG("Running commands %" PRIx64 " at %" PRIx64, data, address); } else if ((address & ~7llu) == MIPS64_PRACC_STACK) { /* load from our debug stack */ if (ctx->stack_offset == 0) { LOG_ERROR("Error reading from stack: stack is empty"); return ERROR_JTAG_DEVICE_ERROR; } data = ctx->stack[--ctx->stack_offset]; LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address); } else { /* TODO: send JMP 0xFF200000 instruction. Hopefully processor jump back * to start of debug vector */ data = 0; LOG_ERROR("Error reading unexpected address %" PRIx64, address); return ERROR_JTAG_DEVICE_ERROR; } /* Send the data out */ mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA); rc = mips_ejtag_drscan_64(ctx->ejtag_info, &data); if (rc != ERROR_OK) return rc; /* Clear the access pending bit (let the processor eat!) */ ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL); rc = mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl); if (rc != ERROR_OK) return rc; jtag_add_clocks(5); return jtag_execute_queue(); } static int mips64_pracc_exec_write(struct mips64_pracc_context *ctx, uint64_t address) { uint32_t ejtag_ctrl; uint64_t data; unsigned offset; struct mips_ejtag *ejtag_info = ctx->ejtag_info; int rc; mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA); rc = mips_ejtag_drscan_64(ctx->ejtag_info, &data); if (rc != ERROR_OK) return rc; /* Clear access pending bit */ ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL); rc = mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl); if (rc != ERROR_OK) return rc; jtag_add_clocks(5); rc = jtag_execute_queue(); if (rc != ERROR_OK) return rc; LOG_DEBUG("Writing %" PRIx64 " at %" PRIx64, data, address); if ((address >= MIPS64_PRACC_PARAM_IN) && (address < MIPS64_PRACC_PARAM_IN + ctx->num_iparam * MIPS64_PRACC_DATA_STEP)) { offset = (address - MIPS64_PRACC_PARAM_IN) / MIPS64_PRACC_DATA_STEP; if (!ctx->local_iparam) { LOG_ERROR("Error: unexpected writing of input parameter"); return ERROR_JTAG_DEVICE_ERROR; } ctx->local_iparam[offset] = data; } else if ((address >= MIPS64_PRACC_PARAM_OUT) && (address < MIPS64_PRACC_PARAM_OUT + ctx->num_oparam * MIPS64_PRACC_DATA_STEP)) { offset = (address - MIPS64_PRACC_PARAM_OUT) / MIPS64_PRACC_DATA_STEP; if (!ctx->local_oparam) { LOG_ERROR("Error: unexpected writing of output parameter"); return ERROR_JTAG_DEVICE_ERROR; } ctx->local_oparam[offset] = data; } else if (address == MIPS64_PRACC_STACK) { /* save data onto our stack */ if (ctx->stack_offset >= STACK_DEPTH) { LOG_ERROR("Error: PrAcc stack depth exceeded"); return ERROR_FAIL; } ctx->stack[ctx->stack_offset++] = data; } else { LOG_ERROR("Error writing unexpected address 0x%" PRIx64, address); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } int mips64_pracc_exec(struct mips_ejtag *ejtag_info, unsigned code_len, const uint32_t *code, unsigned num_param_in, uint64_t *param_in, unsigned num_param_out, uint64_t *param_out) { uint32_t ejtag_ctrl; uint64_t address = 0, address_prev = 0; struct mips64_pracc_context ctx; int retval; int pass = 0; bool first_time_call = true; unsigned i; for (i = 0; i < code_len; i++) LOG_DEBUG("%08" PRIx32, code[i]); ctx.local_iparam = param_in; ctx.local_oparam = param_out; ctx.num_iparam = num_param_in; ctx.num_oparam = num_param_out; ctx.code = code; ctx.code_len = code_len; ctx.ejtag_info = ejtag_info; ctx.stack_offset = 0; while (true) { uint32_t address32; retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); if (retval != ERROR_OK) { LOG_DEBUG("ERROR wait_for_pracc_rw"); return retval; } if (pass) address_prev = address; else address_prev = 0; address32 = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &address32); LOG_DEBUG("-> %08" PRIx32, address32); address = 0xffffffffff200000ull | address32; int psz = (ejtag_ctrl >> 29) & 3; int address20 = address & 7; switch (psz) { case 3: if (address20 != 7) { LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20); return ERROR_FAIL; } address &= ~7ull; break; case 2: if (address20 != 0 && address20 != 4) { LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20); return ERROR_FAIL; } break; default: LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20); return ERROR_FAIL; } if (first_time_call && address != MIPS64_PRACC_TEXT) { LOG_ERROR("Error reading address " TARGET_ADDR_FMT " (0x%08llx expected)", address, MIPS64_PRACC_TEXT); return ERROR_JTAG_DEVICE_ERROR; } first_time_call = false; /* Check for read or write */ if (ejtag_ctrl & EJTAG_CTRL_PRNW) { retval = mips64_pracc_exec_write(&ctx, address); if (retval != ERROR_OK) { LOG_ERROR("mips64_pracc_exec_write() failed"); return retval; } } else { /* Check to see if its reading at the debug vector. The first pass through * the module is always read at the vector, so the first one we allow. When * the second read from the vector occurs we are done and just exit. */ if ((address == MIPS64_PRACC_TEXT) && (pass++)) { LOG_DEBUG("@MIPS64_PRACC_TEXT, address_prev=%" PRIx64, address_prev); break; } retval = mips64_pracc_exec_read(&ctx, address); if (retval != ERROR_OK) { LOG_ERROR("mips64_pracc_exec_read() failed"); return retval; } } } /* stack sanity check */ if (ctx.stack_offset != 0) LOG_ERROR("Pracc Stack not zero"); return ERROR_OK; } static int mips64_pracc_read_u64(struct mips_ejtag *ejtag_info, uint64_t addr, uint64_t *buf) { const uint32_t code[] = { /* move $15 to COP0 DeSave */ MIPS64_DMTC0(15, 31, 0), /* $15 = MIPS64_PRACC_STACK */ MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), /* sd $8, ($15) */ MIPS64_SD(8, 0, 15), /* load R8 @ param_in[0] = address */ MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), /* ld $8, 0($8), Load $8 with the word @mem[$8] */ MIPS64_LD(8, 0, 8), /* sd $8, 0($15) */ MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), /* ld $8, ($15) */ MIPS64_LD(8, 0, 15), MIPS64_SYNC, /* b start */ MIPS64_B(NEG16(10)), /* move COP0 DeSave to $15 */ MIPS64_DMFC0(15, 31, 0), MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, }; uint64_t param_in[1]; param_in[0] = addr; LOG_DEBUG("enter mips64_pracc_exec"); return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, ARRAY_SIZE(param_in), param_in, 1, (uint64_t *) buf); } static int mips64_pracc_read_mem64(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned count, uint64_t *buf) { int retval = ERROR_OK; for (unsigned i = 0; i < count; i++) { retval = mips64_pracc_read_u64(ejtag_info, addr + 8*i, &buf[i]); if (retval != ERROR_OK) return retval; } return retval; } static int mips64_pracc_read_u32(struct mips_ejtag *ejtag_info, uint64_t addr, uint32_t *buf) { const uint32_t code[] = { /* move $15 to COP0 DeSave */ MIPS64_DMTC0(15, 31, 0), /* $15 = MIPS64_PRACC_STACK */ MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), /* sd $8, ($15) */ MIPS64_SD(8, 0, 15), /* load R8 @ param_in[0] = address */ MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), /* lw $8, 0($8), Load $8 with the word @mem[$8] */ MIPS64_LW(8, 0, 8), /* sd $8, 0($9) */ MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), /* ld $8, ($15) */ MIPS64_LD(8, 0, 15), MIPS64_SYNC, /* b start */ MIPS64_B(NEG16(10)), /* move COP0 DeSave to $15 */ MIPS64_DMFC0(15, 31, 0), MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, }; int retval = ERROR_OK; uint64_t param_in[1]; uint64_t param_out[1]; param_in[0] = addr; LOG_DEBUG("enter mips64_pracc_exec"); retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 1, param_in, 1, param_out); buf[0] = (uint32_t) param_out[0]; return retval; } static int mips64_pracc_read_mem32(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned count, uint32_t *buf) { int retval = ERROR_OK; for (unsigned i = 0; i < count; i++) { retval = mips64_pracc_read_u32(ejtag_info, addr + 4 * i, &buf[i]); if (retval != ERROR_OK) return retval; } return retval; } static int mips64_pracc_read_u16(struct mips_ejtag *ejtag_info, uint64_t addr, uint16_t *buf) { const uint32_t code[] = { /* move $15 to COP0 DeSave */ MIPS64_DMTC0(15, 31, 0), /* $15 = MIPS64_PRACC_STACK */ MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), /* sd $8, ($15) */ MIPS64_SD(8, 0, 15), /* load R8 @ param_in[0] = address */ MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), /* lw $8, 0($8), Load $8 with the word @mem[$8] */ MIPS64_LHU(8, 0, 8), /* sd $8, 0($9) */ MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), /* ld $8, ($15) */ MIPS64_LD(8, 0, 15), MIPS64_SYNC, /* b start */ MIPS64_B(NEG16(10)), /* move COP0 DeSave to $15 */ MIPS64_DMFC0(15, 31, 0), MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, }; int retval; uint64_t param_in[1]; uint64_t param_out[1]; param_in[0] = addr; LOG_DEBUG("enter mips64_pracc_exec"); retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 1, param_in, 1, param_out); buf[0] = (uint16_t)param_out[0]; return retval; } static int mips64_pracc_read_mem16(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned count, uint16_t *buf) { int retval = ERROR_OK; for (unsigned i = 0; i < count; i++) { retval = mips64_pracc_read_u16(ejtag_info, addr + 2*i, &buf[i]); if (retval != ERROR_OK) return retval; } return retval; } static int mips64_pracc_read_u8(struct mips_ejtag *ejtag_info, uint64_t addr, uint8_t *buf) { const uint32_t code[] = { /* move $15 to COP0 DeSave */ MIPS64_DMTC0(15, 31, 0), /* $15 = MIPS64_PRACC_STACK */ MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), /* sd $8, ($15) */ MIPS64_SD(8, 0, 15), /* load R8 @ param_in[0] = address */ MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), /* lw $8, 0($8), Load $8 with the word @mem[$8] */ MIPS64_LBU(8, 0, 8), /* sd $8, 0($9) */ MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), /* ld $8, ($15) */ MIPS64_LD(8, 0, 15), MIPS64_SYNC, /* b start */ MIPS64_B(NEG16(10)), /* move COP0 DeSave to $15 */ MIPS64_DMFC0(15, 31, 0), MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, }; int retval; uint64_t param_in[1]; uint64_t param_out[1]; param_in[0] = addr; LOG_DEBUG("enter mips64_pracc_exec"); retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 1, param_in, 1, param_out); buf[0] = (uint8_t)param_out[0]; return retval; } static int mips64_pracc_read_mem8(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned count, uint8_t *buf) { int retval = ERROR_OK; for (unsigned i = 0; i < count; i++) { retval = mips64_pracc_read_u8(ejtag_info, addr + i, &buf[i]); if (retval != ERROR_OK) return retval; } return retval; } int mips64_pracc_read_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned size, unsigned count, void *buf) { switch (size) { case 1: return mips64_pracc_read_mem8(ejtag_info, addr, count, buf); case 2: return mips64_pracc_read_mem16(ejtag_info, addr, count, buf); case 4: return mips64_pracc_read_mem32(ejtag_info, addr, count, buf); case 8: return mips64_pracc_read_mem64(ejtag_info, addr, count, buf); } return ERROR_FAIL; } static int mips64_pracc_write_u64(struct mips_ejtag *ejtag_info, uint64_t addr, uint64_t *buf) { const uint32_t code[] = { /* move $15 to COP0 DeSave */ MIPS64_DMTC0(15, 31, 0), /* $15 = MIPS64_PRACC_STACK */ MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), /* sd $8, ($15) */ MIPS64_SD(8, 0, 15), /* sd $9, ($15) */ MIPS64_SD(9, 0, 15), /* load R8 @ param_in[1] = data */ MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN)-8), 15), /* load R9 @ param_in[0] = address */ MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), /* sd $8, 0($9) */ MIPS64_SD(8, 0, 9), MIPS64_SYNCI(9, 0), /* ld $9, ($15) */ MIPS64_LD(9, 0, 15), /* ld $8, ($15) */ MIPS64_LD(8, 0, 15), MIPS64_SYNC, /* b start */ MIPS64_B(NEG16(13)), /* move COP0 DeSave to $15 */ MIPS64_DMFC0(15, 31, 0), MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, }; /* TODO remove array */ uint64_t param_in[2]; param_in[0] = addr; param_in[1] = *buf; LOG_DEBUG("enter mips64_pracc_exec"); return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, ARRAY_SIZE(param_in), param_in, 0, NULL); } static int mips64_pracc_write_mem64(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned count, uint64_t *buf) { int retval = ERROR_OK; for (unsigned i = 0; i < count; i++) { retval = mips64_pracc_write_u64(ejtag_info, addr + 8 * i, &buf[i]); if (retval != ERROR_OK) return retval; } return retval; } static int mips64_pracc_write_u32(struct mips_ejtag *ejtag_info, uint64_t addr, uint32_t *buf) { const uint32_t code[] = { MIPS64_DMTC0(15, 31, 0), /* move $15 to COP0 DeSave */ MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), /* $15 = MIPS64_PRACC_STACK */ MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), MIPS64_SD(8, 0, 15), /* sd $8, ($15) */ MIPS64_SD(9, 0, 15), /* sd $9, ($15) */ MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15), /* load R8 @ param_in[1] = data */ MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), /* load R9 @ param_in[0] = address */ MIPS64_SW(8, 0, 9), /* sw $8, 0($9) */ MIPS64_SYNCI(9, 0), MIPS64_LD(9, 0, 15), /* ld $9, ($15) */ MIPS64_LD(8, 0, 15), /* ld $8, ($15) */ MIPS64_SYNC, MIPS64_B(NEG16(13)), /* b start */ MIPS64_DMFC0(15, 31, 0), /* move COP0 DeSave to $15 */ MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, }; /* TODO remove array */ uint64_t param_in[1 + 1]; param_in[0] = addr; param_in[1] = *buf; LOG_DEBUG("enter mips64_pracc_exec"); return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, ARRAY_SIZE(param_in), param_in, 0, NULL); } static int mips64_pracc_write_mem32(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned count, uint32_t *buf) { int retval = ERROR_OK; for (unsigned i = 0; i < count; i++) { retval = mips64_pracc_write_u32(ejtag_info, addr + 4 * i, &buf[i]); if (retval != ERROR_OK) return retval; } return retval; } static int mips64_pracc_write_u16(struct mips_ejtag *ejtag_info, uint64_t addr, uint16_t *buf) { const uint32_t code[] = { /* move $15 to COP0 DeSave */ MIPS64_DMTC0(15, 31, 0), /* $15 = MIPS64_PRACC_STACK */ MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), /* sd $8, ($15) */ MIPS64_SD(8, 0, 15), /* sd $9, ($15) */ MIPS64_SD(9, 0, 15), /* load R8 @ param_in[1] = data */ MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15), /* load R9 @ param_in[0] = address */ MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), /* sh $8, 0($9) */ MIPS64_SH(8, 0, 9), /* ld $9, ($15) */ MIPS64_LD(9, 0, 15), /* ld $8, ($15) */ MIPS64_LD(8, 0, 15), MIPS64_SYNC, /* b start */ MIPS64_B(NEG16(12)), /* move COP0 DeSave to $15 */ MIPS64_DMFC0(15, 31, 0), MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, }; uint64_t param_in[2]; param_in[0] = addr; param_in[1] = *buf; LOG_DEBUG("enter mips64_pracc_exec"); return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, ARRAY_SIZE(param_in), param_in, 0, NULL); } static int mips64_pracc_write_mem16(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned count, uint16_t *buf) { int retval = ERROR_OK; for (unsigned i = 0; i < count; i++) { retval = mips64_pracc_write_u16(ejtag_info, addr + 2 * i, &buf[i]); if (retval != ERROR_OK) return retval; } return retval; } static int mips64_pracc_write_u8(struct mips_ejtag *ejtag_info, uint64_t addr, uint8_t *buf) { const uint32_t code[] = { /* move $15 to COP0 DeSave */ MIPS64_DMTC0(15, 31, 0), /* $15 = MIPS64_PRACC_STACK */ MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), /* sd $8, ($15) */ MIPS64_SD(8, 0, 15), /* sd $9, ($15) */ MIPS64_SD(9, 0, 15), /* load R8 @ param_in[1] = data */ MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15), /* load R9 @ param_in[0] = address */ MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), /* sh $8, 0($9) */ MIPS64_SB(8, 0, 9), /* ld $9, ($15) */ MIPS64_LD(9, 0, 15), /* ld $8, ($15) */ MIPS64_LD(8, 0, 15), MIPS64_SYNC, /* b start */ MIPS64_B(NEG16(12)), /* move COP0 DeSave to $15 */ MIPS64_DMFC0(15, 31, 0), MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, }; /* TODO remove array */ uint64_t param_in[2]; param_in[0] = addr; param_in[1] = *buf; LOG_DEBUG("enter mips64_pracc_exec"); return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, ARRAY_SIZE(param_in), param_in, 0, NULL); } static int mips64_pracc_write_mem8(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned count, uint8_t *buf) { int retval = ERROR_OK; for (unsigned i = 0; i < count; i++) { retval = mips64_pracc_write_u8(ejtag_info, addr + i, &buf[i]); if (retval != ERROR_OK) return retval; } return retval; } int mips64_pracc_write_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned size, unsigned count, void *buf) { switch (size) { case 1: return mips64_pracc_write_mem8(ejtag_info, addr, count, buf); case 2: return mips64_pracc_write_mem16(ejtag_info, addr, count, buf); case 4: return mips64_pracc_write_mem32(ejtag_info, addr, count, buf); case 8: return mips64_pracc_write_mem64(ejtag_info, addr, count, buf); } return ERROR_FAIL; } int mips64_pracc_write_regs(struct mips_ejtag *ejtag_info, uint64_t *regs) { const uint32_t code[] = { /* move $2 to COP0 DeSave */ MIPS64_DMTC0(2, 31, 0), /* $15 = MIPS64_PRACC_STACK */ MIPS64_LUI(2, UPPER16(MIPS64_PRACC_PARAM_IN)), MIPS64_ORI(2, 2, LOWER16(MIPS64_PRACC_PARAM_IN)), /* sd $0, 0*8($2) */ MIPS64_LD(1, 1*8, 2), /* sd $1, 1*8($2) */ MIPS64_LD(15, 15*8, 2), /* sd $11, ($15) */ MIPS64_DMFC0(2, 31, 0), MIPS64_DMTC0(15, 31, 0), MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), MIPS64_SD(1, 0, 15), /* $11 = MIPS64_PRACC_PARAM_OUT */ MIPS64_LUI(1, UPPER16(MIPS64_PRACC_PARAM_IN)), MIPS64_ORI(1, 1, LOWER16(MIPS64_PRACC_PARAM_IN)), MIPS64_LD(3, 3*8, 1), MIPS64_LD(4, 4*8, 1), MIPS64_LD(5, 5*8, 1), MIPS64_LD(6, 6*8, 1), MIPS64_LD(7, 7*8, 1), MIPS64_LD(8, 8*8, 1), MIPS64_LD(9, 9*8, 1), MIPS64_LD(10, 10*8, 1), MIPS64_LD(11, 11*8, 1), MIPS64_LD(12, 12*8, 1), MIPS64_LD(13, 13*8, 1), MIPS64_LD(14, 14*8, 1), MIPS64_LD(16, 16*8, 1), MIPS64_LD(17, 17*8, 1), MIPS64_LD(18, 18*8, 1), MIPS64_LD(19, 19*8, 1), MIPS64_LD(20, 20*8, 1), MIPS64_LD(21, 21*8, 1), MIPS64_LD(22, 22*8, 1), MIPS64_LD(23, 23*8, 1), MIPS64_LD(24, 24*8, 1), MIPS64_LD(25, 25*8, 1), MIPS64_LD(26, 26*8, 1), MIPS64_LD(27, 27*8, 1), MIPS64_LD(28, 28*8, 1), MIPS64_LD(29, 29*8, 1), MIPS64_LD(30, 30*8, 1), MIPS64_LD(31, 31*8, 1), MIPS64_LD(2, 32*8, 1), MIPS64_MTLO(2), MIPS64_LD(2, 33*8, 1), MIPS64_MTHI(2), MIPS64_LD(2, MIPS64_NUM_CORE_REGS * 8, 1), MIPS64_DMTC0(2, MIPS64_C0_DEPC, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 2) * 8, 1), MIPS64_DMTC0(2, MIPS64_C0_ENTRYLO0, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 3) * 8, 1), MIPS64_DMTC0(2, MIPS64_C0_ENTRYLO1, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 4) * 8, 1), MIPS64_DMTC0(2, MIPS64_C0_CONTEXT, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 5) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_PAGEMASK, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 6) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_WIRED, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 8) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_COUNT, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 9) * 8, 1), MIPS64_DMTC0(2, MIPS64_C0_ENTRYHI, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 10) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_COMPARE, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 11) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_STATUS, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 12) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_CAUSE, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 13) * 8, 1), MIPS64_DMTC0(2, MIPS64_C0_EPC, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 15) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_CONFIG, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 16) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_LLA, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 21) * 8, 1), MIPS64_DMTC0(2, MIPS64_C0_XCONTEXT, 1), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 22) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_MEMCTRL, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 24) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 25) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 1), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 26) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 2), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 27) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 3), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 28) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_ECC, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 29) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_CACHERR, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 30) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_TAGLO, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 31) * 8, 1), MIPS64_MTC0(2, MIPS64_C0_TAGHI, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 32) * 8, 1), MIPS64_DMTC0(2, MIPS64_C0_DATAHI, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 33) * 8, 1), MIPS64_DMTC0(2, MIPS64_C0_EEPC, 0), /* check if FPU is enabled, */ MIPS64_MFC0(2, MIPS64_C0_STATUS, 0), MIPS64_SRL(2, 2, 29), MIPS64_ANDI(2, 2, 1), /* skip FPU registers restoration if not */ MIPS64_BEQ(0, 2, 77), MIPS64_NOP, MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 33) * 8, 1), MIPS64_CTC1(2, MIPS64_C1_FIR, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 32) * 8, 1), MIPS64_CTC1(2, MIPS64_C1_FCSR, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 34) * 8, 1), MIPS64_CTC1(2, MIPS64_C1_FCONFIG, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 35) * 8, 1), MIPS64_CTC1(2, MIPS64_C1_FCCR, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 36) * 8, 1), MIPS64_CTC1(2, MIPS64_C1_FEXR, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 37) * 8, 1), MIPS64_CTC1(2, MIPS64_C1_FENR, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 0) * 8, 1), MIPS64_DMTC1(2, 0, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 1) * 8, 1), MIPS64_DMTC1(2, 1, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 2) * 8, 1), MIPS64_DMTC1(2, 2, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 3) * 8, 1), MIPS64_DMTC1(2, 3, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 4) * 8, 1), MIPS64_DMTC1(2, 4, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 5) * 8, 1), MIPS64_DMTC1(2, 5, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 6) * 8, 1), MIPS64_DMTC1(2, 6, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 7) * 8, 1), MIPS64_DMTC1(2, 7, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 8) * 8, 1), MIPS64_DMTC1(2, 8, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 9) * 8, 1), MIPS64_DMTC1(2, 9, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 10) * 8, 1), MIPS64_DMTC1(2, 10, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 11) * 8, 1), MIPS64_DMTC1(2, 11, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 12) * 8, 1), MIPS64_DMTC1(2, 12, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 13) * 8, 1), MIPS64_DMTC1(2, 13, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 14) * 8, 1), MIPS64_DMTC1(2, 14, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 15) * 8, 1), MIPS64_DMTC1(2, 15, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 16) * 8, 1), MIPS64_DMTC1(2, 16, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 17) * 8, 1), MIPS64_DMTC1(2, 17, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 18) * 8, 1), MIPS64_DMTC1(2, 18, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 19) * 8, 1), MIPS64_DMTC1(2, 19, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 20) * 8, 1), MIPS64_DMTC1(2, 20, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 21) * 8, 1), MIPS64_DMTC1(2, 21, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 22) * 8, 1), MIPS64_DMTC1(2, 22, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 23) * 8, 1), MIPS64_DMTC1(2, 23, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 24) * 8, 1), MIPS64_DMTC1(2, 24, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 25) * 8, 1), MIPS64_DMTC1(2, 25, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 26) * 8, 1), MIPS64_DMTC1(2, 26, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 27) * 8, 1), MIPS64_DMTC1(2, 27, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 28) * 8, 1), MIPS64_DMTC1(2, 28, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 29) * 8, 1), MIPS64_DMTC1(2, 29, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 30) * 8, 1), MIPS64_DMTC1(2, 30, 0), MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 31) * 8, 1), MIPS64_DMTC1(2, 31, 0), MIPS64_LD(2, 2 * 8, 1), MIPS64_LD(1, 0, 15), MIPS64_SYNC, /* b start */ MIPS64_B(NEG16(181)), /* move COP0 DeSave to $15 */ MIPS64_DMFC0(15, 31, 0), MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, }; LOG_DEBUG("enter mips64_pracc_exec"); return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, MIPS64_NUM_REGS, regs, 0, NULL); } int mips64_pracc_read_regs(struct mips_ejtag *ejtag_info, uint64_t *regs) { const uint32_t code[] = { /* move $2 to COP0 DeSave */ MIPS64_DMTC0(2, 31, 0), /* $2 = MIPS64_PRACC_PARAM_OUT */ MIPS64_LUI(2, UPPER16(MIPS64_PRACC_PARAM_OUT)), MIPS64_ORI(2, 2, LOWER16(MIPS64_PRACC_PARAM_OUT)), /* sd $0, 0*8($2) */ MIPS64_SD(0, 0*8, 2), /* sd $1, 1*8($2) */ MIPS64_SD(1, 1*8, 2), /* sd $15, 15*8($2) */ MIPS64_SD(15, 15*8, 2), /* move COP0 DeSave to $2 */ MIPS64_DMFC0(2, 31, 0), /* move $15 to COP0 DeSave */ MIPS64_DMTC0(15, 31, 0), /* $15 = MIPS64_PRACC_STACK */ MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), /* sd $1, ($15) */ MIPS64_SD(1, 0, 15), /* sd $2, ($15) */ MIPS64_SD(2, 0, 15), /* $1 = MIPS64_PRACC_PARAM_OUT */ MIPS64_LUI(1, UPPER16(MIPS64_PRACC_PARAM_OUT)), MIPS64_ORI(1, 1, LOWER16(MIPS64_PRACC_PARAM_OUT)), MIPS64_SD(2, 2 * 8, 1), MIPS64_SD(3, 3 * 8, 1), MIPS64_SD(4, 4 * 8, 1), MIPS64_SD(5, 5 * 8, 1), MIPS64_SD(6, 6 * 8, 1), MIPS64_SD(7, 7 * 8, 1), MIPS64_SD(8, 8 * 8, 1), MIPS64_SD(9, 9 * 8, 1), MIPS64_SD(10, 10 * 8, 1), MIPS64_SD(11, 11 * 8, 1), MIPS64_SD(12, 12 * 8, 1), MIPS64_SD(13, 13 * 8, 1), MIPS64_SD(14, 14 * 8, 1), MIPS64_SD(16, 16 * 8, 1), MIPS64_SD(17, 17 * 8, 1), MIPS64_SD(18, 18 * 8, 1), MIPS64_SD(19, 19 * 8, 1), MIPS64_SD(20, 20 * 8, 1), MIPS64_SD(21, 21 * 8, 1), MIPS64_SD(22, 22 * 8, 1), MIPS64_SD(23, 23 * 8, 1), MIPS64_SD(24, 24 * 8, 1), MIPS64_SD(25, 25 * 8, 1), MIPS64_SD(26, 26 * 8, 1), MIPS64_SD(27, 27 * 8, 1), MIPS64_SD(28, 28 * 8, 1), MIPS64_SD(29, 29 * 8, 1), MIPS64_SD(30, 30 * 8, 1), MIPS64_SD(31, 31 * 8, 1), MIPS64_MFLO(2), MIPS64_SD(2, 32 * 8, 1), MIPS64_MFHI(2), MIPS64_SD(2, 33 * 8, 1), MIPS64_DMFC0(2, MIPS64_C0_DEPC, 0), MIPS64_SD(2, MIPS64_NUM_CORE_REGS * 8, 1), MIPS64_DMFC0(2, MIPS64_C0_RANDOM, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 1) * 8, 1), MIPS64_DMFC0(2, MIPS64_C0_ENTRYLO0, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 2) * 8, 1), MIPS64_DMFC0(2, MIPS64_C0_ENTRYLO1, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 3) * 8, 1), MIPS64_DMFC0(2, MIPS64_C0_CONTEXT, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 4) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_PAGEMASK, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 5) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_WIRED, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 6) * 8, 1), MIPS64_DMFC0(2, MIPS64_C0_BADVADDR, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 7) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_COUNT, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 8) * 8, 1), MIPS64_DMFC0(2, MIPS64_C0_ENTRYHI, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 9) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_COMPARE, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 10) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_STATUS, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 11) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_CAUSE, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 12) * 8, 1), MIPS64_DMFC0(2, MIPS64_C0_EPC, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 13) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_PRID, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 14) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_CONFIG, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 15) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_LLA, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 16) * 8, 1), MIPS64_DMFC0(2, MIPS64_C0_XCONTEXT, 1), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 21) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_MEMCTRL, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 22) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_DEBUG, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 23) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 24) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 1), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 25) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 2), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 26) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 3), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 27) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_ECC, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 28) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_CACHERR, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 29) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_TAGLO, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 30) * 8, 1), MIPS64_MFC0(2, MIPS64_C0_TAGHI, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 31) * 8, 1), MIPS64_DMFC0(2, MIPS64_C0_DATAHI, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 32) * 8, 1), MIPS64_DMFC0(2, MIPS64_C0_EEPC, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 33) * 8, 1), /* check if FPU is enabled, */ MIPS64_MFC0(2, MIPS64_C0_STATUS, 0), MIPS64_SRL(2, 2, 29), MIPS64_ANDI(2, 2, 1), /* skip FPU registers dump if not */ MIPS64_BEQ(0, 2, 77), MIPS64_NOP, MIPS64_CFC1(2, MIPS64_C1_FIR, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 33) * 8, 1), MIPS64_CFC1(2, MIPS64_C1_FCSR, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 32) * 8, 1), MIPS64_CFC1(2, MIPS64_C1_FCONFIG, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 34) * 8, 1), MIPS64_CFC1(2, MIPS64_C1_FCCR, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 35) * 8, 1), MIPS64_CFC1(2, MIPS64_C1_FEXR, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 36) * 8, 1), MIPS64_CFC1(2, MIPS64_C1_FENR, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 37) * 8, 1), MIPS64_DMFC1(2, 0, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 0) * 8, 1), MIPS64_DMFC1(2, 1, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 1) * 8, 1), MIPS64_DMFC1(2, 2, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 2) * 8, 1), MIPS64_DMFC1(2, 3, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 3) * 8, 1), MIPS64_DMFC1(2, 4, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 4) * 8, 1), MIPS64_DMFC1(2, 5, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 5) * 8, 1), MIPS64_DMFC1(2, 6, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 6) * 8, 1), MIPS64_DMFC1(2, 7, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 7) * 8, 1), MIPS64_DMFC1(2, 8, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 8) * 8, 1), MIPS64_DMFC1(2, 9, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 9) * 8, 1), MIPS64_DMFC1(2, 10, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 10) * 8, 1), MIPS64_DMFC1(2, 11, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 11) * 8, 1), MIPS64_DMFC1(2, 12, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 12) * 8, 1), MIPS64_DMFC1(2, 13, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 13) * 8, 1), MIPS64_DMFC1(2, 14, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 14) * 8, 1), MIPS64_DMFC1(2, 15, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 15) * 8, 1), MIPS64_DMFC1(2, 16, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 16) * 8, 1), MIPS64_DMFC1(2, 17, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 17) * 8, 1), MIPS64_DMFC1(2, 18, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 18) * 8, 1), MIPS64_DMFC1(2, 19, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 19) * 8, 1), MIPS64_DMFC1(2, 20, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 20) * 8, 1), MIPS64_DMFC1(2, 21, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 21) * 8, 1), MIPS64_DMFC1(2, 22, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 22) * 8, 1), MIPS64_DMFC1(2, 23, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 23) * 8, 1), MIPS64_DMFC1(2, 24, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 24) * 8, 1), MIPS64_DMFC1(2, 25, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 25) * 8, 1), MIPS64_DMFC1(2, 26, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 26) * 8, 1), MIPS64_DMFC1(2, 27, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 27) * 8, 1), MIPS64_DMFC1(2, 28, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 28) * 8, 1), MIPS64_DMFC1(2, 29, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 29) * 8, 1), MIPS64_DMFC1(2, 30, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 30) * 8, 1), MIPS64_DMFC1(2, 31, 0), MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 31) * 8, 1), MIPS64_LD(2, 0, 15), MIPS64_LD(1, 0, 15), MIPS64_SYNC, /* b start */ MIPS64_B(NEG16(192)), /* move COP0 DeSave to $15 */ MIPS64_DMFC0(15, 31, 0), MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, }; LOG_DEBUG("enter mips64_pracc_exec"); return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 0, NULL, MIPS64_NUM_REGS, regs); } /* fastdata upload/download requires an initialized working area * to load the download code; it should not be called otherwise * fetch order from the fastdata area * 1. start addr * 2. end addr * 3. data ... */ int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source, bool write_t, uint64_t addr, unsigned count, uint64_t *buf) { uint32_t handler_code[] = { /* caution when editing, table is modified below */ /* r15 points to the start of this code */ MIPS64_SD(8, MIPS64_FASTDATA_HANDLER_SIZE - 8, 15), MIPS64_SD(9, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 2, 15), MIPS64_SD(10, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 3, 15), MIPS64_SD(11, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 4, 15), /* start of fastdata area in t0 */ MIPS64_LUI(8, UPPER16(MIPS64_PRACC_FASTDATA_AREA)), MIPS64_ORI(8, 8, LOWER16(MIPS64_PRACC_FASTDATA_AREA)), /* start addr in t1 */ MIPS64_LD(9, 0, 8), /* end addr to t2 */ MIPS64_LD(10, 0, 8), /* loop: */ /* lw t3,[t8 | r9] */ /* 8 */ MIPS64_LD(11, 0, 0), /* sw t3,[r9 | r8] */ /* 9 */ MIPS64_SD(11, 0, 0), /* bne $t2,t1,loop */ MIPS64_BNE(10, 9, NEG16(3)), /* addi t1,t1,4 */ MIPS64_DADDIU(9, 9, 8), MIPS64_LD(8, MIPS64_FASTDATA_HANDLER_SIZE - 8, 15), MIPS64_LD(9, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 2, 15), MIPS64_LD(10, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 3, 15), MIPS64_LD(11, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 4, 15), MIPS64_LUI(15, UPPER16(MIPS64_PRACC_TEXT)), MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_TEXT)), /* jr start */ MIPS64_JR(15), /* move COP0 DeSave to $15 */ MIPS64_DMFC0(15, 31, 0), }; uint32_t jmp_code[] = { /* addr of working area added below */ /* 0 */ MIPS64_LUI(15, 0), /* addr of working area added below */ /* 1 */ MIPS64_ORI(15, 15, 0), /* jump to ram program */ MIPS64_JR(15), MIPS64_NOP, }; int retval; unsigned i; uint32_t ejtag_ctrl, address32; uint64_t address, val; if (source->size < MIPS64_FASTDATA_HANDLER_SIZE) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if (write_t) { /* load data from probe at fastdata area */ handler_code[8] = MIPS64_LD(11, 0, 8); /* store data to RAM @ r9 */ handler_code[9] = MIPS64_SD(11, 0, 9); } else { /* load data from RAM @ r9 */ handler_code[8] = MIPS64_LD(11, 0, 9); /* store data to probe at fastdata area */ handler_code[9] = MIPS64_SD(11, 0, 8); } /* write program into RAM */ if (write_t != ejtag_info->fast_access_save) { mips64_pracc_write_mem(ejtag_info, source->address, 4, ARRAY_SIZE(handler_code), handler_code); /* save previous operation to speed to any consecutive read/writes */ ejtag_info->fast_access_save = write_t; } LOG_DEBUG("%s using " TARGET_ADDR_FMT " for write handler", __func__, source->address); LOG_DEBUG("daddiu: %08" PRIx32, handler_code[11]); jmp_code[0] |= UPPER16(source->address); jmp_code[1] |= LOWER16(source->address); mips64_pracc_exec(ejtag_info, ARRAY_SIZE(jmp_code), jmp_code, 0, NULL, 0, NULL); /* next fetch to dmseg should be in FASTDATA_AREA, check */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); retval = mips_ejtag_drscan_32(ejtag_info, &address32); if (retval != ERROR_OK) return retval; address = 0xffffffffff200000ull | address32; if ((address & ~7ull) != MIPS64_PRACC_FASTDATA_AREA) { LOG_ERROR("! @MIPS64_PRACC_FASTDATA_AREA (" TARGET_ADDR_FMT ")", address); return ERROR_FAIL; } /* Send the load start address */ val = addr; LOG_DEBUG("start: " TARGET_ADDR_FMT, val); mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); mips64_ejtag_fastdata_scan(ejtag_info, 1, &val); retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); if (retval != ERROR_OK) return retval; /* Send the load end address */ val = addr + (count - 1) * 8; LOG_DEBUG("stop: " TARGET_ADDR_FMT, val); mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); mips64_ejtag_fastdata_scan(ejtag_info, 1, &val); /* like in legacy code */ unsigned num_clocks = 0; if (ejtag_info->mode != 0) num_clocks = ((uint64_t)(ejtag_info->scan_delay) * adapter_get_speed_khz() + 500000) / 1000000; LOG_DEBUG("num_clocks=%d", num_clocks); for (i = 0; i < count; i++) { jtag_add_clocks(num_clocks); retval = mips64_ejtag_fastdata_scan(ejtag_info, write_t, buf++); if (retval != ERROR_OK) { LOG_ERROR("mips64_ejtag_fastdata_scan failed"); return retval; } } retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("jtag_execute_queue failed"); return retval; } retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); if (retval != ERROR_OK) { LOG_ERROR("wait_for_pracc_rw failed"); return retval; } mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); retval = mips_ejtag_drscan_32(ejtag_info, &address32); if (retval != ERROR_OK) { LOG_ERROR("mips_ejtag_drscan_32 failed"); return retval; } address = 0xffffffffff200000ull | address32; if ((address & ~7ull) != MIPS64_PRACC_TEXT) LOG_ERROR("mini program did not return to start"); return retval; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips64_pracc.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Support for processors implementing MIPS64 instruction set * * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com> * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru> * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com> * * Based on the work of: * Copyright (C) 2008 by Spencer Oliver * Copyright (C) 2008 by David T.L. Wong * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev */ #ifndef OPENOCD_TARGET_MIPS64_PRACC_H #define OPENOCD_TARGET_MIPS64_PRACC_H #include "mips_ejtag.h" #define MIPS64_PRACC_TEXT 0xffffffffFF200200ull #define MIPS64_PRACC_STACK 0xffffffffFF204000ull #define MIPS64_PRACC_PARAM_IN 0xffffffffFF201000ull #define MIPS64_PRACC_PARAM_IN_SIZE 0x1000 #define MIPS64_PRACC_PARAM_OUT (MIPS64_PRACC_PARAM_IN + MIPS64_PRACC_PARAM_IN_SIZE) #define MIPS64_PRACC_PARAM_OUT_SIZE 0x1000 #undef UPPER16 #undef LOWER16 #define UPPER16(v) ((uint32_t)((v >> 16) & 0xFFFF)) #define LOWER16(v) ((uint32_t)(v & 0xFFFF)) #define MIPS64_PRACC_FASTDATA_AREA 0xffffffffFF200000ull #define MIPS64_PRACC_FASTDATA_SIZE 16 #define MIPS64_FASTDATA_HANDLER_SIZE 0x80 /* FIXME: 16-bit NEG */ #undef NEG16 #define NEG16(v) ((uint32_t)(((~(v)) + 1) & 0xFFFF)) #define MIPS64_PRACC_ADDR_STEP 4 #define MIPS64_PRACC_DATA_STEP 8 int mips64_pracc_read_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned size, unsigned count, void *buf); int mips64_pracc_write_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned size, unsigned count, void *buf); int mips64_pracc_read_regs(struct mips_ejtag *ejtag_info, uint64_t *regs); int mips64_pracc_write_regs(struct mips_ejtag *ejtag_info, uint64_t *regs); int mips64_pracc_exec(struct mips_ejtag *ejtag_info, unsigned code_len, const uint32_t *code, unsigned num_param_in, uint64_t *param_in, unsigned num_param_out, uint64_t *param_out); int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source, bool write_t, uint64_t addr, unsigned count, uint64_t *buf); #endif /* OPENOCD_TARGET_MIPS64_PRACC_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips_ejtag.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2009 by David N. Claffey <dnclaffey@gmail.com> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "mips32.h" #include "mips_ejtag.h" #include "mips32_dmaacc.h" #include "mips64.h" #include "mips64_pracc.h" void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr) { assert(ejtag_info->tap); struct jtag_tap *tap = ejtag_info->tap; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; field.num_bits = tap->ir_length; uint8_t t[4] = { 0 }; field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); } } int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info) { mips_ejtag_set_instr(ejtag_info, EJTAG_INST_IDCODE); ejtag_info->idcode = 0; return mips_ejtag_drscan_32(ejtag_info, &ejtag_info->idcode); } static int mips_ejtag_get_impcode(struct mips_ejtag *ejtag_info) { mips_ejtag_set_instr(ejtag_info, EJTAG_INST_IMPCODE); ejtag_info->impcode = 0; return mips_ejtag_drscan_32(ejtag_info, &ejtag_info->impcode); } void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32_t data, uint8_t *in_scan_buf) { assert(ejtag_info->tap); struct jtag_tap *tap = ejtag_info->tap; struct scan_field field; uint8_t out_scan[12]; /* processor access "all" register 96 bit */ field.num_bits = 96; field.out_value = out_scan; buf_set_u32(out_scan, 0, 32, ctrl); buf_set_u32(out_scan + 4, 0, 32, data); buf_set_u32(out_scan + 8, 0, 32, 0); field.in_value = in_scan_buf; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); keep_alive(); } int mips_ejtag_drscan_64(struct mips_ejtag *ejtag_info, uint64_t *data) { struct jtag_tap *tap; tap = ejtag_info->tap; if (!tap) return ERROR_FAIL; struct scan_field field; uint8_t t[8] = { 0 }, r[8]; int retval; field.num_bits = 64; field.out_value = t; buf_set_u64(t, 0, field.num_bits, *data); field.in_value = r; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("register read failed"); return retval; } *data = buf_get_u64(field.in_value, 0, 64); keep_alive(); return ERROR_OK; } static void mips_ejtag_drscan_32_queued(struct mips_ejtag *ejtag_info, uint32_t data_out, uint8_t *data_in) { assert(ejtag_info->tap); struct jtag_tap *tap = ejtag_info->tap; struct scan_field field; field.num_bits = 32; uint8_t scan_out[4] = { 0 }; field.out_value = scan_out; buf_set_u32(scan_out, 0, field.num_bits, data_out); field.in_value = data_in; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); keep_alive(); } int mips_ejtag_drscan_32(struct mips_ejtag *ejtag_info, uint32_t *data) { uint8_t scan_in[4]; mips_ejtag_drscan_32_queued(ejtag_info, *data, scan_in); int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("register read failed"); return retval; } *data = buf_get_u32(scan_in, 0, 32); return ERROR_OK; } void mips_ejtag_drscan_32_out(struct mips_ejtag *ejtag_info, uint32_t data) { mips_ejtag_drscan_32_queued(ejtag_info, data, NULL); } int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint8_t *data) { assert(ejtag_info->tap); struct jtag_tap *tap = ejtag_info->tap; struct scan_field field; field.num_bits = 8; field.out_value = data; field.in_value = data; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("register read failed"); return retval; } return ERROR_OK; } void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data) { assert(ejtag_info->tap); struct jtag_tap *tap = ejtag_info->tap; struct scan_field field; field.num_bits = 8; field.out_value = &data; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); } /* Set (to enable) or clear (to disable stepping) the SSt bit (bit 8) in Cp0 Debug reg (reg 23, sel 0) */ int mips_ejtag_config_step(struct mips_ejtag *ejtag_info, int enable_step) { struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 8, 23, 0)); /* move COP0 Debug to $8 */ pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 8, 8, 0x0100)); /* set SSt bit in debug reg */ if (!enable_step) pracc_add(&ctx, 0, MIPS32_XORI(ctx.isa, 8, 8, 0x0100)); /* clear SSt bit in debug reg */ pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 8, 23, 0)); /* move $8 to COP0 Debug */ pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */ pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); pracc_queue_free(&ctx); return ctx.retval; } /* * Disable memory protection for 0xFF20.0000–0xFF3F.FFFF * It is needed by EJTAG 1.5-2.0, especially for BMIPS CPUs * For example bcm7401 and others. At leas on some * CPUs, DebugMode wont start if this bit is not removed. */ static int disable_dcr_mp(struct mips_ejtag *ejtag_info) { uint32_t dcr; int retval; retval = mips32_dmaacc_read_mem(ejtag_info, EJTAG_DCR, 4, 1, &dcr); if (retval != ERROR_OK) goto error; dcr &= ~EJTAG_DCR_MP; retval = mips32_dmaacc_write_mem(ejtag_info, EJTAG_DCR, 4, 1, &dcr); if (retval != ERROR_OK) goto error; return ERROR_OK; error: LOG_ERROR("Failed to remove DCR MPbit!"); return retval; } int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info) { uint32_t ejtag_ctrl; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); if (ejtag_info->ejtag_version == EJTAG_VERSION_20) { if (disable_dcr_mp(ejtag_info) != ERROR_OK) goto error; } /* set debug break bit */ ejtag_ctrl = ejtag_info->ejtag_ctrl | EJTAG_CTRL_JTAGBRK; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* break bit will be cleared by hardware */ ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); LOG_DEBUG("ejtag_ctrl: 0x%8.8" PRIx32 "", ejtag_ctrl); if ((ejtag_ctrl & EJTAG_CTRL_BRKST) == 0) goto error; return ERROR_OK; error: LOG_ERROR("Failed to enter Debug Mode!"); return ERROR_FAIL; } int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info) { struct pa_list pracc_list = {.instr = MIPS32_DRET(ejtag_info->isa), .addr = 0}; struct pracc_queue_info ctx = {.max_code = 1, .pracc_list = &pracc_list, .code_count = 1, .store_count = 0}; /* execute our dret instruction */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 0); /* shift out instr, omit last check */ /* pic32mx workaround, false pending at low core clock */ jtag_add_sleep(1000); return ctx.retval; } /* mips_ejtag_init_mmr - assign Memory-Mapped Registers depending * on EJTAG version. */ static void mips_ejtag_init_mmr(struct mips_ejtag *ejtag_info) { if (ejtag_info->ejtag_version == EJTAG_VERSION_20) { ejtag_info->ejtag_ibs_addr = EJTAG_V20_IBS; ejtag_info->ejtag_iba0_addr = EJTAG_V20_IBA0; ejtag_info->ejtag_ibc_offs = EJTAG_V20_IBC_OFFS; ejtag_info->ejtag_ibm_offs = EJTAG_V20_IBM_OFFS; ejtag_info->ejtag_dbs_addr = EJTAG_V20_DBS; ejtag_info->ejtag_dba0_addr = EJTAG_V20_DBA0; ejtag_info->ejtag_dbc_offs = EJTAG_V20_DBC_OFFS; ejtag_info->ejtag_dbm_offs = EJTAG_V20_DBM_OFFS; ejtag_info->ejtag_dbv_offs = EJTAG_V20_DBV_OFFS; ejtag_info->ejtag_iba_step_size = EJTAG_V20_IBAN_STEP; ejtag_info->ejtag_dba_step_size = EJTAG_V20_DBAN_STEP; } else { ejtag_info->ejtag_ibs_addr = EJTAG_V25_IBS; ejtag_info->ejtag_iba0_addr = EJTAG_V25_IBA0; ejtag_info->ejtag_ibm_offs = EJTAG_V25_IBM_OFFS; ejtag_info->ejtag_ibasid_offs = EJTAG_V25_IBASID_OFFS; ejtag_info->ejtag_ibc_offs = EJTAG_V25_IBC_OFFS; ejtag_info->ejtag_dbs_addr = EJTAG_V25_DBS; ejtag_info->ejtag_dba0_addr = EJTAG_V25_DBA0; ejtag_info->ejtag_dbm_offs = EJTAG_V25_DBM_OFFS; ejtag_info->ejtag_dbasid_offs = EJTAG_V25_DBASID_OFFS; ejtag_info->ejtag_dbc_offs = EJTAG_V25_DBC_OFFS; ejtag_info->ejtag_dbv_offs = EJTAG_V25_DBV_OFFS; ejtag_info->ejtag_iba_step_size = EJTAG_V25_IBAN_STEP; ejtag_info->ejtag_dba_step_size = EJTAG_V25_DBAN_STEP; } } static void ejtag_v20_print_imp(struct mips_ejtag *ejtag_info) { LOG_DEBUG("EJTAG v2.0: features:%s%s%s%s%s%s%s%s", EJTAG_IMP_HAS(EJTAG_V20_IMP_SDBBP) ? " SDBBP_SPECIAL2" : " SDBBP", EJTAG_IMP_HAS(EJTAG_V20_IMP_EADDR_NO32BIT) ? " EADDR>32bit" : " EADDR=32bit", EJTAG_IMP_HAS(EJTAG_V20_IMP_COMPLEX_BREAK) ? " COMPLEX_BREAK" : "", EJTAG_IMP_HAS(EJTAG_V20_IMP_DCACHE_COH) ? " DCACHE_COH" : " DCACHE_NOT_COH", EJTAG_IMP_HAS(EJTAG_V20_IMP_ICACHE_COH) ? " ICACHE_COH" : " ICACHE_NOT_COH", EJTAG_IMP_HAS(EJTAG_V20_IMP_NOPB) ? " noPB" : " PB", EJTAG_IMP_HAS(EJTAG_V20_IMP_NODB) ? " noDB" : " DB", EJTAG_IMP_HAS(EJTAG_V20_IMP_NOIB) ? " noIB" : " IB"); LOG_DEBUG("EJTAG v2.0: Break Channels: %" PRIu8, (uint8_t)((ejtag_info->impcode >> EJTAG_V20_IMP_BCHANNELS_SHIFT) & EJTAG_V20_IMP_BCHANNELS_MASK)); } static void ejtag_v26_print_imp(struct mips_ejtag *ejtag_info) { LOG_DEBUG("EJTAG v2.6: features:%s%s", EJTAG_IMP_HAS(EJTAG_V26_IMP_R3K) ? " R3k" : " R4k", EJTAG_IMP_HAS(EJTAG_V26_IMP_DINT) ? " DINT" : ""); } static void ejtag_main_print_imp(struct mips_ejtag *ejtag_info) { LOG_DEBUG("EJTAG main: features:%s%s%s%s%s", EJTAG_IMP_HAS(EJTAG_IMP_ASID8) ? " ASID_8" : "", EJTAG_IMP_HAS(EJTAG_IMP_ASID6) ? " ASID_6" : "", EJTAG_IMP_HAS(EJTAG_IMP_MIPS16) ? " MIPS16" : "", EJTAG_IMP_HAS(EJTAG_IMP_NODMA) ? " noDMA" : " DMA", EJTAG_IMP_HAS(EJTAG_IMP_MIPS64) ? " MIPS64" : " MIPS32"); switch (ejtag_info->ejtag_version) { case EJTAG_VERSION_20: ejtag_v20_print_imp(ejtag_info); break; case EJTAG_VERSION_25: case EJTAG_VERSION_26: case EJTAG_VERSION_31: case EJTAG_VERSION_41: case EJTAG_VERSION_51: ejtag_v26_print_imp(ejtag_info); break; default: break; } } int mips_ejtag_init(struct mips_ejtag *ejtag_info) { int retval = mips_ejtag_get_impcode(ejtag_info); if (retval != ERROR_OK) { LOG_ERROR("impcode read failed"); return retval; } /* get ejtag version */ ejtag_info->ejtag_version = ((ejtag_info->impcode >> 29) & 0x07); switch (ejtag_info->ejtag_version) { case EJTAG_VERSION_20: LOG_DEBUG("EJTAG: Version 1 or 2.0 Detected"); break; case EJTAG_VERSION_25: LOG_DEBUG("EJTAG: Version 2.5 Detected"); break; case EJTAG_VERSION_26: LOG_DEBUG("EJTAG: Version 2.6 Detected"); break; case EJTAG_VERSION_31: LOG_DEBUG("EJTAG: Version 3.1 Detected"); break; case EJTAG_VERSION_41: LOG_DEBUG("EJTAG: Version 4.1 Detected"); break; case EJTAG_VERSION_51: LOG_DEBUG("EJTAG: Version 5.1 Detected"); break; default: LOG_DEBUG("EJTAG: Unknown Version Detected"); break; } ejtag_main_print_imp(ejtag_info); if ((ejtag_info->impcode & EJTAG_IMP_NODMA) == 0) { LOG_DEBUG("EJTAG: DMA Access Mode detected. Disabling to " "workaround current broken code."); ejtag_info->impcode |= EJTAG_IMP_NODMA; } ejtag_info->ejtag_ctrl = EJTAG_CTRL_PRACC | EJTAG_CTRL_PROBEN; if (ejtag_info->ejtag_version != EJTAG_VERSION_20) ejtag_info->ejtag_ctrl |= EJTAG_CTRL_ROCC | EJTAG_CTRL_SETDEV; ejtag_info->fast_access_save = -1; mips_ejtag_init_mmr(ejtag_info); return ERROR_OK; } int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_t *data) { assert(ejtag_info->tap); struct jtag_tap *tap = ejtag_info->tap; struct scan_field fields[2]; /* fastdata 1-bit register */ fields[0].num_bits = 1; uint8_t spracc = 0; fields[0].out_value = &spracc; fields[0].in_value = NULL; /* processor access data register 32 bit */ fields[1].num_bits = 32; uint8_t t[4] = {0, 0, 0, 0}; fields[1].out_value = t; if (write_t) { fields[1].in_value = NULL; buf_set_u32(t, 0, 32, *data); } else fields[1].in_value = (uint8_t *) data; jtag_add_dr_scan(tap, 2, fields, TAP_IDLE); if (!write_t && data) jtag_add_callback(mips_le_to_h_u32, (jtag_callback_data_t) data); keep_alive(); return ERROR_OK; } int mips64_ejtag_config_step(struct mips_ejtag *ejtag_info, bool enable_step) { const uint32_t code_enable[] = { MIPS64_MTC0(1, 31, 0), /* move $1 to COP0 DeSave */ MIPS64_MFC0(1, 23, 0), /* move COP0 Debug to $1 */ MIPS64_ORI(1, 1, 0x0100), /* set SSt bit in debug reg */ MIPS64_MTC0(1, 23, 0), /* move $1 to COP0 Debug */ MIPS64_B(NEG16(5)), MIPS64_MFC0(1, 31, 0), /* move COP0 DeSave to $1 */ MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, }; const uint32_t code_disable[] = { MIPS64_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */ MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), /* $15 = MIPS64_PRACC_STACK */ MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), MIPS64_SD(1, 0, 15), /* sw $1,($15) */ MIPS64_SD(2, 0, 15), /* sw $2,($15) */ MIPS64_MFC0(1, 23, 0), /* move COP0 Debug to $1 */ MIPS64_LUI(2, 0xFFFF), /* $2 = 0xfffffeff */ MIPS64_ORI(2, 2, 0xFEFF), MIPS64_AND(1, 1, 2), MIPS64_MTC0(1, 23, 0), /* move $1 to COP0 Debug */ MIPS64_LD(2, 0, 15), MIPS64_LD(1, 0, 15), MIPS64_SYNC, MIPS64_B(NEG16(14)), MIPS64_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */ MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, }; const uint32_t *code = enable_step ? code_enable : code_disable; unsigned code_len = enable_step ? ARRAY_SIZE(code_enable) : ARRAY_SIZE(code_disable); return mips64_pracc_exec(ejtag_info, code_len, code, 0, NULL, 0, NULL); } int mips64_ejtag_exit_debug(struct mips_ejtag *ejtag_info) { const uint32_t code[] = { MIPS64_DRET, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, MIPS64_NOP, }; LOG_DEBUG("enter mips64_pracc_exec"); return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 0, NULL, 0, NULL); } int mips64_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, bool write_t, uint64_t *data) { struct jtag_tap *tap; tap = ejtag_info->tap; assert(tap); struct scan_field fields[2]; uint8_t spracc = 0; uint8_t t[8] = {0, 0, 0, 0, 0, 0, 0, 0}; /* fastdata 1-bit register */ fields[0].num_bits = 1; fields[0].out_value = &spracc; fields[0].in_value = NULL; /* processor access data register 64 bit */ fields[1].num_bits = 64; fields[1].out_value = t; if (write_t) { fields[1].in_value = NULL; buf_set_u64(t, 0, 64, *data); } else fields[1].in_value = (uint8_t *) data; jtag_add_dr_scan(tap, 2, fields, TAP_IDLE); if (!write_t && data) jtag_add_callback(mips_le_to_h_u64, (jtag_callback_data_t) data); keep_alive(); return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips_ejtag.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * ***************************************************************************/ #ifndef OPENOCD_TARGET_MIPS_EJTAG_H #define OPENOCD_TARGET_MIPS_EJTAG_H #include <jtag/jtag.h> /* tap instructions */ #define EJTAG_INST_IDCODE 0x01 #define EJTAG_INST_IMPCODE 0x03 #define EJTAG_INST_ADDRESS 0x08 #define EJTAG_INST_DATA 0x09 #define EJTAG_INST_CONTROL 0x0A #define EJTAG_INST_ALL 0x0B #define EJTAG_INST_EJTAGBOOT 0x0C #define EJTAG_INST_NORMALBOOT 0x0D #define EJTAG_INST_FASTDATA 0x0E #define EJTAG_INST_TCBCONTROLA 0x10 #define EJTAG_INST_TCBCONTROLB 0x11 #define EJTAG_INST_TCBDATA 0x12 #define EJTAG_INST_TCBCONTROLC 0x13 #define EJTAG_INST_PCSAMPLE 0x14 #define EJTAG_INST_TCBCONTROLD 0x15 #define EJTAG_INST_TCBCONTROLE 0x16 #define EJTAG_INST_FDC 0x17 #define EJTAG_INST_BYPASS 0xFF /* microchip PIC32MX specific instructions */ #define MTAP_SW_MTAP 0x04 #define MTAP_SW_ETAP 0x05 #define MTAP_COMMAND 0x07 /* microchip specific cmds */ #define MCHP_ASERT_RST 0xd1 #define MCHP_DE_ASSERT_RST 0xd0 #define MCHP_ERASE 0xfc #define MCHP_STATUS 0x00 /* ejtag control register bits ECR */ #define EJTAG_CTRL_TOF (1 << 1) #define EJTAG_CTRL_TIF (1 << 2) #define EJTAG_CTRL_BRKST (1 << 3) #define EJTAG_CTRL_DLOCK (1 << 5) #define EJTAG_CTRL_DRWN (1 << 9) #define EJTAG_CTRL_DERR (1 << 10) #define EJTAG_CTRL_DSTRT (1 << 11) #define EJTAG_CTRL_JTAGBRK (1 << 12) #define EJTAG_CTRL_DBGISA (1 << 13) #define EJTAG_CTRL_SETDEV (1 << 14) #define EJTAG_CTRL_PROBEN (1 << 15) #define EJTAG_CTRL_PRRST (1 << 16) #define EJTAG_CTRL_DMAACC (1 << 17) #define EJTAG_CTRL_PRACC (1 << 18) #define EJTAG_CTRL_PRNW (1 << 19) #define EJTAG_CTRL_PERRST (1 << 20) #define EJTAG_CTRL_SYNC (1 << 23) #define EJTAG_CTRL_DNM (1 << 28) #define EJTAG_CTRL_ROCC (1 << 31) /* Debug Register (CP0 Register 23, Select 0) */ #define EJTAG_DEBUG_DSS (1 << 0) #define EJTAG_DEBUG_DBP (1 << 1) #define EJTAG_DEBUG_DDBL (1 << 2) #define EJTAG_DEBUG_DDBS (1 << 3) #define EJTAG_DEBUG_DIB (1 << 4) #define EJTAG_DEBUG_DINT (1 << 5) #define EJTAG_DEBUG_OFFLINE (1 << 7) #define EJTAG_DEBUG_SST (1 << 8) #define EJTAG_DEBUG_NOSST (1 << 9) #define EJTAG_DEBUG_DDBLIMPR (1 << 18) #define EJTAG_DEBUG_DDBSIMPR (1 << 19) #define EJTAG_DEBUG_IEXI (1 << 20) #define EJTAG_DEBUG_DBUSEP (1 << 21) #define EJTAG_DEBUG_CACHEEP (1 << 22) #define EJTAG_DEBUG_MCHECKP (1 << 23) #define EJTAG_DEBUG_IBUSEP (1 << 24) #define EJTAG_DEBUG_COUNTDM (1 << 25) #define EJTAG_DEBUG_HALT (1 << 26) #define EJTAG_DEBUG_DOZE (1 << 27) #define EJTAG_DEBUG_LSNM (1 << 28) #define EJTAG_DEBUG_NODCR (1 << 29) #define EJTAG_DEBUG_DM (1 << 30) #define EJTAG_DEBUG_DBD (1 << 31) /* implementation MIPS register bits. * Bits marked with V20 or v2.0 mean that, this registers supported only * by EJTAG v2.0. Bits marked with Lexra or BMIPS are different from the * official EJATG. * NOTE: Lexra or BMIPS use EJTAG v2.0 */ #define EJTAG_IMP_HAS(x) (ejtag_info->impcode & (x)) /* v2.0(Lexra) 29 - 1’b1 - Lexra Internal Trace Buffer implemented. This bit * overlaps with version bit of MIPS EJTAG specification. */ #define EJTAG_V26_IMP_R3K (1 << 28) /* v2.0 - 24:25 - 2’b00- No profiling support */ #define EJTAG_V26_IMP_DINT (1 << 24) #define EJTAG_V20_IMP_SDBBP (1 << 23) /* 1’b1 - sdbbp is Special2 Opcode */ #define EJTAG_IMP_ASID8 (1 << 22) #define EJTAG_IMP_ASID6 (1 << 21) #define EJTAG_V20_IMP_COMPLEX_BREAK (1 << 20) /* Complex Breaks supported*/ #define EJTAG_V20_IMP_EADDR_NO32BIT (1 << 19) /* EJTAG_ADDR > 32 bits wide */ #define EJTAG_V20_IMP_DCACHE_COH (1 << 18) /* DCache does keep DMA coherent */ #define EJTAG_V20_IMP_ICACHE_COH (1 << 17) /* DCache does keep DMA coherent */ #define EJTAG_IMP_MIPS16 (1 << 16) #define EJTAG_IMP_NODMA (1 << 14) /* v2.0 - 11:13 external PC trace. Trace PC Width. */ /* v2.0 - 8:10 external PC trace. PCST Width and DCLK Division Factor */ #define EJTAG_V20_IMP_NOPB (1 << 7) /* no processor breaks */ #define EJTAG_V20_IMP_NODB (1 << 6) /* no data breaks */ #define EJTAG_V20_IMP_NOIB (1 << 5) /* no instruction breaks implemented */ /* v2.0 - 1:4 Number of Break Channels. */ #define EJTAG_V20_IMP_BCHANNELS_MASK 0xf #define EJTAG_V20_IMP_BCHANNELS_SHIFT 1 #define EJTAG_IMP_MIPS64 (1 << 0) /* Debug Control Register DCR */ #define EJTAG_DCR 0xFF300000 #define EJTAG_DCR_ENM (1 << 29) #define EJTAG_DCR_DB (1 << 17) #define EJTAG_DCR_IB (1 << 16) #define EJTAG_DCR_INTE (1 << 4) #define EJTAG_DCR_MP (1 << 2) /* breakpoint support */ /* EJTAG_V20_* was tested on Broadcom BCM7401 * and may or will differ with other hardware. For example EZ4021-FC. */ #define EJTAG_V20_IBS 0xFF300004 #define EJTAG_V20_IBA0 0xFF300100 #define EJTAG_V20_IBC_OFFS 0x4 /* IBC Offset */ #define EJTAG_V20_IBM_OFFS 0x8 #define EJTAG_V20_IBAN_STEP 0x10 /* Offset for next channel */ #define EJTAG_V20_DBS 0xFF300008 #define EJTAG_V20_DBA0 0xFF300200 #define EJTAG_V20_DBC_OFFS 0x4 #define EJTAG_V20_DBM_OFFS 0x8 #define EJTAG_V20_DBV_OFFS 0xc #define EJTAG_V20_DBAN_STEP 0x10 #define EJTAG_V25_IBS 0xFF301000 #define EJTAG_V25_IBA0 0xFF301100 #define EJTAG_V25_IBM_OFFS 0x8 #define EJTAG_V25_IBASID_OFFS 0x10 #define EJTAG_V25_IBC_OFFS 0x18 #define EJTAG_V25_IBAN_STEP 0x100 #define EJTAG_V25_DBS 0xFF302000 #define EJTAG_V25_DBA0 0xFF302100 #define EJTAG_V25_DBM_OFFS 0x8 #define EJTAG_V25_DBASID_OFFS 0x10 #define EJTAG_V25_DBC_OFFS 0x18 #define EJTAG_V25_DBV_OFFS 0x20 #define EJTAG_V25_DBAN_STEP 0x100 #define EJTAG_DBCN_NOSB (1 << 13) #define EJTAG_DBCN_NOLB (1 << 12) #define EJTAG_DBCN_BLM_MASK 0xff #define EJTAG_DBCN_BLM_SHIFT 4 #define EJTAG_DBCN_BE (1 << 0) #define EJTAG_VERSION_20 0 #define EJTAG_VERSION_25 1 #define EJTAG_VERSION_26 2 #define EJTAG_VERSION_31 3 #define EJTAG_VERSION_41 4 #define EJTAG_VERSION_51 5 /* * Additional defines for MIPS64 EJTAG */ #define EJTAG64_DCR 0xFFFFFFFFFF300000ull #define EJTAG64_DCR_ENM (1llu << 29) #define EJTAG64_DCR_DB (1llu << 17) #define EJTAG64_DCR_IB (1llu << 16) #define EJTAG64_DCR_INTE (1llu << 4) #define EJTAG64_DCR_MP (1llu << 2) #define EJTAG64_V25_DBA0 0xFFFFFFFFFF302100ull #define EJTAG64_V25_DBS 0xFFFFFFFFFF302000ull #define EJTAG64_V25_IBA0 0xFFFFFFFFFF301100ull #define EJTAG64_V25_IBS 0xFFFFFFFFFF301000ull struct mips_ejtag { struct jtag_tap *tap; uint32_t impcode; uint32_t idcode; uint32_t ejtag_ctrl; int fast_access_save; uint32_t config_regs; /* number of config registers read */ uint32_t config[4]; /* cp0 config to config3 */ uint32_t reg8; uint32_t reg9; unsigned scan_delay; int mode; uint32_t pa_ctrl; uint32_t pa_addr; unsigned int ejtag_version; uint32_t isa; uint32_t endianness; /* Memory-Mapped Registers. This addresses are not same on different * EJTAG versions. */ uint32_t debug_caps; uint32_t ejtag_ibs_addr; /* Instruction Address Break Status */ uint32_t ejtag_iba0_addr; /* IAB channel 0 */ uint32_t ejtag_ibc_offs; /* IAB Control offset */ uint32_t ejtag_ibm_offs; /* IAB Mask offset */ uint32_t ejtag_ibasid_offs; /* IAB ASID (4Kc) */ uint32_t ejtag_dbs_addr; /* Data Address Break Status Register */ uint32_t ejtag_dba0_addr; /* DAB channel 0 */ uint32_t ejtag_dbc_offs; /* DAB Control offset */ uint32_t ejtag_dbm_offs; /* DAB Mask offset */ uint32_t ejtag_dbv_offs; /* DAB Value offset */ uint32_t ejtag_dbasid_offs; /* DAB ASID (4Kc) */ uint32_t ejtag_iba_step_size; uint32_t ejtag_dba_step_size; /* size of step till next *DBAn register. */ }; void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr); int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info); int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info); int mips64_ejtag_exit_debug(struct mips_ejtag *ejtag_info); int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info); void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32_t data, uint8_t *in_scan_buf); int mips_ejtag_drscan_64(struct mips_ejtag *ejtag_info, uint64_t *data); void mips_ejtag_drscan_32_out(struct mips_ejtag *ejtag_info, uint32_t data); int mips_ejtag_drscan_32(struct mips_ejtag *ejtag_info, uint32_t *data); void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data); int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint8_t *data); int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_t *data); int mips64_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, bool write_t, uint64_t *data); int mips_ejtag_init(struct mips_ejtag *ejtag_info); int mips_ejtag_config_step(struct mips_ejtag *ejtag_info, int enable_step); int mips64_ejtag_config_step(struct mips_ejtag *ejtag_info, bool enable_step); static inline void mips_le_to_h_u32(jtag_callback_data_t arg) { uint8_t *in = (uint8_t *)arg; *((uint32_t *)arg) = le_to_h_u32(in); } static inline void mips_le_to_h_u64(jtag_callback_data_t arg) { uint8_t *in = (uint8_t *)arg; *((uint64_t *)arg) = le_to_h_u64(in); } #endif /* OPENOCD_TARGET_MIPS_EJTAG_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips_m4k.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2009 by David N. Claffey <dnclaffey@gmail.com> * * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "breakpoints.h" #include "mips32.h" #include "mips_m4k.h" #include "mips32_dmaacc.h" #include "target_type.h" #include "register.h" #include "smp.h" static void mips_m4k_enable_breakpoints(struct target *target); static void mips_m4k_enable_watchpoints(struct target *target); static int mips_m4k_set_breakpoint(struct target *target, struct breakpoint *breakpoint); static int mips_m4k_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); static int mips_m4k_internal_restore(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); static int mips_m4k_halt(struct target *target); static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer); static int mips_m4k_bulk_read_memory(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer); static int mips_m4k_examine_debug_reason(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; uint32_t break_status; int retval; if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) { if (ejtag_info->debug_caps & EJTAG_DCR_IB) { /* get info about inst breakpoint support */ retval = target_read_u32(target, ejtag_info->ejtag_ibs_addr, &break_status); if (retval != ERROR_OK) return retval; if (break_status & 0x1f) { /* we have halted on a breakpoint */ retval = target_write_u32(target, ejtag_info->ejtag_ibs_addr, 0); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_BREAKPOINT; } } if (ejtag_info->debug_caps & EJTAG_DCR_DB) { /* get info about data breakpoint support */ retval = target_read_u32(target, ejtag_info->ejtag_dbs_addr, &break_status); if (retval != ERROR_OK) return retval; if (break_status & 0x1f) { /* we have halted on a breakpoint */ retval = target_write_u32(target, ejtag_info->ejtag_dbs_addr, 0); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_WATCHPOINT; } } } return ERROR_OK; } static int mips_m4k_debug_entry(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; mips32_save_context(target); /* make sure stepping disabled, SSt bit in CP0 debug register cleared */ mips_ejtag_config_step(ejtag_info, 0); /* make sure break unit configured */ mips32_configure_break_unit(target); /* attempt to find halt reason */ mips_m4k_examine_debug_reason(target); mips32_read_config_regs(target); /* default to mips32 isa, it will be changed below if required */ mips32->isa_mode = MIPS32_ISA_MIPS32; /* other than mips32 only and isa bit set ? */ if (mips32->isa_imp && buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1)) mips32->isa_mode = mips32->isa_imp == 2 ? MIPS32_ISA_MIPS16E : MIPS32_ISA_MMIPS32; LOG_DEBUG("entered debug state at PC 0x%" PRIx32 ", target->state: %s", buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32), target_state_name(target)); return ERROR_OK; } static struct target *get_mips_m4k(struct target *target, int32_t coreid) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) return curr; } return target; } static int mips_m4k_halt_smp(struct target *target) { int retval = ERROR_OK; struct target_list *head; foreach_smp_target(head, target->smp_targets) { int ret = ERROR_OK; struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_HALTED)) ret = mips_m4k_halt(curr); if (ret != ERROR_OK) { LOG_ERROR("halt failed target->coreid: %" PRId32, curr->coreid); retval = ret; } } return retval; } static int update_halt_gdb(struct target *target) { int retval = ERROR_OK; if (target->gdb_service->core[0] == -1) { target->gdb_service->target = target; target->gdb_service->core[0] = target->coreid; retval = mips_m4k_halt_smp(target); } return retval; } static int mips_m4k_poll(struct target *target) { int retval = ERROR_OK; struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl; enum target_state prev_target_state = target->state; /* toggle to another core is done by gdb as follow */ /* maint packet J core_id */ /* continue */ /* the next polling trigger an halt event sent to gdb */ if ((target->state == TARGET_HALTED) && (target->smp) && (target->gdb_service) && (!target->gdb_service->target)) { target->gdb_service->target = get_mips_m4k(target, target->gdb_service->core[1]); target_call_event_callbacks(target, TARGET_EVENT_HALTED); return retval; } /* read ejtag control reg */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (retval != ERROR_OK) return retval; ejtag_info->isa = (ejtag_ctrl & EJTAG_CTRL_DBGISA) ? 1 : 0; /* clear this bit before handling polling * as after reset registers will read zero */ if (ejtag_ctrl & EJTAG_CTRL_ROCC) { /* we have detected a reset, clear flag * otherwise ejtag will not work */ ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_ROCC; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (retval != ERROR_OK) return retval; LOG_DEBUG("Reset Detected"); } /* check for processor halted */ if (ejtag_ctrl & EJTAG_CTRL_BRKST) { if ((target->state != TARGET_HALTED) && (target->state != TARGET_DEBUG_RUNNING)) { if (target->state == TARGET_UNKNOWN) LOG_DEBUG("EJTAG_CTRL_BRKST already set during server startup."); /* OpenOCD was was probably started on the board with EJTAG_CTRL_BRKST already set * (maybe put on by HALT-ing the board in the previous session). * * Force enable debug entry for this session. */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT); target->state = TARGET_HALTED; retval = mips_m4k_debug_entry(target); if (retval != ERROR_OK) return retval; if (target->smp && ((prev_target_state == TARGET_RUNNING) || (prev_target_state == TARGET_RESET))) { retval = update_halt_gdb(target); if (retval != ERROR_OK) return retval; } target_call_event_callbacks(target, TARGET_EVENT_HALTED); } else if (target->state == TARGET_DEBUG_RUNNING) { target->state = TARGET_HALTED; retval = mips_m4k_debug_entry(target); if (retval != ERROR_OK) return retval; if (target->smp) { retval = update_halt_gdb(target); if (retval != ERROR_OK) return retval; } target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } } else target->state = TARGET_RUNNING; /* LOG_DEBUG("ctrl = 0x%08X", ejtag_ctrl); */ return ERROR_OK; } static int mips_m4k_halt(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); if (target->state == TARGET_RESET) { if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST"); return ERROR_TARGET_FAILURE; } else { /* we came here in a reset_halt or reset_init sequence * debug entry was already prepared in mips_m4k_assert_reset() */ target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } } /* break processor */ mips_ejtag_enter_debug(ejtag_info); target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int mips_m4k_assert_reset(struct target *target) { struct mips_m4k_common *mips_m4k = target_to_m4k(target); struct mips_ejtag *ejtag_info = &mips_m4k->mips32.ejtag_info; /* TODO: apply hw reset signal in not examined state */ if (!(target_was_examined(target))) { LOG_WARNING("Reset is not asserted because the target is not examined."); LOG_WARNING("Use a reset button or power cycle the target."); return ERROR_TARGET_NOT_EXAMINED; } LOG_DEBUG("target->state: %s", target_state_name(target)); enum reset_types jtag_reset_config = jtag_get_reset_config(); /* some cores support connecting while srst is asserted * use that mode is it has been configured */ bool srst_asserted = false; if (!(jtag_reset_config & RESET_SRST_PULLS_TRST) && (jtag_reset_config & RESET_SRST_NO_GATING)) { jtag_add_reset(0, 1); srst_asserted = true; } /* EJTAG before v2.5/2.6 does not support EJTAGBOOT or NORMALBOOT */ if (ejtag_info->ejtag_version != EJTAG_VERSION_20) { if (target->reset_halt) { /* use hardware to catch reset */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_EJTAGBOOT); } else mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT); } if (jtag_reset_config & RESET_HAS_SRST) { /* here we should issue a srst only, but we may have to assert trst as well */ if (jtag_reset_config & RESET_SRST_PULLS_TRST) jtag_add_reset(1, 1); else if (!srst_asserted) jtag_add_reset(0, 1); } else if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) { target_handle_event(target, TARGET_EVENT_RESET_ASSERT); } else { if (mips_m4k->is_pic32mx) { LOG_DEBUG("Using MTAP reset to reset processor..."); /* use microchip specific MTAP reset */ mips_ejtag_set_instr(ejtag_info, MTAP_SW_MTAP); mips_ejtag_set_instr(ejtag_info, MTAP_COMMAND); mips_ejtag_drscan_8_out(ejtag_info, MCHP_ASERT_RST); mips_ejtag_drscan_8_out(ejtag_info, MCHP_DE_ASSERT_RST); mips_ejtag_set_instr(ejtag_info, MTAP_SW_ETAP); } else { /* use ejtag reset - not supported by all cores */ uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl | EJTAG_CTRL_PRRST | EJTAG_CTRL_PERRST; LOG_DEBUG("Using EJTAG reset (PRRST) to reset processor..."); mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); mips_ejtag_drscan_32_out(ejtag_info, ejtag_ctrl); } } target->state = TARGET_RESET; jtag_add_sleep(50000); register_cache_invalidate(mips_m4k->mips32.core_cache); if (target->reset_halt) { int retval = target_halt(target); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int mips_m4k_deassert_reset(struct target *target) { LOG_DEBUG("target->state: %s", target_state_name(target)); /* deassert reset lines */ jtag_add_reset(0, 0); return ERROR_OK; } static int mips_m4k_single_step_core(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; /* configure single step mode */ mips_ejtag_config_step(ejtag_info, 1); /* disable interrupts while stepping */ mips32_enable_interrupts(target, 0); /* exit debug mode */ mips_ejtag_exit_debug(ejtag_info); mips_m4k_debug_entry(target); return ERROR_OK; } static int mips_m4k_restore_smp(struct target *target, uint32_t address, int handle_breakpoints) { int retval = ERROR_OK; struct target_list *head; foreach_smp_target(head, target->smp_targets) { int ret = ERROR_OK; struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_RUNNING)) { /* resume current address , not in step mode */ ret = mips_m4k_internal_restore(curr, 1, address, handle_breakpoints, 0); if (ret != ERROR_OK) { LOG_ERROR("target->coreid :%" PRId32 " failed to resume at address :0x%" PRIx32, curr->coreid, address); retval = ret; } } } return retval; } static int mips_m4k_internal_restore(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct breakpoint *breakpoint = NULL; uint32_t resume_pc; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) { target_free_all_working_areas(target); mips_m4k_enable_breakpoints(target); mips_m4k_enable_watchpoints(target); } /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { mips_m4k_isa_filter(mips32->isa_imp, &address); buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address); mips32->core_cache->reg_list[MIPS32_PC].dirty = true; mips32->core_cache->reg_list[MIPS32_PC].valid = true; } if ((mips32->isa_imp > 1) && debug_execution) /* if more than one isa supported */ buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1, mips32->isa_mode); if (!current) resume_pc = address; else resume_pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32); mips32_restore_context(target); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT "", breakpoint->address); mips_m4k_unset_breakpoint(target, breakpoint); mips_m4k_single_step_core(target); mips_m4k_set_breakpoint(target, breakpoint); } } /* enable interrupts if we are running */ mips32_enable_interrupts(target, !debug_execution); /* exit debug mode */ mips_ejtag_exit_debug(ejtag_info); target->debug_reason = DBG_REASON_NOTHALTED; /* registers are now invalid */ register_cache_invalidate(mips32->core_cache); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); } return ERROR_OK; } static int mips_m4k_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { int retval = ERROR_OK; /* dummy resume for smp toggle in order to reduce gdb impact */ if ((target->smp) && (target->gdb_service->core[1] != -1)) { /* simulate a start and halt of target */ target->gdb_service->target = NULL; target->gdb_service->core[0] = target->gdb_service->core[1]; /* fake resume at next poll we play the target core[1], see poll*/ target_call_event_callbacks(target, TARGET_EVENT_RESUMED); return retval; } retval = mips_m4k_internal_restore(target, current, address, handle_breakpoints, debug_execution); if (retval == ERROR_OK && target->smp) { target->gdb_service->core[0] = -1; retval = mips_m4k_restore_smp(target, address, handle_breakpoints); } return retval; } static int mips_m4k_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct breakpoint *breakpoint = NULL; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { mips_m4k_isa_filter(mips32->isa_imp, &address); buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address); mips32->core_cache->reg_list[MIPS32_PC].dirty = true; mips32->core_cache->reg_list[MIPS32_PC].valid = true; } /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { breakpoint = breakpoint_find(target, buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32)); if (breakpoint) mips_m4k_unset_breakpoint(target, breakpoint); } /* restore context */ mips32_restore_context(target); /* configure single step mode */ mips_ejtag_config_step(ejtag_info, 1); target->debug_reason = DBG_REASON_SINGLESTEP; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); /* disable interrupts while stepping */ mips32_enable_interrupts(target, 0); /* exit debug mode */ mips_ejtag_exit_debug(ejtag_info); /* registers are now invalid */ register_cache_invalidate(mips32->core_cache); LOG_DEBUG("target stepped "); mips_m4k_debug_entry(target); if (breakpoint) mips_m4k_set_breakpoint(target, breakpoint); target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } static void mips_m4k_enable_breakpoints(struct target *target) { struct breakpoint *breakpoint = target->breakpoints; /* set any pending breakpoints */ while (breakpoint) { if (!breakpoint->is_set) mips_m4k_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } } static int mips_m4k_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct mips32_comparator *comparator_list = mips32->inst_break_list; int retval; if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { int bp_num = 0; while (comparator_list[bp_num].used && (bp_num < mips32->num_inst_bpoints)) bp_num++; if (bp_num >= mips32->num_inst_bpoints) { LOG_ERROR("Can not find free FP Comparator(bpid: %" PRIu32 ")", breakpoint->unique_id); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint_hw_set(breakpoint, bp_num); comparator_list[bp_num].used = 1; comparator_list[bp_num].bp_value = breakpoint->address; if (breakpoint->length != 4) /* make sure isa bit set */ comparator_list[bp_num].bp_value |= 1; else /* make sure isa bit cleared */ comparator_list[bp_num].bp_value &= ~1; /* EJTAG 2.0 uses 30bit IBA. First 2 bits are reserved. * Warning: there is no IB ASID registers in 2.0. * Do not set it! :) */ if (ejtag_info->ejtag_version == EJTAG_VERSION_20) comparator_list[bp_num].bp_value &= 0xFFFFFFFC; target_write_u32(target, comparator_list[bp_num].reg_address, comparator_list[bp_num].bp_value); target_write_u32(target, comparator_list[bp_num].reg_address + ejtag_info->ejtag_ibm_offs, 0x00000000); target_write_u32(target, comparator_list[bp_num].reg_address + ejtag_info->ejtag_ibc_offs, 1); LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx32 "", breakpoint->unique_id, bp_num, comparator_list[bp_num].bp_value); } else if (breakpoint->type == BKPT_SOFT) { LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); uint32_t isa_req = breakpoint->length & 1; /* micro mips request bit */ uint32_t bplength = breakpoint->length & ~1; /* drop micro mips request bit for length */ uint32_t bpaddr = breakpoint->address & ~1; /* drop isa bit from address, if set */ if (bplength == 4) { uint32_t verify = 0xffffffff; uint32_t sdbbp32_instr = MIPS32_SDBBP(isa_req); if (ejtag_info->endianness && isa_req) sdbbp32_instr = SWAP16(sdbbp32_instr); if ((breakpoint->address & 3) == 0) { /* word aligned */ retval = target_read_memory(target, bpaddr, bplength, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, bpaddr, sdbbp32_instr); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, bpaddr, &verify); if (retval != ERROR_OK) return retval; if (verify != sdbbp32_instr) verify = 0; } else { /* 16 bit aligned */ retval = target_read_memory(target, bpaddr, 2, 2, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; uint8_t sdbbp_buf[4]; target_buffer_set_u32(target, sdbbp_buf, sdbbp32_instr); retval = target_write_memory(target, bpaddr, 2, 2, sdbbp_buf); if (retval != ERROR_OK) return retval; retval = target_read_memory(target, bpaddr, 2, 2, sdbbp_buf); if (retval != ERROR_OK) return retval; if (target_buffer_get_u32(target, sdbbp_buf) != sdbbp32_instr) verify = 0; } if (verify == 0) { LOG_ERROR("Unable to set 32bit breakpoint at address %08" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } } else { uint16_t verify = 0xffff; retval = target_read_memory(target, bpaddr, bplength, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, bpaddr, MIPS16_SDBBP(isa_req)); if (retval != ERROR_OK) return retval; retval = target_read_u16(target, bpaddr, &verify); if (retval != ERROR_OK) return retval; if (verify != MIPS16_SDBBP(isa_req)) { LOG_ERROR("Unable to set 16bit breakpoint at address %08" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } } breakpoint->is_set = true; } return ERROR_OK; } static int mips_m4k_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct mips32_comparator *comparator_list = mips32->inst_break_list; int retval; if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { int bp_num = breakpoint->number; if (bp_num >= mips32->num_inst_bpoints) { LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %" PRIu32 ")", breakpoint->unique_id); return ERROR_OK; } LOG_DEBUG("bpid: %" PRIu32 " - releasing hw: %d", breakpoint->unique_id, bp_num); comparator_list[bp_num].used = 0; comparator_list[bp_num].bp_value = 0; target_write_u32(target, comparator_list[bp_num].reg_address + ejtag_info->ejtag_ibc_offs, 0); } else { /* restore original instruction (kept in target endianness) */ uint32_t isa_req = breakpoint->length & 1; uint32_t bplength = breakpoint->length & ~1; uint8_t current_instr[4]; LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); if (bplength == 4) { uint32_t sdbbp32_instr = MIPS32_SDBBP(isa_req); if (ejtag_info->endianness && isa_req) sdbbp32_instr = SWAP16(sdbbp32_instr); if ((breakpoint->address & 3) == 0) { /* 32bit aligned */ /* check that user program has not modified breakpoint instruction */ retval = target_read_memory(target, breakpoint->address, 4, 1, current_instr); if (retval != ERROR_OK) return retval; /** * target_read_memory() gets us data in _target_ endianness. * If we want to use this data on the host for comparisons with some macros * we must first transform it to _host_ endianness using target_buffer_get_u16(). */ if (sdbbp32_instr == target_buffer_get_u32(target, current_instr)) { retval = target_write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } } else { /* 16bit aligned */ retval = target_read_memory(target, breakpoint->address, 2, 2, current_instr); if (retval != ERROR_OK) return retval; if (sdbbp32_instr == target_buffer_get_u32(target, current_instr)) { retval = target_write_memory(target, breakpoint->address, 2, 2, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } } } else { /* check that user program has not modified breakpoint instruction */ retval = target_read_memory(target, breakpoint->address, 2, 1, current_instr); if (retval != ERROR_OK) return retval; if (target_buffer_get_u16(target, current_instr) == MIPS16_SDBBP(isa_req)) { retval = target_write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } } } breakpoint->is_set = false; return ERROR_OK; } static int mips_m4k_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct mips32_common *mips32 = target_to_mips32(target); if ((breakpoint->length > 5 || breakpoint->length < 2) || /* out of range */ (breakpoint->length == 4 && (breakpoint->address & 2)) || /* mips32 unaligned */ (mips32->isa_imp == MIPS32_ONLY && breakpoint->length != 4) || /* misp32 specific */ ((mips32->isa_imp & 1) != (breakpoint->length & 1))) /* isa not implemented */ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if (breakpoint->type == BKPT_HARD) { if (mips32->num_inst_bpoints_avail < 1) { LOG_INFO("no hardware breakpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } mips32->num_inst_bpoints_avail--; } return mips_m4k_set_breakpoint(target, breakpoint); } static int mips_m4k_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (breakpoint->is_set) mips_m4k_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) mips32->num_inst_bpoints_avail++; return ERROR_OK; } static int mips_m4k_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct mips32_comparator *comparator_list = mips32->data_break_list; int wp_num = 0; /* * watchpoint enabled, ignore all byte lanes in value register * and exclude both load and store accesses from watchpoint * condition evaluation */ int enable = EJTAG_DBCN_NOSB | EJTAG_DBCN_NOLB | EJTAG_DBCN_BE | (0xff << EJTAG_DBCN_BLM_SHIFT); if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } while (comparator_list[wp_num].used && (wp_num < mips32->num_data_bpoints)) wp_num++; if (wp_num >= mips32->num_data_bpoints) { LOG_ERROR("Can not find free FP Comparator"); return ERROR_FAIL; } if (watchpoint->length != 4) { LOG_ERROR("Only watchpoints of length 4 are supported"); return ERROR_TARGET_UNALIGNED_ACCESS; } if (watchpoint->address % 4) { LOG_ERROR("Watchpoints address should be word aligned"); return ERROR_TARGET_UNALIGNED_ACCESS; } switch (watchpoint->rw) { case WPT_READ: enable &= ~EJTAG_DBCN_NOLB; break; case WPT_WRITE: enable &= ~EJTAG_DBCN_NOSB; break; case WPT_ACCESS: enable &= ~(EJTAG_DBCN_NOLB | EJTAG_DBCN_NOSB); break; default: LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } watchpoint_set(watchpoint, wp_num); comparator_list[wp_num].used = 1; comparator_list[wp_num].bp_value = watchpoint->address; /* EJTAG 2.0 uses 29bit DBA. First 3 bits are reserved. * There is as well no ASID register support. */ if (ejtag_info->ejtag_version == EJTAG_VERSION_20) comparator_list[wp_num].bp_value &= 0xFFFFFFF8; else target_write_u32(target, comparator_list[wp_num].reg_address + ejtag_info->ejtag_dbasid_offs, 0x00000000); target_write_u32(target, comparator_list[wp_num].reg_address, comparator_list[wp_num].bp_value); target_write_u32(target, comparator_list[wp_num].reg_address + ejtag_info->ejtag_dbm_offs, 0x00000000); target_write_u32(target, comparator_list[wp_num].reg_address + ejtag_info->ejtag_dbc_offs, enable); /* TODO: probably this value is ignored on 2.0 */ target_write_u32(target, comparator_list[wp_num].reg_address + ejtag_info->ejtag_dbv_offs, 0); LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "", wp_num, comparator_list[wp_num].bp_value); return ERROR_OK; } static int mips_m4k_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct mips32_comparator *comparator_list = mips32->data_break_list; if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } int wp_num = watchpoint->number; if (wp_num >= mips32->num_data_bpoints) { LOG_DEBUG("Invalid FP Comparator number in watchpoint"); return ERROR_OK; } comparator_list[wp_num].used = 0; comparator_list[wp_num].bp_value = 0; target_write_u32(target, comparator_list[wp_num].reg_address + ejtag_info->ejtag_dbc_offs, 0); watchpoint->is_set = false; return ERROR_OK; } static int mips_m4k_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct mips32_common *mips32 = target_to_mips32(target); if (mips32->num_data_bpoints_avail < 1) { LOG_INFO("no hardware watchpoints available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } mips32->num_data_bpoints_avail--; mips_m4k_set_watchpoint(target, watchpoint); return ERROR_OK; } static int mips_m4k_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (watchpoint->is_set) mips_m4k_unset_watchpoint(target, watchpoint); mips32->num_data_bpoints_avail++; return ERROR_OK; } static void mips_m4k_enable_watchpoints(struct target *target) { struct watchpoint *watchpoint = target->watchpoints; /* set any pending watchpoints */ while (watchpoint) { if (!watchpoint->is_set) mips_m4k_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } } static int mips_m4k_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; if (size == 4 && count > 32) { int retval = mips_m4k_bulk_read_memory(target, address, count, buffer); if (retval == ERROR_OK) return ERROR_OK; LOG_WARNING("Falling back to non-bulk read"); } /* since we don't know if buffer is aligned, we allocate new mem that is always aligned */ void *t = NULL; if (size > 1) { t = malloc(count * size * sizeof(uint8_t)); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } } else t = buffer; /* if noDMA off, use DMAACC mode for memory read */ int retval; if (ejtag_info->impcode & EJTAG_IMP_NODMA) retval = mips32_pracc_read_mem(ejtag_info, address, size, count, t); else retval = mips32_dmaacc_read_mem(ejtag_info, address, size, count, t); /* mips32_..._read_mem with size 4/2 returns uint32_t/uint16_t in host */ /* endianness, but byte array should represent target endianness */ if (retval == ERROR_OK) { switch (size) { case 4: target_buffer_set_u32_array(target, buffer, count, t); break; case 2: target_buffer_set_u16_array(target, buffer, count, t); break; } } if (size > 1) free(t); return retval; } static int mips_m4k_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (size == 4 && count > 32) { int retval = mips_m4k_bulk_write_memory(target, address, count, buffer); if (retval == ERROR_OK) return ERROR_OK; LOG_WARNING("Falling back to non-bulk write"); } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; /** correct endianness if we have word or hword access */ void *t = NULL; if (size > 1) { /* mips32_..._write_mem with size 4/2 requires uint32_t/uint16_t in host */ /* endianness, but byte array represents target endianness */ t = malloc(count * size * sizeof(uint8_t)); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } switch (size) { case 4: target_buffer_get_u32_array(target, buffer, count, (uint32_t *)t); break; case 2: target_buffer_get_u16_array(target, buffer, count, (uint16_t *)t); break; } buffer = t; } /* if noDMA off, use DMAACC mode for memory write */ int retval; if (ejtag_info->impcode & EJTAG_IMP_NODMA) retval = mips32_pracc_write_mem(ejtag_info, address, size, count, buffer); else retval = mips32_dmaacc_write_mem(ejtag_info, address, size, count, buffer); free(t); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int mips_m4k_init_target(struct command_context *cmd_ctx, struct target *target) { mips32_build_reg_cache(target); return ERROR_OK; } static int mips_m4k_init_arch_info(struct target *target, struct mips_m4k_common *mips_m4k, struct jtag_tap *tap) { struct mips32_common *mips32 = &mips_m4k->mips32; mips_m4k->common_magic = MIPSM4K_COMMON_MAGIC; /* initialize mips4k specific info */ mips32_init_arch_info(target, mips32, tap); mips32->arch_info = mips_m4k; return ERROR_OK; } static int mips_m4k_target_create(struct target *target, Jim_Interp *interp) { struct mips_m4k_common *mips_m4k = calloc(1, sizeof(struct mips_m4k_common)); mips_m4k_init_arch_info(target, mips_m4k, target->tap); return ERROR_OK; } static int mips_m4k_examine(struct target *target) { struct mips_m4k_common *mips_m4k = target_to_m4k(target); struct mips_ejtag *ejtag_info = &mips_m4k->mips32.ejtag_info; if (!target_was_examined(target)) { int retval = mips_ejtag_get_idcode(ejtag_info); if (retval != ERROR_OK) { LOG_ERROR("idcode read failed"); return retval; } if (((ejtag_info->idcode >> 1) & 0x7FF) == 0x29) { /* we are using a pic32mx so select ejtag port * as it is not selected by default */ mips_ejtag_set_instr(ejtag_info, MTAP_SW_ETAP); LOG_DEBUG("PIC32 Detected - using EJTAG Interface"); mips_m4k->is_pic32mx = true; } } /* init rest of ejtag interface */ int retval = mips_ejtag_init(ejtag_info); if (retval != ERROR_OK) return retval; return mips32_examine(target); } static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct working_area *fast_data_area; int retval; int write_t = 1; LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "", address, count); /* check alignment */ if (address & 0x3u) return ERROR_TARGET_UNALIGNED_ACCESS; if (!mips32->fast_data_area) { /* Get memory for block write handler * we preserve this area between calls and gain a speed increase * of about 3kb/sec when writing flash * this will be released/nulled by the system when the target is resumed or reset */ retval = target_alloc_working_area(target, MIPS32_FASTDATA_HANDLER_SIZE, &mips32->fast_data_area); if (retval != ERROR_OK) { LOG_ERROR("No working area available"); return retval; } /* reset fastadata state so the algo get reloaded */ ejtag_info->fast_access_save = -1; } fast_data_area = mips32->fast_data_area; if (address < (fast_data_area->address + fast_data_area->size) && fast_data_area->address < (address + count)) { LOG_ERROR("fast_data (" TARGET_ADDR_FMT ") is within write area " "(" TARGET_ADDR_FMT "-" TARGET_ADDR_FMT ").", fast_data_area->address, address, address + count); LOG_ERROR("Change work-area-phys or load_image address!"); return ERROR_FAIL; } /* mips32_pracc_fastdata_xfer requires uint32_t in host endianness, */ /* but byte array represents target endianness */ uint32_t *t = NULL; t = malloc(count * sizeof(uint32_t)); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } target_buffer_get_u32_array(target, buffer, count, t); retval = mips32_pracc_fastdata_xfer(ejtag_info, mips32->fast_data_area, write_t, address, count, t); free(t); if (retval != ERROR_OK) LOG_ERROR("Fastdata access Failed"); return retval; } static int mips_m4k_bulk_read_memory(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct working_area *fast_data_area; int retval; int write_t = 0; LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "", address, count); /* check alignment */ if (address & 0x3u) return ERROR_TARGET_UNALIGNED_ACCESS; if (!mips32->fast_data_area) { /* Get memory for block read handler * we preserve this area between calls and gain a speed increase * of about 3kb/sec when reading flash * this will be released/nulled by the system when the target is resumed or reset */ retval = target_alloc_working_area(target, MIPS32_FASTDATA_HANDLER_SIZE, &mips32->fast_data_area); if (retval != ERROR_OK) { LOG_ERROR("No working area available"); return retval; } /* reset fastadata state so the algo get reloaded */ ejtag_info->fast_access_save = -1; } fast_data_area = mips32->fast_data_area; if (address < (fast_data_area->address + fast_data_area->size) && fast_data_area->address < (address + count)) { LOG_ERROR("fast_data (" TARGET_ADDR_FMT ") is within read area " "(" TARGET_ADDR_FMT "-" TARGET_ADDR_FMT ").", fast_data_area->address, address, address + count); LOG_ERROR("Change work-area-phys or load_image address!"); return ERROR_FAIL; } /* mips32_pracc_fastdata_xfer requires uint32_t in host endianness, */ /* but byte array represents target endianness */ uint32_t *t = malloc(count * sizeof(uint32_t)); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } retval = mips32_pracc_fastdata_xfer(ejtag_info, mips32->fast_data_area, write_t, address, count, t); target_buffer_set_u32_array(target, buffer, count, t); free(t); if (retval != ERROR_OK) LOG_ERROR("Fastdata access Failed"); return retval; } static int mips_m4k_verify_pointer(struct command_invocation *cmd, struct mips_m4k_common *mips_m4k) { if (mips_m4k->common_magic != MIPSM4K_COMMON_MAGIC) { command_print(cmd, "target is not an MIPS_M4K"); return ERROR_TARGET_INVALID; } return ERROR_OK; } COMMAND_HANDLER(mips_m4k_handle_cp0_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct mips_m4k_common *mips_m4k = target_to_m4k(target); struct mips_ejtag *ejtag_info = &mips_m4k->mips32.ejtag_info; retval = mips_m4k_verify_pointer(CMD, mips_m4k); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } /* two or more argument, access a single register/select (write if third argument is given) */ if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; else { uint32_t cp0_reg, cp0_sel; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel); if (CMD_ARGC == 2) { uint32_t value; retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel); if (retval != ERROR_OK) { command_print(CMD, "couldn't access reg %" PRIu32, cp0_reg); return ERROR_OK; } command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32, cp0_reg, cp0_sel, value); } else if (CMD_ARGC == 3) { uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); retval = mips32_cp0_write(ejtag_info, value, cp0_reg, cp0_sel); if (retval != ERROR_OK) { command_print(CMD, "couldn't access cp0 reg %" PRIu32 ", select %" PRIu32, cp0_reg, cp0_sel); return ERROR_OK; } command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32, cp0_reg, cp0_sel, value); } } return ERROR_OK; } COMMAND_HANDLER(mips_m4k_handle_scan_delay_command) { struct target *target = get_current_target(CMD_CTX); struct mips_m4k_common *mips_m4k = target_to_m4k(target); struct mips_ejtag *ejtag_info = &mips_m4k->mips32.ejtag_info; if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], ejtag_info->scan_delay); else if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "scan delay: %d nsec", ejtag_info->scan_delay); if (ejtag_info->scan_delay >= MIPS32_SCAN_DELAY_LEGACY_MODE) { ejtag_info->mode = 0; command_print(CMD, "running in legacy mode"); } else { ejtag_info->mode = 1; command_print(CMD, "running in fast queued mode"); } return ERROR_OK; } static const struct command_registration mips_m4k_exec_command_handlers[] = { { .name = "cp0", .handler = mips_m4k_handle_cp0_command, .mode = COMMAND_EXEC, .usage = "regnum [value]", .help = "display/modify cp0 register", }, { .name = "scan_delay", .handler = mips_m4k_handle_scan_delay_command, .mode = COMMAND_ANY, .help = "display/set scan delay in nano seconds", .usage = "[value]", }, { .chain = smp_command_handlers, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration mips_m4k_command_handlers[] = { { .chain = mips32_command_handlers, }, { .name = "mips_m4k", .mode = COMMAND_ANY, .help = "mips_m4k command group", .usage = "", .chain = mips_m4k_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type mips_m4k_target = { .name = "mips_m4k", .poll = mips_m4k_poll, .arch_state = mips32_arch_state, .halt = mips_m4k_halt, .resume = mips_m4k_resume, .step = mips_m4k_step, .assert_reset = mips_m4k_assert_reset, .deassert_reset = mips_m4k_deassert_reset, .get_gdb_reg_list = mips32_get_gdb_reg_list, .read_memory = mips_m4k_read_memory, .write_memory = mips_m4k_write_memory, .checksum_memory = mips32_checksum_memory, .blank_check_memory = mips32_blank_check_memory, .run_algorithm = mips32_run_algorithm, .add_breakpoint = mips_m4k_add_breakpoint, .remove_breakpoint = mips_m4k_remove_breakpoint, .add_watchpoint = mips_m4k_add_watchpoint, .remove_watchpoint = mips_m4k_remove_watchpoint, .commands = mips_m4k_command_handlers, .target_create = mips_m4k_target_create, .init_target = mips_m4k_init_target, .examine = mips_m4k_examine, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips_m4k.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_MIPS_M4K_H #define OPENOCD_TARGET_MIPS_M4K_H struct target; #define MIPSM4K_COMMON_MAGIC 0xB321B321U struct mips_m4k_common { unsigned int common_magic; struct mips32_common mips32; bool is_pic32mx; }; static inline struct mips_m4k_common * target_to_m4k(struct target *target) { return container_of(target->arch_info, struct mips_m4k_common, mips32); } static inline void mips_m4k_isa_filter(enum mips32_isa_imp isa_imp, target_addr_t *addr) { if (isa_imp <= 1) { /* if only one isa implemented */ target_addr_t address = (*addr & ~1) | isa_imp; if (address != *addr) { LOG_USER("Warning: isa bit changed due to isa not implemented"); *addr = address; } } } #endif /* OPENOCD_TARGET_MIPS_M4K_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips_mips64.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * MIPS64 generic target support * * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com> * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru> * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com> * * Based on the work of: * Copyright (C) 2008 by Spencer Oliver * Copyright (C) 2008 by David T.L. Wong */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "breakpoints.h" #include "mips32.h" #include "mips64.h" #include "mips_mips64.h" #include "target_type.h" #include "register.h" static int mips_mips64_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); static uint64_t mips64_extend_sign(uint64_t addr) { if (addr >> 32) return addr; if (addr >> 31) return addr | (ULLONG_MAX << 32); return addr; } static int mips_mips64_examine_debug_reason(struct target *target) { if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) target->debug_reason = DBG_REASON_BREAKPOINT; return ERROR_OK; } static int mips_mips64_debug_entry(struct target *target) { struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; struct reg *pc = &mips64->core_cache->reg_list[MIPS64_PC]; mips64_save_context(target); /* make sure stepping disabled, SSt bit in CP0 debug register cleared */ mips64_ejtag_config_step(ejtag_info, 0); /* make sure break unit configured */ mips64_configure_break_unit(target); /* attempt to find halt reason */ mips_mips64_examine_debug_reason(target); LOG_DEBUG("entered debug state at PC 0x%" PRIx64 ", target->state: %s", buf_get_u64(pc->value, 0, 64), target_state_name(target)); return ERROR_OK; } static int mips_mips64_poll(struct target *target) { int retval; struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl; /* read ejtag control reg */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* clear this bit before handling polling * as after reset registers will read zero */ if (ejtag_ctrl & EJTAG_CTRL_ROCC) { /* we have detected a reset, clear flag * otherwise ejtag will not work */ ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_ROCC; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); LOG_DEBUG("Reset Detected"); } /* check for processor halted */ if (ejtag_ctrl & EJTAG_CTRL_BRKST) { if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { target->state = TARGET_HALTED; retval = mips_mips64_debug_entry(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); } else if (target->state == TARGET_DEBUG_RUNNING) { target->state = TARGET_HALTED; retval = mips_mips64_debug_entry(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } } else { target->state = TARGET_RUNNING; } return ERROR_OK; } static int mips_mips64_halt(struct target *target) { struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); if (target->state == TARGET_RESET) { if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST"); return ERROR_TARGET_FAILURE; } else { /* we came here in a reset_halt or reset_init sequence * debug entry was already prepared in mips64_prepare_reset_halt() */ target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } } /* break processor */ mips_ejtag_enter_debug(ejtag_info); target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int mips_mips64_assert_reset(struct target *target) { struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; int retval; LOG_DEBUG("target->state: %s", target_state_name(target)); enum reset_types jtag_reset_config = jtag_get_reset_config(); if (!(jtag_reset_config & RESET_HAS_SRST)) { LOG_ERROR("Can't assert SRST"); return ERROR_FAIL; } if (target->reset_halt) /* use hardware to catch reset */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_EJTAGBOOT); else mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT); /* here we should issue a srst only, but we may have to assert trst as well */ if (jtag_reset_config & RESET_SRST_PULLS_TRST) jtag_add_reset(1, 1); else jtag_add_reset(0, 1); target->state = TARGET_RESET; jtag_add_sleep(5000); retval = mips64_invalidate_core_regs(target); if (retval != ERROR_OK) return retval; if (target->reset_halt) { retval = target_halt(target); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int mips_mips64_deassert_reset(struct target *target) { LOG_DEBUG("target->state: %s", target_state_name(target)); /* deassert reset lines */ jtag_add_reset(0, 0); return ERROR_OK; } static int mips_mips64_single_step_core(struct target *target) { struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; int retval; /* configure single step mode */ mips64_ejtag_config_step(ejtag_info, 1); /* disable interrupts while stepping */ retval = mips64_enable_interrupts(target, false); if (retval != ERROR_OK) return retval; /* exit debug mode */ retval = mips64_ejtag_exit_debug(ejtag_info); if (retval != ERROR_OK) return retval; mips_mips64_debug_entry(target); return ERROR_OK; } /* TODO: HW breakpoints are in EJTAG spec. Should we share it for MIPS32? */ static int mips_mips64_set_hwbp(struct target *target, struct breakpoint *bp) { struct mips64_common *mips64 = target->arch_info; struct mips64_comparator *c, *cl = mips64->inst_break_list; uint64_t bp_value; int retval, bp_num = 0; while (cl[bp_num].used && (bp_num < mips64->num_inst_bpoints)) bp_num++; if (bp_num >= mips64->num_inst_bpoints) { LOG_DEBUG("ERROR Can not find free FP Comparator(bpid: %" PRIu32 ")", bp->unique_id); LOG_WARNING("ERROR Can not find free FP Comparator"); exit(-1); } c = &cl[bp_num]; c->used = true; c->bp_value = bp->address; bp_value = bp->address; /* Instruction Breakpoint Address n (IBAn) Register */ retval = target_write_u64(target, c->reg_address, bp_value); if (retval != ERROR_OK) return retval; /* TODO: use defines */ /* Instruction Breakpoint Address Mask n (IBMn) Register */ retval = target_write_u64(target, c->reg_address + 0x08, 0); if (retval != ERROR_OK) return retval; /* Instruction Breakpoint Control n (IBCn) Register */ retval = target_write_u64(target, c->reg_address + 0x18, 1); if (retval != ERROR_OK) return retval; LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx64, bp->unique_id, bp_num, c->bp_value); return ERROR_OK; } /* TODO: is it MIPS64 or MIPS32 instruction. If MIPS32, can it be shared with * MIPS32 code? */ static int mips_mips64_set_sdbbp(struct target *target, struct breakpoint *bp) { uint32_t verify; int retval; retval = target_read_memory(target, bp->address, bp->length, 1, bp->orig_instr); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, bp->address, MIPS64_SDBBP); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, bp->address, &verify); if (retval != ERROR_OK) return retval; if (verify != MIPS64_SDBBP) { LOG_ERROR("Unable to set 32bit breakpoint at address %16" PRIx64, bp->address); retval = ERROR_FAIL; } return retval; } /* TODO do MIPS64 support MIPS16 instructions? Can it be shared with MIPS32 * code? */ static int mips_mips16_set_sdbbp(struct target *target, struct breakpoint *bp) { uint32_t isa_req = bp->length & 1; uint16_t verify; int retval; retval = target_read_memory(target, bp->address, bp->length, 1, bp->orig_instr); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, bp->address, MIPS16_SDBBP(isa_req)); if (retval != ERROR_OK) return retval; retval = target_read_u16(target, bp->address, &verify); if (retval != ERROR_OK) return retval; if (verify != MIPS16_SDBBP(isa_req)) { LOG_ERROR("Unable to set 16bit breakpoint at address %16" PRIx64, bp->address); retval = ERROR_FAIL; } return retval; } static int mips_mips64_set_breakpoint(struct target *target, struct breakpoint *bp) { int retval; if (bp->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } if (bp->type == BKPT_HARD) { retval = mips_mips64_set_hwbp(target, bp); } else { LOG_DEBUG("bpid: %" PRIu32, bp->unique_id); switch (bp->length) { case MIPS64_SDBBP_SIZE: retval = mips_mips64_set_sdbbp(target, bp); break; case MIPS16_SDBBP_SIZE: retval = mips_mips16_set_sdbbp(target, bp); break; default: retval = ERROR_FAIL; } } if (retval != ERROR_OK) { LOG_ERROR("can't unset breakpoint. Some thing wrong happened"); return retval; } bp->is_set = true; return ERROR_OK; } static int mips_mips64_enable_breakpoints(struct target *target) { struct breakpoint *bp = target->breakpoints; int retval = ERROR_OK; /* set any pending breakpoints */ while (bp) { if (!bp->is_set) { retval = mips_mips64_set_breakpoint(target, bp); if (retval != ERROR_OK) return retval; } bp = bp->next; } return ERROR_OK; } /* TODO: HW data breakpoints are in EJTAG spec. Should we share it for MIPS32? */ static int mips_mips64_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { uint64_t wp_value; struct mips64_common *mips64 = target->arch_info; struct mips64_comparator *c, *cl = mips64->data_break_list; int retval, wp_num = 0; /* * watchpoint enabled, ignore all byte lanes in value register * and exclude both load and store accesses from watchpoint * condition evaluation */ int enable = EJTAG_DBCN_NOSB | EJTAG_DBCN_NOLB | EJTAG_DBCN_BE | (0xff << EJTAG_DBCN_BLM_SHIFT); if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } while (cl[wp_num].used && (wp_num < mips64->num_data_bpoints)) wp_num++; if (wp_num >= mips64->num_data_bpoints) { LOG_ERROR("ERROR Can not find free comparator"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (watchpoint->length != 4) { LOG_ERROR("Only watchpoints of length 4 are supported"); return ERROR_TARGET_UNALIGNED_ACCESS; } if (watchpoint->address % 4) { LOG_ERROR("Watchpoints address should be word aligned"); return ERROR_TARGET_UNALIGNED_ACCESS; } switch (watchpoint->rw) { case WPT_READ: enable &= ~EJTAG_DBCN_NOLB; break; case WPT_WRITE: enable &= ~EJTAG_DBCN_NOSB; break; case WPT_ACCESS: enable &= ~(EJTAG_DBCN_NOLB | EJTAG_DBCN_NOSB); break; default: LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } c = &cl[wp_num]; watchpoint_set(watchpoint, wp_num); c->used = true; c->bp_value = watchpoint->address; wp_value = watchpoint->address; if (wp_value & 0x80000000) wp_value |= ULLONG_MAX << 32; retval = target_write_u64(target, c->reg_address, wp_value); if (retval != ERROR_OK) return retval; retval = target_write_u64(target, c->reg_address + 0x08, 0); if (retval != ERROR_OK) return retval; retval = target_write_u64(target, c->reg_address + 0x10, 0); if (retval != ERROR_OK) return retval; retval = target_write_u64(target, c->reg_address + 0x18, enable); if (retval != ERROR_OK) return retval; retval = target_write_u64(target, c->reg_address + 0x20, 0); if (retval != ERROR_OK) return retval; LOG_DEBUG("wp_num %i bp_value 0x%" PRIx64 "", wp_num, c->bp_value); return ERROR_OK; } static int mips_mips64_enable_watchpoints(struct target *target) { struct watchpoint *watchpoint = target->watchpoints; int retval; /* set any pending watchpoints */ while (watchpoint) { if (!watchpoint->is_set) { retval = mips_mips64_set_watchpoint(target, watchpoint); if (retval != ERROR_OK) return retval; } watchpoint = watchpoint->next; } return ERROR_OK; } static int mips_mips64_unset_hwbp(struct target *target, struct breakpoint *bp) { struct mips64_common *mips64 = target->arch_info; struct mips64_comparator *comparator_list = mips64->inst_break_list; int bp_num = bp->number; if (bp_num >= mips64->num_inst_bpoints) { LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %" PRIu32 ")", bp->unique_id); return ERROR_OK; } LOG_DEBUG("bpid: %" PRIu32 " - releasing hw: %d", bp->unique_id, bp_num); comparator_list[bp_num].used = false; comparator_list[bp_num].bp_value = 0; return target_write_u64(target, comparator_list[bp_num].reg_address + 0x18, 0); } static int mips_mips64_unset_sdbbp(struct target *target, struct breakpoint *bp) { uint8_t buf[MIPS64_SDBBP_SIZE]; uint32_t instr; int retval; retval = target_read_memory(target, bp->address, MIPS64_SDBBP_SIZE, 1, &buf[0]); if (retval != ERROR_OK) return retval; instr = target_buffer_get_u32(target, &buf[0]); if (instr != MIPS64_SDBBP) return ERROR_OK; return target_write_memory(target, bp->address, MIPS64_SDBBP_SIZE, 1, bp->orig_instr); } static int mips_mips16_unset_sdbbp(struct target *target, struct breakpoint *bp) { uint8_t buf[MIPS16_SDBBP_SIZE]; uint16_t instr; int retval; retval = target_read_memory(target, bp->address, MIPS16_SDBBP_SIZE, 1, &buf[0]); if (retval != ERROR_OK) return retval; instr = target_buffer_get_u16(target, &buf[0]); if (instr != MIPS16_SDBBP(bp->length & 1)) return ERROR_OK; return target_write_memory(target, bp->address, MIPS16_SDBBP_SIZE, 1, bp->orig_instr); } static int mips_mips64_unset_breakpoint(struct target *target, struct breakpoint *bp) { /* get pointers to arch-specific information */ int retval; if (!bp->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (bp->type == BKPT_HARD) { retval = mips_mips64_unset_hwbp(target, bp); } else { LOG_DEBUG("bpid: %" PRIu32, bp->unique_id); switch (bp->length) { case MIPS64_SDBBP_SIZE: retval = mips_mips64_unset_sdbbp(target, bp); break; case MIPS16_SDBBP_SIZE: retval = mips_mips16_unset_sdbbp(target, bp); break; default: retval = ERROR_FAIL; } } if (retval != ERROR_OK) { LOG_ERROR("can't unset breakpoint. Some thing wrong happened"); return retval; } bp->is_set = false; return ERROR_OK; } static int mips_mips64_resume(struct target *target, int current, uint64_t address, int handle_breakpoints, int debug_execution) { struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; int retval = ERROR_OK; uint64_t resume_pc; struct reg *pc; if (mips64->mips64mode32) address = mips64_extend_sign(address); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted %d", target->state); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) { target_free_all_working_areas(target); retval = mips_mips64_enable_breakpoints(target); if (retval != ERROR_OK) return retval; retval = mips_mips64_enable_watchpoints(target); if (retval != ERROR_OK) return retval; } pc = &mips64->core_cache->reg_list[MIPS64_PC]; /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u64(pc->value, 0, 64, address); pc->dirty = 1; pc->valid = 1; } resume_pc = buf_get_u64(pc->value, 0, 64); retval = mips64_restore_context(target); if (retval != ERROR_OK) return retval; /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { struct breakpoint *bp; /* Single step past breakpoint at current address */ bp = breakpoint_find(target, (uint64_t) resume_pc); if (bp) { LOG_DEBUG("unset breakpoint at 0x%16.16" PRIx64 "", bp->address); retval = mips_mips64_unset_breakpoint(target, bp); if (retval != ERROR_OK) return retval; retval = mips_mips64_single_step_core(target); if (retval != ERROR_OK) return retval; retval = mips_mips64_set_breakpoint(target, bp); if (retval != ERROR_OK) return retval; } } /* enable interrupts if we are running */ retval = mips64_enable_interrupts(target, !debug_execution); if (retval != ERROR_OK) return retval; /* exit debug mode */ retval = mips64_ejtag_exit_debug(ejtag_info); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_NOTHALTED; /* registers are now invalid */ retval = mips64_invalidate_core_regs(target); if (retval != ERROR_OK) return retval; if (!debug_execution) { target->state = TARGET_RUNNING; retval = target_call_event_callbacks(target, TARGET_EVENT_RESUMED); if (retval != ERROR_OK) return retval; LOG_DEBUG("target resumed at 0x%" PRIx64 "", resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; retval = target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); if (retval != ERROR_OK) return retval; LOG_DEBUG("target debug resumed at 0x%" PRIx64 "", resume_pc); } return ERROR_OK; } static int mips_mips64_step(struct target *target, int current, uint64_t address, int handle_breakpoints) { struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; struct reg *pc = &mips64->core_cache->reg_list[MIPS64_PC]; struct breakpoint *bp = NULL; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (mips64->mips64mode32) address = mips64_extend_sign(address); /* current = 1: continue on current pc, otherwise continue at * <address> */ if (!current) { buf_set_u64(pc->value, 0, 64, address); pc->dirty = 1; pc->valid = 1; } /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { bp = breakpoint_find(target, buf_get_u64(pc->value, 0, 64)); if (bp) { retval = mips_mips64_unset_breakpoint(target, bp); if (retval != ERROR_OK) return retval; } } retval = mips64_restore_context(target); if (retval != ERROR_OK) return retval; /* configure single step mode */ retval = mips64_ejtag_config_step(ejtag_info, 1); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_SINGLESTEP; retval = target_call_event_callbacks(target, TARGET_EVENT_RESUMED); if (retval != ERROR_OK) return retval; /* disable interrupts while stepping */ retval = mips64_enable_interrupts(target, false); if (retval != ERROR_OK) return retval; /* exit debug mode */ retval = mips64_ejtag_exit_debug(ejtag_info); if (retval != ERROR_OK) return retval; /* registers are now invalid */ retval = mips64_invalidate_core_regs(target); if (retval != ERROR_OK) return retval; if (bp) { retval = mips_mips64_set_breakpoint(target, bp); if (retval != ERROR_OK) return retval; } LOG_DEBUG("target stepped "); retval = mips_mips64_debug_entry(target); if (retval != ERROR_OK) return retval; return target_call_event_callbacks(target, TARGET_EVENT_HALTED); } static int mips_mips64_add_breakpoint(struct target *target, struct breakpoint *bp) { struct mips64_common *mips64 = target->arch_info; if (mips64->mips64mode32) bp->address = mips64_extend_sign(bp->address); if (bp->type == BKPT_HARD) { if (mips64->num_inst_bpoints_avail < 1) { LOG_INFO("no hardware breakpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } mips64->num_inst_bpoints_avail--; } return mips_mips64_set_breakpoint(target, bp); } static int mips_mips64_remove_breakpoint(struct target *target, struct breakpoint *bp) { /* get pointers to arch-specific information */ struct mips64_common *mips64 = target->arch_info; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (bp->is_set) retval = mips_mips64_unset_breakpoint(target, bp); if (bp->type == BKPT_HARD) mips64->num_inst_bpoints_avail++; return retval; } static int mips_mips64_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { /* get pointers to arch-specific information */ struct mips64_common *mips64 = target->arch_info; struct mips64_comparator *comparator_list = mips64->data_break_list; if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } int wp_num = watchpoint->number; if (wp_num >= mips64->num_data_bpoints) { LOG_DEBUG("Invalid FP Comparator number in watchpoint"); return ERROR_OK; } comparator_list[wp_num].used = false; comparator_list[wp_num].bp_value = 0; target_write_u64(target, comparator_list[wp_num].reg_address + 0x18, 0); watchpoint->is_set = false; return ERROR_OK; } static int mips_mips64_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct mips64_common *mips64 = target->arch_info; if (mips64->num_data_bpoints_avail < 1) { LOG_INFO("no hardware watchpoints available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } mips64->num_data_bpoints_avail--; return mips_mips64_set_watchpoint(target, watchpoint); } static int mips_mips64_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { /* get pointers to arch-specific information */ struct mips64_common *mips64 = target->arch_info; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (watchpoint->is_set) retval = mips_mips64_unset_watchpoint(target, watchpoint); mips64->num_data_bpoints_avail++; return retval; } static int mips_mips64_read_memory(struct target *target, uint64_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; int retval; void *t; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted %d", target->state); return ERROR_TARGET_NOT_HALTED; } if (mips64->mips64mode32) address = mips64_extend_sign(address); /* sanitize arguments */ if (((size != 8) && (size != 4) && (size != 2) && (size != 1)) || !count || !buffer) return ERROR_COMMAND_ARGUMENT_INVALID; if (((size == 8) && (address & 0x7)) || ((size == 4) && (address & 0x3)) || ((size == 2) && (address & 0x1))) return ERROR_TARGET_UNALIGNED_ACCESS; if (size > 1) { t = calloc(count, size); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } } else t = buffer; LOG_DEBUG("address: 0x%16.16" PRIx64 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); retval = mips64_pracc_read_mem(ejtag_info, address, size, count, (void *)t); if (retval != ERROR_OK) { LOG_ERROR("mips64_pracc_read_mem filed"); goto read_done; } switch (size) { case 8: target_buffer_set_u64_array(target, buffer, count, t); break; case 4: target_buffer_set_u32_array(target, buffer, count, t); break; case 2: target_buffer_set_u16_array(target, buffer, count, t); break; } read_done: if (size > 1) free(t); return retval; } static int mips_mips64_bulk_write_memory(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer) { struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; struct working_area *fast_data_area; int retval; LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "", address, count); if (address & 0x7) return ERROR_TARGET_UNALIGNED_ACCESS; if (!mips64->fast_data_area) { /* Get memory for block write handler * we preserve this area between calls and gain a speed increase * of about 3kb/sec when writing flash * this will be released/nulled by the system when the target is resumed or reset */ retval = target_alloc_working_area(target, MIPS64_FASTDATA_HANDLER_SIZE, &mips64->fast_data_area); if (retval != ERROR_OK) { LOG_ERROR("No working area available"); return retval; } /* reset fastadata state so the algo get reloaded */ ejtag_info->fast_access_save = -1; } fast_data_area = mips64->fast_data_area; if (address <= fast_data_area->address + fast_data_area->size && fast_data_area->address <= address + count) { LOG_ERROR("fast_data (" TARGET_ADDR_FMT ") is within write area " "(" TARGET_ADDR_FMT "-" TARGET_ADDR_FMT ").", fast_data_area->address, address, address + count); LOG_ERROR("Change work-area-phys or load_image address!"); return ERROR_FAIL; } /* mips32_pracc_fastdata_xfer requires uint32_t in host endianness, */ /* but byte array represents target endianness */ uint64_t *t; t = calloc(count, sizeof(uint64_t)); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } target_buffer_get_u64_array(target, buffer, count, t); retval = mips64_pracc_fastdata_xfer(ejtag_info, mips64->fast_data_area, true, address, count, t); if (retval != ERROR_OK) LOG_ERROR("Fastdata access Failed"); free(t); return retval; } static int mips_mips64_write_memory(struct target *target, uint64_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; int retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (mips64->mips64mode32) address = mips64_extend_sign(address); /* sanitize arguments */ if (((size != 8) && (size != 4) && (size != 2) && (size != 1)) || !count || !buffer) return ERROR_COMMAND_ARGUMENT_INVALID; if (((size == 8) && (address & 0x7)) || ((size == 4) && (address & 0x3)) || ((size == 2) && (address & 0x1))) return ERROR_TARGET_UNALIGNED_ACCESS; if (size == 8 && count > 8) { retval = mips_mips64_bulk_write_memory(target, address, count, buffer); if (retval == ERROR_OK) return ERROR_OK; LOG_WARNING("Falling back to non-bulk write"); } void *t = NULL; if (size > 1) { t = calloc(count, size); if (!t) { LOG_ERROR("unable to allocate t for write buffer"); return ERROR_FAIL; } switch (size) { case 8: target_buffer_get_u64_array(target, buffer, count, (uint64_t *)t); break; case 4: target_buffer_get_u32_array(target, buffer, count, (uint32_t *)t); break; case 2: target_buffer_get_u16_array(target, buffer, count, (uint16_t *)t); break; } buffer = t; } LOG_DEBUG("address: 0x%16.16" PRIx64 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); retval = mips64_pracc_write_mem(ejtag_info, address, size, count, (void *)buffer); free(t); return retval; } static int mips_mips64_init_target(struct command_context *cmd_ctx, struct target *target) { return mips64_build_reg_cache(target); } static int mips_mips64_target_create(struct target *target, Jim_Interp *interp) { struct mips_mips64_common *mips_mips64; struct mips64_common *mips64; mips_mips64 = calloc(1, sizeof(*mips_mips64)); if (!mips_mips64) { LOG_ERROR("unable to allocate mips_mips64"); return ERROR_FAIL; } mips_mips64->common_magic = MIPS64_COMMON_MAGIC; mips64 = &mips_mips64->mips64_common; mips64->arch_info = mips_mips64; target->arch_info = mips64; return mips64_init_arch_info(target, mips64, target->tap); } static int mips_mips64_examine(struct target *target) { int retval; struct mips64_common *mips64 = target->arch_info; retval = mips_ejtag_init(&mips64->ejtag_info); if (retval != ERROR_OK) return retval; return mips64_examine(target); } static int mips_mips64_checksum_memory(struct target *target, uint64_t address, uint32_t size, uint32_t *checksum) { return ERROR_FAIL; /* use bulk read method */ } COMMAND_HANDLER(handle_mips64mode32) { struct target *target = get_current_target(CMD_CTX); struct mips64_common *mips64 = target->arch_info; if (CMD_ARGC > 0) COMMAND_PARSE_BOOL(CMD_ARGV[0], mips64->mips64mode32, "on", "off"); if (mips64->mips64mode32) command_print(CMD, "enabled"); else command_print(CMD, "disabled"); return ERROR_OK; } static const struct command_registration mips64_commands_handlers[] = { { .name = "mips64mode32", .mode = COMMAND_EXEC, .help = "Enable/disable 32 bit mode", .usage = "[1|0]", .handler = handle_mips64mode32 }, COMMAND_REGISTRATION_DONE }; struct target_type mips_mips64_target = { .name = "mips_mips64", .poll = mips_mips64_poll, .arch_state = mips64_arch_state, .target_request_data = NULL, .halt = mips_mips64_halt, .resume = mips_mips64_resume, .step = mips_mips64_step, .assert_reset = mips_mips64_assert_reset, .deassert_reset = mips_mips64_deassert_reset, /* TODO: add .soft_reset_halt */ .get_gdb_reg_list = mips64_get_gdb_reg_list, .read_memory = mips_mips64_read_memory, .write_memory = mips_mips64_write_memory, .checksum_memory = mips_mips64_checksum_memory, .blank_check_memory = NULL, .run_algorithm = mips64_run_algorithm, .add_breakpoint = mips_mips64_add_breakpoint, .remove_breakpoint = mips_mips64_remove_breakpoint, .add_watchpoint = mips_mips64_add_watchpoint, .remove_watchpoint = mips_mips64_remove_watchpoint, .target_create = mips_mips64_target_create, .init_target = mips_mips64_init_target, .examine = mips_mips64_examine, .commands = mips64_commands_handlers, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/mips_mips64.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * MIPS64 generic target support * * * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com> * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru> * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com> * * Based on the work of: * Copyright (C) 2008 by Spencer Oliver * Copyright (C) 2008 by David T.L. Wong */ #ifndef OPENOCD_TARGET_MIPS_MIPS64_H #define OPENOCD_TARGET_MIPS_MIPS64_H #include "helper/types.h" struct mips_mips64_common { unsigned int common_magic; struct mips64_common mips64_common; }; #endif /* OPENOCD_TARGET_MIPS_MIPS64_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/openrisc/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libopenrisc.la %C%_libopenrisc_la_SOURCES = \ %D%/or1k.c \ %D%/or1k_du_adv.c \ %D%/or1k_tap_mohor.c \ %D%/or1k_tap_vjtag.c \ %D%/or1k_tap_xilinx_bscan.c \ %D%/jsp_server.c \ %D%/or1k.h \ %D%/or1k_du.h \ %D%/or1k_tap.h \ %D%/jsp_server.h ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/openrisc/jsp_server.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2014 by Franck Jullien * * franck.jullien@gmail.com * * * * Based on ./src/server/telnet_server.c * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <server/telnet_server.h> #include "or1k_tap.h" #include "or1k_du.h" #include "jsp_server.h" static char *jsp_port; /**A skim of the relevant RFCs suggests that if my application simply sent the * characters IAC DONT LINEMODE (\377\376\042) as soon as the client connects, * the client should be forced into character mode. However it doesn't make any difference. */ static const char * const negotiate = "\xFF\xFB\x03" /* IAC WILL Suppress Go Ahead */ "\xFF\xFB\x01" /* IAC WILL Echo */ "\xFF\xFD\x03" /* IAC DO Suppress Go Ahead */ "\xFF\xFE\x01"; /* IAC DON'T Echo */ /* The only way we can detect that the socket is closed is the first time * we write to it, we will fail. Subsequent write operations will * succeed. Shudder! */ static int telnet_write(struct connection *connection, const void *data, int len) { struct telnet_connection *t_con = connection->priv; if (t_con->closed) return ERROR_SERVER_REMOTE_CLOSED; if (connection_write(connection, data, len) == len) return ERROR_OK; t_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; } static int jsp_poll_read(void *priv) { struct jsp_service *jsp_service = (struct jsp_service *)priv; unsigned char out_buffer[10]; unsigned char in_buffer[10]; int out_len = 0; int in_len; if (!jsp_service->connection) return ERROR_FAIL; memset(out_buffer, 0, 10); or1k_adv_jtag_jsp_xfer(jsp_service->jtag_info, &out_len, out_buffer, &in_len, in_buffer); if (in_len) telnet_write(jsp_service->connection, in_buffer, in_len); return ERROR_OK; } static int jsp_new_connection(struct connection *connection) { struct telnet_connection *telnet_connection = malloc(sizeof(struct telnet_connection)); struct jsp_service *jsp_service = connection->service->priv; connection->priv = telnet_connection; /* initialize telnet connection information */ telnet_connection->closed = 0; telnet_connection->line_size = 0; telnet_connection->line_cursor = 0; telnet_connection->state = TELNET_STATE_DATA; /* negotiate telnet options */ telnet_write(connection, negotiate, strlen(negotiate)); /* print connection banner */ if (jsp_service->banner) { telnet_write(connection, jsp_service->banner, strlen(jsp_service->banner)); telnet_write(connection, "\r\n", 2); } jsp_service->connection = connection; int retval = target_register_timer_callback(&jsp_poll_read, 1, TARGET_TIMER_TYPE_PERIODIC, jsp_service); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int jsp_input(struct connection *connection) { int bytes_read; unsigned char buffer[TELNET_BUFFER_SIZE]; unsigned char *buf_p; struct telnet_connection *t_con = connection->priv; struct jsp_service *jsp_service = connection->service->priv; bytes_read = connection_read(connection, buffer, TELNET_BUFFER_SIZE); if (bytes_read == 0) return ERROR_SERVER_REMOTE_CLOSED; else if (bytes_read == -1) { LOG_ERROR("error during read: %s", strerror(errno)); return ERROR_SERVER_REMOTE_CLOSED; } buf_p = buffer; while (bytes_read) { switch (t_con->state) { case TELNET_STATE_DATA: if (*buf_p == 0xff) t_con->state = TELNET_STATE_IAC; else { int out_len = 1; int in_len; unsigned char in_buffer[10]; or1k_adv_jtag_jsp_xfer(jsp_service->jtag_info, &out_len, buf_p, &in_len, in_buffer); if (in_len) telnet_write(connection, in_buffer, in_len); } break; case TELNET_STATE_IAC: switch (*buf_p) { case 0xfe: t_con->state = TELNET_STATE_DONT; break; case 0xfd: t_con->state = TELNET_STATE_DO; break; case 0xfc: t_con->state = TELNET_STATE_WONT; break; case 0xfb: t_con->state = TELNET_STATE_WILL; break; } break; case TELNET_STATE_SB: break; case TELNET_STATE_SE: break; case TELNET_STATE_WILL: case TELNET_STATE_WONT: case TELNET_STATE_DO: case TELNET_STATE_DONT: t_con->state = TELNET_STATE_DATA; break; default: LOG_ERROR("unknown telnet state"); exit(-1); } bytes_read--; buf_p++; } return ERROR_OK; } static int jsp_connection_closed(struct connection *connection) { struct jsp_service *jsp_service = connection->service->priv; int retval = target_unregister_timer_callback(&jsp_poll_read, jsp_service); if (retval != ERROR_OK) return retval; free(connection->priv); connection->priv = NULL; return ERROR_OK; } static const struct service_driver jsp_service_driver = { .name = "jsp", .new_connection_during_keep_alive_handler = NULL, .new_connection_handler = jsp_new_connection, .input_handler = jsp_input, .connection_closed_handler = jsp_connection_closed, .keep_client_alive_handler = NULL, }; int jsp_init(struct or1k_jtag *jtag_info, char *banner) { struct jsp_service *jsp_service = malloc(sizeof(struct jsp_service)); jsp_service->banner = banner; jsp_service->jtag_info = jtag_info; return add_service(&jsp_service_driver, jsp_port, 1, jsp_service); } COMMAND_HANDLER(handle_jsp_port_command) { return CALL_COMMAND_HANDLER(server_pipe_command, &jsp_port); } static const struct command_registration jsp_command_handlers[] = { { .name = "jsp_port", .handler = handle_jsp_port_command, .mode = COMMAND_ANY, .help = "Specify port on which to listen " "for incoming JSP telnet connections.", .usage = "[port_num]", }, COMMAND_REGISTRATION_DONE }; int jsp_register_commands(struct command_context *cmd_ctx) { jsp_port = strdup("7777"); return register_commands(cmd_ctx, NULL, jsp_command_handlers); } void jsp_service_free(void) { free(jsp_port); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/openrisc/jsp_server.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef OPENOCD_TARGET_OPENRISC_JSP_SERVER_H #define OPENOCD_TARGET_OPENRISC_JSP_SERVER_H #include "or1k_tap.h" #include "or1k.h" #include "or1k_du.h" struct jsp_service { char *banner; struct or1k_jtag *jtag_info; struct connection *connection; }; int jsp_init(struct or1k_jtag *jtag_info, char *banner); int jsp_register_commands(struct command_context *cmd_ctx); void jsp_service_free(void); #endif /* OPENOCD_TARGET_OPENRISC_JSP_SERVER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/openrisc/or1k.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Julius Baxter * * julius@opencores.org * * * * Copyright (C) 2013 by Marek Czerski * * ma.czerski@gmail.com * * * * Copyright (C) 2013 by Franck Jullien * * elec4fun@gmail.com * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <jtag/jtag.h> #include <target/register.h> #include <target/target.h> #include <target/breakpoints.h> #include <target/target_type.h> #include <helper/time_support.h> #include <helper/fileio.h> #include "or1k_tap.h" #include "or1k.h" #include "or1k_du.h" LIST_HEAD(tap_list); LIST_HEAD(du_list); static int or1k_remove_breakpoint(struct target *target, struct breakpoint *breakpoint); static int or1k_read_core_reg(struct target *target, int num); static int or1k_write_core_reg(struct target *target, int num); static struct or1k_core_reg *or1k_core_reg_list_arch_info; static const struct or1k_core_reg_init or1k_init_reg_list[] = { {"r0", GROUP0 + 1024, "org.gnu.gdb.or1k.group0", NULL}, {"r1", GROUP0 + 1025, "org.gnu.gdb.or1k.group0", NULL}, {"r2", GROUP0 + 1026, "org.gnu.gdb.or1k.group0", NULL}, {"r3", GROUP0 + 1027, "org.gnu.gdb.or1k.group0", NULL}, {"r4", GROUP0 + 1028, "org.gnu.gdb.or1k.group0", NULL}, {"r5", GROUP0 + 1029, "org.gnu.gdb.or1k.group0", NULL}, {"r6", GROUP0 + 1030, "org.gnu.gdb.or1k.group0", NULL}, {"r7", GROUP0 + 1031, "org.gnu.gdb.or1k.group0", NULL}, {"r8", GROUP0 + 1032, "org.gnu.gdb.or1k.group0", NULL}, {"r9", GROUP0 + 1033, "org.gnu.gdb.or1k.group0", NULL}, {"r10", GROUP0 + 1034, "org.gnu.gdb.or1k.group0", NULL}, {"r11", GROUP0 + 1035, "org.gnu.gdb.or1k.group0", NULL}, {"r12", GROUP0 + 1036, "org.gnu.gdb.or1k.group0", NULL}, {"r13", GROUP0 + 1037, "org.gnu.gdb.or1k.group0", NULL}, {"r14", GROUP0 + 1038, "org.gnu.gdb.or1k.group0", NULL}, {"r15", GROUP0 + 1039, "org.gnu.gdb.or1k.group0", NULL}, {"r16", GROUP0 + 1040, "org.gnu.gdb.or1k.group0", NULL}, {"r17", GROUP0 + 1041, "org.gnu.gdb.or1k.group0", NULL}, {"r18", GROUP0 + 1042, "org.gnu.gdb.or1k.group0", NULL}, {"r19", GROUP0 + 1043, "org.gnu.gdb.or1k.group0", NULL}, {"r20", GROUP0 + 1044, "org.gnu.gdb.or1k.group0", NULL}, {"r21", GROUP0 + 1045, "org.gnu.gdb.or1k.group0", NULL}, {"r22", GROUP0 + 1046, "org.gnu.gdb.or1k.group0", NULL}, {"r23", GROUP0 + 1047, "org.gnu.gdb.or1k.group0", NULL}, {"r24", GROUP0 + 1048, "org.gnu.gdb.or1k.group0", NULL}, {"r25", GROUP0 + 1049, "org.gnu.gdb.or1k.group0", NULL}, {"r26", GROUP0 + 1050, "org.gnu.gdb.or1k.group0", NULL}, {"r27", GROUP0 + 1051, "org.gnu.gdb.or1k.group0", NULL}, {"r28", GROUP0 + 1052, "org.gnu.gdb.or1k.group0", NULL}, {"r29", GROUP0 + 1053, "org.gnu.gdb.or1k.group0", NULL}, {"r30", GROUP0 + 1054, "org.gnu.gdb.or1k.group0", NULL}, {"r31", GROUP0 + 1055, "org.gnu.gdb.or1k.group0", NULL}, {"ppc", GROUP0 + 18, "org.gnu.gdb.or1k.group0", NULL}, {"npc", GROUP0 + 16, "org.gnu.gdb.or1k.group0", NULL}, {"sr", GROUP0 + 17, "org.gnu.gdb.or1k.group0", NULL}, {"vr", GROUP0 + 0, "org.gnu.gdb.or1k.group0", "system"}, {"upr", GROUP0 + 1, "org.gnu.gdb.or1k.group0", "system"}, {"cpucfgr", GROUP0 + 2, "org.gnu.gdb.or1k.group0", "system"}, {"dmmucfgr", GROUP0 + 3, "org.gnu.gdb.or1k.group0", "system"}, {"immucfgr", GROUP0 + 4, "org.gnu.gdb.or1k.group0", "system"}, {"dccfgr", GROUP0 + 5, "org.gnu.gdb.or1k.group0", "system"}, {"iccfgr", GROUP0 + 6, "org.gnu.gdb.or1k.group0", "system"}, {"dcfgr", GROUP0 + 7, "org.gnu.gdb.or1k.group0", "system"}, {"pccfgr", GROUP0 + 8, "org.gnu.gdb.or1k.group0", "system"}, {"fpcsr", GROUP0 + 20, "org.gnu.gdb.or1k.group0", "system"}, {"epcr0", GROUP0 + 32, "org.gnu.gdb.or1k.group0", "system"}, {"epcr1", GROUP0 + 33, "org.gnu.gdb.or1k.group0", "system"}, {"epcr2", GROUP0 + 34, "org.gnu.gdb.or1k.group0", "system"}, {"epcr3", GROUP0 + 35, "org.gnu.gdb.or1k.group0", "system"}, {"epcr4", GROUP0 + 36, "org.gnu.gdb.or1k.group0", "system"}, {"epcr5", GROUP0 + 37, "org.gnu.gdb.or1k.group0", "system"}, {"epcr6", GROUP0 + 38, "org.gnu.gdb.or1k.group0", "system"}, {"epcr7", GROUP0 + 39, "org.gnu.gdb.or1k.group0", "system"}, {"epcr8", GROUP0 + 40, "org.gnu.gdb.or1k.group0", "system"}, {"epcr9", GROUP0 + 41, "org.gnu.gdb.or1k.group0", "system"}, {"epcr10", GROUP0 + 42, "org.gnu.gdb.or1k.group0", "system"}, {"epcr11", GROUP0 + 43, "org.gnu.gdb.or1k.group0", "system"}, {"epcr12", GROUP0 + 44, "org.gnu.gdb.or1k.group0", "system"}, {"epcr13", GROUP0 + 45, "org.gnu.gdb.or1k.group0", "system"}, {"epcr14", GROUP0 + 46, "org.gnu.gdb.or1k.group0", "system"}, {"epcr15", GROUP0 + 47, "org.gnu.gdb.or1k.group0", "system"}, {"eear0", GROUP0 + 48, "org.gnu.gdb.or1k.group0", "system"}, {"eear1", GROUP0 + 49, "org.gnu.gdb.or1k.group0", "system"}, {"eear2", GROUP0 + 50, "org.gnu.gdb.or1k.group0", "system"}, {"eear3", GROUP0 + 51, "org.gnu.gdb.or1k.group0", "system"}, {"eear4", GROUP0 + 52, "org.gnu.gdb.or1k.group0", "system"}, {"eear5", GROUP0 + 53, "org.gnu.gdb.or1k.group0", "system"}, {"eear6", GROUP0 + 54, "org.gnu.gdb.or1k.group0", "system"}, {"eear7", GROUP0 + 55, "org.gnu.gdb.or1k.group0", "system"}, {"eear8", GROUP0 + 56, "org.gnu.gdb.or1k.group0", "system"}, {"eear9", GROUP0 + 57, "org.gnu.gdb.or1k.group0", "system"}, {"eear10", GROUP0 + 58, "org.gnu.gdb.or1k.group0", "system"}, {"eear11", GROUP0 + 59, "org.gnu.gdb.or1k.group0", "system"}, {"eear12", GROUP0 + 60, "org.gnu.gdb.or1k.group0", "system"}, {"eear13", GROUP0 + 61, "org.gnu.gdb.or1k.group0", "system"}, {"eear14", GROUP0 + 62, "org.gnu.gdb.or1k.group0", "system"}, {"eear15", GROUP0 + 63, "org.gnu.gdb.or1k.group0", "system"}, {"esr0", GROUP0 + 64, "org.gnu.gdb.or1k.group0", "system"}, {"esr1", GROUP0 + 65, "org.gnu.gdb.or1k.group0", "system"}, {"esr2", GROUP0 + 66, "org.gnu.gdb.or1k.group0", "system"}, {"esr3", GROUP0 + 67, "org.gnu.gdb.or1k.group0", "system"}, {"esr4", GROUP0 + 68, "org.gnu.gdb.or1k.group0", "system"}, {"esr5", GROUP0 + 69, "org.gnu.gdb.or1k.group0", "system"}, {"esr6", GROUP0 + 70, "org.gnu.gdb.or1k.group0", "system"}, {"esr7", GROUP0 + 71, "org.gnu.gdb.or1k.group0", "system"}, {"esr8", GROUP0 + 72, "org.gnu.gdb.or1k.group0", "system"}, {"esr9", GROUP0 + 73, "org.gnu.gdb.or1k.group0", "system"}, {"esr10", GROUP0 + 74, "org.gnu.gdb.or1k.group0", "system"}, {"esr11", GROUP0 + 75, "org.gnu.gdb.or1k.group0", "system"}, {"esr12", GROUP0 + 76, "org.gnu.gdb.or1k.group0", "system"}, {"esr13", GROUP0 + 77, "org.gnu.gdb.or1k.group0", "system"}, {"esr14", GROUP0 + 78, "org.gnu.gdb.or1k.group0", "system"}, {"esr15", GROUP0 + 79, "org.gnu.gdb.or1k.group0", "system"}, {"dmmuucr", GROUP1 + 0, "org.gnu.gdb.or1k.group1", "dmmu"}, {"dmmuupr", GROUP1 + 1, "org.gnu.gdb.or1k.group1", "dmmu"}, {"dtlbeir", GROUP1 + 2, "org.gnu.gdb.or1k.group1", "dmmu"}, {"datbmr0", GROUP1 + 4, "org.gnu.gdb.or1k.group1", "dmmu"}, {"datbmr1", GROUP1 + 5, "org.gnu.gdb.or1k.group1", "dmmu"}, {"datbmr2", GROUP1 + 6, "org.gnu.gdb.or1k.group1", "dmmu"}, {"datbmr3", GROUP1 + 7, "org.gnu.gdb.or1k.group1", "dmmu"}, {"datbtr0", GROUP1 + 8, "org.gnu.gdb.or1k.group1", "dmmu"}, {"datbtr1", GROUP1 + 9, "org.gnu.gdb.or1k.group1", "dmmu"}, {"datbtr2", GROUP1 + 10, "org.gnu.gdb.or1k.group1", "dmmu"}, {"datbtr3", GROUP1 + 11, "org.gnu.gdb.or1k.group1", "dmmu"}, {"immucr", GROUP2 + 0, "org.gnu.gdb.or1k.group2", "immu"}, {"immupr", GROUP2 + 1, "org.gnu.gdb.or1k.group2", "immu"}, {"itlbeir", GROUP2 + 2, "org.gnu.gdb.or1k.group2", "immu"}, {"iatbmr0", GROUP2 + 4, "org.gnu.gdb.or1k.group2", "immu"}, {"iatbmr1", GROUP2 + 5, "org.gnu.gdb.or1k.group2", "immu"}, {"iatbmr2", GROUP2 + 6, "org.gnu.gdb.or1k.group2", "immu"}, {"iatbmr3", GROUP2 + 7, "org.gnu.gdb.or1k.group2", "immu"}, {"iatbtr0", GROUP2 + 8, "org.gnu.gdb.or1k.group2", "immu"}, {"iatbtr1", GROUP2 + 9, "org.gnu.gdb.or1k.group2", "immu"}, {"iatbtr2", GROUP2 + 10, "org.gnu.gdb.or1k.group2", "immu"}, {"iatbtr3", GROUP2 + 11, "org.gnu.gdb.or1k.group2", "immu"}, {"dccr", GROUP3 + 0, "org.gnu.gdb.or1k.group3", "dcache"}, {"dcbpr", GROUP3 + 1, "org.gnu.gdb.or1k.group3", "dcache"}, {"dcbfr", GROUP3 + 2, "org.gnu.gdb.or1k.group3", "dcache"}, {"dcbir", GROUP3 + 3, "org.gnu.gdb.or1k.group3", "dcache"}, {"dcbwr", GROUP3 + 4, "org.gnu.gdb.or1k.group3", "dcache"}, {"dcblr", GROUP3 + 5, "org.gnu.gdb.or1k.group3", "dcache"}, {"iccr", GROUP4 + 0, "org.gnu.gdb.or1k.group4", "icache"}, {"icbpr", GROUP4 + 1, "org.gnu.gdb.or1k.group4", "icache"}, {"icbir", GROUP4 + 2, "org.gnu.gdb.or1k.group4", "icache"}, {"icblr", GROUP4 + 3, "org.gnu.gdb.or1k.group4", "icache"}, {"maclo", GROUP5 + 0, "org.gnu.gdb.or1k.group5", "mac"}, {"machi", GROUP5 + 1, "org.gnu.gdb.or1k.group5", "mac"}, {"dvr0", GROUP6 + 0, "org.gnu.gdb.or1k.group6", "debug"}, {"dvr1", GROUP6 + 1, "org.gnu.gdb.or1k.group6", "debug"}, {"dvr2", GROUP6 + 2, "org.gnu.gdb.or1k.group6", "debug"}, {"dvr3", GROUP6 + 3, "org.gnu.gdb.or1k.group6", "debug"}, {"dvr4", GROUP6 + 4, "org.gnu.gdb.or1k.group6", "debug"}, {"dvr5", GROUP6 + 5, "org.gnu.gdb.or1k.group6", "debug"}, {"dvr6", GROUP6 + 6, "org.gnu.gdb.or1k.group6", "debug"}, {"dvr7", GROUP6 + 7, "org.gnu.gdb.or1k.group6", "debug"}, {"dcr0", GROUP6 + 8, "org.gnu.gdb.or1k.group6", "debug"}, {"dcr1", GROUP6 + 9, "org.gnu.gdb.or1k.group6", "debug"}, {"dcr2", GROUP6 + 10, "org.gnu.gdb.or1k.group6", "debug"}, {"dcr3", GROUP6 + 11, "org.gnu.gdb.or1k.group6", "debug"}, {"dcr4", GROUP6 + 12, "org.gnu.gdb.or1k.group6", "debug"}, {"dcr5", GROUP6 + 13, "org.gnu.gdb.or1k.group6", "debug"}, {"dcr6", GROUP6 + 14, "org.gnu.gdb.or1k.group6", "debug"}, {"dcr7", GROUP6 + 15, "org.gnu.gdb.or1k.group6", "debug"}, {"dmr1", GROUP6 + 16, "org.gnu.gdb.or1k.group6", "debug"}, {"dmr2", GROUP6 + 17, "org.gnu.gdb.or1k.group6", "debug"}, {"dcwr0", GROUP6 + 18, "org.gnu.gdb.or1k.group6", "debug"}, {"dcwr1", GROUP6 + 19, "org.gnu.gdb.or1k.group6", "debug"}, {"dsr", GROUP6 + 20, "org.gnu.gdb.or1k.group6", "debug"}, {"drr", GROUP6 + 21, "org.gnu.gdb.or1k.group6", "debug"}, {"pccr0", GROUP7 + 0, "org.gnu.gdb.or1k.group7", "perf"}, {"pccr1", GROUP7 + 1, "org.gnu.gdb.or1k.group7", "perf"}, {"pccr2", GROUP7 + 2, "org.gnu.gdb.or1k.group7", "perf"}, {"pccr3", GROUP7 + 3, "org.gnu.gdb.or1k.group7", "perf"}, {"pccr4", GROUP7 + 4, "org.gnu.gdb.or1k.group7", "perf"}, {"pccr5", GROUP7 + 5, "org.gnu.gdb.or1k.group7", "perf"}, {"pccr6", GROUP7 + 6, "org.gnu.gdb.or1k.group7", "perf"}, {"pccr7", GROUP7 + 7, "org.gnu.gdb.or1k.group7", "perf"}, {"pcmr0", GROUP7 + 8, "org.gnu.gdb.or1k.group7", "perf"}, {"pcmr1", GROUP7 + 9, "org.gnu.gdb.or1k.group7", "perf"}, {"pcmr2", GROUP7 + 10, "org.gnu.gdb.or1k.group7", "perf"}, {"pcmr3", GROUP7 + 11, "org.gnu.gdb.or1k.group7", "perf"}, {"pcmr4", GROUP7 + 12, "org.gnu.gdb.or1k.group7", "perf"}, {"pcmr5", GROUP7 + 13, "org.gnu.gdb.or1k.group7", "perf"}, {"pcmr6", GROUP7 + 14, "org.gnu.gdb.or1k.group7", "perf"}, {"pcmr7", GROUP7 + 15, "org.gnu.gdb.or1k.group7", "perf"}, {"pmr", GROUP8 + 0, "org.gnu.gdb.or1k.group8", "power"}, {"picmr", GROUP9 + 0, "org.gnu.gdb.or1k.group9", "pic"}, {"picsr", GROUP9 + 2, "org.gnu.gdb.or1k.group9", "pic"}, {"ttmr", GROUP10 + 0, "org.gnu.gdb.or1k.group10", "timer"}, {"ttcr", GROUP10 + 1, "org.gnu.gdb.or1k.group10", "timer"}, }; static int or1k_add_reg(struct target *target, struct or1k_core_reg *new_reg) { struct or1k_common *or1k = target_to_or1k(target); int reg_list_size = or1k->nb_regs * sizeof(struct or1k_core_reg); or1k_core_reg_list_arch_info = realloc(or1k_core_reg_list_arch_info, reg_list_size + sizeof(struct or1k_core_reg)); memcpy(&or1k_core_reg_list_arch_info[or1k->nb_regs], new_reg, sizeof(struct or1k_core_reg)); or1k_core_reg_list_arch_info[or1k->nb_regs].list_num = or1k->nb_regs; or1k->nb_regs++; return ERROR_OK; } static int or1k_create_reg_list(struct target *target) { struct or1k_common *or1k = target_to_or1k(target); LOG_DEBUG("-"); or1k_core_reg_list_arch_info = malloc(ARRAY_SIZE(or1k_init_reg_list) * sizeof(struct or1k_core_reg)); for (int i = 0; i < (int)ARRAY_SIZE(or1k_init_reg_list); i++) { or1k_core_reg_list_arch_info[i].name = or1k_init_reg_list[i].name; or1k_core_reg_list_arch_info[i].spr_num = or1k_init_reg_list[i].spr_num; or1k_core_reg_list_arch_info[i].group = or1k_init_reg_list[i].group; or1k_core_reg_list_arch_info[i].feature = or1k_init_reg_list[i].feature; or1k_core_reg_list_arch_info[i].list_num = i; or1k_core_reg_list_arch_info[i].target = NULL; or1k_core_reg_list_arch_info[i].or1k_common = NULL; } or1k->nb_regs = ARRAY_SIZE(or1k_init_reg_list); struct or1k_core_reg new_reg; new_reg.target = NULL; new_reg.or1k_common = NULL; char name[32]; for (int way = 0; way < 4; way++) { for (int i = 0; i < 128; i++) { sprintf(name, "dtlbw%dmr%d", way, i); new_reg.name = strdup(name); new_reg.spr_num = GROUP1 + 512 + i + (way * 256); new_reg.feature = "org.gnu.gdb.or1k.group1"; new_reg.group = "dmmu"; or1k_add_reg(target, &new_reg); sprintf(name, "dtlbw%dtr%d", way, i); new_reg.name = strdup(name); new_reg.spr_num = GROUP1 + 640 + i + (way * 256); new_reg.feature = "org.gnu.gdb.or1k.group1"; new_reg.group = "dmmu"; or1k_add_reg(target, &new_reg); sprintf(name, "itlbw%dmr%d", way, i); new_reg.name = strdup(name); new_reg.spr_num = GROUP2 + 512 + i + (way * 256); new_reg.feature = "org.gnu.gdb.or1k.group2"; new_reg.group = "immu"; or1k_add_reg(target, &new_reg); sprintf(name, "itlbw%dtr%d", way, i); new_reg.name = strdup(name); new_reg.spr_num = GROUP2 + 640 + i + (way * 256); new_reg.feature = "org.gnu.gdb.or1k.group2"; new_reg.group = "immu"; or1k_add_reg(target, &new_reg); } } return ERROR_OK; } static int or1k_jtag_read_regs(struct or1k_common *or1k, uint32_t *regs) { struct or1k_du *du_core = or1k_jtag_to_du(&or1k->jtag); LOG_DEBUG("-"); return du_core->or1k_jtag_read_cpu(&or1k->jtag, or1k->arch_info[OR1K_REG_R0].spr_num, OR1K_REG_R31 + 1, regs + OR1K_REG_R0); } static int or1k_jtag_write_regs(struct or1k_common *or1k, uint32_t *regs) { struct or1k_du *du_core = or1k_jtag_to_du(&or1k->jtag); LOG_DEBUG("-"); return du_core->or1k_jtag_write_cpu(&or1k->jtag, or1k->arch_info[OR1K_REG_R0].spr_num, OR1K_REG_R31 + 1, ®s[OR1K_REG_R0]); } static int or1k_save_context(struct target *target) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); int regs_read = 0; int retval; LOG_DEBUG("-"); for (int i = 0; i < OR1KNUMCOREREGS; i++) { if (!or1k->core_cache->reg_list[i].valid) { if (i == OR1K_REG_PPC || i == OR1K_REG_NPC || i == OR1K_REG_SR) { retval = du_core->or1k_jtag_read_cpu(&or1k->jtag, or1k->arch_info[i].spr_num, 1, &or1k->core_regs[i]); if (retval != ERROR_OK) return retval; } else if (!regs_read) { /* read gpr registers at once (but only one time in this loop) */ retval = or1k_jtag_read_regs(or1k, or1k->core_regs); if (retval != ERROR_OK) return retval; /* prevent next reads in this loop */ regs_read = 1; } /* We've just updated the core_reg[i], now update the core cache */ or1k_read_core_reg(target, i); } } return ERROR_OK; } static int or1k_restore_context(struct target *target) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); int reg_write = 0; int retval; LOG_DEBUG("-"); for (int i = 0; i < OR1KNUMCOREREGS; i++) { if (or1k->core_cache->reg_list[i].dirty) { or1k_write_core_reg(target, i); if (i == OR1K_REG_PPC || i == OR1K_REG_NPC || i == OR1K_REG_SR) { retval = du_core->or1k_jtag_write_cpu(&or1k->jtag, or1k->arch_info[i].spr_num, 1, &or1k->core_regs[i]); if (retval != ERROR_OK) { LOG_ERROR("Error while restoring context"); return retval; } } else reg_write = 1; } } if (reg_write) { /* read gpr registers at once (but only one time in this loop) */ retval = or1k_jtag_write_regs(or1k, or1k->core_regs); if (retval != ERROR_OK) { LOG_ERROR("Error while restoring context"); return retval; } } return ERROR_OK; } static int or1k_read_core_reg(struct target *target, int num) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); uint32_t reg_value; LOG_DEBUG("-"); if ((num < 0) || (num >= or1k->nb_regs)) return ERROR_COMMAND_SYNTAX_ERROR; if ((num >= 0) && (num < OR1KNUMCOREREGS)) { reg_value = or1k->core_regs[num]; buf_set_u32(or1k->core_cache->reg_list[num].value, 0, 32, reg_value); LOG_DEBUG("Read core reg %i value 0x%08" PRIx32, num, reg_value); or1k->core_cache->reg_list[num].valid = true; or1k->core_cache->reg_list[num].dirty = false; } else { /* This is an spr, always read value from HW */ int retval = du_core->or1k_jtag_read_cpu(&or1k->jtag, or1k->arch_info[num].spr_num, 1, ®_value); if (retval != ERROR_OK) { LOG_ERROR("Error while reading spr 0x%08" PRIx32, or1k->arch_info[num].spr_num); return retval; } buf_set_u32(or1k->core_cache->reg_list[num].value, 0, 32, reg_value); LOG_DEBUG("Read spr reg %i value 0x%08" PRIx32, num, reg_value); } return ERROR_OK; } static int or1k_write_core_reg(struct target *target, int num) { struct or1k_common *or1k = target_to_or1k(target); LOG_DEBUG("-"); if ((num < 0) || (num >= OR1KNUMCOREREGS)) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t reg_value = buf_get_u32(or1k->core_cache->reg_list[num].value, 0, 32); or1k->core_regs[num] = reg_value; LOG_DEBUG("Write core reg %i value 0x%08" PRIx32, num, reg_value); or1k->core_cache->reg_list[num].valid = true; or1k->core_cache->reg_list[num].dirty = false; return ERROR_OK; } static int or1k_get_core_reg(struct reg *reg) { struct or1k_core_reg *or1k_reg = reg->arch_info; struct target *target = or1k_reg->target; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; return or1k_read_core_reg(target, or1k_reg->list_num); } static int or1k_set_core_reg(struct reg *reg, uint8_t *buf) { struct or1k_core_reg *or1k_reg = reg->arch_info; struct target *target = or1k_reg->target; struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); uint32_t value = buf_get_u32(buf, 0, 32); LOG_DEBUG("-"); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; if (or1k_reg->list_num < OR1KNUMCOREREGS) { buf_set_u32(reg->value, 0, 32, value); reg->dirty = true; reg->valid = true; } else { /* This is an spr, write it to the HW */ int retval = du_core->or1k_jtag_write_cpu(&or1k->jtag, or1k_reg->spr_num, 1, &value); if (retval != ERROR_OK) { LOG_ERROR("Error while writing spr 0x%08" PRIx32, or1k_reg->spr_num); return retval; } } return ERROR_OK; } static const struct reg_arch_type or1k_reg_type = { .get = or1k_get_core_reg, .set = or1k_set_core_reg, }; static struct reg_cache *or1k_build_reg_cache(struct target *target) { struct or1k_common *or1k = target_to_or1k(target); struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(or1k->nb_regs, sizeof(struct reg)); struct or1k_core_reg *arch_info = malloc((or1k->nb_regs) * sizeof(struct or1k_core_reg)); struct reg_feature *feature; LOG_DEBUG("-"); /* Build the process context cache */ cache->name = "OpenRISC 1000 registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = or1k->nb_regs; (*cache_p) = cache; or1k->core_cache = cache; or1k->arch_info = arch_info; for (int i = 0; i < or1k->nb_regs; i++) { arch_info[i] = or1k_core_reg_list_arch_info[i]; arch_info[i].target = target; arch_info[i].or1k_common = or1k; reg_list[i].name = or1k_core_reg_list_arch_info[i].name; feature = malloc(sizeof(struct reg_feature)); feature->name = or1k_core_reg_list_arch_info[i].feature; reg_list[i].feature = feature; reg_list[i].group = or1k_core_reg_list_arch_info[i].group; reg_list[i].size = 32; reg_list[i].value = calloc(1, 4); reg_list[i].dirty = false; reg_list[i].valid = false; reg_list[i].type = &or1k_reg_type; reg_list[i].arch_info = &arch_info[i]; reg_list[i].number = i; reg_list[i].exist = true; } return cache; } static int or1k_debug_entry(struct target *target) { LOG_DEBUG("-"); int retval = or1k_save_context(target); if (retval != ERROR_OK) { LOG_ERROR("Error while calling or1k_save_context"); return retval; } struct or1k_common *or1k = target_to_or1k(target); uint32_t addr = or1k->core_regs[OR1K_REG_NPC]; if (breakpoint_find(target, addr)) /* Halted on a breakpoint, step back to permit executing the instruction there */ retval = or1k_set_core_reg(&or1k->core_cache->reg_list[OR1K_REG_NPC], (uint8_t *)&addr); return retval; } static int or1k_halt(struct target *target) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_DEBUG("Target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("Target was in unknown state when halt was requested"); if (target->state == TARGET_RESET) { if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { LOG_ERROR("Can't request a halt while in reset if nSRST pulls nTRST"); return ERROR_TARGET_FAILURE; } else { target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } } int retval = du_core->or1k_cpu_stall(&or1k->jtag, CPU_STALL); if (retval != ERROR_OK) { LOG_ERROR("Impossible to stall the CPU"); return retval; } target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int or1k_is_cpu_running(struct target *target, int *running) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); int retval; int tries = 0; const int RETRIES_MAX = 5; /* Have a retry loop to determine of the CPU is running. If target has been hard reset for any reason, it might take a couple of goes before it's ready again. */ while (tries < RETRIES_MAX) { tries++; retval = du_core->or1k_is_cpu_running(&or1k->jtag, running); if (retval != ERROR_OK) { LOG_WARNING("Debug IF CPU control reg read failure."); /* Try once to restart the JTAG infrastructure - quite possibly the board has just been reset. */ LOG_WARNING("Resetting JTAG TAP state and reconnecting to debug IF."); du_core->or1k_jtag_init(&or1k->jtag); LOG_WARNING("...attempt %d of %d", tries, RETRIES_MAX); alive_sleep(2); continue; } else return ERROR_OK; } LOG_ERROR("Could not re-establish communication with target"); return retval; } static int or1k_poll(struct target *target) { int retval; int running; retval = or1k_is_cpu_running(target, &running); if (retval != ERROR_OK) { LOG_ERROR("Error while calling or1k_is_cpu_running"); return retval; } /* check for processor halted */ if (!running) { /* It's actually stalled, so update our software's state */ if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { target->state = TARGET_HALTED; retval = or1k_debug_entry(target); if (retval != ERROR_OK) { LOG_ERROR("Error while calling or1k_debug_entry"); return retval; } target_call_event_callbacks(target, TARGET_EVENT_HALTED); } else if (target->state == TARGET_DEBUG_RUNNING) { target->state = TARGET_HALTED; retval = or1k_debug_entry(target); if (retval != ERROR_OK) { LOG_ERROR("Error while calling or1k_debug_entry"); return retval; } target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } } else { /* ... target is running */ /* If target was supposed to be stalled, stall it again */ if (target->state == TARGET_HALTED) { target->state = TARGET_RUNNING; retval = or1k_halt(target); if (retval != ERROR_OK) { LOG_ERROR("Error while calling or1k_halt"); return retval; } retval = or1k_debug_entry(target); if (retval != ERROR_OK) { LOG_ERROR("Error while calling or1k_debug_entry"); return retval; } target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } target->state = TARGET_RUNNING; } return ERROR_OK; } static int or1k_assert_reset(struct target *target) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); LOG_DEBUG("-"); int retval = du_core->or1k_cpu_reset(&or1k->jtag, CPU_RESET); if (retval != ERROR_OK) { LOG_ERROR("Error while asserting RESET"); return retval; } return ERROR_OK; } static int or1k_deassert_reset(struct target *target) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); LOG_DEBUG("-"); int retval = du_core->or1k_cpu_reset(&or1k->jtag, CPU_NOT_RESET); if (retval != ERROR_OK) { LOG_ERROR("Error while deasserting RESET"); return retval; } return ERROR_OK; } static int or1k_soft_reset_halt(struct target *target) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); LOG_DEBUG("-"); int retval = du_core->or1k_cpu_stall(&or1k->jtag, CPU_STALL); if (retval != ERROR_OK) { LOG_ERROR("Error while stalling the CPU"); return retval; } retval = or1k_assert_reset(target); if (retval != ERROR_OK) return retval; retval = or1k_deassert_reset(target); if (retval != ERROR_OK) return retval; return ERROR_OK; } static bool is_any_soft_breakpoint(struct target *target) { struct breakpoint *breakpoint = target->breakpoints; LOG_DEBUG("-"); while (breakpoint) if (breakpoint->type == BKPT_SOFT) return true; return false; } static int or1k_resume_or_step(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution, int step) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); struct breakpoint *breakpoint = NULL; uint32_t resume_pc; uint32_t debug_reg_list[OR1K_DEBUG_REG_NUM]; LOG_DEBUG("Addr: 0x%" PRIx32 ", stepping: %s, handle breakpoints %s\n", address, step ? "yes" : "no", handle_breakpoints ? "yes" : "no"); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) target_free_all_working_areas(target); /* current ? continue on current pc : continue at <address> */ if (!current) buf_set_u32(or1k->core_cache->reg_list[OR1K_REG_NPC].value, 0, 32, address); int retval = or1k_restore_context(target); if (retval != ERROR_OK) { LOG_ERROR("Error while calling or1k_restore_context"); return retval; } /* read debug registers (starting from DMR1 register) */ retval = du_core->or1k_jtag_read_cpu(&or1k->jtag, OR1K_DMR1_CPU_REG_ADD, OR1K_DEBUG_REG_NUM, debug_reg_list); if (retval != ERROR_OK) { LOG_ERROR("Error while reading debug registers"); return retval; } /* Clear Debug Reason Register (DRR) */ debug_reg_list[OR1K_DEBUG_REG_DRR] = 0; /* Clear watchpoint break generation in Debug Mode Register 2 (DMR2) */ debug_reg_list[OR1K_DEBUG_REG_DMR2] &= ~OR1K_DMR2_WGB; if (step) /* Set the single step trigger in Debug Mode Register 1 (DMR1) */ debug_reg_list[OR1K_DEBUG_REG_DMR1] |= OR1K_DMR1_ST | OR1K_DMR1_BT; else /* Clear the single step trigger in Debug Mode Register 1 (DMR1) */ debug_reg_list[OR1K_DEBUG_REG_DMR1] &= ~(OR1K_DMR1_ST | OR1K_DMR1_BT); /* Set traps to be handled by the debug unit in the Debug Stop Register (DSR). Check if we have any software breakpoints in place before setting this value - the kernel, for instance, relies on l.trap instructions not stalling the processor ! */ if (is_any_soft_breakpoint(target) == true) debug_reg_list[OR1K_DEBUG_REG_DSR] |= OR1K_DSR_TE; /* Write debug registers (starting from DMR1 register) */ retval = du_core->or1k_jtag_write_cpu(&or1k->jtag, OR1K_DMR1_CPU_REG_ADD, OR1K_DEBUG_REG_NUM, debug_reg_list); if (retval != ERROR_OK) { LOG_ERROR("Error while writing back debug registers"); return retval; } resume_pc = buf_get_u32(or1k->core_cache->reg_list[OR1K_REG_NPC].value, 0, 32); /* The front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { LOG_DEBUG("Unset breakpoint at 0x%08" TARGET_PRIxADDR, breakpoint->address); retval = or1k_remove_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; } } /* Unstall time */ retval = du_core->or1k_cpu_stall(&or1k->jtag, CPU_UNSTALL); if (retval != ERROR_OK) { LOG_ERROR("Error while unstalling the CPU"); return retval; } if (step) target->debug_reason = DBG_REASON_SINGLESTEP; else target->debug_reason = DBG_REASON_NOTHALTED; /* Registers are now invalid */ register_cache_invalidate(or1k->core_cache); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); LOG_DEBUG("Target resumed at 0x%08" PRIx32, resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); LOG_DEBUG("Target debug resumed at 0x%08" PRIx32, resume_pc); } return ERROR_OK; } static int or1k_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { return or1k_resume_or_step(target, current, address, handle_breakpoints, debug_execution, NO_SINGLE_STEP); } static int or1k_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { return or1k_resume_or_step(target, current, address, handle_breakpoints, 0, SINGLE_STEP); } static int or1k_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); uint8_t data; LOG_DEBUG("Adding breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, id: %" PRIu32, breakpoint->address, breakpoint->length, breakpoint->type, breakpoint->unique_id); /* Only support SW breakpoints for now. */ if (breakpoint->type == BKPT_HARD) LOG_ERROR("HW breakpoints not supported for now. Doing SW breakpoint."); /* Read and save the instruction */ int retval = du_core->or1k_jtag_read_memory(&or1k->jtag, breakpoint->address, 4, 1, &data); if (retval != ERROR_OK) { LOG_ERROR("Error while reading the instruction at 0x%08" TARGET_PRIxADDR, breakpoint->address); return retval; } free(breakpoint->orig_instr); breakpoint->orig_instr = malloc(breakpoint->length); memcpy(breakpoint->orig_instr, &data, breakpoint->length); /* Sub in the OR1K trap instruction */ uint8_t or1k_trap_insn[4]; target_buffer_set_u32(target, or1k_trap_insn, OR1K_TRAP_INSTR); retval = du_core->or1k_jtag_write_memory(&or1k->jtag, breakpoint->address, 4, 1, or1k_trap_insn); if (retval != ERROR_OK) { LOG_ERROR("Error while writing OR1K_TRAP_INSTR at 0x%08" TARGET_PRIxADDR, breakpoint->address); return retval; } /* invalidate instruction cache */ uint32_t addr = breakpoint->address; retval = du_core->or1k_jtag_write_cpu(&or1k->jtag, OR1K_ICBIR_CPU_REG_ADD, 1, &addr); if (retval != ERROR_OK) { LOG_ERROR("Error while invalidating the ICACHE"); return retval; } return ERROR_OK; } static int or1k_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); LOG_DEBUG("Removing breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, id: %" PRIu32, breakpoint->address, breakpoint->length, breakpoint->type, breakpoint->unique_id); /* Only support SW breakpoints for now. */ if (breakpoint->type == BKPT_HARD) LOG_ERROR("HW breakpoints not supported for now. Doing SW breakpoint."); /* Replace the removed instruction */ int retval = du_core->or1k_jtag_write_memory(&or1k->jtag, breakpoint->address, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) { LOG_ERROR("Error while writing back the instruction at 0x%08" TARGET_PRIxADDR, breakpoint->address); return retval; } /* invalidate instruction cache */ uint32_t addr = breakpoint->address; retval = du_core->or1k_jtag_write_cpu(&or1k->jtag, OR1K_ICBIR_CPU_REG_ADD, 1, &addr); if (retval != ERROR_OK) { LOG_ERROR("Error while invalidating the ICACHE"); return retval; } return ERROR_OK; } static int or1k_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int or1k_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int or1k_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); LOG_DEBUG("Read memory at 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: 0x%08" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !buffer) { LOG_ERROR("Bad arguments"); return ERROR_COMMAND_SYNTAX_ERROR; } if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) { LOG_ERROR("Can't handle unaligned memory access"); return ERROR_TARGET_UNALIGNED_ACCESS; } return du_core->or1k_jtag_read_memory(&or1k->jtag, address, size, count, buffer); } static int or1k_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); LOG_DEBUG("Write memory at 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: 0x%08" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !buffer) { LOG_ERROR("Bad arguments"); return ERROR_COMMAND_SYNTAX_ERROR; } if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) { LOG_ERROR("Can't handle unaligned memory access"); return ERROR_TARGET_UNALIGNED_ACCESS; } return du_core->or1k_jtag_write_memory(&or1k->jtag, address, size, count, buffer); } static int or1k_init_target(struct command_context *cmd_ctx, struct target *target) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); struct or1k_jtag *jtag = &or1k->jtag; if (!du_core) { LOG_ERROR("No debug unit selected"); return ERROR_FAIL; } if (!jtag->tap_ip) { LOG_ERROR("No tap selected"); return ERROR_FAIL; } or1k->jtag.tap = target->tap; or1k->jtag.or1k_jtag_inited = 0; or1k->jtag.or1k_jtag_module_selected = -1; or1k->jtag.target = target; or1k_build_reg_cache(target); return ERROR_OK; } static int or1k_target_create(struct target *target, Jim_Interp *interp) { if (!target->tap) return ERROR_FAIL; struct or1k_common *or1k = calloc(1, sizeof(struct or1k_common)); target->arch_info = or1k; or1k_create_reg_list(target); or1k_tap_vjtag_register(); or1k_tap_xilinx_bscan_register(); or1k_tap_mohor_register(); or1k_du_adv_register(); return ERROR_OK; } static int or1k_examine(struct target *target) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); if (!target_was_examined(target)) { target_set_examined(target); int running; int retval = du_core->or1k_is_cpu_running(&or1k->jtag, &running); if (retval != ERROR_OK) { LOG_ERROR("Couldn't read the CPU state"); return retval; } else { if (running) target->state = TARGET_RUNNING; else { LOG_DEBUG("Target is halted"); /* This is the first time we examine the target, * it is stalled and we don't know why. Let's * assume this is because of a debug reason. */ if (target->state == TARGET_UNKNOWN) target->debug_reason = DBG_REASON_DBGRQ; target->state = TARGET_HALTED; } } } return ERROR_OK; } static int or1k_arch_state(struct target *target) { return ERROR_OK; } static int or1k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { struct or1k_common *or1k = target_to_or1k(target); if (reg_class == REG_CLASS_GENERAL) { /* We will have this called whenever GDB connects. */ int retval = or1k_save_context(target); if (retval != ERROR_OK) { LOG_ERROR("Error while calling or1k_save_context"); return retval; } *reg_list_size = OR1KNUMCOREREGS; /* this is free()'d back in gdb_server.c's gdb_get_register_packet() */ *reg_list = malloc((*reg_list_size) * sizeof(struct reg *)); for (int i = 0; i < OR1KNUMCOREREGS; i++) (*reg_list)[i] = &or1k->core_cache->reg_list[i]; } else { *reg_list_size = or1k->nb_regs; *reg_list = malloc((*reg_list_size) * sizeof(struct reg *)); for (int i = 0; i < or1k->nb_regs; i++) (*reg_list)[i] = &or1k->core_cache->reg_list[i]; } return ERROR_OK; } static int or1k_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) { return ERROR_FAIL; } static int or1k_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { return ERROR_FAIL; } static int or1k_profiling(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { struct timeval timeout, now; struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); int retval = ERROR_OK; gettimeofday(&timeout, NULL); timeval_add_time(&timeout, seconds, 0); LOG_INFO("Starting or1k profiling. Sampling npc as fast as we can..."); /* Make sure the target is running */ target_poll(target); if (target->state == TARGET_HALTED) retval = target_resume(target, 1, 0, 0, 0); if (retval != ERROR_OK) { LOG_ERROR("Error while resuming target"); return retval; } uint32_t sample_count = 0; for (;;) { uint32_t reg_value; retval = du_core->or1k_jtag_read_cpu(&or1k->jtag, GROUP0 + 16 /* NPC */, 1, ®_value); if (retval != ERROR_OK) { LOG_ERROR("Error while reading NPC"); return retval; } samples[sample_count++] = reg_value; gettimeofday(&now, NULL); if ((sample_count >= max_num_samples) || timeval_compare(&now, &timeout) > 0) { LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count); break; } } *num_samples = sample_count; return retval; } COMMAND_HANDLER(or1k_tap_select_command_handler) { struct target *target = get_current_target(CMD_CTX); struct or1k_common *or1k = target_to_or1k(target); struct or1k_jtag *jtag = &or1k->jtag; struct or1k_tap_ip *or1k_tap; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; list_for_each_entry(or1k_tap, &tap_list, list) { if (or1k_tap->name) { if (!strcmp(CMD_ARGV[0], or1k_tap->name)) { jtag->tap_ip = or1k_tap; LOG_INFO("%s tap selected", or1k_tap->name); return ERROR_OK; } } } LOG_ERROR("%s unknown, no tap selected", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_HANDLER(or1k_tap_list_command_handler) { struct or1k_tap_ip *or1k_tap; if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; list_for_each_entry(or1k_tap, &tap_list, list) { if (or1k_tap->name) command_print(CMD, "%s", or1k_tap->name); } return ERROR_OK; } COMMAND_HANDLER(or1k_du_select_command_handler) { struct target *target = get_current_target(CMD_CTX); struct or1k_common *or1k = target_to_or1k(target); struct or1k_jtag *jtag = &or1k->jtag; struct or1k_du *or1k_du; if (CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; list_for_each_entry(or1k_du, &du_list, list) { if (or1k_du->name) { if (!strcmp(CMD_ARGV[0], or1k_du->name)) { jtag->du_core = or1k_du; LOG_INFO("%s debug unit selected", or1k_du->name); if (CMD_ARGC == 2) { int options; COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], options); or1k_du->options = options; LOG_INFO("Option %x is passed to %s debug unit" , options, or1k_du->name); } return ERROR_OK; } } } LOG_ERROR("%s unknown, no debug unit selected", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_HANDLER(or1k_du_list_command_handler) { struct or1k_du *or1k_du; if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; list_for_each_entry(or1k_du, &du_list, list) { if (or1k_du->name) command_print(CMD, "%s", or1k_du->name); } return ERROR_OK; } COMMAND_HANDLER(or1k_addreg_command_handler) { struct target *target = get_current_target(CMD_CTX); struct or1k_core_reg new_reg; if (CMD_ARGC != 4) return ERROR_COMMAND_SYNTAX_ERROR; new_reg.target = NULL; new_reg.or1k_common = NULL; uint32_t addr; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], addr); new_reg.name = strdup(CMD_ARGV[0]); new_reg.spr_num = addr; new_reg.feature = strdup(CMD_ARGV[2]); new_reg.group = strdup(CMD_ARGV[3]); or1k_add_reg(target, &new_reg); LOG_DEBUG("Add reg \"%s\" @ 0x%08" PRIx32 ", group \"%s\", feature \"%s\"", new_reg.name, addr, new_reg.group, new_reg.feature); return ERROR_OK; } static const struct command_registration or1k_hw_ip_command_handlers[] = { { .name = "tap_select", .handler = or1k_tap_select_command_handler, .mode = COMMAND_ANY, .usage = "name", .help = "Select the TAP core to use", }, { .name = "tap_list", .handler = or1k_tap_list_command_handler, .mode = COMMAND_ANY, .usage = "", .help = "Display available TAP core", }, { .name = "du_select", .handler = or1k_du_select_command_handler, .mode = COMMAND_ANY, .usage = "name", .help = "Select the Debug Unit core to use", }, { .name = "du_list", .handler = or1k_du_list_command_handler, .mode = COMMAND_ANY, .usage = "select_tap name", .help = "Display available Debug Unit core", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration or1k_reg_command_handlers[] = { { .name = "addreg", .handler = or1k_addreg_command_handler, .mode = COMMAND_ANY, .usage = "name addr feature group", .help = "Add a register to the register list", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration or1k_command_handlers[] = { { .chain = or1k_reg_command_handlers, }, { .chain = or1k_hw_ip_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type or1k_target = { .name = "or1k", .poll = or1k_poll, .arch_state = or1k_arch_state, .target_request_data = NULL, .halt = or1k_halt, .resume = or1k_resume, .step = or1k_step, .assert_reset = or1k_assert_reset, .deassert_reset = or1k_deassert_reset, .soft_reset_halt = or1k_soft_reset_halt, .get_gdb_reg_list = or1k_get_gdb_reg_list, .read_memory = or1k_read_memory, .write_memory = or1k_write_memory, .checksum_memory = or1k_checksum_memory, .commands = or1k_command_handlers, .add_breakpoint = or1k_add_breakpoint, .remove_breakpoint = or1k_remove_breakpoint, .add_watchpoint = or1k_add_watchpoint, .remove_watchpoint = or1k_remove_watchpoint, .target_create = or1k_target_create, .init_target = or1k_init_target, .examine = or1k_examine, .get_gdb_fileio_info = or1k_get_gdb_fileio_info, .profiling = or1k_profiling, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/openrisc/or1k.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2011 by Julius Baxter * * julius@opencores.org * * * * Copyright (C) 2013 by Marek Czerski * * ma.czerski@gmail.com * * * * Copyright (C) 2013 by Franck Jullien * * elec4fun@gmail.com * * * ***************************************************************************/ #ifndef OPENOCD_TARGET_OPENRISC_OR1K_H #define OPENOCD_TARGET_OPENRISC_OR1K_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <target/target.h> /* SPR groups start address */ #define GROUP0 (0 << 11) #define GROUP1 (1 << 11) #define GROUP2 (2 << 11) #define GROUP3 (3 << 11) #define GROUP4 (4 << 11) #define GROUP5 (5 << 11) #define GROUP6 (6 << 11) #define GROUP7 (7 << 11) #define GROUP8 (8 << 11) #define GROUP9 (9 << 11) #define GROUP10 (10 << 11) /* OR1K registers */ enum or1k_reg_nums { OR1K_REG_R0 = 0, OR1K_REG_R1, OR1K_REG_R2, OR1K_REG_R3, OR1K_REG_R4, OR1K_REG_R5, OR1K_REG_R6, OR1K_REG_R7, OR1K_REG_R8, OR1K_REG_R9, OR1K_REG_R10, OR1K_REG_R11, OR1K_REG_R12, OR1K_REG_R13, OR1K_REG_R14, OR1K_REG_R15, OR1K_REG_R16, OR1K_REG_R17, OR1K_REG_R18, OR1K_REG_R19, OR1K_REG_R20, OR1K_REG_R21, OR1K_REG_R22, OR1K_REG_R23, OR1K_REG_R24, OR1K_REG_R25, OR1K_REG_R26, OR1K_REG_R27, OR1K_REG_R28, OR1K_REG_R29, OR1K_REG_R30, OR1K_REG_R31, OR1K_REG_PPC, OR1K_REG_NPC, OR1K_REG_SR, OR1KNUMCOREREGS }; struct or1k_jtag { struct jtag_tap *tap; int or1k_jtag_inited; int or1k_jtag_module_selected; uint8_t *current_reg_idx; struct or1k_tap_ip *tap_ip; struct or1k_du *du_core; struct target *target; }; struct or1k_common { struct or1k_jtag jtag; struct reg_cache *core_cache; uint32_t core_regs[OR1KNUMCOREREGS]; int nb_regs; struct or1k_core_reg *arch_info; }; static inline struct or1k_common * target_to_or1k(struct target *target) { return (struct or1k_common *)target->arch_info; } struct or1k_core_reg { const char *name; uint32_t list_num; /* Index in register cache */ uint32_t spr_num; /* Number in architecture's SPR space */ struct target *target; struct or1k_common *or1k_common; const char *feature; /* feature name in XML tdesc file */ const char *group; /* register group in XML tdesc file */ }; struct or1k_core_reg_init { const char *name; uint32_t spr_num; /* Number in architecture's SPR space */ const char *feature; /* feature name in XML tdesc file */ const char *group; /* register group in XML tdesc file */ }; /* ORBIS32 Trap instruction */ #define OR1K_TRAP_INSTR 0x21000001 enum or1k_debug_reg_nums { OR1K_DEBUG_REG_DMR1 = 0, OR1K_DEBUG_REG_DMR2, OR1K_DEBUG_REG_DCWR0, OR1K_DEBUG_REG_DCWR1, OR1K_DEBUG_REG_DSR, OR1K_DEBUG_REG_DRR, OR1K_DEBUG_REG_NUM }; #define NO_SINGLE_STEP 0 #define SINGLE_STEP 1 /* OR1K Debug registers and bits needed for resuming */ #define OR1K_DEBUG_REG_BASE GROUP6 /* Debug registers Base address */ #define OR1K_DMR1_CPU_REG_ADD (OR1K_DEBUG_REG_BASE + 16) /* Debug Mode Register 1 0x3010 */ #define OR1K_DMR1_ST 0x00400000 /* Single-step trace */ #define OR1K_DMR1_BT 0x00800000 /* Branch trace */ #define OR1K_DMR2_WGB 0x003ff000 /* Watchpoints generating breakpoint */ #define OR1K_DSR_TE 0x00002000 /* Trap exception */ /* OR1K Instruction cache registers needed for invalidating instruction * memory during adding and removing breakpoints. */ #define OR1K_ICBIR_CPU_REG_ADD ((4 << 11) + 2) /* IC Block Invalidate Register 0x2002 */ #endif /* OPENOCD_TARGET_OPENRISC_OR1K_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/openrisc/or1k_du.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2013 Franck Jullien * * elec4fun@gmail.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_OPENRISC_OR1K_DU_H #define OPENOCD_TARGET_OPENRISC_OR1K_DU_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #define CPU_STALL 0 #define CPU_UNSTALL 1 #define CPU_RESET 0 #define CPU_NOT_RESET 1 int or1k_du_adv_register(void); /* Linear list over all available or1k debug unit */ extern struct list_head du_list; struct or1k_du { const char *name; struct list_head list; int options; int (*or1k_jtag_init)(struct or1k_jtag *jtag_info); int (*or1k_is_cpu_running)(struct or1k_jtag *jtag_info, int *running); int (*or1k_cpu_stall)(struct or1k_jtag *jtag_info, int action); int (*or1k_cpu_reset)(struct or1k_jtag *jtag_info, int action); int (*or1k_jtag_read_cpu)(struct or1k_jtag *jtag_info, uint32_t addr, int count, uint32_t *value); int (*or1k_jtag_write_cpu)(struct or1k_jtag *jtag_info, uint32_t addr, int count, const uint32_t *value); int (*or1k_jtag_read_memory)(struct or1k_jtag *jtag_info, uint32_t addr, uint32_t size, int count, uint8_t *buffer); int (*or1k_jtag_write_memory)(struct or1k_jtag *jtag_info, uint32_t addr, uint32_t size, int count, const uint8_t *buffer); }; static inline struct or1k_du *or1k_jtag_to_du(struct or1k_jtag *jtag_info) { return (struct or1k_du *)jtag_info->du_core; } static inline struct or1k_du *or1k_to_du(struct or1k_common *or1k) { struct or1k_jtag *jtag = &or1k->jtag; return (struct or1k_du *)jtag->du_core; } int or1k_adv_jtag_jsp_xfer(struct or1k_jtag *jtag_info, int *out_len, unsigned char *out_buffer, int *in_len, unsigned char *in_buffer); #endif /* OPENOCD_TARGET_OPENRISC_OR1K_DU_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/openrisc/or1k_du_adv.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013-2014 by Franck Jullien * * elec4fun@gmail.com * * * * Inspired from adv_jtag_bridge which is: * * Copyright (C) 2008-2010 Nathan Yawn * * nyawn@opencores.net * * * * And the Mohor interface version of this file which is: * * Copyright (C) 2011 by Julius Baxter * * julius@opencores.org * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "or1k_tap.h" #include "or1k.h" #include "or1k_du.h" #include "jsp_server.h" #include <helper/crc32.h> #include <jtag/jtag.h> #include <target/target.h> #define JSP_BANNER "\n\r" \ "******************************\n\r" \ "** JTAG Serial Port **\n\r" \ "******************************\n\r" \ "\n\r" #define NO_OPTION 0 /* This an option to the adv debug unit. * If this is defined, status bits will be skipped on burst * reads and writes to improve download speeds. * This option must match the RTL configured option. */ #define ADBG_USE_HISPEED 1 /* This an option to the adv debug unit. * If this is defined, the JTAG Serial Port Server is started. * This option must match the RTL configured option. */ #define ENABLE_JSP_SERVER 2 /* Define this if you intend to use the JSP in a system with multiple * devices on the JTAG chain */ #define ENABLE_JSP_MULTI 4 /* Definitions for the top-level debug unit. This really just consists * of a single register, used to select the active debug module ("chain"). */ #define DBG_MODULE_SELECT_REG_SIZE 2 #define DBG_MAX_MODULES 4 #define DC_NONE -1 #define DC_WISHBONE 0 #define DC_CPU0 1 #define DC_CPU1 2 #define DC_JSP 3 /* CPU control register bits mask */ #define DBG_CPU_CR_STALL 0x01 #define DBG_CPU_CR_RESET 0x02 /* These are for the internal registers in the Wishbone module * The first is the length of the index register, * the indexes of the various registers are defined after that. */ #define DBG_WB_REG_SEL_LEN 1 #define DBG_WB_REG_ERROR 0 /* Opcode definitions for the Wishbone module. */ #define DBG_WB_OPCODE_LEN 4 #define DBG_WB_CMD_NOP 0x0 #define DBG_WB_CMD_BWRITE8 0x1 #define DBG_WB_CMD_BWRITE16 0x2 #define DBG_WB_CMD_BWRITE32 0x3 #define DBG_WB_CMD_BREAD8 0x5 #define DBG_WB_CMD_BREAD16 0x6 #define DBG_WB_CMD_BREAD32 0x7 #define DBG_WB_CMD_IREG_WR 0x9 #define DBG_WB_CMD_IREG_SEL 0xd /* Internal register definitions for the CPU0 module. */ #define DBG_CPU0_REG_SEL_LEN 1 #define DBG_CPU0_REG_STATUS 0 /* Opcode definitions for the first CPU module. */ #define DBG_CPU0_OPCODE_LEN 4 #define DBG_CPU0_CMD_NOP 0x0 #define DBG_CPU0_CMD_BWRITE32 0x3 #define DBG_CPU0_CMD_BREAD32 0x7 #define DBG_CPU0_CMD_IREG_WR 0x9 #define DBG_CPU0_CMD_IREG_SEL 0xd /* Internal register definitions for the CPU1 module. */ #define DBG_CPU1_REG_SEL_LEN 1 #define DBG_CPU1_REG_STATUS 0 /* Opcode definitions for the second CPU module. */ #define DBG_CPU1_OPCODE_LEN 4 #define DBG_CPU1_CMD_NOP 0x0 #define DBG_CPU1_CMD_BWRITE32 0x3 #define DBG_CPU1_CMD_BREAD32 0x7 #define DBG_CPU1_CMD_IREG_WR 0x9 #define DBG_CPU1_CMD_IREG_SEL 0xd #define MAX_READ_STATUS_WAIT 10 #define MAX_READ_BUSY_RETRY 2 #define MAX_READ_CRC_RETRY 2 #define MAX_WRITE_CRC_RETRY 2 #define BURST_READ_READY 1 #define MAX_BUS_ERRORS 2 #define MAX_BURST_SIZE (4 * 1024) #define STATUS_BYTES 1 #define CRC_LEN 4 static struct or1k_du or1k_du_adv; static const char * const chain_name[] = {"WISHBONE", "CPU0", "CPU1", "JSP"}; static int find_status_bit(void *_buf, int len) { int i = 0; int count = 0; int ret = -1; uint8_t *buf = _buf; while (!(buf[i] & (1 << count++)) && (i < len)) { if (count == 8) { count = 0; i++; } } if (i < len) ret = (i * 8) + count; return ret; } static int or1k_adv_jtag_init(struct or1k_jtag *jtag_info) { struct or1k_tap_ip *tap_ip = jtag_info->tap_ip; int retval = tap_ip->init(jtag_info); if (retval != ERROR_OK) { LOG_ERROR("TAP initialization failed"); return retval; } /* TAP is now configured to communicate with debug interface */ jtag_info->or1k_jtag_inited = 1; /* TAP reset - not sure what state debug module chain is in now */ jtag_info->or1k_jtag_module_selected = DC_NONE; jtag_info->current_reg_idx = malloc(DBG_MAX_MODULES * sizeof(uint8_t)); memset(jtag_info->current_reg_idx, 0, DBG_MAX_MODULES * sizeof(uint8_t)); if (or1k_du_adv.options & ADBG_USE_HISPEED) LOG_INFO("adv debug unit is configured with option ADBG_USE_HISPEED"); if (or1k_du_adv.options & ENABLE_JSP_SERVER) { if (or1k_du_adv.options & ENABLE_JSP_MULTI) LOG_INFO("adv debug unit is configured with option ENABLE_JSP_MULTI"); LOG_INFO("adv debug unit is configured with option ENABLE_JSP_SERVER"); retval = jsp_init(jtag_info, JSP_BANNER); if (retval != ERROR_OK) { LOG_ERROR("Couldn't start the JSP server"); return retval; } } LOG_DEBUG("Init done"); return ERROR_OK; } /* Selects one of the modules in the debug unit * (e.g. wishbone unit, CPU0, etc.) */ static int adbg_select_module(struct or1k_jtag *jtag_info, int chain) { if (jtag_info->or1k_jtag_module_selected == chain) return ERROR_OK; /* MSB of the data out must be set to 1, indicating a module * select command */ uint8_t data = chain | (1 << DBG_MODULE_SELECT_REG_SIZE); LOG_DEBUG("Select module: %s", chain_name[chain]); struct scan_field field; field.num_bits = (DBG_MODULE_SELECT_REG_SIZE + 1); field.out_value = &data; field.in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE); int retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; jtag_info->or1k_jtag_module_selected = chain; return ERROR_OK; } /* Set the index of the desired register in the currently selected module * 1 bit module select command * 4 bits opcode * n bits index */ static int adbg_select_ctrl_reg(struct or1k_jtag *jtag_info, uint8_t regidx) { int index_len; uint32_t opcode; uint32_t opcode_len; /* If this reg is already selected, don't do a JTAG transaction */ if (jtag_info->current_reg_idx[jtag_info->or1k_jtag_module_selected] == regidx) return ERROR_OK; switch (jtag_info->or1k_jtag_module_selected) { case DC_WISHBONE: index_len = DBG_WB_REG_SEL_LEN; opcode = DBG_WB_CMD_IREG_SEL; opcode_len = DBG_WB_OPCODE_LEN; break; case DC_CPU0: index_len = DBG_CPU0_REG_SEL_LEN; opcode = DBG_CPU0_CMD_IREG_SEL; opcode_len = DBG_CPU0_OPCODE_LEN; break; case DC_CPU1: index_len = DBG_CPU1_REG_SEL_LEN; opcode = DBG_CPU1_CMD_IREG_SEL; opcode_len = DBG_CPU1_OPCODE_LEN; break; default: LOG_ERROR("Illegal debug chain selected (%i) while selecting control register", jtag_info->or1k_jtag_module_selected); return ERROR_FAIL; } /* MSB must be 0 to access modules */ uint32_t data = (opcode & ~(1 << opcode_len)) << index_len; data |= regidx; struct scan_field field; field.num_bits = (opcode_len + 1) + index_len; field.out_value = (uint8_t *)&data; field.in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE); int retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; jtag_info->current_reg_idx[jtag_info->or1k_jtag_module_selected] = regidx; return ERROR_OK; } /* Write control register (internal to the debug unit) */ static int adbg_ctrl_write(struct or1k_jtag *jtag_info, uint8_t regidx, uint32_t *cmd_data, int length_bits) { int index_len; uint32_t opcode; uint32_t opcode_len; LOG_DEBUG("Write control register %" PRId8 ": 0x%08" PRIx32, regidx, cmd_data[0]); int retval = adbg_select_ctrl_reg(jtag_info, regidx); if (retval != ERROR_OK) { LOG_ERROR("Error while calling adbg_select_ctrl_reg"); return retval; } switch (jtag_info->or1k_jtag_module_selected) { case DC_WISHBONE: index_len = DBG_WB_REG_SEL_LEN; opcode = DBG_WB_CMD_IREG_WR; opcode_len = DBG_WB_OPCODE_LEN; break; case DC_CPU0: index_len = DBG_CPU0_REG_SEL_LEN; opcode = DBG_CPU0_CMD_IREG_WR; opcode_len = DBG_CPU0_OPCODE_LEN; break; case DC_CPU1: index_len = DBG_CPU1_REG_SEL_LEN; opcode = DBG_CPU1_CMD_IREG_WR; opcode_len = DBG_CPU1_OPCODE_LEN; break; default: LOG_ERROR("Illegal debug chain selected (%i) while doing control write", jtag_info->or1k_jtag_module_selected); return ERROR_FAIL; } struct scan_field field[2]; /* MSB must be 0 to access modules */ uint32_t data = (opcode & ~(1 << opcode_len)) << index_len; data |= regidx; field[0].num_bits = length_bits; field[0].out_value = (uint8_t *)cmd_data; field[0].in_value = NULL; field[1].num_bits = (opcode_len + 1) + index_len; field[1].out_value = (uint8_t *)&data; field[1].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 2, field, TAP_IDLE); return jtag_execute_queue(); } /* Reads control register (internal to the debug unit) */ static int adbg_ctrl_read(struct or1k_jtag *jtag_info, uint32_t regidx, uint32_t *data, int length_bits) { int retval = adbg_select_ctrl_reg(jtag_info, regidx); if (retval != ERROR_OK) { LOG_ERROR("Error while calling adbg_select_ctrl_reg"); return retval; } int opcode_len; uint32_t opcode; /* There is no 'read' command, We write a NOP to read */ switch (jtag_info->or1k_jtag_module_selected) { case DC_WISHBONE: opcode = DBG_WB_CMD_NOP; opcode_len = DBG_WB_OPCODE_LEN; break; case DC_CPU0: opcode = DBG_CPU0_CMD_NOP; opcode_len = DBG_CPU0_OPCODE_LEN; break; case DC_CPU1: opcode = DBG_CPU1_CMD_NOP; opcode_len = DBG_CPU1_OPCODE_LEN; break; default: LOG_ERROR("Illegal debug chain selected (%i) while doing control read", jtag_info->or1k_jtag_module_selected); return ERROR_FAIL; } /* Zero MSB = op for module, not top-level debug unit */ uint32_t outdata = opcode & ~(0x1 << opcode_len); struct scan_field field[2]; field[0].num_bits = length_bits; field[0].out_value = NULL; field[0].in_value = (uint8_t *)data; field[1].num_bits = opcode_len + 1; field[1].out_value = (uint8_t *)&outdata; field[1].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 2, field, TAP_IDLE); return jtag_execute_queue(); } /* sends out a burst command to the selected module in the debug unit (MSB to LSB): * 1-bit module command * 4-bit opcode * 32-bit address * 16-bit length (of the burst, in words) */ static int adbg_burst_command(struct or1k_jtag *jtag_info, uint32_t opcode, uint32_t address, uint16_t length_words) { uint32_t data[2]; /* Set up the data */ data[0] = length_words | (address << 16); /* MSB must be 0 to access modules */ data[1] = ((address >> 16) | ((opcode & 0xf) << 16)) & ~(0x1 << 20); struct scan_field field; field.num_bits = 53; field.out_value = (uint8_t *)&data[0]; field.in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE); return jtag_execute_queue(); } static int adbg_wb_burst_read(struct or1k_jtag *jtag_info, int size, int count, uint32_t start_address, uint8_t *data) { int retry_full_crc = 0; int retry_full_busy = 0; int retval; uint8_t opcode; LOG_DEBUG("Doing burst read, word size %d, word count %d, start address 0x%08" PRIx32, size, count, start_address); /* Select the appropriate opcode */ switch (jtag_info->or1k_jtag_module_selected) { case DC_WISHBONE: if (size == 1) opcode = DBG_WB_CMD_BREAD8; else if (size == 2) opcode = DBG_WB_CMD_BREAD16; else if (size == 4) opcode = DBG_WB_CMD_BREAD32; else { LOG_WARNING("Tried burst read with invalid word size (%d)," "defaulting to 4-byte words", size); opcode = DBG_WB_CMD_BREAD32; } break; case DC_CPU0: if (size == 4) opcode = DBG_CPU0_CMD_BREAD32; else { LOG_WARNING("Tried burst read with invalid word size (%d)," "defaulting to 4-byte words", size); opcode = DBG_CPU0_CMD_BREAD32; } break; case DC_CPU1: if (size == 4) opcode = DBG_CPU1_CMD_BREAD32; else { LOG_WARNING("Tried burst read with invalid word size (%d)," "defaulting to 4-byte words", size); opcode = DBG_CPU0_CMD_BREAD32; } break; default: LOG_ERROR("Illegal debug chain selected (%i) while doing burst read", jtag_info->or1k_jtag_module_selected); return ERROR_FAIL; } int total_size_bytes = count * size; struct scan_field field; uint8_t *in_buffer = malloc(total_size_bytes + CRC_LEN + STATUS_BYTES); retry_read_full: /* Send the BURST READ command, returns TAP to idle state */ retval = adbg_burst_command(jtag_info, opcode, start_address, count); if (retval != ERROR_OK) goto out; field.num_bits = (total_size_bytes + CRC_LEN + STATUS_BYTES) * 8; field.out_value = NULL; field.in_value = in_buffer; jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) goto out; /* Look for the start bit in the first (STATUS_BYTES * 8) bits */ int shift = find_status_bit(in_buffer, STATUS_BYTES); /* We expect the status bit to be in the first byte */ if (shift < 0) { if (retry_full_busy++ < MAX_READ_BUSY_RETRY) { LOG_WARNING("Burst read timed out"); goto retry_read_full; } else { LOG_ERROR("Burst read failed"); retval = ERROR_FAIL; goto out; } } buffer_shr(in_buffer, total_size_bytes + CRC_LEN + STATUS_BYTES, shift); uint32_t crc_read; memcpy(data, in_buffer, total_size_bytes); memcpy(&crc_read, &in_buffer[total_size_bytes], 4); uint32_t crc_calc = crc32_le(CRC32_POLY_LE, 0xffffffff, data, total_size_bytes); if (crc_calc != crc_read) { LOG_WARNING("CRC ERROR! Computed 0x%08" PRIx32 ", read CRC 0x%08" PRIx32, crc_calc, crc_read); if (retry_full_crc++ < MAX_READ_CRC_RETRY) goto retry_read_full; else { LOG_ERROR("Burst read failed"); retval = ERROR_FAIL; goto out; } } else LOG_DEBUG("CRC OK!"); /* Now, read the error register, and retry/recompute as necessary */ if (jtag_info->or1k_jtag_module_selected == DC_WISHBONE && !(or1k_du_adv.options & ADBG_USE_HISPEED)) { uint32_t err_data[2] = {0, 0}; uint32_t addr; int bus_error_retries = 0; /* First, just get 1 bit...read address only if necessary */ retval = adbg_ctrl_read(jtag_info, DBG_WB_REG_ERROR, err_data, 1); if (retval != ERROR_OK) goto out; /* Then we have a problem */ if (err_data[0] & 0x1) { retval = adbg_ctrl_read(jtag_info, DBG_WB_REG_ERROR, err_data, 33); if (retval != ERROR_OK) goto out; addr = (err_data[0] >> 1) | (err_data[1] << 31); LOG_WARNING("WB bus error during burst read, address 0x%08" PRIx32 ", retrying!", addr); bus_error_retries++; if (bus_error_retries > MAX_BUS_ERRORS) { LOG_ERROR("Max WB bus errors reached during burst read"); retval = ERROR_FAIL; goto out; } /* Don't call retry_do(), a JTAG reset won't help a WB bus error */ /* Write 1 bit, to reset the error register */ err_data[0] = 1; retval = adbg_ctrl_write(jtag_info, DBG_WB_REG_ERROR, err_data, 1); if (retval != ERROR_OK) goto out; goto retry_read_full; } } out: free(in_buffer); return retval; } /* Set up and execute a burst write to a contiguous set of addresses */ static int adbg_wb_burst_write(struct or1k_jtag *jtag_info, const uint8_t *data, int size, int count, unsigned long start_address) { int retry_full_crc = 0; int retval; uint8_t opcode; LOG_DEBUG("Doing burst write, word size %d, word count %d," "start address 0x%08lx", size, count, start_address); /* Select the appropriate opcode */ switch (jtag_info->or1k_jtag_module_selected) { case DC_WISHBONE: if (size == 1) opcode = DBG_WB_CMD_BWRITE8; else if (size == 2) opcode = DBG_WB_CMD_BWRITE16; else if (size == 4) opcode = DBG_WB_CMD_BWRITE32; else { LOG_DEBUG("Tried WB burst write with invalid word size (%d)," "defaulting to 4-byte words", size); opcode = DBG_WB_CMD_BWRITE32; } break; case DC_CPU0: if (size == 4) opcode = DBG_CPU0_CMD_BWRITE32; else { LOG_DEBUG("Tried CPU0 burst write with invalid word size (%d)," "defaulting to 4-byte words", size); opcode = DBG_CPU0_CMD_BWRITE32; } break; case DC_CPU1: if (size == 4) opcode = DBG_CPU1_CMD_BWRITE32; else { LOG_DEBUG("Tried CPU1 burst write with invalid word size (%d)," "defaulting to 4-byte words", size); opcode = DBG_CPU0_CMD_BWRITE32; } break; default: LOG_ERROR("Illegal debug chain selected (%i) while doing burst write", jtag_info->or1k_jtag_module_selected); return ERROR_FAIL; } retry_full_write: /* Send the BURST WRITE command, returns TAP to idle state */ retval = adbg_burst_command(jtag_info, opcode, start_address, count); if (retval != ERROR_OK) return retval; struct scan_field field[3]; /* Write a start bit so it knows when to start counting */ uint8_t value = 1; field[0].num_bits = 1; field[0].out_value = &value; field[0].in_value = NULL; uint32_t crc_calc = crc32_le(CRC32_POLY_LE, 0xffffffff, data, count * size); field[1].num_bits = count * size * 8; field[1].out_value = data; field[1].in_value = NULL; field[2].num_bits = 32; field[2].out_value = (uint8_t *)&crc_calc; field[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, field, TAP_DRSHIFT); /* Read the 'CRC match' bit, and go to idle */ field[0].num_bits = 1; field[0].out_value = NULL; field[0].in_value = &value; jtag_add_dr_scan(jtag_info->tap, 1, field, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (!value) { LOG_WARNING("CRC ERROR! match bit after write is %" PRIi8 " (computed CRC 0x%08" PRIx32 ")", value, crc_calc); if (retry_full_crc++ < MAX_WRITE_CRC_RETRY) goto retry_full_write; else return ERROR_FAIL; } else LOG_DEBUG("CRC OK!\n"); /* Now, read the error register, and retry/recompute as necessary */ if (jtag_info->or1k_jtag_module_selected == DC_WISHBONE && !(or1k_du_adv.options & ADBG_USE_HISPEED)) { uint32_t addr; int bus_error_retries = 0; uint32_t err_data[2] = {0, 0}; /* First, just get 1 bit...read address only if necessary */ retval = adbg_ctrl_read(jtag_info, DBG_WB_REG_ERROR, err_data, 1); if (retval != ERROR_OK) return retval; /* Then we have a problem */ if (err_data[0] & 0x1) { retval = adbg_ctrl_read(jtag_info, DBG_WB_REG_ERROR, err_data, 33); if (retval != ERROR_OK) return retval; addr = (err_data[0] >> 1) | (err_data[1] << 31); LOG_WARNING("WB bus error during burst write, address 0x%08" PRIx32 ", retrying!", addr); bus_error_retries++; if (bus_error_retries > MAX_BUS_ERRORS) { LOG_ERROR("Max WB bus errors reached during burst read"); retval = ERROR_FAIL; return retval; } /* Don't call retry_do(), a JTAG reset won't help a WB bus error */ /* Write 1 bit, to reset the error register */ err_data[0] = 1; retval = adbg_ctrl_write(jtag_info, DBG_WB_REG_ERROR, err_data, 1); if (retval != ERROR_OK) return retval; goto retry_full_write; } } return ERROR_OK; } /* Currently hard set in functions to 32-bits */ static int or1k_adv_jtag_read_cpu(struct or1k_jtag *jtag_info, uint32_t addr, int count, uint32_t *value) { int retval; if (!jtag_info->or1k_jtag_inited) { retval = or1k_adv_jtag_init(jtag_info); if (retval != ERROR_OK) return retval; } retval = adbg_select_module(jtag_info, DC_CPU0); if (retval != ERROR_OK) return retval; return adbg_wb_burst_read(jtag_info, 4, count, addr, (uint8_t *)value); } static int or1k_adv_jtag_write_cpu(struct or1k_jtag *jtag_info, uint32_t addr, int count, const uint32_t *value) { int retval; if (!jtag_info->or1k_jtag_inited) { retval = or1k_adv_jtag_init(jtag_info); if (retval != ERROR_OK) return retval; } retval = adbg_select_module(jtag_info, DC_CPU0); if (retval != ERROR_OK) return retval; return adbg_wb_burst_write(jtag_info, (uint8_t *)value, 4, count, addr); } static int or1k_adv_cpu_stall(struct or1k_jtag *jtag_info, int action) { int retval; if (!jtag_info->or1k_jtag_inited) { retval = or1k_adv_jtag_init(jtag_info); if (retval != ERROR_OK) return retval; } retval = adbg_select_module(jtag_info, DC_CPU0); if (retval != ERROR_OK) return retval; uint32_t cpu_cr; retval = adbg_ctrl_read(jtag_info, DBG_CPU0_REG_STATUS, &cpu_cr, 2); if (retval != ERROR_OK) return retval; if (action == CPU_STALL) cpu_cr |= DBG_CPU_CR_STALL; else cpu_cr &= ~DBG_CPU_CR_STALL; retval = adbg_select_module(jtag_info, DC_CPU0); if (retval != ERROR_OK) return retval; return adbg_ctrl_write(jtag_info, DBG_CPU0_REG_STATUS, &cpu_cr, 2); } static int or1k_adv_is_cpu_running(struct or1k_jtag *jtag_info, int *running) { int retval; if (!jtag_info->or1k_jtag_inited) { retval = or1k_adv_jtag_init(jtag_info); if (retval != ERROR_OK) return retval; } int current = jtag_info->or1k_jtag_module_selected; retval = adbg_select_module(jtag_info, DC_CPU0); if (retval != ERROR_OK) return retval; uint32_t cpu_cr = 0; retval = adbg_ctrl_read(jtag_info, DBG_CPU0_REG_STATUS, &cpu_cr, 2); if (retval != ERROR_OK) return retval; if (cpu_cr & DBG_CPU_CR_STALL) *running = 0; else *running = 1; if (current != DC_NONE) { retval = adbg_select_module(jtag_info, current); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int or1k_adv_cpu_reset(struct or1k_jtag *jtag_info, int action) { int retval; if (!jtag_info->or1k_jtag_inited) { retval = or1k_adv_jtag_init(jtag_info); if (retval != ERROR_OK) return retval; } retval = adbg_select_module(jtag_info, DC_CPU0); if (retval != ERROR_OK) return retval; uint32_t cpu_cr; retval = adbg_ctrl_read(jtag_info, DBG_CPU0_REG_STATUS, &cpu_cr, 2); if (retval != ERROR_OK) return retval; if (action == CPU_RESET) cpu_cr |= DBG_CPU_CR_RESET; else cpu_cr &= ~DBG_CPU_CR_RESET; retval = adbg_select_module(jtag_info, DC_CPU0); if (retval != ERROR_OK) return retval; return adbg_ctrl_write(jtag_info, DBG_CPU0_REG_STATUS, &cpu_cr, 2); } static int or1k_adv_jtag_read_memory(struct or1k_jtag *jtag_info, uint32_t addr, uint32_t size, int count, uint8_t *buffer) { LOG_DEBUG("Reading WB%" PRIu32 " at 0x%08" PRIx32, size * 8, addr); int retval; if (!jtag_info->or1k_jtag_inited) { retval = or1k_adv_jtag_init(jtag_info); if (retval != ERROR_OK) return retval; } retval = adbg_select_module(jtag_info, DC_WISHBONE); if (retval != ERROR_OK) return retval; int block_count_left = count; uint32_t block_count_address = addr; uint8_t *block_count_buffer = buffer; while (block_count_left) { int blocks_this_round = (block_count_left > MAX_BURST_SIZE) ? MAX_BURST_SIZE : block_count_left; retval = adbg_wb_burst_read(jtag_info, size, blocks_this_round, block_count_address, block_count_buffer); if (retval != ERROR_OK) return retval; block_count_left -= blocks_this_round; block_count_address += size * MAX_BURST_SIZE; block_count_buffer += size * MAX_BURST_SIZE; } /* The adv_debug_if always return words and half words in * little-endian order no matter what the target endian is. * So if the target endian is big, change the order. */ struct target *target = jtag_info->target; if ((target->endianness == TARGET_BIG_ENDIAN) && (size != 1)) { switch (size) { case 4: buf_bswap32(buffer, buffer, size * count); break; case 2: buf_bswap16(buffer, buffer, size * count); break; } } return ERROR_OK; } static int or1k_adv_jtag_write_memory(struct or1k_jtag *jtag_info, uint32_t addr, uint32_t size, int count, const uint8_t *buffer) { LOG_DEBUG("Writing WB%" PRIu32 " at 0x%08" PRIx32, size * 8, addr); int retval; if (!jtag_info->or1k_jtag_inited) { retval = or1k_adv_jtag_init(jtag_info); if (retval != ERROR_OK) return retval; } retval = adbg_select_module(jtag_info, DC_WISHBONE); if (retval != ERROR_OK) return retval; /* The adv_debug_if wants words and half words in little-endian * order no matter what the target endian is. So if the target * endian is big, change the order. */ void *t = NULL; struct target *target = jtag_info->target; if ((target->endianness == TARGET_BIG_ENDIAN) && (size != 1)) { t = calloc(count * size, sizeof(uint8_t)); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } switch (size) { case 4: buf_bswap32(t, buffer, size * count); break; case 2: buf_bswap16(t, buffer, size * count); break; default: free(t); return ERROR_TARGET_FAILURE; } buffer = t; } int block_count_left = count; uint32_t block_count_address = addr; uint8_t *block_count_buffer = (uint8_t *)buffer; while (block_count_left) { int blocks_this_round = (block_count_left > MAX_BURST_SIZE) ? MAX_BURST_SIZE : block_count_left; retval = adbg_wb_burst_write(jtag_info, block_count_buffer, size, blocks_this_round, block_count_address); if (retval != ERROR_OK) { free(t); return retval; } block_count_left -= blocks_this_round; block_count_address += size * MAX_BURST_SIZE; block_count_buffer += size * MAX_BURST_SIZE; } free(t); return ERROR_OK; } int or1k_adv_jtag_jsp_xfer(struct or1k_jtag *jtag_info, int *out_len, unsigned char *out_buffer, int *in_len, unsigned char *in_buffer) { LOG_DEBUG("JSP transfer"); int retval; if (!jtag_info->or1k_jtag_inited) return ERROR_OK; retval = adbg_select_module(jtag_info, DC_JSP); if (retval != ERROR_OK) return retval; /* return nb char xmit */ int xmitsize; if (*out_len > 8) xmitsize = 8; else xmitsize = *out_len; uint8_t out_data[10]; uint8_t in_data[10]; struct scan_field field; int startbit, stopbit, wrapbit; memset(out_data, 0, 10); if (or1k_du_adv.options & ENABLE_JSP_MULTI) { startbit = 1; wrapbit = (xmitsize >> 3) & 0x1; out_data[0] = (xmitsize << 5) | 0x1; /* set the start bit */ int i; /* don't copy off the end of the input array */ for (i = 0; i < xmitsize; i++) { out_data[i + 1] = (out_buffer[i] << 1) | wrapbit; wrapbit = (out_buffer[i] >> 7) & 0x1; } if (i < 8) out_data[i + 1] = wrapbit; else out_data[9] = wrapbit; /* If the last data bit is a '1', then we need to append a '0' so the top-level module * won't treat the burst as a 'module select' command. */ stopbit = !!(out_data[9] & 0x01); } else { startbit = 0; /* First byte out has write count in upper nibble */ out_data[0] = 0x0 | (xmitsize << 4); if (xmitsize > 0) memcpy(&out_data[1], out_buffer, xmitsize); /* If the last data bit is a '1', then we need to append a '0' so the top-level module * won't treat the burst as a 'module select' command. */ stopbit = !!(out_data[8] & 0x80); } field.num_bits = 72 + startbit + stopbit; field.out_value = out_data; field.in_value = in_data; jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* bytes available is in the upper nibble */ *in_len = (in_data[0] >> 4) & 0xF; memcpy(in_buffer, &in_data[1], *in_len); int bytes_free = in_data[0] & 0x0F; *out_len = (bytes_free < xmitsize) ? bytes_free : xmitsize; return ERROR_OK; } static struct or1k_du or1k_du_adv = { .name = "adv", .options = NO_OPTION, .or1k_jtag_init = or1k_adv_jtag_init, .or1k_is_cpu_running = or1k_adv_is_cpu_running, .or1k_cpu_stall = or1k_adv_cpu_stall, .or1k_cpu_reset = or1k_adv_cpu_reset, .or1k_jtag_read_cpu = or1k_adv_jtag_read_cpu, .or1k_jtag_write_cpu = or1k_adv_jtag_write_cpu, .or1k_jtag_read_memory = or1k_adv_jtag_read_memory, .or1k_jtag_write_memory = or1k_adv_jtag_write_memory }; int or1k_du_adv_register(void) { list_add_tail(&or1k_du_adv.list, &du_list); return 0; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/openrisc/or1k_tap.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2012 by Franck Jullien * * elec4fun@gmail.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_OPENRISC_OR1K_TAP_H #define OPENOCD_TARGET_OPENRISC_OR1K_TAP_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/list.h> #include "or1k.h" int or1k_tap_vjtag_register(void); int or1k_tap_xilinx_bscan_register(void); int or1k_tap_mohor_register(void); /* Linear list over all available or1k taps */ extern struct list_head tap_list; struct or1k_tap_ip { struct list_head list; int (*init)(struct or1k_jtag *jtag_info); const char *name; }; #endif /* OPENOCD_TARGET_OPENRISC_OR1K_TAP_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/openrisc/or1k_tap_mohor.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013 by Franck Jullien * * elec4fun@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "or1k_tap.h" #include "or1k.h" #include <jtag/jtag.h> #define OR1K_TAP_INST_DEBUG 0x8 static int or1k_tap_mohor_init(struct or1k_jtag *jtag_info) { LOG_DEBUG("Initialising OpenCores JTAG TAP"); /* Put TAP into state where it can talk to the debug interface * by shifting in correct value to IR. */ /* Ensure TAP is reset - maybe not necessary*/ jtag_add_tlr(); struct jtag_tap *tap = jtag_info->tap; struct scan_field field; uint8_t ir_value = OR1K_TAP_INST_DEBUG; field.num_bits = tap->ir_length; field.out_value = &ir_value; field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); return jtag_execute_queue(); } static struct or1k_tap_ip mohor_tap = { .name = "mohor", .init = or1k_tap_mohor_init, }; int or1k_tap_mohor_register(void) { list_add_tail(&mohor_tap.list, &tap_list); return 0; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/openrisc/or1k_tap_vjtag.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013 by Franck Jullien * * elec4fun@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "or1k_tap.h" #include "or1k.h" #include <jtag/jtag.h> /* Contains constants relevant to the Altera Virtual JTAG * device, which are not included in the BSDL. * As of this writing, these are constant across every * device which supports virtual JTAG. */ /* These are commands for the FPGA's IR. */ #define ALTERA_CYCLONE_CMD_USER1 0x0E #define ALTERA_CYCLONE_CMD_USER0 0x0C /* These defines are for the virtual IR (not the FPGA's) * The virtual TAP was defined in hardware to match the OpenCores native * TAP in both IR size and DEBUG command. */ #define ALT_VJTAG_IR_SIZE 4 #define ALT_VJTAG_CMD_DEBUG 0x8 /* SLD node ID. */ #define JTAG_TO_AVALON_NODE_ID 0x84 #define VJTAG_NODE_ID 0x08 #define SIGNAL_TAP_NODE_ID 0x00 #define SERIAL_FLASH_LOADER_NODE_ID 0x04 #define VER(x) ((x >> 27) & 0x1f) #define NB_NODES(x) ((x >> 19) & 0xff) #define ID(x) ((x >> 19) & 0xff) #define MANUF(x) ((x >> 8) & 0x7ff) #define M_WIDTH(x) ((x >> 0) & 0xff) #define INST_ID(x) ((x >> 0) & 0xff) /* tap instructions - Mohor JTAG TAP */ #define OR1K_TAP_INST_IDCODE 0x2 #define OR1K_TAP_INST_DEBUG 0x8 static const char *id_to_string(unsigned char id) { switch (id) { case VJTAG_NODE_ID: return "Virtual JTAG"; case JTAG_TO_AVALON_NODE_ID: return "JTAG to avalon bridge"; case SIGNAL_TAP_NODE_ID: return "Signal TAP"; case SERIAL_FLASH_LOADER_NODE_ID: return "Serial Flash Loader"; } return "unknown"; } static unsigned char guess_addr_width(unsigned char number_of_nodes) { unsigned char width = 0; while (number_of_nodes) { number_of_nodes >>= 1; width++; } return width; } static int or1k_tap_vjtag_init(struct or1k_jtag *jtag_info) { LOG_DEBUG("Initialising Altera Virtual JTAG TAP"); /* Put TAP into state where it can talk to the debug interface * by shifting in correct value to IR. */ /* Ensure TAP is reset - maybe not necessary*/ jtag_add_tlr(); /* You can use a custom JTAG controller to discover transactions * necessary to enumerate all Virtual JTAG megafunction instances * from your design at runtime. All SLD nodes and the virtual JTAG * registers that they contain are targeted by two Instruction Register * values, USER0 and USER1. * * The USER1 instruction targets the virtual IR of either the sld_hub * or a SLD node. That is,when the USER1 instruction is issued to * the device, the subsequent DR scans target a specific virtual * IR chain based on an address field contained within the DR scan. * The table below shows how the virtual IR, the DR target of the * USER1 instruction is interpreted. * * The VIR_VALUE in the table below is the virtual IR value for the * target SLD node. The width of this field is m bits in length, * where m is the length of the largest VIR for all of the SLD nodes * in the design. All SLD nodes with VIR lengths of fewer than m * bits must pad VIR_VALUE with zeros up to a length of m. * * -------------------------------+------------------------------- * m + n - 1 m | m -1 0 * -------------------------------+------------------------------- * ADDR [(n – 1)..0] | VIR_VALUE [(m – 1)..0] * -------------------------------+------------------------------- * * The ADDR bits act as address values to signal the active SLD node * that the virtual IR shift targets. ADDR is n bits in length, where * n bits must be long enough to encode all SLD nodes within the design, * as shown below. * * n = CEIL(log2(Number of SLD_nodes +1)) * * The SLD hub is always 0 in the address map. * * Discovery and enumeration of the SLD instances within a design * requires interrogation of the sld_hub to determine the dimensions * of the USER1 DR (m and n) and associating each SLD instance, specifically * the Virtual JTAG megafunction instances, with an address value * contained within the ADDR bits of the USER1 DR. * * The SLD hub contains the HUB IP Configuration Register and SLD_NODE_INFO * register for each SLD node in the design. The HUB IP configuration register provides * information needed to determine the dimensions of the USER1 DR chain. The * SLD_NODE_INFO register is used to determine the address mapping for Virtual * JTAG instance in your design. This register set is shifted out by issuing the * HUB_INFO instruction. Both the ADDR bits for the SLD hub and the HUB_INFO * instruction is 0 × 0. * Because m and n are unknown at this point, the DR register * (ADDR bits + VIR_VALUE) must be filled with zeros. Shifting a sequence of 64 zeroes * into the USER1 DR is sufficient to cover the most conservative case for m and n. */ uint8_t t[4] = { 0 }; struct scan_field field; struct jtag_tap *tap = jtag_info->tap; /* Select VIR */ buf_set_u32(t, 0, tap->ir_length, ALTERA_CYCLONE_CMD_USER1); field.num_bits = tap->ir_length; field.out_value = t; field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); /* Select the SLD Hub */ field.num_bits = 64; field.out_value = NULL; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); /* HUB IP Configuration Register * * When the USER1 and HUB_INFO instruction sequence is issued, the * USER0 instruction must be applied to enable the target register * of the HUB_INFO instruction. The HUB IP configuration register * is shifted out using eight four-bit nibble scans of the DR register. * Each four-bit scan must pass through the UPDATE_DR state before * the next four-bit scan. The 8 scans are assembled into a 32-bit * value with the definitions shown in the table below. * * -------------------------------------------------------------------------------- * NIBBLE7 | NIBBLE6 | NIBBLE5 | NIBBLE4 | NIBBLE3 | NIBBLE2 | NIBBLE1 | NIBBLE0 * ----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----- * | | | | | | | | | | | | | | | * ----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----- * HUB IP version| N | ALTERA_MFG_ID (0x06E) | SUM (m, n) * --------------+-------------------+------------------------+-------------------- */ /* Select VDR */ buf_set_u32(t, 0, tap->ir_length, ALTERA_CYCLONE_CMD_USER0); field.num_bits = tap->ir_length; field.out_value = t; field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); int retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; uint8_t nibble; uint32_t hub_info = 0; for (int i = 0; i < 8; i++) { field.num_bits = 4; field.out_value = NULL; field.in_value = &nibble; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; hub_info = ((hub_info >> 4) | ((nibble & 0xf) << 28)); } int nb_nodes = NB_NODES(hub_info); int m_width = M_WIDTH(hub_info); LOG_DEBUG("SLD HUB Configuration register"); LOG_DEBUG("------------------------------"); LOG_DEBUG("m_width = %d", m_width); LOG_DEBUG("manufacturer_id = 0x%02" PRIx32, MANUF(hub_info)); LOG_DEBUG("nb_of_node = %d", nb_nodes); LOG_DEBUG("version = %" PRIu32, VER(hub_info)); LOG_DEBUG("VIR length = %d", guess_addr_width(nb_nodes) + m_width); /* Because the number of SLD nodes is now known, the Nodes on the hub can be * enumerated by repeating the 8 four-bit nibble scans, once for each Node, * to yield the SLD_NODE_INFO register of each Node. The DR nibble shifts * are a continuation of the HUB_INFO DR shift used to shift out the Hub IP * Configuration register. * * The order of the Nodes as they are shifted out determines the ADDR * values for the Nodes, beginning with, for the first Node SLD_NODE_INFO * shifted out, up to and including, for the last node on the hub. The * tables below show the SLD_NODE_INFO register and a their functional descriptions. * * --------------+-----------+---------------+---------------- * 31 27 | 26 19 | 18 8 | 7 0 * --------------+-----------+---------------+---------------- * Node Version | NODE ID | NODE MFG_ID | NODE INST ID * */ int vjtag_node_address = -1; int node_index; uint32_t node_info = 0; for (node_index = 0; node_index < nb_nodes; node_index++) { for (int i = 0; i < 8; i++) { field.num_bits = 4; field.out_value = NULL; field.in_value = &nibble; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; node_info = ((node_info >> 4) | ((nibble & 0xf) << 28)); } LOG_DEBUG("Node info register"); LOG_DEBUG("--------------------"); LOG_DEBUG("instance_id = %" PRIu32, ID(node_info)); LOG_DEBUG("manufacturer_id = 0x%02" PRIx32, MANUF(node_info)); LOG_DEBUG("node_id = %" PRIu32 " (%s)", ID(node_info), id_to_string(ID(node_info))); LOG_DEBUG("version = %" PRIu32, VER(node_info)); if (ID(node_info) == VJTAG_NODE_ID) vjtag_node_address = node_index + 1; } if (vjtag_node_address < 0) { LOG_ERROR("No VJTAG TAP instance found !"); return ERROR_FAIL; } /* Select VIR */ buf_set_u32(t, 0, tap->ir_length, ALTERA_CYCLONE_CMD_USER1); field.num_bits = tap->ir_length; field.out_value = t; field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); /* Send the DEBUG command to the VJTAG IR */ int dr_length = guess_addr_width(nb_nodes) + m_width; buf_set_u32(t, 0, dr_length, (vjtag_node_address << m_width) | ALT_VJTAG_CMD_DEBUG); field.num_bits = dr_length; field.out_value = t; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); /* Select the VJTAG DR */ buf_set_u32(t, 0, tap->ir_length, ALTERA_CYCLONE_CMD_USER0); field.num_bits = tap->ir_length; field.out_value = t; field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); return jtag_execute_queue(); } static struct or1k_tap_ip vjtag_tap = { .name = "vjtag", .init = or1k_tap_vjtag_init, }; int or1k_tap_vjtag_register(void) { list_add_tail(&vjtag_tap.list, &tap_list); return 0; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/openrisc/or1k_tap_xilinx_bscan.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013 by Sergio Chico * * sergio.chico@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "or1k_tap.h" #include "or1k.h" #include <jtag/jtag.h> #define OR1K_XILINX_TAP_INST_USER1 0x02 static int or1k_tap_xilinx_bscan_init(struct or1k_jtag *jtag_info) { LOG_DEBUG("Initialising Xilinx Internal JTAG TAP"); /* Put TAP into state where it can talk to the debug interface * by shifting in correct value to IR. */ /* Ensure TAP is reset - maybe not necessary*/ jtag_add_tlr(); struct jtag_tap *tap = jtag_info->tap; struct scan_field field; uint8_t ir_value = OR1K_XILINX_TAP_INST_USER1; field.num_bits = tap->ir_length; field.out_value = &ir_value; field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); return jtag_execute_queue(); } static struct or1k_tap_ip xilinx_bscan_tap = { .name = "xilinx_bscan", .init = or1k_tap_xilinx_bscan_init, }; int or1k_tap_xilinx_bscan_register(void) { list_add_tail(&xilinx_bscan_tap.list, &tap_list); return 0; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/quark_d20xx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright(c) 2015-2016 Intel Corporation. * * Jessica Gomez (jessica.gomez.hernandez@intel.com) * Ivan De Cesaris (ivan.de.cesaris@intel.com) * * Contact Information: * Intel Corporation */ /* * @file * Debugger for Intel Quark D20xx * The CPU TAP (Lakemont TAP) is used for software debug and the CLTAP is * used for SoC level operations. * * Reference document: * Intel Quark microcontroller D2000 Debug Operations (web search for doc num 333241) */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include "target.h" #include "target_type.h" #include "breakpoints.h" #include "lakemont.h" #include "x86_32_common.h" static int quark_d20xx_target_create(struct target *t, Jim_Interp *interp) { struct x86_32_common *x86_32 = calloc(1, sizeof(struct x86_32_common)); if (!x86_32) { LOG_ERROR("%s out of memory", __func__); return ERROR_FAIL; } x86_32_common_init_arch_info(t, x86_32); lakemont_init_arch_info(t, x86_32); x86_32->core_type = LMT3_5; return ERROR_OK; } static int quark_d20xx_init_target(struct command_context *cmd_ctx, struct target *t) { return lakemont_init_target(cmd_ctx, t); } static int quark_d20xx_reset_deassert(struct target *t) { int retval; /* Can't detect if a warm reset happened while halted but we can make the * openocd and target state consistent here if in probe mode already */ if (!check_not_halted(t)) { retval = lakemont_update_after_probemode_entry(t); if (retval != ERROR_OK) { LOG_ERROR("%s core state update fail", __func__); return retval; } /* resume target if reset mode is run */ if (!t->reset_halt) { retval = lakemont_resume(t, 1, 0, 0, 0); if (retval != ERROR_OK) { LOG_ERROR("%s could not resume target", __func__); return retval; } } } return ERROR_OK; } struct target_type quark_d20xx_target = { .name = "quark_d20xx", .target_create = quark_d20xx_target_create, .init_target = quark_d20xx_init_target, /* lakemont probemode specific code */ .poll = lakemont_poll, .arch_state = lakemont_arch_state, .halt = lakemont_halt, .resume = lakemont_resume, .step = lakemont_step, .assert_reset = lakemont_reset_assert, .deassert_reset = quark_d20xx_reset_deassert, /* common x86 code */ .commands = x86_32_command_handlers, .get_gdb_reg_list = x86_32_get_gdb_reg_list, .read_memory = x86_32_common_read_memory, .write_memory = x86_32_common_write_memory, .add_breakpoint = x86_32_common_add_breakpoint, .remove_breakpoint = x86_32_common_remove_breakpoint, .add_watchpoint = x86_32_common_add_watchpoint, .remove_watchpoint = x86_32_common_remove_watchpoint, .virt2phys = x86_32_common_virt2phys, .read_phys_memory = x86_32_common_read_phys_mem, .write_phys_memory = x86_32_common_write_phys_mem, .mmu = x86_32_common_mmu, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/quark_x10xx.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright(c) 2013-2016 Intel Corporation. * * Adrian Burns (adrian.burns@intel.com) * Thomas Faust (thomas.faust@intel.com) * Ivan De Cesaris (ivan.de.cesaris@intel.com) * Julien Carreno (julien.carreno@intel.com) * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com) * * Contact Information: * Intel Corporation */ /* * @file * Debugger for Intel Quark SoC X1000 * Intel Quark X10xx is the first product in the Quark family of SoCs. * It is an IA-32 (Pentium x86 ISA) compatible SoC. The core CPU in the * X10xx is codenamed Lakemont. Lakemont version 1 (LMT1) is used in X10xx. * The CPU TAP (Lakemont TAP) is used for software debug and the CLTAP is * used for SoC level operations. * Useful docs are here: https://communities.intel.com/community/makers/documentation * Intel Quark SoC X1000 OpenOCD/GDB/Eclipse App Note (web search for doc num 330015) * Intel Quark SoC X1000 Debug Operations User Guide (web search for doc num 329866) * Intel Quark SoC X1000 Datasheet (web search for doc num 329676) * * This file implements any Quark SoC specific features such as resetbreak (TODO) */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include "target.h" #include "target_type.h" #include "lakemont.h" #include "x86_32_common.h" static int quark_x10xx_target_create(struct target *t, Jim_Interp *interp) { struct x86_32_common *x86_32 = calloc(1, sizeof(*x86_32)); if (!x86_32) return ERROR_FAIL; x86_32_common_init_arch_info(t, x86_32); lakemont_init_arch_info(t, x86_32); x86_32->core_type = LMT1; return ERROR_OK; } struct target_type quark_x10xx_target = { .name = "quark_x10xx", /* Quark X1000 SoC */ .target_create = quark_x10xx_target_create, /* lakemont probemode specific code */ .arch_state = lakemont_arch_state, .assert_reset = lakemont_reset_assert, .deassert_reset = lakemont_reset_deassert, .halt = lakemont_halt, .init_target = lakemont_init_target, .poll = lakemont_poll, .resume = lakemont_resume, .step = lakemont_step, /* common x86 code */ .add_breakpoint = x86_32_common_add_breakpoint, .add_watchpoint = x86_32_common_add_watchpoint, .commands = x86_32_command_handlers, .get_gdb_reg_list = x86_32_get_gdb_reg_list, .mmu = x86_32_common_mmu, .read_memory = x86_32_common_read_memory, .read_phys_memory = x86_32_common_read_phys_mem, .remove_breakpoint = x86_32_common_remove_breakpoint, .remove_watchpoint = x86_32_common_remove_watchpoint, .virt2phys = x86_32_common_virt2phys, .write_memory = x86_32_common_write_memory, .write_phys_memory = x86_32_common_write_phys_mem, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/register.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "register.h" #include <helper/log.h> /** * @file * Holds utilities to work with register caches. * * OpenOCD uses machine registers internally, and exposes them by name * to Tcl scripts. Sets of related registers are grouped into caches. * For example, a CPU core will expose a set of registers, and there * may be separate registers associated with debug or trace modules. */ struct reg *register_get_by_number(struct reg_cache *first, uint32_t reg_num, bool search_all) { struct reg_cache *cache = first; while (cache) { for (unsigned int i = 0; i < cache->num_regs; i++) { if (!cache->reg_list[i].exist) continue; if (cache->reg_list[i].number == reg_num) return &(cache->reg_list[i]); } if (!search_all) break; cache = cache->next; } return NULL; } struct reg *register_get_by_name(struct reg_cache *first, const char *name, bool search_all) { struct reg_cache *cache = first; while (cache) { for (unsigned int i = 0; i < cache->num_regs; i++) { if (!cache->reg_list[i].exist) continue; if (strcmp(cache->reg_list[i].name, name) == 0) return &(cache->reg_list[i]); } if (!search_all) break; cache = cache->next; } return NULL; } struct reg_cache **register_get_last_cache_p(struct reg_cache **first) { struct reg_cache **cache_p = first; if (*cache_p) while (*cache_p) cache_p = &((*cache_p)->next); else return first; return cache_p; } void register_unlink_cache(struct reg_cache **cache_p, const struct reg_cache *cache) { while (*cache_p && *cache_p != cache) cache_p = &((*cache_p)->next); if (*cache_p) *cache_p = cache->next; } /** Marks the contents of the register cache as invalid (and clean). */ void register_cache_invalidate(struct reg_cache *cache) { struct reg *reg = cache->reg_list; for (unsigned int n = cache->num_regs; n != 0; n--, reg++) { if (!reg->exist) continue; reg->valid = false; reg->dirty = false; } } static int register_get_dummy_core_reg(struct reg *reg) { return ERROR_OK; } static int register_set_dummy_core_reg(struct reg *reg, uint8_t *buf) { reg->dirty = true; reg->valid = true; return ERROR_OK; } static const struct reg_arch_type dummy_type = { .get = register_get_dummy_core_reg, .set = register_set_dummy_core_reg, }; void register_init_dummy(struct reg *reg) { reg->type = &dummy_type; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/register.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_REGISTER_H #define OPENOCD_TARGET_REGISTER_H #include "helper/replacements.h" #include "helper/types.h" struct target; enum reg_type { REG_TYPE_BOOL, REG_TYPE_INT, REG_TYPE_INT8, REG_TYPE_INT16, REG_TYPE_INT32, REG_TYPE_INT64, REG_TYPE_INT128, REG_TYPE_UINT, REG_TYPE_UINT8, REG_TYPE_UINT16, REG_TYPE_UINT32, REG_TYPE_UINT64, REG_TYPE_UINT128, REG_TYPE_CODE_PTR, REG_TYPE_DATA_PTR, REG_TYPE_FLOAT, REG_TYPE_IEEE_SINGLE, REG_TYPE_IEEE_DOUBLE, REG_TYPE_ARCH_DEFINED, }; struct reg_feature { const char *name; }; struct reg_data_type_vector { struct reg_data_type *type; uint32_t count; }; struct reg_data_type_union_field { const char *name; struct reg_data_type *type; struct reg_data_type_union_field *next; }; struct reg_data_type_union { struct reg_data_type_union_field *fields; }; struct reg_data_type_bitfield { uint32_t start; uint32_t end; enum reg_type type; }; struct reg_data_type_struct_field { const char *name; bool use_bitfields; union { struct reg_data_type_bitfield *bitfield; struct reg_data_type *type; }; struct reg_data_type_struct_field *next; }; struct reg_data_type_struct { uint32_t size; struct reg_data_type_struct_field *fields; }; struct reg_data_type_flags_field { const char *name; struct reg_data_type_bitfield *bitfield; struct reg_data_type_flags_field *next; }; struct reg_data_type_flags { uint32_t size; struct reg_data_type_flags_field *fields; }; enum reg_data_type_class { REG_TYPE_CLASS_VECTOR, REG_TYPE_CLASS_UNION, REG_TYPE_CLASS_STRUCT, REG_TYPE_CLASS_FLAGS, }; struct reg_data_type { enum reg_type type; const char *id; enum reg_data_type_class type_class; union { struct reg_data_type_vector *reg_type_vector; struct reg_data_type_union *reg_type_union; struct reg_data_type_struct *reg_type_struct; struct reg_data_type_flags *reg_type_flags; }; }; struct reg { /* Canonical name of the register. */ const char *name; /* Number that gdb uses to access this register. */ uint32_t number; /* TODO. This should probably be const. */ struct reg_feature *feature; /* TODO: When true, the caller will save this register before running any algorithm. */ bool caller_save; /* Pointer to place where the value is stored, in the format understood by * the binarybuffer.h functions. */ uint8_t *value; /* The stored value needs to be written to the target. */ bool dirty; /* When true, value is valid. */ bool valid; /* When false, the register doesn't actually exist in the target. */ bool exist; /* Hide the register from gdb and omit it in 'reg' cmd output */ bool hidden; /* Size of the register in bits. */ uint32_t size; /* Used for generating XML description of registers. Can be set to NULL for * targets that don't use that. */ struct reg_data_type *reg_data_type; /* Used for generating XML description of registers. Can be set to NULL for * targets that don't use that. */ const char *group; /* Pointer to architecture-specific info for this register. */ void *arch_info; const struct reg_arch_type *type; }; struct reg_cache { const char *name; struct reg_cache *next; struct reg *reg_list; unsigned num_regs; }; struct reg_arch_type { int (*get)(struct reg *reg); int (*set)(struct reg *reg, uint8_t *buf); }; struct reg *register_get_by_number(struct reg_cache *first, uint32_t reg_num, bool search_all); struct reg *register_get_by_name(struct reg_cache *first, const char *name, bool search_all); struct reg_cache **register_get_last_cache_p(struct reg_cache **first); void register_unlink_cache(struct reg_cache **cache_p, const struct reg_cache *cache); void register_cache_invalidate(struct reg_cache *cache); void register_init_dummy(struct reg *reg); #endif /* OPENOCD_TARGET_REGISTER_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libriscv.la %C%_libriscv_la_SOURCES = \ %D%/asm.h \ %D%/batch.h \ %D%/debug_defines.h \ %D%/encoding.h \ %D%/gdb_regs.h \ %D%/opcodes.h \ %D%/program.h \ %D%/riscv.h \ %D%/batch.c \ %D%/program.c \ %D%/riscv-011.c \ %D%/riscv-013.c \ %D%/riscv.c \ %D%/riscv_semihosting.c ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/asm.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef TARGET__RISCV__ASM_H #define TARGET__RISCV__ASM_H #include "riscv.h" /*** Version-independent functions that we don't want in the main address space. ***/ static uint32_t load(const struct target *target, unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t load(const struct target *target, unsigned int rd, unsigned int base, uint16_t offset) { switch (riscv_xlen(target)) { case 32: return lw(rd, base, offset); case 64: return ld(rd, base, offset); } assert(0); return 0; /* Silence -Werror=return-type */ } static uint32_t store(const struct target *target, unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t store(const struct target *target, unsigned int src, unsigned int base, uint16_t offset) { switch (riscv_xlen(target)) { case 32: return sw(src, base, offset); case 64: return sd(src, base, offset); } assert(0); return 0; /* Silence -Werror=return-type */ } #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/batch.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "batch.h" #include "debug_defines.h" #include "riscv.h" #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) #define DTM_DMI_MAX_ADDRESS_LENGTH ((1<<DTM_DTMCS_ABITS_LENGTH)-1) #define DMI_SCAN_MAX_BIT_LENGTH (DTM_DMI_MAX_ADDRESS_LENGTH + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH) #define DMI_SCAN_BUF_SIZE (DIV_ROUND_UP(DMI_SCAN_MAX_BIT_LENGTH, 8)) static void dump_field(int idle, const struct scan_field *field); struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_t idle) { scans += 4; struct riscv_batch *out = calloc(1, sizeof(*out)); if (!out) goto error0; out->target = target; out->allocated_scans = scans; out->idle_count = idle; out->data_out = malloc(sizeof(*out->data_out) * (scans) * DMI_SCAN_BUF_SIZE); if (!out->data_out) { LOG_ERROR("Failed to allocate data_out in RISC-V batch."); goto error1; }; out->data_in = malloc(sizeof(*out->data_in) * (scans) * DMI_SCAN_BUF_SIZE); if (!out->data_in) { LOG_ERROR("Failed to allocate data_in in RISC-V batch."); goto error2; } out->fields = malloc(sizeof(*out->fields) * (scans)); if (!out->fields) { LOG_ERROR("Failed to allocate fields in RISC-V batch."); goto error3; } if (bscan_tunnel_ir_width != 0) { out->bscan_ctxt = malloc(sizeof(*out->bscan_ctxt) * (scans)); if (!out->bscan_ctxt) { LOG_ERROR("Failed to allocate bscan_ctxt in RISC-V batch."); goto error4; } } out->last_scan = RISCV_SCAN_TYPE_INVALID; out->read_keys = malloc(sizeof(*out->read_keys) * (scans)); if (!out->read_keys) { LOG_ERROR("Failed to allocate read_keys in RISC-V batch."); goto error5; } return out; error5: free(out->bscan_ctxt); error4: free(out->fields); error3: free(out->data_in); error2: free(out->data_out); error1: free(out); error0: return NULL; } void riscv_batch_free(struct riscv_batch *batch) { free(batch->data_in); free(batch->data_out); free(batch->fields); free(batch->bscan_ctxt); free(batch->read_keys); free(batch); } bool riscv_batch_full(struct riscv_batch *batch) { return batch->used_scans > (batch->allocated_scans - 4); } int riscv_batch_run(struct riscv_batch *batch) { if (batch->used_scans == 0) { LOG_DEBUG("Ignoring empty batch."); return ERROR_OK; } riscv_batch_add_nop(batch); for (size_t i = 0; i < batch->used_scans; ++i) { if (bscan_tunnel_ir_width != 0) riscv_add_bscan_tunneled_scan(batch->target, batch->fields+i, batch->bscan_ctxt+i); else jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE); if (batch->idle_count > 0) jtag_add_runtest(batch->idle_count, TAP_IDLE); } keep_alive(); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("Unable to execute JTAG queue"); return ERROR_FAIL; } keep_alive(); if (bscan_tunnel_ir_width != 0) { /* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */ for (size_t i = 0; i < batch->used_scans; ++i) buffer_shr((batch->fields + i)->in_value, DMI_SCAN_BUF_SIZE, 1); } for (size_t i = 0; i < batch->used_scans; ++i) dump_field(batch->idle_count, batch->fields + i); return ERROR_OK; } void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data) { assert(batch->used_scans < batch->allocated_scans); struct scan_field *field = batch->fields + batch->used_scans; field->num_bits = riscv_dmi_write_u64_bits(batch->target); field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); riscv_fill_dmi_write_u64(batch->target, (char *)field->out_value, address, data); riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value); batch->last_scan = RISCV_SCAN_TYPE_WRITE; batch->used_scans++; } size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address) { assert(batch->used_scans < batch->allocated_scans); struct scan_field *field = batch->fields + batch->used_scans; field->num_bits = riscv_dmi_write_u64_bits(batch->target); field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); riscv_fill_dmi_read_u64(batch->target, (char *)field->out_value, address); riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value); batch->last_scan = RISCV_SCAN_TYPE_READ; batch->used_scans++; batch->read_keys[batch->read_keys_used] = batch->used_scans; return batch->read_keys_used++; } unsigned riscv_batch_get_dmi_read_op(struct riscv_batch *batch, size_t key) { assert(key < batch->read_keys_used); size_t index = batch->read_keys[key]; assert(index <= batch->used_scans); uint8_t *base = batch->data_in + DMI_SCAN_BUF_SIZE * index; /* extract "op" field from the DMI read result */ return (unsigned)buf_get_u32(base, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); } uint32_t riscv_batch_get_dmi_read_data(struct riscv_batch *batch, size_t key) { assert(key < batch->read_keys_used); size_t index = batch->read_keys[key]; assert(index <= batch->used_scans); uint8_t *base = batch->data_in + DMI_SCAN_BUF_SIZE * index; /* extract "data" field from the DMI read result */ return buf_get_u32(base, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); } void riscv_batch_add_nop(struct riscv_batch *batch) { assert(batch->used_scans < batch->allocated_scans); struct scan_field *field = batch->fields + batch->used_scans; field->num_bits = riscv_dmi_write_u64_bits(batch->target); field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); riscv_fill_dmi_nop_u64(batch->target, (char *)field->out_value); riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value); batch->last_scan = RISCV_SCAN_TYPE_NOP; batch->used_scans++; } void dump_field(int idle, const struct scan_field *field) { static const char * const op_string[] = {"-", "r", "w", "?"}; static const char * const status_string[] = {"+", "?", "F", "b"}; if (debug_level < LOG_LVL_DEBUG) return; assert(field->out_value); uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits); unsigned int out_op = get_field(out, DTM_DMI_OP); unsigned int out_data = get_field(out, DTM_DMI_DATA); unsigned int out_address = out >> DTM_DMI_ADDRESS_OFFSET; if (field->in_value) { uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits); unsigned int in_op = get_field(in, DTM_DMI_OP); unsigned int in_data = get_field(in, DTM_DMI_DATA); unsigned int in_address = in >> DTM_DMI_ADDRESS_OFFSET; log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %s %08x @%02x -> %s %08x @%02x; %di", field->num_bits, op_string[out_op], out_data, out_address, status_string[in_op], in_data, in_address, idle); } else { log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %s %08x @%02x -> ?; %di", field->num_bits, op_string[out_op], out_data, out_address, idle); } } size_t riscv_batch_available_scans(struct riscv_batch *batch) { return batch->allocated_scans - batch->used_scans - 4; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/batch.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef TARGET__RISCV__SCANS_H #define TARGET__RISCV__SCANS_H #include "target/target.h" #include "jtag/jtag.h" #include "riscv.h" enum riscv_scan_type { RISCV_SCAN_TYPE_INVALID, RISCV_SCAN_TYPE_NOP, RISCV_SCAN_TYPE_READ, RISCV_SCAN_TYPE_WRITE, }; /* A batch of multiple JTAG scans, which are grouped together to avoid the * overhead of some JTAG adapters when sending single commands. This is * designed to support block copies, as that's what we actually need to go * fast. */ struct riscv_batch { struct target *target; size_t allocated_scans; size_t used_scans; size_t idle_count; uint8_t *data_out; uint8_t *data_in; struct scan_field *fields; /* If in BSCAN mode, this field will be allocated (one per scan), and utilized to tunnel all the scans in the batch. If not in BSCAN mode, this field is unallocated and stays NULL */ riscv_bscan_tunneled_scan_context_t *bscan_ctxt; /* In JTAG we scan out the previous value's output when performing a * scan. This is a pain for users, so we just provide them the * illusion of not having to do this by eliding all but the last NOP. * */ enum riscv_scan_type last_scan; /* The read keys. */ size_t *read_keys; size_t read_keys_used; }; /* Allocates (or frees) a new scan set. "scans" is the maximum number of JTAG * scans that can be issued to this object, and idle is the number of JTAG idle * cycles between every real scan. */ struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_t idle); void riscv_batch_free(struct riscv_batch *batch); /* Checks to see if this batch is full. */ bool riscv_batch_full(struct riscv_batch *batch); /* Executes this scan batch. */ int riscv_batch_run(struct riscv_batch *batch); /* Adds a DMI write to this batch. */ void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data); /* DMI reads must be handled in two parts: the first one schedules a read and * provides a key, the second one actually obtains the result of the read - * status (op) and the actual data. */ size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address); unsigned riscv_batch_get_dmi_read_op(struct riscv_batch *batch, size_t key); uint32_t riscv_batch_get_dmi_read_data(struct riscv_batch *batch, size_t key); /* Scans in a NOP. */ void riscv_batch_add_nop(struct riscv_batch *batch); /* Returns the number of available scans. */ size_t riscv_batch_available_scans(struct riscv_batch *batch); #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/debug_defines.h ================================================ /* * This file is auto-generated by running 'make debug_defines.h' in * https://github.com/riscv/riscv-debug-spec/ (d749752) */ #define DTM_IDCODE 0x01 /* * Identifies the release version of this part. */ #define DTM_IDCODE_VERSION_OFFSET 0x1c #define DTM_IDCODE_VERSION_LENGTH 4 #define DTM_IDCODE_VERSION 0xf0000000U /* * Identifies the designer's part number of this part. */ #define DTM_IDCODE_PARTNUMBER_OFFSET 0xc #define DTM_IDCODE_PARTNUMBER_LENGTH 0x10 #define DTM_IDCODE_PARTNUMBER 0xffff000 /* * Identifies the designer/manufacturer of this part. Bits 6:0 must be * bits 6:0 of the designer/manufacturer's Identification Code as * assigned by JEDEC Standard JEP106. Bits 10:7 contain the modulo-16 * count of the number of continuation characters (0x7f) in that same * Identification Code. */ #define DTM_IDCODE_MANUFID_OFFSET 1 #define DTM_IDCODE_MANUFID_LENGTH 0xb #define DTM_IDCODE_MANUFID 0xffe #define DTM_IDCODE_1_OFFSET 0 #define DTM_IDCODE_1_LENGTH 1 #define DTM_IDCODE_1 1 #define DTM_DTMCS 0x10 /* * Writing 1 to this bit does a hard reset of the DTM, * causing the DTM to forget about any outstanding DMI transactions, and * returning all registers and internal state to their reset value. * In general this should only be used when the Debugger has * reason to expect that the outstanding DMI transaction will never * complete (e.g. a reset condition caused an inflight DMI transaction to * be cancelled). */ #define DTM_DTMCS_DMIHARDRESET_OFFSET 0x11 #define DTM_DTMCS_DMIHARDRESET_LENGTH 1 #define DTM_DTMCS_DMIHARDRESET 0x20000 /* * Writing 1 to this bit clears the sticky error state, but does * not affect outstanding DMI transactions. */ #define DTM_DTMCS_DMIRESET_OFFSET 0x10 #define DTM_DTMCS_DMIRESET_LENGTH 1 #define DTM_DTMCS_DMIRESET 0x10000 /* * This is a hint to the debugger of the minimum number of * cycles a debugger should spend in * Run-Test/Idle after every DMI scan to avoid a `busy' * return code (\FdtmDtmcsDmistat of 3). A debugger must still * check \FdtmDtmcsDmistat when necessary. * * 0: It is not necessary to enter Run-Test/Idle at all. * * 1: Enter Run-Test/Idle and leave it immediately. * * 2: Enter Run-Test/Idle and stay there for 1 cycle before leaving. * * And so on. */ #define DTM_DTMCS_IDLE_OFFSET 0xc #define DTM_DTMCS_IDLE_LENGTH 3 #define DTM_DTMCS_IDLE 0x7000 /* * Read-only alias of \FdtmDmiOp. */ #define DTM_DTMCS_DMISTAT_OFFSET 0xa #define DTM_DTMCS_DMISTAT_LENGTH 2 #define DTM_DTMCS_DMISTAT 0xc00 /* * The size of \FdmSbaddressZeroAddress in \RdtmDmi. */ #define DTM_DTMCS_ABITS_OFFSET 4 #define DTM_DTMCS_ABITS_LENGTH 6 #define DTM_DTMCS_ABITS 0x3f0 #define DTM_DTMCS_VERSION_OFFSET 0 #define DTM_DTMCS_VERSION_LENGTH 4 #define DTM_DTMCS_VERSION 0xf /* * 0.11: Version described in spec version 0.11. */ #define DTM_DTMCS_VERSION_0_11 0 /* * 1.0: Version described in spec versions 0.13 and 1.0. */ #define DTM_DTMCS_VERSION_1_0 1 /* * custom: Version not described in any available version of this spec. */ #define DTM_DTMCS_VERSION_CUSTOM 15 #define DTM_DMI 0x11 /* * Address used for DMI access. In Update-DR this value is used * to access the DM over the DMI. */ #define DTM_DMI_ADDRESS_OFFSET 0x22 #define DTM_DMI_ADDRESS_LENGTH(abits) abits #define DTM_DMI_ADDRESS(abits) ((0x400000000ULL * (1ULL<<abits)) + -0x400000000ULL) /* * The data to send to the DM over the DMI during Update-DR, and * the data returned from the DM as a result of the previous operation. */ #define DTM_DMI_DATA_OFFSET 2 #define DTM_DMI_DATA_LENGTH 0x20 #define DTM_DMI_DATA 0x3fffffffcULL /* * When the debugger writes this field, it has the following meaning: */ #define DTM_DMI_OP_OFFSET 0 #define DTM_DMI_OP_LENGTH 2 #define DTM_DMI_OP 3 /* * nop: Ignore \FdmSbdataZeroData and \FdmSbaddressZeroAddress. * * Don't send anything over the DMI during Update-DR. * This operation should never result in a busy or error response. * The address and data reported in the following Capture-DR * are undefined. */ #define DTM_DMI_OP_NOP 0 /* * read: Read from \FdmSbaddressZeroAddress. */ #define DTM_DMI_OP_READ 1 /* * write: Write \FdmSbdataZeroData to \FdmSbaddressZeroAddress. */ #define DTM_DMI_OP_WRITE 2 /* * reserved: Reserved. */ /* * When the debugger reads this field, it means the following: */ /* * success: The previous operation completed successfully. */ #define DTM_DMI_OP_SUCCESS 0 /* * reserved: Reserved. */ /* * failed: A previous operation failed. The data scanned into \RdtmDmi in * this access will be ignored. This status is sticky and can be * cleared by writing \FdtmDtmcsDmireset in \RdtmDtmcs. * * This indicates that the DM itself responded with an error. * There are no specified cases in which the DM would * respond with an error, and DMI is not required to support * returning errors. */ #define DTM_DMI_OP_FAILED 2 /* * busy: An operation was attempted while a DMI request is still in * progress. The data scanned into \RdtmDmi in this access will be * ignored. This status is sticky and can be cleared by writing * \FdtmDtmcsDmireset in \RdtmDtmcs. If a debugger sees this status, it * needs to give the target more TCK edges between Update-DR and * Capture-DR. The simplest way to do that is to add extra transitions * in Run-Test/Idle. */ #define DTM_DMI_OP_BUSY 3 #define CSR_DCSR 0x7b0 #define CSR_DCSR_DEBUGVER_OFFSET 0x1c #define CSR_DCSR_DEBUGVER_LENGTH 4 #define CSR_DCSR_DEBUGVER 0xf0000000U /* * none: There is no debug support. */ #define CSR_DCSR_DEBUGVER_NONE 0 /* * 1.0: Debug support exists as it is described in this document. */ #define CSR_DCSR_DEBUGVER_1_0 4 /* * custom: There is debug support, but it does not conform to any * available version of this spec. */ #define CSR_DCSR_DEBUGVER_CUSTOM 15 #define CSR_DCSR_EBREAKVS_OFFSET 0x11 #define CSR_DCSR_EBREAKVS_LENGTH 1 #define CSR_DCSR_EBREAKVS 0x20000 /* * exception: {\tt ebreak} instructions in VS-mode behave as described in the * Privileged Spec. */ #define CSR_DCSR_EBREAKVS_EXCEPTION 0 /* * debug mode: {\tt ebreak} instructions in VS-mode enter Debug Mode. */ #define CSR_DCSR_EBREAKVS_DEBUG_MODE 1 /* * This bit is hardwired to 0 if the hart does not support virtualization mode. */ #define CSR_DCSR_EBREAKVU_OFFSET 0x10 #define CSR_DCSR_EBREAKVU_LENGTH 1 #define CSR_DCSR_EBREAKVU 0x10000 /* * exception: {\tt ebreak} instructions in VU-mode behave as described in the * Privileged Spec. */ #define CSR_DCSR_EBREAKVU_EXCEPTION 0 /* * debug mode: {\tt ebreak} instructions in VU-mode enter Debug Mode. */ #define CSR_DCSR_EBREAKVU_DEBUG_MODE 1 /* * This bit is hardwired to 0 if the hart does not support virtualization mode. */ #define CSR_DCSR_EBREAKM_OFFSET 0xf #define CSR_DCSR_EBREAKM_LENGTH 1 #define CSR_DCSR_EBREAKM 0x8000 /* * exception: {\tt ebreak} instructions in M-mode behave as described in the * Privileged Spec. */ #define CSR_DCSR_EBREAKM_EXCEPTION 0 /* * debug mode: {\tt ebreak} instructions in M-mode enter Debug Mode. */ #define CSR_DCSR_EBREAKM_DEBUG_MODE 1 #define CSR_DCSR_EBREAKS_OFFSET 0xd #define CSR_DCSR_EBREAKS_LENGTH 1 #define CSR_DCSR_EBREAKS 0x2000 /* * exception: {\tt ebreak} instructions in S-mode behave as described in the * Privileged Spec. */ #define CSR_DCSR_EBREAKS_EXCEPTION 0 /* * debug mode: {\tt ebreak} instructions in S-mode enter Debug Mode. */ #define CSR_DCSR_EBREAKS_DEBUG_MODE 1 /* * This bit is hardwired to 0 if the hart does not support S-mode. */ #define CSR_DCSR_EBREAKU_OFFSET 0xc #define CSR_DCSR_EBREAKU_LENGTH 1 #define CSR_DCSR_EBREAKU 0x1000 /* * exception: {\tt ebreak} instructions in U-mode behave as described in the * Privileged Spec. */ #define CSR_DCSR_EBREAKU_EXCEPTION 0 /* * debug mode: {\tt ebreak} instructions in U-mode enter Debug Mode. */ #define CSR_DCSR_EBREAKU_DEBUG_MODE 1 /* * This bit is hardwired to 0 if the hart does not support U-mode. */ #define CSR_DCSR_STEPIE_OFFSET 0xb #define CSR_DCSR_STEPIE_LENGTH 1 #define CSR_DCSR_STEPIE 0x800 /* * interrupts disabled: Interrupts (including NMI) are disabled during single stepping. */ #define CSR_DCSR_STEPIE_INTERRUPTS_DISABLED 0 /* * interrupts enabled: Interrupts (including NMI) are enabled during single stepping. */ #define CSR_DCSR_STEPIE_INTERRUPTS_ENABLED 1 /* * Implementations may hard wire this bit to 0. * In that case interrupt behavior can be emulated by the debugger. * * The debugger must not change the value of this bit while the hart * is running. */ #define CSR_DCSR_STOPCOUNT_OFFSET 0xa #define CSR_DCSR_STOPCOUNT_LENGTH 1 #define CSR_DCSR_STOPCOUNT 0x400 /* * normal: Increment counters as usual. */ #define CSR_DCSR_STOPCOUNT_NORMAL 0 /* * freeze: Don't increment any hart-local counters while in Debug Mode or * on {\tt ebreak} instructions that cause entry into Debug Mode. * These counters include the {\tt instret} CSR. On single-hart cores * {\tt cycle} should be stopped, but on multi-hart cores it must keep * incrementing. */ #define CSR_DCSR_STOPCOUNT_FREEZE 1 /* * An implementation may hardwire this bit to 0 or 1. */ #define CSR_DCSR_STOPTIME_OFFSET 9 #define CSR_DCSR_STOPTIME_LENGTH 1 #define CSR_DCSR_STOPTIME 0x200 /* * normal: Increment \Rtime as usual. */ #define CSR_DCSR_STOPTIME_NORMAL 0 /* * freeze: Don't increment \Rtime while in Debug Mode. If all harts * have \FcsrDcsrStoptime=1 and are in Debug Mode then \Rmtime * is also allowed to stop incrementing. */ #define CSR_DCSR_STOPTIME_FREEZE 1 /* * An implementation may hardwire this bit to 0 or 1. */ /* * Explains why Debug Mode was entered. * * When there are multiple reasons to enter Debug Mode in a single * cycle, hardware should set \FcsrDcsrCause to the cause with the highest * priority. See table~\ref{tab:dcsrcausepriority} for priorities. */ #define CSR_DCSR_CAUSE_OFFSET 6 #define CSR_DCSR_CAUSE_LENGTH 3 #define CSR_DCSR_CAUSE 0x1c0 /* * ebreak: An {\tt ebreak} instruction was executed. */ #define CSR_DCSR_CAUSE_EBREAK 1 /* * trigger: A Trigger Module trigger fired with action=1. */ #define CSR_DCSR_CAUSE_TRIGGER 2 /* * haltreq: The debugger requested entry to Debug Mode using \FdmDmcontrolHaltreq. */ #define CSR_DCSR_CAUSE_HALTREQ 3 /* * step: The hart single stepped because \FcsrDcsrStep was set. */ #define CSR_DCSR_CAUSE_STEP 4 /* * resethaltreq: The hart halted directly out of reset due to \Fresethaltreq. It * is also acceptable to report 3 when this happens. */ #define CSR_DCSR_CAUSE_RESETHALTREQ 5 /* * group: The hart halted because it's part of a halt group. * Harts may report 3 for this cause instead. */ #define CSR_DCSR_CAUSE_GROUP 6 /* * Other values are reserved for future use. */ /* * Extends the prv field with the virtualization mode the hart was operating * in when Debug Mode was entered. The encoding is described in Table * \ref{tab:privmode}. * A debugger can change this value to change the hart's virtualization mode * when exiting Debug Mode. * This bit is hardwired to 0 on harts that do not support virtualization mode. */ #define CSR_DCSR_V_OFFSET 5 #define CSR_DCSR_V_LENGTH 1 #define CSR_DCSR_V 0x20 #define CSR_DCSR_MPRVEN_OFFSET 4 #define CSR_DCSR_MPRVEN_LENGTH 1 #define CSR_DCSR_MPRVEN 0x10 /* * disabled: \FcsrMstatusMprv in \Rmstatus is ignored in Debug Mode. */ #define CSR_DCSR_MPRVEN_DISABLED 0 /* * enabled: \FcsrMstatusMprv in \Rmstatus takes effect in Debug Mode. */ #define CSR_DCSR_MPRVEN_ENABLED 1 /* * Implementing this bit is optional. It may be tied to either 0 or 1. */ /* * When set, there is a Non-Maskable-Interrupt (NMI) pending for the hart. * * Since an NMI can indicate a hardware error condition, * reliable debugging may no longer be possible once this bit becomes set. * This is implementation-dependent. */ #define CSR_DCSR_NMIP_OFFSET 3 #define CSR_DCSR_NMIP_LENGTH 1 #define CSR_DCSR_NMIP 8 /* * When set and not in Debug Mode, the hart will only execute a single * instruction and then enter Debug Mode. See Section~\ref{stepBit} * for details. * * The debugger must not change the value of this bit while the hart * is running. */ #define CSR_DCSR_STEP_OFFSET 2 #define CSR_DCSR_STEP_LENGTH 1 #define CSR_DCSR_STEP 4 /* * Contains the privilege mode the hart was operating in when Debug * Mode was entered. The encoding is described in Table * \ref{tab:privmode}. A debugger can change this value to change * the hart's privilege mode when exiting Debug Mode. * * Not all privilege modes are supported on all harts. If the * encoding written is not supported or the debugger is not allowed to * change to it, the hart may change to any supported privilege mode. */ #define CSR_DCSR_PRV_OFFSET 0 #define CSR_DCSR_PRV_LENGTH 2 #define CSR_DCSR_PRV 3 #define CSR_DPC 0x7b1 #define CSR_DPC_DPC_OFFSET 0 #define CSR_DPC_DPC_LENGTH(DXLEN) DXLEN #define CSR_DPC_DPC(DXLEN) ((1ULL<<DXLEN) + -1) #define CSR_DSCRATCH0 0x7b2 #define CSR_DSCRATCH1 0x7b3 #define CSR_TSELECT 0x7a0 #define CSR_TSELECT_INDEX_OFFSET 0 #define CSR_TSELECT_INDEX_LENGTH(XLEN) XLEN #define CSR_TSELECT_INDEX(XLEN) ((1ULL<<XLEN) + -1) #define CSR_TDATA1 0x7a1 #define CSR_TDATA1_TYPE_OFFSET(XLEN) (XLEN + -4) #define CSR_TDATA1_TYPE_LENGTH 4 #define CSR_TDATA1_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) /* * none: There is no trigger at this \RcsrTselect. */ #define CSR_TDATA1_TYPE_NONE 0 /* * legacy: The trigger is a legacy SiFive address match trigger. These * should not be implemented and aren't further documented here. */ #define CSR_TDATA1_TYPE_LEGACY 1 /* * mcontrol: The trigger is an address/data match trigger. The remaining bits * in this register act as described in \RcsrMcontrol. */ #define CSR_TDATA1_TYPE_MCONTROL 2 /* * icount: The trigger is an instruction count trigger. The remaining bits * in this register act as described in \RcsrIcount. */ #define CSR_TDATA1_TYPE_ICOUNT 3 /* * itrigger: The trigger is an interrupt trigger. The remaining bits * in this register act as described in \RcsrItrigger. */ #define CSR_TDATA1_TYPE_ITRIGGER 4 /* * etrigger: The trigger is an exception trigger. The remaining bits * in this register act as described in \RcsrEtrigger. */ #define CSR_TDATA1_TYPE_ETRIGGER 5 /* * mcontrol6: The trigger is an address/data match trigger. The remaining bits * in this register act as described in \RcsrMcontrolSix. This is similar * to a type 2 trigger, but provides additional functionality and * should be used instead of type 2 in newer implementations. */ #define CSR_TDATA1_TYPE_MCONTROL6 6 /* * tmexttrigger: The trigger is a trigger source external to the TM. The * remaining bits in this register act as described in \RcsrTmexttrigger. */ #define CSR_TDATA1_TYPE_TMEXTTRIGGER 7 /* * custom: These trigger types are available for non-standard use. */ #define CSR_TDATA1_TYPE_CUSTOM_LOW 12 #define CSR_TDATA1_TYPE_CUSTOM_HIGH 14 /* * disabled: This trigger is disabled. In this state, \RcsrTdataTwo and * \RcsrTdataThree can be written with any value that is supported for * any of the types this trigger implements. The remaining bits in this * register are ignored. */ #define CSR_TDATA1_TYPE_DISABLED 15 /* * Other values are reserved for future use. */ /* * If \FcsrTdataOneType is 0, then this bit is hard-wired to 0. */ #define CSR_TDATA1_DMODE_OFFSET(XLEN) (XLEN + -5) #define CSR_TDATA1_DMODE_LENGTH 1 #define CSR_TDATA1_DMODE(XLEN) (1ULL<<(XLEN + -5)) /* * both: Both Debug and M-mode can write the {\tt tdata} registers at the * selected \RcsrTselect. */ #define CSR_TDATA1_DMODE_BOTH 0 /* * dmode: Only Debug Mode can write the {\tt tdata} registers at the * selected \RcsrTselect. Writes from other modes are ignored. */ #define CSR_TDATA1_DMODE_DMODE 1 /* * This bit is only writable from Debug Mode. * In ordinary use, external debuggers will always set this bit when * configuring a trigger. * When clearing this bit, debuggers should also set the action field * (whose location depends on \FcsrTdataOneType) to something other * than 1. */ /* * If \FcsrTdataOneType is 0, then this field is hard-wired to 0. * * Trigger-specific data. */ #define CSR_TDATA1_DATA_OFFSET 0 #define CSR_TDATA1_DATA_LENGTH(XLEN) (XLEN + -5) #define CSR_TDATA1_DATA(XLEN) ((1ULL<<(XLEN + -5)) + -1) #define CSR_TDATA2 0x7a2 #define CSR_TDATA2_DATA_OFFSET 0 #define CSR_TDATA2_DATA_LENGTH(XLEN) XLEN #define CSR_TDATA2_DATA(XLEN) ((1ULL<<XLEN) + -1) #define CSR_TDATA3 0x7a3 #define CSR_TDATA3_DATA_OFFSET 0 #define CSR_TDATA3_DATA_LENGTH(XLEN) XLEN #define CSR_TDATA3_DATA(XLEN) ((1ULL<<XLEN) + -1) #define CSR_TINFO 0x7a4 /* * One bit for each possible \FcsrTdataOneType enumerated in \RcsrTdataOne. Bit N * corresponds to type N. If the bit is set, then that type is * supported by the currently selected trigger. * * If the currently selected trigger doesn't exist, this field * contains 1. */ #define CSR_TINFO_INFO_OFFSET 0 #define CSR_TINFO_INFO_LENGTH 0x10 #define CSR_TINFO_INFO 0xffff #define CSR_TCONTROL 0x7a5 /* * M-mode previous trigger enable field. * * \FcsrTcontrolMpte and \FcsrTcontrolMte provide one solution to a problem * regarding triggers with action=0 firing in M-mode trap handlers. See * Section~\ref{sec:nativetrigger} for more details. * * When a breakpoint trap into M-mode is taken, \FcsrTcontrolMpte is set to the value of * \FcsrTcontrolMte. */ #define CSR_TCONTROL_MPTE_OFFSET 7 #define CSR_TCONTROL_MPTE_LENGTH 1 #define CSR_TCONTROL_MPTE 0x80 /* * M-mode trigger enable field. */ #define CSR_TCONTROL_MTE_OFFSET 3 #define CSR_TCONTROL_MTE_LENGTH 1 #define CSR_TCONTROL_MTE 8 /* * disabled: Triggers with action=0 do not match/fire while the hart is in M-mode. */ #define CSR_TCONTROL_MTE_DISABLED 0 /* * enabled: Triggers do match/fire while the hart is in M-mode. */ #define CSR_TCONTROL_MTE_ENABLED 1 /* * When a breakpoint trap into M-mode is taken, \FcsrTcontrolMte is set to 0. When {\tt * mret} is executed, \FcsrTcontrolMte is set to the value of \FcsrTcontrolMpte. */ #define CSR_HCONTEXT 0x6a8 /* * Hypervisor mode software can write a context number to this register, * which can be used to set triggers that only fire in that specific * context. * * An implementation may tie any number of upper bits in this field to * 0. If the H extension is not implemented, it's recommended to implement * no more than 6 bits on RV32 and 13 on RV64 (as visible through the * \RcsrMcontext register). If the H extension is implemented, * it's recommended to implement no more than 7 bits on RV32 * and 14 on RV64. */ #define CSR_HCONTEXT_HCONTEXT_OFFSET 0 #define CSR_HCONTEXT_HCONTEXT_LENGTH(XLEN) XLEN #define CSR_HCONTEXT_HCONTEXT(XLEN) ((1ULL<<XLEN) + -1) #define CSR_SCONTEXT 0x5a8 /* * Supervisor mode software can write a context number to this * register, which can be used to set triggers that only fire in that * specific context. * * An implementation may tie any number of high bits in this field to * 0. It's recommended to implement no more than 16 bits on RV32, and * 34 on RV64. */ #define CSR_SCONTEXT_DATA_OFFSET 0 #define CSR_SCONTEXT_DATA_LENGTH(XLEN) XLEN #define CSR_SCONTEXT_DATA(XLEN) ((1ULL<<XLEN) + -1) #define CSR_MCONTEXT 0x7a8 #define CSR_MSCONTEXT 0x7aa #define CSR_MCONTROL 0x7a1 #define CSR_MCONTROL_TYPE_OFFSET(XLEN) (XLEN + -4) #define CSR_MCONTROL_TYPE_LENGTH 4 #define CSR_MCONTROL_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) #define CSR_MCONTROL_DMODE_OFFSET(XLEN) (XLEN + -5) #define CSR_MCONTROL_DMODE_LENGTH 1 #define CSR_MCONTROL_DMODE(XLEN) (1ULL<<(XLEN + -5)) /* * Specifies the largest naturally aligned powers-of-two (NAPOT) range * supported by the hardware when \FcsrMcontrolMatch is 1. The value is the * logarithm base 2 of the number of bytes in that range. * A value of 0 indicates \FcsrMcontrolMatch 1 is not supported. * A value of 63 corresponds to the maximum NAPOT range, which is * $2^{63}$ bytes in size. */ #define CSR_MCONTROL_MASKMAX_OFFSET(XLEN) (XLEN + -0xb) #define CSR_MCONTROL_MASKMAX_LENGTH 6 #define CSR_MCONTROL_MASKMAX(XLEN) (0x3f * (1ULL<<(XLEN + -0xb))) /* * This field only exists when XLEN is at least 64. * It contains the 2 high bits of the access size. The low bits * come from \FcsrMcontrolSizelo. See \FcsrMcontrolSizelo for how this * is used. */ #define CSR_MCONTROL_SIZEHI_OFFSET 0x15 #define CSR_MCONTROL_SIZEHI_LENGTH 2 #define CSR_MCONTROL_SIZEHI 0x600000 /* * If this bit is implemented then it must become set when this * trigger fires and may become set when this trigger matches. * The trigger's user can set or clear it at any * time. It is used to determine which * trigger(s) matched. If the bit is not implemented, it is always 0 * and writing it has no effect. */ #define CSR_MCONTROL_HIT_OFFSET 0x14 #define CSR_MCONTROL_HIT_LENGTH 1 #define CSR_MCONTROL_HIT 0x100000 /* * This bit determines the contents of the XLEN-bit compare values. */ #define CSR_MCONTROL_SELECT_OFFSET 0x13 #define CSR_MCONTROL_SELECT_LENGTH 1 #define CSR_MCONTROL_SELECT 0x80000 /* * address: There is at least one compare value and it contains the lowest * virtual address of the access. * It is recommended that there are additional compare values for * the other accessed virtual addresses. * (E.g. on a 32-bit read from 0x4000, the lowest address is 0x4000 * and the other addresses are 0x4001, 0x4002, and 0x4003.) */ #define CSR_MCONTROL_SELECT_ADDRESS 0 /* * data: There is exactly one compare value and it contains the data * value loaded or stored, or the instruction executed. * Any bits beyond the size of the data access will contain 0. */ #define CSR_MCONTROL_SELECT_DATA 1 #define CSR_MCONTROL_TIMING_OFFSET 0x12 #define CSR_MCONTROL_TIMING_LENGTH 1 #define CSR_MCONTROL_TIMING 0x40000 /* * before: The action for this trigger will be taken just before the * instruction that triggered it is committed, but after all preceding * instructions are committed. \Rxepc or \RcsrDpc (depending * on \FcsrMcontrolAction) must be set to the virtual address of the * instruction that matched. * * If this is combined with \FcsrMcontrolLoad and * \FcsrMcontrolSelect=1 then a memory access will be * performed (including any side effects of performing such an access) even * though the load will not update its destination register. Debuggers * should consider this when setting such breakpoints on, for example, * memory-mapped I/O addresses. */ #define CSR_MCONTROL_TIMING_BEFORE 0 /* * after: The action for this trigger will be taken after the instruction * that triggered it is committed. It should be taken before the next * instruction is committed, but it is better to implement triggers imprecisely * than to not implement them at all. \Rxepc or * \RcsrDpc (depending on \FcsrMcontrolAction) must be set to * the virtual address of the next instruction that must be executed to * preserve the program flow. */ #define CSR_MCONTROL_TIMING_AFTER 1 /* * Most hardware will only implement one timing or the other, possibly * dependent on \FcsrMcontrolSelect, \FcsrMcontrolExecute, * \FcsrMcontrolLoad, and \FcsrMcontrolStore. This bit * primarily exists for the hardware to communicate to the debugger * what will happen. Hardware may implement the bit fully writable, in * which case the debugger has a little more control. * * Data load triggers with \FcsrMcontrolTiming of 0 will result in the same load * happening again when the debugger lets the hart run. For data load * triggers, debuggers must first attempt to set the breakpoint with * \FcsrMcontrolTiming of 1. * * If a trigger with \FcsrMcontrolTiming of 0 matches, it is * implementation-dependent whether that prevents a trigger with * \FcsrMcontrolTiming of 1 matching as well. */ /* * This field contains the 2 low bits of the access size. The high bits come * from \FcsrMcontrolSizehi. The combined value is interpreted as follows: */ #define CSR_MCONTROL_SIZELO_OFFSET 0x10 #define CSR_MCONTROL_SIZELO_LENGTH 2 #define CSR_MCONTROL_SIZELO 0x30000 /* * any: The trigger will attempt to match against an access of any size. * The behavior is only well-defined if $|select|=0$, or if the access * size is XLEN. */ #define CSR_MCONTROL_SIZELO_ANY 0 /* * 8bit: The trigger will only match against 8-bit memory accesses. */ #define CSR_MCONTROL_SIZELO_8BIT 1 /* * 16bit: The trigger will only match against 16-bit memory accesses or * execution of 16-bit instructions. */ #define CSR_MCONTROL_SIZELO_16BIT 2 /* * 32bit: The trigger will only match against 32-bit memory accesses or * execution of 32-bit instructions. */ #define CSR_MCONTROL_SIZELO_32BIT 3 /* * 48bit: The trigger will only match against execution of 48-bit instructions. */ #define CSR_MCONTROL_SIZELO_48BIT 4 /* * 64bit: The trigger will only match against 64-bit memory accesses or * execution of 64-bit instructions. */ #define CSR_MCONTROL_SIZELO_64BIT 5 /* * 80bit: The trigger will only match against execution of 80-bit instructions. */ #define CSR_MCONTROL_SIZELO_80BIT 6 /* * 96bit: The trigger will only match against execution of 96-bit instructions. */ #define CSR_MCONTROL_SIZELO_96BIT 7 /* * 112bit: The trigger will only match against execution of 112-bit instructions. */ #define CSR_MCONTROL_SIZELO_112BIT 8 /* * 128bit: The trigger will only match against 128-bit memory accesses or * execution of 128-bit instructions. */ #define CSR_MCONTROL_SIZELO_128BIT 9 /* * An implementation must support the value of 0, but all other values * are optional. When an implementation supports address triggers * (\FcsrMcontrolSelect=0), it is recommended that those triggers * support every access size that the hart supports, as well as for * every instruction size that the hart supports. * * Implementations such as RV32D or RV64V are able to perform loads * and stores that are wider than XLEN. Custom extensions may also * support instructions that are wider than XLEN. Because * \RcsrTdataTwo is of size XLEN, there is a known limitation that * data value triggers (\FcsrMcontrolSelect=1) can only be supported * for access sizes up to XLEN bits. When an implementation supports * data value triggers (\FcsrMcontrolSelect=1), it is recommended * that those triggers support every access size up to XLEN that the * hart supports, as well as for every instruction length up to XLEN * that the hart supports. */ /* * The action to take when the trigger fires. The values are explained * in Table~\ref{tab:action}. */ #define CSR_MCONTROL_ACTION_OFFSET 0xc #define CSR_MCONTROL_ACTION_LENGTH 4 #define CSR_MCONTROL_ACTION 0xf000 /* * breakpoint: */ #define CSR_MCONTROL_ACTION_BREAKPOINT 0 /* * debug mode: */ #define CSR_MCONTROL_ACTION_DEBUG_MODE 1 /* * trace on: */ #define CSR_MCONTROL_ACTION_TRACE_ON 2 /* * trace off: */ #define CSR_MCONTROL_ACTION_TRACE_OFF 3 /* * trace notify: */ #define CSR_MCONTROL_ACTION_TRACE_NOTIFY 4 /* * external0: */ #define CSR_MCONTROL_ACTION_EXTERNAL0 8 /* * external1: */ #define CSR_MCONTROL_ACTION_EXTERNAL1 9 #define CSR_MCONTROL_CHAIN_OFFSET 0xb #define CSR_MCONTROL_CHAIN_LENGTH 1 #define CSR_MCONTROL_CHAIN 0x800 /* * disabled: When this trigger matches, the configured action is taken. */ #define CSR_MCONTROL_CHAIN_DISABLED 0 /* * enabled: While this trigger does not match, it prevents the trigger with * the next index from matching. */ #define CSR_MCONTROL_CHAIN_ENABLED 1 /* * A trigger chain starts on the first trigger with $|chain|=1$ after * a trigger with $|chain|=0$, or simply on the first trigger if that * has $|chain|=1$. It ends on the first trigger after that which has * $|chain|=0$. This final trigger is part of the chain. The action * on all but the final trigger is ignored. The action on that final * trigger will be taken if and only if all the triggers in the chain * match at the same time. * * Debuggers should not terminate a chain with a trigger with a * different type. It is undefined when exactly such a chain fires. * * Because \FcsrMcontrolChain affects the next trigger, hardware must zero it in * writes to \RcsrMcontrol that set \FcsrTdataOneDmode to 0 if the next trigger has * \FcsrTdataOneDmode of 1. * In addition hardware should ignore writes to \RcsrMcontrol that set * \FcsrTdataOneDmode to 1 if the previous trigger has both \FcsrTdataOneDmode of 0 and * \FcsrMcontrolChain of 1. Debuggers must avoid the latter case by checking * \FcsrMcontrolChain on the previous trigger if they're writing \RcsrMcontrol. * * Implementations that wish to limit the maximum length of a trigger * chain (eg. to meet timing requirements) may do so by zeroing * \FcsrMcontrolChain in writes to \RcsrMcontrol that would make the chain too long. */ #define CSR_MCONTROL_MATCH_OFFSET 7 #define CSR_MCONTROL_MATCH_LENGTH 4 #define CSR_MCONTROL_MATCH 0x780 /* * equal: Matches when any compare value equals \RcsrTdataTwo. */ #define CSR_MCONTROL_MATCH_EQUAL 0 /* * napot: Matches when the top $M$ bits of any compare value match the top * $M$ bits of \RcsrTdataTwo. * $M$ is $|XLEN|-1$ minus the index of the least-significant * bit containing 0 in \RcsrTdataTwo. Debuggers should only write values * to \RcsrTdataTwo such that $M + $\FcsrMcontrolMaskmax$ \geq |XLEN|$ * and $M\gt0$ , otherwise it's undefined on what conditions the * trigger will match. */ #define CSR_MCONTROL_MATCH_NAPOT 1 /* * ge: Matches when any compare value is greater than (unsigned) or * equal to \RcsrTdataTwo. */ #define CSR_MCONTROL_MATCH_GE 2 /* * lt: Matches when any compare value is less than (unsigned) * \RcsrTdataTwo. */ #define CSR_MCONTROL_MATCH_LT 3 /* * mask low: Matches when $\frac{|XLEN|}{2}-1$:$0$ of any compare value * equals $\frac{|XLEN|}{2}-1$:$0$ of \RcsrTdataTwo after * $\frac{|XLEN|}{2}-1$:$0$ of the compare value is ANDed with * $|XLEN|-1$:$\frac{|XLEN|}{2}$ of \RcsrTdataTwo. */ #define CSR_MCONTROL_MATCH_MASK_LOW 4 /* * mask high: Matches when $|XLEN|-1$:$\frac{|XLEN|}{2}$ of any compare * value equals $\frac{|XLEN|}{2}-1$:$0$ of \RcsrTdataTwo after * $|XLEN|-1$:$\frac{|XLEN|}{2}$ of the compare value is ANDed with * $|XLEN|-1$:$\frac{|XLEN|}{2}$ of \RcsrTdataTwo. */ #define CSR_MCONTROL_MATCH_MASK_HIGH 5 /* * not equal: Matches when \FcsrMcontrolMatch$=0$ would not match. */ #define CSR_MCONTROL_MATCH_NOT_EQUAL 8 /* * not napot: Matches when \FcsrMcontrolMatch$=1$ would not match. */ #define CSR_MCONTROL_MATCH_NOT_NAPOT 9 /* * not mask low: Matches when \FcsrMcontrolMatch$=4$ would not match. */ #define CSR_MCONTROL_MATCH_NOT_MASK_LOW 12 /* * not mask high: Matches when \FcsrMcontrolMatch$=5$ would not match. */ #define CSR_MCONTROL_MATCH_NOT_MASK_HIGH 13 /* * Other values are reserved for future use. * * All comparisons only look at the lower XLEN (in the current mode) * bits of the compare values and of \RcsrTdataTwo. * When \FcsrMcontrolSelect=1 and access size is N, this is further * reduced, and comparisons only look at the lower N bits of the * compare values and of \RcsrTdataTwo. */ /* * When set, enable this trigger in M-mode. */ #define CSR_MCONTROL_M_OFFSET 6 #define CSR_MCONTROL_M_LENGTH 1 #define CSR_MCONTROL_M 0x40 /* * When set, enable this trigger in S/HS-mode. * This bit is hard-wired to 0 if the hart does not support * S-mode. */ #define CSR_MCONTROL_S_OFFSET 4 #define CSR_MCONTROL_S_LENGTH 1 #define CSR_MCONTROL_S 0x10 /* * When set, enable this trigger in U-mode. * This bit is hard-wired to 0 if the hart does not support * U-mode. */ #define CSR_MCONTROL_U_OFFSET 3 #define CSR_MCONTROL_U_LENGTH 1 #define CSR_MCONTROL_U 8 /* * When set, the trigger fires on the virtual address or opcode of an * instruction that is executed. */ #define CSR_MCONTROL_EXECUTE_OFFSET 2 #define CSR_MCONTROL_EXECUTE_LENGTH 1 #define CSR_MCONTROL_EXECUTE 4 /* * When set, the trigger fires on the virtual address or data of any * store. */ #define CSR_MCONTROL_STORE_OFFSET 1 #define CSR_MCONTROL_STORE_LENGTH 1 #define CSR_MCONTROL_STORE 2 /* * When set, the trigger fires on the virtual address or data of any * load. */ #define CSR_MCONTROL_LOAD_OFFSET 0 #define CSR_MCONTROL_LOAD_LENGTH 1 #define CSR_MCONTROL_LOAD 1 #define CSR_MCONTROL6 0x7a1 #define CSR_MCONTROL6_TYPE_OFFSET(XLEN) (XLEN + -4) #define CSR_MCONTROL6_TYPE_LENGTH 4 #define CSR_MCONTROL6_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) #define CSR_MCONTROL6_DMODE_OFFSET(XLEN) (XLEN + -5) #define CSR_MCONTROL6_DMODE_LENGTH 1 #define CSR_MCONTROL6_DMODE(XLEN) (1ULL<<(XLEN + -5)) /* * When set, enable this trigger in VS-mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ #define CSR_MCONTROL6_VS_OFFSET 0x18 #define CSR_MCONTROL6_VS_LENGTH 1 #define CSR_MCONTROL6_VS 0x1000000 /* * When set, enable this trigger in VU-mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ #define CSR_MCONTROL6_VU_OFFSET 0x17 #define CSR_MCONTROL6_VU_LENGTH 1 #define CSR_MCONTROL6_VU 0x800000 /* * If this bit is implemented then it must become set when this * trigger fires and may become set when this trigger matches. * The trigger's user can set or clear it at any * time. It is used to determine which * trigger(s) matched. If the bit is not implemented, it is always 0 * and writing it has no effect. */ #define CSR_MCONTROL6_HIT_OFFSET 0x16 #define CSR_MCONTROL6_HIT_LENGTH 1 #define CSR_MCONTROL6_HIT 0x400000 /* * This bit determines the contents of the XLEN-bit compare values. */ #define CSR_MCONTROL6_SELECT_OFFSET 0x15 #define CSR_MCONTROL6_SELECT_LENGTH 1 #define CSR_MCONTROL6_SELECT 0x200000 /* * address: There is at least one compare value and it contains the lowest * virtual address of the access. * In addition, it is recommended that there are additional compare * values for the other accessed virtual addresses match. * (E.g. on a 32-bit read from 0x4000, the lowest address is 0x4000 * and the other addresses are 0x4001, 0x4002, and 0x4003.) */ #define CSR_MCONTROL6_SELECT_ADDRESS 0 /* * data: There is exactly one compare value and it contains the data * value loaded or stored, or the instruction executed. * Any bits beyond the size of the data access will contain 0. */ #define CSR_MCONTROL6_SELECT_DATA 1 #define CSR_MCONTROL6_TIMING_OFFSET 0x14 #define CSR_MCONTROL6_TIMING_LENGTH 1 #define CSR_MCONTROL6_TIMING 0x100000 /* * before: The action for this trigger will be taken just before the * instruction that triggered it is committed, but after all preceding * instructions are committed. \Rxepc or \RcsrDpc (depending * on \FcsrMcontrolSixAction) must be set to the virtual address of the * instruction that matched. * * If this is combined with \FcsrMcontrolSixLoad and * \FcsrMcontrolSixSelect=1 then a memory access will be * performed (including any side effects of performing such an access) even * though the load will not update its destination register. Debuggers * should consider this when setting such breakpoints on, for example, * memory-mapped I/O addresses. */ #define CSR_MCONTROL6_TIMING_BEFORE 0 /* * after: The action for this trigger will be taken after the instruction * that triggered it is committed. It should be taken before the next * instruction is committed, but it is better to implement triggers imprecisely * than to not implement them at all. \Rxepc or * \RcsrDpc (depending on \FcsrMcontrolSixAction) must be set to * the virtual address of the next instruction that must be executed to * preserve the program flow. */ #define CSR_MCONTROL6_TIMING_AFTER 1 /* * Most hardware will only implement one timing or the other, possibly * dependent on \FcsrMcontrolSixSelect, \FcsrMcontrolSixExecute, * \FcsrMcontrolSixLoad, and \FcsrMcontrolSixStore. This bit * primarily exists for the hardware to communicate to the debugger * what will happen. Hardware may implement the bit fully writable, in * which case the debugger has a little more control. * * Data load triggers with \FcsrMcontrolSixTiming of 0 will result in the same load * happening again when the debugger lets the hart run. For data load * triggers, debuggers must first attempt to set the breakpoint with * \FcsrMcontrolSixTiming of 1. * * If a trigger with \FcsrMcontrolSixTiming of 0 matches, it is * implementation-dependent whether that prevents a trigger with * \FcsrMcontrolSixTiming of 1 matching as well. */ #define CSR_MCONTROL6_SIZE_OFFSET 0x10 #define CSR_MCONTROL6_SIZE_LENGTH 4 #define CSR_MCONTROL6_SIZE 0xf0000 /* * any: The trigger will attempt to match against an access of any size. * The behavior is only well-defined if $|select|=0$, or if the access * size is XLEN. */ #define CSR_MCONTROL6_SIZE_ANY 0 /* * 8bit: The trigger will only match against 8-bit memory accesses. */ #define CSR_MCONTROL6_SIZE_8BIT 1 /* * 16bit: The trigger will only match against 16-bit memory accesses or * execution of 16-bit instructions. */ #define CSR_MCONTROL6_SIZE_16BIT 2 /* * 32bit: The trigger will only match against 32-bit memory accesses or * execution of 32-bit instructions. */ #define CSR_MCONTROL6_SIZE_32BIT 3 /* * 48bit: The trigger will only match against execution of 48-bit instructions. */ #define CSR_MCONTROL6_SIZE_48BIT 4 /* * 64bit: The trigger will only match against 64-bit memory accesses or * execution of 64-bit instructions. */ #define CSR_MCONTROL6_SIZE_64BIT 5 /* * 80bit: The trigger will only match against execution of 80-bit instructions. */ #define CSR_MCONTROL6_SIZE_80BIT 6 /* * 96bit: The trigger will only match against execution of 96-bit instructions. */ #define CSR_MCONTROL6_SIZE_96BIT 7 /* * 112bit: The trigger will only match against execution of 112-bit instructions. */ #define CSR_MCONTROL6_SIZE_112BIT 8 /* * 128bit: The trigger will only match against 128-bit memory accesses or * execution of 128-bit instructions. */ #define CSR_MCONTROL6_SIZE_128BIT 9 /* * An implementation must support the value of 0, but all other values * are optional. When an implementation supports address triggers * (\FcsrMcontrolSixSelect=0), it is recommended that those triggers * support every access size that the hart supports, as well as for * every instruction size that the hart supports. * * Implementations such as RV32D or RV64V are able to perform loads * and stores that are wider than XLEN. Custom extensions may also * support instructions that are wider than XLEN. Because * \RcsrTdataTwo is of size XLEN, there is a known limitation that * data value triggers (\FcsrMcontrolSixSelect=1) can only be supported * for access sizes up to XLEN bits. When an implementation supports * data value triggers (\FcsrMcontrolSixSelect=1), it is recommended * that those triggers support every access size up to XLEN that the * hart supports, as well as for every instruction length up to XLEN * that the hart supports. */ /* * The action to take when the trigger fires. The values are explained * in Table~\ref{tab:action}. */ #define CSR_MCONTROL6_ACTION_OFFSET 0xc #define CSR_MCONTROL6_ACTION_LENGTH 4 #define CSR_MCONTROL6_ACTION 0xf000 /* * breakpoint: */ #define CSR_MCONTROL6_ACTION_BREAKPOINT 0 /* * debug mode: */ #define CSR_MCONTROL6_ACTION_DEBUG_MODE 1 /* * trace on: */ #define CSR_MCONTROL6_ACTION_TRACE_ON 2 /* * trace off: */ #define CSR_MCONTROL6_ACTION_TRACE_OFF 3 /* * trace notify: */ #define CSR_MCONTROL6_ACTION_TRACE_NOTIFY 4 /* * external0: */ #define CSR_MCONTROL6_ACTION_EXTERNAL0 8 /* * external1: */ #define CSR_MCONTROL6_ACTION_EXTERNAL1 9 #define CSR_MCONTROL6_CHAIN_OFFSET 0xb #define CSR_MCONTROL6_CHAIN_LENGTH 1 #define CSR_MCONTROL6_CHAIN 0x800 /* * disabled: When this trigger matches, the configured action is taken. */ #define CSR_MCONTROL6_CHAIN_DISABLED 0 /* * enabled: While this trigger does not match, it prevents the trigger with * the next index from matching. */ #define CSR_MCONTROL6_CHAIN_ENABLED 1 /* * A trigger chain starts on the first trigger with $|chain|=1$ after * a trigger with $|chain|=0$, or simply on the first trigger if that * has $|chain|=1$. It ends on the first trigger after that which has * $|chain|=0$. This final trigger is part of the chain. The action * on all but the final trigger is ignored. The action on that final * trigger will be taken if and only if all the triggers in the chain * match at the same time. * * Debuggers should not terminate a chain with a trigger with a * different type. It is undefined when exactly such a chain fires. * * Because \FcsrMcontrolSixChain affects the next trigger, hardware must zero it in * writes to \RcsrMcontrolSix that set \FcsrTdataOneDmode to 0 if the next trigger has * \FcsrTdataOneDmode of 1. * In addition hardware should ignore writes to \RcsrMcontrolSix that set * \FcsrTdataOneDmode to 1 if the previous trigger has both \FcsrTdataOneDmode of 0 and * \FcsrMcontrolSixChain of 1. Debuggers must avoid the latter case by checking * \FcsrMcontrolSixChain on the previous trigger if they're writing \RcsrMcontrolSix. * * Implementations that wish to limit the maximum length of a trigger * chain (eg. to meet timing requirements) may do so by zeroing * \FcsrMcontrolSixChain in writes to \RcsrMcontrolSix that would make the chain too long. */ #define CSR_MCONTROL6_MATCH_OFFSET 7 #define CSR_MCONTROL6_MATCH_LENGTH 4 #define CSR_MCONTROL6_MATCH 0x780 /* * equal: Matches when any compare value equals \RcsrTdataTwo. */ #define CSR_MCONTROL6_MATCH_EQUAL 0 /* * napot: Matches when the top $M$ bits of any compare value match the top * $M$ bits of \RcsrTdataTwo. * $M$ is $|XLEN|-1$ minus the index of the least-significant bit * containing 0 in \RcsrTdataTwo. * \RcsrTdataTwo is WARL and if bits $|maskmax6|-1$:0 are written with all * ones then bit $|maskmax6|-1$ will be set to 0 while the values of bits $|maskmax6|-2$:0 * are \unspecified. * Legal values for \RcsrTdataTwo require $M + |maskmax6| \geq |XLEN|$ and $M\gt0$. * See above for how to determine maskmax6. */ #define CSR_MCONTROL6_MATCH_NAPOT 1 /* * ge: Matches when any compare value is greater than (unsigned) or * equal to \RcsrTdataTwo. */ #define CSR_MCONTROL6_MATCH_GE 2 /* * lt: Matches when any compare value is less than (unsigned) * \RcsrTdataTwo. */ #define CSR_MCONTROL6_MATCH_LT 3 /* * mask low: Matches when $\frac{|XLEN|}{2}-1$:$0$ of any compare value * equals $\frac{|XLEN|}{2}-1$:$0$ of \RcsrTdataTwo after * $\frac{|XLEN|}{2}-1$:$0$ of the compare value is ANDed with * $|XLEN|-1$:$\frac{|XLEN|}{2}$ of \RcsrTdataTwo. */ #define CSR_MCONTROL6_MATCH_MASK_LOW 4 /* * mask high: Matches when $|XLEN|-1$:$\frac{|XLEN|}{2}$ of any compare * value equals $\frac{|XLEN|}{2}-1$:$0$ of \RcsrTdataTwo after * $|XLEN|-1$:$\frac{|XLEN|}{2}$ of the compare value is ANDed with * $|XLEN|-1$:$\frac{|XLEN|}{2}$ of \RcsrTdataTwo. */ #define CSR_MCONTROL6_MATCH_MASK_HIGH 5 /* * not equal: Matches when \FcsrMcontrolSixMatch$=0$ would not match. */ #define CSR_MCONTROL6_MATCH_NOT_EQUAL 8 /* * not napot: Matches when \FcsrMcontrolSixMatch$=1$ would not match. */ #define CSR_MCONTROL6_MATCH_NOT_NAPOT 9 /* * not mask low: Matches when \FcsrMcontrolSixMatch$=4$ would not match. */ #define CSR_MCONTROL6_MATCH_NOT_MASK_LOW 12 /* * not mask high: Matches when \FcsrMcontrolSixMatch$=5$ would not match. */ #define CSR_MCONTROL6_MATCH_NOT_MASK_HIGH 13 /* * Other values are reserved for future use. * * All comparisons only look at the lower XLEN (in the current mode) * bits of the compare values and of \RcsrTdataTwo. * When \FcsrMcontrolSelect=1 and access size is N, this is further * reduced, and comparisons only look at the lower N bits of the * compare values and of \RcsrTdataTwo. */ /* * When set, enable this trigger in M-mode. */ #define CSR_MCONTROL6_M_OFFSET 6 #define CSR_MCONTROL6_M_LENGTH 1 #define CSR_MCONTROL6_M 0x40 /* * When set, enable this trigger in S/HS-mode. * This bit is hard-wired to 0 if the hart does not support * S-mode. */ #define CSR_MCONTROL6_S_OFFSET 4 #define CSR_MCONTROL6_S_LENGTH 1 #define CSR_MCONTROL6_S 0x10 /* * When set, enable this trigger in U-mode. * This bit is hard-wired to 0 if the hart does not support * U-mode. */ #define CSR_MCONTROL6_U_OFFSET 3 #define CSR_MCONTROL6_U_LENGTH 1 #define CSR_MCONTROL6_U 8 /* * When set, the trigger fires on the virtual address or opcode of an * instruction that is executed. */ #define CSR_MCONTROL6_EXECUTE_OFFSET 2 #define CSR_MCONTROL6_EXECUTE_LENGTH 1 #define CSR_MCONTROL6_EXECUTE 4 /* * When set, the trigger fires on the virtual address or data of any * store. */ #define CSR_MCONTROL6_STORE_OFFSET 1 #define CSR_MCONTROL6_STORE_LENGTH 1 #define CSR_MCONTROL6_STORE 2 /* * When set, the trigger fires on the virtual address or data of any * load. */ #define CSR_MCONTROL6_LOAD_OFFSET 0 #define CSR_MCONTROL6_LOAD_LENGTH 1 #define CSR_MCONTROL6_LOAD 1 #define CSR_ICOUNT 0x7a1 #define CSR_ICOUNT_TYPE_OFFSET(XLEN) (XLEN + -4) #define CSR_ICOUNT_TYPE_LENGTH 4 #define CSR_ICOUNT_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) #define CSR_ICOUNT_DMODE_OFFSET(XLEN) (XLEN + -5) #define CSR_ICOUNT_DMODE_LENGTH 1 #define CSR_ICOUNT_DMODE(XLEN) (1ULL<<(XLEN + -5)) /* * When set, enable this trigger in VS-mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ #define CSR_ICOUNT_VS_OFFSET 0x1a #define CSR_ICOUNT_VS_LENGTH 1 #define CSR_ICOUNT_VS 0x4000000 /* * When set, enable this trigger in VU-mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ #define CSR_ICOUNT_VU_OFFSET 0x19 #define CSR_ICOUNT_VU_LENGTH 1 #define CSR_ICOUNT_VU 0x2000000 /* * If this bit is implemented, the hardware sets it when this * trigger fires. The trigger's user can set or clear it at any * time. It is used to determine which * trigger(s) fires. If the bit is not implemented, it is always 0 * and writing it has no effect. */ #define CSR_ICOUNT_HIT_OFFSET 0x18 #define CSR_ICOUNT_HIT_LENGTH 1 #define CSR_ICOUNT_HIT 0x1000000 /* * The trigger will generally fire after \FcsrIcountCount instructions * in enabled modes have been executed. See above for the precise behavior. */ #define CSR_ICOUNT_COUNT_OFFSET 0xa #define CSR_ICOUNT_COUNT_LENGTH 0xe #define CSR_ICOUNT_COUNT 0xfffc00 /* * When set, enable this trigger in M-mode. */ #define CSR_ICOUNT_M_OFFSET 9 #define CSR_ICOUNT_M_LENGTH 1 #define CSR_ICOUNT_M 0x200 /* * This bit becomes set when \FcsrIcountCount is decremented from 1 * to 0. It is cleared when the trigger fires, which will happen just * before executing the next instruction in one of the enabled modes. */ #define CSR_ICOUNT_PENDING_OFFSET 8 #define CSR_ICOUNT_PENDING_LENGTH 1 #define CSR_ICOUNT_PENDING 0x100 /* * When set, enable this trigger in S/HS-mode. * This bit is hard-wired to 0 if the hart does not support * S-mode. */ #define CSR_ICOUNT_S_OFFSET 7 #define CSR_ICOUNT_S_LENGTH 1 #define CSR_ICOUNT_S 0x80 /* * When set, enable this trigger in U-mode. * This bit is hard-wired to 0 if the hart does not support * U-mode. */ #define CSR_ICOUNT_U_OFFSET 6 #define CSR_ICOUNT_U_LENGTH 1 #define CSR_ICOUNT_U 0x40 /* * The action to take when the trigger fires. The values are explained * in Table~\ref{tab:action}. */ #define CSR_ICOUNT_ACTION_OFFSET 0 #define CSR_ICOUNT_ACTION_LENGTH 6 #define CSR_ICOUNT_ACTION 0x3f /* * breakpoint: */ #define CSR_ICOUNT_ACTION_BREAKPOINT 0 /* * debug mode: */ #define CSR_ICOUNT_ACTION_DEBUG_MODE 1 /* * trace on: */ #define CSR_ICOUNT_ACTION_TRACE_ON 2 /* * trace off: */ #define CSR_ICOUNT_ACTION_TRACE_OFF 3 /* * trace notify: */ #define CSR_ICOUNT_ACTION_TRACE_NOTIFY 4 /* * external0: */ #define CSR_ICOUNT_ACTION_EXTERNAL0 8 /* * external1: */ #define CSR_ICOUNT_ACTION_EXTERNAL1 9 #define CSR_ITRIGGER 0x7a1 #define CSR_ITRIGGER_TYPE_OFFSET(XLEN) (XLEN + -4) #define CSR_ITRIGGER_TYPE_LENGTH 4 #define CSR_ITRIGGER_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) #define CSR_ITRIGGER_DMODE_OFFSET(XLEN) (XLEN + -5) #define CSR_ITRIGGER_DMODE_LENGTH 1 #define CSR_ITRIGGER_DMODE(XLEN) (1ULL<<(XLEN + -5)) /* * If this bit is implemented, the hardware sets it when this * trigger matches. The trigger's user can set or clear it at any * time. It is used to determine which * trigger(s) matched. If the bit is not implemented, it is always 0 * and writing it has no effect. */ #define CSR_ITRIGGER_HIT_OFFSET(XLEN) (XLEN + -6) #define CSR_ITRIGGER_HIT_LENGTH 1 #define CSR_ITRIGGER_HIT(XLEN) (1ULL<<(XLEN + -6)) /* * When set, enable this trigger for interrupts that are taken from VS * mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ #define CSR_ITRIGGER_VS_OFFSET 0xc #define CSR_ITRIGGER_VS_LENGTH 1 #define CSR_ITRIGGER_VS 0x1000 /* * When set, enable this trigger for interrupts that are taken from VU * mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ #define CSR_ITRIGGER_VU_OFFSET 0xb #define CSR_ITRIGGER_VU_LENGTH 1 #define CSR_ITRIGGER_VU 0x800 /* * When set, non-maskable interrupts cause this * trigger to fire if the trigger is enabled for the current mode. */ #define CSR_ITRIGGER_NMI_OFFSET 0xa #define CSR_ITRIGGER_NMI_LENGTH 1 #define CSR_ITRIGGER_NMI 0x400 /* * When set, enable this trigger for interrupts that are taken from M * mode. */ #define CSR_ITRIGGER_M_OFFSET 9 #define CSR_ITRIGGER_M_LENGTH 1 #define CSR_ITRIGGER_M 0x200 /* * When set, enable this trigger for interrupts that are taken from S/HS * mode. * This bit is hard-wired to 0 if the hart does not support * S-mode. */ #define CSR_ITRIGGER_S_OFFSET 7 #define CSR_ITRIGGER_S_LENGTH 1 #define CSR_ITRIGGER_S 0x80 /* * When set, enable this trigger for interrupts that are taken from U * mode. * This bit is hard-wired to 0 if the hart does not support * U-mode. */ #define CSR_ITRIGGER_U_OFFSET 6 #define CSR_ITRIGGER_U_LENGTH 1 #define CSR_ITRIGGER_U 0x40 /* * The action to take when the trigger fires. The values are explained * in Table~\ref{tab:action}. */ #define CSR_ITRIGGER_ACTION_OFFSET 0 #define CSR_ITRIGGER_ACTION_LENGTH 6 #define CSR_ITRIGGER_ACTION 0x3f /* * breakpoint: */ #define CSR_ITRIGGER_ACTION_BREAKPOINT 0 /* * debug mode: */ #define CSR_ITRIGGER_ACTION_DEBUG_MODE 1 /* * trace on: */ #define CSR_ITRIGGER_ACTION_TRACE_ON 2 /* * trace off: */ #define CSR_ITRIGGER_ACTION_TRACE_OFF 3 /* * trace notify: */ #define CSR_ITRIGGER_ACTION_TRACE_NOTIFY 4 /* * external0: */ #define CSR_ITRIGGER_ACTION_EXTERNAL0 8 /* * external1: */ #define CSR_ITRIGGER_ACTION_EXTERNAL1 9 #define CSR_ETRIGGER 0x7a1 #define CSR_ETRIGGER_TYPE_OFFSET(XLEN) (XLEN + -4) #define CSR_ETRIGGER_TYPE_LENGTH 4 #define CSR_ETRIGGER_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) #define CSR_ETRIGGER_DMODE_OFFSET(XLEN) (XLEN + -5) #define CSR_ETRIGGER_DMODE_LENGTH 1 #define CSR_ETRIGGER_DMODE(XLEN) (1ULL<<(XLEN + -5)) /* * If this bit is implemented, the hardware sets it when this * trigger matches. The trigger's user can set or clear it at any * time. It is used to determine which * trigger(s) matched. If the bit is not implemented, it is always 0 * and writing it has no effect. */ #define CSR_ETRIGGER_HIT_OFFSET(XLEN) (XLEN + -6) #define CSR_ETRIGGER_HIT_LENGTH 1 #define CSR_ETRIGGER_HIT(XLEN) (1ULL<<(XLEN + -6)) /* * When set, enable this trigger for exceptions that are taken from VS * mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ #define CSR_ETRIGGER_VS_OFFSET 0xc #define CSR_ETRIGGER_VS_LENGTH 1 #define CSR_ETRIGGER_VS 0x1000 /* * When set, enable this trigger for exceptions that are taken from VU * mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ #define CSR_ETRIGGER_VU_OFFSET 0xb #define CSR_ETRIGGER_VU_LENGTH 1 #define CSR_ETRIGGER_VU 0x800 /* * When set, enable this trigger for exceptions that are taken from M * mode. */ #define CSR_ETRIGGER_M_OFFSET 9 #define CSR_ETRIGGER_M_LENGTH 1 #define CSR_ETRIGGER_M 0x200 /* * When set, enable this trigger for exceptions that are taken from S/HS * mode. * This bit is hard-wired to 0 if the hart does not support * S-mode. */ #define CSR_ETRIGGER_S_OFFSET 7 #define CSR_ETRIGGER_S_LENGTH 1 #define CSR_ETRIGGER_S 0x80 /* * When set, enable this trigger for exceptions that are taken from U * mode. * This bit is hard-wired to 0 if the hart does not support * U-mode. */ #define CSR_ETRIGGER_U_OFFSET 6 #define CSR_ETRIGGER_U_LENGTH 1 #define CSR_ETRIGGER_U 0x40 /* * The action to take when the trigger fires. The values are explained * in Table~\ref{tab:action}. */ #define CSR_ETRIGGER_ACTION_OFFSET 0 #define CSR_ETRIGGER_ACTION_LENGTH 6 #define CSR_ETRIGGER_ACTION 0x3f /* * breakpoint: */ #define CSR_ETRIGGER_ACTION_BREAKPOINT 0 /* * debug mode: */ #define CSR_ETRIGGER_ACTION_DEBUG_MODE 1 /* * trace on: */ #define CSR_ETRIGGER_ACTION_TRACE_ON 2 /* * trace off: */ #define CSR_ETRIGGER_ACTION_TRACE_OFF 3 /* * trace notify: */ #define CSR_ETRIGGER_ACTION_TRACE_NOTIFY 4 /* * external0: */ #define CSR_ETRIGGER_ACTION_EXTERNAL0 8 /* * external1: */ #define CSR_ETRIGGER_ACTION_EXTERNAL1 9 #define CSR_TMEXTTRIGGER 0x7a1 #define CSR_TMEXTTRIGGER_TYPE_OFFSET(XLEN) (XLEN + -4) #define CSR_TMEXTTRIGGER_TYPE_LENGTH 4 #define CSR_TMEXTTRIGGER_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) #define CSR_TMEXTTRIGGER_DMODE_OFFSET(XLEN) (XLEN + -5) #define CSR_TMEXTTRIGGER_DMODE_LENGTH 1 #define CSR_TMEXTTRIGGER_DMODE(XLEN) (1ULL<<(XLEN + -5)) /* * If this bit is implemented, the hardware sets it when this * trigger matches. The trigger's user can set or clear it at any * time. It is used to determine which * trigger(s) matched. If the bit is not implemented, it is always 0 * and writing it has no effect. */ #define CSR_TMEXTTRIGGER_HIT_OFFSET(XLEN) (XLEN + -6) #define CSR_TMEXTTRIGGER_HIT_LENGTH 1 #define CSR_TMEXTTRIGGER_HIT(XLEN) (1ULL<<(XLEN + -6)) /* * This optional bit, when set, causes this trigger to fire whenever an attached * interrupt controller signals a trigger. */ #define CSR_TMEXTTRIGGER_INTCTL_OFFSET 0x16 #define CSR_TMEXTTRIGGER_INTCTL_LENGTH 1 #define CSR_TMEXTTRIGGER_INTCTL 0x400000 /* * Selects any combination of up to 16 external debug trigger inputs * that cause this trigger to fire. */ #define CSR_TMEXTTRIGGER_SELECT_OFFSET 6 #define CSR_TMEXTTRIGGER_SELECT_LENGTH 0x10 #define CSR_TMEXTTRIGGER_SELECT 0x3fffc0 /* * The action to take when the trigger fires. The values are explained * in Table~\ref{tab:action}. */ #define CSR_TMEXTTRIGGER_ACTION_OFFSET 0 #define CSR_TMEXTTRIGGER_ACTION_LENGTH 6 #define CSR_TMEXTTRIGGER_ACTION 0x3f /* * breakpoint: */ #define CSR_TMEXTTRIGGER_ACTION_BREAKPOINT 0 /* * debug mode: */ #define CSR_TMEXTTRIGGER_ACTION_DEBUG_MODE 1 /* * trace on: */ #define CSR_TMEXTTRIGGER_ACTION_TRACE_ON 2 /* * trace off: */ #define CSR_TMEXTTRIGGER_ACTION_TRACE_OFF 3 /* * trace notify: */ #define CSR_TMEXTTRIGGER_ACTION_TRACE_NOTIFY 4 /* * external0: */ #define CSR_TMEXTTRIGGER_ACTION_EXTERNAL0 8 /* * external1: */ #define CSR_TMEXTTRIGGER_ACTION_EXTERNAL1 9 #define CSR_TEXTRA32 0x7a3 /* * Data used together with \FcsrTextraThirtytwoMhselect. */ #define CSR_TEXTRA32_MHVALUE_OFFSET 0x1a #define CSR_TEXTRA32_MHVALUE_LENGTH 6 #define CSR_TEXTRA32_MHVALUE 0xfc000000U #define CSR_TEXTRA32_MHSELECT_OFFSET 0x17 #define CSR_TEXTRA32_MHSELECT_LENGTH 3 #define CSR_TEXTRA32_MHSELECT 0x3800000 /* * ignore: Ignore \FcsrTextraThirtytwoMhvalue. */ #define CSR_TEXTRA32_MHSELECT_IGNORE 0 /* * mcontext: This trigger will only match if the low bits of * \RcsrMcontext/\RcsrHcontext equal \FcsrTextraThirtytwoMhvalue. */ #define CSR_TEXTRA32_MHSELECT_MCONTEXT 4 /* * 1, 5 (mcontext\_select): This trigger will only match if the low bits of * \RcsrMcontext/\RcsrHcontext equal \{\FcsrTextraThirtytwoMhvalue, mhselect[2]\}. * * 2, 6 (vmid\_select): This trigger will only match if VMID in hgatp equals the lower VMIDMAX * (defined in the Privileged Spec) bits of \{\FcsrTextraThirtytwoMhvalue, mhselect[2]\}. * * 3, 7 (reserved): Reserved. * * If the H extension is not supported, the only legal values are 0 and 4. */ /* * When the least significant bit of this field is 1, it causes bits 7:0 * in the comparison to be ignored, when \FcsrTextraThirtytwoSselect=1. * When the next most significant bit of this field is 1, it causes bits 15:8 * to be ignored in the comparison, when \FcsrTextraThirtytwoSselect=1. */ #define CSR_TEXTRA32_SBYTEMASK_OFFSET 0x12 #define CSR_TEXTRA32_SBYTEMASK_LENGTH 2 #define CSR_TEXTRA32_SBYTEMASK 0xc0000 /* * Data used together with \FcsrTextraThirtytwoSselect. * * This field should be tied to 0 when S-mode is not supported. */ #define CSR_TEXTRA32_SVALUE_OFFSET 2 #define CSR_TEXTRA32_SVALUE_LENGTH 0x10 #define CSR_TEXTRA32_SVALUE 0x3fffc #define CSR_TEXTRA32_SSELECT_OFFSET 0 #define CSR_TEXTRA32_SSELECT_LENGTH 2 #define CSR_TEXTRA32_SSELECT 3 /* * ignore: Ignore \FcsrTextraThirtytwoSvalue. */ #define CSR_TEXTRA32_SSELECT_IGNORE 0 /* * scontext: This trigger will only match if the low bits of * \RcsrScontext equal \FcsrTextraThirtytwoSvalue. */ #define CSR_TEXTRA32_SSELECT_SCONTEXT 1 /* * asid: This trigger will only match if: * \begin{itemize}[noitemsep,nolistsep] * \item the mode is VS-mode or VU-mode and ASID in \Rvsatp * equals the lower ASIDMAX (defined in the Privileged Spec) bits * of \FcsrTextraThirtytwoSvalue. * \item in all other modes, ASID in \Rsatp equals the lower * ASIDMAX (defined in the Privileged Spec) bits of * \FcsrTextraThirtytwoSvalue. * \end{itemize} */ #define CSR_TEXTRA32_SSELECT_ASID 2 /* * This field should be tied to 0 when S-mode is not supported. */ #define CSR_TEXTRA64 0x7a3 #define CSR_TEXTRA64_MHVALUE_OFFSET 0x33 #define CSR_TEXTRA64_MHVALUE_LENGTH 0xd #define CSR_TEXTRA64_MHVALUE 0xfff8000000000000ULL #define CSR_TEXTRA64_MHSELECT_OFFSET 0x30 #define CSR_TEXTRA64_MHSELECT_LENGTH 3 #define CSR_TEXTRA64_MHSELECT 0x7000000000000ULL /* * When the least significant bit of this field is 1, it causes bits 7:0 * in the comparison to be ignored, when \FcsrTextraSixtyfourSselect=1. * Likewise, the second bit controls the comparison of bits 15:8, * third bit controls the comparison of bits 23:16, * fourth bit controls the comparison of bits 31:24, and * fifth bit controls the comparison of bits 33:32. */ #define CSR_TEXTRA64_SBYTEMASK_OFFSET 0x24 #define CSR_TEXTRA64_SBYTEMASK_LENGTH 5 #define CSR_TEXTRA64_SBYTEMASK 0x1f000000000ULL #define CSR_TEXTRA64_SVALUE_OFFSET 2 #define CSR_TEXTRA64_SVALUE_LENGTH 0x22 #define CSR_TEXTRA64_SVALUE 0xffffffffcULL #define CSR_TEXTRA64_SSELECT_OFFSET 0 #define CSR_TEXTRA64_SSELECT_LENGTH 2 #define CSR_TEXTRA64_SSELECT 3 #define DM_DMSTATUS 0x11 #define DM_DMSTATUS_NDMRESETPENDING_OFFSET 0x18 #define DM_DMSTATUS_NDMRESETPENDING_LENGTH 1 #define DM_DMSTATUS_NDMRESETPENDING 0x1000000 /* * false: Unimplemented, or \FdmDmcontrolNdmreset is zero and no ndmreset is currently * in progress. */ #define DM_DMSTATUS_NDMRESETPENDING_FALSE 0 /* * true: \FdmDmcontrolNdmreset is currently nonzero, or there is an ndmreset in progress. */ #define DM_DMSTATUS_NDMRESETPENDING_TRUE 1 #define DM_DMSTATUS_STICKYUNAVAIL_OFFSET 0x17 #define DM_DMSTATUS_STICKYUNAVAIL_LENGTH 1 #define DM_DMSTATUS_STICKYUNAVAIL 0x800000 /* * current: The per-hart {\tt unavail} bits reflect the current state of the hart. */ #define DM_DMSTATUS_STICKYUNAVAIL_CURRENT 0 /* * sticky: The per-hart {\tt unavail} bits are sticky. Once they are set, they will * not clear until the debugger acknowledges them using \FdmDmcontrolAckunavail. */ #define DM_DMSTATUS_STICKYUNAVAIL_STICKY 1 /* * If 1, then there is an implicit {\tt ebreak} instruction at the * non-existent word immediately after the Program Buffer. This saves * the debugger from having to write the {\tt ebreak} itself, and * allows the Program Buffer to be one word smaller. * * This must be 1 when \FdmAbstractcsProgbufsize is 1. */ #define DM_DMSTATUS_IMPEBREAK_OFFSET 0x16 #define DM_DMSTATUS_IMPEBREAK_LENGTH 1 #define DM_DMSTATUS_IMPEBREAK 0x400000 /* * This field is 1 when all currently selected harts have been reset * and reset has not been acknowledged for any of them. */ #define DM_DMSTATUS_ALLHAVERESET_OFFSET 0x13 #define DM_DMSTATUS_ALLHAVERESET_LENGTH 1 #define DM_DMSTATUS_ALLHAVERESET 0x80000 /* * This field is 1 when at least one currently selected hart has been * reset and reset has not been acknowledged for that hart. */ #define DM_DMSTATUS_ANYHAVERESET_OFFSET 0x12 #define DM_DMSTATUS_ANYHAVERESET_LENGTH 1 #define DM_DMSTATUS_ANYHAVERESET 0x40000 /* * This field is 1 when all currently selected harts have their * resume ack bit\index{resume ack bit} set. */ #define DM_DMSTATUS_ALLRESUMEACK_OFFSET 0x11 #define DM_DMSTATUS_ALLRESUMEACK_LENGTH 1 #define DM_DMSTATUS_ALLRESUMEACK 0x20000 /* * This field is 1 when any currently selected hart has its * resume ack bit\index{resume ack bit} set. */ #define DM_DMSTATUS_ANYRESUMEACK_OFFSET 0x10 #define DM_DMSTATUS_ANYRESUMEACK_LENGTH 1 #define DM_DMSTATUS_ANYRESUMEACK 0x10000 /* * This field is 1 when all currently selected harts do not exist in * this hardware platform. */ #define DM_DMSTATUS_ALLNONEXISTENT_OFFSET 0xf #define DM_DMSTATUS_ALLNONEXISTENT_LENGTH 1 #define DM_DMSTATUS_ALLNONEXISTENT 0x8000 /* * This field is 1 when any currently selected hart does not exist in * this hardware platform. */ #define DM_DMSTATUS_ANYNONEXISTENT_OFFSET 0xe #define DM_DMSTATUS_ANYNONEXISTENT_LENGTH 1 #define DM_DMSTATUS_ANYNONEXISTENT 0x4000 /* * This field is 1 when all currently selected harts are * unavailable, or (if \FdmDmstatusStickyunavail is 1) were * unavailable without that being acknowledged. */ #define DM_DMSTATUS_ALLUNAVAIL_OFFSET 0xd #define DM_DMSTATUS_ALLUNAVAIL_LENGTH 1 #define DM_DMSTATUS_ALLUNAVAIL 0x2000 /* * This field is 1 when any currently selected hart is unavailable, * or (if \FdmDmstatusStickyunavail is 1) was unavailable without * that being acknowledged. */ #define DM_DMSTATUS_ANYUNAVAIL_OFFSET 0xc #define DM_DMSTATUS_ANYUNAVAIL_LENGTH 1 #define DM_DMSTATUS_ANYUNAVAIL 0x1000 /* * This field is 1 when all currently selected harts are running. */ #define DM_DMSTATUS_ALLRUNNING_OFFSET 0xb #define DM_DMSTATUS_ALLRUNNING_LENGTH 1 #define DM_DMSTATUS_ALLRUNNING 0x800 /* * This field is 1 when any currently selected hart is running. */ #define DM_DMSTATUS_ANYRUNNING_OFFSET 0xa #define DM_DMSTATUS_ANYRUNNING_LENGTH 1 #define DM_DMSTATUS_ANYRUNNING 0x400 /* * This field is 1 when all currently selected harts are halted. */ #define DM_DMSTATUS_ALLHALTED_OFFSET 9 #define DM_DMSTATUS_ALLHALTED_LENGTH 1 #define DM_DMSTATUS_ALLHALTED 0x200 /* * This field is 1 when any currently selected hart is halted. */ #define DM_DMSTATUS_ANYHALTED_OFFSET 8 #define DM_DMSTATUS_ANYHALTED_LENGTH 1 #define DM_DMSTATUS_ANYHALTED 0x100 #define DM_DMSTATUS_AUTHENTICATED_OFFSET 7 #define DM_DMSTATUS_AUTHENTICATED_LENGTH 1 #define DM_DMSTATUS_AUTHENTICATED 0x80 /* * false: Authentication is required before using the DM. */ #define DM_DMSTATUS_AUTHENTICATED_FALSE 0 /* * true: The authentication check has passed. */ #define DM_DMSTATUS_AUTHENTICATED_TRUE 1 /* * On components that don't implement authentication, this bit must be * preset as 1. */ #define DM_DMSTATUS_AUTHBUSY_OFFSET 6 #define DM_DMSTATUS_AUTHBUSY_LENGTH 1 #define DM_DMSTATUS_AUTHBUSY 0x40 /* * ready: The authentication module is ready to process the next * read/write to \RdmAuthdata. */ #define DM_DMSTATUS_AUTHBUSY_READY 0 /* * busy: The authentication module is busy. Accessing \RdmAuthdata results * in unspecified behavior. */ #define DM_DMSTATUS_AUTHBUSY_BUSY 1 /* * \FdmDmstatusAuthbusy only becomes set in immediate response to an access to * \RdmAuthdata. */ /* * 1 if this Debug Module supports halt-on-reset functionality * controllable by the \FdmDmcontrolSetresethaltreq and \FdmDmcontrolClrresethaltreq bits. * 0 otherwise. */ #define DM_DMSTATUS_HASRESETHALTREQ_OFFSET 5 #define DM_DMSTATUS_HASRESETHALTREQ_LENGTH 1 #define DM_DMSTATUS_HASRESETHALTREQ 0x20 #define DM_DMSTATUS_CONFSTRPTRVALID_OFFSET 4 #define DM_DMSTATUS_CONFSTRPTRVALID_LENGTH 1 #define DM_DMSTATUS_CONFSTRPTRVALID 0x10 /* * invalid: \RdmConfstrptrZero--\RdmConfstrptrThree hold information which * is not relevant to the configuration structure. */ #define DM_DMSTATUS_CONFSTRPTRVALID_INVALID 0 /* * valid: \RdmConfstrptrZero--\RdmConfstrptrThree hold the address of the * configuration structure. */ #define DM_DMSTATUS_CONFSTRPTRVALID_VALID 1 #define DM_DMSTATUS_VERSION_OFFSET 0 #define DM_DMSTATUS_VERSION_LENGTH 4 #define DM_DMSTATUS_VERSION 0xf /* * none: There is no Debug Module present. */ #define DM_DMSTATUS_VERSION_NONE 0 /* * 0.11: There is a Debug Module and it conforms to version 0.11 of this * specification. */ #define DM_DMSTATUS_VERSION_0_11 1 /* * 0.13: There is a Debug Module and it conforms to version 0.13 of this * specification. */ #define DM_DMSTATUS_VERSION_0_13 2 /* * 1.0: There is a Debug Module and it conforms to version 1.0 of this * specification. */ #define DM_DMSTATUS_VERSION_1_0 3 /* * custom: There is a Debug Module but it does not conform to any * available version of this spec. */ #define DM_DMSTATUS_VERSION_CUSTOM 15 #define DM_DMCONTROL 0x10 /* * Writing 0 clears the halt request bit for all currently selected * harts. This may cancel outstanding halt requests for those harts. * * Writing 1 sets the halt request bit for all currently selected * harts. Running harts will halt whenever their halt request bit is * set. * * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ #define DM_DMCONTROL_HALTREQ_OFFSET 0x1f #define DM_DMCONTROL_HALTREQ_LENGTH 1 #define DM_DMCONTROL_HALTREQ 0x80000000U /* * Writing 1 causes the currently selected harts to resume once, if * they are halted when the write occurs. It also clears the resume * ack bit for those harts. * * \FdmDmcontrolResumereq is ignored if \FdmDmcontrolHaltreq is set. * * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ #define DM_DMCONTROL_RESUMEREQ_OFFSET 0x1e #define DM_DMCONTROL_RESUMEREQ_LENGTH 1 #define DM_DMCONTROL_RESUMEREQ 0x40000000 /* * This optional field writes the reset bit for all the currently * selected harts. To perform a reset the debugger writes 1, and then * writes 0 to deassert the reset signal. * * While this bit is 1, the debugger must not change which harts are * selected. * * If this feature is not implemented, the bit always stays 0, so * after writing 1 the debugger can read the register back to see if * the feature is supported. * * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ #define DM_DMCONTROL_HARTRESET_OFFSET 0x1d #define DM_DMCONTROL_HARTRESET_LENGTH 1 #define DM_DMCONTROL_HARTRESET 0x20000000 #define DM_DMCONTROL_ACKHAVERESET_OFFSET 0x1c #define DM_DMCONTROL_ACKHAVERESET_LENGTH 1 #define DM_DMCONTROL_ACKHAVERESET 0x10000000 /* * nop: No effect. */ #define DM_DMCONTROL_ACKHAVERESET_NOP 0 /* * ack: Clears {\tt havereset} for any selected harts. */ #define DM_DMCONTROL_ACKHAVERESET_ACK 1 /* * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ #define DM_DMCONTROL_ACKUNAVAIL_OFFSET 0x1b #define DM_DMCONTROL_ACKUNAVAIL_LENGTH 1 #define DM_DMCONTROL_ACKUNAVAIL 0x8000000 /* * nop: No effect. */ #define DM_DMCONTROL_ACKUNAVAIL_NOP 0 /* * ack: Clears {\tt unavail} for any selected harts that are currently available. */ #define DM_DMCONTROL_ACKUNAVAIL_ACK 1 /* * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ /* * Selects the definition of currently selected harts. */ #define DM_DMCONTROL_HASEL_OFFSET 0x1a #define DM_DMCONTROL_HASEL_LENGTH 1 #define DM_DMCONTROL_HASEL 0x4000000 /* * single: There is a single currently selected hart, that is selected by \Fhartsel. */ #define DM_DMCONTROL_HASEL_SINGLE 0 /* * multiple: There may be multiple currently selected harts -- the hart * selected by \Fhartsel, plus those selected by the hart array mask * register. */ #define DM_DMCONTROL_HASEL_MULTIPLE 1 /* * An implementation which does not implement the hart array mask register * must tie this field to 0. A debugger which wishes to use the hart array * mask register feature should set this bit and read back to see if the functionality * is supported. */ /* * The low 10 bits of \Fhartsel: the DM-specific index of the hart to * select. This hart is always part of the currently selected harts. */ #define DM_DMCONTROL_HARTSELLO_OFFSET 0x10 #define DM_DMCONTROL_HARTSELLO_LENGTH 0xa #define DM_DMCONTROL_HARTSELLO 0x3ff0000 /* * The high 10 bits of \Fhartsel: the DM-specific index of the hart to * select. This hart is always part of the currently selected harts. */ #define DM_DMCONTROL_HARTSELHI_OFFSET 6 #define DM_DMCONTROL_HARTSELHI_LENGTH 0xa #define DM_DMCONTROL_HARTSELHI 0xffc0 /* * This optional field sets \Fkeepalive for all currently selected * harts, unless \FdmDmcontrolClrkeepalive is simultaneously set to * 1. * * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ #define DM_DMCONTROL_SETKEEPALIVE_OFFSET 5 #define DM_DMCONTROL_SETKEEPALIVE_LENGTH 1 #define DM_DMCONTROL_SETKEEPALIVE 0x20 /* * This optional field clears \Fkeepalive for all currently selected * harts. * * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ #define DM_DMCONTROL_CLRKEEPALIVE_OFFSET 4 #define DM_DMCONTROL_CLRKEEPALIVE_LENGTH 1 #define DM_DMCONTROL_CLRKEEPALIVE 0x10 /* * This optional field writes the halt-on-reset request bit for all * currently selected harts, unless \FdmDmcontrolClrresethaltreq is * simultaneously set to 1. * When set to 1, each selected hart will halt upon the next deassertion * of its reset. The halt-on-reset request bit is not automatically * cleared. The debugger must write to \FdmDmcontrolClrresethaltreq to clear it. * * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. * * If \FdmDmstatusHasresethaltreq is 0, this field is not implemented. */ #define DM_DMCONTROL_SETRESETHALTREQ_OFFSET 3 #define DM_DMCONTROL_SETRESETHALTREQ_LENGTH 1 #define DM_DMCONTROL_SETRESETHALTREQ 8 /* * This optional field clears the halt-on-reset request bit for all * currently selected harts. * * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ #define DM_DMCONTROL_CLRRESETHALTREQ_OFFSET 2 #define DM_DMCONTROL_CLRRESETHALTREQ_LENGTH 1 #define DM_DMCONTROL_CLRRESETHALTREQ 4 /* * This bit controls the reset signal from the DM to the rest of the * hardware platform. The signal should reset every part of the hardware platform, including * every hart, except for the DM and any logic required to access the * DM. * To perform a hardware platform reset the debugger writes 1, * and then writes 0 * to deassert the reset. */ #define DM_DMCONTROL_NDMRESET_OFFSET 1 #define DM_DMCONTROL_NDMRESET_LENGTH 1 #define DM_DMCONTROL_NDMRESET 2 /* * This bit serves as a reset signal for the Debug Module itself. * After changing the value of this bit, the debugger must poll * \RdmDmcontrol until \FdmDmcontrolDmactive has taken the requested value * before performing any action that assumes the requested \FdmDmcontrolDmactive * state change has completed. Hardware may * take an arbitrarily long time to complete activation or deactivation and will * indicate completion by setting \FdmDmcontrolDmactive to the requested value. */ #define DM_DMCONTROL_DMACTIVE_OFFSET 0 #define DM_DMCONTROL_DMACTIVE_LENGTH 1 #define DM_DMCONTROL_DMACTIVE 1 /* * inactive: The module's state, including authentication mechanism, * takes its reset values (the \FdmDmcontrolDmactive bit is the only bit which can * be written to something other than its reset value). Any accesses * to the module may fail. Specifically, \FdmDmstatusVersion might not return * correct data. */ #define DM_DMCONTROL_DMACTIVE_INACTIVE 0 /* * active: The module functions normally. */ #define DM_DMCONTROL_DMACTIVE_ACTIVE 1 /* * No other mechanism should exist that may result in resetting the * Debug Module after power up. * * To place the Debug Module into a known state, a debugger may write 0 to \FdmDmcontrolDmactive, * poll until \FdmDmcontrolDmactive is observed 0, write 1 to \FdmDmcontrolDmactive, and * poll until \FdmDmcontrolDmactive is observed 1. * * Implementations may pay attention to this bit to further aid * debugging, for example by preventing the Debug Module from being * power gated while debugging is active. */ #define DM_HARTINFO 0x12 /* * Number of {\tt dscratch} registers available for the debugger * to use during program buffer execution, starting from \RcsrDscratchZero. * The debugger can make no assumptions about the contents of these * registers between commands. */ #define DM_HARTINFO_NSCRATCH_OFFSET 0x14 #define DM_HARTINFO_NSCRATCH_LENGTH 4 #define DM_HARTINFO_NSCRATCH 0xf00000 #define DM_HARTINFO_DATAACCESS_OFFSET 0x10 #define DM_HARTINFO_DATAACCESS_LENGTH 1 #define DM_HARTINFO_DATAACCESS 0x10000 /* * csr: The {\tt data} registers are shadowed in the hart by CSRs. * Each CSR is DXLEN bits in size, and corresponds * to a single argument, per Table~\ref{tab:datareg}. */ #define DM_HARTINFO_DATAACCESS_CSR 0 /* * memory: The {\tt data} registers are shadowed in the hart's memory map. * Each register takes up 4 bytes in the memory map. */ #define DM_HARTINFO_DATAACCESS_MEMORY 1 /* * If \FdmHartinfoDataaccess is 0: Number of CSRs dedicated to * shadowing the {\tt data} registers. * * If \FdmHartinfoDataaccess is 1: Number of 32-bit words in the memory map * dedicated to shadowing the {\tt data} registers. * * If this value is non-zero, then the {tt data} registers must go * beyond being MRs and guarantee they each store a single value, that is * readable/writable by either side. * * Since there are at most 12 {\tt data} registers, the value in this * register must be 12 or smaller. */ #define DM_HARTINFO_DATASIZE_OFFSET 0xc #define DM_HARTINFO_DATASIZE_LENGTH 4 #define DM_HARTINFO_DATASIZE 0xf000 /* * If \FdmHartinfoDataaccess is 0: The number of the first CSR dedicated to * shadowing the {\tt data} registers. * * If \FdmHartinfoDataaccess is 1: Address of RAM where the data * registers are shadowed. This address is sign extended giving a * range of -2048 to 2047, easily addressed with a load or store using * \Xzero as the address register. */ #define DM_HARTINFO_DATAADDR_OFFSET 0 #define DM_HARTINFO_DATAADDR_LENGTH 0xc #define DM_HARTINFO_DATAADDR 0xfff #define DM_HAWINDOWSEL 0x14 /* * The high bits of this field may be tied to 0, depending on how large * the array mask register is. E.g.\ on a hardware platform with 48 harts only bit 0 * of this field may actually be writable. */ #define DM_HAWINDOWSEL_HAWINDOWSEL_OFFSET 0 #define DM_HAWINDOWSEL_HAWINDOWSEL_LENGTH 0xf #define DM_HAWINDOWSEL_HAWINDOWSEL 0x7fff #define DM_HAWINDOW 0x15 #define DM_HAWINDOW_MASKDATA_OFFSET 0 #define DM_HAWINDOW_MASKDATA_LENGTH 0x20 #define DM_HAWINDOW_MASKDATA 0xffffffffU #define DM_ABSTRACTCS 0x16 /* * Size of the Program Buffer, in 32-bit words. Valid sizes are 0 - 16. */ #define DM_ABSTRACTCS_PROGBUFSIZE_OFFSET 0x18 #define DM_ABSTRACTCS_PROGBUFSIZE_LENGTH 5 #define DM_ABSTRACTCS_PROGBUFSIZE 0x1f000000 #define DM_ABSTRACTCS_BUSY_OFFSET 0xc #define DM_ABSTRACTCS_BUSY_LENGTH 1 #define DM_ABSTRACTCS_BUSY 0x1000 /* * ready: There is no abstract command currently being executed. */ #define DM_ABSTRACTCS_BUSY_READY 0 /* * busy: An abstract command is currently being executed. */ #define DM_ABSTRACTCS_BUSY_BUSY 1 /* * This bit is set as soon as \RdmCommand is written, and is * not cleared until that command has completed. */ /* * This optional bit controls whether program buffer and abstract * memory accesses are performed with the exact and full set of * permission checks that apply based on the current architectural * state of the hart performing the access, or with a relaxed set of * permission checks (e.g. PMP restrictions are ignored). The * details of the latter are implementation-specific. When set to 0, * full permissions apply; when set to 1, relaxed permissions apply. */ #define DM_ABSTRACTCS_RELAXEDPRIV_OFFSET 0xb #define DM_ABSTRACTCS_RELAXEDPRIV_LENGTH 1 #define DM_ABSTRACTCS_RELAXEDPRIV 0x800 /* * Gets set if an abstract command fails. The bits in this field remain set until * they are cleared by writing 1 to them. No abstract command is * started until the value is reset to 0. * * This field only contains a valid value if \FdmAbstractcsBusy is 0. */ #define DM_ABSTRACTCS_CMDERR_OFFSET 8 #define DM_ABSTRACTCS_CMDERR_LENGTH 3 #define DM_ABSTRACTCS_CMDERR 0x700 /* * none: No error. */ #define DM_ABSTRACTCS_CMDERR_NONE 0 /* * busy: An abstract command was executing while \RdmCommand, * \RdmAbstractcs, or \RdmAbstractauto was written, or when one * of the {\tt data} or {\tt progbuf} registers was read or written. * This status is only written if \FdmAbstractcsCmderr contains 0. */ #define DM_ABSTRACTCS_CMDERR_BUSY 1 /* * not supported: The command in \RdmCommand is not supported. It * may be supported with different options set, but it will not be * supported at a later time when the hart or system state are * different. */ #define DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED 2 /* * exception: An exception occurred while executing the command * (e.g.\ while executing the Program Buffer). */ #define DM_ABSTRACTCS_CMDERR_EXCEPTION 3 /* * halt/resume: The abstract command couldn't execute because the * hart wasn't in the required state (running/halted), or unavailable. */ #define DM_ABSTRACTCS_CMDERR_HALT_RESUME 4 /* * bus: The abstract command failed due to a bus error (e.g.\ * alignment, access size, or timeout). */ #define DM_ABSTRACTCS_CMDERR_BUS 5 /* * reserved: Reserved for future use. */ #define DM_ABSTRACTCS_CMDERR_RESERVED 6 /* * other: The command failed for another reason. */ #define DM_ABSTRACTCS_CMDERR_OTHER 7 /* * Number of {\tt data} registers that are implemented as part of the * abstract command interface. Valid sizes are 1 -- 12. */ #define DM_ABSTRACTCS_DATACOUNT_OFFSET 0 #define DM_ABSTRACTCS_DATACOUNT_LENGTH 4 #define DM_ABSTRACTCS_DATACOUNT 0xf #define DM_COMMAND 0x17 /* * The type determines the overall functionality of this * abstract command. */ #define DM_COMMAND_CMDTYPE_OFFSET 0x18 #define DM_COMMAND_CMDTYPE_LENGTH 8 #define DM_COMMAND_CMDTYPE 0xff000000U /* * This field is interpreted in a command-specific manner, * described for each abstract command. */ #define DM_COMMAND_CONTROL_OFFSET 0 #define DM_COMMAND_CONTROL_LENGTH 0x18 #define DM_COMMAND_CONTROL 0xffffff #define DM_ABSTRACTAUTO 0x18 /* * When a bit in this field is 1, read or write accesses to the * corresponding {\tt progbuf} word cause the DM to act as if the * current value in \RdmCommand was written there again after the * access to {\tt progbuf} completes. */ #define DM_ABSTRACTAUTO_AUTOEXECPROGBUF_OFFSET 0x10 #define DM_ABSTRACTAUTO_AUTOEXECPROGBUF_LENGTH 0x10 #define DM_ABSTRACTAUTO_AUTOEXECPROGBUF 0xffff0000U /* * When a bit in this field is 1, read or write accesses to the * corresponding {\tt data} word cause the DM to act as if the current * value in \RdmCommand was written there again after the * access to {\tt data} completes. */ #define DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET 0 #define DM_ABSTRACTAUTO_AUTOEXECDATA_LENGTH 0xc #define DM_ABSTRACTAUTO_AUTOEXECDATA 0xfff #define DM_CONFSTRPTR0 0x19 #define DM_CONFSTRPTR0_ADDR_OFFSET 0 #define DM_CONFSTRPTR0_ADDR_LENGTH 0x20 #define DM_CONFSTRPTR0_ADDR 0xffffffffU #define DM_CONFSTRPTR1 0x1a #define DM_CONFSTRPTR1_ADDR_OFFSET 0 #define DM_CONFSTRPTR1_ADDR_LENGTH 0x20 #define DM_CONFSTRPTR1_ADDR 0xffffffffU #define DM_CONFSTRPTR2 0x1b #define DM_CONFSTRPTR2_ADDR_OFFSET 0 #define DM_CONFSTRPTR2_ADDR_LENGTH 0x20 #define DM_CONFSTRPTR2_ADDR 0xffffffffU #define DM_CONFSTRPTR3 0x1c #define DM_CONFSTRPTR3_ADDR_OFFSET 0 #define DM_CONFSTRPTR3_ADDR_LENGTH 0x20 #define DM_CONFSTRPTR3_ADDR 0xffffffffU #define DM_NEXTDM 0x1d #define DM_NEXTDM_ADDR_OFFSET 0 #define DM_NEXTDM_ADDR_LENGTH 0x20 #define DM_NEXTDM_ADDR 0xffffffffU #define DM_DATA0 0x04 #define DM_DATA0_DATA_OFFSET 0 #define DM_DATA0_DATA_LENGTH 0x20 #define DM_DATA0_DATA 0xffffffffU #define DM_DATA1 0x05 #define DM_DATA2 0x06 #define DM_DATA3 0x07 #define DM_DATA4 0x08 #define DM_DATA5 0x09 #define DM_DATA6 0x0a #define DM_DATA7 0x0b #define DM_DATA8 0x0c #define DM_DATA9 0x0d #define DM_DATA10 0x0e #define DM_DATA11 0x0f #define DM_PROGBUF0 0x20 #define DM_PROGBUF0_DATA_OFFSET 0 #define DM_PROGBUF0_DATA_LENGTH 0x20 #define DM_PROGBUF0_DATA 0xffffffffU #define DM_PROGBUF1 0x21 #define DM_PROGBUF2 0x22 #define DM_PROGBUF3 0x23 #define DM_PROGBUF4 0x24 #define DM_PROGBUF5 0x25 #define DM_PROGBUF6 0x26 #define DM_PROGBUF7 0x27 #define DM_PROGBUF8 0x28 #define DM_PROGBUF9 0x29 #define DM_PROGBUF10 0x2a #define DM_PROGBUF11 0x2b #define DM_PROGBUF12 0x2c #define DM_PROGBUF13 0x2d #define DM_PROGBUF14 0x2e #define DM_PROGBUF15 0x2f #define DM_AUTHDATA 0x30 #define DM_AUTHDATA_DATA_OFFSET 0 #define DM_AUTHDATA_DATA_LENGTH 0x20 #define DM_AUTHDATA_DATA 0xffffffffU #define DM_DMCS2 0x32 #define DM_DMCS2_GROUPTYPE_OFFSET 0xb #define DM_DMCS2_GROUPTYPE_LENGTH 1 #define DM_DMCS2_GROUPTYPE 0x800 /* * halt: The remaining fields in this register configure halt groups. */ #define DM_DMCS2_GROUPTYPE_HALT 0 /* * resume: The remaining fields in this register configure resume groups. */ #define DM_DMCS2_GROUPTYPE_RESUME 1 /* * This field contains the currently selected DM external trigger. * * If a non-existent trigger value is written here, the hardware will * change it to a valid one or 0 if no DM external triggers exist. */ #define DM_DMCS2_DMEXTTRIGGER_OFFSET 7 #define DM_DMCS2_DMEXTTRIGGER_LENGTH 4 #define DM_DMCS2_DMEXTTRIGGER 0x780 /* * When \FdmDmcsTwoHgselect is 0, contains the group of the hart * specified by \Fhartsel. * * When \FdmDmcsTwoHgselect is 1, contains the group of the DM external * trigger selected by \FdmDmcsTwoDmexttrigger. * * The value written to this field is ignored unless \FdmDmcsTwoHgwrite * is also written 1. * * Group numbers are contiguous starting at 0, with the highest number * being implementation-dependent, and possibly different between * different group types. Debuggers should read back this field after * writing to confirm they are using a hart group that is supported. * * If groups aren't implemented, then this entire field is 0. */ #define DM_DMCS2_GROUP_OFFSET 2 #define DM_DMCS2_GROUP_LENGTH 5 #define DM_DMCS2_GROUP 0x7c /* * When 1 is written and \FdmDmcsTwoHgselect is 0, for every selected * hart the DM will change its group to the value written to \FdmDmcsTwoGroup, * if the hardware supports that group for that hart. * Implementations may also change the group of a minimal set of * unselected harts in the same way, if that is necessary due to * a hardware limitation. * * When 1 is written and \FdmDmcsTwoHgselect is 1, the DM will change * the group of the DM external trigger selected by \FdmDmcsTwoDmexttrigger * to the value written to \FdmDmcsTwoGroup, if the hardware supports * that group for that trigger. * * Writing 0 has no effect. */ #define DM_DMCS2_HGWRITE_OFFSET 1 #define DM_DMCS2_HGWRITE_LENGTH 1 #define DM_DMCS2_HGWRITE 2 #define DM_DMCS2_HGSELECT_OFFSET 0 #define DM_DMCS2_HGSELECT_LENGTH 1 #define DM_DMCS2_HGSELECT 1 /* * harts: Operate on harts. */ #define DM_DMCS2_HGSELECT_HARTS 0 /* * triggers: Operate on DM external triggers. */ #define DM_DMCS2_HGSELECT_TRIGGERS 1 /* * If there are no DM external triggers, this field must be tied to 0. */ #define DM_HALTSUM0 0x40 #define DM_HALTSUM0_HALTSUM0_OFFSET 0 #define DM_HALTSUM0_HALTSUM0_LENGTH 0x20 #define DM_HALTSUM0_HALTSUM0 0xffffffffU #define DM_HALTSUM1 0x13 #define DM_HALTSUM1_HALTSUM1_OFFSET 0 #define DM_HALTSUM1_HALTSUM1_LENGTH 0x20 #define DM_HALTSUM1_HALTSUM1 0xffffffffU #define DM_HALTSUM2 0x34 #define DM_HALTSUM2_HALTSUM2_OFFSET 0 #define DM_HALTSUM2_HALTSUM2_LENGTH 0x20 #define DM_HALTSUM2_HALTSUM2 0xffffffffU #define DM_HALTSUM3 0x35 #define DM_HALTSUM3_HALTSUM3_OFFSET 0 #define DM_HALTSUM3_HALTSUM3_LENGTH 0x20 #define DM_HALTSUM3_HALTSUM3 0xffffffffU #define DM_SBCS 0x38 #define DM_SBCS_SBVERSION_OFFSET 0x1d #define DM_SBCS_SBVERSION_LENGTH 3 #define DM_SBCS_SBVERSION 0xe0000000U /* * legacy: The System Bus interface conforms to mainline drafts of this * spec older than 1 January, 2018. */ #define DM_SBCS_SBVERSION_LEGACY 0 /* * 1.0: The System Bus interface conforms to this version of the spec. */ #define DM_SBCS_SBVERSION_1_0 1 /* * Other values are reserved for future versions. */ /* * Set when the debugger attempts to read data while a read is in * progress, or when the debugger initiates a new access while one is * already in progress (while \FdmSbcsSbbusy is set). It remains set until * it's explicitly cleared by the debugger. * * While this field is set, no more system bus accesses can be * initiated by the Debug Module. */ #define DM_SBCS_SBBUSYERROR_OFFSET 0x16 #define DM_SBCS_SBBUSYERROR_LENGTH 1 #define DM_SBCS_SBBUSYERROR 0x400000 /* * When 1, indicates the system bus master is busy. (Whether the * system bus itself is busy is related, but not the same thing.) This * bit goes high immediately when a read or write is requested for any * reason, and does not go low until the access is fully completed. * * Writes to \RdmSbcs while \FdmSbcsSbbusy is high result in undefined * behavior. A debugger must not write to \RdmSbcs until it reads * \FdmSbcsSbbusy as 0. */ #define DM_SBCS_SBBUSY_OFFSET 0x15 #define DM_SBCS_SBBUSY_LENGTH 1 #define DM_SBCS_SBBUSY 0x200000 /* * When 1, every write to \RdmSbaddressZero automatically triggers a * system bus read at the new address. */ #define DM_SBCS_SBREADONADDR_OFFSET 0x14 #define DM_SBCS_SBREADONADDR_LENGTH 1 #define DM_SBCS_SBREADONADDR 0x100000 /* * Select the access size to use for system bus accesses. */ #define DM_SBCS_SBACCESS_OFFSET 0x11 #define DM_SBCS_SBACCESS_LENGTH 3 #define DM_SBCS_SBACCESS 0xe0000 /* * 8bit: 8-bit */ #define DM_SBCS_SBACCESS_8BIT 0 /* * 16bit: 16-bit */ #define DM_SBCS_SBACCESS_16BIT 1 /* * 32bit: 32-bit */ #define DM_SBCS_SBACCESS_32BIT 2 /* * 64bit: 64-bit */ #define DM_SBCS_SBACCESS_64BIT 3 /* * 128bit: 128-bit */ #define DM_SBCS_SBACCESS_128BIT 4 /* * If \FdmSbcsSbaccess has an unsupported value when the DM starts a bus * access, the access is not performed and \FdmSbcsSberror is set to 4. */ /* * When 1, {\tt sbaddress} is incremented by the access size (in * bytes) selected in \FdmSbcsSbaccess after every system bus access. */ #define DM_SBCS_SBAUTOINCREMENT_OFFSET 0x10 #define DM_SBCS_SBAUTOINCREMENT_LENGTH 1 #define DM_SBCS_SBAUTOINCREMENT 0x10000 /* * When 1, every read from \RdmSbdataZero automatically triggers a * system bus read at the (possibly auto-incremented) address. */ #define DM_SBCS_SBREADONDATA_OFFSET 0xf #define DM_SBCS_SBREADONDATA_LENGTH 1 #define DM_SBCS_SBREADONDATA 0x8000 /* * When the Debug Module's system bus * master encounters an error, this field gets set. The bits in this * field remain set until they are cleared by writing 1 to them. * While this field is non-zero, no more system bus accesses can be * initiated by the Debug Module. * * An implementation may report ``Other'' (7) for any error condition. */ #define DM_SBCS_SBERROR_OFFSET 0xc #define DM_SBCS_SBERROR_LENGTH 3 #define DM_SBCS_SBERROR 0x7000 /* * none: There was no bus error. */ #define DM_SBCS_SBERROR_NONE 0 /* * timeout: There was a timeout. */ #define DM_SBCS_SBERROR_TIMEOUT 1 /* * address: A bad address was accessed. */ #define DM_SBCS_SBERROR_ADDRESS 2 /* * alignment: There was an alignment error. */ #define DM_SBCS_SBERROR_ALIGNMENT 3 /* * size: An access of unsupported size was requested. */ #define DM_SBCS_SBERROR_SIZE 4 /* * other: Other. */ #define DM_SBCS_SBERROR_OTHER 7 /* * Width of system bus addresses in bits. (0 indicates there is no bus * access support.) */ #define DM_SBCS_SBASIZE_OFFSET 5 #define DM_SBCS_SBASIZE_LENGTH 7 #define DM_SBCS_SBASIZE 0xfe0 /* * 1 when 128-bit system bus accesses are supported. */ #define DM_SBCS_SBACCESS128_OFFSET 4 #define DM_SBCS_SBACCESS128_LENGTH 1 #define DM_SBCS_SBACCESS128 0x10 /* * 1 when 64-bit system bus accesses are supported. */ #define DM_SBCS_SBACCESS64_OFFSET 3 #define DM_SBCS_SBACCESS64_LENGTH 1 #define DM_SBCS_SBACCESS64 8 /* * 1 when 32-bit system bus accesses are supported. */ #define DM_SBCS_SBACCESS32_OFFSET 2 #define DM_SBCS_SBACCESS32_LENGTH 1 #define DM_SBCS_SBACCESS32 4 /* * 1 when 16-bit system bus accesses are supported. */ #define DM_SBCS_SBACCESS16_OFFSET 1 #define DM_SBCS_SBACCESS16_LENGTH 1 #define DM_SBCS_SBACCESS16 2 /* * 1 when 8-bit system bus accesses are supported. */ #define DM_SBCS_SBACCESS8_OFFSET 0 #define DM_SBCS_SBACCESS8_LENGTH 1 #define DM_SBCS_SBACCESS8 1 #define DM_SBADDRESS0 0x39 /* * Accesses bits 31:0 of the physical address in {\tt sbaddress}. */ #define DM_SBADDRESS0_ADDRESS_OFFSET 0 #define DM_SBADDRESS0_ADDRESS_LENGTH 0x20 #define DM_SBADDRESS0_ADDRESS 0xffffffffU #define DM_SBADDRESS1 0x3a /* * Accesses bits 63:32 of the physical address in {\tt sbaddress} (if * the system address bus is that wide). */ #define DM_SBADDRESS1_ADDRESS_OFFSET 0 #define DM_SBADDRESS1_ADDRESS_LENGTH 0x20 #define DM_SBADDRESS1_ADDRESS 0xffffffffU #define DM_SBADDRESS2 0x3b /* * Accesses bits 95:64 of the physical address in {\tt sbaddress} (if * the system address bus is that wide). */ #define DM_SBADDRESS2_ADDRESS_OFFSET 0 #define DM_SBADDRESS2_ADDRESS_LENGTH 0x20 #define DM_SBADDRESS2_ADDRESS 0xffffffffU #define DM_SBADDRESS3 0x37 /* * Accesses bits 127:96 of the physical address in {\tt sbaddress} (if * the system address bus is that wide). */ #define DM_SBADDRESS3_ADDRESS_OFFSET 0 #define DM_SBADDRESS3_ADDRESS_LENGTH 0x20 #define DM_SBADDRESS3_ADDRESS 0xffffffffU #define DM_SBDATA0 0x3c /* * Accesses bits 31:0 of {\tt sbdata}. */ #define DM_SBDATA0_DATA_OFFSET 0 #define DM_SBDATA0_DATA_LENGTH 0x20 #define DM_SBDATA0_DATA 0xffffffffU #define DM_SBDATA1 0x3d /* * Accesses bits 63:32 of {\tt sbdata} (if the system bus is that * wide). */ #define DM_SBDATA1_DATA_OFFSET 0 #define DM_SBDATA1_DATA_LENGTH 0x20 #define DM_SBDATA1_DATA 0xffffffffU #define DM_SBDATA2 0x3e /* * Accesses bits 95:64 of {\tt sbdata} (if the system bus is that * wide). */ #define DM_SBDATA2_DATA_OFFSET 0 #define DM_SBDATA2_DATA_LENGTH 0x20 #define DM_SBDATA2_DATA 0xffffffffU #define DM_SBDATA3 0x3f /* * Accesses bits 127:96 of {\tt sbdata} (if the system bus is that * wide). */ #define DM_SBDATA3_DATA_OFFSET 0 #define DM_SBDATA3_DATA_LENGTH 0x20 #define DM_SBDATA3_DATA 0xffffffffU #define DM_CUSTOM 0x1f #define DM_CUSTOM0 0x70 #define DM_CUSTOM1 0x71 #define DM_CUSTOM2 0x72 #define DM_CUSTOM3 0x73 #define DM_CUSTOM4 0x74 #define DM_CUSTOM5 0x75 #define DM_CUSTOM6 0x76 #define DM_CUSTOM7 0x77 #define DM_CUSTOM8 0x78 #define DM_CUSTOM9 0x79 #define DM_CUSTOM10 0x7a #define DM_CUSTOM11 0x7b #define DM_CUSTOM12 0x7c #define DM_CUSTOM13 0x7d #define DM_CUSTOM14 0x7e #define DM_CUSTOM15 0x7f #define SHORTNAME 0x123 /* * Description of what this field is used for. */ #define SHORTNAME_FIELD_OFFSET 0 #define SHORTNAME_FIELD_LENGTH 8 #define SHORTNAME_FIELD 0xff /* * This is 0 to indicate Access Register Command. */ #define AC_ACCESS_REGISTER_CMDTYPE_OFFSET 0x18 #define AC_ACCESS_REGISTER_CMDTYPE_LENGTH 8 #define AC_ACCESS_REGISTER_CMDTYPE 0xff000000U #define AC_ACCESS_REGISTER_AARSIZE_OFFSET 0x14 #define AC_ACCESS_REGISTER_AARSIZE_LENGTH 3 #define AC_ACCESS_REGISTER_AARSIZE 0x700000 /* * 32bit: Access the lowest 32 bits of the register. */ #define AC_ACCESS_REGISTER_AARSIZE_32BIT 2 /* * 64bit: Access the lowest 64 bits of the register. */ #define AC_ACCESS_REGISTER_AARSIZE_64BIT 3 /* * 128bit: Access the lowest 128 bits of the register. */ #define AC_ACCESS_REGISTER_AARSIZE_128BIT 4 /* * If \FacAccessregisterAarsize specifies a size larger than the register's actual size, * then the access must fail. If a register is accessible, then reads of \FacAccessregisterAarsize * less than or equal to the register's actual size must be supported. * Writing less than the full register may be supported, but what * happens to the high bits in that case is \unspecified. * * This field controls the Argument Width as referenced in * Table~\ref{tab:datareg}. */ #define AC_ACCESS_REGISTER_AARPOSTINCREMENT_OFFSET 0x13 #define AC_ACCESS_REGISTER_AARPOSTINCREMENT_LENGTH 1 #define AC_ACCESS_REGISTER_AARPOSTINCREMENT 0x80000 /* * disabled: No effect. This variant must be supported. */ #define AC_ACCESS_REGISTER_AARPOSTINCREMENT_DISABLED 0 /* * enabled: After a successful register access, \FacAccessregisterRegno is * incremented. Incrementing past the highest supported value * causes \FacAccessregisterRegno to become \unspecified. Supporting * this variant is optional. It is undefined whether the increment * happens when \FacAccessregisterTransfer is 0. */ #define AC_ACCESS_REGISTER_AARPOSTINCREMENT_ENABLED 1 #define AC_ACCESS_REGISTER_POSTEXEC_OFFSET 0x12 #define AC_ACCESS_REGISTER_POSTEXEC_LENGTH 1 #define AC_ACCESS_REGISTER_POSTEXEC 0x40000 /* * disabled: No effect. This variant must be supported, and is the only * supported one if \FdmAbstractcsProgbufsize is 0. */ #define AC_ACCESS_REGISTER_POSTEXEC_DISABLED 0 /* * enabled: Execute the program in the Program Buffer exactly once after * performing the transfer, if any. Supporting this variant is * optional. */ #define AC_ACCESS_REGISTER_POSTEXEC_ENABLED 1 #define AC_ACCESS_REGISTER_TRANSFER_OFFSET 0x11 #define AC_ACCESS_REGISTER_TRANSFER_LENGTH 1 #define AC_ACCESS_REGISTER_TRANSFER 0x20000 /* * disabled: Don't do the operation specified by \FacAccessregisterWrite. */ #define AC_ACCESS_REGISTER_TRANSFER_DISABLED 0 /* * enabled: Do the operation specified by \FacAccessregisterWrite. */ #define AC_ACCESS_REGISTER_TRANSFER_ENABLED 1 /* * This bit can be used to just execute the Program Buffer without * having to worry about placing valid values into \FacAccessregisterAarsize or \FacAccessregisterRegno. */ /* * When \FacAccessregisterTransfer is set: */ #define AC_ACCESS_REGISTER_WRITE_OFFSET 0x10 #define AC_ACCESS_REGISTER_WRITE_LENGTH 1 #define AC_ACCESS_REGISTER_WRITE 0x10000 /* * arg0: Copy data from the specified register into {\tt arg0} portion * of {\tt data}. */ #define AC_ACCESS_REGISTER_WRITE_ARG0 0 /* * register: Copy data from {\tt arg0} portion of {\tt data} into the * specified register. */ #define AC_ACCESS_REGISTER_WRITE_REGISTER 1 /* * Number of the register to access, as described in * Table~\ref{tab:regno}. * \RcsrDpc may be used as an alias for PC if this command is * supported on a non-halted hart. */ #define AC_ACCESS_REGISTER_REGNO_OFFSET 0 #define AC_ACCESS_REGISTER_REGNO_LENGTH 0x10 #define AC_ACCESS_REGISTER_REGNO 0xffff /* * This is 1 to indicate Quick Access command. */ #define AC_QUICK_ACCESS_CMDTYPE_OFFSET 0x18 #define AC_QUICK_ACCESS_CMDTYPE_LENGTH 8 #define AC_QUICK_ACCESS_CMDTYPE 0xff000000U /* * This is 2 to indicate Access Memory Command. */ #define AC_ACCESS_MEMORY_CMDTYPE_OFFSET 0x18 #define AC_ACCESS_MEMORY_CMDTYPE_LENGTH 8 #define AC_ACCESS_MEMORY_CMDTYPE 0xff000000U /* * An implementation does not have to implement both virtual and * physical accesses, but it must fail accesses that it doesn't * support. */ #define AC_ACCESS_MEMORY_AAMVIRTUAL_OFFSET 0x17 #define AC_ACCESS_MEMORY_AAMVIRTUAL_LENGTH 1 #define AC_ACCESS_MEMORY_AAMVIRTUAL 0x800000 /* * physical: Addresses are physical (to the hart they are performed on). */ #define AC_ACCESS_MEMORY_AAMVIRTUAL_PHYSICAL 0 /* * virtual: Addresses are virtual, and translated the way they would be from * M-mode, with \FcsrMstatusMprv set. */ #define AC_ACCESS_MEMORY_AAMVIRTUAL_VIRTUAL 1 /* * Debug Modules on systems without address translation (i.e. virtual addresses equal physical) * may optionally allow \FacAccessmemoryAamvirtual set to 1, which would produce the same result as * that same abstract command with \FacAccessmemoryAamvirtual cleared. */ #define AC_ACCESS_MEMORY_AAMSIZE_OFFSET 0x14 #define AC_ACCESS_MEMORY_AAMSIZE_LENGTH 3 #define AC_ACCESS_MEMORY_AAMSIZE 0x700000 /* * 8bit: Access the lowest 8 bits of the memory location. */ #define AC_ACCESS_MEMORY_AAMSIZE_8BIT 0 /* * 16bit: Access the lowest 16 bits of the memory location. */ #define AC_ACCESS_MEMORY_AAMSIZE_16BIT 1 /* * 32bit: Access the lowest 32 bits of the memory location. */ #define AC_ACCESS_MEMORY_AAMSIZE_32BIT 2 /* * 64bit: Access the lowest 64 bits of the memory location. */ #define AC_ACCESS_MEMORY_AAMSIZE_64BIT 3 /* * 128bit: Access the lowest 128 bits of the memory location. */ #define AC_ACCESS_MEMORY_AAMSIZE_128BIT 4 /* * After a memory access has completed, if this bit is 1, increment * {\tt arg1} (which contains the address used) by the number of bytes * encoded in \FacAccessmemoryAamsize. * * Supporting this variant is optional, but highly recommended for * performance reasons. */ #define AC_ACCESS_MEMORY_AAMPOSTINCREMENT_OFFSET 0x13 #define AC_ACCESS_MEMORY_AAMPOSTINCREMENT_LENGTH 1 #define AC_ACCESS_MEMORY_AAMPOSTINCREMENT 0x80000 #define AC_ACCESS_MEMORY_WRITE_OFFSET 0x10 #define AC_ACCESS_MEMORY_WRITE_LENGTH 1 #define AC_ACCESS_MEMORY_WRITE 0x10000 /* * arg0: Copy data from the memory location specified in {\tt arg1} into * the low bits of {\tt arg0}. The value of the remaining bits of * {\tt arg0} are \unspecified. */ #define AC_ACCESS_MEMORY_WRITE_ARG0 0 /* * memory: Copy data from the low bits of {\tt arg0} into the memory * location specified in {\tt arg1}. */ #define AC_ACCESS_MEMORY_WRITE_MEMORY 1 /* * These bits are reserved for target-specific uses. */ #define AC_ACCESS_MEMORY_TARGET_SPECIFIC_OFFSET 0xe #define AC_ACCESS_MEMORY_TARGET_SPECIFIC_LENGTH 2 #define AC_ACCESS_MEMORY_TARGET_SPECIFIC 0xc000 #define VIRT_PRIV virtual /* * Contains the virtualization mode the hart was operating in when Debug * Mode was entered. The encoding is described in Table \ref{tab:privmode}, * and matches the virtualization mode encoding from the Privileged Spec. * A user can write this value to change the hart's virtualization mode * when exiting Debug Mode. */ #define VIRT_PRIV_V_OFFSET 2 #define VIRT_PRIV_V_LENGTH 1 #define VIRT_PRIV_V 4 /* * Contains the privilege mode the hart was operating in when Debug * Mode was entered. The encoding is described in Table * \ref{tab:privmode}, and matches the privilege mode encoding from * the Privileged Spec. A user can write this * value to change the hart's privilege mode when exiting Debug Mode. */ #define VIRT_PRIV_PRV_OFFSET 0 #define VIRT_PRIV_PRV_LENGTH 2 #define VIRT_PRIV_PRV 3 #define DMI_SERCS 0x34 /* * Number of supported serial ports. */ #define DMI_SERCS_SERIALCOUNT_OFFSET 0x1c #define DMI_SERCS_SERIALCOUNT_LENGTH 4 #define DMI_SERCS_SERIALCOUNT 0xf0000000U /* * Select which serial port is accessed by \RdmiSerrx and \RdmiSertx. */ #define DMI_SERCS_SERIAL_OFFSET 0x18 #define DMI_SERCS_SERIAL_LENGTH 3 #define DMI_SERCS_SERIAL 0x7000000 #define DMI_SERCS_ERROR7_OFFSET 0x17 #define DMI_SERCS_ERROR7_LENGTH 1 #define DMI_SERCS_ERROR7 0x800000 #define DMI_SERCS_VALID7_OFFSET 0x16 #define DMI_SERCS_VALID7_LENGTH 1 #define DMI_SERCS_VALID7 0x400000 #define DMI_SERCS_FULL7_OFFSET 0x15 #define DMI_SERCS_FULL7_LENGTH 1 #define DMI_SERCS_FULL7 0x200000 #define DMI_SERCS_ERROR6_OFFSET 0x14 #define DMI_SERCS_ERROR6_LENGTH 1 #define DMI_SERCS_ERROR6 0x100000 #define DMI_SERCS_VALID6_OFFSET 0x13 #define DMI_SERCS_VALID6_LENGTH 1 #define DMI_SERCS_VALID6 0x80000 #define DMI_SERCS_FULL6_OFFSET 0x12 #define DMI_SERCS_FULL6_LENGTH 1 #define DMI_SERCS_FULL6 0x40000 #define DMI_SERCS_ERROR5_OFFSET 0x11 #define DMI_SERCS_ERROR5_LENGTH 1 #define DMI_SERCS_ERROR5 0x20000 #define DMI_SERCS_VALID5_OFFSET 0x10 #define DMI_SERCS_VALID5_LENGTH 1 #define DMI_SERCS_VALID5 0x10000 #define DMI_SERCS_FULL5_OFFSET 0xf #define DMI_SERCS_FULL5_LENGTH 1 #define DMI_SERCS_FULL5 0x8000 #define DMI_SERCS_ERROR4_OFFSET 0xe #define DMI_SERCS_ERROR4_LENGTH 1 #define DMI_SERCS_ERROR4 0x4000 #define DMI_SERCS_VALID4_OFFSET 0xd #define DMI_SERCS_VALID4_LENGTH 1 #define DMI_SERCS_VALID4 0x2000 #define DMI_SERCS_FULL4_OFFSET 0xc #define DMI_SERCS_FULL4_LENGTH 1 #define DMI_SERCS_FULL4 0x1000 #define DMI_SERCS_ERROR3_OFFSET 0xb #define DMI_SERCS_ERROR3_LENGTH 1 #define DMI_SERCS_ERROR3 0x800 #define DMI_SERCS_VALID3_OFFSET 0xa #define DMI_SERCS_VALID3_LENGTH 1 #define DMI_SERCS_VALID3 0x400 #define DMI_SERCS_FULL3_OFFSET 9 #define DMI_SERCS_FULL3_LENGTH 1 #define DMI_SERCS_FULL3 0x200 #define DMI_SERCS_ERROR2_OFFSET 8 #define DMI_SERCS_ERROR2_LENGTH 1 #define DMI_SERCS_ERROR2 0x100 #define DMI_SERCS_VALID2_OFFSET 7 #define DMI_SERCS_VALID2_LENGTH 1 #define DMI_SERCS_VALID2 0x80 #define DMI_SERCS_FULL2_OFFSET 6 #define DMI_SERCS_FULL2_LENGTH 1 #define DMI_SERCS_FULL2 0x40 #define DMI_SERCS_ERROR1_OFFSET 5 #define DMI_SERCS_ERROR1_LENGTH 1 #define DMI_SERCS_ERROR1 0x20 #define DMI_SERCS_VALID1_OFFSET 4 #define DMI_SERCS_VALID1_LENGTH 1 #define DMI_SERCS_VALID1 0x10 #define DMI_SERCS_FULL1_OFFSET 3 #define DMI_SERCS_FULL1_LENGTH 1 #define DMI_SERCS_FULL1 8 /* * 1 when the debugger-to-core queue for serial port 0 has * over or underflowed. This bit will remain set until it is reset by * writing 1 to this bit. */ #define DMI_SERCS_ERROR0_OFFSET 2 #define DMI_SERCS_ERROR0_LENGTH 1 #define DMI_SERCS_ERROR0 4 /* * 1 when the core-to-debugger queue for serial port 0 is not empty. */ #define DMI_SERCS_VALID0_OFFSET 1 #define DMI_SERCS_VALID0_LENGTH 1 #define DMI_SERCS_VALID0 2 /* * 1 when the debugger-to-core queue for serial port 0 is full. */ #define DMI_SERCS_FULL0_OFFSET 0 #define DMI_SERCS_FULL0_LENGTH 1 #define DMI_SERCS_FULL0 1 #define DMI_SERTX 0x35 #define DMI_SERTX_DATA_OFFSET 0 #define DMI_SERTX_DATA_LENGTH 0x20 #define DMI_SERTX_DATA 0xffffffffU #define DMI_SERRX 0x36 #define DMI_SERRX_DATA_OFFSET 0 #define DMI_SERRX_DATA_LENGTH 0x20 #define DMI_SERRX_DATA 0xffffffffU ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/encoding.h ================================================ /* SPDX-License-Identifier: BSD-3-Clause */ /* Copyright (c) 2022 RISC-V International */ /* * This file is auto-generated by running 'make' in * https://github.com/riscv/riscv-opcodes (dcdf8d3) */ #ifndef RISCV_CSR_ENCODING_H #define RISCV_CSR_ENCODING_H #define MSTATUS_UIE 0x00000001 #define MSTATUS_SIE 0x00000002 #define MSTATUS_HIE 0x00000004 #define MSTATUS_MIE 0x00000008 #define MSTATUS_UPIE 0x00000010 #define MSTATUS_SPIE 0x00000020 #define MSTATUS_UBE 0x00000040 #define MSTATUS_MPIE 0x00000080 #define MSTATUS_SPP 0x00000100 #define MSTATUS_VS 0x00000600 #define MSTATUS_MPP 0x00001800 #define MSTATUS_FS 0x00006000 #define MSTATUS_XS 0x00018000 #define MSTATUS_MPRV 0x00020000 #define MSTATUS_SUM 0x00040000 #define MSTATUS_MXR 0x00080000 #define MSTATUS_TVM 0x00100000 #define MSTATUS_TW 0x00200000 #define MSTATUS_TSR 0x00400000 #define MSTATUS32_SD 0x80000000 #define MSTATUS_UXL 0x0000000300000000 #define MSTATUS_SXL 0x0000000C00000000 #define MSTATUS_SBE 0x0000001000000000 #define MSTATUS_MBE 0x0000002000000000 #define MSTATUS_GVA 0x0000004000000000 #define MSTATUS_MPV 0x0000008000000000 #define MSTATUS64_SD 0x8000000000000000 #define MSTATUSH_SBE 0x00000010 #define MSTATUSH_MBE 0x00000020 #define MSTATUSH_GVA 0x00000040 #define MSTATUSH_MPV 0x00000080 #define SSTATUS_UIE 0x00000001 #define SSTATUS_SIE 0x00000002 #define SSTATUS_UPIE 0x00000010 #define SSTATUS_SPIE 0x00000020 #define SSTATUS_UBE 0x00000040 #define SSTATUS_SPP 0x00000100 #define SSTATUS_VS 0x00000600 #define SSTATUS_FS 0x00006000 #define SSTATUS_XS 0x00018000 #define SSTATUS_SUM 0x00040000 #define SSTATUS_MXR 0x00080000 #define SSTATUS32_SD 0x80000000 #define SSTATUS_UXL 0x0000000300000000 #define SSTATUS64_SD 0x8000000000000000 #define HSTATUS_VSXL 0x300000000 #define HSTATUS_VTSR 0x00400000 #define HSTATUS_VTW 0x00200000 #define HSTATUS_VTVM 0x00100000 #define HSTATUS_VGEIN 0x0003f000 #define HSTATUS_HU 0x00000200 #define HSTATUS_SPVP 0x00000100 #define HSTATUS_SPV 0x00000080 #define HSTATUS_GVA 0x00000040 #define HSTATUS_VSBE 0x00000020 #define USTATUS_UIE 0x00000001 #define USTATUS_UPIE 0x00000010 #define DCSR_XDEBUGVER (3U<<30) #define DCSR_NDRESET (1<<29) #define DCSR_FULLRESET (1<<28) #define DCSR_EBREAKM (1<<15) #define DCSR_EBREAKH (1<<14) #define DCSR_EBREAKS (1<<13) #define DCSR_EBREAKU (1<<12) #define DCSR_STOPCYCLE (1<<10) #define DCSR_STOPTIME (1<<9) #define DCSR_CAUSE (7<<6) #define DCSR_DEBUGINT (1<<5) #define DCSR_HALT (1<<3) #define DCSR_STEP (1<<2) #define DCSR_PRV (3<<0) #define DCSR_CAUSE_NONE 0 #define DCSR_CAUSE_SWBP 1 #define DCSR_CAUSE_HWBP 2 #define DCSR_CAUSE_DEBUGINT 3 #define DCSR_CAUSE_STEP 4 #define DCSR_CAUSE_HALT 5 #define DCSR_CAUSE_GROUP 6 #define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) #define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) #define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11)) #define MCONTROL_SELECT (1<<19) #define MCONTROL_TIMING (1<<18) #define MCONTROL_ACTION (0x3f<<12) #define MCONTROL_CHAIN (1<<11) #define MCONTROL_MATCH (0xf<<7) #define MCONTROL_M (1<<6) #define MCONTROL_H (1<<5) #define MCONTROL_S (1<<4) #define MCONTROL_U (1<<3) #define MCONTROL_EXECUTE (1<<2) #define MCONTROL_STORE (1<<1) #define MCONTROL_LOAD (1<<0) #define MCONTROL_TYPE_NONE 0 #define MCONTROL_TYPE_MATCH 2 #define MCONTROL_ACTION_DEBUG_EXCEPTION 0 #define MCONTROL_ACTION_DEBUG_MODE 1 #define MCONTROL_ACTION_TRACE_START 2 #define MCONTROL_ACTION_TRACE_STOP 3 #define MCONTROL_ACTION_TRACE_EMIT 4 #define MCONTROL_MATCH_EQUAL 0 #define MCONTROL_MATCH_NAPOT 1 #define MCONTROL_MATCH_GE 2 #define MCONTROL_MATCH_LT 3 #define MCONTROL_MATCH_MASK_LOW 4 #define MCONTROL_MATCH_MASK_HIGH 5 #define MIP_USIP (1 << IRQ_U_SOFT) #define MIP_SSIP (1 << IRQ_S_SOFT) #define MIP_VSSIP (1 << IRQ_VS_SOFT) #define MIP_MSIP (1 << IRQ_M_SOFT) #define MIP_UTIP (1 << IRQ_U_TIMER) #define MIP_STIP (1 << IRQ_S_TIMER) #define MIP_VSTIP (1 << IRQ_VS_TIMER) #define MIP_MTIP (1 << IRQ_M_TIMER) #define MIP_UEIP (1 << IRQ_U_EXT) #define MIP_SEIP (1 << IRQ_S_EXT) #define MIP_VSEIP (1 << IRQ_VS_EXT) #define MIP_MEIP (1 << IRQ_M_EXT) #define MIP_SGEIP (1 << IRQ_S_GEXT) #define MIP_LCOFIP (1 << IRQ_LCOF) #define MIP_S_MASK (MIP_SSIP | MIP_STIP | MIP_SEIP) #define MIP_VS_MASK (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP) #define MIP_HS_MASK (MIP_VS_MASK | MIP_SGEIP) #define MIDELEG_FORCED_MASK MIP_HS_MASK #define SIP_SSIP MIP_SSIP #define SIP_STIP MIP_STIP #define MENVCFG_FIOM 0x00000001 #define MENVCFG_CBIE 0x00000030 #define MENVCFG_CBCFE 0x00000040 #define MENVCFG_CBZE 0x00000080 #define MENVCFG_PBMTE 0x4000000000000000 #define MENVCFG_STCE 0x8000000000000000 #define MENVCFGH_PBMTE 0x40000000 #define MENVCFGH_STCE 0x80000000 #define MSTATEEN0_CS 0x00000001 #define MSTATEEN0_FCSR 0x00000002 #define MSTATEEN0_HCONTEXT 0x0200000000000000 #define MSTATEEN0_HENVCFG 0x4000000000000000 #define MSTATEEN_HSTATEEN 0x8000000000000000 #define MSTATEEN0H_HCONTEXT 0x02000000 #define MSTATEEN0H_HENVCFG 0x40000000 #define MSTATEENH_HSTATEEN 0x80000000 #define MHPMEVENT_VUINH 0x0400000000000000 #define MHPMEVENT_VSINH 0x0800000000000000 #define MHPMEVENT_UINH 0x1000000000000000 #define MHPMEVENT_SINH 0x2000000000000000 #define MHPMEVENT_MINH 0x4000000000000000 #define MHPMEVENT_OF 0x8000000000000000 #define MHPMEVENTH_VUINH 0x04000000 #define MHPMEVENTH_VSINH 0x08000000 #define MHPMEVENTH_UINH 0x10000000 #define MHPMEVENTH_SINH 0x20000000 #define MHPMEVENTH_MINH 0x40000000 #define MHPMEVENTH_OF 0x80000000 #define HENVCFG_FIOM 0x00000001 #define HENVCFG_CBIE 0x00000030 #define HENVCFG_CBCFE 0x00000040 #define HENVCFG_CBZE 0x00000080 #define HENVCFG_PBMTE 0x4000000000000000 #define HENVCFG_STCE 0x8000000000000000 #define HENVCFGH_PBMTE 0x40000000 #define HENVCFGH_STCE 0x80000000 #define HSTATEEN0_CS 0x00000001 #define HSTATEEN0_FCSR 0x00000002 #define HSTATEEN0_SCONTEXT 0x0200000000000000 #define HSTATEEN0_SENVCFG 0x4000000000000000 #define HSTATEEN_SSTATEEN 0x8000000000000000 #define HSTATEEN0H_SCONTEXT 0x02000000 #define HSTATEEN0H_SENVCFG 0x40000000 #define HSTATEENH_SSTATEEN 0x80000000 #define SENVCFG_FIOM 0x00000001 #define SENVCFG_CBIE 0x00000030 #define SENVCFG_CBCFE 0x00000040 #define SENVCFG_CBZE 0x00000080 #define SSTATEEN0_CS 0x00000001 #define SSTATEEN0_FCSR 0x00000002 #define MSECCFG_MML 0x00000001 #define MSECCFG_MMWP 0x00000002 #define MSECCFG_RLB 0x00000004 #define MSECCFG_USEED 0x00000100 #define MSECCFG_SSEED 0x00000200 #define PRV_U 0 #define PRV_S 1 #define PRV_M 3 #define PRV_HS (PRV_S + 1) #define SATP32_MODE 0x80000000 #define SATP32_ASID 0x7FC00000 #define SATP32_PPN 0x003FFFFF #define SATP64_MODE 0xF000000000000000 #define SATP64_ASID 0x0FFFF00000000000 #define SATP64_PPN 0x00000FFFFFFFFFFF #define SATP_MODE_OFF 0 #define SATP_MODE_SV32 1 #define SATP_MODE_SV39 8 #define SATP_MODE_SV48 9 #define SATP_MODE_SV57 10 #define SATP_MODE_SV64 11 #define HGATP32_MODE 0x80000000 #define HGATP32_VMID 0x1FC00000 #define HGATP32_PPN 0x003FFFFF #define HGATP64_MODE 0xF000000000000000 #define HGATP64_VMID 0x03FFF00000000000 #define HGATP64_PPN 0x00000FFFFFFFFFFF #define HGATP_MODE_OFF 0 #define HGATP_MODE_SV32X4 1 #define HGATP_MODE_SV39X4 8 #define HGATP_MODE_SV48X4 9 #define HGATP_MODE_SV57X4 10 #define PMP_R 0x01 #define PMP_W 0x02 #define PMP_X 0x04 #define PMP_A 0x18 #define PMP_L 0x80 #define PMP_SHIFT 2 #define PMP_TOR 0x08 #define PMP_NA4 0x10 #define PMP_NAPOT 0x18 #define IRQ_U_SOFT 0 #define IRQ_S_SOFT 1 #define IRQ_VS_SOFT 2 #define IRQ_M_SOFT 3 #define IRQ_U_TIMER 4 #define IRQ_S_TIMER 5 #define IRQ_VS_TIMER 6 #define IRQ_M_TIMER 7 #define IRQ_U_EXT 8 #define IRQ_S_EXT 9 #define IRQ_VS_EXT 10 #define IRQ_M_EXT 11 #define IRQ_S_GEXT 12 #define IRQ_COP 12 #define IRQ_LCOF 13 /* page table entry (PTE) fields */ #define PTE_V 0x001 /* Valid */ #define PTE_R 0x002 /* Read */ #define PTE_W 0x004 /* Write */ #define PTE_X 0x008 /* Execute */ #define PTE_U 0x010 /* User */ #define PTE_G 0x020 /* Global */ #define PTE_A 0x040 /* Accessed */ #define PTE_D 0x080 /* Dirty */ #define PTE_SOFT 0x300 /* Reserved for Software */ #define PTE_RSVD 0x1FC0000000000000 /* Reserved for future standard use */ #define PTE_PBMT 0x6000000000000000 /* Svpbmt: Page-based memory types */ #define PTE_N 0x8000000000000000 /* Svnapot: NAPOT translation contiguity */ #define PTE_ATTR 0xFFC0000000000000 /* All attributes and reserved bits */ #define PTE_PPN_SHIFT 10 #define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) #ifdef __riscv #if __riscv_xlen == 64 # define MSTATUS_SD MSTATUS64_SD # define SSTATUS_SD SSTATUS64_SD # define RISCV_PGLEVEL_BITS 9 # define SATP_MODE SATP64_MODE #else # define MSTATUS_SD MSTATUS32_SD # define SSTATUS_SD SSTATUS32_SD # define RISCV_PGLEVEL_BITS 10 # define SATP_MODE SATP32_MODE #endif #define RISCV_PGSHIFT 12 #define RISCV_PGSIZE (1 << RISCV_PGSHIFT) #ifndef __ASSEMBLER__ #ifdef __GNUC__ #define read_csr(reg) ({ unsigned long __tmp; \ asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ __tmp; }) #define write_csr(reg, val) ({ \ asm volatile ("csrw " #reg ", %0" :: "rK"(val)); }) #define swap_csr(reg, val) ({ unsigned long __tmp; \ asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ __tmp; }) #define set_csr(reg, bit) ({ unsigned long __tmp; \ asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ __tmp; }) #define clear_csr(reg, bit) ({ unsigned long __tmp; \ asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ __tmp; }) #define rdtime() read_csr(time) #define rdcycle() read_csr(cycle) #define rdinstret() read_csr(instret) #endif #endif #endif #endif /* Automatically generated by parse_opcodes. */ #ifndef RISCV_ENCODING_H #define RISCV_ENCODING_H #define MATCH_ADD 0x33 #define MASK_ADD 0xfe00707f #define MATCH_ADD16 0x40000077 #define MASK_ADD16 0xfe00707f #define MATCH_ADD32 0x40002077 #define MASK_ADD32 0xfe00707f #define MATCH_ADD64 0xc0001077 #define MASK_ADD64 0xfe00707f #define MATCH_ADD8 0x48000077 #define MASK_ADD8 0xfe00707f #define MATCH_ADD_UW 0x800003b #define MASK_ADD_UW 0xfe00707f #define MATCH_ADDD 0x7b #define MASK_ADDD 0xfe00707f #define MATCH_ADDI 0x13 #define MASK_ADDI 0x707f #define MATCH_ADDID 0x5b #define MASK_ADDID 0x707f #define MATCH_ADDIW 0x1b #define MASK_ADDIW 0x707f #define MATCH_ADDW 0x3b #define MASK_ADDW 0xfe00707f #define MATCH_AES32DSI 0x2a000033 #define MASK_AES32DSI 0x3e00707f #define MATCH_AES32DSMI 0x2e000033 #define MASK_AES32DSMI 0x3e00707f #define MATCH_AES32ESI 0x22000033 #define MASK_AES32ESI 0x3e00707f #define MATCH_AES32ESMI 0x26000033 #define MASK_AES32ESMI 0x3e00707f #define MATCH_AES64DS 0x3a000033 #define MASK_AES64DS 0xfe00707f #define MATCH_AES64DSM 0x3e000033 #define MASK_AES64DSM 0xfe00707f #define MATCH_AES64ES 0x32000033 #define MASK_AES64ES 0xfe00707f #define MATCH_AES64ESM 0x36000033 #define MASK_AES64ESM 0xfe00707f #define MATCH_AES64IM 0x30001013 #define MASK_AES64IM 0xfff0707f #define MATCH_AES64KS1I 0x31001013 #define MASK_AES64KS1I 0xff00707f #define MATCH_AES64KS2 0x7e000033 #define MASK_AES64KS2 0xfe00707f #define MATCH_AMOADD_D 0x302f #define MASK_AMOADD_D 0xf800707f #define MATCH_AMOADD_W 0x202f #define MASK_AMOADD_W 0xf800707f #define MATCH_AMOAND_D 0x6000302f #define MASK_AMOAND_D 0xf800707f #define MATCH_AMOAND_W 0x6000202f #define MASK_AMOAND_W 0xf800707f #define MATCH_AMOMAX_D 0xa000302f #define MASK_AMOMAX_D 0xf800707f #define MATCH_AMOMAX_W 0xa000202f #define MASK_AMOMAX_W 0xf800707f #define MATCH_AMOMAXU_D 0xe000302f #define MASK_AMOMAXU_D 0xf800707f #define MATCH_AMOMAXU_W 0xe000202f #define MASK_AMOMAXU_W 0xf800707f #define MATCH_AMOMIN_D 0x8000302f #define MASK_AMOMIN_D 0xf800707f #define MATCH_AMOMIN_W 0x8000202f #define MASK_AMOMIN_W 0xf800707f #define MATCH_AMOMINU_D 0xc000302f #define MASK_AMOMINU_D 0xf800707f #define MATCH_AMOMINU_W 0xc000202f #define MASK_AMOMINU_W 0xf800707f #define MATCH_AMOOR_D 0x4000302f #define MASK_AMOOR_D 0xf800707f #define MATCH_AMOOR_W 0x4000202f #define MASK_AMOOR_W 0xf800707f #define MATCH_AMOSWAP_D 0x800302f #define MASK_AMOSWAP_D 0xf800707f #define MATCH_AMOSWAP_W 0x800202f #define MASK_AMOSWAP_W 0xf800707f #define MATCH_AMOXOR_D 0x2000302f #define MASK_AMOXOR_D 0xf800707f #define MATCH_AMOXOR_W 0x2000202f #define MASK_AMOXOR_W 0xf800707f #define MATCH_AND 0x7033 #define MASK_AND 0xfe00707f #define MATCH_ANDI 0x7013 #define MASK_ANDI 0x707f #define MATCH_ANDN 0x40007033 #define MASK_ANDN 0xfe00707f #define MATCH_AUIPC 0x17 #define MASK_AUIPC 0x7f #define MATCH_AVE 0xe0000077 #define MASK_AVE 0xfe00707f #define MATCH_BCLR 0x48001033 #define MASK_BCLR 0xfe00707f #define MATCH_BCLRI 0x48001013 #define MASK_BCLRI 0xfc00707f #define MATCH_BCOMPRESS 0x8006033 #define MASK_BCOMPRESS 0xfe00707f #define MATCH_BCOMPRESSW 0x800603b #define MASK_BCOMPRESSW 0xfe00707f #define MATCH_BDECOMPRESS 0x48006033 #define MASK_BDECOMPRESS 0xfe00707f #define MATCH_BDECOMPRESSW 0x4800603b #define MASK_BDECOMPRESSW 0xfe00707f #define MATCH_BEQ 0x63 #define MASK_BEQ 0x707f #define MATCH_BEXT 0x48005033 #define MASK_BEXT 0xfe00707f #define MATCH_BEXTI 0x48005013 #define MASK_BEXTI 0xfc00707f #define MATCH_BFP 0x48007033 #define MASK_BFP 0xfe00707f #define MATCH_BFPW 0x4800703b #define MASK_BFPW 0xfe00707f #define MATCH_BGE 0x5063 #define MASK_BGE 0x707f #define MATCH_BGEU 0x7063 #define MASK_BGEU 0x707f #define MATCH_BINV 0x68001033 #define MASK_BINV 0xfe00707f #define MATCH_BINVI 0x68001013 #define MASK_BINVI 0xfc00707f #define MATCH_BITREV 0xe6000077 #define MASK_BITREV 0xfe00707f #define MATCH_BITREVI 0xe8000077 #define MASK_BITREVI 0xfc00707f #define MATCH_BLT 0x4063 #define MASK_BLT 0x707f #define MATCH_BLTU 0x6063 #define MASK_BLTU 0x707f #define MATCH_BMATFLIP 0x60301013 #define MASK_BMATFLIP 0xfff0707f #define MATCH_BMATOR 0x8003033 #define MASK_BMATOR 0xfe00707f #define MATCH_BMATXOR 0x48003033 #define MASK_BMATXOR 0xfe00707f #define MATCH_BNE 0x1063 #define MASK_BNE 0x707f #define MATCH_BPICK 0x3077 #define MASK_BPICK 0x600707f #define MATCH_BSET 0x28001033 #define MASK_BSET 0xfe00707f #define MATCH_BSETI 0x28001013 #define MASK_BSETI 0xfc00707f #define MATCH_C_ADD 0x9002 #define MASK_C_ADD 0xf003 #define MATCH_C_ADDI 0x1 #define MASK_C_ADDI 0xe003 #define MATCH_C_ADDI16SP 0x6101 #define MASK_C_ADDI16SP 0xef83 #define MATCH_C_ADDI4SPN 0x0 #define MASK_C_ADDI4SPN 0xe003 #define MATCH_C_ADDIW 0x2001 #define MASK_C_ADDIW 0xe003 #define MATCH_C_ADDW 0x9c21 #define MASK_C_ADDW 0xfc63 #define MATCH_C_AND 0x8c61 #define MASK_C_AND 0xfc63 #define MATCH_C_ANDI 0x8801 #define MASK_C_ANDI 0xec03 #define MATCH_C_BEQZ 0xc001 #define MASK_C_BEQZ 0xe003 #define MATCH_C_BNEZ 0xe001 #define MASK_C_BNEZ 0xe003 #define MATCH_C_EBREAK 0x9002 #define MASK_C_EBREAK 0xffff #define MATCH_C_FLD 0x2000 #define MASK_C_FLD 0xe003 #define MATCH_C_FLDSP 0x2002 #define MASK_C_FLDSP 0xe003 #define MATCH_C_FLW 0x6000 #define MASK_C_FLW 0xe003 #define MATCH_C_FLWSP 0x6002 #define MASK_C_FLWSP 0xe003 #define MATCH_C_FSD 0xa000 #define MASK_C_FSD 0xe003 #define MATCH_C_FSDSP 0xa002 #define MASK_C_FSDSP 0xe003 #define MATCH_C_FSW 0xe000 #define MASK_C_FSW 0xe003 #define MATCH_C_FSWSP 0xe002 #define MASK_C_FSWSP 0xe003 #define MATCH_C_J 0xa001 #define MASK_C_J 0xe003 #define MATCH_C_JAL 0x2001 #define MASK_C_JAL 0xe003 #define MATCH_C_JALR 0x9002 #define MASK_C_JALR 0xf07f #define MATCH_C_JR 0x8002 #define MASK_C_JR 0xf07f #define MATCH_C_LD 0x6000 #define MASK_C_LD 0xe003 #define MATCH_C_LDSP 0x6002 #define MASK_C_LDSP 0xe003 #define MATCH_C_LI 0x4001 #define MASK_C_LI 0xe003 #define MATCH_C_LQ 0x2000 #define MASK_C_LQ 0xe003 #define MATCH_C_LQSP 0x2002 #define MASK_C_LQSP 0xe003 #define MATCH_C_LUI 0x6001 #define MASK_C_LUI 0xe003 #define MATCH_C_LW 0x4000 #define MASK_C_LW 0xe003 #define MATCH_C_LWSP 0x4002 #define MASK_C_LWSP 0xe003 #define MATCH_C_MV 0x8002 #define MASK_C_MV 0xf003 #define MATCH_C_NOP 0x1 #define MASK_C_NOP 0xef83 #define MATCH_C_OR 0x8c41 #define MASK_C_OR 0xfc63 #define MATCH_C_SD 0xe000 #define MASK_C_SD 0xe003 #define MATCH_C_SDSP 0xe002 #define MASK_C_SDSP 0xe003 #define MATCH_C_SLLI 0x2 #define MASK_C_SLLI 0xe003 #define MATCH_C_SQ 0xa000 #define MASK_C_SQ 0xe003 #define MATCH_C_SQSP 0xa002 #define MASK_C_SQSP 0xe003 #define MATCH_C_SRAI 0x8401 #define MASK_C_SRAI 0xec03 #define MATCH_C_SRLI 0x8001 #define MASK_C_SRLI 0xec03 #define MATCH_C_SUB 0x8c01 #define MASK_C_SUB 0xfc63 #define MATCH_C_SUBW 0x9c01 #define MASK_C_SUBW 0xfc63 #define MATCH_C_SW 0xc000 #define MASK_C_SW 0xe003 #define MATCH_C_SWSP 0xc002 #define MASK_C_SWSP 0xe003 #define MATCH_C_XOR 0x8c21 #define MASK_C_XOR 0xfc63 #define MATCH_CBO_CLEAN 0x10200f #define MASK_CBO_CLEAN 0xfff07fff #define MATCH_CBO_FLUSH 0x20200f #define MASK_CBO_FLUSH 0xfff07fff #define MATCH_CBO_INVAL 0x200f #define MASK_CBO_INVAL 0xfff07fff #define MATCH_CBO_ZERO 0x40200f #define MASK_CBO_ZERO 0xfff07fff #define MATCH_CLMUL 0xa001033 #define MASK_CLMUL 0xfe00707f #define MATCH_CLMULH 0xa003033 #define MASK_CLMULH 0xfe00707f #define MATCH_CLMULR 0xa002033 #define MASK_CLMULR 0xfe00707f #define MATCH_CLO16 0xaeb00077 #define MASK_CLO16 0xfff0707f #define MATCH_CLO32 0xafb00077 #define MASK_CLO32 0xfff0707f #define MATCH_CLO8 0xae300077 #define MASK_CLO8 0xfff0707f #define MATCH_CLRS16 0xae800077 #define MASK_CLRS16 0xfff0707f #define MATCH_CLRS32 0xaf800077 #define MASK_CLRS32 0xfff0707f #define MATCH_CLRS8 0xae000077 #define MASK_CLRS8 0xfff0707f #define MATCH_CLZ 0x60001013 #define MASK_CLZ 0xfff0707f #define MATCH_CLZ16 0xae900077 #define MASK_CLZ16 0xfff0707f #define MATCH_CLZ32 0xaf900077 #define MASK_CLZ32 0xfff0707f #define MATCH_CLZ8 0xae100077 #define MASK_CLZ8 0xfff0707f #define MATCH_CLZW 0x6000101b #define MASK_CLZW 0xfff0707f #define MATCH_CMIX 0x6001033 #define MASK_CMIX 0x600707f #define MATCH_CMOV 0x6005033 #define MASK_CMOV 0x600707f #define MATCH_CMPEQ16 0x4c000077 #define MASK_CMPEQ16 0xfe00707f #define MATCH_CMPEQ8 0x4e000077 #define MASK_CMPEQ8 0xfe00707f #define MATCH_CPOP 0x60201013 #define MASK_CPOP 0xfff0707f #define MATCH_CPOPW 0x6020101b #define MASK_CPOPW 0xfff0707f #define MATCH_CRAS16 0x44000077 #define MASK_CRAS16 0xfe00707f #define MATCH_CRAS32 0x44002077 #define MASK_CRAS32 0xfe00707f #define MATCH_CRC32_B 0x61001013 #define MASK_CRC32_B 0xfff0707f #define MATCH_CRC32_D 0x61301013 #define MASK_CRC32_D 0xfff0707f #define MATCH_CRC32_H 0x61101013 #define MASK_CRC32_H 0xfff0707f #define MATCH_CRC32_W 0x61201013 #define MASK_CRC32_W 0xfff0707f #define MATCH_CRC32C_B 0x61801013 #define MASK_CRC32C_B 0xfff0707f #define MATCH_CRC32C_D 0x61b01013 #define MASK_CRC32C_D 0xfff0707f #define MATCH_CRC32C_H 0x61901013 #define MASK_CRC32C_H 0xfff0707f #define MATCH_CRC32C_W 0x61a01013 #define MASK_CRC32C_W 0xfff0707f #define MATCH_CRSA16 0x46000077 #define MASK_CRSA16 0xfe00707f #define MATCH_CRSA32 0x46002077 #define MASK_CRSA32 0xfe00707f #define MATCH_CSRRC 0x3073 #define MASK_CSRRC 0x707f #define MATCH_CSRRCI 0x7073 #define MASK_CSRRCI 0x707f #define MATCH_CSRRS 0x2073 #define MASK_CSRRS 0x707f #define MATCH_CSRRSI 0x6073 #define MASK_CSRRSI 0x707f #define MATCH_CSRRW 0x1073 #define MASK_CSRRW 0x707f #define MATCH_CSRRWI 0x5073 #define MASK_CSRRWI 0x707f #define MATCH_CTZ 0x60101013 #define MASK_CTZ 0xfff0707f #define MATCH_CTZW 0x6010101b #define MASK_CTZW 0xfff0707f #define MATCH_DIV 0x2004033 #define MASK_DIV 0xfe00707f #define MATCH_DIVU 0x2005033 #define MASK_DIVU 0xfe00707f #define MATCH_DIVUW 0x200503b #define MASK_DIVUW 0xfe00707f #define MATCH_DIVW 0x200403b #define MASK_DIVW 0xfe00707f #define MATCH_DRET 0x7b200073 #define MASK_DRET 0xffffffff #define MATCH_EBREAK 0x100073 #define MASK_EBREAK 0xffffffff #define MATCH_ECALL 0x73 #define MASK_ECALL 0xffffffff #define MATCH_FADD_D 0x2000053 #define MASK_FADD_D 0xfe00007f #define MATCH_FADD_H 0x4000053 #define MASK_FADD_H 0xfe00007f #define MATCH_FADD_Q 0x6000053 #define MASK_FADD_Q 0xfe00007f #define MATCH_FADD_S 0x53 #define MASK_FADD_S 0xfe00007f #define MATCH_FCLASS_D 0xe2001053 #define MASK_FCLASS_D 0xfff0707f #define MATCH_FCLASS_H 0xe4001053 #define MASK_FCLASS_H 0xfff0707f #define MATCH_FCLASS_Q 0xe6001053 #define MASK_FCLASS_Q 0xfff0707f #define MATCH_FCLASS_S 0xe0001053 #define MASK_FCLASS_S 0xfff0707f #define MATCH_FCVT_D_H 0x42200053 #define MASK_FCVT_D_H 0xfff0007f #define MATCH_FCVT_D_L 0xd2200053 #define MASK_FCVT_D_L 0xfff0007f #define MATCH_FCVT_D_LU 0xd2300053 #define MASK_FCVT_D_LU 0xfff0007f #define MATCH_FCVT_D_Q 0x42300053 #define MASK_FCVT_D_Q 0xfff0007f #define MATCH_FCVT_D_S 0x42000053 #define MASK_FCVT_D_S 0xfff0007f #define MATCH_FCVT_D_W 0xd2000053 #define MASK_FCVT_D_W 0xfff0007f #define MATCH_FCVT_D_WU 0xd2100053 #define MASK_FCVT_D_WU 0xfff0007f #define MATCH_FCVT_H_D 0x44100053 #define MASK_FCVT_H_D 0xfff0007f #define MATCH_FCVT_H_L 0xd4200053 #define MASK_FCVT_H_L 0xfff0007f #define MATCH_FCVT_H_LU 0xd4300053 #define MASK_FCVT_H_LU 0xfff0007f #define MATCH_FCVT_H_Q 0x44300053 #define MASK_FCVT_H_Q 0xfff0007f #define MATCH_FCVT_H_S 0x44000053 #define MASK_FCVT_H_S 0xfff0007f #define MATCH_FCVT_H_W 0xd4000053 #define MASK_FCVT_H_W 0xfff0007f #define MATCH_FCVT_H_WU 0xd4100053 #define MASK_FCVT_H_WU 0xfff0007f #define MATCH_FCVT_L_D 0xc2200053 #define MASK_FCVT_L_D 0xfff0007f #define MATCH_FCVT_L_H 0xc4200053 #define MASK_FCVT_L_H 0xfff0007f #define MATCH_FCVT_L_Q 0xc6200053 #define MASK_FCVT_L_Q 0xfff0007f #define MATCH_FCVT_L_S 0xc0200053 #define MASK_FCVT_L_S 0xfff0007f #define MATCH_FCVT_LU_D 0xc2300053 #define MASK_FCVT_LU_D 0xfff0007f #define MATCH_FCVT_LU_H 0xc4300053 #define MASK_FCVT_LU_H 0xfff0007f #define MATCH_FCVT_LU_Q 0xc6300053 #define MASK_FCVT_LU_Q 0xfff0007f #define MATCH_FCVT_LU_S 0xc0300053 #define MASK_FCVT_LU_S 0xfff0007f #define MATCH_FCVT_Q_D 0x46100053 #define MASK_FCVT_Q_D 0xfff0007f #define MATCH_FCVT_Q_H 0x46200053 #define MASK_FCVT_Q_H 0xfff0007f #define MATCH_FCVT_Q_L 0xd6200053 #define MASK_FCVT_Q_L 0xfff0007f #define MATCH_FCVT_Q_LU 0xd6300053 #define MASK_FCVT_Q_LU 0xfff0007f #define MATCH_FCVT_Q_S 0x46000053 #define MASK_FCVT_Q_S 0xfff0007f #define MATCH_FCVT_Q_W 0xd6000053 #define MASK_FCVT_Q_W 0xfff0007f #define MATCH_FCVT_Q_WU 0xd6100053 #define MASK_FCVT_Q_WU 0xfff0007f #define MATCH_FCVT_S_D 0x40100053 #define MASK_FCVT_S_D 0xfff0007f #define MATCH_FCVT_S_H 0x40200053 #define MASK_FCVT_S_H 0xfff0007f #define MATCH_FCVT_S_L 0xd0200053 #define MASK_FCVT_S_L 0xfff0007f #define MATCH_FCVT_S_LU 0xd0300053 #define MASK_FCVT_S_LU 0xfff0007f #define MATCH_FCVT_S_Q 0x40300053 #define MASK_FCVT_S_Q 0xfff0007f #define MATCH_FCVT_S_W 0xd0000053 #define MASK_FCVT_S_W 0xfff0007f #define MATCH_FCVT_S_WU 0xd0100053 #define MASK_FCVT_S_WU 0xfff0007f #define MATCH_FCVT_W_D 0xc2000053 #define MASK_FCVT_W_D 0xfff0007f #define MATCH_FCVT_W_H 0xc4000053 #define MASK_FCVT_W_H 0xfff0007f #define MATCH_FCVT_W_Q 0xc6000053 #define MASK_FCVT_W_Q 0xfff0007f #define MATCH_FCVT_W_S 0xc0000053 #define MASK_FCVT_W_S 0xfff0007f #define MATCH_FCVT_WU_D 0xc2100053 #define MASK_FCVT_WU_D 0xfff0007f #define MATCH_FCVT_WU_H 0xc4100053 #define MASK_FCVT_WU_H 0xfff0007f #define MATCH_FCVT_WU_Q 0xc6100053 #define MASK_FCVT_WU_Q 0xfff0007f #define MATCH_FCVT_WU_S 0xc0100053 #define MASK_FCVT_WU_S 0xfff0007f #define MATCH_FDIV_D 0x1a000053 #define MASK_FDIV_D 0xfe00007f #define MATCH_FDIV_H 0x1c000053 #define MASK_FDIV_H 0xfe00007f #define MATCH_FDIV_Q 0x1e000053 #define MASK_FDIV_Q 0xfe00007f #define MATCH_FDIV_S 0x18000053 #define MASK_FDIV_S 0xfe00007f #define MATCH_FENCE 0xf #define MASK_FENCE 0x707f #define MATCH_FENCE_I 0x100f #define MASK_FENCE_I 0x707f #define MATCH_FEQ_D 0xa2002053 #define MASK_FEQ_D 0xfe00707f #define MATCH_FEQ_H 0xa4002053 #define MASK_FEQ_H 0xfe00707f #define MATCH_FEQ_Q 0xa6002053 #define MASK_FEQ_Q 0xfe00707f #define MATCH_FEQ_S 0xa0002053 #define MASK_FEQ_S 0xfe00707f #define MATCH_FLD 0x3007 #define MASK_FLD 0x707f #define MATCH_FLE_D 0xa2000053 #define MASK_FLE_D 0xfe00707f #define MATCH_FLE_H 0xa4000053 #define MASK_FLE_H 0xfe00707f #define MATCH_FLE_Q 0xa6000053 #define MASK_FLE_Q 0xfe00707f #define MATCH_FLE_S 0xa0000053 #define MASK_FLE_S 0xfe00707f #define MATCH_FLH 0x1007 #define MASK_FLH 0x707f #define MATCH_FLQ 0x4007 #define MASK_FLQ 0x707f #define MATCH_FLT_D 0xa2001053 #define MASK_FLT_D 0xfe00707f #define MATCH_FLT_H 0xa4001053 #define MASK_FLT_H 0xfe00707f #define MATCH_FLT_Q 0xa6001053 #define MASK_FLT_Q 0xfe00707f #define MATCH_FLT_S 0xa0001053 #define MASK_FLT_S 0xfe00707f #define MATCH_FLW 0x2007 #define MASK_FLW 0x707f #define MATCH_FMADD_D 0x2000043 #define MASK_FMADD_D 0x600007f #define MATCH_FMADD_H 0x4000043 #define MASK_FMADD_H 0x600007f #define MATCH_FMADD_Q 0x6000043 #define MASK_FMADD_Q 0x600007f #define MATCH_FMADD_S 0x43 #define MASK_FMADD_S 0x600007f #define MATCH_FMAX_D 0x2a001053 #define MASK_FMAX_D 0xfe00707f #define MATCH_FMAX_H 0x2c001053 #define MASK_FMAX_H 0xfe00707f #define MATCH_FMAX_Q 0x2e001053 #define MASK_FMAX_Q 0xfe00707f #define MATCH_FMAX_S 0x28001053 #define MASK_FMAX_S 0xfe00707f #define MATCH_FMIN_D 0x2a000053 #define MASK_FMIN_D 0xfe00707f #define MATCH_FMIN_H 0x2c000053 #define MASK_FMIN_H 0xfe00707f #define MATCH_FMIN_Q 0x2e000053 #define MASK_FMIN_Q 0xfe00707f #define MATCH_FMIN_S 0x28000053 #define MASK_FMIN_S 0xfe00707f #define MATCH_FMSUB_D 0x2000047 #define MASK_FMSUB_D 0x600007f #define MATCH_FMSUB_H 0x4000047 #define MASK_FMSUB_H 0x600007f #define MATCH_FMSUB_Q 0x6000047 #define MASK_FMSUB_Q 0x600007f #define MATCH_FMSUB_S 0x47 #define MASK_FMSUB_S 0x600007f #define MATCH_FMUL_D 0x12000053 #define MASK_FMUL_D 0xfe00007f #define MATCH_FMUL_H 0x14000053 #define MASK_FMUL_H 0xfe00007f #define MATCH_FMUL_Q 0x16000053 #define MASK_FMUL_Q 0xfe00007f #define MATCH_FMUL_S 0x10000053 #define MASK_FMUL_S 0xfe00007f #define MATCH_FMV_D_X 0xf2000053 #define MASK_FMV_D_X 0xfff0707f #define MATCH_FMV_H_X 0xf4000053 #define MASK_FMV_H_X 0xfff0707f #define MATCH_FMV_W_X 0xf0000053 #define MASK_FMV_W_X 0xfff0707f #define MATCH_FMV_X_D 0xe2000053 #define MASK_FMV_X_D 0xfff0707f #define MATCH_FMV_X_H 0xe4000053 #define MASK_FMV_X_H 0xfff0707f #define MATCH_FMV_X_W 0xe0000053 #define MASK_FMV_X_W 0xfff0707f #define MATCH_FNMADD_D 0x200004f #define MASK_FNMADD_D 0x600007f #define MATCH_FNMADD_H 0x400004f #define MASK_FNMADD_H 0x600007f #define MATCH_FNMADD_Q 0x600004f #define MASK_FNMADD_Q 0x600007f #define MATCH_FNMADD_S 0x4f #define MASK_FNMADD_S 0x600007f #define MATCH_FNMSUB_D 0x200004b #define MASK_FNMSUB_D 0x600007f #define MATCH_FNMSUB_H 0x400004b #define MASK_FNMSUB_H 0x600007f #define MATCH_FNMSUB_Q 0x600004b #define MASK_FNMSUB_Q 0x600007f #define MATCH_FNMSUB_S 0x4b #define MASK_FNMSUB_S 0x600007f #define MATCH_FSD 0x3027 #define MASK_FSD 0x707f #define MATCH_FSGNJ_D 0x22000053 #define MASK_FSGNJ_D 0xfe00707f #define MATCH_FSGNJ_H 0x24000053 #define MASK_FSGNJ_H 0xfe00707f #define MATCH_FSGNJ_Q 0x26000053 #define MASK_FSGNJ_Q 0xfe00707f #define MATCH_FSGNJ_S 0x20000053 #define MASK_FSGNJ_S 0xfe00707f #define MATCH_FSGNJN_D 0x22001053 #define MASK_FSGNJN_D 0xfe00707f #define MATCH_FSGNJN_H 0x24001053 #define MASK_FSGNJN_H 0xfe00707f #define MATCH_FSGNJN_Q 0x26001053 #define MASK_FSGNJN_Q 0xfe00707f #define MATCH_FSGNJN_S 0x20001053 #define MASK_FSGNJN_S 0xfe00707f #define MATCH_FSGNJX_D 0x22002053 #define MASK_FSGNJX_D 0xfe00707f #define MATCH_FSGNJX_H 0x24002053 #define MASK_FSGNJX_H 0xfe00707f #define MATCH_FSGNJX_Q 0x26002053 #define MASK_FSGNJX_Q 0xfe00707f #define MATCH_FSGNJX_S 0x20002053 #define MASK_FSGNJX_S 0xfe00707f #define MATCH_FSH 0x1027 #define MASK_FSH 0x707f #define MATCH_FSL 0x4001033 #define MASK_FSL 0x600707f #define MATCH_FSLW 0x400103b #define MASK_FSLW 0x600707f #define MATCH_FSQ 0x4027 #define MASK_FSQ 0x707f #define MATCH_FSQRT_D 0x5a000053 #define MASK_FSQRT_D 0xfff0007f #define MATCH_FSQRT_H 0x5c000053 #define MASK_FSQRT_H 0xfff0007f #define MATCH_FSQRT_Q 0x5e000053 #define MASK_FSQRT_Q 0xfff0007f #define MATCH_FSQRT_S 0x58000053 #define MASK_FSQRT_S 0xfff0007f #define MATCH_FSR 0x4005033 #define MASK_FSR 0x600707f #define MATCH_FSRI 0x4005013 #define MASK_FSRI 0x400707f #define MATCH_FSRIW 0x400501b #define MASK_FSRIW 0x600707f #define MATCH_FSRW 0x400503b #define MASK_FSRW 0x600707f #define MATCH_FSUB_D 0xa000053 #define MASK_FSUB_D 0xfe00007f #define MATCH_FSUB_H 0xc000053 #define MASK_FSUB_H 0xfe00007f #define MATCH_FSUB_Q 0xe000053 #define MASK_FSUB_Q 0xfe00007f #define MATCH_FSUB_S 0x8000053 #define MASK_FSUB_S 0xfe00007f #define MATCH_FSW 0x2027 #define MASK_FSW 0x707f #define MATCH_GORC 0x28005033 #define MASK_GORC 0xfe00707f #define MATCH_GORCI 0x28005013 #define MASK_GORCI 0xfc00707f #define MATCH_GORCIW 0x2800501b #define MASK_GORCIW 0xfe00707f #define MATCH_GORCW 0x2800503b #define MASK_GORCW 0xfe00707f #define MATCH_GREV 0x68005033 #define MASK_GREV 0xfe00707f #define MATCH_GREVI 0x68005013 #define MASK_GREVI 0xfc00707f #define MATCH_GREVIW 0x6800501b #define MASK_GREVIW 0xfe00707f #define MATCH_GREVW 0x6800503b #define MASK_GREVW 0xfe00707f #define MATCH_HFENCE_GVMA 0x62000073 #define MASK_HFENCE_GVMA 0xfe007fff #define MATCH_HFENCE_VVMA 0x22000073 #define MASK_HFENCE_VVMA 0xfe007fff #define MATCH_HINVAL_GVMA 0x66000073 #define MASK_HINVAL_GVMA 0xfe007fff #define MATCH_HINVAL_VVMA 0x26000073 #define MASK_HINVAL_VVMA 0xfe007fff #define MATCH_HLV_B 0x60004073 #define MASK_HLV_B 0xfff0707f #define MATCH_HLV_BU 0x60104073 #define MASK_HLV_BU 0xfff0707f #define MATCH_HLV_D 0x6c004073 #define MASK_HLV_D 0xfff0707f #define MATCH_HLV_H 0x64004073 #define MASK_HLV_H 0xfff0707f #define MATCH_HLV_HU 0x64104073 #define MASK_HLV_HU 0xfff0707f #define MATCH_HLV_W 0x68004073 #define MASK_HLV_W 0xfff0707f #define MATCH_HLV_WU 0x68104073 #define MASK_HLV_WU 0xfff0707f #define MATCH_HLVX_HU 0x64304073 #define MASK_HLVX_HU 0xfff0707f #define MATCH_HLVX_WU 0x68304073 #define MASK_HLVX_WU 0xfff0707f #define MATCH_HSV_B 0x62004073 #define MASK_HSV_B 0xfe007fff #define MATCH_HSV_D 0x6e004073 #define MASK_HSV_D 0xfe007fff #define MATCH_HSV_H 0x66004073 #define MASK_HSV_H 0xfe007fff #define MATCH_HSV_W 0x6a004073 #define MASK_HSV_W 0xfe007fff #define MATCH_INSB 0xac000077 #define MASK_INSB 0xff80707f #define MATCH_JAL 0x6f #define MASK_JAL 0x7f #define MATCH_JALR 0x67 #define MASK_JALR 0x707f #define MATCH_KABS16 0xad100077 #define MASK_KABS16 0xfff0707f #define MATCH_KABS32 0xad200077 #define MASK_KABS32 0xfff0707f #define MATCH_KABS8 0xad000077 #define MASK_KABS8 0xfff0707f #define MATCH_KABSW 0xad400077 #define MASK_KABSW 0xfff0707f #define MATCH_KADD16 0x10000077 #define MASK_KADD16 0xfe00707f #define MATCH_KADD32 0x10002077 #define MASK_KADD32 0xfe00707f #define MATCH_KADD64 0x90001077 #define MASK_KADD64 0xfe00707f #define MATCH_KADD8 0x18000077 #define MASK_KADD8 0xfe00707f #define MATCH_KADDH 0x4001077 #define MASK_KADDH 0xfe00707f #define MATCH_KADDW 0x1077 #define MASK_KADDW 0xfe00707f #define MATCH_KCRAS16 0x14000077 #define MASK_KCRAS16 0xfe00707f #define MATCH_KCRAS32 0x14002077 #define MASK_KCRAS32 0xfe00707f #define MATCH_KCRSA16 0x16000077 #define MASK_KCRSA16 0xfe00707f #define MATCH_KCRSA32 0x16002077 #define MASK_KCRSA32 0xfe00707f #define MATCH_KDMABB 0xd2001077 #define MASK_KDMABB 0xfe00707f #define MATCH_KDMABB16 0xd8001077 #define MASK_KDMABB16 0xfe00707f #define MATCH_KDMABT 0xe2001077 #define MASK_KDMABT 0xfe00707f #define MATCH_KDMABT16 0xe8001077 #define MASK_KDMABT16 0xfe00707f #define MATCH_KDMATT 0xf2001077 #define MASK_KDMATT 0xfe00707f #define MATCH_KDMATT16 0xf8001077 #define MASK_KDMATT16 0xfe00707f #define MATCH_KDMBB 0xa001077 #define MASK_KDMBB 0xfe00707f #define MATCH_KDMBB16 0xda001077 #define MASK_KDMBB16 0xfe00707f #define MATCH_KDMBT 0x1a001077 #define MASK_KDMBT 0xfe00707f #define MATCH_KDMBT16 0xea001077 #define MASK_KDMBT16 0xfe00707f #define MATCH_KDMTT 0x2a001077 #define MASK_KDMTT 0xfe00707f #define MATCH_KDMTT16 0xfa001077 #define MASK_KDMTT16 0xfe00707f #define MATCH_KHM16 0x86000077 #define MASK_KHM16 0xfe00707f #define MATCH_KHM8 0x8e000077 #define MASK_KHM8 0xfe00707f #define MATCH_KHMBB 0xc001077 #define MASK_KHMBB 0xfe00707f #define MATCH_KHMBB16 0xdc001077 #define MASK_KHMBB16 0xfe00707f #define MATCH_KHMBT 0x1c001077 #define MASK_KHMBT 0xfe00707f #define MATCH_KHMBT16 0xec001077 #define MASK_KHMBT16 0xfe00707f #define MATCH_KHMTT 0x2c001077 #define MASK_KHMTT 0xfe00707f #define MATCH_KHMTT16 0xfc001077 #define MASK_KHMTT16 0xfe00707f #define MATCH_KHMX16 0x96000077 #define MASK_KHMX16 0xfe00707f #define MATCH_KHMX8 0x9e000077 #define MASK_KHMX8 0xfe00707f #define MATCH_KMABB 0x5a001077 #define MASK_KMABB 0xfe00707f #define MATCH_KMABB32 0x5a002077 #define MASK_KMABB32 0xfe00707f #define MATCH_KMABT 0x6a001077 #define MASK_KMABT 0xfe00707f #define MATCH_KMABT32 0x6a002077 #define MASK_KMABT32 0xfe00707f #define MATCH_KMADA 0x48001077 #define MASK_KMADA 0xfe00707f #define MATCH_KMADRS 0x6c001077 #define MASK_KMADRS 0xfe00707f #define MATCH_KMADRS32 0x6c002077 #define MASK_KMADRS32 0xfe00707f #define MATCH_KMADS 0x5c001077 #define MASK_KMADS 0xfe00707f #define MATCH_KMADS32 0x5c002077 #define MASK_KMADS32 0xfe00707f #define MATCH_KMAR64 0x94001077 #define MASK_KMAR64 0xfe00707f #define MATCH_KMATT 0x7a001077 #define MASK_KMATT 0xfe00707f #define MATCH_KMATT32 0x7a002077 #define MASK_KMATT32 0xfe00707f #define MATCH_KMAXDA 0x4a001077 #define MASK_KMAXDA 0xfe00707f #define MATCH_KMAXDA32 0x4a002077 #define MASK_KMAXDA32 0xfe00707f #define MATCH_KMAXDS 0x7c001077 #define MASK_KMAXDS 0xfe00707f #define MATCH_KMAXDS32 0x7c002077 #define MASK_KMAXDS32 0xfe00707f #define MATCH_KMDA 0x38001077 #define MASK_KMDA 0xfe00707f #define MATCH_KMDA32 0x38002077 #define MASK_KMDA32 0xfe00707f #define MATCH_KMMAC 0x60001077 #define MASK_KMMAC 0xfe00707f #define MATCH_KMMAC_U 0x70001077 #define MASK_KMMAC_U 0xfe00707f #define MATCH_KMMAWB 0x46001077 #define MASK_KMMAWB 0xfe00707f #define MATCH_KMMAWB2 0xce001077 #define MASK_KMMAWB2 0xfe00707f #define MATCH_KMMAWB2_U 0xde001077 #define MASK_KMMAWB2_U 0xfe00707f #define MATCH_KMMAWB_U 0x56001077 #define MASK_KMMAWB_U 0xfe00707f #define MATCH_KMMAWT 0x66001077 #define MASK_KMMAWT 0xfe00707f #define MATCH_KMMAWT2 0xee001077 #define MASK_KMMAWT2 0xfe00707f #define MATCH_KMMAWT2_U 0xfe001077 #define MASK_KMMAWT2_U 0xfe00707f #define MATCH_KMMAWT_U 0x76001077 #define MASK_KMMAWT_U 0xfe00707f #define MATCH_KMMSB 0x42001077 #define MASK_KMMSB 0xfe00707f #define MATCH_KMMSB_U 0x52001077 #define MASK_KMMSB_U 0xfe00707f #define MATCH_KMMWB2 0x8e001077 #define MASK_KMMWB2 0xfe00707f #define MATCH_KMMWB2_U 0x9e001077 #define MASK_KMMWB2_U 0xfe00707f #define MATCH_KMMWT2 0xae001077 #define MASK_KMMWT2 0xfe00707f #define MATCH_KMMWT2_U 0xbe001077 #define MASK_KMMWT2_U 0xfe00707f #define MATCH_KMSDA 0x4c001077 #define MASK_KMSDA 0xfe00707f #define MATCH_KMSDA32 0x4c002077 #define MASK_KMSDA32 0xfe00707f #define MATCH_KMSR64 0x96001077 #define MASK_KMSR64 0xfe00707f #define MATCH_KMSXDA 0x4e001077 #define MASK_KMSXDA 0xfe00707f #define MATCH_KMSXDA32 0x4e002077 #define MASK_KMSXDA32 0xfe00707f #define MATCH_KMXDA 0x3a001077 #define MASK_KMXDA 0xfe00707f #define MATCH_KMXDA32 0x3a002077 #define MASK_KMXDA32 0xfe00707f #define MATCH_KSLL16 0x64000077 #define MASK_KSLL16 0xfe00707f #define MATCH_KSLL32 0x64002077 #define MASK_KSLL32 0xfe00707f #define MATCH_KSLL8 0x6c000077 #define MASK_KSLL8 0xfe00707f #define MATCH_KSLLI16 0x75000077 #define MASK_KSLLI16 0xff00707f #define MATCH_KSLLI32 0x84002077 #define MASK_KSLLI32 0xfe00707f #define MATCH_KSLLI8 0x7c800077 #define MASK_KSLLI8 0xff80707f #define MATCH_KSLLIW 0x36001077 #define MASK_KSLLIW 0xfe00707f #define MATCH_KSLLW 0x26001077 #define MASK_KSLLW 0xfe00707f #define MATCH_KSLRA16 0x56000077 #define MASK_KSLRA16 0xfe00707f #define MATCH_KSLRA16_U 0x66000077 #define MASK_KSLRA16_U 0xfe00707f #define MATCH_KSLRA32 0x56002077 #define MASK_KSLRA32 0xfe00707f #define MATCH_KSLRA32_U 0x66002077 #define MASK_KSLRA32_U 0xfe00707f #define MATCH_KSLRA8 0x5e000077 #define MASK_KSLRA8 0xfe00707f #define MATCH_KSLRA8_U 0x6e000077 #define MASK_KSLRA8_U 0xfe00707f #define MATCH_KSLRAW 0x6e001077 #define MASK_KSLRAW 0xfe00707f #define MATCH_KSLRAW_U 0x7e001077 #define MASK_KSLRAW_U 0xfe00707f #define MATCH_KSTAS16 0xc4002077 #define MASK_KSTAS16 0xfe00707f #define MATCH_KSTAS32 0xc0002077 #define MASK_KSTAS32 0xfe00707f #define MATCH_KSTSA16 0xc6002077 #define MASK_KSTSA16 0xfe00707f #define MATCH_KSTSA32 0xc2002077 #define MASK_KSTSA32 0xfe00707f #define MATCH_KSUB16 0x12000077 #define MASK_KSUB16 0xfe00707f #define MATCH_KSUB32 0x12002077 #define MASK_KSUB32 0xfe00707f #define MATCH_KSUB64 0x92001077 #define MASK_KSUB64 0xfe00707f #define MATCH_KSUB8 0x1a000077 #define MASK_KSUB8 0xfe00707f #define MATCH_KSUBH 0x6001077 #define MASK_KSUBH 0xfe00707f #define MATCH_KSUBW 0x2001077 #define MASK_KSUBW 0xfe00707f #define MATCH_KWMMUL 0x62001077 #define MASK_KWMMUL 0xfe00707f #define MATCH_KWMMUL_U 0x72001077 #define MASK_KWMMUL_U 0xfe00707f #define MATCH_LB 0x3 #define MASK_LB 0x707f #define MATCH_LBU 0x4003 #define MASK_LBU 0x707f #define MATCH_LD 0x3003 #define MASK_LD 0x707f #define MATCH_LDU 0x7003 #define MASK_LDU 0x707f #define MATCH_LH 0x1003 #define MASK_LH 0x707f #define MATCH_LHU 0x5003 #define MASK_LHU 0x707f #define MATCH_LQ 0x300f #define MASK_LQ 0x707f #define MATCH_LR_D 0x1000302f #define MASK_LR_D 0xf9f0707f #define MATCH_LR_W 0x1000202f #define MASK_LR_W 0xf9f0707f #define MATCH_LUI 0x37 #define MASK_LUI 0x7f #define MATCH_LW 0x2003 #define MASK_LW 0x707f #define MATCH_LWU 0x6003 #define MASK_LWU 0x707f #define MATCH_MADDR32 0xc4001077 #define MASK_MADDR32 0xfe00707f #define MATCH_MAX 0xa006033 #define MASK_MAX 0xfe00707f #define MATCH_MAXU 0xa007033 #define MASK_MAXU 0xfe00707f #define MATCH_MAXW 0xf2000077 #define MASK_MAXW 0xfe00707f #define MATCH_MIN 0xa004033 #define MASK_MIN 0xfe00707f #define MATCH_MINU 0xa005033 #define MASK_MINU 0xfe00707f #define MATCH_MINW 0xf0000077 #define MASK_MINW 0xfe00707f #define MATCH_MRET 0x30200073 #define MASK_MRET 0xffffffff #define MATCH_MSUBR32 0xc6001077 #define MASK_MSUBR32 0xfe00707f #define MATCH_MUL 0x2000033 #define MASK_MUL 0xfe00707f #define MATCH_MULH 0x2001033 #define MASK_MULH 0xfe00707f #define MATCH_MULHSU 0x2002033 #define MASK_MULHSU 0xfe00707f #define MATCH_MULHU 0x2003033 #define MASK_MULHU 0xfe00707f #define MATCH_MULR64 0xf0001077 #define MASK_MULR64 0xfe00707f #define MATCH_MULSR64 0xe0001077 #define MASK_MULSR64 0xfe00707f #define MATCH_MULW 0x200003b #define MASK_MULW 0xfe00707f #define MATCH_OR 0x6033 #define MASK_OR 0xfe00707f #define MATCH_ORI 0x6013 #define MASK_ORI 0x707f #define MATCH_ORN 0x40006033 #define MASK_ORN 0xfe00707f #define MATCH_PACK 0x8004033 #define MASK_PACK 0xfe00707f #define MATCH_PACKH 0x8007033 #define MASK_PACKH 0xfe00707f #define MATCH_PACKU 0x48004033 #define MASK_PACKU 0xfe00707f #define MATCH_PACKUW 0x4800403b #define MASK_PACKUW 0xfe00707f #define MATCH_PACKW 0x800403b #define MASK_PACKW 0xfe00707f #define MATCH_PAUSE 0x100000f #define MASK_PAUSE 0xffffffff #define MATCH_PBSAD 0xfc000077 #define MASK_PBSAD 0xfe00707f #define MATCH_PBSADA 0xfe000077 #define MASK_PBSADA 0xfe00707f #define MATCH_PKBB16 0xe001077 #define MASK_PKBB16 0xfe00707f #define MATCH_PKBB32 0xe002077 #define MASK_PKBB32 0xfe00707f #define MATCH_PKBT16 0x1e001077 #define MASK_PKBT16 0xfe00707f #define MATCH_PKBT32 0x1e002077 #define MASK_PKBT32 0xfe00707f #define MATCH_PKTB16 0x3e001077 #define MASK_PKTB16 0xfe00707f #define MATCH_PKTB32 0x3e002077 #define MASK_PKTB32 0xfe00707f #define MATCH_PKTT16 0x2e001077 #define MASK_PKTT16 0xfe00707f #define MATCH_PKTT32 0x2e002077 #define MASK_PKTT32 0xfe00707f #define MATCH_PREFETCH_I 0x6013 #define MASK_PREFETCH_I 0x1f07fff #define MATCH_PREFETCH_R 0x106013 #define MASK_PREFETCH_R 0x1f07fff #define MATCH_PREFETCH_W 0x306013 #define MASK_PREFETCH_W 0x1f07fff #define MATCH_RADD16 0x77 #define MASK_RADD16 0xfe00707f #define MATCH_RADD32 0x2077 #define MASK_RADD32 0xfe00707f #define MATCH_RADD64 0x80001077 #define MASK_RADD64 0xfe00707f #define MATCH_RADD8 0x8000077 #define MASK_RADD8 0xfe00707f #define MATCH_RADDW 0x20001077 #define MASK_RADDW 0xfe00707f #define MATCH_RCRAS16 0x4000077 #define MASK_RCRAS16 0xfe00707f #define MATCH_RCRAS32 0x4002077 #define MASK_RCRAS32 0xfe00707f #define MATCH_RCRSA16 0x6000077 #define MASK_RCRSA16 0xfe00707f #define MATCH_RCRSA32 0x6002077 #define MASK_RCRSA32 0xfe00707f #define MATCH_REM 0x2006033 #define MASK_REM 0xfe00707f #define MATCH_REMU 0x2007033 #define MASK_REMU 0xfe00707f #define MATCH_REMUW 0x200703b #define MASK_REMUW 0xfe00707f #define MATCH_REMW 0x200603b #define MASK_REMW 0xfe00707f #define MATCH_ROL 0x60001033 #define MASK_ROL 0xfe00707f #define MATCH_ROLW 0x6000103b #define MASK_ROLW 0xfe00707f #define MATCH_ROR 0x60005033 #define MASK_ROR 0xfe00707f #define MATCH_RORI 0x60005013 #define MASK_RORI 0xfc00707f #define MATCH_RORIW 0x6000501b #define MASK_RORIW 0xfe00707f #define MATCH_RORW 0x6000503b #define MASK_RORW 0xfe00707f #define MATCH_RSTAS16 0xb4002077 #define MASK_RSTAS16 0xfe00707f #define MATCH_RSTAS32 0xb0002077 #define MASK_RSTAS32 0xfe00707f #define MATCH_RSTSA16 0xb6002077 #define MASK_RSTSA16 0xfe00707f #define MATCH_RSTSA32 0xb2002077 #define MASK_RSTSA32 0xfe00707f #define MATCH_RSUB16 0x2000077 #define MASK_RSUB16 0xfe00707f #define MATCH_RSUB32 0x2002077 #define MASK_RSUB32 0xfe00707f #define MATCH_RSUB64 0x82001077 #define MASK_RSUB64 0xfe00707f #define MATCH_RSUB8 0xa000077 #define MASK_RSUB8 0xfe00707f #define MATCH_RSUBW 0x22001077 #define MASK_RSUBW 0xfe00707f #define MATCH_SB 0x23 #define MASK_SB 0x707f #define MATCH_SC_D 0x1800302f #define MASK_SC_D 0xf800707f #define MATCH_SC_W 0x1800202f #define MASK_SC_W 0xf800707f #define MATCH_SCLIP16 0x84000077 #define MASK_SCLIP16 0xff00707f #define MATCH_SCLIP32 0xe4000077 #define MASK_SCLIP32 0xfe00707f #define MATCH_SCLIP8 0x8c000077 #define MASK_SCLIP8 0xff80707f #define MATCH_SCMPLE16 0x1c000077 #define MASK_SCMPLE16 0xfe00707f #define MATCH_SCMPLE8 0x1e000077 #define MASK_SCMPLE8 0xfe00707f #define MATCH_SCMPLT16 0xc000077 #define MASK_SCMPLT16 0xfe00707f #define MATCH_SCMPLT8 0xe000077 #define MASK_SCMPLT8 0xfe00707f #define MATCH_SD 0x3023 #define MASK_SD 0x707f #define MATCH_SEXT_B 0x60401013 #define MASK_SEXT_B 0xfff0707f #define MATCH_SEXT_H 0x60501013 #define MASK_SEXT_H 0xfff0707f #define MATCH_SFENCE_INVAL_IR 0x18100073 #define MASK_SFENCE_INVAL_IR 0xffffffff #define MATCH_SFENCE_VMA 0x12000073 #define MASK_SFENCE_VMA 0xfe007fff #define MATCH_SFENCE_W_INVAL 0x18000073 #define MASK_SFENCE_W_INVAL 0xffffffff #define MATCH_SH 0x1023 #define MASK_SH 0x707f #define MATCH_SH1ADD 0x20002033 #define MASK_SH1ADD 0xfe00707f #define MATCH_SH1ADD_UW 0x2000203b #define MASK_SH1ADD_UW 0xfe00707f #define MATCH_SH2ADD 0x20004033 #define MASK_SH2ADD 0xfe00707f #define MATCH_SH2ADD_UW 0x2000403b #define MASK_SH2ADD_UW 0xfe00707f #define MATCH_SH3ADD 0x20006033 #define MASK_SH3ADD 0xfe00707f #define MATCH_SH3ADD_UW 0x2000603b #define MASK_SH3ADD_UW 0xfe00707f #define MATCH_SHA256SIG0 0x10201013 #define MASK_SHA256SIG0 0xfff0707f #define MATCH_SHA256SIG1 0x10301013 #define MASK_SHA256SIG1 0xfff0707f #define MATCH_SHA256SUM0 0x10001013 #define MASK_SHA256SUM0 0xfff0707f #define MATCH_SHA256SUM1 0x10101013 #define MASK_SHA256SUM1 0xfff0707f #define MATCH_SHA512SIG0 0x10601013 #define MASK_SHA512SIG0 0xfff0707f #define MATCH_SHA512SIG0H 0x5c000033 #define MASK_SHA512SIG0H 0xfe00707f #define MATCH_SHA512SIG0L 0x54000033 #define MASK_SHA512SIG0L 0xfe00707f #define MATCH_SHA512SIG1 0x10701013 #define MASK_SHA512SIG1 0xfff0707f #define MATCH_SHA512SIG1H 0x5e000033 #define MASK_SHA512SIG1H 0xfe00707f #define MATCH_SHA512SIG1L 0x56000033 #define MASK_SHA512SIG1L 0xfe00707f #define MATCH_SHA512SUM0 0x10401013 #define MASK_SHA512SUM0 0xfff0707f #define MATCH_SHA512SUM0R 0x50000033 #define MASK_SHA512SUM0R 0xfe00707f #define MATCH_SHA512SUM1 0x10501013 #define MASK_SHA512SUM1 0xfff0707f #define MATCH_SHA512SUM1R 0x52000033 #define MASK_SHA512SUM1R 0xfe00707f #define MATCH_SHFL 0x8001033 #define MASK_SHFL 0xfe00707f #define MATCH_SHFLI 0x8001013 #define MASK_SHFLI 0xfe00707f #define MATCH_SHFLW 0x800103b #define MASK_SHFLW 0xfe00707f #define MATCH_SINVAL_VMA 0x16000073 #define MASK_SINVAL_VMA 0xfe007fff #define MATCH_SLL 0x1033 #define MASK_SLL 0xfe00707f #define MATCH_SLL16 0x54000077 #define MASK_SLL16 0xfe00707f #define MATCH_SLL32 0x54002077 #define MASK_SLL32 0xfe00707f #define MATCH_SLL8 0x5c000077 #define MASK_SLL8 0xfe00707f #define MATCH_SLLD 0x107b #define MASK_SLLD 0xfe00707f #define MATCH_SLLI 0x1013 #define MASK_SLLI 0xf800707f #define MATCH_SLLI16 0x74000077 #define MASK_SLLI16 0xff00707f #define MATCH_SLLI32 0x74002077 #define MASK_SLLI32 0xfe00707f #define MATCH_SLLI8 0x7c000077 #define MASK_SLLI8 0xff80707f #define MATCH_SLLI_UW 0x800101b #define MASK_SLLI_UW 0xfc00707f #define MATCH_SLLID 0x105b #define MASK_SLLID 0xfc00707f #define MATCH_SLLIW 0x101b #define MASK_SLLIW 0xfe00707f #define MATCH_SLLW 0x103b #define MASK_SLLW 0xfe00707f #define MATCH_SLO 0x20001033 #define MASK_SLO 0xfe00707f #define MATCH_SLOI 0x20001013 #define MASK_SLOI 0xfc00707f #define MATCH_SLOIW 0x2000101b #define MASK_SLOIW 0xfe00707f #define MATCH_SLOW 0x2000103b #define MASK_SLOW 0xfe00707f #define MATCH_SLT 0x2033 #define MASK_SLT 0xfe00707f #define MATCH_SLTI 0x2013 #define MASK_SLTI 0x707f #define MATCH_SLTIU 0x3013 #define MASK_SLTIU 0x707f #define MATCH_SLTU 0x3033 #define MASK_SLTU 0xfe00707f #define MATCH_SM3P0 0x10801013 #define MASK_SM3P0 0xfff0707f #define MATCH_SM3P1 0x10901013 #define MASK_SM3P1 0xfff0707f #define MATCH_SM4ED 0x30000033 #define MASK_SM4ED 0x3e00707f #define MATCH_SM4KS 0x34000033 #define MASK_SM4KS 0x3e00707f #define MATCH_SMAL 0x5e001077 #define MASK_SMAL 0xfe00707f #define MATCH_SMALBB 0x88001077 #define MASK_SMALBB 0xfe00707f #define MATCH_SMALBT 0x98001077 #define MASK_SMALBT 0xfe00707f #define MATCH_SMALDA 0x8c001077 #define MASK_SMALDA 0xfe00707f #define MATCH_SMALDRS 0x9a001077 #define MASK_SMALDRS 0xfe00707f #define MATCH_SMALDS 0x8a001077 #define MASK_SMALDS 0xfe00707f #define MATCH_SMALTT 0xa8001077 #define MASK_SMALTT 0xfe00707f #define MATCH_SMALXDA 0x9c001077 #define MASK_SMALXDA 0xfe00707f #define MATCH_SMALXDS 0xaa001077 #define MASK_SMALXDS 0xfe00707f #define MATCH_SMAQA 0xc8000077 #define MASK_SMAQA 0xfe00707f #define MATCH_SMAQA_SU 0xca000077 #define MASK_SMAQA_SU 0xfe00707f #define MATCH_SMAR64 0x84001077 #define MASK_SMAR64 0xfe00707f #define MATCH_SMAX16 0x82000077 #define MASK_SMAX16 0xfe00707f #define MATCH_SMAX32 0x92002077 #define MASK_SMAX32 0xfe00707f #define MATCH_SMAX8 0x8a000077 #define MASK_SMAX8 0xfe00707f #define MATCH_SMBB16 0x8001077 #define MASK_SMBB16 0xfe00707f #define MATCH_SMBT16 0x18001077 #define MASK_SMBT16 0xfe00707f #define MATCH_SMBT32 0x18002077 #define MASK_SMBT32 0xfe00707f #define MATCH_SMDRS 0x68001077 #define MASK_SMDRS 0xfe00707f #define MATCH_SMDRS32 0x68002077 #define MASK_SMDRS32 0xfe00707f #define MATCH_SMDS 0x58001077 #define MASK_SMDS 0xfe00707f #define MATCH_SMDS32 0x58002077 #define MASK_SMDS32 0xfe00707f #define MATCH_SMIN16 0x80000077 #define MASK_SMIN16 0xfe00707f #define MATCH_SMIN32 0x90002077 #define MASK_SMIN32 0xfe00707f #define MATCH_SMIN8 0x88000077 #define MASK_SMIN8 0xfe00707f #define MATCH_SMMUL 0x40001077 #define MASK_SMMUL 0xfe00707f #define MATCH_SMMUL_U 0x50001077 #define MASK_SMMUL_U 0xfe00707f #define MATCH_SMMWB 0x44001077 #define MASK_SMMWB 0xfe00707f #define MATCH_SMMWB_U 0x54001077 #define MASK_SMMWB_U 0xfe00707f #define MATCH_SMMWT 0x64001077 #define MASK_SMMWT 0xfe00707f #define MATCH_SMMWT_U 0x74001077 #define MASK_SMMWT_U 0xfe00707f #define MATCH_SMSLDA 0xac001077 #define MASK_SMSLDA 0xfe00707f #define MATCH_SMSLXDA 0xbc001077 #define MASK_SMSLXDA 0xfe00707f #define MATCH_SMSR64 0x86001077 #define MASK_SMSR64 0xfe00707f #define MATCH_SMTT16 0x28001077 #define MASK_SMTT16 0xfe00707f #define MATCH_SMTT32 0x28002077 #define MASK_SMTT32 0xfe00707f #define MATCH_SMUL16 0xa0000077 #define MASK_SMUL16 0xfe00707f #define MATCH_SMUL8 0xa8000077 #define MASK_SMUL8 0xfe00707f #define MATCH_SMULX16 0xa2000077 #define MASK_SMULX16 0xfe00707f #define MATCH_SMULX8 0xaa000077 #define MASK_SMULX8 0xfe00707f #define MATCH_SMXDS 0x78001077 #define MASK_SMXDS 0xfe00707f #define MATCH_SMXDS32 0x78002077 #define MASK_SMXDS32 0xfe00707f #define MATCH_SQ 0x4023 #define MASK_SQ 0x707f #define MATCH_SRA 0x40005033 #define MASK_SRA 0xfe00707f #define MATCH_SRA16 0x50000077 #define MASK_SRA16 0xfe00707f #define MATCH_SRA16_U 0x60000077 #define MASK_SRA16_U 0xfe00707f #define MATCH_SRA32 0x50002077 #define MASK_SRA32 0xfe00707f #define MATCH_SRA32_U 0x60002077 #define MASK_SRA32_U 0xfe00707f #define MATCH_SRA8 0x58000077 #define MASK_SRA8 0xfe00707f #define MATCH_SRA8_U 0x68000077 #define MASK_SRA8_U 0xfe00707f #define MATCH_SRA_U 0x24001077 #define MASK_SRA_U 0xfe00707f #define MATCH_SRAD 0x4000507b #define MASK_SRAD 0xfe00707f #define MATCH_SRAI 0x40005013 #define MASK_SRAI 0xf800707f #define MATCH_SRAI16 0x70000077 #define MASK_SRAI16 0xff00707f #define MATCH_SRAI16_U 0x71000077 #define MASK_SRAI16_U 0xff00707f #define MATCH_SRAI32 0x70002077 #define MASK_SRAI32 0xfe00707f #define MATCH_SRAI32_U 0x80002077 #define MASK_SRAI32_U 0xfe00707f #define MATCH_SRAI8 0x78000077 #define MASK_SRAI8 0xff80707f #define MATCH_SRAI8_U 0x78800077 #define MASK_SRAI8_U 0xff80707f #define MATCH_SRAI_U 0xd4001077 #define MASK_SRAI_U 0xfc00707f #define MATCH_SRAID 0x4000505b #define MASK_SRAID 0xfc00707f #define MATCH_SRAIW 0x4000501b #define MASK_SRAIW 0xfe00707f #define MATCH_SRAIW_U 0x34001077 #define MASK_SRAIW_U 0xfe00707f #define MATCH_SRAW 0x4000503b #define MASK_SRAW 0xfe00707f #define MATCH_SRET 0x10200073 #define MASK_SRET 0xffffffff #define MATCH_SRL 0x5033 #define MASK_SRL 0xfe00707f #define MATCH_SRL16 0x52000077 #define MASK_SRL16 0xfe00707f #define MATCH_SRL16_U 0x62000077 #define MASK_SRL16_U 0xfe00707f #define MATCH_SRL32 0x52002077 #define MASK_SRL32 0xfe00707f #define MATCH_SRL32_U 0x62002077 #define MASK_SRL32_U 0xfe00707f #define MATCH_SRL8 0x5a000077 #define MASK_SRL8 0xfe00707f #define MATCH_SRL8_U 0x6a000077 #define MASK_SRL8_U 0xfe00707f #define MATCH_SRLD 0x507b #define MASK_SRLD 0xfe00707f #define MATCH_SRLI 0x5013 #define MASK_SRLI 0xf800707f #define MATCH_SRLI16 0x72000077 #define MASK_SRLI16 0xff00707f #define MATCH_SRLI16_U 0x73000077 #define MASK_SRLI16_U 0xff00707f #define MATCH_SRLI32 0x72002077 #define MASK_SRLI32 0xfe00707f #define MATCH_SRLI32_U 0x82002077 #define MASK_SRLI32_U 0xfe00707f #define MATCH_SRLI8 0x7a000077 #define MASK_SRLI8 0xff80707f #define MATCH_SRLI8_U 0x7a800077 #define MASK_SRLI8_U 0xff80707f #define MATCH_SRLID 0x505b #define MASK_SRLID 0xfc00707f #define MATCH_SRLIW 0x501b #define MASK_SRLIW 0xfe00707f #define MATCH_SRLW 0x503b #define MASK_SRLW 0xfe00707f #define MATCH_SRO 0x20005033 #define MASK_SRO 0xfe00707f #define MATCH_SROI 0x20005013 #define MASK_SROI 0xfc00707f #define MATCH_SROIW 0x2000501b #define MASK_SROIW 0xfe00707f #define MATCH_SROW 0x2000503b #define MASK_SROW 0xfe00707f #define MATCH_STAS16 0xf4002077 #define MASK_STAS16 0xfe00707f #define MATCH_STAS32 0xf0002077 #define MASK_STAS32 0xfe00707f #define MATCH_STSA16 0xf6002077 #define MASK_STSA16 0xfe00707f #define MATCH_STSA32 0xf2002077 #define MASK_STSA32 0xfe00707f #define MATCH_SUB 0x40000033 #define MASK_SUB 0xfe00707f #define MATCH_SUB16 0x42000077 #define MASK_SUB16 0xfe00707f #define MATCH_SUB32 0x42002077 #define MASK_SUB32 0xfe00707f #define MATCH_SUB64 0xc2001077 #define MASK_SUB64 0xfe00707f #define MATCH_SUB8 0x4a000077 #define MASK_SUB8 0xfe00707f #define MATCH_SUBD 0x4000007b #define MASK_SUBD 0xfe00707f #define MATCH_SUBW 0x4000003b #define MASK_SUBW 0xfe00707f #define MATCH_SUNPKD810 0xac800077 #define MASK_SUNPKD810 0xfff0707f #define MATCH_SUNPKD820 0xac900077 #define MASK_SUNPKD820 0xfff0707f #define MATCH_SUNPKD830 0xaca00077 #define MASK_SUNPKD830 0xfff0707f #define MATCH_SUNPKD831 0xacb00077 #define MASK_SUNPKD831 0xfff0707f #define MATCH_SUNPKD832 0xad300077 #define MASK_SUNPKD832 0xfff0707f #define MATCH_SW 0x2023 #define MASK_SW 0x707f #define MATCH_SWAP8 0xad800077 #define MASK_SWAP8 0xfff0707f #define MATCH_UCLIP16 0x85000077 #define MASK_UCLIP16 0xff00707f #define MATCH_UCLIP32 0xf4000077 #define MASK_UCLIP32 0xfe00707f #define MATCH_UCLIP8 0x8d000077 #define MASK_UCLIP8 0xff80707f #define MATCH_UCMPLE16 0x3c000077 #define MASK_UCMPLE16 0xfe00707f #define MATCH_UCMPLE8 0x3e000077 #define MASK_UCMPLE8 0xfe00707f #define MATCH_UCMPLT16 0x2c000077 #define MASK_UCMPLT16 0xfe00707f #define MATCH_UCMPLT8 0x2e000077 #define MASK_UCMPLT8 0xfe00707f #define MATCH_UKADD16 0x30000077 #define MASK_UKADD16 0xfe00707f #define MATCH_UKADD32 0x30002077 #define MASK_UKADD32 0xfe00707f #define MATCH_UKADD64 0xb0001077 #define MASK_UKADD64 0xfe00707f #define MATCH_UKADD8 0x38000077 #define MASK_UKADD8 0xfe00707f #define MATCH_UKADDH 0x14001077 #define MASK_UKADDH 0xfe00707f #define MATCH_UKADDW 0x10001077 #define MASK_UKADDW 0xfe00707f #define MATCH_UKCRAS16 0x34000077 #define MASK_UKCRAS16 0xfe00707f #define MATCH_UKCRAS32 0x34002077 #define MASK_UKCRAS32 0xfe00707f #define MATCH_UKCRSA16 0x36000077 #define MASK_UKCRSA16 0xfe00707f #define MATCH_UKCRSA32 0x36002077 #define MASK_UKCRSA32 0xfe00707f #define MATCH_UKMAR64 0xb4001077 #define MASK_UKMAR64 0xfe00707f #define MATCH_UKMSR64 0xb6001077 #define MASK_UKMSR64 0xfe00707f #define MATCH_UKSTAS16 0xe4002077 #define MASK_UKSTAS16 0xfe00707f #define MATCH_UKSTAS32 0xe0002077 #define MASK_UKSTAS32 0xfe00707f #define MATCH_UKSTSA16 0xe6002077 #define MASK_UKSTSA16 0xfe00707f #define MATCH_UKSTSA32 0xe2002077 #define MASK_UKSTSA32 0xfe00707f #define MATCH_UKSUB16 0x32000077 #define MASK_UKSUB16 0xfe00707f #define MATCH_UKSUB32 0x32002077 #define MASK_UKSUB32 0xfe00707f #define MATCH_UKSUB64 0xb2001077 #define MASK_UKSUB64 0xfe00707f #define MATCH_UKSUB8 0x3a000077 #define MASK_UKSUB8 0xfe00707f #define MATCH_UKSUBH 0x16001077 #define MASK_UKSUBH 0xfe00707f #define MATCH_UKSUBW 0x12001077 #define MASK_UKSUBW 0xfe00707f #define MATCH_UMAQA 0xcc000077 #define MASK_UMAQA 0xfe00707f #define MATCH_UMAR64 0xa4001077 #define MASK_UMAR64 0xfe00707f #define MATCH_UMAX16 0x92000077 #define MASK_UMAX16 0xfe00707f #define MATCH_UMAX32 0xa2002077 #define MASK_UMAX32 0xfe00707f #define MATCH_UMAX8 0x9a000077 #define MASK_UMAX8 0xfe00707f #define MATCH_UMIN16 0x90000077 #define MASK_UMIN16 0xfe00707f #define MATCH_UMIN32 0xa0002077 #define MASK_UMIN32 0xfe00707f #define MATCH_UMIN8 0x98000077 #define MASK_UMIN8 0xfe00707f #define MATCH_UMSR64 0xa6001077 #define MASK_UMSR64 0xfe00707f #define MATCH_UMUL16 0xb0000077 #define MASK_UMUL16 0xfe00707f #define MATCH_UMUL8 0xb8000077 #define MASK_UMUL8 0xfe00707f #define MATCH_UMULX16 0xb2000077 #define MASK_UMULX16 0xfe00707f #define MATCH_UMULX8 0xba000077 #define MASK_UMULX8 0xfe00707f #define MATCH_UNSHFL 0x8005033 #define MASK_UNSHFL 0xfe00707f #define MATCH_UNSHFLI 0x8005013 #define MASK_UNSHFLI 0xfe00707f #define MATCH_UNSHFLW 0x800503b #define MASK_UNSHFLW 0xfe00707f #define MATCH_URADD16 0x20000077 #define MASK_URADD16 0xfe00707f #define MATCH_URADD32 0x20002077 #define MASK_URADD32 0xfe00707f #define MATCH_URADD64 0xa0001077 #define MASK_URADD64 0xfe00707f #define MATCH_URADD8 0x28000077 #define MASK_URADD8 0xfe00707f #define MATCH_URADDW 0x30001077 #define MASK_URADDW 0xfe00707f #define MATCH_URCRAS16 0x24000077 #define MASK_URCRAS16 0xfe00707f #define MATCH_URCRAS32 0x24002077 #define MASK_URCRAS32 0xfe00707f #define MATCH_URCRSA16 0x26000077 #define MASK_URCRSA16 0xfe00707f #define MATCH_URCRSA32 0x26002077 #define MASK_URCRSA32 0xfe00707f #define MATCH_URSTAS16 0xd4002077 #define MASK_URSTAS16 0xfe00707f #define MATCH_URSTAS32 0xd0002077 #define MASK_URSTAS32 0xfe00707f #define MATCH_URSTSA16 0xd6002077 #define MASK_URSTSA16 0xfe00707f #define MATCH_URSTSA32 0xd2002077 #define MASK_URSTSA32 0xfe00707f #define MATCH_URSUB16 0x22000077 #define MASK_URSUB16 0xfe00707f #define MATCH_URSUB32 0x22002077 #define MASK_URSUB32 0xfe00707f #define MATCH_URSUB64 0xa2001077 #define MASK_URSUB64 0xfe00707f #define MATCH_URSUB8 0x2a000077 #define MASK_URSUB8 0xfe00707f #define MATCH_URSUBW 0x32001077 #define MASK_URSUBW 0xfe00707f #define MATCH_VAADD_VV 0x24002057 #define MASK_VAADD_VV 0xfc00707f #define MATCH_VAADD_VX 0x24006057 #define MASK_VAADD_VX 0xfc00707f #define MATCH_VAADDU_VV 0x20002057 #define MASK_VAADDU_VV 0xfc00707f #define MATCH_VAADDU_VX 0x20006057 #define MASK_VAADDU_VX 0xfc00707f #define MATCH_VADC_VIM 0x40003057 #define MASK_VADC_VIM 0xfe00707f #define MATCH_VADC_VVM 0x40000057 #define MASK_VADC_VVM 0xfe00707f #define MATCH_VADC_VXM 0x40004057 #define MASK_VADC_VXM 0xfe00707f #define MATCH_VADD_VI 0x3057 #define MASK_VADD_VI 0xfc00707f #define MATCH_VADD_VV 0x57 #define MASK_VADD_VV 0xfc00707f #define MATCH_VADD_VX 0x4057 #define MASK_VADD_VX 0xfc00707f #define MATCH_VAMOADDEI16_V 0x502f #define MASK_VAMOADDEI16_V 0xf800707f #define MATCH_VAMOADDEI32_V 0x602f #define MASK_VAMOADDEI32_V 0xf800707f #define MATCH_VAMOADDEI64_V 0x702f #define MASK_VAMOADDEI64_V 0xf800707f #define MATCH_VAMOADDEI8_V 0x2f #define MASK_VAMOADDEI8_V 0xf800707f #define MATCH_VAMOANDEI16_V 0x6000502f #define MASK_VAMOANDEI16_V 0xf800707f #define MATCH_VAMOANDEI32_V 0x6000602f #define MASK_VAMOANDEI32_V 0xf800707f #define MATCH_VAMOANDEI64_V 0x6000702f #define MASK_VAMOANDEI64_V 0xf800707f #define MATCH_VAMOANDEI8_V 0x6000002f #define MASK_VAMOANDEI8_V 0xf800707f #define MATCH_VAMOMAXEI16_V 0xa000502f #define MASK_VAMOMAXEI16_V 0xf800707f #define MATCH_VAMOMAXEI32_V 0xa000602f #define MASK_VAMOMAXEI32_V 0xf800707f #define MATCH_VAMOMAXEI64_V 0xa000702f #define MASK_VAMOMAXEI64_V 0xf800707f #define MATCH_VAMOMAXEI8_V 0xa000002f #define MASK_VAMOMAXEI8_V 0xf800707f #define MATCH_VAMOMAXUEI16_V 0xe000502f #define MASK_VAMOMAXUEI16_V 0xf800707f #define MATCH_VAMOMAXUEI32_V 0xe000602f #define MASK_VAMOMAXUEI32_V 0xf800707f #define MATCH_VAMOMAXUEI64_V 0xe000702f #define MASK_VAMOMAXUEI64_V 0xf800707f #define MATCH_VAMOMAXUEI8_V 0xe000002f #define MASK_VAMOMAXUEI8_V 0xf800707f #define MATCH_VAMOMINEI16_V 0x8000502f #define MASK_VAMOMINEI16_V 0xf800707f #define MATCH_VAMOMINEI32_V 0x8000602f #define MASK_VAMOMINEI32_V 0xf800707f #define MATCH_VAMOMINEI64_V 0x8000702f #define MASK_VAMOMINEI64_V 0xf800707f #define MATCH_VAMOMINEI8_V 0x8000002f #define MASK_VAMOMINEI8_V 0xf800707f #define MATCH_VAMOMINUEI16_V 0xc000502f #define MASK_VAMOMINUEI16_V 0xf800707f #define MATCH_VAMOMINUEI32_V 0xc000602f #define MASK_VAMOMINUEI32_V 0xf800707f #define MATCH_VAMOMINUEI64_V 0xc000702f #define MASK_VAMOMINUEI64_V 0xf800707f #define MATCH_VAMOMINUEI8_V 0xc000002f #define MASK_VAMOMINUEI8_V 0xf800707f #define MATCH_VAMOOREI16_V 0x4000502f #define MASK_VAMOOREI16_V 0xf800707f #define MATCH_VAMOOREI32_V 0x4000602f #define MASK_VAMOOREI32_V 0xf800707f #define MATCH_VAMOOREI64_V 0x4000702f #define MASK_VAMOOREI64_V 0xf800707f #define MATCH_VAMOOREI8_V 0x4000002f #define MASK_VAMOOREI8_V 0xf800707f #define MATCH_VAMOSWAPEI16_V 0x800502f #define MASK_VAMOSWAPEI16_V 0xf800707f #define MATCH_VAMOSWAPEI32_V 0x800602f #define MASK_VAMOSWAPEI32_V 0xf800707f #define MATCH_VAMOSWAPEI64_V 0x800702f #define MASK_VAMOSWAPEI64_V 0xf800707f #define MATCH_VAMOSWAPEI8_V 0x800002f #define MASK_VAMOSWAPEI8_V 0xf800707f #define MATCH_VAMOXOREI16_V 0x2000502f #define MASK_VAMOXOREI16_V 0xf800707f #define MATCH_VAMOXOREI32_V 0x2000602f #define MASK_VAMOXOREI32_V 0xf800707f #define MATCH_VAMOXOREI64_V 0x2000702f #define MASK_VAMOXOREI64_V 0xf800707f #define MATCH_VAMOXOREI8_V 0x2000002f #define MASK_VAMOXOREI8_V 0xf800707f #define MATCH_VAND_VI 0x24003057 #define MASK_VAND_VI 0xfc00707f #define MATCH_VAND_VV 0x24000057 #define MASK_VAND_VV 0xfc00707f #define MATCH_VAND_VX 0x24004057 #define MASK_VAND_VX 0xfc00707f #define MATCH_VASUB_VV 0x2c002057 #define MASK_VASUB_VV 0xfc00707f #define MATCH_VASUB_VX 0x2c006057 #define MASK_VASUB_VX 0xfc00707f #define MATCH_VASUBU_VV 0x28002057 #define MASK_VASUBU_VV 0xfc00707f #define MATCH_VASUBU_VX 0x28006057 #define MASK_VASUBU_VX 0xfc00707f #define MATCH_VCOMPRESS_VM 0x5e002057 #define MASK_VCOMPRESS_VM 0xfe00707f #define MATCH_VCPOP_M 0x40082057 #define MASK_VCPOP_M 0xfc0ff07f #define MATCH_VDIV_VV 0x84002057 #define MASK_VDIV_VV 0xfc00707f #define MATCH_VDIV_VX 0x84006057 #define MASK_VDIV_VX 0xfc00707f #define MATCH_VDIVU_VV 0x80002057 #define MASK_VDIVU_VV 0xfc00707f #define MATCH_VDIVU_VX 0x80006057 #define MASK_VDIVU_VX 0xfc00707f #define MATCH_VFADD_VF 0x5057 #define MASK_VFADD_VF 0xfc00707f #define MATCH_VFADD_VV 0x1057 #define MASK_VFADD_VV 0xfc00707f #define MATCH_VFCLASS_V 0x4c081057 #define MASK_VFCLASS_V 0xfc0ff07f #define MATCH_VFCVT_F_X_V 0x48019057 #define MASK_VFCVT_F_X_V 0xfc0ff07f #define MATCH_VFCVT_F_XU_V 0x48011057 #define MASK_VFCVT_F_XU_V 0xfc0ff07f #define MATCH_VFCVT_RTZ_X_F_V 0x48039057 #define MASK_VFCVT_RTZ_X_F_V 0xfc0ff07f #define MATCH_VFCVT_RTZ_XU_F_V 0x48031057 #define MASK_VFCVT_RTZ_XU_F_V 0xfc0ff07f #define MATCH_VFCVT_X_F_V 0x48009057 #define MASK_VFCVT_X_F_V 0xfc0ff07f #define MATCH_VFCVT_XU_F_V 0x48001057 #define MASK_VFCVT_XU_F_V 0xfc0ff07f #define MATCH_VFDIV_VF 0x80005057 #define MASK_VFDIV_VF 0xfc00707f #define MATCH_VFDIV_VV 0x80001057 #define MASK_VFDIV_VV 0xfc00707f #define MATCH_VFIRST_M 0x4008a057 #define MASK_VFIRST_M 0xfc0ff07f #define MATCH_VFMACC_VF 0xb0005057 #define MASK_VFMACC_VF 0xfc00707f #define MATCH_VFMACC_VV 0xb0001057 #define MASK_VFMACC_VV 0xfc00707f #define MATCH_VFMADD_VF 0xa0005057 #define MASK_VFMADD_VF 0xfc00707f #define MATCH_VFMADD_VV 0xa0001057 #define MASK_VFMADD_VV 0xfc00707f #define MATCH_VFMAX_VF 0x18005057 #define MASK_VFMAX_VF 0xfc00707f #define MATCH_VFMAX_VV 0x18001057 #define MASK_VFMAX_VV 0xfc00707f #define MATCH_VFMERGE_VFM 0x5c005057 #define MASK_VFMERGE_VFM 0xfe00707f #define MATCH_VFMIN_VF 0x10005057 #define MASK_VFMIN_VF 0xfc00707f #define MATCH_VFMIN_VV 0x10001057 #define MASK_VFMIN_VV 0xfc00707f #define MATCH_VFMSAC_VF 0xb8005057 #define MASK_VFMSAC_VF 0xfc00707f #define MATCH_VFMSAC_VV 0xb8001057 #define MASK_VFMSAC_VV 0xfc00707f #define MATCH_VFMSUB_VF 0xa8005057 #define MASK_VFMSUB_VF 0xfc00707f #define MATCH_VFMSUB_VV 0xa8001057 #define MASK_VFMSUB_VV 0xfc00707f #define MATCH_VFMUL_VF 0x90005057 #define MASK_VFMUL_VF 0xfc00707f #define MATCH_VFMUL_VV 0x90001057 #define MASK_VFMUL_VV 0xfc00707f #define MATCH_VFMV_F_S 0x42001057 #define MASK_VFMV_F_S 0xfe0ff07f #define MATCH_VFMV_S_F 0x42005057 #define MASK_VFMV_S_F 0xfff0707f #define MATCH_VFMV_V_F 0x5e005057 #define MASK_VFMV_V_F 0xfff0707f #define MATCH_VFNCVT_F_F_W 0x480a1057 #define MASK_VFNCVT_F_F_W 0xfc0ff07f #define MATCH_VFNCVT_F_X_W 0x48099057 #define MASK_VFNCVT_F_X_W 0xfc0ff07f #define MATCH_VFNCVT_F_XU_W 0x48091057 #define MASK_VFNCVT_F_XU_W 0xfc0ff07f #define MATCH_VFNCVT_ROD_F_F_W 0x480a9057 #define MASK_VFNCVT_ROD_F_F_W 0xfc0ff07f #define MATCH_VFNCVT_RTZ_X_F_W 0x480b9057 #define MASK_VFNCVT_RTZ_X_F_W 0xfc0ff07f #define MATCH_VFNCVT_RTZ_XU_F_W 0x480b1057 #define MASK_VFNCVT_RTZ_XU_F_W 0xfc0ff07f #define MATCH_VFNCVT_X_F_W 0x48089057 #define MASK_VFNCVT_X_F_W 0xfc0ff07f #define MATCH_VFNCVT_XU_F_W 0x48081057 #define MASK_VFNCVT_XU_F_W 0xfc0ff07f #define MATCH_VFNMACC_VF 0xb4005057 #define MASK_VFNMACC_VF 0xfc00707f #define MATCH_VFNMACC_VV 0xb4001057 #define MASK_VFNMACC_VV 0xfc00707f #define MATCH_VFNMADD_VF 0xa4005057 #define MASK_VFNMADD_VF 0xfc00707f #define MATCH_VFNMADD_VV 0xa4001057 #define MASK_VFNMADD_VV 0xfc00707f #define MATCH_VFNMSAC_VF 0xbc005057 #define MASK_VFNMSAC_VF 0xfc00707f #define MATCH_VFNMSAC_VV 0xbc001057 #define MASK_VFNMSAC_VV 0xfc00707f #define MATCH_VFNMSUB_VF 0xac005057 #define MASK_VFNMSUB_VF 0xfc00707f #define MATCH_VFNMSUB_VV 0xac001057 #define MASK_VFNMSUB_VV 0xfc00707f #define MATCH_VFRDIV_VF 0x84005057 #define MASK_VFRDIV_VF 0xfc00707f #define MATCH_VFREC7_V 0x4c029057 #define MASK_VFREC7_V 0xfc0ff07f #define MATCH_VFREDMAX_VS 0x1c001057 #define MASK_VFREDMAX_VS 0xfc00707f #define MATCH_VFREDMIN_VS 0x14001057 #define MASK_VFREDMIN_VS 0xfc00707f #define MATCH_VFREDOSUM_VS 0xc001057 #define MASK_VFREDOSUM_VS 0xfc00707f #define MATCH_VFREDUSUM_VS 0x4001057 #define MASK_VFREDUSUM_VS 0xfc00707f #define MATCH_VFRSQRT7_V 0x4c021057 #define MASK_VFRSQRT7_V 0xfc0ff07f #define MATCH_VFRSUB_VF 0x9c005057 #define MASK_VFRSUB_VF 0xfc00707f #define MATCH_VFSGNJ_VF 0x20005057 #define MASK_VFSGNJ_VF 0xfc00707f #define MATCH_VFSGNJ_VV 0x20001057 #define MASK_VFSGNJ_VV 0xfc00707f #define MATCH_VFSGNJN_VF 0x24005057 #define MASK_VFSGNJN_VF 0xfc00707f #define MATCH_VFSGNJN_VV 0x24001057 #define MASK_VFSGNJN_VV 0xfc00707f #define MATCH_VFSGNJX_VF 0x28005057 #define MASK_VFSGNJX_VF 0xfc00707f #define MATCH_VFSGNJX_VV 0x28001057 #define MASK_VFSGNJX_VV 0xfc00707f #define MATCH_VFSLIDE1DOWN_VF 0x3c005057 #define MASK_VFSLIDE1DOWN_VF 0xfc00707f #define MATCH_VFSLIDE1UP_VF 0x38005057 #define MASK_VFSLIDE1UP_VF 0xfc00707f #define MATCH_VFSQRT_V 0x4c001057 #define MASK_VFSQRT_V 0xfc0ff07f #define MATCH_VFSUB_VF 0x8005057 #define MASK_VFSUB_VF 0xfc00707f #define MATCH_VFSUB_VV 0x8001057 #define MASK_VFSUB_VV 0xfc00707f #define MATCH_VFWADD_VF 0xc0005057 #define MASK_VFWADD_VF 0xfc00707f #define MATCH_VFWADD_VV 0xc0001057 #define MASK_VFWADD_VV 0xfc00707f #define MATCH_VFWADD_WF 0xd0005057 #define MASK_VFWADD_WF 0xfc00707f #define MATCH_VFWADD_WV 0xd0001057 #define MASK_VFWADD_WV 0xfc00707f #define MATCH_VFWCVT_F_F_V 0x48061057 #define MASK_VFWCVT_F_F_V 0xfc0ff07f #define MATCH_VFWCVT_F_X_V 0x48059057 #define MASK_VFWCVT_F_X_V 0xfc0ff07f #define MATCH_VFWCVT_F_XU_V 0x48051057 #define MASK_VFWCVT_F_XU_V 0xfc0ff07f #define MATCH_VFWCVT_RTZ_X_F_V 0x48079057 #define MASK_VFWCVT_RTZ_X_F_V 0xfc0ff07f #define MATCH_VFWCVT_RTZ_XU_F_V 0x48071057 #define MASK_VFWCVT_RTZ_XU_F_V 0xfc0ff07f #define MATCH_VFWCVT_X_F_V 0x48049057 #define MASK_VFWCVT_X_F_V 0xfc0ff07f #define MATCH_VFWCVT_XU_F_V 0x48041057 #define MASK_VFWCVT_XU_F_V 0xfc0ff07f #define MATCH_VFWMACC_VF 0xf0005057 #define MASK_VFWMACC_VF 0xfc00707f #define MATCH_VFWMACC_VV 0xf0001057 #define MASK_VFWMACC_VV 0xfc00707f #define MATCH_VFWMSAC_VF 0xf8005057 #define MASK_VFWMSAC_VF 0xfc00707f #define MATCH_VFWMSAC_VV 0xf8001057 #define MASK_VFWMSAC_VV 0xfc00707f #define MATCH_VFWMUL_VF 0xe0005057 #define MASK_VFWMUL_VF 0xfc00707f #define MATCH_VFWMUL_VV 0xe0001057 #define MASK_VFWMUL_VV 0xfc00707f #define MATCH_VFWNMACC_VF 0xf4005057 #define MASK_VFWNMACC_VF 0xfc00707f #define MATCH_VFWNMACC_VV 0xf4001057 #define MASK_VFWNMACC_VV 0xfc00707f #define MATCH_VFWNMSAC_VF 0xfc005057 #define MASK_VFWNMSAC_VF 0xfc00707f #define MATCH_VFWNMSAC_VV 0xfc001057 #define MASK_VFWNMSAC_VV 0xfc00707f #define MATCH_VFWREDOSUM_VS 0xcc001057 #define MASK_VFWREDOSUM_VS 0xfc00707f #define MATCH_VFWREDUSUM_VS 0xc4001057 #define MASK_VFWREDUSUM_VS 0xfc00707f #define MATCH_VFWSUB_VF 0xc8005057 #define MASK_VFWSUB_VF 0xfc00707f #define MATCH_VFWSUB_VV 0xc8001057 #define MASK_VFWSUB_VV 0xfc00707f #define MATCH_VFWSUB_WF 0xd8005057 #define MASK_VFWSUB_WF 0xfc00707f #define MATCH_VFWSUB_WV 0xd8001057 #define MASK_VFWSUB_WV 0xfc00707f #define MATCH_VID_V 0x5008a057 #define MASK_VID_V 0xfdfff07f #define MATCH_VIOTA_M 0x50082057 #define MASK_VIOTA_M 0xfc0ff07f #define MATCH_VL1RE16_V 0x2805007 #define MASK_VL1RE16_V 0xfff0707f #define MATCH_VL1RE32_V 0x2806007 #define MASK_VL1RE32_V 0xfff0707f #define MATCH_VL1RE64_V 0x2807007 #define MASK_VL1RE64_V 0xfff0707f #define MATCH_VL1RE8_V 0x2800007 #define MASK_VL1RE8_V 0xfff0707f #define MATCH_VL2RE16_V 0x22805007 #define MASK_VL2RE16_V 0xfff0707f #define MATCH_VL2RE32_V 0x22806007 #define MASK_VL2RE32_V 0xfff0707f #define MATCH_VL2RE64_V 0x22807007 #define MASK_VL2RE64_V 0xfff0707f #define MATCH_VL2RE8_V 0x22800007 #define MASK_VL2RE8_V 0xfff0707f #define MATCH_VL4RE16_V 0x62805007 #define MASK_VL4RE16_V 0xfff0707f #define MATCH_VL4RE32_V 0x62806007 #define MASK_VL4RE32_V 0xfff0707f #define MATCH_VL4RE64_V 0x62807007 #define MASK_VL4RE64_V 0xfff0707f #define MATCH_VL4RE8_V 0x62800007 #define MASK_VL4RE8_V 0xfff0707f #define MATCH_VL8RE16_V 0xe2805007 #define MASK_VL8RE16_V 0xfff0707f #define MATCH_VL8RE32_V 0xe2806007 #define MASK_VL8RE32_V 0xfff0707f #define MATCH_VL8RE64_V 0xe2807007 #define MASK_VL8RE64_V 0xfff0707f #define MATCH_VL8RE8_V 0xe2800007 #define MASK_VL8RE8_V 0xfff0707f #define MATCH_VLE1024_V 0x10007007 #define MASK_VLE1024_V 0x1df0707f #define MATCH_VLE1024FF_V 0x11007007 #define MASK_VLE1024FF_V 0x1df0707f #define MATCH_VLE128_V 0x10000007 #define MASK_VLE128_V 0x1df0707f #define MATCH_VLE128FF_V 0x11000007 #define MASK_VLE128FF_V 0x1df0707f #define MATCH_VLE16_V 0x5007 #define MASK_VLE16_V 0x1df0707f #define MATCH_VLE16FF_V 0x1005007 #define MASK_VLE16FF_V 0x1df0707f #define MATCH_VLE256_V 0x10005007 #define MASK_VLE256_V 0x1df0707f #define MATCH_VLE256FF_V 0x11005007 #define MASK_VLE256FF_V 0x1df0707f #define MATCH_VLE32_V 0x6007 #define MASK_VLE32_V 0x1df0707f #define MATCH_VLE32FF_V 0x1006007 #define MASK_VLE32FF_V 0x1df0707f #define MATCH_VLE512_V 0x10006007 #define MASK_VLE512_V 0x1df0707f #define MATCH_VLE512FF_V 0x11006007 #define MASK_VLE512FF_V 0x1df0707f #define MATCH_VLE64_V 0x7007 #define MASK_VLE64_V 0x1df0707f #define MATCH_VLE64FF_V 0x1007007 #define MASK_VLE64FF_V 0x1df0707f #define MATCH_VLE8_V 0x7 #define MASK_VLE8_V 0x1df0707f #define MATCH_VLE8FF_V 0x1000007 #define MASK_VLE8FF_V 0x1df0707f #define MATCH_VLM_V 0x2b00007 #define MASK_VLM_V 0xfff0707f #define MATCH_VLOXEI1024_V 0x1c007007 #define MASK_VLOXEI1024_V 0x1c00707f #define MATCH_VLOXEI128_V 0x1c000007 #define MASK_VLOXEI128_V 0x1c00707f #define MATCH_VLOXEI16_V 0xc005007 #define MASK_VLOXEI16_V 0x1c00707f #define MATCH_VLOXEI256_V 0x1c005007 #define MASK_VLOXEI256_V 0x1c00707f #define MATCH_VLOXEI32_V 0xc006007 #define MASK_VLOXEI32_V 0x1c00707f #define MATCH_VLOXEI512_V 0x1c006007 #define MASK_VLOXEI512_V 0x1c00707f #define MATCH_VLOXEI64_V 0xc007007 #define MASK_VLOXEI64_V 0x1c00707f #define MATCH_VLOXEI8_V 0xc000007 #define MASK_VLOXEI8_V 0x1c00707f #define MATCH_VLSE1024_V 0x18007007 #define MASK_VLSE1024_V 0x1c00707f #define MATCH_VLSE128_V 0x18000007 #define MASK_VLSE128_V 0x1c00707f #define MATCH_VLSE16_V 0x8005007 #define MASK_VLSE16_V 0x1c00707f #define MATCH_VLSE256_V 0x18005007 #define MASK_VLSE256_V 0x1c00707f #define MATCH_VLSE32_V 0x8006007 #define MASK_VLSE32_V 0x1c00707f #define MATCH_VLSE512_V 0x18006007 #define MASK_VLSE512_V 0x1c00707f #define MATCH_VLSE64_V 0x8007007 #define MASK_VLSE64_V 0x1c00707f #define MATCH_VLSE8_V 0x8000007 #define MASK_VLSE8_V 0x1c00707f #define MATCH_VLUXEI1024_V 0x14007007 #define MASK_VLUXEI1024_V 0x1c00707f #define MATCH_VLUXEI128_V 0x14000007 #define MASK_VLUXEI128_V 0x1c00707f #define MATCH_VLUXEI16_V 0x4005007 #define MASK_VLUXEI16_V 0x1c00707f #define MATCH_VLUXEI256_V 0x14005007 #define MASK_VLUXEI256_V 0x1c00707f #define MATCH_VLUXEI32_V 0x4006007 #define MASK_VLUXEI32_V 0x1c00707f #define MATCH_VLUXEI512_V 0x14006007 #define MASK_VLUXEI512_V 0x1c00707f #define MATCH_VLUXEI64_V 0x4007007 #define MASK_VLUXEI64_V 0x1c00707f #define MATCH_VLUXEI8_V 0x4000007 #define MASK_VLUXEI8_V 0x1c00707f #define MATCH_VMACC_VV 0xb4002057 #define MASK_VMACC_VV 0xfc00707f #define MATCH_VMACC_VX 0xb4006057 #define MASK_VMACC_VX 0xfc00707f #define MATCH_VMADC_VI 0x46003057 #define MASK_VMADC_VI 0xfe00707f #define MATCH_VMADC_VIM 0x44003057 #define MASK_VMADC_VIM 0xfe00707f #define MATCH_VMADC_VV 0x46000057 #define MASK_VMADC_VV 0xfe00707f #define MATCH_VMADC_VVM 0x44000057 #define MASK_VMADC_VVM 0xfe00707f #define MATCH_VMADC_VX 0x46004057 #define MASK_VMADC_VX 0xfe00707f #define MATCH_VMADC_VXM 0x44004057 #define MASK_VMADC_VXM 0xfe00707f #define MATCH_VMADD_VV 0xa4002057 #define MASK_VMADD_VV 0xfc00707f #define MATCH_VMADD_VX 0xa4006057 #define MASK_VMADD_VX 0xfc00707f #define MATCH_VMAND_MM 0x64002057 #define MASK_VMAND_MM 0xfc00707f #define MATCH_VMANDN_MM 0x60002057 #define MASK_VMANDN_MM 0xfc00707f #define MATCH_VMAX_VV 0x1c000057 #define MASK_VMAX_VV 0xfc00707f #define MATCH_VMAX_VX 0x1c004057 #define MASK_VMAX_VX 0xfc00707f #define MATCH_VMAXU_VV 0x18000057 #define MASK_VMAXU_VV 0xfc00707f #define MATCH_VMAXU_VX 0x18004057 #define MASK_VMAXU_VX 0xfc00707f #define MATCH_VMERGE_VIM 0x5c003057 #define MASK_VMERGE_VIM 0xfe00707f #define MATCH_VMERGE_VVM 0x5c000057 #define MASK_VMERGE_VVM 0xfe00707f #define MATCH_VMERGE_VXM 0x5c004057 #define MASK_VMERGE_VXM 0xfe00707f #define MATCH_VMFEQ_VF 0x60005057 #define MASK_VMFEQ_VF 0xfc00707f #define MATCH_VMFEQ_VV 0x60001057 #define MASK_VMFEQ_VV 0xfc00707f #define MATCH_VMFGE_VF 0x7c005057 #define MASK_VMFGE_VF 0xfc00707f #define MATCH_VMFGT_VF 0x74005057 #define MASK_VMFGT_VF 0xfc00707f #define MATCH_VMFLE_VF 0x64005057 #define MASK_VMFLE_VF 0xfc00707f #define MATCH_VMFLE_VV 0x64001057 #define MASK_VMFLE_VV 0xfc00707f #define MATCH_VMFLT_VF 0x6c005057 #define MASK_VMFLT_VF 0xfc00707f #define MATCH_VMFLT_VV 0x6c001057 #define MASK_VMFLT_VV 0xfc00707f #define MATCH_VMFNE_VF 0x70005057 #define MASK_VMFNE_VF 0xfc00707f #define MATCH_VMFNE_VV 0x70001057 #define MASK_VMFNE_VV 0xfc00707f #define MATCH_VMIN_VV 0x14000057 #define MASK_VMIN_VV 0xfc00707f #define MATCH_VMIN_VX 0x14004057 #define MASK_VMIN_VX 0xfc00707f #define MATCH_VMINU_VV 0x10000057 #define MASK_VMINU_VV 0xfc00707f #define MATCH_VMINU_VX 0x10004057 #define MASK_VMINU_VX 0xfc00707f #define MATCH_VMNAND_MM 0x74002057 #define MASK_VMNAND_MM 0xfc00707f #define MATCH_VMNOR_MM 0x78002057 #define MASK_VMNOR_MM 0xfc00707f #define MATCH_VMOR_MM 0x68002057 #define MASK_VMOR_MM 0xfc00707f #define MATCH_VMORN_MM 0x70002057 #define MASK_VMORN_MM 0xfc00707f #define MATCH_VMSBC_VV 0x4e000057 #define MASK_VMSBC_VV 0xfe00707f #define MATCH_VMSBC_VVM 0x4c000057 #define MASK_VMSBC_VVM 0xfe00707f #define MATCH_VMSBC_VX 0x4e004057 #define MASK_VMSBC_VX 0xfe00707f #define MATCH_VMSBC_VXM 0x4c004057 #define MASK_VMSBC_VXM 0xfe00707f #define MATCH_VMSBF_M 0x5000a057 #define MASK_VMSBF_M 0xfc0ff07f #define MATCH_VMSEQ_VI 0x60003057 #define MASK_VMSEQ_VI 0xfc00707f #define MATCH_VMSEQ_VV 0x60000057 #define MASK_VMSEQ_VV 0xfc00707f #define MATCH_VMSEQ_VX 0x60004057 #define MASK_VMSEQ_VX 0xfc00707f #define MATCH_VMSGT_VI 0x7c003057 #define MASK_VMSGT_VI 0xfc00707f #define MATCH_VMSGT_VX 0x7c004057 #define MASK_VMSGT_VX 0xfc00707f #define MATCH_VMSGTU_VI 0x78003057 #define MASK_VMSGTU_VI 0xfc00707f #define MATCH_VMSGTU_VX 0x78004057 #define MASK_VMSGTU_VX 0xfc00707f #define MATCH_VMSIF_M 0x5001a057 #define MASK_VMSIF_M 0xfc0ff07f #define MATCH_VMSLE_VI 0x74003057 #define MASK_VMSLE_VI 0xfc00707f #define MATCH_VMSLE_VV 0x74000057 #define MASK_VMSLE_VV 0xfc00707f #define MATCH_VMSLE_VX 0x74004057 #define MASK_VMSLE_VX 0xfc00707f #define MATCH_VMSLEU_VI 0x70003057 #define MASK_VMSLEU_VI 0xfc00707f #define MATCH_VMSLEU_VV 0x70000057 #define MASK_VMSLEU_VV 0xfc00707f #define MATCH_VMSLEU_VX 0x70004057 #define MASK_VMSLEU_VX 0xfc00707f #define MATCH_VMSLT_VV 0x6c000057 #define MASK_VMSLT_VV 0xfc00707f #define MATCH_VMSLT_VX 0x6c004057 #define MASK_VMSLT_VX 0xfc00707f #define MATCH_VMSLTU_VV 0x68000057 #define MASK_VMSLTU_VV 0xfc00707f #define MATCH_VMSLTU_VX 0x68004057 #define MASK_VMSLTU_VX 0xfc00707f #define MATCH_VMSNE_VI 0x64003057 #define MASK_VMSNE_VI 0xfc00707f #define MATCH_VMSNE_VV 0x64000057 #define MASK_VMSNE_VV 0xfc00707f #define MATCH_VMSNE_VX 0x64004057 #define MASK_VMSNE_VX 0xfc00707f #define MATCH_VMSOF_M 0x50012057 #define MASK_VMSOF_M 0xfc0ff07f #define MATCH_VMUL_VV 0x94002057 #define MASK_VMUL_VV 0xfc00707f #define MATCH_VMUL_VX 0x94006057 #define MASK_VMUL_VX 0xfc00707f #define MATCH_VMULH_VV 0x9c002057 #define MASK_VMULH_VV 0xfc00707f #define MATCH_VMULH_VX 0x9c006057 #define MASK_VMULH_VX 0xfc00707f #define MATCH_VMULHSU_VV 0x98002057 #define MASK_VMULHSU_VV 0xfc00707f #define MATCH_VMULHSU_VX 0x98006057 #define MASK_VMULHSU_VX 0xfc00707f #define MATCH_VMULHU_VV 0x90002057 #define MASK_VMULHU_VV 0xfc00707f #define MATCH_VMULHU_VX 0x90006057 #define MASK_VMULHU_VX 0xfc00707f #define MATCH_VMV1R_V 0x9e003057 #define MASK_VMV1R_V 0xfe0ff07f #define MATCH_VMV2R_V 0x9e00b057 #define MASK_VMV2R_V 0xfe0ff07f #define MATCH_VMV4R_V 0x9e01b057 #define MASK_VMV4R_V 0xfe0ff07f #define MATCH_VMV8R_V 0x9e03b057 #define MASK_VMV8R_V 0xfe0ff07f #define MATCH_VMV_S_X 0x42006057 #define MASK_VMV_S_X 0xfff0707f #define MATCH_VMV_V_I 0x5e003057 #define MASK_VMV_V_I 0xfff0707f #define MATCH_VMV_V_V 0x5e000057 #define MASK_VMV_V_V 0xfff0707f #define MATCH_VMV_V_X 0x5e004057 #define MASK_VMV_V_X 0xfff0707f #define MATCH_VMV_X_S 0x42002057 #define MASK_VMV_X_S 0xfe0ff07f #define MATCH_VMXNOR_MM 0x7c002057 #define MASK_VMXNOR_MM 0xfc00707f #define MATCH_VMXOR_MM 0x6c002057 #define MASK_VMXOR_MM 0xfc00707f #define MATCH_VNCLIP_WI 0xbc003057 #define MASK_VNCLIP_WI 0xfc00707f #define MATCH_VNCLIP_WV 0xbc000057 #define MASK_VNCLIP_WV 0xfc00707f #define MATCH_VNCLIP_WX 0xbc004057 #define MASK_VNCLIP_WX 0xfc00707f #define MATCH_VNCLIPU_WI 0xb8003057 #define MASK_VNCLIPU_WI 0xfc00707f #define MATCH_VNCLIPU_WV 0xb8000057 #define MASK_VNCLIPU_WV 0xfc00707f #define MATCH_VNCLIPU_WX 0xb8004057 #define MASK_VNCLIPU_WX 0xfc00707f #define MATCH_VNMSAC_VV 0xbc002057 #define MASK_VNMSAC_VV 0xfc00707f #define MATCH_VNMSAC_VX 0xbc006057 #define MASK_VNMSAC_VX 0xfc00707f #define MATCH_VNMSUB_VV 0xac002057 #define MASK_VNMSUB_VV 0xfc00707f #define MATCH_VNMSUB_VX 0xac006057 #define MASK_VNMSUB_VX 0xfc00707f #define MATCH_VNSRA_WI 0xb4003057 #define MASK_VNSRA_WI 0xfc00707f #define MATCH_VNSRA_WV 0xb4000057 #define MASK_VNSRA_WV 0xfc00707f #define MATCH_VNSRA_WX 0xb4004057 #define MASK_VNSRA_WX 0xfc00707f #define MATCH_VNSRL_WI 0xb0003057 #define MASK_VNSRL_WI 0xfc00707f #define MATCH_VNSRL_WV 0xb0000057 #define MASK_VNSRL_WV 0xfc00707f #define MATCH_VNSRL_WX 0xb0004057 #define MASK_VNSRL_WX 0xfc00707f #define MATCH_VOR_VI 0x28003057 #define MASK_VOR_VI 0xfc00707f #define MATCH_VOR_VV 0x28000057 #define MASK_VOR_VV 0xfc00707f #define MATCH_VOR_VX 0x28004057 #define MASK_VOR_VX 0xfc00707f #define MATCH_VREDAND_VS 0x4002057 #define MASK_VREDAND_VS 0xfc00707f #define MATCH_VREDMAX_VS 0x1c002057 #define MASK_VREDMAX_VS 0xfc00707f #define MATCH_VREDMAXU_VS 0x18002057 #define MASK_VREDMAXU_VS 0xfc00707f #define MATCH_VREDMIN_VS 0x14002057 #define MASK_VREDMIN_VS 0xfc00707f #define MATCH_VREDMINU_VS 0x10002057 #define MASK_VREDMINU_VS 0xfc00707f #define MATCH_VREDOR_VS 0x8002057 #define MASK_VREDOR_VS 0xfc00707f #define MATCH_VREDSUM_VS 0x2057 #define MASK_VREDSUM_VS 0xfc00707f #define MATCH_VREDXOR_VS 0xc002057 #define MASK_VREDXOR_VS 0xfc00707f #define MATCH_VREM_VV 0x8c002057 #define MASK_VREM_VV 0xfc00707f #define MATCH_VREM_VX 0x8c006057 #define MASK_VREM_VX 0xfc00707f #define MATCH_VREMU_VV 0x88002057 #define MASK_VREMU_VV 0xfc00707f #define MATCH_VREMU_VX 0x88006057 #define MASK_VREMU_VX 0xfc00707f #define MATCH_VRGATHER_VI 0x30003057 #define MASK_VRGATHER_VI 0xfc00707f #define MATCH_VRGATHER_VV 0x30000057 #define MASK_VRGATHER_VV 0xfc00707f #define MATCH_VRGATHER_VX 0x30004057 #define MASK_VRGATHER_VX 0xfc00707f #define MATCH_VRGATHEREI16_VV 0x38000057 #define MASK_VRGATHEREI16_VV 0xfc00707f #define MATCH_VRSUB_VI 0xc003057 #define MASK_VRSUB_VI 0xfc00707f #define MATCH_VRSUB_VX 0xc004057 #define MASK_VRSUB_VX 0xfc00707f #define MATCH_VS1R_V 0x2800027 #define MASK_VS1R_V 0xfff0707f #define MATCH_VS2R_V 0x22800027 #define MASK_VS2R_V 0xfff0707f #define MATCH_VS4R_V 0x62800027 #define MASK_VS4R_V 0xfff0707f #define MATCH_VS8R_V 0xe2800027 #define MASK_VS8R_V 0xfff0707f #define MATCH_VSADD_VI 0x84003057 #define MASK_VSADD_VI 0xfc00707f #define MATCH_VSADD_VV 0x84000057 #define MASK_VSADD_VV 0xfc00707f #define MATCH_VSADD_VX 0x84004057 #define MASK_VSADD_VX 0xfc00707f #define MATCH_VSADDU_VI 0x80003057 #define MASK_VSADDU_VI 0xfc00707f #define MATCH_VSADDU_VV 0x80000057 #define MASK_VSADDU_VV 0xfc00707f #define MATCH_VSADDU_VX 0x80004057 #define MASK_VSADDU_VX 0xfc00707f #define MATCH_VSBC_VVM 0x48000057 #define MASK_VSBC_VVM 0xfe00707f #define MATCH_VSBC_VXM 0x48004057 #define MASK_VSBC_VXM 0xfe00707f #define MATCH_VSE1024_V 0x10007027 #define MASK_VSE1024_V 0x1df0707f #define MATCH_VSE128_V 0x10000027 #define MASK_VSE128_V 0x1df0707f #define MATCH_VSE16_V 0x5027 #define MASK_VSE16_V 0x1df0707f #define MATCH_VSE256_V 0x10005027 #define MASK_VSE256_V 0x1df0707f #define MATCH_VSE32_V 0x6027 #define MASK_VSE32_V 0x1df0707f #define MATCH_VSE512_V 0x10006027 #define MASK_VSE512_V 0x1df0707f #define MATCH_VSE64_V 0x7027 #define MASK_VSE64_V 0x1df0707f #define MATCH_VSE8_V 0x27 #define MASK_VSE8_V 0x1df0707f #define MATCH_VSETIVLI 0xc0007057 #define MASK_VSETIVLI 0xc000707f #define MATCH_VSETVL 0x80007057 #define MASK_VSETVL 0xfe00707f #define MATCH_VSETVLI 0x7057 #define MASK_VSETVLI 0x8000707f #define MATCH_VSEXT_VF2 0x4803a057 #define MASK_VSEXT_VF2 0xfc0ff07f #define MATCH_VSEXT_VF4 0x4802a057 #define MASK_VSEXT_VF4 0xfc0ff07f #define MATCH_VSEXT_VF8 0x4801a057 #define MASK_VSEXT_VF8 0xfc0ff07f #define MATCH_VSLIDE1DOWN_VX 0x3c006057 #define MASK_VSLIDE1DOWN_VX 0xfc00707f #define MATCH_VSLIDE1UP_VX 0x38006057 #define MASK_VSLIDE1UP_VX 0xfc00707f #define MATCH_VSLIDEDOWN_VI 0x3c003057 #define MASK_VSLIDEDOWN_VI 0xfc00707f #define MATCH_VSLIDEDOWN_VX 0x3c004057 #define MASK_VSLIDEDOWN_VX 0xfc00707f #define MATCH_VSLIDEUP_VI 0x38003057 #define MASK_VSLIDEUP_VI 0xfc00707f #define MATCH_VSLIDEUP_VX 0x38004057 #define MASK_VSLIDEUP_VX 0xfc00707f #define MATCH_VSLL_VI 0x94003057 #define MASK_VSLL_VI 0xfc00707f #define MATCH_VSLL_VV 0x94000057 #define MASK_VSLL_VV 0xfc00707f #define MATCH_VSLL_VX 0x94004057 #define MASK_VSLL_VX 0xfc00707f #define MATCH_VSM_V 0x2b00027 #define MASK_VSM_V 0xfff0707f #define MATCH_VSMUL_VV 0x9c000057 #define MASK_VSMUL_VV 0xfc00707f #define MATCH_VSMUL_VX 0x9c004057 #define MASK_VSMUL_VX 0xfc00707f #define MATCH_VSOXEI1024_V 0x1c007027 #define MASK_VSOXEI1024_V 0x1c00707f #define MATCH_VSOXEI128_V 0x1c000027 #define MASK_VSOXEI128_V 0x1c00707f #define MATCH_VSOXEI16_V 0xc005027 #define MASK_VSOXEI16_V 0x1c00707f #define MATCH_VSOXEI256_V 0x1c005027 #define MASK_VSOXEI256_V 0x1c00707f #define MATCH_VSOXEI32_V 0xc006027 #define MASK_VSOXEI32_V 0x1c00707f #define MATCH_VSOXEI512_V 0x1c006027 #define MASK_VSOXEI512_V 0x1c00707f #define MATCH_VSOXEI64_V 0xc007027 #define MASK_VSOXEI64_V 0x1c00707f #define MATCH_VSOXEI8_V 0xc000027 #define MASK_VSOXEI8_V 0x1c00707f #define MATCH_VSRA_VI 0xa4003057 #define MASK_VSRA_VI 0xfc00707f #define MATCH_VSRA_VV 0xa4000057 #define MASK_VSRA_VV 0xfc00707f #define MATCH_VSRA_VX 0xa4004057 #define MASK_VSRA_VX 0xfc00707f #define MATCH_VSRL_VI 0xa0003057 #define MASK_VSRL_VI 0xfc00707f #define MATCH_VSRL_VV 0xa0000057 #define MASK_VSRL_VV 0xfc00707f #define MATCH_VSRL_VX 0xa0004057 #define MASK_VSRL_VX 0xfc00707f #define MATCH_VSSE1024_V 0x18007027 #define MASK_VSSE1024_V 0x1c00707f #define MATCH_VSSE128_V 0x18000027 #define MASK_VSSE128_V 0x1c00707f #define MATCH_VSSE16_V 0x8005027 #define MASK_VSSE16_V 0x1c00707f #define MATCH_VSSE256_V 0x18005027 #define MASK_VSSE256_V 0x1c00707f #define MATCH_VSSE32_V 0x8006027 #define MASK_VSSE32_V 0x1c00707f #define MATCH_VSSE512_V 0x18006027 #define MASK_VSSE512_V 0x1c00707f #define MATCH_VSSE64_V 0x8007027 #define MASK_VSSE64_V 0x1c00707f #define MATCH_VSSE8_V 0x8000027 #define MASK_VSSE8_V 0x1c00707f #define MATCH_VSSRA_VI 0xac003057 #define MASK_VSSRA_VI 0xfc00707f #define MATCH_VSSRA_VV 0xac000057 #define MASK_VSSRA_VV 0xfc00707f #define MATCH_VSSRA_VX 0xac004057 #define MASK_VSSRA_VX 0xfc00707f #define MATCH_VSSRL_VI 0xa8003057 #define MASK_VSSRL_VI 0xfc00707f #define MATCH_VSSRL_VV 0xa8000057 #define MASK_VSSRL_VV 0xfc00707f #define MATCH_VSSRL_VX 0xa8004057 #define MASK_VSSRL_VX 0xfc00707f #define MATCH_VSSUB_VV 0x8c000057 #define MASK_VSSUB_VV 0xfc00707f #define MATCH_VSSUB_VX 0x8c004057 #define MASK_VSSUB_VX 0xfc00707f #define MATCH_VSSUBU_VV 0x88000057 #define MASK_VSSUBU_VV 0xfc00707f #define MATCH_VSSUBU_VX 0x88004057 #define MASK_VSSUBU_VX 0xfc00707f #define MATCH_VSUB_VV 0x8000057 #define MASK_VSUB_VV 0xfc00707f #define MATCH_VSUB_VX 0x8004057 #define MASK_VSUB_VX 0xfc00707f #define MATCH_VSUXEI1024_V 0x14007027 #define MASK_VSUXEI1024_V 0x1c00707f #define MATCH_VSUXEI128_V 0x14000027 #define MASK_VSUXEI128_V 0x1c00707f #define MATCH_VSUXEI16_V 0x4005027 #define MASK_VSUXEI16_V 0x1c00707f #define MATCH_VSUXEI256_V 0x14005027 #define MASK_VSUXEI256_V 0x1c00707f #define MATCH_VSUXEI32_V 0x4006027 #define MASK_VSUXEI32_V 0x1c00707f #define MATCH_VSUXEI512_V 0x14006027 #define MASK_VSUXEI512_V 0x1c00707f #define MATCH_VSUXEI64_V 0x4007027 #define MASK_VSUXEI64_V 0x1c00707f #define MATCH_VSUXEI8_V 0x4000027 #define MASK_VSUXEI8_V 0x1c00707f #define MATCH_VWADD_VV 0xc4002057 #define MASK_VWADD_VV 0xfc00707f #define MATCH_VWADD_VX 0xc4006057 #define MASK_VWADD_VX 0xfc00707f #define MATCH_VWADD_WV 0xd4002057 #define MASK_VWADD_WV 0xfc00707f #define MATCH_VWADD_WX 0xd4006057 #define MASK_VWADD_WX 0xfc00707f #define MATCH_VWADDU_VV 0xc0002057 #define MASK_VWADDU_VV 0xfc00707f #define MATCH_VWADDU_VX 0xc0006057 #define MASK_VWADDU_VX 0xfc00707f #define MATCH_VWADDU_WV 0xd0002057 #define MASK_VWADDU_WV 0xfc00707f #define MATCH_VWADDU_WX 0xd0006057 #define MASK_VWADDU_WX 0xfc00707f #define MATCH_VWMACC_VV 0xf4002057 #define MASK_VWMACC_VV 0xfc00707f #define MATCH_VWMACC_VX 0xf4006057 #define MASK_VWMACC_VX 0xfc00707f #define MATCH_VWMACCSU_VV 0xfc002057 #define MASK_VWMACCSU_VV 0xfc00707f #define MATCH_VWMACCSU_VX 0xfc006057 #define MASK_VWMACCSU_VX 0xfc00707f #define MATCH_VWMACCU_VV 0xf0002057 #define MASK_VWMACCU_VV 0xfc00707f #define MATCH_VWMACCU_VX 0xf0006057 #define MASK_VWMACCU_VX 0xfc00707f #define MATCH_VWMACCUS_VX 0xf8006057 #define MASK_VWMACCUS_VX 0xfc00707f #define MATCH_VWMUL_VV 0xec002057 #define MASK_VWMUL_VV 0xfc00707f #define MATCH_VWMUL_VX 0xec006057 #define MASK_VWMUL_VX 0xfc00707f #define MATCH_VWMULSU_VV 0xe8002057 #define MASK_VWMULSU_VV 0xfc00707f #define MATCH_VWMULSU_VX 0xe8006057 #define MASK_VWMULSU_VX 0xfc00707f #define MATCH_VWMULU_VV 0xe0002057 #define MASK_VWMULU_VV 0xfc00707f #define MATCH_VWMULU_VX 0xe0006057 #define MASK_VWMULU_VX 0xfc00707f #define MATCH_VWREDSUM_VS 0xc4000057 #define MASK_VWREDSUM_VS 0xfc00707f #define MATCH_VWREDSUMU_VS 0xc0000057 #define MASK_VWREDSUMU_VS 0xfc00707f #define MATCH_VWSUB_VV 0xcc002057 #define MASK_VWSUB_VV 0xfc00707f #define MATCH_VWSUB_VX 0xcc006057 #define MASK_VWSUB_VX 0xfc00707f #define MATCH_VWSUB_WV 0xdc002057 #define MASK_VWSUB_WV 0xfc00707f #define MATCH_VWSUB_WX 0xdc006057 #define MASK_VWSUB_WX 0xfc00707f #define MATCH_VWSUBU_VV 0xc8002057 #define MASK_VWSUBU_VV 0xfc00707f #define MATCH_VWSUBU_VX 0xc8006057 #define MASK_VWSUBU_VX 0xfc00707f #define MATCH_VWSUBU_WV 0xd8002057 #define MASK_VWSUBU_WV 0xfc00707f #define MATCH_VWSUBU_WX 0xd8006057 #define MASK_VWSUBU_WX 0xfc00707f #define MATCH_VXOR_VI 0x2c003057 #define MASK_VXOR_VI 0xfc00707f #define MATCH_VXOR_VV 0x2c000057 #define MASK_VXOR_VV 0xfc00707f #define MATCH_VXOR_VX 0x2c004057 #define MASK_VXOR_VX 0xfc00707f #define MATCH_VZEXT_VF2 0x48032057 #define MASK_VZEXT_VF2 0xfc0ff07f #define MATCH_VZEXT_VF4 0x48022057 #define MASK_VZEXT_VF4 0xfc0ff07f #define MATCH_VZEXT_VF8 0x48012057 #define MASK_VZEXT_VF8 0xfc0ff07f #define MATCH_WEXT 0xce000077 #define MASK_WEXT 0xfe00707f #define MATCH_WEXTI 0xde000077 #define MASK_WEXTI 0xfe00707f #define MATCH_WFI 0x10500073 #define MASK_WFI 0xffffffff #define MATCH_WRS_NTO 0xd00073 #define MASK_WRS_NTO 0xffffffff #define MATCH_WRS_STO 0x1d00073 #define MASK_WRS_STO 0xffffffff #define MATCH_XNOR 0x40004033 #define MASK_XNOR 0xfe00707f #define MATCH_XOR 0x4033 #define MASK_XOR 0xfe00707f #define MATCH_XORI 0x4013 #define MASK_XORI 0x707f #define MATCH_XPERM16 0x28006033 #define MASK_XPERM16 0xfe00707f #define MATCH_XPERM32 0x28000033 #define MASK_XPERM32 0xfe00707f #define MATCH_XPERM4 0x28002033 #define MASK_XPERM4 0xfe00707f #define MATCH_XPERM8 0x28004033 #define MASK_XPERM8 0xfe00707f #define MATCH_ZUNPKD810 0xacc00077 #define MASK_ZUNPKD810 0xfff0707f #define MATCH_ZUNPKD820 0xacd00077 #define MASK_ZUNPKD820 0xfff0707f #define MATCH_ZUNPKD830 0xace00077 #define MASK_ZUNPKD830 0xfff0707f #define MATCH_ZUNPKD831 0xacf00077 #define MASK_ZUNPKD831 0xfff0707f #define MATCH_ZUNPKD832 0xad700077 #define MASK_ZUNPKD832 0xfff0707f #define CSR_FFLAGS 0x1 #define CSR_FRM 0x2 #define CSR_FCSR 0x3 #define CSR_VSTART 0x8 #define CSR_VXSAT 0x9 #define CSR_VXRM 0xa #define CSR_VCSR 0xf #define CSR_SEED 0x15 #define CSR_CYCLE 0xc00 #define CSR_TIME 0xc01 #define CSR_INSTRET 0xc02 #define CSR_HPMCOUNTER3 0xc03 #define CSR_HPMCOUNTER4 0xc04 #define CSR_HPMCOUNTER5 0xc05 #define CSR_HPMCOUNTER6 0xc06 #define CSR_HPMCOUNTER7 0xc07 #define CSR_HPMCOUNTER8 0xc08 #define CSR_HPMCOUNTER9 0xc09 #define CSR_HPMCOUNTER10 0xc0a #define CSR_HPMCOUNTER11 0xc0b #define CSR_HPMCOUNTER12 0xc0c #define CSR_HPMCOUNTER13 0xc0d #define CSR_HPMCOUNTER14 0xc0e #define CSR_HPMCOUNTER15 0xc0f #define CSR_HPMCOUNTER16 0xc10 #define CSR_HPMCOUNTER17 0xc11 #define CSR_HPMCOUNTER18 0xc12 #define CSR_HPMCOUNTER19 0xc13 #define CSR_HPMCOUNTER20 0xc14 #define CSR_HPMCOUNTER21 0xc15 #define CSR_HPMCOUNTER22 0xc16 #define CSR_HPMCOUNTER23 0xc17 #define CSR_HPMCOUNTER24 0xc18 #define CSR_HPMCOUNTER25 0xc19 #define CSR_HPMCOUNTER26 0xc1a #define CSR_HPMCOUNTER27 0xc1b #define CSR_HPMCOUNTER28 0xc1c #define CSR_HPMCOUNTER29 0xc1d #define CSR_HPMCOUNTER30 0xc1e #define CSR_HPMCOUNTER31 0xc1f #define CSR_VL 0xc20 #define CSR_VTYPE 0xc21 #define CSR_VLENB 0xc22 #define CSR_SSTATUS 0x100 #define CSR_SEDELEG 0x102 #define CSR_SIDELEG 0x103 #define CSR_SIE 0x104 #define CSR_STVEC 0x105 #define CSR_SCOUNTEREN 0x106 #define CSR_SENVCFG 0x10a #define CSR_SSTATEEN0 0x10c #define CSR_SSTATEEN1 0x10d #define CSR_SSTATEEN2 0x10e #define CSR_SSTATEEN3 0x10f #define CSR_SSCRATCH 0x140 #define CSR_SEPC 0x141 #define CSR_SCAUSE 0x142 #define CSR_STVAL 0x143 #define CSR_SIP 0x144 #define CSR_STIMECMP 0x14d #define CSR_SATP 0x180 #define CSR_SCONTEXT 0x5a8 #define CSR_VSSTATUS 0x200 #define CSR_VSIE 0x204 #define CSR_VSTVEC 0x205 #define CSR_VSSCRATCH 0x240 #define CSR_VSEPC 0x241 #define CSR_VSCAUSE 0x242 #define CSR_VSTVAL 0x243 #define CSR_VSIP 0x244 #define CSR_VSTIMECMP 0x24d #define CSR_VSATP 0x280 #define CSR_HSTATUS 0x600 #define CSR_HEDELEG 0x602 #define CSR_HIDELEG 0x603 #define CSR_HIE 0x604 #define CSR_HTIMEDELTA 0x605 #define CSR_HCOUNTEREN 0x606 #define CSR_HGEIE 0x607 #define CSR_HENVCFG 0x60a #define CSR_HSTATEEN0 0x60c #define CSR_HSTATEEN1 0x60d #define CSR_HSTATEEN2 0x60e #define CSR_HSTATEEN3 0x60f #define CSR_HTVAL 0x643 #define CSR_HIP 0x644 #define CSR_HVIP 0x645 #define CSR_HTINST 0x64a #define CSR_HGATP 0x680 #define CSR_HCONTEXT 0x6a8 #define CSR_HGEIP 0xe12 #define CSR_SCOUNTOVF 0xda0 #define CSR_UTVT 0x7 #define CSR_UNXTI 0x45 #define CSR_UINTSTATUS 0x46 #define CSR_USCRATCHCSW 0x48 #define CSR_USCRATCHCSWL 0x49 #define CSR_STVT 0x107 #define CSR_SNXTI 0x145 #define CSR_SINTSTATUS 0x146 #define CSR_SSCRATCHCSW 0x148 #define CSR_SSCRATCHCSWL 0x149 #define CSR_MTVT 0x307 #define CSR_MNXTI 0x345 #define CSR_MINTSTATUS 0x346 #define CSR_MSCRATCHCSW 0x348 #define CSR_MSCRATCHCSWL 0x349 #define CSR_MSTATUS 0x300 #define CSR_MISA 0x301 #define CSR_MEDELEG 0x302 #define CSR_MIDELEG 0x303 #define CSR_MIE 0x304 #define CSR_MTVEC 0x305 #define CSR_MCOUNTEREN 0x306 #define CSR_MENVCFG 0x30a #define CSR_MSTATEEN0 0x30c #define CSR_MSTATEEN1 0x30d #define CSR_MSTATEEN2 0x30e #define CSR_MSTATEEN3 0x30f #define CSR_MCOUNTINHIBIT 0x320 #define CSR_MSCRATCH 0x340 #define CSR_MEPC 0x341 #define CSR_MCAUSE 0x342 #define CSR_MTVAL 0x343 #define CSR_MIP 0x344 #define CSR_MTINST 0x34a #define CSR_MTVAL2 0x34b #define CSR_PMPCFG0 0x3a0 #define CSR_PMPCFG1 0x3a1 #define CSR_PMPCFG2 0x3a2 #define CSR_PMPCFG3 0x3a3 #define CSR_PMPCFG4 0x3a4 #define CSR_PMPCFG5 0x3a5 #define CSR_PMPCFG6 0x3a6 #define CSR_PMPCFG7 0x3a7 #define CSR_PMPCFG8 0x3a8 #define CSR_PMPCFG9 0x3a9 #define CSR_PMPCFG10 0x3aa #define CSR_PMPCFG11 0x3ab #define CSR_PMPCFG12 0x3ac #define CSR_PMPCFG13 0x3ad #define CSR_PMPCFG14 0x3ae #define CSR_PMPCFG15 0x3af #define CSR_PMPADDR0 0x3b0 #define CSR_PMPADDR1 0x3b1 #define CSR_PMPADDR2 0x3b2 #define CSR_PMPADDR3 0x3b3 #define CSR_PMPADDR4 0x3b4 #define CSR_PMPADDR5 0x3b5 #define CSR_PMPADDR6 0x3b6 #define CSR_PMPADDR7 0x3b7 #define CSR_PMPADDR8 0x3b8 #define CSR_PMPADDR9 0x3b9 #define CSR_PMPADDR10 0x3ba #define CSR_PMPADDR11 0x3bb #define CSR_PMPADDR12 0x3bc #define CSR_PMPADDR13 0x3bd #define CSR_PMPADDR14 0x3be #define CSR_PMPADDR15 0x3bf #define CSR_PMPADDR16 0x3c0 #define CSR_PMPADDR17 0x3c1 #define CSR_PMPADDR18 0x3c2 #define CSR_PMPADDR19 0x3c3 #define CSR_PMPADDR20 0x3c4 #define CSR_PMPADDR21 0x3c5 #define CSR_PMPADDR22 0x3c6 #define CSR_PMPADDR23 0x3c7 #define CSR_PMPADDR24 0x3c8 #define CSR_PMPADDR25 0x3c9 #define CSR_PMPADDR26 0x3ca #define CSR_PMPADDR27 0x3cb #define CSR_PMPADDR28 0x3cc #define CSR_PMPADDR29 0x3cd #define CSR_PMPADDR30 0x3ce #define CSR_PMPADDR31 0x3cf #define CSR_PMPADDR32 0x3d0 #define CSR_PMPADDR33 0x3d1 #define CSR_PMPADDR34 0x3d2 #define CSR_PMPADDR35 0x3d3 #define CSR_PMPADDR36 0x3d4 #define CSR_PMPADDR37 0x3d5 #define CSR_PMPADDR38 0x3d6 #define CSR_PMPADDR39 0x3d7 #define CSR_PMPADDR40 0x3d8 #define CSR_PMPADDR41 0x3d9 #define CSR_PMPADDR42 0x3da #define CSR_PMPADDR43 0x3db #define CSR_PMPADDR44 0x3dc #define CSR_PMPADDR45 0x3dd #define CSR_PMPADDR46 0x3de #define CSR_PMPADDR47 0x3df #define CSR_PMPADDR48 0x3e0 #define CSR_PMPADDR49 0x3e1 #define CSR_PMPADDR50 0x3e2 #define CSR_PMPADDR51 0x3e3 #define CSR_PMPADDR52 0x3e4 #define CSR_PMPADDR53 0x3e5 #define CSR_PMPADDR54 0x3e6 #define CSR_PMPADDR55 0x3e7 #define CSR_PMPADDR56 0x3e8 #define CSR_PMPADDR57 0x3e9 #define CSR_PMPADDR58 0x3ea #define CSR_PMPADDR59 0x3eb #define CSR_PMPADDR60 0x3ec #define CSR_PMPADDR61 0x3ed #define CSR_PMPADDR62 0x3ee #define CSR_PMPADDR63 0x3ef #define CSR_MSECCFG 0x747 #define CSR_TSELECT 0x7a0 #define CSR_TDATA1 0x7a1 #define CSR_TDATA2 0x7a2 #define CSR_TDATA3 0x7a3 #define CSR_TINFO 0x7a4 #define CSR_TCONTROL 0x7a5 #define CSR_MCONTEXT 0x7a8 #define CSR_MSCONTEXT 0x7aa #define CSR_DCSR 0x7b0 #define CSR_DPC 0x7b1 #define CSR_DSCRATCH0 0x7b2 #define CSR_DSCRATCH1 0x7b3 #define CSR_MCYCLE 0xb00 #define CSR_MINSTRET 0xb02 #define CSR_MHPMCOUNTER3 0xb03 #define CSR_MHPMCOUNTER4 0xb04 #define CSR_MHPMCOUNTER5 0xb05 #define CSR_MHPMCOUNTER6 0xb06 #define CSR_MHPMCOUNTER7 0xb07 #define CSR_MHPMCOUNTER8 0xb08 #define CSR_MHPMCOUNTER9 0xb09 #define CSR_MHPMCOUNTER10 0xb0a #define CSR_MHPMCOUNTER11 0xb0b #define CSR_MHPMCOUNTER12 0xb0c #define CSR_MHPMCOUNTER13 0xb0d #define CSR_MHPMCOUNTER14 0xb0e #define CSR_MHPMCOUNTER15 0xb0f #define CSR_MHPMCOUNTER16 0xb10 #define CSR_MHPMCOUNTER17 0xb11 #define CSR_MHPMCOUNTER18 0xb12 #define CSR_MHPMCOUNTER19 0xb13 #define CSR_MHPMCOUNTER20 0xb14 #define CSR_MHPMCOUNTER21 0xb15 #define CSR_MHPMCOUNTER22 0xb16 #define CSR_MHPMCOUNTER23 0xb17 #define CSR_MHPMCOUNTER24 0xb18 #define CSR_MHPMCOUNTER25 0xb19 #define CSR_MHPMCOUNTER26 0xb1a #define CSR_MHPMCOUNTER27 0xb1b #define CSR_MHPMCOUNTER28 0xb1c #define CSR_MHPMCOUNTER29 0xb1d #define CSR_MHPMCOUNTER30 0xb1e #define CSR_MHPMCOUNTER31 0xb1f #define CSR_MHPMEVENT3 0x323 #define CSR_MHPMEVENT4 0x324 #define CSR_MHPMEVENT5 0x325 #define CSR_MHPMEVENT6 0x326 #define CSR_MHPMEVENT7 0x327 #define CSR_MHPMEVENT8 0x328 #define CSR_MHPMEVENT9 0x329 #define CSR_MHPMEVENT10 0x32a #define CSR_MHPMEVENT11 0x32b #define CSR_MHPMEVENT12 0x32c #define CSR_MHPMEVENT13 0x32d #define CSR_MHPMEVENT14 0x32e #define CSR_MHPMEVENT15 0x32f #define CSR_MHPMEVENT16 0x330 #define CSR_MHPMEVENT17 0x331 #define CSR_MHPMEVENT18 0x332 #define CSR_MHPMEVENT19 0x333 #define CSR_MHPMEVENT20 0x334 #define CSR_MHPMEVENT21 0x335 #define CSR_MHPMEVENT22 0x336 #define CSR_MHPMEVENT23 0x337 #define CSR_MHPMEVENT24 0x338 #define CSR_MHPMEVENT25 0x339 #define CSR_MHPMEVENT26 0x33a #define CSR_MHPMEVENT27 0x33b #define CSR_MHPMEVENT28 0x33c #define CSR_MHPMEVENT29 0x33d #define CSR_MHPMEVENT30 0x33e #define CSR_MHPMEVENT31 0x33f #define CSR_MVENDORID 0xf11 #define CSR_MARCHID 0xf12 #define CSR_MIMPID 0xf13 #define CSR_MHARTID 0xf14 #define CSR_MCONFIGPTR 0xf15 #define CSR_STIMECMPH 0x15d #define CSR_VSTIMECMPH 0x25d #define CSR_HTIMEDELTAH 0x615 #define CSR_HENVCFGH 0x61a #define CSR_HSTATEEN0H 0x61c #define CSR_HSTATEEN1H 0x61d #define CSR_HSTATEEN2H 0x61e #define CSR_HSTATEEN3H 0x61f #define CSR_CYCLEH 0xc80 #define CSR_TIMEH 0xc81 #define CSR_INSTRETH 0xc82 #define CSR_HPMCOUNTER3H 0xc83 #define CSR_HPMCOUNTER4H 0xc84 #define CSR_HPMCOUNTER5H 0xc85 #define CSR_HPMCOUNTER6H 0xc86 #define CSR_HPMCOUNTER7H 0xc87 #define CSR_HPMCOUNTER8H 0xc88 #define CSR_HPMCOUNTER9H 0xc89 #define CSR_HPMCOUNTER10H 0xc8a #define CSR_HPMCOUNTER11H 0xc8b #define CSR_HPMCOUNTER12H 0xc8c #define CSR_HPMCOUNTER13H 0xc8d #define CSR_HPMCOUNTER14H 0xc8e #define CSR_HPMCOUNTER15H 0xc8f #define CSR_HPMCOUNTER16H 0xc90 #define CSR_HPMCOUNTER17H 0xc91 #define CSR_HPMCOUNTER18H 0xc92 #define CSR_HPMCOUNTER19H 0xc93 #define CSR_HPMCOUNTER20H 0xc94 #define CSR_HPMCOUNTER21H 0xc95 #define CSR_HPMCOUNTER22H 0xc96 #define CSR_HPMCOUNTER23H 0xc97 #define CSR_HPMCOUNTER24H 0xc98 #define CSR_HPMCOUNTER25H 0xc99 #define CSR_HPMCOUNTER26H 0xc9a #define CSR_HPMCOUNTER27H 0xc9b #define CSR_HPMCOUNTER28H 0xc9c #define CSR_HPMCOUNTER29H 0xc9d #define CSR_HPMCOUNTER30H 0xc9e #define CSR_HPMCOUNTER31H 0xc9f #define CSR_MSTATUSH 0x310 #define CSR_MENVCFGH 0x31a #define CSR_MSTATEEN0H 0x31c #define CSR_MSTATEEN1H 0x31d #define CSR_MSTATEEN2H 0x31e #define CSR_MSTATEEN3H 0x31f #define CSR_MHPMEVENT3H 0x723 #define CSR_MHPMEVENT4H 0x724 #define CSR_MHPMEVENT5H 0x725 #define CSR_MHPMEVENT6H 0x726 #define CSR_MHPMEVENT7H 0x727 #define CSR_MHPMEVENT8H 0x728 #define CSR_MHPMEVENT9H 0x729 #define CSR_MHPMEVENT10H 0x72a #define CSR_MHPMEVENT11H 0x72b #define CSR_MHPMEVENT12H 0x72c #define CSR_MHPMEVENT13H 0x72d #define CSR_MHPMEVENT14H 0x72e #define CSR_MHPMEVENT15H 0x72f #define CSR_MHPMEVENT16H 0x730 #define CSR_MHPMEVENT17H 0x731 #define CSR_MHPMEVENT18H 0x732 #define CSR_MHPMEVENT19H 0x733 #define CSR_MHPMEVENT20H 0x734 #define CSR_MHPMEVENT21H 0x735 #define CSR_MHPMEVENT22H 0x736 #define CSR_MHPMEVENT23H 0x737 #define CSR_MHPMEVENT24H 0x738 #define CSR_MHPMEVENT25H 0x739 #define CSR_MHPMEVENT26H 0x73a #define CSR_MHPMEVENT27H 0x73b #define CSR_MHPMEVENT28H 0x73c #define CSR_MHPMEVENT29H 0x73d #define CSR_MHPMEVENT30H 0x73e #define CSR_MHPMEVENT31H 0x73f #define CSR_MSECCFGH 0x757 #define CSR_MCYCLEH 0xb80 #define CSR_MINSTRETH 0xb82 #define CSR_MHPMCOUNTER3H 0xb83 #define CSR_MHPMCOUNTER4H 0xb84 #define CSR_MHPMCOUNTER5H 0xb85 #define CSR_MHPMCOUNTER6H 0xb86 #define CSR_MHPMCOUNTER7H 0xb87 #define CSR_MHPMCOUNTER8H 0xb88 #define CSR_MHPMCOUNTER9H 0xb89 #define CSR_MHPMCOUNTER10H 0xb8a #define CSR_MHPMCOUNTER11H 0xb8b #define CSR_MHPMCOUNTER12H 0xb8c #define CSR_MHPMCOUNTER13H 0xb8d #define CSR_MHPMCOUNTER14H 0xb8e #define CSR_MHPMCOUNTER15H 0xb8f #define CSR_MHPMCOUNTER16H 0xb90 #define CSR_MHPMCOUNTER17H 0xb91 #define CSR_MHPMCOUNTER18H 0xb92 #define CSR_MHPMCOUNTER19H 0xb93 #define CSR_MHPMCOUNTER20H 0xb94 #define CSR_MHPMCOUNTER21H 0xb95 #define CSR_MHPMCOUNTER22H 0xb96 #define CSR_MHPMCOUNTER23H 0xb97 #define CSR_MHPMCOUNTER24H 0xb98 #define CSR_MHPMCOUNTER25H 0xb99 #define CSR_MHPMCOUNTER26H 0xb9a #define CSR_MHPMCOUNTER27H 0xb9b #define CSR_MHPMCOUNTER28H 0xb9c #define CSR_MHPMCOUNTER29H 0xb9d #define CSR_MHPMCOUNTER30H 0xb9e #define CSR_MHPMCOUNTER31H 0xb9f #define CAUSE_MISALIGNED_FETCH 0x0 #define CAUSE_FETCH_ACCESS 0x1 #define CAUSE_ILLEGAL_INSTRUCTION 0x2 #define CAUSE_BREAKPOINT 0x3 #define CAUSE_MISALIGNED_LOAD 0x4 #define CAUSE_LOAD_ACCESS 0x5 #define CAUSE_MISALIGNED_STORE 0x6 #define CAUSE_STORE_ACCESS 0x7 #define CAUSE_USER_ECALL 0x8 #define CAUSE_SUPERVISOR_ECALL 0x9 #define CAUSE_VIRTUAL_SUPERVISOR_ECALL 0xa #define CAUSE_MACHINE_ECALL 0xb #define CAUSE_FETCH_PAGE_FAULT 0xc #define CAUSE_LOAD_PAGE_FAULT 0xd #define CAUSE_STORE_PAGE_FAULT 0xf #define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14 #define CAUSE_LOAD_GUEST_PAGE_FAULT 0x15 #define CAUSE_VIRTUAL_INSTRUCTION 0x16 #define CAUSE_STORE_GUEST_PAGE_FAULT 0x17 #define INSN_FIELD_RD 0xf80 #define INSN_FIELD_RT 0xf8000 #define INSN_FIELD_RS1 0xf8000 #define INSN_FIELD_RS2 0x1f00000 #define INSN_FIELD_RS3 0xf8000000 #define INSN_FIELD_AQRL 0x6000000 #define INSN_FIELD_AQ 0x4000000 #define INSN_FIELD_RL 0x2000000 #define INSN_FIELD_FM 0xf0000000 #define INSN_FIELD_PRED 0xf000000 #define INSN_FIELD_SUCC 0xf00000 #define INSN_FIELD_RM 0x7000 #define INSN_FIELD_FUNCT3 0x7000 #define INSN_FIELD_FUNCT2 0x6000000 #define INSN_FIELD_IMM20 0xfffff000 #define INSN_FIELD_JIMM20 0xfffff000 #define INSN_FIELD_IMM12 0xfff00000 #define INSN_FIELD_CSR 0xfff00000 #define INSN_FIELD_IMM12HI 0xfe000000 #define INSN_FIELD_BIMM12HI 0xfe000000 #define INSN_FIELD_IMM12LO 0xf80 #define INSN_FIELD_BIMM12LO 0xf80 #define INSN_FIELD_ZIMM 0xf8000 #define INSN_FIELD_SHAMT 0x7f00000 #define INSN_FIELD_SHAMTW 0x1f00000 #define INSN_FIELD_SHAMTW4 0xf00000 #define INSN_FIELD_SHAMTD 0x3f00000 #define INSN_FIELD_BS 0xc0000000 #define INSN_FIELD_RNUM 0xf00000 #define INSN_FIELD_RC 0x3e000000 #define INSN_FIELD_IMM2 0x300000 #define INSN_FIELD_IMM3 0x700000 #define INSN_FIELD_IMM4 0xf00000 #define INSN_FIELD_IMM5 0x1f00000 #define INSN_FIELD_IMM6 0x3f00000 #define INSN_FIELD_OPCODE 0x7f #define INSN_FIELD_FUNCT7 0xfe000000 #define INSN_FIELD_VD 0xf80 #define INSN_FIELD_VS3 0xf80 #define INSN_FIELD_VS1 0xf8000 #define INSN_FIELD_VS2 0x1f00000 #define INSN_FIELD_VM 0x2000000 #define INSN_FIELD_WD 0x4000000 #define INSN_FIELD_AMOOP 0xf8000000 #define INSN_FIELD_NF 0xe0000000 #define INSN_FIELD_SIMM5 0xf8000 #define INSN_FIELD_ZIMM10 0x3ff00000 #define INSN_FIELD_ZIMM11 0x7ff00000 #define INSN_FIELD_C_NZUIMM10 0x1fe0 #define INSN_FIELD_C_UIMM7LO 0x60 #define INSN_FIELD_C_UIMM7HI 0x1c00 #define INSN_FIELD_C_UIMM8LO 0x60 #define INSN_FIELD_C_UIMM8HI 0x1c00 #define INSN_FIELD_C_UIMM9LO 0x60 #define INSN_FIELD_C_UIMM9HI 0x1c00 #define INSN_FIELD_C_NZIMM6LO 0x7c #define INSN_FIELD_C_NZIMM6HI 0x1000 #define INSN_FIELD_C_IMM6LO 0x7c #define INSN_FIELD_C_IMM6HI 0x1000 #define INSN_FIELD_C_NZIMM10HI 0x1000 #define INSN_FIELD_C_NZIMM10LO 0x7c #define INSN_FIELD_C_NZIMM18HI 0x1000 #define INSN_FIELD_C_NZIMM18LO 0x7c #define INSN_FIELD_C_IMM12 0x1ffc #define INSN_FIELD_C_BIMM9LO 0x7c #define INSN_FIELD_C_BIMM9HI 0x1c00 #define INSN_FIELD_C_NZUIMM5 0x7c #define INSN_FIELD_C_NZUIMM6LO 0x7c #define INSN_FIELD_C_NZUIMM6HI 0x1000 #define INSN_FIELD_C_UIMM8SPLO 0x7c #define INSN_FIELD_C_UIMM8SPHI 0x1000 #define INSN_FIELD_C_UIMM8SP_S 0x1f80 #define INSN_FIELD_C_UIMM10SPLO 0x7c #define INSN_FIELD_C_UIMM10SPHI 0x1000 #define INSN_FIELD_C_UIMM9SPLO 0x7c #define INSN_FIELD_C_UIMM9SPHI 0x1000 #define INSN_FIELD_C_UIMM10SP_S 0x1f80 #define INSN_FIELD_C_UIMM9SP_S 0x1f80 #define INSN_FIELD_RS1_P 0x380 #define INSN_FIELD_RS2_P 0x1c #define INSN_FIELD_RD_P 0x1c #define INSN_FIELD_RD_RS1_N0 0xf80 #define INSN_FIELD_RD_RS1_P 0x380 #define INSN_FIELD_RD_RS1 0xf80 #define INSN_FIELD_RD_N2 0xf80 #define INSN_FIELD_RD_N0 0xf80 #define INSN_FIELD_RS1_N0 0xf80 #define INSN_FIELD_C_RS2_N0 0x7c #define INSN_FIELD_C_RS1_N0 0xf80 #define INSN_FIELD_C_RS2 0x7c #endif #ifdef DECLARE_INSN DECLARE_INSN(add, MATCH_ADD, MASK_ADD) DECLARE_INSN(add16, MATCH_ADD16, MASK_ADD16) DECLARE_INSN(add32, MATCH_ADD32, MASK_ADD32) DECLARE_INSN(add64, MATCH_ADD64, MASK_ADD64) DECLARE_INSN(add8, MATCH_ADD8, MASK_ADD8) DECLARE_INSN(add_uw, MATCH_ADD_UW, MASK_ADD_UW) DECLARE_INSN(addd, MATCH_ADDD, MASK_ADDD) DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) DECLARE_INSN(addid, MATCH_ADDID, MASK_ADDID) DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) DECLARE_INSN(aes32dsi, MATCH_AES32DSI, MASK_AES32DSI) DECLARE_INSN(aes32dsmi, MATCH_AES32DSMI, MASK_AES32DSMI) DECLARE_INSN(aes32esi, MATCH_AES32ESI, MASK_AES32ESI) DECLARE_INSN(aes32esmi, MATCH_AES32ESMI, MASK_AES32ESMI) DECLARE_INSN(aes64ds, MATCH_AES64DS, MASK_AES64DS) DECLARE_INSN(aes64dsm, MATCH_AES64DSM, MASK_AES64DSM) DECLARE_INSN(aes64es, MATCH_AES64ES, MASK_AES64ES) DECLARE_INSN(aes64esm, MATCH_AES64ESM, MASK_AES64ESM) DECLARE_INSN(aes64im, MATCH_AES64IM, MASK_AES64IM) DECLARE_INSN(aes64ks1i, MATCH_AES64KS1I, MASK_AES64KS1I) DECLARE_INSN(aes64ks2, MATCH_AES64KS2, MASK_AES64KS2) DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) DECLARE_INSN(and, MATCH_AND, MASK_AND) DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) DECLARE_INSN(andn, MATCH_ANDN, MASK_ANDN) DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) DECLARE_INSN(ave, MATCH_AVE, MASK_AVE) DECLARE_INSN(bclr, MATCH_BCLR, MASK_BCLR) DECLARE_INSN(bclri, MATCH_BCLRI, MASK_BCLRI) DECLARE_INSN(bcompress, MATCH_BCOMPRESS, MASK_BCOMPRESS) DECLARE_INSN(bcompressw, MATCH_BCOMPRESSW, MASK_BCOMPRESSW) DECLARE_INSN(bdecompress, MATCH_BDECOMPRESS, MASK_BDECOMPRESS) DECLARE_INSN(bdecompressw, MATCH_BDECOMPRESSW, MASK_BDECOMPRESSW) DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) DECLARE_INSN(bext, MATCH_BEXT, MASK_BEXT) DECLARE_INSN(bexti, MATCH_BEXTI, MASK_BEXTI) DECLARE_INSN(bfp, MATCH_BFP, MASK_BFP) DECLARE_INSN(bfpw, MATCH_BFPW, MASK_BFPW) DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) DECLARE_INSN(binv, MATCH_BINV, MASK_BINV) DECLARE_INSN(binvi, MATCH_BINVI, MASK_BINVI) DECLARE_INSN(bitrev, MATCH_BITREV, MASK_BITREV) DECLARE_INSN(bitrevi, MATCH_BITREVI, MASK_BITREVI) DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) DECLARE_INSN(bmatflip, MATCH_BMATFLIP, MASK_BMATFLIP) DECLARE_INSN(bmator, MATCH_BMATOR, MASK_BMATOR) DECLARE_INSN(bmatxor, MATCH_BMATXOR, MASK_BMATXOR) DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) DECLARE_INSN(bpick, MATCH_BPICK, MASK_BPICK) DECLARE_INSN(bset, MATCH_BSET, MASK_BSET) DECLARE_INSN(bseti, MATCH_BSETI, MASK_BSETI) DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) DECLARE_INSN(c_lq, MATCH_C_LQ, MASK_C_LQ) DECLARE_INSN(c_lqsp, MATCH_C_LQSP, MASK_C_LQSP) DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) DECLARE_INSN(c_sq, MATCH_C_SQ, MASK_C_SQ) DECLARE_INSN(c_sqsp, MATCH_C_SQSP, MASK_C_SQSP) DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) DECLARE_INSN(cbo_clean, MATCH_CBO_CLEAN, MASK_CBO_CLEAN) DECLARE_INSN(cbo_flush, MATCH_CBO_FLUSH, MASK_CBO_FLUSH) DECLARE_INSN(cbo_inval, MATCH_CBO_INVAL, MASK_CBO_INVAL) DECLARE_INSN(cbo_zero, MATCH_CBO_ZERO, MASK_CBO_ZERO) DECLARE_INSN(clmul, MATCH_CLMUL, MASK_CLMUL) DECLARE_INSN(clmulh, MATCH_CLMULH, MASK_CLMULH) DECLARE_INSN(clmulr, MATCH_CLMULR, MASK_CLMULR) DECLARE_INSN(clo16, MATCH_CLO16, MASK_CLO16) DECLARE_INSN(clo32, MATCH_CLO32, MASK_CLO32) DECLARE_INSN(clo8, MATCH_CLO8, MASK_CLO8) DECLARE_INSN(clrs16, MATCH_CLRS16, MASK_CLRS16) DECLARE_INSN(clrs32, MATCH_CLRS32, MASK_CLRS32) DECLARE_INSN(clrs8, MATCH_CLRS8, MASK_CLRS8) DECLARE_INSN(clz, MATCH_CLZ, MASK_CLZ) DECLARE_INSN(clz16, MATCH_CLZ16, MASK_CLZ16) DECLARE_INSN(clz32, MATCH_CLZ32, MASK_CLZ32) DECLARE_INSN(clz8, MATCH_CLZ8, MASK_CLZ8) DECLARE_INSN(clzw, MATCH_CLZW, MASK_CLZW) DECLARE_INSN(cmix, MATCH_CMIX, MASK_CMIX) DECLARE_INSN(cmov, MATCH_CMOV, MASK_CMOV) DECLARE_INSN(cmpeq16, MATCH_CMPEQ16, MASK_CMPEQ16) DECLARE_INSN(cmpeq8, MATCH_CMPEQ8, MASK_CMPEQ8) DECLARE_INSN(cpop, MATCH_CPOP, MASK_CPOP) DECLARE_INSN(cpopw, MATCH_CPOPW, MASK_CPOPW) DECLARE_INSN(cras16, MATCH_CRAS16, MASK_CRAS16) DECLARE_INSN(cras32, MATCH_CRAS32, MASK_CRAS32) DECLARE_INSN(crc32_b, MATCH_CRC32_B, MASK_CRC32_B) DECLARE_INSN(crc32_d, MATCH_CRC32_D, MASK_CRC32_D) DECLARE_INSN(crc32_h, MATCH_CRC32_H, MASK_CRC32_H) DECLARE_INSN(crc32_w, MATCH_CRC32_W, MASK_CRC32_W) DECLARE_INSN(crc32c_b, MATCH_CRC32C_B, MASK_CRC32C_B) DECLARE_INSN(crc32c_d, MATCH_CRC32C_D, MASK_CRC32C_D) DECLARE_INSN(crc32c_h, MATCH_CRC32C_H, MASK_CRC32C_H) DECLARE_INSN(crc32c_w, MATCH_CRC32C_W, MASK_CRC32C_W) DECLARE_INSN(crsa16, MATCH_CRSA16, MASK_CRSA16) DECLARE_INSN(crsa32, MATCH_CRSA32, MASK_CRSA32) DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) DECLARE_INSN(ctz, MATCH_CTZ, MASK_CTZ) DECLARE_INSN(ctzw, MATCH_CTZW, MASK_CTZW) DECLARE_INSN(div, MATCH_DIV, MASK_DIV) DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) DECLARE_INSN(fadd_h, MATCH_FADD_H, MASK_FADD_H) DECLARE_INSN(fadd_q, MATCH_FADD_Q, MASK_FADD_Q) DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) DECLARE_INSN(fclass_h, MATCH_FCLASS_H, MASK_FCLASS_H) DECLARE_INSN(fclass_q, MATCH_FCLASS_Q, MASK_FCLASS_Q) DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) DECLARE_INSN(fcvt_d_h, MATCH_FCVT_D_H, MASK_FCVT_D_H) DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) DECLARE_INSN(fcvt_d_q, MATCH_FCVT_D_Q, MASK_FCVT_D_Q) DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) DECLARE_INSN(fcvt_h_d, MATCH_FCVT_H_D, MASK_FCVT_H_D) DECLARE_INSN(fcvt_h_l, MATCH_FCVT_H_L, MASK_FCVT_H_L) DECLARE_INSN(fcvt_h_lu, MATCH_FCVT_H_LU, MASK_FCVT_H_LU) DECLARE_INSN(fcvt_h_q, MATCH_FCVT_H_Q, MASK_FCVT_H_Q) DECLARE_INSN(fcvt_h_s, MATCH_FCVT_H_S, MASK_FCVT_H_S) DECLARE_INSN(fcvt_h_w, MATCH_FCVT_H_W, MASK_FCVT_H_W) DECLARE_INSN(fcvt_h_wu, MATCH_FCVT_H_WU, MASK_FCVT_H_WU) DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) DECLARE_INSN(fcvt_l_h, MATCH_FCVT_L_H, MASK_FCVT_L_H) DECLARE_INSN(fcvt_l_q, MATCH_FCVT_L_Q, MASK_FCVT_L_Q) DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) DECLARE_INSN(fcvt_lu_h, MATCH_FCVT_LU_H, MASK_FCVT_LU_H) DECLARE_INSN(fcvt_lu_q, MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q) DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) DECLARE_INSN(fcvt_q_d, MATCH_FCVT_Q_D, MASK_FCVT_Q_D) DECLARE_INSN(fcvt_q_h, MATCH_FCVT_Q_H, MASK_FCVT_Q_H) DECLARE_INSN(fcvt_q_l, MATCH_FCVT_Q_L, MASK_FCVT_Q_L) DECLARE_INSN(fcvt_q_lu, MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU) DECLARE_INSN(fcvt_q_s, MATCH_FCVT_Q_S, MASK_FCVT_Q_S) DECLARE_INSN(fcvt_q_w, MATCH_FCVT_Q_W, MASK_FCVT_Q_W) DECLARE_INSN(fcvt_q_wu, MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU) DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) DECLARE_INSN(fcvt_s_h, MATCH_FCVT_S_H, MASK_FCVT_S_H) DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) DECLARE_INSN(fcvt_s_q, MATCH_FCVT_S_Q, MASK_FCVT_S_Q) DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) DECLARE_INSN(fcvt_w_h, MATCH_FCVT_W_H, MASK_FCVT_W_H) DECLARE_INSN(fcvt_w_q, MATCH_FCVT_W_Q, MASK_FCVT_W_Q) DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) DECLARE_INSN(fcvt_wu_h, MATCH_FCVT_WU_H, MASK_FCVT_WU_H) DECLARE_INSN(fcvt_wu_q, MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q) DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) DECLARE_INSN(fdiv_h, MATCH_FDIV_H, MASK_FDIV_H) DECLARE_INSN(fdiv_q, MATCH_FDIV_Q, MASK_FDIV_Q) DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) DECLARE_INSN(feq_h, MATCH_FEQ_H, MASK_FEQ_H) DECLARE_INSN(feq_q, MATCH_FEQ_Q, MASK_FEQ_Q) DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) DECLARE_INSN(fle_h, MATCH_FLE_H, MASK_FLE_H) DECLARE_INSN(fle_q, MATCH_FLE_Q, MASK_FLE_Q) DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) DECLARE_INSN(flh, MATCH_FLH, MASK_FLH) DECLARE_INSN(flq, MATCH_FLQ, MASK_FLQ) DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) DECLARE_INSN(flt_h, MATCH_FLT_H, MASK_FLT_H) DECLARE_INSN(flt_q, MATCH_FLT_Q, MASK_FLT_Q) DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) DECLARE_INSN(fmadd_h, MATCH_FMADD_H, MASK_FMADD_H) DECLARE_INSN(fmadd_q, MATCH_FMADD_Q, MASK_FMADD_Q) DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) DECLARE_INSN(fmax_h, MATCH_FMAX_H, MASK_FMAX_H) DECLARE_INSN(fmax_q, MATCH_FMAX_Q, MASK_FMAX_Q) DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) DECLARE_INSN(fmin_h, MATCH_FMIN_H, MASK_FMIN_H) DECLARE_INSN(fmin_q, MATCH_FMIN_Q, MASK_FMIN_Q) DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) DECLARE_INSN(fmsub_h, MATCH_FMSUB_H, MASK_FMSUB_H) DECLARE_INSN(fmsub_q, MATCH_FMSUB_Q, MASK_FMSUB_Q) DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) DECLARE_INSN(fmul_h, MATCH_FMUL_H, MASK_FMUL_H) DECLARE_INSN(fmul_q, MATCH_FMUL_Q, MASK_FMUL_Q) DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) DECLARE_INSN(fmv_h_x, MATCH_FMV_H_X, MASK_FMV_H_X) DECLARE_INSN(fmv_w_x, MATCH_FMV_W_X, MASK_FMV_W_X) DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) DECLARE_INSN(fmv_x_h, MATCH_FMV_X_H, MASK_FMV_X_H) DECLARE_INSN(fmv_x_w, MATCH_FMV_X_W, MASK_FMV_X_W) DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) DECLARE_INSN(fnmadd_h, MATCH_FNMADD_H, MASK_FNMADD_H) DECLARE_INSN(fnmadd_q, MATCH_FNMADD_Q, MASK_FNMADD_Q) DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) DECLARE_INSN(fnmsub_h, MATCH_FNMSUB_H, MASK_FNMSUB_H) DECLARE_INSN(fnmsub_q, MATCH_FNMSUB_Q, MASK_FNMSUB_Q) DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) DECLARE_INSN(fsgnj_h, MATCH_FSGNJ_H, MASK_FSGNJ_H) DECLARE_INSN(fsgnj_q, MATCH_FSGNJ_Q, MASK_FSGNJ_Q) DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) DECLARE_INSN(fsgnjn_h, MATCH_FSGNJN_H, MASK_FSGNJN_H) DECLARE_INSN(fsgnjn_q, MATCH_FSGNJN_Q, MASK_FSGNJN_Q) DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) DECLARE_INSN(fsgnjx_h, MATCH_FSGNJX_H, MASK_FSGNJX_H) DECLARE_INSN(fsgnjx_q, MATCH_FSGNJX_Q, MASK_FSGNJX_Q) DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) DECLARE_INSN(fsh, MATCH_FSH, MASK_FSH) DECLARE_INSN(fsl, MATCH_FSL, MASK_FSL) DECLARE_INSN(fslw, MATCH_FSLW, MASK_FSLW) DECLARE_INSN(fsq, MATCH_FSQ, MASK_FSQ) DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) DECLARE_INSN(fsqrt_h, MATCH_FSQRT_H, MASK_FSQRT_H) DECLARE_INSN(fsqrt_q, MATCH_FSQRT_Q, MASK_FSQRT_Q) DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) DECLARE_INSN(fsr, MATCH_FSR, MASK_FSR) DECLARE_INSN(fsri, MATCH_FSRI, MASK_FSRI) DECLARE_INSN(fsriw, MATCH_FSRIW, MASK_FSRIW) DECLARE_INSN(fsrw, MATCH_FSRW, MASK_FSRW) DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) DECLARE_INSN(fsub_h, MATCH_FSUB_H, MASK_FSUB_H) DECLARE_INSN(fsub_q, MATCH_FSUB_Q, MASK_FSUB_Q) DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) DECLARE_INSN(gorc, MATCH_GORC, MASK_GORC) DECLARE_INSN(gorci, MATCH_GORCI, MASK_GORCI) DECLARE_INSN(gorciw, MATCH_GORCIW, MASK_GORCIW) DECLARE_INSN(gorcw, MATCH_GORCW, MASK_GORCW) DECLARE_INSN(grev, MATCH_GREV, MASK_GREV) DECLARE_INSN(grevi, MATCH_GREVI, MASK_GREVI) DECLARE_INSN(greviw, MATCH_GREVIW, MASK_GREVIW) DECLARE_INSN(grevw, MATCH_GREVW, MASK_GREVW) DECLARE_INSN(hfence_gvma, MATCH_HFENCE_GVMA, MASK_HFENCE_GVMA) DECLARE_INSN(hfence_vvma, MATCH_HFENCE_VVMA, MASK_HFENCE_VVMA) DECLARE_INSN(hinval_gvma, MATCH_HINVAL_GVMA, MASK_HINVAL_GVMA) DECLARE_INSN(hinval_vvma, MATCH_HINVAL_VVMA, MASK_HINVAL_VVMA) DECLARE_INSN(hlv_b, MATCH_HLV_B, MASK_HLV_B) DECLARE_INSN(hlv_bu, MATCH_HLV_BU, MASK_HLV_BU) DECLARE_INSN(hlv_d, MATCH_HLV_D, MASK_HLV_D) DECLARE_INSN(hlv_h, MATCH_HLV_H, MASK_HLV_H) DECLARE_INSN(hlv_hu, MATCH_HLV_HU, MASK_HLV_HU) DECLARE_INSN(hlv_w, MATCH_HLV_W, MASK_HLV_W) DECLARE_INSN(hlv_wu, MATCH_HLV_WU, MASK_HLV_WU) DECLARE_INSN(hlvx_hu, MATCH_HLVX_HU, MASK_HLVX_HU) DECLARE_INSN(hlvx_wu, MATCH_HLVX_WU, MASK_HLVX_WU) DECLARE_INSN(hsv_b, MATCH_HSV_B, MASK_HSV_B) DECLARE_INSN(hsv_d, MATCH_HSV_D, MASK_HSV_D) DECLARE_INSN(hsv_h, MATCH_HSV_H, MASK_HSV_H) DECLARE_INSN(hsv_w, MATCH_HSV_W, MASK_HSV_W) DECLARE_INSN(insb, MATCH_INSB, MASK_INSB) DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) DECLARE_INSN(kabs16, MATCH_KABS16, MASK_KABS16) DECLARE_INSN(kabs32, MATCH_KABS32, MASK_KABS32) DECLARE_INSN(kabs8, MATCH_KABS8, MASK_KABS8) DECLARE_INSN(kabsw, MATCH_KABSW, MASK_KABSW) DECLARE_INSN(kadd16, MATCH_KADD16, MASK_KADD16) DECLARE_INSN(kadd32, MATCH_KADD32, MASK_KADD32) DECLARE_INSN(kadd64, MATCH_KADD64, MASK_KADD64) DECLARE_INSN(kadd8, MATCH_KADD8, MASK_KADD8) DECLARE_INSN(kaddh, MATCH_KADDH, MASK_KADDH) DECLARE_INSN(kaddw, MATCH_KADDW, MASK_KADDW) DECLARE_INSN(kcras16, MATCH_KCRAS16, MASK_KCRAS16) DECLARE_INSN(kcras32, MATCH_KCRAS32, MASK_KCRAS32) DECLARE_INSN(kcrsa16, MATCH_KCRSA16, MASK_KCRSA16) DECLARE_INSN(kcrsa32, MATCH_KCRSA32, MASK_KCRSA32) DECLARE_INSN(kdmabb, MATCH_KDMABB, MASK_KDMABB) DECLARE_INSN(kdmabb16, MATCH_KDMABB16, MASK_KDMABB16) DECLARE_INSN(kdmabt, MATCH_KDMABT, MASK_KDMABT) DECLARE_INSN(kdmabt16, MATCH_KDMABT16, MASK_KDMABT16) DECLARE_INSN(kdmatt, MATCH_KDMATT, MASK_KDMATT) DECLARE_INSN(kdmatt16, MATCH_KDMATT16, MASK_KDMATT16) DECLARE_INSN(kdmbb, MATCH_KDMBB, MASK_KDMBB) DECLARE_INSN(kdmbb16, MATCH_KDMBB16, MASK_KDMBB16) DECLARE_INSN(kdmbt, MATCH_KDMBT, MASK_KDMBT) DECLARE_INSN(kdmbt16, MATCH_KDMBT16, MASK_KDMBT16) DECLARE_INSN(kdmtt, MATCH_KDMTT, MASK_KDMTT) DECLARE_INSN(kdmtt16, MATCH_KDMTT16, MASK_KDMTT16) DECLARE_INSN(khm16, MATCH_KHM16, MASK_KHM16) DECLARE_INSN(khm8, MATCH_KHM8, MASK_KHM8) DECLARE_INSN(khmbb, MATCH_KHMBB, MASK_KHMBB) DECLARE_INSN(khmbb16, MATCH_KHMBB16, MASK_KHMBB16) DECLARE_INSN(khmbt, MATCH_KHMBT, MASK_KHMBT) DECLARE_INSN(khmbt16, MATCH_KHMBT16, MASK_KHMBT16) DECLARE_INSN(khmtt, MATCH_KHMTT, MASK_KHMTT) DECLARE_INSN(khmtt16, MATCH_KHMTT16, MASK_KHMTT16) DECLARE_INSN(khmx16, MATCH_KHMX16, MASK_KHMX16) DECLARE_INSN(khmx8, MATCH_KHMX8, MASK_KHMX8) DECLARE_INSN(kmabb, MATCH_KMABB, MASK_KMABB) DECLARE_INSN(kmabb32, MATCH_KMABB32, MASK_KMABB32) DECLARE_INSN(kmabt, MATCH_KMABT, MASK_KMABT) DECLARE_INSN(kmabt32, MATCH_KMABT32, MASK_KMABT32) DECLARE_INSN(kmada, MATCH_KMADA, MASK_KMADA) DECLARE_INSN(kmadrs, MATCH_KMADRS, MASK_KMADRS) DECLARE_INSN(kmadrs32, MATCH_KMADRS32, MASK_KMADRS32) DECLARE_INSN(kmads, MATCH_KMADS, MASK_KMADS) DECLARE_INSN(kmads32, MATCH_KMADS32, MASK_KMADS32) DECLARE_INSN(kmar64, MATCH_KMAR64, MASK_KMAR64) DECLARE_INSN(kmatt, MATCH_KMATT, MASK_KMATT) DECLARE_INSN(kmatt32, MATCH_KMATT32, MASK_KMATT32) DECLARE_INSN(kmaxda, MATCH_KMAXDA, MASK_KMAXDA) DECLARE_INSN(kmaxda32, MATCH_KMAXDA32, MASK_KMAXDA32) DECLARE_INSN(kmaxds, MATCH_KMAXDS, MASK_KMAXDS) DECLARE_INSN(kmaxds32, MATCH_KMAXDS32, MASK_KMAXDS32) DECLARE_INSN(kmda, MATCH_KMDA, MASK_KMDA) DECLARE_INSN(kmda32, MATCH_KMDA32, MASK_KMDA32) DECLARE_INSN(kmmac, MATCH_KMMAC, MASK_KMMAC) DECLARE_INSN(kmmac_u, MATCH_KMMAC_U, MASK_KMMAC_U) DECLARE_INSN(kmmawb, MATCH_KMMAWB, MASK_KMMAWB) DECLARE_INSN(kmmawb2, MATCH_KMMAWB2, MASK_KMMAWB2) DECLARE_INSN(kmmawb2_u, MATCH_KMMAWB2_U, MASK_KMMAWB2_U) DECLARE_INSN(kmmawb_u, MATCH_KMMAWB_U, MASK_KMMAWB_U) DECLARE_INSN(kmmawt, MATCH_KMMAWT, MASK_KMMAWT) DECLARE_INSN(kmmawt2, MATCH_KMMAWT2, MASK_KMMAWT2) DECLARE_INSN(kmmawt2_u, MATCH_KMMAWT2_U, MASK_KMMAWT2_U) DECLARE_INSN(kmmawt_u, MATCH_KMMAWT_U, MASK_KMMAWT_U) DECLARE_INSN(kmmsb, MATCH_KMMSB, MASK_KMMSB) DECLARE_INSN(kmmsb_u, MATCH_KMMSB_U, MASK_KMMSB_U) DECLARE_INSN(kmmwb2, MATCH_KMMWB2, MASK_KMMWB2) DECLARE_INSN(kmmwb2_u, MATCH_KMMWB2_U, MASK_KMMWB2_U) DECLARE_INSN(kmmwt2, MATCH_KMMWT2, MASK_KMMWT2) DECLARE_INSN(kmmwt2_u, MATCH_KMMWT2_U, MASK_KMMWT2_U) DECLARE_INSN(kmsda, MATCH_KMSDA, MASK_KMSDA) DECLARE_INSN(kmsda32, MATCH_KMSDA32, MASK_KMSDA32) DECLARE_INSN(kmsr64, MATCH_KMSR64, MASK_KMSR64) DECLARE_INSN(kmsxda, MATCH_KMSXDA, MASK_KMSXDA) DECLARE_INSN(kmsxda32, MATCH_KMSXDA32, MASK_KMSXDA32) DECLARE_INSN(kmxda, MATCH_KMXDA, MASK_KMXDA) DECLARE_INSN(kmxda32, MATCH_KMXDA32, MASK_KMXDA32) DECLARE_INSN(ksll16, MATCH_KSLL16, MASK_KSLL16) DECLARE_INSN(ksll32, MATCH_KSLL32, MASK_KSLL32) DECLARE_INSN(ksll8, MATCH_KSLL8, MASK_KSLL8) DECLARE_INSN(kslli16, MATCH_KSLLI16, MASK_KSLLI16) DECLARE_INSN(kslli32, MATCH_KSLLI32, MASK_KSLLI32) DECLARE_INSN(kslli8, MATCH_KSLLI8, MASK_KSLLI8) DECLARE_INSN(kslliw, MATCH_KSLLIW, MASK_KSLLIW) DECLARE_INSN(ksllw, MATCH_KSLLW, MASK_KSLLW) DECLARE_INSN(kslra16, MATCH_KSLRA16, MASK_KSLRA16) DECLARE_INSN(kslra16_u, MATCH_KSLRA16_U, MASK_KSLRA16_U) DECLARE_INSN(kslra32, MATCH_KSLRA32, MASK_KSLRA32) DECLARE_INSN(kslra32_u, MATCH_KSLRA32_U, MASK_KSLRA32_U) DECLARE_INSN(kslra8, MATCH_KSLRA8, MASK_KSLRA8) DECLARE_INSN(kslra8_u, MATCH_KSLRA8_U, MASK_KSLRA8_U) DECLARE_INSN(kslraw, MATCH_KSLRAW, MASK_KSLRAW) DECLARE_INSN(kslraw_u, MATCH_KSLRAW_U, MASK_KSLRAW_U) DECLARE_INSN(kstas16, MATCH_KSTAS16, MASK_KSTAS16) DECLARE_INSN(kstas32, MATCH_KSTAS32, MASK_KSTAS32) DECLARE_INSN(kstsa16, MATCH_KSTSA16, MASK_KSTSA16) DECLARE_INSN(kstsa32, MATCH_KSTSA32, MASK_KSTSA32) DECLARE_INSN(ksub16, MATCH_KSUB16, MASK_KSUB16) DECLARE_INSN(ksub32, MATCH_KSUB32, MASK_KSUB32) DECLARE_INSN(ksub64, MATCH_KSUB64, MASK_KSUB64) DECLARE_INSN(ksub8, MATCH_KSUB8, MASK_KSUB8) DECLARE_INSN(ksubh, MATCH_KSUBH, MASK_KSUBH) DECLARE_INSN(ksubw, MATCH_KSUBW, MASK_KSUBW) DECLARE_INSN(kwmmul, MATCH_KWMMUL, MASK_KWMMUL) DECLARE_INSN(kwmmul_u, MATCH_KWMMUL_U, MASK_KWMMUL_U) DECLARE_INSN(lb, MATCH_LB, MASK_LB) DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) DECLARE_INSN(ld, MATCH_LD, MASK_LD) DECLARE_INSN(ldu, MATCH_LDU, MASK_LDU) DECLARE_INSN(lh, MATCH_LH, MASK_LH) DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) DECLARE_INSN(lq, MATCH_LQ, MASK_LQ) DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) DECLARE_INSN(lw, MATCH_LW, MASK_LW) DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) DECLARE_INSN(maddr32, MATCH_MADDR32, MASK_MADDR32) DECLARE_INSN(max, MATCH_MAX, MASK_MAX) DECLARE_INSN(maxu, MATCH_MAXU, MASK_MAXU) DECLARE_INSN(maxw, MATCH_MAXW, MASK_MAXW) DECLARE_INSN(min, MATCH_MIN, MASK_MIN) DECLARE_INSN(minu, MATCH_MINU, MASK_MINU) DECLARE_INSN(minw, MATCH_MINW, MASK_MINW) DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) DECLARE_INSN(msubr32, MATCH_MSUBR32, MASK_MSUBR32) DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) DECLARE_INSN(mulr64, MATCH_MULR64, MASK_MULR64) DECLARE_INSN(mulsr64, MATCH_MULSR64, MASK_MULSR64) DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) DECLARE_INSN(or, MATCH_OR, MASK_OR) DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) DECLARE_INSN(orn, MATCH_ORN, MASK_ORN) DECLARE_INSN(pack, MATCH_PACK, MASK_PACK) DECLARE_INSN(packh, MATCH_PACKH, MASK_PACKH) DECLARE_INSN(packu, MATCH_PACKU, MASK_PACKU) DECLARE_INSN(packuw, MATCH_PACKUW, MASK_PACKUW) DECLARE_INSN(packw, MATCH_PACKW, MASK_PACKW) DECLARE_INSN(pause, MATCH_PAUSE, MASK_PAUSE) DECLARE_INSN(pbsad, MATCH_PBSAD, MASK_PBSAD) DECLARE_INSN(pbsada, MATCH_PBSADA, MASK_PBSADA) DECLARE_INSN(pkbb16, MATCH_PKBB16, MASK_PKBB16) DECLARE_INSN(pkbb32, MATCH_PKBB32, MASK_PKBB32) DECLARE_INSN(pkbt16, MATCH_PKBT16, MASK_PKBT16) DECLARE_INSN(pkbt32, MATCH_PKBT32, MASK_PKBT32) DECLARE_INSN(pktb16, MATCH_PKTB16, MASK_PKTB16) DECLARE_INSN(pktb32, MATCH_PKTB32, MASK_PKTB32) DECLARE_INSN(pktt16, MATCH_PKTT16, MASK_PKTT16) DECLARE_INSN(pktt32, MATCH_PKTT32, MASK_PKTT32) DECLARE_INSN(prefetch_i, MATCH_PREFETCH_I, MASK_PREFETCH_I) DECLARE_INSN(prefetch_r, MATCH_PREFETCH_R, MASK_PREFETCH_R) DECLARE_INSN(prefetch_w, MATCH_PREFETCH_W, MASK_PREFETCH_W) DECLARE_INSN(radd16, MATCH_RADD16, MASK_RADD16) DECLARE_INSN(radd32, MATCH_RADD32, MASK_RADD32) DECLARE_INSN(radd64, MATCH_RADD64, MASK_RADD64) DECLARE_INSN(radd8, MATCH_RADD8, MASK_RADD8) DECLARE_INSN(raddw, MATCH_RADDW, MASK_RADDW) DECLARE_INSN(rcras16, MATCH_RCRAS16, MASK_RCRAS16) DECLARE_INSN(rcras32, MATCH_RCRAS32, MASK_RCRAS32) DECLARE_INSN(rcrsa16, MATCH_RCRSA16, MASK_RCRSA16) DECLARE_INSN(rcrsa32, MATCH_RCRSA32, MASK_RCRSA32) DECLARE_INSN(rem, MATCH_REM, MASK_REM) DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) DECLARE_INSN(rol, MATCH_ROL, MASK_ROL) DECLARE_INSN(rolw, MATCH_ROLW, MASK_ROLW) DECLARE_INSN(ror, MATCH_ROR, MASK_ROR) DECLARE_INSN(rori, MATCH_RORI, MASK_RORI) DECLARE_INSN(roriw, MATCH_RORIW, MASK_RORIW) DECLARE_INSN(rorw, MATCH_RORW, MASK_RORW) DECLARE_INSN(rstas16, MATCH_RSTAS16, MASK_RSTAS16) DECLARE_INSN(rstas32, MATCH_RSTAS32, MASK_RSTAS32) DECLARE_INSN(rstsa16, MATCH_RSTSA16, MASK_RSTSA16) DECLARE_INSN(rstsa32, MATCH_RSTSA32, MASK_RSTSA32) DECLARE_INSN(rsub16, MATCH_RSUB16, MASK_RSUB16) DECLARE_INSN(rsub32, MATCH_RSUB32, MASK_RSUB32) DECLARE_INSN(rsub64, MATCH_RSUB64, MASK_RSUB64) DECLARE_INSN(rsub8, MATCH_RSUB8, MASK_RSUB8) DECLARE_INSN(rsubw, MATCH_RSUBW, MASK_RSUBW) DECLARE_INSN(sb, MATCH_SB, MASK_SB) DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) DECLARE_INSN(sclip16, MATCH_SCLIP16, MASK_SCLIP16) DECLARE_INSN(sclip32, MATCH_SCLIP32, MASK_SCLIP32) DECLARE_INSN(sclip8, MATCH_SCLIP8, MASK_SCLIP8) DECLARE_INSN(scmple16, MATCH_SCMPLE16, MASK_SCMPLE16) DECLARE_INSN(scmple8, MATCH_SCMPLE8, MASK_SCMPLE8) DECLARE_INSN(scmplt16, MATCH_SCMPLT16, MASK_SCMPLT16) DECLARE_INSN(scmplt8, MATCH_SCMPLT8, MASK_SCMPLT8) DECLARE_INSN(sd, MATCH_SD, MASK_SD) DECLARE_INSN(sext_b, MATCH_SEXT_B, MASK_SEXT_B) DECLARE_INSN(sext_h, MATCH_SEXT_H, MASK_SEXT_H) DECLARE_INSN(sfence_inval_ir, MATCH_SFENCE_INVAL_IR, MASK_SFENCE_INVAL_IR) DECLARE_INSN(sfence_vma, MATCH_SFENCE_VMA, MASK_SFENCE_VMA) DECLARE_INSN(sfence_w_inval, MATCH_SFENCE_W_INVAL, MASK_SFENCE_W_INVAL) DECLARE_INSN(sh, MATCH_SH, MASK_SH) DECLARE_INSN(sh1add, MATCH_SH1ADD, MASK_SH1ADD) DECLARE_INSN(sh1add_uw, MATCH_SH1ADD_UW, MASK_SH1ADD_UW) DECLARE_INSN(sh2add, MATCH_SH2ADD, MASK_SH2ADD) DECLARE_INSN(sh2add_uw, MATCH_SH2ADD_UW, MASK_SH2ADD_UW) DECLARE_INSN(sh3add, MATCH_SH3ADD, MASK_SH3ADD) DECLARE_INSN(sh3add_uw, MATCH_SH3ADD_UW, MASK_SH3ADD_UW) DECLARE_INSN(sha256sig0, MATCH_SHA256SIG0, MASK_SHA256SIG0) DECLARE_INSN(sha256sig1, MATCH_SHA256SIG1, MASK_SHA256SIG1) DECLARE_INSN(sha256sum0, MATCH_SHA256SUM0, MASK_SHA256SUM0) DECLARE_INSN(sha256sum1, MATCH_SHA256SUM1, MASK_SHA256SUM1) DECLARE_INSN(sha512sig0, MATCH_SHA512SIG0, MASK_SHA512SIG0) DECLARE_INSN(sha512sig0h, MATCH_SHA512SIG0H, MASK_SHA512SIG0H) DECLARE_INSN(sha512sig0l, MATCH_SHA512SIG0L, MASK_SHA512SIG0L) DECLARE_INSN(sha512sig1, MATCH_SHA512SIG1, MASK_SHA512SIG1) DECLARE_INSN(sha512sig1h, MATCH_SHA512SIG1H, MASK_SHA512SIG1H) DECLARE_INSN(sha512sig1l, MATCH_SHA512SIG1L, MASK_SHA512SIG1L) DECLARE_INSN(sha512sum0, MATCH_SHA512SUM0, MASK_SHA512SUM0) DECLARE_INSN(sha512sum0r, MATCH_SHA512SUM0R, MASK_SHA512SUM0R) DECLARE_INSN(sha512sum1, MATCH_SHA512SUM1, MASK_SHA512SUM1) DECLARE_INSN(sha512sum1r, MATCH_SHA512SUM1R, MASK_SHA512SUM1R) DECLARE_INSN(shfl, MATCH_SHFL, MASK_SHFL) DECLARE_INSN(shfli, MATCH_SHFLI, MASK_SHFLI) DECLARE_INSN(shflw, MATCH_SHFLW, MASK_SHFLW) DECLARE_INSN(sinval_vma, MATCH_SINVAL_VMA, MASK_SINVAL_VMA) DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) DECLARE_INSN(sll16, MATCH_SLL16, MASK_SLL16) DECLARE_INSN(sll32, MATCH_SLL32, MASK_SLL32) DECLARE_INSN(sll8, MATCH_SLL8, MASK_SLL8) DECLARE_INSN(slld, MATCH_SLLD, MASK_SLLD) DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) DECLARE_INSN(slli16, MATCH_SLLI16, MASK_SLLI16) DECLARE_INSN(slli32, MATCH_SLLI32, MASK_SLLI32) DECLARE_INSN(slli8, MATCH_SLLI8, MASK_SLLI8) DECLARE_INSN(slli_uw, MATCH_SLLI_UW, MASK_SLLI_UW) DECLARE_INSN(sllid, MATCH_SLLID, MASK_SLLID) DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) DECLARE_INSN(slo, MATCH_SLO, MASK_SLO) DECLARE_INSN(sloi, MATCH_SLOI, MASK_SLOI) DECLARE_INSN(sloiw, MATCH_SLOIW, MASK_SLOIW) DECLARE_INSN(slow, MATCH_SLOW, MASK_SLOW) DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) DECLARE_INSN(sm3p0, MATCH_SM3P0, MASK_SM3P0) DECLARE_INSN(sm3p1, MATCH_SM3P1, MASK_SM3P1) DECLARE_INSN(sm4ed, MATCH_SM4ED, MASK_SM4ED) DECLARE_INSN(sm4ks, MATCH_SM4KS, MASK_SM4KS) DECLARE_INSN(smal, MATCH_SMAL, MASK_SMAL) DECLARE_INSN(smalbb, MATCH_SMALBB, MASK_SMALBB) DECLARE_INSN(smalbt, MATCH_SMALBT, MASK_SMALBT) DECLARE_INSN(smalda, MATCH_SMALDA, MASK_SMALDA) DECLARE_INSN(smaldrs, MATCH_SMALDRS, MASK_SMALDRS) DECLARE_INSN(smalds, MATCH_SMALDS, MASK_SMALDS) DECLARE_INSN(smaltt, MATCH_SMALTT, MASK_SMALTT) DECLARE_INSN(smalxda, MATCH_SMALXDA, MASK_SMALXDA) DECLARE_INSN(smalxds, MATCH_SMALXDS, MASK_SMALXDS) DECLARE_INSN(smaqa, MATCH_SMAQA, MASK_SMAQA) DECLARE_INSN(smaqa_su, MATCH_SMAQA_SU, MASK_SMAQA_SU) DECLARE_INSN(smar64, MATCH_SMAR64, MASK_SMAR64) DECLARE_INSN(smax16, MATCH_SMAX16, MASK_SMAX16) DECLARE_INSN(smax32, MATCH_SMAX32, MASK_SMAX32) DECLARE_INSN(smax8, MATCH_SMAX8, MASK_SMAX8) DECLARE_INSN(smbb16, MATCH_SMBB16, MASK_SMBB16) DECLARE_INSN(smbt16, MATCH_SMBT16, MASK_SMBT16) DECLARE_INSN(smbt32, MATCH_SMBT32, MASK_SMBT32) DECLARE_INSN(smdrs, MATCH_SMDRS, MASK_SMDRS) DECLARE_INSN(smdrs32, MATCH_SMDRS32, MASK_SMDRS32) DECLARE_INSN(smds, MATCH_SMDS, MASK_SMDS) DECLARE_INSN(smds32, MATCH_SMDS32, MASK_SMDS32) DECLARE_INSN(smin16, MATCH_SMIN16, MASK_SMIN16) DECLARE_INSN(smin32, MATCH_SMIN32, MASK_SMIN32) DECLARE_INSN(smin8, MATCH_SMIN8, MASK_SMIN8) DECLARE_INSN(smmul, MATCH_SMMUL, MASK_SMMUL) DECLARE_INSN(smmul_u, MATCH_SMMUL_U, MASK_SMMUL_U) DECLARE_INSN(smmwb, MATCH_SMMWB, MASK_SMMWB) DECLARE_INSN(smmwb_u, MATCH_SMMWB_U, MASK_SMMWB_U) DECLARE_INSN(smmwt, MATCH_SMMWT, MASK_SMMWT) DECLARE_INSN(smmwt_u, MATCH_SMMWT_U, MASK_SMMWT_U) DECLARE_INSN(smslda, MATCH_SMSLDA, MASK_SMSLDA) DECLARE_INSN(smslxda, MATCH_SMSLXDA, MASK_SMSLXDA) DECLARE_INSN(smsr64, MATCH_SMSR64, MASK_SMSR64) DECLARE_INSN(smtt16, MATCH_SMTT16, MASK_SMTT16) DECLARE_INSN(smtt32, MATCH_SMTT32, MASK_SMTT32) DECLARE_INSN(smul16, MATCH_SMUL16, MASK_SMUL16) DECLARE_INSN(smul8, MATCH_SMUL8, MASK_SMUL8) DECLARE_INSN(smulx16, MATCH_SMULX16, MASK_SMULX16) DECLARE_INSN(smulx8, MATCH_SMULX8, MASK_SMULX8) DECLARE_INSN(smxds, MATCH_SMXDS, MASK_SMXDS) DECLARE_INSN(smxds32, MATCH_SMXDS32, MASK_SMXDS32) DECLARE_INSN(sq, MATCH_SQ, MASK_SQ) DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) DECLARE_INSN(sra16, MATCH_SRA16, MASK_SRA16) DECLARE_INSN(sra16_u, MATCH_SRA16_U, MASK_SRA16_U) DECLARE_INSN(sra32, MATCH_SRA32, MASK_SRA32) DECLARE_INSN(sra32_u, MATCH_SRA32_U, MASK_SRA32_U) DECLARE_INSN(sra8, MATCH_SRA8, MASK_SRA8) DECLARE_INSN(sra8_u, MATCH_SRA8_U, MASK_SRA8_U) DECLARE_INSN(sra_u, MATCH_SRA_U, MASK_SRA_U) DECLARE_INSN(srad, MATCH_SRAD, MASK_SRAD) DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) DECLARE_INSN(srai16, MATCH_SRAI16, MASK_SRAI16) DECLARE_INSN(srai16_u, MATCH_SRAI16_U, MASK_SRAI16_U) DECLARE_INSN(srai32, MATCH_SRAI32, MASK_SRAI32) DECLARE_INSN(srai32_u, MATCH_SRAI32_U, MASK_SRAI32_U) DECLARE_INSN(srai8, MATCH_SRAI8, MASK_SRAI8) DECLARE_INSN(srai8_u, MATCH_SRAI8_U, MASK_SRAI8_U) DECLARE_INSN(srai_u, MATCH_SRAI_U, MASK_SRAI_U) DECLARE_INSN(sraid, MATCH_SRAID, MASK_SRAID) DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) DECLARE_INSN(sraiw_u, MATCH_SRAIW_U, MASK_SRAIW_U) DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) DECLARE_INSN(srl16, MATCH_SRL16, MASK_SRL16) DECLARE_INSN(srl16_u, MATCH_SRL16_U, MASK_SRL16_U) DECLARE_INSN(srl32, MATCH_SRL32, MASK_SRL32) DECLARE_INSN(srl32_u, MATCH_SRL32_U, MASK_SRL32_U) DECLARE_INSN(srl8, MATCH_SRL8, MASK_SRL8) DECLARE_INSN(srl8_u, MATCH_SRL8_U, MASK_SRL8_U) DECLARE_INSN(srld, MATCH_SRLD, MASK_SRLD) DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) DECLARE_INSN(srli16, MATCH_SRLI16, MASK_SRLI16) DECLARE_INSN(srli16_u, MATCH_SRLI16_U, MASK_SRLI16_U) DECLARE_INSN(srli32, MATCH_SRLI32, MASK_SRLI32) DECLARE_INSN(srli32_u, MATCH_SRLI32_U, MASK_SRLI32_U) DECLARE_INSN(srli8, MATCH_SRLI8, MASK_SRLI8) DECLARE_INSN(srli8_u, MATCH_SRLI8_U, MASK_SRLI8_U) DECLARE_INSN(srlid, MATCH_SRLID, MASK_SRLID) DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) DECLARE_INSN(sro, MATCH_SRO, MASK_SRO) DECLARE_INSN(sroi, MATCH_SROI, MASK_SROI) DECLARE_INSN(sroiw, MATCH_SROIW, MASK_SROIW) DECLARE_INSN(srow, MATCH_SROW, MASK_SROW) DECLARE_INSN(stas16, MATCH_STAS16, MASK_STAS16) DECLARE_INSN(stas32, MATCH_STAS32, MASK_STAS32) DECLARE_INSN(stsa16, MATCH_STSA16, MASK_STSA16) DECLARE_INSN(stsa32, MATCH_STSA32, MASK_STSA32) DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) DECLARE_INSN(sub16, MATCH_SUB16, MASK_SUB16) DECLARE_INSN(sub32, MATCH_SUB32, MASK_SUB32) DECLARE_INSN(sub64, MATCH_SUB64, MASK_SUB64) DECLARE_INSN(sub8, MATCH_SUB8, MASK_SUB8) DECLARE_INSN(subd, MATCH_SUBD, MASK_SUBD) DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) DECLARE_INSN(sunpkd810, MATCH_SUNPKD810, MASK_SUNPKD810) DECLARE_INSN(sunpkd820, MATCH_SUNPKD820, MASK_SUNPKD820) DECLARE_INSN(sunpkd830, MATCH_SUNPKD830, MASK_SUNPKD830) DECLARE_INSN(sunpkd831, MATCH_SUNPKD831, MASK_SUNPKD831) DECLARE_INSN(sunpkd832, MATCH_SUNPKD832, MASK_SUNPKD832) DECLARE_INSN(sw, MATCH_SW, MASK_SW) DECLARE_INSN(swap8, MATCH_SWAP8, MASK_SWAP8) DECLARE_INSN(uclip16, MATCH_UCLIP16, MASK_UCLIP16) DECLARE_INSN(uclip32, MATCH_UCLIP32, MASK_UCLIP32) DECLARE_INSN(uclip8, MATCH_UCLIP8, MASK_UCLIP8) DECLARE_INSN(ucmple16, MATCH_UCMPLE16, MASK_UCMPLE16) DECLARE_INSN(ucmple8, MATCH_UCMPLE8, MASK_UCMPLE8) DECLARE_INSN(ucmplt16, MATCH_UCMPLT16, MASK_UCMPLT16) DECLARE_INSN(ucmplt8, MATCH_UCMPLT8, MASK_UCMPLT8) DECLARE_INSN(ukadd16, MATCH_UKADD16, MASK_UKADD16) DECLARE_INSN(ukadd32, MATCH_UKADD32, MASK_UKADD32) DECLARE_INSN(ukadd64, MATCH_UKADD64, MASK_UKADD64) DECLARE_INSN(ukadd8, MATCH_UKADD8, MASK_UKADD8) DECLARE_INSN(ukaddh, MATCH_UKADDH, MASK_UKADDH) DECLARE_INSN(ukaddw, MATCH_UKADDW, MASK_UKADDW) DECLARE_INSN(ukcras16, MATCH_UKCRAS16, MASK_UKCRAS16) DECLARE_INSN(ukcras32, MATCH_UKCRAS32, MASK_UKCRAS32) DECLARE_INSN(ukcrsa16, MATCH_UKCRSA16, MASK_UKCRSA16) DECLARE_INSN(ukcrsa32, MATCH_UKCRSA32, MASK_UKCRSA32) DECLARE_INSN(ukmar64, MATCH_UKMAR64, MASK_UKMAR64) DECLARE_INSN(ukmsr64, MATCH_UKMSR64, MASK_UKMSR64) DECLARE_INSN(ukstas16, MATCH_UKSTAS16, MASK_UKSTAS16) DECLARE_INSN(ukstas32, MATCH_UKSTAS32, MASK_UKSTAS32) DECLARE_INSN(ukstsa16, MATCH_UKSTSA16, MASK_UKSTSA16) DECLARE_INSN(ukstsa32, MATCH_UKSTSA32, MASK_UKSTSA32) DECLARE_INSN(uksub16, MATCH_UKSUB16, MASK_UKSUB16) DECLARE_INSN(uksub32, MATCH_UKSUB32, MASK_UKSUB32) DECLARE_INSN(uksub64, MATCH_UKSUB64, MASK_UKSUB64) DECLARE_INSN(uksub8, MATCH_UKSUB8, MASK_UKSUB8) DECLARE_INSN(uksubh, MATCH_UKSUBH, MASK_UKSUBH) DECLARE_INSN(uksubw, MATCH_UKSUBW, MASK_UKSUBW) DECLARE_INSN(umaqa, MATCH_UMAQA, MASK_UMAQA) DECLARE_INSN(umar64, MATCH_UMAR64, MASK_UMAR64) DECLARE_INSN(umax16, MATCH_UMAX16, MASK_UMAX16) DECLARE_INSN(umax32, MATCH_UMAX32, MASK_UMAX32) DECLARE_INSN(umax8, MATCH_UMAX8, MASK_UMAX8) DECLARE_INSN(umin16, MATCH_UMIN16, MASK_UMIN16) DECLARE_INSN(umin32, MATCH_UMIN32, MASK_UMIN32) DECLARE_INSN(umin8, MATCH_UMIN8, MASK_UMIN8) DECLARE_INSN(umsr64, MATCH_UMSR64, MASK_UMSR64) DECLARE_INSN(umul16, MATCH_UMUL16, MASK_UMUL16) DECLARE_INSN(umul8, MATCH_UMUL8, MASK_UMUL8) DECLARE_INSN(umulx16, MATCH_UMULX16, MASK_UMULX16) DECLARE_INSN(umulx8, MATCH_UMULX8, MASK_UMULX8) DECLARE_INSN(unshfl, MATCH_UNSHFL, MASK_UNSHFL) DECLARE_INSN(unshfli, MATCH_UNSHFLI, MASK_UNSHFLI) DECLARE_INSN(unshflw, MATCH_UNSHFLW, MASK_UNSHFLW) DECLARE_INSN(uradd16, MATCH_URADD16, MASK_URADD16) DECLARE_INSN(uradd32, MATCH_URADD32, MASK_URADD32) DECLARE_INSN(uradd64, MATCH_URADD64, MASK_URADD64) DECLARE_INSN(uradd8, MATCH_URADD8, MASK_URADD8) DECLARE_INSN(uraddw, MATCH_URADDW, MASK_URADDW) DECLARE_INSN(urcras16, MATCH_URCRAS16, MASK_URCRAS16) DECLARE_INSN(urcras32, MATCH_URCRAS32, MASK_URCRAS32) DECLARE_INSN(urcrsa16, MATCH_URCRSA16, MASK_URCRSA16) DECLARE_INSN(urcrsa32, MATCH_URCRSA32, MASK_URCRSA32) DECLARE_INSN(urstas16, MATCH_URSTAS16, MASK_URSTAS16) DECLARE_INSN(urstas32, MATCH_URSTAS32, MASK_URSTAS32) DECLARE_INSN(urstsa16, MATCH_URSTSA16, MASK_URSTSA16) DECLARE_INSN(urstsa32, MATCH_URSTSA32, MASK_URSTSA32) DECLARE_INSN(ursub16, MATCH_URSUB16, MASK_URSUB16) DECLARE_INSN(ursub32, MATCH_URSUB32, MASK_URSUB32) DECLARE_INSN(ursub64, MATCH_URSUB64, MASK_URSUB64) DECLARE_INSN(ursub8, MATCH_URSUB8, MASK_URSUB8) DECLARE_INSN(ursubw, MATCH_URSUBW, MASK_URSUBW) DECLARE_INSN(vaadd_vv, MATCH_VAADD_VV, MASK_VAADD_VV) DECLARE_INSN(vaadd_vx, MATCH_VAADD_VX, MASK_VAADD_VX) DECLARE_INSN(vaaddu_vv, MATCH_VAADDU_VV, MASK_VAADDU_VV) DECLARE_INSN(vaaddu_vx, MATCH_VAADDU_VX, MASK_VAADDU_VX) DECLARE_INSN(vadc_vim, MATCH_VADC_VIM, MASK_VADC_VIM) DECLARE_INSN(vadc_vvm, MATCH_VADC_VVM, MASK_VADC_VVM) DECLARE_INSN(vadc_vxm, MATCH_VADC_VXM, MASK_VADC_VXM) DECLARE_INSN(vadd_vi, MATCH_VADD_VI, MASK_VADD_VI) DECLARE_INSN(vadd_vv, MATCH_VADD_VV, MASK_VADD_VV) DECLARE_INSN(vadd_vx, MATCH_VADD_VX, MASK_VADD_VX) DECLARE_INSN(vamoaddei16_v, MATCH_VAMOADDEI16_V, MASK_VAMOADDEI16_V) DECLARE_INSN(vamoaddei32_v, MATCH_VAMOADDEI32_V, MASK_VAMOADDEI32_V) DECLARE_INSN(vamoaddei64_v, MATCH_VAMOADDEI64_V, MASK_VAMOADDEI64_V) DECLARE_INSN(vamoaddei8_v, MATCH_VAMOADDEI8_V, MASK_VAMOADDEI8_V) DECLARE_INSN(vamoandei16_v, MATCH_VAMOANDEI16_V, MASK_VAMOANDEI16_V) DECLARE_INSN(vamoandei32_v, MATCH_VAMOANDEI32_V, MASK_VAMOANDEI32_V) DECLARE_INSN(vamoandei64_v, MATCH_VAMOANDEI64_V, MASK_VAMOANDEI64_V) DECLARE_INSN(vamoandei8_v, MATCH_VAMOANDEI8_V, MASK_VAMOANDEI8_V) DECLARE_INSN(vamomaxei16_v, MATCH_VAMOMAXEI16_V, MASK_VAMOMAXEI16_V) DECLARE_INSN(vamomaxei32_v, MATCH_VAMOMAXEI32_V, MASK_VAMOMAXEI32_V) DECLARE_INSN(vamomaxei64_v, MATCH_VAMOMAXEI64_V, MASK_VAMOMAXEI64_V) DECLARE_INSN(vamomaxei8_v, MATCH_VAMOMAXEI8_V, MASK_VAMOMAXEI8_V) DECLARE_INSN(vamomaxuei16_v, MATCH_VAMOMAXUEI16_V, MASK_VAMOMAXUEI16_V) DECLARE_INSN(vamomaxuei32_v, MATCH_VAMOMAXUEI32_V, MASK_VAMOMAXUEI32_V) DECLARE_INSN(vamomaxuei64_v, MATCH_VAMOMAXUEI64_V, MASK_VAMOMAXUEI64_V) DECLARE_INSN(vamomaxuei8_v, MATCH_VAMOMAXUEI8_V, MASK_VAMOMAXUEI8_V) DECLARE_INSN(vamominei16_v, MATCH_VAMOMINEI16_V, MASK_VAMOMINEI16_V) DECLARE_INSN(vamominei32_v, MATCH_VAMOMINEI32_V, MASK_VAMOMINEI32_V) DECLARE_INSN(vamominei64_v, MATCH_VAMOMINEI64_V, MASK_VAMOMINEI64_V) DECLARE_INSN(vamominei8_v, MATCH_VAMOMINEI8_V, MASK_VAMOMINEI8_V) DECLARE_INSN(vamominuei16_v, MATCH_VAMOMINUEI16_V, MASK_VAMOMINUEI16_V) DECLARE_INSN(vamominuei32_v, MATCH_VAMOMINUEI32_V, MASK_VAMOMINUEI32_V) DECLARE_INSN(vamominuei64_v, MATCH_VAMOMINUEI64_V, MASK_VAMOMINUEI64_V) DECLARE_INSN(vamominuei8_v, MATCH_VAMOMINUEI8_V, MASK_VAMOMINUEI8_V) DECLARE_INSN(vamoorei16_v, MATCH_VAMOOREI16_V, MASK_VAMOOREI16_V) DECLARE_INSN(vamoorei32_v, MATCH_VAMOOREI32_V, MASK_VAMOOREI32_V) DECLARE_INSN(vamoorei64_v, MATCH_VAMOOREI64_V, MASK_VAMOOREI64_V) DECLARE_INSN(vamoorei8_v, MATCH_VAMOOREI8_V, MASK_VAMOOREI8_V) DECLARE_INSN(vamoswapei16_v, MATCH_VAMOSWAPEI16_V, MASK_VAMOSWAPEI16_V) DECLARE_INSN(vamoswapei32_v, MATCH_VAMOSWAPEI32_V, MASK_VAMOSWAPEI32_V) DECLARE_INSN(vamoswapei64_v, MATCH_VAMOSWAPEI64_V, MASK_VAMOSWAPEI64_V) DECLARE_INSN(vamoswapei8_v, MATCH_VAMOSWAPEI8_V, MASK_VAMOSWAPEI8_V) DECLARE_INSN(vamoxorei16_v, MATCH_VAMOXOREI16_V, MASK_VAMOXOREI16_V) DECLARE_INSN(vamoxorei32_v, MATCH_VAMOXOREI32_V, MASK_VAMOXOREI32_V) DECLARE_INSN(vamoxorei64_v, MATCH_VAMOXOREI64_V, MASK_VAMOXOREI64_V) DECLARE_INSN(vamoxorei8_v, MATCH_VAMOXOREI8_V, MASK_VAMOXOREI8_V) DECLARE_INSN(vand_vi, MATCH_VAND_VI, MASK_VAND_VI) DECLARE_INSN(vand_vv, MATCH_VAND_VV, MASK_VAND_VV) DECLARE_INSN(vand_vx, MATCH_VAND_VX, MASK_VAND_VX) DECLARE_INSN(vasub_vv, MATCH_VASUB_VV, MASK_VASUB_VV) DECLARE_INSN(vasub_vx, MATCH_VASUB_VX, MASK_VASUB_VX) DECLARE_INSN(vasubu_vv, MATCH_VASUBU_VV, MASK_VASUBU_VV) DECLARE_INSN(vasubu_vx, MATCH_VASUBU_VX, MASK_VASUBU_VX) DECLARE_INSN(vcompress_vm, MATCH_VCOMPRESS_VM, MASK_VCOMPRESS_VM) DECLARE_INSN(vcpop_m, MATCH_VCPOP_M, MASK_VCPOP_M) DECLARE_INSN(vdiv_vv, MATCH_VDIV_VV, MASK_VDIV_VV) DECLARE_INSN(vdiv_vx, MATCH_VDIV_VX, MASK_VDIV_VX) DECLARE_INSN(vdivu_vv, MATCH_VDIVU_VV, MASK_VDIVU_VV) DECLARE_INSN(vdivu_vx, MATCH_VDIVU_VX, MASK_VDIVU_VX) DECLARE_INSN(vfadd_vf, MATCH_VFADD_VF, MASK_VFADD_VF) DECLARE_INSN(vfadd_vv, MATCH_VFADD_VV, MASK_VFADD_VV) DECLARE_INSN(vfclass_v, MATCH_VFCLASS_V, MASK_VFCLASS_V) DECLARE_INSN(vfcvt_f_x_v, MATCH_VFCVT_F_X_V, MASK_VFCVT_F_X_V) DECLARE_INSN(vfcvt_f_xu_v, MATCH_VFCVT_F_XU_V, MASK_VFCVT_F_XU_V) DECLARE_INSN(vfcvt_rtz_x_f_v, MATCH_VFCVT_RTZ_X_F_V, MASK_VFCVT_RTZ_X_F_V) DECLARE_INSN(vfcvt_rtz_xu_f_v, MATCH_VFCVT_RTZ_XU_F_V, MASK_VFCVT_RTZ_XU_F_V) DECLARE_INSN(vfcvt_x_f_v, MATCH_VFCVT_X_F_V, MASK_VFCVT_X_F_V) DECLARE_INSN(vfcvt_xu_f_v, MATCH_VFCVT_XU_F_V, MASK_VFCVT_XU_F_V) DECLARE_INSN(vfdiv_vf, MATCH_VFDIV_VF, MASK_VFDIV_VF) DECLARE_INSN(vfdiv_vv, MATCH_VFDIV_VV, MASK_VFDIV_VV) DECLARE_INSN(vfirst_m, MATCH_VFIRST_M, MASK_VFIRST_M) DECLARE_INSN(vfmacc_vf, MATCH_VFMACC_VF, MASK_VFMACC_VF) DECLARE_INSN(vfmacc_vv, MATCH_VFMACC_VV, MASK_VFMACC_VV) DECLARE_INSN(vfmadd_vf, MATCH_VFMADD_VF, MASK_VFMADD_VF) DECLARE_INSN(vfmadd_vv, MATCH_VFMADD_VV, MASK_VFMADD_VV) DECLARE_INSN(vfmax_vf, MATCH_VFMAX_VF, MASK_VFMAX_VF) DECLARE_INSN(vfmax_vv, MATCH_VFMAX_VV, MASK_VFMAX_VV) DECLARE_INSN(vfmerge_vfm, MATCH_VFMERGE_VFM, MASK_VFMERGE_VFM) DECLARE_INSN(vfmin_vf, MATCH_VFMIN_VF, MASK_VFMIN_VF) DECLARE_INSN(vfmin_vv, MATCH_VFMIN_VV, MASK_VFMIN_VV) DECLARE_INSN(vfmsac_vf, MATCH_VFMSAC_VF, MASK_VFMSAC_VF) DECLARE_INSN(vfmsac_vv, MATCH_VFMSAC_VV, MASK_VFMSAC_VV) DECLARE_INSN(vfmsub_vf, MATCH_VFMSUB_VF, MASK_VFMSUB_VF) DECLARE_INSN(vfmsub_vv, MATCH_VFMSUB_VV, MASK_VFMSUB_VV) DECLARE_INSN(vfmul_vf, MATCH_VFMUL_VF, MASK_VFMUL_VF) DECLARE_INSN(vfmul_vv, MATCH_VFMUL_VV, MASK_VFMUL_VV) DECLARE_INSN(vfmv_f_s, MATCH_VFMV_F_S, MASK_VFMV_F_S) DECLARE_INSN(vfmv_s_f, MATCH_VFMV_S_F, MASK_VFMV_S_F) DECLARE_INSN(vfmv_v_f, MATCH_VFMV_V_F, MASK_VFMV_V_F) DECLARE_INSN(vfncvt_f_f_w, MATCH_VFNCVT_F_F_W, MASK_VFNCVT_F_F_W) DECLARE_INSN(vfncvt_f_x_w, MATCH_VFNCVT_F_X_W, MASK_VFNCVT_F_X_W) DECLARE_INSN(vfncvt_f_xu_w, MATCH_VFNCVT_F_XU_W, MASK_VFNCVT_F_XU_W) DECLARE_INSN(vfncvt_rod_f_f_w, MATCH_VFNCVT_ROD_F_F_W, MASK_VFNCVT_ROD_F_F_W) DECLARE_INSN(vfncvt_rtz_x_f_w, MATCH_VFNCVT_RTZ_X_F_W, MASK_VFNCVT_RTZ_X_F_W) DECLARE_INSN(vfncvt_rtz_xu_f_w, MATCH_VFNCVT_RTZ_XU_F_W, MASK_VFNCVT_RTZ_XU_F_W) DECLARE_INSN(vfncvt_x_f_w, MATCH_VFNCVT_X_F_W, MASK_VFNCVT_X_F_W) DECLARE_INSN(vfncvt_xu_f_w, MATCH_VFNCVT_XU_F_W, MASK_VFNCVT_XU_F_W) DECLARE_INSN(vfnmacc_vf, MATCH_VFNMACC_VF, MASK_VFNMACC_VF) DECLARE_INSN(vfnmacc_vv, MATCH_VFNMACC_VV, MASK_VFNMACC_VV) DECLARE_INSN(vfnmadd_vf, MATCH_VFNMADD_VF, MASK_VFNMADD_VF) DECLARE_INSN(vfnmadd_vv, MATCH_VFNMADD_VV, MASK_VFNMADD_VV) DECLARE_INSN(vfnmsac_vf, MATCH_VFNMSAC_VF, MASK_VFNMSAC_VF) DECLARE_INSN(vfnmsac_vv, MATCH_VFNMSAC_VV, MASK_VFNMSAC_VV) DECLARE_INSN(vfnmsub_vf, MATCH_VFNMSUB_VF, MASK_VFNMSUB_VF) DECLARE_INSN(vfnmsub_vv, MATCH_VFNMSUB_VV, MASK_VFNMSUB_VV) DECLARE_INSN(vfrdiv_vf, MATCH_VFRDIV_VF, MASK_VFRDIV_VF) DECLARE_INSN(vfrec7_v, MATCH_VFREC7_V, MASK_VFREC7_V) DECLARE_INSN(vfredmax_vs, MATCH_VFREDMAX_VS, MASK_VFREDMAX_VS) DECLARE_INSN(vfredmin_vs, MATCH_VFREDMIN_VS, MASK_VFREDMIN_VS) DECLARE_INSN(vfredosum_vs, MATCH_VFREDOSUM_VS, MASK_VFREDOSUM_VS) DECLARE_INSN(vfredusum_vs, MATCH_VFREDUSUM_VS, MASK_VFREDUSUM_VS) DECLARE_INSN(vfrsqrt7_v, MATCH_VFRSQRT7_V, MASK_VFRSQRT7_V) DECLARE_INSN(vfrsub_vf, MATCH_VFRSUB_VF, MASK_VFRSUB_VF) DECLARE_INSN(vfsgnj_vf, MATCH_VFSGNJ_VF, MASK_VFSGNJ_VF) DECLARE_INSN(vfsgnj_vv, MATCH_VFSGNJ_VV, MASK_VFSGNJ_VV) DECLARE_INSN(vfsgnjn_vf, MATCH_VFSGNJN_VF, MASK_VFSGNJN_VF) DECLARE_INSN(vfsgnjn_vv, MATCH_VFSGNJN_VV, MASK_VFSGNJN_VV) DECLARE_INSN(vfsgnjx_vf, MATCH_VFSGNJX_VF, MASK_VFSGNJX_VF) DECLARE_INSN(vfsgnjx_vv, MATCH_VFSGNJX_VV, MASK_VFSGNJX_VV) DECLARE_INSN(vfslide1down_vf, MATCH_VFSLIDE1DOWN_VF, MASK_VFSLIDE1DOWN_VF) DECLARE_INSN(vfslide1up_vf, MATCH_VFSLIDE1UP_VF, MASK_VFSLIDE1UP_VF) DECLARE_INSN(vfsqrt_v, MATCH_VFSQRT_V, MASK_VFSQRT_V) DECLARE_INSN(vfsub_vf, MATCH_VFSUB_VF, MASK_VFSUB_VF) DECLARE_INSN(vfsub_vv, MATCH_VFSUB_VV, MASK_VFSUB_VV) DECLARE_INSN(vfwadd_vf, MATCH_VFWADD_VF, MASK_VFWADD_VF) DECLARE_INSN(vfwadd_vv, MATCH_VFWADD_VV, MASK_VFWADD_VV) DECLARE_INSN(vfwadd_wf, MATCH_VFWADD_WF, MASK_VFWADD_WF) DECLARE_INSN(vfwadd_wv, MATCH_VFWADD_WV, MASK_VFWADD_WV) DECLARE_INSN(vfwcvt_f_f_v, MATCH_VFWCVT_F_F_V, MASK_VFWCVT_F_F_V) DECLARE_INSN(vfwcvt_f_x_v, MATCH_VFWCVT_F_X_V, MASK_VFWCVT_F_X_V) DECLARE_INSN(vfwcvt_f_xu_v, MATCH_VFWCVT_F_XU_V, MASK_VFWCVT_F_XU_V) DECLARE_INSN(vfwcvt_rtz_x_f_v, MATCH_VFWCVT_RTZ_X_F_V, MASK_VFWCVT_RTZ_X_F_V) DECLARE_INSN(vfwcvt_rtz_xu_f_v, MATCH_VFWCVT_RTZ_XU_F_V, MASK_VFWCVT_RTZ_XU_F_V) DECLARE_INSN(vfwcvt_x_f_v, MATCH_VFWCVT_X_F_V, MASK_VFWCVT_X_F_V) DECLARE_INSN(vfwcvt_xu_f_v, MATCH_VFWCVT_XU_F_V, MASK_VFWCVT_XU_F_V) DECLARE_INSN(vfwmacc_vf, MATCH_VFWMACC_VF, MASK_VFWMACC_VF) DECLARE_INSN(vfwmacc_vv, MATCH_VFWMACC_VV, MASK_VFWMACC_VV) DECLARE_INSN(vfwmsac_vf, MATCH_VFWMSAC_VF, MASK_VFWMSAC_VF) DECLARE_INSN(vfwmsac_vv, MATCH_VFWMSAC_VV, MASK_VFWMSAC_VV) DECLARE_INSN(vfwmul_vf, MATCH_VFWMUL_VF, MASK_VFWMUL_VF) DECLARE_INSN(vfwmul_vv, MATCH_VFWMUL_VV, MASK_VFWMUL_VV) DECLARE_INSN(vfwnmacc_vf, MATCH_VFWNMACC_VF, MASK_VFWNMACC_VF) DECLARE_INSN(vfwnmacc_vv, MATCH_VFWNMACC_VV, MASK_VFWNMACC_VV) DECLARE_INSN(vfwnmsac_vf, MATCH_VFWNMSAC_VF, MASK_VFWNMSAC_VF) DECLARE_INSN(vfwnmsac_vv, MATCH_VFWNMSAC_VV, MASK_VFWNMSAC_VV) DECLARE_INSN(vfwredosum_vs, MATCH_VFWREDOSUM_VS, MASK_VFWREDOSUM_VS) DECLARE_INSN(vfwredusum_vs, MATCH_VFWREDUSUM_VS, MASK_VFWREDUSUM_VS) DECLARE_INSN(vfwsub_vf, MATCH_VFWSUB_VF, MASK_VFWSUB_VF) DECLARE_INSN(vfwsub_vv, MATCH_VFWSUB_VV, MASK_VFWSUB_VV) DECLARE_INSN(vfwsub_wf, MATCH_VFWSUB_WF, MASK_VFWSUB_WF) DECLARE_INSN(vfwsub_wv, MATCH_VFWSUB_WV, MASK_VFWSUB_WV) DECLARE_INSN(vid_v, MATCH_VID_V, MASK_VID_V) DECLARE_INSN(viota_m, MATCH_VIOTA_M, MASK_VIOTA_M) DECLARE_INSN(vl1re16_v, MATCH_VL1RE16_V, MASK_VL1RE16_V) DECLARE_INSN(vl1re32_v, MATCH_VL1RE32_V, MASK_VL1RE32_V) DECLARE_INSN(vl1re64_v, MATCH_VL1RE64_V, MASK_VL1RE64_V) DECLARE_INSN(vl1re8_v, MATCH_VL1RE8_V, MASK_VL1RE8_V) DECLARE_INSN(vl2re16_v, MATCH_VL2RE16_V, MASK_VL2RE16_V) DECLARE_INSN(vl2re32_v, MATCH_VL2RE32_V, MASK_VL2RE32_V) DECLARE_INSN(vl2re64_v, MATCH_VL2RE64_V, MASK_VL2RE64_V) DECLARE_INSN(vl2re8_v, MATCH_VL2RE8_V, MASK_VL2RE8_V) DECLARE_INSN(vl4re16_v, MATCH_VL4RE16_V, MASK_VL4RE16_V) DECLARE_INSN(vl4re32_v, MATCH_VL4RE32_V, MASK_VL4RE32_V) DECLARE_INSN(vl4re64_v, MATCH_VL4RE64_V, MASK_VL4RE64_V) DECLARE_INSN(vl4re8_v, MATCH_VL4RE8_V, MASK_VL4RE8_V) DECLARE_INSN(vl8re16_v, MATCH_VL8RE16_V, MASK_VL8RE16_V) DECLARE_INSN(vl8re32_v, MATCH_VL8RE32_V, MASK_VL8RE32_V) DECLARE_INSN(vl8re64_v, MATCH_VL8RE64_V, MASK_VL8RE64_V) DECLARE_INSN(vl8re8_v, MATCH_VL8RE8_V, MASK_VL8RE8_V) DECLARE_INSN(vle1024_v, MATCH_VLE1024_V, MASK_VLE1024_V) DECLARE_INSN(vle1024ff_v, MATCH_VLE1024FF_V, MASK_VLE1024FF_V) DECLARE_INSN(vle128_v, MATCH_VLE128_V, MASK_VLE128_V) DECLARE_INSN(vle128ff_v, MATCH_VLE128FF_V, MASK_VLE128FF_V) DECLARE_INSN(vle16_v, MATCH_VLE16_V, MASK_VLE16_V) DECLARE_INSN(vle16ff_v, MATCH_VLE16FF_V, MASK_VLE16FF_V) DECLARE_INSN(vle256_v, MATCH_VLE256_V, MASK_VLE256_V) DECLARE_INSN(vle256ff_v, MATCH_VLE256FF_V, MASK_VLE256FF_V) DECLARE_INSN(vle32_v, MATCH_VLE32_V, MASK_VLE32_V) DECLARE_INSN(vle32ff_v, MATCH_VLE32FF_V, MASK_VLE32FF_V) DECLARE_INSN(vle512_v, MATCH_VLE512_V, MASK_VLE512_V) DECLARE_INSN(vle512ff_v, MATCH_VLE512FF_V, MASK_VLE512FF_V) DECLARE_INSN(vle64_v, MATCH_VLE64_V, MASK_VLE64_V) DECLARE_INSN(vle64ff_v, MATCH_VLE64FF_V, MASK_VLE64FF_V) DECLARE_INSN(vle8_v, MATCH_VLE8_V, MASK_VLE8_V) DECLARE_INSN(vle8ff_v, MATCH_VLE8FF_V, MASK_VLE8FF_V) DECLARE_INSN(vlm_v, MATCH_VLM_V, MASK_VLM_V) DECLARE_INSN(vloxei1024_v, MATCH_VLOXEI1024_V, MASK_VLOXEI1024_V) DECLARE_INSN(vloxei128_v, MATCH_VLOXEI128_V, MASK_VLOXEI128_V) DECLARE_INSN(vloxei16_v, MATCH_VLOXEI16_V, MASK_VLOXEI16_V) DECLARE_INSN(vloxei256_v, MATCH_VLOXEI256_V, MASK_VLOXEI256_V) DECLARE_INSN(vloxei32_v, MATCH_VLOXEI32_V, MASK_VLOXEI32_V) DECLARE_INSN(vloxei512_v, MATCH_VLOXEI512_V, MASK_VLOXEI512_V) DECLARE_INSN(vloxei64_v, MATCH_VLOXEI64_V, MASK_VLOXEI64_V) DECLARE_INSN(vloxei8_v, MATCH_VLOXEI8_V, MASK_VLOXEI8_V) DECLARE_INSN(vlse1024_v, MATCH_VLSE1024_V, MASK_VLSE1024_V) DECLARE_INSN(vlse128_v, MATCH_VLSE128_V, MASK_VLSE128_V) DECLARE_INSN(vlse16_v, MATCH_VLSE16_V, MASK_VLSE16_V) DECLARE_INSN(vlse256_v, MATCH_VLSE256_V, MASK_VLSE256_V) DECLARE_INSN(vlse32_v, MATCH_VLSE32_V, MASK_VLSE32_V) DECLARE_INSN(vlse512_v, MATCH_VLSE512_V, MASK_VLSE512_V) DECLARE_INSN(vlse64_v, MATCH_VLSE64_V, MASK_VLSE64_V) DECLARE_INSN(vlse8_v, MATCH_VLSE8_V, MASK_VLSE8_V) DECLARE_INSN(vluxei1024_v, MATCH_VLUXEI1024_V, MASK_VLUXEI1024_V) DECLARE_INSN(vluxei128_v, MATCH_VLUXEI128_V, MASK_VLUXEI128_V) DECLARE_INSN(vluxei16_v, MATCH_VLUXEI16_V, MASK_VLUXEI16_V) DECLARE_INSN(vluxei256_v, MATCH_VLUXEI256_V, MASK_VLUXEI256_V) DECLARE_INSN(vluxei32_v, MATCH_VLUXEI32_V, MASK_VLUXEI32_V) DECLARE_INSN(vluxei512_v, MATCH_VLUXEI512_V, MASK_VLUXEI512_V) DECLARE_INSN(vluxei64_v, MATCH_VLUXEI64_V, MASK_VLUXEI64_V) DECLARE_INSN(vluxei8_v, MATCH_VLUXEI8_V, MASK_VLUXEI8_V) DECLARE_INSN(vmacc_vv, MATCH_VMACC_VV, MASK_VMACC_VV) DECLARE_INSN(vmacc_vx, MATCH_VMACC_VX, MASK_VMACC_VX) DECLARE_INSN(vmadc_vi, MATCH_VMADC_VI, MASK_VMADC_VI) DECLARE_INSN(vmadc_vim, MATCH_VMADC_VIM, MASK_VMADC_VIM) DECLARE_INSN(vmadc_vv, MATCH_VMADC_VV, MASK_VMADC_VV) DECLARE_INSN(vmadc_vvm, MATCH_VMADC_VVM, MASK_VMADC_VVM) DECLARE_INSN(vmadc_vx, MATCH_VMADC_VX, MASK_VMADC_VX) DECLARE_INSN(vmadc_vxm, MATCH_VMADC_VXM, MASK_VMADC_VXM) DECLARE_INSN(vmadd_vv, MATCH_VMADD_VV, MASK_VMADD_VV) DECLARE_INSN(vmadd_vx, MATCH_VMADD_VX, MASK_VMADD_VX) DECLARE_INSN(vmand_mm, MATCH_VMAND_MM, MASK_VMAND_MM) DECLARE_INSN(vmandn_mm, MATCH_VMANDN_MM, MASK_VMANDN_MM) DECLARE_INSN(vmax_vv, MATCH_VMAX_VV, MASK_VMAX_VV) DECLARE_INSN(vmax_vx, MATCH_VMAX_VX, MASK_VMAX_VX) DECLARE_INSN(vmaxu_vv, MATCH_VMAXU_VV, MASK_VMAXU_VV) DECLARE_INSN(vmaxu_vx, MATCH_VMAXU_VX, MASK_VMAXU_VX) DECLARE_INSN(vmerge_vim, MATCH_VMERGE_VIM, MASK_VMERGE_VIM) DECLARE_INSN(vmerge_vvm, MATCH_VMERGE_VVM, MASK_VMERGE_VVM) DECLARE_INSN(vmerge_vxm, MATCH_VMERGE_VXM, MASK_VMERGE_VXM) DECLARE_INSN(vmfeq_vf, MATCH_VMFEQ_VF, MASK_VMFEQ_VF) DECLARE_INSN(vmfeq_vv, MATCH_VMFEQ_VV, MASK_VMFEQ_VV) DECLARE_INSN(vmfge_vf, MATCH_VMFGE_VF, MASK_VMFGE_VF) DECLARE_INSN(vmfgt_vf, MATCH_VMFGT_VF, MASK_VMFGT_VF) DECLARE_INSN(vmfle_vf, MATCH_VMFLE_VF, MASK_VMFLE_VF) DECLARE_INSN(vmfle_vv, MATCH_VMFLE_VV, MASK_VMFLE_VV) DECLARE_INSN(vmflt_vf, MATCH_VMFLT_VF, MASK_VMFLT_VF) DECLARE_INSN(vmflt_vv, MATCH_VMFLT_VV, MASK_VMFLT_VV) DECLARE_INSN(vmfne_vf, MATCH_VMFNE_VF, MASK_VMFNE_VF) DECLARE_INSN(vmfne_vv, MATCH_VMFNE_VV, MASK_VMFNE_VV) DECLARE_INSN(vmin_vv, MATCH_VMIN_VV, MASK_VMIN_VV) DECLARE_INSN(vmin_vx, MATCH_VMIN_VX, MASK_VMIN_VX) DECLARE_INSN(vminu_vv, MATCH_VMINU_VV, MASK_VMINU_VV) DECLARE_INSN(vminu_vx, MATCH_VMINU_VX, MASK_VMINU_VX) DECLARE_INSN(vmnand_mm, MATCH_VMNAND_MM, MASK_VMNAND_MM) DECLARE_INSN(vmnor_mm, MATCH_VMNOR_MM, MASK_VMNOR_MM) DECLARE_INSN(vmor_mm, MATCH_VMOR_MM, MASK_VMOR_MM) DECLARE_INSN(vmorn_mm, MATCH_VMORN_MM, MASK_VMORN_MM) DECLARE_INSN(vmsbc_vv, MATCH_VMSBC_VV, MASK_VMSBC_VV) DECLARE_INSN(vmsbc_vvm, MATCH_VMSBC_VVM, MASK_VMSBC_VVM) DECLARE_INSN(vmsbc_vx, MATCH_VMSBC_VX, MASK_VMSBC_VX) DECLARE_INSN(vmsbc_vxm, MATCH_VMSBC_VXM, MASK_VMSBC_VXM) DECLARE_INSN(vmsbf_m, MATCH_VMSBF_M, MASK_VMSBF_M) DECLARE_INSN(vmseq_vi, MATCH_VMSEQ_VI, MASK_VMSEQ_VI) DECLARE_INSN(vmseq_vv, MATCH_VMSEQ_VV, MASK_VMSEQ_VV) DECLARE_INSN(vmseq_vx, MATCH_VMSEQ_VX, MASK_VMSEQ_VX) DECLARE_INSN(vmsgt_vi, MATCH_VMSGT_VI, MASK_VMSGT_VI) DECLARE_INSN(vmsgt_vx, MATCH_VMSGT_VX, MASK_VMSGT_VX) DECLARE_INSN(vmsgtu_vi, MATCH_VMSGTU_VI, MASK_VMSGTU_VI) DECLARE_INSN(vmsgtu_vx, MATCH_VMSGTU_VX, MASK_VMSGTU_VX) DECLARE_INSN(vmsif_m, MATCH_VMSIF_M, MASK_VMSIF_M) DECLARE_INSN(vmsle_vi, MATCH_VMSLE_VI, MASK_VMSLE_VI) DECLARE_INSN(vmsle_vv, MATCH_VMSLE_VV, MASK_VMSLE_VV) DECLARE_INSN(vmsle_vx, MATCH_VMSLE_VX, MASK_VMSLE_VX) DECLARE_INSN(vmsleu_vi, MATCH_VMSLEU_VI, MASK_VMSLEU_VI) DECLARE_INSN(vmsleu_vv, MATCH_VMSLEU_VV, MASK_VMSLEU_VV) DECLARE_INSN(vmsleu_vx, MATCH_VMSLEU_VX, MASK_VMSLEU_VX) DECLARE_INSN(vmslt_vv, MATCH_VMSLT_VV, MASK_VMSLT_VV) DECLARE_INSN(vmslt_vx, MATCH_VMSLT_VX, MASK_VMSLT_VX) DECLARE_INSN(vmsltu_vv, MATCH_VMSLTU_VV, MASK_VMSLTU_VV) DECLARE_INSN(vmsltu_vx, MATCH_VMSLTU_VX, MASK_VMSLTU_VX) DECLARE_INSN(vmsne_vi, MATCH_VMSNE_VI, MASK_VMSNE_VI) DECLARE_INSN(vmsne_vv, MATCH_VMSNE_VV, MASK_VMSNE_VV) DECLARE_INSN(vmsne_vx, MATCH_VMSNE_VX, MASK_VMSNE_VX) DECLARE_INSN(vmsof_m, MATCH_VMSOF_M, MASK_VMSOF_M) DECLARE_INSN(vmul_vv, MATCH_VMUL_VV, MASK_VMUL_VV) DECLARE_INSN(vmul_vx, MATCH_VMUL_VX, MASK_VMUL_VX) DECLARE_INSN(vmulh_vv, MATCH_VMULH_VV, MASK_VMULH_VV) DECLARE_INSN(vmulh_vx, MATCH_VMULH_VX, MASK_VMULH_VX) DECLARE_INSN(vmulhsu_vv, MATCH_VMULHSU_VV, MASK_VMULHSU_VV) DECLARE_INSN(vmulhsu_vx, MATCH_VMULHSU_VX, MASK_VMULHSU_VX) DECLARE_INSN(vmulhu_vv, MATCH_VMULHU_VV, MASK_VMULHU_VV) DECLARE_INSN(vmulhu_vx, MATCH_VMULHU_VX, MASK_VMULHU_VX) DECLARE_INSN(vmv1r_v, MATCH_VMV1R_V, MASK_VMV1R_V) DECLARE_INSN(vmv2r_v, MATCH_VMV2R_V, MASK_VMV2R_V) DECLARE_INSN(vmv4r_v, MATCH_VMV4R_V, MASK_VMV4R_V) DECLARE_INSN(vmv8r_v, MATCH_VMV8R_V, MASK_VMV8R_V) DECLARE_INSN(vmv_s_x, MATCH_VMV_S_X, MASK_VMV_S_X) DECLARE_INSN(vmv_v_i, MATCH_VMV_V_I, MASK_VMV_V_I) DECLARE_INSN(vmv_v_v, MATCH_VMV_V_V, MASK_VMV_V_V) DECLARE_INSN(vmv_v_x, MATCH_VMV_V_X, MASK_VMV_V_X) DECLARE_INSN(vmv_x_s, MATCH_VMV_X_S, MASK_VMV_X_S) DECLARE_INSN(vmxnor_mm, MATCH_VMXNOR_MM, MASK_VMXNOR_MM) DECLARE_INSN(vmxor_mm, MATCH_VMXOR_MM, MASK_VMXOR_MM) DECLARE_INSN(vnclip_wi, MATCH_VNCLIP_WI, MASK_VNCLIP_WI) DECLARE_INSN(vnclip_wv, MATCH_VNCLIP_WV, MASK_VNCLIP_WV) DECLARE_INSN(vnclip_wx, MATCH_VNCLIP_WX, MASK_VNCLIP_WX) DECLARE_INSN(vnclipu_wi, MATCH_VNCLIPU_WI, MASK_VNCLIPU_WI) DECLARE_INSN(vnclipu_wv, MATCH_VNCLIPU_WV, MASK_VNCLIPU_WV) DECLARE_INSN(vnclipu_wx, MATCH_VNCLIPU_WX, MASK_VNCLIPU_WX) DECLARE_INSN(vnmsac_vv, MATCH_VNMSAC_VV, MASK_VNMSAC_VV) DECLARE_INSN(vnmsac_vx, MATCH_VNMSAC_VX, MASK_VNMSAC_VX) DECLARE_INSN(vnmsub_vv, MATCH_VNMSUB_VV, MASK_VNMSUB_VV) DECLARE_INSN(vnmsub_vx, MATCH_VNMSUB_VX, MASK_VNMSUB_VX) DECLARE_INSN(vnsra_wi, MATCH_VNSRA_WI, MASK_VNSRA_WI) DECLARE_INSN(vnsra_wv, MATCH_VNSRA_WV, MASK_VNSRA_WV) DECLARE_INSN(vnsra_wx, MATCH_VNSRA_WX, MASK_VNSRA_WX) DECLARE_INSN(vnsrl_wi, MATCH_VNSRL_WI, MASK_VNSRL_WI) DECLARE_INSN(vnsrl_wv, MATCH_VNSRL_WV, MASK_VNSRL_WV) DECLARE_INSN(vnsrl_wx, MATCH_VNSRL_WX, MASK_VNSRL_WX) DECLARE_INSN(vor_vi, MATCH_VOR_VI, MASK_VOR_VI) DECLARE_INSN(vor_vv, MATCH_VOR_VV, MASK_VOR_VV) DECLARE_INSN(vor_vx, MATCH_VOR_VX, MASK_VOR_VX) DECLARE_INSN(vredand_vs, MATCH_VREDAND_VS, MASK_VREDAND_VS) DECLARE_INSN(vredmax_vs, MATCH_VREDMAX_VS, MASK_VREDMAX_VS) DECLARE_INSN(vredmaxu_vs, MATCH_VREDMAXU_VS, MASK_VREDMAXU_VS) DECLARE_INSN(vredmin_vs, MATCH_VREDMIN_VS, MASK_VREDMIN_VS) DECLARE_INSN(vredminu_vs, MATCH_VREDMINU_VS, MASK_VREDMINU_VS) DECLARE_INSN(vredor_vs, MATCH_VREDOR_VS, MASK_VREDOR_VS) DECLARE_INSN(vredsum_vs, MATCH_VREDSUM_VS, MASK_VREDSUM_VS) DECLARE_INSN(vredxor_vs, MATCH_VREDXOR_VS, MASK_VREDXOR_VS) DECLARE_INSN(vrem_vv, MATCH_VREM_VV, MASK_VREM_VV) DECLARE_INSN(vrem_vx, MATCH_VREM_VX, MASK_VREM_VX) DECLARE_INSN(vremu_vv, MATCH_VREMU_VV, MASK_VREMU_VV) DECLARE_INSN(vremu_vx, MATCH_VREMU_VX, MASK_VREMU_VX) DECLARE_INSN(vrgather_vi, MATCH_VRGATHER_VI, MASK_VRGATHER_VI) DECLARE_INSN(vrgather_vv, MATCH_VRGATHER_VV, MASK_VRGATHER_VV) DECLARE_INSN(vrgather_vx, MATCH_VRGATHER_VX, MASK_VRGATHER_VX) DECLARE_INSN(vrgatherei16_vv, MATCH_VRGATHEREI16_VV, MASK_VRGATHEREI16_VV) DECLARE_INSN(vrsub_vi, MATCH_VRSUB_VI, MASK_VRSUB_VI) DECLARE_INSN(vrsub_vx, MATCH_VRSUB_VX, MASK_VRSUB_VX) DECLARE_INSN(vs1r_v, MATCH_VS1R_V, MASK_VS1R_V) DECLARE_INSN(vs2r_v, MATCH_VS2R_V, MASK_VS2R_V) DECLARE_INSN(vs4r_v, MATCH_VS4R_V, MASK_VS4R_V) DECLARE_INSN(vs8r_v, MATCH_VS8R_V, MASK_VS8R_V) DECLARE_INSN(vsadd_vi, MATCH_VSADD_VI, MASK_VSADD_VI) DECLARE_INSN(vsadd_vv, MATCH_VSADD_VV, MASK_VSADD_VV) DECLARE_INSN(vsadd_vx, MATCH_VSADD_VX, MASK_VSADD_VX) DECLARE_INSN(vsaddu_vi, MATCH_VSADDU_VI, MASK_VSADDU_VI) DECLARE_INSN(vsaddu_vv, MATCH_VSADDU_VV, MASK_VSADDU_VV) DECLARE_INSN(vsaddu_vx, MATCH_VSADDU_VX, MASK_VSADDU_VX) DECLARE_INSN(vsbc_vvm, MATCH_VSBC_VVM, MASK_VSBC_VVM) DECLARE_INSN(vsbc_vxm, MATCH_VSBC_VXM, MASK_VSBC_VXM) DECLARE_INSN(vse1024_v, MATCH_VSE1024_V, MASK_VSE1024_V) DECLARE_INSN(vse128_v, MATCH_VSE128_V, MASK_VSE128_V) DECLARE_INSN(vse16_v, MATCH_VSE16_V, MASK_VSE16_V) DECLARE_INSN(vse256_v, MATCH_VSE256_V, MASK_VSE256_V) DECLARE_INSN(vse32_v, MATCH_VSE32_V, MASK_VSE32_V) DECLARE_INSN(vse512_v, MATCH_VSE512_V, MASK_VSE512_V) DECLARE_INSN(vse64_v, MATCH_VSE64_V, MASK_VSE64_V) DECLARE_INSN(vse8_v, MATCH_VSE8_V, MASK_VSE8_V) DECLARE_INSN(vsetivli, MATCH_VSETIVLI, MASK_VSETIVLI) DECLARE_INSN(vsetvl, MATCH_VSETVL, MASK_VSETVL) DECLARE_INSN(vsetvli, MATCH_VSETVLI, MASK_VSETVLI) DECLARE_INSN(vsext_vf2, MATCH_VSEXT_VF2, MASK_VSEXT_VF2) DECLARE_INSN(vsext_vf4, MATCH_VSEXT_VF4, MASK_VSEXT_VF4) DECLARE_INSN(vsext_vf8, MATCH_VSEXT_VF8, MASK_VSEXT_VF8) DECLARE_INSN(vslide1down_vx, MATCH_VSLIDE1DOWN_VX, MASK_VSLIDE1DOWN_VX) DECLARE_INSN(vslide1up_vx, MATCH_VSLIDE1UP_VX, MASK_VSLIDE1UP_VX) DECLARE_INSN(vslidedown_vi, MATCH_VSLIDEDOWN_VI, MASK_VSLIDEDOWN_VI) DECLARE_INSN(vslidedown_vx, MATCH_VSLIDEDOWN_VX, MASK_VSLIDEDOWN_VX) DECLARE_INSN(vslideup_vi, MATCH_VSLIDEUP_VI, MASK_VSLIDEUP_VI) DECLARE_INSN(vslideup_vx, MATCH_VSLIDEUP_VX, MASK_VSLIDEUP_VX) DECLARE_INSN(vsll_vi, MATCH_VSLL_VI, MASK_VSLL_VI) DECLARE_INSN(vsll_vv, MATCH_VSLL_VV, MASK_VSLL_VV) DECLARE_INSN(vsll_vx, MATCH_VSLL_VX, MASK_VSLL_VX) DECLARE_INSN(vsm_v, MATCH_VSM_V, MASK_VSM_V) DECLARE_INSN(vsmul_vv, MATCH_VSMUL_VV, MASK_VSMUL_VV) DECLARE_INSN(vsmul_vx, MATCH_VSMUL_VX, MASK_VSMUL_VX) DECLARE_INSN(vsoxei1024_v, MATCH_VSOXEI1024_V, MASK_VSOXEI1024_V) DECLARE_INSN(vsoxei128_v, MATCH_VSOXEI128_V, MASK_VSOXEI128_V) DECLARE_INSN(vsoxei16_v, MATCH_VSOXEI16_V, MASK_VSOXEI16_V) DECLARE_INSN(vsoxei256_v, MATCH_VSOXEI256_V, MASK_VSOXEI256_V) DECLARE_INSN(vsoxei32_v, MATCH_VSOXEI32_V, MASK_VSOXEI32_V) DECLARE_INSN(vsoxei512_v, MATCH_VSOXEI512_V, MASK_VSOXEI512_V) DECLARE_INSN(vsoxei64_v, MATCH_VSOXEI64_V, MASK_VSOXEI64_V) DECLARE_INSN(vsoxei8_v, MATCH_VSOXEI8_V, MASK_VSOXEI8_V) DECLARE_INSN(vsra_vi, MATCH_VSRA_VI, MASK_VSRA_VI) DECLARE_INSN(vsra_vv, MATCH_VSRA_VV, MASK_VSRA_VV) DECLARE_INSN(vsra_vx, MATCH_VSRA_VX, MASK_VSRA_VX) DECLARE_INSN(vsrl_vi, MATCH_VSRL_VI, MASK_VSRL_VI) DECLARE_INSN(vsrl_vv, MATCH_VSRL_VV, MASK_VSRL_VV) DECLARE_INSN(vsrl_vx, MATCH_VSRL_VX, MASK_VSRL_VX) DECLARE_INSN(vsse1024_v, MATCH_VSSE1024_V, MASK_VSSE1024_V) DECLARE_INSN(vsse128_v, MATCH_VSSE128_V, MASK_VSSE128_V) DECLARE_INSN(vsse16_v, MATCH_VSSE16_V, MASK_VSSE16_V) DECLARE_INSN(vsse256_v, MATCH_VSSE256_V, MASK_VSSE256_V) DECLARE_INSN(vsse32_v, MATCH_VSSE32_V, MASK_VSSE32_V) DECLARE_INSN(vsse512_v, MATCH_VSSE512_V, MASK_VSSE512_V) DECLARE_INSN(vsse64_v, MATCH_VSSE64_V, MASK_VSSE64_V) DECLARE_INSN(vsse8_v, MATCH_VSSE8_V, MASK_VSSE8_V) DECLARE_INSN(vssra_vi, MATCH_VSSRA_VI, MASK_VSSRA_VI) DECLARE_INSN(vssra_vv, MATCH_VSSRA_VV, MASK_VSSRA_VV) DECLARE_INSN(vssra_vx, MATCH_VSSRA_VX, MASK_VSSRA_VX) DECLARE_INSN(vssrl_vi, MATCH_VSSRL_VI, MASK_VSSRL_VI) DECLARE_INSN(vssrl_vv, MATCH_VSSRL_VV, MASK_VSSRL_VV) DECLARE_INSN(vssrl_vx, MATCH_VSSRL_VX, MASK_VSSRL_VX) DECLARE_INSN(vssub_vv, MATCH_VSSUB_VV, MASK_VSSUB_VV) DECLARE_INSN(vssub_vx, MATCH_VSSUB_VX, MASK_VSSUB_VX) DECLARE_INSN(vssubu_vv, MATCH_VSSUBU_VV, MASK_VSSUBU_VV) DECLARE_INSN(vssubu_vx, MATCH_VSSUBU_VX, MASK_VSSUBU_VX) DECLARE_INSN(vsub_vv, MATCH_VSUB_VV, MASK_VSUB_VV) DECLARE_INSN(vsub_vx, MATCH_VSUB_VX, MASK_VSUB_VX) DECLARE_INSN(vsuxei1024_v, MATCH_VSUXEI1024_V, MASK_VSUXEI1024_V) DECLARE_INSN(vsuxei128_v, MATCH_VSUXEI128_V, MASK_VSUXEI128_V) DECLARE_INSN(vsuxei16_v, MATCH_VSUXEI16_V, MASK_VSUXEI16_V) DECLARE_INSN(vsuxei256_v, MATCH_VSUXEI256_V, MASK_VSUXEI256_V) DECLARE_INSN(vsuxei32_v, MATCH_VSUXEI32_V, MASK_VSUXEI32_V) DECLARE_INSN(vsuxei512_v, MATCH_VSUXEI512_V, MASK_VSUXEI512_V) DECLARE_INSN(vsuxei64_v, MATCH_VSUXEI64_V, MASK_VSUXEI64_V) DECLARE_INSN(vsuxei8_v, MATCH_VSUXEI8_V, MASK_VSUXEI8_V) DECLARE_INSN(vwadd_vv, MATCH_VWADD_VV, MASK_VWADD_VV) DECLARE_INSN(vwadd_vx, MATCH_VWADD_VX, MASK_VWADD_VX) DECLARE_INSN(vwadd_wv, MATCH_VWADD_WV, MASK_VWADD_WV) DECLARE_INSN(vwadd_wx, MATCH_VWADD_WX, MASK_VWADD_WX) DECLARE_INSN(vwaddu_vv, MATCH_VWADDU_VV, MASK_VWADDU_VV) DECLARE_INSN(vwaddu_vx, MATCH_VWADDU_VX, MASK_VWADDU_VX) DECLARE_INSN(vwaddu_wv, MATCH_VWADDU_WV, MASK_VWADDU_WV) DECLARE_INSN(vwaddu_wx, MATCH_VWADDU_WX, MASK_VWADDU_WX) DECLARE_INSN(vwmacc_vv, MATCH_VWMACC_VV, MASK_VWMACC_VV) DECLARE_INSN(vwmacc_vx, MATCH_VWMACC_VX, MASK_VWMACC_VX) DECLARE_INSN(vwmaccsu_vv, MATCH_VWMACCSU_VV, MASK_VWMACCSU_VV) DECLARE_INSN(vwmaccsu_vx, MATCH_VWMACCSU_VX, MASK_VWMACCSU_VX) DECLARE_INSN(vwmaccu_vv, MATCH_VWMACCU_VV, MASK_VWMACCU_VV) DECLARE_INSN(vwmaccu_vx, MATCH_VWMACCU_VX, MASK_VWMACCU_VX) DECLARE_INSN(vwmaccus_vx, MATCH_VWMACCUS_VX, MASK_VWMACCUS_VX) DECLARE_INSN(vwmul_vv, MATCH_VWMUL_VV, MASK_VWMUL_VV) DECLARE_INSN(vwmul_vx, MATCH_VWMUL_VX, MASK_VWMUL_VX) DECLARE_INSN(vwmulsu_vv, MATCH_VWMULSU_VV, MASK_VWMULSU_VV) DECLARE_INSN(vwmulsu_vx, MATCH_VWMULSU_VX, MASK_VWMULSU_VX) DECLARE_INSN(vwmulu_vv, MATCH_VWMULU_VV, MASK_VWMULU_VV) DECLARE_INSN(vwmulu_vx, MATCH_VWMULU_VX, MASK_VWMULU_VX) DECLARE_INSN(vwredsum_vs, MATCH_VWREDSUM_VS, MASK_VWREDSUM_VS) DECLARE_INSN(vwredsumu_vs, MATCH_VWREDSUMU_VS, MASK_VWREDSUMU_VS) DECLARE_INSN(vwsub_vv, MATCH_VWSUB_VV, MASK_VWSUB_VV) DECLARE_INSN(vwsub_vx, MATCH_VWSUB_VX, MASK_VWSUB_VX) DECLARE_INSN(vwsub_wv, MATCH_VWSUB_WV, MASK_VWSUB_WV) DECLARE_INSN(vwsub_wx, MATCH_VWSUB_WX, MASK_VWSUB_WX) DECLARE_INSN(vwsubu_vv, MATCH_VWSUBU_VV, MASK_VWSUBU_VV) DECLARE_INSN(vwsubu_vx, MATCH_VWSUBU_VX, MASK_VWSUBU_VX) DECLARE_INSN(vwsubu_wv, MATCH_VWSUBU_WV, MASK_VWSUBU_WV) DECLARE_INSN(vwsubu_wx, MATCH_VWSUBU_WX, MASK_VWSUBU_WX) DECLARE_INSN(vxor_vi, MATCH_VXOR_VI, MASK_VXOR_VI) DECLARE_INSN(vxor_vv, MATCH_VXOR_VV, MASK_VXOR_VV) DECLARE_INSN(vxor_vx, MATCH_VXOR_VX, MASK_VXOR_VX) DECLARE_INSN(vzext_vf2, MATCH_VZEXT_VF2, MASK_VZEXT_VF2) DECLARE_INSN(vzext_vf4, MATCH_VZEXT_VF4, MASK_VZEXT_VF4) DECLARE_INSN(vzext_vf8, MATCH_VZEXT_VF8, MASK_VZEXT_VF8) DECLARE_INSN(wext, MATCH_WEXT, MASK_WEXT) DECLARE_INSN(wexti, MATCH_WEXTI, MASK_WEXTI) DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) DECLARE_INSN(wrs_nto, MATCH_WRS_NTO, MASK_WRS_NTO) DECLARE_INSN(wrs_sto, MATCH_WRS_STO, MASK_WRS_STO) DECLARE_INSN(xnor, MATCH_XNOR, MASK_XNOR) DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) DECLARE_INSN(xperm16, MATCH_XPERM16, MASK_XPERM16) DECLARE_INSN(xperm32, MATCH_XPERM32, MASK_XPERM32) DECLARE_INSN(xperm4, MATCH_XPERM4, MASK_XPERM4) DECLARE_INSN(xperm8, MATCH_XPERM8, MASK_XPERM8) DECLARE_INSN(zunpkd810, MATCH_ZUNPKD810, MASK_ZUNPKD810) DECLARE_INSN(zunpkd820, MATCH_ZUNPKD820, MASK_ZUNPKD820) DECLARE_INSN(zunpkd830, MATCH_ZUNPKD830, MASK_ZUNPKD830) DECLARE_INSN(zunpkd831, MATCH_ZUNPKD831, MASK_ZUNPKD831) DECLARE_INSN(zunpkd832, MATCH_ZUNPKD832, MASK_ZUNPKD832) #endif #ifdef DECLARE_CSR DECLARE_CSR(fflags, CSR_FFLAGS) DECLARE_CSR(frm, CSR_FRM) DECLARE_CSR(fcsr, CSR_FCSR) DECLARE_CSR(vstart, CSR_VSTART) DECLARE_CSR(vxsat, CSR_VXSAT) DECLARE_CSR(vxrm, CSR_VXRM) DECLARE_CSR(vcsr, CSR_VCSR) DECLARE_CSR(seed, CSR_SEED) DECLARE_CSR(cycle, CSR_CYCLE) DECLARE_CSR(time, CSR_TIME) DECLARE_CSR(instret, CSR_INSTRET) DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) DECLARE_CSR(vl, CSR_VL) DECLARE_CSR(vtype, CSR_VTYPE) DECLARE_CSR(vlenb, CSR_VLENB) DECLARE_CSR(sstatus, CSR_SSTATUS) DECLARE_CSR(sedeleg, CSR_SEDELEG) DECLARE_CSR(sideleg, CSR_SIDELEG) DECLARE_CSR(sie, CSR_SIE) DECLARE_CSR(stvec, CSR_STVEC) DECLARE_CSR(scounteren, CSR_SCOUNTEREN) DECLARE_CSR(senvcfg, CSR_SENVCFG) DECLARE_CSR(sstateen0, CSR_SSTATEEN0) DECLARE_CSR(sstateen1, CSR_SSTATEEN1) DECLARE_CSR(sstateen2, CSR_SSTATEEN2) DECLARE_CSR(sstateen3, CSR_SSTATEEN3) DECLARE_CSR(sscratch, CSR_SSCRATCH) DECLARE_CSR(sepc, CSR_SEPC) DECLARE_CSR(scause, CSR_SCAUSE) DECLARE_CSR(stval, CSR_STVAL) DECLARE_CSR(sip, CSR_SIP) DECLARE_CSR(stimecmp, CSR_STIMECMP) DECLARE_CSR(satp, CSR_SATP) DECLARE_CSR(scontext, CSR_SCONTEXT) DECLARE_CSR(vsstatus, CSR_VSSTATUS) DECLARE_CSR(vsie, CSR_VSIE) DECLARE_CSR(vstvec, CSR_VSTVEC) DECLARE_CSR(vsscratch, CSR_VSSCRATCH) DECLARE_CSR(vsepc, CSR_VSEPC) DECLARE_CSR(vscause, CSR_VSCAUSE) DECLARE_CSR(vstval, CSR_VSTVAL) DECLARE_CSR(vsip, CSR_VSIP) DECLARE_CSR(vstimecmp, CSR_VSTIMECMP) DECLARE_CSR(vsatp, CSR_VSATP) DECLARE_CSR(hstatus, CSR_HSTATUS) DECLARE_CSR(hedeleg, CSR_HEDELEG) DECLARE_CSR(hideleg, CSR_HIDELEG) DECLARE_CSR(hie, CSR_HIE) DECLARE_CSR(htimedelta, CSR_HTIMEDELTA) DECLARE_CSR(hcounteren, CSR_HCOUNTEREN) DECLARE_CSR(hgeie, CSR_HGEIE) DECLARE_CSR(henvcfg, CSR_HENVCFG) DECLARE_CSR(hstateen0, CSR_HSTATEEN0) DECLARE_CSR(hstateen1, CSR_HSTATEEN1) DECLARE_CSR(hstateen2, CSR_HSTATEEN2) DECLARE_CSR(hstateen3, CSR_HSTATEEN3) DECLARE_CSR(htval, CSR_HTVAL) DECLARE_CSR(hip, CSR_HIP) DECLARE_CSR(hvip, CSR_HVIP) DECLARE_CSR(htinst, CSR_HTINST) DECLARE_CSR(hgatp, CSR_HGATP) DECLARE_CSR(hcontext, CSR_HCONTEXT) DECLARE_CSR(hgeip, CSR_HGEIP) DECLARE_CSR(scountovf, CSR_SCOUNTOVF) DECLARE_CSR(utvt, CSR_UTVT) DECLARE_CSR(unxti, CSR_UNXTI) DECLARE_CSR(uintstatus, CSR_UINTSTATUS) DECLARE_CSR(uscratchcsw, CSR_USCRATCHCSW) DECLARE_CSR(uscratchcswl, CSR_USCRATCHCSWL) DECLARE_CSR(stvt, CSR_STVT) DECLARE_CSR(snxti, CSR_SNXTI) DECLARE_CSR(sintstatus, CSR_SINTSTATUS) DECLARE_CSR(sscratchcsw, CSR_SSCRATCHCSW) DECLARE_CSR(sscratchcswl, CSR_SSCRATCHCSWL) DECLARE_CSR(mtvt, CSR_MTVT) DECLARE_CSR(mnxti, CSR_MNXTI) DECLARE_CSR(mintstatus, CSR_MINTSTATUS) DECLARE_CSR(mscratchcsw, CSR_MSCRATCHCSW) DECLARE_CSR(mscratchcswl, CSR_MSCRATCHCSWL) DECLARE_CSR(mstatus, CSR_MSTATUS) DECLARE_CSR(misa, CSR_MISA) DECLARE_CSR(medeleg, CSR_MEDELEG) DECLARE_CSR(mideleg, CSR_MIDELEG) DECLARE_CSR(mie, CSR_MIE) DECLARE_CSR(mtvec, CSR_MTVEC) DECLARE_CSR(mcounteren, CSR_MCOUNTEREN) DECLARE_CSR(menvcfg, CSR_MENVCFG) DECLARE_CSR(mstateen0, CSR_MSTATEEN0) DECLARE_CSR(mstateen1, CSR_MSTATEEN1) DECLARE_CSR(mstateen2, CSR_MSTATEEN2) DECLARE_CSR(mstateen3, CSR_MSTATEEN3) DECLARE_CSR(mcountinhibit, CSR_MCOUNTINHIBIT) DECLARE_CSR(mscratch, CSR_MSCRATCH) DECLARE_CSR(mepc, CSR_MEPC) DECLARE_CSR(mcause, CSR_MCAUSE) DECLARE_CSR(mtval, CSR_MTVAL) DECLARE_CSR(mip, CSR_MIP) DECLARE_CSR(mtinst, CSR_MTINST) DECLARE_CSR(mtval2, CSR_MTVAL2) DECLARE_CSR(pmpcfg0, CSR_PMPCFG0) DECLARE_CSR(pmpcfg1, CSR_PMPCFG1) DECLARE_CSR(pmpcfg2, CSR_PMPCFG2) DECLARE_CSR(pmpcfg3, CSR_PMPCFG3) DECLARE_CSR(pmpcfg4, CSR_PMPCFG4) DECLARE_CSR(pmpcfg5, CSR_PMPCFG5) DECLARE_CSR(pmpcfg6, CSR_PMPCFG6) DECLARE_CSR(pmpcfg7, CSR_PMPCFG7) DECLARE_CSR(pmpcfg8, CSR_PMPCFG8) DECLARE_CSR(pmpcfg9, CSR_PMPCFG9) DECLARE_CSR(pmpcfg10, CSR_PMPCFG10) DECLARE_CSR(pmpcfg11, CSR_PMPCFG11) DECLARE_CSR(pmpcfg12, CSR_PMPCFG12) DECLARE_CSR(pmpcfg13, CSR_PMPCFG13) DECLARE_CSR(pmpcfg14, CSR_PMPCFG14) DECLARE_CSR(pmpcfg15, CSR_PMPCFG15) DECLARE_CSR(pmpaddr0, CSR_PMPADDR0) DECLARE_CSR(pmpaddr1, CSR_PMPADDR1) DECLARE_CSR(pmpaddr2, CSR_PMPADDR2) DECLARE_CSR(pmpaddr3, CSR_PMPADDR3) DECLARE_CSR(pmpaddr4, CSR_PMPADDR4) DECLARE_CSR(pmpaddr5, CSR_PMPADDR5) DECLARE_CSR(pmpaddr6, CSR_PMPADDR6) DECLARE_CSR(pmpaddr7, CSR_PMPADDR7) DECLARE_CSR(pmpaddr8, CSR_PMPADDR8) DECLARE_CSR(pmpaddr9, CSR_PMPADDR9) DECLARE_CSR(pmpaddr10, CSR_PMPADDR10) DECLARE_CSR(pmpaddr11, CSR_PMPADDR11) DECLARE_CSR(pmpaddr12, CSR_PMPADDR12) DECLARE_CSR(pmpaddr13, CSR_PMPADDR13) DECLARE_CSR(pmpaddr14, CSR_PMPADDR14) DECLARE_CSR(pmpaddr15, CSR_PMPADDR15) DECLARE_CSR(pmpaddr16, CSR_PMPADDR16) DECLARE_CSR(pmpaddr17, CSR_PMPADDR17) DECLARE_CSR(pmpaddr18, CSR_PMPADDR18) DECLARE_CSR(pmpaddr19, CSR_PMPADDR19) DECLARE_CSR(pmpaddr20, CSR_PMPADDR20) DECLARE_CSR(pmpaddr21, CSR_PMPADDR21) DECLARE_CSR(pmpaddr22, CSR_PMPADDR22) DECLARE_CSR(pmpaddr23, CSR_PMPADDR23) DECLARE_CSR(pmpaddr24, CSR_PMPADDR24) DECLARE_CSR(pmpaddr25, CSR_PMPADDR25) DECLARE_CSR(pmpaddr26, CSR_PMPADDR26) DECLARE_CSR(pmpaddr27, CSR_PMPADDR27) DECLARE_CSR(pmpaddr28, CSR_PMPADDR28) DECLARE_CSR(pmpaddr29, CSR_PMPADDR29) DECLARE_CSR(pmpaddr30, CSR_PMPADDR30) DECLARE_CSR(pmpaddr31, CSR_PMPADDR31) DECLARE_CSR(pmpaddr32, CSR_PMPADDR32) DECLARE_CSR(pmpaddr33, CSR_PMPADDR33) DECLARE_CSR(pmpaddr34, CSR_PMPADDR34) DECLARE_CSR(pmpaddr35, CSR_PMPADDR35) DECLARE_CSR(pmpaddr36, CSR_PMPADDR36) DECLARE_CSR(pmpaddr37, CSR_PMPADDR37) DECLARE_CSR(pmpaddr38, CSR_PMPADDR38) DECLARE_CSR(pmpaddr39, CSR_PMPADDR39) DECLARE_CSR(pmpaddr40, CSR_PMPADDR40) DECLARE_CSR(pmpaddr41, CSR_PMPADDR41) DECLARE_CSR(pmpaddr42, CSR_PMPADDR42) DECLARE_CSR(pmpaddr43, CSR_PMPADDR43) DECLARE_CSR(pmpaddr44, CSR_PMPADDR44) DECLARE_CSR(pmpaddr45, CSR_PMPADDR45) DECLARE_CSR(pmpaddr46, CSR_PMPADDR46) DECLARE_CSR(pmpaddr47, CSR_PMPADDR47) DECLARE_CSR(pmpaddr48, CSR_PMPADDR48) DECLARE_CSR(pmpaddr49, CSR_PMPADDR49) DECLARE_CSR(pmpaddr50, CSR_PMPADDR50) DECLARE_CSR(pmpaddr51, CSR_PMPADDR51) DECLARE_CSR(pmpaddr52, CSR_PMPADDR52) DECLARE_CSR(pmpaddr53, CSR_PMPADDR53) DECLARE_CSR(pmpaddr54, CSR_PMPADDR54) DECLARE_CSR(pmpaddr55, CSR_PMPADDR55) DECLARE_CSR(pmpaddr56, CSR_PMPADDR56) DECLARE_CSR(pmpaddr57, CSR_PMPADDR57) DECLARE_CSR(pmpaddr58, CSR_PMPADDR58) DECLARE_CSR(pmpaddr59, CSR_PMPADDR59) DECLARE_CSR(pmpaddr60, CSR_PMPADDR60) DECLARE_CSR(pmpaddr61, CSR_PMPADDR61) DECLARE_CSR(pmpaddr62, CSR_PMPADDR62) DECLARE_CSR(pmpaddr63, CSR_PMPADDR63) DECLARE_CSR(mseccfg, CSR_MSECCFG) DECLARE_CSR(tselect, CSR_TSELECT) DECLARE_CSR(tdata1, CSR_TDATA1) DECLARE_CSR(tdata2, CSR_TDATA2) DECLARE_CSR(tdata3, CSR_TDATA3) DECLARE_CSR(tinfo, CSR_TINFO) DECLARE_CSR(tcontrol, CSR_TCONTROL) DECLARE_CSR(mcontext, CSR_MCONTEXT) DECLARE_CSR(mscontext, CSR_MSCONTEXT) DECLARE_CSR(dcsr, CSR_DCSR) DECLARE_CSR(dpc, CSR_DPC) DECLARE_CSR(dscratch0, CSR_DSCRATCH0) DECLARE_CSR(dscratch1, CSR_DSCRATCH1) DECLARE_CSR(mcycle, CSR_MCYCLE) DECLARE_CSR(minstret, CSR_MINSTRET) DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) DECLARE_CSR(mvendorid, CSR_MVENDORID) DECLARE_CSR(marchid, CSR_MARCHID) DECLARE_CSR(mimpid, CSR_MIMPID) DECLARE_CSR(mhartid, CSR_MHARTID) DECLARE_CSR(mconfigptr, CSR_MCONFIGPTR) DECLARE_CSR(stimecmph, CSR_STIMECMPH) DECLARE_CSR(vstimecmph, CSR_VSTIMECMPH) DECLARE_CSR(htimedeltah, CSR_HTIMEDELTAH) DECLARE_CSR(henvcfgh, CSR_HENVCFGH) DECLARE_CSR(hstateen0h, CSR_HSTATEEN0H) DECLARE_CSR(hstateen1h, CSR_HSTATEEN1H) DECLARE_CSR(hstateen2h, CSR_HSTATEEN2H) DECLARE_CSR(hstateen3h, CSR_HSTATEEN3H) DECLARE_CSR(cycleh, CSR_CYCLEH) DECLARE_CSR(timeh, CSR_TIMEH) DECLARE_CSR(instreth, CSR_INSTRETH) DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) DECLARE_CSR(mstatush, CSR_MSTATUSH) DECLARE_CSR(menvcfgh, CSR_MENVCFGH) DECLARE_CSR(mstateen0h, CSR_MSTATEEN0H) DECLARE_CSR(mstateen1h, CSR_MSTATEEN1H) DECLARE_CSR(mstateen2h, CSR_MSTATEEN2H) DECLARE_CSR(mstateen3h, CSR_MSTATEEN3H) DECLARE_CSR(mhpmevent3h, CSR_MHPMEVENT3H) DECLARE_CSR(mhpmevent4h, CSR_MHPMEVENT4H) DECLARE_CSR(mhpmevent5h, CSR_MHPMEVENT5H) DECLARE_CSR(mhpmevent6h, CSR_MHPMEVENT6H) DECLARE_CSR(mhpmevent7h, CSR_MHPMEVENT7H) DECLARE_CSR(mhpmevent8h, CSR_MHPMEVENT8H) DECLARE_CSR(mhpmevent9h, CSR_MHPMEVENT9H) DECLARE_CSR(mhpmevent10h, CSR_MHPMEVENT10H) DECLARE_CSR(mhpmevent11h, CSR_MHPMEVENT11H) DECLARE_CSR(mhpmevent12h, CSR_MHPMEVENT12H) DECLARE_CSR(mhpmevent13h, CSR_MHPMEVENT13H) DECLARE_CSR(mhpmevent14h, CSR_MHPMEVENT14H) DECLARE_CSR(mhpmevent15h, CSR_MHPMEVENT15H) DECLARE_CSR(mhpmevent16h, CSR_MHPMEVENT16H) DECLARE_CSR(mhpmevent17h, CSR_MHPMEVENT17H) DECLARE_CSR(mhpmevent18h, CSR_MHPMEVENT18H) DECLARE_CSR(mhpmevent19h, CSR_MHPMEVENT19H) DECLARE_CSR(mhpmevent20h, CSR_MHPMEVENT20H) DECLARE_CSR(mhpmevent21h, CSR_MHPMEVENT21H) DECLARE_CSR(mhpmevent22h, CSR_MHPMEVENT22H) DECLARE_CSR(mhpmevent23h, CSR_MHPMEVENT23H) DECLARE_CSR(mhpmevent24h, CSR_MHPMEVENT24H) DECLARE_CSR(mhpmevent25h, CSR_MHPMEVENT25H) DECLARE_CSR(mhpmevent26h, CSR_MHPMEVENT26H) DECLARE_CSR(mhpmevent27h, CSR_MHPMEVENT27H) DECLARE_CSR(mhpmevent28h, CSR_MHPMEVENT28H) DECLARE_CSR(mhpmevent29h, CSR_MHPMEVENT29H) DECLARE_CSR(mhpmevent30h, CSR_MHPMEVENT30H) DECLARE_CSR(mhpmevent31h, CSR_MHPMEVENT31H) DECLARE_CSR(mseccfgh, CSR_MSECCFGH) DECLARE_CSR(mcycleh, CSR_MCYCLEH) DECLARE_CSR(minstreth, CSR_MINSTRETH) DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) #endif #ifdef DECLARE_CAUSE DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) DECLARE_CAUSE("fetch access", CAUSE_FETCH_ACCESS) DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) DECLARE_CAUSE("load access", CAUSE_LOAD_ACCESS) DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) DECLARE_CAUSE("store access", CAUSE_STORE_ACCESS) DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) DECLARE_CAUSE("virtual_supervisor_ecall", CAUSE_VIRTUAL_SUPERVISOR_ECALL) DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) DECLARE_CAUSE("fetch page fault", CAUSE_FETCH_PAGE_FAULT) DECLARE_CAUSE("load page fault", CAUSE_LOAD_PAGE_FAULT) DECLARE_CAUSE("store page fault", CAUSE_STORE_PAGE_FAULT) DECLARE_CAUSE("fetch guest page fault", CAUSE_FETCH_GUEST_PAGE_FAULT) DECLARE_CAUSE("load guest page fault", CAUSE_LOAD_GUEST_PAGE_FAULT) DECLARE_CAUSE("virtual instruction", CAUSE_VIRTUAL_INSTRUCTION) DECLARE_CAUSE("store guest page fault", CAUSE_STORE_GUEST_PAGE_FAULT) #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/gdb_regs.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef TARGET__RISCV__GDB_REGS_H #define TARGET__RISCV__GDB_REGS_H /* gdb's register list is defined in riscv_gdb_reg_names gdb/riscv-tdep.c in * its source tree. We must interpret the numbers the same here. */ enum gdb_regno { GDB_REGNO_ZERO = 0, /* Read-only register, always 0. */ GDB_REGNO_RA = 1, /* Return Address. */ GDB_REGNO_SP = 2, /* Stack Pointer. */ GDB_REGNO_GP = 3, /* Global Pointer. */ GDB_REGNO_TP = 4, /* Thread Pointer. */ GDB_REGNO_T0, GDB_REGNO_T1, GDB_REGNO_T2, GDB_REGNO_S0 = 8, GDB_REGNO_FP = 8, /* Frame Pointer. */ GDB_REGNO_S1, GDB_REGNO_A0 = 10, /* First argument. */ GDB_REGNO_A1 = 11, /* Second argument. */ GDB_REGNO_A2, GDB_REGNO_A3, GDB_REGNO_A4, GDB_REGNO_A5, GDB_REGNO_XPR15 = GDB_REGNO_A5, GDB_REGNO_A6, GDB_REGNO_A7, GDB_REGNO_S2, GDB_REGNO_S3, GDB_REGNO_S4, GDB_REGNO_S5, GDB_REGNO_S6, GDB_REGNO_S7, GDB_REGNO_S8, GDB_REGNO_S9, GDB_REGNO_S10, GDB_REGNO_S11, GDB_REGNO_T3, GDB_REGNO_T4, GDB_REGNO_T5, GDB_REGNO_T6, GDB_REGNO_XPR31 = GDB_REGNO_T6, GDB_REGNO_PC = 32, GDB_REGNO_FPR0 = 33, GDB_REGNO_FT0 = GDB_REGNO_FPR0, GDB_REGNO_FT1, GDB_REGNO_FT2, GDB_REGNO_FT3, GDB_REGNO_FT4, GDB_REGNO_FT5, GDB_REGNO_FT6, GDB_REGNO_FT7, GDB_REGNO_FS0, GDB_REGNO_FS1, GDB_REGNO_FA0, GDB_REGNO_FA1, GDB_REGNO_FA2, GDB_REGNO_FA3, GDB_REGNO_FA4, GDB_REGNO_FA5, GDB_REGNO_FA6, GDB_REGNO_FA7, GDB_REGNO_FS2, GDB_REGNO_FS3, GDB_REGNO_FS4, GDB_REGNO_FS5, GDB_REGNO_FS6, GDB_REGNO_FS7, GDB_REGNO_FS8, GDB_REGNO_FS9, GDB_REGNO_FS10, GDB_REGNO_FS11, GDB_REGNO_FT8, GDB_REGNO_FT9, GDB_REGNO_FT10, GDB_REGNO_FT11, GDB_REGNO_FPR31 = GDB_REGNO_FT11, GDB_REGNO_CSR0 = 65, GDB_REGNO_VSTART = CSR_VSTART + GDB_REGNO_CSR0, GDB_REGNO_VXSAT = CSR_VXSAT + GDB_REGNO_CSR0, GDB_REGNO_VXRM = CSR_VXRM + GDB_REGNO_CSR0, GDB_REGNO_VLENB = CSR_VLENB + GDB_REGNO_CSR0, GDB_REGNO_VL = CSR_VL + GDB_REGNO_CSR0, GDB_REGNO_VTYPE = CSR_VTYPE + GDB_REGNO_CSR0, GDB_REGNO_TSELECT = CSR_TSELECT + GDB_REGNO_CSR0, GDB_REGNO_TDATA1 = CSR_TDATA1 + GDB_REGNO_CSR0, GDB_REGNO_TDATA2 = CSR_TDATA2 + GDB_REGNO_CSR0, GDB_REGNO_MISA = CSR_MISA + GDB_REGNO_CSR0, GDB_REGNO_DPC = CSR_DPC + GDB_REGNO_CSR0, GDB_REGNO_DCSR = CSR_DCSR + GDB_REGNO_CSR0, GDB_REGNO_DSCRATCH0 = CSR_DSCRATCH0 + GDB_REGNO_CSR0, GDB_REGNO_MSTATUS = CSR_MSTATUS + GDB_REGNO_CSR0, GDB_REGNO_MEPC = CSR_MEPC + GDB_REGNO_CSR0, GDB_REGNO_MCAUSE = CSR_MCAUSE + GDB_REGNO_CSR0, GDB_REGNO_SATP = CSR_SATP + GDB_REGNO_CSR0, GDB_REGNO_CSR4095 = GDB_REGNO_CSR0 + 4095, GDB_REGNO_PRIV = 4161, /* It's still undecided what register numbers GDB will actually use for * these. See * https://groups.google.com/a/groups.riscv.org/d/msg/sw-dev/7lQYiTUN9Ms/gTxGhzaYBQAJ */ GDB_REGNO_V0, GDB_REGNO_V1, GDB_REGNO_V2, GDB_REGNO_V3, GDB_REGNO_V4, GDB_REGNO_V5, GDB_REGNO_V6, GDB_REGNO_V7, GDB_REGNO_V8, GDB_REGNO_V9, GDB_REGNO_V10, GDB_REGNO_V11, GDB_REGNO_V12, GDB_REGNO_V13, GDB_REGNO_V14, GDB_REGNO_V15, GDB_REGNO_V16, GDB_REGNO_V17, GDB_REGNO_V18, GDB_REGNO_V19, GDB_REGNO_V20, GDB_REGNO_V21, GDB_REGNO_V22, GDB_REGNO_V23, GDB_REGNO_V24, GDB_REGNO_V25, GDB_REGNO_V26, GDB_REGNO_V27, GDB_REGNO_V28, GDB_REGNO_V29, GDB_REGNO_V30, GDB_REGNO_V31, GDB_REGNO_COUNT }; const char *gdb_regno_name(enum gdb_regno regno); #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/opcodes.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include "encoding.h" #define ZERO 0 #define T0 5 #define S0 8 #define S1 9 static uint32_t bits(uint32_t value, unsigned int hi, unsigned int lo) { return (value >> lo) & ((1 << (hi+1-lo)) - 1); } static uint32_t bit(uint32_t value, unsigned int b) { return (value >> b) & 1; } static uint32_t inst_rd(uint32_t r) __attribute__ ((unused)); static uint32_t inst_rd(uint32_t r) { return bits(r, 4, 0) << 7; } static uint32_t inst_rs1(uint32_t r) __attribute__ ((unused)); static uint32_t inst_rs1(uint32_t r) { return bits(r, 4, 0) << 15; } static uint32_t inst_rs2(uint32_t r) __attribute__ ((unused)); static uint32_t inst_rs2(uint32_t r) { return bits(r, 4, 0) << 20; } static uint32_t imm_i(uint32_t imm) __attribute__ ((unused)); static uint32_t imm_i(uint32_t imm) { return bits(imm, 11, 0) << 20; } static uint32_t imm_s(uint32_t imm) __attribute__ ((unused)); static uint32_t imm_s(uint32_t imm) { return (bits(imm, 4, 0) << 7) | (bits(imm, 11, 5) << 25); } static uint32_t imm_b(uint32_t imm) __attribute__ ((unused)); static uint32_t imm_b(uint32_t imm) { return (bit(imm, 11) << 7) | (bits(imm, 4, 1) << 8) | (bits(imm, 10, 5) << 25) | (bit(imm, 12) << 31); } static uint32_t imm_u(uint32_t imm) __attribute__ ((unused)); static uint32_t imm_u(uint32_t imm) { return bits(imm, 31, 12) << 12; } static uint32_t imm_j(uint32_t imm) __attribute__ ((unused)); static uint32_t imm_j(uint32_t imm) { return (bits(imm, 19, 12) << 12) | (bit(imm, 11) << 20) | (bits(imm, 10, 1) << 21) | (bit(imm, 20) << 31); } static uint32_t jal(unsigned int rd, uint32_t imm) __attribute__ ((unused)); static uint32_t jal(unsigned int rd, uint32_t imm) { return imm_j(imm) | inst_rd(rd) | MATCH_JAL; } static uint32_t csrsi(unsigned int csr, uint16_t imm) __attribute__ ((unused)); static uint32_t csrsi(unsigned int csr, uint16_t imm) { return imm_i(csr) | inst_rs1(imm) | MATCH_CSRRSI; } static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) { return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SW; } static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) { return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SD; } static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) { return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SH; } static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) { return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SB; } static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) { return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LD; } static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) { return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LW; } static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) { return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LH; } static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) { return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LB; } static uint32_t csrw(unsigned int source, unsigned int csr) __attribute__ ((unused)); static uint32_t csrw(unsigned int source, unsigned int csr) { return imm_i(csr) | inst_rs1(source) | MATCH_CSRRW; } static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused)); static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) { return imm_i(imm) | inst_rs1(src) | inst_rd(dest) | MATCH_ADDI; } static uint32_t csrr(unsigned int rd, unsigned int csr) __attribute__ ((unused)); static uint32_t csrr(unsigned int rd, unsigned int csr) { return imm_i(csr) | inst_rd(rd) | MATCH_CSRRS; } static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused)); static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) { return imm_i(csr) | inst_rs1(rs) | inst_rd(rd) | MATCH_CSRRS; } static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused)); static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) { return imm_i(csr) | inst_rs1(rs) | inst_rd(rd) | MATCH_CSRRW; } static uint32_t csrrci(unsigned int rd, unsigned int zimm, unsigned int csr) __attribute__ ((unused)); static uint32_t csrrci(unsigned int rd, unsigned int zimm, unsigned int csr) { return imm_i(csr) | inst_rs1(zimm) | inst_rd(rd) | MATCH_CSRRCI; } static uint32_t csrrsi(unsigned int rd, unsigned int zimm, unsigned int csr) __attribute__ ((unused)); static uint32_t csrrsi(unsigned int rd, unsigned int zimm, unsigned int csr) { return imm_i(csr) | inst_rs1(zimm) | inst_rd(rd) | MATCH_CSRRSI; } static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) { return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_FSW; } static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) { return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_FSD; } static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) { return imm_i(offset) | inst_rs1(base) | inst_rd(dest) | MATCH_FLW; } static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) { return imm_i(offset) | inst_rs1(base) | inst_rd(dest) | MATCH_FLD; } static uint32_t fmv_x_w(unsigned dest, unsigned src) __attribute__ ((unused)); static uint32_t fmv_x_w(unsigned dest, unsigned src) { return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_X_W; } static uint32_t fmv_x_d(unsigned dest, unsigned src) __attribute__ ((unused)); static uint32_t fmv_x_d(unsigned dest, unsigned src) { return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_X_D; } static uint32_t fmv_w_x(unsigned dest, unsigned src) __attribute__ ((unused)); static uint32_t fmv_w_x(unsigned dest, unsigned src) { return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_W_X; } static uint32_t fmv_d_x(unsigned dest, unsigned src) __attribute__ ((unused)); static uint32_t fmv_d_x(unsigned dest, unsigned src) { return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_D_X; } static uint32_t ebreak(void) __attribute__ ((unused)); static uint32_t ebreak(void) { return MATCH_EBREAK; } static uint32_t ebreak_c(void) __attribute__ ((unused)); static uint32_t ebreak_c(void) { return MATCH_C_EBREAK; } static uint32_t wfi(void) __attribute__ ((unused)); static uint32_t wfi(void) { return MATCH_WFI; } static uint32_t fence_i(void) __attribute__ ((unused)); static uint32_t fence_i(void) { return MATCH_FENCE_I; } static uint32_t lui(unsigned int dest, uint32_t imm) __attribute__ ((unused)); static uint32_t lui(unsigned int dest, uint32_t imm) { return imm_u(imm) | inst_rd(dest) | MATCH_LUI; } /* static uint32_t csrci(unsigned int csr, uint16_t imm) __attribute__ ((unused)); static uint32_t csrci(unsigned int csr, uint16_t imm) { return (csr << 20) | (bits(imm, 4, 0) << 15) | MATCH_CSRRCI; } static uint32_t li(unsigned int dest, uint16_t imm) __attribute__ ((unused)); static uint32_t li(unsigned int dest, uint16_t imm) { return addi(dest, 0, imm); } static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) { return (bits(offset, 11, 5) << 25) | (bits(src, 4, 0) << 20) | (base << 15) | (bits(offset, 4, 0) << 7) | MATCH_FSD; } static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused)); static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm) { return (bits(imm, 11, 0) << 20) | (src << 15) | (dest << 7) | MATCH_ORI; } static uint32_t nop(void) __attribute__ ((unused)); static uint32_t nop(void) { return addi(0, 0, 0); } */ static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused)); static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) { return imm_i(imm) | inst_rs1(src) | inst_rd(dest) | MATCH_XORI; } static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) __attribute__ ((unused)); static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) { return inst_rs2(shamt) | inst_rs1(src) | inst_rd(dest) | MATCH_SRLI; } static uint32_t fence(void) __attribute__((unused)); static uint32_t fence(void) { return MATCH_FENCE; } static uint32_t auipc(unsigned int dest) __attribute__((unused)); static uint32_t auipc(unsigned int dest) { return MATCH_AUIPC | inst_rd(dest); } static uint32_t vsetvli(unsigned int dest, unsigned int src, uint16_t imm) __attribute__((unused)); static uint32_t vsetvli(unsigned int dest, unsigned int src, uint16_t imm) { return (bits(imm, 10, 0) << 20) | inst_rs1(src) | inst_rd(dest) | MATCH_VSETVLI; } static uint32_t vmv_x_s(unsigned int rd, unsigned int vs2) __attribute__((unused)); static uint32_t vmv_x_s(unsigned int rd, unsigned int vs2) { return inst_rs2(vs2) | inst_rd(rd) | MATCH_VMV_X_S; } static uint32_t vmv_s_x(unsigned int vd, unsigned int vs2) __attribute__((unused)); static uint32_t vmv_s_x(unsigned int vd, unsigned int rs1) { return inst_rs1(rs1) | inst_rd(vd) | MATCH_VMV_S_X; } static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2, unsigned int rs1, unsigned int vm) __attribute__((unused)); static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2, unsigned int rs1, unsigned int vm) { return ((vm & 1) << 25) | inst_rs2(vs2) | inst_rs1(rs1) | inst_rd(vd) | MATCH_VSLIDE1DOWN_VX; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/program.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target/target.h" #include "target/register.h" #include "riscv.h" #include "program.h" #include "helper/log.h" #include "asm.h" #include "encoding.h" /* Program interface. */ int riscv_program_init(struct riscv_program *p, struct target *target) { memset(p, 0, sizeof(*p)); p->target = target; p->instruction_count = 0; p->target_xlen = riscv_xlen(target); for (size_t i = 0; i < RISCV_REGISTER_COUNT; ++i) p->writes_xreg[i] = 0; for (size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i) p->debug_buffer[i] = -1; return ERROR_OK; } int riscv_program_write(struct riscv_program *program) { for (unsigned i = 0; i < program->instruction_count; ++i) { LOG_DEBUG("debug_buffer[%02x] = DASM(0x%08x)", i, program->debug_buffer[i]); if (riscv_write_debug_buffer(program->target, i, program->debug_buffer[i]) != ERROR_OK) return ERROR_FAIL; } return ERROR_OK; } /** Add ebreak and execute the program. */ int riscv_program_exec(struct riscv_program *p, struct target *t) { keep_alive(); riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1]; for (size_t i = GDB_REGNO_ZERO + 1; i <= GDB_REGNO_XPR31; ++i) { if (p->writes_xreg[i]) { LOG_DEBUG("Saving register %d as used by program", (int)i); int result = riscv_get_register(t, &saved_registers[i], i); if (result != ERROR_OK) return result; } } if (riscv_program_ebreak(p) != ERROR_OK) { LOG_ERROR("Unable to write ebreak"); for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) LOG_ERROR("ram[%02x]: DASM(0x%08" PRIx32 ") [0x%08" PRIx32 "]", (int)i, p->debug_buffer[i], p->debug_buffer[i]); return ERROR_FAIL; } if (riscv_program_write(p) != ERROR_OK) return ERROR_FAIL; if (riscv_execute_debug_buffer(t) != ERROR_OK) { LOG_DEBUG("Unable to execute program %p", p); return ERROR_FAIL; } for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) if (i >= riscv_debug_buffer_size(p->target)) p->debug_buffer[i] = riscv_read_debug_buffer(t, i); for (size_t i = GDB_REGNO_ZERO; i <= GDB_REGNO_XPR31; ++i) if (p->writes_xreg[i]) riscv_set_register(t, i, saved_registers[i]); return ERROR_OK; } int riscv_program_sdr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { return riscv_program_insert(p, sd(d, b, offset)); } int riscv_program_swr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { return riscv_program_insert(p, sw(d, b, offset)); } int riscv_program_shr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { return riscv_program_insert(p, sh(d, b, offset)); } int riscv_program_sbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { return riscv_program_insert(p, sb(d, b, offset)); } int riscv_program_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { return riscv_program_insert(p, ld(d, b, offset)); } int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { return riscv_program_insert(p, lw(d, b, offset)); } int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { return riscv_program_insert(p, lh(d, b, offset)); } int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { return riscv_program_insert(p, lb(d, b, offset)); } int riscv_program_csrrsi(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr) { assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); return riscv_program_insert(p, csrrsi(d, z, csr - GDB_REGNO_CSR0)); } int riscv_program_csrrci(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr) { assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); return riscv_program_insert(p, csrrci(d, z, csr - GDB_REGNO_CSR0)); } int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr) { assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); return riscv_program_insert(p, csrrs(d, GDB_REGNO_ZERO, csr - GDB_REGNO_CSR0)); } int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr) { assert(csr >= GDB_REGNO_CSR0); return riscv_program_insert(p, csrrw(GDB_REGNO_ZERO, s, csr - GDB_REGNO_CSR0)); } int riscv_program_fence_i(struct riscv_program *p) { return riscv_program_insert(p, fence_i()); } int riscv_program_fence(struct riscv_program *p) { return riscv_program_insert(p, fence()); } int riscv_program_ebreak(struct riscv_program *p) { struct target *target = p->target; RISCV_INFO(r); if (p->instruction_count == riscv_debug_buffer_size(p->target) && r->impebreak) { return ERROR_OK; } return riscv_program_insert(p, ebreak()); } int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t u) { return riscv_program_insert(p, addi(d, s, u)); } int riscv_program_insert(struct riscv_program *p, riscv_insn_t i) { if (p->instruction_count >= riscv_debug_buffer_size(p->target)) { LOG_ERROR("Unable to insert instruction:"); LOG_ERROR(" instruction_count=%d", (int)p->instruction_count); LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target)); return ERROR_FAIL; } p->debug_buffer[p->instruction_count] = i; p->instruction_count++; return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/program.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef TARGET__RISCV__PROGRAM_H #define TARGET__RISCV__PROGRAM_H #include "riscv.h" #define RISCV_MAX_DEBUG_BUFFER_SIZE 32 #define RISCV_REGISTER_COUNT 32 #define RISCV_DSCRATCH_COUNT 2 /* The various RISC-V debug specifications all revolve around setting up * program buffers and executing them on the target. This structure contains a * single program, which can then be executed on targets. */ struct riscv_program { struct target *target; uint32_t debug_buffer[RISCV_MAX_DEBUG_BUFFER_SIZE]; /* Number of 32-bit instructions in the program. */ size_t instruction_count; /* Side effects of executing this program. These must be accounted for * in order to maintain correct executing of the target system. */ bool writes_xreg[RISCV_REGISTER_COUNT]; /* XLEN on the target. */ int target_xlen; }; /* Initializes a program with the header. */ int riscv_program_init(struct riscv_program *p, struct target *t); /* Write the program to the program buffer. */ int riscv_program_write(struct riscv_program *program); /* Executes a program, returning 0 if the program successfully executed. Note * that this may cause registers to be saved or restored, which could result to * calls to things like riscv_save_register which itself could require a * program to execute. That's OK, just make sure this eventually terminates. * */ int riscv_program_exec(struct riscv_program *p, struct target *t); /* A lower level interface, you shouldn't use this unless you have a reason. */ int riscv_program_insert(struct riscv_program *p, riscv_insn_t i); /* Helpers to assemble various instructions. Return 0 on success. These might * assemble into a multi-instruction sequence that overwrites some other * register, but those will be properly saved and restored. */ int riscv_program_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); int riscv_program_sdr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_swr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_shr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_sbr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_csrrsi(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr); int riscv_program_csrrci(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr); int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr); int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr); int riscv_program_fence_i(struct riscv_program *p); int riscv_program_fence(struct riscv_program *p); int riscv_program_ebreak(struct riscv_program *p); int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t i); #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/riscv-011.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Support for RISC-V, debug version 0.11. This was never an officially adopted * spec, but SiFive made some silicon that uses it. */ #include <assert.h> #include <stdlib.h> #include <time.h> #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target/target.h" #include "target/algorithm.h" #include "target/target_type.h" #include <helper/log.h> #include "jtag/jtag.h" #include "target/register.h" #include "target/breakpoints.h" #include "helper/time_support.h" #include "riscv.h" #include "asm.h" #include "gdb_regs.h" /** * Since almost everything can be accomplish by scanning the dbus register, all * functions here assume dbus is already selected. The exception are functions * called directly by OpenOCD, which can't assume anything about what's * currently in IR. They should set IR to dbus explicitly. */ /** * Code structure * * At the bottom of the stack are the OpenOCD JTAG functions: * jtag_add_[id]r_scan * jtag_execute_query * jtag_add_runtest * * There are a few functions to just instantly shift a register and get its * value: * dtmcontrol_scan * idcode_scan * dbus_scan * * Because doing one scan and waiting for the result is slow, most functions * batch up a bunch of dbus writes and then execute them all at once. They use * the scans "class" for this: * scans_new * scans_delete * scans_execute * scans_add_... * Usually you new(), call a bunch of add functions, then execute() and look * at the results by calling scans_get...() * * Optimized functions will directly use the scans class above, but slightly * lazier code will use the cache functions that in turn use the scans * functions: * cache_get... * cache_set... * cache_write * cache_set... update a local structure, which is then synced to the target * with cache_write(). Only Debug RAM words that are actually changed are sent * to the target. Afterwards use cache_get... to read results. */ #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) /* Constants for legacy SiFive hardware breakpoints. */ #define CSR_BPCONTROL_X (1<<0) #define CSR_BPCONTROL_W (1<<1) #define CSR_BPCONTROL_R (1<<2) #define CSR_BPCONTROL_U (1<<3) #define CSR_BPCONTROL_S (1<<4) #define CSR_BPCONTROL_H (1<<5) #define CSR_BPCONTROL_M (1<<6) #define CSR_BPCONTROL_BPMATCH (0xf<<7) #define CSR_BPCONTROL_BPACTION (0xff<<11) #define DEBUG_ROM_START 0x800 #define DEBUG_ROM_RESUME (DEBUG_ROM_START + 4) #define DEBUG_ROM_EXCEPTION (DEBUG_ROM_START + 8) #define DEBUG_RAM_START 0x400 #define SETHALTNOT 0x10c /*** JTAG registers. ***/ #define DTMCONTROL 0x10 #define DTMCONTROL_DBUS_RESET (1<<16) #define DTMCONTROL_IDLE (7<<10) #define DTMCONTROL_ADDRBITS (0xf<<4) #define DTMCONTROL_VERSION (0xf) #define DBUS 0x11 #define DBUS_OP_START 0 #define DBUS_OP_SIZE 2 typedef enum { DBUS_OP_NOP = 0, DBUS_OP_READ = 1, DBUS_OP_WRITE = 2 } dbus_op_t; typedef enum { DBUS_STATUS_SUCCESS = 0, DBUS_STATUS_FAILED = 2, DBUS_STATUS_BUSY = 3 } dbus_status_t; #define DBUS_DATA_START 2 #define DBUS_DATA_SIZE 34 #define DBUS_ADDRESS_START 36 typedef enum { RE_OK, RE_FAIL, RE_AGAIN } riscv_error_t; typedef enum slot { SLOT0, SLOT1, SLOT_LAST, } slot_t; /*** Debug Bus registers. ***/ #define DMCONTROL 0x10 #define DMCONTROL_INTERRUPT (((uint64_t)1)<<33) #define DMCONTROL_HALTNOT (((uint64_t)1)<<32) #define DMCONTROL_BUSERROR (7<<19) #define DMCONTROL_SERIAL (3<<16) #define DMCONTROL_AUTOINCREMENT (1<<15) #define DMCONTROL_ACCESS (7<<12) #define DMCONTROL_HARTID (0x3ff<<2) #define DMCONTROL_NDRESET (1<<1) #define DMCONTROL_FULLRESET 1 #define DMINFO 0x11 #define DMINFO_ABUSSIZE (0x7fU<<25) #define DMINFO_SERIALCOUNT (0xf<<21) #define DMINFO_ACCESS128 (1<<20) #define DMINFO_ACCESS64 (1<<19) #define DMINFO_ACCESS32 (1<<18) #define DMINFO_ACCESS16 (1<<17) #define DMINFO_ACCESS8 (1<<16) #define DMINFO_DRAMSIZE (0x3f<<10) #define DMINFO_AUTHENTICATED (1<<5) #define DMINFO_AUTHBUSY (1<<4) #define DMINFO_AUTHTYPE (3<<2) #define DMINFO_VERSION 3 #define DMAUTHDATA0 0x12 #define DMAUTHDATA1 0x13 /*** Info about the core being debugged. ***/ #define DBUS_ADDRESS_UNKNOWN 0xffff #define DRAM_CACHE_SIZE 16 struct trigger { uint64_t address; uint32_t length; uint64_t mask; uint64_t value; bool read, write, execute; int unique_id; }; struct memory_cache_line { uint32_t data; bool valid; bool dirty; }; typedef struct { /* Number of address bits in the dbus register. */ uint8_t addrbits; /* Number of words in Debug RAM. */ unsigned int dramsize; uint64_t dcsr; uint64_t dpc; uint64_t tselect; bool tselect_dirty; /* The value that mstatus actually has on the target right now. This is not * the value we present to the user. That one may be stored in the * reg_cache. */ uint64_t mstatus_actual; struct memory_cache_line dram_cache[DRAM_CACHE_SIZE]; /* Number of run-test/idle cycles the target requests we do after each dbus * access. */ unsigned int dtmcontrol_idle; /* This value is incremented every time a dbus access comes back as "busy". * It's used to determine how many run-test/idle cycles to feed the target * in between accesses. */ unsigned int dbus_busy_delay; /* This value is incremented every time we read the debug interrupt as * high. It's used to add extra run-test/idle cycles after setting debug * interrupt high, so ideally we never have to perform a whole extra scan * before the interrupt is cleared. */ unsigned int interrupt_high_delay; bool never_halted; } riscv011_info_t; typedef struct { bool haltnot; bool interrupt; } bits_t; /*** Necessary prototypes. ***/ static int poll_target(struct target *target, bool announce); static int riscv011_poll(struct target *target); static int get_register(struct target *target, riscv_reg_t *value, int regid); /*** Utility functions. ***/ #define DEBUG_LENGTH 264 static riscv011_info_t *get_info(const struct target *target) { struct riscv_info *info = target->arch_info; assert(info); assert(info->version_specific); return info->version_specific; } static unsigned int slot_offset(const struct target *target, slot_t slot) { riscv011_info_t *info = get_info(target); switch (riscv_xlen(target)) { case 32: switch (slot) { case SLOT0: return 4; case SLOT1: return 5; case SLOT_LAST: return info->dramsize-1; } break; case 64: switch (slot) { case SLOT0: return 4; case SLOT1: return 6; case SLOT_LAST: return info->dramsize-2; } } LOG_ERROR("slot_offset called with xlen=%d, slot=%d", riscv_xlen(target), slot); assert(0); return 0; /* Silence -Werror=return-type */ } static uint32_t load_slot(const struct target *target, unsigned int dest, slot_t slot) { unsigned int offset = DEBUG_RAM_START + 4 * slot_offset(target, slot); return load(target, dest, ZERO, offset); } static uint32_t store_slot(const struct target *target, unsigned int src, slot_t slot) { unsigned int offset = DEBUG_RAM_START + 4 * slot_offset(target, slot); return store(target, src, ZERO, offset); } static uint16_t dram_address(unsigned int index) { if (index < 0x10) return index; else return 0x40 + index - 0x10; } static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { struct scan_field field; uint8_t in_value[4]; uint8_t out_value[4] = { 0 }; buf_set_u32(out_value, 0, 32, out); jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE); field.num_bits = 32; field.out_value = out_value; field.in_value = in_value; jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); /* Always return to dbus. */ jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("failed jtag scan: %d", retval); return retval; } uint32_t in = buf_get_u32(field.in_value, 0, 32); LOG_DEBUG("DTMCONTROL: 0x%x -> 0x%x", out, in); return in; } static uint32_t idcode_scan(struct target *target) { struct scan_field field; uint8_t in_value[4]; jtag_add_ir_scan(target->tap, &select_idcode, TAP_IDLE); field.num_bits = 32; field.out_value = NULL; field.in_value = in_value; jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("failed jtag scan: %d", retval); return retval; } /* Always return to dbus. */ jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); uint32_t in = buf_get_u32(field.in_value, 0, 32); LOG_DEBUG("IDCODE: 0x0 -> 0x%x", in); return in; } static void increase_dbus_busy_delay(struct target *target) { riscv011_info_t *info = get_info(target); info->dbus_busy_delay += info->dbus_busy_delay / 10 + 1; LOG_DEBUG("dtmcontrol_idle=%d, dbus_busy_delay=%d, interrupt_high_delay=%d", info->dtmcontrol_idle, info->dbus_busy_delay, info->interrupt_high_delay); dtmcontrol_scan(target, DTMCONTROL_DBUS_RESET); } static void increase_interrupt_high_delay(struct target *target) { riscv011_info_t *info = get_info(target); info->interrupt_high_delay += info->interrupt_high_delay / 10 + 1; LOG_DEBUG("dtmcontrol_idle=%d, dbus_busy_delay=%d, interrupt_high_delay=%d", info->dtmcontrol_idle, info->dbus_busy_delay, info->interrupt_high_delay); } static void add_dbus_scan(const struct target *target, struct scan_field *field, uint8_t *out_value, uint8_t *in_value, dbus_op_t op, uint16_t address, uint64_t data) { riscv011_info_t *info = get_info(target); RISCV_INFO(r); if (r->reset_delays_wait >= 0) { r->reset_delays_wait--; if (r->reset_delays_wait < 0) { info->dbus_busy_delay = 0; info->interrupt_high_delay = 0; } } field->num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE; field->in_value = in_value; field->out_value = out_value; buf_set_u64(out_value, DBUS_OP_START, DBUS_OP_SIZE, op); buf_set_u64(out_value, DBUS_DATA_START, DBUS_DATA_SIZE, data); buf_set_u64(out_value, DBUS_ADDRESS_START, info->addrbits, address); jtag_add_dr_scan(target->tap, 1, field, TAP_IDLE); int idle_count = info->dtmcontrol_idle + info->dbus_busy_delay; if (data & DMCONTROL_INTERRUPT) idle_count += info->interrupt_high_delay; if (idle_count) jtag_add_runtest(idle_count, TAP_IDLE); } static void dump_field(const struct scan_field *field) { static const char * const op_string[] = {"nop", "r", "w", "?"}; static const char * const status_string[] = {"+", "?", "F", "b"}; if (debug_level < LOG_LVL_DEBUG) return; uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits); unsigned int out_op = (out >> DBUS_OP_START) & ((1 << DBUS_OP_SIZE) - 1); char out_interrupt = ((out >> DBUS_DATA_START) & DMCONTROL_INTERRUPT) ? 'i' : '.'; char out_haltnot = ((out >> DBUS_DATA_START) & DMCONTROL_HALTNOT) ? 'h' : '.'; unsigned int out_data = out >> 2; unsigned int out_address = out >> DBUS_ADDRESS_START; uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits); unsigned int in_op = (in >> DBUS_OP_START) & ((1 << DBUS_OP_SIZE) - 1); char in_interrupt = ((in >> DBUS_DATA_START) & DMCONTROL_INTERRUPT) ? 'i' : '.'; char in_haltnot = ((in >> DBUS_DATA_START) & DMCONTROL_HALTNOT) ? 'h' : '.'; unsigned int in_data = in >> 2; unsigned int in_address = in >> DBUS_ADDRESS_START; log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, "scan", "%db %s %c%c:%08x @%02x -> %s %c%c:%08x @%02x", field->num_bits, op_string[out_op], out_interrupt, out_haltnot, out_data, out_address, status_string[in_op], in_interrupt, in_haltnot, in_data, in_address); } static dbus_status_t dbus_scan(struct target *target, uint16_t *address_in, uint64_t *data_in, dbus_op_t op, uint16_t address_out, uint64_t data_out) { riscv011_info_t *info = get_info(target); uint8_t in[8] = {0}; uint8_t out[8] = {0}; struct scan_field field = { .num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE, .out_value = out, .in_value = in }; assert(info->addrbits != 0); buf_set_u64(out, DBUS_OP_START, DBUS_OP_SIZE, op); buf_set_u64(out, DBUS_DATA_START, DBUS_DATA_SIZE, data_out); buf_set_u64(out, DBUS_ADDRESS_START, info->addrbits, address_out); /* Assume dbus is already selected. */ jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); int idle_count = info->dtmcontrol_idle + info->dbus_busy_delay; if (idle_count) jtag_add_runtest(idle_count, TAP_IDLE); int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("dbus_scan failed jtag scan"); return DBUS_STATUS_FAILED; } if (data_in) *data_in = buf_get_u64(in, DBUS_DATA_START, DBUS_DATA_SIZE); if (address_in) *address_in = buf_get_u32(in, DBUS_ADDRESS_START, info->addrbits); dump_field(&field); return buf_get_u32(in, DBUS_OP_START, DBUS_OP_SIZE); } static uint64_t dbus_read(struct target *target, uint16_t address) { uint64_t value; dbus_status_t status; uint16_t address_in; /* If the previous read/write was to the same address, we will get the read data * from the previous access. * While somewhat nonintuitive, this is an efficient way to get the data. */ unsigned i = 0; do { status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, address, 0); if (status == DBUS_STATUS_BUSY) increase_dbus_busy_delay(target); if (status == DBUS_STATUS_FAILED) { LOG_ERROR("dbus_read(0x%x) failed!", address); return 0; } } while (((status == DBUS_STATUS_BUSY) || (address_in != address)) && i++ < 256); if (status != DBUS_STATUS_SUCCESS) LOG_ERROR("failed read from 0x%x; value=0x%" PRIx64 ", status=%d\n", address, value, status); return value; } static void dbus_write(struct target *target, uint16_t address, uint64_t value) { dbus_status_t status = DBUS_STATUS_BUSY; unsigned i = 0; while (status == DBUS_STATUS_BUSY && i++ < 256) { status = dbus_scan(target, NULL, NULL, DBUS_OP_WRITE, address, value); if (status == DBUS_STATUS_BUSY) increase_dbus_busy_delay(target); } if (status != DBUS_STATUS_SUCCESS) LOG_ERROR("failed to write 0x%" PRIx64 " to 0x%x; status=%d\n", value, address, status); } /*** scans "class" ***/ typedef struct { /* Number of scans that space is reserved for. */ unsigned int scan_count; /* Size reserved in memory for each scan, in bytes. */ unsigned int scan_size; unsigned int next_scan; uint8_t *in; uint8_t *out; struct scan_field *field; const struct target *target; } scans_t; static scans_t *scans_new(struct target *target, unsigned int scan_count) { scans_t *scans = malloc(sizeof(scans_t)); if (!scans) goto error0; scans->scan_count = scan_count; /* This code also gets called before xlen is detected. */ if (riscv_xlen(target)) scans->scan_size = 2 + riscv_xlen(target) / 8; else scans->scan_size = 2 + 128 / 8; scans->next_scan = 0; scans->in = calloc(scans->scan_size, scans->scan_count); if (!scans->in) goto error1; scans->out = calloc(scans->scan_size, scans->scan_count); if (!scans->out) goto error2; scans->field = calloc(scans->scan_count, sizeof(struct scan_field)); if (!scans->field) goto error3; scans->target = target; return scans; error3: free(scans->out); error2: free(scans->in); error1: free(scans); error0: return NULL; } static scans_t *scans_delete(scans_t *scans) { assert(scans); free(scans->field); free(scans->out); free(scans->in); free(scans); return NULL; } static void scans_reset(scans_t *scans) { scans->next_scan = 0; } static void scans_dump(scans_t *scans) { for (unsigned int i = 0; i < scans->next_scan; i++) dump_field(&scans->field[i]); } static int scans_execute(scans_t *scans) { int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("failed jtag scan: %d", retval); return retval; } scans_dump(scans); return ERROR_OK; } /** Add a 32-bit dbus write to the scans structure. */ static void scans_add_write32(scans_t *scans, uint16_t address, uint32_t data, bool set_interrupt) { const unsigned int i = scans->next_scan; int data_offset = scans->scan_size * i; add_dbus_scan(scans->target, &scans->field[i], scans->out + data_offset, scans->in + data_offset, DBUS_OP_WRITE, address, (set_interrupt ? DMCONTROL_INTERRUPT : 0) | DMCONTROL_HALTNOT | data); scans->next_scan++; assert(scans->next_scan <= scans->scan_count); } /** Add a 32-bit dbus write for an instruction that jumps to the beginning of * debug RAM. */ static void scans_add_write_jump(scans_t *scans, uint16_t address, bool set_interrupt) { scans_add_write32(scans, address, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*address))), set_interrupt); } /** Add a 32-bit dbus write for an instruction that loads from the indicated * slot. */ static void scans_add_write_load(scans_t *scans, uint16_t address, unsigned int reg, slot_t slot, bool set_interrupt) { scans_add_write32(scans, address, load_slot(scans->target, reg, slot), set_interrupt); } /** Add a 32-bit dbus write for an instruction that stores to the indicated * slot. */ static void scans_add_write_store(scans_t *scans, uint16_t address, unsigned int reg, slot_t slot, bool set_interrupt) { scans_add_write32(scans, address, store_slot(scans->target, reg, slot), set_interrupt); } /** Add a 32-bit dbus read. */ static void scans_add_read32(scans_t *scans, uint16_t address, bool set_interrupt) { assert(scans->next_scan < scans->scan_count); const unsigned int i = scans->next_scan; int data_offset = scans->scan_size * i; add_dbus_scan(scans->target, &scans->field[i], scans->out + data_offset, scans->in + data_offset, DBUS_OP_READ, address, (set_interrupt ? DMCONTROL_INTERRUPT : 0) | DMCONTROL_HALTNOT); scans->next_scan++; } /** Add one or more scans to read the indicated slot. */ static void scans_add_read(scans_t *scans, slot_t slot, bool set_interrupt) { const struct target *target = scans->target; switch (riscv_xlen(target)) { case 32: scans_add_read32(scans, slot_offset(target, slot), set_interrupt); break; case 64: scans_add_read32(scans, slot_offset(target, slot), false); scans_add_read32(scans, slot_offset(target, slot) + 1, set_interrupt); break; } } static uint32_t scans_get_u32(scans_t *scans, unsigned int index, unsigned first, unsigned num) { return buf_get_u32(scans->in + scans->scan_size * index, first, num); } static uint64_t scans_get_u64(scans_t *scans, unsigned int index, unsigned first, unsigned num) { return buf_get_u64(scans->in + scans->scan_size * index, first, num); } /*** end of scans class ***/ static uint32_t dram_read32(struct target *target, unsigned int index) { uint16_t address = dram_address(index); uint32_t value = dbus_read(target, address); return value; } static void dram_write32(struct target *target, unsigned int index, uint32_t value, bool set_interrupt) { uint64_t dbus_value = DMCONTROL_HALTNOT | value; if (set_interrupt) dbus_value |= DMCONTROL_INTERRUPT; dbus_write(target, dram_address(index), dbus_value); } /** Read the haltnot and interrupt bits. */ static bits_t read_bits(struct target *target) { uint64_t value; dbus_status_t status; uint16_t address_in; riscv011_info_t *info = get_info(target); bits_t err_result = { .haltnot = 0, .interrupt = 0 }; do { unsigned i = 0; do { status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, 0, 0); if (status == DBUS_STATUS_BUSY) { if (address_in == (1<<info->addrbits) - 1 && value == (1ULL<<DBUS_DATA_SIZE) - 1) { LOG_ERROR("TDO seems to be stuck high."); return err_result; } increase_dbus_busy_delay(target); } else if (status == DBUS_STATUS_FAILED) { /* TODO: return an actual error */ return err_result; } } while (status == DBUS_STATUS_BUSY && i++ < 256); if (i >= 256) { LOG_ERROR("Failed to read from 0x%x; status=%d", address_in, status); return err_result; } } while (address_in > 0x10 && address_in != DMCONTROL); bits_t result = { .haltnot = get_field(value, DMCONTROL_HALTNOT), .interrupt = get_field(value, DMCONTROL_INTERRUPT) }; return result; } static int wait_for_debugint_clear(struct target *target, bool ignore_first) { time_t start = time(NULL); if (ignore_first) { /* Throw away the results of the first read, since they'll contain the * result of the read that happened just before debugint was set. * (Assuming the last scan before calling this function was one that * sets debugint.) */ read_bits(target); } while (1) { bits_t bits = read_bits(target); if (!bits.interrupt) return ERROR_OK; if (time(NULL) - start > riscv_command_timeout_sec) { LOG_ERROR("Timed out waiting for debug int to clear." "Increase timeout with riscv set_command_timeout_sec."); return ERROR_FAIL; } } } static int dram_check32(struct target *target, unsigned int index, uint32_t expected) { uint16_t address = dram_address(index); uint32_t actual = dbus_read(target, address); if (expected != actual) { LOG_ERROR("Wrote 0x%x to Debug RAM at %d, but read back 0x%x", expected, index, actual); return ERROR_FAIL; } return ERROR_OK; } static void cache_set32(struct target *target, unsigned int index, uint32_t data) { riscv011_info_t *info = get_info(target); if (info->dram_cache[index].valid && info->dram_cache[index].data == data) { /* This is already preset on the target. */ LOG_DEBUG("cache[0x%x] = 0x%08x: DASM(0x%x) (hit)", index, data, data); return; } LOG_DEBUG("cache[0x%x] = 0x%08x: DASM(0x%x)", index, data, data); info->dram_cache[index].data = data; info->dram_cache[index].valid = true; info->dram_cache[index].dirty = true; } static void cache_set(struct target *target, slot_t slot, uint64_t data) { unsigned int offset = slot_offset(target, slot); cache_set32(target, offset, data); if (riscv_xlen(target) > 32) cache_set32(target, offset + 1, data >> 32); } static void cache_set_jump(struct target *target, unsigned int index) { cache_set32(target, index, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*index)))); } static void cache_set_load(struct target *target, unsigned int index, unsigned int reg, slot_t slot) { uint16_t offset = DEBUG_RAM_START + 4 * slot_offset(target, slot); cache_set32(target, index, load(target, reg, ZERO, offset)); } static void cache_set_store(struct target *target, unsigned int index, unsigned int reg, slot_t slot) { uint16_t offset = DEBUG_RAM_START + 4 * slot_offset(target, slot); cache_set32(target, index, store(target, reg, ZERO, offset)); } static void dump_debug_ram(struct target *target) { for (unsigned int i = 0; i < DRAM_CACHE_SIZE; i++) { uint32_t value = dram_read32(target, i); LOG_ERROR("Debug RAM 0x%x: 0x%08x", i, value); } } /* Call this if the code you just ran writes to debug RAM entries 0 through 3. */ static void cache_invalidate(struct target *target) { riscv011_info_t *info = get_info(target); for (unsigned int i = 0; i < info->dramsize; i++) { info->dram_cache[i].valid = false; info->dram_cache[i].dirty = false; } } /* Called by cache_write() after the program has run. Also call this if you're * running programs without calling cache_write(). */ static void cache_clean(struct target *target) { riscv011_info_t *info = get_info(target); for (unsigned int i = 0; i < info->dramsize; i++) { if (i >= 4) info->dram_cache[i].valid = false; info->dram_cache[i].dirty = false; } } static int cache_check(struct target *target) { riscv011_info_t *info = get_info(target); int error = 0; for (unsigned int i = 0; i < info->dramsize; i++) { if (info->dram_cache[i].valid && !info->dram_cache[i].dirty) { if (dram_check32(target, i, info->dram_cache[i].data) != ERROR_OK) error++; } } if (error) { dump_debug_ram(target); return ERROR_FAIL; } return ERROR_OK; } /** Write cache to the target, and optionally run the program. * Then read the value at address into the cache, assuming address < 128. */ #define CACHE_NO_READ 128 static int cache_write(struct target *target, unsigned int address, bool run) { LOG_DEBUG("enter"); riscv011_info_t *info = get_info(target); scans_t *scans = scans_new(target, info->dramsize + 2); if (!scans) return ERROR_FAIL; unsigned int last = info->dramsize; for (unsigned int i = 0; i < info->dramsize; i++) { if (info->dram_cache[i].dirty) last = i; } if (last == info->dramsize) { /* Nothing needs to be written to RAM. */ dbus_write(target, DMCONTROL, DMCONTROL_HALTNOT | (run ? DMCONTROL_INTERRUPT : 0)); } else { for (unsigned int i = 0; i < info->dramsize; i++) { if (info->dram_cache[i].dirty) { bool set_interrupt = (i == last && run); scans_add_write32(scans, i, info->dram_cache[i].data, set_interrupt); } } } if (run || address < CACHE_NO_READ) { /* Throw away the results of the first read, since it'll contain the * result of the read that happened just before debugint was set. */ scans_add_read32(scans, address, false); /* This scan contains the results of the read the caller requested, as * well as an interrupt bit worth looking at. */ scans_add_read32(scans, address, false); } int retval = scans_execute(scans); if (retval != ERROR_OK) { scans_delete(scans); LOG_ERROR("JTAG execute failed."); return retval; } int errors = 0; for (unsigned int i = 0; i < scans->next_scan; i++) { dbus_status_t status = scans_get_u32(scans, i, DBUS_OP_START, DBUS_OP_SIZE); switch (status) { case DBUS_STATUS_SUCCESS: break; case DBUS_STATUS_FAILED: LOG_ERROR("Debug RAM write failed. Hardware error?"); scans_delete(scans); return ERROR_FAIL; case DBUS_STATUS_BUSY: errors++; break; default: LOG_ERROR("Got invalid bus access status: %d", status); scans_delete(scans); return ERROR_FAIL; } } if (errors) { increase_dbus_busy_delay(target); /* Try again, using the slow careful code. * Write all RAM, just to be extra cautious. */ for (unsigned int i = 0; i < info->dramsize; i++) { if (i == last && run) dram_write32(target, last, info->dram_cache[last].data, true); else dram_write32(target, i, info->dram_cache[i].data, false); info->dram_cache[i].dirty = false; } if (run) cache_clean(target); if (wait_for_debugint_clear(target, true) != ERROR_OK) { LOG_ERROR("Debug interrupt didn't clear."); dump_debug_ram(target); scans_delete(scans); return ERROR_FAIL; } } else { if (run) { cache_clean(target); } else { for (unsigned int i = 0; i < info->dramsize; i++) info->dram_cache[i].dirty = false; } if (run || address < CACHE_NO_READ) { int interrupt = scans_get_u32(scans, scans->next_scan-1, DBUS_DATA_START + 33, 1); if (interrupt) { increase_interrupt_high_delay(target); /* Slow path wait for it to clear. */ if (wait_for_debugint_clear(target, false) != ERROR_OK) { LOG_ERROR("Debug interrupt didn't clear."); dump_debug_ram(target); scans_delete(scans); return ERROR_FAIL; } } else { /* We read a useful value in that last scan. */ unsigned int read_addr = scans_get_u32(scans, scans->next_scan-1, DBUS_ADDRESS_START, info->addrbits); if (read_addr != address) { LOG_INFO("Got data from 0x%x but expected it from 0x%x", read_addr, address); } info->dram_cache[read_addr].data = scans_get_u32(scans, scans->next_scan-1, DBUS_DATA_START, 32); info->dram_cache[read_addr].valid = true; } } } scans_delete(scans); LOG_DEBUG("exit"); return ERROR_OK; } static uint32_t cache_get32(struct target *target, unsigned int address) { riscv011_info_t *info = get_info(target); if (!info->dram_cache[address].valid) { info->dram_cache[address].data = dram_read32(target, address); info->dram_cache[address].valid = true; } return info->dram_cache[address].data; } static uint64_t cache_get(struct target *target, slot_t slot) { unsigned int offset = slot_offset(target, slot); uint64_t value = cache_get32(target, offset); if (riscv_xlen(target) > 32) value |= ((uint64_t) cache_get32(target, offset + 1)) << 32; return value; } /* Write instruction that jumps from the specified word in Debug RAM to resume * in Debug ROM. */ static void dram_write_jump(struct target *target, unsigned int index, bool set_interrupt) { dram_write32(target, index, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*index))), set_interrupt); } static int wait_for_state(struct target *target, enum target_state state) { time_t start = time(NULL); while (1) { int result = riscv011_poll(target); if (result != ERROR_OK) return result; if (target->state == state) return ERROR_OK; if (time(NULL) - start > riscv_command_timeout_sec) { LOG_ERROR("Timed out waiting for state %d. " "Increase timeout with riscv set_command_timeout_sec.", state); return ERROR_FAIL; } } } static int read_remote_csr(struct target *target, uint64_t *value, uint32_t csr) { riscv011_info_t *info = get_info(target); cache_set32(target, 0, csrr(S0, csr)); cache_set_store(target, 1, S0, SLOT0); cache_set_jump(target, 2); if (cache_write(target, 4, true) != ERROR_OK) return ERROR_FAIL; *value = cache_get(target, SLOT0); LOG_DEBUG("csr 0x%x = 0x%" PRIx64, csr, *value); uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { LOG_WARNING("Got exception 0x%x when reading %s", exception, gdb_regno_name(GDB_REGNO_CSR0 + csr)); *value = ~0; return ERROR_FAIL; } return ERROR_OK; } static int write_remote_csr(struct target *target, uint32_t csr, uint64_t value) { LOG_DEBUG("csr 0x%x <- 0x%" PRIx64, csr, value); cache_set_load(target, 0, S0, SLOT0); cache_set32(target, 1, csrw(S0, csr)); cache_set_jump(target, 2); cache_set(target, SLOT0, value); if (cache_write(target, 4, true) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int write_gpr(struct target *target, unsigned int gpr, uint64_t value) { cache_set_load(target, 0, gpr, SLOT0); cache_set_jump(target, 1); cache_set(target, SLOT0, value); if (cache_write(target, 4, true) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int maybe_read_tselect(struct target *target) { riscv011_info_t *info = get_info(target); if (info->tselect_dirty) { int result = read_remote_csr(target, &info->tselect, CSR_TSELECT); if (result != ERROR_OK) return result; info->tselect_dirty = false; } return ERROR_OK; } static int maybe_write_tselect(struct target *target) { riscv011_info_t *info = get_info(target); if (!info->tselect_dirty) { int result = write_remote_csr(target, CSR_TSELECT, info->tselect); if (result != ERROR_OK) return result; info->tselect_dirty = true; } return ERROR_OK; } static int execute_resume(struct target *target, bool step) { riscv011_info_t *info = get_info(target); LOG_DEBUG("step=%d", step); maybe_write_tselect(target); /* TODO: check if dpc is dirty (which also is true if an exception was hit * at any time) */ cache_set_load(target, 0, S0, SLOT0); cache_set32(target, 1, csrw(S0, CSR_DPC)); cache_set_jump(target, 2); cache_set(target, SLOT0, info->dpc); if (cache_write(target, 4, true) != ERROR_OK) return ERROR_FAIL; struct reg *mstatus_reg = &target->reg_cache->reg_list[GDB_REGNO_MSTATUS]; if (mstatus_reg->valid) { uint64_t mstatus_user = buf_get_u64(mstatus_reg->value, 0, riscv_xlen(target)); if (mstatus_user != info->mstatus_actual) { cache_set_load(target, 0, S0, SLOT0); cache_set32(target, 1, csrw(S0, CSR_MSTATUS)); cache_set_jump(target, 2); cache_set(target, SLOT0, mstatus_user); if (cache_write(target, 4, true) != ERROR_OK) return ERROR_FAIL; } } info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm); info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks); info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku); info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1); info->dcsr &= ~DCSR_HALT; if (step) info->dcsr |= DCSR_STEP; else info->dcsr &= ~DCSR_STEP; dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false); dram_write32(target, 1, csrw(S0, CSR_DCSR), false); dram_write32(target, 2, fence_i(), false); dram_write_jump(target, 3, false); /* Write DCSR value, set interrupt and clear haltnot. */ uint64_t dbus_value = DMCONTROL_INTERRUPT | info->dcsr; dbus_write(target, dram_address(4), dbus_value); cache_invalidate(target); if (wait_for_debugint_clear(target, true) != ERROR_OK) { LOG_ERROR("Debug interrupt didn't clear."); return ERROR_FAIL; } target->state = TARGET_RUNNING; register_cache_invalidate(target->reg_cache); return ERROR_OK; } /* Execute a step, and wait for reentry into Debug Mode. */ static int full_step(struct target *target, bool announce) { int result = execute_resume(target, true); if (result != ERROR_OK) return result; time_t start = time(NULL); while (1) { result = poll_target(target, announce); if (result != ERROR_OK) return result; if (target->state != TARGET_DEBUG_RUNNING) break; if (time(NULL) - start > riscv_command_timeout_sec) { LOG_ERROR("Timed out waiting for step to complete." "Increase timeout with riscv set_command_timeout_sec"); return ERROR_FAIL; } } return ERROR_OK; } static int resume(struct target *target, int debug_execution, bool step) { if (debug_execution) { LOG_ERROR("TODO: debug_execution is true"); return ERROR_FAIL; } return execute_resume(target, step); } static uint64_t reg_cache_get(struct target *target, unsigned int number) { struct reg *r = &target->reg_cache->reg_list[number]; if (!r->valid) { LOG_ERROR("Register cache entry for %d is invalid!", number); assert(r->valid); } uint64_t value = buf_get_u64(r->value, 0, r->size); LOG_DEBUG("%s = 0x%" PRIx64, r->name, value); return value; } static void reg_cache_set(struct target *target, unsigned int number, uint64_t value) { struct reg *r = &target->reg_cache->reg_list[number]; LOG_DEBUG("%s <= 0x%" PRIx64, r->name, value); r->valid = true; buf_set_u64(r->value, 0, r->size, value); } static int update_mstatus_actual(struct target *target) { struct reg *mstatus_reg = &target->reg_cache->reg_list[GDB_REGNO_MSTATUS]; if (mstatus_reg->valid) { /* We previously made it valid. */ return ERROR_OK; } /* Force reading the register. In that process mstatus_actual will be * updated. */ riscv_reg_t mstatus; return get_register(target, &mstatus, GDB_REGNO_MSTATUS); } /*** OpenOCD target functions. ***/ static int register_read(struct target *target, riscv_reg_t *value, int regnum) { riscv011_info_t *info = get_info(target); if (regnum >= GDB_REGNO_CSR0 && regnum <= GDB_REGNO_CSR4095) { cache_set32(target, 0, csrr(S0, regnum - GDB_REGNO_CSR0)); cache_set_store(target, 1, S0, SLOT0); cache_set_jump(target, 2); } else { LOG_ERROR("Don't know how to read register %d", regnum); return ERROR_FAIL; } if (cache_write(target, 4, true) != ERROR_OK) return ERROR_FAIL; uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { LOG_WARNING("Got exception 0x%x when reading %s", exception, gdb_regno_name(regnum)); *value = ~0; return ERROR_FAIL; } *value = cache_get(target, SLOT0); LOG_DEBUG("reg[%d]=0x%" PRIx64, regnum, *value); if (regnum == GDB_REGNO_MSTATUS) info->mstatus_actual = *value; return ERROR_OK; } /* Write the register. No caching or games. */ static int register_write(struct target *target, unsigned int number, uint64_t value) { riscv011_info_t *info = get_info(target); maybe_write_tselect(target); if (number == S0) { cache_set_load(target, 0, S0, SLOT0); cache_set32(target, 1, csrw(S0, CSR_DSCRATCH0)); cache_set_jump(target, 2); } else if (number == S1) { cache_set_load(target, 0, S0, SLOT0); cache_set_store(target, 1, S0, SLOT_LAST); cache_set_jump(target, 2); } else if (number <= GDB_REGNO_XPR31) { cache_set_load(target, 0, number - GDB_REGNO_ZERO, SLOT0); cache_set_jump(target, 1); } else if (number == GDB_REGNO_PC) { info->dpc = value; return ERROR_OK; } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { int result = update_mstatus_actual(target); if (result != ERROR_OK) return result; unsigned i = 0; if ((info->mstatus_actual & MSTATUS_FS) == 0) { info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1); cache_set_load(target, i++, S0, SLOT1); cache_set32(target, i++, csrw(S0, CSR_MSTATUS)); cache_set(target, SLOT1, info->mstatus_actual); } if (riscv_xlen(target) == 32) cache_set32(target, i++, flw(number - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); else cache_set32(target, i++, fld(number - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); cache_set_jump(target, i++); } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { cache_set_load(target, 0, S0, SLOT0); cache_set32(target, 1, csrw(S0, number - GDB_REGNO_CSR0)); cache_set_jump(target, 2); if (number == GDB_REGNO_MSTATUS) info->mstatus_actual = value; } else if (number == GDB_REGNO_PRIV) { info->dcsr = set_field(info->dcsr, DCSR_PRV, value); return ERROR_OK; } else { LOG_ERROR("Don't know how to write register %d", number); return ERROR_FAIL; } cache_set(target, SLOT0, value); if (cache_write(target, info->dramsize - 1, true) != ERROR_OK) return ERROR_FAIL; uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { LOG_WARNING("Got exception 0x%x when writing %s", exception, gdb_regno_name(number)); return ERROR_FAIL; } return ERROR_OK; } static int get_register(struct target *target, riscv_reg_t *value, int regid) { riscv011_info_t *info = get_info(target); maybe_write_tselect(target); if (regid <= GDB_REGNO_XPR31) { *value = reg_cache_get(target, regid); } else if (regid == GDB_REGNO_PC) { *value = info->dpc; } else if (regid >= GDB_REGNO_FPR0 && regid <= GDB_REGNO_FPR31) { int result = update_mstatus_actual(target); if (result != ERROR_OK) return result; unsigned i = 0; if ((info->mstatus_actual & MSTATUS_FS) == 0) { info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1); cache_set_load(target, i++, S0, SLOT1); cache_set32(target, i++, csrw(S0, CSR_MSTATUS)); cache_set(target, SLOT1, info->mstatus_actual); } if (riscv_xlen(target) == 32) cache_set32(target, i++, fsw(regid - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); else cache_set32(target, i++, fsd(regid - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); cache_set_jump(target, i++); if (cache_write(target, 4, true) != ERROR_OK) return ERROR_FAIL; } else if (regid == GDB_REGNO_PRIV) { *value = get_field(info->dcsr, DCSR_PRV); } else { int result = register_read(target, value, regid); if (result != ERROR_OK) return result; } if (regid == GDB_REGNO_MSTATUS) target->reg_cache->reg_list[regid].valid = true; return ERROR_OK; } static int set_register(struct target *target, int regid, uint64_t value) { return register_write(target, regid, value); } static int halt(struct target *target) { LOG_DEBUG("riscv_halt()"); jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); cache_set32(target, 0, csrsi(CSR_DCSR, DCSR_HALT)); cache_set32(target, 1, csrr(S0, CSR_MHARTID)); cache_set32(target, 2, sw(S0, ZERO, SETHALTNOT)); cache_set_jump(target, 3); if (cache_write(target, 4, true) != ERROR_OK) { LOG_ERROR("cache_write() failed."); return ERROR_FAIL; } return ERROR_OK; } static void deinit_target(struct target *target) { LOG_DEBUG("riscv_deinit_target()"); struct riscv_info *info = target->arch_info; if (!info) return; free(info->version_specific); info->version_specific = NULL; } static int strict_step(struct target *target, bool announce) { LOG_DEBUG("enter"); struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { riscv_remove_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } int result = full_step(target, announce); if (result != ERROR_OK) return result; watchpoint = target->watchpoints; while (watchpoint) { riscv_add_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } return ERROR_OK; } static int step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); if (!current) { if (riscv_xlen(target) > 32) { LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.", riscv_xlen(target)); } int result = register_write(target, GDB_REGNO_PC, address); if (result != ERROR_OK) return result; } if (handle_breakpoints) { int result = strict_step(target, true); if (result != ERROR_OK) return result; } else { return full_step(target, false); } return ERROR_OK; } static int examine(struct target *target) { /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ uint32_t dtmcontrol = dtmcontrol_scan(target, 0); LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); LOG_DEBUG(" addrbits=%d", get_field(dtmcontrol, DTMCONTROL_ADDRBITS)); LOG_DEBUG(" version=%d", get_field(dtmcontrol, DTMCONTROL_VERSION)); LOG_DEBUG(" idle=%d", get_field(dtmcontrol, DTMCONTROL_IDLE)); if (dtmcontrol == 0) { LOG_ERROR("dtmcontrol is 0. Check JTAG connectivity/board power."); return ERROR_FAIL; } if (get_field(dtmcontrol, DTMCONTROL_VERSION) != 0) { LOG_ERROR("Unsupported DTM version %d. (dtmcontrol=0x%x)", get_field(dtmcontrol, DTMCONTROL_VERSION), dtmcontrol); return ERROR_FAIL; } RISCV_INFO(r); riscv011_info_t *info = get_info(target); info->addrbits = get_field(dtmcontrol, DTMCONTROL_ADDRBITS); info->dtmcontrol_idle = get_field(dtmcontrol, DTMCONTROL_IDLE); if (info->dtmcontrol_idle == 0) { /* Some old SiFive cores don't set idle but need it to be 1. */ uint32_t idcode = idcode_scan(target); if (idcode == 0x10e31913) info->dtmcontrol_idle = 1; } uint32_t dminfo = dbus_read(target, DMINFO); LOG_DEBUG("dminfo: 0x%08x", dminfo); LOG_DEBUG(" abussize=0x%x", get_field(dminfo, DMINFO_ABUSSIZE)); LOG_DEBUG(" serialcount=0x%x", get_field(dminfo, DMINFO_SERIALCOUNT)); LOG_DEBUG(" access128=%d", get_field(dminfo, DMINFO_ACCESS128)); LOG_DEBUG(" access64=%d", get_field(dminfo, DMINFO_ACCESS64)); LOG_DEBUG(" access32=%d", get_field(dminfo, DMINFO_ACCESS32)); LOG_DEBUG(" access16=%d", get_field(dminfo, DMINFO_ACCESS16)); LOG_DEBUG(" access8=%d", get_field(dminfo, DMINFO_ACCESS8)); LOG_DEBUG(" dramsize=0x%x", get_field(dminfo, DMINFO_DRAMSIZE)); LOG_DEBUG(" authenticated=0x%x", get_field(dminfo, DMINFO_AUTHENTICATED)); LOG_DEBUG(" authbusy=0x%x", get_field(dminfo, DMINFO_AUTHBUSY)); LOG_DEBUG(" authtype=0x%x", get_field(dminfo, DMINFO_AUTHTYPE)); LOG_DEBUG(" version=0x%x", get_field(dminfo, DMINFO_VERSION)); if (get_field(dminfo, DMINFO_VERSION) != 1) { LOG_ERROR("OpenOCD only supports Debug Module version 1, not %d " "(dminfo=0x%x)", get_field(dminfo, DMINFO_VERSION), dminfo); return ERROR_FAIL; } info->dramsize = get_field(dminfo, DMINFO_DRAMSIZE) + 1; if (get_field(dminfo, DMINFO_AUTHTYPE) != 0) { LOG_ERROR("Authentication required by RISC-V core but not " "supported by OpenOCD. dminfo=0x%x", dminfo); return ERROR_FAIL; } /* Pretend this is a 32-bit system until we have found out the true value. */ r->xlen = 32; /* Figure out XLEN, and test writing all of Debug RAM while we're at it. */ cache_set32(target, 0, xori(S1, ZERO, -1)); /* 0xffffffff 0xffffffff:ffffffff 0xffffffff:ffffffff:ffffffff:ffffffff */ cache_set32(target, 1, srli(S1, S1, 31)); /* 0x00000001 0x00000001:ffffffff 0x00000001:ffffffff:ffffffff:ffffffff */ cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START)); cache_set32(target, 3, srli(S1, S1, 31)); /* 0x00000000 0x00000000:00000003 0x00000000:00000003:ffffffff:ffffffff */ cache_set32(target, 4, sw(S1, ZERO, DEBUG_RAM_START + 4)); cache_set_jump(target, 5); for (unsigned i = 6; i < info->dramsize; i++) cache_set32(target, i, i * 0x01020304); cache_write(target, 0, false); /* Check that we can actually read/write dram. */ if (cache_check(target) != ERROR_OK) return ERROR_FAIL; cache_write(target, 0, true); cache_invalidate(target); uint32_t word0 = cache_get32(target, 0); uint32_t word1 = cache_get32(target, 1); struct riscv_info *generic_info = riscv_info(target); if (word0 == 1 && word1 == 0) { generic_info->xlen = 32; } else if (word0 == 0xffffffff && word1 == 3) { generic_info->xlen = 64; } else if (word0 == 0xffffffff && word1 == 0xffffffff) { generic_info->xlen = 128; } else { uint32_t exception = cache_get32(target, info->dramsize-1); LOG_ERROR("Failed to discover xlen; word0=0x%x, word1=0x%x, exception=0x%x", word0, word1, exception); dump_debug_ram(target); return ERROR_FAIL; } LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target)); if (read_remote_csr(target, &r->misa, CSR_MISA) != ERROR_OK) { const unsigned old_csr_misa = 0xf10; LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA, old_csr_misa); if (read_remote_csr(target, &r->misa, old_csr_misa) != ERROR_OK) { /* Maybe this is an old core that still has $misa at the old * address. */ LOG_ERROR("Failed to read misa at 0x%x.", old_csr_misa); return ERROR_FAIL; } } /* Update register list to match discovered XLEN/supported extensions. */ riscv_init_registers(target); info->never_halted = true; int result = riscv011_poll(target); if (result != ERROR_OK) return result; target_set_examined(target); riscv_set_current_hartid(target, 0); for (size_t i = 0; i < 32; ++i) reg_cache_set(target, i, -1); LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64, riscv_xlen(target), r->misa); return ERROR_OK; } static riscv_error_t handle_halt_routine(struct target *target) { riscv011_info_t *info = get_info(target); scans_t *scans = scans_new(target, 256); if (!scans) return RE_FAIL; /* Read all GPRs as fast as we can, because gdb is going to ask for them * anyway. Reading them one at a time is much slower. */ /* Write the jump back to address 1. */ scans_add_write_jump(scans, 1, false); for (int reg = 1; reg < 32; reg++) { if (reg == S0 || reg == S1) continue; /* Write store instruction. */ scans_add_write_store(scans, 0, reg, SLOT0, true); /* Read value. */ scans_add_read(scans, SLOT0, false); } /* Write store of s0 at index 1. */ scans_add_write_store(scans, 1, S0, SLOT0, false); /* Write jump at index 2. */ scans_add_write_jump(scans, 2, false); /* Read S1 from debug RAM */ scans_add_write_load(scans, 0, S0, SLOT_LAST, true); /* Read value. */ scans_add_read(scans, SLOT0, false); /* Read S0 from dscratch */ unsigned int csr[] = {CSR_DSCRATCH0, CSR_DPC, CSR_DCSR}; for (unsigned int i = 0; i < ARRAY_SIZE(csr); i++) { scans_add_write32(scans, 0, csrr(S0, csr[i]), true); scans_add_read(scans, SLOT0, false); } /* Final read to get the last value out. */ scans_add_read32(scans, 4, false); int retval = scans_execute(scans); if (retval != ERROR_OK) { LOG_ERROR("JTAG execute failed: %d", retval); goto error; } unsigned int dbus_busy = 0; unsigned int interrupt_set = 0; unsigned result = 0; uint64_t value = 0; reg_cache_set(target, 0, 0); /* The first scan result is the result from something old we don't care * about. */ for (unsigned int i = 1; i < scans->next_scan && dbus_busy == 0; i++) { dbus_status_t status = scans_get_u32(scans, i, DBUS_OP_START, DBUS_OP_SIZE); uint64_t data = scans_get_u64(scans, i, DBUS_DATA_START, DBUS_DATA_SIZE); uint32_t address = scans_get_u32(scans, i, DBUS_ADDRESS_START, info->addrbits); switch (status) { case DBUS_STATUS_SUCCESS: break; case DBUS_STATUS_FAILED: LOG_ERROR("Debug access failed. Hardware error?"); goto error; case DBUS_STATUS_BUSY: dbus_busy++; break; default: LOG_ERROR("Got invalid bus access status: %d", status); goto error; } if (data & DMCONTROL_INTERRUPT) { interrupt_set++; break; } if (address == 4 || address == 5) { unsigned int reg; switch (result) { case 0: reg = 1; break; case 1: reg = 2; break; case 2: reg = 3; break; case 3: reg = 4; break; case 4: reg = 5; break; case 5: reg = 6; break; case 6: reg = 7; break; /* S0 */ /* S1 */ case 7: reg = 10; break; case 8: reg = 11; break; case 9: reg = 12; break; case 10: reg = 13; break; case 11: reg = 14; break; case 12: reg = 15; break; case 13: reg = 16; break; case 14: reg = 17; break; case 15: reg = 18; break; case 16: reg = 19; break; case 17: reg = 20; break; case 18: reg = 21; break; case 19: reg = 22; break; case 20: reg = 23; break; case 21: reg = 24; break; case 22: reg = 25; break; case 23: reg = 26; break; case 24: reg = 27; break; case 25: reg = 28; break; case 26: reg = 29; break; case 27: reg = 30; break; case 28: reg = 31; break; case 29: reg = S1; break; case 30: reg = S0; break; case 31: reg = CSR_DPC; break; case 32: reg = CSR_DCSR; break; default: assert(0); LOG_ERROR("Got invalid register result %d", result); goto error; } if (riscv_xlen(target) == 32) { reg_cache_set(target, reg, data & 0xffffffff); result++; } else if (riscv_xlen(target) == 64) { if (address == 4) { value = data & 0xffffffff; } else if (address == 5) { reg_cache_set(target, reg, ((data & 0xffffffff) << 32) | value); value = 0; result++; } } } } scans_delete(scans); if (dbus_busy) { increase_dbus_busy_delay(target); return RE_AGAIN; } if (interrupt_set) { increase_interrupt_high_delay(target); return RE_AGAIN; } /* TODO: get rid of those 2 variables and talk to the cache directly. */ info->dpc = reg_cache_get(target, CSR_DPC); info->dcsr = reg_cache_get(target, CSR_DCSR); cache_invalidate(target); return RE_OK; error: scans_delete(scans); return RE_FAIL; } static int handle_halt(struct target *target, bool announce) { riscv011_info_t *info = get_info(target); target->state = TARGET_HALTED; riscv_error_t re; do { re = handle_halt_routine(target); } while (re == RE_AGAIN); if (re != RE_OK) { LOG_ERROR("handle_halt_routine failed"); return ERROR_FAIL; } int cause = get_field(info->dcsr, DCSR_CAUSE); switch (cause) { case DCSR_CAUSE_SWBP: target->debug_reason = DBG_REASON_BREAKPOINT; break; case DCSR_CAUSE_HWBP: target->debug_reason = DBG_REASON_WATCHPOINT; break; case DCSR_CAUSE_DEBUGINT: target->debug_reason = DBG_REASON_DBGRQ; break; case DCSR_CAUSE_STEP: target->debug_reason = DBG_REASON_SINGLESTEP; break; case DCSR_CAUSE_HALT: default: LOG_ERROR("Invalid halt cause %d in DCSR (0x%" PRIx64 ")", cause, info->dcsr); } if (info->never_halted) { info->never_halted = false; int result = maybe_read_tselect(target); if (result != ERROR_OK) return result; riscv_enumerate_triggers(target); } if (target->debug_reason == DBG_REASON_BREAKPOINT) { int retval; if (riscv_semihosting(target, &retval) != 0) return retval; } if (announce) target_call_event_callbacks(target, TARGET_EVENT_HALTED); const char *cause_string[] = { "none", "software breakpoint", "hardware trigger", "debug interrupt", "step", "halt" }; /* This is logged to the user so that gdb will show it when a user types * 'monitor reset init'. At that time gdb appears to have the pc cached * still so if a user manually inspects the pc it will still have the old * value. */ LOG_USER("halted at 0x%" PRIx64 " due to %s", info->dpc, cause_string[cause]); return ERROR_OK; } static int poll_target(struct target *target, bool announce) { jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); /* Inhibit debug logging during poll(), which isn't usually interesting and * just fills up the screen/logs with clutter. */ int old_debug_level = debug_level; if (debug_level >= LOG_LVL_DEBUG) debug_level = LOG_LVL_INFO; bits_t bits = read_bits(target); debug_level = old_debug_level; if (bits.haltnot && bits.interrupt) { target->state = TARGET_DEBUG_RUNNING; LOG_DEBUG("debug running"); } else if (bits.haltnot && !bits.interrupt) { if (target->state != TARGET_HALTED) return handle_halt(target, announce); } else if (!bits.haltnot && bits.interrupt) { /* Target is halting. There is no state for that, so don't change anything. */ LOG_DEBUG("halting"); } else if (!bits.haltnot && !bits.interrupt) { target->state = TARGET_RUNNING; } return ERROR_OK; } static int riscv011_poll(struct target *target) { return poll_target(target, true); } static int riscv011_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { RISCV_INFO(r); jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); r->prepped = false; return resume(target, debug_execution, false); } static int assert_reset(struct target *target) { riscv011_info_t *info = get_info(target); /* TODO: Maybe what I implemented here is more like soft_reset_halt()? */ jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); /* The only assumption we can make is that the TAP was reset. */ if (wait_for_debugint_clear(target, true) != ERROR_OK) { LOG_ERROR("Debug interrupt didn't clear."); return ERROR_FAIL; } /* Not sure what we should do when there are multiple cores. * Here just reset the single hart we're talking to. */ info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm); info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks); info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku); info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1); info->dcsr |= DCSR_HALT; if (target->reset_halt) info->dcsr |= DCSR_NDRESET; else info->dcsr |= DCSR_FULLRESET; dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false); dram_write32(target, 1, csrw(S0, CSR_DCSR), false); /* We shouldn't actually need the jump because a reset should happen. */ dram_write_jump(target, 2, false); dram_write32(target, 4, info->dcsr, true); cache_invalidate(target); target->state = TARGET_RESET; return ERROR_OK; } static int deassert_reset(struct target *target) { jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); if (target->reset_halt) return wait_for_state(target, TARGET_HALTED); else return wait_for_state(target, TARGET_RUNNING); } static int read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { if (increment != size) { LOG_ERROR("read_memory with custom increment not implemented"); return ERROR_NOT_IMPLEMENTED; } jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16)); switch (size) { case 1: cache_set32(target, 1, lb(S1, S0, 0)); cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16)); break; case 2: cache_set32(target, 1, lh(S1, S0, 0)); cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16)); break; case 4: cache_set32(target, 1, lw(S1, S0, 0)); cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16)); break; default: LOG_ERROR("Unsupported size: %d", size); return ERROR_FAIL; } cache_set_jump(target, 3); cache_write(target, CACHE_NO_READ, false); riscv011_info_t *info = get_info(target); const unsigned max_batch_size = 256; scans_t *scans = scans_new(target, max_batch_size); if (!scans) return ERROR_FAIL; uint32_t result_value = 0x777; uint32_t i = 0; while (i < count + 3) { unsigned int batch_size = MIN(count + 3 - i, max_batch_size); scans_reset(scans); for (unsigned int j = 0; j < batch_size; j++) { if (i + j == count) { /* Just insert a read so we can scan out the last value. */ scans_add_read32(scans, 4, false); } else if (i + j >= count + 1) { /* And check for errors. */ scans_add_read32(scans, info->dramsize-1, false); } else { /* Write the next address and set interrupt. */ uint32_t offset = size * (i + j); scans_add_write32(scans, 4, address + offset, true); } } int retval = scans_execute(scans); if (retval != ERROR_OK) { LOG_ERROR("JTAG execute failed: %d", retval); goto error; } int dbus_busy = 0; int execute_busy = 0; for (unsigned int j = 0; j < batch_size; j++) { dbus_status_t status = scans_get_u32(scans, j, DBUS_OP_START, DBUS_OP_SIZE); switch (status) { case DBUS_STATUS_SUCCESS: break; case DBUS_STATUS_FAILED: LOG_ERROR("Debug RAM write failed. Hardware error?"); goto error; case DBUS_STATUS_BUSY: dbus_busy++; break; default: LOG_ERROR("Got invalid bus access status: %d", status); return ERROR_FAIL; } uint64_t data = scans_get_u64(scans, j, DBUS_DATA_START, DBUS_DATA_SIZE); if (data & DMCONTROL_INTERRUPT) execute_busy++; if (i + j == count + 2) { result_value = data; } else if (i + j > 1) { uint32_t offset = size * (i + j - 2); switch (size) { case 1: buffer[offset] = data; break; case 2: buffer[offset] = data; buffer[offset+1] = data >> 8; break; case 4: buffer[offset] = data; buffer[offset+1] = data >> 8; buffer[offset+2] = data >> 16; buffer[offset+3] = data >> 24; break; } } LOG_DEBUG("j=%d status=%d data=%09" PRIx64, j, status, data); } if (dbus_busy) increase_dbus_busy_delay(target); if (execute_busy) increase_interrupt_high_delay(target); if (dbus_busy || execute_busy) { wait_for_debugint_clear(target, false); /* Retry. */ LOG_INFO("Retrying memory read starting from 0x%" TARGET_PRIxADDR " with more delays", address + size * i); } else { i += batch_size; } } if (result_value != 0) { LOG_USER("Core got an exception (0x%x) while reading from 0x%" TARGET_PRIxADDR, result_value, address + size * (count-1)); if (count > 1) { LOG_USER("(It may have failed between 0x%" TARGET_PRIxADDR " and 0x%" TARGET_PRIxADDR " as well, but we " "didn't check then.)", address, address + size * (count-2) + size - 1); } goto error; } scans_delete(scans); cache_clean(target); return ERROR_OK; error: scans_delete(scans); cache_clean(target); return ERROR_FAIL; } static int setup_write_memory(struct target *target, uint32_t size) { switch (size) { case 1: cache_set32(target, 0, lb(S0, ZERO, DEBUG_RAM_START + 16)); cache_set32(target, 1, sb(S0, T0, 0)); break; case 2: cache_set32(target, 0, lh(S0, ZERO, DEBUG_RAM_START + 16)); cache_set32(target, 1, sh(S0, T0, 0)); break; case 4: cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16)); cache_set32(target, 1, sw(S0, T0, 0)); break; default: LOG_ERROR("Unsupported size: %d", size); return ERROR_FAIL; } cache_set32(target, 2, addi(T0, T0, size)); cache_set_jump(target, 3); cache_write(target, 4, false); return ERROR_OK; } static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { riscv011_info_t *info = get_info(target); jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); /* Set up the address. */ cache_set_store(target, 0, T0, SLOT1); cache_set_load(target, 1, T0, SLOT0); cache_set_jump(target, 2); cache_set(target, SLOT0, address); if (cache_write(target, 5, true) != ERROR_OK) return ERROR_FAIL; uint64_t t0 = cache_get(target, SLOT1); LOG_DEBUG("t0 is 0x%" PRIx64, t0); if (setup_write_memory(target, size) != ERROR_OK) return ERROR_FAIL; const unsigned max_batch_size = 256; scans_t *scans = scans_new(target, max_batch_size); if (!scans) return ERROR_FAIL; uint32_t result_value = 0x777; uint32_t i = 0; while (i < count + 2) { unsigned int batch_size = MIN(count + 2 - i, max_batch_size); scans_reset(scans); for (unsigned int j = 0; j < batch_size; j++) { if (i + j >= count) { /* Check for an exception. */ scans_add_read32(scans, info->dramsize-1, false); } else { /* Write the next value and set interrupt. */ uint32_t value; uint32_t offset = size * (i + j); switch (size) { case 1: value = buffer[offset]; break; case 2: value = buffer[offset] | (buffer[offset+1] << 8); break; case 4: value = buffer[offset] | ((uint32_t) buffer[offset+1] << 8) | ((uint32_t) buffer[offset+2] << 16) | ((uint32_t) buffer[offset+3] << 24); break; default: goto error; } scans_add_write32(scans, 4, value, true); } } int retval = scans_execute(scans); if (retval != ERROR_OK) { LOG_ERROR("JTAG execute failed: %d", retval); goto error; } int dbus_busy = 0; int execute_busy = 0; for (unsigned int j = 0; j < batch_size; j++) { dbus_status_t status = scans_get_u32(scans, j, DBUS_OP_START, DBUS_OP_SIZE); switch (status) { case DBUS_STATUS_SUCCESS: break; case DBUS_STATUS_FAILED: LOG_ERROR("Debug RAM write failed. Hardware error?"); goto error; case DBUS_STATUS_BUSY: dbus_busy++; break; default: LOG_ERROR("Got invalid bus access status: %d", status); return ERROR_FAIL; } int interrupt = scans_get_u32(scans, j, DBUS_DATA_START + 33, 1); if (interrupt) execute_busy++; if (i + j == count + 1) result_value = scans_get_u32(scans, j, DBUS_DATA_START, 32); } if (dbus_busy) increase_dbus_busy_delay(target); if (execute_busy) increase_interrupt_high_delay(target); if (dbus_busy || execute_busy) { wait_for_debugint_clear(target, false); /* Retry. * Set t0 back to what it should have been at the beginning of this * batch. */ LOG_INFO("Retrying memory write starting from 0x%" TARGET_PRIxADDR " with more delays", address + size * i); cache_clean(target); if (write_gpr(target, T0, address + size * i) != ERROR_OK) goto error; if (setup_write_memory(target, size) != ERROR_OK) goto error; } else { i += batch_size; } } if (result_value != 0) { LOG_ERROR("Core got an exception (0x%x) while writing to 0x%" TARGET_PRIxADDR, result_value, address + size * (count-1)); if (count > 1) { LOG_ERROR("(It may have failed between 0x%" TARGET_PRIxADDR " and 0x%" TARGET_PRIxADDR " as well, but we " "didn't check then.)", address, address + size * (count-2) + size - 1); } goto error; } scans_delete(scans); cache_clean(target); return register_write(target, T0, t0); error: scans_delete(scans); cache_clean(target); return ERROR_FAIL; } static int arch_state(struct target *target) { return ERROR_OK; } static COMMAND_HELPER(riscv011_print_info, struct target *target) { /* Abstract description. */ riscv_print_info_line(CMD, "target", "memory.read_while_running8", 0); riscv_print_info_line(CMD, "target", "memory.write_while_running8", 0); riscv_print_info_line(CMD, "target", "memory.read_while_running16", 0); riscv_print_info_line(CMD, "target", "memory.write_while_running16", 0); riscv_print_info_line(CMD, "target", "memory.read_while_running32", 0); riscv_print_info_line(CMD, "target", "memory.write_while_running32", 0); riscv_print_info_line(CMD, "target", "memory.read_while_running64", 0); riscv_print_info_line(CMD, "target", "memory.write_while_running64", 0); riscv_print_info_line(CMD, "target", "memory.read_while_running128", 0); riscv_print_info_line(CMD, "target", "memory.write_while_running128", 0); uint32_t dminfo = dbus_read(target, DMINFO); riscv_print_info_line(CMD, "dm", "authenticated", get_field(dminfo, DMINFO_AUTHENTICATED)); return 0; } static int wait_for_authbusy(struct target *target) { time_t start = time(NULL); while (1) { uint32_t dminfo = dbus_read(target, DMINFO); if (!get_field(dminfo, DMINFO_AUTHBUSY)) break; if (time(NULL) - start > riscv_command_timeout_sec) { LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dminfo=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", riscv_command_timeout_sec, dminfo); return ERROR_FAIL; } } return ERROR_OK; } static int riscv011_authdata_read(struct target *target, uint32_t *value, unsigned int index) { if (index > 1) { LOG_ERROR("Spec 0.11 only has a two authdata registers."); return ERROR_FAIL; } if (wait_for_authbusy(target) != ERROR_OK) return ERROR_FAIL; uint16_t authdata_address = index ? DMAUTHDATA1 : DMAUTHDATA0; *value = dbus_read(target, authdata_address); return ERROR_OK; } static int riscv011_authdata_write(struct target *target, uint32_t value, unsigned int index) { if (index > 1) { LOG_ERROR("Spec 0.11 only has a two authdata registers."); return ERROR_FAIL; } if (wait_for_authbusy(target) != ERROR_OK) return ERROR_FAIL; uint16_t authdata_address = index ? DMAUTHDATA1 : DMAUTHDATA0; dbus_write(target, authdata_address, value); return ERROR_OK; } static int init_target(struct command_context *cmd_ctx, struct target *target) { LOG_DEBUG("init"); RISCV_INFO(generic_info); generic_info->get_register = get_register; generic_info->set_register = set_register; generic_info->read_memory = read_memory; generic_info->authdata_read = &riscv011_authdata_read; generic_info->authdata_write = &riscv011_authdata_write; generic_info->print_info = &riscv011_print_info; generic_info->version_specific = calloc(1, sizeof(riscv011_info_t)); if (!generic_info->version_specific) return ERROR_FAIL; /* Assume 32-bit until we discover the real value in examine(). */ generic_info->xlen = 32; riscv_init_registers(target); return ERROR_OK; } struct target_type riscv011_target = { .name = "riscv", .init_target = init_target, .deinit_target = deinit_target, .examine = examine, /* poll current target status */ .poll = riscv011_poll, .halt = halt, .resume = riscv011_resume, .step = step, .assert_reset = assert_reset, .deassert_reset = deassert_reset, .write_memory = write_memory, .arch_state = arch_state, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/riscv-013.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Support for RISC-V, debug version 0.13, which is currently (2/4/17) the * latest draft. */ #include <assert.h> #include <stdlib.h> #include <time.h> #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target/target.h" #include "target/algorithm.h" #include "target/target_type.h" #include <helper/log.h> #include "jtag/jtag.h" #include "target/register.h" #include "target/breakpoints.h" #include "helper/time_support.h" #include "helper/list.h" #include "riscv.h" #include "debug_defines.h" #include "rtos/rtos.h" #include "program.h" #include "asm.h" #include "batch.h" static int riscv013_on_step_or_resume(struct target *target, bool step); static int riscv013_step_or_resume_current_hart(struct target *target, bool step, bool use_hasel); static void riscv013_clear_abstract_error(struct target *target); /* Implementations of the functions in struct riscv_info. */ static int riscv013_get_register(struct target *target, riscv_reg_t *value, int rid); static int riscv013_set_register(struct target *target, int regid, uint64_t value); static int riscv013_select_current_hart(struct target *target); static int riscv013_halt_prep(struct target *target); static int riscv013_halt_go(struct target *target); static int riscv013_resume_go(struct target *target); static int riscv013_step_current_hart(struct target *target); static int riscv013_on_halt(struct target *target); static int riscv013_on_step(struct target *target); static int riscv013_resume_prep(struct target *target); static bool riscv013_is_halted(struct target *target); static enum riscv_halt_reason riscv013_halt_reason(struct target *target); static int riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t d); static riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index); static int riscv013_execute_debug_buffer(struct target *target); static void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d); static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a); static int riscv013_dmi_write_u64_bits(struct target *target); static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf); static int register_read(struct target *target, uint64_t *value, uint32_t number); static int register_read_direct(struct target *target, uint64_t *value, uint32_t number); static int register_write_direct(struct target *target, unsigned number, uint64_t value); static int read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment); static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); /** * Since almost everything can be accomplish by scanning the dbus register, all * functions here assume dbus is already selected. The exception are functions * called directly by OpenOCD, which can't assume anything about what's * currently in IR. They should set IR to dbus explicitly. */ #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) #define CSR_DCSR_CAUSE_SWBP 1 #define CSR_DCSR_CAUSE_TRIGGER 2 #define CSR_DCSR_CAUSE_DEBUGINT 3 #define CSR_DCSR_CAUSE_STEP 4 #define CSR_DCSR_CAUSE_HALT 5 #define CSR_DCSR_CAUSE_GROUP 6 #define RISCV013_INFO(r) riscv013_info_t *r = get_info(target) /*** JTAG registers. ***/ typedef enum { DMI_OP_NOP = 0, DMI_OP_READ = 1, DMI_OP_WRITE = 2 } dmi_op_t; typedef enum { DMI_STATUS_SUCCESS = 0, DMI_STATUS_FAILED = 2, DMI_STATUS_BUSY = 3 } dmi_status_t; typedef enum slot { SLOT0, SLOT1, SLOT_LAST, } slot_t; /*** Debug Bus registers. ***/ #define CMDERR_NONE 0 #define CMDERR_BUSY 1 #define CMDERR_NOT_SUPPORTED 2 #define CMDERR_EXCEPTION 3 #define CMDERR_HALT_RESUME 4 #define CMDERR_OTHER 7 /*** Info about the core being debugged. ***/ struct trigger { uint64_t address; uint32_t length; uint64_t mask; uint64_t value; bool read, write, execute; int unique_id; }; typedef enum { YNM_MAYBE, YNM_YES, YNM_NO } yes_no_maybe_t; typedef struct { struct list_head list; int abs_chain_position; /* The number of harts connected to this DM. */ int hart_count; /* Indicates we already reset this DM, so don't need to do it again. */ bool was_reset; /* Targets that are connected to this DM. */ struct list_head target_list; /* The currently selected hartid on this DM. */ int current_hartid; bool hasel_supported; /* The program buffer stores executable code. 0 is an illegal instruction, * so we use 0 to mean the cached value is invalid. */ uint32_t progbuf_cache[16]; } dm013_info_t; typedef struct { struct list_head list; struct target *target; } target_list_t; typedef struct { /* The indexed used to address this hart in its DM. */ unsigned index; /* Number of address bits in the dbus register. */ unsigned abits; /* Number of abstract command data registers. */ unsigned datacount; /* Number of words in the Program Buffer. */ unsigned progbufsize; /* We cache the read-only bits of sbcs here. */ uint32_t sbcs; yes_no_maybe_t progbuf_writable; /* We only need the address so that we know the alignment of the buffer. */ riscv_addr_t progbuf_address; /* Number of run-test/idle cycles the target requests we do after each dbus * access. */ unsigned int dtmcs_idle; /* This value is incremented every time a dbus access comes back as "busy". * It's used to determine how many run-test/idle cycles to feed the target * in between accesses. */ unsigned int dmi_busy_delay; /* Number of run-test/idle cycles to add between consecutive bus master * reads/writes respectively. */ unsigned int bus_master_write_delay, bus_master_read_delay; /* This value is increased every time we tried to execute two commands * consecutively, and the second one failed because the previous hadn't * completed yet. It's used to add extra run-test/idle cycles after * starting a command, so we don't have to waste time checking for busy to * go low. */ unsigned int ac_busy_delay; bool abstract_read_csr_supported; bool abstract_write_csr_supported; bool abstract_read_fpr_supported; bool abstract_write_fpr_supported; yes_no_maybe_t has_aampostincrement; /* When a function returns some error due to a failure indicated by the * target in cmderr, the caller can look here to see what that error was. * (Compare with errno.) */ uint8_t cmderr; /* Some fields from hartinfo. */ uint8_t datasize; uint8_t dataaccess; int16_t dataaddr; /* The width of the hartsel field. */ unsigned hartsellen; /* DM that provides access to this target. */ dm013_info_t *dm; } riscv013_info_t; static LIST_HEAD(dm_list); static riscv013_info_t *get_info(const struct target *target) { struct riscv_info *info = target->arch_info; assert(info); assert(info->version_specific); return info->version_specific; } /** * Return the DM structure for this target. If there isn't one, find it in the * global list of DMs. If it's not in there, then create one and initialize it * to 0. */ static dm013_info_t *get_dm(struct target *target) { RISCV013_INFO(info); if (info->dm) return info->dm; int abs_chain_position = target->tap->abs_chain_position; dm013_info_t *entry; dm013_info_t *dm = NULL; list_for_each_entry(entry, &dm_list, list) { if (entry->abs_chain_position == abs_chain_position) { dm = entry; break; } } if (!dm) { LOG_DEBUG("[%d] Allocating new DM", target->coreid); dm = calloc(1, sizeof(dm013_info_t)); if (!dm) return NULL; dm->abs_chain_position = abs_chain_position; dm->current_hartid = -1; dm->hart_count = -1; INIT_LIST_HEAD(&dm->target_list); list_add(&dm->list, &dm_list); } info->dm = dm; target_list_t *target_entry; list_for_each_entry(target_entry, &dm->target_list, list) { if (target_entry->target == target) return dm; } target_entry = calloc(1, sizeof(*target_entry)); if (!target_entry) { info->dm = NULL; return NULL; } target_entry->target = target; list_add(&target_entry->list, &dm->target_list); return dm; } static uint32_t set_hartsel(uint32_t initial, uint32_t index) { initial &= ~DM_DMCONTROL_HARTSELLO; initial &= ~DM_DMCONTROL_HARTSELHI; uint32_t index_lo = index & ((1 << DM_DMCONTROL_HARTSELLO_LENGTH) - 1); initial |= index_lo << DM_DMCONTROL_HARTSELLO_OFFSET; uint32_t index_hi = index >> DM_DMCONTROL_HARTSELLO_LENGTH; assert(index_hi < 1 << DM_DMCONTROL_HARTSELHI_LENGTH); initial |= index_hi << DM_DMCONTROL_HARTSELHI_OFFSET; return initial; } static void decode_dmi(char *text, unsigned address, unsigned data) { static const struct { unsigned address; uint64_t mask; const char *name; } description[] = { { DM_DMCONTROL, DM_DMCONTROL_HALTREQ, "haltreq" }, { DM_DMCONTROL, DM_DMCONTROL_RESUMEREQ, "resumereq" }, { DM_DMCONTROL, DM_DMCONTROL_HARTRESET, "hartreset" }, { DM_DMCONTROL, DM_DMCONTROL_HASEL, "hasel" }, { DM_DMCONTROL, DM_DMCONTROL_HARTSELHI, "hartselhi" }, { DM_DMCONTROL, DM_DMCONTROL_HARTSELLO, "hartsello" }, { DM_DMCONTROL, DM_DMCONTROL_NDMRESET, "ndmreset" }, { DM_DMCONTROL, DM_DMCONTROL_DMACTIVE, "dmactive" }, { DM_DMCONTROL, DM_DMCONTROL_ACKHAVERESET, "ackhavereset" }, { DM_DMSTATUS, DM_DMSTATUS_IMPEBREAK, "impebreak" }, { DM_DMSTATUS, DM_DMSTATUS_ALLHAVERESET, "allhavereset" }, { DM_DMSTATUS, DM_DMSTATUS_ANYHAVERESET, "anyhavereset" }, { DM_DMSTATUS, DM_DMSTATUS_ALLRESUMEACK, "allresumeack" }, { DM_DMSTATUS, DM_DMSTATUS_ANYRESUMEACK, "anyresumeack" }, { DM_DMSTATUS, DM_DMSTATUS_ALLNONEXISTENT, "allnonexistent" }, { DM_DMSTATUS, DM_DMSTATUS_ANYNONEXISTENT, "anynonexistent" }, { DM_DMSTATUS, DM_DMSTATUS_ALLUNAVAIL, "allunavail" }, { DM_DMSTATUS, DM_DMSTATUS_ANYUNAVAIL, "anyunavail" }, { DM_DMSTATUS, DM_DMSTATUS_ALLRUNNING, "allrunning" }, { DM_DMSTATUS, DM_DMSTATUS_ANYRUNNING, "anyrunning" }, { DM_DMSTATUS, DM_DMSTATUS_ALLHALTED, "allhalted" }, { DM_DMSTATUS, DM_DMSTATUS_ANYHALTED, "anyhalted" }, { DM_DMSTATUS, DM_DMSTATUS_AUTHENTICATED, "authenticated" }, { DM_DMSTATUS, DM_DMSTATUS_AUTHBUSY, "authbusy" }, { DM_DMSTATUS, DM_DMSTATUS_HASRESETHALTREQ, "hasresethaltreq" }, { DM_DMSTATUS, DM_DMSTATUS_CONFSTRPTRVALID, "confstrptrvalid" }, { DM_DMSTATUS, DM_DMSTATUS_VERSION, "version" }, { DM_ABSTRACTCS, DM_ABSTRACTCS_PROGBUFSIZE, "progbufsize" }, { DM_ABSTRACTCS, DM_ABSTRACTCS_BUSY, "busy" }, { DM_ABSTRACTCS, DM_ABSTRACTCS_CMDERR, "cmderr" }, { DM_ABSTRACTCS, DM_ABSTRACTCS_DATACOUNT, "datacount" }, { DM_COMMAND, DM_COMMAND_CMDTYPE, "cmdtype" }, { DM_SBCS, DM_SBCS_SBVERSION, "sbversion" }, { DM_SBCS, DM_SBCS_SBBUSYERROR, "sbbusyerror" }, { DM_SBCS, DM_SBCS_SBBUSY, "sbbusy" }, { DM_SBCS, DM_SBCS_SBREADONADDR, "sbreadonaddr" }, { DM_SBCS, DM_SBCS_SBACCESS, "sbaccess" }, { DM_SBCS, DM_SBCS_SBAUTOINCREMENT, "sbautoincrement" }, { DM_SBCS, DM_SBCS_SBREADONDATA, "sbreadondata" }, { DM_SBCS, DM_SBCS_SBERROR, "sberror" }, { DM_SBCS, DM_SBCS_SBASIZE, "sbasize" }, { DM_SBCS, DM_SBCS_SBACCESS128, "sbaccess128" }, { DM_SBCS, DM_SBCS_SBACCESS64, "sbaccess64" }, { DM_SBCS, DM_SBCS_SBACCESS32, "sbaccess32" }, { DM_SBCS, DM_SBCS_SBACCESS16, "sbaccess16" }, { DM_SBCS, DM_SBCS_SBACCESS8, "sbaccess8" }, }; text[0] = 0; for (unsigned i = 0; i < ARRAY_SIZE(description); i++) { if (description[i].address == address) { uint64_t mask = description[i].mask; unsigned value = get_field(data, mask); if (value) { if (i > 0) *(text++) = ' '; if (mask & (mask >> 1)) { /* If the field is more than 1 bit wide. */ sprintf(text, "%s=%d", description[i].name, value); } else { strcpy(text, description[i].name); } text += strlen(text); } } } } static void dump_field(int idle, const struct scan_field *field) { static const char * const op_string[] = {"-", "r", "w", "?"}; static const char * const status_string[] = {"+", "?", "F", "b"}; if (debug_level < LOG_LVL_DEBUG) return; uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits); unsigned int out_op = get_field(out, DTM_DMI_OP); unsigned int out_data = get_field(out, DTM_DMI_DATA); unsigned int out_address = out >> DTM_DMI_ADDRESS_OFFSET; uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits); unsigned int in_op = get_field(in, DTM_DMI_OP); unsigned int in_data = get_field(in, DTM_DMI_DATA); unsigned int in_address = in >> DTM_DMI_ADDRESS_OFFSET; log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, "scan", "%db %s %08x @%02x -> %s %08x @%02x; %di", field->num_bits, op_string[out_op], out_data, out_address, status_string[in_op], in_data, in_address, idle); char out_text[500]; char in_text[500]; decode_dmi(out_text, out_address, out_data); decode_dmi(in_text, in_address, in_data); if (in_text[0] || out_text[0]) { log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, "scan", "%s -> %s", out_text, in_text); } } /*** Utility functions. ***/ static void select_dmi(struct target *target) { if (bscan_tunnel_ir_width != 0) { select_dmi_via_bscan(target); return; } jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); } static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { struct scan_field field; uint8_t in_value[4]; uint8_t out_value[4] = { 0 }; if (bscan_tunnel_ir_width != 0) return dtmcontrol_scan_via_bscan(target, out); buf_set_u32(out_value, 0, 32, out); jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE); field.num_bits = 32; field.out_value = out_value; field.in_value = in_value; jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); /* Always return to dmi. */ select_dmi(target); int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("failed jtag scan: %d", retval); return retval; } uint32_t in = buf_get_u32(field.in_value, 0, 32); LOG_DEBUG("DTMCS: 0x%x -> 0x%x", out, in); return in; } static void increase_dmi_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); info->dmi_busy_delay += info->dmi_busy_delay / 10 + 1; LOG_DEBUG("dtmcs_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", info->dtmcs_idle, info->dmi_busy_delay, info->ac_busy_delay); dtmcontrol_scan(target, DTM_DTMCS_DMIRESET); } /** * exec: If this is set, assume the scan results in an execution, so more * run-test/idle cycles may be required. */ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, uint32_t *data_in, dmi_op_t op, uint32_t address_out, uint32_t data_out, bool exec) { riscv013_info_t *info = get_info(target); RISCV_INFO(r); unsigned num_bits = info->abits + DTM_DMI_OP_LENGTH + DTM_DMI_DATA_LENGTH; size_t num_bytes = (num_bits + 7) / 8; uint8_t in[num_bytes]; uint8_t out[num_bytes]; struct scan_field field = { .num_bits = num_bits, .out_value = out, .in_value = in }; riscv_bscan_tunneled_scan_context_t bscan_ctxt; if (r->reset_delays_wait >= 0) { r->reset_delays_wait--; if (r->reset_delays_wait < 0) { info->dmi_busy_delay = 0; info->ac_busy_delay = 0; } } memset(in, 0, num_bytes); memset(out, 0, num_bytes); assert(info->abits != 0); buf_set_u32(out, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, op); buf_set_u32(out, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, data_out); buf_set_u32(out, DTM_DMI_ADDRESS_OFFSET, info->abits, address_out); /* I wanted to place this code in a different function, but the way JTAG command queueing works in the jtag handling functions, the scan fields either have to be heap allocated, global/static, or else they need to stay on the stack until the jtag_execute_queue() call. Heap or static fields in this case doesn't seem the best fit. Declaring stack based field values in a subsidiary function call wouldn't work. */ if (bscan_tunnel_ir_width != 0) { riscv_add_bscan_tunneled_scan(target, &field, &bscan_ctxt); } else { /* Assume dbus is already selected. */ jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); } int idle_count = info->dmi_busy_delay; if (exec) idle_count += info->ac_busy_delay; if (idle_count) jtag_add_runtest(idle_count, TAP_IDLE); int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("dmi_scan failed jtag scan"); if (data_in) *data_in = ~0; return DMI_STATUS_FAILED; } if (bscan_tunnel_ir_width != 0) { /* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */ buffer_shr(in, num_bytes, 1); } if (data_in) *data_in = buf_get_u32(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); if (address_in) *address_in = buf_get_u32(in, DTM_DMI_ADDRESS_OFFSET, info->abits); dump_field(idle_count, &field); return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); } /** * @param target * @param data_in The data we received from the target. * @param dmi_busy_encountered * If non-NULL, will be updated to reflect whether DMI busy was * encountered while executing this operation or not. * @param dmi_op The operation to perform (read/write/nop). * @param address The address argument to that operation. * @param data_out The data to send to the target. * @param timeout_sec * @param exec When true, this scan will execute something, so extra RTI * cycles may be added. * @param ensure_success * Scan a nop after the requested operation, ensuring the * DMI operation succeeded. */ static int dmi_op_timeout(struct target *target, uint32_t *data_in, bool *dmi_busy_encountered, int dmi_op, uint32_t address, uint32_t data_out, int timeout_sec, bool exec, bool ensure_success) { select_dmi(target); dmi_status_t status; uint32_t address_in; if (dmi_busy_encountered) *dmi_busy_encountered = false; const char *op_name; switch (dmi_op) { case DMI_OP_NOP: op_name = "nop"; break; case DMI_OP_READ: op_name = "read"; break; case DMI_OP_WRITE: op_name = "write"; break; default: LOG_ERROR("Invalid DMI operation: %d", dmi_op); return ERROR_FAIL; } keep_alive(); time_t start = time(NULL); /* This first loop performs the request. Note that if for some reason this * stays busy, it is actually due to the previous access. */ while (1) { status = dmi_scan(target, NULL, NULL, dmi_op, address, data_out, exec); if (status == DMI_STATUS_BUSY) { increase_dmi_busy_delay(target); if (dmi_busy_encountered) *dmi_busy_encountered = true; } else if (status == DMI_STATUS_SUCCESS) { break; } else { LOG_ERROR("failed %s at 0x%x, status=%d", op_name, address, status); dtmcontrol_scan(target, DTM_DTMCS_DMIRESET); return ERROR_FAIL; } if (time(NULL) - start > timeout_sec) return ERROR_TIMEOUT_REACHED; } if (status != DMI_STATUS_SUCCESS) { LOG_ERROR("Failed %s at 0x%x; status=%d", op_name, address, status); return ERROR_FAIL; } if (ensure_success) { /* This second loop ensures the request succeeded, and gets back data. * Note that NOP can result in a 'busy' result as well, but that would be * noticed on the next DMI access we do. */ while (1) { status = dmi_scan(target, &address_in, data_in, DMI_OP_NOP, address, 0, false); if (status == DMI_STATUS_BUSY) { increase_dmi_busy_delay(target); if (dmi_busy_encountered) *dmi_busy_encountered = true; } else if (status == DMI_STATUS_SUCCESS) { break; } else { if (data_in) { LOG_ERROR("Failed %s (NOP) at 0x%x; value=0x%x, status=%d", op_name, address, *data_in, status); } else { LOG_ERROR("Failed %s (NOP) at 0x%x; status=%d", op_name, address, status); } dtmcontrol_scan(target, DTM_DTMCS_DMIRESET); return ERROR_FAIL; } if (time(NULL) - start > timeout_sec) return ERROR_TIMEOUT_REACHED; } } return ERROR_OK; } static int dmi_op(struct target *target, uint32_t *data_in, bool *dmi_busy_encountered, int dmi_op, uint32_t address, uint32_t data_out, bool exec, bool ensure_success) { int result = dmi_op_timeout(target, data_in, dmi_busy_encountered, dmi_op, address, data_out, riscv_command_timeout_sec, exec, ensure_success); if (result == ERROR_TIMEOUT_REACHED) { LOG_ERROR("DMI operation didn't complete in %d seconds. The target is " "either really slow or broken. You could increase the " "timeout with riscv set_command_timeout_sec.", riscv_command_timeout_sec); return ERROR_FAIL; } return result; } static int dmi_read(struct target *target, uint32_t *value, uint32_t address) { return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, false, true); } static int dmi_read_exec(struct target *target, uint32_t *value, uint32_t address) { return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, true, true); } static int dmi_write(struct target *target, uint32_t address, uint32_t value) { return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, false, true); } static int dmi_write_exec(struct target *target, uint32_t address, uint32_t value, bool ensure_success) { return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, true, ensure_success); } static int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus, bool authenticated, unsigned timeout_sec) { int result = dmi_op_timeout(target, dmstatus, NULL, DMI_OP_READ, DM_DMSTATUS, 0, timeout_sec, false, true); if (result != ERROR_OK) return result; int dmstatus_version = get_field(*dmstatus, DM_DMSTATUS_VERSION); if (dmstatus_version != 2 && dmstatus_version != 3) { LOG_ERROR("OpenOCD only supports Debug Module version 2 (0.13) and 3 (1.0), not " "%d (dmstatus=0x%x). This error might be caused by a JTAG " "signal issue. Try reducing the JTAG clock speed.", get_field(*dmstatus, DM_DMSTATUS_VERSION), *dmstatus); } else if (authenticated && !get_field(*dmstatus, DM_DMSTATUS_AUTHENTICATED)) { LOG_ERROR("Debugger is not authenticated to target Debug Module. " "(dmstatus=0x%x). Use `riscv authdata_read` and " "`riscv authdata_write` commands to authenticate.", *dmstatus); return ERROR_FAIL; } return ERROR_OK; } static int dmstatus_read(struct target *target, uint32_t *dmstatus, bool authenticated) { return dmstatus_read_timeout(target, dmstatus, authenticated, riscv_command_timeout_sec); } static void increase_ac_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); info->ac_busy_delay += info->ac_busy_delay / 10 + 1; LOG_DEBUG("dtmcs_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", info->dtmcs_idle, info->dmi_busy_delay, info->ac_busy_delay); } static uint32_t __attribute__((unused)) abstract_register_size(unsigned width) { switch (width) { case 32: return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 2); case 64: return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 3); case 128: return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 4); default: LOG_ERROR("Unsupported register width: %d", width); return 0; } } static int wait_for_idle(struct target *target, uint32_t *abstractcs) { RISCV013_INFO(info); time_t start = time(NULL); while (1) { if (dmi_read(target, abstractcs, DM_ABSTRACTCS) != ERROR_OK) return ERROR_FAIL; if (get_field(*abstractcs, DM_ABSTRACTCS_BUSY) == 0) return ERROR_OK; if (time(NULL) - start > riscv_command_timeout_sec) { info->cmderr = get_field(*abstractcs, DM_ABSTRACTCS_CMDERR); if (info->cmderr != CMDERR_NONE) { const char *errors[8] = { "none", "busy", "not supported", "exception", "halt/resume", "reserved", "reserved", "other" }; LOG_ERROR("Abstract command ended in error '%s' (abstractcs=0x%x)", errors[info->cmderr], *abstractcs); } LOG_ERROR("Timed out after %ds waiting for busy to go low (abstractcs=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", riscv_command_timeout_sec, *abstractcs); return ERROR_FAIL; } } } static int execute_abstract_command(struct target *target, uint32_t command) { RISCV013_INFO(info); if (debug_level >= LOG_LVL_DEBUG) { switch (get_field(command, DM_COMMAND_CMDTYPE)) { case 0: LOG_DEBUG("command=0x%x; access register, size=%d, postexec=%d, " "transfer=%d, write=%d, regno=0x%x", command, 8 << get_field(command, AC_ACCESS_REGISTER_AARSIZE), get_field(command, AC_ACCESS_REGISTER_POSTEXEC), get_field(command, AC_ACCESS_REGISTER_TRANSFER), get_field(command, AC_ACCESS_REGISTER_WRITE), get_field(command, AC_ACCESS_REGISTER_REGNO)); break; default: LOG_DEBUG("command=0x%x", command); break; } } if (dmi_write_exec(target, DM_COMMAND, command, false) != ERROR_OK) return ERROR_FAIL; uint32_t abstractcs = 0; int result = wait_for_idle(target, &abstractcs); info->cmderr = get_field(abstractcs, DM_ABSTRACTCS_CMDERR); if (info->cmderr != 0 || result != ERROR_OK) { LOG_DEBUG("command 0x%x failed; abstractcs=0x%x", command, abstractcs); /* Clear the error. */ dmi_write(target, DM_ABSTRACTCS, DM_ABSTRACTCS_CMDERR); return ERROR_FAIL; } return ERROR_OK; } static riscv_reg_t read_abstract_arg(struct target *target, unsigned index, unsigned size_bits) { riscv_reg_t value = 0; uint32_t v; unsigned offset = index * size_bits / 32; switch (size_bits) { default: LOG_ERROR("Unsupported size: %d bits", size_bits); return ~0; case 64: dmi_read(target, &v, DM_DATA0 + offset + 1); value |= ((uint64_t) v) << 32; /* falls through */ case 32: dmi_read(target, &v, DM_DATA0 + offset); value |= v; } return value; } static int write_abstract_arg(struct target *target, unsigned index, riscv_reg_t value, unsigned size_bits) { unsigned offset = index * size_bits / 32; switch (size_bits) { default: LOG_ERROR("Unsupported size: %d bits", size_bits); return ERROR_FAIL; case 64: dmi_write(target, DM_DATA0 + offset + 1, value >> 32); /* falls through */ case 32: dmi_write(target, DM_DATA0 + offset, value); } return ERROR_OK; } /** * @par size in bits */ static uint32_t access_register_command(struct target *target, uint32_t number, unsigned size, uint32_t flags) { uint32_t command = set_field(0, DM_COMMAND_CMDTYPE, 0); switch (size) { case 32: command = set_field(command, AC_ACCESS_REGISTER_AARSIZE, 2); break; case 64: command = set_field(command, AC_ACCESS_REGISTER_AARSIZE, 3); break; default: LOG_ERROR("%d-bit register %s not supported.", size, gdb_regno_name(number)); assert(0); } if (number <= GDB_REGNO_XPR31) { command = set_field(command, AC_ACCESS_REGISTER_REGNO, 0x1000 + number - GDB_REGNO_ZERO); } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { command = set_field(command, AC_ACCESS_REGISTER_REGNO, 0x1020 + number - GDB_REGNO_FPR0); } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { command = set_field(command, AC_ACCESS_REGISTER_REGNO, number - GDB_REGNO_CSR0); } else if (number >= GDB_REGNO_COUNT) { /* Custom register. */ assert(target->reg_cache->reg_list[number].arch_info); riscv_reg_info_t *reg_info = target->reg_cache->reg_list[number].arch_info; assert(reg_info); command = set_field(command, AC_ACCESS_REGISTER_REGNO, 0xc000 + reg_info->custom_number); } else { assert(0); } command |= flags; return command; } static int register_read_abstract(struct target *target, uint64_t *value, uint32_t number, unsigned size) { RISCV013_INFO(info); if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && !info->abstract_read_fpr_supported) return ERROR_FAIL; if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 && !info->abstract_read_csr_supported) return ERROR_FAIL; /* The spec doesn't define abstract register numbers for vector registers. */ if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31) return ERROR_FAIL; uint32_t command = access_register_command(target, number, size, AC_ACCESS_REGISTER_TRANSFER); int result = execute_abstract_command(target, command); if (result != ERROR_OK) { if (info->cmderr == CMDERR_NOT_SUPPORTED) { if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { info->abstract_read_fpr_supported = false; LOG_INFO("Disabling abstract command reads from FPRs."); } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { info->abstract_read_csr_supported = false; LOG_INFO("Disabling abstract command reads from CSRs."); } } return result; } if (value) *value = read_abstract_arg(target, 0, size); return ERROR_OK; } static int register_write_abstract(struct target *target, uint32_t number, uint64_t value, unsigned size) { RISCV013_INFO(info); if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && !info->abstract_write_fpr_supported) return ERROR_FAIL; if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 && !info->abstract_write_csr_supported) return ERROR_FAIL; uint32_t command = access_register_command(target, number, size, AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_WRITE); if (write_abstract_arg(target, 0, value, size) != ERROR_OK) return ERROR_FAIL; int result = execute_abstract_command(target, command); if (result != ERROR_OK) { if (info->cmderr == CMDERR_NOT_SUPPORTED) { if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { info->abstract_write_fpr_supported = false; LOG_INFO("Disabling abstract command writes to FPRs."); } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { info->abstract_write_csr_supported = false; LOG_INFO("Disabling abstract command writes to CSRs."); } } return result; } return ERROR_OK; } /* * Sets the AAMSIZE field of a memory access abstract command based on * the width (bits). */ static uint32_t abstract_memory_size(unsigned width) { switch (width) { case 8: return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 0); case 16: return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 1); case 32: return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 2); case 64: return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 3); case 128: return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 4); default: LOG_ERROR("Unsupported memory width: %d", width); return 0; } } /* * Creates a memory access abstract command. */ static uint32_t access_memory_command(struct target *target, bool virtual, unsigned width, bool postincrement, bool write) { uint32_t command = set_field(0, AC_ACCESS_MEMORY_CMDTYPE, 2); command = set_field(command, AC_ACCESS_MEMORY_AAMVIRTUAL, virtual); command |= abstract_memory_size(width); command = set_field(command, AC_ACCESS_MEMORY_AAMPOSTINCREMENT, postincrement); command = set_field(command, AC_ACCESS_MEMORY_WRITE, write); return command; } static int examine_progbuf(struct target *target) { riscv013_info_t *info = get_info(target); if (info->progbuf_writable != YNM_MAYBE) return ERROR_OK; /* Figure out if progbuf is writable. */ if (info->progbufsize < 1) { info->progbuf_writable = YNM_NO; LOG_INFO("No program buffer present."); return ERROR_OK; } uint64_t s0; if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; struct riscv_program program; riscv_program_init(&program, target); riscv_program_insert(&program, auipc(S0)); if (riscv_program_exec(&program, target) != ERROR_OK) return ERROR_FAIL; if (register_read_direct(target, &info->progbuf_address, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; riscv_program_init(&program, target); riscv_program_insert(&program, sw(S0, S0, 0)); int result = riscv_program_exec(&program, target); if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; if (result != ERROR_OK) { /* This program might have failed if the program buffer is not * writable. */ info->progbuf_writable = YNM_NO; return ERROR_OK; } uint32_t written; if (dmi_read(target, &written, DM_PROGBUF0) != ERROR_OK) return ERROR_FAIL; if (written == (uint32_t) info->progbuf_address) { LOG_INFO("progbuf is writable at 0x%" PRIx64, info->progbuf_address); info->progbuf_writable = YNM_YES; } else { LOG_INFO("progbuf is not writeable at 0x%" PRIx64, info->progbuf_address); info->progbuf_writable = YNM_NO; } return ERROR_OK; } static int is_fpu_reg(uint32_t gdb_regno) { return (gdb_regno >= GDB_REGNO_FPR0 && gdb_regno <= GDB_REGNO_FPR31) || (gdb_regno == GDB_REGNO_CSR0 + CSR_FFLAGS) || (gdb_regno == GDB_REGNO_CSR0 + CSR_FRM) || (gdb_regno == GDB_REGNO_CSR0 + CSR_FCSR); } static int is_vector_reg(uint32_t gdb_regno) { return (gdb_regno >= GDB_REGNO_V0 && gdb_regno <= GDB_REGNO_V31) || gdb_regno == GDB_REGNO_VSTART || gdb_regno == GDB_REGNO_VXSAT || gdb_regno == GDB_REGNO_VXRM || gdb_regno == GDB_REGNO_VL || gdb_regno == GDB_REGNO_VTYPE || gdb_regno == GDB_REGNO_VLENB; } static int prep_for_register_access(struct target *target, uint64_t *mstatus, int regno) { if (is_fpu_reg(regno) || is_vector_reg(regno)) { if (register_read(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) return ERROR_FAIL; if (is_fpu_reg(regno) && (*mstatus & MSTATUS_FS) == 0) { if (register_write_direct(target, GDB_REGNO_MSTATUS, set_field(*mstatus, MSTATUS_FS, 1)) != ERROR_OK) return ERROR_FAIL; } else if (is_vector_reg(regno) && (*mstatus & MSTATUS_VS) == 0) { if (register_write_direct(target, GDB_REGNO_MSTATUS, set_field(*mstatus, MSTATUS_VS, 1)) != ERROR_OK) return ERROR_FAIL; } } else { *mstatus = 0; } return ERROR_OK; } static int cleanup_after_register_access(struct target *target, uint64_t mstatus, int regno) { if ((is_fpu_reg(regno) && (mstatus & MSTATUS_FS) == 0) || (is_vector_reg(regno) && (mstatus & MSTATUS_VS) == 0)) if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } typedef enum { SPACE_DM_DATA, SPACE_DMI_PROGBUF, SPACE_DMI_RAM } memory_space_t; typedef struct { /* How can the debugger access this memory? */ memory_space_t memory_space; /* Memory address to access the scratch memory from the hart. */ riscv_addr_t hart_address; /* Memory address to access the scratch memory from the debugger. */ riscv_addr_t debug_address; struct working_area *area; } scratch_mem_t; /** * Find some scratch memory to be used with the given program. */ static int scratch_reserve(struct target *target, scratch_mem_t *scratch, struct riscv_program *program, unsigned size_bytes) { riscv_addr_t alignment = 1; while (alignment < size_bytes) alignment *= 2; scratch->area = NULL; riscv013_info_t *info = get_info(target); /* Option 1: See if data# registers can be used as the scratch memory */ if (info->dataaccess == 1) { /* Sign extend dataaddr. */ scratch->hart_address = info->dataaddr; if (info->dataaddr & (1<<11)) scratch->hart_address |= 0xfffffffffffff000ULL; /* Align. */ scratch->hart_address = (scratch->hart_address + alignment - 1) & ~(alignment - 1); if ((size_bytes + scratch->hart_address - info->dataaddr + 3) / 4 >= info->datasize) { scratch->memory_space = SPACE_DM_DATA; scratch->debug_address = (scratch->hart_address - info->dataaddr) / 4; return ERROR_OK; } } /* Option 2: See if progbuf can be used as the scratch memory */ if (examine_progbuf(target) != ERROR_OK) return ERROR_FAIL; /* Allow for ebreak at the end of the program. */ unsigned program_size = (program->instruction_count + 1) * 4; scratch->hart_address = (info->progbuf_address + program_size + alignment - 1) & ~(alignment - 1); if ((info->progbuf_writable == YNM_YES) && ((size_bytes + scratch->hart_address - info->progbuf_address + 3) / 4 >= info->progbufsize)) { scratch->memory_space = SPACE_DMI_PROGBUF; scratch->debug_address = (scratch->hart_address - info->progbuf_address) / 4; return ERROR_OK; } /* Option 3: User-configured memory area as scratch RAM */ if (target_alloc_working_area(target, size_bytes + alignment - 1, &scratch->area) == ERROR_OK) { scratch->hart_address = (scratch->area->address + alignment - 1) & ~(alignment - 1); scratch->memory_space = SPACE_DMI_RAM; scratch->debug_address = scratch->hart_address; return ERROR_OK; } LOG_ERROR("Couldn't find %d bytes of scratch RAM to use. Please configure " "a work area with 'configure -work-area-phys'.", size_bytes); return ERROR_FAIL; } static int scratch_release(struct target *target, scratch_mem_t *scratch) { return target_free_working_area(target, scratch->area); } static int scratch_read64(struct target *target, scratch_mem_t *scratch, uint64_t *value) { uint32_t v; switch (scratch->memory_space) { case SPACE_DM_DATA: if (dmi_read(target, &v, DM_DATA0 + scratch->debug_address) != ERROR_OK) return ERROR_FAIL; *value = v; if (dmi_read(target, &v, DM_DATA1 + scratch->debug_address) != ERROR_OK) return ERROR_FAIL; *value |= ((uint64_t) v) << 32; break; case SPACE_DMI_PROGBUF: if (dmi_read(target, &v, DM_PROGBUF0 + scratch->debug_address) != ERROR_OK) return ERROR_FAIL; *value = v; if (dmi_read(target, &v, DM_PROGBUF1 + scratch->debug_address) != ERROR_OK) return ERROR_FAIL; *value |= ((uint64_t) v) << 32; break; case SPACE_DMI_RAM: { uint8_t buffer[8] = {0}; if (read_memory(target, scratch->debug_address, 4, 2, buffer, 4) != ERROR_OK) return ERROR_FAIL; *value = buffer[0] | (((uint64_t) buffer[1]) << 8) | (((uint64_t) buffer[2]) << 16) | (((uint64_t) buffer[3]) << 24) | (((uint64_t) buffer[4]) << 32) | (((uint64_t) buffer[5]) << 40) | (((uint64_t) buffer[6]) << 48) | (((uint64_t) buffer[7]) << 56); } break; } return ERROR_OK; } static int scratch_write64(struct target *target, scratch_mem_t *scratch, uint64_t value) { switch (scratch->memory_space) { case SPACE_DM_DATA: dmi_write(target, DM_DATA0 + scratch->debug_address, value); dmi_write(target, DM_DATA1 + scratch->debug_address, value >> 32); break; case SPACE_DMI_PROGBUF: dmi_write(target, DM_PROGBUF0 + scratch->debug_address, value); dmi_write(target, DM_PROGBUF1 + scratch->debug_address, value >> 32); break; case SPACE_DMI_RAM: { uint8_t buffer[8] = { value, value >> 8, value >> 16, value >> 24, value >> 32, value >> 40, value >> 48, value >> 56 }; if (write_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK) return ERROR_FAIL; } break; } return ERROR_OK; } /** Return register size in bits. */ static unsigned register_size(struct target *target, unsigned number) { /* If reg_cache hasn't been initialized yet, make a guess. We need this for * when this function is called during examine(). */ if (target->reg_cache) return target->reg_cache->reg_list[number].size; else return riscv_xlen(target); } static bool has_sufficient_progbuf(struct target *target, unsigned size) { RISCV013_INFO(info); RISCV_INFO(r); return info->progbufsize + r->impebreak >= size; } /** * Immediately write the new value to the requested register. This mechanism * bypasses any caches. */ static int register_write_direct(struct target *target, unsigned number, uint64_t value) { LOG_DEBUG("{%d} %s <- 0x%" PRIx64, riscv_current_hartid(target), gdb_regno_name(number), value); int result = register_write_abstract(target, number, value, register_size(target, number)); if (result == ERROR_OK || !has_sufficient_progbuf(target, 2) || !riscv_is_halted(target)) return result; struct riscv_program program; riscv_program_init(&program, target); uint64_t s0; if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; uint64_t mstatus; if (prep_for_register_access(target, &mstatus, number) != ERROR_OK) return ERROR_FAIL; scratch_mem_t scratch; bool use_scratch = false; if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && riscv_supports_extension(target, 'D') && riscv_xlen(target) < 64) { /* There are no instructions to move all the bits from a register, so * we need to use some scratch RAM. */ use_scratch = true; riscv_program_insert(&program, fld(number - GDB_REGNO_FPR0, S0, 0)); if (scratch_reserve(target, &scratch, &program, 8) != ERROR_OK) return ERROR_FAIL; if (register_write_direct(target, GDB_REGNO_S0, scratch.hart_address) != ERROR_OK) { scratch_release(target, &scratch); return ERROR_FAIL; } if (scratch_write64(target, &scratch, value) != ERROR_OK) { scratch_release(target, &scratch); return ERROR_FAIL; } } else if (number == GDB_REGNO_VTYPE) { riscv_program_insert(&program, csrr(S0, CSR_VL)); riscv_program_insert(&program, vsetvli(ZERO, S0, value)); } else { if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK) return ERROR_FAIL; if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { if (riscv_supports_extension(target, 'D')) riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); else riscv_program_insert(&program, fmv_w_x(number - GDB_REGNO_FPR0, S0)); } else if (number == GDB_REGNO_VL) { /* "The XLEN-bit-wide read-only vl CSR can only be updated by the * vsetvli and vsetvl instructions, and the fault-only-rst vector * load instruction variants." */ riscv_reg_t vtype; if (register_read(target, &vtype, GDB_REGNO_VTYPE) != ERROR_OK) return ERROR_FAIL; if (riscv_program_insert(&program, vsetvli(ZERO, S0, vtype)) != ERROR_OK) return ERROR_FAIL; } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { riscv_program_csrw(&program, S0, number); } else { LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); return ERROR_FAIL; } } int exec_out = riscv_program_exec(&program, target); /* Don't message on error. Probably the register doesn't exist. */ if (exec_out == ERROR_OK && target->reg_cache) { struct reg *reg = &target->reg_cache->reg_list[number]; buf_set_u64(reg->value, 0, reg->size, value); } if (use_scratch) scratch_release(target, &scratch); if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK) return ERROR_FAIL; /* Restore S0. */ if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; return exec_out; } /** Read register value from the target. Also update the cached value. */ static int register_read(struct target *target, uint64_t *value, uint32_t number) { if (number == GDB_REGNO_ZERO) { *value = 0; return ERROR_OK; } int result = register_read_direct(target, value, number); if (result != ERROR_OK) return ERROR_FAIL; if (target->reg_cache) { struct reg *reg = &target->reg_cache->reg_list[number]; buf_set_u64(reg->value, 0, reg->size, *value); } return ERROR_OK; } /** Actually read registers from the target right now. */ static int register_read_direct(struct target *target, uint64_t *value, uint32_t number) { int result = register_read_abstract(target, value, number, register_size(target, number)); if (result != ERROR_OK && has_sufficient_progbuf(target, 2) && number > GDB_REGNO_XPR31) { struct riscv_program program; riscv_program_init(&program, target); scratch_mem_t scratch; bool use_scratch = false; riscv_reg_t s0; if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; /* Write program to move data into s0. */ uint64_t mstatus; if (prep_for_register_access(target, &mstatus, number) != ERROR_OK) return ERROR_FAIL; if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { if (riscv_supports_extension(target, 'D') && riscv_xlen(target) < 64) { /* There are no instructions to move all the bits from a * register, so we need to use some scratch RAM. */ riscv_program_insert(&program, fsd(number - GDB_REGNO_FPR0, S0, 0)); if (scratch_reserve(target, &scratch, &program, 8) != ERROR_OK) return ERROR_FAIL; use_scratch = true; if (register_write_direct(target, GDB_REGNO_S0, scratch.hart_address) != ERROR_OK) { scratch_release(target, &scratch); return ERROR_FAIL; } } else if (riscv_supports_extension(target, 'D')) { riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); } else { riscv_program_insert(&program, fmv_x_w(S0, number - GDB_REGNO_FPR0)); } } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { riscv_program_csrr(&program, S0, number); } else { LOG_ERROR("Unsupported register: %s", gdb_regno_name(number)); return ERROR_FAIL; } /* Execute program. */ result = riscv_program_exec(&program, target); /* Don't message on error. Probably the register doesn't exist. */ if (use_scratch) { result = scratch_read64(target, &scratch, value); scratch_release(target, &scratch); if (result != ERROR_OK) return result; } else { /* Read S0 */ if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; } if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK) return ERROR_FAIL; /* Restore S0. */ if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; } if (result == ERROR_OK) { LOG_DEBUG("{%d} %s = 0x%" PRIx64, riscv_current_hartid(target), gdb_regno_name(number), *value); } return result; } static int wait_for_authbusy(struct target *target, uint32_t *dmstatus) { time_t start = time(NULL); while (1) { uint32_t value; if (dmstatus_read(target, &value, false) != ERROR_OK) return ERROR_FAIL; if (dmstatus) *dmstatus = value; if (!get_field(value, DM_DMSTATUS_AUTHBUSY)) break; if (time(NULL) - start > riscv_command_timeout_sec) { LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dmstatus=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", riscv_command_timeout_sec, value); return ERROR_FAIL; } } return ERROR_OK; } /*** OpenOCD target functions. ***/ static void deinit_target(struct target *target) { LOG_DEBUG("riscv_deinit_target()"); struct riscv_info *info = target->arch_info; if (!info) return; free(info->version_specific); /* TODO: free register arch_info */ info->version_specific = NULL; } static int set_haltgroup(struct target *target, bool *supported) { uint32_t write = set_field(DM_DMCS2_HGWRITE, DM_DMCS2_GROUP, target->smp); if (dmi_write(target, DM_DMCS2, write) != ERROR_OK) return ERROR_FAIL; uint32_t read; if (dmi_read(target, &read, DM_DMCS2) != ERROR_OK) return ERROR_FAIL; *supported = get_field(read, DM_DMCS2_GROUP) == (unsigned)target->smp; return ERROR_OK; } static int discover_vlenb(struct target *target) { RISCV_INFO(r); riscv_reg_t vlenb; if (register_read(target, &vlenb, GDB_REGNO_VLENB) != ERROR_OK) { LOG_WARNING("Couldn't read vlenb for %s; vector register access won't work.", target_name(target)); r->vlenb = 0; return ERROR_OK; } r->vlenb = vlenb; LOG_INFO("Vector support with vlenb=%d", r->vlenb); return ERROR_OK; } static int examine(struct target *target) { /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ uint32_t dtmcontrol = dtmcontrol_scan(target, 0); LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); LOG_DEBUG(" dmireset=%d", get_field(dtmcontrol, DTM_DTMCS_DMIRESET)); LOG_DEBUG(" idle=%d", get_field(dtmcontrol, DTM_DTMCS_IDLE)); LOG_DEBUG(" dmistat=%d", get_field(dtmcontrol, DTM_DTMCS_DMISTAT)); LOG_DEBUG(" abits=%d", get_field(dtmcontrol, DTM_DTMCS_ABITS)); LOG_DEBUG(" version=%d", get_field(dtmcontrol, DTM_DTMCS_VERSION)); if (dtmcontrol == 0) { LOG_ERROR("dtmcontrol is 0. Check JTAG connectivity/board power."); return ERROR_FAIL; } if (get_field(dtmcontrol, DTM_DTMCS_VERSION) != 1) { LOG_ERROR("Unsupported DTM version %d. (dtmcontrol=0x%x)", get_field(dtmcontrol, DTM_DTMCS_VERSION), dtmcontrol); return ERROR_FAIL; } riscv013_info_t *info = get_info(target); /* TODO: This won't be true if there are multiple DMs. */ info->index = target->coreid; info->abits = get_field(dtmcontrol, DTM_DTMCS_ABITS); info->dtmcs_idle = get_field(dtmcontrol, DTM_DTMCS_IDLE); /* Reset the Debug Module. */ dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; if (!dm->was_reset) { dmi_write(target, DM_DMCONTROL, 0); dmi_write(target, DM_DMCONTROL, DM_DMCONTROL_DMACTIVE); dm->was_reset = true; } dmi_write(target, DM_DMCONTROL, DM_DMCONTROL_HARTSELLO | DM_DMCONTROL_HARTSELHI | DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HASEL); uint32_t dmcontrol; if (dmi_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) return ERROR_FAIL; if (!get_field(dmcontrol, DM_DMCONTROL_DMACTIVE)) { LOG_ERROR("Debug Module did not become active. dmcontrol=0x%x", dmcontrol); return ERROR_FAIL; } dm->hasel_supported = get_field(dmcontrol, DM_DMCONTROL_HASEL); uint32_t dmstatus; if (dmstatus_read(target, &dmstatus, false) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("dmstatus: 0x%08x", dmstatus); int dmstatus_version = get_field(dmstatus, DM_DMSTATUS_VERSION); if (dmstatus_version != 2 && dmstatus_version != 3) { /* Error was already printed out in dmstatus_read(). */ return ERROR_FAIL; } uint32_t hartsel = (get_field(dmcontrol, DM_DMCONTROL_HARTSELHI) << DM_DMCONTROL_HARTSELLO_LENGTH) | get_field(dmcontrol, DM_DMCONTROL_HARTSELLO); info->hartsellen = 0; while (hartsel & 1) { info->hartsellen++; hartsel >>= 1; } LOG_DEBUG("hartsellen=%d", info->hartsellen); uint32_t hartinfo; if (dmi_read(target, &hartinfo, DM_HARTINFO) != ERROR_OK) return ERROR_FAIL; info->datasize = get_field(hartinfo, DM_HARTINFO_DATASIZE); info->dataaccess = get_field(hartinfo, DM_HARTINFO_DATAACCESS); info->dataaddr = get_field(hartinfo, DM_HARTINFO_DATAADDR); if (!get_field(dmstatus, DM_DMSTATUS_AUTHENTICATED)) { LOG_ERROR("Debugger is not authenticated to target Debug Module. " "(dmstatus=0x%x). Use `riscv authdata_read` and " "`riscv authdata_write` commands to authenticate.", dmstatus); /* If we return ERROR_FAIL here, then in a multicore setup the next * core won't be examined, which means we won't set up the * authentication commands for them, which means the config script * needs to be a lot more complex. */ return ERROR_OK; } if (dmi_read(target, &info->sbcs, DM_SBCS) != ERROR_OK) return ERROR_FAIL; /* Check that abstract data registers are accessible. */ uint32_t abstractcs; if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) return ERROR_FAIL; info->datacount = get_field(abstractcs, DM_ABSTRACTCS_DATACOUNT); info->progbufsize = get_field(abstractcs, DM_ABSTRACTCS_PROGBUFSIZE); LOG_INFO("datacount=%d progbufsize=%d", info->datacount, info->progbufsize); RISCV_INFO(r); r->impebreak = get_field(dmstatus, DM_DMSTATUS_IMPEBREAK); if (!has_sufficient_progbuf(target, 2)) { LOG_WARNING("We won't be able to execute fence instructions on this " "target. Memory may not always appear consistent. " "(progbufsize=%d, impebreak=%d)", info->progbufsize, r->impebreak); } if (info->progbufsize < 4 && riscv_enable_virtual) { LOG_ERROR("set_enable_virtual is not available on this target. It " "requires a program buffer size of at least 4. (progbufsize=%d) " "Use `riscv set_enable_virtual off` to continue." , info->progbufsize); } /* Before doing anything else we must first enumerate the harts. */ if (dm->hart_count < 0) { for (int i = 0; i < MIN(RISCV_MAX_HARTS, 1 << info->hartsellen); ++i) { r->current_hartid = i; if (riscv013_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; uint32_t s; if (dmstatus_read(target, &s, true) != ERROR_OK) return ERROR_FAIL; if (get_field(s, DM_DMSTATUS_ANYNONEXISTENT)) break; dm->hart_count = i + 1; if (get_field(s, DM_DMSTATUS_ANYHAVERESET)) dmi_write(target, DM_DMCONTROL, set_hartsel(DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET, i)); } LOG_DEBUG("Detected %d harts.", dm->hart_count); } r->current_hartid = target->coreid; if (dm->hart_count == 0) { LOG_ERROR("No harts found!"); return ERROR_FAIL; } /* Don't call any riscv_* functions until after we've counted the number of * cores and initialized registers. */ if (riscv013_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; bool halted = riscv_is_halted(target); if (!halted) { if (riscv013_halt_go(target) != ERROR_OK) { LOG_ERROR("Fatal: Hart %d failed to halt during examine()", r->current_hartid); return ERROR_FAIL; } } /* Without knowing anything else we can at least mess with the * program buffer. */ r->debug_buffer_size = info->progbufsize; int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64); if (result == ERROR_OK) r->xlen = 64; else r->xlen = 32; if (register_read(target, &r->misa, GDB_REGNO_MISA)) { LOG_ERROR("Fatal: Failed to read MISA from hart %d.", r->current_hartid); return ERROR_FAIL; } if (riscv_supports_extension(target, 'V')) { if (discover_vlenb(target) != ERROR_OK) return ERROR_FAIL; } /* Now init registers based on what we discovered. */ if (riscv_init_registers(target) != ERROR_OK) return ERROR_FAIL; /* Display this as early as possible to help people who are using * really slow simulators. */ LOG_DEBUG(" hart %d: XLEN=%d, misa=0x%" PRIx64, r->current_hartid, r->xlen, r->misa); if (!halted) riscv013_step_or_resume_current_hart(target, false, false); target_set_examined(target); if (target->smp) { bool haltgroup_supported; if (set_haltgroup(target, &haltgroup_supported) != ERROR_OK) return ERROR_FAIL; if (haltgroup_supported) LOG_INFO("Core %d made part of halt group %d.", target->coreid, target->smp); else LOG_INFO("Core %d could not be made part of halt group %d.", target->coreid, target->smp); } /* Some regression suites rely on seeing 'Examined RISC-V core' to know * when they can connect with gdb/telnet. * We will need to update those suites if we want to change that text. */ LOG_INFO("Examined RISC-V core; found %d harts", riscv_count_harts(target)); LOG_INFO(" hart %d: XLEN=%d, misa=0x%" PRIx64, r->current_hartid, r->xlen, r->misa); return ERROR_OK; } static int riscv013_authdata_read(struct target *target, uint32_t *value, unsigned int index) { if (index > 0) { LOG_ERROR("Spec 0.13 only has a single authdata register."); return ERROR_FAIL; } if (wait_for_authbusy(target, NULL) != ERROR_OK) return ERROR_FAIL; return dmi_read(target, value, DM_AUTHDATA); } static int riscv013_authdata_write(struct target *target, uint32_t value, unsigned int index) { if (index > 0) { LOG_ERROR("Spec 0.13 only has a single authdata register."); return ERROR_FAIL; } uint32_t before, after; if (wait_for_authbusy(target, &before) != ERROR_OK) return ERROR_FAIL; dmi_write(target, DM_AUTHDATA, value); if (wait_for_authbusy(target, &after) != ERROR_OK) return ERROR_FAIL; if (!get_field(before, DM_DMSTATUS_AUTHENTICATED) && get_field(after, DM_DMSTATUS_AUTHENTICATED)) { LOG_INFO("authdata_write resulted in successful authentication"); int result = ERROR_OK; dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; target_list_t *entry; list_for_each_entry(entry, &dm->target_list, list) { if (examine(entry->target) != ERROR_OK) result = ERROR_FAIL; } return result; } return ERROR_OK; } static int riscv013_hart_count(struct target *target) { dm013_info_t *dm = get_dm(target); assert(dm); return dm->hart_count; } /* Try to find out the widest memory access size depending on the selected memory access methods. */ static unsigned riscv013_data_bits(struct target *target) { RISCV013_INFO(info); RISCV_INFO(r); for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { int method = r->mem_access_methods[i]; if (method == RISCV_MEM_ACCESS_PROGBUF) { if (has_sufficient_progbuf(target, 3)) return riscv_xlen(target); } else if (method == RISCV_MEM_ACCESS_SYSBUS) { if (get_field(info->sbcs, DM_SBCS_SBACCESS128)) return 128; if (get_field(info->sbcs, DM_SBCS_SBACCESS64)) return 64; if (get_field(info->sbcs, DM_SBCS_SBACCESS32)) return 32; if (get_field(info->sbcs, DM_SBCS_SBACCESS16)) return 16; if (get_field(info->sbcs, DM_SBCS_SBACCESS8)) return 8; } else if (method == RISCV_MEM_ACCESS_ABSTRACT) { /* TODO: Once there is a spec for discovering abstract commands, we can * take those into account as well. For now we assume abstract commands * support XLEN-wide accesses. */ return riscv_xlen(target); } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) /* No further mem access method to try. */ break; } LOG_ERROR("Unable to determine supported data bits on this target. Assuming 32 bits."); return 32; } static COMMAND_HELPER(riscv013_print_info, struct target *target) { RISCV013_INFO(info); /* Abstract description. */ riscv_print_info_line(CMD, "target", "memory.read_while_running8", get_field(info->sbcs, DM_SBCS_SBACCESS8)); riscv_print_info_line(CMD, "target", "memory.write_while_running8", get_field(info->sbcs, DM_SBCS_SBACCESS8)); riscv_print_info_line(CMD, "target", "memory.read_while_running16", get_field(info->sbcs, DM_SBCS_SBACCESS16)); riscv_print_info_line(CMD, "target", "memory.write_while_running16", get_field(info->sbcs, DM_SBCS_SBACCESS16)); riscv_print_info_line(CMD, "target", "memory.read_while_running32", get_field(info->sbcs, DM_SBCS_SBACCESS32)); riscv_print_info_line(CMD, "target", "memory.write_while_running32", get_field(info->sbcs, DM_SBCS_SBACCESS32)); riscv_print_info_line(CMD, "target", "memory.read_while_running64", get_field(info->sbcs, DM_SBCS_SBACCESS64)); riscv_print_info_line(CMD, "target", "memory.write_while_running64", get_field(info->sbcs, DM_SBCS_SBACCESS64)); riscv_print_info_line(CMD, "target", "memory.read_while_running128", get_field(info->sbcs, DM_SBCS_SBACCESS128)); riscv_print_info_line(CMD, "target", "memory.write_while_running128", get_field(info->sbcs, DM_SBCS_SBACCESS128)); /* Lower level description. */ riscv_print_info_line(CMD, "dm", "abits", info->abits); riscv_print_info_line(CMD, "dm", "progbufsize", info->progbufsize); riscv_print_info_line(CMD, "dm", "sbversion", get_field(info->sbcs, DM_SBCS_SBVERSION)); riscv_print_info_line(CMD, "dm", "sbasize", get_field(info->sbcs, DM_SBCS_SBASIZE)); riscv_print_info_line(CMD, "dm", "sbaccess128", get_field(info->sbcs, DM_SBCS_SBACCESS128)); riscv_print_info_line(CMD, "dm", "sbaccess64", get_field(info->sbcs, DM_SBCS_SBACCESS64)); riscv_print_info_line(CMD, "dm", "sbaccess32", get_field(info->sbcs, DM_SBCS_SBACCESS32)); riscv_print_info_line(CMD, "dm", "sbaccess16", get_field(info->sbcs, DM_SBCS_SBACCESS16)); riscv_print_info_line(CMD, "dm", "sbaccess8", get_field(info->sbcs, DM_SBCS_SBACCESS8)); uint32_t dmstatus; if (dmstatus_read(target, &dmstatus, false) == ERROR_OK) riscv_print_info_line(CMD, "dm", "authenticated", get_field(dmstatus, DM_DMSTATUS_AUTHENTICATED)); return 0; } static int prep_for_vector_access(struct target *target, uint64_t *vtype, uint64_t *vl, unsigned *debug_vl) { RISCV_INFO(r); /* TODO: this continuous save/restore is terrible for performance. */ /* Write vtype and vl. */ unsigned encoded_vsew; switch (riscv_xlen(target)) { case 32: encoded_vsew = 2; break; case 64: encoded_vsew = 3; break; default: LOG_ERROR("Unsupported xlen: %d", riscv_xlen(target)); return ERROR_FAIL; } /* Save vtype and vl. */ if (register_read(target, vtype, GDB_REGNO_VTYPE) != ERROR_OK) return ERROR_FAIL; if (register_read(target, vl, GDB_REGNO_VL) != ERROR_OK) return ERROR_FAIL; if (register_write_direct(target, GDB_REGNO_VTYPE, encoded_vsew << 3) != ERROR_OK) return ERROR_FAIL; *debug_vl = DIV_ROUND_UP(r->vlenb * 8, riscv_xlen(target)); if (register_write_direct(target, GDB_REGNO_VL, *debug_vl) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int cleanup_after_vector_access(struct target *target, uint64_t vtype, uint64_t vl) { /* Restore vtype and vl. */ if (register_write_direct(target, GDB_REGNO_VTYPE, vtype) != ERROR_OK) return ERROR_FAIL; if (register_write_direct(target, GDB_REGNO_VL, vl) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int riscv013_get_register_buf(struct target *target, uint8_t *value, int regno) { assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31); if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; riscv_reg_t s0; if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; uint64_t mstatus; if (prep_for_register_access(target, &mstatus, regno) != ERROR_OK) return ERROR_FAIL; uint64_t vtype, vl; unsigned debug_vl; if (prep_for_vector_access(target, &vtype, &vl, &debug_vl) != ERROR_OK) return ERROR_FAIL; unsigned vnum = regno - GDB_REGNO_V0; unsigned xlen = riscv_xlen(target); struct riscv_program program; riscv_program_init(&program, target); riscv_program_insert(&program, vmv_x_s(S0, vnum)); riscv_program_insert(&program, vslide1down_vx(vnum, vnum, S0, true)); int result = ERROR_OK; for (unsigned i = 0; i < debug_vl; i++) { /* Executing the program might result in an exception if there is some * issue with the vector implementation/instructions we're using. If that * happens, attempt to restore as usual. We may have clobbered the * vector register we tried to read already. * For other failures, we just return error because things are probably * so messed up that attempting to restore isn't going to help. */ result = riscv_program_exec(&program, target); if (result == ERROR_OK) { uint64_t v; if (register_read_direct(target, &v, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; buf_set_u64(value, xlen * i, xlen, v); } else { break; } } if (cleanup_after_vector_access(target, vtype, vl) != ERROR_OK) return ERROR_FAIL; if (cleanup_after_register_access(target, mstatus, regno) != ERROR_OK) return ERROR_FAIL; if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; return result; } static int riscv013_set_register_buf(struct target *target, int regno, const uint8_t *value) { assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31); if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; riscv_reg_t s0; if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; uint64_t mstatus; if (prep_for_register_access(target, &mstatus, regno) != ERROR_OK) return ERROR_FAIL; uint64_t vtype, vl; unsigned debug_vl; if (prep_for_vector_access(target, &vtype, &vl, &debug_vl) != ERROR_OK) return ERROR_FAIL; unsigned vnum = regno - GDB_REGNO_V0; unsigned xlen = riscv_xlen(target); struct riscv_program program; riscv_program_init(&program, target); riscv_program_insert(&program, vslide1down_vx(vnum, vnum, S0, true)); int result = ERROR_OK; for (unsigned i = 0; i < debug_vl; i++) { if (register_write_direct(target, GDB_REGNO_S0, buf_get_u64(value, xlen * i, xlen)) != ERROR_OK) return ERROR_FAIL; result = riscv_program_exec(&program, target); if (result != ERROR_OK) break; } if (cleanup_after_vector_access(target, vtype, vl) != ERROR_OK) return ERROR_FAIL; if (cleanup_after_register_access(target, mstatus, regno) != ERROR_OK) return ERROR_FAIL; if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; return result; } static uint32_t sb_sbaccess(unsigned int size_bytes) { switch (size_bytes) { case 1: return set_field(0, DM_SBCS_SBACCESS, 0); case 2: return set_field(0, DM_SBCS_SBACCESS, 1); case 4: return set_field(0, DM_SBCS_SBACCESS, 2); case 8: return set_field(0, DM_SBCS_SBACCESS, 3); case 16: return set_field(0, DM_SBCS_SBACCESS, 4); } assert(0); return 0; } static int sb_write_address(struct target *target, target_addr_t address, bool ensure_success) { RISCV013_INFO(info); unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); /* There currently is no support for >64-bit addresses in OpenOCD. */ if (sbasize > 96) dmi_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS3, 0, false, false); if (sbasize > 64) dmi_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS2, 0, false, false); if (sbasize > 32) dmi_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS1, address >> 32, false, false); return dmi_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS0, address, false, ensure_success); } static int batch_run(const struct target *target, struct riscv_batch *batch) { RISCV013_INFO(info); RISCV_INFO(r); if (r->reset_delays_wait >= 0) { r->reset_delays_wait -= batch->used_scans; if (r->reset_delays_wait <= 0) { batch->idle_count = 0; info->dmi_busy_delay = 0; info->ac_busy_delay = 0; } } return riscv_batch_run(batch); } static int sba_supports_access(struct target *target, unsigned int size_bytes) { RISCV013_INFO(info); switch (size_bytes) { case 1: return get_field(info->sbcs, DM_SBCS_SBACCESS8); case 2: return get_field(info->sbcs, DM_SBCS_SBACCESS16); case 4: return get_field(info->sbcs, DM_SBCS_SBACCESS32); case 8: return get_field(info->sbcs, DM_SBCS_SBACCESS64); case 16: return get_field(info->sbcs, DM_SBCS_SBACCESS128); default: return 0; } } static int sample_memory_bus_v1(struct target *target, struct riscv_sample_buf *buf, const riscv_sample_config_t *config, int64_t until_ms) { RISCV013_INFO(info); unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); if (sbasize > 64) { LOG_ERROR("Memory sampling is only implemented for sbasize <= 64."); return ERROR_NOT_IMPLEMENTED; } if (get_field(info->sbcs, DM_SBCS_SBVERSION) != 1) { LOG_ERROR("Memory sampling is only implemented for SBA version 1."); return ERROR_NOT_IMPLEMENTED; } uint32_t sbcs = 0; uint32_t sbcs_valid = false; uint32_t sbaddress0 = 0; bool sbaddress0_valid = false; uint32_t sbaddress1 = 0; bool sbaddress1_valid = false; /* How often to read each value in a batch. */ const unsigned int repeat = 5; unsigned int enabled_count = 0; for (unsigned int i = 0; i < ARRAY_SIZE(config->bucket); i++) { if (config->bucket[i].enabled) enabled_count++; } while (timeval_ms() < until_ms) { /* * batch_run() adds to the batch, so we can't simply reuse the same * batch over and over. So we create a new one every time through the * loop. */ struct riscv_batch *batch = riscv_batch_alloc( target, 1 + enabled_count * 5 * repeat, info->dmi_busy_delay + info->bus_master_read_delay); if (!batch) return ERROR_FAIL; unsigned int result_bytes = 0; for (unsigned int n = 0; n < repeat; n++) { for (unsigned int i = 0; i < ARRAY_SIZE(config->bucket); i++) { if (config->bucket[i].enabled) { if (!sba_supports_access(target, config->bucket[i].size_bytes)) { LOG_ERROR("Hardware does not support SBA access for %d-byte memory sampling.", config->bucket[i].size_bytes); return ERROR_NOT_IMPLEMENTED; } uint32_t sbcs_write = DM_SBCS_SBREADONADDR; if (enabled_count == 1) sbcs_write |= DM_SBCS_SBREADONDATA; sbcs_write |= sb_sbaccess(config->bucket[i].size_bytes); if (!sbcs_valid || sbcs_write != sbcs) { riscv_batch_add_dmi_write(batch, DM_SBCS, sbcs_write); sbcs = sbcs_write; sbcs_valid = true; } if (sbasize > 32 && (!sbaddress1_valid || sbaddress1 != config->bucket[i].address >> 32)) { sbaddress1 = config->bucket[i].address >> 32; riscv_batch_add_dmi_write(batch, DM_SBADDRESS1, sbaddress1); sbaddress1_valid = true; } if (!sbaddress0_valid || sbaddress0 != (config->bucket[i].address & 0xffffffff)) { sbaddress0 = config->bucket[i].address; riscv_batch_add_dmi_write(batch, DM_SBADDRESS0, sbaddress0); sbaddress0_valid = true; } if (config->bucket[i].size_bytes > 4) riscv_batch_add_dmi_read(batch, DM_SBDATA1); riscv_batch_add_dmi_read(batch, DM_SBDATA0); result_bytes += 1 + config->bucket[i].size_bytes; } } } if (buf->used + result_bytes >= buf->size) { riscv_batch_free(batch); break; } size_t sbcs_key = riscv_batch_add_dmi_read(batch, DM_SBCS); int result = batch_run(target, batch); if (result != ERROR_OK) return result; uint32_t sbcs_read = riscv_batch_get_dmi_read_data(batch, sbcs_key); if (get_field(sbcs_read, DM_SBCS_SBBUSYERROR)) { /* Discard this batch (too much hassle to try to recover partial * data) and try again with a larger delay. */ info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1; dmi_write(target, DM_SBCS, sbcs_read | DM_SBCS_SBBUSYERROR | DM_SBCS_SBERROR); riscv_batch_free(batch); continue; } if (get_field(sbcs_read, DM_SBCS_SBERROR)) { /* The memory we're sampling was unreadable, somehow. Give up. */ dmi_write(target, DM_SBCS, DM_SBCS_SBBUSYERROR | DM_SBCS_SBERROR); riscv_batch_free(batch); return ERROR_FAIL; } unsigned int read = 0; for (unsigned int n = 0; n < repeat; n++) { for (unsigned int i = 0; i < ARRAY_SIZE(config->bucket); i++) { if (config->bucket[i].enabled) { assert(i < RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE); uint64_t value = 0; if (config->bucket[i].size_bytes > 4) value = ((uint64_t)riscv_batch_get_dmi_read_data(batch, read++)) << 32; value |= riscv_batch_get_dmi_read_data(batch, read++); buf->buf[buf->used] = i; buf_set_u64(buf->buf + buf->used + 1, 0, config->bucket[i].size_bytes * 8, value); buf->used += 1 + config->bucket[i].size_bytes; } } } riscv_batch_free(batch); } return ERROR_OK; } static int sample_memory(struct target *target, struct riscv_sample_buf *buf, riscv_sample_config_t *config, int64_t until_ms) { if (!config->enabled) return ERROR_OK; return sample_memory_bus_v1(target, buf, config, until_ms); } static int init_target(struct command_context *cmd_ctx, struct target *target) { LOG_DEBUG("init"); RISCV_INFO(generic_info); generic_info->get_register = &riscv013_get_register; generic_info->set_register = &riscv013_set_register; generic_info->get_register_buf = &riscv013_get_register_buf; generic_info->set_register_buf = &riscv013_set_register_buf; generic_info->select_current_hart = &riscv013_select_current_hart; generic_info->is_halted = &riscv013_is_halted; generic_info->resume_go = &riscv013_resume_go; generic_info->step_current_hart = &riscv013_step_current_hart; generic_info->on_halt = &riscv013_on_halt; generic_info->resume_prep = &riscv013_resume_prep; generic_info->halt_prep = &riscv013_halt_prep; generic_info->halt_go = &riscv013_halt_go; generic_info->on_step = &riscv013_on_step; generic_info->halt_reason = &riscv013_halt_reason; generic_info->read_debug_buffer = &riscv013_read_debug_buffer; generic_info->write_debug_buffer = &riscv013_write_debug_buffer; generic_info->execute_debug_buffer = &riscv013_execute_debug_buffer; generic_info->fill_dmi_write_u64 = &riscv013_fill_dmi_write_u64; generic_info->fill_dmi_read_u64 = &riscv013_fill_dmi_read_u64; generic_info->fill_dmi_nop_u64 = &riscv013_fill_dmi_nop_u64; generic_info->dmi_write_u64_bits = &riscv013_dmi_write_u64_bits; generic_info->authdata_read = &riscv013_authdata_read; generic_info->authdata_write = &riscv013_authdata_write; generic_info->dmi_read = &dmi_read; generic_info->dmi_write = &dmi_write; generic_info->read_memory = read_memory; generic_info->hart_count = &riscv013_hart_count; generic_info->data_bits = &riscv013_data_bits; generic_info->print_info = &riscv013_print_info; if (!generic_info->version_specific) { generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); if (!generic_info->version_specific) return ERROR_FAIL; } generic_info->sample_memory = sample_memory; riscv013_info_t *info = get_info(target); info->progbufsize = -1; info->dmi_busy_delay = 0; info->bus_master_read_delay = 0; info->bus_master_write_delay = 0; info->ac_busy_delay = 0; /* Assume all these abstract commands are supported until we learn * otherwise. * TODO: The spec allows eg. one CSR to be able to be accessed abstractly * while another one isn't. We don't track that this closely here, but in * the future we probably should. */ info->abstract_read_csr_supported = true; info->abstract_write_csr_supported = true; info->abstract_read_fpr_supported = true; info->abstract_write_fpr_supported = true; info->has_aampostincrement = YNM_MAYBE; return ERROR_OK; } static int assert_reset(struct target *target) { RISCV_INFO(r); select_dmi(target); uint32_t control_base = set_field(0, DM_DMCONTROL_DMACTIVE, 1); if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) { /* Run the user-supplied script if there is one. */ target_handle_event(target, TARGET_EVENT_RESET_ASSERT); } else if (target->rtos) { /* There's only one target, and OpenOCD thinks each hart is a thread. * We must reset them all. */ /* TODO: Try to use hasel in dmcontrol */ /* Set haltreq for each hart. */ uint32_t control = set_hartsel(control_base, target->coreid); control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); dmi_write(target, DM_DMCONTROL, control); /* Assert ndmreset */ control = set_field(control, DM_DMCONTROL_NDMRESET, 1); dmi_write(target, DM_DMCONTROL, control); } else { /* Reset just this hart. */ uint32_t control = set_hartsel(control_base, r->current_hartid); control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); control = set_field(control, DM_DMCONTROL_NDMRESET, 1); dmi_write(target, DM_DMCONTROL, control); } target->state = TARGET_RESET; dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; /* The DM might have gotten reset if OpenOCD called us in some reset that * involves SRST being toggled. So clear our cache which may be out of * date. */ memset(dm->progbuf_cache, 0, sizeof(dm->progbuf_cache)); return ERROR_OK; } static int deassert_reset(struct target *target) { RISCV_INFO(r); RISCV013_INFO(info); select_dmi(target); /* Clear the reset, but make sure haltreq is still set */ uint32_t control = 0, control_haltreq; control = set_field(control, DM_DMCONTROL_DMACTIVE, 1); control_haltreq = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); dmi_write(target, DM_DMCONTROL, set_hartsel(control_haltreq, r->current_hartid)); uint32_t dmstatus; int dmi_busy_delay = info->dmi_busy_delay; time_t start = time(NULL); for (int i = 0; i < riscv_count_harts(target); ++i) { int index = i; if (target->rtos) { if (index != target->coreid) continue; dmi_write(target, DM_DMCONTROL, set_hartsel(control_haltreq, index)); } else { index = r->current_hartid; } LOG_DEBUG("Waiting for hart %d to come out of reset.", index); while (1) { int result = dmstatus_read_timeout(target, &dmstatus, true, riscv_reset_timeout_sec); if (result == ERROR_TIMEOUT_REACHED) LOG_ERROR("Hart %d didn't complete a DMI read coming out of " "reset in %ds; Increase the timeout with riscv " "set_reset_timeout_sec.", index, riscv_reset_timeout_sec); if (result != ERROR_OK) return result; /* Certain debug modules, like the one in GD32VF103 * MCUs, violate the specification's requirement that * each hart is in "exactly one of four states" and, * during reset, report harts as both unavailable and * halted/running. To work around this, we check for * the absence of the unavailable state rather than * the presence of any other state. */ if (!get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) break; if (time(NULL) - start > riscv_reset_timeout_sec) { LOG_ERROR("Hart %d didn't leave reset in %ds; " "dmstatus=0x%x; " "Increase the timeout with riscv set_reset_timeout_sec.", index, riscv_reset_timeout_sec, dmstatus); return ERROR_FAIL; } } target->state = TARGET_HALTED; if (get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)) { /* Ack reset and clear DM_DMCONTROL_HALTREQ if previously set */ dmi_write(target, DM_DMCONTROL, set_hartsel(control, index) | DM_DMCONTROL_ACKHAVERESET); } if (!target->rtos) break; } info->dmi_busy_delay = dmi_busy_delay; return ERROR_OK; } static int execute_fence(struct target *target) { /* FIXME: For non-coherent systems we need to flush the caches right * here, but there's no ISA-defined way of doing that. */ { struct riscv_program program; riscv_program_init(&program, target); riscv_program_fence_i(&program); riscv_program_fence(&program); int result = riscv_program_exec(&program, target); if (result != ERROR_OK) LOG_DEBUG("Unable to execute pre-fence"); } return ERROR_OK; } static void log_memory_access(target_addr_t address, uint64_t value, unsigned size_bytes, bool read) { if (debug_level < LOG_LVL_DEBUG) return; char fmt[80]; sprintf(fmt, "M[0x%" TARGET_PRIxADDR "] %ss 0x%%0%d" PRIx64, address, read ? "read" : "write", size_bytes * 2); switch (size_bytes) { case 1: value &= 0xff; break; case 2: value &= 0xffff; break; case 4: value &= 0xffffffffUL; break; case 8: break; default: assert(false); } LOG_DEBUG(fmt, value); } /* Read the relevant sbdata regs depending on size, and put the results into * buffer. */ static int read_memory_bus_word(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { uint32_t value; int result; static int sbdata[4] = { DM_SBDATA0, DM_SBDATA1, DM_SBDATA2, DM_SBDATA3 }; assert(size <= 16); for (int i = (size - 1) / 4; i >= 0; i--) { result = dmi_op(target, &value, NULL, DMI_OP_READ, sbdata[i], 0, false, true); if (result != ERROR_OK) return result; buf_set_u32(buffer + i * 4, 0, 8 * MIN(size, 4), value); log_memory_access(address + i * 4, value, MIN(size, 4), true); } return ERROR_OK; } static target_addr_t sb_read_address(struct target *target) { RISCV013_INFO(info); unsigned sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); target_addr_t address = 0; uint32_t v; if (sbasize > 32) { dmi_read(target, &v, DM_SBADDRESS1); address |= v; address <<= 32; } dmi_read(target, &v, DM_SBADDRESS0); address |= v; return address; } static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs) { time_t start = time(NULL); while (1) { if (dmi_read(target, sbcs, DM_SBCS) != ERROR_OK) return ERROR_FAIL; if (!get_field(*sbcs, DM_SBCS_SBBUSY)) return ERROR_OK; if (time(NULL) - start > riscv_command_timeout_sec) { LOG_ERROR("Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", riscv_command_timeout_sec, *sbcs); return ERROR_FAIL; } } } static int modify_privilege(struct target *target, uint64_t *mstatus, uint64_t *mstatus_old) { if (riscv_enable_virtual && has_sufficient_progbuf(target, 5)) { /* Read DCSR */ uint64_t dcsr; if (register_read(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) return ERROR_FAIL; /* Read and save MSTATUS */ if (register_read(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) return ERROR_FAIL; *mstatus_old = *mstatus; /* If we come from m-mode with mprv set, we want to keep mpp */ if (get_field(dcsr, DCSR_PRV) < 3) { /* MPP = PRIV */ *mstatus = set_field(*mstatus, MSTATUS_MPP, get_field(dcsr, DCSR_PRV)); /* MPRV = 1 */ *mstatus = set_field(*mstatus, MSTATUS_MPRV, 1); /* Write MSTATUS */ if (*mstatus != *mstatus_old) if (register_write_direct(target, GDB_REGNO_MSTATUS, *mstatus) != ERROR_OK) return ERROR_FAIL; } } return ERROR_OK; } static int read_memory_bus_v0(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { if (size != increment) { LOG_ERROR("sba v0 reads only support size==increment"); return ERROR_NOT_IMPLEMENTED; } LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" TARGET_PRIxADDR, size, count, address); uint8_t *t_buffer = buffer; riscv_addr_t cur_addr = address; riscv_addr_t fin_addr = address + (count * size); uint32_t access = 0; const int DM_SBCS_SBSINGLEREAD_OFFSET = 20; const uint32_t DM_SBCS_SBSINGLEREAD = (0x1U << DM_SBCS_SBSINGLEREAD_OFFSET); const int DM_SBCS_SBAUTOREAD_OFFSET = 15; const uint32_t DM_SBCS_SBAUTOREAD = (0x1U << DM_SBCS_SBAUTOREAD_OFFSET); /* ww favorise one off reading if there is an issue */ if (count == 1) { for (uint32_t i = 0; i < count; i++) { if (dmi_read(target, &access, DM_SBCS) != ERROR_OK) return ERROR_FAIL; dmi_write(target, DM_SBADDRESS0, cur_addr); /* size/2 matching the bit access of the spec 0.13 */ access = set_field(access, DM_SBCS_SBACCESS, size/2); access = set_field(access, DM_SBCS_SBSINGLEREAD, 1); LOG_DEBUG("\r\nread_memory: sab: access: 0x%08x", access); dmi_write(target, DM_SBCS, access); /* 3) read */ uint32_t value; if (dmi_read(target, &value, DM_SBDATA0) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("\r\nread_memory: sab: value: 0x%08x", value); buf_set_u32(t_buffer, 0, 8 * size, value); t_buffer += size; cur_addr += size; } return ERROR_OK; } /* has to be the same size if we want to read a block */ LOG_DEBUG("reading block until final address 0x%" PRIx64, fin_addr); if (dmi_read(target, &access, DM_SBCS) != ERROR_OK) return ERROR_FAIL; /* set current address */ dmi_write(target, DM_SBADDRESS0, cur_addr); /* 2) write sbaccess=2, sbsingleread,sbautoread,sbautoincrement * size/2 matching the bit access of the spec 0.13 */ access = set_field(access, DM_SBCS_SBACCESS, size/2); access = set_field(access, DM_SBCS_SBAUTOREAD, 1); access = set_field(access, DM_SBCS_SBSINGLEREAD, 1); access = set_field(access, DM_SBCS_SBAUTOINCREMENT, 1); LOG_DEBUG("\r\naccess: 0x%08x", access); dmi_write(target, DM_SBCS, access); while (cur_addr < fin_addr) { LOG_DEBUG("\r\nsab:autoincrement: \r\n size: %d\tcount:%d\taddress: 0x%08" PRIx64, size, count, cur_addr); /* read */ uint32_t value; if (dmi_read(target, &value, DM_SBDATA0) != ERROR_OK) return ERROR_FAIL; buf_set_u32(t_buffer, 0, 8 * size, value); cur_addr += size; t_buffer += size; /* if we are reaching last address, we must clear autoread */ if (cur_addr == fin_addr && count != 1) { dmi_write(target, DM_SBCS, 0); if (dmi_read(target, &value, DM_SBDATA0) != ERROR_OK) return ERROR_FAIL; buf_set_u32(t_buffer, 0, 8 * size, value); } } uint32_t sbcs; if (dmi_read(target, &sbcs, DM_SBCS) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } /** * Read the requested memory using the system bus interface. */ static int read_memory_bus_v1(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { if (increment != size && increment != 0) { LOG_ERROR("sba v1 reads only support increment of size or 0"); return ERROR_NOT_IMPLEMENTED; } RISCV013_INFO(info); target_addr_t next_address = address; target_addr_t end_address = address + count * size; while (next_address < end_address) { uint32_t sbcs_write = set_field(0, DM_SBCS_SBREADONADDR, 1); sbcs_write |= sb_sbaccess(size); if (increment == size) sbcs_write = set_field(sbcs_write, DM_SBCS_SBAUTOINCREMENT, 1); if (count > 1) sbcs_write = set_field(sbcs_write, DM_SBCS_SBREADONDATA, count > 1); if (dmi_write(target, DM_SBCS, sbcs_write) != ERROR_OK) return ERROR_FAIL; /* This address write will trigger the first read. */ if (sb_write_address(target, next_address, true) != ERROR_OK) return ERROR_FAIL; if (info->bus_master_read_delay) { jtag_add_runtest(info->bus_master_read_delay, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("Failed to scan idle sequence"); return ERROR_FAIL; } } /* First value has been read, and is waiting for us to issue a DMI read * to get it. */ static int sbdata[4] = {DM_SBDATA0, DM_SBDATA1, DM_SBDATA2, DM_SBDATA3}; assert(size <= 16); target_addr_t next_read = address - 1; for (uint32_t i = (next_address - address) / size; i < count - 1; i++) { for (int j = (size - 1) / 4; j >= 0; j--) { uint32_t value; unsigned attempt = 0; while (1) { if (attempt++ > 100) { LOG_ERROR("DMI keeps being busy in while reading memory just past " TARGET_ADDR_FMT, next_read); return ERROR_FAIL; } keep_alive(); dmi_status_t status = dmi_scan(target, NULL, &value, DMI_OP_READ, sbdata[j], 0, false); if (status == DMI_STATUS_BUSY) increase_dmi_busy_delay(target); else if (status == DMI_STATUS_SUCCESS) break; else return ERROR_FAIL; } if (next_read != address - 1) { buf_set_u32(buffer + next_read - address, 0, 8 * MIN(size, 4), value); log_memory_access(next_read, value, MIN(size, 4), true); } next_read = address + i * size + j * 4; } } uint32_t sbcs_read = 0; if (count > 1) { uint32_t value; unsigned attempt = 0; while (1) { if (attempt++ > 100) { LOG_ERROR("DMI keeps being busy in while reading memory just past " TARGET_ADDR_FMT, next_read); return ERROR_FAIL; } dmi_status_t status = dmi_scan(target, NULL, &value, DMI_OP_NOP, 0, 0, false); if (status == DMI_STATUS_BUSY) increase_dmi_busy_delay(target); else if (status == DMI_STATUS_SUCCESS) break; else return ERROR_FAIL; } buf_set_u32(buffer + next_read - address, 0, 8 * MIN(size, 4), value); log_memory_access(next_read, value, MIN(size, 4), true); /* "Writes to sbcs while sbbusy is high result in undefined behavior. * A debugger must not write to sbcs until it reads sbbusy as 0." */ if (read_sbcs_nonbusy(target, &sbcs_read) != ERROR_OK) return ERROR_FAIL; sbcs_write = set_field(sbcs_write, DM_SBCS_SBREADONDATA, 0); if (dmi_write(target, DM_SBCS, sbcs_write) != ERROR_OK) return ERROR_FAIL; } /* Read the last word, after we disabled sbreadondata if necessary. */ if (!get_field(sbcs_read, DM_SBCS_SBERROR) && !get_field(sbcs_read, DM_SBCS_SBBUSYERROR)) { if (read_memory_bus_word(target, address + (count - 1) * size, size, buffer + (count - 1) * size) != ERROR_OK) return ERROR_FAIL; if (read_sbcs_nonbusy(target, &sbcs_read) != ERROR_OK) return ERROR_FAIL; } if (get_field(sbcs_read, DM_SBCS_SBBUSYERROR)) { /* We read while the target was busy. Slow down and try again. */ if (dmi_write(target, DM_SBCS, sbcs_read | DM_SBCS_SBBUSYERROR) != ERROR_OK) return ERROR_FAIL; next_address = sb_read_address(target); info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1; continue; } unsigned error = get_field(sbcs_read, DM_SBCS_SBERROR); if (error == 0) { next_address = end_address; } else { /* Some error indicating the bus access failed, but not because of * something we did wrong. */ if (dmi_write(target, DM_SBCS, DM_SBCS_SBERROR) != ERROR_OK) return ERROR_FAIL; return ERROR_FAIL; } } return ERROR_OK; } static void log_mem_access_result(struct target *target, bool success, int method, bool read) { RISCV_INFO(r); bool warn = false; char msg[60]; /* Compose the message */ snprintf(msg, 60, "%s to %s memory via %s.", success ? "Succeeded" : "Failed", read ? "read" : "write", (method == RISCV_MEM_ACCESS_PROGBUF) ? "program buffer" : (method == RISCV_MEM_ACCESS_SYSBUS) ? "system bus" : "abstract access"); /* Determine the log message severity. Show warnings only once. */ if (!success) { if (method == RISCV_MEM_ACCESS_PROGBUF) { warn = r->mem_access_progbuf_warn; r->mem_access_progbuf_warn = false; } if (method == RISCV_MEM_ACCESS_SYSBUS) { warn = r->mem_access_sysbus_warn; r->mem_access_sysbus_warn = false; } if (method == RISCV_MEM_ACCESS_ABSTRACT) { warn = r->mem_access_abstract_warn; r->mem_access_abstract_warn = false; } } if (warn) LOG_WARNING("%s", msg); else LOG_DEBUG("%s", msg); } static bool mem_should_skip_progbuf(struct target *target, target_addr_t address, uint32_t size, bool read, char **skip_reason) { assert(skip_reason); if (!has_sufficient_progbuf(target, 3)) { LOG_DEBUG("Skipping mem %s via progbuf - insufficient progbuf size.", read ? "read" : "write"); *skip_reason = "skipped (insufficient progbuf)"; return true; } if (target->state != TARGET_HALTED) { LOG_DEBUG("Skipping mem %s via progbuf - target not halted.", read ? "read" : "write"); *skip_reason = "skipped (target not halted)"; return true; } if (riscv_xlen(target) < size * 8) { LOG_DEBUG("Skipping mem %s via progbuf - XLEN (%d) is too short for %d-bit memory access.", read ? "read" : "write", riscv_xlen(target), size * 8); *skip_reason = "skipped (XLEN too short)"; return true; } if (size > 8) { LOG_DEBUG("Skipping mem %s via progbuf - unsupported size.", read ? "read" : "write"); *skip_reason = "skipped (unsupported size)"; return true; } if ((sizeof(address) * 8 > riscv_xlen(target)) && (address >> riscv_xlen(target))) { LOG_DEBUG("Skipping mem %s via progbuf - progbuf only supports %u-bit address.", read ? "read" : "write", riscv_xlen(target)); *skip_reason = "skipped (too large address)"; return true; } return false; } static bool mem_should_skip_sysbus(struct target *target, target_addr_t address, uint32_t size, uint32_t increment, bool read, char **skip_reason) { assert(skip_reason); RISCV013_INFO(info); if (!sba_supports_access(target, size)) { LOG_DEBUG("Skipping mem %s via system bus - unsupported size.", read ? "read" : "write"); *skip_reason = "skipped (unsupported size)"; return true; } unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); if ((sizeof(address) * 8 > sbasize) && (address >> sbasize)) { LOG_DEBUG("Skipping mem %s via system bus - sba only supports %u-bit address.", read ? "read" : "write", sbasize); *skip_reason = "skipped (too large address)"; return true; } if (read && increment != size && (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0 || increment != 0)) { LOG_DEBUG("Skipping mem read via system bus - " "sba reads only support size==increment or also size==0 for sba v1."); *skip_reason = "skipped (unsupported increment)"; return true; } return false; } static bool mem_should_skip_abstract(struct target *target, target_addr_t address, uint32_t size, uint32_t increment, bool read, char **skip_reason) { assert(skip_reason); if (size > 8) { /* TODO: Add 128b support if it's ever used. Involves modifying read/write_abstract_arg() to work on two 64b values. */ LOG_DEBUG("Skipping mem %s via abstract access - unsupported size: %d bits", read ? "read" : "write", size * 8); *skip_reason = "skipped (unsupported size)"; return true; } if ((sizeof(address) * 8 > riscv_xlen(target)) && (address >> riscv_xlen(target))) { LOG_DEBUG("Skipping mem %s via abstract access - abstract access only supports %u-bit address.", read ? "read" : "write", riscv_xlen(target)); *skip_reason = "skipped (too large address)"; return true; } if (read && size != increment) { LOG_ERROR("Skipping mem read via abstract access - " "abstract command reads only support size==increment."); *skip_reason = "skipped (unsupported increment)"; return true; } return false; } /* * Performs a memory read using memory access abstract commands. The read sizes * supported are 1, 2, and 4 bytes despite the spec's support of 8 and 16 byte * aamsize fields in the memory access abstract command. */ static int read_memory_abstract(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { RISCV013_INFO(info); int result = ERROR_OK; bool use_aampostincrement = info->has_aampostincrement != YNM_NO; LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, size, address); memset(buffer, 0, count * size); /* Convert the size (bytes) to width (bits) */ unsigned width = size << 3; /* Create the command (physical address, postincrement, read) */ uint32_t command = access_memory_command(target, false, width, use_aampostincrement, false); /* Execute the reads */ uint8_t *p = buffer; bool updateaddr = true; unsigned int width32 = (width < 32) ? 32 : width; for (uint32_t c = 0; c < count; c++) { /* Update the address if it is the first time or aampostincrement is not supported by the target. */ if (updateaddr) { /* Set arg1 to the address: address + c * size */ result = write_abstract_arg(target, 1, address + c * size, riscv_xlen(target)); if (result != ERROR_OK) { LOG_ERROR("Failed to write arg1 during read_memory_abstract()."); return result; } } /* Execute the command */ result = execute_abstract_command(target, command); if (info->has_aampostincrement == YNM_MAYBE) { if (result == ERROR_OK) { /* Safety: double-check that the address was really auto-incremented */ riscv_reg_t new_address = read_abstract_arg(target, 1, riscv_xlen(target)); if (new_address == address + size) { LOG_DEBUG("aampostincrement is supported on this target."); info->has_aampostincrement = YNM_YES; } else { LOG_WARNING("Buggy aampostincrement! Address not incremented correctly."); info->has_aampostincrement = YNM_NO; } } else { /* Try the same access but with postincrement disabled. */ command = access_memory_command(target, false, width, false, false); result = execute_abstract_command(target, command); if (result == ERROR_OK) { LOG_DEBUG("aampostincrement is not supported on this target."); info->has_aampostincrement = YNM_NO; } } } if (result != ERROR_OK) return result; /* Copy arg0 to buffer (rounded width up to nearest 32) */ riscv_reg_t value = read_abstract_arg(target, 0, width32); buf_set_u64(p, 0, 8 * size, value); if (info->has_aampostincrement == YNM_YES) updateaddr = false; p += size; } return result; } /* * Performs a memory write using memory access abstract commands. The write * sizes supported are 1, 2, and 4 bytes despite the spec's support of 8 and 16 * byte aamsize fields in the memory access abstract command. */ static int write_memory_abstract(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { RISCV013_INFO(info); int result = ERROR_OK; bool use_aampostincrement = info->has_aampostincrement != YNM_NO; LOG_DEBUG("writing %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, size, address); /* Convert the size (bytes) to width (bits) */ unsigned width = size << 3; /* Create the command (physical address, postincrement, write) */ uint32_t command = access_memory_command(target, false, width, use_aampostincrement, true); /* Execute the writes */ const uint8_t *p = buffer; bool updateaddr = true; for (uint32_t c = 0; c < count; c++) { /* Move data to arg0 */ riscv_reg_t value = buf_get_u64(p, 0, 8 * size); result = write_abstract_arg(target, 0, value, riscv_xlen(target)); if (result != ERROR_OK) { LOG_ERROR("Failed to write arg0 during write_memory_abstract()."); return result; } /* Update the address if it is the first time or aampostincrement is not supported by the target. */ if (updateaddr) { /* Set arg1 to the address: address + c * size */ result = write_abstract_arg(target, 1, address + c * size, riscv_xlen(target)); if (result != ERROR_OK) { LOG_ERROR("Failed to write arg1 during write_memory_abstract()."); return result; } } /* Execute the command */ result = execute_abstract_command(target, command); if (info->has_aampostincrement == YNM_MAYBE) { if (result == ERROR_OK) { /* Safety: double-check that the address was really auto-incremented */ riscv_reg_t new_address = read_abstract_arg(target, 1, riscv_xlen(target)); if (new_address == address + size) { LOG_DEBUG("aampostincrement is supported on this target."); info->has_aampostincrement = YNM_YES; } else { LOG_WARNING("Buggy aampostincrement! Address not incremented correctly."); info->has_aampostincrement = YNM_NO; } } else { /* Try the same access but with postincrement disabled. */ command = access_memory_command(target, false, width, false, true); result = execute_abstract_command(target, command); if (result == ERROR_OK) { LOG_DEBUG("aampostincrement is not supported on this target."); info->has_aampostincrement = YNM_NO; } } } if (result != ERROR_OK) return result; if (info->has_aampostincrement == YNM_YES) updateaddr = false; p += size; } return result; } /** * Read the requested memory, taking care to execute every read exactly once, * even if cmderr=busy is encountered. */ static int read_memory_progbuf_inner(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { RISCV013_INFO(info); int result = ERROR_OK; /* Write address to S0. */ result = register_write_direct(target, GDB_REGNO_S0, address); if (result != ERROR_OK) return result; if (increment == 0 && register_write_direct(target, GDB_REGNO_S2, 0) != ERROR_OK) return ERROR_FAIL; uint32_t command = access_register_command(target, GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); if (execute_abstract_command(target, command) != ERROR_OK) return ERROR_FAIL; /* First read has just triggered. Result is in s1. */ if (count == 1) { uint64_t value; if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; buf_set_u64(buffer, 0, 8 * size, value); log_memory_access(address, value, size, true); return ERROR_OK; } if (dmi_write(target, DM_ABSTRACTAUTO, 1 << DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET) != ERROR_OK) goto error; /* Read garbage from dmi_data0, which triggers another execution of the * program. Now dmi_data0 contains the first good result, and s1 the next * memory value. */ if (dmi_read_exec(target, NULL, DM_DATA0) != ERROR_OK) goto error; /* read_addr is the next address that the hart will read from, which is the * value in s0. */ unsigned index = 2; while (index < count) { riscv_addr_t read_addr = address + index * increment; LOG_DEBUG("i=%d, count=%d, read_addr=0x%" PRIx64, index, count, read_addr); /* The pipeline looks like this: * memory -> s1 -> dm_data0 -> debugger * Right now: * s0 contains read_addr * s1 contains mem[read_addr-size] * dm_data0 contains[read_addr-size*2] */ struct riscv_batch *batch = riscv_batch_alloc(target, 32, info->dmi_busy_delay + info->ac_busy_delay); if (!batch) return ERROR_FAIL; unsigned reads = 0; for (unsigned j = index; j < count; j++) { if (size > 4) riscv_batch_add_dmi_read(batch, DM_DATA1); riscv_batch_add_dmi_read(batch, DM_DATA0); reads++; if (riscv_batch_full(batch)) break; } batch_run(target, batch); /* Wait for the target to finish performing the last abstract command, * and update our copy of cmderr. If we see that DMI is busy here, * dmi_busy_delay will be incremented. */ uint32_t abstractcs; if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) return ERROR_FAIL; while (get_field(abstractcs, DM_ABSTRACTCS_BUSY)) if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) return ERROR_FAIL; info->cmderr = get_field(abstractcs, DM_ABSTRACTCS_CMDERR); unsigned next_index; unsigned ignore_last = 0; switch (info->cmderr) { case CMDERR_NONE: LOG_DEBUG("successful (partial?) memory read"); next_index = index + reads; break; case CMDERR_BUSY: LOG_DEBUG("memory read resulted in busy response"); increase_ac_busy_delay(target); riscv013_clear_abstract_error(target); dmi_write(target, DM_ABSTRACTAUTO, 0); uint32_t dmi_data0, dmi_data1 = 0; /* This is definitely a good version of the value that we * attempted to read when we discovered that the target was * busy. */ if (dmi_read(target, &dmi_data0, DM_DATA0) != ERROR_OK) { riscv_batch_free(batch); goto error; } if (size > 4 && dmi_read(target, &dmi_data1, DM_DATA1) != ERROR_OK) { riscv_batch_free(batch); goto error; } /* See how far we got, clobbering dmi_data0. */ if (increment == 0) { uint64_t counter; result = register_read_direct(target, &counter, GDB_REGNO_S2); next_index = counter; } else { uint64_t next_read_addr; result = register_read_direct(target, &next_read_addr, GDB_REGNO_S0); next_index = (next_read_addr - address) / increment; } if (result != ERROR_OK) { riscv_batch_free(batch); goto error; } uint64_t value64 = (((uint64_t)dmi_data1) << 32) | dmi_data0; buf_set_u64(buffer + (next_index - 2) * size, 0, 8 * size, value64); log_memory_access(address + (next_index - 2) * size, value64, size, true); /* Restore the command, and execute it. * Now DM_DATA0 contains the next value just as it would if no * error had occurred. */ dmi_write_exec(target, DM_COMMAND, command, true); next_index++; dmi_write(target, DM_ABSTRACTAUTO, 1 << DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); ignore_last = 1; break; default: LOG_DEBUG("error when reading memory, abstractcs=0x%08lx", (long)abstractcs); riscv013_clear_abstract_error(target); riscv_batch_free(batch); result = ERROR_FAIL; goto error; } /* Now read whatever we got out of the batch. */ dmi_status_t status = DMI_STATUS_SUCCESS; unsigned read = 0; assert(index >= 2); for (unsigned j = index - 2; j < index + reads; j++) { assert(j < count); LOG_DEBUG("index=%d, reads=%d, next_index=%d, ignore_last=%d, j=%d", index, reads, next_index, ignore_last, j); if (j + 3 + ignore_last > next_index) break; status = riscv_batch_get_dmi_read_op(batch, read); uint64_t value = riscv_batch_get_dmi_read_data(batch, read); read++; if (status != DMI_STATUS_SUCCESS) { /* If we're here because of busy count, dmi_busy_delay will * already have been increased and busy state will have been * cleared in dmi_read(). */ /* In at least some implementations, we issue a read, and then * can get busy back when we try to scan out the read result, * and the actual read value is lost forever. Since this is * rare in any case, we return error here and rely on our * caller to reread the entire block. */ LOG_WARNING("Batch memory read encountered DMI error %d. " "Falling back on slower reads.", status); riscv_batch_free(batch); result = ERROR_FAIL; goto error; } if (size > 4) { status = riscv_batch_get_dmi_read_op(batch, read); if (status != DMI_STATUS_SUCCESS) { LOG_WARNING("Batch memory read encountered DMI error %d. " "Falling back on slower reads.", status); riscv_batch_free(batch); result = ERROR_FAIL; goto error; } value <<= 32; value |= riscv_batch_get_dmi_read_data(batch, read); read++; } riscv_addr_t offset = j * size; buf_set_u64(buffer + offset, 0, 8 * size, value); log_memory_access(address + j * increment, value, size, true); } index = next_index; riscv_batch_free(batch); } dmi_write(target, DM_ABSTRACTAUTO, 0); if (count > 1) { /* Read the penultimate word. */ uint32_t dmi_data0, dmi_data1 = 0; if (dmi_read(target, &dmi_data0, DM_DATA0) != ERROR_OK) return ERROR_FAIL; if (size > 4 && dmi_read(target, &dmi_data1, DM_DATA1) != ERROR_OK) return ERROR_FAIL; uint64_t value64 = (((uint64_t)dmi_data1) << 32) | dmi_data0; buf_set_u64(buffer + size * (count - 2), 0, 8 * size, value64); log_memory_access(address + size * (count - 2), value64, size, true); } /* Read the last word. */ uint64_t value; result = register_read_direct(target, &value, GDB_REGNO_S1); if (result != ERROR_OK) goto error; buf_set_u64(buffer + size * (count-1), 0, 8 * size, value); log_memory_access(address + size * (count-1), value, size, true); return ERROR_OK; error: dmi_write(target, DM_ABSTRACTAUTO, 0); return result; } /* Only need to save/restore one GPR to read a single word, and the progbuf * program doesn't need to increment. */ static int read_memory_progbuf_one(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { uint64_t mstatus = 0; uint64_t mstatus_old = 0; if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) return ERROR_FAIL; uint64_t s0; int result = ERROR_FAIL; if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) goto restore_mstatus; /* Write the program (load, increment) */ struct riscv_program program; riscv_program_init(&program, target); if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) riscv_program_csrrsi(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); switch (size) { case 1: riscv_program_lbr(&program, GDB_REGNO_S0, GDB_REGNO_S0, 0); break; case 2: riscv_program_lhr(&program, GDB_REGNO_S0, GDB_REGNO_S0, 0); break; case 4: riscv_program_lwr(&program, GDB_REGNO_S0, GDB_REGNO_S0, 0); break; case 8: riscv_program_ldr(&program, GDB_REGNO_S0, GDB_REGNO_S0, 0); break; default: LOG_ERROR("Unsupported size: %d", size); goto restore_mstatus; } if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) riscv_program_csrrci(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); if (riscv_program_ebreak(&program) != ERROR_OK) goto restore_mstatus; if (riscv_program_write(&program) != ERROR_OK) goto restore_mstatus; /* Write address to S0, and execute buffer. */ if (write_abstract_arg(target, 0, address, riscv_xlen(target)) != ERROR_OK) goto restore_mstatus; uint32_t command = access_register_command(target, GDB_REGNO_S0, riscv_xlen(target), AC_ACCESS_REGISTER_WRITE | AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); if (execute_abstract_command(target, command) != ERROR_OK) goto restore_s0; uint64_t value; if (register_read(target, &value, GDB_REGNO_S0) != ERROR_OK) goto restore_s0; buf_set_u64(buffer, 0, 8 * size, value); log_memory_access(address, value, size, true); result = ERROR_OK; restore_s0: if (riscv_set_register(target, GDB_REGNO_S0, s0) != ERROR_OK) result = ERROR_FAIL; restore_mstatus: if (mstatus != mstatus_old) if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) result = ERROR_FAIL; return result; } /** * Read the requested memory, silently handling memory access errors. */ static int read_memory_progbuf(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { if (riscv_xlen(target) < size * 8) { LOG_ERROR("XLEN (%d) is too short for %d-bit memory read.", riscv_xlen(target), size * 8); return ERROR_FAIL; } int result = ERROR_OK; LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, size, address); select_dmi(target); memset(buffer, 0, count*size); if (execute_fence(target) != ERROR_OK) return ERROR_FAIL; if (count == 1) return read_memory_progbuf_one(target, address, size, buffer); uint64_t mstatus = 0; uint64_t mstatus_old = 0; if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) return ERROR_FAIL; /* s0 holds the next address to read from * s1 holds the next data value read * s2 is a counter in case increment is 0 */ uint64_t s0, s1, s2; if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; if (increment == 0 && register_read(target, &s2, GDB_REGNO_S2) != ERROR_OK) return ERROR_FAIL; /* Write the program (load, increment) */ struct riscv_program program; riscv_program_init(&program, target); if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) riscv_program_csrrsi(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); switch (size) { case 1: riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); break; case 2: riscv_program_lhr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); break; case 4: riscv_program_lwr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); break; case 8: riscv_program_ldr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); break; default: LOG_ERROR("Unsupported size: %d", size); return ERROR_FAIL; } if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) riscv_program_csrrci(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); if (increment == 0) riscv_program_addi(&program, GDB_REGNO_S2, GDB_REGNO_S2, 1); else riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, increment); if (riscv_program_ebreak(&program) != ERROR_OK) return ERROR_FAIL; if (riscv_program_write(&program) != ERROR_OK) return ERROR_FAIL; result = read_memory_progbuf_inner(target, address, size, count, buffer, increment); if (result != ERROR_OK) { /* The full read did not succeed, so we will try to read each word individually. */ /* This will not be fast, but reading outside actual memory is a special case anyway. */ /* It will make the toolchain happier, especially Eclipse Memory View as it reads ahead. */ target_addr_t address_i = address; uint32_t count_i = 1; uint8_t *buffer_i = buffer; for (uint32_t i = 0; i < count; i++, address_i += increment, buffer_i += size) { /* TODO: This is much slower than it needs to be because we end up * writing the address to read for every word we read. */ result = read_memory_progbuf_inner(target, address_i, size, count_i, buffer_i, increment); /* The read of a single word failed, so we will just return 0 for that instead */ if (result != ERROR_OK) { LOG_DEBUG("error reading single word of %d bytes from 0x%" TARGET_PRIxADDR, size, address_i); buf_set_u64(buffer_i, 0, 8 * size, 0); } } result = ERROR_OK; } riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); if (increment == 0) riscv_set_register(target, GDB_REGNO_S2, s2); /* Restore MSTATUS */ if (mstatus != mstatus_old) if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) return ERROR_FAIL; return result; } static int read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { if (count == 0) return ERROR_OK; if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) { LOG_ERROR("BUG: Unsupported size for memory read: %d", size); return ERROR_FAIL; } int ret = ERROR_FAIL; RISCV_INFO(r); RISCV013_INFO(info); char *progbuf_result = "disabled"; char *sysbus_result = "disabled"; char *abstract_result = "disabled"; for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { int method = r->mem_access_methods[i]; if (method == RISCV_MEM_ACCESS_PROGBUF) { if (mem_should_skip_progbuf(target, address, size, true, &progbuf_result)) continue; ret = read_memory_progbuf(target, address, size, count, buffer, increment); if (ret != ERROR_OK) progbuf_result = "failed"; } else if (method == RISCV_MEM_ACCESS_SYSBUS) { if (mem_should_skip_sysbus(target, address, size, increment, true, &sysbus_result)) continue; if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0) ret = read_memory_bus_v0(target, address, size, count, buffer, increment); else if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 1) ret = read_memory_bus_v1(target, address, size, count, buffer, increment); if (ret != ERROR_OK) sysbus_result = "failed"; } else if (method == RISCV_MEM_ACCESS_ABSTRACT) { if (mem_should_skip_abstract(target, address, size, increment, true, &abstract_result)) continue; ret = read_memory_abstract(target, address, size, count, buffer, increment); if (ret != ERROR_OK) abstract_result = "failed"; } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) /* No further mem access method to try. */ break; log_mem_access_result(target, ret == ERROR_OK, method, true); if (ret == ERROR_OK) return ret; } LOG_ERROR("Target %s: Failed to read memory (addr=0x%" PRIx64 ")", target_name(target), address); LOG_ERROR(" progbuf=%s, sysbus=%s, abstract=%s", progbuf_result, sysbus_result, abstract_result); return ret; } static int write_memory_bus_v0(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { /*1) write sbaddress: for singlewrite and autoincrement, we need to write the address once*/ LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" TARGET_PRIxADDR, size, count, address); dmi_write(target, DM_SBADDRESS0, address); int64_t value = 0; int64_t access = 0; riscv_addr_t offset = 0; riscv_addr_t t_addr = 0; const uint8_t *t_buffer = buffer + offset; /* B.8 Writing Memory, single write check if we write in one go */ if (count == 1) { /* count is in bytes here */ value = buf_get_u64(t_buffer, 0, 8 * size); access = 0; access = set_field(access, DM_SBCS_SBACCESS, size/2); dmi_write(target, DM_SBCS, access); LOG_DEBUG("\r\naccess: 0x%08" PRIx64, access); LOG_DEBUG("\r\nwrite_memory:SAB: ONE OFF: value 0x%08" PRIx64, value); dmi_write(target, DM_SBDATA0, value); return ERROR_OK; } /*B.8 Writing Memory, using autoincrement*/ access = 0; access = set_field(access, DM_SBCS_SBACCESS, size/2); access = set_field(access, DM_SBCS_SBAUTOINCREMENT, 1); LOG_DEBUG("\r\naccess: 0x%08" PRIx64, access); dmi_write(target, DM_SBCS, access); /*2)set the value according to the size required and write*/ for (riscv_addr_t i = 0; i < count; ++i) { offset = size*i; /* for monitoring only */ t_addr = address + offset; t_buffer = buffer + offset; value = buf_get_u64(t_buffer, 0, 8 * size); LOG_DEBUG("SAB:autoincrement: expected address: 0x%08x value: 0x%08x" PRIx64, (uint32_t)t_addr, (uint32_t)value); dmi_write(target, DM_SBDATA0, value); } /*reset the autoincrement when finished (something weird is happening if this is not done at the end*/ access = set_field(access, DM_SBCS_SBAUTOINCREMENT, 0); dmi_write(target, DM_SBCS, access); return ERROR_OK; } static int write_memory_bus_v1(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { RISCV013_INFO(info); uint32_t sbcs = sb_sbaccess(size); sbcs = set_field(sbcs, DM_SBCS_SBAUTOINCREMENT, 1); dmi_write(target, DM_SBCS, sbcs); target_addr_t next_address = address; target_addr_t end_address = address + count * size; int result; sb_write_address(target, next_address, true); while (next_address < end_address) { LOG_DEBUG("transferring burst starting at address 0x%" TARGET_PRIxADDR, next_address); struct riscv_batch *batch = riscv_batch_alloc( target, 32, info->dmi_busy_delay + info->bus_master_write_delay); if (!batch) return ERROR_FAIL; for (uint32_t i = (next_address - address) / size; i < count; i++) { const uint8_t *p = buffer + i * size; if (riscv_batch_available_scans(batch) < (size + 3) / 4) break; if (size > 12) riscv_batch_add_dmi_write(batch, DM_SBDATA3, ((uint32_t) p[12]) | (((uint32_t) p[13]) << 8) | (((uint32_t) p[14]) << 16) | (((uint32_t) p[15]) << 24)); if (size > 8) riscv_batch_add_dmi_write(batch, DM_SBDATA2, ((uint32_t) p[8]) | (((uint32_t) p[9]) << 8) | (((uint32_t) p[10]) << 16) | (((uint32_t) p[11]) << 24)); if (size > 4) riscv_batch_add_dmi_write(batch, DM_SBDATA1, ((uint32_t) p[4]) | (((uint32_t) p[5]) << 8) | (((uint32_t) p[6]) << 16) | (((uint32_t) p[7]) << 24)); uint32_t value = p[0]; if (size > 2) { value |= ((uint32_t) p[2]) << 16; value |= ((uint32_t) p[3]) << 24; } if (size > 1) value |= ((uint32_t) p[1]) << 8; riscv_batch_add_dmi_write(batch, DM_SBDATA0, value); log_memory_access(address + i * size, value, size, false); next_address += size; } /* Execute the batch of writes */ result = batch_run(target, batch); riscv_batch_free(batch); if (result != ERROR_OK) return result; /* Read sbcs value. * At the same time, detect if DMI busy has occurred during the batch write. */ bool dmi_busy_encountered; if (dmi_op(target, &sbcs, &dmi_busy_encountered, DMI_OP_READ, DM_SBCS, 0, false, true) != ERROR_OK) return ERROR_FAIL; if (dmi_busy_encountered) LOG_DEBUG("DMI busy encountered during system bus write."); /* Wait until sbbusy goes low */ time_t start = time(NULL); while (get_field(sbcs, DM_SBCS_SBBUSY)) { if (time(NULL) - start > riscv_command_timeout_sec) { LOG_ERROR("Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", riscv_command_timeout_sec, sbcs); return ERROR_FAIL; } if (dmi_read(target, &sbcs, DM_SBCS) != ERROR_OK) return ERROR_FAIL; } if (get_field(sbcs, DM_SBCS_SBBUSYERROR)) { /* We wrote while the target was busy. */ LOG_DEBUG("Sbbusyerror encountered during system bus write."); /* Clear the sticky error flag. */ dmi_write(target, DM_SBCS, sbcs | DM_SBCS_SBBUSYERROR); /* Slow down before trying again. */ info->bus_master_write_delay += info->bus_master_write_delay / 10 + 1; } if (get_field(sbcs, DM_SBCS_SBBUSYERROR) || dmi_busy_encountered) { /* Recover from the case when the write commands were issued too fast. * Determine the address from which to resume writing. */ next_address = sb_read_address(target); if (next_address < address) { /* This should never happen, probably buggy hardware. */ LOG_DEBUG("unexpected sbaddress=0x%" TARGET_PRIxADDR " - buggy sbautoincrement in hw?", next_address); /* Fail the whole operation. */ return ERROR_FAIL; } /* Try again - resume writing. */ continue; } unsigned int sberror = get_field(sbcs, DM_SBCS_SBERROR); if (sberror != 0) { /* Sberror indicates the bus access failed, but not because we issued the writes * too fast. Cannot recover. Sbaddress holds the address where the error occurred * (unless sbautoincrement in the HW is buggy). */ target_addr_t sbaddress = sb_read_address(target); LOG_DEBUG("System bus access failed with sberror=%u (sbaddress=0x%" TARGET_PRIxADDR ")", sberror, sbaddress); if (sbaddress < address) { /* This should never happen, probably buggy hardware. * Make a note to the user not to trust the sbaddress value. */ LOG_DEBUG("unexpected sbaddress=0x%" TARGET_PRIxADDR " - buggy sbautoincrement in hw?", next_address); } /* Clear the sticky error flag */ dmi_write(target, DM_SBCS, DM_SBCS_SBERROR); /* Fail the whole operation */ return ERROR_FAIL; } } return ERROR_OK; } static int write_memory_progbuf(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { RISCV013_INFO(info); if (riscv_xlen(target) < size * 8) { LOG_ERROR("XLEN (%d) is too short for %d-bit memory write.", riscv_xlen(target), size * 8); return ERROR_FAIL; } LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address); select_dmi(target); uint64_t mstatus = 0; uint64_t mstatus_old = 0; if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) return ERROR_FAIL; /* s0 holds the next address to write to * s1 holds the next data value to write */ int result = ERROR_OK; uint64_t s0, s1; if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; /* Write the program (store, increment) */ struct riscv_program program; riscv_program_init(&program, target); if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) riscv_program_csrrsi(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); switch (size) { case 1: riscv_program_sbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); break; case 2: riscv_program_shr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); break; case 4: riscv_program_swr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); break; case 8: riscv_program_sdr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); break; default: LOG_ERROR("write_memory_progbuf(): Unsupported size: %d", size); result = ERROR_FAIL; goto error; } if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) riscv_program_csrrci(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); result = riscv_program_ebreak(&program); if (result != ERROR_OK) goto error; riscv_program_write(&program); riscv_addr_t cur_addr = address; riscv_addr_t fin_addr = address + (count * size); bool setup_needed = true; LOG_DEBUG("writing until final address 0x%016" PRIx64, fin_addr); while (cur_addr < fin_addr) { LOG_DEBUG("transferring burst starting at address 0x%016" PRIx64, cur_addr); struct riscv_batch *batch = riscv_batch_alloc( target, 32, info->dmi_busy_delay + info->ac_busy_delay); if (!batch) goto error; /* To write another word, we put it in S1 and execute the program. */ unsigned start = (cur_addr - address) / size; for (unsigned i = start; i < count; ++i) { unsigned offset = size*i; const uint8_t *t_buffer = buffer + offset; uint64_t value = buf_get_u64(t_buffer, 0, 8 * size); log_memory_access(address + offset, value, size, false); cur_addr += size; if (setup_needed) { result = register_write_direct(target, GDB_REGNO_S0, address + offset); if (result != ERROR_OK) { riscv_batch_free(batch); goto error; } /* Write value. */ if (size > 4) dmi_write(target, DM_DATA1, value >> 32); dmi_write(target, DM_DATA0, value); /* Write and execute command that moves value into S1 and * executes program buffer. */ uint32_t command = access_register_command(target, GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_POSTEXEC | AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_WRITE); result = execute_abstract_command(target, command); if (result != ERROR_OK) { riscv_batch_free(batch); goto error; } /* Turn on autoexec */ dmi_write(target, DM_ABSTRACTAUTO, 1 << DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); setup_needed = false; } else { if (size > 4) riscv_batch_add_dmi_write(batch, DM_DATA1, value >> 32); riscv_batch_add_dmi_write(batch, DM_DATA0, value); if (riscv_batch_full(batch)) break; } } result = batch_run(target, batch); riscv_batch_free(batch); if (result != ERROR_OK) goto error; /* Note that if the scan resulted in a Busy DMI response, it * is this read to abstractcs that will cause the dmi_busy_delay * to be incremented if necessary. */ uint32_t abstractcs; bool dmi_busy_encountered; result = dmi_op(target, &abstractcs, &dmi_busy_encountered, DMI_OP_READ, DM_ABSTRACTCS, 0, false, true); if (result != ERROR_OK) goto error; while (get_field(abstractcs, DM_ABSTRACTCS_BUSY)) if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) return ERROR_FAIL; info->cmderr = get_field(abstractcs, DM_ABSTRACTCS_CMDERR); if (info->cmderr == CMDERR_NONE && !dmi_busy_encountered) { LOG_DEBUG("successful (partial?) memory write"); } else if (info->cmderr == CMDERR_BUSY || dmi_busy_encountered) { if (info->cmderr == CMDERR_BUSY) LOG_DEBUG("Memory write resulted in abstract command busy response."); else if (dmi_busy_encountered) LOG_DEBUG("Memory write resulted in DMI busy response."); riscv013_clear_abstract_error(target); increase_ac_busy_delay(target); dmi_write(target, DM_ABSTRACTAUTO, 0); result = register_read_direct(target, &cur_addr, GDB_REGNO_S0); if (result != ERROR_OK) goto error; setup_needed = true; } else { LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs); riscv013_clear_abstract_error(target); result = ERROR_FAIL; goto error; } } error: dmi_write(target, DM_ABSTRACTAUTO, 0); if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK) return ERROR_FAIL; if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; /* Restore MSTATUS */ if (mstatus != mstatus_old) if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) return ERROR_FAIL; if (execute_fence(target) != ERROR_OK) return ERROR_FAIL; return result; } static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) { LOG_ERROR("BUG: Unsupported size for memory write: %d", size); return ERROR_FAIL; } int ret = ERROR_FAIL; RISCV_INFO(r); RISCV013_INFO(info); char *progbuf_result = "disabled"; char *sysbus_result = "disabled"; char *abstract_result = "disabled"; for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { int method = r->mem_access_methods[i]; if (method == RISCV_MEM_ACCESS_PROGBUF) { if (mem_should_skip_progbuf(target, address, size, false, &progbuf_result)) continue; ret = write_memory_progbuf(target, address, size, count, buffer); if (ret != ERROR_OK) progbuf_result = "failed"; } else if (method == RISCV_MEM_ACCESS_SYSBUS) { if (mem_should_skip_sysbus(target, address, size, 0, false, &sysbus_result)) continue; if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0) ret = write_memory_bus_v0(target, address, size, count, buffer); else if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 1) ret = write_memory_bus_v1(target, address, size, count, buffer); if (ret != ERROR_OK) sysbus_result = "failed"; } else if (method == RISCV_MEM_ACCESS_ABSTRACT) { if (mem_should_skip_abstract(target, address, size, 0, false, &abstract_result)) continue; ret = write_memory_abstract(target, address, size, count, buffer); if (ret != ERROR_OK) abstract_result = "failed"; } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) /* No further mem access method to try. */ break; log_mem_access_result(target, ret == ERROR_OK, method, false); if (ret == ERROR_OK) return ret; } LOG_ERROR("Target %s: Failed to write memory (addr=0x%" PRIx64 ")", target_name(target), address); LOG_ERROR(" progbuf=%s, sysbus=%s, abstract=%s", progbuf_result, sysbus_result, abstract_result); return ret; } static int arch_state(struct target *target) { return ERROR_OK; } struct target_type riscv013_target = { .name = "riscv", .init_target = init_target, .deinit_target = deinit_target, .examine = examine, .poll = &riscv_openocd_poll, .halt = &riscv_halt, .step = &riscv_openocd_step, .assert_reset = assert_reset, .deassert_reset = deassert_reset, .write_memory = write_memory, .arch_state = arch_state }; /*** 0.13-specific implementations of various RISC-V helper functions. ***/ static int riscv013_get_register(struct target *target, riscv_reg_t *value, int rid) { LOG_DEBUG("[%s] reading register %s", target_name(target), gdb_regno_name(rid)); if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; int result = ERROR_OK; if (rid == GDB_REGNO_PC) { /* TODO: move this into riscv.c. */ result = register_read(target, value, GDB_REGNO_DPC); LOG_DEBUG("[%d] read PC from DPC: 0x%" PRIx64, target->coreid, *value); } else if (rid == GDB_REGNO_PRIV) { uint64_t dcsr; /* TODO: move this into riscv.c. */ result = register_read(target, &dcsr, GDB_REGNO_DCSR); *value = set_field(0, VIRT_PRIV_V, get_field(dcsr, CSR_DCSR_V)); *value = set_field(*value, VIRT_PRIV_PRV, get_field(dcsr, CSR_DCSR_PRV)); } else { result = register_read(target, value, rid); if (result != ERROR_OK) *value = -1; } return result; } static int riscv013_set_register(struct target *target, int rid, uint64_t value) { riscv013_select_current_hart(target); LOG_DEBUG("[%d] writing 0x%" PRIx64 " to register %s", target->coreid, value, gdb_regno_name(rid)); if (rid <= GDB_REGNO_XPR31) { return register_write_direct(target, rid, value); } else if (rid == GDB_REGNO_PC) { LOG_DEBUG("[%d] writing PC to DPC: 0x%" PRIx64, target->coreid, value); register_write_direct(target, GDB_REGNO_DPC, value); uint64_t actual_value; register_read_direct(target, &actual_value, GDB_REGNO_DPC); LOG_DEBUG("[%d] actual DPC written: 0x%016" PRIx64, target->coreid, actual_value); if (value != actual_value) { LOG_ERROR("Written PC (0x%" PRIx64 ") does not match read back " "value (0x%" PRIx64 ")", value, actual_value); return ERROR_FAIL; } } else if (rid == GDB_REGNO_PRIV) { uint64_t dcsr; register_read(target, &dcsr, GDB_REGNO_DCSR); dcsr = set_field(dcsr, CSR_DCSR_PRV, get_field(value, VIRT_PRIV_PRV)); dcsr = set_field(dcsr, CSR_DCSR_V, get_field(value, VIRT_PRIV_V)); return register_write_direct(target, GDB_REGNO_DCSR, dcsr); } else { return register_write_direct(target, rid, value); } return ERROR_OK; } static int riscv013_select_current_hart(struct target *target) { RISCV_INFO(r); dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; if (r->current_hartid == dm->current_hartid) return ERROR_OK; uint32_t dmcontrol; /* TODO: can't we just "dmcontrol = DMI_DMACTIVE"? */ if (dmi_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) return ERROR_FAIL; dmcontrol = set_hartsel(dmcontrol, r->current_hartid); int result = dmi_write(target, DM_DMCONTROL, dmcontrol); dm->current_hartid = r->current_hartid; return result; } /* Select all harts that were prepped and that are selectable, clearing the * prepped flag on the harts that actually were selected. */ static int select_prepped_harts(struct target *target, bool *use_hasel) { dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; if (!dm->hasel_supported) { RISCV_INFO(r); r->prepped = false; *use_hasel = false; return ERROR_OK; } assert(dm->hart_count); unsigned hawindow_count = (dm->hart_count + 31) / 32; uint32_t hawindow[hawindow_count]; memset(hawindow, 0, sizeof(uint32_t) * hawindow_count); target_list_t *entry; unsigned total_selected = 0; list_for_each_entry(entry, &dm->target_list, list) { struct target *t = entry->target; struct riscv_info *r = riscv_info(t); riscv013_info_t *info = get_info(t); unsigned index = info->index; LOG_DEBUG("index=%d, coreid=%d, prepped=%d", index, t->coreid, r->prepped); r->selected = r->prepped; if (r->prepped) { hawindow[index / 32] |= 1 << (index % 32); r->prepped = false; total_selected++; } index++; } /* Don't use hasel if we only need to talk to one hart. */ if (total_selected <= 1) { *use_hasel = false; return ERROR_OK; } for (unsigned i = 0; i < hawindow_count; i++) { if (dmi_write(target, DM_HAWINDOWSEL, i) != ERROR_OK) return ERROR_FAIL; if (dmi_write(target, DM_HAWINDOW, hawindow[i]) != ERROR_OK) return ERROR_FAIL; } *use_hasel = true; return ERROR_OK; } static int riscv013_halt_prep(struct target *target) { return ERROR_OK; } static int riscv013_halt_go(struct target *target) { bool use_hasel = false; if (select_prepped_harts(target, &use_hasel) != ERROR_OK) return ERROR_FAIL; RISCV_INFO(r); LOG_DEBUG("halting hart %d", r->current_hartid); /* Issue the halt command, and then wait for the current hart to halt. */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ; if (use_hasel) dmcontrol |= DM_DMCONTROL_HASEL; dmcontrol = set_hartsel(dmcontrol, r->current_hartid); dmi_write(target, DM_DMCONTROL, dmcontrol); for (size_t i = 0; i < 256; ++i) if (riscv_is_halted(target)) break; if (!riscv_is_halted(target)) { uint32_t dmstatus; if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; if (dmi_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) return ERROR_FAIL; LOG_ERROR("unable to halt hart %d", r->current_hartid); LOG_ERROR(" dmcontrol=0x%08x", dmcontrol); LOG_ERROR(" dmstatus =0x%08x", dmstatus); return ERROR_FAIL; } dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HALTREQ, 0); dmi_write(target, DM_DMCONTROL, dmcontrol); if (use_hasel) { target_list_t *entry; dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; list_for_each_entry(entry, &dm->target_list, list) { struct target *t = entry->target; t->state = TARGET_HALTED; if (t->debug_reason == DBG_REASON_NOTHALTED) t->debug_reason = DBG_REASON_DBGRQ; } } /* The "else" case is handled in halt_go(). */ return ERROR_OK; } static int riscv013_resume_go(struct target *target) { bool use_hasel = false; if (select_prepped_harts(target, &use_hasel) != ERROR_OK) return ERROR_FAIL; return riscv013_step_or_resume_current_hart(target, false, use_hasel); } static int riscv013_step_current_hart(struct target *target) { return riscv013_step_or_resume_current_hart(target, true, false); } static int riscv013_resume_prep(struct target *target) { return riscv013_on_step_or_resume(target, false); } static int riscv013_on_step(struct target *target) { return riscv013_on_step_or_resume(target, true); } static int riscv013_on_halt(struct target *target) { return ERROR_OK; } static bool riscv013_is_halted(struct target *target) { uint32_t dmstatus; if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return false; if (get_field(dmstatus, DM_DMSTATUS_ANYUNAVAIL)) LOG_ERROR("Hart %d is unavailable.", riscv_current_hartid(target)); if (get_field(dmstatus, DM_DMSTATUS_ANYNONEXISTENT)) LOG_ERROR("Hart %d doesn't exist.", riscv_current_hartid(target)); if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) { int hartid = riscv_current_hartid(target); LOG_INFO("Hart %d unexpectedly reset!", hartid); /* TODO: Can we make this more obvious to eg. a gdb user? */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET; dmcontrol = set_hartsel(dmcontrol, hartid); /* If we had been halted when we reset, request another halt. If we * ended up running out of reset, then the user will (hopefully) get a * message that a reset happened, that the target is running, and then * that it is halted again once the request goes through. */ if (target->state == TARGET_HALTED) dmcontrol |= DM_DMCONTROL_HALTREQ; dmi_write(target, DM_DMCONTROL, dmcontrol); } return get_field(dmstatus, DM_DMSTATUS_ALLHALTED); } static enum riscv_halt_reason riscv013_halt_reason(struct target *target) { riscv_reg_t dcsr; int result = register_read(target, &dcsr, GDB_REGNO_DCSR); if (result != ERROR_OK) return RISCV_HALT_UNKNOWN; LOG_DEBUG("dcsr.cause: 0x%" PRIx64, get_field(dcsr, CSR_DCSR_CAUSE)); switch (get_field(dcsr, CSR_DCSR_CAUSE)) { case CSR_DCSR_CAUSE_SWBP: return RISCV_HALT_BREAKPOINT; case CSR_DCSR_CAUSE_TRIGGER: /* We could get here before triggers are enumerated if a trigger was * already set when we connected. Force enumeration now, which has the * side effect of clearing any triggers we did not set. */ riscv_enumerate_triggers(target); LOG_DEBUG("{%d} halted because of trigger", target->coreid); return RISCV_HALT_TRIGGER; case CSR_DCSR_CAUSE_STEP: return RISCV_HALT_SINGLESTEP; case CSR_DCSR_CAUSE_DEBUGINT: case CSR_DCSR_CAUSE_HALT: return RISCV_HALT_INTERRUPT; case CSR_DCSR_CAUSE_GROUP: return RISCV_HALT_GROUP; } LOG_ERROR("Unknown DCSR cause field: 0x%" PRIx64, get_field(dcsr, CSR_DCSR_CAUSE)); LOG_ERROR(" dcsr=0x%016lx", (long)dcsr); return RISCV_HALT_UNKNOWN; } int riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) { dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; if (dm->progbuf_cache[index] != data) { if (dmi_write(target, DM_PROGBUF0 + index, data) != ERROR_OK) return ERROR_FAIL; dm->progbuf_cache[index] = data; } else { LOG_DEBUG("cache hit for 0x%" PRIx32 " @%d", data, index); } return ERROR_OK; } riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) { uint32_t value; dmi_read(target, &value, DM_PROGBUF0 + index); return value; } int riscv013_execute_debug_buffer(struct target *target) { uint32_t run_program = 0; run_program = set_field(run_program, AC_ACCESS_REGISTER_AARSIZE, 2); run_program = set_field(run_program, AC_ACCESS_REGISTER_POSTEXEC, 1); run_program = set_field(run_program, AC_ACCESS_REGISTER_TRANSFER, 0); run_program = set_field(run_program, AC_ACCESS_REGISTER_REGNO, 0x1000); return execute_abstract_command(target, run_program); } void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d) { RISCV013_INFO(info); buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_WRITE); buf_set_u64((unsigned char *)buf, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, d); buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a); } void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a) { RISCV013_INFO(info); buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_READ); buf_set_u64((unsigned char *)buf, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, 0); buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a); } void riscv013_fill_dmi_nop_u64(struct target *target, char *buf) { RISCV013_INFO(info); buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_NOP); buf_set_u64((unsigned char *)buf, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, 0); buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, 0); } int riscv013_dmi_write_u64_bits(struct target *target) { RISCV013_INFO(info); return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH; } static int maybe_execute_fence_i(struct target *target) { if (has_sufficient_progbuf(target, 3)) return execute_fence(target); return ERROR_OK; } /* Helper Functions. */ static int riscv013_on_step_or_resume(struct target *target, bool step) { if (maybe_execute_fence_i(target) != ERROR_OK) return ERROR_FAIL; /* We want to twiddle some bits in the debug CSR so debugging works. */ riscv_reg_t dcsr; int result = register_read(target, &dcsr, GDB_REGNO_DCSR); if (result != ERROR_OK) return result; dcsr = set_field(dcsr, CSR_DCSR_STEP, step); dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, riscv_ebreakm); dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, riscv_ebreaks); dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, riscv_ebreaku); return riscv_set_register(target, GDB_REGNO_DCSR, dcsr); } static int riscv013_step_or_resume_current_hart(struct target *target, bool step, bool use_hasel) { RISCV_INFO(r); LOG_DEBUG("resuming hart %d (for step?=%d)", r->current_hartid, step); if (!riscv_is_halted(target)) { LOG_ERROR("Hart %d is not halted!", r->current_hartid); return ERROR_FAIL; } /* Issue the resume command, and then wait for the current hart to resume. */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ; if (use_hasel) dmcontrol |= DM_DMCONTROL_HASEL; dmcontrol = set_hartsel(dmcontrol, r->current_hartid); dmi_write(target, DM_DMCONTROL, dmcontrol); dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HASEL, 0); dmcontrol = set_field(dmcontrol, DM_DMCONTROL_RESUMEREQ, 0); uint32_t dmstatus; for (size_t i = 0; i < 256; ++i) { usleep(10); if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; if (get_field(dmstatus, DM_DMSTATUS_ALLRESUMEACK) == 0) continue; if (step && get_field(dmstatus, DM_DMSTATUS_ALLHALTED) == 0) continue; dmi_write(target, DM_DMCONTROL, dmcontrol); return ERROR_OK; } dmi_write(target, DM_DMCONTROL, dmcontrol); LOG_ERROR("unable to resume hart %d", r->current_hartid); if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; LOG_ERROR(" dmstatus =0x%08x", dmstatus); if (step) { LOG_ERROR(" was stepping, halting"); riscv_halt(target); return ERROR_OK; } return ERROR_FAIL; } void riscv013_clear_abstract_error(struct target *target) { /* Wait for busy to go away. */ time_t start = time(NULL); uint32_t abstractcs; dmi_read(target, &abstractcs, DM_ABSTRACTCS); while (get_field(abstractcs, DM_ABSTRACTCS_BUSY)) { dmi_read(target, &abstractcs, DM_ABSTRACTCS); if (time(NULL) - start > riscv_command_timeout_sec) { LOG_ERROR("abstractcs.busy is not going low after %d seconds " "(abstractcs=0x%x). The target is either really slow or " "broken. You could increase the timeout with riscv " "set_command_timeout_sec.", riscv_command_timeout_sec, abstractcs); break; } } /* Clear the error status. */ dmi_write(target, DM_ABSTRACTCS, DM_ABSTRACTCS_CMDERR); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/riscv.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later #include <assert.h> #include <stdlib.h> #include <time.h> #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include <helper/time_support.h> #include "target/target.h" #include "target/algorithm.h" #include "target/target_type.h" #include <target/smp.h> #include "jtag/jtag.h" #include "target/register.h" #include "target/breakpoints.h" #include "riscv.h" #include "gdb_regs.h" #include "rtos/rtos.h" #include "debug_defines.h" #include <helper/bits.h> #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) /* Constants for legacy SiFive hardware breakpoints. */ #define CSR_BPCONTROL_X (1<<0) #define CSR_BPCONTROL_W (1<<1) #define CSR_BPCONTROL_R (1<<2) #define CSR_BPCONTROL_U (1<<3) #define CSR_BPCONTROL_S (1<<4) #define CSR_BPCONTROL_H (1<<5) #define CSR_BPCONTROL_M (1<<6) #define CSR_BPCONTROL_BPMATCH (0xf<<7) #define CSR_BPCONTROL_BPACTION (0xff<<11) #define DEBUG_ROM_START 0x800 #define DEBUG_ROM_RESUME (DEBUG_ROM_START + 4) #define DEBUG_ROM_EXCEPTION (DEBUG_ROM_START + 8) #define DEBUG_RAM_START 0x400 #define SETHALTNOT 0x10c /*** JTAG registers. ***/ #define DTMCONTROL 0x10 #define DTMCONTROL_DBUS_RESET (1<<16) #define DTMCONTROL_IDLE (7<<10) #define DTMCONTROL_ADDRBITS (0xf<<4) #define DTMCONTROL_VERSION (0xf) #define DBUS 0x11 #define DBUS_OP_START 0 #define DBUS_OP_SIZE 2 typedef enum { DBUS_OP_NOP = 0, DBUS_OP_READ = 1, DBUS_OP_WRITE = 2 } dbus_op_t; typedef enum { DBUS_STATUS_SUCCESS = 0, DBUS_STATUS_FAILED = 2, DBUS_STATUS_BUSY = 3 } dbus_status_t; #define DBUS_DATA_START 2 #define DBUS_DATA_SIZE 34 #define DBUS_ADDRESS_START 36 typedef enum slot { SLOT0, SLOT1, SLOT_LAST, } slot_t; /*** Debug Bus registers. ***/ #define DMCONTROL 0x10 #define DMCONTROL_INTERRUPT (((uint64_t)1)<<33) #define DMCONTROL_HALTNOT (((uint64_t)1)<<32) #define DMCONTROL_BUSERROR (7<<19) #define DMCONTROL_SERIAL (3<<16) #define DMCONTROL_AUTOINCREMENT (1<<15) #define DMCONTROL_ACCESS (7<<12) #define DMCONTROL_HARTID (0x3ff<<2) #define DMCONTROL_NDRESET (1<<1) #define DMCONTROL_FULLRESET 1 #define DMINFO 0x11 #define DMINFO_ABUSSIZE (0x7fU<<25) #define DMINFO_SERIALCOUNT (0xf<<21) #define DMINFO_ACCESS128 (1<<20) #define DMINFO_ACCESS64 (1<<19) #define DMINFO_ACCESS32 (1<<18) #define DMINFO_ACCESS16 (1<<17) #define DMINFO_ACCESS8 (1<<16) #define DMINFO_DRAMSIZE (0x3f<<10) #define DMINFO_AUTHENTICATED (1<<5) #define DMINFO_AUTHBUSY (1<<4) #define DMINFO_AUTHTYPE (3<<2) #define DMINFO_VERSION 3 /*** Info about the core being debugged. ***/ #define DBUS_ADDRESS_UNKNOWN 0xffff #define MAX_HWBPS 16 #define DRAM_CACHE_SIZE 16 static uint8_t ir_dtmcontrol[4] = {DTMCONTROL}; struct scan_field select_dtmcontrol = { .in_value = NULL, .out_value = ir_dtmcontrol }; static uint8_t ir_dbus[4] = {DBUS}; struct scan_field select_dbus = { .in_value = NULL, .out_value = ir_dbus }; static uint8_t ir_idcode[4] = {0x1}; struct scan_field select_idcode = { .in_value = NULL, .out_value = ir_idcode }; static bscan_tunnel_type_t bscan_tunnel_type; int bscan_tunnel_ir_width; /* if zero, then tunneling is not present/active */ static const uint8_t bscan_zero[4] = {0}; static const uint8_t bscan_one[4] = {1}; static uint8_t ir_user4[4]; static struct scan_field select_user4 = { .in_value = NULL, .out_value = ir_user4 }; static uint8_t bscan_tunneled_ir_width[4] = {5}; /* overridden by assignment in riscv_init_target */ static struct scan_field _bscan_tunnel_data_register_select_dmi[] = { { .num_bits = 3, .out_value = bscan_zero, .in_value = NULL, }, { .num_bits = 5, /* initialized in riscv_init_target to ir width of DM */ .out_value = ir_dbus, .in_value = NULL, }, { .num_bits = 7, .out_value = bscan_tunneled_ir_width, .in_value = NULL, }, { .num_bits = 1, .out_value = bscan_zero, .in_value = NULL, } }; static struct scan_field _bscan_tunnel_nested_tap_select_dmi[] = { { .num_bits = 1, .out_value = bscan_zero, .in_value = NULL, }, { .num_bits = 7, .out_value = bscan_tunneled_ir_width, .in_value = NULL, }, { .num_bits = 0, /* initialized in riscv_init_target to ir width of DM */ .out_value = ir_dbus, .in_value = NULL, }, { .num_bits = 3, .out_value = bscan_zero, .in_value = NULL, } }; static struct scan_field *bscan_tunnel_nested_tap_select_dmi = _bscan_tunnel_nested_tap_select_dmi; static uint32_t bscan_tunnel_nested_tap_select_dmi_num_fields = ARRAY_SIZE(_bscan_tunnel_nested_tap_select_dmi); static struct scan_field *bscan_tunnel_data_register_select_dmi = _bscan_tunnel_data_register_select_dmi; static uint32_t bscan_tunnel_data_register_select_dmi_num_fields = ARRAY_SIZE(_bscan_tunnel_data_register_select_dmi); struct trigger { uint64_t address; uint32_t length; uint64_t mask; uint64_t value; bool read, write, execute; int unique_id; }; /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC; /* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC; static bool riscv_enable_virt2phys = true; bool riscv_ebreakm = true; bool riscv_ebreaks = true; bool riscv_ebreaku = true; bool riscv_enable_virtual; static enum { RO_NORMAL, RO_REVERSED } resume_order; static const virt2phys_info_t sv32 = { .name = "Sv32", .va_bits = 32, .level = 2, .pte_shift = 2, .vpn_shift = {12, 22}, .vpn_mask = {0x3ff, 0x3ff}, .pte_ppn_shift = {10, 20}, .pte_ppn_mask = {0x3ff, 0xfff}, .pa_ppn_shift = {12, 22}, .pa_ppn_mask = {0x3ff, 0xfff}, }; static const virt2phys_info_t sv39 = { .name = "Sv39", .va_bits = 39, .level = 3, .pte_shift = 3, .vpn_shift = {12, 21, 30}, .vpn_mask = {0x1ff, 0x1ff, 0x1ff}, .pte_ppn_shift = {10, 19, 28}, .pte_ppn_mask = {0x1ff, 0x1ff, 0x3ffffff}, .pa_ppn_shift = {12, 21, 30}, .pa_ppn_mask = {0x1ff, 0x1ff, 0x3ffffff}, }; static const virt2phys_info_t sv48 = { .name = "Sv48", .va_bits = 48, .level = 4, .pte_shift = 3, .vpn_shift = {12, 21, 30, 39}, .vpn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ff}, .pte_ppn_shift = {10, 19, 28, 37}, .pte_ppn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ffff}, .pa_ppn_shift = {12, 21, 30, 39}, .pa_ppn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ffff}, }; static enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid); static void riscv_info_init(struct target *target, struct riscv_info *r); static void riscv_invalidate_register_cache(struct target *target); static int riscv_step_rtos_hart(struct target *target); static void riscv_sample_buf_maybe_add_timestamp(struct target *target, bool before) { RISCV_INFO(r); uint32_t now = timeval_ms() & 0xffffffff; if (r->sample_buf.used + 5 < r->sample_buf.size) { if (before) r->sample_buf.buf[r->sample_buf.used++] = RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE; else r->sample_buf.buf[r->sample_buf.used++] = RISCV_SAMPLE_BUF_TIMESTAMP_AFTER; r->sample_buf.buf[r->sample_buf.used++] = now & 0xff; r->sample_buf.buf[r->sample_buf.used++] = (now >> 8) & 0xff; r->sample_buf.buf[r->sample_buf.used++] = (now >> 16) & 0xff; r->sample_buf.buf[r->sample_buf.used++] = (now >> 24) & 0xff; } } static int riscv_resume_go_all_harts(struct target *target); void select_dmi_via_bscan(struct target *target) { jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE); if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) jtag_add_dr_scan(target->tap, bscan_tunnel_data_register_select_dmi_num_fields, bscan_tunnel_data_register_select_dmi, TAP_IDLE); else /* BSCAN_TUNNEL_NESTED_TAP */ jtag_add_dr_scan(target->tap, bscan_tunnel_nested_tap_select_dmi_num_fields, bscan_tunnel_nested_tap_select_dmi, TAP_IDLE); } uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out) { /* On BSCAN TAP: Select IR=USER4, issue tunneled IR scan via BSCAN TAP's DR */ uint8_t tunneled_ir_width[4] = {bscan_tunnel_ir_width}; uint8_t tunneled_dr_width[4] = {32}; uint8_t out_value[5] = {0}; uint8_t in_value[5] = {0}; buf_set_u32(out_value, 0, 32, out); struct scan_field tunneled_ir[4] = {}; struct scan_field tunneled_dr[4] = {}; if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) { tunneled_ir[0].num_bits = 3; tunneled_ir[0].out_value = bscan_zero; tunneled_ir[0].in_value = NULL; tunneled_ir[1].num_bits = bscan_tunnel_ir_width; tunneled_ir[1].out_value = ir_dtmcontrol; tunneled_ir[1].in_value = NULL; tunneled_ir[2].num_bits = 7; tunneled_ir[2].out_value = tunneled_ir_width; tunneled_ir[2].in_value = NULL; tunneled_ir[3].num_bits = 1; tunneled_ir[3].out_value = bscan_zero; tunneled_ir[3].in_value = NULL; tunneled_dr[0].num_bits = 3; tunneled_dr[0].out_value = bscan_zero; tunneled_dr[0].in_value = NULL; tunneled_dr[1].num_bits = 32 + 1; tunneled_dr[1].out_value = out_value; tunneled_dr[1].in_value = in_value; tunneled_dr[2].num_bits = 7; tunneled_dr[2].out_value = tunneled_dr_width; tunneled_dr[2].in_value = NULL; tunneled_dr[3].num_bits = 1; tunneled_dr[3].out_value = bscan_one; tunneled_dr[3].in_value = NULL; } else { /* BSCAN_TUNNEL_NESTED_TAP */ tunneled_ir[3].num_bits = 3; tunneled_ir[3].out_value = bscan_zero; tunneled_ir[3].in_value = NULL; tunneled_ir[2].num_bits = bscan_tunnel_ir_width; tunneled_ir[2].out_value = ir_dtmcontrol; tunneled_ir[1].in_value = NULL; tunneled_ir[1].num_bits = 7; tunneled_ir[1].out_value = tunneled_ir_width; tunneled_ir[2].in_value = NULL; tunneled_ir[0].num_bits = 1; tunneled_ir[0].out_value = bscan_zero; tunneled_ir[0].in_value = NULL; tunneled_dr[3].num_bits = 3; tunneled_dr[3].out_value = bscan_zero; tunneled_dr[3].in_value = NULL; tunneled_dr[2].num_bits = 32 + 1; tunneled_dr[2].out_value = out_value; tunneled_dr[2].in_value = in_value; tunneled_dr[1].num_bits = 7; tunneled_dr[1].out_value = tunneled_dr_width; tunneled_dr[1].in_value = NULL; tunneled_dr[0].num_bits = 1; tunneled_dr[0].out_value = bscan_one; tunneled_dr[0].in_value = NULL; } jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE); jtag_add_dr_scan(target->tap, ARRAY_SIZE(tunneled_ir), tunneled_ir, TAP_IDLE); jtag_add_dr_scan(target->tap, ARRAY_SIZE(tunneled_dr), tunneled_dr, TAP_IDLE); select_dmi_via_bscan(target); int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("failed jtag scan: %d", retval); return retval; } /* Note the starting offset is bit 1, not bit 0. In BSCAN tunnel, there is a one-bit TCK skew between output and input */ uint32_t in = buf_get_u32(in_value, 1, 32); LOG_DEBUG("DTMCS: 0x%x -> 0x%x", out, in); return in; } static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { struct scan_field field; uint8_t in_value[4]; uint8_t out_value[4] = { 0 }; if (bscan_tunnel_ir_width != 0) return dtmcontrol_scan_via_bscan(target, out); buf_set_u32(out_value, 0, 32, out); jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE); field.num_bits = 32; field.out_value = out_value; field.in_value = in_value; jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); /* Always return to dbus. */ jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("failed jtag scan: %d", retval); return retval; } uint32_t in = buf_get_u32(field.in_value, 0, 32); LOG_DEBUG("DTMCONTROL: 0x%x -> 0x%x", out, in); return in; } static struct target_type *get_target_type(struct target *target) { if (!target->arch_info) { LOG_ERROR("Target has not been initialized"); return NULL; } RISCV_INFO(info); switch (info->dtm_version) { case 0: return &riscv011_target; case 1: return &riscv013_target; default: LOG_ERROR("Unsupported DTM version: %d", info->dtm_version); return NULL; } } static int riscv_create_target(struct target *target, Jim_Interp *interp) { LOG_DEBUG("riscv_create_target()"); target->arch_info = calloc(1, sizeof(struct riscv_info)); if (!target->arch_info) { LOG_ERROR("Failed to allocate RISC-V target structure."); return ERROR_FAIL; } riscv_info_init(target, target->arch_info); return ERROR_OK; } static int riscv_init_target(struct command_context *cmd_ctx, struct target *target) { LOG_DEBUG("riscv_init_target()"); RISCV_INFO(info); info->cmd_ctx = cmd_ctx; select_dtmcontrol.num_bits = target->tap->ir_length; select_dbus.num_bits = target->tap->ir_length; select_idcode.num_bits = target->tap->ir_length; if (bscan_tunnel_ir_width != 0) { assert(target->tap->ir_length >= 6); uint32_t ir_user4_raw = 0x23 << (target->tap->ir_length - 6); h_u32_to_le(ir_user4, ir_user4_raw); select_user4.num_bits = target->tap->ir_length; bscan_tunneled_ir_width[0] = bscan_tunnel_ir_width; if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) bscan_tunnel_data_register_select_dmi[1].num_bits = bscan_tunnel_ir_width; else /* BSCAN_TUNNEL_NESTED_TAP */ bscan_tunnel_nested_tap_select_dmi[2].num_bits = bscan_tunnel_ir_width; } riscv_semihosting_init(target); target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static void riscv_free_registers(struct target *target) { /* Free the shared structure use for most registers. */ if (target->reg_cache) { if (target->reg_cache->reg_list) { free(target->reg_cache->reg_list[0].arch_info); /* Free the ones we allocated separately. */ for (unsigned i = GDB_REGNO_COUNT; i < target->reg_cache->num_regs; i++) free(target->reg_cache->reg_list[i].arch_info); for (unsigned int i = 0; i < target->reg_cache->num_regs; i++) free(target->reg_cache->reg_list[i].value); free(target->reg_cache->reg_list); } free(target->reg_cache); } } static void riscv_deinit_target(struct target *target) { LOG_DEBUG("riscv_deinit_target()"); struct riscv_info *info = target->arch_info; struct target_type *tt = get_target_type(target); if (tt && info && info->version_specific) tt->deinit_target(target); riscv_free_registers(target); if (!info) return; range_list_t *entry, *tmp; list_for_each_entry_safe(entry, tmp, &info->expose_csr, list) { free(entry->name); free(entry); } list_for_each_entry_safe(entry, tmp, &info->expose_custom, list) { free(entry->name); free(entry); } free(info->reg_names); free(target->arch_info); target->arch_info = NULL; } static void trigger_from_breakpoint(struct trigger *trigger, const struct breakpoint *breakpoint) { trigger->address = breakpoint->address; trigger->length = breakpoint->length; trigger->mask = ~0LL; trigger->read = false; trigger->write = false; trigger->execute = true; /* unique_id is unique across both breakpoints and watchpoints. */ trigger->unique_id = breakpoint->unique_id; } static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger, uint64_t tdata1) { RISCV_INFO(r); const uint32_t bpcontrol_x = 1<<0; const uint32_t bpcontrol_w = 1<<1; const uint32_t bpcontrol_r = 1<<2; const uint32_t bpcontrol_u = 1<<3; const uint32_t bpcontrol_s = 1<<4; const uint32_t bpcontrol_h = 1<<5; const uint32_t bpcontrol_m = 1<<6; const uint32_t bpcontrol_bpmatch = 0xf << 7; const uint32_t bpcontrol_bpaction = 0xff << 11; if (tdata1 & (bpcontrol_r | bpcontrol_w | bpcontrol_x)) { /* Trigger is already in use, presumably by user code. */ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } tdata1 = set_field(tdata1, bpcontrol_r, trigger->read); tdata1 = set_field(tdata1, bpcontrol_w, trigger->write); tdata1 = set_field(tdata1, bpcontrol_x, trigger->execute); tdata1 = set_field(tdata1, bpcontrol_u, !!(r->misa & BIT('U' - 'A'))); tdata1 = set_field(tdata1, bpcontrol_s, !!(r->misa & BIT('S' - 'A'))); tdata1 = set_field(tdata1, bpcontrol_h, !!(r->misa & BIT('H' - 'A'))); tdata1 |= bpcontrol_m; tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */ tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); /* cause bp exception */ riscv_set_register(target, GDB_REGNO_TDATA1, tdata1); riscv_reg_t tdata1_rb; if (riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); if (tdata1 != tdata1_rb) { LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%" PRIx64 " to tdata1 it contains 0x%" PRIx64, tdata1, tdata1_rb); riscv_set_register(target, GDB_REGNO_TDATA1, 0); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address); return ERROR_OK; } static int maybe_add_trigger_t2(struct target *target, struct trigger *trigger, uint64_t tdata1) { RISCV_INFO(r); /* tselect is already set */ if (tdata1 & (MCONTROL_EXECUTE | MCONTROL_STORE | MCONTROL_LOAD)) { /* Trigger is already in use, presumably by user code. */ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* address/data match trigger */ tdata1 |= MCONTROL_DMODE(riscv_xlen(target)); tdata1 = set_field(tdata1, MCONTROL_ACTION, MCONTROL_ACTION_DEBUG_MODE); tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL); tdata1 |= MCONTROL_M; if (r->misa & (1 << ('S' - 'A'))) tdata1 |= MCONTROL_S; if (r->misa & (1 << ('U' - 'A'))) tdata1 |= MCONTROL_U; if (trigger->execute) tdata1 |= MCONTROL_EXECUTE; if (trigger->read) tdata1 |= MCONTROL_LOAD; if (trigger->write) tdata1 |= MCONTROL_STORE; riscv_set_register(target, GDB_REGNO_TDATA1, tdata1); uint64_t tdata1_rb; int result = riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1); if (result != ERROR_OK) return result; LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); if (tdata1 != tdata1_rb) { LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%" PRIx64 " to tdata1 it contains 0x%" PRIx64, tdata1, tdata1_rb); riscv_set_register(target, GDB_REGNO_TDATA1, 0); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address); return ERROR_OK; } static int maybe_add_trigger_t6(struct target *target, struct trigger *trigger, uint64_t tdata1) { RISCV_INFO(r); /* tselect is already set */ if (tdata1 & (CSR_MCONTROL6_EXECUTE | CSR_MCONTROL6_STORE | CSR_MCONTROL6_LOAD)) { /* Trigger is already in use, presumably by user code. */ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* address/data match trigger */ tdata1 |= MCONTROL_DMODE(riscv_xlen(target)); tdata1 = set_field(tdata1, CSR_MCONTROL6_ACTION, MCONTROL_ACTION_DEBUG_MODE); tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, MCONTROL_MATCH_EQUAL); tdata1 |= CSR_MCONTROL6_M; if (r->misa & (1 << ('H' - 'A'))) tdata1 |= CSR_MCONTROL6_VS | CSR_MCONTROL6_VU; if (r->misa & (1 << ('S' - 'A'))) tdata1 |= CSR_MCONTROL6_S; if (r->misa & (1 << ('U' - 'A'))) tdata1 |= CSR_MCONTROL6_U; if (trigger->execute) tdata1 |= CSR_MCONTROL6_EXECUTE; if (trigger->read) tdata1 |= CSR_MCONTROL6_LOAD; if (trigger->write) tdata1 |= CSR_MCONTROL6_STORE; riscv_set_register(target, GDB_REGNO_TDATA1, tdata1); uint64_t tdata1_rb; int result = riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1); if (result != ERROR_OK) return result; LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); if (tdata1 != tdata1_rb) { LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%" PRIx64 " to tdata1 it contains 0x%" PRIx64, tdata1, tdata1_rb); riscv_set_register(target, GDB_REGNO_TDATA1, 0); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address); return ERROR_OK; } static int add_trigger(struct target *target, struct trigger *trigger) { RISCV_INFO(r); if (riscv_enumerate_triggers(target) != ERROR_OK) return ERROR_FAIL; riscv_reg_t tselect; if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) return ERROR_FAIL; unsigned int i; for (i = 0; i < r->trigger_count; i++) { if (r->trigger_unique_id[i] != -1) continue; riscv_set_register(target, GDB_REGNO_TSELECT, i); uint64_t tdata1; int result = riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1); if (result != ERROR_OK) return result; int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); switch (type) { case 1: result = maybe_add_trigger_t1(target, trigger, tdata1); break; case 2: result = maybe_add_trigger_t2(target, trigger, tdata1); break; case 6: result = maybe_add_trigger_t6(target, trigger, tdata1); break; default: LOG_DEBUG("trigger %d has unknown type %d", i, type); continue; } if (result != ERROR_OK) continue; LOG_DEBUG("[%d] Using trigger %d (type %d) for bp %d", target->coreid, i, type, trigger->unique_id); r->trigger_unique_id[i] = trigger->unique_id; break; } riscv_set_register(target, GDB_REGNO_TSELECT, tselect); if (i >= r->trigger_count) { LOG_ERROR("Couldn't find an available hardware trigger."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } return ERROR_OK; } /** * Write one memory item of given "size". Use memory access of given "access_size". * Utilize read-modify-write, if needed. * */ static int write_by_given_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer, uint32_t access_size) { assert(size == 1 || size == 2 || size == 4 || size == 8); assert(access_size == 1 || access_size == 2 || access_size == 4 || access_size == 8); if (access_size <= size && address % access_size == 0) /* Can do the memory access directly without a helper buffer. */ return target_write_memory(target, address, access_size, size / access_size, buffer); unsigned int offset_head = address % access_size; unsigned int n_blocks = ((size + offset_head) <= access_size) ? 1 : 2; uint8_t helper_buf[n_blocks * access_size]; /* Read from memory */ if (target_read_memory(target, address - offset_head, access_size, n_blocks, helper_buf) != ERROR_OK) return ERROR_FAIL; /* Modify and write back */ memcpy(helper_buf + offset_head, buffer, size); return target_write_memory(target, address - offset_head, access_size, n_blocks, helper_buf); } /** * Read one memory item of given "size". Use memory access of given "access_size". * Read larger section of memory and pick out the required portion, if needed. * */ static int read_by_given_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer, uint32_t access_size) { assert(size == 1 || size == 2 || size == 4 || size == 8); assert(access_size == 1 || access_size == 2 || access_size == 4 || access_size == 8); if (access_size <= size && address % access_size == 0) /* Can do the memory access directly without a helper buffer. */ return target_read_memory(target, address, access_size, size / access_size, buffer); unsigned int offset_head = address % access_size; unsigned int n_blocks = ((size + offset_head) <= access_size) ? 1 : 2; uint8_t helper_buf[n_blocks * access_size]; /* Read from memory */ if (target_read_memory(target, address - offset_head, access_size, n_blocks, helper_buf) != ERROR_OK) return ERROR_FAIL; /* Pick the requested portion from the buffer */ memcpy(buffer, helper_buf + offset_head, size); return ERROR_OK; } /** * Write one memory item using any memory access size that will work. * Utilize read-modify-write, if needed. * */ int riscv_write_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { assert(size == 1 || size == 2 || size == 4 || size == 8); /* Find access size that correspond to data size and the alignment. */ unsigned int preferred_size = size; while (address % preferred_size != 0) preferred_size /= 2; /* First try the preferred (most natural) access size. */ if (write_by_given_size(target, address, size, buffer, preferred_size) == ERROR_OK) return ERROR_OK; /* On failure, try other access sizes. Minimize the number of accesses by trying first the largest size. */ for (unsigned int access_size = 8; access_size > 0; access_size /= 2) { if (access_size == preferred_size) /* Already tried this size. */ continue; if (write_by_given_size(target, address, size, buffer, access_size) == ERROR_OK) return ERROR_OK; } /* No access attempt succeeded. */ return ERROR_FAIL; } /** * Read one memory item using any memory access size that will work. * Read larger section of memory and pick out the required portion, if needed. * */ int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { assert(size == 1 || size == 2 || size == 4 || size == 8); /* Find access size that correspond to data size and the alignment. */ unsigned int preferred_size = size; while (address % preferred_size != 0) preferred_size /= 2; /* First try the preferred (most natural) access size. */ if (read_by_given_size(target, address, size, buffer, preferred_size) == ERROR_OK) return ERROR_OK; /* On failure, try other access sizes. Minimize the number of accesses by trying first the largest size. */ for (unsigned int access_size = 8; access_size > 0; access_size /= 2) { if (access_size == preferred_size) /* Already tried this size. */ continue; if (read_by_given_size(target, address, size, buffer, access_size) == ERROR_OK) return ERROR_OK; } /* No access attempt succeeded. */ return ERROR_FAIL; } static int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { LOG_DEBUG("[%d] @0x%" TARGET_PRIxADDR, target->coreid, breakpoint->address); assert(breakpoint); if (breakpoint->type == BKPT_SOFT) { /** @todo check RVC for size/alignment */ if (!(breakpoint->length == 4 || breakpoint->length == 2)) { LOG_ERROR("Invalid breakpoint length %d", breakpoint->length); return ERROR_FAIL; } if (0 != (breakpoint->address % 2)) { LOG_ERROR("Invalid breakpoint alignment for address 0x%" TARGET_PRIxADDR, breakpoint->address); return ERROR_FAIL; } /* Read the original instruction. */ if (riscv_read_by_any_size( target, breakpoint->address, breakpoint->length, breakpoint->orig_instr) != ERROR_OK) { LOG_ERROR("Failed to read original instruction at 0x%" TARGET_PRIxADDR, breakpoint->address); return ERROR_FAIL; } uint8_t buff[4] = { 0 }; buf_set_u32(buff, 0, breakpoint->length * CHAR_BIT, breakpoint->length == 4 ? ebreak() : ebreak_c()); /* Write the ebreak instruction. */ if (riscv_write_by_any_size(target, breakpoint->address, breakpoint->length, buff) != ERROR_OK) { LOG_ERROR("Failed to write %d-byte breakpoint instruction at 0x%" TARGET_PRIxADDR, breakpoint->length, breakpoint->address); return ERROR_FAIL; } } else if (breakpoint->type == BKPT_HARD) { struct trigger trigger; trigger_from_breakpoint(&trigger, breakpoint); int const result = add_trigger(target, &trigger); if (result != ERROR_OK) return result; } else { LOG_INFO("OpenOCD only supports hardware and software breakpoints."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint->is_set = true; return ERROR_OK; } static int remove_trigger(struct target *target, struct trigger *trigger) { RISCV_INFO(r); if (riscv_enumerate_triggers(target) != ERROR_OK) return ERROR_FAIL; unsigned int i; for (i = 0; i < r->trigger_count; i++) { if (r->trigger_unique_id[i] == trigger->unique_id) break; } if (i >= r->trigger_count) { LOG_ERROR("Couldn't find the hardware resources used by hardware " "trigger."); return ERROR_FAIL; } LOG_DEBUG("[%d] Stop using resource %d for bp %d", target->coreid, i, trigger->unique_id); riscv_reg_t tselect; int result = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT); if (result != ERROR_OK) return result; riscv_set_register(target, GDB_REGNO_TSELECT, i); riscv_set_register(target, GDB_REGNO_TDATA1, 0); riscv_set_register(target, GDB_REGNO_TSELECT, tselect); r->trigger_unique_id[i] = -1; return ERROR_OK; } static int riscv_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (breakpoint->type == BKPT_SOFT) { /* Write the original instruction. */ if (riscv_write_by_any_size( target, breakpoint->address, breakpoint->length, breakpoint->orig_instr) != ERROR_OK) { LOG_ERROR("Failed to restore instruction for %d-byte breakpoint at " "0x%" TARGET_PRIxADDR, breakpoint->length, breakpoint->address); return ERROR_FAIL; } } else if (breakpoint->type == BKPT_HARD) { struct trigger trigger; trigger_from_breakpoint(&trigger, breakpoint); int result = remove_trigger(target, &trigger); if (result != ERROR_OK) return result; } else { LOG_INFO("OpenOCD only supports hardware and software breakpoints."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint->is_set = false; return ERROR_OK; } static void trigger_from_watchpoint(struct trigger *trigger, const struct watchpoint *watchpoint) { trigger->address = watchpoint->address; trigger->length = watchpoint->length; trigger->mask = watchpoint->mask; trigger->value = watchpoint->value; trigger->read = (watchpoint->rw == WPT_READ || watchpoint->rw == WPT_ACCESS); trigger->write = (watchpoint->rw == WPT_WRITE || watchpoint->rw == WPT_ACCESS); trigger->execute = false; /* unique_id is unique across both breakpoints and watchpoints. */ trigger->unique_id = watchpoint->unique_id; } int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct trigger trigger; trigger_from_watchpoint(&trigger, watchpoint); int result = add_trigger(target, &trigger); if (result != ERROR_OK) return result; watchpoint->is_set = true; return ERROR_OK; } int riscv_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { LOG_DEBUG("[%d] @0x%" TARGET_PRIxADDR, target->coreid, watchpoint->address); struct trigger trigger; trigger_from_watchpoint(&trigger, watchpoint); int result = remove_trigger(target, &trigger); if (result != ERROR_OK) return result; watchpoint->is_set = false; return ERROR_OK; } /* Sets *hit_watchpoint to the first watchpoint identified as causing the * current halt. * * The GDB server uses this information to tell GDB what data address has * been hit, which enables GDB to print the hit variable along with its old * and new value. */ static int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { struct watchpoint *wp = target->watchpoints; LOG_DEBUG("Current hartid = %d", riscv_current_hartid(target)); /*TODO instead of disassembling the instruction that we think caused the * trigger, check the hit bit of each watchpoint first. The hit bit is * simpler and more reliable to check but as it is optional and relatively * new, not all hardware will implement it */ riscv_reg_t dpc; riscv_get_register(target, &dpc, GDB_REGNO_DPC); const uint8_t length = 4; LOG_DEBUG("dpc is 0x%" PRIx64, dpc); /* fetch the instruction at dpc */ uint8_t buffer[length]; if (target_read_buffer(target, dpc, length, buffer) != ERROR_OK) { LOG_ERROR("Failed to read instruction at dpc 0x%" PRIx64, dpc); return ERROR_FAIL; } uint32_t instruction = 0; for (int i = 0; i < length; i++) { LOG_DEBUG("Next byte is %x", buffer[i]); instruction += (buffer[i] << 8 * i); } LOG_DEBUG("Full instruction is %x", instruction); /* find out which memory address is accessed by the instruction at dpc */ /* opcode is first 7 bits of the instruction */ uint8_t opcode = instruction & 0x7F; uint32_t rs1; int16_t imm; riscv_reg_t mem_addr; if (opcode == MATCH_LB || opcode == MATCH_SB) { rs1 = (instruction & 0xf8000) >> 15; riscv_get_register(target, &mem_addr, rs1); if (opcode == MATCH_SB) { LOG_DEBUG("%x is store instruction", instruction); imm = ((instruction & 0xf80) >> 7) | ((instruction & 0xfe000000) >> 20); } else { LOG_DEBUG("%x is load instruction", instruction); imm = (instruction & 0xfff00000) >> 20; } /* sign extend 12-bit imm to 16-bits */ if (imm & (1 << 11)) imm |= 0xf000; mem_addr += imm; LOG_DEBUG("memory address=0x%" PRIx64, mem_addr); } else { LOG_DEBUG("%x is not a RV32I load or store", instruction); return ERROR_FAIL; } while (wp) { /*TODO support length/mask */ if (wp->address == mem_addr) { *hit_watchpoint = wp; LOG_DEBUG("Hit address=%" TARGET_PRIxADDR, wp->address); return ERROR_OK; } wp = wp->next; } /* No match found - either we hit a watchpoint caused by an instruction that * this function does not yet disassemble, or we hit a breakpoint. * * OpenOCD will behave as if this function had never been implemented i.e. * report the halt to GDB with no address information. */ return ERROR_FAIL; } static int oldriscv_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { struct target_type *tt = get_target_type(target); return tt->step(target, current, address, handle_breakpoints); } static int old_or_new_riscv_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { RISCV_INFO(r); LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); if (!r->is_halted) return oldriscv_step(target, current, address, handle_breakpoints); else return riscv_openocd_step(target, current, address, handle_breakpoints); } static int riscv_examine(struct target *target) { LOG_DEBUG("riscv_examine()"); if (target_was_examined(target)) { LOG_DEBUG("Target was already examined."); return ERROR_OK; } /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ RISCV_INFO(info); uint32_t dtmcontrol = dtmcontrol_scan(target, 0); LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); info->dtm_version = get_field(dtmcontrol, DTMCONTROL_VERSION); LOG_DEBUG(" version=0x%x", info->dtm_version); struct target_type *tt = get_target_type(target); if (!tt) return ERROR_FAIL; int result = tt->init_target(info->cmd_ctx, target); if (result != ERROR_OK) return result; return tt->examine(target); } static int oldriscv_poll(struct target *target) { struct target_type *tt = get_target_type(target); return tt->poll(target); } static int old_or_new_riscv_poll(struct target *target) { RISCV_INFO(r); if (!r->is_halted) return oldriscv_poll(target); else return riscv_openocd_poll(target); } int riscv_select_current_hart(struct target *target) { return riscv_set_current_hartid(target, target->coreid); } static int halt_prep(struct target *target) { RISCV_INFO(r); LOG_DEBUG("[%s] prep hart, debug_reason=%d", target_name(target), target->debug_reason); if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; if (riscv_is_halted(target)) { LOG_DEBUG("[%s] Hart is already halted (reason=%d).", target_name(target), target->debug_reason); } else { if (r->halt_prep(target) != ERROR_OK) return ERROR_FAIL; r->prepped = true; } return ERROR_OK; } static int riscv_halt_go_all_harts(struct target *target) { RISCV_INFO(r); if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; if (riscv_is_halted(target)) { LOG_DEBUG("[%s] Hart is already halted.", target_name(target)); } else { if (r->halt_go(target) != ERROR_OK) return ERROR_FAIL; } riscv_invalidate_register_cache(target); return ERROR_OK; } static int halt_go(struct target *target) { RISCV_INFO(r); int result; if (!r->is_halted) { struct target_type *tt = get_target_type(target); result = tt->halt(target); } else { result = riscv_halt_go_all_harts(target); } target->state = TARGET_HALTED; if (target->debug_reason == DBG_REASON_NOTHALTED) target->debug_reason = DBG_REASON_DBGRQ; return result; } static int halt_finish(struct target *target) { return target_call_event_callbacks(target, TARGET_EVENT_HALTED); } int riscv_halt(struct target *target) { RISCV_INFO(r); if (!r->is_halted) { struct target_type *tt = get_target_type(target); return tt->halt(target); } LOG_DEBUG("[%d] halting all harts", target->coreid); int result = ERROR_OK; if (target->smp) { struct target_list *tlist; foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; if (halt_prep(t) != ERROR_OK) result = ERROR_FAIL; } foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; struct riscv_info *i = riscv_info(t); if (i->prepped) { if (halt_go(t) != ERROR_OK) result = ERROR_FAIL; } } foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; if (halt_finish(t) != ERROR_OK) return ERROR_FAIL; } } else { if (halt_prep(target) != ERROR_OK) result = ERROR_FAIL; if (halt_go(target) != ERROR_OK) result = ERROR_FAIL; if (halt_finish(target) != ERROR_OK) return ERROR_FAIL; } return result; } static int riscv_assert_reset(struct target *target) { LOG_DEBUG("[%d]", target->coreid); struct target_type *tt = get_target_type(target); riscv_invalidate_register_cache(target); return tt->assert_reset(target); } static int riscv_deassert_reset(struct target *target) { LOG_DEBUG("[%d]", target->coreid); struct target_type *tt = get_target_type(target); return tt->deassert_reset(target); } static int riscv_resume_prep_all_harts(struct target *target) { RISCV_INFO(r); LOG_DEBUG("[%s] prep hart", target_name(target)); if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; if (riscv_is_halted(target)) { if (r->resume_prep(target) != ERROR_OK) return ERROR_FAIL; } else { LOG_DEBUG("[%s] hart requested resume, but was already resumed", target_name(target)); } LOG_DEBUG("[%s] mark as prepped", target_name(target)); r->prepped = true; return ERROR_OK; } /* state must be riscv_reg_t state[RISCV_MAX_HWBPS] = {0}; */ static int disable_triggers(struct target *target, riscv_reg_t *state) { RISCV_INFO(r); LOG_DEBUG("deal with triggers"); if (riscv_enumerate_triggers(target) != ERROR_OK) return ERROR_FAIL; if (r->manual_hwbp_set) { /* Look at every trigger that may have been set. */ riscv_reg_t tselect; if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) return ERROR_FAIL; for (unsigned int t = 0; t < r->trigger_count; t++) { if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK) return ERROR_FAIL; riscv_reg_t tdata1; if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) return ERROR_FAIL; if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) { state[t] = tdata1; if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) return ERROR_FAIL; } } if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) return ERROR_FAIL; } else { /* Just go through the triggers we manage. */ struct watchpoint *watchpoint = target->watchpoints; int i = 0; while (watchpoint) { LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->is_set); state[i] = watchpoint->is_set; if (watchpoint->is_set) { if (riscv_remove_watchpoint(target, watchpoint) != ERROR_OK) return ERROR_FAIL; } watchpoint = watchpoint->next; i++; } } return ERROR_OK; } static int enable_triggers(struct target *target, riscv_reg_t *state) { RISCV_INFO(r); if (r->manual_hwbp_set) { /* Look at every trigger that may have been set. */ riscv_reg_t tselect; if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) return ERROR_FAIL; for (unsigned int t = 0; t < r->trigger_count; t++) { if (state[t] != 0) { if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK) return ERROR_FAIL; if (riscv_set_register(target, GDB_REGNO_TDATA1, state[t]) != ERROR_OK) return ERROR_FAIL; } } if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) return ERROR_FAIL; } else { struct watchpoint *watchpoint = target->watchpoints; int i = 0; while (watchpoint) { LOG_DEBUG("watchpoint %d: cleared=%" PRId64, i, state[i]); if (state[i]) { if (riscv_add_watchpoint(target, watchpoint) != ERROR_OK) return ERROR_FAIL; } watchpoint = watchpoint->next; i++; } } return ERROR_OK; } /** * Get everything ready to resume. */ static int resume_prep(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { RISCV_INFO(r); LOG_DEBUG("[%d]", target->coreid); if (!current) riscv_set_register(target, GDB_REGNO_PC, address); if (target->debug_reason == DBG_REASON_WATCHPOINT) { /* To be able to run off a trigger, disable all the triggers, step, and * then resume as usual. */ riscv_reg_t trigger_state[RISCV_MAX_HWBPS] = {0}; if (disable_triggers(target, trigger_state) != ERROR_OK) return ERROR_FAIL; if (old_or_new_riscv_step(target, true, 0, false) != ERROR_OK) return ERROR_FAIL; if (enable_triggers(target, trigger_state) != ERROR_OK) return ERROR_FAIL; } if (r->is_halted) { if (riscv_resume_prep_all_harts(target) != ERROR_OK) return ERROR_FAIL; } LOG_DEBUG("[%d] mark as prepped", target->coreid); r->prepped = true; return ERROR_OK; } /** * Resume all the harts that have been prepped, as close to instantaneous as * possible. */ static int resume_go(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { RISCV_INFO(r); int result; if (!r->is_halted) { struct target_type *tt = get_target_type(target); result = tt->resume(target, current, address, handle_breakpoints, debug_execution); } else { result = riscv_resume_go_all_harts(target); } return result; } static int resume_finish(struct target *target) { register_cache_invalidate(target->reg_cache); target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; return target_call_event_callbacks(target, TARGET_EVENT_RESUMED); } /** * @par single_hart When true, only resume a single hart even if SMP is * configured. This is used to run algorithms on just one hart. */ static int riscv_resume( struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution, bool single_hart) { LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); int result = ERROR_OK; if (target->smp && !single_hart) { struct target_list *tlist; foreach_smp_target_direction(resume_order == RO_NORMAL, tlist, target->smp_targets) { struct target *t = tlist->target; if (resume_prep(t, current, address, handle_breakpoints, debug_execution) != ERROR_OK) result = ERROR_FAIL; } foreach_smp_target_direction(resume_order == RO_NORMAL, tlist, target->smp_targets) { struct target *t = tlist->target; struct riscv_info *i = riscv_info(t); if (i->prepped) { if (resume_go(t, current, address, handle_breakpoints, debug_execution) != ERROR_OK) result = ERROR_FAIL; } } foreach_smp_target_direction(resume_order == RO_NORMAL, tlist, target->smp_targets) { struct target *t = tlist->target; if (resume_finish(t) != ERROR_OK) return ERROR_FAIL; } } else { if (resume_prep(target, current, address, handle_breakpoints, debug_execution) != ERROR_OK) result = ERROR_FAIL; if (resume_go(target, current, address, handle_breakpoints, debug_execution) != ERROR_OK) result = ERROR_FAIL; if (resume_finish(target) != ERROR_OK) return ERROR_FAIL; } return result; } static int riscv_target_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { return riscv_resume(target, current, address, handle_breakpoints, debug_execution, false); } static int riscv_mmu(struct target *target, int *enabled) { if (!riscv_enable_virt2phys) { *enabled = 0; return ERROR_OK; } /* Don't use MMU in explicit or effective M (machine) mode */ riscv_reg_t priv; if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) { LOG_ERROR("Failed to read priv register."); return ERROR_FAIL; } riscv_reg_t mstatus; if (riscv_get_register(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) { LOG_ERROR("Failed to read mstatus register."); return ERROR_FAIL; } if ((get_field(mstatus, MSTATUS_MPRV) ? get_field(mstatus, MSTATUS_MPP) : priv) == PRV_M) { LOG_DEBUG("SATP/MMU ignored in Machine mode (mstatus=0x%" PRIx64 ").", mstatus); *enabled = 0; return ERROR_OK; } riscv_reg_t satp; if (riscv_get_register(target, &satp, GDB_REGNO_SATP) != ERROR_OK) { LOG_DEBUG("Couldn't read SATP."); /* If we can't read SATP, then there must not be an MMU. */ *enabled = 0; return ERROR_OK; } if (get_field(satp, RISCV_SATP_MODE(riscv_xlen(target))) == SATP_MODE_OFF) { LOG_DEBUG("MMU is disabled."); *enabled = 0; } else { LOG_DEBUG("MMU is enabled."); *enabled = 1; } return ERROR_OK; } static int riscv_address_translate(struct target *target, target_addr_t virtual, target_addr_t *physical) { RISCV_INFO(r); riscv_reg_t satp_value; int mode; uint64_t ppn_value; target_addr_t table_address; const virt2phys_info_t *info; uint64_t pte = 0; int i; int result = riscv_get_register(target, &satp_value, GDB_REGNO_SATP); if (result != ERROR_OK) return result; unsigned xlen = riscv_xlen(target); mode = get_field(satp_value, RISCV_SATP_MODE(xlen)); switch (mode) { case SATP_MODE_SV32: info = &sv32; break; case SATP_MODE_SV39: info = &sv39; break; case SATP_MODE_SV48: info = &sv48; break; case SATP_MODE_OFF: LOG_ERROR("No translation or protection." \ " (satp: 0x%" PRIx64 ")", satp_value); return ERROR_FAIL; default: LOG_ERROR("The translation mode is not supported." \ " (satp: 0x%" PRIx64 ")", satp_value); return ERROR_FAIL; } LOG_DEBUG("virtual=0x%" TARGET_PRIxADDR "; mode=%s", virtual, info->name); /* verify bits xlen-1:va_bits-1 are all equal */ assert(xlen >= info->va_bits); target_addr_t mask = ((target_addr_t)1 << (xlen - (info->va_bits - 1))) - 1; target_addr_t masked_msbs = (virtual >> (info->va_bits - 1)) & mask; if (masked_msbs != 0 && masked_msbs != mask) { LOG_ERROR("Virtual address 0x%" TARGET_PRIxADDR " is not sign-extended " "for %s mode.", virtual, info->name); return ERROR_FAIL; } ppn_value = get_field(satp_value, RISCV_SATP_PPN(xlen)); table_address = ppn_value << RISCV_PGSHIFT; i = info->level - 1; while (i >= 0) { uint64_t vpn = virtual >> info->vpn_shift[i]; vpn &= info->vpn_mask[i]; target_addr_t pte_address = table_address + (vpn << info->pte_shift); uint8_t buffer[8]; assert(info->pte_shift <= 3); int retval = r->read_memory(target, pte_address, 4, (1 << info->pte_shift) / 4, buffer, 4); if (retval != ERROR_OK) return ERROR_FAIL; if (info->pte_shift == 2) pte = buf_get_u32(buffer, 0, 32); else pte = buf_get_u64(buffer, 0, 64); LOG_DEBUG("i=%d; PTE @0x%" TARGET_PRIxADDR " = 0x%" PRIx64, i, pte_address, pte); if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) return ERROR_FAIL; if ((pte & PTE_R) || (pte & PTE_X)) /* Found leaf PTE. */ break; i--; if (i < 0) break; ppn_value = pte >> PTE_PPN_SHIFT; table_address = ppn_value << RISCV_PGSHIFT; } if (i < 0) { LOG_ERROR("Couldn't find the PTE."); return ERROR_FAIL; } /* Make sure to clear out the high bits that may be set. */ *physical = virtual & (((target_addr_t)1 << info->va_bits) - 1); while (i < info->level) { ppn_value = pte >> info->pte_ppn_shift[i]; ppn_value &= info->pte_ppn_mask[i]; *physical &= ~(((target_addr_t)info->pa_ppn_mask[i]) << info->pa_ppn_shift[i]); *physical |= (ppn_value << info->pa_ppn_shift[i]); i++; } LOG_DEBUG("0x%" TARGET_PRIxADDR " -> 0x%" TARGET_PRIxADDR, virtual, *physical); return ERROR_OK; } static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical) { int enabled; if (riscv_mmu(target, &enabled) == ERROR_OK) { if (!enabled) return ERROR_FAIL; if (riscv_address_translate(target, virtual, physical) == ERROR_OK) return ERROR_OK; } return ERROR_FAIL; } static int riscv_read_phys_memory(struct target *target, target_addr_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer) { RISCV_INFO(r); if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; return r->read_memory(target, phys_address, size, count, buffer, size); } static int riscv_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { if (count == 0) { LOG_WARNING("0-length read from 0x%" TARGET_PRIxADDR, address); return ERROR_OK; } if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; target_addr_t physical_addr; if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK) address = physical_addr; RISCV_INFO(r); return r->read_memory(target, address, size, count, buffer, size); } static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer) { if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; struct target_type *tt = get_target_type(target); return tt->write_memory(target, phys_address, size, count, buffer); } static int riscv_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { if (count == 0) { LOG_WARNING("0-length write to 0x%" TARGET_PRIxADDR, address); return ERROR_OK; } if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; target_addr_t physical_addr; if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK) address = physical_addr; struct target_type *tt = get_target_type(target); return tt->write_memory(target, address, size, count, buffer); } static const char *riscv_get_gdb_arch(struct target *target) { switch (riscv_xlen(target)) { case 32: return "riscv:rv32"; case 64: return "riscv:rv64"; } LOG_ERROR("Unsupported xlen: %d", riscv_xlen(target)); return NULL; } static int riscv_get_gdb_reg_list_internal(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class, bool read) { RISCV_INFO(r); LOG_DEBUG("[%s] {%d} reg_class=%d, read=%d", target_name(target), r->current_hartid, reg_class, read); if (!target->reg_cache) { LOG_ERROR("Target not initialized. Return ERROR_FAIL."); return ERROR_FAIL; } if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; switch (reg_class) { case REG_CLASS_GENERAL: *reg_list_size = 33; break; case REG_CLASS_ALL: *reg_list_size = target->reg_cache->num_regs; break; default: LOG_ERROR("Unsupported reg_class: %d", reg_class); return ERROR_FAIL; } *reg_list = calloc(*reg_list_size, sizeof(struct reg *)); if (!*reg_list) return ERROR_FAIL; for (int i = 0; i < *reg_list_size; i++) { assert(!target->reg_cache->reg_list[i].valid || target->reg_cache->reg_list[i].size > 0); (*reg_list)[i] = &target->reg_cache->reg_list[i]; if (read && target->reg_cache->reg_list[i].exist && !target->reg_cache->reg_list[i].valid) { if (target->reg_cache->reg_list[i].type->get( &target->reg_cache->reg_list[i]) != ERROR_OK) return ERROR_FAIL; } } return ERROR_OK; } static int riscv_get_gdb_reg_list_noread(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { return riscv_get_gdb_reg_list_internal(target, reg_list, reg_list_size, reg_class, false); } static int riscv_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { return riscv_get_gdb_reg_list_internal(target, reg_list, reg_list_size, reg_class, true); } static int riscv_arch_state(struct target *target) { struct target_type *tt = get_target_type(target); return tt->arch_state(target); } /* Algorithm must end with a software breakpoint instruction. */ static int riscv_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { RISCV_INFO(info); if (num_mem_params > 0) { LOG_ERROR("Memory parameters are not supported for RISC-V algorithms."); return ERROR_FAIL; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Save registers */ struct reg *reg_pc = register_get_by_name(target->reg_cache, "pc", true); if (!reg_pc || reg_pc->type->get(reg_pc) != ERROR_OK) return ERROR_FAIL; uint64_t saved_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size); LOG_DEBUG("saved_pc=0x%" PRIx64, saved_pc); uint64_t saved_regs[32]; for (int i = 0; i < num_reg_params; i++) { LOG_DEBUG("save %s", reg_params[i].reg_name); struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false); if (!r) { LOG_ERROR("Couldn't find register named '%s'", reg_params[i].reg_name); return ERROR_FAIL; } if (r->size != reg_params[i].size) { LOG_ERROR("Register %s is %d bits instead of %d bits.", reg_params[i].reg_name, r->size, reg_params[i].size); return ERROR_FAIL; } if (r->number > GDB_REGNO_XPR31) { LOG_ERROR("Only GPRs can be use as argument registers."); return ERROR_FAIL; } if (r->type->get(r) != ERROR_OK) return ERROR_FAIL; saved_regs[r->number] = buf_get_u64(r->value, 0, r->size); if (reg_params[i].direction == PARAM_OUT || reg_params[i].direction == PARAM_IN_OUT) { if (r->type->set(r, reg_params[i].value) != ERROR_OK) return ERROR_FAIL; } } /* Disable Interrupts before attempting to run the algorithm. */ uint64_t current_mstatus; uint8_t mstatus_bytes[8] = { 0 }; LOG_DEBUG("Disabling Interrupts"); struct reg *reg_mstatus = register_get_by_name(target->reg_cache, "mstatus", true); if (!reg_mstatus) { LOG_ERROR("Couldn't find mstatus!"); return ERROR_FAIL; } reg_mstatus->type->get(reg_mstatus); current_mstatus = buf_get_u64(reg_mstatus->value, 0, reg_mstatus->size); uint64_t ie_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE; buf_set_u64(mstatus_bytes, 0, info->xlen, set_field(current_mstatus, ie_mask, 0)); reg_mstatus->type->set(reg_mstatus, mstatus_bytes); /* Run algorithm */ LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point); if (riscv_resume(target, 0, entry_point, 0, 0, true) != ERROR_OK) return ERROR_FAIL; int64_t start = timeval_ms(); while (target->state != TARGET_HALTED) { LOG_DEBUG("poll()"); int64_t now = timeval_ms(); if (now - start > timeout_ms) { LOG_ERROR("Algorithm timed out after %" PRId64 " ms.", now - start); riscv_halt(target); old_or_new_riscv_poll(target); enum gdb_regno regnums[] = { GDB_REGNO_RA, GDB_REGNO_SP, GDB_REGNO_GP, GDB_REGNO_TP, GDB_REGNO_T0, GDB_REGNO_T1, GDB_REGNO_T2, GDB_REGNO_FP, GDB_REGNO_S1, GDB_REGNO_A0, GDB_REGNO_A1, GDB_REGNO_A2, GDB_REGNO_A3, GDB_REGNO_A4, GDB_REGNO_A5, GDB_REGNO_A6, GDB_REGNO_A7, GDB_REGNO_S2, GDB_REGNO_S3, GDB_REGNO_S4, GDB_REGNO_S5, GDB_REGNO_S6, GDB_REGNO_S7, GDB_REGNO_S8, GDB_REGNO_S9, GDB_REGNO_S10, GDB_REGNO_S11, GDB_REGNO_T3, GDB_REGNO_T4, GDB_REGNO_T5, GDB_REGNO_T6, GDB_REGNO_PC, GDB_REGNO_MSTATUS, GDB_REGNO_MEPC, GDB_REGNO_MCAUSE, }; for (unsigned i = 0; i < ARRAY_SIZE(regnums); i++) { enum gdb_regno regno = regnums[i]; riscv_reg_t reg_value; if (riscv_get_register(target, ®_value, regno) != ERROR_OK) break; LOG_ERROR("%s = 0x%" PRIx64, gdb_regno_name(regno), reg_value); } return ERROR_TARGET_TIMEOUT; } int result = old_or_new_riscv_poll(target); if (result != ERROR_OK) return result; } /* The current hart id might have been changed in poll(). */ if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; if (reg_pc->type->get(reg_pc) != ERROR_OK) return ERROR_FAIL; uint64_t final_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size); if (exit_point && final_pc != exit_point) { LOG_ERROR("PC ended up at 0x%" PRIx64 " instead of 0x%" TARGET_PRIxADDR, final_pc, exit_point); return ERROR_FAIL; } /* Restore Interrupts */ LOG_DEBUG("Restoring Interrupts"); buf_set_u64(mstatus_bytes, 0, info->xlen, current_mstatus); reg_mstatus->type->set(reg_mstatus, mstatus_bytes); /* Restore registers */ uint8_t buf[8] = { 0 }; buf_set_u64(buf, 0, info->xlen, saved_pc); if (reg_pc->type->set(reg_pc, buf) != ERROR_OK) return ERROR_FAIL; for (int i = 0; i < num_reg_params; i++) { if (reg_params[i].direction == PARAM_IN || reg_params[i].direction == PARAM_IN_OUT) { struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false); if (r->type->get(r) != ERROR_OK) { LOG_ERROR("get(%s) failed", r->name); return ERROR_FAIL; } buf_cpy(r->value, reg_params[i].value, reg_params[i].size); } LOG_DEBUG("restore %s", reg_params[i].reg_name); struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false); buf_set_u64(buf, 0, info->xlen, saved_regs[r->number]); if (r->type->set(r, buf) != ERROR_OK) { LOG_ERROR("set(%s) failed", r->name); return ERROR_FAIL; } } return ERROR_OK; } static int riscv_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct reg_param reg_params[2]; int retval; LOG_DEBUG("address=0x%" TARGET_PRIxADDR "; count=0x%" PRIx32, address, count); static const uint8_t riscv32_crc_code[] = { #include "../../../contrib/loaders/checksum/riscv32_crc.inc" }; static const uint8_t riscv64_crc_code[] = { #include "../../../contrib/loaders/checksum/riscv64_crc.inc" }; static const uint8_t *crc_code; unsigned xlen = riscv_xlen(target); unsigned crc_code_size; if (xlen == 32) { crc_code = riscv32_crc_code; crc_code_size = sizeof(riscv32_crc_code); } else { crc_code = riscv64_crc_code; crc_code_size = sizeof(riscv64_crc_code); } if (count < crc_code_size * 4) { /* Don't use the algorithm for relatively small buffers. It's faster * just to read the memory. target_checksum_memory() will take care of * that if we fail. */ return ERROR_FAIL; } retval = target_alloc_working_area(target, crc_code_size, &crc_algorithm); if (retval != ERROR_OK) return retval; if (crc_algorithm->address + crc_algorithm->size > address && crc_algorithm->address < address + count) { /* Region to checksum overlaps with the work area we've been assigned. * Bail. (Would be better to manually checksum what we read there, and * use the algorithm for the rest.) */ target_free_working_area(target, crc_algorithm); return ERROR_FAIL; } retval = target_write_buffer(target, crc_algorithm->address, crc_code_size, crc_code); if (retval != ERROR_OK) { LOG_ERROR("Failed to write code to " TARGET_ADDR_FMT ": %d", crc_algorithm->address, retval); target_free_working_area(target, crc_algorithm); return retval; } init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); buf_set_u64(reg_params[0].value, 0, xlen, address); buf_set_u64(reg_params[1].value, 0, xlen, count); /* 20 second timeout/megabyte */ unsigned int timeout = 20000 * (1 + (count / (1024 * 1024))); retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, 0, /* Leave exit point unspecified because we don't know. */ timeout, NULL); if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); else LOG_ERROR("error executing RISC-V CRC algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); target_free_working_area(target, crc_algorithm); LOG_DEBUG("checksum=0x%" PRIx32 ", result=%d", *checksum, retval); return retval; } /*** OpenOCD Helper Functions ***/ enum riscv_poll_hart { RPH_NO_CHANGE, RPH_DISCOVERED_HALTED, RPH_DISCOVERED_RUNNING, RPH_ERROR }; static enum riscv_poll_hart riscv_poll_hart(struct target *target, int hartid) { RISCV_INFO(r); if (riscv_set_current_hartid(target, hartid) != ERROR_OK) return RPH_ERROR; LOG_DEBUG("polling hart %d, target->state=%d", hartid, target->state); /* If OpenOCD thinks we're running but this hart is halted then it's time * to raise an event. */ bool halted = riscv_is_halted(target); if (target->state != TARGET_HALTED && halted) { LOG_DEBUG(" triggered a halt"); r->on_halt(target); return RPH_DISCOVERED_HALTED; } else if (target->state != TARGET_RUNNING && !halted) { LOG_DEBUG(" triggered running"); target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; return RPH_DISCOVERED_RUNNING; } return RPH_NO_CHANGE; } static int set_debug_reason(struct target *target, enum riscv_halt_reason halt_reason) { switch (halt_reason) { case RISCV_HALT_BREAKPOINT: target->debug_reason = DBG_REASON_BREAKPOINT; break; case RISCV_HALT_TRIGGER: target->debug_reason = DBG_REASON_WATCHPOINT; break; case RISCV_HALT_INTERRUPT: case RISCV_HALT_GROUP: target->debug_reason = DBG_REASON_DBGRQ; break; case RISCV_HALT_SINGLESTEP: target->debug_reason = DBG_REASON_SINGLESTEP; break; case RISCV_HALT_UNKNOWN: target->debug_reason = DBG_REASON_UNDEFINED; break; case RISCV_HALT_ERROR: return ERROR_FAIL; } LOG_DEBUG("[%s] debug_reason=%d", target_name(target), target->debug_reason); return ERROR_OK; } static int sample_memory(struct target *target) { RISCV_INFO(r); if (!r->sample_buf.buf || !r->sample_config.enabled) return ERROR_OK; LOG_DEBUG("buf used/size: %d/%d", r->sample_buf.used, r->sample_buf.size); uint64_t start = timeval_ms(); riscv_sample_buf_maybe_add_timestamp(target, true); int result = ERROR_OK; if (r->sample_memory) { result = r->sample_memory(target, &r->sample_buf, &r->sample_config, start + TARGET_DEFAULT_POLLING_INTERVAL); if (result != ERROR_NOT_IMPLEMENTED) goto exit; } /* Default slow path. */ while (timeval_ms() - start < TARGET_DEFAULT_POLLING_INTERVAL) { for (unsigned int i = 0; i < ARRAY_SIZE(r->sample_config.bucket); i++) { if (r->sample_config.bucket[i].enabled && r->sample_buf.used + 1 + r->sample_config.bucket[i].size_bytes < r->sample_buf.size) { assert(i < RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE); r->sample_buf.buf[r->sample_buf.used] = i; result = riscv_read_phys_memory( target, r->sample_config.bucket[i].address, r->sample_config.bucket[i].size_bytes, 1, r->sample_buf.buf + r->sample_buf.used + 1); if (result == ERROR_OK) r->sample_buf.used += 1 + r->sample_config.bucket[i].size_bytes; else goto exit; } } } exit: riscv_sample_buf_maybe_add_timestamp(target, false); if (result != ERROR_OK) { LOG_INFO("Turning off memory sampling because it failed."); r->sample_config.enabled = false; } return result; } /*** OpenOCD Interface ***/ int riscv_openocd_poll(struct target *target) { LOG_DEBUG("polling all harts"); int halted_hart = -1; if (target->smp) { unsigned should_remain_halted = 0; unsigned should_resume = 0; struct target_list *list; foreach_smp_target(list, target->smp_targets) { struct target *t = list->target; struct riscv_info *r = riscv_info(t); enum riscv_poll_hart out = riscv_poll_hart(t, r->current_hartid); switch (out) { case RPH_NO_CHANGE: break; case RPH_DISCOVERED_RUNNING: t->state = TARGET_RUNNING; t->debug_reason = DBG_REASON_NOTHALTED; break; case RPH_DISCOVERED_HALTED: t->state = TARGET_HALTED; enum riscv_halt_reason halt_reason = riscv_halt_reason(t, r->current_hartid); if (set_debug_reason(t, halt_reason) != ERROR_OK) return ERROR_FAIL; if (halt_reason == RISCV_HALT_BREAKPOINT) { int retval; switch (riscv_semihosting(t, &retval)) { case SEMIHOSTING_NONE: case SEMIHOSTING_WAITING: /* This hart should remain halted. */ should_remain_halted++; break; case SEMIHOSTING_HANDLED: /* This hart should be resumed, along with any other * harts that halted due to haltgroups. */ should_resume++; break; case SEMIHOSTING_ERROR: return retval; } } else if (halt_reason != RISCV_HALT_GROUP) { should_remain_halted++; } break; case RPH_ERROR: return ERROR_FAIL; } } LOG_DEBUG("should_remain_halted=%d, should_resume=%d", should_remain_halted, should_resume); if (should_remain_halted && should_resume) { LOG_WARNING("%d harts should remain halted, and %d should resume.", should_remain_halted, should_resume); } if (should_remain_halted) { LOG_DEBUG("halt all"); riscv_halt(target); } else if (should_resume) { LOG_DEBUG("resume all"); riscv_resume(target, true, 0, 0, 0, false); } /* Sample memory if any target is running. */ foreach_smp_target(list, target->smp_targets) { struct target *t = list->target; if (t->state == TARGET_RUNNING) { sample_memory(target); break; } } return ERROR_OK; } else { enum riscv_poll_hart out = riscv_poll_hart(target, riscv_current_hartid(target)); if (out == RPH_NO_CHANGE || out == RPH_DISCOVERED_RUNNING) { if (target->state == TARGET_RUNNING) sample_memory(target); return ERROR_OK; } else if (out == RPH_ERROR) { return ERROR_FAIL; } halted_hart = riscv_current_hartid(target); LOG_DEBUG(" hart %d halted", halted_hart); enum riscv_halt_reason halt_reason = riscv_halt_reason(target, halted_hart); if (set_debug_reason(target, halt_reason) != ERROR_OK) return ERROR_FAIL; target->state = TARGET_HALTED; } if (target->debug_reason == DBG_REASON_BREAKPOINT) { int retval; switch (riscv_semihosting(target, &retval)) { case SEMIHOSTING_NONE: case SEMIHOSTING_WAITING: target_call_event_callbacks(target, TARGET_EVENT_HALTED); break; case SEMIHOSTING_HANDLED: if (riscv_resume(target, true, 0, 0, 0, false) != ERROR_OK) return ERROR_FAIL; break; case SEMIHOSTING_ERROR: return retval; } } else { target_call_event_callbacks(target, TARGET_EVENT_HALTED); } return ERROR_OK; } int riscv_openocd_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { LOG_DEBUG("stepping rtos hart"); if (!current) riscv_set_register(target, GDB_REGNO_PC, address); riscv_reg_t trigger_state[RISCV_MAX_HWBPS] = {0}; if (disable_triggers(target, trigger_state) != ERROR_OK) return ERROR_FAIL; int out = riscv_step_rtos_hart(target); if (out != ERROR_OK) { LOG_ERROR("unable to step rtos hart"); return out; } register_cache_invalidate(target->reg_cache); if (enable_triggers(target, trigger_state) != ERROR_OK) return ERROR_FAIL; target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); target->state = TARGET_HALTED; target->debug_reason = DBG_REASON_SINGLESTEP; target_call_event_callbacks(target, TARGET_EVENT_HALTED); return out; } /* Command Handlers */ COMMAND_HANDLER(riscv_set_command_timeout_sec) { if (CMD_ARGC != 1) { LOG_ERROR("Command takes exactly 1 parameter"); return ERROR_COMMAND_SYNTAX_ERROR; } int timeout = atoi(CMD_ARGV[0]); if (timeout <= 0) { LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); return ERROR_FAIL; } riscv_command_timeout_sec = timeout; return ERROR_OK; } COMMAND_HANDLER(riscv_set_reset_timeout_sec) { if (CMD_ARGC != 1) { LOG_ERROR("Command takes exactly 1 parameter"); return ERROR_COMMAND_SYNTAX_ERROR; } int timeout = atoi(CMD_ARGV[0]); if (timeout <= 0) { LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); return ERROR_FAIL; } riscv_reset_timeout_sec = timeout; return ERROR_OK; } COMMAND_HANDLER(riscv_set_mem_access) { struct target *target = get_current_target(CMD_CTX); RISCV_INFO(r); int progbuf_cnt = 0; int sysbus_cnt = 0; int abstract_cnt = 0; if (CMD_ARGC < 1 || CMD_ARGC > RISCV_NUM_MEM_ACCESS_METHODS) { LOG_ERROR("Command takes 1 to %d parameters", RISCV_NUM_MEM_ACCESS_METHODS); return ERROR_COMMAND_SYNTAX_ERROR; } /* Check argument validity */ for (unsigned int i = 0; i < CMD_ARGC; i++) { if (strcmp("progbuf", CMD_ARGV[i]) == 0) { progbuf_cnt++; } else if (strcmp("sysbus", CMD_ARGV[i]) == 0) { sysbus_cnt++; } else if (strcmp("abstract", CMD_ARGV[i]) == 0) { abstract_cnt++; } else { LOG_ERROR("Unknown argument '%s'. " "Must be one of: 'progbuf', 'sysbus' or 'abstract'.", CMD_ARGV[i]); return ERROR_COMMAND_SYNTAX_ERROR; } } if (progbuf_cnt > 1 || sysbus_cnt > 1 || abstract_cnt > 1) { LOG_ERROR("Syntax error - duplicate arguments to `riscv set_mem_access`."); return ERROR_COMMAND_SYNTAX_ERROR; } /* Args are valid, store them */ for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) r->mem_access_methods[i] = RISCV_MEM_ACCESS_UNSPECIFIED; for (unsigned int i = 0; i < CMD_ARGC; i++) { if (strcmp("progbuf", CMD_ARGV[i]) == 0) r->mem_access_methods[i] = RISCV_MEM_ACCESS_PROGBUF; else if (strcmp("sysbus", CMD_ARGV[i]) == 0) r->mem_access_methods[i] = RISCV_MEM_ACCESS_SYSBUS; else if (strcmp("abstract", CMD_ARGV[i]) == 0) r->mem_access_methods[i] = RISCV_MEM_ACCESS_ABSTRACT; } /* Reset warning flags */ r->mem_access_progbuf_warn = true; r->mem_access_sysbus_warn = true; r->mem_access_abstract_warn = true; return ERROR_OK; } COMMAND_HANDLER(riscv_set_enable_virtual) { if (CMD_ARGC != 1) { LOG_ERROR("Command takes exactly 1 parameter"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virtual); return ERROR_OK; } static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const char *reg_type, unsigned int max_val) { char *args = strdup(tcl_arg); if (!args) return ERROR_FAIL; /* For backward compatibility, allow multiple parameters within one TCL argument, separated by ',' */ char *arg = strtok(args, ","); while (arg) { unsigned low = 0; unsigned high = 0; char *name = NULL; char *dash = strchr(arg, '-'); char *equals = strchr(arg, '='); unsigned int pos; if (!dash && !equals) { /* Expecting single register number. */ if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) { LOG_ERROR("Failed to parse single register number from '%s'.", arg); free(args); return ERROR_COMMAND_SYNTAX_ERROR; } } else if (dash && !equals) { /* Expecting register range - two numbers separated by a dash: ##-## */ *dash = 0; dash++; if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) { LOG_ERROR("Failed to parse single register number from '%s'.", arg); free(args); return ERROR_COMMAND_SYNTAX_ERROR; } if (sscanf(dash, "%u%n", &high, &pos) != 1 || pos != strlen(dash)) { LOG_ERROR("Failed to parse single register number from '%s'.", dash); free(args); return ERROR_COMMAND_SYNTAX_ERROR; } if (high < low) { LOG_ERROR("Incorrect range encountered [%u, %u].", low, high); free(args); return ERROR_FAIL; } } else if (!dash && equals) { /* Expecting single register number with textual name specified: ##=name */ *equals = 0; equals++; if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) { LOG_ERROR("Failed to parse single register number from '%s'.", arg); free(args); return ERROR_COMMAND_SYNTAX_ERROR; } name = calloc(1, strlen(equals) + strlen(reg_type) + 2); if (!name) { LOG_ERROR("Failed to allocate register name."); free(args); return ERROR_FAIL; } /* Register prefix: "csr_" or "custom_" */ strcpy(name, reg_type); name[strlen(reg_type)] = '_'; if (sscanf(equals, "%[_a-zA-Z0-9]%n", name + strlen(reg_type) + 1, &pos) != 1 || pos != strlen(equals)) { LOG_ERROR("Failed to parse register name from '%s'.", equals); free(args); free(name); return ERROR_COMMAND_SYNTAX_ERROR; } } else { LOG_ERROR("Invalid argument '%s'.", arg); free(args); return ERROR_COMMAND_SYNTAX_ERROR; } high = high > low ? high : low; if (high > max_val) { LOG_ERROR("Cannot expose %s register number %u, maximum allowed value is %u.", reg_type, high, max_val); free(name); free(args); return ERROR_FAIL; } /* Check for overlap, name uniqueness. */ range_list_t *entry; list_for_each_entry(entry, ranges, list) { if ((entry->low <= high) && (low <= entry->high)) { if (low == high) LOG_WARNING("Duplicate %s register number - " "Register %u has already been exposed previously", reg_type, low); else LOG_WARNING("Overlapping register ranges - Register range starting from %u overlaps " "with already exposed register/range at %u.", low, entry->low); } if (entry->name && name && (strcasecmp(entry->name, name) == 0)) { LOG_ERROR("Duplicate register name \"%s\" found.", name); free(name); free(args); return ERROR_FAIL; } } range_list_t *range = calloc(1, sizeof(range_list_t)); if (!range) { LOG_ERROR("Failed to allocate range list."); free(name); free(args); return ERROR_FAIL; } range->low = low; range->high = high; range->name = name; list_add(&range->list, ranges); arg = strtok(NULL, ","); } free(args); return ERROR_OK; } COMMAND_HANDLER(riscv_set_expose_csrs) { if (CMD_ARGC == 0) { LOG_ERROR("Command expects parameters"); return ERROR_COMMAND_SYNTAX_ERROR; } struct target *target = get_current_target(CMD_CTX); RISCV_INFO(info); int ret = ERROR_OK; for (unsigned int i = 0; i < CMD_ARGC; i++) { ret = parse_ranges(&info->expose_csr, CMD_ARGV[i], "csr", 0xfff); if (ret != ERROR_OK) break; } return ret; } COMMAND_HANDLER(riscv_set_expose_custom) { if (CMD_ARGC == 0) { LOG_ERROR("Command expects parameters"); return ERROR_COMMAND_SYNTAX_ERROR; } struct target *target = get_current_target(CMD_CTX); RISCV_INFO(info); int ret = ERROR_OK; for (unsigned int i = 0; i < CMD_ARGC; i++) { ret = parse_ranges(&info->expose_custom, CMD_ARGV[i], "custom", 0x3fff); if (ret != ERROR_OK) break; } return ret; } COMMAND_HANDLER(riscv_authdata_read) { unsigned int index = 0; if (CMD_ARGC == 0) { /* nop */ } else if (CMD_ARGC == 1) { COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], index); } else { LOG_ERROR("Command takes at most one parameter"); return ERROR_COMMAND_SYNTAX_ERROR; } struct target *target = get_current_target(CMD_CTX); if (!target) { LOG_ERROR("target is NULL!"); return ERROR_FAIL; } RISCV_INFO(r); if (!r) { LOG_ERROR("riscv_info is NULL!"); return ERROR_FAIL; } if (r->authdata_read) { uint32_t value; if (r->authdata_read(target, &value, index) != ERROR_OK) return ERROR_FAIL; command_print_sameline(CMD, "0x%08" PRIx32, value); return ERROR_OK; } else { LOG_ERROR("authdata_read is not implemented for this target."); return ERROR_FAIL; } } COMMAND_HANDLER(riscv_authdata_write) { uint32_t value; unsigned int index = 0; if (CMD_ARGC == 0 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], value); } else { COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], index); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); } struct target *target = get_current_target(CMD_CTX); RISCV_INFO(r); if (!r->authdata_write) { LOG_ERROR("authdata_write is not implemented for this target."); return ERROR_FAIL; } return r->authdata_write(target, value, index); } COMMAND_HANDLER(riscv_dmi_read) { if (CMD_ARGC != 1) { LOG_ERROR("Command takes 1 parameter"); return ERROR_COMMAND_SYNTAX_ERROR; } struct target *target = get_current_target(CMD_CTX); if (!target) { LOG_ERROR("target is NULL!"); return ERROR_FAIL; } RISCV_INFO(r); if (!r) { LOG_ERROR("riscv_info is NULL!"); return ERROR_FAIL; } if (r->dmi_read) { uint32_t address, value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); if (r->dmi_read(target, &value, address) != ERROR_OK) return ERROR_FAIL; command_print(CMD, "0x%" PRIx32, value); return ERROR_OK; } else { LOG_ERROR("dmi_read is not implemented for this target."); return ERROR_FAIL; } } COMMAND_HANDLER(riscv_dmi_write) { if (CMD_ARGC != 2) { LOG_ERROR("Command takes exactly 2 arguments"); return ERROR_COMMAND_SYNTAX_ERROR; } struct target *target = get_current_target(CMD_CTX); RISCV_INFO(r); uint32_t address, value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); if (r->dmi_write) { return r->dmi_write(target, address, value); } else { LOG_ERROR("dmi_write is not implemented for this target."); return ERROR_FAIL; } } COMMAND_HANDLER(riscv_reset_delays) { int wait = 0; if (CMD_ARGC > 1) { LOG_ERROR("Command takes at most one argument"); return ERROR_COMMAND_SYNTAX_ERROR; } if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], wait); struct target *target = get_current_target(CMD_CTX); RISCV_INFO(r); r->reset_delays_wait = wait; return ERROR_OK; } COMMAND_HANDLER(riscv_set_ir) { if (CMD_ARGC != 2) { LOG_ERROR("Command takes exactly 2 arguments"); return ERROR_COMMAND_SYNTAX_ERROR; } uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); if (!strcmp(CMD_ARGV[0], "idcode")) buf_set_u32(ir_idcode, 0, 32, value); else if (!strcmp(CMD_ARGV[0], "dtmcs")) buf_set_u32(ir_dtmcontrol, 0, 32, value); else if (!strcmp(CMD_ARGV[0], "dmi")) buf_set_u32(ir_dbus, 0, 32, value); else return ERROR_FAIL; return ERROR_OK; } COMMAND_HANDLER(riscv_resume_order) { if (CMD_ARGC > 1) { LOG_ERROR("Command takes at most one argument"); return ERROR_COMMAND_SYNTAX_ERROR; } if (!strcmp(CMD_ARGV[0], "normal")) { resume_order = RO_NORMAL; } else if (!strcmp(CMD_ARGV[0], "reversed")) { resume_order = RO_REVERSED; } else { LOG_ERROR("Unsupported resume order: %s", CMD_ARGV[0]); return ERROR_FAIL; } return ERROR_OK; } COMMAND_HANDLER(riscv_use_bscan_tunnel) { int irwidth = 0; int tunnel_type = BSCAN_TUNNEL_NESTED_TAP; if (CMD_ARGC > 2) { LOG_ERROR("Command takes at most two arguments"); return ERROR_COMMAND_SYNTAX_ERROR; } else if (CMD_ARGC == 1) { COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth); } else if (CMD_ARGC == 2) { COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth); COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tunnel_type); } if (tunnel_type == BSCAN_TUNNEL_NESTED_TAP) LOG_INFO("Nested Tap based Bscan Tunnel Selected"); else if (tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) LOG_INFO("Simple Register based Bscan Tunnel Selected"); else LOG_INFO("Invalid Tunnel type selected ! : selecting default Nested Tap Type"); bscan_tunnel_type = tunnel_type; bscan_tunnel_ir_width = irwidth; return ERROR_OK; } COMMAND_HANDLER(riscv_set_enable_virt2phys) { if (CMD_ARGC != 1) { LOG_ERROR("Command takes exactly 1 parameter"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virt2phys); return ERROR_OK; } COMMAND_HANDLER(riscv_set_ebreakm) { if (CMD_ARGC != 1) { LOG_ERROR("Command takes exactly 1 parameter"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreakm); return ERROR_OK; } COMMAND_HANDLER(riscv_set_ebreaks) { if (CMD_ARGC != 1) { LOG_ERROR("Command takes exactly 1 parameter"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaks); return ERROR_OK; } COMMAND_HANDLER(riscv_set_ebreaku) { if (CMD_ARGC != 1) { LOG_ERROR("Command takes exactly 1 parameter"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaku); return ERROR_OK; } COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key, unsigned int value) { char full_key[80]; snprintf(full_key, sizeof(full_key), "%s.%s", section, key); command_print(CMD, "%-21s %3d", full_key, value); return 0; } COMMAND_HANDLER(handle_info) { struct target *target = get_current_target(CMD_CTX); RISCV_INFO(r); /* This output format can be fed directly into TCL's "array set". */ riscv_print_info_line(CMD, "hart", "xlen", riscv_xlen(target)); riscv_enumerate_triggers(target); riscv_print_info_line(CMD, "hart", "trigger_count", r->trigger_count); if (r->print_info) return CALL_COMMAND_HANDLER(r->print_info, target); return 0; } static const struct command_registration riscv_exec_command_handlers[] = { { .name = "info", .handler = handle_info, .mode = COMMAND_EXEC, .usage = "", .help = "Displays some information OpenOCD detected about the target." }, { .name = "set_command_timeout_sec", .handler = riscv_set_command_timeout_sec, .mode = COMMAND_ANY, .usage = "[sec]", .help = "Set the wall-clock timeout (in seconds) for individual commands" }, { .name = "set_reset_timeout_sec", .handler = riscv_set_reset_timeout_sec, .mode = COMMAND_ANY, .usage = "[sec]", .help = "Set the wall-clock timeout (in seconds) after reset is deasserted" }, { .name = "set_mem_access", .handler = riscv_set_mem_access, .mode = COMMAND_ANY, .usage = "method1 [method2] [method3]", .help = "Set which memory access methods shall be used and in which order " "of priority. Method can be one of: 'progbuf', 'sysbus' or 'abstract'." }, { .name = "set_enable_virtual", .handler = riscv_set_enable_virtual, .mode = COMMAND_ANY, .usage = "on|off", .help = "When on, memory accesses are performed on physical or virtual " "memory depending on the current system configuration. " "When off (default), all memory accessses are performed on physical memory." }, { .name = "expose_csrs", .handler = riscv_set_expose_csrs, .mode = COMMAND_CONFIG, .usage = "n0[-m0|=name0][,n1[-m1|=name1]]...", .help = "Configure a list of inclusive ranges for CSRs to expose in " "addition to the standard ones. This must be executed before " "`init`." }, { .name = "expose_custom", .handler = riscv_set_expose_custom, .mode = COMMAND_CONFIG, .usage = "n0[-m0|=name0][,n1[-m1|=name1]]...", .help = "Configure a list of inclusive ranges for custom registers to " "expose. custom0 is accessed as abstract register number 0xc000, " "etc. This must be executed before `init`." }, { .name = "authdata_read", .handler = riscv_authdata_read, .usage = "[index]", .mode = COMMAND_ANY, .help = "Return the 32-bit value read from authdata or authdata0 " "(index=0), or authdata1 (index=1)." }, { .name = "authdata_write", .handler = riscv_authdata_write, .mode = COMMAND_ANY, .usage = "[index] value", .help = "Write the 32-bit value to authdata or authdata0 (index=0), " "or authdata1 (index=1)." }, { .name = "dmi_read", .handler = riscv_dmi_read, .mode = COMMAND_ANY, .usage = "address", .help = "Perform a 32-bit DMI read at address, returning the value." }, { .name = "dmi_write", .handler = riscv_dmi_write, .mode = COMMAND_ANY, .usage = "address value", .help = "Perform a 32-bit DMI write of value at address." }, { .name = "reset_delays", .handler = riscv_reset_delays, .mode = COMMAND_ANY, .usage = "[wait]", .help = "OpenOCD learns how many Run-Test/Idle cycles are required " "between scans to avoid encountering the target being busy. This " "command resets those learned values after `wait` scans. It's only " "useful for testing OpenOCD itself." }, { .name = "resume_order", .handler = riscv_resume_order, .mode = COMMAND_ANY, .usage = "normal|reversed", .help = "Choose the order that harts are resumed in when `hasel` is not " "supported. Normal order is from lowest hart index to highest. " "Reversed order is from highest hart index to lowest." }, { .name = "set_ir", .handler = riscv_set_ir, .mode = COMMAND_ANY, .usage = "[idcode|dtmcs|dmi] value", .help = "Set IR value for specified JTAG register." }, { .name = "use_bscan_tunnel", .handler = riscv_use_bscan_tunnel, .mode = COMMAND_ANY, .usage = "value [type]", .help = "Enable or disable use of a BSCAN tunnel to reach DM. Supply " "the width of the DM transport TAP's instruction register to " "enable. Supply a value of 0 to disable. Pass A second argument " "(optional) to indicate Bscan Tunnel Type {0:(default) NESTED_TAP , " "1: DATA_REGISTER}" }, { .name = "set_enable_virt2phys", .handler = riscv_set_enable_virt2phys, .mode = COMMAND_ANY, .usage = "on|off", .help = "When on (default), enable translation from virtual address to " "physical address." }, { .name = "set_ebreakm", .handler = riscv_set_ebreakm, .mode = COMMAND_ANY, .usage = "on|off", .help = "Control dcsr.ebreakm. When off, M-mode ebreak instructions " "don't trap to OpenOCD. Defaults to on." }, { .name = "set_ebreaks", .handler = riscv_set_ebreaks, .mode = COMMAND_ANY, .usage = "on|off", .help = "Control dcsr.ebreaks. When off, S-mode ebreak instructions " "don't trap to OpenOCD. Defaults to on." }, { .name = "set_ebreaku", .handler = riscv_set_ebreaku, .mode = COMMAND_ANY, .usage = "on|off", .help = "Control dcsr.ebreaku. When off, U-mode ebreak instructions " "don't trap to OpenOCD. Defaults to on." }, COMMAND_REGISTRATION_DONE }; /* * To be noted that RISC-V targets use the same semihosting commands as * ARM targets. * * The main reason is compatibility with existing tools. For example the * Eclipse OpenOCD/SEGGER J-Link/QEMU plug-ins have several widgets to * configure semihosting, which generate commands like `arm semihosting * enable`. * A secondary reason is the fact that the protocol used is exactly the * one specified by ARM. If RISC-V will ever define its own semihosting * protocol, then a command like `riscv semihosting enable` will make * sense, but for now all semihosting commands are prefixed with `arm`. */ static const struct command_registration riscv_command_handlers[] = { { .name = "riscv", .mode = COMMAND_ANY, .help = "RISC-V Command Group", .usage = "", .chain = riscv_exec_command_handlers }, { .name = "arm", .mode = COMMAND_ANY, .help = "ARM Command Group", .usage = "", .chain = semihosting_common_handlers }, COMMAND_REGISTRATION_DONE }; static unsigned riscv_xlen_nonconst(struct target *target) { return riscv_xlen(target); } static unsigned int riscv_data_bits(struct target *target) { RISCV_INFO(r); if (r->data_bits) return r->data_bits(target); return riscv_xlen(target); } struct target_type riscv_target = { .name = "riscv", .target_create = riscv_create_target, .init_target = riscv_init_target, .deinit_target = riscv_deinit_target, .examine = riscv_examine, /* poll current target status */ .poll = old_or_new_riscv_poll, .halt = riscv_halt, .resume = riscv_target_resume, .step = old_or_new_riscv_step, .assert_reset = riscv_assert_reset, .deassert_reset = riscv_deassert_reset, .read_memory = riscv_read_memory, .write_memory = riscv_write_memory, .read_phys_memory = riscv_read_phys_memory, .write_phys_memory = riscv_write_phys_memory, .checksum_memory = riscv_checksum_memory, .mmu = riscv_mmu, .virt2phys = riscv_virt2phys, .get_gdb_arch = riscv_get_gdb_arch, .get_gdb_reg_list = riscv_get_gdb_reg_list, .get_gdb_reg_list_noread = riscv_get_gdb_reg_list_noread, .add_breakpoint = riscv_add_breakpoint, .remove_breakpoint = riscv_remove_breakpoint, .add_watchpoint = riscv_add_watchpoint, .remove_watchpoint = riscv_remove_watchpoint, .hit_watchpoint = riscv_hit_watchpoint, .arch_state = riscv_arch_state, .run_algorithm = riscv_run_algorithm, .commands = riscv_command_handlers, .address_bits = riscv_xlen_nonconst, .data_bits = riscv_data_bits }; /*** RISC-V Interface ***/ /* Initializes the shared RISC-V structure. */ static void riscv_info_init(struct target *target, struct riscv_info *r) { memset(r, 0, sizeof(*r)); r->common_magic = RISCV_COMMON_MAGIC; r->dtm_version = 1; r->current_hartid = target->coreid; r->version_specific = NULL; memset(r->trigger_unique_id, 0xff, sizeof(r->trigger_unique_id)); r->xlen = -1; r->mem_access_methods[0] = RISCV_MEM_ACCESS_PROGBUF; r->mem_access_methods[1] = RISCV_MEM_ACCESS_SYSBUS; r->mem_access_methods[2] = RISCV_MEM_ACCESS_ABSTRACT; r->mem_access_progbuf_warn = true; r->mem_access_sysbus_warn = true; r->mem_access_abstract_warn = true; INIT_LIST_HEAD(&r->expose_csr); INIT_LIST_HEAD(&r->expose_custom); } static int riscv_resume_go_all_harts(struct target *target) { RISCV_INFO(r); LOG_DEBUG("[%s] resuming hart", target_name(target)); if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; if (riscv_is_halted(target)) { if (r->resume_go(target) != ERROR_OK) return ERROR_FAIL; } else { LOG_DEBUG("[%s] hart requested resume, but was already resumed", target_name(target)); } riscv_invalidate_register_cache(target); return ERROR_OK; } /* Steps the hart that's currently selected in the RTOS, or if there is no RTOS * then the only hart. */ static int riscv_step_rtos_hart(struct target *target) { RISCV_INFO(r); if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("[%s] stepping", target_name(target)); if (!riscv_is_halted(target)) { LOG_ERROR("Hart isn't halted before single step!"); return ERROR_FAIL; } riscv_invalidate_register_cache(target); r->on_step(target); if (r->step_current_hart(target) != ERROR_OK) return ERROR_FAIL; riscv_invalidate_register_cache(target); r->on_halt(target); if (!riscv_is_halted(target)) { LOG_ERROR("Hart was not halted after single step!"); return ERROR_FAIL; } return ERROR_OK; } bool riscv_supports_extension(struct target *target, char letter) { RISCV_INFO(r); unsigned num; if (letter >= 'a' && letter <= 'z') num = letter - 'a'; else if (letter >= 'A' && letter <= 'Z') num = letter - 'A'; else return false; return r->misa & BIT(num); } unsigned riscv_xlen(const struct target *target) { RISCV_INFO(r); return r->xlen; } int riscv_set_current_hartid(struct target *target, int hartid) { RISCV_INFO(r); if (!r->select_current_hart) return ERROR_OK; int previous_hartid = riscv_current_hartid(target); r->current_hartid = hartid; LOG_DEBUG("setting hartid to %d, was %d", hartid, previous_hartid); if (r->select_current_hart(target) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } /* Invalidates the register cache. */ static void riscv_invalidate_register_cache(struct target *target) { LOG_DEBUG("[%d]", target->coreid); register_cache_invalidate(target->reg_cache); for (size_t i = 0; i < target->reg_cache->num_regs; ++i) { struct reg *reg = &target->reg_cache->reg_list[i]; reg->valid = false; } } int riscv_current_hartid(const struct target *target) { RISCV_INFO(r); return r->current_hartid; } int riscv_count_harts(struct target *target) { if (!target) return 1; RISCV_INFO(r); if (!r || !r->hart_count) return 1; return r->hart_count(target); } /** * If write is true: * return true iff we are guaranteed that the register will contain exactly * the value we just wrote when it's read. * If write is false: * return true iff we are guaranteed that the register will read the same * value in the future as the value we just read. */ static bool gdb_regno_cacheable(enum gdb_regno regno, bool write) { /* GPRs, FPRs, vector registers are just normal data stores. */ if (regno <= GDB_REGNO_XPR31 || (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) || (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31)) return true; /* Most CSRs won't change value on us, but we can't assume it about arbitrary * CSRs. */ switch (regno) { case GDB_REGNO_DPC: return true; case GDB_REGNO_VSTART: case GDB_REGNO_VXSAT: case GDB_REGNO_VXRM: case GDB_REGNO_VLENB: case GDB_REGNO_VL: case GDB_REGNO_VTYPE: case GDB_REGNO_MISA: case GDB_REGNO_DCSR: case GDB_REGNO_DSCRATCH0: case GDB_REGNO_MSTATUS: case GDB_REGNO_MEPC: case GDB_REGNO_MCAUSE: case GDB_REGNO_SATP: /* * WARL registers might not contain the value we just wrote, but * these ones won't spontaneously change their value either. * */ return !write; case GDB_REGNO_TSELECT: /* I think this should be above, but then it doesn't work. */ case GDB_REGNO_TDATA1: /* Changes value when tselect is changed. */ case GDB_REGNO_TDATA2: /* Changse value when tselect is changed. */ default: return false; } } /** * This function is called when the debug user wants to change the value of a * register. The new value may be cached, and may not be written until the hart * is resumed. */ int riscv_set_register(struct target *target, enum gdb_regno regid, riscv_reg_t value) { RISCV_INFO(r); LOG_DEBUG("[%s] %s <- %" PRIx64, target_name(target), gdb_regno_name(regid), value); assert(r->set_register); keep_alive(); /* TODO: Hack to deal with gdb that thinks these registers still exist. */ if (regid > GDB_REGNO_XPR15 && regid <= GDB_REGNO_XPR31 && value == 0 && riscv_supports_extension(target, 'E')) return ERROR_OK; struct reg *reg = &target->reg_cache->reg_list[regid]; buf_set_u64(reg->value, 0, reg->size, value); int result = r->set_register(target, regid, value); if (result == ERROR_OK) reg->valid = gdb_regno_cacheable(regid, true); else reg->valid = false; LOG_DEBUG("[%s] wrote 0x%" PRIx64 " to %s valid=%d", target_name(target), value, reg->name, reg->valid); return result; } int riscv_get_register(struct target *target, riscv_reg_t *value, enum gdb_regno regid) { RISCV_INFO(r); keep_alive(); struct reg *reg = &target->reg_cache->reg_list[regid]; if (!reg->exist) { LOG_DEBUG("[%s] %s does not exist.", target_name(target), gdb_regno_name(regid)); return ERROR_FAIL; } if (reg && reg->valid) { *value = buf_get_u64(reg->value, 0, reg->size); LOG_DEBUG("[%s] %s: %" PRIx64 " (cached)", target_name(target), gdb_regno_name(regid), *value); return ERROR_OK; } /* TODO: Hack to deal with gdb that thinks these registers still exist. */ if (regid > GDB_REGNO_XPR15 && regid <= GDB_REGNO_XPR31 && riscv_supports_extension(target, 'E')) { *value = 0; return ERROR_OK; } int result = r->get_register(target, value, regid); if (result == ERROR_OK) reg->valid = gdb_regno_cacheable(regid, false); LOG_DEBUG("[%s] %s: %" PRIx64, target_name(target), gdb_regno_name(regid), *value); return result; } bool riscv_is_halted(struct target *target) { RISCV_INFO(r); assert(r->is_halted); return r->is_halted(target); } static enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid) { RISCV_INFO(r); if (riscv_set_current_hartid(target, hartid) != ERROR_OK) return RISCV_HALT_ERROR; if (!riscv_is_halted(target)) { LOG_ERROR("Hart is not halted!"); return RISCV_HALT_UNKNOWN; } return r->halt_reason(target); } size_t riscv_debug_buffer_size(struct target *target) { RISCV_INFO(r); return r->debug_buffer_size; } int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn) { RISCV_INFO(r); r->write_debug_buffer(target, index, insn); return ERROR_OK; } riscv_insn_t riscv_read_debug_buffer(struct target *target, int index) { RISCV_INFO(r); return r->read_debug_buffer(target, index); } int riscv_execute_debug_buffer(struct target *target) { RISCV_INFO(r); return r->execute_debug_buffer(target); } void riscv_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d) { RISCV_INFO(r); r->fill_dmi_write_u64(target, buf, a, d); } void riscv_fill_dmi_read_u64(struct target *target, char *buf, int a) { RISCV_INFO(r); r->fill_dmi_read_u64(target, buf, a); } void riscv_fill_dmi_nop_u64(struct target *target, char *buf) { RISCV_INFO(r); r->fill_dmi_nop_u64(target, buf); } int riscv_dmi_write_u64_bits(struct target *target) { RISCV_INFO(r); return r->dmi_write_u64_bits(target); } /** * Count triggers, and initialize trigger_count for each hart. * trigger_count is initialized even if this function fails to discover * something. * Disable any hardware triggers that have dmode set. We can't have set them * ourselves. Maybe they're left over from some killed debug session. * */ int riscv_enumerate_triggers(struct target *target) { RISCV_INFO(r); if (r->triggers_enumerated) return ERROR_OK; r->triggers_enumerated = true; /* At the very least we tried. */ riscv_reg_t tselect; int result = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT); /* If tselect is not readable, the trigger module is likely not * implemented. There are no triggers to enumerate then and no error * should be thrown. */ if (result != ERROR_OK) { LOG_DEBUG("[%s] Cannot access tselect register. " "Assuming that triggers are not implemented.", target_name(target)); r->trigger_count = 0; return ERROR_OK; } for (unsigned int t = 0; t < RISCV_MAX_TRIGGERS; ++t) { r->trigger_count = t; /* If we can't write tselect, then this hart does not support triggers. */ if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK) break; uint64_t tselect_rb; result = riscv_get_register(target, &tselect_rb, GDB_REGNO_TSELECT); if (result != ERROR_OK) return result; /* Mask off the top bit, which is used as tdrmode in old * implementations. */ tselect_rb &= ~(1ULL << (riscv_xlen(target) - 1)); if (tselect_rb != t) break; uint64_t tdata1; result = riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1); if (result != ERROR_OK) return result; int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); if (type == 0) break; switch (type) { case 1: /* On these older cores we don't support software using * triggers. */ riscv_set_register(target, GDB_REGNO_TDATA1, 0); break; case 2: if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) riscv_set_register(target, GDB_REGNO_TDATA1, 0); break; case 6: if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) riscv_set_register(target, GDB_REGNO_TDATA1, 0); break; } } riscv_set_register(target, GDB_REGNO_TSELECT, tselect); LOG_INFO("[%s] Found %d triggers", target_name(target), r->trigger_count); return ERROR_OK; } const char *gdb_regno_name(enum gdb_regno regno) { static char buf[32]; switch (regno) { case GDB_REGNO_ZERO: return "zero"; case GDB_REGNO_RA: return "ra"; case GDB_REGNO_SP: return "sp"; case GDB_REGNO_GP: return "gp"; case GDB_REGNO_TP: return "tp"; case GDB_REGNO_T0: return "t0"; case GDB_REGNO_T1: return "t1"; case GDB_REGNO_T2: return "t2"; case GDB_REGNO_S0: return "s0"; case GDB_REGNO_S1: return "s1"; case GDB_REGNO_A0: return "a0"; case GDB_REGNO_A1: return "a1"; case GDB_REGNO_A2: return "a2"; case GDB_REGNO_A3: return "a3"; case GDB_REGNO_A4: return "a4"; case GDB_REGNO_A5: return "a5"; case GDB_REGNO_A6: return "a6"; case GDB_REGNO_A7: return "a7"; case GDB_REGNO_S2: return "s2"; case GDB_REGNO_S3: return "s3"; case GDB_REGNO_S4: return "s4"; case GDB_REGNO_S5: return "s5"; case GDB_REGNO_S6: return "s6"; case GDB_REGNO_S7: return "s7"; case GDB_REGNO_S8: return "s8"; case GDB_REGNO_S9: return "s9"; case GDB_REGNO_S10: return "s10"; case GDB_REGNO_S11: return "s11"; case GDB_REGNO_T3: return "t3"; case GDB_REGNO_T4: return "t4"; case GDB_REGNO_T5: return "t5"; case GDB_REGNO_T6: return "t6"; case GDB_REGNO_PC: return "pc"; case GDB_REGNO_FPR0: return "fpr0"; case GDB_REGNO_FPR31: return "fpr31"; case GDB_REGNO_CSR0: return "csr0"; case GDB_REGNO_TSELECT: return "tselect"; case GDB_REGNO_TDATA1: return "tdata1"; case GDB_REGNO_TDATA2: return "tdata2"; case GDB_REGNO_MISA: return "misa"; case GDB_REGNO_DPC: return "dpc"; case GDB_REGNO_DCSR: return "dcsr"; case GDB_REGNO_DSCRATCH0: return "dscratch0"; case GDB_REGNO_MSTATUS: return "mstatus"; case GDB_REGNO_MEPC: return "mepc"; case GDB_REGNO_MCAUSE: return "mcause"; case GDB_REGNO_PRIV: return "priv"; case GDB_REGNO_SATP: return "satp"; case GDB_REGNO_VTYPE: return "vtype"; case GDB_REGNO_VL: return "vl"; case GDB_REGNO_V0: return "v0"; case GDB_REGNO_V1: return "v1"; case GDB_REGNO_V2: return "v2"; case GDB_REGNO_V3: return "v3"; case GDB_REGNO_V4: return "v4"; case GDB_REGNO_V5: return "v5"; case GDB_REGNO_V6: return "v6"; case GDB_REGNO_V7: return "v7"; case GDB_REGNO_V8: return "v8"; case GDB_REGNO_V9: return "v9"; case GDB_REGNO_V10: return "v10"; case GDB_REGNO_V11: return "v11"; case GDB_REGNO_V12: return "v12"; case GDB_REGNO_V13: return "v13"; case GDB_REGNO_V14: return "v14"; case GDB_REGNO_V15: return "v15"; case GDB_REGNO_V16: return "v16"; case GDB_REGNO_V17: return "v17"; case GDB_REGNO_V18: return "v18"; case GDB_REGNO_V19: return "v19"; case GDB_REGNO_V20: return "v20"; case GDB_REGNO_V21: return "v21"; case GDB_REGNO_V22: return "v22"; case GDB_REGNO_V23: return "v23"; case GDB_REGNO_V24: return "v24"; case GDB_REGNO_V25: return "v25"; case GDB_REGNO_V26: return "v26"; case GDB_REGNO_V27: return "v27"; case GDB_REGNO_V28: return "v28"; case GDB_REGNO_V29: return "v29"; case GDB_REGNO_V30: return "v30"; case GDB_REGNO_V31: return "v31"; default: if (regno <= GDB_REGNO_XPR31) sprintf(buf, "x%d", regno - GDB_REGNO_ZERO); else if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) sprintf(buf, "csr%d", regno - GDB_REGNO_CSR0); else if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) sprintf(buf, "f%d", regno - GDB_REGNO_FPR0); else sprintf(buf, "gdb_regno_%d", regno); return buf; } } static int register_get(struct reg *reg) { riscv_reg_info_t *reg_info = reg->arch_info; struct target *target = reg_info->target; RISCV_INFO(r); if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) { if (!r->get_register_buf) { LOG_ERROR("Reading register %s not supported on this RISC-V target.", gdb_regno_name(reg->number)); return ERROR_FAIL; } if (r->get_register_buf(target, reg->value, reg->number) != ERROR_OK) return ERROR_FAIL; } else { uint64_t value; int result = riscv_get_register(target, &value, reg->number); if (result != ERROR_OK) return result; buf_set_u64(reg->value, 0, reg->size, value); } reg->valid = gdb_regno_cacheable(reg->number, false); char *str = buf_to_hex_str(reg->value, reg->size); LOG_DEBUG("[%s] read 0x%s from %s (valid=%d)", target_name(target), str, reg->name, reg->valid); free(str); return ERROR_OK; } static int register_set(struct reg *reg, uint8_t *buf) { riscv_reg_info_t *reg_info = reg->arch_info; struct target *target = reg_info->target; RISCV_INFO(r); char *str = buf_to_hex_str(buf, reg->size); LOG_DEBUG("[%s] write 0x%s to %s (valid=%d)", target_name(target), str, reg->name, reg->valid); free(str); /* Exit early for writing x0, which on the hardware would be ignored, and we * don't want to update our cache. */ if (reg->number == GDB_REGNO_ZERO) return ERROR_OK; memcpy(reg->value, buf, DIV_ROUND_UP(reg->size, 8)); reg->valid = gdb_regno_cacheable(reg->number, true); if (reg->number == GDB_REGNO_TDATA1 || reg->number == GDB_REGNO_TDATA2) { r->manual_hwbp_set = true; /* When enumerating triggers, we clear any triggers with DMODE set, * assuming they were left over from a previous debug session. So make * sure that is done before a user might be setting their own triggers. */ if (riscv_enumerate_triggers(target) != ERROR_OK) return ERROR_FAIL; } if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) { if (!r->set_register_buf) { LOG_ERROR("Writing register %s not supported on this RISC-V target.", gdb_regno_name(reg->number)); return ERROR_FAIL; } if (r->set_register_buf(target, reg->number, reg->value) != ERROR_OK) return ERROR_FAIL; } else { uint64_t value = buf_get_u64(buf, 0, reg->size); if (riscv_set_register(target, reg->number, value) != ERROR_OK) return ERROR_FAIL; } return ERROR_OK; } static struct reg_arch_type riscv_reg_arch_type = { .get = register_get, .set = register_set }; struct csr_info { unsigned number; const char *name; }; static int cmp_csr_info(const void *p1, const void *p2) { return (int) (((struct csr_info *)p1)->number) - (int) (((struct csr_info *)p2)->number); } int riscv_init_registers(struct target *target) { RISCV_INFO(info); riscv_free_registers(target); target->reg_cache = calloc(1, sizeof(*target->reg_cache)); if (!target->reg_cache) return ERROR_FAIL; target->reg_cache->name = "RISC-V Registers"; target->reg_cache->num_regs = GDB_REGNO_COUNT; if (!list_empty(&info->expose_custom)) { range_list_t *entry; list_for_each_entry(entry, &info->expose_custom, list) target->reg_cache->num_regs += entry->high - entry->low + 1; } LOG_DEBUG("create register cache for %d registers", target->reg_cache->num_regs); target->reg_cache->reg_list = calloc(target->reg_cache->num_regs, sizeof(struct reg)); if (!target->reg_cache->reg_list) return ERROR_FAIL; const unsigned int max_reg_name_len = 12; free(info->reg_names); info->reg_names = calloc(target->reg_cache->num_regs, max_reg_name_len); if (!info->reg_names) return ERROR_FAIL; char *reg_name = info->reg_names; static struct reg_feature feature_cpu = { .name = "org.gnu.gdb.riscv.cpu" }; static struct reg_feature feature_fpu = { .name = "org.gnu.gdb.riscv.fpu" }; static struct reg_feature feature_csr = { .name = "org.gnu.gdb.riscv.csr" }; static struct reg_feature feature_vector = { .name = "org.gnu.gdb.riscv.vector" }; static struct reg_feature feature_virtual = { .name = "org.gnu.gdb.riscv.virtual" }; static struct reg_feature feature_custom = { .name = "org.gnu.gdb.riscv.custom" }; /* These types are built into gdb. */ static struct reg_data_type type_ieee_single = { .type = REG_TYPE_IEEE_SINGLE, .id = "ieee_single" }; static struct reg_data_type type_ieee_double = { .type = REG_TYPE_IEEE_DOUBLE, .id = "ieee_double" }; static struct reg_data_type_union_field single_double_fields[] = { {"float", &type_ieee_single, single_double_fields + 1}, {"double", &type_ieee_double, NULL}, }; static struct reg_data_type_union single_double_union = { .fields = single_double_fields }; static struct reg_data_type type_ieee_single_double = { .type = REG_TYPE_ARCH_DEFINED, .id = "FPU_FD", .type_class = REG_TYPE_CLASS_UNION, .reg_type_union = &single_double_union }; static struct reg_data_type type_uint8 = { .type = REG_TYPE_UINT8, .id = "uint8" }; static struct reg_data_type type_uint16 = { .type = REG_TYPE_UINT16, .id = "uint16" }; static struct reg_data_type type_uint32 = { .type = REG_TYPE_UINT32, .id = "uint32" }; static struct reg_data_type type_uint64 = { .type = REG_TYPE_UINT64, .id = "uint64" }; static struct reg_data_type type_uint128 = { .type = REG_TYPE_UINT128, .id = "uint128" }; /* This is roughly the XML we want: * <vector id="bytes" type="uint8" count="16"/> * <vector id="shorts" type="uint16" count="8"/> * <vector id="words" type="uint32" count="4"/> * <vector id="longs" type="uint64" count="2"/> * <vector id="quads" type="uint128" count="1"/> * <union id="riscv_vector_type"> * <field name="b" type="bytes"/> * <field name="s" type="shorts"/> * <field name="w" type="words"/> * <field name="l" type="longs"/> * <field name="q" type="quads"/> * </union> */ info->vector_uint8.type = &type_uint8; info->vector_uint8.count = info->vlenb; info->type_uint8_vector.type = REG_TYPE_ARCH_DEFINED; info->type_uint8_vector.id = "bytes"; info->type_uint8_vector.type_class = REG_TYPE_CLASS_VECTOR; info->type_uint8_vector.reg_type_vector = &info->vector_uint8; info->vector_uint16.type = &type_uint16; info->vector_uint16.count = info->vlenb / 2; info->type_uint16_vector.type = REG_TYPE_ARCH_DEFINED; info->type_uint16_vector.id = "shorts"; info->type_uint16_vector.type_class = REG_TYPE_CLASS_VECTOR; info->type_uint16_vector.reg_type_vector = &info->vector_uint16; info->vector_uint32.type = &type_uint32; info->vector_uint32.count = info->vlenb / 4; info->type_uint32_vector.type = REG_TYPE_ARCH_DEFINED; info->type_uint32_vector.id = "words"; info->type_uint32_vector.type_class = REG_TYPE_CLASS_VECTOR; info->type_uint32_vector.reg_type_vector = &info->vector_uint32; info->vector_uint64.type = &type_uint64; info->vector_uint64.count = info->vlenb / 8; info->type_uint64_vector.type = REG_TYPE_ARCH_DEFINED; info->type_uint64_vector.id = "longs"; info->type_uint64_vector.type_class = REG_TYPE_CLASS_VECTOR; info->type_uint64_vector.reg_type_vector = &info->vector_uint64; info->vector_uint128.type = &type_uint128; info->vector_uint128.count = info->vlenb / 16; info->type_uint128_vector.type = REG_TYPE_ARCH_DEFINED; info->type_uint128_vector.id = "quads"; info->type_uint128_vector.type_class = REG_TYPE_CLASS_VECTOR; info->type_uint128_vector.reg_type_vector = &info->vector_uint128; info->vector_fields[0].name = "b"; info->vector_fields[0].type = &info->type_uint8_vector; if (info->vlenb >= 2) { info->vector_fields[0].next = info->vector_fields + 1; info->vector_fields[1].name = "s"; info->vector_fields[1].type = &info->type_uint16_vector; } else { info->vector_fields[0].next = NULL; } if (info->vlenb >= 4) { info->vector_fields[1].next = info->vector_fields + 2; info->vector_fields[2].name = "w"; info->vector_fields[2].type = &info->type_uint32_vector; } else { info->vector_fields[1].next = NULL; } if (info->vlenb >= 8) { info->vector_fields[2].next = info->vector_fields + 3; info->vector_fields[3].name = "l"; info->vector_fields[3].type = &info->type_uint64_vector; } else { info->vector_fields[2].next = NULL; } if (info->vlenb >= 16) { info->vector_fields[3].next = info->vector_fields + 4; info->vector_fields[4].name = "q"; info->vector_fields[4].type = &info->type_uint128_vector; } else { info->vector_fields[3].next = NULL; } info->vector_fields[4].next = NULL; info->vector_union.fields = info->vector_fields; info->type_vector.type = REG_TYPE_ARCH_DEFINED; info->type_vector.id = "riscv_vector"; info->type_vector.type_class = REG_TYPE_CLASS_UNION; info->type_vector.reg_type_union = &info->vector_union; struct csr_info csr_info[] = { #define DECLARE_CSR(name, number) { number, #name }, #include "encoding.h" #undef DECLARE_CSR }; /* encoding.h does not contain the registers in sorted order. */ qsort(csr_info, ARRAY_SIZE(csr_info), sizeof(*csr_info), cmp_csr_info); unsigned csr_info_index = 0; int custom_within_range = 0; riscv_reg_info_t *shared_reg_info = calloc(1, sizeof(riscv_reg_info_t)); if (!shared_reg_info) return ERROR_FAIL; shared_reg_info->target = target; /* When gdb requests register N, gdb_get_register_packet() assumes that this * is register at index N in reg_list. So if there are certain registers * that don't exist, we need to leave holes in the list (or renumber, but * it would be nice not to have yet another set of numbers to translate * between). */ for (uint32_t number = 0; number < target->reg_cache->num_regs; number++) { struct reg *r = &target->reg_cache->reg_list[number]; r->dirty = false; r->valid = false; r->exist = true; r->type = &riscv_reg_arch_type; r->arch_info = shared_reg_info; r->number = number; r->size = riscv_xlen(target); /* r->size is set in riscv_invalidate_register_cache, maybe because the * target is in theory allowed to change XLEN on us. But I expect a lot * of other things to break in that case as well. */ if (number <= GDB_REGNO_XPR31) { r->exist = number <= GDB_REGNO_XPR15 || !riscv_supports_extension(target, 'E'); /* TODO: For now we fake that all GPRs exist because otherwise gdb * doesn't work. */ r->exist = true; r->caller_save = true; switch (number) { case GDB_REGNO_ZERO: r->name = "zero"; break; case GDB_REGNO_RA: r->name = "ra"; break; case GDB_REGNO_SP: r->name = "sp"; break; case GDB_REGNO_GP: r->name = "gp"; break; case GDB_REGNO_TP: r->name = "tp"; break; case GDB_REGNO_T0: r->name = "t0"; break; case GDB_REGNO_T1: r->name = "t1"; break; case GDB_REGNO_T2: r->name = "t2"; break; case GDB_REGNO_FP: r->name = "fp"; break; case GDB_REGNO_S1: r->name = "s1"; break; case GDB_REGNO_A0: r->name = "a0"; break; case GDB_REGNO_A1: r->name = "a1"; break; case GDB_REGNO_A2: r->name = "a2"; break; case GDB_REGNO_A3: r->name = "a3"; break; case GDB_REGNO_A4: r->name = "a4"; break; case GDB_REGNO_A5: r->name = "a5"; break; case GDB_REGNO_A6: r->name = "a6"; break; case GDB_REGNO_A7: r->name = "a7"; break; case GDB_REGNO_S2: r->name = "s2"; break; case GDB_REGNO_S3: r->name = "s3"; break; case GDB_REGNO_S4: r->name = "s4"; break; case GDB_REGNO_S5: r->name = "s5"; break; case GDB_REGNO_S6: r->name = "s6"; break; case GDB_REGNO_S7: r->name = "s7"; break; case GDB_REGNO_S8: r->name = "s8"; break; case GDB_REGNO_S9: r->name = "s9"; break; case GDB_REGNO_S10: r->name = "s10"; break; case GDB_REGNO_S11: r->name = "s11"; break; case GDB_REGNO_T3: r->name = "t3"; break; case GDB_REGNO_T4: r->name = "t4"; break; case GDB_REGNO_T5: r->name = "t5"; break; case GDB_REGNO_T6: r->name = "t6"; break; } r->group = "general"; r->feature = &feature_cpu; } else if (number == GDB_REGNO_PC) { r->caller_save = true; sprintf(reg_name, "pc"); r->group = "general"; r->feature = &feature_cpu; } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { r->caller_save = true; if (riscv_supports_extension(target, 'D')) { r->size = 64; if (riscv_supports_extension(target, 'F')) r->reg_data_type = &type_ieee_single_double; else r->reg_data_type = &type_ieee_double; } else if (riscv_supports_extension(target, 'F')) { r->reg_data_type = &type_ieee_single; r->size = 32; } else { r->exist = false; } switch (number) { case GDB_REGNO_FT0: r->name = "ft0"; break; case GDB_REGNO_FT1: r->name = "ft1"; break; case GDB_REGNO_FT2: r->name = "ft2"; break; case GDB_REGNO_FT3: r->name = "ft3"; break; case GDB_REGNO_FT4: r->name = "ft4"; break; case GDB_REGNO_FT5: r->name = "ft5"; break; case GDB_REGNO_FT6: r->name = "ft6"; break; case GDB_REGNO_FT7: r->name = "ft7"; break; case GDB_REGNO_FS0: r->name = "fs0"; break; case GDB_REGNO_FS1: r->name = "fs1"; break; case GDB_REGNO_FA0: r->name = "fa0"; break; case GDB_REGNO_FA1: r->name = "fa1"; break; case GDB_REGNO_FA2: r->name = "fa2"; break; case GDB_REGNO_FA3: r->name = "fa3"; break; case GDB_REGNO_FA4: r->name = "fa4"; break; case GDB_REGNO_FA5: r->name = "fa5"; break; case GDB_REGNO_FA6: r->name = "fa6"; break; case GDB_REGNO_FA7: r->name = "fa7"; break; case GDB_REGNO_FS2: r->name = "fs2"; break; case GDB_REGNO_FS3: r->name = "fs3"; break; case GDB_REGNO_FS4: r->name = "fs4"; break; case GDB_REGNO_FS5: r->name = "fs5"; break; case GDB_REGNO_FS6: r->name = "fs6"; break; case GDB_REGNO_FS7: r->name = "fs7"; break; case GDB_REGNO_FS8: r->name = "fs8"; break; case GDB_REGNO_FS9: r->name = "fs9"; break; case GDB_REGNO_FS10: r->name = "fs10"; break; case GDB_REGNO_FS11: r->name = "fs11"; break; case GDB_REGNO_FT8: r->name = "ft8"; break; case GDB_REGNO_FT9: r->name = "ft9"; break; case GDB_REGNO_FT10: r->name = "ft10"; break; case GDB_REGNO_FT11: r->name = "ft11"; break; } r->group = "float"; r->feature = &feature_fpu; } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { r->group = "csr"; r->feature = &feature_csr; unsigned csr_number = number - GDB_REGNO_CSR0; while (csr_info[csr_info_index].number < csr_number && csr_info_index < ARRAY_SIZE(csr_info) - 1) { csr_info_index++; } if (csr_info[csr_info_index].number == csr_number) { r->name = csr_info[csr_info_index].name; } else { sprintf(reg_name, "csr%d", csr_number); /* Assume unnamed registers don't exist, unless we have some * configuration that tells us otherwise. That's important * because eg. Eclipse crashes if a target has too many * registers, and apparently has no way of only showing a * subset of registers in any case. */ r->exist = false; } switch (csr_number) { case CSR_FFLAGS: case CSR_FRM: case CSR_FCSR: r->exist = riscv_supports_extension(target, 'F'); r->group = "float"; r->feature = &feature_fpu; break; case CSR_SSTATUS: case CSR_STVEC: case CSR_SIP: case CSR_SIE: case CSR_SCOUNTEREN: case CSR_SSCRATCH: case CSR_SEPC: case CSR_SCAUSE: case CSR_STVAL: case CSR_SATP: r->exist = riscv_supports_extension(target, 'S'); break; case CSR_MEDELEG: case CSR_MIDELEG: /* "In systems with only M-mode, or with both M-mode and * U-mode but without U-mode trap support, the medeleg and * mideleg registers should not exist." */ r->exist = riscv_supports_extension(target, 'S') || riscv_supports_extension(target, 'N'); break; case CSR_PMPCFG1: case CSR_PMPCFG3: case CSR_CYCLEH: case CSR_TIMEH: case CSR_INSTRETH: case CSR_HPMCOUNTER3H: case CSR_HPMCOUNTER4H: case CSR_HPMCOUNTER5H: case CSR_HPMCOUNTER6H: case CSR_HPMCOUNTER7H: case CSR_HPMCOUNTER8H: case CSR_HPMCOUNTER9H: case CSR_HPMCOUNTER10H: case CSR_HPMCOUNTER11H: case CSR_HPMCOUNTER12H: case CSR_HPMCOUNTER13H: case CSR_HPMCOUNTER14H: case CSR_HPMCOUNTER15H: case CSR_HPMCOUNTER16H: case CSR_HPMCOUNTER17H: case CSR_HPMCOUNTER18H: case CSR_HPMCOUNTER19H: case CSR_HPMCOUNTER20H: case CSR_HPMCOUNTER21H: case CSR_HPMCOUNTER22H: case CSR_HPMCOUNTER23H: case CSR_HPMCOUNTER24H: case CSR_HPMCOUNTER25H: case CSR_HPMCOUNTER26H: case CSR_HPMCOUNTER27H: case CSR_HPMCOUNTER28H: case CSR_HPMCOUNTER29H: case CSR_HPMCOUNTER30H: case CSR_HPMCOUNTER31H: case CSR_MCYCLEH: case CSR_MINSTRETH: case CSR_MHPMCOUNTER3H: case CSR_MHPMCOUNTER4H: case CSR_MHPMCOUNTER5H: case CSR_MHPMCOUNTER6H: case CSR_MHPMCOUNTER7H: case CSR_MHPMCOUNTER8H: case CSR_MHPMCOUNTER9H: case CSR_MHPMCOUNTER10H: case CSR_MHPMCOUNTER11H: case CSR_MHPMCOUNTER12H: case CSR_MHPMCOUNTER13H: case CSR_MHPMCOUNTER14H: case CSR_MHPMCOUNTER15H: case CSR_MHPMCOUNTER16H: case CSR_MHPMCOUNTER17H: case CSR_MHPMCOUNTER18H: case CSR_MHPMCOUNTER19H: case CSR_MHPMCOUNTER20H: case CSR_MHPMCOUNTER21H: case CSR_MHPMCOUNTER22H: case CSR_MHPMCOUNTER23H: case CSR_MHPMCOUNTER24H: case CSR_MHPMCOUNTER25H: case CSR_MHPMCOUNTER26H: case CSR_MHPMCOUNTER27H: case CSR_MHPMCOUNTER28H: case CSR_MHPMCOUNTER29H: case CSR_MHPMCOUNTER30H: case CSR_MHPMCOUNTER31H: r->exist = riscv_xlen(target) == 32; break; case CSR_VSTART: case CSR_VXSAT: case CSR_VXRM: case CSR_VL: case CSR_VTYPE: case CSR_VLENB: r->exist = riscv_supports_extension(target, 'V'); break; } if (!r->exist && !list_empty(&info->expose_csr)) { range_list_t *entry; list_for_each_entry(entry, &info->expose_csr, list) if ((entry->low <= csr_number) && (csr_number <= entry->high)) { if (entry->name) { *reg_name = 0; r->name = entry->name; } LOG_DEBUG("Exposing additional CSR %d (name=%s)", csr_number, entry->name ? entry->name : reg_name); r->exist = true; break; } } } else if (number == GDB_REGNO_PRIV) { sprintf(reg_name, "priv"); r->group = "general"; r->feature = &feature_virtual; r->size = 8; } else if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31) { r->caller_save = false; r->exist = riscv_supports_extension(target, 'V') && info->vlenb; r->size = info->vlenb * 8; sprintf(reg_name, "v%d", number - GDB_REGNO_V0); r->group = "vector"; r->feature = &feature_vector; r->reg_data_type = &info->type_vector; } else if (number >= GDB_REGNO_COUNT) { /* Custom registers. */ assert(!list_empty(&info->expose_custom)); range_list_t *range = list_first_entry(&info->expose_custom, range_list_t, list); unsigned custom_number = range->low + custom_within_range; r->group = "custom"; r->feature = &feature_custom; r->arch_info = calloc(1, sizeof(riscv_reg_info_t)); if (!r->arch_info) return ERROR_FAIL; ((riscv_reg_info_t *) r->arch_info)->target = target; ((riscv_reg_info_t *) r->arch_info)->custom_number = custom_number; sprintf(reg_name, "custom%d", custom_number); if (range->name) { *reg_name = 0; r->name = range->name; } LOG_DEBUG("Exposing additional custom register %d (name=%s)", number, range->name ? range->name : reg_name); custom_within_range++; if (custom_within_range > range->high - range->low) { custom_within_range = 0; list_rotate_left(&info->expose_custom); } } if (reg_name[0]) { r->name = reg_name; reg_name += strlen(reg_name) + 1; assert(reg_name < info->reg_names + target->reg_cache->num_regs * max_reg_name_len); } r->value = calloc(1, DIV_ROUND_UP(r->size, 8)); } return ERROR_OK; } void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field, riscv_bscan_tunneled_scan_context_t *ctxt) { jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE); memset(ctxt->tunneled_dr, 0, sizeof(ctxt->tunneled_dr)); if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) { ctxt->tunneled_dr[3].num_bits = 1; ctxt->tunneled_dr[3].out_value = bscan_one; ctxt->tunneled_dr[2].num_bits = 7; ctxt->tunneled_dr_width = field->num_bits; ctxt->tunneled_dr[2].out_value = &ctxt->tunneled_dr_width; /* for BSCAN tunnel, there is a one-TCK skew between shift in and shift out, so scanning num_bits + 1, and then will right shift the input field after executing the queues */ ctxt->tunneled_dr[1].num_bits = field->num_bits + 1; ctxt->tunneled_dr[1].out_value = field->out_value; ctxt->tunneled_dr[1].in_value = field->in_value; ctxt->tunneled_dr[0].num_bits = 3; ctxt->tunneled_dr[0].out_value = bscan_zero; } else { /* BSCAN_TUNNEL_NESTED_TAP */ ctxt->tunneled_dr[0].num_bits = 1; ctxt->tunneled_dr[0].out_value = bscan_one; ctxt->tunneled_dr[1].num_bits = 7; ctxt->tunneled_dr_width = field->num_bits; ctxt->tunneled_dr[1].out_value = &ctxt->tunneled_dr_width; /* for BSCAN tunnel, there is a one-TCK skew between shift in and shift out, so scanning num_bits + 1, and then will right shift the input field after executing the queues */ ctxt->tunneled_dr[2].num_bits = field->num_bits + 1; ctxt->tunneled_dr[2].out_value = field->out_value; ctxt->tunneled_dr[2].in_value = field->in_value; ctxt->tunneled_dr[3].num_bits = 3; ctxt->tunneled_dr[3].out_value = bscan_zero; } jtag_add_dr_scan(target->tap, ARRAY_SIZE(ctxt->tunneled_dr), ctxt->tunneled_dr, TAP_IDLE); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/riscv.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef RISCV_H #define RISCV_H struct riscv_program; #include <stdint.h> #include "opcodes.h" #include "gdb_regs.h" #include "jtag/jtag.h" #include "target/register.h" #include "target/semihosting_common.h" #include <helper/command.h> #define RISCV_COMMON_MAGIC 0x52495356U /* The register cache is statically allocated. */ #define RISCV_MAX_HARTS 1024 #define RISCV_MAX_REGISTERS 5000 #define RISCV_MAX_TRIGGERS 32 #define RISCV_MAX_HWBPS 16 #define DEFAULT_COMMAND_TIMEOUT_SEC 2 #define DEFAULT_RESET_TIMEOUT_SEC 30 #define RISCV_SATP_MODE(xlen) ((xlen) == 32 ? SATP32_MODE : SATP64_MODE) #define RISCV_SATP_PPN(xlen) ((xlen) == 32 ? SATP32_PPN : SATP64_PPN) #define RISCV_PGSHIFT 12 # define PG_MAX_LEVEL 4 #define RISCV_NUM_MEM_ACCESS_METHODS 3 extern struct target_type riscv011_target; extern struct target_type riscv013_target; /* * Definitions shared by code supporting all RISC-V versions. */ typedef uint64_t riscv_reg_t; typedef uint32_t riscv_insn_t; typedef uint64_t riscv_addr_t; enum riscv_mem_access_method { RISCV_MEM_ACCESS_UNSPECIFIED, RISCV_MEM_ACCESS_PROGBUF, RISCV_MEM_ACCESS_SYSBUS, RISCV_MEM_ACCESS_ABSTRACT }; enum riscv_halt_reason { RISCV_HALT_INTERRUPT, RISCV_HALT_BREAKPOINT, RISCV_HALT_SINGLESTEP, RISCV_HALT_TRIGGER, RISCV_HALT_UNKNOWN, RISCV_HALT_GROUP, RISCV_HALT_ERROR }; typedef struct { struct target *target; unsigned custom_number; } riscv_reg_info_t; #define RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE 0x80 #define RISCV_SAMPLE_BUF_TIMESTAMP_AFTER 0x81 struct riscv_sample_buf { uint8_t *buf; unsigned int used; unsigned int size; }; typedef struct { bool enabled; struct { bool enabled; target_addr_t address; uint32_t size_bytes; } bucket[16]; } riscv_sample_config_t; typedef struct { struct list_head list; uint16_t low, high; char *name; } range_list_t; struct riscv_info { unsigned int common_magic; unsigned dtm_version; struct command_context *cmd_ctx; void *version_specific; /* The hart that is currently being debugged. Note that this is * different than the hartid that the RTOS is expected to use. This * one will change all the time, it's more of a global argument to * every function than an actual */ int current_hartid; /* Single buffer that contains all register names, instead of calling * malloc for each register. Needs to be freed when reg_list is freed. */ char *reg_names; /* It's possible that each core has a different supported ISA set. */ int xlen; riscv_reg_t misa; /* Cached value of vlenb. 0 if vlenb is not readable for some reason. */ unsigned int vlenb; /* The number of triggers per hart. */ unsigned int trigger_count; /* For each physical trigger, contains -1 if the hwbp is available, or the * unique_id of the breakpoint/watchpoint that is using it. * Note that in RTOS mode the triggers are the same across all harts the * target controls, while otherwise only a single hart is controlled. */ int trigger_unique_id[RISCV_MAX_HWBPS]; /* The number of entries in the debug buffer. */ int debug_buffer_size; /* This hart contains an implicit ebreak at the end of the program buffer. */ bool impebreak; bool triggers_enumerated; /* Decremented every scan, and when it reaches 0 we clear the learned * delays, causing them to be relearned. Used for testing. */ int reset_delays_wait; /* This target has been prepped and is ready to step/resume. */ bool prepped; /* This target was selected using hasel. */ bool selected; /* Helper functions that target the various RISC-V debug spec * implementations. */ int (*get_register)(struct target *target, riscv_reg_t *value, int regid); int (*set_register)(struct target *target, int regid, uint64_t value); int (*get_register_buf)(struct target *target, uint8_t *buf, int regno); int (*set_register_buf)(struct target *target, int regno, const uint8_t *buf); int (*select_current_hart)(struct target *target); bool (*is_halted)(struct target *target); /* Resume this target, as well as every other prepped target that can be * resumed near-simultaneously. Clear the prepped flag on any target that * was resumed. */ int (*resume_go)(struct target *target); int (*step_current_hart)(struct target *target); int (*on_halt)(struct target *target); /* Get this target as ready as possible to resume, without actually * resuming. */ int (*resume_prep)(struct target *target); int (*halt_prep)(struct target *target); int (*halt_go)(struct target *target); int (*on_step)(struct target *target); enum riscv_halt_reason (*halt_reason)(struct target *target); int (*write_debug_buffer)(struct target *target, unsigned index, riscv_insn_t d); riscv_insn_t (*read_debug_buffer)(struct target *target, unsigned index); int (*execute_debug_buffer)(struct target *target); int (*dmi_write_u64_bits)(struct target *target); void (*fill_dmi_write_u64)(struct target *target, char *buf, int a, uint64_t d); void (*fill_dmi_read_u64)(struct target *target, char *buf, int a); void (*fill_dmi_nop_u64)(struct target *target, char *buf); int (*authdata_read)(struct target *target, uint32_t *value, unsigned int index); int (*authdata_write)(struct target *target, uint32_t value, unsigned int index); int (*dmi_read)(struct target *target, uint32_t *value, uint32_t address); int (*dmi_write)(struct target *target, uint32_t address, uint32_t value); int (*sample_memory)(struct target *target, struct riscv_sample_buf *buf, riscv_sample_config_t *config, int64_t until_ms); int (*read_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment); /* How many harts are attached to the DM that this target is attached to? */ int (*hart_count)(struct target *target); unsigned (*data_bits)(struct target *target); COMMAND_HELPER((*print_info), struct target *target); /* Storage for vector register types. */ struct reg_data_type_vector vector_uint8; struct reg_data_type_vector vector_uint16; struct reg_data_type_vector vector_uint32; struct reg_data_type_vector vector_uint64; struct reg_data_type_vector vector_uint128; struct reg_data_type type_uint8_vector; struct reg_data_type type_uint16_vector; struct reg_data_type type_uint32_vector; struct reg_data_type type_uint64_vector; struct reg_data_type type_uint128_vector; struct reg_data_type_union_field vector_fields[5]; struct reg_data_type_union vector_union; struct reg_data_type type_vector; /* Set when trigger registers are changed by the user. This indicates we eed * to beware that we may hit a trigger that we didn't realize had been set. */ bool manual_hwbp_set; /* Memory access methods to use, ordered by priority, highest to lowest. */ int mem_access_methods[RISCV_NUM_MEM_ACCESS_METHODS]; /* Different memory regions may need different methods but single configuration is applied * for all. Following flags are used to warn only once about failing memory access method. */ bool mem_access_progbuf_warn; bool mem_access_sysbus_warn; bool mem_access_abstract_warn; /* In addition to the ones in the standard spec, we'll also expose additional * CSRs in this list. */ struct list_head expose_csr; /* Same, but for custom registers. * Custom registers are for non-standard extensions and use abstract register numbers * from range 0xc000 ... 0xffff. */ struct list_head expose_custom; riscv_sample_config_t sample_config; struct riscv_sample_buf sample_buf; }; COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key, unsigned int value); typedef struct { uint8_t tunneled_dr_width; struct scan_field tunneled_dr[4]; } riscv_bscan_tunneled_scan_context_t; typedef struct { const char *name; int level; unsigned va_bits; unsigned pte_shift; unsigned vpn_shift[PG_MAX_LEVEL]; unsigned vpn_mask[PG_MAX_LEVEL]; unsigned pte_ppn_shift[PG_MAX_LEVEL]; unsigned pte_ppn_mask[PG_MAX_LEVEL]; unsigned pa_ppn_shift[PG_MAX_LEVEL]; unsigned pa_ppn_mask[PG_MAX_LEVEL]; } virt2phys_info_t; /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ extern int riscv_command_timeout_sec; /* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ extern int riscv_reset_timeout_sec; extern bool riscv_enable_virtual; extern bool riscv_ebreakm; extern bool riscv_ebreaks; extern bool riscv_ebreaku; /* Everything needs the RISC-V specific info structure, so here's a nice macro * that provides that. */ static inline struct riscv_info *riscv_info(const struct target *target) __attribute__((unused)); static inline struct riscv_info *riscv_info(const struct target *target) { assert(target->arch_info); return target->arch_info; } #define RISCV_INFO(R) struct riscv_info *R = riscv_info(target); static inline bool is_riscv(const struct riscv_info *riscv_info) { return riscv_info->common_magic == RISCV_COMMON_MAGIC; } extern struct scan_field select_dtmcontrol; extern struct scan_field select_dbus; extern struct scan_field select_idcode; extern struct scan_field *bscan_tunneled_select_dmi; extern uint32_t bscan_tunneled_select_dmi_num_fields; typedef enum { BSCAN_TUNNEL_NESTED_TAP, BSCAN_TUNNEL_DATA_REGISTER } bscan_tunnel_type_t; extern int bscan_tunnel_ir_width; uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out); void select_dmi_via_bscan(struct target *target); /*** OpenOCD Interface */ int riscv_openocd_poll(struct target *target); int riscv_halt(struct target *target); int riscv_openocd_step( struct target *target, int current, target_addr_t address, int handle_breakpoints ); int riscv_openocd_assert_reset(struct target *target); int riscv_openocd_deassert_reset(struct target *target); /*** RISC-V Interface ***/ bool riscv_supports_extension(struct target *target, char letter); /* Returns XLEN for the given (or current) hart. */ unsigned riscv_xlen(const struct target *target); int riscv_xlen_of_hart(const struct target *target); /* Sets the current hart, which is the hart that will actually be used when * issuing debug commands. */ int riscv_set_current_hartid(struct target *target, int hartid); int riscv_select_current_hart(struct target *target); int riscv_current_hartid(const struct target *target); /*** Support functions for the RISC-V 'RTOS', which provides multihart support * without requiring multiple targets. */ /* Lists the number of harts in the system, which are assumed to be * consecutive and start with mhartid=0. */ int riscv_count_harts(struct target *target); /** Set register, updating the cache. */ int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v); /** Get register, from the cache if it's in there. */ int riscv_get_register(struct target *target, riscv_reg_t *value, enum gdb_regno r); /* Checks the state of the current hart -- "is_halted" checks the actual * on-device register. */ bool riscv_is_halted(struct target *target); /* These helper functions let the generic program interface get target-specific * information. */ size_t riscv_debug_buffer_size(struct target *target); riscv_insn_t riscv_read_debug_buffer(struct target *target, int index); int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn); int riscv_execute_debug_buffer(struct target *target); void riscv_fill_dmi_nop_u64(struct target *target, char *buf); void riscv_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d); void riscv_fill_dmi_read_u64(struct target *target, char *buf, int a); int riscv_dmi_write_u64_bits(struct target *target); int riscv_enumerate_triggers(struct target *target); int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint); int riscv_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); int riscv_init_registers(struct target *target); void riscv_semihosting_init(struct target *target); enum semihosting_result riscv_semihosting(struct target *target, int *retval); void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field, riscv_bscan_tunneled_scan_context_t *ctxt); int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer); int riscv_write_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer); #endif ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/riscv/riscv_semihosting.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2018 by Liviu Ionescu * * ilg@livius.net * * * * Copyright (C) 2009 by Marvell Technology Group Ltd. * * Written by Nicolas Pitre <nico@marvell.com> * * * * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2016 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * ***************************************************************************/ /** * @file * Hold RISC-V semihosting support. * * The RISC-V code is inspired from ARM semihosting. * * Details can be found in chapter 8 of DUI0203I_rvct_developer_guide.pdf * from ARM Ltd. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include "target/target.h" #include "riscv.h" static int riscv_semihosting_setup(struct target *target, int enable); static int riscv_semihosting_post_result(struct target *target); /** * Initialize RISC-V semihosting. Use common ARM code. */ void riscv_semihosting_init(struct target *target) { semihosting_common_init(target, riscv_semihosting_setup, riscv_semihosting_post_result); } /** * Check for and process a semihosting request using the ARM protocol). This * is meant to be called when the target is stopped due to a debug mode entry. * * @param target Pointer to the target to process. * @param retval Pointer to a location where the return code will be stored * @return non-zero value if a request was processed or an error encountered */ enum semihosting_result riscv_semihosting(struct target *target, int *retval) { struct semihosting *semihosting = target->semihosting; if (!semihosting) { LOG_DEBUG(" -> NONE (!semihosting)"); return SEMIHOSTING_NONE; } if (!semihosting->is_active) { LOG_DEBUG(" -> NONE (!semihosting->is_active)"); return SEMIHOSTING_NONE; } riscv_reg_t pc; int result = riscv_get_register(target, &pc, GDB_REGNO_PC); if (result != ERROR_OK) return SEMIHOSTING_ERROR; uint8_t tmp_buf[12]; /* Read three uncompressed instructions: The previous, the current one (pointed to by PC) and the next one */ for (int i = 0; i < 3; i++) { /* Instruction memories may not support arbitrary read size. Use any size that will work. */ *retval = riscv_read_by_any_size(target, (pc - 4) + 4 * i, 4, tmp_buf + 4 * i); if (*retval != ERROR_OK) return SEMIHOSTING_ERROR; } /* * The instructions that trigger a semihosting call, * always uncompressed, should look like: * * 01f01013 slli zero,zero,0x1f * 00100073 ebreak * 40705013 srai zero,zero,0x7 */ uint32_t pre = target_buffer_get_u32(target, tmp_buf); uint32_t ebreak = target_buffer_get_u32(target, tmp_buf + 4); uint32_t post = target_buffer_get_u32(target, tmp_buf + 8); LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, pc); if (pre != 0x01f01013 || ebreak != 0x00100073 || post != 0x40705013) { /* Not the magic sequence defining semihosting. */ LOG_DEBUG(" -> NONE (no magic)"); return SEMIHOSTING_NONE; } /* * Perform semihosting call if we are not waiting on a fileio * operation to complete. */ if (!semihosting->hit_fileio) { /* RISC-V uses A0 and A1 to pass function arguments */ riscv_reg_t r0; riscv_reg_t r1; result = riscv_get_register(target, &r0, GDB_REGNO_A0); if (result != ERROR_OK) { LOG_DEBUG(" -> ERROR (couldn't read a0)"); return SEMIHOSTING_ERROR; } result = riscv_get_register(target, &r1, GDB_REGNO_A1); if (result != ERROR_OK) { LOG_DEBUG(" -> ERROR (couldn't read a1)"); return SEMIHOSTING_ERROR; } semihosting->op = r0; semihosting->param = r1; semihosting->word_size_bytes = riscv_xlen(target) / 8; /* Check for ARM operation numbers. */ if ((semihosting->op >= 0 && semihosting->op <= 0x31) || (semihosting->op >= 0x100 && semihosting->op <= 0x107)) { *retval = semihosting_common(target); if (*retval != ERROR_OK) { LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op); return SEMIHOSTING_ERROR; } } else { /* Unknown operation number, not a semihosting call. */ LOG_DEBUG(" -> NONE (unknown operation number)"); return SEMIHOSTING_NONE; } } /* Resume right after the EBREAK 4 bytes instruction. */ *retval = riscv_set_register(target, GDB_REGNO_PC, pc + 4); if (*retval != ERROR_OK) return SEMIHOSTING_ERROR; /* * Resume target if we are not waiting on a fileio * operation to complete. */ if (semihosting->is_resumable && !semihosting->hit_fileio) { LOG_DEBUG(" -> HANDLED"); return SEMIHOSTING_HANDLED; } LOG_DEBUG(" -> WAITING"); return SEMIHOSTING_WAITING; } /* ------------------------------------------------------------------------- * Local functions. */ /** * Called via semihosting->setup() later, after the target is known, * usually on the first semihosting command. */ static int riscv_semihosting_setup(struct target *target, int enable) { LOG_DEBUG("[%s] enable=%d", target_name(target), enable); struct semihosting *semihosting = target->semihosting; if (semihosting) semihosting->setup_time = clock(); return ERROR_OK; } static int riscv_semihosting_post_result(struct target *target) { struct semihosting *semihosting = target->semihosting; if (!semihosting) { /* If not enabled, silently ignored. */ return 0; } LOG_DEBUG("0x%" PRIx64, semihosting->result); riscv_set_register(target, GDB_REGNO_A0, semihosting->result); return 0; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/rtt.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de> */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stddef.h> #include <stdint.h> #include <helper/log.h> #include <helper/binarybuffer.h> #include <helper/command.h> #include <rtt/rtt.h> #include <target/rtt.h> #include "target.h" static int read_rtt_channel(struct target *target, const struct rtt_control *ctrl, unsigned int channel_index, enum rtt_channel_type type, struct rtt_channel *channel) { int ret; uint8_t buf[RTT_CHANNEL_SIZE]; target_addr_t address; address = ctrl->address + RTT_CB_SIZE + (channel_index * RTT_CHANNEL_SIZE); if (type == RTT_CHANNEL_TYPE_DOWN) address += ctrl->num_up_channels * RTT_CHANNEL_SIZE; ret = target_read_buffer(target, address, RTT_CHANNEL_SIZE, buf); if (ret != ERROR_OK) return ret; channel->address = address; channel->name_addr = buf_get_u32(buf + 0, 0, 32); channel->buffer_addr = buf_get_u32(buf + 4, 0, 32); channel->size = buf_get_u32(buf + 8, 0, 32); channel->write_pos = buf_get_u32(buf + 12, 0, 32); channel->read_pos = buf_get_u32(buf + 16, 0, 32); channel->flags = buf_get_u32(buf + 20, 0, 32); return ERROR_OK; } int target_rtt_start(struct target *target, const struct rtt_control *ctrl, void *user_data) { return ERROR_OK; } int target_rtt_stop(struct target *target, void *user_data) { return ERROR_OK; } static int read_channel_name(struct target *target, target_addr_t address, char *name, size_t length) { size_t offset; offset = 0; while (offset < length) { int ret; size_t read_length; read_length = MIN(32, length - offset); ret = target_read_buffer(target, address + offset, read_length, (uint8_t *)name + offset); if (ret != ERROR_OK) return ret; if (memchr(name + offset, '\0', read_length)) return ERROR_OK; offset += read_length; } name[length - 1] = '\0'; return ERROR_OK; } static int write_to_channel(struct target *target, const struct rtt_channel *channel, const uint8_t *buffer, size_t *length) { int ret; uint32_t len; if (!*length) return ERROR_OK; if (channel->write_pos == channel->read_pos) { uint32_t first_length; len = MIN(*length, channel->size - 1); first_length = MIN(len, channel->size - channel->write_pos); ret = target_write_buffer(target, channel->buffer_addr + channel->write_pos, first_length, buffer); if (ret != ERROR_OK) return ret; ret = target_write_buffer(target, channel->buffer_addr, len - first_length, buffer + first_length); if (ret != ERROR_OK) return ret; } else if (channel->write_pos < channel->read_pos) { len = MIN(*length, channel->read_pos - channel->write_pos - 1); if (!len) { *length = 0; return ERROR_OK; } ret = target_write_buffer(target, channel->buffer_addr + channel->write_pos, len, buffer); if (ret != ERROR_OK) return ret; } else { uint32_t first_length; len = MIN(*length, channel->size - channel->write_pos + channel->read_pos - 1); if (!len) { *length = 0; return ERROR_OK; } first_length = MIN(len, channel->size - channel->write_pos); ret = target_write_buffer(target, channel->buffer_addr + channel->write_pos, first_length, buffer); if (ret != ERROR_OK) return ret; buffer = buffer + first_length; ret = target_write_buffer(target, channel->buffer_addr, len - first_length, buffer); if (ret != ERROR_OK) return ret; } ret = target_write_u32(target, channel->address + 12, (channel->write_pos + len) % channel->size); if (ret != ERROR_OK) return ret; *length = len; return ERROR_OK; } static bool channel_is_active(const struct rtt_channel *channel) { if (!channel) return false; if (!channel->size) return false; return true; } int target_rtt_write_callback(struct target *target, struct rtt_control *ctrl, unsigned int channel_index, const uint8_t *buffer, size_t *length, void *user_data) { int ret; struct rtt_channel channel; ret = read_rtt_channel(target, ctrl, channel_index, RTT_CHANNEL_TYPE_DOWN, &channel); if (ret != ERROR_OK) { LOG_ERROR("rtt: Failed to read down-channel %u description", channel_index); return ret; } if (!channel_is_active(&channel)) { LOG_WARNING("rtt: Down-channel %u is not active", channel_index); return ERROR_OK; } if (channel.size < RTT_CHANNEL_BUFFER_MIN_SIZE) { LOG_WARNING("rtt: Down-channel %u is not large enough", channel_index); return ERROR_OK; } ret = write_to_channel(target, &channel, buffer, length); if (ret != ERROR_OK) return ret; LOG_DEBUG("rtt: Wrote %zu bytes into down-channel %u", *length, channel_index); return ERROR_OK; } int target_rtt_read_control_block(struct target *target, target_addr_t address, struct rtt_control *ctrl, void *user_data) { int ret; uint8_t buf[RTT_CB_SIZE]; ret = target_read_buffer(target, address, RTT_CB_SIZE, buf); if (ret != ERROR_OK) return ret; memcpy(ctrl->id, buf, RTT_CB_MAX_ID_LENGTH); ctrl->id[RTT_CB_MAX_ID_LENGTH - 1] = '\0'; ctrl->num_up_channels = buf_get_u32(buf + RTT_CB_MAX_ID_LENGTH + 0, 0, 32); ctrl->num_down_channels = buf_get_u32(buf + RTT_CB_MAX_ID_LENGTH + 4, 0, 32); return ERROR_OK; } int target_rtt_find_control_block(struct target *target, target_addr_t *address, size_t size, const char *id, bool *found, void *user_data) { target_addr_t address_end = *address + size; uint8_t buf[1024]; *found = false; size_t id_matched_length = 0; const size_t id_length = strlen(id); LOG_INFO("rtt: Searching for control block '%s'", id); for (target_addr_t addr = *address; addr < address_end; addr += sizeof(buf)) { int ret; const size_t buf_size = MIN(sizeof(buf), address_end - addr); ret = target_read_buffer(target, addr, buf_size, buf); if (ret != ERROR_OK) return ret; for (size_t buf_off = 0; buf_off < buf_size; buf_off++) { if (id_matched_length > 0 && buf[buf_off] != id[id_matched_length]) { /* Start from beginning */ id_matched_length = 0; } if (buf[buf_off] == id[id_matched_length]) id_matched_length++; if (id_matched_length == id_length) { *address = addr + buf_off + 1 - id_length; *found = true; return ERROR_OK; } } } return ERROR_OK; } int target_rtt_read_channel_info(struct target *target, const struct rtt_control *ctrl, unsigned int channel_index, enum rtt_channel_type type, struct rtt_channel_info *info, void *user_data) { int ret; struct rtt_channel channel; ret = read_rtt_channel(target, ctrl, channel_index, type, &channel); if (ret != ERROR_OK) { LOG_ERROR("rtt: Failed to read channel %u description", channel_index); return ret; } ret = read_channel_name(target, channel.name_addr, info->name, info->name_length); if (ret != ERROR_OK) return ret; info->size = channel.size; info->flags = channel.flags; return ERROR_OK; } static int read_from_channel(struct target *target, const struct rtt_channel *channel, uint8_t *buffer, size_t *length) { int ret; uint32_t len; if (!*length) return ERROR_OK; if (channel->read_pos == channel->write_pos) { len = 0; } else if (channel->read_pos < channel->write_pos) { len = MIN(*length, channel->write_pos - channel->read_pos); ret = target_read_buffer(target, channel->buffer_addr + channel->read_pos, len, buffer); if (ret != ERROR_OK) return ret; } else { uint32_t first_length; len = MIN(*length, channel->size - channel->read_pos + channel->write_pos); first_length = MIN(len, channel->size - channel->read_pos); ret = target_read_buffer(target, channel->buffer_addr + channel->read_pos, first_length, buffer); if (ret != ERROR_OK) return ret; ret = target_read_buffer(target, channel->buffer_addr, len - first_length, buffer + first_length); if (ret != ERROR_OK) return ret; } if (len > 0) { ret = target_write_u32(target, channel->address + 16, (channel->read_pos + len) % channel->size); if (ret != ERROR_OK) return ret; } *length = len; return ERROR_OK; } int target_rtt_read_callback(struct target *target, const struct rtt_control *ctrl, struct rtt_sink_list **sinks, size_t num_channels, void *user_data) { num_channels = MIN(num_channels, ctrl->num_up_channels); for (size_t i = 0; i < num_channels; i++) { int ret; struct rtt_channel channel; uint8_t buffer[1024]; size_t length; if (!sinks[i]) continue; ret = read_rtt_channel(target, ctrl, i, RTT_CHANNEL_TYPE_UP, &channel); if (ret != ERROR_OK) { LOG_ERROR("rtt: Failed to read up-channel %zu description", i); return ret; } if (!channel_is_active(&channel)) { LOG_WARNING("rtt: Up-channel %zu is not active", i); continue; } if (channel.size < RTT_CHANNEL_BUFFER_MIN_SIZE) { LOG_WARNING("rtt: Up-channel %zu is not large enough", i); continue; } length = sizeof(buffer); ret = read_from_channel(target, &channel, buffer, &length); if (ret != ERROR_OK) { LOG_ERROR("rtt: Failed to read from up-channel %zu", i); return ret; } for (struct rtt_sink_list *sink = sinks[i]; sink; sink = sink->next) sink->read(i, buffer, length, sink->user_data); } return ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/rtt.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de> */ #ifndef OPENOCD_TARGET_RTT_H #define OPENOCD_TARGET_RTT_H #include <stdint.h> #include <stdbool.h> #include <target/target.h> #include <rtt/rtt.h> int target_rtt_start(struct target *target, const struct rtt_control *ctrl, void *user_data); int target_rtt_stop(struct target *target, void *user_data); int target_rtt_find_control_block(struct target *target, target_addr_t *address, size_t size, const char *id, bool *found, void *user_data); int target_rtt_read_control_block(struct target *target, target_addr_t address, struct rtt_control *ctrl, void *user_data); int target_rtt_write_callback(struct target *target, struct rtt_control *ctrl, unsigned int channel_index, const uint8_t *buffer, size_t *length, void *user_data); int target_rtt_read_callback(struct target *target, const struct rtt_control *ctrl, struct rtt_sink_list **sinks, size_t length, void *user_data); int target_rtt_read_channel_info(struct target *target, const struct rtt_control *ctrl, unsigned int channel_index, enum rtt_channel_type type, struct rtt_channel_info *info, void *user_data); #endif /* OPENOCD_TARGET_RTT_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/semihosting_common.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2018 by Liviu Ionescu * * <ilg@livius.net> * * * * Copyright (C) 2018 by Marvell Technology Group Ltd. * * Written by Nicolas Pitre <nico@marvell.com> * * * * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2016 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * ***************************************************************************/ /** * @file * Common ARM semihosting support. * * Semihosting enables code running on a target to use some of the I/O * facilities on the host computer. The target application must be linked * against a library that forwards operation requests by using an * instruction trapped by the debugger. * * Details can be found in * "Semihosting for AArch32 and AArch64, Release 2.0" * https://static.docs.arm.com/100863/0200/semihosting.pdf * from ARM Ltd. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include "target_type.h" #include "semihosting_common.h" #include <helper/binarybuffer.h> #include <helper/log.h> #include <server/gdb_server.h> #include <sys/stat.h> /** * It is not possible to use O_... flags defined in sys/stat.h because they * are not guaranteed to match the values defined by the GDB Remote Protocol. * See https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags */ enum { TARGET_O_RDONLY = 0x000, TARGET_O_WRONLY = 0x001, TARGET_O_RDWR = 0x002, TARGET_O_APPEND = 0x008, TARGET_O_CREAT = 0x200, TARGET_O_TRUNC = 0x400, /* O_EXCL=0x800 is not required in this implementation. */ }; /* GDB remote protocol does not differentiate between text and binary open modes. */ static const int open_gdb_modeflags[12] = { TARGET_O_RDONLY, TARGET_O_RDONLY, TARGET_O_RDWR, TARGET_O_RDWR, TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC, TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC, TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC, TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC, TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND, TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND, TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND, TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND }; static const int open_host_modeflags[12] = { O_RDONLY, O_RDONLY | O_BINARY, O_RDWR, O_RDWR | O_BINARY, O_WRONLY | O_CREAT | O_TRUNC, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, O_RDWR | O_CREAT | O_TRUNC, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, O_WRONLY | O_CREAT | O_APPEND, O_WRONLY | O_CREAT | O_APPEND | O_BINARY, O_RDWR | O_CREAT | O_APPEND, O_RDWR | O_CREAT | O_APPEND | O_BINARY }; static int semihosting_common_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info); static int semihosting_common_fileio_end(struct target *target, int result, int fileio_errno, bool ctrl_c); /** * Initialize common semihosting support. * * @param target Pointer to the target to initialize. * @param setup * @param post_result * @return An error status if there is a problem during initialization. */ int semihosting_common_init(struct target *target, void *setup, void *post_result) { LOG_DEBUG(" "); target->fileio_info = malloc(sizeof(*target->fileio_info)); if (!target->fileio_info) { LOG_ERROR("out of memory"); return ERROR_FAIL; } memset(target->fileio_info, 0, sizeof(*target->fileio_info)); struct semihosting *semihosting; semihosting = malloc(sizeof(*target->semihosting)); if (!semihosting) { LOG_ERROR("out of memory"); return ERROR_FAIL; } semihosting->is_active = false; semihosting->redirect_cfg = SEMIHOSTING_REDIRECT_CFG_NONE; semihosting->tcp_connection = NULL; semihosting->stdin_fd = -1; semihosting->stdout_fd = -1; semihosting->stderr_fd = -1; semihosting->is_fileio = false; semihosting->hit_fileio = false; semihosting->is_resumable = false; semihosting->has_resumable_exit = false; semihosting->word_size_bytes = 0; semihosting->op = -1; semihosting->param = 0; semihosting->result = -1; semihosting->sys_errno = -1; semihosting->cmdline = NULL; semihosting->basedir = NULL; /* If possible, update it in setup(). */ semihosting->setup_time = clock(); semihosting->setup = setup; semihosting->post_result = post_result; semihosting->user_command_extension = NULL; target->semihosting = semihosting; target->type->get_gdb_fileio_info = semihosting_common_fileio_info; target->type->gdb_fileio_end = semihosting_common_fileio_end; return ERROR_OK; } struct semihosting_tcp_service { struct semihosting *semihosting; char *name; int error; }; static bool semihosting_is_redirected(struct semihosting *semihosting, int fd) { if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_NONE) return false; bool is_read_op = false; switch (semihosting->op) { /* check debug semihosting operations: READC, WRITEC and WRITE0 */ case SEMIHOSTING_SYS_READC: is_read_op = true; /* fall through */ case SEMIHOSTING_SYS_WRITEC: case SEMIHOSTING_SYS_WRITE0: /* debug operations are redirected when CFG is either DEBUG or ALL */ if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_STDIO) return false; break; /* check stdio semihosting operations: READ and WRITE */ case SEMIHOSTING_SYS_READ: is_read_op = true; /* fall through */ case SEMIHOSTING_SYS_WRITE: /* stdio operations are redirected when CFG is either STDIO or ALL */ if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_DEBUG) return false; break; default: return false; } if (is_read_op) return fd == semihosting->stdin_fd; /* write operation */ return fd == semihosting->stdout_fd || fd == semihosting->stderr_fd; } static ssize_t semihosting_redirect_write(struct semihosting *semihosting, void *buf, int size) { if (!semihosting->tcp_connection) { LOG_ERROR("No connected TCP client for semihosting"); semihosting->sys_errno = EBADF; /* Bad file number */ return -1; } struct semihosting_tcp_service *service = semihosting->tcp_connection->service->priv; int retval = connection_write(semihosting->tcp_connection, buf, size); if (retval < 0) log_socket_error(service->name); return retval; } static ssize_t semihosting_write(struct semihosting *semihosting, int fd, void *buf, int size) { if (semihosting_is_redirected(semihosting, fd)) return semihosting_redirect_write(semihosting, buf, size); /* default write */ int result = write(fd, buf, size); if (result == -1) semihosting->sys_errno = errno; return result; } static ssize_t semihosting_redirect_read(struct semihosting *semihosting, void *buf, int size) { if (!semihosting->tcp_connection) { LOG_ERROR("No connected TCP client for semihosting"); semihosting->sys_errno = EBADF; /* Bad file number */ return -1; } struct semihosting_tcp_service *service = semihosting->tcp_connection->service->priv; service->error = ERROR_OK; semihosting->tcp_connection->input_pending = true; int retval = connection_read(semihosting->tcp_connection, buf, size); if (retval <= 0) service->error = ERROR_SERVER_REMOTE_CLOSED; if (retval < 0) log_socket_error(service->name); semihosting->tcp_connection->input_pending = false; return retval; } static inline int semihosting_putchar(struct semihosting *semihosting, int fd, int c) { if (semihosting_is_redirected(semihosting, fd)) return semihosting_redirect_write(semihosting, &c, 1); /* default putchar */ return putchar(c); } static inline ssize_t semihosting_read(struct semihosting *semihosting, int fd, void *buf, int size) { if (semihosting_is_redirected(semihosting, fd)) return semihosting_redirect_read(semihosting, buf, size); /* default read */ ssize_t result = read(fd, buf, size); if (result == -1) semihosting->sys_errno = errno; return result; } static inline int semihosting_getchar(struct semihosting *semihosting, int fd) { if (semihosting_is_redirected(semihosting, fd)) { unsigned char c; if (semihosting_redirect_read(semihosting, &c, 1) > 0) return c; return EOF; } /* default getchar */ return getchar(); } /** * User operation parameter string storage buffer. Contains valid data when the * TARGET_EVENT_SEMIHOSTING_USER_CMD_xxxxx event callbacks are running. */ static char *semihosting_user_op_params; const char *semihosting_opcode_to_str(const uint64_t opcode) { switch (opcode) { case SEMIHOSTING_SYS_CLOSE: return "CLOSE"; case SEMIHOSTING_SYS_CLOCK: return "CLOCK"; case SEMIHOSTING_SYS_ELAPSED: return "ELAPSED"; case SEMIHOSTING_SYS_ERRNO: return "ERRNO"; case SEMIHOSTING_SYS_EXIT: return "EXIT"; case SEMIHOSTING_SYS_EXIT_EXTENDED: return "EXIT_EXTENDED"; case SEMIHOSTING_SYS_FLEN: return "FLEN"; case SEMIHOSTING_SYS_GET_CMDLINE: return "GET_CMDLINE"; case SEMIHOSTING_SYS_HEAPINFO: return "HEAPINFO"; case SEMIHOSTING_SYS_ISERROR: return "ISERROR"; case SEMIHOSTING_SYS_ISTTY: return "ISTTY"; case SEMIHOSTING_SYS_OPEN: return "OPEN"; case SEMIHOSTING_SYS_READ: return "READ"; case SEMIHOSTING_SYS_READC: return "READC"; case SEMIHOSTING_SYS_REMOVE: return "REMOVE"; case SEMIHOSTING_SYS_RENAME: return "RENAME"; case SEMIHOSTING_SYS_SEEK: return "SEEK"; case SEMIHOSTING_SYS_SYSTEM: return "SYSTEM"; case SEMIHOSTING_SYS_TICKFREQ: return "TICKFREQ"; case SEMIHOSTING_SYS_TIME: return "TIME"; case SEMIHOSTING_SYS_TMPNAM: return "TMPNAM"; case SEMIHOSTING_SYS_WRITE: return "WRITE"; case SEMIHOSTING_SYS_WRITEC: return "WRITEC"; case SEMIHOSTING_SYS_WRITE0: return "WRITE0"; case SEMIHOSTING_USER_CMD_0X100 ... SEMIHOSTING_USER_CMD_0X1FF: return "USER_CMD"; case SEMIHOSTING_ARM_RESERVED_START ... SEMIHOSTING_ARM_RESERVED_END: return "ARM_RESERVED_CMD"; default: return "<unknown>"; } } /** * Portable implementation of ARM semihosting calls. * Performs the currently pending semihosting operation * encoded in target->semihosting. */ int semihosting_common(struct target *target) { struct semihosting *semihosting = target->semihosting; if (!semihosting) { /* Silently ignore if the semihosting field was not set. */ return ERROR_OK; } struct gdb_fileio_info *fileio_info = target->fileio_info; /* * By default return an error. * The actual result must be set by each function */ semihosting->result = -1; /* Most operations are resumable, except the two exit calls. */ semihosting->is_resumable = true; int retval; /* Enough space to hold 4 long words. */ uint8_t fields[4*8]; LOG_DEBUG("op=0x%x (%s), param=0x%" PRIx64, semihosting->op, semihosting_opcode_to_str(semihosting->op), semihosting->param); switch (semihosting->op) { case SEMIHOSTING_SYS_CLOCK: /* 0x10 */ /* * Returns the number of centiseconds (hundredths of a second) * since the execution started. * * Values returned can be of limited use for some benchmarking * purposes because of communication overhead or other * agent-specific factors. For example, with a debug hardware * unit the request is passed back to the host for execution. * This can lead to unpredictable delays in transmission and * process scheduling. * * Use this function to calculate time intervals, by calculating * differences between intervals with and without the code * sequence to be timed. * * Entry * The PARAMETER REGISTER must contain 0. There are no other * parameters. * * Return * On exit, the RETURN REGISTER contains: * - The number of centiseconds since some arbitrary start * point, if the call is successful. * - –1 if the call is not successful. For example, because * of a communications error. */ { clock_t delta = clock() - semihosting->setup_time; semihosting->result = delta / (CLOCKS_PER_SEC / 100); } break; case SEMIHOSTING_SYS_CLOSE: /* 0x02 */ /* * Closes a file on the host system. The handle must reference * a file that was opened with SYS_OPEN. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a * one-field argument block: * - field 1 Contains a handle for an open file. * * Return * On exit, the RETURN REGISTER contains: * - 0 if the call is successful * - –1 if the call is not successful. */ retval = semihosting_read_fields(target, 1, fields); if (retval != ERROR_OK) return retval; else { int fd = semihosting_get_field(target, 0, fields); /* Do not allow to close OpenOCD's own standard streams */ if (fd == 0 || fd == 1 || fd == 2) { LOG_DEBUG("ignoring semihosting attempt to close %s", (fd == 0) ? "stdin" : (fd == 1) ? "stdout" : "stderr"); /* Just pretend success */ semihosting->result = 0; break; } /* Close the descriptor */ if (semihosting->is_fileio) { semihosting->hit_fileio = true; fileio_info->identifier = "close"; fileio_info->param_1 = fd; } else { semihosting->result = close(fd); if (semihosting->result == -1) semihosting->sys_errno = errno; LOG_DEBUG("close(%d)=%" PRId64, fd, semihosting->result); } } break; case SEMIHOSTING_SYS_ERRNO: /* 0x13 */ /* * Returns the value of the C library errno variable that is * associated with the semihosting implementation. The errno * variable can be set by a number of C library semihosted * functions, including: * - SYS_REMOVE * - SYS_OPEN * - SYS_CLOSE * - SYS_READ * - SYS_WRITE * - SYS_SEEK. * * Whether errno is set or not, and to what value, is entirely * host-specific, except where the ISO C standard defines the * behavior. * * Entry * There are no parameters. The PARAMETER REGISTER must be 0. * * Return * On exit, the RETURN REGISTER contains the value of the C * library errno variable. */ semihosting->result = semihosting->sys_errno; break; case SEMIHOSTING_SYS_EXIT: /* 0x18 */ /* * Note: SYS_EXIT was called angel_SWIreason_ReportException in * previous versions of the documentation. * * An application calls this operation to report an exception * to the debugger directly. The most common use is to report * that execution has completed, using ADP_Stopped_ApplicationExit. * * Note: This semihosting operation provides no means for 32-bit * callers to indicate an application exit with a specified exit * code. Semihosting callers may prefer to check for the presence * of the SH_EXT_EXTENDED_REPORT_EXCEPTION extension and use * the SYS_REPORT_EXCEPTION_EXTENDED operation instead, if it * is available. * * Entry (32-bit) * On entry, the PARAMETER register is set to a reason code * describing the cause of the trap. Not all semihosting client * implementations will necessarily trap every corresponding * event. Important reason codes are: * * - ADP_Stopped_ApplicationExit 0x20026 * - ADP_Stopped_RunTimeErrorUnknown 0x20023 * * Entry (64-bit) * On entry, the PARAMETER REGISTER contains a pointer to a * two-field argument block: * - field 1 The exception type, which is one of the set of * reason codes in the above tables. * - field 2 A subcode, whose meaning depends on the reason * code in field 1. * In particular, if field 1 is ADP_Stopped_ApplicationExit * then field 2 is an exit status code, as passed to the C * standard library exit() function. A simulator receiving * this request must notify a connected debugger, if present, * and then exit with the specified status. * * Return * No return is expected from these calls. However, it is * possible for the debugger to request that the application * continues by performing an RDI_Execute request or equivalent. * In this case, execution continues with the registers as they * were on entry to the operation, or as subsequently modified * by the debugger. */ if (semihosting->word_size_bytes == 8) { retval = semihosting_read_fields(target, 2, fields); if (retval != ERROR_OK) return retval; else { int type = semihosting_get_field(target, 0, fields); int code = semihosting_get_field(target, 1, fields); if (type == ADP_STOPPED_APPLICATION_EXIT) { if (!gdb_get_actual_connections()) exit(code); else { fprintf(stderr, "semihosting: *** application exited with %d ***\n", code); } } else { fprintf(stderr, "semihosting: application exception %#x\n", type); } } } else { if (semihosting->param == ADP_STOPPED_APPLICATION_EXIT) { if (!gdb_get_actual_connections()) exit(0); else { fprintf(stderr, "semihosting: *** application exited normally ***\n"); } } else if (semihosting->param == ADP_STOPPED_RUN_TIME_ERROR) { /* Chosen more or less arbitrarily to have a nicer message, * otherwise all other return the same exit code 1. */ if (!gdb_get_actual_connections()) exit(1); else { fprintf(stderr, "semihosting: *** application exited with error ***\n"); } } else { if (!gdb_get_actual_connections()) exit(1); else { fprintf(stderr, "semihosting: application exception %#x\n", (unsigned) semihosting->param); } } } if (!semihosting->has_resumable_exit) { semihosting->is_resumable = false; return target_call_event_callbacks(target, TARGET_EVENT_HALTED); } break; case SEMIHOSTING_SYS_EXIT_EXTENDED: /* 0x20 */ /* * This operation is only supported if the semihosting extension * SH_EXT_EXIT_EXTENDED is implemented. SH_EXT_EXIT_EXTENDED is * reported using feature byte 0, bit 0. If this extension is * supported, then the implementation provides a means to * report a normal exit with a nonzero exit status in both 32-bit * and 64-bit semihosting APIs. * * The implementation must provide the semihosting call * SYS_EXIT_EXTENDED for both A64 and A32/T32 semihosting APIs. * * SYS_EXIT_EXTENDED is used by an application to report an * exception or exit to the debugger directly. The most common * use is to report that execution has completed, using * ADP_Stopped_ApplicationExit. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a * two-field argument block: * - field 1 The exception type, which should be one of the set * of reason codes that are documented for the SYS_EXIT * (0x18) call. For example, ADP_Stopped_ApplicationExit. * - field 2 A subcode, whose meaning depends on the reason * code in field 1. In particular, if field 1 is * ADP_Stopped_ApplicationExit then field 2 is an exit status * code, as passed to the C standard library exit() function. * A simulator receiving this request must notify a connected * debugger, if present, and then exit with the specified status. * * Return * No return is expected from these calls. * * For the A64 API, this call is identical to the behavior of * the mandatory SYS_EXIT (0x18) call. If this extension is * supported, then both calls must be implemented. */ retval = semihosting_read_fields(target, 2, fields); if (retval != ERROR_OK) return retval; else { int type = semihosting_get_field(target, 0, fields); int code = semihosting_get_field(target, 1, fields); if (type == ADP_STOPPED_APPLICATION_EXIT) { if (!gdb_get_actual_connections()) exit(code); else { fprintf(stderr, "semihosting: *** application exited with %d ***\n", code); } } else { fprintf(stderr, "semihosting: exception %#x\n", type); } } if (!semihosting->has_resumable_exit) { semihosting->is_resumable = false; return target_call_event_callbacks(target, TARGET_EVENT_HALTED); } break; case SEMIHOSTING_SYS_FLEN: /* 0x0C */ /* * Returns the length of a specified file. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a * one-field argument block: * - field 1 A handle for a previously opened, seekable file * object. * * Return * On exit, the RETURN REGISTER contains: * - The current length of the file object, if the call is * successful. * - –1 if an error occurs. */ if (semihosting->is_fileio) { semihosting->result = -1; semihosting->sys_errno = EINVAL; } retval = semihosting_read_fields(target, 1, fields); if (retval != ERROR_OK) return retval; else { int fd = semihosting_get_field(target, 0, fields); struct stat buf; semihosting->result = fstat(fd, &buf); if (semihosting->result == -1) { semihosting->sys_errno = errno; LOG_DEBUG("fstat(%d)=%" PRId64, fd, semihosting->result); break; } LOG_DEBUG("fstat(%d)=%" PRId64, fd, semihosting->result); semihosting->result = buf.st_size; } break; case SEMIHOSTING_SYS_GET_CMDLINE: /* 0x15 */ /* * Returns the command line that is used for the call to the * executable, that is, argc and argv. * * Entry * On entry, the PARAMETER REGISTER points to a two-field data * block to be used for returning the command string and its length: * - field 1 A pointer to a buffer of at least the size that is * specified in field 2. * - field 2 The length of the buffer in bytes. * * Return * On exit: * If the call is successful, then the RETURN REGISTER contains 0, * the PARAMETER REGISTER is unchanged, and the data block is * updated as follows: * - field 1 A pointer to a null-terminated string of the command * line. * - field 2 The length of the string in bytes. * If the call is not successful, then the RETURN REGISTER * contains -1. * * Note: The semihosting implementation might impose limits on * the maximum length of the string that can be transferred. * However, the implementation must be able to support a * command-line length of at least 80 bytes. */ retval = semihosting_read_fields(target, 2, fields); if (retval != ERROR_OK) return retval; else { uint64_t addr = semihosting_get_field(target, 0, fields); size_t size = semihosting_get_field(target, 1, fields); char *arg = semihosting->cmdline ? semihosting->cmdline : ""; uint32_t len = strlen(arg) + 1; if (len > size) semihosting->result = -1; else { semihosting_set_field(target, len, 1, fields); retval = target_write_buffer(target, addr, len, (uint8_t *)arg); if (retval != ERROR_OK) return retval; semihosting->result = 0; retval = semihosting_write_fields(target, 2, fields); if (retval != ERROR_OK) return retval; } LOG_DEBUG("SYS_GET_CMDLINE=[%s], %" PRId64, arg, semihosting->result); } break; case SEMIHOSTING_SYS_HEAPINFO: /* 0x16 */ /* * Returns the system stack and heap parameters. * * Entry * On entry, the PARAMETER REGISTER contains the address of a * pointer to a four-field data block. The contents of the data * block are filled by the function. The following C-like * pseudocode describes the layout of the block: * struct block { * void* heap_base; * void* heap_limit; * void* stack_base; * void* stack_limit; * }; * * Return * On exit, the PARAMETER REGISTER is unchanged and the data * block has been updated. */ retval = semihosting_read_fields(target, 1, fields); if (retval != ERROR_OK) return retval; else { uint64_t addr = semihosting_get_field(target, 0, fields); /* tell the remote we have no idea */ memset(fields, 0, 4 * semihosting->word_size_bytes); retval = target_write_memory(target, addr, 4, semihosting->word_size_bytes, fields); if (retval != ERROR_OK) return retval; semihosting->result = 0; } break; case SEMIHOSTING_SYS_ISERROR: /* 0x08 */ /* * Determines whether the return code from another semihosting * call is an error status or not. * * This call is passed a parameter block containing the error * code to examine. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a * one-field data block: * - field 1 The required status word to check. * * Return * On exit, the RETURN REGISTER contains: * - 0 if the status field is not an error indication * - A nonzero value if the status field is an error indication. */ retval = semihosting_read_fields(target, 1, fields); if (retval != ERROR_OK) return retval; uint64_t code = semihosting_get_field(target, 0, fields); semihosting->result = (code != 0); break; case SEMIHOSTING_SYS_ISTTY: /* 0x09 */ /* * Checks whether a file is connected to an interactive device. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a * one-field argument block: * field 1 A handle for a previously opened file object. * * Return * On exit, the RETURN REGISTER contains: * - 1 if the handle identifies an interactive device. * - 0 if the handle identifies a file. * - A value other than 1 or 0 if an error occurs. */ if (semihosting->is_fileio) { semihosting->hit_fileio = true; fileio_info->identifier = "isatty"; fileio_info->param_1 = semihosting->param; } else { retval = semihosting_read_fields(target, 1, fields); if (retval != ERROR_OK) return retval; int fd = semihosting_get_field(target, 0, fields); // isatty() on Windows may return any non-zero value if fd is a terminal semihosting->result = isatty(fd) ? 1 : 0; if (semihosting->result == 0) semihosting->sys_errno = errno; LOG_DEBUG("isatty(%d)=%" PRId64, fd, semihosting->result); } break; case SEMIHOSTING_SYS_OPEN: /* 0x01 */ /* * Opens a file on the host system. * * The file path is specified either as relative to the current * directory of the host process, or absolute, using the path * conventions of the host operating system. * * Semihosting implementations must support opening the special * path name :semihosting-features as part of the semihosting * extensions reporting mechanism. * * ARM targets interpret the special path name :tt as meaning * the console input stream, for an open-read or the console * output stream, for an open-write. Opening these streams is * performed as part of the standard startup code for those * applications that reference the C stdio streams. The * semihosting extension SH_EXT_STDOUT_STDERR allows the * semihosting caller to open separate output streams * corresponding to stdout and stderr. This extension is * reported using feature byte 0, bit 1. Use SYS_OPEN with * the special path name :semihosting-features to access the * feature bits. * * If this extension is supported, the implementation must * support the following additional semantics to SYS_OPEN: * - If the special path name :tt is opened with an fopen * mode requesting write access (w, wb, w+, or w+b), then * this is a request to open stdout. * - If the special path name :tt is opened with a mode * requesting append access (a, ab, a+, or a+b), then this is * a request to open stderr. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a * three-field argument block: * - field 1 A pointer to a null-terminated string containing * a file or device name. * - field 2 An integer that specifies the file opening mode. * - field 3 An integer that gives the length of the string * pointed to by field 1. * * The length does not include the terminating null character * that must be present. * * Return * On exit, the RETURN REGISTER contains: * - A nonzero handle if the call is successful. * - –1 if the call is not successful. */ retval = semihosting_read_fields(target, 3, fields); if (retval != ERROR_OK) return retval; else { uint64_t addr = semihosting_get_field(target, 0, fields); uint32_t mode = semihosting_get_field(target, 1, fields); size_t len = semihosting_get_field(target, 2, fields); if (mode > 11) { semihosting->result = -1; semihosting->sys_errno = EINVAL; break; } size_t basedir_len = semihosting->basedir ? strlen(semihosting->basedir) : 0; uint8_t *fn = malloc(basedir_len + len + 2); if (!fn) { semihosting->result = -1; semihosting->sys_errno = ENOMEM; } else { if (basedir_len > 0) { strcpy((char *)fn, semihosting->basedir); if (fn[basedir_len - 1] != '/') fn[basedir_len++] = '/'; } retval = target_read_memory(target, addr, 1, len, fn + basedir_len); if (retval != ERROR_OK) { free(fn); return retval; } fn[basedir_len + len] = 0; /* TODO: implement the :semihosting-features special file. * */ if (semihosting->is_fileio) { if (strcmp((char *)fn, ":semihosting-features") == 0) { semihosting->result = -1; semihosting->sys_errno = EINVAL; } else if (strcmp((char *)fn, ":tt") == 0) { if (mode == 0) { semihosting->result = 0; } else if (mode == 4) { semihosting->result = 1; } else if (mode == 8) { semihosting->result = 2; } else { semihosting->result = -1; semihosting->sys_errno = EINVAL; } } else { semihosting->hit_fileio = true; fileio_info->identifier = "open"; fileio_info->param_1 = addr; fileio_info->param_2 = len; fileio_info->param_3 = open_gdb_modeflags[mode]; fileio_info->param_4 = 0644; } } else { if (strcmp((char *)fn, ":tt") == 0) { /* Mode is: * - 0-3 ("r") for stdin, * - 4-7 ("w") for stdout, * - 8-11 ("a") for stderr */ int fd; if (mode < 4) { fd = dup(STDIN_FILENO); semihosting->stdin_fd = fd; LOG_DEBUG("dup(STDIN)=%d", fd); } else if (mode < 8) { fd = dup(STDOUT_FILENO); semihosting->stdout_fd = fd; LOG_DEBUG("dup(STDOUT)=%d", fd); } else { fd = dup(STDERR_FILENO); semihosting->stderr_fd = fd; LOG_DEBUG("dup(STDERR)=%d", fd); } semihosting->result = fd; if (fd == -1) semihosting->sys_errno = errno; } else { /* cygwin requires the permission setting * otherwise it will fail to reopen a previously * written file */ semihosting->result = open((char *)fn, open_host_modeflags[mode], 0644); if (semihosting->result == -1) semihosting->sys_errno = errno; LOG_DEBUG("open('%s')=%" PRId64, fn, semihosting->result); } } free(fn); } } break; case SEMIHOSTING_SYS_READ: /* 0x06 */ /* * Reads the contents of a file into a buffer. The file position * is specified either: * - Explicitly by a SYS_SEEK. * - Implicitly one byte beyond the previous SYS_READ or * SYS_WRITE request. * * The file position is at the start of the file when it is * opened, and is lost when the file is closed. Perform the * file operation as a single action whenever possible. For * example, do not split a read of 16KB into four 4KB chunks * unless there is no alternative. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a * three-field data block: * - field 1 Contains a handle for a file previously opened * with SYS_OPEN. * - field 2 Points to a buffer. * - field 3 Contains the number of bytes to read to the buffer * from the file. * * Return * On exit, the RETURN REGISTER contains the number of bytes not * filled in the buffer (buffer_length - bytes_read) as follows: * - If the RETURN REGISTER is 0, the entire buffer was * successfully filled. * - If the RETURN REGISTER is the same as field 3, no bytes * were read (EOF can be assumed). * - If the RETURN REGISTER contains a value smaller than * field 3, the read succeeded but the buffer was only partly * filled. For interactive devices, this is the most common * return value. */ retval = semihosting_read_fields(target, 3, fields); if (retval != ERROR_OK) return retval; else { int fd = semihosting_get_field(target, 0, fields); uint64_t addr = semihosting_get_field(target, 1, fields); size_t len = semihosting_get_field(target, 2, fields); if (semihosting->is_fileio) { semihosting->hit_fileio = true; fileio_info->identifier = "read"; fileio_info->param_1 = fd; fileio_info->param_2 = addr; fileio_info->param_3 = len; } else { uint8_t *buf = malloc(len); if (!buf) { semihosting->result = -1; semihosting->sys_errno = ENOMEM; } else { semihosting->result = semihosting_read(semihosting, fd, buf, len); LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%" PRId64, fd, addr, len, semihosting->result); if (semihosting->result >= 0) { retval = target_write_buffer(target, addr, semihosting->result, buf); if (retval != ERROR_OK) { free(buf); return retval; } /* the number of bytes NOT filled in */ semihosting->result = len - semihosting->result; } free(buf); } } } break; case SEMIHOSTING_SYS_READC: /* 0x07 */ /* * Reads a byte from the console. * * Entry * The PARAMETER REGISTER must contain 0. There are no other * parameters or values possible. * * Return * On exit, the RETURN REGISTER contains the byte read from * the console. */ if (semihosting->is_fileio) { LOG_ERROR("SYS_READC not supported by semihosting fileio"); return ERROR_FAIL; } semihosting->result = semihosting_getchar(semihosting, semihosting->stdin_fd); LOG_DEBUG("getchar()=%" PRId64, semihosting->result); break; case SEMIHOSTING_SYS_REMOVE: /* 0x0E */ /* * Deletes a specified file on the host filing system. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a * two-field argument block: * - field 1 Points to a null-terminated string that gives the * path name of the file to be deleted. * - field 2 The length of the string. * * Return * On exit, the RETURN REGISTER contains: * - 0 if the delete is successful * - A nonzero, host-specific error code if the delete fails. */ retval = semihosting_read_fields(target, 2, fields); if (retval != ERROR_OK) return retval; else { uint64_t addr = semihosting_get_field(target, 0, fields); size_t len = semihosting_get_field(target, 1, fields); if (semihosting->is_fileio) { semihosting->hit_fileio = true; fileio_info->identifier = "unlink"; fileio_info->param_1 = addr; fileio_info->param_2 = len; } else { uint8_t *fn = malloc(len+1); if (!fn) { semihosting->result = -1; semihosting->sys_errno = ENOMEM; } else { retval = target_read_memory(target, addr, 1, len, fn); if (retval != ERROR_OK) { free(fn); return retval; } fn[len] = 0; semihosting->result = remove((char *)fn); if (semihosting->result == -1) semihosting->sys_errno = errno; LOG_DEBUG("remove('%s')=%" PRId64, fn, semihosting->result); free(fn); } } } break; case SEMIHOSTING_SYS_RENAME: /* 0x0F */ /* * Renames a specified file. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a * four-field data block: * - field 1 A pointer to the name of the old file. * - field 2 The length of the old filename. * - field 3 A pointer to the new filename. * - field 4 The length of the new filename. Both strings are * null-terminated. * * Return * On exit, the RETURN REGISTER contains: * - 0 if the rename is successful. * - A nonzero, host-specific error code if the rename fails. */ retval = semihosting_read_fields(target, 4, fields); if (retval != ERROR_OK) return retval; else { uint64_t addr1 = semihosting_get_field(target, 0, fields); size_t len1 = semihosting_get_field(target, 1, fields); uint64_t addr2 = semihosting_get_field(target, 2, fields); size_t len2 = semihosting_get_field(target, 3, fields); if (semihosting->is_fileio) { semihosting->hit_fileio = true; fileio_info->identifier = "rename"; fileio_info->param_1 = addr1; fileio_info->param_2 = len1; fileio_info->param_3 = addr2; fileio_info->param_4 = len2; } else { uint8_t *fn1 = malloc(len1+1); uint8_t *fn2 = malloc(len2+1); if (!fn1 || !fn2) { free(fn1); free(fn2); semihosting->result = -1; semihosting->sys_errno = ENOMEM; } else { retval = target_read_memory(target, addr1, 1, len1, fn1); if (retval != ERROR_OK) { free(fn1); free(fn2); return retval; } retval = target_read_memory(target, addr2, 1, len2, fn2); if (retval != ERROR_OK) { free(fn1); free(fn2); return retval; } fn1[len1] = 0; fn2[len2] = 0; semihosting->result = rename((char *)fn1, (char *)fn2); // rename() on Windows returns nonzero on error if (semihosting->result != 0) semihosting->sys_errno = errno; LOG_DEBUG("rename('%s', '%s')=%" PRId64 " %d", fn1, fn2, semihosting->result, errno); free(fn1); free(fn2); } } } break; case SEMIHOSTING_SYS_SEEK: /* 0x0A */ /* * Seeks to a specified position in a file using an offset * specified from the start of the file. The file is assumed * to be a byte array and the offset is given in bytes. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a * two-field data block: * - field 1 A handle for a seekable file object. * - field 2 The absolute byte position to seek to. * * Return * On exit, the RETURN REGISTER contains: * - 0 if the request is successful. * - A negative value if the request is not successful. * Use SYS_ERRNO to read the value of the host errno variable * describing the error. * * Note: The effect of seeking outside the current extent of * the file object is undefined. */ retval = semihosting_read_fields(target, 2, fields); if (retval != ERROR_OK) return retval; else { int fd = semihosting_get_field(target, 0, fields); off_t pos = semihosting_get_field(target, 1, fields); if (semihosting->is_fileio) { semihosting->hit_fileio = true; fileio_info->identifier = "lseek"; fileio_info->param_1 = fd; fileio_info->param_2 = pos; fileio_info->param_3 = SEEK_SET; } else { semihosting->result = lseek(fd, pos, SEEK_SET); if (semihosting->result == -1) semihosting->sys_errno = errno; LOG_DEBUG("lseek(%d, %d)=%" PRId64, fd, (int)pos, semihosting->result); if (semihosting->result == pos) semihosting->result = 0; } } break; case SEMIHOSTING_SYS_SYSTEM: /* 0x12 */ /* * Passes a command to the host command-line interpreter. * This enables you to execute a system command such as dir, * ls, or pwd. The terminal I/O is on the host, and is not * visible to the target. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a * two-field argument block: * - field 1 Points to a string to be passed to the host * command-line interpreter. * - field 2 The length of the string. * * Return * On exit, the RETURN REGISTER contains the return status. */ /* Provide SYS_SYSTEM functionality. Uses the * libc system command, there may be a reason *NOT* * to use this, but as I can't think of one, I * implemented it this way. */ retval = semihosting_read_fields(target, 2, fields); if (retval != ERROR_OK) return retval; else { uint64_t addr = semihosting_get_field(target, 0, fields); size_t len = semihosting_get_field(target, 1, fields); if (semihosting->is_fileio) { semihosting->hit_fileio = true; fileio_info->identifier = "system"; fileio_info->param_1 = addr; fileio_info->param_2 = len; } else { uint8_t *cmd = malloc(len+1); if (!cmd) { semihosting->result = -1; semihosting->sys_errno = ENOMEM; } else { retval = target_read_memory(target, addr, 1, len, cmd); if (retval != ERROR_OK) { free(cmd); return retval; } else { cmd[len] = 0; semihosting->result = system( (const char *)cmd); LOG_DEBUG("system('%s')=%" PRId64, cmd, semihosting->result); } free(cmd); } } } break; case SEMIHOSTING_SYS_TIME: /* 0x11 */ /* * Returns the number of seconds since 00:00 January 1, 1970. * This value is real-world time, regardless of any debug agent * configuration. * * Entry * There are no parameters. * * Return * On exit, the RETURN REGISTER contains the number of seconds. */ semihosting->result = time(NULL); break; case SEMIHOSTING_SYS_WRITE: /* 0x05 */ /* * Writes the contents of a buffer to a specified file at the * current file position. The file position is specified either: * - Explicitly, by a SYS_SEEK. * - Implicitly as one byte beyond the previous SYS_READ or * SYS_WRITE request. * * The file position is at the start of the file when the file * is opened, and is lost when the file is closed. * * Perform the file operation as a single action whenever * possible. For example, do not split a write of 16KB into * four 4KB chunks unless there is no alternative. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a * three-field data block: * - field 1 Contains a handle for a file previously opened * with SYS_OPEN. * - field 2 Points to the memory containing the data to be written. * - field 3 Contains the number of bytes to be written from * the buffer to the file. * * Return * On exit, the RETURN REGISTER contains: * - 0 if the call is successful. * - The number of bytes that are not written, if there is an error. */ retval = semihosting_read_fields(target, 3, fields); if (retval != ERROR_OK) return retval; else { int fd = semihosting_get_field(target, 0, fields); uint64_t addr = semihosting_get_field(target, 1, fields); size_t len = semihosting_get_field(target, 2, fields); if (semihosting->is_fileio) { semihosting->hit_fileio = true; fileio_info->identifier = "write"; fileio_info->param_1 = fd; fileio_info->param_2 = addr; fileio_info->param_3 = len; } else { uint8_t *buf = malloc(len); if (!buf) { semihosting->result = -1; semihosting->sys_errno = ENOMEM; } else { retval = target_read_buffer(target, addr, len, buf); if (retval != ERROR_OK) { free(buf); return retval; } semihosting->result = semihosting_write(semihosting, fd, buf, len); LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%" PRId64, fd, addr, len, semihosting->result); if (semihosting->result >= 0) { /* The number of bytes that are NOT written. * */ semihosting->result = len - semihosting->result; } free(buf); } } } break; case SEMIHOSTING_SYS_WRITEC: /* 0x03 */ /* * Writes a character byte, pointed to by the PARAMETER REGISTER, * to the debug channel. When executed under a semihosting * debugger, the character appears on the host debugger console. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to the * character. * * Return * None. The RETURN REGISTER is corrupted. */ if (semihosting->is_fileio) { semihosting->hit_fileio = true; fileio_info->identifier = "write"; fileio_info->param_1 = 1; fileio_info->param_2 = semihosting->param; fileio_info->param_3 = 1; } else { uint64_t addr = semihosting->param; unsigned char c; retval = target_read_memory(target, addr, 1, 1, &c); if (retval != ERROR_OK) return retval; semihosting_putchar(semihosting, semihosting->stdout_fd, c); semihosting->result = 0; } break; case SEMIHOSTING_SYS_WRITE0: /* 0x04 */ /* * Writes a null-terminated string to the debug channel. * When executed under a semihosting debugger, the characters * appear on the host debugger console. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to the * first byte of the string. * * Return * None. The RETURN REGISTER is corrupted. */ if (semihosting->is_fileio) { size_t count = 0; uint64_t addr = semihosting->param; for (;; addr++) { unsigned char c; retval = target_read_memory(target, addr, 1, 1, &c); if (retval != ERROR_OK) return retval; if (c == '\0') break; count++; } semihosting->hit_fileio = true; fileio_info->identifier = "write"; fileio_info->param_1 = 1; fileio_info->param_2 = semihosting->param; fileio_info->param_3 = count; } else { uint64_t addr = semihosting->param; do { unsigned char c; retval = target_read_memory(target, addr++, 1, 1, &c); if (retval != ERROR_OK) return retval; if (!c) break; semihosting_putchar(semihosting, semihosting->stdout_fd, c); } while (1); semihosting->result = 0; } break; case SEMIHOSTING_USER_CMD_0X100 ... SEMIHOSTING_USER_CMD_0X107: /** * This is a user defined operation (while user cmds 0x100-0x1ff * are possible, only 0x100-0x107 are currently implemented). * * Reads the user operation parameters from target, then fires the * corresponding target event. When the target callbacks returned, * cleans up the command parameter buffer. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a * two-field data block: * - field 1 Contains a pointer to the bound command parameter * string * - field 2 Contains the command parameter string length * * Return * On exit, the RETURN REGISTER contains the return status. */ if (semihosting->user_command_extension) { retval = semihosting->user_command_extension(target); if (retval != ERROR_NOT_IMPLEMENTED) break; /* If custom user command not handled, we are looking for the TCL handler */ } assert(!semihosting_user_op_params); retval = semihosting_read_fields(target, 2, fields); if (retval != ERROR_OK) { LOG_ERROR("Failed to read fields for user defined command" " op=0x%x", semihosting->op); return retval; } uint64_t addr = semihosting_get_field(target, 0, fields); size_t len = semihosting_get_field(target, 1, fields); if (len > SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH) { LOG_ERROR("The maximum length for user defined command " "parameter is %u, received length is %zu (op=0x%x)", SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH, len, semihosting->op); return ERROR_FAIL; } semihosting_user_op_params = malloc(len + 1); if (!semihosting_user_op_params) return ERROR_FAIL; semihosting_user_op_params[len] = 0; retval = target_read_buffer(target, addr, len, (uint8_t *)(semihosting_user_op_params)); if (retval != ERROR_OK) { LOG_ERROR("Failed to read from target, semihosting op=0x%x (%s)", semihosting->op, semihosting_opcode_to_str(semihosting->op)); free(semihosting_user_op_params); semihosting_user_op_params = NULL; return retval; } target_handle_event(target, semihosting->op); free(semihosting_user_op_params); semihosting_user_op_params = NULL; semihosting->result = 0; break; case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */ /* * Returns the number of elapsed target ticks since execution * started. * Use SYS_TICKFREQ to determine the tick frequency. * * Entry (32-bit) * On entry, the PARAMETER REGISTER points to a two-field data * block to be used for returning the number of elapsed ticks: * - field 1 The least significant field and is at the low address. * - field 2 The most significant field and is at the high address. * * Entry (64-bit) * On entry the PARAMETER REGISTER points to a one-field data * block to be used for returning the number of elapsed ticks: * - field 1 The number of elapsed ticks as a 64-bit value. * * Return * On exit: * - On success, the RETURN REGISTER contains 0, the PARAMETER * REGISTER is unchanged, and the data block pointed to by the * PARAMETER REGISTER is filled in with the number of elapsed * ticks. * - On failure, the RETURN REGISTER contains -1, and the * PARAMETER REGISTER contains -1. * * Note: Some semihosting implementations might not support this * semihosting operation, and they always return -1 in the * RETURN REGISTER. */ case SEMIHOSTING_SYS_TICKFREQ: /* 0x31 */ /* * Returns the tick frequency. * * Entry * The PARAMETER REGISTER must contain 0 on entry to this routine. * * Return * On exit, the RETURN REGISTER contains either: * - The number of ticks per second. * - –1 if the target does not know the value of one tick. * * Note: Some semihosting implementations might not support * this semihosting operation, and they always return -1 in the * RETURN REGISTER. */ case SEMIHOSTING_SYS_TMPNAM: /* 0x0D */ /* * Returns a temporary name for a file identified by a system * file identifier. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a * three-word argument block: * - field 1 A pointer to a buffer. * - field 2 A target identifier for this filename. Its value * must be an integer in the range 0-255. * - field 3 Contains the length of the buffer. The length must * be at least the value of L_tmpnam on the host system. * * Return * On exit, the RETURN REGISTER contains: * - 0 if the call is successful. * - –1 if an error occurs. * * The buffer pointed to by the PARAMETER REGISTER contains * the filename, prefixed with a suitable directory name. * If you use the same target identifier again, the same * filename is returned. * * Note: The returned string must be null-terminated. */ default: fprintf(stderr, "semihosting: unsupported call %#x\n", (unsigned) semihosting->op); semihosting->result = -1; semihosting->sys_errno = ENOTSUP; } if (!semihosting->hit_fileio) { retval = semihosting->post_result(target); if (retval != ERROR_OK) { LOG_ERROR("Failed to post semihosting result"); return retval; } } return ERROR_OK; } /* ------------------------------------------------------------------------- * Local functions. */ static int semihosting_common_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) { struct semihosting *semihosting = target->semihosting; if (!semihosting) return ERROR_FAIL; /* * To avoid unnecessary duplication, semihosting prepares the * fileio_info structure out-of-band when the target halts. See * do_semihosting for more detail. */ if (!semihosting->is_fileio || !semihosting->hit_fileio) return ERROR_FAIL; return ERROR_OK; } static int semihosting_common_fileio_end(struct target *target, int result, int fileio_errno, bool ctrl_c) { struct gdb_fileio_info *fileio_info = target->fileio_info; struct semihosting *semihosting = target->semihosting; if (!semihosting) return ERROR_FAIL; /* clear pending status */ semihosting->hit_fileio = false; semihosting->result = result; /* * Some fileio results do not match up with what the semihosting * operation expects; for these operations, we munge the results * below: */ switch (semihosting->op) { case SEMIHOSTING_SYS_WRITE: /* 0x05 */ case SEMIHOSTING_SYS_READ: /* 0x06 */ if (result < 0) semihosting->result = fileio_info->param_3; /* Zero bytes read/written. */ else semihosting->result = (int64_t)fileio_info->param_3 - result; break; case SEMIHOSTING_SYS_SEEK: /* 0x0a */ if (result > 0) semihosting->result = 0; break; } bool fileio_failed = false; if (semihosting->op == SEMIHOSTING_SYS_ISTTY) fileio_failed = (semihosting->result == 0); else if (semihosting->op == SEMIHOSTING_SYS_RENAME) fileio_failed = (semihosting->result != 0); else fileio_failed = (semihosting->result == -1); if (fileio_failed) semihosting->sys_errno = fileio_errno; return semihosting->post_result(target); } /* ------------------------------------------------------------------------- * Utility functions. */ /** * Read all fields of a command from target to buffer. */ int semihosting_read_fields(struct target *target, size_t number, uint8_t *fields) { struct semihosting *semihosting = target->semihosting; /* Use 4-byte multiples to trigger fast memory access. */ return target_read_memory(target, semihosting->param, 4, number * (semihosting->word_size_bytes / 4), fields); } /** * Write all fields of a command from buffer to target. */ int semihosting_write_fields(struct target *target, size_t number, uint8_t *fields) { struct semihosting *semihosting = target->semihosting; /* Use 4-byte multiples to trigger fast memory access. */ return target_write_memory(target, semihosting->param, 4, number * (semihosting->word_size_bytes / 4), fields); } /** * Extract a field from the buffer, considering register size and endianness. */ uint64_t semihosting_get_field(struct target *target, size_t index, uint8_t *fields) { struct semihosting *semihosting = target->semihosting; if (semihosting->word_size_bytes == 8) return target_buffer_get_u64(target, fields + (index * 8)); else return target_buffer_get_u32(target, fields + (index * 4)); } /** * Store a field in the buffer, considering register size and endianness. */ void semihosting_set_field(struct target *target, uint64_t value, size_t index, uint8_t *fields) { struct semihosting *semihosting = target->semihosting; if (semihosting->word_size_bytes == 8) target_buffer_set_u64(target, fields + (index * 8), value); else target_buffer_set_u32(target, fields + (index * 4), value); } /* ------------------------------------------------------------------------- * Semihosting redirect over TCP structs and functions */ static int semihosting_service_new_connection_handler(struct connection *connection) { struct semihosting_tcp_service *service = connection->service->priv; service->semihosting->tcp_connection = connection; return ERROR_OK; } static int semihosting_service_input_handler(struct connection *connection) { struct semihosting_tcp_service *service = connection->service->priv; if (!connection->input_pending) { /* consume received data, not for semihosting IO */ const int buf_len = 100; char buf[buf_len]; int bytes_read = connection_read(connection, buf, buf_len); if (bytes_read == 0) { return ERROR_SERVER_REMOTE_CLOSED; } else if (bytes_read == -1) { LOG_ERROR("error during read: %s", strerror(errno)); return ERROR_SERVER_REMOTE_CLOSED; } } else if (service->error != ERROR_OK) { return ERROR_SERVER_REMOTE_CLOSED; } return ERROR_OK; } static int semihosting_service_connection_closed_handler(struct connection *connection) { struct semihosting_tcp_service *service = connection->service->priv; if (service) { free(service->name); free(service); } return ERROR_OK; } static void semihosting_tcp_close_cnx(struct semihosting *semihosting) { if (!semihosting->tcp_connection) return; struct service *service = semihosting->tcp_connection->service; remove_service(service->name, service->port); semihosting->tcp_connection = NULL; } static const struct service_driver semihosting_service_driver = { .name = "semihosting", .new_connection_during_keep_alive_handler = NULL, .new_connection_handler = semihosting_service_new_connection_handler, .input_handler = semihosting_service_input_handler, .connection_closed_handler = semihosting_service_connection_closed_handler, .keep_client_alive_handler = NULL, }; /* ------------------------------------------------------------------------- * Common semihosting commands handlers. */ COMMAND_HANDLER(handle_common_semihosting_command) { struct target *target = get_current_target(CMD_CTX); if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } struct semihosting *semihosting = target->semihosting; if (!semihosting) { command_print(CMD, "semihosting not supported for current target"); return ERROR_FAIL; } if (CMD_ARGC > 0) { int is_active; COMMAND_PARSE_ENABLE(CMD_ARGV[0], is_active); if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (semihosting && semihosting->setup(target, is_active) != ERROR_OK) { LOG_ERROR("Failed to Configure semihosting"); return ERROR_FAIL; } /* FIXME never let that "catch" be dropped! (???) */ semihosting->is_active = is_active; } command_print(CMD, "semihosting is %s", semihosting->is_active ? "enabled" : "disabled"); return ERROR_OK; } COMMAND_HANDLER(handle_common_semihosting_redirect_command) { struct target *target = get_current_target(CMD_CTX); if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } struct semihosting *semihosting = target->semihosting; if (!semihosting) { command_print(CMD, "semihosting not supported for current target"); return ERROR_FAIL; } if (!semihosting->is_active) { command_print(CMD, "semihosting not yet enabled for current target"); return ERROR_FAIL; } enum semihosting_redirect_config cfg; const char *port; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[0], "disable") == 0) { cfg = SEMIHOSTING_REDIRECT_CFG_NONE; if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; } else if (strcmp(CMD_ARGV[0], "tcp") == 0) { if (CMD_ARGC < 2 || CMD_ARGC > 3) return ERROR_COMMAND_SYNTAX_ERROR; port = CMD_ARGV[1]; cfg = SEMIHOSTING_REDIRECT_CFG_ALL; if (CMD_ARGC == 3) { if (strcmp(CMD_ARGV[2], "debug") == 0) cfg = SEMIHOSTING_REDIRECT_CFG_DEBUG; else if (strcmp(CMD_ARGV[2], "stdio") == 0) cfg = SEMIHOSTING_REDIRECT_CFG_STDIO; else if (strcmp(CMD_ARGV[2], "all") != 0) return ERROR_COMMAND_SYNTAX_ERROR; } } else { return ERROR_COMMAND_SYNTAX_ERROR; } semihosting_tcp_close_cnx(semihosting); semihosting->redirect_cfg = SEMIHOSTING_REDIRECT_CFG_NONE; if (cfg != SEMIHOSTING_REDIRECT_CFG_NONE) { struct semihosting_tcp_service *service = calloc(1, sizeof(struct semihosting_tcp_service)); if (!service) { LOG_ERROR("Failed to allocate semihosting TCP service."); return ERROR_FAIL; } service->semihosting = semihosting; service->name = alloc_printf("%s semihosting service", target_name(target)); if (!service->name) { LOG_ERROR("Out of memory"); free(service); return ERROR_FAIL; } int ret = add_service(&semihosting_service_driver, port, 1, service); if (ret != ERROR_OK) { LOG_ERROR("failed to initialize %s", service->name); free(service->name); free(service); return ERROR_FAIL; } } semihosting->redirect_cfg = cfg; return ERROR_OK; } COMMAND_HANDLER(handle_common_semihosting_fileio_command) { struct target *target = get_current_target(CMD_CTX); if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } struct semihosting *semihosting = target->semihosting; if (!semihosting) { command_print(CMD, "semihosting not supported for current target"); return ERROR_FAIL; } if (!semihosting->is_active) { command_print(CMD, "semihosting not yet enabled for current target"); return ERROR_FAIL; } if (CMD_ARGC > 0) COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting->is_fileio); command_print(CMD, "semihosting fileio is %s", semihosting->is_fileio ? "enabled" : "disabled"); return ERROR_OK; } COMMAND_HANDLER(handle_common_semihosting_cmdline) { struct target *target = get_current_target(CMD_CTX); unsigned int i; if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } struct semihosting *semihosting = target->semihosting; if (!semihosting) { command_print(CMD, "semihosting not supported for current target"); return ERROR_FAIL; } free(semihosting->cmdline); semihosting->cmdline = CMD_ARGC > 0 ? strdup(CMD_ARGV[0]) : NULL; for (i = 1; i < CMD_ARGC; i++) { char *cmdline = alloc_printf("%s %s", semihosting->cmdline, CMD_ARGV[i]); if (!cmdline) break; free(semihosting->cmdline); semihosting->cmdline = cmdline; } command_print(CMD, "semihosting command line is [%s]", semihosting->cmdline); return ERROR_OK; } COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command) { struct target *target = get_current_target(CMD_CTX); if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } struct semihosting *semihosting = target->semihosting; if (!semihosting) { command_print(CMD, "semihosting not supported for current target"); return ERROR_FAIL; } if (!semihosting->is_active) { command_print(CMD, "semihosting not yet enabled for current target"); return ERROR_FAIL; } if (CMD_ARGC > 0) COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting->has_resumable_exit); command_print(CMD, "semihosting resumable exit is %s", semihosting->has_resumable_exit ? "enabled" : "disabled"); return ERROR_OK; } COMMAND_HANDLER(handle_common_semihosting_read_user_param_command) { struct target *target = get_current_target(CMD_CTX); struct semihosting *semihosting = target->semihosting; if (CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; if (!semihosting->is_active) { LOG_ERROR("semihosting not yet enabled for current target"); return ERROR_FAIL; } if (!semihosting_user_op_params) { LOG_ERROR("This command is usable only from a registered user " "semihosting event callback."); return ERROR_FAIL; } command_print_sameline(CMD, "%s", semihosting_user_op_params); return ERROR_OK; } COMMAND_HANDLER(handle_common_semihosting_basedir_command) { struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } struct semihosting *semihosting = target->semihosting; if (!semihosting) { command_print(CMD, "semihosting not supported for current target"); return ERROR_FAIL; } if (!semihosting->is_active) { command_print(CMD, "semihosting not yet enabled for current target"); return ERROR_FAIL; } if (CMD_ARGC > 0) { free(semihosting->basedir); semihosting->basedir = strdup(CMD_ARGV[0]); if (!semihosting->basedir) { command_print(CMD, "semihosting failed to allocate memory for basedir!"); return ERROR_FAIL; } } command_print(CMD, "semihosting base dir: %s", semihosting->basedir ? semihosting->basedir : ""); return ERROR_OK; } const struct command_registration semihosting_common_handlers[] = { { .name = "semihosting", .handler = handle_common_semihosting_command, .mode = COMMAND_EXEC, .usage = "['enable'|'disable']", .help = "activate support for semihosting operations", }, { .name = "semihosting_redirect", .handler = handle_common_semihosting_redirect_command, .mode = COMMAND_EXEC, .usage = "(disable | tcp <port> ['debug'|'stdio'|'all'])", .help = "redirect semihosting IO", }, { .name = "semihosting_cmdline", .handler = handle_common_semihosting_cmdline, .mode = COMMAND_EXEC, .usage = "arguments", .help = "command line arguments to be passed to program", }, { .name = "semihosting_fileio", .handler = handle_common_semihosting_fileio_command, .mode = COMMAND_EXEC, .usage = "['enable'|'disable']", .help = "activate support for semihosting fileio operations", }, { .name = "semihosting_resexit", .handler = handle_common_semihosting_resumable_exit_command, .mode = COMMAND_EXEC, .usage = "['enable'|'disable']", .help = "activate support for semihosting resumable exit", }, { .name = "semihosting_read_user_param", .handler = handle_common_semihosting_read_user_param_command, .mode = COMMAND_EXEC, .usage = "", .help = "read parameters in semihosting-user-cmd-0x10X callbacks", }, { .name = "semihosting_basedir", .handler = handle_common_semihosting_basedir_command, .mode = COMMAND_EXEC, .usage = "[dir]", .help = "set the base directory for semihosting I/O operations", }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/semihosting_common.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2018 by Liviu Ionescu * * <ilg@livius.net> * * * * Copyright (C) 2009 by Marvell Technology Group Ltd. * * Written by Nicolas Pitre <nico@marvell.com> * ***************************************************************************/ #ifndef OPENOCD_TARGET_SEMIHOSTING_COMMON_H #define OPENOCD_TARGET_SEMIHOSTING_COMMON_H #include <stdint.h> #include <stdbool.h> #include <time.h> #include "helper/replacements.h" #include <server/server.h> /* * According to: * "Semihosting for AArch32 and AArch64, Release 2.0" * https://static.docs.arm.com/100863/0200/semihosting.pdf * from ARM Ltd. * * The available semihosting operation numbers passed in R0 are allocated * as follows: * - 0x00-0x31 Used by ARM. * - 0x32-0xFF Reserved for future use by ARM. * - 0x100-0x1FF Reserved for user applications. These are not used by ARM. * However, if you are writing your own SVC operations, you are advised * to use a different SVC number rather than using the semihosted * SVC number and these operation type numbers. * - 0x200-0xFFFFFFFF Undefined and currently unused. It is recommended * that you do not use these. */ enum semihosting_operation_numbers { /* * ARM semihosting operations, in lexicographic order. */ SEMIHOSTING_ENTER_SVC = 0x17, /* DEPRECATED */ SEMIHOSTING_SYS_CLOSE = 0x02, SEMIHOSTING_SYS_CLOCK = 0x10, SEMIHOSTING_SYS_ELAPSED = 0x30, SEMIHOSTING_SYS_ERRNO = 0x13, SEMIHOSTING_SYS_EXIT = 0x18, SEMIHOSTING_SYS_EXIT_EXTENDED = 0x20, SEMIHOSTING_SYS_FLEN = 0x0C, SEMIHOSTING_SYS_GET_CMDLINE = 0x15, SEMIHOSTING_SYS_HEAPINFO = 0x16, SEMIHOSTING_SYS_ISERROR = 0x08, SEMIHOSTING_SYS_ISTTY = 0x09, SEMIHOSTING_SYS_OPEN = 0x01, SEMIHOSTING_SYS_READ = 0x06, SEMIHOSTING_SYS_READC = 0x07, SEMIHOSTING_SYS_REMOVE = 0x0E, SEMIHOSTING_SYS_RENAME = 0x0F, SEMIHOSTING_SYS_SEEK = 0x0A, SEMIHOSTING_SYS_SYSTEM = 0x12, SEMIHOSTING_SYS_TICKFREQ = 0x31, SEMIHOSTING_SYS_TIME = 0x11, SEMIHOSTING_SYS_TMPNAM = 0x0D, SEMIHOSTING_SYS_WRITE = 0x05, SEMIHOSTING_SYS_WRITEC = 0x03, SEMIHOSTING_SYS_WRITE0 = 0x04, SEMIHOSTING_ARM_RESERVED_START = 0x32, SEMIHOSTING_ARM_RESERVED_END = 0xFF, SEMIHOSTING_USER_CMD_0X100 = 0x100, /* First user cmd op code */ SEMIHOSTING_USER_CMD_0X107 = 0x107, /* Last supported user cmd op code */ SEMIHOSTING_USER_CMD_0X1FF = 0x1FF, /* Last user cmd op code */ }; /** Maximum allowed Tcl command segment length in bytes*/ #define SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH (1024 * 1024) /* * Codes used by SEMIHOSTING_SYS_EXIT (formerly * SEMIHOSTING_REPORT_EXCEPTION). * On 64-bits, the exit code is passed explicitly. */ enum semihosting_reported_exceptions { /* On 32 bits, use it for exit(0) */ ADP_STOPPED_APPLICATION_EXIT = ((2 << 16) + 38), /* On 32 bits, use it for exit(1) */ ADP_STOPPED_RUN_TIME_ERROR = ((2 << 16) + 35), }; enum semihosting_redirect_config { SEMIHOSTING_REDIRECT_CFG_NONE, SEMIHOSTING_REDIRECT_CFG_DEBUG, SEMIHOSTING_REDIRECT_CFG_STDIO, SEMIHOSTING_REDIRECT_CFG_ALL, }; enum semihosting_result { SEMIHOSTING_NONE, /* Not halted for a semihosting call. */ SEMIHOSTING_HANDLED, /* Call handled, and target was resumed. */ SEMIHOSTING_WAITING, /* Call handled, target is halted waiting until we can resume. */ SEMIHOSTING_ERROR /* Something went wrong. */ }; struct target; /* * A pointer to this structure was added to the target structure. */ struct semihosting { /** A flag reporting whether semihosting is active. */ bool is_active; /** Semihosting STDIO file descriptors */ int stdin_fd, stdout_fd, stderr_fd; /** redirection configuration, NONE by default */ enum semihosting_redirect_config redirect_cfg; /** Handle to redirect semihosting print via tcp */ struct connection *tcp_connection; /** A flag reporting whether semihosting fileio is active. */ bool is_fileio; /** A flag reporting whether semihosting fileio operation is active. */ bool hit_fileio; /** Most are resumable, except the two exit calls. */ bool is_resumable; /** * When SEMIHOSTING_SYS_EXIT is called outside a debug session, * things are simple, the openocd process calls exit() and passes * the value returned by the target. * When SEMIHOSTING_SYS_EXIT is called during a debug session, * by default execution returns to the debugger, leaving the * debugger in a HALT state, similar to the state entered when * encountering a break. * In some use cases, it is useful to have SEMIHOSTING_SYS_EXIT * return normally, as any semihosting call, and do not break * to the debugger. * The standard allows this to happen, but the condition * to trigger it is a bit obscure ("by performing an RDI_Execute * request or equivalent"). * * To make the SEMIHOSTING_SYS_EXIT call return normally, enable * this variable via the dedicated command (default: disabled). */ bool has_resumable_exit; /** The Target (hart) word size; 8 for 64-bits targets. */ size_t word_size_bytes; /** The current semihosting operation (R0 on ARM). */ int op; /** The current semihosting parameter (R1 or ARM). */ uint64_t param; /** * The current semihosting result to be returned to the application. * Usually 0 for success, -1 for error, * but sometimes a useful value, even a pointer. */ int64_t result; /** The value to be returned by semihosting SYS_ERRNO request. */ int sys_errno; /** The semihosting command line to be passed to the target. */ char *cmdline; /** The current time when 'execution starts' */ clock_t setup_time; /** Base directory for semihosting I/O operations. */ char *basedir; /** * Target's extension of semihosting user commands. * @returns ERROR_NOT_IMPLEMENTED when user command is not handled, otherwise * sets semihosting->result and semihosting->sys_errno and returns ERROR_OK. */ int (*user_command_extension)(struct target *target); int (*setup)(struct target *target, int enable); int (*post_result)(struct target *target); }; /** * @brief Convert the syscall opcode to a human-readable string * @param[in] opcode Syscall opcode * @return String representation of syscall opcode */ const char *semihosting_opcode_to_str(uint64_t opcode); int semihosting_common_init(struct target *target, void *setup, void *post_result); int semihosting_common(struct target *target); /* utility functions which may also be used by semihosting extensions (custom vendor-defined syscalls) */ int semihosting_read_fields(struct target *target, size_t number, uint8_t *fields); int semihosting_write_fields(struct target *target, size_t number, uint8_t *fields); uint64_t semihosting_get_field(struct target *target, size_t index, uint8_t *fields); void semihosting_set_field(struct target *target, uint64_t value, size_t index, uint8_t *fields); extern const struct command_registration semihosting_common_handlers[]; #endif /* OPENOCD_TARGET_SEMIHOSTING_COMMON_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/smp.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * * * Copyright (C) ST-Ericsson SA 2011 * * Author: Michel Jaouen <michel.jaouen@stericsson.com> for ST-Ericsson. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "server/server.h" #include "target/target.h" #include "server/gdb_server.h" #include "smp.h" #include "helper/binarybuffer.h" /* DEPRECATED: gdb_read_smp_packet/gdb_write_smp_packet to be removed */ /* implementation of new packet in gdb interface for smp feature */ /* */ /* j : smp status request */ /* J : smp set request */ /* */ /* jc :read core id displayed by gdb connection */ /* reply XXXXXXXX core id is int32_t , 8 hex digits */ /* */ /* Reply ENN error not supported (target not smp) */ /* */ /* JcXX set core id displayed at next gdb continue */ /* maximum 8 bytes described core id int32_t (8 hex digits) */ /* (core id -1 , reserved for returning to normal continue mode) */ /* Reply ENN error not supported(target not smp,core id out of range) */ /* Reply OK : for success */ /* */ /* handling of this packet within gdb can be done by the creation */ /* internal variable by mean of function allocate_computed_value */ /* set $_core 1 => Jc01 packet is sent */ /* print $_core => jc packet is sent and result is affected in $ */ /* Another way to test this packet is the usage of maintenance packet */ /* maint packet Jc01 */ /* maint packet jc */ /* packet j :smp status request */ #define DEPRECATED_MSG "DEPRECATED: This method is deprecated in favor of the hwthread pseudo RTOS" int gdb_read_smp_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); int retval = ERROR_OK; LOG_WARNING(DEPRECATED_MSG); if (target->smp) { if (strncmp(packet, "jc", 2) == 0) { const uint32_t len = sizeof(target->gdb_service->core[0]); char hex_buffer[len * 2 + 1]; uint8_t buffer[len]; buf_set_u32(buffer, 0, len * 8, target->gdb_service->core[0]); size_t pkt_len = hexify(hex_buffer, buffer, sizeof(buffer), sizeof(hex_buffer)); retval = gdb_put_packet(connection, hex_buffer, pkt_len); } } else retval = gdb_put_packet(connection, "E01", 3); return retval; } /* J : smp set request */ int gdb_write_smp_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); char *separator; int coreid = 0; int retval = ERROR_OK; LOG_WARNING(DEPRECATED_MSG); /* skip command character */ if (target->smp) { if (strncmp(packet, "Jc", 2) == 0) { packet += 2; coreid = strtoul(packet, &separator, 16); target->gdb_service->core[1] = coreid; retval = gdb_put_packet(connection, "OK", 2); } } else retval = gdb_put_packet(connection, "E01", 3); return retval; } COMMAND_HANDLER(default_handle_smp_command) { struct target *target = get_current_target(CMD_CTX); struct target_list *head; if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (!CMD_ARGC) { command_print(CMD, "%s", target->smp ? "on" : "off"); return ERROR_OK; } if (!strcmp(CMD_ARGV[0], "on")) { foreach_smp_target(head, target->smp_targets) head->target->smp = 1; return ERROR_OK; } if (!strcmp(CMD_ARGV[0], "off")) { foreach_smp_target(head, target->smp_targets) head->target->smp = 0; /* fixes the target display to the debugger */ if (!list_empty(target->smp_targets)) target->gdb_service->target = target; return ERROR_OK; } return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_HANDLER(handle_smp_gdb_command) { struct target *target = get_current_target(CMD_CTX); int retval = ERROR_OK; if (!list_empty(target->smp_targets)) { if (CMD_ARGC == 1) { int coreid = 0; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], coreid); if (retval != ERROR_OK) return retval; target->gdb_service->core[1] = coreid; } command_print(CMD, "gdb coreid %" PRId32 " -> %" PRId32, target->gdb_service->core[0] , target->gdb_service->core[1]); } return ERROR_OK; } const struct command_registration smp_command_handlers[] = { { .name = "smp", .handler = default_handle_smp_command, .mode = COMMAND_EXEC, .help = "smp handling", .usage = "[on|off]", }, { .name = "smp_gdb", .handler = handle_smp_gdb_command, .mode = COMMAND_EXEC, .help = "display/fix current core played to gdb", .usage = "", }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/smp.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * * * Copyright (C) ST-Ericsson SA 2011 * * Author: Michel Jaouen <michel.jaouen@stericsson.com> for ST-Ericsson. * ***************************************************************************/ #ifndef OPENOCD_TARGET_SMP_H #define OPENOCD_TARGET_SMP_H #include <helper/list.h> #include "server/server.h" #define foreach_smp_target(pos, head) \ list_for_each_entry(pos, head, lh) #define foreach_smp_target_direction(forward, pos, head) \ list_for_each_entry_direction(forward, pos, head, lh) extern const struct command_registration smp_command_handlers[]; /* DEPRECATED */ int gdb_read_smp_packet(struct connection *connection, char const *packet, int packet_size); /* DEPRECATED */ int gdb_write_smp_packet(struct connection *connection, char const *packet, int packet_size); #endif /* OPENOCD_TARGET_SMP_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/startup.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Defines basic Tcl procs for OpenOCD target module proc new_target_name { } { return [target number [expr {[target count] - 1}]] } global in_process_reset set in_process_reset 0 # Catch reset recursion proc ocd_process_reset { MODE } { global in_process_reset if {$in_process_reset} { set in_process_reset 0 return -code error "'reset' can not be invoked recursively" } set in_process_reset 1 set success [expr {[catch {ocd_process_reset_inner $MODE} result] == 0}] set in_process_reset 0 if {$success} { return $result } else { return -code error $result } } proc ocd_process_reset_inner { MODE } { set targets [target names] # If this target must be halted... switch $MODE { halt - init { set halt 1 } run { set halt 0 } default { return -code error "Invalid mode: $MODE, must be one of: halt, init, or run"; } } # Target event handlers *might* change which TAPs are enabled # or disabled, so we fire all of them. But don't issue any # target "arp_*" commands, which may issue JTAG transactions, # unless we know the underlying TAP is active. # # NOTE: ARP == "Advanced Reset Process" ... "advanced" is # relative to a previous restrictive scheme foreach t $targets { # New event script. $t invoke-event reset-start } # Use TRST or TMS/TCK operations to reset all the tap controllers. # TAP reset events get reported; they might enable some taps. init_reset $MODE # Examine all targets on enabled taps. foreach t $targets { if {![using_jtag] || [jtag tapisenabled [$t cget -chain-position]]} { $t invoke-event examine-start set err [catch "$t arp_examine allow-defer"] if { $err } { $t invoke-event examine-fail } else { $t invoke-event examine-end } } } # Assert SRST, and report the pre/post events. # Note: no target sees SRST before "pre" or after "post". foreach t $targets { $t invoke-event reset-assert-pre } foreach t $targets { # C code needs to know if we expect to 'halt' if {![using_jtag] || [jtag tapisenabled [$t cget -chain-position]]} { $t arp_reset assert $halt } } foreach t $targets { $t invoke-event reset-assert-post } # Now de-assert SRST, and report the pre/post events. # Note: no target sees !SRST before "pre" or after "post". foreach t $targets { $t invoke-event reset-deassert-pre } foreach t $targets { # Again, de-assert code needs to know if we 'halt' if {![using_jtag] || [jtag tapisenabled [$t cget -chain-position]]} { $t arp_reset deassert $halt } } foreach t $targets { $t invoke-event reset-deassert-post } # Pass 1 - Now wait for any halt (requested as part of reset # assert/deassert) to happen. Ideally it takes effect without # first executing any instructions. if { $halt } { foreach t $targets { if {[using_jtag] && ![jtag tapisenabled [$t cget -chain-position]]} { continue } if { ![$t was_examined] } { # don't wait for targets where examination is deferred # they can not be halted anyway at this point if { [$t examine_deferred] } { continue } # try to re-examine or target state will be unknown $t invoke-event examine-start set err [catch "$t arp_examine allow-defer"] if { $err } { $t invoke-event examine-fail return -code error [format "TARGET: %s - Not examined" $t] } else { $t invoke-event examine-end } } # Wait up to 1 second for target to halt. Why 1sec? Cause # the JTAG tap reset signal might be hooked to a slow # resistor/capacitor circuit - and it might take a while # to charge # Catch, but ignore any errors. catch { $t arp_waitstate halted 1000 } # Did we succeed? set s [$t curstate] if { $s != "halted" } { return -code error [format "TARGET: %s - Not halted" $t] } } } #Pass 2 - if needed "init" if { $MODE == "init" } { foreach t $targets { if {[using_jtag] && ![jtag tapisenabled [$t cget -chain-position]]} { continue } # don't wait for targets where examination is deferred # they can not be halted anyway at this point if { ![$t was_examined] && [$t examine_deferred] } { continue } set err [catch "$t arp_waitstate halted 5000"] # Did it halt? if { $err == 0 } { $t invoke-event reset-init } } } foreach t $targets { $t invoke-event reset-end } } proc using_jtag {} { set _TRANSPORT [ transport select ] expr { [ string first "jtag" $_TRANSPORT ] != -1 } } proc using_swd {} { set _TRANSPORT [ transport select ] expr { [ string first "swd" $_TRANSPORT ] != -1 } } proc using_hla {} { set _TRANSPORT [ transport select ] expr { [ string first "hla" $_TRANSPORT ] != -1 } } ######### # Target/chain configuration scripts can either execute commands directly # or define a procedure which is executed once all configuration # scripts have completed. # # By default(classic) the config scripts will set up the target configuration proc init_targets {} { } proc set_default_target_event {t e s} { if {[$t cget -event $e] == ""} { $t configure -event $e $s } } proc init_target_events {} { set targets [target names] foreach t $targets { set_default_target_event $t gdb-flash-erase-start "reset init" set_default_target_event $t gdb-flash-write-end "reset halt" set_default_target_event $t gdb-attach "halt 1000" } } # Additionally board config scripts can define a procedure init_board that will be executed after init and init_targets proc init_board {} { } proc mem2array {arrayname bitwidth address count {phys ""}} { echo "DEPRECATED! use 'read_memory' not 'mem2array'" upvar $arrayname $arrayname set $arrayname "" set i 0 foreach elem [read_memory $address $bitwidth $count {*}$phys] { set ${arrayname}($i) $elem incr i } } proc array2mem {arrayname bitwidth address count {phys ""}} { echo "DEPRECATED! use 'write_memory' not 'array2mem'" upvar $arrayname $arrayname set data "" for {set i 0} {$i < $count} {incr i} { lappend data [expr $${arrayname}($i)] } write_memory $address $bitwidth $data {*}$phys } # smp_on/smp_off were already DEPRECATED in v0.11.0 through http://openocd.zylin.com/4615 lappend _telnet_autocomplete_skip "aarch64 smp_on" proc "aarch64 smp_on" {args} { echo "DEPRECATED! use 'aarch64 smp on' not 'aarch64 smp_on'" eval aarch64 smp on $args } lappend _telnet_autocomplete_skip "aarch64 smp_off" proc "aarch64 smp_off" {args} { echo "DEPRECATED! use 'aarch64 smp off' not 'aarch64 smp_off'" eval aarch64 smp off $args } lappend _telnet_autocomplete_skip "cortex_a smp_on" proc "cortex_a smp_on" {args} { echo "DEPRECATED! use 'cortex_a smp on' not 'cortex_a smp_on'" eval cortex_a smp on $args } lappend _telnet_autocomplete_skip "cortex_a smp_off" proc "cortex_a smp_off" {args} { echo "DEPRECATED! use 'cortex_a smp off' not 'cortex_a smp_off'" eval cortex_a smp off $args } lappend _telnet_autocomplete_skip "mips_m4k smp_on" proc "mips_m4k smp_on" {args} { echo "DEPRECATED! use 'mips_m4k smp on' not 'mips_m4k smp_on'" eval mips_m4k smp on $args } lappend _telnet_autocomplete_skip "mips_m4k smp_off" proc "mips_m4k smp_off" {args} { echo "DEPRECATED! use 'mips_m4k smp off' not 'mips_m4k smp_off'" eval mips_m4k smp off $args } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/stm8.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * OpenOCD STM8 target driver * Copyright (C) 2017 Ake Rehnman * ake.rehnman(at)gmail.com */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include "target.h" #include "target_type.h" #include "hello.h" #include "jtag/interface.h" #include "jtag/jtag.h" #include "jtag/swim.h" #include "register.h" #include "breakpoints.h" #include "algorithm.h" #include "stm8.h" static struct reg_cache *stm8_build_reg_cache(struct target *target); static int stm8_read_core_reg(struct target *target, unsigned int num); static int stm8_write_core_reg(struct target *target, unsigned int num); static int stm8_save_context(struct target *target); static void stm8_enable_breakpoints(struct target *target); static int stm8_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); static int stm8_set_breakpoint(struct target *target, struct breakpoint *breakpoint); static void stm8_enable_watchpoints(struct target *target); static int stm8_unset_watchpoint(struct target *target, struct watchpoint *watchpoint); static int (*adapter_speed)(int speed); extern struct adapter_driver *adapter_driver; static const struct { unsigned id; const char *name; const uint8_t bits; enum reg_type type; const char *group; const char *feature; int flag; } stm8_regs[] = { { 0, "pc", 32, REG_TYPE_UINT32, "general", "org.gnu.gdb.stm8.core", 0 }, { 1, "a", 8, REG_TYPE_UINT8, "general", "org.gnu.gdb.stm8.core", 0 }, { 2, "x", 16, REG_TYPE_UINT16, "general", "org.gnu.gdb.stm8.core", 0 }, { 3, "y", 16, REG_TYPE_UINT16, "general", "org.gnu.gdb.stm8.core", 0 }, { 4, "sp", 16, REG_TYPE_UINT16, "general", "org.gnu.gdb.stm8.core", 0 }, { 5, "cc", 8, REG_TYPE_UINT8, "general", "org.gnu.gdb.stm8.core", 0 }, }; #define STM8_NUM_REGS ARRAY_SIZE(stm8_regs) #define STM8_PC 0 #define STM8_A 1 #define STM8_X 2 #define STM8_Y 3 #define STM8_SP 4 #define STM8_CC 5 #define CC_I0 0x8 #define CC_I1 0x20 #define DM_REGS 0x7f00 #define DM_REG_A 0x7f00 #define DM_REG_PC 0x7f01 #define DM_REG_X 0x7f04 #define DM_REG_Y 0x7f06 #define DM_REG_SP 0x7f08 #define DM_REG_CC 0x7f0a #define DM_BKR1E 0x7f90 #define DM_BKR2E 0x7f93 #define DM_CR1 0x7f96 #define DM_CR2 0x7f97 #define DM_CSR1 0x7f98 #define DM_CSR2 0x7f99 #define STE 0x40 #define STF 0x20 #define RST 0x10 #define BRW 0x08 #define BK2F 0x04 #define BK1F 0x02 #define SWBRK 0x20 #define SWBKF 0x10 #define STALL 0x08 #define FLUSH 0x01 #define FLASH_CR1_STM8S 0x505A #define FLASH_CR2_STM8S 0x505B #define FLASH_NCR2_STM8S 0x505C #define FLASH_IAPSR_STM8S 0x505F #define FLASH_PUKR_STM8S 0x5062 #define FLASH_DUKR_STM8S 0x5064 #define FLASH_CR1_STM8L 0x5050 #define FLASH_CR2_STM8L 0x5051 #define FLASH_NCR2_STM8L 0 #define FLASH_PUKR_STM8L 0x5052 #define FLASH_DUKR_STM8L 0x5053 #define FLASH_IAPSR_STM8L 0x5054 /* FLASH_IAPSR */ #define HVOFF 0x40 #define DUL 0x08 #define EOP 0x04 #define PUL 0x02 #define WR_PG_DIS 0x01 /* FLASH_CR2 */ #define OPT 0x80 #define WPRG 0x40 #define ERASE 0x20 #define FPRG 0x10 #define PRG 0x01 /* SWIM_CSR */ #define SAFE_MASK 0x80 #define NO_ACCESS 0x40 #define SWIM_DM 0x20 #define HS 0x10 #define OSCOFF 0x08 #define SWIM_RST 0x04 #define HSIT 0x02 #define PRI 0x01 #define SWIM_CSR 0x7f80 #define STM8_BREAK 0x8B enum mem_type { RAM, FLASH, EEPROM, OPTION }; struct stm8_algorithm { int common_magic; }; struct stm8_core_reg { uint32_t num; struct target *target; }; enum hw_break_type { /* break on execute */ HWBRK_EXEC, /* break on read */ HWBRK_RD, /* break on write */ HWBRK_WR, /* break on read, write and execute */ HWBRK_ACC }; struct stm8_comparator { bool used; uint32_t bp_value; uint32_t reg_address; enum hw_break_type type; }; static int stm8_adapter_read_memory(struct target *target, uint32_t addr, int size, int count, void *buf) { return swim_read_mem(addr, size, count, buf); } static int stm8_adapter_write_memory(struct target *target, uint32_t addr, int size, int count, const void *buf) { return swim_write_mem(addr, size, count, buf); } static int stm8_write_u8(struct target *target, uint32_t addr, uint8_t val) { uint8_t buf[1]; buf[0] = val; return swim_write_mem(addr, 1, 1, buf); } static int stm8_read_u8(struct target *target, uint32_t addr, uint8_t *val) { return swim_read_mem(addr, 1, 1, val); } /* <enable == 0> Disables interrupts. If interrupts are enabled they are masked and the cc register is saved. <enable == 1> Enables interrupts. Enable interrupts is actually restoring I1 I0 state from previous call with enable == 0. Note that if stepping and breaking on a sim instruction will NOT work since the interrupt flags are restored on debug_entry. We don't have any way for the debugger to exclusively disable the interrupts */ static int stm8_enable_interrupts(struct target *target, int enable) { struct stm8_common *stm8 = target_to_stm8(target); uint8_t cc; if (enable) { if (!stm8->cc_valid) return ERROR_OK; /* cc was not stashed */ /* fetch current cc */ stm8_read_u8(target, DM_REG_CC, &cc); /* clear I1 I0 */ cc &= ~(CC_I0 + CC_I1); /* restore I1 & I0 from stash*/ cc |= (stm8->cc & (CC_I0+CC_I1)); /* update current cc */ stm8_write_u8(target, DM_REG_CC, cc); stm8->cc_valid = false; } else { stm8_read_u8(target, DM_REG_CC, &cc); if ((cc & CC_I0) && (cc & CC_I1)) return ERROR_OK; /* interrupts already masked */ /* stash cc */ stm8->cc = cc; stm8->cc_valid = true; /* mask interrupts (disable) */ cc |= (CC_I0 + CC_I1); stm8_write_u8(target, DM_REG_CC, cc); } return ERROR_OK; } static int stm8_set_hwbreak(struct target *target, struct stm8_comparator comparator_list[]) { uint8_t buf[3]; int i, ret; /* Refer to Table 4 in UM0470 */ uint8_t bc = 0x5; uint8_t bir = 0; uint8_t biw = 0; uint32_t data; uint32_t addr; if (!comparator_list[0].used) { comparator_list[0].type = HWBRK_EXEC; comparator_list[0].bp_value = -1; } if (!comparator_list[1].used) { comparator_list[1].type = HWBRK_EXEC; comparator_list[1].bp_value = -1; } if ((comparator_list[0].type == HWBRK_EXEC) && (comparator_list[1].type == HWBRK_EXEC)) { comparator_list[0].reg_address = 0; comparator_list[1].reg_address = 1; } if ((comparator_list[0].type == HWBRK_EXEC) && (comparator_list[1].type != HWBRK_EXEC)) { comparator_list[0].reg_address = 0; comparator_list[1].reg_address = 1; switch (comparator_list[1].type) { case HWBRK_RD: bir = 1; break; case HWBRK_WR: biw = 1; break; default: bir = 1; biw = 1; break; } } if ((comparator_list[1].type == HWBRK_EXEC) && (comparator_list[0].type != HWBRK_EXEC)) { comparator_list[0].reg_address = 1; comparator_list[1].reg_address = 0; switch (comparator_list[0].type) { case HWBRK_RD: bir = 1; break; case HWBRK_WR: biw = 1; break; default: bir = 1; biw = 1; break; } } if ((comparator_list[0].type != HWBRK_EXEC) && (comparator_list[1].type != HWBRK_EXEC)) { if (comparator_list[0].type != comparator_list[1].type) { LOG_ERROR("data hw breakpoints must be of same type"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } for (i = 0; i < 2; i++) { data = comparator_list[i].bp_value; addr = comparator_list[i].reg_address; buf[0] = data >> 16; buf[1] = data >> 8; buf[2] = data; if (addr == 0) { ret = stm8_adapter_write_memory(target, DM_BKR1E, 1, 3, buf); LOG_DEBUG("DM_BKR1E=%" PRIx32, data); } else if (addr == 1) { ret = stm8_adapter_write_memory(target, DM_BKR2E, 1, 3, buf); LOG_DEBUG("DM_BKR2E=%" PRIx32, data); } else { LOG_DEBUG("addr=%" PRIu32, addr); return ERROR_FAIL; } if (ret != ERROR_OK) return ret; ret = stm8_write_u8(target, DM_CR1, (bc << 3) + (bir << 2) + (biw << 1)); LOG_DEBUG("DM_CR1=%" PRIx8, buf[0]); if (ret != ERROR_OK) return ret; } return ERROR_OK; } /* read DM control and status regs */ static int stm8_read_dm_csrx(struct target *target, uint8_t *csr1, uint8_t *csr2) { int ret; uint8_t buf[2]; ret = stm8_adapter_read_memory(target, DM_CSR1, 1, sizeof(buf), buf); if (ret != ERROR_OK) return ret; if (csr1) *csr1 = buf[0]; if (csr2) *csr2 = buf[1]; return ERROR_OK; } /* set or clear the single step flag in DM */ static int stm8_config_step(struct target *target, int enable) { int ret; uint8_t csr1, csr2; ret = stm8_read_dm_csrx(target, &csr1, &csr2); if (ret != ERROR_OK) return ret; if (enable) csr1 |= STE; else csr1 &= ~STE; ret = stm8_write_u8(target, DM_CSR1, csr1); if (ret != ERROR_OK) return ret; return ERROR_OK; } /* set the stall flag in DM */ static int stm8_debug_stall(struct target *target) { int ret; uint8_t csr1, csr2; ret = stm8_read_dm_csrx(target, &csr1, &csr2); if (ret != ERROR_OK) return ret; csr2 |= STALL; ret = stm8_write_u8(target, DM_CSR2, csr2); if (ret != ERROR_OK) return ret; return ERROR_OK; } static int stm8_configure_break_unit(struct target *target) { /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); if (stm8->bp_scanned) return ERROR_OK; stm8->num_hw_bpoints = 2; stm8->num_hw_bpoints_avail = stm8->num_hw_bpoints; stm8->hw_break_list = calloc(stm8->num_hw_bpoints, sizeof(struct stm8_comparator)); stm8->hw_break_list[0].reg_address = 0; stm8->hw_break_list[1].reg_address = 1; LOG_DEBUG("hw breakpoints: numinst %i numdata %i", stm8->num_hw_bpoints, stm8->num_hw_bpoints); stm8->bp_scanned = true; return ERROR_OK; } static int stm8_examine_debug_reason(struct target *target) { int retval; uint8_t csr1, csr2; retval = stm8_read_dm_csrx(target, &csr1, &csr2); if (retval == ERROR_OK) LOG_DEBUG("csr1 = 0x%02X csr2 = 0x%02X", csr1, csr2); if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) { if (retval != ERROR_OK) return retval; if (csr1 & RST) /* halted on reset */ target->debug_reason = DBG_REASON_UNDEFINED; if (csr1 & (BK1F+BK2F)) /* we have halted on a breakpoint (or wp)*/ target->debug_reason = DBG_REASON_BREAKPOINT; if (csr2 & SWBKF) /* we have halted on a breakpoint */ target->debug_reason = DBG_REASON_BREAKPOINT; } return ERROR_OK; } static int stm8_debug_entry(struct target *target) { struct stm8_common *stm8 = target_to_stm8(target); /* restore interrupts */ stm8_enable_interrupts(target, 1); stm8_save_context(target); /* make sure stepping disabled STE bit in CSR1 cleared */ stm8_config_step(target, 0); /* attempt to find halt reason */ stm8_examine_debug_reason(target); LOG_DEBUG("entered debug state at PC 0x%" PRIx32 ", target->state: %s", buf_get_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32), target_state_name(target)); return ERROR_OK; } /* clear stall flag in DM and flush instruction pipe */ static int stm8_exit_debug(struct target *target) { int ret; uint8_t csr1, csr2; ret = stm8_read_dm_csrx(target, &csr1, &csr2); if (ret != ERROR_OK) return ret; csr2 |= FLUSH; ret = stm8_write_u8(target, DM_CSR2, csr2); if (ret != ERROR_OK) return ret; csr2 &= ~STALL; csr2 |= SWBRK; ret = stm8_write_u8(target, DM_CSR2, csr2); if (ret != ERROR_OK) return ret; return ERROR_OK; } static int stm8_read_regs(struct target *target, uint32_t regs[]) { int ret; uint8_t buf[11]; ret = stm8_adapter_read_memory(target, DM_REGS, 1, sizeof(buf), buf); if (ret != ERROR_OK) return ret; regs[0] = be_to_h_u24(buf+DM_REG_PC-DM_REGS); regs[1] = buf[DM_REG_A-DM_REGS]; regs[2] = be_to_h_u16(buf+DM_REG_X-DM_REGS); regs[3] = be_to_h_u16(buf+DM_REG_Y-DM_REGS); regs[4] = be_to_h_u16(buf+DM_REG_SP-DM_REGS); regs[5] = buf[DM_REG_CC-DM_REGS]; return ERROR_OK; } static int stm8_write_regs(struct target *target, uint32_t regs[]) { int ret; uint8_t buf[11]; h_u24_to_be(buf+DM_REG_PC-DM_REGS, regs[0]); buf[DM_REG_A-DM_REGS] = regs[1]; h_u16_to_be(buf+DM_REG_X-DM_REGS, regs[2]); h_u16_to_be(buf+DM_REG_Y-DM_REGS, regs[3]); h_u16_to_be(buf+DM_REG_SP-DM_REGS, regs[4]); buf[DM_REG_CC-DM_REGS] = regs[5]; ret = stm8_adapter_write_memory(target, DM_REGS, 1, sizeof(buf), buf); if (ret != ERROR_OK) return ret; return ERROR_OK; } static int stm8_get_core_reg(struct reg *reg) { int retval; struct stm8_core_reg *stm8_reg = reg->arch_info; struct target *target = stm8_reg->target; struct stm8_common *stm8 = target_to_stm8(target); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = stm8->read_core_reg(target, stm8_reg->num); return retval; } static int stm8_set_core_reg(struct reg *reg, uint8_t *buf) { struct stm8_core_reg *stm8_reg = reg->arch_info; struct target *target = stm8_reg->target; uint32_t value = buf_get_u32(buf, 0, reg->size); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; buf_set_u32(reg->value, 0, 32, value); reg->dirty = true; reg->valid = true; return ERROR_OK; } static int stm8_save_context(struct target *target) { unsigned int i; /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); /* read core registers */ stm8_read_regs(target, stm8->core_regs); for (i = 0; i < STM8_NUM_REGS; i++) { if (!stm8->core_cache->reg_list[i].valid) stm8->read_core_reg(target, i); } return ERROR_OK; } static int stm8_restore_context(struct target *target) { unsigned int i; /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); for (i = 0; i < STM8_NUM_REGS; i++) { if (stm8->core_cache->reg_list[i].dirty) stm8->write_core_reg(target, i); } /* write core regs */ stm8_write_regs(target, stm8->core_regs); return ERROR_OK; } static int stm8_unlock_flash(struct target *target) { uint8_t data[1]; struct stm8_common *stm8 = target_to_stm8(target); /* check if flash is unlocked */ stm8_read_u8(target, stm8->flash_iapsr, data); if (~data[0] & PUL) { /* unlock flash */ stm8_write_u8(target, stm8->flash_pukr, 0x56); stm8_write_u8(target, stm8->flash_pukr, 0xae); } stm8_read_u8(target, stm8->flash_iapsr, data); if (~data[0] & PUL) return ERROR_FAIL; return ERROR_OK; } static int stm8_unlock_eeprom(struct target *target) { uint8_t data[1]; struct stm8_common *stm8 = target_to_stm8(target); /* check if eeprom is unlocked */ stm8_read_u8(target, stm8->flash_iapsr, data); if (~data[0] & DUL) { /* unlock eeprom */ stm8_write_u8(target, stm8->flash_dukr, 0xae); stm8_write_u8(target, stm8->flash_dukr, 0x56); } stm8_read_u8(target, stm8->flash_iapsr, data); if (~data[0] & DUL) return ERROR_FAIL; return ERROR_OK; } static int stm8_write_flash(struct target *target, enum mem_type type, uint32_t address, uint32_t size, uint32_t count, uint32_t blocksize_param, const uint8_t *buffer) { struct stm8_common *stm8 = target_to_stm8(target); uint8_t iapsr; uint8_t opt = 0; unsigned int i; uint32_t blocksize = 0; uint32_t bytecnt; int res; switch (type) { case (FLASH): stm8_unlock_flash(target); break; case (EEPROM): stm8_unlock_eeprom(target); break; case (OPTION): stm8_unlock_eeprom(target); opt = OPT; break; default: LOG_ERROR("BUG: wrong mem_type %d", type); assert(0); } if (size == 2) { /* we don't support short writes */ count = count * 2; size = 1; } bytecnt = count * size; while (bytecnt) { if ((bytecnt >= blocksize_param) && ((address & (blocksize_param-1)) == 0)) { if (stm8->flash_cr2) stm8_write_u8(target, stm8->flash_cr2, PRG + opt); if (stm8->flash_ncr2) stm8_write_u8(target, stm8->flash_ncr2, ~(PRG + opt)); blocksize = blocksize_param; } else if ((bytecnt >= 4) && ((address & 0x3) == 0)) { if (stm8->flash_cr2) stm8_write_u8(target, stm8->flash_cr2, WPRG + opt); if (stm8->flash_ncr2) stm8_write_u8(target, stm8->flash_ncr2, ~(WPRG + opt)); blocksize = 4; } else if (blocksize != 1) { if (stm8->flash_cr2) stm8_write_u8(target, stm8->flash_cr2, opt); if (stm8->flash_ncr2) stm8_write_u8(target, stm8->flash_ncr2, ~opt); blocksize = 1; } res = stm8_adapter_write_memory(target, address, 1, blocksize, buffer); if (res != ERROR_OK) return res; address += blocksize; buffer += blocksize; bytecnt -= blocksize; /* lets hang here until end of program (EOP) */ for (i = 0; i < 16; i++) { stm8_read_u8(target, stm8->flash_iapsr, &iapsr); if (iapsr & EOP) break; else usleep(1000); } if (i == 16) return ERROR_FAIL; } /* disable write access */ res = stm8_write_u8(target, stm8->flash_iapsr, 0x0); if (res != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int stm8_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct stm8_common *stm8 = target_to_stm8(target); LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); if (target->state != TARGET_HALTED) LOG_WARNING("target not halted"); int retval; if ((address >= stm8->flashstart) && (address <= stm8->flashend)) retval = stm8_write_flash(target, FLASH, address, size, count, stm8->blocksize, buffer); else if ((address >= stm8->eepromstart) && (address <= stm8->eepromend)) retval = stm8_write_flash(target, EEPROM, address, size, count, stm8->blocksize, buffer); else if ((address >= stm8->optionstart) && (address <= stm8->optionend)) retval = stm8_write_flash(target, OPTION, address, size, count, 0, buffer); else retval = stm8_adapter_write_memory(target, address, size, count, buffer); if (retval != ERROR_OK) return ERROR_TARGET_FAILURE; return retval; } static int stm8_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); if (target->state != TARGET_HALTED) LOG_WARNING("target not halted"); int retval; retval = stm8_adapter_read_memory(target, address, size, count, buffer); if (retval != ERROR_OK) return ERROR_TARGET_FAILURE; return retval; } static int stm8_speed(int speed) { int retval; uint8_t csr; LOG_DEBUG("stm8_speed: %d", speed); csr = SAFE_MASK | SWIM_DM; if (speed >= SWIM_FREQ_HIGH) csr |= HS; LOG_DEBUG("writing B0 to SWIM_CSR (SAFE_MASK + SWIM_DM + HS:%d)", csr & HS ? 1 : 0); retval = stm8_write_u8(NULL, SWIM_CSR, csr); if (retval != ERROR_OK) return retval; return adapter_speed(speed); } static int stm8_init(struct command_context *cmd_ctx, struct target *target) { /* * FIXME: this is a temporarily hack that needs better implementation. * Being the only overwrite of adapter_driver, it prevents declaring const * the struct adapter_driver. * intercept adapter_driver->speed() calls */ adapter_speed = adapter_driver->speed; adapter_driver->speed = stm8_speed; stm8_build_reg_cache(target); return ERROR_OK; } static int stm8_poll(struct target *target) { int retval = ERROR_OK; uint8_t csr1, csr2; #ifdef LOG_STM8 LOG_DEBUG("target->state=%d", target->state); #endif /* read dm_csrx control regs */ retval = stm8_read_dm_csrx(target, &csr1, &csr2); if (retval != ERROR_OK) { LOG_DEBUG("stm8_read_dm_csrx failed retval=%d", retval); /* We return ERROR_OK here even if we didn't get an answer. openocd will call target_wait_state until we get target state TARGET_HALTED */ return ERROR_OK; } /* check for processor halted */ if (csr2 & STALL) { if (target->state != TARGET_HALTED) { if (target->state == TARGET_UNKNOWN) LOG_DEBUG("DM_CSR2_STALL already set during server startup."); retval = stm8_debug_entry(target); if (retval != ERROR_OK) { LOG_DEBUG("stm8_debug_entry failed retval=%d", retval); return ERROR_TARGET_FAILURE; } if (target->state == TARGET_DEBUG_RUNNING) { target->state = TARGET_HALTED; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } else { target->state = TARGET_HALTED; target_call_event_callbacks(target, TARGET_EVENT_HALTED); } } } else target->state = TARGET_RUNNING; #ifdef LOG_STM8 LOG_DEBUG("csr1 = 0x%02X csr2 = 0x%02X", csr1, csr2); #endif return ERROR_OK; } static int stm8_halt(struct target *target) { LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); if (target->state == TARGET_RESET) { /* we came here in a reset_halt or reset_init sequence * debug entry was already prepared in stm8_assert_reset() */ target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } /* break processor */ stm8_debug_stall(target); target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int stm8_reset_assert(struct target *target) { int res = ERROR_OK; struct stm8_common *stm8 = target_to_stm8(target); bool use_srst_fallback = true; enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_HAS_SRST) { res = adapter_assert_reset(); if (res == ERROR_OK) /* hardware srst supported */ use_srst_fallback = false; else if (res != ERROR_COMMAND_NOTFOUND) /* some other failure */ return res; } if (use_srst_fallback) { LOG_DEBUG("Hardware srst not supported, falling back to swim reset"); res = swim_system_reset(); if (res != ERROR_OK) return res; } /* registers are now invalid */ register_cache_invalidate(stm8->core_cache); target->state = TARGET_RESET; target->debug_reason = DBG_REASON_NOTHALTED; if (target->reset_halt) { res = target_halt(target); if (res != ERROR_OK) return res; } return ERROR_OK; } static int stm8_reset_deassert(struct target *target) { int res; enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_HAS_SRST) { res = adapter_deassert_reset(); if ((res != ERROR_OK) && (res != ERROR_COMMAND_NOTFOUND)) return res; } /* The cpu should now be stalled. If halt was requested let poll detect the stall */ if (target->reset_halt) return ERROR_OK; /* Instead of going through saving context, polling and then resuming target again just clear stall and proceed. */ target->state = TARGET_RUNNING; return stm8_exit_debug(target); } /* stm8_single_step_core() is only used for stepping over breakpoints from stm8_resume() */ static int stm8_single_step_core(struct target *target) { struct stm8_common *stm8 = target_to_stm8(target); /* configure single step mode */ stm8_config_step(target, 1); /* disable interrupts while stepping */ if (!stm8->enable_step_irq) stm8_enable_interrupts(target, 0); /* exit debug mode */ stm8_exit_debug(target); stm8_debug_entry(target); return ERROR_OK; } static int stm8_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { struct stm8_common *stm8 = target_to_stm8(target); struct breakpoint *breakpoint = NULL; uint32_t resume_pc; LOG_DEBUG("%d " TARGET_ADDR_FMT " %d %d", current, address, handle_breakpoints, debug_execution); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) { target_free_all_working_areas(target); stm8_enable_breakpoints(target); stm8_enable_watchpoints(target); struct stm8_comparator *comparator_list = stm8->hw_break_list; stm8_set_hwbreak(target, comparator_list); } /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32, address); stm8->core_cache->reg_list[STM8_PC].dirty = true; stm8->core_cache->reg_list[STM8_PC].valid = true; } if (!current) resume_pc = address; else resume_pc = buf_get_u32( stm8->core_cache->reg_list[STM8_PC].value, 0, 32); stm8_restore_context(target); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT, breakpoint->address); stm8_unset_breakpoint(target, breakpoint); stm8_single_step_core(target); stm8_set_breakpoint(target, breakpoint); } } /* disable interrupts if we are debugging */ if (debug_execution) stm8_enable_interrupts(target, 0); /* exit debug mode */ stm8_exit_debug(target); target->debug_reason = DBG_REASON_NOTHALTED; /* registers are now invalid */ register_cache_invalidate(stm8->core_cache); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); } return ERROR_OK; } static int stm8_init_flash_regs(bool enable_stm8l, struct stm8_common *stm8) { stm8->enable_stm8l = enable_stm8l; if (stm8->enable_stm8l) { stm8->flash_cr2 = FLASH_CR2_STM8L; stm8->flash_ncr2 = FLASH_NCR2_STM8L; stm8->flash_iapsr = FLASH_IAPSR_STM8L; stm8->flash_dukr = FLASH_DUKR_STM8L; stm8->flash_pukr = FLASH_PUKR_STM8L; } else { stm8->flash_cr2 = FLASH_CR2_STM8S; stm8->flash_ncr2 = FLASH_NCR2_STM8S; stm8->flash_iapsr = FLASH_IAPSR_STM8S; stm8->flash_dukr = FLASH_DUKR_STM8S; stm8->flash_pukr = FLASH_PUKR_STM8S; } return ERROR_OK; } static int stm8_init_arch_info(struct target *target, struct stm8_common *stm8, struct jtag_tap *tap) { target->endianness = TARGET_BIG_ENDIAN; target->arch_info = stm8; stm8->common_magic = STM8_COMMON_MAGIC; stm8->fast_data_area = NULL; stm8->blocksize = 0x80; stm8->flashstart = 0x8000; stm8->flashend = 0xffff; stm8->eepromstart = 0x4000; stm8->eepromend = 0x43ff; stm8->optionstart = 0x4800; stm8->optionend = 0x487F; /* has breakpoint/watchpoint unit been scanned */ stm8->bp_scanned = false; stm8->hw_break_list = NULL; stm8->read_core_reg = stm8_read_core_reg; stm8->write_core_reg = stm8_write_core_reg; stm8_init_flash_regs(0, stm8); return ERROR_OK; } static int stm8_target_create(struct target *target, Jim_Interp *interp) { struct stm8_common *stm8 = calloc(1, sizeof(struct stm8_common)); stm8_init_arch_info(target, stm8, target->tap); stm8_configure_break_unit(target); return ERROR_OK; } static int stm8_read_core_reg(struct target *target, unsigned int num) { uint32_t reg_value; /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); if (num >= STM8_NUM_REGS) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = stm8->core_regs[num]; LOG_DEBUG("read core reg %i value 0x%" PRIx32 "", num, reg_value); buf_set_u32(stm8->core_cache->reg_list[num].value, 0, 32, reg_value); stm8->core_cache->reg_list[num].valid = true; stm8->core_cache->reg_list[num].dirty = false; return ERROR_OK; } static int stm8_write_core_reg(struct target *target, unsigned int num) { uint32_t reg_value; /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); if (num >= STM8_NUM_REGS) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = buf_get_u32(stm8->core_cache->reg_list[num].value, 0, 32); stm8->core_regs[num] = reg_value; LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value); stm8->core_cache->reg_list[num].valid = true; stm8->core_cache->reg_list[num].dirty = false; return ERROR_OK; } static const char *stm8_get_gdb_arch(struct target *target) { return "stm8"; } static int stm8_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); unsigned int i; *reg_list_size = STM8_NUM_REGS; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < STM8_NUM_REGS; i++) (*reg_list)[i] = &stm8->core_cache->reg_list[i]; return ERROR_OK; } static const struct reg_arch_type stm8_reg_type = { .get = stm8_get_core_reg, .set = stm8_set_core_reg, }; static struct reg_cache *stm8_build_reg_cache(struct target *target) { /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); int num_regs = STM8_NUM_REGS; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); struct stm8_core_reg *arch_info = malloc( sizeof(struct stm8_core_reg) * num_regs); struct reg_feature *feature; int i; /* Build the process context cache */ cache->name = "stm8 registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = num_regs; (*cache_p) = cache; stm8->core_cache = cache; for (i = 0; i < num_regs; i++) { arch_info[i].num = stm8_regs[i].id; arch_info[i].target = target; reg_list[i].name = stm8_regs[i].name; reg_list[i].size = stm8_regs[i].bits; reg_list[i].value = calloc(1, 4); reg_list[i].valid = false; reg_list[i].type = &stm8_reg_type; reg_list[i].arch_info = &arch_info[i]; reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); if (reg_list[i].reg_data_type) reg_list[i].reg_data_type->type = stm8_regs[i].type; else { LOG_ERROR("unable to allocate reg type list"); return NULL; } reg_list[i].dirty = false; reg_list[i].group = stm8_regs[i].group; reg_list[i].number = stm8_regs[i].id; reg_list[i].exist = true; reg_list[i].caller_save = true; /* gdb defaults to true */ feature = calloc(1, sizeof(struct reg_feature)); if (feature) { feature->name = stm8_regs[i].feature; reg_list[i].feature = feature; } else LOG_ERROR("unable to allocate feature list"); } return cache; } static void stm8_free_reg_cache(struct target *target) { struct stm8_common *stm8 = target_to_stm8(target); struct reg_cache *cache; struct reg *reg; unsigned int i; cache = stm8->core_cache; if (!cache) return; for (i = 0; i < cache->num_regs; i++) { reg = &cache->reg_list[i]; free(reg->feature); free(reg->reg_data_type); free(reg->value); } free(cache->reg_list[0].arch_info); free(cache->reg_list); free(cache); stm8->core_cache = NULL; } static void stm8_deinit(struct target *target) { struct stm8_common *stm8 = target_to_stm8(target); free(stm8->hw_break_list); stm8_free_reg_cache(target); free(stm8); } static int stm8_arch_state(struct target *target) { struct stm8_common *stm8 = target_to_stm8(target); LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32 "", debug_reason_name(target), buf_get_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32)); return ERROR_OK; } static int stm8_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { LOG_DEBUG("%x " TARGET_ADDR_FMT " %x", current, address, handle_breakpoints); /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); struct breakpoint *breakpoint = NULL; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32, address); stm8->core_cache->reg_list[STM8_PC].dirty = true; stm8->core_cache->reg_list[STM8_PC].valid = true; } /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { breakpoint = breakpoint_find(target, buf_get_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32)); if (breakpoint) stm8_unset_breakpoint(target, breakpoint); } /* restore context */ stm8_restore_context(target); /* configure single step mode */ stm8_config_step(target, 1); target->debug_reason = DBG_REASON_SINGLESTEP; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); /* disable interrupts while stepping */ if (!stm8->enable_step_irq) stm8_enable_interrupts(target, 0); /* exit debug mode */ stm8_exit_debug(target); /* registers are now invalid */ register_cache_invalidate(stm8->core_cache); LOG_DEBUG("target stepped "); stm8_debug_entry(target); if (breakpoint) stm8_set_breakpoint(target, breakpoint); target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } static void stm8_enable_breakpoints(struct target *target) { struct breakpoint *breakpoint = target->breakpoints; /* set any pending breakpoints */ while (breakpoint) { if (!breakpoint->is_set) stm8_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } } static int stm8_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct stm8_common *stm8 = target_to_stm8(target); struct stm8_comparator *comparator_list = stm8->hw_break_list; int retval; if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { int bp_num = 0; while (comparator_list[bp_num].used && (bp_num < stm8->num_hw_bpoints)) bp_num++; if (bp_num >= stm8->num_hw_bpoints) { LOG_ERROR("Can not find free breakpoint register (bpid: %" PRIu32 ")", breakpoint->unique_id); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint_hw_set(breakpoint, bp_num); comparator_list[bp_num].used = true; comparator_list[bp_num].bp_value = breakpoint->address; comparator_list[bp_num].type = HWBRK_EXEC; retval = stm8_set_hwbreak(target, comparator_list); if (retval != ERROR_OK) return retval; LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx32 "", breakpoint->unique_id, bp_num, comparator_list[bp_num].bp_value); } else if (breakpoint->type == BKPT_SOFT) { LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); if (breakpoint->length == 1) { uint8_t verify = 0x55; retval = target_read_u8(target, breakpoint->address, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, breakpoint->address, STM8_BREAK); if (retval != ERROR_OK) return retval; retval = target_read_u8(target, breakpoint->address, &verify); if (retval != ERROR_OK) return retval; if (verify != STM8_BREAK) { LOG_ERROR("Unable to set breakpoint at address " TARGET_ADDR_FMT " - check that memory is read/writable", breakpoint->address); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } else { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint->is_set = true; } return ERROR_OK; } static int stm8_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct stm8_common *stm8 = target_to_stm8(target); int ret; if (breakpoint->type == BKPT_HARD) { if (stm8->num_hw_bpoints_avail < 1) { LOG_INFO("no hardware breakpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } ret = stm8_set_breakpoint(target, breakpoint); if (ret != ERROR_OK) return ret; stm8->num_hw_bpoints_avail--; return ERROR_OK; } ret = stm8_set_breakpoint(target, breakpoint); if (ret != ERROR_OK) return ret; return ERROR_OK; } static int stm8_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); struct stm8_comparator *comparator_list = stm8->hw_break_list; int retval; if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { int bp_num = breakpoint->number; if (bp_num >= stm8->num_hw_bpoints) { LOG_DEBUG("Invalid comparator number in breakpoint (bpid: %" PRIu32 ")", breakpoint->unique_id); return ERROR_OK; } LOG_DEBUG("bpid: %" PRIu32 " - releasing hw: %d", breakpoint->unique_id, bp_num); comparator_list[bp_num].used = false; retval = stm8_set_hwbreak(target, comparator_list); if (retval != ERROR_OK) return retval; } else { /* restore original instruction (kept in target endianness) */ LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); if (breakpoint->length == 1) { uint8_t current_instr; /* check that user program has not modified breakpoint instruction */ retval = target_read_memory(target, breakpoint->address, 1, 1, (uint8_t *)¤t_instr); if (retval != ERROR_OK) return retval; if (current_instr == STM8_BREAK) { retval = target_write_memory(target, breakpoint->address, 1, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } } else return ERROR_FAIL; } breakpoint->is_set = false; return ERROR_OK; } static int stm8_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (breakpoint->is_set) stm8_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) stm8->num_hw_bpoints_avail++; return ERROR_OK; } static int stm8_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct stm8_common *stm8 = target_to_stm8(target); struct stm8_comparator *comparator_list = stm8->hw_break_list; int wp_num = 0; int ret; if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } while (comparator_list[wp_num].used && (wp_num < stm8->num_hw_bpoints)) wp_num++; if (wp_num >= stm8->num_hw_bpoints) { LOG_ERROR("Can not find free hw breakpoint"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (watchpoint->length != 1) { LOG_ERROR("Only watchpoints of length 1 are supported"); return ERROR_TARGET_UNALIGNED_ACCESS; } enum hw_break_type enable = 0; switch (watchpoint->rw) { case WPT_READ: enable = HWBRK_RD; break; case WPT_WRITE: enable = HWBRK_WR; break; case WPT_ACCESS: enable = HWBRK_ACC; break; default: LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } comparator_list[wp_num].used = true; comparator_list[wp_num].bp_value = watchpoint->address; comparator_list[wp_num].type = enable; ret = stm8_set_hwbreak(target, comparator_list); if (ret != ERROR_OK) { comparator_list[wp_num].used = false; return ret; } watchpoint_set(watchpoint, wp_num); LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "", wp_num, comparator_list[wp_num].bp_value); return ERROR_OK; } static int stm8_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { int ret; struct stm8_common *stm8 = target_to_stm8(target); if (stm8->num_hw_bpoints_avail < 1) { LOG_INFO("no hardware watchpoints available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } ret = stm8_set_watchpoint(target, watchpoint); if (ret != ERROR_OK) return ret; stm8->num_hw_bpoints_avail--; return ERROR_OK; } static void stm8_enable_watchpoints(struct target *target) { struct watchpoint *watchpoint = target->watchpoints; /* set any pending watchpoints */ while (watchpoint) { if (!watchpoint->is_set) stm8_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } } static int stm8_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); struct stm8_comparator *comparator_list = stm8->hw_break_list; if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } int wp_num = watchpoint->number; if (wp_num >= stm8->num_hw_bpoints) { LOG_DEBUG("Invalid hw comparator number in watchpoint"); return ERROR_OK; } comparator_list[wp_num].used = false; watchpoint->is_set = false; stm8_set_hwbreak(target, comparator_list); return ERROR_OK; } static int stm8_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (watchpoint->is_set) stm8_unset_watchpoint(target, watchpoint); stm8->num_hw_bpoints_avail++; return ERROR_OK; } static int stm8_examine(struct target *target) { int retval; uint8_t csr1, csr2; /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); enum reset_types jtag_reset_config = jtag_get_reset_config(); if (!target_was_examined(target)) { if (!stm8->swim_configured) { stm8->swim_configured = true; /* Now is the time to deassert reset if connect_under_reset. Releasing reset line will cause the option bytes to load. The core will still be stalled. */ if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) stm8_reset_deassert(target); else LOG_WARNING("\'srst_nogate\' reset_config option is required"); } } else { LOG_INFO("trying to reconnect"); retval = swim_reconnect(); if (retval != ERROR_OK) { LOG_ERROR("reconnect failed"); return ERROR_FAIL; } /* read dm_csrx control regs */ retval = stm8_read_dm_csrx(target, &csr1, &csr2); if (retval != ERROR_OK) { LOG_ERROR("state query failed"); return ERROR_FAIL; } } target_set_examined(target); return ERROR_OK; } return ERROR_OK; } /** Checks whether a memory region is erased. */ static int stm8_blank_check_memory(struct target *target, struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value) { struct working_area *erase_check_algorithm; struct reg_param reg_params[2]; struct mem_param mem_params[2]; struct stm8_algorithm stm8_info; static const uint8_t stm8_erase_check_code[] = { #include "../../contrib/loaders/erase_check/stm8_erase_check.inc" }; if (erased_value != 0xff) { LOG_ERROR("Erase value 0x%02" PRIx8 " not yet supported for STM8", erased_value); return ERROR_FAIL; } /* make sure we have a working area */ if (target_alloc_working_area(target, sizeof(stm8_erase_check_code), &erase_check_algorithm) != ERROR_OK) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; target_write_buffer(target, erase_check_algorithm->address, sizeof(stm8_erase_check_code), stm8_erase_check_code); stm8_info.common_magic = STM8_COMMON_MAGIC; init_mem_param(&mem_params[0], 0x0, 3, PARAM_OUT); buf_set_u32(mem_params[0].value, 0, 24, blocks[0].address); init_mem_param(&mem_params[1], 0x3, 3, PARAM_OUT); buf_set_u32(mem_params[1].value, 0, 24, blocks[0].size); init_reg_param(®_params[0], "a", 32, PARAM_IN_OUT); buf_set_u32(reg_params[0].value, 0, 32, erased_value); init_reg_param(®_params[1], "sp", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, erase_check_algorithm->address); int retval = target_run_algorithm(target, 2, mem_params, 2, reg_params, erase_check_algorithm->address + 6, erase_check_algorithm->address + (sizeof(stm8_erase_check_code) - 1), 10000, &stm8_info); if (retval == ERROR_OK) blocks[0].result = (*(reg_params[0].value) == 0xff); destroy_mem_param(&mem_params[0]); destroy_mem_param(&mem_params[1]); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); target_free_working_area(target, erase_check_algorithm); if (retval != ERROR_OK) return retval; return 1; /* only one block has been checked */ } static int stm8_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { /* let image_calculate_checksum() take care of business */ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* run to exit point. return error if exit point was not reached. */ static int stm8_run_and_wait(struct target *target, uint32_t entry_point, unsigned int timeout_ms, uint32_t exit_point, struct stm8_common *stm8) { uint32_t pc; int retval; /* This code relies on the target specific resume() and poll()->debug_entry() sequence to write register values to the processor and the read them back */ retval = target_resume(target, 0, entry_point, 0, 1); if (retval != ERROR_OK) return retval; retval = target_wait_state(target, TARGET_HALTED, timeout_ms); /* If the target fails to halt due to the breakpoint, force a halt */ if (retval != ERROR_OK || target->state != TARGET_HALTED) { retval = target_halt(target); if (retval != ERROR_OK) return retval; retval = target_wait_state(target, TARGET_HALTED, 500); if (retval != ERROR_OK) return retval; return ERROR_TARGET_TIMEOUT; } pc = buf_get_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32); if (exit_point && (pc != exit_point)) { LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 " ", pc); return ERROR_TARGET_TIMEOUT; } return ERROR_OK; } static int stm8_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { struct stm8_common *stm8 = target_to_stm8(target); uint32_t context[STM8_NUM_REGS]; int retval = ERROR_OK; LOG_DEBUG("Running algorithm"); /* NOTE: stm8_run_algorithm requires that each algorithm uses a software breakpoint at the exit point */ if (stm8->common_magic != STM8_COMMON_MAGIC) { LOG_ERROR("current target isn't a STM8 target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* refresh core register cache */ for (unsigned int i = 0; i < STM8_NUM_REGS; i++) { if (!stm8->core_cache->reg_list[i].valid) stm8->read_core_reg(target, i); context[i] = buf_get_u32(stm8->core_cache->reg_list[i].value, 0, 32); } for (int i = 0; i < num_mem_params; i++) { if (mem_params[i].direction == PARAM_IN) continue; retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } for (int i = 0; i < num_reg_params; i++) { if (reg_params[i].direction == PARAM_IN) continue; struct reg *reg = register_get_by_name(stm8->core_cache, reg_params[i].reg_name, false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg_params[i].size != 32) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } stm8_set_core_reg(reg, reg_params[i].value); } retval = stm8_run_and_wait(target, entry_point, timeout_ms, exit_point, stm8); if (retval != ERROR_OK) return retval; for (int i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) { retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } } for (int i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(stm8->core_cache, reg_params[i].reg_name, false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg_params[i].size != 32) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } /* restore everything we saved before */ for (unsigned int i = 0; i < STM8_NUM_REGS; i++) { uint32_t regvalue; regvalue = buf_get_u32(stm8->core_cache->reg_list[i].value, 0, 32); if (regvalue != context[i]) { LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, stm8->core_cache->reg_list[i].name, context[i]); buf_set_u32(stm8->core_cache->reg_list[i].value, 0, 32, context[i]); stm8->core_cache->reg_list[i].valid = true; stm8->core_cache->reg_list[i].dirty = true; } } return ERROR_OK; } static int stm8_jim_configure(struct target *target, struct jim_getopt_info *goi) { struct stm8_common *stm8 = target_to_stm8(target); jim_wide w; int e; const char *arg; arg = Jim_GetString(goi->argv[0], NULL); if (!strcmp(arg, "-blocksize")) { e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; if (goi->argc == 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-blocksize ?bytes? ..."); return JIM_ERR; } e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; stm8->blocksize = w; LOG_DEBUG("blocksize=%8.8" PRIx32, stm8->blocksize); return JIM_OK; } if (!strcmp(arg, "-flashstart")) { e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; if (goi->argc == 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-flashstart ?address? ..."); return JIM_ERR; } e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; stm8->flashstart = w; LOG_DEBUG("flashstart=%8.8" PRIx32, stm8->flashstart); return JIM_OK; } if (!strcmp(arg, "-flashend")) { e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; if (goi->argc == 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-flashend ?address? ..."); return JIM_ERR; } e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; stm8->flashend = w; LOG_DEBUG("flashend=%8.8" PRIx32, stm8->flashend); return JIM_OK; } if (!strcmp(arg, "-eepromstart")) { e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; if (goi->argc == 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-eepromstart ?address? ..."); return JIM_ERR; } e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; stm8->eepromstart = w; LOG_DEBUG("eepromstart=%8.8" PRIx32, stm8->eepromstart); return JIM_OK; } if (!strcmp(arg, "-eepromend")) { e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; if (goi->argc == 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-eepromend ?address? ..."); return JIM_ERR; } e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; stm8->eepromend = w; LOG_DEBUG("eepromend=%8.8" PRIx32, stm8->eepromend); return JIM_OK; } if (!strcmp(arg, "-optionstart")) { e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; if (goi->argc == 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-optionstart ?address? ..."); return JIM_ERR; } e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; stm8->optionstart = w; LOG_DEBUG("optionstart=%8.8" PRIx32, stm8->optionstart); return JIM_OK; } if (!strcmp(arg, "-optionend")) { e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; if (goi->argc == 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-optionend ?address? ..."); return JIM_ERR; } e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; stm8->optionend = w; LOG_DEBUG("optionend=%8.8" PRIx32, stm8->optionend); return JIM_OK; } if (!strcmp(arg, "-enable_step_irq")) { e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; stm8->enable_step_irq = true; LOG_DEBUG("enable_step_irq=%8.8x", stm8->enable_step_irq); return JIM_OK; } if (!strcmp(arg, "-enable_stm8l")) { e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; stm8->enable_stm8l = true; LOG_DEBUG("enable_stm8l=%8.8x", stm8->enable_stm8l); stm8_init_flash_regs(stm8->enable_stm8l, stm8); return JIM_OK; } return JIM_CONTINUE; } COMMAND_HANDLER(stm8_handle_enable_step_irq_command) { const char *msg; struct target *target = get_current_target(CMD_CTX); struct stm8_common *stm8 = target_to_stm8(target); bool enable = stm8->enable_step_irq; if (CMD_ARGC > 0) { COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable); stm8->enable_step_irq = enable; } msg = stm8->enable_step_irq ? "enabled" : "disabled"; command_print(CMD, "enable_step_irq = %s", msg); return ERROR_OK; } COMMAND_HANDLER(stm8_handle_enable_stm8l_command) { const char *msg; struct target *target = get_current_target(CMD_CTX); struct stm8_common *stm8 = target_to_stm8(target); bool enable = stm8->enable_stm8l; if (CMD_ARGC > 0) { COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable); stm8->enable_stm8l = enable; } msg = stm8->enable_stm8l ? "enabled" : "disabled"; command_print(CMD, "enable_stm8l = %s", msg); stm8_init_flash_regs(stm8->enable_stm8l, stm8); return ERROR_OK; } static const struct command_registration stm8_exec_command_handlers[] = { { .name = "enable_step_irq", .handler = stm8_handle_enable_step_irq_command, .mode = COMMAND_ANY, .help = "Enable/disable irq handling during step", .usage = "[1/0]", }, { .name = "enable_stm8l", .handler = stm8_handle_enable_stm8l_command, .mode = COMMAND_ANY, .help = "Enable/disable STM8L flash programming", .usage = "[1/0]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration stm8_command_handlers[] = { { .name = "stm8", .mode = COMMAND_ANY, .help = "stm8 command group", .usage = "", .chain = stm8_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type stm8_target = { .name = "stm8", .poll = stm8_poll, .arch_state = stm8_arch_state, .halt = stm8_halt, .resume = stm8_resume, .step = stm8_step, .assert_reset = stm8_reset_assert, .deassert_reset = stm8_reset_deassert, .get_gdb_arch = stm8_get_gdb_arch, .get_gdb_reg_list = stm8_get_gdb_reg_list, .read_memory = stm8_read_memory, .write_memory = stm8_write_memory, .checksum_memory = stm8_checksum_memory, .blank_check_memory = stm8_blank_check_memory, .run_algorithm = stm8_run_algorithm, .add_breakpoint = stm8_add_breakpoint, .remove_breakpoint = stm8_remove_breakpoint, .add_watchpoint = stm8_add_watchpoint, .remove_watchpoint = stm8_remove_watchpoint, .commands = stm8_command_handlers, .target_create = stm8_target_create, .init_target = stm8_init, .examine = stm8_examine, .deinit_target = stm8_deinit, .target_jim_configure = stm8_jim_configure, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/stm8.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * OpenOCD STM8 target driver * Copyright (C) 2017 Ake Rehnman * ake.rehnman(at)gmail.com */ #ifndef OPENOCD_TARGET_STM8_H #define OPENOCD_TARGET_STM8_H struct target; #define STM8_COMMON_MAGIC 0x53544D38U #define STM8_NUM_CORE_REGS 6 struct stm8_common { unsigned int common_magic; void *arch_info; struct reg_cache *core_cache; uint32_t core_regs[STM8_NUM_CORE_REGS]; /* working area for fastdata access */ struct working_area *fast_data_area; bool swim_configured; bool bp_scanned; uint8_t num_hw_bpoints; uint8_t num_hw_bpoints_avail; struct stm8_comparator *hw_break_list; uint32_t blocksize; uint32_t flashstart; uint32_t flashend; uint32_t eepromstart; uint32_t eepromend; uint32_t optionstart; uint32_t optionend; bool enable_step_irq; bool enable_stm8l; uint32_t flash_cr2; uint32_t flash_ncr2; uint32_t flash_iapsr; uint32_t flash_dukr; uint32_t flash_pukr; /* cc value used for interrupt flags restore */ uint32_t cc; bool cc_valid; /* register cache to processor synchronization */ int (*read_core_reg)(struct target *target, unsigned int num); int (*write_core_reg)(struct target *target, unsigned int num); }; static inline struct stm8_common * target_to_stm8(struct target *target) { return target->arch_info; } #endif /* OPENOCD_TARGET_STM8_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/target.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008, Duane Ellis * * openocd@duaneeellis.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by Rick Altherr * * kc8apf@kc8apf.net> * * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * Copyright (C) ST-Ericsson SA 2011 * * michel.jaouen@stericsson.com : smp minimum support * * * * Copyright (C) 2011 Andreas Fritiofson * * andreas.fritiofson@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/align.h> #include <helper/nvp.h> #include <helper/time_support.h> #include <jtag/jtag.h> #include <flash/nor/core.h> #include "target.h" #include "target_type.h" #include "target_request.h" #include "breakpoints.h" #include "register.h" #include "trace.h" #include "image.h" #include "rtos/rtos.h" #include "transport/transport.h" #include "arm_cti.h" #include "smp.h" #include "semihosting_common.h" /* default halt wait timeout (ms) */ #define DEFAULT_HALT_TIMEOUT 5000 static int target_read_buffer_default(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer); static int target_write_buffer_default(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer); static int target_array2mem(Jim_Interp *interp, struct target *target, int argc, Jim_Obj * const *argv); static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj * const *argv); static int target_register_user_commands(struct command_context *cmd_ctx); static int target_get_gdb_fileio_info_default(struct target *target, struct gdb_fileio_info *fileio_info); static int target_gdb_fileio_end_default(struct target *target, int retcode, int fileio_errno, bool ctrl_c); static struct target_type *target_types[] = { &arm7tdmi_target, &arm9tdmi_target, &arm920t_target, &arm720t_target, &arm966e_target, &arm946e_target, &arm926ejs_target, &fa526_target, &feroceon_target, &dragonite_target, &xscale_target, &xtensa_chip_target, &cortexm_target, &cortexa_target, &cortexr4_target, &arm11_target, &ls1_sap_target, &mips_m4k_target, &avr_target, &dsp563xx_target, &dsp5680xx_target, &testee_target, &avr32_ap7k_target, &hla_target, &esp32_target, &esp32s2_target, &esp32s3_target, &or1k_target, &quark_x10xx_target, &quark_d20xx_target, &stm8_target, &riscv_target, &mem_ap_target, &esirisc_target, &arcv2_target, &aarch64_target, &armv8r_target, &mips_mips64_target, NULL, }; struct target *all_targets; static struct target_event_callback *target_event_callbacks; static struct target_timer_callback *target_timer_callbacks; static int64_t target_timer_next_event_value; static LIST_HEAD(target_reset_callback_list); static LIST_HEAD(target_trace_callback_list); static const int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL; static LIST_HEAD(empty_smp_targets); enum nvp_assert { NVP_DEASSERT, NVP_ASSERT, }; static const struct nvp nvp_assert[] = { { .name = "assert", NVP_ASSERT }, { .name = "deassert", NVP_DEASSERT }, { .name = "T", NVP_ASSERT }, { .name = "F", NVP_DEASSERT }, { .name = "t", NVP_ASSERT }, { .name = "f", NVP_DEASSERT }, { .name = NULL, .value = -1 } }; static const struct nvp nvp_error_target[] = { { .value = ERROR_TARGET_INVALID, .name = "err-invalid" }, { .value = ERROR_TARGET_INIT_FAILED, .name = "err-init-failed" }, { .value = ERROR_TARGET_TIMEOUT, .name = "err-timeout" }, { .value = ERROR_TARGET_NOT_HALTED, .name = "err-not-halted" }, { .value = ERROR_TARGET_FAILURE, .name = "err-failure" }, { .value = ERROR_TARGET_UNALIGNED_ACCESS, .name = "err-unaligned-access" }, { .value = ERROR_TARGET_DATA_ABORT, .name = "err-data-abort" }, { .value = ERROR_TARGET_RESOURCE_NOT_AVAILABLE, .name = "err-resource-not-available" }, { .value = ERROR_TARGET_TRANSLATION_FAULT, .name = "err-translation-fault" }, { .value = ERROR_TARGET_NOT_RUNNING, .name = "err-not-running" }, { .value = ERROR_TARGET_NOT_EXAMINED, .name = "err-not-examined" }, { .value = -1, .name = NULL } }; static const char *target_strerror_safe(int err) { const struct nvp *n; n = nvp_value2name(nvp_error_target, err); if (!n->name) return "unknown"; else return n->name; } static const struct jim_nvp nvp_target_event[] = { { .value = TARGET_EVENT_GDB_HALT, .name = "gdb-halt" }, { .value = TARGET_EVENT_HALTED, .name = "halted" }, { .value = TARGET_EVENT_RESUMED, .name = "resumed" }, { .value = TARGET_EVENT_RESUME_START, .name = "resume-start" }, { .value = TARGET_EVENT_RESUME_END, .name = "resume-end" }, { .value = TARGET_EVENT_STEP_START, .name = "step-start" }, { .value = TARGET_EVENT_STEP_END, .name = "step-end" }, { .name = "gdb-start", .value = TARGET_EVENT_GDB_START }, { .name = "gdb-end", .value = TARGET_EVENT_GDB_END }, { .value = TARGET_EVENT_RESET_START, .name = "reset-start" }, { .value = TARGET_EVENT_RESET_ASSERT_PRE, .name = "reset-assert-pre" }, { .value = TARGET_EVENT_RESET_ASSERT, .name = "reset-assert" }, { .value = TARGET_EVENT_RESET_ASSERT_POST, .name = "reset-assert-post" }, { .value = TARGET_EVENT_RESET_DEASSERT_PRE, .name = "reset-deassert-pre" }, { .value = TARGET_EVENT_RESET_DEASSERT_POST, .name = "reset-deassert-post" }, { .value = TARGET_EVENT_RESET_INIT, .name = "reset-init" }, { .value = TARGET_EVENT_RESET_END, .name = "reset-end" }, { .value = TARGET_EVENT_EXAMINE_START, .name = "examine-start" }, { .value = TARGET_EVENT_EXAMINE_FAIL, .name = "examine-fail" }, { .value = TARGET_EVENT_EXAMINE_END, .name = "examine-end" }, { .value = TARGET_EVENT_DEBUG_HALTED, .name = "debug-halted" }, { .value = TARGET_EVENT_DEBUG_RESUMED, .name = "debug-resumed" }, { .value = TARGET_EVENT_GDB_ATTACH, .name = "gdb-attach" }, { .value = TARGET_EVENT_GDB_DETACH, .name = "gdb-detach" }, { .value = TARGET_EVENT_GDB_FLASH_WRITE_START, .name = "gdb-flash-write-start" }, { .value = TARGET_EVENT_GDB_FLASH_WRITE_END, .name = "gdb-flash-write-end" }, { .value = TARGET_EVENT_GDB_FLASH_ERASE_START, .name = "gdb-flash-erase-start" }, { .value = TARGET_EVENT_GDB_FLASH_ERASE_END, .name = "gdb-flash-erase-end" }, { .value = TARGET_EVENT_TRACE_CONFIG, .name = "trace-config" }, { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X100, .name = "semihosting-user-cmd-0x100" }, { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X101, .name = "semihosting-user-cmd-0x101" }, { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X102, .name = "semihosting-user-cmd-0x102" }, { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X103, .name = "semihosting-user-cmd-0x103" }, { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X104, .name = "semihosting-user-cmd-0x104" }, { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X105, .name = "semihosting-user-cmd-0x105" }, { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X106, .name = "semihosting-user-cmd-0x106" }, { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X107, .name = "semihosting-user-cmd-0x107" }, { .name = NULL, .value = -1 } }; static const struct nvp nvp_target_state[] = { { .name = "unknown", .value = TARGET_UNKNOWN }, { .name = "running", .value = TARGET_RUNNING }, { .name = "halted", .value = TARGET_HALTED }, { .name = "reset", .value = TARGET_RESET }, { .name = "debug-running", .value = TARGET_DEBUG_RUNNING }, { .name = NULL, .value = -1 }, }; static const struct nvp nvp_target_debug_reason[] = { { .name = "debug-request", .value = DBG_REASON_DBGRQ }, { .name = "breakpoint", .value = DBG_REASON_BREAKPOINT }, { .name = "watchpoint", .value = DBG_REASON_WATCHPOINT }, { .name = "watchpoint-and-breakpoint", .value = DBG_REASON_WPTANDBKPT }, { .name = "single-step", .value = DBG_REASON_SINGLESTEP }, { .name = "target-not-halted", .value = DBG_REASON_NOTHALTED }, { .name = "program-exit", .value = DBG_REASON_EXIT }, { .name = "exception-catch", .value = DBG_REASON_EXC_CATCH }, { .name = "undefined", .value = DBG_REASON_UNDEFINED }, { .name = NULL, .value = -1 }, }; static const struct jim_nvp nvp_target_endian[] = { { .name = "big", .value = TARGET_BIG_ENDIAN }, { .name = "little", .value = TARGET_LITTLE_ENDIAN }, { .name = "be", .value = TARGET_BIG_ENDIAN }, { .name = "le", .value = TARGET_LITTLE_ENDIAN }, { .name = NULL, .value = -1 }, }; static const struct nvp nvp_reset_modes[] = { { .name = "unknown", .value = RESET_UNKNOWN }, { .name = "run", .value = RESET_RUN }, { .name = "halt", .value = RESET_HALT }, { .name = "init", .value = RESET_INIT }, { .name = NULL, .value = -1 }, }; const char *debug_reason_name(struct target *t) { const char *cp; cp = nvp_value2name(nvp_target_debug_reason, t->debug_reason)->name; if (!cp) { LOG_ERROR("Invalid debug reason: %d", (int)(t->debug_reason)); cp = "(*BUG*unknown*BUG*)"; } return cp; } const char *target_state_name(struct target *t) { const char *cp; cp = nvp_value2name(nvp_target_state, t->state)->name; if (!cp) { LOG_ERROR("Invalid target state: %d", (int)(t->state)); cp = "(*BUG*unknown*BUG*)"; } if (!target_was_examined(t) && t->defer_examine) cp = "examine deferred"; return cp; } const char *target_event_name(enum target_event event) { const char *cp; cp = jim_nvp_value2name_simple(nvp_target_event, event)->name; if (!cp) { LOG_ERROR("Invalid target event: %d", (int)(event)); cp = "(*BUG*unknown*BUG*)"; } return cp; } const char *target_reset_mode_name(enum target_reset_mode reset_mode) { const char *cp; cp = nvp_value2name(nvp_reset_modes, reset_mode)->name; if (!cp) { LOG_ERROR("Invalid target reset mode: %d", (int)(reset_mode)); cp = "(*BUG*unknown*BUG*)"; } return cp; } /* determine the number of the new target */ static int new_target_number(void) { struct target *t; int x; /* number is 0 based */ x = -1; t = all_targets; while (t) { if (x < t->target_number) x = t->target_number; t = t->next; } return x + 1; } static void append_to_list_all_targets(struct target *target) { struct target **t = &all_targets; while (*t) t = &((*t)->next); *t = target; } /* read a uint64_t from a buffer in target memory endianness */ uint64_t target_buffer_get_u64(struct target *target, const uint8_t *buffer) { if (target->endianness == TARGET_LITTLE_ENDIAN) return le_to_h_u64(buffer); else return be_to_h_u64(buffer); } /* read a uint32_t from a buffer in target memory endianness */ uint32_t target_buffer_get_u32(struct target *target, const uint8_t *buffer) { if (target->endianness == TARGET_LITTLE_ENDIAN) return le_to_h_u32(buffer); else return be_to_h_u32(buffer); } /* read a uint24_t from a buffer in target memory endianness */ uint32_t target_buffer_get_u24(struct target *target, const uint8_t *buffer) { if (target->endianness == TARGET_LITTLE_ENDIAN) return le_to_h_u24(buffer); else return be_to_h_u24(buffer); } /* read a uint16_t from a buffer in target memory endianness */ uint16_t target_buffer_get_u16(struct target *target, const uint8_t *buffer) { if (target->endianness == TARGET_LITTLE_ENDIAN) return le_to_h_u16(buffer); else return be_to_h_u16(buffer); } /* write a uint64_t to a buffer in target memory endianness */ void target_buffer_set_u64(struct target *target, uint8_t *buffer, uint64_t value) { if (target->endianness == TARGET_LITTLE_ENDIAN) h_u64_to_le(buffer, value); else h_u64_to_be(buffer, value); } /* write a uint32_t to a buffer in target memory endianness */ void target_buffer_set_u32(struct target *target, uint8_t *buffer, uint32_t value) { if (target->endianness == TARGET_LITTLE_ENDIAN) h_u32_to_le(buffer, value); else h_u32_to_be(buffer, value); } /* write a uint24_t to a buffer in target memory endianness */ void target_buffer_set_u24(struct target *target, uint8_t *buffer, uint32_t value) { if (target->endianness == TARGET_LITTLE_ENDIAN) h_u24_to_le(buffer, value); else h_u24_to_be(buffer, value); } /* write a uint16_t to a buffer in target memory endianness */ void target_buffer_set_u16(struct target *target, uint8_t *buffer, uint16_t value) { if (target->endianness == TARGET_LITTLE_ENDIAN) h_u16_to_le(buffer, value); else h_u16_to_be(buffer, value); } /* write a uint8_t to a buffer in target memory endianness */ static void target_buffer_set_u8(struct target *target, uint8_t *buffer, uint8_t value) { *buffer = value; } /* write a uint64_t array to a buffer in target memory endianness */ void target_buffer_get_u64_array(struct target *target, const uint8_t *buffer, uint32_t count, uint64_t *dstbuf) { uint32_t i; for (i = 0; i < count; i++) dstbuf[i] = target_buffer_get_u64(target, &buffer[i * 8]); } /* write a uint32_t array to a buffer in target memory endianness */ void target_buffer_get_u32_array(struct target *target, const uint8_t *buffer, uint32_t count, uint32_t *dstbuf) { uint32_t i; for (i = 0; i < count; i++) dstbuf[i] = target_buffer_get_u32(target, &buffer[i * 4]); } /* write a uint16_t array to a buffer in target memory endianness */ void target_buffer_get_u16_array(struct target *target, const uint8_t *buffer, uint32_t count, uint16_t *dstbuf) { uint32_t i; for (i = 0; i < count; i++) dstbuf[i] = target_buffer_get_u16(target, &buffer[i * 2]); } /* write a uint64_t array to a buffer in target memory endianness */ void target_buffer_set_u64_array(struct target *target, uint8_t *buffer, uint32_t count, const uint64_t *srcbuf) { uint32_t i; for (i = 0; i < count; i++) target_buffer_set_u64(target, &buffer[i * 8], srcbuf[i]); } /* write a uint32_t array to a buffer in target memory endianness */ void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, const uint32_t *srcbuf) { uint32_t i; for (i = 0; i < count; i++) target_buffer_set_u32(target, &buffer[i * 4], srcbuf[i]); } /* write a uint16_t array to a buffer in target memory endianness */ void target_buffer_set_u16_array(struct target *target, uint8_t *buffer, uint32_t count, const uint16_t *srcbuf) { uint32_t i; for (i = 0; i < count; i++) target_buffer_set_u16(target, &buffer[i * 2], srcbuf[i]); } /* return a pointer to a configured target; id is name or number */ struct target *get_target(const char *id) { struct target *target; /* try as tcltarget name */ for (target = all_targets; target; target = target->next) { if (!target_name(target)) continue; if (strcmp(id, target_name(target)) == 0) return target; } /* It's OK to remove this fallback sometime after August 2010 or so */ /* no match, try as number */ unsigned num; if (parse_uint(id, &num) != ERROR_OK) return NULL; for (target = all_targets; target; target = target->next) { if (target->target_number == (int)num) { LOG_WARNING("use '%s' as target identifier, not '%u'", target_name(target), num); return target; } } return NULL; } /* returns a pointer to the n-th configured target */ struct target *get_target_by_num(int num) { struct target *target = all_targets; while (target) { if (target->target_number == num) return target; target = target->next; } return NULL; } struct target *get_current_target(struct command_context *cmd_ctx) { struct target *target = get_current_target_or_null(cmd_ctx); if (!target) { LOG_ERROR("BUG: current_target out of bounds"); exit(-1); } return target; } struct target *get_current_target_or_null(struct command_context *cmd_ctx) { return cmd_ctx->current_target_override ? cmd_ctx->current_target_override : cmd_ctx->current_target; } int target_poll(struct target *target) { int retval; /* We can't poll until after examine */ if (!target_was_examined(target)) { /* Fail silently lest we pollute the log */ return ERROR_FAIL; } retval = target->type->poll(target); if (retval != ERROR_OK) return retval; if (target->halt_issued) { if (target->state == TARGET_HALTED) target->halt_issued = false; else { int64_t t = timeval_ms() - target->halt_issued_time; if (t > DEFAULT_HALT_TIMEOUT) { target->halt_issued = false; LOG_INFO("Halt timed out, wake up GDB."); target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } } } return ERROR_OK; } int target_halt(struct target *target) { int retval; /* We can't poll until after examine */ if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } retval = target->type->halt(target); if (retval != ERROR_OK) return retval; target->halt_issued = true; target->halt_issued_time = timeval_ms(); return ERROR_OK; } /** * Make the target (re)start executing using its saved execution * context (possibly with some modifications). * * @param target Which target should start executing. * @param current True to use the target's saved program counter instead * of the address parameter * @param address Optionally used as the program counter. * @param handle_breakpoints True iff breakpoints at the resumption PC * should be skipped. (For example, maybe execution was stopped by * such a breakpoint, in which case it would be counterproductive to * let it re-trigger. * @param debug_execution False if all working areas allocated by OpenOCD * should be released and/or restored to their original contents. * (This would for example be true to run some downloaded "helper" * algorithm code, which resides in one such working buffer and uses * another for data storage.) * * @todo Resolve the ambiguity about what the "debug_execution" flag * signifies. For example, Target implementations don't agree on how * it relates to invalidation of the register cache, or to whether * breakpoints and watchpoints should be enabled. (It would seem wrong * to enable breakpoints when running downloaded "helper" algorithms * (debug_execution true), since the breakpoints would be set to match * target firmware being debugged, not the helper algorithm.... and * enabling them could cause such helpers to malfunction (for example, * by overwriting data with a breakpoint instruction. On the other * hand the infrastructure for running such helpers might use this * procedure but rely on hardware breakpoint to detect termination.) */ int target_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { int retval; /* We can't poll until after examine */ if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } target_call_event_callbacks(target, TARGET_EVENT_RESUME_START); /* note that resume *must* be asynchronous. The CPU can halt before * we poll. The CPU can even halt at the current PC as a result of * a software breakpoint being inserted by (a bug?) the application. */ /* * resume() triggers the event 'resumed'. The execution of TCL commands * in the event handler causes the polling of targets. If the target has * already halted for a breakpoint, polling will run the 'halted' event * handler before the pending 'resumed' handler. * Disable polling during resume() to guarantee the execution of handlers * in the correct order. */ bool save_poll_mask = jtag_poll_mask(); retval = target->type->resume(target, current, address, handle_breakpoints, debug_execution); jtag_poll_unmask(save_poll_mask); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_RESUME_END); return retval; } static int target_process_reset(struct command_invocation *cmd, enum target_reset_mode reset_mode) { char buf[100]; int retval; const struct nvp *n; n = nvp_value2name(nvp_reset_modes, reset_mode); if (!n->name) { LOG_ERROR("invalid reset mode"); return ERROR_FAIL; } struct target *target; for (target = all_targets; target; target = target->next) target_call_reset_callbacks(target, reset_mode); /* disable polling during reset to make reset event scripts * more predictable, i.e. dr/irscan & pathmove in events will * not have JTAG operations injected into the middle of a sequence. */ bool save_poll_mask = jtag_poll_mask(); sprintf(buf, "ocd_process_reset %s", n->name); retval = Jim_Eval(cmd->ctx->interp, buf); jtag_poll_unmask(save_poll_mask); if (retval != JIM_OK) { Jim_MakeErrorMessage(cmd->ctx->interp); command_print(cmd, "%s", Jim_GetString(Jim_GetResult(cmd->ctx->interp), NULL)); return ERROR_FAIL; } /* We want any events to be processed before the prompt */ retval = target_call_timer_callbacks_now(); for (target = all_targets; target; target = target->next) { target->type->check_reset(target); target->running_alg = false; } return retval; } static int identity_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical) { *physical = virtual; return ERROR_OK; } static int no_mmu(struct target *target, int *enabled) { *enabled = 0; return ERROR_OK; } /** * Reset the @c examined flag for the given target. * Pure paranoia -- targets are zeroed on allocation. */ static inline void target_reset_examined(struct target *target) { target->examined = false; } static int default_examine(struct target *target) { target_set_examined(target); return ERROR_OK; } /* no check by default */ static int default_check_reset(struct target *target) { return ERROR_OK; } /* Equivalent Tcl code arp_examine_one is in src/target/startup.tcl * Keep in sync */ int target_examine_one(struct target *target) { target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START); int retval = target->type->examine(target); if (retval != ERROR_OK) { target_reset_examined(target); target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_FAIL); return retval; } target_set_examined(target); target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); return ERROR_OK; } static int jtag_enable_callback(enum jtag_event event, void *priv) { struct target *target = priv; if (event != JTAG_TAP_EVENT_ENABLE || !target->tap->enabled) return ERROR_OK; jtag_unregister_event_callback(jtag_enable_callback, target); return target_examine_one(target); } /* Targets that correctly implement init + examine, i.e. * no communication with target during init: * * XScale */ int target_examine(void) { int retval = ERROR_OK; struct target *target; for (target = all_targets; target; target = target->next) { /* defer examination, but don't skip it */ if (!target->tap->enabled) { jtag_register_event_callback(jtag_enable_callback, target); continue; } if (target->defer_examine) continue; int retval2 = target_examine_one(target); if (retval2 != ERROR_OK) { LOG_WARNING("target %s examination failed", target_name(target)); retval = retval2; } } return retval; } const char *target_type_name(struct target *target) { return target->type->name; } static int target_soft_reset_halt(struct target *target) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (!target->type->soft_reset_halt) { LOG_ERROR("Target %s does not support soft_reset_halt", target_name(target)); return ERROR_FAIL; } return target->type->soft_reset_halt(target); } /** * Downloads a target-specific native code algorithm to the target, * and executes it. * Note that some targets may need to set up, enable, * and tear down a breakpoint (hard or * soft) to detect algorithm * termination, while others may support lower overhead schemes where * soft breakpoints embedded in the algorithm automatically terminate the * algorithm. * * @param target used to run the algorithm * @param num_mem_params * @param mem_params * @param num_reg_params * @param reg_param * @param entry_point * @param exit_point * @param timeout_ms * @param arch_info target-specific description of the algorithm. */ int target_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { int retval = ERROR_FAIL; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); goto done; } if (!target->type->run_algorithm) { LOG_ERROR("Target type '%s' does not support %s", target_type_name(target), __func__); goto done; } target->running_alg = true; retval = target->type->run_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_param, entry_point, exit_point, timeout_ms, arch_info); target->running_alg = false; done: return retval; } /** * Executes a target-specific native code algorithm and leaves it running. * * @param target used to run the algorithm * @param num_mem_params * @param mem_params * @param num_reg_params * @param reg_params * @param entry_point * @param exit_point * @param arch_info target-specific description of the algorithm. */ int target_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, void *arch_info) { int retval = ERROR_FAIL; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); goto done; } if (!target->type->start_algorithm) { LOG_ERROR("Target type '%s' does not support %s", target_type_name(target), __func__); goto done; } if (target->running_alg) { LOG_ERROR("Target is already running an algorithm"); goto done; } target->running_alg = true; retval = target->type->start_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_params, entry_point, exit_point, arch_info); done: return retval; } /** * Waits for an algorithm started with target_start_algorithm() to complete. * * @param target used to run the algorithm * @param num_mem_params * @param mem_params * @param num_reg_params * @param reg_params * @param exit_point * @param timeout_ms * @param arch_info target-specific description of the algorithm. */ int target_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { int retval = ERROR_FAIL; if (!target->type->wait_algorithm) { LOG_ERROR("Target type '%s' does not support %s", target_type_name(target), __func__); goto done; } if (!target->running_alg) { LOG_ERROR("Target is not running an algorithm"); goto done; } retval = target->type->wait_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_params, exit_point, timeout_ms, arch_info); if (retval != ERROR_TARGET_TIMEOUT) target->running_alg = false; done: return retval; } /** * Streams data to a circular buffer on target intended for consumption by code * running asynchronously on target. * * This is intended for applications where target-specific native code runs * on the target, receives data from the circular buffer, does something with * it (most likely writing it to a flash memory), and advances the circular * buffer pointer. * * This assumes that the helper algorithm has already been loaded to the target, * but has not been started yet. Given memory and register parameters are passed * to the algorithm. * * The buffer is defined by (buffer_start, buffer_size) arguments and has the * following format: * * [buffer_start + 0, buffer_start + 4): * Write Pointer address (aka head). Written and updated by this * routine when new data is written to the circular buffer. * [buffer_start + 4, buffer_start + 8): * Read Pointer address (aka tail). Updated by code running on the * target after it consumes data. * [buffer_start + 8, buffer_start + buffer_size): * Circular buffer contents. * * See contrib/loaders/flash/stm32f1x.S for an example. * * @param target used to run the algorithm * @param buffer address on the host where data to be sent is located * @param count number of blocks to send * @param block_size size in bytes of each block * @param num_mem_params count of memory-based params to pass to algorithm * @param mem_params memory-based params to pass to algorithm * @param num_reg_params count of register-based params to pass to algorithm * @param reg_params memory-based params to pass to algorithm * @param buffer_start address on the target of the circular buffer structure * @param buffer_size size of the circular buffer structure * @param entry_point address on the target to execute to start the algorithm * @param exit_point address at which to set a breakpoint to catch the * end of the algorithm; can be 0 if target triggers a breakpoint itself * @param arch_info */ int target_run_flash_async_algorithm(struct target *target, const uint8_t *buffer, uint32_t count, int block_size, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t buffer_start, uint32_t buffer_size, uint32_t entry_point, uint32_t exit_point, void *arch_info) { int retval; int timeout = 0; const uint8_t *buffer_orig = buffer; /* Set up working area. First word is write pointer, second word is read pointer, * rest is fifo data area. */ uint32_t wp_addr = buffer_start; uint32_t rp_addr = buffer_start + 4; uint32_t fifo_start_addr = buffer_start + 8; uint32_t fifo_end_addr = buffer_start + buffer_size; uint32_t wp = fifo_start_addr; uint32_t rp = fifo_start_addr; /* validate block_size is 2^n */ assert(IS_PWR_OF_2(block_size)); retval = target_write_u32(target, wp_addr, wp); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, rp_addr, rp); if (retval != ERROR_OK) return retval; /* Start up algorithm on target and let it idle while writing the first chunk */ retval = target_start_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_params, entry_point, exit_point, arch_info); if (retval != ERROR_OK) { LOG_ERROR("error starting target flash write algorithm"); return retval; } while (count > 0) { retval = target_read_u32(target, rp_addr, &rp); if (retval != ERROR_OK) { LOG_ERROR("failed to get read pointer"); break; } LOG_DEBUG("offs 0x%zx count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32, (size_t) (buffer - buffer_orig), count, wp, rp); if (rp == 0) { LOG_ERROR("flash write algorithm aborted by target"); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (!IS_ALIGNED(rp - fifo_start_addr, block_size) || rp < fifo_start_addr || rp >= fifo_end_addr) { LOG_ERROR("corrupted fifo read pointer 0x%" PRIx32, rp); break; } /* Count the number of bytes available in the fifo without * crossing the wrap around. Make sure to not fill it completely, * because that would make wp == rp and that's the empty condition. */ uint32_t thisrun_bytes; if (rp > wp) thisrun_bytes = rp - wp - block_size; else if (rp > fifo_start_addr) thisrun_bytes = fifo_end_addr - wp; else thisrun_bytes = fifo_end_addr - wp - block_size; if (thisrun_bytes == 0) { /* Throttle polling a bit if transfer is (much) faster than flash * programming. The exact delay shouldn't matter as long as it's * less than buffer size / flash speed. This is very unlikely to * run when using high latency connections such as USB. */ alive_sleep(2); /* to stop an infinite loop on some targets check and increment a timeout * this issue was observed on a stellaris using the new ICDI interface */ if (timeout++ >= 2500) { LOG_ERROR("timeout waiting for algorithm, a target reset is recommended"); return ERROR_FLASH_OPERATION_FAILED; } continue; } /* reset our timeout */ timeout = 0; /* Limit to the amount of data we actually want to write */ if (thisrun_bytes > count * block_size) thisrun_bytes = count * block_size; /* Force end of large blocks to be word aligned */ if (thisrun_bytes >= 16) thisrun_bytes -= (rp + thisrun_bytes) & 0x03; /* Write data to fifo */ retval = target_write_buffer(target, wp, thisrun_bytes, buffer); if (retval != ERROR_OK) break; /* Update counters and wrap write pointer */ buffer += thisrun_bytes; count -= thisrun_bytes / block_size; wp += thisrun_bytes; if (wp >= fifo_end_addr) wp = fifo_start_addr; /* Store updated write pointer to target */ retval = target_write_u32(target, wp_addr, wp); if (retval != ERROR_OK) break; /* Avoid GDB timeouts */ keep_alive(); } if (retval != ERROR_OK) { /* abort flash write algorithm on target */ target_write_u32(target, wp_addr, 0); } int retval2 = target_wait_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_params, exit_point, 10000, arch_info); if (retval2 != ERROR_OK) { LOG_ERROR("error waiting for target flash write algorithm"); retval = retval2; } if (retval == ERROR_OK) { /* check if algorithm set rp = 0 after fifo writer loop finished */ retval = target_read_u32(target, rp_addr, &rp); if (retval == ERROR_OK && rp == 0) { LOG_ERROR("flash write algorithm aborted by target"); retval = ERROR_FLASH_OPERATION_FAILED; } } return retval; } int target_run_read_async_algorithm(struct target *target, uint8_t *buffer, uint32_t count, int block_size, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t buffer_start, uint32_t buffer_size, uint32_t entry_point, uint32_t exit_point, void *arch_info) { int retval; int timeout = 0; const uint8_t *buffer_orig = buffer; /* Set up working area. First word is write pointer, second word is read pointer, * rest is fifo data area. */ uint32_t wp_addr = buffer_start; uint32_t rp_addr = buffer_start + 4; uint32_t fifo_start_addr = buffer_start + 8; uint32_t fifo_end_addr = buffer_start + buffer_size; uint32_t wp = fifo_start_addr; uint32_t rp = fifo_start_addr; /* validate block_size is 2^n */ assert(IS_PWR_OF_2(block_size)); retval = target_write_u32(target, wp_addr, wp); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, rp_addr, rp); if (retval != ERROR_OK) return retval; /* Start up algorithm on target */ retval = target_start_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_params, entry_point, exit_point, arch_info); if (retval != ERROR_OK) { LOG_ERROR("error starting target flash read algorithm"); return retval; } while (count > 0) { retval = target_read_u32(target, wp_addr, &wp); if (retval != ERROR_OK) { LOG_ERROR("failed to get write pointer"); break; } LOG_DEBUG("offs 0x%zx count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32, (size_t)(buffer - buffer_orig), count, wp, rp); if (wp == 0) { LOG_ERROR("flash read algorithm aborted by target"); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (!IS_ALIGNED(wp - fifo_start_addr, block_size) || wp < fifo_start_addr || wp >= fifo_end_addr) { LOG_ERROR("corrupted fifo write pointer 0x%" PRIx32, wp); break; } /* Count the number of bytes available in the fifo without * crossing the wrap around. */ uint32_t thisrun_bytes; if (wp >= rp) thisrun_bytes = wp - rp; else thisrun_bytes = fifo_end_addr - rp; if (thisrun_bytes == 0) { /* Throttle polling a bit if transfer is (much) faster than flash * reading. The exact delay shouldn't matter as long as it's * less than buffer size / flash speed. This is very unlikely to * run when using high latency connections such as USB. */ alive_sleep(2); /* to stop an infinite loop on some targets check and increment a timeout * this issue was observed on a stellaris using the new ICDI interface */ if (timeout++ >= 2500) { LOG_ERROR("timeout waiting for algorithm, a target reset is recommended"); return ERROR_FLASH_OPERATION_FAILED; } continue; } /* Reset our timeout */ timeout = 0; /* Limit to the amount of data we actually want to read */ if (thisrun_bytes > count * block_size) thisrun_bytes = count * block_size; /* Force end of large blocks to be word aligned */ if (thisrun_bytes >= 16) thisrun_bytes -= (rp + thisrun_bytes) & 0x03; /* Read data from fifo */ retval = target_read_buffer(target, rp, thisrun_bytes, buffer); if (retval != ERROR_OK) break; /* Update counters and wrap write pointer */ buffer += thisrun_bytes; count -= thisrun_bytes / block_size; rp += thisrun_bytes; if (rp >= fifo_end_addr) rp = fifo_start_addr; /* Store updated write pointer to target */ retval = target_write_u32(target, rp_addr, rp); if (retval != ERROR_OK) break; /* Avoid GDB timeouts */ keep_alive(); } if (retval != ERROR_OK) { /* abort flash write algorithm on target */ target_write_u32(target, rp_addr, 0); } int retval2 = target_wait_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_params, exit_point, 10000, arch_info); if (retval2 != ERROR_OK) { LOG_ERROR("error waiting for target flash write algorithm"); retval = retval2; } if (retval == ERROR_OK) { /* check if algorithm set wp = 0 after fifo writer loop finished */ retval = target_read_u32(target, wp_addr, &wp); if (retval == ERROR_OK && wp == 0) { LOG_ERROR("flash read algorithm aborted by target"); retval = ERROR_FLASH_OPERATION_FAILED; } } return retval; } int target_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (!target->type->read_memory) { LOG_ERROR("Target %s doesn't support read_memory", target_name(target)); return ERROR_FAIL; } return target->type->read_memory(target, address, size, count, buffer); } int target_read_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (!target->type->read_phys_memory) { LOG_ERROR("Target %s doesn't support read_phys_memory", target_name(target)); return ERROR_FAIL; } return target->type->read_phys_memory(target, address, size, count, buffer); } int target_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (!target->type->write_memory) { LOG_ERROR("Target %s doesn't support write_memory", target_name(target)); return ERROR_FAIL; } return target->type->write_memory(target, address, size, count, buffer); } int target_write_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (!target->type->write_phys_memory) { LOG_ERROR("Target %s doesn't support write_phys_memory", target_name(target)); return ERROR_FAIL; } return target->type->write_phys_memory(target, address, size, count, buffer); } int target_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { if ((target->state != TARGET_HALTED) && (breakpoint->type != BKPT_HARD)) { LOG_WARNING("target %s is not halted (add breakpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_breakpoint(target, breakpoint); } int target_add_context_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state != TARGET_HALTED) { LOG_WARNING("target %s is not halted (add context breakpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_context_breakpoint(target, breakpoint); } int target_add_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state != TARGET_HALTED) { LOG_WARNING("target %s is not halted (add hybrid breakpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_hybrid_breakpoint(target, breakpoint); } int target_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { return target->type->remove_breakpoint(target, breakpoint); } int target_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { if (target->state != TARGET_HALTED) { LOG_WARNING("target %s is not halted (add watchpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_watchpoint(target, watchpoint); } int target_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { return target->type->remove_watchpoint(target, watchpoint); } int target_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { if (target->state != TARGET_HALTED) { LOG_WARNING("target %s is not halted (hit watchpoint)", target->cmd_name); return ERROR_TARGET_NOT_HALTED; } if (!target->type->hit_watchpoint) { /* For backward compatible, if hit_watchpoint is not implemented, * return ERROR_FAIL such that gdb_server will not take the nonsense * information. */ return ERROR_FAIL; } return target->type->hit_watchpoint(target, hit_watchpoint); } const char *target_get_gdb_arch(struct target *target) { if (!target->type->get_gdb_arch) return NULL; return target->type->get_gdb_arch(target); } int target_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { int result = ERROR_FAIL; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); goto done; } result = target->type->get_gdb_reg_list(target, reg_list, reg_list_size, reg_class); done: if (result != ERROR_OK) { *reg_list = NULL; *reg_list_size = 0; } return result; } int target_get_gdb_reg_list_noread(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { if (target->type->get_gdb_reg_list_noread && target->type->get_gdb_reg_list_noread(target, reg_list, reg_list_size, reg_class) == ERROR_OK) return ERROR_OK; return target_get_gdb_reg_list(target, reg_list, reg_list_size, reg_class); } bool target_supports_gdb_connection(struct target *target) { /* * exclude all the targets that don't provide get_gdb_reg_list * or that have explicit gdb_max_connection == 0 */ return !!target->type->get_gdb_reg_list && !!target->gdb_max_connections; } int target_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { int retval; target_call_event_callbacks(target, TARGET_EVENT_STEP_START); retval = target->type->step(target, current, address, handle_breakpoints); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_STEP_END); return retval; } int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) { if (target->state != TARGET_HALTED) { LOG_WARNING("target %s is not halted (gdb fileio)", target->cmd_name); return ERROR_TARGET_NOT_HALTED; } return target->type->get_gdb_fileio_info(target, fileio_info); } int target_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c) { if (target->state != TARGET_HALTED) { LOG_WARNING("target %s is not halted (gdb fileio end)", target->cmd_name); return ERROR_TARGET_NOT_HALTED; } return target->type->gdb_fileio_end(target, retcode, fileio_errno, ctrl_c); } target_addr_t target_address_max(struct target *target) { unsigned bits = target_address_bits(target); if (sizeof(target_addr_t) * 8 == bits) return (target_addr_t) -1; else return (((target_addr_t) 1) << bits) - 1; } unsigned target_address_bits(struct target *target) { if (target->type->address_bits) return target->type->address_bits(target); return 32; } unsigned int target_data_bits(struct target *target) { if (target->type->data_bits) return target->type->data_bits(target); return 32; } static int target_profiling(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { return target->type->profiling(target, samples, max_num_samples, num_samples, seconds); } static int handle_target(void *priv); static int target_init_one(struct command_context *cmd_ctx, struct target *target) { target_reset_examined(target); struct target_type *type = target->type; if (!type->examine) type->examine = default_examine; if (!type->check_reset) type->check_reset = default_check_reset; assert(type->init_target); int retval = type->init_target(cmd_ctx, target); if (retval != ERROR_OK) { LOG_ERROR("target '%s' init failed", target_name(target)); return retval; } /* Sanity-check MMU support ... stub in what we must, to help * implement it in stages, but warn if we need to do so. */ if (type->mmu) { if (!type->virt2phys) { LOG_ERROR("type '%s' is missing virt2phys", type->name); type->virt2phys = identity_virt2phys; } } else { /* Make sure no-MMU targets all behave the same: make no * distinction between physical and virtual addresses, and * ensure that virt2phys() is always an identity mapping. */ if (type->write_phys_memory || type->read_phys_memory || type->virt2phys) LOG_WARNING("type '%s' has bad MMU hooks", type->name); type->mmu = no_mmu; type->write_phys_memory = type->write_memory; type->read_phys_memory = type->read_memory; type->virt2phys = identity_virt2phys; } if (!target->type->read_buffer) target->type->read_buffer = target_read_buffer_default; if (!target->type->write_buffer) target->type->write_buffer = target_write_buffer_default; if (!target->type->get_gdb_fileio_info) target->type->get_gdb_fileio_info = target_get_gdb_fileio_info_default; if (!target->type->gdb_fileio_end) target->type->gdb_fileio_end = target_gdb_fileio_end_default; if (!target->type->profiling) target->type->profiling = target_profiling_default; return ERROR_OK; } static int target_init(struct command_context *cmd_ctx) { struct target *target; int retval; for (target = all_targets; target; target = target->next) { retval = target_init_one(cmd_ctx, target); if (retval != ERROR_OK) return retval; } if (!all_targets) return ERROR_OK; retval = target_register_user_commands(cmd_ctx); if (retval != ERROR_OK) return retval; retval = target_register_timer_callback(&handle_target, polling_interval, TARGET_TIMER_TYPE_PERIODIC, cmd_ctx->interp); if (retval != ERROR_OK) return retval; return ERROR_OK; } COMMAND_HANDLER(handle_target_init_command) { int retval; if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; static bool target_initialized; if (target_initialized) { LOG_INFO("'target init' has already been called"); return ERROR_OK; } target_initialized = true; retval = command_run_line(CMD_CTX, "init_targets"); if (retval != ERROR_OK) return retval; retval = command_run_line(CMD_CTX, "init_target_events"); if (retval != ERROR_OK) return retval; retval = command_run_line(CMD_CTX, "init_board"); if (retval != ERROR_OK) return retval; LOG_DEBUG("Initializing targets..."); return target_init(CMD_CTX); } int target_register_event_callback(int (*callback)(struct target *target, enum target_event event, void *priv), void *priv) { struct target_event_callback **callbacks_p = &target_event_callbacks; if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; if (*callbacks_p) { while ((*callbacks_p)->next) callbacks_p = &((*callbacks_p)->next); callbacks_p = &((*callbacks_p)->next); } (*callbacks_p) = malloc(sizeof(struct target_event_callback)); (*callbacks_p)->callback = callback; (*callbacks_p)->priv = priv; (*callbacks_p)->next = NULL; return ERROR_OK; } int target_register_reset_callback(int (*callback)(struct target *target, enum target_reset_mode reset_mode, void *priv), void *priv) { struct target_reset_callback *entry; if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; entry = malloc(sizeof(struct target_reset_callback)); if (!entry) { LOG_ERROR("error allocating buffer for reset callback entry"); return ERROR_COMMAND_SYNTAX_ERROR; } entry->callback = callback; entry->priv = priv; list_add(&entry->list, &target_reset_callback_list); return ERROR_OK; } int target_register_trace_callback(int (*callback)(struct target *target, size_t len, uint8_t *data, void *priv), void *priv) { struct target_trace_callback *entry; if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; entry = malloc(sizeof(struct target_trace_callback)); if (!entry) { LOG_ERROR("error allocating buffer for trace callback entry"); return ERROR_COMMAND_SYNTAX_ERROR; } entry->callback = callback; entry->priv = priv; list_add(&entry->list, &target_trace_callback_list); return ERROR_OK; } int target_register_timer_callback(int (*callback)(void *priv), unsigned int time_ms, enum target_timer_type type, void *priv) { struct target_timer_callback **callbacks_p = &target_timer_callbacks; if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; if (*callbacks_p) { while ((*callbacks_p)->next) callbacks_p = &((*callbacks_p)->next); callbacks_p = &((*callbacks_p)->next); } (*callbacks_p) = malloc(sizeof(struct target_timer_callback)); (*callbacks_p)->callback = callback; (*callbacks_p)->type = type; (*callbacks_p)->time_ms = time_ms; (*callbacks_p)->removed = false; (*callbacks_p)->when = timeval_ms() + time_ms; target_timer_next_event_value = MIN(target_timer_next_event_value, (*callbacks_p)->when); (*callbacks_p)->priv = priv; (*callbacks_p)->next = NULL; return ERROR_OK; } int target_unregister_event_callback(int (*callback)(struct target *target, enum target_event event, void *priv), void *priv) { struct target_event_callback **p = &target_event_callbacks; struct target_event_callback *c = target_event_callbacks; if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; while (c) { struct target_event_callback *next = c->next; if ((c->callback == callback) && (c->priv == priv)) { *p = next; free(c); return ERROR_OK; } else p = &(c->next); c = next; } return ERROR_OK; } int target_unregister_reset_callback(int (*callback)(struct target *target, enum target_reset_mode reset_mode, void *priv), void *priv) { struct target_reset_callback *entry; if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; list_for_each_entry(entry, &target_reset_callback_list, list) { if (entry->callback == callback && entry->priv == priv) { list_del(&entry->list); free(entry); break; } } return ERROR_OK; } int target_unregister_trace_callback(int (*callback)(struct target *target, size_t len, uint8_t *data, void *priv), void *priv) { struct target_trace_callback *entry; if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; list_for_each_entry(entry, &target_trace_callback_list, list) { if (entry->callback == callback && entry->priv == priv) { list_del(&entry->list); free(entry); break; } } return ERROR_OK; } int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) { if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; for (struct target_timer_callback *c = target_timer_callbacks; c; c = c->next) { if ((c->callback == callback) && (c->priv == priv)) { c->removed = true; return ERROR_OK; } } return ERROR_FAIL; } int target_call_event_callbacks(struct target *target, enum target_event event) { struct target_event_callback *callback = target_event_callbacks; struct target_event_callback *next_callback; if (event == TARGET_EVENT_HALTED) { /* execute early halted first */ target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } LOG_DEBUG("target event %i (%s) for core %s", event, target_event_name(event), target_name(target)); target_handle_event(target, event); while (callback) { next_callback = callback->next; callback->callback(target, event, callback->priv); callback = next_callback; } return ERROR_OK; } int target_call_reset_callbacks(struct target *target, enum target_reset_mode reset_mode) { struct target_reset_callback *callback; LOG_DEBUG("target reset %i (%s)", reset_mode, nvp_value2name(nvp_reset_modes, reset_mode)->name); list_for_each_entry(callback, &target_reset_callback_list, list) callback->callback(target, reset_mode, callback->priv); return ERROR_OK; } int target_call_trace_callbacks(struct target *target, size_t len, uint8_t *data) { struct target_trace_callback *callback; list_for_each_entry(callback, &target_trace_callback_list, list) callback->callback(target, len, data, callback->priv); return ERROR_OK; } static int target_timer_callback_periodic_restart( struct target_timer_callback *cb, int64_t *now) { cb->when = *now + cb->time_ms; return ERROR_OK; } static int target_call_timer_callback(struct target_timer_callback *cb, int64_t *now) { cb->callback(cb->priv); if (cb->type == TARGET_TIMER_TYPE_PERIODIC) return target_timer_callback_periodic_restart(cb, now); return target_unregister_timer_callback(cb->callback, cb->priv); } static int target_call_timer_callbacks_check_time(int checktime) { static bool callback_processing; /* Do not allow nesting */ if (callback_processing) return ERROR_OK; callback_processing = true; keep_alive(); int64_t now = timeval_ms(); /* Initialize to a default value that's a ways into the future. * The loop below will make it closer to now if there are * callbacks that want to be called sooner. */ target_timer_next_event_value = now + 1000; /* Store an address of the place containing a pointer to the * next item; initially, that's a standalone "root of the * list" variable. */ struct target_timer_callback **callback = &target_timer_callbacks; while (callback && *callback) { if ((*callback)->removed) { struct target_timer_callback *p = *callback; *callback = (*callback)->next; free(p); continue; } bool call_it = (*callback)->callback && ((!checktime && (*callback)->type == TARGET_TIMER_TYPE_PERIODIC) || now >= (*callback)->when); if (call_it) target_call_timer_callback(*callback, &now); if (!(*callback)->removed && (*callback)->when < target_timer_next_event_value) target_timer_next_event_value = (*callback)->when; callback = &(*callback)->next; } callback_processing = false; return ERROR_OK; } int target_call_timer_callbacks(void) { return target_call_timer_callbacks_check_time(1); } /* invoke periodic callbacks immediately */ int target_call_timer_callbacks_now(void) { return target_call_timer_callbacks_check_time(0); } int64_t target_timer_next_event(void) { return target_timer_next_event_value; } /* Prints the working area layout for debug purposes */ static void print_wa_layout(struct target *target) { struct working_area *c = target->working_areas; while (c) { LOG_DEBUG("%c%c " TARGET_ADDR_FMT "-" TARGET_ADDR_FMT " (%" PRIu32 " bytes)", c->backup ? 'b' : ' ', c->free ? ' ' : '*', c->address, c->address + c->size - 1, c->size); c = c->next; } } /* Reduce area to size bytes, create a new free area from the remaining bytes, if any. */ static void target_split_working_area(struct working_area *area, uint32_t size) { assert(area->free); /* Shouldn't split an allocated area */ assert(size <= area->size); /* Caller should guarantee this */ /* Split only if not already the right size */ if (size < area->size) { struct working_area *new_wa = malloc(sizeof(*new_wa)); if (!new_wa) return; new_wa->next = area->next; new_wa->size = area->size - size; new_wa->address = area->address + size; new_wa->backup = NULL; new_wa->user = NULL; new_wa->free = true; area->next = new_wa; area->size = size; /* If backup memory was allocated to this area, it has the wrong size * now so free it and it will be reallocated if/when needed */ free(area->backup); area->backup = NULL; } } /* Merge all adjacent free areas into one */ static void target_merge_working_areas(struct target *target) { struct working_area *c = target->working_areas; while (c && c->next) { assert(c->next->address == c->address + c->size); /* This is an invariant */ /* Find two adjacent free areas */ if (c->free && c->next->free) { /* Merge the last into the first */ c->size += c->next->size; /* Remove the last */ struct working_area *to_be_freed = c->next; c->next = c->next->next; free(to_be_freed->backup); free(to_be_freed); /* If backup memory was allocated to the remaining area, it's has * the wrong size now */ free(c->backup); c->backup = NULL; } else { c = c->next; } } } int target_alloc_working_area_try(struct target *target, uint32_t size, struct working_area **area) { /* Reevaluate working area address based on MMU state*/ if (!target->working_areas) { int retval; int enabled; retval = target->type->mmu(target, &enabled); if (retval != ERROR_OK) return retval; if (!enabled) { if (target->working_area_phys_spec) { LOG_DEBUG("MMU disabled, using physical " "address for working memory " TARGET_ADDR_FMT, target->working_area_phys); target->working_area = target->working_area_phys; } else { LOG_ERROR("No working memory available. " "Specify -work-area-phys to target."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } else { if (target->working_area_virt_spec) { LOG_DEBUG("MMU enabled, using virtual " "address for working memory " TARGET_ADDR_FMT, target->working_area_virt); target->working_area = target->working_area_virt; } else { LOG_ERROR("No working memory available. " "Specify -work-area-virt to target."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } /* Set up initial working area on first call */ struct working_area *new_wa = malloc(sizeof(*new_wa)); if (new_wa) { new_wa->next = NULL; new_wa->size = ALIGN_DOWN(target->working_area_size, 4); /* 4-byte align */ new_wa->address = target->working_area; new_wa->backup = NULL; new_wa->user = NULL; new_wa->free = true; } target->working_areas = new_wa; } /* only allocate multiples of 4 byte */ size = ALIGN_UP(size, 4); struct working_area *c = target->working_areas; /* Find the first large enough working area */ while (c) { if (c->free && c->size >= size) break; c = c->next; } if (!c) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* Split the working area into the requested size */ target_split_working_area(c, size); LOG_DEBUG("allocated new working area of %" PRIu32 " bytes at address " TARGET_ADDR_FMT, size, c->address); if (target->backup_working_area) { if (!c->backup) { c->backup = malloc(c->size); if (!c->backup) return ERROR_FAIL; } int retval = target_read_memory(target, c->address, 4, c->size / 4, c->backup); if (retval != ERROR_OK) return retval; } /* mark as used, and return the new (reused) area */ c->free = false; *area = c; /* user pointer */ c->user = area; print_wa_layout(target); return ERROR_OK; } int target_alloc_working_area(struct target *target, uint32_t size, struct working_area **area) { int retval; retval = target_alloc_working_area_try(target, size, area); if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) LOG_WARNING("not enough working area available(requested %"PRIu32")", size); return retval; } static int target_restore_working_area(struct target *target, struct working_area *area) { int retval = ERROR_OK; if (target->backup_working_area && area->backup) { retval = target_write_memory(target, area->address, 4, area->size / 4, area->backup); if (retval != ERROR_OK) LOG_ERROR("failed to restore %" PRIu32 " bytes of working area at address " TARGET_ADDR_FMT, area->size, area->address); } return retval; } /* Restore the area's backup memory, if any, and return the area to the allocation pool */ static int target_free_working_area_restore(struct target *target, struct working_area *area, int restore) { if (!area || area->free) return ERROR_OK; int retval = ERROR_OK; if (restore) { retval = target_restore_working_area(target, area); /* REVISIT: Perhaps the area should be freed even if restoring fails. */ if (retval != ERROR_OK) return retval; } area->free = true; LOG_DEBUG("freed %" PRIu32 " bytes of working area at address " TARGET_ADDR_FMT, area->size, area->address); /* mark user pointer invalid */ /* TODO: Is this really safe? It points to some previous caller's memory. * How could we know that the area pointer is still in that place and not * some other vital data? What's the purpose of this, anyway? */ *area->user = NULL; area->user = NULL; target_merge_working_areas(target); print_wa_layout(target); return retval; } int target_free_working_area(struct target *target, struct working_area *area) { return target_free_working_area_restore(target, area, 1); } /* free resources and restore memory, if restoring memory fails, * free up resources anyway */ static void target_free_all_working_areas_restore(struct target *target, int restore) { struct working_area *c = target->working_areas; LOG_DEBUG("freeing all working areas"); /* Loop through all areas, restoring the allocated ones and marking them as free */ while (c) { if (!c->free) { if (restore) target_restore_working_area(target, c); c->free = true; *c->user = NULL; /* Same as above */ c->user = NULL; } c = c->next; } /* Run a merge pass to combine all areas into one */ target_merge_working_areas(target); print_wa_layout(target); } void target_free_all_working_areas(struct target *target) { target_free_all_working_areas_restore(target, 1); /* Now we have none or only one working area marked as free */ if (target->working_areas) { /* Free the last one to allow on-the-fly moving and resizing */ free(target->working_areas->backup); free(target->working_areas); target->working_areas = NULL; } } /* Find the largest number of bytes that can be allocated */ uint32_t target_get_working_area_avail(struct target *target) { struct working_area *c = target->working_areas; uint32_t max_size = 0; if (!c) return ALIGN_DOWN(target->working_area_size, 4); while (c) { if (c->free && max_size < c->size) max_size = c->size; c = c->next; } return max_size; } static void target_destroy(struct target *target) { if (target->type->deinit_target) target->type->deinit_target(target); if (target->semihosting) free(target->semihosting->basedir); free(target->semihosting); jtag_unregister_event_callback(jtag_enable_callback, target); struct target_event_action *teap = target->event_action; while (teap) { struct target_event_action *next = teap->next; Jim_DecrRefCount(teap->interp, teap->body); free(teap); teap = next; } target_free_all_working_areas(target); /* release the targets SMP list */ if (target->smp) { struct target_list *head, *tmp; list_for_each_entry_safe(head, tmp, target->smp_targets, lh) { list_del(&head->lh); head->target->smp = 0; free(head); } if (target->smp_targets != &empty_smp_targets) free(target->smp_targets); target->smp = 0; } rtos_destroy(target); free(target->gdb_port_override); free(target->type); free(target->trace_info); free(target->fileio_info); free(target->cmd_name); free(target); } void target_quit(void) { struct target_event_callback *pe = target_event_callbacks; while (pe) { struct target_event_callback *t = pe->next; free(pe); pe = t; } target_event_callbacks = NULL; struct target_timer_callback *pt = target_timer_callbacks; while (pt) { struct target_timer_callback *t = pt->next; free(pt); pt = t; } target_timer_callbacks = NULL; for (struct target *target = all_targets; target;) { struct target *tmp; tmp = target->next; target_destroy(target); target = tmp; } all_targets = NULL; } int target_arch_state(struct target *target) { int retval; if (!target) { LOG_WARNING("No target has been configured"); return ERROR_OK; } if (target->state != TARGET_HALTED) return ERROR_OK; retval = target->type->arch_state(target); return retval; } static int target_get_gdb_fileio_info_default(struct target *target, struct gdb_fileio_info *fileio_info) { /* If target does not support semi-hosting function, target has no need to provide .get_gdb_fileio_info callback. It just return ERROR_FAIL and gdb_server will return "Txx" as target halted every time. */ return ERROR_FAIL; } static int target_gdb_fileio_end_default(struct target *target, int retcode, int fileio_errno, bool ctrl_c) { return ERROR_OK; } int target_profiling_default(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { struct timeval timeout, now; gettimeofday(&timeout, NULL); timeval_add_time(&timeout, seconds, 0); LOG_INFO("Starting profiling. Halting and resuming the" " target as often as we can..."); uint32_t sample_count = 0; /* hopefully it is safe to cache! We want to stop/restart as quickly as possible. */ struct reg *reg = register_get_by_name(target->reg_cache, "pc", true); int retval = ERROR_OK; for (;;) { target_poll(target); if (target->state == TARGET_HALTED) { uint32_t t = buf_get_u32(reg->value, 0, 32); samples[sample_count++] = t; /* current pc, addr = 0, do not handle breakpoints, not debugging */ retval = target_resume(target, 1, 0, 0, 0); target_poll(target); alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */ } else if (target->state == TARGET_RUNNING) { /* We want to quickly sample the PC. */ retval = target_halt(target); } else { LOG_INFO("Target not halted or running"); retval = ERROR_OK; break; } if (retval != ERROR_OK) break; gettimeofday(&now, NULL); if ((sample_count >= max_num_samples) || timeval_compare(&now, &timeout) >= 0) { LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count); break; } } *num_samples = sample_count; return retval; } /* Single aligned words are guaranteed to use 16 or 32 bit access * mode respectively, otherwise data is handled as quickly as * possible */ int target_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer) { LOG_DEBUG("writing buffer of %" PRIu32 " byte at " TARGET_ADDR_FMT, size, address); if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (size == 0) return ERROR_OK; if ((address + size - 1) < address) { /* GDB can request this when e.g. PC is 0xfffffffc */ LOG_ERROR("address + size wrapped (" TARGET_ADDR_FMT ", 0x%08" PRIx32 ")", address, size); return ERROR_FAIL; } return target->type->write_buffer(target, address, size, buffer); } static int target_write_buffer_default(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer) { uint32_t size; unsigned int data_bytes = target_data_bits(target) / 8; /* Align up to maximum bytes. The loop condition makes sure the next pass * will have something to do with the size we leave to it. */ for (size = 1; size < data_bytes && count >= size * 2 + (address & size); size *= 2) { if (address & size) { int retval = target_write_memory(target, address, size, 1, buffer); if (retval != ERROR_OK) return retval; address += size; count -= size; buffer += size; } } /* Write the data with as large access size as possible. */ for (; size > 0; size /= 2) { uint32_t aligned = count - count % size; if (aligned > 0) { int retval = target_write_memory(target, address, size, aligned / size, buffer); if (retval != ERROR_OK) return retval; address += aligned; count -= aligned; buffer += aligned; } } return ERROR_OK; } /* Single aligned words are guaranteed to use 16 or 32 bit access * mode respectively, otherwise data is handled as quickly as * possible */ int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { LOG_DEBUG("reading buffer of %" PRIu32 " byte at " TARGET_ADDR_FMT, size, address); if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (size == 0) return ERROR_OK; if ((address + size - 1) < address) { /* GDB can request this when e.g. PC is 0xfffffffc */ LOG_ERROR("address + size wrapped (" TARGET_ADDR_FMT ", 0x%08" PRIx32 ")", address, size); return ERROR_FAIL; } return target->type->read_buffer(target, address, size, buffer); } static int target_read_buffer_default(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer) { uint32_t size; unsigned int data_bytes = target_data_bits(target) / 8; /* Align up to maximum bytes. The loop condition makes sure the next pass * will have something to do with the size we leave to it. */ for (size = 1; size < data_bytes && count >= size * 2 + (address & size); size *= 2) { if (address & size) { int retval = target_read_memory(target, address, size, 1, buffer); if (retval != ERROR_OK) return retval; address += size; count -= size; buffer += size; } } /* Read the data with as large access size as possible. */ for (; size > 0; size /= 2) { uint32_t aligned = count - count % size; if (aligned > 0) { int retval = target_read_memory(target, address, size, aligned / size, buffer); if (retval != ERROR_OK) return retval; address += aligned; count -= aligned; buffer += aligned; } } return ERROR_OK; } int target_checksum_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t *crc) { uint8_t *buffer; int retval; uint32_t i; uint32_t checksum = 0; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (!target->type->checksum_memory) { LOG_ERROR("Target %s doesn't support checksum_memory", target_name(target)); return ERROR_FAIL; } retval = target->type->checksum_memory(target, address, size, &checksum); if (retval != ERROR_OK) { buffer = malloc(size); if (!buffer) { LOG_ERROR("error allocating buffer for section (%" PRIu32 " bytes)", size); return ERROR_COMMAND_SYNTAX_ERROR; } retval = target_read_buffer(target, address, size, buffer); if (retval != ERROR_OK) { free(buffer); return retval; } /* convert to target endianness */ for (i = 0; i < (size/sizeof(uint32_t)); i++) { uint32_t target_data; target_data = target_buffer_get_u32(target, &buffer[i*sizeof(uint32_t)]); target_buffer_set_u32(target, &buffer[i*sizeof(uint32_t)], target_data); } retval = image_calculate_checksum(buffer, size, &checksum); free(buffer); } *crc = checksum; return retval; } int target_blank_check_memory(struct target *target, struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (!target->type->blank_check_memory) return ERROR_NOT_IMPLEMENTED; return target->type->blank_check_memory(target, blocks, num_blocks, erased_value); } int target_read_u64(struct target *target, target_addr_t address, uint64_t *value) { uint8_t value_buf[8]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } int retval = target_read_memory(target, address, 8, 1, value_buf); if (retval == ERROR_OK) { *value = target_buffer_get_u64(target, value_buf); LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", address, *value); } else { *value = 0x0; LOG_DEBUG("address: " TARGET_ADDR_FMT " failed", address); } return retval; } int target_read_u32(struct target *target, target_addr_t address, uint32_t *value) { uint8_t value_buf[4]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } int retval = target_read_memory(target, address, 4, 1, value_buf); if (retval == ERROR_OK) { *value = target_buffer_get_u32(target, value_buf); LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", address, *value); } else { *value = 0x0; LOG_DEBUG("address: " TARGET_ADDR_FMT " failed", address); } return retval; } int target_read_u16(struct target *target, target_addr_t address, uint16_t *value) { uint8_t value_buf[2]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } int retval = target_read_memory(target, address, 2, 1, value_buf); if (retval == ERROR_OK) { *value = target_buffer_get_u16(target, value_buf); LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%4.4" PRIx16, address, *value); } else { *value = 0x0; LOG_DEBUG("address: " TARGET_ADDR_FMT " failed", address); } return retval; } int target_read_u8(struct target *target, target_addr_t address, uint8_t *value) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } int retval = target_read_memory(target, address, 1, 1, value); if (retval == ERROR_OK) { LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%2.2" PRIx8, address, *value); } else { *value = 0x0; LOG_DEBUG("address: " TARGET_ADDR_FMT " failed", address); } return retval; } int target_write_u64(struct target *target, target_addr_t address, uint64_t value) { int retval; uint8_t value_buf[8]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", address, value); target_buffer_set_u64(target, value_buf, value); retval = target_write_memory(target, address, 8, 1, value_buf); if (retval != ERROR_OK) LOG_DEBUG("failed: %i", retval); return retval; } int target_write_u32(struct target *target, target_addr_t address, uint32_t value) { int retval; uint8_t value_buf[4]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", address, value); target_buffer_set_u32(target, value_buf, value); retval = target_write_memory(target, address, 4, 1, value_buf); if (retval != ERROR_OK) LOG_DEBUG("failed: %i", retval); return retval; } int target_write_u16(struct target *target, target_addr_t address, uint16_t value) { int retval; uint8_t value_buf[2]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx16, address, value); target_buffer_set_u16(target, value_buf, value); retval = target_write_memory(target, address, 2, 1, value_buf); if (retval != ERROR_OK) LOG_DEBUG("failed: %i", retval); return retval; } int target_write_u8(struct target *target, target_addr_t address, uint8_t value) { int retval; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%2.2" PRIx8, address, value); retval = target_write_memory(target, address, 1, 1, &value); if (retval != ERROR_OK) LOG_DEBUG("failed: %i", retval); return retval; } int target_write_phys_u64(struct target *target, target_addr_t address, uint64_t value) { int retval; uint8_t value_buf[8]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", address, value); target_buffer_set_u64(target, value_buf, value); retval = target_write_phys_memory(target, address, 8, 1, value_buf); if (retval != ERROR_OK) LOG_DEBUG("failed: %i", retval); return retval; } int target_write_phys_u32(struct target *target, target_addr_t address, uint32_t value) { int retval; uint8_t value_buf[4]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", address, value); target_buffer_set_u32(target, value_buf, value); retval = target_write_phys_memory(target, address, 4, 1, value_buf); if (retval != ERROR_OK) LOG_DEBUG("failed: %i", retval); return retval; } int target_write_phys_u16(struct target *target, target_addr_t address, uint16_t value) { int retval; uint8_t value_buf[2]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx16, address, value); target_buffer_set_u16(target, value_buf, value); retval = target_write_phys_memory(target, address, 2, 1, value_buf); if (retval != ERROR_OK) LOG_DEBUG("failed: %i", retval); return retval; } int target_write_phys_u8(struct target *target, target_addr_t address, uint8_t value) { int retval; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%2.2" PRIx8, address, value); retval = target_write_phys_memory(target, address, 1, 1, &value); if (retval != ERROR_OK) LOG_DEBUG("failed: %i", retval); return retval; } static int find_target(struct command_invocation *cmd, const char *name) { struct target *target = get_target(name); if (!target) { command_print(cmd, "Target: %s is unknown, try one of:\n", name); return ERROR_FAIL; } if (!target->tap->enabled) { command_print(cmd, "Target: TAP %s is disabled, " "can't be the current target\n", target->tap->dotted_name); return ERROR_FAIL; } cmd->ctx->current_target = target; if (cmd->ctx->current_target_override) cmd->ctx->current_target_override = target; return ERROR_OK; } COMMAND_HANDLER(handle_targets_command) { int retval = ERROR_OK; if (CMD_ARGC == 1) { retval = find_target(CMD, CMD_ARGV[0]); if (retval == ERROR_OK) { /* we're done! */ return retval; } } struct target *target = all_targets; command_print(CMD, " TargetName Type Endian TapName State "); command_print(CMD, "-- ------------------ ---------- ------ ------------------ ------------"); while (target) { const char *state; char marker = ' '; if (target->tap->enabled) state = target_state_name(target); else state = "tap-disabled"; if (CMD_CTX->current_target == target) marker = '*'; /* keep columns lined up to match the headers above */ command_print(CMD, "%2d%c %-18s %-10s %-6s %-18s %s", target->target_number, marker, target_name(target), target_type_name(target), jim_nvp_value2name_simple(nvp_target_endian, target->endianness)->name, target->tap->dotted_name, state); target = target->next; } return retval; } /* every 300ms we check for reset & powerdropout and issue a "reset halt" if so. */ static int power_dropout; static int srst_asserted; static int run_power_restore; static int run_power_dropout; static int run_srst_asserted; static int run_srst_deasserted; static int sense_handler(void) { static int prev_srst_asserted; static int prev_power_dropout; int retval = jtag_power_dropout(&power_dropout); if (retval != ERROR_OK) return retval; int power_restored; power_restored = prev_power_dropout && !power_dropout; if (power_restored) run_power_restore = 1; int64_t current = timeval_ms(); static int64_t last_power; bool wait_more = last_power + 2000 > current; if (power_dropout && !wait_more) { run_power_dropout = 1; last_power = current; } retval = jtag_srst_asserted(&srst_asserted); if (retval != ERROR_OK) return retval; int srst_deasserted; srst_deasserted = prev_srst_asserted && !srst_asserted; static int64_t last_srst; wait_more = last_srst + 2000 > current; if (srst_deasserted && !wait_more) { run_srst_deasserted = 1; last_srst = current; } if (!prev_srst_asserted && srst_asserted) run_srst_asserted = 1; prev_srst_asserted = srst_asserted; prev_power_dropout = power_dropout; if (srst_deasserted || power_restored) { /* Other than logging the event we can't do anything here. * Issuing a reset is a particularly bad idea as we might * be inside a reset already. */ } return ERROR_OK; } /* process target state changes */ static int handle_target(void *priv) { Jim_Interp *interp = (Jim_Interp *)priv; int retval = ERROR_OK; if (!is_jtag_poll_safe()) { /* polling is disabled currently */ return ERROR_OK; } /* we do not want to recurse here... */ static int recursive; if (!recursive) { recursive = 1; sense_handler(); /* danger! running these procedures can trigger srst assertions and power dropouts. * We need to avoid an infinite loop/recursion here and we do that by * clearing the flags after running these events. */ int did_something = 0; if (run_srst_asserted) { LOG_INFO("srst asserted detected, running srst_asserted proc."); Jim_Eval(interp, "srst_asserted"); did_something = 1; } if (run_srst_deasserted) { Jim_Eval(interp, "srst_deasserted"); did_something = 1; } if (run_power_dropout) { LOG_INFO("Power dropout detected, running power_dropout proc."); Jim_Eval(interp, "power_dropout"); did_something = 1; } if (run_power_restore) { Jim_Eval(interp, "power_restore"); did_something = 1; } if (did_something) { /* clear detect flags */ sense_handler(); } /* clear action flags */ run_srst_asserted = 0; run_srst_deasserted = 0; run_power_restore = 0; run_power_dropout = 0; recursive = 0; } /* Poll targets for state changes unless that's globally disabled. * Skip targets that are currently disabled. */ for (struct target *target = all_targets; is_jtag_poll_safe() && target; target = target->next) { if (!target_was_examined(target)) continue; if (!target->tap->enabled) continue; if (target->backoff.times > target->backoff.count) { /* do not poll this time as we failed previously */ target->backoff.count++; continue; } target->backoff.count = 0; /* only poll target if we've got power and srst isn't asserted */ if (!power_dropout && !srst_asserted) { /* polling may fail silently until the target has been examined */ retval = target_poll(target); if (retval != ERROR_OK) { /* 100ms polling interval. Increase interval between polling up to 5000ms */ if (target->backoff.times * polling_interval < 5000) { target->backoff.times *= 2; target->backoff.times++; } /* Tell GDB to halt the debugger. This allows the user to * run monitor commands to handle the situation. */ target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } if (target->backoff.times > 0) { LOG_USER("Polling target %s failed, trying to reexamine", target_name(target)); target_reset_examined(target); retval = target_examine_one(target); /* Target examination could have failed due to unstable connection, * but we set the examined flag anyway to repoll it later */ if (retval != ERROR_OK) { target_set_examined(target); LOG_USER("Examination failed, GDB will be halted. Polling again in %dms", target->backoff.times * polling_interval); return retval; } } /* Since we succeeded, we reset backoff count */ target->backoff.times = 0; } } return retval; } COMMAND_HANDLER(handle_reg_command) { LOG_DEBUG("-"); struct target *target = get_current_target(CMD_CTX); struct reg *reg = NULL; /* list all available registers for the current target */ if (CMD_ARGC == 0) { struct reg_cache *cache = target->reg_cache; unsigned int count = 0; while (cache) { unsigned i; command_print(CMD, "===== %s", cache->name); for (i = 0, reg = cache->reg_list; i < cache->num_regs; i++, reg++, count++) { if (reg->exist == false || reg->hidden) continue; /* only print cached values if they are valid */ if (reg->valid) { char *value = buf_to_hex_str(reg->value, reg->size); command_print(CMD, "(%i) %s (/%" PRIu32 "): 0x%s%s", count, reg->name, reg->size, value, reg->dirty ? " (dirty)" : ""); free(value); } else { command_print(CMD, "(%i) %s (/%" PRIu32 ")", count, reg->name, reg->size); } } cache = cache->next; } return ERROR_OK; } /* access a single register by its ordinal number */ if ((CMD_ARGV[0][0] >= '0') && (CMD_ARGV[0][0] <= '9')) { unsigned num; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); struct reg_cache *cache = target->reg_cache; unsigned int count = 0; while (cache) { unsigned i; for (i = 0; i < cache->num_regs; i++) { if (count++ == num) { reg = &cache->reg_list[i]; break; } } if (reg) break; cache = cache->next; } if (!reg) { command_print(CMD, "%i is out of bounds, the current target " "has only %i registers (0 - %i)", num, count, count - 1); return ERROR_OK; } } else { /* access a single register by its name */ reg = register_get_by_name(target->reg_cache, CMD_ARGV[0], true); if (!reg) goto not_found; } assert(reg); /* give clang a hint that we *know* reg is != NULL here */ if (!reg->exist) goto not_found; /* display a register */ if ((CMD_ARGC == 1) || ((CMD_ARGC == 2) && !((CMD_ARGV[1][0] >= '0') && (CMD_ARGV[1][0] <= '9')))) { if ((CMD_ARGC == 2) && (strcmp(CMD_ARGV[1], "force") == 0)) reg->valid = 0; if (reg->valid == 0) { int retval = reg->type->get(reg); if (retval != ERROR_OK) { LOG_ERROR("Could not read register '%s'", reg->name); return retval; } } char *value = buf_to_hex_str(reg->value, reg->size); command_print(CMD, "%s (/%i): 0x%s", reg->name, (int)(reg->size), value); free(value); return ERROR_OK; } /* set register value */ if (CMD_ARGC == 2) { uint8_t *buf = malloc(DIV_ROUND_UP(reg->size, 8)); if (!buf) return ERROR_FAIL; str_to_buf(CMD_ARGV[1], strlen(CMD_ARGV[1]), buf, reg->size, 0); int retval = reg->type->set(reg, buf); if (retval != ERROR_OK) { LOG_ERROR("Could not write to register '%s'", reg->name); } else { char *value = buf_to_hex_str(reg->value, reg->size); command_print(CMD, "%s (/%i): 0x%s", reg->name, (int)(reg->size), value); free(value); } free(buf); return retval; } return ERROR_COMMAND_SYNTAX_ERROR; not_found: command_print(CMD, "register %s not found in current target", CMD_ARGV[0]); return ERROR_OK; } COMMAND_HANDLER(handle_poll_command) { int retval = ERROR_OK; struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC == 0) { command_print(CMD, "background polling: %s", jtag_poll_get_enabled() ? "on" : "off"); command_print(CMD, "TAP: %s (%s)", target->tap->dotted_name, target->tap->enabled ? "enabled" : "disabled"); if (!target->tap->enabled) return ERROR_OK; retval = target_poll(target); if (retval != ERROR_OK) return retval; retval = target_arch_state(target); if (retval != ERROR_OK) return retval; } else if (CMD_ARGC == 1) { bool enable; COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable); jtag_poll_set_enabled(enable); } else return ERROR_COMMAND_SYNTAX_ERROR; return retval; } COMMAND_HANDLER(handle_wait_halt_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; unsigned ms = DEFAULT_HALT_TIMEOUT; if (1 == CMD_ARGC) { int retval = parse_uint(CMD_ARGV[0], &ms); if (retval != ERROR_OK) return ERROR_COMMAND_SYNTAX_ERROR; } struct target *target = get_current_target(CMD_CTX); return target_wait_state(target, TARGET_HALTED, ms); } /* wait for target state to change. The trick here is to have a low * latency for short waits and not to suck up all the CPU time * on longer waits. * * After 500ms, keep_alive() is invoked */ int target_wait_state(struct target *target, enum target_state state, unsigned int ms) { int retval; int64_t then = 0, cur; bool once = true; for (;;) { retval = target_poll(target); if (retval != ERROR_OK) return retval; if (target->state == state) break; cur = timeval_ms(); if (once) { once = false; then = timeval_ms(); LOG_DEBUG("waiting for target %s...", nvp_value2name(nvp_target_state, state)->name); } if (cur-then > 500) keep_alive(); if ((cur-then) > ms) { LOG_ERROR("timed out while waiting for target %s", nvp_value2name(nvp_target_state, state)->name); return ERROR_FAIL; } } return ERROR_OK; } COMMAND_HANDLER(handle_halt_command) { LOG_DEBUG("-"); struct target *target = get_current_target(CMD_CTX); target->verbose_halt_msg = true; int retval = target_halt(target); if (retval != ERROR_OK) return retval; if (CMD_ARGC == 1) { unsigned wait_local; retval = parse_uint(CMD_ARGV[0], &wait_local); if (retval != ERROR_OK) return ERROR_COMMAND_SYNTAX_ERROR; if (!wait_local) return ERROR_OK; } return CALL_COMMAND_HANDLER(handle_wait_halt_command); } COMMAND_HANDLER(handle_soft_reset_halt_command) { struct target *target = get_current_target(CMD_CTX); LOG_TARGET_INFO(target, "requesting target halt and executing a soft reset"); target_soft_reset_halt(target); return ERROR_OK; } COMMAND_HANDLER(handle_reset_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; enum target_reset_mode reset_mode = RESET_RUN; if (CMD_ARGC == 1) { const struct nvp *n; n = nvp_name2value(nvp_reset_modes, CMD_ARGV[0]); if ((!n->name) || (n->value == RESET_UNKNOWN)) return ERROR_COMMAND_SYNTAX_ERROR; reset_mode = n->value; } /* reset *all* targets */ return target_process_reset(CMD, reset_mode); } COMMAND_HANDLER(handle_resume_command) { int current = 1; if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); /* with no CMD_ARGV, resume from current pc, addr = 0, * with one arguments, addr = CMD_ARGV[0], * handle breakpoints, not debugging */ target_addr_t addr = 0; if (CMD_ARGC == 1) { COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); current = 0; } return target_resume(target, current, addr, 1, 0); } COMMAND_HANDLER(handle_step_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; LOG_DEBUG("-"); /* with no CMD_ARGV, step from current pc, addr = 0, * with one argument addr = CMD_ARGV[0], * handle breakpoints, debugging */ target_addr_t addr = 0; int current_pc = 1; if (CMD_ARGC == 1) { COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); current_pc = 0; } struct target *target = get_current_target(CMD_CTX); return target_step(target, current_pc, addr, 1); } void target_handle_md_output(struct command_invocation *cmd, struct target *target, target_addr_t address, unsigned size, unsigned count, const uint8_t *buffer) { const unsigned line_bytecnt = 32; unsigned line_modulo = line_bytecnt / size; char output[line_bytecnt * 4 + 1]; unsigned output_len = 0; const char *value_fmt; switch (size) { case 8: value_fmt = "%16.16"PRIx64" "; break; case 4: value_fmt = "%8.8"PRIx64" "; break; case 2: value_fmt = "%4.4"PRIx64" "; break; case 1: value_fmt = "%2.2"PRIx64" "; break; default: /* "can't happen", caller checked */ LOG_ERROR("invalid memory read size: %u", size); return; } for (unsigned i = 0; i < count; i++) { if (i % line_modulo == 0) { output_len += snprintf(output + output_len, sizeof(output) - output_len, TARGET_ADDR_FMT ": ", (address + (i * size))); } uint64_t value = 0; const uint8_t *value_ptr = buffer + i * size; switch (size) { case 8: value = target_buffer_get_u64(target, value_ptr); break; case 4: value = target_buffer_get_u32(target, value_ptr); break; case 2: value = target_buffer_get_u16(target, value_ptr); break; case 1: value = *value_ptr; } output_len += snprintf(output + output_len, sizeof(output) - output_len, value_fmt, value); if ((i % line_modulo == line_modulo - 1) || (i == count - 1)) { command_print(cmd, "%s", output); output_len = 0; } } } COMMAND_HANDLER(handle_md_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; unsigned size = 0; switch (CMD_NAME[2]) { case 'd': size = 8; break; case 'w': size = 4; break; case 'h': size = 2; break; case 'b': size = 1; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } bool physical = strcmp(CMD_ARGV[0], "phys") == 0; int (*fn)(struct target *target, target_addr_t address, uint32_t size_value, uint32_t count, uint8_t *buffer); if (physical) { CMD_ARGC--; CMD_ARGV++; fn = target_read_phys_memory; } else fn = target_read_memory; if ((CMD_ARGC < 1) || (CMD_ARGC > 2)) return ERROR_COMMAND_SYNTAX_ERROR; target_addr_t address; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); unsigned count = 1; if (CMD_ARGC == 2) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], count); uint8_t *buffer = calloc(count, size); if (!buffer) { LOG_ERROR("Failed to allocate md read buffer"); return ERROR_FAIL; } struct target *target = get_current_target(CMD_CTX); int retval = fn(target, address, size, count, buffer); if (retval == ERROR_OK) target_handle_md_output(CMD, target, address, size, count, buffer); free(buffer); return retval; } typedef int (*target_write_fn)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); static int target_fill_mem(struct target *target, target_addr_t address, target_write_fn fn, unsigned data_size, /* value */ uint64_t b, /* count */ unsigned c) { /* We have to write in reasonably large chunks to be able * to fill large memory areas with any sane speed */ const unsigned chunk_size = 16384; uint8_t *target_buf = malloc(chunk_size * data_size); if (!target_buf) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } for (unsigned i = 0; i < chunk_size; i++) { switch (data_size) { case 8: target_buffer_set_u64(target, target_buf + i * data_size, b); break; case 4: target_buffer_set_u32(target, target_buf + i * data_size, b); break; case 2: target_buffer_set_u16(target, target_buf + i * data_size, b); break; case 1: target_buffer_set_u8(target, target_buf + i * data_size, b); break; default: exit(-1); } } int retval = ERROR_OK; for (unsigned x = 0; x < c; x += chunk_size) { unsigned current; current = c - x; if (current > chunk_size) current = chunk_size; retval = fn(target, address + x * data_size, data_size, current, target_buf); if (retval != ERROR_OK) break; /* avoid GDB timeouts */ keep_alive(); } free(target_buf); return retval; } COMMAND_HANDLER(handle_mw_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; bool physical = strcmp(CMD_ARGV[0], "phys") == 0; target_write_fn fn; if (physical) { CMD_ARGC--; CMD_ARGV++; fn = target_write_phys_memory; } else fn = target_write_memory; if ((CMD_ARGC < 2) || (CMD_ARGC > 3)) return ERROR_COMMAND_SYNTAX_ERROR; target_addr_t address; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); uint64_t value; COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], value); unsigned count = 1; if (CMD_ARGC == 3) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], count); struct target *target = get_current_target(CMD_CTX); unsigned wordsize; switch (CMD_NAME[2]) { case 'd': wordsize = 8; break; case 'w': wordsize = 4; break; case 'h': wordsize = 2; break; case 'b': wordsize = 1; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return target_fill_mem(target, address, fn, wordsize, value, count); } static COMMAND_HELPER(parse_load_image_command, struct image *image, target_addr_t *min_address, target_addr_t *max_address) { if (CMD_ARGC < 1 || CMD_ARGC > 5) return ERROR_COMMAND_SYNTAX_ERROR; /* a base address isn't always necessary, * default to 0x0 (i.e. don't relocate) */ if (CMD_ARGC >= 2) { target_addr_t addr; COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr); image->base_address = addr; image->base_address_set = true; } else image->base_address_set = false; image->start_address_set = false; if (CMD_ARGC >= 4) COMMAND_PARSE_ADDRESS(CMD_ARGV[3], *min_address); if (CMD_ARGC == 5) { COMMAND_PARSE_ADDRESS(CMD_ARGV[4], *max_address); /* use size (given) to find max (required) */ *max_address += *min_address; } if (*min_address > *max_address) return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } COMMAND_HANDLER(handle_load_image_command) { uint8_t *buffer; size_t buf_cnt; uint32_t image_size; target_addr_t min_address = 0; target_addr_t max_address = -1; struct image image; int retval = CALL_COMMAND_HANDLER(parse_load_image_command, &image, &min_address, &max_address); if (retval != ERROR_OK) return retval; struct target *target = get_current_target(CMD_CTX); struct duration bench; duration_start(&bench); if (image_open(&image, CMD_ARGV[0], (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL) != ERROR_OK) return ERROR_FAIL; image_size = 0x0; retval = ERROR_OK; for (unsigned int i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); if (!buffer) { command_print(CMD, "error allocating buffer for section (%d bytes)", (int)(image.sections[i].size)); retval = ERROR_FAIL; break; } retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt); if (retval != ERROR_OK) { free(buffer); break; } uint32_t offset = 0; uint32_t length = buf_cnt; /* DANGER!!! beware of unsigned comparison here!!! */ if ((image.sections[i].base_address + buf_cnt >= min_address) && (image.sections[i].base_address < max_address)) { if (image.sections[i].base_address < min_address) { /* clip addresses below */ offset += min_address-image.sections[i].base_address; length -= offset; } if (image.sections[i].base_address + buf_cnt > max_address) length -= (image.sections[i].base_address + buf_cnt)-max_address; retval = target_write_buffer(target, image.sections[i].base_address + offset, length, buffer + offset); if (retval != ERROR_OK) { free(buffer); break; } image_size += length; command_print(CMD, "%u bytes written at address " TARGET_ADDR_FMT "", (unsigned int)length, image.sections[i].base_address + offset); } free(buffer); } if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "downloaded %" PRIu32 " bytes " "in %fs (%0.3f KiB/s)", image_size, duration_elapsed(&bench), duration_kbps(&bench, image_size)); } image_close(&image); return retval; } COMMAND_HANDLER(handle_dump_image_command) { struct fileio *fileio; uint8_t *buffer; int retval, retvaltemp; target_addr_t address, size; struct duration bench; struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ADDRESS(CMD_ARGV[1], address); COMMAND_PARSE_ADDRESS(CMD_ARGV[2], size); uint32_t buf_size = (size > 4096) ? 4096 : size; buffer = malloc(buf_size); if (!buffer) return ERROR_FAIL; retval = fileio_open(&fileio, CMD_ARGV[0], FILEIO_WRITE, FILEIO_BINARY); if (retval != ERROR_OK) { free(buffer); return retval; } duration_start(&bench); while (size > 0) { size_t size_written; uint32_t this_run_size = (size > buf_size) ? buf_size : size; retval = target_read_buffer(target, address, this_run_size, buffer); if (retval != ERROR_OK) break; retval = fileio_write(fileio, this_run_size, buffer, &size_written); if (retval != ERROR_OK) break; size -= this_run_size; address += this_run_size; } free(buffer); if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { size_t filesize; retval = fileio_size(fileio, &filesize); if (retval != ERROR_OK) return retval; command_print(CMD, "dumped %zu bytes in %fs (%0.3f KiB/s)", filesize, duration_elapsed(&bench), duration_kbps(&bench, filesize)); } retvaltemp = fileio_close(fileio); if (retvaltemp != ERROR_OK) return retvaltemp; return retval; } enum verify_mode { IMAGE_TEST = 0, IMAGE_VERIFY = 1, IMAGE_CHECKSUM_ONLY = 2 }; static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode verify) { uint8_t *buffer; size_t buf_cnt; uint32_t image_size; int retval; uint32_t checksum = 0; uint32_t mem_checksum = 0; struct image image; struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (!target) { LOG_ERROR("no target selected"); return ERROR_FAIL; } struct duration bench; duration_start(&bench); if (CMD_ARGC >= 2) { target_addr_t addr; COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr); image.base_address = addr; image.base_address_set = true; } else { image.base_address_set = false; image.base_address = 0x0; } image.start_address_set = false; retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL); if (retval != ERROR_OK) return retval; image_size = 0x0; int diffs = 0; retval = ERROR_OK; for (unsigned int i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); if (!buffer) { command_print(CMD, "error allocating buffer for section (%" PRIu32 " bytes)", image.sections[i].size); break; } retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt); if (retval != ERROR_OK) { free(buffer); break; } if (verify >= IMAGE_VERIFY) { /* calculate checksum of image */ retval = image_calculate_checksum(buffer, buf_cnt, &checksum); if (retval != ERROR_OK) { free(buffer); break; } retval = target_checksum_memory(target, image.sections[i].base_address, buf_cnt, &mem_checksum); if (retval != ERROR_OK) { free(buffer); break; } if ((checksum != mem_checksum) && (verify == IMAGE_CHECKSUM_ONLY)) { LOG_ERROR("checksum mismatch"); free(buffer); retval = ERROR_FAIL; goto done; } if (checksum != mem_checksum) { /* failed crc checksum, fall back to a binary compare */ uint8_t *data; if (diffs == 0) LOG_ERROR("checksum mismatch - attempting binary compare"); data = malloc(buf_cnt); retval = target_read_buffer(target, image.sections[i].base_address, buf_cnt, data); if (retval == ERROR_OK) { uint32_t t; for (t = 0; t < buf_cnt; t++) { if (data[t] != buffer[t]) { command_print(CMD, "diff %d address 0x%08x. Was 0x%02x instead of 0x%02x", diffs, (unsigned)(t + image.sections[i].base_address), data[t], buffer[t]); if (diffs++ >= 127) { command_print(CMD, "More than 128 errors, the rest are not printed."); free(data); free(buffer); goto done; } } keep_alive(); } } free(data); } } else { command_print(CMD, "address " TARGET_ADDR_FMT " length 0x%08zx", image.sections[i].base_address, buf_cnt); } free(buffer); image_size += buf_cnt; } if (diffs > 0) command_print(CMD, "No more differences found."); done: if (diffs > 0) retval = ERROR_FAIL; if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "verified %" PRIu32 " bytes " "in %fs (%0.3f KiB/s)", image_size, duration_elapsed(&bench), duration_kbps(&bench, image_size)); } image_close(&image); return retval; } COMMAND_HANDLER(handle_verify_image_checksum_command) { return CALL_COMMAND_HANDLER(handle_verify_image_command_internal, IMAGE_CHECKSUM_ONLY); } COMMAND_HANDLER(handle_verify_image_command) { return CALL_COMMAND_HANDLER(handle_verify_image_command_internal, IMAGE_VERIFY); } COMMAND_HANDLER(handle_test_image_command) { return CALL_COMMAND_HANDLER(handle_verify_image_command_internal, IMAGE_TEST); } static int handle_bp_command_list(struct command_invocation *cmd) { struct target *target = get_current_target(cmd->ctx); struct breakpoint *breakpoint = target->breakpoints; while (breakpoint) { if (breakpoint->type == BKPT_SOFT) { char *buf = buf_to_hex_str(breakpoint->orig_instr, breakpoint->length); command_print(cmd, "IVA breakpoint: " TARGET_ADDR_FMT ", 0x%x, 0x%s", breakpoint->address, breakpoint->length, buf); free(buf); } else { if ((breakpoint->address == 0) && (breakpoint->asid != 0)) command_print(cmd, "Context breakpoint: 0x%8.8" PRIx32 ", 0x%x, %u", breakpoint->asid, breakpoint->length, breakpoint->number); else if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { command_print(cmd, "Hybrid breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %u", breakpoint->address, breakpoint->length, breakpoint->number); command_print(cmd, "\t|--->linked with ContextID: 0x%8.8" PRIx32, breakpoint->asid); } else command_print(cmd, "Breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %u", breakpoint->address, breakpoint->length, breakpoint->number); } breakpoint = breakpoint->next; } return ERROR_OK; } static int handle_bp_command_set(struct command_invocation *cmd, target_addr_t addr, uint32_t asid, uint32_t length, int hw) { struct target *target = get_current_target(cmd->ctx); int retval; if (asid == 0) { retval = breakpoint_add(target, addr, length, hw); /* error is always logged in breakpoint_add(), do not print it again */ if (retval == ERROR_OK) command_print(cmd, "breakpoint set at " TARGET_ADDR_FMT "", addr); } else if (addr == 0) { if (!target->type->add_context_breakpoint) { LOG_ERROR("Context breakpoint not available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = context_breakpoint_add(target, asid, length, hw); /* error is always logged in context_breakpoint_add(), do not print it again */ if (retval == ERROR_OK) command_print(cmd, "Context breakpoint set at 0x%8.8" PRIx32 "", asid); } else { if (!target->type->add_hybrid_breakpoint) { LOG_ERROR("Hybrid breakpoint not available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = hybrid_breakpoint_add(target, addr, asid, length, hw); /* error is always logged in hybrid_breakpoint_add(), do not print it again */ if (retval == ERROR_OK) command_print(cmd, "Hybrid breakpoint set at 0x%8.8" PRIx32 "", asid); } return retval; } COMMAND_HANDLER(handle_bp_command) { target_addr_t addr; uint32_t asid; uint32_t length; int hw = BKPT_SOFT; switch (CMD_ARGC) { case 0: return handle_bp_command_list(CMD); case 2: asid = 0; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); return handle_bp_command_set(CMD, addr, asid, length, hw); case 3: if (strcmp(CMD_ARGV[2], "hw") == 0) { hw = BKPT_HARD; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); asid = 0; return handle_bp_command_set(CMD, addr, asid, length, hw); } else if (strcmp(CMD_ARGV[2], "hw_ctx") == 0) { hw = BKPT_HARD; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], asid); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); addr = 0; return handle_bp_command_set(CMD, addr, asid, length, hw); } /* fallthrough */ case 4: hw = BKPT_HARD; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], asid); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], length); return handle_bp_command_set(CMD, addr, asid, length, hw); default: return ERROR_COMMAND_SYNTAX_ERROR; } } COMMAND_HANDLER(handle_rbp_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); if (!strcmp(CMD_ARGV[0], "all")) { breakpoint_remove_all(target); } else { target_addr_t addr; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); breakpoint_remove(target, addr); } return ERROR_OK; } COMMAND_HANDLER(handle_wp_command) { struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC == 0) { struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { command_print(CMD, "address: " TARGET_ADDR_FMT ", len: 0x%8.8" PRIx32 ", r/w/a: %i, value: 0x%8.8" PRIx32 ", mask: 0x%8.8" PRIx32, watchpoint->address, watchpoint->length, (int)watchpoint->rw, watchpoint->value, watchpoint->mask); watchpoint = watchpoint->next; } return ERROR_OK; } enum watchpoint_rw type = WPT_ACCESS; target_addr_t addr = 0; uint32_t length = 0; uint32_t data_value = 0x0; uint32_t data_mask = 0xffffffff; switch (CMD_ARGC) { case 5: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], data_mask); /* fall through */ case 4: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], data_value); /* fall through */ case 3: switch (CMD_ARGV[2][0]) { case 'r': type = WPT_READ; break; case 'w': type = WPT_WRITE; break; case 'a': type = WPT_ACCESS; break; default: LOG_ERROR("invalid watchpoint mode ('%c')", CMD_ARGV[2][0]); return ERROR_COMMAND_SYNTAX_ERROR; } /* fall through */ case 2: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } int retval = watchpoint_add(target, addr, length, type, data_value, data_mask); if (retval != ERROR_OK) LOG_ERROR("Failure setting watchpoints"); return retval; } COMMAND_HANDLER(handle_rwp_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; target_addr_t addr; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); struct target *target = get_current_target(CMD_CTX); watchpoint_remove(target, addr); return ERROR_OK; } /** * Translate a virtual address to a physical address. * * The low-level target implementation must have logged a detailed error * which is forwarded to telnet/GDB session. */ COMMAND_HANDLER(handle_virt2phys_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; target_addr_t va; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], va); target_addr_t pa; struct target *target = get_current_target(CMD_CTX); int retval = target->type->virt2phys(target, va, &pa); if (retval == ERROR_OK) command_print(CMD, "Physical address " TARGET_ADDR_FMT "", pa); return retval; } static void write_data(FILE *f, const void *data, size_t len) { size_t written = fwrite(data, 1, len, f); if (written != len) LOG_ERROR("failed to write %zu bytes: %s", len, strerror(errno)); } static void write_long(FILE *f, int l, struct target *target) { uint8_t val[4]; target_buffer_set_u32(target, val, l); write_data(f, val, 4); } static void write_string(FILE *f, char *s) { write_data(f, s, strlen(s)); } typedef unsigned char UNIT[2]; /* unit of profiling */ /* Dump a gmon.out histogram file. */ static void write_gmon(uint32_t *samples, uint32_t sample_num, const char *filename, bool with_range, uint32_t start_address, uint32_t end_address, struct target *target, uint32_t duration_ms) { uint32_t i; FILE *f = fopen(filename, "w"); if (!f) return; write_string(f, "gmon"); write_long(f, 0x00000001, target); /* Version */ write_long(f, 0, target); /* padding */ write_long(f, 0, target); /* padding */ write_long(f, 0, target); /* padding */ uint8_t zero = 0; /* GMON_TAG_TIME_HIST */ write_data(f, &zero, 1); /* figure out bucket size */ uint32_t min; uint32_t max; if (with_range) { min = start_address; max = end_address; } else { min = samples[0]; max = samples[0]; for (i = 0; i < sample_num; i++) { if (min > samples[i]) min = samples[i]; if (max < samples[i]) max = samples[i]; } /* max should be (largest sample + 1) * Refer to binutils/gprof/hist.c (find_histogram_for_pc) */ if (max < UINT32_MAX) max++; /* gprof requires (max - min) >= 2 */ while ((max - min) < 2) { if (max < UINT32_MAX) max++; else min--; } } uint32_t address_space = max - min; /* FIXME: What is the reasonable number of buckets? * The profiling result will be more accurate if there are enough buckets. */ static const uint32_t max_buckets = 128 * 1024; /* maximum buckets. */ uint32_t num_buckets = address_space / sizeof(UNIT); if (num_buckets > max_buckets) num_buckets = max_buckets; int *buckets = malloc(sizeof(int) * num_buckets); if (!buckets) { fclose(f); return; } memset(buckets, 0, sizeof(int) * num_buckets); for (i = 0; i < sample_num; i++) { uint32_t address = samples[i]; if ((address < min) || (max <= address)) continue; long long a = address - min; long long b = num_buckets; long long c = address_space; int index_t = (a * b) / c; /* danger!!!! int32 overflows */ buckets[index_t]++; } /* append binary memory gmon.out &profile_hist_hdr ((char*)&profile_hist_hdr + sizeof(struct gmon_hist_hdr)) */ write_long(f, min, target); /* low_pc */ write_long(f, max, target); /* high_pc */ write_long(f, num_buckets, target); /* # of buckets */ float sample_rate = sample_num / (duration_ms / 1000.0); write_long(f, sample_rate, target); write_string(f, "seconds"); for (i = 0; i < (15-strlen("seconds")); i++) write_data(f, &zero, 1); write_string(f, "s"); /*append binary memory gmon.out profile_hist_data (profile_hist_data + profile_hist_hdr.hist_size) */ char *data = malloc(2 * num_buckets); if (data) { for (i = 0; i < num_buckets; i++) { int val; val = buckets[i]; if (val > 65535) val = 65535; data[i * 2] = val&0xff; data[i * 2 + 1] = (val >> 8) & 0xff; } free(buckets); write_data(f, data, num_buckets * 2); free(data); } else free(buckets); fclose(f); } /* profiling samples the CPU PC as quickly as OpenOCD is able, * which will be used as a random sampling of PC */ COMMAND_HANDLER(handle_profile_command) { struct target *target = get_current_target(CMD_CTX); if ((CMD_ARGC != 2) && (CMD_ARGC != 4)) return ERROR_COMMAND_SYNTAX_ERROR; const uint32_t MAX_PROFILE_SAMPLE_NUM = 10000; uint32_t offset; uint32_t num_of_samples; int retval = ERROR_OK; bool halted_before_profiling = target->state == TARGET_HALTED; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], offset); uint32_t start_address = 0; uint32_t end_address = 0; bool with_range = false; if (CMD_ARGC == 4) { with_range = true; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], start_address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], end_address); if (start_address > end_address || (end_address - start_address) < 2) { command_print(CMD, "Error: end - start < 2"); return ERROR_COMMAND_ARGUMENT_INVALID; } } uint32_t *samples = malloc(sizeof(uint32_t) * MAX_PROFILE_SAMPLE_NUM); if (!samples) { LOG_ERROR("No memory to store samples."); return ERROR_FAIL; } uint64_t timestart_ms = timeval_ms(); /** * Some cores let us sample the PC without the * annoying halt/resume step; for example, ARMv7 PCSR. * Provide a way to use that more efficient mechanism. */ retval = target_profiling(target, samples, MAX_PROFILE_SAMPLE_NUM, &num_of_samples, offset); if (retval != ERROR_OK) { free(samples); return retval; } uint32_t duration_ms = timeval_ms() - timestart_ms; assert(num_of_samples <= MAX_PROFILE_SAMPLE_NUM); retval = target_poll(target); if (retval != ERROR_OK) { free(samples); return retval; } if (target->state == TARGET_RUNNING && halted_before_profiling) { /* The target was halted before we started and is running now. Halt it, * for consistency. */ retval = target_halt(target); if (retval != ERROR_OK) { free(samples); return retval; } } else if (target->state == TARGET_HALTED && !halted_before_profiling) { /* The target was running before we started and is halted now. Resume * it, for consistency. */ retval = target_resume(target, 1, 0, 0, 0); if (retval != ERROR_OK) { free(samples); return retval; } } retval = target_poll(target); if (retval != ERROR_OK) { free(samples); return retval; } write_gmon(samples, num_of_samples, CMD_ARGV[1], with_range, start_address, end_address, target, duration_ms); command_print(CMD, "Wrote %s", CMD_ARGV[1]); free(samples); return retval; } static int new_u64_array_element(Jim_Interp *interp, const char *varname, int idx, uint64_t val) { char *namebuf; Jim_Obj *obj_name, *obj_val; int result; namebuf = alloc_printf("%s(%d)", varname, idx); if (!namebuf) return JIM_ERR; obj_name = Jim_NewStringObj(interp, namebuf, -1); jim_wide wide_val = val; obj_val = Jim_NewWideObj(interp, wide_val); if (!obj_name || !obj_val) { free(namebuf); return JIM_ERR; } Jim_IncrRefCount(obj_name); Jim_IncrRefCount(obj_val); result = Jim_SetVariable(interp, obj_name, obj_val); Jim_DecrRefCount(interp, obj_name); Jim_DecrRefCount(interp, obj_val); free(namebuf); /* printf("%s(%d) <= 0%08x\n", varname, idx, val); */ return result; } static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv) { int e; LOG_WARNING("DEPRECATED! use 'read_memory' not 'mem2array'"); /* argv[0] = name of array to receive the data * argv[1] = desired element width in bits * argv[2] = memory address * argv[3] = count of times to read * argv[4] = optional "phys" */ if (argc < 4 || argc > 5) { Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]"); return JIM_ERR; } /* Arg 0: Name of the array variable */ const char *varname = Jim_GetString(argv[0], NULL); /* Arg 1: Bit width of one element */ long l; e = Jim_GetLong(interp, argv[1], &l); if (e != JIM_OK) return e; const unsigned int width_bits = l; if (width_bits != 8 && width_bits != 16 && width_bits != 32 && width_bits != 64) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param. Must be one of: 8, 16, 32 or 64.", NULL); return JIM_ERR; } const unsigned int width = width_bits / 8; /* Arg 2: Memory address */ jim_wide wide_addr; e = Jim_GetWide(interp, argv[2], &wide_addr); if (e != JIM_OK) return e; target_addr_t addr = (target_addr_t)wide_addr; /* Arg 3: Number of elements to read */ e = Jim_GetLong(interp, argv[3], &l); if (e != JIM_OK) return e; size_t len = l; /* Arg 4: phys */ bool is_phys = false; if (argc > 4) { int str_len = 0; const char *phys = Jim_GetString(argv[4], &str_len); if (!strncmp(phys, "phys", str_len)) is_phys = true; else return JIM_ERR; } /* Argument checks */ if (len == 0) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: zero width read?", NULL); return JIM_ERR; } if ((addr + (len * width)) < addr) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: addr + len - wraps to zero?", NULL); return JIM_ERR; } if (len > 65536) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: too large read request, exceeds 64K items", NULL); return JIM_ERR; } if ((width == 1) || ((width == 2) && ((addr & 1) == 0)) || ((width == 4) && ((addr & 3) == 0)) || ((width == 8) && ((addr & 7) == 0))) { /* alignment correct */ } else { char buf[100]; Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); sprintf(buf, "mem2array address: " TARGET_ADDR_FMT " is not aligned for %" PRIu32 " byte reads", addr, width); Jim_AppendStrings(interp, Jim_GetResult(interp), buf, NULL); return JIM_ERR; } /* Transfer loop */ /* index counter */ size_t idx = 0; const size_t buffersize = 4096; uint8_t *buffer = malloc(buffersize); if (!buffer) return JIM_ERR; /* assume ok */ e = JIM_OK; while (len) { /* Slurp... in buffer size chunks */ const unsigned int max_chunk_len = buffersize / width; const size_t chunk_len = MIN(len, max_chunk_len); /* in elements.. */ int retval; if (is_phys) retval = target_read_phys_memory(target, addr, width, chunk_len, buffer); else retval = target_read_memory(target, addr, width, chunk_len, buffer); if (retval != ERROR_OK) { /* BOO !*/ LOG_ERROR("mem2array: Read @ " TARGET_ADDR_FMT ", w=%u, cnt=%zu, failed", addr, width, chunk_len); Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL); e = JIM_ERR; break; } else { for (size_t i = 0; i < chunk_len ; i++, idx++) { uint64_t v = 0; switch (width) { case 8: v = target_buffer_get_u64(target, &buffer[i*width]); break; case 4: v = target_buffer_get_u32(target, &buffer[i*width]); break; case 2: v = target_buffer_get_u16(target, &buffer[i*width]); break; case 1: v = buffer[i] & 0x0ff; break; } new_u64_array_element(interp, varname, idx, v); } len -= chunk_len; addr += chunk_len * width; } } free(buffer); Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); return e; } COMMAND_HANDLER(handle_target_read_memory) { /* * CMD_ARGV[0] = memory address * CMD_ARGV[1] = desired element width in bits * CMD_ARGV[2] = number of elements to read * CMD_ARGV[3] = optional "phys" */ if (CMD_ARGC < 3 || CMD_ARGC > 4) return ERROR_COMMAND_SYNTAX_ERROR; /* Arg 1: Memory address. */ target_addr_t addr; COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], addr); /* Arg 2: Bit width of one element. */ unsigned int width_bits; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], width_bits); /* Arg 3: Number of elements to read. */ unsigned int count; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], count); /* Arg 4: Optional 'phys'. */ bool is_phys = false; if (CMD_ARGC == 4) { if (strcmp(CMD_ARGV[3], "phys")) { command_print(CMD, "invalid argument '%s', must be 'phys'", CMD_ARGV[3]); return ERROR_COMMAND_ARGUMENT_INVALID; } is_phys = true; } switch (width_bits) { case 8: case 16: case 32: case 64: break; default: command_print(CMD, "invalid width, must be 8, 16, 32 or 64"); return ERROR_COMMAND_ARGUMENT_INVALID; } const unsigned int width = width_bits / 8; if ((addr + (count * width)) < addr) { command_print(CMD, "read_memory: addr + count wraps to zero"); return ERROR_COMMAND_ARGUMENT_INVALID; } if (count > 65536) { command_print(CMD, "read_memory: too large read request, exceeds 64K elements"); return ERROR_COMMAND_ARGUMENT_INVALID; } struct target *target = get_current_target(CMD_CTX); const size_t buffersize = 4096; uint8_t *buffer = malloc(buffersize); if (!buffer) { LOG_ERROR("Failed to allocate memory"); return ERROR_FAIL; } char *separator = ""; while (count > 0) { const unsigned int max_chunk_len = buffersize / width; const size_t chunk_len = MIN(count, max_chunk_len); int retval; if (is_phys) retval = target_read_phys_memory(target, addr, width, chunk_len, buffer); else retval = target_read_memory(target, addr, width, chunk_len, buffer); if (retval != ERROR_OK) { LOG_DEBUG("read_memory: read at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", addr, width_bits, chunk_len); /* * FIXME: we append the errmsg to the list of value already read. * Add a way to flush and replace old output, but LOG_DEBUG() it */ command_print(CMD, "read_memory: failed to read memory"); free(buffer); return retval; } for (size_t i = 0; i < chunk_len ; i++) { uint64_t v = 0; switch (width) { case 8: v = target_buffer_get_u64(target, &buffer[i * width]); break; case 4: v = target_buffer_get_u32(target, &buffer[i * width]); break; case 2: v = target_buffer_get_u16(target, &buffer[i * width]); break; case 1: v = buffer[i]; break; } command_print_sameline(CMD, "%s0x%" PRIx64, separator, v); separator = " "; } count -= chunk_len; addr += chunk_len * width; } free(buffer); return ERROR_OK; } static int get_u64_array_element(Jim_Interp *interp, const char *varname, size_t idx, uint64_t *val) { char *namebuf = alloc_printf("%s(%zu)", varname, idx); if (!namebuf) return JIM_ERR; Jim_Obj *obj_name = Jim_NewStringObj(interp, namebuf, -1); if (!obj_name) { free(namebuf); return JIM_ERR; } Jim_IncrRefCount(obj_name); Jim_Obj *obj_val = Jim_GetVariable(interp, obj_name, JIM_ERRMSG); Jim_DecrRefCount(interp, obj_name); free(namebuf); if (!obj_val) return JIM_ERR; jim_wide wide_val; int result = Jim_GetWide(interp, obj_val, &wide_val); *val = wide_val; return result; } static int target_array2mem(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv) { int e; LOG_WARNING("DEPRECATED! use 'write_memory' not 'array2mem'"); /* argv[0] = name of array from which to read the data * argv[1] = desired element width in bits * argv[2] = memory address * argv[3] = number of elements to write * argv[4] = optional "phys" */ if (argc < 4 || argc > 5) { Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]"); return JIM_ERR; } /* Arg 0: Name of the array variable */ const char *varname = Jim_GetString(argv[0], NULL); /* Arg 1: Bit width of one element */ long l; e = Jim_GetLong(interp, argv[1], &l); if (e != JIM_OK) return e; const unsigned int width_bits = l; if (width_bits != 8 && width_bits != 16 && width_bits != 32 && width_bits != 64) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param. Must be one of: 8, 16, 32 or 64.", NULL); return JIM_ERR; } const unsigned int width = width_bits / 8; /* Arg 2: Memory address */ jim_wide wide_addr; e = Jim_GetWide(interp, argv[2], &wide_addr); if (e != JIM_OK) return e; target_addr_t addr = (target_addr_t)wide_addr; /* Arg 3: Number of elements to write */ e = Jim_GetLong(interp, argv[3], &l); if (e != JIM_OK) return e; size_t len = l; /* Arg 4: Phys */ bool is_phys = false; if (argc > 4) { int str_len = 0; const char *phys = Jim_GetString(argv[4], &str_len); if (!strncmp(phys, "phys", str_len)) is_phys = true; else return JIM_ERR; } /* Argument checks */ if (len == 0) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: zero width read?", NULL); return JIM_ERR; } if ((addr + (len * width)) < addr) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: addr + len - wraps to zero?", NULL); return JIM_ERR; } if (len > 65536) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: too large memory write request, exceeds 64K items", NULL); return JIM_ERR; } if ((width == 1) || ((width == 2) && ((addr & 1) == 0)) || ((width == 4) && ((addr & 3) == 0)) || ((width == 8) && ((addr & 7) == 0))) { /* alignment correct */ } else { char buf[100]; Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); sprintf(buf, "array2mem address: " TARGET_ADDR_FMT " is not aligned for %" PRIu32 " byte reads", addr, width); Jim_AppendStrings(interp, Jim_GetResult(interp), buf, NULL); return JIM_ERR; } /* Transfer loop */ /* assume ok */ e = JIM_OK; const size_t buffersize = 4096; uint8_t *buffer = malloc(buffersize); if (!buffer) return JIM_ERR; /* index counter */ size_t idx = 0; while (len) { /* Slurp... in buffer size chunks */ const unsigned int max_chunk_len = buffersize / width; const size_t chunk_len = MIN(len, max_chunk_len); /* in elements.. */ /* Fill the buffer */ for (size_t i = 0; i < chunk_len; i++, idx++) { uint64_t v = 0; if (get_u64_array_element(interp, varname, idx, &v) != JIM_OK) { free(buffer); return JIM_ERR; } switch (width) { case 8: target_buffer_set_u64(target, &buffer[i * width], v); break; case 4: target_buffer_set_u32(target, &buffer[i * width], v); break; case 2: target_buffer_set_u16(target, &buffer[i * width], v); break; case 1: buffer[i] = v & 0x0ff; break; } } len -= chunk_len; /* Write the buffer to memory */ int retval; if (is_phys) retval = target_write_phys_memory(target, addr, width, chunk_len, buffer); else retval = target_write_memory(target, addr, width, chunk_len, buffer); if (retval != ERROR_OK) { /* BOO !*/ LOG_ERROR("array2mem: Write @ " TARGET_ADDR_FMT ", w=%u, cnt=%zu, failed", addr, width, chunk_len); Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: cannot read memory", NULL); e = JIM_ERR; break; } addr += chunk_len * width; } free(buffer); Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); return e; } static int target_jim_write_memory(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { /* * argv[1] = memory address * argv[2] = desired element width in bits * argv[3] = list of data to write * argv[4] = optional "phys" */ if (argc < 4 || argc > 5) { Jim_WrongNumArgs(interp, 1, argv, "address width data ['phys']"); return JIM_ERR; } /* Arg 1: Memory address. */ int e; jim_wide wide_addr; e = Jim_GetWide(interp, argv[1], &wide_addr); if (e != JIM_OK) return e; target_addr_t addr = (target_addr_t)wide_addr; /* Arg 2: Bit width of one element. */ long l; e = Jim_GetLong(interp, argv[2], &l); if (e != JIM_OK) return e; const unsigned int width_bits = l; size_t count = Jim_ListLength(interp, argv[3]); /* Arg 4: Optional 'phys'. */ bool is_phys = false; if (argc > 4) { const char *phys = Jim_GetString(argv[4], NULL); if (strcmp(phys, "phys")) { Jim_SetResultFormatted(interp, "invalid argument '%s', must be 'phys'", phys); return JIM_ERR; } is_phys = true; } switch (width_bits) { case 8: case 16: case 32: case 64: break; default: Jim_SetResultString(interp, "invalid width, must be 8, 16, 32 or 64", -1); return JIM_ERR; } const unsigned int width = width_bits / 8; if ((addr + (count * width)) < addr) { Jim_SetResultString(interp, "write_memory: addr + len wraps to zero", -1); return JIM_ERR; } if (count > 65536) { Jim_SetResultString(interp, "write_memory: too large memory write request, exceeds 64K elements", -1); return JIM_ERR; } struct command_context *cmd_ctx = current_command_context(interp); assert(cmd_ctx != NULL); struct target *target = get_current_target(cmd_ctx); const size_t buffersize = 4096; uint8_t *buffer = malloc(buffersize); if (!buffer) { LOG_ERROR("Failed to allocate memory"); return JIM_ERR; } size_t j = 0; while (count > 0) { const unsigned int max_chunk_len = buffersize / width; const size_t chunk_len = MIN(count, max_chunk_len); for (size_t i = 0; i < chunk_len; i++, j++) { Jim_Obj *tmp = Jim_ListGetIndex(interp, argv[3], j); jim_wide element_wide; Jim_GetWide(interp, tmp, &element_wide); const uint64_t v = element_wide; switch (width) { case 8: target_buffer_set_u64(target, &buffer[i * width], v); break; case 4: target_buffer_set_u32(target, &buffer[i * width], v); break; case 2: target_buffer_set_u16(target, &buffer[i * width], v); break; case 1: buffer[i] = v & 0x0ff; break; } } count -= chunk_len; int retval; if (is_phys) retval = target_write_phys_memory(target, addr, width, chunk_len, buffer); else retval = target_write_memory(target, addr, width, chunk_len, buffer); if (retval != ERROR_OK) { LOG_ERROR("write_memory: write at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", addr, width_bits, chunk_len); Jim_SetResultString(interp, "write_memory: failed to write memory", -1); e = JIM_ERR; break; } addr += chunk_len * width; } free(buffer); return e; } /* FIX? should we propagate errors here rather than printing them * and continuing? */ void target_handle_event(struct target *target, enum target_event e) { struct target_event_action *teap; int retval; for (teap = target->event_action; teap; teap = teap->next) { if (teap->event == e) { LOG_DEBUG("target(%d): %s (%s) event: %d (%s) action: %s", target->target_number, target_name(target), target_type_name(target), e, target_event_name(e), Jim_GetString(teap->body, NULL)); /* Override current target by the target an event * is issued from (lot of scripts need it). * Return back to previous override as soon * as the handler processing is done */ struct command_context *cmd_ctx = current_command_context(teap->interp); struct target *saved_target_override = cmd_ctx->current_target_override; cmd_ctx->current_target_override = target; retval = Jim_EvalObj(teap->interp, teap->body); cmd_ctx->current_target_override = saved_target_override; if (retval == ERROR_COMMAND_CLOSE_CONNECTION) return; if (retval == JIM_RETURN) retval = teap->interp->returnCode; if (retval != JIM_OK) { Jim_MakeErrorMessage(teap->interp); LOG_USER("Error executing event %s on target %s:\n%s", target_event_name(e), target_name(target), Jim_GetString(Jim_GetResult(teap->interp), NULL)); /* clean both error code and stacktrace before return */ Jim_Eval(teap->interp, "error \"\" \"\""); } } } } static int target_jim_get_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { bool force = false; if (argc == 3) { const char *option = Jim_GetString(argv[1], NULL); if (!strcmp(option, "-force")) { argc--; argv++; force = true; } else { Jim_SetResultFormatted(interp, "invalid option '%s'", option); return JIM_ERR; } } if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "[-force] list"); return JIM_ERR; } const int length = Jim_ListLength(interp, argv[1]); Jim_Obj *result_dict = Jim_NewDictObj(interp, NULL, 0); if (!result_dict) return JIM_ERR; struct command_context *cmd_ctx = current_command_context(interp); assert(cmd_ctx != NULL); const struct target *target = get_current_target(cmd_ctx); for (int i = 0; i < length; i++) { Jim_Obj *elem = Jim_ListGetIndex(interp, argv[1], i); if (!elem) return JIM_ERR; const char *reg_name = Jim_String(elem); struct reg *reg = register_get_by_name(target->reg_cache, reg_name, false); if (!reg || !reg->exist) { Jim_SetResultFormatted(interp, "unknown register '%s'", reg_name); return JIM_ERR; } if (force) { int retval = reg->type->get(reg); if (retval != ERROR_OK) { Jim_SetResultFormatted(interp, "failed to read register '%s'", reg_name); return JIM_ERR; } } char *reg_value = buf_to_hex_str(reg->value, reg->size); if (!reg_value) { LOG_ERROR("Failed to allocate memory"); return JIM_ERR; } char *tmp = alloc_printf("0x%s", reg_value); free(reg_value); if (!tmp) { LOG_ERROR("Failed to allocate memory"); return JIM_ERR; } Jim_DictAddElement(interp, result_dict, elem, Jim_NewStringObj(interp, tmp, -1)); free(tmp); } Jim_SetResult(interp, result_dict); return JIM_OK; } static int target_jim_set_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "dict"); return JIM_ERR; } int tmp; #if JIM_VERSION >= 80 Jim_Obj **dict = Jim_DictPairs(interp, argv[1], &tmp); if (!dict) return JIM_ERR; #else Jim_Obj **dict; int ret = Jim_DictPairs(interp, argv[1], &dict, &tmp); if (ret != JIM_OK) return ret; #endif const unsigned int length = tmp; struct command_context *cmd_ctx = current_command_context(interp); assert(cmd_ctx); const struct target *target = get_current_target(cmd_ctx); for (unsigned int i = 0; i < length; i += 2) { const char *reg_name = Jim_String(dict[i]); const char *reg_value = Jim_String(dict[i + 1]); struct reg *reg = register_get_by_name(target->reg_cache, reg_name, false); if (!reg || !reg->exist) { Jim_SetResultFormatted(interp, "unknown register '%s'", reg_name); return JIM_ERR; } uint8_t *buf = malloc(DIV_ROUND_UP(reg->size, 8)); if (!buf) { LOG_ERROR("Failed to allocate memory"); return JIM_ERR; } str_to_buf(reg_value, strlen(reg_value), buf, reg->size, 0); int retval = reg->type->set(reg, buf); free(buf); if (retval != ERROR_OK) { Jim_SetResultFormatted(interp, "failed to set '%s' to register '%s'", reg_value, reg_name); return JIM_ERR; } } return JIM_OK; } /** * Returns true only if the target has a handler for the specified event. */ bool target_has_event_action(struct target *target, enum target_event event) { struct target_event_action *teap; for (teap = target->event_action; teap; teap = teap->next) { if (teap->event == event) return true; } return false; } enum target_cfg_param { TCFG_TYPE, TCFG_EVENT, TCFG_WORK_AREA_VIRT, TCFG_WORK_AREA_PHYS, TCFG_WORK_AREA_SIZE, TCFG_WORK_AREA_BACKUP, TCFG_ENDIAN, TCFG_COREID, TCFG_CHAIN_POSITION, TCFG_DBGBASE, TCFG_RTOS, TCFG_DEFER_EXAMINE, TCFG_GDB_PORT, TCFG_GDB_MAX_CONNECTIONS, }; static struct jim_nvp nvp_config_opts[] = { { .name = "-type", .value = TCFG_TYPE }, { .name = "-event", .value = TCFG_EVENT }, { .name = "-work-area-virt", .value = TCFG_WORK_AREA_VIRT }, { .name = "-work-area-phys", .value = TCFG_WORK_AREA_PHYS }, { .name = "-work-area-size", .value = TCFG_WORK_AREA_SIZE }, { .name = "-work-area-backup", .value = TCFG_WORK_AREA_BACKUP }, { .name = "-endian", .value = TCFG_ENDIAN }, { .name = "-coreid", .value = TCFG_COREID }, { .name = "-chain-position", .value = TCFG_CHAIN_POSITION }, { .name = "-dbgbase", .value = TCFG_DBGBASE }, { .name = "-rtos", .value = TCFG_RTOS }, { .name = "-defer-examine", .value = TCFG_DEFER_EXAMINE }, { .name = "-gdb-port", .value = TCFG_GDB_PORT }, { .name = "-gdb-max-connections", .value = TCFG_GDB_MAX_CONNECTIONS }, { .name = NULL, .value = -1 } }; static int target_configure(struct jim_getopt_info *goi, struct target *target) { struct jim_nvp *n; Jim_Obj *o; jim_wide w; int e; /* parse config or cget options ... */ while (goi->argc > 0) { Jim_SetEmptyResult(goi->interp); /* jim_getopt_debug(goi); */ if (target->type->target_jim_configure) { /* target defines a configure function */ /* target gets first dibs on parameters */ e = (*(target->type->target_jim_configure))(target, goi); if (e == JIM_OK) { /* more? */ continue; } if (e == JIM_ERR) { /* An error */ return e; } /* otherwise we 'continue' below */ } e = jim_getopt_nvp(goi, nvp_config_opts, &n); if (e != JIM_OK) { jim_getopt_nvp_unknown(goi, nvp_config_opts, 0); return e; } switch (n->value) { case TCFG_TYPE: /* not settable */ if (goi->isconfigure) { Jim_SetResultFormatted(goi->interp, "not settable: %s", n->name); return JIM_ERR; } else { no_params: if (goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); return JIM_ERR; } } Jim_SetResultString(goi->interp, target_type_name(target), -1); /* loop for more */ break; case TCFG_EVENT: if (goi->argc == 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ..."); return JIM_ERR; } e = jim_getopt_nvp(goi, nvp_target_event, &n); if (e != JIM_OK) { jim_getopt_nvp_unknown(goi, nvp_target_event, 1); return e; } if (goi->isconfigure) { if (goi->argc != 1) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?"); return JIM_ERR; } } else { if (goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?"); return JIM_ERR; } } { struct target_event_action *teap; teap = target->event_action; /* replace existing? */ while (teap) { if (teap->event == (enum target_event)n->value) break; teap = teap->next; } if (goi->isconfigure) { /* START_DEPRECATED_TPIU */ if (n->value == TARGET_EVENT_TRACE_CONFIG) LOG_INFO("DEPRECATED target event %s; use TPIU events {pre,post}-{enable,disable}", n->name); /* END_DEPRECATED_TPIU */ bool replace = true; if (!teap) { /* create new */ teap = calloc(1, sizeof(*teap)); replace = false; } teap->event = n->value; teap->interp = goi->interp; jim_getopt_obj(goi, &o); if (teap->body) Jim_DecrRefCount(teap->interp, teap->body); teap->body = Jim_DuplicateObj(goi->interp, o); /* * FIXME: * Tcl/TK - "tk events" have a nice feature. * See the "BIND" command. * We should support that here. * You can specify %X and %Y in the event code. * The idea is: %T - target name. * The idea is: %N - target number * The idea is: %E - event name. */ Jim_IncrRefCount(teap->body); if (!replace) { /* add to head of event list */ teap->next = target->event_action; target->event_action = teap; } Jim_SetEmptyResult(goi->interp); } else { /* get */ if (!teap) Jim_SetEmptyResult(goi->interp); else Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, teap->body)); } } /* loop for more */ break; case TCFG_WORK_AREA_VIRT: if (goi->isconfigure) { target_free_all_working_areas(target); e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; target->working_area_virt = w; target->working_area_virt_spec = true; } else { if (goi->argc != 0) goto no_params; } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_virt)); /* loop for more */ break; case TCFG_WORK_AREA_PHYS: if (goi->isconfigure) { target_free_all_working_areas(target); e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; target->working_area_phys = w; target->working_area_phys_spec = true; } else { if (goi->argc != 0) goto no_params; } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_phys)); /* loop for more */ break; case TCFG_WORK_AREA_SIZE: if (goi->isconfigure) { target_free_all_working_areas(target); e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; target->working_area_size = w; } else { if (goi->argc != 0) goto no_params; } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_size)); /* loop for more */ break; case TCFG_WORK_AREA_BACKUP: if (goi->isconfigure) { target_free_all_working_areas(target); e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; /* make this exactly 1 or 0 */ target->backup_working_area = (!!w); } else { if (goi->argc != 0) goto no_params; } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->backup_working_area)); /* loop for more e*/ break; case TCFG_ENDIAN: if (goi->isconfigure) { e = jim_getopt_nvp(goi, nvp_target_endian, &n); if (e != JIM_OK) { jim_getopt_nvp_unknown(goi, nvp_target_endian, 1); return e; } target->endianness = n->value; } else { if (goi->argc != 0) goto no_params; } n = jim_nvp_value2name_simple(nvp_target_endian, target->endianness); if (!n->name) { target->endianness = TARGET_LITTLE_ENDIAN; n = jim_nvp_value2name_simple(nvp_target_endian, target->endianness); } Jim_SetResultString(goi->interp, n->name, -1); /* loop for more */ break; case TCFG_COREID: if (goi->isconfigure) { e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; target->coreid = (int32_t)w; } else { if (goi->argc != 0) goto no_params; } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->coreid)); /* loop for more */ break; case TCFG_CHAIN_POSITION: if (goi->isconfigure) { Jim_Obj *o_t; struct jtag_tap *tap; if (target->has_dap) { Jim_SetResultString(goi->interp, "target requires -dap parameter instead of -chain-position!", -1); return JIM_ERR; } target_free_all_working_areas(target); e = jim_getopt_obj(goi, &o_t); if (e != JIM_OK) return e; tap = jtag_tap_by_jim_obj(goi->interp, o_t); if (!tap) return JIM_ERR; target->tap = tap; target->tap_configured = true; } else { if (goi->argc != 0) goto no_params; } Jim_SetResultString(goi->interp, target->tap->dotted_name, -1); /* loop for more e*/ break; case TCFG_DBGBASE: if (goi->isconfigure) { e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; target->dbgbase = (uint32_t)w; target->dbgbase_set = true; } else { if (goi->argc != 0) goto no_params; } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->dbgbase)); /* loop for more */ break; case TCFG_RTOS: /* RTOS */ { int result = rtos_create(goi, target); if (result != JIM_OK) return result; } /* loop for more */ break; case TCFG_DEFER_EXAMINE: /* DEFER_EXAMINE */ target->defer_examine = true; /* loop for more */ break; case TCFG_GDB_PORT: if (goi->isconfigure) { struct command_context *cmd_ctx = current_command_context(goi->interp); if (cmd_ctx->mode != COMMAND_CONFIG) { Jim_SetResultString(goi->interp, "-gdb-port must be configured before 'init'", -1); return JIM_ERR; } const char *s; e = jim_getopt_string(goi, &s, NULL); if (e != JIM_OK) return e; free(target->gdb_port_override); target->gdb_port_override = strdup(s); } else { if (goi->argc != 0) goto no_params; } Jim_SetResultString(goi->interp, target->gdb_port_override ? target->gdb_port_override : "undefined", -1); /* loop for more */ break; case TCFG_GDB_MAX_CONNECTIONS: if (goi->isconfigure) { struct command_context *cmd_ctx = current_command_context(goi->interp); if (cmd_ctx->mode != COMMAND_CONFIG) { Jim_SetResultString(goi->interp, "-gdb-max-connections must be configured before 'init'", -1); return JIM_ERR; } e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; target->gdb_max_connections = (w < 0) ? CONNECTION_LIMIT_UNLIMITED : (int)w; } else { if (goi->argc != 0) goto no_params; } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->gdb_max_connections)); break; } } /* while (goi->argc) */ /* done - we return */ return JIM_OK; } static int jim_target_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { struct command *c = jim_to_command(interp); struct jim_getopt_info goi; jim_getopt_setup(&goi, interp, argc - 1, argv + 1); goi.isconfigure = !strcmp(c->name, "configure"); if (goi.argc < 1) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "missing: -option ..."); return JIM_ERR; } struct command_context *cmd_ctx = current_command_context(interp); assert(cmd_ctx); struct target *target = get_current_target(cmd_ctx); return target_configure(&goi, target); } static int jim_target_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct command_context *cmd_ctx = current_command_context(interp); assert(cmd_ctx); struct target *target = get_current_target(cmd_ctx); return target_mem2array(interp, target, argc - 1, argv + 1); } static int jim_target_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct command_context *cmd_ctx = current_command_context(interp); assert(cmd_ctx); struct target *target = get_current_target(cmd_ctx); return target_array2mem(interp, target, argc - 1, argv + 1); } COMMAND_HANDLER(handle_target_examine) { bool allow_defer = false; if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { if (strcmp(CMD_ARGV[0], "allow-defer")) return ERROR_COMMAND_ARGUMENT_INVALID; allow_defer = true; } struct target *target = get_current_target(CMD_CTX); if (!target->tap->enabled) { command_print(CMD, "[TAP is disabled]"); return ERROR_FAIL; } if (allow_defer && target->defer_examine) { LOG_INFO("Deferring arp_examine of %s", target_name(target)); LOG_INFO("Use arp_examine command to examine it manually!"); return ERROR_OK; } int retval = target->type->examine(target); if (retval != ERROR_OK) { target_reset_examined(target); return retval; } target_set_examined(target); return ERROR_OK; } COMMAND_HANDLER(handle_target_was_examined) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); command_print(CMD, "%d", target_was_examined(target) ? 1 : 0); return ERROR_OK; } COMMAND_HANDLER(handle_target_examine_deferred) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); command_print(CMD, "%d", target->defer_examine ? 1 : 0); return ERROR_OK; } COMMAND_HANDLER(handle_target_halt_gdb) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); return target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } COMMAND_HANDLER(handle_target_poll) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); if (!target->tap->enabled) { command_print(CMD, "[TAP is disabled]"); return ERROR_FAIL; } if (!(target_was_examined(target))) return ERROR_TARGET_NOT_EXAMINED; return target->type->poll(target); } COMMAND_HANDLER(handle_target_reset) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; const struct nvp *n = nvp_name2value(nvp_assert, CMD_ARGV[0]); if (!n->name) { nvp_unknown_command_print(CMD, nvp_assert, NULL, CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } /* the halt or not param */ int a; COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], a); struct target *target = get_current_target(CMD_CTX); if (!target->tap->enabled) { command_print(CMD, "[TAP is disabled]"); return ERROR_FAIL; } if (!target->type->assert_reset || !target->type->deassert_reset) { command_print(CMD, "No target-specific reset for %s", target_name(target)); return ERROR_FAIL; } if (target->defer_examine) target_reset_examined(target); /* determine if we should halt or not. */ target->reset_halt = (a != 0); /* When this happens - all workareas are invalid. */ target_free_all_working_areas_restore(target, 0); /* do the assert */ if (n->value == NVP_ASSERT) return target->type->assert_reset(target); return target->type->deassert_reset(target); } COMMAND_HANDLER(handle_target_halt) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); if (!target->tap->enabled) { command_print(CMD, "[TAP is disabled]"); return ERROR_FAIL; } return target->type->halt(target); } COMMAND_HANDLER(handle_target_wait_state) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; const struct nvp *n = nvp_name2value(nvp_target_state, CMD_ARGV[0]); if (!n->name) { nvp_unknown_command_print(CMD, nvp_target_state, NULL, CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } unsigned int a; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], a); struct target *target = get_current_target(CMD_CTX); if (!target->tap->enabled) { command_print(CMD, "[TAP is disabled]"); return ERROR_FAIL; } int retval = target_wait_state(target, n->value, a); if (retval != ERROR_OK) { command_print(CMD, "target: %s wait %s fails (%d) %s", target_name(target), n->name, retval, target_strerror_safe(retval)); return retval; } return ERROR_OK; } /* List for human, Events defined for this target. * scripts/programs should use 'name cget -event NAME' */ COMMAND_HANDLER(handle_target_event_list) { struct target *target = get_current_target(CMD_CTX); struct target_event_action *teap = target->event_action; command_print(CMD, "Event actions for target (%d) %s\n", target->target_number, target_name(target)); command_print(CMD, "%-25s | Body", "Event"); command_print(CMD, "------------------------- | " "----------------------------------------"); while (teap) { command_print(CMD, "%-25s | %s", target_event_name(teap->event), Jim_GetString(teap->body, NULL)); teap = teap->next; } command_print(CMD, "***END***"); return ERROR_OK; } COMMAND_HANDLER(handle_target_current_state) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); command_print(CMD, "%s", target_state_name(target)); return ERROR_OK; } static int jim_target_invoke_event(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct jim_getopt_info goi; jim_getopt_setup(&goi, interp, argc - 1, argv + 1); if (goi.argc != 1) { const char *cmd_name = Jim_GetString(argv[0], NULL); Jim_SetResultFormatted(goi.interp, "%s <eventname>", cmd_name); return JIM_ERR; } struct jim_nvp *n; int e = jim_getopt_nvp(&goi, nvp_target_event, &n); if (e != JIM_OK) { jim_getopt_nvp_unknown(&goi, nvp_target_event, 1); return e; } struct command_context *cmd_ctx = current_command_context(interp); assert(cmd_ctx); struct target *target = get_current_target(cmd_ctx); target_handle_event(target, n->value); return JIM_OK; } static const struct command_registration target_instance_command_handlers[] = { { .name = "configure", .mode = COMMAND_ANY, .jim_handler = jim_target_configure, .help = "configure a new target for use", .usage = "[target_attribute ...]", }, { .name = "cget", .mode = COMMAND_ANY, .jim_handler = jim_target_configure, .help = "returns the specified target attribute", .usage = "target_attribute", }, { .name = "mwd", .handler = handle_mw_command, .mode = COMMAND_EXEC, .help = "Write 64-bit word(s) to target memory", .usage = "address data [count]", }, { .name = "mww", .handler = handle_mw_command, .mode = COMMAND_EXEC, .help = "Write 32-bit word(s) to target memory", .usage = "address data [count]", }, { .name = "mwh", .handler = handle_mw_command, .mode = COMMAND_EXEC, .help = "Write 16-bit half-word(s) to target memory", .usage = "address data [count]", }, { .name = "mwb", .handler = handle_mw_command, .mode = COMMAND_EXEC, .help = "Write byte(s) to target memory", .usage = "address data [count]", }, { .name = "mdd", .handler = handle_md_command, .mode = COMMAND_EXEC, .help = "Display target memory as 64-bit words", .usage = "address [count]", }, { .name = "mdw", .handler = handle_md_command, .mode = COMMAND_EXEC, .help = "Display target memory as 32-bit words", .usage = "address [count]", }, { .name = "mdh", .handler = handle_md_command, .mode = COMMAND_EXEC, .help = "Display target memory as 16-bit half-words", .usage = "address [count]", }, { .name = "mdb", .handler = handle_md_command, .mode = COMMAND_EXEC, .help = "Display target memory as 8-bit bytes", .usage = "address [count]", }, { .name = "array2mem", .mode = COMMAND_EXEC, .jim_handler = jim_target_array2mem, .help = "Writes Tcl array of 8/16/32 bit numbers " "to target memory", .usage = "arrayname bitwidth address count", }, { .name = "mem2array", .mode = COMMAND_EXEC, .jim_handler = jim_target_mem2array, .help = "Loads Tcl array of 8/16/32 bit numbers " "from target memory", .usage = "arrayname bitwidth address count", }, { .name = "get_reg", .mode = COMMAND_EXEC, .jim_handler = target_jim_get_reg, .help = "Get register values from the target", .usage = "list", }, { .name = "set_reg", .mode = COMMAND_EXEC, .jim_handler = target_jim_set_reg, .help = "Set target register values", .usage = "dict", }, { .name = "read_memory", .mode = COMMAND_EXEC, .handler = handle_target_read_memory, .help = "Read Tcl list of 8/16/32/64 bit numbers from target memory", .usage = "address width count ['phys']", }, { .name = "write_memory", .mode = COMMAND_EXEC, .jim_handler = target_jim_write_memory, .help = "Write Tcl list of 8/16/32/64 bit numbers to target memory", .usage = "address width data ['phys']", }, { .name = "eventlist", .handler = handle_target_event_list, .mode = COMMAND_EXEC, .help = "displays a table of events defined for this target", .usage = "", }, { .name = "curstate", .mode = COMMAND_EXEC, .handler = handle_target_current_state, .help = "displays the current state of this target", .usage = "", }, { .name = "arp_examine", .mode = COMMAND_EXEC, .handler = handle_target_examine, .help = "used internally for reset processing", .usage = "['allow-defer']", }, { .name = "was_examined", .mode = COMMAND_EXEC, .handler = handle_target_was_examined, .help = "used internally for reset processing", .usage = "", }, { .name = "examine_deferred", .mode = COMMAND_EXEC, .handler = handle_target_examine_deferred, .help = "used internally for reset processing", .usage = "", }, { .name = "arp_halt_gdb", .mode = COMMAND_EXEC, .handler = handle_target_halt_gdb, .help = "used internally for reset processing to halt GDB", .usage = "", }, { .name = "arp_poll", .mode = COMMAND_EXEC, .handler = handle_target_poll, .help = "used internally for reset processing", .usage = "", }, { .name = "arp_reset", .mode = COMMAND_EXEC, .handler = handle_target_reset, .help = "used internally for reset processing", .usage = "'assert'|'deassert' halt", }, { .name = "arp_halt", .mode = COMMAND_EXEC, .handler = handle_target_halt, .help = "used internally for reset processing", .usage = "", }, { .name = "arp_waitstate", .mode = COMMAND_EXEC, .handler = handle_target_wait_state, .help = "used internally for reset processing", .usage = "statename timeoutmsecs", }, { .name = "invoke-event", .mode = COMMAND_EXEC, .jim_handler = jim_target_invoke_event, .help = "invoke handler for specified event", .usage = "event_name", }, COMMAND_REGISTRATION_DONE }; static int target_create(struct jim_getopt_info *goi) { Jim_Obj *new_cmd; Jim_Cmd *cmd; const char *cp; int e; int x; struct target *target; struct command_context *cmd_ctx; cmd_ctx = current_command_context(goi->interp); assert(cmd_ctx); if (goi->argc < 3) { Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ?type? ..options..."); return JIM_ERR; } /* COMMAND */ jim_getopt_obj(goi, &new_cmd); /* does this command exist? */ cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_NONE); if (cmd) { cp = Jim_GetString(new_cmd, NULL); Jim_SetResultFormatted(goi->interp, "Command/target: %s Exists", cp); return JIM_ERR; } /* TYPE */ e = jim_getopt_string(goi, &cp, NULL); if (e != JIM_OK) return e; struct transport *tr = get_current_transport(); if (tr->override_target) { e = tr->override_target(&cp); if (e != ERROR_OK) { LOG_ERROR("The selected transport doesn't support this target"); return JIM_ERR; } LOG_INFO("The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD"); } /* now does target type exist */ for (x = 0 ; target_types[x] ; x++) { if (strcmp(cp, target_types[x]->name) == 0) { /* found */ break; } } if (!target_types[x]) { Jim_SetResultFormatted(goi->interp, "Unknown target type %s, try one of ", cp); for (x = 0 ; target_types[x] ; x++) { if (target_types[x + 1]) { Jim_AppendStrings(goi->interp, Jim_GetResult(goi->interp), target_types[x]->name, ", ", NULL); } else { Jim_AppendStrings(goi->interp, Jim_GetResult(goi->interp), " or ", target_types[x]->name, NULL); } } return JIM_ERR; } /* Create it */ target = calloc(1, sizeof(struct target)); if (!target) { LOG_ERROR("Out of memory"); return JIM_ERR; } /* set empty smp cluster */ target->smp_targets = &empty_smp_targets; /* set target number */ target->target_number = new_target_number(); /* allocate memory for each unique target type */ target->type = malloc(sizeof(struct target_type)); if (!target->type) { LOG_ERROR("Out of memory"); free(target); return JIM_ERR; } memcpy(target->type, target_types[x], sizeof(struct target_type)); /* default to first core, override with -coreid */ target->coreid = 0; target->working_area = 0x0; target->working_area_size = 0x0; target->working_areas = NULL; target->backup_working_area = 0; target->state = TARGET_UNKNOWN; target->debug_reason = DBG_REASON_UNDEFINED; target->reg_cache = NULL; target->breakpoints = NULL; target->watchpoints = NULL; target->next = NULL; target->arch_info = NULL; target->verbose_halt_msg = true; target->halt_issued = false; /* initialize trace information */ target->trace_info = calloc(1, sizeof(struct trace)); if (!target->trace_info) { LOG_ERROR("Out of memory"); free(target->type); free(target); return JIM_ERR; } target->dbgmsg = NULL; target->dbg_msg_enabled = 0; target->endianness = TARGET_ENDIAN_UNKNOWN; target->rtos = NULL; target->rtos_auto_detect = false; target->gdb_port_override = NULL; target->gdb_max_connections = 1; /* Do the rest as "configure" options */ goi->isconfigure = 1; e = target_configure(goi, target); if (e == JIM_OK) { if (target->has_dap) { if (!target->dap_configured) { Jim_SetResultString(goi->interp, "-dap ?name? required when creating target", -1); e = JIM_ERR; } } else { if (!target->tap_configured) { Jim_SetResultString(goi->interp, "-chain-position ?name? required when creating target", -1); e = JIM_ERR; } } /* tap must be set after target was configured */ if (!target->tap) e = JIM_ERR; } if (e != JIM_OK) { rtos_destroy(target); free(target->gdb_port_override); free(target->trace_info); free(target->type); free(target); return e; } if (target->endianness == TARGET_ENDIAN_UNKNOWN) { /* default endian to little if not specified */ target->endianness = TARGET_LITTLE_ENDIAN; } cp = Jim_GetString(new_cmd, NULL); target->cmd_name = strdup(cp); if (!target->cmd_name) { LOG_ERROR("Out of memory"); rtos_destroy(target); free(target->gdb_port_override); free(target->trace_info); free(target->type); free(target); return JIM_ERR; } if (target->type->target_create) { e = (*(target->type->target_create))(target, goi->interp); if (e != ERROR_OK) { LOG_DEBUG("target_create failed"); free(target->cmd_name); rtos_destroy(target); free(target->gdb_port_override); free(target->trace_info); free(target->type); free(target); return JIM_ERR; } } /* create the target specific commands */ if (target->type->commands) { e = register_commands(cmd_ctx, NULL, target->type->commands); if (e != ERROR_OK) LOG_ERROR("unable to register '%s' commands", cp); } /* now - create the new target name command */ const struct command_registration target_subcommands[] = { { .chain = target_instance_command_handlers, }, { .chain = target->type->commands, }, COMMAND_REGISTRATION_DONE }; const struct command_registration target_commands[] = { { .name = cp, .mode = COMMAND_ANY, .help = "target command group", .usage = "", .chain = target_subcommands, }, COMMAND_REGISTRATION_DONE }; e = register_commands_override_target(cmd_ctx, NULL, target_commands, target); if (e != ERROR_OK) { if (target->type->deinit_target) target->type->deinit_target(target); free(target->cmd_name); rtos_destroy(target); free(target->gdb_port_override); free(target->trace_info); free(target->type); free(target); return JIM_ERR; } /* append to end of list */ append_to_list_all_targets(target); cmd_ctx->current_target = target; return JIM_OK; } COMMAND_HANDLER(handle_target_current) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target_or_null(CMD_CTX); if (target) command_print(CMD, "%s", target_name(target)); return ERROR_OK; } COMMAND_HANDLER(handle_target_types) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; for (unsigned int x = 0; target_types[x]; x++) command_print(CMD, "%s", target_types[x]->name); return ERROR_OK; } COMMAND_HANDLER(handle_target_names) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = all_targets; while (target) { command_print(CMD, "%s", target_name(target)); target = target->next; } return ERROR_OK; } static struct target_list * __attribute__((warn_unused_result)) create_target_list_node(const char *targetname) { struct target *target = get_target(targetname); LOG_DEBUG("%s ", targetname); if (!target) return NULL; struct target_list *new = malloc(sizeof(struct target_list)); if (!new) { LOG_ERROR("Out of memory"); return new; } new->target = target; return new; } static int get_target_with_common_rtos_type(struct command_invocation *cmd, struct list_head *lh, struct target **result) { struct target *target = NULL; struct target_list *curr; foreach_smp_target(curr, lh) { struct rtos *curr_rtos = curr->target->rtos; if (curr_rtos) { if (target && target->rtos && target->rtos->type != curr_rtos->type) { command_print(cmd, "Different rtos types in members of one smp target!"); return ERROR_FAIL; } target = curr->target; } } *result = target; return ERROR_OK; } COMMAND_HANDLER(handle_target_smp) { static int smp_group = 1; if (CMD_ARGC == 0) { LOG_DEBUG("Empty SMP target"); return ERROR_OK; } LOG_DEBUG("%d", CMD_ARGC); /* CMD_ARGC[0] = target to associate in smp * CMD_ARGC[1] = target to associate in smp * CMD_ARGC[2] ... */ struct list_head *lh = malloc(sizeof(*lh)); if (!lh) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } INIT_LIST_HEAD(lh); for (unsigned int i = 0; i < CMD_ARGC; i++) { struct target_list *new = create_target_list_node(CMD_ARGV[i]); if (new) list_add_tail(&new->lh, lh); } /* now parse the list of cpu and put the target in smp mode*/ struct target_list *curr; foreach_smp_target(curr, lh) { struct target *target = curr->target; target->smp = smp_group; target->smp_targets = lh; } smp_group++; struct target *rtos_target; int retval = get_target_with_common_rtos_type(CMD, lh, &rtos_target); if (retval == ERROR_OK && rtos_target) retval = rtos_smp_init(rtos_target); return retval; } static int jim_target_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct jim_getopt_info goi; jim_getopt_setup(&goi, interp, argc - 1, argv + 1); if (goi.argc < 3) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "<name> <target_type> [<target_options> ...]"); return JIM_ERR; } return target_create(&goi); } static const struct command_registration target_subcommand_handlers[] = { { .name = "init", .mode = COMMAND_CONFIG, .handler = handle_target_init_command, .help = "initialize targets", .usage = "", }, { .name = "create", .mode = COMMAND_CONFIG, .jim_handler = jim_target_create, .usage = "name type '-chain-position' name [options ...]", .help = "Creates and selects a new target", }, { .name = "current", .mode = COMMAND_ANY, .handler = handle_target_current, .help = "Returns the currently selected target", .usage = "", }, { .name = "types", .mode = COMMAND_ANY, .handler = handle_target_types, .help = "Returns the available target types as " "a list of strings", .usage = "", }, { .name = "names", .mode = COMMAND_ANY, .handler = handle_target_names, .help = "Returns the names of all targets as a list of strings", .usage = "", }, { .name = "smp", .mode = COMMAND_ANY, .handler = handle_target_smp, .usage = "targetname1 targetname2 ...", .help = "gather several target in a smp list" }, COMMAND_REGISTRATION_DONE }; struct fast_load { target_addr_t address; uint8_t *data; int length; }; static int fastload_num; static struct fast_load *fastload; static void free_fastload(void) { if (fastload) { for (int i = 0; i < fastload_num; i++) free(fastload[i].data); free(fastload); fastload = NULL; } } COMMAND_HANDLER(handle_fast_load_image_command) { uint8_t *buffer; size_t buf_cnt; uint32_t image_size; target_addr_t min_address = 0; target_addr_t max_address = -1; struct image image; int retval = CALL_COMMAND_HANDLER(parse_load_image_command, &image, &min_address, &max_address); if (retval != ERROR_OK) return retval; struct duration bench; duration_start(&bench); retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL); if (retval != ERROR_OK) return retval; image_size = 0x0; retval = ERROR_OK; fastload_num = image.num_sections; fastload = malloc(sizeof(struct fast_load)*image.num_sections); if (!fastload) { command_print(CMD, "out of memory"); image_close(&image); return ERROR_FAIL; } memset(fastload, 0, sizeof(struct fast_load)*image.num_sections); for (unsigned int i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); if (!buffer) { command_print(CMD, "error allocating buffer for section (%d bytes)", (int)(image.sections[i].size)); retval = ERROR_FAIL; break; } retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt); if (retval != ERROR_OK) { free(buffer); break; } uint32_t offset = 0; uint32_t length = buf_cnt; /* DANGER!!! beware of unsigned comparison here!!! */ if ((image.sections[i].base_address + buf_cnt >= min_address) && (image.sections[i].base_address < max_address)) { if (image.sections[i].base_address < min_address) { /* clip addresses below */ offset += min_address-image.sections[i].base_address; length -= offset; } if (image.sections[i].base_address + buf_cnt > max_address) length -= (image.sections[i].base_address + buf_cnt)-max_address; fastload[i].address = image.sections[i].base_address + offset; fastload[i].data = malloc(length); if (!fastload[i].data) { free(buffer); command_print(CMD, "error allocating buffer for section (%" PRIu32 " bytes)", length); retval = ERROR_FAIL; break; } memcpy(fastload[i].data, buffer + offset, length); fastload[i].length = length; image_size += length; command_print(CMD, "%u bytes written at address 0x%8.8x", (unsigned int)length, ((unsigned int)(image.sections[i].base_address + offset))); } free(buffer); } if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "Loaded %" PRIu32 " bytes " "in %fs (%0.3f KiB/s)", image_size, duration_elapsed(&bench), duration_kbps(&bench, image_size)); command_print(CMD, "WARNING: image has not been loaded to target!" "You can issue a 'fast_load' to finish loading."); } image_close(&image); if (retval != ERROR_OK) free_fastload(); return retval; } COMMAND_HANDLER(handle_fast_load_command) { if (CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; if (!fastload) { LOG_ERROR("No image in memory"); return ERROR_FAIL; } int i; int64_t ms = timeval_ms(); int size = 0; int retval = ERROR_OK; for (i = 0; i < fastload_num; i++) { struct target *target = get_current_target(CMD_CTX); command_print(CMD, "Write to 0x%08x, length 0x%08x", (unsigned int)(fastload[i].address), (unsigned int)(fastload[i].length)); retval = target_write_buffer(target, fastload[i].address, fastload[i].length, fastload[i].data); if (retval != ERROR_OK) break; size += fastload[i].length; } if (retval == ERROR_OK) { int64_t after = timeval_ms(); command_print(CMD, "Loaded image %f kBytes/s", (float)(size/1024.0)/((float)(after-ms)/1000.0)); } return retval; } static const struct command_registration target_command_handlers[] = { { .name = "targets", .handler = handle_targets_command, .mode = COMMAND_ANY, .help = "change current default target (one parameter) " "or prints table of all targets (no parameters)", .usage = "[target]", }, { .name = "target", .mode = COMMAND_CONFIG, .help = "configure target", .chain = target_subcommand_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; int target_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, target_command_handlers); } static bool target_reset_nag = true; bool get_target_reset_nag(void) { return target_reset_nag; } COMMAND_HANDLER(handle_target_reset_nag) { return CALL_COMMAND_HANDLER(handle_command_parse_bool, &target_reset_nag, "Nag after each reset about options to improve " "performance"); } COMMAND_HANDLER(handle_ps_command) { struct target *target = get_current_target(CMD_CTX); char *display; if (target->state != TARGET_HALTED) { LOG_INFO("target not halted !!"); return ERROR_OK; } if ((target->rtos) && (target->rtos->type) && (target->rtos->type->ps_command)) { display = target->rtos->type->ps_command(target); command_print(CMD, "%s", display); free(display); return ERROR_OK; } else { LOG_INFO("failed"); return ERROR_TARGET_FAILURE; } } static void binprint(struct command_invocation *cmd, const char *text, const uint8_t *buf, int size) { if (text) command_print_sameline(cmd, "%s", text); for (int i = 0; i < size; i++) command_print_sameline(cmd, " %02x", buf[i]); command_print(cmd, " "); } COMMAND_HANDLER(handle_test_mem_access_command) { struct target *target = get_current_target(CMD_CTX); uint32_t test_size; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_INFO("target not halted !!"); return ERROR_FAIL; } if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], test_size); /* Test reads */ size_t num_bytes = test_size + 4; struct working_area *wa = NULL; retval = target_alloc_working_area(target, num_bytes, &wa); if (retval != ERROR_OK) { LOG_ERROR("Not enough working area"); return ERROR_FAIL; } uint8_t *test_pattern = malloc(num_bytes); for (size_t i = 0; i < num_bytes; i++) test_pattern[i] = rand(); retval = target_write_memory(target, wa->address, 1, num_bytes, test_pattern); if (retval != ERROR_OK) { LOG_ERROR("Test pattern write failed"); goto out; } for (int host_offset = 0; host_offset <= 1; host_offset++) { for (int size = 1; size <= 4; size *= 2) { for (int offset = 0; offset < 4; offset++) { uint32_t count = test_size / size; size_t host_bufsiz = (count + 2) * size + host_offset; uint8_t *read_ref = malloc(host_bufsiz); uint8_t *read_buf = malloc(host_bufsiz); for (size_t i = 0; i < host_bufsiz; i++) { read_ref[i] = rand(); read_buf[i] = read_ref[i]; } command_print_sameline(CMD, "Test read %" PRIu32 " x %d @ %d to %saligned buffer: ", count, size, offset, host_offset ? "un" : ""); struct duration bench; duration_start(&bench); retval = target_read_memory(target, wa->address + offset, size, count, read_buf + size + host_offset); duration_measure(&bench); if (retval == ERROR_TARGET_UNALIGNED_ACCESS) { command_print(CMD, "Unsupported alignment"); goto next; } else if (retval != ERROR_OK) { command_print(CMD, "Memory read failed"); goto next; } /* replay on host */ memcpy(read_ref + size + host_offset, test_pattern + offset, count * size); /* check result */ int result = memcmp(read_ref, read_buf, host_bufsiz); if (result == 0) { command_print(CMD, "Pass in %fs (%0.3f KiB/s)", duration_elapsed(&bench), duration_kbps(&bench, count * size)); } else { command_print(CMD, "Compare failed"); binprint(CMD, "ref:", read_ref, host_bufsiz); binprint(CMD, "buf:", read_buf, host_bufsiz); } next: free(read_ref); free(read_buf); } } } out: free(test_pattern); target_free_working_area(target, wa); /* Test writes */ num_bytes = test_size + 4 + 4 + 4; retval = target_alloc_working_area(target, num_bytes, &wa); if (retval != ERROR_OK) { LOG_ERROR("Not enough working area"); return ERROR_FAIL; } test_pattern = malloc(num_bytes); for (size_t i = 0; i < num_bytes; i++) test_pattern[i] = rand(); for (int host_offset = 0; host_offset <= 1; host_offset++) { for (int size = 1; size <= 4; size *= 2) { for (int offset = 0; offset < 4; offset++) { uint32_t count = test_size / size; size_t host_bufsiz = count * size + host_offset; uint8_t *read_ref = malloc(num_bytes); uint8_t *read_buf = malloc(num_bytes); uint8_t *write_buf = malloc(host_bufsiz); for (size_t i = 0; i < host_bufsiz; i++) write_buf[i] = rand(); command_print_sameline(CMD, "Test write %" PRIu32 " x %d @ %d from %saligned buffer: ", count, size, offset, host_offset ? "un" : ""); retval = target_write_memory(target, wa->address, 1, num_bytes, test_pattern); if (retval != ERROR_OK) { command_print(CMD, "Test pattern write failed"); goto nextw; } /* replay on host */ memcpy(read_ref, test_pattern, num_bytes); memcpy(read_ref + size + offset, write_buf + host_offset, count * size); struct duration bench; duration_start(&bench); retval = target_write_memory(target, wa->address + size + offset, size, count, write_buf + host_offset); duration_measure(&bench); if (retval == ERROR_TARGET_UNALIGNED_ACCESS) { command_print(CMD, "Unsupported alignment"); goto nextw; } else if (retval != ERROR_OK) { command_print(CMD, "Memory write failed"); goto nextw; } /* read back */ retval = target_read_memory(target, wa->address, 1, num_bytes, read_buf); if (retval != ERROR_OK) { command_print(CMD, "Test pattern write failed"); goto nextw; } /* check result */ int result = memcmp(read_ref, read_buf, num_bytes); if (result == 0) { command_print(CMD, "Pass in %fs (%0.3f KiB/s)", duration_elapsed(&bench), duration_kbps(&bench, count * size)); } else { command_print(CMD, "Compare failed"); binprint(CMD, "ref:", read_ref, num_bytes); binprint(CMD, "buf:", read_buf, num_bytes); } nextw: free(read_ref); free(read_buf); } } } free(test_pattern); target_free_working_area(target, wa); return retval; } static const struct command_registration target_exec_command_handlers[] = { { .name = "fast_load_image", .handler = handle_fast_load_image_command, .mode = COMMAND_ANY, .help = "Load image into server memory for later use by " "fast_load; primarily for profiling", .usage = "filename address ['bin'|'ihex'|'elf'|'s19'] " "[min_address [max_length]]", }, { .name = "fast_load", .handler = handle_fast_load_command, .mode = COMMAND_EXEC, .help = "loads active fast load image to current target " "- mainly for profiling purposes", .usage = "", }, { .name = "profile", .handler = handle_profile_command, .mode = COMMAND_EXEC, .usage = "seconds filename [start end]", .help = "profiling samples the CPU PC", }, /** @todo don't register virt2phys() unless target supports it */ { .name = "virt2phys", .handler = handle_virt2phys_command, .mode = COMMAND_ANY, .help = "translate a virtual address into a physical address", .usage = "virtual_address", }, { .name = "reg", .handler = handle_reg_command, .mode = COMMAND_EXEC, .help = "display (reread from target with \"force\") or set a register; " "with no arguments, displays all registers and their values", .usage = "[(register_number|register_name) [(value|'force')]]", }, { .name = "poll", .handler = handle_poll_command, .mode = COMMAND_EXEC, .help = "poll target state; or reconfigure background polling", .usage = "['on'|'off']", }, { .name = "wait_halt", .handler = handle_wait_halt_command, .mode = COMMAND_EXEC, .help = "wait up to the specified number of milliseconds " "(default 5000) for a previously requested halt", .usage = "[milliseconds]", }, { .name = "halt", .handler = handle_halt_command, .mode = COMMAND_EXEC, .help = "request target to halt, then wait up to the specified " "number of milliseconds (default 5000) for it to complete", .usage = "[milliseconds]", }, { .name = "resume", .handler = handle_resume_command, .mode = COMMAND_EXEC, .help = "resume target execution from current PC or address", .usage = "[address]", }, { .name = "reset", .handler = handle_reset_command, .mode = COMMAND_EXEC, .usage = "[run|halt|init]", .help = "Reset all targets into the specified mode. " "Default reset mode is run, if not given.", }, { .name = "soft_reset_halt", .handler = handle_soft_reset_halt_command, .mode = COMMAND_EXEC, .usage = "", .help = "halt the target and do a soft reset", }, { .name = "step", .handler = handle_step_command, .mode = COMMAND_EXEC, .help = "step one instruction from current PC or address", .usage = "[address]", }, { .name = "mdd", .handler = handle_md_command, .mode = COMMAND_EXEC, .help = "display memory double-words", .usage = "['phys'] address [count]", }, { .name = "mdw", .handler = handle_md_command, .mode = COMMAND_EXEC, .help = "display memory words", .usage = "['phys'] address [count]", }, { .name = "mdh", .handler = handle_md_command, .mode = COMMAND_EXEC, .help = "display memory half-words", .usage = "['phys'] address [count]", }, { .name = "mdb", .handler = handle_md_command, .mode = COMMAND_EXEC, .help = "display memory bytes", .usage = "['phys'] address [count]", }, { .name = "mwd", .handler = handle_mw_command, .mode = COMMAND_EXEC, .help = "write memory double-word", .usage = "['phys'] address value [count]", }, { .name = "mww", .handler = handle_mw_command, .mode = COMMAND_EXEC, .help = "write memory word", .usage = "['phys'] address value [count]", }, { .name = "mwh", .handler = handle_mw_command, .mode = COMMAND_EXEC, .help = "write memory half-word", .usage = "['phys'] address value [count]", }, { .name = "mwb", .handler = handle_mw_command, .mode = COMMAND_EXEC, .help = "write memory byte", .usage = "['phys'] address value [count]", }, { .name = "bp", .handler = handle_bp_command, .mode = COMMAND_EXEC, .help = "list or set hardware or software breakpoint", .usage = "[<address> [<asid>] <length> ['hw'|'hw_ctx']]", }, { .name = "rbp", .handler = handle_rbp_command, .mode = COMMAND_EXEC, .help = "remove breakpoint", .usage = "'all' | address", }, { .name = "wp", .handler = handle_wp_command, .mode = COMMAND_EXEC, .help = "list (no params) or create watchpoints", .usage = "[address length [('r'|'w'|'a') value [mask]]]", }, { .name = "rwp", .handler = handle_rwp_command, .mode = COMMAND_EXEC, .help = "remove watchpoint", .usage = "address", }, { .name = "load_image", .handler = handle_load_image_command, .mode = COMMAND_EXEC, .usage = "filename address ['bin'|'ihex'|'elf'|'s19'] " "[min_address] [max_length]", }, { .name = "dump_image", .handler = handle_dump_image_command, .mode = COMMAND_EXEC, .usage = "filename address size", }, { .name = "verify_image_checksum", .handler = handle_verify_image_checksum_command, .mode = COMMAND_EXEC, .usage = "filename [offset [type]]", }, { .name = "verify_image", .handler = handle_verify_image_command, .mode = COMMAND_EXEC, .usage = "filename [offset [type]]", }, { .name = "test_image", .handler = handle_test_image_command, .mode = COMMAND_EXEC, .usage = "filename [offset [type]]", }, { .name = "get_reg", .mode = COMMAND_EXEC, .jim_handler = target_jim_get_reg, .help = "Get register values from the target", .usage = "list", }, { .name = "set_reg", .mode = COMMAND_EXEC, .jim_handler = target_jim_set_reg, .help = "Set target register values", .usage = "dict", }, { .name = "read_memory", .mode = COMMAND_EXEC, .handler = handle_target_read_memory, .help = "Read Tcl list of 8/16/32/64 bit numbers from target memory", .usage = "address width count ['phys']", }, { .name = "write_memory", .mode = COMMAND_EXEC, .jim_handler = target_jim_write_memory, .help = "Write Tcl list of 8/16/32/64 bit numbers to target memory", .usage = "address width data ['phys']", }, { .name = "reset_nag", .handler = handle_target_reset_nag, .mode = COMMAND_ANY, .help = "Nag after each reset about options that could have been " "enabled to improve performance.", .usage = "['enable'|'disable']", }, { .name = "ps", .handler = handle_ps_command, .mode = COMMAND_EXEC, .help = "list all tasks", .usage = "", }, { .name = "test_mem_access", .handler = handle_test_mem_access_command, .mode = COMMAND_EXEC, .help = "Test the target's memory access functions", .usage = "size", }, COMMAND_REGISTRATION_DONE }; static int target_register_user_commands(struct command_context *cmd_ctx) { int retval = ERROR_OK; retval = target_request_register_commands(cmd_ctx); if (retval != ERROR_OK) return retval; retval = trace_register_commands(cmd_ctx); if (retval != ERROR_OK) return retval; return register_commands(cmd_ctx, NULL, target_exec_command_handlers); } const char *target_debug_reason_str(enum target_debug_reason reason) { switch (reason) { case DBG_REASON_DBGRQ: return "DBGRQ"; case DBG_REASON_BREAKPOINT: return "BREAKPOINT"; case DBG_REASON_WATCHPOINT: return "WATCHPOINT"; case DBG_REASON_WPTANDBKPT: return "WPTANDBKPT"; case DBG_REASON_SINGLESTEP: return "SINGLESTEP"; case DBG_REASON_NOTHALTED: return "NOTHALTED"; case DBG_REASON_EXIT: return "EXIT"; case DBG_REASON_EXC_CATCH: return "EXC_CATCH"; case DBG_REASON_UNDEFINED: return "UNDEFINED"; default: return "UNKNOWN!"; } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/target.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * Copyright (C) ST-Ericsson SA 2011 * * michel.jaouen@stericsson.com : smp minimum support * ***************************************************************************/ #ifndef OPENOCD_TARGET_TARGET_H #define OPENOCD_TARGET_TARGET_H #include <helper/list.h> #include "helper/replacements.h" #include "helper/system.h" #include <jim.h> struct reg; struct trace; struct command_context; struct command_invocation; struct breakpoint; struct watchpoint; struct mem_param; struct reg_param; struct target_list; struct gdb_fileio_info; /* * TARGET_UNKNOWN = 0: we don't know anything about the target yet * TARGET_RUNNING = 1: the target is executing or ready to execute user code * TARGET_HALTED = 2: the target is not executing code, and ready to talk to the * debugger. on an xscale it means that the debug handler is executing * TARGET_RESET = 3: the target is being held in reset (only a temporary state, * not sure how this is used with all the recent changes) * TARGET_DEBUG_RUNNING = 4: the target is running, but it is executing code on * behalf of the debugger (e.g. algorithm for flashing) * * also see: target_state_name(); */ enum target_state { TARGET_UNKNOWN = 0, TARGET_RUNNING = 1, TARGET_HALTED = 2, TARGET_RESET = 3, TARGET_DEBUG_RUNNING = 4, }; enum target_reset_mode { RESET_UNKNOWN = 0, RESET_RUN = 1, /* reset and let target run */ RESET_HALT = 2, /* reset and halt target out of reset */ RESET_INIT = 3, /* reset and halt target out of reset, then run init script */ }; enum target_debug_reason { DBG_REASON_DBGRQ = 0, DBG_REASON_BREAKPOINT = 1, DBG_REASON_WATCHPOINT = 2, DBG_REASON_WPTANDBKPT = 3, DBG_REASON_SINGLESTEP = 4, DBG_REASON_NOTHALTED = 5, DBG_REASON_EXIT = 6, DBG_REASON_EXC_CATCH = 7, DBG_REASON_UNDEFINED = 8, }; enum target_endianness { TARGET_ENDIAN_UNKNOWN = 0, TARGET_BIG_ENDIAN = 1, TARGET_LITTLE_ENDIAN = 2 }; struct working_area { target_addr_t address; uint32_t size; bool free; uint8_t *backup; struct working_area **user; struct working_area *next; }; struct gdb_service { struct target *target; /* field for smp display */ /* element 0 coreid currently displayed ( 1 till n) */ /* element 1 coreid to be displayed at next resume 1 till n 0 means resume * all cores core displayed */ int32_t core[2]; }; /* target back off timer */ struct backoff_timer { int times; int count; }; /* split target registers into multiple class */ enum target_register_class { REG_CLASS_ALL, REG_CLASS_GENERAL, }; /* target_type.h contains the full definition of struct target_type */ struct target { struct target_type *type; /* target type definition (name, access functions) */ char *cmd_name; /* tcl Name of target */ int target_number; /* DO NOT USE! field to be removed in 2010 */ struct jtag_tap *tap; /* where on the jtag chain is this */ int32_t coreid; /* which device on the TAP? */ /** Should we defer examine to later */ bool defer_examine; /** * Indicates whether this target has been examined. * * Do @b not access this field directly, use target_was_examined() * or target_set_examined(). */ bool examined; /** * true if the target is currently running a downloaded * "algorithm" instead of arbitrary user code. OpenOCD code * invoking algorithms is trusted to maintain correctness of * any cached state (e.g. for flash status), which arbitrary * code will have no reason to know about. */ bool running_alg; struct target_event_action *event_action; bool reset_halt; /* attempt resetting the CPU into the halted mode? */ target_addr_t working_area; /* working area (initialised RAM). Evaluated * upon first allocation from virtual/physical address. */ bool working_area_virt_spec; /* virtual address specified? */ target_addr_t working_area_virt; /* virtual address */ bool working_area_phys_spec; /* physical address specified? */ target_addr_t working_area_phys; /* physical address */ uint32_t working_area_size; /* size in bytes */ uint32_t backup_working_area; /* whether the content of the working area has to be preserved */ struct working_area *working_areas;/* list of allocated working areas */ enum target_debug_reason debug_reason;/* reason why the target entered debug state */ enum target_endianness endianness; /* target endianness */ /* also see: target_state_name() */ enum target_state state; /* the current backend-state (running, halted, ...) */ struct reg_cache *reg_cache; /* the first register cache of the target (core regs) */ struct breakpoint *breakpoints; /* list of breakpoints */ struct watchpoint *watchpoints; /* list of watchpoints */ struct trace *trace_info; /* generic trace information */ struct debug_msg_receiver *dbgmsg; /* list of debug message receivers */ uint32_t dbg_msg_enabled; /* debug message status */ void *arch_info; /* architecture specific information */ void *private_config; /* pointer to target specific config data (for jim_configure hook) */ struct target *next; /* next target in list */ bool verbose_halt_msg; /* display async info in telnet session. Do not display * lots of halted/resumed info when stepping in debugger. */ bool halt_issued; /* did we transition to halted state? */ int64_t halt_issued_time; /* Note time when halt was issued */ /* ARM v7/v8 targets with ADIv5 interface */ bool dbgbase_set; /* By default the debug base is not set */ uint32_t dbgbase; /* Really a Cortex-A specific option, but there is no * system in place to support target specific options * currently. */ bool has_dap; /* set to true if target has ADIv5 support */ bool dap_configured; /* set to true if ADIv5 DAP is configured */ bool tap_configured; /* set to true if JTAG tap has been configured * through -chain-position */ struct rtos *rtos; /* Instance of Real Time Operating System support */ bool rtos_auto_detect; /* A flag that indicates that the RTOS has been specified as "auto" * and must be detected when symbols are offered */ struct backoff_timer backoff; int smp; /* Unique non-zero number for each SMP group */ struct list_head *smp_targets; /* list all targets in this smp group/cluster * The head of the list is shared between the * cluster, thus here there is a pointer */ bool smp_halt_event_postponed; /* Some SMP implementations (currently Cortex-M) stores * 'halted' events and emits them after all targets of * the SMP group has been polled */ /* the gdb service is there in case of smp, we have only one gdb server * for all smp target * the target attached to the gdb is changing dynamically by changing * gdb_service->target pointer */ struct gdb_service *gdb_service; /* file-I/O information for host to do syscall */ struct gdb_fileio_info *fileio_info; char *gdb_port_override; /* target-specific override for gdb_port */ int gdb_max_connections; /* max number of simultaneous gdb connections */ /* The semihosting information, extracted from the target. */ struct semihosting *semihosting; }; struct target_list { struct list_head lh; struct target *target; }; struct gdb_fileio_info { char *identifier; uint64_t param_1; uint64_t param_2; uint64_t param_3; uint64_t param_4; }; /** Returns a description of the endianness for the specified target. */ static inline const char *target_endianness(struct target *target) { return (target->endianness == TARGET_ENDIAN_UNKNOWN) ? "unknown" : (target->endianness == TARGET_BIG_ENDIAN) ? "big endian" : "little endian"; } /** Returns the instance-specific name of the specified target. */ static inline const char *target_name(struct target *target) { return target->cmd_name; } const char *debug_reason_name(struct target *t); enum target_event { /* allow GDB to do stuff before others handle the halted event, * this is in lieu of defining ordering of invocation of events, * which would be more complicated * * Telling GDB to halt does not mean that the target stopped running, * simply that we're dropping out of GDB's waiting for step or continue. * * This can be useful when e.g. detecting power dropout. */ TARGET_EVENT_GDB_HALT, TARGET_EVENT_HALTED, /* target entered debug state from normal execution or reset */ TARGET_EVENT_RESUMED, /* target resumed to normal execution */ TARGET_EVENT_RESUME_START, TARGET_EVENT_RESUME_END, TARGET_EVENT_STEP_START, TARGET_EVENT_STEP_END, TARGET_EVENT_GDB_START, /* debugger started execution (step/run) */ TARGET_EVENT_GDB_END, /* debugger stopped execution (step/run) */ TARGET_EVENT_RESET_START, TARGET_EVENT_RESET_ASSERT_PRE, TARGET_EVENT_RESET_ASSERT, /* C code uses this instead of SRST */ TARGET_EVENT_RESET_ASSERT_POST, TARGET_EVENT_RESET_DEASSERT_PRE, TARGET_EVENT_RESET_DEASSERT_POST, TARGET_EVENT_RESET_INIT, TARGET_EVENT_RESET_END, TARGET_EVENT_DEBUG_HALTED, /* target entered debug state, but was executing on behalf of the debugger */ TARGET_EVENT_DEBUG_RESUMED, /* target resumed to execute on behalf of the debugger */ TARGET_EVENT_EXAMINE_START, TARGET_EVENT_EXAMINE_FAIL, TARGET_EVENT_EXAMINE_END, TARGET_EVENT_GDB_ATTACH, TARGET_EVENT_GDB_DETACH, TARGET_EVENT_GDB_FLASH_ERASE_START, TARGET_EVENT_GDB_FLASH_ERASE_END, TARGET_EVENT_GDB_FLASH_WRITE_START, TARGET_EVENT_GDB_FLASH_WRITE_END, TARGET_EVENT_TRACE_CONFIG, TARGET_EVENT_SEMIHOSTING_USER_CMD_0X100 = 0x100, /* semihosting allows user cmds from 0x100 to 0x1ff */ TARGET_EVENT_SEMIHOSTING_USER_CMD_0X101 = 0x101, TARGET_EVENT_SEMIHOSTING_USER_CMD_0X102 = 0x102, TARGET_EVENT_SEMIHOSTING_USER_CMD_0X103 = 0x103, TARGET_EVENT_SEMIHOSTING_USER_CMD_0X104 = 0x104, TARGET_EVENT_SEMIHOSTING_USER_CMD_0X105 = 0x105, TARGET_EVENT_SEMIHOSTING_USER_CMD_0X106 = 0x106, TARGET_EVENT_SEMIHOSTING_USER_CMD_0X107 = 0x107, }; struct target_event_action { enum target_event event; Jim_Interp *interp; Jim_Obj *body; struct target_event_action *next; }; bool target_has_event_action(struct target *target, enum target_event event); struct target_event_callback { int (*callback)(struct target *target, enum target_event event, void *priv); void *priv; struct target_event_callback *next; }; struct target_reset_callback { struct list_head list; void *priv; int (*callback)(struct target *target, enum target_reset_mode reset_mode, void *priv); }; struct target_trace_callback { struct list_head list; void *priv; int (*callback)(struct target *target, size_t len, uint8_t *data, void *priv); }; enum target_timer_type { TARGET_TIMER_TYPE_ONESHOT, TARGET_TIMER_TYPE_PERIODIC }; struct target_timer_callback { int (*callback)(void *priv); unsigned int time_ms; enum target_timer_type type; bool removed; int64_t when; /* output of timeval_ms() */ void *priv; struct target_timer_callback *next; }; struct target_memory_check_block { target_addr_t address; uint32_t size; uint32_t result; }; int target_register_commands(struct command_context *cmd_ctx); int target_examine(void); int target_register_event_callback( int (*callback)(struct target *target, enum target_event event, void *priv), void *priv); int target_unregister_event_callback( int (*callback)(struct target *target, enum target_event event, void *priv), void *priv); int target_register_reset_callback( int (*callback)(struct target *target, enum target_reset_mode reset_mode, void *priv), void *priv); int target_unregister_reset_callback( int (*callback)(struct target *target, enum target_reset_mode reset_mode, void *priv), void *priv); int target_register_trace_callback( int (*callback)(struct target *target, size_t len, uint8_t *data, void *priv), void *priv); int target_unregister_trace_callback( int (*callback)(struct target *target, size_t len, uint8_t *data, void *priv), void *priv); /* Poll the status of the target, detect any error conditions and report them. * * Also note that this fn will clear such error conditions, so a subsequent * invocation will then succeed. * * These error conditions can be "sticky" error conditions. E.g. writing * to memory could be implemented as an open loop and if memory writes * fails, then a note is made of it, the error is sticky, but the memory * write loop still runs to completion. This improves performance in the * normal case as there is no need to verify that every single write succeed, * yet it is possible to detect error conditions. */ int target_poll(struct target *target); int target_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); int target_halt(struct target *target); int target_call_event_callbacks(struct target *target, enum target_event event); int target_call_reset_callbacks(struct target *target, enum target_reset_mode reset_mode); int target_call_trace_callbacks(struct target *target, size_t len, uint8_t *data); /** * The period is very approximate, the callback can happen much more often * or much more rarely than specified */ int target_register_timer_callback(int (*callback)(void *priv), unsigned int time_ms, enum target_timer_type type, void *priv); int target_unregister_timer_callback(int (*callback)(void *priv), void *priv); int target_call_timer_callbacks(void); /** * Invoke this to ensure that e.g. polling timer callbacks happen before * a synchronous command completes. */ int target_call_timer_callbacks_now(void); /** * Returns when the next registered event will take place. Callers can use this * to go to sleep until that time occurs. */ int64_t target_timer_next_event(void); struct target *get_target_by_num(int num); struct target *get_current_target(struct command_context *cmd_ctx); struct target *get_current_target_or_null(struct command_context *cmd_ctx); struct target *get_target(const char *id); /** * Get the target type name. * * This routine is a wrapper for the target->type->name field. * Note that this is not an instance-specific name for his target. */ const char *target_type_name(struct target *target); /** * Examine the specified @a target, letting it perform any * Initialisation that requires JTAG access. * * This routine is a wrapper for target->type->examine. */ int target_examine_one(struct target *target); /** @returns @c true if target_set_examined() has been called. */ static inline bool target_was_examined(struct target *target) { return target->examined; } /** Sets the @c examined flag for the given target. */ /** Use in target->type->examine() after one-time setup is done. */ static inline void target_set_examined(struct target *target) { target->examined = true; } /** * Add the @a breakpoint for @a target. * * This routine is a wrapper for target->type->add_breakpoint. */ int target_add_breakpoint(struct target *target, struct breakpoint *breakpoint); /** * Add the @a ContextID breakpoint for @a target. * * This routine is a wrapper for target->type->add_context_breakpoint. */ int target_add_context_breakpoint(struct target *target, struct breakpoint *breakpoint); /** * Add the @a ContextID & IVA breakpoint for @a target. * * This routine is a wrapper for target->type->add_hybrid_breakpoint. */ int target_add_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint); /** * Remove the @a breakpoint for @a target. * * This routine is a wrapper for target->type->remove_breakpoint. */ int target_remove_breakpoint(struct target *target, struct breakpoint *breakpoint); /** * Add the @a watchpoint for @a target. * * This routine is a wrapper for target->type->add_watchpoint. */ int target_add_watchpoint(struct target *target, struct watchpoint *watchpoint); /** * Remove the @a watchpoint for @a target. * * This routine is a wrapper for target->type->remove_watchpoint. */ int target_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); /** * Find out the just hit @a watchpoint for @a target. * * This routine is a wrapper for target->type->hit_watchpoint. */ int target_hit_watchpoint(struct target *target, struct watchpoint **watchpoint); /** * Obtain the architecture for GDB. * * This routine is a wrapper for target->type->get_gdb_arch. */ const char *target_get_gdb_arch(struct target *target); /** * Obtain the registers for GDB. * * This routine is a wrapper for target->type->get_gdb_reg_list. */ int target_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); /** * Obtain the registers for GDB, but don't read register values from the * target. * * This routine is a wrapper for target->type->get_gdb_reg_list_noread. */ int target_get_gdb_reg_list_noread(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); /** * Check if @a target allows GDB connections. * * Some target do not implement the necessary code required by GDB. */ bool target_supports_gdb_connection(struct target *target); /** * Step the target. * * This routine is a wrapper for target->type->step. */ int target_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); /** * Run an algorithm on the @a target given. * * This routine is a wrapper for target->type->run_algorithm. */ int target_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); /** * Starts an algorithm in the background on the @a target given. * * This routine is a wrapper for target->type->start_algorithm. */ int target_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, void *arch_info); /** * Wait for an algorithm on the @a target given. * * This routine is a wrapper for target->type->wait_algorithm. */ int target_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); /** * This routine is a wrapper for asynchronous algorithms. * */ int target_run_flash_async_algorithm(struct target *target, const uint8_t *buffer, uint32_t count, int block_size, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t buffer_start, uint32_t buffer_size, uint32_t entry_point, uint32_t exit_point, void *arch_info); /** * This routine is a wrapper for asynchronous algorithms. * */ int target_run_read_async_algorithm(struct target *target, uint8_t *buffer, uint32_t count, int block_size, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t buffer_start, uint32_t buffer_size, uint32_t entry_point, uint32_t exit_point, void *arch_info); /** * Read @a count items of @a size bytes from the memory of @a target at * the @a address given. * * This routine is a wrapper for target->type->read_memory. */ int target_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); int target_read_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); /** * Write @a count items of @a size bytes to the memory of @a target at * the @a address given. @a address must be aligned to @a size * in target memory. * * The endianness is the same in the host and target memory for this * function. * * \todo TODO: * Really @a buffer should have been defined as "const void *" and * @a buffer should have been aligned to @a size in the host memory. * * This is not enforced via e.g. assert's today and e.g. the * target_write_buffer fn breaks this assumption. * * This routine is wrapper for target->type->write_memory. */ int target_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int target_write_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); /* * Write to target memory using the virtual address. * * Note that this fn is used to implement software breakpoints. Targets * can implement support for software breakpoints to memory marked as read * only by making this fn write to ram even if it is read only(MMU or * MPUs). * * It is sufficient to implement for writing a single word(16 or 32 in * ARM32/16 bit case) to write the breakpoint to ram. * * The target should also take care of "other things" to make sure that * software breakpoints can be written using this function. E.g. * when there is a separate instruction and data cache, this fn must * make sure that the instruction cache is synced up to the potential * code change that can happen as a result of the memory write(typically * by invalidating the cache). * * The high level wrapper fn in target.c will break down this memory write * request to multiple write requests to the target driver to e.g. guarantee * that writing 4 bytes to an aligned address happens with a single 32 bit * write operation, thus making this fn suitable to e.g. write to special * peripheral registers which do not support byte operations. */ int target_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer); int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer); int target_checksum_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t *crc); int target_blank_check_memory(struct target *target, struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value); int target_wait_state(struct target *target, enum target_state state, unsigned int ms); /** * Obtain file-I/O information from target for GDB to do syscall. * * This routine is a wrapper for target->type->get_gdb_fileio_info. */ int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info); /** * Pass GDB file-I/O response to target after finishing host syscall. * * This routine is a wrapper for target->type->gdb_fileio_end. */ int target_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c); /** * Return the highest accessible address for this target. */ target_addr_t target_address_max(struct target *target); /** * Return the number of address bits this target supports. * * This routine is a wrapper for target->type->address_bits. */ unsigned target_address_bits(struct target *target); /** * Return the number of data bits this target supports. * * This routine is a wrapper for target->type->data_bits. */ unsigned int target_data_bits(struct target *target); /** Return the *name* of this targets current state */ const char *target_state_name(struct target *target); /** Return the *name* of a target event enumeration value */ const char *target_event_name(enum target_event event); /** Return the *name* of a target reset reason enumeration value */ const char *target_reset_mode_name(enum target_reset_mode reset_mode); /* DANGER!!!!! * * if "area" passed in to target_alloc_working_area() points to a memory * location that goes out of scope (e.g. a pointer on the stack), then * the caller of target_alloc_working_area() is responsible for invoking * target_free_working_area() before "area" goes out of scope. * * target_free_all_working_areas() will NULL out the "area" pointer * upon resuming or resetting the CPU. * */ int target_alloc_working_area(struct target *target, uint32_t size, struct working_area **area); /* Same as target_alloc_working_area, except that no error is logged * when ERROR_TARGET_RESOURCE_NOT_AVAILABLE is returned. * * This allows the calling code to *try* to allocate target memory * and have a fallback to another behaviour(slower?). */ int target_alloc_working_area_try(struct target *target, uint32_t size, struct working_area **area); /** * Free a working area. * Restore target data if area backup is configured. * @param target * @param area Pointer to the area to be freed or NULL * @returns ERROR_OK if successful; error code if restore failed */ int target_free_working_area(struct target *target, struct working_area *area); void target_free_all_working_areas(struct target *target); uint32_t target_get_working_area_avail(struct target *target); /** * Free all the resources allocated by targets and the target layer */ void target_quit(void); extern struct target *all_targets; uint64_t target_buffer_get_u64(struct target *target, const uint8_t *buffer); uint32_t target_buffer_get_u32(struct target *target, const uint8_t *buffer); uint32_t target_buffer_get_u24(struct target *target, const uint8_t *buffer); uint16_t target_buffer_get_u16(struct target *target, const uint8_t *buffer); void target_buffer_set_u64(struct target *target, uint8_t *buffer, uint64_t value); void target_buffer_set_u32(struct target *target, uint8_t *buffer, uint32_t value); void target_buffer_set_u24(struct target *target, uint8_t *buffer, uint32_t value); void target_buffer_set_u16(struct target *target, uint8_t *buffer, uint16_t value); void target_buffer_get_u64_array(struct target *target, const uint8_t *buffer, uint32_t count, uint64_t *dstbuf); void target_buffer_get_u32_array(struct target *target, const uint8_t *buffer, uint32_t count, uint32_t *dstbuf); void target_buffer_get_u16_array(struct target *target, const uint8_t *buffer, uint32_t count, uint16_t *dstbuf); void target_buffer_set_u64_array(struct target *target, uint8_t *buffer, uint32_t count, const uint64_t *srcbuf); void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, const uint32_t *srcbuf); void target_buffer_set_u16_array(struct target *target, uint8_t *buffer, uint32_t count, const uint16_t *srcbuf); int target_read_u64(struct target *target, target_addr_t address, uint64_t *value); int target_read_u32(struct target *target, target_addr_t address, uint32_t *value); int target_read_u16(struct target *target, target_addr_t address, uint16_t *value); int target_read_u8(struct target *target, target_addr_t address, uint8_t *value); int target_write_u64(struct target *target, target_addr_t address, uint64_t value); int target_write_u32(struct target *target, target_addr_t address, uint32_t value); int target_write_u16(struct target *target, target_addr_t address, uint16_t value); int target_write_u8(struct target *target, target_addr_t address, uint8_t value); int target_write_phys_u64(struct target *target, target_addr_t address, uint64_t value); int target_write_phys_u32(struct target *target, target_addr_t address, uint32_t value); int target_write_phys_u16(struct target *target, target_addr_t address, uint16_t value); int target_write_phys_u8(struct target *target, target_addr_t address, uint8_t value); /* Issues USER() statements with target state information */ int target_arch_state(struct target *target); void target_handle_event(struct target *t, enum target_event e); void target_handle_md_output(struct command_invocation *cmd, struct target *target, target_addr_t address, unsigned size, unsigned count, const uint8_t *buffer); int target_profiling_default(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds); #define ERROR_TARGET_INVALID (-300) #define ERROR_TARGET_INIT_FAILED (-301) #define ERROR_TARGET_TIMEOUT (-302) #define ERROR_TARGET_NOT_HALTED (-304) #define ERROR_TARGET_FAILURE (-305) #define ERROR_TARGET_UNALIGNED_ACCESS (-306) #define ERROR_TARGET_DATA_ABORT (-307) #define ERROR_TARGET_RESOURCE_NOT_AVAILABLE (-308) #define ERROR_TARGET_TRANSLATION_FAULT (-309) #define ERROR_TARGET_NOT_RUNNING (-310) #define ERROR_TARGET_NOT_EXAMINED (-311) #define ERROR_TARGET_DUPLICATE_BREAKPOINT (-312) #define ERROR_TARGET_ALGO_EXIT (-313) extern bool get_target_reset_nag(void); #define TARGET_DEFAULT_POLLING_INTERVAL 100 const char *target_debug_reason_str(enum target_debug_reason reason); #endif /* OPENOCD_TARGET_TARGET_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/target_request.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include <helper/binarybuffer.h> #include "target.h" #include "target_request.h" #include "target_type.h" #include "trace.h" static bool got_message; bool target_got_message(void) { bool t = got_message; got_message = false; return t; } static int charmsg_mode; static int target_asciimsg(struct target *target, uint32_t length) { char *msg = malloc(DIV_ROUND_UP(length + 1, 4) * 4); struct debug_msg_receiver *c = target->dbgmsg; target->type->target_request_data(target, DIV_ROUND_UP(length, 4), (uint8_t *)msg); msg[length] = 0; LOG_DEBUG("%s", msg); while (c) { command_output_text(c->cmd_ctx, msg); c = c->next; } return ERROR_OK; } static int target_charmsg(struct target *target, uint8_t msg) { LOG_USER_N("%c", msg); return ERROR_OK; } static int target_hexmsg(struct target *target, int size, uint32_t length) { uint8_t *data = malloc(DIV_ROUND_UP(length * size, 4) * 4); char line[128]; int line_len; struct debug_msg_receiver *c = target->dbgmsg; uint32_t i; LOG_DEBUG("size: %i, length: %i", (int)size, (int)length); target->type->target_request_data(target, DIV_ROUND_UP(length * size, 4), (uint8_t *)data); line_len = 0; for (i = 0; i < length; i++) { switch (size) { case 4: line_len += snprintf(line + line_len, 128 - line_len, "%8.8" PRIx32 " ", le_to_h_u32(data + (4*i))); break; case 2: line_len += snprintf(line + line_len, 128 - line_len, "%4.4x ", le_to_h_u16(data + (2*i))); break; case 1: line_len += snprintf(line + line_len, 128 - line_len, "%2.2x ", data[i]); break; } if ((i%8 == 7) || (i == length - 1)) { LOG_DEBUG("%s", line); while (c) { command_output_text(c->cmd_ctx, line); c = c->next; } c = target->dbgmsg; line_len = 0; } } free(data); return ERROR_OK; } /* handle requests from the target received by a target specific * side-band channel (e.g. ARM7/9 DCC) */ int target_request(struct target *target, uint32_t request) { target_req_cmd_t target_req_cmd = request & 0xff; assert(target->type->target_request_data); /* Record that we got a target message for back-off algorithm */ got_message = true; if (charmsg_mode) { target_charmsg(target, target_req_cmd); return ERROR_OK; } switch (target_req_cmd) { case TARGET_REQ_TRACEMSG: trace_point(target, (request & 0xffffff00) >> 8); break; case TARGET_REQ_DEBUGMSG: if (((request & 0xff00) >> 8) == 0) target_asciimsg(target, (request & 0xffff0000) >> 16); else target_hexmsg(target, (request & 0xff00) >> 8, (request & 0xffff0000) >> 16); break; case TARGET_REQ_DEBUGCHAR: target_charmsg(target, (request & 0x00ff0000) >> 16); break; /* case TARGET_REQ_SEMIHOSTING: * break; */ default: LOG_ERROR("unknown target request: %2.2x", target_req_cmd); break; } return ERROR_OK; } static int add_debug_msg_receiver(struct command_context *cmd_ctx, struct target *target) { struct debug_msg_receiver **p = &target->dbgmsg; if (!target) return ERROR_COMMAND_SYNTAX_ERROR; /* see if there's already a list */ if (*p) { /* find end of linked list */ while ((*p)->next) p = &((*p)->next); p = &((*p)->next); } /* add new debug message receiver */ (*p) = malloc(sizeof(struct debug_msg_receiver)); (*p)->cmd_ctx = cmd_ctx; (*p)->next = NULL; /* enable callback */ target->dbg_msg_enabled = 1; return ERROR_OK; } static struct debug_msg_receiver *find_debug_msg_receiver(struct command_context *cmd_ctx, struct target *target) { int do_all_targets = 0; /* if no target has been specified search all of them */ if (!target) { /* if no targets haven been specified */ if (!all_targets) return NULL; target = all_targets; do_all_targets = 1; } /* so we target != null */ struct debug_msg_receiver **p = &target->dbgmsg; do { while (*p) { if ((*p)->cmd_ctx == cmd_ctx) return *p; p = &((*p)->next); } target = target->next; } while (target && do_all_targets); return NULL; } int delete_debug_msg_receiver(struct command_context *cmd_ctx, struct target *target) { struct debug_msg_receiver **p; struct debug_msg_receiver *c; int do_all_targets = 0; /* if no target has been specified search all of them */ if (!target) { /* if no targets haven been specified */ if (!all_targets) return ERROR_OK; target = all_targets; do_all_targets = 1; } do { p = &target->dbgmsg; c = *p; while (c) { struct debug_msg_receiver *next = c->next; if (c->cmd_ctx == cmd_ctx) { *p = next; free(c); if (!*p) { /* disable callback */ target->dbg_msg_enabled = 0; } return ERROR_OK; } else p = &(c->next); c = next; } target = target->next; } while (target && do_all_targets); return ERROR_OK; } COMMAND_HANDLER(handle_target_request_debugmsgs_command) { struct target *target = get_current_target(CMD_CTX); int receiving = 0; if (!target->type->target_request_data) { LOG_ERROR("Target %s does not support target requests", target_name(target)); return ERROR_OK; } /* see if receiver is already registered */ if (find_debug_msg_receiver(CMD_CTX, target)) receiving = 1; if (CMD_ARGC > 0) { if (!strcmp(CMD_ARGV[0], "enable") || !strcmp(CMD_ARGV[0], "charmsg")) { /* don't register if this command context is already receiving */ if (!receiving) { receiving = 1; add_debug_msg_receiver(CMD_CTX, target); } charmsg_mode = !strcmp(CMD_ARGV[0], "charmsg"); } else if (!strcmp(CMD_ARGV[0], "disable")) { /* no need to delete a receiver if none is registered */ if (receiving) { receiving = 0; delete_debug_msg_receiver(CMD_CTX, target); } } else return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "receiving debug messages from current target %s", (receiving) ? (charmsg_mode ? "charmsg" : "enabled") : "disabled"); return ERROR_OK; } static const struct command_registration target_req_exec_command_handlers[] = { { .name = "debugmsgs", .handler = handle_target_request_debugmsgs_command, .mode = COMMAND_EXEC, .help = "display and/or modify reception of debug messages from target", .usage = "['enable'|'charmsg'|'disable']", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration target_req_command_handlers[] = { { .name = "target_request", .mode = COMMAND_ANY, .help = "target request command group", .usage = "", .chain = target_req_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; int target_request_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, target_req_command_handlers); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/target_request.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_TARGET_TARGET_REQUEST_H #define OPENOCD_TARGET_TARGET_REQUEST_H struct target; struct command_context; typedef enum target_req_cmd { TARGET_REQ_TRACEMSG, TARGET_REQ_DEBUGMSG, TARGET_REQ_DEBUGCHAR, /* TARGET_REQ_SEMIHOSTING, */ } target_req_cmd_t; struct debug_msg_receiver { struct command_context *cmd_ctx; struct debug_msg_receiver *next; }; int target_request(struct target *target, uint32_t request); int delete_debug_msg_receiver(struct command_context *cmd_ctx, struct target *target); int target_request_register_commands(struct command_context *cmd_ctx); /** * Read and clear the flag as to whether we got a message. * * This is used to implement the back-off algorithm on * sleeping in idle mode. */ bool target_got_message(void); #endif /* OPENOCD_TARGET_TARGET_REQUEST_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/target_type.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * ***************************************************************************/ #ifndef OPENOCD_TARGET_TARGET_TYPE_H #define OPENOCD_TARGET_TARGET_TYPE_H #include <helper/jim-nvp.h> struct target; /** * This holds methods shared between all instances of a given target * type. For example, all Cortex-M3 targets on a scan chain share * the same method table. */ struct target_type { /** * Name of this type of target. Do @b not access this * field directly, use target_type_name() instead. */ const char *name; /* poll current target status */ int (*poll)(struct target *target); /* Invoked only from target_arch_state(). * Issue USER() w/architecture specific status. */ int (*arch_state)(struct target *target); /* target request support */ int (*target_request_data)(struct target *target, uint32_t size, uint8_t *buffer); /* halt will log a warning, but return ERROR_OK if the target is already halted. */ int (*halt)(struct target *target); /* See target.c target_resume() for documentation. */ int (*resume)(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); int (*step)(struct target *target, int current, target_addr_t address, int handle_breakpoints); /* target reset control. assert reset can be invoked when OpenOCD and * the target is out of sync. * * A typical example is that the target was power cycled while OpenOCD * thought the target was halted or running. * * assert_reset() can therefore make no assumptions whatsoever about the * state of the target * * Before assert_reset() for the target is invoked, a TRST/tms and * chain validation is executed. TRST should not be asserted * during target assert unless there is no way around it due to * the way reset's are configured. * */ int (*assert_reset)(struct target *target); /** * The implementation is responsible for polling the * target such that target->state reflects the * state correctly. * * Otherwise the following would fail, as there will not * be any "poll" invoked between the "reset run" and * "halt". * * reset run; halt */ int (*deassert_reset)(struct target *target); int (*soft_reset_halt)(struct target *target); /** * Target architecture for GDB. * * The string returned by this function will not be automatically freed; * if dynamic allocation is used for this value, it must be managed by * the target, ideally by caching the result for subsequent calls. */ const char *(*get_gdb_arch)(struct target *target); /** * Target register access for GDB. Do @b not call this function * directly, use target_get_gdb_reg_list() instead. * * Danger! this function will succeed even if the target is running * and return a register list with dummy values. * * The reason is that GDB connection will fail without a valid register * list, however it is after GDB is connected that monitor commands can * be run to properly initialize the target */ int (*get_gdb_reg_list)(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); /** * Same as get_gdb_reg_list, but doesn't read the register values. * */ int (*get_gdb_reg_list_noread)(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); /* target memory access * size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit) * count: number of items of <size> */ /** * Target memory read callback. Do @b not call this function * directly, use target_read_memory() instead. */ int (*read_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); /** * Target memory write callback. Do @b not call this function * directly, use target_write_memory() instead. */ int (*write_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); /* Default implementation will do some fancy alignment to improve performance, target can override */ int (*read_buffer)(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer); /* Default implementation will do some fancy alignment to improve performance, target can override */ int (*write_buffer)(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer); int (*checksum_memory)(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); int (*blank_check_memory)(struct target *target, struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value); /* * target break-/watchpoint control * rw: 0 = write, 1 = read, 2 = access * * Target must be halted while this is invoked as this * will actually set up breakpoints on target. * * The breakpoint hardware will be set up upon adding the * first breakpoint. * * Upon GDB connection all breakpoints/watchpoints are cleared. */ int (*add_breakpoint)(struct target *target, struct breakpoint *breakpoint); int (*add_context_breakpoint)(struct target *target, struct breakpoint *breakpoint); int (*add_hybrid_breakpoint)(struct target *target, struct breakpoint *breakpoint); /* remove breakpoint. hw will only be updated if the target * is currently halted. * However, this method can be invoked on unresponsive targets. */ int (*remove_breakpoint)(struct target *target, struct breakpoint *breakpoint); /* add watchpoint ... see add_breakpoint() comment above. */ int (*add_watchpoint)(struct target *target, struct watchpoint *watchpoint); /* remove watchpoint. hw will only be updated if the target * is currently halted. * However, this method can be invoked on unresponsive targets. */ int (*remove_watchpoint)(struct target *target, struct watchpoint *watchpoint); /* Find out just hit watchpoint. After the target hits a watchpoint, the * information could assist gdb to locate where the modified/accessed memory is. */ int (*hit_watchpoint)(struct target *target, struct watchpoint **hit_watchpoint); /** * Target algorithm support. Do @b not call this method directly, * use target_run_algorithm() instead. */ int (*run_algorithm)(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); int (*start_algorithm)(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, target_addr_t entry_point, target_addr_t exit_point, void *arch_info); int (*wait_algorithm)(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); const struct command_registration *commands; /* called when target is created */ int (*target_create)(struct target *target, Jim_Interp *interp); /* called for various config parameters */ /* returns JIM_CONTINUE - if option not understood */ /* otherwise: JIM_OK, or JIM_ERR, */ int (*target_jim_configure)(struct target *target, struct jim_getopt_info *goi); /* target commands specifically handled by the target */ /* returns JIM_OK, or JIM_ERR, or JIM_CONTINUE - if option not understood */ int (*target_jim_commands)(struct target *target, struct jim_getopt_info *goi); /** * This method is used to perform target setup that requires * JTAG access. * * This may be called multiple times. It is called after the * scan chain is initially validated, or later after the target * is enabled by a JRC. It may also be called during some * parts of the reset sequence. * * For one-time initialization tasks, use target_was_examined() * and target_set_examined(). For example, probe the hardware * before setting up chip-specific state, and then set that * flag so you don't do that again. */ int (*examine)(struct target *target); /* Set up structures for target. * * It is illegal to talk to the target at this stage as this fn is invoked * before the JTAG chain has been examined/verified * */ int (*init_target)(struct command_context *cmd_ctx, struct target *target); /** * Free all the resources allocated by the target. * * WARNING: deinit_target is called unconditionally regardless the target has * ever been examined/initialised or not. * If a problem has prevented establishing JTAG/SWD/... communication * or * if the target was created with -defer-examine flag and has never been * examined * then it is not possible to communicate with the target. * * If you need to talk to the target during deinit, first check if * target_was_examined()! * * @param target The target to deinit */ void (*deinit_target)(struct target *target); /* translate from virtual to physical address. Default implementation is successful * no-op(i.e. virtual==physical). */ int (*virt2phys)(struct target *target, target_addr_t address, target_addr_t *physical); /* read directly from physical memory. caches are bypassed and untouched. * * If the target does not support disabling caches, leaving them untouched, * then minimally the actual physical memory location will be read even * if cache states are unchanged, flushed, etc. * * Default implementation is to call read_memory. */ int (*read_phys_memory)(struct target *target, target_addr_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer); /* * same as read_phys_memory, except that it writes... */ int (*write_phys_memory)(struct target *target, target_addr_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer); int (*mmu)(struct target *target, int *enabled); /* after reset is complete, the target can check if things are properly set up. * * This can be used to check if e.g. DCC memory writes have been enabled for * arm7/9 targets, which they really should except in the most contrived * circumstances. */ int (*check_reset)(struct target *target); /* get GDB file-I/O parameters from target */ int (*get_gdb_fileio_info)(struct target *target, struct gdb_fileio_info *fileio_info); /* pass GDB file-I/O response to target */ int (*gdb_fileio_end)(struct target *target, int retcode, int fileio_errno, bool ctrl_c); /* Parse target-specific GDB query commands. * The string pointer "response_p" is always assigned by the called function * to a pointer to a NULL-terminated string, even when the function returns * an error. The string memory is not freed by the caller, so this function * must pay attention for possible memory leaks if the string memory is * dynamically allocated. */ int (*gdb_query_custom)(struct target *target, const char *packet, char **response_p); /* do target profiling */ int (*profiling)(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds); /* Return the number of address bits this target supports. This will * typically be 32 for 32-bit targets, and 64 for 64-bit targets. If not * implemented, it's assumed to be 32. */ unsigned (*address_bits)(struct target *target); /* Return the number of system bus data bits this target supports. This * will typically be 32 for 32-bit targets, and 64 for 64-bit targets. If * not implemented, it's assumed to be 32. */ unsigned int (*data_bits)(struct target *target); }; extern struct target_type aarch64_target; extern struct target_type arcv2_target; extern struct target_type arm11_target; extern struct target_type arm720t_target; extern struct target_type arm7tdmi_target; extern struct target_type arm920t_target; extern struct target_type arm926ejs_target; extern struct target_type arm946e_target; extern struct target_type arm966e_target; extern struct target_type arm9tdmi_target; extern struct target_type armv8r_target; extern struct target_type avr32_ap7k_target; extern struct target_type avr_target; extern struct target_type cortexa_target; extern struct target_type cortexm_target; extern struct target_type cortexr4_target; extern struct target_type dragonite_target; extern struct target_type dsp563xx_target; extern struct target_type dsp5680xx_target; extern struct target_type esirisc_target; extern struct target_type esp32s2_target; extern struct target_type esp32s3_target; extern struct target_type esp32_target; extern struct target_type fa526_target; extern struct target_type feroceon_target; extern struct target_type hla_target; extern struct target_type ls1_sap_target; extern struct target_type mem_ap_target; extern struct target_type mips_m4k_target; extern struct target_type mips_mips64_target; extern struct target_type or1k_target; extern struct target_type quark_d20xx_target; extern struct target_type quark_x10xx_target; extern struct target_type riscv_target; extern struct target_type stm8_target; extern struct target_type testee_target; extern struct target_type xscale_target; extern struct target_type xtensa_chip_target; #endif /* OPENOCD_TARGET_TARGET_TYPE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/testee.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include "target.h" #include "target_type.h" #include "hello.h" static const struct command_registration testee_command_handlers[] = { { .name = "testee", .mode = COMMAND_ANY, .help = "testee target commands", .chain = hello_command_handlers, .usage = "", }, COMMAND_REGISTRATION_DONE }; static int testee_init(struct command_context *cmd_ctx, struct target *target) { return ERROR_OK; } static int testee_poll(struct target *target) { if ((target->state == TARGET_RUNNING) || (target->state == TARGET_DEBUG_RUNNING)) target->state = TARGET_HALTED; return ERROR_OK; } static int testee_halt(struct target *target) { target->state = TARGET_HALTED; return ERROR_OK; } static int testee_reset_assert(struct target *target) { target->state = TARGET_RESET; return ERROR_OK; } static int testee_reset_deassert(struct target *target) { target->state = TARGET_RUNNING; return ERROR_OK; } struct target_type testee_target = { .name = "testee", .commands = testee_command_handlers, .init_target = &testee_init, .poll = &testee_poll, .halt = &testee_halt, .assert_reset = &testee_reset_assert, .deassert_reset = &testee_reset_deassert, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/trace.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include "trace.h" #include "target.h" int trace_point(struct target *target, uint32_t number) { struct trace *trace = target->trace_info; LOG_DEBUG("tracepoint: %i", (int)number); if (number < trace->num_trace_points) trace->trace_points[number].hit_counter++; if (trace->trace_history_size) { trace->trace_history[trace->trace_history_pos++] = number; if (trace->trace_history_pos == trace->trace_history_size) { trace->trace_history_pos = 0; trace->trace_history_overflowed = 1; } } return ERROR_OK; } COMMAND_HANDLER(handle_trace_point_command) { struct target *target = get_current_target(CMD_CTX); struct trace *trace = target->trace_info; if (CMD_ARGC == 0) { uint32_t i; for (i = 0; i < trace->num_trace_points; i++) { command_print(CMD, "trace point 0x%8.8" PRIx32 " (%lld times hit)", trace->trace_points[i].address, (long long)trace->trace_points[i].hit_counter); } return ERROR_OK; } if (!strcmp(CMD_ARGV[0], "clear")) { free(trace->trace_points); trace->trace_points = NULL; trace->num_trace_points = 0; trace->trace_points_size = 0; return ERROR_OK; } /* resize array if necessary */ if (!trace->trace_points || (trace->trace_points_size == trace->num_trace_points)) { trace->trace_points = realloc(trace->trace_points, sizeof(struct trace_point) * (trace->trace_points_size + 32)); trace->trace_points_size += 32; } uint32_t address; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); trace->trace_points[trace->num_trace_points].address = address; trace->trace_points[trace->num_trace_points].hit_counter = 0; trace->num_trace_points++; return ERROR_OK; } COMMAND_HANDLER(handle_trace_history_command) { struct target *target = get_current_target(CMD_CTX); struct trace *trace = target->trace_info; if (CMD_ARGC > 0) { trace->trace_history_pos = 0; trace->trace_history_overflowed = 0; if (!strcmp(CMD_ARGV[0], "clear")) { /* clearing is implicit, we've just reset position anyway */ return ERROR_OK; } free(trace->trace_history); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], trace->trace_history_size); trace->trace_history = malloc(sizeof(uint32_t) * trace->trace_history_size); command_print(CMD, "new trace history size: %i", (int)(trace->trace_history_size)); } else { uint32_t i; uint32_t first = 0; uint32_t last = trace->trace_history_pos; if (!trace->trace_history_size) { command_print(CMD, "trace history buffer is not allocated"); return ERROR_OK; } if (trace->trace_history_overflowed) { first = trace->trace_history_pos; last = trace->trace_history_pos - 1; } for (i = first; (i % trace->trace_history_size) != last; i++) { if (trace->trace_history[i % trace->trace_history_size] < trace->num_trace_points) { uint32_t address; address = trace->trace_points[trace->trace_history[i % trace->trace_history_size]].address; command_print(CMD, "trace point %i: 0x%8.8" PRIx32 "", (int)(trace->trace_history[i % trace->trace_history_size]), address); } else command_print(CMD, "trace point %i: -not defined-", (int)(trace->trace_history[i % trace->trace_history_size])); } } return ERROR_OK; } static const struct command_registration trace_exec_command_handlers[] = { { .name = "history", .handler = handle_trace_history_command, .mode = COMMAND_EXEC, .help = "display trace history, clear history or set size", .usage = "['clear'|size]", }, { .name = "point", .handler = handle_trace_point_command, .mode = COMMAND_EXEC, .help = "display trace points, clear list of trace points, " "or add new tracepoint at address", .usage = "['clear'|address]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration trace_command_handlers[] = { { .name = "trace", .mode = COMMAND_EXEC, .help = "trace command group", .usage = "", .chain = trace_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; int trace_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, trace_command_handlers); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/trace.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_TARGET_TRACE_H #define OPENOCD_TARGET_TRACE_H #include "helper/types.h" struct target; struct command_context; struct trace_point { uint32_t address; uint64_t hit_counter; }; struct trace { uint32_t num_trace_points; uint32_t trace_points_size; struct trace_point *trace_points; uint32_t trace_history_size; uint32_t *trace_history; uint32_t trace_history_pos; int trace_history_overflowed; }; /** * \todo This enum is one of the few things in this file related * to *hardware* tracing ... split such "real" tracing out from * the contrib/libdcc support. */ typedef enum trace_status { TRACE_IDLE = 0x0, TRACE_RUNNING = 0x1, TRACE_TRIGGERED = 0x2, TRACE_COMPLETED = 0x4, TRACE_OVERFLOWED = 0x8, } trace_status_t; int trace_point(struct target *target, uint32_t number); int trace_register_commands(struct command_context *cmd_ctx); #define ERROR_TRACE_IMAGE_UNAVAILABLE (-1500) #define ERROR_TRACE_INSTRUCTION_UNAVAILABLE (-1501) #endif /* OPENOCD_TARGET_TRACE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/x86_32_common.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright(c) 2013 Intel Corporation. * * Adrian Burns (adrian.burns@intel.com) * Thomas Faust (thomas.faust@intel.com) * Ivan De Cesaris (ivan.de.cesaris@intel.com) * Julien Carreno (julien.carreno@intel.com) * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com) * * Contact Information: * Intel Corporation */ /* * @file * This implements generic x86 32 bit memory and breakpoint operations. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <helper/log.h> #include "target.h" #include "target_type.h" #include "register.h" #include "breakpoints.h" #include "x86_32_common.h" static int set_debug_regs(struct target *t, uint32_t address, uint8_t bp_num, uint8_t bp_type, uint8_t bp_length); static int unset_debug_regs(struct target *t, uint8_t bp_num); static int read_mem(struct target *t, uint32_t size, uint32_t addr, uint8_t *buf); static int write_mem(struct target *t, uint32_t size, uint32_t addr, const uint8_t *buf); static int calcaddr_physfromlin(struct target *t, target_addr_t addr, target_addr_t *physaddr); static int read_phys_mem(struct target *t, uint32_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer); static int write_phys_mem(struct target *t, uint32_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer); static int set_breakpoint(struct target *target, struct breakpoint *breakpoint); static int unset_breakpoint(struct target *target, struct breakpoint *breakpoint); static int set_watchpoint(struct target *target, struct watchpoint *watchpoint); static int unset_watchpoint(struct target *target, struct watchpoint *watchpoint); static int read_hw_reg_to_cache(struct target *t, int num); static int write_hw_reg_from_cache(struct target *t, int num); int x86_32_get_gdb_reg_list(struct target *t, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { struct x86_32_common *x86_32 = target_to_x86_32(t); int i; *reg_list_size = x86_32->cache->num_regs; LOG_DEBUG("num_regs=%d, reg_class=%d", (*reg_list_size), reg_class); *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); if (!*reg_list) { LOG_ERROR("%s out of memory", __func__); return ERROR_FAIL; } /* this will copy the values from our reg list to gdbs */ for (i = 0; i < (*reg_list_size); i++) { (*reg_list)[i] = &x86_32->cache->reg_list[i]; LOG_DEBUG("value %s = %08" PRIx32, x86_32->cache->reg_list[i].name, buf_get_u32(x86_32->cache->reg_list[i].value, 0, 32)); } return ERROR_OK; } int x86_32_common_init_arch_info(struct target *t, struct x86_32_common *x86_32) { t->arch_info = x86_32; x86_32->common_magic = X86_32_COMMON_MAGIC; x86_32->num_hw_bpoints = MAX_DEBUG_REGS; x86_32->hw_break_list = calloc(x86_32->num_hw_bpoints, sizeof(struct x86_32_dbg_reg)); if (!x86_32->hw_break_list) { LOG_ERROR("%s out of memory", __func__); return ERROR_FAIL; } x86_32->curr_tap = t->tap; x86_32->fast_data_area = NULL; x86_32->flush = 1; x86_32->read_hw_reg_to_cache = read_hw_reg_to_cache; x86_32->write_hw_reg_from_cache = write_hw_reg_from_cache; return ERROR_OK; } int x86_32_common_mmu(struct target *t, int *enabled) { *enabled = true; return ERROR_OK; } int x86_32_common_virt2phys(struct target *t, target_addr_t address, target_addr_t *physical) { struct x86_32_common *x86_32 = target_to_x86_32(t); /* * We need to ignore 'segmentation' for now, as OpenOCD can't handle * segmented addresses. * In protected mode that is almost OK, as (almost) any known OS is using * flat segmentation. In real mode we use use the base of the DS segment, * as we don't know better ... */ uint32_t cr0 = buf_get_u32(x86_32->cache->reg_list[CR0].value, 0, 32); if (!(cr0 & CR0_PG)) { /* target halted in real mode */ /* TODO: needs validation !!! */ uint32_t dsb = buf_get_u32(x86_32->cache->reg_list[DSB].value, 0, 32); *physical = dsb + address; } else { /* target halted in protected mode */ if (calcaddr_physfromlin(t, address, physical) != ERROR_OK) { LOG_ERROR("%s failed to calculate physical address from " TARGET_ADDR_FMT, __func__, address); return ERROR_FAIL; } } return ERROR_OK; } int x86_32_common_read_phys_mem(struct target *t, target_addr_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer) { struct x86_32_common *x86_32 = target_to_x86_32(t); int error; error = read_phys_mem(t, phys_address, size, count, buffer); if (error != ERROR_OK) return error; /* After reading memory from target, we must replace software breakpoints * with the original instructions again. */ struct swbp_mem_patch *iter = x86_32->swbbp_mem_patch_list; while (iter) { if (iter->physaddr >= phys_address && iter->physaddr < phys_address+(size*count)) { uint32_t offset = iter->physaddr - phys_address; buffer[offset] = iter->orig_byte; } iter = iter->next; } return ERROR_OK; } static int read_phys_mem(struct target *t, uint32_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval = ERROR_OK; bool pg_disabled = false; LOG_DEBUG("addr=0x%08" PRIx32 ", size=%" PRIu32 ", count=0x%" PRIx32 ", buf=%p", phys_address, size, count, buffer); struct x86_32_common *x86_32 = target_to_x86_32(t); if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; if (!count || !buffer || !phys_address) { LOG_ERROR("%s invalid params count=0x%" PRIx32 ", buf=%p, addr=0x%08" PRIx32, __func__, count, buffer, phys_address); return ERROR_COMMAND_ARGUMENT_INVALID; } /* to access physical memory, switch off the CR0.PG bit */ if (x86_32->is_paging_enabled(t)) { retval = x86_32->disable_paging(t); if (retval != ERROR_OK) { LOG_ERROR("%s could not disable paging", __func__); return retval; } pg_disabled = true; } for (uint32_t i = 0; i < count; i++) { switch (size) { case BYTE: retval = read_mem(t, size, phys_address + i, buffer + i); break; case WORD: retval = read_mem(t, size, phys_address + i * 2, buffer + i * 2); break; case DWORD: retval = read_mem(t, size, phys_address + i * 4, buffer + i * 4); break; default: LOG_ERROR("%s invalid read size", __func__); break; } if (retval != ERROR_OK) break; } /* restore CR0.PG bit if needed (regardless of retval) */ if (pg_disabled) { int retval2 = x86_32->enable_paging(t); if (retval2 != ERROR_OK) { LOG_ERROR("%s could not enable paging", __func__); return retval2; } } /* TODO: After reading memory from target, we must replace * software breakpoints with the original instructions again. * Solve this with the breakpoint fix */ return retval; } int x86_32_common_write_phys_mem(struct target *t, target_addr_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct x86_32_common *x86_32 = target_to_x86_32(t); int error = ERROR_OK; uint8_t *newbuffer = NULL; check_not_halted(t); if (!count || !buffer || !phys_address) { LOG_ERROR("%s invalid params count=0x%" PRIx32 ", buf=%p, addr=" TARGET_ADDR_FMT, __func__, count, buffer, phys_address); return ERROR_COMMAND_ARGUMENT_INVALID; } /* Before writing memory to target, we must update software breakpoints * with the new instructions and patch the memory buffer with the * breakpoint instruction. */ newbuffer = malloc(size*count); if (!newbuffer) { LOG_ERROR("%s out of memory", __func__); return ERROR_FAIL; } memcpy(newbuffer, buffer, size*count); struct swbp_mem_patch *iter = x86_32->swbbp_mem_patch_list; while (iter) { if (iter->physaddr >= phys_address && iter->physaddr < phys_address+(size*count)) { uint32_t offset = iter->physaddr - phys_address; newbuffer[offset] = SW_BP_OPCODE; /* update the breakpoint */ struct breakpoint *pbiter = t->breakpoints; while (pbiter && pbiter->unique_id != iter->swbp_unique_id) pbiter = pbiter->next; if (pbiter) pbiter->orig_instr[0] = buffer[offset]; } iter = iter->next; } error = write_phys_mem(t, phys_address, size, count, newbuffer); free(newbuffer); return error; } static int write_phys_mem(struct target *t, uint32_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval = ERROR_OK; bool pg_disabled = false; struct x86_32_common *x86_32 = target_to_x86_32(t); LOG_DEBUG("addr=0x%08" PRIx32 ", size=%" PRIu32 ", count=0x%" PRIx32 ", buf=%p", phys_address, size, count, buffer); check_not_halted(t); if (!count || !buffer || !phys_address) { LOG_ERROR("%s invalid params count=0x%" PRIx32 ", buf=%p, addr=0x%08" PRIx32, __func__, count, buffer, phys_address); return ERROR_COMMAND_ARGUMENT_INVALID; } /* TODO: Before writing memory to target, we must update * software breakpoints with the new instructions and * patch the memory buffer with the breakpoint instruction. * Solve this with the breakpoint fix */ /* to access physical memory, switch off the CR0.PG bit */ if (x86_32->is_paging_enabled(t)) { retval = x86_32->disable_paging(t); if (retval != ERROR_OK) { LOG_ERROR("%s could not disable paging", __func__); return retval; } pg_disabled = true; } for (uint32_t i = 0; i < count; i++) { switch (size) { case BYTE: retval = write_mem(t, size, phys_address + i, buffer + i); break; case WORD: retval = write_mem(t, size, phys_address + i * 2, buffer + i * 2); break; case DWORD: retval = write_mem(t, size, phys_address + i * 4, buffer + i * 4); break; default: LOG_DEBUG("invalid read size"); break; } } /* restore CR0.PG bit if needed (regardless of retval) */ if (pg_disabled) { retval = x86_32->enable_paging(t); if (retval != ERROR_OK) { LOG_ERROR("%s could not enable paging", __func__); return retval; } } return retval; } static int read_mem(struct target *t, uint32_t size, uint32_t addr, uint8_t *buf) { struct x86_32_common *x86_32 = target_to_x86_32(t); /* if CS.D bit=1 then its a 32 bit code segment, else 16 */ bool use32 = (buf_get_u32(x86_32->cache->reg_list[CSAR].value, 0, 32)) & CSAR_D; int retval = x86_32->write_hw_reg(t, EAX, addr, 0); if (retval != ERROR_OK) { LOG_ERROR("%s error write EAX", __func__); return retval; } switch (size) { case BYTE: if (use32) retval = x86_32->submit_instruction(t, MEMRDB32); else retval = x86_32->submit_instruction(t, MEMRDB16); break; case WORD: if (use32) retval = x86_32->submit_instruction(t, MEMRDH32); else retval = x86_32->submit_instruction(t, MEMRDH16); break; case DWORD: if (use32) retval = x86_32->submit_instruction(t, MEMRDW32); else retval = x86_32->submit_instruction(t, MEMRDW16); break; default: LOG_ERROR("%s invalid read mem size", __func__); break; } if (retval != ERROR_OK) return retval; /* read_hw_reg() will write to 4 bytes (uint32_t) * Watch out, the buffer passed into read_mem() might be 1 or 2 bytes. */ uint32_t regval; retval = x86_32->read_hw_reg(t, EDX, ®val, 0); if (retval != ERROR_OK) { LOG_ERROR("%s error read EDX", __func__); return retval; } for (uint8_t i = 0; i < size; i++) buf[i] = (regval >> (i*8)) & 0x000000FF; retval = x86_32->transaction_status(t); if (retval != ERROR_OK) { LOG_ERROR("%s error on mem read", __func__); return retval; } return retval; } static int write_mem(struct target *t, uint32_t size, uint32_t addr, const uint8_t *buf) { uint32_t i = 0; uint32_t buf4bytes = 0; int retval = ERROR_OK; struct x86_32_common *x86_32 = target_to_x86_32(t); for (i = 0; i < size; ++i) { buf4bytes = buf4bytes << 8; /* first time we only shift 0s */ buf4bytes += buf[(size-1)-i]; /* it was hard to write, should be hard to read! */ } /* if CS.D bit=1 then its a 32 bit code segment, else 16 */ bool use32 = (buf_get_u32(x86_32->cache->reg_list[CSAR].value, 0, 32)) & CSAR_D; retval = x86_32->write_hw_reg(t, EAX, addr, 0); if (retval != ERROR_OK) { LOG_ERROR("%s error write EAX", __func__); return retval; } /* write_hw_reg() will write to 4 bytes (uint32_t) * Watch out, the buffer passed into write_mem() might be 1 or 2 bytes. */ retval = x86_32->write_hw_reg(t, EDX, buf4bytes, 0); if (retval != ERROR_OK) { LOG_ERROR("%s error write EDX", __func__); return retval; } switch (size) { case BYTE: if (use32) retval = x86_32->submit_instruction(t, MEMWRB32); else retval = x86_32->submit_instruction(t, MEMWRB16); break; case WORD: if (use32) retval = x86_32->submit_instruction(t, MEMWRH32); else retval = x86_32->submit_instruction(t, MEMWRH16); break; case DWORD: if (use32) retval = x86_32->submit_instruction(t, MEMWRW32); else retval = x86_32->submit_instruction(t, MEMWRW16); break; default: LOG_ERROR("%s invalid write mem size", __func__); return ERROR_FAIL; } if (retval != ERROR_OK) return retval; retval = x86_32->transaction_status(t); if (retval != ERROR_OK) { LOG_ERROR("%s error on mem write", __func__); return retval; } return retval; } int calcaddr_physfromlin(struct target *t, target_addr_t addr, target_addr_t *physaddr) { uint8_t entry_buffer[8]; if (!physaddr || !t) return ERROR_FAIL; struct x86_32_common *x86_32 = target_to_x86_32(t); /* The 'user-visible' CR0.PG should be set - otherwise the function shouldn't be called * (Don't check the CR0.PG on the target, this might be temporally disabled at this point) */ uint32_t cr0 = buf_get_u32(x86_32->cache->reg_list[CR0].value, 0, 32); if (!(cr0 & CR0_PG)) { /* you are wrong in this function, never mind */ *physaddr = addr; return ERROR_OK; } uint32_t cr4 = buf_get_u32(x86_32->cache->reg_list[CR4].value, 0, 32); bool is_pae = cr4 & 0x00000020; /* PAE - Physical Address Extension */ uint32_t cr3 = buf_get_u32(x86_32->cache->reg_list[CR3].value, 0, 32); if (is_pae) { uint32_t pdpt_base = cr3 & 0xFFFFF000; /* lower 12 bits of CR3 must always be 0 */ uint32_t pdpt_index = (addr & 0xC0000000) >> 30; /* A[31:30] index to PDPT */ uint32_t pdpt_addr = pdpt_base + (8 * pdpt_index); if (x86_32_common_read_phys_mem(t, pdpt_addr, 4, 2, entry_buffer) != ERROR_OK) { LOG_ERROR("%s couldn't read page directory pointer table entry at 0x%08" PRIx32, __func__, pdpt_addr); return ERROR_FAIL; } uint64_t pdpt_entry = target_buffer_get_u64(t, entry_buffer); if (!(pdpt_entry & 0x0000000000000001)) { LOG_ERROR("%s page directory pointer table entry at 0x%08" PRIx32 " is not present", __func__, pdpt_addr); return ERROR_FAIL; } uint32_t pd_base = pdpt_entry & 0xFFFFF000; /* A[31:12] is PageTable/Page Base Address */ uint32_t pd_index = (addr & 0x3FE00000) >> 21; /* A[29:21] index to PD entry with PAE */ uint32_t pd_addr = pd_base + (8 * pd_index); if (x86_32_common_read_phys_mem(t, pd_addr, 4, 2, entry_buffer) != ERROR_OK) { LOG_ERROR("%s couldn't read page directory entry at 0x%08" PRIx32, __func__, pd_addr); return ERROR_FAIL; } uint64_t pd_entry = target_buffer_get_u64(t, entry_buffer); if (!(pd_entry & 0x0000000000000001)) { LOG_ERROR("%s page directory entry at 0x%08" PRIx32 " is not present", __func__, pd_addr); return ERROR_FAIL; } /* PS bit in PD entry is indicating 4KB or 2MB page size */ if (pd_entry & 0x0000000000000080) { uint32_t page_base = (uint32_t)(pd_entry & 0x00000000FFE00000); /* [31:21] */ uint32_t offset = addr & 0x001FFFFF; /* [20:0] */ *physaddr = page_base + offset; return ERROR_OK; } else { uint32_t pt_base = (uint32_t)(pd_entry & 0x00000000FFFFF000); /*[31:12]*/ uint32_t pt_index = (addr & 0x001FF000) >> 12; /*[20:12]*/ uint32_t pt_addr = pt_base + (8 * pt_index); if (x86_32_common_read_phys_mem(t, pt_addr, 4, 2, entry_buffer) != ERROR_OK) { LOG_ERROR("%s couldn't read page table entry at 0x%08" PRIx32, __func__, pt_addr); return ERROR_FAIL; } uint64_t pt_entry = target_buffer_get_u64(t, entry_buffer); if (!(pt_entry & 0x0000000000000001)) { LOG_ERROR("%s page table entry at 0x%08" PRIx32 " is not present", __func__, pt_addr); return ERROR_FAIL; } uint32_t page_base = (uint32_t)(pt_entry & 0x00000000FFFFF000); /*[31:12]*/ uint32_t offset = addr & 0x00000FFF; /*[11:0]*/ *physaddr = page_base + offset; return ERROR_OK; } } else { uint32_t pd_base = cr3 & 0xFFFFF000; /* lower 12 bits of CR3 must always be 0 */ uint32_t pd_index = (addr & 0xFFC00000) >> 22; /* A[31:22] index to PD entry */ uint32_t pd_addr = pd_base + (4 * pd_index); if (x86_32_common_read_phys_mem(t, pd_addr, 4, 1, entry_buffer) != ERROR_OK) { LOG_ERROR("%s couldn't read page directory entry at 0x%08" PRIx32, __func__, pd_addr); return ERROR_FAIL; } uint32_t pd_entry = target_buffer_get_u32(t, entry_buffer); if (!(pd_entry & 0x00000001)) { LOG_ERROR("%s page directory entry at 0x%08" PRIx32 " is not present", __func__, pd_addr); return ERROR_FAIL; } /* Bit 7 in page directory entry is page size. */ if (pd_entry & 0x00000080) { /* 4MB pages */ uint32_t page_base = pd_entry & 0xFFC00000; *physaddr = page_base + (addr & 0x003FFFFF); } else { /* 4KB pages */ uint32_t pt_base = pd_entry & 0xFFFFF000; /* A[31:12] is PageTable/Page Base Address */ uint32_t pt_index = (addr & 0x003FF000) >> 12; /* A[21:12] index to page table entry */ uint32_t pt_addr = pt_base + (4 * pt_index); if (x86_32_common_read_phys_mem(t, pt_addr, 4, 1, entry_buffer) != ERROR_OK) { LOG_ERROR("%s couldn't read page table entry at 0x%08" PRIx32, __func__, pt_addr); return ERROR_FAIL; } uint32_t pt_entry = target_buffer_get_u32(t, entry_buffer); if (!(pt_entry & 0x00000001)) { LOG_ERROR("%s page table entry at 0x%08" PRIx32 " is not present", __func__, pt_addr); return ERROR_FAIL; } uint32_t page_base = pt_entry & 0xFFFFF000; /* A[31:12] is PageTable/Page Base Address */ *physaddr = page_base + (addr & 0x00000FFF); /* A[11:0] offset to 4KB page in linear address */ } } return ERROR_OK; } int x86_32_common_read_memory(struct target *t, target_addr_t addr, uint32_t size, uint32_t count, uint8_t *buf) { int retval = ERROR_OK; struct x86_32_common *x86_32 = target_to_x86_32(t); LOG_DEBUG("addr=" TARGET_ADDR_FMT ", size=%" PRIu32 ", count=0x%" PRIx32 ", buf=%p", addr, size, count, buf); check_not_halted(t); if (!count || !buf || !addr) { LOG_ERROR("%s invalid params count=0x%" PRIx32 ", buf=%p, addr=" TARGET_ADDR_FMT, __func__, count, buf, addr); return ERROR_COMMAND_ARGUMENT_INVALID; } if (x86_32->is_paging_enabled(t)) { /* all memory accesses from debugger must be physical (CR0.PG == 0) * conversion to physical address space needed */ retval = x86_32->disable_paging(t); if (retval != ERROR_OK) { LOG_ERROR("%s could not disable paging", __func__); return retval; } target_addr_t physaddr = 0; if (calcaddr_physfromlin(t, addr, &physaddr) != ERROR_OK) { LOG_ERROR("%s failed to calculate physical address from " TARGET_ADDR_FMT, __func__, addr); retval = ERROR_FAIL; } /* TODO: !!! Watch out for page boundaries * for every 4kB, the physical address has to be re-calculated * This should be fixed together with bulk memory reads */ if (retval == ERROR_OK && x86_32_common_read_phys_mem(t, physaddr, size, count, buf) != ERROR_OK) { LOG_ERROR("%s failed to read memory from physical address " TARGET_ADDR_FMT, __func__, physaddr); } /* restore PG bit if it was cleared prior (regardless of retval) */ retval = x86_32->enable_paging(t); if (retval != ERROR_OK) { LOG_ERROR("%s could not enable paging", __func__); return retval; } } else { /* paging is off - linear address is physical address */ if (x86_32_common_read_phys_mem(t, addr, size, count, buf) != ERROR_OK) { LOG_ERROR("%s failed to read memory from address " TARGET_ADDR_FMT, __func__, addr); retval = ERROR_FAIL; } } return retval; } int x86_32_common_write_memory(struct target *t, target_addr_t addr, uint32_t size, uint32_t count, const uint8_t *buf) { int retval = ERROR_OK; struct x86_32_common *x86_32 = target_to_x86_32(t); LOG_DEBUG("addr=" TARGET_ADDR_FMT ", size=%" PRIu32 ", count=0x%" PRIx32 ", buf=%p", addr, size, count, buf); check_not_halted(t); if (!count || !buf || !addr) { LOG_ERROR("%s invalid params count=0x%" PRIx32 ", buf=%p, addr=" TARGET_ADDR_FMT, __func__, count, buf, addr); return ERROR_COMMAND_ARGUMENT_INVALID; } if (x86_32->is_paging_enabled(t)) { /* all memory accesses from debugger must be physical (CR0.PG == 0) * conversion to physical address space needed */ retval = x86_32->disable_paging(t); if (retval != ERROR_OK) { LOG_ERROR("%s could not disable paging", __func__); return retval; } target_addr_t physaddr = 0; if (calcaddr_physfromlin(t, addr, &physaddr) != ERROR_OK) { LOG_ERROR("%s failed to calculate physical address from " TARGET_ADDR_FMT, __func__, addr); retval = ERROR_FAIL; } /* TODO: !!! Watch out for page boundaries * for every 4kB, the physical address has to be re-calculated * This should be fixed together with bulk memory reads */ if (retval == ERROR_OK && x86_32_common_write_phys_mem(t, physaddr, size, count, buf) != ERROR_OK) { LOG_ERROR("%s failed to write memory to physical address " TARGET_ADDR_FMT, __func__, physaddr); } /* restore PG bit if it was cleared prior (regardless of retval) */ retval = x86_32->enable_paging(t); if (retval != ERROR_OK) { LOG_ERROR("%s could not enable paging", __func__); return retval; } } else { /* paging is off - linear address is physical address */ if (x86_32_common_write_phys_mem(t, addr, size, count, buf) != ERROR_OK) { LOG_ERROR("%s failed to write memory to address " TARGET_ADDR_FMT, __func__, addr); retval = ERROR_FAIL; } } return retval; } int x86_32_common_read_io(struct target *t, uint32_t addr, uint32_t size, uint8_t *buf) { struct x86_32_common *x86_32 = target_to_x86_32(t); /* if CS.D bit=1 then its a 32 bit code segment, else 16 */ bool use32 = (buf_get_u32(x86_32->cache->reg_list[CSAR].value, 0, 32)) & CSAR_D; int retval = ERROR_FAIL; bool pg_disabled = false; LOG_DEBUG("addr=0x%08" PRIx32 ", size=%" PRIu32 ", buf=%p", addr, size, buf); check_not_halted(t); if (!buf || !addr) { LOG_ERROR("%s invalid params buf=%p, addr=%08" PRIx32, __func__, buf, addr); return retval; } retval = x86_32->write_hw_reg(t, EDX, addr, 0); if (retval != ERROR_OK) { LOG_ERROR("%s error EDX write", __func__); return retval; } /* to access physical memory, switch off the CR0.PG bit */ if (x86_32->is_paging_enabled(t)) { retval = x86_32->disable_paging(t); if (retval != ERROR_OK) { LOG_ERROR("%s could not disable paging", __func__); return retval; } pg_disabled = true; } switch (size) { case BYTE: if (use32) retval = x86_32->submit_instruction(t, IORDB32); else retval = x86_32->submit_instruction(t, IORDB16); break; case WORD: if (use32) retval = x86_32->submit_instruction(t, IORDH32); else retval = x86_32->submit_instruction(t, IORDH16); break; case DWORD: if (use32) retval = x86_32->submit_instruction(t, IORDW32); else retval = x86_32->submit_instruction(t, IORDW16); break; default: LOG_ERROR("%s invalid read io size", __func__); return ERROR_FAIL; } /* restore CR0.PG bit if needed */ if (pg_disabled) { int retval2 = x86_32->enable_paging(t); if (retval2 != ERROR_OK) { LOG_ERROR("%s could not enable paging", __func__); return retval2; } } if (retval != ERROR_OK) return retval; uint32_t regval = 0; retval = x86_32->read_hw_reg(t, EAX, ®val, 0); if (retval != ERROR_OK) { LOG_ERROR("%s error on read EAX", __func__); return retval; } for (uint8_t i = 0; i < size; i++) buf[i] = (regval >> (i*8)) & 0x000000FF; retval = x86_32->transaction_status(t); if (retval != ERROR_OK) { LOG_ERROR("%s error on io read", __func__); return retval; } return retval; } int x86_32_common_write_io(struct target *t, uint32_t addr, uint32_t size, const uint8_t *buf) { struct x86_32_common *x86_32 = target_to_x86_32(t); /* if CS.D bit=1 then its a 32 bit code segment, else 16 */ bool use32 = (buf_get_u32(x86_32->cache->reg_list[CSAR].value, 0, 32)) & CSAR_D; LOG_DEBUG("addr=0x%08" PRIx32 ", size=%" PRIu32 ", buf=%p", addr, size, buf); check_not_halted(t); int retval = ERROR_FAIL; bool pg_disabled = false; if (!buf || !addr) { LOG_ERROR("%s invalid params buf=%p, addr=0x%08" PRIx32, __func__, buf, addr); return retval; } /* no do the write */ retval = x86_32->write_hw_reg(t, EDX, addr, 0); if (retval != ERROR_OK) { LOG_ERROR("%s error on EDX write", __func__); return retval; } uint32_t regval = 0; for (uint8_t i = 0; i < size; i++) regval += (buf[i] << (i*8)); retval = x86_32->write_hw_reg(t, EAX, regval, 0); if (retval != ERROR_OK) { LOG_ERROR("%s error on EAX write", __func__); return retval; } /* to access physical memory, switch off the CR0.PG bit */ if (x86_32->is_paging_enabled(t)) { retval = x86_32->disable_paging(t); if (retval != ERROR_OK) { LOG_ERROR("%s could not disable paging", __func__); return retval; } pg_disabled = true; } switch (size) { case BYTE: if (use32) retval = x86_32->submit_instruction(t, IOWRB32); else retval = x86_32->submit_instruction(t, IOWRB16); break; case WORD: if (use32) retval = x86_32->submit_instruction(t, IOWRH32); else retval = x86_32->submit_instruction(t, IOWRH16); break; case DWORD: if (use32) retval = x86_32->submit_instruction(t, IOWRW32); else retval = x86_32->submit_instruction(t, IOWRW16); break; default: LOG_ERROR("%s invalid write io size", __func__); return ERROR_FAIL; } /* restore CR0.PG bit if needed */ if (pg_disabled) { int retval2 = x86_32->enable_paging(t); if (retval2 != ERROR_OK) { LOG_ERROR("%s could not enable paging", __func__); return retval2; } } if (retval != ERROR_OK) return retval; retval = x86_32->transaction_status(t); if (retval != ERROR_OK) { LOG_ERROR("%s error on io write", __func__); return retval; } return retval; } int x86_32_common_add_watchpoint(struct target *t, struct watchpoint *wp) { check_not_halted(t); /* set_watchpoint() will return ERROR_TARGET_RESOURCE_NOT_AVAILABLE if all * hardware registers are gone */ return set_watchpoint(t, wp); } int x86_32_common_remove_watchpoint(struct target *t, struct watchpoint *wp) { if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; if (wp->is_set) unset_watchpoint(t, wp); return ERROR_OK; } int x86_32_common_add_breakpoint(struct target *t, struct breakpoint *bp) { LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; /* set_breakpoint() will return ERROR_TARGET_RESOURCE_NOT_AVAILABLE if all * hardware registers are gone (for hardware breakpoints) */ return set_breakpoint(t, bp); } int x86_32_common_remove_breakpoint(struct target *t, struct breakpoint *bp) { LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; if (bp->is_set) unset_breakpoint(t, bp); return ERROR_OK; } static int set_debug_regs(struct target *t, uint32_t address, uint8_t bp_num, uint8_t bp_type, uint8_t bp_length) { struct x86_32_common *x86_32 = target_to_x86_32(t); LOG_DEBUG("addr=0x%08" PRIx32 ", bp_num=%" PRIu8 ", bp_type=%" PRIu8 ", pb_length=%" PRIu8, address, bp_num, bp_type, bp_length); /* DR7 - set global enable */ uint32_t dr7 = buf_get_u32(x86_32->cache->reg_list[DR7].value, 0, 32); if (bp_length != 1 && bp_length != 2 && bp_length != 4) return ERROR_FAIL; if (DR7_BP_FREE(dr7, bp_num)) DR7_GLOBAL_ENABLE(dr7, bp_num); else { LOG_ERROR("%s dr7 error, already enabled, val=%08" PRIx32, __func__, dr7); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } switch (bp_type) { case 0: /* 00 - only on instruction execution */ DR7_SET_EXE(dr7, bp_num); DR7_SET_LENGTH(dr7, bp_num, bp_length); break; case 1: /* 01 - only on data writes */ DR7_SET_WRITE(dr7, bp_num); DR7_SET_LENGTH(dr7, bp_num, bp_length); break; case 2: /* 10 UNSUPPORTED - an I/O read and I/O write */ LOG_ERROR("%s unsupported feature bp_type=%d", __func__, bp_type); return ERROR_FAIL; break; case 3: /* on data read or data write */ DR7_SET_ACCESS(dr7, bp_num); DR7_SET_LENGTH(dr7, bp_num, bp_length); break; default: LOG_ERROR("%s invalid request [only 0-3] bp_type=%d", __func__, bp_type); return ERROR_FAIL; } /* update regs in the reg cache ready to be written to hardware * when we exit PM */ buf_set_u32(x86_32->cache->reg_list[bp_num+DR0].value, 0, 32, address); x86_32->cache->reg_list[bp_num+DR0].dirty = true; x86_32->cache->reg_list[bp_num+DR0].valid = true; buf_set_u32(x86_32->cache->reg_list[DR6].value, 0, 32, PM_DR6); x86_32->cache->reg_list[DR6].dirty = true; x86_32->cache->reg_list[DR6].valid = true; buf_set_u32(x86_32->cache->reg_list[DR7].value, 0, 32, dr7); x86_32->cache->reg_list[DR7].dirty = true; x86_32->cache->reg_list[DR7].valid = true; return ERROR_OK; } static int unset_debug_regs(struct target *t, uint8_t bp_num) { struct x86_32_common *x86_32 = target_to_x86_32(t); LOG_DEBUG("bp_num=%" PRIu8, bp_num); uint32_t dr7 = buf_get_u32(x86_32->cache->reg_list[DR7].value, 0, 32); if (!(DR7_BP_FREE(dr7, bp_num))) { DR7_GLOBAL_DISABLE(dr7, bp_num); } else { LOG_ERROR("%s dr7 error, not enabled, val=0x%08" PRIx32, __func__, dr7); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* this will clear rw and len bits */ DR7_RESET_RWLEN_BITS(dr7, bp_num); /* update regs in the reg cache ready to be written to hardware * when we exit PM */ buf_set_u32(x86_32->cache->reg_list[bp_num+DR0].value, 0, 32, 0); x86_32->cache->reg_list[bp_num+DR0].dirty = true; x86_32->cache->reg_list[bp_num+DR0].valid = true; buf_set_u32(x86_32->cache->reg_list[DR6].value, 0, 32, PM_DR6); x86_32->cache->reg_list[DR6].dirty = true; x86_32->cache->reg_list[DR6].valid = true; buf_set_u32(x86_32->cache->reg_list[DR7].value, 0, 32, dr7); x86_32->cache->reg_list[DR7].dirty = true; x86_32->cache->reg_list[DR7].valid = true; return ERROR_OK; } static int set_hwbp(struct target *t, struct breakpoint *bp) { struct x86_32_common *x86_32 = target_to_x86_32(t); struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list; uint8_t hwbp_num = 0; while (debug_reg_list[hwbp_num].used && (hwbp_num < x86_32->num_hw_bpoints)) hwbp_num++; if (hwbp_num >= x86_32->num_hw_bpoints) { LOG_ERROR("%s no free hw breakpoint bpid=0x%" PRIx32, __func__, bp->unique_id); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (set_debug_regs(t, bp->address, hwbp_num, DR7_BP_EXECUTE, 1) != ERROR_OK) return ERROR_FAIL; breakpoint_hw_set(bp, hwbp_num); debug_reg_list[hwbp_num].used = 1; debug_reg_list[hwbp_num].bp_value = bp->address; LOG_USER("%s hardware breakpoint %" PRIu32 " set at 0x%08" PRIx32 " (hwreg=%" PRIu8 ")", __func__, bp->unique_id, debug_reg_list[hwbp_num].bp_value, hwbp_num); return ERROR_OK; } static int unset_hwbp(struct target *t, struct breakpoint *bp) { struct x86_32_common *x86_32 = target_to_x86_32(t); struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list; int hwbp_num = bp->number; if (hwbp_num >= x86_32->num_hw_bpoints) { LOG_ERROR("%s invalid breakpoint number=%d, bpid=%" PRIu32, __func__, hwbp_num, bp->unique_id); return ERROR_OK; } if (unset_debug_regs(t, hwbp_num) != ERROR_OK) return ERROR_FAIL; debug_reg_list[hwbp_num].used = 0; debug_reg_list[hwbp_num].bp_value = 0; LOG_USER("%s hardware breakpoint %" PRIu32 " removed from " TARGET_ADDR_FMT " (hwreg=%d)", __func__, bp->unique_id, bp->address, hwbp_num); return ERROR_OK; } static int set_swbp(struct target *t, struct breakpoint *bp) { struct x86_32_common *x86_32 = target_to_x86_32(t); LOG_DEBUG("id %" PRIx32, bp->unique_id); target_addr_t physaddr; uint8_t opcode = SW_BP_OPCODE; uint8_t readback; if (calcaddr_physfromlin(t, bp->address, &physaddr) != ERROR_OK) return ERROR_FAIL; if (read_phys_mem(t, physaddr, 1, 1, bp->orig_instr)) return ERROR_FAIL; LOG_DEBUG("set software breakpoint - orig byte=0x%02" PRIx8 "", *bp->orig_instr); /* just write the instruction trap byte */ if (write_phys_mem(t, physaddr, 1, 1, &opcode)) return ERROR_FAIL; /* verify that this is not invalid/read-only memory */ if (read_phys_mem(t, physaddr, 1, 1, &readback)) return ERROR_FAIL; if (readback != SW_BP_OPCODE) { LOG_ERROR("%s software breakpoint error at " TARGET_ADDR_FMT ", check memory", __func__, bp->address); LOG_ERROR("%s readback=0x%02" PRIx8 " orig=0x%02" PRIx8 "", __func__, readback, *bp->orig_instr); return ERROR_FAIL; } bp->is_set = true; /* add the memory patch */ struct swbp_mem_patch *new_patch = malloc(sizeof(struct swbp_mem_patch)); if (!new_patch) { LOG_ERROR("%s out of memory", __func__); return ERROR_FAIL; } new_patch->next = NULL; new_patch->orig_byte = *bp->orig_instr; new_patch->physaddr = physaddr; new_patch->swbp_unique_id = bp->unique_id; struct swbp_mem_patch *addto = x86_32->swbbp_mem_patch_list; if (!addto) x86_32->swbbp_mem_patch_list = new_patch; else { while (addto->next) addto = addto->next; addto->next = new_patch; } LOG_USER("%s software breakpoint %" PRIu32 " set at " TARGET_ADDR_FMT, __func__, bp->unique_id, bp->address); return ERROR_OK; } static int unset_swbp(struct target *t, struct breakpoint *bp) { struct x86_32_common *x86_32 = target_to_x86_32(t); LOG_DEBUG("id %" PRIx32, bp->unique_id); target_addr_t physaddr; uint8_t current_instr; /* check that user program has not modified breakpoint instruction */ if (calcaddr_physfromlin(t, bp->address, &physaddr) != ERROR_OK) return ERROR_FAIL; if (read_phys_mem(t, physaddr, 1, 1, ¤t_instr)) return ERROR_FAIL; if (current_instr == SW_BP_OPCODE) { if (write_phys_mem(t, physaddr, 1, 1, bp->orig_instr)) return ERROR_FAIL; } else { LOG_ERROR("%s software breakpoint remove error at " TARGET_ADDR_FMT ", check memory", __func__, bp->address); LOG_ERROR("%s current=0x%02" PRIx8 " orig=0x%02" PRIx8 "", __func__, current_instr, *bp->orig_instr); return ERROR_FAIL; } /* remove from patch */ struct swbp_mem_patch *iter = x86_32->swbbp_mem_patch_list; if (iter) { if (iter->swbp_unique_id == bp->unique_id) { /* it's the first item */ x86_32->swbbp_mem_patch_list = iter->next; free(iter); } else { while (iter->next && iter->next->swbp_unique_id != bp->unique_id) iter = iter->next; if (iter->next) { /* it's the next one */ struct swbp_mem_patch *freeme = iter->next; iter->next = iter->next->next; free(freeme); } } } LOG_USER("%s software breakpoint %" PRIu32 " removed from " TARGET_ADDR_FMT, __func__, bp->unique_id, bp->address); return ERROR_OK; } static int set_breakpoint(struct target *t, struct breakpoint *bp) { int error = ERROR_OK; struct x86_32_common *x86_32 = target_to_x86_32(t); LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); if (bp->is_set) { LOG_ERROR("breakpoint already set"); return error; } if (bp->type == BKPT_HARD) { error = set_hwbp(t, bp); if (error != ERROR_OK) { LOG_ERROR("%s error setting hardware breakpoint at " TARGET_ADDR_FMT, __func__, bp->address); return error; } } else { if (x86_32->sw_bpts_supported(t)) { error = set_swbp(t, bp); if (error != ERROR_OK) { LOG_ERROR("%s error setting software breakpoint at " TARGET_ADDR_FMT, __func__, bp->address); return error; } } else { LOG_ERROR("%s core doesn't support SW breakpoints", __func__); return ERROR_FAIL; } } return error; } static int unset_breakpoint(struct target *t, struct breakpoint *bp) { LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); if (!bp->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (bp->type == BKPT_HARD) { if (unset_hwbp(t, bp) != ERROR_OK) { LOG_ERROR("%s error removing hardware breakpoint at " TARGET_ADDR_FMT, __func__, bp->address); return ERROR_FAIL; } } else { if (unset_swbp(t, bp) != ERROR_OK) { LOG_ERROR("%s error removing software breakpoint at " TARGET_ADDR_FMT, __func__, bp->address); return ERROR_FAIL; } } bp->is_set = false; return ERROR_OK; } static int set_watchpoint(struct target *t, struct watchpoint *wp) { struct x86_32_common *x86_32 = target_to_x86_32(t); struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list; int wp_num = 0; LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, wp->rw, wp->address); if (wp->is_set) { LOG_ERROR("%s watchpoint already set", __func__); return ERROR_OK; } if (wp->rw == WPT_READ) { LOG_ERROR("%s no support for 'read' watchpoints, use 'access' or 'write'" , __func__); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } while (debug_reg_list[wp_num].used && (wp_num < x86_32->num_hw_bpoints)) wp_num++; if (wp_num >= x86_32->num_hw_bpoints) { LOG_ERROR("%s no debug registers left", __func__); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (wp->length != 4 && wp->length != 2 && wp->length != 1) { LOG_ERROR("%s only watchpoints of length 1, 2 or 4 are supported", __func__); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } switch (wp->rw) { case WPT_WRITE: if (set_debug_regs(t, wp->address, wp_num, DR7_BP_WRITE, wp->length) != ERROR_OK) { return ERROR_FAIL; } break; case WPT_ACCESS: if (set_debug_regs(t, wp->address, wp_num, DR7_BP_READWRITE, wp->length) != ERROR_OK) { return ERROR_FAIL; } break; default: LOG_ERROR("%s only 'access' or 'write' watchpoints are supported", __func__); break; } watchpoint_set(wp, wp_num); debug_reg_list[wp_num].used = 1; debug_reg_list[wp_num].bp_value = wp->address; LOG_USER("'%s' watchpoint %d set at " TARGET_ADDR_FMT " with length %" PRIu32 " (hwreg=%d)", wp->rw == WPT_READ ? "read" : wp->rw == WPT_WRITE ? "write" : wp->rw == WPT_ACCESS ? "access" : "?", wp->unique_id, wp->address, wp->length, wp_num); return ERROR_OK; } static int unset_watchpoint(struct target *t, struct watchpoint *wp) { struct x86_32_common *x86_32 = target_to_x86_32(t); struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list; LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, wp->rw, wp->address); if (!wp->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } int wp_num = wp->number; if (wp_num >= x86_32->num_hw_bpoints) { LOG_DEBUG("Invalid FP Comparator number in watchpoint"); return ERROR_OK; } if (unset_debug_regs(t, wp_num) != ERROR_OK) return ERROR_FAIL; debug_reg_list[wp_num].used = 0; debug_reg_list[wp_num].bp_value = 0; wp->is_set = false; LOG_USER("'%s' watchpoint %d removed from " TARGET_ADDR_FMT " with length %" PRIu32 " (hwreg=%d)", wp->rw == WPT_READ ? "read" : wp->rw == WPT_WRITE ? "write" : wp->rw == WPT_ACCESS ? "access" : "?", wp->unique_id, wp->address, wp->length, wp_num); return ERROR_OK; } /* after reset breakpoints and watchpoints in memory are not valid anymore and * debug registers are cleared. * we can't afford to remove sw breakpoints using the default methods as the * memory doesn't have the same layout yet and an access might crash the target, * so we just clear the openocd breakpoints structures. */ void x86_32_common_reset_breakpoints_watchpoints(struct target *t) { struct x86_32_common *x86_32 = target_to_x86_32(t); struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list; struct breakpoint *next_b; struct watchpoint *next_w; while (t->breakpoints) { next_b = t->breakpoints->next; free(t->breakpoints->orig_instr); free(t->breakpoints); t->breakpoints = next_b; } while (t->watchpoints) { next_w = t->watchpoints->next; free(t->watchpoints); t->watchpoints = next_w; } for (int i = 0; i < x86_32->num_hw_bpoints; i++) { debug_reg_list[i].used = 0; debug_reg_list[i].bp_value = 0; } } static int read_hw_reg_to_cache(struct target *t, int num) { uint32_t reg_value; struct x86_32_common *x86_32 = target_to_x86_32(t); if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; if ((num < 0) || (num >= x86_32->get_num_user_regs(t))) return ERROR_COMMAND_SYNTAX_ERROR; if (x86_32->read_hw_reg(t, num, ®_value, 1) != ERROR_OK) { LOG_ERROR("%s fail for %s", x86_32->cache->reg_list[num].name, __func__); return ERROR_FAIL; } LOG_DEBUG("reg %s value 0x%08" PRIx32, x86_32->cache->reg_list[num].name, reg_value); return ERROR_OK; } static int write_hw_reg_from_cache(struct target *t, int num) { struct x86_32_common *x86_32 = target_to_x86_32(t); if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; if ((num < 0) || (num >= x86_32->get_num_user_regs(t))) return ERROR_COMMAND_SYNTAX_ERROR; if (x86_32->write_hw_reg(t, num, 0, 1) != ERROR_OK) { LOG_ERROR("%s fail for %s", x86_32->cache->reg_list[num].name, __func__); return ERROR_FAIL; } LOG_DEBUG("reg %s value 0x%08" PRIx32, x86_32->cache->reg_list[num].name, buf_get_u32(x86_32->cache->reg_list[num].value, 0, 32)); return ERROR_OK; } /* x86 32 commands */ static void handle_iod_output(struct command_invocation *cmd, struct target *target, uint32_t address, unsigned size, unsigned count, const uint8_t *buffer) { const unsigned line_bytecnt = 32; unsigned line_modulo = line_bytecnt / size; char output[line_bytecnt * 4 + 1]; unsigned output_len = 0; const char *value_fmt; switch (size) { case 4: value_fmt = "%8.8x "; break; case 2: value_fmt = "%4.4x "; break; case 1: value_fmt = "%2.2x "; break; default: /* "can't happen", caller checked */ LOG_ERROR("%s invalid memory read size: %u", __func__, size); return; } for (unsigned i = 0; i < count; i++) { if (i % line_modulo == 0) { output_len += snprintf(output + output_len, sizeof(output) - output_len, "0x%8.8x: ", (unsigned)(address + (i*size))); } uint32_t value = 0; const uint8_t *value_ptr = buffer + i * size; switch (size) { case 4: value = target_buffer_get_u32(target, value_ptr); break; case 2: value = target_buffer_get_u16(target, value_ptr); break; case 1: value = *value_ptr; } output_len += snprintf(output + output_len, sizeof(output) - output_len, value_fmt, value); if ((i % line_modulo == line_modulo - 1) || (i == count - 1)) { command_print(cmd, "%s", output); output_len = 0; } } } COMMAND_HANDLER(handle_iod_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t address; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); if (address > 0xffff) { LOG_ERROR("%s IA-32 I/O space is 2^16, 0x%08" PRIx32 " exceeds max", __func__, address); return ERROR_COMMAND_SYNTAX_ERROR; } unsigned size = 0; switch (CMD_NAME[2]) { case 'w': size = 4; break; case 'h': size = 2; break; case 'b': size = 1; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } unsigned count = 1; uint8_t *buffer = calloc(count, size); struct target *target = get_current_target(CMD_CTX); int retval = x86_32_common_read_io(target, address, size, buffer); if (retval == ERROR_OK) handle_iod_output(CMD, target, address, size, count, buffer); free(buffer); return retval; } static int target_fill_io(struct target *target, uint32_t address, unsigned data_size, /* value */ uint32_t b) { LOG_DEBUG("address=0x%08" PRIx32 ", data_size=%u, b=0x%08" PRIx32, address, data_size, b); uint8_t target_buf[data_size]; switch (data_size) { case 4: target_buffer_set_u32(target, target_buf, b); break; case 2: target_buffer_set_u16(target, target_buf, b); break; case 1: target_buf[0] = (b & 0x0ff); break; default: exit(-1); } return x86_32_common_write_io(target, address, data_size, target_buf); } COMMAND_HANDLER(handle_iow_command) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t address; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); struct target *target = get_current_target(CMD_CTX); unsigned wordsize; switch (CMD_NAME[2]) { case 'w': wordsize = 4; break; case 'h': wordsize = 2; break; case 'b': wordsize = 1; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return target_fill_io(target, address, wordsize, value); } static const struct command_registration x86_32_exec_command_handlers[] = { { .name = "iww", .mode = COMMAND_EXEC, .handler = handle_iow_command, .help = "write I/O port word", .usage = "port data[word]", }, { .name = "iwh", .mode = COMMAND_EXEC, .handler = handle_iow_command, .help = "write I/O port halfword", .usage = "port data[halfword]", }, { .name = "iwb", .mode = COMMAND_EXEC, .handler = handle_iow_command, .help = "write I/O port byte", .usage = "port data[byte]", }, { .name = "idw", .mode = COMMAND_EXEC, .handler = handle_iod_command, .help = "display I/O port word", .usage = "port", }, { .name = "idh", .mode = COMMAND_EXEC, .handler = handle_iod_command, .help = "display I/O port halfword", .usage = "port", }, { .name = "idb", .mode = COMMAND_EXEC, .handler = handle_iod_command, .help = "display I/O port byte", .usage = "port", }, COMMAND_REGISTRATION_DONE }; const struct command_registration x86_32_command_handlers[] = { { .name = "x86_32", .mode = COMMAND_ANY, .help = "x86_32 target commands", .usage = "", .chain = x86_32_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/x86_32_common.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright(c) 2013-2016 Intel Corporation. * * Adrian Burns (adrian.burns@intel.com) * Thomas Faust (thomas.faust@intel.com) * Ivan De Cesaris (ivan.de.cesaris@intel.com) * Julien Carreno (julien.carreno@intel.com) * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com) * * Contact Information: * Intel Corporation */ /* * @file * This is the interface to the x86 32 bit memory and breakpoint operations. */ #ifndef OPENOCD_TARGET_X86_32_COMMON_H #define OPENOCD_TARGET_X86_32_COMMON_H #include <jtag/jtag.h> #include <helper/command.h> #include <helper/types.h> extern const struct command_registration x86_32_command_handlers[]; /* for memory access */ #define BYTE 1 #define WORD 2 #define DWORD 4 #define EFLAGS_TF ((uint32_t)0x00000100) /* Trap Flag */ #define EFLAGS_IF ((uint32_t)0x00000200) /* Interrupt Flag */ #define EFLAGS_RF ((uint32_t)0x00010000) /* Resume Flag */ #define EFLAGS_VM86 ((uint32_t)0x00020000) /* Virtual 8086 Mode */ #define CSAR_DPL ((uint32_t)0x00006000) #define CSAR_D ((uint32_t)0x00400000) #define SSAR_DPL ((uint32_t)0x00006000) #define CR0_PE ((uint32_t)0x00000001) /* Protected Mode Enable */ #define CR0_NW ((uint32_t)0x20000000) /* Non Write-Through */ #define CR0_CD ((uint32_t)0x40000000) /* Cache Disable */ #define CR0_PG ((uint32_t)0x80000000) /* Paging Enable */ /* TODO - move back to PM specific file */ #define PM_DR6 ((uint32_t)0xFFFF0FF0) #define DR6_BRKDETECT_0 ((uint32_t)0x00000001) /* B0 through B3 */ #define DR6_BRKDETECT_1 ((uint32_t)0x00000002) /* breakpoint condition detected */ #define DR6_BRKDETECT_2 ((uint32_t)0x00000004) #define DR6_BRKDETECT_3 ((uint32_t)0x00000008) enum { /* general purpose registers */ EAX = 0, ECX, EDX, EBX, ESP, EBP, ESI, EDI, /* instruction pointer & flags */ EIP, EFLAGS, /* segment registers */ CS, SS, DS, ES, FS, GS, /* floating point unit registers */ ST0, ST1, ST2, ST3, ST4, ST5, ST6, ST7, FCTRL, FSTAT, FTAG, FISEG, FIOFF, FOSEG, FOOFF, FOP, /* control registers */ CR0, CR2, CR3, CR4, /* debug registers */ DR0, DR1, DR2, DR3, DR6, DR7, /* descriptor tables */ IDTB, IDTL, IDTAR, GDTB, GDTL, GDTAR, TR, LDTR, LDTB, LDTL, LDTAR, /* segment registers */ CSB, CSL, CSAR, DSB, DSL, DSAR, ESB, ESL, ESAR, FSB, FSL, FSAR, GSB, GSL, GSAR, SSB, SSL, SSAR, TSSB, TSSL, TSSAR, /* PM control reg */ PMCR, }; #define X86_32_COMMON_MAGIC 0x86328632U enum { /* memory read/write */ MEMRDB32 = 0, MEMRDB16, MEMRDH32, MEMRDH16, MEMRDW32, MEMRDW16, MEMWRB32, MEMWRB16, MEMWRH32, MEMWRH16, MEMWRW32, MEMWRW16, /* IO read/write */ IORDB32, IORDB16, IORDH32, IORDH16, IORDW32, IORDW16, IOWRB32, IOWRB16, IOWRH32, IOWRH16, IOWRW32, IOWRW16, /* lakemont1 core shadow ram access opcodes */ SRAMACCESS, SRAM2PDR, PDR2SRAM, WBINVD, }; enum x86_core_type { LMT1, LMT3_5 }; struct swbp_mem_patch { uint8_t orig_byte; uint32_t swbp_unique_id; uint32_t physaddr; struct swbp_mem_patch *next; }; /* TODO - probemode specific - consider removing */ #define NUM_PM_REGS 18 /* regs used in save/restore */ struct x86_32_common { unsigned int common_magic; void *arch_info; enum x86_core_type core_type; struct reg_cache *cache; struct jtag_tap *curr_tap; uint32_t stored_pc; int forced_halt_for_reset; int flush; /* pm_regs are for probemode save/restore state */ uint32_t pm_regs[NUM_PM_REGS]; /* working area for fastdata access */ struct working_area *fast_data_area; int num_hw_bpoints; struct x86_32_dbg_reg *hw_break_list; struct swbp_mem_patch *swbbp_mem_patch_list; /* core probemode implementation dependent functions */ uint8_t (*get_num_user_regs)(struct target *t); bool (*is_paging_enabled)(struct target *t); int (*disable_paging)(struct target *t); int (*enable_paging)(struct target *t); bool (*sw_bpts_supported)(struct target *t); int (*transaction_status)(struct target *t); int (*submit_instruction)(struct target *t, int num); int (*read_hw_reg)(struct target *t, int reg, uint32_t *regval, uint8_t cache); int (*write_hw_reg)(struct target *t, int reg, uint32_t regval, uint8_t cache); /* register cache to processor synchronization */ int (*read_hw_reg_to_cache)(struct target *target, int num); int (*write_hw_reg_from_cache)(struct target *target, int num); }; static inline struct x86_32_common * target_to_x86_32(struct target *target) { return target->arch_info; } bool check_not_halted(const struct target *t); /* breakpoint defines */ #define MAX_DEBUG_REGS 4 #define SW_BP_OPCODE 0xf1 #define MAX_SW_BPTS 20 struct x86_32_dbg_reg { int used; uint32_t bp_value; }; #define DR7_G_ENABLE_SHIFT 1 #define DR7_ENABLE_SIZE 2 /* 2 bits per debug reg */ #define DR7_RW_SHIFT 16 #define DR7_LENGTH_SHIFT 18 #define DR7_RW_LEN_SIZE 4 #define DR7_BP_EXECUTE 0 /* 00 - only on instruction execution*/ #define DR7_BP_WRITE 1 /* 01 - only on data writes */ /*#define DR7_RW_IORW 2 UNSUPPORTED 10 - an I/O read and I/O write */ #define DR7_BP_READWRITE 3 /* on data read or data write */ #define DR7_BP_LENGTH_1 0 /* 00 - 1 byte length */ #define DR7_BP_LENGTH_2 1 /* 01 - 2 byte length */ #define DR7_BP_LENGTH_4 3 /* 11 - 4 byte length */ #define DR7_GLOBAL_ENABLE(val, regnum) \ (val |= (1 << (DR7_G_ENABLE_SHIFT + (DR7_ENABLE_SIZE * (regnum))))) #define DR7_GLOBAL_DISABLE(val, regnum) \ (val &= ~(3 << (DR7_ENABLE_SIZE * (regnum)))) #define DR7_BP_FREE(val, regnum) \ ((val & (3 << (DR7_ENABLE_SIZE * (regnum)))) == 0) #define DR7_RESET_RWLEN_BITS(val, regnum) \ (val &= ~(0x0f << (DR7_RW_SHIFT + DR7_RW_LEN_SIZE * (regnum)))) #define DR7_SET_EXE(val, regnum) \ (val &= ~(0x0f << (DR7_RW_SHIFT + DR7_RW_LEN_SIZE * (regnum)))) #define DR7_SET_WRITE(val, regnum) \ (val |= (DR7_BP_WRITE << (DR7_RW_SHIFT + DR7_RW_LEN_SIZE * (regnum)))) #define DR7_SET_ACCESS(val, regnum) \ (val |= (DR7_BP_READWRITE << (DR7_RW_SHIFT + DR7_RW_LEN_SIZE * (regnum)))) #define DR7_SET_LENGTH(val, regnum, len) \ (val |= (len == 1) ? (DR7_BP_LENGTH_1 << (DR7_LENGTH_SHIFT + DR7_RW_LEN_SIZE * (regnum))) : \ (len == 2) ? (DR7_BP_LENGTH_2 << (DR7_LENGTH_SHIFT + DR7_RW_LEN_SIZE * (regnum))) : \ (DR7_BP_LENGTH_4 << (DR7_LENGTH_SHIFT + DR7_RW_LEN_SIZE * (regnum)))) /* public interface */ int x86_32_get_gdb_reg_list(struct target *t, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); int x86_32_common_init_arch_info(struct target *target, struct x86_32_common *x86_32); int x86_32_common_mmu(struct target *t, int *enabled); int x86_32_common_virt2phys(struct target *t, target_addr_t address, target_addr_t *physical); int x86_32_common_read_phys_mem(struct target *t, target_addr_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer); int x86_32_common_write_phys_mem(struct target *t, target_addr_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer); int x86_32_common_read_memory(struct target *t, target_addr_t addr, uint32_t size, uint32_t count, uint8_t *buf); int x86_32_common_write_memory(struct target *t, target_addr_t addr, uint32_t size, uint32_t count, const uint8_t *buf); int x86_32_common_read_io(struct target *t, uint32_t addr, uint32_t size, uint8_t *buf); int x86_32_common_write_io(struct target *t, uint32_t addr, uint32_t size, const uint8_t *buf); int x86_32_common_add_breakpoint(struct target *t, struct breakpoint *bp); int x86_32_common_remove_breakpoint(struct target *t, struct breakpoint *bp); int x86_32_common_add_watchpoint(struct target *t, struct watchpoint *wp); int x86_32_common_remove_watchpoint(struct target *t, struct watchpoint *wp); void x86_32_common_reset_breakpoints_watchpoints(struct target *t); #endif /* OPENOCD_TARGET_X86_32_COMMON_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/xscale.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2006, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 Michael Schwingen * * michael@schwingen.org * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "breakpoints.h" #include "xscale.h" #include "target_type.h" #include "arm_jtag.h" #include "arm_simulator.h" #include "arm_disassembler.h" #include <helper/time_support.h> #include "register.h" #include "image.h" #include "arm_opcodes.h" #include "armv4_5.h" /* * Important XScale documents available as of October 2009 include: * * Intel XScale® Core Developer’s Manual, January 2004 * Order Number: 273473-002 * This has a chapter detailing debug facilities, and punts some * details to chip-specific microarchitecture documents. * * Hot-Debug for Intel XScale® Core Debug White Paper, May 2005 * Document Number: 273539-005 * Less detailed than the developer's manual, but summarizes those * missing details (for most XScales) and gives LOTS of notes about * debugger/handler interaction issues. Presents a simpler reset * and load-handler sequence than the arch doc. (Note, OpenOCD * doesn't currently support "Hot-Debug" as defined there.) * * Chip-specific microarchitecture documents may also be useful. */ /* forward declarations */ static int xscale_resume(struct target *, int current, target_addr_t address, int handle_breakpoints, int debug_execution); static int xscale_debug_entry(struct target *); static int xscale_restore_banked(struct target *); static int xscale_get_reg(struct reg *reg); static int xscale_set_reg(struct reg *reg, uint8_t *buf); static int xscale_set_breakpoint(struct target *, struct breakpoint *); static int xscale_set_watchpoint(struct target *, struct watchpoint *); static int xscale_unset_breakpoint(struct target *, struct breakpoint *); static int xscale_read_trace(struct target *); /* This XScale "debug handler" is loaded into the processor's * mini-ICache, which is 2K of code writable only via JTAG. */ static const uint8_t xscale_debug_handler[] = { #include "../../contrib/loaders/debug/xscale/debug_handler.inc" }; static const char *const xscale_reg_list[] = { "XSCALE_MAINID", /* 0 */ "XSCALE_CACHETYPE", "XSCALE_CTRL", "XSCALE_AUXCTRL", "XSCALE_TTB", "XSCALE_DAC", "XSCALE_FSR", "XSCALE_FAR", "XSCALE_PID", "XSCALE_CPACCESS", "XSCALE_IBCR0", /* 10 */ "XSCALE_IBCR1", "XSCALE_DBR0", "XSCALE_DBR1", "XSCALE_DBCON", "XSCALE_TBREG", "XSCALE_CHKPT0", "XSCALE_CHKPT1", "XSCALE_DCSR", "XSCALE_TX", "XSCALE_RX", /* 20 */ "XSCALE_TXRXCTRL", }; static const struct xscale_reg xscale_reg_arch_info[] = { {XSCALE_MAINID, NULL}, {XSCALE_CACHETYPE, NULL}, {XSCALE_CTRL, NULL}, {XSCALE_AUXCTRL, NULL}, {XSCALE_TTB, NULL}, {XSCALE_DAC, NULL}, {XSCALE_FSR, NULL}, {XSCALE_FAR, NULL}, {XSCALE_PID, NULL}, {XSCALE_CPACCESS, NULL}, {XSCALE_IBCR0, NULL}, {XSCALE_IBCR1, NULL}, {XSCALE_DBR0, NULL}, {XSCALE_DBR1, NULL}, {XSCALE_DBCON, NULL}, {XSCALE_TBREG, NULL}, {XSCALE_CHKPT0, NULL}, {XSCALE_CHKPT1, NULL}, {XSCALE_DCSR, NULL}, /* DCSR accessed via JTAG or SW */ {-1, NULL}, /* TX accessed via JTAG */ {-1, NULL}, /* RX accessed via JTAG */ {-1, NULL}, /* TXRXCTRL implicit access via JTAG */ }; /* convenience wrapper to access XScale specific registers */ static int xscale_set_reg_u32(struct reg *reg, uint32_t value) { uint8_t buf[4] = { 0 }; buf_set_u32(buf, 0, 32, value); return xscale_set_reg(reg, buf); } static const char xscale_not[] = "target is not an XScale"; static int xscale_verify_pointer(struct command_invocation *cmd, struct xscale_common *xscale) { if (xscale->common_magic != XSCALE_COMMON_MAGIC) { command_print(cmd, xscale_not); return ERROR_TARGET_INVALID; } return ERROR_OK; } static int xscale_jtag_set_instr(struct jtag_tap *tap, uint32_t new_instr, tap_state_t end_state) { assert(tap); if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; uint8_t scratch[4] = { 0 }; memset(&field, 0, sizeof(field)); field.num_bits = tap->ir_length; field.out_value = scratch; buf_set_u32(scratch, 0, field.num_bits, new_instr); jtag_add_ir_scan(tap, &field, end_state); } return ERROR_OK; } static int xscale_read_dcsr(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); int retval; struct scan_field fields[3]; uint8_t field0 = 0x0; uint8_t field0_check_value = 0x2; uint8_t field0_check_mask = 0x7; uint8_t field2 = 0x0; uint8_t field2_check_value = 0x0; uint8_t field2_check_mask = 0x1; xscale_jtag_set_instr(target->tap, XSCALE_SELDCSR << xscale->xscale_variant, TAP_DRPAUSE); buf_set_u32(&field0, 1, 1, xscale->hold_rst); buf_set_u32(&field0, 2, 1, xscale->external_debug_break); memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; fields[0].out_value = &field0; uint8_t tmp; fields[0].in_value = &tmp; fields[1].num_bits = 32; fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; fields[2].num_bits = 1; fields[2].out_value = &field2; uint8_t tmp2; fields[2].in_value = &tmp2; jtag_add_dr_scan(target->tap, 3, fields, TAP_DRPAUSE); jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask); jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while reading DCSR"); return retval; } xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = false; xscale->reg_cache->reg_list[XSCALE_DCSR].valid = true; /* write the register with the value we just read * on this second pass, only the first bit of field0 is guaranteed to be 0) */ field0_check_mask = 0x1; fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; fields[1].in_value = NULL; jtag_add_dr_scan(target->tap, 3, fields, TAP_DRPAUSE); /* DANGER!!! this must be here. It will make sure that the arguments * to jtag_set_check_value() does not go out of scope! */ return jtag_execute_queue(); } static void xscale_getbuf(jtag_callback_data_t arg) { uint8_t *in = (uint8_t *)arg; *((uint32_t *)arg) = buf_get_u32(in, 0, 32); } static int xscale_receive(struct target *target, uint32_t *buffer, int num_words) { if (num_words == 0) return ERROR_COMMAND_SYNTAX_ERROR; struct xscale_common *xscale = target_to_xscale(target); int retval = ERROR_OK; tap_state_t path[3]; struct scan_field fields[3]; uint8_t *field0 = malloc(num_words * 1); uint8_t field0_check_value = 0x2; uint8_t field0_check_mask = 0x6; uint32_t *field1 = malloc(num_words * 4); uint8_t field2_check_value = 0x0; uint8_t field2_check_mask = 0x1; int words_done = 0; int words_scheduled = 0; int i; path[0] = TAP_DRSELECT; path[1] = TAP_DRCAPTURE; path[2] = TAP_DRSHIFT; memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; uint8_t tmp; fields[0].in_value = &tmp; fields[0].check_value = &field0_check_value; fields[0].check_mask = &field0_check_mask; fields[1].num_bits = 32; fields[2].num_bits = 1; uint8_t tmp2; fields[2].in_value = &tmp2; fields[2].check_value = &field2_check_value; fields[2].check_mask = &field2_check_mask; xscale_jtag_set_instr(target->tap, XSCALE_DBGTX << xscale->xscale_variant, TAP_IDLE); jtag_add_runtest(1, TAP_IDLE); /* ensures that we're in the TAP_IDLE state as the above *could be a no-op */ /* repeat until all words have been collected */ int attempts = 0; while (words_done < num_words) { /* schedule reads */ words_scheduled = 0; for (i = words_done; i < num_words; i++) { fields[0].in_value = &field0[i]; jtag_add_pathmove(3, path); fields[1].in_value = (uint8_t *)(field1 + i); jtag_add_dr_scan_check(target->tap, 3, fields, TAP_IDLE); jtag_add_callback(xscale_getbuf, (jtag_callback_data_t)(field1 + i)); words_scheduled++; } retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while receiving data from debug handler"); break; } /* examine results */ for (i = words_done; i < num_words; i++) { if (!(field0[i] & 1)) { /* move backwards if necessary */ int j; for (j = i; j < num_words - 1; j++) { field0[j] = field0[j + 1]; field1[j] = field1[j + 1]; } words_scheduled--; } } if (words_scheduled == 0) { if (attempts++ == 1000) { LOG_ERROR( "Failed to receiving data from debug handler after 1000 attempts"); retval = ERROR_TARGET_TIMEOUT; break; } } words_done += words_scheduled; } for (i = 0; i < num_words; i++) *(buffer++) = buf_get_u32((uint8_t *)&field1[i], 0, 32); free(field1); return retval; } static int xscale_read_tx(struct target *target, int consume) { struct xscale_common *xscale = target_to_xscale(target); tap_state_t path[3]; tap_state_t noconsume_path[6]; int retval; struct timeval timeout, now; struct scan_field fields[3]; uint8_t field0_in = 0x0; uint8_t field0_check_value = 0x2; uint8_t field0_check_mask = 0x6; uint8_t field2_check_value = 0x0; uint8_t field2_check_mask = 0x1; xscale_jtag_set_instr(target->tap, XSCALE_DBGTX << xscale->xscale_variant, TAP_IDLE); path[0] = TAP_DRSELECT; path[1] = TAP_DRCAPTURE; path[2] = TAP_DRSHIFT; noconsume_path[0] = TAP_DRSELECT; noconsume_path[1] = TAP_DRCAPTURE; noconsume_path[2] = TAP_DREXIT1; noconsume_path[3] = TAP_DRPAUSE; noconsume_path[4] = TAP_DREXIT2; noconsume_path[5] = TAP_DRSHIFT; memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; fields[0].in_value = &field0_in; fields[1].num_bits = 32; fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_TX].value; fields[2].num_bits = 1; uint8_t tmp; fields[2].in_value = &tmp; gettimeofday(&timeout, NULL); timeval_add_time(&timeout, 1, 0); for (;; ) { /* if we want to consume the register content (i.e. clear TX_READY), * we have to go straight from Capture-DR to Shift-DR * otherwise, we go from Capture-DR to Exit1-DR to Pause-DR */ if (consume) jtag_add_pathmove(3, path); else jtag_add_pathmove(ARRAY_SIZE(noconsume_path), noconsume_path); jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE); jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask); jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while reading TX"); return ERROR_TARGET_TIMEOUT; } gettimeofday(&now, NULL); if (timeval_compare(&now, &timeout) > 0) { LOG_ERROR("time out reading TX register"); return ERROR_TARGET_TIMEOUT; } if (!((!(field0_in & 1)) && consume)) goto done; if (debug_level >= 3) { LOG_DEBUG("waiting 100ms"); alive_sleep(100); /* avoid flooding the logs */ } else keep_alive(); } done: if (!(field0_in & 1)) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; return ERROR_OK; } static int xscale_write_rx(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); int retval; struct timeval timeout, now; struct scan_field fields[3]; uint8_t field0_out = 0x0; uint8_t field0_in = 0x0; uint8_t field0_check_value = 0x2; uint8_t field0_check_mask = 0x6; uint8_t field2 = 0x0; uint8_t field2_check_value = 0x0; uint8_t field2_check_mask = 0x1; xscale_jtag_set_instr(target->tap, XSCALE_DBGRX << xscale->xscale_variant, TAP_IDLE); memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; fields[0].out_value = &field0_out; fields[0].in_value = &field0_in; fields[1].num_bits = 32; fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_RX].value; fields[2].num_bits = 1; fields[2].out_value = &field2; uint8_t tmp; fields[2].in_value = &tmp; gettimeofday(&timeout, NULL); timeval_add_time(&timeout, 1, 0); /* poll until rx_read is low */ LOG_DEBUG("polling RX"); for (;;) { jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE); jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask); jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while writing RX"); return retval; } gettimeofday(&now, NULL); if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec > timeout.tv_usec))) { LOG_ERROR("time out writing RX register"); return ERROR_TARGET_TIMEOUT; } if (!(field0_in & 1)) goto done; if (debug_level >= 3) { LOG_DEBUG("waiting 100ms"); alive_sleep(100); /* avoid flooding the logs */ } else keep_alive(); } done: /* set rx_valid */ field2 = 0x1; jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while writing RX"); return retval; } return ERROR_OK; } /* send count elements of size byte to the debug handler */ static int xscale_send(struct target *target, const uint8_t *buffer, int count, int size) { struct xscale_common *xscale = target_to_xscale(target); int retval; int done_count = 0; xscale_jtag_set_instr(target->tap, XSCALE_DBGRX << xscale->xscale_variant, TAP_IDLE); static const uint8_t t0; uint8_t t1[4] = { 0 }; static const uint8_t t2 = 1; struct scan_field fields[3] = { { .num_bits = 3, .out_value = &t0 }, { .num_bits = 32, .out_value = t1 }, { .num_bits = 1, .out_value = &t2 }, }; int endianness = target->endianness; while (done_count++ < count) { uint32_t t; switch (size) { case 4: if (endianness == TARGET_LITTLE_ENDIAN) t = le_to_h_u32(buffer); else t = be_to_h_u32(buffer); break; case 2: if (endianness == TARGET_LITTLE_ENDIAN) t = le_to_h_u16(buffer); else t = be_to_h_u16(buffer); break; case 1: t = buffer[0]; break; default: LOG_ERROR("BUG: size neither 4, 2 nor 1"); return ERROR_COMMAND_SYNTAX_ERROR; } buf_set_u32(t1, 0, 32, t); jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE); buffer += size; } retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while sending data to debug handler"); return retval; } return ERROR_OK; } static int xscale_send_u32(struct target *target, uint32_t value) { struct xscale_common *xscale = target_to_xscale(target); buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value); return xscale_write_rx(target); } static int xscale_write_dcsr(struct target *target, int hold_rst, int ext_dbg_brk) { struct xscale_common *xscale = target_to_xscale(target); int retval; struct scan_field fields[3]; uint8_t field0 = 0x0; uint8_t field0_check_value = 0x2; uint8_t field0_check_mask = 0x7; uint8_t field2 = 0x0; uint8_t field2_check_value = 0x0; uint8_t field2_check_mask = 0x1; if (hold_rst != -1) xscale->hold_rst = hold_rst; if (ext_dbg_brk != -1) xscale->external_debug_break = ext_dbg_brk; xscale_jtag_set_instr(target->tap, XSCALE_SELDCSR << xscale->xscale_variant, TAP_IDLE); buf_set_u32(&field0, 1, 1, xscale->hold_rst); buf_set_u32(&field0, 2, 1, xscale->external_debug_break); memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; fields[0].out_value = &field0; uint8_t tmp; fields[0].in_value = &tmp; fields[1].num_bits = 32; fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; fields[2].num_bits = 1; fields[2].out_value = &field2; uint8_t tmp2; fields[2].in_value = &tmp2; jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE); jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask); jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while writing DCSR"); return retval; } xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = false; xscale->reg_cache->reg_list[XSCALE_DCSR].valid = true; return ERROR_OK; } /* parity of the number of bits 0 if even; 1 if odd. for 32 bit words */ static unsigned int parity(unsigned int v) { /* unsigned int ov = v; */ v ^= v >> 16; v ^= v >> 8; v ^= v >> 4; v &= 0xf; /* LOG_DEBUG("parity of 0x%x is %i", ov, (0x6996 >> v) & 1); */ return (0x6996 >> v) & 1; } static int xscale_load_ic(struct target *target, uint32_t va, uint32_t buffer[8]) { struct xscale_common *xscale = target_to_xscale(target); uint8_t packet[4] = { 0 }; uint8_t cmd = 0; int word; struct scan_field fields[2]; LOG_DEBUG("loading miniIC at 0x%8.8" PRIx32 "", va); /* LDIC into IR */ xscale_jtag_set_instr(target->tap, XSCALE_LDIC << xscale->xscale_variant, TAP_IDLE); /* CMD is b011 to load a cacheline into the Mini ICache. * Loading into the main ICache is deprecated, and unused. * It's followed by three zero bits, and 27 address bits. */ buf_set_u32(&cmd, 0, 6, 0x3); /* virtual address of desired cache line */ buf_set_u32(packet, 0, 27, va >> 5); memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 6; fields[0].out_value = &cmd; fields[1].num_bits = 27; fields[1].out_value = packet; jtag_add_dr_scan(target->tap, 2, fields, TAP_IDLE); /* rest of packet is a cacheline: 8 instructions, with parity */ fields[0].num_bits = 32; fields[0].out_value = packet; fields[1].num_bits = 1; fields[1].out_value = &cmd; for (word = 0; word < 8; word++) { buf_set_u32(packet, 0, 32, buffer[word]); uint32_t value; memcpy(&value, packet, sizeof(uint32_t)); cmd = parity(value); jtag_add_dr_scan(target->tap, 2, fields, TAP_IDLE); } return jtag_execute_queue(); } static int xscale_invalidate_ic_line(struct target *target, uint32_t va) { struct xscale_common *xscale = target_to_xscale(target); uint8_t packet[4] = { 0 }; uint8_t cmd = 0; struct scan_field fields[2]; xscale_jtag_set_instr(target->tap, XSCALE_LDIC << xscale->xscale_variant, TAP_IDLE); /* CMD for invalidate IC line b000, bits [6:4] b000 */ buf_set_u32(&cmd, 0, 6, 0x0); /* virtual address of desired cache line */ buf_set_u32(packet, 0, 27, va >> 5); memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 6; fields[0].out_value = &cmd; fields[1].num_bits = 27; fields[1].out_value = packet; jtag_add_dr_scan(target->tap, 2, fields, TAP_IDLE); return ERROR_OK; } static int xscale_update_vectors(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); int i; int retval; uint32_t low_reset_branch, high_reset_branch; for (i = 1; i < 8; i++) { /* if there's a static vector specified for this exception, override */ if (xscale->static_high_vectors_set & (1 << i)) xscale->high_vectors[i] = xscale->static_high_vectors[i]; else { retval = target_read_u32(target, 0xffff0000 + 4*i, &xscale->high_vectors[i]); if (retval == ERROR_TARGET_TIMEOUT) return retval; if (retval != ERROR_OK) { /* Some of these reads will fail as part of normal execution */ xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0); } } } for (i = 1; i < 8; i++) { if (xscale->static_low_vectors_set & (1 << i)) xscale->low_vectors[i] = xscale->static_low_vectors[i]; else { retval = target_read_u32(target, 0x0 + 4*i, &xscale->low_vectors[i]); if (retval == ERROR_TARGET_TIMEOUT) return retval; if (retval != ERROR_OK) { /* Some of these reads will fail as part of normal execution */ xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0); } } } /* calculate branches to debug handler */ low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2; high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2; xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0); xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0); /* invalidate and load exception vectors in mini i-cache */ xscale_invalidate_ic_line(target, 0x0); xscale_invalidate_ic_line(target, 0xffff0000); xscale_load_ic(target, 0x0, xscale->low_vectors); xscale_load_ic(target, 0xffff0000, xscale->high_vectors); return ERROR_OK; } static int xscale_arch_state(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; static const char *state[] = { "disabled", "enabled" }; static const char *arch_dbg_reason[] = { "", "\n(processor reset)", "\n(trace buffer full)" }; if (arm->common_magic != ARM_COMMON_MAGIC) { LOG_ERROR("BUG: called for a non-ARMv4/5 target"); return ERROR_COMMAND_SYNTAX_ERROR; } arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s%s", state[xscale->armv4_5_mmu.mmu_enabled], state[xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], state[xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled], arch_dbg_reason[xscale->arch_debug_reason]); return ERROR_OK; } static int xscale_poll(struct target *target) { int retval = ERROR_OK; if ((target->state == TARGET_RUNNING) || (target->state == TARGET_DEBUG_RUNNING)) { enum target_state previous_state = target->state; retval = xscale_read_tx(target, 0); if (retval == ERROR_OK) { /* there's data to read from the tx register, we entered debug state */ target->state = TARGET_HALTED; /* process debug entry, fetching current mode regs */ retval = xscale_debug_entry(target); } else if (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { LOG_USER("error while polling TX register, reset CPU"); /* here we "lie" so GDB won't get stuck and a reset can be performed */ target->state = TARGET_HALTED; } /* debug_entry could have overwritten target state (i.e. immediate resume) * don't signal event handlers in that case */ if (target->state != TARGET_HALTED) return ERROR_OK; /* if target was running, signal that we halted * otherwise we reentered from debug execution */ if (previous_state == TARGET_RUNNING) target_call_event_callbacks(target, TARGET_EVENT_HALTED); else target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } return retval; } static int xscale_debug_entry(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; uint32_t pc; uint32_t buffer[10]; unsigned i; int retval; uint32_t moe; /* clear external dbg break (will be written on next DCSR read) */ xscale->external_debug_break = 0; retval = xscale_read_dcsr(target); if (retval != ERROR_OK) return retval; /* get r0, pc, r1 to r7 and cpsr */ retval = xscale_receive(target, buffer, 10); if (retval != ERROR_OK) return retval; /* move r0 from buffer to register cache */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, buffer[0]); arm->core_cache->reg_list[0].dirty = true; arm->core_cache->reg_list[0].valid = true; LOG_DEBUG("r0: 0x%8.8" PRIx32 "", buffer[0]); /* move pc from buffer to register cache */ buf_set_u32(arm->pc->value, 0, 32, buffer[1]); arm->pc->dirty = true; arm->pc->valid = true; LOG_DEBUG("pc: 0x%8.8" PRIx32 "", buffer[1]); /* move data from buffer to register cache */ for (i = 1; i <= 7; i++) { buf_set_u32(arm->core_cache->reg_list[i].value, 0, 32, buffer[1 + i]); arm->core_cache->reg_list[i].dirty = true; arm->core_cache->reg_list[i].valid = true; LOG_DEBUG("r%i: 0x%8.8" PRIx32 "", i, buffer[i + 1]); } arm_set_cpsr(arm, buffer[9]); LOG_DEBUG("cpsr: 0x%8.8" PRIx32 "", buffer[9]); if (!is_arm_mode(arm->core_mode)) { target->state = TARGET_UNKNOWN; LOG_ERROR("cpsr contains invalid mode value - communication failure"); return ERROR_TARGET_FAILURE; } LOG_DEBUG("target entered debug state in %s mode", arm_mode_name(arm->core_mode)); /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */ if (arm->spsr) { xscale_receive(target, buffer, 8); buf_set_u32(arm->spsr->value, 0, 32, buffer[7]); arm->spsr->dirty = false; arm->spsr->valid = true; } else { /* r8 to r14, but no spsr */ xscale_receive(target, buffer, 7); } /* move data from buffer to right banked register in cache */ for (i = 8; i <= 14; i++) { struct reg *r = arm_reg_current(arm, i); buf_set_u32(r->value, 0, 32, buffer[i - 8]); r->dirty = false; r->valid = true; } /* mark xscale regs invalid to ensure they are retrieved from the * debug handler if requested */ for (i = 0; i < xscale->reg_cache->num_regs; i++) xscale->reg_cache->reg_list[i].valid = false; /* examine debug reason */ xscale_read_dcsr(target); moe = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 2, 3); /* stored PC (for calculating fixup) */ pc = buf_get_u32(arm->pc->value, 0, 32); switch (moe) { case 0x0: /* Processor reset */ target->debug_reason = DBG_REASON_DBGRQ; xscale->arch_debug_reason = XSCALE_DBG_REASON_RESET; pc -= 4; break; case 0x1: /* Instruction breakpoint hit */ target->debug_reason = DBG_REASON_BREAKPOINT; xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; pc -= 4; break; case 0x2: /* Data breakpoint hit */ target->debug_reason = DBG_REASON_WATCHPOINT; xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; pc -= 4; break; case 0x3: /* BKPT instruction executed */ target->debug_reason = DBG_REASON_BREAKPOINT; xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; pc -= 4; break; case 0x4: /* Ext. debug event */ target->debug_reason = DBG_REASON_DBGRQ; xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; pc -= 4; break; case 0x5: /* Vector trap occurred */ target->debug_reason = DBG_REASON_BREAKPOINT; xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; pc -= 4; break; case 0x6: /* Trace buffer full break */ target->debug_reason = DBG_REASON_DBGRQ; xscale->arch_debug_reason = XSCALE_DBG_REASON_TB_FULL; pc -= 4; break; case 0x7: /* Reserved (may flag Hot-Debug support) */ default: LOG_ERROR("Method of Entry is 'Reserved'"); exit(-1); break; } /* apply PC fixup */ buf_set_u32(arm->pc->value, 0, 32, pc); /* on the first debug entry, identify cache type */ if (xscale->armv4_5_mmu.armv4_5_cache.ctype == -1) { uint32_t cache_type_reg; /* read cp15 cache type register */ xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CACHETYPE]); cache_type_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CACHETYPE].value, 0, 32); armv4_5_identify_cache(cache_type_reg, &xscale->armv4_5_mmu.armv4_5_cache); } /* examine MMU and Cache settings * read cp15 control register */ xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); xscale->cp15_control_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); xscale->armv4_5_mmu.mmu_enabled = (xscale->cp15_control_reg & 0x1U) ? 1 : 0; xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (xscale->cp15_control_reg & 0x4U) ? 1 : 0; xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (xscale->cp15_control_reg & 0x1000U) ? 1 : 0; /* tracing enabled, read collected trace data */ if (xscale->trace.mode != XSCALE_TRACE_DISABLED) { xscale_read_trace(target); /* Resume if entered debug due to buffer fill and we're still collecting * trace data. Note that a debug exception due to trace buffer full * can only happen in fill mode. */ if (xscale->arch_debug_reason == XSCALE_DBG_REASON_TB_FULL) { if (--xscale->trace.fill_counter > 0) xscale_resume(target, 1, 0x0, 1, 0); } else /* entered debug for other reason; reset counter */ xscale->trace.fill_counter = 0; } return ERROR_OK; } static int xscale_halt(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } else if (target->state == TARGET_UNKNOWN) { /* this must not happen for a xscale target */ LOG_ERROR("target was in unknown state when halt was requested"); return ERROR_TARGET_INVALID; } else if (target->state == TARGET_RESET) LOG_DEBUG("target->state == TARGET_RESET"); else { /* assert external dbg break */ xscale->external_debug_break = 1; xscale_read_dcsr(target); target->debug_reason = DBG_REASON_DBGRQ; } return ERROR_OK; } static int xscale_enable_single_step(struct target *target, uint32_t next_pc) { struct xscale_common *xscale = target_to_xscale(target); struct reg *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0]; int retval; if (xscale->ibcr0_used) { struct breakpoint *ibcr0_bp = breakpoint_find(target, buf_get_u32(ibcr0->value, 0, 32) & 0xfffffffe); if (ibcr0_bp) xscale_unset_breakpoint(target, ibcr0_bp); else { LOG_ERROR( "BUG: xscale->ibcr0_used is set, but no breakpoint with that address found"); exit(-1); } } retval = xscale_set_reg_u32(ibcr0, next_pc | 0x1); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int xscale_disable_single_step(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); struct reg *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0]; int retval; retval = xscale_set_reg_u32(ibcr0, 0x0); if (retval != ERROR_OK) return retval; return ERROR_OK; } static void xscale_enable_watchpoints(struct target *target) { struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { if (!watchpoint->is_set) xscale_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } } static void xscale_enable_breakpoints(struct target *target) { struct breakpoint *breakpoint = target->breakpoints; /* set any pending breakpoints */ while (breakpoint) { if (!breakpoint->is_set) xscale_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } } static void xscale_free_trace_data(struct xscale_common *xscale) { struct xscale_trace_data *td = xscale->trace.data; while (td) { struct xscale_trace_data *next_td = td->next; free(td->entries); free(td); td = next_td; } xscale->trace.data = NULL; } static int xscale_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; uint32_t current_pc; int retval; int i; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) target_free_all_working_areas(target); /* update vector tables */ retval = xscale_update_vectors(target); if (retval != ERROR_OK) return retval; /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) buf_set_u32(arm->pc->value, 0, 32, address); current_pc = buf_get_u32(arm->pc->value, 0, 32); /* if we're at the reset vector, we have to simulate the branch */ if (current_pc == 0x0) { arm_simulate_step(target, NULL); current_pc = buf_get_u32(arm->pc->value, 0, 32); } /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { struct breakpoint *breakpoint; breakpoint = breakpoint_find(target, buf_get_u32(arm->pc->value, 0, 32)); if (breakpoint) { uint32_t next_pc; enum trace_mode saved_trace_mode; /* there's a breakpoint at the current PC, we have to step over it */ LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT "", breakpoint->address); xscale_unset_breakpoint(target, breakpoint); /* calculate PC of next instruction */ retval = arm_simulate_step(target, &next_pc); if (retval != ERROR_OK) { uint32_t current_opcode; target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( "BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", current_opcode); } LOG_DEBUG("enable single-step"); xscale_enable_single_step(target, next_pc); /* restore banked registers */ retval = xscale_restore_banked(target); if (retval != ERROR_OK) return retval; /* send resume request */ xscale_send_u32(target, 0x30); /* send CPSR */ xscale_send_u32(target, buf_get_u32(arm->cpsr->value, 0, 32)); LOG_DEBUG("writing cpsr with value 0x%8.8" PRIx32, buf_get_u32(arm->cpsr->value, 0, 32)); for (i = 7; i >= 0; i--) { /* send register */ xscale_send_u32(target, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32 "", i, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); } /* send PC */ xscale_send_u32(target, buf_get_u32(arm->pc->value, 0, 32)); LOG_DEBUG("writing PC with value 0x%8.8" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); /* disable trace data collection in xscale_debug_entry() */ saved_trace_mode = xscale->trace.mode; xscale->trace.mode = XSCALE_TRACE_DISABLED; /* wait for and process debug entry */ xscale_debug_entry(target); /* re-enable trace buffer, if enabled previously */ xscale->trace.mode = saved_trace_mode; LOG_DEBUG("disable single-step"); xscale_disable_single_step(target); LOG_DEBUG("set breakpoint at " TARGET_ADDR_FMT "", breakpoint->address); xscale_set_breakpoint(target, breakpoint); } } /* enable any pending breakpoints and watchpoints */ xscale_enable_breakpoints(target); xscale_enable_watchpoints(target); /* restore banked registers */ retval = xscale_restore_banked(target); if (retval != ERROR_OK) return retval; /* send resume request (command 0x30 or 0x31) * clean the trace buffer if it is to be enabled (0x62) */ if (xscale->trace.mode != XSCALE_TRACE_DISABLED) { if (xscale->trace.mode == XSCALE_TRACE_FILL) { /* If trace enabled in fill mode and starting collection of new set * of buffers, initialize buffer counter and free previous buffers */ if (xscale->trace.fill_counter == 0) { xscale->trace.fill_counter = xscale->trace.buffer_fill; xscale_free_trace_data(xscale); } } else /* wrap mode; free previous buffer */ xscale_free_trace_data(xscale); xscale_send_u32(target, 0x62); xscale_send_u32(target, 0x31); } else xscale_send_u32(target, 0x30); /* send CPSR */ xscale_send_u32(target, buf_get_u32(arm->cpsr->value, 0, 32)); LOG_DEBUG("writing cpsr with value 0x%8.8" PRIx32, buf_get_u32(arm->cpsr->value, 0, 32)); for (i = 7; i >= 0; i--) { /* send register */ xscale_send_u32(target, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32 "", i, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); } /* send PC */ xscale_send_u32(target, buf_get_u32(arm->pc->value, 0, 32)); LOG_DEBUG("wrote PC with value 0x%8.8" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); target->debug_reason = DBG_REASON_NOTHALTED; if (!debug_execution) { /* registers are now invalid */ register_cache_invalidate(arm->core_cache); target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); } LOG_DEBUG("target resumed"); return ERROR_OK; } static int xscale_step_inner(struct target *target, int current, uint32_t address, int handle_breakpoints) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; uint32_t next_pc; int retval; int i; target->debug_reason = DBG_REASON_SINGLESTEP; /* calculate PC of next instruction */ retval = arm_simulate_step(target, &next_pc); if (retval != ERROR_OK) { uint32_t current_opcode, current_pc; current_pc = buf_get_u32(arm->pc->value, 0, 32); target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( "BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", current_opcode); return retval; } LOG_DEBUG("enable single-step"); retval = xscale_enable_single_step(target, next_pc); if (retval != ERROR_OK) return retval; /* restore banked registers */ retval = xscale_restore_banked(target); if (retval != ERROR_OK) return retval; /* send resume request (command 0x30 or 0x31) * clean the trace buffer if it is to be enabled (0x62) */ if (xscale->trace.mode != XSCALE_TRACE_DISABLED) { retval = xscale_send_u32(target, 0x62); if (retval != ERROR_OK) return retval; retval = xscale_send_u32(target, 0x31); if (retval != ERROR_OK) return retval; } else { retval = xscale_send_u32(target, 0x30); if (retval != ERROR_OK) return retval; } /* send CPSR */ retval = xscale_send_u32(target, buf_get_u32(arm->cpsr->value, 0, 32)); if (retval != ERROR_OK) return retval; LOG_DEBUG("writing cpsr with value 0x%8.8" PRIx32, buf_get_u32(arm->cpsr->value, 0, 32)); for (i = 7; i >= 0; i--) { /* send register */ retval = xscale_send_u32(target, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); if (retval != ERROR_OK) return retval; LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32 "", i, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); } /* send PC */ retval = xscale_send_u32(target, buf_get_u32(arm->pc->value, 0, 32)); if (retval != ERROR_OK) return retval; LOG_DEBUG("wrote PC with value 0x%8.8" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); /* registers are now invalid */ register_cache_invalidate(arm->core_cache); /* wait for and process debug entry */ retval = xscale_debug_entry(target); if (retval != ERROR_OK) return retval; LOG_DEBUG("disable single-step"); retval = xscale_disable_single_step(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } static int xscale_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { struct arm *arm = target_to_arm(target); struct breakpoint *breakpoint = NULL; uint32_t current_pc; int retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) buf_set_u32(arm->pc->value, 0, 32, address); current_pc = buf_get_u32(arm->pc->value, 0, 32); /* if we're at the reset vector, we have to simulate the step */ if (current_pc == 0x0) { retval = arm_simulate_step(target, NULL); if (retval != ERROR_OK) return retval; current_pc = buf_get_u32(arm->pc->value, 0, 32); LOG_DEBUG("current pc %" PRIx32, current_pc); target->debug_reason = DBG_REASON_SINGLESTEP; target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) breakpoint = breakpoint_find(target, buf_get_u32(arm->pc->value, 0, 32)); if (breakpoint) { retval = xscale_unset_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; } retval = xscale_step_inner(target, current, address, handle_breakpoints); if (retval != ERROR_OK) return retval; if (breakpoint) xscale_set_breakpoint(target, breakpoint); LOG_DEBUG("target stepped"); return ERROR_OK; } static int xscale_assert_reset(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); /* TODO: apply hw reset signal in not examined state */ if (!(target_was_examined(target))) { LOG_WARNING("Reset is not asserted because the target is not examined."); LOG_WARNING("Use a reset button or power cycle the target."); return ERROR_TARGET_NOT_EXAMINED; } LOG_DEBUG("target->state: %s", target_state_name(target)); /* assert reset */ jtag_add_reset(0, 1); /* sleep 1ms, to be sure we fulfill any requirements */ jtag_add_sleep(1000); jtag_execute_queue(); /* select DCSR instruction (set endstate to R-T-I to ensure we don't * end up in T-L-R, which would reset JTAG */ xscale_jtag_set_instr(target->tap, XSCALE_SELDCSR << xscale->xscale_variant, TAP_IDLE); /* set Hold reset, Halt mode and Trap Reset */ buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); xscale_write_dcsr(target, 1, 0); /* select BYPASS, because having DCSR selected caused problems on the PXA27x */ xscale_jtag_set_instr(target->tap, ~0, TAP_IDLE); jtag_execute_queue(); target->state = TARGET_RESET; if (target->reset_halt) { int retval = target_halt(target); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int xscale_deassert_reset(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); struct breakpoint *breakpoint = target->breakpoints; LOG_DEBUG("-"); xscale->ibcr_available = 2; xscale->ibcr0_used = 0; xscale->ibcr1_used = 0; xscale->dbr_available = 2; xscale->dbr0_used = 0; xscale->dbr1_used = 0; /* mark all hardware breakpoints as unset */ while (breakpoint) { if (breakpoint->type == BKPT_HARD) breakpoint->is_set = false; breakpoint = breakpoint->next; } xscale->trace.mode = XSCALE_TRACE_DISABLED; xscale_free_trace_data(xscale); register_cache_invalidate(xscale->arm.core_cache); /* FIXME mark hardware watchpoints got unset too. Also, * at least some of the XScale registers are invalid... */ /* * REVISIT: *assumes* we had a SRST+TRST reset so the mini-icache * contents got invalidated. Safer to force that, so writing new * contents can't ever fail.. */ { uint32_t address; unsigned buf_cnt; const uint8_t *buffer = xscale_debug_handler; int retval; /* release SRST */ jtag_add_reset(0, 0); /* wait 300ms; 150 and 100ms were not enough */ jtag_add_sleep(300*1000); jtag_add_runtest(2030, TAP_IDLE); jtag_execute_queue(); /* set Hold reset, Halt mode and Trap Reset */ buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); xscale_write_dcsr(target, 1, 0); /* Load the debug handler into the mini-icache. Since * it's using halt mode (not monitor mode), it runs in * "Special Debug State" for access to registers, memory, * coprocessors, trace data, etc. */ address = xscale->handler_address; for (unsigned binary_size = sizeof(xscale_debug_handler); binary_size > 0; binary_size -= buf_cnt, buffer += buf_cnt) { uint32_t cache_line[8]; unsigned i; buf_cnt = binary_size; if (buf_cnt > 32) buf_cnt = 32; for (i = 0; i < buf_cnt; i += 4) { /* convert LE buffer to host-endian uint32_t */ cache_line[i / 4] = le_to_h_u32(&buffer[i]); } for (; i < 32; i += 4) cache_line[i / 4] = 0xe1a08008; /* only load addresses other than the reset vectors */ if ((address % 0x400) != 0x0) { retval = xscale_load_ic(target, address, cache_line); if (retval != ERROR_OK) return retval; } address += buf_cnt; } retval = xscale_load_ic(target, 0x0, xscale->low_vectors); if (retval != ERROR_OK) return retval; retval = xscale_load_ic(target, 0xffff0000, xscale->high_vectors); if (retval != ERROR_OK) return retval; jtag_add_runtest(30, TAP_IDLE); jtag_add_sleep(100000); /* set Hold reset, Halt mode and Trap Reset */ buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); xscale_write_dcsr(target, 1, 0); /* clear Hold reset to let the target run (should enter debug handler) */ xscale_write_dcsr(target, 0, 1); target->state = TARGET_RUNNING; if (!target->reset_halt) { jtag_add_sleep(10000); /* we should have entered debug now */ xscale_debug_entry(target); target->state = TARGET_HALTED; /* resume the target */ xscale_resume(target, 1, 0x0, 1, 0); } } return ERROR_OK; } static int xscale_read_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode) { /** \todo add debug handler support for core register reads */ LOG_ERROR("not implemented"); return ERROR_OK; } static int xscale_write_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode, uint8_t *value) { /** \todo add debug handler support for core register writes */ LOG_ERROR("not implemented"); return ERROR_OK; } static int xscale_full_context(struct target *target) { struct arm *arm = target_to_arm(target); uint32_t *buffer; int i, j; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } buffer = malloc(4 * 8); /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS) * we can't enter User mode on an XScale (unpredictable), * but User shares registers with SYS */ for (i = 1; i < 7; i++) { enum arm_mode mode = armv4_5_number_to_mode(i); bool valid = true; struct reg *r; if (mode == ARM_MODE_USR) continue; /* check if there are invalid registers in the current mode */ for (j = 0; valid && j <= 16; j++) { if (!ARMV4_5_CORE_REG_MODE(arm->core_cache, mode, j).valid) valid = false; } if (valid) continue; /* request banked registers */ xscale_send_u32(target, 0x0); /* send CPSR for desired bank mode */ xscale_send_u32(target, mode | 0xc0 /* I/F bits */); /* get banked registers: r8 to r14; and SPSR * except in USR/SYS mode */ if (mode != ARM_MODE_SYS) { /* SPSR */ r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, mode, 16); xscale_receive(target, buffer, 8); buf_set_u32(r->value, 0, 32, buffer[7]); r->dirty = false; r->valid = true; } else xscale_receive(target, buffer, 7); /* move data from buffer to register cache */ for (j = 8; j <= 14; j++) { r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, mode, j); buf_set_u32(r->value, 0, 32, buffer[j - 8]); r->dirty = false; r->valid = true; } } free(buffer); return ERROR_OK; } static int xscale_restore_banked(struct target *target) { struct arm *arm = target_to_arm(target); int i, j; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS) * and check if any banked registers need to be written. Ignore * USR mode (number 0) in favor of SYS; we can't enter User mode on * an XScale (unpredictable), but they share all registers. */ for (i = 1; i < 7; i++) { enum arm_mode mode = armv4_5_number_to_mode(i); struct reg *r; if (mode == ARM_MODE_USR) continue; /* check if there are dirty registers in this mode */ for (j = 8; j <= 14; j++) { if (ARMV4_5_CORE_REG_MODE(arm->core_cache, mode, j).dirty) goto dirty; } /* if not USR/SYS, check if the SPSR needs to be written */ if (mode != ARM_MODE_SYS) { if (ARMV4_5_CORE_REG_MODE(arm->core_cache, mode, 16).dirty) goto dirty; } /* there's nothing to flush for this mode */ continue; dirty: /* command 0x1: "send banked registers" */ xscale_send_u32(target, 0x1); /* send CPSR for desired mode */ xscale_send_u32(target, mode | 0xc0 /* I/F bits */); /* send r8 to r14/lr ... only FIQ needs more than r13..r14, * but this protocol doesn't understand that nuance. */ for (j = 8; j <= 14; j++) { r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, mode, j); xscale_send_u32(target, buf_get_u32(r->value, 0, 32)); r->dirty = false; } /* send spsr if not in USR/SYS mode */ if (mode != ARM_MODE_SYS) { r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, mode, 16); xscale_send_u32(target, buf_get_u32(r->value, 0, 32)); r->dirty = false; } } return ERROR_OK; } static int xscale_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct xscale_common *xscale = target_to_xscale(target); uint32_t *buf32; uint32_t i; int retval; LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; /* send memory read request (command 0x1n, n: access size) */ retval = xscale_send_u32(target, 0x10 | size); if (retval != ERROR_OK) return retval; /* send base address for read request */ retval = xscale_send_u32(target, address); if (retval != ERROR_OK) return retval; /* send number of requested data words */ retval = xscale_send_u32(target, count); if (retval != ERROR_OK) return retval; /* receive data from target (count times 32-bit words in host endianness) */ buf32 = malloc(4 * count); retval = xscale_receive(target, buf32, count); if (retval != ERROR_OK) { free(buf32); return retval; } /* extract data from host-endian buffer into byte stream */ for (i = 0; i < count; i++) { switch (size) { case 4: target_buffer_set_u32(target, buffer, buf32[i]); buffer += 4; break; case 2: target_buffer_set_u16(target, buffer, buf32[i] & 0xffff); buffer += 2; break; case 1: *buffer++ = buf32[i] & 0xff; break; default: LOG_ERROR("invalid read size"); return ERROR_COMMAND_SYNTAX_ERROR; } } free(buf32); /* examine DCSR, to see if Sticky Abort (SA) got set */ retval = xscale_read_dcsr(target); if (retval != ERROR_OK) return retval; if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1) { /* clear SA bit */ retval = xscale_send_u32(target, 0x60); if (retval != ERROR_OK) return retval; return ERROR_TARGET_DATA_ABORT; } return ERROR_OK; } static int xscale_read_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct xscale_common *xscale = target_to_xscale(target); /* with MMU inactive, there are only physical addresses */ if (!xscale->armv4_5_mmu.mmu_enabled) return xscale_read_memory(target, address, size, count, buffer); /** \todo: provide a non-stub implementation of this routine. */ LOG_ERROR("%s: %s is not implemented. Disable MMU?", target_name(target), __func__); return ERROR_FAIL; } static int xscale_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct xscale_common *xscale = target_to_xscale(target); int retval; LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; /* send memory write request (command 0x2n, n: access size) */ retval = xscale_send_u32(target, 0x20 | size); if (retval != ERROR_OK) return retval; /* send base address for read request */ retval = xscale_send_u32(target, address); if (retval != ERROR_OK) return retval; /* send number of requested data words to be written*/ retval = xscale_send_u32(target, count); if (retval != ERROR_OK) return retval; /* extract data from host-endian buffer into byte stream */ #if 0 for (i = 0; i < count; i++) { switch (size) { case 4: value = target_buffer_get_u32(target, buffer); xscale_send_u32(target, value); buffer += 4; break; case 2: value = target_buffer_get_u16(target, buffer); xscale_send_u32(target, value); buffer += 2; break; case 1: value = *buffer; xscale_send_u32(target, value); buffer += 1; break; default: LOG_ERROR("should never get here"); exit(-1); } } #endif retval = xscale_send(target, buffer, count, size); if (retval != ERROR_OK) return retval; /* examine DCSR, to see if Sticky Abort (SA) got set */ retval = xscale_read_dcsr(target); if (retval != ERROR_OK) return retval; if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1) { /* clear SA bit */ retval = xscale_send_u32(target, 0x60); if (retval != ERROR_OK) return retval; LOG_ERROR("data abort writing memory"); return ERROR_TARGET_DATA_ABORT; } return ERROR_OK; } static int xscale_write_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct xscale_common *xscale = target_to_xscale(target); /* with MMU inactive, there are only physical addresses */ if (!xscale->armv4_5_mmu.mmu_enabled) return xscale_write_memory(target, address, size, count, buffer); /** \todo: provide a non-stub implementation of this routine. */ LOG_ERROR("%s: %s is not implemented. Disable MMU?", target_name(target), __func__); return ERROR_FAIL; } static int xscale_get_ttb(struct target *target, uint32_t *result) { struct xscale_common *xscale = target_to_xscale(target); uint32_t ttb; int retval; retval = xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_TTB]); if (retval != ERROR_OK) return retval; ttb = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_TTB].value, 0, 32); *result = ttb; return ERROR_OK; } static int xscale_disable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { struct xscale_common *xscale = target_to_xscale(target); uint32_t cp15_control; int retval; /* read cp15 control register */ retval = xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); if (retval != ERROR_OK) return retval; cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); if (mmu) cp15_control &= ~0x1U; if (d_u_cache) { /* clean DCache */ retval = xscale_send_u32(target, 0x50); if (retval != ERROR_OK) return retval; retval = xscale_send_u32(target, xscale->cache_clean_address); if (retval != ERROR_OK) return retval; /* invalidate DCache */ retval = xscale_send_u32(target, 0x51); if (retval != ERROR_OK) return retval; cp15_control &= ~0x4U; } if (i_cache) { /* invalidate ICache */ retval = xscale_send_u32(target, 0x52); if (retval != ERROR_OK) return retval; cp15_control &= ~0x1000U; } /* write new cp15 control register */ retval = xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); if (retval != ERROR_OK) return retval; /* execute cpwait to ensure outstanding operations complete */ retval = xscale_send_u32(target, 0x53); return retval; } static int xscale_enable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { struct xscale_common *xscale = target_to_xscale(target); uint32_t cp15_control; int retval; /* read cp15 control register */ retval = xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); if (retval != ERROR_OK) return retval; cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); if (mmu) cp15_control |= 0x1U; if (d_u_cache) cp15_control |= 0x4U; if (i_cache) cp15_control |= 0x1000U; /* write new cp15 control register */ retval = xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); if (retval != ERROR_OK) return retval; /* execute cpwait to ensure outstanding operations complete */ retval = xscale_send_u32(target, 0x53); return retval; } static int xscale_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval; struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { uint32_t value = breakpoint->address | 1; if (!xscale->ibcr0_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], value); xscale->ibcr0_used = 1; /* breakpoint set on first breakpoint register */ breakpoint_hw_set(breakpoint, 0); } else if (!xscale->ibcr1_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], value); xscale->ibcr1_used = 1; /* breakpoint set on second breakpoint register */ breakpoint_hw_set(breakpoint, 1); } else {/* bug: availability previously verified in xscale_add_breakpoint() */ LOG_ERROR("BUG: no hardware comparator available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } else if (breakpoint->type == BKPT_SOFT) { if (breakpoint->length == 4) { /* keep the original instruction in target endianness */ retval = target_read_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; /* write the bkpt instruction in target endianness *(arm7_9->arm_bkpt is host endian) */ retval = target_write_u32(target, breakpoint->address, xscale->arm_bkpt); if (retval != ERROR_OK) return retval; } else { /* keep the original instruction in target endianness */ retval = target_read_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; /* write the bkpt instruction in target endianness *(arm7_9->arm_bkpt is host endian) */ retval = target_write_u16(target, breakpoint->address, xscale->thumb_bkpt); if (retval != ERROR_OK) return retval; } breakpoint->is_set = true; xscale_send_u32(target, 0x50); /* clean dcache */ xscale_send_u32(target, xscale->cache_clean_address); xscale_send_u32(target, 0x51); /* invalidate dcache */ xscale_send_u32(target, 0x52); /* invalidate icache and flush fetch buffers */ } return ERROR_OK; } static int xscale_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct xscale_common *xscale = target_to_xscale(target); if ((breakpoint->type == BKPT_HARD) && (xscale->ibcr_available < 1)) { LOG_ERROR("no breakpoint unit available for hardware breakpoint"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if ((breakpoint->length != 2) && (breakpoint->length != 4)) { LOG_ERROR("only breakpoints of two (Thumb) or four (ARM) bytes length supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_HARD) xscale->ibcr_available--; return xscale_set_breakpoint(target, breakpoint); } static int xscale_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval; struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { if (breakpoint->number == 0) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], 0x0); xscale->ibcr0_used = 0; } else if (breakpoint->number == 1) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], 0x0); xscale->ibcr1_used = 0; } breakpoint->is_set = false; } else { /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { retval = target_write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } else { retval = target_write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } breakpoint->is_set = false; xscale_send_u32(target, 0x50); /* clean dcache */ xscale_send_u32(target, xscale->cache_clean_address); xscale_send_u32(target, 0x51); /* invalidate dcache */ xscale_send_u32(target, 0x52); /* invalidate icache and flush fetch buffers */ } return ERROR_OK; } static int xscale_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { LOG_ERROR("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (breakpoint->is_set) xscale_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) xscale->ibcr_available++; return ERROR_OK; } static int xscale_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct xscale_common *xscale = target_to_xscale(target); uint32_t enable = 0; struct reg *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; uint32_t dbcon_value = buf_get_u32(dbcon->value, 0, 32); if (target->state != TARGET_HALTED) { LOG_ERROR("target not halted"); return ERROR_TARGET_NOT_HALTED; } switch (watchpoint->rw) { case WPT_READ: enable = 0x3; break; case WPT_ACCESS: enable = 0x2; break; case WPT_WRITE: enable = 0x1; break; default: LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } /* For watchpoint across more than one word, both DBR registers must be enlisted, with the second used as a mask. */ if (watchpoint->length > 4) { if (xscale->dbr0_used || xscale->dbr1_used) { LOG_ERROR("BUG: sufficient hardware comparators unavailable"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* Write mask value to DBR1, based on the length argument. * Address bits ignored by the comparator are those set in mask. */ xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], watchpoint->length - 1); xscale->dbr1_used = 1; enable |= 0x100; /* DBCON[M] */ } if (!xscale->dbr0_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR0], watchpoint->address); dbcon_value |= enable; xscale_set_reg_u32(dbcon, dbcon_value); watchpoint_set(watchpoint, 0); xscale->dbr0_used = 1; } else if (!xscale->dbr1_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], watchpoint->address); dbcon_value |= enable << 2; xscale_set_reg_u32(dbcon, dbcon_value); watchpoint_set(watchpoint, 1); xscale->dbr1_used = 1; } else { LOG_ERROR("BUG: no hardware comparator available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } return ERROR_OK; } static int xscale_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct xscale_common *xscale = target_to_xscale(target); if (xscale->dbr_available < 1) { LOG_ERROR("no more watchpoint registers available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (watchpoint->value) LOG_WARNING("xscale does not support value, mask arguments; ignoring"); /* check that length is a power of two */ for (uint32_t len = watchpoint->length; len != 1; len /= 2) { if (len % 2) { LOG_ERROR("xscale requires that watchpoint length is a power of two"); return ERROR_COMMAND_ARGUMENT_INVALID; } } if (watchpoint->length == 4) { /* single word watchpoint */ xscale->dbr_available--;/* one DBR reg used */ return ERROR_OK; } /* watchpoints across multiple words require both DBR registers */ if (xscale->dbr_available < 2) { LOG_ERROR("insufficient watchpoint registers available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (watchpoint->length > watchpoint->address) { LOG_ERROR("xscale does not support watchpoints with length " "greater than address"); return ERROR_COMMAND_ARGUMENT_INVALID; } xscale->dbr_available = 0; return ERROR_OK; } static int xscale_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct xscale_common *xscale = target_to_xscale(target); struct reg *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; uint32_t dbcon_value = buf_get_u32(dbcon->value, 0, 32); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!watchpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (watchpoint->number == 0) { if (watchpoint->length > 4) { dbcon_value &= ~0x103; /* clear DBCON[M] as well */ xscale->dbr1_used = 0; /* DBR1 was used for mask */ } else dbcon_value &= ~0x3; xscale_set_reg_u32(dbcon, dbcon_value); xscale->dbr0_used = 0; } else if (watchpoint->number == 1) { dbcon_value &= ~0xc; xscale_set_reg_u32(dbcon, dbcon_value); xscale->dbr1_used = 0; } watchpoint->is_set = false; return ERROR_OK; } static int xscale_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { LOG_ERROR("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (watchpoint->is_set) xscale_unset_watchpoint(target, watchpoint); if (watchpoint->length > 4) xscale->dbr_available++;/* both DBR regs now available */ xscale->dbr_available++; return ERROR_OK; } static int xscale_get_reg(struct reg *reg) { struct xscale_reg *arch_info = reg->arch_info; struct target *target = arch_info->target; struct xscale_common *xscale = target_to_xscale(target); /* DCSR, TX and RX are accessible via JTAG */ if (strcmp(reg->name, "XSCALE_DCSR") == 0) return xscale_read_dcsr(arch_info->target); else if (strcmp(reg->name, "XSCALE_TX") == 0) { /* 1 = consume register content */ return xscale_read_tx(arch_info->target, 1); } else if (strcmp(reg->name, "XSCALE_RX") == 0) { /* can't read from RX register (host -> debug handler) */ return ERROR_OK; } else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0) { /* can't (explicitly) read from TXRXCTRL register */ return ERROR_OK; } else {/* Other DBG registers have to be transferred by the debug handler * send CP read request (command 0x40) */ xscale_send_u32(target, 0x40); /* send CP register number */ xscale_send_u32(target, arch_info->dbg_handler_number); /* read register value */ xscale_read_tx(target, 1); buf_cpy(xscale->reg_cache->reg_list[XSCALE_TX].value, reg->value, 32); reg->dirty = false; reg->valid = true; } return ERROR_OK; } static int xscale_set_reg(struct reg *reg, uint8_t *buf) { struct xscale_reg *arch_info = reg->arch_info; struct target *target = arch_info->target; struct xscale_common *xscale = target_to_xscale(target); uint32_t value = buf_get_u32(buf, 0, 32); /* DCSR, TX and RX are accessible via JTAG */ if (strcmp(reg->name, "XSCALE_DCSR") == 0) { buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32, value); return xscale_write_dcsr(arch_info->target, -1, -1); } else if (strcmp(reg->name, "XSCALE_RX") == 0) { buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value); return xscale_write_rx(arch_info->target); } else if (strcmp(reg->name, "XSCALE_TX") == 0) { /* can't write to TX register (debug-handler -> host) */ return ERROR_OK; } else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0) { /* can't (explicitly) write to TXRXCTRL register */ return ERROR_OK; } else {/* Other DBG registers have to be transferred by the debug handler * send CP write request (command 0x41) */ xscale_send_u32(target, 0x41); /* send CP register number */ xscale_send_u32(target, arch_info->dbg_handler_number); /* send CP register value */ xscale_send_u32(target, value); buf_set_u32(reg->value, 0, 32, value); } return ERROR_OK; } static int xscale_write_dcsr_sw(struct target *target, uint32_t value) { struct xscale_common *xscale = target_to_xscale(target); struct reg *dcsr = &xscale->reg_cache->reg_list[XSCALE_DCSR]; struct xscale_reg *dcsr_arch_info = dcsr->arch_info; /* send CP write request (command 0x41) */ xscale_send_u32(target, 0x41); /* send CP register number */ xscale_send_u32(target, dcsr_arch_info->dbg_handler_number); /* send CP register value */ xscale_send_u32(target, value); buf_set_u32(dcsr->value, 0, 32, value); return ERROR_OK; } static int xscale_read_trace(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; struct xscale_trace_data **trace_data_p; /* 258 words from debug handler * 256 trace buffer entries * 2 checkpoint addresses */ uint32_t trace_buffer[258]; int is_address[256]; int i, j; unsigned int num_checkpoints = 0; if (target->state != TARGET_HALTED) { LOG_WARNING("target must be stopped to read trace data"); return ERROR_TARGET_NOT_HALTED; } /* send read trace buffer command (command 0x61) */ xscale_send_u32(target, 0x61); /* receive trace buffer content */ xscale_receive(target, trace_buffer, 258); /* parse buffer backwards to identify address entries */ for (i = 255; i >= 0; i--) { /* also count number of checkpointed entries */ if ((trace_buffer[i] & 0xe0) == 0xc0) num_checkpoints++; is_address[i] = 0; if (((trace_buffer[i] & 0xf0) == 0x90) || ((trace_buffer[i] & 0xf0) == 0xd0)) { if (i > 0) is_address[--i] = 1; if (i > 0) is_address[--i] = 1; if (i > 0) is_address[--i] = 1; if (i > 0) is_address[--i] = 1; } } /* search first non-zero entry that is not part of an address */ for (j = 0; (j < 256) && (trace_buffer[j] == 0) && (!is_address[j]); j++) ; if (j == 256) { LOG_DEBUG("no trace data collected"); return ERROR_XSCALE_NO_TRACE_DATA; } /* account for possible partial address at buffer start (wrap mode only) */ if (is_address[0]) { /* first entry is address; complete set of 4? */ i = 1; while (i < 4) if (!is_address[i++]) break; if (i < 4) j += i; /* partial address; can't use it */ } /* if first valid entry is indirect branch, can't use that either (no address) */ if (((trace_buffer[j] & 0xf0) == 0x90) || ((trace_buffer[j] & 0xf0) == 0xd0)) j++; /* walk linked list to terminating entry */ for (trace_data_p = &xscale->trace.data; *trace_data_p; trace_data_p = &(*trace_data_p)->next) ; *trace_data_p = malloc(sizeof(struct xscale_trace_data)); (*trace_data_p)->next = NULL; (*trace_data_p)->chkpt0 = trace_buffer[256]; (*trace_data_p)->chkpt1 = trace_buffer[257]; (*trace_data_p)->last_instruction = buf_get_u32(arm->pc->value, 0, 32); (*trace_data_p)->entries = malloc(sizeof(struct xscale_trace_entry) * (256 - j)); (*trace_data_p)->depth = 256 - j; (*trace_data_p)->num_checkpoints = num_checkpoints; for (i = j; i < 256; i++) { (*trace_data_p)->entries[i - j].data = trace_buffer[i]; if (is_address[i]) (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_ADDRESS; else (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_MESSAGE; } return ERROR_OK; } static int xscale_read_instruction(struct target *target, uint32_t pc, struct arm_instruction *instruction) { struct xscale_common *const xscale = target_to_xscale(target); int section = -1; size_t size_read; uint32_t opcode; int retval; if (!xscale->trace.image) return ERROR_TRACE_IMAGE_UNAVAILABLE; /* search for the section the current instruction belongs to */ for (unsigned int i = 0; i < xscale->trace.image->num_sections; i++) { if ((xscale->trace.image->sections[i].base_address <= pc) && (xscale->trace.image->sections[i].base_address + xscale->trace.image->sections[i].size > pc)) { section = i; break; } } if (section == -1) { /* current instruction couldn't be found in the image */ return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } if (xscale->trace.core_state == ARM_STATE_ARM) { uint8_t buf[4]; retval = image_read_section(xscale->trace.image, section, pc - xscale->trace.image->sections[section].base_address, 4, buf, &size_read); if (retval != ERROR_OK) { LOG_ERROR("error while reading instruction"); return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } opcode = target_buffer_get_u32(target, buf); arm_evaluate_opcode(opcode, pc, instruction); } else if (xscale->trace.core_state == ARM_STATE_THUMB) { uint8_t buf[2]; retval = image_read_section(xscale->trace.image, section, pc - xscale->trace.image->sections[section].base_address, 2, buf, &size_read); if (retval != ERROR_OK) { LOG_ERROR("error while reading instruction"); return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } opcode = target_buffer_get_u16(target, buf); thumb_evaluate_opcode(opcode, pc, instruction); } else { LOG_ERROR("BUG: unknown core state encountered"); exit(-1); } return ERROR_OK; } /* Extract address encoded into trace data. * Write result to address referenced by argument 'target', or 0 if incomplete. */ static inline void xscale_branch_address(struct xscale_trace_data *trace_data, int i, uint32_t *target) { /* if there are less than four entries prior to the indirect branch message * we can't extract the address */ if (i < 4) *target = 0; else { *target = (trace_data->entries[i-1].data) | (trace_data->entries[i-2].data << 8) | (trace_data->entries[i-3].data << 16) | (trace_data->entries[i-4].data << 24); } } static inline void xscale_display_instruction(struct target *target, uint32_t pc, struct arm_instruction *instruction, struct command_invocation *cmd) { int retval = xscale_read_instruction(target, pc, instruction); if (retval == ERROR_OK) command_print(cmd, "%s", instruction->text); else command_print(cmd, "0x%8.8" PRIx32 "\t<not found in image>", pc); } static int xscale_analyze_trace(struct target *target, struct command_invocation *cmd) { struct xscale_common *xscale = target_to_xscale(target); struct xscale_trace_data *trace_data = xscale->trace.data; int i, retval; uint32_t breakpoint_pc = 0; struct arm_instruction instruction; uint32_t current_pc = 0;/* initialized when address determined */ if (!xscale->trace.image) LOG_WARNING("No trace image loaded; use 'xscale trace_image'"); /* loop for each trace buffer that was loaded from target */ while (trace_data) { int chkpt = 0; /* incremented as checkpointed entries found */ int j; /* FIXME: set this to correct mode when trace buffer is first enabled */ xscale->trace.core_state = ARM_STATE_ARM; /* loop for each entry in this trace buffer */ for (i = 0; i < trace_data->depth; i++) { int exception = 0; uint32_t chkpt_reg = 0x0; uint32_t branch_target = 0; int count; /* trace entry type is upper nybble of 'message byte' */ int trace_msg_type = (trace_data->entries[i].data & 0xf0) >> 4; /* Target addresses of indirect branches are written into buffer * before the message byte representing the branch. Skip past it */ if (trace_data->entries[i].type == XSCALE_TRACE_ADDRESS) continue; switch (trace_msg_type) { case 0: /* Exceptions */ case 1: case 2: case 3: case 4: case 5: case 6: case 7: exception = (trace_data->entries[i].data & 0x70) >> 4; /* FIXME: vector table may be at ffff0000 */ branch_target = (trace_data->entries[i].data & 0xf0) >> 2; break; case 8: /* Direct Branch */ break; case 9: /* Indirect Branch */ xscale_branch_address(trace_data, i, &branch_target); break; case 13: /* Checkpointed Indirect Branch */ xscale_branch_address(trace_data, i, &branch_target); if ((trace_data->num_checkpoints == 2) && (chkpt == 0)) chkpt_reg = trace_data->chkpt1; /* 2 chkpts, this is *oldest */ else chkpt_reg = trace_data->chkpt0; /* 1 chkpt, or 2 and *newest */ chkpt++; break; case 12: /* Checkpointed Direct Branch */ if ((trace_data->num_checkpoints == 2) && (chkpt == 0)) chkpt_reg = trace_data->chkpt1; /* 2 chkpts, this is *oldest */ else chkpt_reg = trace_data->chkpt0; /* 1 chkpt, or 2 and *newest */ /* if no current_pc, checkpoint will be starting point */ if (current_pc == 0) branch_target = chkpt_reg; chkpt++; break; case 15:/* Roll-over */ break; default:/* Reserved */ LOG_WARNING("trace is suspect: invalid trace message byte"); continue; } /* If we don't have the current_pc yet, but we did get the branch target * (either from the trace buffer on indirect branch, or from a checkpoint reg), * then we can start displaying instructions at the next iteration, with * branch_target as the starting point. */ if (current_pc == 0) { current_pc = branch_target; /* remains 0 unless branch_target *obtained */ continue; } /* We have current_pc. Read and display the instructions from the image. * First, display count instructions (lower nybble of message byte). */ count = trace_data->entries[i].data & 0x0f; for (j = 0; j < count; j++) { xscale_display_instruction(target, current_pc, &instruction, cmd); current_pc += xscale->trace.core_state == ARM_STATE_ARM ? 4 : 2; } /* An additional instruction is implicitly added to count for * rollover and some exceptions: undef, swi, prefetch abort. */ if ((trace_msg_type == 15) || (exception > 0 && exception < 4)) { xscale_display_instruction(target, current_pc, &instruction, cmd); current_pc += xscale->trace.core_state == ARM_STATE_ARM ? 4 : 2; } if (trace_msg_type == 15) /* rollover */ continue; if (exception) { command_print(cmd, "--- exception %i ---", exception); continue; } /* not exception or rollover; next instruction is a branch and is * not included in the count */ xscale_display_instruction(target, current_pc, &instruction, cmd); /* for direct branches, extract branch destination from instruction */ if ((trace_msg_type == 8) || (trace_msg_type == 12)) { retval = xscale_read_instruction(target, current_pc, &instruction); if (retval == ERROR_OK) current_pc = instruction.info.b_bl_bx_blx.target_address; else current_pc = 0; /* branch destination unknown */ /* direct branch w/ checkpoint; can also get from checkpoint reg */ if (trace_msg_type == 12) { if (current_pc == 0) current_pc = chkpt_reg; else if (current_pc != chkpt_reg) /* sanity check */ LOG_WARNING("trace is suspect: checkpoint register " "inconsistent with address from image"); } if (current_pc == 0) command_print(cmd, "address unknown"); continue; } /* indirect branch; the branch destination was read from trace buffer */ if ((trace_msg_type == 9) || (trace_msg_type == 13)) { current_pc = branch_target; /* sanity check (checkpoint reg is redundant) */ if ((trace_msg_type == 13) && (chkpt_reg != branch_target)) LOG_WARNING("trace is suspect: checkpoint register " "inconsistent with address from trace buffer"); } } /* END: for (i = 0; i < trace_data->depth; i++) */ breakpoint_pc = trace_data->last_instruction; /* used below */ trace_data = trace_data->next; } /* END: while (trace_data) */ /* Finally... display all instructions up to the value of the pc when the * debug break occurred (saved when trace data was collected from target). * This is necessary because the trace only records execution branches and 16 * consecutive instructions (rollovers), so last few typically missed. */ if (current_pc == 0) return ERROR_OK;/* current_pc was never found */ /* how many instructions remaining? */ int gap_count = (breakpoint_pc - current_pc) / (xscale->trace.core_state == ARM_STATE_ARM ? 4 : 2); /* should never be negative or over 16, but verify */ if (gap_count < 0 || gap_count > 16) { LOG_WARNING("trace is suspect: excessive gap at end of trace"); return ERROR_OK;/* bail; large number or negative value no good */ } /* display remaining instructions */ for (i = 0; i < gap_count; i++) { xscale_display_instruction(target, current_pc, &instruction, cmd); current_pc += xscale->trace.core_state == ARM_STATE_ARM ? 4 : 2; } return ERROR_OK; } static const struct reg_arch_type xscale_reg_type = { .get = xscale_get_reg, .set = xscale_set_reg, }; static void xscale_build_reg_cache(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct xscale_reg *arch_info = malloc(sizeof(xscale_reg_arch_info)); int i; int num_regs = ARRAY_SIZE(xscale_reg_arch_info); (*cache_p) = arm_build_reg_cache(target, arm); (*cache_p)->next = malloc(sizeof(struct reg_cache)); cache_p = &(*cache_p)->next; /* fill in values for the xscale reg cache */ (*cache_p)->name = "XScale registers"; (*cache_p)->next = NULL; (*cache_p)->reg_list = calloc(num_regs, sizeof(struct reg)); (*cache_p)->num_regs = num_regs; for (i = 0; i < num_regs; i++) { (*cache_p)->reg_list[i].name = xscale_reg_list[i]; (*cache_p)->reg_list[i].value = calloc(4, 1); (*cache_p)->reg_list[i].dirty = false; (*cache_p)->reg_list[i].valid = false; (*cache_p)->reg_list[i].size = 32; (*cache_p)->reg_list[i].arch_info = &arch_info[i]; (*cache_p)->reg_list[i].type = &xscale_reg_type; (*cache_p)->reg_list[i].exist = true; arch_info[i] = xscale_reg_arch_info[i]; arch_info[i].target = target; } xscale->reg_cache = (*cache_p); } static void xscale_free_reg_cache(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); struct reg_cache *cache = xscale->reg_cache; for (unsigned int i = 0; i < ARRAY_SIZE(xscale_reg_arch_info); i++) free(cache->reg_list[i].value); free(cache->reg_list[0].arch_info); free(cache->reg_list); free(cache); arm_free_reg_cache(&xscale->arm); } static int xscale_init_target(struct command_context *cmd_ctx, struct target *target) { xscale_build_reg_cache(target); return ERROR_OK; } static void xscale_deinit_target(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); xscale_free_reg_cache(target); free(xscale); } static int xscale_init_arch_info(struct target *target, struct xscale_common *xscale, struct jtag_tap *tap) { struct arm *arm; uint32_t high_reset_branch, low_reset_branch; int i; arm = &xscale->arm; /* store architecture specific data */ xscale->common_magic = XSCALE_COMMON_MAGIC; /* PXA3xx with 11 bit IR shifts the JTAG instructions */ if (tap->ir_length == 11) xscale->xscale_variant = XSCALE_PXA3XX; else xscale->xscale_variant = XSCALE_IXP4XX_PXA2XX; /* the debug handler isn't installed (and thus not running) at this time */ xscale->handler_address = 0xfe000800; /* clear the vectors we keep locally for reference */ memset(xscale->low_vectors, 0, sizeof(xscale->low_vectors)); memset(xscale->high_vectors, 0, sizeof(xscale->high_vectors)); /* no user-specified vectors have been configured yet */ xscale->static_low_vectors_set = 0x0; xscale->static_high_vectors_set = 0x0; /* calculate branches to debug handler */ low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2; high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2; xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0); xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0); for (i = 1; i <= 7; i++) { xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0); xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0); } /* 64kB aligned region used for DCache cleaning */ xscale->cache_clean_address = 0xfffe0000; xscale->hold_rst = 0; xscale->external_debug_break = 0; xscale->ibcr_available = 2; xscale->ibcr0_used = 0; xscale->ibcr1_used = 0; xscale->dbr_available = 2; xscale->dbr0_used = 0; xscale->dbr1_used = 0; LOG_INFO("%s: hardware has 2 breakpoints and 2 watchpoints", target_name(target)); xscale->arm_bkpt = ARMV5_BKPT(0x0); xscale->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; xscale->vector_catch = 0x1; xscale->trace.data = NULL; xscale->trace.image = NULL; xscale->trace.mode = XSCALE_TRACE_DISABLED; xscale->trace.buffer_fill = 0; xscale->trace.fill_counter = 0; /* prepare ARMv4/5 specific information */ arm->arch_info = xscale; arm->core_type = ARM_CORE_TYPE_STD; arm->read_core_reg = xscale_read_core_reg; arm->write_core_reg = xscale_write_core_reg; arm->full_context = xscale_full_context; arm_init_arch_info(target, arm); xscale->armv4_5_mmu.armv4_5_cache.ctype = -1; xscale->armv4_5_mmu.get_ttb = xscale_get_ttb; xscale->armv4_5_mmu.read_memory = xscale_read_memory; xscale->armv4_5_mmu.write_memory = xscale_write_memory; xscale->armv4_5_mmu.disable_mmu_caches = xscale_disable_mmu_caches; xscale->armv4_5_mmu.enable_mmu_caches = xscale_enable_mmu_caches; xscale->armv4_5_mmu.has_tiny_pages = 1; xscale->armv4_5_mmu.mmu_enabled = 0; return ERROR_OK; } static int xscale_target_create(struct target *target, Jim_Interp *interp) { struct xscale_common *xscale; if (sizeof(xscale_debug_handler) > 0x800) { LOG_ERROR("debug_handler.bin: larger than 2kb"); return ERROR_FAIL; } xscale = calloc(1, sizeof(*xscale)); if (!xscale) return ERROR_FAIL; return xscale_init_arch_info(target, xscale, target->tap); } COMMAND_HANDLER(xscale_handle_debug_handler_command) { struct target *target = NULL; struct xscale_common *xscale; int retval; uint32_t handler_address; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; target = get_target(CMD_ARGV[0]); if (!target) { LOG_ERROR("target '%s' not defined", CMD_ARGV[0]); return ERROR_FAIL; } xscale = target_to_xscale(target); retval = xscale_verify_pointer(CMD, xscale); if (retval != ERROR_OK) return retval; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], handler_address); if (((handler_address >= 0x800) && (handler_address <= 0x1fef800)) || ((handler_address >= 0xfe000800) && (handler_address <= 0xfffff800))) xscale->handler_address = handler_address; else { LOG_ERROR( "xscale debug_handler <address> must be between 0x800 and 0x1fef800 or between 0xfe000800 and 0xfffff800"); return ERROR_FAIL; } return ERROR_OK; } COMMAND_HANDLER(xscale_handle_cache_clean_address_command) { struct target *target = NULL; struct xscale_common *xscale; int retval; uint32_t cache_clean_address; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; target = get_target(CMD_ARGV[0]); if (!target) { LOG_ERROR("target '%s' not defined", CMD_ARGV[0]); return ERROR_FAIL; } xscale = target_to_xscale(target); retval = xscale_verify_pointer(CMD, xscale); if (retval != ERROR_OK) return retval; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cache_clean_address); if (cache_clean_address & 0xffff) LOG_ERROR("xscale cache_clean_address <address> must be 64kb aligned"); else xscale->cache_clean_address = cache_clean_address; return ERROR_OK; } COMMAND_HANDLER(xscale_handle_cache_info_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int retval; retval = xscale_verify_pointer(CMD, xscale); if (retval != ERROR_OK) return retval; return armv4_5_handle_cache_info_command(CMD, &xscale->armv4_5_mmu.armv4_5_cache); } static int xscale_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical) { struct xscale_common *xscale = target_to_xscale(target); uint32_t cb; if (xscale->common_magic != XSCALE_COMMON_MAGIC) { LOG_ERROR(xscale_not); return ERROR_TARGET_INVALID; } uint32_t ret; int retval = armv4_5_mmu_translate_va(target, &xscale->armv4_5_mmu, virtual, &cb, &ret); if (retval != ERROR_OK) return retval; *physical = ret; return ERROR_OK; } static int xscale_mmu(struct target *target, int *enabled) { struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_INVALID; } *enabled = xscale->armv4_5_mmu.mmu_enabled; return ERROR_OK; } COMMAND_HANDLER(xscale_handle_mmu_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int retval; retval = xscale_verify_pointer(CMD, xscale); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } if (CMD_ARGC >= 1) { bool enable; COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable); if (enable) xscale_enable_mmu_caches(target, 1, 0, 0); else xscale_disable_mmu_caches(target, 1, 0, 0); xscale->armv4_5_mmu.mmu_enabled = enable; } command_print(CMD, "mmu %s", (xscale->armv4_5_mmu.mmu_enabled) ? "enabled" : "disabled"); return ERROR_OK; } COMMAND_HANDLER(xscale_handle_idcache_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int retval = xscale_verify_pointer(CMD, xscale); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } bool icache = false; if (strcmp(CMD_NAME, "icache") == 0) icache = true; if (CMD_ARGC >= 1) { bool enable; COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable); if (icache) { xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = enable; if (enable) xscale_enable_mmu_caches(target, 0, 0, 1); else xscale_disable_mmu_caches(target, 0, 0, 1); } else { xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = enable; if (enable) xscale_enable_mmu_caches(target, 0, 1, 0); else xscale_disable_mmu_caches(target, 0, 1, 0); } } bool enabled = icache ? xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled : xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled; const char *msg = enabled ? "enabled" : "disabled"; command_print(CMD, "%s %s", CMD_NAME, msg); return ERROR_OK; } static const struct { char name[15]; unsigned mask; } vec_ids[] = { { "fiq", DCSR_TF, }, { "irq", DCSR_TI, }, { "dabt", DCSR_TD, }, { "pabt", DCSR_TA, }, { "swi", DCSR_TS, }, { "undef", DCSR_TU, }, { "reset", DCSR_TR, }, }; COMMAND_HANDLER(xscale_handle_vector_catch_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int retval; uint32_t dcsr_value; uint32_t catch = 0; struct reg *dcsr_reg = &xscale->reg_cache->reg_list[XSCALE_DCSR]; retval = xscale_verify_pointer(CMD, xscale); if (retval != ERROR_OK) return retval; if (CMD_ARGC > 0) { if (CMD_ARGC == 1) { if (strcmp(CMD_ARGV[0], "all") == 0) { catch = DCSR_TRAP_MASK; CMD_ARGC--; } else if (strcmp(CMD_ARGV[0], "none") == 0) { catch = 0; CMD_ARGC--; } } while (CMD_ARGC-- > 0) { unsigned i; for (i = 0; i < ARRAY_SIZE(vec_ids); i++) { if (strcmp(CMD_ARGV[CMD_ARGC], vec_ids[i].name)) continue; catch |= vec_ids[i].mask; break; } if (i == ARRAY_SIZE(vec_ids)) { LOG_ERROR("No vector '%s'", CMD_ARGV[CMD_ARGC]); return ERROR_COMMAND_SYNTAX_ERROR; } } buf_set_u32(dcsr_reg->value, 0, 32, (buf_get_u32(dcsr_reg->value, 0, 32) & ~DCSR_TRAP_MASK) | catch); xscale_write_dcsr(target, -1, -1); } dcsr_value = buf_get_u32(dcsr_reg->value, 0, 32); for (unsigned i = 0; i < ARRAY_SIZE(vec_ids); i++) { command_print(CMD, "%15s: %s", vec_ids[i].name, (dcsr_value & vec_ids[i].mask) ? "catch" : "ignore"); } return ERROR_OK; } COMMAND_HANDLER(xscale_handle_vector_table_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int err = 0; int retval; retval = xscale_verify_pointer(CMD, xscale); if (retval != ERROR_OK) return retval; if (CMD_ARGC == 0) { /* print current settings */ int idx; command_print(CMD, "active user-set static vectors:"); for (idx = 1; idx < 8; idx++) if (xscale->static_low_vectors_set & (1 << idx)) command_print(CMD, "low %d: 0x%" PRIx32, idx, xscale->static_low_vectors[idx]); for (idx = 1; idx < 8; idx++) if (xscale->static_high_vectors_set & (1 << idx)) command_print(CMD, "high %d: 0x%" PRIx32, idx, xscale->static_high_vectors[idx]); return ERROR_OK; } if (CMD_ARGC != 3) err = 1; else { int idx; COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], idx); uint32_t vec; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], vec); if (idx < 1 || idx >= 8) err = 1; if (!err && strcmp(CMD_ARGV[0], "low") == 0) { xscale->static_low_vectors_set |= (1<<idx); xscale->static_low_vectors[idx] = vec; } else if (!err && (strcmp(CMD_ARGV[0], "high") == 0)) { xscale->static_high_vectors_set |= (1<<idx); xscale->static_high_vectors[idx] = vec; } else err = 1; } if (err) return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } COMMAND_HANDLER(xscale_handle_trace_buffer_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); uint32_t dcsr_value; int retval; retval = xscale_verify_pointer(CMD, xscale); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } if (CMD_ARGC >= 1) { if (strcmp("enable", CMD_ARGV[0]) == 0) xscale->trace.mode = XSCALE_TRACE_WRAP; /* default */ else if (strcmp("disable", CMD_ARGV[0]) == 0) xscale->trace.mode = XSCALE_TRACE_DISABLED; else return ERROR_COMMAND_SYNTAX_ERROR; } if (CMD_ARGC >= 2 && xscale->trace.mode != XSCALE_TRACE_DISABLED) { if (strcmp("fill", CMD_ARGV[1]) == 0) { int buffcount = 1; /* default */ if (CMD_ARGC >= 3) COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], buffcount); if (buffcount < 1) { /* invalid */ command_print(CMD, "fill buffer count must be > 0"); xscale->trace.mode = XSCALE_TRACE_DISABLED; return ERROR_COMMAND_SYNTAX_ERROR; } xscale->trace.buffer_fill = buffcount; xscale->trace.mode = XSCALE_TRACE_FILL; } else if (strcmp("wrap", CMD_ARGV[1]) == 0) xscale->trace.mode = XSCALE_TRACE_WRAP; else { xscale->trace.mode = XSCALE_TRACE_DISABLED; return ERROR_COMMAND_SYNTAX_ERROR; } } if (xscale->trace.mode != XSCALE_TRACE_DISABLED) { char fill_string[12]; sprintf(fill_string, "fill %d", xscale->trace.buffer_fill); command_print(CMD, "trace buffer enabled (%s)", (xscale->trace.mode == XSCALE_TRACE_FILL) ? fill_string : "wrap"); } else command_print(CMD, "trace buffer disabled"); dcsr_value = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32); if (xscale->trace.mode == XSCALE_TRACE_FILL) xscale_write_dcsr_sw(target, (dcsr_value & 0xfffffffc) | 2); else xscale_write_dcsr_sw(target, dcsr_value & 0xfffffffc); return ERROR_OK; } COMMAND_HANDLER(xscale_handle_trace_image_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int retval; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; retval = xscale_verify_pointer(CMD, xscale); if (retval != ERROR_OK) return retval; if (xscale->trace.image) { image_close(xscale->trace.image); free(xscale->trace.image); command_print(CMD, "previously loaded image found and closed"); } xscale->trace.image = malloc(sizeof(struct image)); xscale->trace.image->base_address_set = false; xscale->trace.image->start_address_set = false; /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ if (CMD_ARGC >= 2) { xscale->trace.image->base_address_set = true; COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], xscale->trace.image->base_address); } else xscale->trace.image->base_address_set = false; if (image_open(xscale->trace.image, CMD_ARGV[0], (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL) != ERROR_OK) { free(xscale->trace.image); xscale->trace.image = NULL; return ERROR_OK; } return ERROR_OK; } COMMAND_HANDLER(xscale_handle_dump_trace_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); struct xscale_trace_data *trace_data; struct fileio *file; int retval; retval = xscale_verify_pointer(CMD, xscale); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; trace_data = xscale->trace.data; if (!trace_data) { command_print(CMD, "no trace data collected"); return ERROR_OK; } if (fileio_open(&file, CMD_ARGV[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) return ERROR_OK; while (trace_data) { int i; fileio_write_u32(file, trace_data->chkpt0); fileio_write_u32(file, trace_data->chkpt1); fileio_write_u32(file, trace_data->last_instruction); fileio_write_u32(file, trace_data->depth); for (i = 0; i < trace_data->depth; i++) fileio_write_u32(file, trace_data->entries[i].data | ((trace_data->entries[i].type & 0xffff) << 16)); trace_data = trace_data->next; } fileio_close(file); return ERROR_OK; } COMMAND_HANDLER(xscale_handle_analyze_trace_buffer_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int retval; retval = xscale_verify_pointer(CMD, xscale); if (retval != ERROR_OK) return retval; xscale_analyze_trace(target, CMD); return ERROR_OK; } COMMAND_HANDLER(xscale_handle_cp15) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int retval; retval = xscale_verify_pointer(CMD, xscale); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } uint32_t reg_no = 0; struct reg *reg = NULL; if (CMD_ARGC > 0) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg_no); /*translate from xscale cp15 register no to openocd register*/ switch (reg_no) { case 0: reg_no = XSCALE_MAINID; break; case 1: reg_no = XSCALE_CTRL; break; case 2: reg_no = XSCALE_TTB; break; case 3: reg_no = XSCALE_DAC; break; case 5: reg_no = XSCALE_FSR; break; case 6: reg_no = XSCALE_FAR; break; case 13: reg_no = XSCALE_PID; break; case 15: reg_no = XSCALE_CPACCESS; break; default: command_print(CMD, "invalid register number"); return ERROR_COMMAND_SYNTAX_ERROR; } reg = &xscale->reg_cache->reg_list[reg_no]; } if (CMD_ARGC == 1) { uint32_t value; /* read cp15 control register */ xscale_get_reg(reg); value = buf_get_u32(reg->value, 0, 32); command_print(CMD, "%s (/%i): 0x%" PRIx32 "", reg->name, (int)(reg->size), value); } else if (CMD_ARGC == 2) { uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); /* send CP write request (command 0x41) */ xscale_send_u32(target, 0x41); /* send CP register number */ xscale_send_u32(target, reg_no); /* send CP register value */ xscale_send_u32(target, value); /* execute cpwait to ensure outstanding operations complete */ xscale_send_u32(target, 0x53); } else return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } static const struct command_registration xscale_exec_command_handlers[] = { { .name = "cache_info", .handler = xscale_handle_cache_info_command, .mode = COMMAND_EXEC, .help = "display information about CPU caches", .usage = "", }, { .name = "mmu", .handler = xscale_handle_mmu_command, .mode = COMMAND_EXEC, .help = "enable or disable the MMU", .usage = "['enable'|'disable']", }, { .name = "icache", .handler = xscale_handle_idcache_command, .mode = COMMAND_EXEC, .help = "display ICache state, optionally enabling or " "disabling it", .usage = "['enable'|'disable']", }, { .name = "dcache", .handler = xscale_handle_idcache_command, .mode = COMMAND_EXEC, .help = "display DCache state, optionally enabling or " "disabling it", .usage = "['enable'|'disable']", }, { .name = "vector_catch", .handler = xscale_handle_vector_catch_command, .mode = COMMAND_EXEC, .help = "set or display mask of vectors " "that should trigger debug entry", .usage = "['all'|'none'|'fiq'|'irq'|'dabt'|'pabt'|'swi'|'undef'|'reset']", }, { .name = "vector_table", .handler = xscale_handle_vector_table_command, .mode = COMMAND_EXEC, .help = "set vector table entry in mini-ICache, " "or display current tables", .usage = "[('high'|'low') index code]", }, { .name = "trace_buffer", .handler = xscale_handle_trace_buffer_command, .mode = COMMAND_EXEC, .help = "display trace buffer status, enable or disable " "tracing, and optionally reconfigure trace mode", .usage = "['enable'|'disable' ['fill' [number]|'wrap']]", }, { .name = "dump_trace", .handler = xscale_handle_dump_trace_command, .mode = COMMAND_EXEC, .help = "dump content of trace buffer to file", .usage = "filename", }, { .name = "analyze_trace", .handler = xscale_handle_analyze_trace_buffer_command, .mode = COMMAND_EXEC, .help = "analyze content of trace buffer", .usage = "", }, { .name = "trace_image", .handler = xscale_handle_trace_image_command, .mode = COMMAND_EXEC, .help = "load image from file to address (default 0)", .usage = "filename [offset [filetype]]", }, { .name = "cp15", .handler = xscale_handle_cp15, .mode = COMMAND_EXEC, .help = "Read or write coprocessor 15 register.", .usage = "register [value]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration xscale_any_command_handlers[] = { { .name = "debug_handler", .handler = xscale_handle_debug_handler_command, .mode = COMMAND_ANY, .help = "Change address used for debug handler.", .usage = "<target> <address>", }, { .name = "cache_clean_address", .handler = xscale_handle_cache_clean_address_command, .mode = COMMAND_ANY, .help = "Change address used for cleaning data cache.", .usage = "address", }, { .chain = xscale_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration xscale_command_handlers[] = { { .chain = arm_command_handlers, }, { .name = "xscale", .mode = COMMAND_ANY, .help = "xscale command group", .usage = "", .chain = xscale_any_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type xscale_target = { .name = "xscale", .poll = xscale_poll, .arch_state = xscale_arch_state, .halt = xscale_halt, .resume = xscale_resume, .step = xscale_step, .assert_reset = xscale_assert_reset, .deassert_reset = xscale_deassert_reset, /* REVISIT on some cores, allow exporting iwmmxt registers ... */ .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = xscale_read_memory, .read_phys_memory = xscale_read_phys_memory, .write_memory = xscale_write_memory, .write_phys_memory = xscale_write_phys_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = xscale_add_breakpoint, .remove_breakpoint = xscale_remove_breakpoint, .add_watchpoint = xscale_add_watchpoint, .remove_watchpoint = xscale_remove_watchpoint, .commands = xscale_command_handlers, .target_create = xscale_target_create, .init_target = xscale_init_target, .deinit_target = xscale_deinit_target, .virt2phys = xscale_virt2phys, .mmu = xscale_mmu }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/xscale.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_XSCALE_H #define OPENOCD_TARGET_XSCALE_H #include "arm.h" #include "armv4_5_mmu.h" #include "trace.h" #define XSCALE_COMMON_MAGIC 0x58534341U /* These four JTAG instructions are architecturally defined. * Lengths are core-specific; originally 5 bits, later 7. */ #define XSCALE_DBGRX 0x02 #define XSCALE_DBGTX 0x10 #define XSCALE_LDIC 0x07 #define XSCALE_SELDCSR 0x09 /* Possible CPU types */ #define XSCALE_IXP4XX_PXA2XX 0x0 #define XSCALE_PXA3XX 0x4 enum xscale_debug_reason { XSCALE_DBG_REASON_GENERIC, XSCALE_DBG_REASON_RESET, XSCALE_DBG_REASON_TB_FULL, }; enum xscale_trace_entry_type { XSCALE_TRACE_MESSAGE = 0x0, XSCALE_TRACE_ADDRESS = 0x1, }; struct xscale_trace_entry { uint8_t data; enum xscale_trace_entry_type type; }; struct xscale_trace_data { struct xscale_trace_entry *entries; int depth; uint32_t chkpt0; uint32_t chkpt1; uint32_t last_instruction; unsigned int num_checkpoints; struct xscale_trace_data *next; }; enum trace_mode { XSCALE_TRACE_DISABLED, XSCALE_TRACE_FILL, XSCALE_TRACE_WRAP }; struct xscale_trace { struct image *image; /* source for target opcodes */ struct xscale_trace_data *data; /* linked list of collected trace data */ int buffer_fill; /* maximum number of trace runs to read */ int fill_counter; /* running count during trace collection */ enum trace_mode mode; enum arm_state core_state; /* current core state (ARM, Thumb) */ }; struct xscale_common { unsigned int common_magic; /* armv4/5 common stuff */ struct arm arm; /* XScale registers (CP15, DBG) */ struct reg_cache *reg_cache; /* current state of the debug handler */ uint32_t handler_address; /* target-endian buffers with exception vectors */ uint32_t low_vectors[8]; uint32_t high_vectors[8]; /* static low vectors */ uint8_t static_low_vectors_set; /* bit field with static vectors set by the user */ uint8_t static_high_vectors_set; /* bit field with static vectors set by the user */ uint32_t static_low_vectors[8]; uint32_t static_high_vectors[8]; /* DCache cleaning */ uint32_t cache_clean_address; /* whether hold_rst and ext_dbg_break should be set */ int hold_rst; int external_debug_break; /* breakpoint / watchpoint handling */ int dbr_available; int dbr0_used; int dbr1_used; int ibcr_available; int ibcr0_used; int ibcr1_used; uint32_t arm_bkpt; uint16_t thumb_bkpt; uint8_t vector_catch; struct xscale_trace trace; int arch_debug_reason; /* MMU/Caches */ struct armv4_5_mmu_common armv4_5_mmu; uint32_t cp15_control_reg; int fast_memory_access; /* CPU variant */ int xscale_variant; }; static inline struct xscale_common * target_to_xscale(struct target *target) { return container_of(target->arch_info, struct xscale_common, arm); } struct xscale_reg { int dbg_handler_number; struct target *target; }; enum { XSCALE_MAINID, /* 0 */ XSCALE_CACHETYPE, XSCALE_CTRL, XSCALE_AUXCTRL, XSCALE_TTB, XSCALE_DAC, XSCALE_FSR, XSCALE_FAR, XSCALE_PID, XSCALE_CPACCESS, XSCALE_IBCR0, /* 10 */ XSCALE_IBCR1, XSCALE_DBR0, XSCALE_DBR1, XSCALE_DBCON, XSCALE_TBREG, XSCALE_CHKPT0, XSCALE_CHKPT1, XSCALE_DCSR, XSCALE_TX, XSCALE_RX, /* 20 */ XSCALE_TXRXCTRL, }; #define ERROR_XSCALE_NO_TRACE_DATA (-700) /* DCSR bit and field definitions */ #define DCSR_TR (1 << 16) #define DCSR_TU (1 << 17) #define DCSR_TS (1 << 18) #define DCSR_TA (1 << 19) #define DCSR_TD (1 << 20) #define DCSR_TI (1 << 22) #define DCSR_TF (1 << 23) #define DCSR_TRAP_MASK \ (DCSR_TF | DCSR_TI | DCSR_TD | DCSR_TA | DCSR_TS | DCSR_TU | DCSR_TR) #endif /* OPENOCD_TARGET_XSCALE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/xtensa/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libxtensa.la %C%_libxtensa_la_SOURCES = \ %D%/xtensa.c \ %D%/xtensa.h \ %D%/xtensa_chip.c \ %D%/xtensa_chip.h \ %D%/xtensa_debug_module.c \ %D%/xtensa_debug_module.h \ %D%/xtensa_fileio.c \ %D%/xtensa_fileio.h \ %D%/xtensa_regs.h ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/xtensa/xtensa.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Generic Xtensa target API for OpenOCD * * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * * Copyright (C) 2016-2019 Espressif Systems Ltd. * * Derived from esp108.c * * Author: Angus Gratton gus@projectgus.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdlib.h> #include <helper/time_support.h> #include <helper/align.h> #include <target/register.h> #include "xtensa_chip.h" #include "xtensa.h" /* Swap 4-bit Xtensa opcodes and fields */ #define XT_NIBSWAP8(V) \ ((((V) & 0x0F) << 4) \ | (((V) & 0xF0) >> 4)) #define XT_NIBSWAP16(V) \ ((((V) & 0x000F) << 12) \ | (((V) & 0x00F0) << 4) \ | (((V) & 0x0F00) >> 4) \ | (((V) & 0xF000) >> 12)) #define XT_NIBSWAP24(V) \ ((((V) & 0x00000F) << 20) \ | (((V) & 0x0000F0) << 12) \ | (((V) & 0x000F00) << 4) \ | (((V) & 0x00F000) >> 4) \ | (((V) & 0x0F0000) >> 12) \ | (((V) & 0xF00000) >> 20)) /* _XT_INS_FORMAT_*() * Instruction formatting converted from little-endian inputs * and shifted to the MSB-side of DIR for BE systems. */ #define _XT_INS_FORMAT_RSR(X, OPCODE, SR, T) \ (XT_ISBE(X) ? (XT_NIBSWAP24(OPCODE) \ | (((T) & 0x0F) << 16) \ | (((SR) & 0xFF) << 8)) << 8 \ : (OPCODE) \ | (((SR) & 0xFF) << 8) \ | (((T) & 0x0F) << 4)) #define _XT_INS_FORMAT_RRR(X, OPCODE, ST, R) \ (XT_ISBE(X) ? (XT_NIBSWAP24(OPCODE) \ | ((XT_NIBSWAP8((ST) & 0xFF)) << 12) \ | (((R) & 0x0F) << 8)) << 8 \ : (OPCODE) \ | (((ST) & 0xFF) << 4) \ | (((R) & 0x0F) << 12)) #define _XT_INS_FORMAT_RRRN(X, OPCODE, S, T, IMM4) \ (XT_ISBE(X) ? (XT_NIBSWAP16(OPCODE) \ | (((T) & 0x0F) << 8) \ | (((S) & 0x0F) << 4) \ | ((IMM4) & 0x0F)) << 16 \ : (OPCODE) \ | (((T) & 0x0F) << 4) \ | (((S) & 0x0F) << 8) \ | (((IMM4) & 0x0F) << 12)) #define _XT_INS_FORMAT_RRI8(X, OPCODE, R, S, T, IMM8) \ (XT_ISBE(X) ? (XT_NIBSWAP24(OPCODE) \ | (((T) & 0x0F) << 16) \ | (((S) & 0x0F) << 12) \ | (((R) & 0x0F) << 8) \ | ((IMM8) & 0xFF)) << 8 \ : (OPCODE) \ | (((IMM8) & 0xFF) << 16) \ | (((R) & 0x0F) << 12) \ | (((S) & 0x0F) << 8) \ | (((T) & 0x0F) << 4)) #define _XT_INS_FORMAT_RRI4(X, OPCODE, IMM4, R, S, T) \ (XT_ISBE(X) ? (XT_NIBSWAP24(OPCODE) \ | (((T) & 0x0F) << 16) \ | (((S) & 0x0F) << 12) \ | (((R) & 0x0F) << 8)) << 8 \ | ((IMM4) & 0x0F) \ : (OPCODE) \ | (((IMM4) & 0x0F) << 20) \ | (((R) & 0x0F) << 12) \ | (((S) & 0x0F) << 8) \ | (((T) & 0x0F) << 4)) /* Xtensa processor instruction opcodes */ /* "Return From Debug Operation" to Normal */ #define XT_INS_RFDO(X) (XT_ISBE(X) ? 0x000e1f << 8 : 0xf1e000) /* "Return From Debug and Dispatch" - allow sw debugging stuff to take over */ #define XT_INS_RFDD(X) (XT_ISBE(X) ? 0x010e1f << 8 : 0xf1e010) /* Load to DDR register, increase addr register */ #define XT_INS_LDDR32P(X, S) (XT_ISBE(X) ? (0x0E0700 | ((S) << 12)) << 8 : (0x0070E0 | ((S) << 8))) /* Store from DDR register, increase addr register */ #define XT_INS_SDDR32P(X, S) (XT_ISBE(X) ? (0x0F0700 | ((S) << 12)) << 8 : (0x0070F0 | ((S) << 8))) /* Load 32-bit Indirect from A(S)+4*IMM8 to A(T) */ #define XT_INS_L32I(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x002002, 0, S, T, IMM8) /* Load 16-bit Unsigned from A(S)+2*IMM8 to A(T) */ #define XT_INS_L16UI(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x001002, 0, S, T, IMM8) /* Load 8-bit Unsigned from A(S)+IMM8 to A(T) */ #define XT_INS_L8UI(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x000002, 0, S, T, IMM8) /* Store 32-bit Indirect to A(S)+4*IMM8 from A(T) */ #define XT_INS_S32I(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x006002, 0, S, T, IMM8) /* Store 16-bit to A(S)+2*IMM8 from A(T) */ #define XT_INS_S16I(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x005002, 0, S, T, IMM8) /* Store 8-bit to A(S)+IMM8 from A(T) */ #define XT_INS_S8I(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x004002, 0, S, T, IMM8) /* Cache Instructions */ #define XT_INS_IHI(X, S, IMM8) _XT_INS_FORMAT_RRI8(X, 0x0070E2, 0, S, 0, IMM8) #define XT_INS_DHWBI(X, S, IMM8) _XT_INS_FORMAT_RRI8(X, 0x007052, 0, S, 0, IMM8) #define XT_INS_DHWB(X, S, IMM8) _XT_INS_FORMAT_RRI8(X, 0x007042, 0, S, 0, IMM8) #define XT_INS_ISYNC(X) (XT_ISBE(X) ? 0x000200 << 8 : 0x002000) /* Control Instructions */ #define XT_INS_JX(X, S) (XT_ISBE(X) ? (0x050000 | ((S) << 12)) : (0x0000a0 | ((S) << 8))) #define XT_INS_CALL0(X, IMM18) (XT_ISBE(X) ? (0x500000 | ((IMM18) & 0x3ffff)) : (0x000005 | (((IMM18) & 0x3ffff) << 6))) /* Read Special Register */ #define XT_INS_RSR(X, SR, T) _XT_INS_FORMAT_RSR(X, 0x030000, SR, T) /* Write Special Register */ #define XT_INS_WSR(X, SR, T) _XT_INS_FORMAT_RSR(X, 0x130000, SR, T) /* Swap Special Register */ #define XT_INS_XSR(X, SR, T) _XT_INS_FORMAT_RSR(X, 0x610000, SR, T) /* Rotate Window by (-8..7) */ #define XT_INS_ROTW(X, N) (XT_ISBE(X) ? ((0x000804) | (((N) & 15) << 16)) << 8 : ((0x408000) | (((N) & 15) << 4))) /* Read User Register */ #define XT_INS_RUR(X, UR, T) _XT_INS_FORMAT_RRR(X, 0xE30000, UR, T) /* Write User Register */ #define XT_INS_WUR(X, UR, T) _XT_INS_FORMAT_RSR(X, 0xF30000, UR, T) /* Read Floating-Point Register */ #define XT_INS_RFR(X, FR, T) _XT_INS_FORMAT_RRR(X, 0xFA0000, ((FR << 4) | 0x4), T) /* Write Floating-Point Register */ #define XT_INS_WFR(X, FR, T) _XT_INS_FORMAT_RRR(X, 0xFA0000, ((T << 4) | 0x5), FR) #define XT_INS_L32E(X, R, S, T) _XT_INS_FORMAT_RRI4(X, 0x090000, 0, R, S, T) #define XT_INS_S32E(X, R, S, T) _XT_INS_FORMAT_RRI4(X, 0x490000, 0, R, S, T) #define XT_INS_L32E_S32E_MASK(X) (XT_ISBE(X) ? 0xF000FF << 8 : 0xFF000F) #define XT_INS_RFWO(X) (XT_ISBE(X) ? 0x004300 << 8 : 0x003400) #define XT_INS_RFWU(X) (XT_ISBE(X) ? 0x005300 << 8 : 0x003500) #define XT_INS_RFWO_RFWU_MASK(X) (XT_ISBE(X) ? 0xFFFFFF << 8 : 0xFFFFFF) #define XT_WATCHPOINTS_NUM_MAX 2 /* Special register number macro for DDR, PS, WB, A3, A4 registers. * These get used a lot so making a shortcut is useful. */ #define XT_SR_DDR (xtensa_regs[XT_REG_IDX_DDR].reg_num) #define XT_SR_PS (xtensa_regs[XT_REG_IDX_PS].reg_num) #define XT_SR_WB (xtensa_regs[XT_REG_IDX_WINDOWBASE].reg_num) #define XT_REG_A0 (xtensa_regs[XT_REG_IDX_AR0].reg_num) #define XT_REG_A3 (xtensa_regs[XT_REG_IDX_AR3].reg_num) #define XT_REG_A4 (xtensa_regs[XT_REG_IDX_AR4].reg_num) #define XT_PS_REG_NUM (0xe6U) #define XT_EPS_REG_NUM_BASE (0xc0U) /* (EPS2 - 2), for adding DBGLEVEL */ #define XT_EPC_REG_NUM_BASE (0xb0U) /* (EPC1 - 1), for adding DBGLEVEL */ #define XT_PC_REG_NUM_VIRTUAL (0xffU) /* Marker for computing PC (EPC[DBGLEVEL) */ #define XT_PC_DBREG_NUM_BASE (0x20U) /* External (i.e., GDB) access */ #define XT_NX_IBREAKC_BASE (0xc0U) /* (IBREAKC0..IBREAKC1) for NX */ #define XT_SW_BREAKPOINTS_MAX_NUM 32 #define XT_HW_IBREAK_MAX_NUM 2 #define XT_HW_DBREAK_MAX_NUM 2 struct xtensa_reg_desc xtensa_regs[XT_NUM_REGS] = { XT_MK_REG_DESC("pc", XT_PC_REG_NUM_VIRTUAL, XT_REG_SPECIAL, 0), XT_MK_REG_DESC("ar0", 0x00, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar1", 0x01, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar2", 0x02, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar3", 0x03, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar4", 0x04, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar5", 0x05, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar6", 0x06, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar7", 0x07, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar8", 0x08, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar9", 0x09, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar10", 0x0A, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar11", 0x0B, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar12", 0x0C, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar13", 0x0D, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar14", 0x0E, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar15", 0x0F, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar16", 0x10, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar17", 0x11, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar18", 0x12, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar19", 0x13, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar20", 0x14, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar21", 0x15, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar22", 0x16, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar23", 0x17, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar24", 0x18, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar25", 0x19, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar26", 0x1A, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar27", 0x1B, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar28", 0x1C, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar29", 0x1D, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar30", 0x1E, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar31", 0x1F, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar32", 0x20, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar33", 0x21, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar34", 0x22, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar35", 0x23, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar36", 0x24, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar37", 0x25, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar38", 0x26, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar39", 0x27, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar40", 0x28, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar41", 0x29, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar42", 0x2A, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar43", 0x2B, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar44", 0x2C, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar45", 0x2D, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar46", 0x2E, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar47", 0x2F, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar48", 0x30, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar49", 0x31, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar50", 0x32, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar51", 0x33, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar52", 0x34, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar53", 0x35, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar54", 0x36, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar55", 0x37, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar56", 0x38, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar57", 0x39, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar58", 0x3A, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar59", 0x3B, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar60", 0x3C, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar61", 0x3D, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar62", 0x3E, XT_REG_GENERAL, 0), XT_MK_REG_DESC("ar63", 0x3F, XT_REG_GENERAL, 0), XT_MK_REG_DESC("windowbase", 0x48, XT_REG_SPECIAL, 0), XT_MK_REG_DESC("windowstart", 0x49, XT_REG_SPECIAL, 0), XT_MK_REG_DESC("ps", XT_PS_REG_NUM, XT_REG_SPECIAL, 0), /* PS (not mapped through EPS[]) */ XT_MK_REG_DESC("ibreakenable", 0x60, XT_REG_SPECIAL, 0), XT_MK_REG_DESC("ddr", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD), XT_MK_REG_DESC("ibreaka0", 0x80, XT_REG_SPECIAL, 0), XT_MK_REG_DESC("ibreaka1", 0x81, XT_REG_SPECIAL, 0), XT_MK_REG_DESC("dbreaka0", 0x90, XT_REG_SPECIAL, 0), XT_MK_REG_DESC("dbreaka1", 0x91, XT_REG_SPECIAL, 0), XT_MK_REG_DESC("dbreakc0", 0xA0, XT_REG_SPECIAL, 0), XT_MK_REG_DESC("dbreakc1", 0xA1, XT_REG_SPECIAL, 0), XT_MK_REG_DESC("cpenable", 0xE0, XT_REG_SPECIAL, 0), XT_MK_REG_DESC("exccause", 0xE8, XT_REG_SPECIAL, 0), XT_MK_REG_DESC("debugcause", 0xE9, XT_REG_SPECIAL, 0), XT_MK_REG_DESC("icount", 0xEC, XT_REG_SPECIAL, 0), XT_MK_REG_DESC("icountlevel", 0xED, XT_REG_SPECIAL, 0), /* WARNING: For these registers, regnum points to the * index of the corresponding ARx registers, NOT to * the processor register number! */ XT_MK_REG_DESC("a0", XT_REG_IDX_AR0, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a1", XT_REG_IDX_AR1, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a2", XT_REG_IDX_AR2, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a3", XT_REG_IDX_AR3, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a4", XT_REG_IDX_AR4, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a5", XT_REG_IDX_AR5, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a6", XT_REG_IDX_AR6, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a7", XT_REG_IDX_AR7, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a8", XT_REG_IDX_AR8, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a9", XT_REG_IDX_AR9, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a10", XT_REG_IDX_AR10, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a11", XT_REG_IDX_AR11, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a12", XT_REG_IDX_AR12, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a13", XT_REG_IDX_AR13, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a14", XT_REG_IDX_AR14, XT_REG_RELGEN, 0), XT_MK_REG_DESC("a15", XT_REG_IDX_AR15, XT_REG_RELGEN, 0), }; /** * Types of memory used at xtensa target */ enum xtensa_mem_region_type { XTENSA_MEM_REG_IROM = 0x0, XTENSA_MEM_REG_IRAM, XTENSA_MEM_REG_DROM, XTENSA_MEM_REG_DRAM, XTENSA_MEM_REG_SRAM, XTENSA_MEM_REG_SROM, XTENSA_MEM_REGS_NUM }; /* Register definition as union for list allocation */ union xtensa_reg_val_u { xtensa_reg_val_t val; uint8_t buf[4]; }; static const struct xtensa_keyval_info_s xt_qerr[XT_QERR_NUM] = { { .chrval = "E00", .intval = ERROR_FAIL }, { .chrval = "E01", .intval = ERROR_FAIL }, { .chrval = "E02", .intval = ERROR_COMMAND_ARGUMENT_INVALID }, { .chrval = "E03", .intval = ERROR_FAIL }, }; /* Set to true for extra debug logging */ static const bool xtensa_extra_debug_log; /** * Gets a config for the specific mem type */ static inline const struct xtensa_local_mem_config *xtensa_get_mem_config( struct xtensa *xtensa, enum xtensa_mem_region_type type) { switch (type) { case XTENSA_MEM_REG_IROM: return &xtensa->core_config->irom; case XTENSA_MEM_REG_IRAM: return &xtensa->core_config->iram; case XTENSA_MEM_REG_DROM: return &xtensa->core_config->drom; case XTENSA_MEM_REG_DRAM: return &xtensa->core_config->dram; case XTENSA_MEM_REG_SRAM: return &xtensa->core_config->sram; case XTENSA_MEM_REG_SROM: return &xtensa->core_config->srom; default: return NULL; } } /** * Extracts an exact xtensa_local_mem_region_config from xtensa_local_mem_config * for a given address * Returns NULL if nothing found */ static inline const struct xtensa_local_mem_region_config *xtensa_memory_region_find( const struct xtensa_local_mem_config *mem, target_addr_t address) { for (unsigned int i = 0; i < mem->count; i++) { const struct xtensa_local_mem_region_config *region = &mem->regions[i]; if (address >= region->base && address < (region->base + region->size)) return region; } return NULL; } /** * Returns a corresponding xtensa_local_mem_region_config from the xtensa target * for a given address * Returns NULL if nothing found */ static inline const struct xtensa_local_mem_region_config *xtensa_target_memory_region_find( struct xtensa *xtensa, target_addr_t address) { const struct xtensa_local_mem_region_config *result; const struct xtensa_local_mem_config *mcgf; for (unsigned int mtype = 0; mtype < XTENSA_MEM_REGS_NUM; mtype++) { mcgf = xtensa_get_mem_config(xtensa, mtype); result = xtensa_memory_region_find(mcgf, address); if (result) return result; } return NULL; } static inline bool xtensa_is_cacheable(const struct xtensa_cache_config *cache, const struct xtensa_local_mem_config *mem, target_addr_t address) { if (!cache->size) return false; return xtensa_memory_region_find(mem, address); } static inline bool xtensa_is_icacheable(struct xtensa *xtensa, target_addr_t address) { return xtensa_is_cacheable(&xtensa->core_config->icache, &xtensa->core_config->iram, address) || xtensa_is_cacheable(&xtensa->core_config->icache, &xtensa->core_config->irom, address) || xtensa_is_cacheable(&xtensa->core_config->icache, &xtensa->core_config->sram, address) || xtensa_is_cacheable(&xtensa->core_config->icache, &xtensa->core_config->srom, address); } static inline bool xtensa_is_dcacheable(struct xtensa *xtensa, target_addr_t address) { return xtensa_is_cacheable(&xtensa->core_config->dcache, &xtensa->core_config->dram, address) || xtensa_is_cacheable(&xtensa->core_config->dcache, &xtensa->core_config->drom, address) || xtensa_is_cacheable(&xtensa->core_config->dcache, &xtensa->core_config->sram, address) || xtensa_is_cacheable(&xtensa->core_config->dcache, &xtensa->core_config->srom, address); } static int xtensa_core_reg_get(struct reg *reg) { /* We don't need this because we read all registers on halt anyway. */ struct xtensa *xtensa = (struct xtensa *)reg->arch_info; struct target *target = xtensa->target; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; if (!reg->exist) { if (strncmp(reg->name, "?0x", 3) == 0) { unsigned int regnum = strtoul(reg->name + 1, NULL, 0); LOG_WARNING("Read unknown register 0x%04x ignored", regnum); return ERROR_OK; } return ERROR_COMMAND_ARGUMENT_INVALID; } return ERROR_OK; } static int xtensa_core_reg_set(struct reg *reg, uint8_t *buf) { struct xtensa *xtensa = (struct xtensa *)reg->arch_info; struct target *target = xtensa->target; assert(reg->size <= 64 && "up to 64-bit regs are supported only!"); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; if (!reg->exist) { if (strncmp(reg->name, "?0x", 3) == 0) { unsigned int regnum = strtoul(reg->name + 1, NULL, 0); LOG_WARNING("Write unknown register 0x%04x ignored", regnum); return ERROR_OK; } return ERROR_COMMAND_ARGUMENT_INVALID; } buf_cpy(buf, reg->value, reg->size); if (xtensa->core_config->windowed) { /* If the user updates a potential scratch register, track for conflicts */ for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++) { if (strcmp(reg->name, xtensa->scratch_ars[s].chrval) == 0) { LOG_DEBUG("Scratch reg %s [0x%08" PRIx32 "] set from gdb", reg->name, buf_get_u32(reg->value, 0, 32)); LOG_DEBUG("scratch_ars mapping: a3/%s, a4/%s", xtensa->scratch_ars[XT_AR_SCRATCH_AR3].chrval, xtensa->scratch_ars[XT_AR_SCRATCH_AR4].chrval); xtensa->scratch_ars[s].intval = true; break; } } } reg->dirty = true; reg->valid = true; return ERROR_OK; } static const struct reg_arch_type xtensa_reg_type = { .get = xtensa_core_reg_get, .set = xtensa_core_reg_set, }; /* Convert a register index that's indexed relative to windowbase, to the real address. */ static enum xtensa_reg_id xtensa_windowbase_offset_to_canonical(struct xtensa *xtensa, enum xtensa_reg_id reg_idx, int windowbase) { unsigned int idx; if (reg_idx >= XT_REG_IDX_AR0 && reg_idx <= XT_REG_IDX_ARLAST) { idx = reg_idx - XT_REG_IDX_AR0; } else if (reg_idx >= XT_REG_IDX_A0 && reg_idx <= XT_REG_IDX_A15) { idx = reg_idx - XT_REG_IDX_A0; } else { LOG_ERROR("Error: can't convert register %d to non-windowbased register!", reg_idx); return -1; } /* Each windowbase value represents 4 registers on LX and 8 on NX */ int base_inc = (xtensa->core_config->core_type == XT_LX) ? 4 : 8; return ((idx + windowbase * base_inc) & (xtensa->core_config->aregs_num - 1)) + XT_REG_IDX_AR0; } static enum xtensa_reg_id xtensa_canonical_to_windowbase_offset(struct xtensa *xtensa, enum xtensa_reg_id reg_idx, int windowbase) { return xtensa_windowbase_offset_to_canonical(xtensa, reg_idx, -windowbase); } static void xtensa_mark_register_dirty(struct xtensa *xtensa, enum xtensa_reg_id reg_idx) { struct reg *reg_list = xtensa->core_cache->reg_list; reg_list[reg_idx].dirty = true; } static void xtensa_queue_exec_ins(struct xtensa *xtensa, uint32_t ins) { xtensa_queue_dbg_reg_write(xtensa, XDMREG_DIR0EXEC, ins); } static void xtensa_queue_exec_ins_wide(struct xtensa *xtensa, uint8_t *ops, uint8_t oplen) { const int max_oplen = 64; /* 8 DIRx regs: max width 64B */ if ((oplen > 0) && (oplen <= max_oplen)) { uint8_t ops_padded[max_oplen]; memcpy(ops_padded, ops, oplen); memset(ops_padded + oplen, 0, max_oplen - oplen); unsigned int oplenw = DIV_ROUND_UP(oplen, sizeof(uint32_t)); for (int32_t i = oplenw - 1; i > 0; i--) xtensa_queue_dbg_reg_write(xtensa, XDMREG_DIR0 + i, target_buffer_get_u32(xtensa->target, &ops_padded[sizeof(uint32_t)*i])); /* Write DIR0EXEC last */ xtensa_queue_dbg_reg_write(xtensa, XDMREG_DIR0EXEC, target_buffer_get_u32(xtensa->target, &ops_padded[0])); } } static int xtensa_queue_pwr_reg_write(struct xtensa *xtensa, unsigned int reg, uint32_t data) { struct xtensa_debug_module *dm = &xtensa->dbg_mod; return dm->pwr_ops->queue_reg_write(dm, reg, data); } /* NOTE: Assumes A3 has already been saved */ static int xtensa_window_state_save(struct target *target, uint32_t *woe) { struct xtensa *xtensa = target_to_xtensa(target); unsigned int woe_sr = (xtensa->core_config->core_type == XT_LX) ? XT_SR_PS : XT_SR_WB; uint32_t woe_dis; uint8_t woe_buf[4]; if (xtensa->core_config->windowed) { /* Save PS (LX) or WB (NX) and disable window overflow exceptions prior to AR save */ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, woe_sr, XT_REG_A3)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, woe_buf); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read %s (%d)!", (woe_sr == XT_SR_PS) ? "PS" : "WB", res); return res; } xtensa_core_status_check(target); *woe = buf_get_u32(woe_buf, 0, 32); woe_dis = *woe & ~((woe_sr == XT_SR_PS) ? XT_PS_WOE_MSK : XT_WB_S_MSK); LOG_TARGET_DEBUG(target, "Clearing %s (0x%08" PRIx32 " -> 0x%08" PRIx32 ")", (woe_sr == XT_SR_PS) ? "PS.WOE" : "WB.S", *woe, woe_dis); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, woe_dis); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, woe_sr, XT_REG_A3)); } return ERROR_OK; } /* NOTE: Assumes A3 has already been saved */ static void xtensa_window_state_restore(struct target *target, uint32_t woe) { struct xtensa *xtensa = target_to_xtensa(target); unsigned int woe_sr = (xtensa->core_config->core_type == XT_LX) ? XT_SR_PS : XT_SR_WB; if (xtensa->core_config->windowed) { /* Restore window overflow exception state */ xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, woe); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, woe_sr, XT_REG_A3)); LOG_TARGET_DEBUG(target, "Restored %s (0x%08" PRIx32 ")", (woe_sr == XT_SR_PS) ? "PS.WOE" : "WB", woe); } } static bool xtensa_reg_is_readable(int flags, int cpenable) { if (flags & XT_REGF_NOREAD) return false; if ((flags & XT_REGF_COPROC0) && (cpenable & BIT(0)) == 0) return false; return true; } static bool xtensa_scratch_regs_fixup(struct xtensa *xtensa, struct reg *reg_list, int i, int j, int a_idx, int ar_idx) { int a_name = (a_idx == XT_AR_SCRATCH_A3) ? 3 : 4; if (xtensa->scratch_ars[a_idx].intval && !xtensa->scratch_ars[ar_idx].intval) { LOG_DEBUG("AR conflict: a%d -> ar%d", a_name, j - XT_REG_IDX_AR0); memcpy(reg_list[j].value, reg_list[i].value, sizeof(xtensa_reg_val_t)); } else { LOG_DEBUG("AR conflict: ar%d -> a%d", j - XT_REG_IDX_AR0, a_name); memcpy(reg_list[i].value, reg_list[j].value, sizeof(xtensa_reg_val_t)); } return xtensa->scratch_ars[a_idx].intval && xtensa->scratch_ars[ar_idx].intval; } static int xtensa_write_dirty_registers(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); int res; xtensa_reg_val_t regval, windowbase = 0; bool scratch_reg_dirty = false, delay_cpenable = false; struct reg *reg_list = xtensa->core_cache->reg_list; unsigned int reg_list_size = xtensa->core_cache->num_regs; bool preserve_a3 = false; uint8_t a3_buf[4]; xtensa_reg_val_t a3 = 0, woe; unsigned int ms_idx = (xtensa->core_config->core_type == XT_NX) ? xtensa->nx_reg_idx[XT_NX_REG_IDX_MS] : reg_list_size; xtensa_reg_val_t ms = 0; bool restore_ms = false; LOG_TARGET_DEBUG(target, "start"); /* We need to write the dirty registers in the cache list back to the processor. * Start by writing the SFR/user registers. */ for (unsigned int i = 0; i < reg_list_size; i++) { struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs; unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS; if (reg_list[i].dirty) { if (rlist[ridx].type == XT_REG_SPECIAL || rlist[ridx].type == XT_REG_USER || rlist[ridx].type == XT_REG_FR) { scratch_reg_dirty = true; if (i == XT_REG_IDX_CPENABLE) { delay_cpenable = true; continue; } regval = xtensa_reg_get(target, i); LOG_TARGET_DEBUG(target, "Writing back reg %s (%d) val %08" PRIX32, reg_list[i].name, rlist[ridx].reg_num, regval); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, regval); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); if (reg_list[i].exist) { unsigned int reg_num = rlist[ridx].reg_num; if (rlist[ridx].type == XT_REG_USER) { xtensa_queue_exec_ins(xtensa, XT_INS_WUR(xtensa, reg_num, XT_REG_A3)); } else if (rlist[ridx].type == XT_REG_FR) { xtensa_queue_exec_ins(xtensa, XT_INS_WFR(xtensa, reg_num, XT_REG_A3)); } else {/*SFR */ if (reg_num == XT_PC_REG_NUM_VIRTUAL) { if (xtensa->core_config->core_type == XT_LX) { /* reg number of PC for debug interrupt depends on NDEBUGLEVEL */ reg_num = (XT_EPC_REG_NUM_BASE + xtensa->core_config->debug.irq_level); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, reg_num, XT_REG_A3)); } else { /* NX PC set through issuing a jump instruction */ xtensa_queue_exec_ins(xtensa, XT_INS_JX(xtensa, XT_REG_A3)); } } else if (i == ms_idx) { /* MS must be restored after ARs. This ensures ARs remain in correct * order even for reversed register groups (overflow/underflow). */ ms = regval; restore_ms = true; LOG_TARGET_DEBUG(target, "Delaying MS write: 0x%x", ms); } else { xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, reg_num, XT_REG_A3)); } } } reg_list[i].dirty = false; } } } if (scratch_reg_dirty) xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3); if (delay_cpenable) { regval = xtensa_reg_get(target, XT_REG_IDX_CPENABLE); LOG_TARGET_DEBUG(target, "Writing back reg cpenable (224) val %08" PRIX32, regval); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, regval); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, xtensa_regs[XT_REG_IDX_CPENABLE].reg_num, XT_REG_A3)); reg_list[XT_REG_IDX_CPENABLE].dirty = false; } preserve_a3 = (xtensa->core_config->windowed) || (xtensa->core_config->core_type == XT_NX); if (preserve_a3) { /* Save (windowed) A3 for scratch use */ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, a3_buf); res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) return res; xtensa_core_status_check(target); a3 = buf_get_u32(a3_buf, 0, 32); } if (xtensa->core_config->windowed) { res = xtensa_window_state_save(target, &woe); if (res != ERROR_OK) return res; /* Grab the windowbase, we need it. */ uint32_t wb_idx = (xtensa->core_config->core_type == XT_LX) ? XT_REG_IDX_WINDOWBASE : xtensa->nx_reg_idx[XT_NX_REG_IDX_WB]; windowbase = xtensa_reg_get(target, wb_idx); if (xtensa->core_config->core_type == XT_NX) windowbase = (windowbase & XT_WB_P_MSK) >> XT_WB_P_SHIFT; /* Check if there are mismatches between the ARx and corresponding Ax registers. * When the user sets a register on a windowed config, xt-gdb may set the ARx * register directly. Thus we take ARx as priority over Ax if both are dirty * and it's unclear if the user set one over the other explicitly. */ for (unsigned int i = XT_REG_IDX_A0; i <= XT_REG_IDX_A15; i++) { unsigned int j = xtensa_windowbase_offset_to_canonical(xtensa, i, windowbase); if (reg_list[i].dirty && reg_list[j].dirty) { if (memcmp(reg_list[i].value, reg_list[j].value, sizeof(xtensa_reg_val_t)) != 0) { bool show_warning = true; if (i == XT_REG_IDX_A3) show_warning = xtensa_scratch_regs_fixup(xtensa, reg_list, i, j, XT_AR_SCRATCH_A3, XT_AR_SCRATCH_AR3); else if (i == XT_REG_IDX_A4) show_warning = xtensa_scratch_regs_fixup(xtensa, reg_list, i, j, XT_AR_SCRATCH_A4, XT_AR_SCRATCH_AR4); if (show_warning) LOG_WARNING( "Warning: Both A%d [0x%08" PRIx32 "] as well as its underlying physical register " "(AR%d) [0x%08" PRIx32 "] are dirty and differ in value", i - XT_REG_IDX_A0, buf_get_u32(reg_list[i].value, 0, 32), j - XT_REG_IDX_AR0, buf_get_u32(reg_list[j].value, 0, 32)); } } } } /* Write A0-A16. */ for (unsigned int i = 0; i < 16; i++) { if (reg_list[XT_REG_IDX_A0 + i].dirty) { regval = xtensa_reg_get(target, XT_REG_IDX_A0 + i); LOG_TARGET_DEBUG(target, "Writing back reg %s value %08" PRIX32 ", num =%i", xtensa_regs[XT_REG_IDX_A0 + i].name, regval, xtensa_regs[XT_REG_IDX_A0 + i].reg_num); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, regval); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, i)); reg_list[XT_REG_IDX_A0 + i].dirty = false; if (i == 3) { /* Avoid stomping A3 during restore at end of function */ a3 = regval; } } } if (xtensa->core_config->windowed) { /* Now write AR registers */ for (unsigned int j = 0; j < XT_REG_IDX_ARLAST; j += 16) { /* Write the 16 registers we can see */ for (unsigned int i = 0; i < 16; i++) { if (i + j < xtensa->core_config->aregs_num) { enum xtensa_reg_id realadr = xtensa_windowbase_offset_to_canonical(xtensa, XT_REG_IDX_AR0 + i + j, windowbase); /* Write back any dirty un-windowed registers */ if (reg_list[realadr].dirty) { regval = xtensa_reg_get(target, realadr); LOG_TARGET_DEBUG( target, "Writing back reg %s value %08" PRIX32 ", num =%i", xtensa_regs[realadr].name, regval, xtensa_regs[realadr].reg_num); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, regval); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, xtensa_regs[XT_REG_IDX_AR0 + i].reg_num)); reg_list[realadr].dirty = false; if ((i + j) == 3) /* Avoid stomping AR during A3 restore at end of function */ a3 = regval; } } } /* Now rotate the window so we'll see the next 16 registers. The final rotate * will wraparound, leaving us in the state we were. * Each ROTW rotates 4 registers on LX and 8 on NX */ int rotw_arg = (xtensa->core_config->core_type == XT_LX) ? 4 : 2; xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(xtensa, rotw_arg)); } xtensa_window_state_restore(target, woe); for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++) xtensa->scratch_ars[s].intval = false; } if (restore_ms) { uint32_t ms_regno = xtensa->optregs[ms_idx - XT_NUM_REGS].reg_num; xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, ms); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, ms_regno, XT_REG_A3)); LOG_TARGET_DEBUG(target, "Delayed MS (0x%x) write complete: 0x%x", ms_regno, ms); } if (preserve_a3) { xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, a3); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); } res = xtensa_dm_queue_execute(&xtensa->dbg_mod); xtensa_core_status_check(target); return res; } static inline bool xtensa_is_stopped(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); return xtensa->dbg_mod.core_status.dsr & OCDDSR_STOPPED; } int xtensa_examine(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); unsigned int cmd = PWRCTL_DEBUGWAKEUP(xtensa) | PWRCTL_MEMWAKEUP(xtensa) | PWRCTL_COREWAKEUP(xtensa); LOG_DEBUG("coreid = %d", target->coreid); if (xtensa->core_config->core_type == XT_UNDEF) { LOG_ERROR("XTensa core not configured; is xtensa-core-openocd.cfg missing?"); return ERROR_FAIL; } xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd); xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd | PWRCTL_JTAGDEBUGUSE(xtensa)); xtensa_dm_queue_enable(&xtensa->dbg_mod); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) return res; if (!xtensa_dm_is_online(&xtensa->dbg_mod)) { LOG_ERROR("Unexpected OCD_ID = %08" PRIx32, xtensa->dbg_mod.device_id); return ERROR_TARGET_FAILURE; } LOG_DEBUG("OCD_ID = %08" PRIx32, xtensa->dbg_mod.device_id); target_set_examined(target); xtensa_smpbreak_write(xtensa, xtensa->smp_break); return ERROR_OK; } int xtensa_wakeup(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); unsigned int cmd = PWRCTL_DEBUGWAKEUP(xtensa) | PWRCTL_MEMWAKEUP(xtensa) | PWRCTL_COREWAKEUP(xtensa); if (xtensa->reset_asserted) cmd |= PWRCTL_CORERESET(xtensa); xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd); /* TODO: can we join this with the write above? */ xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd | PWRCTL_JTAGDEBUGUSE(xtensa)); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); return xtensa_dm_queue_execute(&xtensa->dbg_mod); } int xtensa_smpbreak_write(struct xtensa *xtensa, uint32_t set) { uint32_t dsr_data = 0x00110000; uint32_t clear = (set | OCDDCR_ENABLEOCD) ^ (OCDDCR_BREAKINEN | OCDDCR_BREAKOUTEN | OCDDCR_RUNSTALLINEN | OCDDCR_DEBUGMODEOUTEN | OCDDCR_ENABLEOCD); LOG_TARGET_DEBUG(xtensa->target, "write smpbreak set=0x%" PRIx32 " clear=0x%" PRIx32, set, clear); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DCRSET, set | OCDDCR_ENABLEOCD); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DCRCLR, clear); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DSR, dsr_data); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); return xtensa_dm_queue_execute(&xtensa->dbg_mod); } int xtensa_smpbreak_set(struct target *target, uint32_t set) { struct xtensa *xtensa = target_to_xtensa(target); int res = ERROR_OK; xtensa->smp_break = set; if (target_was_examined(target)) res = xtensa_smpbreak_write(xtensa, xtensa->smp_break); LOG_TARGET_DEBUG(target, "set smpbreak=%" PRIx32 ", state=%i", set, target->state); return res; } int xtensa_smpbreak_read(struct xtensa *xtensa, uint32_t *val) { uint8_t dcr_buf[sizeof(uint32_t)]; xtensa_queue_dbg_reg_read(xtensa, XDMREG_DCRSET, dcr_buf); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); *val = buf_get_u32(dcr_buf, 0, 32); return res; } int xtensa_smpbreak_get(struct target *target, uint32_t *val) { struct xtensa *xtensa = target_to_xtensa(target); *val = xtensa->smp_break; return ERROR_OK; } static inline xtensa_reg_val_t xtensa_reg_get_value(struct reg *reg) { return buf_get_u32(reg->value, 0, 32); } static inline void xtensa_reg_set_value(struct reg *reg, xtensa_reg_val_t value) { buf_set_u32(reg->value, 0, 32, value); reg->dirty = true; } static int xtensa_imprecise_exception_occurred(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); for (enum xtensa_nx_reg_idx idx = XT_NX_REG_IDX_IEVEC; idx <= XT_NX_REG_IDX_MESR; idx++) { enum xtensa_reg_id ridx = xtensa->nx_reg_idx[idx]; if (xtensa->nx_reg_idx[idx]) { xtensa_reg_val_t reg = xtensa_reg_get(target, xtensa->nx_reg_idx[idx]); if (reg & XT_IMPR_EXC_MSK) { LOG_TARGET_DEBUG(target, "Imprecise exception: %s: 0x%x", xtensa->core_cache->reg_list[ridx].name, reg); return true; } } } return false; } static void xtensa_imprecise_exception_clear(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); for (enum xtensa_nx_reg_idx idx = XT_NX_REG_IDX_IEVEC; idx <= XT_NX_REG_IDX_MESRCLR; idx++) { enum xtensa_reg_id ridx = xtensa->nx_reg_idx[idx]; if (ridx && idx != XT_NX_REG_IDX_MESR) { xtensa_reg_val_t value = (idx == XT_NX_REG_IDX_MESRCLR) ? XT_MESRCLR_IMPR_EXC_MSK : 0; xtensa_reg_set(target, ridx, value); LOG_TARGET_DEBUG(target, "Imprecise exception: clearing %s (0x%x)", xtensa->core_cache->reg_list[ridx].name, value); } } } int xtensa_core_status_check(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); int res, needclear = 0, needimprclear = 0; xtensa_dm_core_status_read(&xtensa->dbg_mod); xtensa_dsr_t dsr = xtensa_dm_core_status_get(&xtensa->dbg_mod); LOG_TARGET_DEBUG(target, "DSR (%08" PRIX32 ")", dsr); if (dsr & OCDDSR_EXECBUSY) { if (!xtensa->suppress_dsr_errors) LOG_TARGET_ERROR(target, "DSR (%08" PRIX32 ") indicates target still busy!", dsr); needclear = 1; } if (dsr & OCDDSR_EXECEXCEPTION) { if (!xtensa->suppress_dsr_errors) LOG_TARGET_ERROR(target, "DSR (%08" PRIX32 ") indicates DIR instruction generated an exception!", dsr); needclear = 1; } if (dsr & OCDDSR_EXECOVERRUN) { if (!xtensa->suppress_dsr_errors) LOG_TARGET_ERROR(target, "DSR (%08" PRIX32 ") indicates DIR instruction generated an overrun!", dsr); needclear = 1; } if (xtensa->core_config->core_type == XT_NX && (xtensa_imprecise_exception_occurred(target))) { if (!xtensa->suppress_dsr_errors) LOG_TARGET_ERROR(target, "%s: Imprecise exception occurred!", target_name(target)); needclear = 1; needimprclear = 1; } if (needclear) { res = xtensa_dm_core_status_clear(&xtensa->dbg_mod, OCDDSR_EXECEXCEPTION | OCDDSR_EXECOVERRUN); if (res != ERROR_OK && !xtensa->suppress_dsr_errors) LOG_TARGET_ERROR(target, "clearing DSR failed!"); if (xtensa->core_config->core_type == XT_NX && needimprclear) xtensa_imprecise_exception_clear(target); return ERROR_FAIL; } return ERROR_OK; } xtensa_reg_val_t xtensa_reg_get(struct target *target, enum xtensa_reg_id reg_id) { struct xtensa *xtensa = target_to_xtensa(target); struct reg *reg = &xtensa->core_cache->reg_list[reg_id]; return xtensa_reg_get_value(reg); } void xtensa_reg_set(struct target *target, enum xtensa_reg_id reg_id, xtensa_reg_val_t value) { struct xtensa *xtensa = target_to_xtensa(target); struct reg *reg = &xtensa->core_cache->reg_list[reg_id]; if (xtensa_reg_get_value(reg) == value) return; xtensa_reg_set_value(reg, value); } /* Set Ax (XT_REG_RELGEN) register along with its underlying ARx (XT_REG_GENERAL) */ void xtensa_reg_set_deep_relgen(struct target *target, enum xtensa_reg_id a_idx, xtensa_reg_val_t value) { struct xtensa *xtensa = target_to_xtensa(target); uint32_t wb_idx = (xtensa->core_config->core_type == XT_LX) ? XT_REG_IDX_WINDOWBASE : xtensa->nx_reg_idx[XT_NX_REG_IDX_WB]; uint32_t windowbase = (xtensa->core_config->windowed ? xtensa_reg_get(target, wb_idx) : 0); if (xtensa->core_config->core_type == XT_NX) windowbase = (windowbase & XT_WB_P_MSK) >> XT_WB_P_SHIFT; int ar_idx = xtensa_windowbase_offset_to_canonical(xtensa, a_idx, windowbase); xtensa_reg_set(target, a_idx, value); xtensa_reg_set(target, ar_idx, value); } /* Read cause for entering halted state; return bitmask in DEBUGCAUSE_* format */ uint32_t xtensa_cause_get(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); if (xtensa->core_config->core_type == XT_LX) { /* LX cause in DEBUGCAUSE */ return xtensa_reg_get(target, XT_REG_IDX_DEBUGCAUSE); } if (xtensa->nx_stop_cause & DEBUGCAUSE_VALID) return xtensa->nx_stop_cause; /* NX cause determined from DSR.StopCause */ if (xtensa_dm_core_status_read(&xtensa->dbg_mod) != ERROR_OK) { LOG_TARGET_ERROR(target, "Read DSR error"); } else { uint32_t dsr = xtensa_dm_core_status_get(&xtensa->dbg_mod); /* NX causes are prioritized; only 1 bit can be set */ switch ((dsr & OCDDSR_STOPCAUSE) >> OCDDSR_STOPCAUSE_SHIFT) { case OCDDSR_STOPCAUSE_DI: xtensa->nx_stop_cause = DEBUGCAUSE_DI; break; case OCDDSR_STOPCAUSE_SS: xtensa->nx_stop_cause = DEBUGCAUSE_IC; break; case OCDDSR_STOPCAUSE_IB: xtensa->nx_stop_cause = DEBUGCAUSE_IB; break; case OCDDSR_STOPCAUSE_B: case OCDDSR_STOPCAUSE_B1: xtensa->nx_stop_cause = DEBUGCAUSE_BI; break; case OCDDSR_STOPCAUSE_BN: xtensa->nx_stop_cause = DEBUGCAUSE_BN; break; case OCDDSR_STOPCAUSE_DB0: case OCDDSR_STOPCAUSE_DB1: xtensa->nx_stop_cause = DEBUGCAUSE_DB; break; default: LOG_TARGET_ERROR(target, "Unknown stop cause (DSR: 0x%08x)", dsr); break; } if (xtensa->nx_stop_cause) xtensa->nx_stop_cause |= DEBUGCAUSE_VALID; } return xtensa->nx_stop_cause; } void xtensa_cause_clear(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); if (xtensa->core_config->core_type == XT_LX) { xtensa_reg_set(target, XT_REG_IDX_DEBUGCAUSE, 0); xtensa->core_cache->reg_list[XT_REG_IDX_DEBUGCAUSE].dirty = false; } else { /* NX DSR.STOPCAUSE is not writeable; clear cached copy but leave it valid */ xtensa->nx_stop_cause = DEBUGCAUSE_VALID; } } void xtensa_cause_reset(struct target *target) { /* Clear DEBUGCAUSE_VALID to trigger re-read (on NX) */ struct xtensa *xtensa = target_to_xtensa(target); xtensa->nx_stop_cause = 0; } int xtensa_assert_reset(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); LOG_TARGET_DEBUG(target, "target_number=%i, begin", target->target_number); xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, PWRCTL_JTAGDEBUGUSE(xtensa) | PWRCTL_DEBUGWAKEUP(xtensa) | PWRCTL_MEMWAKEUP(xtensa) | PWRCTL_COREWAKEUP(xtensa) | PWRCTL_CORERESET(xtensa)); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) return res; /* registers are now invalid */ xtensa->reset_asserted = true; register_cache_invalidate(xtensa->core_cache); target->state = TARGET_RESET; return ERROR_OK; } int xtensa_deassert_reset(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); LOG_TARGET_DEBUG(target, "halt=%d", target->reset_halt); if (target->reset_halt) xtensa_queue_dbg_reg_write(xtensa, XDMREG_DCRSET, OCDDCR_ENABLEOCD | OCDDCR_DEBUGINTERRUPT); xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, PWRCTL_JTAGDEBUGUSE(xtensa) | PWRCTL_DEBUGWAKEUP(xtensa) | PWRCTL_MEMWAKEUP(xtensa) | PWRCTL_COREWAKEUP(xtensa)); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) return res; target->state = TARGET_RUNNING; xtensa->reset_asserted = false; return res; } int xtensa_soft_reset_halt(struct target *target) { LOG_TARGET_DEBUG(target, "begin"); return xtensa_assert_reset(target); } int xtensa_fetch_all_regs(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); struct reg *reg_list = xtensa->core_cache->reg_list; unsigned int reg_list_size = xtensa->core_cache->num_regs; xtensa_reg_val_t cpenable = 0, windowbase = 0, a0 = 0, a3; unsigned int ms_idx = reg_list_size; uint32_t ms = 0; uint32_t woe; uint8_t a0_buf[4], a3_buf[4], ms_buf[4]; bool debug_dsrs = !xtensa->regs_fetched || LOG_LEVEL_IS(LOG_LVL_DEBUG); union xtensa_reg_val_u *regvals = calloc(reg_list_size, sizeof(*regvals)); if (!regvals) { LOG_TARGET_ERROR(target, "unable to allocate memory for regvals!"); return ERROR_FAIL; } union xtensa_reg_val_u *dsrs = calloc(reg_list_size, sizeof(*dsrs)); if (!dsrs) { LOG_TARGET_ERROR(target, "unable to allocate memory for dsrs!"); free(regvals); return ERROR_FAIL; } LOG_TARGET_DEBUG(target, "start"); /* Save (windowed) A3 so cache matches physical AR3; A3 usable as scratch */ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, a3_buf); if (xtensa->core_config->core_type == XT_NX) { /* Save (windowed) A0 as well--it will be required for reading PC */ xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A0)); xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, a0_buf); /* Set MS.DispSt, clear MS.DE prior to accessing ARs. This ensures ARs remain * in correct order even for reversed register groups (overflow/underflow). */ ms_idx = xtensa->nx_reg_idx[XT_NX_REG_IDX_MS]; uint32_t ms_regno = xtensa->optregs[ms_idx - XT_NUM_REGS].reg_num; xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, ms_regno, XT_REG_A3)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, ms_buf); LOG_TARGET_DEBUG(target, "Overriding MS (0x%x): 0x%x", ms_regno, XT_MS_DISPST_DBG); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, XT_MS_DISPST_DBG); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, ms_regno, XT_REG_A3)); } int res = xtensa_window_state_save(target, &woe); if (res != ERROR_OK) goto xtensa_fetch_all_regs_done; /* Assume the CPU has just halted. We now want to fill the register cache with all the * register contents GDB needs. For speed, we pipeline all the read operations, execute them * in one go, then sort everything out from the regvals variable. */ /* Start out with AREGS; we can reach those immediately. Grab them per 16 registers. */ for (unsigned int j = 0; j < XT_AREGS_NUM_MAX; j += 16) { /*Grab the 16 registers we can see */ for (unsigned int i = 0; i < 16; i++) { if (i + j < xtensa->core_config->aregs_num) { xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, xtensa_regs[XT_REG_IDX_AR0 + i].reg_num)); xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, regvals[XT_REG_IDX_AR0 + i + j].buf); if (debug_dsrs) xtensa_queue_dbg_reg_read(xtensa, XDMREG_DSR, dsrs[XT_REG_IDX_AR0 + i + j].buf); } } if (xtensa->core_config->windowed) { /* Now rotate the window so we'll see the next 16 registers. The final rotate * will wraparound, leaving us in the state we were. * Each ROTW rotates 4 registers on LX and 8 on NX */ int rotw_arg = (xtensa->core_config->core_type == XT_LX) ? 4 : 2; xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(xtensa, rotw_arg)); } } xtensa_window_state_restore(target, woe); if (xtensa->core_config->coproc) { /* As the very first thing after AREGS, go grab CPENABLE */ xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, xtensa_regs[XT_REG_IDX_CPENABLE].reg_num, XT_REG_A3)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, regvals[XT_REG_IDX_CPENABLE].buf); } res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_ERROR("Failed to read ARs (%d)!", res); goto xtensa_fetch_all_regs_done; } xtensa_core_status_check(target); a3 = buf_get_u32(a3_buf, 0, 32); if (xtensa->core_config->core_type == XT_NX) { a0 = buf_get_u32(a0_buf, 0, 32); ms = buf_get_u32(ms_buf, 0, 32); } if (xtensa->core_config->coproc) { cpenable = buf_get_u32(regvals[XT_REG_IDX_CPENABLE].buf, 0, 32); /* Enable all coprocessors (by setting all bits in CPENABLE) so we can read FP and user registers. */ xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, 0xffffffff); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, xtensa_regs[XT_REG_IDX_CPENABLE].reg_num, XT_REG_A3)); /* Save CPENABLE; flag dirty later (when regcache updated) so original value is always restored */ LOG_TARGET_DEBUG(target, "CPENABLE: was 0x%" PRIx32 ", all enabled", cpenable); xtensa_reg_set(target, XT_REG_IDX_CPENABLE, cpenable); } /* We're now free to use any of A0-A15 as scratch registers * Grab the SFRs and user registers first. We use A3 as a scratch register. */ for (unsigned int i = 0; i < reg_list_size; i++) { struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs; unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS; if (xtensa_reg_is_readable(rlist[ridx].flags, cpenable) && rlist[ridx].exist) { bool reg_fetched = true; unsigned int reg_num = rlist[ridx].reg_num; switch (rlist[ridx].type) { case XT_REG_USER: xtensa_queue_exec_ins(xtensa, XT_INS_RUR(xtensa, reg_num, XT_REG_A3)); break; case XT_REG_FR: xtensa_queue_exec_ins(xtensa, XT_INS_RFR(xtensa, reg_num, XT_REG_A3)); break; case XT_REG_SPECIAL: if (reg_num == XT_PC_REG_NUM_VIRTUAL) { if (xtensa->core_config->core_type == XT_LX) { /* reg number of PC for debug interrupt depends on NDEBUGLEVEL */ reg_num = XT_EPC_REG_NUM_BASE + xtensa->core_config->debug.irq_level; xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3)); } else { /* NX PC read through CALL0(0) and reading A0 */ xtensa_queue_exec_ins(xtensa, XT_INS_CALL0(xtensa, 0)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A0)); xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, regvals[i].buf); xtensa_queue_dbg_reg_read(xtensa, XDMREG_DSR, dsrs[i].buf); reg_fetched = false; } } else if ((xtensa->core_config->core_type == XT_LX) && (reg_num == xtensa_regs[XT_REG_IDX_PS].reg_num)) { /* reg number of PS for debug interrupt depends on NDEBUGLEVEL */ reg_num = XT_EPS_REG_NUM_BASE + xtensa->core_config->debug.irq_level; xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3)); } else if (reg_num == xtensa_regs[XT_REG_IDX_CPENABLE].reg_num) { /* CPENABLE already read/updated; don't re-read */ reg_fetched = false; break; } else { xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3)); } break; default: reg_fetched = false; } if (reg_fetched) { xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, regvals[i].buf); if (debug_dsrs) xtensa_queue_dbg_reg_read(xtensa, XDMREG_DSR, dsrs[i].buf); } } } /* Ok, send the whole mess to the CPU. */ res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_ERROR("Failed to fetch AR regs!"); goto xtensa_fetch_all_regs_done; } xtensa_core_status_check(target); if (debug_dsrs) { /* DSR checking: follows order in which registers are requested. */ for (unsigned int i = 0; i < reg_list_size; i++) { struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs; unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS; if (xtensa_reg_is_readable(rlist[ridx].flags, cpenable) && rlist[ridx].exist && (rlist[ridx].type != XT_REG_DEBUG) && (rlist[ridx].type != XT_REG_RELGEN) && (rlist[ridx].type != XT_REG_TIE) && (rlist[ridx].type != XT_REG_OTHER)) { if (buf_get_u32(dsrs[i].buf, 0, 32) & OCDDSR_EXECEXCEPTION) { LOG_ERROR("Exception reading %s!", reg_list[i].name); res = ERROR_FAIL; goto xtensa_fetch_all_regs_done; } } } } if (xtensa->core_config->windowed) { /* We need the windowbase to decode the general addresses. */ uint32_t wb_idx = (xtensa->core_config->core_type == XT_LX) ? XT_REG_IDX_WINDOWBASE : xtensa->nx_reg_idx[XT_NX_REG_IDX_WB]; windowbase = buf_get_u32(regvals[wb_idx].buf, 0, 32); if (xtensa->core_config->core_type == XT_NX) windowbase = (windowbase & XT_WB_P_MSK) >> XT_WB_P_SHIFT; } /* Decode the result and update the cache. */ for (unsigned int i = 0; i < reg_list_size; i++) { struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs; unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS; if (xtensa_reg_is_readable(rlist[ridx].flags, cpenable) && rlist[ridx].exist) { if ((xtensa->core_config->windowed) && (rlist[ridx].type == XT_REG_GENERAL)) { /* The 64-value general register set is read from (windowbase) on down. * We need to get the real register address by subtracting windowbase and * wrapping around. */ enum xtensa_reg_id realadr = xtensa_canonical_to_windowbase_offset(xtensa, i, windowbase); buf_cpy(regvals[realadr].buf, reg_list[i].value, reg_list[i].size); } else if (rlist[ridx].type == XT_REG_RELGEN) { buf_cpy(regvals[rlist[ridx].reg_num].buf, reg_list[i].value, reg_list[i].size); if (xtensa_extra_debug_log) { xtensa_reg_val_t regval = buf_get_u32(regvals[rlist[ridx].reg_num].buf, 0, 32); LOG_DEBUG("%s = 0x%x", rlist[ridx].name, regval); } } else { xtensa_reg_val_t regval = buf_get_u32(regvals[i].buf, 0, 32); bool is_dirty = (i == XT_REG_IDX_CPENABLE); if (xtensa_extra_debug_log) LOG_INFO("Register %s: 0x%X", reg_list[i].name, regval); if (rlist[ridx].reg_num == XT_PC_REG_NUM_VIRTUAL && xtensa->core_config->core_type == XT_NX) { /* A0 from prior CALL0 points to next instruction; decrement it */ regval -= 3; is_dirty = 1; } else if (i == ms_idx) { LOG_TARGET_DEBUG(target, "Caching MS: 0x%x", ms); regval = ms; is_dirty = 1; } xtensa_reg_set(target, i, regval); reg_list[i].dirty = is_dirty; /*always do this _after_ xtensa_reg_set! */ } reg_list[i].valid = true; } else { if ((rlist[ridx].flags & XT_REGF_MASK) == XT_REGF_NOREAD) { /* Report read-only registers all-zero but valid */ reg_list[i].valid = true; xtensa_reg_set(target, i, 0); } else { reg_list[i].valid = false; } } } if (xtensa->core_config->windowed) { /* We have used A3 as a scratch register. * Windowed configs: restore A3's AR (XT_REG_GENERAL) and and flag for write-back. */ enum xtensa_reg_id ar3_idx = xtensa_windowbase_offset_to_canonical(xtensa, XT_REG_IDX_A3, windowbase); xtensa_reg_set(target, ar3_idx, a3); xtensa_mark_register_dirty(xtensa, ar3_idx); /* Reset scratch_ars[] on fetch. .chrval tracks AR mapping and changes w/ window */ sprintf(xtensa->scratch_ars[XT_AR_SCRATCH_AR3].chrval, "ar%d", ar3_idx - XT_REG_IDX_AR0); enum xtensa_reg_id ar4_idx = xtensa_windowbase_offset_to_canonical(xtensa, XT_REG_IDX_A4, windowbase); sprintf(xtensa->scratch_ars[XT_AR_SCRATCH_AR4].chrval, "ar%d", ar4_idx - XT_REG_IDX_AR0); for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++) xtensa->scratch_ars[s].intval = false; } /* We have used A3 (XT_REG_RELGEN) as a scratch register. Restore and flag for write-back. */ xtensa_reg_set(target, XT_REG_IDX_A3, a3); xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3); if (xtensa->core_config->core_type == XT_NX) { xtensa_reg_set(target, XT_REG_IDX_A0, a0); xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A0); } xtensa->regs_fetched = true; xtensa_fetch_all_regs_done: free(regvals); free(dsrs); return res; } int xtensa_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { struct xtensa *xtensa = target_to_xtensa(target); unsigned int num_regs; if (reg_class == REG_CLASS_GENERAL) { if ((xtensa->genpkt_regs_num == 0) || !xtensa->contiguous_regs_list) { LOG_ERROR("reg_class %d unhandled; 'xtgregs' not found", reg_class); return ERROR_FAIL; } num_regs = xtensa->genpkt_regs_num; } else { /* Determine whether to return a contiguous or sparse register map */ num_regs = xtensa->regmap_contiguous ? xtensa->total_regs_num : xtensa->dbregs_num; } LOG_DEBUG("reg_class=%i, num_regs=%d", (int)reg_class, num_regs); *reg_list = calloc(num_regs, sizeof(struct reg *)); if (!*reg_list) return ERROR_FAIL; *reg_list_size = num_regs; if (xtensa->regmap_contiguous) { assert((num_regs <= xtensa->total_regs_num) && "contiguous regmap size internal error!"); for (unsigned int i = 0; i < num_regs; i++) (*reg_list)[i] = xtensa->contiguous_regs_list[i]; return ERROR_OK; } for (unsigned int i = 0; i < num_regs; i++) (*reg_list)[i] = (struct reg *)&xtensa->empty_regs[i]; unsigned int k = 0; for (unsigned int i = 0; i < xtensa->core_cache->num_regs && k < num_regs; i++) { if (xtensa->core_cache->reg_list[i].exist) { struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs; unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS; int sparse_idx = rlist[ridx].dbreg_num; if (i == XT_REG_IDX_PS && xtensa->core_config->core_type == XT_LX) { if (xtensa->eps_dbglevel_idx == 0) { LOG_ERROR("eps_dbglevel_idx not set\n"); return ERROR_FAIL; } (*reg_list)[sparse_idx] = &xtensa->core_cache->reg_list[xtensa->eps_dbglevel_idx]; if (xtensa_extra_debug_log) LOG_DEBUG("SPARSE GDB reg 0x%x getting EPS%d 0x%x", sparse_idx, xtensa->core_config->debug.irq_level, xtensa_reg_get_value((*reg_list)[sparse_idx])); } else if (rlist[ridx].type == XT_REG_RELGEN) { (*reg_list)[sparse_idx - XT_REG_IDX_ARFIRST] = &xtensa->core_cache->reg_list[i]; } else { (*reg_list)[sparse_idx] = &xtensa->core_cache->reg_list[i]; } if (i == XT_REG_IDX_PC) /* Make a duplicate copy of PC for external access */ (*reg_list)[XT_PC_DBREG_NUM_BASE] = &xtensa->core_cache->reg_list[i]; k++; } } if (k == num_regs) LOG_ERROR("SPARSE GDB reg list full (size %d)", k); return ERROR_OK; } int xtensa_mmu_is_enabled(struct target *target, int *enabled) { struct xtensa *xtensa = target_to_xtensa(target); *enabled = xtensa->core_config->mmu.itlb_entries_count > 0 || xtensa->core_config->mmu.dtlb_entries_count > 0; return ERROR_OK; } int xtensa_halt(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); LOG_TARGET_DEBUG(target, "start"); if (target->state == TARGET_HALTED) { LOG_TARGET_DEBUG(target, "target was already halted"); return ERROR_OK; } /* First we have to read dsr and check if the target stopped */ int res = xtensa_dm_core_status_read(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read core status!"); return res; } LOG_TARGET_DEBUG(target, "Core status 0x%" PRIx32, xtensa_dm_core_status_get(&xtensa->dbg_mod)); if (!xtensa_is_stopped(target)) { xtensa_queue_dbg_reg_write(xtensa, XDMREG_DCRSET, OCDDCR_ENABLEOCD | OCDDCR_DEBUGINTERRUPT); xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) LOG_TARGET_ERROR(target, "Failed to set OCDDCR_DEBUGINTERRUPT. Can't halt."); } return res; } int xtensa_prepare_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { struct xtensa *xtensa = target_to_xtensa(target); uint32_t bpena = 0; LOG_TARGET_DEBUG(target, "current=%d address=" TARGET_ADDR_FMT ", handle_breakpoints=%i, debug_execution=%i)", current, address, handle_breakpoints, debug_execution); if (target->state != TARGET_HALTED) { LOG_TARGET_WARNING(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } xtensa->halt_request = false; if (address && !current) { xtensa_reg_set(target, XT_REG_IDX_PC, address); } else { uint32_t cause = xtensa_cause_get(target); LOG_TARGET_DEBUG(target, "DEBUGCAUSE 0x%x (watchpoint %lu) (break %lu)", cause, (cause & DEBUGCAUSE_DB), (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN))); if (cause & DEBUGCAUSE_DB) /* We stopped due to a watchpoint. We can't just resume executing the * instruction again because */ /* that would trigger the watchpoint again. To fix this, we single-step, * which ignores watchpoints. */ xtensa_do_step(target, current, address, handle_breakpoints); if (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN)) /* We stopped due to a break instruction. We can't just resume executing the * instruction again because */ /* that would trigger the break again. To fix this, we single-step, which * ignores break. */ xtensa_do_step(target, current, address, handle_breakpoints); } /* Write back hw breakpoints. Current FreeRTOS SMP code can set a hw breakpoint on an * exception; we need to clear that and return to the breakpoints gdb has set on resume. */ for (unsigned int slot = 0; slot < xtensa->core_config->debug.ibreaks_num; slot++) { if (xtensa->hw_brps[slot]) { /* Write IBREAKA[slot] and set bit #slot in IBREAKENABLE */ xtensa_reg_set(target, XT_REG_IDX_IBREAKA0 + slot, xtensa->hw_brps[slot]->address); if (xtensa->core_config->core_type == XT_NX) xtensa_reg_set(target, xtensa->nx_reg_idx[XT_NX_REG_IDX_IBREAKC0] + slot, XT_IBREAKC_FB); bpena |= BIT(slot); } } if (xtensa->core_config->core_type == XT_LX) xtensa_reg_set(target, XT_REG_IDX_IBREAKENABLE, bpena); /* Here we write all registers to the targets */ int res = xtensa_write_dirty_registers(target); if (res != ERROR_OK) LOG_TARGET_ERROR(target, "Failed to write back register cache."); return res; } int xtensa_do_resume(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); LOG_TARGET_DEBUG(target, "start"); xtensa_cause_reset(target); xtensa_queue_exec_ins(xtensa, XT_INS_RFDO(xtensa)); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to exec RFDO %d!", res); return res; } xtensa_core_status_check(target); return ERROR_OK; } int xtensa_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { LOG_TARGET_DEBUG(target, "start"); int res = xtensa_prepare_resume(target, current, address, handle_breakpoints, debug_execution); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to prepare for resume!"); return res; } res = xtensa_do_resume(target); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to resume!"); return res; } target->debug_reason = DBG_REASON_NOTHALTED; if (!debug_execution) target->state = TARGET_RUNNING; else target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); return ERROR_OK; } static bool xtensa_pc_in_winexc(struct target *target, target_addr_t pc) { struct xtensa *xtensa = target_to_xtensa(target); uint8_t insn_buf[XT_ISNS_SZ_MAX]; int err = xtensa_read_buffer(target, pc, sizeof(insn_buf), insn_buf); if (err != ERROR_OK) return false; xtensa_insn_t insn = buf_get_u32(insn_buf, 0, 24); xtensa_insn_t masked = insn & XT_INS_L32E_S32E_MASK(xtensa); if (masked == XT_INS_L32E(xtensa, 0, 0, 0) || masked == XT_INS_S32E(xtensa, 0, 0, 0)) return true; masked = insn & XT_INS_RFWO_RFWU_MASK(xtensa); if (masked == XT_INS_RFWO(xtensa) || masked == XT_INS_RFWU(xtensa)) return true; return false; } int xtensa_do_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { struct xtensa *xtensa = target_to_xtensa(target); int res; const uint32_t icount_val = -2; /* ICOUNT value to load for 1 step */ xtensa_reg_val_t dbreakc[XT_WATCHPOINTS_NUM_MAX]; xtensa_reg_val_t icountlvl, cause; xtensa_reg_val_t oldps, oldpc, cur_pc; bool ps_lowered = false; LOG_TARGET_DEBUG(target, "current=%d, address=" TARGET_ADDR_FMT ", handle_breakpoints=%i", current, address, handle_breakpoints); if (target->state != TARGET_HALTED) { LOG_TARGET_WARNING(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } if (xtensa->eps_dbglevel_idx == 0 && xtensa->core_config->core_type == XT_LX) { LOG_TARGET_ERROR(target, "eps_dbglevel_idx not set\n"); return ERROR_FAIL; } /* Save old ps (EPS[dbglvl] on LX), pc */ oldps = xtensa_reg_get(target, (xtensa->core_config->core_type == XT_LX) ? xtensa->eps_dbglevel_idx : XT_REG_IDX_PS); oldpc = xtensa_reg_get(target, XT_REG_IDX_PC); cause = xtensa_cause_get(target); LOG_TARGET_DEBUG(target, "oldps=%" PRIx32 ", oldpc=%" PRIx32 " dbg_cause=%" PRIx32 " exc_cause=%" PRIx32, oldps, oldpc, cause, xtensa_reg_get(target, XT_REG_IDX_EXCCAUSE)); if (handle_breakpoints && (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN))) { /* handle hard-coded SW breakpoints (e.g. syscalls) */ LOG_TARGET_DEBUG(target, "Increment PC to pass break instruction..."); xtensa_cause_clear(target); /* so we don't recurse into the same routine */ /* pretend that we have stepped */ if (cause & DEBUGCAUSE_BI) xtensa_reg_set(target, XT_REG_IDX_PC, oldpc + 3); /* PC = PC+3 */ else xtensa_reg_set(target, XT_REG_IDX_PC, oldpc + 2); /* PC = PC+2 */ return ERROR_OK; } /* Xtensa LX has an ICOUNTLEVEL register which sets the maximum interrupt level * at which the instructions are to be counted while stepping. * * For example, if we need to step by 2 instructions, and an interrupt occurs * in between, the processor will trigger the interrupt and halt after the 2nd * instruction within the interrupt vector and/or handler. * * However, sometimes we don't want the interrupt handlers to be executed at all * while stepping through the code. In this case (XT_STEPPING_ISR_OFF), * ICOUNTLEVEL can be lowered to the executing code's (level + 1) to prevent ISR * code from being counted during stepping. Note that C exception handlers must * run at level 0 and hence will be counted and stepped into, should one occur. * * TODO: Certain instructions should never be single-stepped and should instead * be emulated (per DUG): RSIL >= DBGLEVEL, RSR/WSR [ICOUNT|ICOUNTLEVEL], and * RFI >= DBGLEVEL. */ if (xtensa->stepping_isr_mode == XT_STEPPING_ISR_OFF) { if (!xtensa->core_config->high_irq.enabled) { LOG_TARGET_WARNING( target, "disabling IRQs while stepping is not implemented w/o high prio IRQs option!"); return ERROR_FAIL; } /* Update ICOUNTLEVEL accordingly */ icountlvl = MIN((oldps & 0xF) + 1, xtensa->core_config->debug.irq_level); } else { icountlvl = xtensa->core_config->debug.irq_level; } if (cause & DEBUGCAUSE_DB) { /* We stopped due to a watchpoint. We can't just resume executing the instruction again because * that would trigger the watchpoint again. To fix this, we remove watchpoints,single-step and * re-enable the watchpoint. */ LOG_TARGET_DEBUG( target, "Single-stepping to get past instruction that triggered the watchpoint..."); xtensa_cause_clear(target); /* so we don't recurse into the same routine */ /* Save all DBREAKCx registers and set to 0 to disable watchpoints */ for (unsigned int slot = 0; slot < xtensa->core_config->debug.dbreaks_num; slot++) { dbreakc[slot] = xtensa_reg_get(target, XT_REG_IDX_DBREAKC0 + slot); xtensa_reg_set(target, XT_REG_IDX_DBREAKC0 + slot, 0); } } if (!handle_breakpoints && (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN))) /* handle normal SW breakpoint */ xtensa_cause_clear(target); /* so we don't recurse into the same routine */ if (xtensa->core_config->core_type == XT_LX && ((oldps & 0xf) >= icountlvl)) { /* Lower interrupt level to allow stepping, but flag eps[dbglvl] to be restored */ ps_lowered = true; uint32_t newps = (oldps & ~0xf) | (icountlvl - 1); xtensa_reg_set(target, xtensa->eps_dbglevel_idx, newps); LOG_TARGET_DEBUG(target, "Lowering PS.INTLEVEL to allow stepping: %s <- 0x%08" PRIx32 " (was 0x%08" PRIx32 ")", xtensa->core_cache->reg_list[xtensa->eps_dbglevel_idx].name, newps, oldps); } do { if (xtensa->core_config->core_type == XT_LX) { xtensa_reg_set(target, XT_REG_IDX_ICOUNTLEVEL, icountlvl); xtensa_reg_set(target, XT_REG_IDX_ICOUNT, icount_val); } else { xtensa_queue_dbg_reg_write(xtensa, XDMREG_DCRSET, OCDDCR_STEPREQUEST); } /* Now that ICOUNT (LX) or DCR.StepRequest (NX) is set, * we can resume as if we were going to run */ res = xtensa_prepare_resume(target, current, address, 0, 0); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to prepare resume for single step"); return res; } res = xtensa_do_resume(target); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to resume after setting up single step"); return res; } /* Wait for stepping to complete */ long long start = timeval_ms(); while (timeval_ms() < start + 500) { /* Do not use target_poll here, it also triggers other things... just manually read the DSR *until stepping is complete. */ usleep(1000); res = xtensa_dm_core_status_read(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read core status!"); return res; } if (xtensa_is_stopped(target)) break; usleep(1000); } LOG_TARGET_DEBUG(target, "Finish stepping. dsr=0x%08" PRIx32, xtensa_dm_core_status_get(&xtensa->dbg_mod)); if (!xtensa_is_stopped(target)) { LOG_TARGET_WARNING( target, "Timed out waiting for target to finish stepping. dsr=0x%08" PRIx32, xtensa_dm_core_status_get(&xtensa->dbg_mod)); target->debug_reason = DBG_REASON_NOTHALTED; target->state = TARGET_RUNNING; return ERROR_FAIL; } xtensa_fetch_all_regs(target); cur_pc = xtensa_reg_get(target, XT_REG_IDX_PC); LOG_TARGET_DEBUG(target, "cur_ps=%" PRIx32 ", cur_pc=%" PRIx32 " dbg_cause=%" PRIx32 " exc_cause=%" PRIx32, xtensa_reg_get(target, XT_REG_IDX_PS), cur_pc, xtensa_cause_get(target), xtensa_reg_get(target, XT_REG_IDX_EXCCAUSE)); /* Do not step into WindowOverflow if ISRs are masked. If we stop in WindowOverflow at breakpoint with masked ISRs and try to do a step it will get us out of that handler */ if (xtensa->core_config->windowed && xtensa->stepping_isr_mode == XT_STEPPING_ISR_OFF && xtensa_pc_in_winexc(target, cur_pc)) { /* isrmask = on, need to step out of the window exception handler */ LOG_DEBUG("Stepping out of window exception, PC=%" PRIX32, cur_pc); oldpc = cur_pc; address = oldpc + 3; continue; } if (oldpc == cur_pc) LOG_TARGET_WARNING(target, "Stepping doesn't seem to change PC! dsr=0x%08" PRIx32, xtensa_dm_core_status_get(&xtensa->dbg_mod)); else LOG_DEBUG("Stepped from %" PRIX32 " to %" PRIX32, oldpc, cur_pc); break; } while (true); target->debug_reason = DBG_REASON_SINGLESTEP; target->state = TARGET_HALTED; LOG_DEBUG("Done stepping, PC=%" PRIX32, cur_pc); if (cause & DEBUGCAUSE_DB) { LOG_TARGET_DEBUG(target, "...Done, re-installing watchpoints."); /* Restore the DBREAKCx registers */ for (unsigned int slot = 0; slot < xtensa->core_config->debug.dbreaks_num; slot++) xtensa_reg_set(target, XT_REG_IDX_DBREAKC0 + slot, dbreakc[slot]); } /* Restore int level */ if (ps_lowered) { LOG_DEBUG("Restoring %s after stepping: 0x%08" PRIx32, xtensa->core_cache->reg_list[xtensa->eps_dbglevel_idx].name, oldps); xtensa_reg_set(target, xtensa->eps_dbglevel_idx, oldps); } /* write ICOUNTLEVEL back to zero */ xtensa_reg_set(target, XT_REG_IDX_ICOUNTLEVEL, 0); /* TODO: can we skip writing dirty registers and re-fetching them? */ res = xtensa_write_dirty_registers(target); xtensa_fetch_all_regs(target); return res; } int xtensa_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { int retval = xtensa_do_step(target, current, address, handle_breakpoints); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } /** * Returns true if two ranges are overlapping */ static inline bool xtensa_memory_regions_overlap(target_addr_t r1_start, target_addr_t r1_end, target_addr_t r2_start, target_addr_t r2_end) { if ((r2_start >= r1_start) && (r2_start < r1_end)) return true; /* r2_start is in r1 region */ if ((r2_end > r1_start) && (r2_end <= r1_end)) return true; /* r2_end is in r1 region */ return false; } /** * Returns a size of overlapped region of two ranges. */ static inline target_addr_t xtensa_get_overlap_size(target_addr_t r1_start, target_addr_t r1_end, target_addr_t r2_start, target_addr_t r2_end) { if (xtensa_memory_regions_overlap(r1_start, r1_end, r2_start, r2_end)) { target_addr_t ov_start = r1_start < r2_start ? r2_start : r1_start; target_addr_t ov_end = r1_end > r2_end ? r2_end : r1_end; return ov_end - ov_start; } return 0; } /** * Check if the address gets to memory regions, and its access mode */ static bool xtensa_memory_op_validate_range(struct xtensa *xtensa, target_addr_t address, size_t size, int access) { target_addr_t adr_pos = address; /* address cursor set to the beginning start */ target_addr_t adr_end = address + size; /* region end */ target_addr_t overlap_size; const struct xtensa_local_mem_region_config *cm; /* current mem region */ while (adr_pos < adr_end) { cm = xtensa_target_memory_region_find(xtensa, adr_pos); if (!cm) /* address is not belong to anything */ return false; if ((cm->access & access) != access) /* access check */ return false; overlap_size = xtensa_get_overlap_size(cm->base, (cm->base + cm->size), adr_pos, adr_end); assert(overlap_size != 0); adr_pos += overlap_size; } return true; } int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct xtensa *xtensa = target_to_xtensa(target); /* We are going to read memory in 32-bit increments. This may not be what the calling * function expects, so we may need to allocate a temp buffer and read into that first. */ target_addr_t addrstart_al = ALIGN_DOWN(address, 4); target_addr_t addrend_al = ALIGN_UP(address + size * count, 4); target_addr_t adr = addrstart_al; uint8_t *albuff; bool bswap = xtensa->target->endianness == TARGET_BIG_ENDIAN; if (target->state != TARGET_HALTED) { LOG_TARGET_WARNING(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!xtensa->permissive_mode) { if (!xtensa_memory_op_validate_range(xtensa, address, (size * count), XT_MEM_ACCESS_READ)) { LOG_DEBUG("address " TARGET_ADDR_FMT " not readable", address); return ERROR_FAIL; } } unsigned int alloc_bytes = ALIGN_UP(addrend_al - addrstart_al, sizeof(uint32_t)); albuff = calloc(alloc_bytes, 1); if (!albuff) { LOG_TARGET_ERROR(target, "Out of memory allocating %" PRId64 " bytes!", addrend_al - addrstart_al); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* We're going to use A3 here */ xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3); /* Write start address to A3 */ xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, addrstart_al); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); /* Now we can safely read data from addrstart_al up to addrend_al into albuff */ if (xtensa->probe_lsddr32p != 0) { xtensa_queue_exec_ins(xtensa, XT_INS_LDDR32P(xtensa, XT_REG_A3)); for (unsigned int i = 0; adr != addrend_al; i += sizeof(uint32_t), adr += sizeof(uint32_t)) xtensa_queue_dbg_reg_read(xtensa, (adr + sizeof(uint32_t) == addrend_al) ? XDMREG_DDR : XDMREG_DDREXEC, &albuff[i]); } else { xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A4); for (unsigned int i = 0; adr != addrend_al; i += sizeof(uint32_t), adr += sizeof(uint32_t)) { xtensa_queue_exec_ins(xtensa, XT_INS_L32I(xtensa, XT_REG_A3, XT_REG_A4, 0)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A4)); xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, &albuff[i]); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, adr + sizeof(uint32_t)); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); } } int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res == ERROR_OK) { bool prev_suppress = xtensa->suppress_dsr_errors; xtensa->suppress_dsr_errors = true; res = xtensa_core_status_check(target); if (xtensa->probe_lsddr32p == -1) xtensa->probe_lsddr32p = 1; xtensa->suppress_dsr_errors = prev_suppress; } if (res != ERROR_OK) { if (xtensa->probe_lsddr32p != 0) { /* Disable fast memory access instructions and retry before reporting an error */ LOG_TARGET_DEBUG(target, "Disabling LDDR32.P/SDDR32.P"); xtensa->probe_lsddr32p = 0; res = xtensa_read_memory(target, address, size, count, albuff); bswap = false; } else { LOG_TARGET_WARNING(target, "Failed reading %d bytes at address "TARGET_ADDR_FMT, count * size, address); } } if (bswap) buf_bswap32(albuff, albuff, addrend_al - addrstart_al); memcpy(buffer, albuff + (address & 3), (size * count)); free(albuff); return res; } int xtensa_read_buffer(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer) { /* xtensa_read_memory can also read unaligned stuff. Just pass through to that routine. */ return xtensa_read_memory(target, address, 1, count, buffer); } int xtensa_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { /* This memory write function can get thrown nigh everything into it, from * aligned uint32 writes to unaligned uint8ths. The Xtensa memory doesn't always * accept anything but aligned uint32 writes, though. That is why we convert * everything into that. */ struct xtensa *xtensa = target_to_xtensa(target); target_addr_t addrstart_al = ALIGN_DOWN(address, 4); target_addr_t addrend_al = ALIGN_UP(address + size * count, 4); target_addr_t adr = addrstart_al; int res; uint8_t *albuff; bool fill_head_tail = false; if (target->state != TARGET_HALTED) { LOG_TARGET_WARNING(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!xtensa->permissive_mode) { if (!xtensa_memory_op_validate_range(xtensa, address, (size * count), XT_MEM_ACCESS_WRITE)) { LOG_WARNING("address " TARGET_ADDR_FMT " not writable", address); return ERROR_FAIL; } } if (size == 0 || count == 0 || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; /* Allocate a temporary buffer to put the aligned bytes in, if needed. */ if (addrstart_al == address && addrend_al == address + (size * count)) { if (xtensa->target->endianness == TARGET_BIG_ENDIAN) /* Need a buffer for byte-swapping */ albuff = malloc(addrend_al - addrstart_al); else /* We discard the const here because albuff can also be non-const */ albuff = (uint8_t *)buffer; } else { fill_head_tail = true; albuff = malloc(addrend_al - addrstart_al); } if (!albuff) { LOG_TARGET_ERROR(target, "Out of memory allocating %" PRId64 " bytes!", addrend_al - addrstart_al); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* We're going to use A3 here */ xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3); /* If we're using a temp aligned buffer, we need to fill the head and/or tail bit of it. */ if (fill_head_tail) { /* See if we need to read the first and/or last word. */ if (address & 3) { xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, addrstart_al); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); if (xtensa->probe_lsddr32p == 1) { xtensa_queue_exec_ins(xtensa, XT_INS_LDDR32P(xtensa, XT_REG_A3)); } else { xtensa_queue_exec_ins(xtensa, XT_INS_L32I(xtensa, XT_REG_A3, XT_REG_A3, 0)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); } xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, &albuff[0]); } if ((address + (size * count)) & 3) { xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, addrend_al - 4); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); if (xtensa->probe_lsddr32p == 1) { xtensa_queue_exec_ins(xtensa, XT_INS_LDDR32P(xtensa, XT_REG_A3)); } else { xtensa_queue_exec_ins(xtensa, XT_INS_L32I(xtensa, XT_REG_A3, XT_REG_A3, 0)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); } xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, &albuff[addrend_al - addrstart_al - 4]); } /* Grab bytes */ res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_ERROR("Error issuing unaligned memory write context instruction(s): %d", res); if (albuff != buffer) free(albuff); return res; } xtensa_core_status_check(target); if (xtensa->target->endianness == TARGET_BIG_ENDIAN) { bool swapped_w0 = false; if (address & 3) { buf_bswap32(&albuff[0], &albuff[0], 4); swapped_w0 = true; } if ((address + (size * count)) & 3) { if ((addrend_al - addrstart_al - 4 == 0) && swapped_w0) { /* Don't double-swap if buffer start/end are within the same word */ } else { buf_bswap32(&albuff[addrend_al - addrstart_al - 4], &albuff[addrend_al - addrstart_al - 4], 4); } } } /* Copy data to be written into the aligned buffer (in host-endianness) */ memcpy(&albuff[address & 3], buffer, size * count); /* Now we can write albuff in aligned uint32s. */ } if (xtensa->target->endianness == TARGET_BIG_ENDIAN) buf_bswap32(albuff, fill_head_tail ? albuff : buffer, addrend_al - addrstart_al); /* Write start address to A3 */ xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, addrstart_al); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); /* Write the aligned buffer */ if (xtensa->probe_lsddr32p != 0) { for (unsigned int i = 0; adr != addrend_al; i += sizeof(uint32_t), adr += sizeof(uint32_t)) { if (i == 0) { xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, buf_get_u32(&albuff[i], 0, 32)); xtensa_queue_exec_ins(xtensa, XT_INS_SDDR32P(xtensa, XT_REG_A3)); } else { xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDREXEC, buf_get_u32(&albuff[i], 0, 32)); } } } else { xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A4); for (unsigned int i = 0; adr != addrend_al; i += sizeof(uint32_t), adr += sizeof(uint32_t)) { xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, buf_get_u32(&albuff[i], 0, 32)); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A4)); xtensa_queue_exec_ins(xtensa, XT_INS_S32I(xtensa, XT_REG_A3, XT_REG_A4, 0)); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, adr + sizeof(uint32_t)); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); } } res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res == ERROR_OK) { bool prev_suppress = xtensa->suppress_dsr_errors; xtensa->suppress_dsr_errors = true; res = xtensa_core_status_check(target); if (xtensa->probe_lsddr32p == -1) xtensa->probe_lsddr32p = 1; xtensa->suppress_dsr_errors = prev_suppress; } if (res != ERROR_OK) { if (xtensa->probe_lsddr32p != 0) { /* Disable fast memory access instructions and retry before reporting an error */ LOG_TARGET_INFO(target, "Disabling LDDR32.P/SDDR32.P"); xtensa->probe_lsddr32p = 0; res = xtensa_write_memory(target, address, size, count, buffer); } else { LOG_TARGET_WARNING(target, "Failed writing %d bytes at address "TARGET_ADDR_FMT, count * size, address); } } else { /* Invalidate ICACHE, writeback DCACHE if present */ uint32_t issue_ihi = xtensa_is_icacheable(xtensa, address); uint32_t issue_dhwb = xtensa_is_dcacheable(xtensa, address); if (issue_ihi || issue_dhwb) { uint32_t ilinesize = issue_ihi ? xtensa->core_config->icache.line_size : UINT32_MAX; uint32_t dlinesize = issue_dhwb ? xtensa->core_config->dcache.line_size : UINT32_MAX; uint32_t linesize = MIN(ilinesize, dlinesize); uint32_t off = 0; adr = addrstart_al; while ((adr + off) < addrend_al) { if (off == 0) { /* Write start address to A3 */ xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, adr); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); } if (issue_ihi) xtensa_queue_exec_ins(xtensa, XT_INS_IHI(xtensa, XT_REG_A3, off)); if (issue_dhwb) xtensa_queue_exec_ins(xtensa, XT_INS_DHWBI(xtensa, XT_REG_A3, off)); off += linesize; if (off > 1020) { /* IHI, DHWB have 8-bit immediate operands (0..1020) */ adr += off; off = 0; } } /* Execute cache WB/INV instructions */ res = xtensa_dm_queue_execute(&xtensa->dbg_mod); xtensa_core_status_check(target); if (res != ERROR_OK) LOG_TARGET_ERROR(target, "Error issuing cache writeback/invaldate instruction(s): %d", res); } } if (albuff != buffer) free(albuff); return res; } int xtensa_write_buffer(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer) { /* xtensa_write_memory can handle everything. Just pass on to that. */ return xtensa_write_memory(target, address, 1, count, buffer); } int xtensa_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { LOG_WARNING("not implemented yet"); return ERROR_FAIL; } int xtensa_poll(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); if (xtensa_dm_poll(&xtensa->dbg_mod) != ERROR_OK) { target->state = TARGET_UNKNOWN; return ERROR_TARGET_NOT_EXAMINED; } int res = xtensa_dm_power_status_read(&xtensa->dbg_mod, PWRSTAT_DEBUGWASRESET(xtensa) | PWRSTAT_COREWASRESET(xtensa)); if (xtensa->dbg_mod.power_status.stat != xtensa->dbg_mod.power_status.stath) LOG_TARGET_DEBUG(target, "PWRSTAT: read 0x%08" PRIx32 ", clear 0x%08lx, reread 0x%08" PRIx32, xtensa->dbg_mod.power_status.stat, PWRSTAT_DEBUGWASRESET(xtensa) | PWRSTAT_COREWASRESET(xtensa), xtensa->dbg_mod.power_status.stath); if (res != ERROR_OK) return res; if (xtensa_dm_tap_was_reset(&xtensa->dbg_mod)) { LOG_TARGET_INFO(target, "Debug controller was reset."); res = xtensa_smpbreak_write(xtensa, xtensa->smp_break); if (res != ERROR_OK) return res; } if (xtensa_dm_core_was_reset(&xtensa->dbg_mod)) LOG_TARGET_INFO(target, "Core was reset."); xtensa_dm_power_status_cache(&xtensa->dbg_mod); /* Enable JTAG, set reset if needed */ res = xtensa_wakeup(target); if (res != ERROR_OK) return res; uint32_t prev_dsr = xtensa->dbg_mod.core_status.dsr; res = xtensa_dm_core_status_read(&xtensa->dbg_mod); if (res != ERROR_OK) return res; if (prev_dsr != xtensa->dbg_mod.core_status.dsr) LOG_TARGET_DEBUG(target, "DSR has changed: was 0x%08" PRIx32 " now 0x%08" PRIx32, prev_dsr, xtensa->dbg_mod.core_status.dsr); if (xtensa->dbg_mod.power_status.stath & PWRSTAT_COREWASRESET(xtensa)) { /* if RESET state is persitent */ target->state = TARGET_RESET; } else if (!xtensa_dm_is_powered(&xtensa->dbg_mod)) { LOG_TARGET_DEBUG(target, "not powered 0x%" PRIX32 "%ld", xtensa->dbg_mod.core_status.dsr, xtensa->dbg_mod.core_status.dsr & OCDDSR_STOPPED); target->state = TARGET_UNKNOWN; if (xtensa->come_online_probes_num == 0) target->examined = false; else xtensa->come_online_probes_num--; } else if (xtensa_is_stopped(target)) { if (target->state != TARGET_HALTED) { enum target_state oldstate = target->state; target->state = TARGET_HALTED; /* Examine why the target has been halted */ target->debug_reason = DBG_REASON_DBGRQ; xtensa_fetch_all_regs(target); /* When setting debug reason DEBUGCAUSE events have the following * priorities: watchpoint == breakpoint > single step > debug interrupt. */ /* Watchpoint and breakpoint events at the same time results in special * debug reason: DBG_REASON_WPTANDBKPT. */ uint32_t halt_cause = xtensa_cause_get(target); /* TODO: Add handling of DBG_REASON_EXC_CATCH */ if (halt_cause & DEBUGCAUSE_IC) target->debug_reason = DBG_REASON_SINGLESTEP; if (halt_cause & (DEBUGCAUSE_IB | DEBUGCAUSE_BN | DEBUGCAUSE_BI)) { if (halt_cause & DEBUGCAUSE_DB) target->debug_reason = DBG_REASON_WPTANDBKPT; else target->debug_reason = DBG_REASON_BREAKPOINT; } else if (halt_cause & DEBUGCAUSE_DB) { target->debug_reason = DBG_REASON_WATCHPOINT; } LOG_TARGET_DEBUG(target, "Target halted, pc=0x%08" PRIx32 ", debug_reason=%08" PRIx32 ", oldstate=%08" PRIx32, xtensa_reg_get(target, XT_REG_IDX_PC), target->debug_reason, oldstate); LOG_TARGET_DEBUG(target, "Halt reason=0x%08" PRIX32 ", exc_cause=%" PRId32 ", dsr=0x%08" PRIx32, halt_cause, xtensa_reg_get(target, XT_REG_IDX_EXCCAUSE), xtensa->dbg_mod.core_status.dsr); xtensa_dm_core_status_clear( &xtensa->dbg_mod, OCDDSR_DEBUGPENDBREAK | OCDDSR_DEBUGINTBREAK | OCDDSR_DEBUGPENDTRAX | OCDDSR_DEBUGINTTRAX | OCDDSR_DEBUGPENDHOST | OCDDSR_DEBUGINTHOST); if (xtensa->core_config->core_type == XT_NX) { /* Enable imprecise exceptions while in halted state */ xtensa_reg_val_t ps = xtensa_reg_get(target, XT_REG_IDX_PS); xtensa_reg_val_t newps = ps & ~(XT_PS_DIEXC_MSK); xtensa_mark_register_dirty(xtensa, XT_REG_IDX_PS); LOG_TARGET_DEBUG(target, "Enabling PS.DIEXC: 0x%08x -> 0x%08x", ps, newps); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, newps); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_PS, XT_REG_A3)); res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to write PS.DIEXC (%d)!", res); return res; } xtensa_core_status_check(target); } } } else { target->debug_reason = DBG_REASON_NOTHALTED; if (target->state != TARGET_RUNNING && target->state != TARGET_DEBUG_RUNNING) { target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; } } if (xtensa->trace_active) { /* Detect if tracing was active but has stopped. */ struct xtensa_trace_status trace_status; res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status); if (res == ERROR_OK) { if (!(trace_status.stat & TRAXSTAT_TRACT)) { LOG_INFO("Detected end of trace."); if (trace_status.stat & TRAXSTAT_PCMTG) LOG_TARGET_INFO(target, "Trace stop triggered by PC match"); if (trace_status.stat & TRAXSTAT_PTITG) LOG_TARGET_INFO(target, "Trace stop triggered by Processor Trigger Input"); if (trace_status.stat & TRAXSTAT_CTITG) LOG_TARGET_INFO(target, "Trace stop triggered by Cross-trigger Input"); xtensa->trace_active = false; } } } return ERROR_OK; } static int xtensa_update_instruction(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer) { struct xtensa *xtensa = target_to_xtensa(target); unsigned int issue_ihi = xtensa_is_icacheable(xtensa, address); unsigned int issue_dhwbi = xtensa_is_dcacheable(xtensa, address); uint32_t icache_line_size = issue_ihi ? xtensa->core_config->icache.line_size : UINT32_MAX; uint32_t dcache_line_size = issue_dhwbi ? xtensa->core_config->dcache.line_size : UINT32_MAX; unsigned int same_ic_line = ((address & (icache_line_size - 1)) + size) <= icache_line_size; unsigned int same_dc_line = ((address & (dcache_line_size - 1)) + size) <= dcache_line_size; int ret; if (size > icache_line_size) return ERROR_FAIL; if (issue_ihi || issue_dhwbi) { /* We're going to use A3 here */ xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3); /* Write start address to A3 and invalidate */ xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, address); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); LOG_TARGET_DEBUG(target, "DHWBI, IHI for address "TARGET_ADDR_FMT, address); if (issue_dhwbi) { xtensa_queue_exec_ins(xtensa, XT_INS_DHWBI(xtensa, XT_REG_A3, 0)); if (!same_dc_line) { LOG_TARGET_DEBUG(target, "DHWBI second dcache line for address "TARGET_ADDR_FMT, address + 4); xtensa_queue_exec_ins(xtensa, XT_INS_DHWBI(xtensa, XT_REG_A3, 4)); } } if (issue_ihi) { xtensa_queue_exec_ins(xtensa, XT_INS_IHI(xtensa, XT_REG_A3, 0)); if (!same_ic_line) { LOG_TARGET_DEBUG(target, "IHI second icache line for address "TARGET_ADDR_FMT, address + 4); xtensa_queue_exec_ins(xtensa, XT_INS_IHI(xtensa, XT_REG_A3, 4)); } } /* Execute invalidate instructions */ ret = xtensa_dm_queue_execute(&xtensa->dbg_mod); xtensa_core_status_check(target); if (ret != ERROR_OK) { LOG_ERROR("Error issuing cache invaldate instruction(s): %d", ret); return ret; } } /* Write new instructions to memory */ ret = target_write_buffer(target, address, size, buffer); if (ret != ERROR_OK) { LOG_TARGET_ERROR(target, "Error writing instruction to memory: %d", ret); return ret; } if (issue_dhwbi) { /* Flush dcache so instruction propagates. A3 may be corrupted during memory write */ xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, address); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_exec_ins(xtensa, XT_INS_DHWB(xtensa, XT_REG_A3, 0)); LOG_DEBUG("DHWB dcache line for address "TARGET_ADDR_FMT, address); if (!same_dc_line) { LOG_TARGET_DEBUG(target, "DHWB second dcache line for address "TARGET_ADDR_FMT, address + 4); xtensa_queue_exec_ins(xtensa, XT_INS_DHWB(xtensa, XT_REG_A3, 4)); } /* Execute invalidate instructions */ ret = xtensa_dm_queue_execute(&xtensa->dbg_mod); xtensa_core_status_check(target); } /* TODO: Handle L2 cache if present */ return ret; } static int xtensa_sw_breakpoint_add(struct target *target, struct breakpoint *breakpoint, struct xtensa_sw_breakpoint *sw_bp) { struct xtensa *xtensa = target_to_xtensa(target); int ret = target_read_buffer(target, breakpoint->address, XT_ISNS_SZ_MAX, sw_bp->insn); if (ret != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read original instruction (%d)!", ret); return ret; } sw_bp->insn_sz = MIN(XT_ISNS_SZ_MAX, breakpoint->length); sw_bp->oocd_bp = breakpoint; uint32_t break_insn = sw_bp->insn_sz == XT_ISNS_SZ_MAX ? XT_INS_BREAK(xtensa, 0, 0) : XT_INS_BREAKN(xtensa, 0); /* Underlying memory write will convert instruction endianness, don't do that here */ ret = xtensa_update_instruction(target, breakpoint->address, sw_bp->insn_sz, (uint8_t *)&break_insn); if (ret != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to write breakpoint instruction (%d)!", ret); return ret; } return ERROR_OK; } static int xtensa_sw_breakpoint_remove(struct target *target, struct xtensa_sw_breakpoint *sw_bp) { int ret = xtensa_update_instruction(target, sw_bp->oocd_bp->address, sw_bp->insn_sz, sw_bp->insn); if (ret != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to write insn (%d)!", ret); return ret; } sw_bp->oocd_bp = NULL; return ERROR_OK; } int xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint) { struct xtensa *xtensa = target_to_xtensa(target); unsigned int slot; if (breakpoint->type == BKPT_SOFT) { for (slot = 0; slot < XT_SW_BREAKPOINTS_MAX_NUM; slot++) { if (!xtensa->sw_brps[slot].oocd_bp || xtensa->sw_brps[slot].oocd_bp == breakpoint) break; } if (slot == XT_SW_BREAKPOINTS_MAX_NUM) { LOG_TARGET_WARNING(target, "No free slots to add SW breakpoint!"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } int ret = xtensa_sw_breakpoint_add(target, breakpoint, &xtensa->sw_brps[slot]); if (ret != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to add SW breakpoint!"); return ret; } LOG_TARGET_DEBUG(target, "placed SW breakpoint %u @ " TARGET_ADDR_FMT, slot, breakpoint->address); return ERROR_OK; } for (slot = 0; slot < xtensa->core_config->debug.ibreaks_num; slot++) { if (!xtensa->hw_brps[slot] || xtensa->hw_brps[slot] == breakpoint) break; } if (slot == xtensa->core_config->debug.ibreaks_num) { LOG_TARGET_ERROR(target, "No free slots to add HW breakpoint!"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } xtensa->hw_brps[slot] = breakpoint; /* We will actually write the breakpoints when we resume the target. */ LOG_TARGET_DEBUG(target, "placed HW breakpoint %u @ " TARGET_ADDR_FMT, slot, breakpoint->address); return ERROR_OK; } int xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint) { struct xtensa *xtensa = target_to_xtensa(target); unsigned int slot; if (breakpoint->type == BKPT_SOFT) { for (slot = 0; slot < XT_SW_BREAKPOINTS_MAX_NUM; slot++) { if (xtensa->sw_brps[slot].oocd_bp && xtensa->sw_brps[slot].oocd_bp == breakpoint) break; } if (slot == XT_SW_BREAKPOINTS_MAX_NUM) { LOG_TARGET_WARNING(target, "Max SW breakpoints slot reached, slot=%u!", slot); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } int ret = xtensa_sw_breakpoint_remove(target, &xtensa->sw_brps[slot]); if (ret != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to remove SW breakpoint (%d)!", ret); return ret; } LOG_TARGET_DEBUG(target, "cleared SW breakpoint %u @ " TARGET_ADDR_FMT, slot, breakpoint->address); return ERROR_OK; } for (slot = 0; slot < xtensa->core_config->debug.ibreaks_num; slot++) { if (xtensa->hw_brps[slot] == breakpoint) break; } if (slot == xtensa->core_config->debug.ibreaks_num) { LOG_TARGET_ERROR(target, "HW breakpoint not found!"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } xtensa->hw_brps[slot] = NULL; if (xtensa->core_config->core_type == XT_NX) xtensa_reg_set(target, xtensa->nx_reg_idx[XT_NX_REG_IDX_IBREAKC0] + slot, 0); LOG_TARGET_DEBUG(target, "cleared HW breakpoint %u @ " TARGET_ADDR_FMT, slot, breakpoint->address); return ERROR_OK; } int xtensa_watchpoint_add(struct target *target, struct watchpoint *watchpoint) { struct xtensa *xtensa = target_to_xtensa(target); unsigned int slot; xtensa_reg_val_t dbreakcval; if (target->state != TARGET_HALTED) { LOG_TARGET_WARNING(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } if (watchpoint->mask != ~(uint32_t)0) { LOG_TARGET_ERROR(target, "watchpoint value masks not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } for (slot = 0; slot < xtensa->core_config->debug.dbreaks_num; slot++) { if (!xtensa->hw_wps[slot] || xtensa->hw_wps[slot] == watchpoint) break; } if (slot == xtensa->core_config->debug.dbreaks_num) { LOG_TARGET_WARNING(target, "No free slots to add HW watchpoint!"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* Figure out value for dbreakc5..0 * It's basically 0x3F with an incremental bit removed from the LSB for each extra length power of 2. */ if (watchpoint->length < 1 || watchpoint->length > 64 || !IS_PWR_OF_2(watchpoint->length) || !IS_ALIGNED(watchpoint->address, watchpoint->length)) { LOG_TARGET_WARNING( target, "Watchpoint with length %d on address " TARGET_ADDR_FMT " not supported by hardware.", watchpoint->length, watchpoint->address); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } dbreakcval = ALIGN_DOWN(0x3F, watchpoint->length); if (watchpoint->rw == WPT_READ) dbreakcval |= BIT(30); if (watchpoint->rw == WPT_WRITE) dbreakcval |= BIT(31); if (watchpoint->rw == WPT_ACCESS) dbreakcval |= BIT(30) | BIT(31); /* Write DBREAKA[slot] and DBCREAKC[slot] */ xtensa_reg_set(target, XT_REG_IDX_DBREAKA0 + slot, watchpoint->address); xtensa_reg_set(target, XT_REG_IDX_DBREAKC0 + slot, dbreakcval); xtensa->hw_wps[slot] = watchpoint; LOG_TARGET_DEBUG(target, "placed HW watchpoint @ " TARGET_ADDR_FMT, watchpoint->address); return ERROR_OK; } int xtensa_watchpoint_remove(struct target *target, struct watchpoint *watchpoint) { struct xtensa *xtensa = target_to_xtensa(target); unsigned int slot; for (slot = 0; slot < xtensa->core_config->debug.dbreaks_num; slot++) { if (xtensa->hw_wps[slot] == watchpoint) break; } if (slot == xtensa->core_config->debug.dbreaks_num) { LOG_TARGET_WARNING(target, "HW watchpoint " TARGET_ADDR_FMT " not found!", watchpoint->address); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } xtensa_reg_set(target, XT_REG_IDX_DBREAKC0 + slot, 0); xtensa->hw_wps[slot] = NULL; LOG_TARGET_DEBUG(target, "cleared HW watchpoint @ " TARGET_ADDR_FMT, watchpoint->address); return ERROR_OK; } static int xtensa_build_reg_cache(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); unsigned int last_dbreg_num = 0; if (xtensa->core_regs_num + xtensa->num_optregs != xtensa->total_regs_num) LOG_TARGET_WARNING(target, "Register count MISMATCH: %d core regs, %d extended regs; %d expected", xtensa->core_regs_num, xtensa->num_optregs, xtensa->total_regs_num); struct reg_cache *reg_cache = calloc(1, sizeof(struct reg_cache)); if (!reg_cache) { LOG_ERROR("Failed to alloc reg cache!"); return ERROR_FAIL; } reg_cache->name = "Xtensa registers"; reg_cache->next = NULL; /* Init reglist */ unsigned int reg_list_size = XT_NUM_REGS + xtensa->num_optregs; struct reg *reg_list = calloc(reg_list_size, sizeof(struct reg)); if (!reg_list) { LOG_ERROR("Failed to alloc reg list!"); goto fail; } xtensa->dbregs_num = 0; unsigned int didx = 0; for (unsigned int whichlist = 0; whichlist < 2; whichlist++) { struct xtensa_reg_desc *rlist = (whichlist == 0) ? xtensa_regs : xtensa->optregs; unsigned int listsize = (whichlist == 0) ? XT_NUM_REGS : xtensa->num_optregs; for (unsigned int i = 0; i < listsize; i++, didx++) { reg_list[didx].exist = rlist[i].exist; reg_list[didx].name = rlist[i].name; reg_list[didx].size = 32; reg_list[didx].value = calloc(1, 4 /*XT_REG_LEN*/); /* make Clang Static Analyzer happy */ if (!reg_list[didx].value) { LOG_ERROR("Failed to alloc reg list value!"); goto fail; } reg_list[didx].dirty = false; reg_list[didx].valid = false; reg_list[didx].type = &xtensa_reg_type; reg_list[didx].arch_info = xtensa; if (rlist[i].exist && (rlist[i].dbreg_num > last_dbreg_num)) last_dbreg_num = rlist[i].dbreg_num; if (xtensa_extra_debug_log) { LOG_TARGET_DEBUG(target, "POPULATE %-16s list %d exist %d, idx %d, type %d, dbreg_num 0x%04x", reg_list[didx].name, whichlist, reg_list[didx].exist, didx, rlist[i].type, rlist[i].dbreg_num); } } } xtensa->dbregs_num = last_dbreg_num + 1; reg_cache->reg_list = reg_list; reg_cache->num_regs = reg_list_size; LOG_TARGET_DEBUG(target, "xtensa->total_regs_num %d reg_list_size %d xtensa->dbregs_num %d", xtensa->total_regs_num, reg_list_size, xtensa->dbregs_num); /* Construct empty-register list for handling unknown register requests */ xtensa->empty_regs = calloc(xtensa->dbregs_num, sizeof(struct reg)); if (!xtensa->empty_regs) { LOG_TARGET_ERROR(target, "ERROR: Out of memory"); goto fail; } for (unsigned int i = 0; i < xtensa->dbregs_num; i++) { xtensa->empty_regs[i].name = calloc(8, sizeof(char)); if (!xtensa->empty_regs[i].name) { LOG_TARGET_ERROR(target, "ERROR: Out of memory"); goto fail; } sprintf((char *)xtensa->empty_regs[i].name, "?0x%04x", i & 0x0000FFFF); xtensa->empty_regs[i].size = 32; xtensa->empty_regs[i].type = &xtensa_reg_type; xtensa->empty_regs[i].value = calloc(1, 4 /*XT_REG_LEN*/); /* make Clang Static Analyzer happy */ if (!xtensa->empty_regs[i].value) { LOG_ERROR("Failed to alloc empty reg list value!"); goto fail; } xtensa->empty_regs[i].arch_info = xtensa; } /* Construct contiguous register list from contiguous descriptor list */ if (xtensa->regmap_contiguous && xtensa->contiguous_regs_desc) { xtensa->contiguous_regs_list = calloc(xtensa->total_regs_num, sizeof(struct reg *)); if (!xtensa->contiguous_regs_list) { LOG_TARGET_ERROR(target, "ERROR: Out of memory"); goto fail; } for (unsigned int i = 0; i < xtensa->total_regs_num; i++) { unsigned int j; for (j = 0; j < reg_cache->num_regs; j++) { if (!strcmp(reg_cache->reg_list[j].name, xtensa->contiguous_regs_desc[i]->name)) { /* Register number field is not filled above. Here we are assigning the corresponding index from the contiguous reg list. These indexes are in the same order with gdb g-packet request/response. Some more changes may be required for sparse reg lists. */ reg_cache->reg_list[j].number = i; xtensa->contiguous_regs_list[i] = &(reg_cache->reg_list[j]); LOG_TARGET_DEBUG(target, "POPULATE contiguous regs list: %-16s, dbreg_num 0x%04x", xtensa->contiguous_regs_list[i]->name, xtensa->contiguous_regs_desc[i]->dbreg_num); break; } } if (j == reg_cache->num_regs) LOG_TARGET_WARNING(target, "contiguous register %s not found", xtensa->contiguous_regs_desc[i]->name); } } xtensa->algo_context_backup = calloc(reg_cache->num_regs, sizeof(void *)); if (!xtensa->algo_context_backup) { LOG_ERROR("Failed to alloc mem for algorithm context backup!"); goto fail; } for (unsigned int i = 0; i < reg_cache->num_regs; i++) { struct reg *reg = ®_cache->reg_list[i]; xtensa->algo_context_backup[i] = calloc(1, reg->size / 8); if (!xtensa->algo_context_backup[i]) { LOG_ERROR("Failed to alloc mem for algorithm context!"); goto fail; } } xtensa->core_cache = reg_cache; if (cache_p) *cache_p = reg_cache; return ERROR_OK; fail: if (reg_list) { for (unsigned int i = 0; i < reg_list_size; i++) free(reg_list[i].value); free(reg_list); } if (xtensa->empty_regs) { for (unsigned int i = 0; i < xtensa->dbregs_num; i++) { free((void *)xtensa->empty_regs[i].name); free(xtensa->empty_regs[i].value); } free(xtensa->empty_regs); } if (xtensa->algo_context_backup) { for (unsigned int i = 0; i < reg_cache->num_regs; i++) free(xtensa->algo_context_backup[i]); free(xtensa->algo_context_backup); } free(reg_cache); return ERROR_FAIL; } static int32_t xtensa_gdbqc_parse_exec_tie_ops(struct target *target, char *opstr) { struct xtensa *xtensa = target_to_xtensa(target); int32_t status = ERROR_COMMAND_ARGUMENT_INVALID; /* Process op[] list */ while (opstr && (*opstr == ':')) { uint8_t ops[32]; unsigned int oplen = strtoul(opstr + 1, &opstr, 16); if (oplen > 32) { LOG_TARGET_ERROR(target, "TIE access instruction too long (%d)\n", oplen); break; } unsigned int i = 0; while ((i < oplen) && opstr && (*opstr == ':')) ops[i++] = strtoul(opstr + 1, &opstr, 16); if (i != oplen) { LOG_TARGET_ERROR(target, "TIE access instruction malformed (%d)\n", i); break; } char insn_buf[128]; sprintf(insn_buf, "Exec %d-byte TIE sequence: ", oplen); for (i = 0; i < oplen; i++) sprintf(insn_buf + strlen(insn_buf), "%02x:", ops[i]); LOG_TARGET_DEBUG(target, "%s", insn_buf); xtensa_queue_exec_ins_wide(xtensa, ops, oplen); /* Handles endian-swap */ status = ERROR_OK; } return status; } static int xtensa_gdbqc_qxtreg(struct target *target, const char *packet, char **response_p) { struct xtensa *xtensa = target_to_xtensa(target); bool iswrite = (packet[0] == 'Q'); enum xtensa_qerr_e error; /* Read/write TIE register. Requires spill location. * qxtreg<num>:<len>:<oplen>:<op[0]>:<...>[:<oplen>:<op[0]>:<...>] * Qxtreg<num>:<len>:<oplen>:<op[0]>:<...>[:<oplen>:<op[0]>:<...>]=<value> */ if (!(xtensa->spill_buf)) { LOG_ERROR("Spill location not specified. Try 'target remote <host>:3333 &spill_location0'"); error = XT_QERR_FAIL; goto xtensa_gdbqc_qxtreg_fail; } char *delim; uint32_t regnum = strtoul(packet + 6, &delim, 16); if (*delim != ':') { LOG_ERROR("Malformed qxtreg packet"); error = XT_QERR_INVAL; goto xtensa_gdbqc_qxtreg_fail; } uint32_t reglen = strtoul(delim + 1, &delim, 16); if (*delim != ':') { LOG_ERROR("Malformed qxtreg packet"); error = XT_QERR_INVAL; goto xtensa_gdbqc_qxtreg_fail; } uint8_t regbuf[XT_QUERYPKT_RESP_MAX]; memset(regbuf, 0, XT_QUERYPKT_RESP_MAX); LOG_DEBUG("TIE reg 0x%08" PRIx32 " %s (%d bytes)", regnum, iswrite ? "write" : "read", reglen); if (reglen * 2 + 1 > XT_QUERYPKT_RESP_MAX) { LOG_ERROR("TIE register too large"); error = XT_QERR_MEM; goto xtensa_gdbqc_qxtreg_fail; } /* (1) Save spill memory, (1.5) [if write then store value to spill location], * (2) read old a4, (3) write spill address to a4. * NOTE: ensure a4 is restored properly by all error handling logic */ unsigned int memop_size = (xtensa->spill_loc & 3) ? 1 : 4; int status = xtensa_read_memory(target, xtensa->spill_loc, memop_size, xtensa->spill_bytes / memop_size, xtensa->spill_buf); if (status != ERROR_OK) { LOG_ERROR("Spill memory save"); error = XT_QERR_MEM; goto xtensa_gdbqc_qxtreg_fail; } if (iswrite) { /* Extract value and store in spill memory */ unsigned int b = 0; char *valbuf = strchr(delim, '='); if (!(valbuf && (*valbuf == '='))) { LOG_ERROR("Malformed Qxtreg packet"); error = XT_QERR_INVAL; goto xtensa_gdbqc_qxtreg_fail; } valbuf++; while (*valbuf && *(valbuf + 1)) { char bytestr[3] = { 0, 0, 0 }; strncpy(bytestr, valbuf, 2); regbuf[b++] = strtoul(bytestr, NULL, 16); valbuf += 2; } if (b != reglen) { LOG_ERROR("Malformed Qxtreg packet"); error = XT_QERR_INVAL; goto xtensa_gdbqc_qxtreg_fail; } status = xtensa_write_memory(target, xtensa->spill_loc, memop_size, reglen / memop_size, regbuf); if (status != ERROR_OK) { LOG_ERROR("TIE value store"); error = XT_QERR_MEM; goto xtensa_gdbqc_qxtreg_fail; } } xtensa_reg_val_t orig_a4 = xtensa_reg_get(target, XT_REG_IDX_A4); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, xtensa->spill_loc); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A4)); int32_t tieop_status = xtensa_gdbqc_parse_exec_tie_ops(target, delim); /* Restore a4 but not yet spill memory. Execute it all... */ xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, orig_a4); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A4)); status = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (status != ERROR_OK) { LOG_TARGET_ERROR(target, "TIE queue execute: %d\n", status); tieop_status = status; } status = xtensa_core_status_check(target); if (status != ERROR_OK) { LOG_TARGET_ERROR(target, "TIE instr execute: %d\n", status); tieop_status = status; } if (tieop_status == ERROR_OK) { if (iswrite) { /* TIE write succeeded; send OK */ strcpy(*response_p, "OK"); } else { /* TIE read succeeded; copy result from spill memory */ status = xtensa_read_memory(target, xtensa->spill_loc, memop_size, reglen, regbuf); if (status != ERROR_OK) { LOG_TARGET_ERROR(target, "TIE result read"); tieop_status = status; } unsigned int i; for (i = 0; i < reglen; i++) sprintf(*response_p + 2 * i, "%02x", regbuf[i]); *(*response_p + 2 * i) = '\0'; LOG_TARGET_DEBUG(target, "TIE response: %s", *response_p); } } /* Restore spill memory first, then report any previous errors */ status = xtensa_write_memory(target, xtensa->spill_loc, memop_size, xtensa->spill_bytes / memop_size, xtensa->spill_buf); if (status != ERROR_OK) { LOG_ERROR("Spill memory restore"); error = XT_QERR_MEM; goto xtensa_gdbqc_qxtreg_fail; } if (tieop_status != ERROR_OK) { LOG_ERROR("TIE execution"); error = XT_QERR_FAIL; goto xtensa_gdbqc_qxtreg_fail; } return ERROR_OK; xtensa_gdbqc_qxtreg_fail: strcpy(*response_p, xt_qerr[error].chrval); return xt_qerr[error].intval; } int xtensa_gdb_query_custom(struct target *target, const char *packet, char **response_p) { struct xtensa *xtensa = target_to_xtensa(target); enum xtensa_qerr_e error; if (!packet || !response_p) { LOG_TARGET_ERROR(target, "invalid parameter: packet %p response_p %p", packet, response_p); return ERROR_FAIL; } *response_p = xtensa->qpkt_resp; if (strncmp(packet, "qxtn", 4) == 0) { strcpy(*response_p, "OpenOCD"); return ERROR_OK; } else if (strncasecmp(packet, "qxtgdbversion=", 14) == 0) { return ERROR_OK; } else if ((strncmp(packet, "Qxtsis=", 7) == 0) || (strncmp(packet, "Qxtsds=", 7) == 0)) { /* Confirm host cache params match core .cfg file */ struct xtensa_cache_config *cachep = (packet[4] == 'i') ? &xtensa->core_config->icache : &xtensa->core_config->dcache; unsigned int line_size = 0, size = 0, way_count = 0; sscanf(&packet[7], "%x,%x,%x", &line_size, &size, &way_count); if ((cachep->line_size != line_size) || (cachep->size != size) || (cachep->way_count != way_count)) { LOG_TARGET_WARNING(target, "%cCache mismatch; check xtensa-core-XXX.cfg file", cachep == &xtensa->core_config->icache ? 'I' : 'D'); } strcpy(*response_p, "OK"); return ERROR_OK; } else if ((strncmp(packet, "Qxtiram=", 8) == 0) || (strncmp(packet, "Qxtirom=", 8) == 0)) { /* Confirm host IRAM/IROM params match core .cfg file */ struct xtensa_local_mem_config *memp = (packet[5] == 'a') ? &xtensa->core_config->iram : &xtensa->core_config->irom; unsigned int base = 0, size = 0, i; char *pkt = (char *)&packet[7]; do { pkt++; size = strtoul(pkt, &pkt, 16); pkt++; base = strtoul(pkt, &pkt, 16); LOG_TARGET_DEBUG(target, "memcheck: %dB @ 0x%08x", size, base); for (i = 0; i < memp->count; i++) { if ((memp->regions[i].base == base) && (memp->regions[i].size == size)) break; } if (i == memp->count) { LOG_TARGET_WARNING(target, "%s mismatch; check xtensa-core-XXX.cfg file", memp == &xtensa->core_config->iram ? "IRAM" : "IROM"); break; } for (i = 0; i < 11; i++) { pkt++; strtoul(pkt, &pkt, 16); } } while (pkt && (pkt[0] == ',')); strcpy(*response_p, "OK"); return ERROR_OK; } else if (strncmp(packet, "Qxtexcmlvl=", 11) == 0) { /* Confirm host EXCM_LEVEL matches core .cfg file */ unsigned int excm_level = strtoul(&packet[11], NULL, 0); if (!xtensa->core_config->high_irq.enabled || (excm_level != xtensa->core_config->high_irq.excm_level)) LOG_TARGET_WARNING(target, "EXCM_LEVEL mismatch; check xtensa-core-XXX.cfg file"); strcpy(*response_p, "OK"); return ERROR_OK; } else if ((strncmp(packet, "Qxtl2cs=", 8) == 0) || (strncmp(packet, "Qxtl2ca=", 8) == 0) || (strncmp(packet, "Qxtdensity=", 11) == 0)) { strcpy(*response_p, "OK"); return ERROR_OK; } else if (strncmp(packet, "Qxtspill=", 9) == 0) { char *delim; uint32_t spill_loc = strtoul(packet + 9, &delim, 16); if (*delim != ':') { LOG_ERROR("Malformed Qxtspill packet"); error = XT_QERR_INVAL; goto xtensa_gdb_query_custom_fail; } xtensa->spill_loc = spill_loc; xtensa->spill_bytes = strtoul(delim + 1, NULL, 16); if (xtensa->spill_buf) free(xtensa->spill_buf); xtensa->spill_buf = calloc(1, xtensa->spill_bytes); if (!xtensa->spill_buf) { LOG_ERROR("Spill buf alloc"); error = XT_QERR_MEM; goto xtensa_gdb_query_custom_fail; } LOG_TARGET_DEBUG(target, "Set spill 0x%08" PRIx32 " (%d)", xtensa->spill_loc, xtensa->spill_bytes); strcpy(*response_p, "OK"); return ERROR_OK; } else if (strncasecmp(packet, "qxtreg", 6) == 0) { return xtensa_gdbqc_qxtreg(target, packet, response_p); } else if ((strncmp(packet, "qTStatus", 8) == 0) || (strncmp(packet, "qxtftie", 7) == 0) || (strncmp(packet, "qxtstie", 7) == 0)) { /* Return empty string to indicate trace, TIE wire debug are unsupported */ strcpy(*response_p, ""); return ERROR_OK; } /* Warn for all other queries, but do not return errors */ LOG_TARGET_WARNING(target, "Unknown target-specific query packet: %s", packet); strcpy(*response_p, ""); return ERROR_OK; xtensa_gdb_query_custom_fail: strcpy(*response_p, xt_qerr[error].chrval); return xt_qerr[error].intval; } int xtensa_init_arch_info(struct target *target, struct xtensa *xtensa, const struct xtensa_debug_module_config *dm_cfg) { target->arch_info = xtensa; xtensa->common_magic = XTENSA_COMMON_MAGIC; xtensa->target = target; xtensa->stepping_isr_mode = XT_STEPPING_ISR_ON; xtensa->core_config = calloc(1, sizeof(struct xtensa_config)); if (!xtensa->core_config) { LOG_ERROR("Xtensa configuration alloc failed\n"); return ERROR_FAIL; } /* Default cache settings are disabled with 1 way */ xtensa->core_config->icache.way_count = 1; xtensa->core_config->dcache.way_count = 1; /* chrval: AR3/AR4 register names will change with window mapping. * intval: tracks whether scratch register was set through gdb P packet. */ for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++) { xtensa->scratch_ars[s].chrval = calloc(8, sizeof(char)); if (!xtensa->scratch_ars[s].chrval) { for (enum xtensa_ar_scratch_set_e f = 0; f < s; f++) free(xtensa->scratch_ars[f].chrval); free(xtensa->core_config); LOG_ERROR("Xtensa scratch AR alloc failed\n"); return ERROR_FAIL; } xtensa->scratch_ars[s].intval = false; sprintf(xtensa->scratch_ars[s].chrval, "%s%d", ((s == XT_AR_SCRATCH_A3) || (s == XT_AR_SCRATCH_A4)) ? "a" : "ar", ((s == XT_AR_SCRATCH_A3) || (s == XT_AR_SCRATCH_AR3)) ? 3 : 4); } return xtensa_dm_init(&xtensa->dbg_mod, dm_cfg); } void xtensa_set_permissive_mode(struct target *target, bool state) { target_to_xtensa(target)->permissive_mode = state; } int xtensa_target_init(struct command_context *cmd_ctx, struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); xtensa->come_online_probes_num = 3; xtensa->hw_brps = calloc(XT_HW_IBREAK_MAX_NUM, sizeof(struct breakpoint *)); if (!xtensa->hw_brps) { LOG_ERROR("Failed to alloc memory for HW breakpoints!"); return ERROR_FAIL; } xtensa->hw_wps = calloc(XT_HW_DBREAK_MAX_NUM, sizeof(struct watchpoint *)); if (!xtensa->hw_wps) { free(xtensa->hw_brps); LOG_ERROR("Failed to alloc memory for HW watchpoints!"); return ERROR_FAIL; } xtensa->sw_brps = calloc(XT_SW_BREAKPOINTS_MAX_NUM, sizeof(struct xtensa_sw_breakpoint)); if (!xtensa->sw_brps) { free(xtensa->hw_brps); free(xtensa->hw_wps); LOG_ERROR("Failed to alloc memory for SW breakpoints!"); return ERROR_FAIL; } xtensa->spill_loc = 0xffffffff; xtensa->spill_bytes = 0; xtensa->spill_buf = NULL; xtensa->probe_lsddr32p = -1; /* Probe for fast load/store operations */ return xtensa_build_reg_cache(target); } static void xtensa_free_reg_cache(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); struct reg_cache *cache = xtensa->core_cache; if (cache) { register_unlink_cache(&target->reg_cache, cache); for (unsigned int i = 0; i < cache->num_regs; i++) { free(xtensa->algo_context_backup[i]); free(cache->reg_list[i].value); } free(xtensa->algo_context_backup); free(cache->reg_list); free(cache); } xtensa->core_cache = NULL; xtensa->algo_context_backup = NULL; if (xtensa->empty_regs) { for (unsigned int i = 0; i < xtensa->dbregs_num; i++) { free((void *)xtensa->empty_regs[i].name); free(xtensa->empty_regs[i].value); } free(xtensa->empty_regs); } xtensa->empty_regs = NULL; if (xtensa->optregs) { for (unsigned int i = 0; i < xtensa->num_optregs; i++) free((void *)xtensa->optregs[i].name); free(xtensa->optregs); } xtensa->optregs = NULL; } void xtensa_target_deinit(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); LOG_DEBUG("start"); if (target_was_examined(target)) { int ret = xtensa_queue_dbg_reg_write(xtensa, XDMREG_DCRCLR, OCDDCR_ENABLEOCD); if (ret != ERROR_OK) { LOG_ERROR("Failed to queue OCDDCR_ENABLEOCD clear operation!"); return; } xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); ret = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (ret != ERROR_OK) { LOG_ERROR("Failed to clear OCDDCR_ENABLEOCD!"); return; } xtensa_dm_deinit(&xtensa->dbg_mod); } xtensa_free_reg_cache(target); free(xtensa->hw_brps); free(xtensa->hw_wps); free(xtensa->sw_brps); if (xtensa->spill_buf) { free(xtensa->spill_buf); xtensa->spill_buf = NULL; } for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++) free(xtensa->scratch_ars[s].chrval); free(xtensa->core_config); } const char *xtensa_get_gdb_arch(struct target *target) { return "xtensa"; } /* exe <ascii-encoded hexadecimal instruction bytes> */ static COMMAND_HELPER(xtensa_cmd_exe_do, struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; /* Process ascii-encoded hex byte string */ const char *parm = CMD_ARGV[0]; unsigned int parm_len = strlen(parm); if ((parm_len >= 64) || (parm_len & 1)) { LOG_ERROR("Invalid parameter length (%d): must be even, < 64 characters", parm_len); return ERROR_FAIL; } uint8_t ops[32]; memset(ops, 0, 32); unsigned int oplen = parm_len / 2; char encoded_byte[3] = { 0, 0, 0 }; for (unsigned int i = 0; i < oplen; i++) { encoded_byte[0] = *parm++; encoded_byte[1] = *parm++; ops[i] = strtoul(encoded_byte, NULL, 16); } /* GDB must handle state save/restore. * Flush reg cache in case spill location is in an AR * Update CPENABLE only for this execution; later restore cached copy * Keep a copy of exccause in case executed code triggers an exception */ int status = xtensa_write_dirty_registers(target); if (status != ERROR_OK) { LOG_ERROR("%s: Failed to write back register cache.", target_name(target)); return ERROR_FAIL; } xtensa_reg_val_t exccause = xtensa_reg_get(target, XT_REG_IDX_EXCCAUSE); xtensa_reg_val_t cpenable = xtensa_reg_get(target, XT_REG_IDX_CPENABLE); xtensa_reg_val_t a3 = xtensa_reg_get(target, XT_REG_IDX_A3); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, 0xffffffff); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, xtensa_regs[XT_REG_IDX_CPENABLE].reg_num, XT_REG_A3)); xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, a3); xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); /* Queue instruction list and execute everything */ LOG_TARGET_DEBUG(target, "execute stub: %s", CMD_ARGV[0]); xtensa_queue_exec_ins_wide(xtensa, ops, oplen); /* Handles endian-swap */ status = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (status != ERROR_OK) LOG_TARGET_ERROR(target, "TIE queue execute: %d\n", status); status = xtensa_core_status_check(target); if (status != ERROR_OK) LOG_TARGET_ERROR(target, "TIE instr execute: %d\n", status); /* Reread register cache and restore saved regs after instruction execution */ if (xtensa_fetch_all_regs(target) != ERROR_OK) LOG_TARGET_ERROR(target, "%s: Failed to fetch register cache (post-exec).", target_name(target)); xtensa_reg_set(target, XT_REG_IDX_EXCCAUSE, exccause); xtensa_reg_set(target, XT_REG_IDX_CPENABLE, cpenable); return status; } COMMAND_HANDLER(xtensa_cmd_exe) { return CALL_COMMAND_HANDLER(xtensa_cmd_exe_do, get_current_target(CMD_CTX)); } /* xtdef <name> */ COMMAND_HELPER(xtensa_cmd_xtdef_do, struct xtensa *xtensa) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; const char *core_name = CMD_ARGV[0]; if (strcasecmp(core_name, "LX") == 0) { xtensa->core_config->core_type = XT_LX; } else if (strcasecmp(core_name, "NX") == 0) { xtensa->core_config->core_type = XT_NX; } else { LOG_ERROR("xtdef [LX|NX]\n"); return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } COMMAND_HANDLER(xtensa_cmd_xtdef) { return CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do, target_to_xtensa(get_current_target(CMD_CTX))); } static inline bool xtensa_cmd_xtopt_legal_val(char *opt, int val, int min, int max) { if ((val < min) || (val > max)) { LOG_ERROR("xtopt %s (%d) out of range [%d..%d]\n", opt, val, min, max); return false; } return true; } /* xtopt <name> <value> */ COMMAND_HELPER(xtensa_cmd_xtopt_do, struct xtensa *xtensa) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; const char *opt_name = CMD_ARGV[0]; int opt_val = strtol(CMD_ARGV[1], NULL, 0); if (strcasecmp(opt_name, "arnum") == 0) { if (!xtensa_cmd_xtopt_legal_val("arnum", opt_val, 0, 64)) return ERROR_COMMAND_ARGUMENT_INVALID; xtensa->core_config->aregs_num = opt_val; } else if (strcasecmp(opt_name, "windowed") == 0) { if (!xtensa_cmd_xtopt_legal_val("windowed", opt_val, 0, 1)) return ERROR_COMMAND_ARGUMENT_INVALID; xtensa->core_config->windowed = opt_val; } else if (strcasecmp(opt_name, "cpenable") == 0) { if (!xtensa_cmd_xtopt_legal_val("cpenable", opt_val, 0, 1)) return ERROR_COMMAND_ARGUMENT_INVALID; xtensa->core_config->coproc = opt_val; } else if (strcasecmp(opt_name, "exceptions") == 0) { if (!xtensa_cmd_xtopt_legal_val("exceptions", opt_val, 0, 1)) return ERROR_COMMAND_ARGUMENT_INVALID; xtensa->core_config->exceptions = opt_val; } else if (strcasecmp(opt_name, "intnum") == 0) { if (!xtensa_cmd_xtopt_legal_val("intnum", opt_val, 0, 32)) return ERROR_COMMAND_ARGUMENT_INVALID; xtensa->core_config->irq.enabled = (opt_val > 0); xtensa->core_config->irq.irq_num = opt_val; } else if (strcasecmp(opt_name, "hipriints") == 0) { if (!xtensa_cmd_xtopt_legal_val("hipriints", opt_val, 0, 1)) return ERROR_COMMAND_ARGUMENT_INVALID; xtensa->core_config->high_irq.enabled = opt_val; } else if (strcasecmp(opt_name, "excmlevel") == 0) { if (!xtensa_cmd_xtopt_legal_val("excmlevel", opt_val, 1, 6)) return ERROR_COMMAND_ARGUMENT_INVALID; if (!xtensa->core_config->high_irq.enabled) { LOG_ERROR("xtopt excmlevel requires hipriints\n"); return ERROR_COMMAND_ARGUMENT_INVALID; } xtensa->core_config->high_irq.excm_level = opt_val; } else if (strcasecmp(opt_name, "intlevels") == 0) { if (xtensa->core_config->core_type == XT_LX) { if (!xtensa_cmd_xtopt_legal_val("intlevels", opt_val, 2, 6)) return ERROR_COMMAND_ARGUMENT_INVALID; } else { if (!xtensa_cmd_xtopt_legal_val("intlevels", opt_val, 1, 255)) return ERROR_COMMAND_ARGUMENT_INVALID; } if (!xtensa->core_config->high_irq.enabled) { LOG_ERROR("xtopt intlevels requires hipriints\n"); return ERROR_COMMAND_ARGUMENT_INVALID; } xtensa->core_config->high_irq.level_num = opt_val; } else if (strcasecmp(opt_name, "debuglevel") == 0) { if (xtensa->core_config->core_type == XT_LX) { if (!xtensa_cmd_xtopt_legal_val("debuglevel", opt_val, 2, 6)) return ERROR_COMMAND_ARGUMENT_INVALID; } else { if (!xtensa_cmd_xtopt_legal_val("debuglevel", opt_val, 0, 0)) return ERROR_COMMAND_ARGUMENT_INVALID; } xtensa->core_config->debug.enabled = 1; xtensa->core_config->debug.irq_level = opt_val; } else if (strcasecmp(opt_name, "ibreaknum") == 0) { if (!xtensa_cmd_xtopt_legal_val("ibreaknum", opt_val, 0, 2)) return ERROR_COMMAND_ARGUMENT_INVALID; xtensa->core_config->debug.ibreaks_num = opt_val; } else if (strcasecmp(opt_name, "dbreaknum") == 0) { if (!xtensa_cmd_xtopt_legal_val("dbreaknum", opt_val, 0, 2)) return ERROR_COMMAND_ARGUMENT_INVALID; xtensa->core_config->debug.dbreaks_num = opt_val; } else if (strcasecmp(opt_name, "tracemem") == 0) { if (!xtensa_cmd_xtopt_legal_val("tracemem", opt_val, 0, 256 * 1024)) return ERROR_COMMAND_ARGUMENT_INVALID; xtensa->core_config->trace.mem_sz = opt_val; xtensa->core_config->trace.enabled = (opt_val > 0); } else if (strcasecmp(opt_name, "tracememrev") == 0) { if (!xtensa_cmd_xtopt_legal_val("tracememrev", opt_val, 0, 1)) return ERROR_COMMAND_ARGUMENT_INVALID; xtensa->core_config->trace.reversed_mem_access = opt_val; } else if (strcasecmp(opt_name, "perfcount") == 0) { if (!xtensa_cmd_xtopt_legal_val("perfcount", opt_val, 0, 8)) return ERROR_COMMAND_ARGUMENT_INVALID; xtensa->core_config->debug.perfcount_num = opt_val; } else { LOG_WARNING("Unknown xtensa command ignored: \"xtopt %s %s\"", CMD_ARGV[0], CMD_ARGV[1]); return ERROR_OK; } return ERROR_OK; } COMMAND_HANDLER(xtensa_cmd_xtopt) { return CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do, target_to_xtensa(get_current_target(CMD_CTX))); } /* xtmem <type> [parameters] */ COMMAND_HELPER(xtensa_cmd_xtmem_do, struct xtensa *xtensa) { struct xtensa_cache_config *cachep = NULL; struct xtensa_local_mem_config *memp = NULL; int mem_access = 0; bool is_dcache = false; if (CMD_ARGC == 0) { LOG_ERROR("xtmem <type> [parameters]\n"); return ERROR_COMMAND_SYNTAX_ERROR; } const char *mem_name = CMD_ARGV[0]; if (strcasecmp(mem_name, "icache") == 0) { cachep = &xtensa->core_config->icache; } else if (strcasecmp(mem_name, "dcache") == 0) { cachep = &xtensa->core_config->dcache; is_dcache = true; } else if (strcasecmp(mem_name, "l2cache") == 0) { /* TODO: support L2 cache */ } else if (strcasecmp(mem_name, "l2addr") == 0) { /* TODO: support L2 cache */ } else if (strcasecmp(mem_name, "iram") == 0) { memp = &xtensa->core_config->iram; mem_access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE; } else if (strcasecmp(mem_name, "dram") == 0) { memp = &xtensa->core_config->dram; mem_access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE; } else if (strcasecmp(mem_name, "sram") == 0) { memp = &xtensa->core_config->sram; mem_access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE; } else if (strcasecmp(mem_name, "irom") == 0) { memp = &xtensa->core_config->irom; mem_access = XT_MEM_ACCESS_READ; } else if (strcasecmp(mem_name, "drom") == 0) { memp = &xtensa->core_config->drom; mem_access = XT_MEM_ACCESS_READ; } else if (strcasecmp(mem_name, "srom") == 0) { memp = &xtensa->core_config->srom; mem_access = XT_MEM_ACCESS_READ; } else { LOG_ERROR("xtmem types: <icache|dcache|l2cache|l2addr|iram|irom|dram|drom|sram|srom>\n"); return ERROR_COMMAND_ARGUMENT_INVALID; } if (cachep) { if ((CMD_ARGC != 4) && (CMD_ARGC != 5)) { LOG_ERROR("xtmem <cachetype> <linebytes> <cachebytes> <ways> [writeback]\n"); return ERROR_COMMAND_SYNTAX_ERROR; } cachep->line_size = strtoul(CMD_ARGV[1], NULL, 0); cachep->size = strtoul(CMD_ARGV[2], NULL, 0); cachep->way_count = strtoul(CMD_ARGV[3], NULL, 0); cachep->writeback = ((CMD_ARGC == 5) && is_dcache) ? strtoul(CMD_ARGV[4], NULL, 0) : 0; } else if (memp) { if (CMD_ARGC != 3) { LOG_ERROR("xtmem <memtype> <baseaddr> <bytes>\n"); return ERROR_COMMAND_SYNTAX_ERROR; } struct xtensa_local_mem_region_config *memcfgp = &memp->regions[memp->count]; memcfgp->base = strtoul(CMD_ARGV[1], NULL, 0); memcfgp->size = strtoul(CMD_ARGV[2], NULL, 0); memcfgp->access = mem_access; memp->count++; } return ERROR_OK; } COMMAND_HANDLER(xtensa_cmd_xtmem) { return CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do, target_to_xtensa(get_current_target(CMD_CTX))); } /* xtmpu <num FG seg> <min seg size> <lockable> <executeonly> */ COMMAND_HELPER(xtensa_cmd_xtmpu_do, struct xtensa *xtensa) { if (CMD_ARGC != 4) { LOG_ERROR("xtmpu <num FG seg> <min seg size> <lockable> <executeonly>\n"); return ERROR_COMMAND_SYNTAX_ERROR; } unsigned int nfgseg = strtoul(CMD_ARGV[0], NULL, 0); unsigned int minsegsize = strtoul(CMD_ARGV[1], NULL, 0); unsigned int lockable = strtoul(CMD_ARGV[2], NULL, 0); unsigned int execonly = strtoul(CMD_ARGV[3], NULL, 0); if ((nfgseg > 32)) { LOG_ERROR("<nfgseg> must be within [0..32]\n"); return ERROR_COMMAND_ARGUMENT_INVALID; } else if (minsegsize & (minsegsize - 1)) { LOG_ERROR("<minsegsize> must be a power of 2 >= 32\n"); return ERROR_COMMAND_ARGUMENT_INVALID; } else if (lockable > 1) { LOG_ERROR("<lockable> must be 0 or 1\n"); return ERROR_COMMAND_ARGUMENT_INVALID; } else if (execonly > 1) { LOG_ERROR("<execonly> must be 0 or 1\n"); return ERROR_COMMAND_ARGUMENT_INVALID; } xtensa->core_config->mpu.enabled = true; xtensa->core_config->mpu.nfgseg = nfgseg; xtensa->core_config->mpu.minsegsize = minsegsize; xtensa->core_config->mpu.lockable = lockable; xtensa->core_config->mpu.execonly = execonly; return ERROR_OK; } COMMAND_HANDLER(xtensa_cmd_xtmpu) { return CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do, target_to_xtensa(get_current_target(CMD_CTX))); } /* xtmmu <NIREFILLENTRIES> <NDREFILLENTRIES> <IVARWAY56> <DVARWAY56> */ COMMAND_HELPER(xtensa_cmd_xtmmu_do, struct xtensa *xtensa) { if (CMD_ARGC != 2) { LOG_ERROR("xtmmu <NIREFILLENTRIES> <NDREFILLENTRIES>\n"); return ERROR_COMMAND_SYNTAX_ERROR; } unsigned int nirefillentries = strtoul(CMD_ARGV[0], NULL, 0); unsigned int ndrefillentries = strtoul(CMD_ARGV[1], NULL, 0); if ((nirefillentries != 16) && (nirefillentries != 32)) { LOG_ERROR("<nirefillentries> must be 16 or 32\n"); return ERROR_COMMAND_ARGUMENT_INVALID; } else if ((ndrefillentries != 16) && (ndrefillentries != 32)) { LOG_ERROR("<ndrefillentries> must be 16 or 32\n"); return ERROR_COMMAND_ARGUMENT_INVALID; } xtensa->core_config->mmu.enabled = true; xtensa->core_config->mmu.itlb_entries_count = nirefillentries; xtensa->core_config->mmu.dtlb_entries_count = ndrefillentries; return ERROR_OK; } COMMAND_HANDLER(xtensa_cmd_xtmmu) { return CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do, target_to_xtensa(get_current_target(CMD_CTX))); } /* xtregs <numregs> * xtreg <regname> <regnum> */ COMMAND_HELPER(xtensa_cmd_xtreg_do, struct xtensa *xtensa) { if (CMD_ARGC == 1) { int32_t numregs = strtoul(CMD_ARGV[0], NULL, 0); if ((numregs <= 0) || (numregs > UINT16_MAX)) { LOG_ERROR("xtreg <numregs>: Invalid 'numregs' (%d)", numregs); return ERROR_COMMAND_SYNTAX_ERROR; } if ((xtensa->genpkt_regs_num > 0) && (numregs < (int32_t)xtensa->genpkt_regs_num)) { LOG_ERROR("xtregs (%d) must be larger than numgenregs (%d) (if xtregfmt specified)", numregs, xtensa->genpkt_regs_num); return ERROR_COMMAND_SYNTAX_ERROR; } xtensa->total_regs_num = numregs; xtensa->core_regs_num = 0; xtensa->num_optregs = 0; /* A little more memory than required, but saves a second initialization pass */ xtensa->optregs = calloc(xtensa->total_regs_num, sizeof(struct xtensa_reg_desc)); if (!xtensa->optregs) { LOG_ERROR("Failed to allocate xtensa->optregs!"); return ERROR_FAIL; } return ERROR_OK; } else if (CMD_ARGC != 2) { return ERROR_COMMAND_SYNTAX_ERROR; } /* "xtregfmt contiguous" must be specified prior to the first "xtreg" definition * if general register (g-packet) requests or contiguous register maps are supported */ if (xtensa->regmap_contiguous && !xtensa->contiguous_regs_desc) { xtensa->contiguous_regs_desc = calloc(xtensa->total_regs_num, sizeof(struct xtensa_reg_desc *)); if (!xtensa->contiguous_regs_desc) { LOG_ERROR("Failed to allocate xtensa->contiguous_regs_desc!"); return ERROR_FAIL; } } const char *regname = CMD_ARGV[0]; unsigned int regnum = strtoul(CMD_ARGV[1], NULL, 0); if (regnum > UINT16_MAX) { LOG_ERROR("<regnum> must be a 16-bit number"); return ERROR_COMMAND_ARGUMENT_INVALID; } if ((xtensa->num_optregs + xtensa->core_regs_num) >= xtensa->total_regs_num) { if (xtensa->total_regs_num) LOG_ERROR("'xtreg %s 0x%04x': Too many registers (%d expected, %d core %d extended)", regname, regnum, xtensa->total_regs_num, xtensa->core_regs_num, xtensa->num_optregs); else LOG_ERROR("'xtreg %s 0x%04x': Number of registers unspecified", regname, regnum); return ERROR_FAIL; } /* Determine whether register belongs in xtensa_regs[] or xtensa->xtensa_spec_regs[] */ struct xtensa_reg_desc *rptr = &xtensa->optregs[xtensa->num_optregs]; bool is_extended_reg = true; unsigned int ridx; for (ridx = 0; ridx < XT_NUM_REGS; ridx++) { if (strcmp(CMD_ARGV[0], xtensa_regs[ridx].name) == 0) { /* Flag core register as defined */ rptr = &xtensa_regs[ridx]; xtensa->core_regs_num++; is_extended_reg = false; break; } } rptr->exist = true; if (is_extended_reg) { /* Register ID, debugger-visible register ID */ rptr->name = strdup(CMD_ARGV[0]); rptr->dbreg_num = regnum; rptr->reg_num = (regnum & XT_REG_INDEX_MASK); xtensa->num_optregs++; /* Register type */ if ((regnum & XT_REG_GENERAL_MASK) == XT_REG_GENERAL_VAL) { rptr->type = XT_REG_GENERAL; } else if ((regnum & XT_REG_USER_MASK) == XT_REG_USER_VAL) { rptr->type = XT_REG_USER; } else if ((regnum & XT_REG_FR_MASK) == XT_REG_FR_VAL) { rptr->type = XT_REG_FR; } else if ((regnum & XT_REG_SPECIAL_MASK) == XT_REG_SPECIAL_VAL) { rptr->type = XT_REG_SPECIAL; } else if ((regnum & XT_REG_RELGEN_MASK) == XT_REG_RELGEN_VAL) { /* WARNING: For these registers, regnum points to the * index of the corresponding ARx registers, NOT to * the processor register number! */ rptr->type = XT_REG_RELGEN; rptr->reg_num += XT_REG_IDX_ARFIRST; rptr->dbreg_num += XT_REG_IDX_ARFIRST; } else if ((regnum & XT_REG_TIE_MASK) != 0) { rptr->type = XT_REG_TIE; } else { rptr->type = XT_REG_OTHER; } /* Register flags */ if ((strcmp(rptr->name, "mmid") == 0) || (strcmp(rptr->name, "eraccess") == 0) || (strcmp(rptr->name, "ddr") == 0) || (strcmp(rptr->name, "intset") == 0) || (strcmp(rptr->name, "intclear") == 0)) rptr->flags = XT_REGF_NOREAD; else rptr->flags = 0; if (rptr->reg_num == (XT_EPS_REG_NUM_BASE + xtensa->core_config->debug.irq_level) && xtensa->core_config->core_type == XT_LX && rptr->type == XT_REG_SPECIAL) { xtensa->eps_dbglevel_idx = XT_NUM_REGS + xtensa->num_optregs - 1; LOG_DEBUG("Setting PS (%s) index to %d", rptr->name, xtensa->eps_dbglevel_idx); } if (xtensa->core_config->core_type == XT_NX) { enum xtensa_nx_reg_idx idx = XT_NX_REG_IDX_NUM; if (strcmp(rptr->name, "ibreakc0") == 0) idx = XT_NX_REG_IDX_IBREAKC0; else if (strcmp(rptr->name, "wb") == 0) idx = XT_NX_REG_IDX_WB; else if (strcmp(rptr->name, "ms") == 0) idx = XT_NX_REG_IDX_MS; else if (strcmp(rptr->name, "ievec") == 0) idx = XT_NX_REG_IDX_IEVEC; else if (strcmp(rptr->name, "ieextern") == 0) idx = XT_NX_REG_IDX_IEEXTERN; else if (strcmp(rptr->name, "mesr") == 0) idx = XT_NX_REG_IDX_MESR; else if (strcmp(rptr->name, "mesrclr") == 0) idx = XT_NX_REG_IDX_MESRCLR; if (idx < XT_NX_REG_IDX_NUM) { if (xtensa->nx_reg_idx[idx] != 0) { LOG_ERROR("nx_reg_idx[%d] previously set to %d", idx, xtensa->nx_reg_idx[idx]); return ERROR_FAIL; } xtensa->nx_reg_idx[idx] = XT_NUM_REGS + xtensa->num_optregs - 1; LOG_DEBUG("NX reg %s: index %d (%d)", rptr->name, xtensa->nx_reg_idx[idx], idx); } } } else if (strcmp(rptr->name, "cpenable") == 0) { xtensa->core_config->coproc = true; } /* Build out list of contiguous registers in specified order */ unsigned int running_reg_count = xtensa->num_optregs + xtensa->core_regs_num; if (xtensa->contiguous_regs_desc) { assert((running_reg_count <= xtensa->total_regs_num) && "contiguous register address internal error!"); xtensa->contiguous_regs_desc[running_reg_count - 1] = rptr; } if (xtensa_extra_debug_log) LOG_DEBUG("Added %s register %-16s: 0x%04x/0x%02x t%d (%d of %d)", is_extended_reg ? "config-specific" : "core", rptr->name, rptr->dbreg_num, rptr->reg_num, rptr->type, is_extended_reg ? xtensa->num_optregs : ridx, is_extended_reg ? xtensa->total_regs_num : XT_NUM_REGS); return ERROR_OK; } COMMAND_HANDLER(xtensa_cmd_xtreg) { return CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do, target_to_xtensa(get_current_target(CMD_CTX))); } /* xtregfmt <contiguous|sparse> [numgregs] */ COMMAND_HELPER(xtensa_cmd_xtregfmt_do, struct xtensa *xtensa) { if ((CMD_ARGC == 1) || (CMD_ARGC == 2)) { if (!strcasecmp(CMD_ARGV[0], "sparse")) { return ERROR_OK; } else if (!strcasecmp(CMD_ARGV[0], "contiguous")) { xtensa->regmap_contiguous = true; if (CMD_ARGC == 2) { unsigned int numgregs = strtoul(CMD_ARGV[1], NULL, 0); if ((numgregs <= 0) || ((numgregs > xtensa->total_regs_num) && (xtensa->total_regs_num > 0))) { LOG_ERROR("xtregfmt: if specified, numgregs (%d) must be <= numregs (%d)", numgregs, xtensa->total_regs_num); return ERROR_COMMAND_SYNTAX_ERROR; } xtensa->genpkt_regs_num = numgregs; } return ERROR_OK; } } return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_HANDLER(xtensa_cmd_xtregfmt) { return CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do, target_to_xtensa(get_current_target(CMD_CTX))); } COMMAND_HELPER(xtensa_cmd_permissive_mode_do, struct xtensa *xtensa) { return CALL_COMMAND_HANDLER(handle_command_parse_bool, &xtensa->permissive_mode, "xtensa permissive mode"); } COMMAND_HANDLER(xtensa_cmd_permissive_mode) { return CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do, target_to_xtensa(get_current_target(CMD_CTX))); } /* perfmon_enable <counter_id> <select> [mask] [kernelcnt] [tracelevel] */ COMMAND_HELPER(xtensa_cmd_perfmon_enable_do, struct xtensa *xtensa) { struct xtensa_perfmon_config config = { .mask = 0xffff, .kernelcnt = 0, .tracelevel = -1 /* use DEBUGLEVEL by default */ }; if (CMD_ARGC < 2 || CMD_ARGC > 6) return ERROR_COMMAND_SYNTAX_ERROR; unsigned int counter_id = strtoul(CMD_ARGV[0], NULL, 0); if (counter_id >= XTENSA_MAX_PERF_COUNTERS) { command_print(CMD, "counter_id should be < %d", XTENSA_MAX_PERF_COUNTERS); return ERROR_COMMAND_ARGUMENT_INVALID; } config.select = strtoul(CMD_ARGV[1], NULL, 0); if (config.select > XTENSA_MAX_PERF_SELECT) { command_print(CMD, "select should be < %d", XTENSA_MAX_PERF_SELECT); return ERROR_COMMAND_ARGUMENT_INVALID; } if (CMD_ARGC >= 3) { config.mask = strtoul(CMD_ARGV[2], NULL, 0); if (config.mask > XTENSA_MAX_PERF_MASK) { command_print(CMD, "mask should be < %d", XTENSA_MAX_PERF_MASK); return ERROR_COMMAND_ARGUMENT_INVALID; } } if (CMD_ARGC >= 4) { config.kernelcnt = strtoul(CMD_ARGV[3], NULL, 0); if (config.kernelcnt > 1) { command_print(CMD, "kernelcnt should be 0 or 1"); return ERROR_COMMAND_ARGUMENT_INVALID; } } if (CMD_ARGC >= 5) { config.tracelevel = strtoul(CMD_ARGV[4], NULL, 0); if (config.tracelevel > 7) { command_print(CMD, "tracelevel should be <=7"); return ERROR_COMMAND_ARGUMENT_INVALID; } } if (config.tracelevel == -1) config.tracelevel = xtensa->core_config->debug.irq_level; return xtensa_dm_perfmon_enable(&xtensa->dbg_mod, counter_id, &config); } COMMAND_HANDLER(xtensa_cmd_perfmon_enable) { return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do, target_to_xtensa(get_current_target(CMD_CTX))); } /* perfmon_dump [counter_id] */ COMMAND_HELPER(xtensa_cmd_perfmon_dump_do, struct xtensa *xtensa) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; int counter_id = -1; if (CMD_ARGC == 1) { counter_id = strtol(CMD_ARGV[0], NULL, 0); if (counter_id > XTENSA_MAX_PERF_COUNTERS) { command_print(CMD, "counter_id should be < %d", XTENSA_MAX_PERF_COUNTERS); return ERROR_COMMAND_ARGUMENT_INVALID; } } unsigned int counter_start = (counter_id < 0) ? 0 : counter_id; unsigned int counter_end = (counter_id < 0) ? XTENSA_MAX_PERF_COUNTERS : counter_id + 1; for (unsigned int counter = counter_start; counter < counter_end; ++counter) { char result_buf[128] = { 0 }; size_t result_pos = snprintf(result_buf, sizeof(result_buf), "Counter %d: ", counter); struct xtensa_perfmon_result result; int res = xtensa_dm_perfmon_dump(&xtensa->dbg_mod, counter, &result); if (res != ERROR_OK) return res; snprintf(result_buf + result_pos, sizeof(result_buf) - result_pos, "%-12" PRIu64 "%s", result.value, result.overflow ? " (overflow)" : ""); LOG_INFO("%s", result_buf); } return ERROR_OK; } COMMAND_HANDLER(xtensa_cmd_perfmon_dump) { return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do, target_to_xtensa(get_current_target(CMD_CTX))); } COMMAND_HELPER(xtensa_cmd_mask_interrupts_do, struct xtensa *xtensa) { int state = -1; if (CMD_ARGC < 1) { const char *st; state = xtensa->stepping_isr_mode; if (state == XT_STEPPING_ISR_ON) st = "OFF"; else if (state == XT_STEPPING_ISR_OFF) st = "ON"; else st = "UNKNOWN"; command_print(CMD, "Current ISR step mode: %s", st); return ERROR_OK; } if (xtensa->core_config->core_type == XT_NX) { command_print(CMD, "ERROR: ISR step mode only supported on Xtensa LX"); return ERROR_FAIL; } /* Masking is ON -> interrupts during stepping are OFF, and vice versa */ if (!strcasecmp(CMD_ARGV[0], "off")) state = XT_STEPPING_ISR_ON; else if (!strcasecmp(CMD_ARGV[0], "on")) state = XT_STEPPING_ISR_OFF; if (state == -1) { command_print(CMD, "Argument unknown. Please pick one of ON, OFF"); return ERROR_FAIL; } xtensa->stepping_isr_mode = state; return ERROR_OK; } COMMAND_HANDLER(xtensa_cmd_mask_interrupts) { return CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do, target_to_xtensa(get_current_target(CMD_CTX))); } COMMAND_HELPER(xtensa_cmd_smpbreak_do, struct target *target) { int res; uint32_t val = 0; if (CMD_ARGC >= 1) { for (unsigned int i = 0; i < CMD_ARGC; i++) { if (!strcasecmp(CMD_ARGV[0], "none")) { val = 0; } else if (!strcasecmp(CMD_ARGV[i], "BreakIn")) { val |= OCDDCR_BREAKINEN; } else if (!strcasecmp(CMD_ARGV[i], "BreakOut")) { val |= OCDDCR_BREAKOUTEN; } else if (!strcasecmp(CMD_ARGV[i], "RunStallIn")) { val |= OCDDCR_RUNSTALLINEN; } else if (!strcasecmp(CMD_ARGV[i], "DebugModeOut")) { val |= OCDDCR_DEBUGMODEOUTEN; } else if (!strcasecmp(CMD_ARGV[i], "BreakInOut")) { val |= OCDDCR_BREAKINEN | OCDDCR_BREAKOUTEN; } else if (!strcasecmp(CMD_ARGV[i], "RunStall")) { val |= OCDDCR_RUNSTALLINEN | OCDDCR_DEBUGMODEOUTEN; } else { command_print(CMD, "Unknown arg %s", CMD_ARGV[i]); command_print( CMD, "use either BreakInOut, None or RunStall as arguments, or any combination of BreakIn, BreakOut, RunStallIn and DebugModeOut."); return ERROR_OK; } } res = xtensa_smpbreak_set(target, val); if (res != ERROR_OK) command_print(CMD, "Failed to set smpbreak config %d", res); } else { struct xtensa *xtensa = target_to_xtensa(target); res = xtensa_smpbreak_read(xtensa, &val); if (res == ERROR_OK) command_print(CMD, "Current bits set:%s%s%s%s", (val & OCDDCR_BREAKINEN) ? " BreakIn" : "", (val & OCDDCR_BREAKOUTEN) ? " BreakOut" : "", (val & OCDDCR_RUNSTALLINEN) ? " RunStallIn" : "", (val & OCDDCR_DEBUGMODEOUTEN) ? " DebugModeOut" : "" ); else command_print(CMD, "Failed to get smpbreak config %d", res); } return res; } COMMAND_HANDLER(xtensa_cmd_smpbreak) { return CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, get_current_target(CMD_CTX)); } COMMAND_HELPER(xtensa_cmd_tracestart_do, struct xtensa *xtensa) { struct xtensa_trace_status trace_status; struct xtensa_trace_start_config cfg = { .stoppc = 0, .stopmask = XTENSA_STOPMASK_DISABLED, .after = 0, .after_is_words = false }; /* Parse arguments */ for (unsigned int i = 0; i < CMD_ARGC; i++) { if ((!strcasecmp(CMD_ARGV[i], "pc")) && CMD_ARGC > i) { char *e; i++; cfg.stoppc = strtol(CMD_ARGV[i], &e, 0); cfg.stopmask = 0; if (*e == '/') cfg.stopmask = strtol(e, NULL, 0); } else if ((!strcasecmp(CMD_ARGV[i], "after")) && CMD_ARGC > i) { i++; cfg.after = strtol(CMD_ARGV[i], NULL, 0); } else if (!strcasecmp(CMD_ARGV[i], "ins")) { cfg.after_is_words = 0; } else if (!strcasecmp(CMD_ARGV[i], "words")) { cfg.after_is_words = 1; } else { command_print(CMD, "Did not understand %s", CMD_ARGV[i]); return ERROR_FAIL; } } int res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status); if (res != ERROR_OK) return res; if (trace_status.stat & TRAXSTAT_TRACT) { LOG_WARNING("Silently stop active tracing!"); res = xtensa_dm_trace_stop(&xtensa->dbg_mod, false); if (res != ERROR_OK) return res; } res = xtensa_dm_trace_start(&xtensa->dbg_mod, &cfg); if (res != ERROR_OK) return res; xtensa->trace_active = true; command_print(CMD, "Trace started."); return ERROR_OK; } COMMAND_HANDLER(xtensa_cmd_tracestart) { return CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do, target_to_xtensa(get_current_target(CMD_CTX))); } COMMAND_HELPER(xtensa_cmd_tracestop_do, struct xtensa *xtensa) { struct xtensa_trace_status trace_status; int res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status); if (res != ERROR_OK) return res; if (!(trace_status.stat & TRAXSTAT_TRACT)) { command_print(CMD, "No trace is currently active."); return ERROR_FAIL; } res = xtensa_dm_trace_stop(&xtensa->dbg_mod, true); if (res != ERROR_OK) return res; xtensa->trace_active = false; command_print(CMD, "Trace stop triggered."); return ERROR_OK; } COMMAND_HANDLER(xtensa_cmd_tracestop) { return CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do, target_to_xtensa(get_current_target(CMD_CTX))); } COMMAND_HELPER(xtensa_cmd_tracedump_do, struct xtensa *xtensa, const char *fname) { struct xtensa_trace_config trace_config; struct xtensa_trace_status trace_status; uint32_t memsz, wmem; int res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status); if (res != ERROR_OK) return res; if (trace_status.stat & TRAXSTAT_TRACT) { command_print(CMD, "Tracing is still active. Please stop it first."); return ERROR_FAIL; } res = xtensa_dm_trace_config_read(&xtensa->dbg_mod, &trace_config); if (res != ERROR_OK) return res; if (!(trace_config.ctrl & TRAXCTRL_TREN)) { command_print(CMD, "No active trace found; nothing to dump."); return ERROR_FAIL; } memsz = trace_config.memaddr_end - trace_config.memaddr_start + 1; LOG_INFO("Total trace memory: %d words", memsz); if ((trace_config.addr & ((TRAXADDR_TWRAP_MASK << TRAXADDR_TWRAP_SHIFT) | TRAXADDR_TWSAT)) == 0) { /*Memory hasn't overwritten itself yet. */ wmem = trace_config.addr & TRAXADDR_TADDR_MASK; LOG_INFO("...but trace is only %d words", wmem); if (wmem < memsz) memsz = wmem; } else { if (trace_config.addr & TRAXADDR_TWSAT) { LOG_INFO("Real trace is many times longer than that (overflow)"); } else { uint32_t trc_sz = (trace_config.addr >> TRAXADDR_TWRAP_SHIFT) & TRAXADDR_TWRAP_MASK; trc_sz = (trc_sz * memsz) + (trace_config.addr & TRAXADDR_TADDR_MASK); LOG_INFO("Real trace is %d words, but the start has been truncated.", trc_sz); } } uint8_t *tracemem = malloc(memsz * 4); if (!tracemem) { command_print(CMD, "Failed to alloc memory for trace data!"); return ERROR_FAIL; } res = xtensa_dm_trace_data_read(&xtensa->dbg_mod, tracemem, memsz * 4); if (res != ERROR_OK) { free(tracemem); return res; } int f = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (f <= 0) { free(tracemem); command_print(CMD, "Unable to open file %s", fname); return ERROR_FAIL; } if (write(f, tracemem, memsz * 4) != (int)memsz * 4) command_print(CMD, "Unable to write to file %s", fname); else command_print(CMD, "Written %d bytes of trace data to %s", memsz * 4, fname); close(f); bool is_all_zeroes = true; for (unsigned int i = 0; i < memsz * 4; i++) { if (tracemem[i] != 0) { is_all_zeroes = false; break; } } free(tracemem); if (is_all_zeroes) command_print( CMD, "WARNING: File written is all zeroes. Are you sure you enabled trace memory?"); return ERROR_OK; } COMMAND_HANDLER(xtensa_cmd_tracedump) { if (CMD_ARGC != 1) { command_print(CMD, "Command takes exactly 1 parameter.Need filename to dump to as output!"); return ERROR_FAIL; } return CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do, target_to_xtensa(get_current_target(CMD_CTX)), CMD_ARGV[0]); } static const struct command_registration xtensa_any_command_handlers[] = { { .name = "xtdef", .handler = xtensa_cmd_xtdef, .mode = COMMAND_CONFIG, .help = "Configure Xtensa core type", .usage = "<type>", }, { .name = "xtopt", .handler = xtensa_cmd_xtopt, .mode = COMMAND_CONFIG, .help = "Configure Xtensa core option", .usage = "<name> <value>", }, { .name = "xtmem", .handler = xtensa_cmd_xtmem, .mode = COMMAND_CONFIG, .help = "Configure Xtensa memory/cache option", .usage = "<type> [parameters]", }, { .name = "xtmmu", .handler = xtensa_cmd_xtmmu, .mode = COMMAND_CONFIG, .help = "Configure Xtensa MMU option", .usage = "<NIREFILLENTRIES> <NDREFILLENTRIES> <IVARWAY56> <DVARWAY56>", }, { .name = "xtmpu", .handler = xtensa_cmd_xtmpu, .mode = COMMAND_CONFIG, .help = "Configure Xtensa MPU option", .usage = "<num FG seg> <min seg size> <lockable> <executeonly>", }, { .name = "xtreg", .handler = xtensa_cmd_xtreg, .mode = COMMAND_CONFIG, .help = "Configure Xtensa register", .usage = "<regname> <regnum>", }, { .name = "xtregs", .handler = xtensa_cmd_xtreg, .mode = COMMAND_CONFIG, .help = "Configure number of Xtensa registers", .usage = "<numregs>", }, { .name = "xtregfmt", .handler = xtensa_cmd_xtregfmt, .mode = COMMAND_CONFIG, .help = "Configure format of Xtensa register map", .usage = "<contiguous|sparse> [numgregs]", }, { .name = "set_permissive", .handler = xtensa_cmd_permissive_mode, .mode = COMMAND_ANY, .help = "When set to 1, enable Xtensa permissive mode (fewer client-side checks)", .usage = "[0|1]", }, { .name = "maskisr", .handler = xtensa_cmd_mask_interrupts, .mode = COMMAND_ANY, .help = "mask Xtensa interrupts at step", .usage = "['on'|'off']", }, { .name = "smpbreak", .handler = xtensa_cmd_smpbreak, .mode = COMMAND_ANY, .help = "Set the way the CPU chains OCD breaks", .usage = "[none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]", }, { .name = "perfmon_enable", .handler = xtensa_cmd_perfmon_enable, .mode = COMMAND_EXEC, .help = "Enable and start performance counter", .usage = "<counter_id> <select> [mask] [kernelcnt] [tracelevel]", }, { .name = "perfmon_dump", .handler = xtensa_cmd_perfmon_dump, .mode = COMMAND_EXEC, .help = "Dump performance counter value. If no argument specified, dumps all counters.", .usage = "[counter_id]", }, { .name = "tracestart", .handler = xtensa_cmd_tracestart, .mode = COMMAND_EXEC, .help = "Tracing: Set up and start a trace. Optionally set stop trigger address and amount of data captured after.", .usage = "[pc <pcval>/[maskbitcount]] [after <n> [ins|words]]", }, { .name = "tracestop", .handler = xtensa_cmd_tracestop, .mode = COMMAND_EXEC, .help = "Tracing: Stop current trace as started by the tracestart command", .usage = "", }, { .name = "tracedump", .handler = xtensa_cmd_tracedump, .mode = COMMAND_EXEC, .help = "Tracing: Dump trace memory to a files. One file per core.", .usage = "<outfile>", }, { .name = "exe", .handler = xtensa_cmd_exe, .mode = COMMAND_ANY, .help = "Xtensa stub execution", .usage = "<ascii-encoded hexadecimal instruction bytes>", }, COMMAND_REGISTRATION_DONE }; const struct command_registration xtensa_command_handlers[] = { { .name = "xtensa", .mode = COMMAND_ANY, .help = "Xtensa command group", .usage = "", .chain = xtensa_any_command_handlers, }, COMMAND_REGISTRATION_DONE }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/xtensa/xtensa.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Generic Xtensa target * * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * * Copyright (C) 2019 Espressif Systems Ltd. * ***************************************************************************/ #ifndef OPENOCD_TARGET_XTENSA_H #define OPENOCD_TARGET_XTENSA_H #include "assert.h" #include <target/target.h> #include <target/breakpoints.h> #include "xtensa_regs.h" #include "xtensa_debug_module.h" /** * @file * Holds the interface to Xtensa cores. */ /* Big-endian vs. little-endian detection */ #define XT_ISBE(X) ((X)->target->endianness == TARGET_BIG_ENDIAN) /* 24-bit break; BE version field-swapped then byte-swapped for use in memory R/W fns */ #define XT_INS_BREAK_LE(S, T) (0x004000 | (((S) & 0xF) << 8) | (((T) & 0xF) << 4)) #define XT_INS_BREAK_BE(S, T) (0x000400 | (((S) & 0xF) << 12) | ((T) & 0xF)) #define XT_INS_BREAK(X, S, T) (XT_ISBE(X) ? XT_INS_BREAK_BE(S, T) : XT_INS_BREAK_LE(S, T)) /* 16-bit break; BE version field-swapped then byte-swapped for use in memory R/W fns */ #define XT_INS_BREAKN_LE(IMM4) (0xF02D | (((IMM4) & 0xF) << 8)) #define XT_INS_BREAKN_BE(IMM4) (0x0FD2 | (((IMM4) & 0xF) << 12)) #define XT_INS_BREAKN(X, IMM4) (XT_ISBE(X) ? XT_INS_BREAKN_BE(IMM4) : XT_INS_BREAKN_LE(IMM4)) #define XT_ISNS_SZ_MAX 3 /* PS register bits (LX) */ #define XT_PS_RING(_v_) ((uint32_t)((_v_) & 0x3) << 6) #define XT_PS_RING_MSK (0x3 << 6) #define XT_PS_RING_GET(_v_) (((_v_) >> 6) & 0x3) #define XT_PS_CALLINC_MSK (0x3 << 16) #define XT_PS_OWB_MSK (0xF << 8) #define XT_PS_WOE_MSK BIT(18) /* PS register bits (NX) */ #define XT_PS_DIEXC_MSK BIT(2) /* MS register bits (NX) */ #define XT_MS_DE_MSK BIT(5) #define XT_MS_DISPST_MSK (0x1f) #define XT_MS_DISPST_DBG (0x10) /* WB register bits (NX) */ #define XT_WB_P_SHIFT (0) #define XT_WB_P_MSK (0x7U << XT_WB_P_SHIFT) #define XT_WB_C_SHIFT (4) #define XT_WB_C_MSK (0x7U << XT_WB_C_SHIFT) #define XT_WB_N_SHIFT (8) #define XT_WB_N_MSK (0x7U << XT_WB_N_SHIFT) #define XT_WB_S_SHIFT (30) #define XT_WB_S_MSK (0x3U << XT_WB_S_SHIFT) /* IBREAKC register bits (NX) */ #define XT_IBREAKC_FB (0x80000000) /* Definitions for imprecise exception registers (NX) */ #define XT_IMPR_EXC_MSK (0x00000013) #define XT_MESRCLR_IMPR_EXC_MSK (0x00000090) #define XT_LOCAL_MEM_REGIONS_NUM_MAX 8 #define XT_AREGS_NUM_MAX 64 #define XT_USER_REGS_NUM_MAX 256 #define XT_MEM_ACCESS_NONE 0x0 #define XT_MEM_ACCESS_READ 0x1 #define XT_MEM_ACCESS_WRITE 0x2 #define XT_MAX_TIE_REG_WIDTH (512) /* TIE register file max 4096 bits */ #define XT_QUERYPKT_RESP_MAX (XT_MAX_TIE_REG_WIDTH * 2 + 1) enum xtensa_qerr_e { XT_QERR_INTERNAL = 0, XT_QERR_FAIL, XT_QERR_INVAL, XT_QERR_MEM, XT_QERR_NUM, }; /* An and ARn registers potentially used as scratch regs */ enum xtensa_ar_scratch_set_e { XT_AR_SCRATCH_A3 = 0, XT_AR_SCRATCH_AR3, XT_AR_SCRATCH_A4, XT_AR_SCRATCH_AR4, XT_AR_SCRATCH_NUM }; struct xtensa_keyval_info_s { char *chrval; int intval; }; enum xtensa_type { XT_UNDEF = 0, XT_LX, XT_NX, }; struct xtensa_cache_config { uint8_t way_count; uint32_t line_size; uint32_t size; int writeback; }; struct xtensa_local_mem_region_config { target_addr_t base; uint32_t size; int access; }; struct xtensa_local_mem_config { uint16_t count; struct xtensa_local_mem_region_config regions[XT_LOCAL_MEM_REGIONS_NUM_MAX]; }; struct xtensa_mmu_config { bool enabled; uint8_t itlb_entries_count; uint8_t dtlb_entries_count; }; struct xtensa_mpu_config { bool enabled; uint8_t nfgseg; uint32_t minsegsize; bool lockable; bool execonly; }; struct xtensa_irq_config { bool enabled; uint8_t irq_num; }; struct xtensa_high_prio_irq_config { bool enabled; uint8_t level_num; uint8_t excm_level; }; struct xtensa_debug_config { bool enabled; uint8_t irq_level; uint8_t ibreaks_num; uint8_t dbreaks_num; uint8_t perfcount_num; }; struct xtensa_tracing_config { bool enabled; uint32_t mem_sz; bool reversed_mem_access; }; struct xtensa_config { enum xtensa_type core_type; uint8_t aregs_num; bool windowed; bool coproc; bool exceptions; struct xtensa_irq_config irq; struct xtensa_high_prio_irq_config high_irq; struct xtensa_mmu_config mmu; struct xtensa_mpu_config mpu; struct xtensa_debug_config debug; struct xtensa_tracing_config trace; struct xtensa_cache_config icache; struct xtensa_cache_config dcache; struct xtensa_local_mem_config irom; struct xtensa_local_mem_config iram; struct xtensa_local_mem_config drom; struct xtensa_local_mem_config dram; struct xtensa_local_mem_config sram; struct xtensa_local_mem_config srom; }; typedef uint32_t xtensa_insn_t; enum xtensa_stepping_isr_mode { XT_STEPPING_ISR_OFF, /* interrupts are disabled during stepping */ XT_STEPPING_ISR_ON, /* interrupts are enabled during stepping */ }; enum xtensa_nx_reg_idx { XT_NX_REG_IDX_IBREAKC0 = 0, XT_NX_REG_IDX_WB, XT_NX_REG_IDX_MS, XT_NX_REG_IDX_IEVEC, /* IEVEC, IEEXTERN, and MESR must be contiguous */ XT_NX_REG_IDX_IEEXTERN, XT_NX_REG_IDX_MESR, XT_NX_REG_IDX_MESRCLR, XT_NX_REG_IDX_NUM }; /* Only supported in cores with in-CPU MMU. None of Espressif chips as of now. */ enum xtensa_mode { XT_MODE_RING0, XT_MODE_RING1, XT_MODE_RING2, XT_MODE_RING3, XT_MODE_ANY /* special value to run algorithm in current core mode */ }; struct xtensa_sw_breakpoint { struct breakpoint *oocd_bp; /* original insn */ uint8_t insn[XT_ISNS_SZ_MAX]; /* original insn size */ uint8_t insn_sz; /* 2 or 3 bytes */ }; #define XTENSA_COMMON_MAGIC 0x54E4E555U /** * Represents a generic Xtensa core. */ struct xtensa { unsigned int common_magic; struct xtensa_chip_common *xtensa_chip; struct xtensa_config *core_config; struct xtensa_debug_module dbg_mod; struct reg_cache *core_cache; unsigned int total_regs_num; unsigned int core_regs_num; bool regmap_contiguous; unsigned int genpkt_regs_num; struct xtensa_reg_desc **contiguous_regs_desc; struct reg **contiguous_regs_list; /* Per-config Xtensa registers as specified via "xtreg" in xtensa-core*.cfg */ struct xtensa_reg_desc *optregs; unsigned int num_optregs; struct reg *empty_regs; char qpkt_resp[XT_QUERYPKT_RESP_MAX]; /* An array of pointers to buffers to backup registers' values while algo is run on target. * Size is 'regs_num'. */ void **algo_context_backup; unsigned int eps_dbglevel_idx; unsigned int dbregs_num; struct target *target; bool reset_asserted; enum xtensa_stepping_isr_mode stepping_isr_mode; struct breakpoint **hw_brps; struct watchpoint **hw_wps; struct xtensa_sw_breakpoint *sw_brps; bool trace_active; bool permissive_mode; /* bypass memory checks */ bool suppress_dsr_errors; uint32_t smp_break; uint32_t spill_loc; unsigned int spill_bytes; uint8_t *spill_buf; int8_t probe_lsddr32p; /* Sometimes debug module's 'powered' bit is cleared after reset, but get set after some * time.This is the number of polling periods after which core is considered to be powered * off (marked as unexamined) if the bit retains to be cleared (e.g. if core is disabled by * SW running on target).*/ uint8_t come_online_probes_num; bool proc_syscall; bool halt_request; uint32_t nx_stop_cause; uint32_t nx_reg_idx[XT_NX_REG_IDX_NUM]; struct xtensa_keyval_info_s scratch_ars[XT_AR_SCRATCH_NUM]; bool regs_fetched; /* true after first register fetch completed successfully */ }; static inline struct xtensa *target_to_xtensa(struct target *target) { assert(target); struct xtensa *xtensa = target->arch_info; assert(xtensa->common_magic == XTENSA_COMMON_MAGIC); return xtensa; } int xtensa_init_arch_info(struct target *target, struct xtensa *xtensa, const struct xtensa_debug_module_config *dm_cfg); int xtensa_target_init(struct command_context *cmd_ctx, struct target *target); void xtensa_target_deinit(struct target *target); static inline bool xtensa_addr_in_mem(const struct xtensa_local_mem_config *mem, uint32_t addr) { for (unsigned int i = 0; i < mem->count; i++) { if (addr >= mem->regions[i].base && addr < mem->regions[i].base + mem->regions[i].size) return true; } return false; } static inline bool xtensa_data_addr_valid(struct target *target, uint32_t addr) { struct xtensa *xtensa = target_to_xtensa(target); if (xtensa_addr_in_mem(&xtensa->core_config->drom, addr)) return true; if (xtensa_addr_in_mem(&xtensa->core_config->dram, addr)) return true; if (xtensa_addr_in_mem(&xtensa->core_config->sram, addr)) return true; return false; } static inline int xtensa_queue_dbg_reg_read(struct xtensa *xtensa, enum xtensa_dm_reg reg, uint8_t *data) { struct xtensa_debug_module *dm = &xtensa->dbg_mod; if (!xtensa->core_config->trace.enabled && (reg <= XDMREG_MEMADDREND || (reg >= XDMREG_PMG && reg <= XDMREG_PMSTAT7))) { LOG_ERROR("Can not access %u reg when Trace Port option disabled!", reg); return ERROR_FAIL; } return dm->dbg_ops->queue_reg_read(dm, reg, data); } static inline int xtensa_queue_dbg_reg_write(struct xtensa *xtensa, enum xtensa_dm_reg reg, uint32_t data) { struct xtensa_debug_module *dm = &xtensa->dbg_mod; if (!xtensa->core_config->trace.enabled && (reg <= XDMREG_MEMADDREND || (reg >= XDMREG_PMG && reg <= XDMREG_PMSTAT7))) { LOG_ERROR("Can not access %u reg when Trace Port option disabled!", reg); return ERROR_FAIL; } return dm->dbg_ops->queue_reg_write(dm, reg, data); } static inline int xtensa_core_status_clear(struct target *target, uint32_t bits) { struct xtensa *xtensa = target_to_xtensa(target); return xtensa_dm_core_status_clear(&xtensa->dbg_mod, bits); } int xtensa_core_status_check(struct target *target); int xtensa_examine(struct target *target); int xtensa_wakeup(struct target *target); int xtensa_smpbreak_set(struct target *target, uint32_t set); int xtensa_smpbreak_get(struct target *target, uint32_t *val); int xtensa_smpbreak_write(struct xtensa *xtensa, uint32_t set); int xtensa_smpbreak_read(struct xtensa *xtensa, uint32_t *val); xtensa_reg_val_t xtensa_reg_get(struct target *target, enum xtensa_reg_id reg_id); void xtensa_reg_set(struct target *target, enum xtensa_reg_id reg_id, xtensa_reg_val_t value); void xtensa_reg_set_deep_relgen(struct target *target, enum xtensa_reg_id a_idx, xtensa_reg_val_t value); int xtensa_fetch_all_regs(struct target *target); int xtensa_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); uint32_t xtensa_cause_get(struct target *target); void xtensa_cause_clear(struct target *target); void xtensa_cause_reset(struct target *target); int xtensa_poll(struct target *target); void xtensa_on_poll(struct target *target); int xtensa_halt(struct target *target); int xtensa_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); int xtensa_prepare_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); int xtensa_do_resume(struct target *target); int xtensa_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); int xtensa_do_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); int xtensa_mmu_is_enabled(struct target *target, int *enabled); int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); int xtensa_read_buffer(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer); int xtensa_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int xtensa_write_buffer(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer); int xtensa_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); int xtensa_assert_reset(struct target *target); int xtensa_deassert_reset(struct target *target); int xtensa_soft_reset_halt(struct target *target); int xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint); int xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint); int xtensa_watchpoint_add(struct target *target, struct watchpoint *watchpoint); int xtensa_watchpoint_remove(struct target *target, struct watchpoint *watchpoint); void xtensa_set_permissive_mode(struct target *target, bool state); const char *xtensa_get_gdb_arch(struct target *target); int xtensa_gdb_query_custom(struct target *target, const char *packet, char **response_p); COMMAND_HELPER(xtensa_cmd_xtdef_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_xtopt_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_xtmem_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_xtmpu_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_xtmmu_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_xtreg_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_xtregfmt_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_permissive_mode_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_mask_interrupts_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_smpbreak_do, struct target *target); COMMAND_HELPER(xtensa_cmd_perfmon_dump_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_perfmon_enable_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_tracestart_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_tracestop_do, struct xtensa *xtensa); COMMAND_HELPER(xtensa_cmd_tracedump_do, struct xtensa *xtensa, const char *fname); extern const struct command_registration xtensa_command_handlers[]; #endif /* OPENOCD_TARGET_XTENSA_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/xtensa/xtensa_chip.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Xtensa Chip-level Target Support for OpenOCD * * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "assert.h" #include <target/target.h> #include <target/target_type.h> #include <target/arm_adi_v5.h> #include <rtos/rtos.h> #include "xtensa_chip.h" #include "xtensa_fileio.h" int xtensa_chip_init_arch_info(struct target *target, void *arch_info, struct xtensa_debug_module_config *dm_cfg) { struct xtensa_chip_common *xtensa_chip = (struct xtensa_chip_common *)arch_info; int ret = xtensa_init_arch_info(target, &xtensa_chip->xtensa, dm_cfg); if (ret != ERROR_OK) return ret; /* All xtensa target structures point back to original xtensa_chip */ xtensa_chip->xtensa.xtensa_chip = arch_info; return ERROR_OK; } int xtensa_chip_target_init(struct command_context *cmd_ctx, struct target *target) { int ret = xtensa_target_init(cmd_ctx, target); if (ret != ERROR_OK) return ret; return xtensa_fileio_init(target); } int xtensa_chip_arch_state(struct target *target) { return ERROR_OK; } static int xtensa_chip_poll(struct target *target) { enum target_state old_state = target->state; int ret = xtensa_poll(target); if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) { /*Call any event callbacks that are applicable */ if (old_state == TARGET_DEBUG_RUNNING) { target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } else { xtensa_fileio_detect_proc(target); target_call_event_callbacks(target, TARGET_EVENT_HALTED); } } return ret; } static int xtensa_chip_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical) { if (physical) { *physical = virtual; return ERROR_OK; } return ERROR_FAIL; } static const struct xtensa_debug_ops xtensa_chip_dm_dbg_ops = { .queue_enable = xtensa_dm_queue_enable, .queue_reg_read = xtensa_dm_queue_reg_read, .queue_reg_write = xtensa_dm_queue_reg_write }; static const struct xtensa_power_ops xtensa_chip_dm_pwr_ops = { .queue_reg_read = xtensa_dm_queue_pwr_reg_read, .queue_reg_write = xtensa_dm_queue_pwr_reg_write }; static int xtensa_chip_target_create(struct target *target, Jim_Interp *interp) { struct xtensa_debug_module_config xtensa_chip_dm_cfg = { .dbg_ops = &xtensa_chip_dm_dbg_ops, .pwr_ops = &xtensa_chip_dm_pwr_ops, .tap = NULL, .queue_tdi_idle = NULL, .queue_tdi_idle_arg = NULL, .dap = NULL, .debug_ap = NULL, .debug_apsel = DP_APSEL_INVALID, .ap_offset = 0, }; struct adiv5_private_config *pc = target->private_config; if (adiv5_verify_config(pc) == ERROR_OK) { xtensa_chip_dm_cfg.dap = pc->dap; xtensa_chip_dm_cfg.debug_apsel = pc->ap_num; xtensa_chip_dm_cfg.ap_offset = target->dbgbase; LOG_DEBUG("DAP: ap_num %" PRId64 " DAP %p\n", pc->ap_num, pc->dap); } else { xtensa_chip_dm_cfg.tap = target->tap; LOG_DEBUG("JTAG: %s:%s pos %d", target->tap->chip, target->tap->tapname, target->tap->abs_chain_position); } struct xtensa_chip_common *xtensa_chip = calloc(1, sizeof(struct xtensa_chip_common)); if (!xtensa_chip) { LOG_ERROR("Failed to alloc chip-level memory!"); return ERROR_FAIL; } int ret = xtensa_chip_init_arch_info(target, xtensa_chip, &xtensa_chip_dm_cfg); if (ret != ERROR_OK) { LOG_ERROR("Failed to init arch info!"); free(xtensa_chip); return ret; } /*Assume running target. If different, the first poll will fix this. */ target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; return ERROR_OK; } static void xtensa_chip_target_deinit(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); xtensa_target_deinit(target); free(xtensa->xtensa_chip); } static int xtensa_chip_examine(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); int retval = xtensa_dm_examine(&xtensa->dbg_mod); if (retval == ERROR_OK) retval = xtensa_examine(target); return retval; } static int xtensa_chip_jim_configure(struct target *target, struct jim_getopt_info *goi) { static bool dap_configured; int ret = adiv5_jim_configure(target, goi); if (ret == JIM_OK) { LOG_DEBUG("xtensa '-dap' target option found"); dap_configured = true; } if (!dap_configured) { LOG_DEBUG("xtensa '-dap' target option not yet found, assuming JTAG..."); target->has_dap = false; } return ret; } /** Methods for generic example of Xtensa-based chip-level targets. */ struct target_type xtensa_chip_target = { .name = "xtensa", .poll = xtensa_chip_poll, .arch_state = xtensa_chip_arch_state, .halt = xtensa_halt, .resume = xtensa_resume, .step = xtensa_step, .assert_reset = xtensa_assert_reset, .deassert_reset = xtensa_deassert_reset, .soft_reset_halt = xtensa_soft_reset_halt, .virt2phys = xtensa_chip_virt2phys, .mmu = xtensa_mmu_is_enabled, .read_memory = xtensa_read_memory, .write_memory = xtensa_write_memory, .read_buffer = xtensa_read_buffer, .write_buffer = xtensa_write_buffer, .checksum_memory = xtensa_checksum_memory, .get_gdb_reg_list = xtensa_get_gdb_reg_list, .add_breakpoint = xtensa_breakpoint_add, .remove_breakpoint = xtensa_breakpoint_remove, .add_watchpoint = xtensa_watchpoint_add, .remove_watchpoint = xtensa_watchpoint_remove, .target_create = xtensa_chip_target_create, .target_jim_configure = xtensa_chip_jim_configure, .init_target = xtensa_chip_target_init, .examine = xtensa_chip_examine, .deinit_target = xtensa_chip_target_deinit, .gdb_query_custom = xtensa_gdb_query_custom, .commands = xtensa_command_handlers, .get_gdb_fileio_info = xtensa_get_gdb_fileio_info, .gdb_fileio_end = xtensa_gdb_fileio_end, }; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/xtensa/xtensa_chip.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Xtensa Chip-level Target Support for OpenOCD * * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * ***************************************************************************/ #ifndef OPENOCD_TARGET_XTENSA_CHIP_H #define OPENOCD_TARGET_XTENSA_CHIP_H #include <target/target.h> #include "xtensa.h" #include "xtensa_debug_module.h" struct xtensa_chip_common { struct xtensa xtensa; /* Chip-specific extensions can be added here */ }; static inline struct xtensa_chip_common *target_to_xtensa_chip(struct target *target) { return container_of(target->arch_info, struct xtensa_chip_common, xtensa); } int xtensa_chip_init_arch_info(struct target *target, void *arch_info, struct xtensa_debug_module_config *dm_cfg); int xtensa_chip_target_init(struct command_context *cmd_ctx, struct target *target); int xtensa_chip_arch_state(struct target *target); void xtensa_chip_queue_tdi_idle(struct target *target); void xtensa_chip_on_reset(struct target *target); bool xtensa_chip_on_halt(struct target *target); void xtensa_chip_on_poll(struct target *target); #endif /* OPENOCD_TARGET_XTENSA_CHIP_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/xtensa/xtensa_debug_module.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Xtensa Debug Module (XDM) Support for OpenOCD * * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * * Copyright (C) 2019 Espressif Systems Ltd. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <helper/align.h> #include "xtensa_debug_module.h" #define TAPINS_PWRCTL 0x08 #define TAPINS_PWRSTAT 0x09 #define TAPINS_NARSEL 0x1C #define TAPINS_IDCODE 0x1E #define TAPINS_BYPASS 0x1F #define TAPINS_PWRCTL_LEN 8 #define TAPINS_PWRSTAT_LEN 8 #define TAPINS_NARSEL_ADRLEN 8 #define TAPINS_NARSEL_DATALEN 32 #define TAPINS_IDCODE_LEN 32 #define TAPINS_BYPASS_LEN 1 /* Table of power register offsets for APB space */ static const struct xtensa_dm_pwr_reg_offsets xdm_pwr_regs[XDMREG_PWRNUM] = XTENSA_DM_PWR_REG_OFFSETS; /* Table of debug register offsets for Nexus and APB space */ static const struct xtensa_dm_reg_offsets xdm_regs[XDMREG_NUM] = XTENSA_DM_REG_OFFSETS; static void xtensa_dm_add_set_ir(struct xtensa_debug_module *dm, uint8_t value) { struct scan_field field; uint8_t t[4] = { 0, 0, 0, 0 }; memset(&field, 0, sizeof(field)); field.num_bits = dm->tap->ir_length; field.out_value = t; buf_set_u32(t, 0, field.num_bits, value); jtag_add_ir_scan(dm->tap, &field, TAP_IDLE); } static void xtensa_dm_add_dr_scan(struct xtensa_debug_module *dm, int len, const uint8_t *src, uint8_t *dest, tap_state_t endstate) { struct scan_field field; memset(&field, 0, sizeof(field)); field.num_bits = len; field.out_value = src; field.in_value = dest; jtag_add_dr_scan(dm->tap, 1, &field, endstate); } int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg) { if (!dm || !cfg) return ERROR_FAIL; if (!IS_ALIGNED(cfg->ap_offset, XTENSA_DM_APB_ALIGN)) { LOG_ERROR("Xtensa DM APB offset must be aligned to a %dKB multiple", XTENSA_DM_APB_ALIGN / 1024); return ERROR_FAIL; } dm->pwr_ops = cfg->pwr_ops; dm->dbg_ops = cfg->dbg_ops; dm->tap = cfg->tap; dm->queue_tdi_idle = cfg->queue_tdi_idle; dm->queue_tdi_idle_arg = cfg->queue_tdi_idle_arg; dm->dap = cfg->dap; dm->debug_ap = cfg->debug_ap; dm->debug_apsel = cfg->debug_apsel; dm->ap_offset = cfg->ap_offset; return ERROR_OK; } void xtensa_dm_deinit(struct xtensa_debug_module *dm) { if (dm->debug_ap) { dap_put_ap(dm->debug_ap); dm->debug_ap = NULL; } } int xtensa_dm_poll(struct xtensa_debug_module *dm) { /* Check if debug_ap is available to prevent segmentation fault. * If the re-examination after an error does not find a MEM-AP * (e.g. the target stopped communicating), debug_ap pointer * can suddenly become NULL. */ return (!dm || (dm->dap && !dm->debug_ap)) ? ERROR_FAIL : ERROR_OK; } int xtensa_dm_examine(struct xtensa_debug_module *dm) { struct adiv5_dap *swjdp = dm->dap; int retval = ERROR_OK; if (swjdp) { LOG_DEBUG("DM examine: DAP AP select %d", dm->debug_apsel); if (dm->debug_ap) { dap_put_ap(dm->debug_ap); dm->debug_ap = NULL; } if (dm->debug_apsel == DP_APSEL_INVALID) { LOG_DEBUG("DM examine: search for APB-type MEM-AP..."); /* TODO: Determine whether AP_TYPE_AXI_AP APs can be supported... */ retval = dap_find_get_ap(swjdp, AP_TYPE_APB_AP, &dm->debug_ap); if (retval != ERROR_OK) { LOG_ERROR("Could not find MEM-AP to control the core"); return retval; } } else { dm->debug_ap = dap_get_ap(swjdp, dm->debug_apsel); } /* TODO: Allow a user-specified AP instead of relying on AP_TYPE_APB_AP */ dm->debug_apsel = dm->debug_ap->ap_num; LOG_DEBUG("DM examine: Setting apsel to %d", dm->debug_apsel); /* Leave (only) generic DAP stuff for debugport_init(); */ dm->debug_ap->memaccess_tck = 8; retval = mem_ap_init(dm->debug_ap); if (retval != ERROR_OK) { LOG_ERROR("MEM-AP init failed: %d", retval); return retval; } /* TODO: how to set autoincrement range? Hard-code it to 1024 bytes for now */ dm->debug_ap->tar_autoincr_block = (1 << 10); } return retval; } int xtensa_dm_queue_enable(struct xtensa_debug_module *dm) { return dm->dbg_ops->queue_reg_write(dm, XDMREG_DCRSET, OCDDCR_ENABLEOCD); } int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint8_t *value) { if (reg >= XDMREG_NUM) { LOG_ERROR("Invalid DBG reg ID %d!", reg); return ERROR_FAIL; } if (dm->dap) /* NOTE: Future optimization: mem_ap_read_u32() offers higher performance with * queued reads, but requires an API change to pass value as a 32-bit pointer. */ return mem_ap_read_buf(dm->debug_ap, value, 4, 1, xdm_regs[reg].apb + dm->ap_offset); uint8_t regdata = (xdm_regs[reg].nar << 1) | 0; uint8_t dummy[4] = { 0, 0, 0, 0 }; xtensa_dm_add_set_ir(dm, TAPINS_NARSEL); xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_ADRLEN, ®data, NULL, TAP_IDLE); xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, dummy, value, TAP_IDLE); return ERROR_OK; } int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint32_t value) { if (reg >= XDMREG_NUM) { LOG_ERROR("Invalid DBG reg ID %d!", reg); return ERROR_FAIL; } if (dm->dap) return mem_ap_write_u32(dm->debug_ap, xdm_regs[reg].apb + dm->ap_offset, value); uint8_t regdata = (xdm_regs[reg].nar << 1) | 1; uint8_t valdata[] = { value, value >> 8, value >> 16, value >> 24 }; xtensa_dm_add_set_ir(dm, TAPINS_NARSEL); xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_ADRLEN, ®data, NULL, TAP_IDLE); xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, valdata, NULL, TAP_IDLE); return ERROR_OK; } int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm, enum xtensa_dm_pwr_reg reg, uint8_t *data, uint32_t clear) { if (reg >= XDMREG_PWRNUM) { LOG_ERROR("Invalid PWR reg ID %d!", reg); return ERROR_FAIL; } if (dm->dap) { /* NOTE: Future optimization: mem_ap_read_u32() offers higher performance with * queued reads, but requires an API change to pass value as a 32-bit pointer. */ uint32_t apbreg = xdm_pwr_regs[reg].apb + dm->ap_offset; int retval = mem_ap_read_buf(dm->debug_ap, data, 4, 1, apbreg); if (retval == ERROR_OK) retval = mem_ap_write_u32(dm->debug_ap, apbreg, clear); return retval; } uint8_t value_clr = (uint8_t)clear; uint8_t tap_insn = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL : TAPINS_PWRSTAT; int tap_insn_sz = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL_LEN : TAPINS_PWRSTAT_LEN; xtensa_dm_add_set_ir(dm, tap_insn); xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value_clr, data, TAP_IDLE); return ERROR_OK; } int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm, enum xtensa_dm_pwr_reg reg, uint32_t data) { if (reg >= XDMREG_PWRNUM) { LOG_ERROR("Invalid PWR reg ID %d!", reg); return ERROR_FAIL; } if (dm->dap) { uint32_t apbreg = xdm_pwr_regs[reg].apb + dm->ap_offset; return mem_ap_write_u32(dm->debug_ap, apbreg, data); } uint8_t tap_insn = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL : TAPINS_PWRSTAT; int tap_insn_sz = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL_LEN : TAPINS_PWRSTAT_LEN; uint8_t value = (uint8_t)data; xtensa_dm_add_set_ir(dm, tap_insn); xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value, NULL, TAP_IDLE); return ERROR_OK; } int xtensa_dm_device_id_read(struct xtensa_debug_module *dm) { uint8_t id_buf[sizeof(uint32_t)]; dm->dbg_ops->queue_reg_read(dm, XDMREG_OCDID, id_buf); xtensa_dm_queue_tdi_idle(dm); int res = xtensa_dm_queue_execute(dm); if (res != ERROR_OK) return res; dm->device_id = buf_get_u32(id_buf, 0, 32); return ERROR_OK; } int xtensa_dm_power_status_read(struct xtensa_debug_module *dm, uint32_t clear) { uint8_t stat_buf[sizeof(uint32_t)] = { 0, 0, 0, 0 }; uint8_t stath_buf[sizeof(uint32_t)] = { 0, 0, 0, 0 }; /* TODO: JTAG does not work when PWRCTL_JTAGDEBUGUSE is not set. * It is set in xtensa_examine(), need to move reading of XDMREG_OCDID out of this function */ /* dm->dbg_ops->queue_reg_read(dm, XDMREG_OCDID, id_buf); *Read reset state */ dm->pwr_ops->queue_reg_read(dm, XDMREG_PWRSTAT, stat_buf, clear); dm->pwr_ops->queue_reg_read(dm, XDMREG_PWRSTAT, stath_buf, clear); xtensa_dm_queue_tdi_idle(dm); int res = xtensa_dm_queue_execute(dm); if (res != ERROR_OK) return res; dm->power_status.stat = buf_get_u32(stat_buf, 0, 32); dm->power_status.stath = buf_get_u32(stath_buf, 0, 32); return res; } int xtensa_dm_core_status_read(struct xtensa_debug_module *dm) { uint8_t dsr_buf[sizeof(uint32_t)]; xtensa_dm_queue_enable(dm); dm->dbg_ops->queue_reg_read(dm, XDMREG_DSR, dsr_buf); xtensa_dm_queue_tdi_idle(dm); int res = xtensa_dm_queue_execute(dm); if (res != ERROR_OK) return res; dm->core_status.dsr = buf_get_u32(dsr_buf, 0, 32); return res; } int xtensa_dm_core_status_clear(struct xtensa_debug_module *dm, xtensa_dsr_t bits) { dm->dbg_ops->queue_reg_write(dm, XDMREG_DSR, bits); xtensa_dm_queue_tdi_idle(dm); return xtensa_dm_queue_execute(dm); } int xtensa_dm_trace_start(struct xtensa_debug_module *dm, struct xtensa_trace_start_config *cfg) { /*Turn off trace unit so we can start a new trace. */ dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXCTRL, 0); xtensa_dm_queue_tdi_idle(dm); int res = xtensa_dm_queue_execute(dm); if (res != ERROR_OK) return res; /*Set up parameters */ dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXADDR, 0); if (cfg->stopmask != XTENSA_STOPMASK_DISABLED) { dm->dbg_ops->queue_reg_write(dm, XDMREG_PCMATCHCTRL, (cfg->stopmask << PCMATCHCTRL_PCML_SHIFT)); dm->dbg_ops->queue_reg_write(dm, XDMREG_TRIGGERPC, cfg->stoppc); } dm->dbg_ops->queue_reg_write(dm, XDMREG_DELAYCNT, cfg->after); /*Options are mostly hardcoded for now. ToDo: make this more configurable. */ dm->dbg_ops->queue_reg_write( dm, XDMREG_TRAXCTRL, TRAXCTRL_TREN | ((cfg->stopmask != XTENSA_STOPMASK_DISABLED) ? TRAXCTRL_PCMEN : 0) | TRAXCTRL_TMEN | (cfg->after_is_words ? 0 : TRAXCTRL_CNTU) | (0 << TRAXCTRL_SMPER_SHIFT) | TRAXCTRL_PTOWS); xtensa_dm_queue_tdi_idle(dm); return xtensa_dm_queue_execute(dm); } int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable) { uint8_t traxctl_buf[sizeof(uint32_t)]; uint32_t traxctl; struct xtensa_trace_status trace_status; dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXCTRL, traxctl_buf); xtensa_dm_queue_tdi_idle(dm); int res = xtensa_dm_queue_execute(dm); if (res != ERROR_OK) return res; traxctl = buf_get_u32(traxctl_buf, 0, 32); if (!pto_enable) traxctl &= ~(TRAXCTRL_PTOWS | TRAXCTRL_PTOWT); dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXCTRL, traxctl | TRAXCTRL_TRSTP); xtensa_dm_queue_tdi_idle(dm); res = xtensa_dm_queue_execute(dm); if (res != ERROR_OK) return res; /*Check current status of trace hardware */ res = xtensa_dm_trace_status_read(dm, &trace_status); if (res != ERROR_OK) return res; if (trace_status.stat & TRAXSTAT_TRACT) { LOG_ERROR("Failed to stop tracing (0x%x)!", trace_status.stat); return ERROR_FAIL; } return ERROR_OK; } int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_trace_status *status) { uint8_t traxstat_buf[sizeof(uint32_t)]; dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXSTAT, traxstat_buf); xtensa_dm_queue_tdi_idle(dm); int res = xtensa_dm_queue_execute(dm); if (res == ERROR_OK && status) status->stat = buf_get_u32(traxstat_buf, 0, 32); return res; } int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_trace_config *config) { uint8_t traxctl_buf[sizeof(uint32_t)]; uint8_t memadrstart_buf[sizeof(uint32_t)]; uint8_t memadrend_buf[sizeof(uint32_t)]; uint8_t adr_buf[sizeof(uint32_t)]; if (!config) return ERROR_FAIL; dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXCTRL, traxctl_buf); dm->dbg_ops->queue_reg_read(dm, XDMREG_MEMADDRSTART, memadrstart_buf); dm->dbg_ops->queue_reg_read(dm, XDMREG_MEMADDREND, memadrend_buf); dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXADDR, adr_buf); xtensa_dm_queue_tdi_idle(dm); int res = xtensa_dm_queue_execute(dm); if (res == ERROR_OK) { config->ctrl = buf_get_u32(traxctl_buf, 0, 32); config->memaddr_start = buf_get_u32(memadrstart_buf, 0, 32); config->memaddr_end = buf_get_u32(memadrend_buf, 0, 32); config->addr = buf_get_u32(adr_buf, 0, 32); } return res; } int xtensa_dm_trace_data_read(struct xtensa_debug_module *dm, uint8_t *dest, uint32_t size) { if (!dest) return ERROR_FAIL; for (unsigned int i = 0; i < size / 4; i++) dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXDATA, &dest[i * 4]); xtensa_dm_queue_tdi_idle(dm); return xtensa_dm_queue_execute(dm); } int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id, const struct xtensa_perfmon_config *config) { if (!config) return ERROR_FAIL; uint8_t pmstat_buf[4]; uint32_t pmctrl = ((config->tracelevel) << 4) + (config->select << 8) + (config->mask << 16) + (config->kernelcnt << 3); /* enable performance monitor */ dm->dbg_ops->queue_reg_write(dm, XDMREG_PMG, 0x1); /* reset counter */ dm->dbg_ops->queue_reg_write(dm, XDMREG_PM0 + counter_id, 0); dm->dbg_ops->queue_reg_write(dm, XDMREG_PMCTRL0 + counter_id, pmctrl); dm->dbg_ops->queue_reg_read(dm, XDMREG_PMSTAT0 + counter_id, pmstat_buf); xtensa_dm_queue_tdi_idle(dm); return xtensa_dm_queue_execute(dm); } int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id, struct xtensa_perfmon_result *out_result) { uint8_t pmstat_buf[4]; uint8_t pmcount_buf[4]; dm->dbg_ops->queue_reg_read(dm, XDMREG_PMSTAT0 + counter_id, pmstat_buf); dm->dbg_ops->queue_reg_read(dm, XDMREG_PM0 + counter_id, pmcount_buf); xtensa_dm_queue_tdi_idle(dm); int res = xtensa_dm_queue_execute(dm); if (res == ERROR_OK) { uint32_t stat = buf_get_u32(pmstat_buf, 0, 32); uint64_t result = buf_get_u32(pmcount_buf, 0, 32); /* TODO: if counter # counter_id+1 has 'select' set to 1, use its value as the * high 32 bits of the counter. */ if (out_result) { out_result->overflow = ((stat & 1) != 0); out_result->value = result; } } return res; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/xtensa/xtensa_debug_module.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Xtensa Debug Module (XDM) Support for OpenOCD * * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * * Copyright (C) 2019 Espressif Systems Ltd. * * Derived from original ESP8266 target. * * Author: Angus Gratton gus@projectgus.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_XTENSA_DEBUG_MODULE_H #define OPENOCD_TARGET_XTENSA_DEBUG_MODULE_H #include <jtag/jtag.h> #include <target/arm_adi_v5.h> #include <helper/bits.h> #include <target/target.h> /* Virtual IDs for using with xtensa_power_ops API */ enum xtensa_dm_pwr_reg { XDMREG_PWRCTL = 0x00, XDMREG_PWRSTAT, XDMREG_PWRNUM }; /* Debug Module Power Register offsets within APB */ struct xtensa_dm_pwr_reg_offsets { uint16_t apb; }; /* Debug Module Power Register offset structure; must include XDMREG_PWRNUM entries */ #define XTENSA_DM_PWR_REG_OFFSETS { \ /* Power/Reset Registers */ \ { .apb = 0x3020 }, /* XDMREG_PWRCTL */ \ { .apb = 0x3024 }, /* XDMREG_PWRSTAT */ \ } /* From the manual: To properly use Debug registers through JTAG, software must ensure that: - Tap is out of reset - Xtensa Debug Module is out of reset - Other bits of PWRCTL are set to their desired values, and finally - JtagDebugUse transitions from 0 to 1 The bit must continue to be 1 in order for JTAG accesses to the Debug Module to happen correctly. When it is set, any write to this bit clears it. Either don't access it, or re-write it to 1 so JTAG accesses continue. */ #define PWRCTL_JTAGDEBUGUSE(x) (((x)->dbg_mod.dap) ? (0) : BIT(7)) #define PWRCTL_DEBUGRESET(x) (((x)->dbg_mod.dap) ? BIT(28) : BIT(6)) #define PWRCTL_CORERESET(x) (((x)->dbg_mod.dap) ? BIT(16) : BIT(4)) #define PWRCTL_DEBUGWAKEUP(x) (((x)->dbg_mod.dap) ? BIT(12) : BIT(2)) #define PWRCTL_MEMWAKEUP(x) (((x)->dbg_mod.dap) ? BIT(8) : BIT(1)) #define PWRCTL_COREWAKEUP(x) (((x)->dbg_mod.dap) ? BIT(0) : BIT(0)) #define PWRSTAT_DEBUGWASRESET_DM(d) (((d)->dap) ? BIT(28) : BIT(6)) #define PWRSTAT_COREWASRESET_DM(d) (((d)->dap) ? BIT(16) : BIT(4)) #define PWRSTAT_DEBUGWASRESET(x) (PWRSTAT_DEBUGWASRESET_DM(&((x)->dbg_mod))) #define PWRSTAT_COREWASRESET(x) (PWRSTAT_COREWASRESET_DM(&((x)->dbg_mod))) #define PWRSTAT_CORESTILLNEEDED(x) (((x)->dbg_mod.dap) ? BIT(4) : BIT(3)) #define PWRSTAT_DEBUGDOMAINON(x) (((x)->dbg_mod.dap) ? BIT(12) : BIT(2)) #define PWRSTAT_MEMDOMAINON(x) (((x)->dbg_mod.dap) ? BIT(8) : BIT(1)) #define PWRSTAT_COREDOMAINON(x) (((x)->dbg_mod.dap) ? BIT(0) : BIT(0)) /* Virtual IDs for using with xtensa_debug_ops API */ enum xtensa_dm_reg { /* TRAX Registers */ XDMREG_TRAXID = 0x00, XDMREG_TRAXCTRL, XDMREG_TRAXSTAT, XDMREG_TRAXDATA, XDMREG_TRAXADDR, XDMREG_TRIGGERPC, XDMREG_PCMATCHCTRL, XDMREG_DELAYCNT, XDMREG_MEMADDRSTART, XDMREG_MEMADDREND, /* Performance Monitor Registers */ XDMREG_PMG, XDMREG_INTPC, XDMREG_PM0, XDMREG_PM1, XDMREG_PM2, XDMREG_PM3, XDMREG_PM4, XDMREG_PM5, XDMREG_PM6, XDMREG_PM7, XDMREG_PMCTRL0, XDMREG_PMCTRL1, XDMREG_PMCTRL2, XDMREG_PMCTRL3, XDMREG_PMCTRL4, XDMREG_PMCTRL5, XDMREG_PMCTRL6, XDMREG_PMCTRL7, XDMREG_PMSTAT0, XDMREG_PMSTAT1, XDMREG_PMSTAT2, XDMREG_PMSTAT3, XDMREG_PMSTAT4, XDMREG_PMSTAT5, XDMREG_PMSTAT6, XDMREG_PMSTAT7, /* OCD Registers */ XDMREG_OCDID, XDMREG_DCRCLR, XDMREG_DCRSET, XDMREG_DSR, XDMREG_DDR, XDMREG_DDREXEC, XDMREG_DIR0EXEC, XDMREG_DIR0, XDMREG_DIR1, XDMREG_DIR2, XDMREG_DIR3, XDMREG_DIR4, XDMREG_DIR5, XDMREG_DIR6, XDMREG_DIR7, /* Misc Registers */ XDMREG_ERISTAT, /* CoreSight Registers */ XDMREG_ITCTRL, XDMREG_CLAIMSET, XDMREG_CLAIMCLR, XDMREG_LOCKACCESS, XDMREG_LOCKSTATUS, XDMREG_AUTHSTATUS, XDMREG_DEVID, XDMREG_DEVTYPE, XDMREG_PERID4, XDMREG_PERID5, XDMREG_PERID6, XDMREG_PERID7, XDMREG_PERID0, XDMREG_PERID1, XDMREG_PERID2, XDMREG_PERID3, XDMREG_COMPID0, XDMREG_COMPID1, XDMREG_COMPID2, XDMREG_COMPID3, XDMREG_NUM }; /* Debug Module Register offsets within Nexus (NAR) or APB */ struct xtensa_dm_reg_offsets { uint8_t nar; uint16_t apb; }; /* Debug Module Register offset structure; must include XDMREG_NUM entries */ #define XTENSA_DM_REG_OFFSETS { \ /* TRAX Registers */ \ { .nar = 0x00, .apb = 0x0000 }, /* XDMREG_TRAXID */ \ { .nar = 0x01, .apb = 0x0004 }, /* XDMREG_TRAXCTRL */ \ { .nar = 0x02, .apb = 0x0008 }, /* XDMREG_TRAXSTAT */ \ { .nar = 0x03, .apb = 0x000c }, /* XDMREG_TRAXDATA */ \ { .nar = 0x04, .apb = 0x0010 }, /* XDMREG_TRAXADDR */ \ { .nar = 0x05, .apb = 0x0014 }, /* XDMREG_TRIGGERPC */ \ { .nar = 0x06, .apb = 0x0018 }, /* XDMREG_PCMATCHCTRL */ \ { .nar = 0x07, .apb = 0x001c }, /* XDMREG_DELAYCNT */ \ { .nar = 0x08, .apb = 0x0020 }, /* XDMREG_MEMADDRSTART */ \ { .nar = 0x09, .apb = 0x0024 }, /* XDMREG_MEMADDREND */ \ \ /* Performance Monitor Registers */ \ { .nar = 0x20, .apb = 0x1000 }, /* XDMREG_PMG */ \ { .nar = 0x24, .apb = 0x1010 }, /* XDMREG_INTPC */ \ { .nar = 0x28, .apb = 0x1080 }, /* XDMREG_PM0 */ \ { .nar = 0x29, .apb = 0x1084 }, /* XDMREG_PM1 */ \ { .nar = 0x2a, .apb = 0x1088 }, /* XDMREG_PM2 */ \ { .nar = 0x2b, .apb = 0x108c }, /* XDMREG_PM3 */ \ { .nar = 0x2c, .apb = 0x1090 }, /* XDMREG_PM4 */ \ { .nar = 0x2d, .apb = 0x1094 }, /* XDMREG_PM5 */ \ { .nar = 0x2e, .apb = 0x1098 }, /* XDMREG_PM6 */ \ { .nar = 0x2f, .apb = 0x109c }, /* XDMREG_PM7 */ \ { .nar = 0x30, .apb = 0x1100 }, /* XDMREG_PMCTRL0 */ \ { .nar = 0x31, .apb = 0x1104 }, /* XDMREG_PMCTRL1 */ \ { .nar = 0x32, .apb = 0x1108 }, /* XDMREG_PMCTRL2 */ \ { .nar = 0x33, .apb = 0x110c }, /* XDMREG_PMCTRL3 */ \ { .nar = 0x34, .apb = 0x1110 }, /* XDMREG_PMCTRL4 */ \ { .nar = 0x35, .apb = 0x1114 }, /* XDMREG_PMCTRL5 */ \ { .nar = 0x36, .apb = 0x1118 }, /* XDMREG_PMCTRL6 */ \ { .nar = 0x37, .apb = 0x111c }, /* XDMREG_PMCTRL7 */ \ { .nar = 0x38, .apb = 0x1180 }, /* XDMREG_PMSTAT0 */ \ { .nar = 0x39, .apb = 0x1184 }, /* XDMREG_PMSTAT1 */ \ { .nar = 0x3a, .apb = 0x1188 }, /* XDMREG_PMSTAT2 */ \ { .nar = 0x3b, .apb = 0x118c }, /* XDMREG_PMSTAT3 */ \ { .nar = 0x3c, .apb = 0x1190 }, /* XDMREG_PMSTAT4 */ \ { .nar = 0x3d, .apb = 0x1194 }, /* XDMREG_PMSTAT5 */ \ { .nar = 0x3e, .apb = 0x1198 }, /* XDMREG_PMSTAT6 */ \ { .nar = 0x3f, .apb = 0x119c }, /* XDMREG_PMSTAT7 */ \ \ /* OCD Registers */ \ { .nar = 0x40, .apb = 0x2000 }, /* XDMREG_OCDID */ \ { .nar = 0x42, .apb = 0x2008 }, /* XDMREG_DCRCLR */ \ { .nar = 0x43, .apb = 0x200c }, /* XDMREG_DCRSET */ \ { .nar = 0x44, .apb = 0x2010 }, /* XDMREG_DSR */ \ { .nar = 0x45, .apb = 0x2014 }, /* XDMREG_DDR */ \ { .nar = 0x46, .apb = 0x2018 }, /* XDMREG_DDREXEC */ \ { .nar = 0x47, .apb = 0x201c }, /* XDMREG_DIR0EXEC */ \ { .nar = 0x48, .apb = 0x2020 }, /* XDMREG_DIR0 */ \ { .nar = 0x49, .apb = 0x2024 }, /* XDMREG_DIR1 */ \ { .nar = 0x4a, .apb = 0x2028 }, /* XDMREG_DIR2 */ \ { .nar = 0x4b, .apb = 0x202c }, /* XDMREG_DIR3 */ \ { .nar = 0x4c, .apb = 0x2030 }, /* XDMREG_DIR4 */ \ { .nar = 0x4d, .apb = 0x2034 }, /* XDMREG_DIR5 */ \ { .nar = 0x4e, .apb = 0x2038 }, /* XDMREG_DIR6 */ \ { .nar = 0x4f, .apb = 0x203c }, /* XDMREG_DIR7 */ \ \ /* Misc Registers */ \ { .nar = 0x5a, .apb = 0x3028 }, /* XDMREG_ERISTAT */ \ \ /* CoreSight Registers */ \ { .nar = 0x60, .apb = 0x3f00 }, /* XDMREG_ITCTRL */ \ { .nar = 0x68, .apb = 0x3fa0 }, /* XDMREG_CLAIMSET */ \ { .nar = 0x69, .apb = 0x3fa4 }, /* XDMREG_CLAIMCLR */ \ { .nar = 0x6c, .apb = 0x3fb0 }, /* XDMREG_LOCKACCESS */ \ { .nar = 0x6d, .apb = 0x3fb4 }, /* XDMREG_LOCKSTATUS */ \ { .nar = 0x6e, .apb = 0x3fb8 }, /* XDMREG_AUTHSTATUS */ \ { .nar = 0x72, .apb = 0x3fc8 }, /* XDMREG_DEVID */ \ { .nar = 0x73, .apb = 0x3fcc }, /* XDMREG_DEVTYPE */ \ { .nar = 0x74, .apb = 0x3fd0 }, /* XDMREG_PERID4 */ \ { .nar = 0x75, .apb = 0x3fd4 }, /* XDMREG_PERID5 */ \ { .nar = 0x76, .apb = 0x3fd8 }, /* XDMREG_PERID6 */ \ { .nar = 0x77, .apb = 0x3fdc }, /* XDMREG_PERID7 */ \ { .nar = 0x78, .apb = 0x3fe0 }, /* XDMREG_PERID0 */ \ { .nar = 0x79, .apb = 0x3fe4 }, /* XDMREG_PERID1 */ \ { .nar = 0x7a, .apb = 0x3fe8 }, /* XDMREG_PERID2 */ \ { .nar = 0x7b, .apb = 0x3fec }, /* XDMREG_PERID3 */ \ { .nar = 0x7c, .apb = 0x3ff0 }, /* XDMREG_COMPID0 */ \ { .nar = 0x7d, .apb = 0x3ff4 }, /* XDMREG_COMPID1 */ \ { .nar = 0x7e, .apb = 0x3ff8 }, /* XDMREG_COMPID2 */ \ { .nar = 0x7f, .apb = 0x3ffc }, /* XDMREG_COMPID3 */ \ } #define XTENSA_DM_APB_ALIGN 0x4000 /* OCD registers, bit definitions */ #define OCDDCR_ENABLEOCD BIT(0) #define OCDDCR_DEBUGINTERRUPT BIT(1) #define OCDDCR_INTERRUPTALLCONDS BIT(2) #define OCDDCR_STEPREQUEST BIT(3) /* NX only */ #define OCDDCR_BREAKINEN BIT(16) #define OCDDCR_BREAKOUTEN BIT(17) #define OCDDCR_DEBUGSWACTIVE BIT(20) #define OCDDCR_RUNSTALLINEN BIT(21) #define OCDDCR_DEBUGMODEOUTEN BIT(22) #define OCDDCR_BREAKOUTITO BIT(24) #define OCDDCR_BREAKACKITO BIT(25) #define OCDDSR_EXECDONE BIT(0) #define OCDDSR_EXECEXCEPTION BIT(1) #define OCDDSR_EXECBUSY BIT(2) #define OCDDSR_EXECOVERRUN BIT(3) #define OCDDSR_STOPPED BIT(4) #define OCDDSR_STOPCAUSE (0xF << 5) /* NX only */ #define OCDDSR_STOPCAUSE_SHIFT (5) /* NX only */ #define OCDDSR_COREWROTEDDR BIT(10) #define OCDDSR_COREREADDDR BIT(11) #define OCDDSR_HOSTWROTEDDR BIT(14) #define OCDDSR_HOSTREADDDR BIT(15) #define OCDDSR_DEBUGPENDBREAK BIT(16) #define OCDDSR_DEBUGPENDHOST BIT(17) #define OCDDSR_DEBUGPENDTRAX BIT(18) #define OCDDSR_DEBUGINTBREAK BIT(20) #define OCDDSR_DEBUGINTHOST BIT(21) #define OCDDSR_DEBUGINTTRAX BIT(22) #define OCDDSR_RUNSTALLTOGGLE BIT(23) #define OCDDSR_RUNSTALLSAMPLE BIT(24) #define OCDDSR_BREACKOUTACKITI BIT(25) #define OCDDSR_BREAKINITI BIT(26) #define OCDDSR_DBGMODPOWERON BIT(31) /* NX stop cause */ #define OCDDSR_STOPCAUSE_DI (0) /* Debug Interrupt */ #define OCDDSR_STOPCAUSE_SS (1) /* Single-step completed */ #define OCDDSR_STOPCAUSE_IB (2) /* HW breakpoint (IBREAKn match) */ #define OCDDSR_STOPCAUSE_B1 (4) /* SW breakpoint (BREAK.1 instruction) */ #define OCDDSR_STOPCAUSE_BN (5) /* SW breakpoint (BREAK.N instruction) */ #define OCDDSR_STOPCAUSE_B (6) /* SW breakpoint (BREAK instruction) */ #define OCDDSR_STOPCAUSE_DB0 (8) /* HW watchpoint (DBREAK0 match) */ #define OCDDSR_STOPCAUSE_DB1 (9) /* HW watchpoint (DBREAK0 match) */ /* LX stop cause */ #define DEBUGCAUSE_IC BIT(0) /* ICOUNT exception */ #define DEBUGCAUSE_IB BIT(1) /* IBREAK exception */ #define DEBUGCAUSE_DB BIT(2) /* DBREAK exception */ #define DEBUGCAUSE_BI BIT(3) /* BREAK instruction encountered */ #define DEBUGCAUSE_BN BIT(4) /* BREAK.N instruction encountered */ #define DEBUGCAUSE_DI BIT(5) /* Debug Interrupt */ #define DEBUGCAUSE_VALID BIT(31) /* Pseudo-value to trigger reread (NX only) */ #define TRAXCTRL_TREN BIT(0) /* Trace enable. Tracing starts on 0->1 */ #define TRAXCTRL_TRSTP BIT(1) /* Trace Stop. Make 1 to stop trace. */ #define TRAXCTRL_PCMEN BIT(2) /* PC match enable */ #define TRAXCTRL_PTIEN BIT(4) /* Processor-trigger enable */ #define TRAXCTRL_CTIEN BIT(5) /* Cross-trigger enable */ #define TRAXCTRL_TMEN BIT(7) /* Tracemem Enable. Always set. */ #define TRAXCTRL_CNTU BIT(9) /* Post-stop-trigger countdown units; selects when DelayCount-- happens. * 0 - every 32-bit word written to tracemem, 1 - every cpu instruction */ #define TRAXCTRL_TSEN BIT(11) /* Undocumented/deprecated? */ #define TRAXCTRL_SMPER_SHIFT 12 /* Send sync every 2^(9-smper) messages. 7=reserved, 0=no sync msg */ #define TRAXCTRL_SMPER_MASK 0x07 /* Synchronization message period */ #define TRAXCTRL_PTOWT BIT(16) /* Processor Trigger Out (OCD halt) enabled when stop triggered */ #define TRAXCTRL_PTOWS BIT(17) /* Processor Trigger Out (OCD halt) enabled when trace stop completes */ #define TRAXCTRL_CTOWT BIT(20) /* Cross-trigger Out enabled when stop triggered */ #define TRAXCTRL_CTOWS BIT(21) /* Cross-trigger Out enabled when trace stop completes */ #define TRAXCTRL_ITCTO BIT(22) /* Integration mode: cross-trigger output */ #define TRAXCTRL_ITCTIA BIT(23) /* Integration mode: cross-trigger ack */ #define TRAXCTRL_ITATV BIT(24) /* replaces ATID when in integration mode: ATVALID output */ #define TRAXCTRL_ATID_MASK 0x7F /* ARB source ID */ #define TRAXCTRL_ATID_SHIFT 24 #define TRAXCTRL_ATEN BIT(31) /* ATB interface enable */ #define TRAXSTAT_TRACT BIT(0) /* Trace active flag. */ #define TRAXSTAT_TRIG BIT(1) /* Trace stop trigger. Clears on TREN 1->0 */ #define TRAXSTAT_PCMTG BIT(2) /* Stop trigger caused by PC match. Clears on TREN 1->0 */ #define TRAXSTAT_PJTR BIT(3) /* JTAG transaction result. 1=err in preceding jtag transaction. */ #define TRAXSTAT_PTITG BIT(4) /* Stop trigger caused by Processor Trigger Input.Clears on TREN 1->0 */ #define TRAXSTAT_CTITG BIT(5) /* Stop trigger caused by Cross-Trigger Input. Clears on TREN 1->0 */ #define TRAXSTAT_MEMSZ_SHIFT 8 /* Traceram size inducator. Usable trace ram is 2^MEMSZ bytes. */ #define TRAXSTAT_MEMSZ_MASK 0x1F #define TRAXSTAT_PTO BIT(16) /* Processor Trigger Output: current value */ #define TRAXSTAT_CTO BIT(17) /* Cross-Trigger Output: current value */ #define TRAXSTAT_ITCTOA BIT(22) /* Cross-Trigger Out Ack: current value */ #define TRAXSTAT_ITCTI BIT(23) /* Cross-Trigger Input: current value */ #define TRAXSTAT_ITATR BIT(24) /* ATREADY Input: current value */ #define TRAXADDR_TADDR_SHIFT 0 /* Trax memory address, in 32-bit words. */ #define TRAXADDR_TADDR_MASK 0x1FFFFF /* Actually is only as big as the trace buffer size max addr. */ #define TRAXADDR_TWRAP_SHIFT 21 /* Amount of times TADDR has overflown */ #define TRAXADDR_TWRAP_MASK 0x3FF #define TRAXADDR_TWSAT BIT(31) /* 1 if TWRAP has overflown, clear by disabling tren.*/ #define PCMATCHCTRL_PCML_SHIFT 0 /* Amount of lower bits to ignore in pc trigger register */ #define PCMATCHCTRL_PCML_MASK 0x1F #define PCMATCHCTRL_PCMS BIT(31) /* PC Match Sense, 0-match when procs PC is in-range, 1-match when * out-of-range */ #define XTENSA_MAX_PERF_COUNTERS 2 #define XTENSA_MAX_PERF_SELECT 32 #define XTENSA_MAX_PERF_MASK 0xffff #define XTENSA_STOPMASK_DISABLED UINT32_MAX struct xtensa_debug_module; struct xtensa_debug_ops { /** enable operation */ int (*queue_enable)(struct xtensa_debug_module *dm); /** register read. */ int (*queue_reg_read)(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint8_t *data); /** register write. */ int (*queue_reg_write)(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint32_t data); }; /* Xtensa power registers are 8 bits wide on JTAG interfaces but 32 bits wide * when accessed via APB/DAP. In order to use DAP queuing APIs (for optimal * performance), the XDM power register APIs take 32-bit register params. */ struct xtensa_power_ops { /** register read. */ int (*queue_reg_read)(struct xtensa_debug_module *dm, enum xtensa_dm_pwr_reg reg, uint8_t *data, uint32_t clear); /** register write. */ int (*queue_reg_write)(struct xtensa_debug_module *dm, enum xtensa_dm_pwr_reg reg, uint32_t data); }; typedef uint32_t xtensa_pwrstat_t; typedef uint32_t xtensa_ocdid_t; typedef uint32_t xtensa_dsr_t; typedef uint32_t xtensa_traxstat_t; struct xtensa_power_status { xtensa_pwrstat_t stat; xtensa_pwrstat_t stath; /* TODO: do not need to keep previous status to detect that core or debug module has been * reset, */ /* we can clear PWRSTAT_DEBUGWASRESET and PWRSTAT_COREWASRESET after reading will do * the job; */ /* upon next reet those bits will be set again. So we can get rid of * xtensa_dm_power_status_cache_reset() and xtensa_dm_power_status_cache(). */ xtensa_pwrstat_t prev_stat; }; struct xtensa_core_status { xtensa_dsr_t dsr; }; struct xtensa_trace_config { uint32_t ctrl; uint32_t memaddr_start; uint32_t memaddr_end; uint32_t addr; }; struct xtensa_trace_status { xtensa_traxstat_t stat; }; struct xtensa_trace_start_config { uint32_t stoppc; bool after_is_words; uint32_t after; uint32_t stopmask; /* UINT32_MAX: disable PC match option */ }; struct xtensa_perfmon_config { int select; uint32_t mask; int kernelcnt; int tracelevel; }; struct xtensa_perfmon_result { uint64_t value; bool overflow; }; struct xtensa_debug_module_config { const struct xtensa_power_ops *pwr_ops; const struct xtensa_debug_ops *dbg_ops; /* Either JTAG or DAP structures will be populated */ struct jtag_tap *tap; void (*queue_tdi_idle)(struct target *target); void *queue_tdi_idle_arg; /* For targets conforming to ARM Debug Interface v5, * "dap" references the Debug Access Port (DAP) * used to make requests to the target; * "debug_ap" is AP instance connected to processor */ struct adiv5_dap *dap; struct adiv5_ap *debug_ap; int debug_apsel; uint32_t ap_offset; }; struct xtensa_debug_module { const struct xtensa_power_ops *pwr_ops; const struct xtensa_debug_ops *dbg_ops; /* Either JTAG or DAP structures will be populated */ struct jtag_tap *tap; void (*queue_tdi_idle)(struct target *target); void *queue_tdi_idle_arg; /* DAP struct; AP instance connected to processor */ struct adiv5_dap *dap; struct adiv5_ap *debug_ap; int debug_apsel; struct xtensa_power_status power_status; struct xtensa_core_status core_status; xtensa_ocdid_t device_id; uint32_t ap_offset; }; int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg); void xtensa_dm_deinit(struct xtensa_debug_module *dm); int xtensa_dm_poll(struct xtensa_debug_module *dm); int xtensa_dm_examine(struct xtensa_debug_module *dm); int xtensa_dm_queue_enable(struct xtensa_debug_module *dm); int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint8_t *value); int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint32_t value); int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm, enum xtensa_dm_pwr_reg reg, uint8_t *data, uint32_t clear); int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm, enum xtensa_dm_pwr_reg reg, uint32_t data); static inline int xtensa_dm_queue_execute(struct xtensa_debug_module *dm) { return dm->dap ? dap_run(dm->dap) : jtag_execute_queue(); } static inline void xtensa_dm_queue_tdi_idle(struct xtensa_debug_module *dm) { if (dm->queue_tdi_idle) dm->queue_tdi_idle(dm->queue_tdi_idle_arg); } int xtensa_dm_power_status_read(struct xtensa_debug_module *dm, uint32_t clear); static inline void xtensa_dm_power_status_cache_reset(struct xtensa_debug_module *dm) { dm->power_status.prev_stat = 0; } static inline void xtensa_dm_power_status_cache(struct xtensa_debug_module *dm) { dm->power_status.prev_stat = dm->power_status.stath; } static inline xtensa_pwrstat_t xtensa_dm_power_status_get(struct xtensa_debug_module *dm) { return dm->power_status.stat; } int xtensa_dm_core_status_read(struct xtensa_debug_module *dm); int xtensa_dm_core_status_clear(struct xtensa_debug_module *dm, xtensa_dsr_t bits); int xtensa_dm_core_status_check(struct xtensa_debug_module *dm); static inline xtensa_dsr_t xtensa_dm_core_status_get(struct xtensa_debug_module *dm) { return dm->core_status.dsr; } int xtensa_dm_device_id_read(struct xtensa_debug_module *dm); static inline xtensa_ocdid_t xtensa_dm_device_id_get(struct xtensa_debug_module *dm) { return dm->device_id; } int xtensa_dm_trace_start(struct xtensa_debug_module *dm, struct xtensa_trace_start_config *cfg); int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable); int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_trace_config *config); int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_trace_status *status); int xtensa_dm_trace_data_read(struct xtensa_debug_module *dm, uint8_t *dest, uint32_t size); static inline bool xtensa_dm_is_online(struct xtensa_debug_module *dm) { int res = xtensa_dm_device_id_read(dm); if (res != ERROR_OK) return false; return dm->device_id != 0xffffffff && dm->device_id != 0; } static inline bool xtensa_dm_tap_was_reset(struct xtensa_debug_module *dm) { return !(dm->power_status.prev_stat & PWRSTAT_DEBUGWASRESET_DM(dm)) && dm->power_status.stat & PWRSTAT_DEBUGWASRESET_DM(dm); } static inline bool xtensa_dm_core_was_reset(struct xtensa_debug_module *dm) { return !(dm->power_status.prev_stat & PWRSTAT_COREWASRESET_DM(dm)) && dm->power_status.stat & PWRSTAT_COREWASRESET_DM(dm); } static inline bool xtensa_dm_core_is_stalled(struct xtensa_debug_module *dm) { return dm->core_status.dsr & OCDDSR_RUNSTALLSAMPLE; } static inline bool xtensa_dm_is_powered(struct xtensa_debug_module *dm) { return dm->core_status.dsr & OCDDSR_DBGMODPOWERON; } int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id, const struct xtensa_perfmon_config *config); int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id, struct xtensa_perfmon_result *out_result); #endif /* OPENOCD_TARGET_XTENSA_DEBUG_MODULE_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/xtensa/xtensa_fileio.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Xtensa Target File-I/O Support for OpenOCD * * Copyright (C) 2020-2023 Cadence Design Systems, Inc. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "xtensa_chip.h" #include "xtensa_fileio.h" #include "xtensa.h" #define XTENSA_SYSCALL(x) XT_INS_BREAK(x, 1, 14) #define XTENSA_SYSCALL_SZ 3 #define XTENSA_SYSCALL_LEN_MAX 255 int xtensa_fileio_init(struct target *target) { char *idmem = malloc(XTENSA_SYSCALL_LEN_MAX + 1); target->fileio_info = malloc(sizeof(struct gdb_fileio_info)); if (!idmem || !target->fileio_info) { LOG_TARGET_ERROR(target, "Out of memory!"); free(idmem); free(target->fileio_info); return ERROR_FAIL; } target->fileio_info->identifier = idmem; return ERROR_OK; } /** * Checks for and processes an Xtensa File-IO request. * * Return ERROR_OK if request was found and handled; or * return ERROR_FAIL if no request was detected. */ int xtensa_fileio_detect_proc(struct target *target) { struct xtensa *xtensa = target_to_xtensa(target); int retval; xtensa_reg_val_t dbg_cause = xtensa_cause_get(target); if ((dbg_cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN)) == 0 || xtensa->halt_request) return ERROR_FAIL; uint8_t brk_insn_buf[sizeof(uint32_t)] = {0}; xtensa_reg_val_t pc = xtensa_reg_get(target, XT_REG_IDX_PC); retval = target_read_memory(target, pc, XTENSA_SYSCALL_SZ, 1, (uint8_t *)brk_insn_buf); if (retval != ERROR_OK) { LOG_ERROR("Failed to read break instruction!"); return ERROR_FAIL; } if (buf_get_u32(brk_insn_buf, 0, 32) != XTENSA_SYSCALL(xtensa)) return ERROR_FAIL; LOG_TARGET_DEBUG(target, "File-I/O: syscall breakpoint found at 0x%x", pc); xtensa->proc_syscall = true; return ERROR_OK; } int xtensa_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) { /* fill syscall parameters to file-I/O info */ if (!fileio_info) { LOG_ERROR("File-I/O data structure uninitialized"); return ERROR_FAIL; } struct xtensa *xtensa = target_to_xtensa(target); if (!xtensa->proc_syscall) return ERROR_FAIL; xtensa_reg_val_t syscall = xtensa_reg_get(target, XTENSA_SYSCALL_OP_REG); xtensa_reg_val_t arg0 = xtensa_reg_get(target, XT_REG_IDX_A6); xtensa_reg_val_t arg1 = xtensa_reg_get(target, XT_REG_IDX_A3); xtensa_reg_val_t arg2 = xtensa_reg_get(target, XT_REG_IDX_A4); xtensa_reg_val_t arg3 = xtensa_reg_get(target, XT_REG_IDX_A5); int retval = ERROR_OK; LOG_TARGET_DEBUG(target, "File-I/O: syscall 0x%x 0x%x 0x%x 0x%x 0x%x", syscall, arg0, arg1, arg2, arg3); switch (syscall) { case XTENSA_SYSCALL_OPEN: snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "open"); fileio_info->param_1 = arg0; // pathp fileio_info->param_2 = arg3; // len fileio_info->param_3 = arg1; // flags fileio_info->param_4 = arg2; // mode break; case XTENSA_SYSCALL_CLOSE: snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "close"); fileio_info->param_1 = arg0; // fd break; case XTENSA_SYSCALL_READ: snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "read"); fileio_info->param_1 = arg0; // fd fileio_info->param_2 = arg1; // bufp fileio_info->param_3 = arg2; // count break; case XTENSA_SYSCALL_WRITE: snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "write"); fileio_info->param_1 = arg0; // fd fileio_info->param_2 = arg1; // bufp fileio_info->param_3 = arg2; // count break; case XTENSA_SYSCALL_LSEEK: snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "lseek"); fileio_info->param_1 = arg0; // fd fileio_info->param_2 = arg1; // offset fileio_info->param_3 = arg2; // flags break; case XTENSA_SYSCALL_RENAME: snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "rename"); fileio_info->param_1 = arg0; // old pathp fileio_info->param_2 = arg3; // old len fileio_info->param_3 = arg1; // new pathp fileio_info->param_4 = arg2; // new len break; case XTENSA_SYSCALL_UNLINK: snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "unlink"); fileio_info->param_1 = arg0; // pathnamep fileio_info->param_2 = arg1; // len break; case XTENSA_SYSCALL_STAT: snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "stat"); fileio_info->param_1 = arg0; // pathnamep fileio_info->param_2 = arg2; // len fileio_info->param_3 = arg1; // bufp break; case XTENSA_SYSCALL_FSTAT: snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "fstat"); fileio_info->param_1 = arg0; // fd fileio_info->param_2 = arg1; // bufp break; case XTENSA_SYSCALL_GETTIMEOFDAY: snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "gettimeofday"); fileio_info->param_1 = arg0; // tvp fileio_info->param_2 = arg1; // tzp break; case XTENSA_SYSCALL_ISATTY: snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "isatty"); fileio_info->param_1 = arg0; // fd break; case XTENSA_SYSCALL_SYSTEM: snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "system"); fileio_info->param_1 = arg0; // cmdp fileio_info->param_2 = arg1; // len break; default: snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "unknown"); LOG_TARGET_DEBUG(target, "File-I/O: syscall unknown (%d), pc=0x%08X", syscall, xtensa_reg_get(target, XT_REG_IDX_PC)); LOG_INFO("File-I/O: syscall unknown (%d), pc=0x%08X", syscall, xtensa_reg_get(target, XT_REG_IDX_PC)); retval = ERROR_FAIL; break; } return retval; } int xtensa_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c) { struct xtensa *xtensa = target_to_xtensa(target); if (!xtensa->proc_syscall) return ERROR_FAIL; LOG_TARGET_DEBUG(target, "File-I/O: syscall return code: 0x%x, errno: 0x%x , ctrl_c: %s", retcode, fileio_errno, ctrl_c ? "true" : "false"); /* If interrupt was requested before FIO completion (ERRNO==4), halt and repeat * syscall. Otherwise, set File-I/O Ax and underlying ARx registers, increment PC. * NOTE: sporadic cases of ((ERRNO==4) && !ctrl_c) were observed; most have ctrl_c. */ if (fileio_errno != 4) { xtensa_reg_set_deep_relgen(target, XTENSA_SYSCALL_RETVAL_REG, retcode); xtensa_reg_set_deep_relgen(target, XTENSA_SYSCALL_ERRNO_REG, fileio_errno); xtensa_reg_val_t pc = xtensa_reg_get(target, XT_REG_IDX_PC); xtensa_reg_set(target, XT_REG_IDX_PC, pc + XTENSA_SYSCALL_SZ); } xtensa->proc_syscall = false; xtensa->halt_request = true; return ctrl_c ? ERROR_FAIL : ERROR_OK; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/xtensa/xtensa_fileio.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Xtensa Target File-I/O Support for OpenOCD * * Copyright (C) 2020-2023 Cadence Design Systems, Inc. * ***************************************************************************/ #ifndef OPENOCD_TARGET_XTENSA_FILEIO_H #define OPENOCD_TARGET_XTENSA_FILEIO_H #include <target/target.h> #include <helper/command.h> #include "xtensa.h" #define XTENSA_SYSCALL_OP_REG XT_REG_IDX_A2 #define XTENSA_SYSCALL_RETVAL_REG XT_REG_IDX_A2 #define XTENSA_SYSCALL_ERRNO_REG XT_REG_IDX_A3 #define XTENSA_SYSCALL_OPEN (-2) #define XTENSA_SYSCALL_CLOSE (-3) #define XTENSA_SYSCALL_READ (-4) #define XTENSA_SYSCALL_WRITE (-5) #define XTENSA_SYSCALL_LSEEK (-6) #define XTENSA_SYSCALL_RENAME (-7) #define XTENSA_SYSCALL_UNLINK (-8) #define XTENSA_SYSCALL_STAT (-9) #define XTENSA_SYSCALL_FSTAT (-10) #define XTENSA_SYSCALL_GETTIMEOFDAY (-11) #define XTENSA_SYSCALL_ISATTY (-12) #define XTENSA_SYSCALL_SYSTEM (-13) int xtensa_fileio_init(struct target *target); int xtensa_fileio_detect_proc(struct target *target); int xtensa_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info); int xtensa_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c); #endif /* OPENOCD_TARGET_XTENSA_FILEIO_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/target/xtensa/xtensa_regs.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Generic Xtensa target API for OpenOCD * * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * * Copyright (C) 2016-2019 Espressif Systems Ltd. * * Author: Angus Gratton gus@projectgus.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_XTENSA_REGS_H #define OPENOCD_TARGET_XTENSA_REGS_H struct reg_arch_type; enum xtensa_reg_id { XT_REG_IDX_PC = 0, XT_REG_IDX_AR0, XT_REG_IDX_ARFIRST = XT_REG_IDX_AR0, XT_REG_IDX_AR1, XT_REG_IDX_AR2, XT_REG_IDX_AR3, XT_REG_IDX_AR4, XT_REG_IDX_AR5, XT_REG_IDX_AR6, XT_REG_IDX_AR7, XT_REG_IDX_AR8, XT_REG_IDX_AR9, XT_REG_IDX_AR10, XT_REG_IDX_AR11, XT_REG_IDX_AR12, XT_REG_IDX_AR13, XT_REG_IDX_AR14, XT_REG_IDX_AR15, XT_REG_IDX_ARLAST = 64, /* Max 64 ARs */ XT_REG_IDX_WINDOWBASE, XT_REG_IDX_WINDOWSTART, XT_REG_IDX_PS, XT_REG_IDX_IBREAKENABLE, XT_REG_IDX_DDR, XT_REG_IDX_IBREAKA0, XT_REG_IDX_IBREAKA1, XT_REG_IDX_DBREAKA0, XT_REG_IDX_DBREAKA1, XT_REG_IDX_DBREAKC0, XT_REG_IDX_DBREAKC1, XT_REG_IDX_CPENABLE, XT_REG_IDX_EXCCAUSE, XT_REG_IDX_DEBUGCAUSE, XT_REG_IDX_ICOUNT, XT_REG_IDX_ICOUNTLEVEL, XT_REG_IDX_A0, XT_REG_IDX_A1, XT_REG_IDX_A2, XT_REG_IDX_A3, XT_REG_IDX_A4, XT_REG_IDX_A5, XT_REG_IDX_A6, XT_REG_IDX_A7, XT_REG_IDX_A8, XT_REG_IDX_A9, XT_REG_IDX_A10, XT_REG_IDX_A11, XT_REG_IDX_A12, XT_REG_IDX_A13, XT_REG_IDX_A14, XT_REG_IDX_A15, XT_NUM_REGS }; typedef uint32_t xtensa_reg_val_t; #define XT_NUM_A_REGS 16 enum xtensa_reg_type { XT_REG_GENERAL = 0, /* General-purpose register; part of the windowed register set */ XT_REG_USER = 1, /* User register, needs RUR to read */ XT_REG_SPECIAL = 2, /* Special register, needs RSR to read */ XT_REG_DEBUG = 3, /* Register used for the debug interface. Don't mess with this. */ XT_REG_RELGEN = 4, /* Relative general address. Points to the absolute addresses plus the window * index */ XT_REG_FR = 5, /* Floating-point register */ XT_REG_TIE = 6, /* TIE (custom) register */ XT_REG_OTHER = 7, /* Other (typically legacy) register */ XT_REG_TYPE_NUM, /* enum names must be one of the above types + _VAL or _MASK */ XT_REG_GENERAL_MASK = 0xFFC0, XT_REG_GENERAL_VAL = 0x0100, XT_REG_USER_MASK = 0xFF00, XT_REG_USER_VAL = 0x0300, XT_REG_SPECIAL_MASK = 0xFF00, XT_REG_SPECIAL_VAL = 0x0200, XT_REG_DEBUG_MASK = 0xFF00, XT_REG_DEBUG_VAL = 0x0200, XT_REG_RELGEN_MASK = 0xFFE0, XT_REG_RELGEN_VAL = 0x0000, XT_REG_FR_MASK = 0xFFF0, XT_REG_FR_VAL = 0x0030, XT_REG_TIE_MASK = 0xF000, XT_REG_TIE_VAL = 0xF000, /* unused */ XT_REG_OTHER_MASK = 0xFFFF, XT_REG_OTHER_VAL = 0xF000, /* unused */ XT_REG_INDEX_MASK = 0x00FF }; enum xtensa_reg_flags { XT_REGF_NOREAD = 0x01, /* Register is write-only */ XT_REGF_COPROC0 = 0x02, /* Can't be read if coproc0 isn't enabled */ XT_REGF_MASK = 0x03 }; struct xtensa_reg_desc { const char *name; bool exist; unsigned int reg_num; /* ISA register num (meaning depends on register type) */ unsigned int dbreg_num; /* Debugger-visible register num (reg type encoded) */ enum xtensa_reg_type type; enum xtensa_reg_flags flags; }; #define _XT_MK_DBREGN(reg_num, reg_type) \ ((reg_type ## _VAL) | (reg_num)) #define _XT_MK_DBREGN_MASK(reg_num, reg_mask) \ ((reg_mask) | (reg_num)) #define XT_MK_REG_DESC(n, r, t, f) \ { .name = (n), .exist = false, .reg_num = (r), \ .dbreg_num = _XT_MK_DBREGN(r, t), .type = (t), \ .flags = (f) } extern struct xtensa_reg_desc xtensa_regs[XT_NUM_REGS]; #endif /* OPENOCD_TARGET_XTENSA_REGS_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/transport/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libtransport.la %C%_libtransport_la_SOURCES = \ %D%/transport.c \ %D%/transport.h ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/transport/transport.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2010 by David Brownell */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /** @file * Infrastructure for specifying and managing the transport protocol * used in a given debug or programming session. * * Examples of "debug-capable" transports are JTAG or SWD. * Additionally, JTAG supports boundary scan testing. * * Examples of "programming-capable" transports include SPI or UART; * those are used (often mediated by a ROM bootloader) for ISP style * programming, to perform an initial load of code into flash, or * sometimes into SRAM. Target code could use "variant" options to * decide how to use such protocols. For example, Cortex-M3 cores * from TI/Luminary and from NXP use different protocols for for * UART or SPI based firmware loading. * * As a rule, there are protocols layered on top of the transport. * For example, different chip families use JTAG in different ways * for debugging. Also, each family that supports programming over * a UART link for initial firmware loading tends to define its own * messaging and error handling. */ #include <helper/log.h> #include <helper/replacements.h> #include <transport/transport.h> extern struct command_context *global_cmd_ctx; /*-----------------------------------------------------------------------*/ /* * Infrastructure internals */ /** List of transports known to OpenOCD. */ static struct transport *transport_list; /** * NULL-terminated Vector of names of transports which the * currently selected debug adapter supports. This is declared * by the time that adapter is fully set up. */ static const char * const *allowed_transports; /** * The transport being used for the current OpenOCD session. */ static struct transport *session; static int transport_select(struct command_context *ctx, const char *name) { /* name may only identify a known transport; * caller guarantees session's transport isn't yet set.*/ for (struct transport *t = transport_list; t; t = t->next) { if (strcmp(t->name, name) == 0) { int retval = t->select(ctx); /* select() registers commands specific to this * transport, and may also reset the link, e.g. * forcing it to JTAG or SWD mode. */ if (retval == ERROR_OK) session = t; else LOG_ERROR("Error selecting '%s' as transport", t->name); return retval; } } LOG_ERROR("No transport named '%s' is available.", name); return ERROR_FAIL; } /** * Called by debug adapter drivers, or affiliated Tcl config scripts, * to declare the set of transports supported by an adapter. When * there is only one member of that set, it is automatically selected. */ int allow_transports(struct command_context *ctx, const char * const *vector) { /* NOTE: caller is required to provide only a list * of *valid* transport names * * REVISIT should we validate that? and insist there's * at least one non-NULL element in that list? * * ... allow removals, e.g. external strapping prevents use * of one transport; C code should be definitive about what * can be used when all goes well. */ if (allowed_transports || session) { LOG_ERROR("Can't modify the set of allowed transports."); return ERROR_FAIL; } allowed_transports = vector; /* autoselect if there's no choice ... */ if (!vector[1]) { LOG_INFO("only one transport option; autoselecting '%s'", vector[0]); return transport_select(ctx, vector[0]); } return ERROR_OK; } /** * Registers a transport. There are general purpose transports * (such as JTAG), as well as relatively proprietary ones which are * specific to a given chip (or chip family). * * Code implementing a transport needs to register it before it can * be selected and then activated. This is a dynamic process, so * that chips (and families) can define transports as needed (without * needing error-prone static tables). * * @param new_transport the transport being registered. On a * successful return, this memory is owned by the transport framework. * * @returns ERROR_OK on success, else a fault code. */ int transport_register(struct transport *new_transport) { struct transport *t; for (t = transport_list; t; t = t->next) { if (strcmp(t->name, new_transport->name) == 0) { LOG_ERROR("transport name already used"); return ERROR_FAIL; } } if (!new_transport->select || !new_transport->init) LOG_ERROR("invalid transport %s", new_transport->name); /* splice this into the list */ new_transport->next = transport_list; transport_list = new_transport; LOG_DEBUG("register '%s'", new_transport->name); return ERROR_OK; } /** * Returns the transport currently being used by this debug or * programming session. * * @returns handle to the read-only transport entity. */ struct transport *get_current_transport(void) { /* REVISIT -- constify */ return session; } /*-----------------------------------------------------------------------*/ /* * Infrastructure for Tcl interface to transports. */ /** * Makes and stores a copy of a set of transports passed as * parameters to a command. * * @param vector where the resulting copy is stored, as an argv-style * NULL-terminated vector. */ COMMAND_HELPER(transport_list_parse, char ***vector) { char **argv; unsigned n = CMD_ARGC; unsigned j = 0; *vector = NULL; if (n < 1) return ERROR_COMMAND_SYNTAX_ERROR; /* our return vector must be NULL terminated */ argv = calloc(n + 1, sizeof(char *)); if (!argv) return ERROR_FAIL; for (unsigned i = 0; i < n; i++) { struct transport *t; for (t = transport_list; t; t = t->next) { if (strcmp(t->name, CMD_ARGV[i]) != 0) continue; argv[j++] = strdup(CMD_ARGV[i]); break; } if (!t) { LOG_ERROR("no such transport '%s'", CMD_ARGV[i]); goto fail; } } *vector = argv; return ERROR_OK; fail: for (unsigned i = 0; i < n; i++) free(argv[i]); free(argv); return ERROR_FAIL; } COMMAND_HANDLER(handle_transport_init) { LOG_DEBUG("%s", __func__); if (!session) { LOG_ERROR("session transport was not selected. Use 'transport select <transport>'"); /* no session transport configured, print transports then fail */ LOG_ERROR("Transports available:"); const char * const *vector = allowed_transports; while (*vector) { LOG_ERROR("%s", *vector); vector++; } return ERROR_FAIL; } return session->init(CMD_CTX); } COMMAND_HANDLER(handle_transport_list) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "The following transports are available:"); for (struct transport *t = transport_list; t; t = t->next) command_print(CMD, "\t%s", t->name); return ERROR_OK; } /** * Implements the Tcl "transport select" command, choosing the * transport to be used in this debug session from among the * set supported by the debug adapter being used. Return value * is scriptable (allowing "if swd then..." etc). */ COMMAND_HANDLER(handle_transport_select) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 0) { /* autoselect if necessary, then return/display current config */ if (!session) { if (!allowed_transports) { command_print(CMD, "Debug adapter does not support any transports? Check config file order."); return ERROR_FAIL; } LOG_INFO("auto-selecting first available session transport \"%s\". " "To override use 'transport select <transport>'.", allowed_transports[0]); int retval = transport_select(CMD_CTX, allowed_transports[0]); if (retval != ERROR_OK) return retval; } command_print(CMD, "%s", session->name); return ERROR_OK; } /* assign transport */ if (session) { if (!strcmp(session->name, CMD_ARGV[0])) { LOG_WARNING("Transport \"%s\" was already selected", session->name); command_print(CMD, "%s", session->name); return ERROR_OK; } command_print(CMD, "Can't change session's transport after the initial selection was made"); return ERROR_FAIL; } /* Is this transport supported by our debug adapter? * Example, "JTAG-only" means SWD is not supported. * * NOTE: requires adapter to have been set up, with * transports declared via C. */ if (!allowed_transports) { command_print(CMD, "Debug adapter doesn't support any transports?"); return ERROR_FAIL; } for (unsigned int i = 0; allowed_transports[i]; i++) { if (!strcmp(allowed_transports[i], CMD_ARGV[0])) { int retval = transport_select(CMD_CTX, CMD_ARGV[0]); if (retval != ERROR_OK) return retval; command_print(CMD, "%s", session->name); return ERROR_OK; } } command_print(CMD, "Debug adapter doesn't support '%s' transport", CMD_ARGV[0]); return ERROR_FAIL; } static const struct command_registration transport_commands[] = { { .name = "init", .handler = handle_transport_init, /* this would be COMMAND_CONFIG ... except that * it needs to trigger event handlers that may * require COMMAND_EXEC ... */ .mode = COMMAND_ANY, .help = "Initialize this session's transport", .usage = "" }, { .name = "list", .handler = handle_transport_list, .mode = COMMAND_ANY, .help = "list all built-in transports", .usage = "" }, { .name = "select", .handler = handle_transport_select, .mode = COMMAND_ANY, .help = "Select this session's transport", .usage = "[transport_name]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration transport_group[] = { { .name = "transport", .mode = COMMAND_ANY, .help = "Transport command group", .chain = transport_commands, .usage = "" }, COMMAND_REGISTRATION_DONE }; int transport_register_commands(struct command_context *ctx) { return register_commands(ctx, NULL, transport_group); } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/transport/transport.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (c) 2010 by David Brownell * Copyright (C) 2011 Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) */ #ifndef OPENOCD_TRANSPORT_TRANSPORT_H #define OPENOCD_TRANSPORT_TRANSPORT_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "helper/command.h" /** * Wrapper for transport lifecycle operations. * * OpenOCD talks to targets through some kind of debugging * or programming adapter, using some protocol that probably * has target-specific aspects. * * A "transport" reflects electrical protocol to the target, * e..g jtag, swd, spi, uart, ... NOT the messaging protocols * layered over it (e.g. JTAG has eICE, CoreSight, Nexus, OnCE, * and more). * * In addition to the lifecycle operations packaged by this * structure, a transport also involves an interface supported * by debug adapters and used by components such as debug targets. * For non-debug transports, there may be interfaces used to * write to flash chips. */ struct transport { /** * Each transport has a unique name, used to select it * from among the alternatives. Examples might include * "jtag", * "swd", "AVR_ISP" and more. */ const char *name; /** * When a transport is selected, this method registers * its commands and activates the transport (e.g. resets * the link). * * After those commands are registered, they will often * be used for further configuration of the debug link. */ int (*select)(struct command_context *ctx); /** * server startup uses this method to validate transport * configuration. (For example, with JTAG this interrogates * the scan chain against the list of expected TAPs.) */ int (*init)(struct command_context *ctx); /** * Optional. If defined, allows transport to override target * name prior to initialisation. * * @returns ERROR_OK on success, or an error code on failure. */ int (*override_target)(const char **targetname); /** * Transports are stored in a singly linked list. */ struct transport *next; }; int transport_register(struct transport *new_transport); struct transport *get_current_transport(void); int transport_register_commands(struct command_context *ctx); COMMAND_HELPER(transport_list_parse, char ***vector); int allow_transports(struct command_context *ctx, const char * const *vector); bool transport_is_jtag(void); bool transport_is_swd(void); bool transport_is_dapdirect_jtag(void); bool transport_is_dapdirect_swd(void); bool transport_is_swim(void); #if BUILD_HLADAPTER bool transport_is_hla(void); #else static inline bool transport_is_hla(void) { return false; } #endif #endif /* OPENOCD_TRANSPORT_TRANSPORT_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/xsvf/Makefile.am ================================================ # SPDX-License-Identifier: GPL-2.0-or-later noinst_LTLIBRARIES += %D%/libxsvf.la %C%_libxsvf_la_SOURCES = %D%/xsvf.c %D%/xsvf.h ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/xsvf/xsvf.c ================================================ // SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 Peter Hettkamp * * peter.hettkamp@htp-tel.de * * * * Copyright (C) 2009 SoftPLC Corporation. http://softplc.com * * Dick Hollenbeck <dick@softplc.com> * ***************************************************************************/ /* The specification for SVF is available here: * http://www.asset-intertech.com/support/svf.pdf * Below, this document is referred to as the "SVF spec". * * The specification for XSVF is available here: * http://www.xilinx.com/support/documentation/application_notes/xapp503.pdf * Below, this document is referred to as the "XSVF spec". */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "xsvf.h" #include "helper/system.h" #include <jtag/jtag.h> #include <svf/svf.h> /* XSVF commands, from appendix B of xapp503.pdf */ #define XCOMPLETE 0x00 #define XTDOMASK 0x01 #define XSIR 0x02 #define XSDR 0x03 #define XRUNTEST 0x04 #define XREPEAT 0x07 #define XSDRSIZE 0x08 #define XSDRTDO 0x09 #define XSETSDRMASKS 0x0A #define XSDRINC 0x0B #define XSDRB 0x0C #define XSDRC 0x0D #define XSDRE 0x0E #define XSDRTDOB 0x0F #define XSDRTDOC 0x10 #define XSDRTDOE 0x11 #define XSTATE 0x12 #define XENDIR 0x13 #define XENDDR 0x14 #define XSIR2 0x15 #define XCOMMENT 0x16 #define XWAIT 0x17 /* XWAITSTATE is not in the xilinx XSVF spec, but the svf2xsvf.py translator * generates this. Arguably it is needed because the XSVF XRUNTEST command * was ill conceived and does not directly flow out of the SVF RUNTEST command. * This XWAITSTATE does map directly from the SVF RUNTEST command. */ #define XWAITSTATE 0x18 /* Lattice has extended the SVF file format, and Dick Hollenbeck's python based * SVF2XSVF converter supports these 3 additional XSVF opcodes, LCOUNT, LDELAY, LSDR. * Here is an example of usage of the 3 lattice opcode extensions: ! Set the maximum loop count to 25. LCOUNT 25; ! Step to DRPAUSE give 5 clocks and wait for 1.00e + 000 SEC. LDELAY DRPAUSE 5 TCK 1.00E-003 SEC; ! Test for the completed status. Match means pass. ! Loop back to LDELAY line if not match and loop count less than 25. LSDR 1 TDI (0) TDO (1); */ #define LCOUNT 0x19 #define LDELAY 0x1A #define LSDR 0x1B #define XTRST 0x1C /* XSVF valid state values for the XSTATE command, from appendix B of xapp503.pdf */ #define XSV_RESET 0x00 #define XSV_IDLE 0x01 #define XSV_DRSELECT 0x02 #define XSV_DRCAPTURE 0x03 #define XSV_DRSHIFT 0x04 #define XSV_DREXIT1 0x05 #define XSV_DRPAUSE 0x06 #define XSV_DREXIT2 0x07 #define XSV_DRUPDATE 0x08 #define XSV_IRSELECT 0x09 #define XSV_IRCAPTURE 0x0A #define XSV_IRSHIFT 0x0B #define XSV_IREXIT1 0x0C #define XSV_IRPAUSE 0x0D #define XSV_IREXIT2 0x0E #define XSV_IRUPDATE 0x0F /* arguments to XTRST */ #define XTRST_ON 0 #define XTRST_OFF 1 #define XTRST_Z 2 #define XTRST_ABSENT 3 #define XSTATE_MAX_PATH 12 static int xsvf_fd; /* map xsvf tap state to an openocd "tap_state_t" */ static tap_state_t xsvf_to_tap(int xsvf_state) { tap_state_t ret; switch (xsvf_state) { case XSV_RESET: ret = TAP_RESET; break; case XSV_IDLE: ret = TAP_IDLE; break; case XSV_DRSELECT: ret = TAP_DRSELECT; break; case XSV_DRCAPTURE: ret = TAP_DRCAPTURE; break; case XSV_DRSHIFT: ret = TAP_DRSHIFT; break; case XSV_DREXIT1: ret = TAP_DREXIT1; break; case XSV_DRPAUSE: ret = TAP_DRPAUSE; break; case XSV_DREXIT2: ret = TAP_DREXIT2; break; case XSV_DRUPDATE: ret = TAP_DRUPDATE; break; case XSV_IRSELECT: ret = TAP_IRSELECT; break; case XSV_IRCAPTURE: ret = TAP_IRCAPTURE; break; case XSV_IRSHIFT: ret = TAP_IRSHIFT; break; case XSV_IREXIT1: ret = TAP_IREXIT1; break; case XSV_IRPAUSE: ret = TAP_IRPAUSE; break; case XSV_IREXIT2: ret = TAP_IREXIT2; break; case XSV_IRUPDATE: ret = TAP_IRUPDATE; break; default: LOG_ERROR("UNKNOWN XSVF STATE 0x%02X", xsvf_state); exit(1); } return ret; } static int xsvf_read_buffer(int num_bits, int fd, uint8_t *buf) { int num_bytes; for (num_bytes = (num_bits + 7) / 8; num_bytes > 0; num_bytes--) { /* reverse the order of bytes as they are read sequentially from file */ if (read(fd, buf + num_bytes - 1, 1) < 0) return ERROR_XSVF_EOF; } return ERROR_OK; } COMMAND_HANDLER(handle_xsvf_command) { uint8_t *dr_out_buf = NULL; /* from host to device (TDI) */ uint8_t *dr_in_buf = NULL; /* from device to host (TDO) */ uint8_t *dr_in_mask = NULL; int xsdrsize = 0; int xruntest = 0; /* number of TCK cycles OR *microseconds */ int xrepeat = 0; /* number of retries */ tap_state_t xendir = TAP_IDLE; /* see page 8 of the SVF spec, initial *xendir to be TAP_IDLE */ tap_state_t xenddr = TAP_IDLE; uint8_t opcode; uint8_t uc = 0; long file_offset = 0; int loop_count = 0; tap_state_t loop_state = TAP_IDLE; int loop_clocks = 0; int loop_usecs = 0; int do_abort = 0; int unsupported = 0; int tdo_mismatch = 0; int result; int verbose = 1; bool collecting_path = false; tap_state_t path[XSTATE_MAX_PATH]; unsigned pathlen = 0; /* a flag telling whether to clock TCK during waits, * or simply sleep, controlled by virt2 */ int runtest_requires_tck = 0; /* use NULL to indicate a "plain" xsvf file which accounts for * additional devices in the scan chain, otherwise the device * that should be affected */ struct jtag_tap *tap = NULL; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; /* we mess with CMD_ARGV starting point below, snapshot filename here */ const char *filename = CMD_ARGV[1]; if (strcmp(CMD_ARGV[0], "plain") != 0) { tap = jtag_tap_by_string(CMD_ARGV[0]); if (!tap) { command_print(CMD, "Tap: %s unknown", CMD_ARGV[0]); return ERROR_FAIL; } } xsvf_fd = open(filename, O_RDONLY); if (xsvf_fd < 0) { command_print(CMD, "file \"%s\" not found", filename); return ERROR_FAIL; } /* if this argument is present, then interpret xruntest counts as TCK cycles rather than as *usecs */ if ((CMD_ARGC > 2) && (strcmp(CMD_ARGV[2], "virt2") == 0)) { runtest_requires_tck = 1; --CMD_ARGC; ++CMD_ARGV; } if ((CMD_ARGC > 2) && (strcmp(CMD_ARGV[2], "quiet") == 0)) verbose = 0; LOG_WARNING("XSVF support in OpenOCD is limited. Consider using SVF instead"); LOG_USER("xsvf processing file: \"%s\"", filename); while (read(xsvf_fd, &opcode, 1) > 0) { /* record the position of this opcode within the file */ file_offset = lseek(xsvf_fd, 0, SEEK_CUR) - 1; /* maybe collect another state for a pathmove(); * or terminate a path. */ if (collecting_path) { tap_state_t mystate; switch (opcode) { case XCOMMENT: /* ignore/show comments between XSTATE ops */ break; case XSTATE: /* try to collect another transition */ if (pathlen == XSTATE_MAX_PATH) { LOG_ERROR("XSVF: path too long"); do_abort = 1; break; } if (read(xsvf_fd, &uc, 1) < 0) { do_abort = 1; break; } mystate = xsvf_to_tap(uc); path[pathlen++] = mystate; LOG_DEBUG("XSTATE 0x%02X %s", uc, tap_state_name(mystate)); /* If path is incomplete, collect more */ if (!svf_tap_state_is_stable(mystate)) continue; /* Else execute the path transitions we've * collected so far. * * NOTE: Punting on the saved path is not * strictly correct, but we must to do this * unless jtag_add_pathmove() stops rejecting * paths containing RESET. This is probably * harmless, since there aren't many options * for going from a stable state to reset; * at the worst, we may issue extra clocks * once we get to RESET. */ if (mystate == TAP_RESET) { LOG_WARNING("XSVF: dodgey RESET"); path[0] = mystate; } /* FALL THROUGH */ default: /* Execute the path we collected * * NOTE: OpenOCD requires something that XSVF * doesn't: the last TAP state in the path * must be stable. In practice, tools that * create XSVF seem to follow that rule too. */ collecting_path = false; if (path[0] == TAP_RESET) jtag_add_tlr(); else jtag_add_pathmove(pathlen, path); result = jtag_execute_queue(); if (result != ERROR_OK) { LOG_ERROR("XSVF: pathmove error %d", result); do_abort = 1; break; } continue; } } switch (opcode) { case XCOMPLETE: LOG_DEBUG("XCOMPLETE"); result = jtag_execute_queue(); if (result != ERROR_OK) { tdo_mismatch = 1; break; } break; case XTDOMASK: LOG_DEBUG("XTDOMASK"); if (dr_in_mask && (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_mask) != ERROR_OK)) do_abort = 1; break; case XRUNTEST: { uint8_t xruntest_buf[4]; if (read(xsvf_fd, xruntest_buf, 4) < 0) { do_abort = 1; break; } xruntest = be_to_h_u32(xruntest_buf); LOG_DEBUG("XRUNTEST %d 0x%08X", xruntest, xruntest); } break; case XREPEAT: { uint8_t myrepeat; if (read(xsvf_fd, &myrepeat, 1) < 0) do_abort = 1; else { xrepeat = myrepeat; LOG_DEBUG("XREPEAT %d", xrepeat); } } break; case XSDRSIZE: { uint8_t xsdrsize_buf[4]; if (read(xsvf_fd, xsdrsize_buf, 4) < 0) { do_abort = 1; break; } xsdrsize = be_to_h_u32(xsdrsize_buf); LOG_DEBUG("XSDRSIZE %d", xsdrsize); free(dr_out_buf); free(dr_in_buf); free(dr_in_mask); dr_out_buf = malloc((xsdrsize + 7) / 8); dr_in_buf = malloc((xsdrsize + 7) / 8); dr_in_mask = malloc((xsdrsize + 7) / 8); } break; case XSDR: /* these two are identical except for the dr_in_buf */ case XSDRTDO: { int limit = xrepeat; int matched = 0; int attempt; const char *op_name = (opcode == XSDR ? "XSDR" : "XSDRTDO"); if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_out_buf) != ERROR_OK) { do_abort = 1; break; } if (opcode == XSDRTDO) { if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_buf) != ERROR_OK) { do_abort = 1; break; } } if (limit < 1) limit = 1; LOG_DEBUG("%s %d", op_name, xsdrsize); for (attempt = 0; attempt < limit; ++attempt) { struct scan_field field; if (attempt > 0) { /* perform the XC9500 exception handling sequence shown in xapp067.pdf and * illustrated in pseudo code at end of this file. We start from state * DRPAUSE: * go to Exit2-DR * go to Shift-DR * go to Exit1-DR * go to Update-DR * go to Run-Test/Idle * * This sequence should be harmless for other devices, and it * will be skipped entirely if xrepeat is set to zero. */ static tap_state_t exception_path[] = { TAP_DREXIT2, TAP_DRSHIFT, TAP_DREXIT1, TAP_DRUPDATE, TAP_IDLE, }; jtag_add_pathmove(ARRAY_SIZE(exception_path), exception_path); if (verbose) LOG_USER("%s mismatch, xsdrsize=%d retry=%d", op_name, xsdrsize, attempt); } field.num_bits = xsdrsize; field.out_value = dr_out_buf; field.in_value = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); if (!tap) jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, TAP_DRPAUSE); else jtag_add_dr_scan(tap, 1, &field, TAP_DRPAUSE); jtag_check_value_mask(&field, dr_in_buf, dr_in_mask); free(field.in_value); /* LOG_DEBUG("FLUSHING QUEUE"); */ result = jtag_execute_queue(); if (result == ERROR_OK) { matched = 1; break; } } if (!matched) { LOG_USER("%s mismatch", op_name); tdo_mismatch = 1; break; } /* See page 19 of XSVF spec regarding opcode "XSDR" */ if (xruntest) { result = svf_add_statemove(TAP_IDLE); if (result != ERROR_OK) return result; if (runtest_requires_tck) jtag_add_clocks(xruntest); else jtag_add_sleep(xruntest); } else if (xendir != TAP_DRPAUSE) { /* we are already in TAP_DRPAUSE */ result = svf_add_statemove(xenddr); if (result != ERROR_OK) return result; } } break; case XSETSDRMASKS: LOG_ERROR("unsupported XSETSDRMASKS"); unsupported = 1; break; case XSDRINC: LOG_ERROR("unsupported XSDRINC"); unsupported = 1; break; case XSDRB: LOG_ERROR("unsupported XSDRB"); unsupported = 1; break; case XSDRC: LOG_ERROR("unsupported XSDRC"); unsupported = 1; break; case XSDRE: LOG_ERROR("unsupported XSDRE"); unsupported = 1; break; case XSDRTDOB: LOG_ERROR("unsupported XSDRTDOB"); unsupported = 1; break; case XSDRTDOC: LOG_ERROR("unsupported XSDRTDOC"); unsupported = 1; break; case XSDRTDOE: LOG_ERROR("unsupported XSDRTDOE"); unsupported = 1; break; case XSTATE: { tap_state_t mystate; if (read(xsvf_fd, &uc, 1) < 0) { do_abort = 1; break; } mystate = xsvf_to_tap(uc); LOG_DEBUG("XSTATE 0x%02X %s", uc, tap_state_name(mystate)); if (mystate == TAP_INVALID) { LOG_ERROR("XSVF: bad XSTATE %02x", uc); do_abort = 1; break; } /* NOTE: the current state is SVF-stable! */ /* no change == NOP */ if (mystate == cmd_queue_cur_state && mystate != TAP_RESET) break; /* Hand off to SVF? */ if (svf_tap_state_is_stable(mystate)) { result = svf_add_statemove(mystate); if (result != ERROR_OK) unsupported = 1; break; } /* * A sequence of XSTATE transitions, each TAP * state adjacent to the previous one. Start * collecting them. */ collecting_path = true; pathlen = 1; path[0] = mystate; } break; case XENDIR: if (read(xsvf_fd, &uc, 1) < 0) { do_abort = 1; break; } /* see page 22 of XSVF spec */ if (uc == 0) xendir = TAP_IDLE; else if (uc == 1) xendir = TAP_IRPAUSE; else { LOG_ERROR("illegial XENDIR argument: 0x%02X", uc); unsupported = 1; break; } LOG_DEBUG("XENDIR 0x%02X %s", uc, tap_state_name(xendir)); break; case XENDDR: if (read(xsvf_fd, &uc, 1) < 0) { do_abort = 1; break; } /* see page 22 of XSVF spec */ if (uc == 0) xenddr = TAP_IDLE; else if (uc == 1) xenddr = TAP_DRPAUSE; else { LOG_ERROR("illegial XENDDR argument: 0x%02X", uc); unsupported = 1; break; } LOG_DEBUG("XENDDR %02X %s", uc, tap_state_name(xenddr)); break; case XSIR: case XSIR2: { uint8_t short_buf[2]; uint8_t *ir_buf; int bitcount; tap_state_t my_end_state = xruntest ? TAP_IDLE : xendir; if (opcode == XSIR) { /* one byte bitcount */ if (read(xsvf_fd, short_buf, 1) < 0) { do_abort = 1; break; } bitcount = short_buf[0]; LOG_DEBUG("XSIR %d", bitcount); } else { if (read(xsvf_fd, short_buf, 2) < 0) { do_abort = 1; break; } bitcount = be_to_h_u16(short_buf); LOG_DEBUG("XSIR2 %d", bitcount); } ir_buf = malloc((bitcount + 7) / 8); if (xsvf_read_buffer(bitcount, xsvf_fd, ir_buf) != ERROR_OK) do_abort = 1; else { struct scan_field field; field.num_bits = bitcount; field.out_value = ir_buf; field.in_value = NULL; if (!tap) jtag_add_plain_ir_scan(field.num_bits, field.out_value, field.in_value, my_end_state); else jtag_add_ir_scan(tap, &field, my_end_state); if (xruntest) { if (runtest_requires_tck) jtag_add_clocks(xruntest); else jtag_add_sleep(xruntest); } /* Note that an -irmask of non-zero in your config file * can cause this to fail. Setting -irmask to zero cand work * around the problem. */ /* LOG_DEBUG("FLUSHING QUEUE"); */ result = jtag_execute_queue(); if (result != ERROR_OK) tdo_mismatch = 1; } free(ir_buf); } break; case XCOMMENT: { unsigned int ndx = 0; char comment[128]; do { if (read(xsvf_fd, &uc, 1) < 0) { do_abort = 1; break; } if (ndx < sizeof(comment)-1) comment[ndx++] = uc; } while (uc != 0); comment[sizeof(comment)-1] = 0; /* regardless, terminate */ if (verbose) LOG_USER("# %s", comment); } break; case XWAIT: { /* expected in stream: XWAIT <uint8_t wait_state> <uint8_t end_state> <uint32_t usecs> */ uint8_t wait_local; uint8_t end; uint8_t delay_buf[4]; tap_state_t wait_state; tap_state_t end_state; int delay; if (read(xsvf_fd, &wait_local, 1) < 0 || read(xsvf_fd, &end, 1) < 0 || read(xsvf_fd, delay_buf, 4) < 0) { do_abort = 1; break; } wait_state = xsvf_to_tap(wait_local); end_state = xsvf_to_tap(end); delay = be_to_h_u32(delay_buf); LOG_DEBUG("XWAIT %s %s usecs:%d", tap_state_name( wait_state), tap_state_name(end_state), delay); if (runtest_requires_tck && wait_state == TAP_IDLE) jtag_add_runtest(delay, end_state); else { /* FIXME handle statemove errors ... */ result = svf_add_statemove(wait_state); if (result != ERROR_OK) return result; jtag_add_sleep(delay); result = svf_add_statemove(end_state); if (result != ERROR_OK) return result; } } break; case XWAITSTATE: { /* expected in stream: * XWAITSTATE <uint8_t wait_state> <uint8_t end_state> <uint32_t clock_count> * <uint32_t usecs> */ uint8_t clock_buf[4]; uint8_t usecs_buf[4]; uint8_t wait_local; uint8_t end; tap_state_t wait_state; tap_state_t end_state; int clock_count; int usecs; if (read(xsvf_fd, &wait_local, 1) < 0 || read(xsvf_fd, &end, 1) < 0 || read(xsvf_fd, clock_buf, 4) < 0 || read(xsvf_fd, usecs_buf, 4) < 0) { do_abort = 1; break; } wait_state = xsvf_to_tap(wait_local); end_state = xsvf_to_tap(end); clock_count = be_to_h_u32(clock_buf); usecs = be_to_h_u32(usecs_buf); LOG_DEBUG("XWAITSTATE %s %s clocks:%i usecs:%i", tap_state_name(wait_state), tap_state_name(end_state), clock_count, usecs); /* the following states are 'stable', meaning that they have a transition * in the state diagram back to themselves. This is necessary because we will * be issuing a number of clocks in this state. This set of allowed states is also * determined by the SVF RUNTEST command's allowed states. */ if (!svf_tap_state_is_stable(wait_state)) { LOG_ERROR("illegal XWAITSTATE wait_state: \"%s\"", tap_state_name(wait_state)); unsupported = 1; /* REVISIT "break" so we won't run? */ } /* FIXME handle statemove errors ... */ result = svf_add_statemove(wait_state); if (result != ERROR_OK) return result; jtag_add_clocks(clock_count); jtag_add_sleep(usecs); result = svf_add_statemove(end_state); if (result != ERROR_OK) return result; } break; case LCOUNT: { /* expected in stream: * LCOUNT <uint32_t loop_count> */ uint8_t count_buf[4]; if (read(xsvf_fd, count_buf, 4) < 0) { do_abort = 1; break; } loop_count = be_to_h_u32(count_buf); LOG_DEBUG("LCOUNT %d", loop_count); } break; case LDELAY: { /* expected in stream: * LDELAY <uint8_t wait_state> <uint32_t clock_count> <uint32_t usecs_to_sleep> */ uint8_t state; uint8_t clock_buf[4]; uint8_t usecs_buf[4]; if (read(xsvf_fd, &state, 1) < 0 || read(xsvf_fd, clock_buf, 4) < 0 || read(xsvf_fd, usecs_buf, 4) < 0) { do_abort = 1; break; } /* NOTE: loop_state must be stable! */ loop_state = xsvf_to_tap(state); loop_clocks = be_to_h_u32(clock_buf); loop_usecs = be_to_h_u32(usecs_buf); LOG_DEBUG("LDELAY %s clocks:%d usecs:%d", tap_state_name( loop_state), loop_clocks, loop_usecs); } break; /* LSDR is more like XSDRTDO than it is like XSDR. It uses LDELAY which * comes with clocks !AND! sleep requirements. */ case LSDR: { int limit = loop_count; int matched = 0; int attempt; LOG_DEBUG("LSDR"); if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_out_buf) != ERROR_OK || xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_buf) != ERROR_OK) { do_abort = 1; break; } if (limit < 1) limit = 1; for (attempt = 0; attempt < limit; ++attempt) { struct scan_field field; result = svf_add_statemove(loop_state); if (result != ERROR_OK) { free(dr_in_mask); return result; } jtag_add_clocks(loop_clocks); jtag_add_sleep(loop_usecs); field.num_bits = xsdrsize; field.out_value = dr_out_buf; field.in_value = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); if (attempt > 0 && verbose) LOG_USER("LSDR retry %d", attempt); if (!tap) jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, TAP_DRPAUSE); else jtag_add_dr_scan(tap, 1, &field, TAP_DRPAUSE); jtag_check_value_mask(&field, dr_in_buf, dr_in_mask); free(field.in_value); /* LOG_DEBUG("FLUSHING QUEUE"); */ result = jtag_execute_queue(); if (result == ERROR_OK) { matched = 1; break; } } if (!matched) { LOG_USER("LSDR mismatch"); tdo_mismatch = 1; break; } } break; case XTRST: { uint8_t trst_mode; if (read(xsvf_fd, &trst_mode, 1) < 0) { do_abort = 1; break; } switch (trst_mode) { case XTRST_ON: jtag_add_reset(1, 0); break; case XTRST_OFF: case XTRST_Z: jtag_add_reset(0, 0); break; case XTRST_ABSENT: break; default: LOG_ERROR("XTRST mode argument (0x%02X) out of range", trst_mode); do_abort = 1; } } break; default: LOG_ERROR("unknown xsvf command (0x%02X)", uc); unsupported = 1; } if (do_abort || unsupported || tdo_mismatch) { LOG_DEBUG("xsvf failed, setting taps to reasonable state"); /* upon error, return the TAPs to a reasonable state */ result = svf_add_statemove(TAP_IDLE); if (result != ERROR_OK) return result; result = jtag_execute_queue(); if (result != ERROR_OK) return result; break; } } if (tdo_mismatch) { command_print(CMD, "TDO mismatch, somewhere near offset %lu in xsvf file, aborting", file_offset); return ERROR_FAIL; } if (unsupported) { off_t offset = lseek(xsvf_fd, 0, SEEK_CUR) - 1; command_print(CMD, "unsupported xsvf command (0x%02X) at offset %jd, aborting", uc, (intmax_t)offset); return ERROR_FAIL; } if (do_abort) { command_print(CMD, "premature end of xsvf file detected, aborting"); return ERROR_FAIL; } free(dr_out_buf); free(dr_in_buf); free(dr_in_mask); close(xsvf_fd); command_print(CMD, "XSVF file programmed successfully"); return ERROR_OK; } static const struct command_registration xsvf_command_handlers[] = { { .name = "xsvf", .handler = handle_xsvf_command, .mode = COMMAND_EXEC, .help = "Runs a XSVF file. If 'virt2' is given, xruntest " "counts are interpreted as TCK cycles rather than " "as microseconds. Without the 'quiet' option, all " "comments, retries, and mismatches will be reported.", .usage = "(tapname|'plain') filename ['virt2'] ['quiet']", }, COMMAND_REGISTRATION_DONE }; int xsvf_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, xsvf_command_handlers); } /* PSEUDO-Code from Xilinx Appnote XAPP067.pdf : the following pseudo code clarifies the intent of the xrepeat support.The flow given is for the entire processing of an SVF file, not an XSVF file. No idea if this is just for the XC9500/XL/XV devices or all Xilinx parts. "Pseudo-Code Algorithm for SVF-Based ISP" 1. Go to Test-Logic-Reset state 2. Go to Run-Test Idle state 3. Read SVF record 4. if SIR record then go to Shift-IR state Scan in <TDI value> 5. else if SDR record then set <repeat count> to 0 store <TDI value> as <current TDI value> store <TDO value> as <current TDO value> 6. go to Shift-DR state scan in <current TDI value> if < current TDO value > is specified then if < current TDO value > does not equal <actual TDO value> then if < repeat count > > 32 then LOG ERROR go to Run-Test Idle state go to Step 3 end if go to Pause-DR go to Exit2-DR go to Shift-DR go to Exit1-DR go to Update-DR go to Run-Test/Idle increment <repeat count> by 1 pause <current pause time> microseconds go to Step 6) end if else go to Run-Test Idle state go to Step 3 endif else if RUNTEST record then pause tester for < TCK value > microseconds store <TCK value> as <current pause time> end if */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/src/xsvf/xsvf.h ================================================ /* SPDX-License-Identifier: GPL-2.0-or-later */ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * ***************************************************************************/ #ifndef OPENOCD_XSVF_XSVF_H #define OPENOCD_XSVF_XSVF_H #include <helper/command.h> int xsvf_register_commands(struct command_context *cmd_ctx); #define ERROR_XSVF_EOF (-200) #define ERROR_XSVF_FAILED (-201) #endif /* OPENOCD_XSVF_XSVF_H */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/bitsbytes.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #---------------------------------------- # Purpose - Create some $BIT variables # Create $K and $M variables # and some bit field extraction variables. # Create helper variables ... # BIT0.. BIT31 for { set x 0 } { $x < 32 } { set x [expr {$x + 1}]} { set vn [format "BIT%d" $x] global $vn set $vn [expr {1 << $x}] } # Create K bytes values # __1K ... to __2048K for { set x 1 } { $x < 2048 } { set x [expr {$x * 2}]} { set vn [format "__%dK" $x] global $vn set $vn [expr {1024 * $x}] } # Create M bytes values # __1M ... to __2048K for { set x 1 } { $x < 2048 } { set x [expr {$x * 2}]} { set vn [format "__%dM" $x] global $vn set $vn [expr {1024 * 1024 * $x}] } proc create_mask { MSB LSB } { return [expr {((1 << ($MSB - $LSB + 1))-1) << $LSB}] } # Cut Bits $MSB to $LSB out of this value. # Example: % format "0x%08x" [extract_bitfield 0x12345678 27 16] # Result: 0x02340000 proc extract_bitfield { VALUE MSB LSB } { return [expr {[create_mask $MSB $LSB] & $VALUE}] } # Cut bits $MSB to $LSB out of this value # and shift (normalize) them down to bit 0. # # Example: % format "0x%08x" [normalize_bitfield 0x12345678 27 16] # Result: 0x00000234 # proc normalize_bitfield { VALUE MSB LSB } { return [expr {[extract_bitfield $VALUE $MSB $LSB ] >> $LSB}] } proc show_normalize_bitfield { VALUE MSB LSB } { set m [create_mask $MSB $LSB] set mr [expr {$VALUE & $m}] set sr [expr {$mr >> $LSB}] echo [format "((0x%08x & 0x%08x) -> 0x%08x) >> %2d => (0x%x) %5d " $VALUE $m $mr $LSB $sr $sr] return $sr } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/8devices-lima.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Product page: # https://www.8devices.com/products/lima # # Location of JTAG pins: # J2 GPIO0 JTAG TCK # J2 GPIO1 JTAG TDI # J2 GPIO2 JTAG TDO # J2 GPIO3 JTAG TMS # J2 RST directly connected to RESET_L of the SoC and can be used as # JTAG SRST. Note: this pin will also reset the debug engine. # J1 +3,3V Can be use as JTAG Vref # J1 or J2 GND Can be used for JTAG GND # # This board is powered from mini USB connecter which is also used # as USB to UART converted based on FTDI FT230XQ chip source [find target/qualcomm_qca4531.cfg] proc board_init { } { qca4531_ddr2_550_550_init } $_TARGETNAME configure -event reset-init { board_init } set ram_boot_address 0xa0000000 $_TARGETNAME configure -work-area-phys 0xa1FFE000 -work-area-size 0x1000 flash bank flash0 ath79 0xbf000000 0 0 0 $_TARGETNAME cs0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/actux3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # board config file for AcTux3/XBA IXP42x board # Date: 2010-12-16 # Author: Michael Schwingen <michael@schwingen.org> reset_config trst_and_srst separate adapter srst delay 100 jtag_ntrst_delay 100 source [find target/ixp42x.cfg] $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 0x10000 -work-area-backup 0 $_TARGETNAME configure -event reset-init { init_actux3 } proc init_actux3 { } { ########################################################################## # setup expansion bus CS ########################################################################## mww 0xc4000000 0xbd113842 ;#CS0 : Flash, write enabled @0x50000000 mww 0xc4000004 0x94d10013 ;#CS1 mww 0xc4000008 0x95960003 ;#CS2 mww 0xc400000c 0x00000000 ;#CS3 mww 0xc4000010 0x80900003 ;#CS4 mww 0xc4000014 0x9d520003 ;#CS5 mww 0xc4000018 0x81860001 ;#CS6 mww 0xc400001c 0x80900003 ;#CS7 ixp42x_init_sdram $::IXP42x_SDRAM_16MB_4Mx16_1BANK 2100 3 #mww 0xc4000020 0xffffee ;# CFG0: remove expansion bus boot flash mirror at 0x00000000 ixp42x_set_bigendian flash probe 0 } proc flash_boot { {FILE "/tftpboot/actux3/u-boot.bin"} } { echo "writing bootloader: $FILE" flash write_image erase $FILE 0x50000000 bin } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x50000000 0x400000 2 2 $_TARGETNAME init reset init # setup to debug u-boot in flash proc uboot_debug {} { gdb_breakpoint_override hard xscale vector_catch 0xFF xscale vector_table low 1 0xe59ff018 xscale vector_table low 2 0xe59ff018 xscale vector_table low 3 0xe59ff018 xscale vector_table low 4 0xe59ff018 xscale vector_table low 5 0xe59ff018 xscale vector_table low 6 0xe59ff018 xscale vector_table low 7 0xe59ff018 xscale vector_table high 1 0xe59ff018 xscale vector_table high 2 0xe59ff018 xscale vector_table high 3 0xe59ff018 xscale vector_table high 4 0xe59ff018 xscale vector_table high 5 0xe59ff018 xscale vector_table high 6 0xe59ff018 xscale vector_table high 7 0xe59ff018 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/adapteva_parallella1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Adapteva Parallella-I board (via Porcupine-1 adapter board) # reset_config srst_only source [find target/zynq_7000.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/adsp-sc584-ezbrd.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Analog Devices ADSP-SC584-EZBRD evaluation board # # Evaluation boards by Analog Devices (and designs derived from them) use a # non-standard 10-pin 0.05" ARM Cortex Debug Connector. In this bastardized # implementation, pin 9 (GND or GNDDetect) has been usurped with JTAG /TRST. # # As a result, a standards-compliant debug pod will force /TRST active, # putting the processor's debug interface into reset and preventing usage. # # A connector adapter must be employed on these boards to isolate or remap # /TRST so that it is only asserted when intended. # Analog expects users to use their proprietary ICE-1000 / ICE-2000 with all # ADSP-SC58x designs, but this is an ARM target (and subject to the # qualifications above) many ARM debug pods should be compatible. #source [find interface/cmsis-dap.cfg] source [find interface/jlink.cfg] # Analog's silicon supports SWD and JTAG, but their proprietary ICE is limited # to JTAG. (This is presumably why their connector pinout was modified.) # SWD is chosen here, as it is more efficient and doesn't require /TRST. transport select swd # chosen speed is 'safe' choice, but your adapter may be capable of more adapter speed 400 source [find target/adsp-sc58x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/alphascale_asm9260_ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/alphascale_asm9260t.cfg] reset_config trst_and_srst $_TARGETNAME configure -event reset-init { echo "Configure clock" # Enable SRAM clk mww 0x80040024 0x4 # Enable IRQ clk mww 0x80040034 0x100 # Enable DMA0,1 clk mww 0x80040024 0x600 # Make sysre syspll is enabled mww 0x80040238 0x750 #CPU = PLLCLK/2 mww 0x8004017C 0x2 #SYSAHBCLK = CPUCLK/2 mww 0x80040180 0x2 # Set PLL freq to 480MHz mww 0x80040100 480 # normally we shoul waiting here until we get 0x1 (0x80040104)&0x1)==0x0) sleep 100 # select PLL as main source mww 0x80040120 0x1 # disable and enable main clk to update changes? mww 0x80040124 0x0 mww 0x80040124 0x1 echo "Configure memory" #enable EMI CLK mww 0x80040024 0x40 # configure memory controller for internal SRAM mww 0x80700000 0x1188 # change default emi clk delay mww 0x8004034C 0xA0503 # make sure chip_select_register2_low has correct value (why?) mww 0x8070001c 0x20000000 # set type to sdram and size to 32MB mww 0x8070005c 0xa # configure internal SDRAM timing mww 0x80700004 0x024996d9 # configure Static Memory timing mww 0x80700094 0x00542b4f echo "Configure uart4" # enable pinctrl clk mww 0x80040024 0x2000000 # mux GPIO3_0 and GPIO3_1 to UART4 mww 0x80044060 0x2 mww 0x80044064 0x2 # configure UART4CLKDIV mww 0x800401a8 0x1 # enable uart4 clk mww 0x80040024 0x8000 # clear softrst and clkgate on uart4 mww 0x80010008 0xC0000000 # set bandrate 115200 12M mww 0x80010030 0x00062070 # enable Rx&Tx mww 0x80010024 0x301 # clear hw control mww 0x80010028 0xc000 } $_TARGETNAME configure -work-area-phys 0x21ffe000 -work-area-virt 0xc1ffe000 -work-area-size 0x1000 $_TARGETNAME arm7_9 fast_memory_access enable $_TARGETNAME arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/altera_sockit.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Cyclone V SocKit board # http://www.altera.com/b/arrow-sockit.html # # Software support page: # http://www.rocketboards.org/ # openocd does not currently support the on-board USB Blaster II. # Install the JTAG header and use a USB Blaster instead. adapter driver usb_blaster source [find target/altera_fpgasoc.cfg] # If the USB Blaster II were supported, these settings would be needed #usb_blaster vid_pid 0x09fb 0x6810 #usb_blaster device_desc "USB-Blaster II" adapter speed 100 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/am3517evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # DANGER!!!! early work in progress for this PCB/target. # # The most basic operations work well enough that it is # useful to have this in the repository for cooperation # alpha testing purposes. # # TI AM3517 # # http://focus.ti.com/docs/prod/folders/print/am3517.html # http://processors.wiki.ti.com/index.php/Debug_Access_Port_(DAP) # http://processors.wiki.ti.com/index.php?title=How_to_Find_the_Silicon_Revision_of_your_OMAP35x set CHIPTYPE "am35x" source [find target/amdm37x.cfg] # The TI-14 JTAG connector does not have srst. CPU reset is handled in # hardware. reset_config trst_only # "amdm37x_dbginit am35x.cpu" needs to be run after init. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ampere_emag8180.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # OpenOCD Board Configuration for eMAG Development Platform # # Copyright (c) 2019-2021, Ampere Computing LLC # # # Configure JTAG speed # adapter speed 2000 # # Configure Resets # jtag_ntrst_delay 100 reset_config trst_only # # Configure Targets # source [find target/ampere_emag.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ampere_qs_mq_1s.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # OpenOCD Board Configuration for Ampere Altra ("Quicksilver") and # Ampere Altra Max ("Mystique") processors # # Copyright (c) 2019-2021, Ampere Computing LLC # Argument Description # # JTAGFREQ # Set the JTAG clock frequency # Syntax: -c "set JTAGFREQ {freq_in_khz}" # # SYSNAME # Set the system name # If not specified, defaults to "qs" # Syntax: -c "set SYSNAME {qs}" # # Life-Cycle State (LCS) # If not specified, defaults to "Secure LCS" # LCS=0, "Secure LCS" # LCS=1, "Chip Manufacturing LCS" # Syntax: -c "set LCS {0}" # Syntax: -c "set LCS {1}" # # CORELIST_S0 # Specify available physical cores by number # Example syntax to connect to physical cores 16 and 17 for S0 # Syntax: -c "set CORELIST_S0 {16 17}" # # COREMASK_S0_LO # Specify available physical cores 0-63 by mask # Example syntax to connect to physical cores 16 and 17 for S0 # Syntax: -c "set COREMASK_S0_LO {0x0000000000030000}" # # COREMASK_S0_HI # Specify available physical cores 64 and above by mask # Example syntax to connect to physical cores 94 and 95 for S0 # Syntax: -c "set COREMASK_S0_HI {0x00000000C0000000}" # # PHYS_IDX # Enable OpenOCD ARMv8 core target physical indexing # If not specified, defaults to OpenOCD ARMv8 core target logical indexing # Syntax: -c "set PHYS_IDX {}" # # Configure JTAG speed # if { [info exists JTAGFREQ] } { adapter speed $JTAGFREQ } else { adapter speed 100 } # # Set the system name # if { [info exists SYSNAME] } { set _SYSNAME $SYSNAME } else { set _SYSNAME qs } # # Configure Resets # jtag_ntrst_delay 100 reset_config trst_only # # Configure Targets # if { [info exists CORELIST_S0] || [info exists COREMASK_S0_LO] || [info exists COREMASK_S0_HI] } { set CHIPNAME ${_SYSNAME}0 if { [info exists CORELIST_S0] } { set CORELIST $CORELIST_S0 } else { if { [info exists COREMASK_S0_LO] } { set COREMASK_LO $COREMASK_S0_LO } else { set COREMASK_LO 0x0 } if { [info exists COREMASK_S0_HI] } { set COREMASK_HI $COREMASK_S0_HI } else { set COREMASK_HI 0x0 } } } else { set CHIPNAME ${_SYSNAME}0 set COREMASK_LO 0x1 set COREMASK_HI 0x0 } source [find target/ampere_qs_mq.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ampere_qs_mq_2s.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # OpenOCD Board Configuration for Ampere Altra ("Quicksilver") and # Ampere Altra Max ("Mystique") processors # # Copyright (c) 2019-2021, Ampere Computing LLC # Argument Description # # JTAGFREQ # Set the JTAG clock frequency # Syntax: -c "set JTAGFREQ {freq_in_khz}" # # SYSNAME # Set the system name # If not specified, defaults to "qs" # Syntax: -c "set SYSNAME {qs}" # # Life-Cycle State (LCS) # If not specified, defaults to "Secure LCS" # LCS=0, "Secure LCS" # LCS=1, "Chip Manufacturing LCS" # Syntax: -c "set LCS {0}" # Syntax: -c "set LCS {1}" # # CORELIST_S0, CORELIST_S1 # Specify available physical cores by number # Example syntax to connect to physical cores 16 and 17 for S0 and S1 # Syntax: -c "set CORELIST_S0 {16 17}" # Syntax: -c "set CORELIST_S1 {16 17}" # # COREMASK_S0_LO, COREMASK_S1_LO # Specify available physical cores 0-63 by mask # Example syntax to connect to physical cores 16 and 17 for S0 and S1 # Syntax: -c "set COREMASK_S0_LO {0x0000000000030000}" # Syntax: -c "set COREMASK_S1_LO {0x0000000000030000}" # # COREMASK_S0_HI, COREMASK_S1_HI # Specify available physical cores 64 and above by mask # Example syntax to connect to physical cores 94 and 95 for S0 and S1 # Syntax: -c "set COREMASK_S0_HI {0x00000000C0000000}" # Syntax: -c "set COREMASK_S1_HI {0x00000000C0000000}" # # SPLITSMP # Group all ARMv8 cores per socket into individual SMP sessions # If not specified, group ARMv8 cores from both sockets into one SMP session # Syntax: -c "set SPLITSMP {}" # # PHYS_IDX # Enable OpenOCD ARMv8 core target physical indexing # If not specified, defaults to OpenOCD ARMv8 core target logical indexing # Syntax: -c "set PHYS_IDX {}" # # Configure JTAG speed # if { [info exists JTAGFREQ] } { adapter speed $JTAGFREQ } else { adapter speed 100 } # # Set the system name # if { [info exists SYSNAME] } { set _SYSNAME $SYSNAME } else { set _SYSNAME qs } # # Configure Board level SMP configuration if necessary # if { ![info exists SPLITSMP] } { # Group dual chip into a single SMP configuration set SMP_STR "target smp" set CORE_INDEX_OFFSET 0 set DUAL_SOCKET_SMP_ENABLED "" } # # Configure Resets # jtag_ntrst_delay 100 reset_config trst_only # # Configure Targets # if { [info exists CORELIST_S0] || [info exists COREMASK_S0_LO] || [info exists COREMASK_S0_HI] || \ [info exists CORELIST_S1] || [info exists COREMASK_S1_LO] || [info exists COREMASK_S1_HI] } { set CHIPNAME ${_SYSNAME}1 if { [info exists CORELIST_S1] } { set CORELIST $CORELIST_S1 } else { if { [info exists COREMASK_S1_LO] } { set COREMASK_LO $COREMASK_S1_LO } else { set COREMASK_LO 0x0 } if { [info exists COREMASK_S1_HI] } { set COREMASK_HI $COREMASK_S1_HI } else { set COREMASK_HI 0x0 } } source [find target/ampere_qs_mq.cfg] if { [info exists DUAL_SOCKET_SMP_ENABLED] && [info exists PHYS_IDX]} { if { [info exists MQ_ENABLE] } { set CORE_INDEX_OFFSET 128 } else { set CORE_INDEX_OFFSET 80 } } set CHIPNAME ${_SYSNAME}0 if { [info exists CORELIST_S0] } { set CORELIST $CORELIST_S0 } else { if { [info exists COREMASK_S0_LO] } { set COREMASK_LO $COREMASK_S0_LO } else { set COREMASK_LO 0x0 } if { [info exists COREMASK_S0_HI] } { set COREMASK_HI $COREMASK_S0_HI } else { set COREMASK_HI 0x0 } } source [find target/ampere_qs_mq.cfg] } else { set CHIPNAME ${_SYSNAME}1 set COREMASK_LO 0x0 set COREMASK_HI 0x0 source [find target/ampere_qs_mq.cfg] if { [info exists DUAL_SOCKET_SMP_ENABLED] && [info exists PHYS_IDX]} { if { [info exists MQ_ENABLE] } { set CORE_INDEX_OFFSET 128 } else { set CORE_INDEX_OFFSET 80 } } set CHIPNAME ${_SYSNAME}0 set COREMASK_LO 0x1 set COREMASK_HI 0x0 source [find target/ampere_qs_mq.cfg] } if { [info exists DUAL_SOCKET_SMP_ENABLED] } { # For dual socket SMP configuration, evaluate the string eval $SMP_STR } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/arm_evaluator7t.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This board is from ARM and has an samsung s3c45101x01 chip source [find target/samsung_s3c4510.cfg] # # FIXME: # Add (A) sdram configuration # Add (B) flash cfi programming configuration # ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/arm_musca_a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Configuration script for ARM Musca-A development board # # For now we do not support Musca A flash programming using OpenOCD. However, a # work area is configured for flash programming speed up. # # GDB considers all memory as RAM unless target supplies a memory map. # OpenOCD will only send memory map if flash banks are configured. Otherwise, # configure GDB after connection by issuing following commands: # (gdb) mem 0x10200000 0x109FFFFF ro # (gdb) mem 0x00200000 0x009FFFFF ro # (gdb) set mem inaccessible-by-default off # ARM Musca A board supports both JTAG and SWD transports. source [find target/swj-dp.tcl] # set a safe JTAG clock speed, can be overridden adapter speed 1000 global _CHIPNAME if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME MUSCA_A } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x6ba00477 } # Enable CPU1 debugging as a separate GDB target set _ENABLE_CPU1 1 # Musca A1 has 32KB SRAM banks. Override default work-area-size to 8KB per CPU set WORKAREASIZE_CPU0 0x2000 set WORKAREASIZE_CPU1 0x2000 # Set SRAM bank 1 to be used for work area. Override here if needed. set WORKAREAADDR_CPU0 0x30008000 set WORKAREAADDR_CPU1 0x3000A000 source [find target/arm_corelink_sse200.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/arty_s7.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Arty S7: Spartan7 25/50 FPGA Board for Makers and Hobbyists # # https://www.xilinx.com/products/boards-and-kits/1-pnziih.html # https://store.digilentinc.com/arty-s7-spartan-7-fpga-board-for-makers-and-hobbyists/ source [find interface/ftdi/digilent-hs1.cfg] # Xilinx Spartan7-25/50 FPGA (XC7S{25,50}-CSGA324) source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] adapter speed 25000 # Usage: # # Load Bitstream into FPGA: # openocd -f board/arty_s7.cfg -c "init;\ # pld load 0 bitstream.bit;\ # shutdown" # # Write Bitstream to Flash: # openocd -f board/arty_s7.cfg -c "init;\ # jtagspi_init 0 bscan_spi_xc7s??.bit;\ # jtagspi_program bitstream.bin 0;\ # xc7_program xc7.tap;\ # shutdown" # # jtagspi flash proxies can be found at: # https://github.com/quartiq/bscan_spi_bitstreams # # For the Spartan 50 variant, use # - https://github.com/quartiq/bscan_spi_bitstreams/raw/master/bscan_spi_xc7s50.bit # For the Spartan 25 variant, use # - https://github.com/quartiq/bscan_spi_bitstreams/raw/master/bscan_spi_xc7s25.bit ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/asus-rt-n16.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # http://wikidevi.com/wiki/ASUS_RT-N16 # set partition_list { CFE { Bootloader 0xbc000000 0x00040000 } firmware { "Kernel+rootfs" 0xbc040000 0x01fa0000 } nvram { "Config space" 0xbdfe0000 0x00020000 } } source [find target/bcm4718.cfg] # External 32MB NOR Flash (Macronix MX29GL256EHTI2I-90Q) set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0xbc000000 0x02000000 1 1 $_TARGETNAME x16_as_x8 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/asus-rt-n66u.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # http://wikidevi.com/wiki/Asus_RT-N66U # echo "ATTENTION: you need to solder a 4.7-10k pullup resistor to pin 21 of flash IC" echo "to enable JTAG, see http://wl500g.info/album.php?albumid=28&attachmentid=8991 ," echo "there is an unpopulated footprint near U8.\n" set partition_list { CFE { Bootloader 0xbc000000 0x00040000 } firmware { "Kernel+rootfs" 0xbc040000 0x01fa0000 } nvram { "Config space" 0xbdfe0000 0x00020000 } } source [find target/bcm4706.cfg] # External 32MB NOR Flash (Spansion S29GL256P10TF101 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0xbc000000 0x02000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/at91cap7a-stk-sdram.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4394 # # use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cap7 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x40700f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-start { # start off real slow when we're running off internal RC oscillator adapter speed 32 } proc peek32 {address} { return [read_memory $address 32 1] } # Wait for an expression to be true with a timeout proc wait_state {expression} { for {set i 0} {$i < 1000} {set i [expr {$i + 1}]} { if {[uplevel 1 $expression] == 0} { return } } return -code 1 "Timed out" } # Use a global variable here to be able to tinker interactively with # post reset jtag frequency. global post_reset_khz # Danger!!!! Even 16MHz kinda works with this target, but # it needs to be as low as 2000kHz to be stable. set post_reset_khz 2000 $_TARGETNAME configure -event reset-init { echo "Configuring master clock" # disable watchdog mww 0xfffffd44 0xff008000 # enable user reset mww 0xfffffd08 0xa5000001 # Enable main oscillator mww 0xFFFFFc20 0x00000f01 wait_state {expr {([peek32 0xFFFFFC68] & 0x1) == 0}} # Set PLLA to 96MHz mww 0xFFFFFc28 0x20072801 wait_state {expr {([peek32 0xFFFFFC68] & 0x2) == 0}} # Select prescaler mww 0xFFFFFC30 0x00000004 wait_state {expr {([peek32 0xFFFFFC68] & 0x8) == 0}} # Select master clock to 48MHz mww 0xFFFFFC30 0x00000006 wait_state {expr {([peek32 0xFFFFFC68] & 0x8) == 0}} echo "Master clock ok." # Now that we're up and running, crank up speed! global post_reset_khz ; adapter speed $post_reset_khz echo "Configuring the SDRAM controller..." # Configure EBI Chip select for SDRAM mww 0xFFFFEF30 0x00000102 # Enable clock on EBI PIOs mww 0xFFFFFC10 0x00000004 # Configure PIO for SDRAM mww 0xFFFFF470 0xFFFF0000 mww 0xFFFFF474 0x00000000 mww 0xFFFFF404 0xFFFF0000 # Configure SDRAMC CR mww 0xFFFFEA08 0xA63392F9 # NOP command mww 0xFFFFEA00 0x1 mww 0x20000000 0 # Precharge All Banks command mww 0xFFFFEA00 0x2 mww 0x20000000 0 # Set 1st CBR mww 0xFFFFEA00 0x00000004 mww 0x20000010 0x00000001 # Set 2nd CBR mww 0xFFFFEA00 0x00000004 mww 0x20000020 0x00000002 # Set 3rd CBR mww 0xFFFFEA00 0x00000004 mww 0x20000030 0x00000003 # Set 4th CBR mww 0xFFFFEA00 0x00000004 mww 0x20000040 0x00000004 # Set 5th CBR mww 0xFFFFEA00 0x00000004 mww 0x20000050 0x00000005 # Set 6th CBR mww 0xFFFFEA00 0x00000004 mww 0x20000060 0x00000006 # Set 7th CBR mww 0xFFFFEA00 0x00000004 mww 0x20000070 0x00000007 # Set 8th CBR mww 0xFFFFEA00 0x00000004 mww 0x20000080 0x00000008 # Set LMR operation mww 0xFFFFEA00 0x00000003 # Perform LMR burst=1, lat=2 mww 0x20000020 0xCAFEDEDE # Set Refresh Timer mww 0xFFFFEA04 0x00000203 # Set Normal mode mww 0xFFFFEA00 0x00000000 mww 0x20000000 0x00000000 #remap internal memory at address 0x0 mww 0xffffef00 0x3 echo "SDRAM configuration ok." } $_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup 0 arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable #set _FLASHNAME $_CHIPNAME.flash #flash bank $_FLASHNAME at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 0 18432 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/at91eb40a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #Script for AT91EB40a # FIXME use some standard target config, maybe create one from this # # source [find target/...cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91eb40a } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x1f0f0f0f } #Atmel ties SRST & TRST together, at which point it makes #no sense to use TRST, but use TMS instead. # #The annoying thing with tying SRST & TRST together is that #there is no way to halt the CPU *before and during* the #SRST reset, which means that the CPU will run a number #of cycles before it can be halted(as much as milliseconds). reset_config srst_only srst_pulls_trst #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID #target configuration set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME # speed up memory downloads arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable #flash driver set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x01000000 0x200000 2 2 $_TARGETNAME # required for usable performance. Used for lots of # other things than flash programming. $_TARGETNAME configure -work-area-phys 0x00030000 -work-area-size 0x10000 -work-area-backup 0 $_TARGETNAME configure -event reset-init { echo "Running reset init script for AT91EB40A" # Reset script for AT91EB40a reg cpsr 0x000000D3 mww 0xFFE00020 0x1 mww 0xFFE00024 0x00000000 mww 0xFFE00000 0x01002539 mww 0xFFFFF124 0xFFFFFFFF mww 0xffff0010 0x100 mww 0xffff0034 0x100 } # This target is pretty snappy... adapter speed 16000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/at91rm9200-dk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # This is for the "at91rm9200-DK" (not the EK) eval board. # # The two are probably very simular.... I have DK... # # It has atmel at91rm9200 chip. source [find target/at91rm9200.cfg] reset_config trst_and_srst $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { at91rm9200_dk_init } #flash bank <name> <driver> <base> <size> <chip_width> <bus_width> <target> set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x10000000 0x00200000 2 2 $_TARGETNAME proc at91rm9200_dk_init { } { # Try to run at 1khz... Yea, that slow! # Chip is really running @ 32khz adapter speed 8 mww 0xfffffc64 0xffffffff ## disable all clocks but system clock mww 0xfffffc04 0xfffffffe ## disable all clocks to pioa and piob mww 0xfffffc14 0xffffffc3 ## master clock = slow cpu = slow ## (means the CPU is running at 32khz!) mww 0xfffffc30 0 ## main osc enable mww 0xfffffc20 0x0000ff01 ## program pllA mww 0xfffffc28 0x20263e04 ## program pllB mww 0xfffffc2c 0x10483e0e ## let pll settle... sleep 100msec sleep 100 ## switch to fast clock mww 0xfffffc30 0x202 ## Sleep some - (go read) sleep 100 #======================================== # CPU now runs at 180mhz # SYS runs at 60mhz. adapter speed 40000 #======================================== ## set memc for all memories mww 0xffffff60 0x02 ## program smc controller mww 0xffffff70 0x3284 ## init sdram mww 0xffffff98 0x7fffffd0 ## all banks precharge mww 0xffffff80 0x02 ## touch sdram chip to make it work mww 0x20000000 0 ## sdram controller mode register mww 0xffffff90 0x04 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 ## sdram controller mode register ## Refresh, etc.... mww 0xffffff90 0x03 mww 0x20000080 0 mww 0xffffff94 0x1f4 mww 0x20000080 0 mww 0xffffff90 0x10 mww 0x20000000 0 mww 0xffffff00 0x01 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/at91rm9200-ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Copyright 2010 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> # # under GPLv2 Only # # This is for the "at91rm9200-ek" eval board. # # # It has atmel at91rm9200 chip. source [find target/at91rm9200.cfg] reset_config trst_and_srst $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { at91rm9200_ek_init } ## flash bank <name> <driver> <base> <size> <chip_width> <bus_width> <target> set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x10000000 0x00800000 2 2 $_TARGETNAME # The chip may run @ 32khz, so set a really low JTAG speed adapter speed 8 proc at91rm9200_ek_init { } { # Try to run at 1khz... Yea, that slow! # Chip is really running @ 32khz adapter speed 8 mww 0xfffffc64 0xffffffff ## disable all clocks but system clock mww 0xfffffc04 0xfffffffe ## disable all clocks to pioa and piob mww 0xfffffc14 0xffffffc3 ## master clock = slow cpu = slow ## (means the CPU is running at 32khz!) mww 0xfffffc30 0 ## main osc enable mww 0xfffffc20 0x0000ff01 ## MC_PUP mww 0xFFFFFF50 0x00000000 ## MC_PUER: Memory controller protection unit disable mww 0xFFFFFF54 0x00000000 ## EBI_CFGR mww 0xFFFFFF64 0x00000000 ## SMC2_CSR[0]: 16bit, 2 TDF, 4 WS mww 0xFFFFFF70 0x00003284 ## Init Clocks ## CKGR_PLLAR mww 0xFFFFFC28 0x2000BF05 ## PLLAR: 179,712000 MHz for PCK mww 0xFFFFFC28 0x20263E04 sleep 100 ## PMC_MCKR mww 0xFFFFFC30 0x00000100 sleep 100 ## ;MCKR : PCK/3 = MCK Master Clock = 59,904000MHz from PLLA mww 0xFFFFFC30 0x00000202 sleep 100 #======================================== # CPU now runs at 180mhz # SYS runs at 60mhz. adapter speed 40000 #======================================== ## Init SDRAM ## PIOC_ASR: Configure PIOC as peripheral (D16/D31) mww 0xFFFFF870 0xFFFF0000 ## PIOC_BSR: mww 0xFFFFF874 0x00000000 ## PIOC_PDR: mww 0xFFFFF804 0xFFFF0000 ## EBI_CSA : CS1=SDRAM mww 0xFFFFFF60 0x00000002 ## EBI_CFGR: mww 0xFFFFFF64 0x00000000 ## SDRC_CR : mww 0xFFFFFF98 0x2188c155 ## SDRC_MR : Precharge All mww 0xFFFFFF90 0x00000002 ## access SDRAM mww 0x20000000 0x00000000 ## SDRC_MR : Refresh mww 0xFFFFFF90 0x00000004 ## access SDRAM mww 0x20000000 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 ## SDRC_MR : Load Mode Register mww 0xFFFFFF90 0x00000003 ## access SDRAM mww 0x20000080 0x00000000 ## SDRC_TR : Write refresh rate mww 0xFFFFFF94 0x000002E0 ## access SDRAM mww 0x20000000 0x00000000 ## SDRC_MR : Normal Mode mww 0xFFFFFF90 0x00000000 ## access SDRAM mww 0x20000000 0x00000000 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/at91sam9261-ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################ # Atmel AT91SAM9261-EK eval board ################################################################################ source [find mem_helper.tcl] source [find target/at91sam9261.cfg] uplevel #0 [list source [find chip/atmel/at91/hardware.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91sam9261.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91sam9261_matrix.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91sam9_init.cfg]] # By default S1 is open and this means that NTRST is not connected. # The reset_config in target/at91sam9261.cfg is overridden here. # (or S1 must be populated with a 0 Ohm resistor) reset_config srst_only scan_chain $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { at91sam9261ek_reset_init } $_TARGETNAME configure -event reset-start { at91sam9_reset_start } proc at91sam9261ek_reset_init { } { ;# for ppla at 199 Mhz set config(master_pll_div) 15 set config(master_pll_mul) 162 ;# for ppla at 239 Mhz ;# set master_pll_div 1 ;# set master_pll_mul 13 set val $::AT91_WDT_WDV ;# Counter Value set val [expr {$val | $::AT91_WDT_WDDIS}] ;# Watchdog Disable set val [expr {$val | $::AT91_WDT_WDD}] ;# Delta Value set val [expr {$val | $::AT91_WDT_WDDBGHLT}] ;# Debug Halt set val [expr {$val | $::AT91_WDT_WDIDLEHLT}] ;# Idle Halt set config(wdt_mr_val) $val ;# EBI_CSA, no pull-ups for D[15:0], CS1 SDRAM, CS3 NAND Flash set config(matrix_ebicsa_addr) $::AT91_MATRIX_EBICSA set config(matrix_ebicsa_val) [expr {$::AT91_MATRIX_DBPUC | $::AT91_MATRIX_CS1A_SDRAMC}] ;# SDRAMC_CR - Configuration register set val $::AT91_SDRAMC_NC_9 set val [expr {$val | $::AT91_SDRAMC_NR_13}] set val [expr {$val | $::AT91_SDRAMC_NB_4}] set val [expr {$val | $::AT91_SDRAMC_CAS_3}] set val [expr {$val | $::AT91_SDRAMC_DBW_32}] set val [expr {$val | (2 << 8)}] ;# Write Recovery Delay set val [expr {$val | (7 << 12)}] ;# Row Cycle Delay set val [expr {$val | (3 << 16)}] ;# Row Precharge Delay set val [expr {$val | (2 << 20)}] ;# Row to Column Delay set val [expr {$val | (5 << 24)}] ;# Active to Precharge Delay set val [expr {$val | (8 << 28)}] ;# Exit Self Refresh to Active Delay set config(sdram_cr_val) $val set config(sdram_tr_val) 0x13c set config(sdram_base) $::AT91_CHIPSELECT_1 at91sam9_reset_init $config } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/at91sam9263-ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################ # Atmel AT91SAM9263-EK eval board ################################################################################ source [find mem_helper.tcl] source [find target/at91sam9263.cfg] uplevel #0 [list source [find chip/atmel/at91/hardware.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91sam9263.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91sam9263_matrix.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91sam9_init.cfg]] # By default S1 is open and this means that NTRST is not connected. # The reset_config in target/at91sam9263.cfg is overridden here. # (or S1 must be populated with a 0 Ohm resistor) reset_config srst_only scan_chain $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { at91sam9263ek_reset_init } $_TARGETNAME configure -event reset-start { at91sam9_reset_start } proc at91sam9263ek_reset_init { } { set config(master_pll_div) 14 set config(master_pll_mul) 171 set val $::AT91_WDT_WDV ;# Counter Value set val [expr {$val | $::AT91_WDT_WDDIS}] ;# Watchdog Disable set val [expr {$val | $::AT91_WDT_WDD}] ;# Delta Value set val [expr {$val | $::AT91_WDT_WDDBGHLT}] ;# Debug Halt set val [expr {$val | $::AT91_WDT_WDIDLEHLT}] ;# Idle Halt set config(wdt_mr_val) $val set config(sdram_piod) 1 ;# EBI_CSA, no pull-ups for D[15:0], CS1 SDRAM, CS3 NAND Flash set config(matrix_ebicsa_addr) $::AT91_MATRIX_EBI0CSA set val $::AT91_MATRIX_EBI0_DBPUC set val [expr {$val | $::AT91_MATRIX_EBI0_VDDIOMSEL_3_3V}] set val [expr {$val | $::AT91_MATRIX_EBI0_CS1A_SDRAMC}] set config(matrix_ebicsa_val) $val ;# SDRAMC_CR - Configuration register set val $::AT91_SDRAMC_NC_9 set val [expr {$val | $::AT91_SDRAMC_NR_13}] set val [expr {$val | $::AT91_SDRAMC_NB_4}] set val [expr {$val | $::AT91_SDRAMC_CAS_3}] set val [expr {$val | $::AT91_SDRAMC_DBW_32}] set val [expr {$val | (1 << 8)}] ;# Write Recovery Delay set val [expr {$val | (7 << 12)}] ;# Row Cycle Delay set val [expr {$val | (2 << 16)}] ;# Row Precharge Delay set val [expr {$val | (2 << 20)}] ;# Row to Column Delay set val [expr {$val | (5 << 24)}] ;# Active to Precharge Delay set val [expr {$val | (1 << 28)}] ;# Exit Self Refresh to Active Delay set config(sdram_cr_val) $val set config(sdram_tr_val) 0x13c set config(sdram_base) $::AT91_CHIPSELECT_1 at91sam9_reset_init $config } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/at91sam9g20-ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################################# # # # Author: Gary Carlson (gcarlson@carlson-minot.com) # # Generated for Atmel AT91SAM9G20-EK evaluation board using Atmel SAM-ICE (J-Link) version 8. # # # ################################################################################################# source [find target/at91sam9g20.cfg] set _FLASHTYPE nandflash_cs3 # Set reset type. Note that the AT91SAM9G20-EK board has the trst signal disconnected. Therefore # the reset needs to be configured for "srst_only". If for some reason, a zero-ohm jumper is # added to the board to connect the trst signal, then this parameter may need to be changed. reset_config srst_only adapter srst delay 200 jtag_ntrst_delay 200 # If you don't want to execute built-in boot rom code (and there are good reasons at times not to do that) in the # AT91SAM9 family, the microcontroller is a lump on a log without initialization. Because this family has # some powerful features, we want to have a special function that handles "reset init". To do this we declare # an event handler where these special activities can take place. scan_chain $_TARGETNAME configure -event reset-init {at91sam9g20_reset_init} $_TARGETNAME configure -event reset-start {at91sam9g20_reset_start} # NandFlash configuration and definition nand device nandflash_cs3 at91sam9 $_TARGETNAME 0x40000000 0xfffffe800 at91sam9 cle 0 22 at91sam9 ale 0 21 at91sam9 rdy_busy 0 0xfffff800 13 at91sam9 ce 0 0xfffff800 14 proc read_register {register} { return [read_memory $register 32 1] } proc at91sam9g20_reset_start { } { # Make sure that the the jtag is running slow, since there are a number of different ways the board # can be configured coming into this state that can cause communication problems with the jtag # adapter. Also since this call can be made following a "reset init" where fast memory accesses # are enabled, need to temporarily shut this down so that the RSTC_MR register can be written at slower # jtag speed without causing GDB keep alive problem. arm7_9 fast_memory_access disable adapter speed 2 ;# Slow-speed oscillator enabled at reset, so run jtag speed slow. halt ;# Make sure processor is halted, or error will result in following steps. wait_halt 10000 mww 0xfffffd08 0xa5000501 ;# RSTC_MR : enable user reset. } proc at91sam9g20_reset_init { } { # At reset AT91SAM9G20 chip runs on slow clock (32.768 kHz). To shift over to a normal clock requires # a number of steps that must be carefully performed. The process outline below follows the # recommended procedure outlined in the AT91SAM9G20 technical manual. # # Several key and very important things to keep in mind: # The SDRAM parts used currently on the Atmel evaluation board are -75 grade parts. This # means the master clock (MCLK) must be at or below 133 MHz or timing errors will occur. The processor # core can operate up to 400 MHz and therefore PCLK must be at or below this to function properly. mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog. # Enable the main 18.432 MHz oscillator in CKGR_MOR register. # Wait for MOSCS in PMC_SR to assert indicating oscillator is again stable after change to CKGR_MOR. mww 0xfffffc20 0x00004001 while { [expr {[read_register 0xfffffc68] & 0x01}] != 1 } { sleep 1 } # Set PLLA Register for 792.576 MHz (divider: bypass, multiplier: 43). # Wait for LOCKA signal in PMC_SR to assert indicating PLLA is stable. mww 0xfffffc28 0x202a3f01 while { [expr {[read_register 0xfffffc68] & 0x02}] != 2 } { sleep 1 } # Set master system clock prescaler divide by 6 and processor clock divide by 2 in PMC_MCKR. # Wait for MCKRDY signal from PMC_SR to assert. mww 0xfffffc30 0x00000101 while { [expr {[read_register 0xfffffc68] & 0x08}] != 8 } { sleep 1 } # Now change PMC_MCKR register to select PLLA. # Wait for MCKRDY signal from PMC_SR to assert. mww 0xfffffc30 0x00001302 while { [expr {[read_register 0xfffffc68] & 0x08}] != 8 } { sleep 1 } # Processor and master clocks are now operating and stable at maximum frequency possible: # -> MCLK = 132.096 MHz # -> PCLK = 396.288 MHz # Switch over to adaptive clocking. adapter speed 0 # Enable faster DCC downloads and memory accesses. arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable # To be able to use external SDRAM, several peripheral configuration registers must # be modified. The first change is made to PIO_ASR to select peripheral functions # for D15 through D31. The second change is made to the PIO_PDR register to disable # this for D15 through D31. mww 0xfffff870 0xffff0000 mww 0xfffff804 0xffff0000 # The EBI chip select register EBI_CS must be specifically configured to enable the internal SDRAM controller # using CS1. Additionally we want CS3 assigned to NandFlash. Also VDDIO is connected physically on # the board to the 3.3 VDC power supply so set the appropriate register bit to notify the micrcontroller. mww 0xffffef1c 0x000100a # The AT91SAM9G20-EK evaluation board has built-in NandFlash. The exact physical timing characteristics # for the memory type used on the current board (MT29F2G08AACWP) can be established by setting # a number of registers. The first step involves setting up the general I/O pins on the processor # to be able to interface and support the external memory. mww 0xfffffc10 0x00000010 ;# PMC_PCER : enable PIOC clock mww 0xfffff800 0x00006000 ;# PIOC_PER : enable PIO function for 13(RDY/~BSY) and 14(~CS) mww 0xfffff810 0x00004000 ;# PIOC_OER : enable output on 14 mww 0xfffff814 0x00002000 ;# PIOC_ODR : disable output on 13 mww 0xfffff830 0x00004000 ;# PIOC_SODR : set 14 to disable NAND # The exact physical timing characteristics for the memory type used on the current board # (MT29F2G08AACWP) can be established by setting four registers in order: SMC_SETUP3, # SMC_PULSE3, SMC_CYCLE3, and SMC_MODE3. Computing the exact values of these registers # is a little tedious to do here. If you have questions about how to do this, Atmel has # a decent application note #6255B that covers this process. mww 0xffffec30 0x00020002 ;# SMC_SETUP3 : 2 clock cycle setup for NRD and NWE mww 0xffffec34 0x04040404 ;# SMC_PULSE3 : 4 clock cycle pulse for all signals mww 0xffffec38 0x00070006 ;# SMC_CYCLE3 : 7 clock cycle NRD and 6 NWE cycle mww 0xffffec3C 0x00020003 ;# SMC_MODE3 : NRD and NWE control, no NWAIT, 8-bit DBW, mww 0xffffe800 0x00000001 ;# ECC_CR : reset the ECC parity registers mww 0xffffe804 0x00000002 ;# ECC_MR : page size is 2112 words (word is 8 bits) # Identify NandFlash bank 0. nand probe nandflash_cs3 # The AT91SAM9G20-EK evaluation board has built-in serial data flash also. # Now setup SDRAM. This is tricky and configuration is very important for reliability! The current calculations # are based on 2 x Micron MT48LC16M16A2-75 memory (4 M x 16 bit x 4 banks). If you use this file as a reference # for a new board that uses different SDRAM devices or clock rates, you need to recalculate the value inserted # into the SDRAM_CR register. Using the memory datasheet for the -75 grade part and assuming a master clock # of 132.096 MHz then the SDCLK period is equal to 7.6 ns. This means the device requires: # # CAS latency = 3 cycles # TXSR = 10 cycles # TRAS = 6 cycles # TRCD = 3 cycles # TRP = 3 cycles # TRC = 9 cycles # TWR = 2 cycles # 9 column, 13 row, 4 banks # refresh equal to or less then 7.8 us for commercial/industrial rated devices # # Thus SDRAM_CR = 0xa6339279 mww 0xffffea08 0xa6339279 # Next issue a 'NOP' command through the SDRAMC_MR register followed by writing a zero value into # the starting memory location for the SDRAM. mww 0xffffea00 0x00000001 mww 0x20000000 0 # Issue an 'All Banks Precharge' command through the SDRAMC_MR register followed by writing a zero # value into the starting memory location for the SDRAM. mww 0xffffea00 0x00000002 mww 0x20000000 0 # Now issue an 'Auto-Refresh' command through the SDRAMC_MR register. Follow this operation by writing # zero values eight times into the starting memory location for the SDRAM. mww 0xffffea00 0x4 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 # Almost done, so next issue a 'Load Mode Register' command followed by a zero value write to the # the starting memory location for the SDRAM. mww 0xffffea00 0x3 mww 0x20000000 0 # Signal normal mode using the SDRAMC_MR register and follow with a zero value write the the starting # memory location for the SDRAM. mww 0xffffea00 0x0 mww 0x20000000 0 # Finally set the refresh rate to about every 7 us (7.5 ns x 924 cycles). mww 0xffffea04 0x0000039c } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_at91sam7s-ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Atmel AT91SAM7S-EK # http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3784 set CHIPNAME at91sam7s256 source [find target/at91sam7sx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_at91sam9260-ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################ # Atmel AT91SAM9260-EK eval board # # http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3933 # # Atmel AT91SAM9260 : PLLA = 198.656 MHz, MCK = 99.328 MHz # OSCSEL configured for external 32.768 kHz crystal # # 32-bit SDRAM : 2 x Micron MT48LC16M16A2, 4M x 16Bit x 4 Banks # ################################################################################ # We add to the minimal configuration. source [find target/at91sam9260.cfg] # By default S1 is open and this means that NTRST is not connected. # The reset_config in target/at91sam9260.cfg is overridden here. # (or S1 must be populated with a 0 Ohm resistor) reset_config srst_only $_TARGETNAME configure -event reset-start { # At reset CPU runs at 32.768 kHz. # JTAG Frequency must be 6 times slower if RCLK is not supported. jtag_rclk 5 halt # RSTC_MR : enable user reset, MMU may be enabled... use physical address mww phys 0xfffffd08 0xa5000501 } $_TARGETNAME configure -event reset-init { mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog mww 0xfffffc20 0x00004001 ;# CKGR_MOR : enable the main oscillator sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000001 ;# PMC_MCKR : switch to main oscillator sleep 10 ;# wait 10 ms mww 0xfffffc28 0x2060bf09 ;# CKGR_PLLAR: Set PLLA Register for 198.656 MHz sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000101 ;# PMC_MCKR : Select prescaler (divide by 2) sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000102 ;# PMC_MCKR : Clock from PLLA is selected (99.328 MHz) sleep 10 ;# wait 10 ms # Increase JTAG Speed to 6 MHz if RCLK is not supported jtag_rclk 6000 arm7_9 dcc_downloads enable ;# Enable faster DCC downloads mww 0xfffff870 0xffff0000 ;# PIO_ASR : Select peripheral function for D15..D31 mww 0xfffff804 0xffff0000 ;# PIO_PDR : Disable PIO function for D15..D31 mww 0xffffef1c 0x00010002 ;# EBI_CSA : Assign EBI Chip Select 1 to SDRAM, VDDIOMSEL set for +3V3 memory mww 0xffffea08 0x85227259 ;# SDRAMC_CR : Configure SDRAM (2 x Micron MT48LC16M16A2 : 4M x 16Bit x 4 Banks) mww 0xffffea00 0x1 ;# SDRAMC_MR : issue a NOP command mww 0x20000000 0 mww 0xffffea00 0x2 ;# SDRAMC_MR : issue an 'All Banks Precharge' command mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue 8 x 'Auto-Refresh' Command mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x3 ;# SDRAMC_MR : issue a 'Load Mode Register' command mww 0x20000000 0 mww 0xffffea00 0x0 ;# SDRAMC_MR : normal mode mww 0x20000000 0 mww 0xffffea04 0x2b6 ;# SDRAMC_TR : Set refresh timer count to 7us } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_at91sam9rl-ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################ # # Generated for Atmel AT91SAM9RL-EK evaluation board using Atmel SAM-ICE (J-Link) V6 # # Atmel AT91SAM9RL : PLL = 200 MHz, MCK = 100 MHz # OSCSEL configured for external 32.768 kHz crystal # # 32-bit SDRAM : 2 x Micron MT48LC16M16A2, 4M x 16Bit x 4 Banks # ################################################################################ # We add to the minimal configuration. source [find target/at91sam9rl.cfg] $_TARGETNAME configure -event reset-start { # At reset CPU runs at 32.768 kHz. # JTAG Frequency must be 6 times slower if RCLK is not supported. jtag_rclk 5 halt # RSTC_MR : enable user reset, MMU may be enabled... use physical address mww phys 0xfffffd08 0xa5000501 } $_TARGETNAME configure -event reset-init { mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog mww 0xfffffc20 0x00004001 ;# CKGR_MOR : enable the main oscillator sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000001 ;# PMC_MCKR : switch to main oscillator sleep 10 ;# wait 10 ms mww 0xfffffc28 0x2031bf03 ;# CKGR_PLLR: Set PLL Register for 200 MHz sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000101 ;# PMC_MCKR : Select prescaler (divide by 2) sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000102 ;# PMC_MCKR : Clock from PLL is selected (100 MHz) sleep 10 ;# wait 10 ms # Increase JTAG Speed to 6 MHz if RCLK is not supported jtag_rclk 6000 arm7_9 dcc_downloads enable ;# Enable faster DCC downloads mww 0xfffff670 0xffff0000 ;# PIO_ASR : Select peripheral function for D16..D31 (PIOB) mww 0xfffff604 0xffff0000 ;# PIO_PDR : Disable PIO function for D16..D31 (PIOB) mww 0xffffef20 0x00010002 ;# EBI_CSA : Assign EBI Chip Select 1 to SDRAM, VDDIOMSEL set for +3V3 memory mww 0xffffea08 0x85227259 ;# SDRAMC_CR : Configure SDRAM (2 x Micron MT48LC16M16A2 : 4M x 16Bit x 4 Banks) mww 0xffffea00 0x1 ;# SDRAMC_MR : issue a NOP command mww 0x20000000 0 mww 0xffffea00 0x2 ;# SDRAMC_MR : issue an 'All Banks Precharge' command mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue 8 x 'Auto-Refresh' Command mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x3 ;# SDRAMC_MR : issue a 'Load Mode Register' command mww 0x20000000 0 mww 0xffffea00 0x0 ;# SDRAMC_MR : normal mode mww 0x20000000 0 mww 0xffffea04 0x2b6 ;# SDRAMC_TR : Set refresh timer count to 7us } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_sam3n_ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Board configuration for Atmel's SAM3N-EK # reset_config srst_only set CHIPNAME at91sam3n4c adapter speed 32 source [find target/at91sam3nXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_sam3s_ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/at91sam3sXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_sam3u_ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/at91sam3u4e.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_sam3x_ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/at91sam3ax_8x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_sam4e_ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an SAM4E-EK board with a single SAM4E16 chip. # http://www.atmel.com/tools/sam4e-ek.aspx # chip name set CHIPNAME SAM4E16E source [find target/at91sam4sXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_sam4l8_xplained_pro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Atmel SAM4L8 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAM4L8-XPRO.aspx # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME ATSAM4LC8CA source [find target/at91sam4lXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_sam4s_ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/at91sam4sXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_sam4s_xplained_pro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Atmel SAM4S Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAM4S-XPRO.aspx # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME ATSAM4SD32C source [find target/at91sam4sd32x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_samc20_xplained_pro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Atmel SAMC20 Xplained Pro evaluation kit. # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91samc20j18 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_samc21_xplained_pro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Atmel SAMC21 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAMC21-XPRO.aspx # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91samc21j18 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_samd10_xplained_mini.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Atmel SAMD10 Xplained mini evaluation kit. # http://www.atmel.com/tools/atsamd10-xmini.aspx source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91samd10d14 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_samd11_xplained_pro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Atmel SAMD11 Xplained Pro evaluation kit. # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91samd11d14 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_samd20_xplained_pro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Atmel SAMD20 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAMD20-XPRO.aspx # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91samd20j18 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_samd21_xplained_pro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Atmel SAMD21 Xplained Pro evaluation kit. # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91samd21j18 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_same70_xplained.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Atmel SAME70 Xplained evaluation kit. # http://www.atmel.com/tools/ATSAME70-XPLD.aspx # # Connect using the EDBG chip on the dev kit over USB source [find interface/cmsis-dap.cfg] set CHIPNAME atsame70q21 source [find target/atsamv.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_samg53_xplained_pro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Atmel SAMG53 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAMG53-XPRO.aspx # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME ATSAMG53N19 source [find target/at91samg5x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_samg55_xplained_pro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Atmel SAMG55 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAMG55-XPRO.aspx # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME ATSAMG55J19 source [find target/at91samg5x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_saml21_xplained_pro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Atmel SAML21 Xplained Pro evaluation kit. # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91saml21j18 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_samr21_xplained_pro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Atmel SAMR21 Xplained Pro evaluation kit. # source [find interface/cmsis-dap.cfg] # chip name set CHIPNAME at91samr21g18 source [find target/at91samdXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/atmel_samv71_xplained_ultra.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Atmel SAMV71 Xplained Ultra evaluation kit. # http://www.atmel.com/tools/ATSAMV71-XULT.aspx # # To connect using the EDBG chip on the dev kit over USB, you will # first need to source [find interface/cmsis-dap.cfg] # however, since this board also has a SWD+ETM connector, we don't # automatically source that file here. set CHIPNAME samv71 source [find target/atsamv.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/avnet_ultrazed-eg.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # AVNET UltraZED EG StarterKit # ZynqMP UlraScale-EG plus IO Carrier with on-board digilent smt2 # source [find interface/ftdi/digilent_jtag_smt2_nc.cfg] # jtag transport only transport select jtag # reset lines are not wired reset_config none # slow default clock adapter speed 1000 set CHIPNAME uscale source [find target/xilinx_zynqmp.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/balloon3-cpu.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Config for balloon3 board, cpu JTAG port. http://balloonboard.org/ # The board has separate JTAG ports for cpu and CPLD/FPGA devices # Chaining is done on IO interfaces if desired. source [find target/pxa270.cfg] # The board supports separate reset lines # Override this in the interface config for parallel dongles reset_config trst_and_srst separate # flash bank <name> <driver> <base> <size> <chip_width> <bus_width> <target> # 29LV650 64Mbit Flash set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x800000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/bcm28155_ap.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # BCM28155_AP adapter speed 20000 set CHIPNAME bcm28155 source [find target/bcm281xx.cfg] reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/bemicro_cycloneiii.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # BeMicro Cyclone III adapter driver ftdi ftdi channel 0 ftdi layout_init 0x0008 0x008b ftdi vid_pid 0x0403 0xa4a0 reset_config none transport select jtag adapter speed 10000 source [find fpga/altera-cycloneiii.cfg] #quartus_cpf --option=bitstream_compression=off -c output_files\cycloneiii_blinker.sof cycloneiii_blinker.rbf #openocd -f board/bemicro_cycloneiii.cfg -c "init" -c "pld load 0 cycloneiii_blinker.rbf" # "ipdbg -start -tap cycloneiii.tap -hub 0x00e -tool 0 -port 5555" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/bluefield.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Board configuration for BlueField SoC. # source [find interface/rshim.cfg] source [find target/bluefield.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/bt-homehubv1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # BT HomeHub v1 # set partition_list { CFE { Bootloader 0xbe400000 0x00020000 } firmware { "Kernel+rootfs" 0xbe420000 0x007d0000 } fisdir { "FIS Directory" 0xbebf0000 0x0000f000 } nvram { "Config space" 0xbebff000 0x00001000 } } source [find target/bcm6348.cfg] set _FLASHNAME $_CHIPNAME.norflash flash bank $_FLASHNAME cfi 0xbe400000 0x00800000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/calao-usb-a9260.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # CALAO Systems USB-A9260 (C01 and C02) adapter driver ftdi ftdi device_desc "USB-A9260" ftdi vid_pid 0x0403 0x6001 0x0403 0x6010 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 transport select jtag source [find target/at91sam9260.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/calao-usb-a9g20-c01.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # CALAO Systems USB-A9G20-C01 # Authors: Gregory Hermant, Jean-Christophe PLAGNIOL-VILLARD, Wolfram Sang adapter driver ftdi ftdi device_desc "USB-A9G20" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 transport select jtag source [find target/at91sam9g20.cfg] source [find mem_helper.tcl] proc at91sam9g20_reset_start { } { # Make sure that the jtag is running slow, since there are a number of different ways the board # can be configured coming into this state that can cause communication problems with the jtag # adapter. Also since this call can be made following a "reset init" where fast memory accesses # are enabled, Need to temporarily shut this down so that the RSTC_MR register can be written at slower # jtag speed without causing GDB keep alive problem. arm7_9 fast_memory_access disable adapter speed 2 ;# Slow-speed oscillator enabled at reset, so run jtag speed slow. halt 0 ;# Make sure processor is halted, or error will result in following steps. wait_halt 10000 # RSTC_MR : enable user reset, MMU may be enabled... use physical address mww phys 0xfffffd08 0xa5000501 } proc at91sam9g20_reset_init { } { # At reset AT91SAM9G20 chip runs on slow clock (32.768 kHz). To shift over to a normal clock requires # a number of steps that must be carefully performed. The process outline below follows the # recommended procedure outlined in the AT91SAM9G20 technical manual. # # Several key and very important things to keep in mind: # The SDRAM parts used currently on the Atmel evaluation board are -75 grade parts. This # means the master clock (MCLK) must be at or below 133 MHz or timing errors will occur. The processor # core can operate up to 400 MHz and therefore PCLK must be at or below this to function properly. mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog. # Set oscillator bypass bit (12.00 MHz external oscillator) in CKGR_MOR register. mww 0xfffffc20 0x00000002 # Set PLLA Register for 798.000 MHz (divider: bypass, multiplier: 132). # Wait for LOCKA signal in PMC_SR to assert indicating PLLA is stable. mww 0xfffffc28 0x20843F02 while { [expr { [mrw 0xfffffc68] & 0x02 } ] != 2 } { sleep 1 } # Set master system clock prescaler divide by 6 and processor clock divide by 2 in PMC_MCKR. # Wait for MCKRDY signal from PMC_SR to assert. mww 0xfffffc30 0x00001300 while { [expr { [mrw 0xfffffc68] & 0x08 } ] != 8 } { sleep 1 } # Now change PMC_MCKR register to select PLLA. # Wait for MCKRDY signal from PMC_SR to assert. mww 0xfffffc30 0x00001302 while { [expr { [mrw 0xfffffc68] & 0x08 } ] != 8 } { sleep 1 } # Processor and master clocks are now operating and stable at maximum frequency possible: # -> MCLK = 133.000 MHz # -> PCLK = 400.000 MHz # Switch to fast JTAG speed adapter speed 9500 # Enable faster DCC downloads. arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable # To be able to use external SDRAM, several peripheral configuration registers must # be modified. The first change is made to PIO_ASR to select peripheral functions # for D15 through D31. The second change is made to the PIO_PDR register to disable # this for D15 through D31. mww 0xfffff870 0xffff0000 mww 0xfffff804 0xffff0000 # The EBI chip select register EBI_CS must be specifically configured to enable the internal SDRAM controller # using CS1. Additionally we want CS3 assigned to NandFlash. Also VDDIO is connected physically on # the board to the 1.8V VDC power supply so set the appropriate register bit to notify the micrcontroller. mww 0xffffef1c 0x000000a # The USB-A9G20 Embedded computer has built-in NandFlash. The exact physical timing characteristics # for the memory type used on the current board (MT29F2G08AACWP) can be established by setting # four registers in order: SMC_SETUP3, SMC_PULSE3, SMC_CYCLE3, and SMC_MODE3. mww 0xffffec30 0x00020002 mww 0xffffec34 0x04040404 mww 0xffffec38 0x00070007 mww 0xffffec3c 0x00030003 # Now setup SDRAM. This is tricky and configuration is very important for reliability! The current calculations # are based on 2 x Micron LPSDRAM MT48H16M16LFBF-75 memory (4 M x 16 bit x 4 banks). If you use this file as a reference # for a new board that uses different SDRAM devices or clock rates, you need to recalculate the value inserted # into the SDRAM_CR register. Using the memory datasheet for the -75 grade part and assuming a master clock # of 133.000 MHz then the SDCLK period is equal to 7.6 ns. This means the device requires: # # CAS latency = 3 cycles # TXSR = 10 cycles # TRAS = 6 cycles # TRCD = 3 cycles # TRP = 3 cycles # TRC = 9 cycles # TWR = 2 cycles # 9 column, 13 row, 4 banks # refresh equal to or less then 7.8 us for commercial/industrial rated devices # # Thus SDRAM_CR = 0xa6339279 mww 0xffffea08 0xa6339279 # Memory Device Type: SDRAM (low-power would be 0x1) mww 0xffffea24 0x00000000 # Next issue a 'NOP' command through the SDRAMC_MR register followed by writing a zero value into # the starting memory location for the SDRAM. mww 0xffffea00 0x00000001 mww 0x20000000 0 # Issue an 'All Banks Precharge' command through the SDRAMC_MR register followed by writing a zero # value into the starting memory location for the SDRAM. mww 0xffffea00 0x00000002 mww 0x20000000 0 # Now issue an 'Auto-Refresh' command through the SDRAMC_MR register. Follow this operation by writing # zero values eight times into the starting memory location for the SDRAM. mww 0xffffea00 0x4 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 # Almost done, so next issue a 'Load Mode Register' command followed by a zero value write to the # the starting memory location for the SDRAM. mww 0xffffea00 0x3 mww 0x20000000 0 # Signal normal mode using the SDRAMC_MR register and follow with a zero value write the starting # memory location for the SDRAM. mww 0xffffea00 0x0 mww 0x20000000 0 # Finally set the refresh rate to about every 7 us (7.5 ns x 924 cycles). mww 0xffffea04 0x0000039c } $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-start {at91sam9g20_reset_start} $_TARGETNAME configure -event reset-init {at91sam9g20_reset_init} ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/certuspro_evaluation.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # https://www.latticesemi.com/products/developmentboardsandkits/certuspro-nx-versa-board adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi channel 0 ftdi layout_init 0x0008 0x008b reset_config none transport select jtag adapter speed 10000 source [find fpga/lattice_certuspro.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/colibri.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Toradex Colibri PXA270 source [find target/pxa270.cfg] reset_config trst_and_srst srst_push_pull adapter srst pulse_width 40 # CS0 -- one bank of CFI flash, 32 MBytes # the bank is 32-bits wide, two 16-bit chips in parallel set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/crossbow_tech_imote2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Crossbow Technology iMote2 set CHIPNAME imote2 source [find target/pxa270.cfg] # longer-than-normal reset delay adapter srst delay 800 reset_config trst_and_srst separate # works for P30 flash set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x2000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/csb337.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cogent CSB337 # http://cogcomp.com/csb_csb337.htm source [find target/at91rm9200.cfg] # boots from NOR on CS0: 8 MBytes CFI flash, 16-bit bus set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x10000000 0x00800000 2 2 $_TARGETNAME # ETM9 trace port connector present on this board, 16 data pins. if { [info exists ETM_DRIVER] } { etm config $_TARGETNAME 16 normal half $ETM_DRIVER # OpenOCD may someday support a real trace port driver... # system config file would need to configure it. } else { etm config $_TARGETNAME 16 normal half dummy etm_dummy config $_TARGETNAME } proc csb337_clk_init { } { # CPU is in Slow Clock Mode (32KiHz) ... needs slow JTAG clock adapter speed 8 # CKGR_MOR: start main oscillator (3.6864 MHz) mww 0xfffffc20 0xff01 sleep 10 # CKGR_PLLAR: start PLL A for CPU and peripherals (184.32 MHz) mww 0xfffffc28 0x20313e01 # CKGR_PLLBR: start PLL B for USB timing (96 MHz, with div2) mww 0xfffffc2c 0x12703e18 # let PLLs lock sleep 10 # PMC_MCKR: switch to CPU clock = PLLA, master clock = CPU/4 mww 0xfffffc30 0x0302 sleep 20 # CPU is in Normal Mode ... allows faster JTAG clock speed adapter speed 40000 } proc csb337_nor_init { } { # SMC_CSR0: adjust timings (10 wait states) mww 0xffffff70 0x1100318a flash probe 0 } proc csb337_sdram_init { } { # enable PIOC clock mww 0xfffffc10 0x0010 # PC31..PC16 are D31..D16, with internal pullups like D15..D0 mww 0xfffff870 0xffff0000 mww 0xfffff874 0x0 mww 0xfffff804 0xffff0000 # SDRC_CR: set timings mww 0xffffff98 0x2188b0d5 # SDRC_MR: issue all banks precharge to SDRAM mww 0xffffff90 2 mww 0x20000000 0 # SDRC_MR: 8 autorefresh cycles mww 0xffffff90 4 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 mww 0x20000000 0 # SDRC_MR: set SDRAM mode registers (CAS, burst len, etc) mww 0xffffff90 3 mww 0x20000080 0 # SDRC_TR: set refresh rate mww 0xffffff94 0x200 mww 0x20000000 0 # SDRC_MR: normal mode, 32 bit bus mww 0xffffff90 0 mww 0x20000000 0 } # The rm9200 chip has just been reset. Bring it up far enough # that we can write flash or run code from SDRAM. proc csb337_reset_init { } { csb337_clk_init # EBI_CSA: CS0 = NOR, CS1 = SDRAM mww 0xffffff60 0x02 csb337_nor_init csb337_sdram_init # Update CP15 control register ... we don't seem to be able to # read/modify/write its value through a TCL variable, so just # write it. Fields are zero unless listed here ... and note # that OpenOCD numbers this register "2", not "1" (!). # # - Core to use Async Clocking mode (so it uses 184 MHz most # of the time instead of limiting to the master clock rate): # iA(31) = 1, nF(30) = 1 # - Icache on (it's disabled now, slowing i-fetches) # I(12) = 1 # - Reserved/ones # 6:3 = 1 arm920t cp15 2 0xc0001078 } $_TARGETNAME configure -event reset-init {csb337_reset_init} arm7_9 fast_memory_access enable ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/csb732.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The Cogent CSB732 board has a single i.MX35 chip source [find target/imx35.cfg] # Determined by trial and error reset_config trst_and_srst combined adapter srst delay 200 jtag_ntrst_delay 200 $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { csb732_init } # Bare-bones initialization of core clocks and SDRAM proc csb732_init { } { # Disable fast writing only for init memwrite burst disable # All delay loops are omitted. # We assume the interpreter latency is enough. # Allow access to all coprocessors arm mcr 15 0 15 1 0 0x2001 # Disable MMU, caches, write buffer arm mcr 15 0 1 0 0 0x78 # Grant manager access to all domains arm mcr 15 0 3 0 0 0xFFFFFFFF # Set ARM clock to 532 MHz, AHB to 133 MHz mww 0x53F80004 0x1000 # Set core clock to 2 * 24 MHz * (11 + 1/12) = 532 MHz mww 0x53F8001C 0xB2C01 set ESDMISC 0xB8001010 set ESDCFG0 0xB8001004 set ESDCTL0 0xB8001000 # Enable DDR mww $ESDMISC 0x4 # Timing mww $ESDCFG0 0x007fff3f # CS0 mww $ESDCTL0 0x92120080 # Precharge all dummy write mww 0x80000400 0 # Enable CS) auto-refresh mww $ESDCTL0 0xA2120080 # Refresh twice (dummy writes) mww 0x80000000 0 mww 0x80000000 0 # Enable CS0 load mode register mww $ESDCTL0 0xB2120080 # Dummy writes mwb 0x80000033 0x01 mwb 0x81000000 0x01 mww $ESDCTL0 0x82226080 mww 0x80000000 0 # Re-enable fast writing memwrite burst enable } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/da850evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #DA850 EVM board # http://focus.ti.com/dsp/docs/thirdparty/catalog/devtoolsproductfolder.tsp?actionPerformed=productFolder&productId=5939 # http://www.logicpd.com/products/development-kits/zoom-omap-l138-evm-development-kit source [find target/omapl138.cfg] reset_config trst_and_srst separate #currently any pinmux/timing must be setup by UBL before openocd can do debug #TODO: implement pinmux/timing on reset like in board/dm365evm.cfg ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/digi_connectcore_wi-9c.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: DIGI ConnectCore Wi-9C ###################################### reset_config trst_and_srst # FIXME use some standard target config, maybe create one from this # # source [find target/...cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ns9360 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # This config file was defaulting to big endian.. set _ENDIAN big } # What's a good fallback frequency for this board if RCLK is # not available?? jtag_rclk 1000 if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926031 } set _TARGETNAME $_CHIPNAME.cpu jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID adapter srst delay 200 jtag_ntrst_delay 0 ###################### # Target configuration ###################### target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-init { mww 0x90600104 0x33313333 mww 0xA0700000 0x00000001 ;# Enable the memory controller. mww 0xA0700024 0x00000006 ;# Set the refresh counter 6 mww 0xA0700028 0x00000001 ;# mww 0xA0700030 0x00000001 ;# Set the precharge period mww 0xA0700034 0x00000004 ;# Active to precharge command period is 16 clock cycles mww 0xA070003C 0x00000001 ;# tAPR mww 0xA0700040 0x00000005 ;# tDAL mww 0xA0700044 0x00000001 ;# tWR mww 0xA0700048 0x00000006 ;# tRC 32 clock cycles mww 0xA070004C 0x00000006 ;# tRFC 32 clock cycles mww 0xA0700054 0x00000001 ;# tRRD mww 0xA0700058 0x00000001 ;# tMRD mww 0xA0700100 0x00004280 ;# Dynamic Config 0 (cs4) mww 0xA0700120 0x00004280 ;# Dynamic Config 1 (cs5) mww 0xA0700140 0x00004280 ;# Dynamic Config 2 (cs6) mww 0xA0700160 0x00004280 ;# Dynamic Config 3 (cs7) # mww 0xA0700104 0x00000203 ;# CAS latency is 2 at 100 MHz mww 0xA0700124 0x00000203 ;# CAS latency is 2 at 100 MHz mww 0xA0700144 0x00000203 ;# CAS latency is 2 at 100 MHz mww 0xA0700164 0x00000203 ;# CAS latency is 2 at 100 MHz # mww 0xA0700020 0x00000103 ;# issue SDRAM PALL command # mww 0xA0700024 0x00000001 ;# Set the refresh counter to be as small as possible # # Add some dummy writes to give the SDRAM time to settle, it needs two # AHB clock cycles, here we poke in the debugger flag, this lets # the software know that we are in the debugger mww 0xA0900000 0x00000002 mww 0xA0900000 0x00000002 mww 0xA0900000 0x00000002 mww 0xA0900000 0x00000002 mww 0xA0900000 0x00000002 # mdw 0xA0900000 mdw 0xA0900000 mdw 0xA0900000 mdw 0xA0900000 mdw 0xA0900000 # mww 0xA0700024 0x00000030 ;# Set the refresh counter to 30 mww 0xA0700020 0x00000083 ;# Issue SDRAM MODE command # # Next we perform a read of RAM. # mw = move word. mdw 0x00022000 # mw 0x00022000:P, r3 # 22000 for cas2 latency, 32000 for cas 3 # mww 0xA0700020 0x00000003 ;# issue SDRAM NORMAL command mww 0xA0700100 0x00084280 ;# Enable buffer access mww 0xA0700120 0x00084280 ;# Enable buffer access mww 0xA0700140 0x00084280 ;# Enable buffer access mww 0xA0700160 0x00084280 ;# Enable buffer access #Set byte lane state (static mem 1)" mww 0xA0700220 0x00000082 #Flash Start mww 0xA09001F8 0x50000000 #Flash Mask Reg mww 0xA09001FC 0xFF000001 mww 0xA0700028 0x00000001 # RAMAddr = 0x00020000 # RAMSize = 0x00004000 # Set the processor mode reg cpsr 0xd3 } $_TARGETNAME configure -work-area-phys 0x00000000 -work-area-size 0x1000 -work-area-backup 1 ##################### # Flash configuration ##################### #M29DW323DB - not working #flash bank <name> cfi <base> <size> <chip width> <bus width> <target> set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x50000000 0x0400000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/digilent_analog_discovery.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Digilent Analog Discovery # # http://www.digilentinc.com/Products/Detail.cfm?NavPath=2,842,1018&Prod=ANALOG-DISCOVERY # # Config is based on data from # https://github.com/bvanheu/urjtag-ad/commit/8bd883ee01d134f94b79cbbd00df42cd03bafd71 # adapter driver ftdi ftdi device_desc "Digilent USB Device" ftdi vid_pid 0x0403 0x6014 ftdi layout_init 0x8008 0x800b adapter speed 25000 source [find cpld/xilinx-xc6s.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/digilent_atlys.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # http://digilentinc.com/atlys/ # # The Digilent Atlys normally requires proprietary tools to program and will # enumerate as: # ID 1443:0007 Digilent Development board JTAG # # However, the ixo-usb-jtag project provides an alternative open firmware for # the on board programmer. When using this firmware the board will then # enumerate as: # ID 16c0:06ad Van Ooijen Technische Informatica # (With SerialNumber == hw_nexys) # # See the interface/usb-jtag.cfg for more information. source [find interface/usb-jtag.cfg] source [find cpld/xilinx-xc6s.cfg] source [find cpld/jtagspi.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/digilent_nexys_video.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Digilent Nexys Video with Xilinx Artix-7 FPGA # https://reference.digilentinc.com/programmable-logic/nexys-video/start adapter driver ftdi adapter speed 30000 ftdi device_desc "Digilent USB Device" ftdi vid_pid 0x0403 0x6010 # channel 0 is dedicated for Digilent's DPTI Interface # channel 1 is used for JTAG ftdi channel 1 # just TCK TDI TDO TMS, no reset ftdi layout_init 0x0088 0x008b reset_config none # Enable sampling on falling edge for high JTAG speeds. ftdi tdo_sample_edge falling transport select jtag source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/digilent_zedboard.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Digilent Zedboard Rev.C, Rev.D with Xilinx Zynq chip # # http://zedboard.com/product/zedboard # source [find interface/ftdi/digilent_jtag_smt2.cfg] reset_config srst_only srst_push_pull source [find target/zynq_7000.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/diolan_lpc4350-db1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Diolan LPC-4350-DB1 development board # set CHIPNAME lpc4350 source [find target/lpc4350.cfg] flash bank $_CHIPNAME.nor cfi 0x1C000000 0x00200000 2 2 $_CHIPNAME.m4 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/diolan_lpc4357-db1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Diolan LPC-4357-DB1 development board # set CHIPNAME lpc4357 source [find target/lpc4357.cfg] flash bank $_CHIPNAME.nor cfi 0x1C000000 0x00200000 2 2 $_CHIPNAME.m4 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/dk-tm4c129.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later echo "WARNING: board/dk-tm4c129.cfg is deprecated, please switch to board/ti_dk-tm4c129.cfg" source [find board/ti_dk-tm4c129.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/dm355evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # DM355 EVM board # http://focus.ti.com/docs/toolsw/folders/print/tmdsevm355.html # http://c6000.spectrumdigital.com/evmdm355/ source [find target/ti_dm355.cfg] reset_config trst_and_srst separate # NOTE: disable or replace this call to dm355evm_init if you're # debugging new UBL code from SRAM. $_TARGETNAME configure -event reset-init { dm355evm_init } # # This post-reset init is called when the MMU isn't active, all IRQs # are disabled, etc. It should do most of what a UBL does, except for # loading code (like U-Boot) into DRAM and running it. # proc dm355evm_init {} { global dm355 echo "Initialize DM355 EVM board" # CLKIN = 24 MHz ... can't talk quickly to ARM yet jtag_rclk 1500 ######################## # PLL1 = 432 MHz (/8, x144) # ...SYSCLK1 = 216 MHz (/2) ... ARM, MJCP # ...SYSCLK2 = 108 MHz (/4) ... Peripherals # ...SYSCLK3 = 27 MHz (/16) ... VPBE, DAC # ...SYSCLK4 = 108 MHz (/4) ... VPSS # pll1.{prediv,div1,div2} are fixed # pll1.postdiv set in MISC (for *this* speed grade) set addr [dict get $dm355 pllc1] set pll_divs [dict create] dict set pll_divs div3 16 dict set pll_divs div4 4 pll_v02_setup $addr 144 $pll_divs # ARM is now running at 216 MHz, so JTAG can go faster jtag_rclk 20000 ######################## # PLL2 = 342 MHz (/8, x114) # ....SYSCLK1 = 342 MHz (/1) ... DDR PHY at 171 MHz, 2x clock # pll2.{postdiv,div1} are fixed set addr [dict get $dm355 pllc2] set pll_divs [dict create] dict set pll_divs div1 1 dict set pll_divs prediv 8 pll_v02_setup $addr 114 $pll_divs ######################## # PINMUX # All Video Inputs davinci_pinmux $dm355 0 0x00007f55 # All Video Outputs davinci_pinmux $dm355 1 0x00145555 # EMIFA (NOTE: more could be set up for use as GPIOs) davinci_pinmux $dm355 2 0x00000c08 # SPI0, SPI1, UART1, I2C, SD0, SD1, McBSP0, CLKOUTs davinci_pinmux $dm355 3 0x1bff55ff # MMC/SD0 instead of MS; SPI0 davinci_pinmux $dm355 4 0x00000000 ######################## # PSC setup (minimal) # DDR EMIF/13, AEMIF/14, UART0/19 psc_enable 13 psc_enable 14 psc_enable 19 psc_go ######################## # DDR2 EMIF # VTPIOCR impedance calibration set addr [dict get $dm355 sysbase] set addr [expr {$addr + 0x70}] # clear CLR, LOCK, PWRDN; wait a clock; set CLR mmw $addr 0 0x20c0 mmw $addr 0x2000 0 # wait for READY while { [expr {[mrw $addr] & 0x8000}] == 0 } { sleep 1 } # set IO_READY; then LOCK and PWRSAVE; then PWRDN mmw $addr 0x4000 0 mmw $addr 0x0180 0 mmw $addr 0x0040 0 # NOTE: this DDR2 initialization sequence borrows from # both UBL 1.50 and the SPRUEH7D DDR2 EMIF spec. # reset (then re-enable) DDR controller psc_reset 13 psc_go psc_enable 13 psc_go # now set it up for Micron MT47H64M16HR-37E @ 171 MHz set addr [dict get $dm355 ddr_emif] # DDRPHYCR1 mww [expr {$addr + 0xe4}] 0x50006404 # PBBPR -- burst priority mww [expr {$addr + 0x20}] 0xfe # SDCR -- unlock boot config; init for DDR2, relock, unlock SDTIM* mmw [expr {$addr + 0x08}] 0x00800000 0 mmw [expr {$addr + 0x08}] 0x0013c632 0x03870fff # SDTIMR0, SDTIMR1 mww [expr {$addr + 0x10}] 0x2a923249 mww [expr {$addr + 0x14}] 0x4c17c763 # SDCR -- relock SDTIM* mmw [expr {$addr + 0x08}] 0 0x00008000 # SDRCR -- refresh rate (171 MHz * 7.8usec) mww [expr {$addr + 0x0c}] 1336 ######################## # ASYNC EMIF set addr [dict get $dm355 a_emif] # slow/pessimistic timings set nand_timings 0x40400204 # fast (25% faster page reads) #set nand_timings 0x0400008c # AWCCR mww [expr {$addr + 0x04}] 0xff # CS0 == socketed NAND (default MT29F16G08FAA, 2GByte) mww [expr {$addr + 0x10}] $nand_timings # CS1 == dm9000 Ethernet mww [expr {$addr + 0x14}] 0x00a00505 # NANDFCR -- only CS0 has NAND mww [expr {$addr + 0x60}] 0x01 # default: both chipselects to the NAND socket are used nand probe 0 nand probe 1 ######################## # UART0 set addr [dict get $dm355 uart0] # PWREMU_MGNT -- rx + tx in reset mww [expr {$addr + 0x30}] 0 # DLL, DLH -- 115200 baud mwb [expr {$addr + 0x20}] 0x0d mwb [expr {$addr + 0x24}] 0x00 # FCR - clear and disable FIFOs mwb [expr {$addr + 0x08}] 0x07 mwb [expr {$addr + 0x08}] 0x00 # IER - disable IRQs mwb [expr {$addr + 0x04}] 0x00 # LCR - 8-N-1 mwb [expr {$addr + 0x0c}] 0x03 # MCR - no flow control or loopback mwb [expr {$addr + 0x10}] 0x00 # PWREMU_MGNT -- rx + tx normal, free running during JTAG halt mww [expr {$addr + 0x30}] 0xe001 ######################## # turn on icache - set I bit in cp15 register c1 arm mcr 15 0 0 1 0 0x00051078 } # NAND -- socket has two chipselects, MT29F16G08FAA puts 1GByte on each one. # # NOTE: "hwecc4" here presumes that if you're using the standard 2GB NAND # you either (a) have 'new' DM355 chips, with boot ROMs that don't need to # use "hwecc4_infix" for the UBL; or else (b) aren't updating anything that # needs infix layout ... like an old UBL, old U-Boot, old MVL kernel, etc. set _FLASHNAME $_CHIPNAME.boot nand device $_FLASHNAME davinci $_TARGETNAME 0x02000000 hwecc4 0x01e10000 set _FLASHNAME $_CHIPNAME.flash nand device $_FLASHNAME davinci $_TARGETNAME 0x02004000 hwecc4 0x01e10000 # FIXME # - support writing UBL with its header (new layout only with new ROMs) # - support writing ABL/U-Boot with its header (new layout) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/dm365evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # DM365 EVM board -- Beta # http://focus.ti.com/docs/toolsw/folders/print/tmdxevm365.html # http://support.spectrumdigital.com/boards/evmdm365 source [find target/ti_dm365.cfg] # NOTE: in Rev C boards, the CPLD ignores SRST from the ARM-20 JTAG # connector, so it doesn't affect generation of the reset signal. # Accordingly, resets require something else. ICEpick could do it; # but its docs aren't generally available. # # At this writing, newer boards aren't available ... so assume no SRST. # Also ICEpick docs aren't available ... so we must use watchdog reset, # and hope the CPU isn't wedged or in a WFI loop (either of which can # block access to CPU and thus watchdog registers). reset_config trst_only $_TARGETNAME configure -event reset-assert "davinci_wdog_reset" # SW5.1 routes CS0: NAND vs OneNAND. # SW4.6:4 controls AEMIF width (8 for NAND, 16 for OneNand) # for boot-from-flash, those must agree with SW4.3:1 settings. if { [info exists CS0MODE] } { # NAND or OneNAND set CS0 $CS0MODE } else { set CS0 "" echo "WARNING: CS0 configuration not known" proc cs0_setup {a_emif} {} proc flashprobe {} {} } set a_emif [dict get $dm365 a_emif] # As shipped: boot from NAND. if { $CS0 == "NAND" } { echo "CS0 NAND" # NAND socket has two chipselects. Default MT29F16G08FAA chip # has 1GByte on each one. # NOTE: "hwecc4" here presumes that you're not updating anything # that needs infix layout (e.g. UBL, old U-Boot, etc) nand device low davinci $_TARGETNAME 0x02000000 hwecc4 $a_emif nand device high davinci $_TARGETNAME 0x02004000 hwecc4 $a_emif proc cs0_setup {a_emif} { global dm365 # 8 bit EMIF davinci_pinmux $dm365 2 0x00000016 # slow/pessimistic timings set nand_timings 0x40400204 # fast (25% faster page reads) #set nand_timings 0x0400008c # CS0 == socketed NAND (default MT29F16G08FAA, 2 GBytes) mww [expr {$a_emif + 0x10}] $nand_timings # NANDFCR -- CS0 has NAND mww [expr {$a_emif + 0x60}] 0x01 } proc flashprobe {} { nand probe 0 nand probe 1 } } elseif { $CS0 == "OneNAND" } { echo "CS0 OneNAND" # No support for this OneNAND in OpenOCD (yet) or Linux ... # REVISIT OneNAND timings not verified to work! echo "WARNING -- OneNAND not yet tested!" proc cs0_setup {a_emif} { global dm365 # 16 bit EMIF davinci_pinmux $dm365 2 0x00000055 # CS0 == OneNAND (KFG1G16U2B-DIB6, 128 KBytes) mww [expr {$a_emif + 0x10}] 0x00000001 # ONENANDCTRL -- CS0 has OneNAND, enable sync reads mww [expr {$a_emif + 0x5c}] 0x0441 } proc flashprobe {} { } } # NOTE: disable or replace this call to dm365evm_init if you're # debugging new UBL/NANDboot code from SRAM. $_TARGETNAME configure -event reset-init { dm365evm_init } # # This post-reset init is called when the MMU isn't active, all IRQs # are disabled, etc. It should do most of what a UBL does, except for # loading code (like U-Boot) into DRAM and running it. # proc dm365evm_init {} { global dm365 echo "Initialize DM365 EVM board" # CLKIN = 24 MHz ... can't talk quickly to ARM yet adapter speed 1500 # FIXME -- PLL init ######################## # PINMUX setup davinci_pinmux $dm365 0 0x00fd0000 davinci_pinmux $dm365 1 0x00145555 # mux2 controls AEMIF ... 8 bit for NAND, 16 for OneNand davinci_pinmux $dm365 3 0x375affff davinci_pinmux $dm365 4 0x55556555 ######################## # PSC setup (minimal) # DDR EMIF/13, AEMIF/14, UART0/19 psc_enable 13 psc_enable 14 psc_enable 19 psc_go # FIXME setup DDR2 (needs PLL) ######################## # ASYNC EMIF set a_emif [dict get $dm365 a_emif] # AWCCR mww [expr {$a_emif + 0x04}] 0xff # CS0 == NAND or OneNAND cs0_setup $a_emif # CS1 == CPLD mww [expr {$a_emif + 0x14}] 0x00a00505 # FIXME setup UART0 flashprobe } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/dm6446evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # DM6446 EVM board # http://focus.ti.com/docs/toolsw/folders/print/tmdsevm6446.html # http://c6000.spectrumdigital.com/davincievm/ # EVM is just the board; buy that at Spectrum. # The "kit" from TI also has: video camera, LCD video monitor, more. source [find target/ti_dm6446.cfg] # J4 controls what CS2 hooks up to, usually NOR or NAND flash. # S3.1/S3.2 controls boot mode, which may force J4 and S3.3 settings. # S3.3 controls AEMIF bus width. if { [info exists J4_OPTION] } { # NOR, NAND, SRAM, ... set CS2_MODE $J4_OPTION } else { set CS2_MODE "" } # ARM boot: # S3.1 = 0, S3.2 = 0 ==> ROM/UBL boot via NAND (J4 == NAND) # S3.1 = 1, S3.2 = 0 ==> AEMIF boot (J4 == NOR or SRAM) # S3.1 = 0, S3.2 = 1 ==> ROM/UBL boot via HPI # S3.1 = 1, S3.2 = 1 ==> ROM/UBL boot via UART (J4 == don't care) # AEMIF bus width: # S3.3 = 0 ==> 8 bit bus width # S3.3 = 1 ==> 16 bit bus width # DSP boot: # S3.4 = 0 ==> controlled by ARM if { $CS2_MODE == "NOR" } { # 16 Mbytes address space; 16 bit bus width # (older boards used 32MB parts, with upper 16 MB unusable) set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x02000000 0x01000000 2 2 $_TARGETNAME proc flashprobe {} { flash probe 0 } } elseif { $CS2_MODE == "NAND" } { # 64 Mbyte small page; 8 bit bus width nand device davinci $_TARGETNAME 0x02000000 hwecc1 0x01e00000 proc flashprobe {} { nand probe 0 } } elseif { $CS2_MODE == "SRAM" } { # 4 Mbyte address space; 16 bit bus width # loaded via JTAG or HPI proc flashprobe {} {} } else { # maybe it's HPI boot? can't tell... echo "WARNING: CS2/flash configuration not recognized" proc flashprobe {} {} } # NOTE: disable or replace this call to dm6446evm_init if you're # debugging new UBL code from SRAM (for NAND boot). $_TARGETNAME configure -event reset-init { dm6446evm_init } # # This post-reset init is called when the MMU isn't active, all IRQs # are disabled, etc. It should do most of what a UBL does, except for # loading code (like U-Boot) into DRAM and running it. # proc dm6446evm_init {} { echo "Initialize DM6446 EVM board" # FIXME initialize everything: # - PLL1 # - PLL2 # - PINMUX # - PSC # - DDR # - AEMIF # - UART0 # - icache flashprobe } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/dp_busblaster_v3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Dangerous Prototypes - Bus Blaster # # http://dangerousprototypes.com/docs/Bus_Blaster # # To reprogram the on-board CPLD do: # openocd -f board/dp_busblaster_v3.cfg -c "adapter speed 1000; init; svf <path_to_svf>; shutdown" # source [find interface/ftdi/dp_busblaster.cfg] ftdi channel 1 jtag newtap xc2c32a tap -expected-id 0x06e1c093 -irlen 8 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/dp_busblaster_v4.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Dangerous Prototypes - Bus Blaster # # http://dangerousprototypes.com/docs/Bus_Blaster # # The Bus Blaster has a configurable buffer between the FTDI FT2232H # and the JTAG header which allows it to emulate various debugger # types. This config works with KT-Link compatible implementation from # https://raw.githubusercontent.com/dergraaf/busblaster_v4/master/ktlink/ktlink.svf # # To reprogram the on-board CPLD do: # openocd -f board/dp_busblaster_v4.cfg -c "adapter speed 1000; init; svf <path_to_svf>; shutdown" # source [find interface/ftdi/dp_busblaster.cfg] ftdi channel 1 jtag newtap xc2c64a tap -expected-id 0x06e5c093 -irlen 8 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/dptechnics_dpt-board-v1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Product page: # https://www.dptechnics.com/en/products/dpt-board-v1.html # # JTAG is a 5 pin array located close to main module in following order: # 1. JTAG TCK # 2. JTAG TDO # 3. JTAG TDI # 4. JTAG TMS # 5. GND The GND is located near letter G of word JTAG on board. # # Two RST pins are connected to: # 1. GND # 2. GPIO11 this pin is located near letter R of word RST. # # To enable EJTAG mode, GPIO11 (RST[1]) pin should be pulled up. For example # with 10K resistor connected to V3.3 pin. # # This board is powered from micro USB connector. No real reset pin or button, for # example RESET_L is available. source [find target/atheros_ar9331.cfg] $_TARGETNAME configure -event reset-init { ar9331_25mhz_pll_init sleep 1 ar9331_ddr2_init } set ram_boot_address 0xa0000000 $_TARGETNAME configure -work-area-phys 0xa1FFE000 -work-area-size 0x1000 flash bank flash0 ath79 0xbf000000 0 0 0 $_TARGETNAME cs0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ecp5_evaluation.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Lattice ECP5 evaluation Kit # https://www.latticesemi.com/view_document?document_id=52479 # adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi channel 0 ftdi layout_init 0x0008 0x008b reset_config none transport select jtag adapter speed 6000 source [find fpga/lattice_ecp5.cfg] #openocd -f board/ecp5_evaluation.cfg -c "init" -c "pld load 0 shared_folder/ecp5_blinker_impl1.bit" #ipdbg -start -tap ecp5.tap -hub 0x32 -port 5555 -tool 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/efikamx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Genesi USA EfikaMX # http://www.genesi-usa.com/products/efika # Fall back to 6MHz if RTCK is not supported jtag_rclk 6000 $_TARGETNAME configure -event "reset-start" { jtag_rclk 6000 } source [find target/imx51.cfg] reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/efm32.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Configuration for EFM32 boards with on-board SEGGER J-Link # # Tested with Tiny, Giant and Zero Gecko Starter Kit. # source [find interface/jlink.cfg] transport select swd adapter speed 1000 set CHIPNAME efm32 source [find target/efm32.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/eir.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Elector Internet Radio board # http://www.ethernut.de/en/hardware/eir/index.html source [find target/at91sam7se512.cfg] $_TARGETNAME configure -event reset-init { # WDT_MR, disable watchdog mww 0xFFFFFD44 0x00008000 # RSTC_MR, enable user reset mww 0xfffffd08 0xa5000001 # CKGR_MOR mww 0xFFFFFC20 0x00000601 sleep 10 # CKGR_PLLR mww 0xFFFFFC2C 0x00481c0e sleep 10 # PMC_MCKR mww 0xFFFFFC30 0x00000007 sleep 10 # PMC_IER mww 0xFFFFFF60 0x00480100 # # Enable SDRAM interface. # # Enable SDRAM control at PIO A. mww 0xfffff474 0x3f800000 ;# PIO_BSR_OFF mww 0xfffff404 0x3f800000 ;# PIO_PDR_OFF # Enable address bus (A0, A2-A11, A13-A17) at PIO B mww 0xfffff674 0x0003effd ;# PIO_BSR_OFF mww 0xfffff604 0x0003effd ;# PIO_PDR_OFF # Enable 16 bit data bus at PIO C mww 0xfffff870 0x0000ffff ;# PIO_ASR_OFF mww 0xfffff804 0x0000ffff ;# PIO_PDR_OFF # Enable SDRAM chip select mww 0xffffff80 0x00000002 ;# EBI_CSA_OFF # Set SDRAM characteristics in configuration register. # Hard coded values for MT48LC32M16A2 with 48MHz CPU. mww 0xffffffb8 0x2192215a ;# SDRAMC_CR_OFF sleep 10 # Issue 16 bit SDRAM command: NOP mww 0xffffffb0 0x00000011 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 # Issue 16 bit SDRAM command: Precharge all mww 0xffffffb0 0x00000012 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 # Issue 8 auto-refresh cycles mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000000 # Issue 16 bit SDRAM command: Set mode register mww 0xffffffb0 0x00000013 ;# SDRAMC_MR_OFF mww 0x20000014 0xcafedede # Set refresh rate count ??? mww 0xffffffb4 0x00000013 ;# SDRAMC_TR_OFF # Issue 16 bit SDRAM command: Normal mode mww 0xffffffb0 0x00000010 ;# SDRAMC_MR_OFF mww 0x20000000 0x00000180 # # Enable external reset key. # mww 0xfffffd08 0xa5000001 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ek-lm3s1968.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI/Luminary Stellaris LM3S1968 Evaluation Kits # # http://www.ti.com/tool/ek-lm3s1968 # # NOTE: to use J-Link instead of the on-board interface, # you may also need to reduce adapter speed to be about 1200. # source [find interface/jlink.cfg] # include the FT2232 interface config for on-board JTAG interface # NOTE: using the on-board FT2232 JTAG/SWD/SWO interface is optional! # so is using in JTAG mode, as done here. source [find interface/ftdi/luminary.cfg] # include the target config set WORKAREASIZE 0x2000 set CHIPNAME lm3s1968 source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ek-lm3s3748.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI/Luminary Stellaris lm3s3748 Evaluation Kits # # http://www.ti.com/tool/ek-lm3s3748 # # NOTE: using the on-board FT2232 JTAG/SWD/SWO interface is optional! # so is using it in JTAG mode, as done here. source [find interface/ftdi/luminary.cfg] # 20k working area set WORKAREASIZE 0x4000 set CHIPNAME lm3s3748 source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ek-lm3s6965.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI/Luminary Stellaris LM3S6965 Evaluation Kits # # http://www.ti.com/tool/ek-lm3s6965 # # NOTE: using the on-board FT2232 JTAG/SWD/SWO interface is optional! # so is using it in JTAG mode, as done here. source [find interface/ftdi/luminary.cfg] # 20k working area set WORKAREASIZE 0x5000 set CHIPNAME lm3s6965 # include the target config source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ek-lm3s811-revb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI/Luminary Stellaris LM3S811 Evaluation Kits (rev B and earlier) # # http://www.ti.com/tool/ek-lm3s811 # # NOTE: newer 811-EK boards (rev C and above) shouldn't use this. # use board/ek-lm3s811.cfg source [find interface/ftdi/luminary-lm3s811.cfg] # include the target config set WORKAREASIZE 0x2000 set CHIPNAME lm3s811 source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ek-lm3s811.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI/Luminary Stellaris LM3S811 Evaluation Kits # # http://www.ti.com/tool/ek-lm3s811 # # NOTE: using the on-board FT2232 JTAG/SWD/SWO interface is optional! # so is using it in JTAG mode, as done here. # NOTE: older '811-EK boards (before rev C) shouldn't use this. source [find interface/ftdi/luminary.cfg] # include the target config set WORKAREASIZE 0x2000 set CHIPNAME lm3s811 source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ek-lm3s8962.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI/Luminary Stellaris LM3S8962 Evaluation Kits # # http://www.ti.com/tool/ek-lm3s8962 # # NOTE: using the on-board FT2232 JTAG/SWD/SWO interface is optional! # so is using it in JTAG mode, as done here. source [find interface/ftdi/luminary.cfg] # 64k working area set WORKAREASIZE 0x10000 set CHIPNAME lm3s8962 # include the target config source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ek-lm3s9b9x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI/Luminary Stellaris LM3S9B9x Evaluation Kits # # http://www.ti.com/tool/ek-lm3s9b90 # http://www.ti.com/tool/ek-lm3s9b92 # # NOTE: using the bundled FT2232 JTAG/SWD/SWO interface is optional! # so is using in JTAG mode, as done here. source [find interface/ftdi/luminary-icdi.cfg] set WORKAREASIZE 0x4000 set CHIPNAME lm3s9b9x source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ek-lm3s9d92.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI/Luminary Stellaris LM3S9D92 Evaluation Kits # # http://www.ti.com/tool/ek-lm3s9d92 # # NOTE: using the bundled FT2232 JTAG/SWD/SWO interface is optional! # so is using in JTAG mode, as done here. source [find interface/ftdi/luminary-icdi.cfg] # 64k working area set WORKAREASIZE 0x10000 set CHIPNAME lm3s9d92 source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ek-lm4f120xl.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI Stellaris Launchpad ek-lm4f120xl Evaluation Kits # # http://www.ti.com/tool/ek-lm4f120xl # # # NOTE: using the bundled ICDI interface is optional! # This interface is not ftdi based as previous boards were # source [find interface/ti-icdi.cfg] transport select hla_jtag set WORKAREASIZE 0x8000 set CHIPNAME lm4f120h5qr source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ek-lm4f232.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI Stellaris LM4F232 Evaluation Kits # # http://www.ti.com/tool/ek-lm4f232 # # # NOTE: using the bundled ICDI interface is optional! # This interface is not ftdi based as previous boards were # source [find interface/ti-icdi.cfg] transport select hla_jtag set WORKAREASIZE 0x8000 set CHIPNAME lm4f23x source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ek-tm4c123gxl.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later echo "WARNING: board/ek-tm4c123gxl.cfg is deprecated, please switch to board/ti_ek-tm4c123gxl.cfg" source [find board/ti_ek-tm4c123gxl.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ek-tm4c1294xl.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later echo "WARNING: board/ek-tm4c1294xl.cfg is deprecated, please switch to board/ti_ek-tm4c1294xl.cfg" source [find board/ti_ek-tm4c1294xl.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/embedded-artists_lpc2478-32.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Embedded Artists eval board for LPC2478 # http://www.embeddedartists.com/ # Target device: LPC2478 set CCLK 72000 source [find target/lpc2478.cfg] # Helper # proc read_register {register} { return [read_memory $register 32 1] } proc init_board {} { # Delays on reset lines adapter srst delay 500 jtag_ntrst_delay 1 # Adaptive JTAG clocking through RTCK. # jtag_rclk 20 global _TARGETNAME global _CHIPNAME # A working area will help speeding the flash programming $_TARGETNAME configure -work-area-phys 0x40000200 -work-area-size [expr {0x10000-0x200-0x20}] -work-area-backup 0 # External 16-bit flash at chip select CS0 (SST39VF3201-70, 4 MiB) flash bank $_CHIPNAME.extflash cfi 0x80000000 0x400000 2 2 $_TARGETNAME jedec_probe # Event handlers # $_TARGETNAME configure -event reset-start { # Back to the slow JTAG clock jtag_rclk 20 } $_TARGETNAME configure -event reset-init { arm core_state arm arm7_9 dcc_downloads enable ;# Speed up downloads by using DCC transfer arm7_9 fast_memory_access enable # Peripheral clocks mww 0xE01FC0C4 0x04280FFE ;# PCONP: (reset value) # Map the user flash to the vector table area (0x00...0x3F) mww 0xE01FC040 0x00000001 ;# MEMMAP: User flash # Memory accelerator module mww 0xE01FC004 0x00000003 ;# MAMTIM: 3 clock cycles mww 0xE01FC000 0x00000002 ;# MAMCR: fully enabled # Enable external memory bus (32-bit SDRAM at DYCS0, 16-bit flash at CS0) mww 0xE002C014 0x55010115 ;# PINSEL5: P2.16=CAS, P2.17=RAS, P2.18=CLKOUT0, # P2.20=DYCS0, P2.24=CKEOUT0, P2.28=DQMOUT0, # P2.29=DQMOUT1, P2.30=DQMOUT2, P2.31=DQMOUT3 mww 0xE002C018 0x55555555 ;# PINSEL6: P3.0...P3.15=D0...D15 mww 0xE002C01C 0x55555555 ;# PINSEL7: P3.16...P3.31=D16...D31 mww 0xE002C020 0x55555555 ;# PINSEL8: P4.0...P4.15=A0...A15 mww 0xE002C024 0x50051555 ;# PINSEL9: P4.16...P4.22=A16...A22, P4.24=OE, # P4.25=WE, P4.30=CS0, P4.31=CS1 mww 0xFFE08000 0x00000001 ;# EMCControl: Enable EMC # Start PLL, then use faster JTAG clock enable_pll jtag_rclk 3000 # 16-bit flash @ CS0 (SST39VF3201-70) mww 0xFFE08200 0x00080081 ;# EMCStaticConfig0: 16 bit, PB=1, buffers on mww 0xFFE08204 0x00000000 ;# EMCStaticWaitWen0 mww 0xFFE08208 0x00000000 ;# EMCStaticWaitOen0 mww 0xFFE0820C 0x00000005 ;# EMCStaticWaitRd0 mww 0xFFE08210 0x00000005 ;# EMCStaticWaitPage0 mww 0xFFE08214 0x00000003 ;# EMCStaticWaitWr0 mww 0xFFE08218 0x00000001 ;# EMCStaticWaitTurn0 # 8-bit NAND @ CS1 # TODO # 32-bit SDRAM @ DYCS0 (K4M563233G-HN75) mww 0xFFE08028 0x00000001 ;# EMCDynamicReadConfig mww 0xFFE08030 0x00000001 ;# EMCDynamicRP mww 0xFFE08034 0x00000003 ;# EMCDynamicRAS mww 0xFFE08038 0x00000005 ;# EMCDynamicSREX mww 0xFFE0803C 0x00000001 ;# EMCDynamicAPR mww 0xFFE08040 0x00000005 ;# EMCDynamicDAL mww 0xFFE08044 0x00000001 ;# EMCDynamicWR mww 0xFFE08048 0x00000005 ;# EMCDynamicRC mww 0xFFE0804C 0x00000005 ;# EMCDynamicRFC mww 0xFFE08050 0x00000005 ;# EMCDynamicXSR mww 0xFFE08054 0x00000001 ;# EMCDynamicRRD mww 0xFFE08058 0x00000001 ;# EMCDynamicMRD # mww 0xFFE08104 0x00000202 ;# EMCDynamicRasCas0 mww 0xFFE08100 0x00005488 ;# EMCDynamicConfig0 sleep 100 mww 0xFFE08020 0x00000183 ;# EMCDynamicControl: Clock on continuously, NOP sleep 10 mww 0xFFE08020 0x00000103 ;# EMCDynamicControl: PRECHARGE-ALL mww 0xFFE08024 0x00000046 ;# EMCDynamicRefresh sleep 100 mww 0xFFE08020 0x00000083 ;# EMCDynamicControl: MODE mdw 0xA0011000 1 ;# Set SDRAM mode register mww 0xFFE08020 0x00000000 ;# EMCDynamicControl: NORMAL mww 0xFFE08100 0x00085488 ;# EMCDynamicConfig0: Enable buffers } $_TARGETNAME configure -event gdb-attach { # Without this gdb-attach will first time as probe will fail reset init } } # Enable the PLL. # Generate maximum CPU clock (72 MHz) Run from internal RC oscillator. # Note: The PLL output runs at a frequency N times the desired CPU clock. # It in unavoidable that the CPU clock drops down to (4 MHz/N) during # the initialization! # Here: N=4 # Note that if the PLL is already active at the time this script is # called, the effective value of N is the value of CCLKCFG at that time! # proc enable_pll {} { # Disconnect PLL in case it is already connected if {[expr {[read_register 0xE01FC080] & 0x03}] == 3} { # Disconnect it, but leave it enabled # (This MUST be done in two steps) mww 0xE01FC080 0x00000001 ;# PLLCON: disconnect PLL mww 0xE01FC08C 0x000000AA ;# PLLFEED mww 0xE01FC08C 0x00000055 ;# PLLFEED } # Disable PLL (as it might already be enabled at this time!) mww 0xE01FC080 0x00000000 ;# PLLCON: disable PLL mww 0xE01FC08C 0x000000AA ;# PLLFEED mww 0xE01FC08C 0x00000055 ;# PLLFEED # Setup PLL to generate 288 MHz from internal RC oscillator mww 0xE01FC10C 0x00000000 ;# CLKSRCSEL: IRC mww 0xE01FC084 0x00000023 ;# PLLCFG: N=1, M=36 mww 0xE01FC08C 0x000000AA ;# PLLFEED mww 0xE01FC08C 0x00000055 ;# PLLFEED mww 0xE01FC080 0x00000001 ;# PLLCON: enable PLL mww 0xE01FC08C 0x000000AA ;# PLLFEED mww 0xE01FC08C 0x00000055 ;# PLLFEED sleep 100 mww 0xE01FC104 0x00000003 ;# CCLKCFG: divide by 4 (72 MHz) mww 0xE01FC080 0x00000003 ;# PLLCON: connect PLL mww 0xE01FC08C 0x000000AA ;# PLLFEED mww 0xE01FC08C 0x00000055 ;# PLLFEED } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/emcraft_imx8m-som-bsb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # configuration file for Emcraft IMX8M-SOM-BSB # # only JTAG supported transport select jtag # set a safe JTAG clock speed, can be overridden adapter speed 1000 # SRST and TRST are wired up reset_config trst_and_srst # delay after SRST goes inactive adapter srst delay 70 # board has an i.MX8MQ with 4 Cortex-A53 cores set CHIPNAME imx8mq set CHIPCORES 4 # source SoC configuration source [find target/imx8m.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/emcraft_twr-vf6-som-bsb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # EmCraft Systems TWR-VF6-SOM-BSB # # http://www.emcraft.com/products/259#twr-kit # source [find board/emcraft_vf6-som.cfg] reset_config srst_only srst_nogate ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/emcraft_vf6-som.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # EmCraft Systems Vybrid VF6 SOM # # http://www.emcraft.com/products/259#som # set CHIPNAME vf610 source [find target/vybrid_vf6xx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/esp32-bridge.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Example OpenOCD configuration file for ESP32 connected via ESP USB Bridge board # # For example, OpenOCD can be started for ESP32 debugging on # # openocd -f board/esp32-bridge.cfg # # Source the JTAG interface configuration file source [find interface/esp_usb_bridge.cfg] # ESP32 chip id defined in the idf esp_chip_model_t espusbjtag chip_id 1 # Source the ESP32 configuration file source [find target/esp32.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/esp32-ethernet-kit-3.3v.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Example OpenOCD configuration file for ESP32-ETHERNET-KIT board. # # For example, OpenOCD can be started for ESP32 debugging on # # openocd -f board/esp32-ethernet-kit-3.3v.cfg # # Source the JTAG interface configuration file source [find interface/ftdi/esp32_devkitj_v1.cfg] set ESP32_FLASH_VOLTAGE 3.3 # Source the ESP32 configuration file source [find target/esp32.cfg] # The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they # do not relate to OpenOCD trying to read from a memory range without physical # memory being present there), you can try lowering this. # # On DevKit-J, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz # if CPU frequency is 160MHz or 240MHz. adapter speed 20000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/esp32-wrover-kit-1.8v.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Example OpenOCD configuration file for ESP32-WROVER-KIT board. # # For example, OpenOCD can be started for ESP32 debugging on # # openocd -f board/esp32-wrover-kit-1.8v.cfg # # Source the JTAG interface configuration file source [find interface/ftdi/esp32_devkitj_v1.cfg] set ESP32_FLASH_VOLTAGE 1.8 # Source the ESP32 configuration file source [find target/esp32.cfg] # The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they # do not relate to OpenOCD trying to read from a memory range without physical # memory being present there), you can try lowering this. # # On DevKit-J, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz # if CPU frequency is 160MHz or 240MHz. adapter speed 20000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/esp32-wrover-kit-3.3v.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Example OpenOCD configuration file for ESP32-WROVER-KIT board. # # For example, OpenOCD can be started for ESP32 debugging on # # openocd -f board/esp32-wrover-kit-3.3v.cfg # # Source the JTAG interface configuration file source [find interface/ftdi/esp32_devkitj_v1.cfg] set ESP32_FLASH_VOLTAGE 3.3 # Source the ESP32 configuration file source [find target/esp32.cfg] # The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they # do not relate to OpenOCD trying to read from a memory range without physical # memory being present there), you can try lowering this. # # On DevKit-J, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz # if CPU frequency is 160MHz or 240MHz. adapter speed 20000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/esp32s2-bridge.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Example OpenOCD configuration file for ESP32-S2 connected via ESP USB Bridge board # # For example, OpenOCD can be started for ESP32-S2 debugging on # # openocd -f board/esp32s2-bridge.cfg # # Source the JTAG interface configuration file source [find interface/esp_usb_bridge.cfg] # ESP32S2 chip id defined in the idf esp_chip_model_t espusbjtag chip_id 2 # Source the ESP32-S2 configuration file source [find target/esp32s2.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/esp32s2-kaluga-1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Example OpenOCD configuration file for ESP32-S2 Kaluga board. # # For example, OpenOCD can be started for ESP32-S2 debugging on # # openocd -f board/esp32s2-kaluga-1.cfg # source [find interface/ftdi/esp32s2_kaluga_v1.cfg] source [find target/esp32s2.cfg] # The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they # do not relate to OpenOCD trying to read from a memory range without physical # memory being present there), you can try lowering this. # On ESP32-S2, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz # if CPU frequency is 160MHz or 240MHz. adapter speed 20000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/esp32s3-bridge.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Example OpenOCD configuration file for ESP32-S3 connected via ESP USB Bridge board # # For example, OpenOCD can be started for ESP32-S3 debugging on # # openocd -f board/esp32s3-bridge.cfg # # Source the JTAG interface configuration file source [find interface/esp_usb_bridge.cfg] # ESP32S3 chip id defined in the idf esp_chip_model_t espusbjtag chip_id 9 # Source the ESP32-S3 configuration file source [find target/esp32s3.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/esp32s3-builtin.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Example OpenOCD configuration file for ESP32-S3 connected via builtin USB-JTAG adapter. # # For example, OpenOCD can be started for ESP32-S3 debugging on # # openocd -f board/esp32s3-builtin.cfg # # Source the JTAG interface configuration file source [find interface/esp_usb_jtag.cfg] # Source the ESP32-S3 configuration file source [find target/esp32s3.cfg] adapter speed 40000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/esp32s3-ftdi.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Example OpenOCD configuration file for ESP32-S3 connected via ESP-Prog. # # For example, OpenOCD can be started for ESP32-S3 debugging on # # openocd -f board/esp32s3-ftdi.cfg # # Source the JTAG interface configuration file source [find interface/ftdi/esp32_devkitj_v1.cfg] # Source the ESP32-S3 configuration file source [find target/esp32s3.cfg] # The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they # do not relate to OpenOCD trying to read from a memory range without physical # memory being present there), you can try lowering this. # # On DevKit-J, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz # if CPU frequency is 160MHz or 240MHz. adapter speed 20000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ethernut3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Ethernut 3 board configuration file # # http://www.ethernut.de/en/hardware/enut3/ # AT91R40008-66AU ARM7TDMI Microcontroller # 256kB internal RAM source [find target/at91r40008.cfg] # AT49BV322A-70TU NOR Flash # 2M x 16 mode at address 0x10000000 # Common flash interface supported # set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x10000000 0x400000 2 2 $_TARGETNAME # Micrel MIC2775-29YM5 Supervisor # Reset output will remain active for 280ms (maximum) # adapter srst delay 300 jtag_ntrst_delay 300 arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable adapter speed 16000 # Target events # $_TARGETNAME configure -event reset-init { board_init } # Initialize board hardware # proc board_init { } { board_remap flash probe 0 } # Memory remap # proc board_remap {{VERBOSE 0}} { # CS0: NOR flash # 16MB @ 0x10000000 # 16-bit data bus # 4 wait states # mww 0xffe00000 0x1000212d # CS1: Ethernet controller # 1MB @ 0x20000000 # 16-bit data bus # 2 wait states # Byte select access # mww 0xffe00004 0x20003025 # CS2: CPLD registers # 1MB @ 0x21000000 # 8-bit data bus # 2 wait states # mww 0xffe00008 0x21002026 # CS3: Expansion bus # 1MB @ 0x22000000 # 8-bit data bus # 8 wait states # mww 0xffe00010 0x22002e3e # Remap command # mww 0xffe00020 0x00000001 if {$VERBOSE != 0} { echo "0x00000000 RAM" echo "0x10000000 Flash" echo "0x20000000 Ethernet" echo "0x21000000 CPLD" echo "0x22000000 Expansion" } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/evb-lan9255.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Microchip LAN9255 evaluation board # https://www.microchip.com/en-us/development-tool/EV25Y25A # set CHIPNAME same53 source [find target/atsame5x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/frdm-kl25z.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an Freescale Freedom eval board with a single MKL25Z128VLK4 chip. # http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=FRDM-KL25Z # source [find interface/cmsis-dap.cfg] # increase working area to 16KB set WORKAREASIZE 0x4000 # chip name set CHIPNAME MKL25Z128VLK4 reset_config srst_only source [find target/kl25.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/frdm-kl46z.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an Freescale Freedom eval board with a single MKL46Z256VLL4 chip. # http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=FRDM-KL46Z # source [find interface/cmsis-dap.cfg] # increase working area to 16KB set WORKAREASIZE 0x4000 # chip name set CHIPNAME MKL46Z256VLL4 reset_config srst_only source [find target/kl46.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/fsl_imx6q_sabresd.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Board configuration file for the Freescale IMX6Q Sabre SD EVM # # This board does not have an embedded JTAG adapter, you must source # a suitable adapter configuration before sourcing this file. # Sabre SD has a standard ARM-20 JTAG connector with # nTRST and nSRST available. reset_config trst_and_srst # the only possible transport is JTAG transport select jtag # iMX6Q POR gates JTAG and the chip is completely incommunicado # over JTAG for at least 10ms after nSRST is deasserted adapter srst delay 11 # Source generic iMX6Q target configuration set CHIPNAME imx6q source [find target/imx6.cfg] # function to apply initial configuration after a reset. It # provides a basic pad configuration and also DDR memory and clocks # sufficient to load and execute a boot loader (e.g. barebox) from # DDR memory. This list is extracted from the barebox flash image # header. proc apply_dcd { } { mww 0x020e05a8 0x00000030 mww 0x020e05b0 0x00000030 mww 0x020e0524 0x00000030 mww 0x020e051c 0x00000030 mww 0x020e0518 0x00000030 mww 0x020e050c 0x00000030 mww 0x020e05b8 0x00000030 mww 0x020e05c0 0x00000030 mww 0x020e05ac 0x00020030 mww 0x020e05b4 0x00020030 mww 0x020e0528 0x00020030 mww 0x020e0520 0x00020030 mww 0x020e0514 0x00020030 mww 0x020e0510 0x00020030 mww 0x020e05bc 0x00020030 mww 0x020e05c4 0x00020030 mww 0x020e056c 0x00020030 mww 0x020e0578 0x00020030 mww 0x020e0588 0x00020030 mww 0x020e0594 0x00020030 mww 0x020e057c 0x00020030 mww 0x020e0590 0x00003000 mww 0x020e0598 0x00003000 mww 0x020e058c 0x00000000 mww 0x020e059c 0x00003030 mww 0x020e05a0 0x00003030 mww 0x020e0784 0x00000030 mww 0x020e0788 0x00000030 mww 0x020e0794 0x00000030 mww 0x020e079c 0x00000030 mww 0x020e07a0 0x00000030 mww 0x020e07a4 0x00000030 mww 0x020e07a8 0x00000030 mww 0x020e0748 0x00000030 mww 0x020e074c 0x00000030 mww 0x020e0750 0x00020000 mww 0x020e0758 0x00000000 mww 0x020e0774 0x00020000 mww 0x020e078c 0x00000030 mww 0x020e0798 0x000c0000 mww 0x021b081c 0x33333333 mww 0x021b0820 0x33333333 mww 0x021b0824 0x33333333 mww 0x021b0828 0x33333333 mww 0x021b481c 0x33333333 mww 0x021b4820 0x33333333 mww 0x021b4824 0x33333333 mww 0x021b4828 0x33333333 mww 0x021b0018 0x00081740 mww 0x021b001c 0x00008000 mww 0x021b000c 0x555a7975 mww 0x021b0010 0xff538e64 mww 0x021b0014 0x01ff00db mww 0x021b002c 0x000026d2 mww 0x021b0030 0x005b0e21 mww 0x021b0008 0x09444040 mww 0x021b0004 0x00025576 mww 0x021b0040 0x00000027 mww 0x021b0000 0x831a0000 mww 0x021b001c 0x04088032 mww 0x021b001c 0x0408803a mww 0x021b001c 0x00008033 mww 0x021b001c 0x0000803b mww 0x021b001c 0x00428031 mww 0x021b001c 0x00428039 mww 0x021b001c 0x09408030 mww 0x021b001c 0x09408038 mww 0x021b001c 0x04008040 mww 0x021b001c 0x04008048 mww 0x021b0800 0xa1380003 mww 0x021b4800 0xa1380003 mww 0x021b0020 0x00005800 mww 0x021b0818 0x00022227 mww 0x021b4818 0x00022227 mww 0x021b083c 0x434b0350 mww 0x021b0840 0x034c0359 mww 0x021b483c 0x434b0350 mww 0x021b4840 0x03650348 mww 0x021b0848 0x4436383b mww 0x021b4848 0x39393341 mww 0x021b0850 0x35373933 mww 0x021b4850 0x48254A36 mww 0x021b080c 0x001f001f mww 0x021b0810 0x001f001f mww 0x021b480c 0x00440044 mww 0x021b4810 0x00440044 mww 0x021b08b8 0x00000800 mww 0x021b48b8 0x00000800 mww 0x021b001c 0x00000000 mww 0x021b0404 0x00011006 mww 0x020c4068 0x00c03f3f mww 0x020c406c 0x0030fc03 mww 0x020c4070 0x0fffc000 mww 0x020c4074 0x3ff00000 mww 0x020c4078 0x00fff300 mww 0x020c407c 0x0f0000c3 mww 0x020c4080 0x000003ff mww 0x020e0010 0xf00000cf mww 0x020e0018 0x007f007f mww 0x020e001c 0x007f007f } # disable watchdog proc disable_wdog { } { mwh 0x020bc000 0x30 } # This function applies the initial configuration after a "reset init" # command proc imx6q_sabresd_init { } { disable_wdog apply_dcd } # prevent cortex-a code from asserting SRST again $_TARGETNAME.0 configure -event reset-assert { } # hook the init function into the reset-init event $_TARGETNAME.0 configure -event reset-init { imx6q_sabresd_init } # set a slow default JTAG clock, can be overridden later adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/gatemate_eval.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # GateMateTM FPGA Evaluation Board # https://www.colognechip.com/programmable-logic/gatemate-evaluation-board/ # adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi channel 0 ftdi layout_init 0x0014 0x011b reset_config none transport select jtag adapter speed 6000 source [find fpga/gatemate.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/glyn_tonga2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Glyn Tonga2 SO-DIMM CPU module (Toshiba TMPA900CMXBG, ARM9) # # http://toshiba-mikrocontroller.de/sites/TMPA900CPUBOARDStarter.htm # # Hardware on the S0-DIMM module: # - Toshiba TMPA900CMXBG (ARM9, ARM926EJ-S, max. 200MHz) # - DDR SDRAM: Hynix H5MS5162DFR-J3M (64Mbyte, x16, 1.8V, 166/83MHz at CL3/2) # - NAND flash: Samsung K9F2G08U0B-PIB0 (256M x 8 Bit, 3.3V) # - Ethernet: SMSC LAN9221I-ABZJ (10/100Mbit, Non-PCI, 16 bit interface) # source [find target/tmpa900.cfg] ######################## # Target configuration # ######################## # Initial JTAG speed should not exceed 1/6 of the initial CPU clock # frequency (24MHz). Be conservative and use 1/8 of the frequency. # (24MHz / 8 = 3MHz) adapter speed 3000 $_TARGETNAME configure -event reset-start { # Upon reset, set the JTAG frequency to 3MHz again, see above. echo "Setting JTAG speed to 3MHz until clocks are initialized." adapter speed 3000 # Halt the CPU. halt # Disable faster memory access for now. arm7_9 fast_memory_access disable } $_TARGETNAME configure -event reset-init { # Setup clocks, and initialize SRAM and DDR SDRAM. tonga2_init # At this point the CPU is running at 192MHz, increase JTAG speed. # Tests showed that 15MHz works OK, higher speeds can cause problems, # though. Not sure if this is a CPU issue or JTAG adapter issue. echo "Increasing JTAG speed to 15MHz." adapter speed 15000 # Enable faster memory access. arm7_9 fast_memory_access enable } proc tonga2_init { } { ###################### # PLL initialization # ###################### # Clock overview (see datasheet chapter 3.5.2, page 57): # - fs: Low-frequency oscillator # - fOSCH: High-frequency oscillator (24MHz on this board) # - fPLL = fOSCH * multiplier (where multiplier can be 6 or 8) # - fFCLK = fPLL / gear (where gear can be 1/2/4/8) # - fHCLK is always fFCLK/2. fPCLK is also fFCLK/2. # # We select multiplier = 8 and gear = 1, so # fFCLK = fOSCH * 8 / 1 = 192MHz. # SYSCR3 (System Control Register 3): Disable and configure PLL. # - PLL operation control: off # - PLL constant value setting 1: always 0, as per datasheet # - PLL constant value setting 2: x8 (multiplier = 8) mww 0xf005000c 0x00000007 # SYSCR4 (System Control Register 4): Configure PLL. # - PLL constant value setting 3: 140MHz or more # - PLL constant value setting 4: always 1, as per datasheet # - PLL constant value setting 5: 140MHz or more mww 0xf0050010 0x00000065 # SYSCR3 (System Control Register 3): Enable PLL. # - PLL operation control: on # - All other bits remain set as above. mww 0xf005000c 0x00000087 # Wait for PLL to stabilize. sleep 10 # SYSCR2 (System Control Register 2): Switch from fOSCH to fPLL. # - Selection of the PLL output clock: fPLL mww 0xf0050008 0x00000002 # SYSCR1 (System Control Register 1): # - Clock gear programming: fc/1 (i.e., gear = 1, don't divide). mww 0xf0050004 0x00000000 # CLKCR5 (Clock Control Register 5): Set bits 3 and 6. The datasheet # says the bits are reserved, but also recommends "Write as one". mww 0xf0050054 0x00000048 ############################################################## # Dynamic Memory Controller (DMC) / DDR SDRAM initialization # ############################################################## # PMC (Power Management Controller): # PMCDRV (External Port "Driverbility" control register): # Bits DRV_MEM0/DRV_MEM1 (memory relation port drive power): mww 0xf0020260 0x00000003 ;# Select 1.8V +/- 0.1V # Setup DDR SDRAM timing parameters for our specific chip. mww 0xf4310014 0x00000004 ;# cas_latency = 2 mww 0xf4310018 0x00000001 ;# t_dqss = 1 mww 0xf431001c 0x00000002 ;# t_mrd = 2 mww 0xf4310020 0x0000000a ;# t_ras = 10 mww 0xf4310024 0x0000000a ;# t_rc = 10 mww 0xf4310028 0x00000013 ;# t_rcd = 3, schedule_rcd = 2 mww 0xf431002c 0x0000010a ;# t_rfc = 10, schedule_rfc = 8 mww 0xf4310030 0x00000013 ;# t_rp = 3, schedule_rp = 2 mww 0xf4310034 0x00000002 ;# t_rrd = 2 mww 0xf4310038 0x00000002 ;# t_wr = 2 mww 0xf431003c 0x00000001 ;# t_wtr = 1 mww 0xf4310040 0x0000000a ;# t_xp = 10 mww 0xf4310044 0x0000000c ;# t_xsr = 12 mww 0xf4310048 0x00000014 ;# t_esr = 20 # dmc_memory_cfg_5 (DMC Memory Configuration register): # Set memory configuration: # column_bits = 10, row_bits = 13, ap-bit = 10, power_down_prd = 0, # auto_power_down = disable, stop_mem_clock = disable, memory_burst = 4 mww 0xf431000c 0x00010012 # dmc_user_config_5 (DMC user_config register): # Data bus width of DDR SDRAM: 16 bit mww 0xf4310304 0x00000058 # dmc_refresh_prd_5 (DMC Refresh Period register): # Auto refresh: every 2656 (0xa60) DMCSCLK periods. mww 0xf4310010 0x00000a60 # dmc_chip_0_cfg_5 (DMC chip_0_cfg registers): # - SDRAM address structure: bank, row, column # - address_match = 01000000 (start address [31:24]) # - address_mask = 11111100 (start address [31:24] mask value) mww 0xf4310200 0x000140fc # Initialize the DDR SDRAM chip. # dmc_direct_cmd_5 (DMC Direct Command register). # See datasheet chapter 3.10.5.1, page 268. mww 0xf4310008 0x000c0000 ;# RAM init: NOP mww 0xf4310008 0x00000000 ;# RAM init: Precharge all mww 0xf4310008 0x00040000 ;# RAM init: Autorefresh mww 0xf4310008 0x00040000 ;# RAM init: Autorefresh mww 0xf4310008 0x00080032 ;# RAM init: addr_13_to_0 = 0x32 mww 0xf4310008 0x000c0000 ;# RAM init: NOP mww 0xf4310008 0x000a0000 ;# RAM init: bank_addr = bank 2 # dmc_id_<0-5>_cfg_5 (DMC id_<0-5>_cfg registers): # Set min./max. QoS values. # - 0x5: Enable QoS, max. QoS = 1 # - 0xb: Enable QoS, min. QoS = 2 mww 0xf4310100 0x00000005 ;# AHB0: CPU Data mww 0xf4310104 0x00000005 ;# AHB1: CPU Inst mww 0xf4310108 0x0000000b ;# AHB2: LCDC mww 0xf431010c 0x00000005 ;# AHB3: LCDDA, USB mww 0xf4310110 0x00000005 ;# AHB4: DMA1 mww 0xf4310114 0x00000005 ;# AHB5: DMA2 # dmc_memc_cmd_5 (DMC Memory Controller Command register): # Change DMC state to ready. mww 0xf4310004 0x00000000 ;# memc_cmd = "Go" # EBI: SMC Timeout register mww 0xf00a0050 0x00000001 ;# smc_timeout = 1 ######################################################## # Static Memory Controller (SMC) / SRAM initialization # ######################################################## # smc_set_cycles_5 (SMC Set Cycles register): # tRC = 10, tWC = 10, tCEOE = 7, tWP = 5, tPC=2, tTR=2 mww 0xf4311014 0x0004afaa # smc_set_opmode_5 (SMC Set Opmode register): # Memory data bus width = 16 bits, async read mode, read burst # length = 1 beat, async write mode, write burst length = 1 beat, # byte enable (SMCBE0-1) timing = SMCCSn timing, memory burst boundary # split setting = burst can cross any address boundary mww 0xf4311018 0x00000001 # smc_direct_cmd_5 (SMC Direct Command register): # cmd_type = UpdateRegs, chip_select = CS1 mww 0xf4311010 0x00c00000 echo "Clocks, SRAM, and DDR SDRAM are now initialized." } ####################### # Flash configuration # ####################### # TODO: Implement NAND support. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/gowin_runber.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Gowin RUNBER FPGA Development Board # https://www.seeedstudio.com/Gowin-RUNBER-Development-Board-p-4779.html adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi channel 0 ftdi layout_init 0x0008 0x008b reset_config none transport select jtag adapter speed 6000 source [find fpga/gowin_gw1n.cfg] #openocd -f board/gowin_runber.cfg -c "init" -c "pld load 0 impl/pnr/gw1n_blinker.fs" #ipdbg -start -tap gw1n.tap -hub 0x42 -port 5555 -tool 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/gti/espressobin.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # config for ESPRESSObin from # Globalscale Technologies Inc. # srst is isolated through missing resistor reset_config trst_only source [find target/marvell/88f3720.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/gumstix-aerocore.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # JTAG for the STM32F4x chip used on the Gumstix AeroCore is available on # the first interface of a Quad FTDI chip. nTRST is bit 4. adapter driver ftdi ftdi vid_pid 0x0403 0x6011 ftdi layout_init 0x0000 0x001b ftdi layout_signal nTRST -data 0x0010 source [find target/stm32f4x.cfg] reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/hammer.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Target Configuration for the TinCanTools S3C2410 Based Hammer Module # http://www.tincantools.com source [find target/samsung_s3c2410.cfg] $_TARGETNAME configure -event reset-init { # Reset Script for the TinCanTools S3C2410 Based Hammer Module # http://www.tincantools.com # # Setup primary clocks and initialize the SDRAM mww 0x53000000 0x00000000 mww 0x4a000008 0xffffffff mww 0x4a00000c 0x000007ff mww 0x4c000000 0x00ffffff mww 0x4c000014 0x00000003 mww 0x4c000004 0x000a1031 mww 0x48000000 0x11111122 mww 0x48000004 0x00000700 mww 0x48000008 0x00000700 mww 0x4800000c 0x00000700 mww 0x48000010 0x00000700 mww 0x48000014 0x00000700 mww 0x48000018 0x00000700 mww 0x4800001c 0x00018005 mww 0x48000020 0x00018005 mww 0x48000024 0x009c0459 mww 0x48000028 0x000000b2 mww 0x4800002c 0x00000030 mww 0x48000030 0x00000030 flash probe 0 } #flash configuration #flash bank <name> <driver> <base> <size> <chip_width> <bus_width> <target> [driver_options ...] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x1000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/hilscher_nxdb500sys.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ source [find target/hilscher_netx500.cfg] reset_config trst_and_srst adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x1000 -work-area-phys 0x1000 -work-area-size 0x4000 -work-area-backup 1 $_TARGETNAME configure -event reset-init { halt arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable sdram_fix puts "Configuring SDRAM controller for paired K4S561632C (64MB) " mww 0x00100140 0 mww 0x00100144 0x03C13261 mww 0x00100140 0x030D0121 puts "Configuring SRAM nCS0 for 150ns paired Par. Flash (x32)" mww 0x00100100 0x0201000E flash probe 0 } ##################### # Flash configuration ##################### #flash bank <name> <driver> <base> <size> <chip width> <bus width> <target#> flash bank parflash cfi 0xC0000000 0x02000000 4 4 $_TARGETNAME init reset init ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/hilscher_nxeb500hmi.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ source [find target/hilscher_netx500.cfg] reset_config trst_and_srst adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x1000 -work-area-phys 0x1000 -work-area-size 0x4000 -work-area-backup 1 $_TARGETNAME configure -event reset-init { halt arm7_9 fast_memory_access enable arm7_9 dcc_downloads disable sdram_fix puts "Configuring SDRAM controller for MT48LC8M32 (32MB) " mww 0x00100140 0 mww 0x00100144 0x03C23251 mww 0x00100140 0x030D0111 puts "Configuring SRAM nCS0 for 150ns Par. Flash (x16)" mww 0x00100100 0x0101000E flash probe 0 } ##################### # Flash configuration ##################### #flash bank <name> <driver> <base> <size> <chip width> <bus width> <target#> flash bank parflash cfi 0xC0000000 0x01000000 2 2 $_TARGETNAME init reset init ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/hilscher_nxhx10.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ source [find target/hilscher_netx10.cfg] # Usually it is not needed to set srst_pulls_trst # but sometimes it does not work without it. If you encounter # problems try to line below # reset_config trst_and_srst srst_pulls_trst reset_config trst_and_srst adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x08000000 -work-area-phys 0x08000000 -work-area-size 0x4000 -work-area-backup 1 # Par. Flash can only be accessed if DIP switch on the board is set in proper # position and init_sdrambus was called. Don't call these functions if the DIP # switch is in invalid position, as some outputs may collide. This is why this # function is not called automatically proc flash_init { } { puts "Configuring SRAM nCS0 for 90ns Par. Flash (x16)" mww 0x101C0100 0x01010008 flash probe 0 } proc mread32 {addr} { return [read_memory $addr 32 1] } proc init_clocks { } { puts "Enabling all clocks " set accesskey [mread32 0x101c0070] mww 0x101c0070 $accesskey mww 0x101c0028 0x00007511 } proc init_sdrambus { } { puts "Initializing external SDRAM Bus 16 Bit " set accesskey [mread32 0x101c0070] mww 0x101c0070 $accesskey mww 0x101c0C40 0x00000050 puts "Configuring SDRAM controller for K4S561632E (32MB) " mww 0x101C0140 0 sleep 100 #mww 0x101C0144 0x00a13262 mww 0x101C0144 0x00a13251 mww 0x101C0148 0x00000033 mww 0x101C0140 0x030d0121 } $_TARGETNAME configure -event reset-init { halt wait_halt 1000 arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable init_clocks # init_sdrambus puts "" puts "-------------------------------------------------" puts "Call 'init_clocks' to enable all clocks" puts "Call 'init_sdrambus' to enable external SDRAM bus" puts "-------------------------------------------------" } ##################### # Flash configuration ##################### #flash bank <name> <driver> <base> <size> <chip width> <bus width> <target#> #flash bank parflash cfi 0xC0000000 0x01000000 2 2 $_TARGETNAME init reset init ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/hilscher_nxhx50.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ source [find target/hilscher_netx50.cfg] reset_config trst_and_srst adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x10000000 -work-area-phys 0x10000000 -work-area-size 0x4000 -work-area-backup 1 $_TARGETNAME configure -event reset-init { halt arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable sdram_fix puts "Configuring SDRAM controller for MT48LC2M32 (8MB) " mww 0x1C000140 0 mww 0x1C000144 0x00A12151 mww 0x1C000140 0x030D0001 puts "Configuring SRAM nCS0 for 90ns Par. Flash (x16)" mww 0x1C000100 0x01010008 flash probe 0 } ##################### # Flash configuration ##################### #flash bank <name> <driver> <base> <size> <chip width> <bus width> <target#> flash bank parflash cfi 0xC0000000 0x01000000 2 2 $_TARGETNAME init reset init ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/hilscher_nxhx500.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ source [find target/hilscher_netx500.cfg] reset_config trst_and_srst adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x1000 -work-area-phys 0x1000 -work-area-size 0x4000 -work-area-backup 1 $_TARGETNAME configure -event reset-init { halt arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable sleep 100 sdram_fix puts "Configuring SDRAM controller for MT48LC2M32 (8MB) " mww 0x00100140 0 mww 0x00100144 0x03C23251 mww 0x00100140 0x030D0001 puts "Configuring SRAM nCS0 for 90ns Par. Flash (x16)" mww 0x00100100 0x01010008 flash probe 0 } ##################### # Flash configuration ##################### #flash bank <name> <driver> <base> <size> <chip width> <bus width> <target#> flash bank parflash cfi 0xC0000000 0x01000000 2 2 $_TARGETNAME init reset init ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/hilscher_nxsb100.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ source [find target/hilscher_netx500.cfg] reset_config trst_and_srst adapter srst delay 500 jtag_ntrst_delay 500 $_TARGETNAME configure -work-area-virt 0x1000 -work-area-phys 0x1000 -work-area-size 0x4000 -work-area-backup 1 $_TARGETNAME configure -event reset-init { halt arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable sdram_fix puts "Configuring SDRAM controller for MT48LC2M32 (8MB) " mww 0x00100140 0 mww 0x00100144 0x03C23251 mww 0x00100140 0x030D0001 } init reset init ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/hitex_lpc1768stick.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Hitex LPC1768 Stick # # http://www.hitex.com/?id=1602 # reset_config trst_and_srst source [find interface/ftdi/hitex_lpc1768stick.cfg] source [find target/lpc17xx.cfg] # startup @ 500kHz adapter speed 500 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/hitex_lpc2929.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Hitex eval board for LPC2929/LPC2939 # http://www.hitex.com/ # Delays on reset lines adapter srst delay 50 jtag_ntrst_delay 1 # Maximum of 1/8 of clock frequency (XTAL = 16 MHz). # Adaptive clocking through RTCK is not supported. adapter speed 2000 # Target device: LPC29xx with ETB # The following variables are used by the LPC2900 script: # HAS_ETB Must be set to 1. The CPU on this board has ETB. # FLASH_CLOCK CPU frequency at the time of flash programming (in kHz) set HAS_ETB 1 set FLASH_CLOCK 112000 source [find target/lpc2900.cfg] # A working area will help speeding the flash programming #$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 0x2000 -work-area-backup 0 $_TARGETNAME configure -work-area-phys 0x58000000 -work-area-size 0x10000 -work-area-backup 0 # Event handlers $_TARGETNAME configure -event reset-start { # Back to the slow JTAG clock adapter speed 2000 } # External 16-bit flash at chip select CS7 (SST39VF3201-70, 4 MiB) set _FLASHNAME $_CHIPNAME.extflash flash bank $_FLASHNAME cfi 0x5C000000 0x400000 2 2 $_TARGETNAME jedec_probe $_TARGETNAME configure -event reset-init { # Flash mww 0x20200010 0x00000007 ;# FBWST: 7 wait states, not cached # Use PLL mww 0xFFFF8020 0x00000001 ;# XTAL_OSC_CONTROL: enable, 1-20 MHz mww 0xFFFF8070 0x01000000 ;# SYS_CLK_CONF: Crystal mww 0xFFFF8028 0x00000005 ;# PLL: (power down) mww 0xFFFF8028 0x01060004 ;# PLL: M=7, 2P=2 (power up) # --> f=112 MHz, fcco=224 MHz sleep 100 mww 0xFFFF8070 0x02000000 ;# SYS_CLK_CONF: PLL # Increase JTAG speed adapter speed 6000 # Enable external memory bus (16-bit SRAM at CS6, 16-bit flash at CS7) mww 0xE0001138 0x0000001F ;# P1.14 = D0 mww 0xE000113C 0x0000001F ;# P1.15 = D1 mww 0xE0001140 0x0000001F ;# P1.16 = D2 mww 0xE0001144 0x0000001F ;# P1.17 = D3 mww 0xE0001148 0x0000001F ;# P1.18 = D4 mww 0xE000114C 0x0000001F ;# P1.19 = D5 mww 0xE0001150 0x0000001F ;# P1.20 = D6 mww 0xE0001154 0x0000001F ;# P1.21 = D7 mww 0xE0001200 0x0000001F ;# P2.0 = D8 mww 0xE0001204 0x0000001F ;# P2.1 = D9 mww 0xE0001208 0x0000001F ;# P2.2 = D10 mww 0xE000120C 0x0000001F ;# P2.3 = D11 mww 0xE0001210 0x0000001F ;# P2.4 = D12 mww 0xE0001214 0x0000001F ;# P2.5 = D13 mww 0xE0001218 0x0000001F ;# P2.6 = D14 mww 0xE000121C 0x0000001F ;# P2.7 = D15 mww 0xE0001104 0x00000007 ;# P1.1 = A1 mww 0xE0001108 0x00000007 ;# P1.2 = A2 mww 0xE000110C 0x00000007 ;# P1.3 = A3 mww 0xE0001110 0x00000007 ;# P1.4 = A4 mww 0xE0001114 0x00000007 ;# P1.5 = A5 mww 0xE0001118 0x00000007 ;# P1.6 = A6 mww 0xE000111C 0x00000007 ;# P1.7 = A7 mww 0xE0001028 0x00000007 ;# P0.10 = A8 mww 0xE000102C 0x00000007 ;# P0.11 = A9 mww 0xE0001030 0x00000007 ;# P0.12 = A10 mww 0xE0001034 0x00000007 ;# P0.13 = A11 mww 0xE0001038 0x00000007 ;# P0.14 = A12 mww 0xE000103C 0x00000007 ;# P0.15 = A13 mww 0xE0001048 0x00000007 ;# P0.18 = A14 mww 0xE000104C 0x00000007 ;# P0.19 = A15 mww 0xE0001050 0x00000007 ;# P0.20 = A16 mww 0xE0001054 0x00000007 ;# P0.21 = A17 mww 0xE0001058 0x00000007 ;# P0.22 = A18 mww 0xE000105C 0x00000007 ;# P0.23 = A19 mww 0xE0001238 0x00000007 ;# P2.14 = BLS0 mww 0xE000123C 0x00000007 ;# P2.15 = BLS1 mww 0xE0001300 0x00000007 ;# P3.0 = CS6 mww 0xE0001304 0x00000007 ;# P3.1 = CS7 mww 0xE0001130 0x00000007 ;# P1.12 = OE_N mww 0xE0001134 0x00000007 ;# P1.13 = WE_N mww 0x600000BC 0x00000041 ;# Bank6 16-bit mode, RBLE=1 mww 0x600000B4 0x00000000 ;# Bank6 WSTOEN=0 mww 0x600000AC 0x00000005 ;# Bank6 WST1=5 mww 0x600000B8 0x00000001 ;# Bank6 WSTWEN=1 mww 0x600000B0 0x00000006 ;# Bank6 WST2=6 mww 0x600000A8 0x00000002 ;# Bank6 IDCY=2 mww 0x600000D8 0x00000041 ;# Bank7 16-bit mode, RBLE=1 mww 0x600000D0 0x00000000 ;# Bank7 WSTOEN=0 mww 0x600000C8 0x0000000A ;# Bank7 WST1=10 mww 0x600000D4 0x00000001 ;# Bank7 WSTWEN=1 mww 0x600000CC 0x0000000C ;# Bank7 WST2=8 mww 0x600000C4 0x00000002 ;# Bank7 IDCY=2 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/hitex_stm32-performancestick.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Hitex stm32 performance stick reset_config trst_and_srst source [find interface/ftdi/stm32-stick.cfg] set CHIPNAME stm32_hitex source [find target/stm32f1x.cfg] # configure str750 connected to jtag chain # FIXME -- source [find target/str750.cfg] after cleaning that up jtag newtap str750 cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id 0x4f1f0041 # for some reason this board like to startup @ 500kHz adapter speed 500 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/hitex_str9-comstick.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Hitex STR9-comStick # http://www.hitex.com/index.php?id=383 # This works for the STR9-comStick revisions STR912CS-A1 and STR912CS-A2. source [find interface/ftdi/hitex_str9-comstick.cfg] # set jtag speed adapter speed 3000 adapter srst delay 100 jtag_ntrst_delay 100 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst # # FIXME use the standard str912 target config; that script might need # updating to "-ignore-version" for the boundary scan TAP # # source [find target/str912.cfg] # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME str912 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists FLASHTAPID] } { set _FLASHTAPID $FLASHTAPID } else { set _FLASHTAPID 0x04570041 } jtag newtap $_CHIPNAME flash -irlen 8 -ircapture 0x1 -irmask 0x1 -expected-id $_FLASHTAPID if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x25966041 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID if { [info exists BSTAPID] } { set _BSTAPID $BSTAPID } else { # Found on STR9-comStick, revision STR912CS-A1 set _BSTAPID1 0x1457f041 # Found on STR9-comStick, revision STR912CS-A2 set _BSTAPID2 0x2457f041 } jtag newtap $_CHIPNAME bs -irlen 5 -ircapture 0x1 -irmask 0x1 -expected-id $_BSTAPID1 -expected-id $_BSTAPID2 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-init { # We can increase speed now that we know the target is halted. #jtag_rclk 3000 # -- Enable 96K RAM # PFQBC enabled / DTCM & AHB wait-states disabled mww 0x5C002034 0x0191 str9x flash_config 0 4 2 0 0x80000 flash protect 0 0 7 off } $_TARGETNAME configure -work-area-phys 0x50000000 -work-area-size 16384 -work-area-backup 0 #flash bank <driver> <base> <size> <chip_width> <bus_width> set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME str9x 0x00000000 0x00080000 0 0 0 set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME str9x 0x00080000 0x00008000 0 0 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/iar_lpc1768.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Board from IAR KickStart Kit for LPC1768 # See www.iar.com and also # http://www.olimex.com/dev/lpc-1766stk.html # source [find target/lpc17xx.cfg] # The chip has just been reset. # $_TARGETNAME configure -event reset-init { # FIXME update the core clock to run at 100 MHz; # and update JTAG clocking similarly; then # make CCLK match, flash probe 0 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/iar_str912_sk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The IAR str912-sk evaluation kick start board has an str912 source [find target/str912.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/icnova_imx53_sodimm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################################# # Author: Benjamin Tietz <benjamin.tietz@in-circuit.de> ;# # based on work from: Wjatscheslaw Stoljarski (Slawa) <wjatscheslaw.stoljarski@kiwigrid.com> ;# # Kiwigrid GmbH ;# # Generated for In-Circuit i.MX53 SO-Dimm ;# ################################################################################################# # The In-Circuit ICnova IMX53SODIMM board has a single IMX53 chip source [find target/imx53.cfg] # Helper for common memory read/modify/write procedures source [find mem_helper.tcl] echo "i.MX53 SO-Dimm board lodaded." # Set reset type #reset_config srst_only adapter speed 3000 # Slow speed to be sure it will work jtag_rclk 1000 $_TARGETNAME configure -event "reset-start" { jtag_rclk 1000 } $_TARGETNAME configure -event "reset-assert" { echo "Resetting ...." #cortex_a dbginit } $_TARGETNAME configure -event reset-init { sodimm_init } global AIPS1_BASE_ADDR set AIPS1_BASE_ADDR 0x53F00000 global AIPS2_BASE_ADDR set AIPS2_BASE_ADDR 0x63F00000 proc sodimm_init { } { echo "Reset-init..." ; # halt the CPU halt echo "HW version [format %x [mrw 0x48]]" dap apsel 1 DCD ; # ARM errata ID #468414 set tR [arm mrc 15 0 1 0 1] arm mcr 15 0 1 0 1 [expr {$tR | (1<<5)}] ; # enable L1NEON bit init_l2cc init_aips init_clock dap apsel 0 ; # Force ARM state ; #reg cpsr 0x000001D3 arm core_state arm jtag_rclk 3000 # adapter speed 3000 } # L2CC Cache setup/invalidation/disable proc init_l2cc { } { ; #/* explicitly disable L2 cache */ ; #mrc 15, 0, r0, c1, c0, 1 set tR [arm mrc 15 0 1 0 1] ; #bic r0, r0, #0x2 ; #mcr 15, 0, r0, c1, c0, 1 arm mcr 15 0 1 0 1 [expr {$tR & ~(1 << 2)}] ; #/* reconfigure L2 cache aux control reg */ ; #mov r0, #0xC0 /* tag RAM */ ; #add r0, r0, #0x4 /* data RAM */ ; #orr r0, r0, #(1 << 24) /* disable write allocate delay */ ; #orr r0, r0, #(1 << 23) /* disable write allocate combine */ ; #orr r0, r0, #(1 << 22) /* disable write allocate */ ; #mcr 15, 1, r0, c9, c0, 2 arm mcr 15 1 9 0 2 [expr {0xC4 | (1<<24) | (1<<23) | (1<<22)}] } # AIPS setup - Only setup MPROTx registers. # The PACR default values are good. proc init_aips { } { ; # Set all MPROTx to be non-bufferable, trusted for R/W, ; # not forced to user-mode. global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR set VAL 0x77777777 # dap apsel 1 mww [expr {$AIPS1_BASE_ADDR + 0x0}] $VAL mww [expr {$AIPS1_BASE_ADDR + 0x4}] $VAL mww [expr {$AIPS2_BASE_ADDR + 0x0}] $VAL mww [expr {$AIPS2_BASE_ADDR + 0x4}] $VAL # dap apsel 0 } proc init_clock { } { global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR set CCM_BASE_ADDR [expr {$AIPS1_BASE_ADDR + 0x000D4000}] set CLKCTL_CCSR 0x0C set CLKCTL_CBCDR 0x14 set CLKCTL_CBCMR 0x18 set PLL1_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00080000}] set PLL2_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00084000}] set PLL3_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00088000}] set PLL4_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x0008C000}] set CLKCTL_CSCMR1 0x1C set CLKCTL_CDHIPR 0x48 set PLATFORM_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x000A0000}] set CLKCTL_CSCDR1 0x24 set CLKCTL_CCDR 0x04 ; # Switch ARM to step clock mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x4 return echo "not returned" setup_pll $PLL1_BASE_ADDR 800 setup_pll $PLL3_BASE_ADDR 400 ; # Switch peripheral to PLL3 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00015154 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x02888945 | (1<<16)}] while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL2_BASE_ADDR 400 ; # Switch peripheral to PLL2 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x00808145 | (2<<10) | (9<<16) | (1<<19)}] mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00016154 ; # change uart clk parent to pll2 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}]] & 0xfcffffff | 0x01000000}] ; # make sure change is effective while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL3_BASE_ADDR 216 setup_pll $PLL4_BASE_ADDR 455 ; # Set the platform clock dividers mww [expr {$PLATFORM_BASE_ADDR + 0x14}] 0x00000124 mww [expr {$CCM_BASE_ADDR + 0x10}] 0 ; # Switch ARM back to PLL 1. mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x0 ; # make uart div=6 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}]] & 0xffffffc0 | 0x0a}] ; # Restore the default values in the Gate registers mww [expr {$CCM_BASE_ADDR + 0x68}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x6C}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x70}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x74}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x78}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x7C}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x80}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x84}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCDR}] 0x00000 ; # for cko - for ARM div by 8 mww [expr {$CCM_BASE_ADDR + 0x60}] [expr {0x000A0000 & 0x00000F0}] } proc setup_pll { PLL_ADDR CLK } { set PLL_DP_CTL 0x00 set PLL_DP_CONFIG 0x04 set PLL_DP_OP 0x08 set PLL_DP_HFS_OP 0x1C set PLL_DP_MFD 0x0C set PLL_DP_HFS_MFD 0x20 set PLL_DP_MFN 0x10 set PLL_DP_HFS_MFN 0x24 if {$CLK == 1000} { set DP_OP [expr {(10 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {12 - 1}] set DP_MFN 5 } elseif {$CLK == 850} { set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {48 - 1}] set DP_MFN 41 } elseif {$CLK == 800} { set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 700} { set DP_OP [expr {(7 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {24 - 1}] set DP_MFN 7 } elseif {$CLK == 600} { set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {4 - 1}] set DP_MFN 1 } elseif {$CLK == 665} { set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {96 - 1}] set DP_MFN 89 } elseif {$CLK == 532} { set DP_OP [expr {(5 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {24 - 1}] set DP_MFN 13 } elseif {$CLK == 455} { set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] set DP_MFD [expr {48 - 1}] set DP_MFN 71 } elseif {$CLK == 400} { set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 216} { set DP_OP [expr {(6 << 4) + ((3 - 1) << 0)}] set DP_MFD [expr {4 - 1}] set DP_MFN 3 } else { error "Error (setup_dll): clock not found!" } mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 mww [expr {$PLL_ADDR + $PLL_DP_CONFIG}] 0x2 mww [expr {$PLL_ADDR + $PLL_DP_OP}] $DP_OP mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_OP mww [expr {$PLL_ADDR + $PLL_DP_MFD}] $DP_MFD mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_MFD mww [expr {$PLL_ADDR + $PLL_DP_MFN}] $DP_MFN mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFN}] $DP_MFN mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 while {[expr {[mrw [expr {$PLL_ADDR + $PLL_DP_CTL}]] & 0x1}] == 0} { sleep 1 } } proc CPU_2_BE_32 { L } { return [expr {(($L & 0x000000FF) << 24) | (($L & 0x0000FF00) << 8) | (($L & 0x00FF0000) >> 8) | (($L & 0xFF000000) >> 24)}] } # Device Configuration Data proc DCD { } { # dap apsel 1 #*========================================================================================== ====== # Initialization script for 32 bit DDR3 (CS0+CS1) #*========================================================================================== ====== # Remux D24/D25 to perform Flash-access mww 0x53fa818C 0x00000000 ; #EIM_RW mww 0x53fa8180 0x00000000 ; #EIM_CS0 mww 0x53fa8188 0x00000000 ; #EIM_OE mww 0x53fa817C 0x00000000 ; #A16 mww 0x53fa8178 0x00000000 ; #A17 mww 0x53fa8174 0x00000000 ; #A18 mww 0x53fa8170 0x00000000 ; #A19 mww 0x53fa816C 0x00000000 ; #A20 mww 0x53fa8168 0x00000000 ; #A21 mww 0x53fa819C 0x00000000 ; #DA0 mww 0x53fa81A0 0x00000000 ; #DA1 mww 0x53fa81A4 0x00000000 ; #DA2 mww 0x53fa81A8 0x00000000 ; #DA3 mww 0x53fa81AC 0x00000000 ; #DA4 mww 0x53fa81B0 0x00000000 ; #DA5 mww 0x53fa81B4 0x00000000 ; #DA6 mww 0x53fa81B8 0x00000000 ; #DA7 mww 0x53fa81BC 0x00000000 ; #DA8 mww 0x53fa81C0 0x00000000 ; #DA9 mww 0x53fa81C4 0x00000000 ; #DA10 mww 0x53fa81C8 0x00000000 ; #DA11 mww 0x53fa81CC 0x00000000 ; #DA12 mww 0x53fa81D0 0x00000000 ; #DA13 mww 0x53fa81D4 0x00000000 ; #DA14 mww 0x53fa81D8 0x00000000 ; #DA15 mww 0x53fa8118 0x00000000 ; #D16 mww 0x53fa811C 0x00000000 ; #D17 mww 0x53fa8120 0x00000000 ; #D18 mww 0x53fa8124 0x00000000 ; #D19 mww 0x53fa8128 0x00000000 ; #D20 mww 0x53fa812C 0x00000000 ; #D21 mww 0x53fa8130 0x00000000 ; #D22 mww 0x53fa8134 0x00000000 ; #D23 mww 0x53fa813c 0x00000000 ; #IOMUXC_SW_PAD_CTL_PAD_EIM_D24 mww 0x53fa8140 0x00000000 ; #IOMUXC_SW_PAD_CTL_PAD_EIM_D25 mww 0x53fa8144 0x00000000 ; #D26 mww 0x53fa8148 0x00000000 ; #D27 mww 0x53fa814C 0x00000000 ; #D28 mww 0x53fa8150 0x00000000 ; #D29 mww 0x53fa8154 0x00000000 ; #D30 mww 0x53fa8158 0x00000000 ; #D31 # DDR3 IOMUX configuration #* Global pad control options */ mww 0x53fa8554 0x00380000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM3 mww 0x53fa8558 0x00380040 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS3 mww 0x53fa8560 0x00380000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM2 mww 0x53fa8564 0x00380040 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT1 mww 0x53fa8568 0x00380040 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS2 mww 0x53fa8570 0x00200000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_1 - boazp: weaker sdclk EVK DDR max frequency mww 0x53fa8574 0x00380000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_CAS mww 0x53fa8578 0x00200000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_0 - boazp: weaker sdclk EVK DDR max frequency mww 0x53fa857c 0x00380040 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0 mww 0x53fa8580 0x00380040 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT0 mww 0x53fa8584 0x00380000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM0 mww 0x53fa8588 0x00380000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_RAS mww 0x53fa8590 0x00380040 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS1 mww 0x53fa8594 0x00380000 ; #IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM1 mww 0x53fa86f0 0x00380000 ; #IOMUXC_SW_PAD_CTL_GRP_ADDDS mww 0x53fa86f4 0x00000200 ; #IOMUXC_SW_PAD_CTL_GRP_DDRMODE_CTL mww 0x53fa86fc 0x00000000 ; #IOMUXC_SW_PAD_CTL_GRP_DDRPKE # mww 0x53fa8714 0x00000200 ; #IOMUXC_SW_PAD_CTL_GRP_DDRMODE - CMOS mode XXX mww 0x53fa8714 0x00000000 ; #IOMUXC_SW_PAD_CTL_GRP_DDRMODE - CMOS mode XXX mww 0x53fa8718 0x00380000 ; #IOMUXC_SW_PAD_CTL_GRP_B0DS mww 0x53fa871c 0x00380000 ; #IOMUXC_SW_PAD_CTL_GRP_B1DS mww 0x53fa8720 0x00380000 ; #IOMUXC_SW_PAD_CTL_GRP_CTLDS mww 0x53fa8724 0x00000000 ; #IOMUXC_SW_PAD_CTL_GRP_DDR_TYPE - DDR_SEL=0 XXX mww 0x53fa8728 0x00380000 ; #IOMUXC_SW_PAD_CTL_GRP_B2DS mww 0x53fa872c 0x00380000 ; #IOMUXC_SW_PAD_CTL_GRP_B3DS # mww 0x53fa86f4 0x00000000 ;IOMUXC_SW_PAD_CTL_GRP_DDRMODE_CTL for sDQS[3:0], 1=DDR2, 0=CMOS mode # mww 0x53fa8714 0x00000000 ;IOMUXC_SW_PAD_CTL_GRP_DDRMODE for D[31:0], 1=DDR2, 0=CMOS mode # mww 0x53fa86fc 0x00000000 ;IOMUXC_SW_PAD_CTL_GRP_DDRPKE # mww 0x53fa8724 0x00000000 ;IOMUXC_SW_PAD_CTL_GRP_DDR_TYPE - DDR_SEL=00 #* Data bus byte lane pad drive strength control options */ # mww 0x53fa872c 0x00300000 ;IOMUXC_SW_PAD_CTL_GRP_B3DS # mww 0x53fa8554 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM3 # mww 0x53fa8558 0x00300040 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS3 # mww 0x53fa8728 0x00300000 ;IOMUXC_SW_PAD_CTL_GRP_B2DS # mww 0x53fa8560 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM2 # mww 0x53fa8568 0x00300040 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS2 # mww 0x53fa871c 0x00300000 ;IOMUXC_SW_PAD_CTL_GRP_B1DS # mww 0x53fa8594 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM1 # mww 0x53fa8590 0x00300040 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS1 # mww 0x53fa8718 0x00300000 ;IOMUXC_SW_PAD_CTL_GRP_B0DS # mww 0x53fa8584 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM0 # mww 0x53fa857c 0x00300040 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0 #* SDCLK pad drive strength control options */ # mww 0x53fa8578 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_0 # mww 0x53fa8570 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_1 #* Control and addr bus pad drive strength control options */ # mww 0x53fa8574 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_CAS # mww 0x53fa8588 0x00300000 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_RAS # mww 0x53fa86f0 0x00300000 ;IOMUXC_SW_PAD_CTL_GRP_ADDDS for DDR addr bus # mww 0x53fa8720 0x00300000 ;IOMUXC_SW_PAD_CTL_GRP_CTLDS for CSD0, CSD1, SDCKE0, SDCKE1, SDWE # mww 0x53fa8564 0x00300040 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT1 # mww 0x53fa8580 0x00300040 ;IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT0 # Initialize DDR3 memory - Micron MT41J128M16-187Er #** Keep for now, same setting as CPU3 board **# mww 0x63fd901c 0x00008000 # mww 0x63fd904c 0x01680172 ; #write leveling reg 0 # mww 0x63fd9050 0x0021017f ; #write leveling reg 1 mww 0x63fd9088 0x32383535 ; #read delay lines mww 0x63fd9090 0x40383538 ; #write delay lines # mww 0x63fd90F8 0x00000800 ; #Measure unit mww 0x63fd907c 0x0136014d ; #DQS gating 0 mww 0x63fd9080 0x01510141 ; #DQS gating 1 #* CPU3 Board settingr # Enable bank interleaving, Address mirror on, WALAT 0x1, RALAT = 0x5, DDR2_EN = 0 # mww 0x63fd9018 0x00091740 ; #Misc register: #* Quick Silver board setting # Enable bank interleaving, Address mirror off, WALAT 0x1, RALAT = 0x5, DDR2_EN = 0 mww 0x63fd9018 0x00011740 ; #Misc register # Enable CSD0 and CSD1, row width = 14, column width = 10, burst length = 8, data width = 32bit # mww 0x63fd9000 0xc3190000 ; #Main control register # Enable CSD0 and CSD1, row width = 14, column width = 10, burst length = 8, data width = 32bit mww 0x63fd9000 0x83190000 ; #Main control register # tRFC=64ck;tXS=68;tXP=3;tXPDLL=10;tFAW=15;CAS=6ck mww 0x63fd900C 0x555952E3 ; #timing configuration Reg 0 # tRCD=6;tRP=6;tRC=21;tRAS=15;tRPA=1;tWR=6;tMRD=4;tCWL=5ck mww 0x63fd9010 0xb68e8b63 ; #timing configuration Reg 1 # tDLLK(tXSRD)=512 cycles; tRTP=4;tWTR=4;tRRD=4 mww 0x63fd9014 0x01ff00db ; #timing configuration Reg 2 mww 0x63fd902c 0x000026d2 ; #command delay (default) mww 0x63fd9030 0x009f0e21 ; #out of reset delays # Keep tAOFPD, tAONPD, tANPD, and tAXPD as default since they are bigger than calc values mww 0x63fd9008 0x12273030 ; #ODT timings # tCKE=3; tCKSRX=5; tCKSRE=5 mww 0x63fd9004 0x0002002d #Power down control #********************************** #DDR device configuration: #********************************** #********************************** # CS0: #********************************** mww 0x63fd901c 0x00008032 ; #write mode reg MR2 with cs0 (see below for settings) # Full array self refresh # Rtt_WR disabled (no ODT at IO CMOS operation) # Manual self refresh # CWS=5 mww 0x63fd901c 0x00008033 ; #write mode reg MR3 with cs0. mww 0x63fd901c 0x00028031 ; #write mode reg MR1 with cs0. ODS=01: out buff= RZQ/7 (see below for settings) # out impedance = RZQ/7 # Rtt_nom disabled (no ODT at IO CMOS operation) # Aditive latency off # write leveling disabled # tdqs (differential?) disabled mww 0x63fd901c 0x09208030 ; #write mode reg MR0 with cs0 , with dll_rst0 mww 0x63fd901c 0x04008040 ; #ZQ calibration with cs0 (A10 high indicates ZQ cal long ZQCL) #********************************** # CS1: #********************************** # mww 0x63fd901c 0x0000803a ; #write mode reg MR2 with cs1. # mww 0x63fd901c 0x0000803b ; #write mode reg MR3 with cs1. # mww 0x63fd901c 0x00028039 ; #write mode reg MR1 with cs1. ODS=01: out buff= RZQ/7 # mww 0x63fd901c 0x09208138 ; #write mode reg MR0 with cs1. # mww 0x63fd901c 0x04008048 ; #ZQ calibration with cs1(A10 high indicates ZQ cal long ZQCL) #********************************** mww 0x63fd9020 0x00001800 ; # Refresh control register mww 0x63fd9040 0x04b80003 ; # ZQ HW control mww 0x63fd9058 0x00022227 ; # ODT control register mww 0x63fd901c 0x00000000 # CLKO muxing (comment out for now till needed to avoid conflicts with intended usage of signals) # mww 0x53FA8314 = 0 # mww 0x53FA8320 0x4 # mww 0x53FD4060 0x01e900f0 # dap apsel 0 } # IRAM $_TARGETNAME configure -work-area-phys 0xF8000000 -work-area-size 0x20000 -work-area-backup 1 flash bank mx535_nor cfi 0xf0000000 0x800000 2 2 $_TARGETNAME # vim:filetype=tcl ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/icnova_sam9g45_sodimm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################################# # # # Author: Lars Poeschel (larsi@wh2.tu-dresden.de) # # Generated for In-Circuit ICnova SAM9G45 SODIMM # # http://www.ic-board.de/product_info.php?info=p214_ICnova-SAM9G45-SODIMM.html|ICnova # # # ################################################################################################# # FIXME use some standard target config, maybe create one from this # # source [find target/...cfg] source [find target/at91sam9g45.cfg] # Set reset type. # reset_config trst_and_srst # adapter srst delay 200 # jtag_ntrst_delay 200 # If you don't want to execute built-in boot rom code (and there are good reasons at times not to do that) in the # AT91SAM9 family, the microcontroller is a lump on a log without initialization. Because this family has # some powerful features, we want to have a special function that handles "reset init". To do this we declare # an event handler where these special activities can take place. scan_chain $_TARGETNAME configure -event reset-init {at91sam9g45_init} # Set fallback clock to 1/6 of worst-case clock speed (which would be the 32.768 kHz slow clock). # Slow-speed oscillator enabled at reset, so run jtag speed slow. $_TARGETNAME configure -event reset-start {at91sam9g45_start} # NandFlash configuration and definition # Future TBD # Flash configuration # flash bank cfi <base> <size> <chip width> <bus width> <target#> set _FLASHNAME $_CHIPNAME.flash # set _NANDNAME $_CHIPNAME.nand flash bank $_FLASHNAME cfi 0x10000000 0x00800000 2 2 $_TARGETNAME # nand device $_NANDNAME at91sam9 $_TARGETNAME 0x40000000 0xFFFFE800 proc read_register {register} { return [read_memory $register 32 1] } proc at91sam9g45_start { } { # Make sure that the the jtag is running slow, since there are a number of different ways the board # can be configured coming into this state that can cause communication problems with the jtag # adapter. Also since this call can be made following a "reset init" where fast memory accesses # are enabled, need to temporarily shut this down so that the RSTC_MR register can be written at slower # jtag speed without causing GDB keep alive problem. arm7_9 fast_memory_access disable # Slow-speed oscillator enabled at reset, so run jtag speed slow. adapter speed 4 # Make sure processor is halted, or error will result in following steps. halt wait_halt 10000 # RSTC_MR : enable user reset. mww 0xfffffd08 0xa5000501 } proc at91sam9g45_init { } { # At reset AT91SAM9G45 chip runs on slow clock (32.768 kHz). To shift over to a normal clock requires # a number of steps that must be carefully performed. The process outline below follows the # recommended procedure outlined in the AT91SAM9G45 technical manual. # # Several key and very important things to keep in mind: # The SDRAM parts used currently on the board are -75 grade parts. This # means the master clock (MCLK) must be at or below 133 MHz or timing errors will occur. The processor # core can operate up to 400 MHz and therefore PCLK must be at or below this to function properly. # Make sure processor is halted, or error will result in following steps. halt # RSTC_MR : enable user reset. mww 0xfffffd08 0xa5000501 # WDT_MR : disable watchdog. mww 0xfffffd44 0x00008000 # Enable the main 15.000 MHz oscillator in CKGR_MOR register. # Wait for MOSCS in PMC_SR to assert indicating oscillator is again stable after change to CKGR_MOR. mww 0xfffffc20 0x00004001 while { [expr {[read_register 0xfffffc68] & 0x01}] != 1 } { sleep 1 } # Set PLLA Register for 792.576 MHz (divider: bypass, multiplier: 43). # Wait for LOCKA signal in PMC_SR to assert indicating PLLA is stable. #mww 0xfffffc28 0x202a3f01 mww 0xfffffc28 0x20c73f03 while { [expr {[read_register 0xfffffc68] & 0x02}] != 2 } { sleep 1 } # Set master system clock prescaler divide by 6 and processor clock divide by 2 in PMC_MCKR. # Wait for MCKRDY signal from PMC_SR to assert. #mww 0xfffffc30 0x00000101 mww 0xfffffc30 0x00001301 while { [expr {[read_register 0xfffffc68] & 0x08}] != 8 } { sleep 1 } # Now change PMC_MCKR register to select PLLA. # Wait for MCKRDY signal from PMC_SR to assert. mww 0xfffffc30 0x00001302 while { [expr {[read_register 0xfffffc68] & 0x08}] != 8 } { sleep 1 } # Processor and master clocks are now operating and stable at maximum frequency possible: # -> MCLK = 132.096 MHz # -> PCLK = 396.288 MHz # Switch over to adaptive clocking. adapter speed 6000 # Enable faster DCC downloads. arm7_9 dcc_downloads enable # To be able to use external SDRAM, several peripheral configuration registers must # be modified. The first change is made to PIO_ASR to select peripheral functions # for D15 through D31. The second change is made to the PIO_PDR register to disable # this for D15 through D31. # mww 0xfffff870 0xffff0000 # mww 0xfffff804 0xffff0000 # The EBI chip select register EBI_CS must be specifically configured to enable the internal SDRAM controller # using CS1. Additionally we want CS3 assigned to NandFlash. Also VDDIO is connected physically on # the board to the 3.3 VDC power supply so set the appropriate register bit to notify the micrcontroller. # mww 0xffffef1c 0x000100a # The ICnova SAM9G45 SODIMM has built-in NandFlash. The exact physical timing characteristics # for the memory type used on the current board (MT29F2G08AACWP) can be established by setting # four registers in order: SMC_SETUP3, SMC_PULSE3, SMC_CYCLE3, and SMC_MODE3. # mww 0xffffec30 0x00020002 # mww 0xffffec34 0x04040404 # mww 0xffffec38 0x00070007 # mww 0xffffec3c 0x00030003 # Identify NandFlash bank 0. Disabled at the moment because a memory driver is not yet complete. # nand probe 0 # SMC_SETUP0 : Setup SMC for NOR Flash mww 0xffffe800 0x0012000a # SMC_PULSE0 mww 0xffffe804 0x3b38343b # SMC_CYCLE0 mww 0xffffe808 0x003f003f # SMC_MODE0 mww 0xffffe80c 0x00001000 # Identify flash bank 0 flash probe 0 # Now setup SDRAM. This is tricky and configuration is very important for reliability! The current calculations # are based on 2 x Samsung K4T51083QG memory. # 0. Enable DDR2 Clock mww 0xfffffc00 0x4 # 1. Program memory device type # 1.1 configure the DDR controller mww 0xffffe620 0x16 # 1.2 program the DDR controller mww 0xffffe608 0x3d # 2. program memory device features # 2.1 assume timings for 7.5ns min clock period mww 0xffffe60c 0x21128226 # 2.2 pSDDRC->HDDRSDRC2_T1PR mww 0xffffe610 0x02c8100e # 2.3 pSDDRC->HDDRSDRC2_T2PR mww 0xffffe614 0x01000702 # 3. NOP mww 0xffffe600 0x1 mww 0x70000000 0x1 # 3.1 delay 200us sleep 1 # jim tcl alternative: after ms # after 0.2 # 4. NOP mww 0xffffe600 0x1 mww 0x70000000 0x1 # 4.1 delay 400ns # 5. set all bank precharge mww 0xffffe600 0x2 mww 0x70000000 0x1 # 5.1 delay 400ns # 6. set EMR operation (EMRS2) mww 0xffffe600 0x5 mww 0x74000000 0x1 # 6.1 delay 2 cycles # 7. set EMR operation (EMRS3) mww 0xffffe600 0x5 mww 0x76000000 0x1 # 7.1 delay 2 cycles # 8. set EMR operation (EMRS1) mww 0xffffe600 0x5 mww 0x72000000 0x1 # 8.1 delay 200 cycles (400Mhz -> 5 * 10^-7s) sleep 1 # 9. Enable DLL Reset (set DLL bit) set CR [expr {[read_register 0xffffe608] | 0x80}] mww 0xffffe608 $CR # 10. mode register cycle to reset the DLL mww 0xffffe600 0x5 mww 0x70000000 0x1 # 10.1 delay 2 cycles # 11. set all bank precharge mww 0xffffe600 0x2 mww 0x70000000 0x1 # 11.1 delay 400 ns # 12. two auto-refresh (CBR) cycles are provided. mww 0xffffe600 0x4 mww 0x70000000 0x1 # 12.1 delay 10 cycles # 12.2 2nd cycle (schreiben des Mode Register sparen wir uns) mww 0x70000000 0x1 # 12.3 delay 10 cycles # 13. disable DLL reset (clear DLL bit) set CR [expr {[read_register 0xffffe608] & 0xffffff7f}] mww 0xffffe608 $CR # 14. mode register set cycle mww 0xffffe600 0x3 mww 0x70000000 0x1 # 15. program OCD field (set OCD bits) set CR [expr {[read_register 0xffffe608] | 0x7000}] mww 0xffffe608 $CR # 16. (EMRS1) mww 0xffffe600 0x5 mww 0x72000000 0x1 # 16.1 delay 2 cycles # 17. disable OCD field (clear OCD bits) set CR [expr {[read_register 0xffffe608] & 0xffff8fff}] mww 0xffffe608 $CR # 18. (EMRS1) mww 0xffffe600 0x5 mww 0x76000000 0x1 # 18.1 delay 2 cycles # 19. normal mode command mww 0xffffe600 0x0 mww 0x70000000 0x1 # 20. perform write to any address #mww 0x70000000 0x1 # 21. write refresh rate into the count field of the refresh rate register mww 0xffffe604 0x24b # 21.1 delay (500 * 6 cycles) arm7_9 fast_memory_access enable } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/imx27ads.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The IMX27 ADS eval board has a single IMX27 chip # Note: tested on IMX27ADS Board REV-2.6 and REV-2.8 source [find target/imx27.cfg] $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { imx27ads_init } # The IMX27 ADS board has a NOR flash on CS0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0xc0000000 0x00200000 2 2 $_TARGETNAME proc imx27ads_init { } { # This setup puts RAM at 0xA0000000 # reset the board correctly reset run reset halt mww 0x10000000 0x20040304 mww 0x10020000 0x00000000 mww 0x10000004 0xDFFBFCFB mww 0x10020004 0xFFFFFFFF sleep 100 # ======================================== # Configure DDR on CSD0 -- initial reset # ======================================== mww 0xD8001010 0x00000008 # ======================================== # Configure PSRAM on CS5 # ======================================== mww 0xd8002050 0x0000dcf6 mww 0xd8002054 0x444a4541 mww 0xd8002058 0x44443302 # ======================================== # Configure16 bit NorFlash on CS0 # ======================================== mww 0xd8002000 0x0000CC03 mww 0xd8002004 0xa0330D01 mww 0xd8002008 0x00220800 # ======================================== # Configure CPLD on CS4 # ======================================== mww 0xd8002040 0x0000DCF6 mww 0xd8002044 0x444A4541 mww 0xd8002048 0x44443302 # ======================================== # Configure DDR on CSD0 -- wait 5000 cycle # ======================================== mww 0x10027828 0x55555555 mww 0x10027830 0x55555555 mww 0x10027834 0x55555555 mww 0x10027838 0x00005005 mww 0x1002783C 0x15555555 mww 0xD8001010 0x00000004 mww 0xD8001004 0x00795729 mww 0xD8001000 0x92200000 mww 0xA0000F00 0x0 mww 0xD8001000 0xA2200000 mww 0xA0000F00 0x0 mww 0xA0000F00 0x0 mww 0xD8001000 0xB2200000 mwb 0xA0000033 0xFF mwb 0xA1000000 0xAA mww 0xD8001000 0x82228085 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/imx27lnst.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The Linuxstamp-mx27 is board has a single IMX27 chip # For further info see http://opencircuits.com/Linuxstamp_mx27#OpenOCD source [find target/imx27.cfg] $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { imx27lnst_init } proc imx27lnst_init { } { # This setup puts RAM at 0xA0000000 # reset the board correctly adapter speed 500 reset run reset halt mww 0x10000000 0x20040304 mww 0x10020000 0x00000000 mww 0x10000004 0xDFFBFCFB mww 0x10020004 0xFFFFFFFF sleep 100 # ======================================== # Configure DDR on CSD0 -- initial reset # ======================================== mww 0xD8001010 0x00000008 sleep 100 # ======================================== # Configure DDR on CSD0 -- wait 5000 cycle # ======================================== mww 0x10027828 0x55555555 mww 0x10027830 0x55555555 mww 0x10027834 0x55555555 mww 0x10027838 0x00005005 mww 0x1002783C 0x15555555 mww 0xD8001010 0x00000004 mww 0xD8001004 0x00795729 #mww 0xD8001000 0x92200000 mww 0xD8001000 0x91120000 mww 0xA0000F00 0x0 #mww 0xD8001000 0xA2200000 mww 0xD8001000 0xA1120000 mww 0xA0000F00 0x0 mww 0xA0000F00 0x0 #mww 0xD8001000 0xB2200000 mww 0xD8001000 0xB1120000 mwb 0xA0000033 0xFF mwb 0xA1000000 0xAA #mww 0xD8001000 0x82228085 mww 0xD8001000 0x81128080 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/imx28evk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The IMX28EVK eval board has a IMX28 chip # Tested on SCH-26241 Rev D board with Olimex ARM-USB-OCD # Date: 201-02-01 # Authors: James Robinson & Fabio Estevam source [find target/imx28.cfg] $_TARGETNAME configure -event gdb-attach { imx28evk_init } $_TARGETNAME configure -event reset-init { imx28evk_init } proc imx28evk_init { } { halt #**************************** # VDDD setting #**************************** # set VDDD =1.55V =(0.8v + TRIG x 0.025v), TRIG=0x1e mww 0x80044010 0x0003F503 mww 0x80044040 0x0002041E #**************************** # CLOCK set up #**************************** # Power up PLL0 HW_CLKCTRL_PLL0CTRL0 mww 0x80040000 0x00020000 # Set up fractional dividers for CPU and EMI - HW_CLKCTRL_FRAC0 # EMI - first set DIV_EMI to div-by-2 before programming frac divider mww 0x800400F0 0x80000002 # CPU: CPUFRAC=19 480*18/29=454.7MHz, EMI: EMIFRAC=22, (480/2)*18/22=196.4MHz mww 0x800401B0 0x92921613 # Clear the bypass bits for CPU and EMI clocks in HW_CLKCTRL_CLKSEQ_CLR mww 0x800401D8 0x00040080 # HCLK = 227MHz,HW_CLKCTRL_HBUS DIV =0x2 mww 0x80040060 0x00000002 #**************************** # POWER up DCDD_VDDA (DDR2) #**************************** # Now set the voltage level to 1.8V HW_POWER_VDDACTRL bits TRC=0xC mww 0x80044050 0x0000270C #**************************** # DDR2 DCDD_VDDA #**************************** # First set up pin muxing and drive strength # Ungate module clock and bring out of reset HW_PINCTRL_CTRL_CLR mww 0x80018008 0xC0000000 #**************************** # EMI PAD setting #**************************** # Set up drive strength for EMI pins mww 0x80019B80 0x00030000 #IOMUXC_SW_PAD_CTL_GRP_CTLDS # Set up pin muxing for EMI, HW_PINCTRL_MUXSEL10, 11, 12, 13 mww 0x800181A8 0xFFFFFFFF mww 0x800181B8 0xFFFFFFFF mww 0x800181C8 0xFFFFFFFF mww 0x800181D8 0xFFFFFFFF #** Ungate EMI clock in CCM mww 0x800400F0 0x00000002 #============================================================================ # DDR Controller Registers #============================================================================ # Manufacturer: Elpida # Device Part Number: EDE1116AEBG # Clock Freq.: 200MHz # Density: 1Gb # Chip Selects: 1 # Number of Banks: 8 # Row address: 13 # Column address: 10 #============================================================================ mww 0x800E0000 0x00000000 mww 0x800E0040 0x00000000 mww 0x800E0054 0x00000000 mww 0x800E0058 0x00000000 mww 0x800E005C 0x00000000 mww 0x800E0060 0x00000000 mww 0x800E0064 0x00000000 mww 0x800E0068 0x00010101 mww 0x800E006C 0x01010101 mww 0x800E0070 0x000f0f01 mww 0x800E0074 0x0102020A mww 0x800E007C 0x00010101 mww 0x800E0080 0x00000100 mww 0x800E0084 0x00000100 mww 0x800E0088 0x00000000 mww 0x800E008C 0x00000002 mww 0x800E0090 0x01010000 mww 0x800E0094 0x07080403 mww 0x800E0098 0x06005003 mww 0x800E009C 0x0A0000C8 mww 0x800E00A0 0x02009C40 mww 0x800E00A4 0x0002030C mww 0x800E00A8 0x0036B009 mww 0x800E00AC 0x031A0612 mww 0x800E00B0 0x02030202 mww 0x800E00B4 0x00C8001C mww 0x800E00C0 0x00011900 mww 0x800E00C4 0xffff0303 mww 0x800E00C8 0x00012100 mww 0x800E00CC 0xffff0303 mww 0x800E00D0 0x00012100 mww 0x800E00D4 0xffff0303 mww 0x800E00D8 0x00012100 mww 0x800E00DC 0xffff0303 mww 0x800E00E0 0x00000003 mww 0x800E00E8 0x00000000 mww 0x800E0108 0x00000612 mww 0x800E010C 0x01000f02 mww 0x800E0114 0x00000200 mww 0x800E0118 0x00020007 mww 0x800E011C 0xf4004a27 mww 0x800E0120 0xf4004a27 mww 0x800E012C 0x07400300 mww 0x800E0130 0x07400300 mww 0x800E013C 0x00000005 mww 0x800E0140 0x00000000 mww 0x800E0144 0x00000000 mww 0x800E0148 0x01000000 mww 0x800E014C 0x01020408 mww 0x800E0150 0x08040201 mww 0x800E0154 0x000f1133 mww 0x800E015C 0x00001f04 mww 0x800E0160 0x00001f04 mww 0x800E016C 0x00001f04 mww 0x800E0170 0x00001f04 mww 0x800E0288 0x00010000 mww 0x800E028C 0x00030404 mww 0x800E0290 0x00000003 mww 0x800E02AC 0x01010000 mww 0x800E02B0 0x01000000 mww 0x800E02B4 0x03030000 mww 0x800E02B8 0x00010303 mww 0x800E02BC 0x01020202 mww 0x800E02C0 0x00000000 mww 0x800E02C4 0x02030303 mww 0x800E02C8 0x21002103 mww 0x800E02CC 0x00061200 mww 0x800E02D0 0x06120612 mww 0x800E02D4 0x04420442 # Mode register 0 for CS1 and CS0, ok to program CS1 even if not used mww 0x800E02D8 0x00000000 # Mode register 0 for CS2 and CS3, not supported in this processor mww 0x800E02DC 0x00040004 # Mode register 1 for CS1 and CS0, ok to program CS1 even if not used mww 0x800E02E0 0x00000000 # Mode register 1 for CS2 and CS3, not supported in this processor mww 0x800E02E4 0x00000000 # Mode register 2 for CS1 and CS0, ok to program CS1 even if not used mww 0x800E02E8 0x00000000 # Mode register 2 for CS2 and CS3, not supported in this processor mww 0x800E02EC 0x00000000 # Mode register 3 for CS1 and CS0, ok to program CS1 even if not used mww 0x800E02F0 0x00000000 # Mode register 3 for CS2 and CS3, not supported in this processor mww 0x800E02F4 0xffffffff #** start controller **# mww 0x800E0040 0x00000001 # bit[0]: start } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/imx31pdk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The IMX31PDK eval board has a single IMX31 chip source [find target/imx31.cfg] source [find target/imx.cfg] $_TARGETNAME configure -event reset-init { imx31pdk_init } proc self_test {} { echo "Running 100 iterations of test." dump_image /ram/test 0x80000000 0x40000 for {set i 0} {$i < 100} {set i [expr {$i+1}]} { echo "Iteration $i" reset init mww 0x80000000 0x12345678 0x10000 load_image /ram/test 0x80000000 bin verify_image /ram/test 0x80000000 bin } } # Slow fallback frequency # measure_clk indicates ca. 3-4MHz. jtag_rclk 1000 proc imx31pdk_init { } { imx3x_reset # This setup puts RAM at 0x80000000 mww 0x53FC0000 0x040 mww 0x53F80000 0x074B0B7D # 399MHz - 26MHz input, PD=1,MFI=7, MFN=27, MFD=40 #mww 0x53F80004 0xFF871D50 #mww 0x53F80010 0x00271C1B # Start 16 bit NorFlash Initialization on CS0 mww 0xb8002000 0x0000CC03 mww 0xb8002004 0xa0330D01 mww 0xb8002008 0x00220800 # Configure CPLD on CS4 mww 0xb8002040 0x0000DCF6 mww 0xb8002044 0x444A4541 mww 0xb8002048 0x44443302 # SDCLK mww 0x43FAC26C 0 # CAS mww 0x43FAC270 0 # RAS mww 0x43FAC274 0 # CS2 (CSD0) mww 0x43FAC27C 0x1000 # DQM3 mww 0x43FAC284 0 # DQM2, DQM1, DQM0, SD31-SD0, A25-A0, MA10 (0x288..0x2DC) mww 0x43FAC288 0 mww 0x43FAC28C 0 mww 0x43FAC290 0 mww 0x43FAC294 0 mww 0x43FAC298 0 mww 0x43FAC29C 0 mww 0x43FAC2A0 0 mww 0x43FAC2A4 0 mww 0x43FAC2A8 0 mww 0x43FAC2AC 0 mww 0x43FAC2B0 0 mww 0x43FAC2B4 0 mww 0x43FAC2B8 0 mww 0x43FAC2BC 0 mww 0x43FAC2C0 0 mww 0x43FAC2C4 0 mww 0x43FAC2C8 0 mww 0x43FAC2CC 0 mww 0x43FAC2D0 0 mww 0x43FAC2D4 0 mww 0x43FAC2D8 0 mww 0x43FAC2DC 0 # Initialization script for 32 bit DDR on MX31 ADS mww 0xB8001010 0x00000004 mww 0xB8001004 0x006ac73a mww 0xB8001000 0x92100000 mww 0x80000f00 0x12344321 mww 0xB8001000 0xa2100000 mww 0x80000000 0x12344321 mww 0x80000000 0x12344321 mww 0xB8001000 0xb2100000 mwb 0x80000033 0xda mwb 0x81000000 0xff mww 0xB8001000 0x82226080 mww 0x80000000 0xDEADBEEF mww 0xB8001010 0x0000000c } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/imx35pdk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The IMX35PDK eval board has a single IMX35 chip source [find target/imx35.cfg] source [find target/imx.cfg] $_TARGETNAME configure -event reset-init { imx35pdk_init } # Stick to *really* low clock rate or reset will fail # without RTCK / RCLK jtag_rclk 10 proc imx35pdk_init { } { imx3x_reset mww 0x43f00040 0x00000000 mww 0x43f00044 0x00000000 mww 0x43f00048 0x00000000 mww 0x43f0004C 0x00000000 mww 0x43f00050 0x00000000 mww 0x43f00000 0x77777777 mww 0x43f00004 0x77777777 mww 0x53f00040 0x00000000 mww 0x53f00044 0x00000000 mww 0x53f00048 0x00000000 mww 0x53f0004C 0x00000000 mww 0x53f00050 0x00000000 mww 0x53f00000 0x77777777 mww 0x53f00004 0x77777777 # clock setup mww 0x53F80004 0x00821000 ;# first need to set IPU_HND_BYP mww 0x53F80004 0x00821000 ;#arm clock is 399Mhz and ahb clock is 133Mhz. #================================================= # WEIM config #================================================= # CS0U mww 0xB8002000 0x0000CC03 # CS0L mww 0xB8002004 0xA0330D01 # CS0A mww 0xB8002008 0x00220800 # CS5U mww 0xB8002050 0x0000dcf6 # CS5L mww 0xB8002054 0x444a4541 # CS5A mww 0xB8002058 0x44443302 # IO SW PAD Control registers - setting of 0x0002 is high drive, mDDR mww 0x43FAC368 0x00000006 mww 0x43FAC36C 0x00000006 mww 0x43FAC370 0x00000006 mww 0x43FAC374 0x00000006 mww 0x43FAC378 0x00000006 mww 0x43FAC37C 0x00000006 mww 0x43FAC380 0x00000006 mww 0x43FAC384 0x00000006 mww 0x43FAC388 0x00000006 mww 0x43FAC38C 0x00000006 mww 0x43FAC390 0x00000006 mww 0x43FAC394 0x00000006 mww 0x43FAC398 0x00000006 mww 0x43FAC39C 0x00000006 mww 0x43FAC3A0 0x00000006 mww 0x43FAC3A4 0x00000006 mww 0x43FAC3A8 0x00000006 mww 0x43FAC3AC 0x00000006 mww 0x43FAC3B0 0x00000006 mww 0x43FAC3B4 0x00000006 mww 0x43FAC3B8 0x00000006 mww 0x43FAC3BC 0x00000006 mww 0x43FAC3C0 0x00000006 mww 0x43FAC3C4 0x00000006 mww 0x43FAC3C8 0x00000006 mww 0x43FAC3CC 0x00000006 mww 0x43FAC3D0 0x00000006 mww 0x43FAC3D4 0x00000006 mww 0x43FAC3D8 0x00000006 # DDR data bus SD 0 through 31 mww 0x43FAC3DC 0x00000082 mww 0x43FAC3E0 0x00000082 mww 0x43FAC3E4 0x00000082 mww 0x43FAC3E8 0x00000082 mww 0x43FAC3EC 0x00000082 mww 0x43FAC3F0 0x00000082 mww 0x43FAC3F4 0x00000082 mww 0x43FAC3F8 0x00000082 mww 0x43FAC3FC 0x00000082 mww 0x43FAC400 0x00000082 mww 0x43FAC404 0x00000082 mww 0x43FAC408 0x00000082 mww 0x43FAC40C 0x00000082 mww 0x43FAC410 0x00000082 mww 0x43FAC414 0x00000082 mww 0x43FAC418 0x00000082 mww 0x43FAC41c 0x00000082 mww 0x43FAC420 0x00000082 mww 0x43FAC424 0x00000082 mww 0x43FAC428 0x00000082 mww 0x43FAC42c 0x00000082 mww 0x43FAC430 0x00000082 mww 0x43FAC434 0x00000082 mww 0x43FAC438 0x00000082 mww 0x43FAC43c 0x00000082 mww 0x43FAC440 0x00000082 mww 0x43FAC444 0x00000082 mww 0x43FAC448 0x00000082 mww 0x43FAC44c 0x00000082 mww 0x43FAC450 0x00000082 mww 0x43FAC454 0x00000082 mww 0x43FAC458 0x00000082 # DQM setup mww 0x43FAC45c 0x00000082 mww 0x43FAC460 0x00000082 mww 0x43FAC464 0x00000082 mww 0x43FAC468 0x00000082 mww 0x43FAC46c 0x00000006 mww 0x43FAC470 0x00000006 mww 0x43FAC474 0x00000006 mww 0x43FAC478 0x00000006 mww 0x43FAC47c 0x00000006 mww 0x43FAC480 0x00000006 ;# CSD0 mww 0x43FAC484 0x00000006 ;# CSD1 mww 0x43FAC488 0x00000006 mww 0x43FAC48c 0x00000006 mww 0x43FAC490 0x00000006 mww 0x43FAC494 0x00000006 mww 0x43FAC498 0x00000006 mww 0x43FAC49c 0x00000006 mww 0x43FAC4A0 0x00000006 mww 0x43FAC4A4 0x00000006 ;# RAS mww 0x43FAC4A8 0x00000006 ;# CAS mww 0x43FAC4Ac 0x00000006 ;# SDWE mww 0x43FAC4B0 0x00000006 ;# SDCKE0 mww 0x43FAC4B4 0x00000006 ;# SDCKE1 mww 0x43FAC4B8 0x00000002 ;# SDCLK # SDQS0 through SDQS3 mww 0x43FAC4Bc 0x00000082 mww 0x43FAC4C0 0x00000082 mww 0x43FAC4C4 0x00000082 mww 0x43FAC4C8 0x00000082 # *================================================== # Initialization script for 32 bit DDR2 on RINGO 3DS # *================================================== #-------------------------------------------- # Init CCM #-------------------------------------------- mww 0x53F80028 0x7D000028 #-------------------------------------------- # Init IOMUX for JTAG #-------------------------------------------- mww 0x43FAC5EC 0x000000C3 mww 0x43FAC5F0 0x000000C3 mww 0x43FAC5F4 0x000000F3 mww 0x43FAC5F8 0x000000F3 mww 0x43FAC5FC 0x000000F3 mww 0x43FAC600 0x000000F3 mww 0x43FAC604 0x000000F3 # ESD_MISC : enable DDR2 mww 0xB8001010 0x00000304 #-------------------------------------------- # Init 32-bit DDR2 memory on CSD0 # COL=10-bit, ROW=13-bit, BA[1:0]=Addr[26:25] #-------------------------------------------- # ESD_ESDCFG0 : set timing parameters mww 0xB8001004 0x007ffC2f # ESD_ESDCTL0 : select Prechare-All mode mww 0xB8001000 0x92220000 # DDR2 : Prechare-All mww 0x80000400 0x12345678 # ESD_ESDCTL0 : select Load-Mode-Register mode mww 0xB8001000 0xB2220000 # DDR2 : Load reg EMR2 mwb 0x84000000 0xda # DDR2 : Load reg EMR3 mwb 0x86000000 0xda # DDR2 : Load reg EMR1 -- enable DLL mwb 0x82000400 0xda # DDR2 : Load reg MR -- reset DLL mwb 0x80000333 0xda # ESD_ESDCTL0 : select Prechare-All mode mww 0xB8001000 0x92220000 # DDR2 : Prechare-All mwb 0x80000400 0x12345678 # ESD_ESDCTL0 : select Manual-Refresh mode mww 0xB8001000 0xA2220000 # DDR2 : Manual-Refresh 2 times mww 0x80000000 0x87654321 mww 0x80000000 0x87654321 # ESD_ESDCTL0 : select Load-Mode-Register mode mww 0xB8001000 0xB2220000 # DDR2 : Load reg MR -- CL=3, BL=8, end DLL reset mwb 0x80000233 0xda # DDR2 : Load reg EMR1 -- OCD default mwb 0x82000780 0xda # DDR2 : Load reg EMR1 -- OCD exit mwb 0x82000400 0xda ;# ODT disabled # ESD_ESDCTL0 : select normal-operation mode # DSIZ=32-bit, BL=8, COL=10-bit, ROW=13-bit # disable PWT & PRCT # disable Auto-Refresh mww 0xB8001000 0x82220080 ## ESD_ESDCTL0 : enable Auto-Refresh mww 0xB8001000 0x82228080 ## ESD_ESDCTL1 : enable Auto-Refresh mww 0xB8001008 0x00002000 #*********************************************** # Adjust the ESDCDLY5 register #*********************************************** # Vary DQS_ABS_OFFSET5 for writes mww 0xB8001020 0x00F48000 ;# this is the default value mww 0xB8001024 0x00F48000 ;# this is the default value mww 0xB8001028 0x00F48000 ;# this is the default value mww 0xB800102c 0x00F48000 ;# this is the default value #Then you can make force measure with the dedicated bit (Bit 7 at ESDMISC) mww 0xB8001010 0x00000384 # wait a while sleep 1000 # now clear the force measurement bit mww 0xB8001010 0x00000304 # dummy write to DDR memory to set DQS low mww 0x80000000 0x00000000 mww 0x30000100 0x0 mww 0x30000104 0x31024 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/imx53-m53evk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ####################################### # DENX M53EVK # # http://www.denx-cs.de/?q=M53EVK # # Author: Marek Vasut <marex@denx.de> # # Based on imx53loco.cfg # ####################################### # The DENX M53EVK has on-board JTAG adapter source [find interface/ftdi/m53evk.cfg] # The DENX M53EVK board has a single i.MX53 chip source [find target/imx53.cfg] # Helper for common memory read/modify/write procedures source [find mem_helper.tcl] echo "iMX53 M53EVK board lodaded." # Set reset type reset_config trst_and_srst separate trst_open_drain srst_open_drain # Run at 6 MHz adapter speed 6000 $_TARGETNAME configure -event "reset-assert" { echo "Resetting ...." #cortex_a dbginit } $_TARGETNAME configure -event reset-init { m53evk_init } global AIPS1_BASE_ADDR set AIPS1_BASE_ADDR 0x53F00000 global AIPS2_BASE_ADDR set AIPS2_BASE_ADDR 0x63F00000 proc m53evk_init { } { echo "Reset-init..." ; # halt the CPU halt echo "HW version [format %x [mrw 0x48]]" dap apsel 1 DCD ; # ARM errata ID #468414 set tR [arm mrc 15 0 1 0 1] arm mcr 15 0 1 0 1 [expr {$tR | (1<<5)}] ; # enable L1NEON bit init_l2cc init_aips init_clock dap apsel 0 ; # Force ARM state ; #reg cpsr 0x000001D3 arm core_state arm } # L2CC Cache setup/invalidation/disable proc init_l2cc { } { ; #/* explicitly disable L2 cache */ ; #mrc 15, 0, r0, c1, c0, 1 set tR [arm mrc 15 0 1 0 1] ; #bic r0, r0, #0x2 ; #mcr 15, 0, r0, c1, c0, 1 arm mcr 15 0 1 0 1 [expr {$tR & ~(1 << 2)}] ; #/* reconfigure L2 cache aux control reg */ ; #mov r0, #0xC0 /* tag RAM */ ; #add r0, r0, #0x4 /* data RAM */ ; #orr r0, r0, #(1 << 24) /* disable write allocate delay */ ; #orr r0, r0, #(1 << 23) /* disable write allocate combine */ ; #orr r0, r0, #(1 << 22) /* disable write allocate */ ; #mcr 15, 1, r0, c9, c0, 2 arm mcr 15 1 9 0 2 [expr {0xC4 | (1<<24) | (1<<23) | (1<<22)}] } # AIPS setup - Only setup MPROTx registers. # The PACR default values are good. proc init_aips { } { ; # Set all MPROTx to be non-bufferable, trusted for R/W, ; # not forced to user-mode. global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR set VAL 0x77777777 # dap apsel 1 mww [expr {$AIPS1_BASE_ADDR + 0x0}] $VAL mww [expr {$AIPS1_BASE_ADDR + 0x4}] $VAL mww [expr {$AIPS2_BASE_ADDR + 0x0}] $VAL mww [expr {$AIPS2_BASE_ADDR + 0x4}] $VAL # dap apsel 0 } proc init_clock { } { global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR set CCM_BASE_ADDR [expr {$AIPS1_BASE_ADDR + 0x000D4000}] set CLKCTL_CCSR 0x0C set CLKCTL_CBCDR 0x14 set CLKCTL_CBCMR 0x18 set PLL1_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00080000}] set PLL2_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00084000}] set PLL3_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00088000}] set PLL4_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x0008C000}] set CLKCTL_CSCMR1 0x1C set CLKCTL_CDHIPR 0x48 set PLATFORM_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x000A0000}] set CLKCTL_CSCDR1 0x24 set CLKCTL_CCDR 0x04 ; # Switch ARM to step clock mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x4 return echo "not returned" setup_pll $PLL1_BASE_ADDR 800 setup_pll $PLL3_BASE_ADDR 400 ; # Switch peripheral to PLL3 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00015154 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x02888945 | (1<<16)}] while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL2_BASE_ADDR 400 ; # Switch peripheral to PLL2 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x00808145 | (2<<10) | (9<<16) | (1<<19)}] mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00016154 ; # change uart clk parent to pll2 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}]] & 0xfcffffff | 0x01000000}] ; # make sure change is effective while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL3_BASE_ADDR 216 setup_pll $PLL4_BASE_ADDR 455 ; # Set the platform clock dividers mww [expr {$PLATFORM_BASE_ADDR + 0x14}] 0x00000124 mww [expr {$CCM_BASE_ADDR + 0x10}] 0 ; # Switch ARM back to PLL 1. mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x0 ; # make uart div=6 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}]] & 0xffffffc0 | 0x0a}] ; # Restore the default values in the Gate registers mww [expr {$CCM_BASE_ADDR + 0x68}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x6C}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x70}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x74}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x78}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x7C}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x80}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x84}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCDR}] 0x00000 ; # for cko - for ARM div by 8 mww [expr {$CCM_BASE_ADDR + 0x60}] [expr {0x000A0000 & 0x00000F0}] } proc setup_pll { PLL_ADDR CLK } { set PLL_DP_CTL 0x00 set PLL_DP_CONFIG 0x04 set PLL_DP_OP 0x08 set PLL_DP_HFS_OP 0x1C set PLL_DP_MFD 0x0C set PLL_DP_HFS_MFD 0x20 set PLL_DP_MFN 0x10 set PLL_DP_HFS_MFN 0x24 if {$CLK == 1000} { set DP_OP [expr {(10 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {12 - 1}] set DP_MFN 5 } elseif {$CLK == 850} { set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {48 - 1}] set DP_MFN 41 } elseif {$CLK == 800} { set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 700} { set DP_OP [expr {(7 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {24 - 1}] set DP_MFN 7 } elseif {$CLK == 600} { set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {4 - 1}] set DP_MFN 1 } elseif {$CLK == 665} { set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {96 - 1}] set DP_MFN 89 } elseif {$CLK == 532} { set DP_OP [expr {(5 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {24 - 1}] set DP_MFN 13 } elseif {$CLK == 455} { set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] set DP_MFD [expr {48 - 1}] set DP_MFN 71 } elseif {$CLK == 400} { set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 216} { set DP_OP [expr {(6 << 4) + ((3 - 1) << 0)}] set DP_MFD [expr {4 - 1}] set DP_MFN 3 } else { error "Error (setup_dll): clock not found!" } mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 mww [expr {$PLL_ADDR + $PLL_DP_CONFIG}] 0x2 mww [expr {$PLL_ADDR + $PLL_DP_OP}] $DP_OP mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_OP mww [expr {$PLL_ADDR + $PLL_DP_MFD}] $DP_MFD mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_MFD mww [expr {$PLL_ADDR + $PLL_DP_MFN}] $DP_MFN mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFN}] $DP_MFN mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 while {[expr {[mrw [expr {$PLL_ADDR + $PLL_DP_CTL}]] & 0x1}] == 0} { sleep 1 } } proc CPU_2_BE_32 { L } { return [expr {(($L & 0x000000FF) << 24) | (($L & 0x0000FF00) << 8) | (($L & 0x00FF0000) >> 8) | (($L & 0xFF000000) >> 24)}] } # Device Configuration Data proc DCD { } { # dap apsel 1 mww 0x53fa86f4 0x00000000 ;# GRP_DDRMODE_CTL mww 0x53fa8714 0x00000000 ;# GRP_DDRMODE mww 0x53fa86fc 0x00000000 ;# GRP_DDRPKE mww 0x53fa8724 0x04000000 ;# GRP_DDR_TYPE mww 0x53fa872c 0x00300000 ;# GRP_B3DS mww 0x53fa8554 0x00300000 ;# DRAM_DQM3 mww 0x53fa8558 0x00300040 ;# DRAM_SDQS3 mww 0x53fa8728 0x00300000 ;# GRP_B2DS mww 0x53fa8560 0x00300000 ;# DRAM_DQM2 mww 0x53fa8568 0x00300040 ;# DRAM_SDQS2 mww 0x53fa871c 0x00300000 ;# GRP_B1DS mww 0x53fa8594 0x00300000 ;# DRAM_DQM1 mww 0x53fa8590 0x00300040 ;# DRAM_SDQS1 mww 0x53fa8718 0x00300000 ;# GRP_B0DS mww 0x53fa8584 0x00300000 ;# DRAM_DQM0 mww 0x53fa857c 0x00300040 ;# DRAM_SDQS0 mww 0x53fa8578 0x00300000 ;# DRAM_SDCLK_0 mww 0x53fa8570 0x00300000 ;# DRAM_SDCLK_1 mww 0x53fa8574 0x00300000 ;# DRAM_CAS mww 0x53fa8588 0x00300000 ;# DRAM_RAS mww 0x53fa86f0 0x00300000 ;# GRP_ADDDS mww 0x53fa8720 0x00300000 ;# GRP_CTLDS mww 0x53fa8564 0x00300040 ;# DRAM_SDODT1 mww 0x53fa8580 0x00300040 ;# DRAM_SDODT0 # Initialize DDR2 memory mww 0x63fd9088 0x32383535 mww 0x63fd9090 0x40383538 mww 0x63fd907c 0x0136014d mww 0x63fd9080 0x01510141 mww 0x63fd9018 0x00011740 mww 0x63fd9000 0xc3190000 mww 0x63fd900c 0x555952e3 mww 0x63fd9010 0xb68e8b63 mww 0x63fd9014 0x01ff00db mww 0x63fd902c 0x000026d2 mww 0x63fd9030 0x009f0e21 mww 0x63fd9008 0x12273030 mww 0x63fd9004 0x0002002d mww 0x63fd901c 0x00008032 mww 0x63fd901c 0x00008033 mww 0x63fd901c 0x00028031 mww 0x63fd901c 0x092080b0 mww 0x63fd901c 0x04008040 mww 0x63fd901c 0x0000803a mww 0x63fd901c 0x0000803b mww 0x63fd901c 0x00028039 mww 0x63fd901c 0x09208138 mww 0x63fd901c 0x04008048 mww 0x63fd9020 0x00001800 mww 0x63fd9040 0x04b80003 mww 0x63fd9058 0x00022227 mww 0x63fd901c 0x00000000 # dap apsel 0 } # vim:filetype=tcl ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/imx53loco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################## # Author: Wjatscheslaw Stoljarski (Slawa) <wjatscheslaw.stoljarski@kiwigrid.com> # # Kiwigrid GmbH # ################################################################################## # The IMX53LOCO (QSB) board has a single IMX53 chip source [find target/imx53.cfg] # Helper for common memory read/modify/write procedures source [find mem_helper.tcl] echo "iMX53 Loco board lodaded." # Set reset type #reset_config srst_only adapter speed 3000 # Slow speed to be sure it will work jtag_rclk 1000 $_TARGETNAME configure -event "reset-start" { jtag_rclk 1000 } #adapter srst delay 200 #jtag_ntrst_delay 200 $_TARGETNAME configure -event "reset-assert" { echo "Resetting ...." #cortex_a dbginit } $_TARGETNAME configure -event reset-init { loco_init } global AIPS1_BASE_ADDR set AIPS1_BASE_ADDR 0x53F00000 global AIPS2_BASE_ADDR set AIPS2_BASE_ADDR 0x63F00000 proc loco_init { } { echo "Reset-init..." ; # halt the CPU halt echo "HW version [format %x [mrw 0x48]]" dap apsel 1 DCD ; # ARM errata ID #468414 set tR [arm mrc 15 0 1 0 1] arm mcr 15 0 1 0 1 [expr {$tR | (1<<5)}] ; # enable L1NEON bit init_l2cc init_aips init_clock dap apsel 0 ; # Force ARM state ; #reg cpsr 0x000001D3 arm core_state arm jtag_rclk 3000 # adapter speed 3000 } # L2CC Cache setup/invalidation/disable proc init_l2cc { } { ; #/* explicitly disable L2 cache */ ; #mrc 15, 0, r0, c1, c0, 1 set tR [arm mrc 15 0 1 0 1] ; #bic r0, r0, #0x2 ; #mcr 15, 0, r0, c1, c0, 1 arm mcr 15 0 1 0 1 [expr {$tR & ~(1 << 2)}] ; #/* reconfigure L2 cache aux control reg */ ; #mov r0, #0xC0 /* tag RAM */ ; #add r0, r0, #0x4 /* data RAM */ ; #orr r0, r0, #(1 << 24) /* disable write allocate delay */ ; #orr r0, r0, #(1 << 23) /* disable write allocate combine */ ; #orr r0, r0, #(1 << 22) /* disable write allocate */ ; #mcr 15, 1, r0, c9, c0, 2 arm mcr 15 1 9 0 2 [expr {0xC4 | (1<<24) | (1<<23) | (1<<22)}] } # AIPS setup - Only setup MPROTx registers. # The PACR default values are good. proc init_aips { } { ; # Set all MPROTx to be non-bufferable, trusted for R/W, ; # not forced to user-mode. global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR set VAL 0x77777777 # dap apsel 1 mww [expr {$AIPS1_BASE_ADDR + 0x0}] $VAL mww [expr {$AIPS1_BASE_ADDR + 0x4}] $VAL mww [expr {$AIPS2_BASE_ADDR + 0x0}] $VAL mww [expr {$AIPS2_BASE_ADDR + 0x4}] $VAL # dap apsel 0 } proc init_clock { } { global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR set CCM_BASE_ADDR [expr {$AIPS1_BASE_ADDR + 0x000D4000}] set CLKCTL_CCSR 0x0C set CLKCTL_CBCDR 0x14 set CLKCTL_CBCMR 0x18 set PLL1_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00080000}] set PLL2_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00084000}] set PLL3_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00088000}] set PLL4_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x0008C000}] set CLKCTL_CSCMR1 0x1C set CLKCTL_CDHIPR 0x48 set PLATFORM_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x000A0000}] set CLKCTL_CSCDR1 0x24 set CLKCTL_CCDR 0x04 ; # Switch ARM to step clock mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x4 return echo "not returned" setup_pll $PLL1_BASE_ADDR 800 setup_pll $PLL3_BASE_ADDR 400 ; # Switch peripheral to PLL3 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00015154 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x02888945 | (1<<16)}] while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL2_BASE_ADDR 400 ; # Switch peripheral to PLL2 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x00808145 | (2<<10) | (9<<16) | (1<<19)}] mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00016154 ; # change uart clk parent to pll2 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}]] & 0xfcffffff | 0x01000000}] ; # make sure change is effective while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL3_BASE_ADDR 216 setup_pll $PLL4_BASE_ADDR 455 ; # Set the platform clock dividers mww [expr {$PLATFORM_BASE_ADDR + 0x14}] 0x00000124 mww [expr {$CCM_BASE_ADDR + 0x10}] 0 ; # Switch ARM back to PLL 1. mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x0 ; # make uart div=6 mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}]] & 0xffffffc0 | 0x0a}] ; # Restore the default values in the Gate registers mww [expr {$CCM_BASE_ADDR + 0x68}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x6C}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x70}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x74}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x78}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x7C}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x80}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + 0x84}] 0xFFFFFFFF mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCDR}] 0x00000 ; # for cko - for ARM div by 8 mww [expr {$CCM_BASE_ADDR + 0x60}] [expr {0x000A0000 & 0x00000F0}] } proc setup_pll { PLL_ADDR CLK } { set PLL_DP_CTL 0x00 set PLL_DP_CONFIG 0x04 set PLL_DP_OP 0x08 set PLL_DP_HFS_OP 0x1C set PLL_DP_MFD 0x0C set PLL_DP_HFS_MFD 0x20 set PLL_DP_MFN 0x10 set PLL_DP_HFS_MFN 0x24 if {$CLK == 1000} { set DP_OP [expr {(10 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {12 - 1}] set DP_MFN 5 } elseif {$CLK == 850} { set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {48 - 1}] set DP_MFN 41 } elseif {$CLK == 800} { set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 700} { set DP_OP [expr {(7 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {24 - 1}] set DP_MFN 7 } elseif {$CLK == 600} { set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {4 - 1}] set DP_MFN 1 } elseif {$CLK == 665} { set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {96 - 1}] set DP_MFN 89 } elseif {$CLK == 532} { set DP_OP [expr {(5 << 4) + ((1 - 1) << 0)}] set DP_MFD [expr {24 - 1}] set DP_MFN 13 } elseif {$CLK == 455} { set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] set DP_MFD [expr {48 - 1}] set DP_MFN 71 } elseif {$CLK == 400} { set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 216} { set DP_OP [expr {(6 << 4) + ((3 - 1) << 0)}] set DP_MFD [expr {4 - 1}] set DP_MFN 3 } else { error "Error (setup_dll): clock not found!" } mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 mww [expr {$PLL_ADDR + $PLL_DP_CONFIG}] 0x2 mww [expr {$PLL_ADDR + $PLL_DP_OP}] $DP_OP mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_OP mww [expr {$PLL_ADDR + $PLL_DP_MFD}] $DP_MFD mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_MFD mww [expr {$PLL_ADDR + $PLL_DP_MFN}] $DP_MFN mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFN}] $DP_MFN mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 while {[expr {[mrw [expr {$PLL_ADDR + $PLL_DP_CTL}]] & 0x1}] == 0} { sleep 1 } } proc CPU_2_BE_32 { L } { return [expr {(($L & 0x000000FF) << 24) | (($L & 0x0000FF00) << 8) | (($L & 0x00FF0000) >> 8) | (($L & 0xFF000000) >> 24)}] } # Device Configuration Data proc DCD { } { # dap apsel 1 mww 0x53FA8554 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM3 mww 0x53FA8558 0x00300040 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS3 mww 0x53FA8560 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM2 mww 0x53FA8564 0x00300040 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT mww 0x53FA8568 0x00300040 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS2 mww 0x53FA8570 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_1 mww 0x53FA8574 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_CAS mww 0x53FA8578 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_0 mww 0x53FA857c 0x00300040 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0 mww 0x53FA8580 0x00300040 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT0 mww 0x53FA8584 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM0 mww 0x53FA8588 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_RAS mww 0x53FA8590 0x00300040 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS1 mww 0x53FA8594 0x00300000 ;# IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM1 mww 0x53FA86f0 0x00300000 ;# IOMUXC_SW_PAD_CTL_GRP_ADDDS mww 0x53FA86f4 0x00000000 ;# IOMUXC_SW_PAD_CTL_GRP_DDRMODE_CTL mww 0x53FA86fc 0x00000000 ;# IOMUXC_SW_PAD_CTL_GRP_DDRPKE mww 0x53FA8714 0x00000000 ;# IOMUXC_SW_PAD_CTL_GRP_DDRMODE - CMOS mode mww 0x53FA8718 0x00300000 ;# IOMUXC_SW_PAD_CTL_GRP_B0DS mww 0x53FA871c 0x00300000 ;# IOMUXC_SW_PAD_CTL_GRP_B1DS mww 0x53FA8720 0x00300000 ;# IOMUXC_SW_PAD_CTL_GRP_CTLDS mww 0x53FA8724 0x04000000 ;# IOMUXC_SW_PAD_CTL_GRP_DDR_TYPE - DDR_SEL0= mww 0x53FA8728 0x00300000 ;# IOMUXC_SW_PAD_CTL_GRP_B2DS mww 0x53FA872c 0x00300000 ;# IOMUXC_SW_PAD_CTL_GRP_B3DS # Initialize DDR2 memory mww 0x63FD9088 0x35343535 ;# ESDCTL_RDDLCTL mww 0x63FD9090 0x4d444c44 ;# ESDCTL_WRDLCTL mww 0x63FD907c 0x01370138 ;# ESDCTL_DGCTRL0 mww 0x63FD9080 0x013b013c ;# ESDCTL_DGCTRL1 mww 0x63FD9018 0x00011740 ;# ESDCTL_ESDMISC mww 0x63FD9000 0xc3190000 ;# ESDCTL_ESDCTL mww 0x63FD900c 0x9f5152e3 ;# ESDCTL_ESDCFG0 mww 0x63FD9010 0xb68e8a63 ;# ESDCTL_ESDCFG1 mww 0x63FD9014 0x01ff00db ;# ESDCTL_ESDCFG2 mww 0x63FD902c 0x000026d2 ;# ESDCTL_ESDRWD mww 0x63FD9030 0x009f0e21 ;# ESDCTL_ESDOR mww 0x63FD9008 0x12273030 ;# ESDCTL_ESDOTC mww 0x63FD9004 0x0002002d ;# ESDCTL_ESDPDC mww 0x63FD901c 0x00008032 ;# ESDCTL_ESDSCR mww 0x63FD901c 0x00008033 ;# ESDCTL_ESDSCR mww 0x63FD901c 0x00028031 ;# ESDCTL_ESDSCR mww 0x63FD901c 0x052080b0 ;# ESDCTL_ESDSCR mww 0x63FD901c 0x04008040 ;# ESDCTL_ESDSCR mww 0x63FD901c 0x0000803a ;# ESDCTL_ESDSCR mww 0x63FD901c 0x0000803b ;# ESDCTL_ESDSCR mww 0x63FD901c 0x00028039 ;# ESDCTL_ESDSCR mww 0x63FD901c 0x05208138 ;# ESDCTL_ESDSCR mww 0x63FD901c 0x04008048 ;# ESDCTL_ESDSCR mww 0x63FD9020 0x00005800 ;# ESDCTL_ESDREF mww 0x63FD9040 0x04b80003 ;# ESDCTL_ZQHWCTRL mww 0x63FD9058 0x00022227 ;# ESDCTL_ODTCTRL mww 0x63FD901C 0x00000000 ;# ESDCTL_ESDSCR # dap apsel 0 } # vim:filetype=tcl ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/imx8mp-evk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # configuration file for NXP MC-IMX8MP-EVK # # Board includes FTDI-based JTAG adapter: interface/ftdi/imx8mp-evk.cfg # transport select jtag adapter speed 1000 reset_config srst_only adapter srst delay 100 set CHIPNAME imx8mp set CHIPCORES 4 source [find target/imx8m.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/insignal_arndale.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # InSignal Arndale board # source [find target/exynos5250.cfg] # Experimentally determined highest working speed adapter speed 200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/kasli.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later adapter driver ftdi ftdi device_desc "Quad RS232-HS" ftdi vid_pid 0x0403 0x6011 ftdi channel 0 ftdi layout_init 0x0008 0x000b # adapter usb location 1:8 reset_config none transport select jtag adapter speed 25000 source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] source [find fpga/xilinx-xadc.cfg] source [find fpga/xilinx-dna.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/kc100.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Knovative KC-100 cable modem # TNETC4401PYP, 208-QFP U3 source [find target/tnetc4401.cfg] # 14-pin EJTAG on JP1. Standard pinout, 1-3-5-7-9-11 = nTRST-TDI-TDO-TMS-TCK-nSRST. Use 2 for GND. # Was initially disabled in hardware; had to add a solder bridge reenabling R124, R125 on back. reset_config trst_and_srst separate # 16Mb Intel CFI flash. Note this CPU has an internal ROM at 0x1FC0000 (phys) for cold boot. # All that really does is some minimal checks before jumping to external flash at 0x00000000 phys. # That is remapped to 0xB0000000 uncached, 0x90000000 cached. flash bank intel cfi 0xB0000000 0x200000 2 2 $_TARGETNAME # Perform this after a clean reboot, halt, and reset init (which should also leave it halted). proc kc100_dump_flash {} { echo "Probing 48 TSOP Intel CFI flash chip (2MB)..." flash probe intel echo "Dumping 2MB flash chip to flashdump.bin. flash read_bank 0 flashdump.bin 0 0x200000 } #TODO figure out memory init sequence to be able to dump from cached segment instead # There is also a serial console on JP2, 3-5-6 = TX-RX-GND. 9600/8/N/1. # Possibly of note, this modem's ancient ethernet port does not support Auto-MDIX. # This modem in many ways appears to be essentially a clone of the SB5120. See usbjtag.com. # The firmware/OS is also susceptible to many of the same procedures in "Hacking the Cable Modem" # by DerEngel (Ryan Harris), available from No Starch Press. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/kc705.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # http://www.xilinx.com/products/boards-and-kits/ek-k7-kc705-g.html source [find interface/ftdi/digilent-hs1.cfg] source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] source [find fpga/xilinx-xadc.cfg] source [find fpga/xilinx-dna.cfg] adapter speed 25000 # example command to write bitstream, soft-cpu bios and runtime: # openocd -f board/kc705.cfg -c "init;\ # jtagspi_init 0 bscan_spi_xc7k325t.bit;\ # jtagspi_program bitstream-kc705.bin 0;\ # jtagspi_program bios.bin 0xaf0000;\ # jtagspi_program runtime.fbi 0xb00000;\ # xc7_program xc7.tap;\ # exit" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/kcu105.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # xilinx ultrascale # http://www.xilinx.com/support/documentation/user_guides/ug570-ultrascale-configuration.pdf source [find interface/ftdi/digilent_jtag_smt2_nc.cfg] set CHIP XCKU040 source [find cpld/xilinx-xcu.cfg] source [find cpld/jtagspi.cfg] adapter speed 25000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/keil_mcb1700.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Keil MCB1700 eval board # # http://www.keil.com/mcb1700/picture.asp # source [find target/lpc17xx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/keil_mcb2140.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Keil MCB2140 eval board # # http://www.keil.com/mcb2140/picture.asp # source [find target/lpc2148.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/kindle2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Board configuration file for Amazon Kindle Model No. D00701 and D00801 # AKA Kindle 2nd generation and Kindle DX # using a Freescale MCIMX31LDVKN5D i.MX31 processor # # Pins at J9 40-Pin FFC-A: # 1 - GND # 16 - TRSTB # 17 - TDI # 18 - TMS # 19 - TCK # 20 - RTCK # 21 - TDO # 22 - DE # 25 - BOOT_MODE4 # 27 - BOOT_MODE2 source [find target/imx31.cfg] source [find target/imx.cfg] $_TARGETNAME configure -event reset-init { kindle2_init } $_TARGETNAME configure -event reset-start { adapter speed 1000 } # 8MiB NOR Flash set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0xa0000000 0x800000 2 2 $_TARGETNAME # 16kiB internal SRAM $_TARGETNAME configure -work-area-phys 0x1fffc000 \ -work-area-size 0x4000 -work-area-backup 0 # FIXME: currently SRST is not wired to the system reset_config trst_only jtag_ntrst_assert_width 10 jtag_ntrst_delay 30 # this is broken but enabled by default arm11 memwrite burst disable adapter speed 1000 ftdi tdo_sample_edge falling proc kindle2_init {} { imx3x_reset kindle2_clock_setup disable_mmu_and_cache kindle2_misc_init kindle2_sdram_init arm core_state arm } proc kindle2_clock_setup {} { # CCMR: clock from FPM/CKIL mww 0x53f80000 0x074b0b7b # IPU_CONF mww 0x53fc0000 0x040 # 398MHz mww 0x53f80004 0xff871650 mww 0x53f80010 0x00331c23 } proc kindle2_misc_init { } { # AIPS1 mww 0x43f00040 0x0 mww 0x43f00044 0x0 mww 0x43f00048 0x0 mww 0x43f0004c 0x0 mww 0x43f00050 0x0 mww 0x43f00000 0x77777777 mww 0x43f00004 0x77777777 # AIPS2 mww 0x53f00040 0x0 mww 0x53f00044 0x0 mww 0x53f00048 0x0 mww 0x53f0004c 0x0 mww 0x53f00050 0x0 mww 0x53f00000 0x77777777 mww 0x53f00004 0x77777777 # Start 16 bit NorFlash Initialization on CS0 mww 0xb8002000 0x0000cc03 mww 0xb8002004 0xa0330d01 mww 0xb8002008 0x00220800 } proc disable_mmu_and_cache {} { # Mode Supervisor, disable FIQ, IRQ and imprecise data aborts reg cpsr 0x1d3 # flush entire BTAC arm mcr 15 0 7 5 6 0 # invalidate instruction and data cache # MCR CP15, 0, R1, C7, C7, 0 arm mcr 15 0 7 7 0 # clean and invalidate cache arm mcr 15 0 7 15 0 # disable MMU and caches arm mcr 15 0 1 0 0 0 arm mcr 15 0 15 2 4 0 # invalidate TLBs arm mcr 15 0 8 7 0 0 # Drain the write buffer arm mcr 15 0 7 10 4 0 # start from AIPS 2GB region arm mcr 15 0 15 2 4 0x40000015 } proc kindle2_sdram_init {} { #-------------------------------------------- # Samsung K4X1G323PC-8GC3 32Mx32 Mobile DDR SDRAM #-------------------------------------------- # SDCLK mww 0x43fac26c 0 # CAS mww 0x43fac270 0 # RAS mww 0x43fac274 0 # CS2 (CSD0) mww 0x43fac27c 0x1000 # DQM3 mww 0x43fac284 0 # DQM2, DQM1, DQM0, SD31-SD0, A25-A0, MA10 (0x288..0x2dc) mww 0x43fac288 0 mww 0x43fac28c 0 mww 0x43fac290 0 mww 0x43fac294 0 mww 0x43fac298 0 mww 0x43fac29c 0 mww 0x43fac2a0 0 mww 0x43fac2a4 0 mww 0x43fac2a8 0 mww 0x43fac2ac 0 mww 0x43fac2b0 0 mww 0x43fac2b4 0 mww 0x43fac2b8 0 mww 0x43fac2bc 0 mww 0x43fac2c0 0 mww 0x43fac2c4 0 mww 0x43fac2c8 0 mww 0x43fac2cc 0 mww 0x43fac2d0 0 mww 0x43fac2d4 0 mww 0x43fac2d8 0 mww 0x43fac2dc 0 # ? mww 0xb8002000 0x00006602 mww 0xb8002004 0x00000501 mww 0xb8002008 0x00000000 # LPDDR1 Initialization script mww 0xb8001010 0x00000002 mww 0xb8001010 0x00000004 # ESDCFG0: set timing parameters mww 0xb8001004 0x007fff7f # ESDCTL0: select Prechare-All mode mww 0xb8001000 0x92100000 mww 0x80000f00 0x12344321 # ESDCTL0: Auto Refresh mww 0xb8001000 0xa2100000 mww 0x80000000 0x12344321 mww 0x80000000 0x12344321 # ESDCTL0: Load Mode Register mww 0xb8001000 0xb2100000 mwb 0x80000033 0xda mwb 0x81000000 0xff # ESDCTL0: enable Auto-Refresh mww 0xb8001000 0x82226080 mww 0x80000000 0xdeadbeef } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/kontron_sl28.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Kontron SMARC-sAL28 transport select jtag reset_config srst_only srst_nogate jtag newtap unknown0 tap -irlen 12 set _CPUS 2 source [find target/ls1028a.cfg] source [find tcl/cpld/altera-epm240.cfg] adapter speed 2000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/kwikstik.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Freescale KwikStik development board # # # JLINK interface is onboard # source [find interface/jlink.cfg] source [find target/k40.cfg] reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/la_fonera-fon2200.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/atheros_ar2315.cfg] reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/lambdaconcept_ecpix-5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # LambdaConcept ECPIX-5 # http://docs.lambdaconcept.com/ecpix-5/ # Currently there are following board variants: # ECPIX-5 45F - LFE5UM5G-45F # ECPIX-5 85F - LFE5UM5G-85F # # This boards have two JTAG interfaces: # - CN4, micro USB port connected to FT2232HQ chip: # ADBUS0 TCK # ADBUS1 TDI # ADBUS2 TDO # ADBUS3 TMS # BDBUS0 UART_TXD # BDBUS1 UART_RXD # This interface should be used with following config: # interface/ftdi/lambdaconcept_ecpix-5.cfg # - CN3, 6 pin connector # See schematics for more details: # http://docs.lambdaconcept.com/ecpix-5/_static/resources/SCH_ECPIX-5_R02.PDF # # No reset lines are implemented. So it is not possible to remote reset the FPGA # by using any of this interfaces source [find interface/ftdi/lambdaconcept_ecpix-5.cfg] source [find fpga/lattice_ecp5.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/lemaker_hikey.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # board configuration for LeMaker Hikey # # board does not feature anything but JTAG transport select jtag # SRST-only reset configuration reset_config srst_only srst_push_pull source [find target/hi6220.cfg] # make sure the default target is the boot core targets ${_TARGETNAME}0 proc core_up { args } { global _TARGETNAME # examine remaining cores foreach _core $args { ${_TARGETNAME}$_core arp_examine } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/linksys-wag200g.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Linksys WAG200G Router # # The stock firmware Flash layout is organized as follow: # # Start End Device # 0x90000000 0x90020000 /dev/mtdblock/2 # 0x90020000 0x900d0000 /dev/mtdblock/1 # 0x900d0000 0x903a0000 /dev/mtdblock/0 # 0x903a0000 0x903e0000 /dev/mtdblock/5 # 0x903e0000 0x903f0000 /dev/mtdblock/3 # 0x903f0000 0x90400000 /dev/mtdblock/4 set partition_list { adam2 { "Adam2 bootloader" 0x90000000 0x00020000 } kernel { "Kernel" 0x90020000 0x000b0000 } rootfs { "Root FS" 0x900d0000 0x002d0000 } lang { "Minix language part" 0x903a0000 0x00040000 } config { "Firmware config" 0x903e0000 0x00010000 } adam2env { "Adam2 environment" 0x903f0000 0x00010000 } } source [find target/ti-ar7.cfg] # External 4MB MXIC 29LV320MBTC Flash (Manufacturer/Device: 0x00c2 0x227e) set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x90000000 0x00400000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/linksys-wrt54gl.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Linksys WRT54GL v1.1 # source [find target/bcm5352e.cfg] set partition_list { CFE { Bootloader 0x1c000000 0x00040000 } firmware { "Kernel+rootfs" 0x1c040000 0x003b0000 } nvram { "Config space" 0x1c3f0000 0x00010000 } } # External 4MB NOR Flash (Intel TE28F320C3BD90 or similar) set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x1c000000 0x00400000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/linksys_nslu2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is for the LinkSys (CISCO) NSLU2 board # It is an Intel XSCALE IXP420 CPU. source [find target/ixp42x.cfg] # The _TARGETNAME is set by the above. $_TARGETNAME configure -work-area-phys 0x00020000 -work-area-size 0x10000 -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/lisa-l.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # the Lost Illusions Serendipitous Autopilot # http://paparazzi.enac.fr/wiki/Lisa # Work-area size (RAM size) = 20kB for STM32F103RB device set WORKAREASIZE 0x5000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/logicpd_imx27.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The LogicPD Eval IMX27 eval board has a single IMX27 chip source [find target/imx27.cfg] # The Logic PD board has a NOR flash on CS0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0xc0000000 0x00200000 2 2 $_TARGETNAME # # FIX ME, Add support to # # (A) hard reset the board. # (B) Initialize the SDRAM on the board # ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/lpc1850_spifi_generic.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Generic LPC1850 board w/ SPIFI flash. # This config file is intended as an example of how to # use the lpcspifi flash driver, but it should be functional # for most LPC1850 boards utilizing SPIFI flash. set CHIPNAME lpc1850 source [find target/lpc1850.cfg] #A large working area greatly reduces flash write times set _WORKAREASIZE 0x4000 $_CHIPNAME.m3 configure -work-area-phys 0x10000000 -work-area-size $_WORKAREASIZE #Configure the flash bank; 0x14000000 is the base address for #lpc43xx/lpc18xx family micros. flash bank SPIFI_FLASH lpcspifi 0x14000000 0 0 0 $_CHIPNAME.m3 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/lpc4350_spifi_generic.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Generic LPC4350 board w/ SPIFI flash. # This config file is intended as an example of how to # use the lpcspifi flash driver, but it should be functional # for most LPC4350 boards utilizing SPIFI flash. set CHIPNAME lpc4350 source [find target/lpc4350.cfg] #Configure the flash bank; 0x14000000 is the base address for #lpc43xx/lpc18xx family micros. flash bank SPIFI_FLASH lpcspifi 0x14000000 0 0 0 $_CHIPNAME.m4 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/lubbock.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Intel "Lubbock" Development Board with PXA255 (dbpxa255) # Obsolete; this was Intel's original PXA255 development system # Board also had CPU cards for SA1100, PXA210, PXA250, and more. source [find target/pxa255.cfg] adapter srst delay 250 jtag_ntrst_delay 250 # NOTE: until after pinmux and such are set up, only CS0 is # available ... not 2nd bank of CFI, or FPGA, SRAM, ENET, etc. # CS0, CS1 -- two banks of CFI flash, 32 MBytes each # each bank is 32-bits wide, two 16-bit chips in parallel set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME cfi 0x04000000 0x02000000 2 4 $_TARGETNAME # CS2 low -- FPGA registers # CS2 high -- 1 MByte SRAM at 0x0a00.0000 ... last 64K for scratch $_TARGETNAME configure -work-area-phys 0x0a0f0000 $_TARGETNAME configure -event reset-assert-pre \ "$_TARGETNAME configure -work-area-size 0" # Make the hex led display a number, assuming CS2 is set up # and all digits have been enabled through the FPGA. proc hexled {u32} { mww 0x08000010 $u32 } # CS3 -- Ethernet # CS4 -- SA1111 # CS5 -- PCMCIA # NOTE: system console normally uses the FF UART connector proc lubbock_init {target} { echo "Initialize PXA255 Lubbock board" # (1) pinmux # GPSR0..GPSR2 mww 0x40e00018 0x00008000 mww 0x40e0001c 0x00FC0382 mww 0x40e00020 0x0001FFFF # GPDR0..GPDR2 mww 0x40e0000c 0x0060A800 mww 0x40e00010 0x00FF0382 mww 0x40e00014 0x0001C000 # GAFR0_[LU]..GAFR2_[LU] mww 0x40e00054 0x98400000 mww 0x40e00058 0x00002950 mww 0x40e0005c 0x000A9558 mww 0x40e00060 0x0005AAAA mww 0x40e00064 0xA0000000 mww 0x40e00068 0x00000002 # write PSSR, enable GPIOs mww 0x40f00000 0x00000020 # write LED ctrl register ... ones disable # high byte, 8 hex leds; low byte, 8 discretes mwh 0x08000040 0xf0ff hexled 0x0000 # (2) Address space setup # MSC0/MSC1/MSC2 mww 0x48000008 0x23f223f2 mww 0x4800000c 0x3ff1a441 mww 0x48000010 0x7ff97ff1 # pcmcia/cf mww 0x48000014 0x00000000 mww 0x48000028 0x00010504 mww 0x4800002c 0x00010504 mww 0x48000030 0x00010504 mww 0x48000034 0x00010504 mww 0x48000038 0x00004715 mww 0x4800003c 0x00004715 hexled 0x1111 # (3) SDRAM setup # REVISIT this looks dubious ... no refresh cycles mww 0x48000004 0x03CA4018 mww 0x48000004 0x004B4018 mww 0x48000004 0x000B4018 mww 0x48000004 0x000BC018 mww 0x48000000 0x00001AC8 mww 0x48000000 0x00001AC9 mww 0x48000040 0x00000000 # FIXME -- setup: # CLOCKS (and faster JTAG) # enable icache # FIXME SRAM isn't working # $target configure -work-area-size 0x10000 hexled 0x2222 flash probe 0 flash probe 1 hexled 0xcafe } $_TARGETNAME configure -event reset-init "lubbock_init $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/marsohod.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Marsohod CPLD Development and Education board # # http://marsohod.org/howtostart/plata # # Recommended MBFTDI programmer source [find interface/ftdi/mbftdi.cfg] adapter speed 2000 transport select jtag # Altera MAXII EPM240T100C CPLD source [find cpld/altera-epm240.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/marsohod2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Marsohod2 FPGA Development and Education board # # http://www.marsohod.org/prodmarsohod2 # # Built-in MBFTDI programmer source [find interface/ftdi/mbftdi.cfg] adapter speed 2000 transport select jtag # Cyclone III EP3C10E144 FPGA source [find fpga/altera-ep3c10.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/marsohod3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Marsohod3 FPGA Development and Education board # # http://www.marsohod.org/plata-marsokhod3 # # Built-in MBFTDI programmer source [find interface/ftdi/mbftdi.cfg] adapter speed 2000 transport select jtag # MAX10 10M50SAE144C8GES FPGA source [find fpga/altera-10m50.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/mbed-lpc11u24.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an mbed eval board with a single NXP LPC11U24 chip. # http://mbed.org/handbook/mbed-NXP-LPC11U24 # source [find interface/cmsis-dap.cfg] # NXP LPC11U24 Cortex-M0 with 32kB Flash and 8kB SRAM set WORKAREASIZE 0x2000 source [find target/lpc11xx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/mbed-lpc1768.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an mbed eval board with a single NXP LPC1768 chip. # http://mbed.org/handbook/mbed-NXP-LPC1768 # source [find interface/cmsis-dap.cfg] source [find target/lpc17xx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/mcb1700.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Keil MCB1700 PCB with 1768 # # Reset init script sets it to 100MHz set CCLK 100000 source [find target/lpc17xx.cfg] global MCB1700_CCLK set MCB1700_CCLK $CCLK $_TARGETNAME configure -event reset-start { # Start *real slow* as we do not know the # state the boot rom left the clock in adapter speed 10 } # Set up 100MHz clock to CPU $_TARGETNAME configure -event reset-init { # PLL0CON: Disable PLL mww 0x400FC080 0x00000000 # PLLFEED mww 0x400FC08C 0x000000AA # PLLFEED mww 0x400FC08C 0x00000055 # CCLK=PLL/4 (=100 MHz) mww 0x400FC104 0x00000003 # CLKSRCSEL: Clock source = internal RC oscillator mww 0x400FC10C 0x00000000 # PLL0CFG: M=50,N=1 -> PLL=400 MHz mww 0x400FC084 0x00000031 # PLLFEED mww 0x400FC08C 0x000000AA # PLLFEED mww 0x400FC08C 0x00000055 # PLL0CON: Enable PLL mww 0x400FC080 0x00000001 # PLLFEED mww 0x400FC08C 0x000000AA # PLLFEED mww 0x400FC08C 0x00000055 sleep 50 # PLL0CON: Connect PLL mww 0x400FC080 0x00000003 # PLLFEED mww 0x400FC08C 0x000000AA # PLLFEED mww 0x400FC08C 0x00000055 # Dividing CPU clock by 8 should be pretty conservative # # global MCB1700_CCLK adapter speed [expr {$MCB1700_CCLK / 8}] # Do not remap 0x0000-0x0020 to anything but the flash (i.e. select # "User Flash Mode" where interrupt vectors are _not_ remapped, # and reside in flash instead). # # See Table 612. Memory Mapping Control register (MEMMAP - 0x400F C040) bit description # Bit Symbol Value Description Reset # value # 0 MAP Memory map control. 0 # 0 Boot mode. A portion of the Boot ROM is mapped to address 0. # 1 User mode. The on-chip Flash memory is mapped to address 0. # 31:1 - Reserved. The value read from a reserved bit is not defined. NA # # http://ics.nxp.com/support/documents/microcontrollers/?scope=LPC1768&type=user mww 0x400FC040 0x01 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/microchip_explorer16.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Microchip Explorer 16 with PIC32MX360F512L PIM module. # http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en024858 # TAPID for PIC32MX360F512L set CPUTAPID 0x30938053 # use 32k working area set WORKAREASIZE 32768 source [find target/pic32mx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/microchip_sama5d27_som1_kit1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Microchip SAMA5D27-SOM1-EK1 # https://www.microchip.com/DevelopmentTools/ProductDetails/PartNO/ATSAMA5D27-SOM1-EK1 # This board provide two jtag interfaces: # J11 - 10 pin interface # J10 - USB interface connected to the J-Link-OB. # This functionality is implemented with an ATSAM3U4C microcontroller and # provides JTAG functions and a bridge USB/Serial debug port (CDC). # # Jumper J7 disables the J-Link-OB-ATSAM3U4C JTAG functionality. # - Jumper J7 not installed: J-Link-OB-ATSAM3U4C is enabled and fully functional. # - Jumper J7 installed: J-Link-OB-ATSAM3U4C is disabled and an external JTAG # controller can be used through the 10-pin JTAG port J11. source [find interface/jlink.cfg] reset_config srst_only source [find target/at91sama5d2.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/microchip_same51_curiosity_nano.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Microchip SAME51 Curiosity Nano evaluation kit. # # https://www.microchip.com/en-us/development-tool/EV76S68A # source [find interface/cmsis-dap.cfg] set CHIPNAME same51 source [find target/atsame5x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/microchip_same54_xplained_pro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Microchip (former Atmel) SAM E54 Xplained Pro evaluation kit. # http://www.microchip.com/developmenttools/productdetails.aspx?partno=atsame54-xpro # source [find interface/cmsis-dap.cfg] set CHIPNAME same54 source [find target/atsame5x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/microchip_saml11_xplained_pro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Microchip (formerly Atmel) SAM L11 Xplained Pro Evaluation Kit. # https://www.microchip.com/DevelopmentTools/ProductDetails/dm320205 # source [find interface/cmsis-dap.cfg] adapter speed 1000 set CHIPNAME saml11 source [find target/atsaml1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/mini2440.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #------------------------------------------------------------------------- # Mini2440 Samsung s3c2440A Processor with 64MB DRAM, 64MB NAND, 2 MB N0R # NOTE: Configured for NAND boot (switch S2 in NANDBOOT) # 64 MB NAND (Samsung K9D1208V0M) # B Findlay 08/09 # # ----------- Important notes to help you on your way ---------- # README: # NOR/NAND Boot Switch - I have not read the vivi source, but from # what I could tell from reading the registers it appears that vivi # loads itself into DRAM and then flips NFCONT (0x4E000004) bits # Mode (bit 0 = 1), and REG_nCE (bit 1 = 0) which maps the NAND # FLASH at the bottom 64MB of memory. This essentially takes the # NOR Flash out of the circuit so you can't trash it. # # I adapted the samsung_s3c2440.cfg file which is why I did not # include "source [find target/samsung_s3c2440.cfg]". I believe # the -work-area-phys 0x200000 is incorrect, but also had to pad # some additional resets. I didn't modify it as if it is working # for someone, the work-area-phys is not used by most. # # JTAG ADAPTER SPECIFIC # IMPORTANT! Any JTAG device that uses ADAPTIVE CLOCKING will likely # FAIL as the pin RTCK on the mini2440 10 pin JTAG Conn doesn't exist. # This is Pin 11 (RTCK) on 20 pin JTAG connector. Therefore it is # necessary to FORCE setting the clock. Normally this should be configured # in the openocd.cfg file, but was placed here as it can be a tough # problem to figure out. THIS MAY NOT FIX YOUR PROBLEM.. I modified # the openOCD driver jlink.c and posted it here. It may eventually end # up changed in openOCD, but its a hack in the driver and really should # be in the jtag layer (core.c me thinks), but haven't done it yet. My # hack for jlink.c may be found here. # # http://forum.sparkfun.com/viewtopic.php?t=16763&sid=946e65abdd3bab39cc7d90dee33ff135 # # Note: Also if you have a USB JTAG, you will need the USB library installed # on your system "libusb-dev" or the make of openocd will fail. I *think* # it's apt-get install libusb-dev. When I made my config I only included # --enable-jlink and --enable-usbdevs # # I HAVE NOT Tested this thoroughly, so there could still be problems. # But it should get you way ahead of the game from where I started. # If you find problems (and fixes) please post them to # openocd-development@lists.berlios.de and join the developers and # check in fixes to this and anything else you find. I do not # provide support, but if you ask really nice and I see anything # obvious I will tell you.. mostly just dig, fix, and submit to openocd. # # best! brfindla@yahoo.com Nashua, NH USA # # Recommended resources: # - first two are the best Mini2440 resources anywhere # - maintained by buserror... thanks guy! # # http://bliterness.blogspot.com/ # http://code.google.com/p/mini2440/ # # others.... # # http://forum.sparkfun.com/viewforum.php?f=18 # http://labs.kernelconcepts.de/Publications/Micro24401/ # http://www.friendlyarm.net/home # http://www.amontec.com/jtag_pinout.shtml # #------------------------------------------------------------------------- # # # Your openocd.cfg file should contain: # source [find interface/<yourjtag>.cfg] # source [find board/mini2440.cfg] # # # # FIXME use some standard target config, maybe create one from this # # source [find target/...cfg] #------------------------------------------------------------------------- # Target configuration for the Samsung 2440 system on chip # Tested on a S3C2440 Evaluation board by keesj # Processor : ARM920Tid(wb) rev 0 (v4l) # Info: JTAG tap: s3c2440.cpu tap/device found: 0x0032409d # (Manufacturer: 0x04e, Part: 0x0324, Version: 0x0) #------------------------------------------------------------------------- if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME s3c2440 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a bigendian set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0032409d } #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm920t -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x40000000 -work-area-size 0x4000 -work-area-backup 1 #reset configuration adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst #------------------------------------------------------------------------- # JTAG ADAPTER SPECIFIC # IMPORTANT! See README at top of this file. #------------------------------------------------------------------------- adapter speed 12000 #------------------------------------------------------------------------- # GDB Setup #------------------------------------------------------------------------- gdb_breakpoint_override hard #------------------------------------------------ # ARM SPECIFIC #------------------------------------------------ targets # arm7_9 dcc_downloads enable # arm7_9 fast_memory_access enable nand device s3c2440 0 adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst init echo " " echo "-------------------------------------------" echo "--- login with - telnet localhost 4444 ---" echo "--- then type help_2440 ---" echo "-------------------------------------------" echo " " #------------------------------------------------ # Processor Initialialization # Note: Processor writes can only occur when # the state is in SYSTEM. When you call init_2440 # one of the first lines will tell you what state # you are in. If a linux image is booting # when you run this, it will not work # a vivi boot loader will run with this just # fine. The reg values were obtained by a combination # of figuring them out fromt the manual, and looking # at post vivi values with the debugger. Don't # place too much faith in them, but seem to work. #------------------------------------------------ proc init_2440 { } { halt s3c2440.cpu curstate #----------------------------------------------- # Set Processor Clocks - mini2440 xtal=12mHz # we set main clock for 405mHZ # we set the USB Clock for 48mHz # OM2 OM3 pulled to ground so main clock and # usb clock are off 12mHz xtal #----------------------------------------------- mww phys 0x4C000014 0x00000005 ;# Clock Divider control Reg mww phys 0x4C000000 0xFFFFFFFF ;# LOCKTIME count register mww phys 0x4C000008 0x00038022 ;# UPPLCON USB clock config Reg mww phys 0x4C000004 0x0007F021 ;# MPPLCON Proc clock config Reg #----------------------------------------------- # Configure Memory controller # BWSCON configures all banks, NAND, NOR, DRAM # DRAM - 64MB - 32 bit bus, uses BANKCON6 BANKCON7 #----------------------------------------------- mww phys 0x48000000 0x22111112 ;# BWSCON - Bank and Bus Width mww phys 0x48000010 0x00001112 ;# BANKCON4 - ? mww phys 0x4800001c 0x00018009 ;# BANKCON6 - DRAM mww phys 0x48000020 0x00018009 ;# BANKCON7 - DRAM mww phys 0x48000024 0x008E04EB ;# REFRESH - DRAM mww phys 0x48000028 0x000000B2 ;# BANKSIZE - DRAM mww phys 0x4800002C 0x00000030 ;# MRSRB6 - DRAM mww phys 0x48000030 0x00000030 ;# MRSRB7 - DRAM #----------------------------------------------- # Now port configuration for enables for memory # and other stuff. #----------------------------------------------- mww phys 0x56000000 0x007FFFFF ;# GPACON mww phys 0x56000010 0x00295559 ;# GPBCON mww phys 0x56000018 0x000003FF ;# GPBUP (PULLUP ENABLE) mww phys 0x56000014 0x000007C2 ;# GPBDAT mww phys 0x56000020 0xAAAAA6AA ;# GPCCON mww phys 0x56000028 0x0000FFFF ;# GPCUP mww phys 0x56000024 0x00000020 ;# GPCDAT mww phys 0x56000030 0xAAAAAAAA ;# GPDCON mww phys 0x56000038 0x0000FFFF ;# GPDUP mww phys 0x56000040 0xAAAAAAAA ;# GPECON mww phys 0x56000048 0x0000FFFF ;# GPEUP mww phys 0x56000050 0x00001555 ;# GPFCON mww phys 0x56000058 0x0000007F ;# GPFUP mww phys 0x56000054 0x00000000 ;# GPFDAT mww phys 0x56000060 0x00150114 ;# GPGCON mww phys 0x56000068 0x0000007F ;# GPGUP mww phys 0x56000070 0x0015AAAA ;# GPHCON mww phys 0x56000078 0x000003FF ;# GPGUP } proc flash_config { } { #----------------------------------------- # Finish Flash Configuration #----------------------------------------- halt #flash configuration (K9D1208V0M: 512Mbit, x8, 3.3V, Mode: Normal, 1st gen) nand probe 0 nand list } proc flash_uboot { } { # flash the u-Boot binary and reboot into it init_2440 flash_config nand erase 0 0x0 0x40000 nand write 0 /tftpboot/u-boot-nand512.bin 0 oob_softecc_kw resume } proc load_uboot { } { echo " " echo " " echo "----------------------------------------------------------" echo "---- Load U-Boot into RAM and execute it. ---" echo "---- NOTE: loads, partially runs, and hangs ---" echo "---- U-Boot is fine, this image runs from vivi. ---" echo "---- I burned u-boot into NAND so I didn't finish ---" echo "---- debugging it. I am leaving this here as it is ---" echo "---- part of the way there if you want to fix it. ---" echo "---- ---" echo "---- mini2440 U-boot here: ---" echo "---- http://repo.or.cz/w/u-boot-openmoko/mini2440.git ---" echo "---- Also this: ---" echo "---- http://code.google.com/p/mini2440/wiki/MiniBringup --" echo "----------------------------------------------------------" init_2440 echo "Loading /tftpboot/u-boot-nand512.bin" load_image /tftpboot/u-boot-nand512.bin 0x33f80000 bin echo "Verifying image...." verify_image /tftpboot/u-boot-nand512.bin 0x33f80000 bin echo "jumping to u-boot" #bp 0x33f80068 4 hw reg 0 0 reg 1 0 reg 2 0 reg 3 0 reg 4 0x33f80000 resume 0x33f80000 } # this may help a little bit debugging the load_uboot proc s {} { step reg arm disassemble 0x33F80068 0x10 } proc help_2440 {} { echo " " echo " " echo "-----------------------------------------------------------" echo "---- The following mini2440 funcs are supported ----" echo "---- init_2440 - initialize clocks, DRAM, IO ----" echo "---- flash_config - configures nand flash ----" echo "---- load_uboot - loads uboot into ram ----" echo "---- flash_uboot - flashes uboot to nand (untested) ----" echo "---- help_2440 - this help display ----" echo "-----------------------------------------------------------" echo " " echo " " } #---------------------------------------------------------------------------- #----------------------------------- END ------------------------------------ #---------------------------------------------------------------------------- ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/mini6410.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Target configuration for the Samsung s3c6410 system on chip # Tested on a tiny6410 # Processor : ARM1176 # Info : JTAG tap: s3c6410.etb tap/device found: 0x2b900f0f (mfg: 0x787, part: 0xb900, ver: 0x2) # Info : JTAG tap: s3c6410.cpu tap/device found: 0x07b76f0f (mfg: 0x787, part: 0x7b76, ver: 0x0) source [find target/samsung_s3c6410.cfg] proc init_6410 {} { halt reg cpsr 0x1D3 arm mcr 15 0 15 2 4 0x70000013 #----------------------------------------------- # Clock and Timer Setting #----------------------------------------------- mww 0x7e004000 0 ;# WATCHDOG - Disable mww 0x7E00F120 0x0003 ;# MEM_SYS_CFG - CS0:8 bit, Mem1:32bit, CS2=NAND #mww 0x7E00F120 0x1000 ;# MEM_SYS_CFG - CS0:16bit, Mem1:32bit, CS2=SROMC #mww 0x7E00F120 0x1002 ;# MEM_SYS_CFG - CS0:16bit, Mem1:32bit, CS2=OND mww 0x7E00F900 0x805e ;# OTHERS - Change SYNCMUX[6] to “1” sleep 1000 mww 0x7E00F900 0x80de ;# OTHERS - Assert SYNCREQ&VICSYNCEN to “1”(rb1004modify) sleep 1000 ;# - Others[11:8] to 0xF mww 0x7E00F000 0xffff ;# APLL_LOCK - APLL LockTime mww 0x7E00F004 0xffff ;# MPLL_LOCK - MPLL LockTime mww 0x7E00F020 0x1047310 ;# CLK_DIV0 - ARMCLK:HCLK:PCLK = 1:4:16 mww 0x7E00F00c 0x81900302 ;# APLL_CON - A:400, P:3, S:2 => 400MHz mww 0x7E00F010 0x81900303 ;# MPLL_CON - M:400, P:3, S:3 => 200MHz mww 0x7E00F01c 0x3 ;# CLK_SRC - APLL,MPLL Clock Select #----------------------------------------------- # DRAM initialization #----------------------------------------------- mww 0x7e001004 0x4 ;# P1MEMCCMD - Enter the config state mww 0x7e001010 0x30C ;# P1REFRESH - Refresh Period register (7800ns), 100MHz # mww 0x7e001010 0x40e ;# P1REFRESH - Refresh Period register (7800ns), 133MHz mww 0x7e001014 0x6 ;# P1CASLAT - CAS Latency = 3 mww 0x7e001018 0x1 ;# P1T_DQSS mww 0x7e00101c 0x2 ;# P1T_MRD mww 0x7e001020 0x7 ;# P1T_RAS - 45 ns mww 0x7e001024 0xA ;# P1T_RC - 67.5 ns mww 0x7e001028 0xC ;# P1T_RCD - 22.5 ns mww 0x7e00102C 0x10B ;# P1T_RFC - 80 ns mww 0x7e001030 0xC ;# P1T_RP - 22.5 ns mww 0x7e001034 0x3 ;# P1T_RRD - 15 ns mww 0x7e001038 0x3 ;# P1T_WR - 15 ns mww 0x7e00103C 0x2 ;# P1T_WTR mww 0x7e001040 0x2 ;# P1T_XP mww 0x7e001044 0x11 ;# P1T_XSR - 120 ns mww 0x7e001048 0x11 ;# P1T_ESR #----------------------------------------------- # Memory Configuration Registers #----------------------------------------------- mww 0x7e00100C 0x00010012 ;# P1MEMCFG - 1 CKE, 1Chip, 4burst, Alw, AP[10],ROW/Column bit mww 0x7e00104C 0x0B41 ;# P1MEMCFG2 - Read delay 1 Cycle, mDDR, 32bit, Sync. mww 0x7e001200 0x150F0 ;# CHIP_N_CFG - 0x150F0 for 256M, 0x150F8 for 128M #----------------------------------------------- # Memory Direct Commands #----------------------------------------------- mww 0x7e001008 0xc0000 ;# Chip0 Direct Command :NOP5 mww 0x7e001008 0x0 ;# Chip0 Direct Command :PreCharge al mww 0x7e001008 0x40000 ;# Chip0 Direct Command :AutoRefresh mww 0x7e001008 0x40000 ;# Chip0 Direct Command :AutoRefresh mww 0x7e001008 0xA0000 ;# EMRS, DS:Full, PASR:Full mww 0x7e001008 0x80032 ;# MRS, CAS3, BL4 mww 0x7e001004 0x0 ;# Enable DMC1 } proc install_6410_uboot {} { # write U-boot magic number mww 0x50000000 0x24564236 mww 0x50000004 0x20764316 load_image u-boot_nand-ram256.bin 0x50008000 bin load_image u-boot_nand-ram256.bin 0x57E00000 bin #Kick in reg pc 0x57E00000 resume } proc init_6410_flash {} { halt nand probe 0 nand list } adapter speed 1000 adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst gdb_breakpoint_override hard targets nand device $_CHIPNAME.flash s3c6400 $_CHIPNAME.cpu init echo " " echo " " echo "-------------------------------------------------------------------" echo "---- The following mini6410/tiny6410 functions are available: ----" echo "---- init_6410 - initialize clock, timer, DRAM ----" echo "---- init_6410_flash - initializes NAND flash support ----" echo "---- install_6410_uboot - copies u-boot image into RAM and ----" echo "---- runs it ----" echo "-------------------------------------------------------------------" echo " " echo " " ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/minispartan6.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # https://www.scarabhardware.com/minispartan6/ source [find interface/ftdi/minispartan6.cfg] source [find cpld/xilinx-xc6s.cfg] source [find cpld/jtagspi.cfg] # example command to read the device dna of the FPGA on the board; # openocd -f board/minispartan6.cfg -c "init;xc6s_print_dna xc6s.tap;shutdown" # example command to write bitstream # openocd -f board/minispartan6.cfg -c "init;\ # jtagspi_init 0 bscan_spi_xc6slx??.bit;\ # jtagspi_program bitstream.bin 0;\ # xc6s_program xc6s.tap;\ # shutdown" # # jtagspi flash procies can be found in the contrib/loaders/flash/fpga/ # directory, with prebuilt versions available at # https://github.com/jordens/bscan_spi_bitstreams # # For the SLX25 variant, use # - https://github.com/jordens/bscan_spi_bitstreams/raw/master/bscan_spi_xc6slx25.bit # For the SLX9 variant, use # - https://github.com/jordens/bscan_spi_bitstreams/raw/master/bscan_spi_xc6slx9.bit ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/nds32_corvettef1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # ADP-Corvette-F1 R1.0 # http://www.andestech.com/en/products-solutions/andeshape-platforms/corvette-f1-r1/ # ADP-Corvette-F1 R2.0 # http://www.andestech.com/en/products-solutions/andeshape-platforms/corvette-f1-r2/ adapter speed 10000 adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 reset_config srst_only source [find target/nds32v5.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/nds32_xc7.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # ADP-XC7K160/410 # http://www.andestech.com/en/products-solutions/andeshape-platforms/adp-xc7k160-410/ source [find target/nds32v5.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/netgear-dg834v3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Netgear DG834v3 Router # Internal 4Kb RAM (@0x80000000) # Flash is located at 0x90000000 (CS0) and RAM is located at 0x94000000 (CS1) # set partition_list { loader { "Bootloader (ADAM2)" 0x90000000 0x00020000 } firmware { "Kernel+rootfs" 0x90020000 0x003d0000 } config { "Bootloader config space" 0x903f0000 0x00010000 } } source [find target/ti-ar7.cfg] # External 16MB SDRAM - disabled as we use internal sram #$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 0x00001000 # External 4MB NOR Flash set _FLASHNAME $_CHIPNAME.norflash flash bank $_FLASHNAME cfi 0x90000000 0x00400000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/netgear-wg102.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/atheros_ar2313.cfg] reset_config trst_and_srst $_TARGETNAME configure -event reset-init { mips32 cp0 12 0 0x10400000 # configure sdram controller mww 0xb8300004 0x0e03 sleep 100 mww 0xb8300004 0x0e01 mww 0xb8300008 0x10 sleep 500 mww 0xb8300004 0x0e02 mww 0xb8300000 0x6c0088 mww 0xb8300008 0x57e mww 0xb8300004 0x0e00 mww 0xb8300004 0xb00 # configure flash # 0x00000001 - 0x01 << FLASHCTL_IDCY_S # 0x000000e0 - 0x07 << FLASHCTL_WST1_S # FLASHCTL_RBLE 0x00000400 - Read byte lane enable # 0x00003800 - 0x07 << FLASHCTL_WST2_S # FLASHCTL_AC_8M 0x00060000 - Size of flash # FLASHCTL_E 0x00080000 - Flash bank enable (added) # FLASHCTL_WP 0x04000000 - write protect. If used, CFI mode wont work!! # FLASHCTL_MWx16 0x10000000 - 16bit mode. Do not use it!! # FLASHCTL_MWx8 0x00000000 - 8bit mode. mww 0xb8400000 0x000d3ce1 } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0xbe000000 0x00400000 1 1 $_TARGETNAME x16_as_x8 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/nordic_nrf51822_mkit.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Nordic Semiconductor PCA10024 board (aka nRF51822-mKIT) # source [find interface/cmsis-dap.cfg] source [find target/nrf51.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/nordic_nrf51_dk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Nordic Semiconductor NRF51 Development Kit (nRF6824) # source [find interface/jlink.cfg] transport select swd source [find target/nrf51.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/nordic_nrf52_dk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Nordic Semiconductor NRF52 Development Kit (nRF52832) # source [find interface/jlink.cfg] transport select swd source [find target/nrf52.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/nordic_nrf52_ftx232.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # nordic module NRF52 (nRF52832/52840) attached to an adafruit ft232h module # or any FT232H/FT2232H/FT4232H based board/module # source [find interface/ftdi/ft232h-module-swd.cfg] #source [find interface/ftdi/minimodule-swd.cfg] transport select swd source [find target/nrf52.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/novena-internal-fpga.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Novena open hardware and F/OSS-friendly computing platform # # Design documentation: # http://www.kosagi.com/w/index.php?title=Novena_PVT_Design_Source # # +-------------+--------------+------+-------+---------+ # | Pad name | Schematic | GPIO | sysfs | JTAG | # +-------------+--------------+------+-------+---------+ # | DISP0_DAT13 | FPGA_RESET_N | 5-07 | 135 | RESET_N | # | DISP0_DAT14 | FPGA_TCK | 5-08 | 136 | TCK | # | DISP0_DAT15 | FPGA_TDI | 5-09 | 137 | TDI | # | DISP0_DAT16 | FPGA_TDO | 5-10 | 138 | TDO | # | DISP0_DAT17 | FPGA_TMS | 5-11 | 139 | TMS | # +-------------+--------------+------+-------+---------+ adapter driver sysfsgpio transport select jtag # TCK TMS TDI TDO sysfsgpio jtag_nums 136 139 137 138 source [find cpld/xilinx-xc6s.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/npcx_evb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Nuvoton NPCX Evaluation Board source [find interface/jlink.cfg] transport select swd source [find target/npcx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/numato_mimas_a7.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Numato Mimas A7 - Artix 7 FPGA Board # # https://numato.com/product/mimas-a7-artix-7-fpga-development-board-with-ddr-sdram-and-gigabit-ethernet # # Note: Connect external DC power supply if programming a heavy design onto FPGA. # Programming while powering via USB may lead to programming failure. # Therefore, prefer external power supply. adapter driver ftdi ftdi device_desc "Mimas Artix 7 FPGA Module" ftdi vid_pid 0x2a19 0x1009 # channel 0 is for custom purpose by users (like uart, fifo etc) # channel 1 is reserved for JTAG (by-default) or SPI (possible via changing solder jumpers) ftdi channel 1 ftdi tdo_sample_edge falling # FTDI Pin Layout # # +--------+-------+-------+-------+-------+-------+-------+-------+ # | DBUS7 | DBUS6 | DBUS5 | DBUS4 | DBUS3 | DBUS2 | DBUS1 | DBUS0 | # +--------+-------+-------+-------+-------+-------+-------+-------+ # | PROG_B | OE_N | NC | NC | TMS | TDO | TDI | TCK | # +--------+-------+-------+-------+-------+-------+-------+-------+ # # OE_N is JTAG buffer output enable signal (active-low) # PROG_B is not used, so left as input to FTDI. # ftdi layout_init 0x0008 0x004b reset_config none adapter speed 30000 source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/numato_opsis.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # http://opsis.hdmi2usb.tv # # The Numato Opsis is an FPGA based, open video platform. # # The board is supported via ixo-usb-jtag project. See the # interface/usb-jtag.cfg for more information. source [find interface/usb-jtag.cfg] source [find cpld/xilinx-xc6s.cfg] source [find cpld/jtagspi.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/nxp_frdm-k64f.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an NXP Freedom eval board with a single MK64FN1M0VLL12 chip. # https://www.nxp.com/design/development-boards/freedom-development-boards/mcu-boards/freedom-development-platform-for-kinetis-k64-k63-and-k24-mcus:FRDM-K64F # source [find interface/cmsis-dap.cfg] # Set working area to 16 KiB set WORKAREASIZE 0x4000 set CHIPNAME k64f reset_config srst_only source [find target/kx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/nxp_frdm-ls1012a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # NXP FRDM-LS1012A (Freedom) # # # NXP Kinetis K20 # source [find interface/cmsis-dap.cfg] transport select jtag # Also offers a 10-pin 0.05" CoreSight JTAG connector. source [find target/ls1012a.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/nxp_imx7sabre.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP IMX7SABRE board # use on-board JTAG header transport select jtag # set a safe speed, can be overridden adapter speed 1000 # reset configuration has TRST and SRST support reset_config trst_and_srst srst_push_pull # need at least 100ms delay after SRST release for JTAG adapter srst delay 100 # source the target file source [find target/imx7.cfg] # import mrw proc source [find mem_helper.tcl] # function to disable the on-chip watchdog proc imx7_disable_wdog { } { # echo "disable watchdog power-down counter" mwh phys 0x30280008 0x00 } proc imx7_uart_dbgconf { } { # disable response to debug_req signal for uart1 mww phys 0x308600b4 0x0a60 } proc check_bits_set_32 { addr mask } { while { [expr {[mrw $addr] & $mask} == 0] } { } } proc apply_dcd { } { # echo "apply dcd" mww phys 0x30340004 0x4F400005 # Clear then set bit30 to ensure exit from DDR retention mww phys 0x30360388 0x40000000 mww phys 0x30360384 0x40000000 mww phys 0x30391000 0x00000002 mww phys 0x307a0000 0x01040001 mww phys 0x307a01a0 0x80400003 mww phys 0x307a01a4 0x00100020 mww phys 0x307a01a8 0x80100004 mww phys 0x307a0064 0x00400046 mww phys 0x307a0490 0x00000001 mww phys 0x307a00d0 0x00020083 mww phys 0x307a00d4 0x00690000 mww phys 0x307a00dc 0x09300004 mww phys 0x307a00e0 0x04080000 mww phys 0x307a00e4 0x00100004 mww phys 0x307a00f4 0x0000033f mww phys 0x307a0100 0x09081109 mww phys 0x307a0104 0x0007020d mww phys 0x307a0108 0x03040407 mww phys 0x307a010c 0x00002006 mww phys 0x307a0110 0x04020205 mww phys 0x307a0114 0x03030202 mww phys 0x307a0120 0x00000803 mww phys 0x307a0180 0x00800020 mww phys 0x307a0184 0x02000100 mww phys 0x307a0190 0x02098204 mww phys 0x307a0194 0x00030303 mww phys 0x307a0200 0x00000016 mww phys 0x307a0204 0x00171717 mww phys 0x307a0214 0x04040404 mww phys 0x307a0218 0x0f040404 mww phys 0x307a0240 0x06000604 mww phys 0x307a0244 0x00000001 mww phys 0x30391000 0x00000000 mww phys 0x30790000 0x17420f40 mww phys 0x30790004 0x10210100 mww phys 0x30790010 0x00060807 mww phys 0x307900b0 0x1010007e mww phys 0x3079009c 0x00000d6e mww phys 0x30790020 0x08080808 mww phys 0x30790030 0x08080808 mww phys 0x30790050 0x01000010 mww phys 0x30790050 0x00000010 mww phys 0x307900c0 0x0e407304 mww phys 0x307900c0 0x0e447304 mww phys 0x307900c0 0x0e447306 check_bits_set_32 0x307900c4 0x1 mww phys 0x307900c0 0x0e447304 mww phys 0x307900c0 0x0e407304 mww phys 0x30384130 0x00000000 mww phys 0x30340020 0x00000178 mww phys 0x30384130 0x00000002 mww phys 0x30790018 0x0000000f check_bits_set_32 0x307a0004 0x1 } # disable internal reset-assert handling to # allow reset-init to work $_TARGETNAME.0 configure -event reset-assert "" $_TARGETNAME.1 configure -event reset-assert "" $_TARGETNAME_2 configure -event reset-assert "" $_TARGETNAME.0 configure -event reset-init { global _CHIPNAME imx7_disable_wdog imx7_uart_dbgconf apply_dcd $_CHIPNAME.dap memaccess 0 } target smp $_TARGETNAME.0 $_TARGETNAME.1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/nxp_lpc-link2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # NXP LPC-Link2 # # http://www.nxp.com/board/OM13054.html # https://www.lpcware.com/lpclink2 # http://embeddedartists.com/products/lpcxpresso/lpclink2.php # source [find target/lpc4370.cfg] # W25Q80BVSSIG w/ 1 MB flash flash bank SPIFI_FLASH lpcspifi 0x14000000 0 0 0 $_CHIPNAME.m4 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/nxp_mcimx8m-evk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # configuration file for NXP MC-IMX8M-EVK # # only JTAG supported transport select jtag # set a safe JTAG clock speed, can be overridden adapter speed 1000 # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive adapter srst delay 70 # board has an i.MX8MQ with 4 Cortex-A53 cores set CHIPNAME imx8mq set CHIPCORES 4 # source SoC configuration source [find target/imx8m.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/nxp_rdb-ls1046a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LS1046ARDB (Reference Design Board) # This is for the "console" USB port on the front panel # You must ensure that SW4-7 is in the "off" position # NXP K20 # The firmware implements the old CMSIS-DAP v1 USB HID interface # You must pass --enable-cmsis-dap to ./configure to enable it source [find interface/cmsis-dap.cfg] transport select jtag reset_config srst_only source [find target/ls1046a.cfg] # The adapter can't handle 10MHz adapter speed 5000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/nxp_rdb-ls1088a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LS1088ARDB (Reference Design Board) # This is for the "main" JTAG connector J55 transport select jtag reset_config srst_only # To access the CPLD, populate J48 and add `-c 'set CWTAP 1'` to your command # line. At the time of this writing, programming is unsupported. if { [info exists CWTAP] } { source [find cpld/altera-epm240.cfg] } else { source [find target/ls1088a.cfg] } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/olimex_LPC2378STK.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ##################################################### # Olimex LPC2378STK eval board # # http://olimex.com/dev/lpc-2378stk.html # # Author: Sten, debian@sansys-electronic.com ##################################################### # source [find target/lpc2378.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/olimex_lpc_h2148.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Olimex LPC-H2148 eval board # # http://www.olimex.com/dev/lpc-h2148.html # source [find target/lpc2148.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/olimex_sam7_ex256.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Olimex SAM7-EX256 has a single Atmel at91sam7ex256 on it. source [find target/at91sam7x256.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/olimex_sam7_la2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/at91sam7a2.cfg] # delays needed to get stable reads of cpu state jtag_ntrst_delay 10 adapter srst delay 200 # board uses pullup and connects only srst reset_config srst_open_drain # srst is connected to NRESET of CPU and fully resets everything... reset_config srst_only srst_pulls_trst adapter speed 1 $_TARGETNAME configure -event reset-start { adapter speed 1 } $_TARGETNAME configure -event reset-init { # init script from http://www.mikrocontroller.net/topic/107462 # AT91SAM7A2 # AMC (advanced memory controller) echo "setting up AMC" # AMC_CS0 - FLASH 1MB (0x40000000-0x400FFFFF) + DM9000E (0x40100000) mww 0xFFE00000 0x40003EBD # AMC_CS1 - RAM low 2MB (0x40400000-0x405FFFFF) mww 0xFFE00004 0x404030A9 # AMC_CS2 - RAM high 2MB (0x40800000-0x405FFFFF) #mww 0xFFE00008 0x404030A9 # changed to 0x40_8_ mww 0xFFE00008 0x408030A9 # AMC_MCR mww 0xFFE00024 0x00000004 # AMC_RCR force remap mww 0xFFE00020 0x00000001 echo "set up AMC" sleep 100 # the following base addresses from the original script did not correspond to those from datasheet # changed bases from 0xFF000000 to 0xFFF00000 # disable watchdog, to prevent unwanted resets mww 0xFFFA0068 0x00000000 echo "disabled watchdog" sleep 50 # disable PLL mww 0xFFFEC004 0x18070004 # PLL = 10 ==> Coreclock = 6Mhz*10/2 = 30 Mhz mww 0xFFFEC010 0x762D800A # enable PLL mww 0xFFFEC000 0x23050004 echo "set up pll" sleep 100 adapter speed 5000 } $_TARGETNAME arm7_9 dcc_downloads enable $_TARGETNAME arm7_9 fast_memory_access enable # remap: ram at 0, flash at 0x40000000, like reset-init above does $_TARGETNAME configure -work-area-phys 0x00000000 -work-area-size 0x4000 -work-area-backup 1 flash bank onboard.flash cfi 0x40000000 0x00100000 2 2 at91sam7a2.cpu # boot: ram at 0x300000, flash at 0x0, useful if board is in funny configuration #$_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x4000 -work-area-backup 1 #flash bank onboard1.flash cfi 0x00000000 0x00100000 2 2 at91sam7a2.cpu ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/olimex_sam9_l9260.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################ # Olimex SAM9-L9260 Development Board # # http://www.olimex.com/dev/sam9-L9260.html # # Atmel AT91SAM9260 : PLLA = 198.656 MHz, MCK = 99.328 MHz # PMC configured for external 18.432 MHz crystal # # 32-bit SDRAM : 2 x Samsung K4S561632J-UC75, 4M x 16Bit x 4 Banks # 8-bit NAND Flash : 1 x Samsung K9F4G08U0M, 512M x 8Bit # Dataflash : 1 x Atmel AT45DB161D, 16Mbit # ################################################################################ source [find target/at91sam9260.cfg] # NTRST_E jumper is enabled by default, so we don't need to override the reset # config. #reset_config srst_only $_TARGETNAME configure -event reset-start { # At reset, CPU runs at 32.768 kHz. JTAG frequency must be 6 times slower if # RCLK is not supported. jtag_rclk 5 halt # RSTC_MR : enable user reset, reset length is 64 slow clock cycles. MMU may # be enabled... use physical address. mww phys 0xfffffd08 0xa5000501 } $_TARGETNAME configure -event reset-init { mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog ## # Clock configuration for 99.328 MHz main clock. ## echo "Setting up clock" mww 0xfffffc20 0x00004001 ;# CKGR_MOR : enable main oscillator, 512 slow clock startup sleep 20 ;# wait 20 ms (need 15.6 ms for startup) mww 0xfffffc30 0x00000001 ;# PMC_MCKR : switch to main oscillator (18.432 MHz) sleep 10 ;# wait 10 ms mww 0xfffffc28 0x2060bf09 ;# CKGR_PLLAR : 18.432 MHz / 9 * 97 = 198.656 MHz, 63 slow clock startup sleep 20 ;# wait 20 ms (need 1.9 ms for startup) mww 0xfffffc30 0x00000101 ;# PMC_MCKR : no scale on proc clock, master is proc / 2 sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000102 ;# PMC_MCKR : switch to PLLA (99.328 MHz) # Increase JTAG speed to 6 MHz if RCLK is not supported. jtag_rclk 6000 arm7_9 dcc_downloads enable ;# Enable faster DCC downloads. ## # SDRAM configuration for 2 x Samsung K4S561632J-UC75, 4M x 16Bit x 4 Banks. ## echo "Configuring SDRAM" mww 0xfffff870 0xffff0000 ;# PIOC_ASR : select peripheral function for D15..D31 mww 0xfffff804 0xffff0000 ;# PIOC_PDR : disable PIO function for D15..D31 mww 0xffffef1c 0x00010002 ;# EBI_CSA : assign EBI CS1 to SDRAM, VDDIOMSEL set for +3V3 memory mww 0xffffea08 0x85237259 ;# SDRAMC_CR : configure SDRAM for Samsung chips mww 0xffffea00 0x1 ;# SDRAMC_MR : issue NOP command mww 0x20000000 0 mww 0xffffea00 0x2 ;# SDRAMC_MR : issue an 'All Banks Precharge' command mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue 8 x 'Auto-Refresh' command mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x3 ;# SDRAMC_MR : issue a 'Load Mode Register' command mww 0x20000000 0 mww 0xffffea00 0x0 ;# SDRAMC_MR : normal mode mww 0x20000000 0 mww 0xffffea04 0x2b6 ;# SDRAMC_TR : set refresh timer count to 7 us ## # NAND Flash Configuration for 1 x Samsung K9F4G08U0M, 512M x 8Bit. ## echo "Configuring NAND flash" mww 0xfffffc10 0x00000010 ;# PMC_PCER : enable PIOC clock mww 0xfffff800 0x00006000 ;# PIOC_PER : enable PIO function for 13(RDY/~BSY) and 14(~CS) mww 0xfffff810 0x00004000 ;# PIOC_OER : enable output on 14 mww 0xfffff814 0x00002000 ;# PIOC_ODR : disable output on 13 mww 0xfffff830 0x00004000 ;# PIOC_SODR : set 14 to disable NAND mww 0xfffff864 0x00002000 ;# PIOC_PUER : enable pull-up on 13 mww 0xffffef1c 0x0001000A ;# EBI_CSA : assign EBI CS3 to NAND, same settings as before mww 0xffffec30 0x00010001 ;# SMC_SETUP3 : 1 clock cycle setup for NRD and NWE mww 0xffffec34 0x03030303 ;# SMC_PULSE3 : 3 clock cycle pulse for all signals mww 0xffffec38 0x00050005 ;# SMC_CYCLE3 : 5 clock cycle NRD and NWE cycle mww 0xffffec3C 0x00020003 ;# SMC_MODE3 : NRD and NWE control, no NWAIT, 8-bit DBW, # 3 TDF cycles, no optimization mww 0xffffe800 0x00000001 ;# ECC_CR : reset the ECC parity registers mww 0xffffe804 0x00000002 ;# ECC_MR : page size is 2112 words (word is 8 bits) nand probe at91sam9260.flash ## # Dataflash configuration for 1 x Atmel AT45DB161D, 16Mbit ## echo "Setting up dataflash" mww 0xfffff404 0x00000807 ;# PIOA_PDR : disable PIO function for 0(SPI0_MISO), 1(SPI0_MOSI), # 2(SPI0_SPCK), and 11(SPI0_NPCS1) mww 0xfffff470 0x00000007 ;# PIOA_ASR : select peripheral A function for 0, 1, and 2 mww 0xfffff474 0x00000800 ;# PIOA_BSR : select peripheral B function for 11 mww 0xfffffc10 0x00001000 ;# PMC_PCER : enable SPI0 clock mww 0xfffc8000 0x00000080 ;# SPI0_CR : software reset SPI0 mww 0xfffc8000 0x00000080 ;# SPI0_CR : again to be sure mww 0xfffc8004 0x000F0011 ;# SPI0_MR : master mode with nothing selected mww 0xfffc8034 0x011a0302 ;# SPI0_CSR1 : capture on leading edge, 8-bits/tx. 33MHz baud, # 250ns delay before SPCK, 250ns b/n tx mww 0xfffc8004 0x000D0011 ;# SPI0_MR : same config, select NPCS1 mww 0xfffc8000 0x00000001 ;# SPI0_CR : enable SPI0 } nand device at91sam9260.flash at91sam9 at91sam9260.cpu 0x40000000 0xffffe800 at91sam9 cle 0 22 at91sam9 ale 0 21 at91sam9 rdy_busy 0 0xfffff800 13 at91sam9 ce 0 0xfffff800 14 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/olimex_stm32_h103.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Olimex STM32-H103 eval board # http://olimex.com/dev/stm32-h103.html # Work-area size (RAM size) = 20kB for STM32F103RB device set WORKAREASIZE 0x5000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/olimex_stm32_h107.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Olimex STM32-H107 # # http://olimex.com/dev/stm32-h107.html # # Work-area size (RAM size) = 64kB for STM32F107VC device set WORKAREASIZE 0x10000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/olimex_stm32_h405.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Olimex STM32-H405 eval board # https://www.olimex.com/Products/ARM/ST/STM32-H405/ # Work-area size (RAM size) = 128kB for STM32F405RG device set WORKAREASIZE 0x20000 source [find target/stm32f4x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/olimex_stm32_p107.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Olimex STM32-P107 # # http://olimex.com/dev/stm32-p107.html # # Work-area size (RAM size) = 64kB for STM32F107VC device set WORKAREASIZE 0x10000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/omap2420_h4.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # OMAP2420 SDP board ("H4") source [find target/omap2420.cfg] # NOTE: this assumes you're *NOT* using a TI-14 connector. reset_config trst_and_srst separate # Board configs can vary a *LOT* ... parts, jumpers, etc. # This GP board boots from cs0 using NOR (2x32M), and also # has 64M NAND on cs6. flash bank h4.u10 cfi 0x04000000 0x02000000 2 2 $_TARGETNAME flash bank h4.u11 cfi 0x06000000 0x02000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/openrd.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Marvell OpenRD source [find interface/ftdi/openrd.cfg] source [find target/feroceon.cfg] adapter speed 2000 $_TARGETNAME configure \ -work-area-phys 0x10000000 \ -work-area-size 65536 \ -work-area-backup 0 arm7_9 dcc_downloads enable # this assumes the hardware default peripherals location before u-Boot moves it set _FLASHNAME $_CHIPNAME.flash nand device $_FLASHNAME orion 0 0xd8000000 proc openrd_init { } { # We need to assert DBGRQ while holding nSRST down. # However DBGACK will be set only when nSRST is released. # Furthermore, the JTAG interface doesn't respond at all when # the CPU is in the WFI (wait for interrupts) state, so it is # possible that initial tap examination failed. So let's # re-examine the target again here when nSRST is asserted which # should then succeed. adapter assert srst feroceon.cpu arp_examine halt 0 adapter deassert srst wait_halt arm mcr 15 0 0 1 0 0x00052078 mww 0xD0001400 0x43000C30 ;# DDR SDRAM Configuration Register mww 0xD0001404 0x37543000 ;# Dunit Control Low Register mww 0xD0001408 0x22125451 ;# DDR SDRAM Timing (Low) Register mww 0xD000140C 0x00000A33 ;# DDR SDRAM Timing (High) Register mww 0xD0001410 0x000000CC ;# DDR SDRAM Address Control Register mww 0xD0001414 0x00000000 ;# DDR SDRAM Open Pages Control Register mww 0xD0001418 0x00000000 ;# DDR SDRAM Operation Register mww 0xD000141C 0x00000C52 ;# DDR SDRAM Mode Register mww 0xD0001420 0x00000004 ;# DDR SDRAM Extended Mode Register mww 0xD0001424 0x0000F17F ;# Dunit Control High Register mww 0xD0001428 0x00085520 ;# Dunit Control High Register mww 0xD000147c 0x00008552 ;# Dunit Control High Register mww 0xD0001504 0x0FFFFFF1 ;# CS0n Size Register mww 0xD0001508 0x10000000 ;# CS1n Base Register mww 0xD000150C 0x0FFFFFF5 ;# CS1n Size Register mww 0xD0001514 0x00000000 ;# CS2n Size Register mww 0xD000151C 0x00000000 ;# CS3n Size Register mww 0xD0001494 0x00120012 ;# DDR2 SDRAM ODT Control (Low) Register mww 0xD0001498 0x00000000 ;# DDR2 SDRAM ODT Control (High) REgister mww 0xD000149C 0x0000E40F ;# DDR2 Dunit ODT Control Register mww 0xD0001480 0x00000001 ;# DDR SDRAM Initialization Control Register mww 0xD0020204 0x00000000 ;# Main IRQ Interrupt Mask Register mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0010000 0x01111111 ;# MPP 0 to 7 mww 0xD0010004 0x11113322 ;# MPP 8 to 15 mww 0xD0010008 0x00001111 ;# MPP 16 to 23 mww 0xD0010418 0x003E07CF ;# NAND Read Parameters REgister mww 0xD001041C 0x000F0F0F ;# NAND Write Parameters Register mww 0xD0010470 0x01C7D943 ;# NAND Flash Control Register } proc openrd_reflash_uboot { } { # reflash the u-Boot binary and reboot into it openrd_init nand probe 0 nand erase 0 0x0 0xa0000 nand write 0 uboot.bin 0 oob_softecc_kw resume } proc openrd_load_uboot { } { # load u-Boot into RAM and execute it openrd_init load_image uboot.elf verify_image uboot.elf resume 0x00600000 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/or1k_generic.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # If you want to use the VJTAG TAP or the XILINX BSCAN, # you must set your FPGA TAP ID here set FPGATAPID 0x020b30dd # Choose your TAP core (VJTAG , MOHOR or XILINX_BSCAN) if { [info exists TAP_TYPE] == 0} { set TAP_TYPE VJTAG } # Set your chip name set CHIPNAME or1200 source [find target/or1k.cfg] # Set the servers polling period to 1ms (needed to JSP Server) poll_period 1 # Set the adapter speed adapter speed 3000 # Enable the target description feature gdb_target_description enable # Add a new register in the cpu register list. This register will be # included in the generated target descriptor file. # format is addreg [name] [address] [feature] [reg_group] addreg rtest 0x1234 org.gnu.gdb.or1k.group0 system # Override default init_reset proc init_reset {mode} { soft_reset_halt resume } # Target initialization init echo "Halting processor" halt foreach name [target names] { set y [$name cget -endian] set z [$name cget -type] puts [format "Chip is %s, Endian: %s, type: %s" \ $name $y $z] } set c_blue "\033\[01;34m" set c_reset "\033\[0m" puts [format "%sTarget ready...%s" $c_blue $c_reset] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/osk5912.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # http://omap.spectrumdigital.com/osk5912/ source [find target/omap5912.cfg] # NOTE: this assumes you're using the ARM 20-pin ("Multi-ICE") # JTAG connector, and accordingly have J1 connecting pins 1 & 2. # The TI-14 pin needs "trst_only", and J1 connecting 2 & 3. reset_config trst_and_srst separate # NOTE: boards with XOMAP parts wire nSRST to nPWRON_RESET. # That resets everything -- including JTAG and EmbeddedICE. # So they must use "reset_config srst_pulls_trst". # NOTE: an expansion board could add a trace connector ... if # it does, change this appropriately. And reset_config too, # assuming JTAG_DIS reroutes JTAG to that connector. etm config $_TARGETNAME 8 demultiplexed full dummy etm_dummy config $_TARGETNAME # standard boards populate two 16 MB chips, but manufacturing # options or an expansion board could change this config. flash bank osk.u1 cfi 0x00000000 0x01000000 2 2 $_TARGETNAME flash bank osk.u2 cfi 0x01000000 0x01000000 2 2 $_TARGETNAME proc osk5912_init {} { omap5912_reset # detect flash flash probe 0 flash probe 1 } $_TARGETNAME configure -event reset-init { osk5912_init } arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/phone_se_j100i.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Sony Ericsson J100I Phone # # more information can be found on # http://bb.osmocom.org/trac/wiki/SonyEricssonJ100i # source [find target/ti_calypso.cfg] # external flash set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x400000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/phytec_lpc3250.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/lpc3250.cfg] adapter srst delay 200 jtag_ntrst_delay 1 adapter speed 200 reset_config trst_and_srst separate arm7_9 dcc_downloads enable $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-start { arm7_9 fast_memory_access disable adapter speed 200 } $_TARGETNAME configure -event reset-end { adapter speed 6000 arm7_9 fast_memory_access enable } $_TARGETNAME configure -event reset-init { phytec_lpc3250_init } # Bare-bones initialization of core clocks and SDRAM proc phytec_lpc3250_init { } { # Set clock dividers # ARMCLK = 266.5 MHz # HCLK = 133.25 MHz # PERIPHCLK = 13.325 MHz mww 0x400040BC 0 mww 0x40004050 0x140 mww 0x40004040 0x4D mww 0x40004058 0x16250 # Init PLLs mww 0x40004044 0x006 sleep 1 busy mww 0x40004044 0x106 sleep 1 busy mww 0x40004044 0x006 sleep 1 busy mww 0x40004048 0x2 # Init SDRAM with 133 MHz timings mww 0x40028134 0x00FFFFFF mww 0x4002802C 0x00000008 mww 0x31080000 1 mww 0x31080008 0 mww 0x40004068 0x1C000 mww 0x31080028 0x11 mww 0x31080400 0 mww 0x31080440 0 mww 0x31080460 0 mww 0x31080480 0 # Delays mww 0x31080030 1 mww 0x31080034 6 mww 0x31080038 10 mww 0x31080044 1 mww 0x31080048 9 mww 0x3108004C 12 mww 0x31080050 10 mww 0x31080054 1 mww 0x31080058 1 mww 0x3108005C 0 mww 0x31080100 0x5680 mww 0x31080104 0x302 # Init sequence mww 0x31080020 0x193 sleep 1 busy mww 0x31080024 1 mww 0x31080020 0x113 sleep 1 busy mww 0x31080020 0x013 sleep 1 busy mww 0x31080024 65 mww 0x31080020 0x093 mdw 0x80020000 mww 0x31080020 0x013 # SYS_CTRL remapping mww 0x40004014 1 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/pic-p32mx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The Olimex PIC-P32MX has a PIC32MX set CPUTAPID 0x40916053 source [find target/pic32mx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/pico-debug.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # pico-debug is a virtual CMSIS-DAP debug adapter # it runs on the very same RP2040 target being debugged without additional hardware # https://github.com/majbthrd/pico-debug source [find interface/cmsis-dap.cfg] adapter speed 4000 set CHIPNAME rp2040 source [find target/rp2040-core0.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/pipistrello.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # http://pipistrello.saanlima.com/ source [find interface/ftdi/pipistrello.cfg] source [find cpld/xilinx-xc6s.cfg] source [find cpld/jtagspi.cfg] # example command to write bitstream, soft-cpu bios and runtime: # openocd -f board/pipistrello.cfg -c "init;\ # jtagspi_init 0 bscan_spi_xc6slx45.bit;\ # jtagspi_program bitstream-pistrello.bin 0;\ # jtagspi_program bios.bin 0x170000;\ # jtagspi_program runtime.fbi 0x180000;\ # xc6s_program xc6s.tap;\ # exit" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/propox_mmnet1001.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ## Chip: set CHIPNAME at91sam9260 set CPUTAPID 0x0792603f set ENDIAN little source [find target/at91sam9260.cfg] $_TARGETNAME configure -event reset-init {at91sam_init} proc at91sam_init { } { # at reset chip runs at 32 kHz => 1/8 * 32 kHz = 4 kHz jtag_rclk 4 # Enable user reset and disable watchdog mww 0xfffffd08 0xa5000501 ;# RSTC_MR : enable user reset mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog # Oscillator setup mww 0xfffffc20 0x00004001 ;# CKGR_MOR : enable the main oscillator (18.432 MHz) sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000001 ;# PMC_MCKR : switch to main oscillator sleep 10 ;# wait 10 ms # now we are running at 18.432 MHz kHz => 1/8 * 18.432 MHz = 2.304 MHz jtag_rclk 2000 mww 0xfffffc28 0x2060bf09 ;# CKGR_PLLAR: Set PLLA Register for 198,656MHz sleep 20 ;# wait 20 ms mww 0xfffffc2c 0x207c3f0c ;# CKGR_PLLBR: Set PLLB Register for USB usage (USB_CLK = 48 MHz) sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000101 ;# PMC_MCKR : Select prescaler sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000102 ;# PMC_MCKR : Clock from PLLA is selected sleep 10 ;# wait 10 ms # now we are running at 198.656 MHz kHz => full speed jtag jtag_rclk 30000 arm7_9 dcc_downloads enable ;# Enable faster DCC downloads # Configure PIO Controller for SDRAM data-lines D16-D31 # PC16-PC31 = Peripheral A: D16-D32 mww 0xfffff844 0xffff0000 ;# Interrupt Disable mww 0xfffff854 0xffff0000 ;# Multi-Drive Disable mww 0xfffff860 0xffff0000 ;# Pull-Up Disable mww 0xfffff870 0xffff0000 ;# PIO_ASR : Select peripheral A function for D15..D31 mww 0xfffff804 0xffff0000 ;# PIO_PDR : Disable PIO function for D15..D31 (Peripheral function enable) mww 0xfffffc10 0x00000010 ;# Enable PIO-C Clock in PMC (PID=4) # SD-Ram setup mww 0xffffef1c 0x2 ;# EBI_CSA : Assign EBI Chip Select 1 to SDRAM mww 0xffffea08 0x85227259 ;# SDRAMC_CR : Configure SDRAM (IS42S32160A: 4M Words x 32 Bits x 4 Banks (512-Mbit)) mww 0xffffea00 0x1 ;# SDRAMC_MR : issue a NOP command mww 0x20000000 0 mww 0xffffea00 0x2 ;# SDRAMC_MR : issue an 'All Banks Precharge' command mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (1st) mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (2nd) mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (3th) mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (4th) mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (5th) mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (6th) mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (7th) mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue an 'Auto-Refresh' command (8th) mww 0x20000000 0 mww 0xffffea00 0x3 ;# SDRAMC_MR : issue a 'Load Mode Register' command mww 0x20000000 0 mww 0xffffea00 0x0 ;# SDRAMC_MR : Normal Mode mww 0x20000000 0 mww 0xFFFFEA04 0x30d ;# SDRAM Refresh Time Register # datasheet: 8k refresh cycles / 64 ms # MCLK / (8*1024 / 64e-3) = 100e6 / 128000 = 781 = 0x30d } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/pxa255_sst.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # A PXA255 test board with SST 39LF400A flash # # At reset the memory map is as follows. Note that # the memory map changes later on as the application # starts... # # RAM at 0x4000000 # Flash at 0x00000000 # source [find target/pxa255.cfg] # Target name is set by above $_TARGETNAME configure -work-area-phys 0x4000000 -work-area-size 0x4000 -work-area-backup 0 # flash bank <driver> <base> <size> <chip_width> <bus_width> <target> [options] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x80000 2 2 $_TARGETNAME jedec_probe proc pxa255_sst_init {} { xscale cp15 15 0x00002001 ;#Enable CP0 and CP13 access # # setup GPIO # mww 0x40E00018 0x00008000 ;#CPSR0 sleep 20 mww 0x40E0001C 0x00000002 ;#GPSR1 sleep 20 mww 0x40E00020 0x00000008 ;#GPSR2 sleep 20 mww 0x40E0000C 0x00008000 ;#GPDR0 sleep 20 mww 0x40E00054 0x80000000 ;#GAFR0_L sleep 20 mww 0x40E00058 0x00188010 ;#GAFR0_H sleep 20 mww 0x40E0005C 0x60908018 ;#GAFR1_L sleep 20 mww 0x40E0000C 0x0280E000 ;#GPDR0 sleep 20 mww 0x40E00010 0x821C88B2 ;#GPDR1 sleep 20 mww 0x40E00014 0x000F03DB ;#GPDR2 sleep 20 mww 0x40E00000 0x000F03DB ;#GPLR0 sleep 20 mww 0x40F00004 0x00000020 ;#PSSR sleep 20 # # setup memory controller # mww 0x48000008 0x01111998 ;#MSC0 sleep 20 mww 0x48000010 0x00047ff0 ;#MSC2 sleep 20 mww 0x48000014 0x00000000 ;#MECR sleep 20 mww 0x48000028 0x00010504 ;#MCMEM0 sleep 20 mww 0x4800002C 0x00010504 ;#MCMEM1 sleep 20 mww 0x48000030 0x00010504 ;#MCATT0 sleep 20 mww 0x48000034 0x00010504 ;#MCATT1 sleep 20 mww 0x48000038 0x00004715 ;#MCIO0 sleep 20 mww 0x4800003C 0x00004715 ;#MCIO1 sleep 20 # mww 0x48000004 0x03CA4018 ;#MDREF sleep 20 mww 0x48000004 0x004B4018 ;#MDREF sleep 20 mww 0x48000004 0x000B4018 ;#MDREF sleep 20 mww 0x48000004 0x000BC018 ;#MDREF sleep 20 mww 0x48000000 0x00001AC8 ;#MDCNFG sleep 20 sleep 20 mww 0x48000000 0x00001AC9 ;#MDCNFG sleep 20 mww 0x48000040 0x00000000 ;#MDMRS sleep 20 } $_TARGETNAME configure -event reset-init {pxa255_sst_init} reset_config trst_and_srst adapter srst delay 200 jtag_ntrst_delay 200 #xscale debug_handler 0 0xFFFF0800 ;# debug handler base address ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/quark_d2000_refboard.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Intel Quark microcontroller D2000 Reference Board (web search for doc num 333582) # the board has an onboard FTDI FT232H chip adapter driver ftdi ftdi vid_pid 0x0403 0x6014 ftdi channel 0 ftdi layout_init 0x0000 0x030b ftdi layout_signal nTRST -data 0x0100 -noe 0x0100 source [find target/quark_d20xx.cfg] adapter speed 1000 reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/quark_x10xx_board.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # There are many Quark boards that can host the quark_x10xx SoC # Galileo is an example board source [find target/quark_x10xx.cfg] #default frequency but this can be adjusted at runtime adapter speed 4000 reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/quicklogic_quickfeather.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # QuickLogic EOS S3 QuickFeather # https://www.quicklogic.com/products/eos-s3/quickfeather-development-kit/ source [find target/eos_s3.cfg] reset_config srst_only transport select swd ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/radiona_ulx3s.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Radiona ULX3S # https://radiona.org/ulx3s/ # Currently there are following board variants: # CS-ULX3S-01 - LFE5U 12F # CS-ULX3S-02 - LFE5U 45F # CS-ULX3S-03 - LFE5U 85F # # two JTAG interfaces: # - US1, micro USB port connected to FT231XQ # This interface should be used with following config: # interface/ft232r/radiona_ulx3s.cfg # - J4, 6 pin connector # # Both of this interfaces share the JTAG lines (TDI, TMS, TCK, TDO) between # Lattice ECP5 FPGA chip and ESP32 WiFi controller. # Note: TRST_N of the ESP32 is pulled up by default and can be pulled down over # J3 interface. # See schematics for more information: # https://github.com/emard/ulx3s/blob/master/doc/schematics_v308.pdf # https://github.com/emard/ulx3s/blob/master/doc/schematics_v314.pdf # https://github.com/emard/ulx3s/blob/master/doc/schematics_v315.pdf # https://github.com/emard/ulx3s/blob/master/doc/schematics_v316.pdf source [find interface/ft232r/radiona_ulx3s.cfg] source [find fpga/lattice_ecp5.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/redbee.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/mc13224v.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/reflexces_achilles_i-dev_kit_arria10.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Achilles Instant-Development Kit Arria 10 SoC SoM # https://www.reflexces.com/products-solutions/achilles-instant-development-kit-arria-10-soc-som # if { [info exists USE_EXTERNAL_DEBUGGER] } { echo "Using external debugger" } else { source [find interface/altera-usb-blaster2.cfg] usb_blaster device_desc "Arria10 IDK" } source [find fpga/altera-10m50.cfg] source [find target/altera_fpgasoc_arria10.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/renesas_dk-s7g2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Renesas Synergy DK-S7G2 # source [find interface/jlink.cfg] transport select swd # XXX 19-pin SWD+TRACE connector also available # Synergy R7FS7G27H2A01CBD source [find target/renesas_s7g2.cfg] # 32 MB QSPI flash (Micron N25Q256A13EF840E) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/renesas_falcon.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas R-Car V3U Falcon Board Config # The Falcon board comes with either an V3U SOC. echo "\nFalcon:" if { ![info exists SOC] } { set SOC V3U } source [find target/renesas_rcar_gen3.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/renesas_gr_peach.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas RZ/A1H GR-Peach board reset_config srst_only source [find target/renesas_r7s72100.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/renesas_porter.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas R-Car M2 Evaluation Board set SOC M2 source [find target/renesas_rcar_gen2.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/renesas_salvator-xs.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas R-Car Gen3 Salvator-X(S) Board Config # The Salvator-X(S) boards come with either an H3, M3W, or M3N SOC. echo "\nSalvator-X(S):" if { ![info exists SOC] } { set SOC H3 } source [find target/renesas_rcar_gen3.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/renesas_silk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas R-Car E2 Evaluation Board set SOC E2 source [find target/renesas_rcar_gen2.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/renesas_stout.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas R-Car H2 Evaluation Board set SOC H2 source [find target/renesas_rcar_gen2.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/rigado_bmd300_ek.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Rigado BMD-300 Evaluation Kit # # https://www.rigado.com/products/modules/bmd-300/ # source [find interface/jlink.cfg] transport select swd adapter speed 1000 source [find target/nrf52.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/rpi3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is the Raspberry Pi 3 board with BCM2837 chip # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837/README.md # # Enable JTAG GPIO on Raspberry Pi boards # https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md source [find target/bcm2837.cfg] transport select jtag # Raspberry Pi boards only expose Test Reset (TRST) pin, no System Reset (SRST) reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/rpi4b.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is the Raspberry Pi 4 model B board with BCM2711 chip # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/README.md # # Enable JTAG GPIO on Raspberry Pi boards # https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md source [find target/bcm2711.cfg] transport select jtag # Raspberry Pi boards only expose Test Reset (TRST) pin, no System Reset (SRST) reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/rsc-w910.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Avalue RSC-W8910 sbc # http://www.avalue.com.tw/products/RSC-W910.cfm # 2MB NOR Flash # 64MB SDRAM # 128MB NAND Flash # Based on Nuvoton nuc910 source [find target/nuc910.cfg] # # reset only behaves correctly if we use srst_pulls_trst # reset_config trst_and_srst srst_pulls_trst adapter speed 1000 adapter srst delay 100 jtag_ntrst_delay 100 $_TARGETNAME configure -work-area-phys 0x00000000 -work-area-size 0x04000000 -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x20000000 0x00200000 2 2 $_TARGETNAME set _NANDNAME $_CHIPNAME.nand nand device $_NANDNAME nuc910 $_TARGETNAME # # Target events # $_TARGETNAME configure -event reset-start {adapter speed 1000} $_TARGETNAME configure -event reset-init { # switch on PLL for 200MHz operation # running from 15MHz input clock mww 0xB0000200 0x00000030 ;# CLKEN mww 0xB0000204 0x00000f3c ;# CLKSEL mww 0xB0000208 0x05007000 ;# CLKDIV mww 0xB000020C 0x00004f24 ;# PLLCON0 mww 0xB0000210 0x00002b63 ;# PLLCON1 mww 0xB000000C 0x08817fa6 ;# MFSEL sleep 10 # we are now running @ 200MHz # enable all openocd speed tweaks arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable adapter speed 15000 # map nor flash to 0x20000000 # map sdram to 0x00000000 mww 0xb0001000 0x000530c1 ;# EBICON mww 0xb0001004 0x40030084 ;# ROMCON mww 0xb0001008 0x000010ee ;# SDCONF0 mww 0xb000100C 0x00000000 ;# SDCONF1 mww 0xb0001010 0x0000015b ;# SDTIME0 mww 0xb0001014 0x0000015b ;# SDTIME1 mww 0xb0001018 0x00000000 ;# EXT0CON mww 0xb000101C 0x00000000 ;# EXT1CON mww 0xb0001020 0x00000000 ;# EXT2CON mww 0xb0001024 0x00000000 ;# EXT3CON mww 0xb000102c 0x00ff0048 ;# CKSKEW } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/sayma_amc.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Sayma AMC is an FPGA board for the µTCA AMC format # The board is open hardware (CERN OHL) and the gateware and software # running on it are open source (ARTIQ, LGPLv3+). # # https://github.com/m-labs/sinara/wiki/Sayma # # It contains a Xilinx Kintex Ultrascale 040 FPGA (xcku040). # There is a SCANSTA112SM JTAG router on the board which is configured to # automatically add devices to the JTAG svcan chain when they are added. # Sayma AMC is usually combined with Sayma RTM (rear transition module) # which features an Artix 7 FPGA. adapter driver ftdi ftdi device_desc "Quad RS232-HS" ftdi vid_pid 0x0403 0x6011 ftdi channel 0 # Use this to distinguish multiple boards by topology #adapter usb location 5:1 # sampling on falling edge generally seems to work and accelerates things but # is not fully tested #ftdi tdo_sample_edge falling # EN_USB_JTAG on ADBUS7: out, high # USB_nTRST on ADBUS4: out, high, but R46 is DNP ftdi layout_init 0x0098 0x008b #ftdi layout_signal EN_USB -data 0x0080 #ftdi layout_signal nTRST -data 0x0010 reset_config none adapter speed 5000 transport select jtag # Add the RTM Artix to the chain. Note that this changes the PLD numbering. # Unfortunately openocd TAPs can't be disabled after they have been added and # before `init`. #source [find cpld/xilinx-xc7.cfg] set CHIP XCKU040 source [find cpld/xilinx-xcu.cfg] set XILINX_USER1 0x02 set XILINX_USER2 0x03 set JTAGSPI_IR $XILINX_USER1 source [find cpld/jtagspi.cfg] flash bank xcu.spi1 jtagspi 0 0 0 0 xcu.proxy $XILINX_USER2 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/sheevaplug.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Marvell SheevaPlug source [find interface/ftdi/sheevaplug.cfg] source [find target/feroceon.cfg] adapter speed 2000 $_TARGETNAME configure \ -work-area-phys 0x10000000 \ -work-area-size 65536 \ -work-area-backup 0 arm7_9 dcc_downloads enable # this assumes the hardware default peripherals location before u-Boot moves it set _FLASHNAME $_CHIPNAME.flash nand device $_FLASHNAME orion 0 0xd8000000 proc sheevaplug_init { } { # We need to assert DBGRQ while holding nSRST down. # However DBGACK will be set only when nSRST is released. # Furthermore, the JTAG interface doesn't respond at all when # the CPU is in the WFI (wait for interrupts) state, so it is # possible that initial tap examination failed. So let's # re-examine the target again here when nSRST is asserted which # should then succeed. adapter assert srst feroceon.cpu arp_examine halt 0 adapter deassert srst wait_halt arm mcr 15 0 0 1 0 0x00052078 mww 0xD0001400 0x43000C30 ;# DDR SDRAM Configuration Register mww 0xD0001404 0x39543000 ;# Dunit Control Low Register mww 0xD0001408 0x22125451 ;# DDR SDRAM Timing (Low) Register mww 0xD000140C 0x00000833 ;# DDR SDRAM Timing (High) Register mww 0xD0001410 0x000000CC ;# DDR SDRAM Address Control Register mww 0xD0001414 0x00000000 ;# DDR SDRAM Open Pages Control Register mww 0xD0001418 0x00000000 ;# DDR SDRAM Operation Register mww 0xD000141C 0x00000C52 ;# DDR SDRAM Mode Register mww 0xD0001420 0x00000042 ;# DDR SDRAM Extended Mode Register mww 0xD0001424 0x0000F17F ;# Dunit Control High Register mww 0xD0001428 0x00085520 ;# Dunit Control High Register mww 0xD000147c 0x00008552 ;# Dunit Control High Register mww 0xD0001504 0x0FFFFFF1 ;# CS0n Size Register mww 0xD0001508 0x10000000 ;# CS1n Base Register mww 0xD000150C 0x0FFFFFF5 ;# CS1n Size Register mww 0xD0001514 0x00000000 ;# CS2n Size Register mww 0xD000151C 0x00000000 ;# CS3n Size Register mww 0xD0001494 0x003C0000 ;# DDR2 SDRAM ODT Control (Low) Register mww 0xD0001498 0x00000000 ;# DDR2 SDRAM ODT Control (High) REgister mww 0xD000149C 0x0000F80F ;# DDR2 Dunit ODT Control Register mww 0xD0001480 0x00000001 ;# DDR SDRAM Initialization Control Register mww 0xD0020204 0x00000000 ;# Main IRQ Interrupt Mask Register mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0020204 0x00000000 ;# " mww 0xD0010000 0x01111111 ;# MPP 0 to 7 mww 0xD0010004 0x11113322 ;# MPP 8 to 15 mww 0xD0010008 0x00001111 ;# MPP 16 to 23 mww 0xD0010418 0x003E07CF ;# NAND Read Parameters REgister mww 0xD001041C 0x000F0F0F ;# NAND Write Parameters Register mww 0xD0010470 0x01C7D943 ;# NAND Flash Control Register } proc sheevaplug_reflash_uboot { } { # reflash the u-Boot binary and reboot into it sheevaplug_init nand probe 0 nand erase 0 0x0 0xa0000 nand write 0 uboot.bin 0 oob_softecc_kw resume } proc sheevaplug_reflash_uboot_env { } { # reflash the u-Boot environment variables area sheevaplug_init nand probe 0 nand erase 0 0xa0000 0x40000 nand write 0 uboot-env.bin 0xa0000 oob_softecc_kw resume } proc sheevaplug_load_uboot { } { # load u-Boot into RAM and execute it sheevaplug_init load_image uboot.elf verify_image uboot.elf resume 0x00600000 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/sifive-e31arty.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Be sure you include the speed and interface before this file # Example: # -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e31arty.cfg" set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME $_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 init if {[ info exists pulse_srst]} { ftdi set_signal nSRST 0 ftdi set_signal nSRST z } halt flash protect 0 64 last off echo "Ready for Remote Connections" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/sifive-e51arty.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Be sure you include the speed and interface before this file # Example: # -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e51arty.cfg" set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME $_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 init if {[ info exists pulse_srst]} { ftdi set_signal nSRST 0 ftdi set_signal nSRST z } halt flash protect 0 64 last off echo "Ready for Remote Connections" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/sifive-hifive1-revb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later adapter speed 4000 adapter driver jlink transport select jtag set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000913 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME $_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 0x4000 -work-area-backup 0 flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME.0 init jlink jtag 3 halt flash protect 0 1 last off echo "Ready for Remote Connections" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/sifive-hifive1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later adapter speed 10000 adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x001b ftdi layout_signal nSRST -oe 0x0020 -data 0x0020 #Reset Stretcher logic on FE310 is ~1 second long #This doesn't apply if you use # ftdi set_signal, but still good to document #adapter srst delay 1500 set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME init #reset -- This type of reset is not implemented yet if {[ info exists pulse_srst]} { ftdi set_signal nSRST 0 ftdi set_signal nSRST z #Wait for the reset stretcher #It will work without this, but #will incur lots of delays for later commands. sleep 1500 } halt flash protect 0 64 last off ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/smdk6410.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Target configuration for the Samsung s3c6410 system on chip # Tested on a SMDK6410 # Processor : ARM1176 # Info: JTAG device found: 0x0032409d (Manufacturer: 0x04e, Part: 0x0324, Version: 0x0) source [find target/samsung_s3c6410.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x00000000 0x00100000 2 2 $_TARGETNAME jedec_probe ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/snps_em_sk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2014-2016,2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> # # Synopsys DesignWare ARC EM Starter Kit v2.x # # Configure JTAG cable # EM Starter Kit has built-in FT2232 chip, which is similar to Digilent HS-1. source [find interface/ftdi/digilent-hs1.cfg] # 5MHz seems to work good with all cores that might happen in 2.x adapter speed 5000 # ARCs support only JTAG. transport select jtag # Configure FPGA. This script supports both LX45 and LX150. source [find target/snps_em_sk_fpga.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/snps_em_sk_v1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2014-2016,2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> # # Synopsys DesignWare ARC EM Starter Kit v1.0 and v1.1 # # Configure JTAG cable # EM Starter Kit has built-in FT2232 chip, which is similar to Digilent HS-1. source [find interface/ftdi/digilent-hs1.cfg] adapter speed 10000 # ARCs support only JTAG. transport select jtag # Configure FPGA. This script supports both LX45 and LX150. source [find target/snps_em_sk_fpga.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/snps_em_sk_v2.1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2014-2016,2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> # # Synopsys DesignWare ARC EM Starter Kit v2.1 # # Configure JTAG cable # EM Starter Kit has built-in FT2232 chip, which is similar to Digilent HS-1. source [find interface/ftdi/digilent-hs1.cfg] # JTAG 10MHz is too fast for EM7D FPU in EM SK 2.1 which has core frequency # 20MHz. 7.5 MHz seems to work fine. adapter speed 7500 # ARCs support only JTAG. transport select jtag # Configure FPGA. This script supports both LX45 and LX150. source [find target/snps_em_sk_fpga.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/snps_em_sk_v2.2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2016,2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> # # Synopsys DesignWare ARC EM Starter Kit v2.2 # # Configure JTAG cable # EM Starter Kit has built-in FT2232 chip, which is similar to Digilent HS-1. source [find interface/ftdi/digilent-hs1.cfg] # EM11D reportedly requires 5 MHz. Other cores and board can work faster. adapter speed 5000 # ARCs support only JTAG. transport select jtag # Configure FPGA. This script supports both LX45 and LX150. source [find target/snps_em_sk_fpga.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/snps_hsdk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2019, 2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> # # Synopsys DesignWare ARC HSDK Software Development Platform (HS38 cores) # source [find interface/ftdi/snps_sdp.cfg] adapter speed 10000 # ARCs supports only JTAG. transport select jtag # Configure SoC source [find target/snps_hsdk.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/spansion_sk-fm4-176l-s6e2cc.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Spansion SK-FM4-176L-S6E2CC # # # FM3 MB9AF312K # source [find interface/cmsis-dap.cfg] # There's also an unpopulated 10-pin 0.05" pinout. # # FM4 S6E2CCAJ0A w/ 192 KB SRAM0 # set CHIPNAME s6e2cc set CHIPSERIES S6E2CCAJ0A set WORKAREASIZE 0x30000 source [find target/fm4_s6e2cc.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/spansion_sk-fm4-u120-9b560.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Spansion SK-FM4-U120-9B560 # # # FM3 MB9AF312K # # source [find interface/cmsis-dap.cfg] # # FM4 MB9BF568R w/ 64 KB SRAM0 # set CHIPNAME mb9bf568 set CHIPSERIES MB9BF568R set WORKAREASIZE 0x10000 source [find target/fm4_mb9bf.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/spear300evb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Configuration for the ST SPEAr300 Evaluation board # EVALSPEAr300 Rev. 1.0 # http://www.st.com/spear # # Date: 2010-11-27 # Author: Antonio Borneo <borneo.antonio@gmail.com> # The standard board has JTAG SRST not connected. # This script targets such boards using quirky code to bypass the issue. source [find mem_helper.tcl] source [find target/spear3xx.cfg] source [find chip/st/spear/spear3xx_ddr.tcl] source [find chip/st/spear/spear3xx.tcl] arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable # Serial NOR on SMI CS0. 8Mbyte. set _FLASHNAME1 $_CHIPNAME.snor flash bank $_FLASHNAME1 stmsmi 0xf8000000 0 0 0 $_TARGETNAME if { [info exists BOARD_HAS_SRST] } { # Modified board has SRST on JTAG connector reset_config trst_and_srst separate srst_gates_jtag \ trst_push_pull srst_open_drain } else { # Standard board has no SRST on JTAG connector reset_config trst_only separate srst_gates_jtag trst_push_pull source [find chip/st/spear/quirk_no_srst.tcl] } $_TARGETNAME configure -event reset-init { spear300evb_init } proc spear300evb_init {} { reg pc 0xffff0020; # loop forever sp3xx_clock_default sp3xx_common_init sp3xx_ddr_init "mt47h64m16_3_333_cl5_async" sp300_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/spear300evb_mod.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Configuration for the ST SPEAr300 Evaluation board # EVALSPEAr300 Rev. 1.0, modified to enable SRST on JTAG connector # http://www.st.com/spear # # List of board modifications to enable SRST, as reported in # ST Application Note (FIXME: add reference). # - Modifications on the top layer: # 1. replace reset chip U4 with a STM6315SDW13F; # - Modifications on the bottom layer: # 2. add 0 ohm resistor R10. It is located close to JTAG connector. # 3. add a 10K ohm pull-up resistor on the reset wire named as # POWERGOOD in the schematic. # # The easier way to do modification 3, is to use a resistor in package # 0603 and solder it between R10 and R54: # - one pad soldered with the pad of R54 connected to 3.3V (this # is the pad of R54 far from JTAG connector J4) # - the other pad soldered with the nearest pad of R10. # # Date: 2011-11-18 # Author: Antonio Borneo <borneo.antonio@gmail.com> # Modified boards has SRST on JTAG connector set BOARD_HAS_SRST 1 source [find board/spear300evb.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/spear310evb20.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Configuration for the ST SPEAr310 Evaluation board # EVALSPEAr310 Rev. 2.0 # http://www.st.com/spear # # Date: 2010-08-17 # Author: Antonio Borneo <borneo.antonio@gmail.com> # The standard board has JTAG SRST not connected. # This script targets such boards using quirky code to bypass the issue. # # Check ST Application Note AN3321 on how to fix SRST on # the board, then use the script board/spear310evb20_mod.cfg source [find mem_helper.tcl] source [find target/spear3xx.cfg] source [find chip/st/spear/spear3xx_ddr.tcl] source [find chip/st/spear/spear3xx.tcl] arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable # CFI parallel NOR on EMI CS0. 2x 16bit 8M devices = 16Mbyte. set _FLASHNAME0 $_CHIPNAME.pnor flash bank $_FLASHNAME0 cfi 0x50000000 0x01000000 2 4 $_TARGETNAME # Serial NOR on SMI CS0. 8Mbyte. set _FLASHNAME1 $_CHIPNAME.snor flash bank $_FLASHNAME1 stmsmi 0xf8000000 0 0 0 $_TARGETNAME if { [info exists BOARD_HAS_SRST] } { # Modified board has SRST on JTAG connector reset_config trst_and_srst separate srst_gates_jtag \ trst_push_pull srst_open_drain } else { # Standard board has no SRST on JTAG connector reset_config trst_only separate srst_gates_jtag trst_push_pull source [find chip/st/spear/quirk_no_srst.tcl] } $_TARGETNAME configure -event reset-init { spear310evb20_init } proc spear310evb20_init {} { reg pc 0xffff0020 ;# loop forever sp3xx_clock_default sp3xx_common_init sp3xx_ddr_init "mt47h64m16_3_333_cl5_async" sp310_init sp310_emi_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/spear310evb20_mod.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Configuration for the ST SPEAr310 Evaluation board # EVALSPEAr310 Rev. 2.0, modified to enable SRST on JTAG connector # http://www.st.com/spear # # List of board modifications to enable SRST, as reported in # ST Application Note AN3321. # - Modifications on the top layer: # 1. remove R137 and C57, located near the SMII PHY U18; # 2. remove R172 and C75, located near the SMII PHY U19; # 3. remove R207 and C90, located near the SMII PHY U20; # 4. remove C236, located near the SMII PHY U21; # 5. remove U12, located near the JTAG connector; # 6. solder together pins 7, 8 and 9 of U12; # 7. solder together pins 11, 12, 13, 14, 15, 16, 17 and 18 of U12. # - Modifications on the bottom layer: # 8. replace reset chip U11 with a STM6315SDW13F; # 9. add 0 ohm resistor R329. It is located close to JTAG connector. # # Date: 2009-10-31 # Author: Antonio Borneo <borneo.antonio@gmail.com> # Modified boards has SRST on JTAG connector set BOARD_HAS_SRST 1 source [find board/spear310evb20.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/spear320cpu.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Configuration for the ST SPEAr320 CPU board # EVAL_SPEAr320CPU Rev. 2.0 # http://www.st.com/spear # # Date: 2011-11-18 # Author: Antonio Borneo <borneo.antonio@gmail.com> # The standard board has JTAG SRST not connected. # This script targets such boards using quirky code to bypass the issue. source [find mem_helper.tcl] source [find target/spear3xx.cfg] source [find chip/st/spear/spear3xx_ddr.tcl] source [find chip/st/spear/spear3xx.tcl] arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable # Serial NOR on SMI CS0. 8Mbyte. set _FLASHNAME1 $_CHIPNAME.snor flash bank $_FLASHNAME1 stmsmi 0xf8000000 0 0 0 $_TARGETNAME if { [info exists BOARD_HAS_SRST] } { # Modified board has SRST on JTAG connector reset_config trst_and_srst separate srst_gates_jtag \ trst_push_pull srst_open_drain } else { # Standard board has no SRST on JTAG connector reset_config trst_only separate srst_gates_jtag trst_push_pull source [find chip/st/spear/quirk_no_srst.tcl] } $_TARGETNAME configure -event reset-init { spear320cpu_init } if { [info exists DDR_CHIPS] } { set _DDR_CHIPS $DDR_CHIPS } else { set _DDR_CHIPS 1 } proc spear320cpu_init {} { global _DDR_CHIPS reg pc 0xffff0020; # loop forever sp3xx_clock_default sp3xx_common_init sp3xx_ddr_init "mt47h64m16_3_333_cl5_async" $_DDR_CHIPS sp320_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/spear320cpu_mod.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Configuration for the ST SPEAr320 Evaluation board # EVAL_SPEAr320CPU Rev. 2.0, modified to enable SRST on JTAG connector # http://www.st.com/spear # # List of board modifications to enable SRST, as reported in # ST Application Note (FIXME: add reference). # - Modifications on the bottom layer: # 1. replace reset chip U7 with a STM6315SDW13F; # 2. add 0 ohm resistor R45. It is located close to JTAG connector. # 3. add a 10K ohm pull-up resistor on the reset wire named as # POWERGOOD in the schematic. # # The easier way to do modification 3, is to use a resistor in package # 0603 or 0402 and solder it between R15 and R45: # - one pad soldered with the pad of R15 connected to 3.3V (this # is the pad of R15 closer to R45) # - the other pad soldered with the nearest pad of R45. # # Date: 2011-11-18 # Author: Antonio Borneo <borneo.antonio@gmail.com> # Modified boards has SRST on JTAG connector set BOARD_HAS_SRST 1 source [find board/spear320cpu.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_b-l475e-iot01a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an B-L475E-IOT01A Discovery kit for IoT node with a single STM32L475VGT6 chip. # http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 96KB set WORKAREASIZE 0x18000 # enable stmqspi set QUADSPI 1 source [find target/stm32l4x.cfg] # QUADSPI initialization proc qspi_init { } { global a mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks) mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PE11: NCS, PE10: CLK, PE15: BK1_IO3, PE14: BK1_IO2, PE13: BK1_IO1, PE12: BK1_IO0 # PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V # Port E: PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V mmw 0x48001000 0xAAA00000 0x55500000 ;# MODER mmw 0x48001008 0xFFF00000 0x00000000 ;# OSPEEDR mmw 0x48001024 0xAAAAAA00 0x55555500 ;# AFRH mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00160100 ;# QUADSPI_DCR: FSIZE=0x16, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # memory-mapped read mode with 3-byte addresses mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK sleep 1 mmw 0x40021000 0x00000100 0x00000000 ;# HSI on mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 mmw 0x40021000 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_8l152r8.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is a ST NUCLEO 8L152R8 board with a single STM8L152R8T6 chip. # http://www.st.com/en/evaluation-tools/nucleo-8l152r8.html source [find interface/stlink-dap.cfg] transport select swim source [find target/stm8l15xx8.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_8s208rb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is a ST NUCLEO 8S208RB board with a single STM8S208RBT6 chip. # https://www.st.com/en/evaluation-tools/nucleo-8s208rb.html source [find interface/stlink-dap.cfg] transport select swim # 128 KiB flash and 2 KiB EEPROM set FLASHEND 0x27fff set EEPROMEND 0x47ff source [find target/stm8s.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_f0.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is for all ST NUCLEO with any STM32F0. Known boards at the moment: # STM32F030R8 # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF259997 # NUCLEO-F072RB # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF259997 # STM32F091RC # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260944 source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32f0x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_f103rb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an ST NUCLEO F103RB board with a single STM32F103RBT6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF259875 source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32f1x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_f3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an ST NUCLEO F334R8 board with a single STM32F334R8T6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260004 source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32f3x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_f4.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is for all ST NUCLEO with any STM32F4. Known boards at the moment: # STM32F401RET6 # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260000 # STM32F411RET6 # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260320 source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_f7.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STMicroelectronics STM32F7 Nucleo development board # Known boards: NUCLEO-F746ZG and NUCLEO-F767ZI source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32f7x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_g0.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is for all ST NUCLEO with any STM32G0. Known boards at the moment: # NUCLEO-G031K8 # https://www.st.com/en/evaluation-tools/nucleo-g031k8.html # NUCLEO-G070RB # https://www.st.com/en/evaluation-tools/nucleo-g070rb.html # NUCLEO-G071RB # https://www.st.com/en/evaluation-tools/nucleo-g071rb.html # NUCLEO-G0B1RE # https://www.st.com/en/evaluation-tools/nucleo-g0b1re.html source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32g0x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_g4.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is for all ST NUCLEO with any STM32G4. Known boards at the moment: # NUCLEO-G431KB # https://www.st.com/en/evaluation-tools/nucleo-g431kb.html # NUCLEO-G431RB # https://www.st.com/en/evaluation-tools/nucleo-g431rb.html # NUCLEO-G474RE # https://www.st.com/en/evaluation-tools/nucleo-g474re.html # NUCLEO-G491RE # https://www.st.com/en/evaluation-tools/nucleo-g491re.html source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32g4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_h743zi.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an ST NUCLEO-H743ZI board with single STM32H743ZI chip. # http://www.st.com/en/evaluation-tools/nucleo-h743zi.html source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32h7x_dual_bank.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_h745zi.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an ST NUCLEO-H745ZI-Q board with single STM32H745ZITx chip. source [find interface/stlink-dap.cfg] transport select dapdirect_swd # STM32H745xx devices are dual core (Cortex-M7 and Cortex-M4) set DUAL_CORE 1 # enable CTI for cross halting both cores set USE_CTI 1 source [find target/stm32h7x_dual_bank.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_l073rz.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an ST NUCLEO-L073RZ board with single STM32L073RZ chip. # http://www.st.com/en/evaluation-tools/nucleo-l073rz.html source [find interface/stlink.cfg] transport select hla_swd set WORKAREASIZE 0x2000 source [find target/stm32l0_dual_bank.cfg] # There is only system reset line and JTAG/SWD command can be issued when SRST reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_l1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an ST NUCLEO L152RE board with a single STM32L152RET6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260002 source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32l1x_dual_bank.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_l4.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Should work with all STM32L4 Nucleo Dev Boards. # http://www.st.com/en/evaluation-tools/stm32-mcu-nucleo.html source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32l4x.cfg] # use hardware reset reset_config srst_only srst_nogate ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_l5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is for STM32L5 Nucleo Dev Boards. # http://www.st.com/en/evaluation-tools/stm32-mcu-nucleo.html source [find interface/stlink-dap.cfg] transport select dapdirect_swd source [find target/stm32l5x.cfg] # use hardware reset reset_config srst_only srst_nogate ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/st_nucleo_wb55.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Configuration for STM32WB55 Nucleo board (STM32WB55RGV6) # source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32wbx.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/steval-idb007v1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an evaluation board with a single BlueNRG-1 chip. # http://www.st.com/content/st_com/en/products/evaluation-tools/solution-evaluation-tools/communication-and-connectivity-solution-eval-boards/steval-idb008v1.html set CHIPNAME bluenrg-1 source [find target/bluenrg-x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/steval-idb008v1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an evaluation board with a single BlueNRG-2 chip. # http://www.st.com/content/st_com/en/products/evaluation-tools/solution-evaluation-tools/communication-and-connectivity-solution-eval-boards/steval-idb007v1.html set CHIPNAME bluenrg-2 source [find target/bluenrg-x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/steval-idb011v1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an evaluation board with a single BlueNRG-LP chip. set CHIPNAME bluenrg-lp source [find target/bluenrg-x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/steval-idb012v1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an evaluation board with a single BlueNRG-LPS chip. set CHIPNAME bluenrg-lps source [find interface/cmsis-dap.cfg] source [find target/bluenrg-x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/steval_pcc010.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Use for the STM207VG plug-in board (1 MiB Flash and 112+16 KiB Ram # coming with the STEVAL-PCC010 board # http://www.st.com/internet/evalboard/product/251530.jsp # or any other board with only a STM32F2x in the JTAG chain # increase working area to 32KB for faster flash programming set WORKAREASIZE 0x8000 source [find target/stm32f2x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm320518_eval.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STM320518-EVAL: This is an STM32F0 eval board with a single STM32F051R8T6 # (64KB) chip. # http://www.st.com/internet/evalboard/product/252994.jsp # # increase working area to 8KB set WORKAREASIZE 0x2000 # chip name set CHIPNAME STM32F051R8T6 source [find target/stm32f0x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm320518_eval_stlink.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STM320518-EVAL: This is an STM32F0 eval board with a single STM32F051R8T6 # (64KB) chip. # http://www.st.com/internet/evalboard/product/252994.jsp # # This is for using the onboard STLINK/V2 source [find interface/stlink.cfg] transport select hla_swd # increase working area to 8KB set WORKAREASIZE 0x2000 # chip name set CHIPNAME STM32F051R8T6 source [find target/stm32f0x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32100b_eval.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32 eval board with a single STM32F100VBT6 chip. # http://www.st.com/internet/evalboard/product/247099.jsp # The chip has only 8KB sram set WORKAREASIZE 0x2000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm3210b_eval.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32 eval board with a single STM32F10x (128KB) chip. # http://www.st.com/internet/evalboard/product/176090.jsp # increase working area to 32KB for faster flash programming set WORKAREASIZE 0x8000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm3210c_eval.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32 eval board with a single STM32F107VCT chip. # http://www.st.com/internet/evalboard/product/217965.jsp # increase working area to 32KB for faster flash programming set WORKAREASIZE 0x8000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm3210e_eval.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32 eval board with a single STM32F103ZET6 chip. # http://www.st.com/internet/evalboard/product/204176.jsp # increase working area to 32KB for faster flash programming set WORKAREASIZE 0x8000 source [find target/stm32f1x.cfg] # # configure FSMC Bank 1 (NOR/PSRAM Bank 2) NOR flash # M29W128GL70ZA6E # set _FLASHNAME $_CHIPNAME.norflash flash bank $_FLASHNAME cfi 0x64000000 0x01000000 2 2 $_TARGETNAME proc stm32_enable_fsmc {} { echo "Enabling FSMC Bank 1 (NOR/PSRAM Bank 2)" # enable gpio (defg) clocks for fsmc # RCC_APB2ENR mww 0x40021018 0x000001E0 # enable fsmc clock # RCC_AHBENR mww 0x40021014 0x00000114 # configure gpio to alternate function # GPIOD_CRL mww 0x40011400 0x44BB44BB # GPIOD_CRH mww 0x40011404 0xBBBBBBBB # GPIOE_CRL mww 0x40011800 0xBBBBB444 # GPIOE_CRH mww 0x40011804 0xBBBBBBBB # GPIOF_CRL mww 0x40011C00 0x44BBBBBB # GPIOF_CRH mww 0x40011C04 0xBBBB4444 # GPIOG_CRL mww 0x40012000 0x44BBBBBB # GPIOG_CRH mww 0x40012004 0x444444B4 # setup fsmc timings # FSMC_BCR1 mww 0xA0000008 0x00001058 # FSMC_BTR1 mww 0xA000000C 0x10000502 # FSMC_BCR1 - enable fsmc mww 0xA0000008 0x00001059 } $_TARGETNAME configure -event reset-init { stm32_enable_fsmc } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm3220g_eval.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STM3220G-EVAL: This is an STM32F2 eval board with a single STM32F207IGH6 # (128KB) chip. # http://www.st.com/internet/evalboard/product/250374.jsp # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F207IGH6 source [find target/stm32f2x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm3220g_eval_stlink.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STM3220G-EVAL: This is an STM32F2 eval board with a single STM32F207IGH6 # (128KB) chip. # http://www.st.com/internet/evalboard/product/250374.jsp # # This is for using the onboard STLINK/V2 source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F207IGH6 source [find target/stm32f2x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm3241g_eval.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STM3241G-EVAL: This is an STM32F4 eval board with a single STM32F417IGH6 # (1024KB) chip. # http://www.st.com/internet/evalboard/product/252216.jsp # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F417IGH6 source [find target/stm32f4x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm3241g_eval_stlink.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STM3241G-EVAL: This is an STM32F4 eval board with a single STM32F417IGH6 # (1024KB) chip. # http://www.st.com/internet/evalboard/product/252216.jsp # # This is for using the onboard STLINK/V2 source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F417IGH6 source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32429i_eval.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STM32429I-EVAL: This is an STM32F4 eval board with a single STM32F429NIH6 # (2048KB) chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF259093 # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F429NIH6 source [find target/stm32f4x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32429i_eval_stlink.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STM32429I-EVAL: This is an STM32F4 eval board with a single STM32F429NIH6 # (2048KB) chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF259093 # # This is for using the onboard STLINK/V2 source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F429NIH6 source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32439i_eval.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STM32439I-EVAL: This is an STM32F4 eval board with a single STM32F439NIH6 # (2048KB) chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF259094 # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F439NIH6 source [find target/stm32f4x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32439i_eval_stlink.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STM32439I-EVAL: This is an STM32F4 eval board with a single STM32F439NIH6 # (2048KB) chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF259094 # # This is for using the onboard STLINK/V2 source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # chip name set CHIPNAME STM32F439NIH6 source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm327x6g_eval.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STM327[4|5]6G-EVAL: This is for the STM32F7 eval boards. # STM32746G-EVAL # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF261639 # STM32756G-EVAL # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF261640 # increase working area to 256KB set WORKAREASIZE 0x40000 source [find target/stm32f7x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f0discovery.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32F0 discovery board with a single STM32F051R8T6 chip. # http://www.st.com/internet/evalboard/product/253215.jsp source [find interface/stlink.cfg] transport select hla_swd set WORKAREASIZE 0x2000 source [find target/stm32f0x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f103c8_blue_pill.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STM32F103C8 "Blue Pill" # NOTE: # There is a fair bit of confusion about whether the "Blue Pill" has 128kB or 64kB flash size. # The most likely cause is that there exist a -C8 and a -CB variant of the STM32F103, where # the C8 has 64kB, the CB has 128kB as per specification. "Blue Pill" boards are manufactured # by a lot of different vendors, some may actually use the CB variant but from a cursory look # it very hard to tell them apart ("C8" and "CB" look very similar). Nevertheless, people have # tried using the full 128kB of flash on the C8 and found it to be working. Hence this board file # overrides the internal size detection. Be aware though that you may be using you particular # board outside of its specification. If in doubt, comment the following line. set FLASH_SIZE 0x20000 source [find target/stm32f1x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f334discovery.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32F334 discovery board with a single STM32F334C8T6 chip. # As it is one of the few boards with stlink V.2-1, we source the corresponding # nucleo file. # http://www.st.com/web/en/catalog/tools/FM116/SC959/SS1532/LN1848/PF260318 source [find board/st_nucleo_f3.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f3discovery.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32F3 discovery board with a single STM32F303VCT6 chip. # http://www.st.com/internet/evalboard/product/254044.jsp source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32f3x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f412g-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32F412G discovery board with a single STM32F412ZGT6 chip. # http://www.st.com/en/evaluation-tools/32f412gdiscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # enable stmqspi set QUADSPI 1 source [find target/stm32f4x.cfg] # QUADSPI initialization proc qspi_init { } { global a mmw 0x40023830 0x000000FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOHEN (enable clocks) mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PB02: CLK, PG06: BK1_NCS, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0 # PB02:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V, PG06:AF10:V # Port B: PB02:AF09:V mmw 0x40020400 0x00000020 0x00000010 ;# MODER mmw 0x40020408 0x00000030 0x00000000 ;# OSPEEDR mmw 0x40020420 0x00000900 0x00000600 ;# AFRL # Port F: PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V mmw 0x40021400 0x000AA000 0x00055000 ;# MODER mmw 0x40021408 0x000FF000 0x00000000 ;# OSPEEDR mmw 0x40021420 0x99000000 0x66000000 ;# AFRL mmw 0x40021424 0x000000AA 0x00000055 ;# AFRH # Port G: PG06:AF10:V mmw 0x40021800 0x00002000 0x00001000 ;# MODER mmw 0x40021808 0x00003000 0x00000000 ;# OSPEEDR mmw 0x40021820 0x0A000000 0x05000000 ;# AFRL mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # 1-line spi mode mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO sleep 1 # memory-mapped read mode with 3-byte addresses mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mww 0x40023C00 0x00000003 ;# 3 WS for 96 MHz HCLK sleep 1 mww 0x40023804 0x24001808 ;# 96 MHz: HSI, PLLM=8, PLLN=96, PLLP=2 mww 0x40023808 0x00001000 ;# APB1: /2, APB2: /1 mmw 0x40023800 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f413h-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32F413H discovery board with a single STM32F413ZHT6 chip. # http://www.st.com/en/evaluation-tools/32f413hdiscovery.html # # Untested!!! # # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # enable stmqspi set QUADSPI 1 source [find target/stm32f4x.cfg] # QUADSPI initialization proc qspi_init { } { global a mmw 0x40023830 0x000000FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOHEN (enable clocks) mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PG06: BK1_NCS, PB02: CLK, PD13: BK1_IO3, PE02: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0 # PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PF09:AF10:V, PF08:AF10:V, PG06:AF10:V # Port B: PB02:AF09:V mmw 0x40020400 0x00000020 0x00000010 ;# MODER mmw 0x40020408 0x00000030 0x00000000 ;# OSPEEDR mmw 0x40020420 0x00000900 0x00000600 ;# AFRL # Port D: PD13:AF09:V mmw 0x40020C00 0x08000000 0x04000000 ;# MODER mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH # Port E: PE02:AF09:V mmw 0x40021000 0x00000020 0x00000010 ;# MODER mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR mmw 0x40021020 0x00000900 0x00000600 ;# AFRL # Port F: PF09:AF10:V, PF08:AF10:V mmw 0x40021400 0x000A0000 0x00050000 ;# MODER mmw 0x40021408 0x000F0000 0x00000000 ;# OSPEEDR mmw 0x40021424 0x000000AA 0x00000055 ;# AFRH # Port G: PG06:AF10:V mmw 0x40021800 0x00002000 0x00001000 ;# MODER mmw 0x40021808 0x00003000 0x00000000 ;# OSPEEDR mmw 0x40021820 0x0A000000 0x05000000 ;# AFRL mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # 1-line spi mode mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO sleep 1 # memory-mapped read mode with 3-byte addresses mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mww 0x40023C00 0x00000003 ;# 3 WS for 96 MHz HCLK sleep 1 mww 0x40023804 0x24001808 ;# 96 MHz: HSI, PLLM=8, PLLN=96, PLLP=2 mww 0x40023808 0x00001000 ;# APB1: /2, APB2: /1 mmw 0x40023800 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f429disc1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # This is an STM32F429 discovery board with a single STM32F429ZI chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF259090 # source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f429discovery.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # This is an STM32F429 discovery board with a single STM32F429ZI chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF259090 # source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f469discovery.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # This is an STM32F469 discovery board with a single STM32F469NI chip. # http://www.st.com/web/catalog/tools/FM116/CL1620/SC959/SS1532/LN1848/PF262395 # source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f469i-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32F469I discovery board with a single STM32F469NIH6 chip. # http://www.st.com/en/evaluation-tools/32f469idiscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # enable stmqspi set QUADSPI 1 source [find target/stm32f4x.cfg] # QUADSPI initialization proc qspi_init { } { global a mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PF10: CLK, PB06: BK1_NCS, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0 # PB06:AF10:V, PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V # Port B: PB06:AF10:V mmw 0x40020400 0x00002000 0x00001000 ;# MODER mmw 0x40020408 0x00003000 0x00000000 ;# OSPEEDR mmw 0x40020420 0x0A000000 0x05000000 ;# AFRL # Port F: PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V mmw 0x40021400 0x002AA000 0x00155000 ;# MODER mmw 0x40021408 0x003FF000 0x00000000 ;# OSPEEDR mmw 0x40021420 0x99000000 0x66000000 ;# AFRL mmw 0x40021424 0x000009AA 0x00000655 ;# AFRH mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # 1-line spi mode mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO sleep 1 # memory-mapped read mode with 3-byte addresses mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mww 0x40023C00 0x00000005 ;# 5 WS for 160 MHz HCLK sleep 1 mww 0x40023804 0x24002808 ;# 160 MHz: HSI, PLLM=8, PLLN=160, PLLP=2 mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 mmw 0x40023800 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f4discovery.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32F4 discovery board with a single STM32F407VGT6 chip. # http://www.st.com/internet/evalboard/product/252419.jsp source [find interface/stlink.cfg] transport select hla_swd # increase working area to 64KB set WORKAREASIZE 0x10000 source [find target/stm32f4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f723e-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32F723E discovery board with a single STM32F723IEK6 chip. # http://www.st.com/en/evaluation-tools/32f723ediscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 128KB set WORKAREASIZE 0x20000 # enable stmqspi set QUADSPI 1 source [find target/stm32f7x.cfg] reset_config srst_only # QUADSPI initialization proc qspi_init { } { global a mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PC10: BK1_IO1, PC09: BK1_IO0 # PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V # Port B: PB06:AF10:V, PB02:AF09:V mmw 0x40020400 0x00002020 0x00001010 ;# MODER mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL # Port C: PC10:AF09:V, PC09:AF09:V mmw 0x40020800 0x00280000 0x00140000 ;# MODER mmw 0x40020808 0x003C0000 0x00000000 ;# OSPEEDR mmw 0x40020824 0x00000990 0x00000660 ;# AFRH # Port D: PD13:AF09:V mmw 0x40020C00 0x08000000 0x04000000 ;# MODER mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH # Port E: PE02:AF09:V mmw 0x40021000 0x00000020 0x00000010 ;# MODER mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR mmw 0x40021020 0x00000900 0x00000600 ;# AFRL mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00190100 ;# QUADSPI_DCR: FSIZE=0x19, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # 1-line spi mode mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO sleep 1 # memory-mapped read mode with 4-byte addresses mww 0xA0001014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK sleep 1 mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2 mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 mmw 0x40023800 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f746g-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32F746G discovery board with a single STM32F746NGH6 chip. # http://www.st.com/en/evaluation-tools/32f746gdiscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 256KB set WORKAREASIZE 0x40000 # enable stmqspi set QUADSPI 1 source [find target/stm32f7x.cfg] reset_config srst_only # QUADSPI initialization proc qspi_init { } { global a mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PD12: BK1_IO1, PD11: BK1_IO0 # PB06:AF10:V, PB02:AF09:V, PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PE02:AF09:V # Port B: PB06:AF10:V, PB02:AF09:V mmw 0x40020400 0x00002020 0x00001010 ;# MODER mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL # Port D: PD13:AF09:V, PD12:AF09:V, PD11:AF09:V mmw 0x40020C00 0x0A800000 0x05400000 ;# MODER mmw 0x40020C08 0x0FC00000 0x00000000 ;# OSPEEDR mmw 0x40020C24 0x00999000 0x00666000 ;# AFRH # Port E: PE02:AF09:V mmw 0x40021000 0x00000020 0x00000010 ;# MODER mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR mmw 0x40021020 0x00000900 0x00000600 ;# AFRL mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # 1-line spi mode mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO sleep 1 # memory-mapped read mode with 3-byte addresses mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK sleep 1 mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2 mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 mmw 0x40023800 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f769i-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32F769I discovery board with a single STM32F769NIH6 chip. # http://www.st.com/en/evaluation-tools/32f769idiscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 256KB set WORKAREASIZE 0x40000 # enable stmqspi set QUADSPI 1 source [find target/stm32f7x.cfg] reset_config srst_only # QUADSPI initialization proc qspi_init { } { global a mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PC10: BK1_IO1, PC09: BK1_IO0 # PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V # Port B: PB06:AF10:V, PB02:AF09:V mmw 0x40020400 0x00002020 0x00001010 ;# MODER mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL # Port C: PC10:AF09:V, PC09:AF09:V mmw 0x40020800 0x00280000 0x00140000 ;# MODER mmw 0x40020808 0x003C0000 0x00000000 ;# OSPEEDR mmw 0x40020824 0x00000990 0x00000660 ;# AFRH # Port D: PD13:AF09:V mmw 0x40020C00 0x08000000 0x04000000 ;# MODER mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH # Port E: PE02:AF09:V mmw 0x40021000 0x00000020 0x00000010 ;# MODER mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR mmw 0x40021020 0x00000900 0x00000600 ;# AFRL mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00190100 ;# QUADSPI_DCR: FSIZE=0x19, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # exit qpi mode mww 0xA0001014 0x000033f5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO # 1-line memory-mapped read mode with 4-byte addresses mww 0xA0001014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ # 4-line qpi mode mww 0xA0001014 0x00003135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=EQIO # 4-line memory-mapped read mode with 4-byte addresses mww 0xA0001014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0xA, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=4READ4B } $_TARGETNAME configure -event reset-init { mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK sleep 1 mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2 mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 mmw 0x40023800 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32f7discovery.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32F7 discovery board with a single STM32F756NGH6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1848/PF261641 # This is for using the onboard STLINK/V2-1 source [find interface/stlink.cfg] transport select hla_swd # increase working area to 256KB set WORKAREASIZE 0x40000 source [find target/stm32f7x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32h735g-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is a stm32h735g-dk with a single STM32H735IGK6 chip. # https://www.st.com/en/evaluation-tools/stm32h735g-dk.html # # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd set CHIPNAME stm32h735igk6 # enable stmqspi if {![info exists OCTOSPI1]} { set OCTOSPI1 1 set OCTOSPI2 0 } source [find target/stm32h7x.cfg] reset_config srst_only # OCTOSPI initialization # octo: 8-line mode proc octospi_init { octo } { global a b mmw 0x58024540 0x000006FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x58024534 0x00284000 0 ;# RCC_AHB3ENR |= IOMNGREN, OSPI2EN, OSPI1EN (enable clocks) sleep 1 ;# Wait for clock startup mww 0x5200B404 0x03010111 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI1 mww 0x5200B408 0x00000000 ;# OCTOSPIM_P2CR: disable Port 2 # PG06: OCSPI1_NCS, PF10: OCSPI1_CLK, PB02: OCSPI1_DQS, PD07: OCSPI1_IO7, PG09: OCSPI1_IO6, PD05: OCSPI1_IO5, # PD04: OCSPI1_IO4, PD13: OCSPI1_IO3, PE02: OCSPI1_IO2, PD12: OCSPI1_IO1, PD11: OCSPI1_IO0 # PB02:AF10:V, PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PD07:AF10:V, PD05:AF10:V # PD04:AF10:V, PE02:AF09:V, PF10:AF09:V, PG09:AF09:V, PG06:AF10:V # Port B: PB02:AF10:V mmw 0x58020400 0x00000020 0x00000010 ;# MODER mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR mmw 0x5802040C 0x00000000 0x00000030 ;# PUPDR mmw 0x58020420 0x00000A00 0x00000500 ;# AFRL # Port D: PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V mmw 0x58020C00 0x0A808A00 0x05404500 ;# MODER mmw 0x58020C08 0x0FC0CF00 0x00000000 ;# OSPEEDR mmw 0x58020C0C 0x00000000 0x0FC0CF00 ;# PUPDR mmw 0x58020C20 0xA0AA0000 0x50550000 ;# AFRL mmw 0x58020C24 0x00999000 0x00666000 ;# AFRH # Port E: PE02:AF09:V mmw 0x58021000 0x00000020 0x00000010 ;# MODER mmw 0x58021008 0x00000030 0x00000000 ;# OSPEEDR mmw 0x5802100C 0x00000000 0x00000030 ;# PUPDR mmw 0x58021020 0x00000900 0x00000600 ;# AFRL # Port F: PF10:AF09:V mmw 0x58021400 0x00200000 0x00100000 ;# MODER mmw 0x58021408 0x00300000 0x00000000 ;# OSPEEDR mmw 0x5802140C 0x00000000 0x00300000 ;# PUPDR mmw 0x58021424 0x00000900 0x00000600 ;# AFRH # Port G: PG09:AF09:V, PG06:AF10:V mmw 0x58021800 0x00082000 0x00041000 ;# MODER mmw 0x58021808 0x000C3000 0x00000000 ;# OSPEEDR mmw 0x5802180C 0x00000000 0x000C3000 ;# PUPDR mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL mmw 0x58021824 0x00000090 0x00000060 ;# AFRH # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses mww 0x52005130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 mww 0x52005008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 mww 0x5200500C 0x00000005 ;# OCTOSPI_DCR2: PRESCALER=5 mww 0x52005108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 mww 0x52005100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 mww 0x52005110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B flash probe $a ;# load configuration from CR, TCR, CCR, IR register values if { $octo == 1 } { stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 ;# Read Status Register stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 mww 0x52005108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 mww 0x52005100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 mww 0x52005110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 0 0x04 ;# Write Disable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits } } $_CHIPNAME.cpu0 configure -event reset-init { global OCTOSPI1 global OCTOSPI2 mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 sleep 1 mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock sleep 1 adapter speed 24000 if { $OCTOSPI1 } { octospi_init 1 } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32h745i-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is a stm32h745i-disco with a single STM32H745XIH6 chip. # www.st.com/en/product/stm32h745i-disco.html # # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd set CHIPNAME stm32h745xih6 # enable stmqspi if {![info exists QUADSPI]} { set QUADSPI 1 } source [find target/stm32h7x_dual_bank.cfg] reset_config srst_only source [find board/stm32h7x_dual_qspi.cfg] $_CHIPNAME.cpu0 configure -event reset-init { global QUADSPI mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 sleep 1 mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock sleep 1 adapter speed 24000 if { $QUADSPI } { qspi_init 1 } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32h747i-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is a stm32h747i-disco with a single STM32H747XIH6 chip. # www.st.com/en/product/stm32h747i-disco.html # # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd set CHIPNAME stm32h747xih6 # enable stmqspi if {![info exists QUADSPI]} { set QUADSPI 1 } source [find target/stm32h7x_dual_bank.cfg] reset_config srst_only # QUADSPI initialization # qpi: 4-line mode proc qspi_init { qpi } { global a mmw 0x580244E0 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x580244D4 0x00004000 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PG06: BK1_NCS, PB02: CLK, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PD11: BK1_IO0, # PG14: BK2_IO3, PG09: BK2_IO2, PH03: BK2_IO1, PH02: BK2_IO0 # PB02:AF09:V, PD11:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V, PG14:AF09:H # PG09:AF09:V, PG06:AF10:H, PH03:AF09:V, PH02:AF09:V # Port B: PB02:AF09:V mmw 0x58020400 0x00000020 0x00000010 ;# MODER mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR mmw 0x58020420 0x00000900 0x00000600 ;# AFRL # Port D: PD11:AF09:V mmw 0x58020C00 0x00800000 0x00400000 ;# MODER mmw 0x58020C08 0x00C00000 0x00000000 ;# OSPEEDR mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH # Port F: PF09:AF10:V, PF07:AF09:V, PF06:AF09:V mmw 0x58021400 0x0008A000 0x00045000 ;# MODER mmw 0x58021408 0x000CF000 0x00000000 ;# OSPEEDR mmw 0x58021420 0x99000000 0x66000000 ;# AFRL mmw 0x58021424 0x000000A0 0x00000050 ;# AFRH # Port G: PG14:AF09:H, PG09:AF09:V, PG06:AF10:H mmw 0x58021800 0x20082000 0x10041000 ;# MODER mmw 0x58021808 0x200C2000 0x10001000 ;# OSPEEDR mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL mmw 0x58021824 0x09000090 0x06000060 ;# AFRH # Port H: PH03:AF09:V, PH02:AF09:V mmw 0x58021C00 0x000000A0 0x00000050 ;# MODER mmw 0x58021C08 0x000000F0 0x00000000 ;# OSPEEDR mmw 0x58021C20 0x00009900 0x00006600 ;# AFRL # correct FSIZE is 0x1A, however, this causes trouble when # reading the last bytes at end of bank in *memory mapped* mode # for dual flash mode 2 * mt25ql512 mww 0x52005000 0x05500058 ;# QUADSPI_CR: PRESCALER=5, APMS=1, FTHRES=0, FSEL=0, DFM=1, SSHIFT=1, TCEN=1 mww 0x52005004 0x001A0200 ;# QUADSPI_DCR: FSIZE=0x1A, CSHT=0x02, CKMODE=0 mww 0x52005030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0x52005014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1 mmw 0x52005000 0x00000001 0 ;# QUADSPI_CR: EN=1 # Exit QPI mode mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=Exit QPI sleep 1 if { $qpi == 1 } { # Write Enable mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable sleep 1 # Configure dummy clocks via volatile configuration register mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes mww 0x52005014 0x01000181 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Volatile Conf. Reg. mwh 0x52005020 0xABAB ;# QUADSPI_DR: 0xAB 0xAB for 10 dummy clocks sleep 1 # Write Enable mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable sleep 1 # Enable QPI mode via enhanced volatile configuration register mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes mww 0x52005014 0x01000161 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enhanced Conf. Reg. mwh 0x52005020 0x3F3F ;# QUADSPI_DR: 0x3F 0x3F to enable QPI and DPI mode sleep 1 # Enter QPI mode mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x00000135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Enter QPI sleep 1 # memory-mapped fast read mode with 4-byte addresses and 10 dummy cycles (for read only) mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x3, DCYC=0xA, ADSIZE=0x3, ADMODE=0x3, IMODE=0x3, INSTR=Fast READ } else { # memory-mapped read mode with 4-byte addresses mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ } } $_CHIPNAME.cpu0 configure -event reset-init { global QUADSPI mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 sleep 1 mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock sleep 1 adapter speed 24000 if { $QUADSPI } { qspi_init 1 } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32h750b-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is a stm32h750b-dk with a single STM32H750XBH6 chip. # www.st.com/en/product/stm32h750b-dk.html # # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd set CHIPNAME stm32h750xbh6 # enable stmqspi if {![info exists QUADSPI]} { set QUADSPI 1 } source [find target/stm32h7x.cfg] reset_config srst_only source [find board/stm32h7x_dual_qspi.cfg] $_CHIPNAME.cpu0 configure -event reset-init { global QUADSPI mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 sleep 1 mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock sleep 1 adapter speed 24000 if { $QUADSPI } { qspi_init 1 } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32h7b3i-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is a stm32h7b3i-dk with a single STM32H7B3LIH6Q chip. # https://www.st.com/en/evaluation-tools/stm32h7b3i-dk.html # # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd set CHIPNAME stm32h7b3lih6q # enable stmqspi if {![info exists OCTOSPI1]} { set OCTOSPI1 1 set OCTOSPI2 0 } source [find target/stm32h7x_dual_bank.cfg] reset_config srst_only # OCTOSPI initialization # octo: 8-line mode proc octospi_init { octo } { global a b mmw 0x58024540 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x58024534 0x00284000 0 ;# RCC_AHB3ENR |= IOMNGREN, OSPI2EN, OSPI1EN (enable clocks) sleep 1 ;# Wait for clock startup mww 0x5200B404 0x03010111 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI1 mww 0x5200B408 0x00000000 ;# OCTOSPIM_P2CR: disable Port 2 # PG06: OCSPI1_NCS, PB02: OCSPI1_CLK, PC05: OCSPI1_DQS, PD07: OCSPI1_IO7, PG09: OCSPI1_IO6, PH03: OCSPI1_IO5, # PC01: OCSPI1_IO4, PF06: OCSPI1_IO3, PF07: OCSPI1_IO2, PF09: OCSPI1_IO1, PD11: OCSPI1_IO0 # PB02:AF09:V, PC05:AF10:V, PC01:AF10:V, PD11:AF09:V, PD07:AF10:V, PF09:AF10:V # PF07:AF10:V, PF06:AF10:V, PG09:AF09:V, PG06:AF10:V, PH03:AF09:V # Port B: PB02:AF09:V mmw 0x58020400 0x00000020 0x00000010 ;# MODER mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR mmw 0x5802040C 0x00000000 0x00000030 ;# PUPDR mmw 0x58020420 0x00000900 0x00000600 ;# AFRL # Port C: PC05:AF10:V, PC01:AF10:V mmw 0x58020800 0x00000808 0x00000404 ;# MODER mmw 0x58020808 0x00000C0C 0x00000000 ;# OSPEEDR mmw 0x5802080C 0x00000000 0x00000C0C ;# PUPDR mmw 0x58020820 0x00A000A0 0x00500050 ;# AFRL # Port D: PD11:AF09:V, PD07:AF10:V mmw 0x58020C00 0x00808000 0x00404000 ;# MODER mmw 0x58020C08 0x00C0C000 0x00000000 ;# OSPEEDR mmw 0x58020C0C 0x00000000 0x00C0C000 ;# PUPDR mmw 0x58020C20 0xA0000000 0x50000000 ;# AFRL mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH # Port F: PF09:AF10:V, PF07:AF10:V, PF06:AF10:V mmw 0x58021400 0x0008A000 0x00045000 ;# MODER mmw 0x58021408 0x000CF000 0x00000000 ;# OSPEEDR mmw 0x5802140C 0x00000000 0x000CF000 ;# PUPDR mmw 0x58021420 0xAA000000 0x55000000 ;# AFRL mmw 0x58021424 0x000000A0 0x00000050 ;# AFRH # Port G: PG09:AF09:V, PG06:AF10:V mmw 0x58021800 0x00082000 0x00041000 ;# MODER mmw 0x58021808 0x000C3000 0x00000000 ;# OSPEEDR mmw 0x5802180C 0x00000000 0x000C3000 ;# PUPDR mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL mmw 0x58021824 0x00000090 0x00000060 ;# AFRH # Port H: PH03:AF09:V mmw 0x58021C00 0x00000080 0x00000040 ;# MODER mmw 0x58021C08 0x000000C0 0x00000000 ;# OSPEEDR mmw 0x58021C0C 0x00000000 0x000000C0 ;# PUPDR mmw 0x58021C20 0x00009000 0x00006000 ;# AFRL # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses mww 0x52005130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 mww 0x52005008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 mww 0x5200500C 0x00000005 ;# OCTOSPI_DCR2: PRESCALER=5 mww 0x52005108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 mww 0x52005100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 mww 0x52005110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B flash probe $a ;# load configuration from CR, TCR, CCR, IR register values if { $octo == 1 } { stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 ;# Read Status Register stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 mww 0x52005108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 mww 0x52005100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 mww 0x52005110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 0 0x04 ;# Write Disable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits } } $_CHIPNAME.cpu0 configure -event reset-init { global OCTOSPI1 global OCTOSPI2 mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 sleep 1 mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock sleep 1 adapter speed 24000 if { $OCTOSPI1 } { octospi_init 1 } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32h7x3i_eval.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STM32H7[4|5]3I-EVAL: this is for the H7 eval boards. # This is an ST EVAL-H743XI board with single STM32H743XI chip. # http://www.st.com/en/evaluation-tools/stm32h743i-eval.html # This is an ST EVAL-H753XI board with single STM32H753XI chip. # http://www.st.com/en/evaluation-tools/stm32h753i-eval.html source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32h7x_dual_bank.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32h7x_dual_qspi.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # stm32h754i-disco and stm32h750b-dk dual quad qspi. # QUADSPI initialization # qpi: 4-line mode proc qspi_init { qpi } { global a mmw 0x580244E0 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) mmw 0x580244D4 0x00004000 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PG06: BK1_NCS, PF10: CLK, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PD11: BK1_IO0, # PG14: BK2_IO3, PG09: BK2_IO2, PH03: BK2_IO1, PH02: BK2_IO0 # PD11:AF09:V, PF10:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V, PG14:AF09:H # PG09:AF09:V, PG06:AF10:H, PH03:AF09:V, PH02:AF09:V # Port D: PD11:AF09:V mmw 0x58020C00 0x00800000 0x00400000 ;# MODER mmw 0x58020C08 0x00C00000 0x00000000 ;# OSPEEDR mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH # Port F: PF10:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V mmw 0x58021400 0x0028A000 0x00145000 ;# MODER mmw 0x58021408 0x003CF000 0x00000000 ;# OSPEEDR mmw 0x58021420 0x99000000 0x66000000 ;# AFRL mmw 0x58021424 0x000009A0 0x00000650 ;# AFRH # Port G: PG14:AF09:H, PG09:AF09:V, PG06:AF10:H mmw 0x58021800 0x20082000 0x10041000 ;# MODER mmw 0x58021808 0x200C2000 0x10001000 ;# OSPEEDR mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL mmw 0x58021824 0x09000090 0x06000060 ;# AFRH # Port H: PH03:AF09:V, PH02:AF09:V mmw 0x58021C00 0x000000A0 0x00000050 ;# MODER mmw 0x58021C08 0x000000F0 0x00000000 ;# OSPEEDR mmw 0x58021C20 0x00009900 0x00006600 ;# AFRL # correct FSIZE is 0x1A, however, this causes trouble when # reading the last bytes at end of bank in *memory mapped* mode # for dual flash mode 2 * mt25ql512 mww 0x52005000 0x05500058 ;# QUADSPI_CR: PRESCALER=5, APMS=1, FTHRES=0, FSEL=0, DFM=1, SSHIFT=1, TCEN=1 mww 0x52005004 0x001A0200 ;# QUADSPI_DCR: FSIZE=0x1A, CSHT=0x02, CKMODE=0 mww 0x52005030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0x52005014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1 mmw 0x52005000 0x00000001 0 ;# QUADSPI_CR: EN=1 # Exit QPI mode mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=Exit QPI sleep 1 if { $qpi == 1 } { # Write Enable mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable sleep 1 # Configure dummy clocks via volatile configuration register mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes mww 0x52005014 0x01000181 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Volatile Conf. Reg. mwh 0x52005020 0xABAB ;# QUADSPI_DR: 0xAB 0xAB for 10 dummy clocks sleep 1 # Write Enable mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable sleep 1 # Enable QPI mode via enhanced volatile configuration register mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes mww 0x52005014 0x01000161 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enhanced Conf. Reg. mwh 0x52005020 0x3F3F ;# QUADSPI_DR: 0x3F 0x3F to enable QPI and DPI mode sleep 1 # Enter QPI mode mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x00000135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Enter QPI sleep 1 # memory-mapped fast read mode with 4-byte addresses and 10 dummy cycles (for read only) mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x3, DCYC=0xA, ADSIZE=0x3, ADMODE=0x3, IMODE=0x3, INSTR=Fast READ } else { # memory-mapped read mode with 4-byte addresses mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 mww 0x52005014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32l0discovery.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32L053 discovery board with a single STM32L053 chip. # http://www.st.com/web/en/catalog/tools/PF260319 source [find interface/stlink.cfg] transport select hla_swd set WORKAREASIZE 0x2000 source [find target/stm32l0.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32l476g-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32L476G discovery board with a single STM32L476VGT6 chip. # http://www.st.com/en/evaluation-tools/32l476gdiscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 96KB set WORKAREASIZE 0x18000 # enable stmqspi set QUADSPI 1 source [find target/stm32l4x.cfg] # QUADSPI initialization proc qspi_init { } { global a mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks) mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PE11: NCS, PE10: CLK, PE15: BK1_IO3, PE14: BK1_IO2, PE13: BK1_IO1, PE12: BK1_IO0 # PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V # Port E: PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V mmw 0x48001000 0xAAA00000 0x55500000 ;# MODER mmw 0x48001008 0xFFF00000 0x00000000 ;# OSPEEDR mmw 0x48001024 0xAAAAAA00 0x55555500 ;# AFRH mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # memory-mapped read mode with 3-byte addresses mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK sleep 1 mmw 0x40021000 0x00000100 0x00000000 ;# HSI on mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 mmw 0x40021000 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32l496g-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32L496G discovery board with a single STM32L496AGI6 chip. # http://www.st.com/en/evaluation-tools/32l496gdiscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 96KB set WORKAREASIZE 0x18000 # enable stmqspi set QUADSPI 1 source [find target/stm32l4x.cfg] # QUADSPI initialization proc qspi_init { } { global a mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks) mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) sleep 1 ;# Wait for clock startup # PB11: BK1_NCS, PA03: CLK, PA06: BK1_IO3, PA07: BK1_IO2, PB00: BK1_IO1, PB01: BK1_IO0 # PA07:AF10:V, PA06:AF10:V, PA03:AF10:V, PB11:AF10:V, PB01:AF10:V, PB00:AF10:V # Port A: PA07:AF10:V, PA06:AF10:V, PA03:AF10:V mmw 0x48000000 0x0000A080 0x00005040 ;# MODER mmw 0x48000008 0x0000F0C0 0x00000000 ;# OSPEEDR mmw 0x48000020 0xAA00A000 0x55005000 ;# AFRL # Port B: PB11:AF10:V, PB01:AF10:V, PB00:AF10:V mmw 0x48000400 0x0080000A 0x00400005 ;# MODER mmw 0x48000408 0x00C0000F 0x00000000 ;# OSPEEDR mmw 0x48000420 0x000000AA 0x00000055 ;# AFRL mmw 0x48000424 0x0000A000 0x00005000 ;# AFRH mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 mww 0xA0001004 0x00160100 ;# QUADSPI_DCR: FSIZE=0x16, CSHT=0x01, CKMODE=0 mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 # 1-line spi mode mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO sleep 1 # memory-mapped read mode with 3-byte addresses mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ } $_TARGETNAME configure -event reset-init { mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK sleep 1 mmw 0x40021000 0x00000100 0x00000000 ;# HSI on mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 mmw 0x40021000 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 qspi_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32l4discovery.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Explicitly for the STM32L476 discovery board: # http://www.st.com/web/en/catalog/tools/PF261635 # but perfectly functional for any other STM32L4 board connected via # an stlink-v2-1 interface. # This is for STM32L4 boards that are connected via stlink-v2-1. source [find interface/stlink.cfg] transport select hla_swd source [find target/stm32l4x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32l4p5g-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is a STM32L4P5G discovery board with a single STM32L4R9AGI6 chip. # http://www.st.com/en/evaluation-tools/stm32l4p5g-dk.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 96KB set WORKAREASIZE 0x18000 # enable stmqspi set OCTOSPI1 1 set OCTOSPI2 0 source [find target/stm32l4x.cfg] # OCTOSPI initialization # octo: 8-line mode proc octospi_init { octo } { global a b mmw 0x4002104C 0x001001FF 0 ;# RCC_AHB2ENR |= OSPIMEN, GPIOAEN-GPIOIEN (enable clocks) mmw 0x40021050 0x00000300 0 ;# RCC_AHB3ENR |= OSPI2EN, OSPI1EN (enable clocks) mmw 0x40021058 0x10000000 0 ;# RCC_APB1ENR1 |= PWREN (enable clock) sleep 1 ;# Wait for clock startup mmw 0x40007004 0x00000200 0 ;# PWR_CR2 |= IOSV (required for use of GPOIG, cf. RM0432) mww 0x50061C04 0x07050333 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI2 mww 0x50061C08 0x03010111 ;# OCTOSPIM_P2CR: assign Port 2 to OCTOSPI1 # PE11: P1_NCS, PE10: P1_CLK, PG06: P1_DQS, PD07: P1_IO7, PC03: P1_IO6, PD05: P1_IO5 # PD04: P1_IO4, PA06: P1_IO3, PA07: P1_IO2, PE13: P1_IO1, PE11: P1_IO0 # PA07:AF10:V, PA06:AF10:V, PC03:AF10:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V # PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V, PG06:AF03:V # Port A: PA07:AF10:V, PA06:AF10:V mmw 0x48000000 0x0000A000 0x00005000 ;# MODER mmw 0x48000008 0x0000F000 0x00000000 ;# OSPEEDR mmw 0x4800000C 0x00000000 0x0000F000 ;# PUPDR mmw 0x48000020 0xAA000000 0x55000000 ;# AFRL # Port C: PC03:AF10:V mmw 0x48000800 0x00000080 0x00000040 ;# MODER mmw 0x48000808 0x000000C0 0x00000000 ;# OSPEEDR mmw 0x4800080C 0x00000000 0x000000C0 ;# PUPDR mmw 0x48000820 0x0000A000 0x00005000 ;# AFRL # Port D: PD07:AF10:V, PD05:AF10:V, PD04:AF10:V mmw 0x48000C00 0x00008A00 0x00004500 ;# MODER mmw 0x48000C08 0x0000CF00 0x00000000 ;# OSPEEDR mmw 0x48000C0C 0x00000000 0x0000CF00 ;# PUPDR mmw 0x48000C20 0xA0AA0000 0x50550000 ;# AFRL # Port E: PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V mmw 0x48001000 0x0AA00000 0x05500000 ;# MODER mmw 0x48001008 0x0FF00000 0x00000000 ;# OSPEEDR mmw 0x4800100C 0x00000000 0x0FF00000 ;# PUPDR mmw 0x48001024 0x00AAAA00 0x00555500 ;# AFRH # Port G: PG06:AF03:V mmw 0x48001800 0x00002000 0x00001000 ;# MODER mmw 0x48001808 0x00003000 0x00000000 ;# OSPEEDR mmw 0x4800180C 0x00000000 0x00003000 ;# PUPDR mmw 0x48001820 0x03000000 0x0C000000 ;# AFRL # PG12: P2_NCS, PF04: P2_CLK, PF12: P2_DQS, PG10: P2_IO7, PG09: P2_IO6, PG01: P2_IO5 # PG00: P2_IO4, PF03: P2_IO3, PF02: P2_IO2, PF01: P2_IO1, PF00: P2_IO0 # PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V # PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V # Port F: PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V mmw 0x48001400 0x020002AA 0x01000155 ;# MODER mmw 0x48001408 0x030003FF 0x00000000 ;# OSPEEDR mmw 0x4800140C 0x00000000 0x030003FF ;# PUPDR mmw 0x48001420 0x00055555 0x000AAAAA ;# AFRL mmw 0x48001424 0x00050000 0x000A0000 ;# AFRH # Port G: PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V mmw 0x48001800 0x0228000A 0x01140005 ;# MODER mmw 0x48001808 0x033C000F 0x00000000 ;# OSPEEDR mmw 0x4800180C 0x00000000 0x033C000F ;# PUPDR mmw 0x48001820 0x00000055 0x000000AA ;# AFRL mmw 0x48001824 0x00050550 0x000A0AA0 ;# AFRH # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses mww 0xA0001130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 mww 0xA0001008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 mww 0xA000100C 0x00000001 ;# OCTOSPI_DCR2: PRESCALER=1 mww 0xA0001108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 mww 0xA0001100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 mww 0xA0001110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B if { $octo == 1 } { stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 ;# Read Status Register stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 mww 0xA0001108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 mww 0xA0001100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 mww 0xA0001110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 0 0x04 ;# Write Disable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits } } $_TARGETNAME configure -event reset-init { mmw 0x40022000 0x00000003 0x0000000C ;# 3 WS for 72 MHz HCLK sleep 1 mmw 0x40021000 0x00000100 0x00000000 ;# HSI on mww 0x4002100C 0x01002432 ;# RCC_PLLCFGR 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 mmw 0x40021000 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL sleep 1 adapter speed 24000 octospi_init 1 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32l4r9i-disco.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is a STM32L4R9I discovery board with a single STM32L4R9AII6 chip. # http://www.st.com/en/evaluation-tools/32l4r9idiscovery.html # This is for using the onboard STLINK source [find interface/stlink.cfg] transport select hla_swd # increase working area to 96KB set WORKAREASIZE 0x18000 # enable stmqspi set OCTOSPI1 1 set OCTOSPI2 0 source [find target/stm32l4x.cfg] # OCTOSPI initialization # octo: 8-line mode proc octospi_init { octo } { global a b mmw 0x4002104C 0x001001FF 0 ;# RCC_AHB2ENR |= OSPIMEN, GPIOAEN-GPIOIEN (enable clocks) mmw 0x40021050 0x00000300 0 ;# RCC_AHB3ENR |= OSPI2EN, OSPI1EN (enable clocks) mmw 0x40021058 0x10000000 0 ;# RCC_APB1ENR1 |= PWREN (enable clock) sleep 1 ;# Wait for clock startup mmw 0x40007004 0x00000200 0 ;# PWR_CR2 |= IOSV (required for use of GPOIG, cf. RM0432) mww 0x50061C04 0x00000000 ;# OCTOSPIM_P1CR: disable Port 1 mww 0x50061C08 0x03010111 ;# OCTOSPIM_P2CR: assign Port 2 to OCTOSPI1 # PG12: P2_NCS, PI06: P2_CLK, PG15: P2_DQS, PG10: P2_IO7, PG09: P2_IO6, PH10: P2_IO5, # PH09: P2_IO4, PH08: P2_IO3, PI09: P2_IO2, PI10: P2_IO1, PI11: P2_IO0 # PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PH10:AF05:V, PH09:AF05:V # PH08:AF05:V, PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V # Port G: PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V mmw 0x48001800 0x82280000 0x41140000 ;# MODER mmw 0x48001808 0xC33C0000 0x00000000 ;# OSPEEDR mmw 0x48001824 0x50050550 0xA00A0AA0 ;# AFRH # Port H: PH10:AF05:V, PH09:AF05:V, PH08:AF05:V mmw 0x48001C00 0x002A0000 0x00150000 ;# MODER mmw 0x48001C08 0x003F0000 0x00000000 ;# OSPEEDR mmw 0x48001C24 0x00000555 0x00000AAA ;# AFRH # Port I: PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V mmw 0x48002000 0x00A82000 0x00541000 ;# MODER mmw 0x48002008 0x00FC3000 0x00000000 ;# OSPEEDR mmw 0x48002020 0x05000000 0x0A000000 ;# AFRL mmw 0x48002024 0x00005550 0x0000AAA0 ;# AFRH # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses mww 0xA0001130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 mww 0xA0001008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 mww 0xA000100C 0x00000001 ;# OCTOSPI_DCR2: PRESCALER=1 mww 0xA0001108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 mww 0xA0001100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 mww 0xA0001110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B if { $octo == 1 } { stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 ;# Read Status Register stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 mww 0xA0001108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 mww 0xA0001100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 mww 0xA0001110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values stmqspi cmd $a 0 0x06 ;# Write Enable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 0 0x04 ;# Write Disable stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits } } $_TARGETNAME configure -event reset-init { mmw 0x40022000 0x00000003 0x0000000C ;# 3 WS for 72 MHz HCLK sleep 1 mmw 0x40021000 0x00000100 0x00000000 ;# HSI on mww 0x4002100C 0x01002432 ;# RCC_PLLCFGR 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 mmw 0x40021000 0x01000000 0x00000000 ;# PLL on sleep 1 mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL sleep 1 adapter speed 4000 octospi_init 1 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32ldiscovery.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32L discovery board with a single STM32L152RBT6 chip. # http://www.st.com/internet/evalboard/product/250990.jsp source [find interface/stlink.cfg] transport select hla_swd set WORKAREASIZE 0x4000 source [find target/stm32l1.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32mp13x_dk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # board MB1635x # http://www.st.com/en/evaluation-tools/stm32mp135f-dk.html source [find interface/stlink-dap.cfg] transport select dapdirect_swd source [find target/stm32mp13x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32mp15x_dk2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # board MB1272B # http://www.st.com/en/evaluation-tools/stm32mp157a-dk1.html # http://www.st.com/en/evaluation-tools/stm32mp157c-dk2.html source [find interface/stlink-dap.cfg] transport select dapdirect_swd source [find target/stm32mp15x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/stm32vldiscovery.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is an STM32VL discovery board with a single STM32F100RB chip. # http://www.st.com/internet/evalboard/product/250863.jsp source [find interface/stlink.cfg] transport select hla_swd set WORKAREASIZE 0x2000 source [find target/stm32f1x.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/str910-eval.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # str910-eval eval board # # Need reset scripts reset_config trst_and_srst # FIXME use some standard target config, maybe create one from this # # source [find target/...cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME str912 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists FLASHTAPID] } { set _FLASHTAPID $FLASHTAPID } else { set _FLASHTAPID 0x04570041 } jtag newtap $_CHIPNAME flash -irlen 8 -ircapture 0x1 -irmask 0x1 -expected-id $_FLASHTAPID if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x25966041 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID if { [info exists BSTAPID] } { set _BSTAPID $BSTAPID } else { set _BSTAPID 0x1457f041 } jtag newtap $_CHIPNAME bs -irlen 5 -ircapture 0x1 -irmask 0x1 -expected-id $_BSTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x50000000 -work-area-size 16384 -work-area-backup 1 $_TARGETNAME configure -event reset-init { # We can increase speed now that we know the target is halted. #jtag_rclk 3000 # -- Enable 96K RAM # PFQBC enabled / DTCM & AHB wait-states disabled mww 0x5C002034 0x0191 str9x flash_config 0 4 2 0 0x80000 flash protect 0 0 7 off } #flash bank str9x <base> <size> 0 0 <target#> <variant> set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME str9x 0x00000000 0x00080000 0 0 0 set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME str9x 0x00080000 0x00008000 0 0 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/telo.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/c100.cfg] # basic register definition for C100 source [find target/c100regs.tcl] # board-config info source [find target/c100config.tcl] # C100 helper functions source [find target/c100helper.tcl] # Telo board & C100 support trst and srst # make the reset asserted to # allow RC circuit to discharge for: [ms] adapter srst pulse_width 100 jtag_ntrst_assert_width 100 # don't talk to JTAG after reset for: [ms] adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst separate # issue telnet: reset init # issue gdb: monitor reset init $_TARGETNAME configure -event reset-init { adapter speed 100 # this will setup Telo board setupTelo #turn up the JTAG speed adapter speed 3000 echo "JTAG speek now 3MHz" echo "type helpC100 to get help on C100" } $_TARGETNAME configure -event reset-deassert-post { # Force target into ARM state. # soft_reset_halt ;# not implemented on ARM11 echo "Detected SRSRT asserted on C100.CPU" } $_TARGETNAME configure -event reset-assert-post { echo "Assering reset" #sleep 10 } proc power_restore {} { echo "Sensed power restore. No action." } proc srst_deasserted {} { echo "Sensed nSRST deasserted. No action." } # boots from NOR on CS0: 8 MBytes CFI flash, 16-bit bus # it's really 16MB but the upper 8mb is controller via gpio # openocd does not support 'complex reads/writes' to NOR set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x20000000 0x01000000 2 2 $_TARGETNAME # writing data to memory does not work without this arm11 memwrite burst disable ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_am335xevm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI AM335x Evaluation Module # # For more information please see http://www.ti.com/tool/tmdxevm3358 # jtag_rclk 6000 source [find target/am335x.cfg] reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_am437x_idk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Texas Instruments AM437x Industrial Development Kit # The JTAG interface is built directly on the board. source [find interface/ftdi/xds100v2.cfg] transport select jtag adapter speed 30000 source [find target/am437x.cfg] $_TARGETNAME configure -event reset-init { init_platform 0x61a11b32 } reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_am43xx_evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Works on both AM437x GP EVM and AM438x ePOS EVM transport select jtag adapter speed 16000 source [find target/am437x.cfg] reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_am625evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2021-2022 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments am625 EVM/SK # Link: https://www.ti.com/lit/zip/sprr448 # # AM625 EVM has an xds110 onboard. source [find interface/xds110.cfg] transport select jtag # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive adapter srst delay 20 if { ![info exists SOC] } { set SOC am625 } source [find target/ti_k3.cfg] adapter speed 2500 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_am642evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments AM642 EVM # # AM642 EVM has an xds110 onboard. source [find interface/xds110.cfg] transport select jtag # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive adapter srst delay 20 if { ![info exists SOC] } { set SOC am642 } source [find target/ti_k3.cfg] adapter speed 250 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_am654evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments AM654 EVM/IDK Base Board # # AM654 EVM has an xds110 onboard. source [find interface/xds110.cfg] transport select jtag # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive adapter srst delay 70 if { ![info exists SOC] } { set SOC am654 } source [find target/ti_k3.cfg] adapter speed 2500 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_beagleboard.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # OMAP3 BeagleBoard # http://beagleboard.org # Fall back to 6MHz if RTCK is not supported jtag_rclk 6000 source [find target/omap3530.cfg] # TI-14 JTAG connector reset_config trst_only # Later run: omap3_dbginit ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_beagleboard_xm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # BeagleBoard xM (DM37x) # http://beagleboard.org set CHIPTYPE "dm37x" source [find target/amdm37x.cfg] # The TI-14 JTAG connector does not have srst. CPU reset is handled in # hardware. reset_config trst_only # "amdm37x_dbginit dm37x.cpu" needs to be run after init. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_beaglebone-base.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # AM335x Beaglebone family base configuration # http://beagleboard.org/bone source [find target/am335x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_beaglebone.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # AM335x Beaglebone # http://beagleboard.org/bone # The JTAG interface is built directly on the board. source [find interface/ftdi/xds100v2.cfg] adapter speed 16000 reset_config trst_and_srst source [find board/ti_beaglebone-base.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_beaglebone_black.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # AM335x Beaglebone Black # http://beagleboard.org/bone adapter speed 1000 reset_config trst_and_srst source [find board/ti_beaglebone-base.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_blaze.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later jtag_rclk 6000 source [find target/omap4430.cfg] reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_cc13x0_launchpad.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI CC13x0 LaunchPad Evaluation Kit # source [find interface/xds110.cfg] transport select jtag adapter speed 5500 source [find target/ti_cc13x0.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_cc13x2_launchpad.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI CC13x2 LaunchPad Evaluation Kit # source [find interface/xds110.cfg] adapter speed 5500 transport select jtag source [find target/ti_cc13x2.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_cc26x0_launchpad.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI CC26x0 LaunchPad Evaluation Kit # source [find interface/xds110.cfg] adapter speed 5500 transport select jtag source [find target/ti_cc26x0.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_cc26x2_launchpad.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI CC26x2 LaunchPad Evaluation Kit # source [find interface/xds110.cfg] adapter speed 5500 transport select jtag source [find target/ti_cc26x2.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_cc3200_launchxl.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI SimpleLink Wi-Fi CC3200 LaunchPad # # http://www.ti.com/tool/cc3200-launchxl # source [find interface/ftdi/ti-icdi.cfg] if { [info exists TRANSPORT] } { transport select $TRANSPORT } else { transport select jtag } adapter speed 2500 set WORKAREASIZE 0x40000 source [find target/ti_cc32xx.cfg] reset_config srst_only adapter srst delay 1100 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_cc3220sf_launchpad.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI CC3220SF-LaunchXL LaunchPad Evaluation Kit # source [find interface/xds110.cfg] adapter speed 8500 transport select swd source [find target/ti_cc3220sf.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_cc32xx_launchpad.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI CC32xx-LaunchXL LaunchPad Evaluation Kit # source [find interface/xds110.cfg] adapter speed 8500 transport select swd source [find target/ti_cc32xx.cfg] reset_config srst_only adapter srst delay 1100 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_dk-tm4c129.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI Tiva C DK-TM4C129X Connected Development Kit # # http://www.ti.com/tool/dk-tm4c129x # source [find interface/ti-icdi.cfg] transport select hla_jtag set WORKAREASIZE 0x8000 set CHIPNAME tm4c129xnczad source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_ek-tm4c123gxl.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI Tiva C Series ek-tm4c123gxl Launchpad Evaluation Kit # # http://www.ti.com/tool/ek-tm4c123gxl # source [find interface/ti-icdi.cfg] transport select hla_jtag set WORKAREASIZE 0x8000 set CHIPNAME tm4c123gh6pm source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_ek-tm4c1294xl.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI Tiva C Series ek-tm4c1294xl Launchpad Evaluation Kit # # http://www.ti.com/tool/ek-tm4c1294xl # source [find interface/ti-icdi.cfg] transport select hla_jtag set WORKAREASIZE 0x8000 set CHIPNAME tm4c1294ncpdt source [find target/stellaris.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_j7200evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments J7200 EVM # # J7200 EVM has an xds110 onboard. source [find interface/xds110.cfg] transport select jtag # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive adapter srst delay 20 if { ![info exists SOC] } { set SOC j7200 } source [find target/ti_k3.cfg] adapter speed 2500 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_j721evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments J721E EVM # # J721E EVM has an xds110 onboard. source [find interface/xds110.cfg] transport select jtag # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive adapter srst delay 20 if { ![info exists SOC] } { set SOC j721e } source [find target/ti_k3.cfg] adapter speed 2500 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_j721s2evm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments J721s2 EVM # Link(SoM): https://www.ti.com/lit/zip/sprr439 # # J721s2 EVM has an xds110 onboard. source [find interface/xds110.cfg] transport select jtag # default JTAG configuration has only SRST and no TRST reset_config srst_only srst_push_pull # delay after SRST goes inactive adapter srst delay 20 if { ![info exists SOC] } { set SOC j721s2 } source [find target/ti_k3.cfg] adapter speed 2500 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_msp432_launchpad.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI MSP432 LaunchPad Evaluation Kit # source [find interface/xds110.cfg] adapter speed 10000 transport select swd source [find target/ti_msp432.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_pandaboard.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later jtag_rclk 6000 source [find target/omap4430.cfg] reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_pandaboard_es.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later jtag_rclk 6000 source [find target/omap4460.cfg] reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_tmdx570ls20susb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # TMS570 Microcontroller USB Kit # http://www.ti.com/tool/TMDX570LS20SUSB # Board uses a FT2232H to emulate an XDS100v2 JTAG debugger # TODO: board also supports an SCI UART on the 2232's B Bus source [find interface/ftdi/xds100v2.cfg] # Processor is TMS570LS20216 source [find target/ti_tms570ls20xxx.cfg] reset_config trst_only # xds100v2 config says add this to the end init ftdi set_signal PWR_RST 1 jtag arp_init ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/ti_tmdx570ls31usb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later adapter speed 1500 source [find interface/ftdi/xds100v2.cfg] source [find target/ti_tms570.cfg] reset_config trst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/tocoding_poplar.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # board configuration for Tocoding Poplar # # board does not feature anything but JTAG transport select jtag adapter speed 10000 # SRST-only reset configuration reset_config srst_only srst_push_pull source [find target/hi3798.cfg] # make sure the default target is the boot core targets ${_TARGETNAME}0 proc core_up { args } { global _TARGETNAME # examine remaining cores foreach _core $args { ${_TARGETNAME}$_core arp_examine } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/topas910.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: Toshiba TOPAS910 -- TMPA910 Starterkit # ###################################### # We add to the minimal configuration. source [find target/tmpa910.cfg] ###################### # Target configuration ###################### #$_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { topas910_init } proc topas910_init { } { # Init PLL # my settings mww 0xf005000c 0x00000007 mww 0xf0050010 0x00000065 mww 0xf005000c 0x000000a7 sleep 10 mdw 0xf0050008 mww 0xf0050008 0x00000002 mww 0xf0050004 0x00000000 # NEW: set CLKCR5 mww 0xf0050054 0x00000040 # sleep 10 # Init SDRAM # _PMCDRV = 0x00000071; # // # // Initialize SDRAM timing parameter # // # _DMC_CAS_LATENCY = 0x00000006; # _DMC_T_DQSS = 0x00000000; # _DMC_T_MRD = 0x00000002; # _DMC_T_RAS = 0x00000007; # # _DMC_T_RC = 0x0000000A; # _DMC_T_RCD = 0x00000013; # # _DMC_T_RFC = 0x0000010A; # # _DMC_T_RP = 0x00000013; # _DMC_T_RRD = 0x00000002; # _DMC_T_WR = 0x00000002; # _DMC_T_WTR = 0x00000001; # _DMC_T_XP = 0x0000000A; # _DMC_T_XSR = 0x0000000B; # _DMC_T_ESR = 0x00000014; # # // # // Configure SDRAM type parameter # _DMC_MEMORY_CFG = 0x00008011; # _DMC_USER_CONFIG = 0x00000011; # // 32 bit memory interface # # # _DMC_REFRESH_PRD = 0x00000A60; # _DMC_CHIP_0_CFG = 0x000140FC; # # _DMC_DIRECT_CMD = 0x000C0000; # _DMC_DIRECT_CMD = 0x00000000; # # _DMC_DIRECT_CMD = 0x00040000; # _DMC_DIRECT_CMD = 0x00040000; # _DMC_DIRECT_CMD = 0x00080031; # // # // Finally start SDRAM # // # _DMC_MEMC_CMD = MEMC_CMD_GO; # */ mww 0xf0020260 0x00000071 mww 0xf4300014 0x00000006 mww 0xf4300018 0x00000000 mww 0xf430001C 0x00000002 mww 0xf4300020 0x00000007 mww 0xf4300024 0x0000000A mww 0xf4300028 0x00000013 mww 0xf430002C 0x0000010A mww 0xf4300030 0x00000013 mww 0xf4300034 0x00000002 mww 0xf4300038 0x00000002 mww 0xf430003C 0x00000001 mww 0xf4300040 0x0000000A mww 0xf4300044 0x0000000B mww 0xf4300048 0x00000014 mww 0xf430000C 0x00008011 mww 0xf4300304 0x00000011 mww 0xf4300010 0x00000A60 mww 0xf4300200 0x000140FC mww 0xf4300008 0x000C0000 mww 0xf4300008 0x00000000 mww 0xf4300008 0x00040000 mww 0xf4300008 0x00040000 mww 0xf4300008 0x00080031 mww 0xf4300004 0x00000000 sleep 10 # adapter speed NNNN # remap off in case of IROM boot mww 0xf0000004 0x00000001 } # comment the following out if usinf J-Link, it soes not support DCC arm7_9 dcc_downloads enable ;# Enable faster DCC downloads ##################### # Flash configuration ##################### #flash bank <name> cfi <base> <size> <chip width> <bus width> <target> set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x20000000 0x2000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/topasa900.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Thanks to Pieter Conradie for this script! # Target: Toshiba TOPAS900 -- TMPA900 Starterkit ###################################### # We add to the minimal configuration. source [find target/tmpa900.cfg] ###################### # Target configuration ###################### #$_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { topasa900_init } proc topasa900_init { } { # Init PLL # my settings mww 0xf005000c 0x00000007 mww 0xf0050010 0x00000065 mww 0xf005000c 0x000000a7 sleep 10 mdw 0xf0050008 mww 0xf0050008 0x00000002 mww 0xf0050004 0x00000000 # NEW: set CLKCR5 mww 0xf0050054 0x00000040 # # bplan settings # mww 0xf0050004 0x00000000 # mww 0xf005000c 0x000000a7 # sleep 10 # mdw 0xf0050008 # mww 0xf0050008 0x00000002 # mww 0xf0050010 0x00000065 # mww 0xf0050054 0x00000040 sleep 10 # Init SDRAM # _PMCDRV = 0x00000071; # // # // Initialize SDRAM timing parameter # // # _DMC_CAS_LATENCY = 0x00000006; # _DMC_T_DQSS = 0x00000000; # _DMC_T_MRD = 0x00000002; # _DMC_T_RAS = 0x00000007; # # _DMC_T_RC = 0x0000000A; # _DMC_T_RCD = 0x00000013; # # _DMC_T_RFC = 0x0000010A; # # _DMC_T_RP = 0x00000013; # _DMC_T_RRD = 0x00000002; # _DMC_T_WR = 0x00000002; # _DMC_T_WTR = 0x00000001; # _DMC_T_XP = 0x0000000A; # _DMC_T_XSR = 0x0000000B; # _DMC_T_ESR = 0x00000014; # # // # // Configure SDRAM type parameter # _DMC_MEMORY_CFG = 0x00008011; # _DMC_USER_CONFIG = 0x00000011; // 32 bit memory interface # # # _DMC_REFRESH_PRD = 0x00000A60; # _DMC_CHIP_0_CFG = 0x000140FC; # # _DMC_DIRECT_CMD = 0x000C0000; # _DMC_DIRECT_CMD = 0x00000000; # # _DMC_DIRECT_CMD = 0x00040000; # _DMC_DIRECT_CMD = 0x00040000; # _DMC_DIRECT_CMD = 0x00080031; # // # // Finally start SDRAM # // # _DMC_MEMC_CMD = MEMC_CMD_GO; # */ mww 0xf0020260 0x00000071 mww 0xf4300014 0x00000006 mww 0xf4300018 0x00000000 mww 0xf430001C 0x00000002 mww 0xf4300020 0x00000007 mww 0xf4300024 0x0000000A mww 0xf4300028 0x00000013 mww 0xf430002C 0x0000010A mww 0xf4300030 0x00000013 mww 0xf4300034 0x00000002 mww 0xf4300038 0x00000002 mww 0xf430003C 0x00000001 mww 0xf4300040 0x0000000A mww 0xf4300044 0x0000000B mww 0xf4300048 0x00000014 mww 0xf430000C 0x00008011 mww 0xf4300304 0x00000011 mww 0xf4300010 0x00000A60 mww 0xf4300200 0x000140FC mww 0xf4300008 0x000C0000 mww 0xf4300008 0x00000000 mww 0xf4300008 0x00040000 mww 0xf4300008 0x00040000 mww 0xf4300008 0x00080031 mww 0xf4300004 0x00000000 sleep 10 # adapter speed NNNN # remap off in case of IROM boot mww 0xf0000004 0x00000001 } # comment the following out if usinf J-Link, it soes not support DCC arm7_9 dcc_downloads enable ;# Enable faster DCC downloads ##################### # Flash configuration ##################### #flash bank <name> cfi <base> <size> <chip width> <bus width> <target> set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x20000000 0x1000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/tp-link_tl-mr3020.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/atheros_ar9331.cfg] $_TARGETNAME configure -event reset-init { ar9331_25mhz_pll_init sleep 1 ar9331_ddr1_init } set ram_boot_address 0xa0000000 $_TARGETNAME configure -work-area-phys 0xa1FFE000 -work-area-size 0x1000 flash bank flash0 ath79 0xbf000000 0 0 0 $_TARGETNAME cs0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/tp-link_wdr4300.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/atheros_ar9344.cfg] reset_config trst_only separate proc ar9344_40mhz_pll_init {} { # QCA_PLL_SRIF_CPU_DPLL2_REG mww 0xb81161C4 0x13210f00 # QCA_PLL_SRIF_CPU_DPLL3_REG mww 0xb81161C8 0x03000000 # QCA_PLL_SRIF_DDR_DPLL2_REG mww 0xb8116244 0x13210f00 # QCA_PLL_SRIF_DDR_DPLL3_REG mww 0xb8116248 0x03000000 # QCA_PLL_SRIF_BB_DPLL_BASE_REG mww 0xb8116188 0x03000000 # QCA_PLL_CPU_DDR_CLK_CTRL_REG mww 0xb8050008 0x0130001C mww 0xb8050008 0x0130001C mww 0xb8050008 0x0130001C # QCA_PLL_CPU_PLL_CFG_REG mww 0xb8050000 0x40021380 # QCA_PLL_DDR_PLL_CFG_REG mww 0xb8050004 0x40815800 # QCA_PLL_CPU_DDR_CLK_CTRL_REG mww 0xb8050008 0x0130801C # QCA_PLL_SRIF_CPU_DPLL2_REG mww 0xb81161C4 0x10810F00 mww 0xb81161C0 0x41C00000 # QCA_PLL_SRIF_CPU_DPLL2_REG mww 0xb81161C4 0xD0810F00 # QCA_PLL_SRIF_CPU_DPLL3_REG mww 0xb81161C8 0x03000000 # QCA_PLL_SRIF_CPU_DPLL2_REG mww 0xb81161C4 0xD0800F00 # QCA_PLL_SRIF_CPU_DPLL3_REG mww 0xb81161C8 0x03000000 # QCA_PLL_SRIF_CPU_DPLL3_REG mww 0xb81161C8 0x43000000 # QCA_PLL_SRIF_CPU_DPLL3_REG mww 0xb81161C8 0x030003E8 # QCA_PLL_SRIF_DDR_DPLL2_REG mww 0xb8116244 0x10810F00 mww 0xb8116240 0x41680000 # QCA_PLL_SRIF_DDR_DPLL2_REG mww 0xb8116244 0xD0810F00 # QCA_PLL_SRIF_DDR_DPLL3_REG mww 0xb8116248 0x03000000 # QCA_PLL_SRIF_DDR_DPLL2_REG mww 0xb8116244 0xD0800F00 # QCA_PLL_SRIF_DDR_DPLL3_REG mww 0xb8116248 0x03000000 # QCA_PLL_SRIF_DDR_DPLL3_REG mww 0xb8116248 0x43000000 # QCA_PLL_SRIF_DDR_DPLL3_REG mww 0xb8116248 0x03000718 # QCA_PLL_CPU_DDR_CLK_CTRL_REG mww 0xb8050008 0x01308018 mww 0xb8050008 0x01308010 mww 0xb8050008 0x01308000 # QCA_PLL_DDR_PLL_DITHER_REG mww 0xb8050044 0x78180200 # QCA_PLL_CPU_PLL_DITHER_REG mww 0xb8050048 0x41C00000 } proc ar9344_ddr_init {} { # QCA_DDR_CTRL_CFG_REG mww 0xb8000108 0x40 # QCA_DDR_RD_DATA_THIS_CYCLE_REG mww 0xb8000018 0xFF # QCA_DDR_BURST_REG mww 0xb80000C4 0x74444444 # QCA_DDR_BURST2_REG mww 0xb80000C8 0x0222 # QCA_AHB_MASTER_TOUT_MAX_REG mww 0xb80000CC 0xFFFFF # QCA_DDR_CFG_REG mww 0xb8000000 0xC7D48CD0 # QCA_DDR_CFG2_REG mww 0xb8000004 0x9DD0E6A8 # QCA_DDR_DDR2_CFG_REG mww 0xb80000B8 0x0E59 # QCA_DDR_CFG2_REG mww 0xb8000004 0x9DD0E6A8 # QCA_DDR_CTRL_REG mww 0xb8000010 0x08 mww 0xb8000010 0x08 mww 0xb8000010 0x10 mww 0xb8000010 0x20 # QCA_DDR_EMR_REG mww 0xb800000C 0x02 # QCA_DDR_CTRL_REG mww 0xb8000010 0x02 # QCA_DDR_MR_REG mww 0xb8000008 0x0133 # QCA_DDR_CTRL_REG mww 0xb8000010 0x1 mww 0xb8000010 0x8 mww 0xb8000010 0x8 mww 0xb8000010 0x4 mww 0xb8000010 0x4 # QCA_DDR_MR_REG mww 0xb8000008 0x33 # QCA_DDR_CTRL_REG mww 0xb8000010 0x1 # QCA_DDR_EMR_REG mww 0xb800000C 0x0382 # QCA_DDR_CTRL_REG mww 0xb8000010 0x2 # QCA_DDR_EMR_REG mww 0xb800000C 0x0402 # QCA_DDR_CTRL_REG mww 0xb8000010 0x2 # QCA_DDR_REFRESH_REG mww 0xb8000014 0x4270 # QCA_DDR_TAP_CTRL_0_REG mww 0xb800001C 0x0e # QCA_DDR_TAP_CTRL_1_REG mww 0xb8000020 0x0e # QCA_DDR_TAP_CTRL_2_REG mww 0xb8000024 0x0e # QCA_DDR_TAP_CTRL_3_REG mww 0xb8000028 0x0e } $_TARGETNAME configure -event reset-init { # mww 0xb806001c 0x1000000 ar9344_40mhz_pll_init sleep 100 # flash remap # SPI_CONTROL_ADDR mww 0xbF000004 0x43 ar9344_ddr_init sleep 100 } set ram_boot_address 0xa0000000 $_TARGETNAME configure -work-area-phys 0x1d000000 -work-area-size 0x1000 flash bank flash0 ath79 0xbf000000 0 0 0 $_TARGETNAME cs0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/trion_t20_bga256.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Trion® T20 BGA256 Development Kit # https://www.efinixinc.com/docs/trion20-devkit-ug-v1.5.pdf # # works after power cycle or pushing sw1. # it is because we cannot control CDONE which is connected to ftdi channel 0 # note from an006: For JTAG programming, T4, T8, T13, and T20 FPGAs use the # CRESET_N and SS_N pins in addition to the standard JTAG pins. adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi channel 1 ftdi layout_init 0x0008 0x008b reset_config none transport select jtag adapter speed 6000 source [find fpga/efinix_trion.cfg] #openocd -f board/trion_t20_bga256.cfg -c "init" -c "pld load 0 outflow/trion_blinker.bit" #ipdbg -start -tap trion.tap -hub 0x8 -port 5555 -tool 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/twr-k60f120m.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Freescale TWRK60F120M development board # source [find target/k60.cfg] $_TARGETNAME configure -event reset-init { puts "-event reset-init occurred" } # # Definitions for the additional 'program flash' banks # (instructions and/or data) # flash bank pflash.1 kinetis 0x00040000 0x40000 0 4 $_TARGETNAME flash bank pflash.2 kinetis 0x00080000 0x40000 0 4 $_TARGETNAME flash bank pflash.3 kinetis 0x000c0000 0x40000 0 4 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/twr-k60n512.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Freescale TWRK60N512 development board # source [find target/k60.cfg] $_TARGETNAME configure -event reset-init { puts "-event reset-init occurred" } # # Definitions for the additional 'program flash' bank # (instructions and/or data) # flash bank pflash.1 kinetis 0x00040000 0x40000 0 4 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/twr-vf65gs10.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Board configuration file for the Freescale VF65GS10 tower board # # Board has a 20 pin Cortex+ETM debug connector with only nSRST available reset_config srst_only # This configuration file only deals with the hardware JTAG. # There is has also an embedded Kinetis K20 with OpenSDA # where a CMSIS-DAP application can be installed. # Source generic VF6xx target configuration source [find target/vybrid_vf6xx.cfg] # basic DDR memory init, setting up pad configuration # for DDR first then configuring the DDRMC for the # board proc ddr_init { } { # iomux ddr mww phys 0x40048220 0x00000180 mww phys 0x40048224 0x00000180 mww phys 0x40048228 0x00000180 mww phys 0x4004822c 0x00000180 mww phys 0x40048230 0x00000180 mww phys 0x40048234 0x00000180 mww phys 0x40048238 0x00000180 mww phys 0x4004823c 0x00000180 mww phys 0x40048240 0x00000180 mww phys 0x40048244 0x00000180 mww phys 0x40048248 0x00000180 mww phys 0x4004824c 0x00000180 mww phys 0x40048250 0x00000180 mww phys 0x40048254 0x00000180 mww phys 0x40048258 0x00000180 mww phys 0x4004825c 0x00000180 mww phys 0x40048260 0x00000180 mww phys 0x40048264 0x00000180 mww phys 0x40048268 0x00000180 mww phys 0x4004826c 0x00000180 mww phys 0x40048270 0x00000180 mww phys 0x40048274 0x00000180 mww phys 0x40048278 0x00000180 mww phys 0x4004827c 0x00010180 mww phys 0x40048280 0x00010180 mww phys 0x40048284 0x00010180 mww phys 0x40048288 0x00010180 mww phys 0x4004828c 0x00010180 mww phys 0x40048290 0x00010180 mww phys 0x40048294 0x00010180 mww phys 0x40048298 0x00010180 mww phys 0x4004829c 0x00010180 mww phys 0x400482a0 0x00010180 mww phys 0x400482a4 0x00010180 mww phys 0x400482a8 0x00010180 mww phys 0x400482ac 0x00010180 mww phys 0x400482b0 0x00010180 mww phys 0x400482b4 0x00010180 mww phys 0x400482b8 0x00010180 mww phys 0x400482bc 0x00010180 mww phys 0x400482c0 0x00010180 mww phys 0x400482c4 0x00010180 mww phys 0x400482c8 0x00010180 mww phys 0x400482cc 0x00000180 mww phys 0x400482d0 0x00000180 mww phys 0x400482d4 0x00000180 mww phys 0x400482d8 0x00000180 mww phys 0x4004821c 0x000001a0 # ddr_ctrl_init mww phys 0x400ae000 0x00000600 mww phys 0x400ae008 0x00000020 mww phys 0x400ae028 0x00013880 mww phys 0x400ae02c 0x00030d40 mww phys 0x400ae030 0x0000050c mww phys 0x400ae034 0x15040400 mww phys 0x400ae038 0x1406040f mww phys 0x400ae040 0x04040000 mww phys 0x400ae044 0x006db00c mww phys 0x400ae048 0x00000403 mww phys 0x400ae050 0x01000000 mww phys 0x400ae054 0x00060001 mww phys 0x400ae058 0x000c0000 mww phys 0x400ae05c 0x03000200 mww phys 0x400ae060 0x00000006 mww phys 0x400ae064 0x00010000 mww phys 0x400ae068 0x0c30002c mww phys 0x400ae070 0x00000000 mww phys 0x400ae074 0x00000003 mww phys 0x400ae078 0x0000000a mww phys 0x400ae07c 0x003001d4 mww phys 0x400ae084 0x00010000 mww phys 0x400ae088 0x00050500 mww phys 0x400ae098 0x00000000 mww phys 0x400ae09c 0x04001002 mww phys 0x400ae0a4 0x00000001 mww phys 0x400ae0c0 0x00460420 mww phys 0x400ae108 0x01000200 mww phys 0x400ae10c 0x00000040 mww phys 0x400ae114 0x00000200 mww phys 0x400ae118 0x00000040 mww phys 0x400ae120 0x00000000 mww phys 0x400ae124 0x0a010300 mww phys 0x400ae128 0x01014040 mww phys 0x400ae12c 0x01010101 mww phys 0x400ae130 0x03030100 mww phys 0x400ae134 0x01000101 mww phys 0x400ae138 0x0700000c mww phys 0x400ae13c 0x00000000 mww phys 0x400ae148 0x10000000 mww phys 0x400ae15c 0x01000000 mww phys 0x400ae160 0x00040000 mww phys 0x400ae164 0x00000002 mww phys 0x400ae16c 0x00020000 mww phys 0x400ae180 0x00002819 mww phys 0x400ae184 0x01000000 mww phys 0x400ae188 0x00000000 mww phys 0x400ae18c 0x00000000 mww phys 0x400ae198 0x00000000 mww phys 0x400ae1a4 0x00000c00 mww phys 0x400ae1a8 0x00000000 mww phys 0x400ae1b8 0x0000000c mww phys 0x400ae1c8 0x00000000 mww phys 0x400ae1cc 0x00000000 mww phys 0x400ae1d4 0x00000000 mww phys 0x400ae1d8 0x01010000 mww phys 0x400ae1e0 0x02020000 mww phys 0x400ae1e4 0x00000202 mww phys 0x400ae1e8 0x01010064 mww phys 0x400ae1ec 0x00010101 mww phys 0x400ae1f0 0x00000064 mww phys 0x400ae1f8 0x00000800 mww phys 0x400ae210 0x00000506 mww phys 0x400ae224 0x00020000 mww phys 0x400ae228 0x01000000 mww phys 0x400ae22c 0x04070303 mww phys 0x400ae230 0x00000040 mww phys 0x400ae23c 0x06000080 mww phys 0x400ae240 0x04070303 mww phys 0x400ae244 0x00000040 mww phys 0x400ae248 0x00000040 mww phys 0x400ae24c 0x000f0000 mww phys 0x400ae250 0x000f0000 mww phys 0x400ae25c 0x00000101 mww phys 0x400ae268 0x682c4000 mww phys 0x400ae26c 0x00000012 mww phys 0x400ae278 0x00000006 mww phys 0x400ae284 0x00010202 mww phys 0x400ae400 0x00002613 mww phys 0x400ae440 0x00002613 mww phys 0x400ae404 0x00002615 mww phys 0x400ae444 0x00002615 mww phys 0x400ae408 0x00210000 mww phys 0x400ae448 0x00210000 mww phys 0x400ae488 0x00210000 mww phys 0x400ae40c 0x0001012a mww phys 0x400ae44c 0x0001012a mww phys 0x400ae48c 0x0001012a mww phys 0x400ae410 0x00002400 mww phys 0x400ae450 0x00002400 mww phys 0x400ae490 0x00002400 mww phys 0x400ae4c4 0x00000000 mww phys 0x400ae4c8 0x00001100 mww phys 0x400ae4d0 0x00010101 mww phys 0x400ae000 0x00000601 } # clock control init, setting up basic # clocks proc clock_init { } { # captured from u-boot mww phys 0x4006b040 0xffffffff mww phys 0x4006b044 0xffffffff mww phys 0x4006b048 0xffffffff mww phys 0x4006b04c 0xffffffff mww phys 0x4006b050 0xffffffff mww phys 0x4006b058 0xffffffff mww phys 0x4006b05c 0xffffffff mww phys 0x4006b060 0xffffffff mww phys 0x4006b064 0xffffffff mww phys 0x4006b068 0xffffffff mww phys 0x40050030 0x00002001 mww phys 0x40050270 0x80002001 mww phys 0x4006b000 0x00011005 mww phys 0x4006b008 0x0001ff24 mww phys 0x4006b00c 0x00000810 mww phys 0x4006b010 0x00cc0000 mww phys 0x4006b014 0x01000000 mww phys 0x4006b018 0x20000000 mww phys 0x4006b01c 0x0000001f mww phys 0x4006b020 0x00000000 } # This function applies the initial configuration after a "reset init" # command proc board_init { } { clock_init ddr_init } # hook the init function into the reset-init event ${_TARGETNAME}0 configure -event reset-init { board_init } # set a slow default JTAG clock, can be overridden later adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/twr-vf65gs10_cmsisdap.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Board configuration file for the Freescale VF65GS10 tower board # # CMSIS-DAP via USB-OTG connector # source [find interface/cmsis-dap.cfg] # only SWD is supported by the CMSIS-DAP on this board transport select swd # Source generic part of twr-vf65gs10 configuration source [find board/twr-vf65gs10.cfg] # override reset configuration reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/tx25_stk5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # ------------------------------------------------------------------------- # KaRo TX25 CPU Module on a StarterkitV base board # http://www.karo-electronics.com/tx25.html # ------------------------------------------------------------------------- source [find target/imx25.cfg] #------------------------------------------------------------------------- # Declare Nand #------------------------------------------------------------------------- nand device K9F1G08UOC mxc imx25.cpu mx25 hwecc biswap $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { tx25_init } proc tx25_init { } { #------------------------------------------------------------------------- # AIPS setup - Only setup MPROTx registers. The PACR default values are good. # Set all MPROTx to be non-bufferable, trusted for R/W, # not forced to user-mode. #------------------------------------------------------------------------- mww 0x43f00000 0x77777777 mww 0x43f00004 0x77777777 mww 0x53f00000 0x77777777 mww 0x53f00004 0x77777777 sleep 100 #------------------------------------------------------------------------- # MAX (Multi-Layer AHB Crossbar Switch) setup # MPR - priority for MX25 is (SDHC2/SDMA)>USBOTG>RTIC>IAHB>DAHB #------------------------------------------------------------------------- mww 0x43f04000 0x00043210 mww 0x43f04100 0x00043210 mww 0x43f04200 0x00043210 mww 0x43f04300 0x00043210 mww 0x43f04400 0x00043210 # SGPCR - always park on last master mww 0x43f04010 0x10 mww 0x43f04110 0x10 mww 0x43f04210 0x10 mww 0x43f04310 0x10 mww 0x43f04410 0x10 # MGPCR - restore default values mww 0x43f04800 0x0 mww 0x43f04900 0x0 mww 0x43f04a00 0x0 mww 0x43f04b00 0x0 mww 0x43f04c00 0x0 # Configure M3IF registers # M3IF Control Register (M3IFCTL) for MX25 # MRRP[0] = LCDC on priority list (1 << 0) = 0x00000001 # MRRP[1] = MAX1 not on priority list (0 << 1) = 0x00000000 # MRRP[2] = MAX0 not on priority list (0 << 2) = 0x00000000 # MRRP[3] = USB HOST not on priority list (0 << 3) = 0x00000000 # MRRP[4] = SDMA not on priority list (0 << 4) = 0x00000000 # MRRP[5] = SD/ATA/FEC not on priority list (0 << 5) = 0x00000000 # MRRP[6] = SCMFBC not on priority list (0 << 6) = 0x00000000 # MRRP[7] = CSI not on priority list (0 << 7) = 0x00000000 # ---------- # 0x00000001 mww 0xb8003000 0x00000001 #------------------------------------------------------------------------- # configure ARM CLK #------------------------------------------------------------------------- # Set the Clock CTL (HRM p. 355) mww 0x53F80008 0x20034000 # Setup Clock Gating CTL 0-2 (HRM p. 357) mww 0x53F8000C 0x1fffffff mww 0x53F80010 0xffffffff mww 0x53F80014 0x000fdfff #------------------------------------------------------------------------- # SDRAM initialization #------------------------------------------------------------------------- # set to 3.3v SDRAM mww 0x43FAC454 0x00000800 # reset (set up ESDMISC) mww 0xB8001010 0x00000002 # Setup for SDRAM Bank 0 #------------------------------------------------------------------------- # Write ESDCFG0 mww 0xB8001004 0x00095728 # CTL SMode = Precharge command mww 0xB8001000 0x92116480 mww 0x80000400 0x00000000 # CTL SMode = Auto Refresh command mww 0xB8001000 0xA2116480 mww 0x80000000 0x0 mww 0x80000000 0x0 mww 0x80000000 0x0 mww 0x80000000 0x0 mww 0x80000000 0x0 mww 0x80000000 0x0 mww 0x80000000 0x0 mww 0x80000000 0x0 # CTL SMode = Load Mode Register command mww 0xB8001000 0xB2116480 mwb 0x80000033 0x00 # CTL SMode = normal mww 0xB8001000 0x82116480 # Setup for SDRAM Bank 1 #------------------------------------------------------------------------- # Write ESDCFG1 mww 0xB800100C 0x00095728 # CTL SMode = Precharge command mww 0xB8001008 0x92116480 mww 0x90000400 0x00000000 # CTL SMode = Auto Refresh command mww 0xB8001008 0xA2116480 mww 0x90000000 0x00000000 mww 0x90000000 0x00000000 mww 0x90000000 0x00000000 mww 0x90000000 0x00000000 mww 0x90000000 0x00000000 mww 0x90000000 0x00000000 mww 0x90000000 0x00000000 mww 0x90000000 0x00000000 # CTL SMode = Load Mode Register command mww 0xB8001008 0xB2116480 mwb 0x90000033 0x00 # CTL SMode = normal mww 0xB8001008 0x82116480 # GPIO configuration #------------------------------------------------------------------------- mww 0x43FAC02C 0x00000015 mww 0x53FD0000 0x01000000 mww 0x53FD0004 0x00000080 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/tx27_stk5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # KaRo TX27 CPU Module on a StarterkitV base board # # http://www.karo-electronics.com/tx27.html # source [find target/imx27.cfg] $_TARGETNAME configure -event gdb-attach { reset init } $_TARGETNAME configure -event reset-init { tx27_init } proc tx27_init { } { # This setup puts RAM at 0xA0000000 # init_aipi (AIPI1.PSR0, AIPI2.PSR0, AIPI1.PSR1 and AIPI2.PSR1) mww 0x10000000 0x20040304 mww 0x10020000 0x00000000 mww 0x10000004 0xDFFBFCFB mww 0x10020004 0xFFFFFFFF sleep 100 #init_max ( PORT0.MPR, #PORT0.AMPR, #PORT1.MPR, #PORT1.AMPR, #PORT2.MPR, #PORT2.AMPR) mww 0x1003F000 0x00302145 mww 0x1003F004 0x00302145 mww 0x1003F100 0x00302145 mww 0x1003F104 0x00302145 mww 0x1003F200 0x00302145 mww 0x1003F204 0x00302145 #init_drive_strength (#DSCR3, #DSCR5, #DSCR6, #DSCR7, #DSCR8 ) mww 0x10027828 0x55555555 mww 0x10027830 0x55555555 mww 0x10027834 0x55555555 mww 0x10027838 0x00005005 mww 0x1002783C 0x15555555 #init_sdram_speed #mww 0xD8001010 0x00000004 mww 0xD8001010 0x00000024 mww 0xD8001004 0x00395729 mww 0xD8001000 0x92120000 mww 0xA0000400 0x0 mww 0xD8001000 0xA2120000 mww 0xA0000000 0x0 mww 0xA0000000 0x0 mww 0xD8001000 0xB2120000 mdb 0xA0000000 mdb 0xA0000033 mww 0xD8001000 0x82126485 # ============================================= # Sync mode (AHB Clk = 133MHz ; BCLK = 44.3MHz) # ============================================= mww 0xD8002000 0x23524E80 mww 0xD8002004 0x10000D03 mww 0xD8002008 0x00720900 nand probe 0 } nand device tx27.nand mxc $_TARGETNAME mx27 hwecc biswap ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/unknown_at91sam9260.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Thanks to Pieter Conradie for this script! # # Unknown vendor board contains: # # Atmel AT91SAM9260 : PLLA = 192.512MHz, MCK = 96.256 MHz # OSCSEL configured for internal RC oscillator (22 to 42 kHz) # # 16-bit NOR FLASH : Intel JS28F128P30T85 128MBit # 32-bit SDRAM : 2 x Samsung K4S561632H-UC75, 4M x 16Bit x 4 Banks ################################################################## # We add to the minimal configuration. source [find target/at91sam9260.cfg] $_TARGETNAME configure -event reset-start { # At reset CPU runs at 22 to 42 kHz. # JTAG Frequency must be 6 times slower. jtag_rclk 3 halt # RSTC_MR : enable user reset, MMU may be enabled... use physical address mww phys 0xfffffd08 0xa5000501 } $_TARGETNAME configure -event reset-init { mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog mww 0xfffffc20 0x00004001 ;# CKGR_MOR : enable the main oscillator sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000001 ;# PMC_MCKR : switch to main oscillator sleep 10 ;# wait 10 ms mww 0xfffffc28 0x205dbf09 ;# CKGR_PLLAR: Set PLLA Register for 192.512MHz sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000101 ;# PMC_MCKR : Select prescaler (divide by 2) sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000102 ;# PMC_MCKR : Clock from PLLA is selected (96.256 MHz) sleep 10 ;# wait 10 ms # Increase JTAG Speed to 6 MHz if RCLK is not supported jtag_rclk 6000 arm7_9 dcc_downloads enable ;# Enable faster DCC downloads mww 0xffffec00 0x01020102 ;# SMC_SETUP0 : Setup SMC for Intel NOR Flash JS28F128P30T85 128MBit mww 0xffffec04 0x09070806 ;# SMC_PULSE0 mww 0xffffec08 0x000d000b ;# SMC_CYCLE0 mww 0xffffec0c 0x00001003 ;# SMC_MODE0 flash probe 0 ;# Identify flash bank 0 mww 0xfffff870 0xffff0000 ;# PIO_ASR : Select peripheral function for D15..D31 mww 0xfffff804 0xffff0000 ;# PIO_PDR : Disable PIO function for D15..D31 mww 0xfffff860 0xffff0000 ;# PIO_PUDR : Disable D15..D31 pull-ups mww 0xffffef1c 0x00010102 ;# EBI_CSA : Assign EBI Chip Select 1 to SDRAM # VDDIOMSEL set for +3V3 memory # Disable D0..D15 pull-ups mww 0xffffea08 0x85227259 ;# SDRAMC_CR : Configure SDRAM (2 x Samsung K4S561632H-UC75 : 4M x 16Bit x 4 Banks) mww 0xffffea00 0x1 ;# SDRAMC_MR : issue a NOP command mww 0x20000000 0 mww 0xffffea00 0x2 ;# SDRAMC_MR : issue an 'All Banks Precharge' command mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue 8 x 'Auto-Refresh' Command mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x3 ;# SDRAMC_MR : issue a 'Load Mode Register' command mww 0x20000000 0 mww 0xffffea00 0x0 ;# SDRAMC_MR : normal mode mww 0x20000000 0 mww 0xffffea04 0x2a2 ;# SDRAMC_TR : Set refresh timer count to 7us } ##################### # Flash configuration ##################### #flash bank <name> cfi <base> <size> <chip width> <bus width> <target> set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x10000000 0x01000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/uptech_2410.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Target Configuration for the Uptech 2410 board. # This configuration should also work on smdk2410, but I haven't tested it yet. # Author: xionglingfeng@Gmail.com source [find target/samsung_s3c2410.cfg] $_TARGETNAME configure -event reset-init { uptech2410_init } $_TARGETNAME configure -event gdb-attach { reset init } proc init_pll_sdram { } { #echo "---------- Initializing PLL and SDRAM ---------" #watchdog timer disable mww phys 0x53000000 0x00000000 #disable all interrupts mww phys 0x4a000008 0xffffffff #disable all sub-interrupts mww phys 0x4a00001c 0x000007ff #clear all source pending bits mww phys 0x4a000000 0xffffffff #clear all sub-source pending bits mww phys 0x4a000018 0x000007ff #clear interrupt pending bit mww phys 0x4a000010 0xffffffff #PLL locktime counter mww phys 0x4c000000 0x00ffffff #Fin=12MHz Fout=202.8MHz #mww phys 0x4c000004 0x000a1031 #FCLK:HCLK:PCLK = 1:2:4 mww phys 0x4c000014 0x00000003 mww phys 0x48000000 0x11111110 mww phys 0x48000004 0x00007FFC mww phys 0x48000008 0x00007FFC mww phys 0x4800000c 0x00000700 mww phys 0x48000010 0x00000700 mww phys 0x48000014 0x00002E50 mww phys 0x48000018 0x00002E50 mww phys 0x4800001c 0x00018005 mww phys 0x48000020 0x00018005 mww phys 0x48000024 0x008c04e9 mww phys 0x48000028 0x000000b2 mww phys 0x4800002c 0x00000030 mww phys 0x48000030 0x00000030 } proc uptech2410_init { } { init_pll_sdram #echo "---------- Probing Nand flash ----------" nand probe 0 #echo "---------- Enable some functions ----------" } set _NANDNAME $_CHIPNAME.nand nand device $_NANDNAME s3c2410 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/vd_a53x2_dap.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # Arm Cortex A53x2 through DAP source [find interface/vdebug.cfg] set _CORES 2 set _CHIPNAME a53 set _MEMSTART 0x00000000 set _MEMSIZE 0x1000000 # vdebug select transport transport select dapdirect_swd # JTAG reset config, frequency and reset delay adapter speed 50000 adapter srst delay 5 # BFM hierarchical path and input clk period vdebug bfm_path tbench.u_vd_swdp_bfm 10ns # DMA Memories to access backdoor (up to 4) vdebug mem_path tbench.u_memory.mem_array $_MEMSTART $_MEMSIZE source [find target/swj-dp.tcl] swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf source [find target/vd_aarch64.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/vd_a53x2_jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # Arm Cortex A53x2 through JTAG source [find interface/vdebug.cfg] set _CORES 2 set _CHIPNAME a53 set _MEMSTART 0x00000000 set _MEMSIZE 0x1000000 set _CPUTAPID 0x5ba00477 # vdebug select transport transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst adapter speed 50000 adapter srst delay 5 # BFM hierarchical path and input clk period vdebug bfm_path tbench.u_vd_jtag_bfm 10ns # DMA Memories to access backdoor (up to 4) vdebug mem_path tbench.u_memory.mem_array $_MEMSTART $_MEMSIZE jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID jtag arp_init-reset source [find target/vd_aarch64.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/vd_m4_dap.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # Arm Cortex m4 through DAP source [find interface/vdebug.cfg] set _CHIPNAME m4 set _MEMSTART 0x00000000 set _MEMSIZE 0x10000 # vdebug select transport transport select dapdirect_swd adapter speed 25000 adapter srst delay 5 # BFM hierarchical path and input clk period vdebug bfm_path tbench.u_vd_swdp_bfm 20ns # DMA Memories to access backdoor (up to 4) vdebug mem_path tbench.u_mcu.u_sys.u_rom.rom $_MEMSTART $_MEMSIZE source [find target/swj-dp.tcl] swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf source [find target/vd_cortex_m.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/vd_m4_jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # Arm Cortex m4 through JTAG source [find interface/vdebug.cfg] set _CHIPNAME m4 set _MEMSTART 0x00000000 set _MEMSIZE 0x10000 set _CPUTAPID 0x4ba00477 # vdebug select transport transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst adapter speed 25000 adapter srst delay 5 # BFM hierarchical path and input clk period vdebug bfm_path tbench.u_vd_jtag_bfm 20ns # DMA Memories to access backdoor (up to 4) vdebug mem_path tbench.u_mcu.u_sys.u_rom.rom $_MEMSTART $_MEMSIZE jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID jtag arp_init-reset source [find target/vd_cortex_m.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/vd_m7_jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # Arm Cortex m7 through JTAG source [find interface/vdebug.cfg] set _CHIPNAME m7 set _MEMSTART 0x00000000 set _MEMSIZE 0x100000 set _CPUTAPID 0x0ba02477 # vdebug select JTAG transport transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst adapter speed 50000 adapter srst delay 5 # BFM hierarchical path and input clk period vdebug bfm_path tbench.u_vd_jtag_bfm 10ns # DMA Memories to access backdoor (up to 4) vdebug mem_path tbench.u_mcu.u_sys.u_itcm_ram.Mem $_MEMSTART $_MEMSIZE jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID jtag arp_init-reset source [find target/vd_cortex_m.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/vd_pulpissimo_jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # RISCV Ibex core with Pulpissimo through JTAG source [find interface/vdebug.cfg] set _CHIPNAME ibex set _HARTID 0x20 set _CPUTAPID 0x249511c3 # vdebug select transport transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst adapter speed 12500 adapter srst delay 10 # BFM hierarchical path and input clk period vdebug bfm_path tbench.u_vd_jtag_bfm 40ns # DMA Memories to access backdoor (up to 4) vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[0\].sram_i.mem_array 0x1c000000 0x8000 vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[1\].sram_i.mem_array 0x1c008000 0x8000 vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2\[0\].sram_i.mem_array 0x1c010000 0x80000 # need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01 jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x05 -irmask 0x1f -expected-id $_CPUTAPID jtag arp_init-reset source [find target/vd_riscv.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/vd_swerv_jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # RISCV swerv core with Swerv through JTAG source [find interface/vdebug.cfg] set _CHIPNAME rv32 set _HARTID 0x00 set _CPUTAPID 0x1000008b set _MEMSTART 0x00000000 set _MEMSIZE 0x10000 # vdebug select transport transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst adapter speed 50000 adapter srst delay 5 # BFM hierarchical path and input clk period vdebug bfm_path tbench.u_vd_jtag_bfm 10ns # DMA Memories to access backdoor (up to 4) vdebug mem_path tbench.i_ahb_ic.mem $_MEMSTART $_MEMSIZE # need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01 jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x01 -irmask 0x1f -expected-id $_CPUTAPID jtag arp_init-reset source [find target/vd_riscv.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/vd_xt8_jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # Xtensa xt8 through JTAG source [find interface/vdebug.cfg] set CHIPNAME xt8 set CPUTAPID 0x120034e5 # vdebug select transport transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst adapter speed 50000 adapter srst delay 5 # BFM hierarchical path and input clk period vdebug bfm_path Testbench.u_vd_jtag_bfm 10ns # DMA Memories to access backdoor, the values come from generated xtensa-core-xt8.cfg #vdebug mem_path Testbench.Xtsubsystem.Core0.iram0.iram0.mem.dataArray 0x40000000 0x100000 #vdebug mem_path Testbench.Xtsubsystem.Core0.dram0.dram0.mem.dataArray 0x3ff00000 0x40000 # Create Xtensa target first source [find target/xtensa.cfg] # Generate [xtensa-core-XXX.cfg] via "xt-gdb --dump-oocd-config" source [find target/xtensa-core-xt8.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/verdex.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Config for Gumstix Verdex XM4 and XL6P (PXA270) set CHIPNAME verdex source [find target/pxa270.cfg] # The board supports separate reset lines # Override this in the interface config for parallel dongles reset_config trst_and_srst separate # XM4 = 400MHz, XL6P = 600MHz...let's run at 0.1*400MHz=40MHz adapter speed 40000 # flash bank <driver> <base> <size> <chip_width> <bus_width> # XL6P has 32 MB flash flash bank $_CHIPNAME.flash0 cfi 0x00000000 0x02000000 2 2 $_TARGETNAME # XM4 has 16 MB flash #flash bank $_CHIPNAME.flash0 cfi 0x00000000 0x01000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/voipac.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Config for Voipac PXA270/PXA270M module. set CHIPNAME voipac source [find target/pxa270.cfg] # The board supports separate reset lines # Override this in the interface config for parallel dongles reset_config trst_and_srst separate # flash bank <driver> <base> <size> <chip_width> <bus_width> flash bank $_CHIPNAME.flash0 cfi 0x00000000 0x2000000 2 2 $_TARGETNAME flash bank $_CHIPNAME.flash1 cfi 0x02000000 0x2000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/voltcraft_dso-3062c.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Voltcraft DSO-3062C digital oscilloscope (uses a Samsung S3C2440) # # http://www.eevblog.com/forum/general-chat/hantek-tekway-dso-hack-get-200mhz-bw-for-free/ # http://www.mikrocontroller.net/topic/249628 # http://elinux.org/Das_Oszi # http://randomprojects.org/wiki/Voltcraft_DSO-3062C # # Enable this if your JTAG adapter supports multiple transports (JTAG or SWD). # Otherwise comment it out, as it will cause an OpenOCD error. ### transport select jtag source [find target/samsung_s3c2440.cfg] adapter speed 16000 # Samsung K9F1208U0C NAND flash chip (64MiB, 3.3V, 8-bit) nand device $_CHIPNAME.nand s3c2440 $_TARGETNAME # arm7_9 fast_memory_access enable # arm7_9 dcc_downloads enable init reset halt scan_chain targets nand probe 0 nand list ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/x300t.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is for the T-Home X300T / X301T IPTV box, # which are based on IPTV reference designs from Kiss/Cisco KMM-3*** # # It has Sigma Designs SMP8634 chip. source [find target/smp8634.cfg] $_TARGETNAME configure -event reset-init { x300t_init } # 1MB CFI capable flash # flash bank <name> <driver> <base> <size> <chip_width> <bus_width> <target> set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0xac000000 0x100000 2 2 $_TARGETNAME proc x300t_init { } { # Setup SDRAM config and flash mapping # initialize ram mww 0xa003fffc 3 mww 0xa003fffc 2 mww 0xa0030000 0xE34111BA mww 0xa003fffc 0xa4444 mww 0xa003fffc 0 # remap boot vector in CPU local RAM mww 0xa006f000 0x60000 # map flash to CPU address space REG_BASE_cpu_block+CPU_remap4 mww 0x0006f010 0x48000000 # map flash addr to REG_BASE_cpu_block + LR_XENV_LOCATION (normally done by XOS) mww 0x00061ff0 0x48000000 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xmc-2go.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Infineon XMC 2Go # # # Segger J-Link Lite XMC4200 on-board # source [find interface/jlink.cfg] transport select swd set CHIPNAME xmc1100 set WORKAREASIZE 0x4000 source [find target/xmc1xxx.cfg] reset_config srst_only srst_nogate ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xmc1100-boot-kit.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Infineon XMC1100 Boot Kit # # # Segger J-Link Lite XMC4200 on-board # source [find interface/jlink.cfg] transport select swd set CHIPNAME xmc1100 set WORKAREASIZE 0x4000 source [find target/xmc1xxx.cfg] reset_config srst_only srst_nogate ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xmc4200-application-kit-actuator.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Infineon XMC4200 Application Kit - Actuator # # # Segger J-Link Lite XMC4200 on-board # source [find interface/jlink.cfg] transport select swd set CHIPNAME xmc4200 source [find target/xmc4xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xmc4300-relax.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Infineon XMC4300 Relax EtherCAT Kit # # # Segger J-Link Lite XMC4200 on-board # source [find interface/jlink.cfg] transport select swd set CHIPNAME xmc4300 source [find target/xmc4xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xmc4500-application-kit-general.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Infineon XMC4500 Application Kit - General Purpose # set CHIPNAME xmc4500 source [find target/xmc4xxx.cfg] reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xmc4500-application-kit-sdram.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Infineon XMC4500 Application Kit - SDRAM # # # Segger J-Link Lite XMC4200 on-board # set CHIPNAME xmc4500 source [find target/xmc4xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xmc4500-relax.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Infineon XMC4500 Relax Kit / Relax Lite Kit # # # Segger J-Link Lite XMC4500 on-board # source [find interface/jlink.cfg] transport select swd # There's also an unpopulated 10-pin 0.05" pinout. set CHIPNAME xmc4500 source [find target/xmc4xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xmc4700-relax.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Infineon XMC4700 Relax Lite Kit / Relax Kit for 5V Shields / Relax Kit # # # Segger J-Link Lite XMC4200 on-board # source [find interface/jlink.cfg] transport select swd # There's also an unpopulated 10-pin 0.05" pinout. set CHIPNAME xmc4700 source [find target/xmc4xxx.cfg] # Relax Kit only: N25Q032A qSPI flash ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xmc4800-relax.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Infineon XMC4800 Relax EtherCAT Kit # # # Segger J-Link Lite XMC4200 on-board # source [find interface/jlink.cfg] transport select swd # There's also an unpopulated 10-pin 0.05" pinout. set CHIPNAME xmc4800 source [find target/xmc4xxx.cfg] # N25Q032A qSPI flash ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xmos_xk-xac-xa8_arm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # xCORE-XA Core Module # # https://www.xmos.com/support/boards?product=17940 # # # J-Link OB STM32F103 # source [find interface/jlink.cfg] transport select swd # # XS1-XAU8A-10 # source [find target/xmos_xs1-xau8a-10_arm.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xtensa-kc705-ext-dap.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence KC705 FPGA Development Platform for Xtensa targets # Can be used with various external adapters that support DAP, e.g. JLink # adapter speed 5000 # KC705 supports DAP/JTAG transport select jtag set XTENSA_DAP enable set XTENSA_DAP_BASE 0x10000 # Create Xtensa target first source [find target/xtensa.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xtensa-kc705-ext.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence KC705 FPGA Development Platform for Xtensa targets # Can be used with various external adapters, e.g. Flyswatter2 or JLink # adapter speed 10000 # KC705 supports JTAG only transport select jtag # Create Xtensa target first source [find target/xtensa.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xtensa-kc705-onboard.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence KC705 FPGA Development Platform for Xtensa targets # Can be used with on-board (FTDI) adapter or various external adapters # source [find interface/ftdi/xt_kc705_ml605.cfg] adapter speed 10000 # KC705 supports JTAG only transport select jtag # Create Xtensa target first source [find target/xtensa.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xtensa-palladium-vdebug.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # for Palladium emulation systems # source [find interface/vdebug.cfg] # vdebug select JTAG transport transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst adapter speed 50000 adapter srst delay 5 source [find target/vd_xtensa_jtag.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/board/xtensa-rt685-ext.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP RT6XX Developemnt Platform with Xtensa HiFi DSP # Can be used with various external adapters that support DAP, e.g. JLink # adapter speed 10000 # RT6XX supports SWD only transport select swd set XTENSA_DAP enable # Create Xtensa target first source [find target/xtensa.cfg] source [find target/xtensa-core-nxp_rt600.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/aic.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set AIC_SMR [expr {$AT91C_BASE_AIC + 0x00000000} ] global AIC_SMR set AIC_SVR [expr {$AT91C_BASE_AIC + 0x00000080} ] global AIC_SVR set AIC_IVR [expr {$AT91C_BASE_AIC + 0x00000100} ] global AIC_IVR set AIC_FVR [expr {$AT91C_BASE_AIC + 0x00000104} ] global AIC_FVR set AIC_ISR [expr {$AT91C_BASE_AIC + 0x00000108} ] global AIC_ISR set AIC_IPR [expr {$AT91C_BASE_AIC + 0x0000010C} ] global AIC_IPR set AIC_IMR [expr {$AT91C_BASE_AIC + 0x00000110} ] global AIC_IMR set AIC_CISR [expr {$AT91C_BASE_AIC + 0x00000114} ] global AIC_CISR set AIC_IECR [expr {$AT91C_BASE_AIC + 0x00000120} ] global AIC_IECR set AIC_IDCR [expr {$AT91C_BASE_AIC + 0x00000124} ] global AIC_IDCR set AIC_ICCR [expr {$AT91C_BASE_AIC + 0x00000128} ] global AIC_ICCR set AIC_ISCR [expr {$AT91C_BASE_AIC + 0x0000012C} ] global AIC_ISCR set AIC_EOICR [expr {$AT91C_BASE_AIC + 0x00000130} ] global AIC_EOICR set AIC_SPU [expr {$AT91C_BASE_AIC + 0x00000134} ] global AIC_SPU set AIC_DCR [expr {$AT91C_BASE_AIC + 0x00000138} ] global AIC_DCR set AIC_FFER [expr {$AT91C_BASE_AIC + 0x00000140} ] global AIC_FFER set AIC_FFDR [expr {$AT91C_BASE_AIC + 0x00000144} ] global AIC_FFDR set AIC_FFSR [expr {$AT91C_BASE_AIC + 0x00000148} ] global AIC_FFSR proc aic_enable_disable_list { VAL ENAME DNAME } { global AT91C_ID show_mmr32_bits AT91C_ID $VAL } proc show_AIC_IPR_helper { NAME ADDR VAL } { aic_enable_disable_list $VAL "IRQ PENDING" "irq not-pending" } proc show_AIC_IMR_helper { NAME ADDR VAL } { aic_enable_disable_list $VAL "IRQ ENABLED" "irq disabled" } proc show_AIC { } { global AIC_SMR if [catch { set aaa [read_memory $AIC_SMR 32 [expr {32 * 4}]] } msg ] { error [format "%s (%s)" $msg AIC_SMR] } echo "AIC_SMR: Mode & Type" global AT91C_ID for { set x 0 } { $x < 32 } { } { echo -n " " echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) [lindex $aaa $x]] incr x } global AIC_SVR if [catch { set aaa [read_memory $AIC_SVR 32 [expr {32 * 4}]] } msg ] { error [format "%s (%s)" $msg AIC_SVR] } echo "AIC_SVR: Vectors" for { set x 0 } { $x < 32 } { } { echo -n " " echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) [lindex $aaa $x]] incr x } foreach REG { AIC_IVR AIC_FVR AIC_ISR AIC_IPR AIC_IMR AIC_CISR AIC_IECR AIC_IDCR AIC_ICCR AIC_ISCR AIC_EOICR AIC_SPU AIC_DCR AIC_FFER AIC_FFDR AIC_FFSR } { if [catch { show_mmr32_reg $REG } msg ] { error $msg break } } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/at91_pio.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set PIO_PER 0x00 ;# Enable Register set PIO_PDR 0x04 ;# Disable Register set PIO_PSR 0x08 ;# Status Register set PIO_OER 0x10 ;# Output Enable Register set PIO_ODR 0x14 ;# Output Disable Register set PIO_OSR 0x18 ;# Output Status Register set PIO_IFER 0x20 ;# Glitch Input Filter Enable set PIO_IFDR 0x24 ;# Glitch Input Filter Disable set PIO_IFSR 0x28 ;# Glitch Input Filter Status set PIO_SODR 0x30 ;# Set Output Data Register set PIO_CODR 0x34 ;# Clear Output Data Register set PIO_ODSR 0x38 ;# Output Data Status Register set PIO_PDSR 0x3c ;# Pin Data Status Register set PIO_IER 0x40 ;# Interrupt Enable Register set PIO_IDR 0x44 ;# Interrupt Disable Register set PIO_IMR 0x48 ;# Interrupt Mask Register set PIO_ISR 0x4c ;# Interrupt Status Register set PIO_MDER 0x50 ;# Multi-driver Enable Register set PIO_MDDR 0x54 ;# Multi-driver Disable Register set PIO_MDSR 0x58 ;# Multi-driver Status Register set PIO_PUDR 0x60 ;# Pull-up Disable Register set PIO_PUER 0x64 ;# Pull-up Enable Register set PIO_PUSR 0x68 ;# Pull-up Status Register set PIO_ASR 0x70 ;# Peripheral A Select Register set PIO_BSR 0x74 ;# Peripheral B Select Register set PIO_ABSR 0x78 ;# AB Status Register set PIO_OWER 0xa0 ;# Output Write Enable Register set PIO_OWDR 0xa4 ;# Output Write Disable Register set PIO_OWSR 0xa8 ;# Output Write Status Register ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/at91_pmc.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set AT91_PMC_SCER [expr {$AT91_PMC + 0x00}] ;# System Clock Enable Register set AT91_PMC_SCDR [expr {$AT91_PMC + 0x04}] ;# System Clock Disable Register set AT91_PMC_SCSR [expr {$AT91_PMC + 0x08}] ;# System Clock Status Register set AT91_PMC_PCK [expr {1 << 0}] ;# Processor Clock set AT91RM9200_PMC_UDP [expr {1 << 1}] ;# USB Devcice Port Clock [AT91RM9200 only] set AT91RM9200_PMC_MCKUDP [expr {1 << 2}] ;# USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] set AT91CAP9_PMC_DDR [expr {1 << 2}] ;# DDR Clock [CAP9 revC & some SAM9 only] set AT91RM9200_PMC_UHP [expr {1 << 4}] ;# USB Host Port Clock [AT91RM9200 only] set AT91SAM926x_PMC_UHP [expr {1 << 6}] ;# USB Host Port Clock [AT91SAM926x only] set AT91CAP9_PMC_UHP [expr {1 << 6}] ;# USB Host Port Clock [AT91CAP9 only] set AT91SAM926x_PMC_UDP [expr {1 << 7}] ;# USB Devcice Port Clock [AT91SAM926x only] set AT91_PMC_PCK0 [expr {1 << 8}] ;# Programmable Clock 0 set AT91_PMC_PCK1 [expr {1 << 9}] ;# Programmable Clock 1 set AT91_PMC_PCK2 [expr {1 << 10}] ;# Programmable Clock 2 set AT91_PMC_PCK3 [expr {1 << 11}] ;# Programmable Clock 3 set AT91_PMC_HCK0 [expr {1 << 16}] ;# AHB Clock (USB host) [AT91SAM9261 only] set AT91_PMC_HCK1 [expr {1 << 17}] ;# AHB Clock (LCD) [AT91SAM9261 only] set AT91_PMC_PCER [expr {$AT91_PMC + 0x10}] ;# Peripheral Clock Enable Register set AT91_PMC_PCDR [expr {$AT91_PMC + 0x14}] ;# Peripheral Clock Disable Register set AT91_PMC_PCSR [expr {$AT91_PMC + 0x18}] ;# Peripheral Clock Status Register set AT91_CKGR_UCKR [expr {$AT91_PMC + 0x1C}] ;# UTMI Clock Register [some SAM9, CAP9] set AT91_PMC_UPLLEN [expr {1 << 16}] ;# UTMI PLL Enable set AT91_PMC_UPLLCOUNT [expr {0xf << 20}] ;# UTMI PLL Start-up Time set AT91_PMC_BIASEN [expr {1 << 24}] ;# UTMI BIAS Enable set AT91_PMC_BIASCOUNT [expr {0xf << 28}] ;# UTMI BIAS Start-up Time set AT91_CKGR_MOR [expr {$AT91_PMC + 0x20}] ;# Main Oscillator Register [not on SAM9RL] set AT91_PMC_MOSCEN [expr {1 << 0}] ;# Main Oscillator Enable set AT91_PMC_OSCBYPASS [expr {1 << 1}] ;# Oscillator Bypass [SAM9x, CAP9] set AT91_PMC_OSCOUNT [expr {0xff << 8}] ;# Main Oscillator Start-up Time set AT91_CKGR_MCFR [expr {$AT91_PMC + 0x24}] ;# Main Clock Frequency Register set AT91_PMC_MAINF [expr {0xffff << 0}] ;# Main Clock Frequency set AT91_PMC_MAINRDY [expr {1 << 16}] ;# Main Clock Ready set AT91_CKGR_PLLAR [expr {$AT91_PMC + 0x28}] ;# PLL A Register set AT91_CKGR_PLLBR [expr {$AT91_PMC + 0x2c}] ;# PLL B Register set AT91_PMC_DIV [expr {0xff << 0}] ;# Divider set AT91_PMC_PLLCOUNT [expr {0x3f << 8}] ;# PLL Counter set AT91_PMC_OUT [expr {3 << 14}] ;# PLL Clock Frequency Range set AT91_PMC_MUL [expr {0x7ff << 16}] ;# PLL Multiplier set AT91_PMC_USBDIV [expr {3 << 28}] ;# USB Divisor (PLLB only) set AT91_PMC_USBDIV_1 [expr {0 << 28}] set AT91_PMC_USBDIV_2 [expr {1 << 28}] set AT91_PMC_USBDIV_4 [expr {2 << 28}] set AT91_PMC_USB96M [expr {1 << 28}] ;# Divider by 2 Enable (PLLB only) set AT91_PMC_PLLA_WR_ERRATA [expr {1 << 29}] ;# Bit 29 must always be set to 1 when programming the CKGR_PLLAR register set AT91_PMC_MCKR [expr {$AT91_PMC + 0x30}] ;# Master Clock Register set AT91_PMC_CSS [expr {3 << 0}] ;# Master Clock Selection set AT91_PMC_CSS_SLOW [expr {0 << 0}] set AT91_PMC_CSS_MAIN [expr {1 << 0}] set AT91_PMC_CSS_PLLA [expr {2 << 0}] set AT91_PMC_CSS_PLLB [expr {3 << 0}] set AT91_PMC_CSS_UPLL [expr {3 << 0}] ;# [some SAM9 only] set AT91_PMC_PRES [expr {7 << 2}] ;# Master Clock Prescaler set AT91_PMC_PRES_1 [expr {0 << 2}] set AT91_PMC_PRES_2 [expr {1 << 2}] set AT91_PMC_PRES_4 [expr {2 << 2}] set AT91_PMC_PRES_8 [expr {3 << 2}] set AT91_PMC_PRES_16 [expr {4 << 2}] set AT91_PMC_PRES_32 [expr {5 << 2}] set AT91_PMC_PRES_64 [expr {6 << 2}] set AT91_PMC_MDIV [expr {3 << 8}] ;# Master Clock Division set AT91RM9200_PMC_MDIV_1 [expr {0 << 8}] ;# [AT91RM9200 only] set AT91RM9200_PMC_MDIV_2 [expr {1 << 8}] set AT91RM9200_PMC_MDIV_3 [expr {2 << 8}] set AT91RM9200_PMC_MDIV_4 [expr {3 << 8}] set AT91SAM9_PMC_MDIV_1 [expr {0 << 8}] ;# [SAM9,CAP9 only] set AT91SAM9_PMC_MDIV_2 [expr {1 << 8}] set AT91SAM9_PMC_MDIV_4 [expr {2 << 8}] set AT91SAM9_PMC_MDIV_6 [expr {3 << 8}] ;# [some SAM9 only] set AT91SAM9_PMC_MDIV_3 [expr {3 << 8}] ;# [some SAM9 only] set AT91_PMC_PDIV [expr {1 << 12}] ;# Processor Clock Division [some SAM9 only] set AT91_PMC_PDIV_1 [expr {0 << 12}] set AT91_PMC_PDIV_2 [expr {1 << 12}] set AT91_PMC_PLLADIV2 [expr {1 << 12}] ;# PLLA divisor by 2 [some SAM9 only] set AT91_PMC_PLLADIV2_OFF [expr {0 << 12}] set AT91_PMC_PLLADIV2_ON [expr {1 << 12}] set AT91_PMC_USB [expr {$AT91_PMC + 0x38}] ;# USB Clock Register [some SAM9 only] set AT91_PMC_USBS [expr {0x1 << 0}] ;# USB OHCI Input clock selection set AT91_PMC_USBS_PLLA [expr {0 << 0}] set AT91_PMC_USBS_UPLL [expr {1 << 0}] set AT91_PMC_OHCIUSBDIV [expr {0xF << 8}] ;# Divider for USB OHCI Clock ;# set AT91_PMC_PCKR(n) [expr {$AT91_PMC + 0x40 + ((n) * 4)}] ;# Programmable Clock 0-N Registers set AT91_PMC_CSSMCK [expr {0x1 << 8}] ;# CSS or Master Clock Selection set AT91_PMC_CSSMCK_CSS [expr {0 << 8}] set AT91_PMC_CSSMCK_MCK [expr {1 << 8}] set AT91_PMC_IER [expr {$AT91_PMC + 0x60}] ;# Interrupt Enable Register set AT91_PMC_IDR [expr {$AT91_PMC + 0x64}] ;# Interrupt Disable Register set AT91_PMC_SR [expr {$AT91_PMC + 0x68}] ;# Status Register set AT91_PMC_MOSCS [expr {1 << 0}] ;# MOSCS Flag set AT91_PMC_LOCKA [expr {1 << 1}] ;# PLLA Lock set AT91_PMC_LOCKB [expr {1 << 2}] ;# PLLB Lock set AT91_PMC_MCKRDY [expr {1 << 3}] ;# Master Clock set AT91_PMC_LOCKU [expr {1 << 6}] ;# UPLL Lock [some SAM9, AT91CAP9 only] set AT91_PMC_OSCSEL [expr {1 << 7}] ;# Slow Clock Oscillator [AT91CAP9 revC only] set AT91_PMC_PCK0RDY [expr {1 << 8}] ;# Programmable Clock 0 set AT91_PMC_PCK1RDY [expr {1 << 9}] ;# Programmable Clock 1 set AT91_PMC_PCK2RDY [expr {1 << 10}] ;# Programmable Clock 2 set AT91_PMC_PCK3RDY [expr {1 << 11}] ;# Programmable Clock 3 set AT91_PMC_IMR [expr {$AT91_PMC + 0x6c}] ;# Interrupt Mask Register set AT91_PMC_PROT [expr {$AT91_PMC + 0xe4}] ;# Protect Register [AT91CAP9 revC only] set AT91_PMC_PROTKEY 0x504d4301 ;# Activation Code set AT91_PMC_VER [expr {$AT91_PMC + 0xfc}] ;# PMC Module Version [AT91CAP9 only] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/at91_rstc.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set AT91_RSTC_CR [expr {$AT91_RSTC + 0x00}] ;# Reset Controller Control Register set AT91_RSTC_PROCRST [expr {1 << 0}] ;# Processor Reset set AT91_RSTC_PERRST [expr {1 << 2}] ;# Peripheral Reset set AT91_RSTC_EXTRST [expr {1 << 3}] ;# External Reset set AT91_RSTC_KEY [expr {0xa5 << 24}] ;# KEY Password set AT91_RSTC_SR [expr {$AT91_RSTC + 0x04}] ;# Reset Controller Status Register set AT91_RSTC_URSTS [expr {1 << 0}] ;# User Reset Status set AT91_RSTC_RSTTYP [expr {7 << 8}] ;# Reset Type set AT91_RSTC_RSTTYP_GENERAL [expr {0 << 8}] set AT91_RSTC_RSTTYP_WAKEUP [expr {1 << 8}] set AT91_RSTC_RSTTYP_WATCHDOG [expr {2 << 8}] set AT91_RSTC_RSTTYP_SOFTWARE [expr {3 << 8}] set AT91_RSTC_RSTTYP_USER [expr {4 << 8}] set AT91_RSTC_NRSTL [expr {1 << 16}] ;# NRST Pin Level set AT91_RSTC_SRCMP [expr {1 << 17}] ;# Software Reset Command in Progress set AT91_RSTC_MR [expr {$AT91_RSTC + 0x08}] ;# Reset Controller Mode Register set AT91_RSTC_URSTEN [expr {1 << 0}] ;# User Reset Enable set AT91_RSTC_URSTIEN [expr {1 << 4}] ;# User Reset Interrupt Enable set AT91_RSTC_ERSTL [expr {0xf << 8}] ;# External Reset Length ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/at91_wdt.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set AT91_WDT_CR [expr {$AT91_WDT + 0x00}] ;# Watchdog Control Register set AT91_WDT_WDRSTT [expr {1 << 0}] ;# Restart set AT91_WDT_KEY [expr {0xa5 << 24}] ;# KEY Password set AT91_WDT_MR [expr {$AT91_WDT + 0x04}] ;# Watchdog Mode Register set AT91_WDT_WDV [expr {0xfff << 0}] ;# Counter Value set AT91_WDT_WDFIEN [expr {1 << 12}] ;# Fault Interrupt Enable set AT91_WDT_WDRSTEN [expr {1 << 13}] ;# Reset Processor set AT91_WDT_WDRPROC [expr {1 << 14}] ;# Timer Restart set AT91_WDT_WDDIS [expr {1 << 15}] ;# Watchdog Disable set AT91_WDT_WDD [expr {0xfff << 16}] ;# Delta Value set AT91_WDT_WDDBGHLT [expr {1 << 28}] ;# Debug Halt set AT91_WDT_WDIDLEHLT [expr {1 << 29}] ;# Idle Halt set AT91_WDT_SR [expr {$AT91_WDT + 0x08}] ;# Watchdog Status Register set AT91_WDT_WDUNF [expr {1 << 0}] ;# Watchdog Underflow set AT91_WDT_WDERR [expr {1 << 1}] ;# Watchdog Error ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/at91sam7x128.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find bitsbytes.tcl] source [find cpu/arm/arm7tdmi.tcl] source [find memory.tcl] source [find mmr_helpers.tcl] set CHIP_MAKER atmel set CHIP_FAMILY at91sam7 set CHIP_NAME at91sam7x128 # how many flash regions. set N_FLASH 1 set FLASH(0,CHIPSELECT) -1 set FLASH(0,BASE) 0x00100000 set FLASH(0,LEN) $__128K set FLASH(0,HUMAN) "internal flash" set FLASH(0,TYPE) "flash" set FLASH(0,RWX) $RWX_R_X set FLASH(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY # how many ram regions. set N_RAM 1 set RAM(0,CHIPSELECT) -1 set RAM(0,BASE) 0x00200000 set RAM(0,LEN) $__32K set RAM(0,HUMAN) "internal ram" set RAM(0,TYPE) "ram" set RAM(0,RWX) $RWX_RWX set RAM(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY # I AM LAZY... I create 1 region for all MMRs. set N_MMREGS 1 set MMREGS(0,CHIPSELECT) -1 set MMREGS(0,BASE) 0xfff00000 set MMREGS(0,LEN) 0x000fffff set MMREGS(0,HUMAN) "mm-regs" set MMREGS(0,TYPE) "mmr" set MMREGS(0,RWX) $RWX_RW set MMREGS(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY # no external memory set N_XMEM 0 set AT91C_BASE_SYS 0xFFFFF000 set AT91C_BASE_AIC 0xFFFFF000 set AT91C_BASE_PDC_DBGU 0xFFFFF300 set AT91C_BASE_DBGU 0xFFFFF200 set AT91C_BASE_PIOA 0xFFFFF400 set AT91C_BASE_PIOB 0xFFFFF600 set AT91C_BASE_CKGR 0xFFFFFC20 set AT91C_BASE_PMC 0xFFFFFC00 set AT91C_BASE_RSTC 0xFFFFFD00 set AT91C_BASE_RTTC 0xFFFFFD20 set AT91C_BASE_PITC 0xFFFFFD30 set AT91C_BASE_WDTC 0xFFFFFD40 set AT91C_BASE_VREG 0xFFFFFD60 set AT91C_BASE_MC 0xFFFFFF00 set AT91C_BASE_PDC_SPI1 0xFFFE4100 set AT91C_BASE_SPI1 0xFFFE4000 set AT91C_BASE_PDC_SPI0 0xFFFE0100 set AT91C_BASE_SPI0 0xFFFE0000 set AT91C_BASE_PDC_US1 0xFFFC4100 set AT91C_BASE_US1 0xFFFC4000 set AT91C_BASE_PDC_US0 0xFFFC0100 set AT91C_BASE_US0 0xFFFC0000 set AT91C_BASE_PDC_SSC 0xFFFD4100 set AT91C_BASE_SSC 0xFFFD4000 set AT91C_BASE_TWI 0xFFFB8000 set AT91C_BASE_PWMC_CH3 0xFFFCC260 set AT91C_BASE_PWMC_CH2 0xFFFCC240 set AT91C_BASE_PWMC_CH1 0xFFFCC220 set AT91C_BASE_PWMC_CH0 0xFFFCC200 set AT91C_BASE_PWMC 0xFFFCC000 set AT91C_BASE_UDP 0xFFFB0000 set AT91C_BASE_TC0 0xFFFA0000 set AT91C_BASE_TC1 0xFFFA0040 set AT91C_BASE_TC2 0xFFFA0080 set AT91C_BASE_TCB 0xFFFA0000 set AT91C_BASE_CAN_MB0 0xFFFD0200 set AT91C_BASE_CAN_MB1 0xFFFD0220 set AT91C_BASE_CAN_MB2 0xFFFD0240 set AT91C_BASE_CAN_MB3 0xFFFD0260 set AT91C_BASE_CAN_MB4 0xFFFD0280 set AT91C_BASE_CAN_MB5 0xFFFD02A0 set AT91C_BASE_CAN_MB6 0xFFFD02C0 set AT91C_BASE_CAN_MB7 0xFFFD02E0 set AT91C_BASE_CAN 0xFFFD0000 set AT91C_BASE_EMAC 0xFFFDC000 set AT91C_BASE_PDC_ADC 0xFFFD8100 set AT91C_BASE_ADC 0xFFFD8000 set AT91C_ID(0) FIQ set AT91C_ID(1) SYS set AT91C_ID(2) PIOA set AT91C_ID(3) PIOB set AT91C_ID(4) SPI0 set AT91C_ID(5) SPI1 set AT91C_ID(6) US0 set AT91C_ID(7) US1 set AT91C_ID(8) SSC set AT91C_ID(9) TWI set AT91C_ID(10) PWMC set AT91C_ID(11) UDP set AT91C_ID(12) TC0 set AT91C_ID(13) TC1 set AT91C_ID(14) TC2 set AT91C_ID(15) CAN set AT91C_ID(16) EMAC set AT91C_ID(17) ADC set AT91C_ID(18) "" set AT91C_ID(19) "" set AT91C_ID(20) "" set AT91C_ID(21) "" set AT91C_ID(22) "" set AT91C_ID(23) "" set AT91C_ID(24) "" set AT91C_ID(25) "" set AT91C_ID(26) "" set AT91C_ID(27) "" set AT91C_ID(28) "" set AT91C_ID(29) "" set AT91C_ID(30) IRQ0 set AT91C_ID(31) IRQ1 source [find chip/atmel/at91/aic.tcl] source [find chip/atmel/at91/usarts.tcl] source [find chip/atmel/at91/pmc.tcl] source [find chip/atmel/at91/rtt.tcl] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/at91sam7x256.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find bitsbytes.tcl] source [find cpu/arm/arm7tdmi.tcl] source [find memory.tcl] source [find mmr_helpers.tcl] set CHIP_MAKER atmel set CHIP_FAMILY at91sam7 set CHIP_NAME at91sam7x256 # how many flash regions. set N_FLASH 1 set FLASH(0,CHIPSELECT) -1 set FLASH(0,BASE) 0x00100000 set FLASH(0,LEN) $__256K set FLASH(0,HUMAN) "internal flash" set FLASH(0,TYPE) "flash" set FLASH(0,RWX) $RWX_R_X set FLASH(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY # how many ram regions. set N_RAM 1 set RAM(0,CHIPSELECT) -1 set RAM(0,BASE) 0x00200000 set RAM(0,LEN) $__64K set RAM(0,HUMAN) "internal ram" set RAM(0,TYPE) "ram" set RAM(0,RWX) $RWX_RWX set RAM(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY # I AM LAZY... I create 1 region for all MMRs. set N_MMREGS 1 set MMREGS(0,CHIPSELECT) -1 set MMREGS(0,BASE) 0xfff00000 set MMREGS(0,LEN) 0x000fffff set MMREGS(0,HUMAN) "mm-regs" set MMREGS(0,TYPE) "mmr" set MMREGS(0,RWX) $RWX_RW set MMREGS(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY # no external memory set N_XMEM 0 set AT91C_BASE_SYS 0xFFFFF000 set AT91C_BASE_AIC 0xFFFFF000 set AT91C_BASE_PDC_DBGU 0xFFFFF300 set AT91C_BASE_DBGU 0xFFFFF200 set AT91C_BASE_PIOA 0xFFFFF400 set AT91C_BASE_PIOB 0xFFFFF600 set AT91C_BASE_CKGR 0xFFFFFC20 set AT91C_BASE_PMC 0xFFFFFC00 set AT91C_BASE_RSTC 0xFFFFFD00 set AT91C_BASE_RTTC 0xFFFFFD20 set AT91C_BASE_PITC 0xFFFFFD30 set AT91C_BASE_WDTC 0xFFFFFD40 set AT91C_BASE_VREG 0xFFFFFD60 set AT91C_BASE_MC 0xFFFFFF00 set AT91C_BASE_PDC_SPI1 0xFFFE4100 set AT91C_BASE_SPI1 0xFFFE4000 set AT91C_BASE_PDC_SPI0 0xFFFE0100 set AT91C_BASE_SPI0 0xFFFE0000 set AT91C_BASE_PDC_US1 0xFFFC4100 set AT91C_BASE_US1 0xFFFC4000 set AT91C_BASE_PDC_US0 0xFFFC0100 set AT91C_BASE_US0 0xFFFC0000 set AT91C_BASE_PDC_SSC 0xFFFD4100 set AT91C_BASE_SSC 0xFFFD4000 set AT91C_BASE_TWI 0xFFFB8000 set AT91C_BASE_PWMC_CH3 0xFFFCC260 set AT91C_BASE_PWMC_CH2 0xFFFCC240 set AT91C_BASE_PWMC_CH1 0xFFFCC220 set AT91C_BASE_PWMC_CH0 0xFFFCC200 set AT91C_BASE_PWMC 0xFFFCC000 set AT91C_BASE_UDP 0xFFFB0000 set AT91C_BASE_TC0 0xFFFA0000 set AT91C_BASE_TC1 0xFFFA0040 set AT91C_BASE_TC2 0xFFFA0080 set AT91C_BASE_TCB 0xFFFA0000 set AT91C_BASE_CAN_MB0 0xFFFD0200 set AT91C_BASE_CAN_MB1 0xFFFD0220 set AT91C_BASE_CAN_MB2 0xFFFD0240 set AT91C_BASE_CAN_MB3 0xFFFD0260 set AT91C_BASE_CAN_MB4 0xFFFD0280 set AT91C_BASE_CAN_MB5 0xFFFD02A0 set AT91C_BASE_CAN_MB6 0xFFFD02C0 set AT91C_BASE_CAN_MB7 0xFFFD02E0 set AT91C_BASE_CAN 0xFFFD0000 set AT91C_BASE_EMAC 0xFFFDC000 set AT91C_BASE_PDC_ADC 0xFFFD8100 set AT91C_BASE_ADC 0xFFFD8000 set AT91C_ID(0) "FIQ" set AT91C_ID(1) "SYS" set AT91C_ID(2) "PIOA" set AT91C_ID(3) "PIOB" set AT91C_ID(4) "SPI0" set AT91C_ID(5) "SPI1" set AT91C_ID(6) "US0" set AT91C_ID(7) "US1" set AT91C_ID(8) "SSC" set AT91C_ID(9) "TWI" set AT91C_ID(10) "PWMC" set AT91C_ID(11) "UDP" set AT91C_ID(12) "TC0" set AT91C_ID(13) "TC1" set AT91C_ID(14) "TC2" set AT91C_ID(15) "CAN" set AT91C_ID(16) "EMAC" set AT91C_ID(17) "ADC" set AT91C_ID(18) "" set AT91C_ID(19) "" set AT91C_ID(20) "" set AT91C_ID(21) "" set AT91C_ID(22) "" set AT91C_ID(23) "" set AT91C_ID(24) "" set AT91C_ID(25) "" set AT91C_ID(26) "" set AT91C_ID(27) "" set AT91C_ID(28) "" set AT91C_ID(29) "" set AT91C_ID(30) "IRQ0" set AT91C_ID(31) "IRQ1" source [find chip/atmel/at91/aic.tcl] source [find chip/atmel/at91/usarts.tcl] source [find chip/atmel/at91/pmc.tcl] source [find chip/atmel/at91/rtt.tcl] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/at91sam9261.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Peripheral identifiers/interrupts. # set AT91_ID_FIQ 0 ;# Advanced Interrupt Controller (FIQ) set AT91_ID_SYS 1 ;# System Peripherals set AT91SAM9261_ID_PIOA 2 ;# Parallel IO Controller A set AT91SAM9261_ID_PIOB 3 ;# Parallel IO Controller B set AT91SAM9261_ID_PIOC 4 ;# Parallel IO Controller C set AT91SAM9261_ID_US0 6 ;# USART 0 set AT91SAM9261_ID_US1 7 ;# USART 1 set AT91SAM9261_ID_US2 8 ;# USART 2 set AT91SAM9261_ID_MCI 9 ;# Multimedia Card Interface set AT91SAM9261_ID_UDP 10 ;# USB Device Port set AT91SAM9261_ID_TWI 11 ;# Two-Wire Interface set AT91SAM9261_ID_SPI0 12 ;# Serial Peripheral Interface 0 set AT91SAM9261_ID_SPI1 13 ;# Serial Peripheral Interface 1 set AT91SAM9261_ID_SSC0 14 ;# Serial Synchronous Controller 0 set AT91SAM9261_ID_SSC1 15 ;# Serial Synchronous Controller 1 set AT91SAM9261_ID_SSC2 16 ;# Serial Synchronous Controller 2 set AT91SAM9261_ID_TC0 17 ;# Timer Counter 0 set AT91SAM9261_ID_TC1 18 ;# Timer Counter 1 set AT91SAM9261_ID_TC2 19 ;# Timer Counter 2 set AT91SAM9261_ID_UHP 20 ;# USB Host port set AT91SAM9261_ID_LCDC 21 ;# LDC Controller set AT91SAM9261_ID_IRQ0 29 ;# Advanced Interrupt Controller (IRQ0) set AT91SAM9261_ID_IRQ1 30 ;# Advanced Interrupt Controller (IRQ1) set AT91SAM9261_ID_IRQ2 31 ;# Advanced Interrupt Controller (IRQ2) # # User Peripheral physical base addresses. # set AT91SAM9261_BASE_TCB0 0xfffa0000 set AT91SAM9261_BASE_TC0 0xfffa0000 set AT91SAM9261_BASE_TC1 0xfffa0040 set AT91SAM9261_BASE_TC2 0xfffa0080 set AT91SAM9261_BASE_UDP 0xfffa4000 set AT91SAM9261_BASE_MCI 0xfffa8000 set AT91SAM9261_BASE_TWI 0xfffac000 set AT91SAM9261_BASE_US0 0xfffb0000 set AT91SAM9261_BASE_US1 0xfffb4000 set AT91SAM9261_BASE_US2 0xfffb8000 set AT91SAM9261_BASE_SSC0 0xfffbc000 set AT91SAM9261_BASE_SSC1 0xfffc0000 set AT91SAM9261_BASE_SSC2 0xfffc4000 set AT91SAM9261_BASE_SPI0 0xfffc8000 set AT91SAM9261_BASE_SPI1 0xfffcc000 set AT91_BASE_SYS 0xffffea00 # # System Peripherals (offset from AT91_BASE_SYS) # set AT91_SDRAMC 0xffffea00 set AT91_SMC 0xffffec00 set AT91_MATRIX 0xffffee00 set AT91_AIC 0xfffff000 set AT91_DBGU 0xfffff200 set AT91_PIOA 0xfffff400 set AT91_PIOB 0xfffff600 set AT91_PIOC 0xfffff800 set AT91_PMC 0xfffffc00 set AT91_RSTC 0xfffffd00 set AT91_SHDWC 0xfffffd10 set AT91_RTT 0xfffffd20 set AT91_PIT 0xfffffd30 set AT91_WDT 0xfffffd40 set AT91_GPBR 0xfffffd50 set AT91_USART0 $AT91SAM9261_BASE_US0 set AT91_USART1 $AT91SAM9261_BASE_US1 set AT91_USART2 $AT91SAM9261_BASE_US2 # # Internal Memory. # set AT91SAM9261_SRAM_BASE 0x00300000 ;# Internal SRAM base address set AT91SAM9261_SRAM_SIZE 0x00028000 ;# Internal SRAM size (160Kb) set AT91SAM9261_ROM_BASE 0x00400000 ;# Internal ROM base address set AT91SAM9261_ROM_SIZE 0x00008000 ;# Internal ROM size (32Kb) set AT91SAM9261_UHP_BASE 0x00500000 ;# USB Host controller set AT91SAM9261_LCDC_BASE 0x00600000 ;# LDC controller # # Cpu Name # set AT91_CPU_NAME "AT91SAM9261" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/at91sam9261_matrix.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set AT91_MATRIX_MCFG [expr {$AT91_MATRIX + 0x00}] ;# Master Configuration Register # set AT91_MATRIX_RCB0 [expr {1 << 0}] ;# Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) set AT91_MATRIX_RCB1 [expr {1 << 1}] ;# Remap Command for AHB Master 1 (ARM926EJ-S Data Master) set AT91_MATRIX_SCFG0 [expr {$AT91_MATRIX + 0x04}] ;# Slave Configuration Register 0 set AT91_MATRIX_SCFG1 [expr {$AT91_MATRIX + 0x08}] ;# Slave Configuration Register 1 set AT91_MATRIX_SCFG2 [expr {$AT91_MATRIX + 0x0C}] ;# Slave Configuration Register 2 set AT91_MATRIX_SCFG3 [expr {$AT91_MATRIX + 0x10}] ;# Slave Configuration Register 3 set AT91_MATRIX_SCFG4 [expr {$AT91_MATRIX + 0x14}] ;# Slave Configuration Register 4 set AT91_MATRIX_SLOT_CYCLE [expr {0xff << 0}] ;# Maximum Number of Allowed Cycles for a Burst set AT91_MATRIX_DEFMSTR_TYPE [expr {3 << 16}] ;# Default Master Type set AT91_MATRIX_DEFMSTR_TYPE_NONE [expr {0 << 16}] set AT91_MATRIX_DEFMSTR_TYPE_LAST [expr {1 << 16}] set AT91_MATRIX_DEFMSTR_TYPE_FIXED [expr {2 << 16}] set AT91_MATRIX_FIXED_DEFMSTR [expr {7 << 18}] ;# Fixed Index of Default Master set AT91_MATRIX_TCR [expr {$AT91_MATRIX + 0x24}] ;# TCM Configuration Register set AT91_MATRIX_ITCM_SIZE [expr {0xf << 0}] ;# Size of ITCM enabled memory block set AT91_MATRIX_ITCM_0 [expr {0 << 0}] set AT91_MATRIX_ITCM_16 [expr {5 << 0}] set AT91_MATRIX_ITCM_32 [expr {6 << 0}] set AT91_MATRIX_ITCM_64 [expr {7 << 0}] set AT91_MATRIX_DTCM_SIZE [expr {0xf << 4}] ;# Size of DTCM enabled memory block set AT91_MATRIX_DTCM_0 [expr {0 << 4}] set AT91_MATRIX_DTCM_16 [expr {5 << 4}] set AT91_MATRIX_DTCM_32 [expr {6 << 4}] set AT91_MATRIX_DTCM_64 [expr {7 << 4}] set AT91_MATRIX_EBICSA [expr {$AT91_MATRIX + 0x30}] ;# EBI Chip Select Assignment Register set AT91_MATRIX_CS1A [expr {1 << 1}] ;# Chip Select 1 Assignment set AT91_MATRIX_CS1A_SMC [expr {0 << 1}] set AT91_MATRIX_CS1A_SDRAMC [expr {1 << 1}] set AT91_MATRIX_CS3A [expr {1 << 3}] ;# Chip Select 3 Assignment set AT91_MATRIX_CS3A_SMC [expr {0 << 3}] set AT91_MATRIX_CS3A_SMC_SMARTMEDIA [expr {1 << 3}] set AT91_MATRIX_CS4A [expr {1 << 4}] ;# Chip Select 4 Assignment set AT91_MATRIX_CS4A_SMC [expr {0 << 4}] set AT91_MATRIX_CS4A_SMC_CF1 [expr {1 << 4}] set AT91_MATRIX_CS5A [expr {1 << 5}] ;# Chip Select 5 Assignment set AT91_MATRIX_CS5A_SMC [expr {0 << 5}] set AT91_MATRIX_CS5A_SMC_CF2 [expr {1 << 5}] set AT91_MATRIX_DBPUC [expr {1 << 8}] ;# Data Bus Pull-up Configuration set AT91_MATRIX_USBPUCR [expr {$AT91_MATRIX + 0x34}] ;# USB Pad Pull-Up Control Register set AT91_MATRIX_USBPUCR_PUON [expr {1 << 30}] ;# USB Device PAD Pull-up Enable ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/at91sam9263.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Peripheral identifiers/interrupts. # set AT91_ID_FIQ 0 ;# Advanced Interrupt Controller (FIQ) set AT91_ID_SYS 1 ;# System Peripherals set AT91SAM9263_ID_PIOA 2 ;# Parallel IO Controller A set AT91SAM9263_ID_PIOB 3 ;# Parallel IO Controller B set AT91SAM9263_ID_PIOCDE 4 ;# Parallel IO Controller C, D and E set AT91SAM9263_ID_US0 7 ;# USART 0 set AT91SAM9263_ID_US1 8 ;# USART 1 set AT91SAM9263_ID_US2 9 ;# USART 2 set AT91SAM9263_ID_MCI0 10 ;# Multimedia Card Interface 0 set AT91SAM9263_ID_MCI1 11 ;# Multimedia Card Interface 1 set AT91SAM9263_ID_CAN 12 ;# CAN set AT91SAM9263_ID_TWI 13 ;# Two-Wire Interface set AT91SAM9263_ID_SPI0 14 ;# Serial Peripheral Interface 0 set AT91SAM9263_ID_SPI1 15 ;# Serial Peripheral Interface 1 set AT91SAM9263_ID_SSC0 16 ;# Serial Synchronous Controller 0 set AT91SAM9263_ID_SSC1 17 ;# Serial Synchronous Controller 1 set AT91SAM9263_ID_AC97C 18 ;# AC97 Controller set AT91SAM9263_ID_TCB 19 ;# Timer Counter 0, 1 and 2 set AT91SAM9263_ID_PWMC 20 ;# Pulse Width Modulation Controller set AT91SAM9263_ID_EMAC 21 ;# Ethernet set AT91SAM9263_ID_2DGE 23 ;# 2D Graphic Engine set AT91SAM9263_ID_UDP 24 ;# USB Device Port set AT91SAM9263_ID_ISI 25 ;# Image Sensor Interface set AT91SAM9263_ID_LCDC 26 ;# LCD Controller set AT91SAM9263_ID_DMA 27 ;# DMA Controller set AT91SAM9263_ID_UHP 29 ;# USB Host port set AT91SAM9263_ID_IRQ0 30 ;# Advanced Interrupt Controller (IRQ0) set AT91SAM9263_ID_IRQ1 31 ;# Advanced Interrupt Controller (IRQ1) # # User Peripheral physical base addresses. # set AT91SAM9263_BASE_UDP 0xfff78000 set AT91SAM9263_BASE_TCB0 0xfff7c000 set AT91SAM9263_BASE_TC0 0xfff7c000 set AT91SAM9263_BASE_TC1 0xfff7c040 set AT91SAM9263_BASE_TC2 0xfff7c080 set AT91SAM9263_BASE_MCI0 0xfff80000 set AT91SAM9263_BASE_MCI1 0xfff84000 set AT91SAM9263_BASE_TWI 0xfff88000 set AT91SAM9263_BASE_US0 0xfff8c000 set AT91SAM9263_BASE_US1 0xfff90000 set AT91SAM9263_BASE_US2 0xfff94000 set AT91SAM9263_BASE_SSC0 0xfff98000 set AT91SAM9263_BASE_SSC1 0xfff9c000 set AT91SAM9263_BASE_AC97C 0xfffa0000 set AT91SAM9263_BASE_SPI0 0xfffa4000 set AT91SAM9263_BASE_SPI1 0xfffa8000 set AT91SAM9263_BASE_CAN 0xfffac000 set AT91SAM9263_BASE_PWMC 0xfffb8000 set AT91SAM9263_BASE_EMAC 0xfffbc000 set AT91SAM9263_BASE_ISI 0xfffc4000 set AT91SAM9263_BASE_2DGE 0xfffc8000 set AT91_BASE_SYS 0xffffe000 # # System Peripherals (offset from AT91_BASE_SYS) # set AT91_ECC0 0xffffe000 set AT91_SDRAMC0 0xffffe200 set AT91_SMC0 0xffffe400 set AT91_ECC1 0xffffe600 set AT91_SDRAMC1 0xffffe800 set AT91_SMC1 0xffffea00 set AT91_MATRIX 0xffffec00 set AT91_CCFG 0xffffed10 set AT91_DBGU 0xffffee00 set AT91_AIC 0xfffff000 set AT91_PIOA 0xfffff200 set AT91_PIOB 0xfffff400 set AT91_PIOC 0xfffff600 set AT91_PIOD 0xfffff800 set AT91_PIOE 0xfffffa00 set AT91_PMC 0xfffffc00 set AT91_RSTC 0xfffffd00 set AT91_SHDWC 0xfffffd10 set AT91_RTT0 0xfffffd20 set AT91_PIT 0xfffffd30 set AT91_WDT 0xfffffd40 set AT91_RTT1 0xfffffd50 set AT91_GPBR 0xfffffd60 set AT91_USART0 $AT91SAM9263_BASE_US0 set AT91_USART1 $AT91SAM9263_BASE_US1 set AT91_USART2 $AT91SAM9263_BASE_US2 set AT91_SMC $AT91_SMC0 set AT91_SDRAMC $AT91_SDRAMC0 # # Internal Memory. # set AT91SAM9263_SRAM0_BASE 0x00300000 ;# Internal SRAM 0 base address set AT91SAM9263_SRAM0_SIZE 0x00014000 ;# Internal SRAM 0 size (80Kb) set AT91SAM9263_ROM_BASE 0x00400000 ;# Internal ROM base address set AT91SAM9263_ROM_SIZE 0x00020000 ;# Internal ROM size (128Kb) set AT91SAM9263_SRAM1_BASE 0x00500000 ;# Internal SRAM 1 base address set AT91SAM9263_SRAM1_SIZE 0x00004000 ;# Internal SRAM 1 size (16Kb) set AT91SAM9263_LCDC_BASE 0x00700000 ;# LCD Controller set AT91SAM9263_DMAC_BASE 0x00800000 ;# DMA Controller set AT91SAM9263_UHP_BASE 0x00a00000 ;# USB Host controller # # Cpu Name # set AT91_CPU_NAME "AT91SAM9263" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/at91sam9263_matrix.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set AT91_MATRIX_MCFG0 [expr {$AT91_MATRIX + 0x00}] ;# Master Configuration Register 0 set AT91_MATRIX_MCFG1 [expr {$AT91_MATRIX + 0x04}] ;# Master Configuration Register 1 set AT91_MATRIX_MCFG2 [expr {$AT91_MATRIX + 0x08}] ;# Master Configuration Register 2 set AT91_MATRIX_MCFG3 [expr {$AT91_MATRIX + 0x0C}] ;# Master Configuration Register 3 set AT91_MATRIX_MCFG4 [expr {$AT91_MATRIX + 0x10}] ;# Master Configuration Register 4 set AT91_MATRIX_MCFG5 [expr {$AT91_MATRIX + 0x14}] ;# Master Configuration Register 5 set AT91_MATRIX_MCFG6 [expr {$AT91_MATRIX + 0x18}] ;# Master Configuration Register 6 set AT91_MATRIX_MCFG7 [expr {$AT91_MATRIX + 0x1C}] ;# Master Configuration Register 7 set AT91_MATRIX_MCFG8 [expr {$AT91_MATRIX + 0x20}] ;# Master Configuration Register 8 set AT91_MATRIX_ULBT [expr {7 << 0}] ;# Undefined Length Burst Type set AT91_MATRIX_ULBT_INFINITE [expr {0 << 0}] set AT91_MATRIX_ULBT_SINGLE [expr {1 << 0}] set AT91_MATRIX_ULBT_FOUR [expr {2 << 0}] set AT91_MATRIX_ULBT_EIGHT [expr {3 << 0}] set AT91_MATRIX_ULBT_SIXTEEN [expr {4 << 0}] set AT91_MATRIX_SCFG0 [expr {$AT91_MATRIX + 0x40}] ;# Slave Configuration Register 0 set AT91_MATRIX_SCFG1 [expr {$AT91_MATRIX + 0x44}] ;# Slave Configuration Register 1 set AT91_MATRIX_SCFG2 [expr {$AT91_MATRIX + 0x48}] ;# Slave Configuration Register 2 set AT91_MATRIX_SCFG3 [expr {$AT91_MATRIX + 0x4C}] ;# Slave Configuration Register 3 set AT91_MATRIX_SCFG4 [expr {$AT91_MATRIX + 0x50}] ;# Slave Configuration Register 4 set AT91_MATRIX_SCFG5 [expr {$AT91_MATRIX + 0x54}] ;# Slave Configuration Register 5 set AT91_MATRIX_SCFG6 [expr {$AT91_MATRIX + 0x58}] ;# Slave Configuration Register 6 set AT91_MATRIX_SCFG7 [expr {$AT91_MATRIX + 0x5C}] ;# Slave Configuration Register 7 set AT91_MATRIX_SLOT_CYCLE [expr {0xff << 0}] ;# Maximum Number of Allowed Cycles for a Burst set AT91_MATRIX_DEFMSTR_TYPE [expr {3 << 16}] ;# Default Master Type set AT91_MATRIX_DEFMSTR_TYPE_NONE [expr {0 << 16}] set AT91_MATRIX_DEFMSTR_TYPE_LAST [expr {1 << 16}] set AT91_MATRIX_DEFMSTR_TYPE_FIXED [expr {2 << 16}] set AT91_MATRIX_FIXED_DEFMSTR [expr {0xf << 18}] ;# Fixed Index of Default Master set AT91_MATRIX_ARBT [expr {3 << 24}] ;# Arbitration Type set AT91_MATRIX_ARBT_ROUND_ROBIN [expr {0 << 24}] set AT91_MATRIX_ARBT_FIXED_PRIORITY [expr {1 << 24}] set AT91_MATRIX_PRAS0 [expr {$AT91_MATRIX + 0x80}] ;# Priority Register A for Slave 0 set AT91_MATRIX_PRBS0 [expr {$AT91_MATRIX + 0x84}] ;# Priority Register B for Slave 0 set AT91_MATRIX_PRAS1 [expr {$AT91_MATRIX + 0x88}] ;# Priority Register A for Slave 1 set AT91_MATRIX_PRBS1 [expr {$AT91_MATRIX + 0x8C}] ;# Priority Register B for Slave 1 set AT91_MATRIX_PRAS2 [expr {$AT91_MATRIX + 0x90}] ;# Priority Register A for Slave 2 set AT91_MATRIX_PRBS2 [expr {$AT91_MATRIX + 0x94}] ;# Priority Register B for Slave 2 set AT91_MATRIX_PRAS3 [expr {$AT91_MATRIX + 0x98}] ;# Priority Register A for Slave 3 set AT91_MATRIX_PRBS3 [expr {$AT91_MATRIX + 0x9C}] ;# Priority Register B for Slave 3 set AT91_MATRIX_PRAS4 [expr {$AT91_MATRIX + 0xA0}] ;# Priority Register A for Slave 4 set AT91_MATRIX_PRBS4 [expr {$AT91_MATRIX + 0xA4}] ;# Priority Register B for Slave 4 set AT91_MATRIX_PRAS5 [expr {$AT91_MATRIX + 0xA8}] ;# Priority Register A for Slave 5 set AT91_MATRIX_PRBS5 [expr {$AT91_MATRIX + 0xAC}] ;# Priority Register B for Slave 5 set AT91_MATRIX_PRAS6 [expr {$AT91_MATRIX + 0xB0}] ;# Priority Register A for Slave 6 set AT91_MATRIX_PRBS6 [expr {$AT91_MATRIX + 0xB4}] ;# Priority Register B for Slave 6 set AT91_MATRIX_PRAS7 [expr {$AT91_MATRIX + 0xB8}] ;# Priority Register A for Slave 7 set AT91_MATRIX_PRBS7 [expr {$AT91_MATRIX + 0xBC}] ;# Priority Register B for Slave 7 set AT91_MATRIX_M0PR [expr {3 << 0}] ;# Master 0 Priority set AT91_MATRIX_M1PR [expr {3 << 4}] ;# Master 1 Priority set AT91_MATRIX_M2PR [expr {3 << 8}] ;# Master 2 Priority set AT91_MATRIX_M3PR [expr {3 << 12}] ;# Master 3 Priority set AT91_MATRIX_M4PR [expr {3 << 16}] ;# Master 4 Priority set AT91_MATRIX_M5PR [expr {3 << 20}] ;# Master 5 Priority set AT91_MATRIX_M6PR [expr {3 << 24}] ;# Master 6 Priority set AT91_MATRIX_M7PR [expr {3 << 28}] ;# Master 7 Priority set AT91_MATRIX_M8PR [expr {3 << 0}] ;# Master 8 Priority (in Register B) set AT91_MATRIX_MRCR [expr {$AT91_MATRIX + 0x100}] ;# Master Remap Control Register set AT91_MATRIX_RCB0 [expr {1 << 0}] ;# Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) set AT91_MATRIX_RCB1 [expr {1 << 1}] ;# Remap Command for AHB Master 1 (ARM926EJ-S Data Master) set AT91_MATRIX_RCB2 [expr {1 << 2}] set AT91_MATRIX_RCB3 [expr {1 << 3}] set AT91_MATRIX_RCB4 [expr {1 << 4}] set AT91_MATRIX_RCB5 [expr {1 << 5}] set AT91_MATRIX_RCB6 [expr {1 << 6}] set AT91_MATRIX_RCB7 [expr {1 << 7}] set AT91_MATRIX_RCB8 [expr {1 << 8}] set AT91_MATRIX_TCMR [expr {$AT91_MATRIX + 0x114}] ;# TCM Configuration Register set AT91_MATRIX_ITCM_SIZE [expr {0xf << 0}] ;# Size of ITCM enabled memory block set AT91_MATRIX_ITCM_0 [expr {0 << 0}] set AT91_MATRIX_ITCM_16 [expr {5 << 0}] set AT91_MATRIX_ITCM_32 [expr {6 << 0}] set AT91_MATRIX_DTCM_SIZE [expr {0xf << 4}] ;# Size of DTCM enabled memory block set AT91_MATRIX_DTCM_0 [expr {0 << 4}] set AT91_MATRIX_DTCM_16 [expr {5 << 4}] set AT91_MATRIX_DTCM_32 [expr {6 << 4}] set AT91_MATRIX_EBI0CSA [expr {$AT91_MATRIX + 0x120}] ;# EBI0 Chip Select Assignment Register set AT91_MATRIX_EBI0_CS1A [expr {1 << 1}] ;# Chip Select 1 Assignment set AT91_MATRIX_EBI0_CS1A_SMC [expr {0 << 1}] set AT91_MATRIX_EBI0_CS1A_SDRAMC [expr {1 << 1}] set AT91_MATRIX_EBI0_CS3A [expr {1 << 3}] ;# Chip Select 3 Assignmen set AT91_MATRIX_EBI0_CS3A_SMC [expr {0 << 3}] set AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA [expr {1 << 3}] set AT91_MATRIX_EBI0_CS4A [expr {1 << 4}] ;# Chip Select 4 Assignment set AT91_MATRIX_EBI0_CS4A_SMC [expr {0 << 4}] set AT91_MATRIX_EBI0_CS4A_SMC_CF1 [expr {1 << 4}] set AT91_MATRIX_EBI0_CS5A [expr {1 << 5}] ;# Chip Select 5 Assignment set AT91_MATRIX_EBI0_CS5A_SMC [expr {0 << 5}] set AT91_MATRIX_EBI0_CS5A_SMC_CF2 [expr {1 << 5}] set AT91_MATRIX_EBI0_DBPUC [expr {1 << 8}] ;# Data Bus Pull-up Configuration set AT91_MATRIX_EBI0_VDDIOMSEL [expr {1 << 16}] ;# Memory voltage selection set AT91_MATRIX_EBI0_VDDIOMSEL_1_8V [expr {0 << 16}] set AT91_MATRIX_EBI0_VDDIOMSEL_3_3V [expr {1 << 16}] set AT91_MATRIX_EBI1CSA [expr {$AT91_MATRIX + 0x124}] ;# EBI1 Chip Select Assignment Register set AT91_MATRIX_EBI1_CS1A [expr {1 << 1}] ;# Chip Select 1 Assignment set AT91_MATRIX_EBI1_CS1A_SMC [expr {0 << 1}] set AT91_MATRIX_EBI1_CS1A_SDRAMC [expr {1 << 1}] set AT91_MATRIX_EBI1_CS2A [expr {1 << 3}] ;# Chip Select 3 Assignment set AT91_MATRIX_EBI1_CS2A_SMC [expr {0 << 3}] set AT91_MATRIX_EBI1_CS2A_SMC_SMARTMEDIA [expr {1 << 3}] set AT91_MATRIX_EBI1_DBPUC [expr {1 << 8}] ;# Data Bus Pull-up Configuration set AT91_MATRIX_EBI1_VDDIOMSEL [expr {1 << 16}] ;# Memory voltage selection set AT91_MATRIX_EBI1_VDDIOMSEL_1_8V [expr {0 << 16}] set AT91_MATRIX_EBI1_VDDIOMSEL_3_3V [expr {1 << 16}] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/at91sam9_init.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later uplevel #0 [list source [find chip/atmel/at91/at91sam9_sdramc.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91_pmc.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91_pio.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91_rstc.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91_wdt.cfg]] proc at91sam9_reset_start { } { arm7_9 fast_memory_access disable jtag_rclk 8 halt wait_halt 10000 set rstc_mr_val $::AT91_RSTC_KEY set rstc_mr_val [expr {$rstc_mr_val | (5 << 8)}] set rstc_mr_val [expr {$rstc_mr_val | $::AT91_RSTC_URSTEN}] mww $::AT91_RSTC_MR $rstc_mr_val ;# RSTC_MR : enable user reset. } proc at91sam9_reset_init { config } { mww $::AT91_WDT_MR $config(wdt_mr_val) ;# disable watchdog set ckgr_mor [expr {$::AT91_PMC_MOSCEN | (255 << 8)}] mww $::AT91_CKGR_MOR $ckgr_mor ;# CKGR_MOR - enable main osc. while { [expr {[mrw $::AT91_PMC_SR] & $::AT91_PMC_MOSCS}] != $::AT91_PMC_MOSCS } { sleep 1 } set pllar_val $::AT91_PMC_PLLA_WR_ERRATA ;# Bit 29 must be 1 when prog set pllar_val [expr {$pllar_val | $::AT91_PMC_OUT}] set pllar_val [expr {$pllar_val | $::AT91_PMC_PLLCOUNT}] set pllar_val [expr {$pllar_val | ($config(master_pll_mul) - 1) << 16}] set pllar_val [expr {$pllar_val | $config(master_pll_div)}] mww $::AT91_CKGR_PLLAR $pllar_val ;# CKGR_PLLA - (18.432MHz/13)*141 = 199.9 MHz while { [expr {[mrw $::AT91_PMC_SR] & $::AT91_PMC_LOCKA}] != $::AT91_PMC_LOCKA } { sleep 1 } ;# PCK/2 = MCK Master Clock from PLLA set mckr_val $::AT91_PMC_CSS_PLLA set mckr_val [expr {$mckr_val | $::AT91_PMC_PRES_1}] set mckr_val [expr {$mckr_val | $::AT91SAM9_PMC_MDIV_2}] set mckr_val [expr {$mckr_val | $::AT91_PMC_PDIV_1}] mww $::AT91_PMC_MCKR $mckr_val ;# PMC_MCKR (MCLK: 0x102 - (CLK/2)MHZ, 0x202 - (CLK/3)MHz) while { [expr {[mrw $::AT91_PMC_SR] & $::AT91_PMC_MCKRDY}] != $::AT91_PMC_MCKRDY } { sleep 1 } ## switch JTAG clock to highspeed clock jtag_rclk 0 arm7_9 dcc_downloads enable ;# Enable faster DCC downloads arm7_9 fast_memory_access enable set rstc_mr_val $::AT91_RSTC_KEY set rstc_mr_val [expr {$rstc_mr_val | $::AT91_RSTC_URSTEN}] mww $::AT91_RSTC_MR $rstc_mr_val ;# user reset enable if { [info exists config(sdram_piod)] } { set pdr_addr [expr {$::AT91_PIOD + $::PIO_PDR}] set pudr_addr [expr {$::AT91_PIOD + $::PIO_PUDR}] set asr_addr [expr {$::AT91_PIOD + $::PIO_ASR}] mww $pdr_addr 0xffff0000 ;# define PDC[31:16] as DATA[31:16] mww $pudr_addr 0xffff0000 ;# no pull-up for D[31:16] mww $asr_addr 0xffff0000 } else { set pdr_addr [expr {$::AT91_PIOC + $::PIO_PDR}] set pudr_addr [expr {$::AT91_PIOC + $::PIO_PUDR}] mww $pdr_addr 0xffff0000 ;# define PDC[31:16] as DATA[31:16] mww $pudr_addr 0xffff0000 ;# no pull-up for D[31:16] } mww $config(matrix_ebicsa_addr) $config(matrix_ebicsa_val) mww $::AT91_SDRAMC_MR $::AT91_SDRAMC_MODE_NORMAL ;# SDRAMC_MR Mode register mww $::AT91_SDRAMC_TR $config(sdram_tr_val) ;# SDRAMC_TR - Refresh Timer register mww $::AT91_SDRAMC_CR $config(sdram_cr_val) ;# SDRAMC_CR - Configuration register mww $::AT91_SDRAMC_MDR $::AT91_SDRAMC_MD_SDRAM ;# Memory Device Register -> SDRAM mww $::AT91_SDRAMC_MR $::AT91_SDRAMC_MODE_PRECHARGE ;# SDRAMC_MR mww $config(sdram_base) 0 ;# SDRAM_BASE mww $::AT91_SDRAMC_MR $::AT91_SDRAMC_MODE_REFRESH ;# SDRC_MR mww $config(sdram_base) 0 ;# SDRAM_BASE mww $config(sdram_base) 0 ;# SDRAM_BASE mww $config(sdram_base) 0 ;# SDRAM_BASE mww $config(sdram_base) 0 ;# SDRAM_BASE mww $config(sdram_base) 0 ;# SDRAM_BASE mww $config(sdram_base) 0 ;# SDRAM_BASE mww $config(sdram_base) 0 ;# SDRAM_BASE mww $config(sdram_base) 0 ;# SDRAM_BASE mww $::AT91_SDRAMC_MR $::AT91_SDRAMC_MODE_LMR ;# SDRC_MR mww $config(sdram_base) 0 ;# SDRAM_BASE mww $::AT91_SDRAMC_MR $::AT91_SDRAMC_MODE_NORMAL ;# SDRC_MR mww $config(sdram_base) 0 ;# SDRAM_BASE mww $::AT91_SDRAMC_TR 1200 ;# SDRAM_TR mww $config(sdram_base) 0 ;# SDRAM_BASE mww $::AT91_MATRIX 0xf ;# MATRIX_MCFG - REMAP all masters } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/at91sam9_sdramc.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # SDRAM Controller (SDRAMC) registers set AT91_SDRAMC_MR [expr {$AT91_SDRAMC + 0x00}] ;# SDRAM Controller Mode Register set AT91_SDRAMC_MODE [expr {0xf << 0}] ;# Command Mode set AT91_SDRAMC_MODE_NORMAL 0 set AT91_SDRAMC_MODE_NOP 1 set AT91_SDRAMC_MODE_PRECHARGE 2 set AT91_SDRAMC_MODE_LMR 3 set AT91_SDRAMC_MODE_REFRESH 4 set AT91_SDRAMC_MODE_EXT_LMR 5 set AT91_SDRAMC_MODE_DEEP 6 set AT91_SDRAMC_TR [expr {$AT91_SDRAMC + 0x04}] ;# SDRAM Controller Refresh Timer Register set AT91_SDRAMC_COUNT [expr {0xfff << 0}] ;# Refresh Timer Counter set AT91_SDRAMC_CR [expr {$AT91_SDRAMC + 0x08}] ;# SDRAM Controller Configuration Register set AT91_SDRAMC_NC [expr {3 << 0}] ;# Number of Column Bits set AT91_SDRAMC_NC_8 [expr {0 << 0}] set AT91_SDRAMC_NC_9 [expr {1 << 0}] set AT91_SDRAMC_NC_10 [expr {2 << 0}] set AT91_SDRAMC_NC_11 [expr {3 << 0}] set AT91_SDRAMC_NR [expr {3 << 2}] ;# Number of Row Bits set AT91_SDRAMC_NR_11 [expr {0 << 2}] set AT91_SDRAMC_NR_12 [expr {1 << 2}] set AT91_SDRAMC_NR_13 [expr {2 << 2}] set AT91_SDRAMC_NB [expr {1 << 4}] ;# Number of Banks set AT91_SDRAMC_NB_2 [expr {0 << 4}] set AT91_SDRAMC_NB_4 [expr {1 << 4}] set AT91_SDRAMC_CAS [expr {3 << 5}] ;# CAS Latency set AT91_SDRAMC_CAS_1 [expr {1 << 5}] set AT91_SDRAMC_CAS_2 [expr {2 << 5}] set AT91_SDRAMC_CAS_3 [expr {3 << 5}] set AT91_SDRAMC_DBW [expr {1 << 7}] ;# Data Bus Width set AT91_SDRAMC_DBW_32 [expr {0 << 7}] set AT91_SDRAMC_DBW_16 [expr {1 << 7}] set AT91_SDRAMC_TWR [expr {0xf << 8}] ;# Write Recovery Delay set AT91_SDRAMC_TRC [expr {0xf << 12}] ;# Row Cycle Delay set AT91_SDRAMC_TRP [expr {0xf << 16}] ;# Row Precharge Delay set AT91_SDRAMC_TRCD [expr {0xf << 20}] ;# Row to Column Delay set AT91_SDRAMC_TRAS [expr {0xf << 24}] ;# Active to Precharge Delay set AT91_SDRAMC_TXSR [expr {0xf << 28}] ;# Exit Self Refresh to Active Delay set AT91_SDRAMC_LPR [expr {$AT91_SDRAMC + 0x10}] ;# SDRAM Controller Low Power Register set AT91_SDRAMC_LPCB [expr {3 << 0}] ;# Low-power Configurations set AT91_SDRAMC_LPCB_DISABLE 0 set AT91_SDRAMC_LPCB_SELF_REFRESH 1 set AT91_SDRAMC_LPCB_POWER_DOWN 2 set AT91_SDRAMC_LPCB_DEEP_POWER_DOWN 3 set AT91_SDRAMC_PASR [expr {7 << 4}] ;# Partial Array Self Refresh set AT91_SDRAMC_TCSR [expr {3 << 8}] ;# Temperature Compensated Self Refresh set AT91_SDRAMC_DS [expr {3 << 10}] ;# Drive Strength set AT91_SDRAMC_TIMEOUT [expr {3 << 12}] ;# Time to define when Low Power Mode is enabled set AT91_SDRAMC_TIMEOUT_0_CLK_CYCLES [expr {0 << 12}] set AT91_SDRAMC_TIMEOUT_64_CLK_CYCLES [expr {1 << 12}] set AT91_SDRAMC_TIMEOUT_128_CLK_CYCLES [expr {2 << 12}] set AT91_SDRAMC_IER [expr {$AT91_SDRAMC + 0x14}] ;# SDRAM Controller Interrupt Enable Register set AT91_SDRAMC_IDR [expr {$AT91_SDRAMC + 0x18}] ;# SDRAM Controller Interrupt Disable Register set AT91_SDRAMC_IMR [expr {$AT91_SDRAMC + 0x1C}] ;# SDRAM Controller Interrupt Mask Register set AT91_SDRAMC_ISR [expr {$AT91_SDRAMC + 0x20}] ;# SDRAM Controller Interrupt Status Register set AT91_SDRAMC_RES [expr {1 << 0}] ;# Refresh Error Status set AT91_SDRAMC_MDR [expr {$AT91_SDRAMC + 0x24}] ;# SDRAM Memory Device Register set AT91_SDRAMC_MD [expr {3 << 0}] ;# Memory Device Type set AT91_SDRAMC_MD_SDRAM 0 set AT91_SDRAMC_MD_LOW_POWER_SDRAM 1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/at91sam9_smc.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set AT91_SMC_READMODE [expr {1 << 0}] ;# Read Mode set AT91_SMC_WRITEMODE [expr {1 << 1}] ;# Write Mode set AT91_SMC_EXNWMODE [expr {3 << 4}] ;# NWAIT Mode set AT91_SMC_EXNWMODE_DISABLE [expr {0 << 4}] set AT91_SMC_EXNWMODE_FROZEN [expr {2 << 4}] set AT91_SMC_EXNWMODE_READY [expr {3 << 4}] set AT91_SMC_BAT [expr {1 << 8}] ;# Byte Access Type set AT91_SMC_BAT_SELECT [expr {0 << 8}] set AT91_SMC_BAT_WRITE [expr {1 << 8}] set AT91_SMC_DBW [expr {3 << 12}] ;# Data Bus Width */ set AT91_SMC_DBW_8 [expr {0 << 12}] set AT91_SMC_DBW_16 [expr {1 << 12}] set AT91_SMC_DBW_32 [expr {2 << 12}] set AT91_SMC_TDFMODE [expr {1 << 20}] ;# TDF Optimization - Enabled set AT91_SMC_PMEN [expr {1 << 24}] ;# Page Mode Enabled set AT91_SMC_PS [expr {3 << 28}] ;# Page Size set AT91_SMC_PS_4 [expr {0 << 28}] set AT91_SMC_PS_8 [expr {1 << 28}] set AT91_SMC_PS_16 [expr {2 << 28}] set AT91_SMC_PS_32 [expr {3 << 28}] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/hardware.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # External Memory Map set AT91_CHIPSELECT_0 0x10000000 set AT91_CHIPSELECT_1 0x20000000 set AT91_CHIPSELECT_2 0x30000000 set AT91_CHIPSELECT_3 0x40000000 set AT91_CHIPSELECT_4 0x50000000 set AT91_CHIPSELECT_5 0x60000000 set AT91_CHIPSELECT_6 0x70000000 set AT91_CHIPSELECT_7 0x80000000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/pmc.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if [info exists AT91C_MAINOSC_FREQ] { # user set this... let it be. } { # 18.432mhz is a common thing... set AT91C_MAINOSC_FREQ 18432000 } global AT91C_MAINOSC_FREQ if [info exists AT91C_SLOWOSC_FREQ] { # user set this... let it be. } { # 32khz is the norm set AT91C_SLOWOSC_FREQ 32768 } global AT91C_SLOWOSC_FREQ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/rtt.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set RTTC_RTMR [expr {$AT91C_BASE_RTTC + 0x00}] set RTTC_RTAR [expr {$AT91C_BASE_RTTC + 0x04}] set RTTC_RTVR [expr {$AT91C_BASE_RTTC + 0x08}] set RTTC_RTSR [expr {$AT91C_BASE_RTTC + 0x0c}] global RTTC_RTMR global RTTC_RTAR global RTTC_RTVR global RTTC_RTSR proc show_RTTC_RTMR_helper { NAME ADDR VAL } { set rtpres [expr {$VAL & 0x0ffff}] global BIT16 BIT17 if { $rtpres == 0 } { set rtpres 65536; } global AT91C_SLOWOSC_FREQ # Nasty hack, make this a float by tacking a .0 on the end # otherwise, jim makes the value an integer set f [expr "$AT91C_SLOWOSC_FREQ.0 / $rtpres.0"] echo [format "\tPrescale value: 0x%04x (%5d) => %f Hz" $rtpres $rtpres $f] if { $VAL & $BIT16 } { echo "\tBit16 -> Alarm IRQ Enabled" } else { echo "\tBit16 -> Alarm IRQ Disabled" } if { $VAL & $BIT17 } { echo "\tBit17 -> RTC Inc IRQ Enabled" } else { echo "\tBit17 -> RTC Inc IRQ Disabled" } # Bit 18 is write only. } proc show_RTTC_RTSR_helper { NAME ADDR VAL } { global BIT0 BIT1 if { $VAL & $BIT0 } { echo "\tBit0 -> ALARM PENDING" } else { echo "\tBit0 -> alarm not pending" } if { $VAL & $BIT1 } { echo "\tBit0 -> RTINC PENDING" } else { echo "\tBit0 -> rtinc not pending" } } proc show_RTTC { } { show_mmr32_reg RTTC_RTMR show_mmr32_reg RTTC_RTAR show_mmr32_reg RTTC_RTVR show_mmr32_reg RTTC_RTSR } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/sam9_smc.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Setup register # # ncs_read_setup # nrd_setup # ncs_write_setup # set nwe_setup # # # Pulse register # # ncs_read_pulse # nrd_pulse # ncs_write_pulse # nwe_pulse # # # Cycle register # # read_cycle 0 # write_cycle 0 # # # Mode register # # mode # tdf_cycles proc sam9_smc_config { cs smc_config } { ;# Setup Register for CS n set AT91_SMC_SETUP [expr {$::AT91_SMC + 0x00 + $cs * 0x10}] set val [expr {$smc_config(nwe_setup) << 0}] set val [expr {$val | $smc_config(ncs_write_setup) << 8}] set val [expr {$val | $smc_config(nrd_setup)) << 16}] set val [expr {$val | $smc_config(ncs_read_setup) << 24}] mww $AT91_SMC_SETUP $val ;# Pulse Register for CS n set AT91_SMC_PULSE [expr {$::AT91_SMC + 0x04 + $cs * 0x10}] set val [expr {$smc_config(nwe_pulse) << 0}] set val [expr {$val | $smc_config(ncs_write_pulse) << 8}] set val [expr {$val | $smc_config(nrd_pulse) << 16}] set val [expr {$val | $smc_config(ncs_read_pulse) << 24}] mww $AT91_SMC_PULSE $val ;# Cycle Register for CS n set AT91_SMC_CYCLE [expr {$::AT91_SMC + 0x08 + $cs * 0x10}] set val [expr {$smc_config(write_cycle) << 0}] set val [expr {$val | $smc_config(read_cycle) << 16}] mww $AT91_SMC_CYCLE $val ;# Mode Register for CS n set AT91_SMC_MODE [expr {$::AT91_SMC + 0x0c + $cs * 0x10}] set val [expr {$smc_config(mode) << 0}] set val [expr {$val | $smc_config(tdf_cycles) << 16}] mww $AT91_SMC_MODE $val } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/atmel/at91/usarts.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # the DBGU and USARTs are 'almost' indentical' set DBGU_CR [expr {$AT91C_BASE_DBGU + 0x00000000}] set DBGU_MR [expr {$AT91C_BASE_DBGU + 0x00000004}] set DBGU_IER [expr {$AT91C_BASE_DBGU + 0x00000008}] set DBGU_IDR [expr {$AT91C_BASE_DBGU + 0x0000000C}] set DBGU_IMR [expr {$AT91C_BASE_DBGU + 0x00000010}] set DBGU_CSR [expr {$AT91C_BASE_DBGU + 0x00000014}] set DBGU_RHR [expr {$AT91C_BASE_DBGU + 0x00000018}] set DBGU_THR [expr {$AT91C_BASE_DBGU + 0x0000001C}] set DBGU_BRGR [expr {$AT91C_BASE_DBGU + 0x00000020}] # no RTOR # no TTGR # no FIDI # no NER set DBGU_CIDR [expr {$AT91C_BASE_DBGU + 0x00000040}] set DBGU_EXID [expr {$AT91C_BASE_DBGU + 0x00000044}] set DBGU_FNTR [expr {$AT91C_BASE_DBGU + 0x00000048}] set USx_CR 0x00000000 set USx_MR 0x00000004 set USx_IER 0x00000008 set USx_IDR 0x0000000C set USx_IMR 0x00000010 set USx_CSR 0x00000014 set USx_RHR 0x00000018 set USx_THR 0x0000001C set USx_BRGR 0x00000020 set USx_RTOR 0x00000024 set USx_TTGR 0x00000028 set USx_FIDI 0x00000040 set USx_NER 0x00000044 set USx_IF 0x0000004C # Create all the uarts that exist.. # we blow up if there are >9 proc show_mmr_USx_MR_helper { NAME ADDR VAL } { # First - just print it set x [show_normalize_bitfield $VAL 3 0] if { $x == 0 } { echo "\tNormal operation" } else { echo [format "\tNon Normal operation mode: 0x%02x" $x] } set x [show_normalize_bitfield $VAL 11 9] set s "unknown" switch -exact $x { 0 { set s "Even" } 1 { set s "Odd" } 2 { set s "Force=0" } 3 { set s "Force=1" } * { set $x [expr {$x & 6}] switch -exact $x { 4 { set s "None" } 6 { set s "Multidrop Mode" } } } } echo [format "\tParity: %s " $s] set x [expr {5 + [show_normalize_bitfield $VAL 7 6]}] echo [format "\tDatabits: %d" $x] set x [show_normalize_bitfield $VAL 13 12] switch -exact $x { 0 { echo "\tStop bits: 1" } 1 { echo "\tStop bits: 1.5" } 2 { echo "\tStop bits: 2" } 3 { echo "\tStop bits: Illegal/Reserved" } } } # For every possbile usart... foreach WHO { US0 US1 US2 US3 US4 US5 US6 US7 US8 US9 } { set n AT91C_BASE_[set WHO] set str "" # Only if it exists on the chip if [ info exists $n ] { # Hence: $n - is like AT91C_BASE_USx # For every sub-register foreach REG {CR MR IER IDR IMR CSR RHR THR BRGR RTOR TTGR FIDI NER IF} { # vn = variable name set vn [set WHO]_[set REG] # vn = USx_IER # vv = variable value set vv [expr "$$n + [set USx_[set REG]]"] # And VV is the address in memory of that register # make that VN a GLOBAL so others can find it global $vn set $vn $vv # Create a command for this specific register. proc show_$vn { } "show_mmr32_reg $vn" # Add this command to the Device(as a whole) command set str "$str\nshow_$vn" } # Now - create the DEVICE(as a whole) command set fn show_$WHO proc $fn { } $str } } # The Debug Uart is special.. set str "" # For every sub-register foreach REG {DBGU_CR DBGU_MR DBGU_IER DBGU_IDR DBGU_IMR DBGU_CSR DBGU_RHR DBGU_THR DBGU_BRGR DBGU_CIDR DBGU_EXID DBGU_FNTR} { # Create a command for this specific register. proc show_$REG { } "show_mmr32_reg $REG" # Add this command to the Device(as a whole) command set str "$str\nshow_$REG" } # Now - create the DEVICE(as a whole) command proc show_DBGU { } $str unset str proc show_DBGU_MR_helper { NAME ADDR VAL } { show_mmr_USx_MR_helper $NAME $ADDR $VAL } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/st/spear/quirk_no_srst.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Quirks to bypass missing SRST on JTAG connector # EVALSPEAr310 Rev. 2.0 # http://www.st.com/spear # # Date: 2010-08-17 # Author: Antonio Borneo <borneo.antonio@gmail.com> # For boards that have JTAG SRST not connected. # We use "arm9 vector_catch reset" to catch button reset event. $_TARGETNAME configure -event reset-assert sp_reset_assert $_TARGETNAME configure -event reset-deassert-post sp_reset_deassert_post # keeps the name of the SPEAr target global sp_target_name set sp_target_name $_TARGETNAME # Keeps the argument of "reset" command (run, init, halt). global sp_reset_mode set sp_reset_mode "" # Helper procedure. Returns 0 is target is halted. proc sp_is_halted {} { global sp_target_name return [expr {[string compare [$sp_target_name curstate] "halted" ] == 0}] } # wait for reset button to be pressed, causing CPU to get halted proc sp_reset_deassert_post {} { global sp_reset_mode set bar(0) | set bar(1) / set bar(2) - set bar(3) \\ poll on echo "====> Press reset button on the board <====" for {set i 0} { [sp_is_halted] == 0 } { set i [expr {$i + 1}]} { echo -n "$bar([expr {$i & 3}])\r" sleep 200 } # Remove catch reset event arm9 vector_catch none # CPU is halted, but we typed "reset run" ... if { [string compare $sp_reset_mode "run"] == 0 } { resume } } # Override reset-assert, since no SRST available # Catch reset event proc sp_reset_assert {} { arm9 vector_catch reset } # Override default init_reset{mode} to catch parameter "mode" proc init_reset {mode} { global sp_reset_mode set sp_reset_mode $mode # We need to detect CPU get halted, so exit from halt if { [sp_is_halted] } { echo "Resuming CPU to detect reset" resume } # Execute default init_reset{mode} jtag arp_init-reset } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/st/spear/spear3xx.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Generic init scripts for all ST SPEAr3xx family # http://www.st.com/spear # # Date: 2010-09-23 # Author: Antonio Borneo <borneo.antonio@gmail.com> # Initialize internal clock # Default: # - Crystal = 24 MHz # - PLL1 = 332 MHz # - PLL2 = 332 MHz # - CPU_CLK = 332 MHz # - DDR_CLK = 332 MHz async # - HCLK = 166 MHz # - PCLK = 83 MHz proc sp3xx_clock_default {} { mww 0xfca00000 0x00000002 ;# set sysclk slow mww 0xfca00014 0x0ffffff8 ;# set pll timeout to minimum (100us ?!?) # DDRCORE disable to change frequency set val [expr {([mrw 0xfca8002c] & ~0x20000000) | 0x40000000}] mww 0xfca8002c $val mww 0xfca8002c $val ;# Yes, write twice! # programming PLL1 mww 0xfca8000c 0xa600010c ;# M=166 P=1 N=12 mww 0xfca80008 0x00001c0a ;# power down mww 0xfca80008 0x00001c0e ;# enable mww 0xfca80008 0x00001c06 ;# strobe mww 0xfca80008 0x00001c0e while { [expr {[mrw 0xfca80008] & 0x01}] == 0x00 } { sleep 1 } # programming PLL2 mww 0xfca80018 0xa600010c ;# M=166, P=1, N=12 mww 0xfca80014 0x00001c0a ;# power down mww 0xfca80014 0x00001c0e ;# enable mww 0xfca80014 0x00001c06 ;# strobe mww 0xfca80014 0x00001c0e while { [expr {[mrw 0xfca80014] & 0x01}] == 0x00 } { sleep 1 } mww 0xfca80028 0x00000082 ;# enable plltimeen mww 0xfca80024 0x00000511 ;# set hclkdiv="/2" & pclkdiv="/2" mww 0xfca00000 0x00000004 ;# setting SYSCTL to NORMAL mode while { [expr {[mrw 0xfca00000] & 0x20}] != 0x20 } { sleep 1 } # Select source of DDR clock #mmw 0xfca80020 0x10000000 0x70000000 ;# PLL1 mmw 0xfca80020 0x30000000 0x70000000 ;# PLL2 # DDRCORE enable after change frequency mmw 0xfca8002c 0x20000000 0x00000000 } proc sp3xx_common_init {} { mww 0xfca8002c 0xfffffff8 ;# enable clock of all peripherals mww 0xfca80038 0x00000000 ;# remove reset of all peripherals mww 0xfca80034 0x0000ffff ;# enable all RAS clocks mww 0xfca80040 0x00000000 ;# remove all RAS resets mww 0xfca800e4 0x78000008 ;# COMP1V8_REG mww 0xfca800ec 0x78000008 ;# COMP3V3_REG mww 0xfc000000 0x10000f5f ;# init SMI and set HW mode mww 0xfc000000 0x00000f5f # Initialize Bus Interconnection Matrix # All ports Round-Robin and lowest priority mww 0xfca8007c 0x80000007 mww 0xfca80080 0x80000007 mww 0xfca80084 0x80000007 mww 0xfca80088 0x80000007 mww 0xfca8008c 0x80000007 mww 0xfca80090 0x80000007 mww 0xfca80094 0x80000007 mww 0xfca80098 0x80000007 mww 0xfca8009c 0x80000007 } # Specific init scripts for ST SPEAr300 proc sp300_init {} { mww 0x99000000 0x00003fff ;# RAS function enable } # Specific init scripts for ST SPEAr310 proc sp310_init {} { mww 0xb4000008 0x00002ff4 ;# RAS function enable mww 0xfca80050 0x00000001 ;# Enable clk mem port 1 mww 0xfca8013c 0x2f7bc210 ;# plgpio_pad_drv mww 0xfca80140 0x017bdef6 } proc sp310_emi_init {} { # set EMI pad strength mmw 0xfca80134 0x0e000000 0x00000000 mmw 0xfca80138 0x0e739ce7 0x00000000 mmw 0xfca8013c 0x00039ce7 0x00000000 # set safe EMI timing as in BootROM #mww 0x4f000000 0x0000000f ;# tAP_0_reg #mww 0x4f000004 0x00000000 ;# tSDP_0_reg #mww 0x4f000008 0x000000ff ;# tDPw_0_reg #mww 0x4f00000c 0x00000111 ;# tDPr_0_reg #mww 0x4f000010 0x00000002 ;# tDCS_0_reg # set fast EMI timing as in Linux mww 0x4f000000 0x00000010 ;# tAP_0_reg mww 0x4f000004 0x00000005 ;# tSDP_0_reg mww 0x4f000008 0x0000000a ;# tDPw_0_reg mww 0x4f00000c 0x0000000a ;# tDPr_0_reg mww 0x4f000010 0x00000005 ;# tDCS_0_re # 32bit wide, 8/16/32bit access mww 0x4f000014 0x0000000e ;# control_0_reg mww 0x4f000094 0x0000003f ;# ack_reg } # Specific init scripts for ST SPEAr320 proc sp320_init {} { mww 0xb300000c 0xffffac04 ;# RAS function enable mww 0xb3000010 0x00000001 ;# RAS mode select } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/st/spear/spear3xx_ddr.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Init scripts to configure DDR controller of SPEAr3xx # http://www.st.com/spear # Original values taken from XLoader source code # # Date: 2010-09-23 # Author: Antonio Borneo <borneo.antonio@gmail.com> proc sp3xx_ddr_init {ddr_type {ddr_chips 1}} { if { $ddr_chips != 1 && $ddr_chips != 2 } { error "Only 1 or 2 DDR chips permitted. Wrong value "$ddr_chips } if { $ddr_type == "mt47h64m16_3_333_cl5_async" } { ddr_spr3xx_mt47h64m16_3_333_cl5_async $ddr_chips set ddr_size 0x08000000 ## add here new DDR chip definition. Prototype: #} elseif { $ddr_type == "?????" } { # ????? $ddr_chips # set ddr_size 0x????? } else { error "sp3xx_ddr_init: unrecognized DDR type "$ddr_type } # MPMC START mww 0xfc60001c 0x01000100 if { $ddr_chips == 2 } { echo [format \ "Double chip DDR memory. Total memory size 0x%08x byte" \ [expr {2 * $ddr_size}]] } else { echo [format \ "Single chip DDR memory. Memory size 0x%08x byte" \ $ddr_size] } } # from Xloader file ddr/spr300_mt47h64m16_3_333_cl5_async.S proc ddr_spr3xx_mt47h64m16_3_333_cl5_async {ddr_chips} { # DDR_PAD_REG mww 0xfca800f0 0x00003aa5 # Use "1:2 sync" only when DDR clock source is PLL1 and # HCLK is half of PLL1 mww 0xfc600000 0x00000001 ;# MEMCTL_AHB_SET_00 # This is async mww 0xfc600004 0x00000000 ;# MEMCTL_AHB_SET_01 # mww 0xfc600000 0x02020201 ;# MEMCTL_AHB_SET_00 # This is 1:2 sync # mww 0xfc600004 0x02020202 ;# MEMCTL_AHB_SET_01 mww 0xfc600008 0x01000000 ;# MEMCTL_RFSH_SET_00 mww 0xfc60000c 0x00000101 ;# MEMCTL_DLL_SET_00 mww 0xfc600010 0x00000101 ;# MEMCTL_GP_00 mww 0xfc600014 0x01000000 ;# MEMCTL_GP_01 mww 0xfc600018 0x00010001 ;# MEMCTL_GP_02 mww 0xfc60001c 0x00000100 ;# MEMCTL_GP_03 mww 0xfc600020 0x00010001 ;# MEMCTL_GP_04 if { $ddr_chips == 2 } { mww 0xfc600024 0x01020203 ;# MEMCTL_GP_05 mww 0xfc600028 0x01000102 ;# MEMCTL_GP_06 mww 0xfc60002c 0x02000202 ;# MEMCTL_AHB_SET_02 } else { mww 0xfc600024 0x00000201 ;# MEMCTL_GP_05 mww 0xfc600028 0x02000001 ;# MEMCTL_GP_06 mww 0xfc60002c 0x02000201 ;# MEMCTL_AHB_SET_02 } mww 0xfc600030 0x04040105 ;# MEMCTL_AHB_SET_03 mww 0xfc600034 0x03030302 ;# MEMCTL_AHB_SET_04 mww 0xfc600038 0x02040101 ;# MEMCTL_AHB_SET_05 mww 0xfc60003c 0x00000002 ;# MEMCTL_AHB_SET_06 mww 0xfc600044 0x03000405 ;# MEMCTL_DQS_SET_0 mww 0xfc600048 0x03040002 ;# MEMCTL_TIME_SET_01 mww 0xfc60004c 0x04000305 ;# MEMCTL_TIME_SET_02 mww 0xfc600050 0x0505053f ;# MEMCTL_AHB_RELPR_00 mww 0xfc600054 0x05050505 ;# MEMCTL_AHB_RELPR_01 mww 0xfc600058 0x04040405 ;# MEMCTL_AHB_RELPR_02 mww 0xfc60005c 0x04040404 ;# MEMCTL_AHB_RELPR_03 mww 0xfc600060 0x03030304 ;# MEMCTL_AHB_RELPR_04 mww 0xfc600064 0x03030303 ;# MEMCTL_AHB_RELPR_05 mww 0xfc600068 0x02020203 ;# MEMCTL_AHB_RELPR_06 mww 0xfc60006c 0x02020202 ;# MEMCTL_AHB_RELPR_07 mww 0xfc600070 0x01010102 ;# MEMCTL_AHB_RELPR_08 mww 0xfc600074 0x01010101 ;# MEMCTL_AHB_RELPR_09 mww 0xfc600078 0x00000001 ;# MEMCTL_AHB_RELPR_10 mww 0xfc600088 0x0a0c0a00 ;# MEMCTL_DQS_SET_1 mww 0xfc60008c 0x0000023f ;# MEMCTL_GP_07 mww 0xfc600090 0x00050a00 ;# MEMCTL_GP_08 mww 0xfc600094 0x11000000 ;# MEMCTL_GP_09 mww 0xfc600098 0x00001302 ;# MEMCTL_GP_10 mww 0xfc60009c 0x00001c1c ;# MEMCTL_DLL_SET_01 mww 0xfc6000a0 0x7c000000 ;# MEMCTL_DQS_OUT_SHIFT mww 0xfc6000a4 0x005c0000 ;# MEMCTL_WR_DQS_SHIFT mww 0xfc6000a8 0x2b050e00 ;# MEMCTL_TIME_SET_03 mww 0xfc6000ac 0x00640064 ;# MEMCTL_AHB_PRRLX_00 mww 0xfc6000b0 0x00640064 ;# MEMCTL_AHB_PRRLX_01 mww 0xfc6000b4 0x00000064 ;# MEMCTL_AHB_PRRLX_02 mww 0xfc6000b8 0x00000000 ;# MEMCTL_OUTRANGE_LGTH mww 0xfc6000bc 0x00200020 ;# MEMCTL_AHB_RW_SET_00 mww 0xfc6000c0 0x00200020 ;# MEMCTL_AHB_RW_SET_01 mww 0xfc6000c4 0x00200020 ;# MEMCTL_AHB_RW_SET_02 mww 0xfc6000c8 0x00200020 ;# MEMCTL_AHB_RW_SET_03 mww 0xfc6000cc 0x00200020 ;# MEMCTL_AHB_RW_SET_04 mww 0xfc6000d8 0x00000a24 ;# MEMCTL_TREF mww 0xfc6000dc 0x00000000 ;# MEMCTL_EMRS3_DATA mww 0xfc6000e0 0x5b1c00c8 ;# MEMCTL_TIME_SET_04 mww 0xfc6000e4 0x00c8002e ;# MEMCTL_TIME_SET_05 mww 0xfc6000e8 0x00000000 ;# MEMCTL_VERSION mww 0xfc6000ec 0x0001046b ;# MEMCTL_TINIT mww 0xfc6000f0 0x00000000 ;# MEMCTL_OUTRANGE_ADDR_01 mww 0xfc6000f4 0x00000000 ;# MEMCTL_OUTRANGE_ADDR_02 mww 0xfc600104 0x001c0000 ;# MEMCTL_DLL_DQS_DELAY_BYPASS_0 mww 0xfc600108 0x0019001c ;# MEMCTL_DLL_SET_02 mww 0xfc60010c 0x00100000 ;# MEMCTL_DLL_SET_03 mww 0xfc600110 0x001e007a ;# MEMCTL_DQS_SET_2 mww 0xfc600188 0x00000000 ;# MEMCTL_USER_DEF_REG_0 mww 0xfc60018c 0x00000000 ;# MEMCTL_USER_DEF_REG_1 mww 0xfc600190 0x01010001 ;# MEMCTL_GP_11 mww 0xfc600194 0x01000000 ;# MEMCTL_GP_12 mww 0xfc600198 0x00000001 ;# MEMCTL_GP_13 mww 0xfc60019c 0x00400000 ;# MEMCTL_GP_14 mww 0xfc6001a0 0x00000000 ;# MEMCTL_EMRS2_DATA_X mww 0xfc6001a4 0x00000000 ;# MEMCTL_LWPWR_CNT mww 0xfc6001a8 0x00000000 ;# MEMCTL_LWPWR_REG mww 0xfc6001ac 0x00860000 ;# MEMCTL_GP_15 mww 0xfc6001b0 0x00000002 ;# MEMCTL_TPDEX } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/st/stm32/stm32.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find bitsbytes.tcl] source [find cpu/arm/cortex_m3.tcl] source [find memory.tcl] source [find mmr_helpers.tcl] source [find chip/st/stm32/stm32_regs.tcl] source [find chip/st/stm32/stm32_rcc.tcl] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/st/stm32/stm32_rcc.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set RCC_CR [expr {$RCC_BASE + 0x00}] set RCC_CFGR [expr {$RCC_BASE + 0x04}] set RCC_CIR [expr {$RCC_BASE + 0x08}] set RCC_APB2RSTR [expr {$RCC_BASE + 0x0c}] set RCC_APB1RSTR [expr {$RCC_BASE + 0x10}] set RCC_AHBENR [expr {$RCC_BASE + 0x14}] set RCC_APB2ENR [expr {$RCC_BASE + 0x18}] set RCC_APB1ENR [expr {$RCC_BASE + 0x1c}] set RCC_BDCR [expr {$RCC_BASE + 0x20}] set RCC_CSR [expr {$RCC_BASE + 0x24}] proc show_RCC_CR { } { if [ catch { set val [show_mmr32_reg RCC_CR] } msg ] { error $msg } show_mmr_bitfield 0 0 $val HSI { OFF ON } show_mmr_bitfield 1 1 $val HSIRDY { NOTRDY RDY } show_mmr_bitfield 7 3 $val HSITRIM { _NUMBER_ } show_mmr_bitfield 15 8 $val HSICAL { _NUMBER_ } show_mmr_bitfield 16 16 $val HSEON { OFF ON } show_mmr_bitfield 17 17 $val HSERDY { NOTRDY RDY } show_mmr_bitfield 18 18 $val HSEBYP { NOTBYPASSED BYPASSED } show_mmr_bitfield 19 19 $val CSSON { OFF ON } show_mmr_bitfield 24 24 $val PLLON { OFF ON } show_mmr_bitfield 25 25 $val PLLRDY { NOTRDY RDY } } proc show_RCC_CFGR { } { if [ catch { set val [show_mmr32_reg RCC_CFGR] } msg ] { error $msg } show_mmr_bitfield 1 0 $val SW { HSI HSE PLL ILLEGAL } show_mmr_bitfield 3 2 $val SWS { HSI HSE PLL ILLEGAL } show_mmr_bitfield 7 4 $val HPRE { sysclk_div_1 sysclk_div_1 sysclk_div_1 sysclk_div_1 sysclk_div_1 sysclk_div_1 sysclk_div_1 sysclk_div_1 sysclk_div_2 sysclk_div_4 sysclk_div_8 sysclk_div_16 sysclk_div_64 sysclk_div_128 sysclk_div_256 sysclk_div_512 } show_mmr_bitfield 10 8 $val PPRE1 { hclk_div1 hclk_div1 hclk_div1 hclk_div1 hclk_div2 hclk_div4 hclk_div8 hclk_div16 } show_mmr_bitfield 13 11 $val PPRE2 { hclk_div1 hclk_div1 hclk_div1 hclk_div1 hclk_div2 hclk_div4 hclk_div8 hclk_div16 } show_mmr_bitfield 15 14 $val ADCPRE { pclk2_div1 pclk2_div1 pclk2_div1 pclk2_div1 pclk2_div2 pclk2_div4 pclk2_div8 pclk2_div16 } show_mmr_bitfield 16 16 $val PLLSRC { HSI_div_2 HSE } show_mmr_bitfield 17 17 $val PLLXTPRE { hse_div1 hse_div2 } show_mmr_bitfield 21 18 $val PLLMUL { x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 x16 } show_mmr_bitfield 22 22 $val USBPRE { div1 div1_5 } show_mmr_bitfield 26 24 $val MCO { none none none none SysClk HSI HSE PLL_div2 } } proc show_RCC_CIR { } { if [ catch { set val [show_mmr32_reg RCC_CIR] } msg ] { error $msg } } proc show_RCC_APB2RSTR { } { if [ catch { set val [ show_mmr32_reg RCC_APB2RSTR] } msg ] { error $msg } for { set x 0 } { $x < 32 } { incr x } { set bits($x) xxx } set bits(15) adc3 set bits(14) usart1 set bits(13) tim8 set bits(12) spi1 set bits(11) tim1 set bits(10) adc2 set bits(9) adc1 set bits(8) iopg set bits(7) iopf set bits(6) iope set bits(5) iopd set bits(4) iopc set bits(3) iopb set bits(2) iopa set bits(1) xxx set bits(0) afio show_mmr32_bits bits $val } proc show_RCC_APB1RSTR { } { if [ catch { set val [ show_mmr32_reg RCC_APB1RSTR] } msg ] { error $msg } set bits(31) xxx set bits(30) xxx set bits(29) dac set bits(28) pwr set bits(27) bkp set bits(26) xxx set bits(25) can set bits(24) xxx set bits(23) usb set bits(22) i2c2 set bits(21) i2c1 set bits(20) uart5 set bits(19) uart4 set bits(18) uart3 set bits(17) uart2 set bits(16) xxx set bits(15) spi3 set bits(14) spi2 set bits(13) xxx set bits(12) xxx set bits(11) wwdg set bits(10) xxx set bits(9) xxx set bits(8) xxx set bits(7) xxx set bits(6) xxx set bits(5) tim7 set bits(4) tim6 set bits(3) tim5 set bits(2) tim4 set bits(1) tim3 set bits(0) tim2 show_mmr32_bits bits $val } proc show_RCC_AHBENR { } { if [ catch { set val [ show_mmr32_reg RCC_AHBENR ] } msg ] { error $msg } set bits(31) xxx set bits(30) xxx set bits(29) xxx set bits(28) xxx set bits(27) xxx set bits(26) xxx set bits(25) xxx set bits(24) xxx set bits(23) xxx set bits(22) xxx set bits(21) xxx set bits(20) xxx set bits(19) xxx set bits(18) xxx set bits(17) xxx set bits(16) xxx set bits(15) xxx set bits(14) xxx set bits(13) xxx set bits(12) xxx set bits(11) xxx set bits(10) sdio set bits(9) xxx set bits(8) fsmc set bits(7) xxx set bits(6) crce set bits(5) xxx set bits(4) flitf set bits(3) xxx set bits(2) sram set bits(1) dma2 set bits(0) dma1 show_mmr32_bits bits $val } proc show_RCC_APB2ENR { } { if [ catch { set val [ show_mmr32_reg RCC_APB2ENR ] } msg ] { error $msg } set bits(31) xxx set bits(30) xxx set bits(29) xxx set bits(28) xxx set bits(27) xxx set bits(26) xxx set bits(25) xxx set bits(24) xxx set bits(23) xxx set bits(22) xxx set bits(21) xxx set bits(20) xxx set bits(19) xxx set bits(18) xxx set bits(17) xxx set bits(16) xxx set bits(15) adc3 set bits(14) usart1 set bits(13) tim8 set bits(12) spi1 set bits(11) tim1 set bits(10) adc2 set bits(9) adc1 set bits(8) iopg set bits(7) iopf set bits(6) iope set bits(5) iopd set bits(4) iopc set bits(3) iopb set bits(2) iopa set bits(1) xxx set bits(0) afio show_mmr32_bits bits $val } proc show_RCC_APB1ENR { } { if [ catch { set val [ show_mmr32_reg RCC_APB1ENR ] } msg ] { error $msg } set bits(31) xxx set bits(30) xxx set bits(29) dac set bits(28) pwr set bits(27) bkp set bits(26) xxx set bits(25) can set bits(24) xxx set bits(23) usb set bits(22) i2c2 set bits(21) i2c1 set bits(20) usart5 set bits(19) usart4 set bits(18) usart3 set bits(17) usart2 set bits(16) xxx set bits(15) spi3 set bits(14) spi2 set bits(13) xxx set bits(12) xxx set bits(11) wwdg set bits(10) xxx set bits(9) xxx set bits(8) xxx set bits(7) xxx set bits(6) xxx set bits(5) tim7 set bits(4) tim6 set bits(3) tim5 set bits(2) tim4 set bits(1) tim3 set bits(0) tim2 show_mmr32_bits bits $val } proc show_RCC_BDCR { } { if [ catch { set val [ show_mmr32_reg RCC_BDCR ] } msg ] { error $msg } for { set x 0 } { $x < 32 } { incr x } { set bits($x) xxx } set bits(0) lseon set bits(1) lserdy set bits(2) lsebyp set bits(8) rtcsel0 set bits(9) rtcsel1 set bits(15) rtcen set bits(16) bdrst show_mmr32_bits bits $val } proc show_RCC_CSR { } { if [ catch { set val [ show_mmr32_reg RCC_CSR ] } msg ] { error $msg } for { set x 0 } { $x < 32 } { incr x } { set bits($x) xxx } set bits(0) lsion set bits(1) lsirdy set bits(24) rmvf set bits(26) pin set bits(27) por set bits(28) sft set bits(29) iwdg set bits(30) wwdg set bits(31) lpwr show_mmr32_bits bits $val } proc show_RCC { } { show_RCC_CR show_RCC_CFGR show_RCC_CIR show_RCC_APB2RSTR show_RCC_APB1RSTR show_RCC_AHBENR show_RCC_APB2ENR show_RCC_APB1ENR show_RCC_BDCR show_RCC_CSR } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/st/stm32/stm32_regs.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # /* Peripheral and SRAM base address in the alias region */ set PERIPH_BB_BASE 0x42000000 set SRAM_BB_BASE 0x22000000 # /*Peripheral and SRAM base address in the bit-band region */ set SRAM_BASE 0x20000000 set PERIPH_BASE 0x40000000 # /*FSMC registers base address */ set FSMC_R_BASE 0xA0000000 # /*Peripheral memory map */ set APB1PERIPH_BASE [set PERIPH_BASE] set APB2PERIPH_BASE [expr {$PERIPH_BASE + 0x10000}] set AHBPERIPH_BASE [expr {$PERIPH_BASE + 0x20000}] set TIM2_BASE [expr {$APB1PERIPH_BASE + 0x0000}] set TIM3_BASE [expr {$APB1PERIPH_BASE + 0x0400}] set TIM4_BASE [expr {$APB1PERIPH_BASE + 0x0800}] set TIM5_BASE [expr {$APB1PERIPH_BASE + 0x0C00}] set TIM6_BASE [expr {$APB1PERIPH_BASE + 0x1000}] set TIM7_BASE [expr {$APB1PERIPH_BASE + 0x1400}] set RTC_BASE [expr {$APB1PERIPH_BASE + 0x2800}] set WWDG_BASE [expr {$APB1PERIPH_BASE + 0x2C00}] set IWDG_BASE [expr {$APB1PERIPH_BASE + 0x3000}] set SPI2_BASE [expr {$APB1PERIPH_BASE + 0x3800}] set SPI3_BASE [expr {$APB1PERIPH_BASE + 0x3C00}] set USART2_BASE [expr {$APB1PERIPH_BASE + 0x4400}] set USART3_BASE [expr {$APB1PERIPH_BASE + 0x4800}] set UART4_BASE [expr {$APB1PERIPH_BASE + 0x4C00}] set UART5_BASE [expr {$APB1PERIPH_BASE + 0x5000}] set I2C1_BASE [expr {$APB1PERIPH_BASE + 0x5400}] set I2C2_BASE [expr {$APB1PERIPH_BASE + 0x5800}] set CAN_BASE [expr {$APB1PERIPH_BASE + 0x6400}] set BKP_BASE [expr {$APB1PERIPH_BASE + 0x6C00}] set PWR_BASE [expr {$APB1PERIPH_BASE + 0x7000}] set DAC_BASE [expr {$APB1PERIPH_BASE + 0x7400}] set AFIO_BASE [expr {$APB2PERIPH_BASE + 0x0000}] set EXTI_BASE [expr {$APB2PERIPH_BASE + 0x0400}] set GPIOA_BASE [expr {$APB2PERIPH_BASE + 0x0800}] set GPIOB_BASE [expr {$APB2PERIPH_BASE + 0x0C00}] set GPIOC_BASE [expr {$APB2PERIPH_BASE + 0x1000}] set GPIOD_BASE [expr {$APB2PERIPH_BASE + 0x1400}] set GPIOE_BASE [expr {$APB2PERIPH_BASE + 0x1800}] set GPIOF_BASE [expr {$APB2PERIPH_BASE + 0x1C00}] set GPIOG_BASE [expr {$APB2PERIPH_BASE + 0x2000}] set ADC1_BASE [expr {$APB2PERIPH_BASE + 0x2400}] set ADC2_BASE [expr {$APB2PERIPH_BASE + 0x2800}] set TIM1_BASE [expr {$APB2PERIPH_BASE + 0x2C00}] set SPI1_BASE [expr {$APB2PERIPH_BASE + 0x3000}] set TIM8_BASE [expr {$APB2PERIPH_BASE + 0x3400}] set USART1_BASE [expr {$APB2PERIPH_BASE + 0x3800}] set ADC3_BASE [expr {$APB2PERIPH_BASE + 0x3C00}] set SDIO_BASE [expr {$PERIPH_BASE + 0x18000}] set DMA1_BASE [expr {$AHBPERIPH_BASE + 0x0000}] set DMA1_Channel1_BASE [expr {$AHBPERIPH_BASE + 0x0008}] set DMA1_Channel2_BASE [expr {$AHBPERIPH_BASE + 0x001C}] set DMA1_Channel3_BASE [expr {$AHBPERIPH_BASE + 0x0030}] set DMA1_Channel4_BASE [expr {$AHBPERIPH_BASE + 0x0044}] set DMA1_Channel5_BASE [expr {$AHBPERIPH_BASE + 0x0058}] set DMA1_Channel6_BASE [expr {$AHBPERIPH_BASE + 0x006C}] set DMA1_Channel7_BASE [expr {$AHBPERIPH_BASE + 0x0080}] set DMA2_BASE [expr {$AHBPERIPH_BASE + 0x0400}] set DMA2_Channel1_BASE [expr {$AHBPERIPH_BASE + 0x0408}] set DMA2_Channel2_BASE [expr {$AHBPERIPH_BASE + 0x041C}] set DMA2_Channel3_BASE [expr {$AHBPERIPH_BASE + 0x0430}] set DMA2_Channel4_BASE [expr {$AHBPERIPH_BASE + 0x0444}] set DMA2_Channel5_BASE [expr {$AHBPERIPH_BASE + 0x0458}] set RCC_BASE [expr {$AHBPERIPH_BASE + 0x1000}] set CRC_BASE [expr {$AHBPERIPH_BASE + 0x3000}] # /*Flash registers base address */ set FLASH_R_BASE [expr {$AHBPERIPH_BASE + 0x2000}] # /*Flash Option Bytes base address */ set OB_BASE 0x1FFFF800 # /*FSMC Bankx registers base address */ set FSMC_Bank1_R_BASE [expr {$FSMC_R_BASE + 0x0000}] set FSMC_Bank1E_R_BASE [expr {$FSMC_R_BASE + 0x0104}] set FSMC_Bank2_R_BASE [expr {$FSMC_R_BASE + 0x0060}] set FSMC_Bank3_R_BASE [expr {$FSMC_R_BASE + 0x0080}] set FSMC_Bank4_R_BASE [expr {$FSMC_R_BASE + 0x00A0}] # /*Debug MCU registers base address */ set DBGMCU_BASE 0xE0042000 # /*System Control Space memory map */ set SCS_BASE 0xE000E000 set SysTick_BASE [expr {$SCS_BASE + 0x0010}] set NVIC_BASE [expr {$SCS_BASE + 0x0100}] set SCB_BASE [expr {$SCS_BASE + 0x0D00}] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/ti/lm3s/lm3s.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find chip/ti/lm3s/lm3s_regs.tcl] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/chip/ti/lm3s/lm3s_regs.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #***************************************************************************** # # The following are defines for the System Control register addresses. # #***************************************************************************** set SYSCTL_DID0 0x400FE000 ;# Device Identification 0 set SYSCTL_DID1 0x400FE004 ;# Device Identification 1 set SYSCTL_DC0 0x400FE008 ;# Device Capabilities 0 set SYSCTL_DC1 0x400FE010 ;# Device Capabilities 1 set SYSCTL_DC2 0x400FE014 ;# Device Capabilities 2 set SYSCTL_DC3 0x400FE018 ;# Device Capabilities 3 set SYSCTL_DC4 0x400FE01C ;# Device Capabilities 4 set SYSCTL_DC5 0x400FE020 ;# Device Capabilities 5 set SYSCTL_DC6 0x400FE024 ;# Device Capabilities 6 set SYSCTL_DC7 0x400FE028 ;# Device Capabilities 7 set SYSCTL_DC8 0x400FE02C ;# Device Capabilities 8 ADC ;# Channels set SYSCTL_PBORCTL 0x400FE030 ;# Brown-Out Reset Control set SYSCTL_LDOPCTL 0x400FE034 ;# LDO Power Control set SYSCTL_SRCR0 0x400FE040 ;# Software Reset Control 0 set SYSCTL_SRCR1 0x400FE044 ;# Software Reset Control 1 set SYSCTL_SRCR2 0x400FE048 ;# Software Reset Control 2 set SYSCTL_RIS 0x400FE050 ;# Raw Interrupt Status set SYSCTL_IMC 0x400FE054 ;# Interrupt Mask Control set SYSCTL_MISC 0x400FE058 ;# Masked Interrupt Status and ;# Clear set SYSCTL_RESC 0x400FE05C ;# Reset Cause set SYSCTL_RCC 0x400FE060 ;# Run-Mode Clock Configuration set SYSCTL_PLLCFG 0x400FE064 ;# XTAL to PLL Translation set SYSCTL_GPIOHSCTL 0x400FE06C ;# GPIO High-Speed Control set SYSCTL_GPIOHBCTL 0x400FE06C ;# GPIO High-Performance Bus ;# Control set SYSCTL_RCC2 0x400FE070 ;# Run-Mode Clock Configuration 2 set SYSCTL_MOSCCTL 0x400FE07C ;# Main Oscillator Control set SYSCTL_RCGC0 0x400FE100 ;# Run Mode Clock Gating Control ;# Register 0 set SYSCTL_RCGC1 0x400FE104 ;# Run Mode Clock Gating Control ;# Register 1 set SYSCTL_RCGC2 0x400FE108 ;# Run Mode Clock Gating Control ;# Register 2 set SYSCTL_SCGC0 0x400FE110 ;# Sleep Mode Clock Gating Control ;# Register 0 set SYSCTL_SCGC1 0x400FE114 ;# Sleep Mode Clock Gating Control ;# Register 1 set SYSCTL_SCGC2 0x400FE118 ;# Sleep Mode Clock Gating Control ;# Register 2 set SYSCTL_DCGC0 0x400FE120 ;# Deep Sleep Mode Clock Gating ;# Control Register 0 set SYSCTL_DCGC1 0x400FE124 ;# Deep-Sleep Mode Clock Gating ;# Control Register 1 set SYSCTL_DCGC2 0x400FE128 ;# Deep Sleep Mode Clock Gating ;# Control Register 2 set SYSCTL_DSLPCLKCFG 0x400FE144 ;# Deep Sleep Clock Configuration set SYSCTL_CLKVCLR 0x400FE150 ;# Clock Verification Clear set SYSCTL_PIOSCCAL 0x400FE150 ;# Precision Internal Oscillator ;# Calibration set SYSCTL_PIOSCSTAT 0x400FE154 ;# Precision Internal Oscillator ;# Statistics set SYSCTL_LDOARST 0x400FE160 ;# Allow Unregulated LDO to Reset ;# the Part set SYSCTL_I2SMCLKCFG 0x400FE170 ;# I2S MCLK Configuration set SYSCTL_DC9 0x400FE190 ;# Device Capabilities 9 ADC ;# Digital Comparators set SYSCTL_NVMSTAT 0x400FE1A0 ;# Non-Volatile Memory Information set SYSCTL_RCC_USESYSDIV 0x00400000 ;# Enable System Clock Divider set SYSCTL_RCC2_BYPASS2 0x00000800 ;# PLL Bypass 2 set SYSCTL_RCC_MOSCDIS 0x00000001 ;# Main Oscillator Disable set SYSCTL_SRCR0 0x400FE040 ;# Software Reset Control 0 set SYSCTL_SRCR1 0x400FE044 ;# Software Reset Control 1 set SYSCTL_SRCR2 0x400FE048 ;# Software Reset Control 2 set SYSCTL_MISC 0x400FE058 ;# Masked Interrupt Status and Clear set FLASH_FMA 0x400FD000 ;# Flash Memory Address set FLASH_FMD 0x400FD004 ;# Flash Memory Data set FLASH_FMC 0x400FD008 ;# Flash Memory Control set FLASH_FCRIS 0x400FD00C ;# Flash Controller Raw Interrupt Status set FLASH_FCIM 0x400FD010 ;# Flash Controller Interrupt Mask set FLASH_FCMISC 0x400FD014 ;# Flash Controller Masked Interrupt Status and Clear set FLASH_FMC2 0x400FD020 ;# Flash Memory Control 2 set FLASH_FWBVAL 0x400FD030 ;# Flash Write Buffer Valid ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/altera-5m570z-cpld.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # file altera-5m570z-cpld.cfg replaced by altera-maxv.cfg echo "DEPRECATED: use altera-maxv.cfg instead of deprecated altera-5m570z-cpld.cfg" #just to be backward compatible: #tap will be 5m570z.tap instead of maxv.tap: set CHIPNAME 5m570z source [find cpld/altera-maxv.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/altera-epm240.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # file altera-epm240.cfg replaced by altera-maxii.cfg echo "DEPRECATED: use altera-maxii.cfg instead of deprecated altera-epm240.cfg" #just to be backward compatible: #tap will be epm240.tap instead of maxii.tap: set CHIPNAME epm240 source [find cpld/altera-maxii.cfg] # 200ns seems like a good speed # c.f. Table 5-34: MAX II JTAG Timing Parameters adapter speed 5000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/altera-max10.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # see MAX 10 FPGA Device Architecture # Table 3-1: IDCODE Information for MAX 10 Devices # Intel MAX 10M02 0x31810dd # Intel MAX 10M04 0x318a0dd # Intel MAX 10M08 0x31820dd # Intel MAX 10M16 0x31830dd # Intel MAX 10M25 0x31840dd # Intel MAX 10M40 0x318d0dd # Intel MAX 10M50 0x31850dd # Intel MAX 10M02 0x31010dd # Intel MAX 10M04 0x310a0dd # Intel MAX 10M08 0x31020dd # Intel MAX 10M16 0x31030dd # Intel MAX 10M25 0x31040dd # Intel MAX 10M40 0x310d0dd # Intel MAX 10M50 0x31050dd if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME max10 } jtag newtap $_CHIPNAME tap -irlen 10 -expected-id 0x31810dd -expected-id 0x318a0dd \ -expected-id 0x31820dd -expected-id 0x31830dd -expected-id 0x31840dd \ -expected-id 0x318d0dd -expected-id 0x31850dd -expected-id 0x31010dd \ -expected-id 0x310a0dd -expected-id 0x31020dd -expected-id 0x31030dd \ -expected-id 0x31040dd -expected-id 0x310d0dd -expected-id 0x31050dd ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/altera-maxii.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Altera MAXII CPLD if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME maxii } # see MAX II Device Handbook # Table 3-3: 32-Bit MAX II Device IDCODE # Version Part Number Manuf. ID LSB # 0000 0010 0000 1010 0001 000 0110 1110 1 jtag newtap $_CHIPNAME tap -irlen 10 \ -expected-id 0x020a10dd \ -expected-id 0x020a20dd \ -expected-id 0x020a30dd \ -expected-id 0x020a40dd \ -expected-id 0x020a50dd \ -expected-id 0x020a60dd ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/altera-maxv.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Altera MAXV 5M24OZ/5M570Z CPLD # see MAX V Device Handbook # Table 6-3: 32-Bit MAX V Device IDCODE # 5M40Z 5M80Z 5M160Z 5M240Z: 0x020A50DD # 5M570Z: 0x020A60DD # 5M1270Z: 0x020A30DD # 5M1270Z 5M2210Z: 0x020A40DD if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME maxv } jtag newtap $_CHIPNAME tap -irlen 10 \ -expected-id 0x020A50DD -expected-id 0x020A60DD \ -expected-id 0x020A30DD -expected-id 0x020A40DD ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/jtagspi.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set _USER1 0x02 if { [info exists JTAGSPI_IR] } { set _JTAGSPI_IR $JTAGSPI_IR } else { set _JTAGSPI_IR $_USER1 } if { [info exists TARGETNAME] } { set _TARGETNAME $TARGETNAME } else { set _TARGETNAME $_CHIPNAME.proxy } if { [info exists FLASHNAME] } { set _FLASHNAME $FLASHNAME } else { set _FLASHNAME $_CHIPNAME.spi } target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME $_JTAGSPI_IR # initialize jtagspi flash # chain_id: identifier of pld (you can get a list with 'pld devices') # proxy_bit: file with bitstream connecting JTAG and SPI interface in the PLD. # release_from_pwr_down_cmd: optional, command sent to spi flash before probing. # ex: 0xAB to release from power-dowm. # Just omit it to not send a command. proc jtagspi_init {chain_id proxy_bit {release_from_pwr_down_cmd -1}} { # load proxy bitstream $proxy_bit and probe spi flash global _FLASHNAME pld load $chain_id $proxy_bit reset halt if {$release_from_pwr_down_cmd != -1} { jtagspi cmd $_FLASHNAME 0 $release_from_pwr_down_cmd } flash probe $_FLASHNAME } proc jtagspi_program {bin addr} { # write and verify binary file $bin at offset $addr global _FLASHNAME flash write_image erase $bin $addr flash verify_bank $_FLASHNAME $bin $addr } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/lattice-lc4032ze.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Lattice ispMACH 4000ZE family, device LC4032ZE # just configure a tap jtag newtap LC4032ZE tap -irlen 8 -expected-id 0x01806043 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xc3s.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # xilinx spartan3 # https://docs.xilinx.com/v/u/en-US/ug332 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xc3s } # the 4 top bits (28:31) are the die stepping. ignore it. jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ -expected-id 0x01414093 \ -expected-id 0x0141C093 \ -expected-id 0x01428093 \ -expected-id 0x01434093 \ -expected-id 0x01440093 \ -expected-id 0x01448093 \ -expected-id 0x01450093 \ -expected-id 0x01C10093 \ -expected-id 0x01C1A093 \ -expected-id 0x01C22093 \ -expected-id 0x01C2E093 \ -expected-id 0x01C3A093 \ -expected-id 0x0140C093 \ -expected-id 0x02210093 \ -expected-id 0x02218093 \ -expected-id 0x02220093 \ -expected-id 0x02228093 \ -expected-id 0x02230093 \ -expected-id 0x02610093 \ -expected-id 0x02618093 \ -expected-id 0x02620093 \ -expected-id 0x02628093 \ -expected-id 0x02630093 \ -expected-id 0x03840093 \ -expected-id 0x0384e093 pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xc4v.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # xilinx virtex 4 # https://docs.xilinx.com/v/u/en-US/ug071 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xc4v } # the 4 top bits (28:31) are the die stepping. ignore it. jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version \ -expected-id 0x01658093 \ -expected-id 0x01E58093 \ -expected-id 0x0167C093 \ -expected-id 0x02068093 \ -expected-id 0x01E64093 \ -expected-id 0x016A4093 \ -expected-id 0x02088093 \ -expected-id 0x016B4093 \ -expected-id 0x020B0093 \ -expected-id 0x016D8093 \ -expected-id 0x01700093 \ -expected-id 0x01718093 \ -expected-id 0x01734093 pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap # cfg_out cfg_in jprogb jstart jshutdown user1-4 virtex2 set_instr_codes $_CHIPNAME.pld 0x3C4 0x3C5 0x3CB 0x3CC 0x3CD virtex2 set_user_codes $_CHIPNAME.pld 0x3C2 0x3C3 0x3E2 0x3E3 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xc4vfx_40_60_100_140.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # xilinx virtex 4 # https://docs.xilinx.com/v/u/en-US/ug071 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xc4vfx } # the 4 top bits (28:31) are the die stepping. ignore it. jtag newtap $_CHIPNAME tap -irlen 14 -ignore-version \ -expected-id 0x01E8C093 \ -expected-id 0x01EB4093 \ -expected-id 0x01EE4093 \ -expected-id 0x01F14093 \ pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap # cfg_out cfg_in jprogb jstart jshutdown user1-4 virtex2 set_instr_codes $_CHIPNAME.pld 0x3FC4 0x3FC5 0x3FCB 0x3FCC 0x3FCD virtex2 set_user_codes $_CHIPNAME.pld 0x3FC2 0x3FC3 0x3FE2 0x3FE3 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xc5v.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # xilinx virtex 5 # https://docs.xilinx.com/v/u/en-US/ug191 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xc5v } # the 4 top bits (28:31) are the die stepping. ignore it. jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version \ -expected-id 0x0286E093 \ -expected-id 0x02896093 \ -expected-id 0x028AE093 \ -expected-id 0x028D6093 \ -expected-id 0x028EC093 \ -expected-id 0x0290C093 \ -expected-id 0x0295C093 \ -expected-id 0x02A56093 \ -expected-id 0x02A6E093 \ -expected-id 0x02A96093 \ -expected-id 0x02AAE093 \ -expected-id 0x02AD6093 \ -expected-id 0x02AEC093 \ -expected-id 0x02B0C093 \ -expected-id 0x02B5C093 \ -expected-id 0x02E72093 \ -expected-id 0x02E9A093 \ -expected-id 0x02ECE093 \ -expected-id 0x02F3E093 \ -expected-id 0x03276093 \ -expected-id 0x032C6093 \ -expected-id 0x04502093 \ -expected-id 0x0453E093 pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap # cfg_out cfg_in jprogb jstart jshutdown user1-4 virtex2 set_instr_codes $_CHIPNAME.pld 0x3C4 0x3C5 0x3CB 0x3CC 0x3CD virtex2 set_user_codes $_CHIPNAME.pld 0x3C2 0x3C3 0x3E2 0x3E3 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xc5vfx_100_130_200.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # xilinx virtex 5 # https://docs.xilinx.com/v/u/en-US/ug191 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xc5vfx } # the 4 top bits (28:31) are the die stepping. ignore it. jtag newtap $_CHIPNAME tap -irlen 14 -ignore-version \ -expected-id 0x032D8093 \ -expected-id 0x03300093 \ -expected-id 0x03334093 pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap # cfg_out cfg_in jprogb jstart jshutdown user1-4 virtex2 set_instr_codes $_CHIPNAME.pld 0x3FC4 0x3FC5 0x3FCB 0x3FCC 0x3FCD virtex2 set_user_codes $_CHIPNAME.pld 0x3FC2 0x3FC3 0x3FE2 0x3FE3 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xc6s.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # xilinx spartan6 # http://www.xilinx.com/support/documentation/user_guides/ug380.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xc6s } # the 4 top bits (28:31) are the die stepping. ignore it. jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ -expected-id 0x04000093 \ -expected-id 0x04001093 \ -expected-id 0x04002093 \ -expected-id 0x04004093 \ -expected-id 0x04024093 \ -expected-id 0x04008093 \ -expected-id 0x04028093 \ -expected-id 0x0400E093 \ -expected-id 0x0402E093 \ -expected-id 0x04011093 \ -expected-id 0x04031093 \ -expected-id 0x0401D093 \ -expected-id 0x0403D093 pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap virtex2 set_user_codes $_CHIPNAME.pld 0x02 0x03 0x1A 0x1B set XC6S_CFG_IN 0x05 set XC6S_JSHUTDOWN 0x0d set XC6S_JPROGRAM 0x0b set XC6S_JSTART 0x0c set XC6S_BYPASS 0x3f proc xc6s_program {tap} { echo "DEPRECATED! use 'virtex2 program ...' not 'xc6s_program'" global XC6S_JSHUTDOWN XC6S_JPROGRAM XC6S_JSTART XC6S_BYPASS irscan $tap $XC6S_JSHUTDOWN irscan $tap $XC6S_JPROGRAM irscan $tap $XC6S_JSTART irscan $tap $XC6S_BYPASS } #xtp038 and xc3sprog approach proc xc6s_program_iprog {tap} { echo "DEPRECATED! use 'virtex2 program ...' not 'xc6s_program_iprog'" global XC6S_JSHUTDOWN XC6S_JSTART XC6S_BYPASS XC6S_CFG_IN irscan $tap $XC6S_JSHUTDOWN runtest 16 irscan $tap $XC6S_CFG_IN # xtp038 IPROG 16bit flipped drscan $tap 16 0xffff 16 0x9955 16 0x66aa 16 0x850c 16 0x7000 16 0x0004 irscan $tap $XC6S_JSTART runtest 32 irscan $tap $XC6S_BYPASS runtest 1 } set XC6S_ISC_ENABLE 0x10 set XC6S_ISC_DISABLE 0x16 set XC6S_ISC_DNA 0x30 # Get the "Device DNA" from the Spartan 6. # Most Xilinx FPGA devices contain an embedded, unique device identifier called # the "Device DNA". The identifier is nonvolatile, permanently programmed into # the FPGA, and is unchangeable providing a great serial / tracking number. proc xc6s_get_dna {tap} { global XC6S_ISC_ENABLE XC6S_ISC_DISABLE XC6S_ISC_DNA irscan $tap $XC6S_ISC_ENABLE runtest 64 irscan $tap $XC6S_ISC_DNA # Device DNA is 57 bits long, but we can only read 32bits at a time # with OpenOCD. set dna [drscan $tap 16 0 16 0 16 0 9 0] runtest 64 irscan $tap $XC6S_ISC_DISABLE runtest 64 # Convert the binary data into the order impact uses scan $dna "%x %x %x %x" v1 v2 v3 v4 set bin_dna [string reverse [concat [format "%09b" $v4][format "%016b" $v3][format "%016b" $v2][format "%016b" $v1]]] # Return a hex version of binary scan [format "0b%s" $bin_dna] "%i" hex_dna return $hex_dna } # Print out the "Device DNA" in the same format that impact uses. proc xc6s_print_dna {tap} { set hex_dna [xc6s_get_dna $tap] puts [format "DNA = %57b (0x%x)\n" $hex_dna $hex_dna] } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xc6v.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # xilinx virtex 6 # https://www.xilinx.com/support/documentation/user_guides/ug360.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xc6v } # the 4 top bits (28:31) are the die stepping. ignore it. jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version \ -expected-id 0x042A2093 \ -expected-id 0x042A4093 \ -expected-id 0x042A8093 \ -expected-id 0x042AC093 \ -expected-id 0x04244093 \ -expected-id 0x0424A093 \ -expected-id 0x0424C093 \ -expected-id 0x04250093 \ -expected-id 0x04252093 \ -expected-id 0x04256093 \ -expected-id 0x0423A093 \ -expected-id 0x04286093 \ -expected-id 0x04288093 \ -expected-id 0x042C4093 \ -expected-id 0x042CA093 \ -expected-id 0x042CC093 \ -expected-id 0x042D0093 pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap # cfg_out cfg_in jprogb jstart jshutdown user1-4 virtex2 set_instr_codes $_CHIPNAME.pld 0x3C4 0x3C5 0x3CB 0x3CC 0x3CD virtex2 set_user_codes $_CHIPNAME.pld 0x3C2 0x3C3 0x3E2 0x3E3 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xc7.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # xilinx series 7 (spartan, artix, kintex, virtex) # http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xc7 } # the 4 top bits (28:31) are the die stepping/revisions. ignore it. jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ -expected-id 0x03622093 \ -expected-id 0x03620093 \ -expected-id 0x037C4093 \ -expected-id 0x0362F093 \ -expected-id 0x037C8093 \ -expected-id 0x037C7093 \ -expected-id 0x037C3093 \ -expected-id 0x0362E093 \ -expected-id 0x037C2093 \ -expected-id 0x0362D093 \ -expected-id 0x0362C093 \ -expected-id 0x03632093 \ -expected-id 0x03631093 \ -expected-id 0x03636093 \ -expected-id 0x03647093 \ -expected-id 0x0364C093 \ -expected-id 0x03651093 \ -expected-id 0x03747093 \ -expected-id 0x03656093 \ -expected-id 0x03752093 \ -expected-id 0x03751093 \ -expected-id 0x03671093 \ -expected-id 0x03667093 \ -expected-id 0x03682093 \ -expected-id 0x03687093 \ -expected-id 0x03692093 \ -expected-id 0x03691093 \ -expected-id 0x03696093 pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart virtex2 set_user_codes $_CHIPNAME.pld 0x02 0x03 0x22 0x23 set XC7_JSHUTDOWN 0x0d set XC7_JPROGRAM 0x0b set XC7_JSTART 0x0c set XC7_BYPASS 0x3f proc xc7_program {tap} { echo "DEPRECATED! use 'virtex2 program ...' not 'xc7_program'" global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS irscan $tap $XC7_JSHUTDOWN irscan $tap $XC7_JPROGRAM runtest 60000 #JSTART prevents this from working... #irscan $tap $XC7_JSTART runtest 2000 irscan $tap $XC7_BYPASS runtest 2000 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xc7v.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # xilinx series 7 (artix, kintex, virtex) # http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf # https://bsdl.info/view.htm?sid=08e275a0cd3ac38988ca59b002289d77 # https://bsdl.info/view.htm?sid=44dae65d3cf9593188ca59b002289d77 # # this config file is for XC7VX1140T and XC7V2000T only. # for other virtex-7 devices use xilinx-xc7vh580t.cfg or xilinx-xc7vh870t.cfg or xilinx-xc7.cfg if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xc7v } #0x036D5093: XC7VX1140T #0x036By093: XC7V2000T #y = xx11 = 3, 7, B or F jtag newtap $_CHIPNAME tap -irlen 24 -ignore-version \ -expected-id 0x036B3093 -expected-id 0x036B7093 \ -expected-id 0x036BB093 -expected-id 0x036BF093 \ -expected-id 0x036D5093 #CFG_OUT_SLR0 0x124924 #CFG_IN_SLR0 0x164924 #CFG_OUT_SLR1 0x904924 #CFG_IN_SLR1 0x905924 #CFG_OUT_SLR2 0x924124 #CFG_IN_SLR2 0x924164 #CFG_OUT_SLR3 0x924904 #CFG_IN_SLR3 0x924905 pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart # cfg_out cfg_in jprogb jstart jshutdown virtex2 set_instr_codes $_CHIPNAME.pld 0x3FFFFF 0x3FFFFF 0x2CB2CB 0x30C30C 0x34D34D ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xc7vh580t.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # xilinx series 7 (artix, kintex, virtex) # http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf # https://bsdl.info/view.htm?sid=65c6b2cfe1467b4988ca59b002289d77 # # this config file is for xc7vh580t only. # for other virtex-7 devices use xilinx-xc7vh870t.cfg or xilinx-xc7v.cfg or xilinx-xc7.cfg if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xc7vh580t } jtag newtap $_CHIPNAME tap -irlen 22 -ignore-version -expected-id 0x036D9093 #CFG_OUT_SLR0 0x0492A0 #CFG_IN_SLR0 0x0592A0 #CFG_OUT_SLR1 0x2412A0 #CFG_IN_SLR1 0x2416A0 pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart # cfg_out cfg_in jprogb jstart jshutdown virtex2 set_instr_codes $_CHIPNAME.pld 0x3FFFFF 0x3FFFFF 0x0B2EA0 0x0C32A0 0x0D36A0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xc7vh870t.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # xilinx series 7 (artix, kintex, virtex) # http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf # https://bsdl.info/view.htm?sid=d9ff0bb764df004588ca59b002289d77 # # this config file is for xc7vh870t only. # for other virtex-7 devices use xilinx-xc7vh580t.cfg or xilinx-xc7v.cfg or xilinx-xc7.cfg # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xc7vh870t } jtag newtap $_CHIPNAME tap -irlen 38 -ignore-version -expected-id 0x036DB093 #CFG_OUT_SLR0 0x0492A092A0 #CFG_IN_SLR0 0x0592A092A0 #CFG_OUT_SLR1 0x2412A092A0 #CFG_IN_SLR1 0x2416A092A0 #CFG_OUT_SLR2 0x2492A012A0 #CFG_IN_SLR2 0x2492A016A0 pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart # cfg_out cfg_in jprogb jstart jshutdown virtex2 set_instr_codes $_CHIPNAME.pld 0x3FFFFFFFFF 0x3FFFFFFFFF 0x0B2EA02EA0 0x0C32A032A0 0x0D36A036A0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xcf-p.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xcf } # IDs acquired from Xilinx's DS123.pdf # XCF08P <v>5057093 # XCF16P <v>5058093 # XCF32P <v>5059093 # The 4 top bits (28:31) are the device revision. Ignore it. jtag newtap $_CHIPNAME flash -irlen 16 -ignore-version \ -expected-id 0x05057093 \ -expected-id 0x05058093 \ -expected-id 0x05059093 target create xcf.flash testee -chain-position $_CHIPNAME.flash flash bank XCF_P xcf 0 0 0 0 xcf.flash ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xcf-s.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xcf } # IDs acquired from Xilinx's DS123.pdf # XCF01S <v>5044093 # XCF02S <v>5045093 # XCF04S <v>5046093 # The 4 top bits (28:31) are the device revision. Ignore it. jtag newtap $_CHIPNAME flash -irlen 8 -ignore-version \ -expected-id 0x05044093 \ -expected-id 0x05045093 \ -expected-id 0x05046093 target create xcf.flash testee -chain-position $_CHIPNAME.flash flash bank XCF_S xcf 0 0 0 0 xcf.flash ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xcr3256.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #xilinx coolrunner xcr3256 #simple device - just configure a tap jtag newtap xcr tap -irlen 5 -ircapture 0x01 -irmask 0x1f -expected-id 0x0494c093 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpld/xilinx-xcu.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Xilinx Ultrascale (Kintex, Virtex, Zynq) # https://www.xilinx.com/support/documentation/user_guides/ug570-ultrascale-configuration.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xcu } # The various chips in the Ultrascale family have different IR length. # Set $CHIP before including this file to determine the device. array set _XCU_DATA { XCKU025 {0x03824093 6} XCKU035 {0x03823093 6} XCKU040 {0x03822093 6} XCKU060 {0x03919093 6} XCKU060_CIV {0x0381b093 6} XCKU095 {0x03844093 6} XCKU095_CIV {0x03845093 6} XCKU3P {0x04A63093 6} XCKU5P {0x04A62093 6} XCKU9P {0x0484A093 6} XCKU11P {0x04A4E093 6} XCKU11P_CIV {0x04A51093 6} XCKU13P {0x04A52093 6} XCKU15P {0x04A56093 6} XCKU15P_CIV {0x04A59093 6} XCVU065 {0x03939093 6} XCVU065_CIV {0x0393b093 6} XCVU080 {0x03843093 6} XCVU080_CIV {0x03845093 6} XCVU095 {0x03842093 6} XCVU2P {0x04aea093 6} XCVU3P {0x04B39093 6} XCVU3P_CIV {0x04b3d093 6} XCAU10P {0x04AC4033 6} XCAU10P_FFVB676 {0x04AC4093 6} XCAU15P {0x04AC2033 6} XCAU15P_FFVB676 {0x04AC2093 6} XCAU20P {0x04A65093 6} XCAU25P {0x04A64093 6} XCKU5P_CIV {0x04A64093 6} XCKU19P {0x04ACF093 6} XCKU19P_CIV {0x04AD3093 6} XCKU085 {0x0380F093 12} XCKU115 {0x0390D093 12} XCVU125 {0x0392D093 12} XCVU125_CIV {0x0392f093 12} XCVU5P {0x04B2B093 12} XCVU5P_CIV {0x04b2f093 12} XCVU7P {0x04B29093 12} XCVU7P_CIV {0x04b2d093 12} XCVU160 {0x03933093 18} XCVU190 {0x03931093 18} XCVU440 {0x0396D093 18} XCVU440_CIV {0x0396f093 18} XCVU9P {0x04B31093 18} XCVU9P_CIV {0x04b35093 18} XCVU11P {0x04B49093 18} XCVU11P_CIV {0x04b4f093 18} XCU200_FSGD2104 {0x04b37093 18} XCU250 {0x04b57093 24} XCVU13P {0x04B51093 24} XCVU13P_CIV {0x04b55093 24} XCVU15P {0x04ba3093 24} XCVU19P {0x04ba1093 24} XCVU19P_CIV {0x04ba5093 24} } if { ![info exists CHIP] } { error "set CHIP to one of "[concat [array names _XCU_DATA]] } if { ![llength [array names _XCU_DATA $CHIP]] } { error "unknown CHIP: "$CHIP } set _EXPID [lindex $_XCU_DATA($CHIP) 0] set _IRLEN [lindex $_XCU_DATA($CHIP) 1] # the 4 top bits (28:31) are the die stepping/revisions. ignore it. jtag newtap $_CHIPNAME tap -irlen $_IRLEN -ignore-version -expected-id $_EXPID pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart # set the correct instruction codes for jtag hub and # at least the right code for jprogb, jstart and jshutdown for SSI devices if { $_IRLEN == 6 } { virtex2 set_user_codes $_CHIPNAME.pld 0x2 0x3 0x22 0x23 } elseif {$_IRLEN == 12 } { puts "loading bitstream through jtag will not work, but reprogram (refresh)" virtex2 set_instr_codes $_CHIPNAME.pld 0x905 0x904 0x2cb 0x30c 0x34d virtex2 set_user_codes $_CHIPNAME.pld 0x0a4 0x0e4 0x8a4 0x8e4 } elseif {$_IRLEN == 18 } { puts "loading bitstream through jtag will not work, but reprogram (refresh)" virtex2 set_instr_codes $_CHIPNAME.pld 0x24905 0x24904 0x0b2cb 0x0c30c 0x0d34d virtex2 set_user_codes $_CHIPNAME.pld 0x000a4 0x000e4 0x008a4 0x008e4 } else { puts "loading bitstream through jtag will not work, but reprogram (refresh)" virtex2 set_instr_codes $_CHIPNAME.pld 0x924905 0x924904 0x2cb2cb 0x30c30c 0x34d34d virtex2 set_user_codes $_CHIPNAME.pld 0x0a4924 0x0e4924 0x8a4924 0x8e4924 } set XCU_JSHUTDOWN 0x0d set XCU_JPROGRAM 0x0b set XCU_JSTART 0x0c set XCU_BYPASS 0x3f proc xcu_program {tap} { echo "DEPRECATED! use 'virtex2 program ...' not 'xcu_program'" global XCU_JSHUTDOWN XCU_JPROGRAM XCU_JSTART XCU_BYPASS irscan $tap $XCU_JSHUTDOWN irscan $tap $XCU_JPROGRAM runtest 60000 #JSTART prevents this from working... #irscan $tap $XCU_JSTART runtest 2000 irscan $tap $XCU_BYPASS runtest 2000 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpu/arc/common.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2015, 2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> # Things common to all ARCs # It is assumed that target is already halted. proc arc_common_reset { {target ""} } { if { $target != "" } { targets $target } halt # 1. Interrupts are disabled (STATUS32.IE) # 2. The status register flags are cleared. # All fields, except the H bit, are set to 0 when the processor is Reset. arc jtag set-aux-reg 0xA 0x1 # 3. The loop count, loop start, and loop end registers are cleared. arc jtag set-core-reg 60 0 arc jtag set-aux-reg 0x2 0 arc jtag set-aux-reg 0x3 0 # Program execution begins at the address referenced by the four byte reset # vector located at the interrupt vector base address, which is the first # entry (offset 0x00) in the vector table. set int_vector_base [arc jtag get-aux-reg 0x25] set start_pc [read_memory $int_vector_base 32 1] arc jtag set-aux-reg 0x6 $start_pc # It is OK to do uncached writes - register cache will be invalidated by # the reset_assert() function. } # vim:expandtab: ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpu/arc/em.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2015, 2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> source [find cpu/arc/v2.tcl] proc arc_em_examine_target { {target ""} } { # Will set current target arc_v2_examine_target $target } proc arc_em_init_regs { } { arc_v2_init_regs [target current] configure \ -event examine-end "arc_em_examine_target [target current]" } # Scripts in "target" folder should call this function instead of direct # invocation of arc_common_reset. proc arc_em_reset { {target ""} } { arc_v2_reset $target # Set DEBUG.ED bit to enable clock in actionpoint module. # This is specific to ARC EM. set debug [arc jtag get-aux-reg 5] if { !($debug & (1 << 20)) } { arc jtag set-aux-reg 5 [expr {$debug | (1 << 20)}] } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpu/arc/hs.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2015, 2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> source [find cpu/arc/v2.tcl] proc arc_hs_examine_target { target } { # Will set current target for us. arc_v2_examine_target $target } proc arc_hs_init_regs { } { arc_v2_init_regs [target current] configure \ -event examine-end "arc_hs_examine_target [target current]" } # Scripts in "target" folder should call this function instead of direct # invocation of arc_common_reset. proc arc_hs_reset { {target ""} } { arc_v2_reset $target # Invalidate L2 cache if there is one. set l2_config [$target arc jtag get-aux-reg 0x901] # Will return 0, if cache is not present and register doesn't exist. set l2_ctrl [$target arc jtag get-aux-reg 0x903] if { ($l2_config != 0) && (($l2_ctrl & 1) == 0) } { puts "L2 cache is present and not disabled" # Wait until BUSY bit is 0. puts "Invalidating L2 cache..." $target arc jtag set-aux-reg 0x905 1 # Dummy read of SLC_AUX_CACHE_CTRL bit, as described in: # https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/commit/arch/arc?id=c70c473396cbdec1168a6eff60e13029c0916854 set l2_ctrl [$target arc jtag get-aux-reg 0x903] set l2_ctrl [$target arc jtag get-aux-reg 0x903] while { ($l2_ctrl & 0x100) != 0 } { set l2_ctrl [$target arc jtag get-aux-reg 0x903] } # Flush cache if needed. If SLC_AUX_CACHE_CTRL.IM is 1, then invalidate # operation already flushed everything. if { ($l2_ctrl & 0x40) == 0 } { puts "Flushing L2 cache..." $target arc jtag set-aux-reg 0x904 1 set l2_ctrl [$target arc jtag get-aux-reg 0x903] set l2_ctrl [$target arc jtag get-aux-reg 0x903] while { [expr {$l2_ctrl & 0x100}] != 0 } { set l2_ctrl [$target arc jtag get-aux-reg 0x903] } } puts "L2 cache has been flushed and invalidated." } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpu/arc/v2.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2015, 2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> source [find cpu/arc/common.tcl] # Currently 'examine_target' can only read JTAG registers and set properties - # but it shouldn't write any of registers - writes will be cached, but cache # will be invalidated before flushing after examine_target, and changes will be # lost. Perhaps that would be fixed later - perhaps writes shouldn't be cached # after all. But if write to register is really needed from TCL - then it # should be done via "arc jtag" for now. proc arc_v2_examine_target { {target ""} } { # Set current target, because OpenOCD event handlers don't do this for us. if { $target != "" } { targets $target } # Those registers always exist. DEBUG and DEBUGI are formally optional, # however they come with JTAG interface, and so far there is no way # OpenOCD can communicate with target without JTAG interface. arc set-reg-exists identity pc status32 bta debug lp_start lp_end \ eret erbta erstatus ecr efa # 32 core registers arc set-reg-exists \ r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 \ r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 r24 r25 \ gp fp sp ilink r30 blink lp_count pcl # Actionpoints if { [arc get-reg-field ap_build version] == 5 } { set ap_build_type [arc get-reg-field ap_build type] # AP_BUILD.TYPE > 0b0110 is reserved in current ISA. # Current ISA supports up to 8 actionpoints. if { $ap_build_type < 8 } { # Two LSB bits of AP_BUILD.TYPE define amount of actionpoints: # 0b00 - 2 actionpoints # 0b01 - 4 actionpoints # 0b10 - 8 actionpoints # 0b11 - reserved. set ap_num [expr {0x2 << ($ap_build_type & 3)}] # Expression on top may produce 16 action points - which is a # reserved value for now. if { $ap_num < 16 } { # Enable actionpoint registers for {set i 0} {$i < $ap_num} {incr i} { arc set-reg-exists ap_amv$i ap_amm$i ap_ac$i } # Set amount of actionpoints arc num-actionpoints $ap_num } } } # DCCM set dccm_version [arc get-reg-field dccm_build version] if { $dccm_version == 3 || $dccm_version == 4 } { arc set-reg-exists aux_dccm } # ICCM if { [arc get-reg-field iccm_build version] == 4 } { arc set-reg-exists aux_iccm } # MPU if { [arc get-reg-field mpu_build version] >= 2 && [arc get-reg-field mpu_build version] <= 4 } { arc set-reg-exists mpu_en mpu_ecr set mpu_regions [arc get-reg-field mpu_build regions] for {set i 0} {$i < $mpu_regions} {incr i} { arc set-reg-exists mpu_rdp$i mpu_rdb$i } # Secure MPU if { [arc get-reg-field mpu_build version] == 4 } { arc set-reg-exists mpu_index mpu_rstart mpu_rend mpu_rper } } } proc arc_v2_init_regs { } { # XML features set core_feature "org.gnu.gdb.arc.core.v2" set aux_min_feature "org.gnu.gdb.arc.aux-minimal" set aux_other_feature "org.gnu.gdb.arc.aux-other" # Describe types # Types are sorted alphabetically according to their name. arc add-reg-type-struct -name ap_build_t -bitfield version 0 7 \ -bitfield type 8 11 arc add-reg-type-struct -name ap_control_t -bitfield at 0 3 -bitfield tt 4 5 \ -bitfield m 6 6 -bitfield p 7 7 -bitfield aa 8 8 -bitfield q 9 9 # Cycles field added in version 4. arc add-reg-type-struct -name dccm_build_t -bitfield version 0 7 \ -bitfield size0 8 11 -bitfield size1 12 15 -bitfield cycles 17 19 arc add-reg-type-struct -name debug_t \ -bitfield fh 1 1 -bitfield ah 2 2 -bitfield asr 3 10 \ -bitfield is 11 11 -bitfield ep 19 19 -bitfield ed 20 20 \ -bitfield eh 21 21 -bitfield ra 22 22 -bitfield zz 23 23 \ -bitfield sm 24 26 -bitfield ub 28 28 -bitfield bh 29 29 \ -bitfield sh 30 30 -bitfield ld 31 31 arc add-reg-type-struct -name ecr_t \ -bitfield parameter 0 7 \ -bitfield cause 8 15 \ -bitfield vector 16 23 \ -bitfield U 30 30 \ -bitfield P 31 31 arc add-reg-type-struct -name iccm_build_t -bitfield version 0 7 \ -bitfield iccm0_size0 8 11 -bitfield iccm1_size0 12 15 \ -bitfield iccm0_size1 16 19 -bitfield iccm1_size1 20 23 arc add-reg-type-struct -name identity_t \ -bitfield arcver 0 7 -bitfield arcnum 8 15 -bitfield chipid 16 31 arc add-reg-type-struct -name isa_config_t -bitfield version 0 7 \ -bitfield pc_size 8 11 -bitfield lpc_size 12 15 -bitfield addr_size 16 19 \ -bitfield b 20 20 -bitfield a 21 21 -bitfield n 22 22 -bitfield l 23 23 \ -bitfield c 24 27 -bitfield d 28 31 arc add-reg-type-struct -name mpu_build_t -bitfield version 0 7 \ -bitfield regions 8 15 \ -bitfield s 16 16 \ -bitfield i 17 17 arc add-reg-type-struct -name mpu_ecr_t \ -bitfield MR 0 7 \ -bitfield VT 8 9 \ -bitfield EC_CODE 16 31 arc add-reg-type-struct -name mpu_en_t \ -bitfield UE 3 3 -bitfield UW 4 4 -bitfield UR 5 5 \ -bitfield KE 6 6 -bitfield KW 7 7 -bitfield KR 8 8 \ -bitfield S 15 15 -bitfield SID 16 23 \ -bitfield EN 30 30 arc add-reg-type-struct -name mpu_index_t \ -bitfield I 0 3 -bitfield M 30 30 -bitfield D 31 31 arc add-reg-type-struct -name mpu_rper_t \ -bitfield V 0 0 \ -bitfield UE 3 3 -bitfield UW 4 4 -bitfield UR 5 5 \ -bitfield KE 6 6 -bitfield KW 7 7 -bitfield KR 8 8 \ -bitfield S 15 15 -bitfield SID 16 23 arc add-reg-type-flags -name status32_t \ -flag H 0 -flag E0 1 -flag E1 2 -flag E2 3 \ -flag E3 4 -flag AE 5 -flag DE 6 -flag U 7 \ -flag V 8 -flag C 9 -flag N 10 -flag Z 11 \ -flag L 12 -flag DZ 13 -flag SC 14 -flag ES 15 \ -flag RB0 16 -flag RB1 17 -flag RB2 18 \ -flag AD 19 -flag US 20 -flag IE 31 # Core registers set core_regs { r0 0 uint32 r1 1 uint32 r2 2 uint32 r3 3 uint32 r4 4 uint32 r5 5 uint32 r6 6 uint32 r7 7 uint32 r8 8 uint32 r9 9 uint32 r10 10 uint32 r11 11 uint32 r12 12 uint32 r13 13 uint32 r14 14 uint32 r15 15 uint32 r16 16 uint32 r17 17 uint32 r18 18 uint32 r19 19 uint32 r20 20 uint32 r21 21 uint32 r22 23 uint32 r23 24 uint32 r24 24 uint32 r25 25 uint32 gp 26 data_ptr fp 27 data_ptr sp 28 data_ptr ilink 29 code_ptr r30 30 uint32 blink 31 code_ptr r32 32 uint32 r33 33 uint32 r34 34 uint32 r35 35 uint32 r36 36 uint32 r37 37 uint32 r38 38 uint32 r39 39 uint32 r40 40 uint32 r41 41 uint32 r42 42 uint32 r43 43 uint32 r44 44 uint32 r45 45 uint32 r46 46 uint32 r47 47 uint32 r48 48 uint32 r49 49 uint32 r50 50 uint32 r51 51 uint32 r52 52 uint32 r53 53 uint32 r54 54 uint32 r55 55 uint32 r56 56 uint32 r57 57 uint32 accl 58 uint32 acch 59 uint32 lp_count 60 uint32 limm 61 uint32 reserved 62 uint32 pcl 63 code_ptr } foreach {reg count type} $core_regs { arc add-reg -name $reg -num $count -core -type $type -g \ -feature $core_feature } # AUX min set aux_min { 0x6 pc code_ptr 0x2 lp_start code_ptr 0x3 lp_end code_ptr 0xA status32 status32_t } foreach {num name type} $aux_min { arc add-reg -name $name -num $num -type $type -feature $aux_min_feature -g } # AUX other set aux_other { 0x004 identity identity_t 0x005 debug debug_t 0x018 aux_dccm int 0x208 aux_iccm int 0x220 ap_amv0 uint32 0x221 ap_amm0 uint32 0x222 ap_ac0 ap_control_t 0x223 ap_amv1 uint32 0x224 ap_amm1 uint32 0x225 ap_ac1 ap_control_t 0x226 ap_amv2 uint32 0x227 ap_amm2 uint32 0x228 ap_ac2 ap_control_t 0x229 ap_amv3 uint32 0x22A ap_amm3 uint32 0x22B ap_ac3 ap_control_t 0x22C ap_amv4 uint32 0x22D ap_amm4 uint32 0x22E ap_ac4 ap_control_t 0x22F ap_amv5 uint32 0x230 ap_amm5 uint32 0x231 ap_ac5 ap_control_t 0x232 ap_amv6 uint32 0x233 ap_amm6 uint32 0x234 ap_ac6 ap_control_t 0x235 ap_amv7 uint32 0x236 ap_amm7 uint32 0x237 ap_ac7 ap_control_t 0x400 eret code_ptr 0x401 erbta code_ptr 0x402 erstatus status32_t 0x403 ecr ecr_t 0x404 efa data_ptr 0x409 mpu_en mpu_en_t 0x412 bta code_ptr 0x420 mpu_ecr mpu_ecr_t 0x422 mpu_rdb0 int 0x423 mpu_rdp0 int 0x424 mpu_rdb1 int 0x425 mpu_rdp1 int 0x426 mpu_rdb2 int 0x427 mpu_rdp2 int 0x428 mpu_rdb3 int 0x429 mpu_rdp3 int 0x42A mpu_rdb4 int 0x42B mpu_rdp4 int 0x42C mpu_rdb5 int 0x42D mpu_rdp5 int 0x42E mpu_rdb6 int 0x42F mpu_rdp6 int 0x430 mpu_rdb7 int 0x431 mpu_rdp7 int 0x432 mpu_rdb8 int 0x433 mpu_rdp8 int 0x434 mpu_rdb9 int 0x435 mpu_rdp9 int 0x436 mpu_rdb10 int 0x437 mpu_rdp10 int 0x438 mpu_rdb11 int 0x439 mpu_rdp11 int 0x43A mpu_rdb12 int 0x43B mpu_rdp12 int 0x43C mpu_rdb13 int 0x43D mpu_rdp13 int 0x43E mpu_rdb14 int 0x43F mpu_rdp14 int 0x440 mpu_rdb15 int 0x441 mpu_rdp15 int 0x448 mpu_index mpu_index_t 0x449 mpu_rstart uint32 0x44A mpu_rend uint32 0x44B mpu_rper mpu_rper_t 0x44C mpu_probe uint32 } foreach {num name type} $aux_other { arc add-reg -name $name -num $num -type $type -feature $aux_other_feature } # AUX BCR set bcr { 0x6D mpu_build 0x74 dccm_build 0x76 ap_build 0x78 iccm_build 0xC1 isa_config } foreach {num reg} $bcr { arc add-reg -name $reg -num $num -type ${reg}_t -bcr -feature $aux_other_feature } [target current] configure \ -event examine-end "arc_v2_examine_target [target current]" } proc arc_v2_reset { {target ""} } { arc_common_reset $target # Disable all actionpoints. Cannot write via regcache yet, because it will # not be flushed and all changes to registers will get lost. Therefore has # to write directly via JTAG layer... set num_ap [arc num-actionpoints] for {set i 0} {$i < $num_ap} {incr i} { arc jtag set-aux-reg [expr {0x222 + $i * 3}] 0 } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpu/arm/arm7tdmi.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set CPU_TYPE arm set CPU_NAME arm7tdmi set CPU_ARCH armv4t set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpu/arm/arm920.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set CPU_TYPE arm set CPU_NAME arm920 set CPU_ARCH armv4t set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpu/arm/arm946.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set CPU_TYPE arm set CPU_NAME arm946 set CPU_ARCH armv5te set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpu/arm/arm966.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set CPU_TYPE arm set CPU_NAME arm966 set CPU_ARCH armv5te set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/cpu/arm/cortex_m3.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set CPU_TYPE arm set CPU_NAME cortex_m3 set CPU_ARCH armv7 set CPU_MAX_ADDRESS 0xFFFFFFFF set CPU_NBITS 32 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/altera-10m50.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # file altera-10m50.cfg replaced by altera-max10.cfg echo "DEPRECATED: use altera-max10.cfg instead of deprecated altera-10m50.cfg" #just to be backward compatible: #tap will be 10m50.tap instead of max10.tap: set CHIPNAME 10m50 source [find cpld/altera-max10.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/altera-arriaii.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Intel Arria II FPGA # Arria II Device Handbook # Table 11–2. 32-Bit IDCODE for Arria II Devices #GX: #EP2AGX45: 0x025120dd #EP2AGX65: 0x025020dd #EP2AGX95: 0x025130dd #EP2AGX125: 0x025030dd #EP2AGX190: 0x025140dd #EP2AGX260: 0x025040dd #EP2AGZ225: 0x024810dd #EP2AGZ300: 0x0240a0dd #EP2AGZ350: 0x024820dd if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME arriaii } jtag newtap $_CHIPNAME tap -irlen 10 \ -expected-id 0x025120dd -expected-id 0x025040dd \ -expected-id 0x025020dd -expected-id 0x024810dd \ -expected-id 0x025130dd -expected-id 0x0240a0dd \ -expected-id 0x025030dd -expected-id 0x024820dd \ -expected-id 0x025140dd pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family arriaii ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/altera-cyclone10.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Intel Cyclone 10 FPGA # see: https://www.intel.com/content/www/us/en/docs/programmable/683777/current/bst-operation-control.html # and: https://www.intel.cn/content/dam/support/us/en/programmable/kdb/pdfs/literature/hb/cyclone-10/c10gx-51003.pdf # GX085: 0x02e120dd # GX105: 0x02e320dd # GX150: 0x02e720dd # GX220: 0x02ef20dd # 10cl006: 0x020f10dd # 10cl010: 0x020f10dd # 10cl016: 0x020f20dd # 10cl025: 0x020f30dd # 10cl040: 0x020f40dd # 10cl055: 0x020f50dd # 10cl080: 0x020f60dd # 10cl120: 0x020f70dd if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cyclone10 } jtag newtap $_CHIPNAME tap -irlen 10 \ -expected-id 0x02e720dd -expected-id 0x02e120dd \ -expected-id 0x02ef20dd -expected-id 0x02e320dd \ -expected-id 0x020f10dd -expected-id 0x020f20dd \ -expected-id 0x020f30dd -expected-id 0x020f40dd \ -expected-id 0x020f50dd -expected-id 0x020f60dd \ -expected-id 0x020f70dd pld device intel $_CHIPNAME.tap cyclone10 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/altera-cycloneiii.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Intel Cyclone III FPGA # see Cyclone III Device Handbook # Table 12-2: Device IDCODE for Cyclone III Device Family #EP3C5 0x020f10dd #EP3C10 0x020f10dd #EP3C16 0x020f20dd #EP3C25 0x020f30dd #EP3C40 0x020f40dd #EP3C55 0x020f50dd #EP3C80 0x020f60dd #EP3C120 0x020f70dd #Cyclone III LS #EP3CLS70 0x027010dd #EP3CLS100 0x027000dd #EP3CLS150 0x027030dd #EP3CLS200 0x027020dd if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cycloneiii } jtag newtap $_CHIPNAME tap -irlen 10 \ -expected-id 0x020f10dd -expected-id 0x020f20dd \ -expected-id 0x020f30dd -expected-id 0x020f40dd \ -expected-id 0x020f50dd -expected-id 0x020f60dd \ -expected-id 0x020f70dd -expected-id 0x027010dd \ -expected-id 0x027000dd -expected-id 0x027030dd \ -expected-id 0x027020dd pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cycloneiii ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/altera-cycloneiv.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Intel Cyclone IV FPGA # see Cyclone IV Device Handbook # Table 10-2: IDCODE Information for 32-Bit Cyclone IV Devices #EP4CE6 0x020f10dd #EP4CE10 0x020f10dd #EP4CE15 0x020f20dd #EP4CE22 0x020f30dd #EP4CE30 0x020f40dd #EP4CE40 0x020f40dd #EP4CE55 0x020f50dd #EP4CE75 0x020f60dd #EP4CE115 0x020f70dd #EP4CGX15 0x028010dd #EP4CGX22 0x028120dd #EP4CGX30 (3) 0x028020dd #EP4CGX30 (4) 0x028230dd #EP4CGX50 0x028130dd #EP4CGX75 0x028030dd #EP4CGX110 0x028140dd #EP4CGX150 0x028040dd if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cycloneiv } jtag newtap $_CHIPNAME tap -irlen 10 \ -expected-id 0x020f10dd -expected-id 0x020f20dd \ -expected-id 0x020f30dd -expected-id 0x020f40dd \ -expected-id 0x020f50dd -expected-id 0x020f60dd \ -expected-id 0x020f70dd -expected-id 0x028010dd \ -expected-id 0x028120dd -expected-id 0x028020dd \ -expected-id 0x028230dd -expected-id 0x028130dd \ -expected-id 0x028030dd -expected-id 0x028140dd \ -expected-id 0x028040dd pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cycloneiv ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/altera-cyclonev.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Intel Cyclone 5 FPGA # see Cyclone V Device Handbook # Table 9-1: IDCODE Information for Cyclone V Devices #5CEA2 0x02b150dd #5CEA4 0x02b050dd #5CEA5 0x02b220dd #5CEA7 0x02b130dd #5CEA9 0x02b140dd #5CGXC3 0x02b010dd #5CGXC4 0x02b120dd #5CGXC5 0x02b020dd #5CGXC7 0x02b030dd #5CGXC9 0x02b040dd #5CGTD5 0x02b020dd #5CGTD7 0x02b030dd #5CGTD9 0x02b040dd #5CSEA2 0x02d110dd #5CSEA4 0x02d010dd #5CSEA5 0x02d120dd #5CSEA6 0x02d020dd #5CSXC2 0x02d110dd #5CSXC4 0x02d010dd #5CSXC5 0x02d120dd #5CSXC6 0x02d020dd #5CSTD5 0x02d120dd #5CSTD6 0x02d020dd if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cyclonev } jtag newtap $_CHIPNAME tap -irlen 10 \ -expected-id 0x02b150dd -expected-id 0x02b050dd \ -expected-id 0x02b220dd -expected-id 0x02b130dd \ -expected-id 0x02b140dd -expected-id 0x02b010dd \ -expected-id 0x02b120dd -expected-id 0x02b020dd \ -expected-id 0x02b030dd -expected-id 0x02b040dd \ -expected-id 0x02d110dd -expected-id 0x02d010dd \ -expected-id 0x02d120dd -expected-id 0x02d020dd pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cyclonev ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/altera-ep3c10.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # file altera-ep3c10.cfg replaced by altera-cycloneiii.cfg echo "DEPRECATED: use altera-cycloneiii.cfg instead of deprecated altera-ep3c10.cfg" #just to be backward compatible: #tap will be ep3c10.tap instead of cycloneiii.tap: set CHIPNAME ep3c10 source [find fpga/altera-cycloneiii.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/efinix_titanium.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # efinix titanium # https://www.efinixinc.com/docs/an048-jtag-bst-titanium-v1.0.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME titanium } jtag newtap $_CHIPNAME tap -irlen 5 -ignore-version \ -expected-id 0x10661A79 \ -expected-id 0x00360A79 \ -expected-id 0x10660A79 \ -expected-id 0x00681A79 \ -expected-id 0x00688A79 \ -expected-id 0x00682A79 \ -expected-id 0x0068CA79 \ -expected-id 0x00680A79 \ -expected-id 0x00684A79 pld create $_CHIPNAME.pld efinix -chain-position $_CHIPNAME.tap -family titanium ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/efinix_trion.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # efinix trion # https://www.efinixinc.com/docs/an021-jtag-bst-trion-v1.0.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME trion } jtag newtap $_CHIPNAME tap -irlen 4 -ignore-version \ -expected-id 0x00210A79 \ -expected-id 0x00240A79 \ -expected-id 0x00220A79 pld create $_CHIPNAME.pld efinix -chain-position $_CHIPNAME.tap -family trion ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/gatemate.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # GateMateTM FPGA # https://www.colognechip.com/programmable-logic/gatemate/ # https://colognechip.com/docs/ds1001-gatemate1-datasheet-latest.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME gatemate } jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ -expected-id 0x20000001 pld create $_CHIPNAME.pld gatemate -chain-position $_CHIPNAME.tap ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/gowin_gw1n.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Gowin FPGA IDCODEs # from JTAG Programming and Configuration Guide # http://cdn.gowinsemi.com.cn/TN653E.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME gw1n } jtag newtap $_CHIPNAME tap -irlen 8 -ignore-version \ -expected-id 0x0900281B \ -expected-id 0x0900381B \ -expected-id 0x0100681B \ -expected-id 0x0300081B \ -expected-id 0x0300181B \ -expected-id 0x0120681B \ -expected-id 0x0100381B \ -expected-id 0x1100381B \ -expected-id 0x0100981B \ -expected-id 0x1100581B \ -expected-id 0x1100481B \ -expected-id 0x0100181B \ -expected-id 0x1100181B \ -expected-id 0x0100481B pld create $_CHIPNAME.pld gowin -chain-position $_CHIPNAME.tap ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/lattice_certus.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME certus } # Lattice Certus # # Certus NX LFD2NX-17 0x310f0043 # Certus NX LFD2NX-40 0x310f1043 jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ -expected-id 0x310F1043 -expected-id 0x310F0043 pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/lattice_certuspro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME certuspro } # Lattice CertusPro # # 0x010f4043 - LFCPNX-100 # 0x 043 - LFCPNX-50 jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ -expected-id 0x010f4043 # -expected-id 0x01112043 pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/lattice_ecp2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME ecp2 } # Lattice ECP2 family # TAP IDs are extracted from BSDL files found on this page: # https://www.latticesemi.com/Products/FPGAandCPLD/LatticeECP2M # # LFE2M20E: 0x01279043 # LFE2M35E: 0x0127A043 # LFE2M50E: 0x0127B043 # LFE2M70E: 0x0127C043 # LFE2M100E: 0x0127D043 # LFEC2_6E: 0x01270043 # LFEC2_12E: 0x01271043 # LFEC2_20E: 0x01272043 # LFEC2_35E: 0x01274043 # LFEC2_50E: 0x01273043 # LFEC2_70E: 0x01275043 jtag newtap $_CHIPNAME tap -irlen 8 \ -expected-id 0x01279043 -expected-id 0x0127A043 -expected-id 0x0127B043 \ -expected-id 0x0127C043 -expected-id 0x0127D043 -expected-id 0x01270043 \ -expected-id 0x01271043 -expected-id 0x01272043 -expected-id 0x01274043 \ -expected-id 0x01273043 -expected-id 0x01275043 pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/lattice_ecp3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME ecp3 } # Lattice ECP3 family # TAP IDs are extracted from BSDL files found on this page: # https://www.latticesemi.com/Products/FPGAandCPLD/LatticeECP3 # # LFE3_17: 0x01010043 # LFE3_35: 0x01012043 # LFE3_95: 0x01014043 and LFE3_70 # LFE3_150: 0x01015043 jtag newtap $_CHIPNAME tap -irlen 8 \ -expected-id 0x01010043 -expected-id 0x01012043 \ -expected-id 0x01014043 -expected-id 0x01015043 pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/lattice_ecp5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME ecp5 } # Lattice ECP5 family # TAP IDs are extracted from BSDL files found on this page: # https://www.latticesemi.com/Products/FPGAandCPLD/ECP5 # # 0x01111043 - LAE5UM_25F/LFE5UM_25F # 0x01112043 - LAE5UM_45F/LFE5UM_45F # 0x01113043 - LAE5UM_85F/LFE5UM_85 # 0x21111043 - LFE5U_12F # 0x41111043 - LFE5U_25F # 0x41112043 - LFE5U_45F # 0x41113043 - LFE5U_85F # 0x81111043 - LFE5UM5G-25 # 0x81112043 - LFE5UM5G-45 # 0x81113043 - LFE5UM5G-85 jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ -expected-id 0x01111043 -expected-id 0x01112043 -expected-id 0x01113043 \ -expected-id 0x21111043 -expected-id 0x41111043 -expected-id 0x41112043 \ -expected-id 0x41113043 -expected-id 0x81111043 -expected-id 0x81112043 \ -expected-id 0x81113043 pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/lattice_machxo3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME machxo3 } # Lattice MachXO3 family # TAP IDs are extracted from BSDL files found on this page: # https://www.latticesemi.com/Products/FPGAandCPLD/MachXO3 # # 0x412b2043 - LCMXO3L_1300E_XXUWG36/XXMG121 # 0x412b3043 - LCMXO3L_2100E_XXMG121/XXMG256/XXUWG49 # 0x412b4043 - LCMXO3L_4300E_XXMG121/XXMG324/XXUWG81 # 0x412b5043 - LCMXO3L_6900E_XXMG256/XXMG324 # 0x412b6043 - LCMXO3L_9400E_XXBG256/XXMG256 # 0x412bb043 - LCMXO3L_2100C_XXBG256 # 0x412bc043 - LCMXO3L_4300C_XXBG256/XXBG324 # 0x412bd043 - LCMXO3L_6900C_XXBG256/XXBG324/XXBG400 # 0x412be043 - LCMXO3L_9400C_XXBG256/XXBG400/XXBG484 # 0x612b2043 - LCMXO3LF_1300E_XXMG121/XXUWG36 # 0x612b3043 - LCMXO3LF_2100E_XXMG121/XXMG256/XXUWG49 # 0x612b4043 - LCMXO3LF_4300E_XXMG121/XXMG256/XXMG324/XXUWG81 # 0x612b5043 - LCMXO3LF_6900E_XXMG256/XXMG324 # 0x612b6043 - LCMXO3LF_9400E_XXBG256/XXMG256 # 0x612bb043 - LCMXO3LF_2100C_XXBG256 # 0x612bc043 - LCMXO3LF_4300C_XXBG256/XXBG324 # 0x612bd043 - LCMXO3LF_6900C_XXBG256/XXBG324/XXBG400 # 0x612be043 - LCMXO3LF_9400C_XXBG256/XXBG400/XXBG484 # 0xc12b2043 - LCMXO3L_640E_XXMG121 # 0xc12b4043 - LCMXO3L_2100E_XXMG324 # 0xc12bb043 - LCMXO3L_1300C_XXBG256/XXMG256 # 0xc12bc043 - LCMXO3L_2100C_XXBG324 # 0xc12bd043 - LCMXO3L_4300C_XXBG400 # 0xe12b2043 - LCMXO3LF_640E_XXMG121 # 0xe12b3043 - LCMXO3LF_1300E_XXMG256 # 0xe12b4043 - LCMXO3LF_2100E_XXMG324 # 0xe12bb043 - LCMXO3LF_1300C_XXBG256 # 0xe12bc043 - LCMXO3LF_2100C_XXBG324 # 0xe12bd043 - LCMXO3LF_4300C_XXBG400 jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ -expected-id 0x412b2043 -expected-id 0x412b3043 -expected-id 0x412b4043 \ -expected-id 0x412b5043 -expected-id 0x412b6043 -expected-id 0x412bb043 \ -expected-id 0x412bc043 -expected-id 0x412bd043 -expected-id 0x412be043 \ -expected-id 0x612b2043 -expected-id 0x612b3043 -expected-id 0x612b4043 \ -expected-id 0x612b5043 -expected-id 0x612b6043 -expected-id 0x612bb043 \ -expected-id 0x612bc043 -expected-id 0x612bd043 -expected-id 0x612be043 \ -expected-id 0xc12b2043 -expected-id 0xc12b4043 -expected-id 0xc12bb043 \ -expected-id 0xc12bc043 -expected-id 0xc12bd043 -expected-id 0xe12b2043 \ -expected-id 0xe12b3043 -expected-id 0xe12b4043 -expected-id 0xe12bb043 \ -expected-id 0xe12bc043 -expected-id 0xe12bd043 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/xilinx-dna.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later proc xilinx_dna_addr {chip} { array set addrs { Spartan6 0x30 Series7 0x17 } return $addrs($chip) } # Get the "Device DNA". # Most Xilinx FPGA devices contain an embedded, unique device identifier. # The identifier is nonvolatile, permanently programmed into # the FPGA, and is unchangeable providing a great serial / tracking number. # This function returns the DNA as a 64 bit integer with the 7 LSBs zeroed. # This is compatible with the FUSE DNA which contains all 64 bits. proc xilinx_get_dna {tap chip} { set XC7_ISC_ENABLE 0x10 set XC7_ISC_DISABLE 0x16 set XC7_ISC_DNA [xilinx_dna_addr $chip] irscan $tap $XC7_ISC_ENABLE runtest 64 irscan $tap $XC7_ISC_DNA scan [drscan $tap 32 0 32 0] "%08x %08x" hi lo runtest 64 irscan $tap $XC7_ISC_DISABLE runtest 64 # openocd interprets DR scans as LSB first, bit-reverse it return [scan [string reverse [format "%032b%032bb0" $lo $hi]] "%i"] } # Print out the "Device DNA" in the same format that impact uses. proc xilinx_print_dna {dna} { set dna [expr {$dna >> 64 - 57}] echo [format "DNA = %057b (0x%016x)" $dna $dna] } proc xc7_get_dna {tap} { return [xilinx_get_dna $tap Series7] } proc xc6s_get_dna {tap} { return [xilinx_get_dna $tap Spartan6] } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/fpga/xilinx-xadc.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Xilinx XADC support for 7 Series FPGAs # # The 7 Series FPGAs contain an on-chip 12 bit ADC that can probe die # temperature, internal power supply rail voltages as well as external # voltages. The XADC is available both from fabric as well as through the # JTAG TAP. # # This code implements access through the JTAG TAP. # # https://www.xilinx.com/support/documentation/user_guides/ug480_7Series_XADC.pdf # build a 32 bit DRP command for the XADC DR proc xadc_cmd {cmd addr data} { array set cmds { NOP 0x00 READ 0x01 WRITE 0x02 } return [expr {($cmds($cmd) << 26) | ($addr << 16) | ($data << 0)}] } # XADC register addresses # Some addresses (status registers 0-3) have special function when written to. proc XADC {key} { array set addrs { TEMP 0x00 LOCK 0x00 VCCINT 0x01 VCCAUX 0x02 VAUXEN 0x02 VPVN 0x03 RESET 0x03 VREFP 0x04 VREFN 0x05 VCCBRAM 0x06 SUPAOFFS 0x08 ADCAOFFS 0x09 ADCAGAIN 0x0a VCCPINT 0x0d VCCPAUX 0x0e VCCODDR 0x0f VAUX0 0x10 VAUX1 0x11 VAUX2 0x12 VAUX3 0x13 VAUX4 0x14 VAUX5 0x15 VAUX6 0x16 VAUX7 0x17 VAUX8 0x18 VAUX9 0x19 VAUX10 0x1a VAUX11 0x1b VAUX12 0x1c VAUX13 0x1d VAUX14 0x1e VAUX15 0x1f SUPBOFFS 0x30 ADCBOFFS 0x31 ADCBGAIN 0x32 FLAG 0x3f CFG0 0x40 CFG1 0x41 CFG2 0x42 SEQ0 0x48 SEQ1 0x49 SEQ2 0x4a SEQ3 0x4b SEQ4 0x4c SEQ5 0x4d SEQ6 0x4e SEQ7 0x4f ALARM0 0x50 ALARM1 0x51 ALARM2 0x52 ALARM3 0x53 ALARM4 0x54 ALARM5 0x55 ALARM6 0x56 ALARM7 0x57 ALARM8 0x58 ALARM9 0x59 ALARM10 0x5a ALARM11 0x5b ALARM12 0x5c ALARM13 0x5d ALARM14 0x5e ALARM15 0x5f } return $addrs($key) } # Select the XADC DR proc xadc_select {tap} { set XADC_IR 0x37 irscan $tap $XADC_IR runtest 10 } # XADC transfer proc xadc_xfer {tap cmd addr data} { set ret [drscan $tap 32 [xadc_cmd $cmd $addr $data]] runtest 10 return [expr "0x$ret"] } # XADC register write proc xadc_write {tap addr data} { xadc_xfer $tap WRITE $addr $data } # XADC register read, non-pipelined proc xadc_read {tap addr} { xadc_xfer $tap READ $addr 0 return [xadc_xfer $tap NOP 0 0] } # convert 16 bit register code from ADC measurement on # external voltages (VAUX) to Volt proc xadc_volt {code} { return [expr {$code * 1./(1 << 16)}] } # convert 16 bit temperature measurement to Celsius proc xadc_temp {code} { return [expr {$code * 503.975/(1 << 16) - 273.15}] } # convert 16 bit suppply voltage measurement to Volt proc xadc_sup {code} { return [expr {$code * 3./(1 << 16)}] } # perform a single channel measurement using default settings proc xadc_single {tap ch} { set cfg0 [xadc_read $tap [XADC CFG0]] set cfg1 [xadc_read $tap [XADC CFG1]] # set channel xadc_write $tap [XADC CFG0] $cfg0 # single channel, disable the sequencer xadc_write $tap [XADC CFG1] 0x3000 # leave some time for the conversion runtest 100 set ret [xadc_read $tap [XADC $ch]] # restore CFG0/1 xadc_write $tap [XADC CFG0] $cfg0 xadc_write $tap [XADC CFG1] $cfg1 return $ret } # measure all internal voltages proc xadc_report {tap} { xadc_select $tap echo "TEMP [format %.2f [xadc_temp [xadc_single $tap TEMP]]] C" foreach ch [list VCCINT VCCAUX VCCBRAM VPVN VREFP VREFN \ VCCPINT VCCPAUX VCCODDR] { echo "$ch [format %.3f [xadc_sup [xadc_single $tap $ch]]] V" } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/altera-usb-blaster.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Altera USB-Blaster # # http://www.altera.com/literature/ug/ug_usb_blstr.pdf # adapter driver usb_blaster usb_blaster lowlevel_driver ftdi # These are already the defaults. # usb_blaster vid_pid 0x09FB 0x6001 # usb_blaster device_desc "USB-Blaster" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/altera-usb-blaster2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Altera USB-Blaster II # adapter driver usb_blaster usb_blaster vid_pid 0x09fb 0x6010 0x09fb 0x6810 usb_blaster lowlevel_driver ublast2 usb_blaster firmware /path/to/quartus/blaster_6810.hex ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/arm-jtag-ew.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Olimex ARM-JTAG-EW # # http://www.olimex.com/dev/arm-jtag-ew.html # adapter driver arm-jtag-ew ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ast2600-gpiod.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Use AST2600 GPIO through linuxgpiod # # +-----------+-------------+-------------+ # | signal | GPIO name | gpio offset | # +-----------+-------------+-------------+ # | TCK/SWCLK | GPIOI2 | 66 | # | TMS/SWDIO | GPIOI3 | 67 | # | TDI | GPIOI1 | 65 | # | TDO | GPIOI4 | 68 | # | nTRST | GPIOI0 | 64 | # +-----------+-------------+-------------+ adapter driver linuxgpiod adapter gpio trst 64 -chip 0 adapter gpio tdi 65 -chip 0 adapter gpio tck 66 -chip 0 adapter gpio swclk 66 -chip 0 adapter gpio tms 67 -chip 0 adapter gpio swdio 67 -chip 0 adapter gpio tdo 68 -chip 0 reset_config trst_only separate trst_push_pull ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/at91rm9200.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Various Atmel AT91RM9200 boards # # TODO: URL? # adapter driver at91rm9200 at91rm9200_device rea_ecr ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/beaglebone-jtag-native.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # BeagleBone native GPIO interface for JTAG # # This is best used with a fast buffer but it is also suitable for a direct # connection if the target voltage matches the host's IO voltage (typically # 3.3V) and the cable is short. # # DO NOT APPLY VOLTAGE TO THE GPIO PINS UNTIL SYS_RESETN IS HIGH. # # Do not forget the GND connection. adapter driver am335xgpio # Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET # These depend on the system clock, calibrated for stock 1 GHz BeagleBoneBlack # am335xgpio speed SPEED_COEFF SPEED_OFFSET am335xgpio speed_coeffs 600000 575 # BeagleBone pin P9_41 adapter gpio tdo 20 -chip 0 # BeagleBone pin P9_12 adapter gpio tdi 28 -chip 1 # BeagleBone pin P9_18 adapter gpio tms 4 -chip 0 # BeagleBone pin P9_22 adapter gpio tck 2 -chip 0 # BeagleBone pin P9_16 adapter gpio led 19 -chip 1 # BeagleBone pin P8_18 adapter gpio srst 1 -chip 2 reset_config srst_only srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/beaglebone-swd-native.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # BeagleBone native GPIO interface for SWD # # This is best used with a fast buffer but it is also suitable for a direct # connection if the target voltage matches the host's IO voltage (typically # 3.3V) and the cable is short. # # DO NOT APPLY VOLTAGE TO THE GPIO PINS UNTIL SYS_RESETN IS HIGH. # # Do not forget the GND connection. adapter driver am335xgpio # Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET # These depend on the system clock, calibrated for stock 1 GHz BeagleBoneBlack # am335xgpio speed SPEED_COEFF SPEED_OFFSET am335xgpio speed_coeffs 600000 575 # BeagleBone pin P9_22 adapter gpio swclk 2 -chip 0 # BeagleBone pin P9_18 adapter gpio swdio 4 -chip 0 # BeagleBone pin P9_12 adapter gpio swdio_dir 28 -chip 1 # USR0 LED adapter gpio led 21 -chip 1 # BeagleBone pin P8_18 adapter gpio srst 1 -chip 2 reset_config srst_only srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/buspirate.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Buspirate with OpenOCD support # # http://dangerousprototypes.com/bus-pirate-manual/ # adapter driver buspirate # you need to specify port on which BP lives #buspirate port /dev/ttyUSB0 # communication speed setting buspirate speed normal ;# or fast # voltage regulator Enabled = 1 Disabled = 0 #buspirate vreg 0 # pin mode normal or open-drain (jtag only) #buspirate mode normal # pullup state Enabled = 1 Disabled = 0 #buspirate pullup 0 # this depends on the cable, you are safe with this option reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/chameleon.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Amontec Chameleon POD # # http://www.amontec.com/chameleon.shtml # adapter driver parport parport cable chameleon ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/cmsis-dap.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # ARM CMSIS-DAP compliant adapter # # http://www.keil.com/support/man/docs/dapdebug/ # adapter driver cmsis-dap # Optionally specify the serial number of CMSIS-DAP usb device. # adapter serial 02200201E6661E601B98E3B9 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/dln-2-gpiod.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Use DLN-2 GPIO through linuxgpiod # # +-----------+-------------+-------------+ # | signal | DLN-2 | gpio offset | # +-----------+-------------+-------------+ # | nSRST | J3.1 (PA0) | 0 | # | TDO | J3.2 (PA1) | 1 | # | TCK/SWCLK | J3.3 (PA2) | 2 | # | TMS/SWDIO | J3.4 (PA3) | 3 | # | TDI | J3.5 (PA4) | 4 | # | nTRST | J3.6 (PA5) | 5 | # | LED | J3.7 (PA6) | 6 | # | GND | J3.12 (GND) | | # +-----------+-------------+-------------+ adapter driver linuxgpiod adapter gpio srst 0 -chip 0 adapter gpio tdo 1 -chip 0 adapter gpio tck 2 -chip 0 adapter gpio swclk 2 -chip 0 adapter gpio tms 3 -chip 0 adapter gpio swdio 3 -chip 0 adapter gpio tdi 4 -chip 0 adapter gpio trst 5 -chip 0 adapter gpio led 6 -chip 0 reset_config trst_and_srst separate srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/dummy.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Dummy interface (for testing purposes) # adapter driver dummy ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/esp_usb_bridge.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # ESP USB Bridge jtag adapter # adapter driver esp_usb_jtag espusbjtag vid_pid 0x303a 0x1002 espusbjtag caps_descriptor 0x030A # string descriptor index:10 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/esp_usb_jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Espressif builtin USB-JTAG adapter # adapter driver esp_usb_jtag espusbjtag vid_pid 0x303a 0x1001 espusbjtag caps_descriptor 0x2000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/estick.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # eStick # # http://code.google.com/p/estick-jtag/ # adapter driver opendous ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/flashlink.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # ST FlashLINK JTAG parallel cable # # http://www.st.com/internet/evalboard/product/94023.jsp # http://www.st.com/stonline/products/literature/um/7889.pdf # if { [info exists PARPORTADDR] } { set _PARPORTADDR $PARPORTADDR } else { set _PARPORTADDR 0 } adapter driver parport parport port $_PARPORTADDR parport cable flashlink ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ft232r/radiona_ulx3s.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # This adapter is integrated in to Radiona ULX3S board: # board/radiona_ulx3s.cfg # See schematics for the ft232r layout: # https://github.com/emard/ulx3s/blob/master/doc/schematics_v316.pdf adapter driver ft232r adapter speed 1000 ft232r vid_pid 0x0403 0x6015 ft232r tck_num DSR ft232r tms_num DCD ft232r tdi_num RI ft232r tdo_num CTS ft232r trst_num RTS ft232r srst_num DTR ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ft232r.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later adapter driver ft232r adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/100ask-openjtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # www.100ask.org OpenJTAG # # http://www.100ask.net/OpenJTAG.html # # Schematics are available from # https://blog.matthiasbock.net/wp-content/uploads/2015/04/100ask-JTAGv3.pdf # adapter driver ftdi ftdi device_desc "USB<=>JTAG&RS232" ftdi vid_pid 0x1457 0x5118 ftdi layout_init 0x0f08 0x0f1b ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/ashling-opella-ld-jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Ashling Opella-LD # # https://www.ashling.com/Opella-LD/ # adapter driver ftdi ftdi device_desc "Opella-LD Debug Probe" ftdi vid_pid 0x0B6B 0x0040 ftdi tdo_sample_edge falling ftdi layout_init 0x0A68 0xFF7B ftdi channel 0 ftdi layout_signal JTAGOE -ndata 0x0010 ftdi layout_signal nTRST -data 0x0020 ftdi layout_signal nSRST -data 0x0040 ftdi layout_signal SWD_EN -data 0x0100 ftdi layout_signal SWDIO_OE -data 0x0200 ftdi layout_signal LED -ndata 0x0800 transport select jtag ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/ashling-opella-ld-swd.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Ashling Opella-LD # # https://www.ashling.com/Opella-LD/ # adapter driver ftdi ftdi device_desc "Opella-LD Debug Probe" ftdi vid_pid 0x0B6B 0x0040 ftdi layout_init 0x0860 0x0b7b ftdi channel 0 ftdi layout_signal JTAGOE -data 0x0010 ftdi layout_signal nTRST -data 0x0020 ftdi layout_signal nSRST -data 0x0040 ftdi layout_signal SWD_EN -data 0x0100 ftdi layout_signal SWDIO_OE -data 0x0200 ftdi layout_signal LED -ndata 0x0800 transport select swd ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/axm0432.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Axiom axm0432 # # http://www.axman.com # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "Symphony SoundBite" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0c08 0x0c2b ftdi layout_signal nTRST -data 0x0800 ftdi layout_signal nSRST -data 0x0400 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/c232hm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # FTDI USB Hi-Speed to MPSSE Cable # # http://www.ftdichip.com/Products/Cables/USBMPSSE.htm # # C232HM-DDHSL-0 and C232HM-EDSL-0 provide 3.3V and 5V on pin 1 (Red), # respectively. # # Adapter: http://www.ftdichip.com/Support/Documents/DataSheets/Cables/DS_C232HM_MPSSE_CABLE.PDF # Chip: http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232H.pdf # See pinout/colors at end of this file. # # Tech notes: # http://www.ftdichip.com/Support/Documents/AppNotes/AN_135_MPSSE_Basics.pdf # http://www.ftdichip.com/Support/Documents/AppNotes/AN_129_FTDI_Hi_Speed_USB_To_JTAG_Example.pdf adapter driver ftdi #ftdi device_desc "C232HM-DDHSL-0" #ftdi device_desc "C232HM-EDHSL-0" # Common PID for FT232H ftdi vid_pid 0x0403 0x6014 # Layout # High data byte 0x40 configures red LED on ACBUS6 initially high (unlit, since active-low) # Low data byte 0x08 configures TMS on ACBUS3 initially high (asserted); TCK, TDI low # High direction byte 0x40 configures red LED on ACBUS6 as high (output) # Low direction byte 0x0b configures TDO on ACBUS2 as low (input) ftdi layout_init 0x4008 0x400b # ---A*BUS-------CCCCCCCC|DDDDDDDD # --------\______76543210|76543210 # LED 0x4000 = 01000000|00000000 = ACBUS6 #GPIOL0 0x0010 = 00000000|00010000 = ADBUS4 #GPIOL1 0x0020 = 00000000|00100000 = ADBUS5 #GPIOL2 0x0040 = 00000000|01000000 = ADBUS6 #GPIOL3 0x0080 = 00000000|10000000 = ADBUS7 # -ndata treats the LED as active-low for expected behavior (toggle when transferring) ftdi layout_signal LED -ndata 0x4000 # Available for aliasing as desired ftdi layout_signal GPIOL0 -data 0x0010 -oe 0x0010 ftdi layout_signal GPIOL1 -data 0x0020 -oe 0x0020 ftdi layout_signal GPIOL2 -data 0x0040 -oe 0x0040 ftdi layout_signal GPIOL3 -data 0x0080 -oe 0x0080 # C232HM FT232H JTAG/Other # Num Color Name Func # 1 Red VCC Optionally, can power the board if it is not using its own power supply. # 2 Orange ADBUS0 TCK # 3 Yellow ADBUS1 TDI # 4 Green ADBUS2 TDO # 5 Brown ADBUS3 TMS # 6 Grey ADBUS4 GPIOL0 # 7 Purple ADBUS5 GPIOL1 # 8 White ADBUS6 GPIOL2 # 9 Blue ADBUS7 GPIOL3 # 10 Black GND Connect to ground ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/cortino.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Hitex Cortino # # http://www.hitex.com/index.php?id=cortino # adapter driver ftdi ftdi device_desc "Cortino" ftdi vid_pid 0x0640 0x0032 ftdi layout_init 0x0108 0x010b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0200 -oe 0x0200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/digilent-hs1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # this supports JTAG-HS1 and JTAG-SMT1 # (the later being the OEM on-board version) adapter driver ftdi ftdi device_desc "Digilent Adept USB Device" ftdi vid_pid 0x0403 0x6010 # channel 1 does not have any functionality ftdi channel 0 # just TCK TDI TDO TMS, no reset ftdi layout_init 0x0088 0x008b reset_config none ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/digilent-hs2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # this supports JTAG-HS2 (and apparently Nexys4 as well) adapter driver ftdi ftdi device_desc "Digilent Adept USB Device" ftdi vid_pid 0x0403 0x6014 ftdi channel 0 ftdi layout_init 0x00e8 0x60eb reset_config none ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/digilent_jtag_hs3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Digilent JTAG-HS3 # adapter driver ftdi ftdi vid_pid 0x0403 0x6014 ftdi device_desc "Digilent USB Device" # From Digilent support: # The SRST pin is [...] 0x20 and 0x10 is the /OE (active low output enable) ftdi layout_init 0x2088 0x308b ftdi layout_signal nSRST -data 0x2000 -noe 0x1000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/digilent_jtag_smt2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Digilent JTAG-SMT2 # # http://www.digilentinc.com/Products/Detail.cfm?NavPath=2,395,1053&Prod=JTAG-SMT2 # # Config is based on data from # http://electronix.ru/forum/index.php?showtopic=114633&view=findpost&p=1215497 and ZedBoard schematics # adapter driver ftdi ftdi vid_pid 0x0403 0x6014 ftdi layout_init 0x20e8 0x3feb ftdi layout_signal nSRST -data 0x2000 ftdi layout_signal GPIO2 -data 0x2000 ftdi layout_signal GPIO1 -data 0x0200 ftdi layout_signal GPIO0 -data 0x0100 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Digilent JTAG-SMT2-NC # # http://store.digilentinc.com/jtag-smt2-nc-surface-mount-programming-module/ # https://reference.digilentinc.com/_media/jtag_smt2nc/jtag-smt2-nc_rm.pdf # # Based on reference sheet (above) and Xilinx KCU105 schematics # https://www.xilinx.com/products/boards-and-kits/kcu105.html#documentation # # Note that the digilent_jtag_smt2 layout does not work and hangs while # the ftdi device_desc from digilent_hs2 is wrong. adapter driver ftdi ftdi device_desc "Digilent USB Device" ftdi vid_pid 0x0403 0x6014 ftdi channel 0 ftdi layout_init 0x00e8 0x60eb reset_config none ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/dlp-usb1232h.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # DLP Design DLP-USB1232H USB-to-UART/FIFO interface module # # http://www.dlpdesign.com/usb/usb1232h.shtml # # Schematics for OpenOCD usage: # http://randomprojects.org/wiki/DLP-USB1232H_and_OpenOCD_based_JTAG_adapter # echo "WARNING!" echo "This file was not tested with real interface, it is based on schematics and code" echo "in ft2232.c. Please report your experience with this file to openocd-devel" echo "mailing list, so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/dp_busblaster.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Dangerous Prototypes - Bus Blaster # # The Bus Blaster has a configurable buffer between the FTDI FT2232H and the # JTAG header which allows it to emulate various debugger types. It comes # configured as a JTAGkey device. # # http://dangerousprototypes.com/docs/Bus_Blaster # echo "Info : If you need SWD support, flash KT-Link buffer from https://github.com/bharrisau/busblaster and use dp_busblaster_kt-link.cfg instead" adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/dp_busblaster_kt-link.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Dangerous Prototypes - Bus Blaster (with KT-Link buffer) # # The Bus Blaster has a configurable buffer between the FTDI FT2232H # and the JTAG header which allows it to emulate various debugger # types. This config works with KT-Link compatible implementation from # https://github.com/bharrisau/busblaster and is SWD-enabled. # # http://dangerousprototypes.com/docs/Bus_Blaster # adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x8c28 0xff3b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ftdi layout_signal LED -ndata 0x8000 ftdi layout_signal SWD_EN -ndata 0x0020 -oe 0x2000 ftdi layout_signal SWDIO_OE -ndata 0x1000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/esp32_devkitj_v1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Driver for the FT2232H JTAG chip on the Espressif DevkitJ board # (and most other FT2232H and FT232H based boards) # adapter driver ftdi ftdi vid_pid 0x0403 0x6010 0x0403 0x6014 # interface 1 is the uart ftdi channel 0 # TCK, TDI, TDO, TMS: ADBUS0-3 # LEDs: ACBUS4-7 ftdi layout_init 0x0008 0xf00b ftdi layout_signal LED -data 0x1000 ftdi layout_signal LED2 -data 0x2000 ftdi layout_signal LED3 -data 0x4000 ftdi layout_signal LED4 -data 0x8000 # ESP32 series chips do not have a TRST input, and the SRST line is connected to the EN pin. # The target code doesn't handle SRST reset properly yet, so this is commented out: # ftdi layout_signal nSRST -oe 0x0020 # reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/esp32s2_kaluga_v1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Driver for the FT2232H JTAG chip on the Espressif Kaluga-1 ESP32-S2 board # (and most other FT2232H and FT232H based boards) # # JTAG DIP switch (labelled SW5 in the schematic) should be "ON" for lines # labelled TCK, TDO, TDI and TWS, to connect the FT2232H to the ESP32-S2. # adapter driver ftdi ftdi vid_pid 0x0403 0x6010 0x0403 0x6014 # interface 1 is the uart ftdi channel 0 # TCK, TDI, TDO, TMS: ADBUS0-3 # TRST/SRST: ADBUS5 (unused for now) # LEDs: ACBUS3-4 (inverted) ftdi layout_init 0x0008 0x180b ftdi layout_signal LED -ndata 0x0800 ftdi layout_signal LED2 -ndata 0x1000 # ESP32* series chips do not have a TRST input, and the SRST line is connected # to the EN pin. # The target code doesn't handle SRST reset properly yet, so this is # commented out: # ftdi layout_signal nSRST -oe 0x0020 # reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/flossjtag-noeeprom.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # FlossJTAG # # http://github.com/esden/floss-jtag # # This is the pre v0.3 Floss-JTAG compatible config file. It can also be used # for newer versions of Floss-JTAG with empty or not populated EEPROM. If you # have several Floss-JTAG connected you have to use the USB ID to select a # specific one. # # If you have a Floss-JTAG WITH EEPROM that is programmed, use the # flossjtag.cfg file. # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/flossjtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # FlossJTAG # # http://github.com/esden/floss-jtag # # This is the v0.3 and v1.0 Floss-JTAG compatible config file. It relies on the # existence of an EEPROM on Floss-JTAG containing a name. If you have several # Floss-JTAG adapters connected you can use the serial number to select a # specific device. # # If your Floss-JTAG does not have an EEPROM, or the EEPROM is empty, use the # flossjtag-noeeprom.cfg file. # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi device_desc "FLOSS-JTAG" # adapter serial "FJ000001" ftdi layout_init 0x0008 0x180b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 ftdi layout_signal LED -data 0x0800 ftdi layout_signal LED2 -data 0x1000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/flyswatter.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TinCanTools Flyswatter # # http://web.archive.org/web/20150419072034/http://www.tincantools.com/JTAG/Flyswatter.html # adapter driver ftdi ftdi device_desc "Flyswatter" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0818 0x0cfb ftdi layout_signal nTRST -data 0x0010 ftdi layout_signal nSRST -oe 0x0020 ftdi layout_signal LED -data 0x0c00 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/flyswatter2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TinCanTools Flyswatter2 # # https://www.tincantools.com/product/flyswatter2/ # adapter driver ftdi ftdi device_desc "Flyswatter2" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0538 0x057b ftdi layout_signal LED -ndata 0x0400 ftdi layout_signal nTRST -data 0x0010 ftdi layout_signal nSRST -data 0x0020 -noe 0x0100 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/ft232h-module-swd.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # ADAFRUIT FTDI FT232H as a SWD direct connect interface # Any FT232H based board may work # # http://www.ftdichip.com/Products/ICs/FT232H.htm # # adapter driver ftdi ftdi vid_pid 0x0403 0x6014 # data MSB..LSB direction (1:out) MSB..LSB # 0000'0000'0011'0000 0000'0000'0011'1011 ftdi layout_init 0x0030 0x003b # 0xfff8 0xfffb # Those signal are only required on some platforms or may required to be # enabled explicitly (e.g. nrf5x chips). ftdi layout_signal nSRST -data 0x0010 -oe 0x0010 ftdi layout_signal nTRST -data 0x0020 -oe 0x0020 # swd enable ftdi layout_signal SWD_EN -data 0 # tri-state (configure as input) TDO/TIO when reading ftdi layout_signal SWDIO_OE -data 0 transport select swd # re-configure TDO as tri-state #ftdi layout_signal TDO -data 0x0002 -oe 0x0002 #ftdi layout_signal TDI -data 0x0004 # Adafruit FT232H JTAG SWD # Name Pin Name Func Func # D0 J1-3 ADBUS0 TCK SWDCLK # D1 J1-4 ADBUS1 TDO/DI SWDIO # D2 J1-5 ADBUS2 TDI/DO SWDIO # D3 J1-6 ADBUS3 TMS N/A # D4 J1-7 ADBUS4 (GPIOL0) /nSRST optional module reset # D5 J1-8 ADBUS5 (GPIOL1) /nTRST optional target reset # D6 J1-9 ADBUS6 (GPIOL2) # D7 J1-10 ADBUS7 (GPIOL3) # C0 J2-1 ACBUS0 (GPIOH0) # C1 J2-2 ACBUS1 (GPIOH1) # C2 J2-3 ACBUS2 (GPIOH2) # C3 J2-4 ACBUS3 (GPIOH3) # C4 J2-5 ACBUS4 (GPIOH4) # C5 J2-6 ACBUS5 (GPIOH5) # C6 J2-7 ACBUS6 (GPIOH6) # C7 J2-8 ACBUS7 (GPIOH7) # C8 J2-9 ACBUS8 # C9 J2-10 ACBUS9 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/gw16042.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Gateworks GW16042 JTAG Dongle # # http://www.gateworks.com/ # # Layout: FTDI FT2232H # ADBUS0 TCK # ADBUS1 TDI # ADBUS2 TDO (input) # ADBUS3 TMS # ADBUS4 nTRST # ADBUS5 nSRST # ADBUS6 OE (active high) for TRST, TDI, TMS, TCK # ADBUS7 NC # ACBUS0-7 NC # BDBUS0 RXD # BDBUS1 TXD (input) # adapter driver ftdi ftdi device_desc "USB-JTAG" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0058 0x007b ftdi layout_signal nTRST -data 0x0010 ftdi layout_signal nSRST -oe 0x0020 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/hie-jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Hofstädtler Industrie-Electronic (HIE) JTAG Debugger # # https://www.hofstaedtler.com/jtag # adapter driver ftdi ftdi channel 0 ftdi vid_pid 0x0403 0x6014 ftdi device_desc "HIE JTAG Debugger" ftdi layout_init 0x0c08 0x4f1b # define both Reset signals ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 # Toggle USB LED ftdi layout_signal LED -ndata 0x4000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Hilscher NXHX 10-ETM # # http://de.hilscher.com/products_details_hardware.html?p_id=P_4ce145a5983e6 # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "NXHX 10-ETM" ftdi vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Hilscher NXHX 500-ETM # # http://de.hilscher.com/files_design/8/NXHX500-ETM_description_Rev01_EN.pdf # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "NXHX 500-ETM" ftdi vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/hilscher_nxhx500_re.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Hilscher NXHX 500-RE # # http://de.hilscher.com/products_details_hardware.html?p_id=P_461ff2053bad1&bs=20 # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "NXHX 500-RE" ftdi vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Hilscher NXHX 50-ETM # # http://de.hilscher.com/files_design/8/NXHX50-ETM_description_Rev01_EN.pdf # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "NXHX 50-ETM" ftdi vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/hilscher_nxhx50_re.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Hilscher NXHX 50-RE # # http://de.hilscher.com/products_details_hardware.html?p_id=P_483c0f582ad36&bs=20 # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "NXHX50-RE" ftdi vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/hitex_lpc1768stick.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Hitex LPC1768-Stick # # http://www.hitex.com/?id=1602 # adapter driver ftdi ftdi device_desc "LPC1768-Stick" ftdi vid_pid 0x0640 0x0026 ftdi layout_init 0x0388 0x038b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0080 -noe 0x200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/hitex_str9-comstick.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Hitex STR9-comStick # # http://www.hitex.com/index.php?id=383 # adapter driver ftdi ftdi device_desc "STR9-comStick" ftdi vid_pid 0x0640 0x002c ftdi layout_init 0x0108 0x010b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0200 -oe 0x0200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/icebear.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Section5 ICEBear # # http://section5.ch/icebear # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "ICEbear JTAG adapter" ftdi vid_pid 0x0403 0xc140 ftdi layout_init 0x0028 0x002b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0020 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/imx8mp-evk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Configuration file for NXP MC-IMX8MP-EVK on-board internal JTAG # # Using this interface requires enabling "remote mode" for the board using the # NXP bcu tool (see https://github.com/NXPmicro/bcu) # # bcu set_gpio remote_en 1 -board=imx8mpevk # # The REMOTE_EN gpio is accessible through the same FTDI adapter but it's # behind an I2C GPIO expander. # adapter driver ftdi ftdi vid_pid 0x0403 0x6011 ftdi channel 0 ftdi layout_init 0x00f8 0x000b ftdi layout_signal RESET_B -data 0x0010 -oe 0x0010 # Called SYS_nRST in schematics ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 ftdi layout_signal IO_nRST -data 0x0040 -oe 0x0040 ftdi layout_signal ONOFF_B -data 0x0080 -oe 0x0080 ftdi layout_signal GPIO1 -data 0x0100 -oe 0x0100 ftdi layout_signal GPIO2 -data 0x0200 -oe 0x0200 ftdi layout_signal GPIO3 -data 0x0400 -oe 0x0400 ftdi layout_signal GPIO4 -data 0x0800 -oe 0x0800 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/incircuit-icprog.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # In-Circuit's ICprog OpenOCD JTAG Adapter # https://shop.in-circuit.de/product_info.php?products_id=112 # # Schematics available at # http://wiki.in-circuit.de/images/0/06/610000158A_openocd.pdf # adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nSRST -noe 0x0400 -data 0x0800 ftdi layout_signal nTRST -noe 0x0100 -data 0x0200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/iotlab-usb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # This is the integrated adapter as found on the IoT-LAB boards # https://github.com/iot-lab/iot-lab/wiki # adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/isodebug.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # isodebug v1 # 5 kV isolated JTAG/SWD + UART adapter by Unjo AB adapter driver ftdi ftdi vid_pid 0x22b7 0x150d ftdi layout_init 0x0ff8 0xfffb ftdi layout_signal LED -ndata 0x0100 ftdi layout_signal nTRST -data 0x0200 ftdi layout_signal nSRST -noe 0x0400 ftdi layout_signal SWDIO_OE -data 0x0008 # Mode signals, either of these needs to be high to drive the JTAG/SWD pins. # The power-on state is low for both signals but the init setting above sets # JTAG_EN high. ftdi layout_signal SWD_EN -data 0x1000 ftdi layout_signal JTAG_EN -data 0x0800 # In SWD mode, the JTAG_EN signal doubles as SWO_EN_N which switches the # second FTDI channel UART RxD to the SWO pin instead of the separate RxD # pin. Note that the default init state has this pin high so when OpenOCD # starts in SWD mode, SWO is by default disabled. To enable SWO tracing, # issue the command 'ftdi set_signal SWO_EN 1' where tracing is configured. # To switch back to using the separate UART, SWO_EN needs to be disabled # before exiting OpenOCD, or the adapter replugged. ftdi layout_signal SWO_EN -nalias JTAG_EN ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # DISTORTEC JTAG-lock-pick Tiny 2 # # http://www.distortec.com # adapter driver ftdi ftdi device_desc "JTAG-lock-pick Tiny 2" ftdi vid_pid 0x0403 0x8220 ftdi layout_init 0x8c28 0xff3b ftdi layout_signal SWD_EN -ndata 0x0020 -oe 0x2000 ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ftdi layout_signal SWDIO_OE -ndata 0x1000 ftdi layout_signal LED -ndata 0x8000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/jtagkey.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Amontec JTAGkey # # http://www.amontec.com/jtagkey.shtml # adapter driver ftdi ftdi device_desc "Amontec JTAGkey" ftdi vid_pid 0x0403 0xcff8 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/jtagkey2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Amontec JTAGkey2 # # http://www.amontec.com/jtagkey2.shtml # adapter driver ftdi ftdi device_desc "Amontec JTAGkey-2" ftdi vid_pid 0x0403 0xcff8 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/jtagkey2p.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Amontec JTAGkey2P # # http://www.amontec.com/jtagkey2p.shtml # adapter driver ftdi ftdi device_desc "Amontec JTAGkey-2P" ftdi vid_pid 0x0403 0xcff8 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/kt-link.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Kristech KT-Link # # http://www.kristech.eu # adapter driver ftdi ftdi device_desc "KT-LINK" ftdi vid_pid 0x0403 0xbbe2 ftdi layout_init 0x8c28 0xff3b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ftdi layout_signal LED -data 0x8000 ftdi layout_signal SWD_EN -ndata 0x0020 -oe 0x2000 ftdi layout_signal SWDIO_OE -ndata 0x1000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/lambdaconcept_ecpix-5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # This adapter is integrated in to LambdaConcept ECPIX-5 board: # interface/ftdi/lambdaconcept_ecpix-5.cfg # See schematics for the ftdi layout: # http://docs.lambdaconcept.com/ecpix-5/_static/resources/SCH_ECPIX-5_R02.PDF adapter driver ftdi adapter speed 10000 ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0xfff8 0xfffb transport select jtag ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/lisa-l.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Lisa/L # # http://paparazzi.enac.fr/wiki/Lisa # echo "WARNING!" echo "This file was not tested with real interface, it is based on schematics and code" echo "in ft2232.c. Please report your experience with this file to openocd-devel" echo "mailing list, so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "Lisa/L" ftdi vid_pid 0x0403 0x6010 ftdi channel 1 ftdi layout_init 0x0008 0x180b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 ftdi layout_signal LED -data 0x1800 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/luminary-icdi.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Luminary Micro Stellaris LM3S9B9x Evaluation Kits # In-Circuit Debug Interface (ICDI) Board # # Essentially all Luminary debug hardware is the same, (with both # JTAG and SWD support compatible with ICDI boards. This ICDI adapter # configuration is JTAG-only, but the same hardware handles SWD too. # # This is a discrete ftdi based debug board which supports ARM's # JTAG/SWD connectors in both backwards-compatible 20-pin format and # in the new-style compact 10-pin. There's also an 8-pin connector # with serial port support. It's included with LM3S9B9x eval boards. # # http://www.luminarymicro.com/products/ek-lm3s9b90.html # http://www.luminarymicro.com/products/ek-lm3s9b92.html # adapter driver ftdi ftdi device_desc "Luminary Micro ICDI Board" ftdi vid_pid 0x0403 0xbcda ftdi layout_init 0x00a8 0x00eb ftdi layout_signal nSRST -noe 0x0020 ftdi layout_signal SWD_EN -ndata 0x0080 ftdi layout_signal SWDIO_OE -data 0x0008 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/luminary-lm3s811.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Luminary Micro Stellaris LM3S811 Evaluation Kit # # http://www.luminarymicro.com/products/stellaris_811_evaluation_kits.html # # NOTE: this is only for boards *before* Rev C, which adds support # for SWO tracing with ADBUS_6 DBG_ENn and BDBUS_4 SWO_EN signals. # The "evb_lm3s811" layout doesn't set up those signals. # # Rev C boards work more like the other Stellaris eval boards. They # need to use the "luminary_icdi" layout to work correctly. # adapter driver ftdi ftdi device_desc "LM3S811 Evaluation Board" ftdi vid_pid 0x0403 0xbcd9 ftdi layout_init 0x0088 0x008b ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 ftdi layout_signal SWD_EN -ndata 0x0080 ftdi layout_signal SWDIO_OE -data 0x0008 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/luminary.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Luminary Micro Stellaris Evaluation Kits # # http://www.luminarymicro.com/products/evaluation_kits.html # # There are a number of evaluation kits for Stellaris Cortex-M3 chips. # Currently they all bundle ftdi based debug support. When that is # used (instead of an external adapter), use this config file in one # of these two modes: # # - Eval board debug ... debug of the Stellaris chip via port A. # # - Other board debug ... same thing, but the board acts as a debug # adapter for another board (using a standard ARM JTAG connector). # The Stellaris chip stays in reset. # # Those support both JTAG and SWD. SWD is an ARM-only two-wire debug # protocol; in 2009, OpenOCD does not support SWD. # # Port B of the ftdi chip is normally used as a serial link to the # Stellaris chip. On most boards (but not older LM3S811 eval boards), # when SWD is used Port B may instead be used to read low-bandwidth # "SWO trace" data, including so-called "printf style" output from # firmware via the ITM module as well as profile data. # adapter driver ftdi ftdi device_desc "Stellaris Evaluation Board" ftdi vid_pid 0x0403 0xbcd9 ftdi layout_init 0x00a8 0x00eb ftdi layout_signal nSRST -noe 0x0020 ftdi layout_signal SWD_EN -ndata 0x0080 ftdi layout_signal SWDIO_OE -data 0x0008 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/m53evk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # DENX M53EVK # # http://www.denx-cs.de/?q=M53EVK # adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi channel 0 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/mbftdi.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # MBFTDI # # http://www.marsohod.org/prodmbftdi # # Also the Marsohod2 and the Marsohod3 boards # include a built-in MBFTDI for FPGA programming. # See http://www.marsohod.org/prodmarsohod2 # and http://www.marsohod.org/plata-marsokhod3 for details. # adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x000b ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/minimodule-swd.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Supports SWD using the FT2232H or FT4232H minimodule. # Each can support 2 SWD interfaces. # # FT2232H or FT4232H minimodule channel 0 (Channel A) # Connector FTDI Target # Pin Name # --------- ------ ------ # CN2-11 VIO VDD_IO (Or connect to CN2-5 on the minimodule instead for a 3V3 interface) # CN2-2 GND GND # CN2-7 ADBUS0 (TCK) SWCLK # CN2-9 ADBUS2 (TDI/TDO) SWDIO # CN2-10 ADBUS1 (TDO/TDI) SWDIO # CN2-14 ADBUS4 (GPIOL0) nRESET # # FT2232H minimodule channel 1 (Channel B) # FTDI Target # ---- ------ # CN2-11 - VDD_IO # CN2-2 - GND # CN3-26 - SWCLK # CN3-25 - SWDIO # CN3-24 - SWDIO # CN3-21 - nRESET # # FT4232H minimodule channel 1 (Channel B) # FTDI Target # ---- ------ # CN2-11 - VDD_IO # CN2-2 - GND # CN2-18 - SWCLK # CN2-17 - SWDIO # CN2-20 - SWDIO # CN2-22 - nRESET # adapter driver ftdi #Select your module type and channel #ftdi device_desc "FT2232H MiniModule" ftdi vid_pid 0x0403 0x6010 #ftdi channel 1 #ftdi device_desc "FT4232H MiniModule" #ftdi vid_pid 0x0403 0x6011 #ftdi channel 1 ftdi layout_init 0x0000 0x000b ftdi layout_signal nSRST -data 0x0010 -oe 0x0010 ftdi layout_signal SWD_EN -data 0 ftdi layout_signal SWDIO_OE -data 0 transport select swd ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/minimodule.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # FTDI MiniModule # # http://www.ftdichip.com/Support/Documents/DataSheets/Modules/DS_FT2232H_Mini_Module.pdf # adapter driver ftdi ftdi device_desc "FT2232H MiniModule" ftdi vid_pid 0x0403 0x6010 # Every pin set as high impedance except TCK, TDI, TDO and TMS ftdi layout_init 0x0008 0x000b # nSRST defined on pin CN2-13 of the MiniModule (pin ADBUS5 [AD5] on the FT2232H chip) # This choice is arbitrary. Use other GPIO pin if desired. ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/minispartan6.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # https://www.scarabhardware.com/minispartan6/ # https://github.com/scarabhardware/miniSpartan6-plus/raw/master/miniSpartan6%2B_Rev_B.pdf adapter driver ftdi # The miniSpartan6+ sadly doesn't have a custom device description, so we just # have to hope you got it right. #ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 # interface 1 is the uart ftdi channel 0 # just TCK TDI TDO TMS, no reset ftdi layout_init 0x0008 0x000b reset_config none # this generally works fast: the fpga can handle 30MHz, the spi flash can handle # 54MHz with simple read, no dummy cycles, and wait-for-write-completion adapter speed 30000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/miniwiggler.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Infineon DAP miniWiggler V3 # # https://www.infineon.com/cms/en/product/evaluation-boards/kit_miniwiggler_3_usb/ # # Layout: FTDI FT2232 # ADBUS0 TCK # ADBUS1 TDI # ADBUS2 TDO # ADBUS3 TMS # ADBUS4 nOE (output enable) # ADBUS5 # ADBUS6 # ADBUS7 Blue LED # # ACBUS0 nTRST # ACBUS1 nSRST # ACUBS2 # ACBUS3 # ACBUS4 # ACBUS5 # ACBUS6 # ACBUS7 # adapter driver ftdi ftdi device_desc "DAS JDS miniWiggler V3.1" ftdi vid_pid 0x058b 0x0043 ftdi channel 0 ftdi layout_init 0x0008 0x001b ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 ftdi layout_signal nSRST -data 0x0200 -oe 0x0200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/neodb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Openmoko USB JTAG/RS232 adapter # # http://wiki.openmoko.org/wiki/Debug_Board_v3 # adapter driver ftdi ftdi device_desc "Debug Board for Neo1973" ftdi vid_pid 0x1457 0x5118 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 ftdi layout_signal nNOR_WP -data 0x0010 -oe 0x0010 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/ngxtech.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # NGX ARM USB JTAG # # http://shop.ngxtechnologies.com/product_info.php?cPath=26&products_id=30 # echo "WARNING!" echo "This file was not tested with real interface, but is assumed to work as this" echo "interface uses the same layout as configs that were verified. Please report your" echo "experience with this file to openocd-devel mailing list, so it could be marked" echo "as working or fixed." adapter driver ftdi ftdi device_desc "NGX JTAG" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/olimex-arm-jtag-swd.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Olimex ARM JTAG SWD adapter # https://www.olimex.com/Products/ARM/JTAG/ARM-JTAG-SWD/ # transport select swd ftdi layout_signal SWD_EN -nalias nTRST ftdi layout_signal SWDIO_OE -alias TMS ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Olimex ARM-USB-OCD-H # # http://www.olimex.com/dev/arm-usb-ocd-h.html # adapter driver ftdi ftdi device_desc "Olimex OpenOCD JTAG ARM-USB-OCD-H" ftdi vid_pid 0x15ba 0x002b ftdi layout_init 0x0908 0x0b1b ftdi layout_signal nSRST -oe 0x0200 ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal LED -data 0x0800 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Olimex ARM-USB-OCD # # http://www.olimex.com/dev/arm-usb-ocd.html # adapter driver ftdi ftdi device_desc "Olimex OpenOCD JTAG" ftdi vid_pid 0x15ba 0x0003 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nSRST -oe 0x0200 ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal LED -data 0x0800 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Olimex ARM-USB-TINY-H # # http://www.olimex.com/dev/arm-usb-tiny-h.html # adapter driver ftdi ftdi device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H" ftdi vid_pid 0x15ba 0x002a ftdi layout_init 0x0808 0x0a1b ftdi layout_signal nSRST -oe 0x0200 ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 ftdi layout_signal LED -data 0x0800 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/olimex-jtag-tiny.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Olimex ARM-USB-TINY # # http://www.olimex.com/dev/arm-usb-tiny.html # adapter driver ftdi ftdi device_desc "Olimex OpenOCD JTAG TINY" ftdi vid_pid 0x15ba 0x0004 ftdi layout_init 0x0808 0x0a1b ftdi layout_signal nSRST -oe 0x0200 ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 ftdi layout_signal LED -data 0x0800 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/oocdlink.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Joern Kaipf's OOCDLink # # http://www.joernonline.de/contrexx2/cms/index.php?page=126 # echo "WARNING!" echo "This file was not tested with real interface, but is assumed to work as this" echo "interface uses the same layout as configs that were verified. Please report your" echo "experience with this file to openocd-devel mailing list, so it could be marked" echo "as working or fixed." adapter driver ftdi ftdi device_desc "OOCDLink" ftdi vid_pid 0x0403 0xbaf8 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/opendous_ftdi.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Opendous # # http://code.google.com/p/opendous/wiki/JTAG # # According to the website, it is similar to jtagkey, but it uses channel B # (and it has a different pid number). # adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi channel 1 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/openocd-usb-hs.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # embedded projects openocd usb adapter v3 # # http://shop.embedded-projects.net/index.php?module=artikel&action=artikel&id=14 # adapter driver ftdi ftdi device_desc "Dual RS232-HS" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/openocd-usb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Hubert Hoegl's USB to JTAG # # http://www.hs-augsburg.de/~hhoegl/proj/usbjtag/usbjtag.html # adapter driver ftdi ftdi device_desc "Dual RS232" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/openrd.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Marvell OpenRD # # http://www.marvell.com/products/embedded_processors/developer/kirkwood/openrd.jsp # adapter driver ftdi ftdi device_desc "OpenRD JTAGKey FT2232D B" ftdi vid_pid 0x0403 0x9e90 ftdi channel 0 ftdi layout_init 0x0608 0x0f1b ftdi layout_signal nTRST -data 0x0200 ftdi layout_signal nSRST -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/pipistrello.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # http://pipistrello.saanlima.com/ # http://www.saanlima.com/download/pipistrello-v2.0/pipistrello_v2_schematic.pdf adapter driver ftdi ftdi device_desc "Pipistrello LX45" ftdi vid_pid 0x0403 0x6010 # interface 1 is the uart ftdi channel 0 # just TCK TDI TDO TMS, no reset ftdi layout_init 0x0008 0x000b reset_config none # this generally works fast: the fpga can handle 30MHz, the spi flash can handle # 54MHz with simple read, no dummy cycles, and wait-for-write-completion adapter speed 10000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/pls_spc5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # PLS SPC5-UDESTK # # https://www.st.com/en/development-tools/spc5-udestk.html # # Reference the SPC56D Discovery schematics. # # Layout: FTDI FT2232 # ADBUS0 TCK # ADBUS1 TDI # ADBUS2 TDO # ADBUS3 TMS # ADBUS4 TMS # ADBUS5 RTCK # ADBUS6 # ADBUS7 LED1 # # ACBUS0 nTRST # ACBUS1 nSRST (external pull-down) # ACUBS2 # ACBUS3 # ACBUS4 # ACBUS5 nSRST direction (input=L, output=H, external pull-down) # ACBUS6 TMS direction (input=L, output=H, external pull-up) # ACBUS7 LED2 # adapter driver ftdi ftdi device_desc "PLS USB/JTAG Adapter for SPC5xxx" ftdi vid_pid 0x263d 0x4001 ftdi channel 0 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 ftdi layout_signal nSRST -ndata 0x2000 -oe 0x2000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/redbee-econotag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Redwire Redbee-Econotag # # http://www.redwirellc.com/store/node/1 # # The Redbee-Econotag has an onboard FT2232H with: # - FT2232H channel A wired to mc13224v JTAG # - FT2232H channel B wired to mc13224v UART1 # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0c08 0x0c2b ftdi layout_signal nTRST -data 0x0800 ftdi layout_signal nSRST -data 0x0400 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/redbee-usb.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Redwire Redbee-USB # # http://www.redwirellc.com # # The Redbee-USB has an onboard FT2232H with: # - FT2232H channel B wired to mc13224v JTAG # - FT2232H channel A wired to mc13224v UART1 # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi channel 1 ftdi layout_init 0x0c08 0x0c2b ftdi layout_signal nTRST -data 0x0800 ftdi layout_signal nSRST -data 0x0400 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/rowley-cc-arm-swd.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Rowley ARM SWD Adapter # http://sites.fastspring.com/rowley/product/armswdadapter # https://drive.google.com/file/d/0Bzv7UpKpOQhnTUNNdzI5OUR4WGs/edit?usp=sharing # transport select swd ftdi layout_signal SWD_EN -nalias nTRST ftdi layout_signal SWDIO_OE -alias TMS ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/sheevaplug.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Marvel SheevaPlug Development Kit # # http://www.marvell.com/products/embedded_processors/developer/kirkwood/sheevaplug.jsp # adapter driver ftdi ftdi device_desc "SheevaPlug JTAGKey FT2232D B" ftdi vid_pid 0x9e88 0x9e8f ftdi channel 0 ftdi layout_init 0x0608 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/signalyzer-lite.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Xverve Signalyzer LITE (DT-USB-SLITE) # # http://www.signalyzer.com # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "Signalyzer LITE" ftdi vid_pid 0x0403 0xbca1 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/signalyzer.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Xverve Signalyzer Tool (DT-USB-ST) # # http://www.signalyzer.com # echo "WARNING!" echo "This file was not tested with real interface, it is based on code in ft2232.c." echo "Please report your experience with this file to openocd-devel mailing list," echo "so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "Signalyzer" ftdi vid_pid 0x0403 0xbca0 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/snps_sdp.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> # # Synopsys SDP Mainboard has embdded FT2232 chip, which is similar to Digilent # HS-1, except that it uses channel B for JTAG communication, instead of # channel A. # adapter driver ftdi ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0088 0x008b ftdi channel 1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/steppenprobe.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Steppenprobe # https://github.com/diegoherranz/steppenprobe # adapter driver ftdi ftdi vid_pid 0x0403 0x6010 # Initial Layout ftdi layout_init 0x0058 0x99fb # Signal Data Direction Notes # TCK 0 1 (out) # TDI 0 1 (out) # TDO 0 0 (in) # TMS 1 1 (out) JTAG IEEE std recommendation # LED 1 1 (out) LED off # SWD_EN 0 1 (out) OpenOCD sets this high for SWD # SWDIO_OE 1 1 (out) Ext. buffer tristated # SRST 0 1 (out) Translates to nSRST=Z # Unused 0 1 (out) # GPIO_A 0 0 (in) # GPIO_B 0 0 (in) # Unused 0 1 (out) # Unused 0 1 (out) # GPIO_C 0 0 (in) # GPIO_D 0 0 (in) # Unused 0 1 (out) # Signals definition ftdi layout_signal LED -ndata 0x0010 ftdi layout_signal SWD_EN -data 0x0020 ftdi layout_signal SWDIO_OE -ndata 0x0040 ftdi layout_signal nSRST -oe 0x0080 ftdi layout_signal GPIO_A -data 0x0200 -oe 0x0200 -input 0x0200 ftdi layout_signal GPIO_B -data 0x0400 -oe 0x0400 -input 0x0400 ftdi layout_signal GPIO_C -data 0x2000 -oe 0x2000 -input 0x2000 ftdi layout_signal GPIO_D -data 0x4000 -oe 0x4000 -input 0x4000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/stm32-stick.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Hitex STM32-PerformanceStick # # http://www.hitex.com/index.php?id=340 # adapter driver ftdi ftdi device_desc "STM32-PerformanceStick" ftdi vid_pid 0x0640 0x002d ftdi layout_init 0x0388 0x038b ftdi layout_signal nTRST -data 0x0100 ftdi layout_signal nSRST -data 0x0080 -noe 0x200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/swd-resistor-hack.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Connect TDI to SWDIO via a suitable series resistor (220-470 Ohm or # so depending on the drive capability of the target and adapter); # connect TDO directly to SWDIO. # # You also need to have reliable GND connection between the target and # adapter. Vref of the adapter should be supplied with a voltage equal # to the target's (preferably connect it to Vcc). You can also # optionally connect nSRST. Leave everything else unconnected. # # FTDI Target # ---- ------ # 1 - Vref ----------------- Vcc # 3 - nTRST - # 4 - GND ----------------- GND # 5 - TDI ---/\470 Ohm/\--- SWDIO # 7 - TMS - # 9 - TCK ----------------- SWCLK # 11 - RTCK - # 13 - TDO ----------------- SWDIO # 15 - nSRST - - - - - - - - - nRESET # transport select swd ftdi layout_signal SWD_EN -data 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/ti-icdi.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # This is an FTDI-based debugging solution as found on some TI boards, # e.g. CC3200 LaunchPad. # # The schematics are identical to luminary-icdi (including SWD # support) but the USB IDs are different. # adapter driver ftdi ftdi vid_pid 0x0451 0xc32a ftdi layout_init 0x00a8 0x00eb ftdi layout_signal nSRST -noe 0x0020 ftdi layout_signal SWD_EN -ndata 0x0080 ftdi layout_signal SWDIO_OE -data 0x0008 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/tigard.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Tigard: An FTDI FT2232H-based multi-protocol tool for hardware hacking. # https://github.com/tigard-tools/tigard adapter driver ftdi ftdi device_desc "Tigard V1.1" ftdi vid_pid 0x0403 0x6010 ftdi channel 1 ftdi layout_init 0x0038 0x003b ftdi layout_signal nTRST -data 0x0010 ftdi layout_signal nSRST -data 0x0020 # This board doesn't support open-drain reset modes since its output buffer is # always enabled. reset_config srst_push_pull trst_push_pull ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/tumpa-lite.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TIAO USB Multi-Protocol Adapter (TUMPA) Lite # # http://www.diygadget.com/tiao-usb-multi-protocol-adapter-lite-jtag-spi-i2c-serial.html # adapter driver ftdi ftdi vid_pid 0x0403 0x8a99 ftdi layout_init 0x0038 0x087b ftdi layout_signal nTRST -data 0x0020 -oe 0x0020 ftdi layout_signal nSRST -data 0x0010 -oe 0x0010 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/tumpa.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TIAO USB Multi-Protocol Adapter (TUMPA) # # http://www.diygadget.com/tiao-usb-multi-protocol-adapter-jtag-spi-i2c-serial.html # adapter driver ftdi ftdi vid_pid 0x0403 0x8a98 0x0403 0x6010 ftdi layout_init 0x0038 0x087b ftdi layout_signal nTRST -data 0x0020 ftdi layout_signal nSRST -data 0x0010 reset_config srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/turtelizer2-revB.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # egnite Turtelizer 2 rev B (with SRST only) # # http://www.ethernut.de/en/hardware/turtelizer/index.html # echo "WARNING!" echo "This file was not tested with real interface, it is based on schematics and code" echo "in ft2232.c. Please report your experience with this file to openocd-devel" echo "mailing list, so it could be marked as working or fixed." adapter driver ftdi ftdi device_desc "Turtelizer JTAG/RS232 Adapter" ftdi vid_pid 0x0403 0xbdc8 ftdi layout_init 0x0008 0x0c5b ftdi layout_signal nSRST -oe 0x0040 ftdi layout_signal LED -data 0x0c00 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/turtelizer2-revC.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # egnite Turtelizer 2 revC (with TRST and SRST) # # http://www.ethernut.de/en/hardware/turtelizer/index.html # adapter driver ftdi ftdi device_desc "Turtelizer JTAG/RS232 Adapter" ftdi vid_pid 0x0403 0xbdc8 ftdi layout_init 0x0008 0x0c7b ftdi layout_signal nTRST -oe 0x0020 ftdi layout_signal nSRST -oe 0x0040 ftdi layout_signal LED -ndata 0x0c00 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/um232h.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # FTDI UM232H as a JTAG interface # # http://www.ftdichip.com/Products/Modules/DevelopmentModules.htm#UM232H # # This should also work with a UM232H-B, but that has not been tested. # Note that UM232H and UM232H-B are 3.3V only. # adapter driver ftdi #ftdi device_desc "UM232H" ftdi vid_pid 0x0403 0x6014 ftdi layout_init 0xfff8 0xfffb ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 ftdi layout_signal nSRST -data 0x0200 -oe 0x0200 # UM232H FT232H JTAG # Name Pin Name Func # AD0 J2-6 ADBUS0 TCK # AD1 J2-7 ADBUS1 TDI # AD2 J2-8 ADBUS2 TDO # AD3 J2-9 ADBUS3 TMS # AD4 J2-10 ADBUS4 (GPIOL0) # AD5 J2-11 ADBUS5 (GPIOL1) # AD6 J2-12 ADBUS6 (GPIOL2) # AD7 J2-13 ADBUS7 (GPIOL3) # AD0 J1-14 ACBUS0 /TRST # AD1 J1-13 ACBUS1 /SRST # AD2 J1-12 ACBUS2 (GPIOH2) # AD3 J1-11 ACBUS3 (GPIOH3) # AD4 J1-10 ACBUS4 (GPIOH4) # AD5 J1-9 ACBUS5 (GPIOH5) # AD6 J1-8 ACBUS6 (GPIOH6) # AD7 J1-7 ACBUS7 (GPIOH7) ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/vpaclink.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Voipac VPACLink # # http://voipac.com/27M-JTG-000 # echo "WARNING!" echo "This file was not tested with real interface, but is assumed to work as this" echo "interface uses the same layout as configs that were verified. Please report your" echo "experience with this file to openocd-devel mailing list, so it could be marked" echo "as working or fixed." adapter driver ftdi ftdi device_desc "VPACLink" ftdi vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/xds100v2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments XDS100v2 # # http://processors.wiki.ti.com/index.php/XDS100#XDS100v2_Features # # Detailed documentation is available only as CPLD verilog source code # to the registered TI users. # adapter driver ftdi ftdi vid_pid 0x0403 0xa6d0 0x0403 0x6010 ftdi layout_init 0x0038 0x597b # 8000 z - unused # 4000 0 > CPLD loopback (all target side pins high-Z) # 2000 z < !( cable connected ) (open drain on CPLD side for $reasons) # 1000 0 > EMU1_oe # # 800 0 > PWR_RST = clear power-loss flag on rising edge # 400 z < !( power-loss flag ) # 200 z < nSRST # 100 0 > nSRST_oe # # 80 z < RTCK # 40 0 > EMU0_oe # 20 1 > EMU_EN # 10 1 > nTRST # # 8 1 > TMS # 4 z < TDO # 2 0 > TDI # 1 0 > TCK # # As long as the power-loss flag is set, all target-side pins are # high-Z except the EMU-pins for which the opposite holds unless # EMU_EN is high. # # To use wait-in-reset, drive EMU0 low at power-on reset. If the # target normally reuses EMU0 for other purposes, clear EMU_EN to # keep the EMU pins high-Z until the target is power-cycled. # # The LED only turns off at USB suspend, which is also the only way to # set the power-loss flag manually. (Can be done in software e.g. by # changing the USB configuration to zero.) # ftdi layout_signal nTRST -data 0x0010 ftdi layout_signal nSRST -oe 0x0100 ftdi layout_signal EMU_EN -data 0x0020 ftdi layout_signal EMU0 -oe 0x0040 ftdi layout_signal EMU1 -oe 0x1000 ftdi layout_signal PWR_RST -data 0x0800 ftdi layout_signal LOOPBACK -data 0x4000 echo "\nInfo : to use this adapter you MUST add ``init; ftdi set_signal PWR_RST 1; jtag arp_init'' to the end of your config file!\n" # note: rising edge on PWR_RST is also needed after power-cycling the # target ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/xds100v3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments XDS100 ver 3.0 # # http://processors.wiki.ti.com/index.php/XDS100 # # Version 3.0 is the same as 2.0 as far as OpenOCD is concerned source [find interface/ftdi/xds100v2.cfg] # The USB ids are different. ftdi vid_pid 0x0403 0xa6d1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ftdi/xt_kc705_ml605.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Xilinx KC705 / ML605 with Xtensa daughtercard; onboard USB/FT2232 # adapter driver ftdi ftdi vid_pid 0x0403 0x6010 # Specify "adapter serial <identifier>" here as needed ftdi layout_init 0x0010 0x007b ftdi layout_signal nTRST -data 0x0010 ftdi layout_signal nSRST -ndata 0x0020 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/imx-native.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Config for using NXP IMX CPU # # This is best used with a fast enough buffer but also # is suitable for direct connection if the target voltage # matches to host voltage and the cable is short enough. # # adapter driver imx_gpio # For most IMX processors 0x0209c000 imx_gpio_peripheral_base 0x0209c000 # Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET # These depend on system clock, calibrated for IMX6UL@528MHz # imx_gpio_speed SPEED_COEFF SPEED_OFFSET imx_gpio_speed_coeffs 50000 50 # Each of the JTAG lines need a gpio number set: tck tms tdi tdo. # Example configuration: # imx_gpio_jtag_nums 6 7 8 9 # SWD interface pins: swclk swdio # Example configuration: imx_gpio_swd_nums 1 6 # imx_gpio_trst_num 10 # reset_config trst_only # imx_gpio_srst_num 11 # reset_config srst_only srst_push_pull # or if you have both connected, # reset_config trst_and_srst srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/jlink.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # SEGGER J-Link # # http://www.segger.com/jlink.html # adapter driver jlink # The serial number can be used to select a specific device in case more than # one is connected to the host. # # Example: Select J-Link with serial number 123456789 # # adapter serial 123456789 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/jtag_dpi.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Provide support for the Cadence JTAG BFM # # Copyright (c) 2020, Ampere Computing LLC # adapter driver jtag_dpi # Set the DPI JTAG server port if { [info exists DPI_PORT] } { set _DPI_PORT $DPI_PORT } else { set _DPI_PORT 5555 } # Set the DPI JTAG server address if { [info exists DPI_ADDRESS] } { set _DPI_ADDRESS $DPI_ADDRESS } else { set _DPI_ADDRESS "127.0.0.1" } jtag_dpi set_port $_DPI_PORT jtag_dpi set_address $_DPI_ADDRESS ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/jtag_hat_rpi2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Blinkinlabs JTAG_Hat # # https://github.com/blinkinlabs/jtag_hat # adapter driver bcm2835gpio bcm2835gpio peripheral_base 0x3F000000 # Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET # These depend on system clock, calibrated for stock 700MHz # bcm2835gpio_speed SPEED_COEFF SPEED_OFFSET bcm2835gpio speed_coeffs 146203 36 # Each of the JTAG lines need a gpio number set: tck tms tdi tdo # Header pin numbers: 23 22 19 21 adapter gpio tck -chip 0 11 adapter gpio tms -chip 0 25 adapter gpio tdi -chip 0 10 adapter gpio tdo -chip 0 9 # Each of the SWD lines need a gpio number set: swclk swdio # Header pin numbers: 23 22 adapter gpio swclk -chip 0 11 adapter gpio swdio -chip 0 25 # Direction pin for SWDIO level shifting buffer adapter gpio swdio_dir -chip 0 6 # If you define trst or srst, use appropriate reset_config # Header pin numbers: TRST - 26, SRST - 18 adapter gpio trst -chip 0 7 #reset_config trst_only adapter gpio srst -chip 0 24 #reset_config srst_only # or if you have both connected #reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/jtag_vpi.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later adapter driver jtag_vpi # Set the VPI JTAG server port if { [info exists VPI_PORT] } { set _VPI_PORT $VPI_PORT } else { set _VPI_PORT 5555 } # Set the VPI JTAG server address if { [info exists VPI_ADDRESS] } { set _VPI_ADDRESS $VPI_ADDRESS } else { set _VPI_ADDRESS "127.0.0.1" } jtag_vpi set_port $_VPI_PORT jtag_vpi set_address $_VPI_ADDRESS ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/kitprog.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Cypress Semiconductor KitProg # # Note: This is the driver for the proprietary KitPtog protocol. If the # KitProg is in CMSIS-DAP mode, you should either use the cmsis-dap # interface driver or switch the KitProg to KitProg mode. # adapter driver kitprog # Optionally specify the serial number of the KitProg you want to use. # adapter serial 1926402735485200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/nulink.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Nuvoton Nu-Link in-circuit debugger/programmer # adapter driver hla hla_layout nulink hla_device_desc "Nu-Link" hla_vid_pid 0x0416 0x511b 0x0416 0x511c 0x0416 0x511d 0x0416 0x5200 0x0416 0x5201 # Only swd is supported transport select hla_swd ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/opendous.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # opendous-jtag # # http://code.google.com/p/opendous-jtag/ # adapter driver opendous ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/openjtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # OpenJTAG # # www.openjtag.org # adapter driver openjtag openjtag device_desc "Open JTAG Project" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/osbdm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # P&E Micro OSBDM (aka OSJTAG) interface # # http://pemicro.com/osbdm/ # adapter driver osbdm reset_config srst_only ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/parport.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Parallel port wiggler (many clones available) on port 0x378 # # Addresses: 0x378/LPT1 or 0x278/LPT2 ... # if { [info exists PARPORTADDR] } { set _PARPORTADDR $PARPORTADDR } else { if {$tcl_platform(platform) eq "windows"} { set _PARPORTADDR 0x378 } { set _PARPORTADDR 0 } } adapter driver parport parport port $_PARPORTADDR parport cable wiggler ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/parport_dlc5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Xilinx Parallel Cable III 'DLC 5' (and various clones) # # http://www.xilinx.com/itp/xilinx4/data/docs/pac/appendixb.html # if { [info exists PARPORTADDR] } { set _PARPORTADDR $PARPORTADDR } else { set _PARPORTADDR 0 } adapter driver parport parport port $_PARPORTADDR parport cable dlc5 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/raspberrypi-gpio-connector.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Config for Raspberry Pi GPIO header # # This is best used with a fast enough buffer but also # is suitable for direct connection if the target voltage # matches RPi's 3.3V and the cable is short enough. # # Do not forget the GND connection, e.g. pin 20 of the GPIO header. # # GPIO 25 (pin 22) previously used for TMS/SWDIO is pulled-down by default. # The JTAG/SWD specification requires pull-up at the target board # for either signal. Connecting the signal pulled-up on the target # to the pull-down on the adapter is not a good idea. # GPIO 8 is pulled-up by default. echo "Warn : TMS/SWDIO moved to GPIO 8 (pin 24). Check the wiring please!" # Each of the JTAG lines need a gpio number set: tck tms tdi tdo # Header pin numbers: 23 24 19 21 adapter gpio tck -chip 0 11 adapter gpio tms -chip 0 8 adapter gpio tdi -chip 0 10 adapter gpio tdo -chip 0 9 # Each of the SWD lines need a gpio number set: swclk swdio # Header pin numbers: 23 24 adapter gpio swclk -chip 0 11 adapter gpio swdio -chip 0 8 # If you define trst or srst, use appropriate reset_config # Header pin numbers: TRST - 26, SRST - 18 # adapter gpio trst -chip 0 7 # reset_config trst_only # adapter gpio srst -chip 0 24 # reset_config srst_only srst_push_pull # or if you have both connected, # reset_config trst_and_srst srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/raspberrypi-native.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Config for Raspberry Pi used as a bitbang adapter. # https://www.raspberrypi.com/documentation/computers/raspberry-pi.html # Supports all models with 40-pin or 26-pin GPIO connector up to Raspberry Pi 4 B # also supports Raspberry Pi Zero, Zero W and Zero 2 W. # Adapter speed calibration is computed from cpufreq/scaling_max_freq. # Adjusts automatically if CPU is overclocked. adapter driver bcm2835gpio proc read_file { name } { if {[catch {open $name r} fd]} { return "" } set result [read $fd] close $fd return $result } proc measure_clock {} { set result [exec vcgencmd measure_clock arm] set clock_hz [lindex [split $result "="] 1] expr { $clock_hz / 1000 } } proc get_max_cpu_clock { default } { set clock [read_file /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq] if { $clock > 100000 } { return $clock } # cpufreq not available. As the last resort try Broadcom's proprietary utility if {![catch measure_clock clock] && $clock > 100000} { return $clock } echo "WARNING: Host CPU clock unknown." echo "WARNING: Using the highest possible value $default kHz as a safe default." echo "WARNING: Expect JTAG/SWD clock significantly slower than requested." return $default } set compat [read_file /proc/device-tree/compatible] set clocks_per_timing_loop 4 if {[string match *bcm2711* $compat]} { set speed_offset 52 } elseif {[string match *bcm2837* $compat] || [string match *bcm2710* $compat]} { set speed_offset 34 } elseif {[string match *bcm2836* $compat] || [string match *bcm2709* $compat]} { set speed_offset 36 } elseif {[string match *bcm2835* $compat] || [string match *bcm2708* $compat]} { set clocks_per_timing_loop 6 set speed_offset 32 } else { set speed_offset 32 echo "WARNING: Unknown type of the host SoC. Expect JTAG/SWD clock slower than requested." } set clock [get_max_cpu_clock 2000000] set speed_coeff [expr { $clock / $clocks_per_timing_loop }] # Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET # The coefficients depend on system clock and CPU frequency scaling. bcm2835gpio speed_coeffs $speed_coeff $speed_offset source [find interface/raspberrypi-gpio-connector.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/raspberrypi2-native.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later echo "WARNING: interface/raspberrypi2-native.cfg is deprecated." echo "WARNING: Please use interface/raspberrypi-native.cfg for all Raspberry Pi models." source [find interface/raspberrypi-native.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/rlink.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Raisonance RLink # # http://www.mcu-raisonance.com/~rlink-debugger-programmer__microcontrollers__tool~tool__T018:4cn9ziz4bnx6.html # adapter driver rlink ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/rshim.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # BlueField SoC in-circuit debugger/programmer # adapter driver rshim transport select dapdirect_swd ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/stlink-dap.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # STMicroelectronics ST-LINK/V1, ST-LINK/V2, ST-LINK/V2-1, STLINK-V3 in-circuit # debugger/programmer # # This new interface driver creates a ST-Link wrapper for ARM-DAP named "dapdirect" # Old ST-LINK/V1 and ST-LINK/V2 pre version V2J24 don't support "dapdirect" # # SWIM transport is natively supported # adapter driver st-link st-link vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 0x0483 0x3755 0x0483 0x3757 # transport select dapdirect_jtag # transport select dapdirect_swd # transport select swim # Optionally specify the serial number of usb device # e.g. # adapter serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/stlink-v1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later echo "WARNING: interface/stlink-v1.cfg is deprecated, please switch to interface/stlink.cfg" source [find interface/stlink.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/stlink-v2-1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later echo "WARNING: interface/stlink-v2-1.cfg is deprecated, please switch to interface/stlink.cfg" source [find interface/stlink.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/stlink-v2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later echo "WARNING: interface/stlink-v2.cfg is deprecated, please switch to interface/stlink.cfg" source [find interface/stlink.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/stlink.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # STMicroelectronics ST-LINK/V1, ST-LINK/V2, ST-LINK/V2-1, STLINK-V3 in-circuit # debugger/programmer # adapter driver hla hla_layout stlink hla_device_desc "ST-LINK" hla_vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 0x0483 0x3755 0x0483 0x3757 # Optionally specify the serial number of ST-LINK/V2 usb device. ST-LINK/V2 # devices seem to have serial numbers with unreadable characters. ST-LINK/V2 # firmware version >= V2.J21.S4 recommended to avoid issues with adapter serial # number reset issues. # eg. # adapter serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/sysfsgpio-raspberrypi.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Config for using RaspberryPi's expansion header # # This is best used with a fast enough buffer but also # is suitable for direct connection if the target voltage # matches RPi's 3.3V # # Do not forget the GND connection, pin 6 of the expansion header. # adapter driver sysfsgpio # Each of the JTAG lines need a gpio number set: tck tms tdi tdo # Header pin numbers: 23 22 19 21 sysfsgpio jtag_nums 11 25 10 9 # Each of the SWD lines need a gpio number set: swclk swdio # Header pin numbers: 23 22 sysfsgpio swd_nums 11 25 # If you define trst or srst, use appropriate reset_config # Header pin numbers: TRST - 26, SRST - 18 # sysfsgpio trst_num 7 # reset_config trst_only # sysfsgpio srst_num 24 # reset_config srst_only srst_push_pull # or if you have both connected, # reset_config trst_and_srst srst_push_pull ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ti-icdi.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI Stellaris In-Circuit Debug Interface (ICDI) Board # # This is the propriety ICDI interface used on newer boards such as # LM4F232 Evaluation Kit - http://www.ti.com/tool/ek-lm4f232 # Stellaris Launchpad - http://www.ti.com/stellaris-launchpad # http://www.ti.com/tool/ek-lm4f232 # adapter driver hla hla_layout ti-icdi hla_vid_pid 0x1cbe 0x00fd # Optionally specify the serial number of TI-ICDI devices, for when using # multiple devices. Serial numbers can be obtained using lsusb -v # Ex. # adapter serial "0F003065" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/ulink.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Keil ULINK running OpenULINK firmware. # # http://www.keil.com/ulink1/ # http://article.gmane.org/gmane.comp.debugging.openocd.devel/17362 # adapter driver ulink ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/usb-jtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # ixo-usb-jtag - Emulation of a Altera Bus Blaster I on a Cypress FX2 IC. # # The ixo-usb-jtag firmware can be loaded onto a bunch of different hardware # including; # * Xilinx USB Platform Cable # * Many Digilent boards such as the Nexys, Nexys 2 and Atlys boards # * Many fpga4fun.com boards from such as the Saxo and Xylo boards # * The Numato Opsis # # Original version - http://www.ixo.de/info/usb_jtag/ # Updated version - http://ixo-jtag.sourceforge.net/ # Newest version - http://github.com/mithro/ixo-usb-jtag # # Procedure for using is; # * Get the ixo-usb-jtag firmware for your hardware (or build it yourself). # * Load the firmware using the fxload tool. # * Use openocd. # # Unless you burn the firmware into the EEPROM on your device, power cycling # will require you to reload the firmware using the fxload tool. This can be # automated by using udev rules (which can be found in the firmware # repository). # # Ubuntu packages built from mithro's version (with prebuilt firmware and udev # rules) can be found at # https://launchpad.net/~timvideos/+archive/ubuntu/fpga-support # # TODO: Refactor the usb_blaster driver to allow loading firmware using any low # level driver. Loading firmware is currently only supported on the ublast2 # driver but ixo-usb-jtag requires the ftdi driver. adapter driver usb_blaster usb_blaster vid_pid 0x16C0 0x06AD usb_blaster device_desc "Van Ooijen Technische Informatica" # ixo-usb-jtag is only compatible with the ublast1 protocol implemented via the # ftdi modes, using ublast2 will cause openocd to hang. usb_blaster lowlevel_driver ftdi ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/usbprog.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Embedded Projects USBprog # # http://embedded-projects.net/index.php?page_id=135 # adapter driver usbprog # USBprog is broken w/short TMS sequences, this is a workaround # until the C code can be fixed. tms_sequence long ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/vdebug.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface if { [info exists VDEBUGHOST] } { set _VDEBUGHOST $VDEBUGHOST } else { set _VDEBUGHOST localhost } if { [info exists VDEBUGPORT] } { set _VDEBUGPORT $VDEBUGPORT } else { set _VDEBUGPORT 8192 } adapter driver vdebug # vdebug server:port vdebug server $_VDEBUGHOST:$_VDEBUGPORT # example config debug level and log #debug_level 3 #log_output vd_ocd.log # example config listen on all interfaces, disable tcl/telnet server bindto 0.0.0.0 #gdb_port 3333 #telnet_port disabled tcl_port disabled # transaction batching: 0 - no batching, 1 - (default) wr, 2 - rw vdebug batching 1 # Polling values vdebug polling 100 1000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/vsllink.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Versaloon Link -- VSLLink # # http://www.versaloon.com/ # adapter driver vsllink ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/interface/xds110.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments XDS110 # # http://processors.wiki.ti.com/index.php/XDS110 # http://processors.wiki.ti.com/index.php/Emulation_Software_Package#XDS110_Support_Utilities # adapter driver xds110 # Use serial number option to use a specific XDS110 # when more than one are connected to the host. # adapter serial 00000000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/mem_helper.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Helper for common memory read/modify/write procedures # mrw: "memory read word", returns value of $reg proc mrw {reg} { return [read_memory $reg 32 1] } add_usage_text mrw "address" add_help_text mrw "Returns value of word in memory." # mrh: "memory read halfword", returns value of $reg proc mrh {reg} { return [read_memory $reg 16 1] } add_usage_text mrh "address" add_help_text mrh "Returns value of halfword in memory." # mrb: "memory read byte", returns value of $reg proc mrb {reg} { return [read_memory $reg 8 1] } add_usage_text mrb "address" add_help_text mrb "Returns value of byte in memory." # mmw: "memory modify word", updates value of $reg # $reg <== ((value & ~$clearbits) | $setbits) proc mmw {reg setbits clearbits} { set old [mrw $reg] set new [expr {($old & ~$clearbits) | $setbits}] mww $reg $new } add_usage_text mmw "address setbits clearbits" add_help_text mmw "Modify word in memory. new_val = (old_val & ~clearbits) | setbits;" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/memory.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # MEMORY # # All Memory regions have two components. # (1) A count of regions, in the form N_NAME # (2) An array within info about each region. # # The ARRAY # # <NAME>( RegionNumber , ATTRIBUTE ) # # Where <NAME> is one of: # # N_FLASH & FLASH (internal memory) # N_RAM & RAM (internal memory) # N_MMREGS & MMREGS (for memory mapped registers) # N_XMEM & XMEM (off chip memory, ie: flash on cs0, sdram on cs2) # or N_UNKNOWN & UNKNOWN for things that do not exist. # # We have 1 unknown region. set N_UNKNOWN 1 # All MEMORY regions must have these attributes # CS - chip select (if internal, use -1) set UNKNOWN(0,CHIPSELECT) -1 # BASE - base address in memory set UNKNOWN(0,BASE) 0 # LEN - length in bytes set UNKNOWN(0,LEN) $CPU_MAX_ADDRESS # HUMAN - human name of the region set UNKNOWN(0,HUMAN) "unknown" # TYPE - one of: # flash, ram, mmr, unknown # For harvard arch: # iflash, dflash, iram, dram set UNKNOWN(0,TYPE) "unknown" # RWX - access ablity # unix style chmod bits # 0 - no access # 1 - execute # 2 - write # 4 - read # hence: 7 - readwrite execute set RWX_NO_ACCESS 0 set RWX_X_ONLY $BIT0 set RWX_W_ONLY $BIT1 set RWX_R_ONLY $BIT2 set RWX_RW [expr {$RWX_R_ONLY + $RWX_W_ONLY}] set RWX_R_X [expr {$RWX_R_ONLY + $RWX_X_ONLY}] set RWX_RWX [expr {$RWX_R_ONLY + $RWX_W_ONLY + $RWX_X_ONLY}] set UNKNOWN(0,RWX) $RWX_NO_ACCESS # WIDTH - access width # 8,16,32 [0 means ANY] set ACCESS_WIDTH_NONE 0 set ACCESS_WIDTH_8 $BIT0 set ACCESS_WIDTH_16 $BIT1 set ACCESS_WIDTH_32 $BIT2 set ACCESS_WIDTH_ANY [expr {$ACCESS_WIDTH_8 + $ACCESS_WIDTH_16 + $ACCESS_WIDTH_32}] set UNKNOWN(0,ACCESS_WIDTH) $ACCESS_WIDTH_NONE proc iswithin { ADDRESS BASE LEN } { return [expr {(($ADDRESS - $BASE) >= 0) && (($BASE + $LEN - $ADDRESS) > 0)}] } proc address_info { ADDRESS } { foreach WHERE { FLASH RAM MMREGS XMEM UNKNOWN } { if { info exists $WHERE } { set lmt [set N_[set WHERE]] for { set region 0 } { $region < $lmt } { incr region } { if { iswithin $ADDRESS $WHERE($region,BASE) $WHERE($region,LEN) } { return "$WHERE $region"; } } } } # Return the 'unknown' return "UNKNOWN 0" } proc memread32 {ADDR} { if ![ catch { set foo [read_memory $ADDR 32 1] } msg ] { return $foo } else { error "memread32: $msg" } } proc memread16 {ADDR} { if ![ catch { set foo [read_memory $ADDR 16 1] } msg ] { return $foo } else { error "memread16: $msg" } } proc memread8 {ADDR} { if ![ catch { set foo [read_memory $ADDR 8 1] } msg ] { return $foo } else { error "memread8: $msg" } } proc memwrite32 {ADDR DATA} { if ![ catch { write_memory $ADDR 32 $DATA } msg ] { return $DATA } else { error "memwrite32: $msg" } } proc memwrite16 {ADDR DATA} { if ![ catch { write_memory $ADDR 16 $DATA } msg ] { return $DATA } else { error "memwrite16: $msg" } } proc memwrite8 {ADDR DATA} { if ![ catch { write_memory $ADDR 8 $DATA } msg ] { return $DATA } else { error "memwrite8: $msg" } } proc memread32_phys {ADDR} { if ![ catch { set foo [read_memory $ADDR 32 1 phys] } msg ] { return $foo } else { error "memread32: $msg" } } proc memread16_phys {ADDR} { if ![ catch { set foo [read_memory $ADDR 16 1 phys] } msg ] { return $foo } else { error "memread16: $msg" } } proc memread8_phys {ADDR} { if ![ catch { set foo [read_memory $ADDR 8 1 phys] } msg ] { return $foo } else { error "memread8: $msg" } } proc memwrite32_phys {ADDR DATA} { if ![ catch { write_memory $ADDR 32 $DATA phys } msg ] { return $DATA } else { error "memwrite32: $msg" } } proc memwrite16_phys {ADDR DATA} { if ![ catch { write_memory $ADDR 16 $DATA phys } msg ] { return $DATA } else { error "memwrite16: $msg" } } proc memwrite8_phys {ADDR DATA} { if ![ catch { write_memory $ADDR 8 $DATA phys } msg ] { return $DATA } else { error "memwrite8: $msg" } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/mmr_helpers.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later proc proc_exists { NAME } { set n [info commands $NAME] set l [string length $n] return [expr {$l != 0}] } # Give: REGISTER name - must be a global variable. proc show_mmr32_reg { NAME } { global $NAME # we want $($NAME) set a [set [set NAME]] if ![catch { set v [memread32 $a] } msg ] { echo [format "%15s: (0x%08x): 0x%08x" $NAME $a $v] # Was a helper defined? set fn show_${NAME}_helper if [ proc_exists $fn ] { # Then call it $fn $NAME $a $v } return $v; } else { error [format "%s (%s)" $msg $NAME ] } } # Give: NAMES - an array of names accessible # in the callers symbol-scope. # VAL - the bits to display. proc show_mmr32_bits { NAMES VAL } { upvar $NAMES MYNAMES set w 5 foreach {IDX N} $MYNAMES { set l [string length $N] if { $l > $w } { set w $l } } for { set x 24 } { $x >= 0 } { incr x -8 } { echo -n " " for { set y 7 } { $y >= 0 } { incr y -1 } { set s $MYNAMES([expr {$x + $y}]) echo -n [format "%2d: %-*s | " [expr {$x + $y}] $w $s ] } echo "" echo -n " " for { set y 7 } { $y >= 0 } { incr y -1 } { echo -n [format " %d%*s | " [expr {!!($VAL & (1 << ($x + $y)))}] [expr {$w -1}] ""] } echo "" } } proc show_mmr_bitfield { MSB LSB VAL FIELDNAME FIELDVALUES } { set width [expr {(($MSB - $LSB + 1) + 7) / 4}] set nval [show_normalize_bitfield $VAL $MSB $LSB ] set name0 [lindex $FIELDVALUES 0 ] if [ string compare $name0 _NUMBER_ ] { set sval [lindex $FIELDVALUES $nval] } else { set sval "" } echo [format "%-15s: %d (0x%0*x) %s" $FIELDNAME $nval $width $nval $sval ] } # Give: ADDR - address of the register. # BIT - bit's number. proc get_mmr_bit { ADDR BIT } { set val [memread32 $ADDR] set bit_val [expr {$val & [expr {1 << $BIT}]}] return $bit_val } # Give: ADDR - address of the register. # MSB - MSB bit's number. # LSB - LSB bit's number. proc get_mmr_bitfield { ADDR MSB LSB } { set rval [memread32 $ADDR] return normalize_bitfield $rval $MSB $LSB } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/1986ве1т.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # 1986ВЕ1Т # http://milandr.ru/index.php?mact=Products,cntnt01,details,0&cntnt01productid=236&cntnt01returnid=68 source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME 1986ве1т } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x4ba00477 } { # SWD IDCODE set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # use AHB-Lite SRAM for work area $_TARGETNAME configure -work-area-phys 0x20100000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # can't handle overlapping memory regions if { [info exists IMEMORY] && [string equal $IMEMORY true] } { flash bank ${_CHIPNAME}_info.flash mdr 0x00000000 0x01000 0 0 $_TARGETNAME 1 1 4 } else { flash bank $_CHIPNAME.flash mdr 0x00000000 0x20000 0 0 $_TARGETNAME 0 32 4 } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz adapter speed 1000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/adsp-sc58x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Analog Devices ADSP-SC58x (ARM Cortex-A5 plus one or two SHARC+ DSPs) # # Evaluation boards by Analog Devices (and designs derived from them) use a # non-standard 10-pin 0.05" ARM Cortex Debug Connector. In this bastardized # implementation, pin 9 (GND or GNDDetect) has been usurped with JTAG /TRST. # # As a result, a standards-compliant debug pod will force /TRST active, # putting the processor's debug interface into reset and preventing usage. # # A connector adapter must be employed on these boards to isolate or remap # /TRST so that it is only asserted when intended. source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ADSP-SC58x } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3BA02477 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create ap0.mem mem_ap -dap $_CHIPNAME.dap -ap-num 0 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -event examine-end { global _TARGETNAME sc58x_enabledebug } proc sc58x_enabledebug {} { # Enable debugging functionality by setting bits in the TAPC_DBGCTL register # it is not possible to halt the target unless these bits have been set ap0.mem mww 0x31131000 0xFFFF } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/aduc702x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME aduc702x } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # This config file was defaulting to big endian.. set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } adapter srst delay 200 jtag_ntrst_delay 200 ## JTAG scan chain #format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE) jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID ## ## Target configuration ## set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME # allocate the entire SRAM as working area $_TARGETNAME configure -work-area-phys 0x10000 -work-area-size 0x2000 ## flash configuration # only target number is needed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME aduc702x 0 0 0 0 $_TARGETNAME ## If you use the watchdog, the following code makes sure that the board ## doesn't reboot when halted via JTAG. Yes, on the older generation ## AdUC702x, timer3 continues running even when the CPU is halted. proc watchdog_service {} { global watchdog_hdl mww 0xffff036c 0 # echo "watchdog!!" set watchdog_hdl [after 500 watchdog_service] } $_TARGETNAME configure -event reset-halt-post { watchdog_service } $_TARGETNAME configure -event resume-start { global watchdog_hdl; after cancel $watchdog_hdl } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/aducm360.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # This file was created using as references the stm32f1x.cfg and aduc702x.cfg # source [find target/swj-dp.tcl] # Chip name if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME aducm360 } # Endianness if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # Eventually, the whole SRAM of ADuCM360 will be used (8kB) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x2000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x2ba01477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # SWD/JTAG speed adapter speed 1000 ## ## Target configuration ## set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # allocate the working area $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME aducm360 0x00 0 0 0 $_TARGETNAME adapter srst delay 100 cortex_m reset_config sysresetreq ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/allwinner_v3s.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is the config for an Allwinner V3/V3s (sun8iw8). # # Notes: # - Single core ARM Cortex-A7 with a maximum frequency of 1.2 GHz. # - Thumb-2 Technology # - Support NEON Advanced SIMD(Single Instruction Multiple Data)instruction # for acceleration of media and signal processing functions # - Support Large Physical Address Extensions(LPAE) # - VFPv4 Floating Point Unit # - 32KB L1 Instruction cache and 32KB L1 Data cache # - 128KB L2 cache # - has some integrated DDR2 RAM. # # Pins related for debug and bootstrap: # JTAG # JTAG_TMS PF0, SDC0_D1 # JTAG_TDI PF1, SDC0_D0 # JTAG_TDO PF3, SDC0_CMD # JTAG_TCK PF5, SDC0_D2 # UART # None of UART ports seems to be enabled by ROM. # UART0_TX PF2, SDC0_CLK Per default disabled # UART0_RX PF4, SDC0_D3 Per default disabled # UART1_TX PE21 Per default disabled # UART1_RX PE22 Per default disabled # UART2_TX PB0 Per default disabled # UART2_RX PB1 Per default disabled # # JTAG is enabled by default after power on on listed JTAG_* pins. So far the # boot sequence is: # Time Action # 0000ms Power ON # 0200ms JTAG enabled # 0220ms JTAG pins switched to SD mode # # The time frame of 20ms can be not enough to init and halt the CPU. In this # case I would recommend to set: "adapter speed 15000" # To get more or less precise timings, the board should provide reset pin, # or some bench power supply with remote function. In my case I used # EEZ H24005 with this command to power on and halt the target: # "exec echo "*TRG" > /dev/ttyACM0; sleep 220; reset halt" # After this it is possible to enable JTAG mode again from boot loader or OS. # Following DAPs are available: # dap[0]->MEM-AP AHB # dap[1]->MEM-AP APB->CA7[0] # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME v3s } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } # No NRST or SRST is present on the SoC. Boards may provide # some sort of Power cycle reset for complete board or SoC. # For this case we provide srst_pulls_trst so the board config # only needs to set srst_only. reset_config none srst_pulls_trst jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # Add Cortex A7 core set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/alphascale_asm9260t.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME asm9260t } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x079264F3 } # And srst_pulls_trst by chip design. reset_config srst_pulls_trst jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/altera_fpgasoc.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Altera cyclone V SoC family, 5Cxxx # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME fpgasoc } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # Subsidiary TAP: fpga if { [info exists FPGA_TAPID] } { set _FPGA_TAPID $FPGA_TAPID } else { set _FPGA_TAPID 0x02d020dd } jtag newtap $_CHIPNAME.fpga tap -irlen 10 -ircapture 0x01 -irmask 0x3 -expected-id $_FPGA_TAPID # # Cortex-A9 target # # GDB target: Cortex-A9, using DAP, configuring only one core # Base addresses of cores: # core 0 - 0x80110000 # core 1 - 0x80112000 # Slow speed to be sure it will work adapter speed 1000 set _TARGETNAME1 $_CHIPNAME.cpu.0 set _TARGETNAME2 $_CHIPNAME.cpu.1 # A9 core 0 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME1 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80110000 $_TARGETNAME1 configure -event reset-start { adapter speed 1000 } $_TARGETNAME1 configure -event reset-assert-post "cycv_dbginit $_TARGETNAME1" # A9 core 1 #target create $_TARGETNAME2 cortex_a -dap $_CHIPNAME.dap \ # -coreid 1 -dbgbase 0x80112000 #$_TARGETNAME2 configure -event reset-start { adapter speed 1000 } #$_TARGETNAME2 configure -event reset-assert-post "cycv_dbginit $_TARGETNAME2" proc cycv_dbginit {target} { # General Cortex-A8/A9 debug initialisation cortex_a dbginit } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/altera_fpgasoc_arria10.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Intel (Altera) Arria10 FPGA SoC if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME arria10 } # ARM CoreSight Debug Access Port (dap HPS) if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_DAP_TAPID # Subsidiary TAP: fpga (tap) # See Intel Arria 10 Handbook # https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/hb/arria-10/a10_handbook.pdf # Intel Arria 10 GX 160 0x02ee20dd # Intel Arria 10 GX 220 0x02e220dd # Intel Arria 10 GX 270 0x02ee30dd # Intel Arria 10 GX 320 0x02e230dd # Intel Arria 10 GX 480 0x02e240dd # Intel Arria 10 GX 570 0x02ee50dd # Intel Arria 10 GX 660 0x02e250dd # Intel Arria 10 GX 900 0x02ee60dd # Intel Arria 10 GX 1150 0x02e660dd # Intel Arria 10 GT 900 0x02e260dd # Intel Arria 10 GT 1150 0x02e060dd # Intel Arria 10 SX 160 0x02e620dd # Intel Arria 10 SX 220 0x02e020dd # Intel Arria 10 SX 270 0x02e630dd # Intel Arria 10 SX 320 0x02e030dd # Intel Arria 10 SX 480 0x02e040dd # Intel Arria 10 SX 570 0x02e650dd # Intel Arria 10 SX 660 0x02e050dd jtag newtap $_CHIPNAME.fpga tap -irlen 10 -expected-id 0x02ee20dd -expected-id 0x02e220dd \ -expected-id 0x02ee30dd -expected-id 0x02e230dd -expected-id 0x02e240dd \ -expected-id 0x02ee50dd -expected-id 0x02e250dd -expected-id 0x02ee60dd \ -expected-id 0x02e660dd -expected-id 0x02e260dd -expected-id 0x02e060dd \ -expected-id 0x02e620dd -expected-id 0x02e020dd -expected-id 0x02e630dd \ -expected-id 0x02e030dd -expected-id 0x02e040dd -expected-id 0x02e650dd \ -expected-id 0x02e050dd set _TARGETNAME $_CHIPNAME.cpu # # Cortex-A9 target dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME.0 cortex_a -dap $_CHIPNAME.dap -coreid 0 target create $_TARGETNAME.1 cortex_a -dap $_CHIPNAME.dap -coreid 1 \ -defer-examine target smp $_TARGETNAME.0 $_TARGETNAME.1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/am335x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/icepick.cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME am335x } # set the taps to be enabled by default. this can be overridden # by setting DEFAULT_TAPS in a separate configuration file # or directly on the command line. if { [info exists DEFAULT_TAPS] } { set _DEFAULT_TAPS "$DEFAULT_TAPS" } else { set _DEFAULT_TAPS "$_CHIPNAME.tap" } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4b6b902f } jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.tap -event tap-enable "icepick_d_tapenable $_CHIPNAME.jrc 12 0" dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap # # M3 DAP # if { [info exists M3_DAP_TAPID] } { set _M3_DAP_TAPID $M3_DAP_TAPID } else { set _M3_DAP_TAPID 0x4b6b902f } jtag newtap $_CHIPNAME m3_tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_M3_DAP_TAPID -disable jtag configure $_CHIPNAME.m3_tap -event tap-enable "icepick_d_tapenable $_CHIPNAME.jrc 11 0" dap create $_CHIPNAME.m3_dap -chain-position $_CHIPNAME.m3_tap # # ICEpick-D (JTAG route controller) # if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0b94402f } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version jtag configure $_CHIPNAME.jrc -event setup { global _DEFAULT_TAPS enable_default_taps $_DEFAULT_TAPS } # some TCK tycles are required to activate the DEBUG power domain jtag configure $_CHIPNAME.jrc -event post-reset "runtest 100" # # helper function that enables all taps passed as argument # proc enable_default_taps { taps } { foreach tap $taps { jtag tapenable $tap } } # # Cortex-M3 target # set _TARGETNAME_2 $_CHIPNAME.m3 target create $_TARGETNAME_2 cortex_m -dap $_CHIPNAME.m3_dap # # Cortex-A8 target # set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap -dbgbase 0x80001000 # SRAM: 64K at 0x4030.0000; use the first 16K $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x4000 # when putting the target into 'reset halt', we need to disable the watchdog as # it would otherwise trigger while we're in JTAG # FIXME: unify with target/am437x.cfg source [find mem_helper.tcl] set WDT1_BASE_ADDR 0x44e35000 set WDT1_W_PEND_WSPR [expr {$WDT1_BASE_ADDR + 0x0034}] set WDT1_WSPR [expr {$WDT1_BASE_ADDR + 0x0048}] proc disable_watchdog { } { global WDT1_WSPR global WDT1_W_PEND_WSPR global _TARGETNAME set curstate [$_TARGETNAME curstate] if { [string compare $curstate halted] == 0 } { set WDT_DISABLE_SEQ1 0xaaaa set WDT_DISABLE_SEQ2 0x5555 mww phys $WDT1_WSPR $WDT_DISABLE_SEQ1 # Empty body to make sure this executes as fast as possible. # We don't want any delays here otherwise romcode might start # executing and end up changing state of certain IPs. while { [expr {[mrw $WDT1_W_PEND_WSPR] & 0x10}] } { } mww phys $WDT1_WSPR $WDT_DISABLE_SEQ2 while { [expr {[mrw $WDT1_W_PEND_WSPR] & 0x10}] } { } } } $_TARGETNAME configure -event reset-end { disable_watchdog } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/am437x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/icepick.cfg] source [find mem_helper.tcl] ############################################################################### ## AM437x Registers ## ############################################################################### set PRCM_BASE_ADDR 0x44df0000 set REVISION_PRM [expr {$PRCM_BASE_ADDR + 0x0000}] set PRM_IRQSTATUS_MPU [expr {$PRCM_BASE_ADDR + 0x0004}] set PRM_IRQENABLE_MPU [expr {$PRCM_BASE_ADDR + 0x0008}] set PRM_IRQSTATUS_M3 [expr {$PRCM_BASE_ADDR + 0x000c}] set PRM_IRQENABLE_M3 [expr {$PRCM_BASE_ADDR + 0x0010}] set PM_MPU_PWRSTCTRL [expr {$PRCM_BASE_ADDR + 0x0300}] set PM_MPU_PWRSTST [expr {$PRCM_BASE_ADDR + 0x0304}] set RM_MPU_RSTST [expr {$PRCM_BASE_ADDR + 0x0314}] set RM_MPU_CONTEXT [expr {$PRCM_BASE_ADDR + 0x0324}] set PM_GFX_PWRSTCTRL [expr {$PRCM_BASE_ADDR + 0x0400}] set PM_GFX_PWRSTST [expr {$PRCM_BASE_ADDR + 0x0404}] set RM_GFX_RSTCTRL [expr {$PRCM_BASE_ADDR + 0x0410}] set RM_GFX_RSTST [expr {$PRCM_BASE_ADDR + 0x0414}] set RM_GFX_CONTEXT [expr {$PRCM_BASE_ADDR + 0x0424}] set RM_RTC_CONTEXT [expr {$PRCM_BASE_ADDR + 0x0524}] set RM_WKUP_RSTCTRL [expr {$PRCM_BASE_ADDR + 0x2010}] set RM_WKUP_RSTST [expr {$PRCM_BASE_ADDR + 0x2014}] set CM_L3_AON_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x2800}] set CM_WKUP_DEBUGSS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2820}] set CM_L3S_TSC_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x2900}] set CM_WKUP_ADC_TSC_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2920}] set CM_L4_WKUP_AON_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x2a00}] set CM_WKUP_L4WKUP_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a20}] set CM_WKUP_WKUP_M3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a28}] set CM_WKUP_SYNCTIMER_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a30}] set CM_WKUP_CLKDIV32K_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a38}] set CM_WKUP_USBPHY0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a40}] set CM_WKUP_USBPHY1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a48}] set CM_WKUP_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x2b00}] set CM_WKUP_TIMER0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b20}] set CM_WKUP_TIMER1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b28}] set CM_WKUP_WDT0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b30}] set CM_WKUP_WDT1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b38}] set CM_WKUP_I2C0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b40}] set CM_WKUP_UART0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b48}] set CM_WKUP_SMARTREFLEX0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b50}] set CM_WKUP_SMARTREFLEX1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b58}] set CM_WKUP_CONTROL_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b60}] set CM_WKUP_GPIO0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b68}] set CM_CLKMODE_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d20}] set CM_IDLEST_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d24}] set CM_CLKSEL_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d2c}] set CM_DIV_M4_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d38}] set CM_DIV_M5_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d3c}] set CM_DIV_M6_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d40}] set CM_SSC_DELTAMSTEP_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d48}] set CM_SSC_MODFREQDIV_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d4c}] set CM_CLKMODE_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d60}] set CM_IDLEST_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d64}] set CM_CLKSEL_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d6c}] set CM_DIV_M2_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d70}] set CM_SSC_DELTAMSTEP_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d88}] set CM_SSC_MODFREQDIV_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d8c}] set CM_CLKMODE_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2da0}] set CM_IDLEST_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2da4}] set CM_CLKSEL_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2dac}] set CM_DIV_M2_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2db0}] set CM_DIV_M4_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2db8}] set CM_SSC_DELTAMSTEP_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2dc8}] set CM_SSC_MODFREQDIV_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2dcc}] set CM_CLKMODE_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2de0}] set CM_IDLEST_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2de4}] set CM_CLKSEL_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2dec}] set CM_DIV_M2_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2df0}] set CM_CLKSEL2_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2e04}] set CM_SSC_DELTAMSTEP_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2e08}] set CM_SSC_MODFREQDIV_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2e0c}] set CM_CLKDCOLDO_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2e14}] set CM_CLKMODE_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e20}] set CM_IDLEST_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e24}] set CM_CLKSEL_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e2c}] set CM_DIV_M2_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e30}] set CM_SSC_DELTAMSTEP_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e48}] set CM_SSC_MODFREQDIV_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e4c}] set CM_CLKMODE_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e60}] set CM_IDLEST_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e64}] set CM_CLKSEL_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e6c}] set CM_DIV_M2_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e70}] set CM_CLKSEL2_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e84}] set CM_SSC_DELTAMSTEP_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e88}] set CM_SSC_MODFREQDIV_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e8c}] set CM_SHADOW_FREQ_CONFIG1 [expr {$PRCM_BASE_ADDR + 0x2fa0}] set CM_SHADOW_FREQ_CONFIG2 [expr {$PRCM_BASE_ADDR + 0x2fa4}] set CM_CLKOUT1_CTRL [expr {$PRCM_BASE_ADDR + 0x4100}] set CM_DLL_CTRL [expr {$PRCM_BASE_ADDR + 0x4104}] set CM_CLKOUT2_CTRL [expr {$PRCM_BASE_ADDR + 0x4108}] set CLKSEL_TIMER1MS_CLK [expr {$PRCM_BASE_ADDR + 0x4200}] set CLKSEL_TIMER2_CLK [expr {$PRCM_BASE_ADDR + 0x4204}] set CLKSEL_TIMER3_CLK [expr {$PRCM_BASE_ADDR + 0x4208}] set CLKSEL_TIMER4_CLK [expr {$PRCM_BASE_ADDR + 0x420c}] set CLKSEL_TIMER5_CLK [expr {$PRCM_BASE_ADDR + 0x4210}] set CLKSEL_TIMER6_CLK [expr {$PRCM_BASE_ADDR + 0x4214}] set CLKSEL_TIMER7_CLK [expr {$PRCM_BASE_ADDR + 0x4218}] set CLKSEL_TIMER8_CLK [expr {$PRCM_BASE_ADDR + 0x421c}] set CLKSEL_TIMER9_CLK [expr {$PRCM_BASE_ADDR + 0x4220}] set CLKSEL_TIMER10_CLK [expr {$PRCM_BASE_ADDR + 0x4224}] set CLKSEL_TIMER11_CLK [expr {$PRCM_BASE_ADDR + 0x4228}] set CLKSEL_WDT1_CLK [expr {$PRCM_BASE_ADDR + 0x422c}] set CLKSEL_SYNCTIMER_CLK [expr {$PRCM_BASE_ADDR + 0x4230}] set CLKSEL_MAC_CLK [expr {$PRCM_BASE_ADDR + 0x4234}] set CLKSEL_CPTS_RFT_CLK [expr {$PRCM_BASE_ADDR + 0x4238}] set CLKSEL_GFX_FCLK [expr {$PRCM_BASE_ADDR + 0x423c}] set CLKSEL_GPIO0_DBCLK [expr {$PRCM_BASE_ADDR + 0x4240}] set CLKSEL_LCDC_PIXEL_CLK [expr {$PRCM_BASE_ADDR + 0x4244}] set CLKSEL_ICSS_OCP_CLK [expr {$PRCM_BASE_ADDR + 0x4248}] set CLKSEL_DLL_AGING_CLK [expr {$PRCM_BASE_ADDR + 0x4250}] set CLKSEL_USBPHY32KHZ_GCLK [expr {$PRCM_BASE_ADDR + 0x4260}] set CM_MPU_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8300}] set CM_MPU_MPU_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8320}] set CM_GFX_L3_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8400}] set CM_GFX_GFX_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8420}] set CM_RTC_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8500}] set CM_RTC_RTC_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8520}] set CM_PER_L3_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8800}] set CM_PER_L3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8820}] set CM_PER_AES0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8828}] set CM_PER_DES_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8830}] set CM_PER_CRYPTODMA_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8838}] set CM_PER_L3_INSTR_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8840}] set CM_PER_MSTR_EXPS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8848}] set CM_PER_OCMCRAM_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8850}] set CM_PER_SHA0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8858}] set CM_PER_SLV_EXPS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8860}] set CM_PER_VPFE0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8868}] set CM_PER_VPFE1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8870}] set CM_PER_TPCC_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8878}] set CM_PER_TPTC0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8880}] set CM_PER_TPTC1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8888}] set CM_PER_TPTC2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8890}] set CM_PER_DLL_AGING_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8898}] set CM_PER_L4HS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x88a0}] set CM_PER_L4FW_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x88a8}] set CM_PER_L3S_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8a00}] set CM_PER_GPMC_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a20}] set CM_PER_IEEE5000_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a28}] set CM_PER_MCASP0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a38}] set CM_PER_MCASP1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a40}] set CM_PER_MMC2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a48}] set CM_PER_QSPI_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a58}] set CM_PER_USB_OTG_SS0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a60}] set CM_PER_USB_OTG_SS1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a68}] set CM_PER_ICSS_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8b00}] set CM_PER_ICSS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8b20}] set CM_PER_L4LS_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8c00}] set CM_PER_L4LS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c20}] set CM_PER_DCAN0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c28}] set CM_PER_DCAN1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c30}] set CM_PER_EPWMSS0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c38}] set CM_PER_EPWMSS1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c40}] set CM_PER_EPWMSS2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c48}] set CM_PER_EPWMSS3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c50}] set CM_PER_EPWMSS4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c58}] set CM_PER_EPWMSS5_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c60}] set CM_PER_ELM_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c68}] set CM_PER_GPIO1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c78}] set CM_PER_GPIO2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c80}] set CM_PER_GPIO3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c88}] set CM_PER_GPIO4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c90}] set CM_PER_GPIO5_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c98}] set CM_PER_HDQ1W_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8ca0}] set CM_PER_I2C1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8ca8}] set CM_PER_I2C2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cb0}] set CM_PER_MAILBOX0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cb8}] set CM_PER_MMC0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cc0}] set CM_PER_MMC1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cc8}] set CM_PER_PKA_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cd0}] set CM_PER_RNG_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8ce0}] set CM_PER_SPARE0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8ce8}] set CM_PER_SPARE1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cf0}] set CM_PER_SPI0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d00}] set CM_PER_SPI1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d08}] set CM_PER_SPI2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d10}] set CM_PER_SPI3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d18}] set CM_PER_SPI4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d20}] set CM_PER_SPINLOCK_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d28}] set CM_PER_TIMER2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d30}] set CM_PER_TIMER3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d38}] set CM_PER_TIMER4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d40}] set CM_PER_TIMER5_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d48}] set CM_PER_TIMER6_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d50}] set CM_PER_TIMER7_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d58}] set CM_PER_TIMER8_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d60}] set CM_PER_TIMER9_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d68}] set CM_PER_TIMER10_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d70}] set CM_PER_TIMER11_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d78}] set CM_PER_UART1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d80}] set CM_PER_UART2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d88}] set CM_PER_UART3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d90}] set CM_PER_UART4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d98}] set CM_PER_UART5_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8da0}] set CM_PER_USBPHYOCP2SCP0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8db8}] set CM_PER_USBPHYOCP2SCP1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8dc0}] set CM_PER_EMIF_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8f00}] set CM_PER_EMIF_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8f20}] set CM_PER_DLL_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8f28}] set CM_PER_EMIF_FW_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8f30}] set CM_PER_OTFA_EMIF_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8f38}] set CM_PER_DSS_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x9200}] set CM_PER_DSS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x9220}] set CM_PER_CPSW_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x9300}] set CM_PER_CPGMAC0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x9320}] set CM_PER_OCPWP_L3_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x9400}] set CM_PER_OCPWP_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x9420}] set CONTROL_BASE_ADDR 0x44e10000 set CONTROL_STATUS [expr {$CONTROL_BASE_ADDR + 0x0040}] set DEVICE_ID [expr {$CONTROL_BASE_ADDR + 0x0600}] set DEV_FEATURE [expr {$CONTROL_BASE_ADDR + 0x0604}] set DEV_ATTRIBUTE [expr {$CONTROL_BASE_ADDR + 0x0610}] set MAC_ID0_LO [expr {$CONTROL_BASE_ADDR + 0x0630}] set MAC_ID0_HI [expr {$CONTROL_BASE_ADDR + 0x0634}] set MAC_ID1_LO [expr {$CONTROL_BASE_ADDR + 0x0638}] set MAC_ID1_HI [expr {$CONTROL_BASE_ADDR + 0x063c}] set USB_VID_PID [expr {$CONTROL_BASE_ADDR + 0x07f4}] set CONTROL_CONF_ECAP0_IN_PWM0_OUT [expr {$CONTROL_BASE_ADDR + 0x0964}] set CONTROL_CONF_SPI4_CS0 [expr {$CONTROL_BASE_ADDR + 0x0a5c}] set CONTROL_CONF_SPI2_SCLK [expr {$CONTROL_BASE_ADDR + 0x0a60}] set CONTROL_CONF_SPI2_D0 [expr {$CONTROL_BASE_ADDR + 0x0a64}] set CONTROL_CONF_XDMA_EVENT_INTR0 [expr {$CONTROL_BASE_ADDR + 0x0a70}] set CONTROL_CONF_XDMA_EVENT_INTR1 [expr {$CONTROL_BASE_ADDR + 0x0a74}] set CONTROL_CONF_GPMC_A0 [expr {$CONTROL_BASE_ADDR + 0x0840}] set DDR_IO_CTRL [expr {$CONTROL_BASE_ADDR + 0x0e04}] set VTP_CTRL_REG [expr {$CONTROL_BASE_ADDR + 0x0e0c}] set VREF_CTRL [expr {$CONTROL_BASE_ADDR + 0x0e14}] set DDR_CKE_CTRL [expr {$CONTROL_BASE_ADDR + 0x131c}] set DDR_ADDRCTRL_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1404}] set DDR_ADDRCTRL_WD0_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1408}] set DDR_ADDRCTRL_WD1_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x140c}] set DDR_DATA0_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1440}] set DDR_DATA1_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1444}] set DDR_DATA2_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1448}] set DDR_DATA3_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x144c}] set EMIF_SDRAM_CONFIG_EXT [expr {$CONTROL_BASE_ADDR + 0x1460}] set EMIF_SDRAM_STATUS_EXT [expr {$CONTROL_BASE_ADDR + 0x1464}] set GPIO0_BASE_ADDR 0x44e07000 set GPIO0_SYSCONFIG [expr {$GPIO0_BASE_ADDR + 0x0010}] set GPIO0_SYSSTATUS [expr {$GPIO0_BASE_ADDR + 0x0114}] set GPIO0_CTRL [expr {$GPIO0_BASE_ADDR + 0x0130}] set GPIO0_OE [expr {$GPIO0_BASE_ADDR + 0x0134}] set GPIO0_CLEARDATAOUT [expr {$GPIO0_BASE_ADDR + 0x0190}] set GPIO0_SETDATAOUT [expr {$GPIO0_BASE_ADDR + 0x0194}] set GPIO5_BASE_ADDR 0x48322000 set GPIO5_SYSCONFIG [expr {$GPIO5_BASE_ADDR + 0x0010}] set GPIO5_SYSSTATUS [expr {$GPIO5_BASE_ADDR + 0x0114}] set GPIO5_CTRL [expr {$GPIO5_BASE_ADDR + 0x0130}] set GPIO5_OE [expr {$GPIO5_BASE_ADDR + 0x0134}] set GPIO5_CLEARDATAOUT [expr {$GPIO5_BASE_ADDR + 0x0190}] set GPIO5_SETDATAOUT [expr {$GPIO5_BASE_ADDR + 0x0194}] set GPIO1_BASE_ADDR 0x4804c000 set GPIO1_SYSCONFIG [expr {$GPIO1_BASE_ADDR + 0x0010}] set GPIO1_SYSSTATUS [expr {$GPIO1_BASE_ADDR + 0x0114}] set GPIO1_CTRL [expr {$GPIO1_BASE_ADDR + 0x0130}] set GPIO1_OE [expr {$GPIO1_BASE_ADDR + 0x0134}] set GPIO1_CLEARDATAOUT [expr {$GPIO1_BASE_ADDR + 0x0190}] set GPIO1_SETDATAOUT [expr {$GPIO1_BASE_ADDR + 0x0194}] set EMIF_BASE_ADDR 0x4c000000 set EMIF_STATUS [expr {$EMIF_BASE_ADDR + 0x0004}] set EMIF_SDRAM_CONFIG [expr {$EMIF_BASE_ADDR + 0x0008}] set EMIF_SDRAM_CONFIG_2 [expr {$EMIF_BASE_ADDR + 0x000c}] set EMIF_SDRAM_REF_CTRL [expr {$EMIF_BASE_ADDR + 0x0010}] set EMIF_SDRAM_REF_CTRL_SHDW [expr {$EMIF_BASE_ADDR + 0x0014}] set EMIF_SDRAM_TIM_1 [expr {$EMIF_BASE_ADDR + 0x0018}] set EMIF_SDRAM_TIM_1_SHDW [expr {$EMIF_BASE_ADDR + 0x001c}] set EMIF_SDRAM_TIM_2 [expr {$EMIF_BASE_ADDR + 0x0020}] set EMIF_SDRAM_TIM_2_SHDW [expr {$EMIF_BASE_ADDR + 0x0024}] set EMIF_SDRAM_TIM_3 [expr {$EMIF_BASE_ADDR + 0x0028}] set EMIF_SDRAM_TIM_3_SHDW [expr {$EMIF_BASE_ADDR + 0x002c}] set EMIF_LPDDR2_NVM_TIM [expr {$EMIF_BASE_ADDR + 0x0030}] set EMIF_LPDDR2_NVM_TIM_SHDW [expr {$EMIF_BASE_ADDR + 0x0034}] set EMIF_PWR_MGMT_CTRL [expr {$EMIF_BASE_ADDR + 0x0038}] set EMIF_PWR_MGMT_CTRL_SHDW [expr {$EMIF_BASE_ADDR + 0x003c}] set EMIF_LPDDR2_MODE_REG_DATA [expr {$EMIF_BASE_ADDR + 0x0040}] set EMIF_LPDDR2_MODE_REG_CFG [expr {$EMIF_BASE_ADDR + 0x0050}] set EMIF_OCP_CONFIG [expr {$EMIF_BASE_ADDR + 0x0054}] set EMIF_OCP_CFG_VAL_1 [expr {$EMIF_BASE_ADDR + 0x0058}] set EMIF_OCP_CFG_VAL_2 [expr {$EMIF_BASE_ADDR + 0x005c}] set EMIF_IODFT_TLGC [expr {$EMIF_BASE_ADDR + 0x0060}] set EMIF_IODFT_CTRL_MISR_RSLT [expr {$EMIF_BASE_ADDR + 0x0064}] set EMIF_IODFT_ADDR_MISR_RSLT [expr {$EMIF_BASE_ADDR + 0x0068}] set EMIF_IODFT_DATA_MISR_RSLT_1 [expr {$EMIF_BASE_ADDR + 0x006c}] set EMIF_IODFT_DATA_MISR_RSLT_2 [expr {$EMIF_BASE_ADDR + 0x0070}] set EMIF_IODFT_DATA_MISR_RSLT_3 [expr {$EMIF_BASE_ADDR + 0x0074}] set EMIF_PERF_CNT_1 [expr {$EMIF_BASE_ADDR + 0x0080}] set EMIF_PERF_CNT_2 [expr {$EMIF_BASE_ADDR + 0x0084}] set EMIF_PERF_CNT_CFG [expr {$EMIF_BASE_ADDR + 0x0088}] set EMIF_PERF_CNT_SEL [expr {$EMIF_BASE_ADDR + 0x008c}] set EMIF_PERF_CNT_TIM [expr {$EMIF_BASE_ADDR + 0x0090}] set EMIF_MISC_REG [expr {$EMIF_BASE_ADDR + 0x0094}] set EMIF_DLL_CALIB_CTRL [expr {$EMIF_BASE_ADDR + 0x0098}] set EMIF_DLL_CALIB_CTRL_SHDW [expr {$EMIF_BASE_ADDR + 0x009c}] set EMIF_IRQ_EOI [expr {$EMIF_BASE_ADDR + 0x00a0}] set EMIF_IRQSTATUS_RAW_SYS [expr {$EMIF_BASE_ADDR + 0x00a4}] set EMIF_IRQSTATUS_SYS [expr {$EMIF_BASE_ADDR + 0x00ac}] set EMIF_IRQENABLE_SET_SYS [expr {$EMIF_BASE_ADDR + 0x00b4}] set EMIF_IRQENABLE_CLR_SYS [expr {$EMIF_BASE_ADDR + 0x00bc}] set EMIF_ZQ_CONFIG [expr {$EMIF_BASE_ADDR + 0x00c8}] set EMIF_TEMP_ALERT_CONFIG [expr {$EMIF_BASE_ADDR + 0x00cc}] set EMIF_OCP_ERR_LOG [expr {$EMIF_BASE_ADDR + 0x00d0}] set EMIF_RDWR_LVL_RMP_WIN [expr {$EMIF_BASE_ADDR + 0x00d4}] set EMIF_RDWR_LVL_RMP_CTRL [expr {$EMIF_BASE_ADDR + 0x00d8}] set EMIF_RDWR_LVL_CTRL [expr {$EMIF_BASE_ADDR + 0x00dc}] set EMIF_DDR_PHY_CTRL_1 [expr {$EMIF_BASE_ADDR + 0x00e4}] set EMIF_DDR_PHY_CTRL_1_SHDW [expr {$EMIF_BASE_ADDR + 0x00e8}] set EMIF_DDR_PHY_CTRL_2 [expr {$EMIF_BASE_ADDR + 0x00ec}] set EMIF_PRI_COS_MAP [expr {$EMIF_BASE_ADDR + 0x0100}] set EMIF_CONNID_COS_1_MAP [expr {$EMIF_BASE_ADDR + 0x0104}] set EMIF_CONNID_COS_2_MAP [expr {$EMIF_BASE_ADDR + 0x0108}] set ECC_CTRL [expr {$EMIF_BASE_ADDR + 0x0110}] set ECC_ADDR_RNG_1 [expr {$EMIF_BASE_ADDR + 0x0114}] set ECC_ADDR_RNG_2 [expr {$EMIF_BASE_ADDR + 0x0118}] set EMIF_RD_WR_EXEC_THRSH [expr {$EMIF_BASE_ADDR + 0x0120}] set COS_CONFIG [expr {$EMIF_BASE_ADDR + 0x0124}] set PHY_STATUS_1 [expr {$EMIF_BASE_ADDR + 0x0144}] set PHY_STATUS_2 [expr {$EMIF_BASE_ADDR + 0x0148}] set PHY_STATUS_3 [expr {$EMIF_BASE_ADDR + 0x014c}] set PHY_STATUS_4 [expr {$EMIF_BASE_ADDR + 0x0150}] set PHY_STATUS_5 [expr {$EMIF_BASE_ADDR + 0x0154}] set PHY_STATUS_6 [expr {$EMIF_BASE_ADDR + 0x0158}] set PHY_STATUS_7 [expr {$EMIF_BASE_ADDR + 0x015c}] set PHY_STATUS_8 [expr {$EMIF_BASE_ADDR + 0x0160}] set PHY_STATUS_9 [expr {$EMIF_BASE_ADDR + 0x0164}] set PHY_STATUS_10 [expr {$EMIF_BASE_ADDR + 0x0168}] set PHY_STATUS_11 [expr {$EMIF_BASE_ADDR + 0x016c}] set PHY_STATUS_12 [expr {$EMIF_BASE_ADDR + 0x0170}] set PHY_STATUS_13 [expr {$EMIF_BASE_ADDR + 0x0174}] set PHY_STATUS_14 [expr {$EMIF_BASE_ADDR + 0x0178}] set PHY_STATUS_15 [expr {$EMIF_BASE_ADDR + 0x017c}] set PHY_STATUS_16 [expr {$EMIF_BASE_ADDR + 0x0180}] set PHY_STATUS_17 [expr {$EMIF_BASE_ADDR + 0x0184}] set PHY_STATUS_18 [expr {$EMIF_BASE_ADDR + 0x0188}] set PHY_STATUS_19 [expr {$EMIF_BASE_ADDR + 0x018c}] set PHY_STATUS_20 [expr {$EMIF_BASE_ADDR + 0x0190}] set PHY_STATUS_21 [expr {$EMIF_BASE_ADDR + 0x0194}] set PHY_STATUS_22 [expr {$EMIF_BASE_ADDR + 0x0198}] set PHY_STATUS_23 [expr {$EMIF_BASE_ADDR + 0x019c}] set PHY_STATUS_24 [expr {$EMIF_BASE_ADDR + 0x01a0}] set PHY_STATUS_25 [expr {$EMIF_BASE_ADDR + 0x01a4}] set PHY_STATUS_26 [expr {$EMIF_BASE_ADDR + 0x01a8}] set PHY_STATUS_27 [expr {$EMIF_BASE_ADDR + 0x01ac}] set PHY_STATUS_28 [expr {$EMIF_BASE_ADDR + 0x01b0}] set EXT_PHY_CTRL_1 [expr {$EMIF_BASE_ADDR + 0x0200}] set EXT_PHY_CTRL_1_SHDW [expr {$EMIF_BASE_ADDR + 0x0204}] set EXT_PHY_CTRL_2 [expr {$EMIF_BASE_ADDR + 0x0208}] set EXT_PHY_CTRL_2_SHDW [expr {$EMIF_BASE_ADDR + 0x020c}] set EXT_PHY_CTRL_3 [expr {$EMIF_BASE_ADDR + 0x0210}] set EXT_PHY_CTRL_3_SHDW [expr {$EMIF_BASE_ADDR + 0x0214}] set EXT_PHY_CTRL_4 [expr {$EMIF_BASE_ADDR + 0x0218}] set EXT_PHY_CTRL_4_SHDW [expr {$EMIF_BASE_ADDR + 0x021c}] set EXT_PHY_CTRL_5 [expr {$EMIF_BASE_ADDR + 0x0220}] set EXT_PHY_CTRL_5_SHDW [expr {$EMIF_BASE_ADDR + 0x0224}] set EXT_PHY_CTRL_6 [expr {$EMIF_BASE_ADDR + 0x0228}] set EXT_PHY_CTRL_6_SHDW [expr {$EMIF_BASE_ADDR + 0x022c}] set EXT_PHY_CTRL_7 [expr {$EMIF_BASE_ADDR + 0x0230}] set EXT_PHY_CTRL_7_SHDW [expr {$EMIF_BASE_ADDR + 0x0234}] set EXT_PHY_CTRL_8 [expr {$EMIF_BASE_ADDR + 0x0238}] set EXT_PHY_CTRL_8_SHDW [expr {$EMIF_BASE_ADDR + 0x023c}] set EXT_PHY_CTRL_9 [expr {$EMIF_BASE_ADDR + 0x0240}] set EXT_PHY_CTRL_9_SHDW [expr {$EMIF_BASE_ADDR + 0x0244}] set EXT_PHY_CTRL_10 [expr {$EMIF_BASE_ADDR + 0x0248}] set EXT_PHY_CTRL_10_SHDW [expr {$EMIF_BASE_ADDR + 0x024c}] set EXT_PHY_CTRL_11 [expr {$EMIF_BASE_ADDR + 0x0250}] set EXT_PHY_CTRL_11_SHDW [expr {$EMIF_BASE_ADDR + 0x0254}] set EXT_PHY_CTRL_12 [expr {$EMIF_BASE_ADDR + 0x0258}] set EXT_PHY_CTRL_12_SHDW [expr {$EMIF_BASE_ADDR + 0x025c}] set EXT_PHY_CTRL_13 [expr {$EMIF_BASE_ADDR + 0x0260}] set EXT_PHY_CTRL_13_SHDW [expr {$EMIF_BASE_ADDR + 0x0264}] set EXT_PHY_CTRL_14 [expr {$EMIF_BASE_ADDR + 0x0268}] set EXT_PHY_CTRL_14_SHDW [expr {$EMIF_BASE_ADDR + 0x026c}] set EXT_PHY_CTRL_15 [expr {$EMIF_BASE_ADDR + 0x0270}] set EXT_PHY_CTRL_15_SHDW [expr {$EMIF_BASE_ADDR + 0x0274}] set EXT_PHY_CTRL_16 [expr {$EMIF_BASE_ADDR + 0x0278}] set EXT_PHY_CTRL_16_SHDW [expr {$EMIF_BASE_ADDR + 0x027c}] set EXT_PHY_CTRL_17 [expr {$EMIF_BASE_ADDR + 0x0280}] set EXT_PHY_CTRL_17_SHDW [expr {$EMIF_BASE_ADDR + 0x0284}] set EXT_PHY_CTRL_18 [expr {$EMIF_BASE_ADDR + 0x0288}] set EXT_PHY_CTRL_18_SHDW [expr {$EMIF_BASE_ADDR + 0x028c}] set EXT_PHY_CTRL_19 [expr {$EMIF_BASE_ADDR + 0x0290}] set EXT_PHY_CTRL_19_SHDW [expr {$EMIF_BASE_ADDR + 0x0294}] set EXT_PHY_CTRL_20 [expr {$EMIF_BASE_ADDR + 0x0298}] set EXT_PHY_CTRL_20_SHDW [expr {$EMIF_BASE_ADDR + 0x029c}] set EXT_PHY_CTRL_21 [expr {$EMIF_BASE_ADDR + 0x02a0}] set EXT_PHY_CTRL_21_SHDW [expr {$EMIF_BASE_ADDR + 0x02a4}] set EXT_PHY_CTRL_22 [expr {$EMIF_BASE_ADDR + 0x02a8}] set EXT_PHY_CTRL_22_SHDW [expr {$EMIF_BASE_ADDR + 0x02ac}] set EXT_PHY_CTRL_23 [expr {$EMIF_BASE_ADDR + 0x02b0}] set EXT_PHY_CTRL_23_SHDW [expr {$EMIF_BASE_ADDR + 0x02b4}] set EXT_PHY_CTRL_24 [expr {$EMIF_BASE_ADDR + 0x02b8}] set EXT_PHY_CTRL_24_SHDW [expr {$EMIF_BASE_ADDR + 0x02bc}] set EXT_PHY_CTRL_25 [expr {$EMIF_BASE_ADDR + 0x02c0}] set EXT_PHY_CTRL_25_SHDW [expr {$EMIF_BASE_ADDR + 0x02c4}] set EXT_PHY_CTRL_26 [expr {$EMIF_BASE_ADDR + 0x02c8}] set EXT_PHY_CTRL_26_SHDW [expr {$EMIF_BASE_ADDR + 0x02cc}] set EXT_PHY_CTRL_27 [expr {$EMIF_BASE_ADDR + 0x02d0}] set EXT_PHY_CTRL_27_SHDW [expr {$EMIF_BASE_ADDR + 0x02d4}] set EXT_PHY_CTRL_28 [expr {$EMIF_BASE_ADDR + 0x02d8}] set EXT_PHY_CTRL_28_SHDW [expr {$EMIF_BASE_ADDR + 0x02dc}] set EXT_PHY_CTRL_29 [expr {$EMIF_BASE_ADDR + 0x02e0}] set EXT_PHY_CTRL_29_SHDW [expr {$EMIF_BASE_ADDR + 0x02e4}] set EXT_PHY_CTRL_30 [expr {$EMIF_BASE_ADDR + 0x02e8}] set EXT_PHY_CTRL_30_SHDW [expr {$EMIF_BASE_ADDR + 0x02ec}] set EXT_PHY_CTRL_31 [expr {$EMIF_BASE_ADDR + 0x02f0}] set EXT_PHY_CTRL_31_SHDW [expr {$EMIF_BASE_ADDR + 0x02f4}] set EXT_PHY_CTRL_32 [expr {$EMIF_BASE_ADDR + 0x02f8}] set EXT_PHY_CTRL_32_SHDW [expr {$EMIF_BASE_ADDR + 0x02fc}] set EXT_PHY_CTRL_33 [expr {$EMIF_BASE_ADDR + 0x0300}] set EXT_PHY_CTRL_33_SHDW [expr {$EMIF_BASE_ADDR + 0x0304}] set EXT_PHY_CTRL_34 [expr {$EMIF_BASE_ADDR + 0x0308}] set EXT_PHY_CTRL_34_SHDW [expr {$EMIF_BASE_ADDR + 0x030c}] set EXT_PHY_CTRL_35 [expr {$EMIF_BASE_ADDR + 0x0310}] set EXT_PHY_CTRL_35_SHDW [expr {$EMIF_BASE_ADDR + 0x0314}] set EXT_PHY_CTRL_36 [expr {$EMIF_BASE_ADDR + 0x0318}] set EXT_PHY_CTRL_36_SHDW [expr {$EMIF_BASE_ADDR + 0x031c}] set WDT1_BASE_ADDR 0x44e35000 set WDT1_W_PEND_WSPR [expr {$WDT1_BASE_ADDR + 0x0034}] set WDT1_WSPR [expr {$WDT1_BASE_ADDR + 0x0048}] set RTC_BASE_ADDR 0x44e3e000 set RTC_KICK0R [expr {$RTC_BASE_ADDR + 0x6c}] set RTC_KICK1R [expr {$RTC_BASE_ADDR + 0x70}] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME am437x } set JRC_MODULE icepick_d set DEBUGSS_MODULE debugss set M3_MODULE m3_wakeupss set JRC_NAME $_CHIPNAME.$JRC_MODULE set DEBUGSS_NAME $_CHIPNAME.$DEBUGSS_MODULE set M3_NAME $_CHIPNAME.$M3_MODULE set _TARGETNAME $_CHIPNAME.mpuss # # M3 WakeupSS DAP # if { [info exists M3_DAP_TAPID] } { set _M3_DAP_TAPID $M3_DAP_TAPID } else { set _M3_DAP_TAPID 0x4b6b902f } jtag newtap $_CHIPNAME $M3_MODULE -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_M3_DAP_TAPID -disable jtag configure $M3_NAME -event tap-enable "icepick_d_tapenable $JRC_NAME 11 0" dap create $M3_NAME.dap -chain-position $M3_NAME # # DebugSS DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x46b6902f } jtag newtap $_CHIPNAME $DEBUGSS_MODULE -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable jtag configure $DEBUGSS_NAME -event tap-enable "icepick_d_tapenable $JRC_NAME 12 0" dap create $DEBUGSS_NAME.dap -chain-position $DEBUGSS_NAME # # ICEpick-D (JTAG route controller) # if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0b98c02f } jtag newtap $_CHIPNAME $JRC_MODULE -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version jtag configure $JRC_NAME -event setup "jtag tapenable $DEBUGSS_NAME" # some TCK tycles are required to activate the DEBUG power domain jtag configure $JRC_NAME -event post-reset "runtest 100" # # Cortex-A9 target # target create $_TARGETNAME cortex_a -dap $DEBUGSS_NAME.dap -coreid 0 -dbgbase 0x80000000 # SRAM: 256K at 0x4030.0000 $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x40000 # Disables watchdog timer after reset otherwise board won't stay in # halted state. proc disable_watchdog { } { global WDT1_WSPR global WDT1_W_PEND_WSPR global _TARGETNAME set curstate [$_TARGETNAME curstate] if { [string compare $curstate halted] == 0 } { set WDT_DISABLE_SEQ1 0xaaaa set WDT_DISABLE_SEQ2 0x5555 mww phys $WDT1_WSPR $WDT_DISABLE_SEQ1 # Empty body to make sure this executes as fast as possible. # We don't want any delays here otherwise romcode might start # executing and end up changing state of certain IPs. while { [expr {[mrw $WDT1_W_PEND_WSPR] & 0x10}] } { } mww phys $WDT1_WSPR $WDT_DISABLE_SEQ2 while { [expr {[mrw $WDT1_W_PEND_WSPR] & 0x10}] } { } } } proc ceil { x y } { return [ expr {($x + $y - 1) / $y} ] } proc device_type { } { global CONTROL_STATUS set tmp [ mrw $CONTROL_STATUS ] set tmp [ expr {$tmp & 0x700} ] set tmp [ expr {$tmp >> 8} ] return $tmp } proc get_input_clock_frequency { } { global CONTROL_STATUS if { [ device_type ] != 3 } { error "Unknown device type\n" return -1 } set freq [ mrw $CONTROL_STATUS ] set freq [ expr {$freq & 0x00c00000} ] set freq [ expr {$freq >> 22} ] switch $freq { 0 { set CLKIN 19200000 } 1 { set CLKIN 24000000 } 2 { set CLKIN 25000000 } 3 { set CLKIN 26000000 } } return $CLKIN } proc mpu_pll_config { CLKIN N M M2 } { global CM_CLKMODE_DPLL_MPU global CM_CLKSEL_DPLL_MPU global CM_DIV_M2_DPLL_MPU global CM_IDLEST_DPLL_MPU set clksel [ mrw $CM_CLKSEL_DPLL_MPU ] set div_m2 [ mrw $CM_DIV_M2_DPLL_MPU ] mww $CM_CLKMODE_DPLL_MPU 0x4 while { !([ mrw $CM_IDLEST_DPLL_MPU ] & 0x0100) } { } set clksel [ expr {$clksel & (~0x7ffff)} ] set clksel [ expr {$clksel | ($M << 0x8) | $N} ] mww $CM_CLKSEL_DPLL_MPU $clksel set div_m2 [ expr {$div_m2 & (~0x1f)} ] set div_m2 [ expr {$div_m2 | $M2} ] mww $CM_DIV_M2_DPLL_MPU $div_m2 mww $CM_CLKMODE_DPLL_MPU 0x7 while { [ mrw $CM_IDLEST_DPLL_MPU ] != 1 } { } echo "MPU DPLL locked" } proc core_pll_config { CLKIN N M M4 M5 M6 } { global CM_CLKMODE_DPLL_CORE global CM_CLKSEL_DPLL_CORE global CM_DIV_M4_DPLL_CORE global CM_DIV_M5_DPLL_CORE global CM_DIV_M6_DPLL_CORE global CM_IDLEST_DPLL_CORE set clksel [ mrw $CM_CLKSEL_DPLL_CORE ] mww $CM_CLKMODE_DPLL_CORE 0x4 while { !([ mrw $CM_IDLEST_DPLL_CORE ] & 0x0100) } { } set clksel [ expr {$clksel & (~0x7ffff)} ] set clksel [ expr {$clksel | ($M << 0x8) | $N} ] mww $CM_CLKSEL_DPLL_CORE $clksel mww $CM_DIV_M4_DPLL_CORE $M4 mww $CM_DIV_M5_DPLL_CORE $M5 mww $CM_DIV_M6_DPLL_CORE $M6 mww $CM_CLKMODE_DPLL_CORE 0x7 while { !([ mrw $CM_IDLEST_DPLL_CORE ] & 0x01) } { } echo "CORE DPLL locked" } proc per_pll_config { CLKIN N M M2 } { global CM_CLKMODE_DPLL_PER global CM_CLKSEL_DPLL_PER global CM_DIV_M2_DPLL_PER global CM_IDLEST_DPLL_PER set x [ expr {$M * $CLKIN / 1000000} ] set y [ expr {($N + 1) * 250} ] set sd [ ceil $x $y ] set clksel [ mrw $CM_CLKSEL_DPLL_PER ] set div_m2 [ mrw $CM_DIV_M2_DPLL_PER ] mww $CM_CLKMODE_DPLL_PER 0x4 while { !([ mrw $CM_IDLEST_DPLL_PER ] & 0x0100) } { } set clksel [ expr {$clksel & (~0xff0fffff)} ] set clksel [ expr {$clksel | ($M << 0x8) | $N} ] set clksel [ expr {$clksel | ($sd << 24)} ] mww $CM_CLKSEL_DPLL_PER $clksel set div_m2 [ expr {0xffffff80 | $M2} ] mww $CM_CLKMODE_DPLL_PER 0x7 while { !([ mrw $CM_IDLEST_DPLL_PER ] & 0x01) } { } echo "PER DPLL locked" } proc ddr_pll_config { CLKIN N M M2 M4 } { global CM_CLKMODE_DPLL_DDR global CM_CLKSEL_DPLL_DDR global CM_DIV_M2_DPLL_DDR global CM_DIV_M4_DPLL_DDR global CM_IDLEST_DPLL_DDR set clksel [ mrw $CM_CLKSEL_DPLL_DDR ] set div_m2 [ mrw $CM_DIV_M2_DPLL_DDR ] mww $CM_CLKMODE_DPLL_DDR 0x4 while { !([ mrw $CM_IDLEST_DPLL_DDR ] & 0x0100) } { } set clksel [ expr {$clksel & (~0x7ffff)} ] set clksel [ expr {$clksel | ($M << 8) | $N} ] mww $CM_CLKSEL_DPLL_DDR $clksel set div_m2 [ expr {($div_m2 & 0xffffffe0) | $M2} ] mww $CM_DIV_M2_DPLL_DDR $div_m2 mww $CM_DIV_M4_DPLL_DDR $M4 mww $CM_CLKMODE_DPLL_DDR 0x7 while { !([ mrw $CM_IDLEST_DPLL_DDR ] & 0x01) } { } echo "DDR DPLL Locked" } proc config_opp100 { } { set CLKIN [ get_input_clock_frequency ] if { $CLKIN == -1 } { return -1 } switch $CLKIN { 24000000 { mpu_pll_config $CLKIN 0 25 1 core_pll_config $CLKIN 2 125 10 8 4 per_pll_config $CLKIN 9 400 5 ddr_pll_config $CLKIN 2 50 1 2 } 25000000 { mpu_pll_config $CLKIN 0 24 1 core_pll_config $CLKIN 0 40 10 8 4 per_pll_config $CLKIN 9 384 5 ddr_pll_config $CLKIN 0 16 1 2 } 26000000 { mpu_pll_config $CLKIN 12 300 1 core_pll_config $CLKIN 12 500 10 8 4 per_pll_config $CLKIN 12 480 5 ddr_pll_config $CLKIN 12 200 1 2 } 19200000 { mpu_pll_config $CLKIN 3 125 1 core_pll_config $CLKIN 11 625 10 8 4 per_pll_config $CLKIN 7 400 5 ddr_pll_config $CLKIN 2 125 1 2 } } } proc emif_prcm_clk_enable { } { global CM_PER_EMIF_FW_CLKCTRL global CM_PER_EMIF_CLKCTRL mww $CM_PER_EMIF_FW_CLKCTRL 0x02 mww $CM_PER_EMIF_CLKCTRL 0x02 while { [ mrw $CM_PER_EMIF_CLKCTRL ] != 0x02 } { } } proc vtp_enable { } { global VTP_CTRL_REG set vtp [ expr {[ mrw $VTP_CTRL_REG ] | 0x40 }] mww $VTP_CTRL_REG $vtp set vtp [ expr {[ mrw $VTP_CTRL_REG ] & ~0x01 }] mww $VTP_CTRL_REG $vtp set vtp [ expr {[ mrw $VTP_CTRL_REG ] | 0x01 }] mww $VTP_CTRL_REG $vtp } proc config_ddr_ioctrl { } { global DDR_ADDRCTRL_IOCTRL global DDR_ADDRCTRL_WD0_IOCTRL global DDR_ADDRCTRL_WD1_IOCTRL global DDR_CKE_CTRL global DDR_DATA0_IOCTRL global DDR_DATA1_IOCTRL global DDR_DATA2_IOCTRL global DDR_DATA3_IOCTRL global DDR_IO_CTRL mww $DDR_ADDRCTRL_IOCTRL 0x84 mww $DDR_ADDRCTRL_WD0_IOCTRL 0x00 mww $DDR_ADDRCTRL_WD1_IOCTRL 0x00 mww $DDR_DATA0_IOCTRL 0x84 mww $DDR_DATA1_IOCTRL 0x84 mww $DDR_DATA2_IOCTRL 0x84 mww $DDR_DATA3_IOCTRL 0x84 mww $DDR_IO_CTRL 0x00 mww $DDR_CKE_CTRL 0x03 } proc config_ddr_phy { } { global EMIF_DDR_PHY_CTRL_1 global EMIF_DDR_PHY_CTRL_1_SHDW global EXT_PHY_CTRL_1 global EXT_PHY_CTRL_1_SHDW global EXT_PHY_CTRL_2 global EXT_PHY_CTRL_2_SHDW global EXT_PHY_CTRL_3 global EXT_PHY_CTRL_3_SHDW global EXT_PHY_CTRL_4 global EXT_PHY_CTRL_4_SHDW global EXT_PHY_CTRL_5 global EXT_PHY_CTRL_5_SHDW global EXT_PHY_CTRL_6 global EXT_PHY_CTRL_6_SHDW global EXT_PHY_CTRL_7 global EXT_PHY_CTRL_7_SHDW global EXT_PHY_CTRL_8 global EXT_PHY_CTRL_8_SHDW global EXT_PHY_CTRL_9 global EXT_PHY_CTRL_9_SHDW global EXT_PHY_CTRL_10 global EXT_PHY_CTRL_10_SHDW global EXT_PHY_CTRL_11 global EXT_PHY_CTRL_11_SHDW global EXT_PHY_CTRL_12 global EXT_PHY_CTRL_12_SHDW global EXT_PHY_CTRL_13 global EXT_PHY_CTRL_13_SHDW global EXT_PHY_CTRL_14 global EXT_PHY_CTRL_14_SHDW global EXT_PHY_CTRL_15 global EXT_PHY_CTRL_15_SHDW global EXT_PHY_CTRL_16 global EXT_PHY_CTRL_16_SHDW global EXT_PHY_CTRL_17 global EXT_PHY_CTRL_17_SHDW global EXT_PHY_CTRL_18 global EXT_PHY_CTRL_18_SHDW global EXT_PHY_CTRL_19 global EXT_PHY_CTRL_19_SHDW global EXT_PHY_CTRL_20 global EXT_PHY_CTRL_20_SHDW global EXT_PHY_CTRL_21 global EXT_PHY_CTRL_21_SHDW global EXT_PHY_CTRL_22 global EXT_PHY_CTRL_22_SHDW global EXT_PHY_CTRL_23 global EXT_PHY_CTRL_23_SHDW global EXT_PHY_CTRL_24 global EXT_PHY_CTRL_24_SHDW global EXT_PHY_CTRL_25 global EXT_PHY_CTRL_25_SHDW global EXT_PHY_CTRL_26 global EXT_PHY_CTRL_26_SHDW global EXT_PHY_CTRL_27 global EXT_PHY_CTRL_27_SHDW global EXT_PHY_CTRL_28 global EXT_PHY_CTRL_28_SHDW global EXT_PHY_CTRL_29 global EXT_PHY_CTRL_29_SHDW global EXT_PHY_CTRL_30 global EXT_PHY_CTRL_30_SHDW global EXT_PHY_CTRL_31 global EXT_PHY_CTRL_31_SHDW global EXT_PHY_CTRL_32 global EXT_PHY_CTRL_32_SHDW global EXT_PHY_CTRL_33 global EXT_PHY_CTRL_33_SHDW global EXT_PHY_CTRL_34 global EXT_PHY_CTRL_34_SHDW global EXT_PHY_CTRL_35 global EXT_PHY_CTRL_35_SHDW global EXT_PHY_CTRL_36 global EXT_PHY_CTRL_36_SHDW mww $EMIF_DDR_PHY_CTRL_1 0x8009 mww $EMIF_DDR_PHY_CTRL_1_SHDW 0x8009 set slave_ratio 0x80 set gatelvl_init_ratio 0x20 set wr_dqs_slave_delay 0x60 set rd_dqs_slave_delay 0x60 set dq_offset 0x40 set gatelvl_init_mode 0x01 set wr_data_slave_delay 0x80 set gatelvl_num_dq0 0x0f set wrlvl_num_dq0 0x0f mww $EXT_PHY_CTRL_1 [ expr {($slave_ratio << 20) | ($slave_ratio << 10) | $slave_ratio} ] mww $EXT_PHY_CTRL_1_SHDW [ expr {($slave_ratio << 20) | ($slave_ratio << 10) | $slave_ratio} ] mww $EXT_PHY_CTRL_26 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_26_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_27 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_27_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_28 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_28_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_29 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_29_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_30 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_30_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_31 0x00 mww $EXT_PHY_CTRL_31_SHDW 0x00 mww $EXT_PHY_CTRL_32 0x00 mww $EXT_PHY_CTRL_32_SHDW 0x00 mww $EXT_PHY_CTRL_33 0x00 mww $EXT_PHY_CTRL_33_SHDW 0x00 mww $EXT_PHY_CTRL_34 0x00 mww $EXT_PHY_CTRL_34_SHDW 0x00 mww $EXT_PHY_CTRL_35 0x00 mww $EXT_PHY_CTRL_35_SHDW 0x00 mww $EXT_PHY_CTRL_22 0x00 mww $EXT_PHY_CTRL_22_SHDW 0x00 mww $EXT_PHY_CTRL_23 [ expr {($wr_dqs_slave_delay << 16) | $rd_dqs_slave_delay} ] mww $EXT_PHY_CTRL_23_SHDW [ expr {($wr_dqs_slave_delay << 16) | $rd_dqs_slave_delay} ] mww $EXT_PHY_CTRL_24 [ expr {($dq_offset << 24) | ($gatelvl_init_mode << 16) | $wr_data_slave_delay} ] mww $EXT_PHY_CTRL_24_SHDW [ expr {($dq_offset << 24) | ($gatelvl_init_mode << 16) | $wr_data_slave_delay << 0} ] mww $EXT_PHY_CTRL_25 [ expr {($dq_offset << 21) | ($dq_offset << 14) | ($dq_offset << 7) | $dq_offset} ] mww $EXT_PHY_CTRL_25_SHDW [ expr {($dq_offset << 21) | ($dq_offset << 14) | ($dq_offset << 7) | $dq_offset} ] mww $EXT_PHY_CTRL_36 [ expr {($wrlvl_num_dq0 << 4) | $gatelvl_num_dq0} ] mww $EXT_PHY_CTRL_36_SHDW [ expr {($wrlvl_num_dq0 << 4) | $gatelvl_num_dq0} ] } proc config_ddr_timing { } { global EMIF_SDRAM_TIM_1 global EMIF_SDRAM_TIM_2 global EMIF_SDRAM_TIM_3 global EMIF_SDRAM_TIM_1_SHDW global EMIF_SDRAM_TIM_2_SHDW global EMIF_SDRAM_TIM_3_SHDW global EMIF_ZQ_CONFIG mww $EMIF_SDRAM_TIM_1 0xeaaad4db mww $EMIF_SDRAM_TIM_1_SHDW 0xeaaad4db mww $EMIF_SDRAM_TIM_2 0x266b7fda mww $EMIF_SDRAM_TIM_2_SHDW 0x266b7fda mww $EMIF_SDRAM_TIM_3 0x107f8678 mww $EMIF_SDRAM_TIM_3_SHDW 0x107f8678 mww $EMIF_ZQ_CONFIG 0x50074be4 } proc config_ddr_pm { } { global EMIF_PWR_MGMT_CTRL global EMIF_PWR_MGMT_CTRL_SHDW global EMIF_DLL_CALIB_CTRL global EMIF_DLL_CALIB_CTRL_SHDW global EMIF_TEMP_ALERT_CONFIG mww $EMIF_PWR_MGMT_CTRL 0x00 mww $EMIF_PWR_MGMT_CTRL_SHDW 0x00 mww $EMIF_DLL_CALIB_CTRL 0x00050000 mww $EMIF_DLL_CALIB_CTRL_SHDW 0x00050000 mww $EMIF_TEMP_ALERT_CONFIG 0x00 } proc config_ddr_priority { } { global EMIF_PRI_COS_MAP global EMIF_CONNID_COS_1_MAP global EMIF_CONNID_COS_2_MAP global EMIF_RD_WR_EXEC_THRSH global COS_CONFIG mww $EMIF_PRI_COS_MAP 0x00 mww $EMIF_CONNID_COS_1_MAP 0x00 mww $EMIF_CONNID_COS_2_MAP 0x0 mww $EMIF_RD_WR_EXEC_THRSH 0x0405 mww $COS_CONFIG 0x00ffffff } proc config_ddr3 { SDRAM_CONFIG } { global CM_DLL_CTRL global EMIF_IODFT_TLGC global EMIF_RDWR_LVL_CTRL global EMIF_RDWR_LVL_RMP_CTRL global EMIF_SDRAM_CONFIG global EMIF_SDRAM_CONFIG_EXT global EMIF_SDRAM_REF_CTRL global EMIF_SDRAM_REF_CTRL_SHDW global EMIF_STATUS global EXT_PHY_CTRL_36 global EXT_PHY_CTRL_36_SHDW emif_prcm_clk_enable vtp_enable set dll [ expr {[ mrw $CM_DLL_CTRL ] & ~0x01 }] mww $CM_DLL_CTRL $dll while { !([ mrw $CM_DLL_CTRL ] & 0x04) } { } config_ddr_ioctrl mww $EMIF_SDRAM_CONFIG_EXT 0xc163 mww $EMIF_IODFT_TLGC 0x2011 mww $EMIF_IODFT_TLGC 0x2411 mww $EMIF_IODFT_TLGC 0x2011 mww $EMIF_SDRAM_REF_CTRL 0x80003000 config_ddr_phy mww $EMIF_IODFT_TLGC 0x2011 mww $EMIF_IODFT_TLGC 0x2411 mww $EMIF_IODFT_TLGC 0x2011 config_ddr_timing config_ddr_pm config_ddr_priority mww $EMIF_SDRAM_REF_CTRL 0x3000 mww $EMIF_SDRAM_CONFIG $SDRAM_CONFIG mww $EMIF_SDRAM_REF_CTRL 0x0c30 mww $EMIF_SDRAM_REF_CTRL_SHDW 0x0c30 sleep 10 set tmp [ expr {[ mrw $EXT_PHY_CTRL_36 ] | 0x0100 }] mww $EXT_PHY_CTRL_36 $tmp mww $EXT_PHY_CTRL_36_SHDW $tmp mww $EMIF_RDWR_LVL_RMP_CTRL 0x80000000 mww $EMIF_RDWR_LVL_CTRL 0x80000000 while { [ mrw $EMIF_RDWR_LVL_CTRL ] & 0x80000000 } { } if { [ mrw $EMIF_STATUS ] & 0x70 } { error "DDR3 Hardware Leveling incomplete!!!" } } proc init_platform { SDRAM_CONFIG } { config_opp100 config_ddr3 $SDRAM_CONFIG } $_TARGETNAME configure -event reset-init { init_platform 0x61a013b2 } $_TARGETNAME configure -event reset-end { disable_watchdog } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/amdm37x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Copyright (C) 2010-2011 by Karl Kurbjun # Copyright (C) 2009-2011 by Øyvind Harboe # Copyright (C) 2009 by David Brownell # Copyright (C) 2009 by Magnus Lundin # # TI AM/DM37x Technical Reference Manual (Version R) # http://www.ti.com/lit/ug/sprugn4r/sprugn4r.pdf # # This script is based on the AM3517 initialization. It should be considered # preliminary since it needs more complete testing and only the basic # operations work. # ############################################################################### # User modifiable parameters ############################################################################### # This script uses the variable CHIPTYPE to determine whether this is an AM35x # or DM37x target. If CHIPTYPE is not set it will error out. if { [info exists CHIPTYPE] } { if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME $CHIPTYPE } switch $CHIPTYPE { dm37x { # Primary TAP: ICEPick-C (JTAG route controller) and boundary scan set _JRC_TAPID "-expected-id 0x2b89102f -expected-id 0x1b89102f -expected-id 0x0b89102f" } am35x { # Primary TAP: ICEPick-C (JTAG route controller) and boundary scan set _JRC_TAPID "-expected-id 0x0b7ae02f -expected-id 0x0b86802f" } default { error "ERROR: CHIPTYPE was set, but it was not set to a valid value. Acceptable values are \"dm37x\" or \"am35x\"." } } } else { error "ERROR: CHIPTYPE was not defined. Please set CHIPTYPE to \"am35x\" for the AM35x or \"dm37x\" for the DM37x series in the board configuration." } # Run the adapter at the fastest acceptable speed with the slowest possible # core clock. adapter speed 10 ############################################################################### # JTAG setup # The OpenOCD commands are described in the TAP Declaration section # http://openocd.org/doc/html/TAP-Declaration.html ############################################################################### # The AM/DM37x has an ICEPick module in it like many of TI's other devices. More # can be read about this module in sprugn4r in chapter 27: "Debug and # Emulation". The module is used to route the JTAG chain to the various # subsystems in the chip. source [find target/icepick.cfg] # The TAP order should be described from the TDO connection in OpenOCD to the # TDI pin. The OpenOCD FAQ describes this in more detail: # http://openocd.org/doc/html/FAQ.html # From SPRUGN4R CH27 the available secondary TAPs are in this order from TDO: # # Device | TAP number # ---------|------------ # DAP | 3 # Sequencer| 2 Note: The sequencer is an ARM968 # DSP | 1 # D2D | 0 # # Right now the only secondary tap enabled is the DAP so the rest are left # undescribed. ###### # Start of Chain Description # The Secondary TAPs all have enable functions defined for use with the ICEPick # Only the DAP is enabled. The AM37xx does not have the Sequencer or DSP but # the TAP numbers for ICEPick do not change. # # TODO: A disable function should also be added. ###### # Secondary TAP: DAP is closest to the TDO output # The TAP enable event also needs to be described jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -disable jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 3" # These taps are only present in the DM37x series. if { $CHIPTYPE == "dm37x" } { # Secondary TAP: Sequencer (ARM968) it is not in the chain by default # The ICEPick can be used to enable it in the chain. jtag newtap $_CHIPNAME arm2 -irlen 4 -ircapture 0x1 -irmask 0x0f -disable jtag configure $_CHIPNAME.arm2 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 2" # Secondary TAP: C64x+ DSP - it is not in the chain by default (-disable) # The ICEPick can be used to enable it in the chain. jtag newtap $_CHIPNAME dsp -irlen 38 -ircapture 0x25 -irmask 0x3f -disable jtag configure $_CHIPNAME.dsp -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 1" } # Secondary TAP: D2D it is not in the chain by default (-disable) # The ICEPick can be used to enable it in the chain. # This IRLEN is probably incorrect - not sure where the documentation is. jtag newtap $_CHIPNAME d2d -irlen 4 -ircapture 0x1 -irmask 0x0f -disable jtag configure $_CHIPNAME.d2d -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 0" # Primary TAP: ICEPick - it is closest to TDI so last in the chain eval "jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f $_JRC_TAPID" ###### # End of Chain Description ###### ###### # Start JTAG TAP events ###### # some TCK tycles are required to activate the DEBUG power domain jtag configure $_CHIPNAME.jrc -event post-reset "runtest 100" # Enable the DAP TAP jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.dap" ###### # End JTAG TAP events ###### ############################################################################### # Target Setup: # This section is described in the OpenOCD documentation under CPU Configuration # http://openocd.org/doc/html/CPU-Configuration.html ############################################################################### # Create the CPU target to be used with GDB: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # The DM37x has 64K of SRAM starting at address 0x4020_0000. Allow the first # 16K to be used as a scratchpad for OpenOCD. $_TARGETNAME configure -work-area-phys 0x40200000 -work-area-size 0x4000 ###### # Start Target Reset Event Setup: ###### # Set the JTAG clock down to 10 kHz to be sure that it will work with the # slowest possible core clock (16.8MHz/2 = 8.4MHz). It is OK to speed up # *after* PLL and clock tree setup. $_TARGETNAME configure -event "reset-start" { adapter speed 10 } # Describe the reset assert process for openocd - this is asserted with the # ICEPick $_TARGETNAME configure -event "reset-assert" { global _CHIPNAME # assert warm system reset through ICEPick icepick_c_wreset $_CHIPNAME.jrc } # After the reset is asserted we need to re-initialize debugging and speed up # the JTAG clock. $_TARGETNAME configure -event reset-assert-post { global _TARGETNAME amdm37x_dbginit $_TARGETNAME adapter speed 1000 } $_TARGETNAME configure -event gdb-attach { global _TARGETNAME amdm37x_dbginit $_TARGETNAME echo "Halting target" halt } ###### # End Target Reset Event Setup: ###### ############################################################################### # Target Functions # Add any functions needed for the target here ############################################################################### # Run this to enable invasive debugging. This is run automatically in the # reset sequence. proc amdm37x_dbginit {target} { # General Cortex-A8 debug initialisation cortex_a dbginit # Enable DBGEN signal. This signal is described in the ARM v7 TRM, but # access to the signal appears to be implementation specific. TI does not # describe this register much except a quick line that states DBGEM (sic) is # at this address and this bit. $target mww phys 0x5401d030 0x00002000 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ampere_emag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # OpenOCD Target Configuration for eMAG ARMv8 Processor # # Copyright (c) 2019-2021, Ampere Computing LLC # # # Configure defaults for target # Can be overriden in board configuration file # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME emag } if { [info exists NUMCORES] } { set _NUMCORES $NUMCORES } else { set _NUMCORES 32 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID ] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4BA00477 } # # Configure JTAG TAP # jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x3 -expected-id $_CPUTAPID set _TAPNAME $_CHIPNAME.cpu set _DAPNAME ${_TAPNAME}_dap set _APNUM 1 dap create $_DAPNAME -chain-position $_TAPNAME $_DAPNAME apsel $_APNUM # Create the DAP AP0 MEM-AP AHB-AP target target create AHB mem_ap -endian $_ENDIAN -dap $_DAPNAME -ap-num 0 # Create the DAP AP1 MEM-AP APB-AP target target create APB mem_ap -endian $_ENDIAN -dap $_DAPNAME -ap-num 1 # # Configure target CPUs # # Build string used to enable smp mode set _SMP_STR "target smp" for {set _i 0} {$_i < $_NUMCORES} {incr _i} { # Format a string to reference which CPU target to use set _TARGETNAME [format "${_TAPNAME}_%02d" $_i] # Create and configure Cross Trigger Interface (CTI) - required for halt and resume set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $_DAPNAME -ap-num $_APNUM -baseaddr [expr {0xFC020000 + ($_i << 20)}] # Create the target target create $_TARGETNAME aarch64 -endian $_ENDIAN -dap $_DAPNAME -ap-num $_APNUM -cti $_CTINAME -coreid $_i set _SMP_STR "$_SMP_STR $_TARGETNAME" # Clear CTI output/input enables that are not configured by OpenOCD for aarch64 $_TARGETNAME configure -event examine-start [subst { $_CTINAME write INEN0 0x00000000 $_CTINAME write INEN1 0x00000000 $_CTINAME write INEN2 0x00000000 $_CTINAME write INEN3 0x00000000 $_CTINAME write INEN4 0x00000000 $_CTINAME write INEN5 0x00000000 $_CTINAME write INEN6 0x00000000 $_CTINAME write INEN7 0x00000000 $_CTINAME write INEN8 0x00000000 $_CTINAME write OUTEN2 0x00000000 $_CTINAME write OUTEN3 0x00000000 $_CTINAME write OUTEN4 0x00000000 $_CTINAME write OUTEN5 0x00000000 $_CTINAME write OUTEN6 0x00000000 $_CTINAME write OUTEN7 0x00000000 $_CTINAME write OUTEN8 0x00000000 }] # Enable OpenOCD HWTHREAD RTOS feature for GDB thread (CPU) selection support # This feature presents CPU cores ("hardware threads") in an SMP system as threads to GDB $_TARGETNAME configure -rtos hwthread } eval $_SMP_STR ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ampere_qs_mq.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # OpenOCD Target Configuration for Ampere Altra ("Quicksilver") and # Ampere Altra Max ("Mystique") processors # # Copyright (c) 2019-2022, Ampere Computing LLC # Command Line Argument Description # # SPLITSMP # Only used for dual socket systems. Do not use for a single socket setup. # Option pertains to the ARMv8 target core naming in a dual socket setup. # If specified, name all ARMv8 cores per socket as individual SMP sessions. # If not specified, name ARMv8 cores from both sockets as one SMP session. # This option is used in conjunction with the SMP_STR board file option. # Syntax: -c "set SPLITSMP {}" # # PHYS_IDX # Enable OpenOCD ARMv8 core target physical indexing. # If not specified, defaults to OpenOCD ARMv8 core target logical indexing. # Syntax: -c "set PHYS_IDX {}" # # CHIPNAME # Specifies the name of the chip. # Will typically be either qs, qs0, qs1, mq, mq0 or mq1. # If not specified, defaults to qs. # Syntax: -c "set CHIPNAME {qs}" # # SYSNAME # Specifies the name of the system. # Will typically be either qs or mq. # If not specified, defaults to qs. # Syntax: -c "set SYSNAME {qs}" # # Life-Cycle State (LCS) # If not specified, defaults to "Secure LCS". # LCS=0, "Secure LCS" # LCS=1, "Chip Manufacturing LCS" # Syntax: -c "set LCS {0}" # Syntax: -c "set LCS {1}" # # CORELIST # Specify available physical cores by number. # Example syntax to connect to physical cores 16 and 17. # Syntax: -c "set CORELIST {16 17}" # # COREMASK_LO # Specify available physical cores 0-63 by mask. # Example syntax to connect to physical cores 16 and 17. # Syntax: -c "set COREMASK_LO {0x0000000000030000}" # # COREMASK_HI # Specify available physical cores 64 and above by mask. # Example syntax to connect to physical cores 94 and 95. # Syntax: -c "set COREMASK_HI {0x00000000C0000000}" # # ARMV8_TAPID # Can override the ARMV8 TAPID default value if necessary. # Experimental Use. Most users will not use this option. # Syntax: -c "set ARMV8_TAPID {0x3BA06477}" # # SMPMPRO_TAPID # Can override the SMPMPRO TAPID default value if necessary. # Experimental Use. Most users will not use this option. # Syntax: -c "set SMPMPRO_TAPID {0x4BA00477}" # # # Board File Argument Description # These optional arguments are defined in the board file and # referenced by the target file. See the corresponding board # files for examples of their use. # # SMP_STR # This option is used primarily for a dual socket system and it is not # recommended for a single socket setup. This option configures whether # the SMP ARMv8 core grouping is maintained at the board or target cfg level. # Specify the option if the SMP core grouping is defined at the board level. # Do not specify if the SMP core grouping is defined at the chip level. # If not specified, defaults to SMP core grouping defined per socket. # If specified, "SMP_STR=target smp", the SMP core grouping is maintained # at the board cfg level. # Used in conjunction with the SPLITSMP option to group two chips into # a single SMP configuration or maintain as two separate SMP sessions. # # CORE_INDEX_OFFSET # Specifies the starting logical core index value. # Used for dual-socket systems. # For socket #0, set to 0. # For socket #1, set the starting logical core based from # the last logical core on socket #0. # If not specified, defaults to 0. # # # Configure defaults for target. # Can be overridden in board configuration file. # if { [info exists SMP_STR] } { # SMP configured at the dual socket board level set _SMP_STR $SMP_STR } else { # SMP configured at the single socket target level set _SMP_STR "target smp" } if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME qs } if { [info exists SYSNAME] } { set _SYSNAME $SYSNAME } else { set _SYSNAME qs } if { [info exists CORE_INDEX_OFFSET] } { set _CORE_INDEX_OFFSET $CORE_INDEX_OFFSET } else { set _CORE_INDEX_OFFSET 0 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists ARMV8_TAPID] } { set _ARMV8_TAPID $ARMV8_TAPID } else { if { [info exists MQ_ENABLE] } { # Configure for Mystique set _ARMV8_TAPID 0x3BA06477 set _MAX_CORE 128 } else { # Configure for Quicksilver set _ARMV8_TAPID 0x2BA06477 set _MAX_CORE 80 } } if { [info exists SMPMPRO_TAPID] } { set _SMPMPRO_TAPID $SMPMPRO_TAPID } else { set _SMPMPRO_TAPID 0x4BA00477 } if { [info exists CORELIST] } { set _CORELIST $CORELIST } else { if { [info exists COREMASK_LO] } { set _COREMASK_LO $COREMASK_LO } else { set _COREMASK_LO 0x0 } if { [info exists COREMASK_HI] } { set _COREMASK_HI $COREMASK_HI } else { set _COREMASK_HI 0x0 } set _CORELIST {} set _MASK 0x1 for {set i 0} {$i < 64} {incr i} { if { [expr {$_COREMASK_LO & $_MASK}] != 0x0 } { set _CORELIST "$_CORELIST $i" } set _MASK [expr {$_MASK << 0x1}] } set _MASK 0x1 for {} {$i < $_MAX_CORE} {incr i} { if { [expr {$_COREMASK_HI & $_MASK}] != 0x0 } { set _CORELIST "$_CORELIST $i" } set _MASK [expr {$_MASK << 0x1}] } } # # Definition of target names # set _TARGETNAME_PMPRO pmpro set _TARGETNAME_SMPRO smpro set _TARGETNAME_ARMV8 armv8 # # Configure JTAG TAPs - TAP chain declaration order is important # jtag newtap $_CHIPNAME pmpro.tap -irlen 4 -ircapture 0x1 -irmask 0x3 -expected-id $_SMPMPRO_TAPID set _TAPNAME_PMPRO $_CHIPNAME.$_TARGETNAME_PMPRO.tap jtag newtap $_CHIPNAME smpro.tap -irlen 4 -ircapture 0x1 -irmask 0x3 -expected-id $_SMPMPRO_TAPID set _TAPNAME_SMPRO $_CHIPNAME.$_TARGETNAME_SMPRO.tap jtag newtap $_CHIPNAME armv8.tap -irlen 4 -ircapture 0x1 -irmask 0x3 -expected-id $_ARMV8_TAPID set _TAPNAME_ARMV8 $_CHIPNAME.$_TARGETNAME_ARMV8.tap set _DAPNAME_PMPRO $_CHIPNAME.$_TARGETNAME_PMPRO.dap set _DAPNAME_SMPRO $_CHIPNAME.$_TARGETNAME_SMPRO.dap set _DAPNAME_ARMV8 $_CHIPNAME.$_TARGETNAME_ARMV8.dap set _AP_PMPRO_AHB 0 set _AP_SMPRO_AHB 0 set _AP_ARMV8_APB 0x00010000 set _AP_ARMV8_AXI 0x00020000 # # Configure JTAG DAPs # dap create $_DAPNAME_PMPRO -chain-position $_TAPNAME_PMPRO -adiv5 dap create $_DAPNAME_SMPRO -chain-position $_TAPNAME_SMPRO -adiv5 dap create $_DAPNAME_ARMV8 -chain-position $_TAPNAME_ARMV8 -adiv6 if { [info exists LCS] && [expr {"$LCS"!="0"}] } { # # Create the DAP AHB-AP MEM-AP target for the PMPRO CPU # target create $_CHIPNAME.$_TARGETNAME_PMPRO.ahb mem_ap -endian $_ENDIAN -dap $_DAPNAME_PMPRO -ap-num $_AP_PMPRO_AHB # # Configure target PMPRO CPU # target create $_CHIPNAME.$_TARGETNAME_PMPRO cortex_m -endian $_ENDIAN -dap $_DAPNAME_PMPRO -ap-num $_AP_PMPRO_AHB # # Create the DAP AHB-AP MEM-AP target for the SMPRO CPU # target create $_CHIPNAME.$_TARGETNAME_SMPRO.ahb mem_ap -endian $_ENDIAN -dap $_DAPNAME_SMPRO -ap-num $_AP_SMPRO_AHB # # Configure target SMPRO CPU # target create $_CHIPNAME.$_TARGETNAME_SMPRO cortex_m -endian $_ENDIAN -dap $_DAPNAME_SMPRO -ap-num $_AP_SMPRO_AHB } # Create the DAP APB-AP MEM-AP target for the ARMV8 cores target create $_CHIPNAME.$_TARGETNAME_ARMV8.apb mem_ap -endian $_ENDIAN -dap $_DAPNAME_ARMV8 -ap-num $_AP_ARMV8_APB # Create the DAP AXI-AP MEM-AP target for the ARMV8 cores target create $_CHIPNAME.$_TARGETNAME_ARMV8.axi mem_ap -endian $_ENDIAN -dap $_DAPNAME_ARMV8 -ap-num $_AP_ARMV8_AXI # Set CSW register value default correctly for AXI accessible device memory: # Select the correct Access Port Number $_DAPNAME_ARMV8 apsel $_AP_ARMV8_AXI # First set the CSW to OpenOCD's internal default $_DAPNAME_ARMV8 apcsw default # Set Domain[1:0]=b'11 (CSW[14:13]=b'11) # Set Cache[3:0]=b'0000 (CSW[27:24]=b'0000) # Porter Cfg registers require secure access, AxPROT[1] (CSW[29]) must be b'0'. # Set AxPROT[2:0]=b'000 (CSW[30:28]=b'000) for an Unpriveleged, Secure, Data access. $_DAPNAME_ARMV8 apcsw 0x00006000 0x7F006000 # # Configure target CPUs # set logical_index $_CORE_INDEX_OFFSET foreach physical_index $_CORELIST { if { [info exists PHYS_IDX] } { set logical_index [expr {$physical_index + $_CORE_INDEX_OFFSET}] } # Format a string to reference which CPU target to use if { [info exists SPLITSMP] } { eval "set _TARGETNAME $_CHIPNAME.${_TARGETNAME_ARMV8}_$logical_index" } else { eval "set _TARGETNAME $_SYSNAME.${_TARGETNAME_ARMV8}_$logical_index" } # Create and configure Cross Trigger Interface (CTI) - required for halt and resume set _CTINAME $_TARGETNAME.cti set _offset [expr {(0x00100000 * $physical_index) + (0x00200000 * ($physical_index>>1))}] cti create $_CTINAME -dap $_DAPNAME_ARMV8 -ap-num $_AP_ARMV8_APB -baseaddr [expr {0xA0220000 + $_offset}] # Create the target target create $_TARGETNAME aarch64 -endian $_ENDIAN \ -dap $_DAPNAME_ARMV8 -ap-num $_AP_ARMV8_APB -dbgbase [expr {0xA0210000 + $_offset}] \ -rtos hwthread -cti $_CTINAME -coreid $logical_index # Build string used to enable SMP mode for the ARMv8 CPU cores set _SMP_STR "$_SMP_STR $_TARGETNAME" # Clear CTI output/input enables that are not configured by OpenOCD for aarch64 $_TARGETNAME configure -event reset-init [subst { $_CTINAME write INEN0 0x00000000 $_CTINAME write INEN1 0x00000000 $_CTINAME write INEN2 0x00000000 $_CTINAME write INEN3 0x00000000 $_CTINAME write INEN4 0x00000000 $_CTINAME write INEN5 0x00000000 $_CTINAME write INEN6 0x00000000 $_CTINAME write INEN7 0x00000000 $_CTINAME write INEN8 0x00000000 $_CTINAME write OUTEN0 0x00000000 $_CTINAME write OUTEN1 0x00000000 $_CTINAME write OUTEN2 0x00000000 $_CTINAME write OUTEN3 0x00000000 $_CTINAME write OUTEN4 0x00000000 $_CTINAME write OUTEN5 0x00000000 $_CTINAME write OUTEN6 0x00000000 $_CTINAME write OUTEN7 0x00000000 $_CTINAME write OUTEN8 0x00000000 }] incr logical_index } if { [info exists SMP_STR] } { # Return updated SMP configuration string back to board level set SMP_STR $_SMP_STR } else { # For single socket per SMP configuration, evaluate the string eval $_SMP_STR } if { [info exists CORE_INDEX_OFFSET] } { # For multi-socket, return total number of cores back to board level set CORE_INDEX_OFFSET $logical_index } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ar71xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Atheros AR71xx MIPS 24Kc SoC. # tested on PB44 refererence board adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst set CHIPNAME ar71xx jtag newtap $CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id 1 set _TARGETNAME $CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-halt-post { #setup PLL to lowest common denominator 300/300/150 setting mww 0xb8050000 0x000f40a3 ;# reset val + CPU:3 DDR:3 AHB:0 mww 0xb8050000 0x800f40a3 ;# send to PLL #next command will reset for PLL changes to take effect mww 0xb8050008 3 ;# set reset_switch and clock_switch (resets SoC) } $_TARGETNAME configure -event reset-init { #complete pll initialization mww 0xb8050000 0x800f0080 ;# set sw_update bit mww 0xb8050008 0 ;# clear reset_switch bit mww 0xb8050000 0x800f00e8 ;# clr pwrdwn & bypass mww 0xb8050008 1 ;# set clock_switch bit sleep 1 ;# wait for lock # Setup DDR config and flash mapping mww 0xb8000000 0xefbc8cd0 ;# DDR cfg cdl val (rst: 0x5bfc8d0) mww 0xb8000004 0x8e7156a2 ;# DDR cfg2 cdl val (rst: 0x80d106a8) mww 0xb8000010 8 ;# force precharge all banks mww 0xb8000010 1 ;# force EMRS update cycle mww 0xb800000c 0 ;# clr ext. mode register mww 0xb8000010 2 ;# force auto refresh all banks mww 0xb8000010 8 ;# force precharge all banks mww 0xb8000008 0x31 ;# set DDR mode value CAS=3 mww 0xb8000010 1 ;# force EMRS update cycle mww 0xb8000014 0x461b ;# DDR refresh value mww 0xb8000018 0xffff ;# DDR Read Data This Cycle value (16bit: 0xffff) mww 0xb800001c 0x7 ;# delay added to the DQS line (normal = 7) mww 0xb8000020 0 mww 0xb8000024 0 mww 0xb8000028 0 } # setup working area somewhere in RAM $_TARGETNAME configure -work-area-phys 0xa0600000 -work-area-size 0x20000 # serial SPI capable flash # flash bank <driver> <base> <size> <chip_width> <bus_width> ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/arm_corelink_sse200.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Configuration script for Arm CoreLink SSE-200 Subsystem based IoT SoCs. # global TARGET set TARGET $_CHIPNAME swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # # SRAM on ARM CoreLink SSE-200 can be 4 banks of 8/16/32/64 KB # We will configure work area assuming 8-KB bank size in SRAM bank 1. # Also SRAM start addresses defaults to secure mode alias. # These values can be overridden as per board configuration # global _WORKAREASIZE_CPU0 if { [info exists WORKAREASIZE_CPU0] } { set _WORKAREASIZE_CPU0 $WORKAREASIZE_CPU0 } else { set _WORKAREASIZE_CPU0 0x1000 } global _WORKAREAADDR_CPU0 if { [info exists WORKAREAADDR_CPU0] } { set _WORKAREAADDR_CPU0 $WORKAREAADDR_CPU0 } else { set _WORKAREAADDR_CPU0 0x30008000 } # # Target configuration for Cortex M33 Core 0 on ARM CoreLink SSE-200 # Core 0 is the boot core and will always be configured. # target create ${TARGET}.CPU0 cortex_m -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 ${TARGET}.CPU0 configure -work-area-phys $_WORKAREAADDR_CPU0 -work-area-size $_WORKAREASIZE_CPU0 -work-area-backup 0 ${TARGET}.CPU0 cortex_m reset_config sysresetreq # # Target configuration for Cortex M33 Core 1 on ARM CoreLink SSE-200 # Core 1 is optional and locked at boot until core 0 unlocks it. # if { $_ENABLE_CPU1 } { global _WORKAREASIZE_CPU1 if { [info exists WORKAREASIZE_CPU1] } { set _WORKAREASIZE_CPU1 $WORKAREASIZE_CPU1 } else { set _WORKAREASIZE_CPU1 0x1000 } global _WORKAREAADDR_CPU1 if { [info exists WORKAREAADDR_CPU1] } { set _WORKAREAADDR_CPU1 $WORKAREAADDR_CPU1 } else { set _WORKAREAADDR_CPU1 0x30009000 } target create ${TARGET}.CPU1 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -coreid 1 ${TARGET}.CPU1 configure -work-area-phys $_WORKAREAADDR_CPU1 -work-area-size $_WORKAREASIZE_CPU1 -work-area-backup 0 ${TARGET}.CPU1 cortex_m reset_config vectreset } # Make sure the default target is the boot core targets ${TARGET}.CPU0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/armada370.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # armada370 -- support for the Marvell Armada/370 CPU family # # gerg@uclinux.org, OCT-2013 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME armada370 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap proc armada370_dbginit {target} { cortex_a dbginit } $_TARGETNAME configure -event reset-assert-post "armada370_dbginit $_TARGETNAME" dap apsel 1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at32ap7000.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Atmel AT32AP7000 # # This is the only core in the now-inactive high end AVR32 product line, # with MMU, Java Acceleration, and "pixel coprocessor". The AP7 line # is for "Application Processors" (AP) with 7-stage pipelines. # # Most current AVR32 parts are in the UC3 flash based microcontroller (UC) # product line with 3-stage pipelines and without those extras. # # All AVR32 parts provide the Nexus Class 3 on-chip debug interfaces # through their JTAG interfaces. jtag newtap ap7 nexus -irlen 5 -expected-id 0x21e8203f # REVISIT declare an avr32 target ... needs OpenOCD infrastructure # for both Nexus (generic) and AVR32 (Atmel-specific). ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91r40008.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # AT91R40008 target configuration file # TRST is tied to SRST on the AT91X40 family. reset_config srst_only srst_pulls_trst if {[info exists CHIPNAME]} { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91r40008 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Setup the JTAG scan chain. if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x1f0f0f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x20000 -work-area-size 0x20000 -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91rm9200.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Atmel AT91rm9200 # http://atmel.com/products/at91/ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91rm9200 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x05b0203f } # Never allow the following! if { $_CPUTAPID == 0x15b0203f } { echo "-------------------------------------------------------" echo "- ERROR: -" echo "- ERROR: TapID 0x15b0203f is wrong for at91rm9200 -" echo "- ERROR: The chip/board has a JTAG select pin/jumper -" echo "- ERROR: -" echo "- ERROR: In one position (0x05b0203f) it selects the -" echo "- ERROR: ARM CPU, in the other position (0x1b0203f) -" echo "- ERROR: it selects boundary-scan not the ARM -" echo "- ERROR: -" echo "-------------------------------------------------------" } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Create the GDB Target. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm920t -endian $_ENDIAN -chain-position $_TARGETNAME # AT91RM9200 has a 16K block of sram @ 0x0020.0000 $_TARGETNAME configure -work-area-phys 0x00200000 \ -work-area-size 0x4000 -work-area-backup 1 # This chip has a DCC ... use it arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam3XXX.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for ATMEL sam3, a Cortex-M3 chip # # at91sam3u4e # at91sam3u2e # at91sam3u1e # at91sam3u4c # at91sam3u2c # at91sam3u1c # # at91sam3s4c # at91sam3s4b # at91sam3s4a # at91sam3s2c # at91sam3s2b # at91sam3s2a # at91sam3s1c # at91sam3s1b # at91sam3s1a # # at91sam3A4C # at91sam3A8C # at91sam3X4C # at91sam3X4E # at91sam3X8C # at91sam3X8E # at91sam3X8H source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sam3 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # By default use 64kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # 16K is plenty, the smallest chip has this much $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 $_TARGETNAME configure -event gdb-flash-erase-start { halt } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 4 MHz, so use F_JTAG = 0.5MHz # # Since we may be running of an RC oscilator, we crank down the speed a # bit more to be on the safe side. Perhaps superstition, but if are # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. adapter speed 500 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam3ax_4x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # common stuff source [find target/at91sam3ax_xx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME # This is a 256K chip - it has the 2nd bank set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam3 0x0000A0000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam3ax_8x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # common stuff source [find target/at91sam3ax_xx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME # This is a 512K chip - it has the 2nd bank set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam3 0x0000C0000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam3ax_xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for ATMEL sam3, a Cortex-M3 chip # # at91sam3A4C # at91sam3A8C # at91sam3X4C # at91sam3X4E # at91sam3X8C # at91sam3X8E # at91sam3X8H source [find target/at91sam3XXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam3nXX.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Configuration for Atmel's SAM3N series # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91sam3n } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap set _FLASHNAME $_CHIPNAME.flash flash bank flash0 at91sam3 0x00400000 0 0 0 $_TARGETNAME if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam3sXX.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for ATMEL sam3, a Cortex-M3 chip # # at91sam3s4c # at91sam3s4b # at91sam3s4a # at91sam3s2c # at91sam3s2b # at91sam3s2a # at91sam3s1c # at91sam3s1b # at91sam3s1a source [find target/at91sam3XXX.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam3 0x00400000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam3u1c.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # common stuff source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam3u1e.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # common stuff source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam3u2c.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # common stuff source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam3u2e.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # common stuff source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam3u4c.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # common stuff source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME # This is a 256K chip, it has the 2nd bank set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam3 0x000100000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam3u4e.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # common stuff source [find target/at91sam3uxx.cfg] # size is automatically "calculated" by probing set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME at91sam3 0x000080000 0 1 1 $_TARGETNAME # This is a 256K chip - it has the 2nd bank set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam3 0x000100000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam3uxx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for ATMEL sam3, a Cortex-M3 chip # # at91sam3u4e # at91sam3u2e # at91sam3u1e # at91sam3u4c # at91sam3u2c # at91sam3u1c source [find target/at91sam3XXX.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam4XXX.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # script for ATMEL sam4, a Cortex-M4 chip # # # sam4 devices can support both JTAG and SWD transports. # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sam4 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # By default use 64kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # 16K is plenty, the smallest chip has this much $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # JTAG speed should be <= F_CPU/6. F_CPU after reset is 4 MHz, so use F_JTAG = 0.5MHz # # Since we may be running of an RC oscilator, we crank down the speed a # bit more to be on the safe side. Perhaps superstition, but if are # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. adapter speed 500 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam4c32x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for ATMEL sam4c32, a Cortex-M4 chip # source [find target/at91sam4XXX.cfg] set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME at91sam4 0x01000000 0 1 1 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam4 0x01100000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam4cXXX.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for ATMEL sam4c, a Cortex-M4 chip # source [find target/at91sam4XXX.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam4 0x01000000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam4lXX.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for ATMEL sam4l, a Cortex-M4 chip # source [find target/at91sam4XXX.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam4l 0x00000000 0 1 1 $_TARGETNAME # SAM4L SMAP will hold the CPU in reset if TCK is low when RESET_N # deasserts (see datasheet 42023E-SAM-07/2013 sec 8.11.3). # # smap_reset_deassert configures whether we want to run or halt out of reset, # then instruct the SMAP to let us out of reset. $_TARGETNAME configure -event reset-deassert-post "at91sam4l smap_reset_deassert" # SRST (wired to RESET_N) resets debug circuitry # srst_pulls_trst is not configured here to avoid an error raised in reset halt reset_config srst_gates_jtag # SAM4L starts from POR with SYSCLK set to 115kHz RCSYS, needs slow JTAG speed. # Datasheet does not specify SYSCLK to JTAG/SWD clock ratio. # Usually used SYSCLK/6 is hell slow, testing shows that debugging can work @ SYSCLK/2 # but your mileage may vary. adapter speed 50 # System RC oscillator RCSYS starts in 3 cycles adapter srst delay 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam4sXX.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for ATMEL sam4, a Cortex-M4 chip # source [find target/at91sam4XXX.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam4 0x00400000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam4sd32x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for ATMEL sam4sd32, a Cortex-M4 chip # source [find target/at91sam4XXX.cfg] set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME at91sam4 0x00400000 0 1 1 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME at91sam4 0x00500000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam7a2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91sam7a2 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x1f0f0f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam7se512.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # ATMEL sam7se512 # Example: the "Elektor Internet Radio" - EIR # http://www.ethernut.de/en/hardware/eir/index.html if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sam7se512 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # Force an error until we get a good number. set _CPUTAPID 0xffffffff } #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only srst_pulls_trst #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # The target set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup 0 #flash bank <driver> <base_addr> <size> <chip_width> <bus_width> <target_number> [<target_name> <banks> <sectors_per_bank> <pages_per_sector> <page_size> <num_nvmbits> <ext_freq_khz>] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 0 18432 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam7sx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only srst_pulls_trst if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91sam7s } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-init { soft_reset_halt # RSTC_CR : Reset peripherals mww 0xfffffd00 0xa5000004 # disable watchdog mww 0xfffffd44 0x00008000 # enable user reset mww 0xfffffd08 0xa5000001 # CKGR_MOR : enable the main oscillator mww 0xfffffc20 0x00000601 sleep 10 # CKGR_PLLR: 96.1097 MHz mww 0xfffffc2c 0x00481c0e sleep 10 # PMC_MCKR : MCK = PLL / 2 ~= 48 MHz mww 0xfffffc30 0x00000007 sleep 10 # MC_FMR: flash mode (FWS=1,FMCN=73) mww 0xffffff60 0x00490100 sleep 100 } $_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup 0 #flash bank <driver> <base_addr> <size> <chip_width> <bus_width> <target_number> [<target_name> <banks> <sectors_per_bank> <pages_per_sector> <page_size> <num_nvmbits> <ext_freq_khz>] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 0 18432 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam7x256.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only srst_pulls_trst if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sam7x256 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-init { # disable watchdog mww 0xfffffd44 0x00008000 # enable user reset mww 0xfffffd08 0xa5000001 # CKGR_MOR : enable the main oscillator mww 0xfffffc20 0x00000601 sleep 10 # CKGR_PLLR: 96.1097 MHz mww 0xfffffc2c 0x00481c0e sleep 10 # PMC_MCKR : MCK = PLL / 2 ~= 48 MHz mww 0xfffffc30 0x00000007 sleep 10 # MC_FMR: flash mode (FWS=1,FMCN=60) mww 0xffffff60 0x003c0100 sleep 100 } $_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup 0 #flash bank <driver> <base_addr> <size> <chip_width> <bus_width> <target_number> [<target_name> <banks> <sectors_per_bank> <pages_per_sector> <page_size> <num_nvmbits> <ext_freq_khz>] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 0 18432 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam7x512.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only srst_pulls_trst if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sam7x512 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-init { # disable watchdog mww 0xfffffd44 0x00008000 # enable user reset mww 0xfffffd08 0xa5000001 # CKGR_MOR : enable the main oscillator mww 0xfffffc20 0x00000601 sleep 10 # CKGR_PLLR: 96.1097 MHz mww 0xfffffc2c 0x00481c0e sleep 10 # PMC_MCKR : MCK = PLL / 2 ~= 48 MHz mww 0xfffffc30 0x00000007 sleep 10 # MC_FMR: flash mode (FWS=1,FMCN=60) mww 0xffffff60 0x003c0100 sleep 100 } $_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup 0 #flash bank <driver> <base_addr> <size> <chip_width> <bus_width> <target_number> [<target_name> <banks> <sectors_per_bank> <pages_per_sector> <page_size> <num_nvmbits> <ext_freq_khz>] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME.0 at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 0 18432 flash bank $_FLASHNAME.1 at91sam7 0 0 0 0 $_TARGETNAME 1 0 0 0 0 0 0 18432 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam9.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: Atmel AT91SAM9 ###################################### if { [info exists AT91_CHIPNAME] } { set _CHIPNAME $AT91_CHIPNAME } else { error "you must specify a chip name" } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0792603f } reset_config trst_and_srst separate trst_push_pull srst_open_drain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID adapter srst delay 300 jtag_ntrst_delay 200 adapter speed 3 ###################### # Target configuration ###################### set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam9260.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: Atmel AT91SAM9260 ###################################### if { [info exists CHIPNAME] } { set AT91_CHIPNAME $CHIPNAME } else { set AT91_CHIPNAME at91sam9260 } source [find target/at91sam9.cfg] # Establish internal SRAM memory work areas that are important to pre-bootstrap loaders, etc. The # AT91SAM9260 has two SRAM areas, one starting at 0x00200000 and the other starting at 0x00300000. # Both areas are 4 kB long. #$_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x1000 -work-area-backup 1 $_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x1000 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam9260_ext_RAM_ext_flash.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: Atmel AT91SAM9260 ###################################### source [find target/at91sam9261.cfg] reset_config trst_and_srst adapter speed 4 adapter srst delay 200 jtag_ntrst_delay 200 scan_chain $_TARGETNAME configure -event reset-start { # at reset chip runs at 32khz adapter speed 8 } $_TARGETNAME configure -event reset-init {at91sam_init} # Flash configuration #flash bank <name> cfi <base> <size> <chip width> <bus width> <target> set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x10000000 0x01000000 2 2 $_TARGETNAME # Faster memory downloads. This is disabled automatically during # reset init since all reset init sequences are too short for # fast memory access arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable proc at91sam_init { } { mww 0xfffffd08 0xa5000501 ;# RSTC_MR : enable user reset mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog mww 0xfffffc20 0x00004001 ;# CKGR_MOR : enable the main oscillator sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000001 ;# PMC_MCKR : switch to main oscillator sleep 10 ;# wait 10 ms mww 0xfffffc28 0x2060bf09 ;# CKGR_PLLAR: Set PLLA Register for 198,656MHz sleep 20 ;# wait 20 ms mww 0xfffffc30 0x00000101 ;# PMC_MCKR : Select prescaler sleep 10 ;# wait 10 ms mww 0xfffffc30 0x00000102 ;# PMC_MCKR : Clock from PLLA is selected sleep 10 ;# wait 10 ms # Now run at anything fast... ie: 10mhz! adapter speed 10000 ;# Increase JTAG Speed to 6 MHz mww 0xffffec00 0x0a0a0a0a ;# SMC_SETUP0 : Setup SMC for Intel NOR Flash JS28F128P30T85 128MBit mww 0xffffec04 0x0b0b0b0b ;# SMC_PULSE0 mww 0xffffec08 0x00160016 ;# SMC_CYCLE0 mww 0xffffec0c 0x00161003 ;# SMC_MODE0 mww 0xfffff870 0xffff0000 ;# PIO_ASR : Select peripheral function for D15..D31 mww 0xfffff804 0xffff0000 ;# PIO_PDR : Disable PIO function for D15..D31 mww 0xffffef1c 0x2 ;# EBI_CSA : Assign EBI Chip Select 1 to SDRAM mww 0xffffea08 0x85227259 ;# SDRAMC_CR : Configure SDRAM (2 x Samsung K4S561632H-UC75 : 4M x 16Bit x 4 Banks) #mww 0xffffea08 0x85227254 ;# SDRAMC_CR : Configure SDRAM (2 x Samsung K4S641632H-UC75 : 1M x 16Bit x 4 Banks) mww 0xffffea00 0x1 ;# SDRAMC_MR : issue a NOP command mww 0x20000000 0 mww 0xffffea00 0x2 ;# SDRAMC_MR : issue an 'All Banks Precharge' command mww 0x20000000 0 mww 0xffffea00 0x4 ;# SDRAMC_MR : issue 8 x 'Auto-Refresh' Command mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x4 mww 0x20000000 0 mww 0xffffea00 0x3 ;# SDRAMC_MR : issue a 'Load Mode Register' command mww 0x20000000 0 mww 0xffffea00 0x0 ;# SDRAMC_MR : normal mode mww 0x20000000 0 mww 0xffffea04 0x5d2 ;# SDRAMC_TR : Set refresh timer count to 15us } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam9261.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: Atmel AT91SAM9261 ###################################### if { [info exists CHIPNAME] } { set AT91_CHIPNAME $CHIPNAME } else { set AT91_CHIPNAME at91sam9261 } source [find target/at91sam9.cfg] # Internal sram1 memory $_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x28000 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam9263.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: Atmel AT91SAM9263 ###################################### if { [info exists CHIPNAME] } { set AT91_CHIPNAME $CHIPNAME } else { set AT91_CHIPNAME at91sam9263 } source [find target/at91sam9.cfg] # Establish internal SRAM memory work areas that are important to pre-bootstrap loaders, etc. The # AT91SAM9263 has two SRAM areas, # one starting at 0x00300000 of 80KiB # and the other starting at 0x00500000 of 16KiB. # Internal sram1 memory $_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x14000 -work-area-backup 1 #$_TARGETNAME configure -work-area-phys 0x00500000 -work-area-size 0x4000 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam9g10.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: Atmel AT91SAM9G10 ###################################### if { [info exists CHIPNAME] } { set AT91_CHIPNAME $CHIPNAME } else { set AT91_CHIPNAME at91sam9g10 } source [find target/at91sam9.cfg] # Establish internal SRAM memory work areas that are important to pre-bootstrap loaders, etc. The # AT91SAM9G10 has one SRAM area at 0x00300000 of 16KiB $_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x4000 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam9g20.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: Atmel AT91SAM9G20 ###################################### if { [info exists CHIPNAME] } { set AT91_CHIPNAME $CHIPNAME } else { set AT91_CHIPNAME at91sam9g20 } source [find target/at91sam9.cfg] # Set fallback clock to 1/6 of worst-case clock speed (which would be the 32.768 kHz slow clock). adapter speed 5 # Establish internal SRAM memory work areas that are important to pre-bootstrap loaders, etc. The # AT91SAM9G20 has two SRAM areas, one starting at 0x00200000 and the other starting at 0x00300000. # Both areas are 16 kB long. #$_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup 1 $_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x4000 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam9g45.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: Atmel AT91SAM9G45 ###################################### if { [info exists CHIPNAME] } { set AT91_CHIPNAME $CHIPNAME } else { set AT91_CHIPNAME at91sam9g45 } source [find target/at91sam9.cfg] # Establish internal SRAM memory work areas that are important to pre-bootstrap loaders, etc. The # AT91SAM9G45 has one SRAM area starting at 0x00300000 of 64 KiB. $_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x200000 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sam9rl.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: Atmel AT91SAM9RL ###################################### if { [info exists CHIPNAME] } { set AT91_CHIPNAME $CHIPNAME } else { set AT91_CHIPNAME at91sam9rl } source [find target/at91sam9.cfg] # Internal sram1 memory $_TARGETNAME configure -work-area-phys 0x00300000 -work-area-size 0x10000 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91sama5d2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # The JTAG connection is disabled at reset, and during the ROM Code execution. # It is re-enabled when the ROM code jumps in the boot file copied from an # external Flash memory into the internalSRAM, or when the ROM code launches # the SAM-BA monitor, when no boot file has been found in any external Flash # memory. # For more JTAG related information see, : # https://ww1.microchip.com/downloads/en/DeviceDoc/SAMA5D2-Series-Data-sheet-ds60001476G.pdf # # If JTAGSEL pin: # - if enabled, boundary Scan mode is activated. JTAG ID Code value is 0x05B3F03F. # - if disabled, ICE mode is activated. Debug Port JTAG IDCODE value is 0x5BA00477 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91sama5d2 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id 0x5ba00477 # Cortex-A5 target set _TARGETNAME $_CHIPNAME.cpu_a5 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME.0 cortex_a -dap $_CHIPNAME.dap ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91samdXX.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # script for Atmel SAMD, SAMR, SAML or SAMC, a Cortex-M0 chip # # # samdXX devices only support SWD transports. # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91samd } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # By default use 2kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x800 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # SAMD DSU will hold the CPU in reset if TCK is low when RESET_N # deasserts (see datasheet Atmel-42181E–SAM-D21_Datasheet–02/2015, section 12.6.2) # # dsu_reset_deassert configures whether we want to run or halt out of reset, # then instruct the DSU to let us out of reset. $_TARGETNAME configure -event reset-deassert-post { at91samd dsu_reset_deassert } # SRST (wired to RESET_N) resets debug circuitry # srst_pulls_trst is not configured here to avoid an error raised in reset halt reset_config srst_gates_jtag # Do not use a reset button with other SWD adapter than Atmel's EDBG. # DSU usually locks MCU in reset state until you issue a reset command # in OpenOCD. # SAMD runs at SYSCLK = 1 MHz divided from RC oscillator after reset. # Other members of family usually use SYSCLK = 4 MHz after reset. # Datasheet does not specify SYSCLK to SWD clock ratio. # Usually used SYSCLK/6 is slow, testing shows that debugging can # work @ SYSCLK/2 but your mileage may vary. # This limit is most probably imposed by incorrectly handled SWD WAIT # on some SWD adapters. adapter speed 400 # Atmel's EDBG (on-board cmsis-dap adapter of Xplained kits) works # without problem at maximal clock speed. Atmel recommends # adapter speed less than 10 * CPU clock. # adapter speed 5000 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91samd 0x00000000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/at91samg5x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for the ATMEL samg5x Cortex-M4F chip family # source [find target/at91sam4XXX.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME at91sam4 0x00400000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/atheros_ar2313.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME ar2313 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x00000001 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/atheros_ar2315.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME ar2315 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x00000001 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/atheros_ar9331.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The Atheros AR9331 is a highly integrated and cost effective # IEEE 802.11n 1x1 2.4 GHz System- on-a-Chip (SoC) for wireless # local area network (WLAN) AP and router platforms. # # Notes: # - MIPS Processor ID (PRId): 0x00019374 # - 24Kc MIPS processor with 64 KB I-Cache and 32 KB D-Cache, # operating at up to 400 MHz # - External 16-bit DDR1, DDR2, or SDRAM memory interface # - TRST is not available. # - EJTAG PrRst signal is not supported # - RESET_L pin A72 on the SoC will reset internal JTAG logic. # # Pins related for debug and bootstrap: # Name Pin Description # JTAG # JTAG_TCK GPIO0, (A27) Software configurable, default JTAG # JTAG_TDI GPIO6, (B46) Software configurable, default JTAG # JTAG_TDO GPIO7, (A54) Software configurable, default JTAG # JTAG_TMS GPIO8, (A52) Software configurable, default JTAG # Reset # RESET_L -, (A72) Input only # SYS_RST_L ???????? Output reset request or GPIO # Bootstrap # MEM_TYPE[1] GPIO28, (A74) 0 - SDRAM, 1 - DDR1 RAM, 2 - DDR2 RAM # MEM_TYPE[0] GPIO12, (A56) # FW_DOWNLOAD GPIO16, (A75) Used if BOOT_FROM_SPI = 0. 0 - boot from USB # 1 - boot from MDIO. # JTAG_MODE(JS) GPIO11, (B48) 0 - JTAG (Default); 1 - EJTAG # BOOT_FROM_SPI GPIO1, (A77) 0 - ROM boot; 1 - SPI boot # SEL_25M_40M GPIO0, (A78) 0 - 25MHz; 1 - 40MHz # UART # UART0_SOUT GPIO10, (A79) # UART0_SIN GPIO9, (B68) # Per default we need to use "none" variant to be able properly "reset init" # or "reset halt" the CPU. reset_config none srst_pulls_trst # For SRST based variant we still need proper timings. # For ETH part the reset should be asserted at least for 10ms # Since there is no other information let's take 100ms to be sure. adapter srst pulse_width 100 # according to the SoC documentation it should take at least 5ms from # reset end till bootstrap end. In the practice we need 8ms to get JTAG back # to live. adapter srst delay 8 if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME ar9331 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00000001 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME # provide watchdog helper. proc disable_watchdog { } { mww 0xb8060008 0x0 } $_TARGETNAME configure -event halted { disable_watchdog } # Since PrRst is not supported and SRST will reset complete chip # with JTAG engine, we need to reset CPU from CPU itself. $_TARGETNAME configure -event reset-assert-pre { halt } $_TARGETNAME configure -event reset-assert { catch "mww 0xb806001C 0x01000000" } # To be able to trigger complete chip reset, in case JTAG is blocked # or CPU not responding, we still can use this helper. proc full_reset { } { reset_config srst_only reset halt reset_config none } proc disable_watchdog { } { ;# disable watchdog mww 0xb8060008 0x0 } $_TARGETNAME configure -event reset-end { disable_watchdog } # Section with helpers which can be used by boards proc ar9331_25mhz_pll_init {} { mww 0xb8050008 0x00018004 ;# bypass PLL; AHB_POST_DIV - ratio 4 mww 0xb8050004 0x00000352 ;# 34000(ns)/40ns(25MHz) = 0x352 (850) mww 0xb8050000 0x40818000 ;# Power down control for CPU PLL ;# OUTDIV | REFDIV | DIV_INT mww 0xb8050010 0x001003e8 ;# CPU PLL Dither FRAC Register ;# (disabled?) mww 0xb8050000 0x00818000 ;# Power on | OUTDIV | REFDIV | DIV_INT mww 0xb8050008 0x00008000 ;# remove bypass; ;# AHB_POST_DIV - ratio 2 } proc ar9331_ddr1_init {} { mww 0xb8000000 0x7fbc8cd0 ;# DDR_CONFIG - lots of DRAM confs mww 0xb8000004 0x9dd0e6a8 ;# DDR_CONFIG2 - more DRAM confs mww 0xb8000010 0x8 ;# Forces a PRECHARGE ALL cycle mww 0xb8000008 0x133 ;# mode reg: 0x133 - default mww 0xb8000010 0x1 ;# Forces an MRS update cycl mww 0xb800000c 0x2 ;# Extended mode register value. ;# default 0x2 - Reset to weak driver, DLL on mww 0xb8000010 0x2 ;# Forces an EMRS update cycle mww 0xb8000010 0x8 ;# Forces a PRECHARGE ALL cycle mww 0xb8000008 0x33 ;# mode reg: remove some bit? mww 0xb8000010 0x1 ;# Forces an MRS update cycl mww 0xb8000014 0x4186 ;# enable refres: bit(14) - set refresh rate mww 0xb800001c 0x8 ;# This register is used along with DQ Lane 0, ;# DQ[7:0], DQS_0 mww 0xb8000020 0x9 ;# This register is used along with DQ Lane 1, ;# DQ[15:8], DQS_1. mww 0xb8000018 0xff ;# DDR read and capture bit mask. ;# Each bit represents a cycle of valid data. } proc ar9331_ddr2_init {} { mww 0xb8000000 0x7fbc8cd0 ;# DDR_CONFIG - lots of DRAM confs mww 0xb8000004 0x9dd0e6a8 ;# DDR_CONFIG2 - more DRAM confs mww 0xb800008c 0x00000a59 mww 0xb8000010 0x00000008 ;# PRECHARGE ALL cycle mww 0xb8000090 0x00000000 mww 0xb8000010 0x00000010 ;# EMR2S update cycle mww 0xb8000094 0x00000000 mww 0xb8000010 0x00000020 ;# EMR3S update cycle mww 0xb800000c 0x00000000 mww 0xb8000010 0x00000002 ;# EMRS update cycle mww 0xb8000008 0x00000100 mww 0xb8000010 0x00000001 ;# MRS update cycle mww 0xb8000010 0x00000008 ;# PRECHARGE ALL cycle mww 0xb8000010 0x00000004 mww 0xb8000010 0x00000004 ;# AUTO REFRESH cycle mww 0xb8000008 0x00000a33 mww 0xb8000010 0x00000001 ;# MRS update cycle mww 0xb800000c 0x00000382 mww 0xb8000010 0x00000002 ;# EMRS update cycle mww 0xb800000c 0x00000402 mww 0xb8000010 0x00000002 ;# EMRS update cycle mww 0xb8000014 0x00004186 ;# DDR_REFRESH mww 0xb800001c 0x00000008 ;# DDR_TAP_CTRL0 mww 0xb8000020 0x00000009 ;# DDR_TAP_CTRL1 ;# DDR read and capture bit mask. ;# Each bit represents a cycle of valid data. ;# 0xff: use 16-bit DDR mww 0xb8000018 0x000000ff } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/atheros_ar9344.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME ar9344 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x00000001 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME proc test_ar9344_uart0_tx {} { echo "configuring uart0.." mww 0xb802000c 0x87 mww 0xb8020000 0x15 mww 0xb8020004 0 mww 0xb802000c 7 mww 0xb8020004 0 echo "send message: hallo world" mww 0xb8020000 0x68 mww 0xb8020000 0x65 mww 0xb8020000 0x6c mww 0xb8020000 0x6c mww 0xb8020000 0x6f mww 0xb8020000 0x20 mww 0xb8020000 0x77 mww 0xb8020000 0x6f mww 0xb8020000 0x72 mww 0xb8020000 0x6c mww 0xb8020000 0x64 mww 0xb8020000 0x0a } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/atmega128.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # for avr set _CHIPNAME avr set _ENDIAN little # jtag speed adapter speed 4500 reset_config srst_only adapter srst delay 100 #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x8970203F } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME avr -endian $_ENDIAN -chain-position $_TARGETNAME #$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 16384 -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME avr 0 0 0 0 $_TARGETNAME #to use it, script will be like: #init #adapter speed 4500 #reset init #verify_ircapture disable # #halt #wait halt #poll #avr mass_erase 0 #flash write_image E:/Versaloon/Software/CAMERAPROTOCOLAGENT.hex #reset run #shutdown ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/atmega128rfa1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set _CHIPNAME avr set _ENDIAN little # jtag speed adapter speed 4500 # avr jtag docs never connect RSTN reset_config none #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0a70103f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME avr -endian $_ENDIAN -chain-position $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME avr 0 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/atmega32u4.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # ATmega32U4 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME avr } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4958703f } adapter speed 4500 jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME avr -endian $_ENDIAN -chain-position $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME avr 0 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/atsame5x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Microchip (former Atmel) SAM E54, E53, E51 and D51 devices # with a Cortex-M4 core # # # Devices only support SWD transports. # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME atsame5 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # By default use 32kB (the smallest RAM size is 128kB) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x8000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # SAM DSU will hold the CPU in reset if TCK is low when RESET_N # deasserts # # dsu_reset_deassert configures whether we want to run or halt out of reset, # then instruct the DSU to let us out of reset. $_TARGETNAME configure -event reset-deassert-post { atsame5 dsu_reset_deassert } # SRST (wired to RESET_N) resets debug circuitry # srst_pulls_trst is not configured here to avoid an error raised in reset halt reset_config srst_gates_jtag # Do not use a reset button with other SWD adapter than Atmel's EDBG. # DSU usually locks MCU in reset state until you issue a reset command # in OpenOCD. # SAM E5x/D51 runs at SYSCLK = 48 MHz from RC oscillator after reset. # Atmel's EDBG (on-board cmsis-dap adapter of Xplained kits) works # without problem at clock speed over 5000 khz. Atmel recommends # adapter speed less than 10 * CPU clock. adapter speed 2000 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME atsame5 0x00000000 0 1 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/atsaml1x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Microchip (formerly Atmel) SAM L1x target # # Note: These devices support SWD only. # transport select swd if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME saml1x } if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x800 } swd newdap $_CHIPNAME cpu -expected-id 0x0bf11477 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 if {![using_hla]} { cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/atsamv.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # ATMEL SAMV, SAMS, and SAME chips are Cortex-M7 parts # The chips are very similar; the SAMV series just has # more peripherals and seems like the "flagship" of the # family. This script will work for all of them. source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME samv } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # By default use 16kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0bd11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20400000 -work-area-size $_WORKAREASIZE -work-area-backup 0 adapter speed 1800 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq # Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal # HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 # makes the data access cacheable. This allows reading and writing data in the # CPU cache from the debugger, which is far more useful than going straight to # RAM when operating on typical variables, and is generally no worse when # operating on special memory locations. $_CHIPNAME.dap apcsw 0x08000000 0x08000000 } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME atsamv 0x00400000 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/avr32.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set _CHIPNAME avr32 set _ENDIAN big set _CPUTAPID 0x21e8203f adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst separate # jtag scan chain # format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE) jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1 -expected-id $_CPUTAPID set _TARGETNAME [format "%s.cpu" $_CHIPNAME] target create $_TARGETNAME avr32_ap7k -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/bcm2711.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The Broadcom BCM2711 used in Raspberry Pi 4 # No documentation was found on Broadcom website # Partial information is available in raspberry pi website: # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME bcm2711 } if { [info exists CHIPCORES] } { set _cores $CHIPCORES } else { set _cores 4 } if { [info exists USE_SMP] } { set _USE_SMP $USE_SMP } else { set _USE_SMP 0 } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 adapter speed 4000 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # MEM-AP for direct access target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0 # these addresses are obtained from the ROM table via 'dap info 0' command set _DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} set _CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} set _smp_command "target smp" for { set _core 0 } { $_core < $_cores } { incr _core } { set _CTINAME $_CHIPNAME.cti$_core set _TARGETNAME $_CHIPNAME.cpu$_core cti create $_CTINAME -dap $_CHIPNAME.dap -ap-num 0 -baseaddr [lindex $_CTIBASE $_core] target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase [lindex $_DBGBASE $_core] -cti $_CTINAME set _smp_command "$_smp_command $_TARGETNAME" } if {$_USE_SMP} { eval $_smp_command } # default target is cpu0 targets $_CHIPNAME.cpu0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/bcm281xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # BCM281xx if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME bcm281xx } # Main CPU DAP if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 # Dual Cortex-A9 set _TARGETNAME0 $_CHIPNAME.cpu0 set _TARGETNAME1 $_CHIPNAME.cpu1 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME0 cortex_a -dap $_CHIPNAME.dap -coreid 0 -dbgbase 0x3fe10000 target create $_TARGETNAME1 cortex_a -dap $_CHIPNAME.dap -coreid 1 -dbgbase 0x3fe12000 target smp $_TARGETNAME0 $_TARGETNAME1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/bcm2835.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is the Broadcom chip used in the Raspberry Pi Model A, B, B+, # the Compute Module, and the Raspberry Pi Zero. # Partial information is available in raspberry pi website: # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME bcm2835 } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x07b7617F } jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 5 adapter speed 4000 target create $_CHIPNAME.cpu0 arm11 -chain-position $_CHIPNAME.cpu ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/bcm2836.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The Broadcom chip used in the Raspberry Pi 2 Model B # Partial information is available in raspberry pi website: # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME bcm2836 } if { [info exists CHIPCORES] } { set _cores $CHIPCORES } else { set _cores 4 } if { [info exists USE_SMP] } { set _USE_SMP $USE_SMP } else { set _USE_SMP 0 } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 adapter speed 4000 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # MEM-AP for direct access target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0 # these addresses are obtained from the ROM table via 'dap info 0' command set _DBGBASE {0x80010000 0x80012000 0x80014000 0x80016000} set _smp_command "target smp" for { set _core 0 } { $_core < $_cores } { incr _core } { set _TARGETNAME $_CHIPNAME.cpu$_core target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap -coreid $_core -dbgbase [lindex $_DBGBASE $_core] $_TARGETNAME configure -event reset-assert-post { cortex_a dbginit } set _smp_command "$_smp_command $_CHIPNAME.cpu$_core" } if {$_USE_SMP} { eval $_smp_command } # default target is cpu0 targets $_CHIPNAME.cpu0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/bcm2837.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This is the Broadcom chip used in the Raspberry Pi 3, # and in later models of the Raspberry Pi 2. # Partial information is available in raspberry pi website: # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837 # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837b0 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME bcm2837 } if { [info exists CHIPCORES] } { set _cores $CHIPCORES } else { set _cores 4 } if { [info exists USE_SMP] } { set _USE_SMP $USE_SMP } else { set _USE_SMP 0 } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 adapter speed 4000 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # MEM-AP for direct access target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0 # these addresses are obtained from the ROM table via 'dap info 0' command set _DBGBASE {0x80010000 0x80012000 0x80014000 0x80016000} set _CTIBASE {0x80018000 0x80019000 0x8001a000 0x8001b000} set _smp_command "target smp" for { set _core 0 } { $_core < $_cores } { incr _core } { set _CTINAME $_CHIPNAME.cti$_core set _TARGETNAME $_CHIPNAME.cpu$_core cti create $_CTINAME -dap $_CHIPNAME.dap -ap-num 0 -baseaddr [lindex $_CTIBASE $_core] target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase [lindex $_DBGBASE $_core] -cti $_CTINAME $_TARGETNAME configure -event reset-assert-post { aarch64 dbginit } set _smp_command "$_smp_command $_TARGETNAME" } if {$_USE_SMP} { eval $_smp_command } # default target is cpu0 targets $_CHIPNAME.cpu0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/bcm4706.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set _CHIPNAME bcm4706 set _CPUID 0x1008c17f jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian little -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/bcm4718.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set _CHIPNAME bcm4718 set _LVTAPID 0x1471617f set _CPUID 0x0008c17f source [find target/bcm47xx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/bcm47xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later echo "Forcing reset_config to none to prevent OpenOCD from pulling SRST after the switch from LV is already performed" reset_config none jtag newtap $_CHIPNAME-lv tap -irlen 32 -ircapture 0x1 -irmask 0x1f -expected-id $_LVTAPID -expected-id $_CPUID jtag configure $_CHIPNAME-lv.tap -event setup "jtag tapenable $_CHIPNAME.cpu" jtag configure $_CHIPNAME-lv.tap -event tap-disable {} jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUID -disable jtag configure $_CHIPNAME.cpu -event tap-enable "switch_lv_to_ejtag" set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian little -chain-position $_TARGETNAME proc switch_lv_to_ejtag {} { global _CHIPNAME poll 0 irscan $_CHIPNAME-lv.tap 0x143ff3a drscan $_CHIPNAME-lv.tap 32 1 jtag tapdisable $_CHIPNAME-lv.tap poll 1 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/bcm5352e.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set _CHIPNAME bcm5352e set _CPUID 0x0535217f jtag newtap $_CHIPNAME cpu -irlen 8 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian little -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/bcm6348.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set _CHIPNAME bcm6348 set _CPUID 0x0634817f adapter speed 1000 jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/bluefield.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # BlueField SoC Target set _CHIPNAME bluefield # Specify the target device #rshim device /dev/rshim0/rshim # Main DAP if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } adapter speed 1500 swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # Initialize the target name and command variable. set _TARGETNAME $_CHIPNAME.cpu set _smp_command "" # CTI relative address set $_TARGETNAME.cti(0) 0xC4020000 set $_TARGETNAME.cti(1) 0xC4120000 set $_TARGETNAME.cti(2) 0xC8020000 set $_TARGETNAME.cti(3) 0xC8120000 set $_TARGETNAME.cti(4) 0xCC020000 set $_TARGETNAME.cti(5) 0xCC120000 set $_TARGETNAME.cti(6) 0xD0020000 set $_TARGETNAME.cti(7) 0xD0120000 set $_TARGETNAME.cti(8) 0xD4020000 set $_TARGETNAME.cti(9) 0xD4120000 set $_TARGETNAME.cti(10) 0xD8020000 set $_TARGETNAME.cti(11) 0xD8120000 set $_TARGETNAME.cti(12) 0xDC020000 set $_TARGETNAME.cti(13) 0xDC120000 set $_TARGETNAME.cti(14) 0xE0020000 set $_TARGETNAME.cti(15) 0xE0120000 # Create debug targets for a number of cores starting from core '_core_start'. # Adjust the numbers according to board configuration. set _core_start 0 set _cores 16 # Create each core for { set _core $_core_start } { $_core < $_core_start + $_cores } { incr _core 1 } { cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" if { $_core != $_core_start } { set _smp_command "$_smp_command ${_TARGETNAME}$_core" } else { set _smp_command "target smp ${_TARGETNAME}$_core" } eval $_command } # Configure SMP if { $_cores > 1 } { eval $_smp_command } # Make sure the default target is the boot core targets ${_TARGETNAME}0 proc core_up { args } { global _TARGETNAME # Examine remaining cores foreach _core $args { ${_TARGETNAME}$_core arp_examine } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/bluenrg-x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # bluenrg-1/2 and bluenrg-lp devices support only SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME bluenrg-1 } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 24kB-256bytes if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x5F00 } adapter speed 4000 swj_newdap $_CHIPNAME cpu -expected-id 0x0bb11477 -expected-id 0x0bc11477 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu set WDOG_VALUE 0 set WDOG_VALUE_SET 0 target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000100 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME bluenrg-x 0 0 0 0 $_TARGETNAME # In BlueNRG-X reset pin is actually a shutdown (power-off), so define reset as none reset_config none if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } set JTAG_IDCODE_B2 0x0200A041 set JTAG_IDCODE_B1 0x0 $_TARGETNAME configure -event halted { global WDOG_VALUE global WDOG_VALUE_SET set _JTAG_IDCODE [mrw 0x40000004] if {$_JTAG_IDCODE == $JTAG_IDCODE_B2 || $_JTAG_IDCODE == $JTAG_IDCODE_B1} { # Stop watchdog during halt, if enabled. Only Bluenrg-1/2 set WDOG_VALUE [mrw 0x40700008] if [expr {$WDOG_VALUE & (1 << 1)}] { set WDOG_VALUE_SET 1 mww 0x40700008 [expr {$WDOG_VALUE & 0xFFFFFFFD}] } } } $_TARGETNAME configure -event resumed { global WDOG_VALUE global WDOG_VALUE_SET set _JTAG_IDCODE [mrw 0x40000004] if {$_JTAG_IDCODE == $JTAG_IDCODE_B2 || $_JTAG_IDCODE == $JTAG_IDCODE_B1} { if {$WDOG_VALUE_SET} { # Restore watchdog enable value after resume. Only Bluenrg-1/2 mww 0x40700008 $WDOG_VALUE set WDOG_VALUE_SET 0 } } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/c100.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # c100 config. # This is ARM1136 dual core # this script only configures one core (that is used to run Linux) # assume no PLL lock, start slowly adapter speed 100 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME c100 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x27b3645b } if { [info exists DSPTAPID] } { set _DSPTAPID $DSPTAPID } else { set _DSPTAPID 0x27b3645b } jtag newtap $_CHIPNAME dsp -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_DSPTAPID # Per ARM: DDI0211J_arm1136_r1p5_trm.pdf - the ARM 1136 as a 5 bit IR register jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm11 -endian $_ENDIAN -chain-position $_TARGETNAME # C100's ARAM 64k SRAM $_TARGETNAME configure -work-area-phys 0x0a000000 -work-area-size 0x10000 -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/c100config.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # board(-config) specific parameters file. # set CFG_REFCLKFREQ [configC100 CFG_REFCLKFREQ] proc config {label} { return [dict get [configC100] $label ] } # show the value for the param. with label proc showconfig {label} { echo [format "0x%x" [dict get [configC100] $label ]] } # Telo board config # when there are more then one board config # use soft links to c100board-config.tcl # so that only the right board-config gets # included (just like include/configs/board-configs.h # in u-boot. proc configC100 {} { # xtal freq. 24MHz dict set configC100 CFG_REFCLKFREQ 24000000 # Amba Clk 165MHz dict set configC100 CONFIG_SYS_HZ_CLOCK 165000000 dict set configC100 w_amba 1 dict set configC100 x_amba 1 # y = amba_clk * (w+1)*(x+1)*2/xtal_clk dict set configC100 y_amba [expr {[dict get $configC100 CONFIG_SYS_HZ_CLOCK] * ( ([dict get $configC100 w_amba]+1 ) * ([dict get $configC100 x_amba]+1 ) *2 ) / [dict get $configC100 CFG_REFCLKFREQ]} ] # Arm Clk 450MHz, must be a multiple of 25 MHz dict set configC100 CFG_ARM_CLOCK 450000000 dict set configC100 w_arm 0 dict set configC100 x_arm 1 # y = arm_clk * (w+1)*(x+1)*2/xtal_clk dict set configC100 y_arm [expr {[dict get $configC100 CFG_ARM_CLOCK] * ( ([dict get $configC100 w_arm]+1 ) * ([dict get $configC100 x_arm]+1 ) *2 ) / [dict get $configC100 CFG_REFCLKFREQ]} ] } # This should be called for reset init event handler proc setupTelo {} { # setup GPIO used as control signals for C100 setupGPIO # This will allow access to lower 8MB or NOR lowGPIO5 # setup NOR size,timing,etc. setupNOR # setup internals + PLL + DDR2 initC100 } proc setupNOR {} { echo "Setting up NOR: 16MB, 16-bit wide bus, CS0" # this is taken from u-boot/boards/mindspeed/ooma-darwin/board.c:nor_hw_init() set EX_CSEN_REG [regs EX_CSEN_REG ] set EX_CS0_SEG_REG [regs EX_CS0_SEG_REG ] set EX_CS0_CFG_REG [regs EX_CS0_CFG_REG ] set EX_CS0_TMG1_REG [regs EX_CS0_TMG1_REG ] set EX_CS0_TMG2_REG [regs EX_CS0_TMG2_REG ] set EX_CS0_TMG3_REG [regs EX_CS0_TMG3_REG ] set EX_CLOCK_DIV_REG [regs EX_CLOCK_DIV_REG ] set EX_MFSM_REG [regs EX_MFSM_REG ] set EX_CSFSM_REG [regs EX_CSFSM_REG ] set EX_WRFSM_REG [regs EX_WRFSM_REG ] set EX_RDFSM_REG [regs EX_RDFSM_REG ] # enable Expansion Bus Clock + CS0 (NOR) mww $EX_CSEN_REG 0x3 # set the address space for CS0=16MB mww $EX_CS0_SEG_REG 0x7ff # set the CS0 bus width to 16-bit mww $EX_CS0_CFG_REG 0x202 # set timings to NOR mww $EX_CS0_TMG1_REG 0x03034006 mww $EX_CS0_TMG2_REG 0x04040002 #mww $EX_CS0_TMG3_REG # set EBUS clock 165/5=33MHz mww $EX_CLOCK_DIV_REG 0x5 # everything else is OK with default } proc bootNOR {} { set EXP_CS0_BASEADDR [regs EXP_CS0_BASEADDR] set BLOCK_RESET_REG [regs BLOCK_RESET_REG] set DDR_RST [regs DDR_RST] # put DDR controller in reset (so that it comes reset in u-boot) mmw $BLOCK_RESET_REG 0x0 $DDR_RST # setup CS0 controller for NOR setupNOR # make sure we are accessing the lower part of NOR lowGPIO5 # set PC to start of NOR (at boot 0x20000000 = 0x0) reg pc $EXP_CS0_BASEADDR # run resume } proc setupGPIO {} { echo "Setting up GPIO block for Telo" # This is current setup for Telo (see sch. for details): #GPIO0 reset for FXS-FXO IC, leave as input, the IC has internal pullup #GPIO1 irq line for FXS-FXO #GPIO5 addr22 for NOR flash (access to upper 8MB) #GPIO17 reset for DECT module. #GPIO29 CS_n for NAND set GPIO_OUTPUT_REG [regs GPIO_OUTPUT_REG] set GPIO_OE_REG [regs GPIO_OE_REG] # set GPIO29=GPIO17=1, GPIO5=0 mww $GPIO_OUTPUT_REG [expr {1<<29 | 1<<17}] # enable [as output] GPIO29,GPIO17,GPIO5 mww $GPIO_OE_REG [expr {1<<29 | 1<<17 | 1<<5}] } proc highGPIO5 {} { echo "GPIO5 high" set GPIO_OUTPUT_REG [regs GPIO_OUTPUT_REG] # set GPIO5=1 mmw $GPIO_OUTPUT_REG [expr {1 << 5}] 0x0 } proc lowGPIO5 {} { echo "GPIO5 low" set GPIO_OUTPUT_REG [regs GPIO_OUTPUT_REG] # set GPIO5=0 mmw $GPIO_OUTPUT_REG 0x0 [expr {1 << 5}] } proc boardID {id} { # so far built: # 4'b1111 dict set boardID 15 name "EVT1" dict set boardID 15 ddr2size 128M # dict set boardID 15 nandsize 1G # dict set boardID 15 norsize 16M # 4'b0000 dict set boardID 0 name "EVT2" dict set boardID 0 ddr2size 128M # 4'b0001 dict set boardID 1 name "EVT3" dict set boardID 1 ddr2size 256M # 4'b1110 dict set boardID 14 name "EVT3_old" dict set boardID 14 ddr2size 128M # 4'b0010 dict set boardID 2 name "EVT4" dict set boardID 2 ddr2size 256M return $boardID } # converted from u-boot/boards/mindspeed/ooma-darwin/board.c:ooma_board_detect() # figure out what board revision this is, uses BOOTSTRAP register to read stuffed resistors proc ooma_board_detect {} { set GPIO_BOOTSTRAP_REG [regs GPIO_BOOTSTRAP_REG] # read the current value of the BOOTSTRAP pins set tmp [mrw $GPIO_BOOTSTRAP_REG] echo [format "GPIO_BOOTSTRAP_REG (0x%x): 0x%x" $GPIO_BOOTSTRAP_REG $tmp] # extract the GPBP bits set gpbt [expr {($tmp &0x1C00) >> 10 | ($tmp & 0x40) >>3}] # display board ID echo [format "This is %s (0x%x)" [dict get [boardID $gpbt] $gpbt name] $gpbt] # show it on serial console putsUART0 [format "This is %s (0x%x)\n" [dict get [boardID $gpbt] $gpbt name] $gpbt] # return the ddr2 size, used to configure DDR2 on a given board. return [dict get [boardID $gpbt] $gpbt ddr2size] } proc configureDDR2regs_256M {} { set DENALI_CTL_00_DATA [regs DENALI_CTL_00_DATA] set DENALI_CTL_01_DATA [regs DENALI_CTL_01_DATA] set DENALI_CTL_02_DATA [regs DENALI_CTL_02_DATA] set DENALI_CTL_03_DATA [regs DENALI_CTL_03_DATA] set DENALI_CTL_04_DATA [regs DENALI_CTL_04_DATA] set DENALI_CTL_05_DATA [regs DENALI_CTL_05_DATA] set DENALI_CTL_06_DATA [regs DENALI_CTL_06_DATA] set DENALI_CTL_07_DATA [regs DENALI_CTL_07_DATA] set DENALI_CTL_08_DATA [regs DENALI_CTL_08_DATA] set DENALI_CTL_09_DATA [regs DENALI_CTL_09_DATA] set DENALI_CTL_10_DATA [regs DENALI_CTL_10_DATA] set DENALI_CTL_11_DATA [regs DENALI_CTL_11_DATA] set DENALI_CTL_12_DATA [regs DENALI_CTL_12_DATA] set DENALI_CTL_13_DATA [regs DENALI_CTL_13_DATA] set DENALI_CTL_14_DATA [regs DENALI_CTL_14_DATA] set DENALI_CTL_15_DATA [regs DENALI_CTL_15_DATA] set DENALI_CTL_16_DATA [regs DENALI_CTL_16_DATA] set DENALI_CTL_17_DATA [regs DENALI_CTL_17_DATA] set DENALI_CTL_18_DATA [regs DENALI_CTL_18_DATA] set DENALI_CTL_19_DATA [regs DENALI_CTL_19_DATA] set DENALI_CTL_20_DATA [regs DENALI_CTL_20_DATA] set DENALI_CTL_02_VAL 0x0100000000010100 set DENALI_CTL_11_VAL 0x433a32164a560a00 mw64bit $DENALI_CTL_00_DATA 0x0100000101010101 # 01_DATA mod [40]=1, enable BA2 mw64bit $DENALI_CTL_01_DATA 0x0100010100000001 mw64bit $DENALI_CTL_02_DATA $DENALI_CTL_02_VAL mw64bit $DENALI_CTL_03_DATA 0x0102020202020201 mw64bit $DENALI_CTL_04_DATA 0x0000010100000001 mw64bit $DENALI_CTL_05_DATA 0x0203010300010101 mw64bit $DENALI_CTL_06_DATA 0x060a020200020202 mw64bit $DENALI_CTL_07_DATA 0x0000000300000206 mw64bit $DENALI_CTL_08_DATA 0x6400003f3f0a0209 mw64bit $DENALI_CTL_09_DATA 0x1a000000001a1a1a mw64bit $DENALI_CTL_10_DATA 0x0120202020191a18 # 11_DATA mod [39-32]=16,more refresh mw64bit $DENALI_CTL_11_DATA $DENALI_CTL_11_VAL mw64bit $DENALI_CTL_12_DATA 0x0000000000000800 mw64bit $DENALI_CTL_13_DATA 0x0010002000100040 mw64bit $DENALI_CTL_14_DATA 0x0010004000100040 mw64bit $DENALI_CTL_15_DATA 0x04f8000000000000 mw64bit $DENALI_CTL_16_DATA 0x000000002cca0000 mw64bit $DENALI_CTL_17_DATA 0x0000000000000000 mw64bit $DENALI_CTL_18_DATA 0x0302000000000000 mw64bit $DENALI_CTL_19_DATA 0x00001300c8030600 mw64bit $DENALI_CTL_20_DATA 0x0000000081fe00c8 set wr_dqs_shift 0x40 # start DDRC mw64bit $DENALI_CTL_02_DATA [expr {$DENALI_CTL_02_VAL | (1 << 32)}] # wait int_status[2] (DRAM init complete) echo -n "Waiting for DDR2 controller to init..." set tmp [mrw [expr {$DENALI_CTL_08_DATA + 4}]] while { [expr {$tmp & 0x040000}] == 0 } { sleep 1 set tmp [mrw [expr {$DENALI_CTL_08_DATA + 4}]] } echo "done." # do ddr2 training sequence # TBD (for now, if you need it, run trainDDR command) } # converted from u-boot/cpu/arm1136/comcerto/bsp100.c:config_board99() # The values are computed based on Mindspeed and Nanya datasheets proc configureDDR2regs_128M {} { set DENALI_CTL_00_DATA [regs DENALI_CTL_00_DATA] set DENALI_CTL_01_DATA [regs DENALI_CTL_01_DATA] set DENALI_CTL_02_DATA [regs DENALI_CTL_02_DATA] set DENALI_CTL_03_DATA [regs DENALI_CTL_03_DATA] set DENALI_CTL_04_DATA [regs DENALI_CTL_04_DATA] set DENALI_CTL_05_DATA [regs DENALI_CTL_05_DATA] set DENALI_CTL_06_DATA [regs DENALI_CTL_06_DATA] set DENALI_CTL_07_DATA [regs DENALI_CTL_07_DATA] set DENALI_CTL_08_DATA [regs DENALI_CTL_08_DATA] set DENALI_CTL_09_DATA [regs DENALI_CTL_09_DATA] set DENALI_CTL_10_DATA [regs DENALI_CTL_10_DATA] set DENALI_CTL_11_DATA [regs DENALI_CTL_11_DATA] set DENALI_CTL_12_DATA [regs DENALI_CTL_12_DATA] set DENALI_CTL_13_DATA [regs DENALI_CTL_13_DATA] set DENALI_CTL_14_DATA [regs DENALI_CTL_14_DATA] set DENALI_CTL_15_DATA [regs DENALI_CTL_15_DATA] set DENALI_CTL_16_DATA [regs DENALI_CTL_16_DATA] set DENALI_CTL_17_DATA [regs DENALI_CTL_17_DATA] set DENALI_CTL_18_DATA [regs DENALI_CTL_18_DATA] set DENALI_CTL_19_DATA [regs DENALI_CTL_19_DATA] set DENALI_CTL_20_DATA [regs DENALI_CTL_20_DATA] set DENALI_CTL_02_VAL 0x0100010000010100 set DENALI_CTL_11_VAL 0x433A42124A650A37 # set some default values mw64bit $DENALI_CTL_00_DATA 0x0100000101010101 mw64bit $DENALI_CTL_01_DATA 0x0100000100000101 mw64bit $DENALI_CTL_02_DATA $DENALI_CTL_02_VAL mw64bit $DENALI_CTL_03_DATA 0x0102020202020201 mw64bit $DENALI_CTL_04_DATA 0x0201010100000201 mw64bit $DENALI_CTL_05_DATA 0x0203010300010101 mw64bit $DENALI_CTL_06_DATA 0x050A020200020202 mw64bit $DENALI_CTL_07_DATA 0x000000030E0B0205 mw64bit $DENALI_CTL_08_DATA 0x6427003F3F0A0209 mw64bit $DENALI_CTL_09_DATA 0x1A00002F00001A00 mw64bit $DENALI_CTL_10_DATA 0x01202020201A1A1A mw64bit $DENALI_CTL_11_DATA $DENALI_CTL_11_VAL mw64bit $DENALI_CTL_12_DATA 0x0000080000000800 mw64bit $DENALI_CTL_13_DATA 0x0010002000100040 mw64bit $DENALI_CTL_14_DATA 0x0010004000100040 mw64bit $DENALI_CTL_15_DATA 0x0508000000000000 mw64bit $DENALI_CTL_16_DATA 0x000020472D200000 mw64bit $DENALI_CTL_17_DATA 0x0000000008000000 mw64bit $DENALI_CTL_18_DATA 0x0302000000000000 mw64bit $DENALI_CTL_19_DATA 0x00001400C8030604 mw64bit $DENALI_CTL_20_DATA 0x00000000823600C8 set wr_dqs_shift 0x40 # start DDRC mw64bit $DENALI_CTL_02_DATA [expr {$DENALI_CTL_02_VAL | (1 << 32)}] # wait int_status[2] (DRAM init complete) echo -n "Waiting for DDR2 controller to init..." set tmp [mrw [expr {$DENALI_CTL_08_DATA + 4}]] while { [expr {$tmp & 0x040000}] == 0 } { sleep 1 set tmp [mrw [expr {$DENALI_CTL_08_DATA + 4}]] } # This is not necessary #mw64bit $DENALI_CTL_11_DATA [expr {($DENALI_CTL_11_VAL & ~0x00007F0000000000) | ($wr_dqs_shift << 40)} ] echo "done." # do ddr2 training sequence # TBD (for now, if you need it, run trainDDR command) } proc setupUART0 {} { # configure UART0 to 115200, 8N1 set GPIO_LOCK_REG [regs GPIO_LOCK_REG] set GPIO_IOCTRL_REG [regs GPIO_IOCTRL_REG] set GPIO_IOCTRL_VAL [regs GPIO_IOCTRL_VAL] set GPIO_IOCTRL_UART0 [regs GPIO_IOCTRL_UART0] set UART0_LCR [regs UART0_LCR] set LCR_DLAB [regs LCR_DLAB] set UART0_DLL [regs UART0_DLL] set UART0_DLH [regs UART0_DLH] set UART0_IIR [regs UART0_IIR] set UART0_IER [regs UART0_IER] set LCR_ONE_STOP [regs LCR_ONE_STOP] set LCR_CHAR_LEN_8 [regs LCR_CHAR_LEN_8] set FCR_XMITRES [regs FCR_XMITRES] set FCR_RCVRRES [regs FCR_RCVRRES] set FCR_FIFOEN [regs FCR_FIFOEN] set IER_UUE [regs IER_UUE] # unlock writing to IOCTRL register mww $GPIO_LOCK_REG $GPIO_IOCTRL_VAL # enable UART0 mmw $GPIO_IOCTRL_REG $GPIO_IOCTRL_UART0 0x0 # baudrate 115200 # This should really be amba_clk/(16*115200) but amba_clk=165MHz set tmp 89 # Enable Divisor Latch access mmw $UART0_LCR $LCR_DLAB 0x0 # set the divisor to $tmp mww $UART0_DLL [expr {$tmp & 0xff}] mww $UART0_DLH [expr {$tmp >> 8}] # Disable Divisor Latch access mmw $UART0_LCR 0x0 $LCR_DLAB # set the UART to 8N1 mmw $UART0_LCR [expr {$LCR_ONE_STOP | $LCR_CHAR_LEN_8} ] 0x0 # reset FIFO mmw $UART0_IIR [expr {$FCR_XMITRES | $FCR_RCVRRES | $FCR_FIFOEN} ] 0x0 # enable FFUART mww $UART0_IER $IER_UUE } proc putcUART0 {char} { set UART0_LSR [regs UART0_LSR] set UART0_THR [regs UART0_THR] set LSR_TEMT [regs LSR_TEMT] # convert the 'char' to digit set tmp [ scan $char %c ] # /* wait for room in the tx FIFO on FFUART */ while {[expr {[mrw $UART0_LSR] & $LSR_TEMT}] == 0} { sleep 1 } mww $UART0_THR $tmp if { $char == "\n" } { putcUART0 \r } } proc putsUART0 {str} { set index 0 set len [string length $str] while { $index < $len } { putcUART0 [string index $str $index] set index [expr {$index + 1}] } } proc trainDDR2 {} { set ARAM_BASEADDR [regs ARAM_BASEADDR] # you must have run 'reset init' or u-boot # load the training code to ARAM load_image ./images/ddr2train.bin $ARAM_BASEADDR bin # set PC to start of NOR (at boot 0x20000000 = 0x0) reg pc $ARAM_BASEADDR # run resume } proc flashUBOOT {file} { # this will update uboot on NOR partition set EXP_CS0_BASEADDR [regs EXP_CS0_BASEADDR] # setup CS0 controller for NOR setupNOR # make sure we are accessing the lower part of NOR lowGPIO5 flash probe 0 echo "Erasing sectors 0-3 for uboot" putsUART0 "Erasing sectors 0-3 for uboot\n" flash erase_sector 0 0 3 echo "Programming u-boot" putsUART0 "Programming u-boot..." arm11 memwrite burst enable flash write_image $file $EXP_CS0_BASEADDR arm11 memwrite burst disable putsUART0 "done.\n" putsUART0 "Rebooting, please wait!\n" reboot } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/c100helper.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later proc helpC100 {} { echo "List of useful functions for C100 processor:" echo "1) reset init: will set up your Telo board" echo "2) setupNOR: will setup NOR access" echo "3) showNOR: will show current NOR config registers for 16-bit, 16MB NOR" echo "4) setupGPIO: will setup GPIOs for Telo board" echo "5) showGPIO: will show current GPIO config registers" echo "6) highGPIO5: will set GPIO5=NOR_addr22=1 to access upper 8MB" echo "7) lowGPIO5: will set GPIO5=NOR_addr22=0 to access lower 8MB" echo "8) showAmbaClk: will show current config registers for Amba Bus Clock" echo "9) setupAmbaClk: will setup Amba Bus Clock=165MHz" echo "10) showArmClk: will show current config registers for Arm Bus Clock" echo "11) setupArmClk: will setup Amba Bus Clock=450MHz" echo "12) ooma_board_detect: will show which version of Telo you have" echo "13) setupDDR2: will configure DDR2 controller, you must have PLLs configured" echo "14) showDDR2: will show DDR2 config registers" echo "15) showWatchdog: will show current register config for watchdog" echo "16) reboot: will trigger watchdog and reboot Telo (hw reset)" echo "17) bootNOR: will boot Telo from NOR" echo "18) setupUART0: will configure UART0 for 115200 8N1, PLLs have to be configured" echo "19) putcUART0: will print a character on UART0" echo "20) putsUART0: will print a string on UART0" echo "21) trainDDR2: will run DDR2 training program" echo "22) flashUBOOT: will program NOR sectors 0-3 with u-boot.bin" } source [find mem_helper.tcl] # read a 64-bit register (memory mapped) proc mr64bit {reg} { return [read_memory $reg 32 2] } # write a 64-bit register (memory mapped) proc mw64bit {reg value} { set high [expr {$value >> 32}] set low [expr {$value & 0xffffffff}] #echo [format "mw64bit(0x%x): 0x%08x%08x" $reg $high $low] mww $reg $low mww [expr {$reg+4}] $high } proc showNOR {} { echo "This is the current NOR setup" set EX_CSEN_REG [regs EX_CSEN_REG ] set EX_CS0_SEG_REG [regs EX_CS0_SEG_REG ] set EX_CS0_CFG_REG [regs EX_CS0_CFG_REG ] set EX_CS0_TMG1_REG [regs EX_CS0_TMG1_REG ] set EX_CS0_TMG2_REG [regs EX_CS0_TMG2_REG ] set EX_CS0_TMG3_REG [regs EX_CS0_TMG3_REG ] set EX_CLOCK_DIV_REG [regs EX_CLOCK_DIV_REG ] set EX_MFSM_REG [regs EX_MFSM_REG ] set EX_CSFSM_REG [regs EX_CSFSM_REG ] set EX_WRFSM_REG [regs EX_WRFSM_REG ] set EX_RDFSM_REG [regs EX_RDFSM_REG ] echo [format "EX_CSEN_REG (0x%x): 0x%x" $EX_CSEN_REG [mrw $EX_CSEN_REG]] echo [format "EX_CS0_SEG_REG (0x%x): 0x%x" $EX_CS0_SEG_REG [mrw $EX_CS0_SEG_REG]] echo [format "EX_CS0_CFG_REG (0x%x): 0x%x" $EX_CS0_CFG_REG [mrw $EX_CS0_CFG_REG]] echo [format "EX_CS0_TMG1_REG (0x%x): 0x%x" $EX_CS0_TMG1_REG [mrw $EX_CS0_TMG1_REG]] echo [format "EX_CS0_TMG2_REG (0x%x): 0x%x" $EX_CS0_TMG2_REG [mrw $EX_CS0_TMG2_REG]] echo [format "EX_CS0_TMG3_REG (0x%x): 0x%x" $EX_CS0_TMG3_REG [mrw $EX_CS0_TMG3_REG]] echo [format "EX_CLOCK_DIV_REG (0x%x): 0x%x" $EX_CLOCK_DIV_REG [mrw $EX_CLOCK_DIV_REG]] echo [format "EX_MFSM_REG (0x%x): 0x%x" $EX_MFSM_REG [mrw $EX_MFSM_REG]] echo [format "EX_CSFSM_REG (0x%x): 0x%x" $EX_CSFSM_REG [mrw $EX_CSFSM_REG]] echo [format "EX_WRFSM_REG (0x%x): 0x%x" $EX_WRFSM_REG [mrw $EX_WRFSM_REG]] echo [format "EX_RDFSM_REG (0x%x): 0x%x" $EX_RDFSM_REG [mrw $EX_RDFSM_REG]] } proc showGPIO {} { echo "This is the current GPIO register setup" # GPIO outputs register set GPIO_OUTPUT_REG [regs GPIO_OUTPUT_REG] # GPIO Output Enable register set GPIO_OE_REG [regs GPIO_OE_REG] set GPIO_HI_INT_ENABLE_REG [regs GPIO_HI_INT_ENABLE_REG] set GPIO_LO_INT_ENABLE_REG [regs GPIO_LO_INT_ENABLE_REG] # GPIO input register set GPIO_INPUT_REG [regs GPIO_INPUT_REG] set APB_ACCESS_WS_REG [regs APB_ACCESS_WS_REG] set MUX_CONF_REG [regs MUX_CONF_REG] set SYSCONF_REG [regs SYSCONF_REG] set GPIO_ARM_ID_REG [regs GPIO_ARM_ID_REG] set GPIO_BOOTSTRAP_REG [regs GPIO_BOOTSTRAP_REG] set GPIO_LOCK_REG [regs GPIO_LOCK_REG] set GPIO_IOCTRL_REG [regs GPIO_IOCTRL_REG] set GPIO_DEVID_REG [regs GPIO_DEVID_REG] echo [format "GPIO_OUTPUT_REG (0x%x): 0x%x" $GPIO_OUTPUT_REG [mrw $GPIO_OUTPUT_REG]] echo [format "GPIO_OE_REG (0x%x): 0x%x" $GPIO_OE_REG [mrw $GPIO_OE_REG]] echo [format "GPIO_HI_INT_ENABLE_REG(0x%x): 0x%x" $GPIO_HI_INT_ENABLE_REG [mrw $GPIO_HI_INT_ENABLE_REG]] echo [format "GPIO_LO_INT_ENABLE_REG(0x%x): 0x%x" $GPIO_LO_INT_ENABLE_REG [mrw $GPIO_LO_INT_ENABLE_REG]] echo [format "GPIO_INPUT_REG (0x%x): 0x%x" $GPIO_INPUT_REG [mrw $GPIO_INPUT_REG]] echo [format "APB_ACCESS_WS_REG (0x%x): 0x%x" $APB_ACCESS_WS_REG [mrw $APB_ACCESS_WS_REG]] echo [format "MUX_CONF_REG (0x%x): 0x%x" $MUX_CONF_REG [mrw $MUX_CONF_REG]] echo [format "SYSCONF_REG (0x%x): 0x%x" $SYSCONF_REG [mrw $SYSCONF_REG]] echo [format "GPIO_ARM_ID_REG (0x%x): 0x%x" $GPIO_ARM_ID_REG [mrw $GPIO_ARM_ID_REG]] echo [format "GPIO_BOOTSTRAP_REG (0x%x): 0x%x" $GPIO_BOOTSTRAP_REG [mrw $GPIO_BOOTSTRAP_REG]] echo [format "GPIO_LOCK_REG (0x%x): 0x%x" $GPIO_LOCK_REG [mrw $GPIO_LOCK_REG]] echo [format "GPIO_IOCTRL_REG (0x%x): 0x%x" $GPIO_IOCTRL_REG [mrw $GPIO_IOCTRL_REG]] echo [format "GPIO_DEVID_REG (0x%x): 0x%x" $GPIO_DEVID_REG [mrw $GPIO_DEVID_REG]] } # converted from u-boot/cpu/arm1136/comcerto/bsp100.c (HAL_get_amba_clk()) proc showAmbaClk {} { set CFG_REFCLKFREQ [config CFG_REFCLKFREQ] set CLKCORE_AHB_CLK_CNTRL [regs CLKCORE_AHB_CLK_CNTRL] set PLL_CLK_BYPASS [regs PLL_CLK_BYPASS] echo [format "CLKCORE_AHB_CLK_CNTRL (0x%x): 0x%x" $CLKCORE_AHB_CLK_CNTRL [mrw $CLKCORE_AHB_CLK_CNTRL]] set value [read_memory $CLKCORE_AHB_CLK_CNTRL 32 1] # see if the PLL is in bypass mode set bypass [expr {($value & $PLL_CLK_BYPASS) >> 24}] echo [format "PLL bypass bit: %d" $bypass] if {$bypass == 1} { echo [format "Amba Clk is set to REFCLK: %d (MHz)" [expr {$CFG_REFCLKFREQ/1000000}]] } else { # nope, extract x,y,w and compute the PLL output freq. set x [expr {($value & 0x0001F0000) >> 16}] echo [format "x: %d" $x] set y [expr {($value & 0x00000007F)}] echo [format "y: %d" $y] set w [expr {($value & 0x000000300) >> 8}] echo [format "w: %d" $w] echo [format "Amba PLL Clk: %d (MHz)" [expr {($CFG_REFCLKFREQ * $y / (($w + 1) * ($x + 1) * 2))/1000000}]] } } # converted from u-boot/cpu/arm1136/comcerto/bsp100.c (HAL_set_amba_clk()) # this clock is useb by all peripherals (DDR2, ethernet, ebus, etc) proc setupAmbaClk {} { set CLKCORE_PLL_STATUS [regs CLKCORE_PLL_STATUS] set CLKCORE_AHB_CLK_CNTRL [regs CLKCORE_AHB_CLK_CNTRL] set ARM_PLL_BY_CTRL [regs ARM_PLL_BY_CTRL] set ARM_AHB_BYP [regs ARM_AHB_BYP] set PLL_DISABLE [regs PLL_DISABLE] set PLL_CLK_BYPASS [regs PLL_CLK_BYPASS] set AHB_PLL_BY_CTRL [regs AHB_PLL_BY_CTRL] set DIV_BYPASS [regs DIV_BYPASS] set AHBCLK_PLL_LOCK [regs AHBCLK_PLL_LOCK] set CFG_REFCLKFREQ [config CFG_REFCLKFREQ] set CONFIG_SYS_HZ_CLOCK [config CONFIG_SYS_HZ_CLOCK] set w [config w_amba] set x [config x_amba] set y [config y_amba] echo [format "Setting Amba PLL to lock to %d MHz" [expr {$CONFIG_SYS_HZ_CLOCK/1000000}]] #echo [format "setupAmbaClk: w= %d" $w] #echo [format "setupAmbaClk: x= %d" $x] #echo [format "setupAmbaClk: y= %d" $y] # set PLL into BYPASS mode using MUX mmw $CLKCORE_AHB_CLK_CNTRL $PLL_CLK_BYPASS 0x0 # do an internal PLL bypass mmw $CLKCORE_AHB_CLK_CNTRL $AHB_PLL_BY_CTRL 0x0 # wait 500us (ARM running @24Mhz -> 12000 cycles => 500us) # openocd smallest resolution is 1ms so, wait 1ms sleep 1 # disable the PLL mmw $CLKCORE_AHB_CLK_CNTRL $PLL_DISABLE 0x0 # wait 1ms sleep 1 # enable the PLL mmw $CLKCORE_AHB_CLK_CNTRL 0x0 $PLL_DISABLE sleep 1 # set X, W and X mmw $CLKCORE_AHB_CLK_CNTRL 0x0 0xFFFFFF mmw $CLKCORE_AHB_CLK_CNTRL [expr {($x << 16) + ($w << 8) + $y}] 0x0 # wait for PLL to lock echo "Waiting for Amba PLL to lock" while {[expr {[mrw $CLKCORE_PLL_STATUS] & $AHBCLK_PLL_LOCK]} == 0} { sleep 1 } # remove the internal PLL bypass mmw $CLKCORE_AHB_CLK_CNTRL 0x0 $AHB_PLL_BY_CTRL # remove PLL from BYPASS mode using MUX mmw $CLKCORE_AHB_CLK_CNTRL 0x0 $PLL_CLK_BYPASS } # converted from u-boot/cpu/arm1136/comcerto/bsp100.c (HAL_get_arm_clk()) proc showArmClk {} { set CFG_REFCLKFREQ [config CFG_REFCLKFREQ] set CLKCORE_ARM_CLK_CNTRL [regs CLKCORE_ARM_CLK_CNTRL] set PLL_CLK_BYPASS [regs PLL_CLK_BYPASS] echo [format "CLKCORE_ARM_CLK_CNTRL (0x%x): 0x%x" $CLKCORE_ARM_CLK_CNTRL [mrw $CLKCORE_ARM_CLK_CNTRL]] set value [read_memory $CLKCORE_ARM_CLK_CNTRL 32 1] # see if the PLL is in bypass mode set bypass [expr {($value & $PLL_CLK_BYPASS) >> 24}] echo [format "PLL bypass bit: %d" $bypass] if {$bypass == 1} { echo [format "Amba Clk is set to REFCLK: %d (MHz)" [expr {$CFG_REFCLKFREQ/1000000}]] } else { # nope, extract x,y,w and compute the PLL output freq. set x [expr {($value & 0x0001F0000) >> 16}] echo [format "x: %d" $x] set y [expr {($value & 0x00000007F)}] echo [format "y: %d" $y] set w [expr {($value & 0x000000300) >> 8}] echo [format "w: %d" $w] echo [format "Arm PLL Clk: %d (MHz)" [expr {($CFG_REFCLKFREQ * $y / (($w + 1) * ($x + 1) * 2))/1000000}]] } } # converted from u-boot/cpu/arm1136/comcerto/bsp100.c (HAL_set_arm_clk()) # Arm Clock is used by two ARM1136 cores proc setupArmClk {} { set CLKCORE_PLL_STATUS [regs CLKCORE_PLL_STATUS] set CLKCORE_ARM_CLK_CNTRL [regs CLKCORE_ARM_CLK_CNTRL] set ARM_PLL_BY_CTRL [regs ARM_PLL_BY_CTRL] set ARM_AHB_BYP [regs ARM_AHB_BYP] set PLL_DISABLE [regs PLL_DISABLE] set PLL_CLK_BYPASS [regs PLL_CLK_BYPASS] set AHB_PLL_BY_CTRL [regs AHB_PLL_BY_CTRL] set DIV_BYPASS [regs DIV_BYPASS] set FCLK_PLL_LOCK [regs FCLK_PLL_LOCK] set CFG_REFCLKFREQ [config CFG_REFCLKFREQ] set CFG_ARM_CLOCK [config CFG_ARM_CLOCK] set w [config w_arm] set x [config x_arm] set y [config y_arm] echo [format "Setting Arm PLL to lock to %d MHz" [expr {$CFG_ARM_CLOCK/1000000}]] #echo [format "setupArmClk: w= %d" $w] #echo [format "setupArmaClk: x= %d" $x] #echo [format "setupArmaClk: y= %d" $y] # set PLL into BYPASS mode using MUX mmw $CLKCORE_ARM_CLK_CNTRL $PLL_CLK_BYPASS 0x0 # do an internal PLL bypass mmw $CLKCORE_ARM_CLK_CNTRL $ARM_PLL_BY_CTRL 0x0 # wait 500us (ARM running @24Mhz -> 12000 cycles => 500us) # openocd smallest resolution is 1ms so, wait 1ms sleep 1 # disable the PLL mmw $CLKCORE_ARM_CLK_CNTRL $PLL_DISABLE 0x0 # wait 1ms sleep 1 # enable the PLL mmw $CLKCORE_ARM_CLK_CNTRL 0x0 $PLL_DISABLE sleep 1 # set X, W and X mmw $CLKCORE_ARM_CLK_CNTRL 0x0 0xFFFFFF mmw $CLKCORE_ARM_CLK_CNTRL [expr {($x << 16) + ($w << 8) + $y}] 0x0 # wait for PLL to lock echo "Waiting for Amba PLL to lock" while {[expr {[mrw $CLKCORE_PLL_STATUS] & $FCLK_PLL_LOCK]} == 0} { sleep 1 } # remove the internal PLL bypass mmw $CLKCORE_ARM_CLK_CNTRL 0x0 $ARM_PLL_BY_CTRL # remove PLL from BYPASS mode using MUX mmw $CLKCORE_ARM_CLK_CNTRL 0x0 $PLL_CLK_BYPASS } proc setupPLL {} { echo "PLLs setup" setupAmbaClk setupArmClk } # converted from u-boot/cpu/arm1136/bsp100.c:SoC_mem_init() proc setupDDR2 {} { echo "Configuring DDR2" set MEMORY_BASE_ADDR [regs MEMORY_BASE_ADDR] set MEMORY_MAX_ADDR [regs MEMORY_MAX_ADDR] set MEMORY_CR [regs MEMORY_CR] set BLOCK_RESET_REG [regs BLOCK_RESET_REG] set DDR_RST [regs DDR_RST] # put DDR controller in reset (so that it is reset and correctly configured) # this is only necessary if DDR was previously confiured # and not reset. mmw $BLOCK_RESET_REG 0x0 $DDR_RST set M [expr {1024 * 1024}] set DDR_SZ_1024M [expr {1024 * $M}] set DDR_SZ_256M [expr {256 * $M}] set DDR_SZ_128M [expr {128 * $M}] set DDR_SZ_64M [expr {64 * $M}] # ooma_board_detect returns DDR2 memory size set tmp [ooma_board_detect] if {$tmp == "128M"} { echo "DDR2 size 128MB" set ddr_size $DDR_SZ_128M } elseif {$tmp == "256M"} { echo "DDR2 size 256MB" set ddr_size $DDR_SZ_256M } else { echo "Don't know how to handle this DDR2 size?" } # Memory setup register mww $MEMORY_MAX_ADDR [expr {($ddr_size - 1) + $MEMORY_BASE_ADDR}] # disable ROM remap mww $MEMORY_CR 0x0 # Take DDR controller out of reset mmw $BLOCK_RESET_REG $DDR_RST 0x0 # min. 20 ops delay sleep 1 # This will setup Denali DDR2 controller if {$tmp == "128M"} { configureDDR2regs_128M } elseif {$tmp == "256M"} { configureDDR2regs_256M } else { echo "Don't know how to configure DDR2 setup?" } } proc showDDR2 {} { set DENALI_CTL_00_DATA [regs DENALI_CTL_00_DATA] set DENALI_CTL_01_DATA [regs DENALI_CTL_01_DATA] set DENALI_CTL_02_DATA [regs DENALI_CTL_02_DATA] set DENALI_CTL_03_DATA [regs DENALI_CTL_03_DATA] set DENALI_CTL_04_DATA [regs DENALI_CTL_04_DATA] set DENALI_CTL_05_DATA [regs DENALI_CTL_05_DATA] set DENALI_CTL_06_DATA [regs DENALI_CTL_06_DATA] set DENALI_CTL_07_DATA [regs DENALI_CTL_07_DATA] set DENALI_CTL_08_DATA [regs DENALI_CTL_08_DATA] set DENALI_CTL_09_DATA [regs DENALI_CTL_09_DATA] set DENALI_CTL_10_DATA [regs DENALI_CTL_10_DATA] set DENALI_CTL_11_DATA [regs DENALI_CTL_11_DATA] set DENALI_CTL_12_DATA [regs DENALI_CTL_12_DATA] set DENALI_CTL_13_DATA [regs DENALI_CTL_13_DATA] set DENALI_CTL_14_DATA [regs DENALI_CTL_14_DATA] set DENALI_CTL_15_DATA [regs DENALI_CTL_15_DATA] set DENALI_CTL_16_DATA [regs DENALI_CTL_16_DATA] set DENALI_CTL_17_DATA [regs DENALI_CTL_17_DATA] set DENALI_CTL_18_DATA [regs DENALI_CTL_18_DATA] set DENALI_CTL_19_DATA [regs DENALI_CTL_19_DATA] set DENALI_CTL_20_DATA [regs DENALI_CTL_20_DATA] set tmp [mr64bit $DENALI_CTL_00_DATA] echo [format "DENALI_CTL_00_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_00_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_01_DATA] echo [format "DENALI_CTL_01_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_01_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_02_DATA] echo [format "DENALI_CTL_02_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_02_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_03_DATA] echo [format "DENALI_CTL_03_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_03_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_04_DATA] echo [format "DENALI_CTL_04_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_04_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_05_DATA] echo [format "DENALI_CTL_05_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_05_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_06_DATA] echo [format "DENALI_CTL_06_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_06_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_07_DATA] echo [format "DENALI_CTL_07_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_07_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_08_DATA] echo [format "DENALI_CTL_08_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_08_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_09_DATA] echo [format "DENALI_CTL_09_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_09_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_10_DATA] echo [format "DENALI_CTL_10_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_10_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_11_DATA] echo [format "DENALI_CTL_11_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_11_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_12_DATA] echo [format "DENALI_CTL_12_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_12_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_13_DATA] echo [format "DENALI_CTL_13_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_13_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_14_DATA] echo [format "DENALI_CTL_14_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_14_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_15_DATA] echo [format "DENALI_CTL_15_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_15_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_16_DATA] echo [format "DENALI_CTL_16_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_16_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_17_DATA] echo [format "DENALI_CTL_17_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_17_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_18_DATA] echo [format "DENALI_CTL_18_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_18_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_19_DATA] echo [format "DENALI_CTL_19_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_19_DATA $tmp(1) $tmp(0)] set tmp [mr64bit $DENALI_CTL_20_DATA] echo [format "DENALI_CTL_20_DATA (0x%x): 0x%08x%08x" $DENALI_CTL_20_DATA $tmp(1) $tmp(0)] } proc initC100 {} { # this follows u-boot/cpu/arm1136/start.S set GPIO_LOCK_REG [regs GPIO_LOCK_REG] set GPIO_IOCTRL_REG [regs GPIO_IOCTRL_REG] set GPIO_IOCTRL_VAL [regs GPIO_IOCTRL_VAL] set APB_ACCESS_WS_REG [regs APB_ACCESS_WS_REG] set ASA_ARAM_BASEADDR [regs ASA_ARAM_BASEADDR] set ASA_ARAM_TC_CR_REG [regs ASA_ARAM_TC_CR_REG] set ASA_EBUS_BASEADDR [regs ASA_EBUS_BASEADDR] set ASA_EBUS_TC_CR_REG [regs ASA_EBUS_TC_CR_REG] set ASA_TC_REQIDMAEN [regs ASA_TC_REQIDMAEN] set ASA_TC_REQTDMEN [regs ASA_TC_REQTDMEN] set ASA_TC_REQIPSECUSBEN [regs ASA_TC_REQIPSECUSBEN] set ASA_TC_REQARM0EN [regs ASA_TC_REQARM0EN] set ASA_TC_REQARM1EN [regs ASA_TC_REQARM1EN] set ASA_TC_REQMDMAEN [regs ASA_TC_REQMDMAEN] set INTC_ARM1_CONTROL_REG [regs INTC_ARM1_CONTROL_REG] # unlock writing to IOCTRL register mww $GPIO_LOCK_REG $GPIO_IOCTRL_VAL # enable address lines A15-A21 mmw $GPIO_IOCTRL_REG 0xf 0x0 # set ARM into supervisor mode (SVC32) # disable IRQ, FIQ # Do I need this in JTAG mode? # it really should be done as 'and ~0x1f | 0xd3 but # openocd does not support this yet reg cpsr 0xd3 # /* # * flush v4 I/D caches # */ # mov r0, #0 # mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ arm mcr 15 0 7 7 0 0x0 # mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ arm mcr 15 0 8 7 0 0x0 # /* # * disable MMU stuff and caches # */ # mrc p15, 0, r0, c1, c0, 0 arm mrc 15 0 1 0 0 # bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) # bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) # orr r0, r0, #0x00000002 @ set bit 2 (A) Align # orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache # orr r0, r0, #0x00400000 @ set bit 22 (U) # mcr p15, 0, r0, c1, c0, 0 arm mcr 15 0 1 0 0 0x401002 # This is from bsp_init() in u-boot/boards/mindspeed/ooma-darwin/board.c # APB init # // Setting APB Bus Wait states to 1, set post write # (*(volatile u32*)(APB_ACCESS_WS_REG)) = 0x40; mww $APB_ACCESS_WS_REG 0x40 # AHB init # // enable all 6 masters for ARAM mmw $ASA_ARAM_TC_CR_REG [expr {$ASA_TC_REQIDMAEN | $ASA_TC_REQTDMEN | $ASA_TC_REQIPSECUSBEN | $ASA_TC_REQARM0EN | $ASA_TC_REQARM1EN | $ASA_TC_REQMDMAEN}] 0x0 # // enable all 6 masters for EBUS mmw $ASA_EBUS_TC_CR_REG [expr {$ASA_TC_REQIDMAEN | $ASA_TC_REQTDMEN | $ASA_TC_REQIPSECUSBEN | $ASA_TC_REQARM0EN | $ASA_TC_REQARM1EN | $ASA_TC_REQMDMAEN}] 0x0 # ARAM init # // disable pipeline mode in ARAM # I don't think this is documented anywhere? mww $INTC_ARM1_CONTROL_REG 0x1 # configure clocks setupPLL # setupUART0 must be run before setupDDR2 as setupDDR2 uses UART. setupUART0 # enable cache # ? (u-boot does nothing here) # DDR2 memory init setupDDR2 putsUART0 "C100 initialization complete.\n" echo "C100 initialization complete." } # show current state of watchdog timer proc showWatchdog {} { set TIMER_WDT_HIGH_BOUND [regs TIMER_WDT_HIGH_BOUND] set TIMER_WDT_CONTROL [regs TIMER_WDT_CONTROL] set TIMER_WDT_CURRENT_COUNT [regs TIMER_WDT_CURRENT_COUNT] echo [format "TIMER_WDT_HIGH_BOUND (0x%x): 0x%x" $TIMER_WDT_HIGH_BOUND [mrw $TIMER_WDT_HIGH_BOUND]] echo [format "TIMER_WDT_CONTROL (0x%x): 0x%x" $TIMER_WDT_CONTROL [mrw $TIMER_WDT_CONTROL]] echo [format "TIMER_WDT_CURRENT_COUNT (0x%x): 0x%x" $TIMER_WDT_CURRENT_COUNT [mrw $TIMER_WDT_CURRENT_COUNT]] } # converted from u-boot/cpu/arm1136/comcerto/intrrupts.c:void reset_cpu (ulong ignored) # this will trigger watchdog reset # the sw. reset does not work on C100 # watchdog reset effectively works as hw. reset proc reboot {} { set TIMER_WDT_HIGH_BOUND [regs TIMER_WDT_HIGH_BOUND] set TIMER_WDT_CONTROL [regs TIMER_WDT_CONTROL] set TIMER_WDT_CURRENT_COUNT [regs TIMER_WDT_CURRENT_COUNT] # allow the counter to count to high value before triggering # this is because register writes are slow over JTAG and # I don't want to miss the high_bound==curr_count condition mww $TIMER_WDT_HIGH_BOUND 0xffffff mww $TIMER_WDT_CURRENT_COUNT 0x0 echo "JTAG speed lowered to 100kHz" adapter speed 100 mww $TIMER_WDT_CONTROL 0x1 # wait until the reset echo -n "Waiting for watchdog to trigger..." #while {[mrw $TIMER_WDT_CONTROL] == 1} { # echo [format "TIMER_WDT_CURRENT_COUNT (0x%x): 0x%x" $TIMER_WDT_CURRENT_COUNT [mrw $TIMER_WDT_CURRENT_COUNT]] # sleep 1 # #} while {[c100.cpu curstate] != "running"} { sleep 1} echo "done." echo [format "Note that C100 is in %s state, type halt to stop" [c100.cpu curstate]] } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/c100regs.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Note that I basically converted # u-boot/include/asm-arm/arch/comcerto_100.h # defines # this is a work-around for 'global' not working under Linux # access registers by calling this routine. # For example: # set EX_CS_TMG1_REG [regs EX_CS0_TMG1_REG] proc regs {reg} { return [dict get [regsC100] $reg ] } proc showreg {reg} { echo [format "0x%x" [dict get [regsC100] $reg ]] } proc regsC100 {} { #/* memcore */ #/* device memory base addresses */ #// device memory sizes #/* ARAM SIZE=64K */ dict set regsC100 ARAM_SIZE 0x00010000 dict set regsC100 ARAM_BASEADDR 0x0A000000 #/* Hardware Interface Units */ dict set regsC100 APB_BASEADDR 0x10000000 #/* APB_SIZE=16M address range */ dict set regsC100 APB_SIZE 0x01000000 dict set regsC100 EXP_CS0_BASEADDR 0x20000000 dict set regsC100 EXP_CS1_BASEADDR 0x24000000 dict set regsC100 EXP_CS2_BASEADDR 0x28000000 dict set regsC100 EXP_CS3_BASEADDR 0x2C000000 dict set regsC100 EXP_CS4_BASEADDR 0x30000000 dict set regsC100 DDR_BASEADDR 0x80000000 dict set regsC100 TDM_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x000000}] dict set regsC100 PHI_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x010000}] dict set regsC100 TDMA_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x020000}] dict set regsC100 ASA_DDR_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x040000}] dict set regsC100 ASA_ARAM_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x048000}] dict set regsC100 TIMER_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x050000}] dict set regsC100 ASD_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x060000}] dict set regsC100 GPIO_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x070000}] dict set regsC100 UART0_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x090000}] dict set regsC100 UART1_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x094000}] dict set regsC100 SPI_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x098000}] dict set regsC100 I2C_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x09C000}] dict set regsC100 INTC_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0A0000}] dict set regsC100 CLKCORE_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0B0000}] dict set regsC100 PUI_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0B0000}] dict set regsC100 GEMAC_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0D0000}] dict set regsC100 IDMA_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0E0000}] dict set regsC100 MEMCORE_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0F0000}] dict set regsC100 ASA_EBUS_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x100000}] dict set regsC100 ASA_AAB_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x108000}] dict set regsC100 GEMAC1_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x190000}] dict set regsC100 EBUS_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x1A0000}] dict set regsC100 MDMA_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x1E0000}] #//////////////////////////////////////////////////////////// #// AHB block // #//////////////////////////////////////////////////////////// dict set regsC100 ASA_ARAM_PRI_REG [expr {[dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x00}] dict set regsC100 ASA_ARAM_TC_REG [expr {[dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x04}] dict set regsC100 ASA_ARAM_TC_CR_REG [expr {[dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x08}] dict set regsC100 ASA_ARAM_STAT_REG [expr {[dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x0C}] dict set regsC100 ASA_EBUS_PRI_REG [expr {[dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x00}] dict set regsC100 ASA_EBUS_TC_REG [expr {[dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x04}] dict set regsC100 ASA_EBUS_TC_CR_REG [expr {[dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x08}] dict set regsC100 ASA_EBUS_STAT_REG [expr {[dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x0C}] dict set regsC100 IDMA_MASTER 0 dict set regsC100 TDMA_MASTER 1 dict set regsC100 USBIPSEC_MASTER 2 dict set regsC100 ARM0_MASTER 3 dict set regsC100 ARM1_MASTER 4 dict set regsC100 MDMA_MASTER 5 #define IDMA_PRIORITY(level) (level) #define TDM_PRIORITY(level) (level << 4) #define USBIPSEC_PRIORITY(level) (level << 8) #define ARM0_PRIORITY(level) (level << 12) #define ARM1_PRIORITY(level) (level << 16) #define MDMA_PRIORITY(level) (level << 20) dict set regsC100 ASA_TC_REQIDMAEN [expr {1<<18}] dict set regsC100 ASA_TC_REQTDMEN [expr {1<<19}] dict set regsC100 ASA_TC_REQIPSECUSBEN [expr {1<<20}] dict set regsC100 ASA_TC_REQARM0EN [expr {1<<21}] dict set regsC100 ASA_TC_REQARM1EN [expr {1<<22}] dict set regsC100 ASA_TC_REQMDMAEN [expr {1<<23}] dict set regsC100 MEMORY_BASE_ADDR 0x80000000 dict set regsC100 MEMORY_MAX_ADDR [expr {[dict get $regsC100 ASD_BASEADDR ] + 0x10}] dict set regsC100 MEMORY_CR [expr {[dict get $regsC100 ASD_BASEADDR ] + 0x14}] dict set regsC100 ROM_REMAP_EN 0x1 #define HAL_asb_priority(level) \ #*(volatile unsigned *)ASA_PRI_REG = level #define HAL_aram_priority(level) \ #*(volatile unsigned *)ASA_ARAM_PRI_REG = level #define HAL_aram_arbitration(arbitration_mask) \ #*(volatile unsigned *)ASA_ARAM_TC_CR_REG |= arbitration_mask #define HAL_aram_defmaster(mask) \ #*(volatile unsigned *)ASA_ARAM_TC_CR_REG = (*(volatile unsigned *)ASA_TC_CR_REG & 0xFFFF) | (mask << 24) #//////////////////////////////////////////////////////////// #// INTC block // #//////////////////////////////////////////////////////////// dict set regsC100 INTC_ARM1_CONTROL_REG [expr {[dict get $regsC100 INTC_BASEADDR ] + 0x18}] #//////////////////////////////////////////////////////////// #// TIMER block // #//////////////////////////////////////////////////////////// dict set regsC100 TIMER0_CNTR_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x00}] dict set regsC100 TIMER0_CURR_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x04}] dict set regsC100 TIMER1_CNTR_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x08}] dict set regsC100 TIMER1_CURR_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x0C}] dict set regsC100 TIMER2_CNTR_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x18}] dict set regsC100 TIMER2_LBOUND_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x10}] dict set regsC100 TIMER2_HBOUND_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x14}] dict set regsC100 TIMER2_CURR_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x1C}] dict set regsC100 TIMER3_LOBND [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x20}] dict set regsC100 TIMER3_HIBND [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x24}] dict set regsC100 TIMER3_CTRL [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x28}] dict set regsC100 TIMER3_CURR_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x2C}] dict set regsC100 TIMER_MASK [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x40}] dict set regsC100 TIMER_STATUS [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x50}] dict set regsC100 TIMER_ACK [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x50}] dict set regsC100 TIMER_WDT_HIGH_BOUND [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0xD0}] dict set regsC100 TIMER_WDT_CONTROL [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0xD4}] dict set regsC100 TIMER_WDT_CURRENT_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0xD8}] #//////////////////////////////////////////////////////////// #// EBUS block #//////////////////////////////////////////////////////////// dict set regsC100 EX_SWRST_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x00}] dict set regsC100 EX_CSEN_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x04}] dict set regsC100 EX_CS0_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x08}] dict set regsC100 EX_CS1_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x0C}] dict set regsC100 EX_CS2_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x10}] dict set regsC100 EX_CS3_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x14}] dict set regsC100 EX_CS4_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x18}] dict set regsC100 EX_CS0_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x1C}] dict set regsC100 EX_CS1_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x20}] dict set regsC100 EX_CS2_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x24}] dict set regsC100 EX_CS3_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x28}] dict set regsC100 EX_CS4_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x2C}] dict set regsC100 EX_CS0_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x30}] dict set regsC100 EX_CS1_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x34}] dict set regsC100 EX_CS2_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x38}] dict set regsC100 EX_CS3_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x3C}] dict set regsC100 EX_CS4_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x40}] dict set regsC100 EX_CS0_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x44}] dict set regsC100 EX_CS1_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x48}] dict set regsC100 EX_CS2_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x4C}] dict set regsC100 EX_CS3_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x50}] dict set regsC100 EX_CS4_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x54}] dict set regsC100 EX_CS0_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x58}] dict set regsC100 EX_CS1_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x5C}] dict set regsC100 EX_CS2_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x60}] dict set regsC100 EX_CS3_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x64}] dict set regsC100 EX_CS4_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x68}] dict set regsC100 EX_CLOCK_DIV_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x6C}] dict set regsC100 EX_MFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x100}] dict set regsC100 EX_MFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x100}] dict set regsC100 EX_CSFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x104}] dict set regsC100 EX_WRFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x108}] dict set regsC100 EX_RDFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x10C}] dict set regsC100 EX_CLK_EN 0x00000001 dict set regsC100 EX_CSBOOT_EN 0x00000002 dict set regsC100 EX_CS0_EN 0x00000002 dict set regsC100 EX_CS1_EN 0x00000004 dict set regsC100 EX_CS2_EN 0x00000008 dict set regsC100 EX_CS3_EN 0x00000010 dict set regsC100 EX_CS4_EN 0x00000020 dict set regsC100 EX_MEM_BUS_8 0x00000000 dict set regsC100 EX_MEM_BUS_16 0x00000002 dict set regsC100 EX_MEM_BUS_32 0x00000004 dict set regsC100 EX_CS_HIGH 0x00000008 dict set regsC100 EX_WE_HIGH 0x00000010 dict set regsC100 EX_RE_HIGH 0x00000020 dict set regsC100 EX_ALE_MODE 0x00000040 dict set regsC100 EX_STRB_MODE 0x00000080 dict set regsC100 EX_DM_MODE 0x00000100 dict set regsC100 EX_NAND_MODE 0x00000200 dict set regsC100 EX_RDY_EN 0x00000400 dict set regsC100 EX_RDY_EDGE 0x00000800 #//////////////////////////////////////////////////////////// #// GPIO block #//////////////////////////////////////////////////////////// # GPIO outputs register dict set regsC100 GPIO_OUTPUT_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x00}] # GPIO Output Enable register dict set regsC100 GPIO_OE_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x04}] dict set regsC100 GPIO_HI_INT_ENABLE_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x08}] dict set regsC100 GPIO_LO_INT_ENABLE_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x0C}] # GPIO input register dict set regsC100 GPIO_INPUT_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x10}] dict set regsC100 APB_ACCESS_WS_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x14}] dict set regsC100 MUX_CONF_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x18}] dict set regsC100 SYSCONF_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x1C}] dict set regsC100 GPIO_ARM_ID_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x30}] dict set regsC100 GPIO_BOOTSTRAP_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x40}] dict set regsC100 GPIO_LOCK_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x38}] dict set regsC100 GPIO_IOCTRL_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x44}] dict set regsC100 GPIO_DEVID_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x50}] dict set regsC100 GPIO_IOCTRL_A15A16 0x00000001 dict set regsC100 GPIO_IOCTRL_A17A18 0x00000002 dict set regsC100 GPIO_IOCTRL_A19A21 0x00000004 dict set regsC100 GPIO_IOCTRL_TMREVT0 0x00000008 dict set regsC100 GPIO_IOCTRL_TMREVT1 0x00000010 dict set regsC100 GPIO_IOCTRL_GPBT3 0x00000020 dict set regsC100 GPIO_IOCTRL_I2C 0x00000040 dict set regsC100 GPIO_IOCTRL_UART0 0x00000080 dict set regsC100 GPIO_IOCTRL_UART1 0x00000100 dict set regsC100 GPIO_IOCTRL_SPI 0x00000200 dict set regsC100 GPIO_IOCTRL_HBMODE 0x00000400 dict set regsC100 GPIO_IOCTRL_VAL 0x55555555 dict set regsC100 GPIO_0 0x01 dict set regsC100 GPIO_1 0x02 dict set regsC100 GPIO_2 0x04 dict set regsC100 GPIO_3 0x08 dict set regsC100 GPIO_4 0x10 dict set regsC100 GPIO_5 0x20 dict set regsC100 GPIO_6 0x40 dict set regsC100 GPIO_7 0x80 dict set regsC100 GPIO_RISING_EDGE 1 dict set regsC100 GPIO_FALLING_EDGE 2 dict set regsC100 GPIO_BOTH_EDGES 3 #//////////////////////////////////////////////////////////// #// UART #//////////////////////////////////////////////////////////// dict set regsC100 UART0_RBR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x00}] dict set regsC100 UART0_THR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x00}] dict set regsC100 UART0_DLL [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x00}] dict set regsC100 UART0_IER [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x04}] dict set regsC100 UART0_DLH [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x04}] dict set regsC100 UART0_IIR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x08}] dict set regsC100 UART0_FCR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x08}] dict set regsC100 UART0_LCR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x0C}] dict set regsC100 UART0_MCR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x10}] dict set regsC100 UART0_LSR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x14}] dict set regsC100 UART0_MSR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x18}] dict set regsC100 UART0_SCR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x1C}] dict set regsC100 UART1_RBR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x00}] dict set regsC100 UART1_THR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x00}] dict set regsC100 UART1_DLL [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x00}] dict set regsC100 UART1_IER [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x04}] dict set regsC100 UART1_DLH [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x04}] dict set regsC100 UART1_IIR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x08}] dict set regsC100 UART1_FCR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x08}] dict set regsC100 UART1_LCR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x0C}] dict set regsC100 UART1_MCR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x10}] dict set regsC100 UART1_LSR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x14}] dict set regsC100 UART1_MSR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x18}] dict set regsC100 UART1_SCR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x1C}] # /* default */ dict set regsC100 LCR_CHAR_LEN_5 0x00 dict set regsC100 LCR_CHAR_LEN_6 0x01 dict set regsC100 LCR_CHAR_LEN_7 0x02 dict set regsC100 LCR_CHAR_LEN_8 0x03 #/* One stop bit! - default */ dict set regsC100 LCR_ONE_STOP 0x00 #/* Two stop bit! */ dict set regsC100 LCR_TWO_STOP 0x04 #/* Parity Enable */ dict set regsC100 LCR_PEN 0x08 dict set regsC100 LCR_PARITY_NONE 0x00 #/* Even Parity Select */ dict set regsC100 LCR_EPS 0x10 #/* Enable Parity Stuff */ dict set regsC100 LCR_PS 0x20 #/* Start Break */ dict set regsC100 LCR_SBRK 0x40 #/* Parity Stuff Bit */ dict set regsC100 LCR_PSB 0x80 #/* UART 16550 Divisor Latch Assess */ dict set regsC100 LCR_DLAB 0x80 #/* FIFO Error Status */ dict set regsC100 LSR_FIFOE [expr {1 << 7}] #/* Transmitter Empty */ dict set regsC100 LSR_TEMT [expr {1 << 6}] #/* Transmit Data Request */ dict set regsC100 LSR_TDRQ [expr {1 << 5}] #/* Break Interrupt */ dict set regsC100 LSR_BI [expr {1 << 4}] #/* Framing Error */ dict set regsC100 LSR_FE [expr {1 << 3}] #/* Parity Error */ dict set regsC100 LSR_PE [expr {1 << 2}] #/* Overrun Error */ dict set regsC100 LSR_OE [expr {1 << 1}] #/* Data Ready */ dict set regsC100 LSR_DR [expr {1 << 0}] #/* DMA Requests Enable */ dict set regsC100 IER_DMAE [expr {1 << 7}] #/* UART Unit Enable */ dict set regsC100 IER_UUE [expr {1 << 6}] #/* NRZ coding Enable */ dict set regsC100 IER_NRZE [expr {1 << 5}] #/* Receiver Time Out Interrupt Enable */ dict set regsC100 IER_RTIOE [expr {1 << 4}] #/* Modem Interrupt Enable */ dict set regsC100 IER_MIE [expr {1 << 3}] #/* Receiver Line Status Interrupt Enable */ dict set regsC100 IER_RLSE [expr {1 << 2}] #/* Transmit Data request Interrupt Enable */ dict set regsC100 IER_TIE [expr {1 << 1}] #/* Receiver Data Available Interrupt Enable */ dict set regsC100 IER_RAVIE [expr {1 << 0}] #/* FIFO Mode Enable Status */ dict set regsC100 IIR_FIFOES1 [expr {1 << 7}] #/* FIFO Mode Enable Status */ dict set regsC100 IIR_FIFOES0 [expr {1 << 6}] #/* Time Out Detected */ dict set regsC100 IIR_TOD [expr {1 << 3}] #/* Interrupt Source Encoded */ dict set regsC100 IIR_IID2 [expr {1 << 2}] #/* Interrupt Source Encoded */ dict set regsC100 IIR_IID1 [expr {1 << 1}] #/* Interrupt Pending (active low) */ dict set regsC100 IIR_IP [expr {1 << 0}] #/* UART 16550 FIFO Control Register */ dict set regsC100 FCR_FIFOEN 0x01 dict set regsC100 FCR_RCVRRES 0x02 dict set regsC100 FCR_XMITRES 0x04 #/* Interrupt Enable Register */ #// UART 16550 #// Enable Received Data Available Interrupt dict set regsC100 IER_RXTH 0x01 #// Enable Transmitter Empty Interrupt dict set regsC100 IER_TXTH 0x02 #//////////////////////////////////////////////////////////// #// CLK + RESET block #//////////////////////////////////////////////////////////// dict set regsC100 CLKCORE_ARM_CLK_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x00}] dict set regsC100 CLKCORE_AHB_CLK_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x04}] dict set regsC100 CLKCORE_PLL_STATUS [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x08}] dict set regsC100 CLKCORE_CLKDIV_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x0C}] dict set regsC100 CLKCORE_TDM_CLK_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x10}] dict set regsC100 CLKCORE_FSYNC_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x14}] dict set regsC100 CLKCORE_CLK_PWR_DWN [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x18}] dict set regsC100 CLKCORE_RNG_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x1C}] dict set regsC100 CLKCORE_RNG_STATUS [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x20}] dict set regsC100 CLKCORE_ARM_CLK_CNTRL2 [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x24}] dict set regsC100 CLKCORE_TDM_REF_DIV_RST [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x40}] dict set regsC100 ARM_PLL_BY_CTRL 0x80000000 dict set regsC100 ARM_AHB_BYP 0x04000000 dict set regsC100 PLL_DISABLE 0x02000000 dict set regsC100 PLL_CLK_BYPASS 0x01000000 dict set regsC100 AHB_PLL_BY_CTRL 0x80000000 dict set regsC100 DIV_BYPASS 0x40000000 dict set regsC100 SYNC_MODE 0x20000000 dict set regsC100 EPHY_CLKDIV_BYPASS 0x00200000 dict set regsC100 EPHY_CLKDIV_RATIO_SHIFT 16 dict set regsC100 PUI_CLKDIV_BYPASS 0x00004000 dict set regsC100 PUI_CLKDIV_SRCCLK 0x00002000 dict set regsC100 PUI_CLKDIV_RATIO_SHIFT 8 dict set regsC100 PCI_CLKDIV_BYPASS 0x00000020 dict set regsC100 PCI_CLKDIV_RATIO_SHIFT 0 dict set regsC100 ARM0_CLK_PD 0x00200000 dict set regsC100 ARM1_CLK_PD 0x00100000 dict set regsC100 EPHY_CLK_PD 0x00080000 dict set regsC100 TDM_CLK_PD 0x00040000 dict set regsC100 PUI_CLK_PD 0x00020000 dict set regsC100 PCI_CLK_PD 0x00010000 dict set regsC100 MDMA_AHBCLK_PD 0x00000400 dict set regsC100 I2CSPI_AHBCLK_PD 0x00000200 dict set regsC100 UART_AHBCLK_PD 0x00000100 dict set regsC100 IPSEC_AHBCLK_PD 0x00000080 dict set regsC100 TDM_AHBCLK_PD 0x00000040 dict set regsC100 USB1_AHBCLK_PD 0x00000020 dict set regsC100 USB0_AHBCLK_PD 0x00000010 dict set regsC100 GEMAC1_AHBCLK_PD 0x00000008 dict set regsC100 GEMAC0_AHBCLK_PD 0x00000004 dict set regsC100 PUI_AHBCLK_PD 0x00000002 dict set regsC100 HIF_AHBCLK_PD 0x00000001 dict set regsC100 ARM1_DIV_BP 0x00001000 dict set regsC100 ARM1_DIV_VAL_SHIFT 8 dict set regsC100 ARM0_DIV_BP 0x00000010 dict set regsC100 ARM0_DIV_VAL_SHIFT 0 dict set regsC100 AHBCLK_PLL_LOCK 0x00000002 dict set regsC100 FCLK_PLL_LOCK 0x00000001 #// reset block dict set regsC100 BLOCK_RESET_REG [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x100}] dict set regsC100 CSP_RESET_REG [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x104}] dict set regsC100 RNG_RST 0x1000 dict set regsC100 IPSEC_RST 0x0800 dict set regsC100 DDR_RST 0x0400 dict set regsC100 USB1_PHY_RST 0x0200 dict set regsC100 USB0_PHY_RST 0x0100 dict set regsC100 USB1_RST 0x0080 dict set regsC100 USB0_RST 0x0040 dict set regsC100 GEMAC1_RST 0x0020 dict set regsC100 GEMAC0_RST 0x0010 dict set regsC100 TDM_RST 0x0008 dict set regsC100 PUI_RST 0x0004 dict set regsC100 HIF_RST 0x0002 dict set regsC100 PCI_RST 0x0001 #//////////////////////////////////////////////////////////////// #// DDR CONTROLLER block #//////////////////////////////////////////////////////////////// dict set regsC100 DDR_CONFIG_BASEADDR 0x0D000000 dict set regsC100 DENALI_CTL_00_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x00}] dict set regsC100 DENALI_CTL_01_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x08}] dict set regsC100 DENALI_CTL_02_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x10}] dict set regsC100 DENALI_CTL_03_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x18}] dict set regsC100 DENALI_CTL_04_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x20}] dict set regsC100 DENALI_CTL_05_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x28}] dict set regsC100 DENALI_CTL_06_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x30}] dict set regsC100 DENALI_CTL_07_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x38}] dict set regsC100 DENALI_CTL_08_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x40}] dict set regsC100 DENALI_CTL_09_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x48}] dict set regsC100 DENALI_CTL_10_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x50}] dict set regsC100 DENALI_CTL_11_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x58}] dict set regsC100 DENALI_CTL_12_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x60}] dict set regsC100 DENALI_CTL_13_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x68}] dict set regsC100 DENALI_CTL_14_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x70}] dict set regsC100 DENALI_CTL_15_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x78}] dict set regsC100 DENALI_CTL_16_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x80}] dict set regsC100 DENALI_CTL_17_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x88}] dict set regsC100 DENALI_CTL_18_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x90}] dict set regsC100 DENALI_CTL_19_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x98}] dict set regsC100 DENALI_CTL_20_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0xA0}] # 32-bit value dict set regsC100 DENALI_READY_CHECK [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x44}] # 8-bit dict set regsC100 DENALI_WR_DQS [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x5D}] # 8-bit dict set regsC100 DENALI_DQS_OUT [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x5A}] # 8-bit dict set regsC100 DENALI_DQS_DELAY0 [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x4F}] # 8-bit dict set regsC100 DENALI_DQS_DELAY1 [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] +0x50}] # 8-bit dict set regsC100 DENALI_DQS_DELAY2 [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] +0x51}] # 8-bit dict set regsC100 DENALI_DQS_DELAY3 [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] +0x52}] # end of proc regsC100 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/cc2538.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Config for Texas Instruments low power RF SoC CC2538 # http://www.ti.com/lit/pdf/swru319 adapter speed 100 source [find target/icepick.cfg] source [find target/ti-cjtag.cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cc2538 } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x8B96402F } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" # # ICEpick-C (JTAG route controller) # if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x8B96402F } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version # A start sequence is needed to change from cJTAG (Compact JTAG) to # 4-pin JTAG before talking via JTAG commands jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu" jtag configure $_CHIPNAME.jrc -event post-reset "ti_cjtag_to_4pin_jtag $_CHIPNAME.jrc" # # Cortex-M3 target # set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/cs351x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cs351x } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x00526fa1 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Create the GDB Target. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME fa526 -endian $_ENDIAN -chain-position $_TARGETNAME # There is 16K of SRAM on this chip # FIXME: flash programming is not working by using this work area. So comment this out for now. #$_TARGETNAME configure -work-area-phys 0x00000000 -work-area-size 0x4000 -work-area-backup 1 # This chip has a DCC ... use it arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/davinci.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Utility code for DaVinci-family chips # # davinci_pinmux: assigns PINMUX$reg <== $value proc davinci_pinmux {soc reg value} { mww [expr {[dict get $soc sysbase] + 4 * $reg}] $value } source [find mem_helper.tcl] # # pll_setup: initialize PLL # - pll_addr ... physical addr of controller # - mult ... pll multiplier # - config ... dict mapping { prediv, postdiv, div[1-9] } to dividers # # For PLLs that don't have a given register (e.g. plldiv8), or where a # given divider is non-programmable, caller provides *NO* config mapping. # # PLL version 0x02: tested on dm355 # REVISIT: On dm6446/dm357 the PLLRST polarity is different. proc pll_v02_setup {pll_addr mult config} { set pll_ctrl_addr [expr {$pll_addr + 0x100}] set pll_ctrl [mrw $pll_ctrl_addr] # 1 - clear CLKMODE (bit 8) iff using on-chip oscillator # NOTE: this assumes we should clear that bit set pll_ctrl [expr {$pll_ctrl & ~0x0100}] mww $pll_ctrl_addr $pll_ctrl # 2 - clear PLLENSRC (bit 5) set pll_ctrl [expr {$pll_ctrl & ~0x0020}] mww $pll_ctrl_addr $pll_ctrl # 3 - clear PLLEN (bit 0) ... enter bypass mode set pll_ctrl [expr {$pll_ctrl & ~0x0001}] mww $pll_ctrl_addr $pll_ctrl # 4 - wait at least 4 refclk cycles sleep 1 # 5 - set PLLRST (bit 3) set pll_ctrl [expr {$pll_ctrl | 0x0008}] mww $pll_ctrl_addr $pll_ctrl # 6 - set PLLDIS (bit 4) set pll_ctrl [expr {$pll_ctrl | 0x0010}] mww $pll_ctrl_addr $pll_ctrl # 7 - clear PLLPWRDN (bit 1) set pll_ctrl [expr {$pll_ctrl & ~0x0002}] mww $pll_ctrl_addr $pll_ctrl # 8 - clear PLLDIS (bit 4) set pll_ctrl [expr {$pll_ctrl & ~0x0010}] mww $pll_ctrl_addr $pll_ctrl # 9 - optional: write prediv, postdiv, and pllm # NOTE: for dm355 PLL1, postdiv is controlled via MISC register mww [expr {$pll_addr + 0x0110}] [expr {($mult - 1) & 0xff}] if { [dict exists $config prediv] } { set div [dict get $config prediv] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0114}] $div } if { [dict exists $config postdiv] } { set div [dict get $config postdiv] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0128}] $div } # 10 - optional: set plldiv1, plldiv2, ... # NOTE: this assumes some registers have their just-reset values: # - PLLSTAT.GOSTAT is clear when we enter # - ALNCTL has everything set set go 0 if { [dict exists $config div1] } { set div [dict get $config div1] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0118}] $div set go 1 } if { [dict exists $config div2] } { set div [dict get $config div2] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x011c}] $div set go 1 } if { [dict exists $config div3] } { set div [dict get $config div3] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0120}] $div set go 1 } if { [dict exists $config div4] } { set div [dict get $config div4] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0160}] $div set go 1 } if { [dict exists $config div5] } { set div [dict get $config div5] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0164}] $div set go 1 } if {$go != 0} { # write pllcmd.GO; poll pllstat.GO mww [expr {$pll_addr + 0x0138}] 0x01 set pllstat [expr {$pll_addr + 0x013c}] while {[expr {[mrw $pllstat] & 0x01}] != 0} { sleep 1 } } mww [expr {$pll_addr + 0x0138}] 0x00 # 11 - wait at least 5 usec for reset to finish # (assume covered by overheads including JTAG messaging) # 12 - clear PLLRST (bit 3) set pll_ctrl [expr {$pll_ctrl & ~0x0008}] mww $pll_ctrl_addr $pll_ctrl # 13 - wait at least 8000 refclk cycles for PLL to lock # if we assume 24 MHz (slowest osc), that's 1/3 msec sleep 3 # 14 - set PLLEN (bit 0) ... leave bypass mode set pll_ctrl [expr {$pll_ctrl | 0x0001}] mww $pll_ctrl_addr $pll_ctrl } # PLL version 0x03: tested on dm365 proc pll_v03_setup {pll_addr mult config} { set pll_ctrl_addr [expr {$pll_addr + 0x100}] set pll_secctrl_addr [expr {$pll_addr + 0x108}] set pll_ctrl [mrw $pll_ctrl_addr] # 1 - power up the PLL set pll_ctrl [expr {$pll_ctrl & ~0x0002}] mww $pll_ctrl_addr $pll_ctrl # 2 - clear PLLENSRC (bit 5) set pll_ctrl [expr {$pll_ctrl & ~0x0020}] mww $pll_ctrl_addr $pll_ctrl # 2 - clear PLLEN (bit 0) ... enter bypass mode set pll_ctrl [expr {$pll_ctrl & ~0x0001}] mww $pll_ctrl_addr $pll_ctrl # 3 - wait at least 4 refclk cycles sleep 1 # 4 - set PLLRST (bit 3) set pll_ctrl [expr {$pll_ctrl | 0x0008}] mww $pll_ctrl_addr $pll_ctrl # 5 - wait at least 5 usec sleep 1 # 6 - clear PLLRST (bit 3) set pll_ctrl [expr {$pll_ctrl & ~0x0008}] mww $pll_ctrl_addr $pll_ctrl # 9 - optional: write prediv, postdiv, and pllm mww [expr {$pll_addr + 0x0110}] [expr {($mult / 2) & 0x1ff}] if { [dict exists $config prediv] } { set div [dict get $config prediv] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0114}] $div } if { [dict exists $config postdiv] } { set div [dict get $config postdiv] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0128}] $div } # 10 - write start sequence to PLLSECCTL mww $pll_secctrl_addr 0x00470000 mww $pll_secctrl_addr 0x00460000 mww $pll_secctrl_addr 0x00400000 mww $pll_secctrl_addr 0x00410000 # 11 - optional: set plldiv1, plldiv2, ... # NOTE: this assumes some registers have their just-reset values: # - PLLSTAT.GOSTAT is clear when we enter set aln 0 if { [dict exists $config div1] } { set div [dict get $config div1] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0118}] $div set aln [expr {$aln | 0x1}] } else { mww [expr {$pll_addr + 0x0118}] 0 } if { [dict exists $config div2] } { set div [dict get $config div2] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x011c}] $div set aln [expr {$aln | 0x2}] } else { mww [expr {$pll_addr + 0x011c}] 0 } if { [dict exists $config div3] } { set div [dict get $config div3] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0120}] $div set aln [expr {$aln | 0x4}] } else { mww [expr {$pll_addr + 0x0120}] 0 } if { [dict exists $config oscdiv] } { set div [dict get $config oscdiv] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0124}] $div } else { mww [expr {$pll_addr + 0x0124}] 0 } if { [dict exists $config div4] } { set div [dict get $config div4] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0160}] $div set aln [expr {$aln | 0x8}] } else { mww [expr {$pll_addr + 0x0160}] 0 } if { [dict exists $config div5] } { set div [dict get $config div5] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0164}] $div set aln [expr {$aln | 0x10}] } else { mww [expr {$pll_addr + 0x0164}] 0 } if { [dict exists $config div6] } { set div [dict get $config div6] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0168}] $div set aln [expr {$aln | 0x20}] } else { mww [expr {$pll_addr + 0x0168}] 0 } if { [dict exists $config div7] } { set div [dict get $config div7] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x016c}] $div set aln [expr {$aln | 0x40}] } else { mww [expr {$pll_addr + 0x016c}] 0 } if { [dict exists $config div8] } { set div [dict get $config div8] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0170}] $div set aln [expr {$aln | 0x80}] } else { mww [expr {$pll_addr + 0x0170}] 0 } if { [dict exists $config div9] } { set div [dict get $config div9] set div [expr {0x8000 | ($div - 1)}] mww [expr {$pll_addr + 0x0174}] $div set aln [expr {$aln | 0x100}] } else { mww [expr {$pll_addr + 0x0174}] 0 } if {$aln != 0} { # clear pllcmd.GO mww [expr {$pll_addr + 0x0138}] 0x00 # write alignment flags mww [expr {$pll_addr + 0x0140}] $aln # write pllcmd.GO; poll pllstat.GO mww [expr {$pll_addr + 0x0138}] 0x01 set pllstat [expr {$pll_addr + 0x013c}] while {[expr {[mrw $pllstat] & 0x01}] != 0} { sleep 1 } } mww [expr {$pll_addr + 0x0138}] 0x00 set addr [dict get $config ctladdr] while {[expr {[mrw $addr] & 0x0e000000}] != 0x0e000000} { sleep 1 } # 12 - set PLLEN (bit 0) ... leave bypass mode set pll_ctrl [expr {$pll_ctrl | 0x0001}] mww $pll_ctrl_addr $pll_ctrl } # NOTE: dm6446 requires EMURSTIE set in MDCTL before certain # modules can be enabled. # prepare a non-DSP module to be enabled; finish with psc_go proc psc_enable {module} { set psc_addr 0x01c41000 # write MDCTL mmw [expr {$psc_addr + 0x0a00 + (4 * $module)}] 0x03 0x1f } # prepare a non-DSP module to be reset; finish with psc_go proc psc_reset {module} { set psc_addr 0x01c41000 # write MDCTL mmw [expr {$psc_addr + 0x0a00 + (4 * $module)}] 0x01 0x1f } # execute non-DSP PSC transition(s) set up by psc_enable, psc_reset, etc proc psc_go {} { set psc_addr 0x01c41000 set ptstat_addr [expr {$psc_addr + 0x0128}] # just in case PTSTAT.go isn't clear while { [expr {[mrw $ptstat_addr] & 0x01}] != 0 } { sleep 1 } # write PTCMD.go ... ignoring any DSP power domain mww [expr {$psc_addr + 0x0120}] 1 # wait for PTSTAT.go to clear (again ignoring DSP power domain) while { [expr {[mrw $ptstat_addr] & 0x01}] != 0 } { sleep 1 } } # # A reset using only SRST is a "Warm Reset", resetting everything in the # chip except ARM emulation (and everything _outside_ the chip that hooks # up to SRST). But many boards don't expose SRST via their JTAG connectors # (it's not present on TI-14 headers). # # From the chip-only perspective, a "Max Reset" is a "Warm" reset ... except # without any board-wide side effects, since it's triggered using JTAG using # either (a) ARM watchdog timer, or (b) ICEpick. # proc davinci_wdog_reset {} { set timer2_phys 0x01c21c00 # NOTE -- on entry # - JTAG communication with the ARM *must* be working OK; this # may imply using adaptive clocking or disabling WFI-in-idle # - current target must be the DaVinci ARM # - that ARM core must be halted # - timer2 clock is still enabled (PSC 29 on most chips) # # Part I -- run regardless of being halted via JTAG # # NOTE: for now, we assume there's no DSP that could control the # watchdog; or, equivalently, SUSPSRC.TMR2SRC says the watchdog # suspend signal is controlled via ARM emulation suspend. # # EMUMGT_CLKSPEED: write FREE bit to run despite emulation halt mww phys [expr {$timer2_phys + 0x28}] 0x00004000 # # Part II -- in case watchdog hasn't been set up # # TCR: disable, force internal clock source mww phys [expr {$timer2_phys + 0x20}] 0 # TGCR: reset, force to 64-bit wdog mode, un-reset ("initial" state) mww phys [expr {$timer2_phys + 0x24}] 0 mww phys [expr {$timer2_phys + 0x24}] 0x110b # clear counter (TIM12, TIM34) and period (PRD12, PRD34) registers # so watchdog triggers ASAP mww phys [expr {$timer2_phys + 0x10}] 0 mww phys [expr {$timer2_phys + 0x14}] 0 mww phys [expr {$timer2_phys + 0x18}] 0 mww phys [expr {$timer2_phys + 0x1c}] 0 # WDTCR: put into pre-active state, then active mww phys [expr {$timer2_phys + 0x28}] 0xa5c64000 mww phys [expr {$timer2_phys + 0x28}] 0xda7e4000 # # Part III -- it's ready to rumble # # WDTCR: write invalid WDKEY to trigger reset mww phys [expr {$timer2_phys + 0x28}] 0x00004000 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/dragonite.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: Marvell Dragonite CPU core ###################################### if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dragonite } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x121003d3 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME dragonite -endian $_ENDIAN -chain-position $_TARGETNAME reset_config trst_and_srst adapter srst delay 200 jtag_ntrst_delay 200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/dsp56321.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Script for freescale DSP56321 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dsp56321 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a big endian set _ENDIAN big } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x1181501d } #jtag speed adapter speed 4500 #has only srst reset_config srst_only #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 1 -irmask 0x1 -expected-id $_CPUTAPID #target configuration set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME dsp563xx -endian $_ENDIAN -chain-position $_TARGETNAME #working area at base of ram $_TARGETNAME configure -work-area-virt 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/dsp568013.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Script for freescale DSP568013 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dsp568013 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a big endian set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x01f2401d } #jtag speed adapter speed 800 reset_config srst_only #MASTER tap jtag newtap $_CHIPNAME chp -irlen 8 -ircapture 1 -irmask 0x03 -expected-id $_CPUTAPID #CORE tap jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 1 -irmask 0x03 -disable -expected-id 0x02211004 #target configuration - There is only 1 tap at a time, hence only 1 target is defined. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME dsp5680xx -endian $_ENDIAN -chain-position $_TARGETNAME # Setup the interesting tap # Disable polling to be able to get idcode from core tap. If re enabled, can be re enabled, but it should be disabled to correctly unlock flash (operations require certain instruction to be in the IR register during reset, and polling would change this) jtag configure $_CHIPNAME.chp -event setup " jtag tapenable $_TARGETNAME poll off " #select CORE tap by modifying the TLM register. #to be used when MASTER tap is selected. jtag configure $_TARGETNAME -event tap-enable " irscan $_CHIPNAME.chp 0x05; drscan $_CHIPNAME.chp 4 0x02; jtag tapdisable $_CHIPNAME.chp; " #select MASTER tap by modifying the TLM register. #to be used when CORE tap is selected. jtag configure $_CHIPNAME.chp -event tap-enable " irscan $_TARGETNAME 0x08; drscan $_TARGETNAME 4 0x1; jtag tapdisable $_TARGETNAME; " #disables the master tap jtag configure $_TARGETNAME -event tap-disable " " #TODO FIND SMARTER WAY. jtag configure $_CHIPNAME.chp -event tap-disable " " #TODO FIND SMARTER WAY. #working area at base of ram $_TARGETNAME configure -work-area-virt 0 #setup flash set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME dsp5680xx_flash 0 0 2 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/dsp568037.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Script for freescale DSP568037 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dsp568037 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a big endian set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x01f2801d } #jtag speed adapter speed 800 reset_config srst_only #MASTER tap jtag newtap $_CHIPNAME chp -irlen 8 -ircapture 1 -irmask 0x03 -expected-id $_CPUTAPID #CORE tap jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 1 -irmask 0x03 -disable -expected-id 0x02211004 #target configuration - There is only 1 tap at a time, hence only 1 target is defined. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME dsp5680xx -endian $_ENDIAN -chain-position $_TARGETNAME # Setup the interesting tap jtag configure $_CHIPNAME.chp -event setup "jtag tapenable $_TARGETNAME" #select CORE tap by modifying the TLM register. #to be used when MASTER tap is selected. jtag configure $_TARGETNAME -event tap-enable " irscan $_CHIPNAME.chp 0x05; drscan $_CHIPNAME.chp 4 0x02; jtag tapdisable $_CHIPNAME.chp; " #select MASTER tap by modifying the TLM register. #to be used when CORE tap is selected. jtag configure $_CHIPNAME.chp -event tap-enable " irscan $_TARGETNAME 0x08; drscan $_TARGETNAME 4 0x1; jtag tapdisable $_TARGETNAME; " #disables the master tap jtag configure $_TARGETNAME -event tap-disable " " #TODO FIND SMARTER WAY. jtag configure $_CHIPNAME.chp -event tap-disable " " #TODO FIND SMARTER WAY. #working area at base of ram $_TARGETNAME configure -work-area-virt 0 #setup flash set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME dsp5680xx_flash 0 0 2 1 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/efm32.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Silicon Labs (formerly Energy Micro) EFM32 target # # Note: All EFM32 chips have SWD support, but only newer series 1 # chips have JTAG support. # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME efm32 } # Work-area is a space in RAM used for flash programming # By default use 2kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x800 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu adapter speed 1000 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME efm32 0 0 0 0 $_TARGETNAME flash bank userdata.flash efm32 0x0FE00000 0 0 0 $_TARGETNAME flash bank lockbits.flash efm32 0x0FE04000 0 0 0 $_TARGETNAME if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/em357.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Target configuration for the Silicon Labs EM357 chips # # # em357 family supports JTAG and SWD transports # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME em357 } # Work-area is a space in RAM used for flash programming # By default use 4kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x3ba00477 } else { set _CPUTAPID 0x1ba00477 } } if { [info exists BSTAPID] } { set _BSTAPID $BSTAPID } else { set _BSTAPID 0x069a962b } if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME em358 } if { [info exists FLASHSIZE] } { set _FLASHSIZE $FLASHSIZE } else { set _FLASHSIZE 0x30000 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if { [using_jtag] } { jtag newtap $_CHIPNAME bs -irlen 4 -expected-id $_BSTAPID -ircapture 0xe -irmask 0xf } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME em357 0x08000000 $_FLASHSIZE 0 0 $_TARGETNAME if { ![using_hla]} { # according to errata, we need to use vectreset rather than sysresetreq to avoid lockup # There is a bug in the chip, which means that when using external debuggers the chip # may lock up in certain CPU clock modes. Affected modes are operating the CPU at # 24MHz derived from the 24MHz crystal, or 12MHz derived from the high frequency RC # oscillator. If an external debugger tool asserts SYSRESETREQ, the chip will lock up and # require a pin reset or power cycle. # # for details, refer to: # http://www.silabs.com/Support%20Documents/TechnicalDocs/EM35x-Errata.pdf cortex_m reset_config vectreset } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/em358.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Target configuration for the Silicon Labs EM358 chips # # em357 family supports JTAG and SWD transports # if { ![info exists CHIPNAME] } { set CHIPNAME em358 } if { ![info exists BSTAPID] } { set BSTAPID 0x069aa62b } # 512K of flash in the em358 chips set FLASHSIZE 0x80000 source [find target/em357.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/eos_s3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # QuickLogic EOS S3 # https://www.quicklogic.com/products/soc/eos-s3-microcontroller/ source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME eos_s3 } if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x80000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap # For now we use SRAM only for software upload $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 adapter speed 4000 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/epc9301.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cirrus Logic EP9301 processor on an Olimex CS-E9301 board. if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ep9301 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # Force an error until we get a good number. set _CPUTAPID 0xffffffff } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID adapter srst delay 100 jtag_ntrst_delay 100 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm920t -endian $_ENDIAN -chain-position $_TARGETNAME -work-area-phys 0x80014000 -work-area-size 0x1000 -work-area-backup 1 #flash configuration #flash bank <driver> <base> <size> <chip_width> <bus_width> [driver_options ...] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cfi 0x60000000 0x1000000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/esi32xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # EnSilica eSi-32xx SoC (eSi-RISC Family) # http://www.ensilica.com/risc-ip/ # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME esi32xx } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x11234001 } jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME esirisc -chain-position $_CHIPNAME.cpu # Targets with the UNIFIED_ADDRESS_SPACE option disabled should set # CACHEARCH to 'harvard'. By default, 'von_neumann' is assumed. if { [info exists CACHEARCH] } { $_TARGETNAME esirisc cache_arch $CACHEARCH } adapter speed 2000 reset_config none # The default linker scripts provided by the eSi-RISC toolchain do not # specify attributes on memory regions, which results in incorrect # application of software breakpoints by GDB. gdb_breakpoint_override hard ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/esp32.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Source the ESP common configuration file. source [find target/esp_common.cfg] # Target specific global variables set _CHIPNAME "esp32" set _CPUTAPID 0x120034e5 set _ESP_ARCH "xtensa" set _ONLYCPU 3 set _FLASH_VOLTAGE 3.3 set _ESP_SMP_TARGET 1 set _ESP_SMP_BREAK 1 set _ESP_EFUSE_MAC_ADDR_REG 0x3ff5A004 if { [info exists ESP32_ONLYCPU] } { set _ONLYCPU $ESP32_ONLYCPU } if { [info exists ESP32_FLASH_VOLTAGE] } { set _FLASH_VOLTAGE $ESP32_FLASH_VOLTAGE } proc esp32_memprot_is_enabled { } { return 0 } proc esp32_soc_reset { } { soft_reset_halt } create_esp_target $_ESP_ARCH source [find target/xtensa-core-esp32.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/esp32s2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Source the ESP common configuration file. source [find target/esp_common.cfg] # Target specific global variables set _CHIPNAME "esp32s2" set _CPUTAPID 0x120034e5 set _ESP_ARCH "xtensa" set _ONLYCPU 1 set _ESP_SMP_TARGET 0 set _ESP_SMP_BREAK 1 set _ESP_EFUSE_MAC_ADDR_REG 0x3f41A004 proc esp32s2_memprot_is_enabled { } { # IRAM0, DPORT_PMS_PRO_IRAM0_0_REG if { [get_mmr_bit 0x3f4c1010 0] != 0 } { return 1 } # DRAM0, DPORT_PMS_PRO_DRAM0_0_REG if { [get_mmr_bit 0x3f4c1028 0] != 0 } { return 1 } # PERI1, DPORT_PMS_PRO_DPORT_0_REG if { [get_mmr_bit 0x3f4c103c 0] != 0 } { return 1 } # PERI2, DPORT_PMS_PRO_AHB_0_REG if { [get_mmr_bit 0x3f4c105c 0] != 0 } { return 1 } return 0 } proc esp32s2_soc_reset { } { soft_reset_halt } create_esp_target $_ESP_ARCH source [find target/xtensa-core-esp32s2.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/esp32s3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Source the ESP common configuration file. source [find target/esp_common.cfg] # Target specific global variables set _CHIPNAME "esp32s3" set _CPUTAPID 0x120034e5 set _ESP_ARCH "xtensa" set _ONLYCPU 3 set _ESP_SMP_TARGET 1 set _ESP_SMP_BREAK 1 set _ESP_EFUSE_MAC_ADDR_REG 0x60007044 if { [info exists ESP32_S3_ONLYCPU] } { set _ONLYCPU $ESP32_S3_ONLYCPU } proc esp32s3_memprot_is_enabled { } { # SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_0_REG if { [get_mmr_bit 0x600C10C0 0] != 0 } { return 1 } # SENSITIVE_CORE_0_PIF_PMS_CONSTRAIN_0_REG if { [get_mmr_bit 0x600C1124 0] != 0 } { return 1 } # SENSITIVE_CORE_1_PIF_PMS_CONSTRAIN_0_REG if { [get_mmr_bit 0x600C11D0 0] != 0 } { return 1 } # IRAM0, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_0_REG if { [get_mmr_bit 0x600C10D8 0] != 0 } { return 1 } # DRAM0, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_0_REG if { [get_mmr_bit 0x600C10FC 0] != 0 } { return 1 } # SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_0_REG if { [get_mmr_bit 0x600C10E4 0] != 0 } { return 1 } # SENSITIVE_CORE_1_IRAM0_PMS_MONITOR_0_REG if { [get_mmr_bit 0x600C10F0 0] != 0 } { return 1 } # SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_0_REG if { [get_mmr_bit 0x600C1104 0] != 0 } { return 1 } # SENSITIVE_CORE_1_DRAM0_PMS_MONITOR_0_REG if { [get_mmr_bit 0x600C1114 0] != 0 } { return 1 } # SENSITIVE_CORE_0_PIF_PMS_MONITOR_0_REG if { [get_mmr_bit 0x600C119C 0] != 0 } { return 1 } # SENSITIVE_CORE_1_PIF_PMS_MONITOR_0_REG if { [get_mmr_bit 0x600C1248 0] != 0 } { return 1 } return 0 } proc esp32s3_soc_reset { } { soft_reset_halt } create_esp_target $_ESP_ARCH source [find target/xtensa-core-esp32s3.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/esp_common.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # set CPU_MAX_ADDRESS 0xFFFFFFFF source [find bitsbytes.tcl] source [find memory.tcl] source [find mmr_helpers.tcl] # Common ESP chips definitions # Espressif supports only NuttX in the upstream. # FreeRTOS support is not upstreamed yet. set _RTOS "hwthread" if { [info exists ESP_RTOS] } { set _RTOS "$ESP_RTOS" } # by default current dir (when OOCD has been started) set _SEMIHOST_BASEDIR "." if { [info exists ESP_SEMIHOST_BASEDIR] } { set _SEMIHOST_BASEDIR $ESP_SEMIHOST_BASEDIR } proc set_esp_common_variables { } { global _CHIPNAME _ONLYCPU _ESP_SMP_TARGET global _CPUNAME_0 _CPUNAME_1 _TARGETNAME_0 _TARGETNAME_1 _TAPNAME_0 _TAPNAME_1 global _ESP_WDT_DISABLE _ESP_SOC_RESET _ESP_MEMPROT_IS_ENABLED # For now we support dual core at most. if { $_ONLYCPU == 1 && $_ESP_SMP_TARGET == 0} { set _TARGETNAME_0 $_CHIPNAME set _CPUNAME_0 cpu set _TAPNAME_0 $_CHIPNAME.$_CPUNAME_0 } else { set _CPUNAME_0 cpu0 set _CPUNAME_1 cpu1 set _TARGETNAME_0 $_CHIPNAME.$_CPUNAME_0 set _TARGETNAME_1 $_CHIPNAME.$_CPUNAME_1 set _TAPNAME_0 $_TARGETNAME_0 set _TAPNAME_1 $_TARGETNAME_1 } set _ESP_WDT_DISABLE "${_CHIPNAME}_wdt_disable" set _ESP_SOC_RESET "${_CHIPNAME}_soc_reset" set _ESP_MEMPROT_IS_ENABLED "${_CHIPNAME}_memprot_is_enabled" } proc create_esp_jtag { } { global _CHIPNAME _CPUNAME_0 _CPUNAME_1 _CPUTAPID _ONLYCPU jtag newtap $_CHIPNAME $_CPUNAME_0 -irlen 5 -expected-id $_CPUTAPID if { $_ONLYCPU != 1 } { jtag newtap $_CHIPNAME $_CPUNAME_1 -irlen 5 -expected-id $_CPUTAPID } elseif [info exists _CPUNAME_1] { jtag newtap $_CHIPNAME $_CPUNAME_1 -irlen 5 -disable -expected-id $_CPUTAPID } } proc create_openocd_targets { } { global _TARGETNAME_0 _TARGETNAME_1 _TAPNAME_0 _TAPNAME_1 _RTOS _CHIPNAME _ONLYCPU target create $_TARGETNAME_0 $_CHIPNAME -chain-position $_TAPNAME_0 -coreid 0 -rtos $_RTOS if { $_ONLYCPU != 1 } { target create $_TARGETNAME_1 $_CHIPNAME -chain-position $_TAPNAME_1 -coreid 1 -rtos $_RTOS target smp $_TARGETNAME_0 $_TARGETNAME_1 } } proc create_esp_target { ARCH } { set_esp_common_variables create_esp_jtag create_openocd_targets configure_openocd_events if { $ARCH == "xtensa"} { configure_esp_xtensa_default_settings } else { # riscv targets are not upstreamed yet. # they can be found at the official Espressif fork. } } #################### Set event handlers and default settings #################### proc configure_event_examine_end { } { global _TARGETNAME_0 _TARGETNAME_1 _ONLYCPU $_TARGETNAME_0 configure -event examine-end { # Need to enable to set 'semihosting_basedir' arm semihosting enable arm semihosting_resexit enable if { [info exists _SEMIHOST_BASEDIR] } { if { $_SEMIHOST_BASEDIR != "" } { arm semihosting_basedir $_SEMIHOST_BASEDIR } } } if { $_ONLYCPU != 1 } { $_TARGETNAME_1 configure -event examine-end { # Need to enable to set 'semihosting_basedir' arm semihosting enable arm semihosting_resexit enable if { [info exists _SEMIHOST_BASEDIR] } { if { $_SEMIHOST_BASEDIR != "" } { arm semihosting_basedir $_SEMIHOST_BASEDIR } } } } } proc configure_event_reset_assert_post { } { global _TARGETNAME_0 _TARGETNAME_1 _ONLYCPU $_TARGETNAME_0 configure -event reset-assert-post { global _ESP_SOC_RESET $_ESP_SOC_RESET } if { $_ONLYCPU != 1 } { $_TARGETNAME_1 configure -event reset-assert-post { global _ESP_SOC_RESET $_ESP_SOC_RESET } } } proc configure_event_halted { } { global _TARGETNAME_0 $_TARGETNAME_0 configure -event halted { global _ESP_WDT_DISABLE $_ESP_WDT_DISABLE esp halted_event_handler } } proc configure_event_gdb_attach { } { global _TARGETNAME_0 _TARGETNAME_1 _ONLYCPU $_TARGETNAME_0 configure -event gdb-attach { if { $_ESP_SMP_BREAK != 0 } { $_TARGETNAME_0 xtensa smpbreak BreakIn BreakOut } # necessary to auto-probe flash bank when GDB is connected and generate proper memory map halt 1000 if { [$_ESP_MEMPROT_IS_ENABLED] } { # 'reset halt' to disable memory protection and allow flasher to work correctly echo "Memory protection is enabled. Reset target to disable it..." reset halt } } if { $_ONLYCPU != 1 } { $_TARGETNAME_1 configure -event gdb-attach { if { $_ESP_SMP_BREAK != 0 } { $_TARGETNAME_1 xtensa smpbreak BreakIn BreakOut } # necessary to auto-probe flash bank when GDB is connected halt 1000 if { [$_ESP_MEMPROT_IS_ENABLED] } { # 'reset halt' to disable memory protection and allow flasher to work correctly echo "Memory protection is enabled. Reset target to disable it..." reset halt } } } } proc configure_openocd_events { } { configure_event_examine_end configure_event_reset_assert_post configure_event_gdb_attach } proc configure_esp_xtensa_default_settings { } { global _TARGETNAME_0 _ESP_SMP_BREAK _FLASH_VOLTAGE _CHIPNAME $_TARGETNAME_0 xtensa maskisr on if { $_ESP_SMP_BREAK != 0 } { $_TARGETNAME_0 xtensa smpbreak BreakIn BreakOut } gdb_breakpoint_override hard if { [info exists _FLASH_VOLTAGE] } { $_TARGETNAME_0 $_CHIPNAME flashbootstrap $_FLASH_VOLTAGE } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/exynos5250.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Samsung Exynos 5250 - dual-core ARM Cortex-A15 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME exynos5250 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create ${_TARGETNAME}0 cortex_a -dap $_CHIPNAME.dap target create ${_TARGETNAME}1 cortex_a -dap $_CHIPNAME.dap target smp ${_TARGETNAME}0 ${_TARGETNAME}1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/faux.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #Script for faux target - used for testing if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91eb40a } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x00000000 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID #target configuration set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME #dummy flash driver set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME faux 0x01000000 0x200000 2 2 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/feroceon.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: Marvell Feroceon CPU core ###################################### if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME feroceon } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x20a023d3 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME feroceon -endian $_ENDIAN -chain-position $_TARGETNAME reset_config trst_and_srst adapter srst delay 200 jtag_ntrst_delay 200 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/fm3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # MB9BF506 # Fujitsu Cortex-M3 with 512kB Flash and 64kB RAM source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME mb9bfxx6 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } # delays on reset lines adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } # Fujitsu Cortex-M3 reset configuration reset_config trst_only swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # MB9BF506 has 64kB of SRAM on its main system bus $_TARGETNAME configure -work-area-phys 0x1FFF8000 -work-area-size 0x10000 -work-area-backup 0 # MB9BF506 has 512kB internal FLASH set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME fm3 0 0 0 0 $_TARGETNAME # 4MHz / 6 = 666kHz, so use 500 adapter speed 500 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/fm4.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Spansion FM4 (ARM Cortex-M4) # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME fm4 } source [find target/swj-dp.tcl] if { [info exists CPUTAPID] } { set _CPU_TAPID $CPUTAPID } elseif { [using_jtag] } { set _CPU_TAPID 0x4ba00477 } else { set _CPU_TAPID 0x2ba01477 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap adapter speed 500 if {![using_hla]} { cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/fm4_mb9bf.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Spansion FM4 MB9BFxxx (ARM Cortex-M4) # source [find target/fm4.cfg] # MB9BF566 M/N/R have 32 KB SRAM0 if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x8000 } $_TARGETNAME configure -work-area-phys [expr {0x20000000 - $_WORKAREASIZE}] \ -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME fm4 0x00000000 0 0 0 $_TARGETNAME $CHIPSERIES ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/fm4_s6e2cc.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Spansion FM4 S6E2CC (ARM Cortex-M4) # source [find target/fm4.cfg] # S6E2CC8 H/J/L have 96 KB SRAM0 if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x18000 } $_TARGETNAME configure -work-area-phys [expr {0x20000000 - $_WORKAREASIZE}] \ -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank ${_FLASHNAME}0 fm4 0x00000000 0 0 0 $_TARGETNAME $CHIPSERIES flash bank ${_FLASHNAME}1 fm4 0x00100000 0 0 0 $_TARGETNAME $CHIPSERIES ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/gd32e23x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for GigaDevice gd32e23x Cortex-M23 Series # https://www.gigadevice.com/microcontroller/gd32e230c8t6/ # # gd32e23x devices support SWD transports only. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME gd32e23x } # Work-area is a space in RAM used for flash programming # By default use 4kB (as found on some GD32E230s) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } # Allow overriding the Flash bank size if { [info exists FLASH_SIZE] } { set _FLASH_SIZE $FLASH_SIZE } else { # autodetect size set _FLASH_SIZE 0 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # this is the SW-DP tap id not the jtag tap id set _CPUTAPID 0x0bf11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME # SWD speed (may be updated to higher value in board config file) adapter speed 1000 reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event examine-end { # Debug clock enable # RCU_APB2EN |= DBGMCUEN mmw 0x40021018 0x00400000 0 # Stop watchdog counters during halt # DBG_CTL0 |= WWDGT_HOLD | FWDGT_HOLD | STB_HOLD | DSLP_HOLD | SLP_HOLD mmw 0x40015804 0x00000307 0 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/gd32vf103.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # GigaDevice GD32VF103 target # # https://www.gigadevice.com/products/microcontrollers/gd32/risc-v/ # source [find mem_helper.tcl] transport select jtag if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME gd32vf103 } # The smallest RAM size 6kB (GD32VF103C4/T4/R4) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1800 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f1x 0x08000000 0 0 0 $_TARGETNAME # DBGMCU_CR register cannot be set in examine-end event as the running RISC-V CPU # does not allow the debugger to access memory. # Stop watchdogs at least before flash programming. $_TARGETNAME configure -event reset-init { # DBGMCU_CR |= DBG_WWDG_STOP | DBG_IWDG_STOP mmw 0xE0042004 0x00000300 0 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/gp326xxxa.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Support for General Plus GP326XXXA chips # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME gp326xxxa } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4f1f0f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME # Use internal SRAM as a work area $_TARGETNAME configure -work-area-phys 0xf8000000 -work-area-size 0x8000 -work-area-backup 0 # The chip has both lines connected together reset_config trst_and_srst srst_pulls_trst # This delay is needed otherwise communication with the target would # be unreliable adapter srst delay 100 # Set the adapter speed ridiculously low just in case we are # running off of a 32kHz clock adapter speed 2 proc gp32xxxa_halt_and_reset_control_registers {} { # System control registers set P_SYSTEM_CTRL_NEW 0xD0000008 set P_SYSTEM_CTRL 0xD000000C set P_SYSTEM_CLK_EN0 0xD0000010 set P_SYSTEM_CLK_EN1 0xD0000014 set P_SYSTEM_RESET_FLAG 0xD0000018 set P_SYSTEM_CLK_CTRL 0xD000001C set P_SYSTEM_LVR_CTRL 0xD0000020 set P_SYSTEM_WATCHDOG_CTRL 0xD0000024 set P_SYSTEM_PLLEN 0xD000005C # Since we can't use SRST without pulling TRST # we can't assume the state of the clock configuration # or watchdog settings. So reset them before porceeding # Set the adapter speed ridiculously low just in case we are # running off of a 32kHz clock adapter speed 2 # Disable any advanced features at this stage arm7_9 dcc_downloads disable arm7_9 fast_memory_access disable # Do a "soft reset" soft_reset_halt # Reset all system control registers to their default "after-reset" values mwh $P_SYSTEM_WATCHDOG_CTRL 0x0000 mwh $P_SYSTEM_LVR_CTRL 0x0000 mwh $P_SYSTEM_CTRL_NEW 0x0001 mwh $P_SYSTEM_CTRL 0x0001 # Clear all reset flags by writing 1's mwh $P_SYSTEM_RESET_FLAG 0x001C mwh $P_SYSTEM_CLK_CTRL 0x8000 mwh $P_SYSTEM_CLK_EN0 0xFFFF mwh $P_SYSTEM_CLK_EN1 0xFFFF mwh $P_SYSTEM_PLLEN 0x0010 # Unfortunately there's no register that would allow us to # know if PLL is locked. So just wait for 100ms in hopes that # it would be enough. sleep 100 # Now that we know that we are running at 48Mhz # Increase JTAG speed and enable speed optimization features adapter speed 5000 arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable } $_TARGETNAME configure -event reset-end { gp32xxxa_halt_and_reset_control_registers } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/hi3798.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Hisilicon Hi3798 Target if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME hi3798 } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } # declare the one JTAG tap to access the DAP jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # declare the 4 main application cores set _TARGETNAME $_CHIPNAME.cpu set _smp_command "" set $_TARGETNAME.cti(0) 0x80020000 set $_TARGETNAME.cti(1) 0x80120000 set $_TARGETNAME.cti(2) 0x80220000 set $_TARGETNAME.cti(3) 0x80320000 set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" if { $_core != 0 } { # non-boot core examination may fail #set _command "$_command -defer-examine" set _smp_command "$_smp_command ${_TARGETNAME}$_core" } else { set _command "$_command -rtos hwthread" set _smp_command "target smp ${_TARGETNAME}$_core" } eval $_command } eval $_smp_command ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/hi6220.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Hisilicon Hi6220 Target if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME hi6220 } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } # declare the one JTAG tap to access the DAP jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version # create the DAP dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap # declare the 8 main application cores set _TARGETNAME $_CHIPNAME.cpu set _smp_command "" set $_TARGETNAME.cti(0) 0x80198000 set $_TARGETNAME.cti(1) 0x80199000 set $_TARGETNAME.cti(2) 0x8019A000 set $_TARGETNAME.cti(3) 0x8019B000 set $_TARGETNAME.cti(4) 0x801D8000 set $_TARGETNAME.cti(5) 0x801D9000 set $_TARGETNAME.cti(6) 0x801DA000 set $_TARGETNAME.cti(7) 0x801DB000 set _cores 8 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" if { $_core != 0 } { # non-boot core examination may fail set _command "$_command -defer-examine" set _smp_command "$_smp_command ${_TARGETNAME}$_core" } else { set _command "$_command -rtos hwthread" set _smp_command "target smp ${_TARGETNAME}$_core" } eval $_command } eval $_smp_command cti create cti.sys -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80003000 # declare the auxiliary Cortex-M3 core on AP #2 (runs mcuimage.bin) target create ${_TARGETNAME}.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -defer-examine # declare the auxiliary Cortex-A7 core target create ${_TARGETNAME}.a7 cortex_a -dap $_CHIPNAME.dap -dbgbase 0x80210000 -defer-examine ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/hilscher_netx10.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ #Hilscher netX 10 CPU if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME netx10 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x25966021 } # jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # that TAP is associated with a target set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/hilscher_netx50.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ #Hilscher netX 50 CPU if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME netx50 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x25966021 } # jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # that TAP is associated with a target set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME # On netX50 SDRAM is not accessible at offset 0xDEAD0-0xDEADF as it is busy from # DMA controller at init. This function will setup a dummy DMA to free this ares # and must be called before using SDRAM proc sdram_fix { } { mww 0x1c005830 0x00000001 mww 0x1c005104 0xBFFFFFFC mww 0x1c00510c 0x00480001 mww 0x1c005110 0x00000001 sleep 100 mww 0x1c00510c 0 mww 0x1c005110 0 mww 0x1c005830 0x00000000 puts "SDRAM Fix executed!" } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/hilscher_netx500.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #Hilscher netX 500 CPU if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME netx500 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926021 } # jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # that TAP is associated with a target set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME proc mread32 {addr} { return [read_memory $addr 32 1] } # This function must be called on netX100/500 right after halt # If it is called later the needed register cannot be written anymore proc sdram_fix { } { set accesskey [mread32 0x00100070] mww 0x00100070 $accesskey mww 0x0010002c 0x00000001 if {[expr {[mread32 0x0010002c] & 0x07}] == 0x07} { puts "SDRAM Fix was not executed. Probably your CPU halted too late and the register is already locked!" } else { puts "SDRAM Fix succeeded!" } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/icepick.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Copyright (C) 2011 by Karl Kurbjun # Copyright (C) 2009 by David Brownell # # Utilities for TI ICEpick-C/D used in most TI SoCs # Details about the ICEPick are available in the the TRM for each SoC # and http://processors.wiki.ti.com/index.php/ICEPICK # create "constants" proc CONST { key } { array set constant { # define ICEPick instructions IR_BYPASS 0x00 IR_ROUTER 0x02 IR_CONNECT 0x07 IF_BYPASS 0x3F } return $constant($key) } # Instruction to connect to the icepick module proc icepick_c_connect {jrc} { # Send CONNECT instruction in IR state irscan $jrc [CONST IR_CONNECT] -endstate IRPAUSE # Send write and connect key drscan $jrc 8 0x89 -endstate DRPAUSE } # Instruction to disconnect to the icepick module proc icepick_c_disconnect {jrc} { # Send CONNECT instruction in IR state irscan $jrc [CONST IR_CONNECT] -endstate IRPAUSE # Send write and connect key drscan $jrc 8 0x86 -endstate DRPAUSE } # # icepick_c_router: # this function is for sending router commands # arguments are: # jrc: TAP name for the ICEpick # rw: read/write (0 for read, 1 for write) # block: icepick or DAP # register: which register to read/write # payload: value to read/write # this function is for sending router commands # proc icepick_c_router {jrc rw block register payload} { set new_dr_value \ [expr { ( ($rw & 0x1) << 31) | ( ($block & 0x7) << 28) | \ ( ($register & 0xF) << 24) | ( $payload & 0xFFFFFF ) } ] # echo "\tNew router value:\t0x[format %x $new_dr_value]" # select router irscan $jrc [CONST IR_ROUTER] -endstate IRPAUSE # ROUTER instructions are 32 bits wide set old_dr_value 0x[drscan $jrc 32 $new_dr_value -endstate DRPAUSE] # echo "\tOld router value:\t0x[format %x $old_dr_value]" } # Configure the icepick control register proc icepick_c_setup {jrc} { # send a router write, block is 0, register is 1, value is 0x2100 icepick_c_router $jrc 1 0x0 0x1 0x001000 } # jrc == TAP name for the ICEpick # port == a port number, 0..15 for debug tap, 16..31 for test tap proc icepick_c_tapenable {jrc port} { if { ($port >= 0) && ($port < 16) } { # Debug tap" set tap $port set block 0x2 } elseif { $port < 32 } { # Test tap set tap [expr {$port - 16}] set block 0x1 } else { echo "ERROR: Invalid ICEPick C port number: $port" return } # First CONNECT to the ICEPick # echo "Connecting to ICEPick" icepick_c_connect $jrc # echo "Configuring the ICEpick" icepick_c_setup $jrc # NOTE: it's important not to enter RUN/IDLE state until # done sending these instructions and data to the ICEpick. # And never to enter RESET, which will disable the TAPs. # first enable power and clock for TAP icepick_c_router $jrc 1 $block $tap 0x110048 # TRM states that the register should be read back here, skipped for now # enable debug "default" mode icepick_c_router $jrc 1 $block $tap 0x112048 # TRM states that debug enable and debug mode should be read back and # confirmed - skipped for now # Finally select the tap icepick_c_router $jrc 1 $block $tap 0x112148 # Enter the bypass state irscan $jrc [CONST IR_BYPASS] -endstate RUN/IDLE runtest 10 } # jrc == TAP name for the ICEpick # coreid== core id number 0..15 (not same as port number!) proc icepick_d_set_core_control {jrc coreid value } { icepick_c_router $jrc 1 0x6 $coreid $value } # jrc == TAP name for the ICEpick # port == a port number, 0..15 # Follow the sequence described in # http://processors.wiki.ti.com/images/f/f6/Router_Scan_Sequence-ICEpick-D.pdf proc icepick_d_tapenable {jrc port coreid { value 0x2008 } } { # First CONNECT to the ICEPick icepick_c_connect $jrc icepick_c_setup $jrc # Select the port icepick_c_router $jrc 1 0x2 $port 0x2108 # Set icepick core control for $coreid icepick_d_set_core_control $jrc $coreid $value # Enter the bypass state irscan $jrc [CONST IF_BYPASS] -endstate RUN/IDLE runtest 10 } # This function uses the ICEPick to send a warm system reset proc icepick_c_wreset {jrc} { # send a router write, block is 0, register is 1, value is 0x2100 icepick_c_router $jrc 1 0x0 0x1 0x002101 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # utility fn's for Freescale i.MX series global TARGETNAME set TARGETNAME $_TARGETNAME # rewrite commands of the form below to arm11 mcr... # Data.Set c15:0x042f %long 0x40000015 proc setc15 {regs value} { global TARGETNAME echo [format "set p15 0x%04x, 0x%08x" $regs $value] arm mcr 15 [expr {($regs>>12)&0x7}] [expr {($regs>>0)&0xf}] [expr {($regs>>4)&0xf}] [expr {($regs>>8)&0x7}] $value } proc imx3x_reset {} { # this reset script comes from the Freescale PDK # # http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=IMX35PDK echo "Target Setup: initialize DRAM controller and peripherals" # Data.Set c15:0x01 %long 0x00050078 setc15 0x01 0x00050078 echo "configuring CP15 for enabling the peripheral bus" # Data.Set c15:0x042f %long 0x40000015 setc15 0x042f 0x40000015 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx21.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #use combined on interfaces or targets that can't set TRST/SRST separately # # Hmmm.... should srst_pulls_trst be used here like i.MX27??? reset_config trst_and_srst if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx21 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Note above there is 1 tap # The CPU tap if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0792611f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Create the GDB Target. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx25.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # imx25 config # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx25 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists ETBTAPID] } { set _ETBTAPID $ETBTAPID } else { set _ETBTAPID 0x1b900f0f } jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0x0f -expected-id $_ETBTAPID if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926041 } jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID jtag newtap $_CHIPNAME whatchacallit -irlen 4 -ircapture 0x0 -irmask 0x0 -expected-id 0x0 if { [info exists SDMATAPID] } { set _SDMATAPID $SDMATAPID } else { set _SDMATAPID 0x0882301d } jtag newtap $_CHIPNAME sdma -irlen 5 -expected-id $_SDMATAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN \ -chain-position $_TARGETNAME # trace setup etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx27.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # page 3-34 of "MCIMC27 Multimedia Applications Processor Reference Manual, Rev 0.3" # SRST pulls TRST # # Without setting these options correctly you'll see all sorts # of weird errors, e.g. MOE=0xe, invalid cpsr values, reset # failing, etc. reset_config trst_and_srst srst_pulls_trst if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx27 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Note above there are 2 taps # trace buffer if { [info exists ETBTAPID] } { set _ETBTAPID $ETBTAPID } else { set _ETBTAPID 0x1b900f0f } jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0xf -expected-id $_ETBTAPID # The CPU tap if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926121 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Create the GDB Target. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME # REVISIT what operating environment sets up this virtual address mapping? $_TARGETNAME configure -work-area-virt 0xffff4c00 -work-area-phys 0xffff4c00 \ -work-area-size 0x8000 -work-area-backup 1 # Internal to the chip, there is 45K of SRAM # arm7_9 dcc_downloads enable # trace setup etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx28.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # i.MX28 config file. # based off of the imx21.cfg file. reset_config trst_and_srst #jtag nTRST and nSRST delay adapter srst delay 100 jtag_ntrst_delay 100 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx28 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Note above there is 1 tap # The CPU tap if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x079264f3 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Create the GDB Target. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx31.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # imx31 config # reset_config trst_and_srst srst_gates_jtag adapter srst delay 5 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx31 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07b3601d } if { [info exists SDMATAPID] } { set _SDMATAPID $SDMATAPID } else { set _SDMATAPID 0x2190101d } if { [info exists ETBTAPID] } { set _ETBTAPID $ETBTAPID } else { set _ETBTAPID 0x2b900f0f } #======================================== jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0xf -expected-id $_ETBTAPID # The "SDMA" - <S>mart <DMA> controller debug tap # Based on some IO pins - this can be disabled & removed # See diagram: 6-14 # SIGNAL NAME: # SJC_MOD - controls multiplexer - disables ARM1136 # SDMA_BYPASS - disables SDMA - # # Per ARM: DDI0211J_arm1136_r1p5_trm.pdf - the ARM 1136 as a 5 bit IR register jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUTAPID # No IDCODE for this TAP jtag newtap $_CHIPNAME whatchacallit -irlen 4 -ircapture 0 -irmask 0xf -expected-id 0x0 # Per section 40.17.1, table 40-85 the IR register is 4 bits # But this conflicts with Diagram 6-13, "3bits ir and drs" jtag newtap $_CHIPNAME smda -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_SDMATAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm11 -endian $_ENDIAN -chain-position $_TARGETNAME proc power_restore {} { echo "Sensed power restore. No action." } proc srst_deasserted {} { echo "Sensed nSRST deasserted. No action." } # trace setup ... NOTE, "normal full" mode fudges the real ETMv3.1 mode etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx35.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # imx35 config # reset_config trst_and_srst srst_gates_jtag jtag_ntrst_delay 100 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx35 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07b3601d } if { [info exists SDMATAPID] } { set _SDMATAPID $SDMATAPID } else { set _SDMATAPID 0x0882601d } if { [info exists ETBTAPID] } { set _ETBTAPID $ETBTAPID } else { set _ETBTAPID 0x2b900f0f } #======================================== jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0xf -expected-id $_ETBTAPID jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUTAPID # No IDCODE for this TAP jtag newtap $_CHIPNAME whatchacallit -irlen 4 -ircapture 0 -irmask 0x0 -expected-id 0x0 jtag newtap $_CHIPNAME smda -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_SDMATAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm11 -endian $_ENDIAN -chain-position $_TARGETNAME proc power_restore {} { echo "Sensed power restore. No action." } proc srst_deasserted {} { echo "Sensed nSRST deasserted. No action." } # trace setup ... NOTE, "normal full" mode fudges the real ETMv3.1 mode etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx51.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Freescale i.MX51 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx51 } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x1ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID # SDMA / no IDCODE jtag newtap $_CHIPNAME sdma -irlen 4 -ircapture 0x0 -irmask 0xf # SJC if { [info exists SJC_TAPID] } { set _SJC_TAPID SJC_TAPID } else { set _SJC_TAPID 0x0190c01d } jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x1 -irmask 0x1f \ -expected-id $_SJC_TAPID -ignore-version # GDB target: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # some TCK tycles are required to activate the DEBUG power domain jtag configure $_CHIPNAME.sjc -event post-reset "runtest 100" proc imx51_dbginit {target} { # General Cortex-A8 debug initialisation cortex_a dbginit } $_TARGETNAME configure -event reset-assert-post "imx51_dbginit $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx53.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Freescale i.MX53 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx53 } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x1ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID # SDMA / no IDCODE jtag newtap $_CHIPNAME sdma -irlen 4 -ircapture 0x0 -irmask 0xf # SJC if { [info exists SJC_TAPID] } { set _SJC_TAPID SJC_TAPID } else { set _SJC_TAPID 0x0190d01d } jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x1 -irmask 0x1f \ -expected-id $_SJC_TAPID -ignore-version # GDB target: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # some TCK tycles are required to activate the DEBUG power domain jtag configure $_CHIPNAME.sjc -event post-reset "runtest 100" proc imx53_dbginit {target} { # General Cortex-A8 debug initialisation cortex_a dbginit } $_TARGETNAME configure -event reset-assert-post "imx53_dbginit $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx6.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Freescale i.MX6 series # # Supports 6Q 6D 6QP 6DP 6DL 6S 6SL 6SLL # # Some imx6 chips have Cortex-A7 or an Cortex-M and need special handling # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx6 } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # SDMA / no IDCODE jtag newtap $_CHIPNAME sdma -irlen 4 -ircapture 0x00 -irmask 0x0f # System JTAG Controller # List supported SJC TAPIDs from imx reference manuals: set _SJC_TAPID_6Q 0x0191c01d set _SJC_TAPID_6D 0x0191e01d set _SJC_TAPID_6QP 0x3191c01d set _SJC_TAPID_6DP 0x3191d01d set _SJC_TAPID_6DL 0x0891a01d set _SJC_TAPID_6S 0x0891b01d set _SJC_TAPID_6SL 0x0891f01d set _SJC_TAPID_6SLL 0x088c201d # Allow external override of the first SJC TAPID if { [info exists SJC_TAPID] } { set _SJC_TAPID $SJC_TAPID } else { set _SJC_TAPID $_SJC_TAPID_6Q } jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x01 -irmask 0x1f \ -ignore-version \ -expected-id $_SJC_TAPID \ -expected-id $_SJC_TAPID_6QP \ -expected-id $_SJC_TAPID_6DP \ -expected-id $_SJC_TAPID_6D \ -expected-id $_SJC_TAPID_6DL \ -expected-id $_SJC_TAPID_6S \ -expected-id $_SJC_TAPID_6SL \ -expected-id $_SJC_TAPID_6SLL # GDB target: Cortex-A9, using DAP, configuring only one core # Base addresses of cores: # core 0 - 0x82150000 # core 1 - 0x82152000 # core 2 - 0x82154000 # core 3 - 0x82156000 set _TARGETNAME $_CHIPNAME.cpu.0 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x82150000 # some TCK cycles are required to activate the DEBUG power domain jtag configure $_CHIPNAME.sjc -event post-reset "runtest 100" proc imx6_dbginit {target} { # General Cortex-A8/A9 debug initialisation cortex_a dbginit } # Slow speed to be sure it will work adapter speed 1000 $_TARGETNAME configure -event reset-start { adapter speed 1000 } $_TARGETNAME configure -event reset-assert-post "imx6_dbginit $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx6sx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Freescale i.MX6SoloX # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx6sx } # 2x CoreSight Debug Access Port for Cortex-M4 and Cortex-A9 if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu_m4 -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap_m4 -chain-position $_CHIPNAME.cpu_m4 jtag newtap $_CHIPNAME cpu_a9 -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap_a9 -chain-position $_CHIPNAME.cpu_a9 # SDMA / no IDCODE jtag newtap $_CHIPNAME sdma -irlen 4 -ircapture 0x00 -irmask 0x0f # System JTAG Controller if { [info exists SJC_TAPID] } { set _SJC_TAPID $SJC_TAPID } else { set _SJC_TAPID 0x0891c01d } jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x01 -irmask 0x1f \ -expected-id $_SJC_TAPID -ignore-version # Cortex-A9 (boot core) target create $_CHIPNAME.cpu_a9 cortex_a -dap $_CHIPNAME.dap_a9 \ -coreid 0 -dbgbase 0x82150000 # Cortex-M4 (default off) target create $_CHIPNAME.cpu_m4 cortex_m -dap $_CHIPNAME.dap_m4 \ -ap-num 0 -defer-examine # AHB mem-ap target target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap_a9 -ap-num 0 # Default target is Cortex-A9 targets $_CHIPNAME.cpu_a9 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx6ul.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Freescale i.MX6UltraLite series: 6UL 6ULL 6ULZ # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx6ul } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # SDMA / no IDCODE jtag newtap $_CHIPNAME sdma -irlen 4 -ircapture 0x00 -irmask 0x0f # System JTAG Controller set _SJC_TAPID_6UL 0x0891d01d set _SJC_TAPID_6ULL 0x0891e01d set _SJC_TAPID_6ULZ 0x1891e01d # Allow external override of the first SJC TAPID if { [info exists SJC_TAPID] } { set _SJC_TAPID $SJC_TAPID } else { set _SJC_TAPID $_SJC_TAPID_6UL } jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x01 -irmask 0x1f \ -ignore-version \ -expected-id $_SJC_TAPID \ -expected-id $_SJC_TAPID_6ULL \ -expected-id $_SJC_TAPID_6ULZ \ # Create DAP dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # Main AHB bus target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 # Cortex-A7 single core set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap -dbgbase 0x82130000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx7.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx7 } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # # Cortex-A7 target # # GDB target: Cortex-A7, using DAP, configuring only one core # Base addresses of cores: # core 0 - 0x80070000 # core 1 - 0x80072000 set _TARGETNAME $_CHIPNAME.cpu_a7 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME.0 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80070000 target create $_TARGETNAME.1 cortex_a -dap $_CHIPNAME.dap \ -coreid 1 -dbgbase 0x80072000 -defer-examine # # Cortex-M4 target # set _TARGETNAME_2 $_CHIPNAME.cpu_m4 target create $_TARGETNAME_2 cortex_m -dap $_CHIPNAME.dap -ap-num 4 \ -defer-examine # # AHB mem-ap target # target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 targets $_TARGETNAME.0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx7ulp.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # NXP i.MX7ULP: Cortex-A7 + Cortex-M4 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx7ulp } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { # TAPID is from FreeScale! set _DAP_TAPID 0x188e101d } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # Cortex-A7 target create $_CHIPNAME.cpu_a7 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80030000 # Cortex-M4 # Boots by default so don't defer examination target create $_CHIPNAME.cpu_m4 cortex_m -dap $_CHIPNAME.dap -ap-num 3 # AHB main soc bus target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 # Default is Cortex-A7 targets $_CHIPNAME.cpu_a7 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx8m.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # configuration file for NXP i.MX8M family of SoCs # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx8m } if { [info exists CHIPCORES] } { set _cores $CHIPCORES } else { set _cores 1 } # CoreSight Debug Access Port if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } # the DAP tap jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.a53 set _CTINAME $_CHIPNAME.cti set DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} set CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} for { set _core 0 } { $_core < $_cores } { incr _core } { cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [lindex $CTIBASE $_core] set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core -coreid $_core" if { $_core != 0 } { # non-boot core examination may fail set _command "$_command -defer-examine" set _smp_command "$_smp_command $_TARGETNAME.$_core" } else { set _command "$_command -rtos hwthread" set _smp_command "target smp $_TARGETNAME.$_core" } eval $_command } eval $_smp_command # declare the auxiliary Cortex-M4 core on AP #4 target create ${_CHIPNAME}.m4 cortex_m -dap ${_CHIPNAME}.dap -ap-num 4 \ -defer-examine # AHB-AP for direct access to soc bus target create ${_CHIPNAME}.ahb mem_ap -dap ${_CHIPNAME}.dap -ap-num 0 # default target is A53 core 0 targets $_TARGETNAME.0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/imx8qm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # NXP i.MX8QuadMax # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME imx8qm } # CoreSight Debug Access Port (DAP) if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { # TAPID is from FreeScale! set _DAP_TAPID 0x1890101d } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # AXI: Main SOC bus on AP #0 target create ${_CHIPNAME}.axi mem_ap -dap ${_CHIPNAME}.dap -ap-num 0 # 4x Cortex-A53 on AP #6 set _A53_DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} set _A53_CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} cti create $_CHIPNAME.a53_cti.0 -dap $_CHIPNAME.dap \ -ap-num 6 -baseaddr [lindex $_A53_CTIBASE 0] cti create $_CHIPNAME.a53_cti.1 -dap $_CHIPNAME.dap \ -ap-num 6 -baseaddr [lindex $_A53_CTIBASE 1] cti create $_CHIPNAME.a53_cti.2 -dap $_CHIPNAME.dap \ -ap-num 6 -baseaddr [lindex $_A53_CTIBASE 2] cti create $_CHIPNAME.a53_cti.3 -dap $_CHIPNAME.dap \ -ap-num 6 -baseaddr [lindex $_A53_CTIBASE 3] target create $_CHIPNAME.a53.0 aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.a53_cti.0 -dbgbase [lindex $_A53_DBGBASE 0] target create $_CHIPNAME.a53.1 aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.a53_cti.1 -dbgbase [lindex $_A53_DBGBASE 1] -defer-examine target create $_CHIPNAME.a53.2 aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.a53_cti.2 -dbgbase [lindex $_A53_DBGBASE 2] -defer-examine target create $_CHIPNAME.a53.3 aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.a53_cti.3 -dbgbase [lindex $_A53_DBGBASE 3] -defer-examine # 2x Cortex-A72 on AP #6 set _A72_DBGBASE {0x80210000 0x80310000} set _A72_CTIBASE {0x80220000 0x80220000} cti create $_CHIPNAME.a72_cti.0 -dap $_CHIPNAME.dap \ -ap-num 6 -baseaddr [lindex $_A72_CTIBASE 0] cti create $_CHIPNAME.a72_cti.1 -dap $_CHIPNAME.dap \ -ap-num 6 -baseaddr [lindex $_A72_CTIBASE 1] target create $_CHIPNAME.a72.0 aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.a72_cti.0 -dbgbase [lindex $_A72_DBGBASE 0] -defer-examine target create $_CHIPNAME.a72.1 aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.a72_cti.1 -dbgbase [lindex $_A72_DBGBASE 1] -defer-examine # All Cortex-A in SMP target smp \ $_CHIPNAME.a53.0 \ $_CHIPNAME.a53.1 \ $_CHIPNAME.a53.2 \ $_CHIPNAME.a53.3 \ $_CHIPNAME.a72.0 \ $_CHIPNAME.a72.1 # SCU: Cortex-M4 core # always running imx SC firmware target create ${_CHIPNAME}.scu cortex_m -dap ${_CHIPNAME}.dap -ap-num 1 # AHB from SCU perspective target create ${_CHIPNAME}.scu_ahb mem_ap -dap ${_CHIPNAME}.dap -ap-num 4 # Cortex-M4 M4_0 core on AP #2 (default off) target create ${_CHIPNAME}.m4_0 cortex_m -dap ${_CHIPNAME}.dap -ap-num 2 \ -defer-examine # Cortex-M4 M4_1 core on AP #3 (default off) target create ${_CHIPNAME}.m4_1 cortex_m -dap ${_CHIPNAME}.dap -ap-num 3 \ -defer-examine # Debug APB bus target create ${_CHIPNAME}.apb mem_ap -dap ${_CHIPNAME}.dap -ap-num 6 # Default target is boot core a53.0 targets $_CHIPNAME.a53.0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/infineon/tle987x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Infineon TLE987x family (Arm Cortex-M3 @ up to 40 MHz) # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME tle987x } source [find target/swj-dp.tcl] if { [info exists CPU_SWD_TAPID] } { set _CPU_SWD_TAPID $CPU_SWD_TAPID } else { set _CPU_SWD_TAPID 0x2BA01477 } if { [using_jtag] } { # JTAG not supported, only SWD set _CPU_TAPID 0 } else { set _CPU_TAPID $_CPU_SWD_TAPID } swj_newdap $_CHIPNAME dap -irlen 4 -expected-id $_CPU_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { ![using_hla] } { cortex_m reset_config sysresetreq } adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/is5114.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for Insilica IS-5114 # AKA: Atmel AT76C114 - an ARM946 chip # ATMEL sold his product line to Insilica... if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME is5114 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a little endian set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # Force an error until we get a good number. set _CPUTAPID 0xffffffff } # jtag speed. We need to stick to 16kHz until we've finished reset. adapter speed 16 reset_config trst_and_srst # Do not specify a tap id here... jtag newtap $_CHIPNAME unknown1 -irlen 8 -ircapture 0x01 -irmask 1 # This is the "arm946" chip. jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x0e -irmask 0xf jtag newtap $_CHIPNAME unknown2 -irlen 5 -ircapture 1 -irmask 1 #arm946e-s and set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-start { adapter speed 16 } $_TARGETNAME configure -event reset-init { # We can increase speed now that we know the target is halted. adapter speed 3000 } $_TARGETNAME configure -work-area-phys 0x50000000 -work-area-size 16384 -work-area-backup 1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ixp42x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #xscale ixp42x CPU if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ixp42x } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a bigendian set _ENDIAN big } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x19274013 } set _CPUTAPID2 0x19275013 set _CPUTAPID3 0x19277013 set _CPUTAPID4 0x29274013 set _CPUTAPID5 0x29275013 set _CPUTAPID6 0x29277013 jtag newtap $_CHIPNAME cpu -irlen 7 -ircapture 0x1 -irmask 0x7f -expected-id $_CPUTAPID -expected-id $_CPUTAPID2 -expected-id $_CPUTAPID3 -expected-id $_CPUTAPID4 -expected-id $_CPUTAPID5 -expected-id $_CPUTAPID6 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME xscale -endian $_ENDIAN -chain-position $_TARGETNAME # register constants for IXP42x SDRAM controller global IXP425_SDRAM_IR_MODE_SET_CAS2_CMD global IXP425_SDRAM_IR_MODE_SET_CAS3_CMD set IXP425_SDRAM_IR_MODE_SET_CAS2_CMD 0x0000 set IXP425_SDRAM_IR_MODE_SET_CAS3_CMD 0x0001 global IXP42x_SDRAM_CL3 global IXP42x_SDRAM_CL2 set IXP42x_SDRAM_CL3 0x0008 set IXP42x_SDRAM_CL2 0x0000 global IXP42x_SDRAM_8MB_2Mx32_1BANK global IXP42x_SDRAM_16MB_2Mx32_2BANK global IXP42x_SDRAM_16MB_4Mx16_1BANK global IXP42x_SDRAM_32MB_4Mx16_2BANK global IXP42x_SDRAM_32MB_8Mx16_1BANK global IXP42x_SDRAM_64MB_8Mx16_2BANK global IXP42x_SDRAM_64MB_16Mx16_1BANK global IXP42x_SDRAM_128MB_16Mx16_2BANK global IXP42x_SDRAM_128MB_32Mx16_1BANK global IXP42x_SDRAM_256MB_32Mx16_2BANK set IXP42x_SDRAM_8MB_2Mx32_1BANK 0x0030 set IXP42x_SDRAM_16MB_2Mx32_2BANK 0x0031 set IXP42x_SDRAM_16MB_4Mx16_1BANK 0x0032 set IXP42x_SDRAM_32MB_4Mx16_2BANK 0x0033 set IXP42x_SDRAM_32MB_8Mx16_1BANK 0x0010 set IXP42x_SDRAM_64MB_8Mx16_2BANK 0x0011 set IXP42x_SDRAM_64MB_16Mx16_1BANK 0x0012 set IXP42x_SDRAM_128MB_16Mx16_2BANK 0x0013 set IXP42x_SDRAM_128MB_32Mx16_1BANK 0x0014 set IXP42x_SDRAM_256MB_32Mx16_2BANK 0x0015 # helper function to init SDRAM on IXP42x. # SDRAM_CFG: one of IXP42X_SDRAM_xxx # REFRESH: refresh counter reload value (integer) # CASLAT: 2 or 3 proc ixp42x_init_sdram { SDRAM_CFG REFRESH CASLAT } { switch $CASLAT { 2 { set SDRAM_CFG [expr {$SDRAM_CFG | $::IXP42x_SDRAM_CL2} ] set CASCMD $::IXP425_SDRAM_IR_MODE_SET_CAS2_CMD } 3 { set SDRAM_CFG [expr {$SDRAM_CFG | $::IXP42x_SDRAM_CL3} ] set CASCMD $::IXP425_SDRAM_IR_MODE_SET_CAS3_CMD } default { error [format "unsupported cas latency \"%s\" " $CASLAT] } } echo [format "\tIXP42x SDRAM Config: 0x%x, Refresh %d " $SDRAM_CFG $REFRESH] mww 0xCC000000 $SDRAM_CFG ;# SDRAM_CFG: 0x2A: 64MBit, CL3 mww 0xCC000004 0 ;# disable refresh mww 0xCC000008 3 ;# NOP sleep 100 mww 0xCC000004 $REFRESH ;# set refresh counter mww 0xCC000008 2 ;# Precharge All Banks sleep 100 mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 4 ;# Auto Refresh mww 0xCC000008 $CASCMD ;# Mode Select CL2/CL3 } proc ixp42x_set_bigendian { } { reg XSCALE_CTRL 0xF8 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/k1921vk01t.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # K1921VK01T # http://niiet.ru/chips/nis?id=354 source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME k1921vk01t } set _ENDIAN little # Work-area is a space in RAM used for flash programming if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x10000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x4ba00477 } { # SWD IDCODE set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.flash niietcm4 0 0 0 0 $_TARGETNAME adapter speed 2000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/k40.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Freescale Kinetis K40 devices # set CHIPNAME k40 source [find target/kx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/k60.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Freescale Kinetis K60 devices # set CHIPNAME k60 source [find target/kx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ke0x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Freescale Kinetis KE0x and KEAx series devices # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ke } # Work-area is a space in RAM used for flash programming # By default use 1kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x400 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0bc11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME kinetis_ke 0 0 0 0 $_TARGETNAME adapter speed 1000 reset_config srst_nogate if {![using_hla]} { # It is important that "kinetis_ke mdm check_security" is called for # 'examine-end' event and not 'eximine-start'. Calling it in 'examine-start' # causes "kinetis_ke mdm check_security" to fail the first time openocd # calls it when it tries to connect after the CPU has been power-cycled. $_CHIPNAME.cpu configure -event examine-end { kinetis_ke mdm check_security } # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ke1xf.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # NXP (Freescale) Kinetis KE1xF devices # set CHIPNAME ke source [find target/kx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ke1xz.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # NXP (Freescale) Kinetis KE1xZ devices # set CHIPNAME ke source [find target/klx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/kl25.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Freescale Kinetis KL25 devices # set CHIPNAME kl25 source [find target/klx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/kl46.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Freescale Kinetis KL46 devices # set CHIPNAME kl46 source [find target/klx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/klx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # NXP (former Freescale) Kinetis KL series devices # Also used for Cortex-M0+ equipped members of KVx and KE1xZ series # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME klx } # Work-area is a space in RAM used for flash programming # By default use 1KiB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x400 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0bc11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.pflash flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME kinetis create_banks # Table 5-1. Clock Summary of KL25 Sub-Family Reference Manual # specifies up to 1MHz for VLPR mode and up to 24MHz for run mode; # Table 17 of Sub-Family Data Sheet rev4 lists 25MHz as the maximum frequency. adapter speed 1000 reset_config srst_nogate if {[using_hla]} { echo "" echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" echo " Kinetis MCUs have a MDM-AP dedicated mainly to MCU security related functions." echo " A high level adapter (like a ST-Link) you are currently using cannot access" echo " the MDM-AP, so commands like 'mdm mass_erase' are not available in your" echo " configuration. Also security locked state of the device will not be reported." echo "" echo " Be very careful as you can lock the device though there is no way to unlock" echo " it without mass erase. Don't set write protection on the first block." echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" echo "" } else { # Detect secured MCU $_TARGETNAME configure -event examine-fail { kinetis mdm check_security } # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } # Disable watchdog not to disturb OpenOCD algorithms running on MCU # (e.g. armv7m_checksum_memory() in verify_image) # Flash driver also disables watchdog before FTFA flash programming. $_TARGETNAME configure -event reset-init { kinetis disable_wdog } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ks869x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # ARM920T CPU if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ks869x } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x00922f0f } adapter speed 6000 # jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm920t -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x20000 -work-area-size 0x20000 -work-area-backup 0 # speed up memory downloads arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/kx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # NXP (former Freescale) Kinetis Kx series devices # Also used for Cortex-M4 equipped members of KVx and KE1xF series # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME kx } # Work-area is a space in RAM used for flash programming # By default use 4kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.pflash flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME kinetis create_banks adapter speed 1000 reset_config srst_nogate if {[using_hla]} { echo "" echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" echo " Kinetis MCUs have a MDM-AP dedicated mainly to MCU security related functions." echo " A high level adapter (like a ST-Link) you are currently using cannot access" echo " the MDM-AP, so commands like 'mdm mass_erase' are not available in your" echo " configuration. Also security locked state of the device will not be reported." echo " Expect problems connecting to a blank device without boot ROM." echo "" echo " Be very careful as you can lock the device though there is no way to unlock" echo " it without mass erase. Don't set write protection on the first block." echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" echo "" } else { # Detect secured MCU or boot lock-up in RESET/WDOG loop $_TARGETNAME configure -event examine-fail { kinetis mdm check_security } # During RESET/WDOG loop the target is sometimes falsely examined $_TARGETNAME configure -event examine-end { kinetis mdm check_security } # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } # Disable watchdog not to disturb OpenOCD algorithms running on MCU # (e.g. armv7m_checksum_memory() in verify_image) # Flash driver also disables watchdog before FTFA flash programming. $_TARGETNAME configure -event reset-init { kinetis disable_wdog } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc11xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC11xx Cortex-M0 with at least 1kB SRAM set CHIPNAME lpc11xx set CHIPSERIES lpc1100 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x400 } source [find target/lpc1xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc12xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC12xx Cortex-M0 with at least 4kB SRAM set CHIPNAME lpc12xx set CHIPSERIES lpc1200 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x1000 } source [find target/lpc1xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc13xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC13xx Cortex-M3 with at least 4kB SRAM set CHIPNAME lpc13xx set CHIPSERIES lpc1300 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x1000 } source [find target/lpc1xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc17xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC17xx Cortex-M3 with at least 8kB SRAM set CHIPNAME lpc17xx set CHIPSERIES lpc1700 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x2000 } source [find target/lpc1xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc1850.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/swj-dp.tcl] adapter speed 500 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lpc1850 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # # M3 JTAG mode TAP # if { [info exists M3_JTAG_TAPID] } { set _M3_JTAG_TAPID $M3_JTAG_TAPID } else { set _M3_JTAG_TAPID 0x4ba00477 } swj_newdap $_CHIPNAME m3 -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_M3_JTAG_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.m3 set _TARGETNAME $_CHIPNAME.m3 target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc1xxx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Main file for NXP LPC1xxx/LPC40xx series Cortex-M0/0+/3/4F parts # # !!!!!! # # This file should not be included directly, rather by the lpc11xx.cfg, # lpc13xx.cfg, lpc17xx.cfg, etc. which set the needed variables to the # appropriate values. # # !!!!!! # LPC8xx chips support only SWD transport. # LPC11xx chips support only SWD transport. # LPC12xx chips support only SWD transport. # LPC11Uxx chips support only SWD transports. # LPC13xx chips support only SWD transports. # LPC17xx chips support both JTAG and SWD transports. # LPC40xx chips support both JTAG and SWD transports. # Adapt based on what transport is active. source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { error "CHIPNAME not set. Please do not include lpc1xxx.cfg directly, but the specific chip configuration file (lpc11xx.cfg, lpc13xx.cfg, lpc17xx.cfg, etc)." } if { [info exists CHIPSERIES] } { # Validate chip series is supported if { $CHIPSERIES != "lpc800" && $CHIPSERIES != "lpc1100" && $CHIPSERIES != "lpc1200" && $CHIPSERIES != "lpc1300" && $CHIPSERIES != "lpc1700" && $CHIPSERIES != "lpc4000" } { error "Unsupported LPC1xxx chip series specified." } set _CHIPSERIES $CHIPSERIES } else { error "CHIPSERIES not set. Please do not include lpc1xxx.cfg directly, but the specific chip configuration file (lpc11xx.cfg, lpc13xx.cfg, lpc17xx.cfg, etc)." } # After reset, the chip is clocked by an internal RC oscillator. # When board-specific code (reset-init handler or device firmware) # configures another oscillator and/or PLL0, set CCLK to match; if # you don't, then flash erase and write operations may misbehave. # (The ROM code doing those updates cares about core clock speed...) # CCLK is the core clock frequency in KHz if { [info exists CCLK] } { # Allow user override set _CCLK $CCLK } else { # LPC8xx/LPC11xx/LPC12xx/LPC13xx use a 12MHz one, LPC17xx uses a 4MHz one(except for LPC177x/8x,LPC407x/8x) if { $_CHIPSERIES == "lpc800" || $_CHIPSERIES == "lpc1100" || $_CHIPSERIES == "lpc1200" || $_CHIPSERIES == "lpc1300" } { set _CCLK 12000 } elseif { $_CHIPSERIES == "lpc1700" || $_CHIPSERIES == "lpc4000" } { set _CCLK 4000 } } if { [info exists CPUTAPID] } { # Allow user override set _CPUTAPID $CPUTAPID } else { # LPC8xx/LPC11xx/LPC12xx use a Cortex-M0/M0+ core, LPC13xx/LPC17xx use a Cortex-M3 core, LPC40xx use a Cortex-M4F core. if { $_CHIPSERIES == "lpc800" || $_CHIPSERIES == "lpc1100" || $_CHIPSERIES == "lpc1200" } { set _CPUTAPID 0x0bb11477 } elseif { $_CHIPSERIES == "lpc1300" || $_CHIPSERIES == "lpc1700" || $_CHIPSERIES == "lpc4000" } { if { [using_jtag] } { set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } } if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { error "WORKAREASIZE is not set. The $CHIPNAME part is available in several Flash and RAM size configurations. Please set WORKAREASIZE." } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap # The LPC11xx devices have 2/4/8kB of SRAM in the ARMv7-M "Code" area (at 0x10000000) # The LPC12xx devices have 4/8kB of SRAM in the ARMv7-M "Code" area (at 0x10000000) # The LPC11Uxx devices have 4/6/8kB of SRAM in the ARMv7-M "Code" area (at 0x10000000) # The LPC13xx devices have 4/8kB of SRAM in the ARMv7-M "Code" area (at 0x10000000) # The LPC17xx devices have 8/16/32/64kB of SRAM in the ARMv7-M "Code" area (at 0x10000000) # The LPC40xx devices have 16/32/64kB of SRAM in the ARMv7-ME "Code" area (at 0x10000000) $_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size $_WORKAREASIZE # The LPC11xx devies have 8/16/24/32/48/56/64kB of flash memory (at 0x00000000) # The LPC12xx devies have 32/48/64/80/96/128kB of flash memory (at 0x00000000) # The LPC11Uxx devies have 16/24/32/40/48/64/96/128kB of flash memory (at 0x00000000) # The LPC13xx devies have 8/16/32kB of flash memory (at 0x00000000) # The LPC17xx devies have 32/64/128/256/512kB of flash memory (at 0x00000000) # The LPC40xx devies have 64/128/256/512kB of flash memory (at 0x00000000) # # All are compatible with the "lpc1700" variant of the LPC2000 flash driver # (same cmd51 destination boundary alignment, and all three support 256 byte # transfers). # # flash bank <name> lpc2000 <base> <size> 0 0 <target#> <variant> <clock> [calc checksum] [iap entry] set _IAP_ENTRY 0 if { [info exists IAP_ENTRY] } { set _IAP_ENTRY $IAP_ENTRY } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME lpc2000 0x0 0 0 0 $_TARGETNAME \ auto $_CCLK calc_checksum $_IAP_ENTRY if { $_CHIPSERIES == "lpc800" || $_CHIPSERIES == "lpc1100" || $_CHIPSERIES == "lpc1200" || $_CHIPSERIES == "lpc1300" } { # Do not remap 0x0000-0x0200 to anything but the flash (i.e. select # "User Flash Mode" where interrupt vectors are _not_ remapped, # and reside in flash instead). # # Table 8. System memory remap register (SYSMEMREMAP, address 0x4004 8000) bit description # Bit Symbol Value Description # 1:0 MAP System memory remap # 0x0 Boot Loader Mode. Interrupt vectors are re-mapped to Boot ROM. # 0x1 User RAM Mode. Interrupt vectors are re-mapped to Static RAM. # 0x2 User Flash Mode. Interrupt vectors are not re-mapped and reside in Flash. # 31:2 - - Reserved. $_TARGETNAME configure -event reset-init { mww 0x40048000 0x02 } } elseif { $_CHIPSERIES == "lpc1700" || $_CHIPSERIES == "lpc4000" } { # Do not remap 0x0000-0x0020 to anything but the flash (i.e. select # "User Flash Mode" where interrupt vectors are _not_ remapped, # and reside in flash instead). # # See Table 612. Memory Mapping Control register (MEMMAP - 0x400F C040) bit description # Bit Symbol Value Description Reset # value # 0 MAP Memory map control. 0 # 0 Boot mode. A portion of the Boot ROM is mapped to address 0. # 1 User mode. The on-chip Flash memory is mapped to address 0. # 31:1 - Reserved. The value read from a reserved bit is not defined. NA # # http://ics.nxp.com/support/documents/microcontrollers/?scope=LPC1768&type=user $_TARGETNAME configure -event reset-init { mww 0x400FC040 0x01 } } # Run with *real slow* clock by default since the # boot rom could have been playing with the PLL, so # we have no idea what clock the target is running at. adapter speed 10 # delays on reset lines adapter srst delay 200 if {[using_jtag]} { jtag_ntrst_delay 200 } # LPC8xx (Cortex-M0+ core) support SYSRESETREQ # LPC11xx/LPC12xx (Cortex-M0 core) support SYSRESETREQ # LPC13xx/LPC17xx (Cortex-M3 core) support SYSRESETREQ # LPC40xx (Cortex-M4F core) support SYSRESETREQ if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc2103.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC2103 ARM7TDMI-S with 32kB flash and 8kB SRAM, clocked with 12MHz crystal source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2103 {core_freq_khz adapter_freq_khz} { # 32kB flash and 8kB SRAM # setup_lpc2xxx <chip_name> <cputapid> <flash_size> <flash_variant> <workarea_size> <core_freq_khz> <adapter_freq_khz> setup_lpc2xxx lpc2103 0x4f1f0f0f 0x8000 lpc2000_v2 0x2000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." # setup_lpc2103 <core_freq_khz> <adapter_freq_khz> setup_lpc2103 12000 1500 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc2124.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC2124 ARM7TDMI-S with 256kB flash and 16kB SRAM, clocked with 12MHz crystal source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2124 {core_freq_khz adapter_freq_khz} { # 256kB flash and 16kB SRAM # setup_lpc2xxx <chip_name> <cputapid> <flash_size> <flash_variant> <workarea_size> <core_freq_khz> <adapter_freq_khz> setup_lpc2xxx lpc2124 0x4f1f0f0f 0x40000 lpc2000_v1 0x4000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." # setup_lpc2124 <core_freq_khz> <adapter_freq_khz> setup_lpc2124 12000 1500 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc2129.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC2129 ARM7TDMI-S with 256kB flash and 16kB SRAM, clocked with 12MHz crystal source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2129 {core_freq_khz adapter_freq_khz} { # 256kB flash and 16kB SRAM # setup_lpc2xxx <chip_name> <cputapid> <flash_size> <flash_variant> <workarea_size> <core_freq_khz> <adapter_freq_khz> setup_lpc2xxx lpc2129 0xcf1f0f0f 0x40000 lpc2000_v1 0x4000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." # setup_lpc2129 <core_freq_khz> <adapter_freq_khz> setup_lpc2129 12000 1500 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc2148.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC2148 ARM7TDMI-S with 512kB flash (12kB used by bootloader) and 40kB SRAM (8kB for USB DMA), clocked with 12MHz crystal source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2148 {core_freq_khz adapter_freq_khz} { # 500kB flash and 32kB SRAM # setup_lpc2xxx <chip_name> <cputapid> <flash_size> <flash_variant> <workarea_size> <core_freq_khz> <adapter_freq_khz> setup_lpc2xxx lpc2148 "0x3f0f0f0f 0x4f1f0f0f" 0x7d000 lpc2000_v2 0x8000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." # setup_lpc2148 <core_freq_khz> <adapter_freq_khz> setup_lpc2148 12000 1500 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc2294.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC2294 ARM7TDMI-S with 256kB flash and 16kB SRAM, clocked with 12MHz crystal source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2294 {core_freq_khz adapter_freq_khz} { # 256kB flash and 16kB SRAM # setup_lpc2xxx <chip_name> <cputapid> <flash_size> <flash_variant> <workarea_size> <core_freq_khz> <adapter_freq_khz> # !! TAPID unknown !! setup_lpc2xxx lpc2294 0xffffffff 0x40000 lpc2000_v1 0x4000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 12MHz crystal echo "Warning - assuming default core clock 12MHz! Flashing may fail if actual core clock is different." # setup_lpc2294 <core_freq_khz> <adapter_freq_khz> setup_lpc2294 12000 1500 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc2378.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC2378 ARM7TDMI-S with 512kB flash (8kB used by bootloader) and 56kB SRAM (16kB for ETH, 8kB for DMA), clocked with 4MHz internal oscillator source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2378 {core_freq_khz adapter_freq_khz} { # 504kB flash and 32kB SRAM # setup_lpc2xxx <chip_name> <cputapid> <flash_size> <flash_variant> <workarea_size> <core_freq_khz> <adapter_freq_khz> setup_lpc2xxx lpc2378 0x4f1f0f0f 0x7e000 lpc2000_v2 0x8000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 4MHz internal oscillator echo "Warning - assuming default core clock 4MHz! Flashing may fail if actual core clock is different." # setup_lpc2378 <core_freq_khz> <adapter_freq_khz> setup_lpc2378 4000 500 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc2460.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC2460 ARM7TDMI-S with 98kB SRAM (16kB for ETH, 16kB for DMA, 2kB for RTC), clocked with 4MHz internal oscillator source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2460 {core_freq_khz adapter_freq_khz} { # 64kB SRAM # setup_lpc2xxx <chip_name> <cputapid> <flash_size> <flash_variant> <workarea_size> <core_freq_khz> <adapter_freq_khz> setup_lpc2xxx lpc2460 0x4f1f0f0f 0 lpc2000_v2 0x10000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 4MHz internal oscillator echo "Warning - assuming default core clock 4MHz! Flashing may fail if actual core clock is different." # setup_lpc2460 <core_freq_khz> <adapter_freq_khz> setup_lpc2460 4000 500 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc2478.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC2478 ARM7TDMI-S with 512kB flash (8kB used by bootloader) and 98kB SRAM (16kB for ETH, 16kB for DMA, 2kB for RTC), clocked with 4MHz internal oscillator source [find target/lpc2xxx.cfg] # parameters: # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2478 {core_freq_khz adapter_freq_khz} { # 504kB flash and 64kB SRAM # setup_lpc2xxx <chip_name> <cputapid> <flash_size> <flash_variant> <workarea_size> <core_freq_khz> <adapter_freq_khz> setup_lpc2xxx lpc2478 0x4f1f0f0f 0x7e000 lpc2000_v2 0x10000 $core_freq_khz $adapter_freq_khz } proc init_targets {} { # default to core clocked with 4MHz internal oscillator echo "Warning - assuming default core clock 4MHz! Flashing may fail if actual core clock is different." # setup_lpc2478 <core_freq_khz> <adapter_freq_khz> setup_lpc2478 4000 500 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc2900.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lpc2900 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0596802B } if { [info exists HAS_ETB] } { } else { # Set default (no ETB). # Show a warning, because this should have been configured explicitly. set HAS_ETB 0 # TODO: warning? } if { [info exists ETBTAPID] } { set _ETBTAPID $ETBTAPID } else { set _ETBTAPID 0x1B900F0F } # TRST and SRST both exist, and can be controlled independently reset_config trst_and_srst separate # Define the _TARGETNAME set _TARGETNAME $_CHIPNAME.cpu # Include the ETB tap controller if asked for. # Has to be done manually for newer devices (not an "old" LPC2917/2919). if { $HAS_ETB == 1 } { # Clear the HAS_ETB flag. Must be set again for a new tap in the chain. set HAS_ETB 0 # Add the ETB tap controller and the ARM9 core debug tap jtag newtap $_CHIPNAME etb -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_ETBTAPID jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Create the ".cpu" target target create $_TARGETNAME arm966e -endian little -chain-position $_TARGETNAME # Configure ETM and ETB etm config $_TARGETNAME 8 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb } else { # Add the ARM9 core debug tap jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Create the ".cpu" target target create $_TARGETNAME arm966e -endian little -chain-position $_TARGETNAME } arm7_9 dbgrq enable arm7_9 dcc_downloads enable # Flash bank configuration: # Flash: flash bank lpc2900 0 0 0 0 <target#> <flash clock (CLK_SYS_FMC) in kHz> # Flash base address, total flash size, and number of sectors are all configured automatically. set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME lpc2900 0 0 0 0 $_TARGETNAME $FLASH_CLOCK ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc2xxx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Common setup for the LPC2xxx parts # parameters: # - chip_name - name of the chip, e.g. lpc2103 # - cputapids - TAP IDs of the core, should be quoted if more than one, e.g. 0x4f1f0f0f or "0x3f0f0f0f 0x4f1f0f0f" # - flash_size - size of on-chip flash (available for code, not including the bootloader) in bytes, e.g. 0x8000 # - flash_variant - "type" of LPC2xxx device, lpc2000_v1 (LPC22xx and older LPC21xx) or lpc2000_v2 (LPC213x, LPC214x, LPC210[123], LPC23xx and LPC24xx) # - workarea_size - size of work-area in RAM for flashing procedures, must not exceed the size of RAM available at 0x40000000, e.g. 0x2000 # - core_freq_khz - frequency of core in kHz during flashing, usually equal to connected crystal or internal oscillator, e.g. 12000 # - adapter_freq_khz - frequency of debug adapter in kHz, should be 8x slower than core_freq_khz, e.g. 1000 proc setup_lpc2xxx {chip_name cputapids flash_size flash_variant workarea_size core_freq_khz adapter_freq_khz} { reset_config trst_and_srst # reset delays adapter srst delay 100 jtag_ntrst_delay 100 adapter speed $adapter_freq_khz foreach i $cputapids { append expected_ids "-expected-id " $i " " } eval "jtag newtap $chip_name cpu -irlen 4 -ircapture 0x1 -irmask 0xf $expected_ids" global _TARGETNAME set _TARGETNAME $chip_name.cpu target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x40000000 -work-area-size $workarea_size -work-area-backup 0 if { $flash_size > 0 } { # flash bank <name> lpc2000 <base> <size> 0 0 <target#> <variant> <clock> [calc checksum] set _FLASHNAME $chip_name.flash flash bank $_FLASHNAME lpc2000 0x0 $flash_size 0 0 $_TARGETNAME $flash_variant $core_freq_khz calc_checksum } } proc init_targets {} { # FIX!!! read out CPUTAPID here and choose right setup. In addition to the # CPUTAPID some querying of the target would be required. return -error "This is a generic LPC2xxx configuration file, use a specific target file." } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc3131.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: NXP lpc3131 ###################################### if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lpc3131 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # ARM926EJS core if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926f0f } # Scan Tap # Wired to separate STDO pin on the lpc3131, externally muxed to TDO on ea3131 module # JTAGSEL pin must be 0 to activate, which reassigns arm tdo to a pass through. if { [info exists SJCTAPID] } { set _SJCTAPID $SJCTAPID } else { set _SJCTAPID 0x1541E02B } jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID ################################################################## # various symbol definitions, to avoid hard-wiring addresses ################################################################## global lpc313x set lpc313x [ dict create ] # Physical addresses for controllers and memory dict set lpc313x sram0 0x11028000 dict set lpc313x sram1 0x11040000 dict set lpc313x uart 0x15001000 dict set lpc313x cgu 0x13004000 dict set lpc313x ioconfig 0x13003000 dict set lpc313x sysconfig 0x13002800 dict set lpc313x wdt 0x13002400 ################################################################## # Target configuration ################################################################## adapter srst delay 1000 jtag_ntrst_delay 0 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME invoke-event halted $_TARGETNAME configure -work-area-phys [dict get $lpc313x sram0] -work-area-size 0x30000 -work-area-backup 0 $_TARGETNAME configure -event reset-init { echo "\nRunning reset init script for LPC3131\n" halt wait_halt reg cpsr 0xa00000d3 ;#Supervisor mode reg pc 0x11029000 poll sleep 500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc3250.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # lpc3250 config # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lpc3250 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x17900f0f } if { [info exists CPUTAPID_REV_A0] } { set _CPUTAPID_REV_A0 $CPUTAPID_REV_A0 } else { set _CPUTAPID_REV_A0 0x17926f0f } if { [info exists SJCTAPID] } { set _SJCTAPID $SJCTAPID } else { set _SJCTAPID 0x1b900f0f } jtag newtap $_CHIPNAME sjc -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_SJCTAPID jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID \ -expected-id $_CPUTAPID_REV_A0 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian little -chain-position $_TARGETNAME -work-area-phys 0x00000000 -work-area-size 0x7d0000 -work-area-backup 0 proc power_restore {} { echo "Sensed power restore. No action." } proc srst_deasserted {} { echo "Sensed nSRST deasserted. No action." } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc40xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC40xx Cortex-M4F with at least 16kB SRAM set CHIPNAME lpc40xx set CHIPSERIES lpc4000 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x4000 } source [find target/lpc1xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc4350.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/swj-dp.tcl] adapter speed 500 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lpc4350 } # # M4 JTAG mode TAP # if { [info exists M4_JTAG_TAPID] } { set _M4_JTAG_TAPID $M4_JTAG_TAPID } else { set _M4_JTAG_TAPID 0x4ba00477 } # # M4 SWD mode TAP # if { [info exists M4_SWD_TAPID] } { set _M4_SWD_TAPID $M4_SWD_TAPID } else { set _M4_SWD_TAPID 0x2ba01477 } if { [using_jtag] } { set _M4_TAPID $_M4_JTAG_TAPID } { set _M4_TAPID $_M4_SWD_TAPID } # # M0 TAP # if { [info exists M0_JTAG_TAPID] } { set _M0_JTAG_TAPID $M0_JTAG_TAPID } else { set _M0_JTAG_TAPID 0x0ba01477 } swj_newdap $_CHIPNAME m4 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M4_TAPID dap create $_CHIPNAME.m4.dap -chain-position $_CHIPNAME.m4 target create $_CHIPNAME.m4 cortex_m -dap $_CHIPNAME.m4.dap if { [using_jtag] } { swj_newdap $_CHIPNAME m0 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M0_JTAG_TAPID dap create $_CHIPNAME.m0.dap -chain-position $_CHIPNAME.m0 target create $_CHIPNAME.m0 cortex_m -dap $_CHIPNAME.m0.dap } # LPC4350 has 96+32 KB SRAM if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x20000 } $_CHIPNAME.m4 configure -work-area-phys 0x10000000 \ -work-area-size $_WORKAREASIZE -work-area-backup 0 if {![using_hla]} { # on this CPU we should use VECTRESET to perform a soft reset and # manually reset the periphery # SRST or SYSRESETREQ disable the debug interface for the time of # the reset and will not fit our requirements for a consistent debug # session cortex_m reset_config vectreset } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc4357.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # NXP LPC4357 # if { ![info exists CHIPNAME] } { set CHIPNAME lpc4357 } set WORKAREASIZE 0x8000 source [find target/lpc4350.cfg] flash bank $_CHIPNAME.flasha lpc2000 0x1A000000 0x80000 0 0 $_CHIPNAME.m4 lpc4300 204000 calc_checksum flash bank $_CHIPNAME.flashb lpc2000 0x1B000000 0x80000 0 0 $_CHIPNAME.m4 lpc4300 204000 calc_checksum ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc4370.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # NXP LPC4370 - 1x ARM Cortex-M4 + 2x ARM Cortex-M0 @ up to 204 MHz each # adapter speed 500 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lpc4370 } # # M4 JTAG mode TAP # if { [info exists M4_JTAG_TAPID] } { set _M4_JTAG_TAPID $M4_JTAG_TAPID } else { set _M4_JTAG_TAPID 0x4ba00477 } # # M4 SWD mode TAP # if { [info exists M4_SWD_TAPID] } { set _M4_SWD_TAPID $M4_SWD_TAPID } else { set _M4_SWD_TAPID 0x2ba01477 } source [find target/swj-dp.tcl] if { [using_jtag] } { set _M4_TAPID $_M4_JTAG_TAPID } else { set _M4_TAPID $_M4_SWD_TAPID } # # M0 TAP # if { [info exists M0_JTAG_TAPID] } { set _M0_JTAG_TAPID $M0_JTAG_TAPID } else { set _M0_JTAG_TAPID 0x0ba01477 } swj_newdap $_CHIPNAME m4 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M4_TAPID dap create $_CHIPNAME.m4.dap -chain-position $_CHIPNAME.m4 target create $_CHIPNAME.m4 cortex_m -dap $_CHIPNAME.m4.dap # LPC4370 has 96+32 KB contiguous SRAM if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x20000 } $_CHIPNAME.m4 configure -work-area-phys 0x10000000 \ -work-area-size $_WORKAREASIZE -work-area-backup 0 if { [using_jtag] } { jtag newtap $_CHIPNAME m0app -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M0_JTAG_TAPID jtag newtap $_CHIPNAME m0sub -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M0_JTAG_TAPID dap create $_CHIPNAME.m0app.dap -chain-position $_CHIPNAME.m0app dap create $_CHIPNAME.m0sub.dap -chain-position $_CHIPNAME.m0sub target create $_CHIPNAME.m0app cortex_m -dap $_CHIPNAME.m0app.dap target create $_CHIPNAME.m0sub cortex_m -dap $_CHIPNAME.m0sub.dap # 32+8+32 KB SRAM $_CHIPNAME.m0app configure -work-area-phys 0x10080000 \ -work-area-size 0x92000 -work-area-backup 0 # 16+2 KB M0 subsystem SRAM $_CHIPNAME.m0sub configure -work-area-phys 0x18000000 \ -work-area-size 0x4800 -work-area-backup 0 # Default to the Cortex-M4 targets $_CHIPNAME.m4 } if { ![using_hla] } { cortex_m reset_config vectreset } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc84x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC84x Cortex-M0+ with at least 8kB SRAM if { ![info exists CHIPNAME] } { set CHIPNAME lpc84x } set CHIPSERIES lpc800 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x1fe0 } set IAP_ENTRY 0x0F001FF1 source [find target/lpc1xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc8nxx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC8Nxx NHS31xx Cortex-M0+ with 8kB SRAM # Copyright (C) 2018 by Jean-Christian de Rivaz # Based on NXP proposal https://community.nxp.com/message/1011149 # Many thanks to Dries Moors from NXP support. # SWD only transport source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lpc8nxx } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id 0 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap if {![using_hla]} { # If srst is not fitted use SYSRESETREQ to perform a soft reset cortex_m reset_config sysresetreq } adapter srst delay 100 $_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size 0x1ff0 -work-area-backup 0 flash bank $_CHIPNAME.flash lpc2000 0x0 0x7800 0 0 $_TARGETNAME lpc800 500 echo "*********************************************************************************" echo "* !!!!! IMPORTANT NOTICE FOR LPC8Nxx and NHS31xx CHIPS !!!!!" echo "* When this IC is in power-off or peep power down mode, the SWD HW block is also" echo "* unpowered. These modes can be entered by firmware. The default firmware image" echo "* (flashed in production) makes use of this. Best is to avoid these power modes" echo "* during development, and only later add them when the functionality is complete." echo "* Hardware reset or NFC field are the only ways to connect in case the SWD is" echo "* powered off. OpenOCD can do a hardware reset if you wire the adapter SRST" echo "* signal to the chip RESETN pin and add the following in your configuration:" echo "* reset_config srst_only; flash init; catch init; reset" echo "* But if the actual firmware immediately set the power down mode after reset," echo "* OpenOCD might be not fast enough to halt the CPU before the SWD lost power. In" echo "* that case the only solution is to apply a NFC field to keep the SWD powered." echo "*********************************************************************************" # Using soft-reset 'reset_config none' is strongly discouraged. # RESETN sets the system clock to 500 kHz. Unlike soft-reset does not. # Set the system clock to 500 kHz before reset to simulate the functionality of hw reset. # proc set_sysclk_500khz {} { set SYSCLKCTRL 0x40048020 set SYSCLKUEN 0x40048024 mww $SYSCLKUEN 0 mmw $SYSCLKCTRL 0x8 0xe mww $SYSCLKUEN 1 echo "Notice: sysclock set to 500kHz." } # Do not remap the ARM interrupt vectors to anything but the beginning of the flash. # Table System memory remap register (SYSMEMREMAP, address 0x4004 8000) bit description # Bit Symbol Value Description # 0 map - interrupt vector remap. 0 after boot. # 0 interrupt vector reside in Flash # 1 interrupt vector reside in SRAM # 5:1 offset - system memory remap offset. 00000b after boot. # 00000b interrupt vectors in flash or remapped to SRAM but no offset # 00001b - # 00111b interrupt vectors offset in flash or SRAM to 1K word segment # 01000b - # 11111b interrupt vectors offset in flash to 1K word segment 8 to 31 # 31:6 reserved # proc set_no_remap {} { mww 0x40048000 0x00 echo "Notice: interrupt vector set to no remap." } $_TARGETNAME configure -event reset-init { set_sysclk_500khz set_no_remap } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lpc8xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LPC8xx Cortex-M0+ with at least 1kB SRAM if { ![info exists CHIPNAME] } { set CHIPNAME lpc8xx } set CHIPSERIES lpc800 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x400 } source [find target/lpc1xxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ls1012a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # NXP LS1012A # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ls1012a } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } if { [info exists SAP_TAPID] } { set _SAP_TAPID $SAP_TAPID } else { set _SAP_TAPID 0x06b2001d } jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID jtag newtap $_CHIPNAME sap -irlen 8 -expected-id $_SAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap cti create $_CHIPNAME.cti -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0x80420000 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -dbgbase 0x80410000 -cti $_CHIPNAME.cti target smp $_TARGETNAME adapter speed 2000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ls1028a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LS1028A if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ls1028a } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x6ba00477 } set _CPUS 2 source [find target/lsch3_common.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ls1046a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LS1046A if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ls1046a } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } if { [info exists SAP_TAPID] } { set _SAP_TAPID $SAP_TAPID } else { set _SAP_TAPID 0x06b3001d } jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 0 set _CPU_BASE 0x80400000 set _CPU_STRIDE 0x100000 set _CPU_DBGOFF 0x10000 set _CPU_CTIOFF 0x20000 set _TARGETS {} for {set i 0} {$i < 4} {incr i} { set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}] cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [expr {$_BASE + $_CPU_CTIOFF}] target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \ -coreid $i {*}[expr {$i ? {-defer-examine} : {-rtos hwthread} }] lappend _TARGETS $_CHIPNAME.cpu$i } target smp {*}$_TARGETS jtag newtap $_CHIPNAME sap -irlen 8 -expected-id $_SAP_TAPID target create $_CHIPNAME.sap ls1_sap -chain-position $_CHIPNAME.sap -endian big proc core_up { args } { foreach core $args { $::_CHIPNAME.cpu$core arp_examine } } targets $_CHIPNAME.cpu0 adapter speed 10000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ls1088a.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP LS1088A if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ls1088a } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } set _CPUS 8 source [find target/lsch3_common.cfg] # Seems to work OK in testing adapter speed 10000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/lsch3_common.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This contains common configuration for NXP Layerscape chassis generation 3 if { ![info exists _CPUS] } { error "_CPUS must be set to the number of cores" } jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 1 set _CPU_BASE 0x81000000 set _CPU_STRIDE 0x100000 set _CPU_DBGOFF 0x10000 set _CPU_CTIOFF 0x20000 set _TARGETS {} for {set i 0} {$i < $_CPUS} {incr i} { set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}] cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 0 \ -baseaddr [expr {$_BASE + $_CPU_CTIOFF}] target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \ -cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \ {*}[expr {$i ? "-coreid $i" : "-rtos hwthread" }] lappend _TARGETS $_CHIPNAME.cpu$i } target smp {*}$_TARGETS # Service processor target create $_CHIPNAME.sp cortex_a -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80138000 # Normally you will not need to call this, but if you are using the hard-coded # Reset Configuration Word (RCW) you will need to call this manually. The CPU's # reset vector is 0, and the boot ROM at that location contains ARMv7-A 32-bit # instructions. This will cause the CPU to almost immediately execute an # illegal instruction. # # This code is idempotent; releasing a released CPU has no effect, although it # will halt/resume the service processor. add_help_text release_cpu "Release a cpu which is held off" proc release_cpu {cpu} { set RST_BRRL 0x1e60060 set old [target current] targets $::_CHIPNAME.sp set not_halted [string compare halted [$::_CHIPNAME.sp curstate]] if {$not_halted} { halt } # Release the cpu; it will start executing something bogus mem2array regs 32 $RST_BRRL 1 mww $RST_BRRL [expr {$regs(0) | 1 << $cpu}] if {$not_halted} { resume } targets $old } targets $_CHIPNAME.cpu0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/marvell/88f3710.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Marvell Armada 3710 set CORES 1 source [find target/marvell/88f37x0.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/marvell/88f3720.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Marvell Armada 3720 set CORES 2 source [find target/marvell/88f37x0.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/marvell/88f37x0.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Main file for Marvell Armada 3700 series targets # # !!!!!! # # This file should not be included directly. Instead, please include # either marvell/88f3710.cfg or marvell/88f3720.cfg, which set the needed # variables to the appropriate values. # # !!!!!! # Armada 3700 supports both JTAG and SWD transports. source [find target/swj-dp.tcl] if { [info exists CORES] } { set _cores $CORES } else { error "CORES not set. Please do not include marvell/88f37x0.cfg directly, but the specific chip configuration file (marvell/88f3710.cfg, marvell/88f3720.cfg, etc.)." } if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME [format a37%s0 $_cores] } set _ctis {0x80820000 0x80920000} # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } # declare the one JTAG tap to access the DAP swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # declare the main application cores set _TARGETNAME $_CHIPNAME.cpu set _smp_command "" for { set _core 0 } { $_core < $_cores } { incr _core 1 } { cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [lindex $_ctis $_core] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core \ -cti cti$_core" if { $_core != 0 } { # non-boot core examination may fail set _command "$_command -defer-examine" set _smp_command "$_smp_command ${_TARGETNAME}$_core" } else { set _command "$_command -rtos hwthread" set _smp_command "target smp ${_TARGETNAME}$_core" } eval $_command } eval $_smp_command # declare the auxiliary Cortex-M3 core on AP #3 target create ${_TARGETNAME}.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 3 -defer-examine targets ${_TARGETNAME}0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/max32620.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Maxim Integrated MAX32620 OpenOCD target configuration file # www.maximintegrated.com # adapter speed adapter speed 4000 # reset pin configuration reset_config srst_only if {[using_jtag]} { jtag newtap max32620 cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -ignore-version } else { swd newdap max32620 cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version } dap create max32620.dap -chain-position max32620.cpu # target configuration target create max32620.cpu cortex_m -dap max32620.dap max32620.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 # Config Command: flash bank name driver base size chip_width bus_width target [driver_options] # flash bank <name> max32xxx <base> <size> 0 0 <target> <flc base> <sector> <clk> <burst> # max32620 flash base address 0x00000000 # max32620 flash size 0x200000 (2MB) # max32620 FLC base address 0x40002000 # max32620 sector (page) size 0x2000 (8kB) # max32620 clock speed 96 (MHz) flash bank max32620.flash max32xxx 0x00000000 0x200000 0 0 max32620.cpu 0x40002000 0x2000 96 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/max32625.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Maxim Integrated MAX32625 OpenOCD target configuration file # www.maximintegrated.com # adapter speed adapter speed 4000 # reset pin configuration reset_config srst_only if {[using_jtag]} { jtag newtap max32625 cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -expected-id 0x07f71197 -ignore-version } else { swd newdap max32625 cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version } dap create max32625.dap -chain-position max32625.cpu # target configuration target create max32625.cpu cortex_m -dap max32625.dap max32625.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 # Config Command: flash bank name driver base size chip_width bus_width target [driver_options] # flash bank <name> max32xxx <base> <size> 0 0 <target> <flc base> <sector> <clk> <burst> # max32625 flash base address 0x00000000 # max32625 flash size 0x80000 (512k) # max32625 FLC base address 0x40002000 # max32625 sector (page) size 0x2000 (8kB) # max32625 clock speed 96 (MHz) flash bank max32625.flash max32xxx 0x00000000 0x80000 0 0 max32625.cpu 0x40002000 0x2000 96 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/max3263x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Maxim Integrated MAX3263X OpenOCD target configuration file # www.maximintegrated.com # adapter speed adapter speed 4000 # reset pin configuration reset_config srst_only if {[using_jtag]} { jtag newtap max3263x cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -expected-id 0x07f76197 -ignore-version } else { swd newdap max3263x cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version } dap create max3263x.dap -chain-position max3263x.cpu # target configuration target create max3263x.cpu cortex_m -dap max3263x.dap max3263x.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 # Config Command: flash bank name driver base size chip_width bus_width target [driver_options] # flash bank <name> max32xxx <base> <size> 0 0 <target> <flc base> <sector> <clk> <burst> # max3263x flash base address 0x00000000 # max3263x flash size 0x200000 (2MB) # max3263x FLC base address 0x40002000 # max3263x sector (page) size 0x2000 (8kB) # max3263x clock speed 96 (MHz) flash bank max3263x.flash max32xxx 0x00000000 0x200000 0 0 max3263x.cpu 0x40002000 0x2000 96 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/mc13224v.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find bitsbytes.tcl] source [find cpu/arm/arm7tdmi.tcl] source [find memory.tcl] source [find mmr_helpers.tcl] set CHIP_MAKER freescale set CHIP_FAMILY mc1322x set CHIP_NAME mc13224 set N_RAM 1 set RAM(0,BASE) 0x00400000 set RAM(0,LEN) 0x18000 set RAM(0,HUMAN) "internal SRAM" set RAM(0,TYPE) "ram" set RAM(0,RWX) $RWX_RWX set RAM(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY # I AM LAZY... I create 1 region for all MMRs. set N_MMREGS 1 set MMREGS(0,CHIPSELECT) -1 set MMREGS(0,BASE) 0x80000000 set MMREGS(0,LEN) 0x00030000 set MMREGS(0,HUMAN) "mm-regs" set MMREGS(0,TYPE) "mmr" set MMREGS(0,RWX) $RWX_RW set MMREGS(0,ACCESS_WIDTH) $ACCESS_WIDTH_ANY set N_XMEM 0 set _CHIPNAME mc13224v set _CPUTAPID 0x1f1f001d jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID reset_config srst_only jtag_ntrst_delay 200 # rclk hasn't been working well. This maybe the mc13224v or something else. #adapter speed 2000 adapter speed 2000 ###################### # Target configuration ###################### set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME # Internal sram memory $_TARGETNAME configure -work-area-phys 0x00408000 \ -work-area-size 0x1000 \ -work-area-backup 1 # flash support is pending (should be straightforward to implement) #flash bank mc1322x 0 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/mdr32f9q2i.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # MDR32F9Q2I (1986ВЕ92У) # http://milandr.ru/index.php?mact=Products,cntnt01,details,0&cntnt01productid=57&cntnt01returnid=68 source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME mdr32f9q2i } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x8000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x4ba00477 } { # SWD IDCODE set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # can't handle overlapping memory regions if { [info exists IMEMORY] && [string equal $IMEMORY true] } { flash bank ${_CHIPNAME}_info.flash mdr 0x08000000 0x01000 0 0 $_TARGETNAME 1 1 4 } else { flash bank $_CHIPNAME.flash mdr 0x08000000 0x20000 0 0 $_TARGETNAME 0 32 4 } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz adapter speed 1000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/nds32v5.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Andes Core # # http://www.andestech.com # set _CHIPNAME nds jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563D set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ngultra.cfg ================================================ # SPDX-License-Identifier: BSD-3-Clause # Copyright (C) 2022 by NanoXplore, France - all rights reserved # # configuration file for NG-Ultra SoC from NanoXplore. # NG-Ultra is a quad-core Cortex-R52 SoC + an FPGA. # transport select jtag adapter speed 10000 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME NGULTRA } if { [info exists CHIPCORES] } { set _cores $CHIPCORES } else { set _cores 4 } set DBGBASE {0x88210000 0x88310000 0x88410000 0x88510000} set CTIBASE {0x88220000 0x88320000 0x88420000 0x88520000} # Coresight access to the SoC jtag newtap $_CHIPNAME.coresight cpu -irlen 4 -expected-id 0x6BA00477 # Misc TAP devices jtag newtap $_CHIPNAME.soc cpu -irlen 7 -expected-id 0xFAAA0555 jtag newtap $_CHIPNAME.pmb unknown1 -irlen 5 -expected-id 0xBA20A005 jtag newtap $_CHIPNAME.fpga fpga -irlen 4 -ignore-version -ignore-bypass # Create the Coresight DAP dap create $_CHIPNAME.coresight.dap -chain-position $_CHIPNAME.coresight.cpu for { set _core 0 } { $_core < $_cores } { incr _core } { cti create cti.$_core -dap $_CHIPNAME.coresight.dap -ap-num 0 \ -baseaddr [lindex $CTIBASE $_core] # Cores are armv8-r but works with aarch64 (since armv8-r not directly supported by openocd yet). if { $_core == 0} { target create core.$_core aarch64 -dap $_CHIPNAME.coresight.dap \ -ap-num 0 -dbgbase [lindex $DBGBASE $_core] -cti cti.$_core } else { target create core.$_core aarch64 -dap $_CHIPNAME.coresight.dap \ -ap-num 0 -dbgbase [lindex $DBGBASE $_core] -cti cti.$_core -defer-examine } } # Create direct APB and AXI interfaces target create APB mem_ap -dap $_CHIPNAME.coresight.dap -ap-num 0 target create AXI mem_ap -dap $_CHIPNAME.coresight.dap -ap-num 1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/nhs31xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP NHS31xx Cortex-M0+ with 8kB SRAM set CHIPNAME nhs31xx source [find target/lpc8nxx.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/npcx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for Nuvoton NPCX Cortex-M4 Series # Adapt based on what transport is active. source [find target/swj-dp.tcl] # Set Chipname if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME NPCX_M4 } # SWD DAP ID of Nuvoton NPCX Cortex-M4. if { [info exists CPUDAPID ] } { set _CPUDAPID $CPUDAPID } else { set _CPUDAPID 0x4BA00477 } # Work-area is a space in RAM used for flash programming # By default use 32kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x8000 } # Debug Adapter Target Settings swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUDAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x200c0000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # Initial JTAG/SWD speed # For safety purposes, set for the lowest cpu clock configuration # 4MHz / 6 = 666KHz, so use 600KHz for it adapter speed 600 # For safety purposes, set for the lowest cpu clock configuration $_TARGETNAME configure -event reset-start {adapter speed 600} # use sysresetreq to perform a system reset cortex_m reset_config sysresetreq # flash configuration set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME npcx 0x64000000 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/nrf51.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # script for Nordic nRF51 series, a Cortex-M0 chip # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME nrf51 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # Work-area is a space in RAM used for flash programming # By default use 16kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0bb11477 } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 if {![using_hla]} { # The chip supports standard ARM/Cortex-M0 SYSRESETREQ signal cortex_m reset_config sysresetreq } flash bank $_CHIPNAME.flash nrf51 0x00000000 0 1 1 $_TARGETNAME flash bank $_CHIPNAME.uicr nrf51 0x10001000 0 1 1 $_TARGETNAME # # The chip should start up from internal 16Mhz RC, so setting adapter # clock to 1Mhz should be OK # adapter speed 1000 proc enable_all_ram {} { # nRF51822 Product Anomaly Notice (PAN) #16 explains that not all RAM banks # are reliably enabled after reset on some revisions (contrary to spec.) So after # resetting we enable all banks via the RAMON register mww 0x40000524 0xF } $_TARGETNAME configure -event reset-end { enable_all_ram } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/nrf52.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Nordic nRF52 series: ARM Cortex-M4 @ 64 MHz # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME nrf52 } # Work-area is a space in RAM used for flash programming # By default use 16kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x2ba01477 } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap adapter speed 1000 $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 if { [using_hla] } { echo "" echo "nRF52 device has a CTRL-AP dedicated to recover the device from AP lock." echo "A high level adapter (like a ST-Link) you are currently using cannot access" echo "the CTRL-AP so 'nrf52_recover' command will not work." echo "Do not enable UICR APPROTECT." echo "" } else { cortex_m reset_config sysresetreq $_TARGETNAME configure -event examine-fail nrf52_check_ap_lock } flash bank $_CHIPNAME.flash nrf5 0x00000000 0 1 1 $_TARGETNAME flash bank $_CHIPNAME.uicr nrf5 0x10001000 0 1 1 $_TARGETNAME # Test if MEM-AP is locked by UICR APPROTECT proc nrf52_check_ap_lock {} { set dap [[target current] cget -dap] set err [catch {set APPROTECTSTATUS [$dap apreg 1 0xc]}] if {$err == 0 && $APPROTECTSTATUS != 1} { echo "****** WARNING ******" echo "nRF52 device has AP lock engaged (see UICR APPROTECT register)." echo "Debug access is denied." echo "Use 'nrf52_recover' to erase and unlock the device." echo "" poll off } } # Mass erase and unlock the device using proprietary nRF CTRL-AP (AP #1) # http://www.ebyte.com produces modules with nRF52 locked by default, # use nrf52_recover to enable flashing and debug. proc nrf52_recover {} { set target [target current] set dap [$target cget -dap] set IDR [$dap apreg 1 0xfc] if {$IDR != 0x02880000} { echo "Error: Cannot access nRF52 CTRL-AP!" return } poll off # Reset and trigger ERASEALL task $dap apreg 1 4 0 $dap apreg 1 4 1 for {set i 0} {1} {incr i} { set ERASEALLSTATUS [$dap apreg 1 8] if {$ERASEALLSTATUS == 0} { echo "$target device has been successfully erased and unlocked." break } if {$i == 0} { echo "Waiting for chip erase..." } if {$i >= 150} { echo "Error: $target recovery failed." break } sleep 100 } # Assert reset $dap apreg 1 0 1 # Deassert reset $dap apreg 1 0 0 # Reset ERASEALL task $dap apreg 1 4 0 sleep 100 $target arp_examine poll on } add_help_text nrf52_recover "Mass erase and unlock nRF52 device" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/nuc910.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Nuvoton nuc910 (previously W90P910) based soc # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME nuc910 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # set useful default set _CPUTAPID 0x07926f0f } set _TARGETNAME $_CHIPNAME.cpu jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/numicro.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for Nuvoton MuMicro Cortex-M0 Series # Adapt based on what transport is active. source [find target/swj-dp.tcl] # Set Chipname if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME NuMicro } # SWD DP-ID Nuvoton NuMicro Cortex-M0 has SWD Transport only. if { [info exists CPUDAPID] } { set _CPUDAPID $CPUDAPID } else { set _CPUDAPID 0x0BB11477 } # Work-area is a space in RAM used for flash programming # By default use 2kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x800 } # Debug Adapter Target Settings swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUDAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash bank <name> numicro <base> <size(autodetect,set to 0)> 0 0 <target#> #set _FLASHNAME $_CHIPNAME.flash #flash bank $_FLASHNAME numicro 0 $_FLASHSIZE 0 0 $_TARGETNAME # flash size will be probed set _FLASHNAME $_CHIPNAME.flash_aprom flash bank $_FLASHNAME numicro 0x00000000 0 0 0 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash_data flash bank $_FLASHNAME numicro 0x0001F000 0 0 0 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash_ldrom flash bank $_FLASHNAME numicro 0x00100000 0 0 0 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash_config flash bank $_FLASHNAME numicro 0x00300000 0 0 0 $_TARGETNAME # set default SWCLK frequency adapter speed 1000 # set default srst setting "none" reset_config none # HLA doesn't have cortex_m commands if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/numicro_m4.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for Nuvoton MuMicro Cortex-M4 Series source [find target/swj-dp.tcl] # Set Chipname if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME NuMicro } # SWD DP-ID Nuvoton NuMicro Cortex-M4 has SWD Transport only. if { [info exists CPUDAPID] } { set _CPUDAPID $CPUDAPID } else { set _CPUDAPID 0x2BA01477 } # Work-area is a space in RAM used for flash programming # By default use 16kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } # Debug Adapter Target Settings swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUDAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash bank <name> numicro <base> <size(autodetect,set to 0)> 0 0 <target#> #set _FLASHNAME $_CHIPNAME.flash #flash bank $_FLASHNAME numicro 0 $_FLASHSIZE 0 0 $_TARGETNAME # flash size will be probed set _FLASHNAME $_CHIPNAME.flash_aprom flash bank $_FLASHNAME numicro 0x00000000 0 0 0 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash_data flash bank $_FLASHNAME numicro 0x0001F000 0 0 0 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash_ldrom flash bank $_FLASHNAME numicro 0x00100000 0 0 0 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash_config flash bank $_FLASHNAME numicro 0x00300000 0 0 0 $_TARGETNAME # set default SWCLK frequency adapter speed 1000 # set default srst setting "none" reset_config none # HLA doesn't have cortex_m commands if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/omap2420.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Texas Instruments OMAP 2420 # http://www.ti.com/omap # as seen in Nokia N8x0 tablets if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME omap2420 } # NOTE: likes slowish clock on reset (1.5 MBit/s or less) or use RCLK reset_config srst_nogate # Subsidiary TAP: ARM7TDMIr4 plus imaging ... must add via ICEpick (addr 6). jtag newtap $_CHIPNAME iva -irlen 4 -disable # Subsidiary TAP: C55x DSP ... must add via ICEpick (addr 2). jtag newtap $_CHIPNAME dsp -irlen 38 -disable # Subsidiary TAP: ARM ETB11, with scan chain for 4K of ETM trace buffer if { [info exists ETB_TAPID] } { set _ETB_TAPID $ETB_TAPID } else { set _ETB_TAPID 0x2b900f0f } jtag newtap $_CHIPNAME etb -irlen 4 -expected-id $_ETB_TAPID # Subsidiary TAP: ARM1136jf-s with scan chains for ARM Debug, EmbeddedICE-RT, ETM. if { [info exists CPU_TAPID] } { set _CPU_TAPID $CPU_TAPID } else { set _CPU_TAPID 0x07b3602f } jtag newtap $_CHIPNAME arm -irlen 5 -expected-id $_CPU_TAPID # Primary TAP: ICEpick-B (JTAG route controller) and boundary scan if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x01ce4801 } jtag newtap $_CHIPNAME jrc -irlen 2 -expected-id $_JRC_TAPID # GDB target: the ARM. set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm11 -chain-position $_TARGETNAME # scratch: framebuffer, may be initially unavailable in some chips $_TARGETNAME configure -work-area-phys 0x40210000 $_TARGETNAME configure -work-area-size 0x00081000 $_TARGETNAME configure -work-area-backup 0 # trace setup ... NOTE, "normal full" mode fudges the real ETMv3.1 mode etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb # RM_RSTCTRL_WKUP.RST.GS - Trigger a global software reset, and # give it a chance to finish before we talk to the chip again. set RM_RSTCTRL_WKUP 0x48008450 $_TARGETNAME configure -event reset-assert \ "halt; $_TARGETNAME mww $RM_RSTCTRL_WKUP 2; sleep 200" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/omap3530.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # TI OMAP3530 # http://focus.ti.com/docs/prod/folders/print/omap3530.html # Other OMAP3 chips remove DSP and/or the OpenGL support if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME omap3530 } # ICEpick-C ... used to route Cortex, DSP, and more not shown here source [find target/icepick.cfg] # Subsidiary TAP: C64x+ DSP ... must enable via ICEpick jtag newtap $_CHIPNAME dsp -irlen 38 -ircapture 0x25 -irmask 0x3f -disable # Subsidiary TAP: CoreSight Debug Access Port (DAP) if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x0b6d602f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 3" # Primary TAP: ICEpick-C (JTAG route controller) and boundary scan if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0b7ae02f } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \ -expected-id $_JRC_TAPID # GDB target: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # SRAM: 64K at 0x4020.0000; use the first 16K $_TARGETNAME configure -work-area-phys 0x40200000 -work-area-size 0x4000 ################### # the reset sequence is event-driven # and kind of finicky... # some TCK tycles are required to activate the DEBUG power domain jtag configure $_CHIPNAME.jrc -event post-reset "runtest 100" # have the DAP "always" be active jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.dap" proc omap3_dbginit {target} { # General Cortex-A8 debug initialisation cortex_a dbginit # Enable DBGU signal for OMAP353x $target mww phys 0x5401d030 0x00002000 } # be absolutely certain the JTAG clock will work with the worst-case # 16.8MHz/2 = 8.4MHz core clock, even before a bootloader kicks in. # OK to speed up *after* PLL and clock tree setup. adapter speed 1000 $_TARGETNAME configure -event "reset-start" { adapter speed 1000 } # Assume SRST is unavailable (e.g. TI-14 JTAG), so we must assert reset # ourselves using PRM_RSTCTRL. RST_GS (2) is a warm reset, like ICEpick # would issue. RST_DPLL3 (4) is a cold reset. set PRM_RSTCTRL 0x48307250 $_TARGETNAME configure -event reset-assert "$_TARGETNAME mww $PRM_RSTCTRL 2" $_TARGETNAME configure -event reset-assert-post "omap3_dbginit $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/omap4430.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # OMAP4430 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME omap4430 } # Although the OMAP4430 supposedly has an ICEpick-D, only the # ICEpick-C router commands seem to work. # See http://processors.wiki.ti.com/index.php/ICEPICK source [find target/icepick.cfg] # # A9 DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x3BA00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 9" # # M3 DAPs, one per core # if { [info exists M3_DAP_TAPID] } { set _M3_DAP_TAPID $M3_DAP_TAPID } else { set _M3_DAP_TAPID 0x4BA00477 } jtag newtap $_CHIPNAME m31 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable jtag configure $_CHIPNAME.m31 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 5" jtag newtap $_CHIPNAME m30 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable jtag configure $_CHIPNAME.m30 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 4" # # ICEpick-D JRC (JTAG route controller) # if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x3b95c02f set _JRC_TAPID2 0x1b85202f } # PandaBoard REV EA1 (PEAP platforms) if { [info exists JRC_TAPID2] } { set _JRC_TAPID2 $JRC_TAPID2 } else { set _JRC_TAPID2 0x1b85202f } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \ -expected-id $_JRC_TAPID -expected-id $_JRC_TAPID2 # Required by ICEpick to power-up the debug domain jtag configure $_CHIPNAME.jrc -event post-reset "runtest 200" # # GDB target: Cortex-A9, using DAP # # The debugger can connect to either core of the A9, but currently # not both simultaneously. Change -coreid to 1 to connect to the # second core. # set _TARGETNAME $_CHIPNAME.cpu # APB DBGBASE reads 0x80040000, but this points to an empty ROM table. # 0x80000000 is cpu0 coresight region # # # CORTEX_A8_PADDRDBG_CPU_SHIFT 13 # 0x80000000 | (coreid << CORTEX_A8_PADDRDBG_CPU_SHIFT) set _coreid 0 set _dbgbase [expr {0x80000000 | ($_coreid << 13)}] echo "Using dbgbase = [format 0x%x $_dbgbase]" dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase $_dbgbase # SRAM: 56KiB at 0x4030.0000 $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x1000 # # M3 targets, separate TAP/DAP for each core # dap create $_CHIPNAME.m30_dap -chain-position $_CHIPNAME.m30 dap create $_CHIPNAME.m31_dap -chain-position $_CHIPNAME.m31 target create $_CHIPNAME.m30 cortex_m -dap $_CHIPNAME.m30_dap target create $_CHIPNAME.m31 cortex_m -dap $_CHIPNAME.m31_dap # Once the JRC is up, enable our TAPs jtag configure $_CHIPNAME.jrc -event setup " jtag tapenable $_CHIPNAME.cpu jtag tapenable $_CHIPNAME.m30 jtag tapenable $_CHIPNAME.m31 " # Assume SRST is unavailable (e.g. TI-14 JTAG), so we must assert reset # ourselves using PRM_RSTCTRL. 1 is a warm reset, 2 a cold reset. set PRM_RSTCTRL 0x4A307B00 $_TARGETNAME configure -event reset-assert "$_TARGETNAME mww phys $PRM_RSTCTRL 0x1" $_CHIPNAME.m30 configure -event reset-assert { } $_CHIPNAME.m31 configure -event reset-assert { } # Soft breakpoints don't currently work due to broken cache handling gdb_breakpoint_override hard ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/omap4460.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # OMAP4460 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME omap4460 } # Although the OMAP4430 supposedly has an ICEpick-D, only the # ICEpick-C router commands seem to work. # See http://processors.wiki.ti.com/index.php/ICEPICK source [find target/icepick.cfg] # # A9 DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x3BA00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 9" # # M3 DAPs, one per core # if { [info exists M3_DAP_TAPID] } { set _M3_DAP_TAPID $M3_DAP_TAPID } else { set _M3_DAP_TAPID 0x4BA00477 } jtag newtap $_CHIPNAME m31 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable jtag configure $_CHIPNAME.m31 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 5" jtag newtap $_CHIPNAME m30 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable jtag configure $_CHIPNAME.m30 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 4" # # ICEpick-D JRC (JTAG route controller) # if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x2b94e02f set _JRC_TAPID2 0x1b85202f } # PandaBoard REV EA1 (PEAP platforms) if { [info exists JRC_TAPID2] } { set _JRC_TAPID2 $JRC_TAPID2 } else { set _JRC_TAPID2 0x1b85202f } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \ -expected-id $_JRC_TAPID -expected-id $_JRC_TAPID2 # Required by ICEpick to power-up the debug domain jtag configure $_CHIPNAME.jrc -event post-reset "runtest 200" # # GDB target: Cortex-A9, using DAP # # The debugger can connect to either core of the A9, but currently # not both simultaneously. Change -coreid to 1 to connect to the # second core. # set _TARGETNAME $_CHIPNAME.cpu # APB DBGBASE reads 0x80040000, but this points to an empty ROM table. # 0x80000000 is cpu0 coresight region # # # CORTEX_A8_PADDRDBG_CPU_SHIFT 13 # 0x80000000 | (coreid << CORTEX_A8_PADDRDBG_CPU_SHIFT) set _coreid 0 set _dbgbase [expr {0x80000000 | ($_coreid << 13)}] echo "Using dbgbase = [format 0x%x $_dbgbase]" dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase $_dbgbase # SRAM: 56KiB at 0x4030.0000 $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x1000 # # M3 targets, separate TAP/DAP for each core # dap create $_CHIPNAME.m30_dap -chain-position $_CHIPNAME.m30 dap create $_CHIPNAME.m31_dap -chain-position $_CHIPNAME.m31 target create $_CHIPNAME.m30 cortex_m -dap $_CHIPNAME.m30_dap target create $_CHIPNAME.m31 cortex_m -dap $_CHIPNAME.m31_dap # Once the JRC is up, enable our TAPs jtag configure $_CHIPNAME.jrc -event setup " jtag tapenable $_CHIPNAME.cpu jtag tapenable $_CHIPNAME.m30 jtag tapenable $_CHIPNAME.m31 " # Assume SRST is unavailable (e.g. TI-14 JTAG), so we must assert reset # ourselves using PRM_RSTCTRL. 1 is a warm reset, 2 a cold reset. set PRM_RSTCTRL 0x4A307B00 $_TARGETNAME configure -event reset-assert "$_TARGETNAME mww phys $PRM_RSTCTRL 0x1" $_CHIPNAME.m30 configure -event reset-assert { } $_CHIPNAME.m31 configure -event reset-assert { } # Soft breakpoints don't currently work due to broken cache handling gdb_breakpoint_override hard ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/omap5912.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # TI OMAP5912 dual core processor # http://focus.ti.com/docs/prod/folders/print/omap5912.html if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME omap5912 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # NOTE: validated with XOMAP5912 part set _CPUTAPID 0x0692602f } adapter srst delay 100 # NOTE: presumes irlen 38 is the C55x DSP, matching BSDL for # its standalone siblings (like TMS320VC5502) of the same era #jtag scan chain jtag newtap $_CHIPNAME dsp -irlen 38 -expected-id 0x03df1d81 jtag newtap $_CHIPNAME arm -irlen 4 -expected-id $_CPUTAPID jtag newtap $_CHIPNAME unknown -irlen 8 set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm926ejs -chain-position $_TARGETNAME proc omap5912_reset {} { # # halt target # poll sleep 1 halt wait_halt # # disable wdt # mww 0xfffec808 0x000000f5 mww 0xfffec808 0x000000a0 mww 0xfffeb048 0x0000aaaa sleep 500 mww 0xfffeb048 0x00005555 sleep 500 } # omap5912 lcd frame buffer as working area $_TARGETNAME configure -work-area-phys 0x20000000 \ -work-area-size 0x3e800 -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/omapl138.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments DaVinci family: OMAPL138 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME omapl138 } source [find target/icepick.cfg] # Subsidiary TAP: ARM ETB11, with scan chain for 4K of ETM trace buffer if { [info exists ETB_TAPID] } { set _ETB_TAPID $ETB_TAPID } else { set _ETB_TAPID 0x2b900f0f } jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0xf -expected-id $_ETB_TAPID -disable jtag configure $_CHIPNAME.etb -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 3" # Subsidiary TAP: ARM926ejs with scan chains for ARM Debug, EmbeddedICE-RT, ETM. if { [info exists CPU_TAPID] } { set _CPU_TAPID $CPU_TAPID } else { set _CPU_TAPID 0x07926001 } jtag newtap $_CHIPNAME arm -irlen 4 -irmask 0xf -expected-id $_CPU_TAPID -disable jtag configure $_CHIPNAME.arm -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 2" # Primary TAP: ICEpick-C (JTAG route controller) and boundary scan if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0b7d102f } jtag newtap $_CHIPNAME jrc -irlen 6 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version jtag configure $_CHIPNAME.jrc -event setup \ "jtag tapenable $_CHIPNAME.etb; jtag tapenable $_CHIPNAME.arm" ################ # GDB target: the ARM, using SRAM1 for scratch. SRAM0 (also 8K) # and the ETB memory (4K) are other options, while trace is unused. # Little-endian; use the OpenOCD default. set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm926ejs -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 0x2000 # be absolutely certain the JTAG clock will work with the worst-case # CLKIN = 20 MHz (best case: 30 MHz) even when no bootloader turns # on the PLL and starts using it. OK to speed up after clock setup. adapter speed 1500 $_TARGETNAME configure -event "reset-start" { adapter speed 1500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable # trace setup etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb gdb_breakpoint_override hard arm7_9 dbgrq enable ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/or1k.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set _ENDIAN big if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME or1k } if { [info exists TAP_TYPE] } { set _TAP_TYPE $TAP_TYPE } else { puts "You need to select a tap type" shutdown } # Configure the target if { [string compare $_TAP_TYPE "VJTAG"] == 0 } { if { [info exists FPGATAPID] } { set _FPGATAPID $FPGATAPID } else { puts "You need to set your FPGA JTAG ID" shutdown } jtag newtap $_CHIPNAME cpu -irlen 10 -expected-id $_FPGATAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME or1k -endian $_ENDIAN -chain-position $_TARGETNAME # Select the TAP core we are using tap_select vjtag } elseif { [string compare $_TAP_TYPE "XILINX_BSCAN"] == 0 } { if { [info exists FPGATAPID] } { set _FPGATAPID $FPGATAPID } else { puts "You need to set your FPGA JTAG ID" shutdown } jtag newtap $_CHIPNAME cpu -irlen 6 -expected-id $_FPGATAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME or1k -endian $_ENDIAN -chain-position $_TARGETNAME # Select the TAP core we are using tap_select xilinx_bscan } else { # OpenCores Mohor JTAG TAP ID set _CPUTAPID 0x14951185 jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME or1k -endian $_ENDIAN -chain-position $_TARGETNAME # Select the TAP core we are using tap_select mohor } # Select the debug unit core we are using. This debug unit as an option. set ADBG_USE_HISPEED 1 set ENABLE_JSP_SERVER 2 set ENABLE_JSP_MULTI 4 # If ADBG_USE_HISPEED is set (options bit 1), status bits will be skipped # on burst reads and writes to improve download speeds. # This option must match the RTL configured option. du_select adv [expr {$ADBG_USE_HISPEED | $ENABLE_JSP_SERVER | $ENABLE_JSP_MULTI}] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/pic32mx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME pic32mx } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x30938053 } # default working area is 16384 if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } adapter srst delay 100 jtag_ntrst_delay 100 #jtag scan chain #format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE) jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian $_ENDIAN -chain-position $_TARGETNAME # # At reset the pic32mx does not allow code execution from RAM # we have to setup the BMX registers to allow this. # One limitation is that we loose the first 2k of RAM. # global _PIC32MX_DATASIZE global _WORKAREASIZE set _PIC32MX_DATASIZE 0x800 set _PIC32MX_PROGSIZE [expr {$_WORKAREASIZE - $_PIC32MX_DATASIZE}] $_TARGETNAME configure -work-area-phys 0xa0000800 -work-area-size $_PIC32MX_PROGSIZE -work-area-backup 0 $_TARGETNAME configure -event reset-init { # # from reset the pic32 cannot execute code in ram - enable ram execution # minimum offset from start of ram is 2k # global _PIC32MX_DATASIZE global _WORKAREASIZE # BMXCON set 0 wait state option by clearing BMXWSDRM bit, bit 6 mww 0xbf882000 0x001f0000 # BMXDKPBA: 2k kernel data @ 0xa0000000 mww 0xbf882010 $_PIC32MX_DATASIZE # BMXDUDBA: 14k kernel program @ 0xa0000800 - (BMXDUDBA - BMXDKPBA) mww 0xbf882020 $_WORKAREASIZE # BMXDUPBA: 0k user program - (BMXDUPBA - BMXDUDBA) mww 0xbf882030 $_WORKAREASIZE # # Set system clock to 8Mhz if the default clock configuration is set # # SYSKEY register, make sure OSCCON is locked mww 0xbf80f230 0x0 # SYSKEY register, write unlock sequence mww 0xbf80f230 0xaa996655 mww 0xbf80f230 0x556699aa # OSCCON register + 4, clear OSCCON FRCDIV bits: 24, 25 and 26, divided by 1 mww 0xbf80f004 0x07000000 # SYSKEY register, relock OSCCON mww 0xbf80f230 0x0 } set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME pic32mx 0x1fc00000 0 0 0 $_TARGETNAME # add virtual banks for kseg0 and kseg1 flash bank vbank0 virtual 0xbfc00000 0 0 0 $_TARGETNAME $_FLASHNAME flash bank vbank1 virtual 0x9fc00000 0 0 0 $_TARGETNAME $_FLASHNAME set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME pic32mx 0x1d000000 0 0 0 $_TARGETNAME # add virtual banks for kseg0 and kseg1 flash bank vbank2 virtual 0xbd000000 0 0 0 $_TARGETNAME $_FLASHNAME flash bank vbank3 virtual 0x9d000000 0 0 0 $_TARGETNAME $_FLASHNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/psoc4.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for Cypress PSoC 4 devices # # PSoC 4 devices support SWD transports only. # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME psoc4 } # Work-area is a space in RAM used for flash programming # By default use 4kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0bb11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME psoc4 0 0 0 0 $_TARGETNAME adapter speed 1500 # Reset, bloody PSoC 4 reset # # 1) XRES (nSRST) resets also SWD DP so SWD line reset and DP reinit is needed. # High level adapter stops working after SRST and needs OpenOCD restart. # If your hw does not use SRST for other circuits, use sysresetreq instead # # 2) PSoC 4 executes initialization code from system ROM after reset. # This code subsequently jumps to user flash reset vector address. # Unfortunately the system ROM code is protected from reading and debugging. # Protection breaks vector catch VC_CORERESET used for "reset halt" by cortex_m. # # Cypress uses TEST_MODE flag to loop CPU in system ROM before executing code # from user flash. Programming specifications states that TEST_MODE flag must be # set in time frame 400 usec delayed about 1 msec from reset. # # OpenOCD have no standard way how to set TEST_MODE in specified time frame. # As a workaround the TEST_MODE flag is set before reset instead. # It worked for the oldest family PSoC4100/4200 even though it is not guaranteed # by specification. # # Newer families like PSoC 4000, 4100M, 4200M, 4100L, 4200L and PSoC 4 BLE # clear TEST_MODE flag during device reset so workaround is not possible. # Use a KitProg adapter for these devices or "reset halt" will not stop # before executing user code. # # 3) SWD cannot be connected during system initialization after reset. # This might be a reason for unconnecting ST-Link v2 when deasserting reset. # As a workaround arp_reset deassert is not called for hla if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } proc psoc4_get_family_id {} { set err [catch {set romtable_pid [read_memory 0xF0000FE0 32 3]}] if { $err } { return 0 } if { [expr {[lindex $romtable_pid 0] & 0xffffff00 }] || [expr {[lindex $romtable_pid 1] & 0xffffff00 }] || [expr {[lindex $romtable_pid 2] & 0xffffff00 }] } { echo "Unexpected data in ROMTABLE" return 0 } set designer_id [expr {(( [lindex $romtable_pid 1] & 0xf0 ) >> 4) | (( [lindex $romtable_pid 2] & 0xf ) << 4 ) }] if { $designer_id != 0xb4 } { echo [format "ROMTABLE Designer ID 0x%02x is not Cypress" $designer_id] return 0 } set family_id [expr {( [lindex $romtable_pid 0] & 0xff ) | (( [lindex $romtable_pid 1] & 0xf ) << 8 ) }] return $family_id } proc ocd_process_reset_inner { MODE } { global PSOC4_USE_ACQUIRE PSOC4_TEST_MODE_WORKAROUND global _TARGETNAME if { 0 != [string compare $_TARGETNAME [target names]] } { return -code error "PSoC 4 reset can handle only one $_TARGETNAME target"; } set t $_TARGETNAME # If this target must be halted... set halt -1 if { 0 == [string compare $MODE halt] } { set halt 1 } if { 0 == [string compare $MODE init] } { set halt 1; } if { 0 == [string compare $MODE run ] } { set halt 0; } if { $halt < 0 } { return -code error "Invalid mode: $MODE, must be one of: halt, init, or run"; } if { ! [info exists PSOC4_USE_ACQUIRE] } { if { 0 == [string compare [adapter name] kitprog ] } { set PSOC4_USE_ACQUIRE 1 } else { set PSOC4_USE_ACQUIRE 0 } } if { $PSOC4_USE_ACQUIRE } { set PSOC4_TEST_MODE_WORKAROUND 0 } elseif { ! [info exists PSOC4_TEST_MODE_WORKAROUND] } { if { [psoc4_get_family_id] == 0x93 } { set PSOC4_TEST_MODE_WORKAROUND 1 } else { set PSOC4_TEST_MODE_WORKAROUND 0 } } #$t invoke-event reset-start $t invoke-event reset-assert-pre if { $halt && $PSOC4_USE_ACQUIRE } { catch { [adapter name] acquire_psoc } $t arp_examine } else { if { $PSOC4_TEST_MODE_WORKAROUND } { set TEST_MODE 0x40030014 if { $halt == 1 } { catch { mww $TEST_MODE 0x80000000 } } else { catch { mww $TEST_MODE 0 } } } $t arp_reset assert 0 } $t invoke-event reset-assert-post $t invoke-event reset-deassert-pre if {![using_hla]} { # workaround ST-Link v2 fails and forcing reconnect $t arp_reset deassert 0 } $t invoke-event reset-deassert-post # Pass 1 - Now wait for any halt (requested as part of reset # assert/deassert) to happen. Ideally it takes effect without # first executing any instructions. if { $halt } { # Now PSoC CPU should loop in system ROM $t arp_waitstate running 200 $t arp_halt # Catch, but ignore any errors. catch { $t arp_waitstate halted 1000 } # Did we succeed? set s [$t curstate] if { 0 != [string compare $s "halted" ] } { return -code error [format "TARGET: %s - Not halted" $t] } # Check if PSoC CPU is stopped in system ROM set pc [reg pc] regsub {pc[^:]*: } $pc "" pc if { $pc < 0x10000000 || $pc > 0x1000ffff } { set hint "" set family_id [psoc4_get_family_id] if { $family_id == 0x93 } { set hint ", use 'reset_config none'" } elseif { $family_id > 0x93 } { set hint ", use a KitProg adapter" } return -code error [format "TARGET: %s - Not halted in system ROM%s" $t $hint] } # Set registers to reset vector values set value [read_memory 0x0 32 2] reg pc [expr {[lindex $value 1] & 0xfffffffe}] reg msp [lindex $value 0] if { $PSOC4_TEST_MODE_WORKAROUND } { catch { mww $TEST_MODE 0 } } } #Pass 2 - if needed "init" if { 0 == [string compare init $MODE] } { set err [catch "$t arp_waitstate halted 5000"] # Did it halt? if { $err == 0 } { $t invoke-event reset-init } } $t invoke-event reset-end } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/psoc5lp.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Cypress PSoC 5LP # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME psoc5lp } if { [info exists CPUTAPID] } { set _CPU_TAPID $CPUTAPID } else { set _CPU_TAPID 0x4BA00477 } if { [using_jtag] } { set _CPU_DAP_ID $_CPU_TAPID } else { set _CPU_DAP_ID 0x2ba01477 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_DAP_ID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x2000 } $_TARGETNAME configure -work-area-phys [expr {0x20000000 - $_WORKAREASIZE / 2}] \ -work-area-size $_WORKAREASIZE -work-area-backup 0 source [find mem_helper.tcl] $_TARGETNAME configure -event reset-init { # Configure Target Device (PSoC 5LP Device Programming Specification 5.2) set PANTHER_DBG_CFG 0x4008000C set PANTHER_DBG_CFG_BYPASS [expr {1 << 1}] mmw $PANTHER_DBG_CFG $PANTHER_DBG_CFG_BYPASS 0 set PM_ACT_CFG0 0x400043A0 mww $PM_ACT_CFG0 0xBF set FASTCLK_IMO_CR 0x40004200 set FASTCLK_IMO_CR_F_RANGE_2 [expr {2 << 0}] set FASTCLK_IMO_CR_F_RANGE_MASK [expr {7 << 0}] mmw $FASTCLK_IMO_CR $FASTCLK_IMO_CR_F_RANGE_2 $FASTCLK_IMO_CR_F_RANGE_MASK } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME psoc5lp 0x00000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.eeprom psoc5lp_eeprom 0x40008000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.nvl psoc5lp_nvl 0 0 0 0 $_TARGETNAME if {![using_hla]} { cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/psoc6.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Configuration script for Cypress PSoC6 family of microcontrollers (CY8C6xxx) # PSoC6 is a dual-core device with CM0+ and CM4 cores. Both cores share # the same Flash/RAM/MMIO address space. # source [find target/swj-dp.tcl] adapter speed 1000 global _CHIPNAME if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME psoc6 } global TARGET set TARGET $_CHIPNAME.cpu swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # Is CM0 Debugging enabled ? global _ENABLE_CM0 if { [info exists ENABLE_CM0] } { set _ENABLE_CM0 $ENABLE_CM0 } else { set _ENABLE_CM0 1 } # Is CM4 Debugging enabled ? global _ENABLE_CM4 if { [info exists ENABLE_CM4] } { set _ENABLE_CM4 $ENABLE_CM4 } else { set _ENABLE_CM4 1 } global _WORKAREASIZE_CM0 if { [info exists WORKAREASIZE_CM0] } { set _WORKAREASIZE_CM0 $WORKAREASIZE_CM0 } else { set _WORKAREASIZE_CM0 0x4000 } global _WORKAREASIZE_CM4 if { [info exists WORKAREASIZE_CM4] } { set _WORKAREASIZE_CM4 $WORKAREASIZE_CM4 } else { set _WORKAREASIZE_CM4 0x4000 } global _WORKAREAADDR_CM0 if { [info exists WORKAREAADDR_CM0] } { set _WORKAREAADDR_CM0 $WORKAREAADDR_CM0 } else { set _WORKAREAADDR_CM0 0x08000000 } global _WORKAREAADDR_CM4 if { [info exists WORKAREAADDR_CM4] } { set _WORKAREAADDR_CM4 $WORKAREAADDR_CM4 } else { set _WORKAREAADDR_CM4 0x08000000 } proc init_reset { mode } { global RESET_MODE set RESET_MODE $mode if {[using_jtag]} { jtag arp_init-reset } } # Utility to make 'reset halt' work as reset;halt on a target # It does not prevent running code after reset proc psoc6_deassert_post { target } { # PSoC6 cleared AP registers including TAR during reset # Force examine to synchronize OpenOCD target status $target arp_examine global RESET_MODE global TARGET if { $RESET_MODE ne "run" } { $target arp_poll $target arp_poll set st [$target curstate] if { $st eq "reset" } { # we assume running state follows # if reset accidentally halts, waiting is useless catch { $target arp_waitstate running 100 } set st [$target curstate] } if { $st eq "running" } { echo "$target: Ran after reset and before halt..." if { $target eq "${TARGET}.cm0" } { # Try to cleanly reset whole system # and halt the CM0 at entry point psoc6 reset_halt $target arp_waitstate halted 100 } else { $target arp_halt } } } } if { $_ENABLE_CM0 } { target create ${TARGET}.cm0 cortex_m -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 ${TARGET}.cm0 configure -work-area-phys $_WORKAREAADDR_CM0 -work-area-size $_WORKAREASIZE_CM0 -work-area-backup 0 flash bank main_flash_cm0 psoc6 0x10000000 0 0 0 ${TARGET}.cm0 flash bank work_flash_cm0 psoc6 0x14000000 0 0 0 ${TARGET}.cm0 flash bank super_flash_user_cm0 psoc6 0x16000800 0 0 0 ${TARGET}.cm0 flash bank super_flash_nar_cm0 psoc6 0x16001A00 0 0 0 ${TARGET}.cm0 flash bank super_flash_key_cm0 psoc6 0x16005A00 0 0 0 ${TARGET}.cm0 flash bank super_flash_toc2_cm0 psoc6 0x16007C00 0 0 0 ${TARGET}.cm0 ${TARGET}.cm0 cortex_m reset_config sysresetreq ${TARGET}.cm0 configure -event reset-deassert-post "psoc6_deassert_post ${TARGET}.cm0" } if { $_ENABLE_CM4 } { target create ${TARGET}.cm4 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -coreid 1 ${TARGET}.cm4 configure -work-area-phys $_WORKAREAADDR_CM4 -work-area-size $_WORKAREASIZE_CM4 -work-area-backup 0 flash bank main_flash_cm4 psoc6 0x10000000 0 0 0 ${TARGET}.cm4 flash bank work_flash_cm4 psoc6 0x14000000 0 0 0 ${TARGET}.cm4 flash bank super_flash_user_cm4 psoc6 0x16000800 0 0 0 ${TARGET}.cm4 flash bank super_flash_nar_cm4 psoc6 0x16001A00 0 0 0 ${TARGET}.cm4 flash bank super_flash_key_cm4 psoc6 0x16005A00 0 0 0 ${TARGET}.cm4 flash bank super_flash_toc2_cm4 psoc6 0x16007C00 0 0 0 ${TARGET}.cm4 ${TARGET}.cm4 cortex_m reset_config vectreset ${TARGET}.cm4 configure -event reset-deassert-post "psoc6_deassert_post ${TARGET}.cm4" } if { $_ENABLE_CM0 } { # Use CM0+ by default on dual-core devices targets ${TARGET}.cm0 } if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 18 -expected-id 0x2e200069 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/pxa255.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # PXA255 chip ... originally from Intel, PXA line was sold to Marvell. # This chip is now at end-of-life. Final orders have been taken. if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME pxa255 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x69264013 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME xscale -endian $_ENDIAN \ -chain-position $_CHIPNAME.cpu # PXA255 comes out of reset using 3.6864 MHz oscillator. # Until the PLL kicks in, keep the JTAG clock slow enough # that we get no errors. adapter speed 300 $_TARGETNAME configure -event "reset-start" { adapter speed 300 } # both TRST and SRST are *required* for debug # DCSR is often accessed with SRST active reset_config trst_and_srst separate srst_nogate # reset processing that works with PXA proc init_reset {mode} { # assert both resets; equivalent to power-on reset adapter assert trst assert srst # drop TRST after at least 32 cycles sleep 1 adapter deassert trst assert srst # minimum 32 TCK cycles to wake up the controller runtest 50 # now the TAP will be responsive; validate scanchain jtag arp_init # ... and take it out of reset adapter deassert trst deassert srst } proc jtag_init {} { init_reset startup } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/pxa270.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #Marvell/Intel PXA270 Script if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME pxa270 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } #IDs for pxa270. Are there more? if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # set useful default set _CPUTAPID 0x49265013 } if { [info exists CPUTAPID2] } { set _CPUTAPID2 $CPUTAPID2 } else { # set useful default set _CPUTAPID2 0x79265013 } if { [info exists CPUTAPID3] } { set _CPUTAPID2 $CPUTAPID3 } else { # set useful default set _CPUTAPID3 0x89265013 } # set adapter srst delay to the delay introduced by your reset circuit # the rest of the needed delays are built into the openocd program adapter srst delay 260 # set the jtag_ntrst_delay to the delay introduced by a reset circuit # the rest of the needed delays are built into the openocd program jtag_ntrst_delay 250 set _TARGETNAME $_CHIPNAME.cpu jtag newtap $_CHIPNAME cpu -irlen 7 -ircapture 0x1 -irmask 0x7f -expected-id $_CPUTAPID -expected-id $_CPUTAPID2 -expected-id $_CPUTAPID3 target create $_TARGETNAME xscale -endian $_ENDIAN -chain-position $_TARGETNAME # maps to PXA internal RAM. If you are using a PXA255 # you must initialize SDRAM or leave this option off $_TARGETNAME configure -work-area-phys 0x5c000000 -work-area-size 0x10000 -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/pxa3xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Marvell PXA3xx if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME pxa3xx } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # IDs for all currently known PXA3xx chips if { [info exists CPUTAPID_PXA30X_A0] } { set _CPUTAPID_PXA30X_A0 $CPUTAPID_PXA30X_A0 } else { set _CPUTAPID_PXA30X_A0 0x0E648013 } if { [info exists CPUTAPID_PXA30X_A1] } { set _CPUTAPID_PXA30X_A1 $CPUTAPID_PXA30X_A1 } else { set _CPUTAPID_PXA30X_A1 0x1E648013 } if { [info exists CPUTAPID_PXA31X_A0] } { set _CPUTAPID_PXA31X_A0 $CPUTAPID_PXA31X_A0 } else { set _CPUTAPID_PXA31X_A0 0x0E649013 } if { [info exists CPUTAPID_PXA31X_A1] } { set _CPUTAPID_PXA31X_A1 $CPUTAPID_PXA31X_A1 } else { set _CPUTAPID_PXA31X_A1 0x1E649013 } if { [info exists CPUTAPID_PXA31X_A2] } { set _CPUTAPID_PXA31X_A2 $CPUTAPID_PXA31X_A2 } else { set _CPUTAPID_PXA31X_A2 0x2E649013 } if { [info exists CPUTAPID_PXA31X_B0] } { set _CPUTAPID_PXA31X_B0 $CPUTAPID_PXA31X_B0 } else { set _CPUTAPID_PXA31X_B0 0x3E649013 } if { [info exists CPUTAPID_PXA32X_B1] } { set _CPUTAPID_PXA32X_B1 $CPUTAPID_PXA32X_B1 } else { set _CPUTAPID_PXA32X_B1 0x5E642013 } if { [info exists CPUTAPID_PXA32X_B2] } { set _CPUTAPID_PXA32X_B2 $CPUTAPID_PXA32X_B2 } else { set _CPUTAPID_PXA32X_B2 0x6E642013 } if { [info exists CPUTAPID_PXA32X_C0] } { set _CPUTAPID_PXA32X_C0 $CPUTAPID_PXA32X_C0 } else { set _CPUTAPID_PXA32X_C0 0x7E642013 } # set adapter srst delay to the delay introduced by your reset circuit # the rest of the needed delays are built into the openocd program adapter srst delay 260 # set the jtag_ntrst_delay to the delay introduced by a reset circuit # the rest of the needed delays are built into the openocd program jtag_ntrst_delay 250 set _TARGETNAME $_CHIPNAME.cpu jtag newtap $_CHIPNAME cpu -irlen 11 -ircapture 0x1 -irmask 0x7f \ -expected-id $_CPUTAPID_PXA30X_A0 \ -expected-id $_CPUTAPID_PXA30X_A1 \ -expected-id $_CPUTAPID_PXA31X_A0 \ -expected-id $_CPUTAPID_PXA31X_A1 \ -expected-id $_CPUTAPID_PXA31X_A2 \ -expected-id $_CPUTAPID_PXA31X_B0 \ -expected-id $_CPUTAPID_PXA32X_B1 \ -expected-id $_CPUTAPID_PXA32X_B2 \ -expected-id $_CPUTAPID_PXA32X_C0 target create $_TARGETNAME xscale -endian $_ENDIAN \ -chain-position $_TARGETNAME # work area in internal RAM. $_TARGETNAME configure -work-area-phys 0x5c030000 -work-area-size 0x10000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/qn908x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # NXP QN908x Cortex-M4F with 128 KiB SRAM source [find target/swj-dp.tcl] set CHIPNAME qn908x set CHIPSERIES qn9080 if { ![info exists WORKAREASIZE] } { set WORKAREASIZE 0x20000 } # SWD IDCODE (Cortex M4). set CPUTAPID 0x2ba01477 swj_newdap $CHIPNAME cpu -irlen 4 -expected-id $CPUTAPID dap create $CHIPNAME.dap -chain-position $CHIPNAME.cpu set TARGETNAME $CHIPNAME.cpu target create $TARGETNAME cortex_m -dap $CHIPNAME.dap # SRAM is mapped at 0x04000000. $TARGETNAME configure -work-area-phys 0x04000000 -work-area-size $WORKAREASIZE # flash bank <name> qn908x <base> <size> 0 0 <target#> [calc_checksum] # The base must be set as 0x01000000, and the size parameter is unused. set FLASHNAME $CHIPNAME.flash flash bank $FLASHNAME qn908x 0x01000000 0 0 0 $TARGETNAME calc_checksum # We write directly to flash memory over this adapter interface. For debugging # this could in theory be faster (the Core clock on reset is normally at 32MHz), # but for flashing 1MHz is more reliable. adapter speed 1000 # Delay on reset line. adapter srst delay 200 cortex_m reset_config sysresetreq ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/qualcomm_qca4531.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # The QCA4531 is a two stream (2x2) 802.11b/g/n single-band programmable # Wi-Fi System-on-Chip (SoC) for the Internet of Things (IoT). # # Product page: # https://www.qualcomm.com/products/qca4531 # # Notes: # - MIPS Processor ID (PRId): 0x00019374 # - 24Kc MIPS processor with 64 KB I-Cache and 32 KB D-Cache, # operating at up to 650 MHz # - External 16-bit DDR1, operating at up to 200 MHz, DDR2 operating at up # to 300 MHz # - TRST is not available. # - EJTAG PrRst signal is not supported # - RESET_L pin B56 on the SoC will reset internal JTAG logic. # # Pins related for debug and bootstrap: # Name Pin Description # JTAG # JTAG_TCK GPIO0, (A27) Software configurable, default JTAG # JTAG_TDI GPIO1, (B23) Software configurable, default JTAG # JTAG_TDO GPIO2, (A28) Software configurable, default JTAG # JTAG_TMS GPIO3, (A29) Software configurable, default JTAG # Reset # RESET_L -, (B56) Input only # SYS_RST_L GPIO17, (A79) Output reset request or GPIO # Bootstrap # JTAG_MODE GPIO16, (A78) 0 - JTAG (Default); 1 - EJTAG # DDR_SELECT GPIO10, (A57) 0 - DDR2; 1 - DDR1 # UART # UART0_SOUT GPIO10, (A57) # UART0_SIN GPIO9, (B49) # Per default we need to use "none" variant to be able properly "reset init" # or "reset halt" the CPU. reset_config none srst_pulls_trst # For SRST based variant we still need proper timings. # For ETH part the reset should be asserted at least for 10ms # Since there is no other information let's take 100ms to be sure. adapter srst pulse_width 100 # according to the SoC documentation it should take at least 5ms from # reset end till bootstrap end. In the practice we need 8ms to get JTAG back # to live. adapter srst delay 8 if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { set _CHIPNAME qca4531 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00000001 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME # provide watchdog helper. proc disable_watchdog { } { mww 0xb8060008 0x0 } $_TARGETNAME configure -event halted { disable_watchdog } # Since PrRst is not supported and SRST will reset complete chip # with JTAG engine, we need to reset CPU from CPU itself. $_TARGETNAME configure -event reset-assert-pre { halt } $_TARGETNAME configure -event reset-assert { catch "mww 0xb806001C 0x01000000" } # To be able to trigger complete chip reset, in case JTAG is blocked # or CPU not responding, we still can use this helper. proc full_reset { } { reset_config srst_only reset halt reset_config none } # Section with helpers which can be used by boards proc qca4531_ddr2_550_550_init {} { # Clear reset flags for different SoC components mww 0xb806001c 0xfeceffff mww 0xb806001c 0xeeceffff mww 0xb806001c 0xe6ceffff # PMU configurations # Internal Switcher mww 0xb8116c40 0x633c8176 # Increase the DDR voltage mww 0xb8116c44 0x10200000 # XTAL Configurations mww 0xb81162c0 0x4b962100 mww 0xb81162c4 0x480 mww 0xb81162c8 0x04000144 # Recommended PLL configurations mww 0xb81161c4 0x54086000 mww 0xb8116244 0x54086000 # PLL init mww 0xb8050008 0x0131001c mww 0xb8050000 0x40001580 mww 0xb8050004 0x40015800 mww 0xb8050008 0x0131001c mww 0xb8050000 0x00001580 mww 0xb8050004 0x00015800 mww 0xb8050008 0x01310000 mww 0xb8050044 0x781003ff mww 0xb8050048 0x003c103f # DDR2 init mww 0xb8000108 0x401f0042 mww 0xb80000b8 0x0000166d mww 0xb8000000 0xcfaaf33b mww 0xb800015c 0x0000000f mww 0xb8000004 0xa272efa8 mww 0xb8000018 0x0000ffff mww 0xb80000c4 0x74444444 mww 0xb80000c8 0x00000444 mww 0xb8000004 0xa210ee28 mww 0xb8000004 0xa2b2e1a8 mww 0xb8000010 0x8 mww 0xb80000bc 0x0 mww 0xb8000010 0x10 mww 0xb80000c0 0x0 mww 0xb8000010 0x40 mww 0xb800000c 0x2 mww 0xb8000010 0x2 mww 0xb8000008 0xb43 mww 0xb8000010 0x1 mww 0xb8000010 0x8 mww 0xb8000010 0x4 mww 0xb8000010 0x4 mww 0xb8000008 0xa43 mww 0xb8000010 0x1 mww 0xb800000c 0x382 mww 0xb8000010 0x2 mww 0xb800000c 0x402 mww 0xb8000010 0x2 mww 0xb8000014 0x40be mww 0xb800001C 0x20 mww 0xb8000020 0x20 mww 0xb80000cc 0xfffff # UART GPIO programming mww 0xb8040000 0xff30b mww 0xb8040044 0x908 mww 0xb8040034 0x160000 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/quark_d20xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x38289013 } jtag newtap quark_d20xx quark -irlen 8 -irmask 0xff -expected-id $_CPUTAPID -disable jtag newtap quark_d20xx cltap -irlen 8 -irmask 0xff -expected-id 0x0e786013 -enable proc quark_d20xx_tapenable {} { echo "enabling quark core tap" irscan quark_d20xx.cltap 0x11 drscan quark_d20xx.cltap 12 1 runtest 10 } proc quark_d20xx_tapdisable {} { echo "disabling quark core tap" irscan quark_d20xx.cltap 0x11 drscan quark_d20xx.cltap 12 0 runtest 10 } proc quark_d20xx_setup {} { jtag tapenable quark_d20xx.quark } jtag configure quark_d20xx.quark -event tap-enable \ "quark_d20xx_tapenable" jtag configure quark_d20xx.quark -event tap-disable \ "quark_d20xx_tapdisable" target create quark_d20xx.quark quark_d20xx -endian little -chain-position quark_d20xx.quark quark_d20xx.quark configure -event reset-start { # need to halt the target to write to memory if {[quark_d20xx.quark curstate] ne "halted"} { halt } # set resetbreak via the core tap irscan quark_d20xx.quark 0x35 ; drscan quark_d20xx.quark 1 0x1 # trigger a warm reset mww 0xb0800570 0x2 # clear resetbreak irscan quark_d20xx.quark 0x35 ; drscan quark_d20xx.quark 1 0x0 } jtag configure quark_d20xx.quark -event setup \ "quark_d20xx_setup" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/quark_x10xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME quark_x10xx } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x18289013 } jtag newtap quark_x10xx cpu -irlen 8 -irmask 0xff -expected-id $_CPUTAPID -disable jtag newtap quark_x10xx cltap -irlen 8 -irmask 0xff -expected-id 0x0e681013 -enable #openocd puts tap at front of chain not end of chain proc quark_x10xx_tapenable {} { echo "enabling core tap" irscan quark_x10xx.cltap 0x11 drscan quark_x10xx.cltap 64 1 runtest 10 } proc quark_x10xx_tapdisable {} { echo "disabling core tap" irscan quark_x10xx.cltap 0x11 drscan quark_x10xx.cltap 64 0 runtest 10 } proc quark_x10xx_setup {} { jtag tapenable quark_x10xx.cpu } jtag configure $_CHIPNAME.cpu -event tap-enable \ "quark_x10xx_tapenable" jtag configure $_CHIPNAME.cpu -event tap-disable \ "quark_x10xx_tapdisable" set _TARGETNAME $_CHIPNAME.cpu target create quark_x10xx.cpu quark_x10xx -endian $_ENDIAN -chain-position quark_x10xx.cpu jtag configure $_CHIPNAME.cpu -event setup \ "quark_x10xx_setup" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/readme.txt ================================================ # SPDX-License-Identifier: GPL-2.0-or-later Prerequisites: The users of OpenOCD as well as computer programs interacting with OpenOCD are expecting that certain commands do the same thing across all the targets. Rules to follow when writing scripts: 1. The configuration script should be defined such as , for example, the following sequences are working: reset flash info <bank> and reset flash erase_address <start> <len> and reset init load In most cases this can be accomplished by specifying the default startup mode as reset_init (target command in the configuration file). 2. If the target is correctly configured, flash must be writable without any other helper commands. It is assumed that all write-protect mechanisms should be disabled. 3. The configuration scripts should be defined such as the binary that was written to flash verifies (turn off remapping, checksums, etc...) flash write_image [file] <parameters> verify_image [file] <parameters> 4. adapter speed sets the maximum speed (or alternatively RCLK). If invoked multiple times only the last setting is used. interface/xxx.cfg files are always executed *before* target/xxx.cfg files, so any adapter speed in interface/xxx.cfg will be overridden by target/xxx.cfg. adapter speed in interface/xxx.cfg would then, effectively, set the default JTAG speed. Note that a target/xxx.cfg file can invoke another target/yyy.cfg file, so one can create target subtype configurations where e.g. only amount of DRAM, oscillator speeds differ and having a single config file for the default/common settings. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/renesas_r7s72100.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas RZ/A1H # https://www.renesas.com/eu/en/products/microcontrollers-microprocessors/rz/rza/rza1h.html if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME r7s72100 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID # Configuring only one core using DAP. # Base addresses of cores: # core 0 - 0x80030000 set _TARGETNAME $_CHIPNAME.ca9 dap create ${_CHIPNAME}.dap -chain-position $_CHIPNAME.cpu target create ${_TARGETNAME} cortex_a -dap ${_CHIPNAME}.dap -coreid 0 -dbgbase 0x80030000 targets ${_TARGETNAME} ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/renesas_rcar_gen2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas R-Car Generation 2 SOCs # - There are a combination of Cortex-A15s and Cortex-A7s for each Gen2 SOC # - Each SOC can boot through any of the, up to 2, core types that it has # e.g. H2 can boot through Cortex-A15 or Cortex-A7 # Supported Gen2 SOCs and their cores: # H2: Cortex-A15 x 4, Cortex-A7 x 4 # M2: Cortex-A15 x 2 # V2H: Cortex-A15 x 2 # M2N: Cortex-A15 x 2 # E2: Cortex-A7 x 2 # Usage: # There are 2 configuration options: # SOC: Selects the supported SOC. (Default 'H2') # BOOT_CORE: Selects the booting core. 'CA15', or 'CA7' # Defaults to 'CA15' if the SOC has one, else defaults to 'CA7' if { [info exists SOC] } { set _soc $SOC } else { set _soc H2 } # Set configuration for each SOC and the default 'BOOT_CORE' switch $_soc { H2 { set _CHIPNAME r8a7790 set _num_ca15 4 set _num_ca7 4 set _boot_core CA15 } M2 { set _CHIPNAME r8a7791 set _num_ca15 2 set _num_ca7 0 set _boot_core CA15 } V2H { set _CHIPNAME r8a7792 set _num_ca15 2 set _num_ca7 0 set _boot_core CA15 } M2N { set _CHIPNAME r8a7793 set _num_ca15 2 set _num_ca7 0 set _boot_core CA15 } E2 { set _CHIPNAME r8a7794 set _num_ca15 0 set _num_ca7 2 set _boot_core CA7 } default { error "'$_soc' is invalid!" } } # If configured, override the default 'CHIPNAME' if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } # If configured, override the default 'BOOT_CORE' if { [info exists BOOT_CORE] } { set _boot_core $BOOT_CORE } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4ba00477 } echo "\t$_soc - $_num_ca15 CA15(s), $_num_ca7 CA7(s)" echo "\tBoot Core - $_boot_core\n" set _DAPNAME $_CHIPNAME.dap # TAP and DAP jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID dap create $_DAPNAME -chain-position $_CHIPNAME.cpu set CA15_DBGBASE {0x800B0000 0x800B2000 0x800B4000 0x800B6000} set CA7_DBGBASE {0x800F0000 0x800F2000 0x800F4000 0x800F6000} set _targets "" set smp_targets "" proc setup_ca {core_name dbgbase num boot} { global _CHIPNAME global _DAPNAME global smp_targets global _targets for { set _core 0 } { $_core < $num } { incr _core } { set _TARGETNAME $_CHIPNAME.$core_name.$_core set _CTINAME $_TARGETNAME.cti set _command "target create $_TARGETNAME cortex_a -dap $_DAPNAME \ -coreid $_core -dbgbase [lindex $dbgbase $_core]" if { $_core == 0 && $boot == 1 } { set _targets "$_TARGETNAME" } else { set _command "$_command -defer-examine" } set smp_targets "$smp_targets $_TARGETNAME" eval $_command } } # Organize target list based on the boot core if { [string equal $_boot_core CA15] } { setup_ca a15 $CA15_DBGBASE $_num_ca15 1 setup_ca a7 $CA7_DBGBASE $_num_ca7 0 } elseif { [string equal $_boot_core CA7] } { setup_ca a7 $CA7_DBGBASE $_num_ca7 1 setup_ca a15 $CA15_DBGBASE $_num_ca15 0 } else { setup_ca a15 $CA15_DBGBASE $_num_ca15 0 setup_ca a7 $CA7_DBGBASE $_num_ca7 0 } source [find target/renesas_rcar_reset_common.cfg] eval "target smp $smp_targets" targets $_targets ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/renesas_rcar_gen3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas R-Car Generation 3 SOCs # - There are a combination of Cortex-A57s, Cortex-A53s, and Cortex-R7 for each Gen3 SOC # - Each SOC can boot through any of the, up to 3, core types that it has # e.g. H3 can boot through Cortex-A57, Cortex-A53, or Cortex-R7 # Supported Gen3 SOCs and their cores: # H3: Cortex-A57 x 4, Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step) # M3W: Cortex-A57 x 2, Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step) # M3N: Cortex-A57 x 2, Cortex-R7 x 2 (Lock-Step) # V3U: Cortex-A76 x 8, Cortex-R52 x2 (Lock-Step) # V3H: Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step) # V3M: Cortex-A53 x 2, Cortex-R7 x 2 (Lock-Step) # E3: Cortex-A53 x 1, Cortex-R7 x 2 (Lock-Step) # D3: Cortex-A53 x 1 # Usage: # There are 2 configuration options: # SOC: Selects the supported SOC. (Default 'H3') # BOOT_CORE: Selects the booting core. 'CA57', 'CA53', or 'CR7' # Defaults to 'CA57' if the SOC has one, else defaults to 'CA53' if { [info exists SOC] } { set _soc $SOC } else { set _soc H3 } set _num_ca53 0 set _num_ca57 0 set _num_ca76 0 set _num_cr52 0 set _num_cr7 0 # Set configuration for each SOC and the default 'BOOT_CORE' switch $_soc { H3 { set _CHIPNAME r8a77950 set _num_ca57 4 set _num_ca53 4 set _num_cr7 1 set _boot_core CA57 } M3W { set _CHIPNAME r8a77960 set _num_ca57 2 set _num_ca53 4 set _num_cr7 1 set _boot_core CA57 } M3N { set _CHIPNAME r8a77965 set _num_ca57 2 set _num_ca53 4 set _num_cr7 1 set _boot_core CA57 } V3M { set _CHIPNAME r8a77970 set _num_ca57 0 set _num_ca53 2 set _num_cr7 1 set _boot_core CA53 } V3H { set _CHIPNAME r8a77980 set _num_ca57 0 set _num_ca53 4 set _num_cr7 1 set _boot_core CA53 } E3 { set _CHIPNAME r8a77990 set _num_ca57 0 set _num_ca53 1 set _num_cr7 1 set _boot_core CA53 } D3 { set _CHIPNAME r8a77995 set _num_ca57 0 set _num_ca53 1 set _num_cr7 0 set _boot_core CA53 } V3U { set _CHIPNAME r8a779a0 set _num_ca76 8 set _num_cr52 1 set _boot_core CA76 } default { error "'$_soc' is invalid!" } } # If configured, override the default 'CHIPNAME' if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } # If configured, override the default 'BOOT_CORE' if { [info exists BOOT_CORE] } { set _boot_core $BOOT_CORE } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } echo "\t$_soc - $_num_ca76 CA76(s), $_num_ca57 CA57(s), $_num_ca53 CA53(s), $_num_cr52 CR52(s), $_num_cr7 CR7(s)" echo "\tBoot Core - $_boot_core\n" set _DAPNAME $_CHIPNAME.dap # TAP and DAP jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID dap create $_DAPNAME -chain-position $_CHIPNAME.cpu set CA76_DBGBASE {0x81410000 0x81510000 0x81610000 0x81710000 0x81c10000 0x81d10000 0x81e10000 0x81f10000} set CA76_CTIBASE {0x81420000 0x81520000 0x81620000 0x81720000 0x81c20000 0x81d20000 0x81e20000 0x81f20000} set CA57_DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} set CA57_CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} set CA53_DBGBASE {0x80C10000 0x80D10000 0x80E10000 0x80F10000} set CA53_CTIBASE {0x80C20000 0x80D20000 0x80E20000 0x80F20000} set CR52_DBGBASE 0x80c10000 set CR52_CTIBASE 0x80c20000 set CR7_DBGBASE 0x80910000 set CR7_CTIBASE 0x80918000 set _targets "" set smp_targets "" proc setup_a5x {core_name dbgbase ctibase num boot} { global _CHIPNAME global _DAPNAME global smp_targets global _targets for { set _core 0 } { $_core < $num } { incr _core } { set _TARGETNAME $_CHIPNAME.$core_name.$_core set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $_DAPNAME -ap-num 1 \ -baseaddr [lindex $ctibase $_core] set _command "target create $_TARGETNAME aarch64 -dap $_DAPNAME \ -ap-num 1 -dbgbase [lindex $dbgbase $_core] -cti $_CTINAME" if { $_core == 0 && $boot == 1 } { set _targets "$_TARGETNAME" } else { set _command "$_command -defer-examine" } set smp_targets "$smp_targets $_TARGETNAME" eval $_command } } proc setup_crx {core_name dbgbase ctibase num boot} { global _CHIPNAME global _DAPNAME for { set _core 0 } { $_core < $num } { incr _core } { set _TARGETNAME $_CHIPNAME.$core_name set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -baseaddr $ctibase if { $core_name == "r52" } { set _command "target create $_TARGETNAME armv8r -dap $_DAPNAME \ -ap-num 1 -dbgbase $dbgbase -cti $_CTINAME" } else { set _command "target create $_TARGETNAME cortex_r4 -dap $_DAPNAME \ -ap-num 1 -dbgbase $dbgbase" } if { $boot == 1 } { set _targets "$_TARGETNAME" } else { set _command "$_command -defer-examine" } eval $_command } } # Organize target list based on the boot core if { [string equal $_boot_core CA76] } { setup_a5x a76 $CA76_DBGBASE $CA76_CTIBASE $_num_ca76 1 setup_crx r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 0 } elseif { [string equal $_boot_core CA57] } { setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 1 setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0 setup_crx r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0 } elseif { [string equal $_boot_core CA53] } { setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 1 setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0 setup_crx r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0 } elseif { [string equal $_boot_core CR52] } { setup_crx r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 1 setup_a5x a76 $CA76_DBGBASE $CA76_CTIBASE $_num_ca76 0 } else { setup_crx r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 1 setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0 setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0 } source [find target/renesas_rcar_reset_common.cfg] eval "target smp $smp_targets" targets $_targets ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/renesas_rcar_reset_common.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas R-Car Gen2 Evaluation Board common settings reset_config trst_and_srst srst_nogate proc init_reset {mode} { # Assert both resets: equivalent to a power-on reset adapter assert trst assert srst # Deassert TRST to begin TAP communication adapter deassert trst assert srst # TAP should now be responsive, validate the scan-chain jtag arp_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/renesas_rz_five.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas RZ/Five SoC # # General-purpose Microprocessors with RISC-V CPU Core (Andes AX45MP Single) (1.0 GHz) transport select jtag reset_config trst_and_srst srst_gates_jtag adapter speed 4000 adapter srst delay 500 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME r9A07g043u } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/renesas_rz_g2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Renesas RZ/G2 SOCs # - There are a combination of Cortex-A57s, Cortex-A53s, Cortex-A55, Cortex-R7 # and Cortex-M33 for each SOC # - Each SOC can boot through the Cortex-A5x cores # Supported RZ/G2 SOCs and their cores: # RZ/G2H: Cortex-A57 x4, Cortex-A53 x4, Cortex-R7 # RZ/G2M: Cortex-A57 x2, Cortex-A53 x4, Cortex-R7 # RZ/G2N: Cortex-A57 x2, Cortex-R7 # RZ/G2E: Cortex-A53 x2, Cortex-R7 # RZ/G2L: Cortex-A55 x2, Cortex-M33 # RZ/G2LC: Cortex-A55 x2, Cortex-M33 # RZ/G2UL: Cortex-A55 x1, Cortex-M33 # Usage: # There are 2 configuration options: # SOC: Selects the supported SOC. (Default 'G2L') # BOOT_CORE: Selects the booting core. 'CA57', 'CA53' or 'CA55' transport select jtag reset_config trst_and_srst srst_gates_jtag adapter speed 4000 adapter srst delay 500 if { [info exists SOC] } { set _soc $SOC } else { set _soc G2L } set _num_ca57 0 set _num_ca55 0 set _num_ca53 0 set _num_cr7 0 set _num_cm33 0 # Set configuration for each SOC and the default 'BOOT_CORE' switch $_soc { G2H { set _CHIPNAME r8a774ex set _num_ca57 4 set _num_ca53 4 set _num_cr7 1 set _boot_core CA57 set _ap_num 1 } G2M { set _CHIPNAME r8a774ax set _num_ca57 2 set _num_ca53 4 set _num_cr7 1 set _boot_core CA57 set _ap_num 1 } G2N { set _CHIPNAME r8a774bx set _num_ca57 2 set _num_ca53 0 set _num_cr7 1 set _boot_core CA57 set _ap_num 1 } G2E { set _CHIPNAME r8a774c0 set _num_ca57 0 set _num_ca53 2 set _num_cr7 1 set _boot_core CA53 set _ap_num 1 } G2L { set _CHIPNAME r9a07g044l set _num_ca55 2 set _num_cm33 1 set _boot_core CA55 set _ap_num 0 } G2LC { set _CHIPNAME r9a07g044c set _num_ca55 2 set _num_cm33 1 set _boot_core CA55 set _ap_num 0 } G2UL { set _CHIPNAME r9a07g043u set _num_ca55 1 set _num_cm33 1 set _boot_core CA55 set _ap_num 0 } default { error "'$_soc' is invalid!" } } # If configured, override the default 'CHIPNAME' if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } # If configured, override the default 'BOOT_CORE' if { [info exists BOOT_CORE] } { set _boot_core $BOOT_CORE } if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x6ba00477 } echo "\t$_soc - $_num_ca57 CA57(s), $_num_ca55 CA55(s), $_num_ca53 CA53(s), $_num_cr7 CR7(s), \ $_num_cm33 CM33(s)" echo "\tBoot Core - $_boot_core\n" set _DAPNAME $_CHIPNAME.dap # TAP and DAP jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID \ -ignore-version dap create $_DAPNAME -chain-position $_CHIPNAME.cpu echo "$_CHIPNAME.cpu" set CA57_DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} set CA57_CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} set CA55_DBGBASE {0x10E10000 0x10F10000} set CA55_CTIBASE {0x10E20000 0x10F20000} set CA53_DBGBASE {0x80C10000 0x80D10000 0x80E10000 0x80F10000} set CA53_CTIBASE {0x80C20000 0x80D20000 0x80E20000 0x80F20000} set CR7_DBGBASE 0x80910000 set CR7_CTIBASE 0x80918000 set CM33_DBGBASE 0xE000E000 set CM33_CTIBASE 0xE0042000 set smp_targets "" proc setup_a5x {core_name dbgbase ctibase num boot} { for { set _core 0 } { $_core < $num } { incr _core } { set _TARGETNAME $::_CHIPNAME.$core_name.$_core set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $::_DAPNAME -ap-num $::_ap_num \ -baseaddr [lindex $ctibase $_core] target create $_TARGETNAME aarch64 -dap $::_DAPNAME \ -ap-num $::_ap_num -dbgbase [lindex $dbgbase $_core] -cti $_CTINAME if { $_core > 0 || $boot == 0 } { $_TARGETNAME configure -defer-examine } set ::smp_targets "$::smp_targets $_TARGETNAME" } } proc setup_cr7 {dbgbase ctibase} { set _TARGETNAME $::_CHIPNAME.r7 set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $::_DAPNAME -ap-num 1 -baseaddr $ctibase target create $_TARGETNAME cortex_r4 -dap $::_DAPNAME \ -ap-num 1 -dbgbase $dbgbase -defer-examine } proc setup_cm33 {dbgbase ctibase} { set _TARGETNAME $::_CHIPNAME.m33 set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $::_DAPNAME -ap-num 2 -baseaddr $ctibase target create $_TARGETNAME cortex_m -dap $::_DAPNAME \ -ap-num 2 -dbgbase $dbgbase -defer-examine } # Organize target list based on the boot core if { $_boot_core == "CA57" } { setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 1 setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0 setup_cr7 $CR7_DBGBASE $CR7_CTIBASE } elseif { $_boot_core == "CA53" } { setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 1 setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0 setup_cr7 $CR7_DBGBASE $CR7_CTIBASE } elseif { $_boot_core == "CA55" } { setup_a5x a55 $CA55_DBGBASE $CA55_CTIBASE $_num_ca55 1 setup_cm33 $CM33_DBGBASE $CM33_CTIBASE } echo "SMP targets:$smp_targets" eval "target smp $smp_targets" if { $_soc == "G2L" || $_soc == "G2LC" || $_soc == "G2UL" } { target create $_CHIPNAME.axi_ap mem_ap -dap $_DAPNAME -ap-num 1 } proc init_reset {mode} { # Assert both resets: equivalent to a power-on reset adapter assert trst assert srst # Deassert TRST to begin TAP communication adapter deassert trst assert srst # TAP should now be responsive, validate the scan-chain jtag arp_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/renesas_s7g2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Renesas Synergy S7 G2 w/ ARM Cortex-M4 @ 240 MHz # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME s7g2 } if { [info exists CPU_JTAG_TAPID] } { set _CPU_JTAG_TAPID $CPU_JTAG_TAPID } else { set _CPU_JTAG_TAPID 0x5ba00477 } if { [info exists CPU_SWD_TAPID] } { set _CPU_SWD_TAPID $CPU_SWD_TAPID } else { set _CPU_SWD_TAPID 0x5ba02477 } source [find target/swj-dp.tcl] if { [using_jtag] } { set _CPU_TAPID $_CPU_JTAG_TAPID } else { set _CPU_TAPID $_CPU_SWD_TAPID } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { # 640 KB On-Chip SRAM set _WORKAREASIZE 0xa0000 } $_TARGETNAME configure -work-area-phys 0x1ffe0000 \ -work-area-size $_WORKAREASIZE -work-area-backup 0 if { ![using_hla] } { cortex_m reset_config sysresetreq } adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/rk3308.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Rockchip RK3308 Target # https://rockchip.fr/RK3308%20datasheet%20V1.5.pdf # https://dl.radxa.com/rockpis/docs/hw/datasheets/Rockchip%20RK3308TRM%20V1.1%20Part1-20180810.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME rk3308 } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x2ba01477 } adapter speed 12000 transport select swd # declare the one SWD tap to access the DAP swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID -ignore-version # create the DAP dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 # declare the 4 main application cores set _TARGETNAME $_CHIPNAME.core set _smp_command "" set $_TARGETNAME.base(0) 0x81010000 set $_TARGETNAME.base(1) 0x81012000 set $_TARGETNAME.base(2) 0x81014000 set $_TARGETNAME.base(3) 0x81016000 set $_TARGETNAME.cti(0) 0x81018000 set $_TARGETNAME.cti(1) 0x81019000 set $_TARGETNAME.cti(2) 0x8101a000 set $_TARGETNAME.cti(3) 0x8101b000 set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core \ -dbgbase [set $_TARGETNAME.base($_core)]" if { $_core != 0 } { set _smp_command "$_smp_command ${_TARGETNAME}$_core" set _command "$_command -defer-examine" } else { # uncomment to use hardware threads pseudo rtos # set _command "$_command -rtos hwthread" set _command "$_command -work-area-size 0x40000 -work-area-phys 0xfff80000 \ -work-area-backup 0" set _smp_command "target smp ${_TARGETNAME}$_core" } eval $_command } eval $_smp_command targets ${_TARGETNAME}0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/rk3399.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Rockchip RK3399 Target # https://rockchip.fr/RK3399%20datasheet%20V1.8.pdf # https://rockchip.fr/Rockchip%20RK3399%20TRM%20V1.4%20Part1.pdf if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME rk3399 } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba02477 } adapter speed 12000 transport select swd # declare the one SWD tap to access the DAP swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID -ignore-version # create the DAP dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 set _TARGETNAME $_CHIPNAME.lcore # declare the 6 main application cores set _smp_command "" set $_TARGETNAME.base(0) 0x80030000 set $_TARGETNAME.base(1) 0x80032000 set $_TARGETNAME.base(2) 0x80034000 set $_TARGETNAME.base(3) 0x80036000 set $_TARGETNAME.cti(0) 0x80038000 set $_TARGETNAME.cti(1) 0x80039000 set $_TARGETNAME.cti(2) 0x8003a000 set $_TARGETNAME.cti(3) 0x8003b000 set _TARGETNAME $_CHIPNAME.bcore set $_TARGETNAME.base(4) 0x80210000 set $_TARGETNAME.base(5) 0x80310000 set $_TARGETNAME.cti(4) 0x80220000 set $_TARGETNAME.cti(5) 0x80320000 set _cores 6 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { if {$_core < 4} { set _TARGETNAME $_CHIPNAME.lcore } else { set _TARGETNAME $_CHIPNAME.bcore } cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 1 target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core \ -dbgbase [set $_TARGETNAME.base($_core)] if { $_core != 0 } { ${_TARGETNAME}$_core configure -defer-examine } else { # uncomment to use hardware threads pseudo rtos # ${_TARGETNAME}$_core configure -rtos hwthread" ${_TARGETNAME}$_core configure -work-area-size 0x30000 -work-area-phys 0xff8c0000 \ -work-area-backup 0 } set _smp_command "$_smp_command ${_TARGETNAME}$_core" } target smp $_smp_command targets rk3399.lcore0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/rp2040.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # RP2040 is a microcontroller with dual Cortex-M0+ core. # https://www.raspberrypi.com/documentation/microcontrollers/rp2040.html # The device requires multidrop SWD for debug. transport select swd source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME rp2040 } if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x10000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x01002927 } # Set to '1' to start rescue mode if { [info exists RESCUE] } { set _RESCUE $RESCUE } else { set _RESCUE 0 } # Set to '0' or '1' for single core configuration, 'SMP' for -rtos hwthread # handling of both cores, anything else for isolated debugging of both cores if { [info exists USE_CORE] } { set _USE_CORE $USE_CORE } else { set _USE_CORE SMP } set _BOTH_CORES [expr { $_USE_CORE != 0 && $_USE_CORE != 1 }] swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID # The rescue debug port uses the DP CTRL/STAT bit DBGPWRUPREQ to reset the # PSM (power on state machine) of the RP2040 with a flag set in the # VREG_AND_POR_CHIP_RESET register. Once the reset is released # (by clearing the DBGPWRUPREQ flag), the bootrom will run, see this flag, # and halt. Allowing the user to load some fresh code, rather than loading # the potentially broken code stored in flash if { $_RESCUE } { dap create $_CHIPNAME.rescue_dap -chain-position $_CHIPNAME.cpu -dp-id $_CPUTAPID -instance-id 0xf -ignore-syspwrupack init # Clear DBGPWRUPREQ $_CHIPNAME.rescue_dap dpreg 0x4 0x00000000 # Verifying CTRL/STAT is 0 set _CTRLSTAT [$_CHIPNAME.rescue_dap dpreg 0x4] if {[expr {$_CTRLSTAT & 0xf0000000}]} { echo "Rescue failed, DP CTRL/STAT readback $_CTRLSTAT" } else { echo "Now restart OpenOCD without RESCUE flag and load code to RP2040" } shutdown } # core 0 if { $_USE_CORE != 1 } { dap create $_CHIPNAME.dap0 -chain-position $_CHIPNAME.cpu -dp-id $_CPUTAPID -instance-id 0 set _TARGETNAME_0 $_CHIPNAME.core0 target create $_TARGETNAME_0 cortex_m -dap $_CHIPNAME.dap0 -coreid 0 # srst does not exist; use SYSRESETREQ to perform a soft reset $_TARGETNAME_0 cortex_m reset_config sysresetreq } # core 1 if { $_USE_CORE != 0 } { dap create $_CHIPNAME.dap1 -chain-position $_CHIPNAME.cpu -dp-id $_CPUTAPID -instance-id 1 set _TARGETNAME_1 $_CHIPNAME.core1 target create $_TARGETNAME_1 cortex_m -dap $_CHIPNAME.dap1 -coreid 1 $_TARGETNAME_1 cortex_m reset_config sysresetreq } if {[string compare $_USE_CORE SMP] == 0} { $_TARGETNAME_0 configure -rtos hwthread $_TARGETNAME_1 configure -rtos hwthread target smp $_TARGETNAME_0 $_TARGETNAME_1 } if { $_USE_CORE == 1 } { set _FLASH_TARGET $_TARGETNAME_1 } else { set _FLASH_TARGET $_TARGETNAME_0 } # Backup the work area. The flash probe runs an algorithm on the target CPU. # The flash is probed during gdb connect if gdb_memory_map is enabled (by default). $_FLASH_TARGET configure -work-area-phys 0x20010000 -work-area-size $_WORKAREASIZE -work-area-backup 1 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME rp2040_flash 0x10000000 0 0 0 $_FLASH_TARGET if { $_BOTH_CORES } { # Alias to ensure gdb connecting to core 1 gets the correct memory map flash bank $_CHIPNAME.alias virtual 0x10000000 0 0 0 $_TARGETNAME_1 $_FLASHNAME # Select core 0 targets $_TARGETNAME_0 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/rsl10.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # RSL10: ARM Cortex-M3 # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME rsl10 } if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x8000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x2ba01477 } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x200000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # TODO: configure reset # reset_config srst_only srst_nogate connect_assert_srst $_TARGETNAME configure -event examine-fail rsl10_lock_warning proc rsl10_check_connection {} { set target [target current] set dap [$target cget -dap] set IDR [$dap apreg 0 0xfc] if {$IDR != 0x24770011} { echo "Error: Cannot access RSL10 AP, maybe connection problem!" return 1 } return 0 } proc rsl10_lock_warning {} { if {[rsl10_check_connection]} {return} poll off echo "****** WARNING ******" echo "RSL10 device probably has lock engaged." echo "Debug access is denied." echo "Use 'rsl10 unlock key1 key2 key3 key4' to erase and unlock the device." echo "****** ....... ******" echo "" } flash bank $_CHIPNAME.main rsl10 0x00100000 0x60000 0 0 $_TARGETNAME flash bank $_CHIPNAME.nvr1 rsl10 0x00080000 0x800 0 0 $_TARGETNAME flash bank $_CHIPNAME.nvr2 rsl10 0x00080800 0x800 0 0 $_TARGETNAME flash bank $_CHIPNAME.nvr3 rsl10 0x00081000 0x800 0 0 $_TARGETNAME # TODO: implement flashing for nvr4 # flash bank $_CHIPNAME.nvr4 rsl10 0x00081800 0x400 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/samsung_s3c2410.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Found on the 'TinCanTools' Hammer board. if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME s3c2410 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # This config file was defaulting to big endian.. set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # Force an error until we get a good number. set _CPUTAPID 0xffffffff } #use combined on interfaces or targets that cannot set TRST/SRST separately reset_config trst_and_srst #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm920t -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x30800000 -work-area-size 0x20000 -work-area-backup 0 # speed up memory downloads arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/samsung_s3c2440.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Target configuration for the Samsung 2440 system on chip # Tested on a S3C2440 Evaluation board by keesj # Processor : ARM920Tid(wb) rev 0 (v4l) # Info: JTAG tap: s3c2440.cpu tap/device found: 0x0032409d (Manufacturer: 0x04e, Part: 0x0324, Version: 0x0) if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME s3c2440 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a bigendian set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0032409d } #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm920t -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x200000 -work-area-size 0x4000 -work-area-backup 1 #reset configuration reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/samsung_s3c2450.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Target configuration for the Samsung 2450 system on chip # Processor : ARM926ejs (wb) rev 0 (v4l) # Info: JTAG tap: s3c2450.cpu tap/device found: 0x07926F0F # FIX!!! what to use here? # # RCLK? # # adapter speed 0 # # Really low clock during reset? # # adapter speed 1 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME s3c2450 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a bigendian set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926f0f } #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0xE -irmask 0x0f -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME # FIX!!!!! should this really use srst_pulls_trst? # With srst_pulls_trst "reset halt" will not reset into the # halted mode, but rather "reset run" and then halt the target. # # However, without "srst_pulls_trst", then "reset halt" produces weird # errors: # WARNING: unknown debug reason: 0x0 reset_config trst_and_srst ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/samsung_s3c4510.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME s3c4510 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # This appears to be a "Version 1" arm7tdmi. if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x1f0f0f0f } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/samsung_s3c6410.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # -*- tcl -*- # Target configuration for the Samsung s3c6410 system on chip # Tested on a SMDK6410 # Processor : ARM1176 # Info: JTAG device found: 0x0032409d (Manufacturer: 0x04e, Part: 0x0324, Version: 0x0) # [Duane Ellis 27/nov/2008: Above 0x0032409d appears to be copy/paste from other places] # [and I do not believe it to be accurate, hence the 0xffffffff below] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME s3c6410 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a bigendian set _ENDIAN little } # trace buffer if { [info exists ETBTAPID] } { set _ETBTAPID $ETBTAPID } else { set _ETBTAPID 0x2b900f0f } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07b76f0f } #jtag scan chain jtag newtap $_CHIPNAME etb -irlen 4 -expected-id $_ETBTAPID jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm11 -endian $_ENDIAN -chain-position $_TARGETNAME adapter srst delay 500 jtag_ntrst_delay 500 #reset configuration reset_config trst_and_srst # trace setup ... NOTE, "normal full" mode fudges the real ETMv3.1 mode etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/sharp_lh79532.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later reset_config srst_only srst_pulls_trst if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lh79532 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # sharp changed the number! set _CPUTAPID 0x00002061 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/sim3x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Silicon Laboratories SiM3x Cortex-M3 # # SiM3x devices support both JTAG and SWD transports. source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME SiM3x } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } if { [info exists CPURAMSIZE] } { set _CPURAMSIZE $CPURAMSIZE } else { # Minimum size of RAM in the Silicon Labs product matrix (8KB) set _CPURAMSIZE 0x2000 } if { [info exists CPUROMSIZE] } { set _CPUROMSIZE $CPUROMSIZE } else { # Minimum size of FLASH in the Silicon Labs product matrix (32KB) set _CPUROMSIZE 0x8000 } if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE $_CPURAMSIZE } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME sim3x 0 $_CPUROMSIZE 0 0 $_TARGETNAME adapter speed 1000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/smp8634.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for Sigma Designs SMP8634 (eventually even SMP8635) if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME smp8634 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x08630001 } adapter srst delay 100 jtag_ntrst_delay 100 reset_config trst_and_srst separate # jtag scan chain # format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE) jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian $_ENDIAN ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/snps_em_sk_fpga.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2014-2015,2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> # # Xilinx Spartan-6 XC6SLX45 FPGA on EM Starter Kit v1. # Xilinx Spartan-6 XC6SLX150 FPGA on EM Starter Kit v2. # source [find cpu/arc/em.tcl] set _CHIPNAME arc-em set _TARGETNAME $_CHIPNAME.cpu # EM SK IDENTITY is 0x200444b1 # EM SK v2 IDENTITY is 0x200044b1 jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -expected-id 0x200444b1 \ -expected-id 0x200044b1 set _coreid 0 set _dbgbase [expr {0x00000000 | ($_coreid << 13)}] target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME \ -coreid 0 -dbgbase $_dbgbase -endian little # There is no SRST, so do a software reset $_TARGETNAME configure -event reset-assert "arc_em_reset $_TARGETNAME" arc_em_init_regs # vim:ft=tcl ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/snps_hsdk.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2019,2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> # # HS Development Kit SoC. # # Contains quad-core ARC HS38. # source [find cpu/arc/hs.tcl] set _coreid 0 set _dbgbase [expr {$_coreid << 13}] # CHIPNAME will be used to choose core family (600, 700 or EM). As far as # OpenOCD is concerned EM and HS are identical. set _CHIPNAME arc-em # OpenOCD discovers JTAG TAPs in reverse order. # ARC HS38 core 4 set _TARGETNAME $_CHIPNAME.cpu4 jtag newtap $_CHIPNAME cpu4 -irlen 4 -ircapture 0x1 -expected-id 0x200c24b1 target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME $_TARGETNAME configure -coreid $_coreid $_TARGETNAME configure -dbgbase $_dbgbase # Flush L2$. $_TARGETNAME configure -event reset-assert "arc_hs_reset $_TARGETNAME" set _coreid [expr {$_coreid + 1}] set _dbgbase [expr {$_coreid << 13}] arc_hs_init_regs # Enable L2 cache support for core 4. $_TARGETNAME arc cache l2 auto 1 # ARC HS38 core 3 set _TARGETNAME $_CHIPNAME.cpu3 jtag newtap $_CHIPNAME cpu3 -irlen 4 -ircapture 0x1 -expected-id 0x200824b1 target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME $_TARGETNAME configure -coreid $_coreid $_TARGETNAME configure -dbgbase $_dbgbase $_TARGETNAME configure -event reset-assert "arc_common_reset $_TARGETNAME" set _coreid [expr {$_coreid + 1}] set _dbgbase [expr {$_coreid << 13}] arc_hs_init_regs # Enable L2 cache support for core 3. $_TARGETNAME arc cache l2 auto 1 # ARC HS38 core 2 set _TARGETNAME $_CHIPNAME.cpu2 jtag newtap $_CHIPNAME cpu2 -irlen 4 -ircapture 0x1 -expected-id 0x200424b1 target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME $_TARGETNAME configure -coreid $_coreid $_TARGETNAME configure -dbgbase $_dbgbase $_TARGETNAME configure -event reset-assert "arc_common_reset $_TARGETNAME" set _coreid [expr {$_coreid + 1}] set _dbgbase [expr {$_coreid << 13}] arc_hs_init_regs # Enable L2 cache support for core 2. $_TARGETNAME arc cache l2 auto 1 # ARC HS38 core 1 set _TARGETNAME $_CHIPNAME.cpu1 jtag newtap $_CHIPNAME cpu1 -irlen 4 -ircapture 0x1 -expected-id 0x200024b1 target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME $_TARGETNAME configure -coreid $_coreid $_TARGETNAME configure -dbgbase $_dbgbase $_TARGETNAME configure -event reset-assert "arc_common_reset $_TARGETNAME" set _coreid [expr {$_coreid + 1}] set _dbgbase [expr {0x00000000 | ($_coreid << 13)}] arc_hs_init_regs # Enable L2 cache support for core 1. $_TARGETNAME arc cache l2 auto 1 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/spear3xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Target configuration for the ST SPEAr3xx family of system on chip # Supported SPEAr300, SPEAr310, SPEAr320 # http://www.st.com/spear # # Processor: ARM926ejs # Info: JTAG tap: spear3xx.cpu tap/device found: 0x07926041 # Date: 2009-10-31 # Author: Antonio Borneo <borneo.antonio@gmail.com> if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME spear3xx } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926041 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x03 \ -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN \ -chain-position $_TARGETNAME # SPEAr3xx has a 8K block of sram @ 0xd280.0000 # REVISIT: what OS puts virtual address equal to phys? $_TARGETNAME configure \ -work-area-virt 0xd2800000 \ -work-area-phys 0xd2800000 \ -work-area-size 0x2000 \ -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stellaris.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # TI/Luminary Stellaris LM3S chip family # Some devices have errata in returning their device class. # DEVICECLASS is provided as a manual override # Manual setting of a device class of 0xff is not allowed global _DEVICECLASS if { [info exists DEVICECLASS] } { set _DEVICECLASS $DEVICECLASS } else { set _DEVICECLASS 0xff } # Luminary chips support both JTAG and SWD transports. # Adapt based on what transport is active. source [find target/swj-dp.tcl] # For now we ignore the SPI and UART options, which # are usable only for ISP style initial flash programming. if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME lm3s } # CPU TAP ID 0x1ba00477 for early Sandstorm parts # CPU TAP ID 0x2ba00477 for later SandStorm parts, e.g. lm3s811 Rev C2 # CPU TAP ID 0x3ba00477 for Cortex-M3 r1p2 (on Fury, DustDevil) # CPU TAP ID 0x4ba00477 for Cortex-M3 r2p0 (on Tempest, Firestorm) # CPU TAP ID 0x4ba00477 for Cortex-M4 r0p1 (on Blizzard) # ... we'll ignore the JTAG version field, rather than list every # chip revision that turns up. if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0ba00477 } # SWD DAP, and JTAG TAP, take same params for now; # ... even though SWD ignores all except TAPID, and # JTAG shouldn't need anything more then irlen. (and TAPID). swj_newdap $_CHIPNAME cpu -irlen 4 -irmask 0xf \ -expected-id $_CPUTAPID -ignore-version dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { # default to 2K working area set _WORKAREASIZE 0x800 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap # 8K working area at base of ram, not backed up # # NOTE: you may need or want to reconfigure the work area; # some parts have just 6K, and you may want to use other # addresses (at end of mem not beginning) or back it up. $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE # JTAG speed ... slow enough to work with a 12 MHz RC oscillator; # LM3S parts don't support RTCK # # NOTE: this may be increased by a reset-init handler, after it # configures and enables the PLL. Or you might need to decrease # this, if you're using a slower clock. adapter speed 500 source [find mem_helper.tcl] proc reset_peripherals {family} { source [find chip/ti/lm3s/lm3s.tcl] echo "Resetting Core Peripherals" # Disable the PLL and the system clock divider (nop if disabled) mmw $SYSCTL_RCC 0 $SYSCTL_RCC_USESYSDIV mmw $SYSCTL_RCC2 $SYSCTL_RCC2_BYPASS2 0 # RCC and RCC2 to their reset values mww $SYSCTL_RCC [expr {0x078e3ad0 | ([mrw $SYSCTL_RCC] & $SYSCTL_RCC_MOSCDIS)}] mww $SYSCTL_RCC2 0x07806810 mww $SYSCTL_RCC 0x078e3ad1 # Reset the deep sleep clock configuration register mww $SYSCTL_DSLPCLKCFG 0x07800000 # Reset the clock gating registers mww $SYSCTL_RCGC0 0x00000040 mww $SYSCTL_RCGC1 0 mww $SYSCTL_RCGC2 0 mww $SYSCTL_SCGC0 0x00000040 mww $SYSCTL_SCGC1 0 mww $SYSCTL_SCGC2 0 mww $SYSCTL_DCGC0 0x00000040 mww $SYSCTL_DCGC1 0 mww $SYSCTL_DCGC2 0 # Reset the remaining SysCtl registers mww $SYSCTL_PBORCTL 0 mww $SYSCTL_IMC 0 mww $SYSCTL_GPIOHBCTL 0 mww $SYSCTL_MOSCCTL 0 mww $SYSCTL_PIOSCCAL 0 mww $SYSCTL_I2SMCLKCFG 0 # Reset the peripherals mww $SYSCTL_SRCR0 0xffffffff mww $SYSCTL_SRCR1 0xffffffff mww $SYSCTL_SRCR2 0xffffffff mww $SYSCTL_SRCR0 0 mww $SYSCTL_SRCR1 0 mww $SYSCTL_SRCR2 0 # Clear any pending SysCtl interrupts mww $SYSCTL_MISC 0xffffffff # Wait for any pending flash operations to complete while {[expr {[mrw $FLASH_FMC] & 0xffff}] != 0} { sleep 1 } while {[expr {[mrw $FLASH_FMC2] & 0xffff}] != 0} { sleep 1 } # Reset the flash controller registers mww $FLASH_FMA 0 mww $FLASH_FCIM 0 mww $FLASH_FCMISC 0xffffffff mww $FLASH_FWBVAL 0 } $_TARGETNAME configure -event reset-start { adapter speed 500 # # When nRST is asserted on most Stellaris devices, it clears some of # the debug state. The ARMv7M and Cortex-M3 TRMs say that's wrong; # and OpenOCD depends on those TRMs. So we won't use SRST on those # chips. (Only power-on reset should affect debug state, beyond a # few specified bits; not the chip's nRST input, wired to SRST.) # # REVISIT current errata specs don't seem to cover this issue. # Do we have more details than this email? # https://lists.berlios.de/pipermail # /openocd-development/2008-August/003065.html # global _DEVICECLASS if {$_DEVICECLASS != 0xff} { set device_class $_DEVICECLASS } else { set device_class [expr {([mrw 0x400fe000] >> 16) & 0xff}] } if {$device_class == 0 || $device_class == 1 || $device_class == 3 || $device_class == 5 || $device_class == 0xa} { if {![using_hla]} { # Sandstorm, Fury, DustDevil, Blizzard and Snowflake are able to use NVIC SYSRESETREQ cortex_m reset_config sysresetreq } } else { if {![using_hla]} { # Tempest and Firestorm default to using NVIC VECTRESET # peripherals will need resetting manually, see proc reset_peripherals cortex_m reset_config vectreset } # reset peripherals, based on code in # http://www.ti.com/lit/er/spmz573a/spmz573a.pdf reset_peripherals $device_class } } # flash configuration ... autodetects sizes, autoprobed flash bank $_CHIPNAME.flash stellaris 0 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32c0x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32c0x family # # stm32c0 devices support SWD transports only. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32c0x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 6kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1800 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # SWD IDCODE (single drop, arm) set _CPUTAPID 0x0bc11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME # reasonable default adapter speed 2000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event examine-end { # Enable DBGMCU clock # RCC_APB1ENR |= DBGMCUEN mmw 0x4002103C 0x08000000 0 # Enable debug during low power modes (uses more power) # DBGMCU_CR |= DBG_STANDBY | DBG_STOP mmw 0x40015804 0x00000006 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_WDGLS_STOP | DBG_WWDG_STOP mmw 0x40015808 0x00001800 0 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32f0x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32f0x family # # stm32 devices support SWD transports only. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32f0x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 4kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } # Allow overriding the Flash bank size if { [info exists FLASH_SIZE] } { set _FLASH_SIZE $FLASH_SIZE } else { # autodetect size set _FLASH_SIZE 0 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # See STM Document RM0091 # Section 29.5.3 set _CPUTAPID 0x0bb11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME # adapter speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz adapter speed 1000 adapter srst delay 100 reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } proc stm32f0x_default_reset_start {} { # Reset clock is HSI (8 MHz) adapter speed 1000 } proc stm32f0x_default_examine_end {} { # Enable debug during low power modes (uses more power) mmw 0x40015804 0x00000006 0 ;# DBGMCU_CR |= DBG_STANDBY | DBG_STOP # Stop watchdog counters during halt mmw 0x40015808 0x00001800 0 ;# DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP } proc stm32f0x_default_reset_init {} { # Configure PLL to boost clock to HSI x 6 (48 MHz) mww 0x40021004 0x00100000 ;# RCC_CFGR = PLLMUL[2] mmw 0x40021000 0x01000000 0 ;# RCC_CR[31:16] |= PLLON mww 0x40022000 0x00000011 ;# FLASH_ACR = PRFTBE | LATENCY[0] sleep 10 ;# Wait for PLL to lock mmw 0x40021004 0x00000002 0 ;# RCC_CFGR |= SW[1] # Boost JTAG frequency adapter speed 8000 } # Default hooks $_TARGETNAME configure -event examine-end { stm32f0x_default_examine_end } $_TARGETNAME configure -event reset-start { stm32f0x_default_reset_start } $_TARGETNAME configure -event reset-init { stm32f0x_default_reset_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32f1x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32f1x family # # stm32 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32f1x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 4kB (as found on some STM32F100s) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } # Allow overriding the Flash bank size if { [info exists FLASH_SIZE] } { set _FLASH_SIZE $FLASH_SIZE } else { # autodetect size set _FLASH_SIZE 0 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0008 Section 26.6.3 set _CPUTAPID 0x3ba00477 } { # this is the SW-DP tap id not the jtag tap id set _CPUTAPID 0x1ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz adapter speed 1000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_WWDG_STOP | DBG_IWDG_STOP | # DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000307 0 } tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { targets $_targetname # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } $_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32f2x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32f2x family # # stm32 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32f2x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 64kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x10000 } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz # # Since we may be running of an RC oscilator, we crank down the speed a # bit more to be on the safe side. Perhaps superstition, but if are # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. adapter speed 1000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0033 # Section 32.6.3 - corresponds to Cortex-M3 r2p0 set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32f2x 0x1fff7800 0 0 0 $_TARGETNAME reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0042008 0x00001800 0 } tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { targets $_targetname # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } $_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32f3x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32f3x family # # stm32 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32f3x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 16kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } # Allow overriding the Flash bank size if { [info exists FLASH_SIZE] } { set _FLASH_SIZE $FLASH_SIZE } else { # autodetect size set _FLASH_SIZE 0 } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz # # Since we may be running of an RC oscilator, we crank down the speed a # bit more to be on the safe side. Perhaps superstition, but if are # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. adapter speed 1000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0316 # Section 29.6.3 - corresponds to Cortex-M4 r0p1 set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f1x 0 $_FLASH_SIZE 0 0 $_TARGETNAME reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } proc stm32f3x_default_reset_start {} { # Reset clock is HSI (8 MHz) adapter speed 1000 } proc stm32f3x_default_examine_end {} { # Enable debug during low power modes (uses more power) mmw 0xe0042004 0x00000007 0 ;# DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP # Stop watchdog counters during halt mmw 0xe0042008 0x00001800 0 ;# DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP } proc stm32f3x_default_reset_init {} { # Configure PLL to boost clock to HSI x 8 (64 MHz) mww 0x40021004 0x00380400 ;# RCC_CFGR = PLLMUL[3:1] | PPRE1[2] mmw 0x40021000 0x01000000 0 ;# RCC_CR |= PLLON mww 0x40022000 0x00000012 ;# FLASH_ACR = PRFTBE | LATENCY[1] sleep 10 ;# Wait for PLL to lock mmw 0x40021004 0x00000002 0 ;# RCC_CFGR |= SW[1] # Boost JTAG frequency adapter speed 8000 } # Default hooks $_TARGETNAME configure -event examine-end { stm32f3x_default_examine_end } $_TARGETNAME configure -event reset-start { stm32f3x_default_reset_start } $_TARGETNAME configure -event reset-init { stm32f3x_default_reset_init } tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { targets $_targetname # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xe0042004 0x00000020 0 } $_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32f4x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32f4x family # # stm32f4 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32f4x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 32kB (Available RAM in smallest device STM32F410) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x8000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0090 # Section 38.6.3 - corresponds to Cortex-M4 r0p1 set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32f2x 0x1fff7800 0 0 0 $_TARGETNAME if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] set _QSPINAME $_CHIPNAME.qspi flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 } # JTAG speed should be <= F_CPU/6. F_CPU after reset is 16MHz, so use F_JTAG = 2MHz # # Since we may be running of an RC oscilator, we crank down the speed a # bit more to be on the safe side. Perhaps superstition, but if are # running off a crystal, we can run closer to the limit. Note # that there can be a pretty wide band where things are more or less stable. adapter speed 2000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event examine-end { # Enable debug during low power modes (uses more power) # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0042008 0x00001800 0 } tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu proc _proc_pre_enable_$_CHIPNAME.tpiu {_chipname} { targets $_chipname.cpu if { [$_chipname.tpiu cget -protocol] eq "sync" } { switch [$_chipname.tpiu cget -port-width] { 1 { # Set TRACE_IOEN; TRACE_MODE to sync 1 bit; GPIOE[2-3] to AF0 mmw 0xE0042004 0x00000060 0x000000c0 mmw 0x40021020 0x00000000 0x0000ff00 mmw 0x40021000 0x000000a0 0x000000f0 mmw 0x40021008 0x000000f0 0x00000000 } 2 { # Set TRACE_IOEN; TRACE_MODE to sync 2 bit; GPIOE[2-4] to AF0 mmw 0xE0042004 0x000000a0 0x000000c0 mmw 0x40021020 0x00000000 0x000fff00 mmw 0x40021000 0x000002a0 0x000003f0 mmw 0x40021008 0x000003f0 0x00000000 } 4 { # Set TRACE_IOEN; TRACE_MODE to sync 4 bit; GPIOE[2-6] to AF0 mmw 0xE0042004 0x000000e0 0x000000c0 mmw 0x40021020 0x00000000 0x0fffff00 mmw 0x40021000 0x00002aa0 0x00003ff0 mmw 0x40021008 0x00003ff0 0x00000000 } } } else { # Set TRACE_IOEN; TRACE_MODE to async mmw 0xE0042004 0x00000020 0x000000c0 } } $_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_CHIPNAME" $_TARGETNAME configure -event reset-init { # Configure PLL to boost clock to HSI x 4 (64 MHz) mww 0x40023804 0x08012008 ;# RCC_PLLCFGR 16 Mhz /8 (M) * 128 (N) /4(P) mww 0x40023C00 0x00000102 ;# FLASH_ACR = PRFTBE | 2(Latency) mmw 0x40023800 0x01000000 0 ;# RCC_CR |= PLLON sleep 10 ;# Wait for PLL to lock mmw 0x40023808 0x00001000 0 ;# RCC_CFGR |= RCC_CFGR_PPRE1_DIV2 mmw 0x40023808 0x00000002 0 ;# RCC_CFGR |= RCC_CFGR_SW_PLL # Boost JTAG frequency adapter speed 8000 } $_TARGETNAME configure -event reset-start { # Reduce speed since CPU speed will slow down to 16MHz with the reset adapter speed 2000 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32f7x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32f7x family # # stm32f7 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32f7x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 128kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x20000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0385 # Section 40.6.3 - corresponds to Cortex-M7 with FPU r0p0 set _CPUTAPID 0x5ba00477 } { set _CPUTAPID 0x5ba02477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32f2x 0x1ff0f000 0 0 0 $_TARGETNAME # On the STM32F7, the Flash is mapped at address 0x08000000 via the AXI and # also address 0x00200000 via the ITCM. The former mapping is read-write in # hardware, while the latter is read-only. By presenting an alias, we # accomplish two things: # (1) We allow writing at 0x00200000 (because the alias acts identically to the # original bank), which allows code intended to run from that address to # also be linked for loading at that address, simplifying linking. # (2) We allow the proper memory map to be delivered to GDB, which will cause # it to use hardware breakpoints at the 0x00200000 mapping (correctly # identifying it as Flash), which it would otherwise not do. Configuring # the Flash via ITCM alias as virtual flash bank $_CHIPNAME.itcm-flash.alias virtual 0x00200000 0 0 0 $_TARGETNAME $_FLASHNAME if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] set _QSPINAME $_CHIPNAME.qspi flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 } # adapter speed should be <= F_CPU/6. F_CPU after reset is 16MHz, so use F_JTAG = 2MHz adapter speed 2000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } # Use hardware reset. # # This target is compatible with connect_assert_srst, which may be set in a # board file. reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq # Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal # HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 # makes the data access cacheable. This allows reading and writing data in the # CPU cache from the debugger, which is far more useful than going straight to # RAM when operating on typical variables, and is generally no worse when # operating on special memory locations. $_CHIPNAME.dap apcsw 0x08000000 0x08000000 } $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0042008 0x00001800 0 } tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { targets $_targetname # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } $_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" $_TARGETNAME configure -event reset-init { # If the HSE was previously enabled and the external clock source # disappeared, RCC_CR.HSERDY can get stuck at 1 and the PLL cannot be # properly switched back to HSI. This situation persists even over a system # reset, including a pin reset via SRST. However, activating the clock # security system will detect the problem and clear HSERDY to 0, which in # turn allows the PLL to switch back to HSI properly. Since we just came # out of reset, HSEON should be 0. If HSERDY is 1, then this situation must # have happened; in that case, activate the clock security system to clear # HSERDY. if {[mrw 0x40023800] & 0x00020000} { mmw 0x40023800 0x00090000 0 ;# RCC_CR = CSSON | HSEON sleep 10 ;# Wait for CSS to fire, if it wants to mmw 0x40023800 0 0x00090000 ;# RCC_CR &= ~CSSON & ~HSEON mww 0x4002380C 0x00800000 ;# RCC_CIR = CSSC sleep 1 ;# Wait for CSSF to clear } # If the clock security system fired, it will pend an NMI. A pending NMI # will cause a bad time for any subsequent executing code, such as a # programming algorithm. if {[mrw 0xE000ED04] & 0x80000000} { # ICSR.NMIPENDSET reads as 1. Need to clear it. A pending NMI can’t be # cleared by any normal means (such as ICSR or NVIC). It can only be # cleared by entering the NMI handler or by resetting the processor. echo "[target current]: Clock security system generated NMI. Clearing." # Keep the old DEMCR value. set old [mrw 0xE000EDFC] # Enable vector catch on reset. mww 0xE000EDFC 0x01000001 # Issue local reset via AIRCR. mww 0xE000ED0C 0x05FA0001 # Restore old DEMCR value. mww 0xE000EDFC $old } # Configure PLL to boost clock to HSI x 10 (160 MHz) mww 0x40023804 0x08002808 ;# RCC_PLLCFGR 16 Mhz /10 (M) * 128 (N) /2(P) mww 0x40023C00 0x00000107 ;# FLASH_ACR = PRFTBE | 7(Latency) mmw 0x40023800 0x01000000 0 ;# RCC_CR |= PLLON sleep 10 ;# Wait for PLL to lock mww 0x40023808 0x00009400 ;# RCC_CFGR_PPRE1 = 5(div 4), PPRE2 = 4(div 2) mmw 0x40023808 0x00000002 0 ;# RCC_CFGR |= RCC_CFGR_SW_PLL # Boost SWD frequency # Do not boost JTAG frequency and slow down JTAG memory access or flash write algo # suffers from DAP WAITs if {[using_jtag]} { [[target current] cget -dap] memaccess 16 } { adapter speed 8000 } } $_TARGETNAME configure -event reset-start { # Reduce speed since CPU speed will slow down to 16MHz with the reset adapter speed 2000 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32g0x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32g0x family # # stm32g0 devices support SWD transports only. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32g0x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # Smallest proposed target has 8kB ram, use 4kB by default to avoid surprises if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # Section 37.5.5 - corresponds to Cortex-M0+ set _CPUTAPID 0x0bc11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME # reasonable default adapter speed 2000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } proc stm32g0x_default_reset_start {} { # Reset clock is HSI16 (16 MHz) adapter speed 2000 } proc stm32g0x_default_examine_end {} { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP mmw 0x40015804 0x00000006 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0x40015808 0x00001800 0 } proc stm32g0x_default_reset_init {} { # Increase clock to 64 Mhz mmw 0x40022000 0x00000002 0x00000005 ;# FLASH_ACR: Latency = 2 mww 0x4002100C 0x30000802 ;# RCC_PLLCFGR = PLLR=/2, PLLN=8, PLLM=/1, PLLSRC=0x2 mmw 0x40021000 0x01000000 0x00000000 ;# RCC_CR |= PLLON mmw 0x40021008 0x00000002 0x00000005 ;# RCC_CFGR: SW=PLLRCLK # Boost JTAG frequency adapter speed 4000 } # Default hooks $_TARGETNAME configure -event examine-end { stm32g0x_default_examine_end } $_TARGETNAME configure -event reset-start { stm32g0x_default_reset_start } $_TARGETNAME configure -event reset-init { stm32g0x_default_reset_init } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32g4x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32g4x family # # stm32g4 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32g4x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # Smallest current target has 32kB ram, use 16kB by default to avoid surprises if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0440 # Section 46.6.3 - corresponds to Cortex-M4 r0p1 set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] set _QSPINAME $_CHIPNAME.qspi flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 } # reasonable default adapter speed 2000 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event reset-init { # CPU comes out of reset with HSION | HSIRDY. # Use HSI 16 MHz clock, compliant even with VOS == 2. # 1 WS compliant with VOS == 2 and 16 MHz. mmw 0x40022000 0x00000001 0x0000000E ;# FLASH_ACR: Latency = 1 mmw 0x40021000 0x00000100 0x00000000 ;# RCC_CR |= HSION mmw 0x40021008 0x00000001 0x00000002 ;# RCC_CFGR: SW=HSI16 } $_TARGETNAME configure -event reset-start { # Reset clock is HSI (16 MHz) adapter speed 2000 } $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZR1 |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0042008 0x00001800 0 } tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { targets $_targetname # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } $_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32h7x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32h7x family # # stm32h7 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32h7x } if { [info exists DUAL_BANK] } { set $_CHIPNAME.DUAL_BANK $DUAL_BANK unset DUAL_BANK } else { set $_CHIPNAME.DUAL_BANK 0 } if { [info exists DUAL_CORE] } { set $_CHIPNAME.DUAL_CORE $DUAL_CORE unset DUAL_CORE } else { set $_CHIPNAME.DUAL_CORE 0 } # Issue a warning when hla is used, and fallback to single core configuration if { [set $_CHIPNAME.DUAL_CORE] && [using_hla] } { echo "Warning : hla does not support multicore debugging" set $_CHIPNAME.DUAL_CORE 0 } if { [info exists USE_CTI] } { set $_CHIPNAME.USE_CTI $USE_CTI unset USE_CTI } else { set $_CHIPNAME.USE_CTI 0 } # Issue a warning when DUAL_CORE=0 and USE_CTI=1, and fallback to USE_CTI=0 if { ![set $_CHIPNAME.DUAL_CORE] && [set $_CHIPNAME.USE_CTI] } { echo "Warning : could not use CTI with a single core device, CTI is disabled" set $_CHIPNAME.USE_CTI 0 } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 64kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x10000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x6ba00477 } { set _CPUTAPID 0x6ba02477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } if {![using_hla]} { # STM32H7 provides an APB-AP at access port 2, which allows the access to # the debug and trace features on the system APB System Debug Bus (APB-D). target create $_CHIPNAME.ap2 mem_ap -dap $_CHIPNAME.dap -ap-num 2 swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xE00E3000 tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xE00F5000 } target create $_CHIPNAME.cpu0 cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap -ap-num 0 $_CHIPNAME.cpu0 configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.bank1.cpu0 stm32h7x 0x08000000 0 0 0 $_CHIPNAME.cpu0 if {[set $_CHIPNAME.DUAL_BANK]} { flash bank $_CHIPNAME.bank2.cpu0 stm32h7x 0x08100000 0 0 0 $_CHIPNAME.cpu0 } if {[set $_CHIPNAME.DUAL_CORE]} { target create $_CHIPNAME.cpu1 cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap -ap-num 3 $_CHIPNAME.cpu1 configure -work-area-phys 0x38000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.bank1.cpu1 stm32h7x 0x08000000 0 0 0 $_CHIPNAME.cpu1 if {[set $_CHIPNAME.DUAL_BANK]} { flash bank $_CHIPNAME.bank2.cpu1 stm32h7x 0x08100000 0 0 0 $_CHIPNAME.cpu1 } } # Make sure that cpu0 is selected targets $_CHIPNAME.cpu0 if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] set _QSPINAME $_CHIPNAME.qspi flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_CHIPNAME.cpu0 0x52005000 } else { if { [info exists OCTOSPI1] && $OCTOSPI1 } { set a [llength [flash list]] set _OCTOSPINAME1 $_CHIPNAME.octospi1 flash bank $_OCTOSPINAME1 stmqspi 0x90000000 0 0 0 $_CHIPNAME.cpu0 0x52005000 } if { [info exists OCTOSPI2] && $OCTOSPI2 } { set b [llength [flash list]] set _OCTOSPINAME2 $_CHIPNAME.octospi2 flash bank $_OCTOSPINAME2 stmqspi 0x70000000 0 0 0 $_CHIPNAME.cpu0 0x5200A000 } } # Clock after reset is HSI at 64 MHz, no need of PLL adapter speed 1800 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } # use hardware reset # # The STM32H7 does not support connect_assert_srst mode because the AXI is # unavailable while SRST is asserted, and that is used to access the DBGMCU # component at 0x5C001000 in the examine-end event handler. # # It is possible to access the DBGMCU component at 0xE00E1000 via AP2 instead # of the default AP0, and that works with SRST asserted; however, nonzero AP # usage does not work with HLA, so is not done by default. That change could be # made in a local configuration file if connect_assert_srst mode is needed for # a specific application and a non-HLA adapter is in use. reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset $_CHIPNAME.cpu0 cortex_m reset_config sysresetreq if {[set $_CHIPNAME.DUAL_CORE]} { $_CHIPNAME.cpu1 cortex_m reset_config sysresetreq } # Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal # HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 # makes the data access cacheable. This allows reading and writing data in the # CPU cache from the debugger, which is far more useful than going straight to # RAM when operating on typical variables, and is generally no worse when # operating on special memory locations. $_CHIPNAME.dap apcsw 0x08000000 0x08000000 } $_CHIPNAME.cpu0 configure -event examine-end { # Enable D3 and D1 DBG clocks # DBGMCU_CR |= D3DBGCKEN | D1DBGCKEN stm32h7x_dbgmcu_mmw 0x004 0x00600000 0 # Enable debug during low power modes (uses more power) # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP D1 Domain stm32h7x_dbgmcu_mmw 0x004 0x00000007 0 # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP D2 Domain stm32h7x_dbgmcu_mmw 0x004 0x00000038 0 # Stop watchdog counters during halt # DBGMCU_APB3FZ1 |= WWDG1 stm32h7x_dbgmcu_mmw 0x034 0x00000040 0 # DBGMCU_APB1LFZ1 |= WWDG2 stm32h7x_dbgmcu_mmw 0x03C 0x00000800 0 # DBGMCU_APB4FZ1 |= WDGLSD1 | WDGLSD2 stm32h7x_dbgmcu_mmw 0x054 0x000C0000 0 # Enable clock for tracing # DBGMCU_CR |= TRACECLKEN stm32h7x_dbgmcu_mmw 0x004 0x00100000 0 # RM0399 (id 0x450) M7+M4 with SWO Funnel # RM0433 (id 0x450) M7 with SWO Funnel # RM0455 (id 0x480) M7 without SWO Funnel # RM0468 (id 0x483) M7 without SWO Funnel # Enable CM7 and CM4 slave ports in SWO trace Funnel # Works ok also on devices single core and without SWO funnel # Hack, use stm32h7x_dbgmcu_mmw with big offset to control SWTF # SWTF_CTRL |= ENS0 | ENS1 stm32h7x_dbgmcu_mmw 0x3000 0x00000003 0 } $_CHIPNAME.cpu0 configure -event reset-init { # Clock after reset is HSI at 64 MHz, no need of PLL adapter speed 4000 } # get _CHIPNAME from current target proc stm32h7x_get_chipname {} { set t [target current] set sep [string last "." $t] if {$sep == -1} { return $t } return [string range $t 0 [expr {$sep - 1}]] } if {[set $_CHIPNAME.DUAL_CORE]} { $_CHIPNAME.cpu1 configure -event examine-end { set _CHIPNAME [stm32h7x_get_chipname] global $_CHIPNAME.USE_CTI # Stop watchdog counters during halt # DBGMCU_APB3FZ2 |= WWDG1 stm32h7x_dbgmcu_mmw 0x038 0x00000040 0 # DBGMCU_APB1LFZ2 |= WWDG2 stm32h7x_dbgmcu_mmw 0x040 0x00000800 0 # DBGMCU_APB4FZ2 |= WDGLSD1 | WDGLSD2 stm32h7x_dbgmcu_mmw 0x058 0x000C0000 0 if {[set $_CHIPNAME.USE_CTI]} { stm32h7x_cti_start } } } # like mrw, but with target selection proc stm32h7x_mrw {used_target reg} { return [$used_target read_memory $reg 32 1] } # like mmw, but with target selection proc stm32h7x_mmw {used_target reg setbits clearbits} { set old [stm32h7x_mrw $used_target $reg] set new [expr {($old & ~$clearbits) | $setbits}] $used_target mww $reg $new } # mmw for dbgmcu component registers, it accepts the register offset from dbgmcu base # this procedure will use the mem_ap on AP2 whenever possible proc stm32h7x_dbgmcu_mmw {reg_offset setbits clearbits} { # use $_CHIPNAME.ap2 if possible, and use the proper dbgmcu base address if {![using_hla]} { set _CHIPNAME [stm32h7x_get_chipname] set used_target $_CHIPNAME.ap2 set reg_addr [expr {0xE00E1000 + $reg_offset}] } { set used_target [target current] set reg_addr [expr {0x5C001000 + $reg_offset}] } stm32h7x_mmw $used_target $reg_addr $setbits $clearbits } if {[set $_CHIPNAME.USE_CTI]} { # create CTI instances for both cores cti create $_CHIPNAME.cti0 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0043000 cti create $_CHIPNAME.cti1 -dap $_CHIPNAME.dap -ap-num 3 -baseaddr 0xE0043000 $_CHIPNAME.cpu0 configure -event halted { stm32h7x_cti_prepare_restart_all } $_CHIPNAME.cpu1 configure -event halted { stm32h7x_cti_prepare_restart_all } $_CHIPNAME.cpu0 configure -event debug-halted { stm32h7x_cti_prepare_restart_all } $_CHIPNAME.cpu1 configure -event debug-halted { stm32h7x_cti_prepare_restart_all } proc stm32h7x_cti_start {} { set _CHIPNAME [stm32h7x_get_chipname] # Configure Cores' CTIs to halt each other # TRIGIN0 (DBGTRIGGER) and TRIGOUT0 (EDBGRQ) at CTM_CHANNEL_0 $_CHIPNAME.cti0 write INEN0 0x1 $_CHIPNAME.cti0 write OUTEN0 0x1 $_CHIPNAME.cti1 write INEN0 0x1 $_CHIPNAME.cti1 write OUTEN0 0x1 # enable CTIs $_CHIPNAME.cti0 enable on $_CHIPNAME.cti1 enable on } proc stm32h7x_cti_stop {} { set _CHIPNAME [stm32h7x_get_chipname] $_CHIPNAME.cti0 enable off $_CHIPNAME.cti1 enable off } proc stm32h7x_cti_prepare_restart_all {} { stm32h7x_cti_prepare_restart cti0 stm32h7x_cti_prepare_restart cti1 } proc stm32h7x_cti_prepare_restart {cti} { set _CHIPNAME [stm32h7x_get_chipname] # Acknowlodge EDBGRQ at TRIGOUT0 $_CHIPNAME.$cti write INACK 0x01 $_CHIPNAME.$cti write INACK 0x00 } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32h7x_dual_bank.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32h7x family (dual flash bank) # STM32H7xxxI 2Mo have a dual bank flash. set DUAL_BANK 1 source [find target/stm32h7x.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32l0.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # M0+ devices only have SW-DP, but swj-dp code works, just don't # set any jtag related features # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32l0 } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 2kB (max ram on smallest part) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x800 } # JTAG speed should be <= F_CPU/6. # F_CPU after reset is ~2MHz, so use F_JTAG max = 333kHz adapter speed 300 adapter srst delay 100 if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { # Arm, m0+, non-multidrop. # http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka16088.html set _CPUTAPID 0x0bc11477 } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32lx 0x08000000 0 0 0 $_TARGETNAME reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } proc stm32l0_enable_HSI16 {} { # Enable HSI16 as clock source echo "STM32L0: Enabling HSI16" # Set HSI16ON in RCC_CR (leave MSI enabled) mmw 0x40021000 0x00000101 0 # Set HSI16 as SYSCLK (RCC_CFGR) mmw 0x4002100c 0x00000001 0 # Wait until System clock switches to HSI16 while { ([ mrw 0x4002100c ] & 0x0c) != 0x04 } { } # Increase speed adapter speed 2500 } $_TARGETNAME configure -event reset-init { stm32l0_enable_HSI16 } $_TARGETNAME configure -event reset-start { adapter speed 300 } $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0x40015804 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0x40015808 0x00001800 0 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32l0_dual_bank.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/stm32l0.cfg] # Add the second flash bank. set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME stm32lx 0 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32l1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # stm32l1 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32l1 } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 10kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x2800 } # JTAG speed should be <= F_CPU/6. # F_CPU after reset is 2MHz, so use F_JTAG max = 333kHz adapter speed 300 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0038 # Section 30.6.3 - corresponds to Cortex-M3 r2p0 set _CPUTAPID 0x4ba00477 } else { # SWD IDCODE (single drop, arm) set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # flash size will be probed set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32lx 0x08000000 0 0 0 $_TARGETNAME reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } proc stm32l_enable_HSI {} { # Enable HSI as clock source echo "STM32L: Enabling HSI" # Set HSION in RCC_CR mmw 0x40023800 0x00000101 0 # Set HSI as SYSCLK mmw 0x40023808 0x00000001 0 # Increase JTAG speed adapter speed 2000 } $_TARGETNAME configure -event reset-init { stm32l_enable_HSI } $_TARGETNAME configure -event reset-start { adapter speed 300 } $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0042008 0x00001800 0 } tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { targets $_targetname # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } $_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32l1x_dual_bank.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/stm32l1.cfg] # The stm32l1x 384kb have a dual bank flash. # Let's add a definition for the second bank here. # Add the second flash bank. set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME stm32lx 0 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32l4x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32l4x family # # stm32l4 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32l4x } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 40kB (Available RAM in smallest device STM32L412) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0xa000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # See STM Document RM0351 # Section 44.6.3 - corresponds to Cortex-M4 r0p1 set _CPUTAPID 0x4ba00477 } { set _CPUTAPID 0x2ba01477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32l4x 0x08000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] set _QSPINAME $_CHIPNAME.qspi flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 } else { if { [info exists OCTOSPI1] && $OCTOSPI1 } { set a [llength [flash list]] set _OCTOSPINAME1 $_CHIPNAME.octospi1 flash bank $_OCTOSPINAME1 stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 } if { [info exists OCTOSPI2] && $OCTOSPI2 } { set b [llength [flash list]] set _OCTOSPINAME2 $_CHIPNAME.octospi2 flash bank $_OCTOSPINAME2 stmqspi 0x70000000 0 0 0 $_TARGETNAME 0xA0001400 } } # Common knowledges tells JTAG speed should be <= F_CPU/6. # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on # the safe side. # # Note that there is a pretty wide band where things are # more or less stable, see http://openocd.zylin.com/#/c/3366/ adapter speed 500 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event examine-end { # Enable debug during low power modes (uses more power) # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0042008 0x00001800 0 } tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu proc _proc_pre_enable_$_CHIPNAME.tpiu {_chipname} { targets $_chipname.cpu if { [$_chipname.tpiu cget -protocol] eq "sync" } { switch [$_chipname.tpiu cget -port-width] { 1 { # Set TRACE_IOEN; TRACE_MODE to sync 1 bit; GPIOE[2-3] to AF0 mmw 0xE0042004 0x00000060 0x000000c0 mmw 0x48001020 0x00000000 0x0000ff00 mmw 0x48001000 0x000000a0 0x000000f0 mmw 0x48001008 0x000000f0 0x00000000 } 2 { # Set TRACE_IOEN; TRACE_MODE to sync 2 bit; GPIOE[2-4] to AF0 mmw 0xE0042004 0x000000a0 0x000000c0 mmw 0x48001020 0x00000000 0x000fff00 mmw 0x48001000 0x000002a0 0x000003f0 mmw 0x48001008 0x000003f0 0x00000000 } 4 { # Set TRACE_IOEN; TRACE_MODE to sync 4 bit; GPIOE[2-6] to AF0 mmw 0xE0042004 0x000000e0 0x000000c0 mmw 0x48001020 0x00000000 0x0fffff00 mmw 0x48001000 0x00002aa0 0x00003ff0 mmw 0x48001008 0x00003ff0 0x00000000 } } } else { # Set TRACE_IOEN; TRACE_MODE to async mmw 0xE0042004 0x00000020 0x000000c0 } } $_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_CHIPNAME" $_TARGETNAME configure -event reset-init { # CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 6 (4 MHz). # Use MSI 24 MHz clock, compliant even with VOS == 2. # 3 WS compliant with VOS == 2 and 24 MHz. mww 0x40022000 0x00000103 ;# FLASH_ACR = PRFTBE | 3(Latency) mww 0x40021000 0x00000099 ;# RCC_CR = MSI_ON | MSIRGSEL | MSI Range 9 # Boost JTAG frequency adapter speed 4000 } $_TARGETNAME configure -event reset-start { # Reset clock is MSI (4 MHz) adapter speed 500 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32l5x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32l5x family # stm32l5x devices support both JTAG and SWD transports. source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32l5x } source [find target/stm32x5x_common.cfg] proc stm32l5x_clock_config {} { set offset [expr {[stm32x5x_is_secure] ? 0x10000000 : 0}] # MCU clock is MSI (4MHz) after reset, set MCU freq at 110 MHz with PLL # RCC_APB1ENR1 = PWREN mww [expr {0x40021058 + $offset}] 0x10000000 # delay for register clock enable (read back reg) mrw [expr {0x40021058 + $offset}] # PWR_CR1 : VOS Range 0 mww [expr {0x40007000 + $offset}] 0 # while (PWR_SR2 & VOSF) while {([mrw [expr {0x40007014 + $offset}]] & 0x0400)} {} # FLASH_ACR : 5 WS for 110 MHz HCLK mww 0x40022000 0x00000005 # RCC_PLLCFGR = PLLP=PLLQ=0, PLLR=00=2, PLLREN=1, PLLN=55, PLLM=0000=1, PLLSRC=MSI 4MHz # fVCO = 4 x 55 /1 = 220 # SYSCLOCK = fVCO/PLLR = 220/2 = 110 MHz mww [expr {0x4002100C + $offset}] 0x01003711 # RCC_CR |= PLLON mmw [expr {0x40021000 + $offset}] 0x01000000 0 # while !(RCC_CR & PLLRDY) while {!([mrw [expr {0x40021000 + $offset}]] & 0x02000000)} {} # RCC_CFGR |= SW_PLL mmw [expr {0x40021008 + $offset}] 0x00000003 0 # while ((RCC_CFGR & SWS) != PLL) while {([mrw [expr {0x40021008 + $offset}]] & 0x0C) != 0x0C} {} } $_TARGETNAME configure -event reset-init { stm32l5x_clock_config # Boost JTAG frequency adapter speed 4000 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32mp13x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STMicroelectronics STM32MP13x (Single Cortex-A7) # http://www.st.com/stm32mp1 # HLA does not support custom CSW nor AP other than 0 if { [using_hla] } { echo "ERROR: HLA transport cannot work with this target." echo "ERROR: To use STLink switch to DAP mode, as in \"board/stm32mp13x_dk.cfg\"." shutdown } source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32mp13x } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x6ba00477 } else { set _CPUTAPID 0x6ba02477 } } # Chip Level TAP Controller, only in jtag mode if { [info exists CLCTAPID] } { set _CLCTAPID $CLCTAPID } else { set _CLCTAPID 0x06501041 } swj_newdap $_CHIPNAME tap -expected-id $_CPUTAPID -irlen 4 if { [using_jtag] } { jtag newtap $_CHIPNAME.clc tap -expected-id $_CLCTAPID -irlen 5 } dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -ignore-syspwrupack # NOTE: keep ap-num and dbgbase to speed-up examine after reset # NOTE: do not change the order of target create target create $_CHIPNAME.ap1 mem_ap -dap $_CHIPNAME.dap -ap-num 1 target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 0 target create $_CHIPNAME.cpu cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 -dbgbase 0xE00D0000 $_CHIPNAME.cpu cortex_a maskisr on $_CHIPNAME.cpu cortex_a dacrfixup on # interface does not work while srst is asserted # this is target specific, valid for every board # srst resets the debug unit, behavior equivalent to "srst_pulls_trst" reset_config srst_gates_jtag srst_pulls_trst adapter speed 5000 adapter srst pulse_width 200 # bootrom has an internal timeout of 1 second for detecting the boot flash. # wait at least 1 second to guarantee we are out of bootrom adapter srst delay 1100 add_help_text axi_secure "Set secure mode for following AXI accesses" proc axi_secure {} { $::_CHIPNAME.dap apsel 0 $::_CHIPNAME.dap apcsw 0x10006000 } add_help_text axi_nsecure "Set non-secure mode for following AXI accesses" proc axi_nsecure {} { $::_CHIPNAME.dap apsel 0 $::_CHIPNAME.dap apcsw 0x30006000 } axi_secure proc dbgmcu_enable_debug {} { # keep clock enabled in low-power ## catch {$::_CHIPNAME.ap1 mww 0xe0081004 0x00000004} # freeze watchdog 1 and 2 on core halted catch {$::_CHIPNAME.ap1 mww 0xe008102c 0x00000004} catch {$::_CHIPNAME.ap1 mww 0xe008104c 0x00000008} } proc toggle_cpu_dbg_claim0 {} { # toggle CPU0 DBG_CLAIM[0] $::_CHIPNAME.ap1 mww 0xe00d0fa0 1 $::_CHIPNAME.ap1 mww 0xe00d0fa4 1 } # FIXME: most of handlers below will be removed once reset framework get merged $_CHIPNAME.ap1 configure -event reset-deassert-pre { adapter deassert srst deassert trst catch {dap init} catch {$::_CHIPNAME.dap apid 1} } $_CHIPNAME.cpu configure -event reset-deassert-pre {$::_CHIPNAME.cpu arp_examine} $_CHIPNAME.cpu configure -event reset-deassert-post {toggle_cpu_dbg_claim0; dbgmcu_enable_debug} $_CHIPNAME.ap1 configure -event examine-start {dap init} $_CHIPNAME.ap1 configure -event examine-end {dbgmcu_enable_debug} ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32mp15x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # STMicroelectronics STM32MP15x (Single/Dual Cortex-A7 plus Cortex-M4) # http://www.st.com/stm32mp1 # HLA does not support multi-cores nor custom CSW nor AP other than 0 if { [using_hla] } { echo "ERROR: HLA transport cannot work with this target." echo "ERROR: To use STLink switch to DAP mode, as in \"board/stm32mp15x_dk2.cfg\"." shutdown } source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32mp15x } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x6ba00477 } else { set _CPUTAPID 0x6ba02477 } } # Chip Level TAP Controller, only in jtag mode if { [info exists CLCTAPID] } { set _CLCTAPID $CLCTAPID } else { set _CLCTAPID 0x06500041 } swj_newdap $_CHIPNAME tap -expected-id $_CPUTAPID -irlen 4 if { [using_jtag] } { jtag newtap $_CHIPNAME.clc tap -expected-id $_CLCTAPID -irlen 5 } dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -ignore-syspwrupack # FIXME: Cortex-M code requires target accessible during reset, but this is not possible in STM32MP1 # so defer-examine it until the reset framework get merged # NOTE: keep ap-num and dbgbase to speed-up examine after reset # NOTE: do not change the order of target create target create $_CHIPNAME.ap1 mem_ap -dap $_CHIPNAME.dap -ap-num 1 target create $_CHIPNAME.ap2 mem_ap -dap $_CHIPNAME.dap -ap-num 2 target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 0 target create $_CHIPNAME.cpu0 cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 -dbgbase 0xE00D0000 target create $_CHIPNAME.cpu1 cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 1 -dbgbase 0xE00D2000 target create $_CHIPNAME.cm4 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -defer-examine targets $_CHIPNAME.cpu0 target smp $_CHIPNAME.cpu0 $_CHIPNAME.cpu1 $_CHIPNAME.cpu0 cortex_a maskisr on $_CHIPNAME.cpu1 cortex_a maskisr on $_CHIPNAME.cpu0 cortex_a dacrfixup on $_CHIPNAME.cpu1 cortex_a dacrfixup on cti create $_CHIPNAME.cti.sys -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE0094000 cti create $_CHIPNAME.cti.cpu0 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE00D8000 cti create $_CHIPNAME.cti.cpu1 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE00D9000 cti create $_CHIPNAME.cti.cm4 -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xE0043000 swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE0083000 tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE0093000 # interface does not work while srst is asserted # this is target specific, valid for every board # Errata "2.3.5 Incorrect reset of glitch-free kernel clock switch" requires # srst to force VDDCORE power cycle or pull srst_core. Both cases reset the # debug unit, behavior equivalent to "srst_pulls_trst" reset_config srst_gates_jtag srst_pulls_trst adapter speed 5000 adapter srst pulse_width 200 # bootrom has an internal timeout of 1 second for detecting the boot flash. # wait at least 1 second to guarantee we are out of bootrom adapter srst delay 1100 add_help_text axi_secure "Set secure mode for following AXI accesses" proc axi_secure {} { $::_CHIPNAME.dap apsel 0 $::_CHIPNAME.dap apcsw 0x10006000 } add_help_text axi_nsecure "Set non-secure mode for following AXI accesses" proc axi_nsecure {} { $::_CHIPNAME.dap apsel 0 $::_CHIPNAME.dap apcsw 0x30006000 } axi_secure proc dbgmcu_enable_debug {} { # set debug enable bits in DBGMCU_CR to get ap2 and cm4 visible catch {$::_CHIPNAME.ap1 mww 0xe0081004 0x00000007} # freeze watchdog 1 and 2 on cores halted catch {$::_CHIPNAME.ap1 mww 0xe008102c 0x00000004} catch {$::_CHIPNAME.ap1 mww 0xe008104c 0x00000008} } proc toggle_cpu0_dbg_claim0 {} { # toggle CPU0 DBG_CLAIM[0] $::_CHIPNAME.ap1 mww 0xe00d0fa0 1 $::_CHIPNAME.ap1 mww 0xe00d0fa4 1 } proc detect_cpu1 {} { set cpu1_prsr [$::_CHIPNAME.ap1 read_memory 0xE00D2314 32 1] set dual_core [expr {$cpu1_prsr & 1}] if {! $dual_core} {$::_CHIPNAME.cpu1 configure -defer-examine} } proc rcc_enable_traceclk {} { $::_CHIPNAME.ap2 mww 0x5000080c 0x301 } # FIXME: most of handler below will be removed once reset framework get merged $_CHIPNAME.ap1 configure -event reset-deassert-pre {adapter deassert srst deassert trst;catch {dap init};catch {$::_CHIPNAME.dap apid 1}} $_CHIPNAME.ap2 configure -event reset-deassert-pre {dbgmcu_enable_debug;rcc_enable_traceclk} $_CHIPNAME.cpu0 configure -event reset-deassert-pre {$::_CHIPNAME.cpu0 arp_examine} $_CHIPNAME.cpu1 configure -event reset-deassert-pre {$::_CHIPNAME.cpu1 arp_examine allow-defer} $_CHIPNAME.cpu0 configure -event reset-deassert-post {toggle_cpu0_dbg_claim0} $_CHIPNAME.cm4 configure -event reset-deassert-post {$::_CHIPNAME.cm4 arp_examine;if {[$::_CHIPNAME.ap2 curstate] == "halted"} {$::_CHIPNAME.cm4 arp_poll;$::_CHIPNAME.cm4 arp_poll;$::_CHIPNAME.cm4 arp_halt}} $_CHIPNAME.ap1 configure -event examine-start {dap init} $_CHIPNAME.ap2 configure -event examine-start {dbgmcu_enable_debug} $_CHIPNAME.cpu0 configure -event examine-end {detect_cpu1} $_CHIPNAME.ap2 configure -event examine-end {rcc_enable_traceclk;$::_CHIPNAME.cm4 arp_examine} ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32u5x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32u5x family # stm32u5x devices support both JTAG and SWD transports. source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32u5x } source [find target/stm32x5x_common.cfg] proc stm32u5x_clock_config {} { set offset [expr {[stm32x5x_is_secure] ? 0x10000000 : 0}] # MCU clock is at MSI 4MHz after reset, set MCU freq at 160 MHz with PLL # Enable voltage range 1 for frequency above 100 Mhz # RCC_AHB3ENR = PWREN mww [expr {0x46020C94 + $offset}] 0x00000004 # delay for register clock enable (read back reg) mrw [expr {0x46020C94 + $offset}] # PWR_VOSR : VOS Range 1 mmw [expr {0x4602080C + $offset}] 0x00030000 0 # while !(PWR_VOSR & VOSRDY) while {!([mrw [expr {0x4602080C + $offset}]] & 0x00008000)} {} # FLASH_ACR : 4 WS for 160 MHz HCLK mww [expr {0x40022000 + $offset}] 0x00000004 # RCC_PLL1CFGR => PLL1MBOOST=0, PLL1M=0=/1, PLL1FRACEN=0, PLL1SRC=MSI 4MHz # PLL1REN=1, PLL1RGE => VCOInputRange=PLLInputRange_4_8 mww [expr {0x46020C28 + $offset}] 0x00040009 # Enable EPOD Booster mmw [expr {0x4602080C + $offset}] 0x00040000 0 # while !(PWR_VOSR & BOOSTRDY) while {!([mrw [expr {0x4602080C + $offset}]] & 0x00004000)} {} # RCC_PLL1DIVR => PLL1P=PLL1Q=PLL1R=000001=/2, PLL1N=0x4F=80 # fVCO = 4 x 80 /1 = 320 # SYSCLOCK = fVCO/PLL1R = 320/2 = 160 MHz mww [expr {0x46020C34 + $offset}] 0x0101024F # RCC_CR |= PLL1ON mmw [expr {0x46020C00 + $offset}] 0x01000000 0 # while !(RCC_CR & PLL1RDY) while {!([mrw [expr {0x46020C00 + $offset}]] & 0x02000000)} {} # RCC_CFGR1 |= SW_PLL mmw [expr {0x46020C1C + $offset}] 0x00000003 0 # while ((RCC_CFGR1 & SWS) != PLL) while {([mrw [expr {0x46020C1C + $offset}]] & 0x0C) != 0x0C} {} } $_TARGETNAME configure -event reset-init { stm32u5x_clock_config # Boost JTAG frequency adapter speed 4000 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32w108xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Target configuration for the ST STM32W108xx chips # # Processor: ARM Cortex-M3 # Date: 2013-06-09 # Author: Giuseppe Barba <giuseppe.barba@gmail.com> # # stm32 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] if { [info exists CHIPNAME] == 0 } { set _CHIPNAME stm32w108 } else { set _CHIPNAME $CHIPNAME } # Work-area is a space in RAM used for flash programming # By default use 8kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x2000 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x3ba00477 } { set _CPUTAPID 0x1ba01477 } } set _ENDIAN little swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { if { [info exists BSTAPID] } { set _BSTAPID $BSTAPID jtag newtap $_CHIPNAME bs -irlen 4 -ircapture 0xe -irmask 0xf -expected-id _BSTAPID } else { set _BSTAPID_1 0x169a862b set _BSTAPID_2 0x269a862b jtag newtap $_CHIPNAME bs -irlen 4 -ircapture 0xe -irmask 0xf \ -expected-id $_BSTAPID_1 -expected-id $_BSTAPID_2 } } # # Set Target # set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # Use the flash driver from the EM357 set _FLASHNAME $_CHIPNAME.flash # 64k (0x10000) of flash flash bank $_FLASHNAME em357 0x08000000 0x10000 0 0 $_TARGETNAME reset_config srst_nogate if {![using_hla]} { cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32wbx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32wbx family # # stm32wb devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32wbx } set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 64kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x10000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x6ba00477 } else { # SWD IDCODE (single drop, arm) set _CPUTAPID 0x6ba02477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME # Common knowledges tells JTAG speed should be <= F_CPU/6. # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on # the safe side. # # Note that there is a pretty wide band where things are # more or less stable, see http://openocd.zylin.com/#/c/3366/ adapter speed 500 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } $_TARGETNAME configure -event reset-init { # CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 4 MHz. # Configure system to use MSI 24 MHz clock, compliant with VOS default Range1. # 2 WS compliant with VOS=Range1 and 24 MHz. mmw 0x58004000 0x00000102 0 ;# FLASH_ACR |= PRFTBE | 2(Latency) mmw 0x58000000 0x00000091 0 ;# RCC_CR = MSI_ON | MSI Range 24 MHz # Boost JTAG frequency adapter speed 4000 } $_TARGETNAME configure -event reset-start { # Reset clock is MSI (4 MHz) adapter speed 500 } $_TARGETNAME configure -event examine-end { # Enable debug during low power modes (uses more power) # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZR1 |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE004203C 0x00001800 0 } tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { targets $_targetname # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } $_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32wlx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32wlx family # # stm32wl devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm32wlx } if { [info exists DUAL_CORE] } { set $_CHIPNAME.DUAL_CORE $DUAL_CORE unset DUAL_CORE } else { set $_CHIPNAME.DUAL_CORE 0 } if { [info exists WKUP_CM0P] } { set $_CHIPNAME.WKUP_CM0P $WKUP_CM0P unset WKUP_CM0P } else { set $_CHIPNAME.WKUP_CM0P 0 } # Issue a warning when hla is used, and fallback to single core configuration if { [set $_CHIPNAME.DUAL_CORE] && [using_hla] } { echo "Warning : hla does not support multicore debugging" set $_CHIPNAME.DUAL_CORE 0 set $_CHIPNAME.WKUP_CM0P 0 } # setup the Work-area start address and size # Work-area is a space in RAM used for flash programming # Memory map for known devices: # STM32WL x5JC x5JB x5J8 # FLASH 256 128 64 # SRAM1 32 16 0 # SRAM2 32 32 20 # By default use 8kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x2000 } # Use SRAM2 as work area (some devices do not have SRAM1): set WORKAREASTART_CM4 0x20008000 set WORKAREASTART_CM0P [expr {$WORKAREASTART_CM4 + $_WORKAREASIZE}] #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { set _CPUTAPID 0x6ba00477 } else { # SWD IDCODE (single drop, arm) set _CPUTAPID 0x6ba02477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } target create $_CHIPNAME.cpu0 cortex_m -endian little -dap $_CHIPNAME.dap $_CHIPNAME.cpu0 configure -work-area-phys $WORKAREASTART_CM4 -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.flash.cpu0 stm32l4x 0x08000000 0 0 0 $_CHIPNAME.cpu0 flash bank $_CHIPNAME.otp.cpu0 stm32l4x 0x1fff7000 0 0 0 $_CHIPNAME.cpu0 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset $_CHIPNAME.cpu0 cortex_m reset_config sysresetreq } $_CHIPNAME.cpu0 configure -event reset-init { # CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 4 MHz. # Configure system to use MSI 24 MHz clock, compliant with VOS default Range1. # 2 WS compliant with VOS=Range1 and 24 MHz. mmw 0x58004000 0x00000102 0 ;# FLASH_ACR |= PRFTEN | 2(Latency) mmw 0x58000000 0x00000091 0 ;# RCC_CR = MSI_ON | MSI Range 24 MHz # Boost JTAG frequency adapter speed 4000 } $_CHIPNAME.cpu0 configure -event reset-start { # Reset clock is MSI (4 MHz) adapter speed 500 } $_CHIPNAME.cpu0 configure -event examine-end { # Enable debug during low power modes (uses more power) # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZR1 |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE004203C 0x00001800 0 set _CHIPNAME [stm32wlx_get_chipname] global $_CHIPNAME.WKUP_CM0P if {[set $_CHIPNAME.WKUP_CM0P]} { stm32wlx_wkup_cm0p } } tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 if {[set $_CHIPNAME.DUAL_CORE]} { target create $_CHIPNAME.cpu1 cortex_m -endian little -dap $_CHIPNAME.dap -ap-num 1 $_CHIPNAME.cpu0 configure -work-area-phys $WORKAREASTART_CM0P -work-area-size $_WORKAREASIZE -work-area-backup 0 flash bank $_CHIPNAME.flash.cpu1 stm32l4x 0x08000000 0 0 0 $_CHIPNAME.cpu1 flash bank $_CHIPNAME.otp.cpu1 stm32l4x 0x1fff7000 0 0 0 $_CHIPNAME.cpu1 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset $_CHIPNAME.cpu1 cortex_m reset_config sysresetreq } proc stm32wlx_wkup_cm0p {} { set _CHIPNAME [stm32wlx_get_chipname] # enable CPU2 boot after reset and after wakeup from Stop or Standby mode # PWR_CR4 |= C2BOOT stm32wlx_mmw $_CHIPNAME.cpu0 0x5800040C 0x00008000 0 } } # get _CHIPNAME from current target proc stm32wlx_get_chipname {} { set t [target current] set sep [string last "." $t] if {$sep == -1} { return $t } return [string range $t 0 [expr {$sep - 1}]] } # like mrw, but with target selection proc stm32wlx_mrw {used_target reg} { return [$used_target read_memory $reg 32 1] } # like mmw, but with target selection proc stm32wlx_mmw {used_target reg setbits clearbits} { set old [stm32wlx_mrw $used_target $reg] set new [expr {($old & ~$clearbits) | $setbits}] $used_target mww $reg $new } # Make sure that cpu0 is selected targets $_CHIPNAME.cpu0 # Common knowledges tells JTAG speed should be <= F_CPU/6. # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on # the safe side. # # Note that there is a pretty wide band where things are # more or less stable, see http://openocd.zylin.com/#/c/3366/ adapter speed 500 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32x5x_common.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # common script for stm32l5x and stm32u5x families # Work-area is a space in RAM used for flash programming # By default use 64kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x10000 } #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { if { [using_jtag] } { # STM32L5x: RM0438 Rev5, Section 52.2.8 JTAG debug port - Table 425. JTAG-DP data registers # STM32U5x: RM0456 Rev1, Section 65.2.8 JTAG debug port - Table 661. JTAG-DP data registers # Corresponds to Cortex®-M33 JTAG debug port ID code set _CPUTAPID 0x0ba04477 } { # SWD IDCODE (single drop, arm) set _CPUTAPID 0x0be12477 } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap # use non-secure RAM by default $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 # create sec/ns flash and otp memories (sizes will be probed) flash bank $_CHIPNAME.flash_ns stm32l4x 0x08000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.flash_alias_s stm32l4x 0x0C000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32l4x 0x0BFA0000 0 0 0 $_TARGETNAME # Common knowledge tells JTAG speed should be <= F_CPU/6. # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on # the safe side. # # Note that there is a pretty wide band where things are # more or less stable, see http://review.openocd.org/3366 adapter speed 500 adapter srst delay 100 if {[using_jtag]} { jtag_ntrst_delay 100 } reset_config srst_nogate if {[using_hla]} { echo "Warn : The selected adapter does not support debugging this device in secure mode" } else { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } proc stm32x5x_is_secure {} { # read Debug Security Control and Status Register (DSCSR) and check CDS (bit 16) set DSCSR [mrw 0xE000EE08] return [expr {($DSCSR & (1 << 16)) != 0}] } proc stm32x5x_ahb_ap_non_secure_access {} { # in HLA mode, non-secure debugging is possible without changing the AP CSW if {![using_hla]} { # SPROT=1=Non Secure access, Priv=1 [[target current] cget -dap] apcsw 0x4B000000 0x4F000000 } } proc stm32x5x_ahb_ap_secure_access {} { if {![using_hla]} { # SPROT=0=Secure access, Priv=1 [[target current] cget -dap] apcsw 0x0B000000 0x4F000000 } } $_TARGETNAME configure -event reset-start { # Reset clock is MSI (4 MHz) adapter speed 480 } $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP mmw 0xE0044004 0x00000006 0 # Stop watchdog counters during halt # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0044008 0x00001800 0 } $_TARGETNAME configure -event halted { set secure [stm32x5x_is_secure] if {$secure} { set secure_str "Secure" stm32x5x_ahb_ap_secure_access } else { set secure_str "Non-Secure" stm32x5x_ahb_ap_non_secure_access } # print the secure state only when it changes set _TARGETNAME [target current] global $_TARGETNAME.secure if {![info exists $_TARGETNAME.secure] || $secure != [set $_TARGETNAME.secure]} { echo "CPU in $secure_str state" # update saved security state set $_TARGETNAME.secure $secure } } $_TARGETNAME configure -event gdb-flash-erase-start { set use_secure_workarea 0 # check if FLASH_OPTR.TZEN is enabled set FLASH_OPTR [mrw 0x40022040] if {[expr {$FLASH_OPTR & 0x80000000}] == 0} { echo "TZEN option bit disabled" stm32x5x_ahb_ap_non_secure_access } else { stm32x5x_ahb_ap_secure_access echo "TZEN option bit enabled" # check if FLASH_OPTR.RDP is not Level 0.5 if {[expr {$FLASH_OPTR & 0xFF}] != 0x55} { set use_secure_workarea 1 } } set _TARGETNAME [target current] set workarea_addr [$_TARGETNAME cget -work-area-phys] echo "workarea_addr $workarea_addr" if {$use_secure_workarea} { set workarea_addr [expr {$workarea_addr | 0x10000000}] } else { set workarea_addr [expr {$workarea_addr & ~0x10000000}] } $_TARGETNAME configure -work-area-phys $workarea_addr } tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { targets $_targetname # Set TRACE_EN and TRACE_IOEN in DBGMCU_CR # Leave TRACE_MODE untouched (defaults to async). # When using sync change this value accordingly to configure trace pins # assignment mmw 0xE0044004 0x00000030 0 } $_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm32xl.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32xl family (dual flash bank) source [find target/stm32f1x.cfg] # flash size will be probed set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME stm32f1x 0x08080000 0 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm8l.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm8l family # # stm8 devices support SWIM transports only. # transport select swim if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm8l } # Work-area is a space in RAM used for flash programming # By default use 1kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x400 } if { [info exists FLASHSTART] } { set _FLASHSTART $FLASHSTART } else { set _FLASHSTART 0x8000 } if { [info exists FLASHEND] } { set _FLASHEND $FLASHEND } else { set _FLASHEND 0xffff } if { [info exists EEPROMSTART] } { set _EEPROMSTART $EEPROMSTART } else { set _EEPROMSTART 0x4000 } if { [info exists EEPROMEND] } { set _EEPROMEND $EEPROMEND } else { set _EEPROMEND 0x43ff } if { [info exists OPTIONSTART] } { set _OPTIONSTART $OPTIONSTART } else { set _OPTIONSTART 0x4800 } if { [info exists OPTIONEND] } { set _OPTIONEND $OPTIONEND } else { set _OPTIONEND 0x487f } if { [info exists BLOCKSIZE] } { set _BLOCKSIZE $BLOCKSIZE } else { set _BLOCKSIZE 0x80 } swim newtap $_CHIPNAME cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME stm8 -chain-position $_CHIPNAME.cpu $_TARGETNAME configure -work-area-phys 0x0 -work-area-size $_WORKAREASIZE -work-area-backup 1 $_TARGETNAME configure -flashstart $_FLASHSTART -flashend $_FLASHEND -eepromstart $_EEPROMSTART -eepromend $_EEPROMEND $_TARGETNAME configure -optionstart $_OPTIONSTART -optionend $_OPTIONEND -blocksize $_BLOCKSIZE # Uncomment this line to enable interrupts while instruction step #$_TARGETNAME configure -enable_step_irq # Set stm8l type $_TARGETNAME configure -enable_stm8l # Set high speed adapter speed 800 # Set low speed #adapter speed 363 reset_config srst_only #uncomment this line to connect under reset #reset_config srst_nogate connect_assert_srst ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm8l151x2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Config script for STM8L151x2 # Supported Devices: # STM8L151C2 # STM8L151F2 # STM8L151G2 # STM8L151K2 # 1kB RAM # Start 0x0000 # End 0x03ff set WORKAREASIZE 1024 # 4kB Flash set FLASHSTART 0x8000 set FLASHEND 0x8fff # 256B EEPROM set EEPROMSTART 0x1000 set EEPROMEND 0x10ff set OPTIONSTART 0x4800 set OPTIONEND 0x487f proc stm8_reset_rop {} { mwb 0x4800 0xaa mwb 0x4800 0xaa reset halt } source [find target/stm8l.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm8l151x3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Config script for STM8L151x3 # Supported Devices: # STM8L151C3 # STM8L151F3 # STM8L151G3 # STM8L151K3 # 1kB RAM # Start 0x0000 # End 0x03ff set WORKAREASIZE 1024 # 8kB Flash set FLASHSTART 0x8000 set FLASHEND 0x9fff # 256B EEPROM set EEPROMSTART 0x1000 set EEPROMEND 0x10ff set OPTIONSTART 0x4800 set OPTIONEND 0x487f proc stm8_reset_rop {} { mwb 0x4800 0xaa mwb 0x4800 0xaa reset halt } source [find target/stm8l.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm8l152.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later echo 'DEPRECATED: choose between stm8l15xx4.cfg, stm8l15xx6.cfg and stm8l15xx8.cfg instead of stm8l152.cfg' echo ' using stm8l152.cfg for backwards compatability' set EEPROMSTART 0x1000 set EEPROMEND 0x13ff proc stm8_reset_rop {} { mwb 0x4800 0xaa mwb 0x4800 0xaa reset halt } source [find target/stm8l.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm8l15xx4.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Config script for STM8L151x4/STM8L152x4 # Supported Devices: # STM8L151C4 # STM8L151G4 # STM8L151K4 # STM8L152C4 # STM8L152K4 # 2kB RAM # Start 0x0000 # End 0x07ff set WORKAREASIZE 2048 # 16kB Flash set FLASHSTART 0x8000 set FLASHEND 0xbfff # 1kB EEPROM set EEPROMSTART 0x1000 set EEPROMEND 0x13ff set OPTIONSTART 0x4800 set OPTIONEND 0x48ff proc stm8_reset_rop {} { mwb 0x4800 0xaa mwb 0x4800 0xaa reset halt } source [find target/stm8l.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm8l15xx6.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Config script for STM8L151x6/STM8L152x6 # Supported Devices: # STM8L151C6 # STM8L151G6 # STM8L151K6 # STM8L151R6 # STM8L152C6 # STM8L152K6 # STM8L152R6 # 2kB RAM # Start 0x0000 # End 0x07ff set WORKAREASIZE 2048 # 32kB Flash set FLASHSTART 0x8000 set FLASHEND 0xffff # 1kB EEPROM set EEPROMSTART 0x1000 set EEPROMEND 0x13ff set OPTIONSTART 0x4800 set OPTIONEND 0x48ff proc stm8_reset_rop {} { mwb 0x4800 0xaa mwb 0x4800 0xaa reset halt } source [find target/stm8l.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm8l15xx8.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Config script for STM8L151x8/STM8L152x8 # Supported Devices: # STM8L151C8 # STM8L151M8 # STM8L151R8 # STM8L152C8 # STM8L152K8 # STM8L152M8 # STM8L152R8 # 4kB RAM # Start 0x0000 # End 0x0fff set WORKAREASIZE 4096 # 64kB Flash set FLASHSTART 0x08000 set FLASHEND 0x17fff # 2kB EEPROM set EEPROMSTART 0x1000 set EEPROMEND 0x17ff set OPTIONSTART 0x4800 set OPTIONEND 0x48ff proc stm8_reset_rop {} { mwb 0x4800 0xaa mwb 0x4800 0xaa reset halt } source [find target/stm8l.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm8s.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm8s family # # stm8 devices support SWIM transports only. # transport select swim if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME stm8s } # Work-area is a space in RAM used for flash programming # By default use 1kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x400 } if { [info exists FLASHSTART] } { set _FLASHSTART $FLASHSTART } else { set _FLASHSTART 0x8000 } if { [info exists FLASHEND] } { set _FLASHEND $FLASHEND } else { set _FLASHEND 0xffff } if { [info exists EEPROMSTART] } { set _EEPROMSTART $EEPROMSTART } else { set _EEPROMSTART 0x4000 } if { [info exists EEPROMEND] } { set _EEPROMEND $EEPROMEND } else { set _EEPROMEND 0x43ff } if { [info exists OPTIONSTART] } { set _OPTIONSTART $OPTIONSTART } else { set _OPTIONSTART 0x4800 } if { [info exists OPTIONEND] } { set _OPTIONEND $OPTIONEND } else { set _OPTIONEND 0x487f } if { [info exists BLOCKSIZE] } { set _BLOCKSIZE $BLOCKSIZE } else { set _BLOCKSIZE 0x80 } swim newtap $_CHIPNAME cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME stm8 -chain-position $_CHIPNAME.cpu $_TARGETNAME configure -work-area-phys 0x0 -work-area-size $_WORKAREASIZE -work-area-backup 1 $_TARGETNAME configure -flashstart $_FLASHSTART -flashend $_FLASHEND -eepromstart $_EEPROMSTART -eepromend $_EEPROMEND $_TARGETNAME configure -optionstart $_OPTIONSTART -optionend $_OPTIONEND -blocksize $_BLOCKSIZE # Uncomment this line to enable interrupts while instruction step #$_TARGETNAME configure -enable_step_irq # Set high speed adapter speed 800 # Set low speed #adapter speed 363 reset_config srst_only # uncomment this line to connect under reset #reset_config srst_nogate connect_assert_srst ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm8s003.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #config script for STM8S003 set FLASHEND 0x9FFF set BLOCKSIZE 0x40 proc stm8_reset_rop {} { mwb 0x4800 0x00 reset halt } source [find target/stm8s.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm8s103.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #config script for STM8S103 set FLASHEND 0x9FFF set EEPROMEND 0x427F set OPTIONEND 0x480A set BLOCKSIZE 0x40 proc stm8_reset_rop {} { mwb 0x4800 0x00 reset halt } source [find target/stm8s.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/stm8s105.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #config script for STM8S105 proc stm8_reset_rop {} { mwb 0x4800 0x00 reset halt } source [find target/stm8s.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/str710.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #start slow, speed up after reset adapter speed 10 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME str710 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-start { adapter speed 10 } $_TARGETNAME configure -event reset-init { adapter speed 6000 # Because the hardware cannot be interrogated for the protection state # of sectors, initialize all the sectors to be unprotected. The initial # state is reflected by the driver, too. flash protect 0 0 last off flash protect 1 0 last off } $_TARGETNAME configure -event gdb-flash-erase-start { flash protect 0 0 7 off flash protect 1 0 1 off } $_TARGETNAME configure -work-area-phys 0x2000C000 -work-area-size 0x4000 -work-area-backup 0 #flash bank str7x <base> <size> 0 0 <target#> <variant> set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME str7x 0x40000000 0x00040000 0 0 $_TARGETNAME STR71x set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME str7x 0x400C0000 0x00004000 0 0 $_TARGETNAME STR71x ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/str730.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #STR730 CPU adapter speed 3000 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME str730 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id $_CPUTAPID #jtag nTRST and nSRST delay adapter srst delay 500 jtag_ntrst_delay 500 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian little -chain-position 0 $_TARGETNAME configure -event reset-start { adapter speed 10 } $_TARGETNAME configure -event reset-init { adapter speed 3000 # Because the hardware cannot be interrogated for the protection state # of sectors, initialize all the sectors to be unprotected. The initial # state is reflected by the driver, too. flash protect 0 0 last off } $_TARGETNAME configure -event gdb-flash-erase-start { flash protect 0 0 7 off } $_TARGETNAME configure -work-area-phys 0xA0000000 -work-area-size 0x4000 -work-area-backup 0 #flash bank <driver> <base> <size> <chip_width> <bus_width> set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME str7x 0x80000000 0x00040000 0 0 $_TARGETNAME STR73x ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/str750.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later #STR750 CPU if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME str750 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4f1f0041 } # jtag speed adapter speed 10 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst #jtag scan chain jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x0f -expected-id $_CPUTAPID #jtag nTRST and nSRST delay adapter srst delay 500 jtag_ntrst_delay 500 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian little -chain-position 0 $_TARGETNAME configure -event reset-start { adapter speed 10 } $_TARGETNAME configure -event reset-init { adapter speed 3000 init_smi # Because the hardware cannot be interrogated for the protection state # of sectors, initialize all the sectors to be unprotected. The initial # state is reflected by the driver, too. flash protect 0 0 last off flash protect 1 0 last off } $_TARGETNAME configure -event gdb-flash-erase-start { flash protect 0 0 7 off flash protect 1 0 1 off } $_TARGETNAME configure -work-area-phys 0x40000000 -work-area-size 0x4000 -work-area-backup 0 #flash bank <driver> <base> <size> <chip_width> <bus_width> set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME str7x 0x20000000 0x00040000 0 0 $_TARGETNAME STR75x set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME str7x 0x200C0000 0x00004000 0 0 $_TARGETNAME STR75x # Serial NOR on SMI CS0. set _FLASHNAME $_CHIPNAME.snor flash bank $_FLASHNAME stmsmi 0x80000000 0 0 0 $_TARGETNAME source [find mem_helper.tcl] proc init_smi {} { mmw 0x60000030 0x01000000 0x00000000; # enable clock for GPIO regs mmw 0xffffe420 0x00000001 0x00000000; # set SMI_EN bit mmw 0x90000000 0x00000001 0x00000000; # set BLOCK_EN_1 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/str912.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # script for str9 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME str912 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # jtag speed. We need to stick to 16kHz until we've finished reset. adapter speed 16 adapter srst delay 100 jtag_ntrst_delay 100 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst if { [info exists FLASHTAPID] } { set _FLASHTAPID $FLASHTAPID } else { set _FLASHTAPID 0x04570041 } jtag newtap $_CHIPNAME flash -irlen 8 -ircapture 0x1 -irmask 0x1 -expected-id $_FLASHTAPID if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x25966041 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID if { [info exists BSTAPID] } { set _BSTAPID $BSTAPID } else { # possible values: 0x1457f041, 0x2457f041 # we ignore version in check below set _BSTAPID 0x1457f041 } jtag newtap $_CHIPNAME bs -irlen 5 -ircapture 0x1 -irmask 0x1 -expected-id $_BSTAPID -ignore-version set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm966e -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-start { adapter speed 16 } $_TARGETNAME configure -event reset-init { # We can increase speed now that we know the target is halted. #adapter speed 3000 # -- Enable 96K RAM # PFQBC enabled / DTCM & AHB wait-states disabled mww 0x5C002034 0x0191 str9x flash_config 0 4 2 0 0x80000 flash protect 0 0 7 off } $_TARGETNAME configure -work-area-phys 0x50000000 -work-area-size 16384 -work-area-backup 0 #flash bank str9x <base> <size> 0 0 <target#> <variant> set _FLASHNAME $_CHIPNAME.flash0 flash bank $_FLASHNAME str9x 0x00000000 0x00080000 0 0 $_TARGETNAME set _FLASHNAME $_CHIPNAME.flash1 flash bank $_FLASHNAME str9x 0x00080000 0x00008000 0 0 $_TARGETNAME ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/swj-dp.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # ARM Debug Interface V5 (ADI_V5) utility # ... Mostly for SWJ-DP (not SW-DP or JTAG-DP, since # SW-DP and JTAG-DP targets don't need to switch based # on which transport is active. # # declare a JTAG or SWD Debug Access Point (DAP) # based on the transport in use with this session. # You can't access JTAG ops when SWD is active, etc. # params are currently what "jtag newtap" uses # because OpenOCD internals are still strongly biased # to JTAG .... but for SWD, "irlen" etc are ignored, # and the internals work differently # for now, ignore non-JTAG and non-SWD transports # (e.g. initial flash programming via SPI or UART) # split out "chip" and "tag" so we can someday handle # them more uniformly irlen too...) if [catch {transport select}] { echo "Error: unable to select a session transport. Can't continue." shutdown } proc swj_newdap {chip tag args} { if [using_jtag] { eval jtag newtap $chip $tag $args } elseif [using_swd] { eval swd newdap $chip $tag $args } else { echo "Error: transport '[ transport select ]' not supported by swj_newdap" shutdown } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/swm050.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Synwit SWM050 source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME swm050 } set _CHIPSERIES swm050 if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x400 } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0bb11477 } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME swm050 0x0 0x2000 0 0 $_TARGETNAME adapter speed 1000 $_TARGETNAME configure -event reset-init { # Stop the watchdog, just to be safe mww 0x40019000 0x00 # Set clock divider value to 1 mww 0x400F0000 0x01 # Set system clock to 18Mhz mww 0x400F0008 0x00 } # SWM050 (Cortex-M0 core) supports SYSRESETREQ if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/test_reset_syntax_error.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Test script to check that syntax error in reset # script is reported properly. # at91eb40a target #jtag scan chain set _CHIPNAME syntaxtest jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf #target configuration set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME $_TARGETNAME configure -event reset-init { syntax error } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/test_syntax_error.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # This script tests a syntax error in the startup # config script syntax error here ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti-ar7.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments AR7 SOC - used in many adsl modems. # http://www.linux-mips.org/wiki/AR7 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME ti-ar7 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x0000100f } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian $_ENDIAN -chain-position $_CHIPNAME.cpu # use onboard 4k sram as working area $_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 0x00001000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti-cjtag.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # A start sequence to change from cJTAG to 4-pin JTAG # This is needed for CC2538 and CC26xx to be able to communicate through JTAG # Read section 6.3 in http://www.ti.com/lit/pdf/swru319 for more information. proc ti_cjtag_to_4pin_jtag {jrc} { # Bypass runtest 20 irscan $jrc 0x3f -endstate RUN/IDLE # Two zero bit scans and a one bit drshift pathmove RUN/IDLE DRSELECT DRCAPTURE DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRUPDATE RUN/IDLE pathmove RUN/IDLE DRSELECT DRCAPTURE DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRUPDATE RUN/IDLE pathmove RUN/IDLE DRSELECT DRCAPTURE DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRSHIFT DREXIT1 DRUPDATE RUN/IDLE pathmove RUN/IDLE DRSELECT DRCAPTURE DREXIT1 DRPAUSE # A two bit drhift and a 9 bit drshift pathmove DRPAUSE DREXIT2 DRSHIFT DRSHIFT DREXIT1 DRUPDATE RUN/IDLE pathmove RUN/IDLE DRSELECT DRCAPTURE DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRSHIFT DRSHIFT DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRSHIFT DRSHIFT DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRSHIFT DRSHIFT DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRSHIFT DRSHIFT DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRSHIFT DREXIT1 DRPAUSE pathmove DRPAUSE DREXIT2 DRUPDATE RUN/IDLE pathmove RUN/IDLE DRSELECT DRCAPTURE DREXIT1 DRPAUSE # Bypass irscan $jrc 0x3f -endstate RUN/IDLE # Set ICEPick IDCODE in data register irscan $jrc 0x04 -endstate RUN/IDLE } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_calypso.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # TI Calypso (lite) G2 C035 Digital Base Band chip # # ARM7TDMIE + DSP subchip (S28C128) # # 512K SRAM Calypso # 256K SRAM Calypso lite # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME calypso } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3100e02f } # Work-area is a space in RAM used for flash programming # By default use 64kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x10000 } adapter speed 1000 reset_config trst_and_srst jtag newtap $_CHIPNAME dsp -expected-id 0x00000000 -irlen 8 jtag newtap $_CHIPNAME arm -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # target set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm7tdmi -endian little -chain-position $_TARGETNAME # workarea $_TARGETNAME configure -work-area-phys 0x00800000 -work-area-size $_WORKAREASIZE -work-area-backup 1 arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable $_TARGETNAME configure -event examine-start { irscan calypso.arm 0x0b -endstate DRPAUSE drscan calypso.arm 2 2 -endstate RUN/IDLE } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_cc13x0.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments CC13x0 - ARM Cortex-M3 # # http://www.ti.com # set CHIPNAME cc13x0 set JRC_TAPID 0x0B9BE02F set WORKAREASIZE 0x4000 source [find target/ti_cc26x0.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_cc13x2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments CC13x2 - ARM Cortex-M4 # # http://www.ti.com # set CHIPNAME cc13x2 set JRC_TAPID 0x0BB4102F set WORKAREASIZE 0x7000 source [find target/ti_cc26x0.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_cc26x0.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments CC26x0 - ARM Cortex-M3 # # http://www.ti.com # source [find target/icepick.cfg] source [find target/ti-cjtag.cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cc26x0 } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x4BA00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" # # ICEpick-C (JTAG route controller) # if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0B99A02F } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu" # A start sequence is needed to change from 2-pin cJTAG to 4-pin JTAG jtag configure $_CHIPNAME.jrc -event post-reset "ti_cjtag_to_4pin_jtag $_CHIPNAME.jrc" set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cc26xx 0 0 0 0 $_TARGETNAME cortex_m reset_config vectreset ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_cc26x2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments CC26x2 - ARM Cortex-M4 # # http://www.ti.com # set CHIPNAME cc26x2 set JRC_TAPID 0x0BB4102F set WORKAREASIZE 0x7000 source [find target/ti_cc26x0.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_cc3220sf.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments CC3220SF - ARM Cortex-M4 # # http://www.ti.com/CC3220SF # source [find target/swj-dp.tcl] source [find target/icepick.cfg] source [find target/ti_cc32xx.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cc3220sf 0 0 0 0 $_TARGETNAME # # On CC32xx family of devices, sysreqreset is disabled, and vectreset is # blocked by the boot loader (stops in a while(1) statement). srst reset can # leave the target in a state that prevents debug. The following uses the # soft_reset_halt command to reset and halt the target. Then the PC and stack # are initialized from internal flash. This allows for a more reliable reset, # but with two caveats: it only works for the SF variant that has internal # flash, and it only resets the CPU and not any peripherals. # proc ocd_process_reset_inner { MODE } { soft_reset_halt # Initialize MSP, PSP, and PC from vector table at flash 0x01000800 set boot [read_memory 0x01000800 32 2] reg msp [lindex $boot 0] reg psp [lindex $boot 0] reg pc [lindex $boot 1] if { 0 == [string compare $MODE run ] } { resume } cc32xx.cpu invoke-event reset-end } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_cc32xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments CC32xx - ARM Cortex-M4 # # http://www.ti.com/product/CC3200 # http://www.ti.com/product/CC3220 # source [find target/swj-dp.tcl] source [find target/icepick.cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cc32xx } # # Main DAP # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { if {[using_jtag]} { set _DAP_TAPID 0x4BA00477 } else { set _DAP_TAPID 0x2BA01477 } } if {[using_jtag]} { jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" } else { swj_newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID } # # ICEpick-C (JTAG route controller) # if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0B97C02F } if {[using_jtag]} { jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu" } set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x2000 } $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_dm355.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments DaVinci family: TMS320DM355 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dm355 } # TI boards default to EMU0/EMU1 *high* -- ARM and ETB are *disabled* # after JTAG reset until ICEpick is used to route them in. set EMU01 "-disable" # With EMU0/EMU1 jumpered *low* ARM and ETB are *enabled* without # needing any ICEpick interaction. #set EMU01 "-enable" source [find target/icepick.cfg] # # Also note: when running without RTCK before the PLLs are set up, you # may need to slow the JTAG clock down quite a lot (under 2 MHz). # # Subsidiary TAP: ARM ETB11, with scan chain for 4K of ETM trace buffer if { [info exists ETB_TAPID] } { set _ETB_TAPID $ETB_TAPID } else { set _ETB_TAPID 0x2b900f0f } jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0xf -expected-id $_ETB_TAPID $EMU01 jtag configure $_CHIPNAME.etb -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 1" # Subsidiary TAP: ARM926ejs with scan chains for ARM Debug, EmbeddedICE-RT, ETM. if { [info exists CPU_TAPID] } { set _CPU_TAPID $CPU_TAPID } else { set _CPU_TAPID 0x07926001 } jtag newtap $_CHIPNAME arm -irlen 4 -irmask 0xf -expected-id $_CPU_TAPID $EMU01 jtag configure $_CHIPNAME.arm -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 0" # Primary TAP: ICEpick (JTAG route controller) and boundary scan if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0b73b02f } jtag newtap $_CHIPNAME jrc -irlen 6 -irmask 0x3f -expected-id $_JRC_TAPID jtag configure $_CHIPNAME.jrc -event setup \ "jtag tapenable $_CHIPNAME.etb; jtag tapenable $_CHIPNAME.arm" ################ # various symbol definitions, to avoid hard-wiring addresses # and enable some sharing of DaVinci-family utility code global dm355 set dm355 [ dict create ] # Physical addresses for controllers and memory # (Some of these are valid for many DaVinci family chips) dict set dm355 sram0 0x00010000 dict set dm355 sram1 0x00014000 dict set dm355 sysbase 0x01c40000 dict set dm355 pllc1 0x01c40800 dict set dm355 pllc2 0x01c40c00 dict set dm355 psc 0x01c41000 dict set dm355 gpio 0x01c67000 dict set dm355 a_emif 0x01e10000 dict set dm355 a_emif_cs0 0x02000000 dict set dm355 a_emif_cs1 0x04000000 dict set dm355 ddr_emif 0x20000000 dict set dm355 ddr 0x80000000 dict set dm355 uart0 0x01c20000 dict set dm355 uart1 0x01c20400 dict set dm355 uart2 0x01e06000 source [find target/davinci.cfg] ################ # GDB target: the ARM, using SRAM1 for scratch. SRAM0 (also 16K) # and the ETB memory (4K) are other options, while trace is unused. set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm926ejs -chain-position $_TARGETNAME # NOTE that work-area-virt presumes a Linux 2.6.30-rc2+ kernel, # and that the work area is used only with a kernel mmu context ... $_TARGETNAME configure \ -work-area-virt [expr {0xfffe0000 + 0x4000}] \ -work-area-phys [dict get $dm355 sram1] \ -work-area-size 0x4000 \ -work-area-backup 0 # be absolutely certain the JTAG clock will work with the worst-case # CLKIN = 24 MHz (best case: 36 MHz) even when no bootloader turns # on the PLL and starts using it. OK to speed up after clock setup. adapter speed 1500 $_TARGETNAME configure -event "reset-start" { adapter speed 1500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable # trace setup etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_dm365.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments DaVinci family: TMS320DM365 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dm365 } # TI boards default to EMU0/EMU1 *high* -- ARM and ETB are *disabled* # after JTAG reset until ICEpick is used to route them in. set EMU01 "-disable" # With EMU0/EMU1 jumpered *low* ARM and ETB are *enabled* without # needing any ICEpick interaction. #set EMU01 "-enable" source [find target/icepick.cfg] # Subsidiary TAP: ARM ETB11, with scan chain for 4K of ETM trace buffer if { [info exists ETB_TAPID] } { set _ETB_TAPID $ETB_TAPID } else { set _ETB_TAPID 0x2b900f0f } jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0xf -expected-id $_ETB_TAPID $EMU01 jtag configure $_CHIPNAME.etb -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 1" # Subsidiary TAP: ARM926ejs with scan chains for ARM Debug, EmbeddedICE-RT, ETM. if { [info exists CPU_TAPID] } { set _CPU_TAPID $CPU_TAPID } else { set _CPU_TAPID 0x0792602f } jtag newtap $_CHIPNAME arm -irlen 4 -irmask 0xf -expected-id $_CPU_TAPID $EMU01 jtag configure $_CHIPNAME.arm -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 0" # Primary TAP: ICEpick (JTAG route controller) and boundary scan if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0b83e02f } jtag newtap $_CHIPNAME jrc -irlen 6 -irmask 0x3f -expected-id $_JRC_TAPID jtag configure $_CHIPNAME.jrc -event setup \ "jtag tapenable $_CHIPNAME.etb; jtag tapenable $_CHIPNAME.arm" ################ # various symbol definitions, to avoid hard-wiring addresses # and enable some sharing of DaVinci-family utility code global dm365 set dm365 [ dict create ] # Physical addresses for controllers and memory # (Some of these are valid for many DaVinci family chips) dict set dm365 sram0 0x00010000 dict set dm365 sram1 0x00014000 dict set dm365 sysbase 0x01c40000 dict set dm365 pllc1 0x01c40800 dict set dm365 pllc2 0x01c40c00 dict set dm365 psc 0x01c41000 dict set dm365 gpio 0x01c67000 dict set dm365 a_emif 0x01d10000 dict set dm365 a_emif_cs0 0x02000000 dict set dm365 a_emif_cs1 0x04000000 dict set dm365 ddr_emif 0x20000000 dict set dm365 ddr 0x80000000 source [find target/davinci.cfg] ################ # GDB target: the ARM, using SRAM1 for scratch. SRAM0 (also 16K) # and the ETB memory (4K) are other options, while trace is unused. set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm926ejs -chain-position $_TARGETNAME # NOTE that work-area-virt presumes a Linux 2.6.30-rc2+ kernel, # and that the work area is used only with a kernel mmu context ... $_TARGETNAME configure \ -work-area-virt [expr {0xfffe0000 + 0x4000}] \ -work-area-phys [dict get $dm365 sram1] \ -work-area-size 0x4000 \ -work-area-backup 0 # be absolutely certain the JTAG clock will work with the worst-case # CLKIN = 19.2 MHz (best case: 36 MHz) even when no bootloader turns # on the PLL and starts using it. OK to speed up after clock setup. adapter speed 1500 $_TARGETNAME configure -event "reset-start" { adapter speed 1500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable # trace setup etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_dm6446.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments DaVinci family: TMS320DM6446 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME dm6446 } # TI boards default to EMU0/EMU1 *high* -- ARM and ETB are *disabled* # after JTAG reset until ICEpick is used to route them in. set EMU01 "-disable" # With EMU0/EMU1 jumpered *low* ARM and ETB are *enabled* without # needing any ICEpick interaction. #set EMU01 "-enable" source [find target/icepick.cfg] # Subsidiary TAP: unknown ... must enable via ICEpick jtag newtap $_CHIPNAME unknown -irlen 8 -disable jtag configure $_CHIPNAME.unknown -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 3" # Subsidiary TAP: C64x+ DSP ... must enable via ICEpick jtag newtap $_CHIPNAME dsp -irlen 38 -ircapture 0x25 -irmask 0x3f -disable jtag configure $_CHIPNAME.dsp -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 2" # Subsidiary TAP: ARM ETB11, with scan chain for 4K of ETM trace buffer if { [info exists ETB_TAPID] } { set _ETB_TAPID $ETB_TAPID } else { set _ETB_TAPID 0x2b900f0f } jtag newtap $_CHIPNAME etb -irlen 4 -irmask 0xf -expected-id $_ETB_TAPID $EMU01 jtag configure $_CHIPNAME.etb -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 1" # Subsidiary TAP: ARM926ejs with scan chains for ARM Debug, EmbeddedICE-RT, ETM. if { [info exists CPU_TAPID] } { set _CPU_TAPID $CPU_TAPID } else { set _CPU_TAPID 0x07926001 } jtag newtap $_CHIPNAME arm -irlen 4 -irmask 0xf -expected-id $_CPU_TAPID $EMU01 jtag configure $_CHIPNAME.arm -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 0" # Primary TAP: ICEpick-C (JTAG route controller) and boundary scan if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } else { set _JRC_TAPID 0x0b70002f } jtag newtap $_CHIPNAME jrc -irlen 6 -irmask 0x3f -expected-id $_JRC_TAPID jtag configure $_CHIPNAME.jrc -event setup \ "jtag tapenable $_CHIPNAME.etb; jtag tapenable $_CHIPNAME.arm" ################ # GDB target: the ARM, using SRAM1 for scratch. SRAM0 (also 8K) # and the ETB memory (4K) are other options, while trace is unused. # Little-endian; use the OpenOCD default. set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm926ejs -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x0000a000 -work-area-size 0x2000 # be absolutely certain the JTAG clock will work with the worst-case # CLKIN = 20 MHz (best case: 30 MHz) even when no bootloader turns # on the PLL and starts using it. OK to speed up after clock setup. adapter speed 1500 $_TARGETNAME configure -event "reset-start" { adapter speed 1500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable # trace setup etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_k3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments K3 devices: # * AM654x: https://www.ti.com/lit/pdf/spruid7 # Has 4 ARMV8 Cores and 2 R5 Cores and an M3 # * J721E: https://www.ti.com/lit/pdf/spruil1 # Has 2 ARMV8 Cores and 6 R5 Cores and an M3 # * J7200: https://www.ti.com/lit/pdf/spruiu1 # Has 2 ARMV8 Cores and 4 R5 Cores and an M3 # * AM642: https://www.ti.com/lit/pdf/spruim2 # Has 2 ARMV8 Cores and 4 R5 Cores, M4F and an M3 # source [find target/swj-dp.tcl] if { [info exists SOC] } { set _soc $SOC } else { set _soc am654 } # set V8_SMP_DEBUG to non 0 value in board if you'd like to use SMP debug if { [info exists V8_SMP_DEBUG] } { set _v8_smp_debug $V8_SMP_DEBUG } else { set _v8_smp_debug 0 } # Common Definitions # System Controller is the very first processor - all current SoCs have it. set CM3_CTIBASE {0x3C016000} # sysctrl power-ap unlock offsets set _sysctrl_ap_unlock_offsets {0xf0 0x44} # All the ARMV8s are the next processors. # CL0,CORE0 CL0,CORE1 CL1,CORE0 CL1,CORE1 set ARMV8_DBGBASE {0x90410000 0x90510000 0x90810000 0x90910000} set ARMV8_CTIBASE {0x90420000 0x90520000 0x90820000 0x90920000} # And we add up the R5s # (0)MCU 0 (1)MCU 1 (2)MAIN_0_0 (3)MAIN_0_1 (4)MAIN_1_0 (5)MAIN_1_1 set R5_DBGBASE {0x9d010000 0x9d012000 0x9d410000 0x9d412000 0x9d510000 0x9d512000} set R5_CTIBASE {0x9d018000 0x9d019000 0x9d418000 0x9d419000 0x9d518000 0x9d519000} set R5_NAMES {mcu_r5.0 mcu_r5.1 main0_r5.0 main0_r5.1 main1_r5.0 main1_r5.1} # Finally an General Purpose(GP) MCU set CM4_CTIBASE {0x20001000} # General Purpose MCU (M4) may be present on some very few SoCs set _gp_mcu_cores 0 # General Purpose MCU power-ap unlock offsets set _gp_mcu_ap_unlock_offsets {0xf0 0x60} # Set configuration overrides for each SOC switch $_soc { am654 { set _CHIPNAME am654 set _K3_DAP_TAPID 0x0bb5a02f # AM654 has 2 clusters of 2 A53 cores each. set _armv8_cpu_name a53 set _armv8_cores 4 # AM654 has 1 cluster of 2 R5s cores. set _r5_cores 2 set R5_NAMES {mcu_r5.0 mcu_r5.1} # Sysctrl power-ap unlock offsets set _sysctrl_ap_unlock_offsets {0xf0 0x50} } am642 { set _CHIPNAME am642 set _K3_DAP_TAPID 0x0bb3802f # AM642 has 1 clusters of 2 A53 cores each. set _armv8_cpu_name a53 set _armv8_cores 2 set ARMV8_DBGBASE {0x90010000 0x90110000} set ARMV8_CTIBASE {0x90020000 0x90120000} # AM642 has 2 cluster of 2 R5s cores. set _r5_cores 4 set R5_NAMES {main0_r5.0 main0_r5.1 main1_r5.0 main1_r5.1} set R5_DBGBASE {0x9d410000 0x9d412000 0x9d510000 0x9d512000} set R5_CTIBASE {0x9d418000 0x9d419000 0x9d518000 0x9d519000} # M4 processor set _gp_mcu_cores 1 } am625 { set _CHIPNAME am625 set _K3_DAP_TAPID 0x0bb7e02f # AM625 has 1 clusters of 4 A53 cores. set _armv8_cpu_name a53 set _armv8_cores 4 set ARMV8_DBGBASE {0x90010000 0x90110000 0x90210000 0x90310000} set ARMV8_CTIBASE {0x90020000 0x90120000 0x90220000 0x90320000} # AM625 has 1 cluster of 1 R5s core. set _r5_cores 1 set R5_NAMES {main0_r5.0} set R5_DBGBASE {0x9d410000} set R5_CTIBASE {0x9d418000} # sysctrl CTI base set CM3_CTIBASE {0x20001000} # Sysctrl power-ap unlock offsets set _sysctrl_ap_unlock_offsets {0xf0 0x78} # M4 processor set _gp_mcu_cores 1 set _gp_mcu_ap_unlock_offsets {0xf0 0x7c} } j721e { set _CHIPNAME j721e set _K3_DAP_TAPID 0x0bb6402f # J721E has 1 cluster of 2 A72 cores. set _armv8_cpu_name a72 set _armv8_cores 2 # J721E has 3 clusters of 2 R5 cores each. set _r5_cores 6 } j7200 { set _CHIPNAME j7200 set _K3_DAP_TAPID 0x0bb6d02f # J7200 has 1 cluster of 2 A72 cores. set _armv8_cpu_name a72 set _armv8_cores 2 # J7200 has 2 clusters of 2 R5 cores each. set _r5_cores 4 set R5_DBGBASE {0x9d010000 0x9d012000 0x9d110000 0x9d112000} set R5_CTIBASE {0x9d018000 0x9d019000 0x9d118000 0x9d119000} # M3 CTI base set CM3_CTIBASE {0x20001000} } j721s2 { set _CHIPNAME j721s2 set _K3_DAP_TAPID 0x0bb7502f # J721s2 has 1 cluster of 2 A72 cores. set _armv8_cpu_name a72 set _armv8_cores 2 # J721s2 has 3 clusters of 2 R5 cores each. set _r5_cores 6 # sysctrl CTI base set CM3_CTIBASE {0x20001000} # Sysctrl power-ap unlock offsets set _sysctrl_ap_unlock_offsets {0xf0 0x78} # M4 processor set _gp_mcu_cores 1 set _gp_mcu_ap_unlock_offsets {0xf0 0x7c} } default { echo "'$_soc' is invalid!" } } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_K3_DAP_TAPID -ignore-version dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu set _CTINAME $_CHIPNAME.cti # sysctrl is always present cti create $_CTINAME.sysctrl -dap $_CHIPNAME.dap -ap-num 7 -baseaddr [lindex $CM3_CTIBASE 0] target create $_TARGETNAME.sysctrl cortex_m -dap $_CHIPNAME.dap -ap-num 7 -defer-examine $_TARGETNAME.sysctrl configure -event reset-assert { } proc sysctrl_up {} { # To access sysctrl, we need to enable the JTAG access for the same. # Ensure Power-AP unlocked $::_CHIPNAME.dap apreg 3 [lindex $::_sysctrl_ap_unlock_offsets 0] 0x00190000 $::_CHIPNAME.dap apreg 3 [lindex $::_sysctrl_ap_unlock_offsets 1] 0x00102098 $::_TARGETNAME.sysctrl arp_examine } $_TARGETNAME.sysctrl configure -event gdb-attach { sysctrl_up # gdb-attach default rule halt 1000 } proc _cpu_no_smp_up {} { set _current_target [target current] set _current_type [$_current_target cget -type] $_current_target arp_examine $_current_target $_current_type dbginit } proc _armv8_smp_up {} { for { set _core 0 } { $_core < $::_armv8_cores } { incr _core } { $::_TARGETNAME.$::_armv8_cpu_name.$_core arp_examine $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 dbginit $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 smp on } # Set Default target as core 0 targets $::_TARGETNAME.$::_armv8_cpu_name.0 } set _v8_smp_targets "" for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { cti create $_CTINAME.$_armv8_cpu_name.$_core -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [lindex $ARMV8_CTIBASE $_core] target create $_TARGETNAME.$_armv8_cpu_name.$_core aarch64 -dap $_CHIPNAME.dap \ -dbgbase [lindex $ARMV8_DBGBASE $_core] -cti $_CTINAME.$_armv8_cpu_name.$_core -defer-examine set _v8_smp_targets "$_v8_smp_targets $_TARGETNAME.$_armv8_cpu_name.$_core" if { $_v8_smp_debug == 0 } { $_TARGETNAME.$_armv8_cpu_name.$_core configure -event gdb-attach { _cpu_no_smp_up # gdb-attach default rule halt 1000 } } else { $_TARGETNAME.$_armv8_cpu_name.$_core configure -event gdb-attach { _armv8_smp_up # gdb-attach default rule halt 1000 } } } # Setup ARMV8 proc commands based on CPU to prevent people confusing SoCs set _armv8_up_cmd "$_armv8_cpu_name"_up # Available if V8_SMP_DEBUG is set to non-zero value set _armv8_smp_cmd "$_armv8_cpu_name"_smp if { $_v8_smp_debug == 0 } { proc $_armv8_up_cmd { args } { foreach _core $args { targets $_core _cpu_no_smp_up } } } else { proc $_armv8_smp_cmd { args } { _armv8_smp_up } # Declare SMP target smp $:::_v8_smp_targets } for { set _core 0 } { $_core < $_r5_cores } { incr _core } { set _r5_name [lindex $R5_NAMES $_core] cti create $_CTINAME.$_r5_name -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [lindex $R5_CTIBASE $_core] # inactive core examination will fail - wait till startup of additional core target create $_TARGETNAME.$_r5_name cortex_r4 -dap $_CHIPNAME.dap \ -dbgbase [lindex $R5_DBGBASE $_core] -ap-num 1 -defer-examine $_TARGETNAME.$_r5_name configure -event gdb-attach { _cpu_no_smp_up # gdb-attach default rule halt 1000 } } proc r5_up { args } { foreach _core $args { targets $_core _cpu_no_smp_up } } if { $_gp_mcu_cores != 0 } { cti create $_CTINAME.gp_mcu -dap $_CHIPNAME.dap -ap-num 8 -baseaddr [lindex $CM4_CTIBASE 0] target create $_TARGETNAME.gp_mcu cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine $_TARGETNAME.gp_mcu configure -event reset-assert { } proc gp_mcu_up {} { # To access GP MCU, we need to enable the JTAG access for the same. # Ensure Power-AP unlocked $::_CHIPNAME.dap apreg 3 [lindex $::_gp_mcu_ap_unlock_offsets 0] 0x00190000 $::_CHIPNAME.dap apreg 3 [lindex $::_gp_mcu_ap_unlock_offsets 1] 0x00102098 $::_TARGETNAME.gp_mcu arp_examine } $_TARGETNAME.gp_mcu configure -event gdb-attach { gp_mcu_up # gdb-attach default rule halt 1000 } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_msp432.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Texas Instruments MSP432 - ARM Cortex-M4F @ up to 48 MHz # # http://www.ti.com/MSP432 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME msp432 } if { [info exists CPUTAPID] } { set _DAP_TAPID $CPUTAPID } else { set _DAP_TAPID 0x4ba00477 } if { [info exists DAP_SWD_ID] } { set _DAP_SWD_ID $DAP_SWD_ID } else { set _DAP_SWD_ID 0x2ba01477 } source [find target/swj-dp.tcl] if { [using_jtag] } { set _DAP_ID $_DAP_TAPID } else { set _DAP_ID $_DAP_SWD_ID } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_DAP_ID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME msp432 0 0 0 0 $_TARGETNAME cortex_m reset_config sysresetreq ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_rm4x.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later source [find target/ti_tms570.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_tms570.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later adapter speed 1500 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME tms570 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN big } # TMS570 has an ICEpick-C on which we need the router commands. source [find target/icepick.cfg] # Main DAP # DAP_TAPID should be set before source-ing this file if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable -ignore-version jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" # ICEpick-C (JTAG route controller) # JRC_TAPID should be set before source-ing this file if { [info exists JRC_TAPID] } { set _JRC_TAPID $JRC_TAPID } set _JRC_TAPID2 0x0B7B302F set _JRC_TAPID3 0x0B95502F set _JRC_TAPID4 0x0B97102F set _JRC_TAPID5 0x0D8A002F set _JRC_TAPID6 0x0B8A002F jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \ -expected-id $_JRC_TAPID \ -expected-id $_JRC_TAPID2 \ -expected-id $_JRC_TAPID3 \ -expected-id $_JRC_TAPID4 \ -expected-id $_JRC_TAPID5 \ -expected-id $_JRC_TAPID6 \ -ignore-version jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu" jtag configure $_CHIPNAME.jrc -event post-reset "runtest 100" dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # Cortex-R4 target set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_r4 -endian $_ENDIAN \ -dap $_CHIPNAME.dap -coreid 0 -dbgbase 0x80001000 # TMS570 uses quirky BE-32 mode $_CHIPNAME.dap ti_be_32_quirks 1 $_TARGETNAME configure -event "reset-assert" { global _CHIPNAME # assert warm system reset through ICEPick icepick_c_wreset $_CHIPNAME.jrc } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_tms570lc43xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later set DAP_TAPID 0x0B95A02F set JRC_TAPID 0x0B95A02F source [find target/ti_tms570.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_tms570ls20xxx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # TMS570LS20216, TMS570LS20206, TMS570LS10216 # TMS570LS10206, TMS570LS10116, TMS570LS10106 set DAP_TAPID 0x0B7B302F set JRC_TAPID 0x0B7B302F source [find target/ti_tms570.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/ti_tms570ls3137.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # TMS570LS3137 set DAP_TAPID 0x0B8A002F set JRC_TAPID 0x0B8A002F source [find target/ti_tms570.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/tmpa900.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: Toshiba TMPA900 ###################################### if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME tmpa900 } # Toshiba TMPA900 series MCUs are always little endian as per datasheet. set _ENDIAN little if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926031 } #TMPA900 has following IDs: # CP15.0 register 0x41069265 # CP15.1 register 0x1d152152 # ARM core 0x07926031 # jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst adapter srst delay 20 jtag_ntrst_delay 20 ###################### # Target configuration ###################### set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME # Internal RAM-0 (16kB): 0xf8004000 # Internal RAM-1 (8kB): 0xf8008000 # Use internal RAM-0 and RAM-1 as working area (24kB total). $_TARGETNAME configure -work-area-phys 0xf8004000 -work-area-size 0x6000 \ -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/tmpa910.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later ###################################### # Target: Toshiba TMPA910 ###################################### if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME tmpa910 } # Toshiba TMPA910 series MCUs are always little endian as per datasheet. set _ENDIAN little if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x07926031 } #TMPA910 has following IDs: # CP15.0 register 0x41069265 # CP15.1 register 0x1d152152 # ARM core 0x07926031 # jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst adapter srst delay 20 jtag_ntrst_delay 20 ###################### # Target configuration ###################### set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME # Internal RAM-0 (16kB): 0xf8004000 # Internal RAM-1 (16kB): 0xf8008000 # Internal RAM-2 (16kB): 0xf800c000 # Use internal RAM-0, RAM-1, and RAM-2 as working area (48kB total). $_TARGETNAME configure -work-area-phys 0xf8004000 -work-area-size 0xc000 \ -work-area-backup 0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/tnetc4401.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Texas Instruments (TI) TNETC4401, MIPS32 DOCSIS-tailored SoC (4Kc-based) # Used in Knovative KC-100 and Motorola Surfboard SB5120 cable modems. # Datasheet: https://brezn.muc.ccc.de/~mazzoo/DOCSIS/tnetc4401.pdf transport select jtag set _TARGETNAME tnetc4401 set _CPUTAPID 0x0000100f jtag newtap $_TARGETNAME tap -irlen 5 -ircapture 0x01 -irmask 0x1f -expected-id $_CPUTAPID target create $_TARGETNAME mips_m4k -chain-position $_TARGETNAME.tap -endian big # May need to halt manually before calling reset init $_TARGETNAME configure -event reset-init { halt echo "Attempting to disable watchdog..." mwb phys 0xa8610b00 0 256 halt wait_halt } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/u8500.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) ST-Ericsson SA 2011 # Author : michel.jaouen@stericsson.com # U8500 target proc mmu_off {} { set cp [arm mrc 15 0 1 0 0] set cp [expr {$cp & ~1}] arm mcr 15 0 1 0 0 $cp } proc mmu_on {} { set cp [arm mrc 15 0 1 0 0] set cp [expr {$cp | 1}] arm mcr 15 0 1 0 0 $cp } proc ocd_gdb_restart {target_id} { global _TARGETNAME_1 global _SMP targets $_TARGETNAME_1 if { $_SMP == 1 } { cortex_a smp off } rst_run halt if { $_SMP == 1 } { cortex_a smp on } } proc smp_reg {} { global _TARGETNAME_1 global _TARGETNAME_2 targets $_TARGETNAME_1 echo "$_TARGETNAME_1" set pc1 [reg pc] set stck1 [reg sp_svc] targets $_TARGETNAME_2 echo "$_TARGETNAME_1" set pc2 [reg pc] set stck2 [reg sp_svc] } proc u8500_tapenable {chip val} { echo "JTAG tap enable $chip" } proc pwrsts { } { global _CHIPNAME irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 0 set pwrsts [drscan $_CHIPNAME.jrc 16 0] echo "pwrsts ="$pwrsts set a9 [expr "0x$pwrsts & 0xc"] set ape [expr "0x$pwrsts & 0x3"] if {[string equal "0" $ape]} { echo "ape off" } else { echo "ape on" } echo "$a9" switch $a9 { 4 { echo "A9 in retention" } 8 { echo "A9 100% DVFS" } c { echo "A9 50% DVFS" } } } proc poll_pwrsts { } { global _CHIPNAME set result 1 set i 0 irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 0 set pwrsts [drscan $_CHIPNAME.jrc 16 0] set pwrsts [expr "0x$pwrsts & 0xc"] while {[string equal "4" $pwrsts] && $i<20} { irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 0; set pwrsts [drscan $_CHIPNAME.jrc 16 0] set pwrsts [expr "0x$pwrsts & 0xc"] if {![string equal "4" $pwrsts]} { set result 1 } else { set result 0 sleep 200 echo "loop $i" } incr i } return $result } proc halt_ { } { if {[poll_pwrsts]==1} { halt } else { echo "halt failed : target in retention" } } proc u8500_dapenable {chip} { } proc u8500_tapdisable {chip val} { echo "JTAG tap disable $chip" } proc enable_apetap {} { global _CHIPNAME global _TARGETNAME_2 global _TARGETNAME_1 poll off irscan $_CHIPNAME.jrc 0x3e drscan $_CHIPNAME.jrc 8 0xcf jtag tapenable $_CHIPNAME.dap irscan $_CHIPNAME.jrc 0x6 drscan $_CHIPNAME.jrc 32 0 irscan $_CHIPNAME.jrc 0x6 drscan $_CHIPNAME.jrc 32 0 set status [$_TARGETNAME_1 curstate] if {[string equal "unknown" $status]} { $_TARGETNAME_1 arp_examine cache_config l2x 0xa0412000 8 } set status [$_TARGETNAME_2 curstate] if {[string equal "unknown" $status]} { $_TARGETNAME_2 arp_examine } } tcl_port 5555 telnet_port 4444 gdb_port 3333 if { [info exists CHIPNAME] } { global _CHIPNAME set _CHIPNAME $CHIPNAME } else { global _CHIPNAME set _CHIPNAME u8500 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { # this defaults to a bigendian set _ENDIAN little } # Subsidiary TAP: APE with scan chains for ARM Debug, EmbeddedICE-RT, if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x4ba00477 } jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0xe -irmask 0xf -expected-id $_CPUTAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable \ "u8500_dapenable $_CHIPNAME.cpu" jtag configure $_CHIPNAME.cpu -event tap-disable \ "u8500_tapdisable $_CHIPNAME.cpu 0xc0" #CLTAPC TAP JRC equivalent if { [info exists CLTAPC_ID] } { set _CLTAPC_ID $CLTAPC_ID } else { set _CLTAPC_ID 0x22286041 } jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x6 -irmask 0xf -expected-id $_CLTAPC_ID -ignore-version if { ![info exists TARGETNAME_1] } { global _TARGETNAME_1 set _TARGETNAME_1 $_CHIPNAME.cpu1 } else { global _TARGETNAME_1 set _TARGETNAME_1 $TARGETNAME_1 } if { [info exists DAP_DBG1] } { set _DAP_DBG1 $DAP_DBG1 } else { set _DAP_DBG1 0x801A8000 } if { [info exists DAP_DBG2] } { set _DAP_DBG2 $DAP_DBG2 } else { set _DAP_DBG2 0x801AA000 } dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME_1 cortex_a -dap $_CHIPNAME.dap -dbgbase $_DAP_DBG1 -coreid 0 -rtos linux if { ![info exists TARGETNAME_2] } { global _TARGETNAME_2 set _TARGETNAME_2 $_CHIPNAME.cpu2 } else { global _TARGETNAME_2 set _TARGETNAME_2 $TARGETNAME_2 } target create $_TARGETNAME_2 cortex_a -dap $_CHIPNAME.dap -dbgbase $_DAP_DBG2 -coreid 1 -rtos linux if {![info exists SMP]} { global _SMP set _SMP 1 } else { global _SMP set _SMP $SMP } global SMP if { $_SMP == 1} { target smp $_CHIPNAME.cpu2 $_CHIPNAME.cpu1 } proc secsts1 { } { global _CHIPNAME irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 4 set secsts1 [drscan $_CHIPNAME.jrc 16 0] echo "secsts1 ="$secsts1 set secsts1 [expr "0x$secsts1 & 0x4"] if {![string equal "4" $secsts1]} { echo "APE target secured" } else { echo "APE target not secured" } } proc att { } { global _CHIPNAME jtag arp_init irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 4 set secsts1 [drscan $_CHIPNAME.jrc 16 0] echo "secsts1 ="$secsts1 set secsts1 [expr "0x$secsts1 & 0x4"] if {[string equal "4" $secsts1]} { if {[poll_pwrsts]==1} { enable_apetap } else { echo "target in retention" } } else { echo "target secured" } } proc rst_run { } { global _CHIPNAME global _TARGETNAME_2 global _TARGETNAME_1 set status [$_TARGETNAME_1 curstate] if {[string equal "halted" $status]} { resume targets $_TARGETNAME_1 } set status [$_TARGETNAME_2 curstate] if {[string equal "halted" $status]} { resume targets $_TARGETNAME_2 } poll off jtag arp_init reset sleep 20 irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 4 set secsts1 [drscan $_CHIPNAME.jrc 16 0] echo "secsts1 ="$secsts1 set secsts1 [expr "0x$secsts1 & 0x4"] while {![string equal "4" $secsts1]} { irscan u8500.jrc 0x3a drscan u8500.jrc 4 4 set secsts1 [drscan $_CHIPNAME.jrc 16 0] echo "secsts1 ="$secsts1 set secsts1 [expr "0x$secsts1 & 0x4"] } echo "ape debugable" enable_apetap poll on targets $_TARGETNAME_1 dap apsel 1 } if {![info exists MAXSPEED]} { global _MAXSPEED set _MAXSPEED 15000 } else { global _MAXSPEED set _MAXSPEED $MAXSPEED } global _MAXSPEED adapter speed $_MAXSPEED gdb_breakpoint_override hard set mem inaccessible-by-default-off jtag_ntrst_delay 100 reset_config trst_and_srst combined ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/vd_aarch64.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # Arm v8 64b Cortex A if {![info exists _CORES]} { set _CORES 1 } if {![info exists _CHIPNAME]} { set _CHIPNAME aarch64 } set _TARGETNAME $_CHIPNAME.cpu set _CTINAME $_CHIPNAME.cti set DBGBASE {0x80810000 0x80910000} set CTIBASE {0x80820000 0x80920000} dap create $_CHIPNAME.dap -chain-position $_TARGETNAME $_CHIPNAME.dap apsel 1 for { set _core 0 } { $_core < $_CORES } { incr _core } \ { cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 -baseaddr [lindex $CTIBASE $_core] set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core -coreid $_core" if { $_core != 0 } { # non-boot core examination may fail set _command "$_command -defer-examine" set _smp_command "$_smp_command $_TARGETNAME.$_core" } else { set _smp_command "target smp $_TARGETNAME.$_core" } eval $_command } eval $_smp_command # default target is core 0 targets $_TARGETNAME.0 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/vd_cortex_m.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # ARM Cortex M if {![info exists _CHIPNAME]} { set _CHIPNAME cortex_m } set _TARGETNAME $_CHIPNAME.cpu dap create $_CHIPNAME.dap -chain-position $_TARGETNAME target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/vd_riscv.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Cadence virtual debug interface # RISCV core if {![info exists _HARTID]} { set _HARTID 0x00 } if {![info exists _CHIPNAME]} { set _CHIPNAME riscv } set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid $_HARTID riscv set_reset_timeout_sec 120 riscv set_command_timeout_sec 120 riscv set_mem_access sysbus progbuf ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/vybrid_vf6xx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Freescale Vybrid VF610 # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME vf610 } if { [info exists A5_JTAG_TAPID] } { set _A5_JTAG_TAPID $A5_JTAG_TAPID } else { set _A5_JTAG_TAPID 0x4BA00477 } if { [info exists A5_SWD_TAPID] } { set _A5_SWD_TAPID $A5_SWD_TAPID } else { set _A5_SWD_TAPID 0x3BA02477 } if { [using_jtag] } { set _A5_TAPID $_A5_JTAG_TAPID } else { set _A5_TAPID $_A5_SWD_TAPID } source [find target/swj-dp.tcl] swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_A5_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create ${_TARGETNAME}0 cortex_a -dap $_CHIPNAME.dap -dbgbase 0xc0088000 target create ${_TARGETNAME}1 cortex_m -dap $_CHIPNAME.dap -ap-num 3 -defer-examine adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/xilinx_zynqmp.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # target configuration for # Xilinx ZynqMP (UltraScale+ / A53) # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME uscale } # # DAP tap (Quard core A53) # if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } else { set _DAP_TAPID 0x5ba00477 } jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap # # PS tap (UltraScale+) # if { [info exists PS_TAPID] } { set _PS_TAPID $PS_TAPID jtag newtap $_CHIPNAME ps -irlen 12 -ircapture 0x1 -irmask 0x03 -expected-id $_PS_TAPID } else { # FPGA Programmable logic. Values take from Table 39-1 in UG1085: jtag newtap $_CHIPNAME ps -irlen 12 -ircapture 0x1 -irmask 0x03 -ignore-version \ -expected-id 0x04711093 \ -expected-id 0x04710093 \ -expected-id 0x04721093 \ -expected-id 0x04720093 \ -expected-id 0x04739093 \ -expected-id 0x04730093 \ -expected-id 0x04738093 \ -expected-id 0x04740093 \ -expected-id 0x04750093 \ -expected-id 0x04759093 \ -expected-id 0x04758093 } set jtag_configured 0 jtag configure $_CHIPNAME.ps -event setup { global _CHIPNAME global jtag_configured if { $jtag_configured == 0 } { # add the DAP tap to the chain # See https://forums.xilinx.com/t5/UltraScale-Architecture/JTAG-Chain-Configuration-for-Zynq-UltraScale-MPSoC/td-p/758924 irscan $_CHIPNAME.ps 0x824 drscan $_CHIPNAME.ps 32 0x00000003 runtest 100 # setup event will be re-entered through jtag arp_init # break the recursion set jtag_configured 1 # re-initialized the jtag chain jtag arp_init } } set _TARGETNAME $_CHIPNAME.a53 set _CTINAME $_CHIPNAME.cti set _smp_command "" set DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} set CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core } { cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [lindex $CTIBASE $_core] set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core" if { $_core != 0 } { # non-boot core examination may fail set _command "$_command -defer-examine" set _smp_command "$_smp_command $_TARGETNAME.$_core" } else { set _command "$_command -rtos hwthread" set _smp_command "target smp $_TARGETNAME.$_core" } eval $_command } target create uscale.axi mem_ap -dap uscale.dap -ap-num 0 eval $_smp_command targets $_TARGETNAME.0 proc core_up { args } { global _TARGETNAME foreach core $args { $_TARGETNAME.$core arp_examine } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/xmc1xxx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Infineon XMC1100/XMC1200/XMC1300 family (ARM Cortex-M0 @ 32 MHz) # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xmc1000 } # # Only SWD and SPD supported # source [find target/swj-dp.tcl] if { [info exists CPUTAPID] } { set _CPU_SWD_TAPID $CPUTAPID } else { set _CPU_SWD_TAPID 0x0BB11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_SWD_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x4000 } $_TARGETNAME configure -work-area-phys 0x20000000 \ -work-area-size $_WORKAREASIZE \ -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME xmc1xxx 0x10000000 0 0 0 $_TARGETNAME adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/xmc4xxx.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # Infineon XMC4100/XMC4200/XMC4400/XMC4500 family (ARM Cortex-M4 @ 80-120 MHz) # if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xmc4000 } source [find target/swj-dp.tcl] # # SWJ-DP # if { [info exists CPU_JTAG_TAPID] } { set _CPU_JTAG_TAPID $CPU_JTAG_TAPID } else { set _CPU_JTAG_TAPID 0x4BA00477 } # # SW_DP # if { [info exists CPU_SWD_TAPID] } { set _CPU_SWD_TAPID $CPU_SWD_TAPID } else { set _CPU_SWD_TAPID 0x2BA01477 } if { [using_jtag] } { set _CPU_TAPID $_CPU_JTAG_TAPID } else { set _CPU_TAPID $_CPU_SWD_TAPID } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap # Work-area is a space in RAM used for flash programming # By default use 16 kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { set _WORKAREASIZE 0x1000 } $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME xmc4xxx 0x0C000000 0 0 0 $_TARGETNAME if { ![using_hla] } { cortex_m reset_config sysresetreq } adapter speed 1000 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/xmos_xs1-xau8a-10_arm.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # # XMOS xCORE-XA XS1-XAU8A-10: ARM Cortex-M3 @ 48 MHz # # http://www.xmos.com/products/silicon/xcore-xa/xa-series # if { ![info exists CHIPNAME] } { set CHIPNAME xcorexa } if { ![info exists WORKAREASIZE] } { # XS1-XAU8A-10-FB265: 128 KB SRAM set WORKAREASIZE 0x20000 } source [find target/efm32.cfg] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/xtensa-core-esp32.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # OpenOCD configuration file for Xtensa ESP32 target # Core definition and ABI xtensa xtdef LX xtensa xtopt arnum 64 xtensa xtopt windowed 1 # Exception/Interrupt Options xtensa xtopt exceptions 1 xtensa xtopt hipriints 1 xtensa xtopt intlevels 6 xtensa xtopt excmlevel 3 # Cache Options xtensa xtmem icache 4 0 1 xtensa xtmem dcache 4 0 1 0 # Memory Options xtensa xtmem irom 0x400D0000 0x330000 xtensa xtmem irom 0x40000000 0x64F00 xtensa xtmem iram 0x40070000 0x30000 xtensa xtmem iram 0x400C0000 0x2000 xtensa xtmem drom 0x3F400000 0x800000 xtensa xtmem drom 0x3FF90000 0x10000 xtensa xtmem dram 0x3FFAE000 0x52000 xtensa xtmem dram 0x3FF80000 0x2000 xtensa xtmem dram 0x3F800000 0x400000 xtensa xtmem dram 0x50000000 0x2000 xtensa xtmem dram 0x3FF00000 0x71000 xtensa xtmem dram 0x60000000 0x20000000 # Memory Protection/Translation Options # Debug Options xtensa xtopt debuglevel 6 xtensa xtopt ibreaknum 2 xtensa xtopt dbreaknum 2 xtensa xtopt tracemem 0x4000 xtensa xtopt tracememrev 1 xtensa xtopt perfcount 2 # Core Registers # xtregfmt: Optionally specify "contiguous" vs. "sparse" GDB register map. # Default setting is "sparse" and is used with xt-gdb. # If contiguous, optional parameter specifies number of registers # in "Read General Registers" (g-packet) requests. # NOTE: For contiguous format, registers listed in GDB order. # xtregs: Total number of Xtensa registers in the system xtensa xtregs 173 xtensa xtregfmt contiguous 105 xtensa xtreg pc 0x0020 xtensa xtreg ar0 0x0100 xtensa xtreg ar1 0x0101 xtensa xtreg ar2 0x0102 xtensa xtreg ar3 0x0103 xtensa xtreg ar4 0x0104 xtensa xtreg ar5 0x0105 xtensa xtreg ar6 0x0106 xtensa xtreg ar7 0x0107 xtensa xtreg ar8 0x0108 xtensa xtreg ar9 0x0109 xtensa xtreg ar10 0x010a xtensa xtreg ar11 0x010b xtensa xtreg ar12 0x010c xtensa xtreg ar13 0x010d xtensa xtreg ar14 0x010e xtensa xtreg ar15 0x010f xtensa xtreg ar16 0x0110 xtensa xtreg ar17 0x0111 xtensa xtreg ar18 0x0112 xtensa xtreg ar19 0x0113 xtensa xtreg ar20 0x0114 xtensa xtreg ar21 0x0115 xtensa xtreg ar22 0x0116 xtensa xtreg ar23 0x0117 xtensa xtreg ar24 0x0118 xtensa xtreg ar25 0x0119 xtensa xtreg ar26 0x011a xtensa xtreg ar27 0x011b xtensa xtreg ar28 0x011c xtensa xtreg ar29 0x011d xtensa xtreg ar30 0x011e xtensa xtreg ar31 0x011f xtensa xtreg ar32 0x0120 xtensa xtreg ar33 0x0121 xtensa xtreg ar34 0x0122 xtensa xtreg ar35 0x0123 xtensa xtreg ar36 0x0124 xtensa xtreg ar37 0x0125 xtensa xtreg ar38 0x0126 xtensa xtreg ar39 0x0127 xtensa xtreg ar40 0x0128 xtensa xtreg ar41 0x0129 xtensa xtreg ar42 0x012a xtensa xtreg ar43 0x012b xtensa xtreg ar44 0x012c xtensa xtreg ar45 0x012d xtensa xtreg ar46 0x012e xtensa xtreg ar47 0x012f xtensa xtreg ar48 0x0130 xtensa xtreg ar49 0x0131 xtensa xtreg ar50 0x0132 xtensa xtreg ar51 0x0133 xtensa xtreg ar52 0x0134 xtensa xtreg ar53 0x0135 xtensa xtreg ar54 0x0136 xtensa xtreg ar55 0x0137 xtensa xtreg ar56 0x0138 xtensa xtreg ar57 0x0139 xtensa xtreg ar58 0x013a xtensa xtreg ar59 0x013b xtensa xtreg ar60 0x013c xtensa xtreg ar61 0x013d xtensa xtreg ar62 0x013e xtensa xtreg ar63 0x013f xtensa xtreg lbeg 0x0200 xtensa xtreg lend 0x0201 xtensa xtreg lcount 0x0202 xtensa xtreg sar 0x0203 xtensa xtreg windowbase 0x0248 xtensa xtreg windowstart 0x0249 xtensa xtreg configid0 0x02b0 xtensa xtreg configid1 0x02d0 xtensa xtreg ps 0x02e6 xtensa xtreg threadptr 0x03e7 xtensa xtreg br 0x0204 xtensa xtreg scompare1 0x020c xtensa xtreg acclo 0x0210 xtensa xtreg acchi 0x0211 xtensa xtreg m0 0x0220 xtensa xtreg m1 0x0221 xtensa xtreg m2 0x0222 xtensa xtreg m3 0x0223 xtensa xtreg expstate 0x03e6 xtensa xtreg f64r_lo 0x03ea xtensa xtreg f64r_hi 0x03eb xtensa xtreg f64s 0x03ec xtensa xtreg f0 0x0030 xtensa xtreg f1 0x0031 xtensa xtreg f2 0x0032 xtensa xtreg f3 0x0033 xtensa xtreg f4 0x0034 xtensa xtreg f5 0x0035 xtensa xtreg f6 0x0036 xtensa xtreg f7 0x0037 xtensa xtreg f8 0x0038 xtensa xtreg f9 0x0039 xtensa xtreg f10 0x003a xtensa xtreg f11 0x003b xtensa xtreg f12 0x003c xtensa xtreg f13 0x003d xtensa xtreg f14 0x003e xtensa xtreg f15 0x003f xtensa xtreg fcr 0x03e8 xtensa xtreg fsr 0x03e9 xtensa xtreg mmid 0x0259 xtensa xtreg ibreakenable 0x0260 xtensa xtreg memctl 0x0261 xtensa xtreg atomctl 0x0263 xtensa xtreg ddr 0x0268 xtensa xtreg ibreaka0 0x0280 xtensa xtreg ibreaka1 0x0281 xtensa xtreg dbreaka0 0x0290 xtensa xtreg dbreaka1 0x0291 xtensa xtreg dbreakc0 0x02a0 xtensa xtreg dbreakc1 0x02a1 xtensa xtreg epc1 0x02b1 xtensa xtreg epc2 0x02b2 xtensa xtreg epc3 0x02b3 xtensa xtreg epc4 0x02b4 xtensa xtreg epc5 0x02b5 xtensa xtreg epc6 0x02b6 xtensa xtreg epc7 0x02b7 xtensa xtreg depc 0x02c0 xtensa xtreg eps2 0x02c2 xtensa xtreg eps3 0x02c3 xtensa xtreg eps4 0x02c4 xtensa xtreg eps5 0x02c5 xtensa xtreg eps6 0x02c6 xtensa xtreg eps7 0x02c7 xtensa xtreg excsave1 0x02d1 xtensa xtreg excsave2 0x02d2 xtensa xtreg excsave3 0x02d3 xtensa xtreg excsave4 0x02d4 xtensa xtreg excsave5 0x02d5 xtensa xtreg excsave6 0x02d6 xtensa xtreg excsave7 0x02d7 xtensa xtreg cpenable 0x02e0 xtensa xtreg interrupt 0x02e2 xtensa xtreg intset 0x02e2 xtensa xtreg intclear 0x02e3 xtensa xtreg intenable 0x02e4 xtensa xtreg vecbase 0x02e7 xtensa xtreg exccause 0x02e8 xtensa xtreg debugcause 0x02e9 xtensa xtreg ccount 0x02ea xtensa xtreg prid 0x02eb xtensa xtreg icount 0x02ec xtensa xtreg icountlevel 0x02ed xtensa xtreg excvaddr 0x02ee xtensa xtreg ccompare0 0x02f0 xtensa xtreg ccompare1 0x02f1 xtensa xtreg ccompare2 0x02f2 xtensa xtreg misc0 0x02f4 xtensa xtreg misc1 0x02f5 xtensa xtreg misc2 0x02f6 xtensa xtreg misc3 0x02f7 xtensa xtreg a0 0x0000 xtensa xtreg a1 0x0001 xtensa xtreg a2 0x0002 xtensa xtreg a3 0x0003 xtensa xtreg a4 0x0004 xtensa xtreg a5 0x0005 xtensa xtreg a6 0x0006 xtensa xtreg a7 0x0007 xtensa xtreg a8 0x0008 xtensa xtreg a9 0x0009 xtensa xtreg a10 0x000a xtensa xtreg a11 0x000b xtensa xtreg a12 0x000c xtensa xtreg a13 0x000d xtensa xtreg a14 0x000e xtensa xtreg a15 0x000f ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/xtensa-core-esp32s2.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # OpenOCD configuration file for Xtensa ESP32S2 target # Core definition and ABI xtensa xtdef LX xtensa xtopt arnum 64 xtensa xtopt windowed 1 # Exception/Interrupt Options xtensa xtopt exceptions 1 xtensa xtopt hipriints 1 xtensa xtopt intlevels 6 xtensa xtopt excmlevel 3 # Cache Options xtensa xtmem icache 4 0 1 xtensa xtmem dcache 4 0 1 0 # Memory Options xtensa xtmem irom 0x40080000 0x780000 xtensa xtmem irom 0x40000000 0x20000 xtensa xtmem iram 0x40020000 0x50000 xtensa xtmem iram 0x40070000 0x2000 xtensa xtmem drom 0x3F000000 0x400000 xtensa xtmem drom 0x3F4D3FFC 0xAAC004 xtensa xtmem drom 0x3FFA0000 0x10000 xtensa xtmem dram 0x3FFB0000 0x50000 xtensa xtmem dram 0x3FF9E000 0x2000 xtensa xtmem dram 0x50000000 0x2000 xtensa xtmem dram 0x3F500000 0xA80000 xtensa xtmem dram 0x3F400000 0xD3FFC xtensa xtmem dram 0x60000000 0x20000000 # Memory Protection/Translation Options # Debug Options xtensa xtopt debuglevel 6 xtensa xtopt ibreaknum 2 xtensa xtopt dbreaknum 2 xtensa xtopt tracemem 0x4000 xtensa xtopt tracememrev 0 xtensa xtopt perfcount 2 # Core Registers # xtregfmt: Optionally specify "contiguous" vs. "sparse" GDB register map. # Default setting is "sparse" and is used with xt-gdb. # If contiguous, optional parameter specifies number of registers # in "Read General Registers" (g-packet) requests. # NOTE: For contiguous format, registers listed in GDB order. # xtregs: Total number of Xtensa registers in the system xtensa xtregs 171 xtensa xtregfmt contiguous 73 xtensa xtreg pc 0x0020 xtensa xtreg ar0 0x0100 xtensa xtreg ar1 0x0101 xtensa xtreg ar2 0x0102 xtensa xtreg ar3 0x0103 xtensa xtreg ar4 0x0104 xtensa xtreg ar5 0x0105 xtensa xtreg ar6 0x0106 xtensa xtreg ar7 0x0107 xtensa xtreg ar8 0x0108 xtensa xtreg ar9 0x0109 xtensa xtreg ar10 0x010a xtensa xtreg ar11 0x010b xtensa xtreg ar12 0x010c xtensa xtreg ar13 0x010d xtensa xtreg ar14 0x010e xtensa xtreg ar15 0x010f xtensa xtreg ar16 0x0110 xtensa xtreg ar17 0x0111 xtensa xtreg ar18 0x0112 xtensa xtreg ar19 0x0113 xtensa xtreg ar20 0x0114 xtensa xtreg ar21 0x0115 xtensa xtreg ar22 0x0116 xtensa xtreg ar23 0x0117 xtensa xtreg ar24 0x0118 xtensa xtreg ar25 0x0119 xtensa xtreg ar26 0x011a xtensa xtreg ar27 0x011b xtensa xtreg ar28 0x011c xtensa xtreg ar29 0x011d xtensa xtreg ar30 0x011e xtensa xtreg ar31 0x011f xtensa xtreg ar32 0x0120 xtensa xtreg ar33 0x0121 xtensa xtreg ar34 0x0122 xtensa xtreg ar35 0x0123 xtensa xtreg ar36 0x0124 xtensa xtreg ar37 0x0125 xtensa xtreg ar38 0x0126 xtensa xtreg ar39 0x0127 xtensa xtreg ar40 0x0128 xtensa xtreg ar41 0x0129 xtensa xtreg ar42 0x012a xtensa xtreg ar43 0x012b xtensa xtreg ar44 0x012c xtensa xtreg ar45 0x012d xtensa xtreg ar46 0x012e xtensa xtreg ar47 0x012f xtensa xtreg ar48 0x0130 xtensa xtreg ar49 0x0131 xtensa xtreg ar50 0x0132 xtensa xtreg ar51 0x0133 xtensa xtreg ar52 0x0134 xtensa xtreg ar53 0x0135 xtensa xtreg ar54 0x0136 xtensa xtreg ar55 0x0137 xtensa xtreg ar56 0x0138 xtensa xtreg ar57 0x0139 xtensa xtreg ar58 0x013a xtensa xtreg ar59 0x013b xtensa xtreg ar60 0x013c xtensa xtreg ar61 0x013d xtensa xtreg ar62 0x013e xtensa xtreg ar63 0x013f xtensa xtreg sar 0x0203 xtensa xtreg windowbase 0x0248 xtensa xtreg windowstart 0x0249 xtensa xtreg configid0 0x02b0 xtensa xtreg configid1 0x02d0 xtensa xtreg ps 0x02e6 xtensa xtreg threadptr 0x03e7 xtensa xtreg gpio_out 0x0300 xtensa xtreg mmid 0x0259 xtensa xtreg ibreakenable 0x0260 xtensa xtreg ddr 0x0268 xtensa xtreg ibreaka0 0x0280 xtensa xtreg ibreaka1 0x0281 xtensa xtreg dbreaka0 0x0290 xtensa xtreg dbreaka1 0x0291 xtensa xtreg dbreakc0 0x02a0 xtensa xtreg dbreakc1 0x02a1 xtensa xtreg epc1 0x02b1 xtensa xtreg epc2 0x02b2 xtensa xtreg epc3 0x02b3 xtensa xtreg epc4 0x02b4 xtensa xtreg epc5 0x02b5 xtensa xtreg epc6 0x02b6 xtensa xtreg epc7 0x02b7 xtensa xtreg depc 0x02c0 xtensa xtreg eps2 0x02c2 xtensa xtreg eps3 0x02c3 xtensa xtreg eps4 0x02c4 xtensa xtreg eps5 0x02c5 xtensa xtreg eps6 0x02c6 xtensa xtreg eps7 0x02c7 xtensa xtreg excsave1 0x02d1 xtensa xtreg excsave2 0x02d2 xtensa xtreg excsave3 0x02d3 xtensa xtreg excsave4 0x02d4 xtensa xtreg excsave5 0x02d5 xtensa xtreg excsave6 0x02d6 xtensa xtreg excsave7 0x02d7 xtensa xtreg cpenable 0x02e0 xtensa xtreg interrupt 0x02e2 xtensa xtreg intset 0x02e2 xtensa xtreg intclear 0x02e3 xtensa xtreg intenable 0x02e4 xtensa xtreg vecbase 0x02e7 xtensa xtreg exccause 0x02e8 xtensa xtreg debugcause 0x02e9 xtensa xtreg ccount 0x02ea xtensa xtreg prid 0x02eb xtensa xtreg icount 0x02ec xtensa xtreg icountlevel 0x02ed xtensa xtreg excvaddr 0x02ee xtensa xtreg ccompare0 0x02f0 xtensa xtreg ccompare1 0x02f1 xtensa xtreg ccompare2 0x02f2 xtensa xtreg misc0 0x02f4 xtensa xtreg misc1 0x02f5 xtensa xtreg misc2 0x02f6 xtensa xtreg misc3 0x02f7 xtensa xtreg pwrctl 0x2014 xtensa xtreg pwrstat 0x2015 xtensa xtreg eristat 0x2016 xtensa xtreg cs_itctrl 0x2017 xtensa xtreg cs_claimset 0x2018 xtensa xtreg cs_claimclr 0x2019 xtensa xtreg cs_lockaccess 0x201a xtensa xtreg cs_lockstatus 0x201b xtensa xtreg cs_authstatus 0x201c xtensa xtreg fault_info 0x202b xtensa xtreg trax_id 0x202c xtensa xtreg trax_control 0x202d xtensa xtreg trax_status 0x202e xtensa xtreg trax_data 0x202f xtensa xtreg trax_address 0x2030 xtensa xtreg trax_pctrigger 0x2031 xtensa xtreg trax_pcmatch 0x2032 xtensa xtreg trax_delay 0x2033 xtensa xtreg trax_memstart 0x2034 xtensa xtreg trax_memend 0x2035 xtensa xtreg pmg 0x2043 xtensa xtreg pmpc 0x2044 xtensa xtreg pm0 0x2045 xtensa xtreg pm1 0x2046 xtensa xtreg pmctrl0 0x2047 xtensa xtreg pmctrl1 0x2048 xtensa xtreg pmstat0 0x2049 xtensa xtreg pmstat1 0x204a xtensa xtreg ocdid 0x204b xtensa xtreg ocd_dcrclr 0x204c xtensa xtreg ocd_dcrset 0x204d xtensa xtreg ocd_dsr 0x204e xtensa xtreg a0 0x0000 xtensa xtreg a1 0x0001 xtensa xtreg a2 0x0002 xtensa xtreg a3 0x0003 xtensa xtreg a4 0x0004 xtensa xtreg a5 0x0005 xtensa xtreg a6 0x0006 xtensa xtreg a7 0x0007 xtensa xtreg a8 0x0008 xtensa xtreg a9 0x0009 xtensa xtreg a10 0x000a xtensa xtreg a11 0x000b xtensa xtreg a12 0x000c xtensa xtreg a13 0x000d xtensa xtreg a14 0x000e xtensa xtreg a15 0x000f ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/xtensa-core-esp32s3.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # OpenOCD configuration file for Xtensa ESP32S3 target # Core definition and ABI xtensa xtdef LX xtensa xtopt arnum 64 xtensa xtopt windowed 1 # Exception/Interrupt Options xtensa xtopt exceptions 1 xtensa xtopt hipriints 1 xtensa xtopt intlevels 6 xtensa xtopt excmlevel 3 # Cache Options # Memory Options xtensa xtmem irom 0x42000000 0x2000000 xtensa xtmem irom 0x40000000 0x60000 xtensa xtmem iram 0x40370000 0x70000 xtensa xtmem iram 0x600FE000 0x2000 xtensa xtmem drom 0x3C000000 0x1000000 xtensa xtmem drom 0x3FF00000 0x20000 xtensa xtmem dram 0x3FC88000 0x78000 xtensa xtmem dram 0x600FE000 0x2000 xtensa xtmem dram 0x50000000 0x2000 xtensa xtmem dram 0x60000000 0x10000000 # Memory Protection/Translation Options # Debug Options xtensa xtopt debuglevel 6 xtensa xtopt ibreaknum 2 xtensa xtopt dbreaknum 2 xtensa xtopt tracemem 0x4000 xtensa xtopt tracememrev 0 xtensa xtopt perfcount 2 # Core Registers # xtregfmt: Optionally specify "contiguous" vs. "sparse" GDB register map. # Default setting is "sparse" and is used with xt-gdb. # If contiguous, optional parameter specifies number of registers # in "Read General Registers" (g-packet) requests. # NOTE: For contiguous format, registers listed in GDB order. # xtregs: Total number of Xtensa registers in the system xtensa xtregs 228 xtensa xtregfmt contiguous 128 xtensa xtreg pc 0x0020 xtensa xtreg ar0 0x0100 xtensa xtreg ar1 0x0101 xtensa xtreg ar2 0x0102 xtensa xtreg ar3 0x0103 xtensa xtreg ar4 0x0104 xtensa xtreg ar5 0x0105 xtensa xtreg ar6 0x0106 xtensa xtreg ar7 0x0107 xtensa xtreg ar8 0x0108 xtensa xtreg ar9 0x0109 xtensa xtreg ar10 0x010a xtensa xtreg ar11 0x010b xtensa xtreg ar12 0x010c xtensa xtreg ar13 0x010d xtensa xtreg ar14 0x010e xtensa xtreg ar15 0x010f xtensa xtreg ar16 0x0110 xtensa xtreg ar17 0x0111 xtensa xtreg ar18 0x0112 xtensa xtreg ar19 0x0113 xtensa xtreg ar20 0x0114 xtensa xtreg ar21 0x0115 xtensa xtreg ar22 0x0116 xtensa xtreg ar23 0x0117 xtensa xtreg ar24 0x0118 xtensa xtreg ar25 0x0119 xtensa xtreg ar26 0x011a xtensa xtreg ar27 0x011b xtensa xtreg ar28 0x011c xtensa xtreg ar29 0x011d xtensa xtreg ar30 0x011e xtensa xtreg ar31 0x011f xtensa xtreg ar32 0x0120 xtensa xtreg ar33 0x0121 xtensa xtreg ar34 0x0122 xtensa xtreg ar35 0x0123 xtensa xtreg ar36 0x0124 xtensa xtreg ar37 0x0125 xtensa xtreg ar38 0x0126 xtensa xtreg ar39 0x0127 xtensa xtreg ar40 0x0128 xtensa xtreg ar41 0x0129 xtensa xtreg ar42 0x012a xtensa xtreg ar43 0x012b xtensa xtreg ar44 0x012c xtensa xtreg ar45 0x012d xtensa xtreg ar46 0x012e xtensa xtreg ar47 0x012f xtensa xtreg ar48 0x0130 xtensa xtreg ar49 0x0131 xtensa xtreg ar50 0x0132 xtensa xtreg ar51 0x0133 xtensa xtreg ar52 0x0134 xtensa xtreg ar53 0x0135 xtensa xtreg ar54 0x0136 xtensa xtreg ar55 0x0137 xtensa xtreg ar56 0x0138 xtensa xtreg ar57 0x0139 xtensa xtreg ar58 0x013a xtensa xtreg ar59 0x013b xtensa xtreg ar60 0x013c xtensa xtreg ar61 0x013d xtensa xtreg ar62 0x013e xtensa xtreg ar63 0x013f xtensa xtreg lbeg 0x0200 xtensa xtreg lend 0x0201 xtensa xtreg lcount 0x0202 xtensa xtreg sar 0x0203 xtensa xtreg windowbase 0x0248 xtensa xtreg windowstart 0x0249 xtensa xtreg configid0 0x02b0 xtensa xtreg configid1 0x02d0 xtensa xtreg ps 0x02e6 xtensa xtreg threadptr 0x03e7 xtensa xtreg br 0x0204 xtensa xtreg scompare1 0x020c xtensa xtreg acclo 0x0210 xtensa xtreg acchi 0x0211 xtensa xtreg m0 0x0220 xtensa xtreg m1 0x0221 xtensa xtreg m2 0x0222 xtensa xtreg m3 0x0223 xtensa xtreg gpio_out 0x030c xtensa xtreg f0 0x0030 xtensa xtreg f1 0x0031 xtensa xtreg f2 0x0032 xtensa xtreg f3 0x0033 xtensa xtreg f4 0x0034 xtensa xtreg f5 0x0035 xtensa xtreg f6 0x0036 xtensa xtreg f7 0x0037 xtensa xtreg f8 0x0038 xtensa xtreg f9 0x0039 xtensa xtreg f10 0x003a xtensa xtreg f11 0x003b xtensa xtreg f12 0x003c xtensa xtreg f13 0x003d xtensa xtreg f14 0x003e xtensa xtreg f15 0x003f xtensa xtreg fcr 0x03e8 xtensa xtreg fsr 0x03e9 xtensa xtreg accx_0 0x0300 xtensa xtreg accx_1 0x0301 xtensa xtreg qacc_h_0 0x0302 xtensa xtreg qacc_h_1 0x0303 xtensa xtreg qacc_h_2 0x0304 xtensa xtreg qacc_h_3 0x0305 xtensa xtreg qacc_h_4 0x0306 xtensa xtreg qacc_l_0 0x0307 xtensa xtreg qacc_l_1 0x0308 xtensa xtreg qacc_l_2 0x0309 xtensa xtreg qacc_l_3 0x030a xtensa xtreg qacc_l_4 0x030b xtensa xtreg sar_byte 0x030d xtensa xtreg fft_bit_width 0x030e xtensa xtreg ua_state_0 0x030f xtensa xtreg ua_state_1 0x0310 xtensa xtreg ua_state_2 0x0311 xtensa xtreg ua_state_3 0x0312 xtensa xtreg q0 0x1008 xtensa xtreg q1 0x1009 xtensa xtreg q2 0x100a xtensa xtreg q3 0x100b xtensa xtreg q4 0x100c xtensa xtreg q5 0x100d xtensa xtreg q6 0x100e xtensa xtreg q7 0x100f xtensa xtreg mmid 0x0259 xtensa xtreg ibreakenable 0x0260 xtensa xtreg memctl 0x0261 xtensa xtreg atomctl 0x0263 xtensa xtreg ddr 0x0268 xtensa xtreg ibreaka0 0x0280 xtensa xtreg ibreaka1 0x0281 xtensa xtreg dbreaka0 0x0290 xtensa xtreg dbreaka1 0x0291 xtensa xtreg dbreakc0 0x02a0 xtensa xtreg dbreakc1 0x02a1 xtensa xtreg epc1 0x02b1 xtensa xtreg epc2 0x02b2 xtensa xtreg epc3 0x02b3 xtensa xtreg epc4 0x02b4 xtensa xtreg epc5 0x02b5 xtensa xtreg epc6 0x02b6 xtensa xtreg epc7 0x02b7 xtensa xtreg depc 0x02c0 xtensa xtreg eps2 0x02c2 xtensa xtreg eps3 0x02c3 xtensa xtreg eps4 0x02c4 xtensa xtreg eps5 0x02c5 xtensa xtreg eps6 0x02c6 xtensa xtreg eps7 0x02c7 xtensa xtreg excsave1 0x02d1 xtensa xtreg excsave2 0x02d2 xtensa xtreg excsave3 0x02d3 xtensa xtreg excsave4 0x02d4 xtensa xtreg excsave5 0x02d5 xtensa xtreg excsave6 0x02d6 xtensa xtreg excsave7 0x02d7 xtensa xtreg cpenable 0x02e0 xtensa xtreg interrupt 0x02e2 xtensa xtreg intset 0x02e2 xtensa xtreg intclear 0x02e3 xtensa xtreg intenable 0x02e4 xtensa xtreg vecbase 0x02e7 xtensa xtreg exccause 0x02e8 xtensa xtreg debugcause 0x02e9 xtensa xtreg ccount 0x02ea xtensa xtreg prid 0x02eb xtensa xtreg icount 0x02ec xtensa xtreg icountlevel 0x02ed xtensa xtreg excvaddr 0x02ee xtensa xtreg ccompare0 0x02f0 xtensa xtreg ccompare1 0x02f1 xtensa xtreg ccompare2 0x02f2 xtensa xtreg misc0 0x02f4 xtensa xtreg misc1 0x02f5 xtensa xtreg misc2 0x02f6 xtensa xtreg misc3 0x02f7 xtensa xtreg pwrctl 0x2028 xtensa xtreg pwrstat 0x2029 xtensa xtreg eristat 0x202a xtensa xtreg cs_itctrl 0x202b xtensa xtreg cs_claimset 0x202c xtensa xtreg cs_claimclr 0x202d xtensa xtreg cs_lockaccess 0x202e xtensa xtreg cs_lockstatus 0x202f xtensa xtreg cs_authstatus 0x2030 xtensa xtreg fault_info 0x203f xtensa xtreg trax_id 0x2040 xtensa xtreg trax_control 0x2041 xtensa xtreg trax_status 0x2042 xtensa xtreg trax_data 0x2043 xtensa xtreg trax_address 0x2044 xtensa xtreg trax_pctrigger 0x2045 xtensa xtreg trax_pcmatch 0x2046 xtensa xtreg trax_delay 0x2047 xtensa xtreg trax_memstart 0x2048 xtensa xtreg trax_memend 0x2049 xtensa xtreg pmg 0x2057 xtensa xtreg pmpc 0x2058 xtensa xtreg pm0 0x2059 xtensa xtreg pm1 0x205a xtensa xtreg pmctrl0 0x205b xtensa xtreg pmctrl1 0x205c xtensa xtreg pmstat0 0x205d xtensa xtreg pmstat1 0x205e xtensa xtreg ocdid 0x205f xtensa xtreg ocd_dcrclr 0x2060 xtensa xtreg ocd_dcrset 0x2061 xtensa xtreg ocd_dsr 0x2062 xtensa xtreg a0 0x0000 xtensa xtreg a1 0x0001 xtensa xtreg a2 0x0002 xtensa xtreg a3 0x0003 xtensa xtreg a4 0x0004 xtensa xtreg a5 0x0005 xtensa xtreg a6 0x0006 xtensa xtreg a7 0x0007 xtensa xtreg a8 0x0008 xtensa xtreg a9 0x0009 xtensa xtreg a10 0x000a xtensa xtreg a11 0x000b xtensa xtreg a12 0x000c xtensa xtreg a13 0x000d xtensa xtreg a14 0x000e xtensa xtreg a15 0x000f ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/xtensa-core-nxp_rt600.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # OpenOCD configuration file for Xtensa HiFi DSP in NXP RT600 target # Core definition and ABI xtensa xtdef LX xtensa xtopt arnum 32 xtensa xtopt windowed 1 # Exception/Interrupt Options xtensa xtopt exceptions 1 xtensa xtopt hipriints 1 xtensa xtopt intlevels 4 xtensa xtopt excmlevel 2 # Cache Options xtensa xtmem icache 256 32768 4 xtensa xtmem dcache 256 65536 4 1 # Memory Options xtensa xtmem iram 0x24020000 65536 xtensa xtmem dram 0x24000000 65536 xtensa xtmem sram 0x00000000 603979776 # Memory Protection/Translation Options # Debug Options xtensa xtopt debuglevel 4 xtensa xtopt ibreaknum 2 xtensa xtopt dbreaknum 2 # Core Registers xtensa xtregs 208 xtensa xtreg pc 0x0020 xtensa xtreg ar0 0x0100 xtensa xtreg ar1 0x0101 xtensa xtreg ar2 0x0102 xtensa xtreg ar3 0x0103 xtensa xtreg ar4 0x0104 xtensa xtreg ar5 0x0105 xtensa xtreg ar6 0x0106 xtensa xtreg ar7 0x0107 xtensa xtreg ar8 0x0108 xtensa xtreg ar9 0x0109 xtensa xtreg ar10 0x010a xtensa xtreg ar11 0x010b xtensa xtreg ar12 0x010c xtensa xtreg ar13 0x010d xtensa xtreg ar14 0x010e xtensa xtreg ar15 0x010f xtensa xtreg ar16 0x0110 xtensa xtreg ar17 0x0111 xtensa xtreg ar18 0x0112 xtensa xtreg ar19 0x0113 xtensa xtreg ar20 0x0114 xtensa xtreg ar21 0x0115 xtensa xtreg ar22 0x0116 xtensa xtreg ar23 0x0117 xtensa xtreg ar24 0x0118 xtensa xtreg ar25 0x0119 xtensa xtreg ar26 0x011a xtensa xtreg ar27 0x011b xtensa xtreg ar28 0x011c xtensa xtreg ar29 0x011d xtensa xtreg ar30 0x011e xtensa xtreg ar31 0x011f xtensa xtreg lbeg 0x0200 xtensa xtreg lend 0x0201 xtensa xtreg lcount 0x0202 xtensa xtreg sar 0x0203 xtensa xtreg prefctl 0x0228 xtensa xtreg windowbase 0x0248 xtensa xtreg windowstart 0x0249 xtensa xtreg configid0 0x02b0 xtensa xtreg configid1 0x02d0 xtensa xtreg ps 0x02e6 xtensa xtreg threadptr 0x03e7 xtensa xtreg br 0x0204 xtensa xtreg scompare1 0x020c xtensa xtreg acclo 0x0210 xtensa xtreg acchi 0x0211 xtensa xtreg m0 0x0220 xtensa xtreg m1 0x0221 xtensa xtreg m2 0x0222 xtensa xtreg m3 0x0223 xtensa xtreg expstate 0x03e6 xtensa xtreg f64r_lo 0x03ea xtensa xtreg f64r_hi 0x03eb xtensa xtreg f64s 0x03ec xtensa xtreg ae_ovf_sar 0x03f0 xtensa xtreg ae_bithead 0x03f1 xtensa xtreg ae_ts_fts_bu_bp 0x03f2 xtensa xtreg ae_cw_sd_no 0x03f3 xtensa xtreg ae_cbegin0 0x03f6 xtensa xtreg ae_cend0 0x03f7 xtensa xtreg ae_cbegin1 0x03f8 xtensa xtreg ae_cend1 0x03f9 xtensa xtreg aed0 0x1010 xtensa xtreg aed1 0x1011 xtensa xtreg aed2 0x1012 xtensa xtreg aed3 0x1013 xtensa xtreg aed4 0x1014 xtensa xtreg aed5 0x1015 xtensa xtreg aed6 0x1016 xtensa xtreg aed7 0x1017 xtensa xtreg aed8 0x1018 xtensa xtreg aed9 0x1019 xtensa xtreg aed10 0x101a xtensa xtreg aed11 0x101b xtensa xtreg aed12 0x101c xtensa xtreg aed13 0x101d xtensa xtreg aed14 0x101e xtensa xtreg aed15 0x101f xtensa xtreg u0 0x1020 xtensa xtreg u1 0x1021 xtensa xtreg u2 0x1022 xtensa xtreg u3 0x1023 xtensa xtreg aep0 0x1024 xtensa xtreg aep1 0x1025 xtensa xtreg aep2 0x1026 xtensa xtreg aep3 0x1027 xtensa xtreg fcr_fsr 0x1029 xtensa xtreg mmid 0x0259 xtensa xtreg ibreakenable 0x0260 xtensa xtreg memctl 0x0261 xtensa xtreg atomctl 0x0263 xtensa xtreg ddr 0x0268 xtensa xtreg ibreaka0 0x0280 xtensa xtreg ibreaka1 0x0281 xtensa xtreg dbreaka0 0x0290 xtensa xtreg dbreaka1 0x0291 xtensa xtreg dbreakc0 0x02a0 xtensa xtreg dbreakc1 0x02a1 xtensa xtreg epc1 0x02b1 xtensa xtreg epc2 0x02b2 xtensa xtreg epc3 0x02b3 xtensa xtreg epc4 0x02b4 xtensa xtreg epc5 0x02b5 xtensa xtreg depc 0x02c0 xtensa xtreg eps2 0x02c2 xtensa xtreg eps3 0x02c3 xtensa xtreg eps4 0x02c4 xtensa xtreg eps5 0x02c5 xtensa xtreg excsave1 0x02d1 xtensa xtreg excsave2 0x02d2 xtensa xtreg excsave3 0x02d3 xtensa xtreg excsave4 0x02d4 xtensa xtreg excsave5 0x02d5 xtensa xtreg cpenable 0x02e0 xtensa xtreg interrupt 0x02e2 xtensa xtreg intset 0x02e2 xtensa xtreg intclear 0x02e3 xtensa xtreg intenable 0x02e4 xtensa xtreg vecbase 0x02e7 xtensa xtreg exccause 0x02e8 xtensa xtreg debugcause 0x02e9 xtensa xtreg ccount 0x02ea xtensa xtreg prid 0x02eb xtensa xtreg icount 0x02ec xtensa xtreg icountlevel 0x02ed xtensa xtreg excvaddr 0x02ee xtensa xtreg ccompare0 0x02f0 xtensa xtreg ccompare1 0x02f1 xtensa xtreg misc0 0x02f4 xtensa xtreg misc1 0x02f5 xtensa xtreg pwrctl 0x2024 xtensa xtreg pwrstat 0x2025 xtensa xtreg eristat 0x2026 xtensa xtreg cs_itctrl 0x2027 xtensa xtreg cs_claimset 0x2028 xtensa xtreg cs_claimclr 0x2029 xtensa xtreg cs_lockaccess 0x202a xtensa xtreg cs_lockstatus 0x202b xtensa xtreg cs_authstatus 0x202c xtensa xtreg pmg 0x203b xtensa xtreg pmpc 0x203c xtensa xtreg pm0 0x203d xtensa xtreg pm1 0x203e xtensa xtreg pmctrl0 0x203f xtensa xtreg pmctrl1 0x2040 xtensa xtreg pmstat0 0x2041 xtensa xtreg pmstat1 0x2042 xtensa xtreg ocdid 0x2043 xtensa xtreg ocd_dcrclr 0x2044 xtensa xtreg ocd_dcrset 0x2045 xtensa xtreg ocd_dsr 0x2046 xtensa xtreg a0 0x0000 xtensa xtreg a1 0x0001 xtensa xtreg a2 0x0002 xtensa xtreg a3 0x0003 xtensa xtreg a4 0x0004 xtensa xtreg a5 0x0005 xtensa xtreg a6 0x0006 xtensa xtreg a7 0x0007 xtensa xtreg a8 0x0008 xtensa xtreg a9 0x0009 xtensa xtreg a10 0x000a xtensa xtreg a11 0x000b xtensa xtreg a12 0x000c xtensa xtreg a13 0x000d xtensa xtreg a14 0x000e xtensa xtreg a15 0x000f xtensa xtreg b0 0x0010 xtensa xtreg b1 0x0011 xtensa xtreg b2 0x0012 xtensa xtreg b3 0x0013 xtensa xtreg b4 0x0014 xtensa xtreg b5 0x0015 xtensa xtreg b6 0x0016 xtensa xtreg b7 0x0017 xtensa xtreg b8 0x0018 xtensa xtreg b9 0x0019 xtensa xtreg b10 0x001a xtensa xtreg b11 0x001b xtensa xtreg b12 0x001c xtensa xtreg b13 0x001d xtensa xtreg b14 0x001e xtensa xtreg b15 0x001f xtensa xtreg psintlevel 0x2006 xtensa xtreg psum 0x2007 xtensa xtreg pswoe 0x2008 xtensa xtreg psexcm 0x2009 xtensa xtreg pscallinc 0x200a xtensa xtreg psowb 0x200b xtensa xtreg acc 0x200c xtensa xtreg dbnum 0x2011 xtensa xtreg ae_overflow 0x2014 xtensa xtreg ae_sar 0x2015 xtensa xtreg ae_cwrap 0x2016 xtensa xtreg ae_bitptr 0x2017 xtensa xtreg ae_bitsused 0x2018 xtensa xtreg ae_tablesize 0x2019 xtensa xtreg ae_first_ts 0x201a xtensa xtreg ae_nextoffset 0x201b xtensa xtreg ae_searchdone 0x201c xtensa xtreg roundmode 0x201d xtensa xtreg invalidflag 0x201e xtensa xtreg divzeroflag 0x201f xtensa xtreg overflowflag 0x2020 xtensa xtreg underflowflag 0x2021 xtensa xtreg inexactflag 0x2022 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/xtensa-core-xt8.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # OpenOCD configuration file for Xtensa xt8 target # Core definition and ABI xtensa xtdef LX xtensa xtopt arnum 32 xtensa xtopt windowed 1 # Exception/Interrupt Options xtensa xtopt exceptions 1 xtensa xtopt hipriints 1 xtensa xtopt intlevels 3 xtensa xtopt excmlevel 1 # Cache Options xtensa xtmem icache 16 1024 1 xtensa xtmem dcache 16 1024 1 1 # Memory Options xtensa xtmem iram 0x40000000 1048576 xtensa xtmem dram 0x3ff00000 262144 xtensa xtmem srom 0x50000000 131072 xtensa xtmem sram 0x60000000 4194304 # Memory Protection/Translation Options # Debug Options xtensa xtopt debuglevel 3 xtensa xtopt ibreaknum 2 xtensa xtopt dbreaknum 2 # Core Registers xtensa xtregs 127 xtensa xtreg a0 0x0000 xtensa xtreg a1 0x0001 xtensa xtreg a2 0x0002 xtensa xtreg a3 0x0003 xtensa xtreg a4 0x0004 xtensa xtreg a5 0x0005 xtensa xtreg a6 0x0006 xtensa xtreg a7 0x0007 xtensa xtreg a8 0x0008 xtensa xtreg a9 0x0009 xtensa xtreg a10 0x000a xtensa xtreg a11 0x000b xtensa xtreg a12 0x000c xtensa xtreg a13 0x000d xtensa xtreg a14 0x000e xtensa xtreg a15 0x000f xtensa xtreg pc 0x0020 xtensa xtreg ar0 0x0100 xtensa xtreg ar1 0x0101 xtensa xtreg ar2 0x0102 xtensa xtreg ar3 0x0103 xtensa xtreg ar4 0x0104 xtensa xtreg ar5 0x0105 xtensa xtreg ar6 0x0106 xtensa xtreg ar7 0x0107 xtensa xtreg ar8 0x0108 xtensa xtreg ar9 0x0109 xtensa xtreg ar10 0x010a xtensa xtreg ar11 0x010b xtensa xtreg ar12 0x010c xtensa xtreg ar13 0x010d xtensa xtreg ar14 0x010e xtensa xtreg ar15 0x010f xtensa xtreg ar16 0x0110 xtensa xtreg ar17 0x0111 xtensa xtreg ar18 0x0112 xtensa xtreg ar19 0x0113 xtensa xtreg ar20 0x0114 xtensa xtreg ar21 0x0115 xtensa xtreg ar22 0x0116 xtensa xtreg ar23 0x0117 xtensa xtreg ar24 0x0118 xtensa xtreg ar25 0x0119 xtensa xtreg ar26 0x011a xtensa xtreg ar27 0x011b xtensa xtreg ar28 0x011c xtensa xtreg ar29 0x011d xtensa xtreg ar30 0x011e xtensa xtreg ar31 0x011f xtensa xtreg lbeg 0x0200 xtensa xtreg lend 0x0201 xtensa xtreg lcount 0x0202 xtensa xtreg sar 0x0203 xtensa xtreg windowbase 0x0248 xtensa xtreg windowstart 0x0249 xtensa xtreg configid0 0x02b0 xtensa xtreg configid1 0x02d0 xtensa xtreg ps 0x02e6 xtensa xtreg expstate 0x03e6 xtensa xtreg mmid 0x0259 xtensa xtreg ibreakenable 0x0260 xtensa xtreg ddr 0x0268 xtensa xtreg ibreaka0 0x0280 xtensa xtreg ibreaka1 0x0281 xtensa xtreg dbreaka0 0x0290 xtensa xtreg dbreaka1 0x0291 xtensa xtreg dbreakc0 0x02a0 xtensa xtreg dbreakc1 0x02a1 xtensa xtreg epc1 0x02b1 xtensa xtreg epc2 0x02b2 xtensa xtreg epc3 0x02b3 xtensa xtreg depc 0x02c0 xtensa xtreg eps2 0x02c2 xtensa xtreg eps3 0x02c3 xtensa xtreg excsave1 0x02d1 xtensa xtreg excsave2 0x02d2 xtensa xtreg excsave3 0x02d3 xtensa xtreg interrupt 0x02e2 xtensa xtreg intset 0x02e2 xtensa xtreg intclear 0x02e3 xtensa xtreg intenable 0x02e4 xtensa xtreg exccause 0x02e8 xtensa xtreg debugcause 0x02e9 xtensa xtreg ccount 0x02ea xtensa xtreg icount 0x02ec xtensa xtreg icountlevel 0x02ed xtensa xtreg excvaddr 0x02ee xtensa xtreg ccompare0 0x02f0 xtensa xtreg ccompare1 0x02f1 xtensa xtreg pwrctl 0x200f xtensa xtreg pwrstat 0x2010 xtensa xtreg eristat 0x2011 xtensa xtreg cs_itctrl 0x2012 xtensa xtreg cs_claimset 0x2013 xtensa xtreg cs_claimclr 0x2014 xtensa xtreg cs_lockaccess 0x2015 xtensa xtreg cs_lockstatus 0x2016 xtensa xtreg cs_authstatus 0x2017 xtensa xtreg fault_info 0x2026 xtensa xtreg trax_id 0x2027 xtensa xtreg trax_control 0x2028 xtensa xtreg trax_status 0x2029 xtensa xtreg trax_data 0x202a xtensa xtreg trax_address 0x202b xtensa xtreg trax_pctrigger 0x202c xtensa xtreg trax_pcmatch 0x202d xtensa xtreg trax_delay 0x202e xtensa xtreg trax_memstart 0x202f xtensa xtreg trax_memend 0x2030 xtensa xtreg pmg 0x203e xtensa xtreg pmpc 0x203f xtensa xtreg pm0 0x2040 xtensa xtreg pm1 0x2041 xtensa xtreg pmctrl0 0x2042 xtensa xtreg pmctrl1 0x2043 xtensa xtreg pmstat0 0x2044 xtensa xtreg pmstat1 0x2045 xtensa xtreg ocdid 0x2046 xtensa xtreg ocd_dcrclr 0x2047 xtensa xtreg ocd_dcrset 0x2048 xtensa xtreg ocd_dsr 0x2049 xtensa xtreg psintlevel 0x2003 xtensa xtreg psum 0x2004 xtensa xtreg pswoe 0x2005 xtensa xtreg psexcm 0x2006 xtensa xtreg pscallinc 0x2007 xtensa xtreg psowb 0x2008 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/xtensa.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Target Support for Xtensa Processors # set xtensa_ids { 0x120034e5 0x120134e5 0x209034e5 0x209134e5 0x209234e5 0x209334e5 0x209434e5 0x209534e5 0x209634e5 0x209734e5 0x20a034e5 0x20a134e5 0x20a234e5 0x20a334e5 0x20a434e5 0x20a534e5 0x20a634e5 0x20a734e5 0x20a834e5 0x20b034e5 } set expected_xtensa_ids {} foreach i $xtensa_ids { lappend expected_xtensa_ids -expected-id $i } if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME xtensa } if { [info exists CPUTAPID] } { set _CPUTAPARGLIST "-expected-id $CPUTAPID" } else { set _CPUTAPARGLIST [join $expected_xtensa_ids] } set _TARGETNAME $_CHIPNAME set _CPU0NAME cpu set _TAPNAME $_CHIPNAME.$_CPU0NAME if { [info exists XTENSA_DAP] } { source [find target/swj-dp.tcl] # SWD mode ignores the -irlen parameter eval swj_newdap $_CHIPNAME cpu -irlen 4 $_CPUTAPARGLIST dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu if { [info exists XTENSA_DAP_BASE] } { # Specify fixed offset for accessing XDM via APB behind a DAP interface target create $_TARGETNAME xtensa -dap $_CHIPNAME.dap -dbgbase $XTENSA_DAP_BASE } else { target create $_TARGETNAME xtensa -dap $_CHIPNAME.dap } } else { # JTAG direct (without DAP) eval jtag newtap $_CHIPNAME $_CPU0NAME -irlen 5 $_CPUTAPARGLIST target create $_TARGETNAME xtensa -chain-position $_TAPNAME } $_TARGETNAME configure -event reset-assert-post { soft_reset_halt } gdb_report_register_access_error enable ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/zynq_7000.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Xilinx Zynq-7000 All Programmable SoC # # http://www.xilinx.com/products/silicon-devices/soc/zynq-7000/index.htm # https://www.xilinx.com/member/forms/download/sim-model-eval-license-xef.html?filename=bsdl_zynq_2.zip # # 0x03736093 XQ7Z100 XC7Z100I XC7Z100 # 0x03731093 XQ7Z045 XC7Z045I XC7Z045 # 0x0372c093 XQ7Z030 XC7Z030I XC7Z030 XA7Z030 # 0x03727093 XQ7Z020 XC7Z020I XC7Z020 XA7Z020 # 0x03732093 XC7Z035I XC7Z035 # 0x0373b093 XC7Z015I XC7Z015 # 0x03728093 XC7Z014S # 0x0373c093 XC7Z012S # 0x03722093 XC7Z010I XC7Z010 XA7Z010 # 0x03723093 XC7Z007S set _CHIPNAME zynq set _TARGETNAME $_CHIPNAME.cpu jtag newtap zynq_pl bs -irlen 6 -ignore-version -ircapture 0x1 -irmask 0x03 \ -expected-id 0x03723093 \ -expected-id 0x03722093 \ -expected-id 0x0373c093 \ -expected-id 0x03728093 \ -expected-id 0x0373B093 \ -expected-id 0x03732093 \ -expected-id 0x03727093 \ -expected-id 0x0372C093 \ -expected-id 0x03731093 \ -expected-id 0x03736093 jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4ba00477 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create ${_TARGETNAME}0 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80090000 target create ${_TARGETNAME}1 cortex_a -dap $_CHIPNAME.dap \ -coreid 1 -dbgbase 0x80092000 target smp ${_TARGETNAME}0 ${_TARGETNAME}1 adapter speed 1000 ${_TARGETNAME}0 configure -event reset-assert-post "cortex_a dbginit" ${_TARGETNAME}1 configure -event reset-assert-post "cortex_a dbginit" pld create zynq_pl.pld virtex2 -chain-position zynq_pl.bs -no_jstart virtex2 set_user_codes $zynq_pl.pld 0x02 0x03 0x22 0x23 set XC7_JSHUTDOWN 0x0d set XC7_JPROGRAM 0x0b set XC7_JSTART 0x0c set XC7_BYPASS 0x3f proc zynqpl_program {tap} { echo "DEPRECATED! use 'virtex2 program ...' not 'zynqpl_program'" global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS irscan $tap $XC7_JSHUTDOWN irscan $tap $XC7_JPROGRAM runtest 60000 #JSTART prevents this from working... #irscan $tap $XC7_JSTART runtest 2000 irscan $tap $XC7_BYPASS runtest 2000 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/target/к1879xб1я.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # СБИС К1879ХБ1Я # http://www.module.ru/catalog/micro/mikroshema_dekodera_cifrovogo_televizionnogo_signala_sbis_k1879hb1ya/ adapter speed 1000 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME к1879хб1я } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists DSP_TAPID] } { set _DSP_TAPID $DSP_TAPID } else { set _DSP_TAPID 0x2b900f0f } jtag newtap $_CHIPNAME dsp -irlen 4 -expected-id $_DSP_TAPID if { [info exists CPU_TAPID] } { set _CPU_TAPID $CPU_TAPID } else { set _CPU_TAPID 0x07b76f0f } jtag newtap $_CHIPNAME arm -irlen 5 -expected-id $_CPU_TAPID set _TARGETNAME $_CHIPNAME.arm target create $_TARGETNAME arm11 -chain-position $_CHIPNAME.arm ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/test/selftest.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later add_help_text selftest "run selftest using working ram <tmpfile> <address> <size>" proc selftest {tmpfile address size} { for {set i 0} {$i < $size } {set i [expr {$i+4}]} { mww [expr {$address+$i}] $i } for {set i 0} {$i < 10 } {set i [expr {$i+1}]} { echo "Test iteration $i" dump_image $tmpfile $address $size verify_image $tmpfile $address bin load_image $tmpfile $address bin } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/test/syntax1.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later adapter srst delay 200 jtag_ntrst_delay 200 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst #LPCs need reset pulled while RTCK is low. 0 to activate JTAG, power-on reset is not enough adapter assert trst assert srst adapter deassert trst deassert srst #jtag scan chain #format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE) jtag newtap lpc2148 one -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4f1f0f0f #target configuration #daemon_startup reset set _TARGETNAME [format "%s.cpu" lpc2148] target create lpc2148.cpu arm7tdmi -endian little -work-area-size 0x4000 -work-area-phys 0x40000000 -work-area-backup 0 $_TARGETNAME configure -event reset-init { soft_reset_halt mvb 0xE01FC040 0x01 } set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME lpc2000 0x0 0x7d000 0 0 0 lpc2000_v2 14765 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/tools/firmware-recovery.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later echo "\n\nFirmware recovery helpers" echo "Use -c firmware_help to get help\n" set known_boards { "asus-rt-n16 ASUS RT-N16" "asus-rt-n66u ASUS RT-N66U" "linksys-wag200g Linksys WAG200G" "linksys-wrt54gl Linksys WRT54GL v1.1" "netgear-dg834v3 Netgear DG834G v3" "tp-link_tl-mr3020 TP-LINK TL-MR3020" "bt-homehubv1 BT HomeHub v1" } proc firmware_help { } { echo " Your OpenOCD command should look like this: openocd -f interface/<jtag adapter>.cfg -f tools/firmware-recovery.tcl -c \"<commands>*; shutdown\" Where: <jtag adapter> is one of the supported devices, e.g. ftdi/jtagkey2 <commands> are firmware-recovery commands separated by semicolon Supported commands: firmware_help get this help list_boards list known boards and exit board <name> select board you work with list_partitions list partitions of the currently selected board dump_part <name> <filename> save partition's contents to a file erase_part <name> erase the given partition flash_part <name> <filename> erase, flash and verify the given partition ram_boot <filename> load binary file to RAM and run it adapter speed <freq> set JTAG clock frequency in kHz For example, to clear nvram and reflash CFE on an RT-N16 using TUMPA, run: openocd -f interface/ftdi/tumpa.cfg -f tools/firmware-recovery.tcl \\ -c \"board asus-rt-n16; erase_part nvram; flash_part CFE cfe-n16.bin; shutdown\" \n\n" shutdown } # set default, can be overridden later adapter speed 1000 proc get_partition { name } { global partition_list dict get $partition_list $name } proc partition_desc { name } { lindex [get_partition $name] 0 } proc partition_start { name } { lindex [get_partition $name] 1 } proc partition_size { name } { lindex [get_partition $name] 2 } proc list_boards { } { global known_boards echo "List of the supported boards:\n" echo "Board name\t\tDescription" echo "-----------------------------------" foreach i $known_boards { echo $i } echo "\n\n" } proc board { name } { script [find board/$name.cfg] } proc list_partitions { } { global partition_list set fstr "%-16s%-14s%-14s%s" echo "\nThe currently selected board is known to have these partitions:\n" echo [format $fstr Name Start Size Description] echo "-------------------------------------------------------" for {set i 0} {$i < [llength $partition_list]} {incr i 2} { set key [lindex $partition_list $i] echo [format $fstr $key [partition_start $key] [partition_size $key] [partition_desc $key]] } echo "\n\n" } # Magic to work with any targets, including semi-functional proc prepare_target { } { init catch {halt} catch {reset init} catch {halt} } proc dump_part { name filename } { prepare_target dump_image $filename [partition_start $name] [partition_size $name] } proc erase_part { name } { prepare_target flash erase_address [partition_start $name] [partition_size $name] } proc flash_part { name filename } { prepare_target flash write_image erase $filename [partition_start $name] bin echo "Verifying:" verify_image $filename [partition_start $name] } proc ram_boot { filename } { global ram_boot_address prepare_target load_image $filename $ram_boot_address bin resume $ram_boot_address } echo "" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/tools/memtest.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Algorithms by Michael Barr, released into public domain # Ported to OpenOCD by Shane Volpe, additional fixes by Paul Fertser set CPU_MAX_ADDRESS 0xFFFFFFFF source [find bitsbytes.tcl] source [find memory.tcl] proc runAllMemTests { baseAddress nBytes } { memTestDataBus $baseAddress memTestAddressBus $baseAddress $nBytes memTestDevice $baseAddress $nBytes } #*********************************************************************************** # * # * Function: memTestDataBus() # * # * Description: Test the data bus wiring in a memory region by # * performing a walking 1's test at a fixed address # * within that region. The address (and hence the # * memory region) is selected by the caller. # * Ported from: # * http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C # * Notes: # * # * Returns: Empty string if the test succeeds. # * A non-zero result is the first pattern that failed. # * #*********************************************************************************** proc memTestDataBus { address } { echo "Running memTestDataBus" for {set i 0} {$i < 32} {incr i} { # Shift bit set pattern [expr {1 << $i}] # Write pattern to memory memwrite32 $address $pattern # Read pattern from memory set data [memread32 $address] if {$data != $pattern} { echo "FAILED DATABUS: Address: $address, Pattern: $pattern, Returned: $data" return $pattern } } } #*********************************************************************************** # * # * Function: memTestAddressBus() # * # * Description: Perform a walking 1's test on the relevant bits # * of the address and check for aliasing. This test # * will find single-bit address failures such as stuck # * -high, stuck-low, and shorted pins. The base address # * and size of the region are selected by the caller. # * Ported from: # * http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C # * # * Notes: For best results, the selected base address should # * have enough LSB 0's to guarantee single address bit # * changes. For example, to test a 64-Kbyte region, # * select a base address on a 64-Kbyte boundary. Also, # * select the region size as a power-of-two--if at all # * possible. # * # * Returns: Empty string if the test succeeds. # * A non-zero result is the first address at which an # * aliasing problem was uncovered. By examining the # * contents of memory, it may be possible to gather # * additional information about the problem. # * #*********************************************************************************** proc memTestAddressBus { baseAddress nBytes } { set addressMask [expr {$nBytes - 1}] set pattern 0xAAAAAAAA set antipattern 0x55555555 echo "Running memTestAddressBus" echo "addressMask: [convertToHex $addressMask]" echo "memTestAddressBus: Writing the default pattern at each of the power-of-two offsets..." for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}] } { set addr [expr {$baseAddress + $offset}] memwrite32 $addr $pattern } echo "memTestAddressBus: Checking for address bits stuck high..." memwrite32 $baseAddress $antipattern for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}]} { set addr [expr {$baseAddress + $offset}] set data [memread32 $addr] if {$data != $pattern} { echo "FAILED DATA_ADDR_BUS_SHIGH: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data]" return $pattern } } echo "memTestAddressBus: Checking for address bits stuck low or shorted..." memwrite32 $baseAddress $pattern for {set testOffset 32} {[expr {$testOffset & $addressMask}] != 0} {set testOffset [expr {$testOffset << 1}] } { set addr [expr {$baseAddress + $testOffset}] memwrite32 $addr $antipattern set data [memread32 $baseAddress] if {$data != $pattern} { echo "FAILED DATA_ADDR_BUS_SLOW: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data]" return $pattern } for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}]} { set addr [expr {$baseAddress + $offset}] set data [memread32 $baseAddress] if {(($data != $pattern) && ($offset != $testOffset))} { echo "FAILED DATA_ADDR_BUS_SLOW2: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data], offset: [convertToHex $offset], testOffset [convertToHex $testOffset]" return $pattern } } set addr [expr {$baseAddress + $testOffset}] memwrite32 $addr $pattern } } #*********************************************************************************** # * # * Function: memTestDevice() # * # * Description: Test the integrity of a physical memory device by # * performing an increment/decrement test over the # * entire region. In the process every storage bit # * in the device is tested as zero and as one. The # * base address and the size of the region are # * selected by the caller. # * Ported from: # * http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C # * Notes: # * # * Returns: Empty string if the test succeeds. # * A non-zero result is the first address at which an # * incorrect value was read back. By examining the # * contents of memory, it may be possible to gather # * additional information about the problem. # * #*********************************************************************************** proc memTestDevice { baseAddress nBytes } { echo "Running memTestDevice" echo "memTestDevice: Filling memory with a known pattern..." for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} { memwrite32 [expr {$baseAddress + $offset}] $pattern } echo "memTestDevice: Checking each location and inverting it for the second pass..." for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} { set addr [expr {$baseAddress + $offset}] set data [memread32 $addr] if {$data != $pattern} { echo "FAILED memTestDevice_pattern: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data], offset: [convertToHex $offset]" return $pattern } set antiPattern [expr {~$pattern}] memwrite32 [expr {$baseAddress + $offset}] $antiPattern } echo "memTestDevice: Checking each location for the inverted pattern and zeroing it..." for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} { set antiPattern [expr {~$pattern & ((1<<32) - 1)}] set addr [expr {$baseAddress + $offset}] set data [memread32 $addr] set dataHex [convertToHex $data] set antiPatternHex [convertToHex $antiPattern] if {$dataHex != $antiPatternHex} { echo "FAILED memTestDevice_antipattern: Address: [convertToHex $addr], antiPattern: $antiPatternHex, Returned: $dataHex, offset: $offset" return $pattern } } } proc convertToHex { value } { format 0x%08x $value } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tcl/tools/test_cpu_speed.tcl ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # Description: # Measure the CPU clock frequency of an ARM Cortex-M based device. # # Return: # The CPU clock frequency in Hz. A negative value indicates that the loop # counter was saturated. # # Note: # You may need to adapt the number of cycles for your device. # add_help_text cortex_m_test_cpu_speed "Measure the CPU clock frequency of an ARM Cortex-M based device" add_usage_text cortex_m_test_cpu_speed {address [timeout [cycles_per_loop]]} proc cortex_m_test_cpu_speed { address { timeout 200 } { cycles_per_loop 4 } } { set loop_counter_start 0xffffffff halt # Backup registers and memory. set backup_regs [get_reg -force {pc r0 xpsr}] set backup_mem [read_memory $address 16 3] # We place the following code at the given address to measure the # CPU clock frequency: # # 3801: subs r0, #1 # d1fd: bne #-2 # e7fe: b #-4 write_memory $address 16 {0x3801 0xd1fd 0xe7fe} set_reg "pc $address r0 $loop_counter_start" resume sleep $timeout halt # Get the loop counter value from register r0. set loop_counter_end [dict values [get_reg r0]] set loop_counter_diff [expr {$loop_counter_start - $loop_counter_end}] # Restore registers and memory. set_reg $backup_regs write_memory $address 16 $backup_mem if { [expr {$loop_counter_end == 0}] } { return -1 } return [expr {double($loop_counter_diff) * $cycles_per_loop / $timeout * 1000}] } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/AT91R40008Test/inc/typedefs.h ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial ****************************************************************************/ #ifndef __TYPEDEFS_H__ #define __TYPEDEFS_H__ /* * Some types to use Windows like source */ typedef char CHAR; /* 8-bit signed data */ typedef unsigned char BYTE; /* 8-bit unsigned data */ typedef unsigned short WORD; /* 16-bit unsigned data */ typedef long LONG; /* 32-bit signed data */ typedef unsigned long ULONG; /* 32-bit unsigned data */ typedef unsigned long DWORD; /* 32-bit unsigned data */ #endif /* !__TYPEDEFS_H_ */ /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/AT91R40008Test/prj/at91r40008_reset.script ================================================ wait_halt sleep 10 poll # Ethernut 3 remapping is required to access external flash memory. mww 0xffe00000 0x1000213d mww 0xffe00004 0x20003e3d mww 0xffe00020 0x00000001 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/AT91R40008Test/prj/at91r40008_turtle.cfg ================================================ #daemon configuration telnet_port 4444 gdb_port 3333 # tell gdb our flash memory map gdb_memory_map enable # enable flash programming gdb_flash_program enable #interface interface ft2232 ft2232_device_desc "Turtelizer JTAG/RS232 Adapter A" ft2232_layout turtelizer2 ft2232_vid_pid 0x0403 0xbdc8 jtag_speed 0 jtag_nsrst_delay 200 jtag_ntrst_delay 200 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only srst_pulls_trst #jtag scan chain jtag newtap at91 cpu -irlen 4 -irmask 0xf #target configuration target create target0 arm7tdmi -endian little -chain-position 0 [new_target_name] configure -work-area-virt 0 -work-area-phys 0x3C000 -work-area-size 0x4000 -work-area-backup false target_script 0 reset .\prj\at91r40008_reset.script flash bank cfi 0x10000000 0x400000 2 2 0 # For more information about the configuration files, # look at the OpenOCD User's Guide. init reset halt ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/AT91R40008Test/prj/eclipse_ram.gdb ================================================ target remote localhost:3333 monitor reset monitor sleep 500 monitor poll monitor soft_reset_halt monitor arm7_9 sw_bkpts enable monitor mww 0xFFE00000 0x1000213D monitor mww 0xFFE00004 0x20003E3D monitor mww 0xFFE00020 0x00000001 monitor mdw 0xFFE00000 1 monitor mdw 0xFFE00004 1 load break main continue ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/AT91R40008Test/prj/ethernut3_ram.ld ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 09.04.06 mifi First Version ****************************************************************************/ ENTRY(ResetHandler) SEARCH_DIR(.) /* * Define stack size here */ FIQ_STACK_SIZE = 0x0100; IRQ_STACK_SIZE = 0x0100; ABT_STACK_SIZE = 0x0100; UND_STACK_SIZE = 0x0100; SVC_STACK_SIZE = 0x0400; /* * This file, ethernut3_ram.ld, locate the program in the internal * ram of the AT91R40008. For more information about the memory of the * AT91R40008 take a look in the AT91 ARM data sheet. * Reference is made to Rev. 1354D-ATARM-08/02 * * Take a look at page 15, Memory Map, Figure 3 */ MEMORY { ram : org = 0x00000000, len = 256k } /* * Do not change the next code */ SECTIONS { .text : { *(.vectors); . = ALIGN(4); *(.init); . = ALIGN(4); *(.text); . = ALIGN(4); *(.rodata); . = ALIGN(4); *(.rodata*); . = ALIGN(4); *(.glue_7t); . = ALIGN(4); *(.glue_7); . = ALIGN(4); etext = .; } > ram .data : { PROVIDE (__data_start = .); *(.data) . = ALIGN(4); edata = .; _edata = .; PROVIDE (__data_end = .); } > ram .bss : { PROVIDE (__bss_start = .); *(.bss) *(COMMON) . = ALIGN(4); PROVIDE (__bss_end = .); . = ALIGN(256); PROVIDE (__stack_start = .); PROVIDE (__stack_fiq_start = .); . += FIQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_fiq_end = .); PROVIDE (__stack_irq_start = .); . += IRQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_irq_end = .); PROVIDE (__stack_abt_start = .); . += ABT_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_abt_end = .); PROVIDE (__stack_und_start = .); . += UND_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_und_end = .); PROVIDE (__stack_svc_start = .); . += SVC_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_svc_end = .); PROVIDE (__stack_end = .); PROVIDE (__heap_start = .); } > ram } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/AT91R40008Test/src/crt.s ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 09.04.06 mifi First Version ****************************************************************************/ /* * Some defines for the program status registers */ ARM_MODE_USER = 0x10 /* Normal User Mode */ ARM_MODE_FIQ = 0x11 /* FIQ Fast Interrupts Mode */ ARM_MODE_IRQ = 0x12 /* IRQ Standard Interrupts Mode */ ARM_MODE_SVC = 0x13 /* Supervisor Interrupts Mode */ ARM_MODE_ABORT = 0x17 /* Abort Processing memory Faults Mode */ ARM_MODE_UNDEF = 0x1B /* Undefined Instructions Mode */ ARM_MODE_SYS = 0x1F /* System Running in Priviledged Operating Mode */ ARM_MODE_MASK = 0x1F I_BIT = 0x80 /* disable IRQ when I bit is set */ F_BIT = 0x40 /* disable IRQ when I bit is set */ .section .vectors,"ax" .code 32 /****************************************************************************/ /* Vector table and reset entry */ /****************************************************************************/ _vectors: ldr pc, ResetAddr /* Reset */ ldr pc, UndefAddr /* Undefined instruction */ ldr pc, SWIAddr /* Software interrupt */ ldr pc, PAbortAddr /* Prefetch abort */ ldr pc, DAbortAddr /* Data abort */ ldr pc, ReservedAddr /* Reserved */ ldr pc, IRQAddr /* IRQ interrupt */ ldr pc, FIQAddr /* FIQ interrupt */ ResetAddr: .word ResetHandler UndefAddr: .word UndefHandler SWIAddr: .word SWIHandler PAbortAddr: .word PAbortHandler DAbortAddr: .word DAbortHandler ReservedAddr: .word 0 IRQAddr: .word IRQHandler FIQAddr: .word FIQHandler .ltorg .section .init, "ax" .code 32 .global ResetHandler .global ExitFunction .extern main /****************************************************************************/ /* Reset handler */ /****************************************************************************/ ResetHandler: /* * Setup a stack for each mode */ msr CPSR_c, #ARM_MODE_UNDEF | I_BIT | F_BIT /* Undefined Instruction Mode */ ldr sp, =__stack_und_end msr CPSR_c, #ARM_MODE_ABORT | I_BIT | F_BIT /* Abort Mode */ ldr sp, =__stack_abt_end msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT /* FIQ Mode */ ldr sp, =__stack_fiq_end msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT /* IRQ Mode */ ldr sp, =__stack_irq_end msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT /* Supervisor Mode */ ldr sp, =__stack_svc_end /* * Clear .bss section */ ldr r1, =__bss_start ldr r2, =__bss_end ldr r3, =0 bss_clear_loop: cmp r1, r2 strne r3, [r1], #+4 bne bss_clear_loop /* * Jump to main */ mrs r0, cpsr bic r0, r0, #I_BIT | F_BIT /* Enable FIQ and IRQ interrupt */ msr cpsr, r0 mov r0, #0 /* No arguments */ mov r1, #0 /* No arguments */ ldr r2, =main mov lr, pc bx r2 /* And jump... */ ExitFunction: nop nop nop b ExitFunction /****************************************************************************/ /* Default interrupt handler */ /****************************************************************************/ UndefHandler: b UndefHandler SWIHandler: b SWIHandler PAbortHandler: b PAbortHandler DAbortHandler: b DAbortHandler IRQHandler: b IRQHandler FIQHandler: b FIQHandler .weak ExitFunction .weak UndefHandler, PAbortHandler, DAbortHandler .weak IRQHandler, FIQHandler .ltorg /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/AT91R40008Test/src/main.c ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial * 26.01.08 mifi Added variable "d" to test const variable. ****************************************************************************/ #define __MAIN_C__ /* * I use the include only, to show * how to setup a include dir in the makefile */ #include <stdio.h> #include <stdlib.h> #include "typedefs.h" /*=========================================================================*/ /* DEFINE: All Structures and Common Constants */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Prototypes */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Definition of all local Data */ /*=========================================================================*/ static const DWORD d = 7; /*=========================================================================*/ /* DEFINE: Definition of all local Procedures */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: All code exported */ /*=========================================================================*/ /***************************************************************************/ /* main */ /***************************************************************************/ int main (void) { DWORD a = 1; DWORD b = 2; DWORD c = 0; a = a + d; while (1) { a++; b++; c = a + b; } /* * This return here make no sense. * But to prevent the compiler warning: * "return type of 'main' is not 'int' * we use an int as return :-) */ return(0); } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/AT91R40008Test/test_ram.hex ================================================ :1000000018F09FE518F09FE518F09FE518F09FE5C0 :1000100018F09FE518F09FE518F09FE518F09FE5B0 :1000200040000000B0000000B4000000B800000074 :10003000BC00000000000000C0000000C400000080 :10004000DBF021E37CD09FE5D7F021E378D09FE57A :10005000D1F021E374D09FE5D2F021E370D09FE589 :10006000D3F021E36CD09FE56C109FE56C209FE5F9 :100070000030A0E3020051E104308114FCFFFF1ABC :1000800000000FE1C000C0E300F029E10000A0E3A0 :100090000010A0E348209FE50FE0A0E112FF2FE150 :1000A0000000A0E10000A0E10000A0E1FBFFFFEAEA :1000B000FEFFFFEAFEFFFFEAFEFFFFEAFEFFFFEAA8 :1000C000FEFFFFEAFEFFFFEA000600000005000059 :1000D0000003000000040000000A00004C010000C2 :1000E0004C010000E80000000CD04DE20130A0E31C :1000F00000308DE50230A0E304308DE50030A0E350 :1001000008308DE538309FE5002093E500309DE50F :10011000023083E000308DE500309DE5013083E260 :1001200000308DE504309DE5013083E204308DE53B :1001300000209DE504309DE5033082E008308DE528 :0C014000F4FFFFEA480100000700000087 :0400000300000040B9 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2148Test/inc/typedefs.h ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial ****************************************************************************/ #ifndef __TYPEDEFS_H__ #define __TYPEDEFS_H__ /* * Some types to use Windows like source */ typedef char CHAR; /* 8-bit signed data */ typedef unsigned char BYTE; /* 8-bit unsigned data */ typedef unsigned short WORD; /* 16-bit unsigned data */ typedef long LONG; /* 32-bit signed data */ typedef unsigned long ULONG; /* 32-bit unsigned data */ typedef unsigned long DWORD; /* 32-bit unsigned data */ #endif /* !__TYPEDEFS_H_ */ /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2148Test/prj/eclipse_ram.gdb ================================================ target remote localhost:3333 monitor reset monitor sleep 500 monitor poll monitor soft_reset_halt monitor arm7_9 sw_bkpts enable monitor mww 0xE01FC040 0x0002 monitor mdw 0xE01FC040 load break main continue ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2148Test/prj/eclipse_rom.gdb ================================================ target remote localhost:3333 monitor reset monitor sleep 500 monitor poll monitor soft_reset_halt monitor arm7_9 force_hw_bkpts enable monitor mww 0xE01FC040 0x0002 monitor mdw 0xE01FC040 load break main continue ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2148Test/prj/lpc2148_jtagkey.cfg ================================================ #daemon configuration telnet_port 4444 gdb_port 3333 # tell gdb our flash memory map # and enable flash programming gdb_memory_map enable gdb_flash_program enable #interface interface ft2232 ft2232_device_desc "Amontec JTAGkey A" ft2232_layout jtagkey ft2232_vid_pid 0x0403 0xcff8 jtag_speed 3 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst #jtag scan chain jtag newtap lpc cpu -irlen 4 -irmask 0xf #target configuration target create target0 arm7tdmi -endian little -chain-position 0 [new_target_name] configure -work-area-virt 0 -work-area-phys 0x40000000 -work-area-size 0x4000 -work-area-backup false #flash bank lpc2000 <base> <size> 0 0 <target#> <variant> flash bank lpc2000 0x0 0x7d000 0 0 0 lpc2000_v2 14765 calc_checksum # For more information about the configuration files, # look at the OpenOCD User's Guide. init reset halt ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2148Test/prj/lpc2148_ram.ld ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 18.12.06 mifi First Version ****************************************************************************/ ENTRY(ResetHandler) SEARCH_DIR(.) /* * Define stack size here */ FIQ_STACK_SIZE = 0x0100; IRQ_STACK_SIZE = 0x0100; ABT_STACK_SIZE = 0x0100; UND_STACK_SIZE = 0x0100; SVC_STACK_SIZE = 0x0400; /* * This file, olimex_lpcp2148_ram.ld, locate the program in the internal * ram of the LPC2148. For more information about the memory of the LPC2148 * take a look in the LPC2141/2142/2144/2146/2148 USER MANUAL. * Reference is made to the user manual from 25 July 2006 Rev. 02 * * Take a look at page 8, section 1.Memory maps */ MEMORY { ram : org = 0x40000000, len = 32k } /* * Do not change the next code */ SECTIONS { .text : { *(.vectors); . = ALIGN(4); *(.init); . = ALIGN(4); *(.text); . = ALIGN(4); *(.rodata); . = ALIGN(4); *(.rodata*); . = ALIGN(4); *(.glue_7t); . = ALIGN(4); *(.glue_7); . = ALIGN(4); etext = .; } > ram .data : { PROVIDE (__data_start = .); *(.data) . = ALIGN(4); edata = .; _edata = .; PROVIDE (__data_end = .); } > ram .bss : { PROVIDE (__bss_start = .); *(.bss) *(COMMON) . = ALIGN(4); PROVIDE (__bss_end = .); . = ALIGN(256); PROVIDE (__stack_start = .); PROVIDE (__stack_fiq_start = .); . += FIQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_fiq_end = .); PROVIDE (__stack_irq_start = .); . += IRQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_irq_end = .); PROVIDE (__stack_abt_start = .); . += ABT_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_abt_end = .); PROVIDE (__stack_und_start = .); . += UND_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_und_end = .); PROVIDE (__stack_svc_start = .); . += SVC_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_svc_end = .); PROVIDE (__stack_end = .); PROVIDE (__heap_start = .); } > ram } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2148Test/prj/lpc2148_rom.ld ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 26.01.08 mifi First Version ****************************************************************************/ ENTRY(ResetHandler) SEARCH_DIR(.) /* * Define stack size here */ FIQ_STACK_SIZE = 0x0100; IRQ_STACK_SIZE = 0x0100; ABT_STACK_SIZE = 0x0100; UND_STACK_SIZE = 0x0100; SVC_STACK_SIZE = 0x0400; /* * This file, olimex_lpcp2148_ram.ld, locate the program in the internal * ram of the LPC2148. For more information about the memory of the LPC2148 * take a look in the LPC2141/2142/2144/2146/2148 USER MANUAL. * Reference is made to the user manual from 25 July 2006 Rev. 02 * * Take a look at page 8, section 1.Memory maps */ MEMORY { rom : org = 0x00000000, len = 512k ram : org = 0x40000000, len = 32k } /* * Do not change the next code */ SECTIONS { .text : { *(.vectors); . = ALIGN(4); *(.init); . = ALIGN(4); *(.text); . = ALIGN(4); *(.rodata); . = ALIGN(4); *(.rodata*); . = ALIGN(4); *(.glue_7t); . = ALIGN(4); *(.glue_7); . = ALIGN(4); etext = .; } > rom .data : { PROVIDE (__data_start = .); *(.data) . = ALIGN(4); edata = .; _edata = .; PROVIDE (__data_end = .); } > ram .bss : { PROVIDE (__bss_start = .); *(.bss) *(COMMON) . = ALIGN(4); PROVIDE (__bss_end = .); . = ALIGN(256); PROVIDE (__stack_start = .); PROVIDE (__stack_fiq_start = .); . += FIQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_fiq_end = .); PROVIDE (__stack_irq_start = .); . += IRQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_irq_end = .); PROVIDE (__stack_abt_start = .); . += ABT_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_abt_end = .); PROVIDE (__stack_und_start = .); . += UND_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_und_end = .); PROVIDE (__stack_svc_start = .); . += SVC_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_svc_end = .); PROVIDE (__stack_end = .); PROVIDE (__heap_start = .); } > ram } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2148Test/src/crt.s ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 31.03.06 mifi First Version * This version based on an example from Ethernut and * "ARM Cross Development with Eclipse" from James P. Lynch ****************************************************************************/ /* * Some defines for the program status registers */ ARM_MODE_USER = 0x10 /* Normal User Mode */ ARM_MODE_FIQ = 0x11 /* FIQ Fast Interrupts Mode */ ARM_MODE_IRQ = 0x12 /* IRQ Standard Interrupts Mode */ ARM_MODE_SVC = 0x13 /* Supervisor Interrupts Mode */ ARM_MODE_ABORT = 0x17 /* Abort Processing memory Faults Mode */ ARM_MODE_UNDEF = 0x1B /* Undefined Instructions Mode */ ARM_MODE_SYS = 0x1F /* System Running in Priviledged Operating Mode */ ARM_MODE_MASK = 0x1F I_BIT = 0x80 /* disable IRQ when I bit is set */ F_BIT = 0x40 /* disable IRQ when I bit is set */ /* * Register Base Address */ .section .vectors,"ax" .code 32 /****************************************************************************/ /* Vector table and reset entry */ /****************************************************************************/ _vectors: ldr pc, ResetAddr /* Reset */ ldr pc, UndefAddr /* Undefined instruction */ ldr pc, SWIAddr /* Software interrupt */ ldr pc, PAbortAddr /* Prefetch abort */ ldr pc, DAbortAddr /* Data abort */ .word 0xB8A06F60 ldr pc, IRQAddr /* IRQ interrupt */ ldr pc, FIQAddr /* FIQ interrupt */ ResetAddr: .word ResetHandler UndefAddr: .word UndefHandler SWIAddr: .word SWIHandler PAbortAddr: .word PAbortHandler DAbortAddr: .word DAbortHandler ReservedAddr: .word 0 IRQAddr: .word IRQHandler FIQAddr: .word FIQHandler .ltorg .section .init, "ax" .code 32 .global ResetHandler .global ExitFunction .extern main /****************************************************************************/ /* Reset handler */ /****************************************************************************/ ResetHandler: /* * Wait for the oscillator is stable */ nop nop nop nop nop nop nop nop /* * Setup a stack for each mode */ msr CPSR_c, #ARM_MODE_UNDEF | I_BIT | F_BIT /* Undefined Instruction Mode */ ldr sp, =__stack_und_end msr CPSR_c, #ARM_MODE_ABORT | I_BIT | F_BIT /* Abort Mode */ ldr sp, =__stack_abt_end msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT /* FIQ Mode */ ldr sp, =__stack_fiq_end msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT /* IRQ Mode */ ldr sp, =__stack_irq_end msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT /* Supervisor Mode */ ldr sp, =__stack_svc_end /* * Clear .bss section */ ldr r1, =__bss_start ldr r2, =__bss_end ldr r3, =0 bss_clear_loop: cmp r1, r2 strne r3, [r1], #+4 bne bss_clear_loop /* * Jump to main */ mrs r0, cpsr bic r0, r0, #I_BIT | F_BIT /* Enable FIQ and IRQ interrupt */ msr cpsr, r0 mov r0, #0 /* No arguments */ mov r1, #0 /* No arguments */ ldr r2, =main mov lr, pc bx r2 /* And jump... */ ExitFunction: nop nop nop b ExitFunction /****************************************************************************/ /* Default interrupt handler */ /****************************************************************************/ UndefHandler: b UndefHandler SWIHandler: b SWIHandler PAbortHandler: b PAbortHandler DAbortHandler: b DAbortHandler IRQHandler: b IRQHandler FIQHandler: b FIQHandler .weak ExitFunction .weak UndefHandler, PAbortHandler, DAbortHandler .weak IRQHandler, FIQHandler .ltorg /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2148Test/src/main.c ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial * 26.01.08 mifi Added variable "d" to test const variable. ****************************************************************************/ #define __MAIN_C__ /* * I use the include only, to show * how to setup a include dir in the makefile */ #include <stdio.h> #include <stdlib.h> #include "typedefs.h" /*=========================================================================*/ /* DEFINE: All Structures and Common Constants */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Prototypes */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Definition of all local Data */ /*=========================================================================*/ static const DWORD d = 7; /*=========================================================================*/ /* DEFINE: Definition of all local Procedures */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: All code exported */ /*=========================================================================*/ /***************************************************************************/ /* main */ /***************************************************************************/ int main (void) { DWORD a = 1; DWORD b = 2; DWORD c = 0; a = a + d; while (1) { a++; b++; c = a + b; } /* * This return here make no sense. * But to prevent the compiler warning: * "return type of 'main' is not 'int' * we use an int as return :-) */ return(0); } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2148Test/test_ram.hex ================================================ :020000044000BA :1000000018F09FE518F09FE518F09FE518F09FE5C0 :1000100018F09FE5606FA0B818F09FE518F09FE515 :1000200040000040D0000040D4000040D800004014 :10003000DC00004000000000E0000040E400004060 :100040000000A0E10000A0E10000A0E10000A0E1AC :100050000000A0E10000A0E10000A0E10000A0E19C :10006000DBF021E37CD09FE5D7F021E378D09FE55A :10007000D1F021E374D09FE5D2F021E370D09FE569 :10008000D3F021E36CD09FE56C109FE56C209FE5D9 :100090000030A0E3020051E104308114FCFFFF1A9C :1000A00000000FE1C000C0E300F029E10000A0E380 :1000B0000010A0E348209FE50FE0A0E112FF2FE130 :1000C0000000A0E10000A0E10000A0E1FBFFFFEACA :1000D000FEFFFFEAFEFFFFEAFEFFFFEAFEFFFFEA88 :1000E000FEFFFFEAFEFFFFEA0006004000050040B9 :1000F0000003004000040040000A00406C01004082 :100100006C010040080100400CD04DE20130A0E33A :1001100000308DE50230A0E304308DE50030A0E32F :1001200008308DE538309FE5002093E500309DE5EF :10013000023083E000308DE500309DE5013083E240 :1001400000308DE504309DE5013083E204308DE51B :1001500000209DE504309DE5033082E008308DE508 :0C016000F4FFFFEA680100400700000007 :040000054000004077 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2148Test/test_rom.hex ================================================ :1000000018F09FE518F09FE518F09FE518F09FE5C0 :1000100018F09FE5606FA0B818F09FE518F09FE515 :1000200040000000D0000000D4000000D800000014 :10003000DC00000000000000E0000000E400000020 :100040000000A0E10000A0E10000A0E10000A0E1AC :100050000000A0E10000A0E10000A0E10000A0E19C :10006000DBF021E37CD09FE5D7F021E378D09FE55A :10007000D1F021E374D09FE5D2F021E370D09FE569 :10008000D3F021E36CD09FE56C109FE56C209FE5D9 :100090000030A0E3020051E104308114FCFFFF1A9C :1000A00000000FE1C000C0E300F029E10000A0E380 :1000B0000010A0E348209FE50FE0A0E112FF2FE130 :1000C0000000A0E10000A0E10000A0E1FBFFFFEACA :1000D000FEFFFFEAFEFFFFEAFEFFFFEAFEFFFFEA88 :1000E000FEFFFFEAFEFFFFEA0004004000030040BD :1000F00000010040000200400008004000000040F5 :1001000000000040080100000CD04DE20130A0E3E7 :1001100000308DE50230A0E304308DE50030A0E32F :1001200008308DE538309FE5002093E500309DE5EF :10013000023083E000308DE500309DE5013083E240 :1001400000308DE504309DE5013083E204308DE51B :1001500000209DE504309DE5033082E008308DE508 :0C016000F4FFFFEA680100000700000047 :0400000300000040B9 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2294Test/inc/typedefs.h ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial ****************************************************************************/ #ifndef __TYPEDEFS_H__ #define __TYPEDEFS_H__ /* * Some types to use Windows like source */ typedef char CHAR; /* 8-bit signed data */ typedef unsigned char BYTE; /* 8-bit unsigned data */ typedef unsigned short WORD; /* 16-bit unsigned data */ typedef long LONG; /* 32-bit signed data */ typedef unsigned long ULONG; /* 32-bit unsigned data */ typedef unsigned long DWORD; /* 32-bit unsigned data */ #endif /* !__TYPEDEFS_H_ */ /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2294Test/prj/eclipse_ram.gdb ================================================ target remote localhost:3333 monitor reset monitor sleep 500 monitor poll monitor soft_reset_halt monitor arm7_9 sw_bkpts enable monitor mww 0xE01FC040 0x0002 monitor mdw 0xE01FC040 load break main continue ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2294Test/prj/eclipse_rom.gdb ================================================ target remote localhost:3333 monitor reset monitor sleep 500 monitor poll monitor soft_reset_halt monitor arm7_9 force_hw_bkpts enable monitor mww 0xE01FC040 0x0002 monitor mdw 0xE01FC040 load break main continue ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2294Test/prj/lpc2294_jtagkey.cfg ================================================ #daemon configuration telnet_port 4444 gdb_port 3333 # tell gdb our flash memory map # and enable flash programming gdb_memory_map enable gdb_flash_program enable #interface interface ft2232 ft2232_device_desc "Amontec JTAGkey A" ft2232_layout jtagkey ft2232_vid_pid 0x0403 0xcff8 jtag_speed 3 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst #jtag scan chain jtag newtap lpc cpu -irlen 4 -irmask 0xf #target configuration target create target0 arm7tdmi -endian little -chain-position 0 [new_target_name] configure -work-area-virt 0 -work-area-phys 0x40000000 -work-area-size 0x4000 -work-area-backup false #flash configuration #flash bank lpc2000 <base> <size> 0 0 <target#> <variant> flash bank lpc2000 0x0 0x40000 0 0 0 lpc2000_v1 14765 calc_checksum # For more information about the configuration files, # look at the OpenOCD User's Guide. init reset halt ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2294Test/prj/lpc2294_ram.ld ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 31.03.06 mifi First Version ****************************************************************************/ ENTRY(ResetHandler) SEARCH_DIR(.) /* * Define stack size here */ FIQ_STACK_SIZE = 0x0100; IRQ_STACK_SIZE = 0x0100; ABT_STACK_SIZE = 0x0100; UND_STACK_SIZE = 0x0100; SVC_STACK_SIZE = 0x0400; /* * This file, olimex_lpce2294_ram.ld, locate the program in the internal * ram of the LPC2294. For more information about the memory of the LPC2294 * take a look in the LPC2119/2129/2194/2292/2294 USER MANUAL. * Reference is made to the user manual from 2004 May 03 * * Take a look at page 48, section 2.Memory Addressing */ MEMORY { ram : org = 0x40000000, len = 16k } /* * Do not change the next code */ SECTIONS { .text : { *(.vectors); . = ALIGN(4); *(.init); . = ALIGN(4); *(.text); . = ALIGN(4); *(.rodata); . = ALIGN(4); *(.rodata*); . = ALIGN(4); *(.glue_7t); . = ALIGN(4); *(.glue_7); . = ALIGN(4); etext = .; } > ram .data : { PROVIDE (__data_start = .); *(.data) . = ALIGN(4); edata = .; _edata = .; PROVIDE (__data_end = .); } > ram .bss : { PROVIDE (__bss_start = .); *(.bss) *(COMMON) . = ALIGN(4); PROVIDE (__bss_end = .); . = ALIGN(256); PROVIDE (__stack_start = .); PROVIDE (__stack_fiq_start = .); . += FIQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_fiq_end = .); PROVIDE (__stack_irq_start = .); . += IRQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_irq_end = .); PROVIDE (__stack_abt_start = .); . += ABT_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_abt_end = .); PROVIDE (__stack_und_start = .); . += UND_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_und_end = .); PROVIDE (__stack_svc_start = .); . += SVC_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_svc_end = .); PROVIDE (__stack_end = .); PROVIDE (__heap_start = .); } > ram } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2294Test/prj/lpc2294_rom.ld ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 31.03.06 mifi First Version ****************************************************************************/ ENTRY(ResetHandler) SEARCH_DIR(.) /* * Define stack size here */ FIQ_STACK_SIZE = 0x0100; IRQ_STACK_SIZE = 0x0100; ABT_STACK_SIZE = 0x0100; UND_STACK_SIZE = 0x0100; SVC_STACK_SIZE = 0x0400; /* * This file, olimex_lpce2294_ram.ld, locate the program in the internal * ram of the LPC2294. For more information about the memory of the LPC2294 * take a look in the LPC2119/2129/2194/2292/2294 USER MANUAL. * Reference is made to the user manual from 2004 May 03 * * Take a look at page 48, section 2.Memory Addressing */ MEMORY { rom : org = 0x00000000, len = 256k ram : org = 0x40000000, len = 16k } /* * Do not change the next code */ SECTIONS { .text : { *(.vectors); . = ALIGN(4); *(.init); . = ALIGN(4); *(.text); . = ALIGN(4); *(.rodata); . = ALIGN(4); *(.rodata*); . = ALIGN(4); *(.glue_7t); . = ALIGN(4); *(.glue_7); . = ALIGN(4); etext = .; } > rom .data : { PROVIDE (__data_start = .); *(.data) . = ALIGN(4); edata = .; _edata = .; PROVIDE (__data_end = .); } > ram .bss : { PROVIDE (__bss_start = .); *(.bss) *(COMMON) . = ALIGN(4); PROVIDE (__bss_end = .); . = ALIGN(256); PROVIDE (__stack_start = .); PROVIDE (__stack_fiq_start = .); . += FIQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_fiq_end = .); PROVIDE (__stack_irq_start = .); . += IRQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_irq_end = .); PROVIDE (__stack_abt_start = .); . += ABT_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_abt_end = .); PROVIDE (__stack_und_start = .); . += UND_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_und_end = .); PROVIDE (__stack_svc_start = .); . += SVC_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_svc_end = .); PROVIDE (__stack_end = .); PROVIDE (__heap_start = .); } > ram } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2294Test/src/crt.s ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 31.03.06 mifi First Version * This version based on an example from Ethernut and * "ARM Cross Development with Eclipse" from James P. Lynch ****************************************************************************/ /* * Some defines for the program status registers */ ARM_MODE_USER = 0x10 /* Normal User Mode */ ARM_MODE_FIQ = 0x11 /* FIQ Fast Interrupts Mode */ ARM_MODE_IRQ = 0x12 /* IRQ Standard Interrupts Mode */ ARM_MODE_SVC = 0x13 /* Supervisor Interrupts Mode */ ARM_MODE_ABORT = 0x17 /* Abort Processing memory Faults Mode */ ARM_MODE_UNDEF = 0x1B /* Undefined Instructions Mode */ ARM_MODE_SYS = 0x1F /* System Running in Priviledged Operating Mode */ ARM_MODE_MASK = 0x1F I_BIT = 0x80 /* disable IRQ when I bit is set */ F_BIT = 0x40 /* disable IRQ when I bit is set */ /* * Register Base Address */ .section .vectors,"ax" .code 32 /****************************************************************************/ /* Vector table and reset entry */ /****************************************************************************/ _vectors: ldr pc, ResetAddr /* Reset */ ldr pc, UndefAddr /* Undefined instruction */ ldr pc, SWIAddr /* Software interrupt */ ldr pc, PAbortAddr /* Prefetch abort */ ldr pc, DAbortAddr /* Data abort */ ldr pc, ReservedAddr /* Reserved */ ldr pc, IRQAddr /* IRQ interrupt */ ldr pc, FIQAddr /* FIQ interrupt */ ResetAddr: .word ResetHandler UndefAddr: .word UndefHandler SWIAddr: .word SWIHandler PAbortAddr: .word PAbortHandler DAbortAddr: .word DAbortHandler ReservedAddr: .word 0 IRQAddr: .word IRQHandler FIQAddr: .word FIQHandler .ltorg .section .init, "ax" .code 32 .global ResetHandler .global ExitFunction .extern main /****************************************************************************/ /* Reset handler */ /****************************************************************************/ ResetHandler: /* * Wait for the oscillator is stable */ nop nop nop nop nop nop nop nop /* * Setup a stack for each mode */ msr CPSR_c, #ARM_MODE_UNDEF | I_BIT | F_BIT /* Undefined Instruction Mode */ ldr sp, =__stack_und_end msr CPSR_c, #ARM_MODE_ABORT | I_BIT | F_BIT /* Abort Mode */ ldr sp, =__stack_abt_end msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT /* FIQ Mode */ ldr sp, =__stack_fiq_end msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT /* IRQ Mode */ ldr sp, =__stack_irq_end msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT /* Supervisor Mode */ ldr sp, =__stack_svc_end /* * Clear .bss section */ ldr r1, =__bss_start ldr r2, =__bss_end ldr r3, =0 bss_clear_loop: cmp r1, r2 strne r3, [r1], #+4 bne bss_clear_loop /* * Jump to main */ mrs r0, cpsr bic r0, r0, #I_BIT | F_BIT /* Enable FIQ and IRQ interrupt */ msr cpsr, r0 mov r0, #0 /* No arguments */ mov r1, #0 /* No arguments */ ldr r2, =main mov lr, pc bx r2 /* And jump... */ ExitFunction: nop nop nop b ExitFunction /****************************************************************************/ /* Default interrupt handler */ /****************************************************************************/ UndefHandler: b UndefHandler SWIHandler: b SWIHandler PAbortHandler: b PAbortHandler DAbortHandler: b DAbortHandler IRQHandler: b IRQHandler FIQHandler: b FIQHandler .weak ExitFunction .weak UndefHandler, PAbortHandler, DAbortHandler .weak IRQHandler, FIQHandler .ltorg /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2294Test/src/main.c ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial * 26.01.08 mifi Added variable "d" to test const variable. ****************************************************************************/ #define __MAIN_C__ /* * I use the include only, to show * how to setup a include dir in the makefile */ #include <stdio.h> #include <stdlib.h> #include "typedefs.h" /*=========================================================================*/ /* DEFINE: All Structures and Common Constants */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Prototypes */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Definition of all local Data */ /*=========================================================================*/ static const DWORD d = 7; /*=========================================================================*/ /* DEFINE: Definition of all local Procedures */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: All code exported */ /*=========================================================================*/ /***************************************************************************/ /* main */ /***************************************************************************/ int main (void) { DWORD a = 1; DWORD b = 2; DWORD c = 0; a = a + d; while (1) { a++; b++; c = a + b; } /* * This return here make no sense. * But to prevent the compiler warning: * "return type of 'main' is not 'int' * we use an int as return :-) */ return(0); } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2294Test/test_ram.hex ================================================ :020000044000BA :1000000018F09FE518F09FE518F09FE518F09FE5C0 :1000100018F09FE518F09FE518F09FE518F09FE5B0 :1000200040000040D0000040D4000040D800004014 :10003000DC00004000000000E0000040E400004060 :100040000000A0E10000A0E10000A0E10000A0E1AC :100050000000A0E10000A0E10000A0E10000A0E19C :10006000DBF021E37CD09FE5D7F021E378D09FE55A :10007000D1F021E374D09FE5D2F021E370D09FE569 :10008000D3F021E36CD09FE56C109FE56C209FE5D9 :100090000030A0E3020051E104308114FCFFFF1A9C :1000A00000000FE1C000C0E300F029E10000A0E380 :1000B0000010A0E348209FE50FE0A0E112FF2FE130 :1000C0000000A0E10000A0E10000A0E1FBFFFFEACA :1000D000FEFFFFEAFEFFFFEAFEFFFFEAFEFFFFEA88 :1000E000FEFFFFEAFEFFFFEA0006004000050040B9 :1000F0000003004000040040000A00406C01004082 :100100006C010040080100400CD04DE20130A0E33A :1001100000308DE50230A0E304308DE50030A0E32F :1001200008308DE538309FE5002093E500309DE5EF :10013000023083E000308DE500309DE5013083E240 :1001400000308DE504309DE5013083E204308DE51B :1001500000209DE504309DE5033082E008308DE508 :0C016000F4FFFFEA680100400700000007 :040000054000004077 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/LPC2294Test/test_rom.hex ================================================ :1000000018F09FE518F09FE518F09FE518F09FE5C0 :1000100018F09FE518F09FE518F09FE518F09FE5B0 :1000200040000000D0000000D4000000D800000014 :10003000DC00000000000000E0000000E400000020 :100040000000A0E10000A0E10000A0E10000A0E1AC :100050000000A0E10000A0E10000A0E10000A0E19C :10006000DBF021E37CD09FE5D7F021E378D09FE55A :10007000D1F021E374D09FE5D2F021E370D09FE569 :10008000D3F021E36CD09FE56C109FE56C209FE5D9 :100090000030A0E3020051E104308114FCFFFF1A9C :1000A00000000FE1C000C0E300F029E10000A0E380 :1000B0000010A0E348209FE50FE0A0E112FF2FE130 :1000C0000000A0E10000A0E10000A0E1FBFFFFEACA :1000D000FEFFFFEAFEFFFFEAFEFFFFEAFEFFFFEA88 :1000E000FEFFFFEAFEFFFFEA0004004000030040BD :1000F00000010040000200400008004000000040F5 :1001000000000040080100000CD04DE20130A0E3E7 :1001100000308DE50230A0E304308DE50030A0E32F :1001200008308DE538309FE5002093E500309DE5EF :10013000023083E000308DE500309DE5013083E240 :1001400000308DE504309DE5013083E204308DE51B :1001500000209DE504309DE5033082E008308DE508 :0C016000F4FFFFEA680100000700000047 :0400000300000040B9 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/PIC32/BlinkingLeds.c ================================================ #include <plib.h> int main(void) { int i; mPORTDClearBits(BIT_0); mPORTDSetPinsDigitalOut(BIT_0); mPORTDClearBits(BIT_1); mPORTDSetPinsDigitalOut(BIT_1); mPORTDClearBits(BIT_2); mPORTDSetPinsDigitalOut(BIT_2); while (1) { for (i = 0; i < 500000; i++) mPORTDToggleBits(BIT_0); for (i = 0; i < 500000; i++) mPORTDToggleBits(BIT_1); for (i = 0; i < 500000; i++) mPORTDToggleBits(BIT_2); } return 0; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/PIC32/readme.txt ================================================ Here you'll find a simple example tested with PIC32 Starter kit (source code and .elf file). It will blink repeatedly the LEDs on the board. The program was compiled and written on the target using MPLAB IDE v 8.0 that comes with the kit because openocd is missing currently the ability to program the flash for this specific target. It is possible in the future this limitation to be removed. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7S256Test/inc/typedefs.h ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial ****************************************************************************/ #ifndef __TYPEDEFS_H__ #define __TYPEDEFS_H__ /* * Some types to use Windows like source */ typedef char CHAR; /* 8-bit signed data */ typedef unsigned char BYTE; /* 8-bit unsigned data */ typedef unsigned short WORD; /* 16-bit unsigned data */ typedef long LONG; /* 32-bit signed data */ typedef unsigned long ULONG; /* 32-bit unsigned data */ typedef unsigned long DWORD; /* 32-bit unsigned data */ #endif /* !__TYPEDEFS_H_ */ /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7S256Test/prj/eclipse_ram.gdb ================================================ target remote localhost:3333 monitor reset monitor sleep 500 monitor poll monitor soft_reset_halt monitor arm7_9 sw_bkpts enable # WDT_MR, disable watchdog monitor mww 0xFFFFFD44 0x00008000 # RSTC_MR, enable user reset monitor mww 0xfffffd08 0xa5000001 # CKGR_MOR monitor mww 0xFFFFFC20 0x00000601 monitor sleep 10 # CKGR_PLLR monitor mww 0xFFFFFC2C 0x00481c0e monitor sleep 10 # PMC_MCKR monitor mww 0xFFFFFC30 0x00000007 monitor sleep 10 # PMC_IER monitor mww 0xFFFFFF60 0x00480100 monitor sleep 100 load break main continue ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7S256Test/prj/eclipse_rom.gdb ================================================ target remote localhost:3333 monitor reset monitor sleep 500 monitor poll monitor soft_reset_halt monitor arm7_9 force_hw_bkpts enable # WDT_MR, disable watchdog monitor mww 0xFFFFFD44 0x00008000 # RSTC_MR, enable user reset monitor mww 0xfffffd08 0xa5000001 # CKGR_MOR monitor mww 0xFFFFFC20 0x00000601 monitor sleep 10 # CKGR_PLLR monitor mww 0xFFFFFC2C 0x00481c0e monitor sleep 10 # PMC_MCKR monitor mww 0xFFFFFC30 0x00000007 monitor sleep 10 # PMC_IER monitor mww 0xFFFFFF60 0x00480100 monitor sleep 100 load break main continue ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7S256Test/prj/sam7s256_jtagkey.cfg ================================================ #daemon configuration telnet_port 4444 gdb_port 3333 # tell gdb our flash memory map # and enable flash programming gdb_memory_map enable gdb_flash_program enable #interface interface ft2232 ft2232_device_desc "Amontec JTAGkey A" ft2232_layout jtagkey ft2232_vid_pid 0x0403 0xcff8 jtag_speed 0 jtag_nsrst_delay 200 jtag_ntrst_delay 200 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only srst_pulls_trst #jtag scan chain jtag newtap sam7 cpu -irlen 4 -irmask 0xf #target configuration target create target0 arm7tdmi -endian little -chain-position 0 [new_target_name] configure -work-area-virt 0 -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup false target_script 0 reset .\prj\sam7s256_reset.script #flash bank <driver> <base> <size> <chip_width> <bus_width> flash bank at91sam7 0 0 0 0 0 # For more information about the configuration files, # look at the OpenOCD User's Guide. init reset halt ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7S256Test/prj/sam7s256_ram.ld ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 30.03.06 mifi First Version ****************************************************************************/ ENTRY(ResetHandler) SEARCH_DIR(.) /* * Define stack size here */ FIQ_STACK_SIZE = 0x0100; IRQ_STACK_SIZE = 0x0100; ABT_STACK_SIZE = 0x0100; UND_STACK_SIZE = 0x0100; SVC_STACK_SIZE = 0x0400; MEMORY { ram : org = 0x00200000, len = 64k } /* * Do not change the next code */ SECTIONS { .text : { *(.vectors); . = ALIGN(4); *(.init); . = ALIGN(4); *(.text); . = ALIGN(4); *(.rodata); . = ALIGN(4); *(.rodata*); . = ALIGN(4); *(.glue_7t); . = ALIGN(4); *(.glue_7); . = ALIGN(4); etext = .; } > ram .data : { PROVIDE (__data_start = .); *(.data) . = ALIGN(4); edata = .; _edata = .; PROVIDE (__data_end = .); } > ram .bss : { PROVIDE (__bss_start = .); *(.bss) *(COMMON) . = ALIGN(4); PROVIDE (__bss_end = .); . = ALIGN(256); PROVIDE (__stack_start = .); PROVIDE (__stack_fiq_start = .); . += FIQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_fiq_end = .); PROVIDE (__stack_irq_start = .); . += IRQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_irq_end = .); PROVIDE (__stack_abt_start = .); . += ABT_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_abt_end = .); PROVIDE (__stack_und_start = .); . += UND_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_und_end = .); PROVIDE (__stack_svc_start = .); . += SVC_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_svc_end = .); PROVIDE (__stack_end = .); PROVIDE (__heap_start = .); } > ram } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7S256Test/prj/sam7s256_reset.script ================================================ # # Init - taken form the script openocd_at91sam7_ecr.script # # I take this script from the following page: # # http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/openocd_intro/index.html # mww 0xfffffd44 0x00008000 # disable watchdog mww 0xfffffd08 0xa5000001 # enable user reset mww 0xfffffc20 0x00000601 # CKGR_MOR : enable the main oscillator sleep 10 mww 0xfffffc2c 0x00481c0e # CKGR_PLLR: 96.1097 MHz sleep 10 mww 0xfffffc30 0x00000007 # PMC_MCKR : MCK = PLL / 2 ~= 48 MHz sleep 10 mww 0xffffff60 0x003c0100 # MC_FMR: flash mode (FWS=1,FMCN=60) sleep 100 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7S256Test/prj/sam7s256_rom.ld ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 26.01.08 mifi First Version ****************************************************************************/ ENTRY(ResetHandler) SEARCH_DIR(.) /* * Define stack size here */ FIQ_STACK_SIZE = 0x0100; IRQ_STACK_SIZE = 0x0100; ABT_STACK_SIZE = 0x0100; UND_STACK_SIZE = 0x0100; SVC_STACK_SIZE = 0x0400; MEMORY { rom : org = 0x00100000, len = 256k ram : org = 0x00200000, len = 64k } /* * Do not change the next code */ SECTIONS { .text : { *(.vectors); . = ALIGN(4); *(.init); . = ALIGN(4); *(.text); . = ALIGN(4); *(.rodata); . = ALIGN(4); *(.rodata*); . = ALIGN(4); *(.glue_7t); . = ALIGN(4); *(.glue_7); . = ALIGN(4); etext = .; } > rom .data : { PROVIDE (__data_start = .); *(.data) . = ALIGN(4); edata = .; _edata = .; PROVIDE (__data_end = .); } > ram .bss : { PROVIDE (__bss_start = .); *(.bss) *(COMMON) . = ALIGN(4); PROVIDE (__bss_end = .); . = ALIGN(256); PROVIDE (__stack_start = .); PROVIDE (__stack_fiq_start = .); . += FIQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_fiq_end = .); PROVIDE (__stack_irq_start = .); . += IRQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_irq_end = .); PROVIDE (__stack_abt_start = .); . += ABT_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_abt_end = .); PROVIDE (__stack_und_start = .); . += UND_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_und_end = .); PROVIDE (__stack_svc_start = .); . += SVC_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_svc_end = .); PROVIDE (__stack_end = .); PROVIDE (__heap_start = .); } > ram } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7S256Test/results/607.html ================================================ <html> <head> <title>Test results for revision 607

Test cases

Test case results

The test results are stored in seperate documents. One document for each subversion number.
Test resultscomment
607
templateTest results template

SAM7S64

Connectivity

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
CON001 SAM7S64 ZY1000 Telnet connection Power on, jtag target attached On console, type
telnet ip port
Open On-Chip Debugger
>
Open On-Chip Debugger
>
PASS
CON002 SAM7S64 ZY1000 GDB server connection Power on, jtag target attached On GDB console, type
target remote ip:port
Remote debugging using 10.0.0.73:3333 Remote debugging using 10.0.0.73:3333 PASS

Reset

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
RES001 SAM7S64 ZY1000 Reset halt on a blank target Erase all the content of the flash Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
pc = 0
JTAG device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
nSRST pulls nTRST, falling back to "reset run_and_halt"
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0x60000013 pc: 0x00100178
PASS
RES002 SAM7S64 ZY1000 Reset init on a blank target Erase all the content of the flash Connect via the telnet interface and type
reset init
Reset should return without error and the output should contain
executing reset script 'name_of_the_script'
JTAG device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
nSRST pulls nTRST, falling back to "reset run_and_init"
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0x600000d3 pc: 0x00003e24
executing reset script 'event/sam7s256_reset.script'
PASS
RES003 SAM7S64 ZY1000 Reset after a power cycle of the target Reset the target then power cycle the target Connect via the telnet interface and type
reset halt after the power was detected
Reset should return without error and the output should contain
target state: halted
JTAG device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
nSRST pulls nTRST, falling back to "reset run_and_halt"
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0x300000d3 pc: 0x00003a38
PASS

JTAG Speed

ID Target ZY1000 Description Initial state Input Expected output Actual output Pass/Fail
RES001 SAM7S64 ZY1000 16MHz on normal operation Reset init the target according to RES002 Exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 16000
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
PASS

Debugging

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
DBG001 SAM7S64 ZY1000 Load is working Reset init is working, RAM is accesible, GDB server is started On the console of the OS:
arm-elf-gdb test_ram.elf
(gdb) target remote ip:port
(gdb) load
Load should return without error, typical output looks like:
Loading section .text, size 0x14c lma 0x0
Start address 0x40, load size 332
Transfer rate: 180 bytes/sec, 332 bytes/write.
(gdb) load
Loading section .text, size 0x194 lma 0x200000
Start address 0x200040, load size 404
Transfer rate: 17470 bits/sec, 404 bytes/write.
PASS
DBG002 SAM7S64 ZY1000 Software breakpoint Load the test_ram.elf application, use instructions from GDB001 In the GDB console:
(gdb) monitor arm7_9 sw_bkpts enable
software breakpoints enabled
(gdb) break main
Breakpoint 1 at 0xec: file src/main.c, line 71.
(gdb) continue
Continuing.
The software breakpoint should be reached, a typical output looks like:
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x000000ec

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
(gdb) break main
Breakpoint 2 at 0x200134: file src/main.c, line 69.
(gdb) c
Continuing.
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x60000013 pc: 0x00200134

Breakpoint 2, main () at src/main.c:69
69 DWORD a = 1;
PASS
DBG003 SAM7S64 ZY1000 Single step in a RAM application Load the test_ram.elf application, use instructions from GDB001, break in main using the instructions from GDB002 In GDB, type
(gdb) step
The next instruction should be reached, typical output:
(gdb) step
target state: halted
target halted in ARM state due to single step, current mode: Abort
cpsr: 0x20000097 pc: 0x000000f0
target state: halted
target halted in ARM state due to single step, current mode: Abort
cpsr: 0x20000097 pc: 0x000000f4
72 DWORD b = 2;
(gdb) step
target state: halted
target halted in ARM state due to single step, current mode: Abort
cpsr: 0x20000097 pc: 0x000000f0
target state: halted
target halted in ARM state due to single step, current mode: Abort
cpsr: 0x20000097 pc: 0x000000f4
72 DWORD b = 2;
PASS
DBG004 SAM7S64 ZY1000 Software break points are working after a reset Load the test_ram.elf application, use instructions from GDB001, break in main using the instructions from GDB002 In GDB, type
(gdb) monitor reset
(gdb) load
(gdb) continue
The breakpoint should be reached, typical output:
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x000000ec

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
(gdb) moni reset
JTAG device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0x600000d3 pc: 0x00003e28
executing reset script 'event/sam7s256_reset.script'
(gdb) load
Loading section .text, size 0x194 lma 0x200000
Start address 0x200040, load size 404
Transfer rate: 20455 bits/sec, 404 bytes/write.
(gdb) continue
Continuing.
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x60000013 pc: 0x00200134

Breakpoint 2, main () at src/main.c:69
69 DWORD a = 1;
PASS
DBG005 SAM7S64 ZY1000 Hardware breakpoint Flash the test_rom.elf application. Make this test after FLA004 has passed Be sure that gdb_memory_map and gdb_flash_program are enabled. In GDB, type
(gdb) monitor reset
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor arm7_9 force_hw_bkpts enable
force hardware breakpoints enabled
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
The breakpoint should be reached, typical output:
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) c
Continuing.
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x60000013 pc: 0x00100134

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
PASS
DBG006 SAM7S64 ZY1000 Hardware breakpoint is set after a reset Follow the instructions to flash and insert a hardware breakpoint from DBG005 In GDB, type
(gdb) monitor reset
(gdb) monitor reg pc 0x100000
pc (/32): 0x00100000
(gdb) continue

where the value inserted in PC is the start address of the application
The breakpoint should be reached, typical output:
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
Continuing.
target state: halted
target halted in ARM state due to single step, current mode: Supervisor
cpsr: 0x60000013 pc: 0x00100040
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x60000013 pc: 0x00100134

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;

Aren't there too many "halted" signs?
PASS
DBG007 SAM7S64 ZY1000 Single step in ROM Flash the test_rom.elf application and set a breakpoint in main, use DBG005. Make this test after FLA004 has passed Be sure that gdb_memory_map and gdb_flash_program are enabled. In GDB, type
(gdb) monitor reset
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor arm7_9 force_hw_bkpts enable
force hardware breakpoints enabled
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) step
The breakpoint should be reached, typical output:
target state: halted
target halted in ARM state due to single step, current mode: Supervisor
cpsr: 0x60000013 pc: 0x0010013c
70 DWORD b = 2;
(gdb) step
target state: halted
target halted in ARM state due to single step, current mode: Supervisor
cpsr: 0x60000013 pc: 0x00100138
target state: halted
target halted in ARM state due to single step, current mode: Supervisor
cpsr: 0x60000013 pc: 0x0010013c
70 DWORD b = 2;
PASS

RAM access

Note: these tests are not designed to test/debug the target, but to test functionalities!
ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
RAM001 SAM7S64 ZY1000 32 bit Write/read RAM Reset init is working On the telnet interface
> mww ram_address 0xdeadbeef 16
> mdw ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 32bit long containing 0xdeadbeef.
> mww 0x0 0xdeadbeef 16
> mdw 0x0 32
0x00000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000040: e1a00000 e59fa51c e59f051c e04aa000 00080017 00009388 00009388 00009388
0x00000060: 00009388 0002c2c0 0002c2c0 000094f8 000094f4 00009388 00009388 00009388
> mww 0x00200000 0xdeadbeef 16
> mdw 0x00200000 32
0x00200000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00200020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00200040: e59f10b4 e3a00902 e5810004 e59f00ac e59f10ac e5810000 e3e010ff e59f00a4
0x00200060: e5810060 e59f10a0 e3e00000 e5810130 e5810124 e321f0db e59fd090 e321f0d7
PASS
RAM002 SAM7S64 ZY1000 16 bit Write/read RAM Reset init is working On the telnet interface
> mwh ram_address 0xbeef 16
> mdh ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 16bit long containing 0xbeef.
> mwh 0x0 0xbeef 16
> mdh 0x0 32
0x00000000: beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef
0x00000020: 00e0 0000 021c 0000 0240 0000 026c 0000 0288 0000 0000 0000 0388 0000 0350 0000
>
> mwh 0x00200000 0xbeef 16
> mdh 0x00200000 32
0x00200000: beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef
0x00200020: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
PASS
RAM003 SAM7S64 ZY1000 8 bit Write/read RAM Reset init is working On the telnet interface
> mwb ram_address 0xab 16
> mdb ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 8bit long containing 0xab.
> mwb ram_address 0xab 16
> mdb ram_address 32
0x00000000: ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>
> mwb 0x00200000 0xab 16
> mdb 0x00200000 32
0x00200000: ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
PASS

Flash access

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
FLA001 SAM7S64 ZY1000 Flash probe Reset init is working On the telnet interface:
> flash probe 0
The command should execute without error. The output should state the name of the flash and the starting address. An example of output:
flash 'ecosflash' found at 0x01000000
> flash probe 0
flash 'at91sam7' found at 0x00100000
PASS
FLA002 SAM7S64 ZY1000 flash fillw Reset init is working, flash is probed On the telnet interface
> flash fillw 0x1000000 0xdeadbeef 16
The commands should execute without error. The output looks like:
wrote 64 bytes to 0x01000000 in 11.610000s (0.091516 kb/s)
To verify the contents of the flash:
> mdw 0x1000000 32
0x01000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x01000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x01000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> flash fillw 0x100000 0xdeadbeef 16
wrote 64 bytes to 0x00100000 in 1.110000s (0.957207 kb/s)
> mdw 0x100000 32
0x00100000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00100020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00100040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00100060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
PASS
FLA003 SAM7S64 ZY1000 Flash erase Reset init is working, flash is probed On the telnet interface
> flash erase_address 0x1000000 0x2000
The commands should execute without error.
erased address 0x01000000 length 8192 in 4.970000s To check that the flash has been erased, read at different addresses. The result should always be 0xff. > mdw 0x1000000 32
0x01000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> flash erase_address 0x100000 0x2000
erased address 0x00100000 length 8192 in 0.510000s
> mdw 0x100000 32
0x00100000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00100020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00100040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00100060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
FLA004 SAM7S64 ZY1000 Loading to flash from GDB Reset init is working, flash is probed, connectivity to GDB server is working Start GDB using a ROM elf image, eg: arm-elf-gdb test_rom.elf.
(gdb) target remote ip:port
(gdb) monitor reset
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write. (gdb) monitor verify_image path_to_elf_file
The output should look like:
verified 404 bytes in 5.060000s
The failure message is something like:
Verify operation failed address 0x00200000. Was 0x00 instead of 0x18
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 1540 bits/sec, 404 bytes/write.
(gdb) monitor verify_image /tftp/10.0.0.9/c:\workspace/ecosboard/ecosboard/phi/openocd/rep/testing/examples/SAM7S256Test/test_rom.elf
verified 404 bytes in 4.860000s
PASS
================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7S256Test/src/crt.s ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 18.12.06 mifi First Version * The hardware initialization is based on the startup file * crtat91sam7x256_rom.S from NutOS 4.2.1. * Therefore partial copyright by egnite Software GmbH. ****************************************************************************/ /* * Some defines for the program status registers */ ARM_MODE_USER = 0x10 /* Normal User Mode */ ARM_MODE_FIQ = 0x11 /* FIQ Fast Interrupts Mode */ ARM_MODE_IRQ = 0x12 /* IRQ Standard Interrupts Mode */ ARM_MODE_SVC = 0x13 /* Supervisor Interrupts Mode */ ARM_MODE_ABORT = 0x17 /* Abort Processing memory Faults Mode */ ARM_MODE_UNDEF = 0x1B /* Undefined Instructions Mode */ ARM_MODE_SYS = 0x1F /* System Running in Priviledged Operating Mode */ ARM_MODE_MASK = 0x1F I_BIT = 0x80 /* disable IRQ when I bit is set */ F_BIT = 0x40 /* disable IRQ when I bit is set */ /* * Register Base Address */ AIC_BASE = 0xFFFFF000 AIC_EOICR_OFF = 0x130 AIC_IDCR_OFF = 0x124 RSTC_MR = 0xFFFFFD08 RSTC_KEY = 0xA5000000 RSTC_URSTEN = 0x00000001 WDT_BASE = 0xFFFFFD40 WDT_MR_OFF = 0x00000004 WDT_WDDIS = 0x00008000 MC_BASE = 0xFFFFFF00 MC_FMR_OFF = 0x00000060 MC_FWS_1FWS = 0x00480100 .section .vectors,"ax" .code 32 /****************************************************************************/ /* Vector table and reset entry */ /****************************************************************************/ _vectors: ldr pc, ResetAddr /* Reset */ ldr pc, UndefAddr /* Undefined instruction */ ldr pc, SWIAddr /* Software interrupt */ ldr pc, PAbortAddr /* Prefetch abort */ ldr pc, DAbortAddr /* Data abort */ ldr pc, ReservedAddr /* Reserved */ ldr pc, IRQAddr /* IRQ interrupt */ ldr pc, FIQAddr /* FIQ interrupt */ ResetAddr: .word ResetHandler UndefAddr: .word UndefHandler SWIAddr: .word SWIHandler PAbortAddr: .word PAbortHandler DAbortAddr: .word DAbortHandler ReservedAddr: .word 0 IRQAddr: .word IRQHandler FIQAddr: .word FIQHandler .ltorg .section .init, "ax" .code 32 .global ResetHandler .global ExitFunction .extern main /****************************************************************************/ /* Reset handler */ /****************************************************************************/ ResetHandler: /* * The watchdog is enabled after processor reset. Disable it. */ ldr r1, =WDT_BASE ldr r0, =WDT_WDDIS str r0, [r1, #WDT_MR_OFF] /* * Enable user reset: assertion length programmed to 1ms */ ldr r0, =(RSTC_KEY | RSTC_URSTEN | (4 << 8)) ldr r1, =RSTC_MR str r0, [r1, #0] /* * Use 2 cycles for flash access. */ ldr r1, =MC_BASE ldr r0, =MC_FWS_1FWS str r0, [r1, #MC_FMR_OFF] /* * Disable all interrupts. Useful for debugging w/o target reset. */ ldr r1, =AIC_BASE mvn r0, #0 str r0, [r1, #AIC_EOICR_OFF] str r0, [r1, #AIC_IDCR_OFF] /* * Setup a stack for each mode */ msr CPSR_c, #ARM_MODE_UNDEF | I_BIT | F_BIT /* Undefined Instruction Mode */ ldr sp, =__stack_und_end msr CPSR_c, #ARM_MODE_ABORT | I_BIT | F_BIT /* Abort Mode */ ldr sp, =__stack_abt_end msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT /* FIQ Mode */ ldr sp, =__stack_fiq_end msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT /* IRQ Mode */ ldr sp, =__stack_irq_end msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT /* Supervisor Mode */ ldr sp, =__stack_svc_end /* * Clear .bss section */ ldr r1, =__bss_start ldr r2, =__bss_end ldr r3, =0 bss_clear_loop: cmp r1, r2 strne r3, [r1], #+4 bne bss_clear_loop /* * Jump to main */ mrs r0, cpsr bic r0, r0, #I_BIT | F_BIT /* Enable FIQ and IRQ interrupt */ msr cpsr, r0 mov r0, #0 /* No arguments */ mov r1, #0 /* No arguments */ ldr r2, =main mov lr, pc bx r2 /* And jump... */ ExitFunction: nop nop nop b ExitFunction /****************************************************************************/ /* Default interrupt handler */ /****************************************************************************/ UndefHandler: b UndefHandler SWIHandler: b SWIHandler PAbortHandler: b PAbortHandler DAbortHandler: b DAbortHandler IRQHandler: b IRQHandler FIQHandler: b FIQHandler .weak ExitFunction .weak UndefHandler, PAbortHandler, DAbortHandler .weak IRQHandler, FIQHandler .ltorg /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7S256Test/src/main.c ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial * 26.01.08 mifi Added variable "d" to test const variable. ****************************************************************************/ #define __MAIN_C__ /* * I use the include only, to show * how to setup a include dir in the makefile */ #include "typedefs.h" /*=========================================================================*/ /* DEFINE: All Structures and Common Constants */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Prototypes */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Definition of all local Data */ /*=========================================================================*/ static const DWORD d = 7; /*=========================================================================*/ /* DEFINE: Definition of all local Procedures */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: All code exported */ /*=========================================================================*/ /***************************************************************************/ /* main */ /***************************************************************************/ int main (void) { DWORD a = 1; DWORD b = 2; DWORD c = 0; a = a + d; while (1) { a++; b++; c = a + b; } /* * This return here make no sense. * But to prevent the compiler warning: * "return type of 'main' is not 'int' * we use an int as return :-) */ return(0); } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7S256Test/test_ram.hex ================================================ :020000040020DA :1000000018F09FE518F09FE518F09FE518F09FE5C0 :1000100018F09FE518F09FE518F09FE518F09FE5B0 :1000200040002000E4002000E8002000EC00200058 :10003000F000200000000000F4002000F800200084 :10004000B4109FE50209A0E3040081E5AC009FE540 :10005000AC109FE5000081E5FF10E0E3A4009FE500 :10006000600081E5A0109FE50000E0E3300181E53C :10007000240181E5DBF021E390D09FE5D7F021E377 :100080008CD09FE5D1F021E388D09FE5D2F021E329 :1000900084D09FE5D3F021E380D09FE580109FE5D9 :1000A00080209FE50030A0E3020051E1043081147C :1000B000FCFFFF1A00000FE1C000C0E300F029E1DF :1000C0000000A0E30010A0E35C209FE50FE0A0E1AA :1000D00012FF2FE10000A0E10000A0E10000A0E17C :1000E000FBFFFFEAFEFFFFEAFEFFFFEAFEFFFFEA7B :1000F000FEFFFFEAFEFFFFEAFEFFFFEA40FDFFFF13 :10010000010400A508FDFFFF0001480000F0FFFF0B :10011000000620000005200000032000000420004D :10012000000A2000940120009401200030012000EA :100130000CD04DE20130A0E300308DE50230A0E3A9 :1001400004308DE50030A0E308308DE538309FE5C0 :10015000002093E500309DE5023083E000308DE51E :1001600000309DE5013083E200308DE504309DE5EF :10017000013083E204308DE500209DE504309DE5EB :10018000033082E008308DE5F4FFFFEA90012000A3 :040190000700000064 :040000050020004097 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7S256Test/test_rom.hex ================================================ :020000040010EA :1000000018F09FE518F09FE518F09FE518F09FE5C0 :1000100018F09FE518F09FE518F09FE518F09FE5B0 :1000200040001000E4001000E8001000EC00100098 :10003000F000100000000000F4001000F8001000B4 :10004000B4109FE50209A0E3040081E5AC009FE540 :10005000AC109FE5000081E5FF10E0E3A4009FE500 :10006000600081E5A0109FE50000E0E3300181E53C :10007000240181E5DBF021E390D09FE5D7F021E377 :100080008CD09FE5D1F021E388D09FE5D2F021E329 :1000900084D09FE5D3F021E380D09FE580109FE5D9 :1000A00080209FE50030A0E3020051E1043081147C :1000B000FCFFFF1A00000FE1C000C0E300F029E1DF :1000C0000000A0E30010A0E35C209FE50FE0A0E1AA :1000D00012FF2FE10000A0E10000A0E10000A0E17C :1000E000FBFFFFEAFEFFFFEAFEFFFFEAFEFFFFEA7B :1000F000FEFFFFEAFEFFFFEAFEFFFFEA40FDFFFF13 :10010000010400A508FDFFFF0001480000F0FFFF0B :100110000004200000032000000120000002200055 :100120000008200000002000000020003001100026 :100130000CD04DE20130A0E300308DE50230A0E3A9 :1001400004308DE50030A0E308308DE538309FE5C0 :10015000002093E500309DE5023083E000308DE51E :1001600000309DE5013083E200308DE504309DE5EF :10017000013083E204308DE500209DE504309DE5EB :10018000033082E008308DE5F4FFFFEA90011000B3 :040190000700000064 :0400000500100040A7 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7X256Test/inc/typedefs.h ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial ****************************************************************************/ #ifndef __TYPEDEFS_H__ #define __TYPEDEFS_H__ /* * Some types to use Windows like source */ typedef char CHAR; /* 8-bit signed data */ typedef unsigned char BYTE; /* 8-bit unsigned data */ typedef unsigned short WORD; /* 16-bit unsigned data */ typedef long LONG; /* 32-bit signed data */ typedef unsigned long ULONG; /* 32-bit unsigned data */ typedef unsigned long DWORD; /* 32-bit unsigned data */ #endif /* !__TYPEDEFS_H_ */ /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7X256Test/prj/eclipse_ram.gdb ================================================ target remote localhost:3333 monitor reset monitor sleep 500 monitor poll monitor soft_reset_halt monitor arm7_9 sw_bkpts enable # WDT_MR, disable watchdog monitor mww 0xFFFFFD44 0x00008000 # RSTC_MR, enable user reset monitor mww 0xfffffd08 0xa5000001 # CKGR_MOR monitor mww 0xFFFFFC20 0x00000601 monitor sleep 10 # CKGR_PLLR monitor mww 0xFFFFFC2C 0x00481c0e monitor sleep 10 # PMC_MCKR monitor mww 0xFFFFFC30 0x00000007 monitor sleep 10 # PMC_IER monitor mww 0xFFFFFF60 0x00480100 monitor sleep 100 load break main continue ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7X256Test/prj/eclipse_rom.gdb ================================================ target remote localhost:3333 monitor reset monitor sleep 500 monitor poll monitor soft_reset_halt monitor arm7_9 force_hw_bkpts enable # WDT_MR, disable watchdog monitor mww 0xFFFFFD44 0x00008000 # RSTC_MR, enable user reset monitor mww 0xfffffd08 0xa5000001 # CKGR_MOR monitor mww 0xFFFFFC20 0x00000601 monitor sleep 10 # CKGR_PLLR monitor mww 0xFFFFFC2C 0x00481c0e monitor sleep 10 # PMC_MCKR monitor mww 0xFFFFFC30 0x00000007 monitor sleep 10 # PMC_IER monitor mww 0xFFFFFF60 0x00480100 monitor sleep 100 load break main continue ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7X256Test/prj/sam7x256_jtagkey.cfg ================================================ #daemon configuration telnet_port 4444 gdb_port 3333 # tell gdb our flash memory map # and enable flash programming gdb_memory_map enable gdb_flash_program enable #interface interface ft2232 ft2232_device_desc "Amontec JTAGkey A" ft2232_layout jtagkey ft2232_vid_pid 0x0403 0xcff8 jtag_speed 0 jtag_nsrst_delay 200 jtag_ntrst_delay 200 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only srst_pulls_trst #jtag scan chain jtag newtap sam7 cpu -irlen 4 -irmask 0xf #target configuration target create target0 arm7tdmi -endian little -chain-position 0 [new_target_name] configure -work-area-virt 0 -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup false target_script 0 reset .\prj\sam7x256_reset.script #flash bank flash bank at91sam7 0 0 0 0 0 # For more information about the configuration files, # look at the OpenOCD User's Guide. init reset halt ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7X256Test/prj/sam7x256_ram.ld ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 30.03.06 mifi First Version ****************************************************************************/ ENTRY(ResetHandler) SEARCH_DIR(.) /* * Define stack size here */ FIQ_STACK_SIZE = 0x0100; IRQ_STACK_SIZE = 0x0100; ABT_STACK_SIZE = 0x0100; UND_STACK_SIZE = 0x0100; SVC_STACK_SIZE = 0x0400; MEMORY { ram : org = 0x00200000, len = 64k } /* * Do not change the next code */ SECTIONS { .text : { *(.vectors); . = ALIGN(4); *(.init); . = ALIGN(4); *(.text); . = ALIGN(4); *(.rodata); . = ALIGN(4); *(.rodata*); . = ALIGN(4); *(.glue_7t); . = ALIGN(4); *(.glue_7); . = ALIGN(4); etext = .; } > ram .data : { PROVIDE (__data_start = .); *(.data) . = ALIGN(4); edata = .; _edata = .; PROVIDE (__data_end = .); } > ram .bss : { PROVIDE (__bss_start = .); *(.bss) *(COMMON) . = ALIGN(4); PROVIDE (__bss_end = .); . = ALIGN(256); PROVIDE (__stack_start = .); PROVIDE (__stack_fiq_start = .); . += FIQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_fiq_end = .); PROVIDE (__stack_irq_start = .); . += IRQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_irq_end = .); PROVIDE (__stack_abt_start = .); . += ABT_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_abt_end = .); PROVIDE (__stack_und_start = .); . += UND_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_und_end = .); PROVIDE (__stack_svc_start = .); . += SVC_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_svc_end = .); PROVIDE (__stack_end = .); PROVIDE (__heap_start = .); } > ram } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7X256Test/prj/sam7x256_reset.script ================================================ # # Init - taken form the script openocd_at91sam7_ecr.script # # I take this script from the following page: # # http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/openocd_intro/index.html # mww 0xfffffd44 0x00008000 # disable watchdog mww 0xfffffd08 0xa5000001 # enable user reset mww 0xfffffc20 0x00000601 # CKGR_MOR : enable the main oscillator sleep 10 mww 0xfffffc2c 0x00481c0e # CKGR_PLLR: 96.1097 MHz sleep 10 mww 0xfffffc30 0x00000007 # PMC_MCKR : MCK = PLL / 2 ~= 48 MHz sleep 10 mww 0xffffff60 0x003c0100 # MC_FMR: flash mode (FWS=1,FMCN=60) sleep 100 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7X256Test/prj/sam7x256_rom.ld ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 26.01.08 mifi First Version ****************************************************************************/ ENTRY(ResetHandler) SEARCH_DIR(.) /* * Define stack size here */ FIQ_STACK_SIZE = 0x0100; IRQ_STACK_SIZE = 0x0100; ABT_STACK_SIZE = 0x0100; UND_STACK_SIZE = 0x0100; SVC_STACK_SIZE = 0x0400; MEMORY { rom : org = 0x00100000, len = 256k ram : org = 0x00200000, len = 64k } /* * Do not change the next code */ SECTIONS { .text : { *(.vectors); . = ALIGN(4); *(.init); . = ALIGN(4); *(.text); . = ALIGN(4); *(.rodata); . = ALIGN(4); *(.rodata*); . = ALIGN(4); *(.glue_7t); . = ALIGN(4); *(.glue_7); . = ALIGN(4); etext = .; } > rom .data : { PROVIDE (__data_start = .); *(.data) . = ALIGN(4); edata = .; _edata = .; PROVIDE (__data_end = .); } > ram .bss : { PROVIDE (__bss_start = .); *(.bss) *(COMMON) . = ALIGN(4); PROVIDE (__bss_end = .); . = ALIGN(256); PROVIDE (__stack_start = .); PROVIDE (__stack_fiq_start = .); . += FIQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_fiq_end = .); PROVIDE (__stack_irq_start = .); . += IRQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_irq_end = .); PROVIDE (__stack_abt_start = .); . += ABT_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_abt_end = .); PROVIDE (__stack_und_start = .); . += UND_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_und_end = .); PROVIDE (__stack_svc_start = .); . += SVC_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_svc_end = .); PROVIDE (__stack_end = .); PROVIDE (__heap_start = .); } > ram } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7X256Test/src/crt.s ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 18.12.06 mifi First Version * The hardware initialization is based on the startup file * crtat91sam7x256_rom.S from NutOS 4.2.1. * Therefore partial copyright by egnite Software GmbH. ****************************************************************************/ /* * Some defines for the program status registers */ ARM_MODE_USER = 0x10 /* Normal User Mode */ ARM_MODE_FIQ = 0x11 /* FIQ Fast Interrupts Mode */ ARM_MODE_IRQ = 0x12 /* IRQ Standard Interrupts Mode */ ARM_MODE_SVC = 0x13 /* Supervisor Interrupts Mode */ ARM_MODE_ABORT = 0x17 /* Abort Processing memory Faults Mode */ ARM_MODE_UNDEF = 0x1B /* Undefined Instructions Mode */ ARM_MODE_SYS = 0x1F /* System Running in Priviledged Operating Mode */ ARM_MODE_MASK = 0x1F I_BIT = 0x80 /* disable IRQ when I bit is set */ F_BIT = 0x40 /* disable IRQ when I bit is set */ /* * Register Base Address */ AIC_BASE = 0xFFFFF000 AIC_EOICR_OFF = 0x130 AIC_IDCR_OFF = 0x124 RSTC_MR = 0xFFFFFD08 RSTC_KEY = 0xA5000000 RSTC_URSTEN = 0x00000001 WDT_BASE = 0xFFFFFD40 WDT_MR_OFF = 0x00000004 WDT_WDDIS = 0x00008000 MC_BASE = 0xFFFFFF00 MC_FMR_OFF = 0x00000060 MC_FWS_1FWS = 0x00480100 .section .vectors,"ax" .code 32 /****************************************************************************/ /* Vector table and reset entry */ /****************************************************************************/ _vectors: ldr pc, ResetAddr /* Reset */ ldr pc, UndefAddr /* Undefined instruction */ ldr pc, SWIAddr /* Software interrupt */ ldr pc, PAbortAddr /* Prefetch abort */ ldr pc, DAbortAddr /* Data abort */ ldr pc, ReservedAddr /* Reserved */ ldr pc, IRQAddr /* IRQ interrupt */ ldr pc, FIQAddr /* FIQ interrupt */ ResetAddr: .word ResetHandler UndefAddr: .word UndefHandler SWIAddr: .word SWIHandler PAbortAddr: .word PAbortHandler DAbortAddr: .word DAbortHandler ReservedAddr: .word 0 IRQAddr: .word IRQHandler FIQAddr: .word FIQHandler .ltorg .section .init, "ax" .code 32 .global ResetHandler .global ExitFunction .extern main /****************************************************************************/ /* Reset handler */ /****************************************************************************/ ResetHandler: /* * The watchdog is enabled after processor reset. Disable it. */ ldr r1, =WDT_BASE ldr r0, =WDT_WDDIS str r0, [r1, #WDT_MR_OFF] /* * Enable user reset: assertion length programmed to 1ms */ ldr r0, =(RSTC_KEY | RSTC_URSTEN | (4 << 8)) ldr r1, =RSTC_MR str r0, [r1, #0] /* * Use 2 cycles for flash access. */ ldr r1, =MC_BASE ldr r0, =MC_FWS_1FWS str r0, [r1, #MC_FMR_OFF] /* * Disable all interrupts. Useful for debugging w/o target reset. */ ldr r1, =AIC_BASE mvn r0, #0 str r0, [r1, #AIC_EOICR_OFF] str r0, [r1, #AIC_IDCR_OFF] /* * Setup a stack for each mode */ msr CPSR_c, #ARM_MODE_UNDEF | I_BIT | F_BIT /* Undefined Instruction Mode */ ldr sp, =__stack_und_end msr CPSR_c, #ARM_MODE_ABORT | I_BIT | F_BIT /* Abort Mode */ ldr sp, =__stack_abt_end msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT /* FIQ Mode */ ldr sp, =__stack_fiq_end msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT /* IRQ Mode */ ldr sp, =__stack_irq_end msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT /* Supervisor Mode */ ldr sp, =__stack_svc_end /* * Clear .bss section */ ldr r1, =__bss_start ldr r2, =__bss_end ldr r3, =0 bss_clear_loop: cmp r1, r2 strne r3, [r1], #+4 bne bss_clear_loop /* * Jump to main */ mrs r0, cpsr bic r0, r0, #I_BIT | F_BIT /* Enable FIQ and IRQ interrupt */ msr cpsr, r0 mov r0, #0 /* No arguments */ mov r1, #0 /* No arguments */ ldr r2, =main mov lr, pc bx r2 /* And jump... */ ExitFunction: nop nop nop b ExitFunction /****************************************************************************/ /* Default interrupt handler */ /****************************************************************************/ UndefHandler: b UndefHandler SWIHandler: b SWIHandler PAbortHandler: b PAbortHandler DAbortHandler: b DAbortHandler IRQHandler: b IRQHandler FIQHandler: b FIQHandler .weak ExitFunction .weak UndefHandler, PAbortHandler, DAbortHandler .weak IRQHandler, FIQHandler .ltorg /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7X256Test/src/main.c ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial * 26.01.08 mifi Added variable "d" to test const variable. ****************************************************************************/ #define __MAIN_C__ /* * I use the include only, to show * how to setup a include dir in the makefile */ #include "typedefs.h" /*=========================================================================*/ /* DEFINE: All Structures and Common Constants */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Prototypes */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Definition of all local Data */ /*=========================================================================*/ static const DWORD d = 7; /*=========================================================================*/ /* DEFINE: Definition of all local Procedures */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: All code exported */ /*=========================================================================*/ /***************************************************************************/ /* main */ /***************************************************************************/ int main (void) { DWORD a = 1; DWORD b = 2; DWORD c = 0; a = a + d; while (1) { a++; b++; c = a + b; } /* * This return here make no sense. * But to prevent the compiler warning: * "return type of 'main' is not 'int' * we use an int as return :-) */ return(0); } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7X256Test/test_ram.hex ================================================ :020000040020DA :1000000018F09FE518F09FE518F09FE518F09FE5C0 :1000100018F09FE518F09FE518F09FE518F09FE5B0 :1000200040002000E4002000E8002000EC00200058 :10003000F000200000000000F4002000F800200084 :10004000B4109FE50209A0E3040081E5AC009FE540 :10005000AC109FE5000081E5FF10E0E3A4009FE500 :10006000600081E5A0109FE50000E0E3300181E53C :10007000240181E5DBF021E390D09FE5D7F021E377 :100080008CD09FE5D1F021E388D09FE5D2F021E329 :1000900084D09FE5D3F021E380D09FE580109FE5D9 :1000A00080209FE50030A0E3020051E1043081147C :1000B000FCFFFF1A00000FE1C000C0E300F029E1DF :1000C0000000A0E30010A0E35C209FE50FE0A0E1AA :1000D00012FF2FE10000A0E10000A0E10000A0E17C :1000E000FBFFFFEAFEFFFFEAFEFFFFEAFEFFFFEA7B :1000F000FEFFFFEAFEFFFFEAFEFFFFEA40FDFFFF13 :10010000010400A508FDFFFF0001480000F0FFFF0B :10011000000620000005200000032000000420004D :10012000000A2000940120009401200030012000EA :100130000CD04DE20130A0E300308DE50230A0E3A9 :1001400004308DE50030A0E308308DE538309FE5C0 :10015000002093E500309DE5023083E000308DE51E :1001600000309DE5013083E200308DE504309DE5EF :10017000013083E204308DE500209DE504309DE5EB :10018000033082E008308DE5F4FFFFEA90012000A3 :040190000700000064 :040000050020004097 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/SAM7X256Test/test_rom.hex ================================================ :020000040010EA :1000000018F09FE518F09FE518F09FE518F09FE5C0 :1000100018F09FE518F09FE518F09FE518F09FE5B0 :1000200040001000E4001000E8001000EC00100098 :10003000F000100000000000F4001000F8001000B4 :10004000B4109FE50209A0E3040081E5AC009FE540 :10005000AC109FE5000081E5FF10E0E3A4009FE500 :10006000600081E5A0109FE50000E0E3300181E53C :10007000240181E5DBF021E390D09FE5D7F021E377 :100080008CD09FE5D1F021E388D09FE5D2F021E329 :1000900084D09FE5D3F021E380D09FE580109FE5D9 :1000A00080209FE50030A0E3020051E1043081147C :1000B000FCFFFF1A00000FE1C000C0E300F029E1DF :1000C0000000A0E30010A0E35C209FE50FE0A0E1AA :1000D00012FF2FE10000A0E10000A0E10000A0E17C :1000E000FBFFFFEAFEFFFFEAFEFFFFEAFEFFFFEA7B :1000F000FEFFFFEAFEFFFFEAFEFFFFEA40FDFFFF13 :10010000010400A508FDFFFF0001480000F0FFFF0B :100110000004200000032000000120000002200055 :100120000008200000002000000020003001100026 :100130000CD04DE20130A0E300308DE50230A0E3A9 :1001400004308DE50030A0E308308DE538309FE5C0 :10015000002093E500309DE5023083E000308DE51E :1001600000309DE5013083E200308DE504309DE5EF :10017000013083E204308DE500209DE504309DE5EB :10018000033082E008308DE5F4FFFFEA90011000B3 :040190000700000064 :0400000500100040A7 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STM32-103/readme.txt ================================================ Olimex STM32-p103 board. main.elf is a file that can be programmed to flash for testing purposes(e.g. test GDB load performance). http://www.olimex.com/dev/stm32-p103.html ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710JtagSpeed/inc/typedefs.h ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial ****************************************************************************/ #ifndef __TYPEDEFS_H__ #define __TYPEDEFS_H__ /* * Some types to use Windows like source */ typedef char CHAR; /* 8-bit signed data */ typedef unsigned char BYTE; /* 8-bit unsigned data */ typedef unsigned short WORD; /* 16-bit unsigned data */ typedef long LONG; /* 32-bit signed data */ typedef unsigned long ULONG; /* 32-bit unsigned data */ typedef unsigned long DWORD; /* 32-bit unsigned data */ #endif /* !__TYPEDEFS_H_ */ /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710JtagSpeed/prj/eclipse_ft2232_ram.gdb ================================================ target remote localhost:3333 monitor reset monitor sleep 500 monitor poll monitor soft_reset_halt monitor arm7_9 sw_bkpts enable monitor mww 0xA0000050 0x01c2 monitor mdw 0xA0000050 monitor mww 0x6C000004 0x8005 monitor mdw 0x6C000004 monitor mww 0xE0005000 0xFFFF monitor mww 0xE0005004 0x00FF monitor mww 0xE0005008 0xFFFF monitor mdw 0xE0005000 monitor mdw 0xE0005004 monitor mdw 0xE0005008 monitor mww 0xE000500C 0x0000 monitor arm7_9 fast_memory_access enable monitor arm7_9 dcc_downloads enable monitor verify_ircapture disable load break main continue ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710JtagSpeed/prj/str710_jtagkey.cfg ================================================ #daemon configuration telnet_port 4444 gdb_port 3333 # tell gdb our flash memory map # and enable flash programming gdb_memory_map enable gdb_flash_program enable #interface interface ft2232 ft2232_device_desc "Amontec JTAGkey A" ft2232_layout jtagkey ft2232_vid_pid 0x0403 0xcff8 jtag_speed 0 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst #jtag scan chain jtag newtap str7 cpu -irlen 4 -irmask 0xf #target configuration target create target0 arm7tdmi -endian little -chain-position 0 [new_target_name] configure -work-area-virt 0 -work-area-phys 0x2000C000 -work-area-size 0x4000 -work-area-backup false #flash bank str7x 0 0 flash bank str7x 0x40000000 0x00040000 0 0 0 STR71x # For more information about the configuration files, # look at the OpenOCD User's Guide. init reset halt ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710JtagSpeed/prj/str7_ram.ld ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 30.03.06 mifi First Version ****************************************************************************/ ENTRY(ResetHandler) SEARCH_DIR(.) /* * Define stack size here */ FIQ_STACK_SIZE = 0x0100; IRQ_STACK_SIZE = 0x0100; ABT_STACK_SIZE = 0x0100; UND_STACK_SIZE = 0x0100; SVC_STACK_SIZE = 0x0400; /* * This file, hitex_str7_ram.ld, locate the program in the internal * ram of the STR7. For more information about the memory of the STR7 * take a look in the STR71X Microcontroller Reference Manual. * Reference is made to Rev. 6 March 2005 * * Take a look at page 16, section 2.1.1 Memory Map */ MEMORY { ram : org = 0x62000000, len = 512k } /* * Do not change the next code */ SECTIONS { .text : { *(.vectors); . = ALIGN(4); *(.init); . = ALIGN(4); *(.text); . = ALIGN(4); *(.rodata); . = ALIGN(4); *(.rodata*); . = ALIGN(4); *(.glue_7t); . = ALIGN(4); *(.glue_7); . = ALIGN(4); etext = .; } > ram .data : { PROVIDE (__data_start = .); *(.data) . = ALIGN(4); edata = .; _edata = .; PROVIDE (__data_end = .); } > ram .bss : { PROVIDE (__bss_start = .); *(.bss) *(COMMON) . = ALIGN(4); PROVIDE (__bss_end = .); . = ALIGN(256); PROVIDE (__stack_start = .); PROVIDE (__stack_fiq_start = .); . += FIQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_fiq_end = .); PROVIDE (__stack_irq_start = .); . += IRQ_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_irq_end = .); PROVIDE (__stack_abt_start = .); . += ABT_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_abt_end = .); PROVIDE (__stack_und_start = .); . += UND_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_und_end = .); PROVIDE (__stack_svc_start = .); . += SVC_STACK_SIZE; . = ALIGN(4); PROVIDE (__stack_svc_end = .); PROVIDE (__stack_end = .); PROVIDE (__heap_start = .); } > ram } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710JtagSpeed/src/crt.s ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 04.03.06 mifi First Version * This version based on an example from Ethernut and * "ARM Cross Development with Eclipse" from James P. Lynch ****************************************************************************/ /* * Some defines for the program status registers */ ARM_MODE_USER = 0x10 /* Normal User Mode */ ARM_MODE_FIQ = 0x11 /* FIQ Fast Interrupts Mode */ ARM_MODE_IRQ = 0x12 /* IRQ Standard Interrupts Mode */ ARM_MODE_SVC = 0x13 /* Supervisor Interrupts Mode */ ARM_MODE_ABORT = 0x17 /* Abort Processing memory Faults Mode */ ARM_MODE_UNDEF = 0x1B /* Undefined Instructions Mode */ ARM_MODE_SYS = 0x1F /* System Running in Priviledged Operating Mode */ ARM_MODE_MASK = 0x1F I_BIT = 0x80 /* disable IRQ when I bit is set */ F_BIT = 0x40 /* disable IRQ when I bit is set */ /* * Register Base Address */ PRCCU_BASE = 0xA0000000 RCCU_CFR = 0x08 RCCU_PLL1CR = 0x18 PCU_MDIVR = 0x40 PCU_PDIVR = 0x44 PCU_BOOTCR = 0x50 .section .vectors,"ax" .code 32 /****************************************************************************/ /* Vector table and reset entry */ /****************************************************************************/ _vectors: ldr pc, ResetAddr /* Reset */ ldr pc, UndefAddr /* Undefined instruction */ ldr pc, SWIAddr /* Software interrupt */ ldr pc, PAbortAddr /* Prefetch abort */ ldr pc, DAbortAddr /* Data abort */ ldr pc, ReservedAddr /* Reserved */ ldr pc, IRQAddr /* IRQ interrupt */ ldr pc, FIQAddr /* FIQ interrupt */ ResetAddr: .word ResetHandler UndefAddr: .word UndefHandler SWIAddr: .word SWIHandler PAbortAddr: .word PAbortHandler DAbortAddr: .word DAbortHandler ReservedAddr: .word 0 IRQAddr: .word IRQHandler FIQAddr: .word FIQHandler .ltorg .section .init, "ax" .code 32 .global ResetHandler .global ExitFunction .extern main /****************************************************************************/ /* Reset handler */ /****************************************************************************/ ResetHandler: /* * Wait for the oscillator is stable */ nop nop nop nop nop nop nop nop /* * Setup STR71X, for more information about the register * take a look in the STR71x Microcontroller Reference Manual. * * Reference is made to: Rev. 6 March 2005 * * 1. Map internal RAM to address 0 * In this case, we are running always in the RAM * this make no sence. But if we are in flash, we * can copy the interrupt vectors into the ram and * switch to RAM mode. * * 2. Setup the PLL, the eval board HITEX STR7 is equipped * with an external 16MHz oscillator. We want: * * RCLK: 32MHz = (CLK2 * 16) / 4 * MCLK: 32Mhz * PCLK1: 32MHz * PCLK2: 32MHz * */ /* * 1. Map RAM to the boot memory 0x00000000 */ ldr r0, =PRCCU_BASE ldr r1, =0x01C2 str r1, [r0, #PCU_BOOTCR] /* * 2. Setup PLL start */ /* Set the prescaling factor for APB and APB1 group */ ldr r0, =PRCCU_BASE ldr r1, =0x0000 /* no prescaling PCLKx = RCLK */ str r1, [r0, #PCU_PDIVR] /* Set the prescaling factor for the Main System Clock MCLK */ ldr r0, =PRCCU_BASE ldr r1, =0x0000 /* no prescaling MCLK = RCLK str r1, [r0, #PCU_MDIVR] /* Configure the PLL1 ( * 16 , / 4 ) */ ldr r0, =PRCCU_BASE ldr r1, =0x0073 str r1, [r0, #RCCU_PLL1CR] /* Check if the PLL is locked */ pll_lock_loop: ldr r1, [r0, #RCCU_CFR] tst r1, #0x0002 beq pll_lock_loop /* Select PLL1_Output as RCLK clock */ ldr r0, =PRCCU_BASE ldr r1, =0x8009 str r1, [r0, #RCCU_CFR] /* * Setup PLL end */ /* * Setup a stack for each mode */ msr CPSR_c, #ARM_MODE_UNDEF | I_BIT | F_BIT /* Undefined Instruction Mode */ ldr sp, =__stack_und_end msr CPSR_c, #ARM_MODE_ABORT | I_BIT | F_BIT /* Abort Mode */ ldr sp, =__stack_abt_end msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT /* FIQ Mode */ ldr sp, =__stack_fiq_end msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT /* IRQ Mode */ ldr sp, =__stack_irq_end msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT /* Supervisor Mode */ ldr sp, =__stack_svc_end /* * Clear .bss section */ ldr r1, =__bss_start ldr r2, =__bss_end ldr r3, =0 bss_clear_loop: cmp r1, r2 strne r3, [r1], #+4 bne bss_clear_loop /* * Jump to main */ mrs r0, cpsr bic r0, r0, #I_BIT | F_BIT /* Enable FIQ and IRQ interrupt */ msr cpsr, r0 mov r0, #0 /* No arguments */ mov r1, #0 /* No arguments */ ldr r2, =main mov lr, pc bx r2 /* And jump... */ ExitFunction: nop nop nop b ExitFunction /****************************************************************************/ /* Default interrupt handler */ /****************************************************************************/ UndefHandler: b UndefHandler SWIHandler: b SWIHandler PAbortHandler: b PAbortHandler DAbortHandler: b DAbortHandler IRQHandler: b IRQHandler FIQHandler: b FIQHandler .weak ExitFunction .weak UndefHandler, PAbortHandler, DAbortHandler .weak IRQHandler, FIQHandler .ltorg /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710JtagSpeed/src/main.c ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial ****************************************************************************/ #define __MAIN_C__ /* * I use the include only, to show * how to setup a include dir in the makefile */ #include "typedefs.h" /*=========================================================================*/ /* DEFINE: All Structures and Common Constants */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Prototypes */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Definition of all local Data */ /*=========================================================================*/ static const BYTE ConstArray1[128*1024] = {1}; static const BYTE ConstArray2[128*1024] = {2}; static const BYTE ConstArray3[128*1024] = {3}; /*=========================================================================*/ /* DEFINE: Definition of all local Procedures */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: All code exported */ /*=========================================================================*/ /***************************************************************************/ /* main */ /***************************************************************************/ int main (void) { DWORD a = 1; DWORD b = 2; DWORD c = 0; while (1) { a++; b++; c = a + b; } /* * This return here make no sense. * But to prevent the compiler warning: * "return type of 'main' is not 'int' * we use an int as return :-) */ return(0); } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710JtagSpeed/test.hex ================================================ :02000004620098 :1000000018F09FE518F09FE518F09FE518F09FE5C0 :1000100018F09FE518F09FE518F09FE518F09FE5B0 :100020004000006214010062180100621C010062BD :10003000200100620000000024010062280100622B :100040000000A0E10000A0E10000A0E10000A0E1AC :100050000000A0E10000A0E10000A0E10000A0E19C :100060000A02A0E3C0109FE5501080E50A02A0E359 :100070000010A0E3441080E50A02A0E30010A0E312 :100080000A02A0E37310A0E3181080E5081090E5C1 :10009000020011E3FCFFFF0A0A02A0E38C109FE5B7 :1000A000081080E5DBF021E384D09FE5D7F021E361 :1000B00080D09FE5D1F021E37CD09FE5D2F021E311 :1000C00078D09FE5D3F021E374D09FE574109FE5CD :1000D00074209FE50030A0E3020051E10430811458 :1000E000FCFFFF1A00000FE1C000C0E300F029E1AF :1000F0000000A0E30010A0E350209FE50FE0A0E186 :1001000012FF2FE10000A0E10000A0E10000A0E14B :10011000FBFFFFEAFEFFFFEAFEFFFFEAFEFFFFEA4A :10012000FEFFFFEAFEFFFFEAFEFFFFEAC20100005A :1001300009800000000606620005066200030662F0 :1001400000040662000A06629C0106629C010662C7 :10015000540100620CD04DE20130A0E300308DE587 :100160000230A0E304308DE50030A0E308308DE5D7 :1001700000309DE5013083E200308DE504309DE5DF :10018000013083E204308DE500209DE504309DE5DB :10019000033082E008308DE5F4FFFFEA0100000043 :1001A000000000000000000000000000000000004F :1001B000000000000000000000000000000000003F :1001C000000000000000000000000000000000002F :1001D000000000000000000000000000000000001F :1001E000000000000000000000000000000000000F :1001F00000000000000000000000000000000000FF :1002000000000000000000000000000000000000EE :1002100000000000000000000000000000000000DE :1002200000000000000000000000000000000000CE :1002300000000000000000000000000000000000BE :1002400000000000000000000000000000000000AE :10025000000000000000000000000000000000009E :10026000000000000000000000000000000000008E :10027000000000000000000000000000000000007E :10028000000000000000000000000000000000006E :10029000000000000000000000000000000000005E :1002A000000000000000000000000000000000004E :1002B000000000000000000000000000000000003E :1002C000000000000000000000000000000000002E :1002D000000000000000000000000000000000001E :1002E000000000000000000000000000000000000E :1002F00000000000000000000000000000000000FE :1003000000000000000000000000000000000000ED :1003100000000000000000000000000000000000DD :1003200000000000000000000000000000000000CD :1003300000000000000000000000000000000000BD :1003400000000000000000000000000000000000AD :10035000000000000000000000000000000000009D :10036000000000000000000000000000000000008D :10037000000000000000000000000000000000007D :10038000000000000000000000000000000000006D :10039000000000000000000000000000000000005D :1003A000000000000000000000000000000000004D :1003B000000000000000000000000000000000003D :1003C000000000000000000000000000000000002D :1003D000000000000000000000000000000000001D :1003E000000000000000000000000000000000000D :1003F00000000000000000000000000000000000FD :1004000000000000000000000000000000000000EC :1004100000000000000000000000000000000000DC :1004200000000000000000000000000000000000CC :1004300000000000000000000000000000000000BC :1004400000000000000000000000000000000000AC :10045000000000000000000000000000000000009C :10046000000000000000000000000000000000008C :10047000000000000000000000000000000000007C :10048000000000000000000000000000000000006C :10049000000000000000000000000000000000005C :1004A000000000000000000000000000000000004C :1004B000000000000000000000000000000000003C :1004C000000000000000000000000000000000002C :1004D000000000000000000000000000000000001C :1004E000000000000000000000000000000000000C :1004F00000000000000000000000000000000000FC :1005000000000000000000000000000000000000EB :1005100000000000000000000000000000000000DB :1005200000000000000000000000000000000000CB :1005300000000000000000000000000000000000BB :1005400000000000000000000000000000000000AB :10055000000000000000000000000000000000009B :10056000000000000000000000000000000000008B :10057000000000000000000000000000000000007B :10058000000000000000000000000000000000006B :10059000000000000000000000000000000000005B :1005A000000000000000000000000000000000004B :1005B000000000000000000000000000000000003B :1005C000000000000000000000000000000000002B :1005D000000000000000000000000000000000001B :1005E000000000000000000000000000000000000B :1005F00000000000000000000000000000000000FB :1006000000000000000000000000000000000000EA :1006100000000000000000000000000000000000DA :1006200000000000000000000000000000000000CA :1006300000000000000000000000000000000000BA :1006400000000000000000000000000000000000AA :10065000000000000000000000000000000000009A :10066000000000000000000000000000000000008A :10067000000000000000000000000000000000007A :10068000000000000000000000000000000000006A :10069000000000000000000000000000000000005A :1006A000000000000000000000000000000000004A :1006B000000000000000000000000000000000003A :1006C000000000000000000000000000000000002A :1006D000000000000000000000000000000000001A :1006E000000000000000000000000000000000000A :1006F00000000000000000000000000000000000FA :1007000000000000000000000000000000000000E9 :1007100000000000000000000000000000000000D9 :1007200000000000000000000000000000000000C9 :1007300000000000000000000000000000000000B9 :1007400000000000000000000000000000000000A9 :100750000000000000000000000000000000000099 :100760000000000000000000000000000000000089 :100770000000000000000000000000000000000079 :100780000000000000000000000000000000000069 :100790000000000000000000000000000000000059 :1007A0000000000000000000000000000000000049 :1007B0000000000000000000000000000000000039 :1007C0000000000000000000000000000000000029 :1007D0000000000000000000000000000000000019 :1007E0000000000000000000000000000000000009 :1007F00000000000000000000000000000000000F9 :1008000000000000000000000000000000000000E8 :1008100000000000000000000000000000000000D8 :1008200000000000000000000000000000000000C8 :1008300000000000000000000000000000000000B8 :1008400000000000000000000000000000000000A8 :100850000000000000000000000000000000000098 :100860000000000000000000000000000000000088 :100870000000000000000000000000000000000078 :100880000000000000000000000000000000000068 :100890000000000000000000000000000000000058 :1008A0000000000000000000000000000000000048 :1008B0000000000000000000000000000000000038 :1008C0000000000000000000000000000000000028 :1008D0000000000000000000000000000000000018 :1008E0000000000000000000000000000000000008 :1008F00000000000000000000000000000000000F8 :1009000000000000000000000000000000000000E7 :1009100000000000000000000000000000000000D7 :1009200000000000000000000000000000000000C7 :1009300000000000000000000000000000000000B7 :1009400000000000000000000000000000000000A7 :100950000000000000000000000000000000000097 :100960000000000000000000000000000000000087 :100970000000000000000000000000000000000077 :100980000000000000000000000000000000000067 :100990000000000000000000000000000000000057 :1009A0000000000000000000000000000000000047 :1009B0000000000000000000000000000000000037 :1009C0000000000000000000000000000000000027 :1009D0000000000000000000000000000000000017 :1009E0000000000000000000000000000000000007 :1009F00000000000000000000000000000000000F7 :100A000000000000000000000000000000000000E6 :100A100000000000000000000000000000000000D6 :100A200000000000000000000000000000000000C6 :100A300000000000000000000000000000000000B6 :100A400000000000000000000000000000000000A6 :100A50000000000000000000000000000000000096 :100A60000000000000000000000000000000000086 :100A70000000000000000000000000000000000076 :100A80000000000000000000000000000000000066 :100A90000000000000000000000000000000000056 :100AA0000000000000000000000000000000000046 :100AB0000000000000000000000000000000000036 :100AC0000000000000000000000000000000000026 :100AD0000000000000000000000000000000000016 :100AE0000000000000000000000000000000000006 :100AF00000000000000000000000000000000000F6 :100B000000000000000000000000000000000000E5 :100B100000000000000000000000000000000000D5 :100B200000000000000000000000000000000000C5 :100B300000000000000000000000000000000000B5 :100B400000000000000000000000000000000000A5 :100B50000000000000000000000000000000000095 :100B60000000000000000000000000000000000085 :100B70000000000000000000000000000000000075 :100B80000000000000000000000000000000000065 :100B90000000000000000000000000000000000055 :100BA0000000000000000000000000000000000045 :100BB0000000000000000000000000000000000035 :100BC0000000000000000000000000000000000025 :100BD0000000000000000000000000000000000015 :100BE0000000000000000000000000000000000005 :100BF00000000000000000000000000000000000F5 :100C000000000000000000000000000000000000E4 :100C100000000000000000000000000000000000D4 :100C200000000000000000000000000000000000C4 :100C300000000000000000000000000000000000B4 :100C400000000000000000000000000000000000A4 :100C50000000000000000000000000000000000094 :100C60000000000000000000000000000000000084 :100C70000000000000000000000000000000000074 :100C80000000000000000000000000000000000064 :100C90000000000000000000000000000000000054 :100CA0000000000000000000000000000000000044 :100CB0000000000000000000000000000000000034 :100CC0000000000000000000000000000000000024 :100CD0000000000000000000000000000000000014 :100CE0000000000000000000000000000000000004 :100CF00000000000000000000000000000000000F4 :100D000000000000000000000000000000000000E3 :100D100000000000000000000000000000000000D3 :100D200000000000000000000000000000000000C3 :100D300000000000000000000000000000000000B3 :100D400000000000000000000000000000000000A3 :100D50000000000000000000000000000000000093 :100D60000000000000000000000000000000000083 :100D70000000000000000000000000000000000073 :100D80000000000000000000000000000000000063 :100D90000000000000000000000000000000000053 :100DA0000000000000000000000000000000000043 :100DB0000000000000000000000000000000000033 :100DC0000000000000000000000000000000000023 :100DD0000000000000000000000000000000000013 :100DE0000000000000000000000000000000000003 :100DF00000000000000000000000000000000000F3 :100E000000000000000000000000000000000000E2 :100E100000000000000000000000000000000000D2 :100E200000000000000000000000000000000000C2 :100E300000000000000000000000000000000000B2 :100E400000000000000000000000000000000000A2 :100E50000000000000000000000000000000000092 :100E60000000000000000000000000000000000082 :100E70000000000000000000000000000000000072 :100E80000000000000000000000000000000000062 :100E90000000000000000000000000000000000052 :100EA0000000000000000000000000000000000042 :100EB0000000000000000000000000000000000032 :100EC0000000000000000000000000000000000022 :100ED0000000000000000000000000000000000012 :100EE0000000000000000000000000000000000002 :100EF00000000000000000000000000000000000F2 :100F000000000000000000000000000000000000E1 :100F100000000000000000000000000000000000D1 :100F200000000000000000000000000000000000C1 :100F300000000000000000000000000000000000B1 :100F400000000000000000000000000000000000A1 :100F50000000000000000000000000000000000091 :100F60000000000000000000000000000000000081 :100F70000000000000000000000000000000000071 :100F80000000000000000000000000000000000061 :100F90000000000000000000000000000000000051 :100FA0000000000000000000000000000000000041 :100FB0000000000000000000000000000000000031 :100FC0000000000000000000000000000000000021 :100FD0000000000000000000000000000000000011 :100FE0000000000000000000000000000000000001 :100FF00000000000000000000000000000000000F1 :1010000000000000000000000000000000000000E0 :1010100000000000000000000000000000000000D0 :1010200000000000000000000000000000000000C0 :1010300000000000000000000000000000000000B0 :1010400000000000000000000000000000000000A0 :101050000000000000000000000000000000000090 :101060000000000000000000000000000000000080 :101070000000000000000000000000000000000070 :101080000000000000000000000000000000000060 :101090000000000000000000000000000000000050 :1010A0000000000000000000000000000000000040 :1010B0000000000000000000000000000000000030 :1010C0000000000000000000000000000000000020 :1010D0000000000000000000000000000000000010 :1010E0000000000000000000000000000000000000 :1010F00000000000000000000000000000000000F0 :1011000000000000000000000000000000000000DF :1011100000000000000000000000000000000000CF :1011200000000000000000000000000000000000BF :1011300000000000000000000000000000000000AF :10114000000000000000000000000000000000009F :10115000000000000000000000000000000000008F :10116000000000000000000000000000000000007F :10117000000000000000000000000000000000006F :10118000000000000000000000000000000000005F :10119000000000000000000000000000000000004F :1011A000000000000000000000000000000000003F :1011B000000000000000000000000000000000002F :1011C000000000000000000000000000000000001F :1011D000000000000000000000000000000000000F :1011E00000000000000000000000000000000000FF :1011F00000000000000000000000000000000000EF :1012000000000000000000000000000000000000DE :1012100000000000000000000000000000000000CE :1012200000000000000000000000000000000000BE :1012300000000000000000000000000000000000AE :10124000000000000000000000000000000000009E :10125000000000000000000000000000000000008E :10126000000000000000000000000000000000007E :10127000000000000000000000000000000000006E :10128000000000000000000000000000000000005E :10129000000000000000000000000000000000004E :1012A000000000000000000000000000000000003E :1012B000000000000000000000000000000000002E :1012C000000000000000000000000000000000001E :1012D000000000000000000000000000000000000E :1012E00000000000000000000000000000000000FE :1012F00000000000000000000000000000000000EE :1013000000000000000000000000000000000000DD :1013100000000000000000000000000000000000CD :1013200000000000000000000000000000000000BD :1013300000000000000000000000000000000000AD :10134000000000000000000000000000000000009D :10135000000000000000000000000000000000008D :10136000000000000000000000000000000000007D :10137000000000000000000000000000000000006D :10138000000000000000000000000000000000005D :10139000000000000000000000000000000000004D :1013A000000000000000000000000000000000003D :1013B000000000000000000000000000000000002D :1013C000000000000000000000000000000000001D :1013D000000000000000000000000000000000000D :1013E00000000000000000000000000000000000FD :1013F00000000000000000000000000000000000ED :1014000000000000000000000000000000000000DC :1014100000000000000000000000000000000000CC :1014200000000000000000000000000000000000BC :1014300000000000000000000000000000000000AC :10144000000000000000000000000000000000009C :10145000000000000000000000000000000000008C :10146000000000000000000000000000000000007C :10147000000000000000000000000000000000006C :10148000000000000000000000000000000000005C :10149000000000000000000000000000000000004C :1014A000000000000000000000000000000000003C :1014B000000000000000000000000000000000002C :1014C000000000000000000000000000000000001C :1014D000000000000000000000000000000000000C :1014E00000000000000000000000000000000000FC :1014F00000000000000000000000000000000000EC :1015000000000000000000000000000000000000DB :1015100000000000000000000000000000000000CB :1015200000000000000000000000000000000000BB :1015300000000000000000000000000000000000AB :10154000000000000000000000000000000000009B :10155000000000000000000000000000000000008B :10156000000000000000000000000000000000007B :10157000000000000000000000000000000000006B :10158000000000000000000000000000000000005B :10159000000000000000000000000000000000004B :1015A000000000000000000000000000000000003B :1015B000000000000000000000000000000000002B :1015C000000000000000000000000000000000001B :1015D000000000000000000000000000000000000B :1015E00000000000000000000000000000000000FB :1015F00000000000000000000000000000000000EB :1016000000000000000000000000000000000000DA :1016100000000000000000000000000000000000CA :1016200000000000000000000000000000000000BA :1016300000000000000000000000000000000000AA :10164000000000000000000000000000000000009A :10165000000000000000000000000000000000008A :10166000000000000000000000000000000000007A :10167000000000000000000000000000000000006A :10168000000000000000000000000000000000005A :10169000000000000000000000000000000000004A :1016A000000000000000000000000000000000003A :1016B000000000000000000000000000000000002A :1016C000000000000000000000000000000000001A :1016D000000000000000000000000000000000000A :1016E00000000000000000000000000000000000FA :1016F00000000000000000000000000000000000EA :1017000000000000000000000000000000000000D9 :1017100000000000000000000000000000000000C9 :1017200000000000000000000000000000000000B9 :1017300000000000000000000000000000000000A9 :101740000000000000000000000000000000000099 :101750000000000000000000000000000000000089 :101760000000000000000000000000000000000079 :101770000000000000000000000000000000000069 :101780000000000000000000000000000000000059 :101790000000000000000000000000000000000049 :1017A0000000000000000000000000000000000039 :1017B0000000000000000000000000000000000029 :1017C0000000000000000000000000000000000019 :1017D0000000000000000000000000000000000009 :1017E00000000000000000000000000000000000F9 :1017F00000000000000000000000000000000000E9 :1018000000000000000000000000000000000000D8 :1018100000000000000000000000000000000000C8 :1018200000000000000000000000000000000000B8 :1018300000000000000000000000000000000000A8 :101840000000000000000000000000000000000098 :101850000000000000000000000000000000000088 :101860000000000000000000000000000000000078 :101870000000000000000000000000000000000068 :101880000000000000000000000000000000000058 :101890000000000000000000000000000000000048 :1018A0000000000000000000000000000000000038 :1018B0000000000000000000000000000000000028 :1018C0000000000000000000000000000000000018 :1018D0000000000000000000000000000000000008 :1018E00000000000000000000000000000000000F8 :1018F00000000000000000000000000000000000E8 :1019000000000000000000000000000000000000D7 :1019100000000000000000000000000000000000C7 :1019200000000000000000000000000000000000B7 :1019300000000000000000000000000000000000A7 :101940000000000000000000000000000000000097 :101950000000000000000000000000000000000087 :101960000000000000000000000000000000000077 :101970000000000000000000000000000000000067 :101980000000000000000000000000000000000057 :101990000000000000000000000000000000000047 :1019A0000000000000000000000000000000000037 :1019B0000000000000000000000000000000000027 :1019C0000000000000000000000000000000000017 :1019D0000000000000000000000000000000000007 :1019E00000000000000000000000000000000000F7 :1019F00000000000000000000000000000000000E7 :101A000000000000000000000000000000000000D6 :101A100000000000000000000000000000000000C6 :101A200000000000000000000000000000000000B6 :101A300000000000000000000000000000000000A6 :101A40000000000000000000000000000000000096 :101A50000000000000000000000000000000000086 :101A60000000000000000000000000000000000076 :101A70000000000000000000000000000000000066 :101A80000000000000000000000000000000000056 :101A90000000000000000000000000000000000046 :101AA0000000000000000000000000000000000036 :101AB0000000000000000000000000000000000026 :101AC0000000000000000000000000000000000016 :101AD0000000000000000000000000000000000006 :101AE00000000000000000000000000000000000F6 :101AF00000000000000000000000000000000000E6 :101B000000000000000000000000000000000000D5 :101B100000000000000000000000000000000000C5 :101B200000000000000000000000000000000000B5 :101B300000000000000000000000000000000000A5 :101B40000000000000000000000000000000000095 :101B50000000000000000000000000000000000085 :101B60000000000000000000000000000000000075 :101B70000000000000000000000000000000000065 :101B80000000000000000000000000000000000055 :101B90000000000000000000000000000000000045 :101BA0000000000000000000000000000000000035 :101BB0000000000000000000000000000000000025 :101BC0000000000000000000000000000000000015 :101BD0000000000000000000000000000000000005 :101BE00000000000000000000000000000000000F5 :101BF00000000000000000000000000000000000E5 :101C000000000000000000000000000000000000D4 :101C100000000000000000000000000000000000C4 :101C200000000000000000000000000000000000B4 :101C300000000000000000000000000000000000A4 :101C40000000000000000000000000000000000094 :101C50000000000000000000000000000000000084 :101C60000000000000000000000000000000000074 :101C70000000000000000000000000000000000064 :101C80000000000000000000000000000000000054 :101C90000000000000000000000000000000000044 :101CA0000000000000000000000000000000000034 :101CB0000000000000000000000000000000000024 :101CC0000000000000000000000000000000000014 :101CD0000000000000000000000000000000000004 :101CE00000000000000000000000000000000000F4 :101CF00000000000000000000000000000000000E4 :101D000000000000000000000000000000000000D3 :101D100000000000000000000000000000000000C3 :101D200000000000000000000000000000000000B3 :101D300000000000000000000000000000000000A3 :101D40000000000000000000000000000000000093 :101D50000000000000000000000000000000000083 :101D60000000000000000000000000000000000073 :101D70000000000000000000000000000000000063 :101D80000000000000000000000000000000000053 :101D90000000000000000000000000000000000043 :101DA0000000000000000000000000000000000033 :101DB0000000000000000000000000000000000023 :101DC0000000000000000000000000000000000013 :101DD0000000000000000000000000000000000003 :101DE00000000000000000000000000000000000F3 :101DF00000000000000000000000000000000000E3 :101E000000000000000000000000000000000000D2 :101E100000000000000000000000000000000000C2 :101E200000000000000000000000000000000000B2 :101E300000000000000000000000000000000000A2 :101E40000000000000000000000000000000000092 :101E50000000000000000000000000000000000082 :101E60000000000000000000000000000000000072 :101E70000000000000000000000000000000000062 :101E80000000000000000000000000000000000052 :101E90000000000000000000000000000000000042 :101EA0000000000000000000000000000000000032 :101EB0000000000000000000000000000000000022 :101EC0000000000000000000000000000000000012 :101ED0000000000000000000000000000000000002 :101EE00000000000000000000000000000000000F2 :101EF00000000000000000000000000000000000E2 :101F000000000000000000000000000000000000D1 :101F100000000000000000000000000000000000C1 :101F200000000000000000000000000000000000B1 :101F300000000000000000000000000000000000A1 :101F40000000000000000000000000000000000091 :101F50000000000000000000000000000000000081 :101F60000000000000000000000000000000000071 :101F70000000000000000000000000000000000061 :101F80000000000000000000000000000000000051 :101F90000000000000000000000000000000000041 :101FA0000000000000000000000000000000000031 :101FB0000000000000000000000000000000000021 :101FC0000000000000000000000000000000000011 :101FD0000000000000000000000000000000000001 :101FE00000000000000000000000000000000000F1 :101FF00000000000000000000000000000000000E1 :1020000000000000000000000000000000000000D0 :1020100000000000000000000000000000000000C0 :1020200000000000000000000000000000000000B0 :1020300000000000000000000000000000000000A0 :102040000000000000000000000000000000000090 :102050000000000000000000000000000000000080 :102060000000000000000000000000000000000070 :102070000000000000000000000000000000000060 :102080000000000000000000000000000000000050 :102090000000000000000000000000000000000040 :1020A0000000000000000000000000000000000030 :1020B0000000000000000000000000000000000020 :1020C0000000000000000000000000000000000010 :1020D0000000000000000000000000000000000000 :1020E00000000000000000000000000000000000F0 :1020F00000000000000000000000000000000000E0 :1021000000000000000000000000000000000000CF :1021100000000000000000000000000000000000BF :1021200000000000000000000000000000000000AF :10213000000000000000000000000000000000009F :10214000000000000000000000000000000000008F :10215000000000000000000000000000000000007F :10216000000000000000000000000000000000006F :10217000000000000000000000000000000000005F :10218000000000000000000000000000000000004F :10219000000000000000000000000000000000003F :1021A000000000000000000000000000000000002F :1021B000000000000000000000000000000000001F :1021C000000000000000000000000000000000000F :1021D00000000000000000000000000000000000FF :1021E00000000000000000000000000000000000EF :1021F00000000000000000000000000000000000DF :1022000000000000000000000000000000000000CE :1022100000000000000000000000000000000000BE :1022200000000000000000000000000000000000AE :10223000000000000000000000000000000000009E :10224000000000000000000000000000000000008E :10225000000000000000000000000000000000007E :10226000000000000000000000000000000000006E :10227000000000000000000000000000000000005E :10228000000000000000000000000000000000004E :10229000000000000000000000000000000000003E :1022A000000000000000000000000000000000002E :1022B000000000000000000000000000000000001E :1022C000000000000000000000000000000000000E :1022D00000000000000000000000000000000000FE :1022E00000000000000000000000000000000000EE :1022F00000000000000000000000000000000000DE :1023000000000000000000000000000000000000CD :1023100000000000000000000000000000000000BD :1023200000000000000000000000000000000000AD :10233000000000000000000000000000000000009D :10234000000000000000000000000000000000008D :10235000000000000000000000000000000000007D :10236000000000000000000000000000000000006D :10237000000000000000000000000000000000005D :10238000000000000000000000000000000000004D :10239000000000000000000000000000000000003D :1023A000000000000000000000000000000000002D :1023B000000000000000000000000000000000001D :1023C000000000000000000000000000000000000D :1023D00000000000000000000000000000000000FD :1023E00000000000000000000000000000000000ED :1023F00000000000000000000000000000000000DD :1024000000000000000000000000000000000000CC :1024100000000000000000000000000000000000BC :1024200000000000000000000000000000000000AC :10243000000000000000000000000000000000009C :10244000000000000000000000000000000000008C :10245000000000000000000000000000000000007C :10246000000000000000000000000000000000006C :10247000000000000000000000000000000000005C :10248000000000000000000000000000000000004C :10249000000000000000000000000000000000003C :1024A000000000000000000000000000000000002C :1024B000000000000000000000000000000000001C :1024C000000000000000000000000000000000000C :1024D00000000000000000000000000000000000FC :1024E00000000000000000000000000000000000EC :1024F00000000000000000000000000000000000DC :1025000000000000000000000000000000000000CB :1025100000000000000000000000000000000000BB :1025200000000000000000000000000000000000AB :10253000000000000000000000000000000000009B :10254000000000000000000000000000000000008B :10255000000000000000000000000000000000007B :10256000000000000000000000000000000000006B :10257000000000000000000000000000000000005B :10258000000000000000000000000000000000004B :10259000000000000000000000000000000000003B :1025A000000000000000000000000000000000002B :1025B000000000000000000000000000000000001B :1025C000000000000000000000000000000000000B :1025D00000000000000000000000000000000000FB :1025E00000000000000000000000000000000000EB :1025F00000000000000000000000000000000000DB :1026000000000000000000000000000000000000CA :1026100000000000000000000000000000000000BA :1026200000000000000000000000000000000000AA :10263000000000000000000000000000000000009A :10264000000000000000000000000000000000008A :10265000000000000000000000000000000000007A :10266000000000000000000000000000000000006A :10267000000000000000000000000000000000005A :10268000000000000000000000000000000000004A :10269000000000000000000000000000000000003A :1026A000000000000000000000000000000000002A :1026B000000000000000000000000000000000001A :1026C000000000000000000000000000000000000A :1026D00000000000000000000000000000000000FA :1026E00000000000000000000000000000000000EA :1026F00000000000000000000000000000000000DA :1027000000000000000000000000000000000000C9 :1027100000000000000000000000000000000000B9 :1027200000000000000000000000000000000000A9 :102730000000000000000000000000000000000099 :102740000000000000000000000000000000000089 :102750000000000000000000000000000000000079 :102760000000000000000000000000000000000069 :102770000000000000000000000000000000000059 :102780000000000000000000000000000000000049 :102790000000000000000000000000000000000039 :1027A0000000000000000000000000000000000029 :1027B0000000000000000000000000000000000019 :1027C0000000000000000000000000000000000009 :1027D00000000000000000000000000000000000F9 :1027E00000000000000000000000000000000000E9 :1027F00000000000000000000000000000000000D9 :1028000000000000000000000000000000000000C8 :1028100000000000000000000000000000000000B8 :1028200000000000000000000000000000000000A8 :102830000000000000000000000000000000000098 :102840000000000000000000000000000000000088 :102850000000000000000000000000000000000078 :102860000000000000000000000000000000000068 :102870000000000000000000000000000000000058 :102880000000000000000000000000000000000048 :102890000000000000000000000000000000000038 :1028A0000000000000000000000000000000000028 :1028B0000000000000000000000000000000000018 :1028C0000000000000000000000000000000000008 :1028D00000000000000000000000000000000000F8 :1028E00000000000000000000000000000000000E8 :1028F00000000000000000000000000000000000D8 :1029000000000000000000000000000000000000C7 :1029100000000000000000000000000000000000B7 :1029200000000000000000000000000000000000A7 :102930000000000000000000000000000000000097 :102940000000000000000000000000000000000087 :102950000000000000000000000000000000000077 :102960000000000000000000000000000000000067 :102970000000000000000000000000000000000057 :102980000000000000000000000000000000000047 :102990000000000000000000000000000000000037 :1029A0000000000000000000000000000000000027 :1029B0000000000000000000000000000000000017 :1029C0000000000000000000000000000000000007 :1029D00000000000000000000000000000000000F7 :1029E00000000000000000000000000000000000E7 :1029F00000000000000000000000000000000000D7 :102A000000000000000000000000000000000000C6 :102A100000000000000000000000000000000000B6 :102A200000000000000000000000000000000000A6 :102A30000000000000000000000000000000000096 :102A40000000000000000000000000000000000086 :102A50000000000000000000000000000000000076 :102A60000000000000000000000000000000000066 :102A70000000000000000000000000000000000056 :102A80000000000000000000000000000000000046 :102A90000000000000000000000000000000000036 :102AA0000000000000000000000000000000000026 :102AB0000000000000000000000000000000000016 :102AC0000000000000000000000000000000000006 :102AD00000000000000000000000000000000000F6 :102AE00000000000000000000000000000000000E6 :102AF00000000000000000000000000000000000D6 :102B000000000000000000000000000000000000C5 :102B100000000000000000000000000000000000B5 :102B200000000000000000000000000000000000A5 :102B30000000000000000000000000000000000095 :102B40000000000000000000000000000000000085 :102B50000000000000000000000000000000000075 :102B60000000000000000000000000000000000065 :102B70000000000000000000000000000000000055 :102B80000000000000000000000000000000000045 :102B90000000000000000000000000000000000035 :102BA0000000000000000000000000000000000025 :102BB0000000000000000000000000000000000015 :102BC0000000000000000000000000000000000005 :102BD00000000000000000000000000000000000F5 :102BE00000000000000000000000000000000000E5 :102BF00000000000000000000000000000000000D5 :102C000000000000000000000000000000000000C4 :102C100000000000000000000000000000000000B4 :102C200000000000000000000000000000000000A4 :102C30000000000000000000000000000000000094 :102C40000000000000000000000000000000000084 :102C50000000000000000000000000000000000074 :102C60000000000000000000000000000000000064 :102C70000000000000000000000000000000000054 :102C80000000000000000000000000000000000044 :102C90000000000000000000000000000000000034 :102CA0000000000000000000000000000000000024 :102CB0000000000000000000000000000000000014 :102CC0000000000000000000000000000000000004 :102CD00000000000000000000000000000000000F4 :102CE00000000000000000000000000000000000E4 :102CF00000000000000000000000000000000000D4 :102D000000000000000000000000000000000000C3 :102D100000000000000000000000000000000000B3 :102D200000000000000000000000000000000000A3 :102D30000000000000000000000000000000000093 :102D40000000000000000000000000000000000083 :102D50000000000000000000000000000000000073 :102D60000000000000000000000000000000000063 :102D70000000000000000000000000000000000053 :102D80000000000000000000000000000000000043 :102D90000000000000000000000000000000000033 :102DA0000000000000000000000000000000000023 :102DB0000000000000000000000000000000000013 :102DC0000000000000000000000000000000000003 :102DD00000000000000000000000000000000000F3 :102DE00000000000000000000000000000000000E3 :102DF00000000000000000000000000000000000D3 :102E000000000000000000000000000000000000C2 :102E100000000000000000000000000000000000B2 :102E200000000000000000000000000000000000A2 :102E30000000000000000000000000000000000092 :102E40000000000000000000000000000000000082 :102E50000000000000000000000000000000000072 :102E60000000000000000000000000000000000062 :102E70000000000000000000000000000000000052 :102E80000000000000000000000000000000000042 :102E90000000000000000000000000000000000032 :102EA0000000000000000000000000000000000022 :102EB0000000000000000000000000000000000012 :102EC0000000000000000000000000000000000002 :102ED00000000000000000000000000000000000F2 :102EE00000000000000000000000000000000000E2 :102EF00000000000000000000000000000000000D2 :102F000000000000000000000000000000000000C1 :102F100000000000000000000000000000000000B1 :102F200000000000000000000000000000000000A1 :102F30000000000000000000000000000000000091 :102F40000000000000000000000000000000000081 :102F50000000000000000000000000000000000071 :102F60000000000000000000000000000000000061 :102F70000000000000000000000000000000000051 :102F80000000000000000000000000000000000041 :102F90000000000000000000000000000000000031 :102FA0000000000000000000000000000000000021 :102FB0000000000000000000000000000000000011 :102FC0000000000000000000000000000000000001 :102FD00000000000000000000000000000000000F1 :102FE00000000000000000000000000000000000E1 :102FF00000000000000000000000000000000000D1 :1030000000000000000000000000000000000000C0 :1030100000000000000000000000000000000000B0 :1030200000000000000000000000000000000000A0 :103030000000000000000000000000000000000090 :103040000000000000000000000000000000000080 :103050000000000000000000000000000000000070 :103060000000000000000000000000000000000060 :103070000000000000000000000000000000000050 :103080000000000000000000000000000000000040 :103090000000000000000000000000000000000030 :1030A0000000000000000000000000000000000020 :1030B0000000000000000000000000000000000010 :1030C0000000000000000000000000000000000000 :1030D00000000000000000000000000000000000F0 :1030E00000000000000000000000000000000000E0 :1030F00000000000000000000000000000000000D0 :1031000000000000000000000000000000000000BF :1031100000000000000000000000000000000000AF :10312000000000000000000000000000000000009F :10313000000000000000000000000000000000008F :10314000000000000000000000000000000000007F :10315000000000000000000000000000000000006F :10316000000000000000000000000000000000005F :10317000000000000000000000000000000000004F :10318000000000000000000000000000000000003F :10319000000000000000000000000000000000002F :1031A000000000000000000000000000000000001F :1031B000000000000000000000000000000000000F :1031C00000000000000000000000000000000000FF :1031D00000000000000000000000000000000000EF :1031E00000000000000000000000000000000000DF :1031F00000000000000000000000000000000000CF :1032000000000000000000000000000000000000BE :1032100000000000000000000000000000000000AE :10322000000000000000000000000000000000009E :10323000000000000000000000000000000000008E :10324000000000000000000000000000000000007E :10325000000000000000000000000000000000006E :10326000000000000000000000000000000000005E :10327000000000000000000000000000000000004E :10328000000000000000000000000000000000003E :10329000000000000000000000000000000000002E :1032A000000000000000000000000000000000001E :1032B000000000000000000000000000000000000E :1032C00000000000000000000000000000000000FE :1032D00000000000000000000000000000000000EE :1032E00000000000000000000000000000000000DE :1032F00000000000000000000000000000000000CE :1033000000000000000000000000000000000000BD :1033100000000000000000000000000000000000AD :10332000000000000000000000000000000000009D :10333000000000000000000000000000000000008D :10334000000000000000000000000000000000007D :10335000000000000000000000000000000000006D :10336000000000000000000000000000000000005D :10337000000000000000000000000000000000004D :10338000000000000000000000000000000000003D :10339000000000000000000000000000000000002D :1033A000000000000000000000000000000000001D :1033B000000000000000000000000000000000000D :1033C00000000000000000000000000000000000FD :1033D00000000000000000000000000000000000ED :1033E00000000000000000000000000000000000DD :1033F00000000000000000000000000000000000CD :1034000000000000000000000000000000000000BC :1034100000000000000000000000000000000000AC :10342000000000000000000000000000000000009C :10343000000000000000000000000000000000008C :10344000000000000000000000000000000000007C :10345000000000000000000000000000000000006C :10346000000000000000000000000000000000005C :10347000000000000000000000000000000000004C :10348000000000000000000000000000000000003C :10349000000000000000000000000000000000002C :1034A000000000000000000000000000000000001C :1034B000000000000000000000000000000000000C :1034C00000000000000000000000000000000000FC :1034D00000000000000000000000000000000000EC :1034E00000000000000000000000000000000000DC :1034F00000000000000000000000000000000000CC :1035000000000000000000000000000000000000BB :1035100000000000000000000000000000000000AB :10352000000000000000000000000000000000009B :10353000000000000000000000000000000000008B :10354000000000000000000000000000000000007B :10355000000000000000000000000000000000006B :10356000000000000000000000000000000000005B :10357000000000000000000000000000000000004B :10358000000000000000000000000000000000003B :10359000000000000000000000000000000000002B :1035A000000000000000000000000000000000001B :1035B000000000000000000000000000000000000B :1035C00000000000000000000000000000000000FB :1035D00000000000000000000000000000000000EB :1035E00000000000000000000000000000000000DB :1035F00000000000000000000000000000000000CB :1036000000000000000000000000000000000000BA :1036100000000000000000000000000000000000AA :10362000000000000000000000000000000000009A :10363000000000000000000000000000000000008A :10364000000000000000000000000000000000007A :10365000000000000000000000000000000000006A :10366000000000000000000000000000000000005A :10367000000000000000000000000000000000004A :10368000000000000000000000000000000000003A :10369000000000000000000000000000000000002A :1036A000000000000000000000000000000000001A :1036B000000000000000000000000000000000000A :1036C00000000000000000000000000000000000FA :1036D00000000000000000000000000000000000EA :1036E00000000000000000000000000000000000DA :1036F00000000000000000000000000000000000CA :1037000000000000000000000000000000000000B9 :1037100000000000000000000000000000000000A9 :103720000000000000000000000000000000000099 :103730000000000000000000000000000000000089 :103740000000000000000000000000000000000079 :103750000000000000000000000000000000000069 :103760000000000000000000000000000000000059 :103770000000000000000000000000000000000049 :103780000000000000000000000000000000000039 :103790000000000000000000000000000000000029 :1037A0000000000000000000000000000000000019 :1037B0000000000000000000000000000000000009 :1037C00000000000000000000000000000000000F9 :1037D00000000000000000000000000000000000E9 :1037E00000000000000000000000000000000000D9 :1037F00000000000000000000000000000000000C9 :1038000000000000000000000000000000000000B8 :1038100000000000000000000000000000000000A8 :103820000000000000000000000000000000000098 :103830000000000000000000000000000000000088 :103840000000000000000000000000000000000078 :103850000000000000000000000000000000000068 :103860000000000000000000000000000000000058 :103870000000000000000000000000000000000048 :103880000000000000000000000000000000000038 :103890000000000000000000000000000000000028 :1038A0000000000000000000000000000000000018 :1038B0000000000000000000000000000000000008 :1038C00000000000000000000000000000000000F8 :1038D00000000000000000000000000000000000E8 :1038E00000000000000000000000000000000000D8 :1038F00000000000000000000000000000000000C8 :1039000000000000000000000000000000000000B7 :1039100000000000000000000000000000000000A7 :103920000000000000000000000000000000000097 :103930000000000000000000000000000000000087 :103940000000000000000000000000000000000077 :103950000000000000000000000000000000000067 :103960000000000000000000000000000000000057 :103970000000000000000000000000000000000047 :103980000000000000000000000000000000000037 :103990000000000000000000000000000000000027 :1039A0000000000000000000000000000000000017 :1039B0000000000000000000000000000000000007 :1039C00000000000000000000000000000000000F7 :1039D00000000000000000000000000000000000E7 :1039E00000000000000000000000000000000000D7 :1039F00000000000000000000000000000000000C7 :103A000000000000000000000000000000000000B6 :103A100000000000000000000000000000000000A6 :103A20000000000000000000000000000000000096 :103A30000000000000000000000000000000000086 :103A40000000000000000000000000000000000076 :103A50000000000000000000000000000000000066 :103A60000000000000000000000000000000000056 :103A70000000000000000000000000000000000046 :103A80000000000000000000000000000000000036 :103A90000000000000000000000000000000000026 :103AA0000000000000000000000000000000000016 :103AB0000000000000000000000000000000000006 :103AC00000000000000000000000000000000000F6 :103AD00000000000000000000000000000000000E6 :103AE00000000000000000000000000000000000D6 :103AF00000000000000000000000000000000000C6 :103B000000000000000000000000000000000000B5 :103B100000000000000000000000000000000000A5 :103B20000000000000000000000000000000000095 :103B30000000000000000000000000000000000085 :103B40000000000000000000000000000000000075 :103B50000000000000000000000000000000000065 :103B60000000000000000000000000000000000055 :103B70000000000000000000000000000000000045 :103B80000000000000000000000000000000000035 :103B90000000000000000000000000000000000025 :103BA0000000000000000000000000000000000015 :103BB0000000000000000000000000000000000005 :103BC00000000000000000000000000000000000F5 :103BD00000000000000000000000000000000000E5 :103BE00000000000000000000000000000000000D5 :103BF00000000000000000000000000000000000C5 :103C000000000000000000000000000000000000B4 :103C100000000000000000000000000000000000A4 :103C20000000000000000000000000000000000094 :103C30000000000000000000000000000000000084 :103C40000000000000000000000000000000000074 :103C50000000000000000000000000000000000064 :103C60000000000000000000000000000000000054 :103C70000000000000000000000000000000000044 :103C80000000000000000000000000000000000034 :103C90000000000000000000000000000000000024 :103CA0000000000000000000000000000000000014 :103CB0000000000000000000000000000000000004 :103CC00000000000000000000000000000000000F4 :103CD00000000000000000000000000000000000E4 :103CE00000000000000000000000000000000000D4 :103CF00000000000000000000000000000000000C4 :103D000000000000000000000000000000000000B3 :103D100000000000000000000000000000000000A3 :103D20000000000000000000000000000000000093 :103D30000000000000000000000000000000000083 :103D40000000000000000000000000000000000073 :103D50000000000000000000000000000000000063 :103D60000000000000000000000000000000000053 :103D70000000000000000000000000000000000043 :103D80000000000000000000000000000000000033 :103D90000000000000000000000000000000000023 :103DA0000000000000000000000000000000000013 :103DB0000000000000000000000000000000000003 :103DC00000000000000000000000000000000000F3 :103DD00000000000000000000000000000000000E3 :103DE00000000000000000000000000000000000D3 :103DF00000000000000000000000000000000000C3 :103E000000000000000000000000000000000000B2 :103E100000000000000000000000000000000000A2 :103E20000000000000000000000000000000000092 :103E30000000000000000000000000000000000082 :103E40000000000000000000000000000000000072 :103E50000000000000000000000000000000000062 :103E60000000000000000000000000000000000052 :103E70000000000000000000000000000000000042 :103E80000000000000000000000000000000000032 :103E90000000000000000000000000000000000022 :103EA0000000000000000000000000000000000012 :103EB0000000000000000000000000000000000002 :103EC00000000000000000000000000000000000F2 :103ED00000000000000000000000000000000000E2 :103EE00000000000000000000000000000000000D2 :103EF00000000000000000000000000000000000C2 :103F000000000000000000000000000000000000B1 :103F100000000000000000000000000000000000A1 :103F20000000000000000000000000000000000091 :103F30000000000000000000000000000000000081 :103F40000000000000000000000000000000000071 :103F50000000000000000000000000000000000061 :103F60000000000000000000000000000000000051 :103F70000000000000000000000000000000000041 :103F80000000000000000000000000000000000031 :103F90000000000000000000000000000000000021 :103FA0000000000000000000000000000000000011 :103FB0000000000000000000000000000000000001 :103FC00000000000000000000000000000000000F1 :103FD00000000000000000000000000000000000E1 :103FE00000000000000000000000000000000000D1 :103FF00000000000000000000000000000000000C1 :1040000000000000000000000000000000000000B0 :1040100000000000000000000000000000000000A0 :104020000000000000000000000000000000000090 :104030000000000000000000000000000000000080 :104040000000000000000000000000000000000070 :104050000000000000000000000000000000000060 :104060000000000000000000000000000000000050 :104070000000000000000000000000000000000040 :104080000000000000000000000000000000000030 :104090000000000000000000000000000000000020 :1040A0000000000000000000000000000000000010 :1040B0000000000000000000000000000000000000 :1040C00000000000000000000000000000000000F0 :1040D00000000000000000000000000000000000E0 :1040E00000000000000000000000000000000000D0 :1040F00000000000000000000000000000000000C0 :1041000000000000000000000000000000000000AF :10411000000000000000000000000000000000009F :10412000000000000000000000000000000000008F :10413000000000000000000000000000000000007F :10414000000000000000000000000000000000006F :10415000000000000000000000000000000000005F :10416000000000000000000000000000000000004F :10417000000000000000000000000000000000003F :10418000000000000000000000000000000000002F :10419000000000000000000000000000000000001F :1041A000000000000000000000000000000000000F :1041B00000000000000000000000000000000000FF :1041C00000000000000000000000000000000000EF :1041D00000000000000000000000000000000000DF :1041E00000000000000000000000000000000000CF :1041F00000000000000000000000000000000000BF :1042000000000000000000000000000000000000AE :10421000000000000000000000000000000000009E :10422000000000000000000000000000000000008E :10423000000000000000000000000000000000007E :10424000000000000000000000000000000000006E :10425000000000000000000000000000000000005E :10426000000000000000000000000000000000004E :10427000000000000000000000000000000000003E :10428000000000000000000000000000000000002E :10429000000000000000000000000000000000001E :1042A000000000000000000000000000000000000E :1042B00000000000000000000000000000000000FE :1042C00000000000000000000000000000000000EE :1042D00000000000000000000000000000000000DE :1042E00000000000000000000000000000000000CE :1042F00000000000000000000000000000000000BE :1043000000000000000000000000000000000000AD :10431000000000000000000000000000000000009D :10432000000000000000000000000000000000008D :10433000000000000000000000000000000000007D :10434000000000000000000000000000000000006D :10435000000000000000000000000000000000005D :10436000000000000000000000000000000000004D :10437000000000000000000000000000000000003D :10438000000000000000000000000000000000002D :10439000000000000000000000000000000000001D :1043A000000000000000000000000000000000000D :1043B00000000000000000000000000000000000FD :1043C00000000000000000000000000000000000ED :1043D00000000000000000000000000000000000DD :1043E00000000000000000000000000000000000CD :1043F00000000000000000000000000000000000BD :1044000000000000000000000000000000000000AC :10441000000000000000000000000000000000009C :10442000000000000000000000000000000000008C :10443000000000000000000000000000000000007C :10444000000000000000000000000000000000006C :10445000000000000000000000000000000000005C :10446000000000000000000000000000000000004C :10447000000000000000000000000000000000003C :10448000000000000000000000000000000000002C :10449000000000000000000000000000000000001C :1044A000000000000000000000000000000000000C :1044B00000000000000000000000000000000000FC :1044C00000000000000000000000000000000000EC :1044D00000000000000000000000000000000000DC :1044E00000000000000000000000000000000000CC :1044F00000000000000000000000000000000000BC :1045000000000000000000000000000000000000AB :10451000000000000000000000000000000000009B :10452000000000000000000000000000000000008B :10453000000000000000000000000000000000007B :10454000000000000000000000000000000000006B :10455000000000000000000000000000000000005B :10456000000000000000000000000000000000004B :10457000000000000000000000000000000000003B :10458000000000000000000000000000000000002B :10459000000000000000000000000000000000001B :1045A000000000000000000000000000000000000B :1045B00000000000000000000000000000000000FB :1045C00000000000000000000000000000000000EB :1045D00000000000000000000000000000000000DB :1045E00000000000000000000000000000000000CB :1045F00000000000000000000000000000000000BB :1046000000000000000000000000000000000000AA :10461000000000000000000000000000000000009A :10462000000000000000000000000000000000008A :10463000000000000000000000000000000000007A :10464000000000000000000000000000000000006A :10465000000000000000000000000000000000005A :10466000000000000000000000000000000000004A :10467000000000000000000000000000000000003A :10468000000000000000000000000000000000002A :10469000000000000000000000000000000000001A :1046A000000000000000000000000000000000000A :1046B00000000000000000000000000000000000FA :1046C00000000000000000000000000000000000EA :1046D00000000000000000000000000000000000DA :1046E00000000000000000000000000000000000CA :1046F00000000000000000000000000000000000BA :1047000000000000000000000000000000000000A9 :104710000000000000000000000000000000000099 :104720000000000000000000000000000000000089 :104730000000000000000000000000000000000079 :104740000000000000000000000000000000000069 :104750000000000000000000000000000000000059 :104760000000000000000000000000000000000049 :104770000000000000000000000000000000000039 :104780000000000000000000000000000000000029 :104790000000000000000000000000000000000019 :1047A0000000000000000000000000000000000009 :1047B00000000000000000000000000000000000F9 :1047C00000000000000000000000000000000000E9 :1047D00000000000000000000000000000000000D9 :1047E00000000000000000000000000000000000C9 :1047F00000000000000000000000000000000000B9 :1048000000000000000000000000000000000000A8 :104810000000000000000000000000000000000098 :104820000000000000000000000000000000000088 :104830000000000000000000000000000000000078 :104840000000000000000000000000000000000068 :104850000000000000000000000000000000000058 :104860000000000000000000000000000000000048 :104870000000000000000000000000000000000038 :104880000000000000000000000000000000000028 :104890000000000000000000000000000000000018 :1048A0000000000000000000000000000000000008 :1048B00000000000000000000000000000000000F8 :1048C00000000000000000000000000000000000E8 :1048D00000000000000000000000000000000000D8 :1048E00000000000000000000000000000000000C8 :1048F00000000000000000000000000000000000B8 :1049000000000000000000000000000000000000A7 :104910000000000000000000000000000000000097 :104920000000000000000000000000000000000087 :104930000000000000000000000000000000000077 :104940000000000000000000000000000000000067 :104950000000000000000000000000000000000057 :104960000000000000000000000000000000000047 :104970000000000000000000000000000000000037 :104980000000000000000000000000000000000027 :104990000000000000000000000000000000000017 :1049A0000000000000000000000000000000000007 :1049B00000000000000000000000000000000000F7 :1049C00000000000000000000000000000000000E7 :1049D00000000000000000000000000000000000D7 :1049E00000000000000000000000000000000000C7 :1049F00000000000000000000000000000000000B7 :104A000000000000000000000000000000000000A6 :104A10000000000000000000000000000000000096 :104A20000000000000000000000000000000000086 :104A30000000000000000000000000000000000076 :104A40000000000000000000000000000000000066 :104A50000000000000000000000000000000000056 :104A60000000000000000000000000000000000046 :104A70000000000000000000000000000000000036 :104A80000000000000000000000000000000000026 :104A90000000000000000000000000000000000016 :104AA0000000000000000000000000000000000006 :104AB00000000000000000000000000000000000F6 :104AC00000000000000000000000000000000000E6 :104AD00000000000000000000000000000000000D6 :104AE00000000000000000000000000000000000C6 :104AF00000000000000000000000000000000000B6 :104B000000000000000000000000000000000000A5 :104B10000000000000000000000000000000000095 :104B20000000000000000000000000000000000085 :104B30000000000000000000000000000000000075 :104B40000000000000000000000000000000000065 :104B50000000000000000000000000000000000055 :104B60000000000000000000000000000000000045 :104B70000000000000000000000000000000000035 :104B80000000000000000000000000000000000025 :104B90000000000000000000000000000000000015 :104BA0000000000000000000000000000000000005 :104BB00000000000000000000000000000000000F5 :104BC00000000000000000000000000000000000E5 :104BD00000000000000000000000000000000000D5 :104BE00000000000000000000000000000000000C5 :104BF00000000000000000000000000000000000B5 :104C000000000000000000000000000000000000A4 :104C10000000000000000000000000000000000094 :104C20000000000000000000000000000000000084 :104C30000000000000000000000000000000000074 :104C40000000000000000000000000000000000064 :104C50000000000000000000000000000000000054 :104C60000000000000000000000000000000000044 :104C70000000000000000000000000000000000034 :104C80000000000000000000000000000000000024 :104C90000000000000000000000000000000000014 :104CA0000000000000000000000000000000000004 :104CB00000000000000000000000000000000000F4 :104CC00000000000000000000000000000000000E4 :104CD00000000000000000000000000000000000D4 :104CE00000000000000000000000000000000000C4 :104CF00000000000000000000000000000000000B4 :104D000000000000000000000000000000000000A3 :104D10000000000000000000000000000000000093 :104D20000000000000000000000000000000000083 :104D30000000000000000000000000000000000073 :104D40000000000000000000000000000000000063 :104D50000000000000000000000000000000000053 :104D60000000000000000000000000000000000043 :104D70000000000000000000000000000000000033 :104D80000000000000000000000000000000000023 :104D90000000000000000000000000000000000013 :104DA0000000000000000000000000000000000003 :104DB00000000000000000000000000000000000F3 :104DC00000000000000000000000000000000000E3 :104DD00000000000000000000000000000000000D3 :104DE00000000000000000000000000000000000C3 :104DF00000000000000000000000000000000000B3 :104E000000000000000000000000000000000000A2 :104E10000000000000000000000000000000000092 :104E20000000000000000000000000000000000082 :104E30000000000000000000000000000000000072 :104E40000000000000000000000000000000000062 :104E50000000000000000000000000000000000052 :104E60000000000000000000000000000000000042 :104E70000000000000000000000000000000000032 :104E80000000000000000000000000000000000022 :104E90000000000000000000000000000000000012 :104EA0000000000000000000000000000000000002 :104EB00000000000000000000000000000000000F2 :104EC00000000000000000000000000000000000E2 :104ED00000000000000000000000000000000000D2 :104EE00000000000000000000000000000000000C2 :104EF00000000000000000000000000000000000B2 :104F000000000000000000000000000000000000A1 :104F10000000000000000000000000000000000091 :104F20000000000000000000000000000000000081 :104F30000000000000000000000000000000000071 :104F40000000000000000000000000000000000061 :104F50000000000000000000000000000000000051 :104F60000000000000000000000000000000000041 :104F70000000000000000000000000000000000031 :104F80000000000000000000000000000000000021 :104F90000000000000000000000000000000000011 :104FA0000000000000000000000000000000000001 :104FB00000000000000000000000000000000000F1 :104FC00000000000000000000000000000000000E1 :104FD00000000000000000000000000000000000D1 :104FE00000000000000000000000000000000000C1 :104FF00000000000000000000000000000000000B1 :1050000000000000000000000000000000000000A0 :105010000000000000000000000000000000000090 :105020000000000000000000000000000000000080 :105030000000000000000000000000000000000070 :105040000000000000000000000000000000000060 :105050000000000000000000000000000000000050 :105060000000000000000000000000000000000040 :105070000000000000000000000000000000000030 :105080000000000000000000000000000000000020 :105090000000000000000000000000000000000010 :1050A0000000000000000000000000000000000000 :1050B00000000000000000000000000000000000F0 :1050C00000000000000000000000000000000000E0 :1050D00000000000000000000000000000000000D0 :1050E00000000000000000000000000000000000C0 :1050F00000000000000000000000000000000000B0 :10510000000000000000000000000000000000009F :10511000000000000000000000000000000000008F :10512000000000000000000000000000000000007F :10513000000000000000000000000000000000006F :10514000000000000000000000000000000000005F :10515000000000000000000000000000000000004F :10516000000000000000000000000000000000003F :10517000000000000000000000000000000000002F :10518000000000000000000000000000000000001F :10519000000000000000000000000000000000000F :1051A00000000000000000000000000000000000FF :1051B00000000000000000000000000000000000EF :1051C00000000000000000000000000000000000DF :1051D00000000000000000000000000000000000CF :1051E00000000000000000000000000000000000BF :1051F00000000000000000000000000000000000AF :10520000000000000000000000000000000000009E :10521000000000000000000000000000000000008E :10522000000000000000000000000000000000007E :10523000000000000000000000000000000000006E :10524000000000000000000000000000000000005E :10525000000000000000000000000000000000004E :10526000000000000000000000000000000000003E :10527000000000000000000000000000000000002E :10528000000000000000000000000000000000001E :10529000000000000000000000000000000000000E :1052A00000000000000000000000000000000000FE :1052B00000000000000000000000000000000000EE :1052C00000000000000000000000000000000000DE :1052D00000000000000000000000000000000000CE :1052E00000000000000000000000000000000000BE :1052F00000000000000000000000000000000000AE :10530000000000000000000000000000000000009D :10531000000000000000000000000000000000008D :10532000000000000000000000000000000000007D :10533000000000000000000000000000000000006D :10534000000000000000000000000000000000005D :10535000000000000000000000000000000000004D :10536000000000000000000000000000000000003D :10537000000000000000000000000000000000002D :10538000000000000000000000000000000000001D :10539000000000000000000000000000000000000D :1053A00000000000000000000000000000000000FD :1053B00000000000000000000000000000000000ED :1053C00000000000000000000000000000000000DD :1053D00000000000000000000000000000000000CD :1053E00000000000000000000000000000000000BD :1053F00000000000000000000000000000000000AD :10540000000000000000000000000000000000009C :10541000000000000000000000000000000000008C :10542000000000000000000000000000000000007C :10543000000000000000000000000000000000006C :10544000000000000000000000000000000000005C :10545000000000000000000000000000000000004C :10546000000000000000000000000000000000003C :10547000000000000000000000000000000000002C :10548000000000000000000000000000000000001C :10549000000000000000000000000000000000000C :1054A00000000000000000000000000000000000FC :1054B00000000000000000000000000000000000EC :1054C00000000000000000000000000000000000DC :1054D00000000000000000000000000000000000CC :1054E00000000000000000000000000000000000BC :1054F00000000000000000000000000000000000AC :10550000000000000000000000000000000000009B :10551000000000000000000000000000000000008B :10552000000000000000000000000000000000007B :10553000000000000000000000000000000000006B :10554000000000000000000000000000000000005B :10555000000000000000000000000000000000004B :10556000000000000000000000000000000000003B :10557000000000000000000000000000000000002B :10558000000000000000000000000000000000001B :10559000000000000000000000000000000000000B :1055A00000000000000000000000000000000000FB :1055B00000000000000000000000000000000000EB :1055C00000000000000000000000000000000000DB :1055D00000000000000000000000000000000000CB :1055E00000000000000000000000000000000000BB :1055F00000000000000000000000000000000000AB :10560000000000000000000000000000000000009A :10561000000000000000000000000000000000008A :10562000000000000000000000000000000000007A :10563000000000000000000000000000000000006A :10564000000000000000000000000000000000005A :10565000000000000000000000000000000000004A :10566000000000000000000000000000000000003A :10567000000000000000000000000000000000002A :10568000000000000000000000000000000000001A :10569000000000000000000000000000000000000A :1056A00000000000000000000000000000000000FA :1056B00000000000000000000000000000000000EA :1056C00000000000000000000000000000000000DA :1056D00000000000000000000000000000000000CA :1056E00000000000000000000000000000000000BA :1056F00000000000000000000000000000000000AA :105700000000000000000000000000000000000099 :105710000000000000000000000000000000000089 :105720000000000000000000000000000000000079 :105730000000000000000000000000000000000069 :105740000000000000000000000000000000000059 :105750000000000000000000000000000000000049 :105760000000000000000000000000000000000039 :105770000000000000000000000000000000000029 :105780000000000000000000000000000000000019 :105790000000000000000000000000000000000009 :1057A00000000000000000000000000000000000F9 :1057B00000000000000000000000000000000000E9 :1057C00000000000000000000000000000000000D9 :1057D00000000000000000000000000000000000C9 :1057E00000000000000000000000000000000000B9 :1057F00000000000000000000000000000000000A9 :105800000000000000000000000000000000000098 :105810000000000000000000000000000000000088 :105820000000000000000000000000000000000078 :105830000000000000000000000000000000000068 :105840000000000000000000000000000000000058 :105850000000000000000000000000000000000048 :105860000000000000000000000000000000000038 :105870000000000000000000000000000000000028 :105880000000000000000000000000000000000018 :105890000000000000000000000000000000000008 :1058A00000000000000000000000000000000000F8 :1058B00000000000000000000000000000000000E8 :1058C00000000000000000000000000000000000D8 :1058D00000000000000000000000000000000000C8 :1058E00000000000000000000000000000000000B8 :1058F00000000000000000000000000000000000A8 :105900000000000000000000000000000000000097 :105910000000000000000000000000000000000087 :105920000000000000000000000000000000000077 :105930000000000000000000000000000000000067 :105940000000000000000000000000000000000057 :105950000000000000000000000000000000000047 :105960000000000000000000000000000000000037 :105970000000000000000000000000000000000027 :105980000000000000000000000000000000000017 :105990000000000000000000000000000000000007 :1059A00000000000000000000000000000000000F7 :1059B00000000000000000000000000000000000E7 :1059C00000000000000000000000000000000000D7 :1059D00000000000000000000000000000000000C7 :1059E00000000000000000000000000000000000B7 :1059F00000000000000000000000000000000000A7 :105A00000000000000000000000000000000000096 :105A10000000000000000000000000000000000086 :105A20000000000000000000000000000000000076 :105A30000000000000000000000000000000000066 :105A40000000000000000000000000000000000056 :105A50000000000000000000000000000000000046 :105A60000000000000000000000000000000000036 :105A70000000000000000000000000000000000026 :105A80000000000000000000000000000000000016 :105A90000000000000000000000000000000000006 :105AA00000000000000000000000000000000000F6 :105AB00000000000000000000000000000000000E6 :105AC00000000000000000000000000000000000D6 :105AD00000000000000000000000000000000000C6 :105AE00000000000000000000000000000000000B6 :105AF00000000000000000000000000000000000A6 :105B00000000000000000000000000000000000095 :105B10000000000000000000000000000000000085 :105B20000000000000000000000000000000000075 :105B30000000000000000000000000000000000065 :105B40000000000000000000000000000000000055 :105B50000000000000000000000000000000000045 :105B60000000000000000000000000000000000035 :105B70000000000000000000000000000000000025 :105B80000000000000000000000000000000000015 :105B90000000000000000000000000000000000005 :105BA00000000000000000000000000000000000F5 :105BB00000000000000000000000000000000000E5 :105BC00000000000000000000000000000000000D5 :105BD00000000000000000000000000000000000C5 :105BE00000000000000000000000000000000000B5 :105BF00000000000000000000000000000000000A5 :105C00000000000000000000000000000000000094 :105C10000000000000000000000000000000000084 :105C20000000000000000000000000000000000074 :105C30000000000000000000000000000000000064 :105C40000000000000000000000000000000000054 :105C50000000000000000000000000000000000044 :105C60000000000000000000000000000000000034 :105C70000000000000000000000000000000000024 :105C80000000000000000000000000000000000014 :105C90000000000000000000000000000000000004 :105CA00000000000000000000000000000000000F4 :105CB00000000000000000000000000000000000E4 :105CC00000000000000000000000000000000000D4 :105CD00000000000000000000000000000000000C4 :105CE00000000000000000000000000000000000B4 :105CF00000000000000000000000000000000000A4 :105D00000000000000000000000000000000000093 :105D10000000000000000000000000000000000083 :105D20000000000000000000000000000000000073 :105D30000000000000000000000000000000000063 :105D40000000000000000000000000000000000053 :105D50000000000000000000000000000000000043 :105D60000000000000000000000000000000000033 :105D70000000000000000000000000000000000023 :105D80000000000000000000000000000000000013 :105D90000000000000000000000000000000000003 :105DA00000000000000000000000000000000000F3 :105DB00000000000000000000000000000000000E3 :105DC00000000000000000000000000000000000D3 :105DD00000000000000000000000000000000000C3 :105DE00000000000000000000000000000000000B3 :105DF00000000000000000000000000000000000A3 :105E00000000000000000000000000000000000092 :105E10000000000000000000000000000000000082 :105E20000000000000000000000000000000000072 :105E30000000000000000000000000000000000062 :105E40000000000000000000000000000000000052 :105E50000000000000000000000000000000000042 :105E60000000000000000000000000000000000032 :105E70000000000000000000000000000000000022 :105E80000000000000000000000000000000000012 :105E90000000000000000000000000000000000002 :105EA00000000000000000000000000000000000F2 :105EB00000000000000000000000000000000000E2 :105EC00000000000000000000000000000000000D2 :105ED00000000000000000000000000000000000C2 :105EE00000000000000000000000000000000000B2 :105EF00000000000000000000000000000000000A2 :105F00000000000000000000000000000000000091 :105F10000000000000000000000000000000000081 :105F20000000000000000000000000000000000071 :105F30000000000000000000000000000000000061 :105F40000000000000000000000000000000000051 :105F50000000000000000000000000000000000041 :105F60000000000000000000000000000000000031 :105F70000000000000000000000000000000000021 :105F80000000000000000000000000000000000011 :105F90000000000000000000000000000000000001 :105FA00000000000000000000000000000000000F1 :105FB00000000000000000000000000000000000E1 :105FC00000000000000000000000000000000000D1 :105FD00000000000000000000000000000000000C1 :105FE00000000000000000000000000000000000B1 :105FF00000000000000000000000000000000000A1 :106000000000000000000000000000000000000090 :106010000000000000000000000000000000000080 :106020000000000000000000000000000000000070 :106030000000000000000000000000000000000060 :106040000000000000000000000000000000000050 :106050000000000000000000000000000000000040 :106060000000000000000000000000000000000030 :106070000000000000000000000000000000000020 :106080000000000000000000000000000000000010 :106090000000000000000000000000000000000000 :1060A00000000000000000000000000000000000F0 :1060B00000000000000000000000000000000000E0 :1060C00000000000000000000000000000000000D0 :1060D00000000000000000000000000000000000C0 :1060E00000000000000000000000000000000000B0 :1060F00000000000000000000000000000000000A0 :10610000000000000000000000000000000000008F :10611000000000000000000000000000000000007F :10612000000000000000000000000000000000006F :10613000000000000000000000000000000000005F :10614000000000000000000000000000000000004F :10615000000000000000000000000000000000003F :10616000000000000000000000000000000000002F :10617000000000000000000000000000000000001F :10618000000000000000000000000000000000000F :1061900000000000000000000000000000000000FF :1061A00000000000000000000000000000000000EF :1061B00000000000000000000000000000000000DF :1061C00000000000000000000000000000000000CF :1061D00000000000000000000000000000000000BF :1061E00000000000000000000000000000000000AF :1061F000000000000000000000000000000000009F :10620000000000000000000000000000000000008E :10621000000000000000000000000000000000007E :10622000000000000000000000000000000000006E :10623000000000000000000000000000000000005E :10624000000000000000000000000000000000004E :10625000000000000000000000000000000000003E :10626000000000000000000000000000000000002E :10627000000000000000000000000000000000001E :10628000000000000000000000000000000000000E :1062900000000000000000000000000000000000FE :1062A00000000000000000000000000000000000EE :1062B00000000000000000000000000000000000DE :1062C00000000000000000000000000000000000CE :1062D00000000000000000000000000000000000BE :1062E00000000000000000000000000000000000AE :1062F000000000000000000000000000000000009E :10630000000000000000000000000000000000008D :10631000000000000000000000000000000000007D :10632000000000000000000000000000000000006D :10633000000000000000000000000000000000005D :10634000000000000000000000000000000000004D :10635000000000000000000000000000000000003D :10636000000000000000000000000000000000002D :10637000000000000000000000000000000000001D :10638000000000000000000000000000000000000D :1063900000000000000000000000000000000000FD :1063A00000000000000000000000000000000000ED :1063B00000000000000000000000000000000000DD :1063C00000000000000000000000000000000000CD :1063D00000000000000000000000000000000000BD :1063E00000000000000000000000000000000000AD :1063F000000000000000000000000000000000009D :10640000000000000000000000000000000000008C :10641000000000000000000000000000000000007C :10642000000000000000000000000000000000006C :10643000000000000000000000000000000000005C :10644000000000000000000000000000000000004C :10645000000000000000000000000000000000003C :10646000000000000000000000000000000000002C :10647000000000000000000000000000000000001C :10648000000000000000000000000000000000000C :1064900000000000000000000000000000000000FC :1064A00000000000000000000000000000000000EC :1064B00000000000000000000000000000000000DC :1064C00000000000000000000000000000000000CC :1064D00000000000000000000000000000000000BC :1064E00000000000000000000000000000000000AC :1064F000000000000000000000000000000000009C :10650000000000000000000000000000000000008B :10651000000000000000000000000000000000007B :10652000000000000000000000000000000000006B :10653000000000000000000000000000000000005B :10654000000000000000000000000000000000004B :10655000000000000000000000000000000000003B :10656000000000000000000000000000000000002B :10657000000000000000000000000000000000001B :10658000000000000000000000000000000000000B :1065900000000000000000000000000000000000FB :1065A00000000000000000000000000000000000EB :1065B00000000000000000000000000000000000DB :1065C00000000000000000000000000000000000CB :1065D00000000000000000000000000000000000BB :1065E00000000000000000000000000000000000AB :1065F000000000000000000000000000000000009B :10660000000000000000000000000000000000008A :10661000000000000000000000000000000000007A :10662000000000000000000000000000000000006A :10663000000000000000000000000000000000005A :10664000000000000000000000000000000000004A :10665000000000000000000000000000000000003A :10666000000000000000000000000000000000002A :10667000000000000000000000000000000000001A :10668000000000000000000000000000000000000A :1066900000000000000000000000000000000000FA :1066A00000000000000000000000000000000000EA :1066B00000000000000000000000000000000000DA :1066C00000000000000000000000000000000000CA :1066D00000000000000000000000000000000000BA :1066E00000000000000000000000000000000000AA :1066F000000000000000000000000000000000009A :106700000000000000000000000000000000000089 :106710000000000000000000000000000000000079 :106720000000000000000000000000000000000069 :106730000000000000000000000000000000000059 :106740000000000000000000000000000000000049 :106750000000000000000000000000000000000039 :106760000000000000000000000000000000000029 :106770000000000000000000000000000000000019 :106780000000000000000000000000000000000009 :1067900000000000000000000000000000000000F9 :1067A00000000000000000000000000000000000E9 :1067B00000000000000000000000000000000000D9 :1067C00000000000000000000000000000000000C9 :1067D00000000000000000000000000000000000B9 :1067E00000000000000000000000000000000000A9 :1067F0000000000000000000000000000000000099 :106800000000000000000000000000000000000088 :106810000000000000000000000000000000000078 :106820000000000000000000000000000000000068 :106830000000000000000000000000000000000058 :106840000000000000000000000000000000000048 :106850000000000000000000000000000000000038 :106860000000000000000000000000000000000028 :106870000000000000000000000000000000000018 :106880000000000000000000000000000000000008 :1068900000000000000000000000000000000000F8 :1068A00000000000000000000000000000000000E8 :1068B00000000000000000000000000000000000D8 :1068C00000000000000000000000000000000000C8 :1068D00000000000000000000000000000000000B8 :1068E00000000000000000000000000000000000A8 :1068F0000000000000000000000000000000000098 :106900000000000000000000000000000000000087 :106910000000000000000000000000000000000077 :106920000000000000000000000000000000000067 :106930000000000000000000000000000000000057 :106940000000000000000000000000000000000047 :106950000000000000000000000000000000000037 :106960000000000000000000000000000000000027 :106970000000000000000000000000000000000017 :106980000000000000000000000000000000000007 :1069900000000000000000000000000000000000F7 :1069A00000000000000000000000000000000000E7 :1069B00000000000000000000000000000000000D7 :1069C00000000000000000000000000000000000C7 :1069D00000000000000000000000000000000000B7 :1069E00000000000000000000000000000000000A7 :1069F0000000000000000000000000000000000097 :106A00000000000000000000000000000000000086 :106A10000000000000000000000000000000000076 :106A20000000000000000000000000000000000066 :106A30000000000000000000000000000000000056 :106A40000000000000000000000000000000000046 :106A50000000000000000000000000000000000036 :106A60000000000000000000000000000000000026 :106A70000000000000000000000000000000000016 :106A80000000000000000000000000000000000006 :106A900000000000000000000000000000000000F6 :106AA00000000000000000000000000000000000E6 :106AB00000000000000000000000000000000000D6 :106AC00000000000000000000000000000000000C6 :106AD00000000000000000000000000000000000B6 :106AE00000000000000000000000000000000000A6 :106AF0000000000000000000000000000000000096 :106B00000000000000000000000000000000000085 :106B10000000000000000000000000000000000075 :106B20000000000000000000000000000000000065 :106B30000000000000000000000000000000000055 :106B40000000000000000000000000000000000045 :106B50000000000000000000000000000000000035 :106B60000000000000000000000000000000000025 :106B70000000000000000000000000000000000015 :106B80000000000000000000000000000000000005 :106B900000000000000000000000000000000000F5 :106BA00000000000000000000000000000000000E5 :106BB00000000000000000000000000000000000D5 :106BC00000000000000000000000000000000000C5 :106BD00000000000000000000000000000000000B5 :106BE00000000000000000000000000000000000A5 :106BF0000000000000000000000000000000000095 :106C00000000000000000000000000000000000084 :106C10000000000000000000000000000000000074 :106C20000000000000000000000000000000000064 :106C30000000000000000000000000000000000054 :106C40000000000000000000000000000000000044 :106C50000000000000000000000000000000000034 :106C60000000000000000000000000000000000024 :106C70000000000000000000000000000000000014 :106C80000000000000000000000000000000000004 :106C900000000000000000000000000000000000F4 :106CA00000000000000000000000000000000000E4 :106CB00000000000000000000000000000000000D4 :106CC00000000000000000000000000000000000C4 :106CD00000000000000000000000000000000000B4 :106CE00000000000000000000000000000000000A4 :106CF0000000000000000000000000000000000094 :106D00000000000000000000000000000000000083 :106D10000000000000000000000000000000000073 :106D20000000000000000000000000000000000063 :106D30000000000000000000000000000000000053 :106D40000000000000000000000000000000000043 :106D50000000000000000000000000000000000033 :106D60000000000000000000000000000000000023 :106D70000000000000000000000000000000000013 :106D80000000000000000000000000000000000003 :106D900000000000000000000000000000000000F3 :106DA00000000000000000000000000000000000E3 :106DB00000000000000000000000000000000000D3 :106DC00000000000000000000000000000000000C3 :106DD00000000000000000000000000000000000B3 :106DE00000000000000000000000000000000000A3 :106DF0000000000000000000000000000000000093 :106E00000000000000000000000000000000000082 :106E10000000000000000000000000000000000072 :106E20000000000000000000000000000000000062 :106E30000000000000000000000000000000000052 :106E40000000000000000000000000000000000042 :106E50000000000000000000000000000000000032 :106E60000000000000000000000000000000000022 :106E70000000000000000000000000000000000012 :106E80000000000000000000000000000000000002 :106E900000000000000000000000000000000000F2 :106EA00000000000000000000000000000000000E2 :106EB00000000000000000000000000000000000D2 :106EC00000000000000000000000000000000000C2 :106ED00000000000000000000000000000000000B2 :106EE00000000000000000000000000000000000A2 :106EF0000000000000000000000000000000000092 :106F00000000000000000000000000000000000081 :106F10000000000000000000000000000000000071 :106F20000000000000000000000000000000000061 :106F30000000000000000000000000000000000051 :106F40000000000000000000000000000000000041 :106F50000000000000000000000000000000000031 :106F60000000000000000000000000000000000021 :106F70000000000000000000000000000000000011 :106F80000000000000000000000000000000000001 :106F900000000000000000000000000000000000F1 :106FA00000000000000000000000000000000000E1 :106FB00000000000000000000000000000000000D1 :106FC00000000000000000000000000000000000C1 :106FD00000000000000000000000000000000000B1 :106FE00000000000000000000000000000000000A1 :106FF0000000000000000000000000000000000091 :107000000000000000000000000000000000000080 :107010000000000000000000000000000000000070 :107020000000000000000000000000000000000060 :107030000000000000000000000000000000000050 :107040000000000000000000000000000000000040 :107050000000000000000000000000000000000030 :107060000000000000000000000000000000000020 :107070000000000000000000000000000000000010 :107080000000000000000000000000000000000000 :1070900000000000000000000000000000000000F0 :1070A00000000000000000000000000000000000E0 :1070B00000000000000000000000000000000000D0 :1070C00000000000000000000000000000000000C0 :1070D00000000000000000000000000000000000B0 :1070E00000000000000000000000000000000000A0 :1070F0000000000000000000000000000000000090 :10710000000000000000000000000000000000007F :10711000000000000000000000000000000000006F :10712000000000000000000000000000000000005F :10713000000000000000000000000000000000004F :10714000000000000000000000000000000000003F :10715000000000000000000000000000000000002F :10716000000000000000000000000000000000001F :10717000000000000000000000000000000000000F :1071800000000000000000000000000000000000FF :1071900000000000000000000000000000000000EF :1071A00000000000000000000000000000000000DF :1071B00000000000000000000000000000000000CF :1071C00000000000000000000000000000000000BF :1071D00000000000000000000000000000000000AF :1071E000000000000000000000000000000000009F :1071F000000000000000000000000000000000008F :10720000000000000000000000000000000000007E :10721000000000000000000000000000000000006E :10722000000000000000000000000000000000005E :10723000000000000000000000000000000000004E :10724000000000000000000000000000000000003E :10725000000000000000000000000000000000002E :10726000000000000000000000000000000000001E :10727000000000000000000000000000000000000E :1072800000000000000000000000000000000000FE :1072900000000000000000000000000000000000EE :1072A00000000000000000000000000000000000DE :1072B00000000000000000000000000000000000CE :1072C00000000000000000000000000000000000BE :1072D00000000000000000000000000000000000AE :1072E000000000000000000000000000000000009E :1072F000000000000000000000000000000000008E :10730000000000000000000000000000000000007D :10731000000000000000000000000000000000006D :10732000000000000000000000000000000000005D :10733000000000000000000000000000000000004D :10734000000000000000000000000000000000003D :10735000000000000000000000000000000000002D :10736000000000000000000000000000000000001D :10737000000000000000000000000000000000000D :1073800000000000000000000000000000000000FD :1073900000000000000000000000000000000000ED :1073A00000000000000000000000000000000000DD :1073B00000000000000000000000000000000000CD :1073C00000000000000000000000000000000000BD :1073D00000000000000000000000000000000000AD :1073E000000000000000000000000000000000009D :1073F000000000000000000000000000000000008D :10740000000000000000000000000000000000007C :10741000000000000000000000000000000000006C :10742000000000000000000000000000000000005C :10743000000000000000000000000000000000004C :10744000000000000000000000000000000000003C :10745000000000000000000000000000000000002C :10746000000000000000000000000000000000001C :10747000000000000000000000000000000000000C :1074800000000000000000000000000000000000FC :1074900000000000000000000000000000000000EC :1074A00000000000000000000000000000000000DC :1074B00000000000000000000000000000000000CC :1074C00000000000000000000000000000000000BC :1074D00000000000000000000000000000000000AC :1074E000000000000000000000000000000000009C :1074F000000000000000000000000000000000008C :10750000000000000000000000000000000000007B :10751000000000000000000000000000000000006B :10752000000000000000000000000000000000005B :10753000000000000000000000000000000000004B :10754000000000000000000000000000000000003B :10755000000000000000000000000000000000002B :10756000000000000000000000000000000000001B :10757000000000000000000000000000000000000B :1075800000000000000000000000000000000000FB :1075900000000000000000000000000000000000EB :1075A00000000000000000000000000000000000DB :1075B00000000000000000000000000000000000CB :1075C00000000000000000000000000000000000BB :1075D00000000000000000000000000000000000AB :1075E000000000000000000000000000000000009B :1075F000000000000000000000000000000000008B :10760000000000000000000000000000000000007A :10761000000000000000000000000000000000006A :10762000000000000000000000000000000000005A :10763000000000000000000000000000000000004A :10764000000000000000000000000000000000003A :10765000000000000000000000000000000000002A :10766000000000000000000000000000000000001A :10767000000000000000000000000000000000000A :1076800000000000000000000000000000000000FA :1076900000000000000000000000000000000000EA :1076A00000000000000000000000000000000000DA :1076B00000000000000000000000000000000000CA :1076C00000000000000000000000000000000000BA :1076D00000000000000000000000000000000000AA :1076E000000000000000000000000000000000009A :1076F000000000000000000000000000000000008A :107700000000000000000000000000000000000079 :107710000000000000000000000000000000000069 :107720000000000000000000000000000000000059 :107730000000000000000000000000000000000049 :107740000000000000000000000000000000000039 :107750000000000000000000000000000000000029 :107760000000000000000000000000000000000019 :107770000000000000000000000000000000000009 :1077800000000000000000000000000000000000F9 :1077900000000000000000000000000000000000E9 :1077A00000000000000000000000000000000000D9 :1077B00000000000000000000000000000000000C9 :1077C00000000000000000000000000000000000B9 :1077D00000000000000000000000000000000000A9 :1077E0000000000000000000000000000000000099 :1077F0000000000000000000000000000000000089 :107800000000000000000000000000000000000078 :107810000000000000000000000000000000000068 :107820000000000000000000000000000000000058 :107830000000000000000000000000000000000048 :107840000000000000000000000000000000000038 :107850000000000000000000000000000000000028 :107860000000000000000000000000000000000018 :107870000000000000000000000000000000000008 :1078800000000000000000000000000000000000F8 :1078900000000000000000000000000000000000E8 :1078A00000000000000000000000000000000000D8 :1078B00000000000000000000000000000000000C8 :1078C00000000000000000000000000000000000B8 :1078D00000000000000000000000000000000000A8 :1078E0000000000000000000000000000000000098 :1078F0000000000000000000000000000000000088 :107900000000000000000000000000000000000077 :107910000000000000000000000000000000000067 :107920000000000000000000000000000000000057 :107930000000000000000000000000000000000047 :107940000000000000000000000000000000000037 :107950000000000000000000000000000000000027 :107960000000000000000000000000000000000017 :107970000000000000000000000000000000000007 :1079800000000000000000000000000000000000F7 :1079900000000000000000000000000000000000E7 :1079A00000000000000000000000000000000000D7 :1079B00000000000000000000000000000000000C7 :1079C00000000000000000000000000000000000B7 :1079D00000000000000000000000000000000000A7 :1079E0000000000000000000000000000000000097 :1079F0000000000000000000000000000000000087 :107A00000000000000000000000000000000000076 :107A10000000000000000000000000000000000066 :107A20000000000000000000000000000000000056 :107A30000000000000000000000000000000000046 :107A40000000000000000000000000000000000036 :107A50000000000000000000000000000000000026 :107A60000000000000000000000000000000000016 :107A70000000000000000000000000000000000006 :107A800000000000000000000000000000000000F6 :107A900000000000000000000000000000000000E6 :107AA00000000000000000000000000000000000D6 :107AB00000000000000000000000000000000000C6 :107AC00000000000000000000000000000000000B6 :107AD00000000000000000000000000000000000A6 :107AE0000000000000000000000000000000000096 :107AF0000000000000000000000000000000000086 :107B00000000000000000000000000000000000075 :107B10000000000000000000000000000000000065 :107B20000000000000000000000000000000000055 :107B30000000000000000000000000000000000045 :107B40000000000000000000000000000000000035 :107B50000000000000000000000000000000000025 :107B60000000000000000000000000000000000015 :107B70000000000000000000000000000000000005 :107B800000000000000000000000000000000000F5 :107B900000000000000000000000000000000000E5 :107BA00000000000000000000000000000000000D5 :107BB00000000000000000000000000000000000C5 :107BC00000000000000000000000000000000000B5 :107BD00000000000000000000000000000000000A5 :107BE0000000000000000000000000000000000095 :107BF0000000000000000000000000000000000085 :107C00000000000000000000000000000000000074 :107C10000000000000000000000000000000000064 :107C20000000000000000000000000000000000054 :107C30000000000000000000000000000000000044 :107C40000000000000000000000000000000000034 :107C50000000000000000000000000000000000024 :107C60000000000000000000000000000000000014 :107C70000000000000000000000000000000000004 :107C800000000000000000000000000000000000F4 :107C900000000000000000000000000000000000E4 :107CA00000000000000000000000000000000000D4 :107CB00000000000000000000000000000000000C4 :107CC00000000000000000000000000000000000B4 :107CD00000000000000000000000000000000000A4 :107CE0000000000000000000000000000000000094 :107CF0000000000000000000000000000000000084 :107D00000000000000000000000000000000000073 :107D10000000000000000000000000000000000063 :107D20000000000000000000000000000000000053 :107D30000000000000000000000000000000000043 :107D40000000000000000000000000000000000033 :107D50000000000000000000000000000000000023 :107D60000000000000000000000000000000000013 :107D70000000000000000000000000000000000003 :107D800000000000000000000000000000000000F3 :107D900000000000000000000000000000000000E3 :107DA00000000000000000000000000000000000D3 :107DB00000000000000000000000000000000000C3 :107DC00000000000000000000000000000000000B3 :107DD00000000000000000000000000000000000A3 :107DE0000000000000000000000000000000000093 :107DF0000000000000000000000000000000000083 :107E00000000000000000000000000000000000072 :107E10000000000000000000000000000000000062 :107E20000000000000000000000000000000000052 :107E30000000000000000000000000000000000042 :107E40000000000000000000000000000000000032 :107E50000000000000000000000000000000000022 :107E60000000000000000000000000000000000012 :107E70000000000000000000000000000000000002 :107E800000000000000000000000000000000000F2 :107E900000000000000000000000000000000000E2 :107EA00000000000000000000000000000000000D2 :107EB00000000000000000000000000000000000C2 :107EC00000000000000000000000000000000000B2 :107ED00000000000000000000000000000000000A2 :107EE0000000000000000000000000000000000092 :107EF0000000000000000000000000000000000082 :107F00000000000000000000000000000000000071 :107F10000000000000000000000000000000000061 :107F20000000000000000000000000000000000051 :107F30000000000000000000000000000000000041 :107F40000000000000000000000000000000000031 :107F50000000000000000000000000000000000021 :107F60000000000000000000000000000000000011 :107F70000000000000000000000000000000000001 :107F800000000000000000000000000000000000F1 :107F900000000000000000000000000000000000E1 :107FA00000000000000000000000000000000000D1 :107FB00000000000000000000000000000000000C1 :107FC00000000000000000000000000000000000B1 :107FD00000000000000000000000000000000000A1 :107FE0000000000000000000000000000000000091 :107FF0000000000000000000000000000000000081 :108000000000000000000000000000000000000070 :108010000000000000000000000000000000000060 :108020000000000000000000000000000000000050 :108030000000000000000000000000000000000040 :108040000000000000000000000000000000000030 :108050000000000000000000000000000000000020 :108060000000000000000000000000000000000010 :108070000000000000000000000000000000000000 :1080800000000000000000000000000000000000F0 :1080900000000000000000000000000000000000E0 :1080A00000000000000000000000000000000000D0 :1080B00000000000000000000000000000000000C0 :1080C00000000000000000000000000000000000B0 :1080D00000000000000000000000000000000000A0 :1080E0000000000000000000000000000000000090 :1080F0000000000000000000000000000000000080 :10810000000000000000000000000000000000006F :10811000000000000000000000000000000000005F :10812000000000000000000000000000000000004F :10813000000000000000000000000000000000003F :10814000000000000000000000000000000000002F :10815000000000000000000000000000000000001F :10816000000000000000000000000000000000000F :1081700000000000000000000000000000000000FF :1081800000000000000000000000000000000000EF :1081900000000000000000000000000000000000DF :1081A00000000000000000000000000000000000CF :1081B00000000000000000000000000000000000BF :1081C00000000000000000000000000000000000AF :1081D000000000000000000000000000000000009F :1081E000000000000000000000000000000000008F :1081F000000000000000000000000000000000007F :10820000000000000000000000000000000000006E :10821000000000000000000000000000000000005E :10822000000000000000000000000000000000004E :10823000000000000000000000000000000000003E :10824000000000000000000000000000000000002E :10825000000000000000000000000000000000001E :10826000000000000000000000000000000000000E :1082700000000000000000000000000000000000FE :1082800000000000000000000000000000000000EE :1082900000000000000000000000000000000000DE :1082A00000000000000000000000000000000000CE :1082B00000000000000000000000000000000000BE :1082C00000000000000000000000000000000000AE :1082D000000000000000000000000000000000009E :1082E000000000000000000000000000000000008E :1082F000000000000000000000000000000000007E :10830000000000000000000000000000000000006D :10831000000000000000000000000000000000005D :10832000000000000000000000000000000000004D :10833000000000000000000000000000000000003D :10834000000000000000000000000000000000002D :10835000000000000000000000000000000000001D :10836000000000000000000000000000000000000D :1083700000000000000000000000000000000000FD :1083800000000000000000000000000000000000ED :1083900000000000000000000000000000000000DD :1083A00000000000000000000000000000000000CD :1083B00000000000000000000000000000000000BD :1083C00000000000000000000000000000000000AD :1083D000000000000000000000000000000000009D :1083E000000000000000000000000000000000008D :1083F000000000000000000000000000000000007D :10840000000000000000000000000000000000006C :10841000000000000000000000000000000000005C :10842000000000000000000000000000000000004C :10843000000000000000000000000000000000003C :10844000000000000000000000000000000000002C :10845000000000000000000000000000000000001C :10846000000000000000000000000000000000000C :1084700000000000000000000000000000000000FC :1084800000000000000000000000000000000000EC :1084900000000000000000000000000000000000DC :1084A00000000000000000000000000000000000CC :1084B00000000000000000000000000000000000BC :1084C00000000000000000000000000000000000AC :1084D000000000000000000000000000000000009C :1084E000000000000000000000000000000000008C :1084F000000000000000000000000000000000007C :10850000000000000000000000000000000000006B :10851000000000000000000000000000000000005B :10852000000000000000000000000000000000004B :10853000000000000000000000000000000000003B :10854000000000000000000000000000000000002B :10855000000000000000000000000000000000001B :10856000000000000000000000000000000000000B :1085700000000000000000000000000000000000FB :1085800000000000000000000000000000000000EB :1085900000000000000000000000000000000000DB :1085A00000000000000000000000000000000000CB :1085B00000000000000000000000000000000000BB :1085C00000000000000000000000000000000000AB :1085D000000000000000000000000000000000009B :1085E000000000000000000000000000000000008B :1085F000000000000000000000000000000000007B :10860000000000000000000000000000000000006A :10861000000000000000000000000000000000005A :10862000000000000000000000000000000000004A :10863000000000000000000000000000000000003A :10864000000000000000000000000000000000002A :10865000000000000000000000000000000000001A :10866000000000000000000000000000000000000A :1086700000000000000000000000000000000000FA :1086800000000000000000000000000000000000EA :1086900000000000000000000000000000000000DA :1086A00000000000000000000000000000000000CA :1086B00000000000000000000000000000000000BA :1086C00000000000000000000000000000000000AA :1086D000000000000000000000000000000000009A :1086E000000000000000000000000000000000008A :1086F000000000000000000000000000000000007A :108700000000000000000000000000000000000069 :108710000000000000000000000000000000000059 :108720000000000000000000000000000000000049 :108730000000000000000000000000000000000039 :108740000000000000000000000000000000000029 :108750000000000000000000000000000000000019 :108760000000000000000000000000000000000009 :1087700000000000000000000000000000000000F9 :1087800000000000000000000000000000000000E9 :1087900000000000000000000000000000000000D9 :1087A00000000000000000000000000000000000C9 :1087B00000000000000000000000000000000000B9 :1087C00000000000000000000000000000000000A9 :1087D0000000000000000000000000000000000099 :1087E0000000000000000000000000000000000089 :1087F0000000000000000000000000000000000079 :108800000000000000000000000000000000000068 :108810000000000000000000000000000000000058 :108820000000000000000000000000000000000048 :108830000000000000000000000000000000000038 :108840000000000000000000000000000000000028 :108850000000000000000000000000000000000018 :108860000000000000000000000000000000000008 :1088700000000000000000000000000000000000F8 :1088800000000000000000000000000000000000E8 :1088900000000000000000000000000000000000D8 :1088A00000000000000000000000000000000000C8 :1088B00000000000000000000000000000000000B8 :1088C00000000000000000000000000000000000A8 :1088D0000000000000000000000000000000000098 :1088E0000000000000000000000000000000000088 :1088F0000000000000000000000000000000000078 :108900000000000000000000000000000000000067 :108910000000000000000000000000000000000057 :108920000000000000000000000000000000000047 :108930000000000000000000000000000000000037 :108940000000000000000000000000000000000027 :108950000000000000000000000000000000000017 :108960000000000000000000000000000000000007 :1089700000000000000000000000000000000000F7 :1089800000000000000000000000000000000000E7 :1089900000000000000000000000000000000000D7 :1089A00000000000000000000000000000000000C7 :1089B00000000000000000000000000000000000B7 :1089C00000000000000000000000000000000000A7 :1089D0000000000000000000000000000000000097 :1089E0000000000000000000000000000000000087 :1089F0000000000000000000000000000000000077 :108A00000000000000000000000000000000000066 :108A10000000000000000000000000000000000056 :108A20000000000000000000000000000000000046 :108A30000000000000000000000000000000000036 :108A40000000000000000000000000000000000026 :108A50000000000000000000000000000000000016 :108A60000000000000000000000000000000000006 :108A700000000000000000000000000000000000F6 :108A800000000000000000000000000000000000E6 :108A900000000000000000000000000000000000D6 :108AA00000000000000000000000000000000000C6 :108AB00000000000000000000000000000000000B6 :108AC00000000000000000000000000000000000A6 :108AD0000000000000000000000000000000000096 :108AE0000000000000000000000000000000000086 :108AF0000000000000000000000000000000000076 :108B00000000000000000000000000000000000065 :108B10000000000000000000000000000000000055 :108B20000000000000000000000000000000000045 :108B30000000000000000000000000000000000035 :108B40000000000000000000000000000000000025 :108B50000000000000000000000000000000000015 :108B60000000000000000000000000000000000005 :108B700000000000000000000000000000000000F5 :108B800000000000000000000000000000000000E5 :108B900000000000000000000000000000000000D5 :108BA00000000000000000000000000000000000C5 :108BB00000000000000000000000000000000000B5 :108BC00000000000000000000000000000000000A5 :108BD0000000000000000000000000000000000095 :108BE0000000000000000000000000000000000085 :108BF0000000000000000000000000000000000075 :108C00000000000000000000000000000000000064 :108C10000000000000000000000000000000000054 :108C20000000000000000000000000000000000044 :108C30000000000000000000000000000000000034 :108C40000000000000000000000000000000000024 :108C50000000000000000000000000000000000014 :108C60000000000000000000000000000000000004 :108C700000000000000000000000000000000000F4 :108C800000000000000000000000000000000000E4 :108C900000000000000000000000000000000000D4 :108CA00000000000000000000000000000000000C4 :108CB00000000000000000000000000000000000B4 :108CC00000000000000000000000000000000000A4 :108CD0000000000000000000000000000000000094 :108CE0000000000000000000000000000000000084 :108CF0000000000000000000000000000000000074 :108D00000000000000000000000000000000000063 :108D10000000000000000000000000000000000053 :108D20000000000000000000000000000000000043 :108D30000000000000000000000000000000000033 :108D40000000000000000000000000000000000023 :108D50000000000000000000000000000000000013 :108D60000000000000000000000000000000000003 :108D700000000000000000000000000000000000F3 :108D800000000000000000000000000000000000E3 :108D900000000000000000000000000000000000D3 :108DA00000000000000000000000000000000000C3 :108DB00000000000000000000000000000000000B3 :108DC00000000000000000000000000000000000A3 :108DD0000000000000000000000000000000000093 :108DE0000000000000000000000000000000000083 :108DF0000000000000000000000000000000000073 :108E00000000000000000000000000000000000062 :108E10000000000000000000000000000000000052 :108E20000000000000000000000000000000000042 :108E30000000000000000000000000000000000032 :108E40000000000000000000000000000000000022 :108E50000000000000000000000000000000000012 :108E60000000000000000000000000000000000002 :108E700000000000000000000000000000000000F2 :108E800000000000000000000000000000000000E2 :108E900000000000000000000000000000000000D2 :108EA00000000000000000000000000000000000C2 :108EB00000000000000000000000000000000000B2 :108EC00000000000000000000000000000000000A2 :108ED0000000000000000000000000000000000092 :108EE0000000000000000000000000000000000082 :108EF0000000000000000000000000000000000072 :108F00000000000000000000000000000000000061 :108F10000000000000000000000000000000000051 :108F20000000000000000000000000000000000041 :108F30000000000000000000000000000000000031 :108F40000000000000000000000000000000000021 :108F50000000000000000000000000000000000011 :108F60000000000000000000000000000000000001 :108F700000000000000000000000000000000000F1 :108F800000000000000000000000000000000000E1 :108F900000000000000000000000000000000000D1 :108FA00000000000000000000000000000000000C1 :108FB00000000000000000000000000000000000B1 :108FC00000000000000000000000000000000000A1 :108FD0000000000000000000000000000000000091 :108FE0000000000000000000000000000000000081 :108FF0000000000000000000000000000000000071 :109000000000000000000000000000000000000060 :109010000000000000000000000000000000000050 :109020000000000000000000000000000000000040 :109030000000000000000000000000000000000030 :109040000000000000000000000000000000000020 :109050000000000000000000000000000000000010 :109060000000000000000000000000000000000000 :1090700000000000000000000000000000000000F0 :1090800000000000000000000000000000000000E0 :1090900000000000000000000000000000000000D0 :1090A00000000000000000000000000000000000C0 :1090B00000000000000000000000000000000000B0 :1090C00000000000000000000000000000000000A0 :1090D0000000000000000000000000000000000090 :1090E0000000000000000000000000000000000080 :1090F0000000000000000000000000000000000070 :10910000000000000000000000000000000000005F :10911000000000000000000000000000000000004F :10912000000000000000000000000000000000003F :10913000000000000000000000000000000000002F :10914000000000000000000000000000000000001F :10915000000000000000000000000000000000000F :1091600000000000000000000000000000000000FF :1091700000000000000000000000000000000000EF :1091800000000000000000000000000000000000DF :1091900000000000000000000000000000000000CF :1091A00000000000000000000000000000000000BF :1091B00000000000000000000000000000000000AF :1091C000000000000000000000000000000000009F :1091D000000000000000000000000000000000008F :1091E000000000000000000000000000000000007F :1091F000000000000000000000000000000000006F :10920000000000000000000000000000000000005E :10921000000000000000000000000000000000004E :10922000000000000000000000000000000000003E :10923000000000000000000000000000000000002E :10924000000000000000000000000000000000001E :10925000000000000000000000000000000000000E :1092600000000000000000000000000000000000FE :1092700000000000000000000000000000000000EE :1092800000000000000000000000000000000000DE :1092900000000000000000000000000000000000CE :1092A00000000000000000000000000000000000BE :1092B00000000000000000000000000000000000AE :1092C000000000000000000000000000000000009E :1092D000000000000000000000000000000000008E :1092E000000000000000000000000000000000007E :1092F000000000000000000000000000000000006E :10930000000000000000000000000000000000005D :10931000000000000000000000000000000000004D :10932000000000000000000000000000000000003D :10933000000000000000000000000000000000002D :10934000000000000000000000000000000000001D :10935000000000000000000000000000000000000D :1093600000000000000000000000000000000000FD :1093700000000000000000000000000000000000ED :1093800000000000000000000000000000000000DD :1093900000000000000000000000000000000000CD :1093A00000000000000000000000000000000000BD :1093B00000000000000000000000000000000000AD :1093C000000000000000000000000000000000009D :1093D000000000000000000000000000000000008D :1093E000000000000000000000000000000000007D :1093F000000000000000000000000000000000006D :10940000000000000000000000000000000000005C :10941000000000000000000000000000000000004C :10942000000000000000000000000000000000003C :10943000000000000000000000000000000000002C :10944000000000000000000000000000000000001C :10945000000000000000000000000000000000000C :1094600000000000000000000000000000000000FC :1094700000000000000000000000000000000000EC :1094800000000000000000000000000000000000DC :1094900000000000000000000000000000000000CC :1094A00000000000000000000000000000000000BC :1094B00000000000000000000000000000000000AC :1094C000000000000000000000000000000000009C :1094D000000000000000000000000000000000008C :1094E000000000000000000000000000000000007C :1094F000000000000000000000000000000000006C :10950000000000000000000000000000000000005B :10951000000000000000000000000000000000004B :10952000000000000000000000000000000000003B :10953000000000000000000000000000000000002B :10954000000000000000000000000000000000001B :10955000000000000000000000000000000000000B :1095600000000000000000000000000000000000FB :1095700000000000000000000000000000000000EB :1095800000000000000000000000000000000000DB :1095900000000000000000000000000000000000CB :1095A00000000000000000000000000000000000BB :1095B00000000000000000000000000000000000AB :1095C000000000000000000000000000000000009B :1095D000000000000000000000000000000000008B :1095E000000000000000000000000000000000007B :1095F000000000000000000000000000000000006B :10960000000000000000000000000000000000005A :10961000000000000000000000000000000000004A :10962000000000000000000000000000000000003A :10963000000000000000000000000000000000002A :10964000000000000000000000000000000000001A :10965000000000000000000000000000000000000A :1096600000000000000000000000000000000000FA :1096700000000000000000000000000000000000EA :1096800000000000000000000000000000000000DA :1096900000000000000000000000000000000000CA :1096A00000000000000000000000000000000000BA :1096B00000000000000000000000000000000000AA :1096C000000000000000000000000000000000009A :1096D000000000000000000000000000000000008A :1096E000000000000000000000000000000000007A :1096F000000000000000000000000000000000006A :109700000000000000000000000000000000000059 :109710000000000000000000000000000000000049 :109720000000000000000000000000000000000039 :109730000000000000000000000000000000000029 :109740000000000000000000000000000000000019 :109750000000000000000000000000000000000009 :1097600000000000000000000000000000000000F9 :1097700000000000000000000000000000000000E9 :1097800000000000000000000000000000000000D9 :1097900000000000000000000000000000000000C9 :1097A00000000000000000000000000000000000B9 :1097B00000000000000000000000000000000000A9 :1097C0000000000000000000000000000000000099 :1097D0000000000000000000000000000000000089 :1097E0000000000000000000000000000000000079 :1097F0000000000000000000000000000000000069 :109800000000000000000000000000000000000058 :109810000000000000000000000000000000000048 :109820000000000000000000000000000000000038 :109830000000000000000000000000000000000028 :109840000000000000000000000000000000000018 :109850000000000000000000000000000000000008 :1098600000000000000000000000000000000000F8 :1098700000000000000000000000000000000000E8 :1098800000000000000000000000000000000000D8 :1098900000000000000000000000000000000000C8 :1098A00000000000000000000000000000000000B8 :1098B00000000000000000000000000000000000A8 :1098C0000000000000000000000000000000000098 :1098D0000000000000000000000000000000000088 :1098E0000000000000000000000000000000000078 :1098F0000000000000000000000000000000000068 :109900000000000000000000000000000000000057 :109910000000000000000000000000000000000047 :109920000000000000000000000000000000000037 :109930000000000000000000000000000000000027 :109940000000000000000000000000000000000017 :109950000000000000000000000000000000000007 :1099600000000000000000000000000000000000F7 :1099700000000000000000000000000000000000E7 :1099800000000000000000000000000000000000D7 :1099900000000000000000000000000000000000C7 :1099A00000000000000000000000000000000000B7 :1099B00000000000000000000000000000000000A7 :1099C0000000000000000000000000000000000097 :1099D0000000000000000000000000000000000087 :1099E0000000000000000000000000000000000077 :1099F0000000000000000000000000000000000067 :109A00000000000000000000000000000000000056 :109A10000000000000000000000000000000000046 :109A20000000000000000000000000000000000036 :109A30000000000000000000000000000000000026 :109A40000000000000000000000000000000000016 :109A50000000000000000000000000000000000006 :109A600000000000000000000000000000000000F6 :109A700000000000000000000000000000000000E6 :109A800000000000000000000000000000000000D6 :109A900000000000000000000000000000000000C6 :109AA00000000000000000000000000000000000B6 :109AB00000000000000000000000000000000000A6 :109AC0000000000000000000000000000000000096 :109AD0000000000000000000000000000000000086 :109AE0000000000000000000000000000000000076 :109AF0000000000000000000000000000000000066 :109B00000000000000000000000000000000000055 :109B10000000000000000000000000000000000045 :109B20000000000000000000000000000000000035 :109B30000000000000000000000000000000000025 :109B40000000000000000000000000000000000015 :109B50000000000000000000000000000000000005 :109B600000000000000000000000000000000000F5 :109B700000000000000000000000000000000000E5 :109B800000000000000000000000000000000000D5 :109B900000000000000000000000000000000000C5 :109BA00000000000000000000000000000000000B5 :109BB00000000000000000000000000000000000A5 :109BC0000000000000000000000000000000000095 :109BD0000000000000000000000000000000000085 :109BE0000000000000000000000000000000000075 :109BF0000000000000000000000000000000000065 :109C00000000000000000000000000000000000054 :109C10000000000000000000000000000000000044 :109C20000000000000000000000000000000000034 :109C30000000000000000000000000000000000024 :109C40000000000000000000000000000000000014 :109C50000000000000000000000000000000000004 :109C600000000000000000000000000000000000F4 :109C700000000000000000000000000000000000E4 :109C800000000000000000000000000000000000D4 :109C900000000000000000000000000000000000C4 :109CA00000000000000000000000000000000000B4 :109CB00000000000000000000000000000000000A4 :109CC0000000000000000000000000000000000094 :109CD0000000000000000000000000000000000084 :109CE0000000000000000000000000000000000074 :109CF0000000000000000000000000000000000064 :109D00000000000000000000000000000000000053 :109D10000000000000000000000000000000000043 :109D20000000000000000000000000000000000033 :109D30000000000000000000000000000000000023 :109D40000000000000000000000000000000000013 :109D50000000000000000000000000000000000003 :109D600000000000000000000000000000000000F3 :109D700000000000000000000000000000000000E3 :109D800000000000000000000000000000000000D3 :109D900000000000000000000000000000000000C3 :109DA00000000000000000000000000000000000B3 :109DB00000000000000000000000000000000000A3 :109DC0000000000000000000000000000000000093 :109DD0000000000000000000000000000000000083 :109DE0000000000000000000000000000000000073 :109DF0000000000000000000000000000000000063 :109E00000000000000000000000000000000000052 :109E10000000000000000000000000000000000042 :109E20000000000000000000000000000000000032 :109E30000000000000000000000000000000000022 :109E40000000000000000000000000000000000012 :109E50000000000000000000000000000000000002 :109E600000000000000000000000000000000000F2 :109E700000000000000000000000000000000000E2 :109E800000000000000000000000000000000000D2 :109E900000000000000000000000000000000000C2 :109EA00000000000000000000000000000000000B2 :109EB00000000000000000000000000000000000A2 :109EC0000000000000000000000000000000000092 :109ED0000000000000000000000000000000000082 :109EE0000000000000000000000000000000000072 :109EF0000000000000000000000000000000000062 :109F00000000000000000000000000000000000051 :109F10000000000000000000000000000000000041 :109F20000000000000000000000000000000000031 :109F30000000000000000000000000000000000021 :109F40000000000000000000000000000000000011 :109F50000000000000000000000000000000000001 :109F600000000000000000000000000000000000F1 :109F700000000000000000000000000000000000E1 :109F800000000000000000000000000000000000D1 :109F900000000000000000000000000000000000C1 :109FA00000000000000000000000000000000000B1 :109FB00000000000000000000000000000000000A1 :109FC0000000000000000000000000000000000091 :109FD0000000000000000000000000000000000081 :109FE0000000000000000000000000000000000071 :109FF0000000000000000000000000000000000061 :10A000000000000000000000000000000000000050 :10A010000000000000000000000000000000000040 :10A020000000000000000000000000000000000030 :10A030000000000000000000000000000000000020 :10A040000000000000000000000000000000000010 :10A050000000000000000000000000000000000000 :10A0600000000000000000000000000000000000F0 :10A0700000000000000000000000000000000000E0 :10A0800000000000000000000000000000000000D0 :10A0900000000000000000000000000000000000C0 :10A0A00000000000000000000000000000000000B0 :10A0B00000000000000000000000000000000000A0 :10A0C0000000000000000000000000000000000090 :10A0D0000000000000000000000000000000000080 :10A0E0000000000000000000000000000000000070 :10A0F0000000000000000000000000000000000060 :10A10000000000000000000000000000000000004F :10A11000000000000000000000000000000000003F :10A12000000000000000000000000000000000002F :10A13000000000000000000000000000000000001F :10A14000000000000000000000000000000000000F :10A1500000000000000000000000000000000000FF :10A1600000000000000000000000000000000000EF :10A1700000000000000000000000000000000000DF :10A1800000000000000000000000000000000000CF :10A1900000000000000000000000000000000000BF :10A1A00000000000000000000000000000000000AF :10A1B000000000000000000000000000000000009F :10A1C000000000000000000000000000000000008F :10A1D000000000000000000000000000000000007F :10A1E000000000000000000000000000000000006F :10A1F000000000000000000000000000000000005F :10A20000000000000000000000000000000000004E :10A21000000000000000000000000000000000003E :10A22000000000000000000000000000000000002E :10A23000000000000000000000000000000000001E :10A24000000000000000000000000000000000000E :10A2500000000000000000000000000000000000FE :10A2600000000000000000000000000000000000EE :10A2700000000000000000000000000000000000DE :10A2800000000000000000000000000000000000CE :10A2900000000000000000000000000000000000BE :10A2A00000000000000000000000000000000000AE :10A2B000000000000000000000000000000000009E :10A2C000000000000000000000000000000000008E :10A2D000000000000000000000000000000000007E :10A2E000000000000000000000000000000000006E :10A2F000000000000000000000000000000000005E :10A30000000000000000000000000000000000004D :10A31000000000000000000000000000000000003D :10A32000000000000000000000000000000000002D :10A33000000000000000000000000000000000001D :10A34000000000000000000000000000000000000D :10A3500000000000000000000000000000000000FD :10A3600000000000000000000000000000000000ED :10A3700000000000000000000000000000000000DD :10A3800000000000000000000000000000000000CD :10A3900000000000000000000000000000000000BD :10A3A00000000000000000000000000000000000AD :10A3B000000000000000000000000000000000009D :10A3C000000000000000000000000000000000008D :10A3D000000000000000000000000000000000007D :10A3E000000000000000000000000000000000006D :10A3F000000000000000000000000000000000005D :10A40000000000000000000000000000000000004C :10A41000000000000000000000000000000000003C :10A42000000000000000000000000000000000002C :10A43000000000000000000000000000000000001C :10A44000000000000000000000000000000000000C :10A4500000000000000000000000000000000000FC :10A4600000000000000000000000000000000000EC :10A4700000000000000000000000000000000000DC :10A4800000000000000000000000000000000000CC :10A4900000000000000000000000000000000000BC :10A4A00000000000000000000000000000000000AC :10A4B000000000000000000000000000000000009C :10A4C000000000000000000000000000000000008C :10A4D000000000000000000000000000000000007C :10A4E000000000000000000000000000000000006C :10A4F000000000000000000000000000000000005C :10A50000000000000000000000000000000000004B :10A51000000000000000000000000000000000003B :10A52000000000000000000000000000000000002B :10A53000000000000000000000000000000000001B :10A54000000000000000000000000000000000000B :10A5500000000000000000000000000000000000FB :10A5600000000000000000000000000000000000EB :10A5700000000000000000000000000000000000DB :10A5800000000000000000000000000000000000CB :10A5900000000000000000000000000000000000BB :10A5A00000000000000000000000000000000000AB :10A5B000000000000000000000000000000000009B :10A5C000000000000000000000000000000000008B :10A5D000000000000000000000000000000000007B :10A5E000000000000000000000000000000000006B :10A5F000000000000000000000000000000000005B :10A60000000000000000000000000000000000004A :10A61000000000000000000000000000000000003A :10A62000000000000000000000000000000000002A :10A63000000000000000000000000000000000001A :10A64000000000000000000000000000000000000A :10A6500000000000000000000000000000000000FA :10A6600000000000000000000000000000000000EA :10A6700000000000000000000000000000000000DA :10A6800000000000000000000000000000000000CA :10A6900000000000000000000000000000000000BA :10A6A00000000000000000000000000000000000AA :10A6B000000000000000000000000000000000009A :10A6C000000000000000000000000000000000008A :10A6D000000000000000000000000000000000007A :10A6E000000000000000000000000000000000006A :10A6F000000000000000000000000000000000005A :10A700000000000000000000000000000000000049 :10A710000000000000000000000000000000000039 :10A720000000000000000000000000000000000029 :10A730000000000000000000000000000000000019 :10A740000000000000000000000000000000000009 :10A7500000000000000000000000000000000000F9 :10A7600000000000000000000000000000000000E9 :10A7700000000000000000000000000000000000D9 :10A7800000000000000000000000000000000000C9 :10A7900000000000000000000000000000000000B9 :10A7A00000000000000000000000000000000000A9 :10A7B0000000000000000000000000000000000099 :10A7C0000000000000000000000000000000000089 :10A7D0000000000000000000000000000000000079 :10A7E0000000000000000000000000000000000069 :10A7F0000000000000000000000000000000000059 :10A800000000000000000000000000000000000048 :10A810000000000000000000000000000000000038 :10A820000000000000000000000000000000000028 :10A830000000000000000000000000000000000018 :10A840000000000000000000000000000000000008 :10A8500000000000000000000000000000000000F8 :10A8600000000000000000000000000000000000E8 :10A8700000000000000000000000000000000000D8 :10A8800000000000000000000000000000000000C8 :10A8900000000000000000000000000000000000B8 :10A8A00000000000000000000000000000000000A8 :10A8B0000000000000000000000000000000000098 :10A8C0000000000000000000000000000000000088 :10A8D0000000000000000000000000000000000078 :10A8E0000000000000000000000000000000000068 :10A8F0000000000000000000000000000000000058 :10A900000000000000000000000000000000000047 :10A910000000000000000000000000000000000037 :10A920000000000000000000000000000000000027 :10A930000000000000000000000000000000000017 :10A940000000000000000000000000000000000007 :10A9500000000000000000000000000000000000F7 :10A9600000000000000000000000000000000000E7 :10A9700000000000000000000000000000000000D7 :10A9800000000000000000000000000000000000C7 :10A9900000000000000000000000000000000000B7 :10A9A00000000000000000000000000000000000A7 :10A9B0000000000000000000000000000000000097 :10A9C0000000000000000000000000000000000087 :10A9D0000000000000000000000000000000000077 :10A9E0000000000000000000000000000000000067 :10A9F0000000000000000000000000000000000057 :10AA00000000000000000000000000000000000046 :10AA10000000000000000000000000000000000036 :10AA20000000000000000000000000000000000026 :10AA30000000000000000000000000000000000016 :10AA40000000000000000000000000000000000006 :10AA500000000000000000000000000000000000F6 :10AA600000000000000000000000000000000000E6 :10AA700000000000000000000000000000000000D6 :10AA800000000000000000000000000000000000C6 :10AA900000000000000000000000000000000000B6 :10AAA00000000000000000000000000000000000A6 :10AAB0000000000000000000000000000000000096 :10AAC0000000000000000000000000000000000086 :10AAD0000000000000000000000000000000000076 :10AAE0000000000000000000000000000000000066 :10AAF0000000000000000000000000000000000056 :10AB00000000000000000000000000000000000045 :10AB10000000000000000000000000000000000035 :10AB20000000000000000000000000000000000025 :10AB30000000000000000000000000000000000015 :10AB40000000000000000000000000000000000005 :10AB500000000000000000000000000000000000F5 :10AB600000000000000000000000000000000000E5 :10AB700000000000000000000000000000000000D5 :10AB800000000000000000000000000000000000C5 :10AB900000000000000000000000000000000000B5 :10ABA00000000000000000000000000000000000A5 :10ABB0000000000000000000000000000000000095 :10ABC0000000000000000000000000000000000085 :10ABD0000000000000000000000000000000000075 :10ABE0000000000000000000000000000000000065 :10ABF0000000000000000000000000000000000055 :10AC00000000000000000000000000000000000044 :10AC10000000000000000000000000000000000034 :10AC20000000000000000000000000000000000024 :10AC30000000000000000000000000000000000014 :10AC40000000000000000000000000000000000004 :10AC500000000000000000000000000000000000F4 :10AC600000000000000000000000000000000000E4 :10AC700000000000000000000000000000000000D4 :10AC800000000000000000000000000000000000C4 :10AC900000000000000000000000000000000000B4 :10ACA00000000000000000000000000000000000A4 :10ACB0000000000000000000000000000000000094 :10ACC0000000000000000000000000000000000084 :10ACD0000000000000000000000000000000000074 :10ACE0000000000000000000000000000000000064 :10ACF0000000000000000000000000000000000054 :10AD00000000000000000000000000000000000043 :10AD10000000000000000000000000000000000033 :10AD20000000000000000000000000000000000023 :10AD30000000000000000000000000000000000013 :10AD40000000000000000000000000000000000003 :10AD500000000000000000000000000000000000F3 :10AD600000000000000000000000000000000000E3 :10AD700000000000000000000000000000000000D3 :10AD800000000000000000000000000000000000C3 :10AD900000000000000000000000000000000000B3 :10ADA00000000000000000000000000000000000A3 :10ADB0000000000000000000000000000000000093 :10ADC0000000000000000000000000000000000083 :10ADD0000000000000000000000000000000000073 :10ADE0000000000000000000000000000000000063 :10ADF0000000000000000000000000000000000053 :10AE00000000000000000000000000000000000042 :10AE10000000000000000000000000000000000032 :10AE20000000000000000000000000000000000022 :10AE30000000000000000000000000000000000012 :10AE40000000000000000000000000000000000002 :10AE500000000000000000000000000000000000F2 :10AE600000000000000000000000000000000000E2 :10AE700000000000000000000000000000000000D2 :10AE800000000000000000000000000000000000C2 :10AE900000000000000000000000000000000000B2 :10AEA00000000000000000000000000000000000A2 :10AEB0000000000000000000000000000000000092 :10AEC0000000000000000000000000000000000082 :10AED0000000000000000000000000000000000072 :10AEE0000000000000000000000000000000000062 :10AEF0000000000000000000000000000000000052 :10AF00000000000000000000000000000000000041 :10AF10000000000000000000000000000000000031 :10AF20000000000000000000000000000000000021 :10AF30000000000000000000000000000000000011 :10AF40000000000000000000000000000000000001 :10AF500000000000000000000000000000000000F1 :10AF600000000000000000000000000000000000E1 :10AF700000000000000000000000000000000000D1 :10AF800000000000000000000000000000000000C1 :10AF900000000000000000000000000000000000B1 :10AFA00000000000000000000000000000000000A1 :10AFB0000000000000000000000000000000000091 :10AFC0000000000000000000000000000000000081 :10AFD0000000000000000000000000000000000071 :10AFE0000000000000000000000000000000000061 :10AFF0000000000000000000000000000000000051 :10B000000000000000000000000000000000000040 :10B010000000000000000000000000000000000030 :10B020000000000000000000000000000000000020 :10B030000000000000000000000000000000000010 :10B040000000000000000000000000000000000000 :10B0500000000000000000000000000000000000F0 :10B0600000000000000000000000000000000000E0 :10B0700000000000000000000000000000000000D0 :10B0800000000000000000000000000000000000C0 :10B0900000000000000000000000000000000000B0 :10B0A00000000000000000000000000000000000A0 :10B0B0000000000000000000000000000000000090 :10B0C0000000000000000000000000000000000080 :10B0D0000000000000000000000000000000000070 :10B0E0000000000000000000000000000000000060 :10B0F0000000000000000000000000000000000050 :10B10000000000000000000000000000000000003F :10B11000000000000000000000000000000000002F :10B12000000000000000000000000000000000001F :10B13000000000000000000000000000000000000F :10B1400000000000000000000000000000000000FF :10B1500000000000000000000000000000000000EF :10B1600000000000000000000000000000000000DF :10B1700000000000000000000000000000000000CF :10B1800000000000000000000000000000000000BF :10B1900000000000000000000000000000000000AF :10B1A000000000000000000000000000000000009F :10B1B000000000000000000000000000000000008F :10B1C000000000000000000000000000000000007F :10B1D000000000000000000000000000000000006F :10B1E000000000000000000000000000000000005F :10B1F000000000000000000000000000000000004F :10B20000000000000000000000000000000000003E :10B21000000000000000000000000000000000002E :10B22000000000000000000000000000000000001E :10B23000000000000000000000000000000000000E :10B2400000000000000000000000000000000000FE :10B2500000000000000000000000000000000000EE :10B2600000000000000000000000000000000000DE :10B2700000000000000000000000000000000000CE :10B2800000000000000000000000000000000000BE :10B2900000000000000000000000000000000000AE :10B2A000000000000000000000000000000000009E :10B2B000000000000000000000000000000000008E :10B2C000000000000000000000000000000000007E :10B2D000000000000000000000000000000000006E :10B2E000000000000000000000000000000000005E :10B2F000000000000000000000000000000000004E :10B30000000000000000000000000000000000003D :10B31000000000000000000000000000000000002D :10B32000000000000000000000000000000000001D :10B33000000000000000000000000000000000000D :10B3400000000000000000000000000000000000FD :10B3500000000000000000000000000000000000ED :10B3600000000000000000000000000000000000DD :10B3700000000000000000000000000000000000CD :10B3800000000000000000000000000000000000BD :10B3900000000000000000000000000000000000AD :10B3A000000000000000000000000000000000009D :10B3B000000000000000000000000000000000008D :10B3C000000000000000000000000000000000007D :10B3D000000000000000000000000000000000006D :10B3E000000000000000000000000000000000005D :10B3F000000000000000000000000000000000004D :10B40000000000000000000000000000000000003C :10B41000000000000000000000000000000000002C :10B42000000000000000000000000000000000001C :10B43000000000000000000000000000000000000C :10B4400000000000000000000000000000000000FC :10B4500000000000000000000000000000000000EC :10B4600000000000000000000000000000000000DC :10B4700000000000000000000000000000000000CC :10B4800000000000000000000000000000000000BC :10B4900000000000000000000000000000000000AC :10B4A000000000000000000000000000000000009C :10B4B000000000000000000000000000000000008C :10B4C000000000000000000000000000000000007C :10B4D000000000000000000000000000000000006C :10B4E000000000000000000000000000000000005C :10B4F000000000000000000000000000000000004C :10B50000000000000000000000000000000000003B :10B51000000000000000000000000000000000002B :10B52000000000000000000000000000000000001B :10B53000000000000000000000000000000000000B :10B5400000000000000000000000000000000000FB :10B5500000000000000000000000000000000000EB :10B5600000000000000000000000000000000000DB :10B5700000000000000000000000000000000000CB :10B5800000000000000000000000000000000000BB :10B5900000000000000000000000000000000000AB :10B5A000000000000000000000000000000000009B :10B5B000000000000000000000000000000000008B :10B5C000000000000000000000000000000000007B :10B5D000000000000000000000000000000000006B :10B5E000000000000000000000000000000000005B :10B5F000000000000000000000000000000000004B :10B60000000000000000000000000000000000003A :10B61000000000000000000000000000000000002A :10B62000000000000000000000000000000000001A :10B63000000000000000000000000000000000000A :10B6400000000000000000000000000000000000FA :10B6500000000000000000000000000000000000EA :10B6600000000000000000000000000000000000DA :10B6700000000000000000000000000000000000CA :10B6800000000000000000000000000000000000BA :10B6900000000000000000000000000000000000AA :10B6A000000000000000000000000000000000009A :10B6B000000000000000000000000000000000008A :10B6C000000000000000000000000000000000007A :10B6D000000000000000000000000000000000006A :10B6E000000000000000000000000000000000005A :10B6F000000000000000000000000000000000004A :10B700000000000000000000000000000000000039 :10B710000000000000000000000000000000000029 :10B720000000000000000000000000000000000019 :10B730000000000000000000000000000000000009 :10B7400000000000000000000000000000000000F9 :10B7500000000000000000000000000000000000E9 :10B7600000000000000000000000000000000000D9 :10B7700000000000000000000000000000000000C9 :10B7800000000000000000000000000000000000B9 :10B7900000000000000000000000000000000000A9 :10B7A0000000000000000000000000000000000099 :10B7B0000000000000000000000000000000000089 :10B7C0000000000000000000000000000000000079 :10B7D0000000000000000000000000000000000069 :10B7E0000000000000000000000000000000000059 :10B7F0000000000000000000000000000000000049 :10B800000000000000000000000000000000000038 :10B810000000000000000000000000000000000028 :10B820000000000000000000000000000000000018 :10B830000000000000000000000000000000000008 :10B8400000000000000000000000000000000000F8 :10B8500000000000000000000000000000000000E8 :10B8600000000000000000000000000000000000D8 :10B8700000000000000000000000000000000000C8 :10B8800000000000000000000000000000000000B8 :10B8900000000000000000000000000000000000A8 :10B8A0000000000000000000000000000000000098 :10B8B0000000000000000000000000000000000088 :10B8C0000000000000000000000000000000000078 :10B8D0000000000000000000000000000000000068 :10B8E0000000000000000000000000000000000058 :10B8F0000000000000000000000000000000000048 :10B900000000000000000000000000000000000037 :10B910000000000000000000000000000000000027 :10B920000000000000000000000000000000000017 :10B930000000000000000000000000000000000007 :10B9400000000000000000000000000000000000F7 :10B9500000000000000000000000000000000000E7 :10B9600000000000000000000000000000000000D7 :10B9700000000000000000000000000000000000C7 :10B9800000000000000000000000000000000000B7 :10B9900000000000000000000000000000000000A7 :10B9A0000000000000000000000000000000000097 :10B9B0000000000000000000000000000000000087 :10B9C0000000000000000000000000000000000077 :10B9D0000000000000000000000000000000000067 :10B9E0000000000000000000000000000000000057 :10B9F0000000000000000000000000000000000047 :10BA00000000000000000000000000000000000036 :10BA10000000000000000000000000000000000026 :10BA20000000000000000000000000000000000016 :10BA30000000000000000000000000000000000006 :10BA400000000000000000000000000000000000F6 :10BA500000000000000000000000000000000000E6 :10BA600000000000000000000000000000000000D6 :10BA700000000000000000000000000000000000C6 :10BA800000000000000000000000000000000000B6 :10BA900000000000000000000000000000000000A6 :10BAA0000000000000000000000000000000000096 :10BAB0000000000000000000000000000000000086 :10BAC0000000000000000000000000000000000076 :10BAD0000000000000000000000000000000000066 :10BAE0000000000000000000000000000000000056 :10BAF0000000000000000000000000000000000046 :10BB00000000000000000000000000000000000035 :10BB10000000000000000000000000000000000025 :10BB20000000000000000000000000000000000015 :10BB30000000000000000000000000000000000005 :10BB400000000000000000000000000000000000F5 :10BB500000000000000000000000000000000000E5 :10BB600000000000000000000000000000000000D5 :10BB700000000000000000000000000000000000C5 :10BB800000000000000000000000000000000000B5 :10BB900000000000000000000000000000000000A5 :10BBA0000000000000000000000000000000000095 :10BBB0000000000000000000000000000000000085 :10BBC0000000000000000000000000000000000075 :10BBD0000000000000000000000000000000000065 :10BBE0000000000000000000000000000000000055 :10BBF0000000000000000000000000000000000045 :10BC00000000000000000000000000000000000034 :10BC10000000000000000000000000000000000024 :10BC20000000000000000000000000000000000014 :10BC30000000000000000000000000000000000004 :10BC400000000000000000000000000000000000F4 :10BC500000000000000000000000000000000000E4 :10BC600000000000000000000000000000000000D4 :10BC700000000000000000000000000000000000C4 :10BC800000000000000000000000000000000000B4 :10BC900000000000000000000000000000000000A4 :10BCA0000000000000000000000000000000000094 :10BCB0000000000000000000000000000000000084 :10BCC0000000000000000000000000000000000074 :10BCD0000000000000000000000000000000000064 :10BCE0000000000000000000000000000000000054 :10BCF0000000000000000000000000000000000044 :10BD00000000000000000000000000000000000033 :10BD10000000000000000000000000000000000023 :10BD20000000000000000000000000000000000013 :10BD30000000000000000000000000000000000003 :10BD400000000000000000000000000000000000F3 :10BD500000000000000000000000000000000000E3 :10BD600000000000000000000000000000000000D3 :10BD700000000000000000000000000000000000C3 :10BD800000000000000000000000000000000000B3 :10BD900000000000000000000000000000000000A3 :10BDA0000000000000000000000000000000000093 :10BDB0000000000000000000000000000000000083 :10BDC0000000000000000000000000000000000073 :10BDD0000000000000000000000000000000000063 :10BDE0000000000000000000000000000000000053 :10BDF0000000000000000000000000000000000043 :10BE00000000000000000000000000000000000032 :10BE10000000000000000000000000000000000022 :10BE20000000000000000000000000000000000012 :10BE30000000000000000000000000000000000002 :10BE400000000000000000000000000000000000F2 :10BE500000000000000000000000000000000000E2 :10BE600000000000000000000000000000000000D2 :10BE700000000000000000000000000000000000C2 :10BE800000000000000000000000000000000000B2 :10BE900000000000000000000000000000000000A2 :10BEA0000000000000000000000000000000000092 :10BEB0000000000000000000000000000000000082 :10BEC0000000000000000000000000000000000072 :10BED0000000000000000000000000000000000062 :10BEE0000000000000000000000000000000000052 :10BEF0000000000000000000000000000000000042 :10BF00000000000000000000000000000000000031 :10BF10000000000000000000000000000000000021 :10BF20000000000000000000000000000000000011 :10BF30000000000000000000000000000000000001 :10BF400000000000000000000000000000000000F1 :10BF500000000000000000000000000000000000E1 :10BF600000000000000000000000000000000000D1 :10BF700000000000000000000000000000000000C1 :10BF800000000000000000000000000000000000B1 :10BF900000000000000000000000000000000000A1 :10BFA0000000000000000000000000000000000091 :10BFB0000000000000000000000000000000000081 :10BFC0000000000000000000000000000000000071 :10BFD0000000000000000000000000000000000061 :10BFE0000000000000000000000000000000000051 :10BFF0000000000000000000000000000000000041 :10C000000000000000000000000000000000000030 :10C010000000000000000000000000000000000020 :10C020000000000000000000000000000000000010 :10C030000000000000000000000000000000000000 :10C0400000000000000000000000000000000000F0 :10C0500000000000000000000000000000000000E0 :10C0600000000000000000000000000000000000D0 :10C0700000000000000000000000000000000000C0 :10C0800000000000000000000000000000000000B0 :10C0900000000000000000000000000000000000A0 :10C0A0000000000000000000000000000000000090 :10C0B0000000000000000000000000000000000080 :10C0C0000000000000000000000000000000000070 :10C0D0000000000000000000000000000000000060 :10C0E0000000000000000000000000000000000050 :10C0F0000000000000000000000000000000000040 :10C10000000000000000000000000000000000002F :10C11000000000000000000000000000000000001F :10C12000000000000000000000000000000000000F :10C1300000000000000000000000000000000000FF :10C1400000000000000000000000000000000000EF :10C1500000000000000000000000000000000000DF :10C1600000000000000000000000000000000000CF :10C1700000000000000000000000000000000000BF :10C1800000000000000000000000000000000000AF :10C19000000000000000000000000000000000009F :10C1A000000000000000000000000000000000008F :10C1B000000000000000000000000000000000007F :10C1C000000000000000000000000000000000006F :10C1D000000000000000000000000000000000005F :10C1E000000000000000000000000000000000004F :10C1F000000000000000000000000000000000003F :10C20000000000000000000000000000000000002E :10C21000000000000000000000000000000000001E :10C22000000000000000000000000000000000000E :10C2300000000000000000000000000000000000FE :10C2400000000000000000000000000000000000EE :10C2500000000000000000000000000000000000DE :10C2600000000000000000000000000000000000CE :10C2700000000000000000000000000000000000BE :10C2800000000000000000000000000000000000AE :10C29000000000000000000000000000000000009E :10C2A000000000000000000000000000000000008E :10C2B000000000000000000000000000000000007E :10C2C000000000000000000000000000000000006E :10C2D000000000000000000000000000000000005E :10C2E000000000000000000000000000000000004E :10C2F000000000000000000000000000000000003E :10C30000000000000000000000000000000000002D :10C31000000000000000000000000000000000001D :10C32000000000000000000000000000000000000D :10C3300000000000000000000000000000000000FD :10C3400000000000000000000000000000000000ED :10C3500000000000000000000000000000000000DD :10C3600000000000000000000000000000000000CD :10C3700000000000000000000000000000000000BD :10C3800000000000000000000000000000000000AD :10C39000000000000000000000000000000000009D :10C3A000000000000000000000000000000000008D :10C3B000000000000000000000000000000000007D :10C3C000000000000000000000000000000000006D :10C3D000000000000000000000000000000000005D :10C3E000000000000000000000000000000000004D :10C3F000000000000000000000000000000000003D :10C40000000000000000000000000000000000002C :10C41000000000000000000000000000000000001C :10C42000000000000000000000000000000000000C :10C4300000000000000000000000000000000000FC :10C4400000000000000000000000000000000000EC :10C4500000000000000000000000000000000000DC :10C4600000000000000000000000000000000000CC :10C4700000000000000000000000000000000000BC :10C4800000000000000000000000000000000000AC :10C49000000000000000000000000000000000009C :10C4A000000000000000000000000000000000008C :10C4B000000000000000000000000000000000007C :10C4C000000000000000000000000000000000006C :10C4D000000000000000000000000000000000005C :10C4E000000000000000000000000000000000004C :10C4F000000000000000000000000000000000003C :10C50000000000000000000000000000000000002B :10C51000000000000000000000000000000000001B :10C52000000000000000000000000000000000000B :10C5300000000000000000000000000000000000FB :10C5400000000000000000000000000000000000EB :10C5500000000000000000000000000000000000DB :10C5600000000000000000000000000000000000CB :10C5700000000000000000000000000000000000BB :10C5800000000000000000000000000000000000AB :10C59000000000000000000000000000000000009B :10C5A000000000000000000000000000000000008B :10C5B000000000000000000000000000000000007B :10C5C000000000000000000000000000000000006B :10C5D000000000000000000000000000000000005B :10C5E000000000000000000000000000000000004B :10C5F000000000000000000000000000000000003B :10C60000000000000000000000000000000000002A :10C61000000000000000000000000000000000001A :10C62000000000000000000000000000000000000A :10C6300000000000000000000000000000000000FA :10C6400000000000000000000000000000000000EA :10C6500000000000000000000000000000000000DA :10C6600000000000000000000000000000000000CA :10C6700000000000000000000000000000000000BA :10C6800000000000000000000000000000000000AA :10C69000000000000000000000000000000000009A :10C6A000000000000000000000000000000000008A :10C6B000000000000000000000000000000000007A :10C6C000000000000000000000000000000000006A :10C6D000000000000000000000000000000000005A :10C6E000000000000000000000000000000000004A :10C6F000000000000000000000000000000000003A :10C700000000000000000000000000000000000029 :10C710000000000000000000000000000000000019 :10C720000000000000000000000000000000000009 :10C7300000000000000000000000000000000000F9 :10C7400000000000000000000000000000000000E9 :10C7500000000000000000000000000000000000D9 :10C7600000000000000000000000000000000000C9 :10C7700000000000000000000000000000000000B9 :10C7800000000000000000000000000000000000A9 :10C790000000000000000000000000000000000099 :10C7A0000000000000000000000000000000000089 :10C7B0000000000000000000000000000000000079 :10C7C0000000000000000000000000000000000069 :10C7D0000000000000000000000000000000000059 :10C7E0000000000000000000000000000000000049 :10C7F0000000000000000000000000000000000039 :10C800000000000000000000000000000000000028 :10C810000000000000000000000000000000000018 :10C820000000000000000000000000000000000008 :10C8300000000000000000000000000000000000F8 :10C8400000000000000000000000000000000000E8 :10C8500000000000000000000000000000000000D8 :10C8600000000000000000000000000000000000C8 :10C8700000000000000000000000000000000000B8 :10C8800000000000000000000000000000000000A8 :10C890000000000000000000000000000000000098 :10C8A0000000000000000000000000000000000088 :10C8B0000000000000000000000000000000000078 :10C8C0000000000000000000000000000000000068 :10C8D0000000000000000000000000000000000058 :10C8E0000000000000000000000000000000000048 :10C8F0000000000000000000000000000000000038 :10C900000000000000000000000000000000000027 :10C910000000000000000000000000000000000017 :10C920000000000000000000000000000000000007 :10C9300000000000000000000000000000000000F7 :10C9400000000000000000000000000000000000E7 :10C9500000000000000000000000000000000000D7 :10C9600000000000000000000000000000000000C7 :10C9700000000000000000000000000000000000B7 :10C9800000000000000000000000000000000000A7 :10C990000000000000000000000000000000000097 :10C9A0000000000000000000000000000000000087 :10C9B0000000000000000000000000000000000077 :10C9C0000000000000000000000000000000000067 :10C9D0000000000000000000000000000000000057 :10C9E0000000000000000000000000000000000047 :10C9F0000000000000000000000000000000000037 :10CA00000000000000000000000000000000000026 :10CA10000000000000000000000000000000000016 :10CA20000000000000000000000000000000000006 :10CA300000000000000000000000000000000000F6 :10CA400000000000000000000000000000000000E6 :10CA500000000000000000000000000000000000D6 :10CA600000000000000000000000000000000000C6 :10CA700000000000000000000000000000000000B6 :10CA800000000000000000000000000000000000A6 :10CA90000000000000000000000000000000000096 :10CAA0000000000000000000000000000000000086 :10CAB0000000000000000000000000000000000076 :10CAC0000000000000000000000000000000000066 :10CAD0000000000000000000000000000000000056 :10CAE0000000000000000000000000000000000046 :10CAF0000000000000000000000000000000000036 :10CB00000000000000000000000000000000000025 :10CB10000000000000000000000000000000000015 :10CB20000000000000000000000000000000000005 :10CB300000000000000000000000000000000000F5 :10CB400000000000000000000000000000000000E5 :10CB500000000000000000000000000000000000D5 :10CB600000000000000000000000000000000000C5 :10CB700000000000000000000000000000000000B5 :10CB800000000000000000000000000000000000A5 :10CB90000000000000000000000000000000000095 :10CBA0000000000000000000000000000000000085 :10CBB0000000000000000000000000000000000075 :10CBC0000000000000000000000000000000000065 :10CBD0000000000000000000000000000000000055 :10CBE0000000000000000000000000000000000045 :10CBF0000000000000000000000000000000000035 :10CC00000000000000000000000000000000000024 :10CC10000000000000000000000000000000000014 :10CC20000000000000000000000000000000000004 :10CC300000000000000000000000000000000000F4 :10CC400000000000000000000000000000000000E4 :10CC500000000000000000000000000000000000D4 :10CC600000000000000000000000000000000000C4 :10CC700000000000000000000000000000000000B4 :10CC800000000000000000000000000000000000A4 :10CC90000000000000000000000000000000000094 :10CCA0000000000000000000000000000000000084 :10CCB0000000000000000000000000000000000074 :10CCC0000000000000000000000000000000000064 :10CCD0000000000000000000000000000000000054 :10CCE0000000000000000000000000000000000044 :10CCF0000000000000000000000000000000000034 :10CD00000000000000000000000000000000000023 :10CD10000000000000000000000000000000000013 :10CD20000000000000000000000000000000000003 :10CD300000000000000000000000000000000000F3 :10CD400000000000000000000000000000000000E3 :10CD500000000000000000000000000000000000D3 :10CD600000000000000000000000000000000000C3 :10CD700000000000000000000000000000000000B3 :10CD800000000000000000000000000000000000A3 :10CD90000000000000000000000000000000000093 :10CDA0000000000000000000000000000000000083 :10CDB0000000000000000000000000000000000073 :10CDC0000000000000000000000000000000000063 :10CDD0000000000000000000000000000000000053 :10CDE0000000000000000000000000000000000043 :10CDF0000000000000000000000000000000000033 :10CE00000000000000000000000000000000000022 :10CE10000000000000000000000000000000000012 :10CE20000000000000000000000000000000000002 :10CE300000000000000000000000000000000000F2 :10CE400000000000000000000000000000000000E2 :10CE500000000000000000000000000000000000D2 :10CE600000000000000000000000000000000000C2 :10CE700000000000000000000000000000000000B2 :10CE800000000000000000000000000000000000A2 :10CE90000000000000000000000000000000000092 :10CEA0000000000000000000000000000000000082 :10CEB0000000000000000000000000000000000072 :10CEC0000000000000000000000000000000000062 :10CED0000000000000000000000000000000000052 :10CEE0000000000000000000000000000000000042 :10CEF0000000000000000000000000000000000032 :10CF00000000000000000000000000000000000021 :10CF10000000000000000000000000000000000011 :10CF20000000000000000000000000000000000001 :10CF300000000000000000000000000000000000F1 :10CF400000000000000000000000000000000000E1 :10CF500000000000000000000000000000000000D1 :10CF600000000000000000000000000000000000C1 :10CF700000000000000000000000000000000000B1 :10CF800000000000000000000000000000000000A1 :10CF90000000000000000000000000000000000091 :10CFA0000000000000000000000000000000000081 :10CFB0000000000000000000000000000000000071 :10CFC0000000000000000000000000000000000061 :10CFD0000000000000000000000000000000000051 :10CFE0000000000000000000000000000000000041 :10CFF0000000000000000000000000000000000031 :10D000000000000000000000000000000000000020 :10D010000000000000000000000000000000000010 :10D020000000000000000000000000000000000000 :10D0300000000000000000000000000000000000F0 :10D0400000000000000000000000000000000000E0 :10D0500000000000000000000000000000000000D0 :10D0600000000000000000000000000000000000C0 :10D0700000000000000000000000000000000000B0 :10D0800000000000000000000000000000000000A0 :10D090000000000000000000000000000000000090 :10D0A0000000000000000000000000000000000080 :10D0B0000000000000000000000000000000000070 :10D0C0000000000000000000000000000000000060 :10D0D0000000000000000000000000000000000050 :10D0E0000000000000000000000000000000000040 :10D0F0000000000000000000000000000000000030 :10D10000000000000000000000000000000000001F :10D11000000000000000000000000000000000000F :10D1200000000000000000000000000000000000FF :10D1300000000000000000000000000000000000EF :10D1400000000000000000000000000000000000DF :10D1500000000000000000000000000000000000CF :10D1600000000000000000000000000000000000BF :10D1700000000000000000000000000000000000AF :10D18000000000000000000000000000000000009F :10D19000000000000000000000000000000000008F :10D1A000000000000000000000000000000000007F :10D1B000000000000000000000000000000000006F :10D1C000000000000000000000000000000000005F :10D1D000000000000000000000000000000000004F :10D1E000000000000000000000000000000000003F :10D1F000000000000000000000000000000000002F :10D20000000000000000000000000000000000001E :10D21000000000000000000000000000000000000E :10D2200000000000000000000000000000000000FE :10D2300000000000000000000000000000000000EE :10D2400000000000000000000000000000000000DE :10D2500000000000000000000000000000000000CE :10D2600000000000000000000000000000000000BE :10D2700000000000000000000000000000000000AE :10D28000000000000000000000000000000000009E :10D29000000000000000000000000000000000008E :10D2A000000000000000000000000000000000007E :10D2B000000000000000000000000000000000006E :10D2C000000000000000000000000000000000005E :10D2D000000000000000000000000000000000004E :10D2E000000000000000000000000000000000003E :10D2F000000000000000000000000000000000002E :10D30000000000000000000000000000000000001D :10D31000000000000000000000000000000000000D :10D3200000000000000000000000000000000000FD :10D3300000000000000000000000000000000000ED :10D3400000000000000000000000000000000000DD :10D3500000000000000000000000000000000000CD :10D3600000000000000000000000000000000000BD :10D3700000000000000000000000000000000000AD :10D38000000000000000000000000000000000009D :10D39000000000000000000000000000000000008D :10D3A000000000000000000000000000000000007D :10D3B000000000000000000000000000000000006D :10D3C000000000000000000000000000000000005D :10D3D000000000000000000000000000000000004D :10D3E000000000000000000000000000000000003D :10D3F000000000000000000000000000000000002D :10D40000000000000000000000000000000000001C :10D41000000000000000000000000000000000000C :10D4200000000000000000000000000000000000FC :10D4300000000000000000000000000000000000EC :10D4400000000000000000000000000000000000DC :10D4500000000000000000000000000000000000CC :10D4600000000000000000000000000000000000BC :10D4700000000000000000000000000000000000AC :10D48000000000000000000000000000000000009C :10D49000000000000000000000000000000000008C :10D4A000000000000000000000000000000000007C :10D4B000000000000000000000000000000000006C :10D4C000000000000000000000000000000000005C :10D4D000000000000000000000000000000000004C :10D4E000000000000000000000000000000000003C :10D4F000000000000000000000000000000000002C :10D50000000000000000000000000000000000001B :10D51000000000000000000000000000000000000B :10D5200000000000000000000000000000000000FB :10D5300000000000000000000000000000000000EB :10D5400000000000000000000000000000000000DB :10D5500000000000000000000000000000000000CB :10D5600000000000000000000000000000000000BB :10D5700000000000000000000000000000000000AB :10D58000000000000000000000000000000000009B :10D59000000000000000000000000000000000008B :10D5A000000000000000000000000000000000007B :10D5B000000000000000000000000000000000006B :10D5C000000000000000000000000000000000005B :10D5D000000000000000000000000000000000004B :10D5E000000000000000000000000000000000003B :10D5F000000000000000000000000000000000002B :10D60000000000000000000000000000000000001A :10D61000000000000000000000000000000000000A :10D6200000000000000000000000000000000000FA :10D6300000000000000000000000000000000000EA :10D6400000000000000000000000000000000000DA :10D6500000000000000000000000000000000000CA :10D6600000000000000000000000000000000000BA :10D6700000000000000000000000000000000000AA :10D68000000000000000000000000000000000009A :10D69000000000000000000000000000000000008A :10D6A000000000000000000000000000000000007A :10D6B000000000000000000000000000000000006A :10D6C000000000000000000000000000000000005A :10D6D000000000000000000000000000000000004A :10D6E000000000000000000000000000000000003A :10D6F000000000000000000000000000000000002A :10D700000000000000000000000000000000000019 :10D710000000000000000000000000000000000009 :10D7200000000000000000000000000000000000F9 :10D7300000000000000000000000000000000000E9 :10D7400000000000000000000000000000000000D9 :10D7500000000000000000000000000000000000C9 :10D7600000000000000000000000000000000000B9 :10D7700000000000000000000000000000000000A9 :10D780000000000000000000000000000000000099 :10D790000000000000000000000000000000000089 :10D7A0000000000000000000000000000000000079 :10D7B0000000000000000000000000000000000069 :10D7C0000000000000000000000000000000000059 :10D7D0000000000000000000000000000000000049 :10D7E0000000000000000000000000000000000039 :10D7F0000000000000000000000000000000000029 :10D800000000000000000000000000000000000018 :10D810000000000000000000000000000000000008 :10D8200000000000000000000000000000000000F8 :10D8300000000000000000000000000000000000E8 :10D8400000000000000000000000000000000000D8 :10D8500000000000000000000000000000000000C8 :10D8600000000000000000000000000000000000B8 :10D8700000000000000000000000000000000000A8 :10D880000000000000000000000000000000000098 :10D890000000000000000000000000000000000088 :10D8A0000000000000000000000000000000000078 :10D8B0000000000000000000000000000000000068 :10D8C0000000000000000000000000000000000058 :10D8D0000000000000000000000000000000000048 :10D8E0000000000000000000000000000000000038 :10D8F0000000000000000000000000000000000028 :10D900000000000000000000000000000000000017 :10D910000000000000000000000000000000000007 :10D9200000000000000000000000000000000000F7 :10D9300000000000000000000000000000000000E7 :10D9400000000000000000000000000000000000D7 :10D9500000000000000000000000000000000000C7 :10D9600000000000000000000000000000000000B7 :10D9700000000000000000000000000000000000A7 :10D980000000000000000000000000000000000097 :10D990000000000000000000000000000000000087 :10D9A0000000000000000000000000000000000077 :10D9B0000000000000000000000000000000000067 :10D9C0000000000000000000000000000000000057 :10D9D0000000000000000000000000000000000047 :10D9E0000000000000000000000000000000000037 :10D9F0000000000000000000000000000000000027 :10DA00000000000000000000000000000000000016 :10DA10000000000000000000000000000000000006 :10DA200000000000000000000000000000000000F6 :10DA300000000000000000000000000000000000E6 :10DA400000000000000000000000000000000000D6 :10DA500000000000000000000000000000000000C6 :10DA600000000000000000000000000000000000B6 :10DA700000000000000000000000000000000000A6 :10DA80000000000000000000000000000000000096 :10DA90000000000000000000000000000000000086 :10DAA0000000000000000000000000000000000076 :10DAB0000000000000000000000000000000000066 :10DAC0000000000000000000000000000000000056 :10DAD0000000000000000000000000000000000046 :10DAE0000000000000000000000000000000000036 :10DAF0000000000000000000000000000000000026 :10DB00000000000000000000000000000000000015 :10DB10000000000000000000000000000000000005 :10DB200000000000000000000000000000000000F5 :10DB300000000000000000000000000000000000E5 :10DB400000000000000000000000000000000000D5 :10DB500000000000000000000000000000000000C5 :10DB600000000000000000000000000000000000B5 :10DB700000000000000000000000000000000000A5 :10DB80000000000000000000000000000000000095 :10DB90000000000000000000000000000000000085 :10DBA0000000000000000000000000000000000075 :10DBB0000000000000000000000000000000000065 :10DBC0000000000000000000000000000000000055 :10DBD0000000000000000000000000000000000045 :10DBE0000000000000000000000000000000000035 :10DBF0000000000000000000000000000000000025 :10DC00000000000000000000000000000000000014 :10DC10000000000000000000000000000000000004 :10DC200000000000000000000000000000000000F4 :10DC300000000000000000000000000000000000E4 :10DC400000000000000000000000000000000000D4 :10DC500000000000000000000000000000000000C4 :10DC600000000000000000000000000000000000B4 :10DC700000000000000000000000000000000000A4 :10DC80000000000000000000000000000000000094 :10DC90000000000000000000000000000000000084 :10DCA0000000000000000000000000000000000074 :10DCB0000000000000000000000000000000000064 :10DCC0000000000000000000000000000000000054 :10DCD0000000000000000000000000000000000044 :10DCE0000000000000000000000000000000000034 :10DCF0000000000000000000000000000000000024 :10DD00000000000000000000000000000000000013 :10DD10000000000000000000000000000000000003 :10DD200000000000000000000000000000000000F3 :10DD300000000000000000000000000000000000E3 :10DD400000000000000000000000000000000000D3 :10DD500000000000000000000000000000000000C3 :10DD600000000000000000000000000000000000B3 :10DD700000000000000000000000000000000000A3 :10DD80000000000000000000000000000000000093 :10DD90000000000000000000000000000000000083 :10DDA0000000000000000000000000000000000073 :10DDB0000000000000000000000000000000000063 :10DDC0000000000000000000000000000000000053 :10DDD0000000000000000000000000000000000043 :10DDE0000000000000000000000000000000000033 :10DDF0000000000000000000000000000000000023 :10DE00000000000000000000000000000000000012 :10DE10000000000000000000000000000000000002 :10DE200000000000000000000000000000000000F2 :10DE300000000000000000000000000000000000E2 :10DE400000000000000000000000000000000000D2 :10DE500000000000000000000000000000000000C2 :10DE600000000000000000000000000000000000B2 :10DE700000000000000000000000000000000000A2 :10DE80000000000000000000000000000000000092 :10DE90000000000000000000000000000000000082 :10DEA0000000000000000000000000000000000072 :10DEB0000000000000000000000000000000000062 :10DEC0000000000000000000000000000000000052 :10DED0000000000000000000000000000000000042 :10DEE0000000000000000000000000000000000032 :10DEF0000000000000000000000000000000000022 :10DF00000000000000000000000000000000000011 :10DF10000000000000000000000000000000000001 :10DF200000000000000000000000000000000000F1 :10DF300000000000000000000000000000000000E1 :10DF400000000000000000000000000000000000D1 :10DF500000000000000000000000000000000000C1 :10DF600000000000000000000000000000000000B1 :10DF700000000000000000000000000000000000A1 :10DF80000000000000000000000000000000000091 :10DF90000000000000000000000000000000000081 :10DFA0000000000000000000000000000000000071 :10DFB0000000000000000000000000000000000061 :10DFC0000000000000000000000000000000000051 :10DFD0000000000000000000000000000000000041 :10DFE0000000000000000000000000000000000031 :10DFF0000000000000000000000000000000000021 :10E000000000000000000000000000000000000010 :10E010000000000000000000000000000000000000 :10E0200000000000000000000000000000000000F0 :10E0300000000000000000000000000000000000E0 :10E0400000000000000000000000000000000000D0 :10E0500000000000000000000000000000000000C0 :10E0600000000000000000000000000000000000B0 :10E0700000000000000000000000000000000000A0 :10E080000000000000000000000000000000000090 :10E090000000000000000000000000000000000080 :10E0A0000000000000000000000000000000000070 :10E0B0000000000000000000000000000000000060 :10E0C0000000000000000000000000000000000050 :10E0D0000000000000000000000000000000000040 :10E0E0000000000000000000000000000000000030 :10E0F0000000000000000000000000000000000020 :10E10000000000000000000000000000000000000F :10E1100000000000000000000000000000000000FF :10E1200000000000000000000000000000000000EF :10E1300000000000000000000000000000000000DF :10E1400000000000000000000000000000000000CF :10E1500000000000000000000000000000000000BF :10E1600000000000000000000000000000000000AF :10E17000000000000000000000000000000000009F :10E18000000000000000000000000000000000008F :10E19000000000000000000000000000000000007F :10E1A000000000000000000000000000000000006F :10E1B000000000000000000000000000000000005F :10E1C000000000000000000000000000000000004F :10E1D000000000000000000000000000000000003F :10E1E000000000000000000000000000000000002F :10E1F000000000000000000000000000000000001F :10E20000000000000000000000000000000000000E :10E2100000000000000000000000000000000000FE :10E2200000000000000000000000000000000000EE :10E2300000000000000000000000000000000000DE :10E2400000000000000000000000000000000000CE :10E2500000000000000000000000000000000000BE :10E2600000000000000000000000000000000000AE :10E27000000000000000000000000000000000009E :10E28000000000000000000000000000000000008E :10E29000000000000000000000000000000000007E :10E2A000000000000000000000000000000000006E :10E2B000000000000000000000000000000000005E :10E2C000000000000000000000000000000000004E :10E2D000000000000000000000000000000000003E :10E2E000000000000000000000000000000000002E :10E2F000000000000000000000000000000000001E :10E30000000000000000000000000000000000000D :10E3100000000000000000000000000000000000FD :10E3200000000000000000000000000000000000ED :10E3300000000000000000000000000000000000DD :10E3400000000000000000000000000000000000CD :10E3500000000000000000000000000000000000BD :10E3600000000000000000000000000000000000AD :10E37000000000000000000000000000000000009D :10E38000000000000000000000000000000000008D :10E39000000000000000000000000000000000007D :10E3A000000000000000000000000000000000006D :10E3B000000000000000000000000000000000005D :10E3C000000000000000000000000000000000004D :10E3D000000000000000000000000000000000003D :10E3E000000000000000000000000000000000002D :10E3F000000000000000000000000000000000001D :10E40000000000000000000000000000000000000C :10E4100000000000000000000000000000000000FC :10E4200000000000000000000000000000000000EC :10E4300000000000000000000000000000000000DC :10E4400000000000000000000000000000000000CC :10E4500000000000000000000000000000000000BC :10E4600000000000000000000000000000000000AC :10E47000000000000000000000000000000000009C :10E48000000000000000000000000000000000008C :10E49000000000000000000000000000000000007C :10E4A000000000000000000000000000000000006C :10E4B000000000000000000000000000000000005C :10E4C000000000000000000000000000000000004C :10E4D000000000000000000000000000000000003C :10E4E000000000000000000000000000000000002C :10E4F000000000000000000000000000000000001C :10E50000000000000000000000000000000000000B :10E5100000000000000000000000000000000000FB :10E5200000000000000000000000000000000000EB :10E5300000000000000000000000000000000000DB :10E5400000000000000000000000000000000000CB :10E5500000000000000000000000000000000000BB :10E5600000000000000000000000000000000000AB :10E57000000000000000000000000000000000009B :10E58000000000000000000000000000000000008B :10E59000000000000000000000000000000000007B :10E5A000000000000000000000000000000000006B :10E5B000000000000000000000000000000000005B :10E5C000000000000000000000000000000000004B :10E5D000000000000000000000000000000000003B :10E5E000000000000000000000000000000000002B :10E5F000000000000000000000000000000000001B :10E60000000000000000000000000000000000000A :10E6100000000000000000000000000000000000FA :10E6200000000000000000000000000000000000EA :10E6300000000000000000000000000000000000DA :10E6400000000000000000000000000000000000CA :10E6500000000000000000000000000000000000BA :10E6600000000000000000000000000000000000AA :10E67000000000000000000000000000000000009A :10E68000000000000000000000000000000000008A :10E69000000000000000000000000000000000007A :10E6A000000000000000000000000000000000006A :10E6B000000000000000000000000000000000005A :10E6C000000000000000000000000000000000004A :10E6D000000000000000000000000000000000003A :10E6E000000000000000000000000000000000002A :10E6F000000000000000000000000000000000001A :10E700000000000000000000000000000000000009 :10E7100000000000000000000000000000000000F9 :10E7200000000000000000000000000000000000E9 :10E7300000000000000000000000000000000000D9 :10E7400000000000000000000000000000000000C9 :10E7500000000000000000000000000000000000B9 :10E7600000000000000000000000000000000000A9 :10E770000000000000000000000000000000000099 :10E780000000000000000000000000000000000089 :10E790000000000000000000000000000000000079 :10E7A0000000000000000000000000000000000069 :10E7B0000000000000000000000000000000000059 :10E7C0000000000000000000000000000000000049 :10E7D0000000000000000000000000000000000039 :10E7E0000000000000000000000000000000000029 :10E7F0000000000000000000000000000000000019 :10E800000000000000000000000000000000000008 :10E8100000000000000000000000000000000000F8 :10E8200000000000000000000000000000000000E8 :10E8300000000000000000000000000000000000D8 :10E8400000000000000000000000000000000000C8 :10E8500000000000000000000000000000000000B8 :10E8600000000000000000000000000000000000A8 :10E870000000000000000000000000000000000098 :10E880000000000000000000000000000000000088 :10E890000000000000000000000000000000000078 :10E8A0000000000000000000000000000000000068 :10E8B0000000000000000000000000000000000058 :10E8C0000000000000000000000000000000000048 :10E8D0000000000000000000000000000000000038 :10E8E0000000000000000000000000000000000028 :10E8F0000000000000000000000000000000000018 :10E900000000000000000000000000000000000007 :10E9100000000000000000000000000000000000F7 :10E9200000000000000000000000000000000000E7 :10E9300000000000000000000000000000000000D7 :10E9400000000000000000000000000000000000C7 :10E9500000000000000000000000000000000000B7 :10E9600000000000000000000000000000000000A7 :10E970000000000000000000000000000000000097 :10E980000000000000000000000000000000000087 :10E990000000000000000000000000000000000077 :10E9A0000000000000000000000000000000000067 :10E9B0000000000000000000000000000000000057 :10E9C0000000000000000000000000000000000047 :10E9D0000000000000000000000000000000000037 :10E9E0000000000000000000000000000000000027 :10E9F0000000000000000000000000000000000017 :10EA00000000000000000000000000000000000006 :10EA100000000000000000000000000000000000F6 :10EA200000000000000000000000000000000000E6 :10EA300000000000000000000000000000000000D6 :10EA400000000000000000000000000000000000C6 :10EA500000000000000000000000000000000000B6 :10EA600000000000000000000000000000000000A6 :10EA70000000000000000000000000000000000096 :10EA80000000000000000000000000000000000086 :10EA90000000000000000000000000000000000076 :10EAA0000000000000000000000000000000000066 :10EAB0000000000000000000000000000000000056 :10EAC0000000000000000000000000000000000046 :10EAD0000000000000000000000000000000000036 :10EAE0000000000000000000000000000000000026 :10EAF0000000000000000000000000000000000016 :10EB00000000000000000000000000000000000005 :10EB100000000000000000000000000000000000F5 :10EB200000000000000000000000000000000000E5 :10EB300000000000000000000000000000000000D5 :10EB400000000000000000000000000000000000C5 :10EB500000000000000000000000000000000000B5 :10EB600000000000000000000000000000000000A5 :10EB70000000000000000000000000000000000095 :10EB80000000000000000000000000000000000085 :10EB90000000000000000000000000000000000075 :10EBA0000000000000000000000000000000000065 :10EBB0000000000000000000000000000000000055 :10EBC0000000000000000000000000000000000045 :10EBD0000000000000000000000000000000000035 :10EBE0000000000000000000000000000000000025 :10EBF0000000000000000000000000000000000015 :10EC00000000000000000000000000000000000004 :10EC100000000000000000000000000000000000F4 :10EC200000000000000000000000000000000000E4 :10EC300000000000000000000000000000000000D4 :10EC400000000000000000000000000000000000C4 :10EC500000000000000000000000000000000000B4 :10EC600000000000000000000000000000000000A4 :10EC70000000000000000000000000000000000094 :10EC80000000000000000000000000000000000084 :10EC90000000000000000000000000000000000074 :10ECA0000000000000000000000000000000000064 :10ECB0000000000000000000000000000000000054 :10ECC0000000000000000000000000000000000044 :10ECD0000000000000000000000000000000000034 :10ECE0000000000000000000000000000000000024 :10ECF0000000000000000000000000000000000014 :10ED00000000000000000000000000000000000003 :10ED100000000000000000000000000000000000F3 :10ED200000000000000000000000000000000000E3 :10ED300000000000000000000000000000000000D3 :10ED400000000000000000000000000000000000C3 :10ED500000000000000000000000000000000000B3 :10ED600000000000000000000000000000000000A3 :10ED70000000000000000000000000000000000093 :10ED80000000000000000000000000000000000083 :10ED90000000000000000000000000000000000073 :10EDA0000000000000000000000000000000000063 :10EDB0000000000000000000000000000000000053 :10EDC0000000000000000000000000000000000043 :10EDD0000000000000000000000000000000000033 :10EDE0000000000000000000000000000000000023 :10EDF0000000000000000000000000000000000013 :10EE00000000000000000000000000000000000002 :10EE100000000000000000000000000000000000F2 :10EE200000000000000000000000000000000000E2 :10EE300000000000000000000000000000000000D2 :10EE400000000000000000000000000000000000C2 :10EE500000000000000000000000000000000000B2 :10EE600000000000000000000000000000000000A2 :10EE70000000000000000000000000000000000092 :10EE80000000000000000000000000000000000082 :10EE90000000000000000000000000000000000072 :10EEA0000000000000000000000000000000000062 :10EEB0000000000000000000000000000000000052 :10EEC0000000000000000000000000000000000042 :10EED0000000000000000000000000000000000032 :10EEE0000000000000000000000000000000000022 :10EEF0000000000000000000000000000000000012 :10EF00000000000000000000000000000000000001 :10EF100000000000000000000000000000000000F1 :10EF200000000000000000000000000000000000E1 :10EF300000000000000000000000000000000000D1 :10EF400000000000000000000000000000000000C1 :10EF500000000000000000000000000000000000B1 :10EF600000000000000000000000000000000000A1 :10EF70000000000000000000000000000000000091 :10EF80000000000000000000000000000000000081 :10EF90000000000000000000000000000000000071 :10EFA0000000000000000000000000000000000061 :10EFB0000000000000000000000000000000000051 :10EFC0000000000000000000000000000000000041 :10EFD0000000000000000000000000000000000031 :10EFE0000000000000000000000000000000000021 :10EFF0000000000000000000000000000000000011 :10F000000000000000000000000000000000000000 :10F0100000000000000000000000000000000000F0 :10F0200000000000000000000000000000000000E0 :10F0300000000000000000000000000000000000D0 :10F0400000000000000000000000000000000000C0 :10F0500000000000000000000000000000000000B0 :10F0600000000000000000000000000000000000A0 :10F070000000000000000000000000000000000090 :10F080000000000000000000000000000000000080 :10F090000000000000000000000000000000000070 :10F0A0000000000000000000000000000000000060 :10F0B0000000000000000000000000000000000050 :10F0C0000000000000000000000000000000000040 :10F0D0000000000000000000000000000000000030 :10F0E0000000000000000000000000000000000020 :10F0F0000000000000000000000000000000000010 :10F1000000000000000000000000000000000000FF :10F1100000000000000000000000000000000000EF :10F1200000000000000000000000000000000000DF :10F1300000000000000000000000000000000000CF :10F1400000000000000000000000000000000000BF :10F1500000000000000000000000000000000000AF :10F16000000000000000000000000000000000009F :10F17000000000000000000000000000000000008F :10F18000000000000000000000000000000000007F :10F19000000000000000000000000000000000006F :10F1A000000000000000000000000000000000005F :10F1B000000000000000000000000000000000004F :10F1C000000000000000000000000000000000003F :10F1D000000000000000000000000000000000002F :10F1E000000000000000000000000000000000001F :10F1F000000000000000000000000000000000000F :10F2000000000000000000000000000000000000FE :10F2100000000000000000000000000000000000EE :10F2200000000000000000000000000000000000DE :10F2300000000000000000000000000000000000CE :10F2400000000000000000000000000000000000BE :10F2500000000000000000000000000000000000AE :10F26000000000000000000000000000000000009E :10F27000000000000000000000000000000000008E :10F28000000000000000000000000000000000007E :10F29000000000000000000000000000000000006E :10F2A000000000000000000000000000000000005E :10F2B000000000000000000000000000000000004E :10F2C000000000000000000000000000000000003E :10F2D000000000000000000000000000000000002E :10F2E000000000000000000000000000000000001E :10F2F000000000000000000000000000000000000E :10F3000000000000000000000000000000000000FD :10F3100000000000000000000000000000000000ED :10F3200000000000000000000000000000000000DD :10F3300000000000000000000000000000000000CD :10F3400000000000000000000000000000000000BD :10F3500000000000000000000000000000000000AD :10F36000000000000000000000000000000000009D :10F37000000000000000000000000000000000008D :10F38000000000000000000000000000000000007D :10F39000000000000000000000000000000000006D :10F3A000000000000000000000000000000000005D :10F3B000000000000000000000000000000000004D :10F3C000000000000000000000000000000000003D :10F3D000000000000000000000000000000000002D :10F3E000000000000000000000000000000000001D :10F3F000000000000000000000000000000000000D :10F4000000000000000000000000000000000000FC :10F4100000000000000000000000000000000000EC :10F4200000000000000000000000000000000000DC :10F4300000000000000000000000000000000000CC :10F4400000000000000000000000000000000000BC :10F4500000000000000000000000000000000000AC :10F46000000000000000000000000000000000009C :10F47000000000000000000000000000000000008C :10F48000000000000000000000000000000000007C :10F49000000000000000000000000000000000006C :10F4A000000000000000000000000000000000005C :10F4B000000000000000000000000000000000004C :10F4C000000000000000000000000000000000003C :10F4D000000000000000000000000000000000002C :10F4E000000000000000000000000000000000001C :10F4F000000000000000000000000000000000000C :10F5000000000000000000000000000000000000FB :10F5100000000000000000000000000000000000EB :10F5200000000000000000000000000000000000DB :10F5300000000000000000000000000000000000CB :10F5400000000000000000000000000000000000BB :10F5500000000000000000000000000000000000AB :10F56000000000000000000000000000000000009B :10F57000000000000000000000000000000000008B :10F58000000000000000000000000000000000007B :10F59000000000000000000000000000000000006B :10F5A000000000000000000000000000000000005B :10F5B000000000000000000000000000000000004B :10F5C000000000000000000000000000000000003B :10F5D000000000000000000000000000000000002B :10F5E000000000000000000000000000000000001B :10F5F000000000000000000000000000000000000B :10F6000000000000000000000000000000000000FA :10F6100000000000000000000000000000000000EA :10F6200000000000000000000000000000000000DA :10F6300000000000000000000000000000000000CA :10F6400000000000000000000000000000000000BA :10F6500000000000000000000000000000000000AA :10F66000000000000000000000000000000000009A :10F67000000000000000000000000000000000008A :10F68000000000000000000000000000000000007A :10F69000000000000000000000000000000000006A :10F6A000000000000000000000000000000000005A :10F6B000000000000000000000000000000000004A :10F6C000000000000000000000000000000000003A :10F6D000000000000000000000000000000000002A :10F6E000000000000000000000000000000000001A :10F6F000000000000000000000000000000000000A :10F7000000000000000000000000000000000000F9 :10F7100000000000000000000000000000000000E9 :10F7200000000000000000000000000000000000D9 :10F7300000000000000000000000000000000000C9 :10F7400000000000000000000000000000000000B9 :10F7500000000000000000000000000000000000A9 :10F760000000000000000000000000000000000099 :10F770000000000000000000000000000000000089 :10F780000000000000000000000000000000000079 :10F790000000000000000000000000000000000069 :10F7A0000000000000000000000000000000000059 :10F7B0000000000000000000000000000000000049 :10F7C0000000000000000000000000000000000039 :10F7D0000000000000000000000000000000000029 :10F7E0000000000000000000000000000000000019 :10F7F0000000000000000000000000000000000009 :10F8000000000000000000000000000000000000F8 :10F8100000000000000000000000000000000000E8 :10F8200000000000000000000000000000000000D8 :10F8300000000000000000000000000000000000C8 :10F8400000000000000000000000000000000000B8 :10F8500000000000000000000000000000000000A8 :10F860000000000000000000000000000000000098 :10F870000000000000000000000000000000000088 :10F880000000000000000000000000000000000078 :10F890000000000000000000000000000000000068 :10F8A0000000000000000000000000000000000058 :10F8B0000000000000000000000000000000000048 :10F8C0000000000000000000000000000000000038 :10F8D0000000000000000000000000000000000028 :10F8E0000000000000000000000000000000000018 :10F8F0000000000000000000000000000000000008 :10F9000000000000000000000000000000000000F7 :10F9100000000000000000000000000000000000E7 :10F9200000000000000000000000000000000000D7 :10F9300000000000000000000000000000000000C7 :10F9400000000000000000000000000000000000B7 :10F9500000000000000000000000000000000000A7 :10F960000000000000000000000000000000000097 :10F970000000000000000000000000000000000087 :10F980000000000000000000000000000000000077 :10F990000000000000000000000000000000000067 :10F9A0000000000000000000000000000000000057 :10F9B0000000000000000000000000000000000047 :10F9C0000000000000000000000000000000000037 :10F9D0000000000000000000000000000000000027 :10F9E0000000000000000000000000000000000017 :10F9F0000000000000000000000000000000000007 :10FA000000000000000000000000000000000000F6 :10FA100000000000000000000000000000000000E6 :10FA200000000000000000000000000000000000D6 :10FA300000000000000000000000000000000000C6 :10FA400000000000000000000000000000000000B6 :10FA500000000000000000000000000000000000A6 :10FA60000000000000000000000000000000000096 :10FA70000000000000000000000000000000000086 :10FA80000000000000000000000000000000000076 :10FA90000000000000000000000000000000000066 :10FAA0000000000000000000000000000000000056 :10FAB0000000000000000000000000000000000046 :10FAC0000000000000000000000000000000000036 :10FAD0000000000000000000000000000000000026 :10FAE0000000000000000000000000000000000016 :10FAF0000000000000000000000000000000000006 :10FB000000000000000000000000000000000000F5 :10FB100000000000000000000000000000000000E5 :10FB200000000000000000000000000000000000D5 :10FB300000000000000000000000000000000000C5 :10FB400000000000000000000000000000000000B5 :10FB500000000000000000000000000000000000A5 :10FB60000000000000000000000000000000000095 :10FB70000000000000000000000000000000000085 :10FB80000000000000000000000000000000000075 :10FB90000000000000000000000000000000000065 :10FBA0000000000000000000000000000000000055 :10FBB0000000000000000000000000000000000045 :10FBC0000000000000000000000000000000000035 :10FBD0000000000000000000000000000000000025 :10FBE0000000000000000000000000000000000015 :10FBF0000000000000000000000000000000000005 :10FC000000000000000000000000000000000000F4 :10FC100000000000000000000000000000000000E4 :10FC200000000000000000000000000000000000D4 :10FC300000000000000000000000000000000000C4 :10FC400000000000000000000000000000000000B4 :10FC500000000000000000000000000000000000A4 :10FC60000000000000000000000000000000000094 :10FC70000000000000000000000000000000000084 :10FC80000000000000000000000000000000000074 :10FC90000000000000000000000000000000000064 :10FCA0000000000000000000000000000000000054 :10FCB0000000000000000000000000000000000044 :10FCC0000000000000000000000000000000000034 :10FCD0000000000000000000000000000000000024 :10FCE0000000000000000000000000000000000014 :10FCF0000000000000000000000000000000000004 :10FD000000000000000000000000000000000000F3 :10FD100000000000000000000000000000000000E3 :10FD200000000000000000000000000000000000D3 :10FD300000000000000000000000000000000000C3 :10FD400000000000000000000000000000000000B3 :10FD500000000000000000000000000000000000A3 :10FD60000000000000000000000000000000000093 :10FD70000000000000000000000000000000000083 :10FD80000000000000000000000000000000000073 :10FD90000000000000000000000000000000000063 :10FDA0000000000000000000000000000000000053 :10FDB0000000000000000000000000000000000043 :10FDC0000000000000000000000000000000000033 :10FDD0000000000000000000000000000000000023 :10FDE0000000000000000000000000000000000013 :10FDF0000000000000000000000000000000000003 :10FE000000000000000000000000000000000000F2 :10FE100000000000000000000000000000000000E2 :10FE200000000000000000000000000000000000D2 :10FE300000000000000000000000000000000000C2 :10FE400000000000000000000000000000000000B2 :10FE500000000000000000000000000000000000A2 :10FE60000000000000000000000000000000000092 :10FE70000000000000000000000000000000000082 :10FE80000000000000000000000000000000000072 :10FE90000000000000000000000000000000000062 :10FEA0000000000000000000000000000000000052 :10FEB0000000000000000000000000000000000042 :10FEC0000000000000000000000000000000000032 :10FED0000000000000000000000000000000000022 :10FEE0000000000000000000000000000000000012 :10FEF0000000000000000000000000000000000002 :10FF000000000000000000000000000000000000F1 :10FF100000000000000000000000000000000000E1 :10FF200000000000000000000000000000000000D1 :10FF300000000000000000000000000000000000C1 :10FF400000000000000000000000000000000000B1 :10FF500000000000000000000000000000000000A1 :10FF60000000000000000000000000000000000091 :10FF70000000000000000000000000000000000081 :10FF80000000000000000000000000000000000071 :10FF90000000000000000000000000000000000061 :10FFA0000000000000000000000000000000000051 :10FFB0000000000000000000000000000000000041 :10FFC0000000000000000000000000000000000031 :10FFD0000000000000000000000000000000000021 :10FFE0000000000000000000000000000000000011 :10FFF0000000000000000000000000000000000001 :02000004620197 :1000000000000000000000000000000000000000F0 :1000100000000000000000000000000000000000E0 :1000200000000000000000000000000000000000D0 :1000300000000000000000000000000000000000C0 :1000400000000000000000000000000000000000B0 :1000500000000000000000000000000000000000A0 :100060000000000000000000000000000000000090 :100070000000000000000000000000000000000080 :100080000000000000000000000000000000000070 :100090000000000000000000000000000000000060 :1000A0000000000000000000000000000000000050 :1000B0000000000000000000000000000000000040 :1000C0000000000000000000000000000000000030 :1000D0000000000000000000000000000000000020 :1000E0000000000000000000000000000000000010 :1000F0000000000000000000000000000000000000 :1001000000000000000000000000000000000000EF :1001100000000000000000000000000000000000DF :1001200000000000000000000000000000000000CF :1001300000000000000000000000000000000000BF :1001400000000000000000000000000000000000AF :10015000000000000000000000000000000000009F :10016000000000000000000000000000000000008F :10017000000000000000000000000000000000007F :10018000000000000000000000000000000000006F :10019000000000000000000000000000000000005F :1001A000000000000000000000000000000000004F :1001B000000000000000000000000000000000003F :1001C000000000000000000000000000000000002F :1001D000000000000000000000000000000000001F :1001E000000000000000000000000000000000000F :1001F00000000000000000000000000000000000FF :1002000000000000000000000000000000000000EE :1002100000000000000000000000000000000000DE :1002200000000000000000000000000000000000CE :1002300000000000000000000000000000000000BE :1002400000000000000000000000000000000000AE :10025000000000000000000000000000000000009E :10026000000000000000000000000000000000008E :10027000000000000000000000000000000000007E :10028000000000000000000000000000000000006E :10029000000000000000000000000000000000005E :1002A000000000000000000000000000000000004E :1002B000000000000000000000000000000000003E :1002C000000000000000000000000000000000002E :1002D000000000000000000000000000000000001E :1002E000000000000000000000000000000000000E :1002F00000000000000000000000000000000000FE :1003000000000000000000000000000000000000ED :1003100000000000000000000000000000000000DD :1003200000000000000000000000000000000000CD :1003300000000000000000000000000000000000BD :1003400000000000000000000000000000000000AD :10035000000000000000000000000000000000009D :10036000000000000000000000000000000000008D :10037000000000000000000000000000000000007D :10038000000000000000000000000000000000006D :10039000000000000000000000000000000000005D :1003A000000000000000000000000000000000004D :1003B000000000000000000000000000000000003D :1003C000000000000000000000000000000000002D :1003D000000000000000000000000000000000001D :1003E000000000000000000000000000000000000D :1003F00000000000000000000000000000000000FD :1004000000000000000000000000000000000000EC :1004100000000000000000000000000000000000DC :1004200000000000000000000000000000000000CC :1004300000000000000000000000000000000000BC :1004400000000000000000000000000000000000AC :10045000000000000000000000000000000000009C :10046000000000000000000000000000000000008C :10047000000000000000000000000000000000007C :10048000000000000000000000000000000000006C :10049000000000000000000000000000000000005C :1004A000000000000000000000000000000000004C :1004B000000000000000000000000000000000003C :1004C000000000000000000000000000000000002C :1004D000000000000000000000000000000000001C :1004E000000000000000000000000000000000000C :1004F00000000000000000000000000000000000FC :1005000000000000000000000000000000000000EB :1005100000000000000000000000000000000000DB :1005200000000000000000000000000000000000CB :1005300000000000000000000000000000000000BB :1005400000000000000000000000000000000000AB :10055000000000000000000000000000000000009B :10056000000000000000000000000000000000008B :10057000000000000000000000000000000000007B :10058000000000000000000000000000000000006B :10059000000000000000000000000000000000005B :1005A000000000000000000000000000000000004B :1005B000000000000000000000000000000000003B :1005C000000000000000000000000000000000002B :1005D000000000000000000000000000000000001B :1005E000000000000000000000000000000000000B :1005F00000000000000000000000000000000000FB :1006000000000000000000000000000000000000EA :1006100000000000000000000000000000000000DA :1006200000000000000000000000000000000000CA :1006300000000000000000000000000000000000BA :1006400000000000000000000000000000000000AA :10065000000000000000000000000000000000009A :10066000000000000000000000000000000000008A :10067000000000000000000000000000000000007A :10068000000000000000000000000000000000006A :10069000000000000000000000000000000000005A :1006A000000000000000000000000000000000004A :1006B000000000000000000000000000000000003A :1006C000000000000000000000000000000000002A :1006D000000000000000000000000000000000001A :1006E000000000000000000000000000000000000A :1006F00000000000000000000000000000000000FA :1007000000000000000000000000000000000000E9 :1007100000000000000000000000000000000000D9 :1007200000000000000000000000000000000000C9 :1007300000000000000000000000000000000000B9 :1007400000000000000000000000000000000000A9 :100750000000000000000000000000000000000099 :100760000000000000000000000000000000000089 :100770000000000000000000000000000000000079 :100780000000000000000000000000000000000069 :100790000000000000000000000000000000000059 :1007A0000000000000000000000000000000000049 :1007B0000000000000000000000000000000000039 :1007C0000000000000000000000000000000000029 :1007D0000000000000000000000000000000000019 :1007E0000000000000000000000000000000000009 :1007F00000000000000000000000000000000000F9 :1008000000000000000000000000000000000000E8 :1008100000000000000000000000000000000000D8 :1008200000000000000000000000000000000000C8 :1008300000000000000000000000000000000000B8 :1008400000000000000000000000000000000000A8 :100850000000000000000000000000000000000098 :100860000000000000000000000000000000000088 :100870000000000000000000000000000000000078 :100880000000000000000000000000000000000068 :100890000000000000000000000000000000000058 :1008A0000000000000000000000000000000000048 :1008B0000000000000000000000000000000000038 :1008C0000000000000000000000000000000000028 :1008D0000000000000000000000000000000000018 :1008E0000000000000000000000000000000000008 :1008F00000000000000000000000000000000000F8 :1009000000000000000000000000000000000000E7 :1009100000000000000000000000000000000000D7 :1009200000000000000000000000000000000000C7 :1009300000000000000000000000000000000000B7 :1009400000000000000000000000000000000000A7 :100950000000000000000000000000000000000097 :100960000000000000000000000000000000000087 :100970000000000000000000000000000000000077 :100980000000000000000000000000000000000067 :100990000000000000000000000000000000000057 :1009A0000000000000000000000000000000000047 :1009B0000000000000000000000000000000000037 :1009C0000000000000000000000000000000000027 :1009D0000000000000000000000000000000000017 :1009E0000000000000000000000000000000000007 :1009F00000000000000000000000000000000000F7 :100A000000000000000000000000000000000000E6 :100A100000000000000000000000000000000000D6 :100A200000000000000000000000000000000000C6 :100A300000000000000000000000000000000000B6 :100A400000000000000000000000000000000000A6 :100A50000000000000000000000000000000000096 :100A60000000000000000000000000000000000086 :100A70000000000000000000000000000000000076 :100A80000000000000000000000000000000000066 :100A90000000000000000000000000000000000056 :100AA0000000000000000000000000000000000046 :100AB0000000000000000000000000000000000036 :100AC0000000000000000000000000000000000026 :100AD0000000000000000000000000000000000016 :100AE0000000000000000000000000000000000006 :100AF00000000000000000000000000000000000F6 :100B000000000000000000000000000000000000E5 :100B100000000000000000000000000000000000D5 :100B200000000000000000000000000000000000C5 :100B300000000000000000000000000000000000B5 :100B400000000000000000000000000000000000A5 :100B50000000000000000000000000000000000095 :100B60000000000000000000000000000000000085 :100B70000000000000000000000000000000000075 :100B80000000000000000000000000000000000065 :100B90000000000000000000000000000000000055 :100BA0000000000000000000000000000000000045 :100BB0000000000000000000000000000000000035 :100BC0000000000000000000000000000000000025 :100BD0000000000000000000000000000000000015 :100BE0000000000000000000000000000000000005 :100BF00000000000000000000000000000000000F5 :100C000000000000000000000000000000000000E4 :100C100000000000000000000000000000000000D4 :100C200000000000000000000000000000000000C4 :100C300000000000000000000000000000000000B4 :100C400000000000000000000000000000000000A4 :100C50000000000000000000000000000000000094 :100C60000000000000000000000000000000000084 :100C70000000000000000000000000000000000074 :100C80000000000000000000000000000000000064 :100C90000000000000000000000000000000000054 :100CA0000000000000000000000000000000000044 :100CB0000000000000000000000000000000000034 :100CC0000000000000000000000000000000000024 :100CD0000000000000000000000000000000000014 :100CE0000000000000000000000000000000000004 :100CF00000000000000000000000000000000000F4 :100D000000000000000000000000000000000000E3 :100D100000000000000000000000000000000000D3 :100D200000000000000000000000000000000000C3 :100D300000000000000000000000000000000000B3 :100D400000000000000000000000000000000000A3 :100D50000000000000000000000000000000000093 :100D60000000000000000000000000000000000083 :100D70000000000000000000000000000000000073 :100D80000000000000000000000000000000000063 :100D90000000000000000000000000000000000053 :100DA0000000000000000000000000000000000043 :100DB0000000000000000000000000000000000033 :100DC0000000000000000000000000000000000023 :100DD0000000000000000000000000000000000013 :100DE0000000000000000000000000000000000003 :100DF00000000000000000000000000000000000F3 :100E000000000000000000000000000000000000E2 :100E100000000000000000000000000000000000D2 :100E200000000000000000000000000000000000C2 :100E300000000000000000000000000000000000B2 :100E400000000000000000000000000000000000A2 :100E50000000000000000000000000000000000092 :100E60000000000000000000000000000000000082 :100E70000000000000000000000000000000000072 :100E80000000000000000000000000000000000062 :100E90000000000000000000000000000000000052 :100EA0000000000000000000000000000000000042 :100EB0000000000000000000000000000000000032 :100EC0000000000000000000000000000000000022 :100ED0000000000000000000000000000000000012 :100EE0000000000000000000000000000000000002 :100EF00000000000000000000000000000000000F2 :100F000000000000000000000000000000000000E1 :100F100000000000000000000000000000000000D1 :100F200000000000000000000000000000000000C1 :100F300000000000000000000000000000000000B1 :100F400000000000000000000000000000000000A1 :100F50000000000000000000000000000000000091 :100F60000000000000000000000000000000000081 :100F70000000000000000000000000000000000071 :100F80000000000000000000000000000000000061 :100F90000000000000000000000000000000000051 :100FA0000000000000000000000000000000000041 :100FB0000000000000000000000000000000000031 :100FC0000000000000000000000000000000000021 :100FD0000000000000000000000000000000000011 :100FE0000000000000000000000000000000000001 :100FF00000000000000000000000000000000000F1 :1010000000000000000000000000000000000000E0 :1010100000000000000000000000000000000000D0 :1010200000000000000000000000000000000000C0 :1010300000000000000000000000000000000000B0 :1010400000000000000000000000000000000000A0 :101050000000000000000000000000000000000090 :101060000000000000000000000000000000000080 :101070000000000000000000000000000000000070 :101080000000000000000000000000000000000060 :101090000000000000000000000000000000000050 :1010A0000000000000000000000000000000000040 :1010B0000000000000000000000000000000000030 :1010C0000000000000000000000000000000000020 :1010D0000000000000000000000000000000000010 :1010E0000000000000000000000000000000000000 :1010F00000000000000000000000000000000000F0 :1011000000000000000000000000000000000000DF :1011100000000000000000000000000000000000CF :1011200000000000000000000000000000000000BF :1011300000000000000000000000000000000000AF :10114000000000000000000000000000000000009F :10115000000000000000000000000000000000008F :10116000000000000000000000000000000000007F :10117000000000000000000000000000000000006F :10118000000000000000000000000000000000005F :10119000000000000000000000000000000000004F :1011A000000000000000000000000000000000003F :1011B000000000000000000000000000000000002F :1011C000000000000000000000000000000000001F :1011D000000000000000000000000000000000000F :1011E00000000000000000000000000000000000FF :1011F00000000000000000000000000000000000EF :1012000000000000000000000000000000000000DE :1012100000000000000000000000000000000000CE :1012200000000000000000000000000000000000BE :1012300000000000000000000000000000000000AE :10124000000000000000000000000000000000009E :10125000000000000000000000000000000000008E :10126000000000000000000000000000000000007E :10127000000000000000000000000000000000006E :10128000000000000000000000000000000000005E :10129000000000000000000000000000000000004E :1012A000000000000000000000000000000000003E :1012B000000000000000000000000000000000002E :1012C000000000000000000000000000000000001E :1012D000000000000000000000000000000000000E :1012E00000000000000000000000000000000000FE :1012F00000000000000000000000000000000000EE :1013000000000000000000000000000000000000DD :1013100000000000000000000000000000000000CD :1013200000000000000000000000000000000000BD :1013300000000000000000000000000000000000AD :10134000000000000000000000000000000000009D :10135000000000000000000000000000000000008D :10136000000000000000000000000000000000007D :10137000000000000000000000000000000000006D :10138000000000000000000000000000000000005D :10139000000000000000000000000000000000004D :1013A000000000000000000000000000000000003D :1013B000000000000000000000000000000000002D :1013C000000000000000000000000000000000001D :1013D000000000000000000000000000000000000D :1013E00000000000000000000000000000000000FD :1013F00000000000000000000000000000000000ED :1014000000000000000000000000000000000000DC :1014100000000000000000000000000000000000CC :1014200000000000000000000000000000000000BC :1014300000000000000000000000000000000000AC :10144000000000000000000000000000000000009C :10145000000000000000000000000000000000008C :10146000000000000000000000000000000000007C :10147000000000000000000000000000000000006C :10148000000000000000000000000000000000005C :10149000000000000000000000000000000000004C :1014A000000000000000000000000000000000003C :1014B000000000000000000000000000000000002C :1014C000000000000000000000000000000000001C :1014D000000000000000000000000000000000000C :1014E00000000000000000000000000000000000FC :1014F00000000000000000000000000000000000EC :1015000000000000000000000000000000000000DB :1015100000000000000000000000000000000000CB :1015200000000000000000000000000000000000BB :1015300000000000000000000000000000000000AB :10154000000000000000000000000000000000009B :10155000000000000000000000000000000000008B :10156000000000000000000000000000000000007B :10157000000000000000000000000000000000006B :10158000000000000000000000000000000000005B :10159000000000000000000000000000000000004B :1015A000000000000000000000000000000000003B :1015B000000000000000000000000000000000002B :1015C000000000000000000000000000000000001B :1015D000000000000000000000000000000000000B :1015E00000000000000000000000000000000000FB :1015F00000000000000000000000000000000000EB :1016000000000000000000000000000000000000DA :1016100000000000000000000000000000000000CA :1016200000000000000000000000000000000000BA :1016300000000000000000000000000000000000AA :10164000000000000000000000000000000000009A :10165000000000000000000000000000000000008A :10166000000000000000000000000000000000007A :10167000000000000000000000000000000000006A :10168000000000000000000000000000000000005A :10169000000000000000000000000000000000004A :1016A000000000000000000000000000000000003A :1016B000000000000000000000000000000000002A :1016C000000000000000000000000000000000001A :1016D000000000000000000000000000000000000A :1016E00000000000000000000000000000000000FA :1016F00000000000000000000000000000000000EA :1017000000000000000000000000000000000000D9 :1017100000000000000000000000000000000000C9 :1017200000000000000000000000000000000000B9 :1017300000000000000000000000000000000000A9 :101740000000000000000000000000000000000099 :101750000000000000000000000000000000000089 :101760000000000000000000000000000000000079 :101770000000000000000000000000000000000069 :101780000000000000000000000000000000000059 :101790000000000000000000000000000000000049 :1017A0000000000000000000000000000000000039 :1017B0000000000000000000000000000000000029 :1017C0000000000000000000000000000000000019 :1017D0000000000000000000000000000000000009 :1017E00000000000000000000000000000000000F9 :1017F00000000000000000000000000000000000E9 :1018000000000000000000000000000000000000D8 :1018100000000000000000000000000000000000C8 :1018200000000000000000000000000000000000B8 :1018300000000000000000000000000000000000A8 :101840000000000000000000000000000000000098 :101850000000000000000000000000000000000088 :101860000000000000000000000000000000000078 :101870000000000000000000000000000000000068 :101880000000000000000000000000000000000058 :101890000000000000000000000000000000000048 :1018A0000000000000000000000000000000000038 :1018B0000000000000000000000000000000000028 :1018C0000000000000000000000000000000000018 :1018D0000000000000000000000000000000000008 :1018E00000000000000000000000000000000000F8 :1018F00000000000000000000000000000000000E8 :1019000000000000000000000000000000000000D7 :1019100000000000000000000000000000000000C7 :1019200000000000000000000000000000000000B7 :1019300000000000000000000000000000000000A7 :101940000000000000000000000000000000000097 :101950000000000000000000000000000000000087 :101960000000000000000000000000000000000077 :101970000000000000000000000000000000000067 :101980000000000000000000000000000000000057 :101990000000000000000000000000000000000047 :1019A0000000000000000000000000000000000037 :1019B0000000000000000000000000000000000027 :1019C0000000000000000000000000000000000017 :1019D0000000000000000000000000000000000007 :1019E00000000000000000000000000000000000F7 :1019F00000000000000000000000000000000000E7 :101A000000000000000000000000000000000000D6 :101A100000000000000000000000000000000000C6 :101A200000000000000000000000000000000000B6 :101A300000000000000000000000000000000000A6 :101A40000000000000000000000000000000000096 :101A50000000000000000000000000000000000086 :101A60000000000000000000000000000000000076 :101A70000000000000000000000000000000000066 :101A80000000000000000000000000000000000056 :101A90000000000000000000000000000000000046 :101AA0000000000000000000000000000000000036 :101AB0000000000000000000000000000000000026 :101AC0000000000000000000000000000000000016 :101AD0000000000000000000000000000000000006 :101AE00000000000000000000000000000000000F6 :101AF00000000000000000000000000000000000E6 :101B000000000000000000000000000000000000D5 :101B100000000000000000000000000000000000C5 :101B200000000000000000000000000000000000B5 :101B300000000000000000000000000000000000A5 :101B40000000000000000000000000000000000095 :101B50000000000000000000000000000000000085 :101B60000000000000000000000000000000000075 :101B70000000000000000000000000000000000065 :101B80000000000000000000000000000000000055 :101B90000000000000000000000000000000000045 :101BA0000000000000000000000000000000000035 :101BB0000000000000000000000000000000000025 :101BC0000000000000000000000000000000000015 :101BD0000000000000000000000000000000000005 :101BE00000000000000000000000000000000000F5 :101BF00000000000000000000000000000000000E5 :101C000000000000000000000000000000000000D4 :101C100000000000000000000000000000000000C4 :101C200000000000000000000000000000000000B4 :101C300000000000000000000000000000000000A4 :101C40000000000000000000000000000000000094 :101C50000000000000000000000000000000000084 :101C60000000000000000000000000000000000074 :101C70000000000000000000000000000000000064 :101C80000000000000000000000000000000000054 :101C90000000000000000000000000000000000044 :101CA0000000000000000000000000000000000034 :101CB0000000000000000000000000000000000024 :101CC0000000000000000000000000000000000014 :101CD0000000000000000000000000000000000004 :101CE00000000000000000000000000000000000F4 :101CF00000000000000000000000000000000000E4 :101D000000000000000000000000000000000000D3 :101D100000000000000000000000000000000000C3 :101D200000000000000000000000000000000000B3 :101D300000000000000000000000000000000000A3 :101D40000000000000000000000000000000000093 :101D50000000000000000000000000000000000083 :101D60000000000000000000000000000000000073 :101D70000000000000000000000000000000000063 :101D80000000000000000000000000000000000053 :101D90000000000000000000000000000000000043 :101DA0000000000000000000000000000000000033 :101DB0000000000000000000000000000000000023 :101DC0000000000000000000000000000000000013 :101DD0000000000000000000000000000000000003 :101DE00000000000000000000000000000000000F3 :101DF00000000000000000000000000000000000E3 :101E000000000000000000000000000000000000D2 :101E100000000000000000000000000000000000C2 :101E200000000000000000000000000000000000B2 :101E300000000000000000000000000000000000A2 :101E40000000000000000000000000000000000092 :101E50000000000000000000000000000000000082 :101E60000000000000000000000000000000000072 :101E70000000000000000000000000000000000062 :101E80000000000000000000000000000000000052 :101E90000000000000000000000000000000000042 :101EA0000000000000000000000000000000000032 :101EB0000000000000000000000000000000000022 :101EC0000000000000000000000000000000000012 :101ED0000000000000000000000000000000000002 :101EE00000000000000000000000000000000000F2 :101EF00000000000000000000000000000000000E2 :101F000000000000000000000000000000000000D1 :101F100000000000000000000000000000000000C1 :101F200000000000000000000000000000000000B1 :101F300000000000000000000000000000000000A1 :101F40000000000000000000000000000000000091 :101F50000000000000000000000000000000000081 :101F60000000000000000000000000000000000071 :101F70000000000000000000000000000000000061 :101F80000000000000000000000000000000000051 :101F90000000000000000000000000000000000041 :101FA0000000000000000000000000000000000031 :101FB0000000000000000000000000000000000021 :101FC0000000000000000000000000000000000011 :101FD0000000000000000000000000000000000001 :101FE00000000000000000000000000000000000F1 :101FF00000000000000000000000000000000000E1 :1020000000000000000000000000000000000000D0 :1020100000000000000000000000000000000000C0 :1020200000000000000000000000000000000000B0 :1020300000000000000000000000000000000000A0 :102040000000000000000000000000000000000090 :102050000000000000000000000000000000000080 :102060000000000000000000000000000000000070 :102070000000000000000000000000000000000060 :102080000000000000000000000000000000000050 :102090000000000000000000000000000000000040 :1020A0000000000000000000000000000000000030 :1020B0000000000000000000000000000000000020 :1020C0000000000000000000000000000000000010 :1020D0000000000000000000000000000000000000 :1020E00000000000000000000000000000000000F0 :1020F00000000000000000000000000000000000E0 :1021000000000000000000000000000000000000CF :1021100000000000000000000000000000000000BF :1021200000000000000000000000000000000000AF :10213000000000000000000000000000000000009F :10214000000000000000000000000000000000008F :10215000000000000000000000000000000000007F :10216000000000000000000000000000000000006F :10217000000000000000000000000000000000005F :10218000000000000000000000000000000000004F :10219000000000000000000000000000000000003F :1021A000000000000000000000000000000000002F :1021B000000000000000000000000000000000001F :1021C000000000000000000000000000000000000F :1021D00000000000000000000000000000000000FF :1021E00000000000000000000000000000000000EF :1021F00000000000000000000000000000000000DF :1022000000000000000000000000000000000000CE :1022100000000000000000000000000000000000BE :1022200000000000000000000000000000000000AE :10223000000000000000000000000000000000009E :10224000000000000000000000000000000000008E :10225000000000000000000000000000000000007E :10226000000000000000000000000000000000006E :10227000000000000000000000000000000000005E :10228000000000000000000000000000000000004E :10229000000000000000000000000000000000003E :1022A000000000000000000000000000000000002E :1022B000000000000000000000000000000000001E :1022C000000000000000000000000000000000000E :1022D00000000000000000000000000000000000FE :1022E00000000000000000000000000000000000EE :1022F00000000000000000000000000000000000DE :1023000000000000000000000000000000000000CD :1023100000000000000000000000000000000000BD :1023200000000000000000000000000000000000AD :10233000000000000000000000000000000000009D :10234000000000000000000000000000000000008D :10235000000000000000000000000000000000007D :10236000000000000000000000000000000000006D :10237000000000000000000000000000000000005D :10238000000000000000000000000000000000004D :10239000000000000000000000000000000000003D :1023A000000000000000000000000000000000002D :1023B000000000000000000000000000000000001D :1023C000000000000000000000000000000000000D :1023D00000000000000000000000000000000000FD :1023E00000000000000000000000000000000000ED :1023F00000000000000000000000000000000000DD :1024000000000000000000000000000000000000CC :1024100000000000000000000000000000000000BC :1024200000000000000000000000000000000000AC :10243000000000000000000000000000000000009C :10244000000000000000000000000000000000008C :10245000000000000000000000000000000000007C :10246000000000000000000000000000000000006C :10247000000000000000000000000000000000005C :10248000000000000000000000000000000000004C :10249000000000000000000000000000000000003C :1024A000000000000000000000000000000000002C :1024B000000000000000000000000000000000001C :1024C000000000000000000000000000000000000C :1024D00000000000000000000000000000000000FC :1024E00000000000000000000000000000000000EC :1024F00000000000000000000000000000000000DC :1025000000000000000000000000000000000000CB :1025100000000000000000000000000000000000BB :1025200000000000000000000000000000000000AB :10253000000000000000000000000000000000009B :10254000000000000000000000000000000000008B :10255000000000000000000000000000000000007B :10256000000000000000000000000000000000006B :10257000000000000000000000000000000000005B :10258000000000000000000000000000000000004B :10259000000000000000000000000000000000003B :1025A000000000000000000000000000000000002B :1025B000000000000000000000000000000000001B :1025C000000000000000000000000000000000000B :1025D00000000000000000000000000000000000FB :1025E00000000000000000000000000000000000EB :1025F00000000000000000000000000000000000DB :1026000000000000000000000000000000000000CA :1026100000000000000000000000000000000000BA :1026200000000000000000000000000000000000AA :10263000000000000000000000000000000000009A :10264000000000000000000000000000000000008A :10265000000000000000000000000000000000007A :10266000000000000000000000000000000000006A :10267000000000000000000000000000000000005A :10268000000000000000000000000000000000004A :10269000000000000000000000000000000000003A :1026A000000000000000000000000000000000002A :1026B000000000000000000000000000000000001A :1026C000000000000000000000000000000000000A :1026D00000000000000000000000000000000000FA :1026E00000000000000000000000000000000000EA :1026F00000000000000000000000000000000000DA :1027000000000000000000000000000000000000C9 :1027100000000000000000000000000000000000B9 :1027200000000000000000000000000000000000A9 :102730000000000000000000000000000000000099 :102740000000000000000000000000000000000089 :102750000000000000000000000000000000000079 :102760000000000000000000000000000000000069 :102770000000000000000000000000000000000059 :102780000000000000000000000000000000000049 :102790000000000000000000000000000000000039 :1027A0000000000000000000000000000000000029 :1027B0000000000000000000000000000000000019 :1027C0000000000000000000000000000000000009 :1027D00000000000000000000000000000000000F9 :1027E00000000000000000000000000000000000E9 :1027F00000000000000000000000000000000000D9 :1028000000000000000000000000000000000000C8 :1028100000000000000000000000000000000000B8 :1028200000000000000000000000000000000000A8 :102830000000000000000000000000000000000098 :102840000000000000000000000000000000000088 :102850000000000000000000000000000000000078 :102860000000000000000000000000000000000068 :102870000000000000000000000000000000000058 :102880000000000000000000000000000000000048 :102890000000000000000000000000000000000038 :1028A0000000000000000000000000000000000028 :1028B0000000000000000000000000000000000018 :1028C0000000000000000000000000000000000008 :1028D00000000000000000000000000000000000F8 :1028E00000000000000000000000000000000000E8 :1028F00000000000000000000000000000000000D8 :1029000000000000000000000000000000000000C7 :1029100000000000000000000000000000000000B7 :1029200000000000000000000000000000000000A7 :102930000000000000000000000000000000000097 :102940000000000000000000000000000000000087 :102950000000000000000000000000000000000077 :102960000000000000000000000000000000000067 :102970000000000000000000000000000000000057 :102980000000000000000000000000000000000047 :102990000000000000000000000000000000000037 :1029A0000000000000000000000000000000000027 :1029B0000000000000000000000000000000000017 :1029C0000000000000000000000000000000000007 :1029D00000000000000000000000000000000000F7 :1029E00000000000000000000000000000000000E7 :1029F00000000000000000000000000000000000D7 :102A000000000000000000000000000000000000C6 :102A100000000000000000000000000000000000B6 :102A200000000000000000000000000000000000A6 :102A30000000000000000000000000000000000096 :102A40000000000000000000000000000000000086 :102A50000000000000000000000000000000000076 :102A60000000000000000000000000000000000066 :102A70000000000000000000000000000000000056 :102A80000000000000000000000000000000000046 :102A90000000000000000000000000000000000036 :102AA0000000000000000000000000000000000026 :102AB0000000000000000000000000000000000016 :102AC0000000000000000000000000000000000006 :102AD00000000000000000000000000000000000F6 :102AE00000000000000000000000000000000000E6 :102AF00000000000000000000000000000000000D6 :102B000000000000000000000000000000000000C5 :102B100000000000000000000000000000000000B5 :102B200000000000000000000000000000000000A5 :102B30000000000000000000000000000000000095 :102B40000000000000000000000000000000000085 :102B50000000000000000000000000000000000075 :102B60000000000000000000000000000000000065 :102B70000000000000000000000000000000000055 :102B80000000000000000000000000000000000045 :102B90000000000000000000000000000000000035 :102BA0000000000000000000000000000000000025 :102BB0000000000000000000000000000000000015 :102BC0000000000000000000000000000000000005 :102BD00000000000000000000000000000000000F5 :102BE00000000000000000000000000000000000E5 :102BF00000000000000000000000000000000000D5 :102C000000000000000000000000000000000000C4 :102C100000000000000000000000000000000000B4 :102C200000000000000000000000000000000000A4 :102C30000000000000000000000000000000000094 :102C40000000000000000000000000000000000084 :102C50000000000000000000000000000000000074 :102C60000000000000000000000000000000000064 :102C70000000000000000000000000000000000054 :102C80000000000000000000000000000000000044 :102C90000000000000000000000000000000000034 :102CA0000000000000000000000000000000000024 :102CB0000000000000000000000000000000000014 :102CC0000000000000000000000000000000000004 :102CD00000000000000000000000000000000000F4 :102CE00000000000000000000000000000000000E4 :102CF00000000000000000000000000000000000D4 :102D000000000000000000000000000000000000C3 :102D100000000000000000000000000000000000B3 :102D200000000000000000000000000000000000A3 :102D30000000000000000000000000000000000093 :102D40000000000000000000000000000000000083 :102D50000000000000000000000000000000000073 :102D60000000000000000000000000000000000063 :102D70000000000000000000000000000000000053 :102D80000000000000000000000000000000000043 :102D90000000000000000000000000000000000033 :102DA0000000000000000000000000000000000023 :102DB0000000000000000000000000000000000013 :102DC0000000000000000000000000000000000003 :102DD00000000000000000000000000000000000F3 :102DE00000000000000000000000000000000000E3 :102DF00000000000000000000000000000000000D3 :102E000000000000000000000000000000000000C2 :102E100000000000000000000000000000000000B2 :102E200000000000000000000000000000000000A2 :102E30000000000000000000000000000000000092 :102E40000000000000000000000000000000000082 :102E50000000000000000000000000000000000072 :102E60000000000000000000000000000000000062 :102E70000000000000000000000000000000000052 :102E80000000000000000000000000000000000042 :102E90000000000000000000000000000000000032 :102EA0000000000000000000000000000000000022 :102EB0000000000000000000000000000000000012 :102EC0000000000000000000000000000000000002 :102ED00000000000000000000000000000000000F2 :102EE00000000000000000000000000000000000E2 :102EF00000000000000000000000000000000000D2 :102F000000000000000000000000000000000000C1 :102F100000000000000000000000000000000000B1 :102F200000000000000000000000000000000000A1 :102F30000000000000000000000000000000000091 :102F40000000000000000000000000000000000081 :102F50000000000000000000000000000000000071 :102F60000000000000000000000000000000000061 :102F70000000000000000000000000000000000051 :102F80000000000000000000000000000000000041 :102F90000000000000000000000000000000000031 :102FA0000000000000000000000000000000000021 :102FB0000000000000000000000000000000000011 :102FC0000000000000000000000000000000000001 :102FD00000000000000000000000000000000000F1 :102FE00000000000000000000000000000000000E1 :102FF00000000000000000000000000000000000D1 :1030000000000000000000000000000000000000C0 :1030100000000000000000000000000000000000B0 :1030200000000000000000000000000000000000A0 :103030000000000000000000000000000000000090 :103040000000000000000000000000000000000080 :103050000000000000000000000000000000000070 :103060000000000000000000000000000000000060 :103070000000000000000000000000000000000050 :103080000000000000000000000000000000000040 :103090000000000000000000000000000000000030 :1030A0000000000000000000000000000000000020 :1030B0000000000000000000000000000000000010 :1030C0000000000000000000000000000000000000 :1030D00000000000000000000000000000000000F0 :1030E00000000000000000000000000000000000E0 :1030F00000000000000000000000000000000000D0 :1031000000000000000000000000000000000000BF :1031100000000000000000000000000000000000AF :10312000000000000000000000000000000000009F :10313000000000000000000000000000000000008F :10314000000000000000000000000000000000007F :10315000000000000000000000000000000000006F :10316000000000000000000000000000000000005F :10317000000000000000000000000000000000004F :10318000000000000000000000000000000000003F :10319000000000000000000000000000000000002F :1031A000000000000000000000000000000000001F :1031B000000000000000000000000000000000000F :1031C00000000000000000000000000000000000FF :1031D00000000000000000000000000000000000EF :1031E00000000000000000000000000000000000DF :1031F00000000000000000000000000000000000CF :1032000000000000000000000000000000000000BE :1032100000000000000000000000000000000000AE :10322000000000000000000000000000000000009E :10323000000000000000000000000000000000008E :10324000000000000000000000000000000000007E :10325000000000000000000000000000000000006E :10326000000000000000000000000000000000005E :10327000000000000000000000000000000000004E :10328000000000000000000000000000000000003E :10329000000000000000000000000000000000002E :1032A000000000000000000000000000000000001E :1032B000000000000000000000000000000000000E :1032C00000000000000000000000000000000000FE :1032D00000000000000000000000000000000000EE :1032E00000000000000000000000000000000000DE :1032F00000000000000000000000000000000000CE :1033000000000000000000000000000000000000BD :1033100000000000000000000000000000000000AD :10332000000000000000000000000000000000009D :10333000000000000000000000000000000000008D :10334000000000000000000000000000000000007D :10335000000000000000000000000000000000006D :10336000000000000000000000000000000000005D :10337000000000000000000000000000000000004D :10338000000000000000000000000000000000003D :10339000000000000000000000000000000000002D :1033A000000000000000000000000000000000001D :1033B000000000000000000000000000000000000D :1033C00000000000000000000000000000000000FD :1033D00000000000000000000000000000000000ED :1033E00000000000000000000000000000000000DD :1033F00000000000000000000000000000000000CD :1034000000000000000000000000000000000000BC :1034100000000000000000000000000000000000AC :10342000000000000000000000000000000000009C :10343000000000000000000000000000000000008C :10344000000000000000000000000000000000007C :10345000000000000000000000000000000000006C :10346000000000000000000000000000000000005C :10347000000000000000000000000000000000004C :10348000000000000000000000000000000000003C :10349000000000000000000000000000000000002C :1034A000000000000000000000000000000000001C :1034B000000000000000000000000000000000000C :1034C00000000000000000000000000000000000FC :1034D00000000000000000000000000000000000EC :1034E00000000000000000000000000000000000DC :1034F00000000000000000000000000000000000CC :1035000000000000000000000000000000000000BB :1035100000000000000000000000000000000000AB :10352000000000000000000000000000000000009B :10353000000000000000000000000000000000008B :10354000000000000000000000000000000000007B :10355000000000000000000000000000000000006B :10356000000000000000000000000000000000005B :10357000000000000000000000000000000000004B :10358000000000000000000000000000000000003B :10359000000000000000000000000000000000002B :1035A000000000000000000000000000000000001B :1035B000000000000000000000000000000000000B :1035C00000000000000000000000000000000000FB :1035D00000000000000000000000000000000000EB :1035E00000000000000000000000000000000000DB :1035F00000000000000000000000000000000000CB :1036000000000000000000000000000000000000BA :1036100000000000000000000000000000000000AA :10362000000000000000000000000000000000009A :10363000000000000000000000000000000000008A :10364000000000000000000000000000000000007A :10365000000000000000000000000000000000006A :10366000000000000000000000000000000000005A :10367000000000000000000000000000000000004A :10368000000000000000000000000000000000003A :10369000000000000000000000000000000000002A :1036A000000000000000000000000000000000001A :1036B000000000000000000000000000000000000A :1036C00000000000000000000000000000000000FA :1036D00000000000000000000000000000000000EA :1036E00000000000000000000000000000000000DA :1036F00000000000000000000000000000000000CA :1037000000000000000000000000000000000000B9 :1037100000000000000000000000000000000000A9 :103720000000000000000000000000000000000099 :103730000000000000000000000000000000000089 :103740000000000000000000000000000000000079 :103750000000000000000000000000000000000069 :103760000000000000000000000000000000000059 :103770000000000000000000000000000000000049 :103780000000000000000000000000000000000039 :103790000000000000000000000000000000000029 :1037A0000000000000000000000000000000000019 :1037B0000000000000000000000000000000000009 :1037C00000000000000000000000000000000000F9 :1037D00000000000000000000000000000000000E9 :1037E00000000000000000000000000000000000D9 :1037F00000000000000000000000000000000000C9 :1038000000000000000000000000000000000000B8 :1038100000000000000000000000000000000000A8 :103820000000000000000000000000000000000098 :103830000000000000000000000000000000000088 :103840000000000000000000000000000000000078 :103850000000000000000000000000000000000068 :103860000000000000000000000000000000000058 :103870000000000000000000000000000000000048 :103880000000000000000000000000000000000038 :103890000000000000000000000000000000000028 :1038A0000000000000000000000000000000000018 :1038B0000000000000000000000000000000000008 :1038C00000000000000000000000000000000000F8 :1038D00000000000000000000000000000000000E8 :1038E00000000000000000000000000000000000D8 :1038F00000000000000000000000000000000000C8 :1039000000000000000000000000000000000000B7 :1039100000000000000000000000000000000000A7 :103920000000000000000000000000000000000097 :103930000000000000000000000000000000000087 :103940000000000000000000000000000000000077 :103950000000000000000000000000000000000067 :103960000000000000000000000000000000000057 :103970000000000000000000000000000000000047 :103980000000000000000000000000000000000037 :103990000000000000000000000000000000000027 :1039A0000000000000000000000000000000000017 :1039B0000000000000000000000000000000000007 :1039C00000000000000000000000000000000000F7 :1039D00000000000000000000000000000000000E7 :1039E00000000000000000000000000000000000D7 :1039F00000000000000000000000000000000000C7 :103A000000000000000000000000000000000000B6 :103A100000000000000000000000000000000000A6 :103A20000000000000000000000000000000000096 :103A30000000000000000000000000000000000086 :103A40000000000000000000000000000000000076 :103A50000000000000000000000000000000000066 :103A60000000000000000000000000000000000056 :103A70000000000000000000000000000000000046 :103A80000000000000000000000000000000000036 :103A90000000000000000000000000000000000026 :103AA0000000000000000000000000000000000016 :103AB0000000000000000000000000000000000006 :103AC00000000000000000000000000000000000F6 :103AD00000000000000000000000000000000000E6 :103AE00000000000000000000000000000000000D6 :103AF00000000000000000000000000000000000C6 :103B000000000000000000000000000000000000B5 :103B100000000000000000000000000000000000A5 :103B20000000000000000000000000000000000095 :103B30000000000000000000000000000000000085 :103B40000000000000000000000000000000000075 :103B50000000000000000000000000000000000065 :103B60000000000000000000000000000000000055 :103B70000000000000000000000000000000000045 :103B80000000000000000000000000000000000035 :103B90000000000000000000000000000000000025 :103BA0000000000000000000000000000000000015 :103BB0000000000000000000000000000000000005 :103BC00000000000000000000000000000000000F5 :103BD00000000000000000000000000000000000E5 :103BE00000000000000000000000000000000000D5 :103BF00000000000000000000000000000000000C5 :103C000000000000000000000000000000000000B4 :103C100000000000000000000000000000000000A4 :103C20000000000000000000000000000000000094 :103C30000000000000000000000000000000000084 :103C40000000000000000000000000000000000074 :103C50000000000000000000000000000000000064 :103C60000000000000000000000000000000000054 :103C70000000000000000000000000000000000044 :103C80000000000000000000000000000000000034 :103C90000000000000000000000000000000000024 :103CA0000000000000000000000000000000000014 :103CB0000000000000000000000000000000000004 :103CC00000000000000000000000000000000000F4 :103CD00000000000000000000000000000000000E4 :103CE00000000000000000000000000000000000D4 :103CF00000000000000000000000000000000000C4 :103D000000000000000000000000000000000000B3 :103D100000000000000000000000000000000000A3 :103D20000000000000000000000000000000000093 :103D30000000000000000000000000000000000083 :103D40000000000000000000000000000000000073 :103D50000000000000000000000000000000000063 :103D60000000000000000000000000000000000053 :103D70000000000000000000000000000000000043 :103D80000000000000000000000000000000000033 :103D90000000000000000000000000000000000023 :103DA0000000000000000000000000000000000013 :103DB0000000000000000000000000000000000003 :103DC00000000000000000000000000000000000F3 :103DD00000000000000000000000000000000000E3 :103DE00000000000000000000000000000000000D3 :103DF00000000000000000000000000000000000C3 :103E000000000000000000000000000000000000B2 :103E100000000000000000000000000000000000A2 :103E20000000000000000000000000000000000092 :103E30000000000000000000000000000000000082 :103E40000000000000000000000000000000000072 :103E50000000000000000000000000000000000062 :103E60000000000000000000000000000000000052 :103E70000000000000000000000000000000000042 :103E80000000000000000000000000000000000032 :103E90000000000000000000000000000000000022 :103EA0000000000000000000000000000000000012 :103EB0000000000000000000000000000000000002 :103EC00000000000000000000000000000000000F2 :103ED00000000000000000000000000000000000E2 :103EE00000000000000000000000000000000000D2 :103EF00000000000000000000000000000000000C2 :103F000000000000000000000000000000000000B1 :103F100000000000000000000000000000000000A1 :103F20000000000000000000000000000000000091 :103F30000000000000000000000000000000000081 :103F40000000000000000000000000000000000071 :103F50000000000000000000000000000000000061 :103F60000000000000000000000000000000000051 :103F70000000000000000000000000000000000041 :103F80000000000000000000000000000000000031 :103F90000000000000000000000000000000000021 :103FA0000000000000000000000000000000000011 :103FB0000000000000000000000000000000000001 :103FC00000000000000000000000000000000000F1 :103FD00000000000000000000000000000000000E1 :103FE00000000000000000000000000000000000D1 :103FF00000000000000000000000000000000000C1 :1040000000000000000000000000000000000000B0 :1040100000000000000000000000000000000000A0 :104020000000000000000000000000000000000090 :104030000000000000000000000000000000000080 :104040000000000000000000000000000000000070 :104050000000000000000000000000000000000060 :104060000000000000000000000000000000000050 :104070000000000000000000000000000000000040 :104080000000000000000000000000000000000030 :104090000000000000000000000000000000000020 :1040A0000000000000000000000000000000000010 :1040B0000000000000000000000000000000000000 :1040C00000000000000000000000000000000000F0 :1040D00000000000000000000000000000000000E0 :1040E00000000000000000000000000000000000D0 :1040F00000000000000000000000000000000000C0 :1041000000000000000000000000000000000000AF :10411000000000000000000000000000000000009F :10412000000000000000000000000000000000008F :10413000000000000000000000000000000000007F :10414000000000000000000000000000000000006F :10415000000000000000000000000000000000005F :10416000000000000000000000000000000000004F :10417000000000000000000000000000000000003F :10418000000000000000000000000000000000002F :10419000000000000000000000000000000000001F :1041A000000000000000000000000000000000000F :1041B00000000000000000000000000000000000FF :1041C00000000000000000000000000000000000EF :1041D00000000000000000000000000000000000DF :1041E00000000000000000000000000000000000CF :1041F00000000000000000000000000000000000BF :1042000000000000000000000000000000000000AE :10421000000000000000000000000000000000009E :10422000000000000000000000000000000000008E :10423000000000000000000000000000000000007E :10424000000000000000000000000000000000006E :10425000000000000000000000000000000000005E :10426000000000000000000000000000000000004E :10427000000000000000000000000000000000003E :10428000000000000000000000000000000000002E :10429000000000000000000000000000000000001E :1042A000000000000000000000000000000000000E :1042B00000000000000000000000000000000000FE :1042C00000000000000000000000000000000000EE :1042D00000000000000000000000000000000000DE :1042E00000000000000000000000000000000000CE :1042F00000000000000000000000000000000000BE :1043000000000000000000000000000000000000AD :10431000000000000000000000000000000000009D :10432000000000000000000000000000000000008D :10433000000000000000000000000000000000007D :10434000000000000000000000000000000000006D :10435000000000000000000000000000000000005D :10436000000000000000000000000000000000004D :10437000000000000000000000000000000000003D :10438000000000000000000000000000000000002D :10439000000000000000000000000000000000001D :1043A000000000000000000000000000000000000D :1043B00000000000000000000000000000000000FD :1043C00000000000000000000000000000000000ED :1043D00000000000000000000000000000000000DD :1043E00000000000000000000000000000000000CD :1043F00000000000000000000000000000000000BD :1044000000000000000000000000000000000000AC :10441000000000000000000000000000000000009C :10442000000000000000000000000000000000008C :10443000000000000000000000000000000000007C :10444000000000000000000000000000000000006C :10445000000000000000000000000000000000005C :10446000000000000000000000000000000000004C :10447000000000000000000000000000000000003C :10448000000000000000000000000000000000002C :10449000000000000000000000000000000000001C :1044A000000000000000000000000000000000000C :1044B00000000000000000000000000000000000FC :1044C00000000000000000000000000000000000EC :1044D00000000000000000000000000000000000DC :1044E00000000000000000000000000000000000CC :1044F00000000000000000000000000000000000BC :1045000000000000000000000000000000000000AB :10451000000000000000000000000000000000009B :10452000000000000000000000000000000000008B :10453000000000000000000000000000000000007B :10454000000000000000000000000000000000006B :10455000000000000000000000000000000000005B :10456000000000000000000000000000000000004B :10457000000000000000000000000000000000003B :10458000000000000000000000000000000000002B :10459000000000000000000000000000000000001B :1045A000000000000000000000000000000000000B :1045B00000000000000000000000000000000000FB :1045C00000000000000000000000000000000000EB :1045D00000000000000000000000000000000000DB :1045E00000000000000000000000000000000000CB :1045F00000000000000000000000000000000000BB :1046000000000000000000000000000000000000AA :10461000000000000000000000000000000000009A :10462000000000000000000000000000000000008A :10463000000000000000000000000000000000007A :10464000000000000000000000000000000000006A :10465000000000000000000000000000000000005A :10466000000000000000000000000000000000004A :10467000000000000000000000000000000000003A :10468000000000000000000000000000000000002A :10469000000000000000000000000000000000001A :1046A000000000000000000000000000000000000A :1046B00000000000000000000000000000000000FA :1046C00000000000000000000000000000000000EA :1046D00000000000000000000000000000000000DA :1046E00000000000000000000000000000000000CA :1046F00000000000000000000000000000000000BA :1047000000000000000000000000000000000000A9 :104710000000000000000000000000000000000099 :104720000000000000000000000000000000000089 :104730000000000000000000000000000000000079 :104740000000000000000000000000000000000069 :104750000000000000000000000000000000000059 :104760000000000000000000000000000000000049 :104770000000000000000000000000000000000039 :104780000000000000000000000000000000000029 :104790000000000000000000000000000000000019 :1047A0000000000000000000000000000000000009 :1047B00000000000000000000000000000000000F9 :1047C00000000000000000000000000000000000E9 :1047D00000000000000000000000000000000000D9 :1047E00000000000000000000000000000000000C9 :1047F00000000000000000000000000000000000B9 :1048000000000000000000000000000000000000A8 :104810000000000000000000000000000000000098 :104820000000000000000000000000000000000088 :104830000000000000000000000000000000000078 :104840000000000000000000000000000000000068 :104850000000000000000000000000000000000058 :104860000000000000000000000000000000000048 :104870000000000000000000000000000000000038 :104880000000000000000000000000000000000028 :104890000000000000000000000000000000000018 :1048A0000000000000000000000000000000000008 :1048B00000000000000000000000000000000000F8 :1048C00000000000000000000000000000000000E8 :1048D00000000000000000000000000000000000D8 :1048E00000000000000000000000000000000000C8 :1048F00000000000000000000000000000000000B8 :1049000000000000000000000000000000000000A7 :104910000000000000000000000000000000000097 :104920000000000000000000000000000000000087 :104930000000000000000000000000000000000077 :104940000000000000000000000000000000000067 :104950000000000000000000000000000000000057 :104960000000000000000000000000000000000047 :104970000000000000000000000000000000000037 :104980000000000000000000000000000000000027 :104990000000000000000000000000000000000017 :1049A0000000000000000000000000000000000007 :1049B00000000000000000000000000000000000F7 :1049C00000000000000000000000000000000000E7 :1049D00000000000000000000000000000000000D7 :1049E00000000000000000000000000000000000C7 :1049F00000000000000000000000000000000000B7 :104A000000000000000000000000000000000000A6 :104A10000000000000000000000000000000000096 :104A20000000000000000000000000000000000086 :104A30000000000000000000000000000000000076 :104A40000000000000000000000000000000000066 :104A50000000000000000000000000000000000056 :104A60000000000000000000000000000000000046 :104A70000000000000000000000000000000000036 :104A80000000000000000000000000000000000026 :104A90000000000000000000000000000000000016 :104AA0000000000000000000000000000000000006 :104AB00000000000000000000000000000000000F6 :104AC00000000000000000000000000000000000E6 :104AD00000000000000000000000000000000000D6 :104AE00000000000000000000000000000000000C6 :104AF00000000000000000000000000000000000B6 :104B000000000000000000000000000000000000A5 :104B10000000000000000000000000000000000095 :104B20000000000000000000000000000000000085 :104B30000000000000000000000000000000000075 :104B40000000000000000000000000000000000065 :104B50000000000000000000000000000000000055 :104B60000000000000000000000000000000000045 :104B70000000000000000000000000000000000035 :104B80000000000000000000000000000000000025 :104B90000000000000000000000000000000000015 :104BA0000000000000000000000000000000000005 :104BB00000000000000000000000000000000000F5 :104BC00000000000000000000000000000000000E5 :104BD00000000000000000000000000000000000D5 :104BE00000000000000000000000000000000000C5 :104BF00000000000000000000000000000000000B5 :104C000000000000000000000000000000000000A4 :104C10000000000000000000000000000000000094 :104C20000000000000000000000000000000000084 :104C30000000000000000000000000000000000074 :104C40000000000000000000000000000000000064 :104C50000000000000000000000000000000000054 :104C60000000000000000000000000000000000044 :104C70000000000000000000000000000000000034 :104C80000000000000000000000000000000000024 :104C90000000000000000000000000000000000014 :104CA0000000000000000000000000000000000004 :104CB00000000000000000000000000000000000F4 :104CC00000000000000000000000000000000000E4 :104CD00000000000000000000000000000000000D4 :104CE00000000000000000000000000000000000C4 :104CF00000000000000000000000000000000000B4 :104D000000000000000000000000000000000000A3 :104D10000000000000000000000000000000000093 :104D20000000000000000000000000000000000083 :104D30000000000000000000000000000000000073 :104D40000000000000000000000000000000000063 :104D50000000000000000000000000000000000053 :104D60000000000000000000000000000000000043 :104D70000000000000000000000000000000000033 :104D80000000000000000000000000000000000023 :104D90000000000000000000000000000000000013 :104DA0000000000000000000000000000000000003 :104DB00000000000000000000000000000000000F3 :104DC00000000000000000000000000000000000E3 :104DD00000000000000000000000000000000000D3 :104DE00000000000000000000000000000000000C3 :104DF00000000000000000000000000000000000B3 :104E000000000000000000000000000000000000A2 :104E10000000000000000000000000000000000092 :104E20000000000000000000000000000000000082 :104E30000000000000000000000000000000000072 :104E40000000000000000000000000000000000062 :104E50000000000000000000000000000000000052 :104E60000000000000000000000000000000000042 :104E70000000000000000000000000000000000032 :104E80000000000000000000000000000000000022 :104E90000000000000000000000000000000000012 :104EA0000000000000000000000000000000000002 :104EB00000000000000000000000000000000000F2 :104EC00000000000000000000000000000000000E2 :104ED00000000000000000000000000000000000D2 :104EE00000000000000000000000000000000000C2 :104EF00000000000000000000000000000000000B2 :104F000000000000000000000000000000000000A1 :104F10000000000000000000000000000000000091 :104F20000000000000000000000000000000000081 :104F30000000000000000000000000000000000071 :104F40000000000000000000000000000000000061 :104F50000000000000000000000000000000000051 :104F60000000000000000000000000000000000041 :104F70000000000000000000000000000000000031 :104F80000000000000000000000000000000000021 :104F90000000000000000000000000000000000011 :104FA0000000000000000000000000000000000001 :104FB00000000000000000000000000000000000F1 :104FC00000000000000000000000000000000000E1 :104FD00000000000000000000000000000000000D1 :104FE00000000000000000000000000000000000C1 :104FF00000000000000000000000000000000000B1 :1050000000000000000000000000000000000000A0 :105010000000000000000000000000000000000090 :105020000000000000000000000000000000000080 :105030000000000000000000000000000000000070 :105040000000000000000000000000000000000060 :105050000000000000000000000000000000000050 :105060000000000000000000000000000000000040 :105070000000000000000000000000000000000030 :105080000000000000000000000000000000000020 :105090000000000000000000000000000000000010 :1050A0000000000000000000000000000000000000 :1050B00000000000000000000000000000000000F0 :1050C00000000000000000000000000000000000E0 :1050D00000000000000000000000000000000000D0 :1050E00000000000000000000000000000000000C0 :1050F00000000000000000000000000000000000B0 :10510000000000000000000000000000000000009F :10511000000000000000000000000000000000008F :10512000000000000000000000000000000000007F :10513000000000000000000000000000000000006F :10514000000000000000000000000000000000005F :10515000000000000000000000000000000000004F :10516000000000000000000000000000000000003F :10517000000000000000000000000000000000002F :10518000000000000000000000000000000000001F :10519000000000000000000000000000000000000F :1051A00000000000000000000000000000000000FF :1051B00000000000000000000000000000000000EF :1051C00000000000000000000000000000000000DF :1051D00000000000000000000000000000000000CF :1051E00000000000000000000000000000000000BF :1051F00000000000000000000000000000000000AF :10520000000000000000000000000000000000009E :10521000000000000000000000000000000000008E :10522000000000000000000000000000000000007E :10523000000000000000000000000000000000006E :10524000000000000000000000000000000000005E :10525000000000000000000000000000000000004E :10526000000000000000000000000000000000003E :10527000000000000000000000000000000000002E :10528000000000000000000000000000000000001E :10529000000000000000000000000000000000000E :1052A00000000000000000000000000000000000FE :1052B00000000000000000000000000000000000EE :1052C00000000000000000000000000000000000DE :1052D00000000000000000000000000000000000CE :1052E00000000000000000000000000000000000BE :1052F00000000000000000000000000000000000AE :10530000000000000000000000000000000000009D :10531000000000000000000000000000000000008D :10532000000000000000000000000000000000007D :10533000000000000000000000000000000000006D :10534000000000000000000000000000000000005D :10535000000000000000000000000000000000004D :10536000000000000000000000000000000000003D :10537000000000000000000000000000000000002D :10538000000000000000000000000000000000001D :10539000000000000000000000000000000000000D :1053A00000000000000000000000000000000000FD :1053B00000000000000000000000000000000000ED :1053C00000000000000000000000000000000000DD :1053D00000000000000000000000000000000000CD :1053E00000000000000000000000000000000000BD :1053F00000000000000000000000000000000000AD :10540000000000000000000000000000000000009C :10541000000000000000000000000000000000008C :10542000000000000000000000000000000000007C :10543000000000000000000000000000000000006C :10544000000000000000000000000000000000005C :10545000000000000000000000000000000000004C :10546000000000000000000000000000000000003C :10547000000000000000000000000000000000002C :10548000000000000000000000000000000000001C :10549000000000000000000000000000000000000C :1054A00000000000000000000000000000000000FC :1054B00000000000000000000000000000000000EC :1054C00000000000000000000000000000000000DC :1054D00000000000000000000000000000000000CC :1054E00000000000000000000000000000000000BC :1054F00000000000000000000000000000000000AC :10550000000000000000000000000000000000009B :10551000000000000000000000000000000000008B :10552000000000000000000000000000000000007B :10553000000000000000000000000000000000006B :10554000000000000000000000000000000000005B :10555000000000000000000000000000000000004B :10556000000000000000000000000000000000003B :10557000000000000000000000000000000000002B :10558000000000000000000000000000000000001B :10559000000000000000000000000000000000000B :1055A00000000000000000000000000000000000FB :1055B00000000000000000000000000000000000EB :1055C00000000000000000000000000000000000DB :1055D00000000000000000000000000000000000CB :1055E00000000000000000000000000000000000BB :1055F00000000000000000000000000000000000AB :10560000000000000000000000000000000000009A :10561000000000000000000000000000000000008A :10562000000000000000000000000000000000007A :10563000000000000000000000000000000000006A :10564000000000000000000000000000000000005A :10565000000000000000000000000000000000004A :10566000000000000000000000000000000000003A :10567000000000000000000000000000000000002A :10568000000000000000000000000000000000001A :10569000000000000000000000000000000000000A :1056A00000000000000000000000000000000000FA :1056B00000000000000000000000000000000000EA :1056C00000000000000000000000000000000000DA :1056D00000000000000000000000000000000000CA :1056E00000000000000000000000000000000000BA :1056F00000000000000000000000000000000000AA :105700000000000000000000000000000000000099 :105710000000000000000000000000000000000089 :105720000000000000000000000000000000000079 :105730000000000000000000000000000000000069 :105740000000000000000000000000000000000059 :105750000000000000000000000000000000000049 :105760000000000000000000000000000000000039 :105770000000000000000000000000000000000029 :105780000000000000000000000000000000000019 :105790000000000000000000000000000000000009 :1057A00000000000000000000000000000000000F9 :1057B00000000000000000000000000000000000E9 :1057C00000000000000000000000000000000000D9 :1057D00000000000000000000000000000000000C9 :1057E00000000000000000000000000000000000B9 :1057F00000000000000000000000000000000000A9 :105800000000000000000000000000000000000098 :105810000000000000000000000000000000000088 :105820000000000000000000000000000000000078 :105830000000000000000000000000000000000068 :105840000000000000000000000000000000000058 :105850000000000000000000000000000000000048 :105860000000000000000000000000000000000038 :105870000000000000000000000000000000000028 :105880000000000000000000000000000000000018 :105890000000000000000000000000000000000008 :1058A00000000000000000000000000000000000F8 :1058B00000000000000000000000000000000000E8 :1058C00000000000000000000000000000000000D8 :1058D00000000000000000000000000000000000C8 :1058E00000000000000000000000000000000000B8 :1058F00000000000000000000000000000000000A8 :105900000000000000000000000000000000000097 :105910000000000000000000000000000000000087 :105920000000000000000000000000000000000077 :105930000000000000000000000000000000000067 :105940000000000000000000000000000000000057 :105950000000000000000000000000000000000047 :105960000000000000000000000000000000000037 :105970000000000000000000000000000000000027 :105980000000000000000000000000000000000017 :105990000000000000000000000000000000000007 :1059A00000000000000000000000000000000000F7 :1059B00000000000000000000000000000000000E7 :1059C00000000000000000000000000000000000D7 :1059D00000000000000000000000000000000000C7 :1059E00000000000000000000000000000000000B7 :1059F00000000000000000000000000000000000A7 :105A00000000000000000000000000000000000096 :105A10000000000000000000000000000000000086 :105A20000000000000000000000000000000000076 :105A30000000000000000000000000000000000066 :105A40000000000000000000000000000000000056 :105A50000000000000000000000000000000000046 :105A60000000000000000000000000000000000036 :105A70000000000000000000000000000000000026 :105A80000000000000000000000000000000000016 :105A90000000000000000000000000000000000006 :105AA00000000000000000000000000000000000F6 :105AB00000000000000000000000000000000000E6 :105AC00000000000000000000000000000000000D6 :105AD00000000000000000000000000000000000C6 :105AE00000000000000000000000000000000000B6 :105AF00000000000000000000000000000000000A6 :105B00000000000000000000000000000000000095 :105B10000000000000000000000000000000000085 :105B20000000000000000000000000000000000075 :105B30000000000000000000000000000000000065 :105B40000000000000000000000000000000000055 :105B50000000000000000000000000000000000045 :105B60000000000000000000000000000000000035 :105B70000000000000000000000000000000000025 :105B80000000000000000000000000000000000015 :105B90000000000000000000000000000000000005 :105BA00000000000000000000000000000000000F5 :105BB00000000000000000000000000000000000E5 :105BC00000000000000000000000000000000000D5 :105BD00000000000000000000000000000000000C5 :105BE00000000000000000000000000000000000B5 :105BF00000000000000000000000000000000000A5 :105C00000000000000000000000000000000000094 :105C10000000000000000000000000000000000084 :105C20000000000000000000000000000000000074 :105C30000000000000000000000000000000000064 :105C40000000000000000000000000000000000054 :105C50000000000000000000000000000000000044 :105C60000000000000000000000000000000000034 :105C70000000000000000000000000000000000024 :105C80000000000000000000000000000000000014 :105C90000000000000000000000000000000000004 :105CA00000000000000000000000000000000000F4 :105CB00000000000000000000000000000000000E4 :105CC00000000000000000000000000000000000D4 :105CD00000000000000000000000000000000000C4 :105CE00000000000000000000000000000000000B4 :105CF00000000000000000000000000000000000A4 :105D00000000000000000000000000000000000093 :105D10000000000000000000000000000000000083 :105D20000000000000000000000000000000000073 :105D30000000000000000000000000000000000063 :105D40000000000000000000000000000000000053 :105D50000000000000000000000000000000000043 :105D60000000000000000000000000000000000033 :105D70000000000000000000000000000000000023 :105D80000000000000000000000000000000000013 :105D90000000000000000000000000000000000003 :105DA00000000000000000000000000000000000F3 :105DB00000000000000000000000000000000000E3 :105DC00000000000000000000000000000000000D3 :105DD00000000000000000000000000000000000C3 :105DE00000000000000000000000000000000000B3 :105DF00000000000000000000000000000000000A3 :105E00000000000000000000000000000000000092 :105E10000000000000000000000000000000000082 :105E20000000000000000000000000000000000072 :105E30000000000000000000000000000000000062 :105E40000000000000000000000000000000000052 :105E50000000000000000000000000000000000042 :105E60000000000000000000000000000000000032 :105E70000000000000000000000000000000000022 :105E80000000000000000000000000000000000012 :105E90000000000000000000000000000000000002 :105EA00000000000000000000000000000000000F2 :105EB00000000000000000000000000000000000E2 :105EC00000000000000000000000000000000000D2 :105ED00000000000000000000000000000000000C2 :105EE00000000000000000000000000000000000B2 :105EF00000000000000000000000000000000000A2 :105F00000000000000000000000000000000000091 :105F10000000000000000000000000000000000081 :105F20000000000000000000000000000000000071 :105F30000000000000000000000000000000000061 :105F40000000000000000000000000000000000051 :105F50000000000000000000000000000000000041 :105F60000000000000000000000000000000000031 :105F70000000000000000000000000000000000021 :105F80000000000000000000000000000000000011 :105F90000000000000000000000000000000000001 :105FA00000000000000000000000000000000000F1 :105FB00000000000000000000000000000000000E1 :105FC00000000000000000000000000000000000D1 :105FD00000000000000000000000000000000000C1 :105FE00000000000000000000000000000000000B1 :105FF00000000000000000000000000000000000A1 :106000000000000000000000000000000000000090 :106010000000000000000000000000000000000080 :106020000000000000000000000000000000000070 :106030000000000000000000000000000000000060 :106040000000000000000000000000000000000050 :106050000000000000000000000000000000000040 :106060000000000000000000000000000000000030 :106070000000000000000000000000000000000020 :106080000000000000000000000000000000000010 :106090000000000000000000000000000000000000 :1060A00000000000000000000000000000000000F0 :1060B00000000000000000000000000000000000E0 :1060C00000000000000000000000000000000000D0 :1060D00000000000000000000000000000000000C0 :1060E00000000000000000000000000000000000B0 :1060F00000000000000000000000000000000000A0 :10610000000000000000000000000000000000008F :10611000000000000000000000000000000000007F :10612000000000000000000000000000000000006F :10613000000000000000000000000000000000005F :10614000000000000000000000000000000000004F :10615000000000000000000000000000000000003F :10616000000000000000000000000000000000002F :10617000000000000000000000000000000000001F :10618000000000000000000000000000000000000F :1061900000000000000000000000000000000000FF :1061A00000000000000000000000000000000000EF :1061B00000000000000000000000000000000000DF :1061C00000000000000000000000000000000000CF :1061D00000000000000000000000000000000000BF :1061E00000000000000000000000000000000000AF :1061F000000000000000000000000000000000009F :10620000000000000000000000000000000000008E :10621000000000000000000000000000000000007E :10622000000000000000000000000000000000006E :10623000000000000000000000000000000000005E :10624000000000000000000000000000000000004E :10625000000000000000000000000000000000003E :10626000000000000000000000000000000000002E :10627000000000000000000000000000000000001E :10628000000000000000000000000000000000000E :1062900000000000000000000000000000000000FE :1062A00000000000000000000000000000000000EE :1062B00000000000000000000000000000000000DE :1062C00000000000000000000000000000000000CE :1062D00000000000000000000000000000000000BE :1062E00000000000000000000000000000000000AE :1062F000000000000000000000000000000000009E :10630000000000000000000000000000000000008D :10631000000000000000000000000000000000007D :10632000000000000000000000000000000000006D :10633000000000000000000000000000000000005D :10634000000000000000000000000000000000004D :10635000000000000000000000000000000000003D :10636000000000000000000000000000000000002D :10637000000000000000000000000000000000001D :10638000000000000000000000000000000000000D :1063900000000000000000000000000000000000FD :1063A00000000000000000000000000000000000ED :1063B00000000000000000000000000000000000DD :1063C00000000000000000000000000000000000CD :1063D00000000000000000000000000000000000BD :1063E00000000000000000000000000000000000AD :1063F000000000000000000000000000000000009D :10640000000000000000000000000000000000008C :10641000000000000000000000000000000000007C :10642000000000000000000000000000000000006C :10643000000000000000000000000000000000005C :10644000000000000000000000000000000000004C :10645000000000000000000000000000000000003C :10646000000000000000000000000000000000002C :10647000000000000000000000000000000000001C :10648000000000000000000000000000000000000C :1064900000000000000000000000000000000000FC :1064A00000000000000000000000000000000000EC :1064B00000000000000000000000000000000000DC :1064C00000000000000000000000000000000000CC :1064D00000000000000000000000000000000000BC :1064E00000000000000000000000000000000000AC :1064F000000000000000000000000000000000009C :10650000000000000000000000000000000000008B :10651000000000000000000000000000000000007B :10652000000000000000000000000000000000006B :10653000000000000000000000000000000000005B :10654000000000000000000000000000000000004B :10655000000000000000000000000000000000003B :10656000000000000000000000000000000000002B :10657000000000000000000000000000000000001B :10658000000000000000000000000000000000000B :1065900000000000000000000000000000000000FB :1065A00000000000000000000000000000000000EB :1065B00000000000000000000000000000000000DB :1065C00000000000000000000000000000000000CB :1065D00000000000000000000000000000000000BB :1065E00000000000000000000000000000000000AB :1065F000000000000000000000000000000000009B :10660000000000000000000000000000000000008A :10661000000000000000000000000000000000007A :10662000000000000000000000000000000000006A :10663000000000000000000000000000000000005A :10664000000000000000000000000000000000004A :10665000000000000000000000000000000000003A :10666000000000000000000000000000000000002A :10667000000000000000000000000000000000001A :10668000000000000000000000000000000000000A :1066900000000000000000000000000000000000FA :1066A00000000000000000000000000000000000EA :1066B00000000000000000000000000000000000DA :1066C00000000000000000000000000000000000CA :1066D00000000000000000000000000000000000BA :1066E00000000000000000000000000000000000AA :1066F000000000000000000000000000000000009A :106700000000000000000000000000000000000089 :106710000000000000000000000000000000000079 :106720000000000000000000000000000000000069 :106730000000000000000000000000000000000059 :106740000000000000000000000000000000000049 :106750000000000000000000000000000000000039 :106760000000000000000000000000000000000029 :106770000000000000000000000000000000000019 :106780000000000000000000000000000000000009 :1067900000000000000000000000000000000000F9 :1067A00000000000000000000000000000000000E9 :1067B00000000000000000000000000000000000D9 :1067C00000000000000000000000000000000000C9 :1067D00000000000000000000000000000000000B9 :1067E00000000000000000000000000000000000A9 :1067F0000000000000000000000000000000000099 :106800000000000000000000000000000000000088 :106810000000000000000000000000000000000078 :106820000000000000000000000000000000000068 :106830000000000000000000000000000000000058 :106840000000000000000000000000000000000048 :106850000000000000000000000000000000000038 :106860000000000000000000000000000000000028 :106870000000000000000000000000000000000018 :106880000000000000000000000000000000000008 :1068900000000000000000000000000000000000F8 :1068A00000000000000000000000000000000000E8 :1068B00000000000000000000000000000000000D8 :1068C00000000000000000000000000000000000C8 :1068D00000000000000000000000000000000000B8 :1068E00000000000000000000000000000000000A8 :1068F0000000000000000000000000000000000098 :106900000000000000000000000000000000000087 :106910000000000000000000000000000000000077 :106920000000000000000000000000000000000067 :106930000000000000000000000000000000000057 :106940000000000000000000000000000000000047 :106950000000000000000000000000000000000037 :106960000000000000000000000000000000000027 :106970000000000000000000000000000000000017 :106980000000000000000000000000000000000007 :1069900000000000000000000000000000000000F7 :1069A00000000000000000000000000000000000E7 :1069B00000000000000000000000000000000000D7 :1069C00000000000000000000000000000000000C7 :1069D00000000000000000000000000000000000B7 :1069E00000000000000000000000000000000000A7 :1069F0000000000000000000000000000000000097 :106A00000000000000000000000000000000000086 :106A10000000000000000000000000000000000076 :106A20000000000000000000000000000000000066 :106A30000000000000000000000000000000000056 :106A40000000000000000000000000000000000046 :106A50000000000000000000000000000000000036 :106A60000000000000000000000000000000000026 :106A70000000000000000000000000000000000016 :106A80000000000000000000000000000000000006 :106A900000000000000000000000000000000000F6 :106AA00000000000000000000000000000000000E6 :106AB00000000000000000000000000000000000D6 :106AC00000000000000000000000000000000000C6 :106AD00000000000000000000000000000000000B6 :106AE00000000000000000000000000000000000A6 :106AF0000000000000000000000000000000000096 :106B00000000000000000000000000000000000085 :106B10000000000000000000000000000000000075 :106B20000000000000000000000000000000000065 :106B30000000000000000000000000000000000055 :106B40000000000000000000000000000000000045 :106B50000000000000000000000000000000000035 :106B60000000000000000000000000000000000025 :106B70000000000000000000000000000000000015 :106B80000000000000000000000000000000000005 :106B900000000000000000000000000000000000F5 :106BA00000000000000000000000000000000000E5 :106BB00000000000000000000000000000000000D5 :106BC00000000000000000000000000000000000C5 :106BD00000000000000000000000000000000000B5 :106BE00000000000000000000000000000000000A5 :106BF0000000000000000000000000000000000095 :106C00000000000000000000000000000000000084 :106C10000000000000000000000000000000000074 :106C20000000000000000000000000000000000064 :106C30000000000000000000000000000000000054 :106C40000000000000000000000000000000000044 :106C50000000000000000000000000000000000034 :106C60000000000000000000000000000000000024 :106C70000000000000000000000000000000000014 :106C80000000000000000000000000000000000004 :106C900000000000000000000000000000000000F4 :106CA00000000000000000000000000000000000E4 :106CB00000000000000000000000000000000000D4 :106CC00000000000000000000000000000000000C4 :106CD00000000000000000000000000000000000B4 :106CE00000000000000000000000000000000000A4 :106CF0000000000000000000000000000000000094 :106D00000000000000000000000000000000000083 :106D10000000000000000000000000000000000073 :106D20000000000000000000000000000000000063 :106D30000000000000000000000000000000000053 :106D40000000000000000000000000000000000043 :106D50000000000000000000000000000000000033 :106D60000000000000000000000000000000000023 :106D70000000000000000000000000000000000013 :106D80000000000000000000000000000000000003 :106D900000000000000000000000000000000000F3 :106DA00000000000000000000000000000000000E3 :106DB00000000000000000000000000000000000D3 :106DC00000000000000000000000000000000000C3 :106DD00000000000000000000000000000000000B3 :106DE00000000000000000000000000000000000A3 :106DF0000000000000000000000000000000000093 :106E00000000000000000000000000000000000082 :106E10000000000000000000000000000000000072 :106E20000000000000000000000000000000000062 :106E30000000000000000000000000000000000052 :106E40000000000000000000000000000000000042 :106E50000000000000000000000000000000000032 :106E60000000000000000000000000000000000022 :106E70000000000000000000000000000000000012 :106E80000000000000000000000000000000000002 :106E900000000000000000000000000000000000F2 :106EA00000000000000000000000000000000000E2 :106EB00000000000000000000000000000000000D2 :106EC00000000000000000000000000000000000C2 :106ED00000000000000000000000000000000000B2 :106EE00000000000000000000000000000000000A2 :106EF0000000000000000000000000000000000092 :106F00000000000000000000000000000000000081 :106F10000000000000000000000000000000000071 :106F20000000000000000000000000000000000061 :106F30000000000000000000000000000000000051 :106F40000000000000000000000000000000000041 :106F50000000000000000000000000000000000031 :106F60000000000000000000000000000000000021 :106F70000000000000000000000000000000000011 :106F80000000000000000000000000000000000001 :106F900000000000000000000000000000000000F1 :106FA00000000000000000000000000000000000E1 :106FB00000000000000000000000000000000000D1 :106FC00000000000000000000000000000000000C1 :106FD00000000000000000000000000000000000B1 :106FE00000000000000000000000000000000000A1 :106FF0000000000000000000000000000000000091 :107000000000000000000000000000000000000080 :107010000000000000000000000000000000000070 :107020000000000000000000000000000000000060 :107030000000000000000000000000000000000050 :107040000000000000000000000000000000000040 :107050000000000000000000000000000000000030 :107060000000000000000000000000000000000020 :107070000000000000000000000000000000000010 :107080000000000000000000000000000000000000 :1070900000000000000000000000000000000000F0 :1070A00000000000000000000000000000000000E0 :1070B00000000000000000000000000000000000D0 :1070C00000000000000000000000000000000000C0 :1070D00000000000000000000000000000000000B0 :1070E00000000000000000000000000000000000A0 :1070F0000000000000000000000000000000000090 :10710000000000000000000000000000000000007F :10711000000000000000000000000000000000006F :10712000000000000000000000000000000000005F :10713000000000000000000000000000000000004F :10714000000000000000000000000000000000003F :10715000000000000000000000000000000000002F :10716000000000000000000000000000000000001F :10717000000000000000000000000000000000000F :1071800000000000000000000000000000000000FF :1071900000000000000000000000000000000000EF :1071A00000000000000000000000000000000000DF :1071B00000000000000000000000000000000000CF :1071C00000000000000000000000000000000000BF :1071D00000000000000000000000000000000000AF :1071E000000000000000000000000000000000009F :1071F000000000000000000000000000000000008F :10720000000000000000000000000000000000007E :10721000000000000000000000000000000000006E :10722000000000000000000000000000000000005E :10723000000000000000000000000000000000004E :10724000000000000000000000000000000000003E :10725000000000000000000000000000000000002E :10726000000000000000000000000000000000001E :10727000000000000000000000000000000000000E :1072800000000000000000000000000000000000FE :1072900000000000000000000000000000000000EE :1072A00000000000000000000000000000000000DE :1072B00000000000000000000000000000000000CE :1072C00000000000000000000000000000000000BE :1072D00000000000000000000000000000000000AE :1072E000000000000000000000000000000000009E :1072F000000000000000000000000000000000008E :10730000000000000000000000000000000000007D :10731000000000000000000000000000000000006D :10732000000000000000000000000000000000005D :10733000000000000000000000000000000000004D :10734000000000000000000000000000000000003D :10735000000000000000000000000000000000002D :10736000000000000000000000000000000000001D :10737000000000000000000000000000000000000D :1073800000000000000000000000000000000000FD :1073900000000000000000000000000000000000ED :1073A00000000000000000000000000000000000DD :1073B00000000000000000000000000000000000CD :1073C00000000000000000000000000000000000BD :1073D00000000000000000000000000000000000AD :1073E000000000000000000000000000000000009D :1073F000000000000000000000000000000000008D :10740000000000000000000000000000000000007C :10741000000000000000000000000000000000006C :10742000000000000000000000000000000000005C :10743000000000000000000000000000000000004C :10744000000000000000000000000000000000003C :10745000000000000000000000000000000000002C :10746000000000000000000000000000000000001C :10747000000000000000000000000000000000000C :1074800000000000000000000000000000000000FC :1074900000000000000000000000000000000000EC :1074A00000000000000000000000000000000000DC :1074B00000000000000000000000000000000000CC :1074C00000000000000000000000000000000000BC :1074D00000000000000000000000000000000000AC :1074E000000000000000000000000000000000009C :1074F000000000000000000000000000000000008C :10750000000000000000000000000000000000007B :10751000000000000000000000000000000000006B :10752000000000000000000000000000000000005B :10753000000000000000000000000000000000004B :10754000000000000000000000000000000000003B :10755000000000000000000000000000000000002B :10756000000000000000000000000000000000001B :10757000000000000000000000000000000000000B :1075800000000000000000000000000000000000FB :1075900000000000000000000000000000000000EB :1075A00000000000000000000000000000000000DB :1075B00000000000000000000000000000000000CB :1075C00000000000000000000000000000000000BB :1075D00000000000000000000000000000000000AB :1075E000000000000000000000000000000000009B :1075F000000000000000000000000000000000008B :10760000000000000000000000000000000000007A :10761000000000000000000000000000000000006A :10762000000000000000000000000000000000005A :10763000000000000000000000000000000000004A :10764000000000000000000000000000000000003A :10765000000000000000000000000000000000002A :10766000000000000000000000000000000000001A :10767000000000000000000000000000000000000A :1076800000000000000000000000000000000000FA :1076900000000000000000000000000000000000EA :1076A00000000000000000000000000000000000DA :1076B00000000000000000000000000000000000CA :1076C00000000000000000000000000000000000BA :1076D00000000000000000000000000000000000AA :1076E000000000000000000000000000000000009A :1076F000000000000000000000000000000000008A :107700000000000000000000000000000000000079 :107710000000000000000000000000000000000069 :107720000000000000000000000000000000000059 :107730000000000000000000000000000000000049 :107740000000000000000000000000000000000039 :107750000000000000000000000000000000000029 :107760000000000000000000000000000000000019 :107770000000000000000000000000000000000009 :1077800000000000000000000000000000000000F9 :1077900000000000000000000000000000000000E9 :1077A00000000000000000000000000000000000D9 :1077B00000000000000000000000000000000000C9 :1077C00000000000000000000000000000000000B9 :1077D00000000000000000000000000000000000A9 :1077E0000000000000000000000000000000000099 :1077F0000000000000000000000000000000000089 :107800000000000000000000000000000000000078 :107810000000000000000000000000000000000068 :107820000000000000000000000000000000000058 :107830000000000000000000000000000000000048 :107840000000000000000000000000000000000038 :107850000000000000000000000000000000000028 :107860000000000000000000000000000000000018 :107870000000000000000000000000000000000008 :1078800000000000000000000000000000000000F8 :1078900000000000000000000000000000000000E8 :1078A00000000000000000000000000000000000D8 :1078B00000000000000000000000000000000000C8 :1078C00000000000000000000000000000000000B8 :1078D00000000000000000000000000000000000A8 :1078E0000000000000000000000000000000000098 :1078F0000000000000000000000000000000000088 :107900000000000000000000000000000000000077 :107910000000000000000000000000000000000067 :107920000000000000000000000000000000000057 :107930000000000000000000000000000000000047 :107940000000000000000000000000000000000037 :107950000000000000000000000000000000000027 :107960000000000000000000000000000000000017 :107970000000000000000000000000000000000007 :1079800000000000000000000000000000000000F7 :1079900000000000000000000000000000000000E7 :1079A00000000000000000000000000000000000D7 :1079B00000000000000000000000000000000000C7 :1079C00000000000000000000000000000000000B7 :1079D00000000000000000000000000000000000A7 :1079E0000000000000000000000000000000000097 :1079F0000000000000000000000000000000000087 :107A00000000000000000000000000000000000076 :107A10000000000000000000000000000000000066 :107A20000000000000000000000000000000000056 :107A30000000000000000000000000000000000046 :107A40000000000000000000000000000000000036 :107A50000000000000000000000000000000000026 :107A60000000000000000000000000000000000016 :107A70000000000000000000000000000000000006 :107A800000000000000000000000000000000000F6 :107A900000000000000000000000000000000000E6 :107AA00000000000000000000000000000000000D6 :107AB00000000000000000000000000000000000C6 :107AC00000000000000000000000000000000000B6 :107AD00000000000000000000000000000000000A6 :107AE0000000000000000000000000000000000096 :107AF0000000000000000000000000000000000086 :107B00000000000000000000000000000000000075 :107B10000000000000000000000000000000000065 :107B20000000000000000000000000000000000055 :107B30000000000000000000000000000000000045 :107B40000000000000000000000000000000000035 :107B50000000000000000000000000000000000025 :107B60000000000000000000000000000000000015 :107B70000000000000000000000000000000000005 :107B800000000000000000000000000000000000F5 :107B900000000000000000000000000000000000E5 :107BA00000000000000000000000000000000000D5 :107BB00000000000000000000000000000000000C5 :107BC00000000000000000000000000000000000B5 :107BD00000000000000000000000000000000000A5 :107BE0000000000000000000000000000000000095 :107BF0000000000000000000000000000000000085 :107C00000000000000000000000000000000000074 :107C10000000000000000000000000000000000064 :107C20000000000000000000000000000000000054 :107C30000000000000000000000000000000000044 :107C40000000000000000000000000000000000034 :107C50000000000000000000000000000000000024 :107C60000000000000000000000000000000000014 :107C70000000000000000000000000000000000004 :107C800000000000000000000000000000000000F4 :107C900000000000000000000000000000000000E4 :107CA00000000000000000000000000000000000D4 :107CB00000000000000000000000000000000000C4 :107CC00000000000000000000000000000000000B4 :107CD00000000000000000000000000000000000A4 :107CE0000000000000000000000000000000000094 :107CF0000000000000000000000000000000000084 :107D00000000000000000000000000000000000073 :107D10000000000000000000000000000000000063 :107D20000000000000000000000000000000000053 :107D30000000000000000000000000000000000043 :107D40000000000000000000000000000000000033 :107D50000000000000000000000000000000000023 :107D60000000000000000000000000000000000013 :107D70000000000000000000000000000000000003 :107D800000000000000000000000000000000000F3 :107D900000000000000000000000000000000000E3 :107DA00000000000000000000000000000000000D3 :107DB00000000000000000000000000000000000C3 :107DC00000000000000000000000000000000000B3 :107DD00000000000000000000000000000000000A3 :107DE0000000000000000000000000000000000093 :107DF0000000000000000000000000000000000083 :107E00000000000000000000000000000000000072 :107E10000000000000000000000000000000000062 :107E20000000000000000000000000000000000052 :107E30000000000000000000000000000000000042 :107E40000000000000000000000000000000000032 :107E50000000000000000000000000000000000022 :107E60000000000000000000000000000000000012 :107E70000000000000000000000000000000000002 :107E800000000000000000000000000000000000F2 :107E900000000000000000000000000000000000E2 :107EA00000000000000000000000000000000000D2 :107EB00000000000000000000000000000000000C2 :107EC00000000000000000000000000000000000B2 :107ED00000000000000000000000000000000000A2 :107EE0000000000000000000000000000000000092 :107EF0000000000000000000000000000000000082 :107F00000000000000000000000000000000000071 :107F10000000000000000000000000000000000061 :107F20000000000000000000000000000000000051 :107F30000000000000000000000000000000000041 :107F40000000000000000000000000000000000031 :107F50000000000000000000000000000000000021 :107F60000000000000000000000000000000000011 :107F70000000000000000000000000000000000001 :107F800000000000000000000000000000000000F1 :107F900000000000000000000000000000000000E1 :107FA00000000000000000000000000000000000D1 :107FB00000000000000000000000000000000000C1 :107FC00000000000000000000000000000000000B1 :107FD00000000000000000000000000000000000A1 :107FE0000000000000000000000000000000000091 :107FF0000000000000000000000000000000000081 :108000000000000000000000000000000000000070 :108010000000000000000000000000000000000060 :108020000000000000000000000000000000000050 :108030000000000000000000000000000000000040 :108040000000000000000000000000000000000030 :108050000000000000000000000000000000000020 :108060000000000000000000000000000000000010 :108070000000000000000000000000000000000000 :1080800000000000000000000000000000000000F0 :1080900000000000000000000000000000000000E0 :1080A00000000000000000000000000000000000D0 :1080B00000000000000000000000000000000000C0 :1080C00000000000000000000000000000000000B0 :1080D00000000000000000000000000000000000A0 :1080E0000000000000000000000000000000000090 :1080F0000000000000000000000000000000000080 :10810000000000000000000000000000000000006F :10811000000000000000000000000000000000005F :10812000000000000000000000000000000000004F :10813000000000000000000000000000000000003F :10814000000000000000000000000000000000002F :10815000000000000000000000000000000000001F :10816000000000000000000000000000000000000F :1081700000000000000000000000000000000000FF :1081800000000000000000000000000000000000EF :1081900000000000000000000000000000000000DF :1081A00000000000000000000000000000000000CF :1081B00000000000000000000000000000000000BF :1081C00000000000000000000000000000000000AF :1081D000000000000000000000000000000000009F :1081E000000000000000000000000000000000008F :1081F000000000000000000000000000000000007F :10820000000000000000000000000000000000006E :10821000000000000000000000000000000000005E :10822000000000000000000000000000000000004E :10823000000000000000000000000000000000003E :10824000000000000000000000000000000000002E :10825000000000000000000000000000000000001E :10826000000000000000000000000000000000000E :1082700000000000000000000000000000000000FE :1082800000000000000000000000000000000000EE :1082900000000000000000000000000000000000DE :1082A00000000000000000000000000000000000CE :1082B00000000000000000000000000000000000BE :1082C00000000000000000000000000000000000AE :1082D000000000000000000000000000000000009E :1082E000000000000000000000000000000000008E :1082F000000000000000000000000000000000007E :10830000000000000000000000000000000000006D :10831000000000000000000000000000000000005D :10832000000000000000000000000000000000004D :10833000000000000000000000000000000000003D :10834000000000000000000000000000000000002D :10835000000000000000000000000000000000001D :10836000000000000000000000000000000000000D :1083700000000000000000000000000000000000FD :1083800000000000000000000000000000000000ED :1083900000000000000000000000000000000000DD :1083A00000000000000000000000000000000000CD :1083B00000000000000000000000000000000000BD :1083C00000000000000000000000000000000000AD :1083D000000000000000000000000000000000009D :1083E000000000000000000000000000000000008D :1083F000000000000000000000000000000000007D :10840000000000000000000000000000000000006C :10841000000000000000000000000000000000005C :10842000000000000000000000000000000000004C :10843000000000000000000000000000000000003C :10844000000000000000000000000000000000002C :10845000000000000000000000000000000000001C :10846000000000000000000000000000000000000C :1084700000000000000000000000000000000000FC :1084800000000000000000000000000000000000EC :1084900000000000000000000000000000000000DC :1084A00000000000000000000000000000000000CC :1084B00000000000000000000000000000000000BC :1084C00000000000000000000000000000000000AC :1084D000000000000000000000000000000000009C :1084E000000000000000000000000000000000008C :1084F000000000000000000000000000000000007C :10850000000000000000000000000000000000006B :10851000000000000000000000000000000000005B :10852000000000000000000000000000000000004B :10853000000000000000000000000000000000003B :10854000000000000000000000000000000000002B :10855000000000000000000000000000000000001B :10856000000000000000000000000000000000000B :1085700000000000000000000000000000000000FB :1085800000000000000000000000000000000000EB :1085900000000000000000000000000000000000DB :1085A00000000000000000000000000000000000CB :1085B00000000000000000000000000000000000BB :1085C00000000000000000000000000000000000AB :1085D000000000000000000000000000000000009B :1085E000000000000000000000000000000000008B :1085F000000000000000000000000000000000007B :10860000000000000000000000000000000000006A :10861000000000000000000000000000000000005A :10862000000000000000000000000000000000004A :10863000000000000000000000000000000000003A :10864000000000000000000000000000000000002A :10865000000000000000000000000000000000001A :10866000000000000000000000000000000000000A :1086700000000000000000000000000000000000FA :1086800000000000000000000000000000000000EA :1086900000000000000000000000000000000000DA :1086A00000000000000000000000000000000000CA :1086B00000000000000000000000000000000000BA :1086C00000000000000000000000000000000000AA :1086D000000000000000000000000000000000009A :1086E000000000000000000000000000000000008A :1086F000000000000000000000000000000000007A :108700000000000000000000000000000000000069 :108710000000000000000000000000000000000059 :108720000000000000000000000000000000000049 :108730000000000000000000000000000000000039 :108740000000000000000000000000000000000029 :108750000000000000000000000000000000000019 :108760000000000000000000000000000000000009 :1087700000000000000000000000000000000000F9 :1087800000000000000000000000000000000000E9 :1087900000000000000000000000000000000000D9 :1087A00000000000000000000000000000000000C9 :1087B00000000000000000000000000000000000B9 :1087C00000000000000000000000000000000000A9 :1087D0000000000000000000000000000000000099 :1087E0000000000000000000000000000000000089 :1087F0000000000000000000000000000000000079 :108800000000000000000000000000000000000068 :108810000000000000000000000000000000000058 :108820000000000000000000000000000000000048 :108830000000000000000000000000000000000038 :108840000000000000000000000000000000000028 :108850000000000000000000000000000000000018 :108860000000000000000000000000000000000008 :1088700000000000000000000000000000000000F8 :1088800000000000000000000000000000000000E8 :1088900000000000000000000000000000000000D8 :1088A00000000000000000000000000000000000C8 :1088B00000000000000000000000000000000000B8 :1088C00000000000000000000000000000000000A8 :1088D0000000000000000000000000000000000098 :1088E0000000000000000000000000000000000088 :1088F0000000000000000000000000000000000078 :108900000000000000000000000000000000000067 :108910000000000000000000000000000000000057 :108920000000000000000000000000000000000047 :108930000000000000000000000000000000000037 :108940000000000000000000000000000000000027 :108950000000000000000000000000000000000017 :108960000000000000000000000000000000000007 :1089700000000000000000000000000000000000F7 :1089800000000000000000000000000000000000E7 :1089900000000000000000000000000000000000D7 :1089A00000000000000000000000000000000000C7 :1089B00000000000000000000000000000000000B7 :1089C00000000000000000000000000000000000A7 :1089D0000000000000000000000000000000000097 :1089E0000000000000000000000000000000000087 :1089F0000000000000000000000000000000000077 :108A00000000000000000000000000000000000066 :108A10000000000000000000000000000000000056 :108A20000000000000000000000000000000000046 :108A30000000000000000000000000000000000036 :108A40000000000000000000000000000000000026 :108A50000000000000000000000000000000000016 :108A60000000000000000000000000000000000006 :108A700000000000000000000000000000000000F6 :108A800000000000000000000000000000000000E6 :108A900000000000000000000000000000000000D6 :108AA00000000000000000000000000000000000C6 :108AB00000000000000000000000000000000000B6 :108AC00000000000000000000000000000000000A6 :108AD0000000000000000000000000000000000096 :108AE0000000000000000000000000000000000086 :108AF0000000000000000000000000000000000076 :108B00000000000000000000000000000000000065 :108B10000000000000000000000000000000000055 :108B20000000000000000000000000000000000045 :108B30000000000000000000000000000000000035 :108B40000000000000000000000000000000000025 :108B50000000000000000000000000000000000015 :108B60000000000000000000000000000000000005 :108B700000000000000000000000000000000000F5 :108B800000000000000000000000000000000000E5 :108B900000000000000000000000000000000000D5 :108BA00000000000000000000000000000000000C5 :108BB00000000000000000000000000000000000B5 :108BC00000000000000000000000000000000000A5 :108BD0000000000000000000000000000000000095 :108BE0000000000000000000000000000000000085 :108BF0000000000000000000000000000000000075 :108C00000000000000000000000000000000000064 :108C10000000000000000000000000000000000054 :108C20000000000000000000000000000000000044 :108C30000000000000000000000000000000000034 :108C40000000000000000000000000000000000024 :108C50000000000000000000000000000000000014 :108C60000000000000000000000000000000000004 :108C700000000000000000000000000000000000F4 :108C800000000000000000000000000000000000E4 :108C900000000000000000000000000000000000D4 :108CA00000000000000000000000000000000000C4 :108CB00000000000000000000000000000000000B4 :108CC00000000000000000000000000000000000A4 :108CD0000000000000000000000000000000000094 :108CE0000000000000000000000000000000000084 :108CF0000000000000000000000000000000000074 :108D00000000000000000000000000000000000063 :108D10000000000000000000000000000000000053 :108D20000000000000000000000000000000000043 :108D30000000000000000000000000000000000033 :108D40000000000000000000000000000000000023 :108D50000000000000000000000000000000000013 :108D60000000000000000000000000000000000003 :108D700000000000000000000000000000000000F3 :108D800000000000000000000000000000000000E3 :108D900000000000000000000000000000000000D3 :108DA00000000000000000000000000000000000C3 :108DB00000000000000000000000000000000000B3 :108DC00000000000000000000000000000000000A3 :108DD0000000000000000000000000000000000093 :108DE0000000000000000000000000000000000083 :108DF0000000000000000000000000000000000073 :108E00000000000000000000000000000000000062 :108E10000000000000000000000000000000000052 :108E20000000000000000000000000000000000042 :108E30000000000000000000000000000000000032 :108E40000000000000000000000000000000000022 :108E50000000000000000000000000000000000012 :108E60000000000000000000000000000000000002 :108E700000000000000000000000000000000000F2 :108E800000000000000000000000000000000000E2 :108E900000000000000000000000000000000000D2 :108EA00000000000000000000000000000000000C2 :108EB00000000000000000000000000000000000B2 :108EC00000000000000000000000000000000000A2 :108ED0000000000000000000000000000000000092 :108EE0000000000000000000000000000000000082 :108EF0000000000000000000000000000000000072 :108F00000000000000000000000000000000000061 :108F10000000000000000000000000000000000051 :108F20000000000000000000000000000000000041 :108F30000000000000000000000000000000000031 :108F40000000000000000000000000000000000021 :108F50000000000000000000000000000000000011 :108F60000000000000000000000000000000000001 :108F700000000000000000000000000000000000F1 :108F800000000000000000000000000000000000E1 :108F900000000000000000000000000000000000D1 :108FA00000000000000000000000000000000000C1 :108FB00000000000000000000000000000000000B1 :108FC00000000000000000000000000000000000A1 :108FD0000000000000000000000000000000000091 :108FE0000000000000000000000000000000000081 :108FF0000000000000000000000000000000000071 :109000000000000000000000000000000000000060 :109010000000000000000000000000000000000050 :109020000000000000000000000000000000000040 :109030000000000000000000000000000000000030 :109040000000000000000000000000000000000020 :109050000000000000000000000000000000000010 :109060000000000000000000000000000000000000 :1090700000000000000000000000000000000000F0 :1090800000000000000000000000000000000000E0 :1090900000000000000000000000000000000000D0 :1090A00000000000000000000000000000000000C0 :1090B00000000000000000000000000000000000B0 :1090C00000000000000000000000000000000000A0 :1090D0000000000000000000000000000000000090 :1090E0000000000000000000000000000000000080 :1090F0000000000000000000000000000000000070 :10910000000000000000000000000000000000005F :10911000000000000000000000000000000000004F :10912000000000000000000000000000000000003F :10913000000000000000000000000000000000002F :10914000000000000000000000000000000000001F :10915000000000000000000000000000000000000F :1091600000000000000000000000000000000000FF :1091700000000000000000000000000000000000EF :1091800000000000000000000000000000000000DF :1091900000000000000000000000000000000000CF :1091A00000000000000000000000000000000000BF :1091B00000000000000000000000000000000000AF :1091C000000000000000000000000000000000009F :1091D000000000000000000000000000000000008F :1091E000000000000000000000000000000000007F :1091F000000000000000000000000000000000006F :10920000000000000000000000000000000000005E :10921000000000000000000000000000000000004E :10922000000000000000000000000000000000003E :10923000000000000000000000000000000000002E :10924000000000000000000000000000000000001E :10925000000000000000000000000000000000000E :1092600000000000000000000000000000000000FE :1092700000000000000000000000000000000000EE :1092800000000000000000000000000000000000DE :1092900000000000000000000000000000000000CE :1092A00000000000000000000000000000000000BE :1092B00000000000000000000000000000000000AE :1092C000000000000000000000000000000000009E :1092D000000000000000000000000000000000008E :1092E000000000000000000000000000000000007E :1092F000000000000000000000000000000000006E :10930000000000000000000000000000000000005D :10931000000000000000000000000000000000004D :10932000000000000000000000000000000000003D :10933000000000000000000000000000000000002D :10934000000000000000000000000000000000001D :10935000000000000000000000000000000000000D :1093600000000000000000000000000000000000FD :1093700000000000000000000000000000000000ED :1093800000000000000000000000000000000000DD :1093900000000000000000000000000000000000CD :1093A00000000000000000000000000000000000BD :1093B00000000000000000000000000000000000AD :1093C000000000000000000000000000000000009D :1093D000000000000000000000000000000000008D :1093E000000000000000000000000000000000007D :1093F000000000000000000000000000000000006D :10940000000000000000000000000000000000005C :10941000000000000000000000000000000000004C :10942000000000000000000000000000000000003C :10943000000000000000000000000000000000002C :10944000000000000000000000000000000000001C :10945000000000000000000000000000000000000C :1094600000000000000000000000000000000000FC :1094700000000000000000000000000000000000EC :1094800000000000000000000000000000000000DC :1094900000000000000000000000000000000000CC :1094A00000000000000000000000000000000000BC :1094B00000000000000000000000000000000000AC :1094C000000000000000000000000000000000009C :1094D000000000000000000000000000000000008C :1094E000000000000000000000000000000000007C :1094F000000000000000000000000000000000006C :10950000000000000000000000000000000000005B :10951000000000000000000000000000000000004B :10952000000000000000000000000000000000003B :10953000000000000000000000000000000000002B :10954000000000000000000000000000000000001B :10955000000000000000000000000000000000000B :1095600000000000000000000000000000000000FB :1095700000000000000000000000000000000000EB :1095800000000000000000000000000000000000DB :1095900000000000000000000000000000000000CB :1095A00000000000000000000000000000000000BB :1095B00000000000000000000000000000000000AB :1095C000000000000000000000000000000000009B :1095D000000000000000000000000000000000008B :1095E000000000000000000000000000000000007B :1095F000000000000000000000000000000000006B :10960000000000000000000000000000000000005A :10961000000000000000000000000000000000004A :10962000000000000000000000000000000000003A :10963000000000000000000000000000000000002A :10964000000000000000000000000000000000001A :10965000000000000000000000000000000000000A :1096600000000000000000000000000000000000FA :1096700000000000000000000000000000000000EA :1096800000000000000000000000000000000000DA :1096900000000000000000000000000000000000CA :1096A00000000000000000000000000000000000BA :1096B00000000000000000000000000000000000AA :1096C000000000000000000000000000000000009A :1096D000000000000000000000000000000000008A :1096E000000000000000000000000000000000007A :1096F000000000000000000000000000000000006A :109700000000000000000000000000000000000059 :109710000000000000000000000000000000000049 :109720000000000000000000000000000000000039 :109730000000000000000000000000000000000029 :109740000000000000000000000000000000000019 :109750000000000000000000000000000000000009 :1097600000000000000000000000000000000000F9 :1097700000000000000000000000000000000000E9 :1097800000000000000000000000000000000000D9 :1097900000000000000000000000000000000000C9 :1097A00000000000000000000000000000000000B9 :1097B00000000000000000000000000000000000A9 :1097C0000000000000000000000000000000000099 :1097D0000000000000000000000000000000000089 :1097E0000000000000000000000000000000000079 :1097F0000000000000000000000000000000000069 :109800000000000000000000000000000000000058 :109810000000000000000000000000000000000048 :109820000000000000000000000000000000000038 :109830000000000000000000000000000000000028 :109840000000000000000000000000000000000018 :109850000000000000000000000000000000000008 :1098600000000000000000000000000000000000F8 :1098700000000000000000000000000000000000E8 :1098800000000000000000000000000000000000D8 :1098900000000000000000000000000000000000C8 :1098A00000000000000000000000000000000000B8 :1098B00000000000000000000000000000000000A8 :1098C0000000000000000000000000000000000098 :1098D0000000000000000000000000000000000088 :1098E0000000000000000000000000000000000078 :1098F0000000000000000000000000000000000068 :109900000000000000000000000000000000000057 :109910000000000000000000000000000000000047 :109920000000000000000000000000000000000037 :109930000000000000000000000000000000000027 :109940000000000000000000000000000000000017 :109950000000000000000000000000000000000007 :1099600000000000000000000000000000000000F7 :1099700000000000000000000000000000000000E7 :1099800000000000000000000000000000000000D7 :1099900000000000000000000000000000000000C7 :1099A00000000000000000000000000000000000B7 :1099B00000000000000000000000000000000000A7 :1099C0000000000000000000000000000000000097 :1099D0000000000000000000000000000000000087 :1099E0000000000000000000000000000000000077 :1099F0000000000000000000000000000000000067 :109A00000000000000000000000000000000000056 :109A10000000000000000000000000000000000046 :109A20000000000000000000000000000000000036 :109A30000000000000000000000000000000000026 :109A40000000000000000000000000000000000016 :109A50000000000000000000000000000000000006 :109A600000000000000000000000000000000000F6 :109A700000000000000000000000000000000000E6 :109A800000000000000000000000000000000000D6 :109A900000000000000000000000000000000000C6 :109AA00000000000000000000000000000000000B6 :109AB00000000000000000000000000000000000A6 :109AC0000000000000000000000000000000000096 :109AD0000000000000000000000000000000000086 :109AE0000000000000000000000000000000000076 :109AF0000000000000000000000000000000000066 :109B00000000000000000000000000000000000055 :109B10000000000000000000000000000000000045 :109B20000000000000000000000000000000000035 :109B30000000000000000000000000000000000025 :109B40000000000000000000000000000000000015 :109B50000000000000000000000000000000000005 :109B600000000000000000000000000000000000F5 :109B700000000000000000000000000000000000E5 :109B800000000000000000000000000000000000D5 :109B900000000000000000000000000000000000C5 :109BA00000000000000000000000000000000000B5 :109BB00000000000000000000000000000000000A5 :109BC0000000000000000000000000000000000095 :109BD0000000000000000000000000000000000085 :109BE0000000000000000000000000000000000075 :109BF0000000000000000000000000000000000065 :109C00000000000000000000000000000000000054 :109C10000000000000000000000000000000000044 :109C20000000000000000000000000000000000034 :109C30000000000000000000000000000000000024 :109C40000000000000000000000000000000000014 :109C50000000000000000000000000000000000004 :109C600000000000000000000000000000000000F4 :109C700000000000000000000000000000000000E4 :109C800000000000000000000000000000000000D4 :109C900000000000000000000000000000000000C4 :109CA00000000000000000000000000000000000B4 :109CB00000000000000000000000000000000000A4 :109CC0000000000000000000000000000000000094 :109CD0000000000000000000000000000000000084 :109CE0000000000000000000000000000000000074 :109CF0000000000000000000000000000000000064 :109D00000000000000000000000000000000000053 :109D10000000000000000000000000000000000043 :109D20000000000000000000000000000000000033 :109D30000000000000000000000000000000000023 :109D40000000000000000000000000000000000013 :109D50000000000000000000000000000000000003 :109D600000000000000000000000000000000000F3 :109D700000000000000000000000000000000000E3 :109D800000000000000000000000000000000000D3 :109D900000000000000000000000000000000000C3 :109DA00000000000000000000000000000000000B3 :109DB00000000000000000000000000000000000A3 :109DC0000000000000000000000000000000000093 :109DD0000000000000000000000000000000000083 :109DE0000000000000000000000000000000000073 :109DF0000000000000000000000000000000000063 :109E00000000000000000000000000000000000052 :109E10000000000000000000000000000000000042 :109E20000000000000000000000000000000000032 :109E30000000000000000000000000000000000022 :109E40000000000000000000000000000000000012 :109E50000000000000000000000000000000000002 :109E600000000000000000000000000000000000F2 :109E700000000000000000000000000000000000E2 :109E800000000000000000000000000000000000D2 :109E900000000000000000000000000000000000C2 :109EA00000000000000000000000000000000000B2 :109EB00000000000000000000000000000000000A2 :109EC0000000000000000000000000000000000092 :109ED0000000000000000000000000000000000082 :109EE0000000000000000000000000000000000072 :109EF0000000000000000000000000000000000062 :109F00000000000000000000000000000000000051 :109F10000000000000000000000000000000000041 :109F20000000000000000000000000000000000031 :109F30000000000000000000000000000000000021 :109F40000000000000000000000000000000000011 :109F50000000000000000000000000000000000001 :109F600000000000000000000000000000000000F1 :109F700000000000000000000000000000000000E1 :109F800000000000000000000000000000000000D1 :109F900000000000000000000000000000000000C1 :109FA00000000000000000000000000000000000B1 :109FB00000000000000000000000000000000000A1 :109FC0000000000000000000000000000000000091 :109FD0000000000000000000000000000000000081 :109FE0000000000000000000000000000000000071 :109FF0000000000000000000000000000000000061 :10A000000000000000000000000000000000000050 :10A010000000000000000000000000000000000040 :10A020000000000000000000000000000000000030 :10A030000000000000000000000000000000000020 :10A040000000000000000000000000000000000010 :10A050000000000000000000000000000000000000 :10A0600000000000000000000000000000000000F0 :10A0700000000000000000000000000000000000E0 :10A0800000000000000000000000000000000000D0 :10A0900000000000000000000000000000000000C0 :10A0A00000000000000000000000000000000000B0 :10A0B00000000000000000000000000000000000A0 :10A0C0000000000000000000000000000000000090 :10A0D0000000000000000000000000000000000080 :10A0E0000000000000000000000000000000000070 :10A0F0000000000000000000000000000000000060 :10A10000000000000000000000000000000000004F :10A11000000000000000000000000000000000003F :10A12000000000000000000000000000000000002F :10A13000000000000000000000000000000000001F :10A14000000000000000000000000000000000000F :10A1500000000000000000000000000000000000FF :10A1600000000000000000000000000000000000EF :10A1700000000000000000000000000000000000DF :10A1800000000000000000000000000000000000CF :10A1900000000000000000000000000000000000BF :10A1A00000000000000000000000000000000000AF :10A1B000000000000000000000000000000000009F :10A1C000000000000000000000000000000000008F :10A1D000000000000000000000000000000000007F :10A1E000000000000000000000000000000000006F :10A1F000000000000000000000000000000000005F :10A20000000000000000000000000000000000004E :10A21000000000000000000000000000000000003E :10A22000000000000000000000000000000000002E :10A23000000000000000000000000000000000001E :10A24000000000000000000000000000000000000E :10A2500000000000000000000000000000000000FE :10A2600000000000000000000000000000000000EE :10A2700000000000000000000000000000000000DE :10A2800000000000000000000000000000000000CE :10A2900000000000000000000000000000000000BE :10A2A00000000000000000000000000000000000AE :10A2B000000000000000000000000000000000009E :10A2C000000000000000000000000000000000008E :10A2D000000000000000000000000000000000007E :10A2E000000000000000000000000000000000006E :10A2F000000000000000000000000000000000005E :10A30000000000000000000000000000000000004D :10A31000000000000000000000000000000000003D :10A32000000000000000000000000000000000002D :10A33000000000000000000000000000000000001D :10A34000000000000000000000000000000000000D :10A3500000000000000000000000000000000000FD :10A3600000000000000000000000000000000000ED :10A3700000000000000000000000000000000000DD :10A3800000000000000000000000000000000000CD :10A3900000000000000000000000000000000000BD :10A3A00000000000000000000000000000000000AD :10A3B000000000000000000000000000000000009D :10A3C000000000000000000000000000000000008D :10A3D000000000000000000000000000000000007D :10A3E000000000000000000000000000000000006D :10A3F000000000000000000000000000000000005D :10A40000000000000000000000000000000000004C :10A41000000000000000000000000000000000003C :10A42000000000000000000000000000000000002C :10A43000000000000000000000000000000000001C :10A44000000000000000000000000000000000000C :10A4500000000000000000000000000000000000FC :10A4600000000000000000000000000000000000EC :10A4700000000000000000000000000000000000DC :10A4800000000000000000000000000000000000CC :10A4900000000000000000000000000000000000BC :10A4A00000000000000000000000000000000000AC :10A4B000000000000000000000000000000000009C :10A4C000000000000000000000000000000000008C :10A4D000000000000000000000000000000000007C :10A4E000000000000000000000000000000000006C :10A4F000000000000000000000000000000000005C :10A50000000000000000000000000000000000004B :10A51000000000000000000000000000000000003B :10A52000000000000000000000000000000000002B :10A53000000000000000000000000000000000001B :10A54000000000000000000000000000000000000B :10A5500000000000000000000000000000000000FB :10A5600000000000000000000000000000000000EB :10A5700000000000000000000000000000000000DB :10A5800000000000000000000000000000000000CB :10A5900000000000000000000000000000000000BB :10A5A00000000000000000000000000000000000AB :10A5B000000000000000000000000000000000009B :10A5C000000000000000000000000000000000008B :10A5D000000000000000000000000000000000007B :10A5E000000000000000000000000000000000006B :10A5F000000000000000000000000000000000005B :10A60000000000000000000000000000000000004A :10A61000000000000000000000000000000000003A :10A62000000000000000000000000000000000002A :10A63000000000000000000000000000000000001A :10A64000000000000000000000000000000000000A :10A6500000000000000000000000000000000000FA :10A6600000000000000000000000000000000000EA :10A6700000000000000000000000000000000000DA :10A6800000000000000000000000000000000000CA :10A6900000000000000000000000000000000000BA :10A6A00000000000000000000000000000000000AA :10A6B000000000000000000000000000000000009A :10A6C000000000000000000000000000000000008A :10A6D000000000000000000000000000000000007A :10A6E000000000000000000000000000000000006A :10A6F000000000000000000000000000000000005A :10A700000000000000000000000000000000000049 :10A710000000000000000000000000000000000039 :10A720000000000000000000000000000000000029 :10A730000000000000000000000000000000000019 :10A740000000000000000000000000000000000009 :10A7500000000000000000000000000000000000F9 :10A7600000000000000000000000000000000000E9 :10A7700000000000000000000000000000000000D9 :10A7800000000000000000000000000000000000C9 :10A7900000000000000000000000000000000000B9 :10A7A00000000000000000000000000000000000A9 :10A7B0000000000000000000000000000000000099 :10A7C0000000000000000000000000000000000089 :10A7D0000000000000000000000000000000000079 :10A7E0000000000000000000000000000000000069 :10A7F0000000000000000000000000000000000059 :10A800000000000000000000000000000000000048 :10A810000000000000000000000000000000000038 :10A820000000000000000000000000000000000028 :10A830000000000000000000000000000000000018 :10A840000000000000000000000000000000000008 :10A8500000000000000000000000000000000000F8 :10A8600000000000000000000000000000000000E8 :10A8700000000000000000000000000000000000D8 :10A8800000000000000000000000000000000000C8 :10A8900000000000000000000000000000000000B8 :10A8A00000000000000000000000000000000000A8 :10A8B0000000000000000000000000000000000098 :10A8C0000000000000000000000000000000000088 :10A8D0000000000000000000000000000000000078 :10A8E0000000000000000000000000000000000068 :10A8F0000000000000000000000000000000000058 :10A900000000000000000000000000000000000047 :10A910000000000000000000000000000000000037 :10A920000000000000000000000000000000000027 :10A930000000000000000000000000000000000017 :10A940000000000000000000000000000000000007 :10A9500000000000000000000000000000000000F7 :10A9600000000000000000000000000000000000E7 :10A9700000000000000000000000000000000000D7 :10A9800000000000000000000000000000000000C7 :10A9900000000000000000000000000000000000B7 :10A9A00000000000000000000000000000000000A7 :10A9B0000000000000000000000000000000000097 :10A9C0000000000000000000000000000000000087 :10A9D0000000000000000000000000000000000077 :10A9E0000000000000000000000000000000000067 :10A9F0000000000000000000000000000000000057 :10AA00000000000000000000000000000000000046 :10AA10000000000000000000000000000000000036 :10AA20000000000000000000000000000000000026 :10AA30000000000000000000000000000000000016 :10AA40000000000000000000000000000000000006 :10AA500000000000000000000000000000000000F6 :10AA600000000000000000000000000000000000E6 :10AA700000000000000000000000000000000000D6 :10AA800000000000000000000000000000000000C6 :10AA900000000000000000000000000000000000B6 :10AAA00000000000000000000000000000000000A6 :10AAB0000000000000000000000000000000000096 :10AAC0000000000000000000000000000000000086 :10AAD0000000000000000000000000000000000076 :10AAE0000000000000000000000000000000000066 :10AAF0000000000000000000000000000000000056 :10AB00000000000000000000000000000000000045 :10AB10000000000000000000000000000000000035 :10AB20000000000000000000000000000000000025 :10AB30000000000000000000000000000000000015 :10AB40000000000000000000000000000000000005 :10AB500000000000000000000000000000000000F5 :10AB600000000000000000000000000000000000E5 :10AB700000000000000000000000000000000000D5 :10AB800000000000000000000000000000000000C5 :10AB900000000000000000000000000000000000B5 :10ABA00000000000000000000000000000000000A5 :10ABB0000000000000000000000000000000000095 :10ABC0000000000000000000000000000000000085 :10ABD0000000000000000000000000000000000075 :10ABE0000000000000000000000000000000000065 :10ABF0000000000000000000000000000000000055 :10AC00000000000000000000000000000000000044 :10AC10000000000000000000000000000000000034 :10AC20000000000000000000000000000000000024 :10AC30000000000000000000000000000000000014 :10AC40000000000000000000000000000000000004 :10AC500000000000000000000000000000000000F4 :10AC600000000000000000000000000000000000E4 :10AC700000000000000000000000000000000000D4 :10AC800000000000000000000000000000000000C4 :10AC900000000000000000000000000000000000B4 :10ACA00000000000000000000000000000000000A4 :10ACB0000000000000000000000000000000000094 :10ACC0000000000000000000000000000000000084 :10ACD0000000000000000000000000000000000074 :10ACE0000000000000000000000000000000000064 :10ACF0000000000000000000000000000000000054 :10AD00000000000000000000000000000000000043 :10AD10000000000000000000000000000000000033 :10AD20000000000000000000000000000000000023 :10AD30000000000000000000000000000000000013 :10AD40000000000000000000000000000000000003 :10AD500000000000000000000000000000000000F3 :10AD600000000000000000000000000000000000E3 :10AD700000000000000000000000000000000000D3 :10AD800000000000000000000000000000000000C3 :10AD900000000000000000000000000000000000B3 :10ADA00000000000000000000000000000000000A3 :10ADB0000000000000000000000000000000000093 :10ADC0000000000000000000000000000000000083 :10ADD0000000000000000000000000000000000073 :10ADE0000000000000000000000000000000000063 :10ADF0000000000000000000000000000000000053 :10AE00000000000000000000000000000000000042 :10AE10000000000000000000000000000000000032 :10AE20000000000000000000000000000000000022 :10AE30000000000000000000000000000000000012 :10AE40000000000000000000000000000000000002 :10AE500000000000000000000000000000000000F2 :10AE600000000000000000000000000000000000E2 :10AE700000000000000000000000000000000000D2 :10AE800000000000000000000000000000000000C2 :10AE900000000000000000000000000000000000B2 :10AEA00000000000000000000000000000000000A2 :10AEB0000000000000000000000000000000000092 :10AEC0000000000000000000000000000000000082 :10AED0000000000000000000000000000000000072 :10AEE0000000000000000000000000000000000062 :10AEF0000000000000000000000000000000000052 :10AF00000000000000000000000000000000000041 :10AF10000000000000000000000000000000000031 :10AF20000000000000000000000000000000000021 :10AF30000000000000000000000000000000000011 :10AF40000000000000000000000000000000000001 :10AF500000000000000000000000000000000000F1 :10AF600000000000000000000000000000000000E1 :10AF700000000000000000000000000000000000D1 :10AF800000000000000000000000000000000000C1 :10AF900000000000000000000000000000000000B1 :10AFA00000000000000000000000000000000000A1 :10AFB0000000000000000000000000000000000091 :10AFC0000000000000000000000000000000000081 :10AFD0000000000000000000000000000000000071 :10AFE0000000000000000000000000000000000061 :10AFF0000000000000000000000000000000000051 :10B000000000000000000000000000000000000040 :10B010000000000000000000000000000000000030 :10B020000000000000000000000000000000000020 :10B030000000000000000000000000000000000010 :10B040000000000000000000000000000000000000 :10B0500000000000000000000000000000000000F0 :10B0600000000000000000000000000000000000E0 :10B0700000000000000000000000000000000000D0 :10B0800000000000000000000000000000000000C0 :10B0900000000000000000000000000000000000B0 :10B0A00000000000000000000000000000000000A0 :10B0B0000000000000000000000000000000000090 :10B0C0000000000000000000000000000000000080 :10B0D0000000000000000000000000000000000070 :10B0E0000000000000000000000000000000000060 :10B0F0000000000000000000000000000000000050 :10B10000000000000000000000000000000000003F :10B11000000000000000000000000000000000002F :10B12000000000000000000000000000000000001F :10B13000000000000000000000000000000000000F :10B1400000000000000000000000000000000000FF :10B1500000000000000000000000000000000000EF :10B1600000000000000000000000000000000000DF :10B1700000000000000000000000000000000000CF :10B1800000000000000000000000000000000000BF :10B1900000000000000000000000000000000000AF :10B1A000000000000000000000000000000000009F :10B1B000000000000000000000000000000000008F :10B1C000000000000000000000000000000000007F :10B1D000000000000000000000000000000000006F :10B1E000000000000000000000000000000000005F :10B1F000000000000000000000000000000000004F :10B20000000000000000000000000000000000003E :10B21000000000000000000000000000000000002E :10B22000000000000000000000000000000000001E :10B23000000000000000000000000000000000000E :10B2400000000000000000000000000000000000FE :10B2500000000000000000000000000000000000EE :10B2600000000000000000000000000000000000DE :10B2700000000000000000000000000000000000CE :10B2800000000000000000000000000000000000BE :10B2900000000000000000000000000000000000AE :10B2A000000000000000000000000000000000009E :10B2B000000000000000000000000000000000008E :10B2C000000000000000000000000000000000007E :10B2D000000000000000000000000000000000006E :10B2E000000000000000000000000000000000005E :10B2F000000000000000000000000000000000004E :10B30000000000000000000000000000000000003D :10B31000000000000000000000000000000000002D :10B32000000000000000000000000000000000001D :10B33000000000000000000000000000000000000D :10B3400000000000000000000000000000000000FD :10B3500000000000000000000000000000000000ED :10B3600000000000000000000000000000000000DD :10B3700000000000000000000000000000000000CD :10B3800000000000000000000000000000000000BD :10B3900000000000000000000000000000000000AD :10B3A000000000000000000000000000000000009D :10B3B000000000000000000000000000000000008D :10B3C000000000000000000000000000000000007D :10B3D000000000000000000000000000000000006D :10B3E000000000000000000000000000000000005D :10B3F000000000000000000000000000000000004D :10B40000000000000000000000000000000000003C :10B41000000000000000000000000000000000002C :10B42000000000000000000000000000000000001C :10B43000000000000000000000000000000000000C :10B4400000000000000000000000000000000000FC :10B4500000000000000000000000000000000000EC :10B4600000000000000000000000000000000000DC :10B4700000000000000000000000000000000000CC :10B4800000000000000000000000000000000000BC :10B4900000000000000000000000000000000000AC :10B4A000000000000000000000000000000000009C :10B4B000000000000000000000000000000000008C :10B4C000000000000000000000000000000000007C :10B4D000000000000000000000000000000000006C :10B4E000000000000000000000000000000000005C :10B4F000000000000000000000000000000000004C :10B50000000000000000000000000000000000003B :10B51000000000000000000000000000000000002B :10B52000000000000000000000000000000000001B :10B53000000000000000000000000000000000000B :10B5400000000000000000000000000000000000FB :10B5500000000000000000000000000000000000EB :10B5600000000000000000000000000000000000DB :10B5700000000000000000000000000000000000CB :10B5800000000000000000000000000000000000BB :10B5900000000000000000000000000000000000AB :10B5A000000000000000000000000000000000009B :10B5B000000000000000000000000000000000008B :10B5C000000000000000000000000000000000007B :10B5D000000000000000000000000000000000006B :10B5E000000000000000000000000000000000005B :10B5F000000000000000000000000000000000004B :10B60000000000000000000000000000000000003A :10B61000000000000000000000000000000000002A :10B62000000000000000000000000000000000001A :10B63000000000000000000000000000000000000A :10B6400000000000000000000000000000000000FA :10B6500000000000000000000000000000000000EA :10B6600000000000000000000000000000000000DA :10B6700000000000000000000000000000000000CA :10B6800000000000000000000000000000000000BA :10B6900000000000000000000000000000000000AA :10B6A000000000000000000000000000000000009A :10B6B000000000000000000000000000000000008A :10B6C000000000000000000000000000000000007A :10B6D000000000000000000000000000000000006A :10B6E000000000000000000000000000000000005A :10B6F000000000000000000000000000000000004A :10B700000000000000000000000000000000000039 :10B710000000000000000000000000000000000029 :10B720000000000000000000000000000000000019 :10B730000000000000000000000000000000000009 :10B7400000000000000000000000000000000000F9 :10B7500000000000000000000000000000000000E9 :10B7600000000000000000000000000000000000D9 :10B7700000000000000000000000000000000000C9 :10B7800000000000000000000000000000000000B9 :10B7900000000000000000000000000000000000A9 :10B7A0000000000000000000000000000000000099 :10B7B0000000000000000000000000000000000089 :10B7C0000000000000000000000000000000000079 :10B7D0000000000000000000000000000000000069 :10B7E0000000000000000000000000000000000059 :10B7F0000000000000000000000000000000000049 :10B800000000000000000000000000000000000038 :10B810000000000000000000000000000000000028 :10B820000000000000000000000000000000000018 :10B830000000000000000000000000000000000008 :10B8400000000000000000000000000000000000F8 :10B8500000000000000000000000000000000000E8 :10B8600000000000000000000000000000000000D8 :10B8700000000000000000000000000000000000C8 :10B8800000000000000000000000000000000000B8 :10B8900000000000000000000000000000000000A8 :10B8A0000000000000000000000000000000000098 :10B8B0000000000000000000000000000000000088 :10B8C0000000000000000000000000000000000078 :10B8D0000000000000000000000000000000000068 :10B8E0000000000000000000000000000000000058 :10B8F0000000000000000000000000000000000048 :10B900000000000000000000000000000000000037 :10B910000000000000000000000000000000000027 :10B920000000000000000000000000000000000017 :10B930000000000000000000000000000000000007 :10B9400000000000000000000000000000000000F7 :10B9500000000000000000000000000000000000E7 :10B9600000000000000000000000000000000000D7 :10B9700000000000000000000000000000000000C7 :10B9800000000000000000000000000000000000B7 :10B9900000000000000000000000000000000000A7 :10B9A0000000000000000000000000000000000097 :10B9B0000000000000000000000000000000000087 :10B9C0000000000000000000000000000000000077 :10B9D0000000000000000000000000000000000067 :10B9E0000000000000000000000000000000000057 :10B9F0000000000000000000000000000000000047 :10BA00000000000000000000000000000000000036 :10BA10000000000000000000000000000000000026 :10BA20000000000000000000000000000000000016 :10BA30000000000000000000000000000000000006 :10BA400000000000000000000000000000000000F6 :10BA500000000000000000000000000000000000E6 :10BA600000000000000000000000000000000000D6 :10BA700000000000000000000000000000000000C6 :10BA800000000000000000000000000000000000B6 :10BA900000000000000000000000000000000000A6 :10BAA0000000000000000000000000000000000096 :10BAB0000000000000000000000000000000000086 :10BAC0000000000000000000000000000000000076 :10BAD0000000000000000000000000000000000066 :10BAE0000000000000000000000000000000000056 :10BAF0000000000000000000000000000000000046 :10BB00000000000000000000000000000000000035 :10BB10000000000000000000000000000000000025 :10BB20000000000000000000000000000000000015 :10BB30000000000000000000000000000000000005 :10BB400000000000000000000000000000000000F5 :10BB500000000000000000000000000000000000E5 :10BB600000000000000000000000000000000000D5 :10BB700000000000000000000000000000000000C5 :10BB800000000000000000000000000000000000B5 :10BB900000000000000000000000000000000000A5 :10BBA0000000000000000000000000000000000095 :10BBB0000000000000000000000000000000000085 :10BBC0000000000000000000000000000000000075 :10BBD0000000000000000000000000000000000065 :10BBE0000000000000000000000000000000000055 :10BBF0000000000000000000000000000000000045 :10BC00000000000000000000000000000000000034 :10BC10000000000000000000000000000000000024 :10BC20000000000000000000000000000000000014 :10BC30000000000000000000000000000000000004 :10BC400000000000000000000000000000000000F4 :10BC500000000000000000000000000000000000E4 :10BC600000000000000000000000000000000000D4 :10BC700000000000000000000000000000000000C4 :10BC800000000000000000000000000000000000B4 :10BC900000000000000000000000000000000000A4 :10BCA0000000000000000000000000000000000094 :10BCB0000000000000000000000000000000000084 :10BCC0000000000000000000000000000000000074 :10BCD0000000000000000000000000000000000064 :10BCE0000000000000000000000000000000000054 :10BCF0000000000000000000000000000000000044 :10BD00000000000000000000000000000000000033 :10BD10000000000000000000000000000000000023 :10BD20000000000000000000000000000000000013 :10BD30000000000000000000000000000000000003 :10BD400000000000000000000000000000000000F3 :10BD500000000000000000000000000000000000E3 :10BD600000000000000000000000000000000000D3 :10BD700000000000000000000000000000000000C3 :10BD800000000000000000000000000000000000B3 :10BD900000000000000000000000000000000000A3 :10BDA0000000000000000000000000000000000093 :10BDB0000000000000000000000000000000000083 :10BDC0000000000000000000000000000000000073 :10BDD0000000000000000000000000000000000063 :10BDE0000000000000000000000000000000000053 :10BDF0000000000000000000000000000000000043 :10BE00000000000000000000000000000000000032 :10BE10000000000000000000000000000000000022 :10BE20000000000000000000000000000000000012 :10BE30000000000000000000000000000000000002 :10BE400000000000000000000000000000000000F2 :10BE500000000000000000000000000000000000E2 :10BE600000000000000000000000000000000000D2 :10BE700000000000000000000000000000000000C2 :10BE800000000000000000000000000000000000B2 :10BE900000000000000000000000000000000000A2 :10BEA0000000000000000000000000000000000092 :10BEB0000000000000000000000000000000000082 :10BEC0000000000000000000000000000000000072 :10BED0000000000000000000000000000000000062 :10BEE0000000000000000000000000000000000052 :10BEF0000000000000000000000000000000000042 :10BF00000000000000000000000000000000000031 :10BF10000000000000000000000000000000000021 :10BF20000000000000000000000000000000000011 :10BF30000000000000000000000000000000000001 :10BF400000000000000000000000000000000000F1 :10BF500000000000000000000000000000000000E1 :10BF600000000000000000000000000000000000D1 :10BF700000000000000000000000000000000000C1 :10BF800000000000000000000000000000000000B1 :10BF900000000000000000000000000000000000A1 :10BFA0000000000000000000000000000000000091 :10BFB0000000000000000000000000000000000081 :10BFC0000000000000000000000000000000000071 :10BFD0000000000000000000000000000000000061 :10BFE0000000000000000000000000000000000051 :10BFF0000000000000000000000000000000000041 :10C000000000000000000000000000000000000030 :10C010000000000000000000000000000000000020 :10C020000000000000000000000000000000000010 :10C030000000000000000000000000000000000000 :10C0400000000000000000000000000000000000F0 :10C0500000000000000000000000000000000000E0 :10C0600000000000000000000000000000000000D0 :10C0700000000000000000000000000000000000C0 :10C0800000000000000000000000000000000000B0 :10C0900000000000000000000000000000000000A0 :10C0A0000000000000000000000000000000000090 :10C0B0000000000000000000000000000000000080 :10C0C0000000000000000000000000000000000070 :10C0D0000000000000000000000000000000000060 :10C0E0000000000000000000000000000000000050 :10C0F0000000000000000000000000000000000040 :10C10000000000000000000000000000000000002F :10C11000000000000000000000000000000000001F :10C12000000000000000000000000000000000000F :10C1300000000000000000000000000000000000FF :10C1400000000000000000000000000000000000EF :10C1500000000000000000000000000000000000DF :10C1600000000000000000000000000000000000CF :10C1700000000000000000000000000000000000BF :10C1800000000000000000000000000000000000AF :10C19000000000000000000000000000000000009F :10C1A000000000000000000000000000000000008F :10C1B000000000000000000000000000000000007F :10C1C000000000000000000000000000000000006F :10C1D000000000000000000000000000000000005F :10C1E000000000000000000000000000000000004F :10C1F000000000000000000000000000000000003F :10C20000000000000000000000000000000000002E :10C21000000000000000000000000000000000001E :10C22000000000000000000000000000000000000E :10C2300000000000000000000000000000000000FE :10C2400000000000000000000000000000000000EE :10C2500000000000000000000000000000000000DE :10C2600000000000000000000000000000000000CE :10C2700000000000000000000000000000000000BE :10C2800000000000000000000000000000000000AE :10C29000000000000000000000000000000000009E :10C2A000000000000000000000000000000000008E :10C2B000000000000000000000000000000000007E :10C2C000000000000000000000000000000000006E :10C2D000000000000000000000000000000000005E :10C2E000000000000000000000000000000000004E :10C2F000000000000000000000000000000000003E :10C30000000000000000000000000000000000002D :10C31000000000000000000000000000000000001D :10C32000000000000000000000000000000000000D :10C3300000000000000000000000000000000000FD :10C3400000000000000000000000000000000000ED :10C3500000000000000000000000000000000000DD :10C3600000000000000000000000000000000000CD :10C3700000000000000000000000000000000000BD :10C3800000000000000000000000000000000000AD :10C39000000000000000000000000000000000009D :10C3A000000000000000000000000000000000008D :10C3B000000000000000000000000000000000007D :10C3C000000000000000000000000000000000006D :10C3D000000000000000000000000000000000005D :10C3E000000000000000000000000000000000004D :10C3F000000000000000000000000000000000003D :10C40000000000000000000000000000000000002C :10C41000000000000000000000000000000000001C :10C42000000000000000000000000000000000000C :10C4300000000000000000000000000000000000FC :10C4400000000000000000000000000000000000EC :10C4500000000000000000000000000000000000DC :10C4600000000000000000000000000000000000CC :10C4700000000000000000000000000000000000BC :10C4800000000000000000000000000000000000AC :10C49000000000000000000000000000000000009C :10C4A000000000000000000000000000000000008C :10C4B000000000000000000000000000000000007C :10C4C000000000000000000000000000000000006C :10C4D000000000000000000000000000000000005C :10C4E000000000000000000000000000000000004C :10C4F000000000000000000000000000000000003C :10C50000000000000000000000000000000000002B :10C51000000000000000000000000000000000001B :10C52000000000000000000000000000000000000B :10C5300000000000000000000000000000000000FB :10C5400000000000000000000000000000000000EB :10C5500000000000000000000000000000000000DB :10C5600000000000000000000000000000000000CB :10C5700000000000000000000000000000000000BB :10C5800000000000000000000000000000000000AB :10C59000000000000000000000000000000000009B :10C5A000000000000000000000000000000000008B :10C5B000000000000000000000000000000000007B :10C5C000000000000000000000000000000000006B :10C5D000000000000000000000000000000000005B :10C5E000000000000000000000000000000000004B :10C5F000000000000000000000000000000000003B :10C60000000000000000000000000000000000002A :10C61000000000000000000000000000000000001A :10C62000000000000000000000000000000000000A :10C6300000000000000000000000000000000000FA :10C6400000000000000000000000000000000000EA :10C6500000000000000000000000000000000000DA :10C6600000000000000000000000000000000000CA :10C6700000000000000000000000000000000000BA :10C6800000000000000000000000000000000000AA :10C69000000000000000000000000000000000009A :10C6A000000000000000000000000000000000008A :10C6B000000000000000000000000000000000007A :10C6C000000000000000000000000000000000006A :10C6D000000000000000000000000000000000005A :10C6E000000000000000000000000000000000004A :10C6F000000000000000000000000000000000003A :10C700000000000000000000000000000000000029 :10C710000000000000000000000000000000000019 :10C720000000000000000000000000000000000009 :10C7300000000000000000000000000000000000F9 :10C7400000000000000000000000000000000000E9 :10C7500000000000000000000000000000000000D9 :10C7600000000000000000000000000000000000C9 :10C7700000000000000000000000000000000000B9 :10C7800000000000000000000000000000000000A9 :10C790000000000000000000000000000000000099 :10C7A0000000000000000000000000000000000089 :10C7B0000000000000000000000000000000000079 :10C7C0000000000000000000000000000000000069 :10C7D0000000000000000000000000000000000059 :10C7E0000000000000000000000000000000000049 :10C7F0000000000000000000000000000000000039 :10C800000000000000000000000000000000000028 :10C810000000000000000000000000000000000018 :10C820000000000000000000000000000000000008 :10C8300000000000000000000000000000000000F8 :10C8400000000000000000000000000000000000E8 :10C8500000000000000000000000000000000000D8 :10C8600000000000000000000000000000000000C8 :10C8700000000000000000000000000000000000B8 :10C8800000000000000000000000000000000000A8 :10C890000000000000000000000000000000000098 :10C8A0000000000000000000000000000000000088 :10C8B0000000000000000000000000000000000078 :10C8C0000000000000000000000000000000000068 :10C8D0000000000000000000000000000000000058 :10C8E0000000000000000000000000000000000048 :10C8F0000000000000000000000000000000000038 :10C900000000000000000000000000000000000027 :10C910000000000000000000000000000000000017 :10C920000000000000000000000000000000000007 :10C9300000000000000000000000000000000000F7 :10C9400000000000000000000000000000000000E7 :10C9500000000000000000000000000000000000D7 :10C9600000000000000000000000000000000000C7 :10C9700000000000000000000000000000000000B7 :10C9800000000000000000000000000000000000A7 :10C990000000000000000000000000000000000097 :10C9A0000000000000000000000000000000000087 :10C9B0000000000000000000000000000000000077 :10C9C0000000000000000000000000000000000067 :10C9D0000000000000000000000000000000000057 :10C9E0000000000000000000000000000000000047 :10C9F0000000000000000000000000000000000037 :10CA00000000000000000000000000000000000026 :10CA10000000000000000000000000000000000016 :10CA20000000000000000000000000000000000006 :10CA300000000000000000000000000000000000F6 :10CA400000000000000000000000000000000000E6 :10CA500000000000000000000000000000000000D6 :10CA600000000000000000000000000000000000C6 :10CA700000000000000000000000000000000000B6 :10CA800000000000000000000000000000000000A6 :10CA90000000000000000000000000000000000096 :10CAA0000000000000000000000000000000000086 :10CAB0000000000000000000000000000000000076 :10CAC0000000000000000000000000000000000066 :10CAD0000000000000000000000000000000000056 :10CAE0000000000000000000000000000000000046 :10CAF0000000000000000000000000000000000036 :10CB00000000000000000000000000000000000025 :10CB10000000000000000000000000000000000015 :10CB20000000000000000000000000000000000005 :10CB300000000000000000000000000000000000F5 :10CB400000000000000000000000000000000000E5 :10CB500000000000000000000000000000000000D5 :10CB600000000000000000000000000000000000C5 :10CB700000000000000000000000000000000000B5 :10CB800000000000000000000000000000000000A5 :10CB90000000000000000000000000000000000095 :10CBA0000000000000000000000000000000000085 :10CBB0000000000000000000000000000000000075 :10CBC0000000000000000000000000000000000065 :10CBD0000000000000000000000000000000000055 :10CBE0000000000000000000000000000000000045 :10CBF0000000000000000000000000000000000035 :10CC00000000000000000000000000000000000024 :10CC10000000000000000000000000000000000014 :10CC20000000000000000000000000000000000004 :10CC300000000000000000000000000000000000F4 :10CC400000000000000000000000000000000000E4 :10CC500000000000000000000000000000000000D4 :10CC600000000000000000000000000000000000C4 :10CC700000000000000000000000000000000000B4 :10CC800000000000000000000000000000000000A4 :10CC90000000000000000000000000000000000094 :10CCA0000000000000000000000000000000000084 :10CCB0000000000000000000000000000000000074 :10CCC0000000000000000000000000000000000064 :10CCD0000000000000000000000000000000000054 :10CCE0000000000000000000000000000000000044 :10CCF0000000000000000000000000000000000034 :10CD00000000000000000000000000000000000023 :10CD10000000000000000000000000000000000013 :10CD20000000000000000000000000000000000003 :10CD300000000000000000000000000000000000F3 :10CD400000000000000000000000000000000000E3 :10CD500000000000000000000000000000000000D3 :10CD600000000000000000000000000000000000C3 :10CD700000000000000000000000000000000000B3 :10CD800000000000000000000000000000000000A3 :10CD90000000000000000000000000000000000093 :10CDA0000000000000000000000000000000000083 :10CDB0000000000000000000000000000000000073 :10CDC0000000000000000000000000000000000063 :10CDD0000000000000000000000000000000000053 :10CDE0000000000000000000000000000000000043 :10CDF0000000000000000000000000000000000033 :10CE00000000000000000000000000000000000022 :10CE10000000000000000000000000000000000012 :10CE20000000000000000000000000000000000002 :10CE300000000000000000000000000000000000F2 :10CE400000000000000000000000000000000000E2 :10CE500000000000000000000000000000000000D2 :10CE600000000000000000000000000000000000C2 :10CE700000000000000000000000000000000000B2 :10CE800000000000000000000000000000000000A2 :10CE90000000000000000000000000000000000092 :10CEA0000000000000000000000000000000000082 :10CEB0000000000000000000000000000000000072 :10CEC0000000000000000000000000000000000062 :10CED0000000000000000000000000000000000052 :10CEE0000000000000000000000000000000000042 :10CEF0000000000000000000000000000000000032 :10CF00000000000000000000000000000000000021 :10CF10000000000000000000000000000000000011 :10CF20000000000000000000000000000000000001 :10CF300000000000000000000000000000000000F1 :10CF400000000000000000000000000000000000E1 :10CF500000000000000000000000000000000000D1 :10CF600000000000000000000000000000000000C1 :10CF700000000000000000000000000000000000B1 :10CF800000000000000000000000000000000000A1 :10CF90000000000000000000000000000000000091 :10CFA0000000000000000000000000000000000081 :10CFB0000000000000000000000000000000000071 :10CFC0000000000000000000000000000000000061 :10CFD0000000000000000000000000000000000051 :10CFE0000000000000000000000000000000000041 :10CFF0000000000000000000000000000000000031 :10D000000000000000000000000000000000000020 :10D010000000000000000000000000000000000010 :10D020000000000000000000000000000000000000 :10D0300000000000000000000000000000000000F0 :10D0400000000000000000000000000000000000E0 :10D0500000000000000000000000000000000000D0 :10D0600000000000000000000000000000000000C0 :10D0700000000000000000000000000000000000B0 :10D0800000000000000000000000000000000000A0 :10D090000000000000000000000000000000000090 :10D0A0000000000000000000000000000000000080 :10D0B0000000000000000000000000000000000070 :10D0C0000000000000000000000000000000000060 :10D0D0000000000000000000000000000000000050 :10D0E0000000000000000000000000000000000040 :10D0F0000000000000000000000000000000000030 :10D10000000000000000000000000000000000001F :10D11000000000000000000000000000000000000F :10D1200000000000000000000000000000000000FF :10D1300000000000000000000000000000000000EF :10D1400000000000000000000000000000000000DF :10D1500000000000000000000000000000000000CF :10D1600000000000000000000000000000000000BF :10D1700000000000000000000000000000000000AF :10D18000000000000000000000000000000000009F :10D19000000000000000000000000000000000008F :10D1A000000000000000000000000000000000007F :10D1B000000000000000000000000000000000006F :10D1C000000000000000000000000000000000005F :10D1D000000000000000000000000000000000004F :10D1E000000000000000000000000000000000003F :10D1F000000000000000000000000000000000002F :10D20000000000000000000000000000000000001E :10D21000000000000000000000000000000000000E :10D2200000000000000000000000000000000000FE :10D2300000000000000000000000000000000000EE :10D2400000000000000000000000000000000000DE :10D2500000000000000000000000000000000000CE :10D2600000000000000000000000000000000000BE :10D2700000000000000000000000000000000000AE :10D28000000000000000000000000000000000009E :10D29000000000000000000000000000000000008E :10D2A000000000000000000000000000000000007E :10D2B000000000000000000000000000000000006E :10D2C000000000000000000000000000000000005E :10D2D000000000000000000000000000000000004E :10D2E000000000000000000000000000000000003E :10D2F000000000000000000000000000000000002E :10D30000000000000000000000000000000000001D :10D31000000000000000000000000000000000000D :10D3200000000000000000000000000000000000FD :10D3300000000000000000000000000000000000ED :10D3400000000000000000000000000000000000DD :10D3500000000000000000000000000000000000CD :10D3600000000000000000000000000000000000BD :10D3700000000000000000000000000000000000AD :10D38000000000000000000000000000000000009D :10D39000000000000000000000000000000000008D :10D3A000000000000000000000000000000000007D :10D3B000000000000000000000000000000000006D :10D3C000000000000000000000000000000000005D :10D3D000000000000000000000000000000000004D :10D3E000000000000000000000000000000000003D :10D3F000000000000000000000000000000000002D :10D40000000000000000000000000000000000001C :10D41000000000000000000000000000000000000C :10D4200000000000000000000000000000000000FC :10D4300000000000000000000000000000000000EC :10D4400000000000000000000000000000000000DC :10D4500000000000000000000000000000000000CC :10D4600000000000000000000000000000000000BC :10D4700000000000000000000000000000000000AC :10D48000000000000000000000000000000000009C :10D49000000000000000000000000000000000008C :10D4A000000000000000000000000000000000007C :10D4B000000000000000000000000000000000006C :10D4C000000000000000000000000000000000005C :10D4D000000000000000000000000000000000004C :10D4E000000000000000000000000000000000003C :10D4F000000000000000000000000000000000002C :10D50000000000000000000000000000000000001B :10D51000000000000000000000000000000000000B :10D5200000000000000000000000000000000000FB :10D5300000000000000000000000000000000000EB :10D5400000000000000000000000000000000000DB :10D5500000000000000000000000000000000000CB :10D5600000000000000000000000000000000000BB :10D5700000000000000000000000000000000000AB :10D58000000000000000000000000000000000009B :10D59000000000000000000000000000000000008B :10D5A000000000000000000000000000000000007B :10D5B000000000000000000000000000000000006B :10D5C000000000000000000000000000000000005B :10D5D000000000000000000000000000000000004B :10D5E000000000000000000000000000000000003B :10D5F000000000000000000000000000000000002B :10D60000000000000000000000000000000000001A :10D61000000000000000000000000000000000000A :10D6200000000000000000000000000000000000FA :10D6300000000000000000000000000000000000EA :10D6400000000000000000000000000000000000DA :10D6500000000000000000000000000000000000CA :10D6600000000000000000000000000000000000BA :10D6700000000000000000000000000000000000AA :10D68000000000000000000000000000000000009A :10D69000000000000000000000000000000000008A :10D6A000000000000000000000000000000000007A :10D6B000000000000000000000000000000000006A :10D6C000000000000000000000000000000000005A :10D6D000000000000000000000000000000000004A :10D6E000000000000000000000000000000000003A :10D6F000000000000000000000000000000000002A :10D700000000000000000000000000000000000019 :10D710000000000000000000000000000000000009 :10D7200000000000000000000000000000000000F9 :10D7300000000000000000000000000000000000E9 :10D7400000000000000000000000000000000000D9 :10D7500000000000000000000000000000000000C9 :10D7600000000000000000000000000000000000B9 :10D7700000000000000000000000000000000000A9 :10D780000000000000000000000000000000000099 :10D790000000000000000000000000000000000089 :10D7A0000000000000000000000000000000000079 :10D7B0000000000000000000000000000000000069 :10D7C0000000000000000000000000000000000059 :10D7D0000000000000000000000000000000000049 :10D7E0000000000000000000000000000000000039 :10D7F0000000000000000000000000000000000029 :10D800000000000000000000000000000000000018 :10D810000000000000000000000000000000000008 :10D8200000000000000000000000000000000000F8 :10D8300000000000000000000000000000000000E8 :10D8400000000000000000000000000000000000D8 :10D8500000000000000000000000000000000000C8 :10D8600000000000000000000000000000000000B8 :10D8700000000000000000000000000000000000A8 :10D880000000000000000000000000000000000098 :10D890000000000000000000000000000000000088 :10D8A0000000000000000000000000000000000078 :10D8B0000000000000000000000000000000000068 :10D8C0000000000000000000000000000000000058 :10D8D0000000000000000000000000000000000048 :10D8E0000000000000000000000000000000000038 :10D8F0000000000000000000000000000000000028 :10D900000000000000000000000000000000000017 :10D910000000000000000000000000000000000007 :10D9200000000000000000000000000000000000F7 :10D9300000000000000000000000000000000000E7 :10D9400000000000000000000000000000000000D7 :10D9500000000000000000000000000000000000C7 :10D9600000000000000000000000000000000000B7 :10D9700000000000000000000000000000000000A7 :10D980000000000000000000000000000000000097 :10D990000000000000000000000000000000000087 :10D9A0000000000000000000000000000000000077 :10D9B0000000000000000000000000000000000067 :10D9C0000000000000000000000000000000000057 :10D9D0000000000000000000000000000000000047 :10D9E0000000000000000000000000000000000037 :10D9F0000000000000000000000000000000000027 :10DA00000000000000000000000000000000000016 :10DA10000000000000000000000000000000000006 :10DA200000000000000000000000000000000000F6 :10DA300000000000000000000000000000000000E6 :10DA400000000000000000000000000000000000D6 :10DA500000000000000000000000000000000000C6 :10DA600000000000000000000000000000000000B6 :10DA700000000000000000000000000000000000A6 :10DA80000000000000000000000000000000000096 :10DA90000000000000000000000000000000000086 :10DAA0000000000000000000000000000000000076 :10DAB0000000000000000000000000000000000066 :10DAC0000000000000000000000000000000000056 :10DAD0000000000000000000000000000000000046 :10DAE0000000000000000000000000000000000036 :10DAF0000000000000000000000000000000000026 :10DB00000000000000000000000000000000000015 :10DB10000000000000000000000000000000000005 :10DB200000000000000000000000000000000000F5 :10DB300000000000000000000000000000000000E5 :10DB400000000000000000000000000000000000D5 :10DB500000000000000000000000000000000000C5 :10DB600000000000000000000000000000000000B5 :10DB700000000000000000000000000000000000A5 :10DB80000000000000000000000000000000000095 :10DB90000000000000000000000000000000000085 :10DBA0000000000000000000000000000000000075 :10DBB0000000000000000000000000000000000065 :10DBC0000000000000000000000000000000000055 :10DBD0000000000000000000000000000000000045 :10DBE0000000000000000000000000000000000035 :10DBF0000000000000000000000000000000000025 :10DC00000000000000000000000000000000000014 :10DC10000000000000000000000000000000000004 :10DC200000000000000000000000000000000000F4 :10DC300000000000000000000000000000000000E4 :10DC400000000000000000000000000000000000D4 :10DC500000000000000000000000000000000000C4 :10DC600000000000000000000000000000000000B4 :10DC700000000000000000000000000000000000A4 :10DC80000000000000000000000000000000000094 :10DC90000000000000000000000000000000000084 :10DCA0000000000000000000000000000000000074 :10DCB0000000000000000000000000000000000064 :10DCC0000000000000000000000000000000000054 :10DCD0000000000000000000000000000000000044 :10DCE0000000000000000000000000000000000034 :10DCF0000000000000000000000000000000000024 :10DD00000000000000000000000000000000000013 :10DD10000000000000000000000000000000000003 :10DD200000000000000000000000000000000000F3 :10DD300000000000000000000000000000000000E3 :10DD400000000000000000000000000000000000D3 :10DD500000000000000000000000000000000000C3 :10DD600000000000000000000000000000000000B3 :10DD700000000000000000000000000000000000A3 :10DD80000000000000000000000000000000000093 :10DD90000000000000000000000000000000000083 :10DDA0000000000000000000000000000000000073 :10DDB0000000000000000000000000000000000063 :10DDC0000000000000000000000000000000000053 :10DDD0000000000000000000000000000000000043 :10DDE0000000000000000000000000000000000033 :10DDF0000000000000000000000000000000000023 :10DE00000000000000000000000000000000000012 :10DE10000000000000000000000000000000000002 :10DE200000000000000000000000000000000000F2 :10DE300000000000000000000000000000000000E2 :10DE400000000000000000000000000000000000D2 :10DE500000000000000000000000000000000000C2 :10DE600000000000000000000000000000000000B2 :10DE700000000000000000000000000000000000A2 :10DE80000000000000000000000000000000000092 :10DE90000000000000000000000000000000000082 :10DEA0000000000000000000000000000000000072 :10DEB0000000000000000000000000000000000062 :10DEC0000000000000000000000000000000000052 :10DED0000000000000000000000000000000000042 :10DEE0000000000000000000000000000000000032 :10DEF0000000000000000000000000000000000022 :10DF00000000000000000000000000000000000011 :10DF10000000000000000000000000000000000001 :10DF200000000000000000000000000000000000F1 :10DF300000000000000000000000000000000000E1 :10DF400000000000000000000000000000000000D1 :10DF500000000000000000000000000000000000C1 :10DF600000000000000000000000000000000000B1 :10DF700000000000000000000000000000000000A1 :10DF80000000000000000000000000000000000091 :10DF90000000000000000000000000000000000081 :10DFA0000000000000000000000000000000000071 :10DFB0000000000000000000000000000000000061 :10DFC0000000000000000000000000000000000051 :10DFD0000000000000000000000000000000000041 :10DFE0000000000000000000000000000000000031 :10DFF0000000000000000000000000000000000021 :10E000000000000000000000000000000000000010 :10E010000000000000000000000000000000000000 :10E0200000000000000000000000000000000000F0 :10E0300000000000000000000000000000000000E0 :10E0400000000000000000000000000000000000D0 :10E0500000000000000000000000000000000000C0 :10E0600000000000000000000000000000000000B0 :10E0700000000000000000000000000000000000A0 :10E080000000000000000000000000000000000090 :10E090000000000000000000000000000000000080 :10E0A0000000000000000000000000000000000070 :10E0B0000000000000000000000000000000000060 :10E0C0000000000000000000000000000000000050 :10E0D0000000000000000000000000000000000040 :10E0E0000000000000000000000000000000000030 :10E0F0000000000000000000000000000000000020 :10E10000000000000000000000000000000000000F :10E1100000000000000000000000000000000000FF :10E1200000000000000000000000000000000000EF :10E1300000000000000000000000000000000000DF :10E1400000000000000000000000000000000000CF :10E1500000000000000000000000000000000000BF :10E1600000000000000000000000000000000000AF :10E17000000000000000000000000000000000009F :10E18000000000000000000000000000000000008F :10E19000000000000000000000000000000000007F :10E1A000000000000000000000000000000000006F :10E1B000000000000000000000000000000000005F :10E1C000000000000000000000000000000000004F :10E1D000000000000000000000000000000000003F :10E1E000000000000000000000000000000000002F :10E1F000000000000000000000000000000000001F :10E20000000000000000000000000000000000000E :10E2100000000000000000000000000000000000FE :10E2200000000000000000000000000000000000EE :10E2300000000000000000000000000000000000DE :10E2400000000000000000000000000000000000CE :10E2500000000000000000000000000000000000BE :10E2600000000000000000000000000000000000AE :10E27000000000000000000000000000000000009E :10E28000000000000000000000000000000000008E :10E29000000000000000000000000000000000007E :10E2A000000000000000000000000000000000006E :10E2B000000000000000000000000000000000005E :10E2C000000000000000000000000000000000004E :10E2D000000000000000000000000000000000003E :10E2E000000000000000000000000000000000002E :10E2F000000000000000000000000000000000001E :10E30000000000000000000000000000000000000D :10E3100000000000000000000000000000000000FD :10E3200000000000000000000000000000000000ED :10E3300000000000000000000000000000000000DD :10E3400000000000000000000000000000000000CD :10E3500000000000000000000000000000000000BD :10E3600000000000000000000000000000000000AD :10E37000000000000000000000000000000000009D :10E38000000000000000000000000000000000008D :10E39000000000000000000000000000000000007D :10E3A000000000000000000000000000000000006D :10E3B000000000000000000000000000000000005D :10E3C000000000000000000000000000000000004D :10E3D000000000000000000000000000000000003D :10E3E000000000000000000000000000000000002D :10E3F000000000000000000000000000000000001D :10E40000000000000000000000000000000000000C :10E4100000000000000000000000000000000000FC :10E4200000000000000000000000000000000000EC :10E4300000000000000000000000000000000000DC :10E4400000000000000000000000000000000000CC :10E4500000000000000000000000000000000000BC :10E4600000000000000000000000000000000000AC :10E47000000000000000000000000000000000009C :10E48000000000000000000000000000000000008C :10E49000000000000000000000000000000000007C :10E4A000000000000000000000000000000000006C :10E4B000000000000000000000000000000000005C :10E4C000000000000000000000000000000000004C :10E4D000000000000000000000000000000000003C :10E4E000000000000000000000000000000000002C :10E4F000000000000000000000000000000000001C :10E50000000000000000000000000000000000000B :10E5100000000000000000000000000000000000FB :10E5200000000000000000000000000000000000EB :10E5300000000000000000000000000000000000DB :10E5400000000000000000000000000000000000CB :10E5500000000000000000000000000000000000BB :10E5600000000000000000000000000000000000AB :10E57000000000000000000000000000000000009B :10E58000000000000000000000000000000000008B :10E59000000000000000000000000000000000007B :10E5A000000000000000000000000000000000006B :10E5B000000000000000000000000000000000005B :10E5C000000000000000000000000000000000004B :10E5D000000000000000000000000000000000003B :10E5E000000000000000000000000000000000002B :10E5F000000000000000000000000000000000001B :10E60000000000000000000000000000000000000A :10E6100000000000000000000000000000000000FA :10E6200000000000000000000000000000000000EA :10E6300000000000000000000000000000000000DA :10E6400000000000000000000000000000000000CA :10E6500000000000000000000000000000000000BA :10E6600000000000000000000000000000000000AA :10E67000000000000000000000000000000000009A :10E68000000000000000000000000000000000008A :10E69000000000000000000000000000000000007A :10E6A000000000000000000000000000000000006A :10E6B000000000000000000000000000000000005A :10E6C000000000000000000000000000000000004A :10E6D000000000000000000000000000000000003A :10E6E000000000000000000000000000000000002A :10E6F000000000000000000000000000000000001A :10E700000000000000000000000000000000000009 :10E7100000000000000000000000000000000000F9 :10E7200000000000000000000000000000000000E9 :10E7300000000000000000000000000000000000D9 :10E7400000000000000000000000000000000000C9 :10E7500000000000000000000000000000000000B9 :10E7600000000000000000000000000000000000A9 :10E770000000000000000000000000000000000099 :10E780000000000000000000000000000000000089 :10E790000000000000000000000000000000000079 :10E7A0000000000000000000000000000000000069 :10E7B0000000000000000000000000000000000059 :10E7C0000000000000000000000000000000000049 :10E7D0000000000000000000000000000000000039 :10E7E0000000000000000000000000000000000029 :10E7F0000000000000000000000000000000000019 :10E800000000000000000000000000000000000008 :10E8100000000000000000000000000000000000F8 :10E8200000000000000000000000000000000000E8 :10E8300000000000000000000000000000000000D8 :10E8400000000000000000000000000000000000C8 :10E8500000000000000000000000000000000000B8 :10E8600000000000000000000000000000000000A8 :10E870000000000000000000000000000000000098 :10E880000000000000000000000000000000000088 :10E890000000000000000000000000000000000078 :10E8A0000000000000000000000000000000000068 :10E8B0000000000000000000000000000000000058 :10E8C0000000000000000000000000000000000048 :10E8D0000000000000000000000000000000000038 :10E8E0000000000000000000000000000000000028 :10E8F0000000000000000000000000000000000018 :10E900000000000000000000000000000000000007 :10E9100000000000000000000000000000000000F7 :10E9200000000000000000000000000000000000E7 :10E9300000000000000000000000000000000000D7 :10E9400000000000000000000000000000000000C7 :10E9500000000000000000000000000000000000B7 :10E9600000000000000000000000000000000000A7 :10E970000000000000000000000000000000000097 :10E980000000000000000000000000000000000087 :10E990000000000000000000000000000000000077 :10E9A0000000000000000000000000000000000067 :10E9B0000000000000000000000000000000000057 :10E9C0000000000000000000000000000000000047 :10E9D0000000000000000000000000000000000037 :10E9E0000000000000000000000000000000000027 :10E9F0000000000000000000000000000000000017 :10EA00000000000000000000000000000000000006 :10EA100000000000000000000000000000000000F6 :10EA200000000000000000000000000000000000E6 :10EA300000000000000000000000000000000000D6 :10EA400000000000000000000000000000000000C6 :10EA500000000000000000000000000000000000B6 :10EA600000000000000000000000000000000000A6 :10EA70000000000000000000000000000000000096 :10EA80000000000000000000000000000000000086 :10EA90000000000000000000000000000000000076 :10EAA0000000000000000000000000000000000066 :10EAB0000000000000000000000000000000000056 :10EAC0000000000000000000000000000000000046 :10EAD0000000000000000000000000000000000036 :10EAE0000000000000000000000000000000000026 :10EAF0000000000000000000000000000000000016 :10EB00000000000000000000000000000000000005 :10EB100000000000000000000000000000000000F5 :10EB200000000000000000000000000000000000E5 :10EB300000000000000000000000000000000000D5 :10EB400000000000000000000000000000000000C5 :10EB500000000000000000000000000000000000B5 :10EB600000000000000000000000000000000000A5 :10EB70000000000000000000000000000000000095 :10EB80000000000000000000000000000000000085 :10EB90000000000000000000000000000000000075 :10EBA0000000000000000000000000000000000065 :10EBB0000000000000000000000000000000000055 :10EBC0000000000000000000000000000000000045 :10EBD0000000000000000000000000000000000035 :10EBE0000000000000000000000000000000000025 :10EBF0000000000000000000000000000000000015 :10EC00000000000000000000000000000000000004 :10EC100000000000000000000000000000000000F4 :10EC200000000000000000000000000000000000E4 :10EC300000000000000000000000000000000000D4 :10EC400000000000000000000000000000000000C4 :10EC500000000000000000000000000000000000B4 :10EC600000000000000000000000000000000000A4 :10EC70000000000000000000000000000000000094 :10EC80000000000000000000000000000000000084 :10EC90000000000000000000000000000000000074 :10ECA0000000000000000000000000000000000064 :10ECB0000000000000000000000000000000000054 :10ECC0000000000000000000000000000000000044 :10ECD0000000000000000000000000000000000034 :10ECE0000000000000000000000000000000000024 :10ECF0000000000000000000000000000000000014 :10ED00000000000000000000000000000000000003 :10ED100000000000000000000000000000000000F3 :10ED200000000000000000000000000000000000E3 :10ED300000000000000000000000000000000000D3 :10ED400000000000000000000000000000000000C3 :10ED500000000000000000000000000000000000B3 :10ED600000000000000000000000000000000000A3 :10ED70000000000000000000000000000000000093 :10ED80000000000000000000000000000000000083 :10ED90000000000000000000000000000000000073 :10EDA0000000000000000000000000000000000063 :10EDB0000000000000000000000000000000000053 :10EDC0000000000000000000000000000000000043 :10EDD0000000000000000000000000000000000033 :10EDE0000000000000000000000000000000000023 :10EDF0000000000000000000000000000000000013 :10EE00000000000000000000000000000000000002 :10EE100000000000000000000000000000000000F2 :10EE200000000000000000000000000000000000E2 :10EE300000000000000000000000000000000000D2 :10EE400000000000000000000000000000000000C2 :10EE500000000000000000000000000000000000B2 :10EE600000000000000000000000000000000000A2 :10EE70000000000000000000000000000000000092 :10EE80000000000000000000000000000000000082 :10EE90000000000000000000000000000000000072 :10EEA0000000000000000000000000000000000062 :10EEB0000000000000000000000000000000000052 :10EEC0000000000000000000000000000000000042 :10EED0000000000000000000000000000000000032 :10EEE0000000000000000000000000000000000022 :10EEF0000000000000000000000000000000000012 :10EF00000000000000000000000000000000000001 :10EF100000000000000000000000000000000000F1 :10EF200000000000000000000000000000000000E1 :10EF300000000000000000000000000000000000D1 :10EF400000000000000000000000000000000000C1 :10EF500000000000000000000000000000000000B1 :10EF600000000000000000000000000000000000A1 :10EF70000000000000000000000000000000000091 :10EF80000000000000000000000000000000000081 :10EF90000000000000000000000000000000000071 :10EFA0000000000000000000000000000000000061 :10EFB0000000000000000000000000000000000051 :10EFC0000000000000000000000000000000000041 :10EFD0000000000000000000000000000000000031 :10EFE0000000000000000000000000000000000021 :10EFF0000000000000000000000000000000000011 :10F000000000000000000000000000000000000000 :10F0100000000000000000000000000000000000F0 :10F0200000000000000000000000000000000000E0 :10F0300000000000000000000000000000000000D0 :10F0400000000000000000000000000000000000C0 :10F0500000000000000000000000000000000000B0 :10F0600000000000000000000000000000000000A0 :10F070000000000000000000000000000000000090 :10F080000000000000000000000000000000000080 :10F090000000000000000000000000000000000070 :10F0A0000000000000000000000000000000000060 :10F0B0000000000000000000000000000000000050 :10F0C0000000000000000000000000000000000040 :10F0D0000000000000000000000000000000000030 :10F0E0000000000000000000000000000000000020 :10F0F0000000000000000000000000000000000010 :10F1000000000000000000000000000000000000FF :10F1100000000000000000000000000000000000EF :10F1200000000000000000000000000000000000DF :10F1300000000000000000000000000000000000CF :10F1400000000000000000000000000000000000BF :10F1500000000000000000000000000000000000AF :10F16000000000000000000000000000000000009F :10F17000000000000000000000000000000000008F :10F18000000000000000000000000000000000007F :10F19000000000000000000000000000000000006F :10F1A000000000000000000000000000000000005F :10F1B000000000000000000000000000000000004F :10F1C000000000000000000000000000000000003F :10F1D000000000000000000000000000000000002F :10F1E000000000000000000000000000000000001F :10F1F000000000000000000000000000000000000F :10F2000000000000000000000000000000000000FE :10F2100000000000000000000000000000000000EE :10F2200000000000000000000000000000000000DE :10F2300000000000000000000000000000000000CE :10F2400000000000000000000000000000000000BE :10F2500000000000000000000000000000000000AE :10F26000000000000000000000000000000000009E :10F27000000000000000000000000000000000008E :10F28000000000000000000000000000000000007E :10F29000000000000000000000000000000000006E :10F2A000000000000000000000000000000000005E :10F2B000000000000000000000000000000000004E :10F2C000000000000000000000000000000000003E :10F2D000000000000000000000000000000000002E :10F2E000000000000000000000000000000000001E :10F2F000000000000000000000000000000000000E :10F3000000000000000000000000000000000000FD :10F3100000000000000000000000000000000000ED :10F3200000000000000000000000000000000000DD :10F3300000000000000000000000000000000000CD :10F3400000000000000000000000000000000000BD :10F3500000000000000000000000000000000000AD :10F36000000000000000000000000000000000009D :10F37000000000000000000000000000000000008D :10F38000000000000000000000000000000000007D :10F39000000000000000000000000000000000006D :10F3A000000000000000000000000000000000005D :10F3B000000000000000000000000000000000004D :10F3C000000000000000000000000000000000003D :10F3D000000000000000000000000000000000002D :10F3E000000000000000000000000000000000001D :10F3F000000000000000000000000000000000000D :10F4000000000000000000000000000000000000FC :10F4100000000000000000000000000000000000EC :10F4200000000000000000000000000000000000DC :10F4300000000000000000000000000000000000CC :10F4400000000000000000000000000000000000BC :10F4500000000000000000000000000000000000AC :10F46000000000000000000000000000000000009C :10F47000000000000000000000000000000000008C :10F48000000000000000000000000000000000007C :10F49000000000000000000000000000000000006C :10F4A000000000000000000000000000000000005C :10F4B000000000000000000000000000000000004C :10F4C000000000000000000000000000000000003C :10F4D000000000000000000000000000000000002C :10F4E000000000000000000000000000000000001C :10F4F000000000000000000000000000000000000C :10F5000000000000000000000000000000000000FB :10F5100000000000000000000000000000000000EB :10F5200000000000000000000000000000000000DB :10F5300000000000000000000000000000000000CB :10F5400000000000000000000000000000000000BB :10F5500000000000000000000000000000000000AB :10F56000000000000000000000000000000000009B :10F57000000000000000000000000000000000008B :10F58000000000000000000000000000000000007B :10F59000000000000000000000000000000000006B :10F5A000000000000000000000000000000000005B :10F5B000000000000000000000000000000000004B :10F5C000000000000000000000000000000000003B :10F5D000000000000000000000000000000000002B :10F5E000000000000000000000000000000000001B :10F5F000000000000000000000000000000000000B :10F6000000000000000000000000000000000000FA :10F6100000000000000000000000000000000000EA :10F6200000000000000000000000000000000000DA :10F6300000000000000000000000000000000000CA :10F6400000000000000000000000000000000000BA :10F6500000000000000000000000000000000000AA :10F66000000000000000000000000000000000009A :10F67000000000000000000000000000000000008A :10F68000000000000000000000000000000000007A :10F69000000000000000000000000000000000006A :10F6A000000000000000000000000000000000005A :10F6B000000000000000000000000000000000004A :10F6C000000000000000000000000000000000003A :10F6D000000000000000000000000000000000002A :10F6E000000000000000000000000000000000001A :10F6F000000000000000000000000000000000000A :10F7000000000000000000000000000000000000F9 :10F7100000000000000000000000000000000000E9 :10F7200000000000000000000000000000000000D9 :10F7300000000000000000000000000000000000C9 :10F7400000000000000000000000000000000000B9 :10F7500000000000000000000000000000000000A9 :10F760000000000000000000000000000000000099 :10F770000000000000000000000000000000000089 :10F780000000000000000000000000000000000079 :10F790000000000000000000000000000000000069 :10F7A0000000000000000000000000000000000059 :10F7B0000000000000000000000000000000000049 :10F7C0000000000000000000000000000000000039 :10F7D0000000000000000000000000000000000029 :10F7E0000000000000000000000000000000000019 :10F7F0000000000000000000000000000000000009 :10F8000000000000000000000000000000000000F8 :10F8100000000000000000000000000000000000E8 :10F8200000000000000000000000000000000000D8 :10F8300000000000000000000000000000000000C8 :10F8400000000000000000000000000000000000B8 :10F8500000000000000000000000000000000000A8 :10F860000000000000000000000000000000000098 :10F870000000000000000000000000000000000088 :10F880000000000000000000000000000000000078 :10F890000000000000000000000000000000000068 :10F8A0000000000000000000000000000000000058 :10F8B0000000000000000000000000000000000048 :10F8C0000000000000000000000000000000000038 :10F8D0000000000000000000000000000000000028 :10F8E0000000000000000000000000000000000018 :10F8F0000000000000000000000000000000000008 :10F9000000000000000000000000000000000000F7 :10F9100000000000000000000000000000000000E7 :10F9200000000000000000000000000000000000D7 :10F9300000000000000000000000000000000000C7 :10F9400000000000000000000000000000000000B7 :10F9500000000000000000000000000000000000A7 :10F960000000000000000000000000000000000097 :10F970000000000000000000000000000000000087 :10F980000000000000000000000000000000000077 :10F990000000000000000000000000000000000067 :10F9A0000000000000000000000000000000000057 :10F9B0000000000000000000000000000000000047 :10F9C0000000000000000000000000000000000037 :10F9D0000000000000000000000000000000000027 :10F9E0000000000000000000000000000000000017 :10F9F0000000000000000000000000000000000007 :10FA000000000000000000000000000000000000F6 :10FA100000000000000000000000000000000000E6 :10FA200000000000000000000000000000000000D6 :10FA300000000000000000000000000000000000C6 :10FA400000000000000000000000000000000000B6 :10FA500000000000000000000000000000000000A6 :10FA60000000000000000000000000000000000096 :10FA70000000000000000000000000000000000086 :10FA80000000000000000000000000000000000076 :10FA90000000000000000000000000000000000066 :10FAA0000000000000000000000000000000000056 :10FAB0000000000000000000000000000000000046 :10FAC0000000000000000000000000000000000036 :10FAD0000000000000000000000000000000000026 :10FAE0000000000000000000000000000000000016 :10FAF0000000000000000000000000000000000006 :10FB000000000000000000000000000000000000F5 :10FB100000000000000000000000000000000000E5 :10FB200000000000000000000000000000000000D5 :10FB300000000000000000000000000000000000C5 :10FB400000000000000000000000000000000000B5 :10FB500000000000000000000000000000000000A5 :10FB60000000000000000000000000000000000095 :10FB70000000000000000000000000000000000085 :10FB80000000000000000000000000000000000075 :10FB90000000000000000000000000000000000065 :10FBA0000000000000000000000000000000000055 :10FBB0000000000000000000000000000000000045 :10FBC0000000000000000000000000000000000035 :10FBD0000000000000000000000000000000000025 :10FBE0000000000000000000000000000000000015 :10FBF0000000000000000000000000000000000005 :10FC000000000000000000000000000000000000F4 :10FC100000000000000000000000000000000000E4 :10FC200000000000000000000000000000000000D4 :10FC300000000000000000000000000000000000C4 :10FC400000000000000000000000000000000000B4 :10FC500000000000000000000000000000000000A4 :10FC60000000000000000000000000000000000094 :10FC70000000000000000000000000000000000084 :10FC80000000000000000000000000000000000074 :10FC90000000000000000000000000000000000064 :10FCA0000000000000000000000000000000000054 :10FCB0000000000000000000000000000000000044 :10FCC0000000000000000000000000000000000034 :10FCD0000000000000000000000000000000000024 :10FCE0000000000000000000000000000000000014 :10FCF0000000000000000000000000000000000004 :10FD000000000000000000000000000000000000F3 :10FD100000000000000000000000000000000000E3 :10FD200000000000000000000000000000000000D3 :10FD300000000000000000000000000000000000C3 :10FD400000000000000000000000000000000000B3 :10FD500000000000000000000000000000000000A3 :10FD60000000000000000000000000000000000093 :10FD70000000000000000000000000000000000083 :10FD80000000000000000000000000000000000073 :10FD90000000000000000000000000000000000063 :10FDA0000000000000000000000000000000000053 :10FDB0000000000000000000000000000000000043 :10FDC0000000000000000000000000000000000033 :10FDD0000000000000000000000000000000000023 :10FDE0000000000000000000000000000000000013 :10FDF0000000000000000000000000000000000003 :10FE000000000000000000000000000000000000F2 :10FE100000000000000000000000000000000000E2 :10FE200000000000000000000000000000000000D2 :10FE300000000000000000000000000000000000C2 :10FE400000000000000000000000000000000000B2 :10FE500000000000000000000000000000000000A2 :10FE60000000000000000000000000000000000092 :10FE70000000000000000000000000000000000082 :10FE80000000000000000000000000000000000072 :10FE90000000000000000000000000000000000062 :10FEA0000000000000000000000000000000000052 :10FEB0000000000000000000000000000000000042 :10FEC0000000000000000000000000000000000032 :10FED0000000000000000000000000000000000022 :10FEE0000000000000000000000000000000000012 :10FEF0000000000000000000000000000000000002 :10FF000000000000000000000000000000000000F1 :10FF100000000000000000000000000000000000E1 :10FF200000000000000000000000000000000000D1 :10FF300000000000000000000000000000000000C1 :10FF400000000000000000000000000000000000B1 :10FF500000000000000000000000000000000000A1 :10FF60000000000000000000000000000000000091 :10FF70000000000000000000000000000000000081 :10FF80000000000000000000000000000000000071 :10FF90000000000000000000000000000000000061 :10FFA0000000000000000000000000000000000051 :10FFB0000000000000000000000000000000000041 :10FFC0000000000000000000000000000000000031 :10FFD0000000000000000000000000000000000021 :10FFE0000000000000000000000000000000000011 :10FFF0000000000000000000000000000000000001 :02000004620296 :1000000000000000000000000000000000000000F0 :1000100000000000000000000000000000000000E0 :1000200000000000000000000000000000000000D0 :1000300000000000000000000000000000000000C0 :1000400000000000000000000000000000000000B0 :1000500000000000000000000000000000000000A0 :100060000000000000000000000000000000000090 :100070000000000000000000000000000000000080 :100080000000000000000000000000000000000070 :100090000000000000000000000000000000000060 :1000A0000000000000000000000000000000000050 :1000B0000000000000000000000000000000000040 :1000C0000000000000000000000000000000000030 :1000D0000000000000000000000000000000000020 :1000E0000000000000000000000000000000000010 :1000F0000000000000000000000000000000000000 :1001000000000000000000000000000000000000EF :1001100000000000000000000000000000000000DF :1001200000000000000000000000000000000000CF :1001300000000000000000000000000000000000BF :1001400000000000000000000000000000000000AF :10015000000000000000000000000000000000009F :10016000000000000000000000000000000000008F :10017000000000000000000000000000000000007F :10018000000000000000000000000000000000006F :10019000000000000000000000000000020000005D :1001A000000000000000000000000000000000004F :1001B000000000000000000000000000000000003F :1001C000000000000000000000000000000000002F :1001D000000000000000000000000000000000001F :1001E000000000000000000000000000000000000F :1001F00000000000000000000000000000000000FF :1002000000000000000000000000000000000000EE :1002100000000000000000000000000000000000DE :1002200000000000000000000000000000000000CE :1002300000000000000000000000000000000000BE :1002400000000000000000000000000000000000AE :10025000000000000000000000000000000000009E :10026000000000000000000000000000000000008E :10027000000000000000000000000000000000007E :10028000000000000000000000000000000000006E :10029000000000000000000000000000000000005E :1002A000000000000000000000000000000000004E :1002B000000000000000000000000000000000003E :1002C000000000000000000000000000000000002E :1002D000000000000000000000000000000000001E :1002E000000000000000000000000000000000000E :1002F00000000000000000000000000000000000FE :1003000000000000000000000000000000000000ED :1003100000000000000000000000000000000000DD :1003200000000000000000000000000000000000CD :1003300000000000000000000000000000000000BD :1003400000000000000000000000000000000000AD :10035000000000000000000000000000000000009D :10036000000000000000000000000000000000008D :10037000000000000000000000000000000000007D :10038000000000000000000000000000000000006D :10039000000000000000000000000000000000005D :1003A000000000000000000000000000000000004D :1003B000000000000000000000000000000000003D :1003C000000000000000000000000000000000002D :1003D000000000000000000000000000000000001D :1003E000000000000000000000000000000000000D :1003F00000000000000000000000000000000000FD :1004000000000000000000000000000000000000EC :1004100000000000000000000000000000000000DC :1004200000000000000000000000000000000000CC :1004300000000000000000000000000000000000BC :1004400000000000000000000000000000000000AC :10045000000000000000000000000000000000009C :10046000000000000000000000000000000000008C :10047000000000000000000000000000000000007C :10048000000000000000000000000000000000006C :10049000000000000000000000000000000000005C :1004A000000000000000000000000000000000004C :1004B000000000000000000000000000000000003C :1004C000000000000000000000000000000000002C :1004D000000000000000000000000000000000001C :1004E000000000000000000000000000000000000C :1004F00000000000000000000000000000000000FC :1005000000000000000000000000000000000000EB :1005100000000000000000000000000000000000DB :1005200000000000000000000000000000000000CB :1005300000000000000000000000000000000000BB :1005400000000000000000000000000000000000AB :10055000000000000000000000000000000000009B :10056000000000000000000000000000000000008B :10057000000000000000000000000000000000007B :10058000000000000000000000000000000000006B :10059000000000000000000000000000000000005B :1005A000000000000000000000000000000000004B :1005B000000000000000000000000000000000003B :1005C000000000000000000000000000000000002B :1005D000000000000000000000000000000000001B :1005E000000000000000000000000000000000000B :1005F00000000000000000000000000000000000FB :1006000000000000000000000000000000000000EA :1006100000000000000000000000000000000000DA :1006200000000000000000000000000000000000CA :1006300000000000000000000000000000000000BA :1006400000000000000000000000000000000000AA :10065000000000000000000000000000000000009A :10066000000000000000000000000000000000008A :10067000000000000000000000000000000000007A :10068000000000000000000000000000000000006A :10069000000000000000000000000000000000005A :1006A000000000000000000000000000000000004A :1006B000000000000000000000000000000000003A :1006C000000000000000000000000000000000002A :1006D000000000000000000000000000000000001A :1006E000000000000000000000000000000000000A :1006F00000000000000000000000000000000000FA :1007000000000000000000000000000000000000E9 :1007100000000000000000000000000000000000D9 :1007200000000000000000000000000000000000C9 :1007300000000000000000000000000000000000B9 :1007400000000000000000000000000000000000A9 :100750000000000000000000000000000000000099 :100760000000000000000000000000000000000089 :100770000000000000000000000000000000000079 :100780000000000000000000000000000000000069 :100790000000000000000000000000000000000059 :1007A0000000000000000000000000000000000049 :1007B0000000000000000000000000000000000039 :1007C0000000000000000000000000000000000029 :1007D0000000000000000000000000000000000019 :1007E0000000000000000000000000000000000009 :1007F00000000000000000000000000000000000F9 :1008000000000000000000000000000000000000E8 :1008100000000000000000000000000000000000D8 :1008200000000000000000000000000000000000C8 :1008300000000000000000000000000000000000B8 :1008400000000000000000000000000000000000A8 :100850000000000000000000000000000000000098 :100860000000000000000000000000000000000088 :100870000000000000000000000000000000000078 :100880000000000000000000000000000000000068 :100890000000000000000000000000000000000058 :1008A0000000000000000000000000000000000048 :1008B0000000000000000000000000000000000038 :1008C0000000000000000000000000000000000028 :1008D0000000000000000000000000000000000018 :1008E0000000000000000000000000000000000008 :1008F00000000000000000000000000000000000F8 :1009000000000000000000000000000000000000E7 :1009100000000000000000000000000000000000D7 :1009200000000000000000000000000000000000C7 :1009300000000000000000000000000000000000B7 :1009400000000000000000000000000000000000A7 :100950000000000000000000000000000000000097 :100960000000000000000000000000000000000087 :100970000000000000000000000000000000000077 :100980000000000000000000000000000000000067 :100990000000000000000000000000000000000057 :1009A0000000000000000000000000000000000047 :1009B0000000000000000000000000000000000037 :1009C0000000000000000000000000000000000027 :1009D0000000000000000000000000000000000017 :1009E0000000000000000000000000000000000007 :1009F00000000000000000000000000000000000F7 :100A000000000000000000000000000000000000E6 :100A100000000000000000000000000000000000D6 :100A200000000000000000000000000000000000C6 :100A300000000000000000000000000000000000B6 :100A400000000000000000000000000000000000A6 :100A50000000000000000000000000000000000096 :100A60000000000000000000000000000000000086 :100A70000000000000000000000000000000000076 :100A80000000000000000000000000000000000066 :100A90000000000000000000000000000000000056 :100AA0000000000000000000000000000000000046 :100AB0000000000000000000000000000000000036 :100AC0000000000000000000000000000000000026 :100AD0000000000000000000000000000000000016 :100AE0000000000000000000000000000000000006 :100AF00000000000000000000000000000000000F6 :100B000000000000000000000000000000000000E5 :100B100000000000000000000000000000000000D5 :100B200000000000000000000000000000000000C5 :100B300000000000000000000000000000000000B5 :100B400000000000000000000000000000000000A5 :100B50000000000000000000000000000000000095 :100B60000000000000000000000000000000000085 :100B70000000000000000000000000000000000075 :100B80000000000000000000000000000000000065 :100B90000000000000000000000000000000000055 :100BA0000000000000000000000000000000000045 :100BB0000000000000000000000000000000000035 :100BC0000000000000000000000000000000000025 :100BD0000000000000000000000000000000000015 :100BE0000000000000000000000000000000000005 :100BF00000000000000000000000000000000000F5 :100C000000000000000000000000000000000000E4 :100C100000000000000000000000000000000000D4 :100C200000000000000000000000000000000000C4 :100C300000000000000000000000000000000000B4 :100C400000000000000000000000000000000000A4 :100C50000000000000000000000000000000000094 :100C60000000000000000000000000000000000084 :100C70000000000000000000000000000000000074 :100C80000000000000000000000000000000000064 :100C90000000000000000000000000000000000054 :100CA0000000000000000000000000000000000044 :100CB0000000000000000000000000000000000034 :100CC0000000000000000000000000000000000024 :100CD0000000000000000000000000000000000014 :100CE0000000000000000000000000000000000004 :100CF00000000000000000000000000000000000F4 :100D000000000000000000000000000000000000E3 :100D100000000000000000000000000000000000D3 :100D200000000000000000000000000000000000C3 :100D300000000000000000000000000000000000B3 :100D400000000000000000000000000000000000A3 :100D50000000000000000000000000000000000093 :100D60000000000000000000000000000000000083 :100D70000000000000000000000000000000000073 :100D80000000000000000000000000000000000063 :100D90000000000000000000000000000000000053 :100DA0000000000000000000000000000000000043 :100DB0000000000000000000000000000000000033 :100DC0000000000000000000000000000000000023 :100DD0000000000000000000000000000000000013 :100DE0000000000000000000000000000000000003 :100DF00000000000000000000000000000000000F3 :100E000000000000000000000000000000000000E2 :100E100000000000000000000000000000000000D2 :100E200000000000000000000000000000000000C2 :100E300000000000000000000000000000000000B2 :100E400000000000000000000000000000000000A2 :100E50000000000000000000000000000000000092 :100E60000000000000000000000000000000000082 :100E70000000000000000000000000000000000072 :100E80000000000000000000000000000000000062 :100E90000000000000000000000000000000000052 :100EA0000000000000000000000000000000000042 :100EB0000000000000000000000000000000000032 :100EC0000000000000000000000000000000000022 :100ED0000000000000000000000000000000000012 :100EE0000000000000000000000000000000000002 :100EF00000000000000000000000000000000000F2 :100F000000000000000000000000000000000000E1 :100F100000000000000000000000000000000000D1 :100F200000000000000000000000000000000000C1 :100F300000000000000000000000000000000000B1 :100F400000000000000000000000000000000000A1 :100F50000000000000000000000000000000000091 :100F60000000000000000000000000000000000081 :100F70000000000000000000000000000000000071 :100F80000000000000000000000000000000000061 :100F90000000000000000000000000000000000051 :100FA0000000000000000000000000000000000041 :100FB0000000000000000000000000000000000031 :100FC0000000000000000000000000000000000021 :100FD0000000000000000000000000000000000011 :100FE0000000000000000000000000000000000001 :100FF00000000000000000000000000000000000F1 :1010000000000000000000000000000000000000E0 :1010100000000000000000000000000000000000D0 :1010200000000000000000000000000000000000C0 :1010300000000000000000000000000000000000B0 :1010400000000000000000000000000000000000A0 :101050000000000000000000000000000000000090 :101060000000000000000000000000000000000080 :101070000000000000000000000000000000000070 :101080000000000000000000000000000000000060 :101090000000000000000000000000000000000050 :1010A0000000000000000000000000000000000040 :1010B0000000000000000000000000000000000030 :1010C0000000000000000000000000000000000020 :1010D0000000000000000000000000000000000010 :1010E0000000000000000000000000000000000000 :1010F00000000000000000000000000000000000F0 :1011000000000000000000000000000000000000DF :1011100000000000000000000000000000000000CF :1011200000000000000000000000000000000000BF :1011300000000000000000000000000000000000AF :10114000000000000000000000000000000000009F :10115000000000000000000000000000000000008F :10116000000000000000000000000000000000007F :10117000000000000000000000000000000000006F :10118000000000000000000000000000000000005F :10119000000000000000000000000000000000004F :1011A000000000000000000000000000000000003F :1011B000000000000000000000000000000000002F :1011C000000000000000000000000000000000001F :1011D000000000000000000000000000000000000F :1011E00000000000000000000000000000000000FF :1011F00000000000000000000000000000000000EF :1012000000000000000000000000000000000000DE :1012100000000000000000000000000000000000CE :1012200000000000000000000000000000000000BE :1012300000000000000000000000000000000000AE :10124000000000000000000000000000000000009E :10125000000000000000000000000000000000008E :10126000000000000000000000000000000000007E :10127000000000000000000000000000000000006E :10128000000000000000000000000000000000005E :10129000000000000000000000000000000000004E :1012A000000000000000000000000000000000003E :1012B000000000000000000000000000000000002E :1012C000000000000000000000000000000000001E :1012D000000000000000000000000000000000000E :1012E00000000000000000000000000000000000FE :1012F00000000000000000000000000000000000EE :1013000000000000000000000000000000000000DD :1013100000000000000000000000000000000000CD :1013200000000000000000000000000000000000BD :1013300000000000000000000000000000000000AD :10134000000000000000000000000000000000009D :10135000000000000000000000000000000000008D :10136000000000000000000000000000000000007D :10137000000000000000000000000000000000006D :10138000000000000000000000000000000000005D :10139000000000000000000000000000000000004D :1013A000000000000000000000000000000000003D :1013B000000000000000000000000000000000002D :1013C000000000000000000000000000000000001D :1013D000000000000000000000000000000000000D :1013E00000000000000000000000000000000000FD :1013F00000000000000000000000000000000000ED :1014000000000000000000000000000000000000DC :1014100000000000000000000000000000000000CC :1014200000000000000000000000000000000000BC :1014300000000000000000000000000000000000AC :10144000000000000000000000000000000000009C :10145000000000000000000000000000000000008C :10146000000000000000000000000000000000007C :10147000000000000000000000000000000000006C :10148000000000000000000000000000000000005C :10149000000000000000000000000000000000004C :1014A000000000000000000000000000000000003C :1014B000000000000000000000000000000000002C :1014C000000000000000000000000000000000001C :1014D000000000000000000000000000000000000C :1014E00000000000000000000000000000000000FC :1014F00000000000000000000000000000000000EC :1015000000000000000000000000000000000000DB :1015100000000000000000000000000000000000CB :1015200000000000000000000000000000000000BB :1015300000000000000000000000000000000000AB :10154000000000000000000000000000000000009B :10155000000000000000000000000000000000008B :10156000000000000000000000000000000000007B :10157000000000000000000000000000000000006B :10158000000000000000000000000000000000005B :10159000000000000000000000000000000000004B :1015A000000000000000000000000000000000003B :1015B000000000000000000000000000000000002B :1015C000000000000000000000000000000000001B :1015D000000000000000000000000000000000000B :1015E00000000000000000000000000000000000FB :1015F00000000000000000000000000000000000EB :1016000000000000000000000000000000000000DA :1016100000000000000000000000000000000000CA :1016200000000000000000000000000000000000BA :1016300000000000000000000000000000000000AA :10164000000000000000000000000000000000009A :10165000000000000000000000000000000000008A :10166000000000000000000000000000000000007A :10167000000000000000000000000000000000006A :10168000000000000000000000000000000000005A :10169000000000000000000000000000000000004A :1016A000000000000000000000000000000000003A :1016B000000000000000000000000000000000002A :1016C000000000000000000000000000000000001A :1016D000000000000000000000000000000000000A :1016E00000000000000000000000000000000000FA :1016F00000000000000000000000000000000000EA :1017000000000000000000000000000000000000D9 :1017100000000000000000000000000000000000C9 :1017200000000000000000000000000000000000B9 :1017300000000000000000000000000000000000A9 :101740000000000000000000000000000000000099 :101750000000000000000000000000000000000089 :101760000000000000000000000000000000000079 :101770000000000000000000000000000000000069 :101780000000000000000000000000000000000059 :101790000000000000000000000000000000000049 :1017A0000000000000000000000000000000000039 :1017B0000000000000000000000000000000000029 :1017C0000000000000000000000000000000000019 :1017D0000000000000000000000000000000000009 :1017E00000000000000000000000000000000000F9 :1017F00000000000000000000000000000000000E9 :1018000000000000000000000000000000000000D8 :1018100000000000000000000000000000000000C8 :1018200000000000000000000000000000000000B8 :1018300000000000000000000000000000000000A8 :101840000000000000000000000000000000000098 :101850000000000000000000000000000000000088 :101860000000000000000000000000000000000078 :101870000000000000000000000000000000000068 :101880000000000000000000000000000000000058 :101890000000000000000000000000000000000048 :1018A0000000000000000000000000000000000038 :1018B0000000000000000000000000000000000028 :1018C0000000000000000000000000000000000018 :1018D0000000000000000000000000000000000008 :1018E00000000000000000000000000000000000F8 :1018F00000000000000000000000000000000000E8 :1019000000000000000000000000000000000000D7 :1019100000000000000000000000000000000000C7 :1019200000000000000000000000000000000000B7 :1019300000000000000000000000000000000000A7 :101940000000000000000000000000000000000097 :101950000000000000000000000000000000000087 :101960000000000000000000000000000000000077 :101970000000000000000000000000000000000067 :101980000000000000000000000000000000000057 :101990000000000000000000000000000000000047 :1019A0000000000000000000000000000000000037 :1019B0000000000000000000000000000000000027 :1019C0000000000000000000000000000000000017 :1019D0000000000000000000000000000000000007 :1019E00000000000000000000000000000000000F7 :1019F00000000000000000000000000000000000E7 :101A000000000000000000000000000000000000D6 :101A100000000000000000000000000000000000C6 :101A200000000000000000000000000000000000B6 :101A300000000000000000000000000000000000A6 :101A40000000000000000000000000000000000096 :101A50000000000000000000000000000000000086 :101A60000000000000000000000000000000000076 :101A70000000000000000000000000000000000066 :101A80000000000000000000000000000000000056 :101A90000000000000000000000000000000000046 :101AA0000000000000000000000000000000000036 :101AB0000000000000000000000000000000000026 :101AC0000000000000000000000000000000000016 :101AD0000000000000000000000000000000000006 :101AE00000000000000000000000000000000000F6 :101AF00000000000000000000000000000000000E6 :101B000000000000000000000000000000000000D5 :101B100000000000000000000000000000000000C5 :101B200000000000000000000000000000000000B5 :101B300000000000000000000000000000000000A5 :101B40000000000000000000000000000000000095 :101B50000000000000000000000000000000000085 :101B60000000000000000000000000000000000075 :101B70000000000000000000000000000000000065 :101B80000000000000000000000000000000000055 :101B90000000000000000000000000000000000045 :101BA0000000000000000000000000000000000035 :101BB0000000000000000000000000000000000025 :101BC0000000000000000000000000000000000015 :101BD0000000000000000000000000000000000005 :101BE00000000000000000000000000000000000F5 :101BF00000000000000000000000000000000000E5 :101C000000000000000000000000000000000000D4 :101C100000000000000000000000000000000000C4 :101C200000000000000000000000000000000000B4 :101C300000000000000000000000000000000000A4 :101C40000000000000000000000000000000000094 :101C50000000000000000000000000000000000084 :101C60000000000000000000000000000000000074 :101C70000000000000000000000000000000000064 :101C80000000000000000000000000000000000054 :101C90000000000000000000000000000000000044 :101CA0000000000000000000000000000000000034 :101CB0000000000000000000000000000000000024 :101CC0000000000000000000000000000000000014 :101CD0000000000000000000000000000000000004 :101CE00000000000000000000000000000000000F4 :101CF00000000000000000000000000000000000E4 :101D000000000000000000000000000000000000D3 :101D100000000000000000000000000000000000C3 :101D200000000000000000000000000000000000B3 :101D300000000000000000000000000000000000A3 :101D40000000000000000000000000000000000093 :101D50000000000000000000000000000000000083 :101D60000000000000000000000000000000000073 :101D70000000000000000000000000000000000063 :101D80000000000000000000000000000000000053 :101D90000000000000000000000000000000000043 :101DA0000000000000000000000000000000000033 :101DB0000000000000000000000000000000000023 :101DC0000000000000000000000000000000000013 :101DD0000000000000000000000000000000000003 :101DE00000000000000000000000000000000000F3 :101DF00000000000000000000000000000000000E3 :101E000000000000000000000000000000000000D2 :101E100000000000000000000000000000000000C2 :101E200000000000000000000000000000000000B2 :101E300000000000000000000000000000000000A2 :101E40000000000000000000000000000000000092 :101E50000000000000000000000000000000000082 :101E60000000000000000000000000000000000072 :101E70000000000000000000000000000000000062 :101E80000000000000000000000000000000000052 :101E90000000000000000000000000000000000042 :101EA0000000000000000000000000000000000032 :101EB0000000000000000000000000000000000022 :101EC0000000000000000000000000000000000012 :101ED0000000000000000000000000000000000002 :101EE00000000000000000000000000000000000F2 :101EF00000000000000000000000000000000000E2 :101F000000000000000000000000000000000000D1 :101F100000000000000000000000000000000000C1 :101F200000000000000000000000000000000000B1 :101F300000000000000000000000000000000000A1 :101F40000000000000000000000000000000000091 :101F50000000000000000000000000000000000081 :101F60000000000000000000000000000000000071 :101F70000000000000000000000000000000000061 :101F80000000000000000000000000000000000051 :101F90000000000000000000000000000000000041 :101FA0000000000000000000000000000000000031 :101FB0000000000000000000000000000000000021 :101FC0000000000000000000000000000000000011 :101FD0000000000000000000000000000000000001 :101FE00000000000000000000000000000000000F1 :101FF00000000000000000000000000000000000E1 :1020000000000000000000000000000000000000D0 :1020100000000000000000000000000000000000C0 :1020200000000000000000000000000000000000B0 :1020300000000000000000000000000000000000A0 :102040000000000000000000000000000000000090 :102050000000000000000000000000000000000080 :102060000000000000000000000000000000000070 :102070000000000000000000000000000000000060 :102080000000000000000000000000000000000050 :102090000000000000000000000000000000000040 :1020A0000000000000000000000000000000000030 :1020B0000000000000000000000000000000000020 :1020C0000000000000000000000000000000000010 :1020D0000000000000000000000000000000000000 :1020E00000000000000000000000000000000000F0 :1020F00000000000000000000000000000000000E0 :1021000000000000000000000000000000000000CF :1021100000000000000000000000000000000000BF :1021200000000000000000000000000000000000AF :10213000000000000000000000000000000000009F :10214000000000000000000000000000000000008F :10215000000000000000000000000000000000007F :10216000000000000000000000000000000000006F :10217000000000000000000000000000000000005F :10218000000000000000000000000000000000004F :10219000000000000000000000000000000000003F :1021A000000000000000000000000000000000002F :1021B000000000000000000000000000000000001F :1021C000000000000000000000000000000000000F :1021D00000000000000000000000000000000000FF :1021E00000000000000000000000000000000000EF :1021F00000000000000000000000000000000000DF :1022000000000000000000000000000000000000CE :1022100000000000000000000000000000000000BE :1022200000000000000000000000000000000000AE :10223000000000000000000000000000000000009E :10224000000000000000000000000000000000008E :10225000000000000000000000000000000000007E :10226000000000000000000000000000000000006E :10227000000000000000000000000000000000005E :10228000000000000000000000000000000000004E :10229000000000000000000000000000000000003E :1022A000000000000000000000000000000000002E :1022B000000000000000000000000000000000001E :1022C000000000000000000000000000000000000E :1022D00000000000000000000000000000000000FE :1022E00000000000000000000000000000000000EE :1022F00000000000000000000000000000000000DE :1023000000000000000000000000000000000000CD :1023100000000000000000000000000000000000BD :1023200000000000000000000000000000000000AD :10233000000000000000000000000000000000009D :10234000000000000000000000000000000000008D :10235000000000000000000000000000000000007D :10236000000000000000000000000000000000006D :10237000000000000000000000000000000000005D :10238000000000000000000000000000000000004D :10239000000000000000000000000000000000003D :1023A000000000000000000000000000000000002D :1023B000000000000000000000000000000000001D :1023C000000000000000000000000000000000000D :1023D00000000000000000000000000000000000FD :1023E00000000000000000000000000000000000ED :1023F00000000000000000000000000000000000DD :1024000000000000000000000000000000000000CC :1024100000000000000000000000000000000000BC :1024200000000000000000000000000000000000AC :10243000000000000000000000000000000000009C :10244000000000000000000000000000000000008C :10245000000000000000000000000000000000007C :10246000000000000000000000000000000000006C :10247000000000000000000000000000000000005C :10248000000000000000000000000000000000004C :10249000000000000000000000000000000000003C :1024A000000000000000000000000000000000002C :1024B000000000000000000000000000000000001C :1024C000000000000000000000000000000000000C :1024D00000000000000000000000000000000000FC :1024E00000000000000000000000000000000000EC :1024F00000000000000000000000000000000000DC :1025000000000000000000000000000000000000CB :1025100000000000000000000000000000000000BB :1025200000000000000000000000000000000000AB :10253000000000000000000000000000000000009B :10254000000000000000000000000000000000008B :10255000000000000000000000000000000000007B :10256000000000000000000000000000000000006B :10257000000000000000000000000000000000005B :10258000000000000000000000000000000000004B :10259000000000000000000000000000000000003B :1025A000000000000000000000000000000000002B :1025B000000000000000000000000000000000001B :1025C000000000000000000000000000000000000B :1025D00000000000000000000000000000000000FB :1025E00000000000000000000000000000000000EB :1025F00000000000000000000000000000000000DB :1026000000000000000000000000000000000000CA :1026100000000000000000000000000000000000BA :1026200000000000000000000000000000000000AA :10263000000000000000000000000000000000009A :10264000000000000000000000000000000000008A :10265000000000000000000000000000000000007A :10266000000000000000000000000000000000006A :10267000000000000000000000000000000000005A :10268000000000000000000000000000000000004A :10269000000000000000000000000000000000003A :1026A000000000000000000000000000000000002A :1026B000000000000000000000000000000000001A :1026C000000000000000000000000000000000000A :1026D00000000000000000000000000000000000FA :1026E00000000000000000000000000000000000EA :1026F00000000000000000000000000000000000DA :1027000000000000000000000000000000000000C9 :1027100000000000000000000000000000000000B9 :1027200000000000000000000000000000000000A9 :102730000000000000000000000000000000000099 :102740000000000000000000000000000000000089 :102750000000000000000000000000000000000079 :102760000000000000000000000000000000000069 :102770000000000000000000000000000000000059 :102780000000000000000000000000000000000049 :102790000000000000000000000000000000000039 :1027A0000000000000000000000000000000000029 :1027B0000000000000000000000000000000000019 :1027C0000000000000000000000000000000000009 :1027D00000000000000000000000000000000000F9 :1027E00000000000000000000000000000000000E9 :1027F00000000000000000000000000000000000D9 :1028000000000000000000000000000000000000C8 :1028100000000000000000000000000000000000B8 :1028200000000000000000000000000000000000A8 :102830000000000000000000000000000000000098 :102840000000000000000000000000000000000088 :102850000000000000000000000000000000000078 :102860000000000000000000000000000000000068 :102870000000000000000000000000000000000058 :102880000000000000000000000000000000000048 :102890000000000000000000000000000000000038 :1028A0000000000000000000000000000000000028 :1028B0000000000000000000000000000000000018 :1028C0000000000000000000000000000000000008 :1028D00000000000000000000000000000000000F8 :1028E00000000000000000000000000000000000E8 :1028F00000000000000000000000000000000000D8 :1029000000000000000000000000000000000000C7 :1029100000000000000000000000000000000000B7 :1029200000000000000000000000000000000000A7 :102930000000000000000000000000000000000097 :102940000000000000000000000000000000000087 :102950000000000000000000000000000000000077 :102960000000000000000000000000000000000067 :102970000000000000000000000000000000000057 :102980000000000000000000000000000000000047 :102990000000000000000000000000000000000037 :1029A0000000000000000000000000000000000027 :1029B0000000000000000000000000000000000017 :1029C0000000000000000000000000000000000007 :1029D00000000000000000000000000000000000F7 :1029E00000000000000000000000000000000000E7 :1029F00000000000000000000000000000000000D7 :102A000000000000000000000000000000000000C6 :102A100000000000000000000000000000000000B6 :102A200000000000000000000000000000000000A6 :102A30000000000000000000000000000000000096 :102A40000000000000000000000000000000000086 :102A50000000000000000000000000000000000076 :102A60000000000000000000000000000000000066 :102A70000000000000000000000000000000000056 :102A80000000000000000000000000000000000046 :102A90000000000000000000000000000000000036 :102AA0000000000000000000000000000000000026 :102AB0000000000000000000000000000000000016 :102AC0000000000000000000000000000000000006 :102AD00000000000000000000000000000000000F6 :102AE00000000000000000000000000000000000E6 :102AF00000000000000000000000000000000000D6 :102B000000000000000000000000000000000000C5 :102B100000000000000000000000000000000000B5 :102B200000000000000000000000000000000000A5 :102B30000000000000000000000000000000000095 :102B40000000000000000000000000000000000085 :102B50000000000000000000000000000000000075 :102B60000000000000000000000000000000000065 :102B70000000000000000000000000000000000055 :102B80000000000000000000000000000000000045 :102B90000000000000000000000000000000000035 :102BA0000000000000000000000000000000000025 :102BB0000000000000000000000000000000000015 :102BC0000000000000000000000000000000000005 :102BD00000000000000000000000000000000000F5 :102BE00000000000000000000000000000000000E5 :102BF00000000000000000000000000000000000D5 :102C000000000000000000000000000000000000C4 :102C100000000000000000000000000000000000B4 :102C200000000000000000000000000000000000A4 :102C30000000000000000000000000000000000094 :102C40000000000000000000000000000000000084 :102C50000000000000000000000000000000000074 :102C60000000000000000000000000000000000064 :102C70000000000000000000000000000000000054 :102C80000000000000000000000000000000000044 :102C90000000000000000000000000000000000034 :102CA0000000000000000000000000000000000024 :102CB0000000000000000000000000000000000014 :102CC0000000000000000000000000000000000004 :102CD00000000000000000000000000000000000F4 :102CE00000000000000000000000000000000000E4 :102CF00000000000000000000000000000000000D4 :102D000000000000000000000000000000000000C3 :102D100000000000000000000000000000000000B3 :102D200000000000000000000000000000000000A3 :102D30000000000000000000000000000000000093 :102D40000000000000000000000000000000000083 :102D50000000000000000000000000000000000073 :102D60000000000000000000000000000000000063 :102D70000000000000000000000000000000000053 :102D80000000000000000000000000000000000043 :102D90000000000000000000000000000000000033 :102DA0000000000000000000000000000000000023 :102DB0000000000000000000000000000000000013 :102DC0000000000000000000000000000000000003 :102DD00000000000000000000000000000000000F3 :102DE00000000000000000000000000000000000E3 :102DF00000000000000000000000000000000000D3 :102E000000000000000000000000000000000000C2 :102E100000000000000000000000000000000000B2 :102E200000000000000000000000000000000000A2 :102E30000000000000000000000000000000000092 :102E40000000000000000000000000000000000082 :102E50000000000000000000000000000000000072 :102E60000000000000000000000000000000000062 :102E70000000000000000000000000000000000052 :102E80000000000000000000000000000000000042 :102E90000000000000000000000000000000000032 :102EA0000000000000000000000000000000000022 :102EB0000000000000000000000000000000000012 :102EC0000000000000000000000000000000000002 :102ED00000000000000000000000000000000000F2 :102EE00000000000000000000000000000000000E2 :102EF00000000000000000000000000000000000D2 :102F000000000000000000000000000000000000C1 :102F100000000000000000000000000000000000B1 :102F200000000000000000000000000000000000A1 :102F30000000000000000000000000000000000091 :102F40000000000000000000000000000000000081 :102F50000000000000000000000000000000000071 :102F60000000000000000000000000000000000061 :102F70000000000000000000000000000000000051 :102F80000000000000000000000000000000000041 :102F90000000000000000000000000000000000031 :102FA0000000000000000000000000000000000021 :102FB0000000000000000000000000000000000011 :102FC0000000000000000000000000000000000001 :102FD00000000000000000000000000000000000F1 :102FE00000000000000000000000000000000000E1 :102FF00000000000000000000000000000000000D1 :1030000000000000000000000000000000000000C0 :1030100000000000000000000000000000000000B0 :1030200000000000000000000000000000000000A0 :103030000000000000000000000000000000000090 :103040000000000000000000000000000000000080 :103050000000000000000000000000000000000070 :103060000000000000000000000000000000000060 :103070000000000000000000000000000000000050 :103080000000000000000000000000000000000040 :103090000000000000000000000000000000000030 :1030A0000000000000000000000000000000000020 :1030B0000000000000000000000000000000000010 :1030C0000000000000000000000000000000000000 :1030D00000000000000000000000000000000000F0 :1030E00000000000000000000000000000000000E0 :1030F00000000000000000000000000000000000D0 :1031000000000000000000000000000000000000BF :1031100000000000000000000000000000000000AF :10312000000000000000000000000000000000009F :10313000000000000000000000000000000000008F :10314000000000000000000000000000000000007F :10315000000000000000000000000000000000006F :10316000000000000000000000000000000000005F :10317000000000000000000000000000000000004F :10318000000000000000000000000000000000003F :10319000000000000000000000000000000000002F :1031A000000000000000000000000000000000001F :1031B000000000000000000000000000000000000F :1031C00000000000000000000000000000000000FF :1031D00000000000000000000000000000000000EF :1031E00000000000000000000000000000000000DF :1031F00000000000000000000000000000000000CF :1032000000000000000000000000000000000000BE :1032100000000000000000000000000000000000AE :10322000000000000000000000000000000000009E :10323000000000000000000000000000000000008E :10324000000000000000000000000000000000007E :10325000000000000000000000000000000000006E :10326000000000000000000000000000000000005E :10327000000000000000000000000000000000004E :10328000000000000000000000000000000000003E :10329000000000000000000000000000000000002E :1032A000000000000000000000000000000000001E :1032B000000000000000000000000000000000000E :1032C00000000000000000000000000000000000FE :1032D00000000000000000000000000000000000EE :1032E00000000000000000000000000000000000DE :1032F00000000000000000000000000000000000CE :1033000000000000000000000000000000000000BD :1033100000000000000000000000000000000000AD :10332000000000000000000000000000000000009D :10333000000000000000000000000000000000008D :10334000000000000000000000000000000000007D :10335000000000000000000000000000000000006D :10336000000000000000000000000000000000005D :10337000000000000000000000000000000000004D :10338000000000000000000000000000000000003D :10339000000000000000000000000000000000002D :1033A000000000000000000000000000000000001D :1033B000000000000000000000000000000000000D :1033C00000000000000000000000000000000000FD :1033D00000000000000000000000000000000000ED :1033E00000000000000000000000000000000000DD :1033F00000000000000000000000000000000000CD :1034000000000000000000000000000000000000BC :1034100000000000000000000000000000000000AC :10342000000000000000000000000000000000009C :10343000000000000000000000000000000000008C :10344000000000000000000000000000000000007C :10345000000000000000000000000000000000006C :10346000000000000000000000000000000000005C :10347000000000000000000000000000000000004C :10348000000000000000000000000000000000003C :10349000000000000000000000000000000000002C :1034A000000000000000000000000000000000001C :1034B000000000000000000000000000000000000C :1034C00000000000000000000000000000000000FC :1034D00000000000000000000000000000000000EC :1034E00000000000000000000000000000000000DC :1034F00000000000000000000000000000000000CC :1035000000000000000000000000000000000000BB :1035100000000000000000000000000000000000AB :10352000000000000000000000000000000000009B :10353000000000000000000000000000000000008B :10354000000000000000000000000000000000007B :10355000000000000000000000000000000000006B :10356000000000000000000000000000000000005B :10357000000000000000000000000000000000004B :10358000000000000000000000000000000000003B :10359000000000000000000000000000000000002B :1035A000000000000000000000000000000000001B :1035B000000000000000000000000000000000000B :1035C00000000000000000000000000000000000FB :1035D00000000000000000000000000000000000EB :1035E00000000000000000000000000000000000DB :1035F00000000000000000000000000000000000CB :1036000000000000000000000000000000000000BA :1036100000000000000000000000000000000000AA :10362000000000000000000000000000000000009A :10363000000000000000000000000000000000008A :10364000000000000000000000000000000000007A :10365000000000000000000000000000000000006A :10366000000000000000000000000000000000005A :10367000000000000000000000000000000000004A :10368000000000000000000000000000000000003A :10369000000000000000000000000000000000002A :1036A000000000000000000000000000000000001A :1036B000000000000000000000000000000000000A :1036C00000000000000000000000000000000000FA :1036D00000000000000000000000000000000000EA :1036E00000000000000000000000000000000000DA :1036F00000000000000000000000000000000000CA :1037000000000000000000000000000000000000B9 :1037100000000000000000000000000000000000A9 :103720000000000000000000000000000000000099 :103730000000000000000000000000000000000089 :103740000000000000000000000000000000000079 :103750000000000000000000000000000000000069 :103760000000000000000000000000000000000059 :103770000000000000000000000000000000000049 :103780000000000000000000000000000000000039 :103790000000000000000000000000000000000029 :1037A0000000000000000000000000000000000019 :1037B0000000000000000000000000000000000009 :1037C00000000000000000000000000000000000F9 :1037D00000000000000000000000000000000000E9 :1037E00000000000000000000000000000000000D9 :1037F00000000000000000000000000000000000C9 :1038000000000000000000000000000000000000B8 :1038100000000000000000000000000000000000A8 :103820000000000000000000000000000000000098 :103830000000000000000000000000000000000088 :103840000000000000000000000000000000000078 :103850000000000000000000000000000000000068 :103860000000000000000000000000000000000058 :103870000000000000000000000000000000000048 :103880000000000000000000000000000000000038 :103890000000000000000000000000000000000028 :1038A0000000000000000000000000000000000018 :1038B0000000000000000000000000000000000008 :1038C00000000000000000000000000000000000F8 :1038D00000000000000000000000000000000000E8 :1038E00000000000000000000000000000000000D8 :1038F00000000000000000000000000000000000C8 :1039000000000000000000000000000000000000B7 :1039100000000000000000000000000000000000A7 :103920000000000000000000000000000000000097 :103930000000000000000000000000000000000087 :103940000000000000000000000000000000000077 :103950000000000000000000000000000000000067 :103960000000000000000000000000000000000057 :103970000000000000000000000000000000000047 :103980000000000000000000000000000000000037 :103990000000000000000000000000000000000027 :1039A0000000000000000000000000000000000017 :1039B0000000000000000000000000000000000007 :1039C00000000000000000000000000000000000F7 :1039D00000000000000000000000000000000000E7 :1039E00000000000000000000000000000000000D7 :1039F00000000000000000000000000000000000C7 :103A000000000000000000000000000000000000B6 :103A100000000000000000000000000000000000A6 :103A20000000000000000000000000000000000096 :103A30000000000000000000000000000000000086 :103A40000000000000000000000000000000000076 :103A50000000000000000000000000000000000066 :103A60000000000000000000000000000000000056 :103A70000000000000000000000000000000000046 :103A80000000000000000000000000000000000036 :103A90000000000000000000000000000000000026 :103AA0000000000000000000000000000000000016 :103AB0000000000000000000000000000000000006 :103AC00000000000000000000000000000000000F6 :103AD00000000000000000000000000000000000E6 :103AE00000000000000000000000000000000000D6 :103AF00000000000000000000000000000000000C6 :103B000000000000000000000000000000000000B5 :103B100000000000000000000000000000000000A5 :103B20000000000000000000000000000000000095 :103B30000000000000000000000000000000000085 :103B40000000000000000000000000000000000075 :103B50000000000000000000000000000000000065 :103B60000000000000000000000000000000000055 :103B70000000000000000000000000000000000045 :103B80000000000000000000000000000000000035 :103B90000000000000000000000000000000000025 :103BA0000000000000000000000000000000000015 :103BB0000000000000000000000000000000000005 :103BC00000000000000000000000000000000000F5 :103BD00000000000000000000000000000000000E5 :103BE00000000000000000000000000000000000D5 :103BF00000000000000000000000000000000000C5 :103C000000000000000000000000000000000000B4 :103C100000000000000000000000000000000000A4 :103C20000000000000000000000000000000000094 :103C30000000000000000000000000000000000084 :103C40000000000000000000000000000000000074 :103C50000000000000000000000000000000000064 :103C60000000000000000000000000000000000054 :103C70000000000000000000000000000000000044 :103C80000000000000000000000000000000000034 :103C90000000000000000000000000000000000024 :103CA0000000000000000000000000000000000014 :103CB0000000000000000000000000000000000004 :103CC00000000000000000000000000000000000F4 :103CD00000000000000000000000000000000000E4 :103CE00000000000000000000000000000000000D4 :103CF00000000000000000000000000000000000C4 :103D000000000000000000000000000000000000B3 :103D100000000000000000000000000000000000A3 :103D20000000000000000000000000000000000093 :103D30000000000000000000000000000000000083 :103D40000000000000000000000000000000000073 :103D50000000000000000000000000000000000063 :103D60000000000000000000000000000000000053 :103D70000000000000000000000000000000000043 :103D80000000000000000000000000000000000033 :103D90000000000000000000000000000000000023 :103DA0000000000000000000000000000000000013 :103DB0000000000000000000000000000000000003 :103DC00000000000000000000000000000000000F3 :103DD00000000000000000000000000000000000E3 :103DE00000000000000000000000000000000000D3 :103DF00000000000000000000000000000000000C3 :103E000000000000000000000000000000000000B2 :103E100000000000000000000000000000000000A2 :103E20000000000000000000000000000000000092 :103E30000000000000000000000000000000000082 :103E40000000000000000000000000000000000072 :103E50000000000000000000000000000000000062 :103E60000000000000000000000000000000000052 :103E70000000000000000000000000000000000042 :103E80000000000000000000000000000000000032 :103E90000000000000000000000000000000000022 :103EA0000000000000000000000000000000000012 :103EB0000000000000000000000000000000000002 :103EC00000000000000000000000000000000000F2 :103ED00000000000000000000000000000000000E2 :103EE00000000000000000000000000000000000D2 :103EF00000000000000000000000000000000000C2 :103F000000000000000000000000000000000000B1 :103F100000000000000000000000000000000000A1 :103F20000000000000000000000000000000000091 :103F30000000000000000000000000000000000081 :103F40000000000000000000000000000000000071 :103F50000000000000000000000000000000000061 :103F60000000000000000000000000000000000051 :103F70000000000000000000000000000000000041 :103F80000000000000000000000000000000000031 :103F90000000000000000000000000000000000021 :103FA0000000000000000000000000000000000011 :103FB0000000000000000000000000000000000001 :103FC00000000000000000000000000000000000F1 :103FD00000000000000000000000000000000000E1 :103FE00000000000000000000000000000000000D1 :103FF00000000000000000000000000000000000C1 :1040000000000000000000000000000000000000B0 :1040100000000000000000000000000000000000A0 :104020000000000000000000000000000000000090 :104030000000000000000000000000000000000080 :104040000000000000000000000000000000000070 :104050000000000000000000000000000000000060 :104060000000000000000000000000000000000050 :104070000000000000000000000000000000000040 :104080000000000000000000000000000000000030 :104090000000000000000000000000000000000020 :1040A0000000000000000000000000000000000010 :1040B0000000000000000000000000000000000000 :1040C00000000000000000000000000000000000F0 :1040D00000000000000000000000000000000000E0 :1040E00000000000000000000000000000000000D0 :1040F00000000000000000000000000000000000C0 :1041000000000000000000000000000000000000AF :10411000000000000000000000000000000000009F :10412000000000000000000000000000000000008F :10413000000000000000000000000000000000007F :10414000000000000000000000000000000000006F :10415000000000000000000000000000000000005F :10416000000000000000000000000000000000004F :10417000000000000000000000000000000000003F :10418000000000000000000000000000000000002F :10419000000000000000000000000000000000001F :1041A000000000000000000000000000000000000F :1041B00000000000000000000000000000000000FF :1041C00000000000000000000000000000000000EF :1041D00000000000000000000000000000000000DF :1041E00000000000000000000000000000000000CF :1041F00000000000000000000000000000000000BF :1042000000000000000000000000000000000000AE :10421000000000000000000000000000000000009E :10422000000000000000000000000000000000008E :10423000000000000000000000000000000000007E :10424000000000000000000000000000000000006E :10425000000000000000000000000000000000005E :10426000000000000000000000000000000000004E :10427000000000000000000000000000000000003E :10428000000000000000000000000000000000002E :10429000000000000000000000000000000000001E :1042A000000000000000000000000000000000000E :1042B00000000000000000000000000000000000FE :1042C00000000000000000000000000000000000EE :1042D00000000000000000000000000000000000DE :1042E00000000000000000000000000000000000CE :1042F00000000000000000000000000000000000BE :1043000000000000000000000000000000000000AD :10431000000000000000000000000000000000009D :10432000000000000000000000000000000000008D :10433000000000000000000000000000000000007D :10434000000000000000000000000000000000006D :10435000000000000000000000000000000000005D :10436000000000000000000000000000000000004D :10437000000000000000000000000000000000003D :10438000000000000000000000000000000000002D :10439000000000000000000000000000000000001D :1043A000000000000000000000000000000000000D :1043B00000000000000000000000000000000000FD :1043C00000000000000000000000000000000000ED :1043D00000000000000000000000000000000000DD :1043E00000000000000000000000000000000000CD :1043F00000000000000000000000000000000000BD :1044000000000000000000000000000000000000AC :10441000000000000000000000000000000000009C :10442000000000000000000000000000000000008C :10443000000000000000000000000000000000007C :10444000000000000000000000000000000000006C :10445000000000000000000000000000000000005C :10446000000000000000000000000000000000004C :10447000000000000000000000000000000000003C :10448000000000000000000000000000000000002C :10449000000000000000000000000000000000001C :1044A000000000000000000000000000000000000C :1044B00000000000000000000000000000000000FC :1044C00000000000000000000000000000000000EC :1044D00000000000000000000000000000000000DC :1044E00000000000000000000000000000000000CC :1044F00000000000000000000000000000000000BC :1045000000000000000000000000000000000000AB :10451000000000000000000000000000000000009B :10452000000000000000000000000000000000008B :10453000000000000000000000000000000000007B :10454000000000000000000000000000000000006B :10455000000000000000000000000000000000005B :10456000000000000000000000000000000000004B :10457000000000000000000000000000000000003B :10458000000000000000000000000000000000002B :10459000000000000000000000000000000000001B :1045A000000000000000000000000000000000000B :1045B00000000000000000000000000000000000FB :1045C00000000000000000000000000000000000EB :1045D00000000000000000000000000000000000DB :1045E00000000000000000000000000000000000CB :1045F00000000000000000000000000000000000BB :1046000000000000000000000000000000000000AA :10461000000000000000000000000000000000009A :10462000000000000000000000000000000000008A :10463000000000000000000000000000000000007A :10464000000000000000000000000000000000006A :10465000000000000000000000000000000000005A :10466000000000000000000000000000000000004A :10467000000000000000000000000000000000003A :10468000000000000000000000000000000000002A :10469000000000000000000000000000000000001A :1046A000000000000000000000000000000000000A :1046B00000000000000000000000000000000000FA :1046C00000000000000000000000000000000000EA :1046D00000000000000000000000000000000000DA :1046E00000000000000000000000000000000000CA :1046F00000000000000000000000000000000000BA :1047000000000000000000000000000000000000A9 :104710000000000000000000000000000000000099 :104720000000000000000000000000000000000089 :104730000000000000000000000000000000000079 :104740000000000000000000000000000000000069 :104750000000000000000000000000000000000059 :104760000000000000000000000000000000000049 :104770000000000000000000000000000000000039 :104780000000000000000000000000000000000029 :104790000000000000000000000000000000000019 :1047A0000000000000000000000000000000000009 :1047B00000000000000000000000000000000000F9 :1047C00000000000000000000000000000000000E9 :1047D00000000000000000000000000000000000D9 :1047E00000000000000000000000000000000000C9 :1047F00000000000000000000000000000000000B9 :1048000000000000000000000000000000000000A8 :104810000000000000000000000000000000000098 :104820000000000000000000000000000000000088 :104830000000000000000000000000000000000078 :104840000000000000000000000000000000000068 :104850000000000000000000000000000000000058 :104860000000000000000000000000000000000048 :104870000000000000000000000000000000000038 :104880000000000000000000000000000000000028 :104890000000000000000000000000000000000018 :1048A0000000000000000000000000000000000008 :1048B00000000000000000000000000000000000F8 :1048C00000000000000000000000000000000000E8 :1048D00000000000000000000000000000000000D8 :1048E00000000000000000000000000000000000C8 :1048F00000000000000000000000000000000000B8 :1049000000000000000000000000000000000000A7 :104910000000000000000000000000000000000097 :104920000000000000000000000000000000000087 :104930000000000000000000000000000000000077 :104940000000000000000000000000000000000067 :104950000000000000000000000000000000000057 :104960000000000000000000000000000000000047 :104970000000000000000000000000000000000037 :104980000000000000000000000000000000000027 :104990000000000000000000000000000000000017 :1049A0000000000000000000000000000000000007 :1049B00000000000000000000000000000000000F7 :1049C00000000000000000000000000000000000E7 :1049D00000000000000000000000000000000000D7 :1049E00000000000000000000000000000000000C7 :1049F00000000000000000000000000000000000B7 :104A000000000000000000000000000000000000A6 :104A10000000000000000000000000000000000096 :104A20000000000000000000000000000000000086 :104A30000000000000000000000000000000000076 :104A40000000000000000000000000000000000066 :104A50000000000000000000000000000000000056 :104A60000000000000000000000000000000000046 :104A70000000000000000000000000000000000036 :104A80000000000000000000000000000000000026 :104A90000000000000000000000000000000000016 :104AA0000000000000000000000000000000000006 :104AB00000000000000000000000000000000000F6 :104AC00000000000000000000000000000000000E6 :104AD00000000000000000000000000000000000D6 :104AE00000000000000000000000000000000000C6 :104AF00000000000000000000000000000000000B6 :104B000000000000000000000000000000000000A5 :104B10000000000000000000000000000000000095 :104B20000000000000000000000000000000000085 :104B30000000000000000000000000000000000075 :104B40000000000000000000000000000000000065 :104B50000000000000000000000000000000000055 :104B60000000000000000000000000000000000045 :104B70000000000000000000000000000000000035 :104B80000000000000000000000000000000000025 :104B90000000000000000000000000000000000015 :104BA0000000000000000000000000000000000005 :104BB00000000000000000000000000000000000F5 :104BC00000000000000000000000000000000000E5 :104BD00000000000000000000000000000000000D5 :104BE00000000000000000000000000000000000C5 :104BF00000000000000000000000000000000000B5 :104C000000000000000000000000000000000000A4 :104C10000000000000000000000000000000000094 :104C20000000000000000000000000000000000084 :104C30000000000000000000000000000000000074 :104C40000000000000000000000000000000000064 :104C50000000000000000000000000000000000054 :104C60000000000000000000000000000000000044 :104C70000000000000000000000000000000000034 :104C80000000000000000000000000000000000024 :104C90000000000000000000000000000000000014 :104CA0000000000000000000000000000000000004 :104CB00000000000000000000000000000000000F4 :104CC00000000000000000000000000000000000E4 :104CD00000000000000000000000000000000000D4 :104CE00000000000000000000000000000000000C4 :104CF00000000000000000000000000000000000B4 :104D000000000000000000000000000000000000A3 :104D10000000000000000000000000000000000093 :104D20000000000000000000000000000000000083 :104D30000000000000000000000000000000000073 :104D40000000000000000000000000000000000063 :104D50000000000000000000000000000000000053 :104D60000000000000000000000000000000000043 :104D70000000000000000000000000000000000033 :104D80000000000000000000000000000000000023 :104D90000000000000000000000000000000000013 :104DA0000000000000000000000000000000000003 :104DB00000000000000000000000000000000000F3 :104DC00000000000000000000000000000000000E3 :104DD00000000000000000000000000000000000D3 :104DE00000000000000000000000000000000000C3 :104DF00000000000000000000000000000000000B3 :104E000000000000000000000000000000000000A2 :104E10000000000000000000000000000000000092 :104E20000000000000000000000000000000000082 :104E30000000000000000000000000000000000072 :104E40000000000000000000000000000000000062 :104E50000000000000000000000000000000000052 :104E60000000000000000000000000000000000042 :104E70000000000000000000000000000000000032 :104E80000000000000000000000000000000000022 :104E90000000000000000000000000000000000012 :104EA0000000000000000000000000000000000002 :104EB00000000000000000000000000000000000F2 :104EC00000000000000000000000000000000000E2 :104ED00000000000000000000000000000000000D2 :104EE00000000000000000000000000000000000C2 :104EF00000000000000000000000000000000000B2 :104F000000000000000000000000000000000000A1 :104F10000000000000000000000000000000000091 :104F20000000000000000000000000000000000081 :104F30000000000000000000000000000000000071 :104F40000000000000000000000000000000000061 :104F50000000000000000000000000000000000051 :104F60000000000000000000000000000000000041 :104F70000000000000000000000000000000000031 :104F80000000000000000000000000000000000021 :104F90000000000000000000000000000000000011 :104FA0000000000000000000000000000000000001 :104FB00000000000000000000000000000000000F1 :104FC00000000000000000000000000000000000E1 :104FD00000000000000000000000000000000000D1 :104FE00000000000000000000000000000000000C1 :104FF00000000000000000000000000000000000B1 :1050000000000000000000000000000000000000A0 :105010000000000000000000000000000000000090 :105020000000000000000000000000000000000080 :105030000000000000000000000000000000000070 :105040000000000000000000000000000000000060 :105050000000000000000000000000000000000050 :105060000000000000000000000000000000000040 :105070000000000000000000000000000000000030 :105080000000000000000000000000000000000020 :105090000000000000000000000000000000000010 :1050A0000000000000000000000000000000000000 :1050B00000000000000000000000000000000000F0 :1050C00000000000000000000000000000000000E0 :1050D00000000000000000000000000000000000D0 :1050E00000000000000000000000000000000000C0 :1050F00000000000000000000000000000000000B0 :10510000000000000000000000000000000000009F :10511000000000000000000000000000000000008F :10512000000000000000000000000000000000007F :10513000000000000000000000000000000000006F :10514000000000000000000000000000000000005F :10515000000000000000000000000000000000004F :10516000000000000000000000000000000000003F :10517000000000000000000000000000000000002F :10518000000000000000000000000000000000001F :10519000000000000000000000000000000000000F :1051A00000000000000000000000000000000000FF :1051B00000000000000000000000000000000000EF :1051C00000000000000000000000000000000000DF :1051D00000000000000000000000000000000000CF :1051E00000000000000000000000000000000000BF :1051F00000000000000000000000000000000000AF :10520000000000000000000000000000000000009E :10521000000000000000000000000000000000008E :10522000000000000000000000000000000000007E :10523000000000000000000000000000000000006E :10524000000000000000000000000000000000005E :10525000000000000000000000000000000000004E :10526000000000000000000000000000000000003E :10527000000000000000000000000000000000002E :10528000000000000000000000000000000000001E :10529000000000000000000000000000000000000E :1052A00000000000000000000000000000000000FE :1052B00000000000000000000000000000000000EE :1052C00000000000000000000000000000000000DE :1052D00000000000000000000000000000000000CE :1052E00000000000000000000000000000000000BE :1052F00000000000000000000000000000000000AE :10530000000000000000000000000000000000009D :10531000000000000000000000000000000000008D :10532000000000000000000000000000000000007D :10533000000000000000000000000000000000006D :10534000000000000000000000000000000000005D :10535000000000000000000000000000000000004D :10536000000000000000000000000000000000003D :10537000000000000000000000000000000000002D :10538000000000000000000000000000000000001D :10539000000000000000000000000000000000000D :1053A00000000000000000000000000000000000FD :1053B00000000000000000000000000000000000ED :1053C00000000000000000000000000000000000DD :1053D00000000000000000000000000000000000CD :1053E00000000000000000000000000000000000BD :1053F00000000000000000000000000000000000AD :10540000000000000000000000000000000000009C :10541000000000000000000000000000000000008C :10542000000000000000000000000000000000007C :10543000000000000000000000000000000000006C :10544000000000000000000000000000000000005C :10545000000000000000000000000000000000004C :10546000000000000000000000000000000000003C :10547000000000000000000000000000000000002C :10548000000000000000000000000000000000001C :10549000000000000000000000000000000000000C :1054A00000000000000000000000000000000000FC :1054B00000000000000000000000000000000000EC :1054C00000000000000000000000000000000000DC :1054D00000000000000000000000000000000000CC :1054E00000000000000000000000000000000000BC :1054F00000000000000000000000000000000000AC :10550000000000000000000000000000000000009B :10551000000000000000000000000000000000008B :10552000000000000000000000000000000000007B :10553000000000000000000000000000000000006B :10554000000000000000000000000000000000005B :10555000000000000000000000000000000000004B :10556000000000000000000000000000000000003B :10557000000000000000000000000000000000002B :10558000000000000000000000000000000000001B :10559000000000000000000000000000000000000B :1055A00000000000000000000000000000000000FB :1055B00000000000000000000000000000000000EB :1055C00000000000000000000000000000000000DB :1055D00000000000000000000000000000000000CB :1055E00000000000000000000000000000000000BB :1055F00000000000000000000000000000000000AB :10560000000000000000000000000000000000009A :10561000000000000000000000000000000000008A :10562000000000000000000000000000000000007A :10563000000000000000000000000000000000006A :10564000000000000000000000000000000000005A :10565000000000000000000000000000000000004A :10566000000000000000000000000000000000003A :10567000000000000000000000000000000000002A :10568000000000000000000000000000000000001A :10569000000000000000000000000000000000000A :1056A00000000000000000000000000000000000FA :1056B00000000000000000000000000000000000EA :1056C00000000000000000000000000000000000DA :1056D00000000000000000000000000000000000CA :1056E00000000000000000000000000000000000BA :1056F00000000000000000000000000000000000AA :105700000000000000000000000000000000000099 :105710000000000000000000000000000000000089 :105720000000000000000000000000000000000079 :105730000000000000000000000000000000000069 :105740000000000000000000000000000000000059 :105750000000000000000000000000000000000049 :105760000000000000000000000000000000000039 :105770000000000000000000000000000000000029 :105780000000000000000000000000000000000019 :105790000000000000000000000000000000000009 :1057A00000000000000000000000000000000000F9 :1057B00000000000000000000000000000000000E9 :1057C00000000000000000000000000000000000D9 :1057D00000000000000000000000000000000000C9 :1057E00000000000000000000000000000000000B9 :1057F00000000000000000000000000000000000A9 :105800000000000000000000000000000000000098 :105810000000000000000000000000000000000088 :105820000000000000000000000000000000000078 :105830000000000000000000000000000000000068 :105840000000000000000000000000000000000058 :105850000000000000000000000000000000000048 :105860000000000000000000000000000000000038 :105870000000000000000000000000000000000028 :105880000000000000000000000000000000000018 :105890000000000000000000000000000000000008 :1058A00000000000000000000000000000000000F8 :1058B00000000000000000000000000000000000E8 :1058C00000000000000000000000000000000000D8 :1058D00000000000000000000000000000000000C8 :1058E00000000000000000000000000000000000B8 :1058F00000000000000000000000000000000000A8 :105900000000000000000000000000000000000097 :105910000000000000000000000000000000000087 :105920000000000000000000000000000000000077 :105930000000000000000000000000000000000067 :105940000000000000000000000000000000000057 :105950000000000000000000000000000000000047 :105960000000000000000000000000000000000037 :105970000000000000000000000000000000000027 :105980000000000000000000000000000000000017 :105990000000000000000000000000000000000007 :1059A00000000000000000000000000000000000F7 :1059B00000000000000000000000000000000000E7 :1059C00000000000000000000000000000000000D7 :1059D00000000000000000000000000000000000C7 :1059E00000000000000000000000000000000000B7 :1059F00000000000000000000000000000000000A7 :105A00000000000000000000000000000000000096 :105A10000000000000000000000000000000000086 :105A20000000000000000000000000000000000076 :105A30000000000000000000000000000000000066 :105A40000000000000000000000000000000000056 :105A50000000000000000000000000000000000046 :105A60000000000000000000000000000000000036 :105A70000000000000000000000000000000000026 :105A80000000000000000000000000000000000016 :105A90000000000000000000000000000000000006 :105AA00000000000000000000000000000000000F6 :105AB00000000000000000000000000000000000E6 :105AC00000000000000000000000000000000000D6 :105AD00000000000000000000000000000000000C6 :105AE00000000000000000000000000000000000B6 :105AF00000000000000000000000000000000000A6 :105B00000000000000000000000000000000000095 :105B10000000000000000000000000000000000085 :105B20000000000000000000000000000000000075 :105B30000000000000000000000000000000000065 :105B40000000000000000000000000000000000055 :105B50000000000000000000000000000000000045 :105B60000000000000000000000000000000000035 :105B70000000000000000000000000000000000025 :105B80000000000000000000000000000000000015 :105B90000000000000000000000000000000000005 :105BA00000000000000000000000000000000000F5 :105BB00000000000000000000000000000000000E5 :105BC00000000000000000000000000000000000D5 :105BD00000000000000000000000000000000000C5 :105BE00000000000000000000000000000000000B5 :105BF00000000000000000000000000000000000A5 :105C00000000000000000000000000000000000094 :105C10000000000000000000000000000000000084 :105C20000000000000000000000000000000000074 :105C30000000000000000000000000000000000064 :105C40000000000000000000000000000000000054 :105C50000000000000000000000000000000000044 :105C60000000000000000000000000000000000034 :105C70000000000000000000000000000000000024 :105C80000000000000000000000000000000000014 :105C90000000000000000000000000000000000004 :105CA00000000000000000000000000000000000F4 :105CB00000000000000000000000000000000000E4 :105CC00000000000000000000000000000000000D4 :105CD00000000000000000000000000000000000C4 :105CE00000000000000000000000000000000000B4 :105CF00000000000000000000000000000000000A4 :105D00000000000000000000000000000000000093 :105D10000000000000000000000000000000000083 :105D20000000000000000000000000000000000073 :105D30000000000000000000000000000000000063 :105D40000000000000000000000000000000000053 :105D50000000000000000000000000000000000043 :105D60000000000000000000000000000000000033 :105D70000000000000000000000000000000000023 :105D80000000000000000000000000000000000013 :105D90000000000000000000000000000000000003 :105DA00000000000000000000000000000000000F3 :105DB00000000000000000000000000000000000E3 :105DC00000000000000000000000000000000000D3 :105DD00000000000000000000000000000000000C3 :105DE00000000000000000000000000000000000B3 :105DF00000000000000000000000000000000000A3 :105E00000000000000000000000000000000000092 :105E10000000000000000000000000000000000082 :105E20000000000000000000000000000000000072 :105E30000000000000000000000000000000000062 :105E40000000000000000000000000000000000052 :105E50000000000000000000000000000000000042 :105E60000000000000000000000000000000000032 :105E70000000000000000000000000000000000022 :105E80000000000000000000000000000000000012 :105E90000000000000000000000000000000000002 :105EA00000000000000000000000000000000000F2 :105EB00000000000000000000000000000000000E2 :105EC00000000000000000000000000000000000D2 :105ED00000000000000000000000000000000000C2 :105EE00000000000000000000000000000000000B2 :105EF00000000000000000000000000000000000A2 :105F00000000000000000000000000000000000091 :105F10000000000000000000000000000000000081 :105F20000000000000000000000000000000000071 :105F30000000000000000000000000000000000061 :105F40000000000000000000000000000000000051 :105F50000000000000000000000000000000000041 :105F60000000000000000000000000000000000031 :105F70000000000000000000000000000000000021 :105F80000000000000000000000000000000000011 :105F90000000000000000000000000000000000001 :105FA00000000000000000000000000000000000F1 :105FB00000000000000000000000000000000000E1 :105FC00000000000000000000000000000000000D1 :105FD00000000000000000000000000000000000C1 :105FE00000000000000000000000000000000000B1 :105FF00000000000000000000000000000000000A1 :106000000000000000000000000000000000000090 :106010000000000000000000000000000000000080 :106020000000000000000000000000000000000070 :106030000000000000000000000000000000000060 :106040000000000000000000000000000000000050 :106050000000000000000000000000000000000040 :106060000000000000000000000000000000000030 :106070000000000000000000000000000000000020 :106080000000000000000000000000000000000010 :106090000000000000000000000000000000000000 :1060A00000000000000000000000000000000000F0 :1060B00000000000000000000000000000000000E0 :1060C00000000000000000000000000000000000D0 :1060D00000000000000000000000000000000000C0 :1060E00000000000000000000000000000000000B0 :1060F00000000000000000000000000000000000A0 :10610000000000000000000000000000000000008F :10611000000000000000000000000000000000007F :10612000000000000000000000000000000000006F :10613000000000000000000000000000000000005F :10614000000000000000000000000000000000004F :10615000000000000000000000000000000000003F :10616000000000000000000000000000000000002F :10617000000000000000000000000000000000001F :10618000000000000000000000000000000000000F :1061900000000000000000000000000000000000FF :1061A00000000000000000000000000000000000EF :1061B00000000000000000000000000000000000DF :1061C00000000000000000000000000000000000CF :1061D00000000000000000000000000000000000BF :1061E00000000000000000000000000000000000AF :1061F000000000000000000000000000000000009F :10620000000000000000000000000000000000008E :10621000000000000000000000000000000000007E :10622000000000000000000000000000000000006E :10623000000000000000000000000000000000005E :10624000000000000000000000000000000000004E :10625000000000000000000000000000000000003E :10626000000000000000000000000000000000002E :10627000000000000000000000000000000000001E :10628000000000000000000000000000000000000E :1062900000000000000000000000000000000000FE :1062A00000000000000000000000000000000000EE :1062B00000000000000000000000000000000000DE :1062C00000000000000000000000000000000000CE :1062D00000000000000000000000000000000000BE :1062E00000000000000000000000000000000000AE :1062F000000000000000000000000000000000009E :10630000000000000000000000000000000000008D :10631000000000000000000000000000000000007D :10632000000000000000000000000000000000006D :10633000000000000000000000000000000000005D :10634000000000000000000000000000000000004D :10635000000000000000000000000000000000003D :10636000000000000000000000000000000000002D :10637000000000000000000000000000000000001D :10638000000000000000000000000000000000000D :1063900000000000000000000000000000000000FD :1063A00000000000000000000000000000000000ED :1063B00000000000000000000000000000000000DD :1063C00000000000000000000000000000000000CD :1063D00000000000000000000000000000000000BD :1063E00000000000000000000000000000000000AD :1063F000000000000000000000000000000000009D :10640000000000000000000000000000000000008C :10641000000000000000000000000000000000007C :10642000000000000000000000000000000000006C :10643000000000000000000000000000000000005C :10644000000000000000000000000000000000004C :10645000000000000000000000000000000000003C :10646000000000000000000000000000000000002C :10647000000000000000000000000000000000001C :10648000000000000000000000000000000000000C :1064900000000000000000000000000000000000FC :1064A00000000000000000000000000000000000EC :1064B00000000000000000000000000000000000DC :1064C00000000000000000000000000000000000CC :1064D00000000000000000000000000000000000BC :1064E00000000000000000000000000000000000AC :1064F000000000000000000000000000000000009C :10650000000000000000000000000000000000008B :10651000000000000000000000000000000000007B :10652000000000000000000000000000000000006B :10653000000000000000000000000000000000005B :10654000000000000000000000000000000000004B :10655000000000000000000000000000000000003B :10656000000000000000000000000000000000002B :10657000000000000000000000000000000000001B :10658000000000000000000000000000000000000B :1065900000000000000000000000000000000000FB :1065A00000000000000000000000000000000000EB :1065B00000000000000000000000000000000000DB :1065C00000000000000000000000000000000000CB :1065D00000000000000000000000000000000000BB :1065E00000000000000000000000000000000000AB :1065F000000000000000000000000000000000009B :10660000000000000000000000000000000000008A :10661000000000000000000000000000000000007A :10662000000000000000000000000000000000006A :10663000000000000000000000000000000000005A :10664000000000000000000000000000000000004A :10665000000000000000000000000000000000003A :10666000000000000000000000000000000000002A :10667000000000000000000000000000000000001A :10668000000000000000000000000000000000000A :1066900000000000000000000000000000000000FA :1066A00000000000000000000000000000000000EA :1066B00000000000000000000000000000000000DA :1066C00000000000000000000000000000000000CA :1066D00000000000000000000000000000000000BA :1066E00000000000000000000000000000000000AA :1066F000000000000000000000000000000000009A :106700000000000000000000000000000000000089 :106710000000000000000000000000000000000079 :106720000000000000000000000000000000000069 :106730000000000000000000000000000000000059 :106740000000000000000000000000000000000049 :106750000000000000000000000000000000000039 :106760000000000000000000000000000000000029 :106770000000000000000000000000000000000019 :106780000000000000000000000000000000000009 :1067900000000000000000000000000000000000F9 :1067A00000000000000000000000000000000000E9 :1067B00000000000000000000000000000000000D9 :1067C00000000000000000000000000000000000C9 :1067D00000000000000000000000000000000000B9 :1067E00000000000000000000000000000000000A9 :1067F0000000000000000000000000000000000099 :106800000000000000000000000000000000000088 :106810000000000000000000000000000000000078 :106820000000000000000000000000000000000068 :106830000000000000000000000000000000000058 :106840000000000000000000000000000000000048 :106850000000000000000000000000000000000038 :106860000000000000000000000000000000000028 :106870000000000000000000000000000000000018 :106880000000000000000000000000000000000008 :1068900000000000000000000000000000000000F8 :1068A00000000000000000000000000000000000E8 :1068B00000000000000000000000000000000000D8 :1068C00000000000000000000000000000000000C8 :1068D00000000000000000000000000000000000B8 :1068E00000000000000000000000000000000000A8 :1068F0000000000000000000000000000000000098 :106900000000000000000000000000000000000087 :106910000000000000000000000000000000000077 :106920000000000000000000000000000000000067 :106930000000000000000000000000000000000057 :106940000000000000000000000000000000000047 :106950000000000000000000000000000000000037 :106960000000000000000000000000000000000027 :106970000000000000000000000000000000000017 :106980000000000000000000000000000000000007 :1069900000000000000000000000000000000000F7 :1069A00000000000000000000000000000000000E7 :1069B00000000000000000000000000000000000D7 :1069C00000000000000000000000000000000000C7 :1069D00000000000000000000000000000000000B7 :1069E00000000000000000000000000000000000A7 :1069F0000000000000000000000000000000000097 :106A00000000000000000000000000000000000086 :106A10000000000000000000000000000000000076 :106A20000000000000000000000000000000000066 :106A30000000000000000000000000000000000056 :106A40000000000000000000000000000000000046 :106A50000000000000000000000000000000000036 :106A60000000000000000000000000000000000026 :106A70000000000000000000000000000000000016 :106A80000000000000000000000000000000000006 :106A900000000000000000000000000000000000F6 :106AA00000000000000000000000000000000000E6 :106AB00000000000000000000000000000000000D6 :106AC00000000000000000000000000000000000C6 :106AD00000000000000000000000000000000000B6 :106AE00000000000000000000000000000000000A6 :106AF0000000000000000000000000000000000096 :106B00000000000000000000000000000000000085 :106B10000000000000000000000000000000000075 :106B20000000000000000000000000000000000065 :106B30000000000000000000000000000000000055 :106B40000000000000000000000000000000000045 :106B50000000000000000000000000000000000035 :106B60000000000000000000000000000000000025 :106B70000000000000000000000000000000000015 :106B80000000000000000000000000000000000005 :106B900000000000000000000000000000000000F5 :106BA00000000000000000000000000000000000E5 :106BB00000000000000000000000000000000000D5 :106BC00000000000000000000000000000000000C5 :106BD00000000000000000000000000000000000B5 :106BE00000000000000000000000000000000000A5 :106BF0000000000000000000000000000000000095 :106C00000000000000000000000000000000000084 :106C10000000000000000000000000000000000074 :106C20000000000000000000000000000000000064 :106C30000000000000000000000000000000000054 :106C40000000000000000000000000000000000044 :106C50000000000000000000000000000000000034 :106C60000000000000000000000000000000000024 :106C70000000000000000000000000000000000014 :106C80000000000000000000000000000000000004 :106C900000000000000000000000000000000000F4 :106CA00000000000000000000000000000000000E4 :106CB00000000000000000000000000000000000D4 :106CC00000000000000000000000000000000000C4 :106CD00000000000000000000000000000000000B4 :106CE00000000000000000000000000000000000A4 :106CF0000000000000000000000000000000000094 :106D00000000000000000000000000000000000083 :106D10000000000000000000000000000000000073 :106D20000000000000000000000000000000000063 :106D30000000000000000000000000000000000053 :106D40000000000000000000000000000000000043 :106D50000000000000000000000000000000000033 :106D60000000000000000000000000000000000023 :106D70000000000000000000000000000000000013 :106D80000000000000000000000000000000000003 :106D900000000000000000000000000000000000F3 :106DA00000000000000000000000000000000000E3 :106DB00000000000000000000000000000000000D3 :106DC00000000000000000000000000000000000C3 :106DD00000000000000000000000000000000000B3 :106DE00000000000000000000000000000000000A3 :106DF0000000000000000000000000000000000093 :106E00000000000000000000000000000000000082 :106E10000000000000000000000000000000000072 :106E20000000000000000000000000000000000062 :106E30000000000000000000000000000000000052 :106E40000000000000000000000000000000000042 :106E50000000000000000000000000000000000032 :106E60000000000000000000000000000000000022 :106E70000000000000000000000000000000000012 :106E80000000000000000000000000000000000002 :106E900000000000000000000000000000000000F2 :106EA00000000000000000000000000000000000E2 :106EB00000000000000000000000000000000000D2 :106EC00000000000000000000000000000000000C2 :106ED00000000000000000000000000000000000B2 :106EE00000000000000000000000000000000000A2 :106EF0000000000000000000000000000000000092 :106F00000000000000000000000000000000000081 :106F10000000000000000000000000000000000071 :106F20000000000000000000000000000000000061 :106F30000000000000000000000000000000000051 :106F40000000000000000000000000000000000041 :106F50000000000000000000000000000000000031 :106F60000000000000000000000000000000000021 :106F70000000000000000000000000000000000011 :106F80000000000000000000000000000000000001 :106F900000000000000000000000000000000000F1 :106FA00000000000000000000000000000000000E1 :106FB00000000000000000000000000000000000D1 :106FC00000000000000000000000000000000000C1 :106FD00000000000000000000000000000000000B1 :106FE00000000000000000000000000000000000A1 :106FF0000000000000000000000000000000000091 :107000000000000000000000000000000000000080 :107010000000000000000000000000000000000070 :107020000000000000000000000000000000000060 :107030000000000000000000000000000000000050 :107040000000000000000000000000000000000040 :107050000000000000000000000000000000000030 :107060000000000000000000000000000000000020 :107070000000000000000000000000000000000010 :107080000000000000000000000000000000000000 :1070900000000000000000000000000000000000F0 :1070A00000000000000000000000000000000000E0 :1070B00000000000000000000000000000000000D0 :1070C00000000000000000000000000000000000C0 :1070D00000000000000000000000000000000000B0 :1070E00000000000000000000000000000000000A0 :1070F0000000000000000000000000000000000090 :10710000000000000000000000000000000000007F :10711000000000000000000000000000000000006F :10712000000000000000000000000000000000005F :10713000000000000000000000000000000000004F :10714000000000000000000000000000000000003F :10715000000000000000000000000000000000002F :10716000000000000000000000000000000000001F :10717000000000000000000000000000000000000F :1071800000000000000000000000000000000000FF :1071900000000000000000000000000000000000EF :1071A00000000000000000000000000000000000DF :1071B00000000000000000000000000000000000CF :1071C00000000000000000000000000000000000BF :1071D00000000000000000000000000000000000AF :1071E000000000000000000000000000000000009F :1071F000000000000000000000000000000000008F :10720000000000000000000000000000000000007E :10721000000000000000000000000000000000006E :10722000000000000000000000000000000000005E :10723000000000000000000000000000000000004E :10724000000000000000000000000000000000003E :10725000000000000000000000000000000000002E :10726000000000000000000000000000000000001E :10727000000000000000000000000000000000000E :1072800000000000000000000000000000000000FE :1072900000000000000000000000000000000000EE :1072A00000000000000000000000000000000000DE :1072B00000000000000000000000000000000000CE :1072C00000000000000000000000000000000000BE :1072D00000000000000000000000000000000000AE :1072E000000000000000000000000000000000009E :1072F000000000000000000000000000000000008E :10730000000000000000000000000000000000007D :10731000000000000000000000000000000000006D :10732000000000000000000000000000000000005D :10733000000000000000000000000000000000004D :10734000000000000000000000000000000000003D :10735000000000000000000000000000000000002D :10736000000000000000000000000000000000001D :10737000000000000000000000000000000000000D :1073800000000000000000000000000000000000FD :1073900000000000000000000000000000000000ED :1073A00000000000000000000000000000000000DD :1073B00000000000000000000000000000000000CD :1073C00000000000000000000000000000000000BD :1073D00000000000000000000000000000000000AD :1073E000000000000000000000000000000000009D :1073F000000000000000000000000000000000008D :10740000000000000000000000000000000000007C :10741000000000000000000000000000000000006C :10742000000000000000000000000000000000005C :10743000000000000000000000000000000000004C :10744000000000000000000000000000000000003C :10745000000000000000000000000000000000002C :10746000000000000000000000000000000000001C :10747000000000000000000000000000000000000C :1074800000000000000000000000000000000000FC :1074900000000000000000000000000000000000EC :1074A00000000000000000000000000000000000DC :1074B00000000000000000000000000000000000CC :1074C00000000000000000000000000000000000BC :1074D00000000000000000000000000000000000AC :1074E000000000000000000000000000000000009C :1074F000000000000000000000000000000000008C :10750000000000000000000000000000000000007B :10751000000000000000000000000000000000006B :10752000000000000000000000000000000000005B :10753000000000000000000000000000000000004B :10754000000000000000000000000000000000003B :10755000000000000000000000000000000000002B :10756000000000000000000000000000000000001B :10757000000000000000000000000000000000000B :1075800000000000000000000000000000000000FB :1075900000000000000000000000000000000000EB :1075A00000000000000000000000000000000000DB :1075B00000000000000000000000000000000000CB :1075C00000000000000000000000000000000000BB :1075D00000000000000000000000000000000000AB :1075E000000000000000000000000000000000009B :1075F000000000000000000000000000000000008B :10760000000000000000000000000000000000007A :10761000000000000000000000000000000000006A :10762000000000000000000000000000000000005A :10763000000000000000000000000000000000004A :10764000000000000000000000000000000000003A :10765000000000000000000000000000000000002A :10766000000000000000000000000000000000001A :10767000000000000000000000000000000000000A :1076800000000000000000000000000000000000FA :1076900000000000000000000000000000000000EA :1076A00000000000000000000000000000000000DA :1076B00000000000000000000000000000000000CA :1076C00000000000000000000000000000000000BA :1076D00000000000000000000000000000000000AA :1076E000000000000000000000000000000000009A :1076F000000000000000000000000000000000008A :107700000000000000000000000000000000000079 :107710000000000000000000000000000000000069 :107720000000000000000000000000000000000059 :107730000000000000000000000000000000000049 :107740000000000000000000000000000000000039 :107750000000000000000000000000000000000029 :107760000000000000000000000000000000000019 :107770000000000000000000000000000000000009 :1077800000000000000000000000000000000000F9 :1077900000000000000000000000000000000000E9 :1077A00000000000000000000000000000000000D9 :1077B00000000000000000000000000000000000C9 :1077C00000000000000000000000000000000000B9 :1077D00000000000000000000000000000000000A9 :1077E0000000000000000000000000000000000099 :1077F0000000000000000000000000000000000089 :107800000000000000000000000000000000000078 :107810000000000000000000000000000000000068 :107820000000000000000000000000000000000058 :107830000000000000000000000000000000000048 :107840000000000000000000000000000000000038 :107850000000000000000000000000000000000028 :107860000000000000000000000000000000000018 :107870000000000000000000000000000000000008 :1078800000000000000000000000000000000000F8 :1078900000000000000000000000000000000000E8 :1078A00000000000000000000000000000000000D8 :1078B00000000000000000000000000000000000C8 :1078C00000000000000000000000000000000000B8 :1078D00000000000000000000000000000000000A8 :1078E0000000000000000000000000000000000098 :1078F0000000000000000000000000000000000088 :107900000000000000000000000000000000000077 :107910000000000000000000000000000000000067 :107920000000000000000000000000000000000057 :107930000000000000000000000000000000000047 :107940000000000000000000000000000000000037 :107950000000000000000000000000000000000027 :107960000000000000000000000000000000000017 :107970000000000000000000000000000000000007 :1079800000000000000000000000000000000000F7 :1079900000000000000000000000000000000000E7 :1079A00000000000000000000000000000000000D7 :1079B00000000000000000000000000000000000C7 :1079C00000000000000000000000000000000000B7 :1079D00000000000000000000000000000000000A7 :1079E0000000000000000000000000000000000097 :1079F0000000000000000000000000000000000087 :107A00000000000000000000000000000000000076 :107A10000000000000000000000000000000000066 :107A20000000000000000000000000000000000056 :107A30000000000000000000000000000000000046 :107A40000000000000000000000000000000000036 :107A50000000000000000000000000000000000026 :107A60000000000000000000000000000000000016 :107A70000000000000000000000000000000000006 :107A800000000000000000000000000000000000F6 :107A900000000000000000000000000000000000E6 :107AA00000000000000000000000000000000000D6 :107AB00000000000000000000000000000000000C6 :107AC00000000000000000000000000000000000B6 :107AD00000000000000000000000000000000000A6 :107AE0000000000000000000000000000000000096 :107AF0000000000000000000000000000000000086 :107B00000000000000000000000000000000000075 :107B10000000000000000000000000000000000065 :107B20000000000000000000000000000000000055 :107B30000000000000000000000000000000000045 :107B40000000000000000000000000000000000035 :107B50000000000000000000000000000000000025 :107B60000000000000000000000000000000000015 :107B70000000000000000000000000000000000005 :107B800000000000000000000000000000000000F5 :107B900000000000000000000000000000000000E5 :107BA00000000000000000000000000000000000D5 :107BB00000000000000000000000000000000000C5 :107BC00000000000000000000000000000000000B5 :107BD00000000000000000000000000000000000A5 :107BE0000000000000000000000000000000000095 :107BF0000000000000000000000000000000000085 :107C00000000000000000000000000000000000074 :107C10000000000000000000000000000000000064 :107C20000000000000000000000000000000000054 :107C30000000000000000000000000000000000044 :107C40000000000000000000000000000000000034 :107C50000000000000000000000000000000000024 :107C60000000000000000000000000000000000014 :107C70000000000000000000000000000000000004 :107C800000000000000000000000000000000000F4 :107C900000000000000000000000000000000000E4 :107CA00000000000000000000000000000000000D4 :107CB00000000000000000000000000000000000C4 :107CC00000000000000000000000000000000000B4 :107CD00000000000000000000000000000000000A4 :107CE0000000000000000000000000000000000094 :107CF0000000000000000000000000000000000084 :107D00000000000000000000000000000000000073 :107D10000000000000000000000000000000000063 :107D20000000000000000000000000000000000053 :107D30000000000000000000000000000000000043 :107D40000000000000000000000000000000000033 :107D50000000000000000000000000000000000023 :107D60000000000000000000000000000000000013 :107D70000000000000000000000000000000000003 :107D800000000000000000000000000000000000F3 :107D900000000000000000000000000000000000E3 :107DA00000000000000000000000000000000000D3 :107DB00000000000000000000000000000000000C3 :107DC00000000000000000000000000000000000B3 :107DD00000000000000000000000000000000000A3 :107DE0000000000000000000000000000000000093 :107DF0000000000000000000000000000000000083 :107E00000000000000000000000000000000000072 :107E10000000000000000000000000000000000062 :107E20000000000000000000000000000000000052 :107E30000000000000000000000000000000000042 :107E40000000000000000000000000000000000032 :107E50000000000000000000000000000000000022 :107E60000000000000000000000000000000000012 :107E70000000000000000000000000000000000002 :107E800000000000000000000000000000000000F2 :107E900000000000000000000000000000000000E2 :107EA00000000000000000000000000000000000D2 :107EB00000000000000000000000000000000000C2 :107EC00000000000000000000000000000000000B2 :107ED00000000000000000000000000000000000A2 :107EE0000000000000000000000000000000000092 :107EF0000000000000000000000000000000000082 :107F00000000000000000000000000000000000071 :107F10000000000000000000000000000000000061 :107F20000000000000000000000000000000000051 :107F30000000000000000000000000000000000041 :107F40000000000000000000000000000000000031 :107F50000000000000000000000000000000000021 :107F60000000000000000000000000000000000011 :107F70000000000000000000000000000000000001 :107F800000000000000000000000000000000000F1 :107F900000000000000000000000000000000000E1 :107FA00000000000000000000000000000000000D1 :107FB00000000000000000000000000000000000C1 :107FC00000000000000000000000000000000000B1 :107FD00000000000000000000000000000000000A1 :107FE0000000000000000000000000000000000091 :107FF0000000000000000000000000000000000081 :108000000000000000000000000000000000000070 :108010000000000000000000000000000000000060 :108020000000000000000000000000000000000050 :108030000000000000000000000000000000000040 :108040000000000000000000000000000000000030 :108050000000000000000000000000000000000020 :108060000000000000000000000000000000000010 :108070000000000000000000000000000000000000 :1080800000000000000000000000000000000000F0 :1080900000000000000000000000000000000000E0 :1080A00000000000000000000000000000000000D0 :1080B00000000000000000000000000000000000C0 :1080C00000000000000000000000000000000000B0 :1080D00000000000000000000000000000000000A0 :1080E0000000000000000000000000000000000090 :1080F0000000000000000000000000000000000080 :10810000000000000000000000000000000000006F :10811000000000000000000000000000000000005F :10812000000000000000000000000000000000004F :10813000000000000000000000000000000000003F :10814000000000000000000000000000000000002F :10815000000000000000000000000000000000001F :10816000000000000000000000000000000000000F :1081700000000000000000000000000000000000FF :1081800000000000000000000000000000000000EF :1081900000000000000000000000000000000000DF :1081A00000000000000000000000000000000000CF :1081B00000000000000000000000000000000000BF :1081C00000000000000000000000000000000000AF :1081D000000000000000000000000000000000009F :1081E000000000000000000000000000000000008F :1081F000000000000000000000000000000000007F :10820000000000000000000000000000000000006E :10821000000000000000000000000000000000005E :10822000000000000000000000000000000000004E :10823000000000000000000000000000000000003E :10824000000000000000000000000000000000002E :10825000000000000000000000000000000000001E :10826000000000000000000000000000000000000E :1082700000000000000000000000000000000000FE :1082800000000000000000000000000000000000EE :1082900000000000000000000000000000000000DE :1082A00000000000000000000000000000000000CE :1082B00000000000000000000000000000000000BE :1082C00000000000000000000000000000000000AE :1082D000000000000000000000000000000000009E :1082E000000000000000000000000000000000008E :1082F000000000000000000000000000000000007E :10830000000000000000000000000000000000006D :10831000000000000000000000000000000000005D :10832000000000000000000000000000000000004D :10833000000000000000000000000000000000003D :10834000000000000000000000000000000000002D :10835000000000000000000000000000000000001D :10836000000000000000000000000000000000000D :1083700000000000000000000000000000000000FD :1083800000000000000000000000000000000000ED :1083900000000000000000000000000000000000DD :1083A00000000000000000000000000000000000CD :1083B00000000000000000000000000000000000BD :1083C00000000000000000000000000000000000AD :1083D000000000000000000000000000000000009D :1083E000000000000000000000000000000000008D :1083F000000000000000000000000000000000007D :10840000000000000000000000000000000000006C :10841000000000000000000000000000000000005C :10842000000000000000000000000000000000004C :10843000000000000000000000000000000000003C :10844000000000000000000000000000000000002C :10845000000000000000000000000000000000001C :10846000000000000000000000000000000000000C :1084700000000000000000000000000000000000FC :1084800000000000000000000000000000000000EC :1084900000000000000000000000000000000000DC :1084A00000000000000000000000000000000000CC :1084B00000000000000000000000000000000000BC :1084C00000000000000000000000000000000000AC :1084D000000000000000000000000000000000009C :1084E000000000000000000000000000000000008C :1084F000000000000000000000000000000000007C :10850000000000000000000000000000000000006B :10851000000000000000000000000000000000005B :10852000000000000000000000000000000000004B :10853000000000000000000000000000000000003B :10854000000000000000000000000000000000002B :10855000000000000000000000000000000000001B :10856000000000000000000000000000000000000B :1085700000000000000000000000000000000000FB :1085800000000000000000000000000000000000EB :1085900000000000000000000000000000000000DB :1085A00000000000000000000000000000000000CB :1085B00000000000000000000000000000000000BB :1085C00000000000000000000000000000000000AB :1085D000000000000000000000000000000000009B :1085E000000000000000000000000000000000008B :1085F000000000000000000000000000000000007B :10860000000000000000000000000000000000006A :10861000000000000000000000000000000000005A :10862000000000000000000000000000000000004A :10863000000000000000000000000000000000003A :10864000000000000000000000000000000000002A :10865000000000000000000000000000000000001A :10866000000000000000000000000000000000000A :1086700000000000000000000000000000000000FA :1086800000000000000000000000000000000000EA :1086900000000000000000000000000000000000DA :1086A00000000000000000000000000000000000CA :1086B00000000000000000000000000000000000BA :1086C00000000000000000000000000000000000AA :1086D000000000000000000000000000000000009A :1086E000000000000000000000000000000000008A :1086F000000000000000000000000000000000007A :108700000000000000000000000000000000000069 :108710000000000000000000000000000000000059 :108720000000000000000000000000000000000049 :108730000000000000000000000000000000000039 :108740000000000000000000000000000000000029 :108750000000000000000000000000000000000019 :108760000000000000000000000000000000000009 :1087700000000000000000000000000000000000F9 :1087800000000000000000000000000000000000E9 :1087900000000000000000000000000000000000D9 :1087A00000000000000000000000000000000000C9 :1087B00000000000000000000000000000000000B9 :1087C00000000000000000000000000000000000A9 :1087D0000000000000000000000000000000000099 :1087E0000000000000000000000000000000000089 :1087F0000000000000000000000000000000000079 :108800000000000000000000000000000000000068 :108810000000000000000000000000000000000058 :108820000000000000000000000000000000000048 :108830000000000000000000000000000000000038 :108840000000000000000000000000000000000028 :108850000000000000000000000000000000000018 :108860000000000000000000000000000000000008 :1088700000000000000000000000000000000000F8 :1088800000000000000000000000000000000000E8 :1088900000000000000000000000000000000000D8 :1088A00000000000000000000000000000000000C8 :1088B00000000000000000000000000000000000B8 :1088C00000000000000000000000000000000000A8 :1088D0000000000000000000000000000000000098 :1088E0000000000000000000000000000000000088 :1088F0000000000000000000000000000000000078 :108900000000000000000000000000000000000067 :108910000000000000000000000000000000000057 :108920000000000000000000000000000000000047 :108930000000000000000000000000000000000037 :108940000000000000000000000000000000000027 :108950000000000000000000000000000000000017 :108960000000000000000000000000000000000007 :1089700000000000000000000000000000000000F7 :1089800000000000000000000000000000000000E7 :1089900000000000000000000000000000000000D7 :1089A00000000000000000000000000000000000C7 :1089B00000000000000000000000000000000000B7 :1089C00000000000000000000000000000000000A7 :1089D0000000000000000000000000000000000097 :1089E0000000000000000000000000000000000087 :1089F0000000000000000000000000000000000077 :108A00000000000000000000000000000000000066 :108A10000000000000000000000000000000000056 :108A20000000000000000000000000000000000046 :108A30000000000000000000000000000000000036 :108A40000000000000000000000000000000000026 :108A50000000000000000000000000000000000016 :108A60000000000000000000000000000000000006 :108A700000000000000000000000000000000000F6 :108A800000000000000000000000000000000000E6 :108A900000000000000000000000000000000000D6 :108AA00000000000000000000000000000000000C6 :108AB00000000000000000000000000000000000B6 :108AC00000000000000000000000000000000000A6 :108AD0000000000000000000000000000000000096 :108AE0000000000000000000000000000000000086 :108AF0000000000000000000000000000000000076 :108B00000000000000000000000000000000000065 :108B10000000000000000000000000000000000055 :108B20000000000000000000000000000000000045 :108B30000000000000000000000000000000000035 :108B40000000000000000000000000000000000025 :108B50000000000000000000000000000000000015 :108B60000000000000000000000000000000000005 :108B700000000000000000000000000000000000F5 :108B800000000000000000000000000000000000E5 :108B900000000000000000000000000000000000D5 :108BA00000000000000000000000000000000000C5 :108BB00000000000000000000000000000000000B5 :108BC00000000000000000000000000000000000A5 :108BD0000000000000000000000000000000000095 :108BE0000000000000000000000000000000000085 :108BF0000000000000000000000000000000000075 :108C00000000000000000000000000000000000064 :108C10000000000000000000000000000000000054 :108C20000000000000000000000000000000000044 :108C30000000000000000000000000000000000034 :108C40000000000000000000000000000000000024 :108C50000000000000000000000000000000000014 :108C60000000000000000000000000000000000004 :108C700000000000000000000000000000000000F4 :108C800000000000000000000000000000000000E4 :108C900000000000000000000000000000000000D4 :108CA00000000000000000000000000000000000C4 :108CB00000000000000000000000000000000000B4 :108CC00000000000000000000000000000000000A4 :108CD0000000000000000000000000000000000094 :108CE0000000000000000000000000000000000084 :108CF0000000000000000000000000000000000074 :108D00000000000000000000000000000000000063 :108D10000000000000000000000000000000000053 :108D20000000000000000000000000000000000043 :108D30000000000000000000000000000000000033 :108D40000000000000000000000000000000000023 :108D50000000000000000000000000000000000013 :108D60000000000000000000000000000000000003 :108D700000000000000000000000000000000000F3 :108D800000000000000000000000000000000000E3 :108D900000000000000000000000000000000000D3 :108DA00000000000000000000000000000000000C3 :108DB00000000000000000000000000000000000B3 :108DC00000000000000000000000000000000000A3 :108DD0000000000000000000000000000000000093 :108DE0000000000000000000000000000000000083 :108DF0000000000000000000000000000000000073 :108E00000000000000000000000000000000000062 :108E10000000000000000000000000000000000052 :108E20000000000000000000000000000000000042 :108E30000000000000000000000000000000000032 :108E40000000000000000000000000000000000022 :108E50000000000000000000000000000000000012 :108E60000000000000000000000000000000000002 :108E700000000000000000000000000000000000F2 :108E800000000000000000000000000000000000E2 :108E900000000000000000000000000000000000D2 :108EA00000000000000000000000000000000000C2 :108EB00000000000000000000000000000000000B2 :108EC00000000000000000000000000000000000A2 :108ED0000000000000000000000000000000000092 :108EE0000000000000000000000000000000000082 :108EF0000000000000000000000000000000000072 :108F00000000000000000000000000000000000061 :108F10000000000000000000000000000000000051 :108F20000000000000000000000000000000000041 :108F30000000000000000000000000000000000031 :108F40000000000000000000000000000000000021 :108F50000000000000000000000000000000000011 :108F60000000000000000000000000000000000001 :108F700000000000000000000000000000000000F1 :108F800000000000000000000000000000000000E1 :108F900000000000000000000000000000000000D1 :108FA00000000000000000000000000000000000C1 :108FB00000000000000000000000000000000000B1 :108FC00000000000000000000000000000000000A1 :108FD0000000000000000000000000000000000091 :108FE0000000000000000000000000000000000081 :108FF0000000000000000000000000000000000071 :109000000000000000000000000000000000000060 :109010000000000000000000000000000000000050 :109020000000000000000000000000000000000040 :109030000000000000000000000000000000000030 :109040000000000000000000000000000000000020 :109050000000000000000000000000000000000010 :109060000000000000000000000000000000000000 :1090700000000000000000000000000000000000F0 :1090800000000000000000000000000000000000E0 :1090900000000000000000000000000000000000D0 :1090A00000000000000000000000000000000000C0 :1090B00000000000000000000000000000000000B0 :1090C00000000000000000000000000000000000A0 :1090D0000000000000000000000000000000000090 :1090E0000000000000000000000000000000000080 :1090F0000000000000000000000000000000000070 :10910000000000000000000000000000000000005F :10911000000000000000000000000000000000004F :10912000000000000000000000000000000000003F :10913000000000000000000000000000000000002F :10914000000000000000000000000000000000001F :10915000000000000000000000000000000000000F :1091600000000000000000000000000000000000FF :1091700000000000000000000000000000000000EF :1091800000000000000000000000000000000000DF :1091900000000000000000000000000000000000CF :1091A00000000000000000000000000000000000BF :1091B00000000000000000000000000000000000AF :1091C000000000000000000000000000000000009F :1091D000000000000000000000000000000000008F :1091E000000000000000000000000000000000007F :1091F000000000000000000000000000000000006F :10920000000000000000000000000000000000005E :10921000000000000000000000000000000000004E :10922000000000000000000000000000000000003E :10923000000000000000000000000000000000002E :10924000000000000000000000000000000000001E :10925000000000000000000000000000000000000E :1092600000000000000000000000000000000000FE :1092700000000000000000000000000000000000EE :1092800000000000000000000000000000000000DE :1092900000000000000000000000000000000000CE :1092A00000000000000000000000000000000000BE :1092B00000000000000000000000000000000000AE :1092C000000000000000000000000000000000009E :1092D000000000000000000000000000000000008E :1092E000000000000000000000000000000000007E :1092F000000000000000000000000000000000006E :10930000000000000000000000000000000000005D :10931000000000000000000000000000000000004D :10932000000000000000000000000000000000003D :10933000000000000000000000000000000000002D :10934000000000000000000000000000000000001D :10935000000000000000000000000000000000000D :1093600000000000000000000000000000000000FD :1093700000000000000000000000000000000000ED :1093800000000000000000000000000000000000DD :1093900000000000000000000000000000000000CD :1093A00000000000000000000000000000000000BD :1093B00000000000000000000000000000000000AD :1093C000000000000000000000000000000000009D :1093D000000000000000000000000000000000008D :1093E000000000000000000000000000000000007D :1093F000000000000000000000000000000000006D :10940000000000000000000000000000000000005C :10941000000000000000000000000000000000004C :10942000000000000000000000000000000000003C :10943000000000000000000000000000000000002C :10944000000000000000000000000000000000001C :10945000000000000000000000000000000000000C :1094600000000000000000000000000000000000FC :1094700000000000000000000000000000000000EC :1094800000000000000000000000000000000000DC :1094900000000000000000000000000000000000CC :1094A00000000000000000000000000000000000BC :1094B00000000000000000000000000000000000AC :1094C000000000000000000000000000000000009C :1094D000000000000000000000000000000000008C :1094E000000000000000000000000000000000007C :1094F000000000000000000000000000000000006C :10950000000000000000000000000000000000005B :10951000000000000000000000000000000000004B :10952000000000000000000000000000000000003B :10953000000000000000000000000000000000002B :10954000000000000000000000000000000000001B :10955000000000000000000000000000000000000B :1095600000000000000000000000000000000000FB :1095700000000000000000000000000000000000EB :1095800000000000000000000000000000000000DB :1095900000000000000000000000000000000000CB :1095A00000000000000000000000000000000000BB :1095B00000000000000000000000000000000000AB :1095C000000000000000000000000000000000009B :1095D000000000000000000000000000000000008B :1095E000000000000000000000000000000000007B :1095F000000000000000000000000000000000006B :10960000000000000000000000000000000000005A :10961000000000000000000000000000000000004A :10962000000000000000000000000000000000003A :10963000000000000000000000000000000000002A :10964000000000000000000000000000000000001A :10965000000000000000000000000000000000000A :1096600000000000000000000000000000000000FA :1096700000000000000000000000000000000000EA :1096800000000000000000000000000000000000DA :1096900000000000000000000000000000000000CA :1096A00000000000000000000000000000000000BA :1096B00000000000000000000000000000000000AA :1096C000000000000000000000000000000000009A :1096D000000000000000000000000000000000008A :1096E000000000000000000000000000000000007A :1096F000000000000000000000000000000000006A :109700000000000000000000000000000000000059 :109710000000000000000000000000000000000049 :109720000000000000000000000000000000000039 :109730000000000000000000000000000000000029 :109740000000000000000000000000000000000019 :109750000000000000000000000000000000000009 :1097600000000000000000000000000000000000F9 :1097700000000000000000000000000000000000E9 :1097800000000000000000000000000000000000D9 :1097900000000000000000000000000000000000C9 :1097A00000000000000000000000000000000000B9 :1097B00000000000000000000000000000000000A9 :1097C0000000000000000000000000000000000099 :1097D0000000000000000000000000000000000089 :1097E0000000000000000000000000000000000079 :1097F0000000000000000000000000000000000069 :109800000000000000000000000000000000000058 :109810000000000000000000000000000000000048 :109820000000000000000000000000000000000038 :109830000000000000000000000000000000000028 :109840000000000000000000000000000000000018 :109850000000000000000000000000000000000008 :1098600000000000000000000000000000000000F8 :1098700000000000000000000000000000000000E8 :1098800000000000000000000000000000000000D8 :1098900000000000000000000000000000000000C8 :1098A00000000000000000000000000000000000B8 :1098B00000000000000000000000000000000000A8 :1098C0000000000000000000000000000000000098 :1098D0000000000000000000000000000000000088 :1098E0000000000000000000000000000000000078 :1098F0000000000000000000000000000000000068 :109900000000000000000000000000000000000057 :109910000000000000000000000000000000000047 :109920000000000000000000000000000000000037 :109930000000000000000000000000000000000027 :109940000000000000000000000000000000000017 :109950000000000000000000000000000000000007 :1099600000000000000000000000000000000000F7 :1099700000000000000000000000000000000000E7 :1099800000000000000000000000000000000000D7 :1099900000000000000000000000000000000000C7 :1099A00000000000000000000000000000000000B7 :1099B00000000000000000000000000000000000A7 :1099C0000000000000000000000000000000000097 :1099D0000000000000000000000000000000000087 :1099E0000000000000000000000000000000000077 :1099F0000000000000000000000000000000000067 :109A00000000000000000000000000000000000056 :109A10000000000000000000000000000000000046 :109A20000000000000000000000000000000000036 :109A30000000000000000000000000000000000026 :109A40000000000000000000000000000000000016 :109A50000000000000000000000000000000000006 :109A600000000000000000000000000000000000F6 :109A700000000000000000000000000000000000E6 :109A800000000000000000000000000000000000D6 :109A900000000000000000000000000000000000C6 :109AA00000000000000000000000000000000000B6 :109AB00000000000000000000000000000000000A6 :109AC0000000000000000000000000000000000096 :109AD0000000000000000000000000000000000086 :109AE0000000000000000000000000000000000076 :109AF0000000000000000000000000000000000066 :109B00000000000000000000000000000000000055 :109B10000000000000000000000000000000000045 :109B20000000000000000000000000000000000035 :109B30000000000000000000000000000000000025 :109B40000000000000000000000000000000000015 :109B50000000000000000000000000000000000005 :109B600000000000000000000000000000000000F5 :109B700000000000000000000000000000000000E5 :109B800000000000000000000000000000000000D5 :109B900000000000000000000000000000000000C5 :109BA00000000000000000000000000000000000B5 :109BB00000000000000000000000000000000000A5 :109BC0000000000000000000000000000000000095 :109BD0000000000000000000000000000000000085 :109BE0000000000000000000000000000000000075 :109BF0000000000000000000000000000000000065 :109C00000000000000000000000000000000000054 :109C10000000000000000000000000000000000044 :109C20000000000000000000000000000000000034 :109C30000000000000000000000000000000000024 :109C40000000000000000000000000000000000014 :109C50000000000000000000000000000000000004 :109C600000000000000000000000000000000000F4 :109C700000000000000000000000000000000000E4 :109C800000000000000000000000000000000000D4 :109C900000000000000000000000000000000000C4 :109CA00000000000000000000000000000000000B4 :109CB00000000000000000000000000000000000A4 :109CC0000000000000000000000000000000000094 :109CD0000000000000000000000000000000000084 :109CE0000000000000000000000000000000000074 :109CF0000000000000000000000000000000000064 :109D00000000000000000000000000000000000053 :109D10000000000000000000000000000000000043 :109D20000000000000000000000000000000000033 :109D30000000000000000000000000000000000023 :109D40000000000000000000000000000000000013 :109D50000000000000000000000000000000000003 :109D600000000000000000000000000000000000F3 :109D700000000000000000000000000000000000E3 :109D800000000000000000000000000000000000D3 :109D900000000000000000000000000000000000C3 :109DA00000000000000000000000000000000000B3 :109DB00000000000000000000000000000000000A3 :109DC0000000000000000000000000000000000093 :109DD0000000000000000000000000000000000083 :109DE0000000000000000000000000000000000073 :109DF0000000000000000000000000000000000063 :109E00000000000000000000000000000000000052 :109E10000000000000000000000000000000000042 :109E20000000000000000000000000000000000032 :109E30000000000000000000000000000000000022 :109E40000000000000000000000000000000000012 :109E50000000000000000000000000000000000002 :109E600000000000000000000000000000000000F2 :109E700000000000000000000000000000000000E2 :109E800000000000000000000000000000000000D2 :109E900000000000000000000000000000000000C2 :109EA00000000000000000000000000000000000B2 :109EB00000000000000000000000000000000000A2 :109EC0000000000000000000000000000000000092 :109ED0000000000000000000000000000000000082 :109EE0000000000000000000000000000000000072 :109EF0000000000000000000000000000000000062 :109F00000000000000000000000000000000000051 :109F10000000000000000000000000000000000041 :109F20000000000000000000000000000000000031 :109F30000000000000000000000000000000000021 :109F40000000000000000000000000000000000011 :109F50000000000000000000000000000000000001 :109F600000000000000000000000000000000000F1 :109F700000000000000000000000000000000000E1 :109F800000000000000000000000000000000000D1 :109F900000000000000000000000000000000000C1 :109FA00000000000000000000000000000000000B1 :109FB00000000000000000000000000000000000A1 :109FC0000000000000000000000000000000000091 :109FD0000000000000000000000000000000000081 :109FE0000000000000000000000000000000000071 :109FF0000000000000000000000000000000000061 :10A000000000000000000000000000000000000050 :10A010000000000000000000000000000000000040 :10A020000000000000000000000000000000000030 :10A030000000000000000000000000000000000020 :10A040000000000000000000000000000000000010 :10A050000000000000000000000000000000000000 :10A0600000000000000000000000000000000000F0 :10A0700000000000000000000000000000000000E0 :10A0800000000000000000000000000000000000D0 :10A0900000000000000000000000000000000000C0 :10A0A00000000000000000000000000000000000B0 :10A0B00000000000000000000000000000000000A0 :10A0C0000000000000000000000000000000000090 :10A0D0000000000000000000000000000000000080 :10A0E0000000000000000000000000000000000070 :10A0F0000000000000000000000000000000000060 :10A10000000000000000000000000000000000004F :10A11000000000000000000000000000000000003F :10A12000000000000000000000000000000000002F :10A13000000000000000000000000000000000001F :10A14000000000000000000000000000000000000F :10A1500000000000000000000000000000000000FF :10A1600000000000000000000000000000000000EF :10A1700000000000000000000000000000000000DF :10A1800000000000000000000000000000000000CF :10A1900000000000000000000000000000000000BF :10A1A00000000000000000000000000000000000AF :10A1B000000000000000000000000000000000009F :10A1C000000000000000000000000000000000008F :10A1D000000000000000000000000000000000007F :10A1E000000000000000000000000000000000006F :10A1F000000000000000000000000000000000005F :10A20000000000000000000000000000000000004E :10A21000000000000000000000000000000000003E :10A22000000000000000000000000000000000002E :10A23000000000000000000000000000000000001E :10A24000000000000000000000000000000000000E :10A2500000000000000000000000000000000000FE :10A2600000000000000000000000000000000000EE :10A2700000000000000000000000000000000000DE :10A2800000000000000000000000000000000000CE :10A2900000000000000000000000000000000000BE :10A2A00000000000000000000000000000000000AE :10A2B000000000000000000000000000000000009E :10A2C000000000000000000000000000000000008E :10A2D000000000000000000000000000000000007E :10A2E000000000000000000000000000000000006E :10A2F000000000000000000000000000000000005E :10A30000000000000000000000000000000000004D :10A31000000000000000000000000000000000003D :10A32000000000000000000000000000000000002D :10A33000000000000000000000000000000000001D :10A34000000000000000000000000000000000000D :10A3500000000000000000000000000000000000FD :10A3600000000000000000000000000000000000ED :10A3700000000000000000000000000000000000DD :10A3800000000000000000000000000000000000CD :10A3900000000000000000000000000000000000BD :10A3A00000000000000000000000000000000000AD :10A3B000000000000000000000000000000000009D :10A3C000000000000000000000000000000000008D :10A3D000000000000000000000000000000000007D :10A3E000000000000000000000000000000000006D :10A3F000000000000000000000000000000000005D :10A40000000000000000000000000000000000004C :10A41000000000000000000000000000000000003C :10A42000000000000000000000000000000000002C :10A43000000000000000000000000000000000001C :10A44000000000000000000000000000000000000C :10A4500000000000000000000000000000000000FC :10A4600000000000000000000000000000000000EC :10A4700000000000000000000000000000000000DC :10A4800000000000000000000000000000000000CC :10A4900000000000000000000000000000000000BC :10A4A00000000000000000000000000000000000AC :10A4B000000000000000000000000000000000009C :10A4C000000000000000000000000000000000008C :10A4D000000000000000000000000000000000007C :10A4E000000000000000000000000000000000006C :10A4F000000000000000000000000000000000005C :10A50000000000000000000000000000000000004B :10A51000000000000000000000000000000000003B :10A52000000000000000000000000000000000002B :10A53000000000000000000000000000000000001B :10A54000000000000000000000000000000000000B :10A5500000000000000000000000000000000000FB :10A5600000000000000000000000000000000000EB :10A5700000000000000000000000000000000000DB :10A5800000000000000000000000000000000000CB :10A5900000000000000000000000000000000000BB :10A5A00000000000000000000000000000000000AB :10A5B000000000000000000000000000000000009B :10A5C000000000000000000000000000000000008B :10A5D000000000000000000000000000000000007B :10A5E000000000000000000000000000000000006B :10A5F000000000000000000000000000000000005B :10A60000000000000000000000000000000000004A :10A61000000000000000000000000000000000003A :10A62000000000000000000000000000000000002A :10A63000000000000000000000000000000000001A :10A64000000000000000000000000000000000000A :10A6500000000000000000000000000000000000FA :10A6600000000000000000000000000000000000EA :10A6700000000000000000000000000000000000DA :10A6800000000000000000000000000000000000CA :10A6900000000000000000000000000000000000BA :10A6A00000000000000000000000000000000000AA :10A6B000000000000000000000000000000000009A :10A6C000000000000000000000000000000000008A :10A6D000000000000000000000000000000000007A :10A6E000000000000000000000000000000000006A :10A6F000000000000000000000000000000000005A :10A700000000000000000000000000000000000049 :10A710000000000000000000000000000000000039 :10A720000000000000000000000000000000000029 :10A730000000000000000000000000000000000019 :10A740000000000000000000000000000000000009 :10A7500000000000000000000000000000000000F9 :10A7600000000000000000000000000000000000E9 :10A7700000000000000000000000000000000000D9 :10A7800000000000000000000000000000000000C9 :10A7900000000000000000000000000000000000B9 :10A7A00000000000000000000000000000000000A9 :10A7B0000000000000000000000000000000000099 :10A7C0000000000000000000000000000000000089 :10A7D0000000000000000000000000000000000079 :10A7E0000000000000000000000000000000000069 :10A7F0000000000000000000000000000000000059 :10A800000000000000000000000000000000000048 :10A810000000000000000000000000000000000038 :10A820000000000000000000000000000000000028 :10A830000000000000000000000000000000000018 :10A840000000000000000000000000000000000008 :10A8500000000000000000000000000000000000F8 :10A8600000000000000000000000000000000000E8 :10A8700000000000000000000000000000000000D8 :10A8800000000000000000000000000000000000C8 :10A8900000000000000000000000000000000000B8 :10A8A00000000000000000000000000000000000A8 :10A8B0000000000000000000000000000000000098 :10A8C0000000000000000000000000000000000088 :10A8D0000000000000000000000000000000000078 :10A8E0000000000000000000000000000000000068 :10A8F0000000000000000000000000000000000058 :10A900000000000000000000000000000000000047 :10A910000000000000000000000000000000000037 :10A920000000000000000000000000000000000027 :10A930000000000000000000000000000000000017 :10A940000000000000000000000000000000000007 :10A9500000000000000000000000000000000000F7 :10A9600000000000000000000000000000000000E7 :10A9700000000000000000000000000000000000D7 :10A9800000000000000000000000000000000000C7 :10A9900000000000000000000000000000000000B7 :10A9A00000000000000000000000000000000000A7 :10A9B0000000000000000000000000000000000097 :10A9C0000000000000000000000000000000000087 :10A9D0000000000000000000000000000000000077 :10A9E0000000000000000000000000000000000067 :10A9F0000000000000000000000000000000000057 :10AA00000000000000000000000000000000000046 :10AA10000000000000000000000000000000000036 :10AA20000000000000000000000000000000000026 :10AA30000000000000000000000000000000000016 :10AA40000000000000000000000000000000000006 :10AA500000000000000000000000000000000000F6 :10AA600000000000000000000000000000000000E6 :10AA700000000000000000000000000000000000D6 :10AA800000000000000000000000000000000000C6 :10AA900000000000000000000000000000000000B6 :10AAA00000000000000000000000000000000000A6 :10AAB0000000000000000000000000000000000096 :10AAC0000000000000000000000000000000000086 :10AAD0000000000000000000000000000000000076 :10AAE0000000000000000000000000000000000066 :10AAF0000000000000000000000000000000000056 :10AB00000000000000000000000000000000000045 :10AB10000000000000000000000000000000000035 :10AB20000000000000000000000000000000000025 :10AB30000000000000000000000000000000000015 :10AB40000000000000000000000000000000000005 :10AB500000000000000000000000000000000000F5 :10AB600000000000000000000000000000000000E5 :10AB700000000000000000000000000000000000D5 :10AB800000000000000000000000000000000000C5 :10AB900000000000000000000000000000000000B5 :10ABA00000000000000000000000000000000000A5 :10ABB0000000000000000000000000000000000095 :10ABC0000000000000000000000000000000000085 :10ABD0000000000000000000000000000000000075 :10ABE0000000000000000000000000000000000065 :10ABF0000000000000000000000000000000000055 :10AC00000000000000000000000000000000000044 :10AC10000000000000000000000000000000000034 :10AC20000000000000000000000000000000000024 :10AC30000000000000000000000000000000000014 :10AC40000000000000000000000000000000000004 :10AC500000000000000000000000000000000000F4 :10AC600000000000000000000000000000000000E4 :10AC700000000000000000000000000000000000D4 :10AC800000000000000000000000000000000000C4 :10AC900000000000000000000000000000000000B4 :10ACA00000000000000000000000000000000000A4 :10ACB0000000000000000000000000000000000094 :10ACC0000000000000000000000000000000000084 :10ACD0000000000000000000000000000000000074 :10ACE0000000000000000000000000000000000064 :10ACF0000000000000000000000000000000000054 :10AD00000000000000000000000000000000000043 :10AD10000000000000000000000000000000000033 :10AD20000000000000000000000000000000000023 :10AD30000000000000000000000000000000000013 :10AD40000000000000000000000000000000000003 :10AD500000000000000000000000000000000000F3 :10AD600000000000000000000000000000000000E3 :10AD700000000000000000000000000000000000D3 :10AD800000000000000000000000000000000000C3 :10AD900000000000000000000000000000000000B3 :10ADA00000000000000000000000000000000000A3 :10ADB0000000000000000000000000000000000093 :10ADC0000000000000000000000000000000000083 :10ADD0000000000000000000000000000000000073 :10ADE0000000000000000000000000000000000063 :10ADF0000000000000000000000000000000000053 :10AE00000000000000000000000000000000000042 :10AE10000000000000000000000000000000000032 :10AE20000000000000000000000000000000000022 :10AE30000000000000000000000000000000000012 :10AE40000000000000000000000000000000000002 :10AE500000000000000000000000000000000000F2 :10AE600000000000000000000000000000000000E2 :10AE700000000000000000000000000000000000D2 :10AE800000000000000000000000000000000000C2 :10AE900000000000000000000000000000000000B2 :10AEA00000000000000000000000000000000000A2 :10AEB0000000000000000000000000000000000092 :10AEC0000000000000000000000000000000000082 :10AED0000000000000000000000000000000000072 :10AEE0000000000000000000000000000000000062 :10AEF0000000000000000000000000000000000052 :10AF00000000000000000000000000000000000041 :10AF10000000000000000000000000000000000031 :10AF20000000000000000000000000000000000021 :10AF30000000000000000000000000000000000011 :10AF40000000000000000000000000000000000001 :10AF500000000000000000000000000000000000F1 :10AF600000000000000000000000000000000000E1 :10AF700000000000000000000000000000000000D1 :10AF800000000000000000000000000000000000C1 :10AF900000000000000000000000000000000000B1 :10AFA00000000000000000000000000000000000A1 :10AFB0000000000000000000000000000000000091 :10AFC0000000000000000000000000000000000081 :10AFD0000000000000000000000000000000000071 :10AFE0000000000000000000000000000000000061 :10AFF0000000000000000000000000000000000051 :10B000000000000000000000000000000000000040 :10B010000000000000000000000000000000000030 :10B020000000000000000000000000000000000020 :10B030000000000000000000000000000000000010 :10B040000000000000000000000000000000000000 :10B0500000000000000000000000000000000000F0 :10B0600000000000000000000000000000000000E0 :10B0700000000000000000000000000000000000D0 :10B0800000000000000000000000000000000000C0 :10B0900000000000000000000000000000000000B0 :10B0A00000000000000000000000000000000000A0 :10B0B0000000000000000000000000000000000090 :10B0C0000000000000000000000000000000000080 :10B0D0000000000000000000000000000000000070 :10B0E0000000000000000000000000000000000060 :10B0F0000000000000000000000000000000000050 :10B10000000000000000000000000000000000003F :10B11000000000000000000000000000000000002F :10B12000000000000000000000000000000000001F :10B13000000000000000000000000000000000000F :10B1400000000000000000000000000000000000FF :10B1500000000000000000000000000000000000EF :10B1600000000000000000000000000000000000DF :10B1700000000000000000000000000000000000CF :10B1800000000000000000000000000000000000BF :10B1900000000000000000000000000000000000AF :10B1A000000000000000000000000000000000009F :10B1B000000000000000000000000000000000008F :10B1C000000000000000000000000000000000007F :10B1D000000000000000000000000000000000006F :10B1E000000000000000000000000000000000005F :10B1F000000000000000000000000000000000004F :10B20000000000000000000000000000000000003E :10B21000000000000000000000000000000000002E :10B22000000000000000000000000000000000001E :10B23000000000000000000000000000000000000E :10B2400000000000000000000000000000000000FE :10B2500000000000000000000000000000000000EE :10B2600000000000000000000000000000000000DE :10B2700000000000000000000000000000000000CE :10B2800000000000000000000000000000000000BE :10B2900000000000000000000000000000000000AE :10B2A000000000000000000000000000000000009E :10B2B000000000000000000000000000000000008E :10B2C000000000000000000000000000000000007E :10B2D000000000000000000000000000000000006E :10B2E000000000000000000000000000000000005E :10B2F000000000000000000000000000000000004E :10B30000000000000000000000000000000000003D :10B31000000000000000000000000000000000002D :10B32000000000000000000000000000000000001D :10B33000000000000000000000000000000000000D :10B3400000000000000000000000000000000000FD :10B3500000000000000000000000000000000000ED :10B3600000000000000000000000000000000000DD :10B3700000000000000000000000000000000000CD :10B3800000000000000000000000000000000000BD :10B3900000000000000000000000000000000000AD :10B3A000000000000000000000000000000000009D :10B3B000000000000000000000000000000000008D :10B3C000000000000000000000000000000000007D :10B3D000000000000000000000000000000000006D :10B3E000000000000000000000000000000000005D :10B3F000000000000000000000000000000000004D :10B40000000000000000000000000000000000003C :10B41000000000000000000000000000000000002C :10B42000000000000000000000000000000000001C :10B43000000000000000000000000000000000000C :10B4400000000000000000000000000000000000FC :10B4500000000000000000000000000000000000EC :10B4600000000000000000000000000000000000DC :10B4700000000000000000000000000000000000CC :10B4800000000000000000000000000000000000BC :10B4900000000000000000000000000000000000AC :10B4A000000000000000000000000000000000009C :10B4B000000000000000000000000000000000008C :10B4C000000000000000000000000000000000007C :10B4D000000000000000000000000000000000006C :10B4E000000000000000000000000000000000005C :10B4F000000000000000000000000000000000004C :10B50000000000000000000000000000000000003B :10B51000000000000000000000000000000000002B :10B52000000000000000000000000000000000001B :10B53000000000000000000000000000000000000B :10B5400000000000000000000000000000000000FB :10B5500000000000000000000000000000000000EB :10B5600000000000000000000000000000000000DB :10B5700000000000000000000000000000000000CB :10B5800000000000000000000000000000000000BB :10B5900000000000000000000000000000000000AB :10B5A000000000000000000000000000000000009B :10B5B000000000000000000000000000000000008B :10B5C000000000000000000000000000000000007B :10B5D000000000000000000000000000000000006B :10B5E000000000000000000000000000000000005B :10B5F000000000000000000000000000000000004B :10B60000000000000000000000000000000000003A :10B61000000000000000000000000000000000002A :10B62000000000000000000000000000000000001A :10B63000000000000000000000000000000000000A :10B6400000000000000000000000000000000000FA :10B6500000000000000000000000000000000000EA :10B6600000000000000000000000000000000000DA :10B6700000000000000000000000000000000000CA :10B6800000000000000000000000000000000000BA :10B6900000000000000000000000000000000000AA :10B6A000000000000000000000000000000000009A :10B6B000000000000000000000000000000000008A :10B6C000000000000000000000000000000000007A :10B6D000000000000000000000000000000000006A :10B6E000000000000000000000000000000000005A :10B6F000000000000000000000000000000000004A :10B700000000000000000000000000000000000039 :10B710000000000000000000000000000000000029 :10B720000000000000000000000000000000000019 :10B730000000000000000000000000000000000009 :10B7400000000000000000000000000000000000F9 :10B7500000000000000000000000000000000000E9 :10B7600000000000000000000000000000000000D9 :10B7700000000000000000000000000000000000C9 :10B7800000000000000000000000000000000000B9 :10B7900000000000000000000000000000000000A9 :10B7A0000000000000000000000000000000000099 :10B7B0000000000000000000000000000000000089 :10B7C0000000000000000000000000000000000079 :10B7D0000000000000000000000000000000000069 :10B7E0000000000000000000000000000000000059 :10B7F0000000000000000000000000000000000049 :10B800000000000000000000000000000000000038 :10B810000000000000000000000000000000000028 :10B820000000000000000000000000000000000018 :10B830000000000000000000000000000000000008 :10B8400000000000000000000000000000000000F8 :10B8500000000000000000000000000000000000E8 :10B8600000000000000000000000000000000000D8 :10B8700000000000000000000000000000000000C8 :10B8800000000000000000000000000000000000B8 :10B8900000000000000000000000000000000000A8 :10B8A0000000000000000000000000000000000098 :10B8B0000000000000000000000000000000000088 :10B8C0000000000000000000000000000000000078 :10B8D0000000000000000000000000000000000068 :10B8E0000000000000000000000000000000000058 :10B8F0000000000000000000000000000000000048 :10B900000000000000000000000000000000000037 :10B910000000000000000000000000000000000027 :10B920000000000000000000000000000000000017 :10B930000000000000000000000000000000000007 :10B9400000000000000000000000000000000000F7 :10B9500000000000000000000000000000000000E7 :10B9600000000000000000000000000000000000D7 :10B9700000000000000000000000000000000000C7 :10B9800000000000000000000000000000000000B7 :10B9900000000000000000000000000000000000A7 :10B9A0000000000000000000000000000000000097 :10B9B0000000000000000000000000000000000087 :10B9C0000000000000000000000000000000000077 :10B9D0000000000000000000000000000000000067 :10B9E0000000000000000000000000000000000057 :10B9F0000000000000000000000000000000000047 :10BA00000000000000000000000000000000000036 :10BA10000000000000000000000000000000000026 :10BA20000000000000000000000000000000000016 :10BA30000000000000000000000000000000000006 :10BA400000000000000000000000000000000000F6 :10BA500000000000000000000000000000000000E6 :10BA600000000000000000000000000000000000D6 :10BA700000000000000000000000000000000000C6 :10BA800000000000000000000000000000000000B6 :10BA900000000000000000000000000000000000A6 :10BAA0000000000000000000000000000000000096 :10BAB0000000000000000000000000000000000086 :10BAC0000000000000000000000000000000000076 :10BAD0000000000000000000000000000000000066 :10BAE0000000000000000000000000000000000056 :10BAF0000000000000000000000000000000000046 :10BB00000000000000000000000000000000000035 :10BB10000000000000000000000000000000000025 :10BB20000000000000000000000000000000000015 :10BB30000000000000000000000000000000000005 :10BB400000000000000000000000000000000000F5 :10BB500000000000000000000000000000000000E5 :10BB600000000000000000000000000000000000D5 :10BB700000000000000000000000000000000000C5 :10BB800000000000000000000000000000000000B5 :10BB900000000000000000000000000000000000A5 :10BBA0000000000000000000000000000000000095 :10BBB0000000000000000000000000000000000085 :10BBC0000000000000000000000000000000000075 :10BBD0000000000000000000000000000000000065 :10BBE0000000000000000000000000000000000055 :10BBF0000000000000000000000000000000000045 :10BC00000000000000000000000000000000000034 :10BC10000000000000000000000000000000000024 :10BC20000000000000000000000000000000000014 :10BC30000000000000000000000000000000000004 :10BC400000000000000000000000000000000000F4 :10BC500000000000000000000000000000000000E4 :10BC600000000000000000000000000000000000D4 :10BC700000000000000000000000000000000000C4 :10BC800000000000000000000000000000000000B4 :10BC900000000000000000000000000000000000A4 :10BCA0000000000000000000000000000000000094 :10BCB0000000000000000000000000000000000084 :10BCC0000000000000000000000000000000000074 :10BCD0000000000000000000000000000000000064 :10BCE0000000000000000000000000000000000054 :10BCF0000000000000000000000000000000000044 :10BD00000000000000000000000000000000000033 :10BD10000000000000000000000000000000000023 :10BD20000000000000000000000000000000000013 :10BD30000000000000000000000000000000000003 :10BD400000000000000000000000000000000000F3 :10BD500000000000000000000000000000000000E3 :10BD600000000000000000000000000000000000D3 :10BD700000000000000000000000000000000000C3 :10BD800000000000000000000000000000000000B3 :10BD900000000000000000000000000000000000A3 :10BDA0000000000000000000000000000000000093 :10BDB0000000000000000000000000000000000083 :10BDC0000000000000000000000000000000000073 :10BDD0000000000000000000000000000000000063 :10BDE0000000000000000000000000000000000053 :10BDF0000000000000000000000000000000000043 :10BE00000000000000000000000000000000000032 :10BE10000000000000000000000000000000000022 :10BE20000000000000000000000000000000000012 :10BE30000000000000000000000000000000000002 :10BE400000000000000000000000000000000000F2 :10BE500000000000000000000000000000000000E2 :10BE600000000000000000000000000000000000D2 :10BE700000000000000000000000000000000000C2 :10BE800000000000000000000000000000000000B2 :10BE900000000000000000000000000000000000A2 :10BEA0000000000000000000000000000000000092 :10BEB0000000000000000000000000000000000082 :10BEC0000000000000000000000000000000000072 :10BED0000000000000000000000000000000000062 :10BEE0000000000000000000000000000000000052 :10BEF0000000000000000000000000000000000042 :10BF00000000000000000000000000000000000031 :10BF10000000000000000000000000000000000021 :10BF20000000000000000000000000000000000011 :10BF30000000000000000000000000000000000001 :10BF400000000000000000000000000000000000F1 :10BF500000000000000000000000000000000000E1 :10BF600000000000000000000000000000000000D1 :10BF700000000000000000000000000000000000C1 :10BF800000000000000000000000000000000000B1 :10BF900000000000000000000000000000000000A1 :10BFA0000000000000000000000000000000000091 :10BFB0000000000000000000000000000000000081 :10BFC0000000000000000000000000000000000071 :10BFD0000000000000000000000000000000000061 :10BFE0000000000000000000000000000000000051 :10BFF0000000000000000000000000000000000041 :10C000000000000000000000000000000000000030 :10C010000000000000000000000000000000000020 :10C020000000000000000000000000000000000010 :10C030000000000000000000000000000000000000 :10C0400000000000000000000000000000000000F0 :10C0500000000000000000000000000000000000E0 :10C0600000000000000000000000000000000000D0 :10C0700000000000000000000000000000000000C0 :10C0800000000000000000000000000000000000B0 :10C0900000000000000000000000000000000000A0 :10C0A0000000000000000000000000000000000090 :10C0B0000000000000000000000000000000000080 :10C0C0000000000000000000000000000000000070 :10C0D0000000000000000000000000000000000060 :10C0E0000000000000000000000000000000000050 :10C0F0000000000000000000000000000000000040 :10C10000000000000000000000000000000000002F :10C11000000000000000000000000000000000001F :10C12000000000000000000000000000000000000F :10C1300000000000000000000000000000000000FF :10C1400000000000000000000000000000000000EF :10C1500000000000000000000000000000000000DF :10C1600000000000000000000000000000000000CF :10C1700000000000000000000000000000000000BF :10C1800000000000000000000000000000000000AF :10C19000000000000000000000000000000000009F :10C1A000000000000000000000000000000000008F :10C1B000000000000000000000000000000000007F :10C1C000000000000000000000000000000000006F :10C1D000000000000000000000000000000000005F :10C1E000000000000000000000000000000000004F :10C1F000000000000000000000000000000000003F :10C20000000000000000000000000000000000002E :10C21000000000000000000000000000000000001E :10C22000000000000000000000000000000000000E :10C2300000000000000000000000000000000000FE :10C2400000000000000000000000000000000000EE :10C2500000000000000000000000000000000000DE :10C2600000000000000000000000000000000000CE :10C2700000000000000000000000000000000000BE :10C2800000000000000000000000000000000000AE :10C29000000000000000000000000000000000009E :10C2A000000000000000000000000000000000008E :10C2B000000000000000000000000000000000007E :10C2C000000000000000000000000000000000006E :10C2D000000000000000000000000000000000005E :10C2E000000000000000000000000000000000004E :10C2F000000000000000000000000000000000003E :10C30000000000000000000000000000000000002D :10C31000000000000000000000000000000000001D :10C32000000000000000000000000000000000000D :10C3300000000000000000000000000000000000FD :10C3400000000000000000000000000000000000ED :10C3500000000000000000000000000000000000DD :10C3600000000000000000000000000000000000CD :10C3700000000000000000000000000000000000BD :10C3800000000000000000000000000000000000AD :10C39000000000000000000000000000000000009D :10C3A000000000000000000000000000000000008D :10C3B000000000000000000000000000000000007D :10C3C000000000000000000000000000000000006D :10C3D000000000000000000000000000000000005D :10C3E000000000000000000000000000000000004D :10C3F000000000000000000000000000000000003D :10C40000000000000000000000000000000000002C :10C41000000000000000000000000000000000001C :10C42000000000000000000000000000000000000C :10C4300000000000000000000000000000000000FC :10C4400000000000000000000000000000000000EC :10C4500000000000000000000000000000000000DC :10C4600000000000000000000000000000000000CC :10C4700000000000000000000000000000000000BC :10C4800000000000000000000000000000000000AC :10C49000000000000000000000000000000000009C :10C4A000000000000000000000000000000000008C :10C4B000000000000000000000000000000000007C :10C4C000000000000000000000000000000000006C :10C4D000000000000000000000000000000000005C :10C4E000000000000000000000000000000000004C :10C4F000000000000000000000000000000000003C :10C50000000000000000000000000000000000002B :10C51000000000000000000000000000000000001B :10C52000000000000000000000000000000000000B :10C5300000000000000000000000000000000000FB :10C5400000000000000000000000000000000000EB :10C5500000000000000000000000000000000000DB :10C5600000000000000000000000000000000000CB :10C5700000000000000000000000000000000000BB :10C5800000000000000000000000000000000000AB :10C59000000000000000000000000000000000009B :10C5A000000000000000000000000000000000008B :10C5B000000000000000000000000000000000007B :10C5C000000000000000000000000000000000006B :10C5D000000000000000000000000000000000005B :10C5E000000000000000000000000000000000004B :10C5F000000000000000000000000000000000003B :10C60000000000000000000000000000000000002A :10C61000000000000000000000000000000000001A :10C62000000000000000000000000000000000000A :10C6300000000000000000000000000000000000FA :10C6400000000000000000000000000000000000EA :10C6500000000000000000000000000000000000DA :10C6600000000000000000000000000000000000CA :10C6700000000000000000000000000000000000BA :10C6800000000000000000000000000000000000AA :10C69000000000000000000000000000000000009A :10C6A000000000000000000000000000000000008A :10C6B000000000000000000000000000000000007A :10C6C000000000000000000000000000000000006A :10C6D000000000000000000000000000000000005A :10C6E000000000000000000000000000000000004A :10C6F000000000000000000000000000000000003A :10C700000000000000000000000000000000000029 :10C710000000000000000000000000000000000019 :10C720000000000000000000000000000000000009 :10C7300000000000000000000000000000000000F9 :10C7400000000000000000000000000000000000E9 :10C7500000000000000000000000000000000000D9 :10C7600000000000000000000000000000000000C9 :10C7700000000000000000000000000000000000B9 :10C7800000000000000000000000000000000000A9 :10C790000000000000000000000000000000000099 :10C7A0000000000000000000000000000000000089 :10C7B0000000000000000000000000000000000079 :10C7C0000000000000000000000000000000000069 :10C7D0000000000000000000000000000000000059 :10C7E0000000000000000000000000000000000049 :10C7F0000000000000000000000000000000000039 :10C800000000000000000000000000000000000028 :10C810000000000000000000000000000000000018 :10C820000000000000000000000000000000000008 :10C8300000000000000000000000000000000000F8 :10C8400000000000000000000000000000000000E8 :10C8500000000000000000000000000000000000D8 :10C8600000000000000000000000000000000000C8 :10C8700000000000000000000000000000000000B8 :10C8800000000000000000000000000000000000A8 :10C890000000000000000000000000000000000098 :10C8A0000000000000000000000000000000000088 :10C8B0000000000000000000000000000000000078 :10C8C0000000000000000000000000000000000068 :10C8D0000000000000000000000000000000000058 :10C8E0000000000000000000000000000000000048 :10C8F0000000000000000000000000000000000038 :10C900000000000000000000000000000000000027 :10C910000000000000000000000000000000000017 :10C920000000000000000000000000000000000007 :10C9300000000000000000000000000000000000F7 :10C9400000000000000000000000000000000000E7 :10C9500000000000000000000000000000000000D7 :10C9600000000000000000000000000000000000C7 :10C9700000000000000000000000000000000000B7 :10C9800000000000000000000000000000000000A7 :10C990000000000000000000000000000000000097 :10C9A0000000000000000000000000000000000087 :10C9B0000000000000000000000000000000000077 :10C9C0000000000000000000000000000000000067 :10C9D0000000000000000000000000000000000057 :10C9E0000000000000000000000000000000000047 :10C9F0000000000000000000000000000000000037 :10CA00000000000000000000000000000000000026 :10CA10000000000000000000000000000000000016 :10CA20000000000000000000000000000000000006 :10CA300000000000000000000000000000000000F6 :10CA400000000000000000000000000000000000E6 :10CA500000000000000000000000000000000000D6 :10CA600000000000000000000000000000000000C6 :10CA700000000000000000000000000000000000B6 :10CA800000000000000000000000000000000000A6 :10CA90000000000000000000000000000000000096 :10CAA0000000000000000000000000000000000086 :10CAB0000000000000000000000000000000000076 :10CAC0000000000000000000000000000000000066 :10CAD0000000000000000000000000000000000056 :10CAE0000000000000000000000000000000000046 :10CAF0000000000000000000000000000000000036 :10CB00000000000000000000000000000000000025 :10CB10000000000000000000000000000000000015 :10CB20000000000000000000000000000000000005 :10CB300000000000000000000000000000000000F5 :10CB400000000000000000000000000000000000E5 :10CB500000000000000000000000000000000000D5 :10CB600000000000000000000000000000000000C5 :10CB700000000000000000000000000000000000B5 :10CB800000000000000000000000000000000000A5 :10CB90000000000000000000000000000000000095 :10CBA0000000000000000000000000000000000085 :10CBB0000000000000000000000000000000000075 :10CBC0000000000000000000000000000000000065 :10CBD0000000000000000000000000000000000055 :10CBE0000000000000000000000000000000000045 :10CBF0000000000000000000000000000000000035 :10CC00000000000000000000000000000000000024 :10CC10000000000000000000000000000000000014 :10CC20000000000000000000000000000000000004 :10CC300000000000000000000000000000000000F4 :10CC400000000000000000000000000000000000E4 :10CC500000000000000000000000000000000000D4 :10CC600000000000000000000000000000000000C4 :10CC700000000000000000000000000000000000B4 :10CC800000000000000000000000000000000000A4 :10CC90000000000000000000000000000000000094 :10CCA0000000000000000000000000000000000084 :10CCB0000000000000000000000000000000000074 :10CCC0000000000000000000000000000000000064 :10CCD0000000000000000000000000000000000054 :10CCE0000000000000000000000000000000000044 :10CCF0000000000000000000000000000000000034 :10CD00000000000000000000000000000000000023 :10CD10000000000000000000000000000000000013 :10CD20000000000000000000000000000000000003 :10CD300000000000000000000000000000000000F3 :10CD400000000000000000000000000000000000E3 :10CD500000000000000000000000000000000000D3 :10CD600000000000000000000000000000000000C3 :10CD700000000000000000000000000000000000B3 :10CD800000000000000000000000000000000000A3 :10CD90000000000000000000000000000000000093 :10CDA0000000000000000000000000000000000083 :10CDB0000000000000000000000000000000000073 :10CDC0000000000000000000000000000000000063 :10CDD0000000000000000000000000000000000053 :10CDE0000000000000000000000000000000000043 :10CDF0000000000000000000000000000000000033 :10CE00000000000000000000000000000000000022 :10CE10000000000000000000000000000000000012 :10CE20000000000000000000000000000000000002 :10CE300000000000000000000000000000000000F2 :10CE400000000000000000000000000000000000E2 :10CE500000000000000000000000000000000000D2 :10CE600000000000000000000000000000000000C2 :10CE700000000000000000000000000000000000B2 :10CE800000000000000000000000000000000000A2 :10CE90000000000000000000000000000000000092 :10CEA0000000000000000000000000000000000082 :10CEB0000000000000000000000000000000000072 :10CEC0000000000000000000000000000000000062 :10CED0000000000000000000000000000000000052 :10CEE0000000000000000000000000000000000042 :10CEF0000000000000000000000000000000000032 :10CF00000000000000000000000000000000000021 :10CF10000000000000000000000000000000000011 :10CF20000000000000000000000000000000000001 :10CF300000000000000000000000000000000000F1 :10CF400000000000000000000000000000000000E1 :10CF500000000000000000000000000000000000D1 :10CF600000000000000000000000000000000000C1 :10CF700000000000000000000000000000000000B1 :10CF800000000000000000000000000000000000A1 :10CF90000000000000000000000000000000000091 :10CFA0000000000000000000000000000000000081 :10CFB0000000000000000000000000000000000071 :10CFC0000000000000000000000000000000000061 :10CFD0000000000000000000000000000000000051 :10CFE0000000000000000000000000000000000041 :10CFF0000000000000000000000000000000000031 :10D000000000000000000000000000000000000020 :10D010000000000000000000000000000000000010 :10D020000000000000000000000000000000000000 :10D0300000000000000000000000000000000000F0 :10D0400000000000000000000000000000000000E0 :10D0500000000000000000000000000000000000D0 :10D0600000000000000000000000000000000000C0 :10D0700000000000000000000000000000000000B0 :10D0800000000000000000000000000000000000A0 :10D090000000000000000000000000000000000090 :10D0A0000000000000000000000000000000000080 :10D0B0000000000000000000000000000000000070 :10D0C0000000000000000000000000000000000060 :10D0D0000000000000000000000000000000000050 :10D0E0000000000000000000000000000000000040 :10D0F0000000000000000000000000000000000030 :10D10000000000000000000000000000000000001F :10D11000000000000000000000000000000000000F :10D1200000000000000000000000000000000000FF :10D1300000000000000000000000000000000000EF :10D1400000000000000000000000000000000000DF :10D1500000000000000000000000000000000000CF :10D1600000000000000000000000000000000000BF :10D1700000000000000000000000000000000000AF :10D18000000000000000000000000000000000009F :10D19000000000000000000000000000000000008F :10D1A000000000000000000000000000000000007F :10D1B000000000000000000000000000000000006F :10D1C000000000000000000000000000000000005F :10D1D000000000000000000000000000000000004F :10D1E000000000000000000000000000000000003F :10D1F000000000000000000000000000000000002F :10D20000000000000000000000000000000000001E :10D21000000000000000000000000000000000000E :10D2200000000000000000000000000000000000FE :10D2300000000000000000000000000000000000EE :10D2400000000000000000000000000000000000DE :10D2500000000000000000000000000000000000CE :10D2600000000000000000000000000000000000BE :10D2700000000000000000000000000000000000AE :10D28000000000000000000000000000000000009E :10D29000000000000000000000000000000000008E :10D2A000000000000000000000000000000000007E :10D2B000000000000000000000000000000000006E :10D2C000000000000000000000000000000000005E :10D2D000000000000000000000000000000000004E :10D2E000000000000000000000000000000000003E :10D2F000000000000000000000000000000000002E :10D30000000000000000000000000000000000001D :10D31000000000000000000000000000000000000D :10D3200000000000000000000000000000000000FD :10D3300000000000000000000000000000000000ED :10D3400000000000000000000000000000000000DD :10D3500000000000000000000000000000000000CD :10D3600000000000000000000000000000000000BD :10D3700000000000000000000000000000000000AD :10D38000000000000000000000000000000000009D :10D39000000000000000000000000000000000008D :10D3A000000000000000000000000000000000007D :10D3B000000000000000000000000000000000006D :10D3C000000000000000000000000000000000005D :10D3D000000000000000000000000000000000004D :10D3E000000000000000000000000000000000003D :10D3F000000000000000000000000000000000002D :10D40000000000000000000000000000000000001C :10D41000000000000000000000000000000000000C :10D4200000000000000000000000000000000000FC :10D4300000000000000000000000000000000000EC :10D4400000000000000000000000000000000000DC :10D4500000000000000000000000000000000000CC :10D4600000000000000000000000000000000000BC :10D4700000000000000000000000000000000000AC :10D48000000000000000000000000000000000009C :10D49000000000000000000000000000000000008C :10D4A000000000000000000000000000000000007C :10D4B000000000000000000000000000000000006C :10D4C000000000000000000000000000000000005C :10D4D000000000000000000000000000000000004C :10D4E000000000000000000000000000000000003C :10D4F000000000000000000000000000000000002C :10D50000000000000000000000000000000000001B :10D51000000000000000000000000000000000000B :10D5200000000000000000000000000000000000FB :10D5300000000000000000000000000000000000EB :10D5400000000000000000000000000000000000DB :10D5500000000000000000000000000000000000CB :10D5600000000000000000000000000000000000BB :10D5700000000000000000000000000000000000AB :10D58000000000000000000000000000000000009B :10D59000000000000000000000000000000000008B :10D5A000000000000000000000000000000000007B :10D5B000000000000000000000000000000000006B :10D5C000000000000000000000000000000000005B :10D5D000000000000000000000000000000000004B :10D5E000000000000000000000000000000000003B :10D5F000000000000000000000000000000000002B :10D60000000000000000000000000000000000001A :10D61000000000000000000000000000000000000A :10D6200000000000000000000000000000000000FA :10D6300000000000000000000000000000000000EA :10D6400000000000000000000000000000000000DA :10D6500000000000000000000000000000000000CA :10D6600000000000000000000000000000000000BA :10D6700000000000000000000000000000000000AA :10D68000000000000000000000000000000000009A :10D69000000000000000000000000000000000008A :10D6A000000000000000000000000000000000007A :10D6B000000000000000000000000000000000006A :10D6C000000000000000000000000000000000005A :10D6D000000000000000000000000000000000004A :10D6E000000000000000000000000000000000003A :10D6F000000000000000000000000000000000002A :10D700000000000000000000000000000000000019 :10D710000000000000000000000000000000000009 :10D7200000000000000000000000000000000000F9 :10D7300000000000000000000000000000000000E9 :10D7400000000000000000000000000000000000D9 :10D7500000000000000000000000000000000000C9 :10D7600000000000000000000000000000000000B9 :10D7700000000000000000000000000000000000A9 :10D780000000000000000000000000000000000099 :10D790000000000000000000000000000000000089 :10D7A0000000000000000000000000000000000079 :10D7B0000000000000000000000000000000000069 :10D7C0000000000000000000000000000000000059 :10D7D0000000000000000000000000000000000049 :10D7E0000000000000000000000000000000000039 :10D7F0000000000000000000000000000000000029 :10D800000000000000000000000000000000000018 :10D810000000000000000000000000000000000008 :10D8200000000000000000000000000000000000F8 :10D8300000000000000000000000000000000000E8 :10D8400000000000000000000000000000000000D8 :10D8500000000000000000000000000000000000C8 :10D8600000000000000000000000000000000000B8 :10D8700000000000000000000000000000000000A8 :10D880000000000000000000000000000000000098 :10D890000000000000000000000000000000000088 :10D8A0000000000000000000000000000000000078 :10D8B0000000000000000000000000000000000068 :10D8C0000000000000000000000000000000000058 :10D8D0000000000000000000000000000000000048 :10D8E0000000000000000000000000000000000038 :10D8F0000000000000000000000000000000000028 :10D900000000000000000000000000000000000017 :10D910000000000000000000000000000000000007 :10D9200000000000000000000000000000000000F7 :10D9300000000000000000000000000000000000E7 :10D9400000000000000000000000000000000000D7 :10D9500000000000000000000000000000000000C7 :10D9600000000000000000000000000000000000B7 :10D9700000000000000000000000000000000000A7 :10D980000000000000000000000000000000000097 :10D990000000000000000000000000000000000087 :10D9A0000000000000000000000000000000000077 :10D9B0000000000000000000000000000000000067 :10D9C0000000000000000000000000000000000057 :10D9D0000000000000000000000000000000000047 :10D9E0000000000000000000000000000000000037 :10D9F0000000000000000000000000000000000027 :10DA00000000000000000000000000000000000016 :10DA10000000000000000000000000000000000006 :10DA200000000000000000000000000000000000F6 :10DA300000000000000000000000000000000000E6 :10DA400000000000000000000000000000000000D6 :10DA500000000000000000000000000000000000C6 :10DA600000000000000000000000000000000000B6 :10DA700000000000000000000000000000000000A6 :10DA80000000000000000000000000000000000096 :10DA90000000000000000000000000000000000086 :10DAA0000000000000000000000000000000000076 :10DAB0000000000000000000000000000000000066 :10DAC0000000000000000000000000000000000056 :10DAD0000000000000000000000000000000000046 :10DAE0000000000000000000000000000000000036 :10DAF0000000000000000000000000000000000026 :10DB00000000000000000000000000000000000015 :10DB10000000000000000000000000000000000005 :10DB200000000000000000000000000000000000F5 :10DB300000000000000000000000000000000000E5 :10DB400000000000000000000000000000000000D5 :10DB500000000000000000000000000000000000C5 :10DB600000000000000000000000000000000000B5 :10DB700000000000000000000000000000000000A5 :10DB80000000000000000000000000000000000095 :10DB90000000000000000000000000000000000085 :10DBA0000000000000000000000000000000000075 :10DBB0000000000000000000000000000000000065 :10DBC0000000000000000000000000000000000055 :10DBD0000000000000000000000000000000000045 :10DBE0000000000000000000000000000000000035 :10DBF0000000000000000000000000000000000025 :10DC00000000000000000000000000000000000014 :10DC10000000000000000000000000000000000004 :10DC200000000000000000000000000000000000F4 :10DC300000000000000000000000000000000000E4 :10DC400000000000000000000000000000000000D4 :10DC500000000000000000000000000000000000C4 :10DC600000000000000000000000000000000000B4 :10DC700000000000000000000000000000000000A4 :10DC80000000000000000000000000000000000094 :10DC90000000000000000000000000000000000084 :10DCA0000000000000000000000000000000000074 :10DCB0000000000000000000000000000000000064 :10DCC0000000000000000000000000000000000054 :10DCD0000000000000000000000000000000000044 :10DCE0000000000000000000000000000000000034 :10DCF0000000000000000000000000000000000024 :10DD00000000000000000000000000000000000013 :10DD10000000000000000000000000000000000003 :10DD200000000000000000000000000000000000F3 :10DD300000000000000000000000000000000000E3 :10DD400000000000000000000000000000000000D3 :10DD500000000000000000000000000000000000C3 :10DD600000000000000000000000000000000000B3 :10DD700000000000000000000000000000000000A3 :10DD80000000000000000000000000000000000093 :10DD90000000000000000000000000000000000083 :10DDA0000000000000000000000000000000000073 :10DDB0000000000000000000000000000000000063 :10DDC0000000000000000000000000000000000053 :10DDD0000000000000000000000000000000000043 :10DDE0000000000000000000000000000000000033 :10DDF0000000000000000000000000000000000023 :10DE00000000000000000000000000000000000012 :10DE10000000000000000000000000000000000002 :10DE200000000000000000000000000000000000F2 :10DE300000000000000000000000000000000000E2 :10DE400000000000000000000000000000000000D2 :10DE500000000000000000000000000000000000C2 :10DE600000000000000000000000000000000000B2 :10DE700000000000000000000000000000000000A2 :10DE80000000000000000000000000000000000092 :10DE90000000000000000000000000000000000082 :10DEA0000000000000000000000000000000000072 :10DEB0000000000000000000000000000000000062 :10DEC0000000000000000000000000000000000052 :10DED0000000000000000000000000000000000042 :10DEE0000000000000000000000000000000000032 :10DEF0000000000000000000000000000000000022 :10DF00000000000000000000000000000000000011 :10DF10000000000000000000000000000000000001 :10DF200000000000000000000000000000000000F1 :10DF300000000000000000000000000000000000E1 :10DF400000000000000000000000000000000000D1 :10DF500000000000000000000000000000000000C1 :10DF600000000000000000000000000000000000B1 :10DF700000000000000000000000000000000000A1 :10DF80000000000000000000000000000000000091 :10DF90000000000000000000000000000000000081 :10DFA0000000000000000000000000000000000071 :10DFB0000000000000000000000000000000000061 :10DFC0000000000000000000000000000000000051 :10DFD0000000000000000000000000000000000041 :10DFE0000000000000000000000000000000000031 :10DFF0000000000000000000000000000000000021 :10E000000000000000000000000000000000000010 :10E010000000000000000000000000000000000000 :10E0200000000000000000000000000000000000F0 :10E0300000000000000000000000000000000000E0 :10E0400000000000000000000000000000000000D0 :10E0500000000000000000000000000000000000C0 :10E0600000000000000000000000000000000000B0 :10E0700000000000000000000000000000000000A0 :10E080000000000000000000000000000000000090 :10E090000000000000000000000000000000000080 :10E0A0000000000000000000000000000000000070 :10E0B0000000000000000000000000000000000060 :10E0C0000000000000000000000000000000000050 :10E0D0000000000000000000000000000000000040 :10E0E0000000000000000000000000000000000030 :10E0F0000000000000000000000000000000000020 :10E10000000000000000000000000000000000000F :10E1100000000000000000000000000000000000FF :10E1200000000000000000000000000000000000EF :10E1300000000000000000000000000000000000DF :10E1400000000000000000000000000000000000CF :10E1500000000000000000000000000000000000BF :10E1600000000000000000000000000000000000AF :10E17000000000000000000000000000000000009F :10E18000000000000000000000000000000000008F :10E19000000000000000000000000000000000007F :10E1A000000000000000000000000000000000006F :10E1B000000000000000000000000000000000005F :10E1C000000000000000000000000000000000004F :10E1D000000000000000000000000000000000003F :10E1E000000000000000000000000000000000002F :10E1F000000000000000000000000000000000001F :10E20000000000000000000000000000000000000E :10E2100000000000000000000000000000000000FE :10E2200000000000000000000000000000000000EE :10E2300000000000000000000000000000000000DE :10E2400000000000000000000000000000000000CE :10E2500000000000000000000000000000000000BE :10E2600000000000000000000000000000000000AE :10E27000000000000000000000000000000000009E :10E28000000000000000000000000000000000008E :10E29000000000000000000000000000000000007E :10E2A000000000000000000000000000000000006E :10E2B000000000000000000000000000000000005E :10E2C000000000000000000000000000000000004E :10E2D000000000000000000000000000000000003E :10E2E000000000000000000000000000000000002E :10E2F000000000000000000000000000000000001E :10E30000000000000000000000000000000000000D :10E3100000000000000000000000000000000000FD :10E3200000000000000000000000000000000000ED :10E3300000000000000000000000000000000000DD :10E3400000000000000000000000000000000000CD :10E3500000000000000000000000000000000000BD :10E3600000000000000000000000000000000000AD :10E37000000000000000000000000000000000009D :10E38000000000000000000000000000000000008D :10E39000000000000000000000000000000000007D :10E3A000000000000000000000000000000000006D :10E3B000000000000000000000000000000000005D :10E3C000000000000000000000000000000000004D :10E3D000000000000000000000000000000000003D :10E3E000000000000000000000000000000000002D :10E3F000000000000000000000000000000000001D :10E40000000000000000000000000000000000000C :10E4100000000000000000000000000000000000FC :10E4200000000000000000000000000000000000EC :10E4300000000000000000000000000000000000DC :10E4400000000000000000000000000000000000CC :10E4500000000000000000000000000000000000BC :10E4600000000000000000000000000000000000AC :10E47000000000000000000000000000000000009C :10E48000000000000000000000000000000000008C :10E49000000000000000000000000000000000007C :10E4A000000000000000000000000000000000006C :10E4B000000000000000000000000000000000005C :10E4C000000000000000000000000000000000004C :10E4D000000000000000000000000000000000003C :10E4E000000000000000000000000000000000002C :10E4F000000000000000000000000000000000001C :10E50000000000000000000000000000000000000B :10E5100000000000000000000000000000000000FB :10E5200000000000000000000000000000000000EB :10E5300000000000000000000000000000000000DB :10E5400000000000000000000000000000000000CB :10E5500000000000000000000000000000000000BB :10E5600000000000000000000000000000000000AB :10E57000000000000000000000000000000000009B :10E58000000000000000000000000000000000008B :10E59000000000000000000000000000000000007B :10E5A000000000000000000000000000000000006B :10E5B000000000000000000000000000000000005B :10E5C000000000000000000000000000000000004B :10E5D000000000000000000000000000000000003B :10E5E000000000000000000000000000000000002B :10E5F000000000000000000000000000000000001B :10E60000000000000000000000000000000000000A :10E6100000000000000000000000000000000000FA :10E6200000000000000000000000000000000000EA :10E6300000000000000000000000000000000000DA :10E6400000000000000000000000000000000000CA :10E6500000000000000000000000000000000000BA :10E6600000000000000000000000000000000000AA :10E67000000000000000000000000000000000009A :10E68000000000000000000000000000000000008A :10E69000000000000000000000000000000000007A :10E6A000000000000000000000000000000000006A :10E6B000000000000000000000000000000000005A :10E6C000000000000000000000000000000000004A :10E6D000000000000000000000000000000000003A :10E6E000000000000000000000000000000000002A :10E6F000000000000000000000000000000000001A :10E700000000000000000000000000000000000009 :10E7100000000000000000000000000000000000F9 :10E7200000000000000000000000000000000000E9 :10E7300000000000000000000000000000000000D9 :10E7400000000000000000000000000000000000C9 :10E7500000000000000000000000000000000000B9 :10E7600000000000000000000000000000000000A9 :10E770000000000000000000000000000000000099 :10E780000000000000000000000000000000000089 :10E790000000000000000000000000000000000079 :10E7A0000000000000000000000000000000000069 :10E7B0000000000000000000000000000000000059 :10E7C0000000000000000000000000000000000049 :10E7D0000000000000000000000000000000000039 :10E7E0000000000000000000000000000000000029 :10E7F0000000000000000000000000000000000019 :10E800000000000000000000000000000000000008 :10E8100000000000000000000000000000000000F8 :10E8200000000000000000000000000000000000E8 :10E8300000000000000000000000000000000000D8 :10E8400000000000000000000000000000000000C8 :10E8500000000000000000000000000000000000B8 :10E8600000000000000000000000000000000000A8 :10E870000000000000000000000000000000000098 :10E880000000000000000000000000000000000088 :10E890000000000000000000000000000000000078 :10E8A0000000000000000000000000000000000068 :10E8B0000000000000000000000000000000000058 :10E8C0000000000000000000000000000000000048 :10E8D0000000000000000000000000000000000038 :10E8E0000000000000000000000000000000000028 :10E8F0000000000000000000000000000000000018 :10E900000000000000000000000000000000000007 :10E9100000000000000000000000000000000000F7 :10E9200000000000000000000000000000000000E7 :10E9300000000000000000000000000000000000D7 :10E9400000000000000000000000000000000000C7 :10E9500000000000000000000000000000000000B7 :10E9600000000000000000000000000000000000A7 :10E970000000000000000000000000000000000097 :10E980000000000000000000000000000000000087 :10E990000000000000000000000000000000000077 :10E9A0000000000000000000000000000000000067 :10E9B0000000000000000000000000000000000057 :10E9C0000000000000000000000000000000000047 :10E9D0000000000000000000000000000000000037 :10E9E0000000000000000000000000000000000027 :10E9F0000000000000000000000000000000000017 :10EA00000000000000000000000000000000000006 :10EA100000000000000000000000000000000000F6 :10EA200000000000000000000000000000000000E6 :10EA300000000000000000000000000000000000D6 :10EA400000000000000000000000000000000000C6 :10EA500000000000000000000000000000000000B6 :10EA600000000000000000000000000000000000A6 :10EA70000000000000000000000000000000000096 :10EA80000000000000000000000000000000000086 :10EA90000000000000000000000000000000000076 :10EAA0000000000000000000000000000000000066 :10EAB0000000000000000000000000000000000056 :10EAC0000000000000000000000000000000000046 :10EAD0000000000000000000000000000000000036 :10EAE0000000000000000000000000000000000026 :10EAF0000000000000000000000000000000000016 :10EB00000000000000000000000000000000000005 :10EB100000000000000000000000000000000000F5 :10EB200000000000000000000000000000000000E5 :10EB300000000000000000000000000000000000D5 :10EB400000000000000000000000000000000000C5 :10EB500000000000000000000000000000000000B5 :10EB600000000000000000000000000000000000A5 :10EB70000000000000000000000000000000000095 :10EB80000000000000000000000000000000000085 :10EB90000000000000000000000000000000000075 :10EBA0000000000000000000000000000000000065 :10EBB0000000000000000000000000000000000055 :10EBC0000000000000000000000000000000000045 :10EBD0000000000000000000000000000000000035 :10EBE0000000000000000000000000000000000025 :10EBF0000000000000000000000000000000000015 :10EC00000000000000000000000000000000000004 :10EC100000000000000000000000000000000000F4 :10EC200000000000000000000000000000000000E4 :10EC300000000000000000000000000000000000D4 :10EC400000000000000000000000000000000000C4 :10EC500000000000000000000000000000000000B4 :10EC600000000000000000000000000000000000A4 :10EC70000000000000000000000000000000000094 :10EC80000000000000000000000000000000000084 :10EC90000000000000000000000000000000000074 :10ECA0000000000000000000000000000000000064 :10ECB0000000000000000000000000000000000054 :10ECC0000000000000000000000000000000000044 :10ECD0000000000000000000000000000000000034 :10ECE0000000000000000000000000000000000024 :10ECF0000000000000000000000000000000000014 :10ED00000000000000000000000000000000000003 :10ED100000000000000000000000000000000000F3 :10ED200000000000000000000000000000000000E3 :10ED300000000000000000000000000000000000D3 :10ED400000000000000000000000000000000000C3 :10ED500000000000000000000000000000000000B3 :10ED600000000000000000000000000000000000A3 :10ED70000000000000000000000000000000000093 :10ED80000000000000000000000000000000000083 :10ED90000000000000000000000000000000000073 :10EDA0000000000000000000000000000000000063 :10EDB0000000000000000000000000000000000053 :10EDC0000000000000000000000000000000000043 :10EDD0000000000000000000000000000000000033 :10EDE0000000000000000000000000000000000023 :10EDF0000000000000000000000000000000000013 :10EE00000000000000000000000000000000000002 :10EE100000000000000000000000000000000000F2 :10EE200000000000000000000000000000000000E2 :10EE300000000000000000000000000000000000D2 :10EE400000000000000000000000000000000000C2 :10EE500000000000000000000000000000000000B2 :10EE600000000000000000000000000000000000A2 :10EE70000000000000000000000000000000000092 :10EE80000000000000000000000000000000000082 :10EE90000000000000000000000000000000000072 :10EEA0000000000000000000000000000000000062 :10EEB0000000000000000000000000000000000052 :10EEC0000000000000000000000000000000000042 :10EED0000000000000000000000000000000000032 :10EEE0000000000000000000000000000000000022 :10EEF0000000000000000000000000000000000012 :10EF00000000000000000000000000000000000001 :10EF100000000000000000000000000000000000F1 :10EF200000000000000000000000000000000000E1 :10EF300000000000000000000000000000000000D1 :10EF400000000000000000000000000000000000C1 :10EF500000000000000000000000000000000000B1 :10EF600000000000000000000000000000000000A1 :10EF70000000000000000000000000000000000091 :10EF80000000000000000000000000000000000081 :10EF90000000000000000000000000000000000071 :10EFA0000000000000000000000000000000000061 :10EFB0000000000000000000000000000000000051 :10EFC0000000000000000000000000000000000041 :10EFD0000000000000000000000000000000000031 :10EFE0000000000000000000000000000000000021 :10EFF0000000000000000000000000000000000011 :10F000000000000000000000000000000000000000 :10F0100000000000000000000000000000000000F0 :10F0200000000000000000000000000000000000E0 :10F0300000000000000000000000000000000000D0 :10F0400000000000000000000000000000000000C0 :10F0500000000000000000000000000000000000B0 :10F0600000000000000000000000000000000000A0 :10F070000000000000000000000000000000000090 :10F080000000000000000000000000000000000080 :10F090000000000000000000000000000000000070 :10F0A0000000000000000000000000000000000060 :10F0B0000000000000000000000000000000000050 :10F0C0000000000000000000000000000000000040 :10F0D0000000000000000000000000000000000030 :10F0E0000000000000000000000000000000000020 :10F0F0000000000000000000000000000000000010 :10F1000000000000000000000000000000000000FF :10F1100000000000000000000000000000000000EF :10F1200000000000000000000000000000000000DF :10F1300000000000000000000000000000000000CF :10F1400000000000000000000000000000000000BF :10F1500000000000000000000000000000000000AF :10F16000000000000000000000000000000000009F :10F17000000000000000000000000000000000008F :10F18000000000000000000000000000000000007F :10F19000000000000000000000000000000000006F :10F1A000000000000000000000000000000000005F :10F1B000000000000000000000000000000000004F :10F1C000000000000000000000000000000000003F :10F1D000000000000000000000000000000000002F :10F1E000000000000000000000000000000000001F :10F1F000000000000000000000000000000000000F :10F2000000000000000000000000000000000000FE :10F2100000000000000000000000000000000000EE :10F2200000000000000000000000000000000000DE :10F2300000000000000000000000000000000000CE :10F2400000000000000000000000000000000000BE :10F2500000000000000000000000000000000000AE :10F26000000000000000000000000000000000009E :10F27000000000000000000000000000000000008E :10F28000000000000000000000000000000000007E :10F29000000000000000000000000000000000006E :10F2A000000000000000000000000000000000005E :10F2B000000000000000000000000000000000004E :10F2C000000000000000000000000000000000003E :10F2D000000000000000000000000000000000002E :10F2E000000000000000000000000000000000001E :10F2F000000000000000000000000000000000000E :10F3000000000000000000000000000000000000FD :10F3100000000000000000000000000000000000ED :10F3200000000000000000000000000000000000DD :10F3300000000000000000000000000000000000CD :10F3400000000000000000000000000000000000BD :10F3500000000000000000000000000000000000AD :10F36000000000000000000000000000000000009D :10F37000000000000000000000000000000000008D :10F38000000000000000000000000000000000007D :10F39000000000000000000000000000000000006D :10F3A000000000000000000000000000000000005D :10F3B000000000000000000000000000000000004D :10F3C000000000000000000000000000000000003D :10F3D000000000000000000000000000000000002D :10F3E000000000000000000000000000000000001D :10F3F000000000000000000000000000000000000D :10F4000000000000000000000000000000000000FC :10F4100000000000000000000000000000000000EC :10F4200000000000000000000000000000000000DC :10F4300000000000000000000000000000000000CC :10F4400000000000000000000000000000000000BC :10F4500000000000000000000000000000000000AC :10F46000000000000000000000000000000000009C :10F47000000000000000000000000000000000008C :10F48000000000000000000000000000000000007C :10F49000000000000000000000000000000000006C :10F4A000000000000000000000000000000000005C :10F4B000000000000000000000000000000000004C :10F4C000000000000000000000000000000000003C :10F4D000000000000000000000000000000000002C :10F4E000000000000000000000000000000000001C :10F4F000000000000000000000000000000000000C :10F5000000000000000000000000000000000000FB :10F5100000000000000000000000000000000000EB :10F5200000000000000000000000000000000000DB :10F5300000000000000000000000000000000000CB :10F5400000000000000000000000000000000000BB :10F5500000000000000000000000000000000000AB :10F56000000000000000000000000000000000009B :10F57000000000000000000000000000000000008B :10F58000000000000000000000000000000000007B :10F59000000000000000000000000000000000006B :10F5A000000000000000000000000000000000005B :10F5B000000000000000000000000000000000004B :10F5C000000000000000000000000000000000003B :10F5D000000000000000000000000000000000002B :10F5E000000000000000000000000000000000001B :10F5F000000000000000000000000000000000000B :10F6000000000000000000000000000000000000FA :10F6100000000000000000000000000000000000EA :10F6200000000000000000000000000000000000DA :10F6300000000000000000000000000000000000CA :10F6400000000000000000000000000000000000BA :10F6500000000000000000000000000000000000AA :10F66000000000000000000000000000000000009A :10F67000000000000000000000000000000000008A :10F68000000000000000000000000000000000007A :10F69000000000000000000000000000000000006A :10F6A000000000000000000000000000000000005A :10F6B000000000000000000000000000000000004A :10F6C000000000000000000000000000000000003A :10F6D000000000000000000000000000000000002A :10F6E000000000000000000000000000000000001A :10F6F000000000000000000000000000000000000A :10F7000000000000000000000000000000000000F9 :10F7100000000000000000000000000000000000E9 :10F7200000000000000000000000000000000000D9 :10F7300000000000000000000000000000000000C9 :10F7400000000000000000000000000000000000B9 :10F7500000000000000000000000000000000000A9 :10F760000000000000000000000000000000000099 :10F770000000000000000000000000000000000089 :10F780000000000000000000000000000000000079 :10F790000000000000000000000000000000000069 :10F7A0000000000000000000000000000000000059 :10F7B0000000000000000000000000000000000049 :10F7C0000000000000000000000000000000000039 :10F7D0000000000000000000000000000000000029 :10F7E0000000000000000000000000000000000019 :10F7F0000000000000000000000000000000000009 :10F8000000000000000000000000000000000000F8 :10F8100000000000000000000000000000000000E8 :10F8200000000000000000000000000000000000D8 :10F8300000000000000000000000000000000000C8 :10F8400000000000000000000000000000000000B8 :10F8500000000000000000000000000000000000A8 :10F860000000000000000000000000000000000098 :10F870000000000000000000000000000000000088 :10F880000000000000000000000000000000000078 :10F890000000000000000000000000000000000068 :10F8A0000000000000000000000000000000000058 :10F8B0000000000000000000000000000000000048 :10F8C0000000000000000000000000000000000038 :10F8D0000000000000000000000000000000000028 :10F8E0000000000000000000000000000000000018 :10F8F0000000000000000000000000000000000008 :10F9000000000000000000000000000000000000F7 :10F9100000000000000000000000000000000000E7 :10F9200000000000000000000000000000000000D7 :10F9300000000000000000000000000000000000C7 :10F9400000000000000000000000000000000000B7 :10F9500000000000000000000000000000000000A7 :10F960000000000000000000000000000000000097 :10F970000000000000000000000000000000000087 :10F980000000000000000000000000000000000077 :10F990000000000000000000000000000000000067 :10F9A0000000000000000000000000000000000057 :10F9B0000000000000000000000000000000000047 :10F9C0000000000000000000000000000000000037 :10F9D0000000000000000000000000000000000027 :10F9E0000000000000000000000000000000000017 :10F9F0000000000000000000000000000000000007 :10FA000000000000000000000000000000000000F6 :10FA100000000000000000000000000000000000E6 :10FA200000000000000000000000000000000000D6 :10FA300000000000000000000000000000000000C6 :10FA400000000000000000000000000000000000B6 :10FA500000000000000000000000000000000000A6 :10FA60000000000000000000000000000000000096 :10FA70000000000000000000000000000000000086 :10FA80000000000000000000000000000000000076 :10FA90000000000000000000000000000000000066 :10FAA0000000000000000000000000000000000056 :10FAB0000000000000000000000000000000000046 :10FAC0000000000000000000000000000000000036 :10FAD0000000000000000000000000000000000026 :10FAE0000000000000000000000000000000000016 :10FAF0000000000000000000000000000000000006 :10FB000000000000000000000000000000000000F5 :10FB100000000000000000000000000000000000E5 :10FB200000000000000000000000000000000000D5 :10FB300000000000000000000000000000000000C5 :10FB400000000000000000000000000000000000B5 :10FB500000000000000000000000000000000000A5 :10FB60000000000000000000000000000000000095 :10FB70000000000000000000000000000000000085 :10FB80000000000000000000000000000000000075 :10FB90000000000000000000000000000000000065 :10FBA0000000000000000000000000000000000055 :10FBB0000000000000000000000000000000000045 :10FBC0000000000000000000000000000000000035 :10FBD0000000000000000000000000000000000025 :10FBE0000000000000000000000000000000000015 :10FBF0000000000000000000000000000000000005 :10FC000000000000000000000000000000000000F4 :10FC100000000000000000000000000000000000E4 :10FC200000000000000000000000000000000000D4 :10FC300000000000000000000000000000000000C4 :10FC400000000000000000000000000000000000B4 :10FC500000000000000000000000000000000000A4 :10FC60000000000000000000000000000000000094 :10FC70000000000000000000000000000000000084 :10FC80000000000000000000000000000000000074 :10FC90000000000000000000000000000000000064 :10FCA0000000000000000000000000000000000054 :10FCB0000000000000000000000000000000000044 :10FCC0000000000000000000000000000000000034 :10FCD0000000000000000000000000000000000024 :10FCE0000000000000000000000000000000000014 :10FCF0000000000000000000000000000000000004 :10FD000000000000000000000000000000000000F3 :10FD100000000000000000000000000000000000E3 :10FD200000000000000000000000000000000000D3 :10FD300000000000000000000000000000000000C3 :10FD400000000000000000000000000000000000B3 :10FD500000000000000000000000000000000000A3 :10FD60000000000000000000000000000000000093 :10FD70000000000000000000000000000000000083 :10FD80000000000000000000000000000000000073 :10FD90000000000000000000000000000000000063 :10FDA0000000000000000000000000000000000053 :10FDB0000000000000000000000000000000000043 :10FDC0000000000000000000000000000000000033 :10FDD0000000000000000000000000000000000023 :10FDE0000000000000000000000000000000000013 :10FDF0000000000000000000000000000000000003 :10FE000000000000000000000000000000000000F2 :10FE100000000000000000000000000000000000E2 :10FE200000000000000000000000000000000000D2 :10FE300000000000000000000000000000000000C2 :10FE400000000000000000000000000000000000B2 :10FE500000000000000000000000000000000000A2 :10FE60000000000000000000000000000000000092 :10FE70000000000000000000000000000000000082 :10FE80000000000000000000000000000000000072 :10FE90000000000000000000000000000000000062 :10FEA0000000000000000000000000000000000052 :10FEB0000000000000000000000000000000000042 :10FEC0000000000000000000000000000000000032 :10FED0000000000000000000000000000000000022 :10FEE0000000000000000000000000000000000012 :10FEF0000000000000000000000000000000000002 :10FF000000000000000000000000000000000000F1 :10FF100000000000000000000000000000000000E1 :10FF200000000000000000000000000000000000D1 :10FF300000000000000000000000000000000000C1 :10FF400000000000000000000000000000000000B1 :10FF500000000000000000000000000000000000A1 :10FF60000000000000000000000000000000000091 :10FF70000000000000000000000000000000000081 :10FF80000000000000000000000000000000000071 :10FF90000000000000000000000000000000000061 :10FFA0000000000000000000000000000000000051 :10FFB0000000000000000000000000000000000041 :10FFC0000000000000000000000000000000000031 :10FFD0000000000000000000000000000000000021 :10FFE0000000000000000000000000000000000011 :10FFF0000000000000000000000000000000000001 :02000004620395 :1000000000000000000000000000000000000000F0 :1000100000000000000000000000000000000000E0 :1000200000000000000000000000000000000000D0 :1000300000000000000000000000000000000000C0 :1000400000000000000000000000000000000000B0 :1000500000000000000000000000000000000000A0 :100060000000000000000000000000000000000090 :100070000000000000000000000000000000000080 :100080000000000000000000000000000000000070 :100090000000000000000000000000000000000060 :1000A0000000000000000000000000000000000050 :1000B0000000000000000000000000000000000040 :1000C0000000000000000000000000000000000030 :1000D0000000000000000000000000000000000020 :1000E0000000000000000000000000000000000010 :1000F0000000000000000000000000000000000000 :1001000000000000000000000000000000000000EF :1001100000000000000000000000000000000000DF :1001200000000000000000000000000000000000CF :1001300000000000000000000000000000000000BF :1001400000000000000000000000000000000000AF :10015000000000000000000000000000000000009F :10016000000000000000000000000000000000008F :10017000000000000000000000000000000000007F :10018000000000000000000000000000000000006F :10019000000000000000000000000000000000005F :1001A000000000000000000000000000000000004F :1001B000000000000000000000000000000000003F :1001C000000000000000000000000000000000002F :1001D000000000000000000000000000000000001F :1001E000000000000000000000000000000000000F :1001F00000000000000000000000000000000000FF :1002000000000000000000000000000000000000EE :1002100000000000000000000000000000000000DE :1002200000000000000000000000000000000000CE :1002300000000000000000000000000000000000BE :1002400000000000000000000000000000000000AE :10025000000000000000000000000000000000009E :10026000000000000000000000000000000000008E :10027000000000000000000000000000000000007E :10028000000000000000000000000000000000006E :10029000000000000000000000000000000000005E :1002A000000000000000000000000000000000004E :1002B000000000000000000000000000000000003E :1002C000000000000000000000000000000000002E :1002D000000000000000000000000000000000001E :1002E000000000000000000000000000000000000E :1002F00000000000000000000000000000000000FE :1003000000000000000000000000000000000000ED :1003100000000000000000000000000000000000DD :1003200000000000000000000000000000000000CD :1003300000000000000000000000000000000000BD :1003400000000000000000000000000000000000AD :10035000000000000000000000000000000000009D :10036000000000000000000000000000000000008D :10037000000000000000000000000000000000007D :10038000000000000000000000000000000000006D :10039000000000000000000000000000000000005D :1003A000000000000000000000000000000000004D :1003B000000000000000000000000000000000003D :1003C000000000000000000000000000000000002D :1003D000000000000000000000000000000000001D :1003E000000000000000000000000000000000000D :1003F00000000000000000000000000000000000FD :1004000000000000000000000000000000000000EC :1004100000000000000000000000000000000000DC :1004200000000000000000000000000000000000CC :1004300000000000000000000000000000000000BC :1004400000000000000000000000000000000000AC :10045000000000000000000000000000000000009C :10046000000000000000000000000000000000008C :10047000000000000000000000000000000000007C :10048000000000000000000000000000000000006C :10049000000000000000000000000000000000005C :1004A000000000000000000000000000000000004C :1004B000000000000000000000000000000000003C :1004C000000000000000000000000000000000002C :1004D000000000000000000000000000000000001C :1004E000000000000000000000000000000000000C :1004F00000000000000000000000000000000000FC :1005000000000000000000000000000000000000EB :1005100000000000000000000000000000000000DB :1005200000000000000000000000000000000000CB :1005300000000000000000000000000000000000BB :1005400000000000000000000000000000000000AB :10055000000000000000000000000000000000009B :10056000000000000000000000000000000000008B :10057000000000000000000000000000000000007B :10058000000000000000000000000000000000006B :10059000000000000000000000000000000000005B :1005A000000000000000000000000000000000004B :1005B000000000000000000000000000000000003B :1005C000000000000000000000000000000000002B :1005D000000000000000000000000000000000001B :1005E000000000000000000000000000000000000B :1005F00000000000000000000000000000000000FB :1006000000000000000000000000000000000000EA :1006100000000000000000000000000000000000DA :1006200000000000000000000000000000000000CA :1006300000000000000000000000000000000000BA :1006400000000000000000000000000000000000AA :10065000000000000000000000000000000000009A :10066000000000000000000000000000000000008A :10067000000000000000000000000000000000007A :10068000000000000000000000000000000000006A :10069000000000000000000000000000000000005A :1006A000000000000000000000000000000000004A :1006B000000000000000000000000000000000003A :1006C000000000000000000000000000000000002A :1006D000000000000000000000000000000000001A :1006E000000000000000000000000000000000000A :1006F00000000000000000000000000000000000FA :1007000000000000000000000000000000000000E9 :1007100000000000000000000000000000000000D9 :1007200000000000000000000000000000000000C9 :1007300000000000000000000000000000000000B9 :1007400000000000000000000000000000000000A9 :100750000000000000000000000000000000000099 :100760000000000000000000000000000000000089 :100770000000000000000000000000000000000079 :100780000000000000000000000000000000000069 :100790000000000000000000000000000000000059 :1007A0000000000000000000000000000000000049 :1007B0000000000000000000000000000000000039 :1007C0000000000000000000000000000000000029 :1007D0000000000000000000000000000000000019 :1007E0000000000000000000000000000000000009 :1007F00000000000000000000000000000000000F9 :1008000000000000000000000000000000000000E8 :1008100000000000000000000000000000000000D8 :1008200000000000000000000000000000000000C8 :1008300000000000000000000000000000000000B8 :1008400000000000000000000000000000000000A8 :100850000000000000000000000000000000000098 :100860000000000000000000000000000000000088 :100870000000000000000000000000000000000078 :100880000000000000000000000000000000000068 :100890000000000000000000000000000000000058 :1008A0000000000000000000000000000000000048 :1008B0000000000000000000000000000000000038 :1008C0000000000000000000000000000000000028 :1008D0000000000000000000000000000000000018 :1008E0000000000000000000000000000000000008 :1008F00000000000000000000000000000000000F8 :1009000000000000000000000000000000000000E7 :1009100000000000000000000000000000000000D7 :1009200000000000000000000000000000000000C7 :1009300000000000000000000000000000000000B7 :1009400000000000000000000000000000000000A7 :100950000000000000000000000000000000000097 :100960000000000000000000000000000000000087 :100970000000000000000000000000000000000077 :100980000000000000000000000000000000000067 :100990000000000000000000000000000000000057 :1009A0000000000000000000000000000000000047 :1009B0000000000000000000000000000000000037 :1009C0000000000000000000000000000000000027 :1009D0000000000000000000000000000000000017 :1009E0000000000000000000000000000000000007 :1009F00000000000000000000000000000000000F7 :100A000000000000000000000000000000000000E6 :100A100000000000000000000000000000000000D6 :100A200000000000000000000000000000000000C6 :100A300000000000000000000000000000000000B6 :100A400000000000000000000000000000000000A6 :100A50000000000000000000000000000000000096 :100A60000000000000000000000000000000000086 :100A70000000000000000000000000000000000076 :100A80000000000000000000000000000000000066 :100A90000000000000000000000000000000000056 :100AA0000000000000000000000000000000000046 :100AB0000000000000000000000000000000000036 :100AC0000000000000000000000000000000000026 :100AD0000000000000000000000000000000000016 :100AE0000000000000000000000000000000000006 :100AF00000000000000000000000000000000000F6 :100B000000000000000000000000000000000000E5 :100B100000000000000000000000000000000000D5 :100B200000000000000000000000000000000000C5 :100B300000000000000000000000000000000000B5 :100B400000000000000000000000000000000000A5 :100B50000000000000000000000000000000000095 :100B60000000000000000000000000000000000085 :100B70000000000000000000000000000000000075 :100B80000000000000000000000000000000000065 :100B90000000000000000000000000000000000055 :100BA0000000000000000000000000000000000045 :100BB0000000000000000000000000000000000035 :100BC0000000000000000000000000000000000025 :100BD0000000000000000000000000000000000015 :100BE0000000000000000000000000000000000005 :100BF00000000000000000000000000000000000F5 :100C000000000000000000000000000000000000E4 :100C100000000000000000000000000000000000D4 :100C200000000000000000000000000000000000C4 :100C300000000000000000000000000000000000B4 :100C400000000000000000000000000000000000A4 :100C50000000000000000000000000000000000094 :100C60000000000000000000000000000000000084 :100C70000000000000000000000000000000000074 :100C80000000000000000000000000000000000064 :100C90000000000000000000000000000000000054 :100CA0000000000000000000000000000000000044 :100CB0000000000000000000000000000000000034 :100CC0000000000000000000000000000000000024 :100CD0000000000000000000000000000000000014 :100CE0000000000000000000000000000000000004 :100CF00000000000000000000000000000000000F4 :100D000000000000000000000000000000000000E3 :100D100000000000000000000000000000000000D3 :100D200000000000000000000000000000000000C3 :100D300000000000000000000000000000000000B3 :100D400000000000000000000000000000000000A3 :100D50000000000000000000000000000000000093 :100D60000000000000000000000000000000000083 :100D70000000000000000000000000000000000073 :100D80000000000000000000000000000000000063 :100D90000000000000000000000000000000000053 :100DA0000000000000000000000000000000000043 :100DB0000000000000000000000000000000000033 :100DC0000000000000000000000000000000000023 :100DD0000000000000000000000000000000000013 :100DE0000000000000000000000000000000000003 :100DF00000000000000000000000000000000000F3 :100E000000000000000000000000000000000000E2 :100E100000000000000000000000000000000000D2 :100E200000000000000000000000000000000000C2 :100E300000000000000000000000000000000000B2 :100E400000000000000000000000000000000000A2 :100E50000000000000000000000000000000000092 :100E60000000000000000000000000000000000082 :100E70000000000000000000000000000000000072 :100E80000000000000000000000000000000000062 :100E90000000000000000000000000000000000052 :100EA0000000000000000000000000000000000042 :100EB0000000000000000000000000000000000032 :100EC0000000000000000000000000000000000022 :100ED0000000000000000000000000000000000012 :100EE0000000000000000000000000000000000002 :100EF00000000000000000000000000000000000F2 :100F000000000000000000000000000000000000E1 :100F100000000000000000000000000000000000D1 :100F200000000000000000000000000000000000C1 :100F300000000000000000000000000000000000B1 :100F400000000000000000000000000000000000A1 :100F50000000000000000000000000000000000091 :100F60000000000000000000000000000000000081 :100F70000000000000000000000000000000000071 :100F80000000000000000000000000000000000061 :100F90000000000000000000000000000000000051 :100FA0000000000000000000000000000000000041 :100FB0000000000000000000000000000000000031 :100FC0000000000000000000000000000000000021 :100FD0000000000000000000000000000000000011 :100FE0000000000000000000000000000000000001 :100FF00000000000000000000000000000000000F1 :1010000000000000000000000000000000000000E0 :1010100000000000000000000000000000000000D0 :1010200000000000000000000000000000000000C0 :1010300000000000000000000000000000000000B0 :1010400000000000000000000000000000000000A0 :101050000000000000000000000000000000000090 :101060000000000000000000000000000000000080 :101070000000000000000000000000000000000070 :101080000000000000000000000000000000000060 :101090000000000000000000000000000000000050 :1010A0000000000000000000000000000000000040 :1010B0000000000000000000000000000000000030 :1010C0000000000000000000000000000000000020 :1010D0000000000000000000000000000000000010 :1010E0000000000000000000000000000000000000 :1010F00000000000000000000000000000000000F0 :1011000000000000000000000000000000000000DF :1011100000000000000000000000000000000000CF :1011200000000000000000000000000000000000BF :1011300000000000000000000000000000000000AF :10114000000000000000000000000000000000009F :10115000000000000000000000000000000000008F :10116000000000000000000000000000000000007F :10117000000000000000000000000000000000006F :10118000000000000000000000000000000000005F :10119000000000000000000000000000000000004F :1011A000000000000000000000000000000000003F :1011B000000000000000000000000000000000002F :1011C000000000000000000000000000000000001F :1011D000000000000000000000000000000000000F :1011E00000000000000000000000000000000000FF :1011F00000000000000000000000000000000000EF :1012000000000000000000000000000000000000DE :1012100000000000000000000000000000000000CE :1012200000000000000000000000000000000000BE :1012300000000000000000000000000000000000AE :10124000000000000000000000000000000000009E :10125000000000000000000000000000000000008E :10126000000000000000000000000000000000007E :10127000000000000000000000000000000000006E :10128000000000000000000000000000000000005E :10129000000000000000000000000000000000004E :1012A000000000000000000000000000000000003E :1012B000000000000000000000000000000000002E :1012C000000000000000000000000000000000001E :1012D000000000000000000000000000000000000E :1012E00000000000000000000000000000000000FE :1012F00000000000000000000000000000000000EE :1013000000000000000000000000000000000000DD :1013100000000000000000000000000000000000CD :1013200000000000000000000000000000000000BD :1013300000000000000000000000000000000000AD :10134000000000000000000000000000000000009D :10135000000000000000000000000000000000008D :10136000000000000000000000000000000000007D :10137000000000000000000000000000000000006D :10138000000000000000000000000000000000005D :10139000000000000000000000000000000000004D :1013A000000000000000000000000000000000003D :1013B000000000000000000000000000000000002D :1013C000000000000000000000000000000000001D :1013D000000000000000000000000000000000000D :1013E00000000000000000000000000000000000FD :1013F00000000000000000000000000000000000ED :1014000000000000000000000000000000000000DC :1014100000000000000000000000000000000000CC :1014200000000000000000000000000000000000BC :1014300000000000000000000000000000000000AC :10144000000000000000000000000000000000009C :10145000000000000000000000000000000000008C :10146000000000000000000000000000000000007C :10147000000000000000000000000000000000006C :10148000000000000000000000000000000000005C :10149000000000000000000000000000000000004C :1014A000000000000000000000000000000000003C :1014B000000000000000000000000000000000002C :1014C000000000000000000000000000000000001C :1014D000000000000000000000000000000000000C :1014E00000000000000000000000000000000000FC :1014F00000000000000000000000000000000000EC :1015000000000000000000000000000000000000DB :1015100000000000000000000000000000000000CB :1015200000000000000000000000000000000000BB :1015300000000000000000000000000000000000AB :10154000000000000000000000000000000000009B :10155000000000000000000000000000000000008B :10156000000000000000000000000000000000007B :10157000000000000000000000000000000000006B :10158000000000000000000000000000000000005B :10159000000000000000000000000000000000004B :1015A000000000000000000000000000000000003B :1015B000000000000000000000000000000000002B :1015C000000000000000000000000000000000001B :1015D000000000000000000000000000000000000B :1015E00000000000000000000000000000000000FB :1015F00000000000000000000000000000000000EB :1016000000000000000000000000000000000000DA :1016100000000000000000000000000000000000CA :1016200000000000000000000000000000000000BA :1016300000000000000000000000000000000000AA :10164000000000000000000000000000000000009A :10165000000000000000000000000000000000008A :10166000000000000000000000000000000000007A :10167000000000000000000000000000000000006A :10168000000000000000000000000000000000005A :10169000000000000000000000000000000000004A :1016A000000000000000000000000000000000003A :1016B000000000000000000000000000000000002A :1016C000000000000000000000000000000000001A :1016D000000000000000000000000000000000000A :1016E00000000000000000000000000000000000FA :1016F00000000000000000000000000000000000EA :1017000000000000000000000000000000000000D9 :1017100000000000000000000000000000000000C9 :1017200000000000000000000000000000000000B9 :1017300000000000000000000000000000000000A9 :101740000000000000000000000000000000000099 :101750000000000000000000000000000000000089 :101760000000000000000000000000000000000079 :101770000000000000000000000000000000000069 :101780000000000000000000000000000000000059 :101790000000000000000000000000000000000049 :1017A0000000000000000000000000000000000039 :1017B0000000000000000000000000000000000029 :1017C0000000000000000000000000000000000019 :1017D0000000000000000000000000000000000009 :1017E00000000000000000000000000000000000F9 :1017F00000000000000000000000000000000000E9 :1018000000000000000000000000000000000000D8 :1018100000000000000000000000000000000000C8 :1018200000000000000000000000000000000000B8 :1018300000000000000000000000000000000000A8 :101840000000000000000000000000000000000098 :101850000000000000000000000000000000000088 :101860000000000000000000000000000000000078 :101870000000000000000000000000000000000068 :101880000000000000000000000000000000000058 :101890000000000000000000000000000000000048 :1018A0000000000000000000000000000000000038 :1018B0000000000000000000000000000000000028 :1018C0000000000000000000000000000000000018 :1018D0000000000000000000000000000000000008 :1018E00000000000000000000000000000000000F8 :1018F00000000000000000000000000000000000E8 :1019000000000000000000000000000000000000D7 :1019100000000000000000000000000000000000C7 :1019200000000000000000000000000000000000B7 :1019300000000000000000000000000000000000A7 :101940000000000000000000000000000000000097 :101950000000000000000000000000000000000087 :101960000000000000000000000000000000000077 :101970000000000000000000000000000000000067 :101980000000000000000000000000000000000057 :101990000000000000000000000000000000000047 :1019A0000000000000000000000000000000000037 :1019B0000000000000000000000000000000000027 :1019C0000000000000000000000000000000000017 :1019D0000000000000000000000000000000000007 :1019E00000000000000000000000000000000000F7 :1019F00000000000000000000000000000000000E7 :101A000000000000000000000000000000000000D6 :101A100000000000000000000000000000000000C6 :101A200000000000000000000000000000000000B6 :101A300000000000000000000000000000000000A6 :101A40000000000000000000000000000000000096 :101A50000000000000000000000000000000000086 :101A60000000000000000000000000000000000076 :101A70000000000000000000000000000000000066 :101A80000000000000000000000000000000000056 :101A90000000000000000000000000000000000046 :101AA0000000000000000000000000000000000036 :101AB0000000000000000000000000000000000026 :101AC0000000000000000000000000000000000016 :101AD0000000000000000000000000000000000006 :101AE00000000000000000000000000000000000F6 :101AF00000000000000000000000000000000000E6 :101B000000000000000000000000000000000000D5 :101B100000000000000000000000000000000000C5 :101B200000000000000000000000000000000000B5 :101B300000000000000000000000000000000000A5 :101B40000000000000000000000000000000000095 :101B50000000000000000000000000000000000085 :101B60000000000000000000000000000000000075 :101B70000000000000000000000000000000000065 :101B80000000000000000000000000000000000055 :101B90000000000000000000000000000000000045 :101BA0000000000000000000000000000000000035 :101BB0000000000000000000000000000000000025 :101BC0000000000000000000000000000000000015 :101BD0000000000000000000000000000000000005 :101BE00000000000000000000000000000000000F5 :101BF00000000000000000000000000000000000E5 :101C000000000000000000000000000000000000D4 :101C100000000000000000000000000000000000C4 :101C200000000000000000000000000000000000B4 :101C300000000000000000000000000000000000A4 :101C40000000000000000000000000000000000094 :101C50000000000000000000000000000000000084 :101C60000000000000000000000000000000000074 :101C70000000000000000000000000000000000064 :101C80000000000000000000000000000000000054 :101C90000000000000000000000000000000000044 :101CA0000000000000000000000000000000000034 :101CB0000000000000000000000000000000000024 :101CC0000000000000000000000000000000000014 :101CD0000000000000000000000000000000000004 :101CE00000000000000000000000000000000000F4 :101CF00000000000000000000000000000000000E4 :101D000000000000000000000000000000000000D3 :101D100000000000000000000000000000000000C3 :101D200000000000000000000000000000000000B3 :101D300000000000000000000000000000000000A3 :101D40000000000000000000000000000000000093 :101D50000000000000000000000000000000000083 :101D60000000000000000000000000000000000073 :101D70000000000000000000000000000000000063 :101D80000000000000000000000000000000000053 :101D90000000000000000000000000000000000043 :101DA0000000000000000000000000000000000033 :101DB0000000000000000000000000000000000023 :101DC0000000000000000000000000000000000013 :101DD0000000000000000000000000000000000003 :101DE00000000000000000000000000000000000F3 :101DF00000000000000000000000000000000000E3 :101E000000000000000000000000000000000000D2 :101E100000000000000000000000000000000000C2 :101E200000000000000000000000000000000000B2 :101E300000000000000000000000000000000000A2 :101E40000000000000000000000000000000000092 :101E50000000000000000000000000000000000082 :101E60000000000000000000000000000000000072 :101E70000000000000000000000000000000000062 :101E80000000000000000000000000000000000052 :101E90000000000000000000000000000000000042 :101EA0000000000000000000000000000000000032 :101EB0000000000000000000000000000000000022 :101EC0000000000000000000000000000000000012 :101ED0000000000000000000000000000000000002 :101EE00000000000000000000000000000000000F2 :101EF00000000000000000000000000000000000E2 :101F000000000000000000000000000000000000D1 :101F100000000000000000000000000000000000C1 :101F200000000000000000000000000000000000B1 :101F300000000000000000000000000000000000A1 :101F40000000000000000000000000000000000091 :101F50000000000000000000000000000000000081 :101F60000000000000000000000000000000000071 :101F70000000000000000000000000000000000061 :101F80000000000000000000000000000000000051 :101F90000000000000000000000000000000000041 :101FA0000000000000000000000000000000000031 :101FB0000000000000000000000000000000000021 :101FC0000000000000000000000000000000000011 :101FD0000000000000000000000000000000000001 :101FE00000000000000000000000000000000000F1 :101FF00000000000000000000000000000000000E1 :1020000000000000000000000000000000000000D0 :1020100000000000000000000000000000000000C0 :1020200000000000000000000000000000000000B0 :1020300000000000000000000000000000000000A0 :102040000000000000000000000000000000000090 :102050000000000000000000000000000000000080 :102060000000000000000000000000000000000070 :102070000000000000000000000000000000000060 :102080000000000000000000000000000000000050 :102090000000000000000000000000000000000040 :1020A0000000000000000000000000000000000030 :1020B0000000000000000000000000000000000020 :1020C0000000000000000000000000000000000010 :1020D0000000000000000000000000000000000000 :1020E00000000000000000000000000000000000F0 :1020F00000000000000000000000000000000000E0 :1021000000000000000000000000000000000000CF :1021100000000000000000000000000000000000BF :1021200000000000000000000000000000000000AF :10213000000000000000000000000000000000009F :10214000000000000000000000000000000000008F :10215000000000000000000000000000000000007F :10216000000000000000000000000000000000006F :10217000000000000000000000000000000000005F :10218000000000000000000000000000000000004F :10219000000000000000000000000000000000003F :1021A000000000000000000000000000000000002F :1021B000000000000000000000000000000000001F :1021C000000000000000000000000000000000000F :1021D00000000000000000000000000000000000FF :1021E00000000000000000000000000000000000EF :1021F00000000000000000000000000000000000DF :1022000000000000000000000000000000000000CE :1022100000000000000000000000000000000000BE :1022200000000000000000000000000000000000AE :10223000000000000000000000000000000000009E :10224000000000000000000000000000000000008E :10225000000000000000000000000000000000007E :10226000000000000000000000000000000000006E :10227000000000000000000000000000000000005E :10228000000000000000000000000000000000004E :10229000000000000000000000000000000000003E :1022A000000000000000000000000000000000002E :1022B000000000000000000000000000000000001E :1022C000000000000000000000000000000000000E :1022D00000000000000000000000000000000000FE :1022E00000000000000000000000000000000000EE :1022F00000000000000000000000000000000000DE :1023000000000000000000000000000000000000CD :1023100000000000000000000000000000000000BD :1023200000000000000000000000000000000000AD :10233000000000000000000000000000000000009D :10234000000000000000000000000000000000008D :10235000000000000000000000000000000000007D :10236000000000000000000000000000000000006D :10237000000000000000000000000000000000005D :10238000000000000000000000000000000000004D :10239000000000000000000000000000000000003D :1023A000000000000000000000000000000000002D :1023B000000000000000000000000000000000001D :1023C000000000000000000000000000000000000D :1023D00000000000000000000000000000000000FD :1023E00000000000000000000000000000000000ED :1023F00000000000000000000000000000000000DD :1024000000000000000000000000000000000000CC :1024100000000000000000000000000000000000BC :1024200000000000000000000000000000000000AC :10243000000000000000000000000000000000009C :10244000000000000000000000000000000000008C :10245000000000000000000000000000000000007C :10246000000000000000000000000000000000006C :10247000000000000000000000000000000000005C :10248000000000000000000000000000000000004C :10249000000000000000000000000000000000003C :1024A000000000000000000000000000000000002C :1024B000000000000000000000000000000000001C :1024C000000000000000000000000000000000000C :1024D00000000000000000000000000000000000FC :1024E00000000000000000000000000000000000EC :1024F00000000000000000000000000000000000DC :1025000000000000000000000000000000000000CB :1025100000000000000000000000000000000000BB :1025200000000000000000000000000000000000AB :10253000000000000000000000000000000000009B :10254000000000000000000000000000000000008B :10255000000000000000000000000000000000007B :10256000000000000000000000000000000000006B :10257000000000000000000000000000000000005B :10258000000000000000000000000000000000004B :10259000000000000000000000000000000000003B :1025A000000000000000000000000000000000002B :1025B000000000000000000000000000000000001B :1025C000000000000000000000000000000000000B :1025D00000000000000000000000000000000000FB :1025E00000000000000000000000000000000000EB :1025F00000000000000000000000000000000000DB :1026000000000000000000000000000000000000CA :1026100000000000000000000000000000000000BA :1026200000000000000000000000000000000000AA :10263000000000000000000000000000000000009A :10264000000000000000000000000000000000008A :10265000000000000000000000000000000000007A :10266000000000000000000000000000000000006A :10267000000000000000000000000000000000005A :10268000000000000000000000000000000000004A :10269000000000000000000000000000000000003A :1026A000000000000000000000000000000000002A :1026B000000000000000000000000000000000001A :1026C000000000000000000000000000000000000A :1026D00000000000000000000000000000000000FA :1026E00000000000000000000000000000000000EA :1026F00000000000000000000000000000000000DA :1027000000000000000000000000000000000000C9 :1027100000000000000000000000000000000000B9 :1027200000000000000000000000000000000000A9 :102730000000000000000000000000000000000099 :102740000000000000000000000000000000000089 :102750000000000000000000000000000000000079 :102760000000000000000000000000000000000069 :102770000000000000000000000000000000000059 :102780000000000000000000000000000000000049 :102790000000000000000000000000000000000039 :1027A0000000000000000000000000000000000029 :1027B0000000000000000000000000000000000019 :1027C0000000000000000000000000000000000009 :1027D00000000000000000000000000000000000F9 :1027E00000000000000000000000000000000000E9 :1027F00000000000000000000000000000000000D9 :1028000000000000000000000000000000000000C8 :1028100000000000000000000000000000000000B8 :1028200000000000000000000000000000000000A8 :102830000000000000000000000000000000000098 :102840000000000000000000000000000000000088 :102850000000000000000000000000000000000078 :102860000000000000000000000000000000000068 :102870000000000000000000000000000000000058 :102880000000000000000000000000000000000048 :102890000000000000000000000000000000000038 :1028A0000000000000000000000000000000000028 :1028B0000000000000000000000000000000000018 :1028C0000000000000000000000000000000000008 :1028D00000000000000000000000000000000000F8 :1028E00000000000000000000000000000000000E8 :1028F00000000000000000000000000000000000D8 :1029000000000000000000000000000000000000C7 :1029100000000000000000000000000000000000B7 :1029200000000000000000000000000000000000A7 :102930000000000000000000000000000000000097 :102940000000000000000000000000000000000087 :102950000000000000000000000000000000000077 :102960000000000000000000000000000000000067 :102970000000000000000000000000000000000057 :102980000000000000000000000000000000000047 :102990000000000000000000000000000000000037 :1029A0000000000000000000000000000000000027 :1029B0000000000000000000000000000000000017 :1029C0000000000000000000000000000000000007 :1029D00000000000000000000000000000000000F7 :1029E00000000000000000000000000000000000E7 :1029F00000000000000000000000000000000000D7 :102A000000000000000000000000000000000000C6 :102A100000000000000000000000000000000000B6 :102A200000000000000000000000000000000000A6 :102A30000000000000000000000000000000000096 :102A40000000000000000000000000000000000086 :102A50000000000000000000000000000000000076 :102A60000000000000000000000000000000000066 :102A70000000000000000000000000000000000056 :102A80000000000000000000000000000000000046 :102A90000000000000000000000000000000000036 :102AA0000000000000000000000000000000000026 :102AB0000000000000000000000000000000000016 :102AC0000000000000000000000000000000000006 :102AD00000000000000000000000000000000000F6 :102AE00000000000000000000000000000000000E6 :102AF00000000000000000000000000000000000D6 :102B000000000000000000000000000000000000C5 :102B100000000000000000000000000000000000B5 :102B200000000000000000000000000000000000A5 :102B30000000000000000000000000000000000095 :102B40000000000000000000000000000000000085 :102B50000000000000000000000000000000000075 :102B60000000000000000000000000000000000065 :102B70000000000000000000000000000000000055 :102B80000000000000000000000000000000000045 :102B90000000000000000000000000000000000035 :102BA0000000000000000000000000000000000025 :102BB0000000000000000000000000000000000015 :102BC0000000000000000000000000000000000005 :102BD00000000000000000000000000000000000F5 :102BE00000000000000000000000000000000000E5 :102BF00000000000000000000000000000000000D5 :102C000000000000000000000000000000000000C4 :102C100000000000000000000000000000000000B4 :102C200000000000000000000000000000000000A4 :102C30000000000000000000000000000000000094 :102C40000000000000000000000000000000000084 :102C50000000000000000000000000000000000074 :102C60000000000000000000000000000000000064 :102C70000000000000000000000000000000000054 :102C80000000000000000000000000000000000044 :102C90000000000000000000000000000000000034 :102CA0000000000000000000000000000000000024 :102CB0000000000000000000000000000000000014 :102CC0000000000000000000000000000000000004 :102CD00000000000000000000000000000000000F4 :102CE00000000000000000000000000000000000E4 :102CF00000000000000000000000000000000000D4 :102D000000000000000000000000000000000000C3 :102D100000000000000000000000000000000000B3 :102D200000000000000000000000000000000000A3 :102D30000000000000000000000000000000000093 :102D40000000000000000000000000000000000083 :102D50000000000000000000000000000000000073 :102D60000000000000000000000000000000000063 :102D70000000000000000000000000000000000053 :102D80000000000000000000000000000000000043 :102D90000000000000000000000000000000000033 :102DA0000000000000000000000000000000000023 :102DB0000000000000000000000000000000000013 :102DC0000000000000000000000000000000000003 :102DD00000000000000000000000000000000000F3 :102DE00000000000000000000000000000000000E3 :102DF00000000000000000000000000000000000D3 :102E000000000000000000000000000000000000C2 :102E100000000000000000000000000000000000B2 :102E200000000000000000000000000000000000A2 :102E30000000000000000000000000000000000092 :102E40000000000000000000000000000000000082 :102E50000000000000000000000000000000000072 :102E60000000000000000000000000000000000062 :102E70000000000000000000000000000000000052 :102E80000000000000000000000000000000000042 :102E90000000000000000000000000000000000032 :102EA0000000000000000000000000000000000022 :102EB0000000000000000000000000000000000012 :102EC0000000000000000000000000000000000002 :102ED00000000000000000000000000000000000F2 :102EE00000000000000000000000000000000000E2 :102EF00000000000000000000000000000000000D2 :102F000000000000000000000000000000000000C1 :102F100000000000000000000000000000000000B1 :102F200000000000000000000000000000000000A1 :102F30000000000000000000000000000000000091 :102F40000000000000000000000000000000000081 :102F50000000000000000000000000000000000071 :102F60000000000000000000000000000000000061 :102F70000000000000000000000000000000000051 :102F80000000000000000000000000000000000041 :102F90000000000000000000000000000000000031 :102FA0000000000000000000000000000000000021 :102FB0000000000000000000000000000000000011 :102FC0000000000000000000000000000000000001 :102FD00000000000000000000000000000000000F1 :102FE00000000000000000000000000000000000E1 :102FF00000000000000000000000000000000000D1 :1030000000000000000000000000000000000000C0 :1030100000000000000000000000000000000000B0 :1030200000000000000000000000000000000000A0 :103030000000000000000000000000000000000090 :103040000000000000000000000000000000000080 :103050000000000000000000000000000000000070 :103060000000000000000000000000000000000060 :103070000000000000000000000000000000000050 :103080000000000000000000000000000000000040 :103090000000000000000000000000000000000030 :1030A0000000000000000000000000000000000020 :1030B0000000000000000000000000000000000010 :1030C0000000000000000000000000000000000000 :1030D00000000000000000000000000000000000F0 :1030E00000000000000000000000000000000000E0 :1030F00000000000000000000000000000000000D0 :1031000000000000000000000000000000000000BF :1031100000000000000000000000000000000000AF :10312000000000000000000000000000000000009F :10313000000000000000000000000000000000008F :10314000000000000000000000000000000000007F :10315000000000000000000000000000000000006F :10316000000000000000000000000000000000005F :10317000000000000000000000000000000000004F :10318000000000000000000000000000000000003F :10319000000000000000000000000000000000002F :1031A000000000000000000000000000000000001F :1031B000000000000000000000000000000000000F :1031C00000000000000000000000000000000000FF :1031D00000000000000000000000000000000000EF :1031E00000000000000000000000000000000000DF :1031F00000000000000000000000000000000000CF :1032000000000000000000000000000000000000BE :1032100000000000000000000000000000000000AE :10322000000000000000000000000000000000009E :10323000000000000000000000000000000000008E :10324000000000000000000000000000000000007E :10325000000000000000000000000000000000006E :10326000000000000000000000000000000000005E :10327000000000000000000000000000000000004E :10328000000000000000000000000000000000003E :10329000000000000000000000000000000000002E :1032A000000000000000000000000000000000001E :1032B000000000000000000000000000000000000E :1032C00000000000000000000000000000000000FE :1032D00000000000000000000000000000000000EE :1032E00000000000000000000000000000000000DE :1032F00000000000000000000000000000000000CE :1033000000000000000000000000000000000000BD :1033100000000000000000000000000000000000AD :10332000000000000000000000000000000000009D :10333000000000000000000000000000000000008D :10334000000000000000000000000000000000007D :10335000000000000000000000000000000000006D :10336000000000000000000000000000000000005D :10337000000000000000000000000000000000004D :10338000000000000000000000000000000000003D :10339000000000000000000000000000000000002D :1033A000000000000000000000000000000000001D :1033B000000000000000000000000000000000000D :1033C00000000000000000000000000000000000FD :1033D00000000000000000000000000000000000ED :1033E00000000000000000000000000000000000DD :1033F00000000000000000000000000000000000CD :1034000000000000000000000000000000000000BC :1034100000000000000000000000000000000000AC :10342000000000000000000000000000000000009C :10343000000000000000000000000000000000008C :10344000000000000000000000000000000000007C :10345000000000000000000000000000000000006C :10346000000000000000000000000000000000005C :10347000000000000000000000000000000000004C :10348000000000000000000000000000000000003C :10349000000000000000000000000000000000002C :1034A000000000000000000000000000000000001C :1034B000000000000000000000000000000000000C :1034C00000000000000000000000000000000000FC :1034D00000000000000000000000000000000000EC :1034E00000000000000000000000000000000000DC :1034F00000000000000000000000000000000000CC :1035000000000000000000000000000000000000BB :1035100000000000000000000000000000000000AB :10352000000000000000000000000000000000009B :10353000000000000000000000000000000000008B :10354000000000000000000000000000000000007B :10355000000000000000000000000000000000006B :10356000000000000000000000000000000000005B :10357000000000000000000000000000000000004B :10358000000000000000000000000000000000003B :10359000000000000000000000000000000000002B :1035A000000000000000000000000000000000001B :1035B000000000000000000000000000000000000B :1035C00000000000000000000000000000000000FB :1035D00000000000000000000000000000000000EB :1035E00000000000000000000000000000000000DB :1035F00000000000000000000000000000000000CB :1036000000000000000000000000000000000000BA :1036100000000000000000000000000000000000AA :10362000000000000000000000000000000000009A :10363000000000000000000000000000000000008A :10364000000000000000000000000000000000007A :10365000000000000000000000000000000000006A :10366000000000000000000000000000000000005A :10367000000000000000000000000000000000004A :10368000000000000000000000000000000000003A :10369000000000000000000000000000000000002A :1036A000000000000000000000000000000000001A :1036B000000000000000000000000000000000000A :1036C00000000000000000000000000000000000FA :1036D00000000000000000000000000000000000EA :1036E00000000000000000000000000000000000DA :1036F00000000000000000000000000000000000CA :1037000000000000000000000000000000000000B9 :1037100000000000000000000000000000000000A9 :103720000000000000000000000000000000000099 :103730000000000000000000000000000000000089 :103740000000000000000000000000000000000079 :103750000000000000000000000000000000000069 :103760000000000000000000000000000000000059 :103770000000000000000000000000000000000049 :103780000000000000000000000000000000000039 :103790000000000000000000000000000000000029 :1037A0000000000000000000000000000000000019 :1037B0000000000000000000000000000000000009 :1037C00000000000000000000000000000000000F9 :1037D00000000000000000000000000000000000E9 :1037E00000000000000000000000000000000000D9 :1037F00000000000000000000000000000000000C9 :1038000000000000000000000000000000000000B8 :1038100000000000000000000000000000000000A8 :103820000000000000000000000000000000000098 :103830000000000000000000000000000000000088 :103840000000000000000000000000000000000078 :103850000000000000000000000000000000000068 :103860000000000000000000000000000000000058 :103870000000000000000000000000000000000048 :103880000000000000000000000000000000000038 :103890000000000000000000000000000000000028 :1038A0000000000000000000000000000000000018 :1038B0000000000000000000000000000000000008 :1038C00000000000000000000000000000000000F8 :1038D00000000000000000000000000000000000E8 :1038E00000000000000000000000000000000000D8 :1038F00000000000000000000000000000000000C8 :1039000000000000000000000000000000000000B7 :1039100000000000000000000000000000000000A7 :103920000000000000000000000000000000000097 :103930000000000000000000000000000000000087 :103940000000000000000000000000000000000077 :103950000000000000000000000000000000000067 :103960000000000000000000000000000000000057 :103970000000000000000000000000000000000047 :103980000000000000000000000000000000000037 :103990000000000000000000000000000000000027 :1039A0000000000000000000000000000000000017 :1039B0000000000000000000000000000000000007 :1039C00000000000000000000000000000000000F7 :1039D00000000000000000000000000000000000E7 :1039E00000000000000000000000000000000000D7 :1039F00000000000000000000000000000000000C7 :103A000000000000000000000000000000000000B6 :103A100000000000000000000000000000000000A6 :103A20000000000000000000000000000000000096 :103A30000000000000000000000000000000000086 :103A40000000000000000000000000000000000076 :103A50000000000000000000000000000000000066 :103A60000000000000000000000000000000000056 :103A70000000000000000000000000000000000046 :103A80000000000000000000000000000000000036 :103A90000000000000000000000000000000000026 :103AA0000000000000000000000000000000000016 :103AB0000000000000000000000000000000000006 :103AC00000000000000000000000000000000000F6 :103AD00000000000000000000000000000000000E6 :103AE00000000000000000000000000000000000D6 :103AF00000000000000000000000000000000000C6 :103B000000000000000000000000000000000000B5 :103B100000000000000000000000000000000000A5 :103B20000000000000000000000000000000000095 :103B30000000000000000000000000000000000085 :103B40000000000000000000000000000000000075 :103B50000000000000000000000000000000000065 :103B60000000000000000000000000000000000055 :103B70000000000000000000000000000000000045 :103B80000000000000000000000000000000000035 :103B90000000000000000000000000000000000025 :103BA0000000000000000000000000000000000015 :103BB0000000000000000000000000000000000005 :103BC00000000000000000000000000000000000F5 :103BD00000000000000000000000000000000000E5 :103BE00000000000000000000000000000000000D5 :103BF00000000000000000000000000000000000C5 :103C000000000000000000000000000000000000B4 :103C100000000000000000000000000000000000A4 :103C20000000000000000000000000000000000094 :103C30000000000000000000000000000000000084 :103C40000000000000000000000000000000000074 :103C50000000000000000000000000000000000064 :103C60000000000000000000000000000000000054 :103C70000000000000000000000000000000000044 :103C80000000000000000000000000000000000034 :103C90000000000000000000000000000000000024 :103CA0000000000000000000000000000000000014 :103CB0000000000000000000000000000000000004 :103CC00000000000000000000000000000000000F4 :103CD00000000000000000000000000000000000E4 :103CE00000000000000000000000000000000000D4 :103CF00000000000000000000000000000000000C4 :103D000000000000000000000000000000000000B3 :103D100000000000000000000000000000000000A3 :103D20000000000000000000000000000000000093 :103D30000000000000000000000000000000000083 :103D40000000000000000000000000000000000073 :103D50000000000000000000000000000000000063 :103D60000000000000000000000000000000000053 :103D70000000000000000000000000000000000043 :103D80000000000000000000000000000000000033 :103D90000000000000000000000000000000000023 :103DA0000000000000000000000000000000000013 :103DB0000000000000000000000000000000000003 :103DC00000000000000000000000000000000000F3 :103DD00000000000000000000000000000000000E3 :103DE00000000000000000000000000000000000D3 :103DF00000000000000000000000000000000000C3 :103E000000000000000000000000000000000000B2 :103E100000000000000000000000000000000000A2 :103E20000000000000000000000000000000000092 :103E30000000000000000000000000000000000082 :103E40000000000000000000000000000000000072 :103E50000000000000000000000000000000000062 :103E60000000000000000000000000000000000052 :103E70000000000000000000000000000000000042 :103E80000000000000000000000000000000000032 :103E90000000000000000000000000000000000022 :103EA0000000000000000000000000000000000012 :103EB0000000000000000000000000000000000002 :103EC00000000000000000000000000000000000F2 :103ED00000000000000000000000000000000000E2 :103EE00000000000000000000000000000000000D2 :103EF00000000000000000000000000000000000C2 :103F000000000000000000000000000000000000B1 :103F100000000000000000000000000000000000A1 :103F20000000000000000000000000000000000091 :103F30000000000000000000000000000000000081 :103F40000000000000000000000000000000000071 :103F50000000000000000000000000000000000061 :103F60000000000000000000000000000000000051 :103F70000000000000000000000000000000000041 :103F80000000000000000000000000000000000031 :103F90000000000000000000000000000000000021 :103FA0000000000000000000000000000000000011 :103FB0000000000000000000000000000000000001 :103FC00000000000000000000000000000000000F1 :103FD00000000000000000000000000000000000E1 :103FE00000000000000000000000000000000000D1 :103FF00000000000000000000000000000000000C1 :1040000000000000000000000000000000000000B0 :1040100000000000000000000000000000000000A0 :104020000000000000000000000000000000000090 :104030000000000000000000000000000000000080 :104040000000000000000000000000000000000070 :104050000000000000000000000000000000000060 :104060000000000000000000000000000000000050 :104070000000000000000000000000000000000040 :104080000000000000000000000000000000000030 :104090000000000000000000000000000000000020 :1040A0000000000000000000000000000000000010 :1040B0000000000000000000000000000000000000 :1040C00000000000000000000000000000000000F0 :1040D00000000000000000000000000000000000E0 :1040E00000000000000000000000000000000000D0 :1040F00000000000000000000000000000000000C0 :1041000000000000000000000000000000000000AF :10411000000000000000000000000000000000009F :10412000000000000000000000000000000000008F :10413000000000000000000000000000000000007F :10414000000000000000000000000000000000006F :10415000000000000000000000000000000000005F :10416000000000000000000000000000000000004F :10417000000000000000000000000000000000003F :10418000000000000000000000000000000000002F :10419000000000000000000000000000000000001F :1041A000000000000000000000000000000000000F :1041B00000000000000000000000000000000000FF :1041C00000000000000000000000000000000000EF :1041D00000000000000000000000000000000000DF :1041E00000000000000000000000000000000000CF :1041F00000000000000000000000000000000000BF :1042000000000000000000000000000000000000AE :10421000000000000000000000000000000000009E :10422000000000000000000000000000000000008E :10423000000000000000000000000000000000007E :10424000000000000000000000000000000000006E :10425000000000000000000000000000000000005E :10426000000000000000000000000000000000004E :10427000000000000000000000000000000000003E :10428000000000000000000000000000000000002E :10429000000000000000000000000000000000001E :1042A000000000000000000000000000000000000E :1042B00000000000000000000000000000000000FE :1042C00000000000000000000000000000000000EE :1042D00000000000000000000000000000000000DE :1042E00000000000000000000000000000000000CE :1042F00000000000000000000000000000000000BE :1043000000000000000000000000000000000000AD :10431000000000000000000000000000000000009D :10432000000000000000000000000000000000008D :10433000000000000000000000000000000000007D :10434000000000000000000000000000000000006D :10435000000000000000000000000000000000005D :10436000000000000000000000000000000000004D :10437000000000000000000000000000000000003D :10438000000000000000000000000000000000002D :10439000000000000000000000000000000000001D :1043A000000000000000000000000000000000000D :1043B00000000000000000000000000000000000FD :1043C00000000000000000000000000000000000ED :1043D00000000000000000000000000000000000DD :1043E00000000000000000000000000000000000CD :1043F00000000000000000000000000000000000BD :1044000000000000000000000000000000000000AC :10441000000000000000000000000000000000009C :10442000000000000000000000000000000000008C :10443000000000000000000000000000000000007C :10444000000000000000000000000000000000006C :10445000000000000000000000000000000000005C :10446000000000000000000000000000000000004C :10447000000000000000000000000000000000003C :10448000000000000000000000000000000000002C :10449000000000000000000000000000000000001C :1044A000000000000000000000000000000000000C :1044B00000000000000000000000000000000000FC :1044C00000000000000000000000000000000000EC :1044D00000000000000000000000000000000000DC :1044E00000000000000000000000000000000000CC :1044F00000000000000000000000000000000000BC :1045000000000000000000000000000000000000AB :10451000000000000000000000000000000000009B :10452000000000000000000000000000000000008B :10453000000000000000000000000000000000007B :10454000000000000000000000000000000000006B :10455000000000000000000000000000000000005B :10456000000000000000000000000000000000004B :10457000000000000000000000000000000000003B :10458000000000000000000000000000000000002B :10459000000000000000000000000000000000001B :1045A000000000000000000000000000000000000B :1045B00000000000000000000000000000000000FB :1045C00000000000000000000000000000000000EB :1045D00000000000000000000000000000000000DB :1045E00000000000000000000000000000000000CB :1045F00000000000000000000000000000000000BB :1046000000000000000000000000000000000000AA :10461000000000000000000000000000000000009A :10462000000000000000000000000000000000008A :10463000000000000000000000000000000000007A :10464000000000000000000000000000000000006A :10465000000000000000000000000000000000005A :10466000000000000000000000000000000000004A :10467000000000000000000000000000000000003A :10468000000000000000000000000000000000002A :10469000000000000000000000000000000000001A :1046A000000000000000000000000000000000000A :1046B00000000000000000000000000000000000FA :1046C00000000000000000000000000000000000EA :1046D00000000000000000000000000000000000DA :1046E00000000000000000000000000000000000CA :1046F00000000000000000000000000000000000BA :1047000000000000000000000000000000000000A9 :104710000000000000000000000000000000000099 :104720000000000000000000000000000000000089 :104730000000000000000000000000000000000079 :104740000000000000000000000000000000000069 :104750000000000000000000000000000000000059 :104760000000000000000000000000000000000049 :104770000000000000000000000000000000000039 :104780000000000000000000000000000000000029 :104790000000000000000000000000000000000019 :1047A0000000000000000000000000000000000009 :1047B00000000000000000000000000000000000F9 :1047C00000000000000000000000000000000000E9 :1047D00000000000000000000000000000000000D9 :1047E00000000000000000000000000000000000C9 :1047F00000000000000000000000000000000000B9 :1048000000000000000000000000000000000000A8 :104810000000000000000000000000000000000098 :104820000000000000000000000000000000000088 :104830000000000000000000000000000000000078 :104840000000000000000000000000000000000068 :104850000000000000000000000000000000000058 :104860000000000000000000000000000000000048 :104870000000000000000000000000000000000038 :104880000000000000000000000000000000000028 :104890000000000000000000000000000000000018 :1048A0000000000000000000000000000000000008 :1048B00000000000000000000000000000000000F8 :1048C00000000000000000000000000000000000E8 :1048D00000000000000000000000000000000000D8 :1048E00000000000000000000000000000000000C8 :1048F00000000000000000000000000000000000B8 :1049000000000000000000000000000000000000A7 :104910000000000000000000000000000000000097 :104920000000000000000000000000000000000087 :104930000000000000000000000000000000000077 :104940000000000000000000000000000000000067 :104950000000000000000000000000000000000057 :104960000000000000000000000000000000000047 :104970000000000000000000000000000000000037 :104980000000000000000000000000000000000027 :104990000000000000000000000000000000000017 :1049A0000000000000000000000000000000000007 :1049B00000000000000000000000000000000000F7 :1049C00000000000000000000000000000000000E7 :1049D00000000000000000000000000000000000D7 :1049E00000000000000000000000000000000000C7 :1049F00000000000000000000000000000000000B7 :104A000000000000000000000000000000000000A6 :104A10000000000000000000000000000000000096 :104A20000000000000000000000000000000000086 :104A30000000000000000000000000000000000076 :104A40000000000000000000000000000000000066 :104A50000000000000000000000000000000000056 :104A60000000000000000000000000000000000046 :104A70000000000000000000000000000000000036 :104A80000000000000000000000000000000000026 :104A90000000000000000000000000000000000016 :104AA0000000000000000000000000000000000006 :104AB00000000000000000000000000000000000F6 :104AC00000000000000000000000000000000000E6 :104AD00000000000000000000000000000000000D6 :104AE00000000000000000000000000000000000C6 :104AF00000000000000000000000000000000000B6 :104B000000000000000000000000000000000000A5 :104B10000000000000000000000000000000000095 :104B20000000000000000000000000000000000085 :104B30000000000000000000000000000000000075 :104B40000000000000000000000000000000000065 :104B50000000000000000000000000000000000055 :104B60000000000000000000000000000000000045 :104B70000000000000000000000000000000000035 :104B80000000000000000000000000000000000025 :104B90000000000000000000000000000000000015 :104BA0000000000000000000000000000000000005 :104BB00000000000000000000000000000000000F5 :104BC00000000000000000000000000000000000E5 :104BD00000000000000000000000000000000000D5 :104BE00000000000000000000000000000000000C5 :104BF00000000000000000000000000000000000B5 :104C000000000000000000000000000000000000A4 :104C10000000000000000000000000000000000094 :104C20000000000000000000000000000000000084 :104C30000000000000000000000000000000000074 :104C40000000000000000000000000000000000064 :104C50000000000000000000000000000000000054 :104C60000000000000000000000000000000000044 :104C70000000000000000000000000000000000034 :104C80000000000000000000000000000000000024 :104C90000000000000000000000000000000000014 :104CA0000000000000000000000000000000000004 :104CB00000000000000000000000000000000000F4 :104CC00000000000000000000000000000000000E4 :104CD00000000000000000000000000000000000D4 :104CE00000000000000000000000000000000000C4 :104CF00000000000000000000000000000000000B4 :104D000000000000000000000000000000000000A3 :104D10000000000000000000000000000000000093 :104D20000000000000000000000000000000000083 :104D30000000000000000000000000000000000073 :104D40000000000000000000000000000000000063 :104D50000000000000000000000000000000000053 :104D60000000000000000000000000000000000043 :104D70000000000000000000000000000000000033 :104D80000000000000000000000000000000000023 :104D90000000000000000000000000000000000013 :104DA0000000000000000000000000000000000003 :104DB00000000000000000000000000000000000F3 :104DC00000000000000000000000000000000000E3 :104DD00000000000000000000000000000000000D3 :104DE00000000000000000000000000000000000C3 :104DF00000000000000000000000000000000000B3 :104E000000000000000000000000000000000000A2 :104E10000000000000000000000000000000000092 :104E20000000000000000000000000000000000082 :104E30000000000000000000000000000000000072 :104E40000000000000000000000000000000000062 :104E50000000000000000000000000000000000052 :104E60000000000000000000000000000000000042 :104E70000000000000000000000000000000000032 :104E80000000000000000000000000000000000022 :104E90000000000000000000000000000000000012 :104EA0000000000000000000000000000000000002 :104EB00000000000000000000000000000000000F2 :104EC00000000000000000000000000000000000E2 :104ED00000000000000000000000000000000000D2 :104EE00000000000000000000000000000000000C2 :104EF00000000000000000000000000000000000B2 :104F000000000000000000000000000000000000A1 :104F10000000000000000000000000000000000091 :104F20000000000000000000000000000000000081 :104F30000000000000000000000000000000000071 :104F40000000000000000000000000000000000061 :104F50000000000000000000000000000000000051 :104F60000000000000000000000000000000000041 :104F70000000000000000000000000000000000031 :104F80000000000000000000000000000000000021 :104F90000000000000000000000000000000000011 :104FA0000000000000000000000000000000000001 :104FB00000000000000000000000000000000000F1 :104FC00000000000000000000000000000000000E1 :104FD00000000000000000000000000000000000D1 :104FE00000000000000000000000000000000000C1 :104FF00000000000000000000000000000000000B1 :1050000000000000000000000000000000000000A0 :105010000000000000000000000000000000000090 :105020000000000000000000000000000000000080 :105030000000000000000000000000000000000070 :105040000000000000000000000000000000000060 :105050000000000000000000000000000000000050 :105060000000000000000000000000000000000040 :105070000000000000000000000000000000000030 :105080000000000000000000000000000000000020 :105090000000000000000000000000000000000010 :1050A0000000000000000000000000000000000000 :1050B00000000000000000000000000000000000F0 :1050C00000000000000000000000000000000000E0 :1050D00000000000000000000000000000000000D0 :1050E00000000000000000000000000000000000C0 :1050F00000000000000000000000000000000000B0 :10510000000000000000000000000000000000009F :10511000000000000000000000000000000000008F :10512000000000000000000000000000000000007F :10513000000000000000000000000000000000006F :10514000000000000000000000000000000000005F :10515000000000000000000000000000000000004F :10516000000000000000000000000000000000003F :10517000000000000000000000000000000000002F :10518000000000000000000000000000000000001F :10519000000000000000000000000000000000000F :1051A00000000000000000000000000000000000FF :1051B00000000000000000000000000000000000EF :1051C00000000000000000000000000000000000DF :1051D00000000000000000000000000000000000CF :1051E00000000000000000000000000000000000BF :1051F00000000000000000000000000000000000AF :10520000000000000000000000000000000000009E :10521000000000000000000000000000000000008E :10522000000000000000000000000000000000007E :10523000000000000000000000000000000000006E :10524000000000000000000000000000000000005E :10525000000000000000000000000000000000004E :10526000000000000000000000000000000000003E :10527000000000000000000000000000000000002E :10528000000000000000000000000000000000001E :10529000000000000000000000000000000000000E :1052A00000000000000000000000000000000000FE :1052B00000000000000000000000000000000000EE :1052C00000000000000000000000000000000000DE :1052D00000000000000000000000000000000000CE :1052E00000000000000000000000000000000000BE :1052F00000000000000000000000000000000000AE :10530000000000000000000000000000000000009D :10531000000000000000000000000000000000008D :10532000000000000000000000000000000000007D :10533000000000000000000000000000000000006D :10534000000000000000000000000000000000005D :10535000000000000000000000000000000000004D :10536000000000000000000000000000000000003D :10537000000000000000000000000000000000002D :10538000000000000000000000000000000000001D :10539000000000000000000000000000000000000D :1053A00000000000000000000000000000000000FD :1053B00000000000000000000000000000000000ED :1053C00000000000000000000000000000000000DD :1053D00000000000000000000000000000000000CD :1053E00000000000000000000000000000000000BD :1053F00000000000000000000000000000000000AD :10540000000000000000000000000000000000009C :10541000000000000000000000000000000000008C :10542000000000000000000000000000000000007C :10543000000000000000000000000000000000006C :10544000000000000000000000000000000000005C :10545000000000000000000000000000000000004C :10546000000000000000000000000000000000003C :10547000000000000000000000000000000000002C :10548000000000000000000000000000000000001C :10549000000000000000000000000000000000000C :1054A00000000000000000000000000000000000FC :1054B00000000000000000000000000000000000EC :1054C00000000000000000000000000000000000DC :1054D00000000000000000000000000000000000CC :1054E00000000000000000000000000000000000BC :1054F00000000000000000000000000000000000AC :10550000000000000000000000000000000000009B :10551000000000000000000000000000000000008B :10552000000000000000000000000000000000007B :10553000000000000000000000000000000000006B :10554000000000000000000000000000000000005B :10555000000000000000000000000000000000004B :10556000000000000000000000000000000000003B :10557000000000000000000000000000000000002B :10558000000000000000000000000000000000001B :10559000000000000000000000000000000000000B :1055A00000000000000000000000000000000000FB :1055B00000000000000000000000000000000000EB :1055C00000000000000000000000000000000000DB :1055D00000000000000000000000000000000000CB :1055E00000000000000000000000000000000000BB :1055F00000000000000000000000000000000000AB :10560000000000000000000000000000000000009A :10561000000000000000000000000000000000008A :10562000000000000000000000000000000000007A :10563000000000000000000000000000000000006A :10564000000000000000000000000000000000005A :10565000000000000000000000000000000000004A :10566000000000000000000000000000000000003A :10567000000000000000000000000000000000002A :10568000000000000000000000000000000000001A :10569000000000000000000000000000000000000A :1056A00000000000000000000000000000000000FA :1056B00000000000000000000000000000000000EA :1056C00000000000000000000000000000000000DA :1056D00000000000000000000000000000000000CA :1056E00000000000000000000000000000000000BA :1056F00000000000000000000000000000000000AA :105700000000000000000000000000000000000099 :105710000000000000000000000000000000000089 :105720000000000000000000000000000000000079 :105730000000000000000000000000000000000069 :105740000000000000000000000000000000000059 :105750000000000000000000000000000000000049 :105760000000000000000000000000000000000039 :105770000000000000000000000000000000000029 :105780000000000000000000000000000000000019 :105790000000000000000000000000000000000009 :1057A00000000000000000000000000000000000F9 :1057B00000000000000000000000000000000000E9 :1057C00000000000000000000000000000000000D9 :1057D00000000000000000000000000000000000C9 :1057E00000000000000000000000000000000000B9 :1057F00000000000000000000000000000000000A9 :105800000000000000000000000000000000000098 :105810000000000000000000000000000000000088 :105820000000000000000000000000000000000078 :105830000000000000000000000000000000000068 :105840000000000000000000000000000000000058 :105850000000000000000000000000000000000048 :105860000000000000000000000000000000000038 :105870000000000000000000000000000000000028 :105880000000000000000000000000000000000018 :105890000000000000000000000000000000000008 :1058A00000000000000000000000000000000000F8 :1058B00000000000000000000000000000000000E8 :1058C00000000000000000000000000000000000D8 :1058D00000000000000000000000000000000000C8 :1058E00000000000000000000000000000000000B8 :1058F00000000000000000000000000000000000A8 :105900000000000000000000000000000000000097 :105910000000000000000000000000000000000087 :105920000000000000000000000000000000000077 :105930000000000000000000000000000000000067 :105940000000000000000000000000000000000057 :105950000000000000000000000000000000000047 :105960000000000000000000000000000000000037 :105970000000000000000000000000000000000027 :105980000000000000000000000000000000000017 :105990000000000000000000000000000000000007 :1059A00000000000000000000000000000000000F7 :1059B00000000000000000000000000000000000E7 :1059C00000000000000000000000000000000000D7 :1059D00000000000000000000000000000000000C7 :1059E00000000000000000000000000000000000B7 :1059F00000000000000000000000000000000000A7 :105A00000000000000000000000000000000000096 :105A10000000000000000000000000000000000086 :105A20000000000000000000000000000000000076 :105A30000000000000000000000000000000000066 :105A40000000000000000000000000000000000056 :105A50000000000000000000000000000000000046 :105A60000000000000000000000000000000000036 :105A70000000000000000000000000000000000026 :105A80000000000000000000000000000000000016 :105A90000000000000000000000000000000000006 :105AA00000000000000000000000000000000000F6 :105AB00000000000000000000000000000000000E6 :105AC00000000000000000000000000000000000D6 :105AD00000000000000000000000000000000000C6 :105AE00000000000000000000000000000000000B6 :105AF00000000000000000000000000000000000A6 :105B00000000000000000000000000000000000095 :105B10000000000000000000000000000000000085 :105B20000000000000000000000000000000000075 :105B30000000000000000000000000000000000065 :105B40000000000000000000000000000000000055 :105B50000000000000000000000000000000000045 :105B60000000000000000000000000000000000035 :105B70000000000000000000000000000000000025 :105B80000000000000000000000000000000000015 :105B90000000000000000000000000000000000005 :105BA00000000000000000000000000000000000F5 :105BB00000000000000000000000000000000000E5 :105BC00000000000000000000000000000000000D5 :105BD00000000000000000000000000000000000C5 :105BE00000000000000000000000000000000000B5 :105BF00000000000000000000000000000000000A5 :105C00000000000000000000000000000000000094 :105C10000000000000000000000000000000000084 :105C20000000000000000000000000000000000074 :105C30000000000000000000000000000000000064 :105C40000000000000000000000000000000000054 :105C50000000000000000000000000000000000044 :105C60000000000000000000000000000000000034 :105C70000000000000000000000000000000000024 :105C80000000000000000000000000000000000014 :105C90000000000000000000000000000000000004 :105CA00000000000000000000000000000000000F4 :105CB00000000000000000000000000000000000E4 :105CC00000000000000000000000000000000000D4 :105CD00000000000000000000000000000000000C4 :105CE00000000000000000000000000000000000B4 :105CF00000000000000000000000000000000000A4 :105D00000000000000000000000000000000000093 :105D10000000000000000000000000000000000083 :105D20000000000000000000000000000000000073 :105D30000000000000000000000000000000000063 :105D40000000000000000000000000000000000053 :105D50000000000000000000000000000000000043 :105D60000000000000000000000000000000000033 :105D70000000000000000000000000000000000023 :105D80000000000000000000000000000000000013 :105D90000000000000000000000000000000000003 :105DA00000000000000000000000000000000000F3 :105DB00000000000000000000000000000000000E3 :105DC00000000000000000000000000000000000D3 :105DD00000000000000000000000000000000000C3 :105DE00000000000000000000000000000000000B3 :105DF00000000000000000000000000000000000A3 :105E00000000000000000000000000000000000092 :105E10000000000000000000000000000000000082 :105E20000000000000000000000000000000000072 :105E30000000000000000000000000000000000062 :105E40000000000000000000000000000000000052 :105E50000000000000000000000000000000000042 :105E60000000000000000000000000000000000032 :105E70000000000000000000000000000000000022 :105E80000000000000000000000000000000000012 :105E90000000000000000000000000000000000002 :105EA00000000000000000000000000000000000F2 :105EB00000000000000000000000000000000000E2 :105EC00000000000000000000000000000000000D2 :105ED00000000000000000000000000000000000C2 :105EE00000000000000000000000000000000000B2 :105EF00000000000000000000000000000000000A2 :105F00000000000000000000000000000000000091 :105F10000000000000000000000000000000000081 :105F20000000000000000000000000000000000071 :105F30000000000000000000000000000000000061 :105F40000000000000000000000000000000000051 :105F50000000000000000000000000000000000041 :105F60000000000000000000000000000000000031 :105F70000000000000000000000000000000000021 :105F80000000000000000000000000000000000011 :105F90000000000000000000000000000000000001 :105FA00000000000000000000000000000000000F1 :105FB00000000000000000000000000000000000E1 :105FC00000000000000000000000000000000000D1 :105FD00000000000000000000000000000000000C1 :105FE00000000000000000000000000000000000B1 :105FF00000000000000000000000000000000000A1 :106000000000000000000000000000000000000090 :106010000000000000000000000000000000000080 :106020000000000000000000000000000000000070 :106030000000000000000000000000000000000060 :106040000000000000000000000000000000000050 :106050000000000000000000000000000000000040 :106060000000000000000000000000000000000030 :106070000000000000000000000000000000000020 :106080000000000000000000000000000000000010 :106090000000000000000000000000000000000000 :1060A00000000000000000000000000000000000F0 :1060B00000000000000000000000000000000000E0 :1060C00000000000000000000000000000000000D0 :1060D00000000000000000000000000000000000C0 :1060E00000000000000000000000000000000000B0 :1060F00000000000000000000000000000000000A0 :10610000000000000000000000000000000000008F :10611000000000000000000000000000000000007F :10612000000000000000000000000000000000006F :10613000000000000000000000000000000000005F :10614000000000000000000000000000000000004F :10615000000000000000000000000000000000003F :10616000000000000000000000000000000000002F :10617000000000000000000000000000000000001F :10618000000000000000000000000000000000000F :1061900000000000000000000000000000000000FF :1061A00000000000000000000000000000000000EF :1061B00000000000000000000000000000000000DF :1061C00000000000000000000000000000000000CF :1061D00000000000000000000000000000000000BF :1061E00000000000000000000000000000000000AF :1061F000000000000000000000000000000000009F :10620000000000000000000000000000000000008E :10621000000000000000000000000000000000007E :10622000000000000000000000000000000000006E :10623000000000000000000000000000000000005E :10624000000000000000000000000000000000004E :10625000000000000000000000000000000000003E :10626000000000000000000000000000000000002E :10627000000000000000000000000000000000001E :10628000000000000000000000000000000000000E :1062900000000000000000000000000000000000FE :1062A00000000000000000000000000000000000EE :1062B00000000000000000000000000000000000DE :1062C00000000000000000000000000000000000CE :1062D00000000000000000000000000000000000BE :1062E00000000000000000000000000000000000AE :1062F000000000000000000000000000000000009E :10630000000000000000000000000000000000008D :10631000000000000000000000000000000000007D :10632000000000000000000000000000000000006D :10633000000000000000000000000000000000005D :10634000000000000000000000000000000000004D :10635000000000000000000000000000000000003D :10636000000000000000000000000000000000002D :10637000000000000000000000000000000000001D :10638000000000000000000000000000000000000D :1063900000000000000000000000000000000000FD :1063A00000000000000000000000000000000000ED :1063B00000000000000000000000000000000000DD :1063C00000000000000000000000000000000000CD :1063D00000000000000000000000000000000000BD :1063E00000000000000000000000000000000000AD :1063F000000000000000000000000000000000009D :10640000000000000000000000000000000000008C :10641000000000000000000000000000000000007C :10642000000000000000000000000000000000006C :10643000000000000000000000000000000000005C :10644000000000000000000000000000000000004C :10645000000000000000000000000000000000003C :10646000000000000000000000000000000000002C :10647000000000000000000000000000000000001C :10648000000000000000000000000000000000000C :1064900000000000000000000000000000000000FC :1064A00000000000000000000000000000000000EC :1064B00000000000000000000000000000000000DC :1064C00000000000000000000000000000000000CC :1064D00000000000000000000000000000000000BC :1064E00000000000000000000000000000000000AC :1064F000000000000000000000000000000000009C :10650000000000000000000000000000000000008B :10651000000000000000000000000000000000007B :10652000000000000000000000000000000000006B :10653000000000000000000000000000000000005B :10654000000000000000000000000000000000004B :10655000000000000000000000000000000000003B :10656000000000000000000000000000000000002B :10657000000000000000000000000000000000001B :10658000000000000000000000000000000000000B :1065900000000000000000000000000000000000FB :1065A00000000000000000000000000000000000EB :1065B00000000000000000000000000000000000DB :1065C00000000000000000000000000000000000CB :1065D00000000000000000000000000000000000BB :1065E00000000000000000000000000000000000AB :1065F000000000000000000000000000000000009B :10660000000000000000000000000000000000008A :10661000000000000000000000000000000000007A :10662000000000000000000000000000000000006A :10663000000000000000000000000000000000005A :10664000000000000000000000000000000000004A :10665000000000000000000000000000000000003A :10666000000000000000000000000000000000002A :10667000000000000000000000000000000000001A :10668000000000000000000000000000000000000A :1066900000000000000000000000000000000000FA :1066A00000000000000000000000000000000000EA :1066B00000000000000000000000000000000000DA :1066C00000000000000000000000000000000000CA :1066D00000000000000000000000000000000000BA :1066E00000000000000000000000000000000000AA :1066F000000000000000000000000000000000009A :106700000000000000000000000000000000000089 :106710000000000000000000000000000000000079 :106720000000000000000000000000000000000069 :106730000000000000000000000000000000000059 :106740000000000000000000000000000000000049 :106750000000000000000000000000000000000039 :106760000000000000000000000000000000000029 :106770000000000000000000000000000000000019 :106780000000000000000000000000000000000009 :1067900000000000000000000000000000000000F9 :1067A00000000000000000000000000000000000E9 :1067B00000000000000000000000000000000000D9 :1067C00000000000000000000000000000000000C9 :1067D00000000000000000000000000000000000B9 :1067E00000000000000000000000000000000000A9 :1067F0000000000000000000000000000000000099 :106800000000000000000000000000000000000088 :106810000000000000000000000000000000000078 :106820000000000000000000000000000000000068 :106830000000000000000000000000000000000058 :106840000000000000000000000000000000000048 :106850000000000000000000000000000000000038 :106860000000000000000000000000000000000028 :106870000000000000000000000000000000000018 :106880000000000000000000000000000000000008 :1068900000000000000000000000000000000000F8 :1068A00000000000000000000000000000000000E8 :1068B00000000000000000000000000000000000D8 :1068C00000000000000000000000000000000000C8 :1068D00000000000000000000000000000000000B8 :1068E00000000000000000000000000000000000A8 :1068F0000000000000000000000000000000000098 :106900000000000000000000000000000000000087 :106910000000000000000000000000000000000077 :106920000000000000000000000000000000000067 :106930000000000000000000000000000000000057 :106940000000000000000000000000000000000047 :106950000000000000000000000000000000000037 :106960000000000000000000000000000000000027 :106970000000000000000000000000000000000017 :106980000000000000000000000000000000000007 :1069900000000000000000000000000000000000F7 :1069A00000000000000000000000000000000000E7 :1069B00000000000000000000000000000000000D7 :1069C00000000000000000000000000000000000C7 :1069D00000000000000000000000000000000000B7 :1069E00000000000000000000000000000000000A7 :1069F0000000000000000000000000000000000097 :106A00000000000000000000000000000000000086 :106A10000000000000000000000000000000000076 :106A20000000000000000000000000000000000066 :106A30000000000000000000000000000000000056 :106A40000000000000000000000000000000000046 :106A50000000000000000000000000000000000036 :106A60000000000000000000000000000000000026 :106A70000000000000000000000000000000000016 :106A80000000000000000000000000000000000006 :106A900000000000000000000000000000000000F6 :106AA00000000000000000000000000000000000E6 :106AB00000000000000000000000000000000000D6 :106AC00000000000000000000000000000000000C6 :106AD00000000000000000000000000000000000B6 :106AE00000000000000000000000000000000000A6 :106AF0000000000000000000000000000000000096 :106B00000000000000000000000000000000000085 :106B10000000000000000000000000000000000075 :106B20000000000000000000000000000000000065 :106B30000000000000000000000000000000000055 :106B40000000000000000000000000000000000045 :106B50000000000000000000000000000000000035 :106B60000000000000000000000000000000000025 :106B70000000000000000000000000000000000015 :106B80000000000000000000000000000000000005 :106B900000000000000000000000000000000000F5 :106BA00000000000000000000000000000000000E5 :106BB00000000000000000000000000000000000D5 :106BC00000000000000000000000000000000000C5 :106BD00000000000000000000000000000000000B5 :106BE00000000000000000000000000000000000A5 :106BF0000000000000000000000000000000000095 :106C00000000000000000000000000000000000084 :106C10000000000000000000000000000000000074 :106C20000000000000000000000000000000000064 :106C30000000000000000000000000000000000054 :106C40000000000000000000000000000000000044 :106C50000000000000000000000000000000000034 :106C60000000000000000000000000000000000024 :106C70000000000000000000000000000000000014 :106C80000000000000000000000000000000000004 :106C900000000000000000000000000000000000F4 :106CA00000000000000000000000000000000000E4 :106CB00000000000000000000000000000000000D4 :106CC00000000000000000000000000000000000C4 :106CD00000000000000000000000000000000000B4 :106CE00000000000000000000000000000000000A4 :106CF0000000000000000000000000000000000094 :106D00000000000000000000000000000000000083 :106D10000000000000000000000000000000000073 :106D20000000000000000000000000000000000063 :106D30000000000000000000000000000000000053 :106D40000000000000000000000000000000000043 :106D50000000000000000000000000000000000033 :106D60000000000000000000000000000000000023 :106D70000000000000000000000000000000000013 :106D80000000000000000000000000000000000003 :106D900000000000000000000000000000000000F3 :106DA00000000000000000000000000000000000E3 :106DB00000000000000000000000000000000000D3 :106DC00000000000000000000000000000000000C3 :106DD00000000000000000000000000000000000B3 :106DE00000000000000000000000000000000000A3 :106DF0000000000000000000000000000000000093 :106E00000000000000000000000000000000000082 :106E10000000000000000000000000000000000072 :106E20000000000000000000000000000000000062 :106E30000000000000000000000000000000000052 :106E40000000000000000000000000000000000042 :106E50000000000000000000000000000000000032 :106E60000000000000000000000000000000000022 :106E70000000000000000000000000000000000012 :106E80000000000000000000000000000000000002 :106E900000000000000000000000000000000000F2 :106EA00000000000000000000000000000000000E2 :106EB00000000000000000000000000000000000D2 :106EC00000000000000000000000000000000000C2 :106ED00000000000000000000000000000000000B2 :106EE00000000000000000000000000000000000A2 :106EF0000000000000000000000000000000000092 :106F00000000000000000000000000000000000081 :106F10000000000000000000000000000000000071 :106F20000000000000000000000000000000000061 :106F30000000000000000000000000000000000051 :106F40000000000000000000000000000000000041 :106F50000000000000000000000000000000000031 :106F60000000000000000000000000000000000021 :106F70000000000000000000000000000000000011 :106F80000000000000000000000000000000000001 :106F900000000000000000000000000000000000F1 :106FA00000000000000000000000000000000000E1 :106FB00000000000000000000000000000000000D1 :106FC00000000000000000000000000000000000C1 :106FD00000000000000000000000000000000000B1 :106FE00000000000000000000000000000000000A1 :106FF0000000000000000000000000000000000091 :107000000000000000000000000000000000000080 :107010000000000000000000000000000000000070 :107020000000000000000000000000000000000060 :107030000000000000000000000000000000000050 :107040000000000000000000000000000000000040 :107050000000000000000000000000000000000030 :107060000000000000000000000000000000000020 :107070000000000000000000000000000000000010 :107080000000000000000000000000000000000000 :1070900000000000000000000000000000000000F0 :1070A00000000000000000000000000000000000E0 :1070B00000000000000000000000000000000000D0 :1070C00000000000000000000000000000000000C0 :1070D00000000000000000000000000000000000B0 :1070E00000000000000000000000000000000000A0 :1070F0000000000000000000000000000000000090 :10710000000000000000000000000000000000007F :10711000000000000000000000000000000000006F :10712000000000000000000000000000000000005F :10713000000000000000000000000000000000004F :10714000000000000000000000000000000000003F :10715000000000000000000000000000000000002F :10716000000000000000000000000000000000001F :10717000000000000000000000000000000000000F :1071800000000000000000000000000000000000FF :1071900000000000000000000000000000000000EF :1071A00000000000000000000000000000000000DF :1071B00000000000000000000000000000000000CF :1071C00000000000000000000000000000000000BF :1071D00000000000000000000000000000000000AF :1071E000000000000000000000000000000000009F :1071F000000000000000000000000000000000008F :10720000000000000000000000000000000000007E :10721000000000000000000000000000000000006E :10722000000000000000000000000000000000005E :10723000000000000000000000000000000000004E :10724000000000000000000000000000000000003E :10725000000000000000000000000000000000002E :10726000000000000000000000000000000000001E :10727000000000000000000000000000000000000E :1072800000000000000000000000000000000000FE :1072900000000000000000000000000000000000EE :1072A00000000000000000000000000000000000DE :1072B00000000000000000000000000000000000CE :1072C00000000000000000000000000000000000BE :1072D00000000000000000000000000000000000AE :1072E000000000000000000000000000000000009E :1072F000000000000000000000000000000000008E :10730000000000000000000000000000000000007D :10731000000000000000000000000000000000006D :10732000000000000000000000000000000000005D :10733000000000000000000000000000000000004D :10734000000000000000000000000000000000003D :10735000000000000000000000000000000000002D :10736000000000000000000000000000000000001D :10737000000000000000000000000000000000000D :1073800000000000000000000000000000000000FD :1073900000000000000000000000000000000000ED :1073A00000000000000000000000000000000000DD :1073B00000000000000000000000000000000000CD :1073C00000000000000000000000000000000000BD :1073D00000000000000000000000000000000000AD :1073E000000000000000000000000000000000009D :1073F000000000000000000000000000000000008D :10740000000000000000000000000000000000007C :10741000000000000000000000000000000000006C :10742000000000000000000000000000000000005C :10743000000000000000000000000000000000004C :10744000000000000000000000000000000000003C :10745000000000000000000000000000000000002C :10746000000000000000000000000000000000001C :10747000000000000000000000000000000000000C :1074800000000000000000000000000000000000FC :1074900000000000000000000000000000000000EC :1074A00000000000000000000000000000000000DC :1074B00000000000000000000000000000000000CC :1074C00000000000000000000000000000000000BC :1074D00000000000000000000000000000000000AC :1074E000000000000000000000000000000000009C :1074F000000000000000000000000000000000008C :10750000000000000000000000000000000000007B :10751000000000000000000000000000000000006B :10752000000000000000000000000000000000005B :10753000000000000000000000000000000000004B :10754000000000000000000000000000000000003B :10755000000000000000000000000000000000002B :10756000000000000000000000000000000000001B :10757000000000000000000000000000000000000B :1075800000000000000000000000000000000000FB :1075900000000000000000000000000000000000EB :1075A00000000000000000000000000000000000DB :1075B00000000000000000000000000000000000CB :1075C00000000000000000000000000000000000BB :1075D00000000000000000000000000000000000AB :1075E000000000000000000000000000000000009B :1075F000000000000000000000000000000000008B :10760000000000000000000000000000000000007A :10761000000000000000000000000000000000006A :10762000000000000000000000000000000000005A :10763000000000000000000000000000000000004A :10764000000000000000000000000000000000003A :10765000000000000000000000000000000000002A :10766000000000000000000000000000000000001A :10767000000000000000000000000000000000000A :1076800000000000000000000000000000000000FA :1076900000000000000000000000000000000000EA :1076A00000000000000000000000000000000000DA :1076B00000000000000000000000000000000000CA :1076C00000000000000000000000000000000000BA :1076D00000000000000000000000000000000000AA :1076E000000000000000000000000000000000009A :1076F000000000000000000000000000000000008A :107700000000000000000000000000000000000079 :107710000000000000000000000000000000000069 :107720000000000000000000000000000000000059 :107730000000000000000000000000000000000049 :107740000000000000000000000000000000000039 :107750000000000000000000000000000000000029 :107760000000000000000000000000000000000019 :107770000000000000000000000000000000000009 :1077800000000000000000000000000000000000F9 :1077900000000000000000000000000000000000E9 :1077A00000000000000000000000000000000000D9 :1077B00000000000000000000000000000000000C9 :1077C00000000000000000000000000000000000B9 :1077D00000000000000000000000000000000000A9 :1077E0000000000000000000000000000000000099 :1077F0000000000000000000000000000000000089 :107800000000000000000000000000000000000078 :107810000000000000000000000000000000000068 :107820000000000000000000000000000000000058 :107830000000000000000000000000000000000048 :107840000000000000000000000000000000000038 :107850000000000000000000000000000000000028 :107860000000000000000000000000000000000018 :107870000000000000000000000000000000000008 :1078800000000000000000000000000000000000F8 :1078900000000000000000000000000000000000E8 :1078A00000000000000000000000000000000000D8 :1078B00000000000000000000000000000000000C8 :1078C00000000000000000000000000000000000B8 :1078D00000000000000000000000000000000000A8 :1078E0000000000000000000000000000000000098 :1078F0000000000000000000000000000000000088 :107900000000000000000000000000000000000077 :107910000000000000000000000000000000000067 :107920000000000000000000000000000000000057 :107930000000000000000000000000000000000047 :107940000000000000000000000000000000000037 :107950000000000000000000000000000000000027 :107960000000000000000000000000000000000017 :107970000000000000000000000000000000000007 :1079800000000000000000000000000000000000F7 :1079900000000000000000000000000000000000E7 :1079A00000000000000000000000000000000000D7 :1079B00000000000000000000000000000000000C7 :1079C00000000000000000000000000000000000B7 :1079D00000000000000000000000000000000000A7 :1079E0000000000000000000000000000000000097 :1079F0000000000000000000000000000000000087 :107A00000000000000000000000000000000000076 :107A10000000000000000000000000000000000066 :107A20000000000000000000000000000000000056 :107A30000000000000000000000000000000000046 :107A40000000000000000000000000000000000036 :107A50000000000000000000000000000000000026 :107A60000000000000000000000000000000000016 :107A70000000000000000000000000000000000006 :107A800000000000000000000000000000000000F6 :107A900000000000000000000000000000000000E6 :107AA00000000000000000000000000000000000D6 :107AB00000000000000000000000000000000000C6 :107AC00000000000000000000000000000000000B6 :107AD00000000000000000000000000000000000A6 :107AE0000000000000000000000000000000000096 :107AF0000000000000000000000000000000000086 :107B00000000000000000000000000000000000075 :107B10000000000000000000000000000000000065 :107B20000000000000000000000000000000000055 :107B30000000000000000000000000000000000045 :107B40000000000000000000000000000000000035 :107B50000000000000000000000000000000000025 :107B60000000000000000000000000000000000015 :107B70000000000000000000000000000000000005 :107B800000000000000000000000000000000000F5 :107B900000000000000000000000000000000000E5 :107BA00000000000000000000000000000000000D5 :107BB00000000000000000000000000000000000C5 :107BC00000000000000000000000000000000000B5 :107BD00000000000000000000000000000000000A5 :107BE0000000000000000000000000000000000095 :107BF0000000000000000000000000000000000085 :107C00000000000000000000000000000000000074 :107C10000000000000000000000000000000000064 :107C20000000000000000000000000000000000054 :107C30000000000000000000000000000000000044 :107C40000000000000000000000000000000000034 :107C50000000000000000000000000000000000024 :107C60000000000000000000000000000000000014 :107C70000000000000000000000000000000000004 :107C800000000000000000000000000000000000F4 :107C900000000000000000000000000000000000E4 :107CA00000000000000000000000000000000000D4 :107CB00000000000000000000000000000000000C4 :107CC00000000000000000000000000000000000B4 :107CD00000000000000000000000000000000000A4 :107CE0000000000000000000000000000000000094 :107CF0000000000000000000000000000000000084 :107D00000000000000000000000000000000000073 :107D10000000000000000000000000000000000063 :107D20000000000000000000000000000000000053 :107D30000000000000000000000000000000000043 :107D40000000000000000000000000000000000033 :107D50000000000000000000000000000000000023 :107D60000000000000000000000000000000000013 :107D70000000000000000000000000000000000003 :107D800000000000000000000000000000000000F3 :107D900000000000000000000000000000000000E3 :107DA00000000000000000000000000000000000D3 :107DB00000000000000000000000000000000000C3 :107DC00000000000000000000000000000000000B3 :107DD00000000000000000000000000000000000A3 :107DE0000000000000000000000000000000000093 :107DF0000000000000000000000000000000000083 :107E00000000000000000000000000000000000072 :107E10000000000000000000000000000000000062 :107E20000000000000000000000000000000000052 :107E30000000000000000000000000000000000042 :107E40000000000000000000000000000000000032 :107E50000000000000000000000000000000000022 :107E60000000000000000000000000000000000012 :107E70000000000000000000000000000000000002 :107E800000000000000000000000000000000000F2 :107E900000000000000000000000000000000000E2 :107EA00000000000000000000000000000000000D2 :107EB00000000000000000000000000000000000C2 :107EC00000000000000000000000000000000000B2 :107ED00000000000000000000000000000000000A2 :107EE0000000000000000000000000000000000092 :107EF0000000000000000000000000000000000082 :107F00000000000000000000000000000000000071 :107F10000000000000000000000000000000000061 :107F20000000000000000000000000000000000051 :107F30000000000000000000000000000000000041 :107F40000000000000000000000000000000000031 :107F50000000000000000000000000000000000021 :107F60000000000000000000000000000000000011 :107F70000000000000000000000000000000000001 :107F800000000000000000000000000000000000F1 :107F900000000000000000000000000000000000E1 :107FA00000000000000000000000000000000000D1 :107FB00000000000000000000000000000000000C1 :107FC00000000000000000000000000000000000B1 :107FD00000000000000000000000000000000000A1 :107FE0000000000000000000000000000000000091 :107FF0000000000000000000000000000000000081 :108000000000000000000000000000000000000070 :108010000000000000000000000000000000000060 :108020000000000000000000000000000000000050 :108030000000000000000000000000000000000040 :108040000000000000000000000000000000000030 :108050000000000000000000000000000000000020 :108060000000000000000000000000000000000010 :108070000000000000000000000000000000000000 :1080800000000000000000000000000000000000F0 :1080900000000000000000000000000000000000E0 :1080A00000000000000000000000000000000000D0 :1080B00000000000000000000000000000000000C0 :1080C00000000000000000000000000000000000B0 :1080D00000000000000000000000000000000000A0 :1080E0000000000000000000000000000000000090 :1080F0000000000000000000000000000000000080 :10810000000000000000000000000000000000006F :10811000000000000000000000000000000000005F :10812000000000000000000000000000000000004F :10813000000000000000000000000000000000003F :10814000000000000000000000000000000000002F :10815000000000000000000000000000000000001F :10816000000000000000000000000000000000000F :1081700000000000000000000000000000000000FF :1081800000000000000000000000000000000000EF :1081900000000000000000000000000000000000DF :1081A00000000000000000000000000000000000CF :1081B00000000000000000000000000000000000BF :1081C00000000000000000000000000000000000AF :1081D000000000000000000000000000000000009F :1081E000000000000000000000000000000000008F :1081F000000000000000000000000000000000007F :10820000000000000000000000000000000000006E :10821000000000000000000000000000000000005E :10822000000000000000000000000000000000004E :10823000000000000000000000000000000000003E :10824000000000000000000000000000000000002E :10825000000000000000000000000000000000001E :10826000000000000000000000000000000000000E :1082700000000000000000000000000000000000FE :1082800000000000000000000000000000000000EE :1082900000000000000000000000000000000000DE :1082A00000000000000000000000000000000000CE :1082B00000000000000000000000000000000000BE :1082C00000000000000000000000000000000000AE :1082D000000000000000000000000000000000009E :1082E000000000000000000000000000000000008E :1082F000000000000000000000000000000000007E :10830000000000000000000000000000000000006D :10831000000000000000000000000000000000005D :10832000000000000000000000000000000000004D :10833000000000000000000000000000000000003D :10834000000000000000000000000000000000002D :10835000000000000000000000000000000000001D :10836000000000000000000000000000000000000D :1083700000000000000000000000000000000000FD :1083800000000000000000000000000000000000ED :1083900000000000000000000000000000000000DD :1083A00000000000000000000000000000000000CD :1083B00000000000000000000000000000000000BD :1083C00000000000000000000000000000000000AD :1083D000000000000000000000000000000000009D :1083E000000000000000000000000000000000008D :1083F000000000000000000000000000000000007D :10840000000000000000000000000000000000006C :10841000000000000000000000000000000000005C :10842000000000000000000000000000000000004C :10843000000000000000000000000000000000003C :10844000000000000000000000000000000000002C :10845000000000000000000000000000000000001C :10846000000000000000000000000000000000000C :1084700000000000000000000000000000000000FC :1084800000000000000000000000000000000000EC :1084900000000000000000000000000000000000DC :1084A00000000000000000000000000000000000CC :1084B00000000000000000000000000000000000BC :1084C00000000000000000000000000000000000AC :1084D000000000000000000000000000000000009C :1084E000000000000000000000000000000000008C :1084F000000000000000000000000000000000007C :10850000000000000000000000000000000000006B :10851000000000000000000000000000000000005B :10852000000000000000000000000000000000004B :10853000000000000000000000000000000000003B :10854000000000000000000000000000000000002B :10855000000000000000000000000000000000001B :10856000000000000000000000000000000000000B :1085700000000000000000000000000000000000FB :1085800000000000000000000000000000000000EB :1085900000000000000000000000000000000000DB :1085A00000000000000000000000000000000000CB :1085B00000000000000000000000000000000000BB :1085C00000000000000000000000000000000000AB :1085D000000000000000000000000000000000009B :1085E000000000000000000000000000000000008B :1085F000000000000000000000000000000000007B :10860000000000000000000000000000000000006A :10861000000000000000000000000000000000005A :10862000000000000000000000000000000000004A :10863000000000000000000000000000000000003A :10864000000000000000000000000000000000002A :10865000000000000000000000000000000000001A :10866000000000000000000000000000000000000A :1086700000000000000000000000000000000000FA :1086800000000000000000000000000000000000EA :1086900000000000000000000000000000000000DA :1086A00000000000000000000000000000000000CA :1086B00000000000000000000000000000000000BA :1086C00000000000000000000000000000000000AA :1086D000000000000000000000000000000000009A :1086E000000000000000000000000000000000008A :1086F000000000000000000000000000000000007A :108700000000000000000000000000000000000069 :108710000000000000000000000000000000000059 :108720000000000000000000000000000000000049 :108730000000000000000000000000000000000039 :108740000000000000000000000000000000000029 :108750000000000000000000000000000000000019 :108760000000000000000000000000000000000009 :1087700000000000000000000000000000000000F9 :1087800000000000000000000000000000000000E9 :1087900000000000000000000000000000000000D9 :1087A00000000000000000000000000000000000C9 :1087B00000000000000000000000000000000000B9 :1087C00000000000000000000000000000000000A9 :1087D0000000000000000000000000000000000099 :1087E0000000000000000000000000000000000089 :1087F0000000000000000000000000000000000079 :108800000000000000000000000000000000000068 :108810000000000000000000000000000000000058 :108820000000000000000000000000000000000048 :108830000000000000000000000000000000000038 :108840000000000000000000000000000000000028 :108850000000000000000000000000000000000018 :108860000000000000000000000000000000000008 :1088700000000000000000000000000000000000F8 :1088800000000000000000000000000000000000E8 :1088900000000000000000000000000000000000D8 :1088A00000000000000000000000000000000000C8 :1088B00000000000000000000000000000000000B8 :1088C00000000000000000000000000000000000A8 :1088D0000000000000000000000000000000000098 :1088E0000000000000000000000000000000000088 :1088F0000000000000000000000000000000000078 :108900000000000000000000000000000000000067 :108910000000000000000000000000000000000057 :108920000000000000000000000000000000000047 :108930000000000000000000000000000000000037 :108940000000000000000000000000000000000027 :108950000000000000000000000000000000000017 :108960000000000000000000000000000000000007 :1089700000000000000000000000000000000000F7 :1089800000000000000000000000000000000000E7 :1089900000000000000000000000000000000000D7 :1089A00000000000000000000000000000000000C7 :1089B00000000000000000000000000000000000B7 :1089C00000000000000000000000000000000000A7 :1089D0000000000000000000000000000000000097 :1089E0000000000000000000000000000000000087 :1089F0000000000000000000000000000000000077 :108A00000000000000000000000000000000000066 :108A10000000000000000000000000000000000056 :108A20000000000000000000000000000000000046 :108A30000000000000000000000000000000000036 :108A40000000000000000000000000000000000026 :108A50000000000000000000000000000000000016 :108A60000000000000000000000000000000000006 :108A700000000000000000000000000000000000F6 :108A800000000000000000000000000000000000E6 :108A900000000000000000000000000000000000D6 :108AA00000000000000000000000000000000000C6 :108AB00000000000000000000000000000000000B6 :108AC00000000000000000000000000000000000A6 :108AD0000000000000000000000000000000000096 :108AE0000000000000000000000000000000000086 :108AF0000000000000000000000000000000000076 :108B00000000000000000000000000000000000065 :108B10000000000000000000000000000000000055 :108B20000000000000000000000000000000000045 :108B30000000000000000000000000000000000035 :108B40000000000000000000000000000000000025 :108B50000000000000000000000000000000000015 :108B60000000000000000000000000000000000005 :108B700000000000000000000000000000000000F5 :108B800000000000000000000000000000000000E5 :108B900000000000000000000000000000000000D5 :108BA00000000000000000000000000000000000C5 :108BB00000000000000000000000000000000000B5 :108BC00000000000000000000000000000000000A5 :108BD0000000000000000000000000000000000095 :108BE0000000000000000000000000000000000085 :108BF0000000000000000000000000000000000075 :108C00000000000000000000000000000000000064 :108C10000000000000000000000000000000000054 :108C20000000000000000000000000000000000044 :108C30000000000000000000000000000000000034 :108C40000000000000000000000000000000000024 :108C50000000000000000000000000000000000014 :108C60000000000000000000000000000000000004 :108C700000000000000000000000000000000000F4 :108C800000000000000000000000000000000000E4 :108C900000000000000000000000000000000000D4 :108CA00000000000000000000000000000000000C4 :108CB00000000000000000000000000000000000B4 :108CC00000000000000000000000000000000000A4 :108CD0000000000000000000000000000000000094 :108CE0000000000000000000000000000000000084 :108CF0000000000000000000000000000000000074 :108D00000000000000000000000000000000000063 :108D10000000000000000000000000000000000053 :108D20000000000000000000000000000000000043 :108D30000000000000000000000000000000000033 :108D40000000000000000000000000000000000023 :108D50000000000000000000000000000000000013 :108D60000000000000000000000000000000000003 :108D700000000000000000000000000000000000F3 :108D800000000000000000000000000000000000E3 :108D900000000000000000000000000000000000D3 :108DA00000000000000000000000000000000000C3 :108DB00000000000000000000000000000000000B3 :108DC00000000000000000000000000000000000A3 :108DD0000000000000000000000000000000000093 :108DE0000000000000000000000000000000000083 :108DF0000000000000000000000000000000000073 :108E00000000000000000000000000000000000062 :108E10000000000000000000000000000000000052 :108E20000000000000000000000000000000000042 :108E30000000000000000000000000000000000032 :108E40000000000000000000000000000000000022 :108E50000000000000000000000000000000000012 :108E60000000000000000000000000000000000002 :108E700000000000000000000000000000000000F2 :108E800000000000000000000000000000000000E2 :108E900000000000000000000000000000000000D2 :108EA00000000000000000000000000000000000C2 :108EB00000000000000000000000000000000000B2 :108EC00000000000000000000000000000000000A2 :108ED0000000000000000000000000000000000092 :108EE0000000000000000000000000000000000082 :108EF0000000000000000000000000000000000072 :108F00000000000000000000000000000000000061 :108F10000000000000000000000000000000000051 :108F20000000000000000000000000000000000041 :108F30000000000000000000000000000000000031 :108F40000000000000000000000000000000000021 :108F50000000000000000000000000000000000011 :108F60000000000000000000000000000000000001 :108F700000000000000000000000000000000000F1 :108F800000000000000000000000000000000000E1 :108F900000000000000000000000000000000000D1 :108FA00000000000000000000000000000000000C1 :108FB00000000000000000000000000000000000B1 :108FC00000000000000000000000000000000000A1 :108FD0000000000000000000000000000000000091 :108FE0000000000000000000000000000000000081 :108FF0000000000000000000000000000000000071 :109000000000000000000000000000000000000060 :109010000000000000000000000000000000000050 :109020000000000000000000000000000000000040 :109030000000000000000000000000000000000030 :109040000000000000000000000000000000000020 :109050000000000000000000000000000000000010 :109060000000000000000000000000000000000000 :1090700000000000000000000000000000000000F0 :1090800000000000000000000000000000000000E0 :1090900000000000000000000000000000000000D0 :1090A00000000000000000000000000000000000C0 :1090B00000000000000000000000000000000000B0 :1090C00000000000000000000000000000000000A0 :1090D0000000000000000000000000000000000090 :1090E0000000000000000000000000000000000080 :1090F0000000000000000000000000000000000070 :10910000000000000000000000000000000000005F :10911000000000000000000000000000000000004F :10912000000000000000000000000000000000003F :10913000000000000000000000000000000000002F :10914000000000000000000000000000000000001F :10915000000000000000000000000000000000000F :1091600000000000000000000000000000000000FF :1091700000000000000000000000000000000000EF :1091800000000000000000000000000000000000DF :1091900000000000000000000000000000000000CF :1091A00000000000000000000000000000000000BF :1091B00000000000000000000000000000000000AF :1091C000000000000000000000000000000000009F :1091D000000000000000000000000000000000008F :1091E000000000000000000000000000000000007F :1091F000000000000000000000000000000000006F :10920000000000000000000000000000000000005E :10921000000000000000000000000000000000004E :10922000000000000000000000000000000000003E :10923000000000000000000000000000000000002E :10924000000000000000000000000000000000001E :10925000000000000000000000000000000000000E :1092600000000000000000000000000000000000FE :1092700000000000000000000000000000000000EE :1092800000000000000000000000000000000000DE :1092900000000000000000000000000000000000CE :1092A00000000000000000000000000000000000BE :1092B00000000000000000000000000000000000AE :1092C000000000000000000000000000000000009E :1092D000000000000000000000000000000000008E :1092E000000000000000000000000000000000007E :1092F000000000000000000000000000000000006E :10930000000000000000000000000000000000005D :10931000000000000000000000000000000000004D :10932000000000000000000000000000000000003D :10933000000000000000000000000000000000002D :10934000000000000000000000000000000000001D :10935000000000000000000000000000000000000D :1093600000000000000000000000000000000000FD :1093700000000000000000000000000000000000ED :1093800000000000000000000000000000000000DD :1093900000000000000000000000000000000000CD :1093A00000000000000000000000000000000000BD :1093B00000000000000000000000000000000000AD :1093C000000000000000000000000000000000009D :1093D000000000000000000000000000000000008D :1093E000000000000000000000000000000000007D :1093F000000000000000000000000000000000006D :10940000000000000000000000000000000000005C :10941000000000000000000000000000000000004C :10942000000000000000000000000000000000003C :10943000000000000000000000000000000000002C :10944000000000000000000000000000000000001C :10945000000000000000000000000000000000000C :1094600000000000000000000000000000000000FC :1094700000000000000000000000000000000000EC :1094800000000000000000000000000000000000DC :1094900000000000000000000000000000000000CC :1094A00000000000000000000000000000000000BC :1094B00000000000000000000000000000000000AC :1094C000000000000000000000000000000000009C :1094D000000000000000000000000000000000008C :1094E000000000000000000000000000000000007C :1094F000000000000000000000000000000000006C :10950000000000000000000000000000000000005B :10951000000000000000000000000000000000004B :10952000000000000000000000000000000000003B :10953000000000000000000000000000000000002B :10954000000000000000000000000000000000001B :10955000000000000000000000000000000000000B :1095600000000000000000000000000000000000FB :1095700000000000000000000000000000000000EB :1095800000000000000000000000000000000000DB :1095900000000000000000000000000000000000CB :1095A00000000000000000000000000000000000BB :1095B00000000000000000000000000000000000AB :1095C000000000000000000000000000000000009B :1095D000000000000000000000000000000000008B :1095E000000000000000000000000000000000007B :1095F000000000000000000000000000000000006B :10960000000000000000000000000000000000005A :10961000000000000000000000000000000000004A :10962000000000000000000000000000000000003A :10963000000000000000000000000000000000002A :10964000000000000000000000000000000000001A :10965000000000000000000000000000000000000A :1096600000000000000000000000000000000000FA :1096700000000000000000000000000000000000EA :1096800000000000000000000000000000000000DA :1096900000000000000000000000000000000000CA :1096A00000000000000000000000000000000000BA :1096B00000000000000000000000000000000000AA :1096C000000000000000000000000000000000009A :1096D000000000000000000000000000000000008A :1096E000000000000000000000000000000000007A :1096F000000000000000000000000000000000006A :109700000000000000000000000000000000000059 :109710000000000000000000000000000000000049 :109720000000000000000000000000000000000039 :109730000000000000000000000000000000000029 :109740000000000000000000000000000000000019 :109750000000000000000000000000000000000009 :1097600000000000000000000000000000000000F9 :1097700000000000000000000000000000000000E9 :1097800000000000000000000000000000000000D9 :1097900000000000000000000000000000000000C9 :1097A00000000000000000000000000000000000B9 :1097B00000000000000000000000000000000000A9 :1097C0000000000000000000000000000000000099 :1097D0000000000000000000000000000000000089 :1097E0000000000000000000000000000000000079 :1097F0000000000000000000000000000000000069 :109800000000000000000000000000000000000058 :109810000000000000000000000000000000000048 :109820000000000000000000000000000000000038 :109830000000000000000000000000000000000028 :109840000000000000000000000000000000000018 :109850000000000000000000000000000000000008 :1098600000000000000000000000000000000000F8 :1098700000000000000000000000000000000000E8 :1098800000000000000000000000000000000000D8 :1098900000000000000000000000000000000000C8 :1098A00000000000000000000000000000000000B8 :1098B00000000000000000000000000000000000A8 :1098C0000000000000000000000000000000000098 :1098D0000000000000000000000000000000000088 :1098E0000000000000000000000000000000000078 :1098F0000000000000000000000000000000000068 :109900000000000000000000000000000000000057 :109910000000000000000000000000000000000047 :109920000000000000000000000000000000000037 :109930000000000000000000000000000000000027 :109940000000000000000000000000000000000017 :109950000000000000000000000000000000000007 :1099600000000000000000000000000000000000F7 :1099700000000000000000000000000000000000E7 :1099800000000000000000000000000000000000D7 :1099900000000000000000000000000000000000C7 :1099A00000000000000000000000000000000000B7 :1099B00000000000000000000000000000000000A7 :1099C0000000000000000000000000000000000097 :1099D0000000000000000000000000000000000087 :1099E0000000000000000000000000000000000077 :1099F0000000000000000000000000000000000067 :109A00000000000000000000000000000000000056 :109A10000000000000000000000000000000000046 :109A20000000000000000000000000000000000036 :109A30000000000000000000000000000000000026 :109A40000000000000000000000000000000000016 :109A50000000000000000000000000000000000006 :109A600000000000000000000000000000000000F6 :109A700000000000000000000000000000000000E6 :109A800000000000000000000000000000000000D6 :109A900000000000000000000000000000000000C6 :109AA00000000000000000000000000000000000B6 :109AB00000000000000000000000000000000000A6 :109AC0000000000000000000000000000000000096 :109AD0000000000000000000000000000000000086 :109AE0000000000000000000000000000000000076 :109AF0000000000000000000000000000000000066 :109B00000000000000000000000000000000000055 :109B10000000000000000000000000000000000045 :109B20000000000000000000000000000000000035 :109B30000000000000000000000000000000000025 :109B40000000000000000000000000000000000015 :109B50000000000000000000000000000000000005 :109B600000000000000000000000000000000000F5 :109B700000000000000000000000000000000000E5 :109B800000000000000000000000000000000000D5 :109B900000000000000000000000000000000000C5 :109BA00000000000000000000000000000000000B5 :109BB00000000000000000000000000000000000A5 :109BC0000000000000000000000000000000000095 :109BD0000000000000000000000000000000000085 :109BE0000000000000000000000000000000000075 :109BF0000000000000000000000000000000000065 :109C00000000000000000000000000000000000054 :109C10000000000000000000000000000000000044 :109C20000000000000000000000000000000000034 :109C30000000000000000000000000000000000024 :109C40000000000000000000000000000000000014 :109C50000000000000000000000000000000000004 :109C600000000000000000000000000000000000F4 :109C700000000000000000000000000000000000E4 :109C800000000000000000000000000000000000D4 :109C900000000000000000000000000000000000C4 :109CA00000000000000000000000000000000000B4 :109CB00000000000000000000000000000000000A4 :109CC0000000000000000000000000000000000094 :109CD0000000000000000000000000000000000084 :109CE0000000000000000000000000000000000074 :109CF0000000000000000000000000000000000064 :109D00000000000000000000000000000000000053 :109D10000000000000000000000000000000000043 :109D20000000000000000000000000000000000033 :109D30000000000000000000000000000000000023 :109D40000000000000000000000000000000000013 :109D50000000000000000000000000000000000003 :109D600000000000000000000000000000000000F3 :109D700000000000000000000000000000000000E3 :109D800000000000000000000000000000000000D3 :109D900000000000000000000000000000000000C3 :109DA00000000000000000000000000000000000B3 :109DB00000000000000000000000000000000000A3 :109DC0000000000000000000000000000000000093 :109DD0000000000000000000000000000000000083 :109DE0000000000000000000000000000000000073 :109DF0000000000000000000000000000000000063 :109E00000000000000000000000000000000000052 :109E10000000000000000000000000000000000042 :109E20000000000000000000000000000000000032 :109E30000000000000000000000000000000000022 :109E40000000000000000000000000000000000012 :109E50000000000000000000000000000000000002 :109E600000000000000000000000000000000000F2 :109E700000000000000000000000000000000000E2 :109E800000000000000000000000000000000000D2 :109E900000000000000000000000000000000000C2 :109EA00000000000000000000000000000000000B2 :109EB00000000000000000000000000000000000A2 :109EC0000000000000000000000000000000000092 :109ED0000000000000000000000000000000000082 :109EE0000000000000000000000000000000000072 :109EF0000000000000000000000000000000000062 :109F00000000000000000000000000000000000051 :109F10000000000000000000000000000000000041 :109F20000000000000000000000000000000000031 :109F30000000000000000000000000000000000021 :109F40000000000000000000000000000000000011 :109F50000000000000000000000000000000000001 :109F600000000000000000000000000000000000F1 :109F700000000000000000000000000000000000E1 :109F800000000000000000000000000000000000D1 :109F900000000000000000000000000000000000C1 :109FA00000000000000000000000000000000000B1 :109FB00000000000000000000000000000000000A1 :109FC0000000000000000000000000000000000091 :109FD0000000000000000000000000000000000081 :109FE0000000000000000000000000000000000071 :109FF0000000000000000000000000000000000061 :10A000000000000000000000000000000000000050 :10A010000000000000000000000000000000000040 :10A020000000000000000000000000000000000030 :10A030000000000000000000000000000000000020 :10A040000000000000000000000000000000000010 :10A050000000000000000000000000000000000000 :10A0600000000000000000000000000000000000F0 :10A0700000000000000000000000000000000000E0 :10A0800000000000000000000000000000000000D0 :10A0900000000000000000000000000000000000C0 :10A0A00000000000000000000000000000000000B0 :10A0B00000000000000000000000000000000000A0 :10A0C0000000000000000000000000000000000090 :10A0D0000000000000000000000000000000000080 :10A0E0000000000000000000000000000000000070 :10A0F0000000000000000000000000000000000060 :10A10000000000000000000000000000000000004F :10A11000000000000000000000000000000000003F :10A12000000000000000000000000000000000002F :10A13000000000000000000000000000000000001F :10A14000000000000000000000000000000000000F :10A1500000000000000000000000000000000000FF :10A1600000000000000000000000000000000000EF :10A1700000000000000000000000000000000000DF :10A1800000000000000000000000000000000000CF :10A1900000000000000000000000000000000000BF :10A1A00000000000000000000000000000000000AF :10A1B000000000000000000000000000000000009F :10A1C000000000000000000000000000000000008F :10A1D000000000000000000000000000000000007F :10A1E000000000000000000000000000000000006F :10A1F000000000000000000000000000000000005F :10A20000000000000000000000000000000000004E :10A21000000000000000000000000000000000003E :10A22000000000000000000000000000000000002E :10A23000000000000000000000000000000000001E :10A24000000000000000000000000000000000000E :10A2500000000000000000000000000000000000FE :10A2600000000000000000000000000000000000EE :10A2700000000000000000000000000000000000DE :10A2800000000000000000000000000000000000CE :10A2900000000000000000000000000000000000BE :10A2A00000000000000000000000000000000000AE :10A2B000000000000000000000000000000000009E :10A2C000000000000000000000000000000000008E :10A2D000000000000000000000000000000000007E :10A2E000000000000000000000000000000000006E :10A2F000000000000000000000000000000000005E :10A30000000000000000000000000000000000004D :10A31000000000000000000000000000000000003D :10A32000000000000000000000000000000000002D :10A33000000000000000000000000000000000001D :10A34000000000000000000000000000000000000D :10A3500000000000000000000000000000000000FD :10A3600000000000000000000000000000000000ED :10A3700000000000000000000000000000000000DD :10A3800000000000000000000000000000000000CD :10A3900000000000000000000000000000000000BD :10A3A00000000000000000000000000000000000AD :10A3B000000000000000000000000000000000009D :10A3C000000000000000000000000000000000008D :10A3D000000000000000000000000000000000007D :10A3E000000000000000000000000000000000006D :10A3F000000000000000000000000000000000005D :10A40000000000000000000000000000000000004C :10A41000000000000000000000000000000000003C :10A42000000000000000000000000000000000002C :10A43000000000000000000000000000000000001C :10A44000000000000000000000000000000000000C :10A4500000000000000000000000000000000000FC :10A4600000000000000000000000000000000000EC :10A4700000000000000000000000000000000000DC :10A4800000000000000000000000000000000000CC :10A4900000000000000000000000000000000000BC :10A4A00000000000000000000000000000000000AC :10A4B000000000000000000000000000000000009C :10A4C000000000000000000000000000000000008C :10A4D000000000000000000000000000000000007C :10A4E000000000000000000000000000000000006C :10A4F000000000000000000000000000000000005C :10A50000000000000000000000000000000000004B :10A51000000000000000000000000000000000003B :10A52000000000000000000000000000000000002B :10A53000000000000000000000000000000000001B :10A54000000000000000000000000000000000000B :10A5500000000000000000000000000000000000FB :10A5600000000000000000000000000000000000EB :10A5700000000000000000000000000000000000DB :10A5800000000000000000000000000000000000CB :10A5900000000000000000000000000000000000BB :10A5A00000000000000000000000000000000000AB :10A5B000000000000000000000000000000000009B :10A5C000000000000000000000000000000000008B :10A5D000000000000000000000000000000000007B :10A5E000000000000000000000000000000000006B :10A5F000000000000000000000000000000000005B :10A60000000000000000000000000000000000004A :10A61000000000000000000000000000000000003A :10A62000000000000000000000000000000000002A :10A63000000000000000000000000000000000001A :10A64000000000000000000000000000000000000A :10A6500000000000000000000000000000000000FA :10A6600000000000000000000000000000000000EA :10A6700000000000000000000000000000000000DA :10A6800000000000000000000000000000000000CA :10A6900000000000000000000000000000000000BA :10A6A00000000000000000000000000000000000AA :10A6B000000000000000000000000000000000009A :10A6C000000000000000000000000000000000008A :10A6D000000000000000000000000000000000007A :10A6E000000000000000000000000000000000006A :10A6F000000000000000000000000000000000005A :10A700000000000000000000000000000000000049 :10A710000000000000000000000000000000000039 :10A720000000000000000000000000000000000029 :10A730000000000000000000000000000000000019 :10A740000000000000000000000000000000000009 :10A7500000000000000000000000000000000000F9 :10A7600000000000000000000000000000000000E9 :10A7700000000000000000000000000000000000D9 :10A7800000000000000000000000000000000000C9 :10A7900000000000000000000000000000000000B9 :10A7A00000000000000000000000000000000000A9 :10A7B0000000000000000000000000000000000099 :10A7C0000000000000000000000000000000000089 :10A7D0000000000000000000000000000000000079 :10A7E0000000000000000000000000000000000069 :10A7F0000000000000000000000000000000000059 :10A800000000000000000000000000000000000048 :10A810000000000000000000000000000000000038 :10A820000000000000000000000000000000000028 :10A830000000000000000000000000000000000018 :10A840000000000000000000000000000000000008 :10A8500000000000000000000000000000000000F8 :10A8600000000000000000000000000000000000E8 :10A8700000000000000000000000000000000000D8 :10A8800000000000000000000000000000000000C8 :10A8900000000000000000000000000000000000B8 :10A8A00000000000000000000000000000000000A8 :10A8B0000000000000000000000000000000000098 :10A8C0000000000000000000000000000000000088 :10A8D0000000000000000000000000000000000078 :10A8E0000000000000000000000000000000000068 :10A8F0000000000000000000000000000000000058 :10A900000000000000000000000000000000000047 :10A910000000000000000000000000000000000037 :10A920000000000000000000000000000000000027 :10A930000000000000000000000000000000000017 :10A940000000000000000000000000000000000007 :10A9500000000000000000000000000000000000F7 :10A9600000000000000000000000000000000000E7 :10A9700000000000000000000000000000000000D7 :10A9800000000000000000000000000000000000C7 :10A9900000000000000000000000000000000000B7 :10A9A00000000000000000000000000000000000A7 :10A9B0000000000000000000000000000000000097 :10A9C0000000000000000000000000000000000087 :10A9D0000000000000000000000000000000000077 :10A9E0000000000000000000000000000000000067 :10A9F0000000000000000000000000000000000057 :10AA00000000000000000000000000000000000046 :10AA10000000000000000000000000000000000036 :10AA20000000000000000000000000000000000026 :10AA30000000000000000000000000000000000016 :10AA40000000000000000000000000000000000006 :10AA500000000000000000000000000000000000F6 :10AA600000000000000000000000000000000000E6 :10AA700000000000000000000000000000000000D6 :10AA800000000000000000000000000000000000C6 :10AA900000000000000000000000000000000000B6 :10AAA00000000000000000000000000000000000A6 :10AAB0000000000000000000000000000000000096 :10AAC0000000000000000000000000000000000086 :10AAD0000000000000000000000000000000000076 :10AAE0000000000000000000000000000000000066 :10AAF0000000000000000000000000000000000056 :10AB00000000000000000000000000000000000045 :10AB10000000000000000000000000000000000035 :10AB20000000000000000000000000000000000025 :10AB30000000000000000000000000000000000015 :10AB40000000000000000000000000000000000005 :10AB500000000000000000000000000000000000F5 :10AB600000000000000000000000000000000000E5 :10AB700000000000000000000000000000000000D5 :10AB800000000000000000000000000000000000C5 :10AB900000000000000000000000000000000000B5 :10ABA00000000000000000000000000000000000A5 :10ABB0000000000000000000000000000000000095 :10ABC0000000000000000000000000000000000085 :10ABD0000000000000000000000000000000000075 :10ABE0000000000000000000000000000000000065 :10ABF0000000000000000000000000000000000055 :10AC00000000000000000000000000000000000044 :10AC10000000000000000000000000000000000034 :10AC20000000000000000000000000000000000024 :10AC30000000000000000000000000000000000014 :10AC40000000000000000000000000000000000004 :10AC500000000000000000000000000000000000F4 :10AC600000000000000000000000000000000000E4 :10AC700000000000000000000000000000000000D4 :10AC800000000000000000000000000000000000C4 :10AC900000000000000000000000000000000000B4 :10ACA00000000000000000000000000000000000A4 :10ACB0000000000000000000000000000000000094 :10ACC0000000000000000000000000000000000084 :10ACD0000000000000000000000000000000000074 :10ACE0000000000000000000000000000000000064 :10ACF0000000000000000000000000000000000054 :10AD00000000000000000000000000000000000043 :10AD10000000000000000000000000000000000033 :10AD20000000000000000000000000000000000023 :10AD30000000000000000000000000000000000013 :10AD40000000000000000000000000000000000003 :10AD500000000000000000000000000000000000F3 :10AD600000000000000000000000000000000000E3 :10AD700000000000000000000000000000000000D3 :10AD800000000000000000000000000000000000C3 :10AD900000000000000000000000000000000000B3 :10ADA00000000000000000000000000000000000A3 :10ADB0000000000000000000000000000000000093 :10ADC0000000000000000000000000000000000083 :10ADD0000000000000000000000000000000000073 :10ADE0000000000000000000000000000000000063 :10ADF0000000000000000000000000000000000053 :10AE00000000000000000000000000000000000042 :10AE10000000000000000000000000000000000032 :10AE20000000000000000000000000000000000022 :10AE30000000000000000000000000000000000012 :10AE40000000000000000000000000000000000002 :10AE500000000000000000000000000000000000F2 :10AE600000000000000000000000000000000000E2 :10AE700000000000000000000000000000000000D2 :10AE800000000000000000000000000000000000C2 :10AE900000000000000000000000000000000000B2 :10AEA00000000000000000000000000000000000A2 :10AEB0000000000000000000000000000000000092 :10AEC0000000000000000000000000000000000082 :10AED0000000000000000000000000000000000072 :10AEE0000000000000000000000000000000000062 :10AEF0000000000000000000000000000000000052 :10AF00000000000000000000000000000000000041 :10AF10000000000000000000000000000000000031 :10AF20000000000000000000000000000000000021 :10AF30000000000000000000000000000000000011 :10AF40000000000000000000000000000000000001 :10AF500000000000000000000000000000000000F1 :10AF600000000000000000000000000000000000E1 :10AF700000000000000000000000000000000000D1 :10AF800000000000000000000000000000000000C1 :10AF900000000000000000000000000000000000B1 :10AFA00000000000000000000000000000000000A1 :10AFB0000000000000000000000000000000000091 :10AFC0000000000000000000000000000000000081 :10AFD0000000000000000000000000000000000071 :10AFE0000000000000000000000000000000000061 :10AFF0000000000000000000000000000000000051 :10B000000000000000000000000000000000000040 :10B010000000000000000000000000000000000030 :10B020000000000000000000000000000000000020 :10B030000000000000000000000000000000000010 :10B040000000000000000000000000000000000000 :10B0500000000000000000000000000000000000F0 :10B0600000000000000000000000000000000000E0 :10B0700000000000000000000000000000000000D0 :10B0800000000000000000000000000000000000C0 :10B0900000000000000000000000000000000000B0 :10B0A00000000000000000000000000000000000A0 :10B0B0000000000000000000000000000000000090 :10B0C0000000000000000000000000000000000080 :10B0D0000000000000000000000000000000000070 :10B0E0000000000000000000000000000000000060 :10B0F0000000000000000000000000000000000050 :10B10000000000000000000000000000000000003F :10B11000000000000000000000000000000000002F :10B12000000000000000000000000000000000001F :10B13000000000000000000000000000000000000F :10B1400000000000000000000000000000000000FF :10B1500000000000000000000000000000000000EF :10B1600000000000000000000000000000000000DF :10B1700000000000000000000000000000000000CF :10B1800000000000000000000000000000000000BF :10B1900000000000000000000000000000000000AF :10B1A000000000000000000000000000000000009F :10B1B000000000000000000000000000000000008F :10B1C000000000000000000000000000000000007F :10B1D000000000000000000000000000000000006F :10B1E000000000000000000000000000000000005F :10B1F000000000000000000000000000000000004F :10B20000000000000000000000000000000000003E :10B21000000000000000000000000000000000002E :10B22000000000000000000000000000000000001E :10B23000000000000000000000000000000000000E :10B2400000000000000000000000000000000000FE :10B2500000000000000000000000000000000000EE :10B2600000000000000000000000000000000000DE :10B2700000000000000000000000000000000000CE :10B2800000000000000000000000000000000000BE :10B2900000000000000000000000000000000000AE :10B2A000000000000000000000000000000000009E :10B2B000000000000000000000000000000000008E :10B2C000000000000000000000000000000000007E :10B2D000000000000000000000000000000000006E :10B2E000000000000000000000000000000000005E :10B2F000000000000000000000000000000000004E :10B30000000000000000000000000000000000003D :10B31000000000000000000000000000000000002D :10B32000000000000000000000000000000000001D :10B33000000000000000000000000000000000000D :10B3400000000000000000000000000000000000FD :10B3500000000000000000000000000000000000ED :10B3600000000000000000000000000000000000DD :10B3700000000000000000000000000000000000CD :10B3800000000000000000000000000000000000BD :10B3900000000000000000000000000000000000AD :10B3A000000000000000000000000000000000009D :10B3B000000000000000000000000000000000008D :10B3C000000000000000000000000000000000007D :10B3D000000000000000000000000000000000006D :10B3E000000000000000000000000000000000005D :10B3F000000000000000000000000000000000004D :10B40000000000000000000000000000000000003C :10B41000000000000000000000000000000000002C :10B42000000000000000000000000000000000001C :10B43000000000000000000000000000000000000C :10B4400000000000000000000000000000000000FC :10B4500000000000000000000000000000000000EC :10B4600000000000000000000000000000000000DC :10B4700000000000000000000000000000000000CC :10B4800000000000000000000000000000000000BC :10B4900000000000000000000000000000000000AC :10B4A000000000000000000000000000000000009C :10B4B000000000000000000000000000000000008C :10B4C000000000000000000000000000000000007C :10B4D000000000000000000000000000000000006C :10B4E000000000000000000000000000000000005C :10B4F000000000000000000000000000000000004C :10B50000000000000000000000000000000000003B :10B51000000000000000000000000000000000002B :10B52000000000000000000000000000000000001B :10B53000000000000000000000000000000000000B :10B5400000000000000000000000000000000000FB :10B5500000000000000000000000000000000000EB :10B5600000000000000000000000000000000000DB :10B5700000000000000000000000000000000000CB :10B5800000000000000000000000000000000000BB :10B5900000000000000000000000000000000000AB :10B5A000000000000000000000000000000000009B :10B5B000000000000000000000000000000000008B :10B5C000000000000000000000000000000000007B :10B5D000000000000000000000000000000000006B :10B5E000000000000000000000000000000000005B :10B5F000000000000000000000000000000000004B :10B60000000000000000000000000000000000003A :10B61000000000000000000000000000000000002A :10B62000000000000000000000000000000000001A :10B63000000000000000000000000000000000000A :10B6400000000000000000000000000000000000FA :10B6500000000000000000000000000000000000EA :10B6600000000000000000000000000000000000DA :10B6700000000000000000000000000000000000CA :10B6800000000000000000000000000000000000BA :10B6900000000000000000000000000000000000AA :10B6A000000000000000000000000000000000009A :10B6B000000000000000000000000000000000008A :10B6C000000000000000000000000000000000007A :10B6D000000000000000000000000000000000006A :10B6E000000000000000000000000000000000005A :10B6F000000000000000000000000000000000004A :10B700000000000000000000000000000000000039 :10B710000000000000000000000000000000000029 :10B720000000000000000000000000000000000019 :10B730000000000000000000000000000000000009 :10B7400000000000000000000000000000000000F9 :10B7500000000000000000000000000000000000E9 :10B7600000000000000000000000000000000000D9 :10B7700000000000000000000000000000000000C9 :10B7800000000000000000000000000000000000B9 :10B7900000000000000000000000000000000000A9 :10B7A0000000000000000000000000000000000099 :10B7B0000000000000000000000000000000000089 :10B7C0000000000000000000000000000000000079 :10B7D0000000000000000000000000000000000069 :10B7E0000000000000000000000000000000000059 :10B7F0000000000000000000000000000000000049 :10B800000000000000000000000000000000000038 :10B810000000000000000000000000000000000028 :10B820000000000000000000000000000000000018 :10B830000000000000000000000000000000000008 :10B8400000000000000000000000000000000000F8 :10B8500000000000000000000000000000000000E8 :10B8600000000000000000000000000000000000D8 :10B8700000000000000000000000000000000000C8 :10B8800000000000000000000000000000000000B8 :10B8900000000000000000000000000000000000A8 :10B8A0000000000000000000000000000000000098 :10B8B0000000000000000000000000000000000088 :10B8C0000000000000000000000000000000000078 :10B8D0000000000000000000000000000000000068 :10B8E0000000000000000000000000000000000058 :10B8F0000000000000000000000000000000000048 :10B900000000000000000000000000000000000037 :10B910000000000000000000000000000000000027 :10B920000000000000000000000000000000000017 :10B930000000000000000000000000000000000007 :10B9400000000000000000000000000000000000F7 :10B9500000000000000000000000000000000000E7 :10B9600000000000000000000000000000000000D7 :10B9700000000000000000000000000000000000C7 :10B9800000000000000000000000000000000000B7 :10B9900000000000000000000000000000000000A7 :10B9A0000000000000000000000000000000000097 :10B9B0000000000000000000000000000000000087 :10B9C0000000000000000000000000000000000077 :10B9D0000000000000000000000000000000000067 :10B9E0000000000000000000000000000000000057 :10B9F0000000000000000000000000000000000047 :10BA00000000000000000000000000000000000036 :10BA10000000000000000000000000000000000026 :10BA20000000000000000000000000000000000016 :10BA30000000000000000000000000000000000006 :10BA400000000000000000000000000000000000F6 :10BA500000000000000000000000000000000000E6 :10BA600000000000000000000000000000000000D6 :10BA700000000000000000000000000000000000C6 :10BA800000000000000000000000000000000000B6 :10BA900000000000000000000000000000000000A6 :10BAA0000000000000000000000000000000000096 :10BAB0000000000000000000000000000000000086 :10BAC0000000000000000000000000000000000076 :10BAD0000000000000000000000000000000000066 :10BAE0000000000000000000000000000000000056 :10BAF0000000000000000000000000000000000046 :10BB00000000000000000000000000000000000035 :10BB10000000000000000000000000000000000025 :10BB20000000000000000000000000000000000015 :10BB30000000000000000000000000000000000005 :10BB400000000000000000000000000000000000F5 :10BB500000000000000000000000000000000000E5 :10BB600000000000000000000000000000000000D5 :10BB700000000000000000000000000000000000C5 :10BB800000000000000000000000000000000000B5 :10BB900000000000000000000000000000000000A5 :10BBA0000000000000000000000000000000000095 :10BBB0000000000000000000000000000000000085 :10BBC0000000000000000000000000000000000075 :10BBD0000000000000000000000000000000000065 :10BBE0000000000000000000000000000000000055 :10BBF0000000000000000000000000000000000045 :10BC00000000000000000000000000000000000034 :10BC10000000000000000000000000000000000024 :10BC20000000000000000000000000000000000014 :10BC30000000000000000000000000000000000004 :10BC400000000000000000000000000000000000F4 :10BC500000000000000000000000000000000000E4 :10BC600000000000000000000000000000000000D4 :10BC700000000000000000000000000000000000C4 :10BC800000000000000000000000000000000000B4 :10BC900000000000000000000000000000000000A4 :10BCA0000000000000000000000000000000000094 :10BCB0000000000000000000000000000000000084 :10BCC0000000000000000000000000000000000074 :10BCD0000000000000000000000000000000000064 :10BCE0000000000000000000000000000000000054 :10BCF0000000000000000000000000000000000044 :10BD00000000000000000000000000000000000033 :10BD10000000000000000000000000000000000023 :10BD20000000000000000000000000000000000013 :10BD30000000000000000000000000000000000003 :10BD400000000000000000000000000000000000F3 :10BD500000000000000000000000000000000000E3 :10BD600000000000000000000000000000000000D3 :10BD700000000000000000000000000000000000C3 :10BD800000000000000000000000000000000000B3 :10BD900000000000000000000000000000000000A3 :10BDA0000000000000000000000000000000000093 :10BDB0000000000000000000000000000000000083 :10BDC0000000000000000000000000000000000073 :10BDD0000000000000000000000000000000000063 :10BDE0000000000000000000000000000000000053 :10BDF0000000000000000000000000000000000043 :10BE00000000000000000000000000000000000032 :10BE10000000000000000000000000000000000022 :10BE20000000000000000000000000000000000012 :10BE30000000000000000000000000000000000002 :10BE400000000000000000000000000000000000F2 :10BE500000000000000000000000000000000000E2 :10BE600000000000000000000000000000000000D2 :10BE700000000000000000000000000000000000C2 :10BE800000000000000000000000000000000000B2 :10BE900000000000000000000000000000000000A2 :10BEA0000000000000000000000000000000000092 :10BEB0000000000000000000000000000000000082 :10BEC0000000000000000000000000000000000072 :10BED0000000000000000000000000000000000062 :10BEE0000000000000000000000000000000000052 :10BEF0000000000000000000000000000000000042 :10BF00000000000000000000000000000000000031 :10BF10000000000000000000000000000000000021 :10BF20000000000000000000000000000000000011 :10BF30000000000000000000000000000000000001 :10BF400000000000000000000000000000000000F1 :10BF500000000000000000000000000000000000E1 :10BF600000000000000000000000000000000000D1 :10BF700000000000000000000000000000000000C1 :10BF800000000000000000000000000000000000B1 :10BF900000000000000000000000000000000000A1 :10BFA0000000000000000000000000000000000091 :10BFB0000000000000000000000000000000000081 :10BFC0000000000000000000000000000000000071 :10BFD0000000000000000000000000000000000061 :10BFE0000000000000000000000000000000000051 :10BFF0000000000000000000000000000000000041 :10C000000000000000000000000000000000000030 :10C010000000000000000000000000000000000020 :10C020000000000000000000000000000000000010 :10C030000000000000000000000000000000000000 :10C0400000000000000000000000000000000000F0 :10C0500000000000000000000000000000000000E0 :10C0600000000000000000000000000000000000D0 :10C0700000000000000000000000000000000000C0 :10C0800000000000000000000000000000000000B0 :10C0900000000000000000000000000000000000A0 :10C0A0000000000000000000000000000000000090 :10C0B0000000000000000000000000000000000080 :10C0C0000000000000000000000000000000000070 :10C0D0000000000000000000000000000000000060 :10C0E0000000000000000000000000000000000050 :10C0F0000000000000000000000000000000000040 :10C10000000000000000000000000000000000002F :10C11000000000000000000000000000000000001F :10C12000000000000000000000000000000000000F :10C1300000000000000000000000000000000000FF :10C1400000000000000000000000000000000000EF :10C1500000000000000000000000000000000000DF :10C1600000000000000000000000000000000000CF :10C1700000000000000000000000000000000000BF :10C1800000000000000000000000000000000000AF :10C19000000000000000000000000000000000009F :10C1A000000000000000000000000000000000008F :10C1B000000000000000000000000000000000007F :10C1C000000000000000000000000000000000006F :10C1D000000000000000000000000000000000005F :10C1E000000000000000000000000000000000004F :10C1F000000000000000000000000000000000003F :10C20000000000000000000000000000000000002E :10C21000000000000000000000000000000000001E :10C22000000000000000000000000000000000000E :10C2300000000000000000000000000000000000FE :10C2400000000000000000000000000000000000EE :10C2500000000000000000000000000000000000DE :10C2600000000000000000000000000000000000CE :10C2700000000000000000000000000000000000BE :10C2800000000000000000000000000000000000AE :10C29000000000000000000000000000000000009E :10C2A000000000000000000000000000000000008E :10C2B000000000000000000000000000000000007E :10C2C000000000000000000000000000000000006E :10C2D000000000000000000000000000000000005E :10C2E000000000000000000000000000000000004E :10C2F000000000000000000000000000000000003E :10C30000000000000000000000000000000000002D :10C31000000000000000000000000000000000001D :10C32000000000000000000000000000000000000D :10C3300000000000000000000000000000000000FD :10C3400000000000000000000000000000000000ED :10C3500000000000000000000000000000000000DD :10C3600000000000000000000000000000000000CD :10C3700000000000000000000000000000000000BD :10C3800000000000000000000000000000000000AD :10C39000000000000000000000000000000000009D :10C3A000000000000000000000000000000000008D :10C3B000000000000000000000000000000000007D :10C3C000000000000000000000000000000000006D :10C3D000000000000000000000000000000000005D :10C3E000000000000000000000000000000000004D :10C3F000000000000000000000000000000000003D :10C40000000000000000000000000000000000002C :10C41000000000000000000000000000000000001C :10C42000000000000000000000000000000000000C :10C4300000000000000000000000000000000000FC :10C4400000000000000000000000000000000000EC :10C4500000000000000000000000000000000000DC :10C4600000000000000000000000000000000000CC :10C4700000000000000000000000000000000000BC :10C4800000000000000000000000000000000000AC :10C49000000000000000000000000000000000009C :10C4A000000000000000000000000000000000008C :10C4B000000000000000000000000000000000007C :10C4C000000000000000000000000000000000006C :10C4D000000000000000000000000000000000005C :10C4E000000000000000000000000000000000004C :10C4F000000000000000000000000000000000003C :10C50000000000000000000000000000000000002B :10C51000000000000000000000000000000000001B :10C52000000000000000000000000000000000000B :10C5300000000000000000000000000000000000FB :10C5400000000000000000000000000000000000EB :10C5500000000000000000000000000000000000DB :10C5600000000000000000000000000000000000CB :10C5700000000000000000000000000000000000BB :10C5800000000000000000000000000000000000AB :10C59000000000000000000000000000000000009B :10C5A000000000000000000000000000000000008B :10C5B000000000000000000000000000000000007B :10C5C000000000000000000000000000000000006B :10C5D000000000000000000000000000000000005B :10C5E000000000000000000000000000000000004B :10C5F000000000000000000000000000000000003B :10C60000000000000000000000000000000000002A :10C61000000000000000000000000000000000001A :10C62000000000000000000000000000000000000A :10C6300000000000000000000000000000000000FA :10C6400000000000000000000000000000000000EA :10C6500000000000000000000000000000000000DA :10C6600000000000000000000000000000000000CA :10C6700000000000000000000000000000000000BA :10C6800000000000000000000000000000000000AA :10C69000000000000000000000000000000000009A :10C6A000000000000000000000000000000000008A :10C6B000000000000000000000000000000000007A :10C6C000000000000000000000000000000000006A :10C6D000000000000000000000000000000000005A :10C6E000000000000000000000000000000000004A :10C6F000000000000000000000000000000000003A :10C700000000000000000000000000000000000029 :10C710000000000000000000000000000000000019 :10C720000000000000000000000000000000000009 :10C7300000000000000000000000000000000000F9 :10C7400000000000000000000000000000000000E9 :10C7500000000000000000000000000000000000D9 :10C7600000000000000000000000000000000000C9 :10C7700000000000000000000000000000000000B9 :10C7800000000000000000000000000000000000A9 :10C790000000000000000000000000000000000099 :10C7A0000000000000000000000000000000000089 :10C7B0000000000000000000000000000000000079 :10C7C0000000000000000000000000000000000069 :10C7D0000000000000000000000000000000000059 :10C7E0000000000000000000000000000000000049 :10C7F0000000000000000000000000000000000039 :10C800000000000000000000000000000000000028 :10C810000000000000000000000000000000000018 :10C820000000000000000000000000000000000008 :10C8300000000000000000000000000000000000F8 :10C8400000000000000000000000000000000000E8 :10C8500000000000000000000000000000000000D8 :10C8600000000000000000000000000000000000C8 :10C8700000000000000000000000000000000000B8 :10C8800000000000000000000000000000000000A8 :10C890000000000000000000000000000000000098 :10C8A0000000000000000000000000000000000088 :10C8B0000000000000000000000000000000000078 :10C8C0000000000000000000000000000000000068 :10C8D0000000000000000000000000000000000058 :10C8E0000000000000000000000000000000000048 :10C8F0000000000000000000000000000000000038 :10C900000000000000000000000000000000000027 :10C910000000000000000000000000000000000017 :10C920000000000000000000000000000000000007 :10C9300000000000000000000000000000000000F7 :10C9400000000000000000000000000000000000E7 :10C9500000000000000000000000000000000000D7 :10C9600000000000000000000000000000000000C7 :10C9700000000000000000000000000000000000B7 :10C9800000000000000000000000000000000000A7 :10C990000000000000000000000000000000000097 :10C9A0000000000000000000000000000000000087 :10C9B0000000000000000000000000000000000077 :10C9C0000000000000000000000000000000000067 :10C9D0000000000000000000000000000000000057 :10C9E0000000000000000000000000000000000047 :10C9F0000000000000000000000000000000000037 :10CA00000000000000000000000000000000000026 :10CA10000000000000000000000000000000000016 :10CA20000000000000000000000000000000000006 :10CA300000000000000000000000000000000000F6 :10CA400000000000000000000000000000000000E6 :10CA500000000000000000000000000000000000D6 :10CA600000000000000000000000000000000000C6 :10CA700000000000000000000000000000000000B6 :10CA800000000000000000000000000000000000A6 :10CA90000000000000000000000000000000000096 :10CAA0000000000000000000000000000000000086 :10CAB0000000000000000000000000000000000076 :10CAC0000000000000000000000000000000000066 :10CAD0000000000000000000000000000000000056 :10CAE0000000000000000000000000000000000046 :10CAF0000000000000000000000000000000000036 :10CB00000000000000000000000000000000000025 :10CB10000000000000000000000000000000000015 :10CB20000000000000000000000000000000000005 :10CB300000000000000000000000000000000000F5 :10CB400000000000000000000000000000000000E5 :10CB500000000000000000000000000000000000D5 :10CB600000000000000000000000000000000000C5 :10CB700000000000000000000000000000000000B5 :10CB800000000000000000000000000000000000A5 :10CB90000000000000000000000000000000000095 :10CBA0000000000000000000000000000000000085 :10CBB0000000000000000000000000000000000075 :10CBC0000000000000000000000000000000000065 :10CBD0000000000000000000000000000000000055 :10CBE0000000000000000000000000000000000045 :10CBF0000000000000000000000000000000000035 :10CC00000000000000000000000000000000000024 :10CC10000000000000000000000000000000000014 :10CC20000000000000000000000000000000000004 :10CC300000000000000000000000000000000000F4 :10CC400000000000000000000000000000000000E4 :10CC500000000000000000000000000000000000D4 :10CC600000000000000000000000000000000000C4 :10CC700000000000000000000000000000000000B4 :10CC800000000000000000000000000000000000A4 :10CC90000000000000000000000000000000000094 :10CCA0000000000000000000000000000000000084 :10CCB0000000000000000000000000000000000074 :10CCC0000000000000000000000000000000000064 :10CCD0000000000000000000000000000000000054 :10CCE0000000000000000000000000000000000044 :10CCF0000000000000000000000000000000000034 :10CD00000000000000000000000000000000000023 :10CD10000000000000000000000000000000000013 :10CD20000000000000000000000000000000000003 :10CD300000000000000000000000000000000000F3 :10CD400000000000000000000000000000000000E3 :10CD500000000000000000000000000000000000D3 :10CD600000000000000000000000000000000000C3 :10CD700000000000000000000000000000000000B3 :10CD800000000000000000000000000000000000A3 :10CD90000000000000000000000000000000000093 :10CDA0000000000000000000000000000000000083 :10CDB0000000000000000000000000000000000073 :10CDC0000000000000000000000000000000000063 :10CDD0000000000000000000000000000000000053 :10CDE0000000000000000000000000000000000043 :10CDF0000000000000000000000000000000000033 :10CE00000000000000000000000000000000000022 :10CE10000000000000000000000000000000000012 :10CE20000000000000000000000000000000000002 :10CE300000000000000000000000000000000000F2 :10CE400000000000000000000000000000000000E2 :10CE500000000000000000000000000000000000D2 :10CE600000000000000000000000000000000000C2 :10CE700000000000000000000000000000000000B2 :10CE800000000000000000000000000000000000A2 :10CE90000000000000000000000000000000000092 :10CEA0000000000000000000000000000000000082 :10CEB0000000000000000000000000000000000072 :10CEC0000000000000000000000000000000000062 :10CED0000000000000000000000000000000000052 :10CEE0000000000000000000000000000000000042 :10CEF0000000000000000000000000000000000032 :10CF00000000000000000000000000000000000021 :10CF10000000000000000000000000000000000011 :10CF20000000000000000000000000000000000001 :10CF300000000000000000000000000000000000F1 :10CF400000000000000000000000000000000000E1 :10CF500000000000000000000000000000000000D1 :10CF600000000000000000000000000000000000C1 :10CF700000000000000000000000000000000000B1 :10CF800000000000000000000000000000000000A1 :10CF90000000000000000000000000000000000091 :10CFA0000000000000000000000000000000000081 :10CFB0000000000000000000000000000000000071 :10CFC0000000000000000000000000000000000061 :10CFD0000000000000000000000000000000000051 :10CFE0000000000000000000000000000000000041 :10CFF0000000000000000000000000000000000031 :10D000000000000000000000000000000000000020 :10D010000000000000000000000000000000000010 :10D020000000000000000000000000000000000000 :10D0300000000000000000000000000000000000F0 :10D0400000000000000000000000000000000000E0 :10D0500000000000000000000000000000000000D0 :10D0600000000000000000000000000000000000C0 :10D0700000000000000000000000000000000000B0 :10D0800000000000000000000000000000000000A0 :10D090000000000000000000000000000000000090 :10D0A0000000000000000000000000000000000080 :10D0B0000000000000000000000000000000000070 :10D0C0000000000000000000000000000000000060 :10D0D0000000000000000000000000000000000050 :10D0E0000000000000000000000000000000000040 :10D0F0000000000000000000000000000000000030 :10D10000000000000000000000000000000000001F :10D11000000000000000000000000000000000000F :10D1200000000000000000000000000000000000FF :10D1300000000000000000000000000000000000EF :10D1400000000000000000000000000000000000DF :10D1500000000000000000000000000000000000CF :10D1600000000000000000000000000000000000BF :10D1700000000000000000000000000000000000AF :10D18000000000000000000000000000000000009F :10D19000000000000000000000000000000000008F :10D1A000000000000000000000000000000000007F :10D1B000000000000000000000000000000000006F :10D1C000000000000000000000000000000000005F :10D1D000000000000000000000000000000000004F :10D1E000000000000000000000000000000000003F :10D1F000000000000000000000000000000000002F :10D20000000000000000000000000000000000001E :10D21000000000000000000000000000000000000E :10D2200000000000000000000000000000000000FE :10D2300000000000000000000000000000000000EE :10D2400000000000000000000000000000000000DE :10D2500000000000000000000000000000000000CE :10D2600000000000000000000000000000000000BE :10D2700000000000000000000000000000000000AE :10D28000000000000000000000000000000000009E :10D29000000000000000000000000000000000008E :10D2A000000000000000000000000000000000007E :10D2B000000000000000000000000000000000006E :10D2C000000000000000000000000000000000005E :10D2D000000000000000000000000000000000004E :10D2E000000000000000000000000000000000003E :10D2F000000000000000000000000000000000002E :10D30000000000000000000000000000000000001D :10D31000000000000000000000000000000000000D :10D3200000000000000000000000000000000000FD :10D3300000000000000000000000000000000000ED :10D3400000000000000000000000000000000000DD :10D3500000000000000000000000000000000000CD :10D3600000000000000000000000000000000000BD :10D3700000000000000000000000000000000000AD :10D38000000000000000000000000000000000009D :10D39000000000000000000000000000000000008D :10D3A000000000000000000000000000000000007D :10D3B000000000000000000000000000000000006D :10D3C000000000000000000000000000000000005D :10D3D000000000000000000000000000000000004D :10D3E000000000000000000000000000000000003D :10D3F000000000000000000000000000000000002D :10D40000000000000000000000000000000000001C :10D41000000000000000000000000000000000000C :10D4200000000000000000000000000000000000FC :10D4300000000000000000000000000000000000EC :10D4400000000000000000000000000000000000DC :10D4500000000000000000000000000000000000CC :10D4600000000000000000000000000000000000BC :10D4700000000000000000000000000000000000AC :10D48000000000000000000000000000000000009C :10D49000000000000000000000000000000000008C :10D4A000000000000000000000000000000000007C :10D4B000000000000000000000000000000000006C :10D4C000000000000000000000000000000000005C :10D4D000000000000000000000000000000000004C :10D4E000000000000000000000000000000000003C :10D4F000000000000000000000000000000000002C :10D50000000000000000000000000000000000001B :10D51000000000000000000000000000000000000B :10D5200000000000000000000000000000000000FB :10D5300000000000000000000000000000000000EB :10D5400000000000000000000000000000000000DB :10D5500000000000000000000000000000000000CB :10D5600000000000000000000000000000000000BB :10D5700000000000000000000000000000000000AB :10D58000000000000000000000000000000000009B :10D59000000000000000000000000000000000008B :10D5A000000000000000000000000000000000007B :10D5B000000000000000000000000000000000006B :10D5C000000000000000000000000000000000005B :10D5D000000000000000000000000000000000004B :10D5E000000000000000000000000000000000003B :10D5F000000000000000000000000000000000002B :10D60000000000000000000000000000000000001A :10D61000000000000000000000000000000000000A :10D6200000000000000000000000000000000000FA :10D6300000000000000000000000000000000000EA :10D6400000000000000000000000000000000000DA :10D6500000000000000000000000000000000000CA :10D6600000000000000000000000000000000000BA :10D6700000000000000000000000000000000000AA :10D68000000000000000000000000000000000009A :10D69000000000000000000000000000000000008A :10D6A000000000000000000000000000000000007A :10D6B000000000000000000000000000000000006A :10D6C000000000000000000000000000000000005A :10D6D000000000000000000000000000000000004A :10D6E000000000000000000000000000000000003A :10D6F000000000000000000000000000000000002A :10D700000000000000000000000000000000000019 :10D710000000000000000000000000000000000009 :10D7200000000000000000000000000000000000F9 :10D7300000000000000000000000000000000000E9 :10D7400000000000000000000000000000000000D9 :10D7500000000000000000000000000000000000C9 :10D7600000000000000000000000000000000000B9 :10D7700000000000000000000000000000000000A9 :10D780000000000000000000000000000000000099 :10D790000000000000000000000000000000000089 :10D7A0000000000000000000000000000000000079 :10D7B0000000000000000000000000000000000069 :10D7C0000000000000000000000000000000000059 :10D7D0000000000000000000000000000000000049 :10D7E0000000000000000000000000000000000039 :10D7F0000000000000000000000000000000000029 :10D800000000000000000000000000000000000018 :10D810000000000000000000000000000000000008 :10D8200000000000000000000000000000000000F8 :10D8300000000000000000000000000000000000E8 :10D8400000000000000000000000000000000000D8 :10D8500000000000000000000000000000000000C8 :10D8600000000000000000000000000000000000B8 :10D8700000000000000000000000000000000000A8 :10D880000000000000000000000000000000000098 :10D890000000000000000000000000000000000088 :10D8A0000000000000000000000000000000000078 :10D8B0000000000000000000000000000000000068 :10D8C0000000000000000000000000000000000058 :10D8D0000000000000000000000000000000000048 :10D8E0000000000000000000000000000000000038 :10D8F0000000000000000000000000000000000028 :10D900000000000000000000000000000000000017 :10D910000000000000000000000000000000000007 :10D9200000000000000000000000000000000000F7 :10D9300000000000000000000000000000000000E7 :10D9400000000000000000000000000000000000D7 :10D9500000000000000000000000000000000000C7 :10D9600000000000000000000000000000000000B7 :10D9700000000000000000000000000000000000A7 :10D980000000000000000000000000000000000097 :10D990000000000000000000000000000000000087 :10D9A0000000000000000000000000000000000077 :10D9B0000000000000000000000000000000000067 :10D9C0000000000000000000000000000000000057 :10D9D0000000000000000000000000000000000047 :10D9E0000000000000000000000000000000000037 :10D9F0000000000000000000000000000000000027 :10DA00000000000000000000000000000000000016 :10DA10000000000000000000000000000000000006 :10DA200000000000000000000000000000000000F6 :10DA300000000000000000000000000000000000E6 :10DA400000000000000000000000000000000000D6 :10DA500000000000000000000000000000000000C6 :10DA600000000000000000000000000000000000B6 :10DA700000000000000000000000000000000000A6 :10DA80000000000000000000000000000000000096 :10DA90000000000000000000000000000000000086 :10DAA0000000000000000000000000000000000076 :10DAB0000000000000000000000000000000000066 :10DAC0000000000000000000000000000000000056 :10DAD0000000000000000000000000000000000046 :10DAE0000000000000000000000000000000000036 :10DAF0000000000000000000000000000000000026 :10DB00000000000000000000000000000000000015 :10DB10000000000000000000000000000000000005 :10DB200000000000000000000000000000000000F5 :10DB300000000000000000000000000000000000E5 :10DB400000000000000000000000000000000000D5 :10DB500000000000000000000000000000000000C5 :10DB600000000000000000000000000000000000B5 :10DB700000000000000000000000000000000000A5 :10DB80000000000000000000000000000000000095 :10DB90000000000000000000000000000000000085 :10DBA0000000000000000000000000000000000075 :10DBB0000000000000000000000000000000000065 :10DBC0000000000000000000000000000000000055 :10DBD0000000000000000000000000000000000045 :10DBE0000000000000000000000000000000000035 :10DBF0000000000000000000000000000000000025 :10DC00000000000000000000000000000000000014 :10DC10000000000000000000000000000000000004 :10DC200000000000000000000000000000000000F4 :10DC300000000000000000000000000000000000E4 :10DC400000000000000000000000000000000000D4 :10DC500000000000000000000000000000000000C4 :10DC600000000000000000000000000000000000B4 :10DC700000000000000000000000000000000000A4 :10DC80000000000000000000000000000000000094 :10DC90000000000000000000000000000000000084 :10DCA0000000000000000000000000000000000074 :10DCB0000000000000000000000000000000000064 :10DCC0000000000000000000000000000000000054 :10DCD0000000000000000000000000000000000044 :10DCE0000000000000000000000000000000000034 :10DCF0000000000000000000000000000000000024 :10DD00000000000000000000000000000000000013 :10DD10000000000000000000000000000000000003 :10DD200000000000000000000000000000000000F3 :10DD300000000000000000000000000000000000E3 :10DD400000000000000000000000000000000000D3 :10DD500000000000000000000000000000000000C3 :10DD600000000000000000000000000000000000B3 :10DD700000000000000000000000000000000000A3 :10DD80000000000000000000000000000000000093 :10DD90000000000000000000000000000000000083 :10DDA0000000000000000000000000000000000073 :10DDB0000000000000000000000000000000000063 :10DDC0000000000000000000000000000000000053 :10DDD0000000000000000000000000000000000043 :10DDE0000000000000000000000000000000000033 :10DDF0000000000000000000000000000000000023 :10DE00000000000000000000000000000000000012 :10DE10000000000000000000000000000000000002 :10DE200000000000000000000000000000000000F2 :10DE300000000000000000000000000000000000E2 :10DE400000000000000000000000000000000000D2 :10DE500000000000000000000000000000000000C2 :10DE600000000000000000000000000000000000B2 :10DE700000000000000000000000000000000000A2 :10DE80000000000000000000000000000000000092 :10DE90000000000000000000000000000000000082 :10DEA0000000000000000000000000000000000072 :10DEB0000000000000000000000000000000000062 :10DEC0000000000000000000000000000000000052 :10DED0000000000000000000000000000000000042 :10DEE0000000000000000000000000000000000032 :10DEF0000000000000000000000000000000000022 :10DF00000000000000000000000000000000000011 :10DF10000000000000000000000000000000000001 :10DF200000000000000000000000000000000000F1 :10DF300000000000000000000000000000000000E1 :10DF400000000000000000000000000000000000D1 :10DF500000000000000000000000000000000000C1 :10DF600000000000000000000000000000000000B1 :10DF700000000000000000000000000000000000A1 :10DF80000000000000000000000000000000000091 :10DF90000000000000000000000000000000000081 :10DFA0000000000000000000000000000000000071 :10DFB0000000000000000000000000000000000061 :10DFC0000000000000000000000000000000000051 :10DFD0000000000000000000000000000000000041 :10DFE0000000000000000000000000000000000031 :10DFF0000000000000000000000000000000000021 :10E000000000000000000000000000000000000010 :10E010000000000000000000000000000000000000 :10E0200000000000000000000000000000000000F0 :10E0300000000000000000000000000000000000E0 :10E0400000000000000000000000000000000000D0 :10E0500000000000000000000000000000000000C0 :10E0600000000000000000000000000000000000B0 :10E0700000000000000000000000000000000000A0 :10E080000000000000000000000000000000000090 :10E090000000000000000000000000000000000080 :10E0A0000000000000000000000000000000000070 :10E0B0000000000000000000000000000000000060 :10E0C0000000000000000000000000000000000050 :10E0D0000000000000000000000000000000000040 :10E0E0000000000000000000000000000000000030 :10E0F0000000000000000000000000000000000020 :10E10000000000000000000000000000000000000F :10E1100000000000000000000000000000000000FF :10E1200000000000000000000000000000000000EF :10E1300000000000000000000000000000000000DF :10E1400000000000000000000000000000000000CF :10E1500000000000000000000000000000000000BF :10E1600000000000000000000000000000000000AF :10E17000000000000000000000000000000000009F :10E18000000000000000000000000000000000008F :10E19000000000000000000000000000000000007F :10E1A000000000000000000000000000000000006F :10E1B000000000000000000000000000000000005F :10E1C000000000000000000000000000000000004F :10E1D000000000000000000000000000000000003F :10E1E000000000000000000000000000000000002F :10E1F000000000000000000000000000000000001F :10E20000000000000000000000000000000000000E :10E2100000000000000000000000000000000000FE :10E2200000000000000000000000000000000000EE :10E2300000000000000000000000000000000000DE :10E2400000000000000000000000000000000000CE :10E2500000000000000000000000000000000000BE :10E2600000000000000000000000000000000000AE :10E27000000000000000000000000000000000009E :10E28000000000000000000000000000000000008E :10E29000000000000000000000000000000000007E :10E2A000000000000000000000000000000000006E :10E2B000000000000000000000000000000000005E :10E2C000000000000000000000000000000000004E :10E2D000000000000000000000000000000000003E :10E2E000000000000000000000000000000000002E :10E2F000000000000000000000000000000000001E :10E30000000000000000000000000000000000000D :10E3100000000000000000000000000000000000FD :10E3200000000000000000000000000000000000ED :10E3300000000000000000000000000000000000DD :10E3400000000000000000000000000000000000CD :10E3500000000000000000000000000000000000BD :10E3600000000000000000000000000000000000AD :10E37000000000000000000000000000000000009D :10E38000000000000000000000000000000000008D :10E39000000000000000000000000000000000007D :10E3A000000000000000000000000000000000006D :10E3B000000000000000000000000000000000005D :10E3C000000000000000000000000000000000004D :10E3D000000000000000000000000000000000003D :10E3E000000000000000000000000000000000002D :10E3F000000000000000000000000000000000001D :10E40000000000000000000000000000000000000C :10E4100000000000000000000000000000000000FC :10E4200000000000000000000000000000000000EC :10E4300000000000000000000000000000000000DC :10E4400000000000000000000000000000000000CC :10E4500000000000000000000000000000000000BC :10E4600000000000000000000000000000000000AC :10E47000000000000000000000000000000000009C :10E48000000000000000000000000000000000008C :10E49000000000000000000000000000000000007C :10E4A000000000000000000000000000000000006C :10E4B000000000000000000000000000000000005C :10E4C000000000000000000000000000000000004C :10E4D000000000000000000000000000000000003C :10E4E000000000000000000000000000000000002C :10E4F000000000000000000000000000000000001C :10E50000000000000000000000000000000000000B :10E5100000000000000000000000000000000000FB :10E5200000000000000000000000000000000000EB :10E5300000000000000000000000000000000000DB :10E5400000000000000000000000000000000000CB :10E5500000000000000000000000000000000000BB :10E5600000000000000000000000000000000000AB :10E57000000000000000000000000000000000009B :10E58000000000000000000000000000000000008B :10E59000000000000000000000000000000000007B :10E5A000000000000000000000000000000000006B :10E5B000000000000000000000000000000000005B :10E5C000000000000000000000000000000000004B :10E5D000000000000000000000000000000000003B :10E5E000000000000000000000000000000000002B :10E5F000000000000000000000000000000000001B :10E60000000000000000000000000000000000000A :10E6100000000000000000000000000000000000FA :10E6200000000000000000000000000000000000EA :10E6300000000000000000000000000000000000DA :10E6400000000000000000000000000000000000CA :10E6500000000000000000000000000000000000BA :10E6600000000000000000000000000000000000AA :10E67000000000000000000000000000000000009A :10E68000000000000000000000000000000000008A :10E69000000000000000000000000000000000007A :10E6A000000000000000000000000000000000006A :10E6B000000000000000000000000000000000005A :10E6C000000000000000000000000000000000004A :10E6D000000000000000000000000000000000003A :10E6E000000000000000000000000000000000002A :10E6F000000000000000000000000000000000001A :10E700000000000000000000000000000000000009 :10E7100000000000000000000000000000000000F9 :10E7200000000000000000000000000000000000E9 :10E7300000000000000000000000000000000000D9 :10E7400000000000000000000000000000000000C9 :10E7500000000000000000000000000000000000B9 :10E7600000000000000000000000000000000000A9 :10E770000000000000000000000000000000000099 :10E780000000000000000000000000000000000089 :10E790000000000000000000000000000000000079 :10E7A0000000000000000000000000000000000069 :10E7B0000000000000000000000000000000000059 :10E7C0000000000000000000000000000000000049 :10E7D0000000000000000000000000000000000039 :10E7E0000000000000000000000000000000000029 :10E7F0000000000000000000000000000000000019 :10E800000000000000000000000000000000000008 :10E8100000000000000000000000000000000000F8 :10E8200000000000000000000000000000000000E8 :10E8300000000000000000000000000000000000D8 :10E8400000000000000000000000000000000000C8 :10E8500000000000000000000000000000000000B8 :10E8600000000000000000000000000000000000A8 :10E870000000000000000000000000000000000098 :10E880000000000000000000000000000000000088 :10E890000000000000000000000000000000000078 :10E8A0000000000000000000000000000000000068 :10E8B0000000000000000000000000000000000058 :10E8C0000000000000000000000000000000000048 :10E8D0000000000000000000000000000000000038 :10E8E0000000000000000000000000000000000028 :10E8F0000000000000000000000000000000000018 :10E900000000000000000000000000000000000007 :10E9100000000000000000000000000000000000F7 :10E9200000000000000000000000000000000000E7 :10E9300000000000000000000000000000000000D7 :10E9400000000000000000000000000000000000C7 :10E9500000000000000000000000000000000000B7 :10E9600000000000000000000000000000000000A7 :10E970000000000000000000000000000000000097 :10E980000000000000000000000000000000000087 :10E990000000000000000000000000000000000077 :10E9A0000000000000000000000000000000000067 :10E9B0000000000000000000000000000000000057 :10E9C0000000000000000000000000000000000047 :10E9D0000000000000000000000000000000000037 :10E9E0000000000000000000000000000000000027 :10E9F0000000000000000000000000000000000017 :10EA00000000000000000000000000000000000006 :10EA100000000000000000000000000000000000F6 :10EA200000000000000000000000000000000000E6 :10EA300000000000000000000000000000000000D6 :10EA400000000000000000000000000000000000C6 :10EA500000000000000000000000000000000000B6 :10EA600000000000000000000000000000000000A6 :10EA70000000000000000000000000000000000096 :10EA80000000000000000000000000000000000086 :10EA90000000000000000000000000000000000076 :10EAA0000000000000000000000000000000000066 :10EAB0000000000000000000000000000000000056 :10EAC0000000000000000000000000000000000046 :10EAD0000000000000000000000000000000000036 :10EAE0000000000000000000000000000000000026 :10EAF0000000000000000000000000000000000016 :10EB00000000000000000000000000000000000005 :10EB100000000000000000000000000000000000F5 :10EB200000000000000000000000000000000000E5 :10EB300000000000000000000000000000000000D5 :10EB400000000000000000000000000000000000C5 :10EB500000000000000000000000000000000000B5 :10EB600000000000000000000000000000000000A5 :10EB70000000000000000000000000000000000095 :10EB80000000000000000000000000000000000085 :10EB90000000000000000000000000000000000075 :10EBA0000000000000000000000000000000000065 :10EBB0000000000000000000000000000000000055 :10EBC0000000000000000000000000000000000045 :10EBD0000000000000000000000000000000000035 :10EBE0000000000000000000000000000000000025 :10EBF0000000000000000000000000000000000015 :10EC00000000000000000000000000000000000004 :10EC100000000000000000000000000000000000F4 :10EC200000000000000000000000000000000000E4 :10EC300000000000000000000000000000000000D4 :10EC400000000000000000000000000000000000C4 :10EC500000000000000000000000000000000000B4 :10EC600000000000000000000000000000000000A4 :10EC70000000000000000000000000000000000094 :10EC80000000000000000000000000000000000084 :10EC90000000000000000000000000000000000074 :10ECA0000000000000000000000000000000000064 :10ECB0000000000000000000000000000000000054 :10ECC0000000000000000000000000000000000044 :10ECD0000000000000000000000000000000000034 :10ECE0000000000000000000000000000000000024 :10ECF0000000000000000000000000000000000014 :10ED00000000000000000000000000000000000003 :10ED100000000000000000000000000000000000F3 :10ED200000000000000000000000000000000000E3 :10ED300000000000000000000000000000000000D3 :10ED400000000000000000000000000000000000C3 :10ED500000000000000000000000000000000000B3 :10ED600000000000000000000000000000000000A3 :10ED70000000000000000000000000000000000093 :10ED80000000000000000000000000000000000083 :10ED90000000000000000000000000000000000073 :10EDA0000000000000000000000000000000000063 :10EDB0000000000000000000000000000000000053 :10EDC0000000000000000000000000000000000043 :10EDD0000000000000000000000000000000000033 :10EDE0000000000000000000000000000000000023 :10EDF0000000000000000000000000000000000013 :10EE00000000000000000000000000000000000002 :10EE100000000000000000000000000000000000F2 :10EE200000000000000000000000000000000000E2 :10EE300000000000000000000000000000000000D2 :10EE400000000000000000000000000000000000C2 :10EE500000000000000000000000000000000000B2 :10EE600000000000000000000000000000000000A2 :10EE70000000000000000000000000000000000092 :10EE80000000000000000000000000000000000082 :10EE90000000000000000000000000000000000072 :10EEA0000000000000000000000000000000000062 :10EEB0000000000000000000000000000000000052 :10EEC0000000000000000000000000000000000042 :10EED0000000000000000000000000000000000032 :10EEE0000000000000000000000000000000000022 :10EEF0000000000000000000000000000000000012 :10EF00000000000000000000000000000000000001 :10EF100000000000000000000000000000000000F1 :10EF200000000000000000000000000000000000E1 :10EF300000000000000000000000000000000000D1 :10EF400000000000000000000000000000000000C1 :10EF500000000000000000000000000000000000B1 :10EF600000000000000000000000000000000000A1 :10EF70000000000000000000000000000000000091 :10EF80000000000000000000000000000000000081 :10EF90000000000000000000000000000000000071 :10EFA0000000000000000000000000000000000061 :10EFB0000000000000000000000000000000000051 :10EFC0000000000000000000000000000000000041 :10EFD0000000000000000000000000000000000031 :10EFE0000000000000000000000000000000000021 :10EFF0000000000000000000000000000000000011 :10F000000000000000000000000000000000000000 :10F0100000000000000000000000000000000000F0 :10F0200000000000000000000000000000000000E0 :10F0300000000000000000000000000000000000D0 :10F0400000000000000000000000000000000000C0 :10F0500000000000000000000000000000000000B0 :10F0600000000000000000000000000000000000A0 :10F070000000000000000000000000000000000090 :10F080000000000000000000000000000000000080 :10F090000000000000000000000000000000000070 :10F0A0000000000000000000000000000000000060 :10F0B0000000000000000000000000000000000050 :10F0C0000000000000000000000000000000000040 :10F0D0000000000000000000000000000000000030 :10F0E0000000000000000000000000000000000020 :10F0F0000000000000000000000000000000000010 :10F1000000000000000000000000000000000000FF :10F1100000000000000000000000000000000000EF :10F1200000000000000000000000000000000000DF :10F1300000000000000000000000000000000000CF :10F1400000000000000000000000000000000000BF :10F1500000000000000000000000000000000000AF :10F16000000000000000000000000000000000009F :10F17000000000000000000000000000000000008F :10F18000000000000000000000000000000000007F :10F19000000000000000000000000000000000006F :10F1A000000000000000000000000000000000005F :10F1B000000000000000000000000000000000004F :10F1C000000000000000000000000000000000003F :10F1D000000000000000000000000000000000002F :10F1E000000000000000000000000000000000001F :10F1F000000000000000000000000000000000000F :10F2000000000000000000000000000000000000FE :10F2100000000000000000000000000000000000EE :10F2200000000000000000000000000000000000DE :10F2300000000000000000000000000000000000CE :10F2400000000000000000000000000000000000BE :10F2500000000000000000000000000000000000AE :10F26000000000000000000000000000000000009E :10F27000000000000000000000000000000000008E :10F28000000000000000000000000000000000007E :10F29000000000000000000000000000000000006E :10F2A000000000000000000000000000000000005E :10F2B000000000000000000000000000000000004E :10F2C000000000000000000000000000000000003E :10F2D000000000000000000000000000000000002E :10F2E000000000000000000000000000000000001E :10F2F000000000000000000000000000000000000E :10F3000000000000000000000000000000000000FD :10F3100000000000000000000000000000000000ED :10F3200000000000000000000000000000000000DD :10F3300000000000000000000000000000000000CD :10F3400000000000000000000000000000000000BD :10F3500000000000000000000000000000000000AD :10F36000000000000000000000000000000000009D :10F37000000000000000000000000000000000008D :10F38000000000000000000000000000000000007D :10F39000000000000000000000000000000000006D :10F3A000000000000000000000000000000000005D :10F3B000000000000000000000000000000000004D :10F3C000000000000000000000000000000000003D :10F3D000000000000000000000000000000000002D :10F3E000000000000000000000000000000000001D :10F3F000000000000000000000000000000000000D :10F4000000000000000000000000000000000000FC :10F4100000000000000000000000000000000000EC :10F4200000000000000000000000000000000000DC :10F4300000000000000000000000000000000000CC :10F4400000000000000000000000000000000000BC :10F4500000000000000000000000000000000000AC :10F46000000000000000000000000000000000009C :10F47000000000000000000000000000000000008C :10F48000000000000000000000000000000000007C :10F49000000000000000000000000000000000006C :10F4A000000000000000000000000000000000005C :10F4B000000000000000000000000000000000004C :10F4C000000000000000000000000000000000003C :10F4D000000000000000000000000000000000002C :10F4E000000000000000000000000000000000001C :10F4F000000000000000000000000000000000000C :10F5000000000000000000000000000000000000FB :10F5100000000000000000000000000000000000EB :10F5200000000000000000000000000000000000DB :10F5300000000000000000000000000000000000CB :10F5400000000000000000000000000000000000BB :10F5500000000000000000000000000000000000AB :10F56000000000000000000000000000000000009B :10F57000000000000000000000000000000000008B :10F58000000000000000000000000000000000007B :10F59000000000000000000000000000000000006B :10F5A000000000000000000000000000000000005B :10F5B000000000000000000000000000000000004B :10F5C000000000000000000000000000000000003B :10F5D000000000000000000000000000000000002B :10F5E000000000000000000000000000000000001B :10F5F000000000000000000000000000000000000B :10F6000000000000000000000000000000000000FA :10F6100000000000000000000000000000000000EA :10F6200000000000000000000000000000000000DA :10F6300000000000000000000000000000000000CA :10F6400000000000000000000000000000000000BA :10F6500000000000000000000000000000000000AA :10F66000000000000000000000000000000000009A :10F67000000000000000000000000000000000008A :10F68000000000000000000000000000000000007A :10F69000000000000000000000000000000000006A :10F6A000000000000000000000000000000000005A :10F6B000000000000000000000000000000000004A :10F6C000000000000000000000000000000000003A :10F6D000000000000000000000000000000000002A :10F6E000000000000000000000000000000000001A :10F6F000000000000000000000000000000000000A :10F7000000000000000000000000000000000000F9 :10F7100000000000000000000000000000000000E9 :10F7200000000000000000000000000000000000D9 :10F7300000000000000000000000000000000000C9 :10F7400000000000000000000000000000000000B9 :10F7500000000000000000000000000000000000A9 :10F760000000000000000000000000000000000099 :10F770000000000000000000000000000000000089 :10F780000000000000000000000000000000000079 :10F790000000000000000000000000000000000069 :10F7A0000000000000000000000000000000000059 :10F7B0000000000000000000000000000000000049 :10F7C0000000000000000000000000000000000039 :10F7D0000000000000000000000000000000000029 :10F7E0000000000000000000000000000000000019 :10F7F0000000000000000000000000000000000009 :10F8000000000000000000000000000000000000F8 :10F8100000000000000000000000000000000000E8 :10F8200000000000000000000000000000000000D8 :10F8300000000000000000000000000000000000C8 :10F8400000000000000000000000000000000000B8 :10F8500000000000000000000000000000000000A8 :10F860000000000000000000000000000000000098 :10F870000000000000000000000000000000000088 :10F880000000000000000000000000000000000078 :10F890000000000000000000000000000000000068 :10F8A0000000000000000000000000000000000058 :10F8B0000000000000000000000000000000000048 :10F8C0000000000000000000000000000000000038 :10F8D0000000000000000000000000000000000028 :10F8E0000000000000000000000000000000000018 :10F8F0000000000000000000000000000000000008 :10F9000000000000000000000000000000000000F7 :10F9100000000000000000000000000000000000E7 :10F9200000000000000000000000000000000000D7 :10F9300000000000000000000000000000000000C7 :10F9400000000000000000000000000000000000B7 :10F9500000000000000000000000000000000000A7 :10F960000000000000000000000000000000000097 :10F970000000000000000000000000000000000087 :10F980000000000000000000000000000000000077 :10F990000000000000000000000000000000000067 :10F9A0000000000000000000000000000000000057 :10F9B0000000000000000000000000000000000047 :10F9C0000000000000000000000000000000000037 :10F9D0000000000000000000000000000000000027 :10F9E0000000000000000000000000000000000017 :10F9F0000000000000000000000000000000000007 :10FA000000000000000000000000000000000000F6 :10FA100000000000000000000000000000000000E6 :10FA200000000000000000000000000000000000D6 :10FA300000000000000000000000000000000000C6 :10FA400000000000000000000000000000000000B6 :10FA500000000000000000000000000000000000A6 :10FA60000000000000000000000000000000000096 :10FA70000000000000000000000000000000000086 :10FA80000000000000000000000000000000000076 :10FA90000000000000000000000000000000000066 :10FAA0000000000000000000000000000000000056 :10FAB0000000000000000000000000000000000046 :10FAC0000000000000000000000000000000000036 :10FAD0000000000000000000000000000000000026 :10FAE0000000000000000000000000000000000016 :10FAF0000000000000000000000000000000000006 :10FB000000000000000000000000000000000000F5 :10FB100000000000000000000000000000000000E5 :10FB200000000000000000000000000000000000D5 :10FB300000000000000000000000000000000000C5 :10FB400000000000000000000000000000000000B5 :10FB500000000000000000000000000000000000A5 :10FB60000000000000000000000000000000000095 :10FB70000000000000000000000000000000000085 :10FB80000000000000000000000000000000000075 :10FB90000000000000000000000000000000000065 :10FBA0000000000000000000000000000000000055 :10FBB0000000000000000000000000000000000045 :10FBC0000000000000000000000000000000000035 :10FBD0000000000000000000000000000000000025 :10FBE0000000000000000000000000000000000015 :10FBF0000000000000000000000000000000000005 :10FC000000000000000000000000000000000000F4 :10FC100000000000000000000000000000000000E4 :10FC200000000000000000000000000000000000D4 :10FC300000000000000000000000000000000000C4 :10FC400000000000000000000000000000000000B4 :10FC500000000000000000000000000000000000A4 :10FC60000000000000000000000000000000000094 :10FC70000000000000000000000000000000000084 :10FC80000000000000000000000000000000000074 :10FC90000000000000000000000000000000000064 :10FCA0000000000000000000000000000000000054 :10FCB0000000000000000000000000000000000044 :10FCC0000000000000000000000000000000000034 :10FCD0000000000000000000000000000000000024 :10FCE0000000000000000000000000000000000014 :10FCF0000000000000000000000000000000000004 :10FD000000000000000000000000000000000000F3 :10FD100000000000000000000000000000000000E3 :10FD200000000000000000000000000000000000D3 :10FD300000000000000000000000000000000000C3 :10FD400000000000000000000000000000000000B3 :10FD500000000000000000000000000000000000A3 :10FD60000000000000000000000000000000000093 :10FD70000000000000000000000000000000000083 :10FD80000000000000000000000000000000000073 :10FD90000000000000000000000000000000000063 :10FDA0000000000000000000000000000000000053 :10FDB0000000000000000000000000000000000043 :10FDC0000000000000000000000000000000000033 :10FDD0000000000000000000000000000000000023 :10FDE0000000000000000000000000000000000013 :10FDF0000000000000000000000000000000000003 :10FE000000000000000000000000000000000000F2 :10FE100000000000000000000000000000000000E2 :10FE200000000000000000000000000000000000D2 :10FE300000000000000000000000000000000000C2 :10FE400000000000000000000000000000000000B2 :10FE500000000000000000000000000000000000A2 :10FE60000000000000000000000000000000000092 :10FE70000000000000000000000000000000000082 :10FE80000000000000000000000000000000000072 :10FE90000000000000000000000000000000000062 :10FEA0000000000000000000000000000000000052 :10FEB0000000000000000000000000000000000042 :10FEC0000000000000000000000000000000000032 :10FED0000000000000000000000000000000000022 :10FEE0000000000000000000000000000000000012 :10FEF0000000000000000000000000000000000002 :10FF000000000000000000000000000000000000F1 :10FF100000000000000000000000000000000000E1 :10FF200000000000000000000000000000000000D1 :10FF300000000000000000000000000000000000C1 :10FF400000000000000000000000000000000000B1 :10FF500000000000000000000000000000000000A1 :10FF60000000000000000000000000000000000091 :10FF70000000000000000000000000000000000081 :10FF80000000000000000000000000000000000071 :10FF90000000000000000000000000000000000061 :10FFA0000000000000000000000000000000000051 :10FFB0000000000000000000000000000000000041 :10FFC0000000000000000000000000000000000031 :10FFD0000000000000000000000000000000000021 :10FFE0000000000000000000000000000000000011 :10FFF0000000000000000000000000000000000001 :02000004620494 :1000000000000000000000000000000000000000F0 :1000100000000000000000000000000000000000E0 :1000200000000000000000000000000000000000D0 :1000300000000000000000000000000000000000C0 :1000400000000000000000000000000000000000B0 :1000500000000000000000000000000000000000A0 :100060000000000000000000000000000000000090 :100070000000000000000000000000000000000080 :100080000000000000000000000000000000000070 :100090000000000000000000000000000000000060 :1000A0000000000000000000000000000000000050 :1000B0000000000000000000000000000000000040 :1000C0000000000000000000000000000000000030 :1000D0000000000000000000000000000000000020 :1000E0000000000000000000000000000000000010 :1000F0000000000000000000000000000000000000 :1001000000000000000000000000000000000000EF :1001100000000000000000000000000000000000DF :1001200000000000000000000000000000000000CF :1001300000000000000000000000000000000000BF :1001400000000000000000000000000000000000AF :10015000000000000000000000000000000000009F :10016000000000000000000000000000000000008F :10017000000000000000000000000000000000007F :10018000000000000000000000000000000000006F :10019000000000000000000000000000030000005C :1001A000000000000000000000000000000000004F :1001B000000000000000000000000000000000003F :1001C000000000000000000000000000000000002F :1001D000000000000000000000000000000000001F :1001E000000000000000000000000000000000000F :1001F00000000000000000000000000000000000FF :1002000000000000000000000000000000000000EE :1002100000000000000000000000000000000000DE :1002200000000000000000000000000000000000CE :1002300000000000000000000000000000000000BE :1002400000000000000000000000000000000000AE :10025000000000000000000000000000000000009E :10026000000000000000000000000000000000008E :10027000000000000000000000000000000000007E :10028000000000000000000000000000000000006E :10029000000000000000000000000000000000005E :1002A000000000000000000000000000000000004E :1002B000000000000000000000000000000000003E :1002C000000000000000000000000000000000002E :1002D000000000000000000000000000000000001E :1002E000000000000000000000000000000000000E :1002F00000000000000000000000000000000000FE :1003000000000000000000000000000000000000ED :1003100000000000000000000000000000000000DD :1003200000000000000000000000000000000000CD :1003300000000000000000000000000000000000BD :1003400000000000000000000000000000000000AD :10035000000000000000000000000000000000009D :10036000000000000000000000000000000000008D :10037000000000000000000000000000000000007D :10038000000000000000000000000000000000006D :10039000000000000000000000000000000000005D :1003A000000000000000000000000000000000004D :1003B000000000000000000000000000000000003D :1003C000000000000000000000000000000000002D :1003D000000000000000000000000000000000001D :1003E000000000000000000000000000000000000D :1003F00000000000000000000000000000000000FD :1004000000000000000000000000000000000000EC :1004100000000000000000000000000000000000DC :1004200000000000000000000000000000000000CC :1004300000000000000000000000000000000000BC :1004400000000000000000000000000000000000AC :10045000000000000000000000000000000000009C :10046000000000000000000000000000000000008C :10047000000000000000000000000000000000007C :10048000000000000000000000000000000000006C :10049000000000000000000000000000000000005C :1004A000000000000000000000000000000000004C :1004B000000000000000000000000000000000003C :1004C000000000000000000000000000000000002C :1004D000000000000000000000000000000000001C :1004E000000000000000000000000000000000000C :1004F00000000000000000000000000000000000FC :1005000000000000000000000000000000000000EB :1005100000000000000000000000000000000000DB :1005200000000000000000000000000000000000CB :1005300000000000000000000000000000000000BB :1005400000000000000000000000000000000000AB :10055000000000000000000000000000000000009B :10056000000000000000000000000000000000008B :10057000000000000000000000000000000000007B :10058000000000000000000000000000000000006B :10059000000000000000000000000000000000005B :1005A000000000000000000000000000000000004B :1005B000000000000000000000000000000000003B :1005C000000000000000000000000000000000002B :1005D000000000000000000000000000000000001B :1005E000000000000000000000000000000000000B :1005F00000000000000000000000000000000000FB :1006000000000000000000000000000000000000EA :1006100000000000000000000000000000000000DA :1006200000000000000000000000000000000000CA :1006300000000000000000000000000000000000BA :1006400000000000000000000000000000000000AA :10065000000000000000000000000000000000009A :10066000000000000000000000000000000000008A :10067000000000000000000000000000000000007A :10068000000000000000000000000000000000006A :10069000000000000000000000000000000000005A :1006A000000000000000000000000000000000004A :1006B000000000000000000000000000000000003A :1006C000000000000000000000000000000000002A :1006D000000000000000000000000000000000001A :1006E000000000000000000000000000000000000A :1006F00000000000000000000000000000000000FA :1007000000000000000000000000000000000000E9 :1007100000000000000000000000000000000000D9 :1007200000000000000000000000000000000000C9 :1007300000000000000000000000000000000000B9 :1007400000000000000000000000000000000000A9 :100750000000000000000000000000000000000099 :100760000000000000000000000000000000000089 :100770000000000000000000000000000000000079 :100780000000000000000000000000000000000069 :100790000000000000000000000000000000000059 :1007A0000000000000000000000000000000000049 :1007B0000000000000000000000000000000000039 :1007C0000000000000000000000000000000000029 :1007D0000000000000000000000000000000000019 :1007E0000000000000000000000000000000000009 :1007F00000000000000000000000000000000000F9 :1008000000000000000000000000000000000000E8 :1008100000000000000000000000000000000000D8 :1008200000000000000000000000000000000000C8 :1008300000000000000000000000000000000000B8 :1008400000000000000000000000000000000000A8 :100850000000000000000000000000000000000098 :100860000000000000000000000000000000000088 :100870000000000000000000000000000000000078 :100880000000000000000000000000000000000068 :100890000000000000000000000000000000000058 :1008A0000000000000000000000000000000000048 :1008B0000000000000000000000000000000000038 :1008C0000000000000000000000000000000000028 :1008D0000000000000000000000000000000000018 :1008E0000000000000000000000000000000000008 :1008F00000000000000000000000000000000000F8 :1009000000000000000000000000000000000000E7 :1009100000000000000000000000000000000000D7 :1009200000000000000000000000000000000000C7 :1009300000000000000000000000000000000000B7 :1009400000000000000000000000000000000000A7 :100950000000000000000000000000000000000097 :100960000000000000000000000000000000000087 :100970000000000000000000000000000000000077 :100980000000000000000000000000000000000067 :100990000000000000000000000000000000000057 :1009A0000000000000000000000000000000000047 :1009B0000000000000000000000000000000000037 :1009C0000000000000000000000000000000000027 :1009D0000000000000000000000000000000000017 :1009E0000000000000000000000000000000000007 :1009F00000000000000000000000000000000000F7 :100A000000000000000000000000000000000000E6 :100A100000000000000000000000000000000000D6 :100A200000000000000000000000000000000000C6 :100A300000000000000000000000000000000000B6 :100A400000000000000000000000000000000000A6 :100A50000000000000000000000000000000000096 :100A60000000000000000000000000000000000086 :100A70000000000000000000000000000000000076 :100A80000000000000000000000000000000000066 :100A90000000000000000000000000000000000056 :100AA0000000000000000000000000000000000046 :100AB0000000000000000000000000000000000036 :100AC0000000000000000000000000000000000026 :100AD0000000000000000000000000000000000016 :100AE0000000000000000000000000000000000006 :100AF00000000000000000000000000000000000F6 :100B000000000000000000000000000000000000E5 :100B100000000000000000000000000000000000D5 :100B200000000000000000000000000000000000C5 :100B300000000000000000000000000000000000B5 :100B400000000000000000000000000000000000A5 :100B50000000000000000000000000000000000095 :100B60000000000000000000000000000000000085 :100B70000000000000000000000000000000000075 :100B80000000000000000000000000000000000065 :100B90000000000000000000000000000000000055 :100BA0000000000000000000000000000000000045 :100BB0000000000000000000000000000000000035 :100BC0000000000000000000000000000000000025 :100BD0000000000000000000000000000000000015 :100BE0000000000000000000000000000000000005 :100BF00000000000000000000000000000000000F5 :100C000000000000000000000000000000000000E4 :100C100000000000000000000000000000000000D4 :100C200000000000000000000000000000000000C4 :100C300000000000000000000000000000000000B4 :100C400000000000000000000000000000000000A4 :100C50000000000000000000000000000000000094 :100C60000000000000000000000000000000000084 :100C70000000000000000000000000000000000074 :100C80000000000000000000000000000000000064 :100C90000000000000000000000000000000000054 :100CA0000000000000000000000000000000000044 :100CB0000000000000000000000000000000000034 :100CC0000000000000000000000000000000000024 :100CD0000000000000000000000000000000000014 :100CE0000000000000000000000000000000000004 :100CF00000000000000000000000000000000000F4 :100D000000000000000000000000000000000000E3 :100D100000000000000000000000000000000000D3 :100D200000000000000000000000000000000000C3 :100D300000000000000000000000000000000000B3 :100D400000000000000000000000000000000000A3 :100D50000000000000000000000000000000000093 :100D60000000000000000000000000000000000083 :100D70000000000000000000000000000000000073 :100D80000000000000000000000000000000000063 :100D90000000000000000000000000000000000053 :100DA0000000000000000000000000000000000043 :100DB0000000000000000000000000000000000033 :100DC0000000000000000000000000000000000023 :100DD0000000000000000000000000000000000013 :100DE0000000000000000000000000000000000003 :100DF00000000000000000000000000000000000F3 :100E000000000000000000000000000000000000E2 :100E100000000000000000000000000000000000D2 :100E200000000000000000000000000000000000C2 :100E300000000000000000000000000000000000B2 :100E400000000000000000000000000000000000A2 :100E50000000000000000000000000000000000092 :100E60000000000000000000000000000000000082 :100E70000000000000000000000000000000000072 :100E80000000000000000000000000000000000062 :100E90000000000000000000000000000000000052 :100EA0000000000000000000000000000000000042 :100EB0000000000000000000000000000000000032 :100EC0000000000000000000000000000000000022 :100ED0000000000000000000000000000000000012 :100EE0000000000000000000000000000000000002 :100EF00000000000000000000000000000000000F2 :100F000000000000000000000000000000000000E1 :100F100000000000000000000000000000000000D1 :100F200000000000000000000000000000000000C1 :100F300000000000000000000000000000000000B1 :100F400000000000000000000000000000000000A1 :100F50000000000000000000000000000000000091 :100F60000000000000000000000000000000000081 :100F70000000000000000000000000000000000071 :100F80000000000000000000000000000000000061 :100F90000000000000000000000000000000000051 :100FA0000000000000000000000000000000000041 :100FB0000000000000000000000000000000000031 :100FC0000000000000000000000000000000000021 :100FD0000000000000000000000000000000000011 :100FE0000000000000000000000000000000000001 :100FF00000000000000000000000000000000000F1 :1010000000000000000000000000000000000000E0 :1010100000000000000000000000000000000000D0 :1010200000000000000000000000000000000000C0 :1010300000000000000000000000000000000000B0 :1010400000000000000000000000000000000000A0 :101050000000000000000000000000000000000090 :101060000000000000000000000000000000000080 :101070000000000000000000000000000000000070 :101080000000000000000000000000000000000060 :101090000000000000000000000000000000000050 :1010A0000000000000000000000000000000000040 :1010B0000000000000000000000000000000000030 :1010C0000000000000000000000000000000000020 :1010D0000000000000000000000000000000000010 :1010E0000000000000000000000000000000000000 :1010F00000000000000000000000000000000000F0 :1011000000000000000000000000000000000000DF :1011100000000000000000000000000000000000CF :1011200000000000000000000000000000000000BF :1011300000000000000000000000000000000000AF :10114000000000000000000000000000000000009F :10115000000000000000000000000000000000008F :10116000000000000000000000000000000000007F :10117000000000000000000000000000000000006F :10118000000000000000000000000000000000005F :10119000000000000000000000000000000000004F :1011A000000000000000000000000000000000003F :1011B000000000000000000000000000000000002F :1011C000000000000000000000000000000000001F :1011D000000000000000000000000000000000000F :1011E00000000000000000000000000000000000FF :1011F00000000000000000000000000000000000EF :1012000000000000000000000000000000000000DE :1012100000000000000000000000000000000000CE :1012200000000000000000000000000000000000BE :1012300000000000000000000000000000000000AE :10124000000000000000000000000000000000009E :10125000000000000000000000000000000000008E :10126000000000000000000000000000000000007E :10127000000000000000000000000000000000006E :10128000000000000000000000000000000000005E :10129000000000000000000000000000000000004E :1012A000000000000000000000000000000000003E :1012B000000000000000000000000000000000002E :1012C000000000000000000000000000000000001E :1012D000000000000000000000000000000000000E :1012E00000000000000000000000000000000000FE :1012F00000000000000000000000000000000000EE :1013000000000000000000000000000000000000DD :1013100000000000000000000000000000000000CD :1013200000000000000000000000000000000000BD :1013300000000000000000000000000000000000AD :10134000000000000000000000000000000000009D :10135000000000000000000000000000000000008D :10136000000000000000000000000000000000007D :10137000000000000000000000000000000000006D :10138000000000000000000000000000000000005D :10139000000000000000000000000000000000004D :1013A000000000000000000000000000000000003D :1013B000000000000000000000000000000000002D :1013C000000000000000000000000000000000001D :1013D000000000000000000000000000000000000D :1013E00000000000000000000000000000000000FD :1013F00000000000000000000000000000000000ED :1014000000000000000000000000000000000000DC :1014100000000000000000000000000000000000CC :1014200000000000000000000000000000000000BC :1014300000000000000000000000000000000000AC :10144000000000000000000000000000000000009C :10145000000000000000000000000000000000008C :10146000000000000000000000000000000000007C :10147000000000000000000000000000000000006C :10148000000000000000000000000000000000005C :10149000000000000000000000000000000000004C :1014A000000000000000000000000000000000003C :1014B000000000000000000000000000000000002C :1014C000000000000000000000000000000000001C :1014D000000000000000000000000000000000000C :1014E00000000000000000000000000000000000FC :1014F00000000000000000000000000000000000EC :1015000000000000000000000000000000000000DB :1015100000000000000000000000000000000000CB :1015200000000000000000000000000000000000BB :1015300000000000000000000000000000000000AB :10154000000000000000000000000000000000009B :10155000000000000000000000000000000000008B :10156000000000000000000000000000000000007B :10157000000000000000000000000000000000006B :10158000000000000000000000000000000000005B :10159000000000000000000000000000000000004B :1015A000000000000000000000000000000000003B :1015B000000000000000000000000000000000002B :1015C000000000000000000000000000000000001B :1015D000000000000000000000000000000000000B :1015E00000000000000000000000000000000000FB :1015F00000000000000000000000000000000000EB :1016000000000000000000000000000000000000DA :1016100000000000000000000000000000000000CA :1016200000000000000000000000000000000000BA :1016300000000000000000000000000000000000AA :10164000000000000000000000000000000000009A :10165000000000000000000000000000000000008A :10166000000000000000000000000000000000007A :10167000000000000000000000000000000000006A :10168000000000000000000000000000000000005A :10169000000000000000000000000000000000004A :1016A000000000000000000000000000000000003A :1016B000000000000000000000000000000000002A :1016C000000000000000000000000000000000001A :1016D000000000000000000000000000000000000A :1016E00000000000000000000000000000000000FA :1016F00000000000000000000000000000000000EA :1017000000000000000000000000000000000000D9 :1017100000000000000000000000000000000000C9 :1017200000000000000000000000000000000000B9 :1017300000000000000000000000000000000000A9 :101740000000000000000000000000000000000099 :101750000000000000000000000000000000000089 :101760000000000000000000000000000000000079 :101770000000000000000000000000000000000069 :101780000000000000000000000000000000000059 :101790000000000000000000000000000000000049 :1017A0000000000000000000000000000000000039 :1017B0000000000000000000000000000000000029 :1017C0000000000000000000000000000000000019 :1017D0000000000000000000000000000000000009 :1017E00000000000000000000000000000000000F9 :1017F00000000000000000000000000000000000E9 :1018000000000000000000000000000000000000D8 :1018100000000000000000000000000000000000C8 :1018200000000000000000000000000000000000B8 :1018300000000000000000000000000000000000A8 :101840000000000000000000000000000000000098 :101850000000000000000000000000000000000088 :101860000000000000000000000000000000000078 :101870000000000000000000000000000000000068 :101880000000000000000000000000000000000058 :101890000000000000000000000000000000000048 :1018A0000000000000000000000000000000000038 :1018B0000000000000000000000000000000000028 :1018C0000000000000000000000000000000000018 :1018D0000000000000000000000000000000000008 :1018E00000000000000000000000000000000000F8 :1018F00000000000000000000000000000000000E8 :1019000000000000000000000000000000000000D7 :1019100000000000000000000000000000000000C7 :1019200000000000000000000000000000000000B7 :1019300000000000000000000000000000000000A7 :101940000000000000000000000000000000000097 :101950000000000000000000000000000000000087 :101960000000000000000000000000000000000077 :101970000000000000000000000000000000000067 :101980000000000000000000000000000000000057 :101990000000000000000000000000000000000047 :1019A0000000000000000000000000000000000037 :1019B0000000000000000000000000000000000027 :1019C0000000000000000000000000000000000017 :1019D0000000000000000000000000000000000007 :1019E00000000000000000000000000000000000F7 :1019F00000000000000000000000000000000000E7 :101A000000000000000000000000000000000000D6 :101A100000000000000000000000000000000000C6 :101A200000000000000000000000000000000000B6 :101A300000000000000000000000000000000000A6 :101A40000000000000000000000000000000000096 :101A50000000000000000000000000000000000086 :101A60000000000000000000000000000000000076 :101A70000000000000000000000000000000000066 :101A80000000000000000000000000000000000056 :101A90000000000000000000000000000000000046 :101AA0000000000000000000000000000000000036 :101AB0000000000000000000000000000000000026 :101AC0000000000000000000000000000000000016 :101AD0000000000000000000000000000000000006 :101AE00000000000000000000000000000000000F6 :101AF00000000000000000000000000000000000E6 :101B000000000000000000000000000000000000D5 :101B100000000000000000000000000000000000C5 :101B200000000000000000000000000000000000B5 :101B300000000000000000000000000000000000A5 :101B40000000000000000000000000000000000095 :101B50000000000000000000000000000000000085 :101B60000000000000000000000000000000000075 :101B70000000000000000000000000000000000065 :101B80000000000000000000000000000000000055 :101B90000000000000000000000000000000000045 :101BA0000000000000000000000000000000000035 :101BB0000000000000000000000000000000000025 :101BC0000000000000000000000000000000000015 :101BD0000000000000000000000000000000000005 :101BE00000000000000000000000000000000000F5 :101BF00000000000000000000000000000000000E5 :101C000000000000000000000000000000000000D4 :101C100000000000000000000000000000000000C4 :101C200000000000000000000000000000000000B4 :101C300000000000000000000000000000000000A4 :101C40000000000000000000000000000000000094 :101C50000000000000000000000000000000000084 :101C60000000000000000000000000000000000074 :101C70000000000000000000000000000000000064 :101C80000000000000000000000000000000000054 :101C90000000000000000000000000000000000044 :101CA0000000000000000000000000000000000034 :101CB0000000000000000000000000000000000024 :101CC0000000000000000000000000000000000014 :101CD0000000000000000000000000000000000004 :101CE00000000000000000000000000000000000F4 :101CF00000000000000000000000000000000000E4 :101D000000000000000000000000000000000000D3 :101D100000000000000000000000000000000000C3 :101D200000000000000000000000000000000000B3 :101D300000000000000000000000000000000000A3 :101D40000000000000000000000000000000000093 :101D50000000000000000000000000000000000083 :101D60000000000000000000000000000000000073 :101D70000000000000000000000000000000000063 :101D80000000000000000000000000000000000053 :101D90000000000000000000000000000000000043 :101DA0000000000000000000000000000000000033 :101DB0000000000000000000000000000000000023 :101DC0000000000000000000000000000000000013 :101DD0000000000000000000000000000000000003 :101DE00000000000000000000000000000000000F3 :101DF00000000000000000000000000000000000E3 :101E000000000000000000000000000000000000D2 :101E100000000000000000000000000000000000C2 :101E200000000000000000000000000000000000B2 :101E300000000000000000000000000000000000A2 :101E40000000000000000000000000000000000092 :101E50000000000000000000000000000000000082 :101E60000000000000000000000000000000000072 :101E70000000000000000000000000000000000062 :101E80000000000000000000000000000000000052 :101E90000000000000000000000000000000000042 :101EA0000000000000000000000000000000000032 :101EB0000000000000000000000000000000000022 :101EC0000000000000000000000000000000000012 :101ED0000000000000000000000000000000000002 :101EE00000000000000000000000000000000000F2 :101EF00000000000000000000000000000000000E2 :101F000000000000000000000000000000000000D1 :101F100000000000000000000000000000000000C1 :101F200000000000000000000000000000000000B1 :101F300000000000000000000000000000000000A1 :101F40000000000000000000000000000000000091 :101F50000000000000000000000000000000000081 :101F60000000000000000000000000000000000071 :101F70000000000000000000000000000000000061 :101F80000000000000000000000000000000000051 :101F90000000000000000000000000000000000041 :101FA0000000000000000000000000000000000031 :101FB0000000000000000000000000000000000021 :101FC0000000000000000000000000000000000011 :101FD0000000000000000000000000000000000001 :101FE00000000000000000000000000000000000F1 :101FF00000000000000000000000000000000000E1 :1020000000000000000000000000000000000000D0 :1020100000000000000000000000000000000000C0 :1020200000000000000000000000000000000000B0 :1020300000000000000000000000000000000000A0 :102040000000000000000000000000000000000090 :102050000000000000000000000000000000000080 :102060000000000000000000000000000000000070 :102070000000000000000000000000000000000060 :102080000000000000000000000000000000000050 :102090000000000000000000000000000000000040 :1020A0000000000000000000000000000000000030 :1020B0000000000000000000000000000000000020 :1020C0000000000000000000000000000000000010 :1020D0000000000000000000000000000000000000 :1020E00000000000000000000000000000000000F0 :1020F00000000000000000000000000000000000E0 :1021000000000000000000000000000000000000CF :1021100000000000000000000000000000000000BF :1021200000000000000000000000000000000000AF :10213000000000000000000000000000000000009F :10214000000000000000000000000000000000008F :10215000000000000000000000000000000000007F :10216000000000000000000000000000000000006F :10217000000000000000000000000000000000005F :10218000000000000000000000000000000000004F :10219000000000000000000000000000000000003F :1021A000000000000000000000000000000000002F :1021B000000000000000000000000000000000001F :1021C000000000000000000000000000000000000F :1021D00000000000000000000000000000000000FF :1021E00000000000000000000000000000000000EF :1021F00000000000000000000000000000000000DF :1022000000000000000000000000000000000000CE :1022100000000000000000000000000000000000BE :1022200000000000000000000000000000000000AE :10223000000000000000000000000000000000009E :10224000000000000000000000000000000000008E :10225000000000000000000000000000000000007E :10226000000000000000000000000000000000006E :10227000000000000000000000000000000000005E :10228000000000000000000000000000000000004E :10229000000000000000000000000000000000003E :1022A000000000000000000000000000000000002E :1022B000000000000000000000000000000000001E :1022C000000000000000000000000000000000000E :1022D00000000000000000000000000000000000FE :1022E00000000000000000000000000000000000EE :1022F00000000000000000000000000000000000DE :1023000000000000000000000000000000000000CD :1023100000000000000000000000000000000000BD :1023200000000000000000000000000000000000AD :10233000000000000000000000000000000000009D :10234000000000000000000000000000000000008D :10235000000000000000000000000000000000007D :10236000000000000000000000000000000000006D :10237000000000000000000000000000000000005D :10238000000000000000000000000000000000004D :10239000000000000000000000000000000000003D :1023A000000000000000000000000000000000002D :1023B000000000000000000000000000000000001D :1023C000000000000000000000000000000000000D :1023D00000000000000000000000000000000000FD :1023E00000000000000000000000000000000000ED :1023F00000000000000000000000000000000000DD :1024000000000000000000000000000000000000CC :1024100000000000000000000000000000000000BC :1024200000000000000000000000000000000000AC :10243000000000000000000000000000000000009C :10244000000000000000000000000000000000008C :10245000000000000000000000000000000000007C :10246000000000000000000000000000000000006C :10247000000000000000000000000000000000005C :10248000000000000000000000000000000000004C :10249000000000000000000000000000000000003C :1024A000000000000000000000000000000000002C :1024B000000000000000000000000000000000001C :1024C000000000000000000000000000000000000C :1024D00000000000000000000000000000000000FC :1024E00000000000000000000000000000000000EC :1024F00000000000000000000000000000000000DC :1025000000000000000000000000000000000000CB :1025100000000000000000000000000000000000BB :1025200000000000000000000000000000000000AB :10253000000000000000000000000000000000009B :10254000000000000000000000000000000000008B :10255000000000000000000000000000000000007B :10256000000000000000000000000000000000006B :10257000000000000000000000000000000000005B :10258000000000000000000000000000000000004B :10259000000000000000000000000000000000003B :1025A000000000000000000000000000000000002B :1025B000000000000000000000000000000000001B :1025C000000000000000000000000000000000000B :1025D00000000000000000000000000000000000FB :1025E00000000000000000000000000000000000EB :1025F00000000000000000000000000000000000DB :1026000000000000000000000000000000000000CA :1026100000000000000000000000000000000000BA :1026200000000000000000000000000000000000AA :10263000000000000000000000000000000000009A :10264000000000000000000000000000000000008A :10265000000000000000000000000000000000007A :10266000000000000000000000000000000000006A :10267000000000000000000000000000000000005A :10268000000000000000000000000000000000004A :10269000000000000000000000000000000000003A :1026A000000000000000000000000000000000002A :1026B000000000000000000000000000000000001A :1026C000000000000000000000000000000000000A :1026D00000000000000000000000000000000000FA :1026E00000000000000000000000000000000000EA :1026F00000000000000000000000000000000000DA :1027000000000000000000000000000000000000C9 :1027100000000000000000000000000000000000B9 :1027200000000000000000000000000000000000A9 :102730000000000000000000000000000000000099 :102740000000000000000000000000000000000089 :102750000000000000000000000000000000000079 :102760000000000000000000000000000000000069 :102770000000000000000000000000000000000059 :102780000000000000000000000000000000000049 :102790000000000000000000000000000000000039 :1027A0000000000000000000000000000000000029 :1027B0000000000000000000000000000000000019 :1027C0000000000000000000000000000000000009 :1027D00000000000000000000000000000000000F9 :1027E00000000000000000000000000000000000E9 :1027F00000000000000000000000000000000000D9 :1028000000000000000000000000000000000000C8 :1028100000000000000000000000000000000000B8 :1028200000000000000000000000000000000000A8 :102830000000000000000000000000000000000098 :102840000000000000000000000000000000000088 :102850000000000000000000000000000000000078 :102860000000000000000000000000000000000068 :102870000000000000000000000000000000000058 :102880000000000000000000000000000000000048 :102890000000000000000000000000000000000038 :1028A0000000000000000000000000000000000028 :1028B0000000000000000000000000000000000018 :1028C0000000000000000000000000000000000008 :1028D00000000000000000000000000000000000F8 :1028E00000000000000000000000000000000000E8 :1028F00000000000000000000000000000000000D8 :1029000000000000000000000000000000000000C7 :1029100000000000000000000000000000000000B7 :1029200000000000000000000000000000000000A7 :102930000000000000000000000000000000000097 :102940000000000000000000000000000000000087 :102950000000000000000000000000000000000077 :102960000000000000000000000000000000000067 :102970000000000000000000000000000000000057 :102980000000000000000000000000000000000047 :102990000000000000000000000000000000000037 :1029A0000000000000000000000000000000000027 :1029B0000000000000000000000000000000000017 :1029C0000000000000000000000000000000000007 :1029D00000000000000000000000000000000000F7 :1029E00000000000000000000000000000000000E7 :1029F00000000000000000000000000000000000D7 :102A000000000000000000000000000000000000C6 :102A100000000000000000000000000000000000B6 :102A200000000000000000000000000000000000A6 :102A30000000000000000000000000000000000096 :102A40000000000000000000000000000000000086 :102A50000000000000000000000000000000000076 :102A60000000000000000000000000000000000066 :102A70000000000000000000000000000000000056 :102A80000000000000000000000000000000000046 :102A90000000000000000000000000000000000036 :102AA0000000000000000000000000000000000026 :102AB0000000000000000000000000000000000016 :102AC0000000000000000000000000000000000006 :102AD00000000000000000000000000000000000F6 :102AE00000000000000000000000000000000000E6 :102AF00000000000000000000000000000000000D6 :102B000000000000000000000000000000000000C5 :102B100000000000000000000000000000000000B5 :102B200000000000000000000000000000000000A5 :102B30000000000000000000000000000000000095 :102B40000000000000000000000000000000000085 :102B50000000000000000000000000000000000075 :102B60000000000000000000000000000000000065 :102B70000000000000000000000000000000000055 :102B80000000000000000000000000000000000045 :102B90000000000000000000000000000000000035 :102BA0000000000000000000000000000000000025 :102BB0000000000000000000000000000000000015 :102BC0000000000000000000000000000000000005 :102BD00000000000000000000000000000000000F5 :102BE00000000000000000000000000000000000E5 :102BF00000000000000000000000000000000000D5 :102C000000000000000000000000000000000000C4 :102C100000000000000000000000000000000000B4 :102C200000000000000000000000000000000000A4 :102C30000000000000000000000000000000000094 :102C40000000000000000000000000000000000084 :102C50000000000000000000000000000000000074 :102C60000000000000000000000000000000000064 :102C70000000000000000000000000000000000054 :102C80000000000000000000000000000000000044 :102C90000000000000000000000000000000000034 :102CA0000000000000000000000000000000000024 :102CB0000000000000000000000000000000000014 :102CC0000000000000000000000000000000000004 :102CD00000000000000000000000000000000000F4 :102CE00000000000000000000000000000000000E4 :102CF00000000000000000000000000000000000D4 :102D000000000000000000000000000000000000C3 :102D100000000000000000000000000000000000B3 :102D200000000000000000000000000000000000A3 :102D30000000000000000000000000000000000093 :102D40000000000000000000000000000000000083 :102D50000000000000000000000000000000000073 :102D60000000000000000000000000000000000063 :102D70000000000000000000000000000000000053 :102D80000000000000000000000000000000000043 :102D90000000000000000000000000000000000033 :102DA0000000000000000000000000000000000023 :102DB0000000000000000000000000000000000013 :102DC0000000000000000000000000000000000003 :102DD00000000000000000000000000000000000F3 :102DE00000000000000000000000000000000000E3 :102DF00000000000000000000000000000000000D3 :102E000000000000000000000000000000000000C2 :102E100000000000000000000000000000000000B2 :102E200000000000000000000000000000000000A2 :102E30000000000000000000000000000000000092 :102E40000000000000000000000000000000000082 :102E50000000000000000000000000000000000072 :102E60000000000000000000000000000000000062 :102E70000000000000000000000000000000000052 :102E80000000000000000000000000000000000042 :102E90000000000000000000000000000000000032 :102EA0000000000000000000000000000000000022 :102EB0000000000000000000000000000000000012 :102EC0000000000000000000000000000000000002 :102ED00000000000000000000000000000000000F2 :102EE00000000000000000000000000000000000E2 :102EF00000000000000000000000000000000000D2 :102F000000000000000000000000000000000000C1 :102F100000000000000000000000000000000000B1 :102F200000000000000000000000000000000000A1 :102F30000000000000000000000000000000000091 :102F40000000000000000000000000000000000081 :102F50000000000000000000000000000000000071 :102F60000000000000000000000000000000000061 :102F70000000000000000000000000000000000051 :102F80000000000000000000000000000000000041 :102F90000000000000000000000000000000000031 :102FA0000000000000000000000000000000000021 :102FB0000000000000000000000000000000000011 :102FC0000000000000000000000000000000000001 :102FD00000000000000000000000000000000000F1 :102FE00000000000000000000000000000000000E1 :102FF00000000000000000000000000000000000D1 :1030000000000000000000000000000000000000C0 :1030100000000000000000000000000000000000B0 :1030200000000000000000000000000000000000A0 :103030000000000000000000000000000000000090 :103040000000000000000000000000000000000080 :103050000000000000000000000000000000000070 :103060000000000000000000000000000000000060 :103070000000000000000000000000000000000050 :103080000000000000000000000000000000000040 :103090000000000000000000000000000000000030 :1030A0000000000000000000000000000000000020 :1030B0000000000000000000000000000000000010 :1030C0000000000000000000000000000000000000 :1030D00000000000000000000000000000000000F0 :1030E00000000000000000000000000000000000E0 :1030F00000000000000000000000000000000000D0 :1031000000000000000000000000000000000000BF :1031100000000000000000000000000000000000AF :10312000000000000000000000000000000000009F :10313000000000000000000000000000000000008F :10314000000000000000000000000000000000007F :10315000000000000000000000000000000000006F :10316000000000000000000000000000000000005F :10317000000000000000000000000000000000004F :10318000000000000000000000000000000000003F :10319000000000000000000000000000000000002F :1031A000000000000000000000000000000000001F :1031B000000000000000000000000000000000000F :1031C00000000000000000000000000000000000FF :1031D00000000000000000000000000000000000EF :1031E00000000000000000000000000000000000DF :1031F00000000000000000000000000000000000CF :1032000000000000000000000000000000000000BE :1032100000000000000000000000000000000000AE :10322000000000000000000000000000000000009E :10323000000000000000000000000000000000008E :10324000000000000000000000000000000000007E :10325000000000000000000000000000000000006E :10326000000000000000000000000000000000005E :10327000000000000000000000000000000000004E :10328000000000000000000000000000000000003E :10329000000000000000000000000000000000002E :1032A000000000000000000000000000000000001E :1032B000000000000000000000000000000000000E :1032C00000000000000000000000000000000000FE :1032D00000000000000000000000000000000000EE :1032E00000000000000000000000000000000000DE :1032F00000000000000000000000000000000000CE :1033000000000000000000000000000000000000BD :1033100000000000000000000000000000000000AD :10332000000000000000000000000000000000009D :10333000000000000000000000000000000000008D :10334000000000000000000000000000000000007D :10335000000000000000000000000000000000006D :10336000000000000000000000000000000000005D :10337000000000000000000000000000000000004D :10338000000000000000000000000000000000003D :10339000000000000000000000000000000000002D :1033A000000000000000000000000000000000001D :1033B000000000000000000000000000000000000D :1033C00000000000000000000000000000000000FD :1033D00000000000000000000000000000000000ED :1033E00000000000000000000000000000000000DD :1033F00000000000000000000000000000000000CD :1034000000000000000000000000000000000000BC :1034100000000000000000000000000000000000AC :10342000000000000000000000000000000000009C :10343000000000000000000000000000000000008C :10344000000000000000000000000000000000007C :10345000000000000000000000000000000000006C :10346000000000000000000000000000000000005C :10347000000000000000000000000000000000004C :10348000000000000000000000000000000000003C :10349000000000000000000000000000000000002C :1034A000000000000000000000000000000000001C :1034B000000000000000000000000000000000000C :1034C00000000000000000000000000000000000FC :1034D00000000000000000000000000000000000EC :1034E00000000000000000000000000000000000DC :1034F00000000000000000000000000000000000CC :1035000000000000000000000000000000000000BB :1035100000000000000000000000000000000000AB :10352000000000000000000000000000000000009B :10353000000000000000000000000000000000008B :10354000000000000000000000000000000000007B :10355000000000000000000000000000000000006B :10356000000000000000000000000000000000005B :10357000000000000000000000000000000000004B :10358000000000000000000000000000000000003B :10359000000000000000000000000000000000002B :1035A000000000000000000000000000000000001B :1035B000000000000000000000000000000000000B :1035C00000000000000000000000000000000000FB :1035D00000000000000000000000000000000000EB :1035E00000000000000000000000000000000000DB :1035F00000000000000000000000000000000000CB :1036000000000000000000000000000000000000BA :1036100000000000000000000000000000000000AA :10362000000000000000000000000000000000009A :10363000000000000000000000000000000000008A :10364000000000000000000000000000000000007A :10365000000000000000000000000000000000006A :10366000000000000000000000000000000000005A :10367000000000000000000000000000000000004A :10368000000000000000000000000000000000003A :10369000000000000000000000000000000000002A :1036A000000000000000000000000000000000001A :1036B000000000000000000000000000000000000A :1036C00000000000000000000000000000000000FA :1036D00000000000000000000000000000000000EA :1036E00000000000000000000000000000000000DA :1036F00000000000000000000000000000000000CA :1037000000000000000000000000000000000000B9 :1037100000000000000000000000000000000000A9 :103720000000000000000000000000000000000099 :103730000000000000000000000000000000000089 :103740000000000000000000000000000000000079 :103750000000000000000000000000000000000069 :103760000000000000000000000000000000000059 :103770000000000000000000000000000000000049 :103780000000000000000000000000000000000039 :103790000000000000000000000000000000000029 :1037A0000000000000000000000000000000000019 :1037B0000000000000000000000000000000000009 :1037C00000000000000000000000000000000000F9 :1037D00000000000000000000000000000000000E9 :1037E00000000000000000000000000000000000D9 :1037F00000000000000000000000000000000000C9 :1038000000000000000000000000000000000000B8 :1038100000000000000000000000000000000000A8 :103820000000000000000000000000000000000098 :103830000000000000000000000000000000000088 :103840000000000000000000000000000000000078 :103850000000000000000000000000000000000068 :103860000000000000000000000000000000000058 :103870000000000000000000000000000000000048 :103880000000000000000000000000000000000038 :103890000000000000000000000000000000000028 :1038A0000000000000000000000000000000000018 :1038B0000000000000000000000000000000000008 :1038C00000000000000000000000000000000000F8 :1038D00000000000000000000000000000000000E8 :1038E00000000000000000000000000000000000D8 :1038F00000000000000000000000000000000000C8 :1039000000000000000000000000000000000000B7 :1039100000000000000000000000000000000000A7 :103920000000000000000000000000000000000097 :103930000000000000000000000000000000000087 :103940000000000000000000000000000000000077 :103950000000000000000000000000000000000067 :103960000000000000000000000000000000000057 :103970000000000000000000000000000000000047 :103980000000000000000000000000000000000037 :103990000000000000000000000000000000000027 :1039A0000000000000000000000000000000000017 :1039B0000000000000000000000000000000000007 :1039C00000000000000000000000000000000000F7 :1039D00000000000000000000000000000000000E7 :1039E00000000000000000000000000000000000D7 :1039F00000000000000000000000000000000000C7 :103A000000000000000000000000000000000000B6 :103A100000000000000000000000000000000000A6 :103A20000000000000000000000000000000000096 :103A30000000000000000000000000000000000086 :103A40000000000000000000000000000000000076 :103A50000000000000000000000000000000000066 :103A60000000000000000000000000000000000056 :103A70000000000000000000000000000000000046 :103A80000000000000000000000000000000000036 :103A90000000000000000000000000000000000026 :103AA0000000000000000000000000000000000016 :103AB0000000000000000000000000000000000006 :103AC00000000000000000000000000000000000F6 :103AD00000000000000000000000000000000000E6 :103AE00000000000000000000000000000000000D6 :103AF00000000000000000000000000000000000C6 :103B000000000000000000000000000000000000B5 :103B100000000000000000000000000000000000A5 :103B20000000000000000000000000000000000095 :103B30000000000000000000000000000000000085 :103B40000000000000000000000000000000000075 :103B50000000000000000000000000000000000065 :103B60000000000000000000000000000000000055 :103B70000000000000000000000000000000000045 :103B80000000000000000000000000000000000035 :103B90000000000000000000000000000000000025 :103BA0000000000000000000000000000000000015 :103BB0000000000000000000000000000000000005 :103BC00000000000000000000000000000000000F5 :103BD00000000000000000000000000000000000E5 :103BE00000000000000000000000000000000000D5 :103BF00000000000000000000000000000000000C5 :103C000000000000000000000000000000000000B4 :103C100000000000000000000000000000000000A4 :103C20000000000000000000000000000000000094 :103C30000000000000000000000000000000000084 :103C40000000000000000000000000000000000074 :103C50000000000000000000000000000000000064 :103C60000000000000000000000000000000000054 :103C70000000000000000000000000000000000044 :103C80000000000000000000000000000000000034 :103C90000000000000000000000000000000000024 :103CA0000000000000000000000000000000000014 :103CB0000000000000000000000000000000000004 :103CC00000000000000000000000000000000000F4 :103CD00000000000000000000000000000000000E4 :103CE00000000000000000000000000000000000D4 :103CF00000000000000000000000000000000000C4 :103D000000000000000000000000000000000000B3 :103D100000000000000000000000000000000000A3 :103D20000000000000000000000000000000000093 :103D30000000000000000000000000000000000083 :103D40000000000000000000000000000000000073 :103D50000000000000000000000000000000000063 :103D60000000000000000000000000000000000053 :103D70000000000000000000000000000000000043 :103D80000000000000000000000000000000000033 :103D90000000000000000000000000000000000023 :103DA0000000000000000000000000000000000013 :103DB0000000000000000000000000000000000003 :103DC00000000000000000000000000000000000F3 :103DD00000000000000000000000000000000000E3 :103DE00000000000000000000000000000000000D3 :103DF00000000000000000000000000000000000C3 :103E000000000000000000000000000000000000B2 :103E100000000000000000000000000000000000A2 :103E20000000000000000000000000000000000092 :103E30000000000000000000000000000000000082 :103E40000000000000000000000000000000000072 :103E50000000000000000000000000000000000062 :103E60000000000000000000000000000000000052 :103E70000000000000000000000000000000000042 :103E80000000000000000000000000000000000032 :103E90000000000000000000000000000000000022 :103EA0000000000000000000000000000000000012 :103EB0000000000000000000000000000000000002 :103EC00000000000000000000000000000000000F2 :103ED00000000000000000000000000000000000E2 :103EE00000000000000000000000000000000000D2 :103EF00000000000000000000000000000000000C2 :103F000000000000000000000000000000000000B1 :103F100000000000000000000000000000000000A1 :103F20000000000000000000000000000000000091 :103F30000000000000000000000000000000000081 :103F40000000000000000000000000000000000071 :103F50000000000000000000000000000000000061 :103F60000000000000000000000000000000000051 :103F70000000000000000000000000000000000041 :103F80000000000000000000000000000000000031 :103F90000000000000000000000000000000000021 :103FA0000000000000000000000000000000000011 :103FB0000000000000000000000000000000000001 :103FC00000000000000000000000000000000000F1 :103FD00000000000000000000000000000000000E1 :103FE00000000000000000000000000000000000D1 :103FF00000000000000000000000000000000000C1 :1040000000000000000000000000000000000000B0 :1040100000000000000000000000000000000000A0 :104020000000000000000000000000000000000090 :104030000000000000000000000000000000000080 :104040000000000000000000000000000000000070 :104050000000000000000000000000000000000060 :104060000000000000000000000000000000000050 :104070000000000000000000000000000000000040 :104080000000000000000000000000000000000030 :104090000000000000000000000000000000000020 :1040A0000000000000000000000000000000000010 :1040B0000000000000000000000000000000000000 :1040C00000000000000000000000000000000000F0 :1040D00000000000000000000000000000000000E0 :1040E00000000000000000000000000000000000D0 :1040F00000000000000000000000000000000000C0 :1041000000000000000000000000000000000000AF :10411000000000000000000000000000000000009F :10412000000000000000000000000000000000008F :10413000000000000000000000000000000000007F :10414000000000000000000000000000000000006F :10415000000000000000000000000000000000005F :10416000000000000000000000000000000000004F :10417000000000000000000000000000000000003F :10418000000000000000000000000000000000002F :10419000000000000000000000000000000000001F :1041A000000000000000000000000000000000000F :1041B00000000000000000000000000000000000FF :1041C00000000000000000000000000000000000EF :1041D00000000000000000000000000000000000DF :1041E00000000000000000000000000000000000CF :1041F00000000000000000000000000000000000BF :1042000000000000000000000000000000000000AE :10421000000000000000000000000000000000009E :10422000000000000000000000000000000000008E :10423000000000000000000000000000000000007E :10424000000000000000000000000000000000006E :10425000000000000000000000000000000000005E :10426000000000000000000000000000000000004E :10427000000000000000000000000000000000003E :10428000000000000000000000000000000000002E :10429000000000000000000000000000000000001E :1042A000000000000000000000000000000000000E :1042B00000000000000000000000000000000000FE :1042C00000000000000000000000000000000000EE :1042D00000000000000000000000000000000000DE :1042E00000000000000000000000000000000000CE :1042F00000000000000000000000000000000000BE :1043000000000000000000000000000000000000AD :10431000000000000000000000000000000000009D :10432000000000000000000000000000000000008D :10433000000000000000000000000000000000007D :10434000000000000000000000000000000000006D :10435000000000000000000000000000000000005D :10436000000000000000000000000000000000004D :10437000000000000000000000000000000000003D :10438000000000000000000000000000000000002D :10439000000000000000000000000000000000001D :1043A000000000000000000000000000000000000D :1043B00000000000000000000000000000000000FD :1043C00000000000000000000000000000000000ED :1043D00000000000000000000000000000000000DD :1043E00000000000000000000000000000000000CD :1043F00000000000000000000000000000000000BD :1044000000000000000000000000000000000000AC :10441000000000000000000000000000000000009C :10442000000000000000000000000000000000008C :10443000000000000000000000000000000000007C :10444000000000000000000000000000000000006C :10445000000000000000000000000000000000005C :10446000000000000000000000000000000000004C :10447000000000000000000000000000000000003C :10448000000000000000000000000000000000002C :10449000000000000000000000000000000000001C :1044A000000000000000000000000000000000000C :1044B00000000000000000000000000000000000FC :1044C00000000000000000000000000000000000EC :1044D00000000000000000000000000000000000DC :1044E00000000000000000000000000000000000CC :1044F00000000000000000000000000000000000BC :1045000000000000000000000000000000000000AB :10451000000000000000000000000000000000009B :10452000000000000000000000000000000000008B :10453000000000000000000000000000000000007B :10454000000000000000000000000000000000006B :10455000000000000000000000000000000000005B :10456000000000000000000000000000000000004B :10457000000000000000000000000000000000003B :10458000000000000000000000000000000000002B :10459000000000000000000000000000000000001B :1045A000000000000000000000000000000000000B :1045B00000000000000000000000000000000000FB :1045C00000000000000000000000000000000000EB :1045D00000000000000000000000000000000000DB :1045E00000000000000000000000000000000000CB :1045F00000000000000000000000000000000000BB :1046000000000000000000000000000000000000AA :10461000000000000000000000000000000000009A :10462000000000000000000000000000000000008A :10463000000000000000000000000000000000007A :10464000000000000000000000000000000000006A :10465000000000000000000000000000000000005A :10466000000000000000000000000000000000004A :10467000000000000000000000000000000000003A :10468000000000000000000000000000000000002A :10469000000000000000000000000000000000001A :1046A000000000000000000000000000000000000A :1046B00000000000000000000000000000000000FA :1046C00000000000000000000000000000000000EA :1046D00000000000000000000000000000000000DA :1046E00000000000000000000000000000000000CA :1046F00000000000000000000000000000000000BA :1047000000000000000000000000000000000000A9 :104710000000000000000000000000000000000099 :104720000000000000000000000000000000000089 :104730000000000000000000000000000000000079 :104740000000000000000000000000000000000069 :104750000000000000000000000000000000000059 :104760000000000000000000000000000000000049 :104770000000000000000000000000000000000039 :104780000000000000000000000000000000000029 :104790000000000000000000000000000000000019 :1047A0000000000000000000000000000000000009 :1047B00000000000000000000000000000000000F9 :1047C00000000000000000000000000000000000E9 :1047D00000000000000000000000000000000000D9 :1047E00000000000000000000000000000000000C9 :1047F00000000000000000000000000000000000B9 :1048000000000000000000000000000000000000A8 :104810000000000000000000000000000000000098 :104820000000000000000000000000000000000088 :104830000000000000000000000000000000000078 :104840000000000000000000000000000000000068 :104850000000000000000000000000000000000058 :104860000000000000000000000000000000000048 :104870000000000000000000000000000000000038 :104880000000000000000000000000000000000028 :104890000000000000000000000000000000000018 :1048A0000000000000000000000000000000000008 :1048B00000000000000000000000000000000000F8 :1048C00000000000000000000000000000000000E8 :1048D00000000000000000000000000000000000D8 :1048E00000000000000000000000000000000000C8 :1048F00000000000000000000000000000000000B8 :1049000000000000000000000000000000000000A7 :104910000000000000000000000000000000000097 :104920000000000000000000000000000000000087 :104930000000000000000000000000000000000077 :104940000000000000000000000000000000000067 :104950000000000000000000000000000000000057 :104960000000000000000000000000000000000047 :104970000000000000000000000000000000000037 :104980000000000000000000000000000000000027 :104990000000000000000000000000000000000017 :1049A0000000000000000000000000000000000007 :1049B00000000000000000000000000000000000F7 :1049C00000000000000000000000000000000000E7 :1049D00000000000000000000000000000000000D7 :1049E00000000000000000000000000000000000C7 :1049F00000000000000000000000000000000000B7 :104A000000000000000000000000000000000000A6 :104A10000000000000000000000000000000000096 :104A20000000000000000000000000000000000086 :104A30000000000000000000000000000000000076 :104A40000000000000000000000000000000000066 :104A50000000000000000000000000000000000056 :104A60000000000000000000000000000000000046 :104A70000000000000000000000000000000000036 :104A80000000000000000000000000000000000026 :104A90000000000000000000000000000000000016 :104AA0000000000000000000000000000000000006 :104AB00000000000000000000000000000000000F6 :104AC00000000000000000000000000000000000E6 :104AD00000000000000000000000000000000000D6 :104AE00000000000000000000000000000000000C6 :104AF00000000000000000000000000000000000B6 :104B000000000000000000000000000000000000A5 :104B10000000000000000000000000000000000095 :104B20000000000000000000000000000000000085 :104B30000000000000000000000000000000000075 :104B40000000000000000000000000000000000065 :104B50000000000000000000000000000000000055 :104B60000000000000000000000000000000000045 :104B70000000000000000000000000000000000035 :104B80000000000000000000000000000000000025 :104B90000000000000000000000000000000000015 :104BA0000000000000000000000000000000000005 :104BB00000000000000000000000000000000000F5 :104BC00000000000000000000000000000000000E5 :104BD00000000000000000000000000000000000D5 :104BE00000000000000000000000000000000000C5 :104BF00000000000000000000000000000000000B5 :104C000000000000000000000000000000000000A4 :104C10000000000000000000000000000000000094 :104C20000000000000000000000000000000000084 :104C30000000000000000000000000000000000074 :104C40000000000000000000000000000000000064 :104C50000000000000000000000000000000000054 :104C60000000000000000000000000000000000044 :104C70000000000000000000000000000000000034 :104C80000000000000000000000000000000000024 :104C90000000000000000000000000000000000014 :104CA0000000000000000000000000000000000004 :104CB00000000000000000000000000000000000F4 :104CC00000000000000000000000000000000000E4 :104CD00000000000000000000000000000000000D4 :104CE00000000000000000000000000000000000C4 :104CF00000000000000000000000000000000000B4 :104D000000000000000000000000000000000000A3 :104D10000000000000000000000000000000000093 :104D20000000000000000000000000000000000083 :104D30000000000000000000000000000000000073 :104D40000000000000000000000000000000000063 :104D50000000000000000000000000000000000053 :104D60000000000000000000000000000000000043 :104D70000000000000000000000000000000000033 :104D80000000000000000000000000000000000023 :104D90000000000000000000000000000000000013 :104DA0000000000000000000000000000000000003 :104DB00000000000000000000000000000000000F3 :104DC00000000000000000000000000000000000E3 :104DD00000000000000000000000000000000000D3 :104DE00000000000000000000000000000000000C3 :104DF00000000000000000000000000000000000B3 :104E000000000000000000000000000000000000A2 :104E10000000000000000000000000000000000092 :104E20000000000000000000000000000000000082 :104E30000000000000000000000000000000000072 :104E40000000000000000000000000000000000062 :104E50000000000000000000000000000000000052 :104E60000000000000000000000000000000000042 :104E70000000000000000000000000000000000032 :104E80000000000000000000000000000000000022 :104E90000000000000000000000000000000000012 :104EA0000000000000000000000000000000000002 :104EB00000000000000000000000000000000000F2 :104EC00000000000000000000000000000000000E2 :104ED00000000000000000000000000000000000D2 :104EE00000000000000000000000000000000000C2 :104EF00000000000000000000000000000000000B2 :104F000000000000000000000000000000000000A1 :104F10000000000000000000000000000000000091 :104F20000000000000000000000000000000000081 :104F30000000000000000000000000000000000071 :104F40000000000000000000000000000000000061 :104F50000000000000000000000000000000000051 :104F60000000000000000000000000000000000041 :104F70000000000000000000000000000000000031 :104F80000000000000000000000000000000000021 :104F90000000000000000000000000000000000011 :104FA0000000000000000000000000000000000001 :104FB00000000000000000000000000000000000F1 :104FC00000000000000000000000000000000000E1 :104FD00000000000000000000000000000000000D1 :104FE00000000000000000000000000000000000C1 :104FF00000000000000000000000000000000000B1 :1050000000000000000000000000000000000000A0 :105010000000000000000000000000000000000090 :105020000000000000000000000000000000000080 :105030000000000000000000000000000000000070 :105040000000000000000000000000000000000060 :105050000000000000000000000000000000000050 :105060000000000000000000000000000000000040 :105070000000000000000000000000000000000030 :105080000000000000000000000000000000000020 :105090000000000000000000000000000000000010 :1050A0000000000000000000000000000000000000 :1050B00000000000000000000000000000000000F0 :1050C00000000000000000000000000000000000E0 :1050D00000000000000000000000000000000000D0 :1050E00000000000000000000000000000000000C0 :1050F00000000000000000000000000000000000B0 :10510000000000000000000000000000000000009F :10511000000000000000000000000000000000008F :10512000000000000000000000000000000000007F :10513000000000000000000000000000000000006F :10514000000000000000000000000000000000005F :10515000000000000000000000000000000000004F :10516000000000000000000000000000000000003F :10517000000000000000000000000000000000002F :10518000000000000000000000000000000000001F :10519000000000000000000000000000000000000F :1051A00000000000000000000000000000000000FF :1051B00000000000000000000000000000000000EF :1051C00000000000000000000000000000000000DF :1051D00000000000000000000000000000000000CF :1051E00000000000000000000000000000000000BF :1051F00000000000000000000000000000000000AF :10520000000000000000000000000000000000009E :10521000000000000000000000000000000000008E :10522000000000000000000000000000000000007E :10523000000000000000000000000000000000006E :10524000000000000000000000000000000000005E :10525000000000000000000000000000000000004E :10526000000000000000000000000000000000003E :10527000000000000000000000000000000000002E :10528000000000000000000000000000000000001E :10529000000000000000000000000000000000000E :1052A00000000000000000000000000000000000FE :1052B00000000000000000000000000000000000EE :1052C00000000000000000000000000000000000DE :1052D00000000000000000000000000000000000CE :1052E00000000000000000000000000000000000BE :1052F00000000000000000000000000000000000AE :10530000000000000000000000000000000000009D :10531000000000000000000000000000000000008D :10532000000000000000000000000000000000007D :10533000000000000000000000000000000000006D :10534000000000000000000000000000000000005D :10535000000000000000000000000000000000004D :10536000000000000000000000000000000000003D :10537000000000000000000000000000000000002D :10538000000000000000000000000000000000001D :10539000000000000000000000000000000000000D :1053A00000000000000000000000000000000000FD :1053B00000000000000000000000000000000000ED :1053C00000000000000000000000000000000000DD :1053D00000000000000000000000000000000000CD :1053E00000000000000000000000000000000000BD :1053F00000000000000000000000000000000000AD :10540000000000000000000000000000000000009C :10541000000000000000000000000000000000008C :10542000000000000000000000000000000000007C :10543000000000000000000000000000000000006C :10544000000000000000000000000000000000005C :10545000000000000000000000000000000000004C :10546000000000000000000000000000000000003C :10547000000000000000000000000000000000002C :10548000000000000000000000000000000000001C :10549000000000000000000000000000000000000C :1054A00000000000000000000000000000000000FC :1054B00000000000000000000000000000000000EC :1054C00000000000000000000000000000000000DC :1054D00000000000000000000000000000000000CC :1054E00000000000000000000000000000000000BC :1054F00000000000000000000000000000000000AC :10550000000000000000000000000000000000009B :10551000000000000000000000000000000000008B :10552000000000000000000000000000000000007B :10553000000000000000000000000000000000006B :10554000000000000000000000000000000000005B :10555000000000000000000000000000000000004B :10556000000000000000000000000000000000003B :10557000000000000000000000000000000000002B :10558000000000000000000000000000000000001B :10559000000000000000000000000000000000000B :1055A00000000000000000000000000000000000FB :1055B00000000000000000000000000000000000EB :1055C00000000000000000000000000000000000DB :1055D00000000000000000000000000000000000CB :1055E00000000000000000000000000000000000BB :1055F00000000000000000000000000000000000AB :10560000000000000000000000000000000000009A :10561000000000000000000000000000000000008A :10562000000000000000000000000000000000007A :10563000000000000000000000000000000000006A :10564000000000000000000000000000000000005A :10565000000000000000000000000000000000004A :10566000000000000000000000000000000000003A :10567000000000000000000000000000000000002A :10568000000000000000000000000000000000001A :10569000000000000000000000000000000000000A :1056A00000000000000000000000000000000000FA :1056B00000000000000000000000000000000000EA :1056C00000000000000000000000000000000000DA :1056D00000000000000000000000000000000000CA :1056E00000000000000000000000000000000000BA :1056F00000000000000000000000000000000000AA :105700000000000000000000000000000000000099 :105710000000000000000000000000000000000089 :105720000000000000000000000000000000000079 :105730000000000000000000000000000000000069 :105740000000000000000000000000000000000059 :105750000000000000000000000000000000000049 :105760000000000000000000000000000000000039 :105770000000000000000000000000000000000029 :105780000000000000000000000000000000000019 :105790000000000000000000000000000000000009 :1057A00000000000000000000000000000000000F9 :1057B00000000000000000000000000000000000E9 :1057C00000000000000000000000000000000000D9 :1057D00000000000000000000000000000000000C9 :1057E00000000000000000000000000000000000B9 :1057F00000000000000000000000000000000000A9 :105800000000000000000000000000000000000098 :105810000000000000000000000000000000000088 :105820000000000000000000000000000000000078 :105830000000000000000000000000000000000068 :105840000000000000000000000000000000000058 :105850000000000000000000000000000000000048 :105860000000000000000000000000000000000038 :105870000000000000000000000000000000000028 :105880000000000000000000000000000000000018 :105890000000000000000000000000000000000008 :1058A00000000000000000000000000000000000F8 :1058B00000000000000000000000000000000000E8 :1058C00000000000000000000000000000000000D8 :1058D00000000000000000000000000000000000C8 :1058E00000000000000000000000000000000000B8 :1058F00000000000000000000000000000000000A8 :105900000000000000000000000000000000000097 :105910000000000000000000000000000000000087 :105920000000000000000000000000000000000077 :105930000000000000000000000000000000000067 :105940000000000000000000000000000000000057 :105950000000000000000000000000000000000047 :105960000000000000000000000000000000000037 :105970000000000000000000000000000000000027 :105980000000000000000000000000000000000017 :105990000000000000000000000000000000000007 :1059A00000000000000000000000000000000000F7 :1059B00000000000000000000000000000000000E7 :1059C00000000000000000000000000000000000D7 :1059D00000000000000000000000000000000000C7 :1059E00000000000000000000000000000000000B7 :1059F00000000000000000000000000000000000A7 :105A00000000000000000000000000000000000096 :105A10000000000000000000000000000000000086 :105A20000000000000000000000000000000000076 :105A30000000000000000000000000000000000066 :105A40000000000000000000000000000000000056 :105A50000000000000000000000000000000000046 :105A60000000000000000000000000000000000036 :105A70000000000000000000000000000000000026 :105A80000000000000000000000000000000000016 :105A90000000000000000000000000000000000006 :105AA00000000000000000000000000000000000F6 :105AB00000000000000000000000000000000000E6 :105AC00000000000000000000000000000000000D6 :105AD00000000000000000000000000000000000C6 :105AE00000000000000000000000000000000000B6 :105AF00000000000000000000000000000000000A6 :105B00000000000000000000000000000000000095 :105B10000000000000000000000000000000000085 :105B20000000000000000000000000000000000075 :105B30000000000000000000000000000000000065 :105B40000000000000000000000000000000000055 :105B50000000000000000000000000000000000045 :105B60000000000000000000000000000000000035 :105B70000000000000000000000000000000000025 :105B80000000000000000000000000000000000015 :105B90000000000000000000000000000000000005 :105BA00000000000000000000000000000000000F5 :105BB00000000000000000000000000000000000E5 :105BC00000000000000000000000000000000000D5 :105BD00000000000000000000000000000000000C5 :105BE00000000000000000000000000000000000B5 :105BF00000000000000000000000000000000000A5 :105C00000000000000000000000000000000000094 :105C10000000000000000000000000000000000084 :105C20000000000000000000000000000000000074 :105C30000000000000000000000000000000000064 :105C40000000000000000000000000000000000054 :105C50000000000000000000000000000000000044 :105C60000000000000000000000000000000000034 :105C70000000000000000000000000000000000024 :105C80000000000000000000000000000000000014 :105C90000000000000000000000000000000000004 :105CA00000000000000000000000000000000000F4 :105CB00000000000000000000000000000000000E4 :105CC00000000000000000000000000000000000D4 :105CD00000000000000000000000000000000000C4 :105CE00000000000000000000000000000000000B4 :105CF00000000000000000000000000000000000A4 :105D00000000000000000000000000000000000093 :105D10000000000000000000000000000000000083 :105D20000000000000000000000000000000000073 :105D30000000000000000000000000000000000063 :105D40000000000000000000000000000000000053 :105D50000000000000000000000000000000000043 :105D60000000000000000000000000000000000033 :105D70000000000000000000000000000000000023 :105D80000000000000000000000000000000000013 :105D90000000000000000000000000000000000003 :105DA00000000000000000000000000000000000F3 :105DB00000000000000000000000000000000000E3 :105DC00000000000000000000000000000000000D3 :105DD00000000000000000000000000000000000C3 :105DE00000000000000000000000000000000000B3 :105DF00000000000000000000000000000000000A3 :105E00000000000000000000000000000000000092 :105E10000000000000000000000000000000000082 :105E20000000000000000000000000000000000072 :105E30000000000000000000000000000000000062 :105E40000000000000000000000000000000000052 :105E50000000000000000000000000000000000042 :105E60000000000000000000000000000000000032 :105E70000000000000000000000000000000000022 :105E80000000000000000000000000000000000012 :105E90000000000000000000000000000000000002 :105EA00000000000000000000000000000000000F2 :105EB00000000000000000000000000000000000E2 :105EC00000000000000000000000000000000000D2 :105ED00000000000000000000000000000000000C2 :105EE00000000000000000000000000000000000B2 :105EF00000000000000000000000000000000000A2 :105F00000000000000000000000000000000000091 :105F10000000000000000000000000000000000081 :105F20000000000000000000000000000000000071 :105F30000000000000000000000000000000000061 :105F40000000000000000000000000000000000051 :105F50000000000000000000000000000000000041 :105F60000000000000000000000000000000000031 :105F70000000000000000000000000000000000021 :105F80000000000000000000000000000000000011 :105F90000000000000000000000000000000000001 :105FA00000000000000000000000000000000000F1 :105FB00000000000000000000000000000000000E1 :105FC00000000000000000000000000000000000D1 :105FD00000000000000000000000000000000000C1 :105FE00000000000000000000000000000000000B1 :105FF00000000000000000000000000000000000A1 :106000000000000000000000000000000000000090 :106010000000000000000000000000000000000080 :106020000000000000000000000000000000000070 :106030000000000000000000000000000000000060 :106040000000000000000000000000000000000050 :106050000000000000000000000000000000000040 :106060000000000000000000000000000000000030 :106070000000000000000000000000000000000020 :106080000000000000000000000000000000000010 :106090000000000000000000000000000000000000 :1060A00000000000000000000000000000000000F0 :1060B00000000000000000000000000000000000E0 :1060C00000000000000000000000000000000000D0 :1060D00000000000000000000000000000000000C0 :1060E00000000000000000000000000000000000B0 :1060F00000000000000000000000000000000000A0 :10610000000000000000000000000000000000008F :10611000000000000000000000000000000000007F :10612000000000000000000000000000000000006F :10613000000000000000000000000000000000005F :10614000000000000000000000000000000000004F :10615000000000000000000000000000000000003F :10616000000000000000000000000000000000002F :10617000000000000000000000000000000000001F :10618000000000000000000000000000000000000F :1061900000000000000000000000000000000000FF :1061A00000000000000000000000000000000000EF :1061B00000000000000000000000000000000000DF :1061C00000000000000000000000000000000000CF :1061D00000000000000000000000000000000000BF :1061E00000000000000000000000000000000000AF :1061F000000000000000000000000000000000009F :10620000000000000000000000000000000000008E :10621000000000000000000000000000000000007E :10622000000000000000000000000000000000006E :10623000000000000000000000000000000000005E :10624000000000000000000000000000000000004E :10625000000000000000000000000000000000003E :10626000000000000000000000000000000000002E :10627000000000000000000000000000000000001E :10628000000000000000000000000000000000000E :1062900000000000000000000000000000000000FE :1062A00000000000000000000000000000000000EE :1062B00000000000000000000000000000000000DE :1062C00000000000000000000000000000000000CE :1062D00000000000000000000000000000000000BE :1062E00000000000000000000000000000000000AE :1062F000000000000000000000000000000000009E :10630000000000000000000000000000000000008D :10631000000000000000000000000000000000007D :10632000000000000000000000000000000000006D :10633000000000000000000000000000000000005D :10634000000000000000000000000000000000004D :10635000000000000000000000000000000000003D :10636000000000000000000000000000000000002D :10637000000000000000000000000000000000001D :10638000000000000000000000000000000000000D :1063900000000000000000000000000000000000FD :1063A00000000000000000000000000000000000ED :1063B00000000000000000000000000000000000DD :1063C00000000000000000000000000000000000CD :1063D00000000000000000000000000000000000BD :1063E00000000000000000000000000000000000AD :1063F000000000000000000000000000000000009D :10640000000000000000000000000000000000008C :10641000000000000000000000000000000000007C :10642000000000000000000000000000000000006C :10643000000000000000000000000000000000005C :10644000000000000000000000000000000000004C :10645000000000000000000000000000000000003C :10646000000000000000000000000000000000002C :10647000000000000000000000000000000000001C :10648000000000000000000000000000000000000C :1064900000000000000000000000000000000000FC :1064A00000000000000000000000000000000000EC :1064B00000000000000000000000000000000000DC :1064C00000000000000000000000000000000000CC :1064D00000000000000000000000000000000000BC :1064E00000000000000000000000000000000000AC :1064F000000000000000000000000000000000009C :10650000000000000000000000000000000000008B :10651000000000000000000000000000000000007B :10652000000000000000000000000000000000006B :10653000000000000000000000000000000000005B :10654000000000000000000000000000000000004B :10655000000000000000000000000000000000003B :10656000000000000000000000000000000000002B :10657000000000000000000000000000000000001B :10658000000000000000000000000000000000000B :1065900000000000000000000000000000000000FB :1065A00000000000000000000000000000000000EB :1065B00000000000000000000000000000000000DB :1065C00000000000000000000000000000000000CB :1065D00000000000000000000000000000000000BB :1065E00000000000000000000000000000000000AB :1065F000000000000000000000000000000000009B :10660000000000000000000000000000000000008A :10661000000000000000000000000000000000007A :10662000000000000000000000000000000000006A :10663000000000000000000000000000000000005A :10664000000000000000000000000000000000004A :10665000000000000000000000000000000000003A :10666000000000000000000000000000000000002A :10667000000000000000000000000000000000001A :10668000000000000000000000000000000000000A :1066900000000000000000000000000000000000FA :1066A00000000000000000000000000000000000EA :1066B00000000000000000000000000000000000DA :1066C00000000000000000000000000000000000CA :1066D00000000000000000000000000000000000BA :1066E00000000000000000000000000000000000AA :1066F000000000000000000000000000000000009A :106700000000000000000000000000000000000089 :106710000000000000000000000000000000000079 :106720000000000000000000000000000000000069 :106730000000000000000000000000000000000059 :106740000000000000000000000000000000000049 :106750000000000000000000000000000000000039 :106760000000000000000000000000000000000029 :106770000000000000000000000000000000000019 :106780000000000000000000000000000000000009 :1067900000000000000000000000000000000000F9 :1067A00000000000000000000000000000000000E9 :1067B00000000000000000000000000000000000D9 :1067C00000000000000000000000000000000000C9 :1067D00000000000000000000000000000000000B9 :1067E00000000000000000000000000000000000A9 :1067F0000000000000000000000000000000000099 :106800000000000000000000000000000000000088 :106810000000000000000000000000000000000078 :106820000000000000000000000000000000000068 :106830000000000000000000000000000000000058 :106840000000000000000000000000000000000048 :106850000000000000000000000000000000000038 :106860000000000000000000000000000000000028 :106870000000000000000000000000000000000018 :106880000000000000000000000000000000000008 :1068900000000000000000000000000000000000F8 :1068A00000000000000000000000000000000000E8 :1068B00000000000000000000000000000000000D8 :1068C00000000000000000000000000000000000C8 :1068D00000000000000000000000000000000000B8 :1068E00000000000000000000000000000000000A8 :1068F0000000000000000000000000000000000098 :106900000000000000000000000000000000000087 :106910000000000000000000000000000000000077 :106920000000000000000000000000000000000067 :106930000000000000000000000000000000000057 :106940000000000000000000000000000000000047 :106950000000000000000000000000000000000037 :106960000000000000000000000000000000000027 :106970000000000000000000000000000000000017 :106980000000000000000000000000000000000007 :1069900000000000000000000000000000000000F7 :1069A00000000000000000000000000000000000E7 :1069B00000000000000000000000000000000000D7 :1069C00000000000000000000000000000000000C7 :1069D00000000000000000000000000000000000B7 :1069E00000000000000000000000000000000000A7 :1069F0000000000000000000000000000000000097 :106A00000000000000000000000000000000000086 :106A10000000000000000000000000000000000076 :106A20000000000000000000000000000000000066 :106A30000000000000000000000000000000000056 :106A40000000000000000000000000000000000046 :106A50000000000000000000000000000000000036 :106A60000000000000000000000000000000000026 :106A70000000000000000000000000000000000016 :106A80000000000000000000000000000000000006 :106A900000000000000000000000000000000000F6 :106AA00000000000000000000000000000000000E6 :106AB00000000000000000000000000000000000D6 :106AC00000000000000000000000000000000000C6 :106AD00000000000000000000000000000000000B6 :106AE00000000000000000000000000000000000A6 :106AF0000000000000000000000000000000000096 :106B00000000000000000000000000000000000085 :106B10000000000000000000000000000000000075 :106B20000000000000000000000000000000000065 :106B30000000000000000000000000000000000055 :106B40000000000000000000000000000000000045 :106B50000000000000000000000000000000000035 :106B60000000000000000000000000000000000025 :106B70000000000000000000000000000000000015 :106B80000000000000000000000000000000000005 :106B900000000000000000000000000000000000F5 :106BA00000000000000000000000000000000000E5 :106BB00000000000000000000000000000000000D5 :106BC00000000000000000000000000000000000C5 :106BD00000000000000000000000000000000000B5 :106BE00000000000000000000000000000000000A5 :106BF0000000000000000000000000000000000095 :106C00000000000000000000000000000000000084 :106C10000000000000000000000000000000000074 :106C20000000000000000000000000000000000064 :106C30000000000000000000000000000000000054 :106C40000000000000000000000000000000000044 :106C50000000000000000000000000000000000034 :106C60000000000000000000000000000000000024 :106C70000000000000000000000000000000000014 :106C80000000000000000000000000000000000004 :106C900000000000000000000000000000000000F4 :106CA00000000000000000000000000000000000E4 :106CB00000000000000000000000000000000000D4 :106CC00000000000000000000000000000000000C4 :106CD00000000000000000000000000000000000B4 :106CE00000000000000000000000000000000000A4 :106CF0000000000000000000000000000000000094 :106D00000000000000000000000000000000000083 :106D10000000000000000000000000000000000073 :106D20000000000000000000000000000000000063 :106D30000000000000000000000000000000000053 :106D40000000000000000000000000000000000043 :106D50000000000000000000000000000000000033 :106D60000000000000000000000000000000000023 :106D70000000000000000000000000000000000013 :106D80000000000000000000000000000000000003 :106D900000000000000000000000000000000000F3 :106DA00000000000000000000000000000000000E3 :106DB00000000000000000000000000000000000D3 :106DC00000000000000000000000000000000000C3 :106DD00000000000000000000000000000000000B3 :106DE00000000000000000000000000000000000A3 :106DF0000000000000000000000000000000000093 :106E00000000000000000000000000000000000082 :106E10000000000000000000000000000000000072 :106E20000000000000000000000000000000000062 :106E30000000000000000000000000000000000052 :106E40000000000000000000000000000000000042 :106E50000000000000000000000000000000000032 :106E60000000000000000000000000000000000022 :106E70000000000000000000000000000000000012 :106E80000000000000000000000000000000000002 :106E900000000000000000000000000000000000F2 :106EA00000000000000000000000000000000000E2 :106EB00000000000000000000000000000000000D2 :106EC00000000000000000000000000000000000C2 :106ED00000000000000000000000000000000000B2 :106EE00000000000000000000000000000000000A2 :106EF0000000000000000000000000000000000092 :106F00000000000000000000000000000000000081 :106F10000000000000000000000000000000000071 :106F20000000000000000000000000000000000061 :106F30000000000000000000000000000000000051 :106F40000000000000000000000000000000000041 :106F50000000000000000000000000000000000031 :106F60000000000000000000000000000000000021 :106F70000000000000000000000000000000000011 :106F80000000000000000000000000000000000001 :106F900000000000000000000000000000000000F1 :106FA00000000000000000000000000000000000E1 :106FB00000000000000000000000000000000000D1 :106FC00000000000000000000000000000000000C1 :106FD00000000000000000000000000000000000B1 :106FE00000000000000000000000000000000000A1 :106FF0000000000000000000000000000000000091 :107000000000000000000000000000000000000080 :107010000000000000000000000000000000000070 :107020000000000000000000000000000000000060 :107030000000000000000000000000000000000050 :107040000000000000000000000000000000000040 :107050000000000000000000000000000000000030 :107060000000000000000000000000000000000020 :107070000000000000000000000000000000000010 :107080000000000000000000000000000000000000 :1070900000000000000000000000000000000000F0 :1070A00000000000000000000000000000000000E0 :1070B00000000000000000000000000000000000D0 :1070C00000000000000000000000000000000000C0 :1070D00000000000000000000000000000000000B0 :1070E00000000000000000000000000000000000A0 :1070F0000000000000000000000000000000000090 :10710000000000000000000000000000000000007F :10711000000000000000000000000000000000006F :10712000000000000000000000000000000000005F :10713000000000000000000000000000000000004F :10714000000000000000000000000000000000003F :10715000000000000000000000000000000000002F :10716000000000000000000000000000000000001F :10717000000000000000000000000000000000000F :1071800000000000000000000000000000000000FF :1071900000000000000000000000000000000000EF :1071A00000000000000000000000000000000000DF :1071B00000000000000000000000000000000000CF :1071C00000000000000000000000000000000000BF :1071D00000000000000000000000000000000000AF :1071E000000000000000000000000000000000009F :1071F000000000000000000000000000000000008F :10720000000000000000000000000000000000007E :10721000000000000000000000000000000000006E :10722000000000000000000000000000000000005E :10723000000000000000000000000000000000004E :10724000000000000000000000000000000000003E :10725000000000000000000000000000000000002E :10726000000000000000000000000000000000001E :10727000000000000000000000000000000000000E :1072800000000000000000000000000000000000FE :1072900000000000000000000000000000000000EE :1072A00000000000000000000000000000000000DE :1072B00000000000000000000000000000000000CE :1072C00000000000000000000000000000000000BE :1072D00000000000000000000000000000000000AE :1072E000000000000000000000000000000000009E :1072F000000000000000000000000000000000008E :10730000000000000000000000000000000000007D :10731000000000000000000000000000000000006D :10732000000000000000000000000000000000005D :10733000000000000000000000000000000000004D :10734000000000000000000000000000000000003D :10735000000000000000000000000000000000002D :10736000000000000000000000000000000000001D :10737000000000000000000000000000000000000D :1073800000000000000000000000000000000000FD :1073900000000000000000000000000000000000ED :1073A00000000000000000000000000000000000DD :1073B00000000000000000000000000000000000CD :1073C00000000000000000000000000000000000BD :1073D00000000000000000000000000000000000AD :1073E000000000000000000000000000000000009D :1073F000000000000000000000000000000000008D :10740000000000000000000000000000000000007C :10741000000000000000000000000000000000006C :10742000000000000000000000000000000000005C :10743000000000000000000000000000000000004C :10744000000000000000000000000000000000003C :10745000000000000000000000000000000000002C :10746000000000000000000000000000000000001C :10747000000000000000000000000000000000000C :1074800000000000000000000000000000000000FC :1074900000000000000000000000000000000000EC :1074A00000000000000000000000000000000000DC :1074B00000000000000000000000000000000000CC :1074C00000000000000000000000000000000000BC :1074D00000000000000000000000000000000000AC :1074E000000000000000000000000000000000009C :1074F000000000000000000000000000000000008C :10750000000000000000000000000000000000007B :10751000000000000000000000000000000000006B :10752000000000000000000000000000000000005B :10753000000000000000000000000000000000004B :10754000000000000000000000000000000000003B :10755000000000000000000000000000000000002B :10756000000000000000000000000000000000001B :10757000000000000000000000000000000000000B :1075800000000000000000000000000000000000FB :1075900000000000000000000000000000000000EB :1075A00000000000000000000000000000000000DB :1075B00000000000000000000000000000000000CB :1075C00000000000000000000000000000000000BB :1075D00000000000000000000000000000000000AB :1075E000000000000000000000000000000000009B :1075F000000000000000000000000000000000008B :10760000000000000000000000000000000000007A :10761000000000000000000000000000000000006A :10762000000000000000000000000000000000005A :10763000000000000000000000000000000000004A :10764000000000000000000000000000000000003A :10765000000000000000000000000000000000002A :10766000000000000000000000000000000000001A :10767000000000000000000000000000000000000A :1076800000000000000000000000000000000000FA :1076900000000000000000000000000000000000EA :1076A00000000000000000000000000000000000DA :1076B00000000000000000000000000000000000CA :1076C00000000000000000000000000000000000BA :1076D00000000000000000000000000000000000AA :1076E000000000000000000000000000000000009A :1076F000000000000000000000000000000000008A :107700000000000000000000000000000000000079 :107710000000000000000000000000000000000069 :107720000000000000000000000000000000000059 :107730000000000000000000000000000000000049 :107740000000000000000000000000000000000039 :107750000000000000000000000000000000000029 :107760000000000000000000000000000000000019 :107770000000000000000000000000000000000009 :1077800000000000000000000000000000000000F9 :1077900000000000000000000000000000000000E9 :1077A00000000000000000000000000000000000D9 :1077B00000000000000000000000000000000000C9 :1077C00000000000000000000000000000000000B9 :1077D00000000000000000000000000000000000A9 :1077E0000000000000000000000000000000000099 :1077F0000000000000000000000000000000000089 :107800000000000000000000000000000000000078 :107810000000000000000000000000000000000068 :107820000000000000000000000000000000000058 :107830000000000000000000000000000000000048 :107840000000000000000000000000000000000038 :107850000000000000000000000000000000000028 :107860000000000000000000000000000000000018 :107870000000000000000000000000000000000008 :1078800000000000000000000000000000000000F8 :1078900000000000000000000000000000000000E8 :1078A00000000000000000000000000000000000D8 :1078B00000000000000000000000000000000000C8 :1078C00000000000000000000000000000000000B8 :1078D00000000000000000000000000000000000A8 :1078E0000000000000000000000000000000000098 :1078F0000000000000000000000000000000000088 :107900000000000000000000000000000000000077 :107910000000000000000000000000000000000067 :107920000000000000000000000000000000000057 :107930000000000000000000000000000000000047 :107940000000000000000000000000000000000037 :107950000000000000000000000000000000000027 :107960000000000000000000000000000000000017 :107970000000000000000000000000000000000007 :1079800000000000000000000000000000000000F7 :1079900000000000000000000000000000000000E7 :1079A00000000000000000000000000000000000D7 :1079B00000000000000000000000000000000000C7 :1079C00000000000000000000000000000000000B7 :1079D00000000000000000000000000000000000A7 :1079E0000000000000000000000000000000000097 :1079F0000000000000000000000000000000000087 :107A00000000000000000000000000000000000076 :107A10000000000000000000000000000000000066 :107A20000000000000000000000000000000000056 :107A30000000000000000000000000000000000046 :107A40000000000000000000000000000000000036 :107A50000000000000000000000000000000000026 :107A60000000000000000000000000000000000016 :107A70000000000000000000000000000000000006 :107A800000000000000000000000000000000000F6 :107A900000000000000000000000000000000000E6 :107AA00000000000000000000000000000000000D6 :107AB00000000000000000000000000000000000C6 :107AC00000000000000000000000000000000000B6 :107AD00000000000000000000000000000000000A6 :107AE0000000000000000000000000000000000096 :107AF0000000000000000000000000000000000086 :107B00000000000000000000000000000000000075 :107B10000000000000000000000000000000000065 :107B20000000000000000000000000000000000055 :107B30000000000000000000000000000000000045 :107B40000000000000000000000000000000000035 :107B50000000000000000000000000000000000025 :107B60000000000000000000000000000000000015 :107B70000000000000000000000000000000000005 :107B800000000000000000000000000000000000F5 :107B900000000000000000000000000000000000E5 :107BA00000000000000000000000000000000000D5 :107BB00000000000000000000000000000000000C5 :107BC00000000000000000000000000000000000B5 :107BD00000000000000000000000000000000000A5 :107BE0000000000000000000000000000000000095 :107BF0000000000000000000000000000000000085 :107C00000000000000000000000000000000000074 :107C10000000000000000000000000000000000064 :107C20000000000000000000000000000000000054 :107C30000000000000000000000000000000000044 :107C40000000000000000000000000000000000034 :107C50000000000000000000000000000000000024 :107C60000000000000000000000000000000000014 :107C70000000000000000000000000000000000004 :107C800000000000000000000000000000000000F4 :107C900000000000000000000000000000000000E4 :107CA00000000000000000000000000000000000D4 :107CB00000000000000000000000000000000000C4 :107CC00000000000000000000000000000000000B4 :107CD00000000000000000000000000000000000A4 :107CE0000000000000000000000000000000000094 :107CF0000000000000000000000000000000000084 :107D00000000000000000000000000000000000073 :107D10000000000000000000000000000000000063 :107D20000000000000000000000000000000000053 :107D30000000000000000000000000000000000043 :107D40000000000000000000000000000000000033 :107D50000000000000000000000000000000000023 :107D60000000000000000000000000000000000013 :107D70000000000000000000000000000000000003 :107D800000000000000000000000000000000000F3 :107D900000000000000000000000000000000000E3 :107DA00000000000000000000000000000000000D3 :107DB00000000000000000000000000000000000C3 :107DC00000000000000000000000000000000000B3 :107DD00000000000000000000000000000000000A3 :107DE0000000000000000000000000000000000093 :107DF0000000000000000000000000000000000083 :107E00000000000000000000000000000000000072 :107E10000000000000000000000000000000000062 :107E20000000000000000000000000000000000052 :107E30000000000000000000000000000000000042 :107E40000000000000000000000000000000000032 :107E50000000000000000000000000000000000022 :107E60000000000000000000000000000000000012 :107E70000000000000000000000000000000000002 :107E800000000000000000000000000000000000F2 :107E900000000000000000000000000000000000E2 :107EA00000000000000000000000000000000000D2 :107EB00000000000000000000000000000000000C2 :107EC00000000000000000000000000000000000B2 :107ED00000000000000000000000000000000000A2 :107EE0000000000000000000000000000000000092 :107EF0000000000000000000000000000000000082 :107F00000000000000000000000000000000000071 :107F10000000000000000000000000000000000061 :107F20000000000000000000000000000000000051 :107F30000000000000000000000000000000000041 :107F40000000000000000000000000000000000031 :107F50000000000000000000000000000000000021 :107F60000000000000000000000000000000000011 :107F70000000000000000000000000000000000001 :107F800000000000000000000000000000000000F1 :107F900000000000000000000000000000000000E1 :107FA00000000000000000000000000000000000D1 :107FB00000000000000000000000000000000000C1 :107FC00000000000000000000000000000000000B1 :107FD00000000000000000000000000000000000A1 :107FE0000000000000000000000000000000000091 :107FF0000000000000000000000000000000000081 :108000000000000000000000000000000000000070 :108010000000000000000000000000000000000060 :108020000000000000000000000000000000000050 :108030000000000000000000000000000000000040 :108040000000000000000000000000000000000030 :108050000000000000000000000000000000000020 :108060000000000000000000000000000000000010 :108070000000000000000000000000000000000000 :1080800000000000000000000000000000000000F0 :1080900000000000000000000000000000000000E0 :1080A00000000000000000000000000000000000D0 :1080B00000000000000000000000000000000000C0 :1080C00000000000000000000000000000000000B0 :1080D00000000000000000000000000000000000A0 :1080E0000000000000000000000000000000000090 :1080F0000000000000000000000000000000000080 :10810000000000000000000000000000000000006F :10811000000000000000000000000000000000005F :10812000000000000000000000000000000000004F :10813000000000000000000000000000000000003F :10814000000000000000000000000000000000002F :10815000000000000000000000000000000000001F :10816000000000000000000000000000000000000F :1081700000000000000000000000000000000000FF :1081800000000000000000000000000000000000EF :1081900000000000000000000000000000000000DF :1081A00000000000000000000000000000000000CF :1081B00000000000000000000000000000000000BF :1081C00000000000000000000000000000000000AF :1081D000000000000000000000000000000000009F :1081E000000000000000000000000000000000008F :1081F000000000000000000000000000000000007F :10820000000000000000000000000000000000006E :10821000000000000000000000000000000000005E :10822000000000000000000000000000000000004E :10823000000000000000000000000000000000003E :10824000000000000000000000000000000000002E :10825000000000000000000000000000000000001E :10826000000000000000000000000000000000000E :1082700000000000000000000000000000000000FE :1082800000000000000000000000000000000000EE :1082900000000000000000000000000000000000DE :1082A00000000000000000000000000000000000CE :1082B00000000000000000000000000000000000BE :1082C00000000000000000000000000000000000AE :1082D000000000000000000000000000000000009E :1082E000000000000000000000000000000000008E :1082F000000000000000000000000000000000007E :10830000000000000000000000000000000000006D :10831000000000000000000000000000000000005D :10832000000000000000000000000000000000004D :10833000000000000000000000000000000000003D :10834000000000000000000000000000000000002D :10835000000000000000000000000000000000001D :10836000000000000000000000000000000000000D :1083700000000000000000000000000000000000FD :1083800000000000000000000000000000000000ED :1083900000000000000000000000000000000000DD :1083A00000000000000000000000000000000000CD :1083B00000000000000000000000000000000000BD :1083C00000000000000000000000000000000000AD :1083D000000000000000000000000000000000009D :1083E000000000000000000000000000000000008D :1083F000000000000000000000000000000000007D :10840000000000000000000000000000000000006C :10841000000000000000000000000000000000005C :10842000000000000000000000000000000000004C :10843000000000000000000000000000000000003C :10844000000000000000000000000000000000002C :10845000000000000000000000000000000000001C :10846000000000000000000000000000000000000C :1084700000000000000000000000000000000000FC :1084800000000000000000000000000000000000EC :1084900000000000000000000000000000000000DC :1084A00000000000000000000000000000000000CC :1084B00000000000000000000000000000000000BC :1084C00000000000000000000000000000000000AC :1084D000000000000000000000000000000000009C :1084E000000000000000000000000000000000008C :1084F000000000000000000000000000000000007C :10850000000000000000000000000000000000006B :10851000000000000000000000000000000000005B :10852000000000000000000000000000000000004B :10853000000000000000000000000000000000003B :10854000000000000000000000000000000000002B :10855000000000000000000000000000000000001B :10856000000000000000000000000000000000000B :1085700000000000000000000000000000000000FB :1085800000000000000000000000000000000000EB :1085900000000000000000000000000000000000DB :1085A00000000000000000000000000000000000CB :1085B00000000000000000000000000000000000BB :1085C00000000000000000000000000000000000AB :1085D000000000000000000000000000000000009B :1085E000000000000000000000000000000000008B :1085F000000000000000000000000000000000007B :10860000000000000000000000000000000000006A :10861000000000000000000000000000000000005A :10862000000000000000000000000000000000004A :10863000000000000000000000000000000000003A :10864000000000000000000000000000000000002A :10865000000000000000000000000000000000001A :10866000000000000000000000000000000000000A :1086700000000000000000000000000000000000FA :1086800000000000000000000000000000000000EA :1086900000000000000000000000000000000000DA :1086A00000000000000000000000000000000000CA :1086B00000000000000000000000000000000000BA :1086C00000000000000000000000000000000000AA :1086D000000000000000000000000000000000009A :1086E000000000000000000000000000000000008A :1086F000000000000000000000000000000000007A :108700000000000000000000000000000000000069 :108710000000000000000000000000000000000059 :108720000000000000000000000000000000000049 :108730000000000000000000000000000000000039 :108740000000000000000000000000000000000029 :108750000000000000000000000000000000000019 :108760000000000000000000000000000000000009 :1087700000000000000000000000000000000000F9 :1087800000000000000000000000000000000000E9 :1087900000000000000000000000000000000000D9 :1087A00000000000000000000000000000000000C9 :1087B00000000000000000000000000000000000B9 :1087C00000000000000000000000000000000000A9 :1087D0000000000000000000000000000000000099 :1087E0000000000000000000000000000000000089 :1087F0000000000000000000000000000000000079 :108800000000000000000000000000000000000068 :108810000000000000000000000000000000000058 :108820000000000000000000000000000000000048 :108830000000000000000000000000000000000038 :108840000000000000000000000000000000000028 :108850000000000000000000000000000000000018 :108860000000000000000000000000000000000008 :1088700000000000000000000000000000000000F8 :1088800000000000000000000000000000000000E8 :1088900000000000000000000000000000000000D8 :1088A00000000000000000000000000000000000C8 :1088B00000000000000000000000000000000000B8 :1088C00000000000000000000000000000000000A8 :1088D0000000000000000000000000000000000098 :1088E0000000000000000000000000000000000088 :1088F0000000000000000000000000000000000078 :108900000000000000000000000000000000000067 :108910000000000000000000000000000000000057 :108920000000000000000000000000000000000047 :108930000000000000000000000000000000000037 :108940000000000000000000000000000000000027 :108950000000000000000000000000000000000017 :108960000000000000000000000000000000000007 :1089700000000000000000000000000000000000F7 :1089800000000000000000000000000000000000E7 :1089900000000000000000000000000000000000D7 :1089A00000000000000000000000000000000000C7 :1089B00000000000000000000000000000000000B7 :1089C00000000000000000000000000000000000A7 :1089D0000000000000000000000000000000000097 :1089E0000000000000000000000000000000000087 :1089F0000000000000000000000000000000000077 :108A00000000000000000000000000000000000066 :108A10000000000000000000000000000000000056 :108A20000000000000000000000000000000000046 :108A30000000000000000000000000000000000036 :108A40000000000000000000000000000000000026 :108A50000000000000000000000000000000000016 :108A60000000000000000000000000000000000006 :108A700000000000000000000000000000000000F6 :108A800000000000000000000000000000000000E6 :108A900000000000000000000000000000000000D6 :108AA00000000000000000000000000000000000C6 :108AB00000000000000000000000000000000000B6 :108AC00000000000000000000000000000000000A6 :108AD0000000000000000000000000000000000096 :108AE0000000000000000000000000000000000086 :108AF0000000000000000000000000000000000076 :108B00000000000000000000000000000000000065 :108B10000000000000000000000000000000000055 :108B20000000000000000000000000000000000045 :108B30000000000000000000000000000000000035 :108B40000000000000000000000000000000000025 :108B50000000000000000000000000000000000015 :108B60000000000000000000000000000000000005 :108B700000000000000000000000000000000000F5 :108B800000000000000000000000000000000000E5 :108B900000000000000000000000000000000000D5 :108BA00000000000000000000000000000000000C5 :108BB00000000000000000000000000000000000B5 :108BC00000000000000000000000000000000000A5 :108BD0000000000000000000000000000000000095 :108BE0000000000000000000000000000000000085 :108BF0000000000000000000000000000000000075 :108C00000000000000000000000000000000000064 :108C10000000000000000000000000000000000054 :108C20000000000000000000000000000000000044 :108C30000000000000000000000000000000000034 :108C40000000000000000000000000000000000024 :108C50000000000000000000000000000000000014 :108C60000000000000000000000000000000000004 :108C700000000000000000000000000000000000F4 :108C800000000000000000000000000000000000E4 :108C900000000000000000000000000000000000D4 :108CA00000000000000000000000000000000000C4 :108CB00000000000000000000000000000000000B4 :108CC00000000000000000000000000000000000A4 :108CD0000000000000000000000000000000000094 :108CE0000000000000000000000000000000000084 :108CF0000000000000000000000000000000000074 :108D00000000000000000000000000000000000063 :108D10000000000000000000000000000000000053 :108D20000000000000000000000000000000000043 :108D30000000000000000000000000000000000033 :108D40000000000000000000000000000000000023 :108D50000000000000000000000000000000000013 :108D60000000000000000000000000000000000003 :108D700000000000000000000000000000000000F3 :108D800000000000000000000000000000000000E3 :108D900000000000000000000000000000000000D3 :108DA00000000000000000000000000000000000C3 :108DB00000000000000000000000000000000000B3 :108DC00000000000000000000000000000000000A3 :108DD0000000000000000000000000000000000093 :108DE0000000000000000000000000000000000083 :108DF0000000000000000000000000000000000073 :108E00000000000000000000000000000000000062 :108E10000000000000000000000000000000000052 :108E20000000000000000000000000000000000042 :108E30000000000000000000000000000000000032 :108E40000000000000000000000000000000000022 :108E50000000000000000000000000000000000012 :108E60000000000000000000000000000000000002 :108E700000000000000000000000000000000000F2 :108E800000000000000000000000000000000000E2 :108E900000000000000000000000000000000000D2 :108EA00000000000000000000000000000000000C2 :108EB00000000000000000000000000000000000B2 :108EC00000000000000000000000000000000000A2 :108ED0000000000000000000000000000000000092 :108EE0000000000000000000000000000000000082 :108EF0000000000000000000000000000000000072 :108F00000000000000000000000000000000000061 :108F10000000000000000000000000000000000051 :108F20000000000000000000000000000000000041 :108F30000000000000000000000000000000000031 :108F40000000000000000000000000000000000021 :108F50000000000000000000000000000000000011 :108F60000000000000000000000000000000000001 :108F700000000000000000000000000000000000F1 :108F800000000000000000000000000000000000E1 :108F900000000000000000000000000000000000D1 :108FA00000000000000000000000000000000000C1 :108FB00000000000000000000000000000000000B1 :108FC00000000000000000000000000000000000A1 :108FD0000000000000000000000000000000000091 :108FE0000000000000000000000000000000000081 :108FF0000000000000000000000000000000000071 :109000000000000000000000000000000000000060 :109010000000000000000000000000000000000050 :109020000000000000000000000000000000000040 :109030000000000000000000000000000000000030 :109040000000000000000000000000000000000020 :109050000000000000000000000000000000000010 :109060000000000000000000000000000000000000 :1090700000000000000000000000000000000000F0 :1090800000000000000000000000000000000000E0 :1090900000000000000000000000000000000000D0 :1090A00000000000000000000000000000000000C0 :1090B00000000000000000000000000000000000B0 :1090C00000000000000000000000000000000000A0 :1090D0000000000000000000000000000000000090 :1090E0000000000000000000000000000000000080 :1090F0000000000000000000000000000000000070 :10910000000000000000000000000000000000005F :10911000000000000000000000000000000000004F :10912000000000000000000000000000000000003F :10913000000000000000000000000000000000002F :10914000000000000000000000000000000000001F :10915000000000000000000000000000000000000F :1091600000000000000000000000000000000000FF :1091700000000000000000000000000000000000EF :1091800000000000000000000000000000000000DF :1091900000000000000000000000000000000000CF :1091A00000000000000000000000000000000000BF :1091B00000000000000000000000000000000000AF :1091C000000000000000000000000000000000009F :1091D000000000000000000000000000000000008F :1091E000000000000000000000000000000000007F :1091F000000000000000000000000000000000006F :10920000000000000000000000000000000000005E :10921000000000000000000000000000000000004E :10922000000000000000000000000000000000003E :10923000000000000000000000000000000000002E :10924000000000000000000000000000000000001E :10925000000000000000000000000000000000000E :1092600000000000000000000000000000000000FE :1092700000000000000000000000000000000000EE :1092800000000000000000000000000000000000DE :1092900000000000000000000000000000000000CE :1092A00000000000000000000000000000000000BE :1092B00000000000000000000000000000000000AE :1092C000000000000000000000000000000000009E :1092D000000000000000000000000000000000008E :1092E000000000000000000000000000000000007E :1092F000000000000000000000000000000000006E :10930000000000000000000000000000000000005D :10931000000000000000000000000000000000004D :10932000000000000000000000000000000000003D :10933000000000000000000000000000000000002D :10934000000000000000000000000000000000001D :10935000000000000000000000000000000000000D :1093600000000000000000000000000000000000FD :1093700000000000000000000000000000000000ED :1093800000000000000000000000000000000000DD :1093900000000000000000000000000000000000CD :1093A00000000000000000000000000000000000BD :1093B00000000000000000000000000000000000AD :1093C000000000000000000000000000000000009D :1093D000000000000000000000000000000000008D :1093E000000000000000000000000000000000007D :1093F000000000000000000000000000000000006D :10940000000000000000000000000000000000005C :10941000000000000000000000000000000000004C :10942000000000000000000000000000000000003C :10943000000000000000000000000000000000002C :10944000000000000000000000000000000000001C :10945000000000000000000000000000000000000C :1094600000000000000000000000000000000000FC :1094700000000000000000000000000000000000EC :1094800000000000000000000000000000000000DC :1094900000000000000000000000000000000000CC :1094A00000000000000000000000000000000000BC :1094B00000000000000000000000000000000000AC :1094C000000000000000000000000000000000009C :1094D000000000000000000000000000000000008C :1094E000000000000000000000000000000000007C :1094F000000000000000000000000000000000006C :10950000000000000000000000000000000000005B :10951000000000000000000000000000000000004B :10952000000000000000000000000000000000003B :10953000000000000000000000000000000000002B :10954000000000000000000000000000000000001B :10955000000000000000000000000000000000000B :1095600000000000000000000000000000000000FB :1095700000000000000000000000000000000000EB :1095800000000000000000000000000000000000DB :1095900000000000000000000000000000000000CB :1095A00000000000000000000000000000000000BB :1095B00000000000000000000000000000000000AB :1095C000000000000000000000000000000000009B :1095D000000000000000000000000000000000008B :1095E000000000000000000000000000000000007B :1095F000000000000000000000000000000000006B :10960000000000000000000000000000000000005A :10961000000000000000000000000000000000004A :10962000000000000000000000000000000000003A :10963000000000000000000000000000000000002A :10964000000000000000000000000000000000001A :10965000000000000000000000000000000000000A :1096600000000000000000000000000000000000FA :1096700000000000000000000000000000000000EA :1096800000000000000000000000000000000000DA :1096900000000000000000000000000000000000CA :1096A00000000000000000000000000000000000BA :1096B00000000000000000000000000000000000AA :1096C000000000000000000000000000000000009A :1096D000000000000000000000000000000000008A :1096E000000000000000000000000000000000007A :1096F000000000000000000000000000000000006A :109700000000000000000000000000000000000059 :109710000000000000000000000000000000000049 :109720000000000000000000000000000000000039 :109730000000000000000000000000000000000029 :109740000000000000000000000000000000000019 :109750000000000000000000000000000000000009 :1097600000000000000000000000000000000000F9 :1097700000000000000000000000000000000000E9 :1097800000000000000000000000000000000000D9 :1097900000000000000000000000000000000000C9 :1097A00000000000000000000000000000000000B9 :1097B00000000000000000000000000000000000A9 :1097C0000000000000000000000000000000000099 :1097D0000000000000000000000000000000000089 :1097E0000000000000000000000000000000000079 :1097F0000000000000000000000000000000000069 :109800000000000000000000000000000000000058 :109810000000000000000000000000000000000048 :109820000000000000000000000000000000000038 :109830000000000000000000000000000000000028 :109840000000000000000000000000000000000018 :109850000000000000000000000000000000000008 :1098600000000000000000000000000000000000F8 :1098700000000000000000000000000000000000E8 :1098800000000000000000000000000000000000D8 :1098900000000000000000000000000000000000C8 :1098A00000000000000000000000000000000000B8 :1098B00000000000000000000000000000000000A8 :1098C0000000000000000000000000000000000098 :1098D0000000000000000000000000000000000088 :1098E0000000000000000000000000000000000078 :1098F0000000000000000000000000000000000068 :109900000000000000000000000000000000000057 :109910000000000000000000000000000000000047 :109920000000000000000000000000000000000037 :109930000000000000000000000000000000000027 :109940000000000000000000000000000000000017 :109950000000000000000000000000000000000007 :1099600000000000000000000000000000000000F7 :1099700000000000000000000000000000000000E7 :1099800000000000000000000000000000000000D7 :1099900000000000000000000000000000000000C7 :1099A00000000000000000000000000000000000B7 :1099B00000000000000000000000000000000000A7 :1099C0000000000000000000000000000000000097 :1099D0000000000000000000000000000000000087 :1099E0000000000000000000000000000000000077 :1099F0000000000000000000000000000000000067 :109A00000000000000000000000000000000000056 :109A10000000000000000000000000000000000046 :109A20000000000000000000000000000000000036 :109A30000000000000000000000000000000000026 :109A40000000000000000000000000000000000016 :109A50000000000000000000000000000000000006 :109A600000000000000000000000000000000000F6 :109A700000000000000000000000000000000000E6 :109A800000000000000000000000000000000000D6 :109A900000000000000000000000000000000000C6 :109AA00000000000000000000000000000000000B6 :109AB00000000000000000000000000000000000A6 :109AC0000000000000000000000000000000000096 :109AD0000000000000000000000000000000000086 :109AE0000000000000000000000000000000000076 :109AF0000000000000000000000000000000000066 :109B00000000000000000000000000000000000055 :109B10000000000000000000000000000000000045 :109B20000000000000000000000000000000000035 :109B30000000000000000000000000000000000025 :109B40000000000000000000000000000000000015 :109B50000000000000000000000000000000000005 :109B600000000000000000000000000000000000F5 :109B700000000000000000000000000000000000E5 :109B800000000000000000000000000000000000D5 :109B900000000000000000000000000000000000C5 :109BA00000000000000000000000000000000000B5 :109BB00000000000000000000000000000000000A5 :109BC0000000000000000000000000000000000095 :109BD0000000000000000000000000000000000085 :109BE0000000000000000000000000000000000075 :109BF0000000000000000000000000000000000065 :109C00000000000000000000000000000000000054 :109C10000000000000000000000000000000000044 :109C20000000000000000000000000000000000034 :109C30000000000000000000000000000000000024 :109C40000000000000000000000000000000000014 :109C50000000000000000000000000000000000004 :109C600000000000000000000000000000000000F4 :109C700000000000000000000000000000000000E4 :109C800000000000000000000000000000000000D4 :109C900000000000000000000000000000000000C4 :109CA00000000000000000000000000000000000B4 :109CB00000000000000000000000000000000000A4 :109CC0000000000000000000000000000000000094 :109CD0000000000000000000000000000000000084 :109CE0000000000000000000000000000000000074 :109CF0000000000000000000000000000000000064 :109D00000000000000000000000000000000000053 :109D10000000000000000000000000000000000043 :109D20000000000000000000000000000000000033 :109D30000000000000000000000000000000000023 :109D40000000000000000000000000000000000013 :109D50000000000000000000000000000000000003 :109D600000000000000000000000000000000000F3 :109D700000000000000000000000000000000000E3 :109D800000000000000000000000000000000000D3 :109D900000000000000000000000000000000000C3 :109DA00000000000000000000000000000000000B3 :109DB00000000000000000000000000000000000A3 :109DC0000000000000000000000000000000000093 :109DD0000000000000000000000000000000000083 :109DE0000000000000000000000000000000000073 :109DF0000000000000000000000000000000000063 :109E00000000000000000000000000000000000052 :109E10000000000000000000000000000000000042 :109E20000000000000000000000000000000000032 :109E30000000000000000000000000000000000022 :109E40000000000000000000000000000000000012 :109E50000000000000000000000000000000000002 :109E600000000000000000000000000000000000F2 :109E700000000000000000000000000000000000E2 :109E800000000000000000000000000000000000D2 :109E900000000000000000000000000000000000C2 :109EA00000000000000000000000000000000000B2 :109EB00000000000000000000000000000000000A2 :109EC0000000000000000000000000000000000092 :109ED0000000000000000000000000000000000082 :109EE0000000000000000000000000000000000072 :109EF0000000000000000000000000000000000062 :109F00000000000000000000000000000000000051 :109F10000000000000000000000000000000000041 :109F20000000000000000000000000000000000031 :109F30000000000000000000000000000000000021 :109F40000000000000000000000000000000000011 :109F50000000000000000000000000000000000001 :109F600000000000000000000000000000000000F1 :109F700000000000000000000000000000000000E1 :109F800000000000000000000000000000000000D1 :109F900000000000000000000000000000000000C1 :109FA00000000000000000000000000000000000B1 :109FB00000000000000000000000000000000000A1 :109FC0000000000000000000000000000000000091 :109FD0000000000000000000000000000000000081 :109FE0000000000000000000000000000000000071 :109FF0000000000000000000000000000000000061 :10A000000000000000000000000000000000000050 :10A010000000000000000000000000000000000040 :10A020000000000000000000000000000000000030 :10A030000000000000000000000000000000000020 :10A040000000000000000000000000000000000010 :10A050000000000000000000000000000000000000 :10A0600000000000000000000000000000000000F0 :10A0700000000000000000000000000000000000E0 :10A0800000000000000000000000000000000000D0 :10A0900000000000000000000000000000000000C0 :10A0A00000000000000000000000000000000000B0 :10A0B00000000000000000000000000000000000A0 :10A0C0000000000000000000000000000000000090 :10A0D0000000000000000000000000000000000080 :10A0E0000000000000000000000000000000000070 :10A0F0000000000000000000000000000000000060 :10A10000000000000000000000000000000000004F :10A11000000000000000000000000000000000003F :10A12000000000000000000000000000000000002F :10A13000000000000000000000000000000000001F :10A14000000000000000000000000000000000000F :10A1500000000000000000000000000000000000FF :10A1600000000000000000000000000000000000EF :10A1700000000000000000000000000000000000DF :10A1800000000000000000000000000000000000CF :10A1900000000000000000000000000000000000BF :10A1A00000000000000000000000000000000000AF :10A1B000000000000000000000000000000000009F :10A1C000000000000000000000000000000000008F :10A1D000000000000000000000000000000000007F :10A1E000000000000000000000000000000000006F :10A1F000000000000000000000000000000000005F :10A20000000000000000000000000000000000004E :10A21000000000000000000000000000000000003E :10A22000000000000000000000000000000000002E :10A23000000000000000000000000000000000001E :10A24000000000000000000000000000000000000E :10A2500000000000000000000000000000000000FE :10A2600000000000000000000000000000000000EE :10A2700000000000000000000000000000000000DE :10A2800000000000000000000000000000000000CE :10A2900000000000000000000000000000000000BE :10A2A00000000000000000000000000000000000AE :10A2B000000000000000000000000000000000009E :10A2C000000000000000000000000000000000008E :10A2D000000000000000000000000000000000007E :10A2E000000000000000000000000000000000006E :10A2F000000000000000000000000000000000005E :10A30000000000000000000000000000000000004D :10A31000000000000000000000000000000000003D :10A32000000000000000000000000000000000002D :10A33000000000000000000000000000000000001D :10A34000000000000000000000000000000000000D :10A3500000000000000000000000000000000000FD :10A3600000000000000000000000000000000000ED :10A3700000000000000000000000000000000000DD :10A3800000000000000000000000000000000000CD :10A3900000000000000000000000000000000000BD :10A3A00000000000000000000000000000000000AD :10A3B000000000000000000000000000000000009D :10A3C000000000000000000000000000000000008D :10A3D000000000000000000000000000000000007D :10A3E000000000000000000000000000000000006D :10A3F000000000000000000000000000000000005D :10A40000000000000000000000000000000000004C :10A41000000000000000000000000000000000003C :10A42000000000000000000000000000000000002C :10A43000000000000000000000000000000000001C :10A44000000000000000000000000000000000000C :10A4500000000000000000000000000000000000FC :10A4600000000000000000000000000000000000EC :10A4700000000000000000000000000000000000DC :10A4800000000000000000000000000000000000CC :10A4900000000000000000000000000000000000BC :10A4A00000000000000000000000000000000000AC :10A4B000000000000000000000000000000000009C :10A4C000000000000000000000000000000000008C :10A4D000000000000000000000000000000000007C :10A4E000000000000000000000000000000000006C :10A4F000000000000000000000000000000000005C :10A50000000000000000000000000000000000004B :10A51000000000000000000000000000000000003B :10A52000000000000000000000000000000000002B :10A53000000000000000000000000000000000001B :10A54000000000000000000000000000000000000B :10A5500000000000000000000000000000000000FB :10A5600000000000000000000000000000000000EB :10A5700000000000000000000000000000000000DB :10A5800000000000000000000000000000000000CB :10A5900000000000000000000000000000000000BB :10A5A00000000000000000000000000000000000AB :10A5B000000000000000000000000000000000009B :10A5C000000000000000000000000000000000008B :10A5D000000000000000000000000000000000007B :10A5E000000000000000000000000000000000006B :10A5F000000000000000000000000000000000005B :10A60000000000000000000000000000000000004A :10A61000000000000000000000000000000000003A :10A62000000000000000000000000000000000002A :10A63000000000000000000000000000000000001A :10A64000000000000000000000000000000000000A :10A6500000000000000000000000000000000000FA :10A6600000000000000000000000000000000000EA :10A6700000000000000000000000000000000000DA :10A6800000000000000000000000000000000000CA :10A6900000000000000000000000000000000000BA :10A6A00000000000000000000000000000000000AA :10A6B000000000000000000000000000000000009A :10A6C000000000000000000000000000000000008A :10A6D000000000000000000000000000000000007A :10A6E000000000000000000000000000000000006A :10A6F000000000000000000000000000000000005A :10A700000000000000000000000000000000000049 :10A710000000000000000000000000000000000039 :10A720000000000000000000000000000000000029 :10A730000000000000000000000000000000000019 :10A740000000000000000000000000000000000009 :10A7500000000000000000000000000000000000F9 :10A7600000000000000000000000000000000000E9 :10A7700000000000000000000000000000000000D9 :10A7800000000000000000000000000000000000C9 :10A7900000000000000000000000000000000000B9 :10A7A00000000000000000000000000000000000A9 :10A7B0000000000000000000000000000000000099 :10A7C0000000000000000000000000000000000089 :10A7D0000000000000000000000000000000000079 :10A7E0000000000000000000000000000000000069 :10A7F0000000000000000000000000000000000059 :10A800000000000000000000000000000000000048 :10A810000000000000000000000000000000000038 :10A820000000000000000000000000000000000028 :10A830000000000000000000000000000000000018 :10A840000000000000000000000000000000000008 :10A8500000000000000000000000000000000000F8 :10A8600000000000000000000000000000000000E8 :10A8700000000000000000000000000000000000D8 :10A8800000000000000000000000000000000000C8 :10A8900000000000000000000000000000000000B8 :10A8A00000000000000000000000000000000000A8 :10A8B0000000000000000000000000000000000098 :10A8C0000000000000000000000000000000000088 :10A8D0000000000000000000000000000000000078 :10A8E0000000000000000000000000000000000068 :10A8F0000000000000000000000000000000000058 :10A900000000000000000000000000000000000047 :10A910000000000000000000000000000000000037 :10A920000000000000000000000000000000000027 :10A930000000000000000000000000000000000017 :10A940000000000000000000000000000000000007 :10A9500000000000000000000000000000000000F7 :10A9600000000000000000000000000000000000E7 :10A9700000000000000000000000000000000000D7 :10A9800000000000000000000000000000000000C7 :10A9900000000000000000000000000000000000B7 :10A9A00000000000000000000000000000000000A7 :10A9B0000000000000000000000000000000000097 :10A9C0000000000000000000000000000000000087 :10A9D0000000000000000000000000000000000077 :10A9E0000000000000000000000000000000000067 :10A9F0000000000000000000000000000000000057 :10AA00000000000000000000000000000000000046 :10AA10000000000000000000000000000000000036 :10AA20000000000000000000000000000000000026 :10AA30000000000000000000000000000000000016 :10AA40000000000000000000000000000000000006 :10AA500000000000000000000000000000000000F6 :10AA600000000000000000000000000000000000E6 :10AA700000000000000000000000000000000000D6 :10AA800000000000000000000000000000000000C6 :10AA900000000000000000000000000000000000B6 :10AAA00000000000000000000000000000000000A6 :10AAB0000000000000000000000000000000000096 :10AAC0000000000000000000000000000000000086 :10AAD0000000000000000000000000000000000076 :10AAE0000000000000000000000000000000000066 :10AAF0000000000000000000000000000000000056 :10AB00000000000000000000000000000000000045 :10AB10000000000000000000000000000000000035 :10AB20000000000000000000000000000000000025 :10AB30000000000000000000000000000000000015 :10AB40000000000000000000000000000000000005 :10AB500000000000000000000000000000000000F5 :10AB600000000000000000000000000000000000E5 :10AB700000000000000000000000000000000000D5 :10AB800000000000000000000000000000000000C5 :10AB900000000000000000000000000000000000B5 :10ABA00000000000000000000000000000000000A5 :10ABB0000000000000000000000000000000000095 :10ABC0000000000000000000000000000000000085 :10ABD0000000000000000000000000000000000075 :10ABE0000000000000000000000000000000000065 :10ABF0000000000000000000000000000000000055 :10AC00000000000000000000000000000000000044 :10AC10000000000000000000000000000000000034 :10AC20000000000000000000000000000000000024 :10AC30000000000000000000000000000000000014 :10AC40000000000000000000000000000000000004 :10AC500000000000000000000000000000000000F4 :10AC600000000000000000000000000000000000E4 :10AC700000000000000000000000000000000000D4 :10AC800000000000000000000000000000000000C4 :10AC900000000000000000000000000000000000B4 :10ACA00000000000000000000000000000000000A4 :10ACB0000000000000000000000000000000000094 :10ACC0000000000000000000000000000000000084 :10ACD0000000000000000000000000000000000074 :10ACE0000000000000000000000000000000000064 :10ACF0000000000000000000000000000000000054 :10AD00000000000000000000000000000000000043 :10AD10000000000000000000000000000000000033 :10AD20000000000000000000000000000000000023 :10AD30000000000000000000000000000000000013 :10AD40000000000000000000000000000000000003 :10AD500000000000000000000000000000000000F3 :10AD600000000000000000000000000000000000E3 :10AD700000000000000000000000000000000000D3 :10AD800000000000000000000000000000000000C3 :10AD900000000000000000000000000000000000B3 :10ADA00000000000000000000000000000000000A3 :10ADB0000000000000000000000000000000000093 :10ADC0000000000000000000000000000000000083 :10ADD0000000000000000000000000000000000073 :10ADE0000000000000000000000000000000000063 :10ADF0000000000000000000000000000000000053 :10AE00000000000000000000000000000000000042 :10AE10000000000000000000000000000000000032 :10AE20000000000000000000000000000000000022 :10AE30000000000000000000000000000000000012 :10AE40000000000000000000000000000000000002 :10AE500000000000000000000000000000000000F2 :10AE600000000000000000000000000000000000E2 :10AE700000000000000000000000000000000000D2 :10AE800000000000000000000000000000000000C2 :10AE900000000000000000000000000000000000B2 :10AEA00000000000000000000000000000000000A2 :10AEB0000000000000000000000000000000000092 :10AEC0000000000000000000000000000000000082 :10AED0000000000000000000000000000000000072 :10AEE0000000000000000000000000000000000062 :10AEF0000000000000000000000000000000000052 :10AF00000000000000000000000000000000000041 :10AF10000000000000000000000000000000000031 :10AF20000000000000000000000000000000000021 :10AF30000000000000000000000000000000000011 :10AF40000000000000000000000000000000000001 :10AF500000000000000000000000000000000000F1 :10AF600000000000000000000000000000000000E1 :10AF700000000000000000000000000000000000D1 :10AF800000000000000000000000000000000000C1 :10AF900000000000000000000000000000000000B1 :10AFA00000000000000000000000000000000000A1 :10AFB0000000000000000000000000000000000091 :10AFC0000000000000000000000000000000000081 :10AFD0000000000000000000000000000000000071 :10AFE0000000000000000000000000000000000061 :10AFF0000000000000000000000000000000000051 :10B000000000000000000000000000000000000040 :10B010000000000000000000000000000000000030 :10B020000000000000000000000000000000000020 :10B030000000000000000000000000000000000010 :10B040000000000000000000000000000000000000 :10B0500000000000000000000000000000000000F0 :10B0600000000000000000000000000000000000E0 :10B0700000000000000000000000000000000000D0 :10B0800000000000000000000000000000000000C0 :10B0900000000000000000000000000000000000B0 :10B0A00000000000000000000000000000000000A0 :10B0B0000000000000000000000000000000000090 :10B0C0000000000000000000000000000000000080 :10B0D0000000000000000000000000000000000070 :10B0E0000000000000000000000000000000000060 :10B0F0000000000000000000000000000000000050 :10B10000000000000000000000000000000000003F :10B11000000000000000000000000000000000002F :10B12000000000000000000000000000000000001F :10B13000000000000000000000000000000000000F :10B1400000000000000000000000000000000000FF :10B1500000000000000000000000000000000000EF :10B1600000000000000000000000000000000000DF :10B1700000000000000000000000000000000000CF :10B1800000000000000000000000000000000000BF :10B1900000000000000000000000000000000000AF :10B1A000000000000000000000000000000000009F :10B1B000000000000000000000000000000000008F :10B1C000000000000000000000000000000000007F :10B1D000000000000000000000000000000000006F :10B1E000000000000000000000000000000000005F :10B1F000000000000000000000000000000000004F :10B20000000000000000000000000000000000003E :10B21000000000000000000000000000000000002E :10B22000000000000000000000000000000000001E :10B23000000000000000000000000000000000000E :10B2400000000000000000000000000000000000FE :10B2500000000000000000000000000000000000EE :10B2600000000000000000000000000000000000DE :10B2700000000000000000000000000000000000CE :10B2800000000000000000000000000000000000BE :10B2900000000000000000000000000000000000AE :10B2A000000000000000000000000000000000009E :10B2B000000000000000000000000000000000008E :10B2C000000000000000000000000000000000007E :10B2D000000000000000000000000000000000006E :10B2E000000000000000000000000000000000005E :10B2F000000000000000000000000000000000004E :10B30000000000000000000000000000000000003D :10B31000000000000000000000000000000000002D :10B32000000000000000000000000000000000001D :10B33000000000000000000000000000000000000D :10B3400000000000000000000000000000000000FD :10B3500000000000000000000000000000000000ED :10B3600000000000000000000000000000000000DD :10B3700000000000000000000000000000000000CD :10B3800000000000000000000000000000000000BD :10B3900000000000000000000000000000000000AD :10B3A000000000000000000000000000000000009D :10B3B000000000000000000000000000000000008D :10B3C000000000000000000000000000000000007D :10B3D000000000000000000000000000000000006D :10B3E000000000000000000000000000000000005D :10B3F000000000000000000000000000000000004D :10B40000000000000000000000000000000000003C :10B41000000000000000000000000000000000002C :10B42000000000000000000000000000000000001C :10B43000000000000000000000000000000000000C :10B4400000000000000000000000000000000000FC :10B4500000000000000000000000000000000000EC :10B4600000000000000000000000000000000000DC :10B4700000000000000000000000000000000000CC :10B4800000000000000000000000000000000000BC :10B4900000000000000000000000000000000000AC :10B4A000000000000000000000000000000000009C :10B4B000000000000000000000000000000000008C :10B4C000000000000000000000000000000000007C :10B4D000000000000000000000000000000000006C :10B4E000000000000000000000000000000000005C :10B4F000000000000000000000000000000000004C :10B50000000000000000000000000000000000003B :10B51000000000000000000000000000000000002B :10B52000000000000000000000000000000000001B :10B53000000000000000000000000000000000000B :10B5400000000000000000000000000000000000FB :10B5500000000000000000000000000000000000EB :10B5600000000000000000000000000000000000DB :10B5700000000000000000000000000000000000CB :10B5800000000000000000000000000000000000BB :10B5900000000000000000000000000000000000AB :10B5A000000000000000000000000000000000009B :10B5B000000000000000000000000000000000008B :10B5C000000000000000000000000000000000007B :10B5D000000000000000000000000000000000006B :10B5E000000000000000000000000000000000005B :10B5F000000000000000000000000000000000004B :10B60000000000000000000000000000000000003A :10B61000000000000000000000000000000000002A :10B62000000000000000000000000000000000001A :10B63000000000000000000000000000000000000A :10B6400000000000000000000000000000000000FA :10B6500000000000000000000000000000000000EA :10B6600000000000000000000000000000000000DA :10B6700000000000000000000000000000000000CA :10B6800000000000000000000000000000000000BA :10B6900000000000000000000000000000000000AA :10B6A000000000000000000000000000000000009A :10B6B000000000000000000000000000000000008A :10B6C000000000000000000000000000000000007A :10B6D000000000000000000000000000000000006A :10B6E000000000000000000000000000000000005A :10B6F000000000000000000000000000000000004A :10B700000000000000000000000000000000000039 :10B710000000000000000000000000000000000029 :10B720000000000000000000000000000000000019 :10B730000000000000000000000000000000000009 :10B7400000000000000000000000000000000000F9 :10B7500000000000000000000000000000000000E9 :10B7600000000000000000000000000000000000D9 :10B7700000000000000000000000000000000000C9 :10B7800000000000000000000000000000000000B9 :10B7900000000000000000000000000000000000A9 :10B7A0000000000000000000000000000000000099 :10B7B0000000000000000000000000000000000089 :10B7C0000000000000000000000000000000000079 :10B7D0000000000000000000000000000000000069 :10B7E0000000000000000000000000000000000059 :10B7F0000000000000000000000000000000000049 :10B800000000000000000000000000000000000038 :10B810000000000000000000000000000000000028 :10B820000000000000000000000000000000000018 :10B830000000000000000000000000000000000008 :10B8400000000000000000000000000000000000F8 :10B8500000000000000000000000000000000000E8 :10B8600000000000000000000000000000000000D8 :10B8700000000000000000000000000000000000C8 :10B8800000000000000000000000000000000000B8 :10B8900000000000000000000000000000000000A8 :10B8A0000000000000000000000000000000000098 :10B8B0000000000000000000000000000000000088 :10B8C0000000000000000000000000000000000078 :10B8D0000000000000000000000000000000000068 :10B8E0000000000000000000000000000000000058 :10B8F0000000000000000000000000000000000048 :10B900000000000000000000000000000000000037 :10B910000000000000000000000000000000000027 :10B920000000000000000000000000000000000017 :10B930000000000000000000000000000000000007 :10B9400000000000000000000000000000000000F7 :10B9500000000000000000000000000000000000E7 :10B9600000000000000000000000000000000000D7 :10B9700000000000000000000000000000000000C7 :10B9800000000000000000000000000000000000B7 :10B9900000000000000000000000000000000000A7 :10B9A0000000000000000000000000000000000097 :10B9B0000000000000000000000000000000000087 :10B9C0000000000000000000000000000000000077 :10B9D0000000000000000000000000000000000067 :10B9E0000000000000000000000000000000000057 :10B9F0000000000000000000000000000000000047 :10BA00000000000000000000000000000000000036 :10BA10000000000000000000000000000000000026 :10BA20000000000000000000000000000000000016 :10BA30000000000000000000000000000000000006 :10BA400000000000000000000000000000000000F6 :10BA500000000000000000000000000000000000E6 :10BA600000000000000000000000000000000000D6 :10BA700000000000000000000000000000000000C6 :10BA800000000000000000000000000000000000B6 :10BA900000000000000000000000000000000000A6 :10BAA0000000000000000000000000000000000096 :10BAB0000000000000000000000000000000000086 :10BAC0000000000000000000000000000000000076 :10BAD0000000000000000000000000000000000066 :10BAE0000000000000000000000000000000000056 :10BAF0000000000000000000000000000000000046 :10BB00000000000000000000000000000000000035 :10BB10000000000000000000000000000000000025 :10BB20000000000000000000000000000000000015 :10BB30000000000000000000000000000000000005 :10BB400000000000000000000000000000000000F5 :10BB500000000000000000000000000000000000E5 :10BB600000000000000000000000000000000000D5 :10BB700000000000000000000000000000000000C5 :10BB800000000000000000000000000000000000B5 :10BB900000000000000000000000000000000000A5 :10BBA0000000000000000000000000000000000095 :10BBB0000000000000000000000000000000000085 :10BBC0000000000000000000000000000000000075 :10BBD0000000000000000000000000000000000065 :10BBE0000000000000000000000000000000000055 :10BBF0000000000000000000000000000000000045 :10BC00000000000000000000000000000000000034 :10BC10000000000000000000000000000000000024 :10BC20000000000000000000000000000000000014 :10BC30000000000000000000000000000000000004 :10BC400000000000000000000000000000000000F4 :10BC500000000000000000000000000000000000E4 :10BC600000000000000000000000000000000000D4 :10BC700000000000000000000000000000000000C4 :10BC800000000000000000000000000000000000B4 :10BC900000000000000000000000000000000000A4 :10BCA0000000000000000000000000000000000094 :10BCB0000000000000000000000000000000000084 :10BCC0000000000000000000000000000000000074 :10BCD0000000000000000000000000000000000064 :10BCE0000000000000000000000000000000000054 :10BCF0000000000000000000000000000000000044 :10BD00000000000000000000000000000000000033 :10BD10000000000000000000000000000000000023 :10BD20000000000000000000000000000000000013 :10BD30000000000000000000000000000000000003 :10BD400000000000000000000000000000000000F3 :10BD500000000000000000000000000000000000E3 :10BD600000000000000000000000000000000000D3 :10BD700000000000000000000000000000000000C3 :10BD800000000000000000000000000000000000B3 :10BD900000000000000000000000000000000000A3 :10BDA0000000000000000000000000000000000093 :10BDB0000000000000000000000000000000000083 :10BDC0000000000000000000000000000000000073 :10BDD0000000000000000000000000000000000063 :10BDE0000000000000000000000000000000000053 :10BDF0000000000000000000000000000000000043 :10BE00000000000000000000000000000000000032 :10BE10000000000000000000000000000000000022 :10BE20000000000000000000000000000000000012 :10BE30000000000000000000000000000000000002 :10BE400000000000000000000000000000000000F2 :10BE500000000000000000000000000000000000E2 :10BE600000000000000000000000000000000000D2 :10BE700000000000000000000000000000000000C2 :10BE800000000000000000000000000000000000B2 :10BE900000000000000000000000000000000000A2 :10BEA0000000000000000000000000000000000092 :10BEB0000000000000000000000000000000000082 :10BEC0000000000000000000000000000000000072 :10BED0000000000000000000000000000000000062 :10BEE0000000000000000000000000000000000052 :10BEF0000000000000000000000000000000000042 :10BF00000000000000000000000000000000000031 :10BF10000000000000000000000000000000000021 :10BF20000000000000000000000000000000000011 :10BF30000000000000000000000000000000000001 :10BF400000000000000000000000000000000000F1 :10BF500000000000000000000000000000000000E1 :10BF600000000000000000000000000000000000D1 :10BF700000000000000000000000000000000000C1 :10BF800000000000000000000000000000000000B1 :10BF900000000000000000000000000000000000A1 :10BFA0000000000000000000000000000000000091 :10BFB0000000000000000000000000000000000081 :10BFC0000000000000000000000000000000000071 :10BFD0000000000000000000000000000000000061 :10BFE0000000000000000000000000000000000051 :10BFF0000000000000000000000000000000000041 :10C000000000000000000000000000000000000030 :10C010000000000000000000000000000000000020 :10C020000000000000000000000000000000000010 :10C030000000000000000000000000000000000000 :10C0400000000000000000000000000000000000F0 :10C0500000000000000000000000000000000000E0 :10C0600000000000000000000000000000000000D0 :10C0700000000000000000000000000000000000C0 :10C0800000000000000000000000000000000000B0 :10C0900000000000000000000000000000000000A0 :10C0A0000000000000000000000000000000000090 :10C0B0000000000000000000000000000000000080 :10C0C0000000000000000000000000000000000070 :10C0D0000000000000000000000000000000000060 :10C0E0000000000000000000000000000000000050 :10C0F0000000000000000000000000000000000040 :10C10000000000000000000000000000000000002F :10C11000000000000000000000000000000000001F :10C12000000000000000000000000000000000000F :10C1300000000000000000000000000000000000FF :10C1400000000000000000000000000000000000EF :10C1500000000000000000000000000000000000DF :10C1600000000000000000000000000000000000CF :10C1700000000000000000000000000000000000BF :10C1800000000000000000000000000000000000AF :10C19000000000000000000000000000000000009F :10C1A000000000000000000000000000000000008F :10C1B000000000000000000000000000000000007F :10C1C000000000000000000000000000000000006F :10C1D000000000000000000000000000000000005F :10C1E000000000000000000000000000000000004F :10C1F000000000000000000000000000000000003F :10C20000000000000000000000000000000000002E :10C21000000000000000000000000000000000001E :10C22000000000000000000000000000000000000E :10C2300000000000000000000000000000000000FE :10C2400000000000000000000000000000000000EE :10C2500000000000000000000000000000000000DE :10C2600000000000000000000000000000000000CE :10C2700000000000000000000000000000000000BE :10C2800000000000000000000000000000000000AE :10C29000000000000000000000000000000000009E :10C2A000000000000000000000000000000000008E :10C2B000000000000000000000000000000000007E :10C2C000000000000000000000000000000000006E :10C2D000000000000000000000000000000000005E :10C2E000000000000000000000000000000000004E :10C2F000000000000000000000000000000000003E :10C30000000000000000000000000000000000002D :10C31000000000000000000000000000000000001D :10C32000000000000000000000000000000000000D :10C3300000000000000000000000000000000000FD :10C3400000000000000000000000000000000000ED :10C3500000000000000000000000000000000000DD :10C3600000000000000000000000000000000000CD :10C3700000000000000000000000000000000000BD :10C3800000000000000000000000000000000000AD :10C39000000000000000000000000000000000009D :10C3A000000000000000000000000000000000008D :10C3B000000000000000000000000000000000007D :10C3C000000000000000000000000000000000006D :10C3D000000000000000000000000000000000005D :10C3E000000000000000000000000000000000004D :10C3F000000000000000000000000000000000003D :10C40000000000000000000000000000000000002C :10C41000000000000000000000000000000000001C :10C42000000000000000000000000000000000000C :10C4300000000000000000000000000000000000FC :10C4400000000000000000000000000000000000EC :10C4500000000000000000000000000000000000DC :10C4600000000000000000000000000000000000CC :10C4700000000000000000000000000000000000BC :10C4800000000000000000000000000000000000AC :10C49000000000000000000000000000000000009C :10C4A000000000000000000000000000000000008C :10C4B000000000000000000000000000000000007C :10C4C000000000000000000000000000000000006C :10C4D000000000000000000000000000000000005C :10C4E000000000000000000000000000000000004C :10C4F000000000000000000000000000000000003C :10C50000000000000000000000000000000000002B :10C51000000000000000000000000000000000001B :10C52000000000000000000000000000000000000B :10C5300000000000000000000000000000000000FB :10C5400000000000000000000000000000000000EB :10C5500000000000000000000000000000000000DB :10C5600000000000000000000000000000000000CB :10C5700000000000000000000000000000000000BB :10C5800000000000000000000000000000000000AB :10C59000000000000000000000000000000000009B :10C5A000000000000000000000000000000000008B :10C5B000000000000000000000000000000000007B :10C5C000000000000000000000000000000000006B :10C5D000000000000000000000000000000000005B :10C5E000000000000000000000000000000000004B :10C5F000000000000000000000000000000000003B :10C60000000000000000000000000000000000002A :10C61000000000000000000000000000000000001A :10C62000000000000000000000000000000000000A :10C6300000000000000000000000000000000000FA :10C6400000000000000000000000000000000000EA :10C6500000000000000000000000000000000000DA :10C6600000000000000000000000000000000000CA :10C6700000000000000000000000000000000000BA :10C6800000000000000000000000000000000000AA :10C69000000000000000000000000000000000009A :10C6A000000000000000000000000000000000008A :10C6B000000000000000000000000000000000007A :10C6C000000000000000000000000000000000006A :10C6D000000000000000000000000000000000005A :10C6E000000000000000000000000000000000004A :10C6F000000000000000000000000000000000003A :10C700000000000000000000000000000000000029 :10C710000000000000000000000000000000000019 :10C720000000000000000000000000000000000009 :10C7300000000000000000000000000000000000F9 :10C7400000000000000000000000000000000000E9 :10C7500000000000000000000000000000000000D9 :10C7600000000000000000000000000000000000C9 :10C7700000000000000000000000000000000000B9 :10C7800000000000000000000000000000000000A9 :10C790000000000000000000000000000000000099 :10C7A0000000000000000000000000000000000089 :10C7B0000000000000000000000000000000000079 :10C7C0000000000000000000000000000000000069 :10C7D0000000000000000000000000000000000059 :10C7E0000000000000000000000000000000000049 :10C7F0000000000000000000000000000000000039 :10C800000000000000000000000000000000000028 :10C810000000000000000000000000000000000018 :10C820000000000000000000000000000000000008 :10C8300000000000000000000000000000000000F8 :10C8400000000000000000000000000000000000E8 :10C8500000000000000000000000000000000000D8 :10C8600000000000000000000000000000000000C8 :10C8700000000000000000000000000000000000B8 :10C8800000000000000000000000000000000000A8 :10C890000000000000000000000000000000000098 :10C8A0000000000000000000000000000000000088 :10C8B0000000000000000000000000000000000078 :10C8C0000000000000000000000000000000000068 :10C8D0000000000000000000000000000000000058 :10C8E0000000000000000000000000000000000048 :10C8F0000000000000000000000000000000000038 :10C900000000000000000000000000000000000027 :10C910000000000000000000000000000000000017 :10C920000000000000000000000000000000000007 :10C9300000000000000000000000000000000000F7 :10C9400000000000000000000000000000000000E7 :10C9500000000000000000000000000000000000D7 :10C9600000000000000000000000000000000000C7 :10C9700000000000000000000000000000000000B7 :10C9800000000000000000000000000000000000A7 :10C990000000000000000000000000000000000097 :10C9A0000000000000000000000000000000000087 :10C9B0000000000000000000000000000000000077 :10C9C0000000000000000000000000000000000067 :10C9D0000000000000000000000000000000000057 :10C9E0000000000000000000000000000000000047 :10C9F0000000000000000000000000000000000037 :10CA00000000000000000000000000000000000026 :10CA10000000000000000000000000000000000016 :10CA20000000000000000000000000000000000006 :10CA300000000000000000000000000000000000F6 :10CA400000000000000000000000000000000000E6 :10CA500000000000000000000000000000000000D6 :10CA600000000000000000000000000000000000C6 :10CA700000000000000000000000000000000000B6 :10CA800000000000000000000000000000000000A6 :10CA90000000000000000000000000000000000096 :10CAA0000000000000000000000000000000000086 :10CAB0000000000000000000000000000000000076 :10CAC0000000000000000000000000000000000066 :10CAD0000000000000000000000000000000000056 :10CAE0000000000000000000000000000000000046 :10CAF0000000000000000000000000000000000036 :10CB00000000000000000000000000000000000025 :10CB10000000000000000000000000000000000015 :10CB20000000000000000000000000000000000005 :10CB300000000000000000000000000000000000F5 :10CB400000000000000000000000000000000000E5 :10CB500000000000000000000000000000000000D5 :10CB600000000000000000000000000000000000C5 :10CB700000000000000000000000000000000000B5 :10CB800000000000000000000000000000000000A5 :10CB90000000000000000000000000000000000095 :10CBA0000000000000000000000000000000000085 :10CBB0000000000000000000000000000000000075 :10CBC0000000000000000000000000000000000065 :10CBD0000000000000000000000000000000000055 :10CBE0000000000000000000000000000000000045 :10CBF0000000000000000000000000000000000035 :10CC00000000000000000000000000000000000024 :10CC10000000000000000000000000000000000014 :10CC20000000000000000000000000000000000004 :10CC300000000000000000000000000000000000F4 :10CC400000000000000000000000000000000000E4 :10CC500000000000000000000000000000000000D4 :10CC600000000000000000000000000000000000C4 :10CC700000000000000000000000000000000000B4 :10CC800000000000000000000000000000000000A4 :10CC90000000000000000000000000000000000094 :10CCA0000000000000000000000000000000000084 :10CCB0000000000000000000000000000000000074 :10CCC0000000000000000000000000000000000064 :10CCD0000000000000000000000000000000000054 :10CCE0000000000000000000000000000000000044 :10CCF0000000000000000000000000000000000034 :10CD00000000000000000000000000000000000023 :10CD10000000000000000000000000000000000013 :10CD20000000000000000000000000000000000003 :10CD300000000000000000000000000000000000F3 :10CD400000000000000000000000000000000000E3 :10CD500000000000000000000000000000000000D3 :10CD600000000000000000000000000000000000C3 :10CD700000000000000000000000000000000000B3 :10CD800000000000000000000000000000000000A3 :10CD90000000000000000000000000000000000093 :10CDA0000000000000000000000000000000000083 :10CDB0000000000000000000000000000000000073 :10CDC0000000000000000000000000000000000063 :10CDD0000000000000000000000000000000000053 :10CDE0000000000000000000000000000000000043 :10CDF0000000000000000000000000000000000033 :10CE00000000000000000000000000000000000022 :10CE10000000000000000000000000000000000012 :10CE20000000000000000000000000000000000002 :10CE300000000000000000000000000000000000F2 :10CE400000000000000000000000000000000000E2 :10CE500000000000000000000000000000000000D2 :10CE600000000000000000000000000000000000C2 :10CE700000000000000000000000000000000000B2 :10CE800000000000000000000000000000000000A2 :10CE90000000000000000000000000000000000092 :10CEA0000000000000000000000000000000000082 :10CEB0000000000000000000000000000000000072 :10CEC0000000000000000000000000000000000062 :10CED0000000000000000000000000000000000052 :10CEE0000000000000000000000000000000000042 :10CEF0000000000000000000000000000000000032 :10CF00000000000000000000000000000000000021 :10CF10000000000000000000000000000000000011 :10CF20000000000000000000000000000000000001 :10CF300000000000000000000000000000000000F1 :10CF400000000000000000000000000000000000E1 :10CF500000000000000000000000000000000000D1 :10CF600000000000000000000000000000000000C1 :10CF700000000000000000000000000000000000B1 :10CF800000000000000000000000000000000000A1 :10CF90000000000000000000000000000000000091 :10CFA0000000000000000000000000000000000081 :10CFB0000000000000000000000000000000000071 :10CFC0000000000000000000000000000000000061 :10CFD0000000000000000000000000000000000051 :10CFE0000000000000000000000000000000000041 :10CFF0000000000000000000000000000000000031 :10D000000000000000000000000000000000000020 :10D010000000000000000000000000000000000010 :10D020000000000000000000000000000000000000 :10D0300000000000000000000000000000000000F0 :10D0400000000000000000000000000000000000E0 :10D0500000000000000000000000000000000000D0 :10D0600000000000000000000000000000000000C0 :10D0700000000000000000000000000000000000B0 :10D0800000000000000000000000000000000000A0 :10D090000000000000000000000000000000000090 :10D0A0000000000000000000000000000000000080 :10D0B0000000000000000000000000000000000070 :10D0C0000000000000000000000000000000000060 :10D0D0000000000000000000000000000000000050 :10D0E0000000000000000000000000000000000040 :10D0F0000000000000000000000000000000000030 :10D10000000000000000000000000000000000001F :10D11000000000000000000000000000000000000F :10D1200000000000000000000000000000000000FF :10D1300000000000000000000000000000000000EF :10D1400000000000000000000000000000000000DF :10D1500000000000000000000000000000000000CF :10D1600000000000000000000000000000000000BF :10D1700000000000000000000000000000000000AF :10D18000000000000000000000000000000000009F :10D19000000000000000000000000000000000008F :10D1A000000000000000000000000000000000007F :10D1B000000000000000000000000000000000006F :10D1C000000000000000000000000000000000005F :10D1D000000000000000000000000000000000004F :10D1E000000000000000000000000000000000003F :10D1F000000000000000000000000000000000002F :10D20000000000000000000000000000000000001E :10D21000000000000000000000000000000000000E :10D2200000000000000000000000000000000000FE :10D2300000000000000000000000000000000000EE :10D2400000000000000000000000000000000000DE :10D2500000000000000000000000000000000000CE :10D2600000000000000000000000000000000000BE :10D2700000000000000000000000000000000000AE :10D28000000000000000000000000000000000009E :10D29000000000000000000000000000000000008E :10D2A000000000000000000000000000000000007E :10D2B000000000000000000000000000000000006E :10D2C000000000000000000000000000000000005E :10D2D000000000000000000000000000000000004E :10D2E000000000000000000000000000000000003E :10D2F000000000000000000000000000000000002E :10D30000000000000000000000000000000000001D :10D31000000000000000000000000000000000000D :10D3200000000000000000000000000000000000FD :10D3300000000000000000000000000000000000ED :10D3400000000000000000000000000000000000DD :10D3500000000000000000000000000000000000CD :10D3600000000000000000000000000000000000BD :10D3700000000000000000000000000000000000AD :10D38000000000000000000000000000000000009D :10D39000000000000000000000000000000000008D :10D3A000000000000000000000000000000000007D :10D3B000000000000000000000000000000000006D :10D3C000000000000000000000000000000000005D :10D3D000000000000000000000000000000000004D :10D3E000000000000000000000000000000000003D :10D3F000000000000000000000000000000000002D :10D40000000000000000000000000000000000001C :10D41000000000000000000000000000000000000C :10D4200000000000000000000000000000000000FC :10D4300000000000000000000000000000000000EC :10D4400000000000000000000000000000000000DC :10D4500000000000000000000000000000000000CC :10D4600000000000000000000000000000000000BC :10D4700000000000000000000000000000000000AC :10D48000000000000000000000000000000000009C :10D49000000000000000000000000000000000008C :10D4A000000000000000000000000000000000007C :10D4B000000000000000000000000000000000006C :10D4C000000000000000000000000000000000005C :10D4D000000000000000000000000000000000004C :10D4E000000000000000000000000000000000003C :10D4F000000000000000000000000000000000002C :10D50000000000000000000000000000000000001B :10D51000000000000000000000000000000000000B :10D5200000000000000000000000000000000000FB :10D5300000000000000000000000000000000000EB :10D5400000000000000000000000000000000000DB :10D5500000000000000000000000000000000000CB :10D5600000000000000000000000000000000000BB :10D5700000000000000000000000000000000000AB :10D58000000000000000000000000000000000009B :10D59000000000000000000000000000000000008B :10D5A000000000000000000000000000000000007B :10D5B000000000000000000000000000000000006B :10D5C000000000000000000000000000000000005B :10D5D000000000000000000000000000000000004B :10D5E000000000000000000000000000000000003B :10D5F000000000000000000000000000000000002B :10D60000000000000000000000000000000000001A :10D61000000000000000000000000000000000000A :10D6200000000000000000000000000000000000FA :10D6300000000000000000000000000000000000EA :10D6400000000000000000000000000000000000DA :10D6500000000000000000000000000000000000CA :10D6600000000000000000000000000000000000BA :10D6700000000000000000000000000000000000AA :10D68000000000000000000000000000000000009A :10D69000000000000000000000000000000000008A :10D6A000000000000000000000000000000000007A :10D6B000000000000000000000000000000000006A :10D6C000000000000000000000000000000000005A :10D6D000000000000000000000000000000000004A :10D6E000000000000000000000000000000000003A :10D6F000000000000000000000000000000000002A :10D700000000000000000000000000000000000019 :10D710000000000000000000000000000000000009 :10D7200000000000000000000000000000000000F9 :10D7300000000000000000000000000000000000E9 :10D7400000000000000000000000000000000000D9 :10D7500000000000000000000000000000000000C9 :10D7600000000000000000000000000000000000B9 :10D7700000000000000000000000000000000000A9 :10D780000000000000000000000000000000000099 :10D790000000000000000000000000000000000089 :10D7A0000000000000000000000000000000000079 :10D7B0000000000000000000000000000000000069 :10D7C0000000000000000000000000000000000059 :10D7D0000000000000000000000000000000000049 :10D7E0000000000000000000000000000000000039 :10D7F0000000000000000000000000000000000029 :10D800000000000000000000000000000000000018 :10D810000000000000000000000000000000000008 :10D8200000000000000000000000000000000000F8 :10D8300000000000000000000000000000000000E8 :10D8400000000000000000000000000000000000D8 :10D8500000000000000000000000000000000000C8 :10D8600000000000000000000000000000000000B8 :10D8700000000000000000000000000000000000A8 :10D880000000000000000000000000000000000098 :10D890000000000000000000000000000000000088 :10D8A0000000000000000000000000000000000078 :10D8B0000000000000000000000000000000000068 :10D8C0000000000000000000000000000000000058 :10D8D0000000000000000000000000000000000048 :10D8E0000000000000000000000000000000000038 :10D8F0000000000000000000000000000000000028 :10D900000000000000000000000000000000000017 :10D910000000000000000000000000000000000007 :10D9200000000000000000000000000000000000F7 :10D9300000000000000000000000000000000000E7 :10D9400000000000000000000000000000000000D7 :10D9500000000000000000000000000000000000C7 :10D9600000000000000000000000000000000000B7 :10D9700000000000000000000000000000000000A7 :10D980000000000000000000000000000000000097 :10D990000000000000000000000000000000000087 :10D9A0000000000000000000000000000000000077 :10D9B0000000000000000000000000000000000067 :10D9C0000000000000000000000000000000000057 :10D9D0000000000000000000000000000000000047 :10D9E0000000000000000000000000000000000037 :10D9F0000000000000000000000000000000000027 :10DA00000000000000000000000000000000000016 :10DA10000000000000000000000000000000000006 :10DA200000000000000000000000000000000000F6 :10DA300000000000000000000000000000000000E6 :10DA400000000000000000000000000000000000D6 :10DA500000000000000000000000000000000000C6 :10DA600000000000000000000000000000000000B6 :10DA700000000000000000000000000000000000A6 :10DA80000000000000000000000000000000000096 :10DA90000000000000000000000000000000000086 :10DAA0000000000000000000000000000000000076 :10DAB0000000000000000000000000000000000066 :10DAC0000000000000000000000000000000000056 :10DAD0000000000000000000000000000000000046 :10DAE0000000000000000000000000000000000036 :10DAF0000000000000000000000000000000000026 :10DB00000000000000000000000000000000000015 :10DB10000000000000000000000000000000000005 :10DB200000000000000000000000000000000000F5 :10DB300000000000000000000000000000000000E5 :10DB400000000000000000000000000000000000D5 :10DB500000000000000000000000000000000000C5 :10DB600000000000000000000000000000000000B5 :10DB700000000000000000000000000000000000A5 :10DB80000000000000000000000000000000000095 :10DB90000000000000000000000000000000000085 :10DBA0000000000000000000000000000000000075 :10DBB0000000000000000000000000000000000065 :10DBC0000000000000000000000000000000000055 :10DBD0000000000000000000000000000000000045 :10DBE0000000000000000000000000000000000035 :10DBF0000000000000000000000000000000000025 :10DC00000000000000000000000000000000000014 :10DC10000000000000000000000000000000000004 :10DC200000000000000000000000000000000000F4 :10DC300000000000000000000000000000000000E4 :10DC400000000000000000000000000000000000D4 :10DC500000000000000000000000000000000000C4 :10DC600000000000000000000000000000000000B4 :10DC700000000000000000000000000000000000A4 :10DC80000000000000000000000000000000000094 :10DC90000000000000000000000000000000000084 :10DCA0000000000000000000000000000000000074 :10DCB0000000000000000000000000000000000064 :10DCC0000000000000000000000000000000000054 :10DCD0000000000000000000000000000000000044 :10DCE0000000000000000000000000000000000034 :10DCF0000000000000000000000000000000000024 :10DD00000000000000000000000000000000000013 :10DD10000000000000000000000000000000000003 :10DD200000000000000000000000000000000000F3 :10DD300000000000000000000000000000000000E3 :10DD400000000000000000000000000000000000D3 :10DD500000000000000000000000000000000000C3 :10DD600000000000000000000000000000000000B3 :10DD700000000000000000000000000000000000A3 :10DD80000000000000000000000000000000000093 :10DD90000000000000000000000000000000000083 :10DDA0000000000000000000000000000000000073 :10DDB0000000000000000000000000000000000063 :10DDC0000000000000000000000000000000000053 :10DDD0000000000000000000000000000000000043 :10DDE0000000000000000000000000000000000033 :10DDF0000000000000000000000000000000000023 :10DE00000000000000000000000000000000000012 :10DE10000000000000000000000000000000000002 :10DE200000000000000000000000000000000000F2 :10DE300000000000000000000000000000000000E2 :10DE400000000000000000000000000000000000D2 :10DE500000000000000000000000000000000000C2 :10DE600000000000000000000000000000000000B2 :10DE700000000000000000000000000000000000A2 :10DE80000000000000000000000000000000000092 :10DE90000000000000000000000000000000000082 :10DEA0000000000000000000000000000000000072 :10DEB0000000000000000000000000000000000062 :10DEC0000000000000000000000000000000000052 :10DED0000000000000000000000000000000000042 :10DEE0000000000000000000000000000000000032 :10DEF0000000000000000000000000000000000022 :10DF00000000000000000000000000000000000011 :10DF10000000000000000000000000000000000001 :10DF200000000000000000000000000000000000F1 :10DF300000000000000000000000000000000000E1 :10DF400000000000000000000000000000000000D1 :10DF500000000000000000000000000000000000C1 :10DF600000000000000000000000000000000000B1 :10DF700000000000000000000000000000000000A1 :10DF80000000000000000000000000000000000091 :10DF90000000000000000000000000000000000081 :10DFA0000000000000000000000000000000000071 :10DFB0000000000000000000000000000000000061 :10DFC0000000000000000000000000000000000051 :10DFD0000000000000000000000000000000000041 :10DFE0000000000000000000000000000000000031 :10DFF0000000000000000000000000000000000021 :10E000000000000000000000000000000000000010 :10E010000000000000000000000000000000000000 :10E0200000000000000000000000000000000000F0 :10E0300000000000000000000000000000000000E0 :10E0400000000000000000000000000000000000D0 :10E0500000000000000000000000000000000000C0 :10E0600000000000000000000000000000000000B0 :10E0700000000000000000000000000000000000A0 :10E080000000000000000000000000000000000090 :10E090000000000000000000000000000000000080 :10E0A0000000000000000000000000000000000070 :10E0B0000000000000000000000000000000000060 :10E0C0000000000000000000000000000000000050 :10E0D0000000000000000000000000000000000040 :10E0E0000000000000000000000000000000000030 :10E0F0000000000000000000000000000000000020 :10E10000000000000000000000000000000000000F :10E1100000000000000000000000000000000000FF :10E1200000000000000000000000000000000000EF :10E1300000000000000000000000000000000000DF :10E1400000000000000000000000000000000000CF :10E1500000000000000000000000000000000000BF :10E1600000000000000000000000000000000000AF :10E17000000000000000000000000000000000009F :10E18000000000000000000000000000000000008F :10E19000000000000000000000000000000000007F :10E1A000000000000000000000000000000000006F :10E1B000000000000000000000000000000000005F :10E1C000000000000000000000000000000000004F :10E1D000000000000000000000000000000000003F :10E1E000000000000000000000000000000000002F :10E1F000000000000000000000000000000000001F :10E20000000000000000000000000000000000000E :10E2100000000000000000000000000000000000FE :10E2200000000000000000000000000000000000EE :10E2300000000000000000000000000000000000DE :10E2400000000000000000000000000000000000CE :10E2500000000000000000000000000000000000BE :10E2600000000000000000000000000000000000AE :10E27000000000000000000000000000000000009E :10E28000000000000000000000000000000000008E :10E29000000000000000000000000000000000007E :10E2A000000000000000000000000000000000006E :10E2B000000000000000000000000000000000005E :10E2C000000000000000000000000000000000004E :10E2D000000000000000000000000000000000003E :10E2E000000000000000000000000000000000002E :10E2F000000000000000000000000000000000001E :10E30000000000000000000000000000000000000D :10E3100000000000000000000000000000000000FD :10E3200000000000000000000000000000000000ED :10E3300000000000000000000000000000000000DD :10E3400000000000000000000000000000000000CD :10E3500000000000000000000000000000000000BD :10E3600000000000000000000000000000000000AD :10E37000000000000000000000000000000000009D :10E38000000000000000000000000000000000008D :10E39000000000000000000000000000000000007D :10E3A000000000000000000000000000000000006D :10E3B000000000000000000000000000000000005D :10E3C000000000000000000000000000000000004D :10E3D000000000000000000000000000000000003D :10E3E000000000000000000000000000000000002D :10E3F000000000000000000000000000000000001D :10E40000000000000000000000000000000000000C :10E4100000000000000000000000000000000000FC :10E4200000000000000000000000000000000000EC :10E4300000000000000000000000000000000000DC :10E4400000000000000000000000000000000000CC :10E4500000000000000000000000000000000000BC :10E4600000000000000000000000000000000000AC :10E47000000000000000000000000000000000009C :10E48000000000000000000000000000000000008C :10E49000000000000000000000000000000000007C :10E4A000000000000000000000000000000000006C :10E4B000000000000000000000000000000000005C :10E4C000000000000000000000000000000000004C :10E4D000000000000000000000000000000000003C :10E4E000000000000000000000000000000000002C :10E4F000000000000000000000000000000000001C :10E50000000000000000000000000000000000000B :10E5100000000000000000000000000000000000FB :10E5200000000000000000000000000000000000EB :10E5300000000000000000000000000000000000DB :10E5400000000000000000000000000000000000CB :10E5500000000000000000000000000000000000BB :10E5600000000000000000000000000000000000AB :10E57000000000000000000000000000000000009B :10E58000000000000000000000000000000000008B :10E59000000000000000000000000000000000007B :10E5A000000000000000000000000000000000006B :10E5B000000000000000000000000000000000005B :10E5C000000000000000000000000000000000004B :10E5D000000000000000000000000000000000003B :10E5E000000000000000000000000000000000002B :10E5F000000000000000000000000000000000001B :10E60000000000000000000000000000000000000A :10E6100000000000000000000000000000000000FA :10E6200000000000000000000000000000000000EA :10E6300000000000000000000000000000000000DA :10E6400000000000000000000000000000000000CA :10E6500000000000000000000000000000000000BA :10E6600000000000000000000000000000000000AA :10E67000000000000000000000000000000000009A :10E68000000000000000000000000000000000008A :10E69000000000000000000000000000000000007A :10E6A000000000000000000000000000000000006A :10E6B000000000000000000000000000000000005A :10E6C000000000000000000000000000000000004A :10E6D000000000000000000000000000000000003A :10E6E000000000000000000000000000000000002A :10E6F000000000000000000000000000000000001A :10E700000000000000000000000000000000000009 :10E7100000000000000000000000000000000000F9 :10E7200000000000000000000000000000000000E9 :10E7300000000000000000000000000000000000D9 :10E7400000000000000000000000000000000000C9 :10E7500000000000000000000000000000000000B9 :10E7600000000000000000000000000000000000A9 :10E770000000000000000000000000000000000099 :10E780000000000000000000000000000000000089 :10E790000000000000000000000000000000000079 :10E7A0000000000000000000000000000000000069 :10E7B0000000000000000000000000000000000059 :10E7C0000000000000000000000000000000000049 :10E7D0000000000000000000000000000000000039 :10E7E0000000000000000000000000000000000029 :10E7F0000000000000000000000000000000000019 :10E800000000000000000000000000000000000008 :10E8100000000000000000000000000000000000F8 :10E8200000000000000000000000000000000000E8 :10E8300000000000000000000000000000000000D8 :10E8400000000000000000000000000000000000C8 :10E8500000000000000000000000000000000000B8 :10E8600000000000000000000000000000000000A8 :10E870000000000000000000000000000000000098 :10E880000000000000000000000000000000000088 :10E890000000000000000000000000000000000078 :10E8A0000000000000000000000000000000000068 :10E8B0000000000000000000000000000000000058 :10E8C0000000000000000000000000000000000048 :10E8D0000000000000000000000000000000000038 :10E8E0000000000000000000000000000000000028 :10E8F0000000000000000000000000000000000018 :10E900000000000000000000000000000000000007 :10E9100000000000000000000000000000000000F7 :10E9200000000000000000000000000000000000E7 :10E9300000000000000000000000000000000000D7 :10E9400000000000000000000000000000000000C7 :10E9500000000000000000000000000000000000B7 :10E9600000000000000000000000000000000000A7 :10E970000000000000000000000000000000000097 :10E980000000000000000000000000000000000087 :10E990000000000000000000000000000000000077 :10E9A0000000000000000000000000000000000067 :10E9B0000000000000000000000000000000000057 :10E9C0000000000000000000000000000000000047 :10E9D0000000000000000000000000000000000037 :10E9E0000000000000000000000000000000000027 :10E9F0000000000000000000000000000000000017 :10EA00000000000000000000000000000000000006 :10EA100000000000000000000000000000000000F6 :10EA200000000000000000000000000000000000E6 :10EA300000000000000000000000000000000000D6 :10EA400000000000000000000000000000000000C6 :10EA500000000000000000000000000000000000B6 :10EA600000000000000000000000000000000000A6 :10EA70000000000000000000000000000000000096 :10EA80000000000000000000000000000000000086 :10EA90000000000000000000000000000000000076 :10EAA0000000000000000000000000000000000066 :10EAB0000000000000000000000000000000000056 :10EAC0000000000000000000000000000000000046 :10EAD0000000000000000000000000000000000036 :10EAE0000000000000000000000000000000000026 :10EAF0000000000000000000000000000000000016 :10EB00000000000000000000000000000000000005 :10EB100000000000000000000000000000000000F5 :10EB200000000000000000000000000000000000E5 :10EB300000000000000000000000000000000000D5 :10EB400000000000000000000000000000000000C5 :10EB500000000000000000000000000000000000B5 :10EB600000000000000000000000000000000000A5 :10EB70000000000000000000000000000000000095 :10EB80000000000000000000000000000000000085 :10EB90000000000000000000000000000000000075 :10EBA0000000000000000000000000000000000065 :10EBB0000000000000000000000000000000000055 :10EBC0000000000000000000000000000000000045 :10EBD0000000000000000000000000000000000035 :10EBE0000000000000000000000000000000000025 :10EBF0000000000000000000000000000000000015 :10EC00000000000000000000000000000000000004 :10EC100000000000000000000000000000000000F4 :10EC200000000000000000000000000000000000E4 :10EC300000000000000000000000000000000000D4 :10EC400000000000000000000000000000000000C4 :10EC500000000000000000000000000000000000B4 :10EC600000000000000000000000000000000000A4 :10EC70000000000000000000000000000000000094 :10EC80000000000000000000000000000000000084 :10EC90000000000000000000000000000000000074 :10ECA0000000000000000000000000000000000064 :10ECB0000000000000000000000000000000000054 :10ECC0000000000000000000000000000000000044 :10ECD0000000000000000000000000000000000034 :10ECE0000000000000000000000000000000000024 :10ECF0000000000000000000000000000000000014 :10ED00000000000000000000000000000000000003 :10ED100000000000000000000000000000000000F3 :10ED200000000000000000000000000000000000E3 :10ED300000000000000000000000000000000000D3 :10ED400000000000000000000000000000000000C3 :10ED500000000000000000000000000000000000B3 :10ED600000000000000000000000000000000000A3 :10ED70000000000000000000000000000000000093 :10ED80000000000000000000000000000000000083 :10ED90000000000000000000000000000000000073 :10EDA0000000000000000000000000000000000063 :10EDB0000000000000000000000000000000000053 :10EDC0000000000000000000000000000000000043 :10EDD0000000000000000000000000000000000033 :10EDE0000000000000000000000000000000000023 :10EDF0000000000000000000000000000000000013 :10EE00000000000000000000000000000000000002 :10EE100000000000000000000000000000000000F2 :10EE200000000000000000000000000000000000E2 :10EE300000000000000000000000000000000000D2 :10EE400000000000000000000000000000000000C2 :10EE500000000000000000000000000000000000B2 :10EE600000000000000000000000000000000000A2 :10EE70000000000000000000000000000000000092 :10EE80000000000000000000000000000000000082 :10EE90000000000000000000000000000000000072 :10EEA0000000000000000000000000000000000062 :10EEB0000000000000000000000000000000000052 :10EEC0000000000000000000000000000000000042 :10EED0000000000000000000000000000000000032 :10EEE0000000000000000000000000000000000022 :10EEF0000000000000000000000000000000000012 :10EF00000000000000000000000000000000000001 :10EF100000000000000000000000000000000000F1 :10EF200000000000000000000000000000000000E1 :10EF300000000000000000000000000000000000D1 :10EF400000000000000000000000000000000000C1 :10EF500000000000000000000000000000000000B1 :10EF600000000000000000000000000000000000A1 :10EF70000000000000000000000000000000000091 :10EF80000000000000000000000000000000000081 :10EF90000000000000000000000000000000000071 :10EFA0000000000000000000000000000000000061 :10EFB0000000000000000000000000000000000051 :10EFC0000000000000000000000000000000000041 :10EFD0000000000000000000000000000000000031 :10EFE0000000000000000000000000000000000021 :10EFF0000000000000000000000000000000000011 :10F000000000000000000000000000000000000000 :10F0100000000000000000000000000000000000F0 :10F0200000000000000000000000000000000000E0 :10F0300000000000000000000000000000000000D0 :10F0400000000000000000000000000000000000C0 :10F0500000000000000000000000000000000000B0 :10F0600000000000000000000000000000000000A0 :10F070000000000000000000000000000000000090 :10F080000000000000000000000000000000000080 :10F090000000000000000000000000000000000070 :10F0A0000000000000000000000000000000000060 :10F0B0000000000000000000000000000000000050 :10F0C0000000000000000000000000000000000040 :10F0D0000000000000000000000000000000000030 :10F0E0000000000000000000000000000000000020 :10F0F0000000000000000000000000000000000010 :10F1000000000000000000000000000000000000FF :10F1100000000000000000000000000000000000EF :10F1200000000000000000000000000000000000DF :10F1300000000000000000000000000000000000CF :10F1400000000000000000000000000000000000BF :10F1500000000000000000000000000000000000AF :10F16000000000000000000000000000000000009F :10F17000000000000000000000000000000000008F :10F18000000000000000000000000000000000007F :10F19000000000000000000000000000000000006F :10F1A000000000000000000000000000000000005F :10F1B000000000000000000000000000000000004F :10F1C000000000000000000000000000000000003F :10F1D000000000000000000000000000000000002F :10F1E000000000000000000000000000000000001F :10F1F000000000000000000000000000000000000F :10F2000000000000000000000000000000000000FE :10F2100000000000000000000000000000000000EE :10F2200000000000000000000000000000000000DE :10F2300000000000000000000000000000000000CE :10F2400000000000000000000000000000000000BE :10F2500000000000000000000000000000000000AE :10F26000000000000000000000000000000000009E :10F27000000000000000000000000000000000008E :10F28000000000000000000000000000000000007E :10F29000000000000000000000000000000000006E :10F2A000000000000000000000000000000000005E :10F2B000000000000000000000000000000000004E :10F2C000000000000000000000000000000000003E :10F2D000000000000000000000000000000000002E :10F2E000000000000000000000000000000000001E :10F2F000000000000000000000000000000000000E :10F3000000000000000000000000000000000000FD :10F3100000000000000000000000000000000000ED :10F3200000000000000000000000000000000000DD :10F3300000000000000000000000000000000000CD :10F3400000000000000000000000000000000000BD :10F3500000000000000000000000000000000000AD :10F36000000000000000000000000000000000009D :10F37000000000000000000000000000000000008D :10F38000000000000000000000000000000000007D :10F39000000000000000000000000000000000006D :10F3A000000000000000000000000000000000005D :10F3B000000000000000000000000000000000004D :10F3C000000000000000000000000000000000003D :10F3D000000000000000000000000000000000002D :10F3E000000000000000000000000000000000001D :10F3F000000000000000000000000000000000000D :10F4000000000000000000000000000000000000FC :10F4100000000000000000000000000000000000EC :10F4200000000000000000000000000000000000DC :10F4300000000000000000000000000000000000CC :10F4400000000000000000000000000000000000BC :10F4500000000000000000000000000000000000AC :10F46000000000000000000000000000000000009C :10F47000000000000000000000000000000000008C :10F48000000000000000000000000000000000007C :10F49000000000000000000000000000000000006C :10F4A000000000000000000000000000000000005C :10F4B000000000000000000000000000000000004C :10F4C000000000000000000000000000000000003C :10F4D000000000000000000000000000000000002C :10F4E000000000000000000000000000000000001C :10F4F000000000000000000000000000000000000C :10F5000000000000000000000000000000000000FB :10F5100000000000000000000000000000000000EB :10F5200000000000000000000000000000000000DB :10F5300000000000000000000000000000000000CB :10F5400000000000000000000000000000000000BB :10F5500000000000000000000000000000000000AB :10F56000000000000000000000000000000000009B :10F57000000000000000000000000000000000008B :10F58000000000000000000000000000000000007B :10F59000000000000000000000000000000000006B :10F5A000000000000000000000000000000000005B :10F5B000000000000000000000000000000000004B :10F5C000000000000000000000000000000000003B :10F5D000000000000000000000000000000000002B :10F5E000000000000000000000000000000000001B :10F5F000000000000000000000000000000000000B :10F6000000000000000000000000000000000000FA :10F6100000000000000000000000000000000000EA :10F6200000000000000000000000000000000000DA :10F6300000000000000000000000000000000000CA :10F6400000000000000000000000000000000000BA :10F6500000000000000000000000000000000000AA :10F66000000000000000000000000000000000009A :10F67000000000000000000000000000000000008A :10F68000000000000000000000000000000000007A :10F69000000000000000000000000000000000006A :10F6A000000000000000000000000000000000005A :10F6B000000000000000000000000000000000004A :10F6C000000000000000000000000000000000003A :10F6D000000000000000000000000000000000002A :10F6E000000000000000000000000000000000001A :10F6F000000000000000000000000000000000000A :10F7000000000000000000000000000000000000F9 :10F7100000000000000000000000000000000000E9 :10F7200000000000000000000000000000000000D9 :10F7300000000000000000000000000000000000C9 :10F7400000000000000000000000000000000000B9 :10F7500000000000000000000000000000000000A9 :10F760000000000000000000000000000000000099 :10F770000000000000000000000000000000000089 :10F780000000000000000000000000000000000079 :10F790000000000000000000000000000000000069 :10F7A0000000000000000000000000000000000059 :10F7B0000000000000000000000000000000000049 :10F7C0000000000000000000000000000000000039 :10F7D0000000000000000000000000000000000029 :10F7E0000000000000000000000000000000000019 :10F7F0000000000000000000000000000000000009 :10F8000000000000000000000000000000000000F8 :10F8100000000000000000000000000000000000E8 :10F8200000000000000000000000000000000000D8 :10F8300000000000000000000000000000000000C8 :10F8400000000000000000000000000000000000B8 :10F8500000000000000000000000000000000000A8 :10F860000000000000000000000000000000000098 :10F870000000000000000000000000000000000088 :10F880000000000000000000000000000000000078 :10F890000000000000000000000000000000000068 :10F8A0000000000000000000000000000000000058 :10F8B0000000000000000000000000000000000048 :10F8C0000000000000000000000000000000000038 :10F8D0000000000000000000000000000000000028 :10F8E0000000000000000000000000000000000018 :10F8F0000000000000000000000000000000000008 :10F9000000000000000000000000000000000000F7 :10F9100000000000000000000000000000000000E7 :10F9200000000000000000000000000000000000D7 :10F9300000000000000000000000000000000000C7 :10F9400000000000000000000000000000000000B7 :10F9500000000000000000000000000000000000A7 :10F960000000000000000000000000000000000097 :10F970000000000000000000000000000000000087 :10F980000000000000000000000000000000000077 :10F990000000000000000000000000000000000067 :10F9A0000000000000000000000000000000000057 :10F9B0000000000000000000000000000000000047 :10F9C0000000000000000000000000000000000037 :10F9D0000000000000000000000000000000000027 :10F9E0000000000000000000000000000000000017 :10F9F0000000000000000000000000000000000007 :10FA000000000000000000000000000000000000F6 :10FA100000000000000000000000000000000000E6 :10FA200000000000000000000000000000000000D6 :10FA300000000000000000000000000000000000C6 :10FA400000000000000000000000000000000000B6 :10FA500000000000000000000000000000000000A6 :10FA60000000000000000000000000000000000096 :10FA70000000000000000000000000000000000086 :10FA80000000000000000000000000000000000076 :10FA90000000000000000000000000000000000066 :10FAA0000000000000000000000000000000000056 :10FAB0000000000000000000000000000000000046 :10FAC0000000000000000000000000000000000036 :10FAD0000000000000000000000000000000000026 :10FAE0000000000000000000000000000000000016 :10FAF0000000000000000000000000000000000006 :10FB000000000000000000000000000000000000F5 :10FB100000000000000000000000000000000000E5 :10FB200000000000000000000000000000000000D5 :10FB300000000000000000000000000000000000C5 :10FB400000000000000000000000000000000000B5 :10FB500000000000000000000000000000000000A5 :10FB60000000000000000000000000000000000095 :10FB70000000000000000000000000000000000085 :10FB80000000000000000000000000000000000075 :10FB90000000000000000000000000000000000065 :10FBA0000000000000000000000000000000000055 :10FBB0000000000000000000000000000000000045 :10FBC0000000000000000000000000000000000035 :10FBD0000000000000000000000000000000000025 :10FBE0000000000000000000000000000000000015 :10FBF0000000000000000000000000000000000005 :10FC000000000000000000000000000000000000F4 :10FC100000000000000000000000000000000000E4 :10FC200000000000000000000000000000000000D4 :10FC300000000000000000000000000000000000C4 :10FC400000000000000000000000000000000000B4 :10FC500000000000000000000000000000000000A4 :10FC60000000000000000000000000000000000094 :10FC70000000000000000000000000000000000084 :10FC80000000000000000000000000000000000074 :10FC90000000000000000000000000000000000064 :10FCA0000000000000000000000000000000000054 :10FCB0000000000000000000000000000000000044 :10FCC0000000000000000000000000000000000034 :10FCD0000000000000000000000000000000000024 :10FCE0000000000000000000000000000000000014 :10FCF0000000000000000000000000000000000004 :10FD000000000000000000000000000000000000F3 :10FD100000000000000000000000000000000000E3 :10FD200000000000000000000000000000000000D3 :10FD300000000000000000000000000000000000C3 :10FD400000000000000000000000000000000000B3 :10FD500000000000000000000000000000000000A3 :10FD60000000000000000000000000000000000093 :10FD70000000000000000000000000000000000083 :10FD80000000000000000000000000000000000073 :10FD90000000000000000000000000000000000063 :10FDA0000000000000000000000000000000000053 :10FDB0000000000000000000000000000000000043 :10FDC0000000000000000000000000000000000033 :10FDD0000000000000000000000000000000000023 :10FDE0000000000000000000000000000000000013 :10FDF0000000000000000000000000000000000003 :10FE000000000000000000000000000000000000F2 :10FE100000000000000000000000000000000000E2 :10FE200000000000000000000000000000000000D2 :10FE300000000000000000000000000000000000C2 :10FE400000000000000000000000000000000000B2 :10FE500000000000000000000000000000000000A2 :10FE60000000000000000000000000000000000092 :10FE70000000000000000000000000000000000082 :10FE80000000000000000000000000000000000072 :10FE90000000000000000000000000000000000062 :10FEA0000000000000000000000000000000000052 :10FEB0000000000000000000000000000000000042 :10FEC0000000000000000000000000000000000032 :10FED0000000000000000000000000000000000022 :10FEE0000000000000000000000000000000000012 :10FEF0000000000000000000000000000000000002 :10FF000000000000000000000000000000000000F1 :10FF100000000000000000000000000000000000E1 :10FF200000000000000000000000000000000000D1 :10FF300000000000000000000000000000000000C1 :10FF400000000000000000000000000000000000B1 :10FF500000000000000000000000000000000000A1 :10FF60000000000000000000000000000000000091 :10FF70000000000000000000000000000000000081 :10FF80000000000000000000000000000000000071 :10FF90000000000000000000000000000000000061 :10FFA0000000000000000000000000000000000051 :10FFB0000000000000000000000000000000000041 :10FFC0000000000000000000000000000000000031 :10FFD0000000000000000000000000000000000021 :10FFE0000000000000000000000000000000000011 :10FFF0000000000000000000000000000000000001 :02000004620593 :1000000000000000000000000000000000000000F0 :1000100000000000000000000000000000000000E0 :1000200000000000000000000000000000000000D0 :1000300000000000000000000000000000000000C0 :1000400000000000000000000000000000000000B0 :1000500000000000000000000000000000000000A0 :100060000000000000000000000000000000000090 :100070000000000000000000000000000000000080 :100080000000000000000000000000000000000070 :100090000000000000000000000000000000000060 :1000A0000000000000000000000000000000000050 :1000B0000000000000000000000000000000000040 :1000C0000000000000000000000000000000000030 :1000D0000000000000000000000000000000000020 :1000E0000000000000000000000000000000000010 :1000F0000000000000000000000000000000000000 :1001000000000000000000000000000000000000EF :1001100000000000000000000000000000000000DF :1001200000000000000000000000000000000000CF :1001300000000000000000000000000000000000BF :1001400000000000000000000000000000000000AF :10015000000000000000000000000000000000009F :10016000000000000000000000000000000000008F :10017000000000000000000000000000000000007F :10018000000000000000000000000000000000006F :10019000000000000000000000000000000000005F :1001A000000000000000000000000000000000004F :1001B000000000000000000000000000000000003F :1001C000000000000000000000000000000000002F :1001D000000000000000000000000000000000001F :1001E000000000000000000000000000000000000F :1001F00000000000000000000000000000000000FF :1002000000000000000000000000000000000000EE :1002100000000000000000000000000000000000DE :1002200000000000000000000000000000000000CE :1002300000000000000000000000000000000000BE :1002400000000000000000000000000000000000AE :10025000000000000000000000000000000000009E :10026000000000000000000000000000000000008E :10027000000000000000000000000000000000007E :10028000000000000000000000000000000000006E :10029000000000000000000000000000000000005E :1002A000000000000000000000000000000000004E :1002B000000000000000000000000000000000003E :1002C000000000000000000000000000000000002E :1002D000000000000000000000000000000000001E :1002E000000000000000000000000000000000000E :1002F00000000000000000000000000000000000FE :1003000000000000000000000000000000000000ED :1003100000000000000000000000000000000000DD :1003200000000000000000000000000000000000CD :1003300000000000000000000000000000000000BD :1003400000000000000000000000000000000000AD :10035000000000000000000000000000000000009D :10036000000000000000000000000000000000008D :10037000000000000000000000000000000000007D :10038000000000000000000000000000000000006D :10039000000000000000000000000000000000005D :1003A000000000000000000000000000000000004D :1003B000000000000000000000000000000000003D :1003C000000000000000000000000000000000002D :1003D000000000000000000000000000000000001D :1003E000000000000000000000000000000000000D :1003F00000000000000000000000000000000000FD :1004000000000000000000000000000000000000EC :1004100000000000000000000000000000000000DC :1004200000000000000000000000000000000000CC :1004300000000000000000000000000000000000BC :1004400000000000000000000000000000000000AC :10045000000000000000000000000000000000009C :10046000000000000000000000000000000000008C :10047000000000000000000000000000000000007C :10048000000000000000000000000000000000006C :10049000000000000000000000000000000000005C :1004A000000000000000000000000000000000004C :1004B000000000000000000000000000000000003C :1004C000000000000000000000000000000000002C :1004D000000000000000000000000000000000001C :1004E000000000000000000000000000000000000C :1004F00000000000000000000000000000000000FC :1005000000000000000000000000000000000000EB :1005100000000000000000000000000000000000DB :1005200000000000000000000000000000000000CB :1005300000000000000000000000000000000000BB :1005400000000000000000000000000000000000AB :10055000000000000000000000000000000000009B :10056000000000000000000000000000000000008B :10057000000000000000000000000000000000007B :10058000000000000000000000000000000000006B :10059000000000000000000000000000000000005B :1005A000000000000000000000000000000000004B :1005B000000000000000000000000000000000003B :1005C000000000000000000000000000000000002B :1005D000000000000000000000000000000000001B :1005E000000000000000000000000000000000000B :1005F00000000000000000000000000000000000FB :1006000000000000000000000000000000000000EA :1006100000000000000000000000000000000000DA :1006200000000000000000000000000000000000CA :1006300000000000000000000000000000000000BA :1006400000000000000000000000000000000000AA :10065000000000000000000000000000000000009A :10066000000000000000000000000000000000008A :10067000000000000000000000000000000000007A :10068000000000000000000000000000000000006A :10069000000000000000000000000000000000005A :1006A000000000000000000000000000000000004A :1006B000000000000000000000000000000000003A :1006C000000000000000000000000000000000002A :1006D000000000000000000000000000000000001A :1006E000000000000000000000000000000000000A :1006F00000000000000000000000000000000000FA :1007000000000000000000000000000000000000E9 :1007100000000000000000000000000000000000D9 :1007200000000000000000000000000000000000C9 :1007300000000000000000000000000000000000B9 :1007400000000000000000000000000000000000A9 :100750000000000000000000000000000000000099 :100760000000000000000000000000000000000089 :100770000000000000000000000000000000000079 :100780000000000000000000000000000000000069 :100790000000000000000000000000000000000059 :1007A0000000000000000000000000000000000049 :1007B0000000000000000000000000000000000039 :1007C0000000000000000000000000000000000029 :1007D0000000000000000000000000000000000019 :1007E0000000000000000000000000000000000009 :1007F00000000000000000000000000000000000F9 :1008000000000000000000000000000000000000E8 :1008100000000000000000000000000000000000D8 :1008200000000000000000000000000000000000C8 :1008300000000000000000000000000000000000B8 :1008400000000000000000000000000000000000A8 :100850000000000000000000000000000000000098 :100860000000000000000000000000000000000088 :100870000000000000000000000000000000000078 :100880000000000000000000000000000000000068 :100890000000000000000000000000000000000058 :1008A0000000000000000000000000000000000048 :1008B0000000000000000000000000000000000038 :1008C0000000000000000000000000000000000028 :1008D0000000000000000000000000000000000018 :1008E0000000000000000000000000000000000008 :1008F00000000000000000000000000000000000F8 :1009000000000000000000000000000000000000E7 :1009100000000000000000000000000000000000D7 :1009200000000000000000000000000000000000C7 :1009300000000000000000000000000000000000B7 :1009400000000000000000000000000000000000A7 :100950000000000000000000000000000000000097 :100960000000000000000000000000000000000087 :100970000000000000000000000000000000000077 :100980000000000000000000000000000000000067 :100990000000000000000000000000000000000057 :1009A0000000000000000000000000000000000047 :1009B0000000000000000000000000000000000037 :1009C0000000000000000000000000000000000027 :1009D0000000000000000000000000000000000017 :1009E0000000000000000000000000000000000007 :1009F00000000000000000000000000000000000F7 :100A000000000000000000000000000000000000E6 :100A100000000000000000000000000000000000D6 :100A200000000000000000000000000000000000C6 :100A300000000000000000000000000000000000B6 :100A400000000000000000000000000000000000A6 :100A50000000000000000000000000000000000096 :100A60000000000000000000000000000000000086 :100A70000000000000000000000000000000000076 :100A80000000000000000000000000000000000066 :100A90000000000000000000000000000000000056 :100AA0000000000000000000000000000000000046 :100AB0000000000000000000000000000000000036 :100AC0000000000000000000000000000000000026 :100AD0000000000000000000000000000000000016 :100AE0000000000000000000000000000000000006 :100AF00000000000000000000000000000000000F6 :100B000000000000000000000000000000000000E5 :100B100000000000000000000000000000000000D5 :100B200000000000000000000000000000000000C5 :100B300000000000000000000000000000000000B5 :100B400000000000000000000000000000000000A5 :100B50000000000000000000000000000000000095 :100B60000000000000000000000000000000000085 :100B70000000000000000000000000000000000075 :100B80000000000000000000000000000000000065 :100B90000000000000000000000000000000000055 :100BA0000000000000000000000000000000000045 :100BB0000000000000000000000000000000000035 :100BC0000000000000000000000000000000000025 :100BD0000000000000000000000000000000000015 :100BE0000000000000000000000000000000000005 :100BF00000000000000000000000000000000000F5 :100C000000000000000000000000000000000000E4 :100C100000000000000000000000000000000000D4 :100C200000000000000000000000000000000000C4 :100C300000000000000000000000000000000000B4 :100C400000000000000000000000000000000000A4 :100C50000000000000000000000000000000000094 :100C60000000000000000000000000000000000084 :100C70000000000000000000000000000000000074 :100C80000000000000000000000000000000000064 :100C90000000000000000000000000000000000054 :100CA0000000000000000000000000000000000044 :100CB0000000000000000000000000000000000034 :100CC0000000000000000000000000000000000024 :100CD0000000000000000000000000000000000014 :100CE0000000000000000000000000000000000004 :100CF00000000000000000000000000000000000F4 :100D000000000000000000000000000000000000E3 :100D100000000000000000000000000000000000D3 :100D200000000000000000000000000000000000C3 :100D300000000000000000000000000000000000B3 :100D400000000000000000000000000000000000A3 :100D50000000000000000000000000000000000093 :100D60000000000000000000000000000000000083 :100D70000000000000000000000000000000000073 :100D80000000000000000000000000000000000063 :100D90000000000000000000000000000000000053 :100DA0000000000000000000000000000000000043 :100DB0000000000000000000000000000000000033 :100DC0000000000000000000000000000000000023 :100DD0000000000000000000000000000000000013 :100DE0000000000000000000000000000000000003 :100DF00000000000000000000000000000000000F3 :100E000000000000000000000000000000000000E2 :100E100000000000000000000000000000000000D2 :100E200000000000000000000000000000000000C2 :100E300000000000000000000000000000000000B2 :100E400000000000000000000000000000000000A2 :100E50000000000000000000000000000000000092 :100E60000000000000000000000000000000000082 :100E70000000000000000000000000000000000072 :100E80000000000000000000000000000000000062 :100E90000000000000000000000000000000000052 :100EA0000000000000000000000000000000000042 :100EB0000000000000000000000000000000000032 :100EC0000000000000000000000000000000000022 :100ED0000000000000000000000000000000000012 :100EE0000000000000000000000000000000000002 :100EF00000000000000000000000000000000000F2 :100F000000000000000000000000000000000000E1 :100F100000000000000000000000000000000000D1 :100F200000000000000000000000000000000000C1 :100F300000000000000000000000000000000000B1 :100F400000000000000000000000000000000000A1 :100F50000000000000000000000000000000000091 :100F60000000000000000000000000000000000081 :100F70000000000000000000000000000000000071 :100F80000000000000000000000000000000000061 :100F90000000000000000000000000000000000051 :100FA0000000000000000000000000000000000041 :100FB0000000000000000000000000000000000031 :100FC0000000000000000000000000000000000021 :100FD0000000000000000000000000000000000011 :100FE0000000000000000000000000000000000001 :100FF00000000000000000000000000000000000F1 :1010000000000000000000000000000000000000E0 :1010100000000000000000000000000000000000D0 :1010200000000000000000000000000000000000C0 :1010300000000000000000000000000000000000B0 :1010400000000000000000000000000000000000A0 :101050000000000000000000000000000000000090 :101060000000000000000000000000000000000080 :101070000000000000000000000000000000000070 :101080000000000000000000000000000000000060 :101090000000000000000000000000000000000050 :1010A0000000000000000000000000000000000040 :1010B0000000000000000000000000000000000030 :1010C0000000000000000000000000000000000020 :1010D0000000000000000000000000000000000010 :1010E0000000000000000000000000000000000000 :1010F00000000000000000000000000000000000F0 :1011000000000000000000000000000000000000DF :1011100000000000000000000000000000000000CF :1011200000000000000000000000000000000000BF :1011300000000000000000000000000000000000AF :10114000000000000000000000000000000000009F :10115000000000000000000000000000000000008F :10116000000000000000000000000000000000007F :10117000000000000000000000000000000000006F :10118000000000000000000000000000000000005F :10119000000000000000000000000000000000004F :1011A000000000000000000000000000000000003F :1011B000000000000000000000000000000000002F :1011C000000000000000000000000000000000001F :1011D000000000000000000000000000000000000F :1011E00000000000000000000000000000000000FF :1011F00000000000000000000000000000000000EF :1012000000000000000000000000000000000000DE :1012100000000000000000000000000000000000CE :1012200000000000000000000000000000000000BE :1012300000000000000000000000000000000000AE :10124000000000000000000000000000000000009E :10125000000000000000000000000000000000008E :10126000000000000000000000000000000000007E :10127000000000000000000000000000000000006E :10128000000000000000000000000000000000005E :10129000000000000000000000000000000000004E :1012A000000000000000000000000000000000003E :1012B000000000000000000000000000000000002E :1012C000000000000000000000000000000000001E :1012D000000000000000000000000000000000000E :1012E00000000000000000000000000000000000FE :1012F00000000000000000000000000000000000EE :1013000000000000000000000000000000000000DD :1013100000000000000000000000000000000000CD :1013200000000000000000000000000000000000BD :1013300000000000000000000000000000000000AD :10134000000000000000000000000000000000009D :10135000000000000000000000000000000000008D :10136000000000000000000000000000000000007D :10137000000000000000000000000000000000006D :10138000000000000000000000000000000000005D :10139000000000000000000000000000000000004D :1013A000000000000000000000000000000000003D :1013B000000000000000000000000000000000002D :1013C000000000000000000000000000000000001D :1013D000000000000000000000000000000000000D :1013E00000000000000000000000000000000000FD :1013F00000000000000000000000000000000000ED :1014000000000000000000000000000000000000DC :1014100000000000000000000000000000000000CC :1014200000000000000000000000000000000000BC :1014300000000000000000000000000000000000AC :10144000000000000000000000000000000000009C :10145000000000000000000000000000000000008C :10146000000000000000000000000000000000007C :10147000000000000000000000000000000000006C :10148000000000000000000000000000000000005C :10149000000000000000000000000000000000004C :1014A000000000000000000000000000000000003C :1014B000000000000000000000000000000000002C :1014C000000000000000000000000000000000001C :1014D000000000000000000000000000000000000C :1014E00000000000000000000000000000000000FC :1014F00000000000000000000000000000000000EC :1015000000000000000000000000000000000000DB :1015100000000000000000000000000000000000CB :1015200000000000000000000000000000000000BB :1015300000000000000000000000000000000000AB :10154000000000000000000000000000000000009B :10155000000000000000000000000000000000008B :10156000000000000000000000000000000000007B :10157000000000000000000000000000000000006B :10158000000000000000000000000000000000005B :10159000000000000000000000000000000000004B :1015A000000000000000000000000000000000003B :1015B000000000000000000000000000000000002B :1015C000000000000000000000000000000000001B :1015D000000000000000000000000000000000000B :1015E00000000000000000000000000000000000FB :1015F00000000000000000000000000000000000EB :1016000000000000000000000000000000000000DA :1016100000000000000000000000000000000000CA :1016200000000000000000000000000000000000BA :1016300000000000000000000000000000000000AA :10164000000000000000000000000000000000009A :10165000000000000000000000000000000000008A :10166000000000000000000000000000000000007A :10167000000000000000000000000000000000006A :10168000000000000000000000000000000000005A :10169000000000000000000000000000000000004A :1016A000000000000000000000000000000000003A :1016B000000000000000000000000000000000002A :1016C000000000000000000000000000000000001A :1016D000000000000000000000000000000000000A :1016E00000000000000000000000000000000000FA :1016F00000000000000000000000000000000000EA :1017000000000000000000000000000000000000D9 :1017100000000000000000000000000000000000C9 :1017200000000000000000000000000000000000B9 :1017300000000000000000000000000000000000A9 :101740000000000000000000000000000000000099 :101750000000000000000000000000000000000089 :101760000000000000000000000000000000000079 :101770000000000000000000000000000000000069 :101780000000000000000000000000000000000059 :101790000000000000000000000000000000000049 :1017A0000000000000000000000000000000000039 :1017B0000000000000000000000000000000000029 :1017C0000000000000000000000000000000000019 :1017D0000000000000000000000000000000000009 :1017E00000000000000000000000000000000000F9 :1017F00000000000000000000000000000000000E9 :1018000000000000000000000000000000000000D8 :1018100000000000000000000000000000000000C8 :1018200000000000000000000000000000000000B8 :1018300000000000000000000000000000000000A8 :101840000000000000000000000000000000000098 :101850000000000000000000000000000000000088 :101860000000000000000000000000000000000078 :101870000000000000000000000000000000000068 :101880000000000000000000000000000000000058 :101890000000000000000000000000000000000048 :1018A0000000000000000000000000000000000038 :1018B0000000000000000000000000000000000028 :1018C0000000000000000000000000000000000018 :1018D0000000000000000000000000000000000008 :1018E00000000000000000000000000000000000F8 :1018F00000000000000000000000000000000000E8 :1019000000000000000000000000000000000000D7 :1019100000000000000000000000000000000000C7 :1019200000000000000000000000000000000000B7 :1019300000000000000000000000000000000000A7 :101940000000000000000000000000000000000097 :101950000000000000000000000000000000000087 :101960000000000000000000000000000000000077 :101970000000000000000000000000000000000067 :101980000000000000000000000000000000000057 :101990000000000000000000000000000000000047 :1019A0000000000000000000000000000000000037 :1019B0000000000000000000000000000000000027 :1019C0000000000000000000000000000000000017 :1019D0000000000000000000000000000000000007 :1019E00000000000000000000000000000000000F7 :1019F00000000000000000000000000000000000E7 :101A000000000000000000000000000000000000D6 :101A100000000000000000000000000000000000C6 :101A200000000000000000000000000000000000B6 :101A300000000000000000000000000000000000A6 :101A40000000000000000000000000000000000096 :101A50000000000000000000000000000000000086 :101A60000000000000000000000000000000000076 :101A70000000000000000000000000000000000066 :101A80000000000000000000000000000000000056 :101A90000000000000000000000000000000000046 :101AA0000000000000000000000000000000000036 :101AB0000000000000000000000000000000000026 :101AC0000000000000000000000000000000000016 :101AD0000000000000000000000000000000000006 :101AE00000000000000000000000000000000000F6 :101AF00000000000000000000000000000000000E6 :101B000000000000000000000000000000000000D5 :101B100000000000000000000000000000000000C5 :101B200000000000000000000000000000000000B5 :101B300000000000000000000000000000000000A5 :101B40000000000000000000000000000000000095 :101B50000000000000000000000000000000000085 :101B60000000000000000000000000000000000075 :101B70000000000000000000000000000000000065 :101B80000000000000000000000000000000000055 :101B90000000000000000000000000000000000045 :101BA0000000000000000000000000000000000035 :101BB0000000000000000000000000000000000025 :101BC0000000000000000000000000000000000015 :101BD0000000000000000000000000000000000005 :101BE00000000000000000000000000000000000F5 :101BF00000000000000000000000000000000000E5 :101C000000000000000000000000000000000000D4 :101C100000000000000000000000000000000000C4 :101C200000000000000000000000000000000000B4 :101C300000000000000000000000000000000000A4 :101C40000000000000000000000000000000000094 :101C50000000000000000000000000000000000084 :101C60000000000000000000000000000000000074 :101C70000000000000000000000000000000000064 :101C80000000000000000000000000000000000054 :101C90000000000000000000000000000000000044 :101CA0000000000000000000000000000000000034 :101CB0000000000000000000000000000000000024 :101CC0000000000000000000000000000000000014 :101CD0000000000000000000000000000000000004 :101CE00000000000000000000000000000000000F4 :101CF00000000000000000000000000000000000E4 :101D000000000000000000000000000000000000D3 :101D100000000000000000000000000000000000C3 :101D200000000000000000000000000000000000B3 :101D300000000000000000000000000000000000A3 :101D40000000000000000000000000000000000093 :101D50000000000000000000000000000000000083 :101D60000000000000000000000000000000000073 :101D70000000000000000000000000000000000063 :101D80000000000000000000000000000000000053 :101D90000000000000000000000000000000000043 :101DA0000000000000000000000000000000000033 :101DB0000000000000000000000000000000000023 :101DC0000000000000000000000000000000000013 :101DD0000000000000000000000000000000000003 :101DE00000000000000000000000000000000000F3 :101DF00000000000000000000000000000000000E3 :101E000000000000000000000000000000000000D2 :101E100000000000000000000000000000000000C2 :101E200000000000000000000000000000000000B2 :101E300000000000000000000000000000000000A2 :101E40000000000000000000000000000000000092 :101E50000000000000000000000000000000000082 :101E60000000000000000000000000000000000072 :101E70000000000000000000000000000000000062 :101E80000000000000000000000000000000000052 :101E90000000000000000000000000000000000042 :101EA0000000000000000000000000000000000032 :101EB0000000000000000000000000000000000022 :101EC0000000000000000000000000000000000012 :101ED0000000000000000000000000000000000002 :101EE00000000000000000000000000000000000F2 :101EF00000000000000000000000000000000000E2 :101F000000000000000000000000000000000000D1 :101F100000000000000000000000000000000000C1 :101F200000000000000000000000000000000000B1 :101F300000000000000000000000000000000000A1 :101F40000000000000000000000000000000000091 :101F50000000000000000000000000000000000081 :101F60000000000000000000000000000000000071 :101F70000000000000000000000000000000000061 :101F80000000000000000000000000000000000051 :101F90000000000000000000000000000000000041 :101FA0000000000000000000000000000000000031 :101FB0000000000000000000000000000000000021 :101FC0000000000000000000000000000000000011 :101FD0000000000000000000000000000000000001 :101FE00000000000000000000000000000000000F1 :101FF00000000000000000000000000000000000E1 :1020000000000000000000000000000000000000D0 :1020100000000000000000000000000000000000C0 :1020200000000000000000000000000000000000B0 :1020300000000000000000000000000000000000A0 :102040000000000000000000000000000000000090 :102050000000000000000000000000000000000080 :102060000000000000000000000000000000000070 :102070000000000000000000000000000000000060 :102080000000000000000000000000000000000050 :102090000000000000000000000000000000000040 :1020A0000000000000000000000000000000000030 :1020B0000000000000000000000000000000000020 :1020C0000000000000000000000000000000000010 :1020D0000000000000000000000000000000000000 :1020E00000000000000000000000000000000000F0 :1020F00000000000000000000000000000000000E0 :1021000000000000000000000000000000000000CF :1021100000000000000000000000000000000000BF :1021200000000000000000000000000000000000AF :10213000000000000000000000000000000000009F :10214000000000000000000000000000000000008F :10215000000000000000000000000000000000007F :10216000000000000000000000000000000000006F :10217000000000000000000000000000000000005F :10218000000000000000000000000000000000004F :10219000000000000000000000000000000000003F :1021A000000000000000000000000000000000002F :1021B000000000000000000000000000000000001F :1021C000000000000000000000000000000000000F :1021D00000000000000000000000000000000000FF :1021E00000000000000000000000000000000000EF :1021F00000000000000000000000000000000000DF :1022000000000000000000000000000000000000CE :1022100000000000000000000000000000000000BE :1022200000000000000000000000000000000000AE :10223000000000000000000000000000000000009E :10224000000000000000000000000000000000008E :10225000000000000000000000000000000000007E :10226000000000000000000000000000000000006E :10227000000000000000000000000000000000005E :10228000000000000000000000000000000000004E :10229000000000000000000000000000000000003E :1022A000000000000000000000000000000000002E :1022B000000000000000000000000000000000001E :1022C000000000000000000000000000000000000E :1022D00000000000000000000000000000000000FE :1022E00000000000000000000000000000000000EE :1022F00000000000000000000000000000000000DE :1023000000000000000000000000000000000000CD :1023100000000000000000000000000000000000BD :1023200000000000000000000000000000000000AD :10233000000000000000000000000000000000009D :10234000000000000000000000000000000000008D :10235000000000000000000000000000000000007D :10236000000000000000000000000000000000006D :10237000000000000000000000000000000000005D :10238000000000000000000000000000000000004D :10239000000000000000000000000000000000003D :1023A000000000000000000000000000000000002D :1023B000000000000000000000000000000000001D :1023C000000000000000000000000000000000000D :1023D00000000000000000000000000000000000FD :1023E00000000000000000000000000000000000ED :1023F00000000000000000000000000000000000DD :1024000000000000000000000000000000000000CC :1024100000000000000000000000000000000000BC :1024200000000000000000000000000000000000AC :10243000000000000000000000000000000000009C :10244000000000000000000000000000000000008C :10245000000000000000000000000000000000007C :10246000000000000000000000000000000000006C :10247000000000000000000000000000000000005C :10248000000000000000000000000000000000004C :10249000000000000000000000000000000000003C :1024A000000000000000000000000000000000002C :1024B000000000000000000000000000000000001C :1024C000000000000000000000000000000000000C :1024D00000000000000000000000000000000000FC :1024E00000000000000000000000000000000000EC :1024F00000000000000000000000000000000000DC :1025000000000000000000000000000000000000CB :1025100000000000000000000000000000000000BB :1025200000000000000000000000000000000000AB :10253000000000000000000000000000000000009B :10254000000000000000000000000000000000008B :10255000000000000000000000000000000000007B :10256000000000000000000000000000000000006B :10257000000000000000000000000000000000005B :10258000000000000000000000000000000000004B :10259000000000000000000000000000000000003B :1025A000000000000000000000000000000000002B :1025B000000000000000000000000000000000001B :1025C000000000000000000000000000000000000B :1025D00000000000000000000000000000000000FB :1025E00000000000000000000000000000000000EB :1025F00000000000000000000000000000000000DB :1026000000000000000000000000000000000000CA :1026100000000000000000000000000000000000BA :1026200000000000000000000000000000000000AA :10263000000000000000000000000000000000009A :10264000000000000000000000000000000000008A :10265000000000000000000000000000000000007A :10266000000000000000000000000000000000006A :10267000000000000000000000000000000000005A :10268000000000000000000000000000000000004A :10269000000000000000000000000000000000003A :1026A000000000000000000000000000000000002A :1026B000000000000000000000000000000000001A :1026C000000000000000000000000000000000000A :1026D00000000000000000000000000000000000FA :1026E00000000000000000000000000000000000EA :1026F00000000000000000000000000000000000DA :1027000000000000000000000000000000000000C9 :1027100000000000000000000000000000000000B9 :1027200000000000000000000000000000000000A9 :102730000000000000000000000000000000000099 :102740000000000000000000000000000000000089 :102750000000000000000000000000000000000079 :102760000000000000000000000000000000000069 :102770000000000000000000000000000000000059 :102780000000000000000000000000000000000049 :102790000000000000000000000000000000000039 :1027A0000000000000000000000000000000000029 :1027B0000000000000000000000000000000000019 :1027C0000000000000000000000000000000000009 :1027D00000000000000000000000000000000000F9 :1027E00000000000000000000000000000000000E9 :1027F00000000000000000000000000000000000D9 :1028000000000000000000000000000000000000C8 :1028100000000000000000000000000000000000B8 :1028200000000000000000000000000000000000A8 :102830000000000000000000000000000000000098 :102840000000000000000000000000000000000088 :102850000000000000000000000000000000000078 :102860000000000000000000000000000000000068 :102870000000000000000000000000000000000058 :102880000000000000000000000000000000000048 :102890000000000000000000000000000000000038 :1028A0000000000000000000000000000000000028 :1028B0000000000000000000000000000000000018 :1028C0000000000000000000000000000000000008 :1028D00000000000000000000000000000000000F8 :1028E00000000000000000000000000000000000E8 :1028F00000000000000000000000000000000000D8 :1029000000000000000000000000000000000000C7 :1029100000000000000000000000000000000000B7 :1029200000000000000000000000000000000000A7 :102930000000000000000000000000000000000097 :102940000000000000000000000000000000000087 :102950000000000000000000000000000000000077 :102960000000000000000000000000000000000067 :102970000000000000000000000000000000000057 :102980000000000000000000000000000000000047 :102990000000000000000000000000000000000037 :1029A0000000000000000000000000000000000027 :1029B0000000000000000000000000000000000017 :1029C0000000000000000000000000000000000007 :1029D00000000000000000000000000000000000F7 :1029E00000000000000000000000000000000000E7 :1029F00000000000000000000000000000000000D7 :102A000000000000000000000000000000000000C6 :102A100000000000000000000000000000000000B6 :102A200000000000000000000000000000000000A6 :102A30000000000000000000000000000000000096 :102A40000000000000000000000000000000000086 :102A50000000000000000000000000000000000076 :102A60000000000000000000000000000000000066 :102A70000000000000000000000000000000000056 :102A80000000000000000000000000000000000046 :102A90000000000000000000000000000000000036 :102AA0000000000000000000000000000000000026 :102AB0000000000000000000000000000000000016 :102AC0000000000000000000000000000000000006 :102AD00000000000000000000000000000000000F6 :102AE00000000000000000000000000000000000E6 :102AF00000000000000000000000000000000000D6 :102B000000000000000000000000000000000000C5 :102B100000000000000000000000000000000000B5 :102B200000000000000000000000000000000000A5 :102B30000000000000000000000000000000000095 :102B40000000000000000000000000000000000085 :102B50000000000000000000000000000000000075 :102B60000000000000000000000000000000000065 :102B70000000000000000000000000000000000055 :102B80000000000000000000000000000000000045 :102B90000000000000000000000000000000000035 :102BA0000000000000000000000000000000000025 :102BB0000000000000000000000000000000000015 :102BC0000000000000000000000000000000000005 :102BD00000000000000000000000000000000000F5 :102BE00000000000000000000000000000000000E5 :102BF00000000000000000000000000000000000D5 :102C000000000000000000000000000000000000C4 :102C100000000000000000000000000000000000B4 :102C200000000000000000000000000000000000A4 :102C30000000000000000000000000000000000094 :102C40000000000000000000000000000000000084 :102C50000000000000000000000000000000000074 :102C60000000000000000000000000000000000064 :102C70000000000000000000000000000000000054 :102C80000000000000000000000000000000000044 :102C90000000000000000000000000000000000034 :102CA0000000000000000000000000000000000024 :102CB0000000000000000000000000000000000014 :102CC0000000000000000000000000000000000004 :102CD00000000000000000000000000000000000F4 :102CE00000000000000000000000000000000000E4 :102CF00000000000000000000000000000000000D4 :102D000000000000000000000000000000000000C3 :102D100000000000000000000000000000000000B3 :102D200000000000000000000000000000000000A3 :102D30000000000000000000000000000000000093 :102D40000000000000000000000000000000000083 :102D50000000000000000000000000000000000073 :102D60000000000000000000000000000000000063 :102D70000000000000000000000000000000000053 :102D80000000000000000000000000000000000043 :102D90000000000000000000000000000000000033 :102DA0000000000000000000000000000000000023 :102DB0000000000000000000000000000000000013 :102DC0000000000000000000000000000000000003 :102DD00000000000000000000000000000000000F3 :102DE00000000000000000000000000000000000E3 :102DF00000000000000000000000000000000000D3 :102E000000000000000000000000000000000000C2 :102E100000000000000000000000000000000000B2 :102E200000000000000000000000000000000000A2 :102E30000000000000000000000000000000000092 :102E40000000000000000000000000000000000082 :102E50000000000000000000000000000000000072 :102E60000000000000000000000000000000000062 :102E70000000000000000000000000000000000052 :102E80000000000000000000000000000000000042 :102E90000000000000000000000000000000000032 :102EA0000000000000000000000000000000000022 :102EB0000000000000000000000000000000000012 :102EC0000000000000000000000000000000000002 :102ED00000000000000000000000000000000000F2 :102EE00000000000000000000000000000000000E2 :102EF00000000000000000000000000000000000D2 :102F000000000000000000000000000000000000C1 :102F100000000000000000000000000000000000B1 :102F200000000000000000000000000000000000A1 :102F30000000000000000000000000000000000091 :102F40000000000000000000000000000000000081 :102F50000000000000000000000000000000000071 :102F60000000000000000000000000000000000061 :102F70000000000000000000000000000000000051 :102F80000000000000000000000000000000000041 :102F90000000000000000000000000000000000031 :102FA0000000000000000000000000000000000021 :102FB0000000000000000000000000000000000011 :102FC0000000000000000000000000000000000001 :102FD00000000000000000000000000000000000F1 :102FE00000000000000000000000000000000000E1 :102FF00000000000000000000000000000000000D1 :1030000000000000000000000000000000000000C0 :1030100000000000000000000000000000000000B0 :1030200000000000000000000000000000000000A0 :103030000000000000000000000000000000000090 :103040000000000000000000000000000000000080 :103050000000000000000000000000000000000070 :103060000000000000000000000000000000000060 :103070000000000000000000000000000000000050 :103080000000000000000000000000000000000040 :103090000000000000000000000000000000000030 :1030A0000000000000000000000000000000000020 :1030B0000000000000000000000000000000000010 :1030C0000000000000000000000000000000000000 :1030D00000000000000000000000000000000000F0 :1030E00000000000000000000000000000000000E0 :1030F00000000000000000000000000000000000D0 :1031000000000000000000000000000000000000BF :1031100000000000000000000000000000000000AF :10312000000000000000000000000000000000009F :10313000000000000000000000000000000000008F :10314000000000000000000000000000000000007F :10315000000000000000000000000000000000006F :10316000000000000000000000000000000000005F :10317000000000000000000000000000000000004F :10318000000000000000000000000000000000003F :10319000000000000000000000000000000000002F :1031A000000000000000000000000000000000001F :1031B000000000000000000000000000000000000F :1031C00000000000000000000000000000000000FF :1031D00000000000000000000000000000000000EF :1031E00000000000000000000000000000000000DF :1031F00000000000000000000000000000000000CF :1032000000000000000000000000000000000000BE :1032100000000000000000000000000000000000AE :10322000000000000000000000000000000000009E :10323000000000000000000000000000000000008E :10324000000000000000000000000000000000007E :10325000000000000000000000000000000000006E :10326000000000000000000000000000000000005E :10327000000000000000000000000000000000004E :10328000000000000000000000000000000000003E :10329000000000000000000000000000000000002E :1032A000000000000000000000000000000000001E :1032B000000000000000000000000000000000000E :1032C00000000000000000000000000000000000FE :1032D00000000000000000000000000000000000EE :1032E00000000000000000000000000000000000DE :1032F00000000000000000000000000000000000CE :1033000000000000000000000000000000000000BD :1033100000000000000000000000000000000000AD :10332000000000000000000000000000000000009D :10333000000000000000000000000000000000008D :10334000000000000000000000000000000000007D :10335000000000000000000000000000000000006D :10336000000000000000000000000000000000005D :10337000000000000000000000000000000000004D :10338000000000000000000000000000000000003D :10339000000000000000000000000000000000002D :1033A000000000000000000000000000000000001D :1033B000000000000000000000000000000000000D :1033C00000000000000000000000000000000000FD :1033D00000000000000000000000000000000000ED :1033E00000000000000000000000000000000000DD :1033F00000000000000000000000000000000000CD :1034000000000000000000000000000000000000BC :1034100000000000000000000000000000000000AC :10342000000000000000000000000000000000009C :10343000000000000000000000000000000000008C :10344000000000000000000000000000000000007C :10345000000000000000000000000000000000006C :10346000000000000000000000000000000000005C :10347000000000000000000000000000000000004C :10348000000000000000000000000000000000003C :10349000000000000000000000000000000000002C :1034A000000000000000000000000000000000001C :1034B000000000000000000000000000000000000C :1034C00000000000000000000000000000000000FC :1034D00000000000000000000000000000000000EC :1034E00000000000000000000000000000000000DC :1034F00000000000000000000000000000000000CC :1035000000000000000000000000000000000000BB :1035100000000000000000000000000000000000AB :10352000000000000000000000000000000000009B :10353000000000000000000000000000000000008B :10354000000000000000000000000000000000007B :10355000000000000000000000000000000000006B :10356000000000000000000000000000000000005B :10357000000000000000000000000000000000004B :10358000000000000000000000000000000000003B :10359000000000000000000000000000000000002B :1035A000000000000000000000000000000000001B :1035B000000000000000000000000000000000000B :1035C00000000000000000000000000000000000FB :1035D00000000000000000000000000000000000EB :1035E00000000000000000000000000000000000DB :1035F00000000000000000000000000000000000CB :1036000000000000000000000000000000000000BA :1036100000000000000000000000000000000000AA :10362000000000000000000000000000000000009A :10363000000000000000000000000000000000008A :10364000000000000000000000000000000000007A :10365000000000000000000000000000000000006A :10366000000000000000000000000000000000005A :10367000000000000000000000000000000000004A :10368000000000000000000000000000000000003A :10369000000000000000000000000000000000002A :1036A000000000000000000000000000000000001A :1036B000000000000000000000000000000000000A :1036C00000000000000000000000000000000000FA :1036D00000000000000000000000000000000000EA :1036E00000000000000000000000000000000000DA :1036F00000000000000000000000000000000000CA :1037000000000000000000000000000000000000B9 :1037100000000000000000000000000000000000A9 :103720000000000000000000000000000000000099 :103730000000000000000000000000000000000089 :103740000000000000000000000000000000000079 :103750000000000000000000000000000000000069 :103760000000000000000000000000000000000059 :103770000000000000000000000000000000000049 :103780000000000000000000000000000000000039 :103790000000000000000000000000000000000029 :1037A0000000000000000000000000000000000019 :1037B0000000000000000000000000000000000009 :1037C00000000000000000000000000000000000F9 :1037D00000000000000000000000000000000000E9 :1037E00000000000000000000000000000000000D9 :1037F00000000000000000000000000000000000C9 :1038000000000000000000000000000000000000B8 :1038100000000000000000000000000000000000A8 :103820000000000000000000000000000000000098 :103830000000000000000000000000000000000088 :103840000000000000000000000000000000000078 :103850000000000000000000000000000000000068 :103860000000000000000000000000000000000058 :103870000000000000000000000000000000000048 :103880000000000000000000000000000000000038 :103890000000000000000000000000000000000028 :1038A0000000000000000000000000000000000018 :1038B0000000000000000000000000000000000008 :1038C00000000000000000000000000000000000F8 :1038D00000000000000000000000000000000000E8 :1038E00000000000000000000000000000000000D8 :1038F00000000000000000000000000000000000C8 :1039000000000000000000000000000000000000B7 :1039100000000000000000000000000000000000A7 :103920000000000000000000000000000000000097 :103930000000000000000000000000000000000087 :103940000000000000000000000000000000000077 :103950000000000000000000000000000000000067 :103960000000000000000000000000000000000057 :103970000000000000000000000000000000000047 :103980000000000000000000000000000000000037 :103990000000000000000000000000000000000027 :1039A0000000000000000000000000000000000017 :1039B0000000000000000000000000000000000007 :1039C00000000000000000000000000000000000F7 :1039D00000000000000000000000000000000000E7 :1039E00000000000000000000000000000000000D7 :1039F00000000000000000000000000000000000C7 :103A000000000000000000000000000000000000B6 :103A100000000000000000000000000000000000A6 :103A20000000000000000000000000000000000096 :103A30000000000000000000000000000000000086 :103A40000000000000000000000000000000000076 :103A50000000000000000000000000000000000066 :103A60000000000000000000000000000000000056 :103A70000000000000000000000000000000000046 :103A80000000000000000000000000000000000036 :103A90000000000000000000000000000000000026 :103AA0000000000000000000000000000000000016 :103AB0000000000000000000000000000000000006 :103AC00000000000000000000000000000000000F6 :103AD00000000000000000000000000000000000E6 :103AE00000000000000000000000000000000000D6 :103AF00000000000000000000000000000000000C6 :103B000000000000000000000000000000000000B5 :103B100000000000000000000000000000000000A5 :103B20000000000000000000000000000000000095 :103B30000000000000000000000000000000000085 :103B40000000000000000000000000000000000075 :103B50000000000000000000000000000000000065 :103B60000000000000000000000000000000000055 :103B70000000000000000000000000000000000045 :103B80000000000000000000000000000000000035 :103B90000000000000000000000000000000000025 :103BA0000000000000000000000000000000000015 :103BB0000000000000000000000000000000000005 :103BC00000000000000000000000000000000000F5 :103BD00000000000000000000000000000000000E5 :103BE00000000000000000000000000000000000D5 :103BF00000000000000000000000000000000000C5 :103C000000000000000000000000000000000000B4 :103C100000000000000000000000000000000000A4 :103C20000000000000000000000000000000000094 :103C30000000000000000000000000000000000084 :103C40000000000000000000000000000000000074 :103C50000000000000000000000000000000000064 :103C60000000000000000000000000000000000054 :103C70000000000000000000000000000000000044 :103C80000000000000000000000000000000000034 :103C90000000000000000000000000000000000024 :103CA0000000000000000000000000000000000014 :103CB0000000000000000000000000000000000004 :103CC00000000000000000000000000000000000F4 :103CD00000000000000000000000000000000000E4 :103CE00000000000000000000000000000000000D4 :103CF00000000000000000000000000000000000C4 :103D000000000000000000000000000000000000B3 :103D100000000000000000000000000000000000A3 :103D20000000000000000000000000000000000093 :103D30000000000000000000000000000000000083 :103D40000000000000000000000000000000000073 :103D50000000000000000000000000000000000063 :103D60000000000000000000000000000000000053 :103D70000000000000000000000000000000000043 :103D80000000000000000000000000000000000033 :103D90000000000000000000000000000000000023 :103DA0000000000000000000000000000000000013 :103DB0000000000000000000000000000000000003 :103DC00000000000000000000000000000000000F3 :103DD00000000000000000000000000000000000E3 :103DE00000000000000000000000000000000000D3 :103DF00000000000000000000000000000000000C3 :103E000000000000000000000000000000000000B2 :103E100000000000000000000000000000000000A2 :103E20000000000000000000000000000000000092 :103E30000000000000000000000000000000000082 :103E40000000000000000000000000000000000072 :103E50000000000000000000000000000000000062 :103E60000000000000000000000000000000000052 :103E70000000000000000000000000000000000042 :103E80000000000000000000000000000000000032 :103E90000000000000000000000000000000000022 :103EA0000000000000000000000000000000000012 :103EB0000000000000000000000000000000000002 :103EC00000000000000000000000000000000000F2 :103ED00000000000000000000000000000000000E2 :103EE00000000000000000000000000000000000D2 :103EF00000000000000000000000000000000000C2 :103F000000000000000000000000000000000000B1 :103F100000000000000000000000000000000000A1 :103F20000000000000000000000000000000000091 :103F30000000000000000000000000000000000081 :103F40000000000000000000000000000000000071 :103F50000000000000000000000000000000000061 :103F60000000000000000000000000000000000051 :103F70000000000000000000000000000000000041 :103F80000000000000000000000000000000000031 :103F90000000000000000000000000000000000021 :103FA0000000000000000000000000000000000011 :103FB0000000000000000000000000000000000001 :103FC00000000000000000000000000000000000F1 :103FD00000000000000000000000000000000000E1 :103FE00000000000000000000000000000000000D1 :103FF00000000000000000000000000000000000C1 :1040000000000000000000000000000000000000B0 :1040100000000000000000000000000000000000A0 :104020000000000000000000000000000000000090 :104030000000000000000000000000000000000080 :104040000000000000000000000000000000000070 :104050000000000000000000000000000000000060 :104060000000000000000000000000000000000050 :104070000000000000000000000000000000000040 :104080000000000000000000000000000000000030 :104090000000000000000000000000000000000020 :1040A0000000000000000000000000000000000010 :1040B0000000000000000000000000000000000000 :1040C00000000000000000000000000000000000F0 :1040D00000000000000000000000000000000000E0 :1040E00000000000000000000000000000000000D0 :1040F00000000000000000000000000000000000C0 :1041000000000000000000000000000000000000AF :10411000000000000000000000000000000000009F :10412000000000000000000000000000000000008F :10413000000000000000000000000000000000007F :10414000000000000000000000000000000000006F :10415000000000000000000000000000000000005F :10416000000000000000000000000000000000004F :10417000000000000000000000000000000000003F :10418000000000000000000000000000000000002F :10419000000000000000000000000000000000001F :1041A000000000000000000000000000000000000F :1041B00000000000000000000000000000000000FF :1041C00000000000000000000000000000000000EF :1041D00000000000000000000000000000000000DF :1041E00000000000000000000000000000000000CF :1041F00000000000000000000000000000000000BF :1042000000000000000000000000000000000000AE :10421000000000000000000000000000000000009E :10422000000000000000000000000000000000008E :10423000000000000000000000000000000000007E :10424000000000000000000000000000000000006E :10425000000000000000000000000000000000005E :10426000000000000000000000000000000000004E :10427000000000000000000000000000000000003E :10428000000000000000000000000000000000002E :10429000000000000000000000000000000000001E :1042A000000000000000000000000000000000000E :1042B00000000000000000000000000000000000FE :1042C00000000000000000000000000000000000EE :1042D00000000000000000000000000000000000DE :1042E00000000000000000000000000000000000CE :1042F00000000000000000000000000000000000BE :1043000000000000000000000000000000000000AD :10431000000000000000000000000000000000009D :10432000000000000000000000000000000000008D :10433000000000000000000000000000000000007D :10434000000000000000000000000000000000006D :10435000000000000000000000000000000000005D :10436000000000000000000000000000000000004D :10437000000000000000000000000000000000003D :10438000000000000000000000000000000000002D :10439000000000000000000000000000000000001D :1043A000000000000000000000000000000000000D :1043B00000000000000000000000000000000000FD :1043C00000000000000000000000000000000000ED :1043D00000000000000000000000000000000000DD :1043E00000000000000000000000000000000000CD :1043F00000000000000000000000000000000000BD :1044000000000000000000000000000000000000AC :10441000000000000000000000000000000000009C :10442000000000000000000000000000000000008C :10443000000000000000000000000000000000007C :10444000000000000000000000000000000000006C :10445000000000000000000000000000000000005C :10446000000000000000000000000000000000004C :10447000000000000000000000000000000000003C :10448000000000000000000000000000000000002C :10449000000000000000000000000000000000001C :1044A000000000000000000000000000000000000C :1044B00000000000000000000000000000000000FC :1044C00000000000000000000000000000000000EC :1044D00000000000000000000000000000000000DC :1044E00000000000000000000000000000000000CC :1044F00000000000000000000000000000000000BC :1045000000000000000000000000000000000000AB :10451000000000000000000000000000000000009B :10452000000000000000000000000000000000008B :10453000000000000000000000000000000000007B :10454000000000000000000000000000000000006B :10455000000000000000000000000000000000005B :10456000000000000000000000000000000000004B :10457000000000000000000000000000000000003B :10458000000000000000000000000000000000002B :10459000000000000000000000000000000000001B :1045A000000000000000000000000000000000000B :1045B00000000000000000000000000000000000FB :1045C00000000000000000000000000000000000EB :1045D00000000000000000000000000000000000DB :1045E00000000000000000000000000000000000CB :1045F00000000000000000000000000000000000BB :1046000000000000000000000000000000000000AA :10461000000000000000000000000000000000009A :10462000000000000000000000000000000000008A :10463000000000000000000000000000000000007A :10464000000000000000000000000000000000006A :10465000000000000000000000000000000000005A :10466000000000000000000000000000000000004A :10467000000000000000000000000000000000003A :10468000000000000000000000000000000000002A :10469000000000000000000000000000000000001A :1046A000000000000000000000000000000000000A :1046B00000000000000000000000000000000000FA :1046C00000000000000000000000000000000000EA :1046D00000000000000000000000000000000000DA :1046E00000000000000000000000000000000000CA :1046F00000000000000000000000000000000000BA :1047000000000000000000000000000000000000A9 :104710000000000000000000000000000000000099 :104720000000000000000000000000000000000089 :104730000000000000000000000000000000000079 :104740000000000000000000000000000000000069 :104750000000000000000000000000000000000059 :104760000000000000000000000000000000000049 :104770000000000000000000000000000000000039 :104780000000000000000000000000000000000029 :104790000000000000000000000000000000000019 :1047A0000000000000000000000000000000000009 :1047B00000000000000000000000000000000000F9 :1047C00000000000000000000000000000000000E9 :1047D00000000000000000000000000000000000D9 :1047E00000000000000000000000000000000000C9 :1047F00000000000000000000000000000000000B9 :1048000000000000000000000000000000000000A8 :104810000000000000000000000000000000000098 :104820000000000000000000000000000000000088 :104830000000000000000000000000000000000078 :104840000000000000000000000000000000000068 :104850000000000000000000000000000000000058 :104860000000000000000000000000000000000048 :104870000000000000000000000000000000000038 :104880000000000000000000000000000000000028 :104890000000000000000000000000000000000018 :1048A0000000000000000000000000000000000008 :1048B00000000000000000000000000000000000F8 :1048C00000000000000000000000000000000000E8 :1048D00000000000000000000000000000000000D8 :1048E00000000000000000000000000000000000C8 :1048F00000000000000000000000000000000000B8 :1049000000000000000000000000000000000000A7 :104910000000000000000000000000000000000097 :104920000000000000000000000000000000000087 :104930000000000000000000000000000000000077 :104940000000000000000000000000000000000067 :104950000000000000000000000000000000000057 :104960000000000000000000000000000000000047 :104970000000000000000000000000000000000037 :104980000000000000000000000000000000000027 :104990000000000000000000000000000000000017 :1049A0000000000000000000000000000000000007 :1049B00000000000000000000000000000000000F7 :1049C00000000000000000000000000000000000E7 :1049D00000000000000000000000000000000000D7 :1049E00000000000000000000000000000000000C7 :1049F00000000000000000000000000000000000B7 :104A000000000000000000000000000000000000A6 :104A10000000000000000000000000000000000096 :104A20000000000000000000000000000000000086 :104A30000000000000000000000000000000000076 :104A40000000000000000000000000000000000066 :104A50000000000000000000000000000000000056 :104A60000000000000000000000000000000000046 :104A70000000000000000000000000000000000036 :104A80000000000000000000000000000000000026 :104A90000000000000000000000000000000000016 :104AA0000000000000000000000000000000000006 :104AB00000000000000000000000000000000000F6 :104AC00000000000000000000000000000000000E6 :104AD00000000000000000000000000000000000D6 :104AE00000000000000000000000000000000000C6 :104AF00000000000000000000000000000000000B6 :104B000000000000000000000000000000000000A5 :104B10000000000000000000000000000000000095 :104B20000000000000000000000000000000000085 :104B30000000000000000000000000000000000075 :104B40000000000000000000000000000000000065 :104B50000000000000000000000000000000000055 :104B60000000000000000000000000000000000045 :104B70000000000000000000000000000000000035 :104B80000000000000000000000000000000000025 :104B90000000000000000000000000000000000015 :104BA0000000000000000000000000000000000005 :104BB00000000000000000000000000000000000F5 :104BC00000000000000000000000000000000000E5 :104BD00000000000000000000000000000000000D5 :104BE00000000000000000000000000000000000C5 :104BF00000000000000000000000000000000000B5 :104C000000000000000000000000000000000000A4 :104C10000000000000000000000000000000000094 :104C20000000000000000000000000000000000084 :104C30000000000000000000000000000000000074 :104C40000000000000000000000000000000000064 :104C50000000000000000000000000000000000054 :104C60000000000000000000000000000000000044 :104C70000000000000000000000000000000000034 :104C80000000000000000000000000000000000024 :104C90000000000000000000000000000000000014 :104CA0000000000000000000000000000000000004 :104CB00000000000000000000000000000000000F4 :104CC00000000000000000000000000000000000E4 :104CD00000000000000000000000000000000000D4 :104CE00000000000000000000000000000000000C4 :104CF00000000000000000000000000000000000B4 :104D000000000000000000000000000000000000A3 :104D10000000000000000000000000000000000093 :104D20000000000000000000000000000000000083 :104D30000000000000000000000000000000000073 :104D40000000000000000000000000000000000063 :104D50000000000000000000000000000000000053 :104D60000000000000000000000000000000000043 :104D70000000000000000000000000000000000033 :104D80000000000000000000000000000000000023 :104D90000000000000000000000000000000000013 :104DA0000000000000000000000000000000000003 :104DB00000000000000000000000000000000000F3 :104DC00000000000000000000000000000000000E3 :104DD00000000000000000000000000000000000D3 :104DE00000000000000000000000000000000000C3 :104DF00000000000000000000000000000000000B3 :104E000000000000000000000000000000000000A2 :104E10000000000000000000000000000000000092 :104E20000000000000000000000000000000000082 :104E30000000000000000000000000000000000072 :104E40000000000000000000000000000000000062 :104E50000000000000000000000000000000000052 :104E60000000000000000000000000000000000042 :104E70000000000000000000000000000000000032 :104E80000000000000000000000000000000000022 :104E90000000000000000000000000000000000012 :104EA0000000000000000000000000000000000002 :104EB00000000000000000000000000000000000F2 :104EC00000000000000000000000000000000000E2 :104ED00000000000000000000000000000000000D2 :104EE00000000000000000000000000000000000C2 :104EF00000000000000000000000000000000000B2 :104F000000000000000000000000000000000000A1 :104F10000000000000000000000000000000000091 :104F20000000000000000000000000000000000081 :104F30000000000000000000000000000000000071 :104F40000000000000000000000000000000000061 :104F50000000000000000000000000000000000051 :104F60000000000000000000000000000000000041 :104F70000000000000000000000000000000000031 :104F80000000000000000000000000000000000021 :104F90000000000000000000000000000000000011 :104FA0000000000000000000000000000000000001 :104FB00000000000000000000000000000000000F1 :104FC00000000000000000000000000000000000E1 :104FD00000000000000000000000000000000000D1 :104FE00000000000000000000000000000000000C1 :104FF00000000000000000000000000000000000B1 :1050000000000000000000000000000000000000A0 :105010000000000000000000000000000000000090 :105020000000000000000000000000000000000080 :105030000000000000000000000000000000000070 :105040000000000000000000000000000000000060 :105050000000000000000000000000000000000050 :105060000000000000000000000000000000000040 :105070000000000000000000000000000000000030 :105080000000000000000000000000000000000020 :105090000000000000000000000000000000000010 :1050A0000000000000000000000000000000000000 :1050B00000000000000000000000000000000000F0 :1050C00000000000000000000000000000000000E0 :1050D00000000000000000000000000000000000D0 :1050E00000000000000000000000000000000000C0 :1050F00000000000000000000000000000000000B0 :10510000000000000000000000000000000000009F :10511000000000000000000000000000000000008F :10512000000000000000000000000000000000007F :10513000000000000000000000000000000000006F :10514000000000000000000000000000000000005F :10515000000000000000000000000000000000004F :10516000000000000000000000000000000000003F :10517000000000000000000000000000000000002F :10518000000000000000000000000000000000001F :10519000000000000000000000000000000000000F :1051A00000000000000000000000000000000000FF :1051B00000000000000000000000000000000000EF :1051C00000000000000000000000000000000000DF :1051D00000000000000000000000000000000000CF :1051E00000000000000000000000000000000000BF :1051F00000000000000000000000000000000000AF :10520000000000000000000000000000000000009E :10521000000000000000000000000000000000008E :10522000000000000000000000000000000000007E :10523000000000000000000000000000000000006E :10524000000000000000000000000000000000005E :10525000000000000000000000000000000000004E :10526000000000000000000000000000000000003E :10527000000000000000000000000000000000002E :10528000000000000000000000000000000000001E :10529000000000000000000000000000000000000E :1052A00000000000000000000000000000000000FE :1052B00000000000000000000000000000000000EE :1052C00000000000000000000000000000000000DE :1052D00000000000000000000000000000000000CE :1052E00000000000000000000000000000000000BE :1052F00000000000000000000000000000000000AE :10530000000000000000000000000000000000009D :10531000000000000000000000000000000000008D :10532000000000000000000000000000000000007D :10533000000000000000000000000000000000006D :10534000000000000000000000000000000000005D :10535000000000000000000000000000000000004D :10536000000000000000000000000000000000003D :10537000000000000000000000000000000000002D :10538000000000000000000000000000000000001D :10539000000000000000000000000000000000000D :1053A00000000000000000000000000000000000FD :1053B00000000000000000000000000000000000ED :1053C00000000000000000000000000000000000DD :1053D00000000000000000000000000000000000CD :1053E00000000000000000000000000000000000BD :1053F00000000000000000000000000000000000AD :10540000000000000000000000000000000000009C :10541000000000000000000000000000000000008C :10542000000000000000000000000000000000007C :10543000000000000000000000000000000000006C :10544000000000000000000000000000000000005C :10545000000000000000000000000000000000004C :10546000000000000000000000000000000000003C :10547000000000000000000000000000000000002C :10548000000000000000000000000000000000001C :10549000000000000000000000000000000000000C :1054A00000000000000000000000000000000000FC :1054B00000000000000000000000000000000000EC :1054C00000000000000000000000000000000000DC :1054D00000000000000000000000000000000000CC :1054E00000000000000000000000000000000000BC :1054F00000000000000000000000000000000000AC :10550000000000000000000000000000000000009B :10551000000000000000000000000000000000008B :10552000000000000000000000000000000000007B :10553000000000000000000000000000000000006B :10554000000000000000000000000000000000005B :10555000000000000000000000000000000000004B :10556000000000000000000000000000000000003B :10557000000000000000000000000000000000002B :10558000000000000000000000000000000000001B :10559000000000000000000000000000000000000B :1055A00000000000000000000000000000000000FB :1055B00000000000000000000000000000000000EB :1055C00000000000000000000000000000000000DB :1055D00000000000000000000000000000000000CB :1055E00000000000000000000000000000000000BB :1055F00000000000000000000000000000000000AB :10560000000000000000000000000000000000009A :10561000000000000000000000000000000000008A :10562000000000000000000000000000000000007A :10563000000000000000000000000000000000006A :10564000000000000000000000000000000000005A :10565000000000000000000000000000000000004A :10566000000000000000000000000000000000003A :10567000000000000000000000000000000000002A :10568000000000000000000000000000000000001A :10569000000000000000000000000000000000000A :1056A00000000000000000000000000000000000FA :1056B00000000000000000000000000000000000EA :1056C00000000000000000000000000000000000DA :1056D00000000000000000000000000000000000CA :1056E00000000000000000000000000000000000BA :1056F00000000000000000000000000000000000AA :105700000000000000000000000000000000000099 :105710000000000000000000000000000000000089 :105720000000000000000000000000000000000079 :105730000000000000000000000000000000000069 :105740000000000000000000000000000000000059 :105750000000000000000000000000000000000049 :105760000000000000000000000000000000000039 :105770000000000000000000000000000000000029 :105780000000000000000000000000000000000019 :105790000000000000000000000000000000000009 :1057A00000000000000000000000000000000000F9 :1057B00000000000000000000000000000000000E9 :1057C00000000000000000000000000000000000D9 :1057D00000000000000000000000000000000000C9 :1057E00000000000000000000000000000000000B9 :1057F00000000000000000000000000000000000A9 :105800000000000000000000000000000000000098 :105810000000000000000000000000000000000088 :105820000000000000000000000000000000000078 :105830000000000000000000000000000000000068 :105840000000000000000000000000000000000058 :105850000000000000000000000000000000000048 :105860000000000000000000000000000000000038 :105870000000000000000000000000000000000028 :105880000000000000000000000000000000000018 :105890000000000000000000000000000000000008 :1058A00000000000000000000000000000000000F8 :1058B00000000000000000000000000000000000E8 :1058C00000000000000000000000000000000000D8 :1058D00000000000000000000000000000000000C8 :1058E00000000000000000000000000000000000B8 :1058F00000000000000000000000000000000000A8 :105900000000000000000000000000000000000097 :105910000000000000000000000000000000000087 :105920000000000000000000000000000000000077 :105930000000000000000000000000000000000067 :105940000000000000000000000000000000000057 :105950000000000000000000000000000000000047 :105960000000000000000000000000000000000037 :105970000000000000000000000000000000000027 :105980000000000000000000000000000000000017 :105990000000000000000000000000000000000007 :1059A00000000000000000000000000000000000F7 :1059B00000000000000000000000000000000000E7 :1059C00000000000000000000000000000000000D7 :1059D00000000000000000000000000000000000C7 :1059E00000000000000000000000000000000000B7 :1059F00000000000000000000000000000000000A7 :105A00000000000000000000000000000000000096 :105A10000000000000000000000000000000000086 :105A20000000000000000000000000000000000076 :105A30000000000000000000000000000000000066 :105A40000000000000000000000000000000000056 :105A50000000000000000000000000000000000046 :105A60000000000000000000000000000000000036 :105A70000000000000000000000000000000000026 :105A80000000000000000000000000000000000016 :105A90000000000000000000000000000000000006 :105AA00000000000000000000000000000000000F6 :105AB00000000000000000000000000000000000E6 :105AC00000000000000000000000000000000000D6 :105AD00000000000000000000000000000000000C6 :105AE00000000000000000000000000000000000B6 :105AF00000000000000000000000000000000000A6 :105B00000000000000000000000000000000000095 :105B10000000000000000000000000000000000085 :105B20000000000000000000000000000000000075 :105B30000000000000000000000000000000000065 :105B40000000000000000000000000000000000055 :105B50000000000000000000000000000000000045 :105B60000000000000000000000000000000000035 :105B70000000000000000000000000000000000025 :105B80000000000000000000000000000000000015 :105B90000000000000000000000000000000000005 :105BA00000000000000000000000000000000000F5 :105BB00000000000000000000000000000000000E5 :105BC00000000000000000000000000000000000D5 :105BD00000000000000000000000000000000000C5 :105BE00000000000000000000000000000000000B5 :105BF00000000000000000000000000000000000A5 :105C00000000000000000000000000000000000094 :105C10000000000000000000000000000000000084 :105C20000000000000000000000000000000000074 :105C30000000000000000000000000000000000064 :105C40000000000000000000000000000000000054 :105C50000000000000000000000000000000000044 :105C60000000000000000000000000000000000034 :105C70000000000000000000000000000000000024 :105C80000000000000000000000000000000000014 :105C90000000000000000000000000000000000004 :105CA00000000000000000000000000000000000F4 :105CB00000000000000000000000000000000000E4 :105CC00000000000000000000000000000000000D4 :105CD00000000000000000000000000000000000C4 :105CE00000000000000000000000000000000000B4 :105CF00000000000000000000000000000000000A4 :105D00000000000000000000000000000000000093 :105D10000000000000000000000000000000000083 :105D20000000000000000000000000000000000073 :105D30000000000000000000000000000000000063 :105D40000000000000000000000000000000000053 :105D50000000000000000000000000000000000043 :105D60000000000000000000000000000000000033 :105D70000000000000000000000000000000000023 :105D80000000000000000000000000000000000013 :105D90000000000000000000000000000000000003 :105DA00000000000000000000000000000000000F3 :105DB00000000000000000000000000000000000E3 :105DC00000000000000000000000000000000000D3 :105DD00000000000000000000000000000000000C3 :105DE00000000000000000000000000000000000B3 :105DF00000000000000000000000000000000000A3 :105E00000000000000000000000000000000000092 :105E10000000000000000000000000000000000082 :105E20000000000000000000000000000000000072 :105E30000000000000000000000000000000000062 :105E40000000000000000000000000000000000052 :105E50000000000000000000000000000000000042 :105E60000000000000000000000000000000000032 :105E70000000000000000000000000000000000022 :105E80000000000000000000000000000000000012 :105E90000000000000000000000000000000000002 :105EA00000000000000000000000000000000000F2 :105EB00000000000000000000000000000000000E2 :105EC00000000000000000000000000000000000D2 :105ED00000000000000000000000000000000000C2 :105EE00000000000000000000000000000000000B2 :105EF00000000000000000000000000000000000A2 :105F00000000000000000000000000000000000091 :105F10000000000000000000000000000000000081 :105F20000000000000000000000000000000000071 :105F30000000000000000000000000000000000061 :105F40000000000000000000000000000000000051 :105F50000000000000000000000000000000000041 :105F60000000000000000000000000000000000031 :105F70000000000000000000000000000000000021 :105F80000000000000000000000000000000000011 :105F90000000000000000000000000000000000001 :105FA00000000000000000000000000000000000F1 :105FB00000000000000000000000000000000000E1 :105FC00000000000000000000000000000000000D1 :105FD00000000000000000000000000000000000C1 :105FE00000000000000000000000000000000000B1 :105FF00000000000000000000000000000000000A1 :106000000000000000000000000000000000000090 :106010000000000000000000000000000000000080 :106020000000000000000000000000000000000070 :106030000000000000000000000000000000000060 :106040000000000000000000000000000000000050 :106050000000000000000000000000000000000040 :106060000000000000000000000000000000000030 :106070000000000000000000000000000000000020 :106080000000000000000000000000000000000010 :106090000000000000000000000000000000000000 :1060A00000000000000000000000000000000000F0 :1060B00000000000000000000000000000000000E0 :1060C00000000000000000000000000000000000D0 :1060D00000000000000000000000000000000000C0 :1060E00000000000000000000000000000000000B0 :1060F00000000000000000000000000000000000A0 :10610000000000000000000000000000000000008F :10611000000000000000000000000000000000007F :10612000000000000000000000000000000000006F :10613000000000000000000000000000000000005F :10614000000000000000000000000000000000004F :10615000000000000000000000000000000000003F :10616000000000000000000000000000000000002F :10617000000000000000000000000000000000001F :10618000000000000000000000000000000000000F :1061900000000000000000000000000000000000FF :1061A00000000000000000000000000000000000EF :1061B00000000000000000000000000000000000DF :1061C00000000000000000000000000000000000CF :1061D00000000000000000000000000000000000BF :1061E00000000000000000000000000000000000AF :1061F000000000000000000000000000000000009F :10620000000000000000000000000000000000008E :10621000000000000000000000000000000000007E :10622000000000000000000000000000000000006E :10623000000000000000000000000000000000005E :10624000000000000000000000000000000000004E :10625000000000000000000000000000000000003E :10626000000000000000000000000000000000002E :10627000000000000000000000000000000000001E :10628000000000000000000000000000000000000E :1062900000000000000000000000000000000000FE :1062A00000000000000000000000000000000000EE :1062B00000000000000000000000000000000000DE :1062C00000000000000000000000000000000000CE :1062D00000000000000000000000000000000000BE :1062E00000000000000000000000000000000000AE :1062F000000000000000000000000000000000009E :10630000000000000000000000000000000000008D :10631000000000000000000000000000000000007D :10632000000000000000000000000000000000006D :10633000000000000000000000000000000000005D :10634000000000000000000000000000000000004D :10635000000000000000000000000000000000003D :10636000000000000000000000000000000000002D :10637000000000000000000000000000000000001D :10638000000000000000000000000000000000000D :1063900000000000000000000000000000000000FD :1063A00000000000000000000000000000000000ED :1063B00000000000000000000000000000000000DD :1063C00000000000000000000000000000000000CD :1063D00000000000000000000000000000000000BD :1063E00000000000000000000000000000000000AD :1063F000000000000000000000000000000000009D :10640000000000000000000000000000000000008C :10641000000000000000000000000000000000007C :10642000000000000000000000000000000000006C :10643000000000000000000000000000000000005C :10644000000000000000000000000000000000004C :10645000000000000000000000000000000000003C :10646000000000000000000000000000000000002C :10647000000000000000000000000000000000001C :10648000000000000000000000000000000000000C :1064900000000000000000000000000000000000FC :1064A00000000000000000000000000000000000EC :1064B00000000000000000000000000000000000DC :1064C00000000000000000000000000000000000CC :1064D00000000000000000000000000000000000BC :1064E00000000000000000000000000000000000AC :1064F000000000000000000000000000000000009C :10650000000000000000000000000000000000008B :10651000000000000000000000000000000000007B :10652000000000000000000000000000000000006B :10653000000000000000000000000000000000005B :10654000000000000000000000000000000000004B :10655000000000000000000000000000000000003B :10656000000000000000000000000000000000002B :10657000000000000000000000000000000000001B :10658000000000000000000000000000000000000B :1065900000000000000000000000000000000000FB :1065A00000000000000000000000000000000000EB :1065B00000000000000000000000000000000000DB :1065C00000000000000000000000000000000000CB :1065D00000000000000000000000000000000000BB :1065E00000000000000000000000000000000000AB :1065F000000000000000000000000000000000009B :10660000000000000000000000000000000000008A :10661000000000000000000000000000000000007A :10662000000000000000000000000000000000006A :10663000000000000000000000000000000000005A :10664000000000000000000000000000000000004A :10665000000000000000000000000000000000003A :10666000000000000000000000000000000000002A :10667000000000000000000000000000000000001A :10668000000000000000000000000000000000000A :1066900000000000000000000000000000000000FA :1066A00000000000000000000000000000000000EA :1066B00000000000000000000000000000000000DA :1066C00000000000000000000000000000000000CA :1066D00000000000000000000000000000000000BA :1066E00000000000000000000000000000000000AA :1066F000000000000000000000000000000000009A :106700000000000000000000000000000000000089 :106710000000000000000000000000000000000079 :106720000000000000000000000000000000000069 :106730000000000000000000000000000000000059 :106740000000000000000000000000000000000049 :106750000000000000000000000000000000000039 :106760000000000000000000000000000000000029 :106770000000000000000000000000000000000019 :106780000000000000000000000000000000000009 :1067900000000000000000000000000000000000F9 :1067A00000000000000000000000000000000000E9 :1067B00000000000000000000000000000000000D9 :1067C00000000000000000000000000000000000C9 :1067D00000000000000000000000000000000000B9 :1067E00000000000000000000000000000000000A9 :1067F0000000000000000000000000000000000099 :106800000000000000000000000000000000000088 :106810000000000000000000000000000000000078 :106820000000000000000000000000000000000068 :106830000000000000000000000000000000000058 :106840000000000000000000000000000000000048 :106850000000000000000000000000000000000038 :106860000000000000000000000000000000000028 :106870000000000000000000000000000000000018 :106880000000000000000000000000000000000008 :1068900000000000000000000000000000000000F8 :1068A00000000000000000000000000000000000E8 :1068B00000000000000000000000000000000000D8 :1068C00000000000000000000000000000000000C8 :1068D00000000000000000000000000000000000B8 :1068E00000000000000000000000000000000000A8 :1068F0000000000000000000000000000000000098 :106900000000000000000000000000000000000087 :106910000000000000000000000000000000000077 :106920000000000000000000000000000000000067 :106930000000000000000000000000000000000057 :106940000000000000000000000000000000000047 :106950000000000000000000000000000000000037 :106960000000000000000000000000000000000027 :106970000000000000000000000000000000000017 :106980000000000000000000000000000000000007 :1069900000000000000000000000000000000000F7 :1069A00000000000000000000000000000000000E7 :1069B00000000000000000000000000000000000D7 :1069C00000000000000000000000000000000000C7 :1069D00000000000000000000000000000000000B7 :1069E00000000000000000000000000000000000A7 :1069F0000000000000000000000000000000000097 :106A00000000000000000000000000000000000086 :106A10000000000000000000000000000000000076 :106A20000000000000000000000000000000000066 :106A30000000000000000000000000000000000056 :106A40000000000000000000000000000000000046 :106A50000000000000000000000000000000000036 :106A60000000000000000000000000000000000026 :106A70000000000000000000000000000000000016 :106A80000000000000000000000000000000000006 :106A900000000000000000000000000000000000F6 :106AA00000000000000000000000000000000000E6 :106AB00000000000000000000000000000000000D6 :106AC00000000000000000000000000000000000C6 :106AD00000000000000000000000000000000000B6 :106AE00000000000000000000000000000000000A6 :106AF0000000000000000000000000000000000096 :106B00000000000000000000000000000000000085 :106B10000000000000000000000000000000000075 :106B20000000000000000000000000000000000065 :106B30000000000000000000000000000000000055 :106B40000000000000000000000000000000000045 :106B50000000000000000000000000000000000035 :106B60000000000000000000000000000000000025 :106B70000000000000000000000000000000000015 :106B80000000000000000000000000000000000005 :106B900000000000000000000000000000000000F5 :106BA00000000000000000000000000000000000E5 :106BB00000000000000000000000000000000000D5 :106BC00000000000000000000000000000000000C5 :106BD00000000000000000000000000000000000B5 :106BE00000000000000000000000000000000000A5 :106BF0000000000000000000000000000000000095 :106C00000000000000000000000000000000000084 :106C10000000000000000000000000000000000074 :106C20000000000000000000000000000000000064 :106C30000000000000000000000000000000000054 :106C40000000000000000000000000000000000044 :106C50000000000000000000000000000000000034 :106C60000000000000000000000000000000000024 :106C70000000000000000000000000000000000014 :106C80000000000000000000000000000000000004 :106C900000000000000000000000000000000000F4 :106CA00000000000000000000000000000000000E4 :106CB00000000000000000000000000000000000D4 :106CC00000000000000000000000000000000000C4 :106CD00000000000000000000000000000000000B4 :106CE00000000000000000000000000000000000A4 :106CF0000000000000000000000000000000000094 :106D00000000000000000000000000000000000083 :106D10000000000000000000000000000000000073 :106D20000000000000000000000000000000000063 :106D30000000000000000000000000000000000053 :106D40000000000000000000000000000000000043 :106D50000000000000000000000000000000000033 :106D60000000000000000000000000000000000023 :106D70000000000000000000000000000000000013 :106D80000000000000000000000000000000000003 :106D900000000000000000000000000000000000F3 :106DA00000000000000000000000000000000000E3 :106DB00000000000000000000000000000000000D3 :106DC00000000000000000000000000000000000C3 :106DD00000000000000000000000000000000000B3 :106DE00000000000000000000000000000000000A3 :106DF0000000000000000000000000000000000093 :106E00000000000000000000000000000000000082 :106E10000000000000000000000000000000000072 :106E20000000000000000000000000000000000062 :106E30000000000000000000000000000000000052 :106E40000000000000000000000000000000000042 :106E50000000000000000000000000000000000032 :106E60000000000000000000000000000000000022 :106E70000000000000000000000000000000000012 :106E80000000000000000000000000000000000002 :106E900000000000000000000000000000000000F2 :106EA00000000000000000000000000000000000E2 :106EB00000000000000000000000000000000000D2 :106EC00000000000000000000000000000000000C2 :106ED00000000000000000000000000000000000B2 :106EE00000000000000000000000000000000000A2 :106EF0000000000000000000000000000000000092 :106F00000000000000000000000000000000000081 :106F10000000000000000000000000000000000071 :106F20000000000000000000000000000000000061 :106F30000000000000000000000000000000000051 :106F40000000000000000000000000000000000041 :106F50000000000000000000000000000000000031 :106F60000000000000000000000000000000000021 :106F70000000000000000000000000000000000011 :106F80000000000000000000000000000000000001 :106F900000000000000000000000000000000000F1 :106FA00000000000000000000000000000000000E1 :106FB00000000000000000000000000000000000D1 :106FC00000000000000000000000000000000000C1 :106FD00000000000000000000000000000000000B1 :106FE00000000000000000000000000000000000A1 :106FF0000000000000000000000000000000000091 :107000000000000000000000000000000000000080 :107010000000000000000000000000000000000070 :107020000000000000000000000000000000000060 :107030000000000000000000000000000000000050 :107040000000000000000000000000000000000040 :107050000000000000000000000000000000000030 :107060000000000000000000000000000000000020 :107070000000000000000000000000000000000010 :107080000000000000000000000000000000000000 :1070900000000000000000000000000000000000F0 :1070A00000000000000000000000000000000000E0 :1070B00000000000000000000000000000000000D0 :1070C00000000000000000000000000000000000C0 :1070D00000000000000000000000000000000000B0 :1070E00000000000000000000000000000000000A0 :1070F0000000000000000000000000000000000090 :10710000000000000000000000000000000000007F :10711000000000000000000000000000000000006F :10712000000000000000000000000000000000005F :10713000000000000000000000000000000000004F :10714000000000000000000000000000000000003F :10715000000000000000000000000000000000002F :10716000000000000000000000000000000000001F :10717000000000000000000000000000000000000F :1071800000000000000000000000000000000000FF :1071900000000000000000000000000000000000EF :1071A00000000000000000000000000000000000DF :1071B00000000000000000000000000000000000CF :1071C00000000000000000000000000000000000BF :1071D00000000000000000000000000000000000AF :1071E000000000000000000000000000000000009F :1071F000000000000000000000000000000000008F :10720000000000000000000000000000000000007E :10721000000000000000000000000000000000006E :10722000000000000000000000000000000000005E :10723000000000000000000000000000000000004E :10724000000000000000000000000000000000003E :10725000000000000000000000000000000000002E :10726000000000000000000000000000000000001E :10727000000000000000000000000000000000000E :1072800000000000000000000000000000000000FE :1072900000000000000000000000000000000000EE :1072A00000000000000000000000000000000000DE :1072B00000000000000000000000000000000000CE :1072C00000000000000000000000000000000000BE :1072D00000000000000000000000000000000000AE :1072E000000000000000000000000000000000009E :1072F000000000000000000000000000000000008E :10730000000000000000000000000000000000007D :10731000000000000000000000000000000000006D :10732000000000000000000000000000000000005D :10733000000000000000000000000000000000004D :10734000000000000000000000000000000000003D :10735000000000000000000000000000000000002D :10736000000000000000000000000000000000001D :10737000000000000000000000000000000000000D :1073800000000000000000000000000000000000FD :1073900000000000000000000000000000000000ED :1073A00000000000000000000000000000000000DD :1073B00000000000000000000000000000000000CD :1073C00000000000000000000000000000000000BD :1073D00000000000000000000000000000000000AD :1073E000000000000000000000000000000000009D :1073F000000000000000000000000000000000008D :10740000000000000000000000000000000000007C :10741000000000000000000000000000000000006C :10742000000000000000000000000000000000005C :10743000000000000000000000000000000000004C :10744000000000000000000000000000000000003C :10745000000000000000000000000000000000002C :10746000000000000000000000000000000000001C :10747000000000000000000000000000000000000C :1074800000000000000000000000000000000000FC :1074900000000000000000000000000000000000EC :1074A00000000000000000000000000000000000DC :1074B00000000000000000000000000000000000CC :1074C00000000000000000000000000000000000BC :1074D00000000000000000000000000000000000AC :1074E000000000000000000000000000000000009C :1074F000000000000000000000000000000000008C :10750000000000000000000000000000000000007B :10751000000000000000000000000000000000006B :10752000000000000000000000000000000000005B :10753000000000000000000000000000000000004B :10754000000000000000000000000000000000003B :10755000000000000000000000000000000000002B :10756000000000000000000000000000000000001B :10757000000000000000000000000000000000000B :1075800000000000000000000000000000000000FB :1075900000000000000000000000000000000000EB :1075A00000000000000000000000000000000000DB :1075B00000000000000000000000000000000000CB :1075C00000000000000000000000000000000000BB :1075D00000000000000000000000000000000000AB :1075E000000000000000000000000000000000009B :1075F000000000000000000000000000000000008B :10760000000000000000000000000000000000007A :10761000000000000000000000000000000000006A :10762000000000000000000000000000000000005A :10763000000000000000000000000000000000004A :10764000000000000000000000000000000000003A :10765000000000000000000000000000000000002A :10766000000000000000000000000000000000001A :10767000000000000000000000000000000000000A :1076800000000000000000000000000000000000FA :1076900000000000000000000000000000000000EA :1076A00000000000000000000000000000000000DA :1076B00000000000000000000000000000000000CA :1076C00000000000000000000000000000000000BA :1076D00000000000000000000000000000000000AA :1076E000000000000000000000000000000000009A :1076F000000000000000000000000000000000008A :107700000000000000000000000000000000000079 :107710000000000000000000000000000000000069 :107720000000000000000000000000000000000059 :107730000000000000000000000000000000000049 :107740000000000000000000000000000000000039 :107750000000000000000000000000000000000029 :107760000000000000000000000000000000000019 :107770000000000000000000000000000000000009 :1077800000000000000000000000000000000000F9 :1077900000000000000000000000000000000000E9 :1077A00000000000000000000000000000000000D9 :1077B00000000000000000000000000000000000C9 :1077C00000000000000000000000000000000000B9 :1077D00000000000000000000000000000000000A9 :1077E0000000000000000000000000000000000099 :1077F0000000000000000000000000000000000089 :107800000000000000000000000000000000000078 :107810000000000000000000000000000000000068 :107820000000000000000000000000000000000058 :107830000000000000000000000000000000000048 :107840000000000000000000000000000000000038 :107850000000000000000000000000000000000028 :107860000000000000000000000000000000000018 :107870000000000000000000000000000000000008 :1078800000000000000000000000000000000000F8 :1078900000000000000000000000000000000000E8 :1078A00000000000000000000000000000000000D8 :1078B00000000000000000000000000000000000C8 :1078C00000000000000000000000000000000000B8 :1078D00000000000000000000000000000000000A8 :1078E0000000000000000000000000000000000098 :1078F0000000000000000000000000000000000088 :107900000000000000000000000000000000000077 :107910000000000000000000000000000000000067 :107920000000000000000000000000000000000057 :107930000000000000000000000000000000000047 :107940000000000000000000000000000000000037 :107950000000000000000000000000000000000027 :107960000000000000000000000000000000000017 :107970000000000000000000000000000000000007 :1079800000000000000000000000000000000000F7 :1079900000000000000000000000000000000000E7 :1079A00000000000000000000000000000000000D7 :1079B00000000000000000000000000000000000C7 :1079C00000000000000000000000000000000000B7 :1079D00000000000000000000000000000000000A7 :1079E0000000000000000000000000000000000097 :1079F0000000000000000000000000000000000087 :107A00000000000000000000000000000000000076 :107A10000000000000000000000000000000000066 :107A20000000000000000000000000000000000056 :107A30000000000000000000000000000000000046 :107A40000000000000000000000000000000000036 :107A50000000000000000000000000000000000026 :107A60000000000000000000000000000000000016 :107A70000000000000000000000000000000000006 :107A800000000000000000000000000000000000F6 :107A900000000000000000000000000000000000E6 :107AA00000000000000000000000000000000000D6 :107AB00000000000000000000000000000000000C6 :107AC00000000000000000000000000000000000B6 :107AD00000000000000000000000000000000000A6 :107AE0000000000000000000000000000000000096 :107AF0000000000000000000000000000000000086 :107B00000000000000000000000000000000000075 :107B10000000000000000000000000000000000065 :107B20000000000000000000000000000000000055 :107B30000000000000000000000000000000000045 :107B40000000000000000000000000000000000035 :107B50000000000000000000000000000000000025 :107B60000000000000000000000000000000000015 :107B70000000000000000000000000000000000005 :107B800000000000000000000000000000000000F5 :107B900000000000000000000000000000000000E5 :107BA00000000000000000000000000000000000D5 :107BB00000000000000000000000000000000000C5 :107BC00000000000000000000000000000000000B5 :107BD00000000000000000000000000000000000A5 :107BE0000000000000000000000000000000000095 :107BF0000000000000000000000000000000000085 :107C00000000000000000000000000000000000074 :107C10000000000000000000000000000000000064 :107C20000000000000000000000000000000000054 :107C30000000000000000000000000000000000044 :107C40000000000000000000000000000000000034 :107C50000000000000000000000000000000000024 :107C60000000000000000000000000000000000014 :107C70000000000000000000000000000000000004 :107C800000000000000000000000000000000000F4 :107C900000000000000000000000000000000000E4 :107CA00000000000000000000000000000000000D4 :107CB00000000000000000000000000000000000C4 :107CC00000000000000000000000000000000000B4 :107CD00000000000000000000000000000000000A4 :107CE0000000000000000000000000000000000094 :107CF0000000000000000000000000000000000084 :107D00000000000000000000000000000000000073 :107D10000000000000000000000000000000000063 :107D20000000000000000000000000000000000053 :107D30000000000000000000000000000000000043 :107D40000000000000000000000000000000000033 :107D50000000000000000000000000000000000023 :107D60000000000000000000000000000000000013 :107D70000000000000000000000000000000000003 :107D800000000000000000000000000000000000F3 :107D900000000000000000000000000000000000E3 :107DA00000000000000000000000000000000000D3 :107DB00000000000000000000000000000000000C3 :107DC00000000000000000000000000000000000B3 :107DD00000000000000000000000000000000000A3 :107DE0000000000000000000000000000000000093 :107DF0000000000000000000000000000000000083 :107E00000000000000000000000000000000000072 :107E10000000000000000000000000000000000062 :107E20000000000000000000000000000000000052 :107E30000000000000000000000000000000000042 :107E40000000000000000000000000000000000032 :107E50000000000000000000000000000000000022 :107E60000000000000000000000000000000000012 :107E70000000000000000000000000000000000002 :107E800000000000000000000000000000000000F2 :107E900000000000000000000000000000000000E2 :107EA00000000000000000000000000000000000D2 :107EB00000000000000000000000000000000000C2 :107EC00000000000000000000000000000000000B2 :107ED00000000000000000000000000000000000A2 :107EE0000000000000000000000000000000000092 :107EF0000000000000000000000000000000000082 :107F00000000000000000000000000000000000071 :107F10000000000000000000000000000000000061 :107F20000000000000000000000000000000000051 :107F30000000000000000000000000000000000041 :107F40000000000000000000000000000000000031 :107F50000000000000000000000000000000000021 :107F60000000000000000000000000000000000011 :107F70000000000000000000000000000000000001 :107F800000000000000000000000000000000000F1 :107F900000000000000000000000000000000000E1 :107FA00000000000000000000000000000000000D1 :107FB00000000000000000000000000000000000C1 :107FC00000000000000000000000000000000000B1 :107FD00000000000000000000000000000000000A1 :107FE0000000000000000000000000000000000091 :107FF0000000000000000000000000000000000081 :108000000000000000000000000000000000000070 :108010000000000000000000000000000000000060 :108020000000000000000000000000000000000050 :108030000000000000000000000000000000000040 :108040000000000000000000000000000000000030 :108050000000000000000000000000000000000020 :108060000000000000000000000000000000000010 :108070000000000000000000000000000000000000 :1080800000000000000000000000000000000000F0 :1080900000000000000000000000000000000000E0 :1080A00000000000000000000000000000000000D0 :1080B00000000000000000000000000000000000C0 :1080C00000000000000000000000000000000000B0 :1080D00000000000000000000000000000000000A0 :1080E0000000000000000000000000000000000090 :1080F0000000000000000000000000000000000080 :10810000000000000000000000000000000000006F :10811000000000000000000000000000000000005F :10812000000000000000000000000000000000004F :10813000000000000000000000000000000000003F :10814000000000000000000000000000000000002F :10815000000000000000000000000000000000001F :10816000000000000000000000000000000000000F :1081700000000000000000000000000000000000FF :1081800000000000000000000000000000000000EF :1081900000000000000000000000000000000000DF :1081A00000000000000000000000000000000000CF :1081B00000000000000000000000000000000000BF :1081C00000000000000000000000000000000000AF :1081D000000000000000000000000000000000009F :1081E000000000000000000000000000000000008F :1081F000000000000000000000000000000000007F :10820000000000000000000000000000000000006E :10821000000000000000000000000000000000005E :10822000000000000000000000000000000000004E :10823000000000000000000000000000000000003E :10824000000000000000000000000000000000002E :10825000000000000000000000000000000000001E :10826000000000000000000000000000000000000E :1082700000000000000000000000000000000000FE :1082800000000000000000000000000000000000EE :1082900000000000000000000000000000000000DE :1082A00000000000000000000000000000000000CE :1082B00000000000000000000000000000000000BE :1082C00000000000000000000000000000000000AE :1082D000000000000000000000000000000000009E :1082E000000000000000000000000000000000008E :1082F000000000000000000000000000000000007E :10830000000000000000000000000000000000006D :10831000000000000000000000000000000000005D :10832000000000000000000000000000000000004D :10833000000000000000000000000000000000003D :10834000000000000000000000000000000000002D :10835000000000000000000000000000000000001D :10836000000000000000000000000000000000000D :1083700000000000000000000000000000000000FD :1083800000000000000000000000000000000000ED :1083900000000000000000000000000000000000DD :1083A00000000000000000000000000000000000CD :1083B00000000000000000000000000000000000BD :1083C00000000000000000000000000000000000AD :1083D000000000000000000000000000000000009D :1083E000000000000000000000000000000000008D :1083F000000000000000000000000000000000007D :10840000000000000000000000000000000000006C :10841000000000000000000000000000000000005C :10842000000000000000000000000000000000004C :10843000000000000000000000000000000000003C :10844000000000000000000000000000000000002C :10845000000000000000000000000000000000001C :10846000000000000000000000000000000000000C :1084700000000000000000000000000000000000FC :1084800000000000000000000000000000000000EC :1084900000000000000000000000000000000000DC :1084A00000000000000000000000000000000000CC :1084B00000000000000000000000000000000000BC :1084C00000000000000000000000000000000000AC :1084D000000000000000000000000000000000009C :1084E000000000000000000000000000000000008C :1084F000000000000000000000000000000000007C :10850000000000000000000000000000000000006B :10851000000000000000000000000000000000005B :10852000000000000000000000000000000000004B :10853000000000000000000000000000000000003B :10854000000000000000000000000000000000002B :10855000000000000000000000000000000000001B :10856000000000000000000000000000000000000B :1085700000000000000000000000000000000000FB :1085800000000000000000000000000000000000EB :1085900000000000000000000000000000000000DB :1085A00000000000000000000000000000000000CB :1085B00000000000000000000000000000000000BB :1085C00000000000000000000000000000000000AB :1085D000000000000000000000000000000000009B :1085E000000000000000000000000000000000008B :1085F000000000000000000000000000000000007B :10860000000000000000000000000000000000006A :10861000000000000000000000000000000000005A :10862000000000000000000000000000000000004A :10863000000000000000000000000000000000003A :10864000000000000000000000000000000000002A :10865000000000000000000000000000000000001A :10866000000000000000000000000000000000000A :1086700000000000000000000000000000000000FA :1086800000000000000000000000000000000000EA :1086900000000000000000000000000000000000DA :1086A00000000000000000000000000000000000CA :1086B00000000000000000000000000000000000BA :1086C00000000000000000000000000000000000AA :1086D000000000000000000000000000000000009A :1086E000000000000000000000000000000000008A :1086F000000000000000000000000000000000007A :108700000000000000000000000000000000000069 :108710000000000000000000000000000000000059 :108720000000000000000000000000000000000049 :108730000000000000000000000000000000000039 :108740000000000000000000000000000000000029 :108750000000000000000000000000000000000019 :108760000000000000000000000000000000000009 :1087700000000000000000000000000000000000F9 :1087800000000000000000000000000000000000E9 :1087900000000000000000000000000000000000D9 :1087A00000000000000000000000000000000000C9 :1087B00000000000000000000000000000000000B9 :1087C00000000000000000000000000000000000A9 :1087D0000000000000000000000000000000000099 :1087E0000000000000000000000000000000000089 :1087F0000000000000000000000000000000000079 :108800000000000000000000000000000000000068 :108810000000000000000000000000000000000058 :108820000000000000000000000000000000000048 :108830000000000000000000000000000000000038 :108840000000000000000000000000000000000028 :108850000000000000000000000000000000000018 :108860000000000000000000000000000000000008 :1088700000000000000000000000000000000000F8 :1088800000000000000000000000000000000000E8 :1088900000000000000000000000000000000000D8 :1088A00000000000000000000000000000000000C8 :1088B00000000000000000000000000000000000B8 :1088C00000000000000000000000000000000000A8 :1088D0000000000000000000000000000000000098 :1088E0000000000000000000000000000000000088 :1088F0000000000000000000000000000000000078 :108900000000000000000000000000000000000067 :108910000000000000000000000000000000000057 :108920000000000000000000000000000000000047 :108930000000000000000000000000000000000037 :108940000000000000000000000000000000000027 :108950000000000000000000000000000000000017 :108960000000000000000000000000000000000007 :1089700000000000000000000000000000000000F7 :1089800000000000000000000000000000000000E7 :1089900000000000000000000000000000000000D7 :1089A00000000000000000000000000000000000C7 :1089B00000000000000000000000000000000000B7 :1089C00000000000000000000000000000000000A7 :1089D0000000000000000000000000000000000097 :1089E0000000000000000000000000000000000087 :1089F0000000000000000000000000000000000077 :108A00000000000000000000000000000000000066 :108A10000000000000000000000000000000000056 :108A20000000000000000000000000000000000046 :108A30000000000000000000000000000000000036 :108A40000000000000000000000000000000000026 :108A50000000000000000000000000000000000016 :108A60000000000000000000000000000000000006 :108A700000000000000000000000000000000000F6 :108A800000000000000000000000000000000000E6 :108A900000000000000000000000000000000000D6 :108AA00000000000000000000000000000000000C6 :108AB00000000000000000000000000000000000B6 :108AC00000000000000000000000000000000000A6 :108AD0000000000000000000000000000000000096 :108AE0000000000000000000000000000000000086 :108AF0000000000000000000000000000000000076 :108B00000000000000000000000000000000000065 :108B10000000000000000000000000000000000055 :108B20000000000000000000000000000000000045 :108B30000000000000000000000000000000000035 :108B40000000000000000000000000000000000025 :108B50000000000000000000000000000000000015 :108B60000000000000000000000000000000000005 :108B700000000000000000000000000000000000F5 :108B800000000000000000000000000000000000E5 :108B900000000000000000000000000000000000D5 :108BA00000000000000000000000000000000000C5 :108BB00000000000000000000000000000000000B5 :108BC00000000000000000000000000000000000A5 :108BD0000000000000000000000000000000000095 :108BE0000000000000000000000000000000000085 :108BF0000000000000000000000000000000000075 :108C00000000000000000000000000000000000064 :108C10000000000000000000000000000000000054 :108C20000000000000000000000000000000000044 :108C30000000000000000000000000000000000034 :108C40000000000000000000000000000000000024 :108C50000000000000000000000000000000000014 :108C60000000000000000000000000000000000004 :108C700000000000000000000000000000000000F4 :108C800000000000000000000000000000000000E4 :108C900000000000000000000000000000000000D4 :108CA00000000000000000000000000000000000C4 :108CB00000000000000000000000000000000000B4 :108CC00000000000000000000000000000000000A4 :108CD0000000000000000000000000000000000094 :108CE0000000000000000000000000000000000084 :108CF0000000000000000000000000000000000074 :108D00000000000000000000000000000000000063 :108D10000000000000000000000000000000000053 :108D20000000000000000000000000000000000043 :108D30000000000000000000000000000000000033 :108D40000000000000000000000000000000000023 :108D50000000000000000000000000000000000013 :108D60000000000000000000000000000000000003 :108D700000000000000000000000000000000000F3 :108D800000000000000000000000000000000000E3 :108D900000000000000000000000000000000000D3 :108DA00000000000000000000000000000000000C3 :108DB00000000000000000000000000000000000B3 :108DC00000000000000000000000000000000000A3 :108DD0000000000000000000000000000000000093 :108DE0000000000000000000000000000000000083 :108DF0000000000000000000000000000000000073 :108E00000000000000000000000000000000000062 :108E10000000000000000000000000000000000052 :108E20000000000000000000000000000000000042 :108E30000000000000000000000000000000000032 :108E40000000000000000000000000000000000022 :108E50000000000000000000000000000000000012 :108E60000000000000000000000000000000000002 :108E700000000000000000000000000000000000F2 :108E800000000000000000000000000000000000E2 :108E900000000000000000000000000000000000D2 :108EA00000000000000000000000000000000000C2 :108EB00000000000000000000000000000000000B2 :108EC00000000000000000000000000000000000A2 :108ED0000000000000000000000000000000000092 :108EE0000000000000000000000000000000000082 :108EF0000000000000000000000000000000000072 :108F00000000000000000000000000000000000061 :108F10000000000000000000000000000000000051 :108F20000000000000000000000000000000000041 :108F30000000000000000000000000000000000031 :108F40000000000000000000000000000000000021 :108F50000000000000000000000000000000000011 :108F60000000000000000000000000000000000001 :108F700000000000000000000000000000000000F1 :108F800000000000000000000000000000000000E1 :108F900000000000000000000000000000000000D1 :108FA00000000000000000000000000000000000C1 :108FB00000000000000000000000000000000000B1 :108FC00000000000000000000000000000000000A1 :108FD0000000000000000000000000000000000091 :108FE0000000000000000000000000000000000081 :108FF0000000000000000000000000000000000071 :109000000000000000000000000000000000000060 :109010000000000000000000000000000000000050 :109020000000000000000000000000000000000040 :109030000000000000000000000000000000000030 :109040000000000000000000000000000000000020 :109050000000000000000000000000000000000010 :109060000000000000000000000000000000000000 :1090700000000000000000000000000000000000F0 :1090800000000000000000000000000000000000E0 :1090900000000000000000000000000000000000D0 :1090A00000000000000000000000000000000000C0 :1090B00000000000000000000000000000000000B0 :1090C00000000000000000000000000000000000A0 :1090D0000000000000000000000000000000000090 :1090E0000000000000000000000000000000000080 :1090F0000000000000000000000000000000000070 :10910000000000000000000000000000000000005F :10911000000000000000000000000000000000004F :10912000000000000000000000000000000000003F :10913000000000000000000000000000000000002F :10914000000000000000000000000000000000001F :10915000000000000000000000000000000000000F :1091600000000000000000000000000000000000FF :1091700000000000000000000000000000000000EF :1091800000000000000000000000000000000000DF :1091900000000000000000000000000000000000CF :1091A00000000000000000000000000000000000BF :1091B00000000000000000000000000000000000AF :1091C000000000000000000000000000000000009F :1091D000000000000000000000000000000000008F :1091E000000000000000000000000000000000007F :1091F000000000000000000000000000000000006F :10920000000000000000000000000000000000005E :10921000000000000000000000000000000000004E :10922000000000000000000000000000000000003E :10923000000000000000000000000000000000002E :10924000000000000000000000000000000000001E :10925000000000000000000000000000000000000E :1092600000000000000000000000000000000000FE :1092700000000000000000000000000000000000EE :1092800000000000000000000000000000000000DE :1092900000000000000000000000000000000000CE :1092A00000000000000000000000000000000000BE :1092B00000000000000000000000000000000000AE :1092C000000000000000000000000000000000009E :1092D000000000000000000000000000000000008E :1092E000000000000000000000000000000000007E :1092F000000000000000000000000000000000006E :10930000000000000000000000000000000000005D :10931000000000000000000000000000000000004D :10932000000000000000000000000000000000003D :10933000000000000000000000000000000000002D :10934000000000000000000000000000000000001D :10935000000000000000000000000000000000000D :1093600000000000000000000000000000000000FD :1093700000000000000000000000000000000000ED :1093800000000000000000000000000000000000DD :1093900000000000000000000000000000000000CD :1093A00000000000000000000000000000000000BD :1093B00000000000000000000000000000000000AD :1093C000000000000000000000000000000000009D :1093D000000000000000000000000000000000008D :1093E000000000000000000000000000000000007D :1093F000000000000000000000000000000000006D :10940000000000000000000000000000000000005C :10941000000000000000000000000000000000004C :10942000000000000000000000000000000000003C :10943000000000000000000000000000000000002C :10944000000000000000000000000000000000001C :10945000000000000000000000000000000000000C :1094600000000000000000000000000000000000FC :1094700000000000000000000000000000000000EC :1094800000000000000000000000000000000000DC :1094900000000000000000000000000000000000CC :1094A00000000000000000000000000000000000BC :1094B00000000000000000000000000000000000AC :1094C000000000000000000000000000000000009C :1094D000000000000000000000000000000000008C :1094E000000000000000000000000000000000007C :1094F000000000000000000000000000000000006C :10950000000000000000000000000000000000005B :10951000000000000000000000000000000000004B :10952000000000000000000000000000000000003B :10953000000000000000000000000000000000002B :10954000000000000000000000000000000000001B :10955000000000000000000000000000000000000B :1095600000000000000000000000000000000000FB :1095700000000000000000000000000000000000EB :1095800000000000000000000000000000000000DB :1095900000000000000000000000000000000000CB :1095A00000000000000000000000000000000000BB :1095B00000000000000000000000000000000000AB :1095C000000000000000000000000000000000009B :1095D000000000000000000000000000000000008B :1095E000000000000000000000000000000000007B :1095F000000000000000000000000000000000006B :10960000000000000000000000000000000000005A :10961000000000000000000000000000000000004A :10962000000000000000000000000000000000003A :10963000000000000000000000000000000000002A :10964000000000000000000000000000000000001A :10965000000000000000000000000000000000000A :1096600000000000000000000000000000000000FA :1096700000000000000000000000000000000000EA :1096800000000000000000000000000000000000DA :1096900000000000000000000000000000000000CA :1096A00000000000000000000000000000000000BA :1096B00000000000000000000000000000000000AA :1096C000000000000000000000000000000000009A :1096D000000000000000000000000000000000008A :1096E000000000000000000000000000000000007A :1096F000000000000000000000000000000000006A :109700000000000000000000000000000000000059 :109710000000000000000000000000000000000049 :109720000000000000000000000000000000000039 :109730000000000000000000000000000000000029 :109740000000000000000000000000000000000019 :109750000000000000000000000000000000000009 :1097600000000000000000000000000000000000F9 :1097700000000000000000000000000000000000E9 :1097800000000000000000000000000000000000D9 :1097900000000000000000000000000000000000C9 :1097A00000000000000000000000000000000000B9 :1097B00000000000000000000000000000000000A9 :1097C0000000000000000000000000000000000099 :1097D0000000000000000000000000000000000089 :1097E0000000000000000000000000000000000079 :1097F0000000000000000000000000000000000069 :109800000000000000000000000000000000000058 :109810000000000000000000000000000000000048 :109820000000000000000000000000000000000038 :109830000000000000000000000000000000000028 :109840000000000000000000000000000000000018 :109850000000000000000000000000000000000008 :1098600000000000000000000000000000000000F8 :1098700000000000000000000000000000000000E8 :1098800000000000000000000000000000000000D8 :1098900000000000000000000000000000000000C8 :1098A00000000000000000000000000000000000B8 :1098B00000000000000000000000000000000000A8 :1098C0000000000000000000000000000000000098 :1098D0000000000000000000000000000000000088 :1098E0000000000000000000000000000000000078 :1098F0000000000000000000000000000000000068 :109900000000000000000000000000000000000057 :109910000000000000000000000000000000000047 :109920000000000000000000000000000000000037 :109930000000000000000000000000000000000027 :109940000000000000000000000000000000000017 :109950000000000000000000000000000000000007 :1099600000000000000000000000000000000000F7 :1099700000000000000000000000000000000000E7 :1099800000000000000000000000000000000000D7 :1099900000000000000000000000000000000000C7 :1099A00000000000000000000000000000000000B7 :1099B00000000000000000000000000000000000A7 :1099C0000000000000000000000000000000000097 :1099D0000000000000000000000000000000000087 :1099E0000000000000000000000000000000000077 :1099F0000000000000000000000000000000000067 :109A00000000000000000000000000000000000056 :109A10000000000000000000000000000000000046 :109A20000000000000000000000000000000000036 :109A30000000000000000000000000000000000026 :109A40000000000000000000000000000000000016 :109A50000000000000000000000000000000000006 :109A600000000000000000000000000000000000F6 :109A700000000000000000000000000000000000E6 :109A800000000000000000000000000000000000D6 :109A900000000000000000000000000000000000C6 :109AA00000000000000000000000000000000000B6 :109AB00000000000000000000000000000000000A6 :109AC0000000000000000000000000000000000096 :109AD0000000000000000000000000000000000086 :109AE0000000000000000000000000000000000076 :109AF0000000000000000000000000000000000066 :109B00000000000000000000000000000000000055 :109B10000000000000000000000000000000000045 :109B20000000000000000000000000000000000035 :109B30000000000000000000000000000000000025 :109B40000000000000000000000000000000000015 :109B50000000000000000000000000000000000005 :109B600000000000000000000000000000000000F5 :109B700000000000000000000000000000000000E5 :109B800000000000000000000000000000000000D5 :109B900000000000000000000000000000000000C5 :109BA00000000000000000000000000000000000B5 :109BB00000000000000000000000000000000000A5 :109BC0000000000000000000000000000000000095 :109BD0000000000000000000000000000000000085 :109BE0000000000000000000000000000000000075 :109BF0000000000000000000000000000000000065 :109C00000000000000000000000000000000000054 :109C10000000000000000000000000000000000044 :109C20000000000000000000000000000000000034 :109C30000000000000000000000000000000000024 :109C40000000000000000000000000000000000014 :109C50000000000000000000000000000000000004 :109C600000000000000000000000000000000000F4 :109C700000000000000000000000000000000000E4 :109C800000000000000000000000000000000000D4 :109C900000000000000000000000000000000000C4 :109CA00000000000000000000000000000000000B4 :109CB00000000000000000000000000000000000A4 :109CC0000000000000000000000000000000000094 :109CD0000000000000000000000000000000000084 :109CE0000000000000000000000000000000000074 :109CF0000000000000000000000000000000000064 :109D00000000000000000000000000000000000053 :109D10000000000000000000000000000000000043 :109D20000000000000000000000000000000000033 :109D30000000000000000000000000000000000023 :109D40000000000000000000000000000000000013 :109D50000000000000000000000000000000000003 :109D600000000000000000000000000000000000F3 :109D700000000000000000000000000000000000E3 :109D800000000000000000000000000000000000D3 :109D900000000000000000000000000000000000C3 :109DA00000000000000000000000000000000000B3 :109DB00000000000000000000000000000000000A3 :109DC0000000000000000000000000000000000093 :109DD0000000000000000000000000000000000083 :109DE0000000000000000000000000000000000073 :109DF0000000000000000000000000000000000063 :109E00000000000000000000000000000000000052 :109E10000000000000000000000000000000000042 :109E20000000000000000000000000000000000032 :109E30000000000000000000000000000000000022 :109E40000000000000000000000000000000000012 :109E50000000000000000000000000000000000002 :109E600000000000000000000000000000000000F2 :109E700000000000000000000000000000000000E2 :109E800000000000000000000000000000000000D2 :109E900000000000000000000000000000000000C2 :109EA00000000000000000000000000000000000B2 :109EB00000000000000000000000000000000000A2 :109EC0000000000000000000000000000000000092 :109ED0000000000000000000000000000000000082 :109EE0000000000000000000000000000000000072 :109EF0000000000000000000000000000000000062 :109F00000000000000000000000000000000000051 :109F10000000000000000000000000000000000041 :109F20000000000000000000000000000000000031 :109F30000000000000000000000000000000000021 :109F40000000000000000000000000000000000011 :109F50000000000000000000000000000000000001 :109F600000000000000000000000000000000000F1 :109F700000000000000000000000000000000000E1 :109F800000000000000000000000000000000000D1 :109F900000000000000000000000000000000000C1 :109FA00000000000000000000000000000000000B1 :109FB00000000000000000000000000000000000A1 :109FC0000000000000000000000000000000000091 :109FD0000000000000000000000000000000000081 :109FE0000000000000000000000000000000000071 :109FF0000000000000000000000000000000000061 :10A000000000000000000000000000000000000050 :10A010000000000000000000000000000000000040 :10A020000000000000000000000000000000000030 :10A030000000000000000000000000000000000020 :10A040000000000000000000000000000000000010 :10A050000000000000000000000000000000000000 :10A0600000000000000000000000000000000000F0 :10A0700000000000000000000000000000000000E0 :10A0800000000000000000000000000000000000D0 :10A0900000000000000000000000000000000000C0 :10A0A00000000000000000000000000000000000B0 :10A0B00000000000000000000000000000000000A0 :10A0C0000000000000000000000000000000000090 :10A0D0000000000000000000000000000000000080 :10A0E0000000000000000000000000000000000070 :10A0F0000000000000000000000000000000000060 :10A10000000000000000000000000000000000004F :10A11000000000000000000000000000000000003F :10A12000000000000000000000000000000000002F :10A13000000000000000000000000000000000001F :10A14000000000000000000000000000000000000F :10A1500000000000000000000000000000000000FF :10A1600000000000000000000000000000000000EF :10A1700000000000000000000000000000000000DF :10A1800000000000000000000000000000000000CF :10A1900000000000000000000000000000000000BF :10A1A00000000000000000000000000000000000AF :10A1B000000000000000000000000000000000009F :10A1C000000000000000000000000000000000008F :10A1D000000000000000000000000000000000007F :10A1E000000000000000000000000000000000006F :10A1F000000000000000000000000000000000005F :10A20000000000000000000000000000000000004E :10A21000000000000000000000000000000000003E :10A22000000000000000000000000000000000002E :10A23000000000000000000000000000000000001E :10A24000000000000000000000000000000000000E :10A2500000000000000000000000000000000000FE :10A2600000000000000000000000000000000000EE :10A2700000000000000000000000000000000000DE :10A2800000000000000000000000000000000000CE :10A2900000000000000000000000000000000000BE :10A2A00000000000000000000000000000000000AE :10A2B000000000000000000000000000000000009E :10A2C000000000000000000000000000000000008E :10A2D000000000000000000000000000000000007E :10A2E000000000000000000000000000000000006E :10A2F000000000000000000000000000000000005E :10A30000000000000000000000000000000000004D :10A31000000000000000000000000000000000003D :10A32000000000000000000000000000000000002D :10A33000000000000000000000000000000000001D :10A34000000000000000000000000000000000000D :10A3500000000000000000000000000000000000FD :10A3600000000000000000000000000000000000ED :10A3700000000000000000000000000000000000DD :10A3800000000000000000000000000000000000CD :10A3900000000000000000000000000000000000BD :10A3A00000000000000000000000000000000000AD :10A3B000000000000000000000000000000000009D :10A3C000000000000000000000000000000000008D :10A3D000000000000000000000000000000000007D :10A3E000000000000000000000000000000000006D :10A3F000000000000000000000000000000000005D :10A40000000000000000000000000000000000004C :10A41000000000000000000000000000000000003C :10A42000000000000000000000000000000000002C :10A43000000000000000000000000000000000001C :10A44000000000000000000000000000000000000C :10A4500000000000000000000000000000000000FC :10A4600000000000000000000000000000000000EC :10A4700000000000000000000000000000000000DC :10A4800000000000000000000000000000000000CC :10A4900000000000000000000000000000000000BC :10A4A00000000000000000000000000000000000AC :10A4B000000000000000000000000000000000009C :10A4C000000000000000000000000000000000008C :10A4D000000000000000000000000000000000007C :10A4E000000000000000000000000000000000006C :10A4F000000000000000000000000000000000005C :10A50000000000000000000000000000000000004B :10A51000000000000000000000000000000000003B :10A52000000000000000000000000000000000002B :10A53000000000000000000000000000000000001B :10A54000000000000000000000000000000000000B :10A5500000000000000000000000000000000000FB :10A5600000000000000000000000000000000000EB :10A5700000000000000000000000000000000000DB :10A5800000000000000000000000000000000000CB :10A5900000000000000000000000000000000000BB :10A5A00000000000000000000000000000000000AB :10A5B000000000000000000000000000000000009B :10A5C000000000000000000000000000000000008B :10A5D000000000000000000000000000000000007B :10A5E000000000000000000000000000000000006B :10A5F000000000000000000000000000000000005B :10A60000000000000000000000000000000000004A :10A61000000000000000000000000000000000003A :10A62000000000000000000000000000000000002A :10A63000000000000000000000000000000000001A :10A64000000000000000000000000000000000000A :10A6500000000000000000000000000000000000FA :10A6600000000000000000000000000000000000EA :10A6700000000000000000000000000000000000DA :10A6800000000000000000000000000000000000CA :10A6900000000000000000000000000000000000BA :10A6A00000000000000000000000000000000000AA :10A6B000000000000000000000000000000000009A :10A6C000000000000000000000000000000000008A :10A6D000000000000000000000000000000000007A :10A6E000000000000000000000000000000000006A :10A6F000000000000000000000000000000000005A :10A700000000000000000000000000000000000049 :10A710000000000000000000000000000000000039 :10A720000000000000000000000000000000000029 :10A730000000000000000000000000000000000019 :10A740000000000000000000000000000000000009 :10A7500000000000000000000000000000000000F9 :10A7600000000000000000000000000000000000E9 :10A7700000000000000000000000000000000000D9 :10A7800000000000000000000000000000000000C9 :10A7900000000000000000000000000000000000B9 :10A7A00000000000000000000000000000000000A9 :10A7B0000000000000000000000000000000000099 :10A7C0000000000000000000000000000000000089 :10A7D0000000000000000000000000000000000079 :10A7E0000000000000000000000000000000000069 :10A7F0000000000000000000000000000000000059 :10A800000000000000000000000000000000000048 :10A810000000000000000000000000000000000038 :10A820000000000000000000000000000000000028 :10A830000000000000000000000000000000000018 :10A840000000000000000000000000000000000008 :10A8500000000000000000000000000000000000F8 :10A8600000000000000000000000000000000000E8 :10A8700000000000000000000000000000000000D8 :10A8800000000000000000000000000000000000C8 :10A8900000000000000000000000000000000000B8 :10A8A00000000000000000000000000000000000A8 :10A8B0000000000000000000000000000000000098 :10A8C0000000000000000000000000000000000088 :10A8D0000000000000000000000000000000000078 :10A8E0000000000000000000000000000000000068 :10A8F0000000000000000000000000000000000058 :10A900000000000000000000000000000000000047 :10A910000000000000000000000000000000000037 :10A920000000000000000000000000000000000027 :10A930000000000000000000000000000000000017 :10A940000000000000000000000000000000000007 :10A9500000000000000000000000000000000000F7 :10A9600000000000000000000000000000000000E7 :10A9700000000000000000000000000000000000D7 :10A9800000000000000000000000000000000000C7 :10A9900000000000000000000000000000000000B7 :10A9A00000000000000000000000000000000000A7 :10A9B0000000000000000000000000000000000097 :10A9C0000000000000000000000000000000000087 :10A9D0000000000000000000000000000000000077 :10A9E0000000000000000000000000000000000067 :10A9F0000000000000000000000000000000000057 :10AA00000000000000000000000000000000000046 :10AA10000000000000000000000000000000000036 :10AA20000000000000000000000000000000000026 :10AA30000000000000000000000000000000000016 :10AA40000000000000000000000000000000000006 :10AA500000000000000000000000000000000000F6 :10AA600000000000000000000000000000000000E6 :10AA700000000000000000000000000000000000D6 :10AA800000000000000000000000000000000000C6 :10AA900000000000000000000000000000000000B6 :10AAA00000000000000000000000000000000000A6 :10AAB0000000000000000000000000000000000096 :10AAC0000000000000000000000000000000000086 :10AAD0000000000000000000000000000000000076 :10AAE0000000000000000000000000000000000066 :10AAF0000000000000000000000000000000000056 :10AB00000000000000000000000000000000000045 :10AB10000000000000000000000000000000000035 :10AB20000000000000000000000000000000000025 :10AB30000000000000000000000000000000000015 :10AB40000000000000000000000000000000000005 :10AB500000000000000000000000000000000000F5 :10AB600000000000000000000000000000000000E5 :10AB700000000000000000000000000000000000D5 :10AB800000000000000000000000000000000000C5 :10AB900000000000000000000000000000000000B5 :10ABA00000000000000000000000000000000000A5 :10ABB0000000000000000000000000000000000095 :10ABC0000000000000000000000000000000000085 :10ABD0000000000000000000000000000000000075 :10ABE0000000000000000000000000000000000065 :10ABF0000000000000000000000000000000000055 :10AC00000000000000000000000000000000000044 :10AC10000000000000000000000000000000000034 :10AC20000000000000000000000000000000000024 :10AC30000000000000000000000000000000000014 :10AC40000000000000000000000000000000000004 :10AC500000000000000000000000000000000000F4 :10AC600000000000000000000000000000000000E4 :10AC700000000000000000000000000000000000D4 :10AC800000000000000000000000000000000000C4 :10AC900000000000000000000000000000000000B4 :10ACA00000000000000000000000000000000000A4 :10ACB0000000000000000000000000000000000094 :10ACC0000000000000000000000000000000000084 :10ACD0000000000000000000000000000000000074 :10ACE0000000000000000000000000000000000064 :10ACF0000000000000000000000000000000000054 :10AD00000000000000000000000000000000000043 :10AD10000000000000000000000000000000000033 :10AD20000000000000000000000000000000000023 :10AD30000000000000000000000000000000000013 :10AD40000000000000000000000000000000000003 :10AD500000000000000000000000000000000000F3 :10AD600000000000000000000000000000000000E3 :10AD700000000000000000000000000000000000D3 :10AD800000000000000000000000000000000000C3 :10AD900000000000000000000000000000000000B3 :10ADA00000000000000000000000000000000000A3 :10ADB0000000000000000000000000000000000093 :10ADC0000000000000000000000000000000000083 :10ADD0000000000000000000000000000000000073 :10ADE0000000000000000000000000000000000063 :10ADF0000000000000000000000000000000000053 :10AE00000000000000000000000000000000000042 :10AE10000000000000000000000000000000000032 :10AE20000000000000000000000000000000000022 :10AE30000000000000000000000000000000000012 :10AE40000000000000000000000000000000000002 :10AE500000000000000000000000000000000000F2 :10AE600000000000000000000000000000000000E2 :10AE700000000000000000000000000000000000D2 :10AE800000000000000000000000000000000000C2 :10AE900000000000000000000000000000000000B2 :10AEA00000000000000000000000000000000000A2 :10AEB0000000000000000000000000000000000092 :10AEC0000000000000000000000000000000000082 :10AED0000000000000000000000000000000000072 :10AEE0000000000000000000000000000000000062 :10AEF0000000000000000000000000000000000052 :10AF00000000000000000000000000000000000041 :10AF10000000000000000000000000000000000031 :10AF20000000000000000000000000000000000021 :10AF30000000000000000000000000000000000011 :10AF40000000000000000000000000000000000001 :10AF500000000000000000000000000000000000F1 :10AF600000000000000000000000000000000000E1 :10AF700000000000000000000000000000000000D1 :10AF800000000000000000000000000000000000C1 :10AF900000000000000000000000000000000000B1 :10AFA00000000000000000000000000000000000A1 :10AFB0000000000000000000000000000000000091 :10AFC0000000000000000000000000000000000081 :10AFD0000000000000000000000000000000000071 :10AFE0000000000000000000000000000000000061 :10AFF0000000000000000000000000000000000051 :10B000000000000000000000000000000000000040 :10B010000000000000000000000000000000000030 :10B020000000000000000000000000000000000020 :10B030000000000000000000000000000000000010 :10B040000000000000000000000000000000000000 :10B0500000000000000000000000000000000000F0 :10B0600000000000000000000000000000000000E0 :10B0700000000000000000000000000000000000D0 :10B0800000000000000000000000000000000000C0 :10B0900000000000000000000000000000000000B0 :10B0A00000000000000000000000000000000000A0 :10B0B0000000000000000000000000000000000090 :10B0C0000000000000000000000000000000000080 :10B0D0000000000000000000000000000000000070 :10B0E0000000000000000000000000000000000060 :10B0F0000000000000000000000000000000000050 :10B10000000000000000000000000000000000003F :10B11000000000000000000000000000000000002F :10B12000000000000000000000000000000000001F :10B13000000000000000000000000000000000000F :10B1400000000000000000000000000000000000FF :10B1500000000000000000000000000000000000EF :10B1600000000000000000000000000000000000DF :10B1700000000000000000000000000000000000CF :10B1800000000000000000000000000000000000BF :10B1900000000000000000000000000000000000AF :10B1A000000000000000000000000000000000009F :10B1B000000000000000000000000000000000008F :10B1C000000000000000000000000000000000007F :10B1D000000000000000000000000000000000006F :10B1E000000000000000000000000000000000005F :10B1F000000000000000000000000000000000004F :10B20000000000000000000000000000000000003E :10B21000000000000000000000000000000000002E :10B22000000000000000000000000000000000001E :10B23000000000000000000000000000000000000E :10B2400000000000000000000000000000000000FE :10B2500000000000000000000000000000000000EE :10B2600000000000000000000000000000000000DE :10B2700000000000000000000000000000000000CE :10B2800000000000000000000000000000000000BE :10B2900000000000000000000000000000000000AE :10B2A000000000000000000000000000000000009E :10B2B000000000000000000000000000000000008E :10B2C000000000000000000000000000000000007E :10B2D000000000000000000000000000000000006E :10B2E000000000000000000000000000000000005E :10B2F000000000000000000000000000000000004E :10B30000000000000000000000000000000000003D :10B31000000000000000000000000000000000002D :10B32000000000000000000000000000000000001D :10B33000000000000000000000000000000000000D :10B3400000000000000000000000000000000000FD :10B3500000000000000000000000000000000000ED :10B3600000000000000000000000000000000000DD :10B3700000000000000000000000000000000000CD :10B3800000000000000000000000000000000000BD :10B3900000000000000000000000000000000000AD :10B3A000000000000000000000000000000000009D :10B3B000000000000000000000000000000000008D :10B3C000000000000000000000000000000000007D :10B3D000000000000000000000000000000000006D :10B3E000000000000000000000000000000000005D :10B3F000000000000000000000000000000000004D :10B40000000000000000000000000000000000003C :10B41000000000000000000000000000000000002C :10B42000000000000000000000000000000000001C :10B43000000000000000000000000000000000000C :10B4400000000000000000000000000000000000FC :10B4500000000000000000000000000000000000EC :10B4600000000000000000000000000000000000DC :10B4700000000000000000000000000000000000CC :10B4800000000000000000000000000000000000BC :10B4900000000000000000000000000000000000AC :10B4A000000000000000000000000000000000009C :10B4B000000000000000000000000000000000008C :10B4C000000000000000000000000000000000007C :10B4D000000000000000000000000000000000006C :10B4E000000000000000000000000000000000005C :10B4F000000000000000000000000000000000004C :10B50000000000000000000000000000000000003B :10B51000000000000000000000000000000000002B :10B52000000000000000000000000000000000001B :10B53000000000000000000000000000000000000B :10B5400000000000000000000000000000000000FB :10B5500000000000000000000000000000000000EB :10B5600000000000000000000000000000000000DB :10B5700000000000000000000000000000000000CB :10B5800000000000000000000000000000000000BB :10B5900000000000000000000000000000000000AB :10B5A000000000000000000000000000000000009B :10B5B000000000000000000000000000000000008B :10B5C000000000000000000000000000000000007B :10B5D000000000000000000000000000000000006B :10B5E000000000000000000000000000000000005B :10B5F000000000000000000000000000000000004B :10B60000000000000000000000000000000000003A :10B61000000000000000000000000000000000002A :10B62000000000000000000000000000000000001A :10B63000000000000000000000000000000000000A :10B6400000000000000000000000000000000000FA :10B6500000000000000000000000000000000000EA :10B6600000000000000000000000000000000000DA :10B6700000000000000000000000000000000000CA :10B6800000000000000000000000000000000000BA :10B6900000000000000000000000000000000000AA :10B6A000000000000000000000000000000000009A :10B6B000000000000000000000000000000000008A :10B6C000000000000000000000000000000000007A :10B6D000000000000000000000000000000000006A :10B6E000000000000000000000000000000000005A :10B6F000000000000000000000000000000000004A :10B700000000000000000000000000000000000039 :10B710000000000000000000000000000000000029 :10B720000000000000000000000000000000000019 :10B730000000000000000000000000000000000009 :10B7400000000000000000000000000000000000F9 :10B7500000000000000000000000000000000000E9 :10B7600000000000000000000000000000000000D9 :10B7700000000000000000000000000000000000C9 :10B7800000000000000000000000000000000000B9 :10B7900000000000000000000000000000000000A9 :10B7A0000000000000000000000000000000000099 :10B7B0000000000000000000000000000000000089 :10B7C0000000000000000000000000000000000079 :10B7D0000000000000000000000000000000000069 :10B7E0000000000000000000000000000000000059 :10B7F0000000000000000000000000000000000049 :10B800000000000000000000000000000000000038 :10B810000000000000000000000000000000000028 :10B820000000000000000000000000000000000018 :10B830000000000000000000000000000000000008 :10B8400000000000000000000000000000000000F8 :10B8500000000000000000000000000000000000E8 :10B8600000000000000000000000000000000000D8 :10B8700000000000000000000000000000000000C8 :10B8800000000000000000000000000000000000B8 :10B8900000000000000000000000000000000000A8 :10B8A0000000000000000000000000000000000098 :10B8B0000000000000000000000000000000000088 :10B8C0000000000000000000000000000000000078 :10B8D0000000000000000000000000000000000068 :10B8E0000000000000000000000000000000000058 :10B8F0000000000000000000000000000000000048 :10B900000000000000000000000000000000000037 :10B910000000000000000000000000000000000027 :10B920000000000000000000000000000000000017 :10B930000000000000000000000000000000000007 :10B9400000000000000000000000000000000000F7 :10B9500000000000000000000000000000000000E7 :10B9600000000000000000000000000000000000D7 :10B9700000000000000000000000000000000000C7 :10B9800000000000000000000000000000000000B7 :10B9900000000000000000000000000000000000A7 :10B9A0000000000000000000000000000000000097 :10B9B0000000000000000000000000000000000087 :10B9C0000000000000000000000000000000000077 :10B9D0000000000000000000000000000000000067 :10B9E0000000000000000000000000000000000057 :10B9F0000000000000000000000000000000000047 :10BA00000000000000000000000000000000000036 :10BA10000000000000000000000000000000000026 :10BA20000000000000000000000000000000000016 :10BA30000000000000000000000000000000000006 :10BA400000000000000000000000000000000000F6 :10BA500000000000000000000000000000000000E6 :10BA600000000000000000000000000000000000D6 :10BA700000000000000000000000000000000000C6 :10BA800000000000000000000000000000000000B6 :10BA900000000000000000000000000000000000A6 :10BAA0000000000000000000000000000000000096 :10BAB0000000000000000000000000000000000086 :10BAC0000000000000000000000000000000000076 :10BAD0000000000000000000000000000000000066 :10BAE0000000000000000000000000000000000056 :10BAF0000000000000000000000000000000000046 :10BB00000000000000000000000000000000000035 :10BB10000000000000000000000000000000000025 :10BB20000000000000000000000000000000000015 :10BB30000000000000000000000000000000000005 :10BB400000000000000000000000000000000000F5 :10BB500000000000000000000000000000000000E5 :10BB600000000000000000000000000000000000D5 :10BB700000000000000000000000000000000000C5 :10BB800000000000000000000000000000000000B5 :10BB900000000000000000000000000000000000A5 :10BBA0000000000000000000000000000000000095 :10BBB0000000000000000000000000000000000085 :10BBC0000000000000000000000000000000000075 :10BBD0000000000000000000000000000000000065 :10BBE0000000000000000000000000000000000055 :10BBF0000000000000000000000000000000000045 :10BC00000000000000000000000000000000000034 :10BC10000000000000000000000000000000000024 :10BC20000000000000000000000000000000000014 :10BC30000000000000000000000000000000000004 :10BC400000000000000000000000000000000000F4 :10BC500000000000000000000000000000000000E4 :10BC600000000000000000000000000000000000D4 :10BC700000000000000000000000000000000000C4 :10BC800000000000000000000000000000000000B4 :10BC900000000000000000000000000000000000A4 :10BCA0000000000000000000000000000000000094 :10BCB0000000000000000000000000000000000084 :10BCC0000000000000000000000000000000000074 :10BCD0000000000000000000000000000000000064 :10BCE0000000000000000000000000000000000054 :10BCF0000000000000000000000000000000000044 :10BD00000000000000000000000000000000000033 :10BD10000000000000000000000000000000000023 :10BD20000000000000000000000000000000000013 :10BD30000000000000000000000000000000000003 :10BD400000000000000000000000000000000000F3 :10BD500000000000000000000000000000000000E3 :10BD600000000000000000000000000000000000D3 :10BD700000000000000000000000000000000000C3 :10BD800000000000000000000000000000000000B3 :10BD900000000000000000000000000000000000A3 :10BDA0000000000000000000000000000000000093 :10BDB0000000000000000000000000000000000083 :10BDC0000000000000000000000000000000000073 :10BDD0000000000000000000000000000000000063 :10BDE0000000000000000000000000000000000053 :10BDF0000000000000000000000000000000000043 :10BE00000000000000000000000000000000000032 :10BE10000000000000000000000000000000000022 :10BE20000000000000000000000000000000000012 :10BE30000000000000000000000000000000000002 :10BE400000000000000000000000000000000000F2 :10BE500000000000000000000000000000000000E2 :10BE600000000000000000000000000000000000D2 :10BE700000000000000000000000000000000000C2 :10BE800000000000000000000000000000000000B2 :10BE900000000000000000000000000000000000A2 :10BEA0000000000000000000000000000000000092 :10BEB0000000000000000000000000000000000082 :10BEC0000000000000000000000000000000000072 :10BED0000000000000000000000000000000000062 :10BEE0000000000000000000000000000000000052 :10BEF0000000000000000000000000000000000042 :10BF00000000000000000000000000000000000031 :10BF10000000000000000000000000000000000021 :10BF20000000000000000000000000000000000011 :10BF30000000000000000000000000000000000001 :10BF400000000000000000000000000000000000F1 :10BF500000000000000000000000000000000000E1 :10BF600000000000000000000000000000000000D1 :10BF700000000000000000000000000000000000C1 :10BF800000000000000000000000000000000000B1 :10BF900000000000000000000000000000000000A1 :10BFA0000000000000000000000000000000000091 :10BFB0000000000000000000000000000000000081 :10BFC0000000000000000000000000000000000071 :10BFD0000000000000000000000000000000000061 :10BFE0000000000000000000000000000000000051 :10BFF0000000000000000000000000000000000041 :10C000000000000000000000000000000000000030 :10C010000000000000000000000000000000000020 :10C020000000000000000000000000000000000010 :10C030000000000000000000000000000000000000 :10C0400000000000000000000000000000000000F0 :10C0500000000000000000000000000000000000E0 :10C0600000000000000000000000000000000000D0 :10C0700000000000000000000000000000000000C0 :10C0800000000000000000000000000000000000B0 :10C0900000000000000000000000000000000000A0 :10C0A0000000000000000000000000000000000090 :10C0B0000000000000000000000000000000000080 :10C0C0000000000000000000000000000000000070 :10C0D0000000000000000000000000000000000060 :10C0E0000000000000000000000000000000000050 :10C0F0000000000000000000000000000000000040 :10C10000000000000000000000000000000000002F :10C11000000000000000000000000000000000001F :10C12000000000000000000000000000000000000F :10C1300000000000000000000000000000000000FF :10C1400000000000000000000000000000000000EF :10C1500000000000000000000000000000000000DF :10C1600000000000000000000000000000000000CF :10C1700000000000000000000000000000000000BF :10C1800000000000000000000000000000000000AF :10C19000000000000000000000000000000000009F :10C1A000000000000000000000000000000000008F :10C1B000000000000000000000000000000000007F :10C1C000000000000000000000000000000000006F :10C1D000000000000000000000000000000000005F :10C1E000000000000000000000000000000000004F :10C1F000000000000000000000000000000000003F :10C20000000000000000000000000000000000002E :10C21000000000000000000000000000000000001E :10C22000000000000000000000000000000000000E :10C2300000000000000000000000000000000000FE :10C2400000000000000000000000000000000000EE :10C2500000000000000000000000000000000000DE :10C2600000000000000000000000000000000000CE :10C2700000000000000000000000000000000000BE :10C2800000000000000000000000000000000000AE :10C29000000000000000000000000000000000009E :10C2A000000000000000000000000000000000008E :10C2B000000000000000000000000000000000007E :10C2C000000000000000000000000000000000006E :10C2D000000000000000000000000000000000005E :10C2E000000000000000000000000000000000004E :10C2F000000000000000000000000000000000003E :10C30000000000000000000000000000000000002D :10C31000000000000000000000000000000000001D :10C32000000000000000000000000000000000000D :10C3300000000000000000000000000000000000FD :10C3400000000000000000000000000000000000ED :10C3500000000000000000000000000000000000DD :10C3600000000000000000000000000000000000CD :10C3700000000000000000000000000000000000BD :10C3800000000000000000000000000000000000AD :10C39000000000000000000000000000000000009D :10C3A000000000000000000000000000000000008D :10C3B000000000000000000000000000000000007D :10C3C000000000000000000000000000000000006D :10C3D000000000000000000000000000000000005D :10C3E000000000000000000000000000000000004D :10C3F000000000000000000000000000000000003D :10C40000000000000000000000000000000000002C :10C41000000000000000000000000000000000001C :10C42000000000000000000000000000000000000C :10C4300000000000000000000000000000000000FC :10C4400000000000000000000000000000000000EC :10C4500000000000000000000000000000000000DC :10C4600000000000000000000000000000000000CC :10C4700000000000000000000000000000000000BC :10C4800000000000000000000000000000000000AC :10C49000000000000000000000000000000000009C :10C4A000000000000000000000000000000000008C :10C4B000000000000000000000000000000000007C :10C4C000000000000000000000000000000000006C :10C4D000000000000000000000000000000000005C :10C4E000000000000000000000000000000000004C :10C4F000000000000000000000000000000000003C :10C50000000000000000000000000000000000002B :10C51000000000000000000000000000000000001B :10C52000000000000000000000000000000000000B :10C5300000000000000000000000000000000000FB :10C5400000000000000000000000000000000000EB :10C5500000000000000000000000000000000000DB :10C5600000000000000000000000000000000000CB :10C5700000000000000000000000000000000000BB :10C5800000000000000000000000000000000000AB :10C59000000000000000000000000000000000009B :10C5A000000000000000000000000000000000008B :10C5B000000000000000000000000000000000007B :10C5C000000000000000000000000000000000006B :10C5D000000000000000000000000000000000005B :10C5E000000000000000000000000000000000004B :10C5F000000000000000000000000000000000003B :10C60000000000000000000000000000000000002A :10C61000000000000000000000000000000000001A :10C62000000000000000000000000000000000000A :10C6300000000000000000000000000000000000FA :10C6400000000000000000000000000000000000EA :10C6500000000000000000000000000000000000DA :10C6600000000000000000000000000000000000CA :10C6700000000000000000000000000000000000BA :10C6800000000000000000000000000000000000AA :10C69000000000000000000000000000000000009A :10C6A000000000000000000000000000000000008A :10C6B000000000000000000000000000000000007A :10C6C000000000000000000000000000000000006A :10C6D000000000000000000000000000000000005A :10C6E000000000000000000000000000000000004A :10C6F000000000000000000000000000000000003A :10C700000000000000000000000000000000000029 :10C710000000000000000000000000000000000019 :10C720000000000000000000000000000000000009 :10C7300000000000000000000000000000000000F9 :10C7400000000000000000000000000000000000E9 :10C7500000000000000000000000000000000000D9 :10C7600000000000000000000000000000000000C9 :10C7700000000000000000000000000000000000B9 :10C7800000000000000000000000000000000000A9 :10C790000000000000000000000000000000000099 :10C7A0000000000000000000000000000000000089 :10C7B0000000000000000000000000000000000079 :10C7C0000000000000000000000000000000000069 :10C7D0000000000000000000000000000000000059 :10C7E0000000000000000000000000000000000049 :10C7F0000000000000000000000000000000000039 :10C800000000000000000000000000000000000028 :10C810000000000000000000000000000000000018 :10C820000000000000000000000000000000000008 :10C8300000000000000000000000000000000000F8 :10C8400000000000000000000000000000000000E8 :10C8500000000000000000000000000000000000D8 :10C8600000000000000000000000000000000000C8 :10C8700000000000000000000000000000000000B8 :10C8800000000000000000000000000000000000A8 :10C890000000000000000000000000000000000098 :10C8A0000000000000000000000000000000000088 :10C8B0000000000000000000000000000000000078 :10C8C0000000000000000000000000000000000068 :10C8D0000000000000000000000000000000000058 :10C8E0000000000000000000000000000000000048 :10C8F0000000000000000000000000000000000038 :10C900000000000000000000000000000000000027 :10C910000000000000000000000000000000000017 :10C920000000000000000000000000000000000007 :10C9300000000000000000000000000000000000F7 :10C9400000000000000000000000000000000000E7 :10C9500000000000000000000000000000000000D7 :10C9600000000000000000000000000000000000C7 :10C9700000000000000000000000000000000000B7 :10C9800000000000000000000000000000000000A7 :10C990000000000000000000000000000000000097 :10C9A0000000000000000000000000000000000087 :10C9B0000000000000000000000000000000000077 :10C9C0000000000000000000000000000000000067 :10C9D0000000000000000000000000000000000057 :10C9E0000000000000000000000000000000000047 :10C9F0000000000000000000000000000000000037 :10CA00000000000000000000000000000000000026 :10CA10000000000000000000000000000000000016 :10CA20000000000000000000000000000000000006 :10CA300000000000000000000000000000000000F6 :10CA400000000000000000000000000000000000E6 :10CA500000000000000000000000000000000000D6 :10CA600000000000000000000000000000000000C6 :10CA700000000000000000000000000000000000B6 :10CA800000000000000000000000000000000000A6 :10CA90000000000000000000000000000000000096 :10CAA0000000000000000000000000000000000086 :10CAB0000000000000000000000000000000000076 :10CAC0000000000000000000000000000000000066 :10CAD0000000000000000000000000000000000056 :10CAE0000000000000000000000000000000000046 :10CAF0000000000000000000000000000000000036 :10CB00000000000000000000000000000000000025 :10CB10000000000000000000000000000000000015 :10CB20000000000000000000000000000000000005 :10CB300000000000000000000000000000000000F5 :10CB400000000000000000000000000000000000E5 :10CB500000000000000000000000000000000000D5 :10CB600000000000000000000000000000000000C5 :10CB700000000000000000000000000000000000B5 :10CB800000000000000000000000000000000000A5 :10CB90000000000000000000000000000000000095 :10CBA0000000000000000000000000000000000085 :10CBB0000000000000000000000000000000000075 :10CBC0000000000000000000000000000000000065 :10CBD0000000000000000000000000000000000055 :10CBE0000000000000000000000000000000000045 :10CBF0000000000000000000000000000000000035 :10CC00000000000000000000000000000000000024 :10CC10000000000000000000000000000000000014 :10CC20000000000000000000000000000000000004 :10CC300000000000000000000000000000000000F4 :10CC400000000000000000000000000000000000E4 :10CC500000000000000000000000000000000000D4 :10CC600000000000000000000000000000000000C4 :10CC700000000000000000000000000000000000B4 :10CC800000000000000000000000000000000000A4 :10CC90000000000000000000000000000000000094 :10CCA0000000000000000000000000000000000084 :10CCB0000000000000000000000000000000000074 :10CCC0000000000000000000000000000000000064 :10CCD0000000000000000000000000000000000054 :10CCE0000000000000000000000000000000000044 :10CCF0000000000000000000000000000000000034 :10CD00000000000000000000000000000000000023 :10CD10000000000000000000000000000000000013 :10CD20000000000000000000000000000000000003 :10CD300000000000000000000000000000000000F3 :10CD400000000000000000000000000000000000E3 :10CD500000000000000000000000000000000000D3 :10CD600000000000000000000000000000000000C3 :10CD700000000000000000000000000000000000B3 :10CD800000000000000000000000000000000000A3 :10CD90000000000000000000000000000000000093 :10CDA0000000000000000000000000000000000083 :10CDB0000000000000000000000000000000000073 :10CDC0000000000000000000000000000000000063 :10CDD0000000000000000000000000000000000053 :10CDE0000000000000000000000000000000000043 :10CDF0000000000000000000000000000000000033 :10CE00000000000000000000000000000000000022 :10CE10000000000000000000000000000000000012 :10CE20000000000000000000000000000000000002 :10CE300000000000000000000000000000000000F2 :10CE400000000000000000000000000000000000E2 :10CE500000000000000000000000000000000000D2 :10CE600000000000000000000000000000000000C2 :10CE700000000000000000000000000000000000B2 :10CE800000000000000000000000000000000000A2 :10CE90000000000000000000000000000000000092 :10CEA0000000000000000000000000000000000082 :10CEB0000000000000000000000000000000000072 :10CEC0000000000000000000000000000000000062 :10CED0000000000000000000000000000000000052 :10CEE0000000000000000000000000000000000042 :10CEF0000000000000000000000000000000000032 :10CF00000000000000000000000000000000000021 :10CF10000000000000000000000000000000000011 :10CF20000000000000000000000000000000000001 :10CF300000000000000000000000000000000000F1 :10CF400000000000000000000000000000000000E1 :10CF500000000000000000000000000000000000D1 :10CF600000000000000000000000000000000000C1 :10CF700000000000000000000000000000000000B1 :10CF800000000000000000000000000000000000A1 :10CF90000000000000000000000000000000000091 :10CFA0000000000000000000000000000000000081 :10CFB0000000000000000000000000000000000071 :10CFC0000000000000000000000000000000000061 :10CFD0000000000000000000000000000000000051 :10CFE0000000000000000000000000000000000041 :10CFF0000000000000000000000000000000000031 :10D000000000000000000000000000000000000020 :10D010000000000000000000000000000000000010 :10D020000000000000000000000000000000000000 :10D0300000000000000000000000000000000000F0 :10D0400000000000000000000000000000000000E0 :10D0500000000000000000000000000000000000D0 :10D0600000000000000000000000000000000000C0 :10D0700000000000000000000000000000000000B0 :10D0800000000000000000000000000000000000A0 :10D090000000000000000000000000000000000090 :10D0A0000000000000000000000000000000000080 :10D0B0000000000000000000000000000000000070 :10D0C0000000000000000000000000000000000060 :10D0D0000000000000000000000000000000000050 :10D0E0000000000000000000000000000000000040 :10D0F0000000000000000000000000000000000030 :10D10000000000000000000000000000000000001F :10D11000000000000000000000000000000000000F :10D1200000000000000000000000000000000000FF :10D1300000000000000000000000000000000000EF :10D1400000000000000000000000000000000000DF :10D1500000000000000000000000000000000000CF :10D1600000000000000000000000000000000000BF :10D1700000000000000000000000000000000000AF :10D18000000000000000000000000000000000009F :10D19000000000000000000000000000000000008F :10D1A000000000000000000000000000000000007F :10D1B000000000000000000000000000000000006F :10D1C000000000000000000000000000000000005F :10D1D000000000000000000000000000000000004F :10D1E000000000000000000000000000000000003F :10D1F000000000000000000000000000000000002F :10D20000000000000000000000000000000000001E :10D21000000000000000000000000000000000000E :10D2200000000000000000000000000000000000FE :10D2300000000000000000000000000000000000EE :10D2400000000000000000000000000000000000DE :10D2500000000000000000000000000000000000CE :10D2600000000000000000000000000000000000BE :10D2700000000000000000000000000000000000AE :10D28000000000000000000000000000000000009E :10D29000000000000000000000000000000000008E :10D2A000000000000000000000000000000000007E :10D2B000000000000000000000000000000000006E :10D2C000000000000000000000000000000000005E :10D2D000000000000000000000000000000000004E :10D2E000000000000000000000000000000000003E :10D2F000000000000000000000000000000000002E :10D30000000000000000000000000000000000001D :10D31000000000000000000000000000000000000D :10D3200000000000000000000000000000000000FD :10D3300000000000000000000000000000000000ED :10D3400000000000000000000000000000000000DD :10D3500000000000000000000000000000000000CD :10D3600000000000000000000000000000000000BD :10D3700000000000000000000000000000000000AD :10D38000000000000000000000000000000000009D :10D39000000000000000000000000000000000008D :10D3A000000000000000000000000000000000007D :10D3B000000000000000000000000000000000006D :10D3C000000000000000000000000000000000005D :10D3D000000000000000000000000000000000004D :10D3E000000000000000000000000000000000003D :10D3F000000000000000000000000000000000002D :10D40000000000000000000000000000000000001C :10D41000000000000000000000000000000000000C :10D4200000000000000000000000000000000000FC :10D4300000000000000000000000000000000000EC :10D4400000000000000000000000000000000000DC :10D4500000000000000000000000000000000000CC :10D4600000000000000000000000000000000000BC :10D4700000000000000000000000000000000000AC :10D48000000000000000000000000000000000009C :10D49000000000000000000000000000000000008C :10D4A000000000000000000000000000000000007C :10D4B000000000000000000000000000000000006C :10D4C000000000000000000000000000000000005C :10D4D000000000000000000000000000000000004C :10D4E000000000000000000000000000000000003C :10D4F000000000000000000000000000000000002C :10D50000000000000000000000000000000000001B :10D51000000000000000000000000000000000000B :10D5200000000000000000000000000000000000FB :10D5300000000000000000000000000000000000EB :10D5400000000000000000000000000000000000DB :10D5500000000000000000000000000000000000CB :10D5600000000000000000000000000000000000BB :10D5700000000000000000000000000000000000AB :10D58000000000000000000000000000000000009B :10D59000000000000000000000000000000000008B :10D5A000000000000000000000000000000000007B :10D5B000000000000000000000000000000000006B :10D5C000000000000000000000000000000000005B :10D5D000000000000000000000000000000000004B :10D5E000000000000000000000000000000000003B :10D5F000000000000000000000000000000000002B :10D60000000000000000000000000000000000001A :10D61000000000000000000000000000000000000A :10D6200000000000000000000000000000000000FA :10D6300000000000000000000000000000000000EA :10D6400000000000000000000000000000000000DA :10D6500000000000000000000000000000000000CA :10D6600000000000000000000000000000000000BA :10D6700000000000000000000000000000000000AA :10D68000000000000000000000000000000000009A :10D69000000000000000000000000000000000008A :10D6A000000000000000000000000000000000007A :10D6B000000000000000000000000000000000006A :10D6C000000000000000000000000000000000005A :10D6D000000000000000000000000000000000004A :10D6E000000000000000000000000000000000003A :10D6F000000000000000000000000000000000002A :10D700000000000000000000000000000000000019 :10D710000000000000000000000000000000000009 :10D7200000000000000000000000000000000000F9 :10D7300000000000000000000000000000000000E9 :10D7400000000000000000000000000000000000D9 :10D7500000000000000000000000000000000000C9 :10D7600000000000000000000000000000000000B9 :10D7700000000000000000000000000000000000A9 :10D780000000000000000000000000000000000099 :10D790000000000000000000000000000000000089 :10D7A0000000000000000000000000000000000079 :10D7B0000000000000000000000000000000000069 :10D7C0000000000000000000000000000000000059 :10D7D0000000000000000000000000000000000049 :10D7E0000000000000000000000000000000000039 :10D7F0000000000000000000000000000000000029 :10D800000000000000000000000000000000000018 :10D810000000000000000000000000000000000008 :10D8200000000000000000000000000000000000F8 :10D8300000000000000000000000000000000000E8 :10D8400000000000000000000000000000000000D8 :10D8500000000000000000000000000000000000C8 :10D8600000000000000000000000000000000000B8 :10D8700000000000000000000000000000000000A8 :10D880000000000000000000000000000000000098 :10D890000000000000000000000000000000000088 :10D8A0000000000000000000000000000000000078 :10D8B0000000000000000000000000000000000068 :10D8C0000000000000000000000000000000000058 :10D8D0000000000000000000000000000000000048 :10D8E0000000000000000000000000000000000038 :10D8F0000000000000000000000000000000000028 :10D900000000000000000000000000000000000017 :10D910000000000000000000000000000000000007 :10D9200000000000000000000000000000000000F7 :10D9300000000000000000000000000000000000E7 :10D9400000000000000000000000000000000000D7 :10D9500000000000000000000000000000000000C7 :10D9600000000000000000000000000000000000B7 :10D9700000000000000000000000000000000000A7 :10D980000000000000000000000000000000000097 :10D990000000000000000000000000000000000087 :10D9A0000000000000000000000000000000000077 :10D9B0000000000000000000000000000000000067 :10D9C0000000000000000000000000000000000057 :10D9D0000000000000000000000000000000000047 :10D9E0000000000000000000000000000000000037 :10D9F0000000000000000000000000000000000027 :10DA00000000000000000000000000000000000016 :10DA10000000000000000000000000000000000006 :10DA200000000000000000000000000000000000F6 :10DA300000000000000000000000000000000000E6 :10DA400000000000000000000000000000000000D6 :10DA500000000000000000000000000000000000C6 :10DA600000000000000000000000000000000000B6 :10DA700000000000000000000000000000000000A6 :10DA80000000000000000000000000000000000096 :10DA90000000000000000000000000000000000086 :10DAA0000000000000000000000000000000000076 :10DAB0000000000000000000000000000000000066 :10DAC0000000000000000000000000000000000056 :10DAD0000000000000000000000000000000000046 :10DAE0000000000000000000000000000000000036 :10DAF0000000000000000000000000000000000026 :10DB00000000000000000000000000000000000015 :10DB10000000000000000000000000000000000005 :10DB200000000000000000000000000000000000F5 :10DB300000000000000000000000000000000000E5 :10DB400000000000000000000000000000000000D5 :10DB500000000000000000000000000000000000C5 :10DB600000000000000000000000000000000000B5 :10DB700000000000000000000000000000000000A5 :10DB80000000000000000000000000000000000095 :10DB90000000000000000000000000000000000085 :10DBA0000000000000000000000000000000000075 :10DBB0000000000000000000000000000000000065 :10DBC0000000000000000000000000000000000055 :10DBD0000000000000000000000000000000000045 :10DBE0000000000000000000000000000000000035 :10DBF0000000000000000000000000000000000025 :10DC00000000000000000000000000000000000014 :10DC10000000000000000000000000000000000004 :10DC200000000000000000000000000000000000F4 :10DC300000000000000000000000000000000000E4 :10DC400000000000000000000000000000000000D4 :10DC500000000000000000000000000000000000C4 :10DC600000000000000000000000000000000000B4 :10DC700000000000000000000000000000000000A4 :10DC80000000000000000000000000000000000094 :10DC90000000000000000000000000000000000084 :10DCA0000000000000000000000000000000000074 :10DCB0000000000000000000000000000000000064 :10DCC0000000000000000000000000000000000054 :10DCD0000000000000000000000000000000000044 :10DCE0000000000000000000000000000000000034 :10DCF0000000000000000000000000000000000024 :10DD00000000000000000000000000000000000013 :10DD10000000000000000000000000000000000003 :10DD200000000000000000000000000000000000F3 :10DD300000000000000000000000000000000000E3 :10DD400000000000000000000000000000000000D3 :10DD500000000000000000000000000000000000C3 :10DD600000000000000000000000000000000000B3 :10DD700000000000000000000000000000000000A3 :10DD80000000000000000000000000000000000093 :10DD90000000000000000000000000000000000083 :10DDA0000000000000000000000000000000000073 :10DDB0000000000000000000000000000000000063 :10DDC0000000000000000000000000000000000053 :10DDD0000000000000000000000000000000000043 :10DDE0000000000000000000000000000000000033 :10DDF0000000000000000000000000000000000023 :10DE00000000000000000000000000000000000012 :10DE10000000000000000000000000000000000002 :10DE200000000000000000000000000000000000F2 :10DE300000000000000000000000000000000000E2 :10DE400000000000000000000000000000000000D2 :10DE500000000000000000000000000000000000C2 :10DE600000000000000000000000000000000000B2 :10DE700000000000000000000000000000000000A2 :10DE80000000000000000000000000000000000092 :10DE90000000000000000000000000000000000082 :10DEA0000000000000000000000000000000000072 :10DEB0000000000000000000000000000000000062 :10DEC0000000000000000000000000000000000052 :10DED0000000000000000000000000000000000042 :10DEE0000000000000000000000000000000000032 :10DEF0000000000000000000000000000000000022 :10DF00000000000000000000000000000000000011 :10DF10000000000000000000000000000000000001 :10DF200000000000000000000000000000000000F1 :10DF300000000000000000000000000000000000E1 :10DF400000000000000000000000000000000000D1 :10DF500000000000000000000000000000000000C1 :10DF600000000000000000000000000000000000B1 :10DF700000000000000000000000000000000000A1 :10DF80000000000000000000000000000000000091 :10DF90000000000000000000000000000000000081 :10DFA0000000000000000000000000000000000071 :10DFB0000000000000000000000000000000000061 :10DFC0000000000000000000000000000000000051 :10DFD0000000000000000000000000000000000041 :10DFE0000000000000000000000000000000000031 :10DFF0000000000000000000000000000000000021 :10E000000000000000000000000000000000000010 :10E010000000000000000000000000000000000000 :10E0200000000000000000000000000000000000F0 :10E0300000000000000000000000000000000000E0 :10E0400000000000000000000000000000000000D0 :10E0500000000000000000000000000000000000C0 :10E0600000000000000000000000000000000000B0 :10E0700000000000000000000000000000000000A0 :10E080000000000000000000000000000000000090 :10E090000000000000000000000000000000000080 :10E0A0000000000000000000000000000000000070 :10E0B0000000000000000000000000000000000060 :10E0C0000000000000000000000000000000000050 :10E0D0000000000000000000000000000000000040 :10E0E0000000000000000000000000000000000030 :10E0F0000000000000000000000000000000000020 :10E10000000000000000000000000000000000000F :10E1100000000000000000000000000000000000FF :10E1200000000000000000000000000000000000EF :10E1300000000000000000000000000000000000DF :10E1400000000000000000000000000000000000CF :10E1500000000000000000000000000000000000BF :10E1600000000000000000000000000000000000AF :10E17000000000000000000000000000000000009F :10E18000000000000000000000000000000000008F :10E19000000000000000000000000000000000007F :10E1A000000000000000000000000000000000006F :10E1B000000000000000000000000000000000005F :10E1C000000000000000000000000000000000004F :10E1D000000000000000000000000000000000003F :10E1E000000000000000000000000000000000002F :10E1F000000000000000000000000000000000001F :10E20000000000000000000000000000000000000E :10E2100000000000000000000000000000000000FE :10E2200000000000000000000000000000000000EE :10E2300000000000000000000000000000000000DE :10E2400000000000000000000000000000000000CE :10E2500000000000000000000000000000000000BE :10E2600000000000000000000000000000000000AE :10E27000000000000000000000000000000000009E :10E28000000000000000000000000000000000008E :10E29000000000000000000000000000000000007E :10E2A000000000000000000000000000000000006E :10E2B000000000000000000000000000000000005E :10E2C000000000000000000000000000000000004E :10E2D000000000000000000000000000000000003E :10E2E000000000000000000000000000000000002E :10E2F000000000000000000000000000000000001E :10E30000000000000000000000000000000000000D :10E3100000000000000000000000000000000000FD :10E3200000000000000000000000000000000000ED :10E3300000000000000000000000000000000000DD :10E3400000000000000000000000000000000000CD :10E3500000000000000000000000000000000000BD :10E3600000000000000000000000000000000000AD :10E37000000000000000000000000000000000009D :10E38000000000000000000000000000000000008D :10E39000000000000000000000000000000000007D :10E3A000000000000000000000000000000000006D :10E3B000000000000000000000000000000000005D :10E3C000000000000000000000000000000000004D :10E3D000000000000000000000000000000000003D :10E3E000000000000000000000000000000000002D :10E3F000000000000000000000000000000000001D :10E40000000000000000000000000000000000000C :10E4100000000000000000000000000000000000FC :10E4200000000000000000000000000000000000EC :10E4300000000000000000000000000000000000DC :10E4400000000000000000000000000000000000CC :10E4500000000000000000000000000000000000BC :10E4600000000000000000000000000000000000AC :10E47000000000000000000000000000000000009C :10E48000000000000000000000000000000000008C :10E49000000000000000000000000000000000007C :10E4A000000000000000000000000000000000006C :10E4B000000000000000000000000000000000005C :10E4C000000000000000000000000000000000004C :10E4D000000000000000000000000000000000003C :10E4E000000000000000000000000000000000002C :10E4F000000000000000000000000000000000001C :10E50000000000000000000000000000000000000B :10E5100000000000000000000000000000000000FB :10E5200000000000000000000000000000000000EB :10E5300000000000000000000000000000000000DB :10E5400000000000000000000000000000000000CB :10E5500000000000000000000000000000000000BB :10E5600000000000000000000000000000000000AB :10E57000000000000000000000000000000000009B :10E58000000000000000000000000000000000008B :10E59000000000000000000000000000000000007B :10E5A000000000000000000000000000000000006B :10E5B000000000000000000000000000000000005B :10E5C000000000000000000000000000000000004B :10E5D000000000000000000000000000000000003B :10E5E000000000000000000000000000000000002B :10E5F000000000000000000000000000000000001B :10E60000000000000000000000000000000000000A :10E6100000000000000000000000000000000000FA :10E6200000000000000000000000000000000000EA :10E6300000000000000000000000000000000000DA :10E6400000000000000000000000000000000000CA :10E6500000000000000000000000000000000000BA :10E6600000000000000000000000000000000000AA :10E67000000000000000000000000000000000009A :10E68000000000000000000000000000000000008A :10E69000000000000000000000000000000000007A :10E6A000000000000000000000000000000000006A :10E6B000000000000000000000000000000000005A :10E6C000000000000000000000000000000000004A :10E6D000000000000000000000000000000000003A :10E6E000000000000000000000000000000000002A :10E6F000000000000000000000000000000000001A :10E700000000000000000000000000000000000009 :10E7100000000000000000000000000000000000F9 :10E7200000000000000000000000000000000000E9 :10E7300000000000000000000000000000000000D9 :10E7400000000000000000000000000000000000C9 :10E7500000000000000000000000000000000000B9 :10E7600000000000000000000000000000000000A9 :10E770000000000000000000000000000000000099 :10E780000000000000000000000000000000000089 :10E790000000000000000000000000000000000079 :10E7A0000000000000000000000000000000000069 :10E7B0000000000000000000000000000000000059 :10E7C0000000000000000000000000000000000049 :10E7D0000000000000000000000000000000000039 :10E7E0000000000000000000000000000000000029 :10E7F0000000000000000000000000000000000019 :10E800000000000000000000000000000000000008 :10E8100000000000000000000000000000000000F8 :10E8200000000000000000000000000000000000E8 :10E8300000000000000000000000000000000000D8 :10E8400000000000000000000000000000000000C8 :10E8500000000000000000000000000000000000B8 :10E8600000000000000000000000000000000000A8 :10E870000000000000000000000000000000000098 :10E880000000000000000000000000000000000088 :10E890000000000000000000000000000000000078 :10E8A0000000000000000000000000000000000068 :10E8B0000000000000000000000000000000000058 :10E8C0000000000000000000000000000000000048 :10E8D0000000000000000000000000000000000038 :10E8E0000000000000000000000000000000000028 :10E8F0000000000000000000000000000000000018 :10E900000000000000000000000000000000000007 :10E9100000000000000000000000000000000000F7 :10E9200000000000000000000000000000000000E7 :10E9300000000000000000000000000000000000D7 :10E9400000000000000000000000000000000000C7 :10E9500000000000000000000000000000000000B7 :10E9600000000000000000000000000000000000A7 :10E970000000000000000000000000000000000097 :10E980000000000000000000000000000000000087 :10E990000000000000000000000000000000000077 :10E9A0000000000000000000000000000000000067 :10E9B0000000000000000000000000000000000057 :10E9C0000000000000000000000000000000000047 :10E9D0000000000000000000000000000000000037 :10E9E0000000000000000000000000000000000027 :10E9F0000000000000000000000000000000000017 :10EA00000000000000000000000000000000000006 :10EA100000000000000000000000000000000000F6 :10EA200000000000000000000000000000000000E6 :10EA300000000000000000000000000000000000D6 :10EA400000000000000000000000000000000000C6 :10EA500000000000000000000000000000000000B6 :10EA600000000000000000000000000000000000A6 :10EA70000000000000000000000000000000000096 :10EA80000000000000000000000000000000000086 :10EA90000000000000000000000000000000000076 :10EAA0000000000000000000000000000000000066 :10EAB0000000000000000000000000000000000056 :10EAC0000000000000000000000000000000000046 :10EAD0000000000000000000000000000000000036 :10EAE0000000000000000000000000000000000026 :10EAF0000000000000000000000000000000000016 :10EB00000000000000000000000000000000000005 :10EB100000000000000000000000000000000000F5 :10EB200000000000000000000000000000000000E5 :10EB300000000000000000000000000000000000D5 :10EB400000000000000000000000000000000000C5 :10EB500000000000000000000000000000000000B5 :10EB600000000000000000000000000000000000A5 :10EB70000000000000000000000000000000000095 :10EB80000000000000000000000000000000000085 :10EB90000000000000000000000000000000000075 :10EBA0000000000000000000000000000000000065 :10EBB0000000000000000000000000000000000055 :10EBC0000000000000000000000000000000000045 :10EBD0000000000000000000000000000000000035 :10EBE0000000000000000000000000000000000025 :10EBF0000000000000000000000000000000000015 :10EC00000000000000000000000000000000000004 :10EC100000000000000000000000000000000000F4 :10EC200000000000000000000000000000000000E4 :10EC300000000000000000000000000000000000D4 :10EC400000000000000000000000000000000000C4 :10EC500000000000000000000000000000000000B4 :10EC600000000000000000000000000000000000A4 :10EC70000000000000000000000000000000000094 :10EC80000000000000000000000000000000000084 :10EC90000000000000000000000000000000000074 :10ECA0000000000000000000000000000000000064 :10ECB0000000000000000000000000000000000054 :10ECC0000000000000000000000000000000000044 :10ECD0000000000000000000000000000000000034 :10ECE0000000000000000000000000000000000024 :10ECF0000000000000000000000000000000000014 :10ED00000000000000000000000000000000000003 :10ED100000000000000000000000000000000000F3 :10ED200000000000000000000000000000000000E3 :10ED300000000000000000000000000000000000D3 :10ED400000000000000000000000000000000000C3 :10ED500000000000000000000000000000000000B3 :10ED600000000000000000000000000000000000A3 :10ED70000000000000000000000000000000000093 :10ED80000000000000000000000000000000000083 :10ED90000000000000000000000000000000000073 :10EDA0000000000000000000000000000000000063 :10EDB0000000000000000000000000000000000053 :10EDC0000000000000000000000000000000000043 :10EDD0000000000000000000000000000000000033 :10EDE0000000000000000000000000000000000023 :10EDF0000000000000000000000000000000000013 :10EE00000000000000000000000000000000000002 :10EE100000000000000000000000000000000000F2 :10EE200000000000000000000000000000000000E2 :10EE300000000000000000000000000000000000D2 :10EE400000000000000000000000000000000000C2 :10EE500000000000000000000000000000000000B2 :10EE600000000000000000000000000000000000A2 :10EE70000000000000000000000000000000000092 :10EE80000000000000000000000000000000000082 :10EE90000000000000000000000000000000000072 :10EEA0000000000000000000000000000000000062 :10EEB0000000000000000000000000000000000052 :10EEC0000000000000000000000000000000000042 :10EED0000000000000000000000000000000000032 :10EEE0000000000000000000000000000000000022 :10EEF0000000000000000000000000000000000012 :10EF00000000000000000000000000000000000001 :10EF100000000000000000000000000000000000F1 :10EF200000000000000000000000000000000000E1 :10EF300000000000000000000000000000000000D1 :10EF400000000000000000000000000000000000C1 :10EF500000000000000000000000000000000000B1 :10EF600000000000000000000000000000000000A1 :10EF70000000000000000000000000000000000091 :10EF80000000000000000000000000000000000081 :10EF90000000000000000000000000000000000071 :10EFA0000000000000000000000000000000000061 :10EFB0000000000000000000000000000000000051 :10EFC0000000000000000000000000000000000041 :10EFD0000000000000000000000000000000000031 :10EFE0000000000000000000000000000000000021 :10EFF0000000000000000000000000000000000011 :10F000000000000000000000000000000000000000 :10F0100000000000000000000000000000000000F0 :10F0200000000000000000000000000000000000E0 :10F0300000000000000000000000000000000000D0 :10F0400000000000000000000000000000000000C0 :10F0500000000000000000000000000000000000B0 :10F0600000000000000000000000000000000000A0 :10F070000000000000000000000000000000000090 :10F080000000000000000000000000000000000080 :10F090000000000000000000000000000000000070 :10F0A0000000000000000000000000000000000060 :10F0B0000000000000000000000000000000000050 :10F0C0000000000000000000000000000000000040 :10F0D0000000000000000000000000000000000030 :10F0E0000000000000000000000000000000000020 :10F0F0000000000000000000000000000000000010 :10F1000000000000000000000000000000000000FF :10F1100000000000000000000000000000000000EF :10F1200000000000000000000000000000000000DF :10F1300000000000000000000000000000000000CF :10F1400000000000000000000000000000000000BF :10F1500000000000000000000000000000000000AF :10F16000000000000000000000000000000000009F :10F17000000000000000000000000000000000008F :10F18000000000000000000000000000000000007F :10F19000000000000000000000000000000000006F :10F1A000000000000000000000000000000000005F :10F1B000000000000000000000000000000000004F :10F1C000000000000000000000000000000000003F :10F1D000000000000000000000000000000000002F :10F1E000000000000000000000000000000000001F :10F1F000000000000000000000000000000000000F :10F2000000000000000000000000000000000000FE :10F2100000000000000000000000000000000000EE :10F2200000000000000000000000000000000000DE :10F2300000000000000000000000000000000000CE :10F2400000000000000000000000000000000000BE :10F2500000000000000000000000000000000000AE :10F26000000000000000000000000000000000009E :10F27000000000000000000000000000000000008E :10F28000000000000000000000000000000000007E :10F29000000000000000000000000000000000006E :10F2A000000000000000000000000000000000005E :10F2B000000000000000000000000000000000004E :10F2C000000000000000000000000000000000003E :10F2D000000000000000000000000000000000002E :10F2E000000000000000000000000000000000001E :10F2F000000000000000000000000000000000000E :10F3000000000000000000000000000000000000FD :10F3100000000000000000000000000000000000ED :10F3200000000000000000000000000000000000DD :10F3300000000000000000000000000000000000CD :10F3400000000000000000000000000000000000BD :10F3500000000000000000000000000000000000AD :10F36000000000000000000000000000000000009D :10F37000000000000000000000000000000000008D :10F38000000000000000000000000000000000007D :10F39000000000000000000000000000000000006D :10F3A000000000000000000000000000000000005D :10F3B000000000000000000000000000000000004D :10F3C000000000000000000000000000000000003D :10F3D000000000000000000000000000000000002D :10F3E000000000000000000000000000000000001D :10F3F000000000000000000000000000000000000D :10F4000000000000000000000000000000000000FC :10F4100000000000000000000000000000000000EC :10F4200000000000000000000000000000000000DC :10F4300000000000000000000000000000000000CC :10F4400000000000000000000000000000000000BC :10F4500000000000000000000000000000000000AC :10F46000000000000000000000000000000000009C :10F47000000000000000000000000000000000008C :10F48000000000000000000000000000000000007C :10F49000000000000000000000000000000000006C :10F4A000000000000000000000000000000000005C :10F4B000000000000000000000000000000000004C :10F4C000000000000000000000000000000000003C :10F4D000000000000000000000000000000000002C :10F4E000000000000000000000000000000000001C :10F4F000000000000000000000000000000000000C :10F5000000000000000000000000000000000000FB :10F5100000000000000000000000000000000000EB :10F5200000000000000000000000000000000000DB :10F5300000000000000000000000000000000000CB :10F5400000000000000000000000000000000000BB :10F5500000000000000000000000000000000000AB :10F56000000000000000000000000000000000009B :10F57000000000000000000000000000000000008B :10F58000000000000000000000000000000000007B :10F59000000000000000000000000000000000006B :10F5A000000000000000000000000000000000005B :10F5B000000000000000000000000000000000004B :10F5C000000000000000000000000000000000003B :10F5D000000000000000000000000000000000002B :10F5E000000000000000000000000000000000001B :10F5F000000000000000000000000000000000000B :10F6000000000000000000000000000000000000FA :10F6100000000000000000000000000000000000EA :10F6200000000000000000000000000000000000DA :10F6300000000000000000000000000000000000CA :10F6400000000000000000000000000000000000BA :10F6500000000000000000000000000000000000AA :10F66000000000000000000000000000000000009A :10F67000000000000000000000000000000000008A :10F68000000000000000000000000000000000007A :10F69000000000000000000000000000000000006A :10F6A000000000000000000000000000000000005A :10F6B000000000000000000000000000000000004A :10F6C000000000000000000000000000000000003A :10F6D000000000000000000000000000000000002A :10F6E000000000000000000000000000000000001A :10F6F000000000000000000000000000000000000A :10F7000000000000000000000000000000000000F9 :10F7100000000000000000000000000000000000E9 :10F7200000000000000000000000000000000000D9 :10F7300000000000000000000000000000000000C9 :10F7400000000000000000000000000000000000B9 :10F7500000000000000000000000000000000000A9 :10F760000000000000000000000000000000000099 :10F770000000000000000000000000000000000089 :10F780000000000000000000000000000000000079 :10F790000000000000000000000000000000000069 :10F7A0000000000000000000000000000000000059 :10F7B0000000000000000000000000000000000049 :10F7C0000000000000000000000000000000000039 :10F7D0000000000000000000000000000000000029 :10F7E0000000000000000000000000000000000019 :10F7F0000000000000000000000000000000000009 :10F8000000000000000000000000000000000000F8 :10F8100000000000000000000000000000000000E8 :10F8200000000000000000000000000000000000D8 :10F8300000000000000000000000000000000000C8 :10F8400000000000000000000000000000000000B8 :10F8500000000000000000000000000000000000A8 :10F860000000000000000000000000000000000098 :10F870000000000000000000000000000000000088 :10F880000000000000000000000000000000000078 :10F890000000000000000000000000000000000068 :10F8A0000000000000000000000000000000000058 :10F8B0000000000000000000000000000000000048 :10F8C0000000000000000000000000000000000038 :10F8D0000000000000000000000000000000000028 :10F8E0000000000000000000000000000000000018 :10F8F0000000000000000000000000000000000008 :10F9000000000000000000000000000000000000F7 :10F9100000000000000000000000000000000000E7 :10F9200000000000000000000000000000000000D7 :10F9300000000000000000000000000000000000C7 :10F9400000000000000000000000000000000000B7 :10F9500000000000000000000000000000000000A7 :10F960000000000000000000000000000000000097 :10F970000000000000000000000000000000000087 :10F980000000000000000000000000000000000077 :10F990000000000000000000000000000000000067 :10F9A0000000000000000000000000000000000057 :10F9B0000000000000000000000000000000000047 :10F9C0000000000000000000000000000000000037 :10F9D0000000000000000000000000000000000027 :10F9E0000000000000000000000000000000000017 :10F9F0000000000000000000000000000000000007 :10FA000000000000000000000000000000000000F6 :10FA100000000000000000000000000000000000E6 :10FA200000000000000000000000000000000000D6 :10FA300000000000000000000000000000000000C6 :10FA400000000000000000000000000000000000B6 :10FA500000000000000000000000000000000000A6 :10FA60000000000000000000000000000000000096 :10FA70000000000000000000000000000000000086 :10FA80000000000000000000000000000000000076 :10FA90000000000000000000000000000000000066 :10FAA0000000000000000000000000000000000056 :10FAB0000000000000000000000000000000000046 :10FAC0000000000000000000000000000000000036 :10FAD0000000000000000000000000000000000026 :10FAE0000000000000000000000000000000000016 :10FAF0000000000000000000000000000000000006 :10FB000000000000000000000000000000000000F5 :10FB100000000000000000000000000000000000E5 :10FB200000000000000000000000000000000000D5 :10FB300000000000000000000000000000000000C5 :10FB400000000000000000000000000000000000B5 :10FB500000000000000000000000000000000000A5 :10FB60000000000000000000000000000000000095 :10FB70000000000000000000000000000000000085 :10FB80000000000000000000000000000000000075 :10FB90000000000000000000000000000000000065 :10FBA0000000000000000000000000000000000055 :10FBB0000000000000000000000000000000000045 :10FBC0000000000000000000000000000000000035 :10FBD0000000000000000000000000000000000025 :10FBE0000000000000000000000000000000000015 :10FBF0000000000000000000000000000000000005 :10FC000000000000000000000000000000000000F4 :10FC100000000000000000000000000000000000E4 :10FC200000000000000000000000000000000000D4 :10FC300000000000000000000000000000000000C4 :10FC400000000000000000000000000000000000B4 :10FC500000000000000000000000000000000000A4 :10FC60000000000000000000000000000000000094 :10FC70000000000000000000000000000000000084 :10FC80000000000000000000000000000000000074 :10FC90000000000000000000000000000000000064 :10FCA0000000000000000000000000000000000054 :10FCB0000000000000000000000000000000000044 :10FCC0000000000000000000000000000000000034 :10FCD0000000000000000000000000000000000024 :10FCE0000000000000000000000000000000000014 :10FCF0000000000000000000000000000000000004 :10FD000000000000000000000000000000000000F3 :10FD100000000000000000000000000000000000E3 :10FD200000000000000000000000000000000000D3 :10FD300000000000000000000000000000000000C3 :10FD400000000000000000000000000000000000B3 :10FD500000000000000000000000000000000000A3 :10FD60000000000000000000000000000000000093 :10FD70000000000000000000000000000000000083 :10FD80000000000000000000000000000000000073 :10FD90000000000000000000000000000000000063 :10FDA0000000000000000000000000000000000053 :10FDB0000000000000000000000000000000000043 :10FDC0000000000000000000000000000000000033 :10FDD0000000000000000000000000000000000023 :10FDE0000000000000000000000000000000000013 :10FDF0000000000000000000000000000000000003 :10FE000000000000000000000000000000000000F2 :10FE100000000000000000000000000000000000E2 :10FE200000000000000000000000000000000000D2 :10FE300000000000000000000000000000000000C2 :10FE400000000000000000000000000000000000B2 :10FE500000000000000000000000000000000000A2 :10FE60000000000000000000000000000000000092 :10FE70000000000000000000000000000000000082 :10FE80000000000000000000000000000000000072 :10FE90000000000000000000000000000000000062 :10FEA0000000000000000000000000000000000052 :10FEB0000000000000000000000000000000000042 :10FEC0000000000000000000000000000000000032 :10FED0000000000000000000000000000000000022 :10FEE0000000000000000000000000000000000012 :10FEF0000000000000000000000000000000000002 :10FF000000000000000000000000000000000000F1 :10FF100000000000000000000000000000000000E1 :10FF200000000000000000000000000000000000D1 :10FF300000000000000000000000000000000000C1 :10FF400000000000000000000000000000000000B1 :10FF500000000000000000000000000000000000A1 :10FF60000000000000000000000000000000000091 :10FF70000000000000000000000000000000000081 :10FF80000000000000000000000000000000000071 :10FF90000000000000000000000000000000000061 :10FFA0000000000000000000000000000000000051 :10FFB0000000000000000000000000000000000041 :10FFC0000000000000000000000000000000000031 :10FFD0000000000000000000000000000000000021 :10FFE0000000000000000000000000000000000011 :10FFF0000000000000000000000000000000000001 :02000004620692 :1000000000000000000000000000000000000000F0 :1000100000000000000000000000000000000000E0 :1000200000000000000000000000000000000000D0 :1000300000000000000000000000000000000000C0 :1000400000000000000000000000000000000000B0 :1000500000000000000000000000000000000000A0 :100060000000000000000000000000000000000090 :100070000000000000000000000000000000000080 :100080000000000000000000000000000000000070 :100090000000000000000000000000000000000060 :1000A0000000000000000000000000000000000050 :1000B0000000000000000000000000000000000040 :1000C0000000000000000000000000000000000030 :1000D0000000000000000000000000000000000020 :1000E0000000000000000000000000000000000010 :1000F0000000000000000000000000000000000000 :1001000000000000000000000000000000000000EF :1001100000000000000000000000000000000000DF :1001200000000000000000000000000000000000CF :1001300000000000000000000000000000000000BF :1001400000000000000000000000000000000000AF :10015000000000000000000000000000000000009F :10016000000000000000000000000000000000008F :10017000000000000000000000000000000000007F :10018000000000000000000000000000000000006F :0C01900000000000000000000000000063 :040000056200004055 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710Test/.gitignore ================================================ .dep src/main.lst ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710Test/inc/typedefs.h ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial ****************************************************************************/ #ifndef __TYPEDEFS_H__ #define __TYPEDEFS_H__ /* * Some types to use Windows like source */ typedef char CHAR; /* 8-bit signed data */ typedef unsigned char BYTE; /* 8-bit unsigned data */ typedef unsigned short WORD; /* 16-bit unsigned data */ typedef long LONG; /* 32-bit signed data */ typedef unsigned long ULONG; /* 32-bit unsigned data */ typedef unsigned long DWORD; /* 32-bit unsigned data */ #endif /* !__TYPEDEFS_H__ */ /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710Test/prj/eclipse_ram.gdb ================================================ target remote localhost:3333 monitor reset monitor sleep 500 monitor poll monitor soft_reset_halt monitor arm7_9 sw_bkpts enable monitor mww 0xA0000050 0x01c2 monitor mdw 0xA0000050 load break main continue ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710Test/prj/eclipse_rom.gdb ================================================ target remote localhost:3333 monitor reset monitor sleep 500 monitor poll monitor soft_reset_halt monitor arm7_9 force_hw_bkpts enable monitor mww 0xA0000050 0x01c2 monitor mdw 0xA0000050 load break main continue ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710Test/prj/hitex_str7_ram.ld ================================================ /*********************************************************************************** * Copyright 2005 Anglia Design * This demo code and associated components are provided as is and has no warranty, * implied or otherwise. You are free to use/modify any of the provided * code at your own risk in your applications with the expressed limitation * of liability (see below) * * LIMITATION OF LIABILITY: ANGLIA OR ANGLIA DESIGNS SHALL NOT BE LIABLE FOR ANY * LOSS OF PROFITS, LOSS OF USE, LOSS OF DATA, INTERRUPTION OF BUSINESS, NOR FOR * INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND WHETHER UNDER * THIS AGREEMENT OR OTHERWISE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * Author : Spencer Oliver * Web : www.anglia-designs.com * ***********************************************************************************/ /* Stack Sizes */ _STACKSIZE = 1024; _STACKSIZE_IRQ = 256; _STACKSIZE_FIQ = 0; _STACKSIZE_SVC = 1024; _STACKSIZE_ABT = 0; _STACKSIZE_UND = 0; _HEAPSIZE = 1024; /* Memory Definitions */ MEMORY { DATA (rw) : ORIGIN = 0x20000000, LENGTH = 0x00010000 } /* Section Definitions */ SECTIONS { /* first section is .text which is used for code */ .text : { CREATE_OBJECT_SYMBOLS KEEP(*(.vectrom)) KEEP(*(.init)) *(.text .text.*) *(.gnu.linkonce.t.*) *(.glue_7t) *(.glue_7) *(.vfp11_veneer) KEEP(*(.fini)) *(.gcc_except_table) } >DATA =0 . = ALIGN(4); /* .ctors .dtors are used for c++ constructors/destructors */ .ctors : { PROVIDE(__ctors_start__ = .); KEEP(*(SORT(.ctors.*))) KEEP(*(.ctors)) PROVIDE(__ctors_end__ = .); } >DATA .dtors : { PROVIDE(__dtors_start__ = .); KEEP(*(SORT(.dtors.*))) KEEP(*(.dtors)) PROVIDE(__dtors_end__ = .); } >DATA /* .rodata section which is used for read-only data (constants) */ .rodata : { *(.rodata .rodata.*) *(.gnu.linkonce.r.*) } >DATA . = ALIGN(4); .init_array : { *(.init) *(.fini) PROVIDE (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE (__preinit_array_end = .); PROVIDE (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE (__init_array_end = .); PROVIDE (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE (__fini_array_end = .); } >DATA . = ALIGN(4); /* .ARM.exidx is sorted, so has to go in its own output section. */ __exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >DATA __exidx_end = .; _vectext = .; PROVIDE (vectext = .); .vect : AT (_vectext) { _vecstart = .; KEEP(*(.vectram)) _vecend = .; } >DATA _etext = _vectext + SIZEOF(.vect); PROVIDE (etext = .); /* .data section which is used for initialized data */ .data : AT (_etext) { *(.data .data.*) *(.gnu.linkonce.d.*) SORT(CONSTRUCTORS) } >DATA . = ALIGN(4); __data_start = .; _edata = .; PROVIDE (edata = .); /* .bss section which is used for uninitialized data */ .bss : { __bss_start = .; __bss_start__ = .; *(.bss .bss.*) *(.gnu.linkonce.b.*) *(COMMON) . = ALIGN(4); } >DATA . = ALIGN(4); __bss_end__ = .; _end = .; PROVIDE(end = .); /* .heap section which is used for memory allocation */ .heap (NOLOAD) : { __heap_start__ = .; *(.heap) . = MAX(__heap_start__ + _HEAPSIZE , .); } >DATA __heap_end__ = __heap_start__ + SIZEOF(.heap); /* .stack section - user mode stack */ .stack (__heap_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_start__ = .; *(.stack) . = MAX(__stack_start__ + _STACKSIZE , .); } >DATA __stack_end__ = __stack_start__ + SIZEOF(.stack); /* .stack_irq section */ .stack_irq (__stack_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_irq_start__ = .; *(.stack_irq) . = MAX(__stack_irq_start__ + _STACKSIZE_IRQ , .); } >DATA __stack_irq_end__ = __stack_irq_start__ + SIZEOF(.stack_irq); /* .stack_fiq section */ .stack_fiq (__stack_irq_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_fiq_start__ = .; *(.stack_fiq) . = MAX(__stack_fiq_start__ + _STACKSIZE_FIQ , .); } >DATA __stack_fiq_end__ = __stack_fiq_start__ + SIZEOF(.stack_fiq); /* .stack_svc section */ .stack_svc (__stack_fiq_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_svc_start__ = .; *(.stack_svc) . = MAX(__stack_svc_start__ + _STACKSIZE_SVC , .); } >DATA __stack_svc_end__ = __stack_svc_start__ + SIZEOF(.stack_svc); /* .stack_abt section */ .stack_abt (__stack_svc_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_abt_start__ = .; *(.stack_abt) . = MAX(__stack_abt_start__ + _STACKSIZE_ABT , .); } >DATA __stack_abt_end__ = __stack_abt_start__ + SIZEOF(.stack_abt); /* .stack_und section */ .stack_und (__stack_abt_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_und_start__ = .; *(.stack_und) . = MAX(__stack_und_start__ + _STACKSIZE_UND , .); } >DATA __stack_und_end__ = __stack_und_start__ + SIZEOF(.stack_und); /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710Test/prj/hitex_str7_rom.ld ================================================ /*********************************************************************************** * Copyright 2005 Anglia Design * This demo code and associated components are provided as is and has no warranty, * implied or otherwise. You are free to use/modify any of the provided * code at your own risk in your applications with the expressed limitation * of liability (see below) * * LIMITATION OF LIABILITY: ANGLIA OR ANGLIA DESIGNS SHALL NOT BE LIABLE FOR ANY * LOSS OF PROFITS, LOSS OF USE, LOSS OF DATA, INTERRUPTION OF BUSINESS, NOR FOR * INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND WHETHER UNDER * THIS AGREEMENT OR OTHERWISE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * Author : Spencer Oliver * Web : www.anglia-designs.com * ***********************************************************************************/ /* Stack Sizes */ _STACKSIZE = 1024; _STACKSIZE_IRQ = 256; _STACKSIZE_FIQ = 0; _STACKSIZE_SVC = 1024; _STACKSIZE_ABT = 0; _STACKSIZE_UND = 0; _HEAPSIZE = 1024; /* Memory Definitions */ MEMORY { CODE (rx) : ORIGIN = 0x40000000, LENGTH = 0x00040000 DATA (rw) : ORIGIN = 0x20000000, LENGTH = 0x00010000 } /* Section Definitions */ SECTIONS { /* first section is .text which is used for code */ .text : { CREATE_OBJECT_SYMBOLS KEEP(*(.vectrom)) KEEP(*(.init)) *(.text .text.*) *(.gnu.linkonce.t.*) *(.glue_7t) *(.glue_7) *(.vfp11_veneer) KEEP(*(.fini)) *(.gcc_except_table) } >CODE =0 . = ALIGN(4); /* .ctors .dtors are used for c++ constructors/destructors */ .ctors : { PROVIDE(__ctors_start__ = .); KEEP(*(SORT(.ctors.*))) KEEP(*(.ctors)) PROVIDE(__ctors_end__ = .); } >CODE .dtors : { PROVIDE(__dtors_start__ = .); KEEP(*(SORT(.dtors.*))) KEEP(*(.dtors)) PROVIDE(__dtors_end__ = .); } >CODE /* .rodata section which is used for read-only data (constants) */ .rodata : { *(.rodata .rodata.*) *(.gnu.linkonce.r.*) } >CODE . = ALIGN(4); .init_array : { *(.init) *(.fini) PROVIDE (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE (__preinit_array_end = .); PROVIDE (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE (__init_array_end = .); PROVIDE (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE (__fini_array_end = .); } >CODE . = ALIGN(4); /* .ARM.exidx is sorted, so has to go in its own output section. */ __exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >CODE __exidx_end = .; _vectext = .; PROVIDE (vectext = .); .vect : AT (_vectext) { _vecstart = .; KEEP(*(.vectram)) _vecend = .; } >DATA _etext = _vectext + SIZEOF(.vect); PROVIDE (etext = .); /* .data section which is used for initialized data */ .data : AT (_etext) { __data_start = .; *(.data .data.*) *(.gnu.linkonce.d.*) SORT(CONSTRUCTORS) . = ALIGN(4); *(.fastrun .fastrun.*) } >DATA . = ALIGN(4); _edata = .; PROVIDE (edata = .); /* .bss section which is used for uninitialized data */ .bss : { __bss_start = .; __bss_start__ = .; *(.bss .bss.*) *(.gnu.linkonce.b.*) *(COMMON) . = ALIGN(4); } >DATA . = ALIGN(4); __bss_end__ = .; _end = .; PROVIDE(end = .); /* .heap section which is used for memory allocation */ .heap (NOLOAD) : { __heap_start__ = .; *(.heap) . = MAX(__heap_start__ + _HEAPSIZE , .); } >DATA __heap_end__ = __heap_start__ + SIZEOF(.heap); /* .stack section - user mode stack */ .stack (__heap_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_start__ = .; *(.stack) . = MAX(__stack_start__ + _STACKSIZE , .); } >DATA __stack_end__ = __stack_start__ + SIZEOF(.stack); /* .stack_irq section */ .stack_irq (__stack_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_irq_start__ = .; *(.stack_irq) . = MAX(__stack_irq_start__ + _STACKSIZE_IRQ , .); } >DATA __stack_irq_end__ = __stack_irq_start__ + SIZEOF(.stack_irq); /* .stack_fiq section */ .stack_fiq (__stack_irq_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_fiq_start__ = .; *(.stack_fiq) . = MAX(__stack_fiq_start__ + _STACKSIZE_FIQ , .); } >DATA __stack_fiq_end__ = __stack_fiq_start__ + SIZEOF(.stack_fiq); /* .stack_svc section */ .stack_svc (__stack_fiq_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_svc_start__ = .; *(.stack_svc) . = MAX(__stack_svc_start__ + _STACKSIZE_SVC , .); } >DATA __stack_svc_end__ = __stack_svc_start__ + SIZEOF(.stack_svc); /* .stack_abt section */ .stack_abt (__stack_svc_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_abt_start__ = .; *(.stack_abt) . = MAX(__stack_abt_start__ + _STACKSIZE_ABT , .); } >DATA __stack_abt_end__ = __stack_abt_start__ + SIZEOF(.stack_abt); /* .stack_und section */ .stack_und (__stack_abt_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_und_start__ = .; *(.stack_und) . = MAX(__stack_und_start__ + _STACKSIZE_UND , .); } >DATA __stack_und_end__ = __stack_und_start__ + SIZEOF(.stack_und); /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710Test/prj/str710_jtagkey.cfg ================================================ #daemon configuration telnet_port 4444 gdb_port 3333 # tell gdb our flash memory map # and enable flash programming gdb_memory_map enable gdb_flash_program enable #interface interface ft2232 ft2232_device_desc "Amontec JTAGkey A" ft2232_layout jtagkey ft2232_vid_pid 0x0403 0xcff8 jtag_speed 0 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst srst_pulls_trst #jtag scan chain jtag newtap str7 cpu -irlen 4 -irmask 0xf #target configuration target create target0 arm7tdmi -endian little -chain-position 0 [new_target_name] configure -work-area-virt 0 -work-area-phys 0x2000C000 -work-area-size 0x4000 -work-area-backup false target_script 0 gdb_program_config .\prj\str710_program.script #flash bank str7x 0 0 flash bank str7x 0x40000000 0x00040000 0 0 0 STR71x # For more information about the configuration files, # look at the OpenOCD User's Guide. init reset halt ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710Test/prj/str710_program.script ================================================ flash protect 0 0 7 off ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710Test/src/crt.s ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * * History: * * 04.03.06 mifi First Version * This version based on an example from Ethernut and * "ARM Cross Development with Eclipse" from James P. Lynch * * 26.01.08 mifi Change the code of the init section. Here I have used * some of the source from the Anglia startup.s * Author: Spencer Oliver (www.anglia-designs.com) ****************************************************************************/ /* * Some defines for the program status registers */ ARM_MODE_USER = 0x10 /* Normal User Mode */ ARM_MODE_FIQ = 0x11 /* FIQ Fast Interrupts Mode */ ARM_MODE_IRQ = 0x12 /* IRQ Standard Interrupts Mode */ ARM_MODE_SVC = 0x13 /* Supervisor Interrupts Mode */ ARM_MODE_ABORT = 0x17 /* Abort Processing memory Faults Mode */ ARM_MODE_UNDEF = 0x1B /* Undefined Instructions Mode */ ARM_MODE_SYS = 0x1F /* System Running in Priviledged Operating Mode */ ARM_MODE_MASK = 0x1F I_BIT = 0x80 /* disable IRQ when I bit is set */ F_BIT = 0x40 /* disable IRQ when I bit is set */ /* * Register Base Address */ PRCCU_BASE = 0xA0000000 RCCU_CFR = 0x08 RCCU_PLL1CR = 0x18 PCU_MDIVR = 0x40 PCU_PDIVR = 0x44 PCU_BOOTCR = 0x50 .section .vectors,"ax" .code 32 /****************************************************************************/ /* Vector table and reset entry */ /****************************************************************************/ _vectors: ldr pc, ResetAddr /* Reset */ ldr pc, UndefAddr /* Undefined instruction */ ldr pc, SWIAddr /* Software interrupt */ ldr pc, PAbortAddr /* Prefetch abort */ ldr pc, DAbortAddr /* Data abort */ ldr pc, ReservedAddr /* Reserved */ ldr pc, IRQAddr /* IRQ interrupt */ ldr pc, FIQAddr /* FIQ interrupt */ ResetAddr: .word ResetHandler UndefAddr: .word UndefHandler SWIAddr: .word SWIHandler PAbortAddr: .word PAbortHandler DAbortAddr: .word DAbortHandler ReservedAddr: .word 0 IRQAddr: .word IRQHandler FIQAddr: .word FIQHandler .ltorg .section .init, "ax" .code 32 .global ResetHandler .global ExitFunction .extern main /****************************************************************************/ /* Reset handler */ /****************************************************************************/ ResetHandler: /* * Wait for the oscillator is stable */ nop nop nop nop nop nop nop nop /* * Setup STR71X, for more information about the register * take a look in the STR71x Microcontroller Reference Manual. * * Reference is made to: Rev. 6 March 2005 * * 1. Map internal RAM to address 0 * In this case, we are running always in the RAM * this make no sence. But if we are in flash, we * can copy the interrupt vectors into the ram and * switch to RAM mode. * * 2. Setup the PLL, the eval board HITEX STR7 is equipped * with an external 16MHz oscillator. We want: * * RCLK: 32MHz = (CLK2 * 16) / 4 * MCLK: 32Mhz * PCLK1: 32MHz * PCLK2: 32MHz * */ /* * 1. Map RAM to the boot memory 0x00000000 */ ldr r0, =PRCCU_BASE ldr r1, =0x01C2 str r1, [r0, #PCU_BOOTCR] /* * 2. Setup PLL start */ /* Set the prescaling factor for APB and APB1 group */ ldr r0, =PRCCU_BASE ldr r1, =0x0000 /* no prescaling PCLKx = RCLK */ str r1, [r0, #PCU_PDIVR] /* Set the prescaling factor for the Main System Clock MCLK */ ldr r0, =PRCCU_BASE ldr r1, =0x0000 /* no prescaling MCLK = RCLK str r1, [r0, #PCU_MDIVR] /* Configure the PLL1 ( * 16 , / 4 ) */ ldr r0, =PRCCU_BASE ldr r1, =0x0073 str r1, [r0, #RCCU_PLL1CR] /* Check if the PLL is locked */ pll_lock_loop: ldr r1, [r0, #RCCU_CFR] tst r1, #0x0002 beq pll_lock_loop /* Select PLL1_Output as RCLK clock */ ldr r0, =PRCCU_BASE ldr r1, =0x8009 str r1, [r0, #RCCU_CFR] /* * Setup PLL end */ /* * Setup a stack for each mode */ msr CPSR_c, #ARM_MODE_UNDEF | I_BIT | F_BIT /* Undefined Instruction Mode */ ldr sp, =__stack_und_end__ msr CPSR_c, #ARM_MODE_ABORT | I_BIT | F_BIT /* Abort Mode */ ldr sp, =__stack_abt_end__ msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT /* FIQ Mode */ ldr sp, =__stack_fiq_end__ msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT /* IRQ Mode */ ldr sp, =__stack_irq_end__ msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT /* Supervisor Mode */ ldr sp, =__stack_svc_end__ /* * Now init all the sections */ /* * Relocate .data section (Copy from ROM to RAM) */ ldr r1, =_etext ldr r2, =__data_start ldr r3, =_edata LoopRel: cmp r2, r3 ldrlo r0, [r1], #4 strlo r0, [r2], #4 blo LoopRel /* * Clear .bss section (Zero init) */ mov r0, #0 ldr r1, =__bss_start__ ldr r2, =__bss_end__ LoopZI: cmp r1, r2 strlo r0, [r1], #4 blo LoopZI /* * Call C++ constructors */ ldr r0, =__ctors_start__ ldr r1, =__ctors_end__ ctor_loop: cmp r0, r1 beq ctor_end ldr r2, [r0], #4 stmfd sp!, {r0-r1} mov lr, pc mov pc, r2 ldmfd sp!, {r0-r1} b ctor_loop ctor_end: /* * Jump to main */ mrs r0, cpsr bic r0, r0, #I_BIT | F_BIT /* Enable FIQ and IRQ interrupt */ msr cpsr, r0 mov r0, #0 /* No arguments */ mov r1, #0 /* No arguments */ ldr r2, =main mov lr, pc bx r2 /* And jump... */ ExitFunction: nop nop nop b ExitFunction /****************************************************************************/ /* Default interrupt handler */ /****************************************************************************/ UndefHandler: b UndefHandler SWIHandler: b SWIHandler PAbortHandler: b PAbortHandler DAbortHandler: b DAbortHandler IRQHandler: b IRQHandler FIQHandler: b FIQHandler .weak ExitFunction .weak UndefHandler, PAbortHandler, DAbortHandler .weak IRQHandler, FIQHandler .ltorg /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710Test/src/main.c ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial * 26.01.08 mifi Added variable "d" to test const variable. ****************************************************************************/ #define __MAIN_C__ /* * I use the include only, to show * how to setup a include dir in the makefile */ #include "typedefs.h" /* Increase the size of this dummy global data to create a larger ROM image */ static const char test[] = "ljasdfljkasdfljsaflsjadflksjadflksjadfasdfsadfsa" "ljasdfljkasdfljsaflsjadflksjadflksjadfasdfsadfsa" "ljasdfljkasdfljsaflsjadflksjadflksjadfasdfsadfsa" "ljasdfljkasdfljsaflsjadflksjadflksjadfasdfsadfsa" "ljasdfljkasdfljsaflsjadflksjadflksjadfasdfsadfsa" "ljasdfljkasdfljsaflsjadflksjadflksjadfasdfsadfsa" "ljasdfljkasdfljsaflsjadflksjadflksjadfasdfsadfsa" "ljasdfljkasdfljsaflsjadflksjadflksjadfasdfsadfsa" "ljasdfljkasdfljsaflsjadflksjadflksjadfasdfsadfsa"; /*=========================================================================*/ /* DEFINE: All Structures and Common Constants */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Prototypes */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Definition of all local Data */ /*=========================================================================*/ static const DWORD d = 7; /*=========================================================================*/ /* DEFINE: Definition of all local Procedures */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: All code exported */ /*=========================================================================*/ /***************************************************************************/ /* main */ /***************************************************************************/ int main (void) { DWORD a = 1; DWORD b = 2; DWORD c = 0; a = a + d; while (1) { a++; b++; c = a + b; } /* * This return here make no sense. * But to prevent the compiler warning: * "return type of 'main' is not 'int' * we use an int as return :-) */ return(0); } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710Test/test_ram.hex ================================================ :020000042000DA :100000000000A0E10000A0E10000A0E10000A0E1EC :100010000000A0E10000A0E10000A0E10000A0E1DC :100020000A02A0E304119FE5501080E50A02A0E354 :100030000010A0E3441080E50A02A0E30010A0E352 :100040000A02A0E37310A0E3181080E5081090E501 :10005000020011E3FCFFFF0A0A02A0E3D0109FE5B3 :10006000081080E5DBF021E3C8D09FE5D7F021E35D :10007000C4D09FE5D1F021E3C0D09FE5D2F021E3C9 :10008000BCD09FE5D3F021E3B8D09FE5B8109FE541 :10009000B8209FE5B8309FE5030052E10400913499 :1000A00004008234FBFFFF3A0000A0E3A4109FE5A8 :1000B000A4209FE5020051E104008134FCFFFF3AD7 :1000C00098009FE598109FE5010050E10500000AA7 :1000D000042090E403002DE90FE0A0E102F0A0E18C :1000E0000300BDE8F7FFFFEA00000FE1C000C0E336 :1000F00000F029E10000A0E30010A0E364209FE5E8 :100100000FE0A0E112FF2FE10000A0E10000A0E15C :100110000000A0E1FBFFFFEAFEFFFFEAFEFFFFEAAF :10012000FEFFFFEAFEFFFFEAFEFFFFEAFEFFFFEA37 :10013000C201000009800000100F0020100F0020F5 :10014000100B0020100B0020100F002010020020C8 :1001500010020020100200201002002010020020D7 :100160000C0200200C0200206C0100200CD04DE29B :100170000130A0E300308DE50230A0E304308DE5CE :100180000030A0E308308DE538309FE5002093E58E :1001900000309DE5023083E000308DE500309DE5C4 :1001A000013083E200308DE504309DE5013083E2CB :1001B00004308DE500209DE504309DE5033082E0AC :0C01C00008308DE5F4FFFFEA0C0200207F :1001CC0018F09FE518F09FE518F09FE518F09FE5F3 :1001DC0018F09FE518F09FE518F09FE518F09FE5E3 :1001EC0000000020180100201C010020200100202C :1001FC002401002000000000280100202C01002018 :04020C0007000000E7 :0400000520000000D7 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR710Test/test_rom.hex ================================================ :020000044000BA :100000000000A0E10000A0E10000A0E10000A0E1EC :100010000000A0E10000A0E10000A0E10000A0E1DC :100020000A02A0E304119FE5501080E50A02A0E354 :100030000010A0E3441080E50A02A0E30010A0E352 :100040000A02A0E37310A0E3181080E5081090E501 :10005000020011E3FCFFFF0A0A02A0E3D0109FE5B3 :10006000081080E5DBF021E3C8D09FE5D7F021E35D :10007000C4D09FE5D1F021E3C0D09FE5D2F021E3C9 :10008000BCD09FE5D3F021E3B8D09FE5B8109FE541 :10009000B8209FE5B8309FE5030052E10400913499 :1000A00004008234FBFFFF3A0000A0E3A4109FE5A8 :1000B000A4209FE5020051E104008134FCFFFF3AD7 :1000C00098009FE598109FE5010050E10500000AA7 :1000D000042090E403002DE90FE0A0E102F0A0E18C :1000E0000300BDE8F7FFFFEA00000FE1C000C0E336 :1000F00000F029E10000A0E30010A0E364209FE5E8 :100100000FE0A0E112FF2FE10000A0E10000A0E15C :100110000000A0E1FBFFFFEAFEFFFFEAFEFFFFEAAF :10012000FEFFFFEAFEFFFFEAFEFFFFEAFEFFFFEA37 :10013000C201000009800000000D0020000D002019 :100140000009002000090020000D002010020040DE :10015000000000200000002000000020000000201F :100160000C0200400C0200406C0100400CD04DE23B :100170000130A0E300308DE50230A0E304308DE5CE :100180000030A0E308308DE538309FE5002093E58E :1001900000309DE5023083E000308DE500309DE5C4 :1001A000013083E200308DE504309DE5013083E2CB :1001B00004308DE500209DE504309DE5033082E0AC :0C01C00008308DE5F4FFFFEA0C0200405F :1001CC0018F09FE518F09FE518F09FE518F09FE5F3 :1001DC0018F09FE518F09FE518F09FE518F09FE5E3 :1001EC0000000040180100401C01004020010040AC :1001FC002401004000000000280100402C010040B8 :04020C0007000000E7 :0400000540000000B7 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR912Test/inc/typedefs.h ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial ****************************************************************************/ #ifndef __TYPEDEFS_H__ #define __TYPEDEFS_H__ /* * Some types to use Windows like source */ typedef char CHAR; /* 8-bit signed data */ typedef unsigned char BYTE; /* 8-bit unsigned data */ typedef unsigned short WORD; /* 16-bit unsigned data */ typedef long LONG; /* 32-bit signed data */ typedef unsigned long ULONG; /* 32-bit unsigned data */ typedef unsigned long DWORD; /* 32-bit unsigned data */ #endif /* !__TYPEDEFS_H__ */ /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR912Test/prj/eclipse_ram.gdb ================================================ target remote localhost:3333 monitor reset monitor sleep 500 monitor poll monitor soft_reset_halt monitor arm7_9 sw_bkpts enable # Set SRAM size to 96 KB monitor mww 0x5C002034 0x0197 monitor mdw 0x5C002034 # Set Flash, Bank0 size to 512 KB monitor mww 0x54000000 0xf load break main continue ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR912Test/prj/eclipse_rom.gdb ================================================ target remote localhost:3333 monitor reset monitor sleep 500 monitor poll monitor soft_reset_halt monitor arm7_9 force_hw_bkpts enable # Set SRAM size to 96 KB monitor mww 0x5C002034 0x0197 monitor mdw 0x5C002034 # Set Flash, Bank0 size to 512 KB monitor mww 0x54000000 0xf load break main continue ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR912Test/prj/str912_jtagkey.cfg ================================================ #daemon configuration telnet_port 4444 gdb_port 3333 # tell gdb our flash memory map # and enable flash programming gdb_memory_map enable gdb_flash_program enable #interface interface ft2232 ft2232_device_desc "Amontec JTAGkey A" ft2232_layout jtagkey ft2232_vid_pid 0x0403 0xcff8 jtag_speed 1 jtag_nsrst_delay 100 jtag_ntrst_delay 100 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config trst_and_srst #jtag scan chain jtag newtap str9 flash -irlen 8 jtag newtap str9 cpu -irlen 4 -irmask 0xf jtag newtap str9 bs -irlen 5 #target configuration target create target0 arm966e -endian little -chain-position 1 [new_target_name] configure -work-area-virt 0 -work-area-phys 0x50000000 -work-area-size 16384 -work-area-backup false target_script 0 gdb_program_config .\prj\str912_program.script #flash bank str7x 0 0 flash bank str9x 0x00000000 0x00080000 0 0 0 # For more information about the configuration files, # look at the OpenOCD User's Guide. init reset halt ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR912Test/prj/str912_program.script ================================================ str9x flash_config 0 4 2 0 0x80000 flash protect 0 0 7 off ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR912Test/prj/str912_ram.ld ================================================ /*********************************************************************************** * Copyright 2005 Anglia Design * This demo code and associated components are provided as is and has no warranty, * implied or otherwise. You are free to use/modify any of the provided * code at your own risk in your applications with the expressed limitation * of liability (see below) * * LIMITATION OF LIABILITY: ANGLIA OR ANGLIA DESIGNS SHALL NOT BE LIABLE FOR ANY * LOSS OF PROFITS, LOSS OF USE, LOSS OF DATA, INTERRUPTION OF BUSINESS, NOR FOR * INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND WHETHER UNDER * THIS AGREEMENT OR OTHERWISE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * Author : Spencer Oliver * Web : www.anglia-designs.com * ***********************************************************************************/ /* Stack Sizes */ _STACKSIZE = 1024; _STACKSIZE_IRQ = 256; _STACKSIZE_FIQ = 0; _STACKSIZE_SVC = 1024; _STACKSIZE_ABT = 0; _STACKSIZE_UND = 0; _HEAPSIZE = 1024; /* Memory Definitions */ MEMORY { DATA (rw) : ORIGIN = 0x04000000, LENGTH = 0x00018000 } /* Section Definitions */ SECTIONS { /* first section is .text which is used for code */ .text : { KEEP(*(.vectors)) KEEP(*(.init)) *(.text .text.*) *(.gnu.linkonce.t.*) *(.glue_7t .glue_7) KEEP(*(.fini)) *(.gcc_except_table) } >DATA =0 . = ALIGN(4); /* .ctors .dtors are used for c++ constructors/destructors */ .ctors : { PROVIDE(__ctors_start__ = .); KEEP(*(SORT(.ctors.*))) KEEP(*(.ctors)) PROVIDE(__ctors_end__ = .); } >DATA .dtors : { PROVIDE(__dtors_start__ = .); KEEP(*(SORT(.dtors.*))) KEEP(*(.dtors)) PROVIDE(__dtors_end__ = .); } >DATA /* .rodata section which is used for read-only data (constants) */ .rodata : { *(.rodata .rodata.*) *(.gnu.linkonce.r.*) } >DATA . = ALIGN(4); _etext = .; PROVIDE (etext = .); /* .data section which is used for initialized data */ .data : AT (_etext) { *(.data .data.*) *(.gnu.linkonce.d.*) SORT(CONSTRUCTORS) } >DATA . = ALIGN(4); __data_start = .; _edata = .; PROVIDE (edata = .); /* .bss section which is used for uninitialized data */ .bss : { __bss_start = .; __bss_start__ = .; *(.bss .bss.*) *(.gnu.linkonce.b.*) *(COMMON) . = ALIGN(4); } >DATA . = ALIGN(4); __bss_end__ = .; _end = .; PROVIDE(end = .); /* .heap section which is used for memory allocation */ .heap (NOLOAD) : { __heap_start__ = .; *(.heap) . = MAX(__heap_start__ + _HEAPSIZE , .); } >DATA __heap_end__ = __heap_start__ + SIZEOF(.heap); /* .stack section - user mode stack */ .stack (__heap_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_start__ = .; *(.stack) . = MAX(__stack_start__ + _STACKSIZE , .); } >DATA __stack_end__ = __stack_start__ + SIZEOF(.stack); /* .stack_irq section */ .stack_irq (__stack_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_irq_start__ = .; *(.stack_irq) . = MAX(__stack_irq_start__ + _STACKSIZE_IRQ , .); } >DATA __stack_irq_end__ = __stack_irq_start__ + SIZEOF(.stack_irq); /* .stack_fiq section */ .stack_fiq (__stack_irq_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_fiq_start__ = .; *(.stack_fiq) . = MAX(__stack_fiq_start__ + _STACKSIZE_FIQ , .); } >DATA __stack_fiq_end__ = __stack_fiq_start__ + SIZEOF(.stack_fiq); /* .stack_svc section */ .stack_svc (__stack_fiq_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_svc_start__ = .; *(.stack_svc) . = MAX(__stack_svc_start__ + _STACKSIZE_SVC , .); } >DATA __stack_svc_end__ = __stack_svc_start__ + SIZEOF(.stack_svc); /* .stack_abt section */ .stack_abt (__stack_svc_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_abt_start__ = .; *(.stack_abt) . = MAX(__stack_abt_start__ + _STACKSIZE_ABT , .); } >DATA __stack_abt_end__ = __stack_abt_start__ + SIZEOF(.stack_abt); /* .stack_und section */ .stack_und (__stack_abt_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_und_start__ = .; *(.stack_und) . = MAX(__stack_und_start__ + _STACKSIZE_UND , .); } >DATA __stack_und_end__ = __stack_und_start__ + SIZEOF(.stack_und); /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR912Test/prj/str912_rom.ld ================================================ /*********************************************************************************** * Copyright 2005 Anglia Design * This demo code and associated components are provided as is and has no warranty, * implied or otherwise. You are free to use/modify any of the provided * code at your own risk in your applications with the expressed limitation * of liability (see below) * * LIMITATION OF LIABILITY: ANGLIA OR ANGLIA DESIGNS SHALL NOT BE LIABLE FOR ANY * LOSS OF PROFITS, LOSS OF USE, LOSS OF DATA, INTERRUPTION OF BUSINESS, NOR FOR * INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND WHETHER UNDER * THIS AGREEMENT OR OTHERWISE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * Author : Spencer Oliver * Web : www.anglia-designs.com * ***********************************************************************************/ /* Stack Sizes */ _STACKSIZE = 1024; _STACKSIZE_IRQ = 256; _STACKSIZE_FIQ = 0; _STACKSIZE_SVC = 1024; _STACKSIZE_ABT = 0; _STACKSIZE_UND = 0; _HEAPSIZE = 1024; /* Memory Definitions */ MEMORY { CODE (rx) : ORIGIN = 0x00000000, LENGTH = 0x00080000 DATA (rw) : ORIGIN = 0x04000000, LENGTH = 0x00018000 } /* Section Definitions */ SECTIONS { /* first section is .text which is used for code */ .text : { CREATE_OBJECT_SYMBOLS KEEP(*(.vectors)) KEEP(*(.init)) *(.text .text.*) *(.gnu.linkonce.t.*) *(.glue_7t) *(.glue_7) *(.vfp11_veneer) KEEP(*(.fini)) *(.gcc_except_table) } >CODE =0 . = ALIGN(4); /* .ctors .dtors are used for c++ constructors/destructors */ .ctors : { PROVIDE(__ctors_start__ = .); KEEP(*(SORT(.ctors.*))) KEEP(*(.ctors)) PROVIDE(__ctors_end__ = .); } >CODE .dtors : { PROVIDE(__dtors_start__ = .); KEEP(*(SORT(.dtors.*))) KEEP(*(.dtors)) PROVIDE(__dtors_end__ = .); } >CODE /* .rodata section which is used for read-only data (constants) */ .rodata : { *(.rodata .rodata.*) *(.gnu.linkonce.r.*) } >CODE . = ALIGN(4); .init_array : { *(.init) *(.fini) PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .); PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE_HIDDEN (__fini_array_end = .); } >CODE . = ALIGN(4); /* .ARM.exidx is sorted, so has to go in its own output section. */ __exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >CODE __exidx_end = .; _etext = .; PROVIDE (etext = .); /* .data section which is used for initialized data */ .data : AT (_etext) { __data_start = .; *(.data .data.*) *(.gnu.linkonce.d.*) SORT(CONSTRUCTORS) . = ALIGN(4); *(.fastrun .fastrun.*) } >DATA . = ALIGN(4); _edata = .; PROVIDE (edata = .); /* .bss section which is used for uninitialized data */ .bss : { __bss_start = .; __bss_start__ = .; *(.bss .bss.*) *(.gnu.linkonce.b.*) *(COMMON) . = ALIGN(4); } >DATA . = ALIGN(4); __bss_end__ = .; _end = .; PROVIDE(end = .); /* .heap section which is used for memory allocation */ .heap (NOLOAD) : { __heap_start__ = .; *(.heap) . = MAX(__heap_start__ + _HEAPSIZE , .); } >DATA __heap_end__ = __heap_start__ + SIZEOF(.heap); /* .stack section - user mode stack */ .stack (__heap_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_start__ = .; *(.stack) . = MAX(__stack_start__ + _STACKSIZE , .); } >DATA __stack_end__ = __stack_start__ + SIZEOF(.stack); /* .stack_irq section */ .stack_irq (__stack_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_irq_start__ = .; *(.stack_irq) . = MAX(__stack_irq_start__ + _STACKSIZE_IRQ , .); } >DATA __stack_irq_end__ = __stack_irq_start__ + SIZEOF(.stack_irq); /* .stack_fiq section */ .stack_fiq (__stack_irq_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_fiq_start__ = .; *(.stack_fiq) . = MAX(__stack_fiq_start__ + _STACKSIZE_FIQ , .); } >DATA __stack_fiq_end__ = __stack_fiq_start__ + SIZEOF(.stack_fiq); /* .stack_svc section */ .stack_svc (__stack_fiq_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_svc_start__ = .; *(.stack_svc) . = MAX(__stack_svc_start__ + _STACKSIZE_SVC , .); } >DATA __stack_svc_end__ = __stack_svc_start__ + SIZEOF(.stack_svc); /* .stack_abt section */ .stack_abt (__stack_svc_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_abt_start__ = .; *(.stack_abt) . = MAX(__stack_abt_start__ + _STACKSIZE_ABT , .); } >DATA __stack_abt_end__ = __stack_abt_start__ + SIZEOF(.stack_abt); /* .stack_und section */ .stack_und (__stack_abt_end__ + 3) / 4 * 4 (NOLOAD) : { __stack_und_start__ = .; *(.stack_und) . = MAX(__stack_und_start__ + _STACKSIZE_UND , .); } >DATA __stack_und_end__ = __stack_und_start__ + SIZEOF(.stack_und); /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR912Test/src/main.c ================================================ /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * **************************************************************************** * History: * * 30.03.06 mifi First Version for Insight tutorial * 26.01.08 mifi Added variable "d" to test const variable. ****************************************************************************/ #define __MAIN_C__ /* * I use the include only, to show * how to setup a include dir in the makefile */ #include "typedefs.h" /*=========================================================================*/ /* DEFINE: All Structures and Common Constants */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Prototypes */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: Definition of all local Data */ /*=========================================================================*/ static const DWORD d = 7; /*=========================================================================*/ /* DEFINE: Definition of all local Procedures */ /*=========================================================================*/ /*=========================================================================*/ /* DEFINE: All code exported */ /*=========================================================================*/ /***************************************************************************/ /* main */ /***************************************************************************/ int main (void) { DWORD a = 1; DWORD b = 2; DWORD c = 0; a = a + d; while (1) { a++; b++; c = a + b; } /* * This return here make no sense. * But to prevent the compiler warning: * "return type of 'main' is not 'int' * we use an int as return :-) */ return(0); } /*** EOF ***/ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR912Test/src/startup.s ================================================ /*********************************************************************************** * Copyright 2005 Anglia Design * This demo code and associated components are provided as is and has no warranty, * implied or otherwise. You are free to use/modify any of the provided * code at your own risk in your applications with the expressed limitation * of liability (see below) * * LIMITATION OF LIABILITY: ANGLIA OR ANGLIA DESIGNS SHALL NOT BE LIABLE FOR ANY * LOSS OF PROFITS, LOSS OF USE, LOSS OF DATA, INTERRUPTION OF BUSINESS, NOR FOR * INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND WHETHER UNDER * THIS AGREEMENT OR OTHERWISE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * Author : Spencer Oliver * Web : www.anglia-designs.com * * mifi, 22.01.2008, small changes by the init of the C++ eabi constructors. * Here I have replaced the eabi init by the normal init. * Thanks to Spen for the startup code. ***********************************************************************************/ /**** Startup Code (executed after Reset) ****/ /* Frequency values kHz */ /* set to suit target hardware */ .equ FOSC, 25000 /* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs */ .equ Mode_USR, 0x10 .equ Mode_FIQ, 0x11 .equ Mode_IRQ, 0x12 .equ Mode_SVC, 0x13 .equ Mode_ABT, 0x17 .equ Mode_UND, 0x1B .equ Mode_SYS, 0x1F /* available on ARM Arch 4 and later */ .equ I_Bit, 0x80 /* when I bit is set, IRQ is disabled */ .equ F_Bit, 0x40 /* when F bit is set, FIQ is disabled */ .equ SRAM32, 0x00 .equ SRAM64, 0x08 .equ SRAM96, 0x10 /* --- System memory locations */ .equ SCRO_AHB_UMB, 0x5C002034 /* System configuration register 0 (unbuffered) */ .equ FMI_BASE_UMB, 0x54000000 /* Flash FMI base address (unbuffered) */ .equ BBSR_off_addr, 0x00 .equ NBBSR_off_addr, 0x04 .equ BBADR_off_addr, 0x0C .equ NBBADR_off_addr, 0x10 .equ CR_off_addr, 0x18 .ifndef LIBUFF .equ LIBUFF, 0 .endif /* Startup Code must be linked first at Address at which it expects to run. */ .text .arm .section .init, "ax" .global _start .global _Main_Crystal /* After remap this will be our reset handler */ _start: LDR pc, =NextInst NextInst: NOP /* Wait for OSC stabilization */ NOP NOP NOP NOP NOP NOP NOP NOP /* Enable buffered mode */ .if LIBUFF MRC p15, 0, r0, c1, c0, 0 /* Read CP15 register 1 into r0 */ ORR r0, r0, #0x8 /* Enable Write Buffer on AHB */ MCR p15, 0, r0, c1, c0, 0 /* Write CP15 register 1 */ .endif /* Remap Flash Bank 0 at address 0x0 and Bank 1 at address 0x80000, */ /* when the bank 0 is the boot bank, then enable the Bank 1. */ LDR r0, =FMI_BASE_UMB LDR r1, =0x4 /* configure 512KB Boot bank 0 */ STR r1, [r0, #BBSR_off_addr] LDR r1, =0x2 /* configure 32KB Non Boot bank 1 */ STR r1, [r0, #NBBSR_off_addr] LDR r1, =(0x00000000 >> 2) /* Boot Bank Base Address */ STR r1, [r0, #BBADR_off_addr] LDR r1, =(0x00080000 >> 2) /* Non Boot Bank Base Address */ STR r1, [r0, #NBBADR_off_addr] LDR r1, =0x18 /* Flash Banks 0 1 enabled */ STR r1, [r0, #CR_off_addr] /* Enable 96K RAM */ LDR r0, =SCRO_AHB_UMB # LDR r1, =0x0196 /* prefetch disabled, default enabled */ LDR r1, =0x0187|SRAM96 STR r1, [r0] /* Set bits 17-18 (Instruction/Data TCM order) of the */ /* Core Configuration Control Register */ MOV r0, #0x60000 MCR p15, 0x1, r0, c15, c1, 0 /* Setup Stack for each mode */ /* Enter Abort Mode and set its Stack Pointer */ MSR cpsr_c, #Mode_ABT|I_Bit|F_Bit LDR sp, =__stack_abt_end__ /* Enter Undefined Instruction Mode and set its Stack Pointer */ MSR cpsr_c, #Mode_UND|I_Bit|F_Bit LDR sp, =__stack_und_end__ /* Enter Supervisor Mode and set its Stack Pointer */ MSR cpsr_c, #Mode_SVC|I_Bit|F_Bit LDR sp, =__stack_svc_end__ /* Enter FIQ Mode and set its Stack Pointer */ MSR cpsr_c, #Mode_FIQ|I_Bit|F_Bit LDR sp, =__stack_fiq_end__ /* Enter IRQ Mode and set its Stack Pointer */ MSR cpsr_c, #Mode_IRQ|I_Bit|F_Bit LDR sp, =__stack_irq_end__ /* Enter System/User Mode and set its Stack Pointer */ MSR cpsr_c, #Mode_SYS LDR sp, =__stack_end__ /* Setup a default Stack Limit (when compiled with "-mapcs-stack-check") */ LDR sl, =__bss_end__ /* Relocate .data section (Copy from ROM to RAM) */ LDR r1, =_etext LDR r2, =__data_start LDR r3, =_edata LoopRel: CMP r2, r3 LDRLO r0, [r1], #4 STRLO r0, [r2], #4 BLO LoopRel /* Clear .bss section (Zero init) */ MOV r0, #0 LDR r1, =__bss_start__ LDR r2, =__bss_end__ LoopZI: CMP r1, r2 STRLO r0, [r1], #4 BLO LoopZI /* Call C++ constructors */ LDR r0, =__ctors_start__ LDR r1, =__ctors_end__ ctor_loop: CMP r0, r1 BEQ ctor_end LDR r2, [r0], #4 STMFD sp!, {r0-r1} BLX r2 LDMFD sp!, {r0-r1} B ctor_loop ctor_end: /* Need to set up standard file handles */ /* Only used under simulator, normally overide syscall.c */ # BL initialise_monitor_handles /* if we use debug version of str9lib this will call the init function */ BL libdebug libdebug: /* Enter the C code, use B instruction so as to never return */ /* use BL main if you want to use c++ destructors below */ B main /* Return from main, loop forever. */ #exit_loop: # B exit_loop /* Fosc values, used by libstr9 */ _Main_Crystal: .long FOSC .weak libdebug .end ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR912Test/test_ram.hex ================================================ :020000040400F6 :10000000F8F09FE50000A0E10000A0E10000A0E101 :100010000000A0E10000A0E10000A0E10000A0E1DC :100020000000A0E10000A0E11503A0E30410A0E39C :10003000001080E50210A0E3041080E50010A0E3AA :100040000C1080E50218A0E3101080E51810A0E362 :10005000181080E5A8009FE5A8109FE5001080E536 :100060000608A0E3110F2FEED7F021E398D09FE50B :10007000DBF021E394D09FE5D3F021E390D09FE51E :10008000D1F021E38CD09FE5D2F021E388D09FE529 :100090001FF021E384D09FE584A09FE584109FE5B5 :1000A00084209FE584309FE5030052E104009134F1 :1000B00004008234FBFFFF3A0000A0E370109FE5CC :1000C0005C209FE5020051E104008134FCFFFF3A0F :1000D00060009FE560109FE5010050E10400000A08 :1000E000042090E403002DE932FF2FE10300BDE876 :1000F000F8FFFFEAFFFFFFEB100000EAA861000035 :10010000040000043420005C97010000A40E0004E9 :10011000A40E0004A40E0004A40A0004A40A00040F :10012000A4090004A4010004A4010004A401000423 :10013000A4010004A4010004A0010004A001000423 :100140000CD04DE20130A0E300308DE50230A0E399 :1001500004308DE50030A0E308308DE538309FE5B0 :10016000002093E500309DE5023083E000308DE50E :1001700000309DE5013083E200308DE504309DE5DF :10018000013083E204308DE500209DE504309DE5DB :10019000033082E008308DE5F4FFFFEAA00100049F :0401A0000700000054 :0400000504000000F3 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/STR912Test/test_rom.hex ================================================ :10000000F8F09FE50000A0E10000A0E10000A0E101 :100010000000A0E10000A0E10000A0E10000A0E1DC :100020000000A0E10000A0E11503A0E30410A0E39C :10003000001080E50210A0E3041080E50010A0E3AA :100040000C1080E50218A0E3101080E51810A0E362 :10005000181080E5A8009FE5A8109FE5001080E536 :100060000608A0E3110F2FEED7F021E398D09FE50B :10007000DBF021E394D09FE5D3F021E390D09FE51E :10008000D1F021E38CD09FE5D2F021E388D09FE529 :100090001FF021E384D09FE584A09FE584109FE5B5 :1000A00084209FE584309FE5030052E104009134F1 :1000B00004008234FBFFFF3A0000A0E370109FE5CC :1000C0005C209FE5020051E104008134FCFFFF3A0F :1000D00060009FE560109FE5010050E10400000A08 :1000E000042090E403002DE932FF2FE10300BDE876 :1000F000F8FFFFEAFFFFFFEB100000EAA861000035 :10010000040000003420005C97010000000D000492 :10011000000D0004000D00040009000400090004A3 :100120000008000400000004A40100000000000416 :100130000000000400000004A0010000A001000075 :100140000CD04DE20130A0E300308DE50230A0E399 :1001500004308DE50030A0E308308DE538309FE5B0 :10016000002093E500309DE5023083E000308DE50E :1001700000309DE5013083E200308DE504309DE5DF :10018000013083E204308DE500209DE504309DE5DB :10019000033082E008308DE5F4FFFFEAA0010000A3 :0401A0000700000054 :00000001FF ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/cortex/cm3-ftest.cfg ================================================ # # For each named Cortex-M3 vector_catch flag VECTOR ... # bus_err state_err # chk_err nocp_err # mm_err reset # # BUT NYET hard_err, int_err (their test cases don't yet work) ... # # Do the following: # # - Test #1: verify that OpenOCD ignores exceptions by default # + l_VECTOR (loads testcase to RAM) # + fault triggers loop-to-self exception "handler" # + "halt" # + observe fault "handling" -- loop-to-self from load_and_run (below) # # - Test #2: verify that "vector_catch" makes OpenOCD stops ignoring them # + cortex_m vector_catch none # + cortex_m vector_catch VECTOR # + l_VECTOR (loads testcase to RAM) # + fault triggers vector catch hardware # + observe OpenOCD entering debug state with no assistance # # NOTE "reset" includes the NVIC, so that test case gets its reset vector # from the flash, not from the vector table set up here. Which means that # for that vector_catch option, the Test #1 (above) "observe" step won't # use the SRAM address. # # we can fully automate test #2 proc vector_test {tag} { halt # REVISIT -- annoying, we'd like to scrap vector_catch output cortex_m vector_catch none cortex_m vector_catch $tag eval "l_$tag" } # # Load and start one vector_catch test case. # # name -- tag for the vector_catch flag being tested # halfwords -- array of instructions (some wide, some narrow) # n_instr -- how many instructions are in $halfwords # proc load_and_run { name halfwords n_instr } { reset halt # Load code at beginning of SRAM. echo "# code to trigger $name vector" set addr 0x20000000 # write_memory should be faster, though we'd need to # compute the resulting $addr ourselves foreach opcode $halfwords { mwh $addr $opcode incr addr 2 } # create default loop-to-self at $addr ... it serves as # (a) "main loop" on error # (b) handler for all exceptions that get triggered mwh $addr 0xe7fe # disassemble, as sanity check and what's-happening trace arm disassemble 0x20000000 [expr 1 + $n_instr ] # Assume that block of code is at most 16 halfwords long. # Create a basic table of loop-to-self exception handlers. mww 0x20000020 $addr 16 # Store its address in VTOR mww 0xe000ed08 0x20000020 # Use SHCSR to ensure nothing escalates to a HardFault mww 0xe000ed24 0x00070000 # now start, trigering the $name vector catch logic resume 0x20000000 } #proc l_hard_err {} { # IMPLEMENT ME # FORCED -- escalate something to HardFault #} #proc l_int_err {} { # IMPLEMENT ME # STKERR -- exception stack BusFault #} # BusFault, escalates to HardFault proc l_bus_err {} { # PRECISERR -- assume less than 512 MBytes of SRAM load_and_run bus_err { 0xf06f 0x4040 0x7800 } 2 } # UsageFault, escalates to HardFault proc l_state_err {} { # UNDEFINSTR -- issue architecturally undefined instruction load_and_run state_err { 0xde00 } 1 } # UsageFault, escalates to HardFault proc l_chk_err {} { # UNALIGNED -- LDM through unaligned pointer load_and_run chk_err { 0xf04f 0x0001 0xe890 0x0006 } 2 } # UsageFault, escalates to HardFault proc l_nocp_err {} { # NOCP -- issue cp14 DCC instruction load_and_run nocp_err { 0xee10 0x0e15 } 1 } # MemManage, escalates to HardFault proc l_mm_err {} { # IACCVIOL -- instruction fetch from an XN region load_and_run mm_err { 0xf04f 0x4060 0x4687 } 2 } proc l_reset {} { # issue SYSRESETREQ via AIRCR load_and_run reset { 0xf04f 0x0104 0xf2c0 0x51fa 0xf44f 0x406d 0xf100 0x000c 0xf2ce 0x0000 0x6001 } 6 } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/cortex/fault.c ================================================ /* * COMPILE: arm-none-eabi-gcc -mthumb -march=armv7-m ... * ... plus, provide at least a default exception vector table. * * RUN: this is best run from SRAM. It starts at main() then triggers * a fault before more than a handful of instructions have executed. * Run each test case in two modes: * * (1) Faults caught on the Cortex-M3. Default handlers are usually * loop-to-self NOPs, so a debugger won't notice faults until they * halt the core and examine xSPR and other registers. * * To verify the fault triggered, issue "halt" from OpenOCD; you * should be told about the fault and (some of) its details. * Then it's time to run the next test. * * NOTE however that "reset" will restart everything; verify that * case by observing your reset handler doing its normal work. * * (2) Faults intercepted by OpenOCD "vector_catch ..." commands. * * OpenOCD should tell you about the fault, and show the same * details, without your "halt" command. * * Someday, a fancy version of this code could provide a vector table and * fault handlers which use semihosting (when that works on Cortex-M3) to * report what happened, again without needing a "halt" command. */ /* These symbols match the OpenOCD "cortex_m vector_catch" bit names. */ enum vc_case { hard_err, int_err, bus_err, state_err, chk_err, nocp_err, mm_err, reset, }; /* REVISIT come up with a way to avoid recompiling, maybe: * - write it in RAM before starting * - compiled-in BKPT, manual patch of r0, then resume * - ... */ #ifndef VC_ID #warning "no VC_ID ... using reset" #define VC_ID reset #endif int main(void) __attribute__ ((externally_visible, noreturn)); /* * Trigger various Cortex-M3 faults to verify that OpenOCD behaves OK * in terms of its vector_catch handling. * * Fault handling should be left entirely up to the application code * UNLESS a "vector_catch" command tells OpenOCD to intercept a fault. * * See ARMv7-M architecure spec table B1-9 for the list of faults and * their mappings to the vector catch bits. */ int main(void) { /* One test case for each vector catch bit. We're not doing * hardware testing; so it doesn't matter when some DEMCR bits * could apply in multiple ways. */ switch (VC_ID) { /* "cortex_m vector_catch hard_err" */ case hard_err: /* FORCED - Fault escalation */ /* FIXME code this */ break; /* "cortex_m vector_catch int_err" */ case int_err: /* STKERR -- Exception stack BusFault */ /* FIXME code this */ break; /* "cortex_m vector_catch bus_err" */ case bus_err: /* PRECISERR -- precise data bus read * Here we assume a Cortex-M3 with 512 MBytes SRAM is very * unlikely, so the last SRAM byte isn't a valid address. */ __asm__ volatile( "mov r0, #0x3fffffff\n" "ldrb r0, [r0]\n" ); break; /* "cortex_m vector_catch state_err" */ case state_err: /* UNDEFINSTR -- architectural undefined instruction */ __asm__ volatile(".hword 0xde00"); break; /* "cortex_m vector_catch chk_err" */ case chk_err: /* UNALIGNED ldm */ __asm__ volatile( "mov r0, #1\n" "ldm r0, {r1, r2}\n" ); break; /* "cortex_m vector_catch nocp_err" */ case nocp_err: /* NOCP ... Cortex-M3 has no coprocessors (like CP14 DCC), * but these instructions are allowed by ARMv7-M. */ __asm__ volatile("mrc p14, 0, r0, c0, c5, 0"); break; /* "cortex_m vector_catch mm_err" */ case mm_err: /* IACCVIOL -- instruction fetch from an XN region */ __asm__ volatile( "mov r0, #0xe0000000\n" "mov pc, r0\n" ); break; /* "cortex_m vector_catch reset" */ case reset: __asm__ volatile( /* r1 = SYSRESETREQ */ "mov r1, #0x0004\n" /* r1 |= VECTKEY */ "movt r1, #0x05fa\n" /* r0 = &AIRCR */ "mov r0, #0xed00\n" "add r0, #0xc\n" "movt r0, #0xe000\n" /* AIRCR = ... */ "str r1, [r0, #0]\n" ); break; } /* don't return */ while (1) continue; } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/cortex/test.c ================================================ /* simple app. modify test.ld to change address. Even if the app is position independent, the symbols need to match to test basic debugging. To load the app to 0x20000000 in GDB, use: load a.out monitor reg sp 0x20004000 monitor reg pc 0x20002000 stepi arm-elf-gcc -mthumb -mcpu = cortex-m3 -nostdlib -Ttest.ld test.c */ int j; void _start() { int i; for (i = 0; i < 1000; i++) { j++; } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/cortex/test.ld ================================================ OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) /* Do we need any of these for elf? __DYNAMIC = 0; */ SECTIONS { /* Read-only sections, merged into text segment: */ . = 0x20002000; .interp : { *(.interp) } .hash : { *(.hash) } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } .gnu.version : { *(.gnu.version) } .gnu.version_d : { *(.gnu.version_d) } .gnu.version_r : { *(.gnu.version_r) } .rel.init : { *(.rel.init) } .rela.init : { *(.rela.init) } .rel.text : { *(.rel.text) *(.rel.text.*) *(.rel.gnu.linkonce.t*) } .rela.text : { *(.rela.text) *(.rela.text.*) *(.rela.gnu.linkonce.t*) } .rel.fini : { *(.rel.fini) } .rela.fini : { *(.rela.fini) } .rel.rodata : { *(.rel.rodata) *(.rel.rodata.*) *(.rel.gnu.linkonce.r*) } .rela.rodata : { *(.rela.rodata) *(.rela.rodata.*) *(.rela.gnu.linkonce.r*) } .rel.data : { *(.rel.data) *(.rel.data.*) *(.rel.gnu.linkonce.d*) } .rela.data : { *(.rela.data) *(.rela.data.*) *(.rela.gnu.linkonce.d*) } .rel.ctors : { *(.rel.ctors) } .rela.ctors : { *(.rela.ctors) } .rel.dtors : { *(.rel.dtors) } .rela.dtors : { *(.rela.dtors) } .rel.got : { *(.rel.got) } .rela.got : { *(.rela.got) } .rel.sdata : { *(.rel.sdata) *(.rel.sdata.*) *(.rel.gnu.linkonce.s*) } .rela.sdata : { *(.rela.sdata) *(.rela.sdata.*) *(.rela.gnu.linkonce.s*) } .rel.sbss : { *(.rel.sbss) } .rela.sbss : { *(.rela.sbss) } .rel.bss : { *(.rel.bss) } .rela.bss : { *(.rela.bss) } .rel.plt : { *(.rel.plt) } .rela.plt : { *(.rela.plt) } .plt : { *(.plt) } .text : { *(.text) *(.text.*) *(.stub) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) *(.gnu.linkonce.t*) *(.glue_7t) *(.glue_7) } =0 .init : { KEEP (*(.init)) } =0 _etext = .; PROVIDE (etext = .); .fini : { KEEP (*(.fini)) } =0 .rodata : { *(.rodata) *(.rodata.*) *(.gnu.linkonce.r*) } .rodata1 : { *(.rodata1) } .eh_frame_hdr : { *(.eh_frame_hdr) } /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ . = ALIGN(256) + (. & (256 - 1)); .data : { *(.data) *(.data.*) *(.gnu.linkonce.d*) SORT(CONSTRUCTORS) } .data1 : { *(.data1) } .eh_frame : { KEEP (*(.eh_frame)) } .gcc_except_table : { *(.gcc_except_table) } .ctors : { /* gcc uses crtbegin.o to find the start of the constructors, so we make sure it is first. Because this is a wildcard, it doesn't matter if the user does not actually link against crtbegin.o; the linker won't look for a file to match a wildcard. The wildcard also means that it doesn't matter which directory crtbegin.o is in. */ KEEP (*crtbegin.o(.ctors)) /* We don't want to include the .ctor section from from the crtend.o file until after the sorted ctors. The .ctor section from the crtend file contains the end of ctors marker and it must be last */ KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } .dtors : { KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } .jcr : { KEEP (*(.jcr)) } .got : { *(.got.plt) *(.got) } .dynamic : { *(.dynamic) } /* We want the small data sections together, so single-instruction offsets can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ .sdata : { *(.sdata) *(.sdata.*) *(.gnu.linkonce.s.*) } _edata = .; PROVIDE (edata = .); __bss_start = .; __bss_start__ = .; .sbss : { *(.dynsbss) *(.sbss) *(.sbss.*) *(.scommon) } .bss : { *(.dynbss) *(.bss) *(.bss.*) *(COMMON) /* Align here to ensure that the .bss section occupies space up to _end. Align after .bss to ensure correct alignment even if the .bss section disappears because there are no input sections. */ . = ALIGN(32 / 8); } . = ALIGN(32 / 8); _end = .; _bss_end__ = . ; __bss_end__ = . ; __end__ = . ; PROVIDE (end = .); /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } .debug_ranges 0 : { *(.debug_ranges) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } .stack 0x20004000 : { _stack = .; *(.stack) } /* These must appear regardless of . */ } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/ledtest-imx27ads/crt0.S ================================================ /* Sample initialization file */ .extern main .extern exit /* .text is used instead of .section .text so it works with arm-aout too. */ .text .code 32 .align 0 .global _mainCRTStartup .global _start .global start start: _start: _mainCRTStartup: /* Start by setting up a stack */ /* Set up the stack pointer to end of bss */ ldr r3, .LC2 mov sp, r3 sub sl, sp, #512 /* Still assumes 512 bytes below sl */ mov a2, #0 /* Second arg: fill value */ mov fp, a2 /* Null frame pointer */ mov r7, a2 /* Null frame pointer for Thumb */ ldr a1, .LC1 /* First arg: start of memory block */ ldr a3, .LC2 /* Second arg: end of memory block */ sub a3, a3, a1 /* Third arg: length of block */ mov r0, #0 /* no arguments */ mov r1, #0 /* no argv either */ bl main bl exit /* Should not return */ /* For Thumb, constants must be after the code since only positive offsets are supported for PC relative addresses. */ .align 0 .LC1: .word __bss_start__ .LC2: .word __bss_end__ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/ledtest-imx27ads/gdbinit-imx27ads ================================================ echo Script to load ledtest on iMX27ADS.\n # Note: you need to startup openocd with "-f board/imx27ads.cfg" # in order to it initialize RAM memory. # SETUP GDB : # # Common gdb setup for ARM CPUs set complaints 1 set output-radix 10 set input-radix 10 set prompt (arm-gdb) set endian little dir . # CONNECT TO TARGET : target remote 127.0.0.1:3333 # LOAD IMAGE : # # Load the program executable called "u-boot" load test.elf # Load the symbols for the program. symbol-file test.elf # RUN TO MAIN : # # Set a breakpoint at main(). #b reset b main # Run to the breakpoint. c ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/ledtest-imx27ads/ldscript ================================================ SECTIONS { . = 0xA0000000; .text : { *(.text) } .data ALIGN(0x10): { *(.data) } .bss ALIGN(0x10): { __bss_start__ = ABSOLUTE(.); *(.bss) . += 0x100; } __bss_end__ = .; PROVIDE (__stack = .); _end = .; .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/ledtest-imx27ads/test.c ================================================ /*************************************************************************** * Copyright (C) 2009 by Alan Carvalho de Assis * * acassis@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * ***************************************************************************/ void delay() { int i; for (i = 0; i < 500000; i++); } /* MAIN ARM FUNTION */ int main (void) { int i; volatile unsigned char *ledoff = ((volatile unsigned char *)0xD4000008); volatile unsigned char *ledon = ((volatile unsigned char *)0xD400000C); for (i = 0; i < 10000; i++) { *ledon = 0x30; delay(); *ledoff = 0x30; delay(); } /* FOR */ } /* MAIN */ __gccmain() { } /* GCCMAIN */ void exit(int exit_code) { while (1); } /* EXIT */ atexit() { while (1); } /* ATEXIT */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/ledtest-imx31pdk/crt0.S ================================================ /* Sample initialization file */ .extern main .extern exit /* .text is used instead of .section .text so it works with arm-aout too. */ .text .code 32 .align 0 .global _mainCRTStartup .global _start .global start start: _start: _mainCRTStartup: /* Start by setting up a stack */ /* Set up the stack pointer to end of bss */ ldr r3, .LC2 mov sp, r3 sub sl, sp, #512 /* Still assumes 512 bytes below sl */ mov a2, #0 /* Second arg: fill value */ mov fp, a2 /* Null frame pointer */ mov r7, a2 /* Null frame pointer for Thumb */ ldr a1, .LC1 /* First arg: start of memory block */ ldr a3, .LC2 /* Second arg: end of memory block */ sub a3, a3, a1 /* Third arg: length of block */ mov r0, #0 /* no arguments */ mov r1, #0 /* no argv either */ bl main bl exit /* Should not return */ /* For Thumb, constants must be after the code since only positive offsets are supported for PC relative addresses. */ .align 0 .LC1: .word __bss_start__ .LC2: .word __bss_end__ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/ledtest-imx31pdk/gdbinit-imx31pdk ================================================ echo Script to load ledtest on iMX31PDK.\n # Note: you need to startup openocd with "-f board/imx31pdk.cfg" # in order to it initialize RAM memory. # SETUP GDB : # # Common gdb setup for ARM CPUs set complaints 1 set output-radix 10 set input-radix 10 set prompt (arm-gdb) set endian little dir . # CONNECT TO TARGET : target remote 127.0.0.1:3333 # LOAD IMAGE : # # Load the program executable called "u-boot" load test.elf # Load the symbols for the program. symbol-file test.elf # RUN TO MAIN : # # Set a breakpoint at main(). #b reset b main # Run to the breakpoint. c ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/ledtest-imx31pdk/ldscript ================================================ SECTIONS { . = 0x80000100; .text : { *(.text) } .data ALIGN(0x10): { *(.data) } .bss ALIGN(0x10): { __bss_start__ = ABSOLUTE(.); *(.bss) . += 0x100; } __bss_end__ = .; PROVIDE (__stack = .); _end = .; .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } } ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/examples/ledtest-imx31pdk/test.c ================================================ /*************************************************************************** * Copyright (C) 2009 by Alan Carvalho de Assis * * acassis@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * ***************************************************************************/ void delay() { int i; for (i = 0; i < 500000; i++); } /* MAIN ARM FUNTION */ int main (void) { volatile unsigned char *led = ((volatile unsigned char *)0xB6020000); while (1) { *led = 0xFF; delay(); *led = 0x00; delay(); } /* FOR */ } /* MAIN */ __gccmain() { } /* GCCMAIN */ void exit(int exit_code) { while (1); } /* EXIT */ atexit() { while (1); } /* ATEXIT */ ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/index.html ================================================

Release testing

A release test must be done on code committed to git. Commit, then test. That way one can know for sure *what* code was actually tested.

Note that this testing document does not have anything to do with testing that is done before committing to git. It is a test document for released code. Pre-commit testing is done mostly by the developer who has written the change. Sometimes code is committed to synchronize work, even if it has known problems. Release testing is done on code believed to be stable, often a couple of weeks old, and not by the developers, but rather users and community testers who has the requisite hardware and test setup. Also the testing will take place over an extended period of time.

All of the above makes it imperative that there can be no doubt about *which* code is tested and thus all tests refer to committed code by subversion number.

Release procedure

OpenOCD mainline is work in progress. Expect it to change daily and to have some quirks.

If you need the latest released and tested version, look for binary snapshots of OpenOCD. Worst case look up the test result table below for the features that are important to you and extract and build the version that has the right cocktail of working features for you. You can also work with the community to address the problems you are seing. Testing work and bug reports are highly appreciated.

The OpenOCD community may decide to create release branches. If this happens, then a branch will be created from OpenOCD mainline. The particular version to create that branch might be an older version rather than the latest and greatest. Fixes are then ported to that release branch from OpenOCD mainline.


OpenOCD smoketests

This is a set of tests that exercise the entire OpenOCD system and various targets. It is a small suite of systemwide smoketests.

Smoketests

Test cases

Additionally OpenOCD has test cases that target specific functionality more precisely.

A full release test must include both smoketests and unit testing.

Test cases ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/profile_stm32.txt ================================================ These are profile tests for the stm32 target. old version rev 1606: single step: 59 ms flash 64k : 24kB/s mdb 0 128 : 44ms trunk rev 1662: single step: 99 ms flash 64k : 21.5kB/s mdb 0 128 : 72ms How to run tests: poll off set before [flush_count] step set step_count [expr [flush_count]-$before] set before [flush_count] mdb 0 128 set mem_count [expr [flush_count]-$before] set before [flush_count] flash erase_address 0x8000000 0x10000 set erase_count [expr [flush_count]-$before] set before [flush_count] flash fillb 0x8000000 0x55 0x10000 set flash_fill_count [expr [flush_count]-$before] puts "counts" ; puts "step $step_count" ; puts "mem $mem_count" ; puts "erase $erase_count" ; puts "flash fill $flash_fill_count" parport trunk rev 1675 ====================== step 336 mem 160 erase 3076 flash fill 32754 verify_ircapture disable step 114 mem 96 erase 1547 flash fill 15564 ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/results/template.html ================================================ Testcases
TestInterfaceTargetResult
CON001 FILL IN! FILL IN!PASS/FAIL
CON002 FILL IN! FILL IN!PASS/FAIL
RES001 FILL IN! FILL IN!PASS/FAIL
RES002 FILL IN! FILL IN!PASS/FAIL
RES003 FILL IN! FILL IN!PASS/FAIL
DBG001 FILL IN! FILL IN!PASS/FAIL
================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/results/v0.4.0-rc1/AT91FR40162.html ================================================ Test results for revision 1.62

SAM7

Connectivity

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
CON001 AT91FR40162 ZY1000 Telnet connection Power on, jtag target attached On console, type
telnet ip port
Open On-Chip Debugger
>
Open On-Chip Debugger
>
PASS
CON002 AT91FR40162 ZY1000 GDB server connection Power on, jtag target attached On GDB console, type
target remote ip:port
Remote debugging using 10.0.0.73:3333 (gdb) tar remo 10.0.0.138:3333
Remote debugging using 10.0.0.138:3333
0x000155b8 in ?? ()
PASS

Reset

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
RES001 AT91FR40162 ZY1000 Reset halt on a blank target Erase all the content of the flash Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
> mdw 0x01000000 32
0x01000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> reset halt
JTAG tap: zy1000.cpu tap/device found: 0x1f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x1)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x600000d3 pc: 0x00008a70
>
PASS
RES002 AT91FR40162 ZY1000 Reset init on a blank target Erase all the content of the flash Connect via the telnet interface and type
reset init
Reset should return without error and the output should contain
executing reset script 'name_of_the_script'
> reset init
JTAG tap: zy1000.cpu tap/device found: 0x1f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x1)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x600000d3 pc: 0x00008ea4
>
PASS
NOTE! Even if there is no message, the reset script is being executed (proved by side effects)
RES003 AT91FR40162 ZY1000 Reset after a power cycle of the target Reset the target then power cycle the target Connect via the telnet interface and type
reset halt after the power was detected
Reset should return without error and the output should contain
target state: halted
Sensed nSRST asserted
Sensed power dropout.
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0xf00000d3 pc: 0xd5dff7e6
Sensed power restore.
Sensed nSRST deasserted
> reset halt
JTAG device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0xf00000d3 pc: 0x0000072c
>
PASS
RES004 AT91FR40162 ZY1000 Reset halt on a blank target where reset halt is supported Erase all the content of the flash Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
pc = 0
> reset halt
JTAG tap: zy1000.cpu tap/device found: 0x1f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x1)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0xf00000d3 pc: 0x00008b38
>
PASS
RES005 AT91FR40162 ZY1000 Reset halt on a blank target using return clock Erase all the content of the flash, set the configuration script to use RCLK Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
N/A, At91EB40A does NOT have support for RCLK N/A

JTAG Speed

ID Target ZY1000 Description Initial state Input Expected output Actual output Pass/Fail
SPD001 AT91FR40162 ZY1000 16MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > reset halt
JTAG tap: zy1000.cpu tap/device found: 0x1f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x1)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0xf00000d3 pc: 0x00008ae8
> jtag_khz 16000
jtag_speed 4 => JTAG clk=16.000000
16000 kHz
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
PASS
SPD002 AT91FR40162 ZY1000 8MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > reset halt
JTAG tap: zy1000.cpu tap/device found: 0x1f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x1)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0xf00000d3 pc: 0x00008c14
> jtag_khz 8000
jtag_speed 8 => JTAG clk=8.000000
8000 kHz
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
SPD003 AT91FR40162 ZY1000 4MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > reset halt
JTAG tap: zy1000.cpu tap/device found: 0x1f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x1)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0xf00000d3 pc: 0x00008bc4
> jtag_khz 4000
jtag_speed 16 => JTAG clk=4.000000
4000 kHz
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
SPD004 AT91FR40162 ZY1000 2MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > reset halt
JTAG tap: zy1000.cpu tap/device found: 0x1f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x1)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0xf00000d3 pc: 0x00009678
> jtag_khz 2000
jtag_speed 32 => JTAG clk=2.000000
2000 kHz
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
SPD005 AT91FR40162 ZY1000 RCLK on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 0
RCLK - adaptive
RCLK timeout
N/A for this target
N/A for this target

Debugging

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
DBG001 AT91FR40162 ZY1000 Load is working Reset init is working, RAM is accesible, GDB server is started On the console of the OS:
$ arm-none-eabi-gdb redboot_ram.elf
(gdb) target remote ip:port
(gdb) load
Load should return without error, typical output looks like:
Loading section .text, size 0x14c lma 0x0
Start address 0x40, load size 332
Transfer rate: 180 bytes/sec, 332 bytes/write.
(gdb) load
Loading section .rom_vectors, size 0x40 lma 0xc000
Loading section .text, size 0x103e8 lma 0xc040
Loading section .rodata, size 0x1a84 lma 0x1c428
Loading section .data, size 0x3ec lma 0x1deac
Start address 0xc040, load size 74392
Transfer rate: 572 KB/sec, 9299 bytes/write.
(gdb)
PASS
DBG002 AT91FR40162 ZY1000 Software breakpoint Load the redboot_ram.elf application, use instructions from GDB001 In the GDB console:
(gdb) monitor arm7_9 dbgrq enable
software breakpoints enabled
(gdb) break cyg_start
Breakpoint 1 at 0xec: file src/main.c, line 71.
(gdb) continue
Continuing.
The software breakpoint should be reached, a typical output looks like:
Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) monitor arm7_9 dbgrq enable
use of EmbeddedICE dbgrq instead of breakpoint for target halt enabled
(gdb) break cyg_start

Breakpoint 1 at 0x155b8: file /home/edgar/temp/ecosboard/packages/redboot/current/src/main.c, line 264.
(gdb) continue
Continuing.

Breakpoint 1, cyg_start ()
at /home/edgar/temp/ecosboard/packages/redboot/current/src/main.c:264
264 CYGACC_CALL_IF_MONITOR_VERSION_SET(RedBoot_version);
(gdb)
PASS
DBG003 AT91FR40162 ZY1000 Single step in a RAM application Load the test_ram.elf application, use instructions from GDB001, break in main using the instructions from GDB002 In GDB, type
(gdb) step
The next instruction should be reached, typical output:
(gdb) step
70 DWORD b = 2;
(gdb) step
266 CYGACC_CALL_IF_MONITOR_RETURN_SET(return_to_redboot);
(gdb)
PASS
DBG004 AT91FR40162 ZY1000 Software break points are working after a reset Load the test_ram.elf application, use instructions from GDB001, break in main using the instructions from GDB002 In GDB, type
(gdb) monitor reset init
(gdb) load
(gdb) continue
The breakpoint should be reached, typical output:
Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) moni reset init
JTAG tap: zy1000.cpu tap/device found: 0x1f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x1)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x600000d3 pc: 0x00008ae8
(gdb) load
Loading section .rom_vectors, size 0x40 lma 0xc000
Loading section .text, size 0x103e8 lma 0xc040
Loading section .rodata, size 0x1a84 lma 0x1c428
Loading section .data, size 0x3ec lma 0x1deac
Start address 0xc040, load size 74392
Transfer rate: 576 KB/sec, 9299 bytes/write.
(gdb) c
Continuing.

Breakpoint 1, cyg_start ()
at /home/edgar/temp/ecosboard/packages/redboot/current/src/main.c:264
264 CYGACC_CALL_IF_MONITOR_VERSION_SET(RedBoot_version);
(gdb)
PASS
DBG005 AT91FR40162 ZY1000 Hardware breakpoint Flash the redboot_rom.elf application. Make this test after FLA004 has passed Be sure that gdb_memory_map and gdb_flash_program are enabled. In GDB, type
(gdb) monitor reset init
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor arm7_9 force_hw_bkpts enable
force hardware breakpoints enabled
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
The breakpoint should be reached, typical output:
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) load
Loading section .rom_vectors, size 0x40 lma 0x1000000
Loading section .text, size 0x10638 lma 0x1000040
Loading section .rodata, size 0x1a84 lma 0x1010678
Loading section .data, size 0x428 lma 0x10120fc
Start address 0x1000040, load size 75044
Transfer rate: 33 KB/sec, 9380 bytes/write.
(gdb) break cyg_start
Breakpoint 1 at 0x100979c: file /home/edgar/temp/ecosboard/packages/redboot/current/src/main.c, line 264.
(gdb) c
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, cyg_start () at /home/edgar/temp/ecosboard/packages/redboot/current/src/main.c:264
264 CYGACC_CALL_IF_MONITOR_VERSION_SET(RedBoot_version);
(gdb)
PASS
DBG006 AT91FR40162 ZY1000 Hardware breakpoint is set after a reset Follow the instructions to flash and insert a hardware breakpoint from DBG005 In GDB, type
(gdb) monitor reset
(gdb) monitor reg pc 0x100000
pc (/32): 0x00100000
(gdb) continue

where the value inserted in PC is the start address of the application
The breakpoint should be reached, typical output:
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) moni reset init
JTAG tap: zy1000.cpu tap/device found: 0x1f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x1)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x200000d3 pc: 0x01000200
(gdb) moni reg pc 0x1000000
pc (/32): 0x01000000
(gdb) c
Continuing.

Breakpoint 1, cyg_start () at /home/edgar/temp/ecosboard/packages/redboot/current/src/main.c:264
264 CYGACC_CALL_IF_MONITOR_VERSION_SET(RedBoot_version);
(gdb)
PASS
DBG007 AT91FR40162 ZY1000 Single step in ROM Flash the test_rom.elf application and set a breakpoint in main, use DBG005. Make this test after FLA004 has passed Be sure that gdb_memory_map and gdb_flash_program are enabled. In GDB, type
(gdb) monitor reset
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor arm7_9 force_hw_bkpts enable
force hardware breakpoints enabled
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) step
The breakpoint should be reached, typical output:
target state: halted
target halted in ARM state due to single step, current mode: Supervisor
cpsr: 0x60000013 pc: 0x0010013c
70 DWORD b = 2;
Breakpoint 1, cyg_start () at /home/edgar/temp/ecosboard/packages/redboot/current/src/main.c:264
264 CYGACC_CALL_IF_MONITOR_VERSION_SET(RedBoot_version);
(gdb) step
266 CYGACC_CALL_IF_MONITOR_RETURN_SET(return_to_redboot);
PASS

RAM access

Note: these tests are not designed to test/debug the target, but to test functionalities!
ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
RAM001 AT91FR40162 ZY1000 32 bit Write/read RAM Reset init is working On the telnet interface
> mww ram_address 0xdeadbeef 16
> mdw ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 32bit long containing 0xdeadbeef.
> mww 0x0 0xdeadbeef 16
> mdw 0x0 32
0x00000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000040: e1a00000 e59fa51c e59f051c e04aa000 00080017 00009388 00009388 00009388
0x00000060: 00009388 0002c2c0 0002c2c0 000094f8 000094f4 00009388 00009388 00009388
> mww 0 0xdeadbeef 16
> mdw 0x0 32
0x00000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000040: 15aadc6d 425b6f33 e789f955 d390dcc2 00080017 010067b4 010067b4 010067b4
0x00000060: 010067b4 00006e74 00006e74 010067b4 010067b4 010067b4 010067b4 010067b4
PASS
RAM002 AT91FR40162 ZY1000 16 bit Write/read RAM Reset init is working On the telnet interface
> mwh ram_address 0xbeef 16
> mdh ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 16bit long containing 0xbeef.
> mwh 0x0 0xbeef 16
> mdh 0x0 32
0x00000000: beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef
0x00000020: 00e0 0000 021c 0000 0240 0000 026c 0000 0288 0000 0000 0000 0388 0000 0350 0000
>
> mwh 0 0xbeef 16
> mdh 0x0 32
0x00000000: beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef
0x00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
PASS
There is a problem with the formatting of the output
RAM003 AT91FR40162 ZY1000 8 bit Write/read RAM Reset init is working On the telnet interface
> mwb ram_address 0xab 16
> mdb ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 8bit long containing 0xab.
> mwb ram_address 0xab 16
> mdb ram_address 32
0x00000000: ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>
> mwb 0x0 0xab 16
> mdb 0x0 32
0x00000000: ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
PASS

Flash access

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
FLA001 AT91FR40162 ZY1000 Flash probe Reset init is working On the telnet interface:
> flash probe 0
The command should execute without error. The output should state the name of the flash and the starting address. An example of output:
flash 'ecosflash' found at 0x01000000
> flash probe 0 flash 'ecosflash' found at 0x01000000 PASS
FLA002 AT91FR40162 ZY1000 flash fillw Reset init is working, flash is probed On the telnet interface
> flash fillw 0x100000 0xdeadbeef 16
The commands should execute without error. The output looks like:
wrote 64 bytes to 0x0100000 in 11.610000s (0.091516 kb/s)
To verify the contents of the flash:
> mdw 0x100000 32
0x0100000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x0100020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x0100040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x0100060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> flash fillw 0x01000000 0xdeadbeef 16
wrote 64 bytes to 0x01000000 in 0.010000s (6.250 kb/s)
> mdw 0x1000000 32
0x01000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x01000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x01000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
FLA003 AT91FR40162 ZY1000 Flash erase Reset init is working, flash is probed On the telnet interface
> flash erase_address 0x100000 0x2000
The commands should execute without error.
erased address 0x0100000 length 8192 in 4.970000s To check that the flash has been erased, read at different addresses. The result should always be 0xff. > mdw 0x100000 32
0x0100000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x0100020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x0100040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x0100060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> flash erase_address 0x1000000 0x10000
erased address 0x01000000 (length 65536) in 0.840000s (76.190 kb/s)
> mdw 0x1000000 32
0x01000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
PASS
FLA004 AT91FR40162 ZY1000 Loading to flash from GDB Reset init is working, flash is probed, connectivity to GDB server is working Start GDB using a ROM elf image, eg: arm-elf-gdb test_rom.elf.
(gdb) target remote ip:port
(gdb) monitor reset halt
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor verify_image path_to_elf_file
The output should look like:
verified 404 bytes in 5.060000s
The failure message is something like:
Verify operation failed address 0x00200000. Was 0x00 instead of 0x18
(gdb) load
Loading section .rom_vectors, size 0x40 lma 0x1000000
Loading section .text, size 0x10638 lma 0x1000040
Loading section .rodata, size 0x1a84 lma 0x1010678
Loading section .data, size 0x428 lma 0x10120fc
Start address 0x1000040, load size 75044
Transfer rate: 34 KB/sec, 9380 bytes/write.
(gdb) moni verify_image /tftp/10.0.0.190/redboot_rom.elf
keep_alive() was not invoked in the 1000ms timelimit. GDB alive packet not sent! (1820). Workaround: increase "set remotetimeout" in GDB
verified 75044 bytes in 1.960000s (37.390 kb/s)
PASS
================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/results/v0.4.0-rc1/LPC2148.html ================================================ Test results for revision 1.62

LPC2148

Connectivity

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
CON001 LPC2148 ZY1000 Telnet connection Power on, jtag target attached On console, type
telnet ip port
Open On-Chip Debugger
>
Open On-Chip Debugger
>
PASS
CON002 LPC2148 ZY1000 GDB server connection Power on, jtag target attached On GDB console, type
target remote ip:port
Remote debugging using 10.0.0.73:3333 (gdb) tar remo 10.0.0.73:3333
Remote debugging using 10.0.0.73:3333
0x00000000 in ?? ()
PASS

Reset

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
RES001 LPC2148 ZY1000 Reset halt on a blank target Erase all the content of the flash Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> reset halt
JTAG tap: lpc2148.cpu tap/device found: 0x4f1f0f0f (mfg: 0x787, part: 0xf1f0, ver: 0x4)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in Thumb state due to debug-request, current mode: Supervisor
cpsr: 0xa00000f3 pc: 0x7fffd2d6
>
PASS
RES002 LPC2148 ZY1000 Reset init on a blank target Erase all the content of the flash Connect via the telnet interface and type
reset init
Reset should return without error and the output should contain
executing reset script 'name_of_the_script'
> reset init
JTAG tap: lpc2148.cpu tap/device found: 0x4f1f0f0f (mfg: 0x787, part: 0xf1f0, ver: 0x4)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in Thumb state due to debug-request, current mode: Supervisor
cpsr: 0xa00000f3 pc: 0x7fffd2da
core state: ARM
>
PASS
NOTE! Even if there is no message, the reset script is being executed (proved by side effects)
RES003 LPC2148 ZY1000 Reset after a power cycle of the target Reset the target then power cycle the target Connect via the telnet interface and type
reset halt after the power was detected
Reset should return without error and the output should contain
target state: halted
nsed nSRST asserted.
nsed power dropout.
nsed power restore.
SRST took 186ms to deassert
JTAG tap: lpc2148.cpu tap/device found: 0x4f1f0f0f (mfg: 0x787, part: 0xf1f0, ver: 0x4)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in Thumb state due to debug-request, current mode: Supervisor
cpsr: 0xa00000f3 pc: 0x7fffd2d6
core state: ARM
> reset halt
JTAG tap: lpc2148.cpu tap/device found: 0x4f1f0f0f (mfg: 0x787, part: 0xf1f0, ver: 0x4)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in Thumb state due to debug-request, current mode: Supervisor
cpsr: 0xa00000f3 pc: 0x7fffd2d6
>
PASS
RES004 LPC2148 ZY1000 Reset halt on a blank target where reset halt is supported Erase all the content of the flash Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
pc = 0
> reset halt
JTAG tap: lpc2148.cpu tap/device found: 0x4f1f0f0f (mfg: 0x787, part: 0xf1f0, ver: 0x4)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in Thumb state due to debug-request, current mode: Supervisor
cpsr: 0xa00000f3 pc: 0x7fffd2d6
>
PASS
RES005 LPC2148 ZY1000 Reset halt on a blank target using return clock Erase all the content of the flash, set the configuration script to use RCLK Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
> jtag_khz 0
RCLK - adaptive
> reset init
JTAG tap: lpc2148.cpu tap/device found: 0x4f1f0f0f (mfg: 0x787, part: 0xf1f0, ver: 0x4)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in Thumb state due to debug-request, current mode: Supervisor
cpsr: 0xa00000f3 pc: 0x7fffd2d6
core state: ARM
>
PASS

JTAG Speed

ID Target ZY1000 Description Initial state Input Expected output Actual output Pass/Fail
SPD001 LPC2148 ZY1000 16MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 16000
jtag_speed 4 => JTAG clk=16.000000
16000 kHz
> reset halt
JTAG scan chain interrogation failed: all zeroes
Check JTAG interface, timings, target power, etc.
error: -100
Command handler execution failed
in procedure 'reset' called at file "command.c", line 638
called at file "/home/laurentiu/workspace/zy1000/build/../openocd/src/helper/command.c", line 352
invalid mode value encountered 0
cpsr contains invalid mode value - communication failure
ThumbEE -- incomplete support
target state: halted
target halted in ThumbEE state due to debug-request, current mode: System
cpsr: 0x1fffffff pc: 0xfffffffa
invalid mode value encountered 0
cpsr contains invalid mode value - communication failure
target state: halted
target halted in Thumb state due to debug-request, current mode: System
cpsr: 0xc00003ff pc: 0xfffffff0
invalid mode value encountered 0
cpsr contains invalid mode value - communication failure
invalid mode value encountered 0
cpsr contains invalid mode value - communication failure
invalid mode value encountered 0
cpsr contains invalid mode value - communication failure
invalid mode value encountered 0
cpsr contains invalid mode value - communication failure
ThumbEE -- incomplete support
target state: halted
target halted in ThumbEE state due to debug-request, current mode: System
cpsr: 0xffffffff pc: 0xfffffffa
>
FAIL
SPD002 LPC2148 ZY1000 8MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 8000
jtag_speed 8 => JTAG clk=8.000000
8000 kHz
> reset halt
JTAG scan chain interrogation failed: all zeroes
Check JTAG interface, timings, target power, etc.
error: -100
Command handler execution failed
in procedure 'reset' called at file "command.c", line 638
called at file "/home/laurentiu/workspace/zy1000/build/../openocd/src/helper/command.c", line 352
invalid mode value encountered 0
cpsr contains invalid mode value - communication failure
invalid mode value encountered 0
cpsr contains invalid mode value - communication failure
>
FAIL
SPD003 LPC2148 ZY1000 4MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 4000
jtag_speed 16 => JTAG clk=4.000000
4000 kHz
> reset halt
JTAG tap: lpc2148.cpu tap/device found: 0xc79f0f87 (mfg: 0x7c3, part: 0x79f0, ver: 0xc)
JTAG tap: lpc2148.cpu UNEXPECTED: 0xc79f0f87 (mfg: 0x7c3, part: 0x79f0, ver: 0xc)
JTAG tap: lpc2148.cpu expected 1 of 1: 0x4f1f0f0f (mfg: 0x787, part: 0xf1f0, ver: 0x4)
Unexpected idcode after end of chain: 64 0x0000007f
Unexpected idcode after end of chain: 160 0x0000007f
Unexpected idcode after end of chain: 192 0x0000007f
Unexpected idcode after end of chain: 320 0x0000007f
Unexpected idcode after end of chain: 352 0x0000007f
Unexpected idcode after end of chain: 384 0x0000007f
Unexpected idcode after end of chain: 480 0x0000007f
Unexpected idcode after end of chain: 512 0x0000007f
Unexpected idcode after end of chain: 544 0x0000007f
double-check your JTAG setup (interface, speed, missing TAPs, ...)
error: -100
Command handler execution failed
in procedure 'reset' called at file "command.c", line 638
called at file "/home/laurentiu/workspace/zy1000/build/../openocd/src/helper/command.c", line 352
>
FAIL
SPD004 LPC2148 ZY1000 2MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 2000
jtag_speed 32 => JTAG clk=2.000000
2000 kHz
> reset halt
JTAG tap: lpc2148.cpu tap/device found: 0x4f1f0f0f (mfg: 0x787, part: 0xf1f0, ver: 0x4)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in Thumb state due to debug-request, current mode: Supervisor
cpsr: 0xa00000f3 pc: 0x7fffd2da
> mdw 0 32
0x00000000: e59f4034 e3a05002 e5845000 e3a05003 e5845004 e59f201c e3a03000 e1020093
0x00000020: e2822028 e1021093 e3c03007 e5023028 e51ff004 7fffd1c4 e002c014 e01fc000
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
SPD005 LPC2148 ZY1000 RCLK on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 0
RCLK - adaptive
> mdw 0 32
0x00000000: e59f4034 e3a05002 e5845000 e3a05003 e5845004 e59f201c e3a03000 e1020093
0x00000020: e2822028 e1021093 e3c03007 e5023028 e51ff004 7fffd1c4 e002c014 e01fc000
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS

Debugging

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
DBG001 LPC2148 ZY1000 Load is working Reset init is working, RAM is accesible, GDB server is started On the console of the OS:
arm-elf-gdb test_ram.elf
(gdb) target remote ip:port
(gdb) load
Load should return without error, typical output looks like:
Loading section .text, size 0x14c lma 0x0
Start address 0x40, load size 332
Transfer rate: 180 bytes/sec, 332 bytes/write.
(gdb) load
Loading section .text, size 0x16c lma 0x40000000
Start address 0x40000040, load size 364
Transfer rate: 32 KB/sec, 364 bytes/write.
(gdb)
PASS
DBG002 LPC2148 ZY1000 Software breakpoint Load the test_ram.elf application, use instructions from GDB001 In the GDB console:
(gdb) monitor gdb_breakpoint_override soft
software breakpoints enabled
(gdb) break main
Breakpoint 1 at 0xec: file src/main.c, line 71.
(gdb) continue
Continuing.
The software breakpoint should be reached, a typical output looks like:
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x000000ec

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
(gdb) monitor gdb_breakpoint_override soft
force soft breakpoints
Current language: auto
The current source language is "auto; currently asm".
(gdb) break main
Breakpoint 1 at 0x4000010c: file src/main.c, line 71.
(gdb) c
Continuing.

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
Current language: auto
The current source language is "auto; currently c".
(gdb)
PASS
DBG003 LPC2148 ZY1000 Single step in a RAM application Load the test_ram.elf application, use instructions from GDB001, break in main using the instructions from GDB002 In GDB, type
(gdb) step
The next instruction should be reached, typical output:
(gdb) step
target state: halted
target halted in ARM state due to single step, current mode: Abort
cpsr: 0x20000097 pc: 0x000000f0
target state: halted
target halted in ARM state due to single step, current mode: Abort
cpsr: 0x20000097 pc: 0x000000f4
72 DWORD b = 2;
(gdb) step
72 DWORD b = 2;
(gdb)
PASS
DBG004 LPC2148 ZY1000 Software break points are working after a reset Load the test_ram.elf application, use instructions from GDB001, break in main using the instructions from GDB002 In GDB, type
(gdb) monitor reset init
(gdb) load
(gdb) continue
The breakpoint should be reached, typical output:
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x000000ec

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
(gdb) moni reset init
JTAG tap: lpc2148.cpu tap/device found: 0x4f1f0f0f (mfg: 0x787, part: 0xf1f0, ver: 0x4)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in Thumb state due to debug-request, current mode: Supervisor
cpsr: 0xa00000f3 pc: 0x7fffd2d6
core state: ARM
(gdb) load
Loading section .text, size 0x16c lma 0x40000000
Start address 0x40000040, load size 364
Transfer rate: 27 KB/sec, 364 bytes/write.
(gdb) c
Continuing.

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
(gdb)
PASS
DBG005 LPC2148 ZY1000 Hardware breakpoint Flash the test_rom.elf application. Make this test after FLA004 has passed Be sure that gdb_memory_map and gdb_flash_program are enabled. In GDB, type
(gdb) monitor reset init
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor gdb_breakpoint_override hard
force hard breakpoints
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
The breakpoint should be reached, typical output:
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) monitor gdb_breakpoint_override hard
force hard breakpoints
(gdb) break main
Breakpoint 1 at 0x10c: file src/main.c, line 71.
(gdb) continue
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
Current language: auto
The current source language is "auto; currently c".
(gdb)
PASS NOTE: This test is failing from time to time, not able to describe a cause
DBG006 LPC2148 ZY1000 Hardware breakpoint is set after a reset Follow the instructions to flash and insert a hardware breakpoint from DBG005 In GDB, type
(gdb) monitor reset
(gdb) monitor reg pc 0x100000
pc (/32): 0x00100000
(gdb) continue

where the value inserted in PC is the start address of the application
The breakpoint should be reached, typical output:
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) monitor reset init
JTAG tap: lpc2148.cpu tap/device found: 0x4f1f0f0f (mfg: 0x787, part: 0xf1f0, ver: 0x4)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x60000013 pc: 0x00000160
core state: ARM
(gdb) monitor reg pc 0x40
pc (/32): 0x00000040
(gdb) continue
Continuing.

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
(gdb)
PASS
DBG007 LPC2148 ZY1000 Single step in ROM Flash the test_rom.elf application and set a breakpoint in main, use DBG005. Make this test after FLA004 has passed Be sure that gdb_memory_map and gdb_flash_program are enabled. In GDB, type
(gdb) monitor reset
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor gdb_breakpoint_override hard
force hard breakpoints
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) step
The breakpoint should be reached, typical output:
target state: halted
target halted in ARM state due to single step, current mode: Supervisor
cpsr: 0x60000013 pc: 0x0010013c
70 DWORD b = 2;
(gdb) load
Loading section .text, size 0x16c lma 0x0
Start address 0x40, load size 364
Transfer rate: 637 bytes/sec, 364 bytes/write.
(gdb) monitor gdb_breakpoint_override hard
force hard breakpoints
Current language: auto
The current source language is "auto; currently asm".
(gdb) break main
Breakpoint 1 at 0x10c: file src/main.c, line 71.
(gdb) continue
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
Current language: auto
The current source language is "auto; currently c".
(gdb) step
72 DWORD b = 2;
(gdb)
PASS

RAM access

Note: these tests are not designed to test/debug the target, but to test functionalities!
ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
RAM001 LPC2148 ZY1000 32 bit Write/read RAM Reset init is working On the telnet interface
> mww ram_address 0xdeadbeef 16
> mdw ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 32bit long containing 0xdeadbeef.
> mww 0x0 0xdeadbeef 16
> mdw 0x0 32
0x00000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000040: e1a00000 e59fa51c e59f051c e04aa000 00080017 00009388 00009388 00009388
0x00000060: 00009388 0002c2c0 0002c2c0 000094f8 000094f4 00009388 00009388 00009388
> mww 0x40000000 0xdeadbeef 16
> mdw 0x40000000 32
0x40000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x40000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x40000040: e1a00000 e1a00000 e1a00000 e1a00000 e1a00000 e1a00000 e1a00000 e1a00000
0x40000060: e321f0db e59fd07c e321f0d7 e59fd078 e321f0d1 e59fd074 e321f0d2 e59fd070
>
PASS
RAM002 LPC2148 ZY1000 16 bit Write/read RAM Reset init is working On the telnet interface
> mwh ram_address 0xbeef 16
> mdh ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 16bit long containing 0xbeef.
> mwh 0x0 0xbeef 16
> mdh 0x0 32
0x00000000: beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef
0x00000020: 00e0 0000 021c 0000 0240 0000 026c 0000 0288 0000 0000 0000 0388 0000 0350 0000
>
> mwh 0x40000000 0xbeef 16
> mdh 0x40000000 32
0x40000000: beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef
0x40000020: beef dead beef dead beef dead beef dead beef dead beef dead beef dead beef dead
>
PASS
RAM003 LPC2148 ZY1000 8 bit Write/read RAM Reset init is working On the telnet interface
> mwb ram_address 0xab 16
> mdb ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 8bit long containing 0xab.
> mwb ram_address 0xab 16
> mdb ram_address 32
0x00000000: ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>
> mwb 0x40000000 0xab 16 > mdb 0x40000000 32 0x40000000: ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ef be ef be ef be ef be ef be ef be ef be ef be > PASS

Flash access

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
FLA001 LPC2148 ZY1000 Flash probe Reset init is working On the telnet interface:
> flash probe 0
The command should execute without error. The output should state the name of the flash and the starting address. An example of output:
flash 'ecosflash' found at 0x01000000
> flash probe 0
flash 'lpc2000' found at 0x00000000
PASS
FLA002 LPC2148 ZY1000 flash fillw Reset init is working, flash is probed On the telnet interface
> flash fillw 0x1000000 0xdeadbeef 16
The commands should execute without error. The output looks like:
wrote 64 bytes to 0x01000000 in 11.610000s (0.091516 kb/s)
To verify the contents of the flash:
> mdw 0x1000000 32
0x01000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x01000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x01000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> flash fillw 0x0 0xdeadbeef 16
Verification will fail since checksum in image (0xdeadbeef) to be written to flash is different from calculated vector checksum (0xe93fc777).
To remove this warning modify build tools on developer PC to inject correct LPC vector checksum.
wrote 64 bytes to 0x00000000 in 0.040000s (1.563 kb/s)
> mdw 0 32
0x00000000: deadbeef deadbeef deadbeef deadbeef deadbeef e93fc777 deadbeef deadbeef
0x00000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
FAIL
FLA003 LPC2148 ZY1000 Flash erase Reset init is working, flash is probed On the telnet interface
> flash erase_address 0x1000000 0x2000
The commands should execute without error.
erased address 0x01000000 length 8192 in 4.970000s To check that the flash has been erased, read at different addresses. The result should always be 0xff. > mdw 0x1000000 32
0x01000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> flash erase_address 0 0x2000
erased address 0x00000000 (length 8192) in 0.510000s (15.686 kb/s)
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
FLA004 LPC2148 ZY1000 Loading to flash from GDB Reset init is working, flash is probed, connectivity to GDB server is working Start GDB using a ROM elf image, eg: arm-elf-gdb test_rom.elf.
(gdb) target remote ip:port
(gdb) monitor reset
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write. (gdb) monitor verify_image path_to_elf_file
The output should look like:
verified 404 bytes in 5.060000s
The failure message is something like:
Verify operation failed address 0x00200000. Was 0x00 instead of 0x18
(gdb) moni verify_image /tftp/10.0.0.194/test_rom.elf
checksum mismatch - attempting binary compare
Verify operation failed address 0x00000014. Was 0x58 instead of 0x60

Command handler execution failed
in procedure 'verify_image' called at file "command.c", line 647
called at file "command.c", line 361
(gdb)
FAIL
================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/results/v0.4.0-rc1/SAM7.html ================================================ Test results for revision 1.62

SAM7

Connectivity

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
CON001 SAM7S64 ZY1000 Telnet connection Power on, jtag target attached On console, type
telnet ip port
Open On-Chip Debugger
>
Open On-Chip Debugger
>
PASS
CON002 SAM7S64 ZY1000 GDB server connection Power on, jtag target attached On GDB console, type
target remote ip:port
Remote debugging using 10.0.0.73:3333 (gdb) tar remo 10.0.0.73:3333
Remote debugging using 10.0.0.73:3333
0x00100174 in ?? ()
PASS

Reset

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
RES001 SAM7S64 ZY1000 Reset halt on a blank target Erase all the content of the flash Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> reset halt
SRST took 2ms to deassert
JTAG device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0x600000d3 pc: 0x000003c4
>
PASS
RES002 SAM7S64 ZY1000 Reset init on a blank target Erase all the content of the flash Connect via the telnet interface and type
reset init
Reset should return without error and the output should contain
executing reset script 'name_of_the_script'
> reset init
SRST took 2ms to deassert
JTAG device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0x600000d3 pc: 0x000003c0
>
PASS
NOTE! Even if there is no message, the reset script is being executed (proved by side effects)
RES003 SAM7S64 ZY1000 Reset after a power cycle of the target Reset the target then power cycle the target Connect via the telnet interface and type
reset halt after the power was detected
Reset should return without error and the output should contain
target state: halted
Sensed nSRST asserted
Sensed power dropout.
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0xf00000d3 pc: 0xd5dff7e6
Sensed power restore.
Sensed nSRST deasserted
> reset halt
JTAG device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0xf00000d3 pc: 0x0000072c
>
PASS
RES004 SAM7S64 ZY1000 Reset halt on a blank target where reset halt is supported Erase all the content of the flash Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
pc = 0
> reset halt
SRST took 2ms to deassert
JTAG device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0x300000d3 pc: 0x000003c0
PASS
RES005 SAM7S64 ZY1000 Reset halt on a blank target using return clock Erase all the content of the flash, set the configuration script to use RCLK Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
> jtag_khz 0
jtag_khz: 0
> reset init
SRST took 2ms to deassert
JTAG device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0x300000d3 pc: 0x000003c0
executing event/sam7s256_reset.script
>
PASS

JTAG Speed

ID Target ZY1000 Description Initial state Input Expected output Actual output Pass/Fail
SPD001 SAM7S64 ZY1000 16MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 16000
jtag_speed 4 => JTAG clk=16.000000
jtag_khz: 16000
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
SPD002 SAM7S64 ZY1000 8MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 8000
jtag_speed 8 => JTAG clk=8.000000
jtag_khz: 8000
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
PASS
SPD003 SAM7S64 ZY1000 4MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 4000
jtag_speed 16 => JTAG clk=4.000000
jtag_khz: 4000
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
SPD004 SAM7S64 ZY1000 2MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 2000
jtag_speed 32 => JTAG clk=2.000000
jtag_khz: 2000
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
SPD005 SAM7S64 ZY1000 RCLK on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 0
jtag_khz: 0
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS

Debugging

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
DBG001 SAM7S64 ZY1000 Load is working Reset init is working, RAM is accesible, GDB server is started On the console of the OS:
arm-elf-gdb test_ram.elf
(gdb) target remote ip:port
(gdb) load
Load should return without error, typical output looks like:
Loading section .text, size 0x14c lma 0x0
Start address 0x40, load size 332
Transfer rate: 180 bytes/sec, 332 bytes/write.
(gdb) load
Loading section .text, size 0x194 lma 0x200000
Start address 0x200040, load size 404
Transfer rate: 443 bytes/sec, 404 bytes/write.
(gdb)
PASS
DBG002 SAM7S64 ZY1000 Software breakpoint Load the test_ram.elf application, use instructions from GDB001 In the GDB console:
(gdb) monitor arm7_9 dbgrq enable
software breakpoints enabled
(gdb) break main
Breakpoint 1 at 0xec: file src/main.c, line 71.
(gdb) continue
Continuing.
The software breakpoint should be reached, a typical output looks like:
Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) monitor arm7_9 dbgrq enable
use of EmbeddedICE dbgrq instead of breakpoint for target halt enabled
(gdb) break main
Breakpoint 1 at 0x200134: file src/main.c, line 69.
(gdb) c
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
Current language: auto
The current source language is "auto; currently c".
(gdb)
PASS
DBG003 SAM7S64 ZY1000 Single step in a RAM application Load the test_ram.elf application, use instructions from GDB001, break in main using the instructions from GDB002 In GDB, type
(gdb) step
The next instruction should be reached, typical output:
(gdb) step
70 DWORD b = 2;
(gdb) step
70 DWORD b = 2; (gdb)
PASS
DBG004 SAM7S64 ZY1000 Software break points are working after a reset Load the test_ram.elf application, use instructions from GDB001, break in main using the instructions from GDB002 In GDB, type
(gdb) monitor reset init
(gdb) load
(gdb) continue
The breakpoint should be reached, typical output:
Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) monitor reset init
JTAG tap: sam7x256.cpu tap/device found: 0x3f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x600000d3 pc: 0x0000031c
(gdb) load
Loading section .text, size 0x194 lma 0x200000
Start address 0x200040, load size 404
Transfer rate: 26 KB/sec, 404 bytes/write.
(gdb) continue
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb)
PASS
DBG005 SAM7S64 ZY1000 Hardware breakpoint Flash the test_rom.elf application. Make this test after FLA004 has passed Be sure that gdb_memory_map and gdb_flash_program are enabled. In GDB, type
(gdb) monitor reset init
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor arm7_9 force_hw_bkpts enable
force hardware breakpoints enabled
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
The breakpoint should be reached, typical output:
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) monitor arm7_9 force_hw_bkpts enable
force hardware breakpoints enabled
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x60000013 pc: 0x00100134

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb)
PASS
DBG006 SAM7S64 ZY1000 Hardware breakpoint is set after a reset Follow the instructions to flash and insert a hardware breakpoint from DBG005 In GDB, type
(gdb) monitor reset
(gdb) monitor reg pc 0x100000
pc (/32): 0x00100000
(gdb) continue

where the value inserted in PC is the start address of the application
The breakpoint should be reached, typical output:
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) monitor reset init
SRST took 3ms to deassert
JTAG device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug request, current mode: Supervisor
cpsr: 0x60000013 pc: 0x00100168
executing event/sam7s256_reset.script
(gdb) monitor reg pc 0x100000
pc (/32): 0x00100000
(gdb) continue
Continuing.
target state: halted
target halted in ARM state due to single step, current mode: Supervisor
cpsr: 0x60000013 pc: 0x00100040
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x60000013 pc: 0x00100134

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb)
PASS
DBG007 SAM7S64 ZY1000 Single step in ROM Flash the test_rom.elf application and set a breakpoint in main, use DBG005. Make this test after FLA004 has passed Be sure that gdb_memory_map and gdb_flash_program are enabled. In GDB, type
(gdb) monitor reset
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor arm7_9 force_hw_bkpts enable
force hardware breakpoints enabled
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) step
The breakpoint should be reached, typical output:
target state: halted
target halted in ARM state due to single step, current mode: Supervisor
cpsr: 0x60000013 pc: 0x0010013c
70 DWORD b = 2;
Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) step
target state: halted
target halted in ARM state due to single step, current mode: Supervisor
cpsr: 0x60000013 pc: 0x00100138
target state: halted
target halted in ARM state due to single step, current mode: Supervisor
cpsr: 0x60000013 pc: 0x0010013c
70 DWORD b = 2;
(gdb)
PASS

RAM access

Note: these tests are not designed to test/debug the target, but to test functionalities!
ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
RAM001 SAM7S64 ZY1000 32 bit Write/read RAM Reset init is working On the telnet interface
> mww ram_address 0xdeadbeef 16
> mdw ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 32bit long containing 0xdeadbeef.
> mww 0x0 0xdeadbeef 16
> mdw 0x0 32
0x00000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000040: e1a00000 e59fa51c e59f051c e04aa000 00080017 00009388 00009388 00009388
0x00000060: 00009388 0002c2c0 0002c2c0 000094f8 000094f4 00009388 00009388 00009388
> mww 0x00200000 0xdeadbeef 16
> mdw 0x00200000 32
0x00200000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00200020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00200040: e59f10b4 e3a00902 e5810004 e59f00ac e59f10ac e5810000 e3e010ff e59f00a4
0x00200060: e5810060 e59f10a0 e3e00000 e5810130 e5810124 e321f0db e59fd090 e321f0d7
PASS
RAM002 SAM7S64 ZY1000 16 bit Write/read RAM Reset init is working On the telnet interface
> mwh ram_address 0xbeef 16
> mdh ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 16bit long containing 0xbeef.
> mwh 0x0 0xbeef 16
> mdh 0x0 32
0x00000000: beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef
0x00000020: 00e0 0000 021c 0000 0240 0000 026c 0000 0288 0000 0000 0000 0388 0000 0350 0000
>
> mwh 0x00200000 0xbeef 16
> mdh 0x00200000 32
0x00200000: beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef
0x00200020: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
PASS
RAM003 SAM7S64 ZY1000 8 bit Write/read RAM Reset init is working On the telnet interface
> mwb ram_address 0xab 16
> mdb ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 8bit long containing 0xab.
> mwb ram_address 0xab 16
> mdb ram_address 32
0x00000000: ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>
> mwb 0x00200000 0xab 16
> mdb 0x00200000 32
0x00200000: ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
PASS

Flash access

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
FLA001 SAM7S64 ZY1000 Flash probe Reset init is working On the telnet interface:
> flash probe 0
The command should execute without error. The output should state the name of the flash and the starting address. An example of output:
flash 'ecosflash' found at 0x01000000
> flash probe 0
flash 'at91sam7' found at 0x00100000
PASS
FLA002 SAM7S64 ZY1000 flash fillw Reset init is working, flash is probed On the telnet interface
> flash fillw 0x100000 0xdeadbeef 16
The commands should execute without error. The output looks like:
wrote 64 bytes to 0x0100000 in 11.610000s (0.091516 kb/s)
To verify the contents of the flash:
> mdw 0x100000 32
0x0100000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x0100020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x0100040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x0100060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> flash fillw 0x100000 0xdeadbeef 16
wrote 64 bytes to 0x00100000 in 0.040000s (26.562500 kb/s)
> mdw 0x100000 32
0x00100000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00100020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00100040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00100060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
FLA003 SAM7S64 ZY1000 Flash erase Reset init is working, flash is probed On the telnet interface
> flash erase_address 0x100000 0x2000
The commands should execute without error.
erased address 0x0100000 length 8192 in 4.970000s To check that the flash has been erased, read at different addresses. The result should always be 0xff. > mdw 0x100000 32
0x0100000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x0100020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x0100040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x0100060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> flash erase_address 0x100000 0x2000
erased address 0x00100000 length 8192 in 0.020000s
> mdw 0x100000 32
0x00100000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00100020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00100040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00100060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
FLA004 SAM7S64 ZY1000 Loading to flash from GDB Reset init is working, flash is probed, connectivity to GDB server is working Start GDB using a ROM elf image, eg: arm-elf-gdb test_rom.elf.
(gdb) target remote ip:port
(gdb) monitor reset halt
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor verify_image path_to_elf_file
The output should look like:
verified 404 bytes in 5.060000s
The failure message is something like:
Verify operation failed address 0x00200000. Was 0x00 instead of 0x18
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 4 KB/sec, 404 bytes/write.
(gdb) moni verify_image /tftp/10.0.0.9/c:/temp/testing/examples/SAM7S256Test/test_rom.elf
verified 404 bytes in 0.570000s
PASS
================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/results/v0.4.0-rc1/STR710.html ================================================ Test results for version 1.62

STR710

Connectivity

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
CON001 STR912 ZY1000 Telnet connection Power on, jtag target attached On console, type
telnet ip port
Open On-Chip Debugger
>
> telnet 10.0.0.142
Trying 10.0.0.142...
Connected to 10.0.0.142.
Escape character is '^]'.
Open On-Chip Debugger
>
PASS
CON002 STR912 ZY1000 GDB server connection Power on, jtag target attached On GDB console, type
target remote ip:port
Remote debugging using 10.0.0.73:3333 (gdb) tar remo 10.0.0.142:3333
Remote debugging using 10.0.0.142:3333
0x00016434 in ?? ()
(gdb)
PASS

Reset

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
RES001 STR912 ZY1000 Reset halt on a blank target Erase all the content of the flash Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
> mdw 0 32
0x00000000: 75755000 8a930104 65696f65 939a3e98 214751f1 fa0edb9b 6664686d 931a989e
0x00000020: 676c65e4 9a0a0982 25653445 da02ba90 c4ed3165 9b9a8a9a 65676365 01981292
0x00000040: 212e0982 82ba3f8b 34674765 96ba1a9a 6175e7e5 9b9ab91a 0789644d 120a9a18
0x00000060: 65446167 80d20982 6d6d6565 187090ca 65277d65 9a9a0b81 6960416c 9ffe88b8
> reset
jtag_speed 6400 => JTAG clk=0.010000
10 kHz
JTAG tap: str710.cpu tap/device found: 0x3f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x3)
>
PASS
RES002 STR912 ZY1000 Reset init on a blank target Erase all the content of the flash Connect via the telnet interface and type
reset init
Reset should return without error and the output should contain
executing reset script 'name_of_the_script'
> reset init
jtag_speed 6400 => JTAG clk=0.010000
10 kHz
JTAG tap: str710.cpu tap/device found: 0x3f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Undefined instruction
cpsr: 0xf00000db pc: 0x00000004
jtag_speed 10 => JTAG clk=6.400000
6400 kHz
PASS
RES003 STR912 ZY1000 Reset after a power cycle of the target Reset the target then power cycle the target Connect via the telnet interface and type
reset halt after the power was detected
Reset should return without error and the output should contain
target state: halted
nsed power dropout.
nsed power dropout.
nsed nSRST deasserted.
invalid mode value encountered 0
cpsr contains invalid mode value - communication failure
jtag_speed 6400 => JTAG clk=0.010000
10 kHz
JTAG tap: str710.cpu tap/device found: 0x3f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x100000d3 pc: 0x0000001c
jtag_speed 10 => JTAG clk=6.400000
6400 kHz
nsed power restore.
jtag_speed 6400 => JTAG clk=0.010000
10 kHz
JTAG tap: str710.cpu tap/device found: 0x3f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x500000d3 pc: 0x00000000
jtag_speed 10 => JTAG clk=6.400000
6400 kHz
> reset init
jtag_speed 6400 => JTAG clk=0.010000
10 kHz
JTAG tap: str710.cpu tap/device found: 0x3f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x500000d3 pc: 0x00000000
jtag_speed 10 => JTAG clk=6.400000
6400 kHz
>
PASS
RES004 STR912 ZY1000 Reset halt on a blank target where reset halt is supported Erase all the content of the flash Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
> reset halt
jtag_speed 6400 => JTAG clk=0.010000
10 kHz
JTAG tap: str710.cpu tap/device found: 0x3f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x200000d3 pc: 0xfe50cba4
>
PASS
RES005 STR912 ZY1000 Reset halt on a blank target using return clock Erase all the content of the flash, set the configuration script to use RCLK Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
> jtag_khz 0
RCLK - adaptive
RCLK timeout
RCLK timeout
RCLK timeout
> reset halt
RCLK timeout
jtag_speed 6400 => JTAG clk=0.010000
10 kHz
JTAG tap: str710.cpu tap/device found: 0x3f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x200000d3 pc: 0xfe50cb50
FAIL

JTAG Speed

ID Target ZY1000 Description Initial state Input Expected output Actual output Pass/Fail
SPD001 STR912 ZY1000 16MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 16000
jtag_speed 4 => JTAG clk=16.000000
16000 kHz
> mdw 0 32
0x00000000: 75755000 8a930104 65696f65 939a3e98 214751f1 fa0edb9b 6664686d 931a989e
0x00000020: 676c65e4 9a0a0982 25653445 da02ba90 c4ed3165 9b9a8a9a 65676365 01981292
0x00000040: 212e0982 82ba3f8b 34674765 96ba1a9a 6175e7e5 9b9ab91a 0789644d 120a9a18
0x00000060: 65446167 80d20982 6d6d6565 187090ca 65277d65 9a9a0b81 6960416c 9ffe88b8
>
PASS
SPD002 STR912 ZY1000 8MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 8000
jtag_speed 8 => JTAG clk=8.000000
8000 kHz
> mdw 0 32
0x00000000: 75755000 8a930104 65696f65 939a3e98 214751f1 fa0edb9b 6664686d 931a989e
0x00000020: 676c65e4 9a0a0982 25653445 da02ba90 c4ed3165 9b9a8a9a 65676365 01981292
0x00000040: 212e0982 82ba3f8b 34674765 96ba1a9a 6175e7e5 9b9ab91a 0789644d 120a9a18
0x00000060: 65446167 80d20982 6d6d6565 187090ca 65277d65 9a9a0b81 6960416c 9ffe88b8
>
PASS
SPD003 STR912 ZY1000 4MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 4000
jtag_speed 16 => JTAG clk=4.000000
4000 kHz
> mdw 0 32
0x00000000: 75755000 8a930104 65696f65 939a3e98 214751f1 fa0edb9b 6664686d 931a989e
0x00000020: 676c65e4 9a0a0982 25653445 da02ba90 c4ed3165 9b9a8a9a 65676365 01981292
0x00000040: 212e0982 82ba3f8b 34674765 96ba1a9a 6175e7e5 9b9ab91a 0789644d 120a9a18
0x00000060: 65446167 80d20982 6d6d6565 187090ca 65277d65 9a9a0b81 6960416c 9ffe88b8
>
PASS
SPD004 STR912 ZY1000 2MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > > jtag_khz 2000
jtag_speed 32 => JTAG clk=2.000000
2000 kHz
> mdw 0 32
0x00000000: 75755000 8a930104 65696f65 939a3e98 214751f1 fa0edb9b 6664686d 931a989e
0x00000020: 676c65e4 9a0a0982 25653445 da02ba90 c4ed3165 9b9a8a9a 65676365 01981292
0x00000040: 212e0982 82ba3f8b 34674765 96ba1a9a 6175e7e5 9b9ab91a 0789644d 120a9a18
0x00000060: 65446167 80d20982 6d6d6565 187090ca 65277d65 9a9a0b81 6960416c 9ffe88b8
>
PASS
SPD005 STR912 ZY1000 RCLK on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 0
RCLK - adaptive
RCLK timeout
RCLK timeout
RCLK timeout
FAIL

Debugging

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
DBG001 STR912 ZY1000 Load is working Reset init is working, RAM is accesible, GDB server is started On the console of the OS:
arm-elf-gdb test_ram.elf
(gdb) target remote ip:port
(gdb) load
Load should return without error, typical output looks like:
Loading section .text, size 0x14c lma 0x0
Start address 0x40, load size 332
Transfer rate: 180 bytes/sec, 332 bytes/write.
(gdb) load
Loading section .text, size 0x1cc lma 0x20000000
Loading section .vectors, size 0x40 lma 0x200001cc
Loading section .rodata, size 0x4 lma 0x2000020c
Start address 0x20000000, load size 528
Transfer rate: 64 KB/sec, 176 bytes/write.
(gdb)
PASS
DBG002 STR912 ZY1000 Software breakpoint Load the test_ram.elf application, use instructions from GDB001 In the GDB console:
(gdb) monitor gdb_breakpoint_override soft
force soft breakpoints
(gdb) break main
Breakpoint 1 at 0xec: file src/main.c, line 71.
(gdb) continue
Continuing.
The software breakpoint should be reached, a typical output looks like:
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x000000ec

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
(gdb) monitor gdb_breakpoint_override soft
force soft breakpoints
Current language: auto
The current source language is "auto; currently asm".
(gdb) break main
Breakpoint 1 at 0x20000170: file src/main.c, line 69.
(gdb) c
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
Current language: auto
The current source language is "auto; currently c".
(gdb)
PASS
DBG003 STR912 ZY1000 Single step in a RAM application Load the test_ram.elf application, use instructions from GDB001, break in main using the instructions from GDB002 In GDB, type
(gdb) step
The next instruction should be reached, typical output:
(gdb) step
target state: halted
target halted in ARM state due to single step, current mode: Abort
cpsr: 0x20000097 pc: 0x000000f0
target state: halted
target halted in ARM state due to single step, current mode: Abort
cpsr: 0x20000097 pc: 0x000000f4
72 DWORD b = 2;
(gdb) step
70 DWORD b = 2;
(gdb)
PASS
DBG004 STR912 ZY1000 Software break points are working after a reset Load the test_ram.elf application, use instructions from GDB001, break in main using the instructions from GDB002 In GDB, type
(gdb) monitor reset init
(gdb) load
(gdb) continue
The breakpoint should be reached, typical output:
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x000000ec

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
((gdb) monitor reset init
jtag_speed 6400 => JTAG clk=0.010000
10 kHz
JTAG tap: str710.cpu tap/device found: 0x3f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x60000013 pc: 0x200001bc
jtag_speed 10 => JTAG clk=6.400000
6400 kHz
(gdb) load
Loading section .text, size 0x1cc lma 0x20000000
Loading section .vectors, size 0x40 lma 0x200001cc
Loading section .rodata, size 0x4 lma 0x2000020c
Start address 0x20000000, load size 528
Transfer rate: 64 KB/sec, 176 bytes/write.
(gdb) c
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb)
PASS
DBG005 STR912 ZY1000 Hardware breakpoint Flash the test_rom.elf application. Make this test after FLA004 has passed Be sure that gdb_memory_map and gdb_flash_program are enabled. In GDB, type
(gdb) monitor reset init
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor gdb_breakpoint_override hard
force hard breakpoints
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
The breakpoint should be reached, typical output:
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) monitor gdb_breakpoint_override hard
force hard breakpoints
(gdb) break main
Breakpoint 1 at 0x40000170: file src/main.c, line 69.
(gdb) c
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
Current language: auto
The current source language is "auto; currently c".
(gdb)
PASS
DBG006 STR912 ZY1000 Hardware breakpoint is set after a reset Follow the instructions to flash and insert a hardware breakpoint from DBG005 In GDB, type
(gdb) monitor reset
(gdb) monitor reg pc 0x100000
pc (/32): 0x00100000
(gdb) continue

where the value inserted in PC is the start address of the application
The breakpoint should be reached, typical output:
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) monitor reset init
jtag_speed 6400 => JTAG clk=0.010000
10 kHz
JTAG tap: str710.cpu tap/device found: 0x3f0f0f0f (mfg: 0x787, part: 0xf0f0, ver: 0x3)
srst pulls trst - can not reset into halted mode. Issuing halt after reset.
target state: halted
target halted in ARM state due to debug-request, current mode: Undefined instruction
cpsr: 0x400000db pc: 0x010aea80
jtag_speed 10 => JTAG clk=6.400000
6400 kHz
(gdb) monitor reg pc 0x40000000
pc (/32): 0x40000000
(gdb) c
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
Current language: auto
The current source language is "auto; currently c".
(gdb)
PASS
DBG007 STR912 ZY1000 Single step in ROM Flash the test_rom.elf application and set a breakpoint in main, use DBG005. Make this test after FLA004 has passed Be sure that gdb_memory_map and gdb_flash_program are enabled. In GDB, type
(gdb) monitor reset
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor arm7_9 force_hw_bkpts enable
force hardware breakpoints enabled
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) step
The breakpoint should be reached, typical output:
target state: halted
target halted in ARM state due to single step, current mode: Supervisor
cpsr: 0x60000013 pc: 0x0010013c
70 DWORD b = 2;
Breakpoint 2, main () at src/main.c:69
69 DWORD a = 1;
Current language: auto
The current source language is "auto; currently c".
(gdb) step
70 DWORD b = 2;
(gdb)
PASS

RAM access

Note: these tests are not designed to test/debug the target, but to test functionalities!
ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
RAM001 STR912 ZY1000 32 bit Write/read RAM Reset init is working On the telnet interface
> mww ram_address 0xdeadbeef 16
> mdw ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 32bit long containing 0xdeadbeef.
> mww 0x0 0xdeadbeef 16
> mdw 0x0 32
0x00000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000040: e1a00000 e59fa51c e59f051c e04aa000 00080017 00009388 00009388 00009388
0x00000060: 00009388 0002c2c0 0002c2c0 000094f8 000094f4 00009388 00009388 00009388
> mww 0x20000000 0xdeadbeef 16
> mdw 0x20000000 32
0x20000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x20000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x20000040: e3a0020a e3a01073 e5801018 e5901008 e3110002 0afffffc e3a0020a e59f10d0
0x20000060: e5801008 e321f0db e59fd0c8 e321f0d7 e59fd0c4 e321f0d1 e59fd0c0 e321f0d2
>
PASS
RAM002 STR912 ZY1000 16 bit Write/read RAM Reset init is working On the telnet interface
> mwh ram_address 0xbeef 16
> mdh ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 16bit long containing 0xbeef.
> mwh 0x0 0xbeef 16
> mdh 0x0 32
0x00000000: beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef
0x00000020: 00e0 0000 021c 0000 0240 0000 026c 0000 0288 0000 0000 0000 0388 0000 0350 0000
>
> mwh 0x20000000 0xbeef 16
> mdh 0x20000000 32
0x20000000: beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef
0x20000020: beef dead beef dead beef dead beef dead beef dead beef dead beef dead beef dead
>
PASS
RAM003 STR912 ZY1000 8 bit Write/read RAM Reset init is working On the telnet interface
> mwb ram_address 0xab 16
> mdb ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 8bit long containing 0xab.
> mwb ram_address 0xab 16
> mdb ram_address 32
0x00000000: ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>
> mwb 0x20000000 0xab 16
> mdb 0x20000000 32
0x20000000: ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ef be ef be ef be ef be ef be ef be ef be ef be
>
PASS

Flash access

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
FLA001 STR912 ZY1000 Flash probe Reset init is working On the telnet interface:
> flash probe 0
The command should execute without error. The output should state the name of the flash and the starting address. An example of output:
flash 'ecosflash' found at 0x01000000
> flash probe 0
flash 'str7x' found at 0x40000000
>
PASS
FLA002 STR912 ZY1000 flash fillw Reset init is working, flash is probed On the telnet interface
> flash fillw 0x1000000 0xdeadbeef 16
The commands should execute without error. The output looks like:
wrote 64 bytes to 0x01000000 in 11.610000s (0.091516 kb/s)
To verify the contents of the flash:
> mdw 0x1000000 32
0x01000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x01000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x01000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> flash fillw 0x40000000 0xdeadbeef 16
wrote 64 bytes to 0x40000000 in 0.000000s (inf kb/s)
> mdw 0x40000000 32
0x40000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x40000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x40000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x40000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
FLA003 STR912 ZY1000 Flash erase Reset init is working, flash is probed On the telnet interface
> flash erase_address 0x1000000 0x2000
The commands should execute without error.
erased address 0x01000000 length 8192 in 4.970000s To check that the flash has been erased, read at different addresses. The result should always be 0xff. > mdw 0x1000000 32
0x01000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> flash erase_address 0x40000000 0x2000
erased address 0x40000000 (length 8192) in 0.270000s (29.630 kb/s)
> mdw 0x40000000 32
0x40000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x40000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x40000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x40000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
FLA004 STR912 ZY1000 Loading to flash from GDB Reset init is working, flash is probed, connectivity to GDB server is working Start GDB using a ROM elf image, eg: arm-elf-gdb test_rom.elf.
(gdb) target remote ip:port
(gdb) monitor reset
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write. (gdb) monitor verify_image path_to_elf_file
The output should look like:
verified 404 bytes in 5.060000s
The failure message is something like:
Verify operation failed address 0x00200000. Was 0x00 instead of 0x18
(gdb) load
Loading section .text, size 0x1cc lma 0x40000000
Loading section .vectors, size 0x40 lma 0x400001cc
Loading section .rodata, size 0x4 lma 0x4000020c
Start address 0x40000000, load size 528
Transfer rate: 53 bytes/sec, 176 bytes/write.
(gdb) monitor verify_image /tftp/10.0.0.194/test_rom.elf
verified 528 bytes in 4.760000s (0.108 kb/s)
Current language: auto
The current source language is "auto; currently asm".
(gdb)
PASS
================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/results/v0.4.0-rc1/STR912.html ================================================ Test results for version 1.62

STR912

Connectivity

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
CON001 STR912 ZY1000 Telnet connection Power on, jtag target attached On console, type
telnet ip port
Open On-Chip Debugger
>
> telnet 10.0.0.142
Trying 10.0.0.142...
Connected to 10.0.0.142.
Escape character is '^]'.
Open On-Chip Debugger
>
PASS
CON002 STR912 ZY1000 GDB server connection Power on, jtag target attached On GDB console, type
target remote ip:port
Remote debugging using 10.0.0.73:3333 (gdb) tar remo 10.0.0.142:3333
Remote debugging using 10.0.0.142:3333
0x00016434 in ?? ()
(gdb)
PASS

Reset

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
RES001 STR912 ZY1000 Reset halt on a blank target Erase all the content of the flash Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
> reset halt
RCLK - adaptive
SRST took 2ms to deassert
JTAG tap: str912.flash tap/device found: 0x04570041 (mfg: 0x020, part: 0x4570, ver: 0x0)
JTAG tap: str912.cpu tap/device found: 0x25966041 (mfg: 0x020, part: 0x5966, ver: 0x2)
JTAG tap: str912.bs tap/device found: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs UNEXPECTED: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs expected 1 of 1: 0x1457f041 (mfg: 0x020, part: 0x457f, ver: 0x1)
Trying to use configured scan chain anyway...
Bypassing JTAG setup events due to errors
SRST took 2ms to deassert
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x00000000
NOTE! DCC downloads have not been enabled, defaulting to slow memory writes. Type 'help dcc'.
>
PASS
RES002 STR912 ZY1000 Reset init on a blank target Erase all the content of the flash Connect via the telnet interface and type
reset init
Reset should return without error and the output should contain
executing reset script 'name_of_the_script'
> reset init
RCLK - adaptive
SRST took 2ms to deassert
JTAG tap: str912.flash tap/device found: 0x04570041 (mfg: 0x020, part: 0x4570, ver: 0x0)
JTAG tap: str912.cpu tap/device found: 0x25966041 (mfg: 0x020, part: 0x5966, ver: 0x2)
JTAG tap: str912.bs tap/device found: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs UNEXPECTED: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs expected 1 of 1: 0x1457f041 (mfg: 0x020, part: 0x457f, ver: 0x1)
Trying to use configured scan chain anyway...
Bypassing JTAG setup events due to errors
SRST took 2ms to deassert
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x00000000
cleared protection for sectors 0 through 7 on flash bank 0
NOTE! DCC downloads have not been enabled, defaulting to slow memory writes. Type 'help dcc'.
>
PASS
RES003 STR912 ZY1000 Reset after a power cycle of the target Reset the target then power cycle the target Connect via the telnet interface and type
reset halt after the power was detected
Reset should return without error and the output should contain
target state: halted
nsed nSRST asserted.
nsed power dropout.
nsed power restore.
RCLK - adaptive
SRST took 85ms to deassert
SRST took 2ms to deassert
JTAG tap: str912.flash tap/device found: 0x04570041 (mfg: 0x020, part: 0x4570, ver: 0x0)
JTAG tap: str912.cpu tap/device found: 0x25966041 (mfg: 0x020, part: 0x5966, ver: 0x2)
JTAG tap: str912.bs tap/device found: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs UNEXPECTED: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs expected 1 of 1: 0x1457f041 (mfg: 0x020, part: 0x457f, ver: 0x1)
Trying to use configured scan chain anyway...
Bypassing JTAG setup events due to errors
SRST took 2ms to deassert
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x00000000
cleared protection for sectors 0 through 7 on flash bank 0
NOTE! DCC downloads have not been enabled, defaulting to slow memory writes. Type 'help dcc'.
> reset halt
RCLK - adaptive
SRST took 2ms to deassert
JTAG tap: str912.flash tap/device found: 0x04570041 (mfg: 0x020, part: 0x4570, ver: 0x0)
JTAG tap: str912.cpu tap/device found: 0x25966041 (mfg: 0x020, part: 0x5966, ver: 0x2)
JTAG tap: str912.bs tap/device found: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs UNEXPECTED: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs expected 1 of 1: 0x1457f041 (mfg: 0x020, part: 0x457f, ver: 0x1)
Trying to use configured scan chain anyway...
Bypassing JTAG setup events due to errors
SRST took 2ms to deassert
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x00000000
NOTE! DCC downloads have not been enabled, defaulting to slow memory writes. Type 'help dcc'.
>
PASS
RES004 STR912 ZY1000 Reset halt on a blank target where reset halt is supported Erase all the content of the flash Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
pc = 0
> reset halt
RCLK - adaptive
SRST took 2ms to deassert
JTAG tap: str912.flash tap/device found: 0x04570041 (Manufacturer: 0x020, Part: 0x4570, Version: 0x0)
JTAG Tap/device matched
JTAG tap: str912.cpu tap/device found: 0x25966041 (Manufacturer: 0x020, Part: 0x5966, Version: 0x2)
JTAG Tap/device matched
JTAG tap: str912.bs tap/device found: 0x2457f041 (Manufacturer: 0x020, Part: 0x457f, Version: 0x2)
JTAG Tap/device matched
SRST took 2ms to deassert
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x00000000
>
PASS
RES005 STR912 ZY1000 Reset halt on a blank target using return clock Erase all the content of the flash, set the configuration script to use RCLK Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
> reset halt
RCLK - adaptive
SRST took 2ms to deassert
JTAG tap: str912.flash tap/device found: 0x04570041 (mfg: 0x020, part: 0x4570, ver: 0x0)
JTAG tap: str912.cpu tap/device found: 0x25966041 (mfg: 0x020, part: 0x5966, ver: 0x2)
JTAG tap: str912.bs tap/device found: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs UNEXPECTED: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs expected 1 of 1: 0x1457f041 (mfg: 0x020, part: 0x457f, ver: 0x1)
Trying to use configured scan chain anyway...
Bypassing JTAG setup events due to errors
SRST took 2ms to deassert
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x00000000
NOTE! DCC downloads have not been enabled, defaulting to slow memory writes. Type 'help dcc'.
>
PASS

JTAG Speed

ID Target ZY1000 Description Initial state Input Expected output Actual output Pass/Fail
SPD001 STR912 ZY1000 16MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 16000
jtag_speed 4 => JTAG clk=16.000000
16000 kHz
ThumbEE -- incomplete support
target state: halted
target halted in ThumbEE state due to debug-request, current mode: System
cpsr: 0xfdfdffff pc: 0xfdfdfff9
> mdw 0 32
0x00000000: 00000000 00000000 ffffffff ffffffff 00000001 ffffffff 00000001 ffffffff
0x00000020: 00000001 00000001 00000001 00000001 00000001 fffffffe fffffffe 00000001
0x00000040: fffffffe 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x00000060: 00000000 00000000 00000000 00000000 ffffffff ffffffff 00000001 00000000
invalid mode value encountered 0
cpsr contains invalid mode value - communication failure
ThumbEE -- incomplete support
target state: halted
target halted in ThumbEE state due to debug-request, current mode: System
cpsr: 0xffffffff pc: 0xfffffff8
>
FAIL
SPD002 STR912 ZY1000 8MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 8000
jtag_speed 8 => JTAG clk=8.000000
8000 kHz
> halt
invalid mode value encountered 0
cpsr contains invalid mode value - communication failure
Command handler execution failed
in procedure 'halt' called at file "command.c", line 647
called at file "command.c", line 361
Halt timed out, wake up GDB.
>
FAIL
SPD003 STR912 ZY1000 4MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 4000
jtag_speed 16 => JTAG clk=4.000000
4000 kHz
> halt
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
SPD004 STR912 ZY1000 2MHz on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 2000
jtag_speed 32 => JTAG clk=2.000000
2000 kHz
> halt
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
SPD005 STR912 ZY1000 RCLK on normal operation Reset init the target according to RES002 Change speed and exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed > jtag_khz 0
RCLK - adaptive
> halt
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS

Debugging

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
DBG001 STR912 ZY1000 Load is working Reset init is working, RAM is accesible, GDB server is started On the console of the OS:
arm-elf-gdb test_ram.elf
(gdb) target remote ip:port
(gdb) load
Load should return without error, typical output looks like:
Loading section .text, size 0x14c lma 0x0
Start address 0x40, load size 332
Transfer rate: 180 bytes/sec, 332 bytes/write.
(gdb) load
Loading section .text, size 0x1a0 lma 0x4000000
Loading section .rodata, size 0x4 lma 0x40001a0
Start address 0x4000000, load size 420
Transfer rate: 29 KB/sec, 210 bytes/write.
(gdb)
PASS
DBG002 STR912 ZY1000 Software breakpoint Load the test_ram.elf application, use instructions from GDB001 In the GDB console:
(gdb) monitor gdb_breakpoint_override soft
force soft breakpoints
(gdb) break main
Breakpoint 1 at 0xec: file src/main.c, line 71.
(gdb) continue
Continuing.
The software breakpoint should be reached, a typical output looks like:
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x000000ec

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
(gdb) monitor gdb_breakpoint_override soft
force soft breakpoints
Current language: auto
The current source language is "auto; currently asm".
(gdb) break main
Breakpoint 1 at 0x4000144: file src/main.c, line 69.
(gdb) c
Continuing.

Breakpoint 1, main () at src/main.c:69
warning: Source file is more recent than executable.
69 DWORD a = 1;
Current language: auto
The current source language is "auto; currently c".
(gdb)
PASS
DBG003 STR912 ZY1000 Single step in a RAM application Load the test_ram.elf application, use instructions from GDB001, break in main using the instructions from GDB002 In GDB, type
(gdb) step
The next instruction should be reached, typical output:
(gdb) step
target state: halted
target halted in ARM state due to single step, current mode: Abort
cpsr: 0x20000097 pc: 0x000000f0
target state: halted
target halted in ARM state due to single step, current mode: Abort
cpsr: 0x20000097 pc: 0x000000f4
72 DWORD b = 2;
(gdb) step
70 DWORD b = 2;
(gdb)
PASS
DBG004 STR912 ZY1000 Software break points are working after a reset Load the test_ram.elf application, use instructions from GDB001, break in main using the instructions from GDB002 In GDB, type
(gdb) monitor reset init
(gdb) load
(gdb) continue
The breakpoint should be reached, typical output:
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x000000ec

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
(gdb) monitor reset init
RCLK - adaptive
SRST took 2ms to deassert
JTAG tap: str912.flash tap/device found: 0x04570041 (mfg: 0x020, part: 0x4570, ver: 0x0)
JTAG tap: str912.cpu tap/device found: 0x25966041 (mfg: 0x020, part: 0x5966, ver: 0x2)
JTAG tap: str912.bs tap/device found: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs UNEXPECTED: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs expected 1 of 1: 0x1457f041 (mfg: 0x020, part: 0x457f, ver: 0x1)
Trying to use configured scan chain anyway...
Bypassing JTAG setup events due to errors
SRST took 2ms to deassert
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x00000000
cleared protection for sectors 0 through 7 on flash bank 0
NOTE! DCC downloads have not been enabled, defaulting to slow memory writes. Type 'help dcc'.
(gdb) load
Loading section .text, size 0x1a0 lma 0x4000000
Loading section .rodata, size 0x4 lma 0x40001a0
Start address 0x4000000, load size 420
Transfer rate: 25 KB/sec, 210 bytes/write.
(gdb) c
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb)
PASS
DBG005 STR912 ZY1000 Hardware breakpoint Flash the test_rom.elf application. Make this test after FLA004 has passed Be sure that gdb_memory_map and gdb_flash_program are enabled. In GDB, type
(gdb) monitor reset init
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor gdb_breakpoint_override hard
force hard breakpoints
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
The breakpoint should be reached, typical output:
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) monitor reset init
RCLK - adaptive
SRST took 2ms to deassert
JTAG tap: str912.flash tap/device found: 0x04570041 (mfg: 0x020, part: 0x4570, ver: 0x0)
JTAG tap: str912.cpu tap/device found: 0x25966041 (mfg: 0x020, part: 0x5966, ver: 0x2)
JTAG tap: str912.bs tap/device found: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs UNEXPECTED: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs expected 1 of 1: 0x1457f041 (mfg: 0x020, part: 0x457f, ver: 0x1)
Trying to use configured scan chain anyway...
Bypassing JTAG setup events due to errors
SRST took 2ms to deassert
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x00000000
cleared protection for sectors 0 through 7 on flash bank 0
NOTE! DCC downloads have not been enabled, defaulting to slow memory writes. Type 'help dcc'.
(gdb) load
Loading section .text, size 0x1a0 lma 0x0
Loading section .rodata, size 0x4 lma 0x1a0
Start address 0x0, load size 420
Transfer rate: 426 bytes/sec, 210 bytes/write.
(gdb) monitor gdb_breakpoint_override hard
force hard breakpoints
(gdb) break main
Breakpoint 1 at 0x144: file src/main.c, line 69.
(gdb) continue
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, main () at src/main.c:69
warning: Source file is more recent than executable.
69 DWORD a = 1;
Current language: auto
The current source language is "auto; currently c".
(gdb)
PASS
DBG006 STR912 ZY1000 Hardware breakpoint is set after a reset Follow the instructions to flash and insert a hardware breakpoint from DBG005 In GDB, type
(gdb) monitor reset
(gdb) monitor reg pc 0x100000
pc (/32): 0x00100000
(gdb) continue

where the value inserted in PC is the start address of the application
The breakpoint should be reached, typical output:
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) monitor reset init
RCLK - adaptive
SRST took 2ms to deassert
JTAG tap: str912.flash tap/device found: 0x04570041 (mfg: 0x020, part: 0x4570, ver: 0x0)
JTAG tap: str912.cpu tap/device found: 0x25966041 (mfg: 0x020, part: 0x5966, ver: 0x2)
JTAG tap: str912.bs tap/device found: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs UNEXPECTED: 0x2457f041 (mfg: 0x020, part: 0x457f, ver: 0x2)
JTAG tap: str912.bs expected 1 of 1: 0x1457f041 (mfg: 0x020, part: 0x457f, ver: 0x1)
Trying to use configured scan chain anyway...
Bypassing JTAG setup events due to errors
SRST took 2ms to deassert
target state: halted
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x00000000
cleared protection for sectors 0 through 7 on flash bank 0
NOTE! DCC downloads have not been enabled, defaulting to slow memory writes. Type 'help dcc'.
(gdb) c
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb)
PASS
DBG007 STR912 ZY1000 Single step in ROM Flash the test_rom.elf application and set a breakpoint in main, use DBG005. Make this test after FLA004 has passed Be sure that gdb_memory_map and gdb_flash_program are enabled. In GDB, type
(gdb) monitor reset
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor arm7_9 force_hw_bkpts enable
force hardware breakpoints enabled
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) step
The breakpoint should be reached, typical output:
target state: halted
target halted in ARM state due to single step, current mode: Supervisor
cpsr: 0x60000013 pc: 0x0010013c
70 DWORD b = 2;
(gdb) c
Continuing.

Breakpoint 2, main () at src/main.c:69
69 DWORD a = 1;
Current language: auto
The current source language is "auto; currently c".
(gdb) step
70 DWORD b = 2;
(gdb)
PASS

RAM access

Note: these tests are not designed to test/debug the target, but to test functionalities!
ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
RAM001 STR912 ZY1000 32 bit Write/read RAM Reset init is working On the telnet interface
> mww ram_address 0xdeadbeef 16
> mdw ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 32bit long containing 0xdeadbeef.
> mww 0x0 0xdeadbeef 16
> mdw 0x0 32
0x00000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000040: e1a00000 e59fa51c e59f051c e04aa000 00080017 00009388 00009388 00009388
0x00000060: 00009388 0002c2c0 0002c2c0 000094f8 000094f4 00009388 00009388 00009388
> mww 0x4000000 0xdeadbeef 16
> mdw 0x4000000 32
0x04000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x04000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x04000040: e580100c e3a01802 e5801010 e3a01018 e5801018 e59f00a8 e59f10a8 e5801000
0x04000060: e3a00806 ee2f0f11 e321f0d7 e59fd098 e321f0db e59fd094 e321f0d3 e59fd090
>
PASS
RAM002 STR912 ZY1000 16 bit Write/read RAM Reset init is working On the telnet interface
> mwh ram_address 0xbeef 16
> mdh ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 16bit long containing 0xbeef.
> mwh 0x0 0xbeef 16
> mdh 0x0 32
0x00000000: beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef
0x00000020: 00e0 0000 021c 0000 0240 0000 026c 0000 0288 0000 0000 0000 0388 0000 0350 0000
>
> mwh 0x4000000 0xbeef 16
> mdh 0x4000000 32
0x04000000: beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef
0x04000020: beef dead beef dead beef dead beef dead beef dead beef dead beef dead beef dead
>
PASS
RAM003 STR912 ZY1000 8 bit Write/read RAM Reset init is working On the telnet interface
> mwb ram_address 0xab 16
> mdb ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 8bit long containing 0xab.
> mwb ram_address 0xab 16
> mdb ram_address 32
0x00000000: ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>
> mwb 0x4000000 0xab 16
> mdb 0x4000000 32
0x04000000: ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ef be ef be ef be ef be ef be ef be ef be ef be
>
PASS

Flash access

ID Target Interface Description Initial state Input Expected output Actual output Pass/Fail
FLA001 STR912 ZY1000 Flash probe Reset init is working On the telnet interface:
> flash probe 0
The command should execute without error. The output should state the name of the flash and the starting address. An example of output:
flash 'ecosflash' found at 0x01000000
> flash probe 0
flash 'str9x' found at 0x00000000
>
PASS
FLA002 STR912 ZY1000 flash fillw Reset init is working, flash is probed On the telnet interface
> flash fillw 0x1000000 0xdeadbeef 16
The commands should execute without error. The output looks like:
wrote 64 bytes to 0x01000000 in 11.610000s (0.091516 kb/s)
To verify the contents of the flash:
> mdw 0x1000000 32
0x01000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x01000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x01000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> flash fillw 0x0 0xdeadbeef 16
wrote 64 bytes to 0x00000000 in 0.020000s (3.125 kb/s)
> mdw 0 32
0x00000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
FLA003 STR912 ZY1000 Flash erase Reset init is working, flash is probed On the telnet interface
> flash erase_address 0x1000000 0x20000
The commands should execute without error.
erased address 0x01000000 length 131072 in 4.970000s
To check that the flash has been erased, read at different addresses. The result should always be 0xff.
> mdw 0x1000000 32
0x01000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> flash erase_address 0 0x20000
erased address 0x00000000 (length 131072) in 1.970000s (64.975 kb/s)
> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
>
PASS
FLA004 STR912 ZY1000 Entire flash erase Reset init is working, flash is probed On the telnet interface
> flash erase_address 0x0 0x80000
The commands should execute without error.
erased address 0x01000000 length 8192 in 4.970000s
To check that the flash has been erased, read at different addresses. The result should always be 0xff.
> mdw 0x1000000 32
0x01000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
> flash erase_address 0 0x80000
erased address 0x00000000 length 524288 in 1.020000s

> mdw 0 32
0x00000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x00000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
PASS
FLA005 STR912 ZY1000 Loading to flash from GDB Reset init is working, flash is probed, connectivity to GDB server is working Start GDB using a ROM elf image, eg: arm-elf-gdb test_rom.elf.
(gdb) target remote ip:port
(gdb) monitor reset
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write. (gdb) monitor verify_image path_to_elf_file
The output should look like:
verified 404 bytes in 5.060000s
The failure message is something like:
Verify operation failed address 0x00200000. Was 0x00 instead of 0x18
(gdb) load
Loading section .text, size 0x1a0 lma 0x0
Loading section .rodata, size 0x4 lma 0x1a0
Start address 0x0, load size 420
Transfer rate: 425 bytes/sec, 210 bytes/write.
(gdb) moni verify_image /tftp/10.0.0.194/test_rom.elf
verified 420 bytes in 0.350000s (1.172 kb/s)
(gdb)
PASS
================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/smoketests.html ================================================

OpenOCD smoketest results

These tests can be performed on any JTAG device as long as they are executed using the unmodified code from git.

The latest version in which the test is known to have passed is in the table below.

Vocabulary

Passed version The latest branch and version on which the test is known to pass
Broken version The latest branch and version on which the test is known to fail. n/a when older than passed version.
ID A unqiue ID to refer to a test. The unique numbers are maintained in this file. Note that the same test can be run on different hardware/interface. Each combination yields a unique id.

Unique ID Synopsis JTAG device Passed version Broken version
fill_malloc Fill malloc() memory with garbage n/a n/a n/a
ocd1 Telnet Windows n/a n/a n/a
ocd2 Telnet Linux n/a n/a n/a
ocd3 Telnet Cygwin n/a n/a n/a
ocd4 ARM7 debugging n/a n/a n/a
SAM9260 SAM9260 debugging ft2232 500 n/a
xscale1 XScale debugging bitbang 505 n/a
xscale2 XScale debugging FT2232 202 n/a
bdte-ram1 str710 ram debugging JTAGkey 657 n/a
bdte-rom2 str710 rom debugging JTAGkey 657 n/a
bdte-ram3 str912 ram debugging JTAGkey 657 n/a
bdte-rom4 str912 rom debugging JTAGkey 657 n/a
bdte-ram5 lpc2148 ram debugging JTAGkey 657 n/a
bdte-rom6 lpc2148 rom debugging JTAGkey 657 n/a
bdte-ram7 lpc2294 ram debugging JTAGkey 657 n/a
bdte-rom8 lpc2294 rom debugging JTAGkey 657 n/a
bdte-ram9 sam7s256 ram debugging JTAGkey 657 n/a
bdte-rom10 sam7s256 rom debugging JTAGkey 657 n/a
bdte-ram11 sam7x256 ram debugging JTAGkey 657 n/a
bdte-rom12 sam7x256 rom debugging JTAGkey 657 n/a
bdte-ram13 at91r40008 ram debugging JTAGkey 657 n/a


OpenOCD JTAG device test results

Each JTAG device must be tested
ID Synopsis Passed version Broken version
jtag1 Parport n/a n/a
jtag2 JTAGkey 657 n/a
jtag3 Turtelizer2 657 n/a
jtag4 JTAGkey 657 n/a
jtag5 add new one n/a n/a

jtag1:

jtag2: Tested on Windows XP Prof. (SP2) with original FTDI driver.

jtag3: Tested on Windows XP Prof. (SP2) with original FTDI driver.

jtag4: Tested on Mac OS X (10.5.2, Intel) with libftdi-0.10 and libusb-0.1.12

jtag5:


OpenOCD JTAG device speed test result

The test result is in KB/sec.

ID Synopsis r320 r420 r423 r459 r517 r536 r651 r657
speed1 JTAGkey 93 64 93 93 93 93 162 165
speed2 JTAGkey n/a n/a n/a n/a 52 52 110 111
speed3 add new one n/a n/a n/a n/a n/a n/a n/a n/a


Policy on removing features from OpenOCD

If a feature in OpenOCD is known to be broken and nobody has submitted a fix and the feature is causing trouble for maintainence, it can be removed from OpenOCD mainline. The threshold for temporarily removing something from OpenOCD mainline is low to ease maintainence and place the burden of maintainence on those that care about a feature.

Note that code is never deleted from OpenOCD git, it remains in the repository so if somebody sees a feature removed that they would like kept, they have but to port and fix that feature back up to main mainline. This document can be helpful in this regard in that the latest working version and the known broken version may be listed.

Policy on adding features from OpenOCD

To add a feature to OpenOCD, generally it should not break any existing features and it should be functional and the code reasonably readable and useful to others in the OpenOCD community. The code does not have to be completed. Work in progress is fine for OpenOCD mainline.

Also new tests should be defined. Note that the code does not have to pass all the tests. In fact it can be helpful to have tests to describe facets that really should be working, but aren't done yet.


ocd4 - ARM7 debugging

Connect to ARM7 device(any), use GDB load to load a program into RAM and single halt, resume and single step.

bdte-ram (Basic debugging test with Eclipse in RAM)

This test was made under Eclipse with the Zylin Embedded CDT plugin. For the GDB "Initialize commands" take a look in the examples/<target>/prj/eclipse_ram.gdb file.

Start debugging, the debugger should stop at main. set some breakpoints and "Resume". If the debugger hit a breakpoint check if the "Variables" looks correct. Remove some breakpoints and "Resume" again. If the target is running, use the "Suspend" function and use "Step Into" or "Step Over" through the source. Even open the "Disassembly" view and enable the "Instruction Stepping Mode". Now you can single step through the assembler source. Use "Resume" again to run the program, set a breakpoint while the target is running. Check if you can inspect the variables with the mouse over. Play a little with the target...


bdte-rom (Basic debugging test with Eclipse in ROM)

This test was made under Eclipse with the Zylin Embedded CDT plugin. For the GDB "Initialize commands" take a look in the examples/<target>/prj/eclipse_rom.gdb file.

Start debugging, the debugger should download and store the program in the flash of the target.

Now you can make some tests like described in the bdte-ram section above too.


speed1 - Download speed test

For this test a STR710 with external memory was used. The example project can be found under examples/STR710JtagSpeed. Here Eclipse or the arm-elf-gdb can be used to download the test.elf file into the RAM. The result of the GDB can look like:

Loading section .text, size 0x6019c lma 0x62000000
Start address 0x62000040, load size 393628
Transfer rate: 93 KB/sec, 2008 bytes/write.

In this example a speed of 93 KB/sec was reached. The hardware which was used for the test can be found here.

The test was made on Windows XP Prof. (SP2) with a JTAGkey and the original FTDI driver.


speed2 - Download speed test

For this test a STR710 with external memory was used. The example project can be found under examples/STR710JtagSpeed. Here Eclipse or the arm-elf-gdb can be used to download the test.elf file into the RAM. The result of the GDB can look like:

Loading section .text, size 0x6019c lma 0x62000000
Start address 0x62000040, load size 393628
Transfer rate: 52 KB/sec, 2008 bytes/write.

In this example a speed of 52 KB/sec was reached. The hardware which was used for the test can be found here.

The test was made on Mac OS X (10.5.2, Intel) with a JTAGkey and the following driver:

- libftdi 0.10
- libusb 0.1.12

================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/tcl_server.tcl ================================================ # Simple tcl client to connect to openocd puts "Use empty line to exit" set fo [socket 127.0.0.1 6666] puts -nonewline stdout "> " flush stdout while {[gets stdin line] >= 0} { if {$line eq {}} break puts $fo $line flush $fo gets $fo line puts $line puts -nonewline stdout "> " flush stdout } close $fo ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/tcl_test.tcl ================================================ if { $argc != 1 } { puts "Usage: test_tcl.tcl " exit 1 } puts $argv # Simple tcl client to connect to openocd global fo set fo [socket $argv 6666] # If a fn is unknown to Tcl, send it off to OpenOCD proc unknown args { global fo puts $fo $args flush $fo gets $fo line return $line } #Print help text for a command. Word wrap #help text that is too wide inside column. proc pc_help {args} { global ocd_helptext set cmd $args foreach a [lsort $ocd_helptext] { if {[string length $cmd]==0||[string first $cmd $a]!=-1||[string first $cmd [lindex $a 1]]!=-1} { set w 50 set cmdname [lindex $a 0] set h [lindex $a 1] set n 0 while 1 { if {$n > [string length $h]} {break} set next_a [expr $n+$w] if {[string length $h]>$n+$w} { set xxxx [string range $h $n [expr $n+$w]] for {set lastpos [expr [string length $xxxx]-1]} {$lastpos>=0&&[string compare [string range $xxxx $lastpos $lastpos] " "]!=0} {set lastpos [expr $lastpos-1]} { } #set next_a -1 if {$lastpos!=-1} { set next_a [expr $lastpos+$n+1] } } puts [format "%-25s %s" $cmdname [string range $h $n [expr $next_a-1]] ] set cmdname "" set n [expr $next_a] } } } } puts "Running flash_banks" puts [flash_banks] puts "Running help on PC using data from OpenOCD" global ocd_helptext set ocd_helptext [get_help_text] puts [pc_help] ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/test-am335xgpio-deprecated-commands.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # OpenOCD script to test that the deprecated "am335xgpio *" commands produce the # expected results. Run this command as: # # openocd -f /test-linuxgpiod-deprecated-commands.cfg # Raise an error if the "actual" value does not match the "expected" value. Trim # whitespace (including newlines) from strings before comparing. proc expected_value {expected actual} { if {[string trim $expected] ne [string trim $actual]} { error [puts "ERROR: '${actual}' != '${expected}'"] } } adapter driver am335xgpio am335xgpio jtag_nums 1 2 3 4 expected_value "adapter gpio tck (output): num 1, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] expected_value "adapter gpio tms (output): num 2, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] expected_value "adapter gpio tdi (output): num 3, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] expected_value "adapter gpio tdo (input): num 4, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] am335xgpio tck_num 5 expected_value "adapter gpio tck (output): num 5, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] am335xgpio tms_num 6 expected_value "adapter gpio tms (output): num 6, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] am335xgpio tdi_num 7 expected_value "adapter gpio tdi (output): num 7, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] am335xgpio tdo_num 8 expected_value "adapter gpio tdo (input): num 8, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] am335xgpio swd_nums 9 10 expected_value "adapter gpio swclk (output): num 9, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] expected_value "adapter gpio swdio (bidirectional): num 10, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] am335xgpio swclk_num 11 expected_value "adapter gpio swclk (output): num 11, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] am335xgpio swdio_num 12 expected_value "adapter gpio swdio (bidirectional): num 12, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] am335xgpio swdio_dir_num 13 expected_value "adapter gpio swdio_dir (output): num 13, chip 0, active-high, push-pull, pull-none" [eval adapter gpio swdio_dir] am335xgpio swdio_dir_output_state low expected_value "adapter gpio swdio_dir (output): num 13, chip 0, active-low, push-pull, pull-none" [eval adapter gpio swdio_dir] am335xgpio swdio_dir_output_state high expected_value "adapter gpio swdio_dir (output): num 13, chip 0, active-high, push-pull, pull-none" [eval adapter gpio swdio_dir] am335xgpio srst_num 14 expected_value "adapter gpio srst (output): num 14, chip 0, active-low, pull-none, init-state inactive" [eval adapter gpio srst] am335xgpio trst_num 15 expected_value "adapter gpio trst (output): num 15, chip 0, active-low, pull-none, init-state inactive" [eval adapter gpio trst] am335xgpio led_num 16 expected_value "adapter gpio led (output): num 16, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio led] am335xgpio led_on_state low expected_value "adapter gpio led (output): num 16, chip 0, active-low, push-pull, pull-none, init-state inactive" [eval adapter gpio led] am335xgpio led_on_state high expected_value "adapter gpio led (output): num 16, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio led] puts "SUCCESS" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/test-bcm2835gpio-deprecated-commands.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # OpenOCD script to test that the deprecated "bcm2835gpio *" and "bcm2835gpio_*" # commands produce the expected results. Run this command as: # openocd -f /test-bcm2835gpio-deprecated-commands.cfg # Raise an error if the "actual" value does not match the "expected" value. Trim # whitespace (including newlines) from strings before comparing. proc expected_value {expected actual} { if {[string trim $expected] ne [string trim $actual]} { error [puts "ERROR: '${actual}' != '${expected}'"] } } set supported_signals {tdo tdi tms tck trst swdio swdio_dir swclk srst} adapter speed 100 adapter driver bcm2835gpio puts "Driver is '[adapter name]'" expected_value "bcm2835gpio" [adapter name] echo [adapter gpio] ##################################### # Test the "bcm2835gpio *" commands # Change the GPIO chip for all signals. Don't check directly here, do so when # each signal command is tested. # bcm2835gpio gpiochip 0 bcm2835gpio jtag_nums 1 2 3 4 expected_value "adapter gpio tck (output): num 1, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] expected_value "adapter gpio tms (output): num 2, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] expected_value "adapter gpio tdi (output): num 3, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] expected_value "adapter gpio tdo (input): num 4, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] bcm2835gpio tck_num 5 expected_value "adapter gpio tck (output): num 5, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] bcm2835gpio tms_num 6 expected_value "adapter gpio tms (output): num 6, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] bcm2835gpio tdi_num 7 expected_value "adapter gpio tdi (output): num 7, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] bcm2835gpio tdo_num 8 expected_value "adapter gpio tdo (input): num 8, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] bcm2835gpio swd_nums 9 10 expected_value "adapter gpio swclk (output): num 9, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] expected_value "adapter gpio swdio (bidirectional): num 10, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] bcm2835gpio swclk_num 11 expected_value "adapter gpio swclk (output): num 11, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] bcm2835gpio swdio_num 12 expected_value "adapter gpio swdio (bidirectional): num 12, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] bcm2835gpio swdio_dir_num 13 expected_value "adapter gpio swdio_dir (output): num 13, chip 0, active-high, push-pull, pull-none" [eval adapter gpio swdio_dir] bcm2835gpio srst_num 14 expected_value "adapter gpio srst (output): num 14, chip 0, active-low, pull-none, init-state inactive" [eval adapter gpio srst] bcm2835gpio trst_num 15 expected_value "adapter gpio trst (output): num 15, chip 0, active-low, pull-none, init-state inactive" [eval adapter gpio trst] ##################################### # Test the old bcm2835gpio_* commands # Reset the GPIO chip for all signals. Don't check directly here, do so when # each signal command is tested. foreach sig_name $supported_signals { eval adapter gpio $sig_name -chip -1 } bcm2835gpio_jtag_nums 17 18 19 20 expected_value "adapter gpio tck (output): num 17, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] expected_value "adapter gpio tms (output): num 18, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] expected_value "adapter gpio tdi (output): num 19, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] expected_value "adapter gpio tdo (input): num 20, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] bcm2835gpio_tck_num 21 expected_value "adapter gpio tck (output): num 21, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] bcm2835gpio_tms_num 22 expected_value "adapter gpio tms (output): num 22, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] bcm2835gpio_tdi_num 23 expected_value "adapter gpio tdi (output): num 23, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] bcm2835gpio_tdo_num 24 expected_value "adapter gpio tdo (input): num 24, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] bcm2835gpio_swd_nums 25 26 expected_value "adapter gpio swclk (output): num 25, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] expected_value "adapter gpio swdio (bidirectional): num 26, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] bcm2835gpio_swclk_num 27 expected_value "adapter gpio swclk (output): num 27, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] bcm2835gpio_swdio_num 28 expected_value "adapter gpio swdio (bidirectional): num 28, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] puts "SUCCESS" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/test-linuxgpiod-deprecated-commands.cfg ================================================ # SPDX-License-Identifier: GPL-2.0-or-later # OpenOCD script to test that the deprecated "linuxgpiod *" and "linuxgpiod_*" # commands produce the expected results. Run this command as: # openocd -f /test-linuxgpiod-deprecated-commands.cfg # Raise an error if the "actual" value does not match the "expected" value. Trim # whitespace (including newlines) from strings before comparing. proc expected_value {expected actual} { if {[string trim $expected] ne [string trim $actual]} { error [puts "ERROR: '${actual}' != '${expected}'"] } } adapter driver linuxgpiod puts "Driver is '[adapter name]'" expected_value "linuxgpiod" [adapter name] echo [adapter gpio] ##################################### # Test the "linuxgpiod *" commands # Change the GPIO chip for all signals. Don't check directly here, do so when # each signal command is tested. linuxgpiod gpiochip 0 linuxgpiod jtag_nums 1 2 3 4 expected_value "adapter gpio tck (output): num 1, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] expected_value "adapter gpio tms (output): num 2, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] expected_value "adapter gpio tdi (output): num 3, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] expected_value "adapter gpio tdo (input): num 4, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] linuxgpiod tck_num 5 expected_value "adapter gpio tck (output): num 5, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] linuxgpiod tms_num 6 expected_value "adapter gpio tms (output): num 6, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] linuxgpiod tdi_num 7 expected_value "adapter gpio tdi (output): num 7, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] linuxgpiod tdo_num 8 expected_value "adapter gpio tdo (input): num 8, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] linuxgpiod swd_nums 9 10 expected_value "adapter gpio swclk (output): num 9, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] expected_value "adapter gpio swdio (bidirectional): num 10, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] linuxgpiod swclk_num 11 expected_value "adapter gpio swclk (output): num 11, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] linuxgpiod swdio_num 12 expected_value "adapter gpio swdio (bidirectional): num 12, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] linuxgpiod swdio_dir_num 13 expected_value "adapter gpio swdio_dir (output): num 13, chip 0, active-high, push-pull, pull-none" [eval adapter gpio swdio_dir] linuxgpiod srst_num 14 expected_value "adapter gpio srst (output): num 14, chip 0, active-low, pull-none, init-state inactive" [eval adapter gpio srst] linuxgpiod trst_num 15 expected_value "adapter gpio trst (output): num 15, chip 0, active-low, pull-none, init-state inactive" [eval adapter gpio trst] linuxgpiod led_num 16 expected_value "adapter gpio led (output): num 16, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio led] ##################################### # Test the old linuxgpiod_* commands # Change the GPIO chip for all signals. Don't check directly here, do so when # each signal command is tested. linuxgpiod_gpiochip 1 linuxgpiod_jtag_nums 17 18 19 20 expected_value "adapter gpio tck (output): num 17, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] expected_value "adapter gpio tms (output): num 18, chip 1, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] expected_value "adapter gpio tdi (output): num 19, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] expected_value "adapter gpio tdo (input): num 20, chip 1, active-high, pull-none, init-state input" [eval adapter gpio tdo] linuxgpiod_tck_num 21 expected_value "adapter gpio tck (output): num 21, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] linuxgpiod_tms_num 22 expected_value "adapter gpio tms (output): num 22, chip 1, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] linuxgpiod_tdi_num 23 expected_value "adapter gpio tdi (output): num 23, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] linuxgpiod_tdo_num 24 expected_value "adapter gpio tdo (input): num 24, chip 1, active-high, pull-none, init-state input" [eval adapter gpio tdo] linuxgpiod_swd_nums 25 26 expected_value "adapter gpio swclk (output): num 25, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] expected_value "adapter gpio swdio (bidirectional): num 26, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] linuxgpiod_swclk_num 27 expected_value "adapter gpio swclk (output): num 27, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] linuxgpiod_swdio_num 28 expected_value "adapter gpio swdio (bidirectional): num 28, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] linuxgpiod_led_num 29 expected_value "adapter gpio led (output): num 29, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio led] puts "SUCCESS" ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/testing/testcases.html ================================================ Test cases

Test cases

Test case results

The test results are stored in seperate documents. One document for each subversion number.
Test resultscomment
SAM7 R607PASS
STR710 R607PASS
templateTest results template

Vocabulary

Passed version The latest branch and version on which the test is known to pass
Broken version The latest branch and version on which the test is known to fail. n/a when older than passed version.
ID A unqiue ID to refer to a test. The unique numbers are maintained in this file. Note that the same test can be run on different hardware/interface. Each combination yields a unique id.
Test case An atomic entity that describes the operations needed to test a feature or only a part of it. The test case should:
  • be uniquely identifiable
  • define the complete prerequisites of the test (eg: the target, the interface, the initial state of the system)
  • define the input to be applied to the system in order to execute the test
  • define the expected output
  • contain the output resulted by running the test case
  • contain the result of the test (pass/fail)
Test suite A (completable) collection of test cases
Testing Testing refers to running the test suite for a specific revision of the software, for one or many targets, using one or many JTAG interfaces. Testing should be be stored along with all the other records for that specific revision. For releases, the results can be stored along with the binaries
Target = ANY Any target can be used for this test
Interface = ANY Any interface can be used for this test
Target = "reset_config srst_and_trst" Any target which supports the reset_config above

Test cases

Connectivity

ID Target Interface Description Initial state Input Expected output Pass/Fail
CON001 ALL ALL Telnet connection Power on, jtag target attached On console, type
telnet ip port
Open On-Chip Debugger
>
PASS/FAIL
CON002 ALL ALL GDB server connection Power on, jtag target attached On GDB console, type
target remote ip:port
Remote debugging using 10.0.0.73:3333 PASS/FAIL

Reset

ID Target Interface Description Initial state Input Expected output Pass/Fail
RES001 Fill in! Fill in! Reset halt on a blank target Erase all the content of the flash Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
pc = 0
PASS/FAIL
RES002 Fill in! Fill in! Reset init on a blank target Erase all the content of the flash Connect via the telnet interface and type
reset init
Reset should return without error and the output should contain
executing reset script 'name_of_the_script'
PASS/FAIL
RES003 Fill in! Fill in! Reset after a power cycle of the target Reset the target then power cycle the target Connect via the telnet interface and type
reset halt after the power was detected
Reset should return without error and the output should contain
target state: halted
PASS/FAIL
RES004 ARM7/9,reset_config srst_and_trst ANY Reset halt on a blank target where reset halt is supported Erase all the content of the flash Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
pc = 0
PASS/FAIL
RES005 arm926ejs,reset_config srst_and_trst ANY Reset halt on a blank target where reset halt is supported. This target has problems with the reset vector catch being disabled by TRST Erase all the content of the flash Connect via the telnet interface and type
reset halt
Reset should return without error and the output should contain
target state: halted
pc = 0
PASS/FAIL

JTAG Speed

ID Target Interface Description Initial state Input Expected output Pass/Fail
RES001 Fill in! Fill in! 16MHz on normal operation Reset init the target according to RES002 Exercise a memory access over the JTAG, for example
mdw 0x0 32
The command should run without any errors. If any JTAG checking errors happen, the test failed PASS/FAIL

Debugging

ID Target Interface Description Initial state Input Expected output Pass/Fail
DBG001 Fill in! Fill in! Load is working Reset init is working, RAM is accesible, GDB server is started On the console of the OS:
arm-elf-gdb test_ram.elf
(gdb) target remote ip:port
(gdb) load
Load should return without error, typical output looks like:
Loading section .text, size 0x14c lma 0x0
Start address 0x40, load size 332
Transfer rate: 180 bytes/sec, 332 bytes/write.
PASS/FAIL
DBG002 Fill in! Fill in! Software breakpoint Load the test_ram.elf application, use instructions from GDB001 In the GDB console:
(gdb) monitor arm7_9 sw_bkpts enable
software breakpoints enabled
(gdb) break main
Breakpoint 1 at 0xec: file src/main.c, line 71.
(gdb) continue
Continuing.
The software breakpoint should be reached, a typical output looks like:
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x000000ec

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
PASS/FAIL
DBG003 Fill in! Fill in! Single step in a RAM application Load the test_ram.elf application, use instructions from GDB001, break in main using the instructions from GDB002 In GDB, type
(gdb) step
The next instruction should be reached, typical output:
(gdb) step
target state: halted
target halted in ARM state due to single step, current mode: Abort
cpsr: 0x20000097 pc: 0x000000f0
target state: halted
target halted in ARM state due to single step, current mode: Abort
cpsr: 0x20000097 pc: 0x000000f4
72 DWORD b = 2;
PASS/FAIL
DBG004 Fill in! Fill in! Software break points are working after a reset Load the test_ram.elf application, use instructions from GDB001, break in main using the instructions from GDB002 In GDB, type
(gdb) monitor reset
(gdb) load
(gdb) continue
The breakpoint should be reached, typical output:
target state: halted
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x000000d3 pc: 0x000000ec

Breakpoint 1, main () at src/main.c:71
71 DWORD a = 1;
PASS/FAIL
DBG005 Fill in! Fill in! Hardware breakpoint Flash the test_rom.elf application. Make this test after FLA004 has passed Be sure that gdb_memory_map and gdb_flash_program are enabled. In GDB, type
(gdb) monitor reset
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor arm7_9 force_hw_bkpts enable
force hardware breakpoints enabled
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
The breakpoint should be reached, typical output:
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
PASS/FAIL
DBG006 Fill in! Fill in! Hardware breakpoint is set after a reset Follow the instructions to flash and insert a hardware breakpoint from DBG005 In GDB, type
(gdb) monitor reset
(gdb) monitor reg pc 0x100000
pc (/32): 0x00100000
(gdb) continue
The breakpoint should be reached, typical output:
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
PASS/FAIL
DBG007 Fill in! Fill in! Single step in ROM Flash the test_rom.elf application and set a breakpoint in main, use DBG005. Make this test after FLA004 has passed Be sure that gdb_memory_map and gdb_flash_program are enabled. In GDB, type
(gdb) monitor reset
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write.
(gdb) monitor arm7_9 force_hw_bkpts enable
force hardware breakpoints enabled
(gdb) break main
Breakpoint 1 at 0x100134: file src/main.c, line 69.
(gdb) continue
Continuing.

Breakpoint 1, main () at src/main.c:69
69 DWORD a = 1;
(gdb) step
The breakpoint should be reached, typical output:
target state: halted
target halted in ARM state due to single step, current mode: Supervisor
cpsr: 0x60000013 pc: 0x0010013c
70 DWORD b = 2;
PASS/FAIL

RAM access

Note: these tests are not designed to test/debug the target, but to test functionalities!
ID Target Interface Description Initial state Input Expected output Pass/Fail
RAM001 Fill in! Fill in! 32 bit Write/read RAM Reset init is working On the telnet interface
> mww ram_address 0xdeadbeef 16
> mdw ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 32bit long containing 0xdeadbeef.
> mww 0x0 0xdeadbeef 16
> mdw 0x0 32
0x00000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x00000040: e1a00000 e59fa51c e59f051c e04aa000 00080017 00009388 00009388 00009388
0x00000060: 00009388 0002c2c0 0002c2c0 000094f8 000094f4 00009388 00009388 00009388
PASS/FAIL
RAM001 Fill in! Fill in! 16 bit Write/read RAM Reset init is working On the telnet interface
> mwh ram_address 0xbeef 16
> mdh ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 16bit long containing 0xbeef.
> mwh 0x0 0xbeef 16
> mdh 0x0 32
0x00000000: beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef beef
0x00000020: 00e0 0000 021c 0000 0240 0000 026c 0000 0288 0000 0000 0000 0388 0000 0350 0000
>
PASS/FAIL
RAM003 Fill in! Fill in! 8 bit Write/read RAM Reset init is working On the telnet interface
> mwb ram_address 0xab 16
> mdb ram_address 32
The commands should execute without error. A clear failure is a memory access exception. The result of running the commands should be a list of 16 locations 8bit long containing 0xab.
> mwh 0x0 0x0 16
> mwb ram_address 0xab 16
> mdb ram_address 32
0x00000000: ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>
PASS/FAIL

Flash access

ID Target Interface Description Initial state Input Expected output Pass/Fail
FLA002 Fill in! Fill in! flash fillw Reset init is working, flash is probed On the telnet interface
> flash fillw 0x1000000 0xdeadbeef 16
The commands should execute without error. The output looks like:
wrote 64 bytes to 0x01000000 in 11.610000s (0.091516 kb/s)
To verify the contents of the flash:
> mdw 0x1000000 32
0x01000000: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x01000020: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x01000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
PASS/FAIL
FLA003 Fill in! Fill in! Flash erase Reset init is working, flash is probed On the telnet interface
> flash erase_address 0x1000000 0x2000
The commands should execute without error.
erased address 0x01000000 length 8192 in 4.970000s To check that the flash has been erased, read at different addresses. The result should always be 0xff. > mdw 0x1000000 32
0x01000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x01000060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
PASS/FAIL
FLA004 Fill in! Fill in! Loading to flash from GDB Reset init is working, flash is probed, connectivity to GDB server is working Start GDB using a ROM elf image, eg: arm-elf-gdb test_rom.elf.
(gdb) target remote ip:port
(gdb) monitor reset
(gdb) load
Loading section .text, size 0x194 lma 0x100000
Start address 0x100040, load size 404
Transfer rate: 179 bytes/sec, 404 bytes/write. (gdb) monitor verify_image path_to_elf_file
The output should look like:
verified 404 bytes in 5.060000s
The failure message is something like:
Verify operation failed address 0x00200000. Was 0x00 instead of 0x18
PASS/FAIL
================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tools/checkpatch.sh ================================================ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later since=${1:-HEAD^} tools/scripts/checkpatch.pl --git ${since}.. ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tools/disassemble_inc.sh ================================================ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Simple script to disassemble a file .inc generated by # src/helper/bin2char.sh # Can be useful to check the correctness of the file .inc # # By default it decodes ARM thumb little-endian, e.g. cortex-m. # Set CROSS_COMPILE for other toolchains. # Set OBJDUMP_FLAGS for different objdump flags. # # Usage: # contrib/loaders/disassemble_inc.sh file.inc default_CROSS_COMPILE="arm-none-eabi-" default_OBJDUMP_FLAGS="-m arm -EL -M force-thumb" if [ $# != 1 -o ! -f "$1" ]; then echo "Usage:" echo " $0 path/to/file.inc" echo "" echo "Set CROSS_COMPILE and/or OBJDUMP_FLAGS to override current default:" echo " export CROSS_COMPILE=\"${default_CROSS_COMPILE}\"" echo " export OBJDUMP_FLAGS=\"${default_OBJDUMP_FLAGS}\"" exit 1 fi if [ -z "${CROSS_COMPILE}" ]; then CROSS_COMPILE="${default_CROSS_COMPILE}" fi if [ -z "${OBJDUMP_FLAGS}" ]; then OBJDUMP_FLAGS="${default_OBJDUMP_FLAGS}" fi perl -v > /dev/null 2>&1 if [ $? != 0 ]; then echo "Error: 'perl' interpreter not available." exit 1 fi tmpfile=$(mktemp --suffix=.bin) echo "Disassemble $1:" echo "${CROSS_COMPILE}objdump ${OBJDUMP_FLAGS} -b binary -D ${tmpfile}" perl -e 'while (<>){while ($_=~/(0x..)/g){print chr(hex($1));}}' $1 > ${tmpfile} ${CROSS_COMPILE}objdump ${OBJDUMP_FLAGS} -b binary -D ${tmpfile} rm ${tmpfile} ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tools/initial.sh ================================================ #!/bin/sh TOPDIR=`pwd` USERNAME=$1 if [ "x$1" = "x" ] ; then echo "Usage: $0 " exit 1 fi add_remote() { remote_exist=`grep remote .git/config | grep review | wc -l` if [ "x$remote_exist" = "x0" ] ; then git remote add review ssh://$USERNAME@review.openocd.org:29418/openocd.git git config remote.review.push HEAD:refs/for/master else echo "Remote review exists" fi } update_commit_msg() { cd "${TOPDIR}/.git/hooks" save_file=commit-msg-`date +%F-%T` mv commit-msg $save_file printf "%-30s" "Updating commit-msg" status="OK" wget -o log https://review.openocd.org/tools/hooks/commit-msg || status="FAIL" echo $status if [ $status = "FAIL" ] ; then mv $save_file commit-msg fi chmod a+x commit-msg } add_remote update_commit_msg ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tools/logger.pl ================================================ #!/usr/bin/perl # logger.pl: masks long meaningless output with pretty lines of dots # Details: 1) reads lines from STDIN and echos them on STDOUT, # 2) print a '.' to STDERR every $N lines. # 3) print a newline after a sequence of $C dots use strict; use warnings; # make sure all output gets displayed immediately $| = 1; # TODO: add -n and -c options w/ zero checks) # line and column limits my $N = 10; my $C = 72; # current line and column counters my $n = 0; my $c = 0; # read all lines from STDIN while () { # echo line to output print STDOUT $_; # echo line to console if it is important if (/(Warning|Error)/) { print STDERR "\n" if $c; print STDERR $_; $c = 0; } # only display progress every Nth step next if ++$n % $N; print STDERR "."; # wrap at column C to provide fixed-width rows of dots print STDERR "\n" unless ++$c % $C; } print STDERR "\n" if $c; ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tools/release/helpers.sh ================================================ #!/bin/sh -e die() { echo "$@" >&2 exit 1 } package_info_load_name() { grep AC_INIT configure.ac | perl -ne 's/^.+\(\[([-\w]*)\],.+$/$1/ and print' } package_info_load_version() { grep AC_INIT configure.ac | perl -ne 's/^.+\[([-\w\.]*)\],$/$1/ and print' } package_info_load() { [ -f "configure.ac" ] || \ die "package_info_load: configure.ac is missing" PACKAGE_NAME="$(package_info_load_name)" # todo: fix this PACKAGE_TARNAME="${PACKAGE_NAME}" PACKAGE_VERSION="$(package_info_load_version)" [ "${PACKAGE_NAME}" -a "${PACKAGE_VERSION}" ] || \ die "package information is missing from configure script" PACKAGE_VERSION_TAGS= [ "${PACKAGE_VERSION/-/}" = "${PACKAGE_VERSION}" ] || \ PACKAGE_VERSION_TAGS="-${PACKAGE_VERSION#*-}" PACKAGE_VERSION_BASE="${PACKAGE_VERSION%%-*}" PACKAGE_MICRO="${PACKAGE_VERSION_BASE##*.}" PACKAGE_MAJOR_AND_MINOR="${PACKAGE_VERSION_BASE%.*}" PACKAGE_MAJOR="${PACKAGE_MAJOR_AND_MINOR%.*}" PACKAGE_MINOR="${PACKAGE_MAJOR_AND_MINOR#*.}" [ "${RELEASE_FINAL}" ] \ && RELEASE_VERSION="${PACKAGE_VERSION_BASE}" \ || RELEASE_VERSION="${PACKAGE_VERSION/-dev/}" PACKAGE_RELEASE="${PACKAGE_TARNAME}-${RELEASE_VERSION}" PACKAGE_STRING="${PACKAGE_NAME} ${PACKAGE_VERSION}" } package_info_show() { cat < 0.3.1 tools/release.sh branch --next='micro' # 0.3.1 0.3.2 tools/release.sh release --next='micro' git checkout "v0.4.0-rc0-dev" # 0.4.0-rc0 0.4.0-rc1 tools/release.sh release --next='rc' # 0.4.0 1.0.0-rc0 tools/release.sh release --next='major' --final --start-rc git checkout -q "v0.4.0" # 0.4.1 tools/release.sh branch --next='micro' # 0.4.1 0.4.2 tools/release.sh release --next='micro' git checkout "v1.0.0-rc0-dev" # 1.0.0-rc0 1.0.0-rc1 tools/release.sh release --next='rc' # 1.0.0 1.1.0-rc0 tools/release.sh release --next='minor' --final --start-rc git checkout -q "v1.0.0" # 1.0.1 tools/release.sh branch --next='micro' # 1.0.1 1.0.2 tools/release.sh release --next='micro' git checkout "v1.1.0-rc0-dev" # 1.1.0-rc0 1.1.0-rc1 tools/release.sh release --next='rc' # 1.1.0 1.2.0 tools/release.sh release --next='minor' --final --start-rc git checkout -q "v1.0.0" tools/release.sh branch --next='major' --start-rc # 2.0.0-rc0 git checkout "v2.0.0-rc0-dev" # 2.0.0-rc0 2.0.0-rc1 tools/release.sh release --next='rc' # 2.0.0-rc1 2.0.0-rc2 tools/release.sh release --next='rc' # 2.0.0 2.1.0-rc0 tools/release.sh release --next='minor' --final --start-rc git checkout -q "v1.1.0" # 1.1.1 tools/release.sh branch --next='micro' # 1.1.1 1.1.2 tools/release.sh release --next='micro' git checkout -q "v2.0.0" # 2.0.0 tools/release.sh branch --next='micro' # 2.0.1 2.0.2 tools/release.sh release --next='micro' git checkout "v1.2.0-rc0-dev" # 1.2.0-rc0 1.2.0-rc1 tools/release.sh release --next='rc' # 1.2.0 1.3.0-rc0 tools/release.sh release --next='micro' --final git checkout "v2.1.0-rc0-dev" # 2.1.0-rc0 2.1.0-rc1 tools/release.sh release --next='rc' # 2.1.0-rc1 2.1.0-rc2 tools/release.sh release --next='rc' # 2.1.0 2.2.0-rc0 tools/release.sh release --next='minor' --final --start-rc git checkout -q "v2.1.0" # 2.1.1 tools/release.sh branch --next='micro' # 2.1.1 2.1.2 tools/release.sh release --next='micro' git checkout "v2.2.0-rc0-dev" # 2.2.0-rc0 2.2.0-rc1 tools/release.sh release --next='rc' gitk --all ================================================ FILE: Tools/CH347/ch347-main/OpenOCD_SourceCode_CH347/tools/release/version.sh ================================================ #!/bin/bash # version.sh: openocd version process automation # Copyright (C) 2009 by Zachary T Welch # Release under the GNU GPL v2 (or later versions). # FIXME Remove more bash-isms. Fix errors making "ash -e" lose. # NOTE Use with care! "RC" should only follow x.x.x, with # vendor tags after that. Be traditional; avoid "rc0". # NOTE: This *ONLY* updates the "configure.ac" version tag. # It does not affect GIT tags. Use this script immediately # before making a release, to remove the "-dev" tag and to # update the version label. Then commit the change and tag # that commit to match the version label. . "tools/release/helpers.sh" do_version_usage() { cat << USAGE usage: $0 Version Commands: tag {add|remove}